diff --git a/src/renderer/wg_engine/meson.build b/src/renderer/wg_engine/meson.build index 76a21c8a..ff831e70 100644 --- a/src/renderer/wg_engine/meson.build +++ b/src/renderer/wg_engine/meson.build @@ -7,6 +7,7 @@ source_file = [ 'tvgWgRenderData.h', 'tvgWgRenderer.h', 'tvgWgRenderTarget.h', + 'tvgWgRenderTask.h', 'tvgWgShaderSrc.h', 'tvgWgShaderTypes.h', 'tvgWgBindGroups.cpp', @@ -17,6 +18,7 @@ source_file = [ 'tvgWgRenderData.cpp', 'tvgWgRenderer.cpp', 'tvgWgRenderTarget.cpp', + 'tvgWgRenderTask.cpp', 'tvgWgShaderSrc.cpp', 'tvgWgShaderTypes.cpp' ] diff --git a/src/renderer/wg_engine/tvgWgCommon.cpp b/src/renderer/wg_engine/tvgWgCommon.cpp index 6f6611bd..eba88031 100644 --- a/src/renderer/wg_engine/tvgWgCommon.cpp +++ b/src/renderer/wg_engine/tvgWgCommon.cpp @@ -268,4 +268,35 @@ void WgContext::releaseQueue(WGPUQueue& queue) wgpuQueueRelease(queue); queue = nullptr; } -} \ No newline at end of file +} + + +WGPUCommandEncoder WgContext::createCommandEncoder() +{ + WGPUCommandEncoderDescriptor commandEncoderDesc{}; + return wgpuDeviceCreateCommandEncoder(device, &commandEncoderDesc); +} + + +void WgContext::submitCommandEncoder(WGPUCommandEncoder commandEncoder) +{ + const WGPUCommandBufferDescriptor commandBufferDesc{}; + WGPUCommandBuffer commandsBuffer = wgpuCommandEncoderFinish(commandEncoder, &commandBufferDesc); + wgpuQueueSubmit(queue, 1, &commandsBuffer); + wgpuCommandBufferRelease(commandsBuffer); +} + + +void WgContext::releaseCommandEncoder(WGPUCommandEncoder& commandEncoder) +{ + if (commandEncoder) { + wgpuCommandEncoderRelease(commandEncoder); + commandEncoder = nullptr; + } +} + + +bool WgContext::invalid() +{ + return !instance || !device; +} diff --git a/src/renderer/wg_engine/tvgWgCommon.h b/src/renderer/wg_engine/tvgWgCommon.h index 45774b9e..f0b0695d 100644 --- a/src/renderer/wg_engine/tvgWgCommon.h +++ b/src/renderer/wg_engine/tvgWgCommon.h @@ -71,10 +71,12 @@ struct WgContext { // release buffer objects void releaseBuffer(WGPUBuffer& buffer); - bool invalid() - { - return !instance || !device; - } + // command encoder + WGPUCommandEncoder createCommandEncoder(); + void submitCommandEncoder(WGPUCommandEncoder encoder); + void releaseCommandEncoder(WGPUCommandEncoder& encoder); + + bool invalid(); }; #endif // _TVG_WG_COMMON_H_ diff --git a/src/renderer/wg_engine/tvgWgCompositor.cpp b/src/renderer/wg_engine/tvgWgCompositor.cpp index 4211a65b..071fd3a0 100644 --- a/src/renderer/wg_engine/tvgWgCompositor.cpp +++ b/src/renderer/wg_engine/tvgWgCompositor.cpp @@ -28,6 +28,7 @@ void WgCompositor::initialize(WgContext& context, uint32_t width, uint32_t heigh { // pipelines (external handle, do not release) pipelines.initialize(context); + stageBuffer.initialize(context); // initialize opacity pool initPools(context); // allocate global view matrix handles @@ -37,7 +38,7 @@ void WgCompositor::initialize(WgContext& context, uint32_t width, uint32_t heigh // create render targets handles resize(context, width, height); // composition and blend geometries - meshData.blitBox(context); + meshDataBlit.blitBox(context); } @@ -54,7 +55,7 @@ void WgCompositor::initPools(WgContext& context) void WgCompositor::release(WgContext& context) { // composition and blend geometries - meshData.release(context); + meshDataBlit.release(context); // release render targets habdles resize(context, 0, 0); // release opacity pool @@ -62,6 +63,8 @@ void WgCompositor::release(WgContext& context) // release global view matrix handles context.layouts.releaseBindGroup(bindGroupViewMat); context.releaseBuffer(bufferViewMat); + // release stage buffer + stageBuffer.release(context); // release pipelines pipelines.release(context); } @@ -81,9 +84,9 @@ void WgCompositor::resize(WgContext& context, uint32_t width, uint32_t height) { // release existig handles if ((this->width != width) || (this->height != height)) { context.layouts.releaseBindGroup(bindGroupStorageTemp); - // release intermediate render storages - storageTemp1.release(context); - storageTemp0.release(context); + // release intermediate render target + targetTemp1.release(context); + targetTemp0.release(context); // release global stencil buffer handles context.releaseTextureView(texViewDepthStencilMS); context.releaseTexture(texDepthStencilMS); @@ -107,10 +110,10 @@ void WgCompositor::resize(WgContext& context, uint32_t width, uint32_t height) { texViewDepthStencil = context.createTextureView(texDepthStencil); texDepthStencilMS = context.createTexAttachement(width, height, WGPUTextureFormat_Depth24PlusStencil8, 4); texViewDepthStencilMS = context.createTextureView(texDepthStencilMS); - // initialize intermediate render storages - storageTemp0.initialize(context, width, height); - storageTemp1.initialize(context, width, height); - bindGroupStorageTemp = context.layouts.createBindGroupStrorage2RO(storageTemp0.texView, storageTemp1.texView); + // initialize intermediate render targets + targetTemp0.initialize(context, width, height); + targetTemp1.initialize(context, width, height); + bindGroupStorageTemp = context.layouts.createBindGroupStrorage2RO(targetTemp0.texView, targetTemp1.texView); } } @@ -121,14 +124,14 @@ RenderRegion WgCompositor::shrinkRenderRegion(RenderRegion& rect) } -void WgCompositor::copyTexture(const WgRenderStorage* dst, const WgRenderStorage* src) +void WgCompositor::copyTexture(const WgRenderTarget* dst, const WgRenderTarget* src) { const RenderRegion region = {{0, 0}, {(int32_t)src->width, (int32_t)src->height}}; copyTexture(dst, src, region); } -void WgCompositor::copyTexture(const WgRenderStorage* dst, const WgRenderStorage* src, const RenderRegion& region) +void WgCompositor::copyTexture(const WgRenderTarget* dst, const WgRenderTarget* src, const RenderRegion& region) { assert(dst); assert(src); @@ -140,16 +143,25 @@ void WgCompositor::copyTexture(const WgRenderStorage* dst, const WgRenderStorage } -void WgCompositor::beginRenderPass(WGPUCommandEncoder commandEncoder, WgRenderStorage* target, bool clear, WGPUColor clearColor) +void WgCompositor::beginRenderPass(WGPUCommandEncoder commandEncoder, WgRenderTarget* target, bool clear, WGPUColor clearColor) { - assert(commandEncoder); assert(target); + assert(commandEncoder); + // do not start same render bass + if (target == currentTarget) return; + // we must to end render pass first + endRenderPass(); this->currentTarget = target; + // start new render pass this->commandEncoder = commandEncoder; const WGPURenderPassDepthStencilAttachment depthStencilAttachment{ .view = texViewDepthStencilMS, - .depthLoadOp = WGPULoadOp_Clear, .depthStoreOp = WGPUStoreOp_Discard, .depthClearValue = 1.0f, - .stencilLoadOp = WGPULoadOp_Clear, .stencilStoreOp = WGPUStoreOp_Discard, .stencilClearValue = 0 + .depthLoadOp = WGPULoadOp_Clear, + .depthStoreOp = WGPUStoreOp_Discard, + .depthClearValue = 1.0f, + .stencilLoadOp = WGPULoadOp_Clear, + .stencilStoreOp = WGPUStoreOp_Discard, + .stencilClearValue = 0 }; const WGPURenderPassColorAttachment colorAttachment{ .view = target->texViewMS, @@ -158,7 +170,6 @@ void WgCompositor::beginRenderPass(WGPUCommandEncoder commandEncoder, WgRenderSt .loadOp = clear ? WGPULoadOp_Clear : WGPULoadOp_Load, .storeOp = WGPUStoreOp_Store, .clearValue = clearColor - }; WGPURenderPassDescriptor renderPassDesc{ .colorAttachmentCount = 1, .colorAttachments = &colorAttachment, .depthStencilAttachment = &depthStencilAttachment }; renderPassEncoder = wgpuCommandEncoderBeginRenderPass(commandEncoder, &renderPassDesc); @@ -172,11 +183,37 @@ void WgCompositor::endRenderPass() assert(renderPassEncoder); wgpuRenderPassEncoderEnd(renderPassEncoder); wgpuRenderPassEncoderRelease(renderPassEncoder); - this->renderPassEncoder = nullptr; - this->currentTarget = nullptr; + renderPassEncoder = nullptr; + currentTarget = nullptr; } } +void WgCompositor::reset(WgContext& context) +{ + stageBuffer.clear(); +} + + +void WgCompositor::flush(WgContext& context) +{ + stageBuffer.append(&meshDataBlit); + stageBuffer.flush(context); +} + + +void WgCompositor::requestShape(WgRenderDataShape* renderData) +{ + stageBuffer.append(renderData); + // TODO: expand for fill settings +} + + +void WgCompositor::requestImage(WgRenderDataPicture* renderData) +{ + stageBuffer.append(renderData); + // TODO: expand for fill settings +} + void WgCompositor::renderShape(WgContext& context, WgRenderDataShape* renderData, BlendMethod blendMethod) { @@ -232,7 +269,7 @@ void WgCompositor::renderImage(WgContext& context, WgRenderDataPicture* renderDa } -void WgCompositor::renderScene(WgContext& context, WgRenderStorage* scene, WgCompose* compose) +void WgCompositor::renderScene(WgContext& context, WgRenderTarget* scene, WgCompose* compose) { assert(scene); assert(compose); @@ -245,7 +282,7 @@ void WgCompositor::renderScene(WgContext& context, WgRenderStorage* scene, WgCom } -void WgCompositor::composeScene(WgContext& context, WgRenderStorage* src, WgRenderStorage* mask, WgCompose* cmp) +void WgCompositor::composeScene(WgContext& context, WgRenderTarget* src, WgRenderTarget* mask, WgCompose* cmp) { assert(cmp); assert(src); @@ -257,15 +294,19 @@ void WgCompositor::composeScene(WgContext& context, WgRenderStorage* src, WgRend wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 0, src->bindGroupTexure, 0, nullptr); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, mask->bindGroupTexure, 0, nullptr); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.scene_compose[(uint32_t)cmp->method]); - meshData.drawImage(context, renderPassEncoder); + drawMeshImage(context, &meshDataBlit); } -void WgCompositor::blit(WgContext& context, WGPUCommandEncoder encoder, WgRenderStorage* src, WGPUTextureView dstView) { +void WgCompositor::blit(WgContext& context, WGPUCommandEncoder encoder, WgRenderTarget* src, WGPUTextureView dstView) +{ + assert(!renderPassEncoder); const WGPURenderPassDepthStencilAttachment depthStencilAttachment{ .view = texViewDepthStencil, - .depthLoadOp = WGPULoadOp_Load, .depthStoreOp = WGPUStoreOp_Discard, - .stencilLoadOp = WGPULoadOp_Load, .stencilStoreOp = WGPUStoreOp_Discard + .depthLoadOp = WGPULoadOp_Load, + .depthStoreOp = WGPUStoreOp_Discard, + .stencilLoadOp = WGPULoadOp_Load, + .stencilStoreOp = WGPUStoreOp_Discard }; const WGPURenderPassColorAttachment colorAttachment { .view = dstView, @@ -274,15 +315,56 @@ void WgCompositor::blit(WgContext& context, WGPUCommandEncoder encoder, WgRender .storeOp = WGPUStoreOp_Store, }; const WGPURenderPassDescriptor renderPassDesc{ .colorAttachmentCount = 1, .colorAttachments = &colorAttachment, .depthStencilAttachment = &depthStencilAttachment }; - WGPURenderPassEncoder renderPass = wgpuCommandEncoderBeginRenderPass(encoder, &renderPassDesc); - wgpuRenderPassEncoderSetBindGroup(renderPass, 0, src->bindGroupTexure, 0, nullptr); - wgpuRenderPassEncoderSetPipeline(renderPass, pipelines.blit); - meshData.drawImage(context, renderPass); - wgpuRenderPassEncoderEnd(renderPass); - wgpuRenderPassEncoderRelease(renderPass); + renderPassEncoder = wgpuCommandEncoderBeginRenderPass(encoder, &renderPassDesc); + wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 0, src->bindGroupTexure, 0, nullptr); + wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.blit); + drawMeshImage(context, &meshDataBlit); + wgpuRenderPassEncoderEnd(renderPassEncoder); + wgpuRenderPassEncoderRelease(renderPassEncoder); + renderPassEncoder = nullptr; } +void WgCompositor::drawMesh(WgContext& context, WgMeshData* meshData) +{ + assert(meshData); + assert(renderPassEncoder); + uint64_t icount = meshData->ibuffer.count; + uint64_t vsize = meshData->vbuffer.count * sizeof(Point); + uint64_t isize = icount * sizeof(uint32_t); + wgpuRenderPassEncoderSetVertexBuffer(renderPassEncoder, 0, stageBuffer.vbuffer_gpu, meshData->voffset, vsize); + wgpuRenderPassEncoderSetIndexBuffer(renderPassEncoder, stageBuffer.ibuffer_gpu, WGPUIndexFormat_Uint32, meshData->ioffset, isize); + wgpuRenderPassEncoderDrawIndexed(renderPassEncoder, icount, 1, 0, 0, 0); +}; + + +void WgCompositor::drawMeshFan(WgContext& context, WgMeshData* meshData) +{ + assert(meshData); + assert(renderPassEncoder); + uint64_t icount = (meshData->vbuffer.count - 2) * 3; + uint64_t vsize = meshData->vbuffer.count * sizeof(Point); + uint64_t isize = icount * sizeof(uint32_t); + wgpuRenderPassEncoderSetVertexBuffer(renderPassEncoder, 0, stageBuffer.vbuffer_gpu, meshData->voffset, vsize); + wgpuRenderPassEncoderSetIndexBuffer(renderPassEncoder, context.bufferIndexFan, WGPUIndexFormat_Uint32, 0, isize); + wgpuRenderPassEncoderDrawIndexed(renderPassEncoder, icount, 1, 0, 0, 0); +}; + + +void WgCompositor::drawMeshImage(WgContext& context, WgMeshData* meshData) +{ + assert(meshData); + assert(renderPassEncoder); + uint64_t icount = meshData->ibuffer.count; + uint64_t vsize = meshData->vbuffer.count * sizeof(Point); + uint64_t isize = icount * sizeof(uint32_t); + wgpuRenderPassEncoderSetVertexBuffer(renderPassEncoder, 0, stageBuffer.vbuffer_gpu, meshData->voffset, vsize); + wgpuRenderPassEncoderSetVertexBuffer(renderPassEncoder, 1, stageBuffer.vbuffer_gpu, meshData->toffset, vsize); + wgpuRenderPassEncoderSetIndexBuffer(renderPassEncoder, stageBuffer.ibuffer_gpu, WGPUIndexFormat_Uint32, meshData->ioffset, isize); + wgpuRenderPassEncoderDrawIndexed(renderPassEncoder, icount, 1, 0, 0, 0); +}; + + void WgCompositor::drawShape(WgContext& context, WgRenderDataShape* renderData) { assert(renderData); @@ -298,7 +380,7 @@ void WgCompositor::drawShape(WgContext& context, WgRenderDataShape* renderData) wgpuRenderPassEncoderSetPipeline(renderPassEncoder, stencilPipeline); // draw to stencil (first pass) ARRAY_FOREACH(p, renderData->meshGroupShapes.meshes) - (*p)->drawFan(context, renderPassEncoder); + drawMeshFan(context, (*p)); // setup fill rules wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 0, bindGroupViewMat, 0, nullptr); @@ -315,7 +397,7 @@ void WgCompositor::drawShape(WgContext& context, WgRenderDataShape* renderData) wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.radial); } // draw to color (second pass) - renderData->meshDataBBox.drawFan(context, renderPassEncoder); + drawMeshFan(context, &renderData->meshDataBBox); } @@ -325,10 +407,10 @@ void WgCompositor::blendShape(WgContext& context, WgRenderDataShape* renderData, assert(renderPassEncoder); assert(renderData->meshGroupShapes.meshes.count == renderData->meshGroupShapesBBox.meshes.count); if (renderData->renderSettingsShape.skip || renderData->meshGroupShapes.meshes.count == 0 || renderData->viewport.invalid()) return; - // copy current render target data to dst storage - WgRenderStorage *target = currentTarget; + // copy current render target data to dst target + WgRenderTarget *target = currentTarget; endRenderPass(); - copyTexture(&storageTemp0, target); + copyTexture(&targetTemp0, target); beginRenderPass(commandEncoder, target, false); // render shape with blend settings wgpuRenderPassEncoderSetScissorRect(renderPassEncoder, renderData->viewport.x(), renderData->viewport.y(), renderData->viewport.w(), renderData->viewport.h()); @@ -340,12 +422,12 @@ void WgCompositor::blendShape(WgContext& context, WgRenderDataShape* renderData, wgpuRenderPassEncoderSetPipeline(renderPassEncoder, stencilPipeline); // draw to stencil (first pass) ARRAY_FOREACH(p, renderData->meshGroupShapes.meshes) - (*p)->drawFan(context, renderPassEncoder); + drawMeshFan(context, (*p)); // setup fill rules wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 0, bindGroupViewMat, 0, nullptr); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, renderData->bindGroupPaint, 0, nullptr); - wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 3, storageTemp0.bindGroupTexure, 0, nullptr); + wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 3, targetTemp0.bindGroupTexure, 0, nullptr); uint32_t blendMethodInd = (uint32_t)blendMethod; WgRenderSettings& settings = renderData->renderSettingsShape; if (settings.fillType == WgRenderSettingsType::Solid) { @@ -359,7 +441,7 @@ void WgCompositor::blendShape(WgContext& context, WgRenderDataShape* renderData, wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.radial_blend[blendMethodInd]); } // draw to color (second pass) - renderData->meshDataBBox.drawFan(context, renderPassEncoder); + drawMeshFan(context, &renderData->meshDataBBox); } @@ -379,12 +461,12 @@ void WgCompositor::clipShape(WgContext& context, WgRenderDataShape* renderData) wgpuRenderPassEncoderSetPipeline(renderPassEncoder, stencilPipeline); // draw to stencil (first pass) ARRAY_FOREACH(p, renderData->meshGroupShapes.meshes) - (*p)->drawFan(context, renderPassEncoder); + drawMeshFan(context, (*p)); // merge depth and stencil buffer wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, bindGroupOpacities[128], 0, nullptr); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.merge_depth_stencil); - renderData->meshDataBBox.drawFan(context, renderPassEncoder); + drawMeshFan(context, &renderData->meshDataBBox); // setup fill rules wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 0, bindGroupViewMat, 0, nullptr); @@ -401,7 +483,7 @@ void WgCompositor::clipShape(WgContext& context, WgRenderDataShape* renderData) wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.radial); } // draw to color (second pass) - renderData->meshDataBBox.drawFan(context, renderPassEncoder); + drawMeshFan(context, &renderData->meshDataBBox); } @@ -421,7 +503,7 @@ void WgCompositor::drawStrokes(WgContext& context, WgRenderDataShape* renderData wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, renderData->bindGroupPaint, 0, nullptr); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.direct); // draw to stencil (first pass) - renderData->meshGroupStrokes.meshes[i]->draw(context, renderPassEncoder); + drawMesh(context, renderData->meshGroupStrokes.meshes[i]); // setup fill rules wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 0, bindGroupViewMat, 0, nullptr); @@ -438,7 +520,7 @@ void WgCompositor::drawStrokes(WgContext& context, WgRenderDataShape* renderData wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.radial); } // draw to color (second pass) - renderData->meshGroupStrokesBBox.meshes[i]->drawFan(context, renderPassEncoder); + drawMeshFan(context, renderData->meshGroupStrokesBBox.meshes[i]); } } @@ -450,10 +532,10 @@ void WgCompositor::blendStrokes(WgContext& context, WgRenderDataShape* renderDat assert(renderData->meshGroupStrokes.meshes.count == renderData->meshGroupStrokesBBox.meshes.count); if (renderData->renderSettingsStroke.skip || renderData->meshGroupStrokes.meshes.count == 0 || renderData->viewport.invalid()) return; - // copy current render target data to dst storage - WgRenderStorage *target = currentTarget; + // copy current render target data to dst target + WgRenderTarget *target = currentTarget; endRenderPass(); - copyTexture(&storageTemp0, target); + copyTexture(&targetTemp0, target); beginRenderPass(commandEncoder, target, false); wgpuRenderPassEncoderSetScissorRect(renderPassEncoder, renderData->viewport.x(), renderData->viewport.y(), renderData->viewport.w(), renderData->viewport.h()); // draw strokes to stencil (first pass) @@ -464,12 +546,12 @@ void WgCompositor::blendStrokes(WgContext& context, WgRenderDataShape* renderDat wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, renderData->bindGroupPaint, 0, nullptr); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.direct); // draw to stencil (first pass) - renderData->meshGroupStrokes.meshes[i]->draw(context, renderPassEncoder); + drawMesh(context, renderData->meshGroupStrokes.meshes[i]); // setup fill rules wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 0, bindGroupViewMat, 0, nullptr); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, renderData->bindGroupPaint, 0, nullptr); - wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 3, storageTemp0.bindGroupTexure, 0, nullptr); + wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 3, targetTemp0.bindGroupTexure, 0, nullptr); uint32_t blendMethodInd = (uint32_t)blendMethod; WgRenderSettings& settings = renderData->renderSettingsStroke; if (settings.fillType == WgRenderSettingsType::Solid) { @@ -483,7 +565,7 @@ void WgCompositor::blendStrokes(WgContext& context, WgRenderDataShape* renderDat wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.radial_blend[blendMethodInd]); } // draw to color (second pass) - renderData->meshGroupStrokesBBox.meshes[i]->drawFan(context, renderPassEncoder); + drawMeshFan(context, renderData->meshGroupStrokesBBox.meshes[i]); } }; @@ -505,12 +587,12 @@ void WgCompositor::clipStrokes(WgContext& context, WgRenderDataShape* renderData wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, renderData->bindGroupPaint, 0, nullptr); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.direct); // draw to stencil (first pass) - renderData->meshGroupStrokes.meshes[i]->draw(context, renderPassEncoder); + drawMesh(context, renderData->meshGroupStrokes.meshes[i]); // merge depth and stencil buffer wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, bindGroupOpacities[128], 0, nullptr); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.merge_depth_stencil); - renderData->meshDataBBox.drawFan(context, renderPassEncoder); + drawMeshFan(context, &renderData->meshDataBBox); // setup fill rules wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 0, bindGroupViewMat, 0, nullptr); @@ -527,7 +609,7 @@ void WgCompositor::clipStrokes(WgContext& context, WgRenderDataShape* renderData wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.radial); } // draw to color (second pass) - renderData->meshGroupStrokesBBox.meshes[i]->drawFan(context, renderPassEncoder); + drawMeshFan(context, renderData->meshGroupStrokesBBox.meshes[i]); } } @@ -543,14 +625,14 @@ void WgCompositor::drawImage(WgContext& context, WgRenderDataPicture* renderData wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 0, bindGroupViewMat, 0, nullptr); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, renderData->bindGroupPaint, 0, nullptr); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.direct); - renderData->meshData.drawImage(context, renderPassEncoder); + drawMeshImage(context, &renderData->meshData); // draw image wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 0, bindGroupViewMat, 0, nullptr); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, renderData->bindGroupPaint, 0, nullptr); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, renderData->bindGroupPicture, 0, nullptr); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.image); - renderData->meshData.drawImage(context, renderPassEncoder); + drawMeshImage(context, &renderData->meshData); } @@ -560,26 +642,26 @@ void WgCompositor::blendImage(WgContext& context, WgRenderDataPicture* renderDat assert(renderPassEncoder); if (renderData->viewport.invalid()) return; wgpuRenderPassEncoderSetScissorRect(renderPassEncoder, renderData->viewport.x(), renderData->viewport.y(), renderData->viewport.w(), renderData->viewport.h()); - // copy current render target data to dst storage - WgRenderStorage *target = currentTarget; + // copy current render target data to dst target + WgRenderTarget *target = currentTarget; endRenderPass(); - copyTexture(&storageTemp0, target); + copyTexture(&targetTemp0, target); beginRenderPass(commandEncoder, target, false); // setup stencil rules wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 255); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 0, bindGroupViewMat, 0, nullptr); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, renderData->bindGroupPaint, 0, nullptr); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.direct); - renderData->meshData.drawImage(context, renderPassEncoder); + drawMeshImage(context, &renderData->meshData); // blend image uint32_t blendMethodInd = (uint32_t)blendMethod; wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 0, bindGroupViewMat, 0, nullptr); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, renderData->bindGroupPaint, 0, nullptr); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, renderData->bindGroupPicture, 0, nullptr); - wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 3, storageTemp0.bindGroupTexure, 0, nullptr); + wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 3, targetTemp0.bindGroupTexure, 0, nullptr); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.image_blend[blendMethodInd]); - renderData->meshData.drawImage(context, renderPassEncoder); + drawMeshImage(context, &renderData->meshData); }; @@ -594,23 +676,23 @@ void WgCompositor::clipImage(WgContext& context, WgRenderDataPicture* renderData wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 0, bindGroupViewMat, 0, nullptr); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, renderData->bindGroupPaint, 0, nullptr); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.direct); - renderData->meshData.drawImage(context, renderPassEncoder); + drawMeshImage(context, &renderData->meshData); // merge depth and stencil buffer wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, bindGroupOpacities[128], 0, nullptr); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.merge_depth_stencil); - renderData->meshData.drawImage(context, renderPassEncoder); + drawMeshImage(context, &renderData->meshData); // draw image wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 0, bindGroupViewMat, 0, nullptr); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, renderData->bindGroupPaint, 0, nullptr); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, renderData->bindGroupPicture, 0, nullptr); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.image); - renderData->meshData.drawImage(context, renderPassEncoder); + drawMeshImage(context, &renderData->meshData); } -void WgCompositor::drawScene(WgContext& context, WgRenderStorage* scene, WgCompose* compose) +void WgCompositor::drawScene(WgContext& context, WgRenderTarget* scene, WgCompose* compose) { assert(scene); assert(compose); @@ -622,19 +704,19 @@ void WgCompositor::drawScene(WgContext& context, WgRenderStorage* scene, WgCompo wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 0, scene->bindGroupTexure, 0, nullptr); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, bindGroupOpacities[compose->opacity], 0, nullptr); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.scene); - meshData.drawImage(context, renderPassEncoder); + drawMeshImage(context, &meshDataBlit); } -void WgCompositor::blendScene(WgContext& context, WgRenderStorage* scene, WgCompose* compose) +void WgCompositor::blendScene(WgContext& context, WgRenderTarget* scene, WgCompose* compose) { assert(scene); assert(compose); assert(currentTarget); - // copy current render target data to dst storage - WgRenderStorage *target = currentTarget; + // copy current render target data to dst target + WgRenderTarget *target = currentTarget; endRenderPass(); - copyTexture(&storageTemp0, target); + copyTexture(&targetTemp0, target); beginRenderPass(commandEncoder, target, false); // blend scene uint32_t blendMethodInd = (uint32_t)compose->blend; @@ -642,10 +724,10 @@ void WgCompositor::blendScene(WgContext& context, WgRenderStorage* scene, WgComp wgpuRenderPassEncoderSetScissorRect(renderPassEncoder, rect.x(), rect.y(), rect.w(), rect.h()); wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 0, scene->bindGroupTexure, 0, nullptr); - wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, storageTemp0.bindGroupTexure, 0, nullptr); + wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, targetTemp0.bindGroupTexure, 0, nullptr); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, bindGroupOpacities[compose->opacity], 0, nullptr); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.scene_blend[blendMethodInd]); - meshData.drawImage(context, renderPassEncoder); + drawMeshImage(context, &meshDataBlit); } @@ -658,13 +740,13 @@ void WgCompositor::markupClipPath(WgContext& context, WgRenderDataShape* renderD wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 255); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.direct); ARRAY_FOREACH(p, renderData->meshGroupStrokes.meshes) - (*p)->draw(context, renderPassEncoder); + drawMesh(context, (*p)); } else { WGPURenderPipeline stencilPipeline = (renderData->fillRule == FillRule::NonZero) ? pipelines.nonzero : pipelines.evenodd; wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, stencilPipeline); ARRAY_FOREACH(p, renderData->meshGroupShapes.meshes) - (*p)->drawFan(context, renderPassEncoder); + drawMeshFan(context, (*p)); } } @@ -686,7 +768,7 @@ void WgCompositor::renderClipPath(WgContext& context, WgRenderDataPaint* paint) wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, renderData0->bindGroupPaint, 0, nullptr); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, bindGroupOpacities[128], 0, nullptr); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.copy_stencil_to_depth); - renderData0->meshDataBBox.drawFan(context, renderPassEncoder); + drawMeshFan(context, &renderData0->meshDataBBox); // merge clip pathes with AND logic for (auto p = paint->clips.begin() + 1; p < paint->clips.end(); ++p) { // get render data @@ -698,31 +780,31 @@ void WgCompositor::renderClipPath(WgContext& context, WgRenderDataPaint* paint) wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, renderData->bindGroupPaint, 0, nullptr); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, bindGroupOpacities[190], 0, nullptr); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.copy_stencil_to_depth_interm); - renderData->meshDataBBox.drawFan(context, renderPassEncoder); + drawMeshFan(context, &renderData->meshDataBBox); // copy depth to stencil wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 1); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, renderData->bindGroupPaint, 0, nullptr); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, bindGroupOpacities[190], 0, nullptr); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.copy_depth_to_stencil); - renderData->meshDataBBox.drawFan(context, renderPassEncoder); + drawMeshFan(context, &renderData->meshDataBBox); // clear depth current (keep stencil) wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, renderData->bindGroupPaint, 0, nullptr); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, bindGroupOpacities[255], 0, nullptr); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.clear_depth); - renderData->meshDataBBox.drawFan(context, renderPassEncoder); + drawMeshFan(context, &renderData->meshDataBBox); // clear depth original (keep stencil) wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, renderData0->bindGroupPaint, 0, nullptr); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, bindGroupOpacities[255], 0, nullptr); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.clear_depth); - renderData0->meshDataBBox.drawFan(context, renderPassEncoder); + drawMeshFan(context, &renderData0->meshDataBBox); // copy stencil to depth (clear stencil) wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, renderData->bindGroupPaint, 0, nullptr); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, bindGroupOpacities[128], 0, nullptr); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.copy_stencil_to_depth); - renderData->meshDataBBox.drawFan(context, renderPassEncoder); + drawMeshFan(context, &renderData->meshDataBBox); } } @@ -743,12 +825,12 @@ void WgCompositor::clearClipPath(WgContext& context, WgRenderDataPaint* paint) wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, renderData->bindGroupPaint, 0, nullptr); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, bindGroupOpacities[255], 0, nullptr); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.clear_depth); - renderData->meshDataBBox.drawFan(context, renderPassEncoder); + drawMeshFan(context, &renderData->meshDataBBox); } } -bool WgCompositor::gaussianBlur(WgContext& context, WgRenderStorage* dst, const RenderEffectGaussianBlur* params, const WgCompose* compose) +bool WgCompositor::gaussianBlur(WgContext& context, WgRenderTarget* dst, const RenderEffectGaussianBlur* params, const WgCompose* compose) { assert(dst); assert(params); @@ -758,8 +840,8 @@ bool WgCompositor::gaussianBlur(WgContext& context, WgRenderStorage* dst, const auto renderData = (WgRenderDataEffectParams*)params->rd; auto aabb = compose->aabb; auto viewport = compose->rdViewport; - WgRenderStorage* sbuff = dst; - WgRenderStorage* dbuff = &storageTemp0; + WgRenderTarget* sbuff = dst; + WgRenderTarget* dbuff = &targetTemp0; // begin compute pass WGPUComputePassDescriptor computePassDesc{ .label = "Compute pass gaussian blur" }; @@ -791,14 +873,14 @@ bool WgCompositor::gaussianBlur(WgContext& context, WgRenderStorage* dst, const wgpuComputePassEncoderRelease(computePassEncoder); // if final result stored in intermidiate buffer we must copy result to destination buffer - if (sbuff == &storageTemp0) + if (sbuff == &targetTemp0) copyTexture(sbuff, dbuff, aabb); return true; } -bool WgCompositor::dropShadow(WgContext& context, WgRenderStorage* dst, const RenderEffectDropShadow* params, const WgCompose* compose) +bool WgCompositor::dropShadow(WgContext& context, WgRenderTarget* dst, const RenderEffectDropShadow* params, const WgCompose* compose) { assert(dst); assert(params); @@ -811,9 +893,9 @@ bool WgCompositor::dropShadow(WgContext& context, WgRenderStorage* dst, const Re auto viewport = compose->rdViewport; { // apply blur - copyTexture(&storageTemp1, dst, aabb); - WgRenderStorage* sbuff = &storageTemp1; - WgRenderStorage* dbuff = &storageTemp0; + copyTexture(&targetTemp1, dst, aabb); + WgRenderTarget* sbuff = &targetTemp1; + WgRenderTarget* dbuff = &targetTemp0; WGPUComputePassDescriptor computePassDesc{ .label = "Compute pass drop shadow blur" }; WGPUComputePassEncoder computePassEncoder = wgpuCommandEncoderBeginComputePass(commandEncoder, &computePassDesc); // horizontal blur @@ -837,7 +919,7 @@ bool WgCompositor::dropShadow(WgContext& context, WgRenderStorage* dst, const Re } { // blend origin (temp0), shadow (temp1) to destination - copyTexture(&storageTemp0, dst, aabb); + copyTexture(&targetTemp0, dst, aabb); WGPUComputePassDescriptor computePassDesc{ .label = "Compute pass drop shadow blend" }; WGPUComputePassEncoder computePassEncoder = wgpuCommandEncoderBeginComputePass(commandEncoder, &computePassDesc); wgpuComputePassEncoderSetBindGroup(computePassEncoder, 0, bindGroupStorageTemp, 0, nullptr); @@ -854,7 +936,7 @@ bool WgCompositor::dropShadow(WgContext& context, WgRenderStorage* dst, const Re } -bool WgCompositor::fillEffect(WgContext& context, WgRenderStorage* dst, const RenderEffectFill* params, const WgCompose* compose) +bool WgCompositor::fillEffect(WgContext& context, WgRenderTarget* dst, const RenderEffectFill* params, const WgCompose* compose) { assert(dst); assert(params); @@ -862,7 +944,7 @@ bool WgCompositor::fillEffect(WgContext& context, WgRenderStorage* dst, const Re assert(compose->rdViewport); assert(!renderPassEncoder); - copyTexture(&storageTemp0, dst, compose->aabb); + copyTexture(&targetTemp0, dst, compose->aabb); WGPUComputePassDescriptor computePassDesc{ .label = "Compute pass fill" }; WGPUComputePassEncoder computePassEncoder = wgpuCommandEncoderBeginComputePass(commandEncoder, &computePassDesc); wgpuComputePassEncoderSetBindGroup(computePassEncoder, 0, bindGroupStorageTemp, 0, nullptr); @@ -878,7 +960,7 @@ bool WgCompositor::fillEffect(WgContext& context, WgRenderStorage* dst, const Re } -bool WgCompositor::tintEffect(WgContext& context, WgRenderStorage* dst, const RenderEffectTint* params, const WgCompose* compose) +bool WgCompositor::tintEffect(WgContext& context, WgRenderTarget* dst, const RenderEffectTint* params, const WgCompose* compose) { assert(dst); assert(params); @@ -886,7 +968,7 @@ bool WgCompositor::tintEffect(WgContext& context, WgRenderStorage* dst, const Re assert(compose->rdViewport); assert(!renderPassEncoder); - copyTexture(&storageTemp0, dst, compose->aabb); + copyTexture(&targetTemp0, dst, compose->aabb); WGPUComputePassDescriptor computePassDesc{ .label = "Compute pass tint" }; WGPUComputePassEncoder computePassEncoder = wgpuCommandEncoderBeginComputePass(commandEncoder, &computePassDesc); wgpuComputePassEncoderSetBindGroup(computePassEncoder, 0, bindGroupStorageTemp, 0, nullptr); @@ -901,7 +983,7 @@ bool WgCompositor::tintEffect(WgContext& context, WgRenderStorage* dst, const Re return true; } -bool WgCompositor::tritoneEffect(WgContext& context, WgRenderStorage* dst, const RenderEffectTritone* params, const WgCompose* compose) +bool WgCompositor::tritoneEffect(WgContext& context, WgRenderTarget* dst, const RenderEffectTritone* params, const WgCompose* compose) { assert(dst); assert(params); @@ -909,7 +991,7 @@ bool WgCompositor::tritoneEffect(WgContext& context, WgRenderStorage* dst, const assert(compose->rdViewport); assert(!renderPassEncoder); - copyTexture(&storageTemp0, dst, compose->aabb); + copyTexture(&targetTemp0, dst, compose->aabb); WGPUComputePassDescriptor computePassDesc{ .label = "Compute pass tritone" }; WGPUComputePassEncoder computePassEncoder = wgpuCommandEncoderBeginComputePass(commandEncoder, &computePassDesc); wgpuComputePassEncoderSetBindGroup(computePassEncoder, 0, bindGroupStorageTemp, 0, nullptr); diff --git a/src/renderer/wg_engine/tvgWgCompositor.h b/src/renderer/wg_engine/tvgWgCompositor.h index c2572c29..648248d9 100644 --- a/src/renderer/wg_engine/tvgWgCompositor.h +++ b/src/renderer/wg_engine/tvgWgCompositor.h @@ -38,6 +38,8 @@ class WgCompositor private: // pipelines WgPipelines pipelines{}; + // stage buffers + WgRenderDataStageBuffer stageBuffer{}; // global stencil/depth buffer handles WGPUTexture texDepthStencil{}; WGPUTextureView texViewDepthStencil{}; @@ -52,21 +54,26 @@ private: // current render pass handles WGPURenderPassEncoder renderPassEncoder{}; WGPUCommandEncoder commandEncoder{}; - WgRenderStorage* currentTarget{}; - // intermediate render storages - WgRenderStorage storageTemp0; - WgRenderStorage storageTemp1; + WgRenderTarget* currentTarget{}; + // intermediate render targets + WgRenderTarget targetTemp0; + WgRenderTarget targetTemp1; WGPUBindGroup bindGroupStorageTemp{}; // composition and blend geometries - WgMeshData meshData; + WgMeshData meshDataBlit; // render target dimensions uint32_t width{}; uint32_t height{}; // viewport utilities RenderRegion shrinkRenderRegion(RenderRegion& rect); - void copyTexture(const WgRenderStorage* dst, const WgRenderStorage* src); - void copyTexture(const WgRenderStorage* dst, const WgRenderStorage* src, const RenderRegion& region); + void copyTexture(const WgRenderTarget* dst, const WgRenderTarget* src); + void copyTexture(const WgRenderTarget* dst, const WgRenderTarget* src, const RenderRegion& region); + + // base meshes draw + void drawMesh(WgContext& context, WgMeshData* meshData); + void drawMeshFan(WgContext& context, WgMeshData* meshData); + void drawMeshImage(WgContext& context, WgMeshData* meshData); // shapes void drawShape(WgContext& context, WgRenderDataShape* renderData); @@ -84,8 +91,8 @@ private: void clipImage(WgContext& context, WgRenderDataPicture* renderData); // scenes - void drawScene(WgContext& context, WgRenderStorage* scene, WgCompose* compose); - void blendScene(WgContext& context, WgRenderStorage* src, WgCompose* compose); + void drawScene(WgContext& context, WgRenderTarget* scene, WgCompose* compose); + void blendScene(WgContext& context, WgRenderTarget* src, WgCompose* compose); // the renderer prioritizes clipping with the stroke over the shape's fill void markupClipPath(WgContext& context, WgRenderDataShape* renderData); @@ -100,24 +107,32 @@ public: void resize(WgContext& context, uint32_t width, uint32_t height); // render passes workflow - void beginRenderPass(WGPUCommandEncoder encoder, WgRenderStorage* target, bool clear, WGPUColor clearColor = { 0.0, 0.0, 0.0, 0.0 }); + void beginRenderPass(WGPUCommandEncoder encoder, WgRenderTarget* target, bool clear, WGPUColor clearColor = { 0.0, 0.0, 0.0, 0.0 }); void endRenderPass(); + // request shapes for drawing (staging) + // stage data + void reset(WgContext& context); + void flush(WgContext& context); + + void requestShape(WgRenderDataShape* renderData); + void requestImage(WgRenderDataPicture* renderData); + // render shapes, images and scenes void renderShape(WgContext& context, WgRenderDataShape* renderData, BlendMethod blendMethod); void renderImage(WgContext& context, WgRenderDataPicture* renderData, BlendMethod blendMethod); - void renderScene(WgContext& context, WgRenderStorage* scene, WgCompose* compose); - void composeScene(WgContext& context, WgRenderStorage* src, WgRenderStorage* mask, WgCompose* compose); + void renderScene(WgContext& context, WgRenderTarget* scene, WgCompose* compose); + void composeScene(WgContext& context, WgRenderTarget* src, WgRenderTarget* mask, WgCompose* compose); - // blit render storage to texture view (f.e. screen buffer) - void blit(WgContext& context, WGPUCommandEncoder encoder, WgRenderStorage* src, WGPUTextureView dstView); + // blit render target to texture view (f.e. screen buffer) + void blit(WgContext& context, WGPUCommandEncoder encoder, WgRenderTarget* src, WGPUTextureView dstView); // effects - bool gaussianBlur(WgContext& context, WgRenderStorage* dst, const RenderEffectGaussianBlur* params, const WgCompose* compose); - bool dropShadow(WgContext& context, WgRenderStorage* dst, const RenderEffectDropShadow* params, const WgCompose* compose); - bool fillEffect(WgContext& context, WgRenderStorage* dst, const RenderEffectFill* params, const WgCompose* compose); - bool tintEffect(WgContext& context, WgRenderStorage* dst, const RenderEffectTint* params, const WgCompose* compose); - bool tritoneEffect(WgContext& context, WgRenderStorage* dst, const RenderEffectTritone* params, const WgCompose* compose); + bool gaussianBlur(WgContext& context, WgRenderTarget* dst, const RenderEffectGaussianBlur* params, const WgCompose* compose); + bool dropShadow(WgContext& context, WgRenderTarget* dst, const RenderEffectDropShadow* params, const WgCompose* compose); + bool fillEffect(WgContext& context, WgRenderTarget* dst, const RenderEffectFill* params, const WgCompose* compose); + bool tintEffect(WgContext& context, WgRenderTarget* dst, const RenderEffectTint* params, const WgCompose* compose); + bool tritoneEffect(WgContext& context, WgRenderTarget* dst, const RenderEffectTritone* params, const WgCompose* compose); }; #endif // _TVG_WG_COMPOSITOR_H_ diff --git a/src/renderer/wg_engine/tvgWgRenderData.cpp b/src/renderer/wg_engine/tvgWgRenderData.cpp index fba2a8a7..f6eea81e 100644 --- a/src/renderer/wg_engine/tvgWgRenderData.cpp +++ b/src/renderer/wg_engine/tvgWgRenderData.cpp @@ -30,95 +30,88 @@ // WgMeshData //*********************************************************************** -void WgMeshData::draw(WgContext& context, WGPURenderPassEncoder renderPassEncoder) -{ - wgpuRenderPassEncoderSetVertexBuffer(renderPassEncoder, 0, bufferPosition, 0, vertexCount * sizeof(float) * 2); - wgpuRenderPassEncoderSetIndexBuffer(renderPassEncoder, bufferIndex, WGPUIndexFormat_Uint32, 0, indexCount * sizeof(uint32_t)); - wgpuRenderPassEncoderDrawIndexed(renderPassEncoder, indexCount, 1, 0, 0, 0); -} - - -void WgMeshData::drawFan(WgContext& context, WGPURenderPassEncoder renderPassEncoder) -{ - wgpuRenderPassEncoderSetVertexBuffer(renderPassEncoder, 0, bufferPosition, 0, vertexCount * sizeof(float) * 2); - wgpuRenderPassEncoderSetIndexBuffer(renderPassEncoder, context.bufferIndexFan, WGPUIndexFormat_Uint32, 0, indexCount * sizeof(uint32_t)); - wgpuRenderPassEncoderDrawIndexed(renderPassEncoder, indexCount, 1, 0, 0, 0); -} - - -void WgMeshData::drawImage(WgContext& context, WGPURenderPassEncoder renderPassEncoder) -{ - wgpuRenderPassEncoderSetVertexBuffer(renderPassEncoder, 0, bufferPosition, 0, vertexCount * sizeof(float) * 2); - wgpuRenderPassEncoderSetVertexBuffer(renderPassEncoder, 1, bufferTexCoord, 0, vertexCount * sizeof(float) * 2); - wgpuRenderPassEncoderSetIndexBuffer(renderPassEncoder, bufferIndex, WGPUIndexFormat_Uint32, 0, indexCount * sizeof(uint32_t)); - wgpuRenderPassEncoderDrawIndexed(renderPassEncoder, indexCount, 1, 0, 0, 0); -}; - - void WgMeshData::update(WgContext& context, const WgVertexBuffer& vertexBuffer) { assert(vertexBuffer.count > 2); - vertexCount = vertexBuffer.count; - indexCount = (vertexBuffer.count - 2) * 3; - context.allocateBufferVertex(bufferPosition, (float*)vertexBuffer.data, vertexCount * sizeof(float) * 2); - context.allocateBufferIndexFan(vertexCount); + // setup vertex data + vbuffer.reserve(vertexBuffer.count); + vbuffer.count = vertexBuffer.count; + memcpy(vbuffer.data, vertexBuffer.data, sizeof(vertexBuffer.data[0])*vertexBuffer.count); + // setup tex coords data + tbuffer.clear(); + context.allocateBufferIndexFan(vbuffer.count); } void WgMeshData::update(WgContext& context, const WgIndexedVertexBuffer& vertexBufferInd) { assert(vertexBufferInd.vcount > 2); - vertexCount = vertexBufferInd.vcount; - indexCount = vertexBufferInd.icount; - if (vertexCount > 0) context.allocateBufferVertex(bufferPosition, (float*)vertexBufferInd.vbuff, vertexCount * sizeof(float) * 2); - if (indexCount > 0) context.allocateBufferIndex(bufferIndex, vertexBufferInd.ibuff, indexCount * sizeof(uint32_t)); + // setup vertex data + vbuffer.reserve(vertexBufferInd.vcount); + vbuffer.count = vertexBufferInd.vcount; + memcpy(vbuffer.data, vertexBufferInd.vbuff, sizeof(vertexBufferInd.vbuff[0])*vertexBufferInd.vcount); + // setup tex coords data + tbuffer.clear(); + // copy index data + ibuffer.reserve(vertexBufferInd.icount); + ibuffer.count = vertexBufferInd.icount; + memcpy(ibuffer.data, vertexBufferInd.ibuff, sizeof(vertexBufferInd.ibuff[0])*vertexBufferInd.icount); }; void WgMeshData::bbox(WgContext& context, const Point pmin, const Point pmax) { - vertexCount = 4; - indexCount = 6; const float data[] = {pmin.x, pmin.y, pmax.x, pmin.y, pmax.x, pmax.y, pmin.x, pmax.y}; - context.allocateBufferVertex(bufferPosition, data, sizeof(data)); - context.allocateBufferIndexFan(vertexCount); + // setup vertex data + vbuffer.reserve(4); + vbuffer.count = 4; + memcpy(vbuffer.data, data, sizeof(data)); + // setup tex coords data + tbuffer.clear(); + context.allocateBufferIndexFan(vbuffer.count); } void WgMeshData::imageBox(WgContext& context, float w, float h) { - vertexCount = 4; - indexCount = 6; const float vdata[] = {0.0f, 0.0f, w, 0.0f, w, h, 0.0f, h}; const float tdata[] = {0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f}; const uint32_t idata[] = {0, 1, 2, 0, 2, 3}; - context.allocateBufferVertex(bufferPosition, vdata, sizeof(vdata)); - context.allocateBufferVertex(bufferTexCoord, tdata, sizeof(tdata)); - context.allocateBufferIndex(bufferIndex, idata, sizeof(idata)); + // setup vertex data + vbuffer.reserve(4); + vbuffer.count = 4; + memcpy(vbuffer.data, vdata, sizeof(vdata)); + // setup tex coords data + tbuffer.reserve(4); + tbuffer.count = 4; + memcpy(tbuffer.data, tdata, sizeof(tdata)); + // setup indexes data + ibuffer.reserve(6); + ibuffer.count = 6; + memcpy(ibuffer.data, idata, sizeof(idata)); } void WgMeshData::blitBox(WgContext& context) { - vertexCount = 4; - indexCount = 6; const float vdata[] = {-1.0f, +1.0f, +1.0f, +1.0f, +1.0f, -1.0f, -1.0f, -1.0f}; const float tdata[] = {+0.0f, +0.0f, +1.0f, +0.0f, +1.0f, +1.0f, +0.0f, +1.0f}; const uint32_t idata[] = { 0, 1, 2, 0, 2, 3 }; - context.allocateBufferVertex(bufferPosition, vdata, sizeof(vdata)); - context.allocateBufferVertex(bufferTexCoord, tdata, sizeof(tdata)); - context.allocateBufferIndex(bufferIndex, idata, sizeof(idata)); + // setup vertex data + vbuffer.reserve(4); + vbuffer.count = 4; + memcpy(vbuffer.data, vdata, sizeof(vdata)); + // setup tex coords data + tbuffer.reserve(4); + tbuffer.count = 4; + memcpy(tbuffer.data, tdata, sizeof(tdata)); + // setup indexes data + ibuffer.reserve(6); + ibuffer.count = 6; + memcpy(ibuffer.data, idata, sizeof(idata)); } -void WgMeshData::release(WgContext& context) -{ - context.releaseBuffer(bufferIndex); - context.releaseBuffer(bufferTexCoord); - context.releaseBuffer(bufferPosition); -}; - - //*********************************************************************** // WgMeshDataPool //*********************************************************************** @@ -681,3 +674,94 @@ void WgRenderDataEffectParamsPool::release(WgContext& context) mPool.clear(); mList.clear(); } + +//*********************************************************************** +// WgRenderDataStageBuffer +//*********************************************************************** + +void WgRenderDataStageBuffer::append(WgMeshData* meshData) +{ + assert(meshData); + uint32_t vsize = meshData->vbuffer.count * sizeof(meshData->vbuffer[0]); + uint32_t tsize = meshData->tbuffer.count * sizeof(meshData->tbuffer[0]); + uint32_t isize = meshData->ibuffer.count * sizeof(meshData->ibuffer[0]); + // append vertex data + if (vbuffer.reserved < vbuffer.count + vsize) + vbuffer.grow(std::max(vsize, vbuffer.reserved)); + if (meshData->vbuffer.count > 0) { + meshData->voffset = vbuffer.count; + memcpy(vbuffer.data + vbuffer.count, meshData->vbuffer.data, vsize); + vbuffer.count += vsize; + } + // append tex coords data + if (vbuffer.reserved < vbuffer.count + tsize) + vbuffer.grow(std::max(tsize, vbuffer.reserved)); + if (meshData->tbuffer.count > 0) { + meshData->toffset = vbuffer.count; + memcpy(vbuffer.data + vbuffer.count, meshData->tbuffer.data, tsize); + vbuffer.count += tsize; + } + // append index data + if (ibuffer.reserved < ibuffer.count + isize) + ibuffer.grow(std::max(isize, ibuffer.reserved)); + if (meshData->ibuffer.count > 0) { + meshData->ioffset = ibuffer.count; + memcpy(ibuffer.data + ibuffer.count, meshData->ibuffer.data, isize); + ibuffer.count += isize; + } +} + + +void WgRenderDataStageBuffer::append(WgMeshDataGroup* meshDataGroup) +{ + ARRAY_FOREACH(p, meshDataGroup->meshes) append(*p); +} + + +void WgRenderDataStageBuffer::append(WgRenderDataShape* renderDataShape) +{ + append(&renderDataShape->meshGroupShapes); + append(&renderDataShape->meshGroupShapesBBox); + append(&renderDataShape->meshGroupStrokes); + append(&renderDataShape->meshGroupStrokesBBox); + append(&renderDataShape->meshDataBBox); + ARRAY_FOREACH(p, renderDataShape->clips) + append((WgRenderDataShape* )(*p)); +} + + +void WgRenderDataStageBuffer::append(WgRenderDataPicture* renderDataPicture) +{ + append(&renderDataPicture->meshData); + ARRAY_FOREACH(p, renderDataPicture->clips) + append((WgRenderDataShape* )(*p)); +} + + +void WgRenderDataStageBuffer::release(WgContext& context) +{ + context.releaseBuffer(vbuffer_gpu); + context.releaseBuffer(ibuffer_gpu); +} + + +void WgRenderDataStageBuffer::clear() +{ + vbuffer.clear(); + ibuffer.clear(); +} + + +void WgRenderDataStageBuffer::flush(WgContext& context) +{ + context.allocateBufferVertex(vbuffer_gpu, (float *)vbuffer.data, vbuffer.count); + context.allocateBufferIndex(ibuffer_gpu, (uint32_t *)ibuffer.data, ibuffer.count); +} + + +void WgRenderDataStageBuffer::bind(WGPURenderPassEncoder renderPass, size_t voffset, size_t toffset) +{ + wgpuRenderPassEncoderSetVertexBuffer(renderPass, 0, vbuffer_gpu, voffset, vbuffer.count - voffset); + wgpuRenderPassEncoderSetVertexBuffer(renderPass, 1, vbuffer_gpu, toffset, vbuffer.count - toffset); + wgpuRenderPassEncoderSetIndexBuffer(renderPass, ibuffer_gpu, WGPUIndexFormat_Uint32, 0, ibuffer.count); +} diff --git a/src/renderer/wg_engine/tvgWgRenderData.h b/src/renderer/wg_engine/tvgWgRenderData.h index 57f1d6c4..ba3805a2 100644 --- a/src/renderer/wg_engine/tvgWgRenderData.h +++ b/src/renderer/wg_engine/tvgWgRenderData.h @@ -28,22 +28,19 @@ #include "tvgWgShaderTypes.h" struct WgMeshData { - WGPUBuffer bufferPosition{}; - WGPUBuffer bufferTexCoord{}; - WGPUBuffer bufferIndex{}; - size_t vertexCount{}; - size_t indexCount{}; - - void draw(WgContext& context, WGPURenderPassEncoder renderPassEncoder); - void drawFan(WgContext& context, WGPURenderPassEncoder renderPassEncoder); - void drawImage(WgContext& context, WGPURenderPassEncoder renderPassEncoder); + Array vbuffer; + Array tbuffer; + Array ibuffer; + size_t voffset{}; + size_t toffset{}; + size_t ioffset{}; void update(WgContext& context, const WgVertexBuffer& vertexBuffer); void update(WgContext& context, const WgIndexedVertexBuffer& vertexBufferInd); void bbox(WgContext& context, const Point pmin, const Point pmax); void imageBox(WgContext& context, float w, float h); void blitBox(WgContext& context); - void release(WgContext& context); + void release(WgContext& context) {}; }; class WgMeshDataPool { @@ -224,4 +221,23 @@ public: void release(WgContext& context); }; +class WgRenderDataStageBuffer { +private: + Array vbuffer; + Array ibuffer; +public: + WGPUBuffer vbuffer_gpu{}; + WGPUBuffer ibuffer_gpu{}; + + void append(WgMeshData* meshData); + void append(WgMeshDataGroup* meshDataGroup); + void append(WgRenderDataShape* renderDataShape); + void append(WgRenderDataPicture* renderDataPicture); + void initialize(WgContext& context){}; + void release(WgContext& context); + void clear(); + void flush(WgContext& context); + void bind(WGPURenderPassEncoder renderPass, size_t voffset, size_t toffset); +}; + #endif // _TVG_WG_RENDER_DATA_H_ diff --git a/src/renderer/wg_engine/tvgWgRenderTarget.cpp b/src/renderer/wg_engine/tvgWgRenderTarget.cpp index b20542d0..2b31ae3f 100644 --- a/src/renderer/wg_engine/tvgWgRenderTarget.cpp +++ b/src/renderer/wg_engine/tvgWgRenderTarget.cpp @@ -22,7 +22,7 @@ #include "tvgWgRenderTarget.h" -void WgRenderStorage::initialize(WgContext& context, uint32_t width, uint32_t height) +void WgRenderTarget::initialize(WgContext& context, uint32_t width, uint32_t height) { this->width = width; this->height = height; @@ -36,7 +36,7 @@ void WgRenderStorage::initialize(WgContext& context, uint32_t width, uint32_t he } -void WgRenderStorage::release(WgContext& context) +void WgRenderTarget::release(WgContext& context) { context.layouts.releaseBindGroup(bindGroupTexure); context.layouts.releaseBindGroup(bindGroupWrite); @@ -50,38 +50,38 @@ void WgRenderStorage::release(WgContext& context) } //***************************************************************************** -// render storage pool +// render target pool //***************************************************************************** -WgRenderStorage* WgRenderStoragePool::allocate(WgContext& context) +WgRenderTarget* WgRenderTargetPool::allocate(WgContext& context) { - WgRenderStorage* renderStorage{}; + WgRenderTarget* renderTarget{}; if (pool.count > 0) { - renderStorage = pool.last(); + renderTarget = pool.last(); pool.pop(); } else { - renderStorage = new WgRenderStorage; - renderStorage->initialize(context, width, height); - list.push(renderStorage); + renderTarget = new WgRenderTarget; + renderTarget->initialize(context, width, height); + list.push(renderTarget); } - return renderStorage; + return renderTarget; }; -void WgRenderStoragePool::free(WgContext& context, WgRenderStorage* renderStorage) +void WgRenderTargetPool::free(WgContext& context, WgRenderTarget* renderTarget) { - pool.push(renderStorage); + pool.push(renderTarget); }; -void WgRenderStoragePool::initialize(WgContext& context, uint32_t width, uint32_t height) +void WgRenderTargetPool::initialize(WgContext& context, uint32_t width, uint32_t height) { this->width = width; this->height = height; } -void WgRenderStoragePool::release(WgContext& context) +void WgRenderTargetPool::release(WgContext& context) { ARRAY_FOREACH(p, list) { (*p)->release(context); diff --git a/src/renderer/wg_engine/tvgWgRenderTarget.h b/src/renderer/wg_engine/tvgWgRenderTarget.h index 49b975c0..f24c9a04 100644 --- a/src/renderer/wg_engine/tvgWgRenderTarget.h +++ b/src/renderer/wg_engine/tvgWgRenderTarget.h @@ -26,7 +26,7 @@ #include "tvgWgPipelines.h" #include "tvgRender.h" -struct WgRenderStorage { +struct WgRenderTarget { WGPUTexture texture{}; WGPUTexture textureMS{}; WGPUTextureView texView{}; @@ -42,15 +42,15 @@ struct WgRenderStorage { }; -class WgRenderStoragePool { +class WgRenderTargetPool { private: - Array list; - Array pool; + Array list; + Array pool; uint32_t width{}; uint32_t height{}; public: - WgRenderStorage* allocate(WgContext& context); - void free(WgContext& context, WgRenderStorage* renderTarget); + WgRenderTarget* allocate(WgContext& context); + void free(WgContext& context, WgRenderTarget* renderTarget); void initialize(WgContext& context, uint32_t width, uint32_t height); void release(WgContext& context); diff --git a/src/renderer/wg_engine/tvgWgRenderTask.cpp b/src/renderer/wg_engine/tvgWgRenderTask.cpp new file mode 100644 index 00000000..ae74f099 --- /dev/null +++ b/src/renderer/wg_engine/tvgWgRenderTask.cpp @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2025 the ThorVG project. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "tvgWgRenderTask.h" +#include + +//*********************************************************************** +// WgPaintTask +//*********************************************************************** + +void WgPaintTask::run(WgContext& context, WgCompositor& compositor, WGPUCommandEncoder encoder) +{ + if (renderData->type() == tvg::Type::Shape) + compositor.renderShape(context, (WgRenderDataShape*)renderData, blendMethod); + if (renderData->type() == tvg::Type::Picture) + compositor.renderImage(context, (WgRenderDataPicture*)renderData, blendMethod); + else assert(true); +} + +//*********************************************************************** +// WgSceneTask +//*********************************************************************** + +void WgSceneTask::run(WgContext& context, WgCompositor& compositor, WGPUCommandEncoder encoder) +{ + // begin the render pass for the current scene and clear the target content + WGPUColor color{}; + if ((compose->method == MaskMethod::None) && (compose->blend != BlendMethod::Normal)) color = { 1.0, 1.0, 1.0, 0.0 }; + compositor.beginRenderPass(encoder, renderTarget, true, color); + // run all childs (scenes and shapes) + runChildren(context, compositor, encoder); + // we must to end current render pass for current scene + compositor.endRenderPass(); + // we must to apply effect for current scene + if (effect) + runEffect(context, compositor, encoder); + // there's no point in continuing if the scene has no destination target (e.g., the root scene) + if (!renderTargetDst) return; + // apply scene blending + if (compose->method == MaskMethod::None) { + compositor.beginRenderPass(encoder, renderTargetDst, false); + compositor.renderScene(context, renderTarget, compose); + // apply scene composition (for scenes, that have a handle to mask) + } else if (renderTargetMsk) { + compositor.beginRenderPass(encoder, renderTargetDst, false); + compositor.composeScene(context, renderTarget, renderTargetMsk, compose); + } +} + + +void WgSceneTask::runChildren(WgContext& context, WgCompositor& compositor, WGPUCommandEncoder encoder) +{ + ARRAY_FOREACH(task, children) { + WgRenderTask* renderTask = *task; + // we need to restore current render pass without clear + compositor.beginRenderPass(encoder, renderTarget, false); + // run children (shape or scene) + renderTask->run(context, compositor, encoder); + } +} + + +void WgSceneTask::runEffect(WgContext& context, WgCompositor& compositor, WGPUCommandEncoder encoder) +{ + assert(effect); + switch (effect->type) { + case SceneEffect::GaussianBlur: compositor.gaussianBlur(context, renderTarget, (RenderEffectGaussianBlur*)effect, compose); break; + case SceneEffect::DropShadow: compositor.dropShadow(context, renderTarget, (RenderEffectDropShadow*)effect, compose); break; + case SceneEffect::Fill: compositor.fillEffect(context, renderTarget, (RenderEffectFill*)effect, compose); break; + case SceneEffect::Tint: compositor.tintEffect(context, renderTarget, (RenderEffectTint*)effect, compose); break; + case SceneEffect::Tritone : compositor.tritoneEffect(context, renderTarget, (RenderEffectTritone*)effect, compose); break; + default: break; + } +} diff --git a/src/renderer/wg_engine/tvgWgRenderTask.h b/src/renderer/wg_engine/tvgWgRenderTask.h new file mode 100644 index 00000000..f9786d40 --- /dev/null +++ b/src/renderer/wg_engine/tvgWgRenderTask.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2025 the ThorVG project. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef _TVG_WG_RENDER_TASK_H_ +#define _TVG_WG_RENDER_TASK_H_ + +#include "tvgWgCompositor.h" + +// base class for any renderable objects +struct WgRenderTask { + virtual ~WgRenderTask() {} + virtual void run(WgContext& context, WgCompositor& compositor, WGPUCommandEncoder encoder) = 0; +}; + +// task for sinlge shape rendering +struct WgPaintTask: public WgRenderTask { + // shape render properties + WgRenderDataPaint* renderData{}; + BlendMethod blendMethod{}; + + WgPaintTask(WgRenderDataPaint* renderData, BlendMethod blendMethod) : + renderData(renderData), blendMethod(blendMethod) {} + // apply shape execution, including custom blending and clipping + void run(WgContext& context, WgCompositor& compositor, WGPUCommandEncoder encoder) override; +}; + +// task for scene rendering with blending, composition and effect +struct WgSceneTask: public WgRenderTask { +public: + // parent scene (nullptr for root scene) + WgSceneTask* parent{}; + // childs can be shapes or scenes tesks + Array children; + // scene blend/compose targets + WgRenderTarget* renderTarget{}; + WgRenderTarget* renderTargetMsk{}; + WgRenderTarget* renderTargetDst{}; + // scene blend/compose properties + WgCompose* compose{}; + // scene effect properties + const RenderEffect* effect{}; + + WgSceneTask(WgRenderTarget* renderTarget, WgCompose* compose, WgSceneTask* parent) : + parent(parent), renderTarget(renderTarget), compose(compose) {} + // run all, including all shapes drawing, blending, composition and effect + void run(WgContext& context, WgCompositor& compositor, WGPUCommandEncoder encoder) override; +private: + void runChildren(WgContext& context, WgCompositor& compositor, WGPUCommandEncoder encoder); + void runEffect(WgContext& context, WgCompositor& compositor, WGPUCommandEncoder encoder); +}; + + #endif // _TVG_WG_RENDER_TASK_H_ + \ No newline at end of file diff --git a/src/renderer/wg_engine/tvgWgRenderer.cpp b/src/renderer/wg_engine/tvgWgRenderer.cpp index f4f9374a..af860865 100644 --- a/src/renderer/wg_engine/tvgWgRenderer.cpp +++ b/src/renderer/wg_engine/tvgWgRenderer.cpp @@ -47,13 +47,13 @@ void WgRenderer::release() mRenderDataEffectParamsPool.release(mContext); WgMeshDataPool::gMeshDataPool->release(mContext); - // clear render storage pool - mRenderStoragePool.release(mContext); + // clear render pool + mRenderTargetPool.release(mContext); // clear rendering tree stacks - mCompositorStack.clear(); - mRenderStorageStack.clear(); - mRenderStorageRoot.release(mContext); + mCompositorList.clear(); + mRenderTargetStack.clear(); + mRenderTargetRoot.release(mContext); // release context handles mCompositor.release(mContext); @@ -195,50 +195,71 @@ RenderData WgRenderer::prepare(RenderSurface* surface, RenderData data, const Ma bool WgRenderer::preRender() { + // invalidate context if (mContext.invalid()) return false; - - // push rot render storage to the render tree stack - assert(mRenderStorageStack.count == 0); - mRenderStorageStack.push(&mRenderStorageRoot); - // create command encoder for drawing - WGPUCommandEncoderDescriptor commandEncoderDesc{}; - mCommandEncoder = wgpuDeviceCreateCommandEncoder(mContext.device, &commandEncoderDesc); - // start root render pass - mCompositor.beginRenderPass(mCommandEncoder, mRenderStorageStack.last(), true); + // reset stage data + mCompositor.reset(mContext); + // push root render target to the render tree stack + assert(mRenderTargetStack.count == 0); + mRenderTargetStack.push(&mRenderTargetRoot); + // create root compose settings + WgCompose* compose = new WgCompose(); + compose->aabb = { { 0, 0 }, { (int32_t)mTargetSurface.w, (int32_t)mTargetSurface.h } }; + compose->blend = BlendMethod::Normal; + compose->method = MaskMethod::None; + compose->opacity = 255; + mCompositorList.push(compose); + // create root scene + WgSceneTask* sceneTask = new WgSceneTask(&mRenderTargetRoot, compose, nullptr); + mRenderTaskList.push(sceneTask); + mSceneTaskStack.push(sceneTask); return true; } bool WgRenderer::renderShape(RenderData data) { - // temporary simple render data to the current render target - mCompositor.renderShape(mContext, (WgRenderDataShape*)data, mBlendMethod); + WgPaintTask* paintTask = new WgPaintTask((WgRenderDataPaint*)data, mBlendMethod); + WgSceneTask* sceneTask = mSceneTaskStack.last(); + sceneTask->children.push(paintTask); + mRenderTaskList.push(paintTask); + mCompositor.requestShape((WgRenderDataShape*)data); return true; } bool WgRenderer::renderImage(RenderData data) { - // temporary simple render data to the current render target - mCompositor.renderImage(mContext, (WgRenderDataPicture*)data, mBlendMethod); + WgPaintTask* paintTask = new WgPaintTask((WgRenderDataPaint*)data, mBlendMethod); + WgSceneTask* sceneTask = mSceneTaskStack.last(); + sceneTask->children.push(paintTask); + mRenderTaskList.push(paintTask); + mCompositor.requestImage((WgRenderDataPicture*)data); return true; } bool WgRenderer::postRender() { - // end root render pass - mCompositor.endRenderPass(); - // release command encoder - const WGPUCommandBufferDescriptor commandBufferDesc{}; - WGPUCommandBuffer commandsBuffer = wgpuCommandEncoderFinish(mCommandEncoder, &commandBufferDesc); - wgpuQueueSubmit(mContext.queue, 1, &commandsBuffer); - wgpuCommandBufferRelease(commandsBuffer); - wgpuCommandEncoderRelease(mCommandEncoder); - // pop root render storage to the render tree stack - mRenderStorageStack.pop(); - assert(mRenderStorageStack.count == 0); - // clear viewport list and store allocated handles to pool + // flush stage data to gpu + mCompositor.flush(mContext); + // create command encoder for drawing + WGPUCommandEncoder commandEncoder = mContext.createCommandEncoder(); + // run rendering (all the fun is here) + WgSceneTask* sceneTaskRoot = mSceneTaskStack.last(); + sceneTaskRoot->run(mContext, mCompositor, commandEncoder); + // execute and release command encoder + mContext.submitCommandEncoder(commandEncoder); + mContext.releaseCommandEncoder(commandEncoder); + // clear the render tasks tree + mSceneTaskStack.pop(); + assert(mSceneTaskStack.count == 0); + mRenderTargetStack.pop(); + assert(mRenderTargetStack.count == 0); + ARRAY_FOREACH(p, mRenderTaskList) { delete (*p); }; + mRenderTaskList.clear(); + ARRAY_FOREACH(p, mCompositorList) { delete (*p); }; + mCompositorList.clear(); ARRAY_FOREACH(p, mRenderDataViewportList) mRenderDataViewportPool.free(mContext, *p); mRenderDataViewportList.clear(); @@ -325,18 +346,11 @@ bool WgRenderer::sync() WGPUTextureView dstTextureView = mContext.createTextureView(dstTexture); // create command encoder - const WGPUCommandEncoderDescriptor commandEncoderDesc{}; - WGPUCommandEncoder commandEncoder = wgpuDeviceCreateCommandEncoder(mContext.device, &commandEncoderDesc); - + WGPUCommandEncoder commandEncoder = mContext.createCommandEncoder(); // show root offscreen buffer - mCompositor.blit(mContext, commandEncoder, &mRenderStorageRoot, dstTextureView); - - // release command encoder - const WGPUCommandBufferDescriptor commandBufferDesc{}; - WGPUCommandBuffer commandsBuffer = wgpuCommandEncoderFinish(commandEncoder, &commandBufferDesc); - wgpuQueueSubmit(mContext.queue, 1, &commandsBuffer); - wgpuCommandBufferRelease(commandsBuffer); - wgpuCommandEncoderRelease(commandEncoder); + mCompositor.blit(mContext, commandEncoder, &mRenderTargetRoot, dstTextureView); + mContext.submitCommandEncoder(commandEncoder); + mContext.releaseCommandEncoder(commandEncoder); // release dest buffer view mContext.releaseTextureView(dstTextureView); @@ -367,8 +381,8 @@ bool WgRenderer::target(WGPUDevice device, WGPUInstance instance, void* target, mContext.initialize(instance, device); // initialize render tree instances - mRenderStoragePool.initialize(mContext, width, height); - mRenderStorageRoot.initialize(mContext, width, height); + mRenderTargetPool.initialize(mContext, width, height); + mRenderTargetRoot.initialize(mContext, width, height); mCompositor.initialize(mContext, width, height); // store target properties @@ -387,12 +401,12 @@ bool WgRenderer::target(WGPUDevice device, WGPUInstance instance, void* target, // update render targets dimentions if ((mTargetSurface.w != width) || (mTargetSurface.h != height) || (type == 0 ? (surface != (WGPUSurface)target) : (targetTexture != (WGPUTexture)target))) { // release render tagets - mRenderStoragePool.release(mContext); - mRenderStorageRoot.release(mContext); + mRenderTargetPool.release(mContext); + mRenderTargetRoot.release(mContext); clearTargets(); - mRenderStoragePool.initialize(mContext, width, height); - mRenderStorageRoot.initialize(mContext, width, height); + mRenderTargetPool.initialize(mContext, width, height); + mRenderTargetRoot.initialize(mContext, width, height); mCompositor.resize(mContext, width, height); // store target properties @@ -447,7 +461,7 @@ RenderCompositor* WgRenderer::target(const RenderRegion& region, TVG_UNUSED Colo compose->rdViewport->update(mContext, region); mRenderDataViewportList.push(compose->rdViewport); } - mCompositorStack.push(compose); + mCompositorList.push(compose); return compose; } @@ -459,57 +473,52 @@ bool WgRenderer::beginComposite(RenderCompositor* cmp, MaskMethod method, uint8_ compose->method = method; compose->opacity = opacity; compose->blend = mBlendMethod; - // end current render pass - mCompositor.endRenderPass(); - // allocate new render storage and push to the render tree stack - WgRenderStorage* storage = mRenderStoragePool.allocate(mContext); - mRenderStorageStack.push(storage); - // begin newly added render pass - WGPUColor color{}; - if ((compose->method == MaskMethod::None) && (compose->blend != BlendMethod::Normal)) color = { 1.0, 1.0, 1.0, 0.0 }; - mCompositor.beginRenderPass(mCommandEncoder, mRenderStorageStack.last(), true, color); + WgSceneTask* sceneTaskCurrent = mSceneTaskStack.last(); + // allocate new render target and push to the render tree stack + WgRenderTarget* renderTarget = mRenderTargetPool.allocate(mContext); + mRenderTargetStack.push(renderTarget); + // create and setup new scene task + WgSceneTask* sceneTask = new WgSceneTask(renderTarget, compose, sceneTaskCurrent); + sceneTaskCurrent->children.push(sceneTask); + mRenderTaskList.push(sceneTask); + mSceneTaskStack.push(sceneTask); return true; } bool WgRenderer::endComposite(RenderCompositor* cmp) { - // get current composition settings - WgCompose* comp = (WgCompose*)cmp; - // we must to end current render pass to run blend/composition mechanics - mCompositor.endRenderPass(); // finish scene blending - if (comp->method == MaskMethod::None) { - // get source and destination render storages - WgRenderStorage* src = mRenderStorageStack.last(); - mRenderStorageStack.pop(); - WgRenderStorage* dst = mRenderStorageStack.last(); - // begin previous render pass - mCompositor.beginRenderPass(mCommandEncoder, dst, false); - // apply composition - mCompositor.renderScene(mContext, src, comp); + if (cmp->method == MaskMethod::None) { + // get source and destination render targets + WgRenderTarget* src = mRenderTargetStack.last(); + mRenderTargetStack.pop(); + // pop source scene + WgSceneTask* srcScene = mSceneTaskStack.last(); + mSceneTaskStack.pop(); + // setup render target compose destitations + srcScene->renderTargetDst = mSceneTaskStack.last()->renderTarget; + srcScene->renderTargetMsk = nullptr; // back render targets to the pool - mRenderStoragePool.free(mContext, src); - } else { // finish composition - // get source, mask and destination render storages - WgRenderStorage* src = mRenderStorageStack.last(); - mRenderStorageStack.pop(); - WgRenderStorage* msk = mRenderStorageStack.last(); - mRenderStorageStack.pop(); - WgRenderStorage* dst = mRenderStorageStack.last(); - // begin previous render pass - mCompositor.beginRenderPass(mCommandEncoder, dst, false); - // apply composition - mCompositor.composeScene(mContext, src, msk, comp); + mRenderTargetPool.free(mContext, src); + } else { // finish scene composition + // get source, mask and destination render targets + WgRenderTarget* src = mRenderTargetStack.last(); + mRenderTargetStack.pop(); + WgRenderTarget* msk = mRenderTargetStack.last(); + mRenderTargetStack.pop(); + // get source and mask scenes + WgSceneTask* srcScene = mSceneTaskStack.last(); + mSceneTaskStack.pop(); + WgSceneTask* mskScene = mSceneTaskStack.last(); + mSceneTaskStack.pop(); + // setup render target compose destitations + srcScene->renderTargetDst = mSceneTaskStack.last()->renderTarget; + srcScene->renderTargetMsk = mskScene->renderTarget; // back render targets to the pool - mRenderStoragePool.free(mContext, src); - mRenderStoragePool.free(mContext, msk); + mRenderTargetPool.free(mContext, src); + mRenderTargetPool.free(mContext, msk); } - - // delete current compositor settings - delete mCompositorStack.last(); - mCompositorStack.pop(); - return true; } @@ -606,20 +615,8 @@ bool WgRenderer::region(RenderEffect* effect) bool WgRenderer::render(RenderCompositor* cmp, const RenderEffect* effect, TVG_UNUSED bool direct) { - // we must to end current render pass to resolve ms texture before effect - mCompositor.endRenderPass(); - WgCompose* comp = (WgCompose*)cmp; - WgRenderStorage* dst = mRenderStorageStack.last(); - - switch (effect->type) { - case SceneEffect::GaussianBlur: return mCompositor.gaussianBlur(mContext, dst, (RenderEffectGaussianBlur*)effect, comp); - case SceneEffect::DropShadow: return mCompositor.dropShadow(mContext, dst, (RenderEffectDropShadow*)effect, comp); - case SceneEffect::Fill: return mCompositor.fillEffect(mContext, dst, (RenderEffectFill*)effect, comp); - case SceneEffect::Tint: return mCompositor.tintEffect(mContext, dst, (RenderEffectTint*)effect, comp); - case SceneEffect::Tritone : return mCompositor.tritoneEffect(mContext, dst, (RenderEffectTritone*)effect, comp); - default: return false; - } - return false; + mSceneTaskStack.last()->effect = effect; + return true; } diff --git a/src/renderer/wg_engine/tvgWgRenderer.h b/src/renderer/wg_engine/tvgWgRenderer.h index d82c9322..50825279 100644 --- a/src/renderer/wg_engine/tvgWgRenderer.h +++ b/src/renderer/wg_engine/tvgWgRenderer.h @@ -23,7 +23,7 @@ #ifndef _TVG_WG_RENDERER_H_ #define _TVG_WG_RENDERER_H_ -#include "tvgWgCompositor.h" +#include "tvgWgRenderTask.h" class WgRenderer : public RenderMethod { @@ -72,13 +72,15 @@ private: bool surfaceConfigure(WGPUSurface surface, WgContext& context, uint32_t width, uint32_t height); // render tree stacks - WgRenderStorage mRenderStorageRoot; - Array mCompositorStack; - Array mRenderStorageStack; + WgRenderTarget mRenderTargetRoot; + Array mCompositorList; + Array mRenderTargetStack; Array mRenderDataViewportList; + Array mSceneTaskStack; + Array mRenderTaskList; - // render storage pool - WgRenderStoragePool mRenderStoragePool; + // render target pool + WgRenderTargetPool mRenderTargetPool; // render data paint pools WgRenderDataShapePool mRenderDataShapePool; @@ -100,7 +102,6 @@ private: Key mDisposeKey{}; // gpu handles - WGPUCommandEncoder mCommandEncoder{}; WGPUTexture targetTexture{}; // external handle WGPUSurfaceTexture surfaceTexture{}; WGPUSurface surface{}; // external handle