From 92e3c243ec5ec890150c5d575f1eb483a53ddab0 Mon Sep 17 00:00:00 2001 From: Sergii Liebodkin Date: Wed, 11 Jun 2025 01:29:25 +0300 Subject: [PATCH] wg_engine: uniform stage buffers implementation Introduced stage buffer for uniforms to reduce number of memory shafles from cpu to gpu memory https://github.com/thorvg/thorvg/issues/3505 --- src/renderer/wg_engine/tvgWgBindGroups.cpp | 8 +- src/renderer/wg_engine/tvgWgBindGroups.h | 1 + src/renderer/wg_engine/tvgWgCompositor.cpp | 156 +++++++++++--------- src/renderer/wg_engine/tvgWgCompositor.h | 3 +- src/renderer/wg_engine/tvgWgPipelines.cpp | 18 +-- src/renderer/wg_engine/tvgWgRenderData.cpp | 130 +++++++--------- src/renderer/wg_engine/tvgWgRenderData.h | 74 +++++++--- src/renderer/wg_engine/tvgWgRenderer.cpp | 16 +- src/renderer/wg_engine/tvgWgShaderSrc.cpp | 133 ++++++++--------- src/renderer/wg_engine/tvgWgShaderTypes.cpp | 71 +++++---- src/renderer/wg_engine/tvgWgShaderTypes.h | 44 +++++- 11 files changed, 354 insertions(+), 300 deletions(-) diff --git a/src/renderer/wg_engine/tvgWgBindGroups.cpp b/src/renderer/wg_engine/tvgWgBindGroups.cpp index e25e4181..20cab5d4 100644 --- a/src/renderer/wg_engine/tvgWgBindGroups.cpp +++ b/src/renderer/wg_engine/tvgWgBindGroups.cpp @@ -103,9 +103,15 @@ WGPUBindGroup WgBindGroupLayouts::createBindGroupStrorage3RO(WGPUTextureView tex WGPUBindGroup WgBindGroupLayouts::createBindGroupBuffer1Un(WGPUBuffer buff) +{ + return createBindGroupBuffer1Un(buff, 0, wgpuBufferGetSize(buff)); +} + + +WGPUBindGroup WgBindGroupLayouts::createBindGroupBuffer1Un(WGPUBuffer buff, uint64_t offset, uint64_t size) { const WGPUBindGroupEntry bindGroupEntrys[] = { - { .binding = 0, .buffer = buff, .size = wgpuBufferGetSize(buff) } + { .binding = 0, .buffer = buff, .offset = offset, .size = size } }; const WGPUBindGroupDescriptor bindGroupDesc { .layout = layoutBuffer1Un, .entryCount = 1, .entries = bindGroupEntrys }; return wgpuDeviceCreateBindGroup(device, &bindGroupDesc); diff --git a/src/renderer/wg_engine/tvgWgBindGroups.h b/src/renderer/wg_engine/tvgWgBindGroups.h index 9bab0e77..ac959700 100644 --- a/src/renderer/wg_engine/tvgWgBindGroups.h +++ b/src/renderer/wg_engine/tvgWgBindGroups.h @@ -49,6 +49,7 @@ public: WGPUBindGroup createBindGroupStrorage2RO(WGPUTextureView texView0, WGPUTextureView texView1); WGPUBindGroup createBindGroupStrorage3RO(WGPUTextureView texView0, WGPUTextureView texView1, WGPUTextureView texView2); WGPUBindGroup createBindGroupBuffer1Un(WGPUBuffer buff); + WGPUBindGroup createBindGroupBuffer1Un(WGPUBuffer buff, uint64_t offset, uint64_t size); WGPUBindGroup createBindGroupBuffer2Un(WGPUBuffer buff0, WGPUBuffer buff1); WGPUBindGroup createBindGroupBuffer3Un(WGPUBuffer buff0, WGPUBuffer buff1, WGPUBuffer buff2); void releaseBindGroup(WGPUBindGroup& bindGroup); diff --git a/src/renderer/wg_engine/tvgWgCompositor.cpp b/src/renderer/wg_engine/tvgWgCompositor.cpp index 071fd3a0..af8f7f15 100644 --- a/src/renderer/wg_engine/tvgWgCompositor.cpp +++ b/src/renderer/wg_engine/tvgWgCompositor.cpp @@ -28,7 +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); + stageBufferGeometry.initialize(context); // initialize opacity pool initPools(context); // allocate global view matrix handles @@ -64,7 +64,8 @@ void WgCompositor::release(WgContext& context) context.layouts.releaseBindGroup(bindGroupViewMat); context.releaseBuffer(bufferViewMat); // release stage buffer - stageBuffer.release(context); + stageBufferPaint.release(context); + stageBufferGeometry.release(context); // release pipelines pipelines.release(context); } @@ -190,28 +191,35 @@ void WgCompositor::endRenderPass() void WgCompositor::reset(WgContext& context) { - stageBuffer.clear(); + stageBufferGeometry.clear(); + stageBufferPaint.clear(); } void WgCompositor::flush(WgContext& context) { - stageBuffer.append(&meshDataBlit); - stageBuffer.flush(context); + stageBufferGeometry.append(&meshDataBlit); + stageBufferGeometry.flush(context); + stageBufferPaint.flush(context); } void WgCompositor::requestShape(WgRenderDataShape* renderData) { - stageBuffer.append(renderData); - // TODO: expand for fill settings + stageBufferGeometry.append(renderData); + renderData->renderSettingsShape.bindGroupInd = stageBufferPaint.append(renderData->renderSettingsShape.settings); + renderData->renderSettingsStroke.bindGroupInd = stageBufferPaint.append(renderData->renderSettingsStroke.settings); + ARRAY_FOREACH(p, renderData->clips) + requestShape((WgRenderDataShape* )(*p)); } void WgCompositor::requestImage(WgRenderDataPicture* renderData) { - stageBuffer.append(renderData); - // TODO: expand for fill settings + stageBufferGeometry.append(renderData); + renderData->renderSettings.bindGroupInd = stageBufferPaint.append(renderData->renderSettings.settings); + ARRAY_FOREACH(p, renderData->clips) + requestShape((WgRenderDataShape* )(*p)); } @@ -332,8 +340,8 @@ void WgCompositor::drawMesh(WgContext& context, WgMeshData* meshData) 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); + wgpuRenderPassEncoderSetVertexBuffer(renderPassEncoder, 0, stageBufferGeometry.vbuffer_gpu, meshData->voffset, vsize); + wgpuRenderPassEncoderSetIndexBuffer(renderPassEncoder, stageBufferGeometry.ibuffer_gpu, WGPUIndexFormat_Uint32, meshData->ioffset, isize); wgpuRenderPassEncoderDrawIndexed(renderPassEncoder, icount, 1, 0, 0, 0); }; @@ -345,7 +353,7 @@ void WgCompositor::drawMeshFan(WgContext& context, WgMeshData* meshData) 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); + wgpuRenderPassEncoderSetVertexBuffer(renderPassEncoder, 0, stageBufferGeometry.vbuffer_gpu, meshData->voffset, vsize); wgpuRenderPassEncoderSetIndexBuffer(renderPassEncoder, context.bufferIndexFan, WGPUIndexFormat_Uint32, 0, isize); wgpuRenderPassEncoderDrawIndexed(renderPassEncoder, icount, 1, 0, 0, 0); }; @@ -358,9 +366,9 @@ void WgCompositor::drawMeshImage(WgContext& context, WgMeshData* meshData) 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); + wgpuRenderPassEncoderSetVertexBuffer(renderPassEncoder, 0, stageBufferGeometry.vbuffer_gpu, meshData->voffset, vsize); + wgpuRenderPassEncoderSetVertexBuffer(renderPassEncoder, 1, stageBufferGeometry.vbuffer_gpu, meshData->toffset, vsize); + wgpuRenderPassEncoderSetIndexBuffer(renderPassEncoder, stageBufferGeometry.ibuffer_gpu, WGPUIndexFormat_Uint32, meshData->ioffset, isize); wgpuRenderPassEncoderDrawIndexed(renderPassEncoder, icount, 1, 0, 0, 0); }; @@ -371,12 +379,13 @@ void WgCompositor::drawShape(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; + WgRenderSettings& settings = renderData->renderSettingsShape; wgpuRenderPassEncoderSetScissorRect(renderPassEncoder, renderData->viewport.x(), renderData->viewport.y(), renderData->viewport.w(), renderData->viewport.h()); // setup stencil rules WGPURenderPipeline stencilPipeline = (renderData->fillRule == FillRule::NonZero) ? pipelines.nonzero : pipelines.evenodd; wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 0, bindGroupViewMat, 0, nullptr); - wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, renderData->bindGroupPaint, 0, nullptr); + wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, stageBufferPaint[settings.bindGroupInd], 0, nullptr); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, stencilPipeline); // draw to stencil (first pass) ARRAY_FOREACH(p, renderData->meshGroupShapes.meshes) @@ -384,16 +393,15 @@ void WgCompositor::drawShape(WgContext& context, WgRenderDataShape* renderData) // setup fill rules wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 0, bindGroupViewMat, 0, nullptr); - wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, renderData->bindGroupPaint, 0, nullptr); - WgRenderSettings& settings = renderData->renderSettingsShape; + wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, stageBufferPaint[settings.bindGroupInd], 0, nullptr); if (settings.fillType == WgRenderSettingsType::Solid) { - wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, settings.bindGroupSolid, 0, nullptr); + wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, stageBufferPaint[settings.bindGroupInd], 0, nullptr); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.solid); } else if (settings.fillType == WgRenderSettingsType::Linear) { - wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, settings.bindGroupGradient, 0, nullptr); + wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, settings.gradientData.bindGroup, 0, nullptr); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.linear); } else if (settings.fillType == WgRenderSettingsType::Radial) { - wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, settings.bindGroupGradient, 0, nullptr); + wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, settings.gradientData.bindGroup, 0, nullptr); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.radial); } // draw to color (second pass) @@ -407,6 +415,7 @@ 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; + WgRenderSettings& settings = renderData->renderSettingsShape; // copy current render target data to dst target WgRenderTarget *target = currentTarget; endRenderPass(); @@ -418,7 +427,7 @@ void WgCompositor::blendShape(WgContext& context, WgRenderDataShape* renderData, WGPURenderPipeline stencilPipeline = (renderData->fillRule == FillRule::NonZero) ? pipelines.nonzero : pipelines.evenodd; wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 0, bindGroupViewMat, 0, nullptr); - wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, renderData->bindGroupPaint, 0, nullptr); + wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, stageBufferPaint[settings.bindGroupInd], 0, nullptr); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, stencilPipeline); // draw to stencil (first pass) ARRAY_FOREACH(p, renderData->meshGroupShapes.meshes) @@ -426,18 +435,17 @@ void WgCompositor::blendShape(WgContext& context, WgRenderDataShape* renderData, // setup fill rules wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 0, bindGroupViewMat, 0, nullptr); - wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, renderData->bindGroupPaint, 0, nullptr); + wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, stageBufferPaint[settings.bindGroupInd], 0, nullptr); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 3, targetTemp0.bindGroupTexure, 0, nullptr); uint32_t blendMethodInd = (uint32_t)blendMethod; - WgRenderSettings& settings = renderData->renderSettingsShape; if (settings.fillType == WgRenderSettingsType::Solid) { - wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, settings.bindGroupSolid, 0, nullptr); + wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, stageBufferPaint[settings.bindGroupInd], 0, nullptr); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.solid_blend[blendMethodInd]); } else if (settings.fillType == WgRenderSettingsType::Linear) { - wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, settings.bindGroupGradient, 0, nullptr); + wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, settings.gradientData.bindGroup, 0, nullptr); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.linear_blend[blendMethodInd]); } else if (settings.fillType == WgRenderSettingsType::Radial) { - wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, settings.bindGroupGradient, 0, nullptr); + wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, settings.gradientData.bindGroup, 0, nullptr); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.radial_blend[blendMethodInd]); } // draw to color (second pass) @@ -451,13 +459,13 @@ void WgCompositor::clipShape(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; - + WgRenderSettings& settings = renderData->renderSettingsShape; wgpuRenderPassEncoderSetScissorRect(renderPassEncoder, renderData->viewport.x(), renderData->viewport.y(), renderData->viewport.w(), renderData->viewport.h()); // setup stencil rules WGPURenderPipeline stencilPipeline = (renderData->fillRule == FillRule::NonZero) ? pipelines.nonzero : pipelines.evenodd; wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 0, bindGroupViewMat, 0, nullptr); - wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, renderData->bindGroupPaint, 0, nullptr); + wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, stageBufferPaint[settings.bindGroupInd], 0, nullptr); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, stencilPipeline); // draw to stencil (first pass) ARRAY_FOREACH(p, renderData->meshGroupShapes.meshes) @@ -470,16 +478,15 @@ void WgCompositor::clipShape(WgContext& context, WgRenderDataShape* renderData) // setup fill rules wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 0, bindGroupViewMat, 0, nullptr); - wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, renderData->bindGroupPaint, 0, nullptr); - WgRenderSettings& settings = renderData->renderSettingsShape; + wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, stageBufferPaint[settings.bindGroupInd], 0, nullptr); if (settings.fillType == WgRenderSettingsType::Solid) { - wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, settings.bindGroupSolid, 0, nullptr); + wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, stageBufferPaint[settings.bindGroupInd], 0, nullptr); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.solid); } else if (settings.fillType == WgRenderSettingsType::Linear) { - wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, settings.bindGroupGradient, 0, nullptr); + wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, settings.gradientData.bindGroup, 0, nullptr); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.linear); } else if (settings.fillType == WgRenderSettingsType::Radial) { - wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, settings.bindGroupGradient, 0, nullptr); + wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, settings.gradientData.bindGroup, 0, nullptr); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.radial); } // draw to color (second pass) @@ -493,30 +500,29 @@ void WgCompositor::drawStrokes(WgContext& context, WgRenderDataShape* renderData assert(renderPassEncoder); assert(renderData->meshGroupStrokes.meshes.count == renderData->meshGroupStrokesBBox.meshes.count); if (renderData->renderSettingsStroke.skip || renderData->meshGroupStrokes.meshes.count == 0 || renderData->viewport.invalid()) return; - + WgRenderSettings& settings = renderData->renderSettingsStroke; wgpuRenderPassEncoderSetScissorRect(renderPassEncoder, renderData->viewport.x(), renderData->viewport.y(), renderData->viewport.w(), renderData->viewport.h()); // draw strokes to stencil (first pass) for (uint32_t i = 0; i < renderData->meshGroupStrokes.meshes.count; i++) { // setup stencil rules wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 255); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 0, bindGroupViewMat, 0, nullptr); - wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, renderData->bindGroupPaint, 0, nullptr); + wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, stageBufferPaint[settings.bindGroupInd], 0, nullptr); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.direct); // draw to stencil (first pass) 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); - WgRenderSettings& settings = renderData->renderSettingsStroke; + wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, stageBufferPaint[settings.bindGroupInd], 0, nullptr); if (settings.fillType == WgRenderSettingsType::Solid) { - wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, settings.bindGroupSolid, 0, nullptr); + wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, stageBufferPaint[settings.bindGroupInd], 0, nullptr); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.solid); } else if (settings.fillType == WgRenderSettingsType::Linear) { - wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, settings.bindGroupGradient, 0, nullptr); + wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, settings.gradientData.bindGroup, 0, nullptr); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.linear); } else if (settings.fillType == WgRenderSettingsType::Radial) { - wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, settings.bindGroupGradient, 0, nullptr); + wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, settings.gradientData.bindGroup, 0, nullptr); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.radial); } // draw to color (second pass) @@ -531,7 +537,7 @@ void WgCompositor::blendStrokes(WgContext& context, WgRenderDataShape* renderDat assert(renderPassEncoder); assert(renderData->meshGroupStrokes.meshes.count == renderData->meshGroupStrokesBBox.meshes.count); if (renderData->renderSettingsStroke.skip || renderData->meshGroupStrokes.meshes.count == 0 || renderData->viewport.invalid()) return; - + WgRenderSettings& settings = renderData->renderSettingsStroke; // copy current render target data to dst target WgRenderTarget *target = currentTarget; endRenderPass(); @@ -543,25 +549,24 @@ void WgCompositor::blendStrokes(WgContext& context, WgRenderDataShape* renderDat // setup stencil rules wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 255); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 0, bindGroupViewMat, 0, nullptr); - wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, renderData->bindGroupPaint, 0, nullptr); + wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, stageBufferPaint[settings.bindGroupInd], 0, nullptr); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.direct); // draw to stencil (first pass) 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, 1, stageBufferPaint[settings.bindGroupInd], 0, nullptr); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 3, targetTemp0.bindGroupTexure, 0, nullptr); uint32_t blendMethodInd = (uint32_t)blendMethod; - WgRenderSettings& settings = renderData->renderSettingsStroke; if (settings.fillType == WgRenderSettingsType::Solid) { - wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, settings.bindGroupSolid, 0, nullptr); + wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, stageBufferPaint[settings.bindGroupInd], 0, nullptr); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.solid_blend[blendMethodInd]); } else if (settings.fillType == WgRenderSettingsType::Linear) { - wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, settings.bindGroupGradient, 0, nullptr); + wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, settings.gradientData.bindGroup, 0, nullptr); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.linear_blend[blendMethodInd]); } else if (settings.fillType == WgRenderSettingsType::Radial) { - wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, settings.bindGroupGradient, 0, nullptr); + wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, settings.gradientData.bindGroup, 0, nullptr); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.radial_blend[blendMethodInd]); } // draw to color (second pass) @@ -578,13 +583,14 @@ void WgCompositor::clipStrokes(WgContext& context, WgRenderDataShape* renderData if (renderData->renderSettingsStroke.skip) return; if (renderData->meshGroupStrokes.meshes.count == 0) return; if (renderData->viewport.invalid()) return; + WgRenderSettings& settings = renderData->renderSettingsStroke; wgpuRenderPassEncoderSetScissorRect(renderPassEncoder, renderData->viewport.x(), renderData->viewport.y(), renderData->viewport.w(), renderData->viewport.h()); // draw strokes to stencil (first pass) for (uint32_t i = 0; i < renderData->meshGroupStrokes.meshes.count; i++) { // setup stencil rules wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 255); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 0, bindGroupViewMat, 0, nullptr); - wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, renderData->bindGroupPaint, 0, nullptr); + wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, stageBufferPaint[settings.bindGroupInd], 0, nullptr); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.direct); // draw to stencil (first pass) drawMesh(context, renderData->meshGroupStrokes.meshes[i]); @@ -596,16 +602,15 @@ void WgCompositor::clipStrokes(WgContext& context, WgRenderDataShape* renderData // setup fill rules wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 0, bindGroupViewMat, 0, nullptr); - wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, renderData->bindGroupPaint, 0, nullptr); - WgRenderSettings& settings = renderData->renderSettingsStroke; + wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, stageBufferPaint[settings.bindGroupInd], 0, nullptr); if (settings.fillType == WgRenderSettingsType::Solid) { - wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, settings.bindGroupSolid, 0, nullptr); + wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, stageBufferPaint[settings.bindGroupInd], 0, nullptr); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.solid); } else if (settings.fillType == WgRenderSettingsType::Linear) { - wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, settings.bindGroupGradient, 0, nullptr); + wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, settings.gradientData.bindGroup, 0, nullptr); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.linear); } else if (settings.fillType == WgRenderSettingsType::Radial) { - wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, settings.bindGroupGradient, 0, nullptr); + wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, settings.gradientData.bindGroup, 0, nullptr); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.radial); } // draw to color (second pass) @@ -619,18 +624,19 @@ void WgCompositor::drawImage(WgContext& context, WgRenderDataPicture* renderData assert(renderData); assert(renderPassEncoder); if (renderData->viewport.invalid()) return; + WgRenderSettings& settings = renderData->renderSettings; wgpuRenderPassEncoderSetScissorRect(renderPassEncoder, renderData->viewport.x(), renderData->viewport.y(), renderData->viewport.w(), renderData->viewport.h()); // draw stencil wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 255); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 0, bindGroupViewMat, 0, nullptr); - wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, renderData->bindGroupPaint, 0, nullptr); + wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, stageBufferPaint[settings.bindGroupInd], 0, nullptr); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.direct); 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); + wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, stageBufferPaint[settings.bindGroupInd], 0, nullptr); + wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, renderData->imageData.bindGroup, 0, nullptr); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.image); drawMeshImage(context, &renderData->meshData); } @@ -641,6 +647,7 @@ void WgCompositor::blendImage(WgContext& context, WgRenderDataPicture* renderDat assert(renderData); assert(renderPassEncoder); if (renderData->viewport.invalid()) return; + WgRenderSettings& settings = renderData->renderSettings; wgpuRenderPassEncoderSetScissorRect(renderPassEncoder, renderData->viewport.x(), renderData->viewport.y(), renderData->viewport.w(), renderData->viewport.h()); // copy current render target data to dst target WgRenderTarget *target = currentTarget; @@ -650,15 +657,15 @@ void WgCompositor::blendImage(WgContext& context, WgRenderDataPicture* renderDat // setup stencil rules wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 255); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 0, bindGroupViewMat, 0, nullptr); - wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, renderData->bindGroupPaint, 0, nullptr); + wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, stageBufferPaint[settings.bindGroupInd], 0, nullptr); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.direct); 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, 1, stageBufferPaint[settings.bindGroupInd], 0, nullptr); + wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, renderData->imageData.bindGroup, 0, nullptr); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 3, targetTemp0.bindGroupTexure, 0, nullptr); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.image_blend[blendMethodInd]); drawMeshImage(context, &renderData->meshData); @@ -670,11 +677,12 @@ void WgCompositor::clipImage(WgContext& context, WgRenderDataPicture* renderData assert(renderData); assert(renderPassEncoder); if (renderData->viewport.invalid()) return; + WgRenderSettings& settings = renderData->renderSettings; wgpuRenderPassEncoderSetScissorRect(renderPassEncoder, renderData->viewport.x(), renderData->viewport.y(), renderData->viewport.w(), renderData->viewport.h()); // setup stencil rules wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 255); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 0, bindGroupViewMat, 0, nullptr); - wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, renderData->bindGroupPaint, 0, nullptr); + wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, stageBufferPaint[settings.bindGroupInd], 0, nullptr); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.direct); drawMeshImage(context, &renderData->meshData); // merge depth and stencil buffer @@ -685,8 +693,8 @@ void WgCompositor::clipImage(WgContext& context, WgRenderDataPicture* renderData // 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); + wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, stageBufferPaint[settings.bindGroupInd], 0, nullptr); + wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, renderData->imageData.bindGroup, 0, nullptr); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.image); drawMeshImage(context, &renderData->meshData); } @@ -734,16 +742,19 @@ void WgCompositor::blendScene(WgContext& context, WgRenderTarget* scene, WgCompo void WgCompositor::markupClipPath(WgContext& context, WgRenderDataShape* renderData) { wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 0, bindGroupViewMat, 0, nullptr); - wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, renderData->bindGroupPaint, 0, nullptr); // markup stencil if (renderData->meshGroupStrokes.meshes.count > 0) { + WgRenderSettings& settings = renderData->renderSettingsStroke; wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 255); + wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, stageBufferPaint[settings.bindGroupInd], 0, nullptr); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.direct); ARRAY_FOREACH(p, renderData->meshGroupStrokes.meshes) drawMesh(context, (*p)); } else { WGPURenderPipeline stencilPipeline = (renderData->fillRule == FillRule::NonZero) ? pipelines.nonzero : pipelines.evenodd; + WgRenderSettings& settings = renderData->renderSettingsShape; wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0); + wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, stageBufferPaint[settings.bindGroupInd], 0, nullptr); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, stencilPipeline); ARRAY_FOREACH(p, renderData->meshGroupShapes.meshes) drawMeshFan(context, (*p)); @@ -760,12 +771,13 @@ void WgCompositor::renderClipPath(WgContext& context, WgRenderDataPaint* paint) wgpuRenderPassEncoderSetScissorRect(renderPassEncoder, 0, 0, width, height); // get render data WgRenderDataShape* renderData0 = (WgRenderDataShape*)paint->clips[0]; + WgRenderSettings& settings0 = renderData0->renderSettingsShape; // markup stencil markupClipPath(context, renderData0); // copy stencil to depth wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 0, bindGroupViewMat, 0, nullptr); - wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, renderData0->bindGroupPaint, 0, nullptr); + wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, stageBufferPaint[settings0.bindGroupInd], 0, nullptr); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, bindGroupOpacities[128], 0, nullptr); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.copy_stencil_to_depth); drawMeshFan(context, &renderData0->meshDataBBox); @@ -773,35 +785,36 @@ void WgCompositor::renderClipPath(WgContext& context, WgRenderDataPaint* paint) for (auto p = paint->clips.begin() + 1; p < paint->clips.end(); ++p) { // get render data WgRenderDataShape* renderData = (WgRenderDataShape*)(*p); + WgRenderSettings& settings = renderData->renderSettingsShape; // markup stencil markupClipPath(context, renderData); // copy stencil to depth (clear stencil) wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0); - wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, renderData->bindGroupPaint, 0, nullptr); + wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, stageBufferPaint[settings.bindGroupInd], 0, nullptr); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, bindGroupOpacities[190], 0, nullptr); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.copy_stencil_to_depth_interm); drawMeshFan(context, &renderData->meshDataBBox); // copy depth to stencil wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 1); - wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, renderData->bindGroupPaint, 0, nullptr); + wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, stageBufferPaint[settings.bindGroupInd], 0, nullptr); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, bindGroupOpacities[190], 0, nullptr); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.copy_depth_to_stencil); drawMeshFan(context, &renderData->meshDataBBox); // clear depth current (keep stencil) wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0); - wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, renderData->bindGroupPaint, 0, nullptr); + wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, stageBufferPaint[settings.bindGroupInd], 0, nullptr); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, bindGroupOpacities[255], 0, nullptr); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.clear_depth); drawMeshFan(context, &renderData->meshDataBBox); // clear depth original (keep stencil) wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0); - wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, renderData0->bindGroupPaint, 0, nullptr); + wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, stageBufferPaint[settings0.bindGroupInd], 0, nullptr); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, bindGroupOpacities[255], 0, nullptr); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.clear_depth); drawMeshFan(context, &renderData0->meshDataBBox); // copy stencil to depth (clear stencil) wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0); - wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, renderData->bindGroupPaint, 0, nullptr); + wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, stageBufferPaint[settings.bindGroupInd], 0, nullptr); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, bindGroupOpacities[128], 0, nullptr); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.copy_stencil_to_depth); drawMeshFan(context, &renderData->meshDataBBox); @@ -819,10 +832,11 @@ void WgCompositor::clearClipPath(WgContext& context, WgRenderDataPaint* paint) // get render data ARRAY_FOREACH(p, paint->clips) { WgRenderDataShape* renderData = (WgRenderDataShape*)(*p); + WgRenderSettings& settings = renderData->renderSettingsShape; // set transformations wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 0, bindGroupViewMat, 0, nullptr); - wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, renderData->bindGroupPaint, 0, nullptr); + wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, stageBufferPaint[settings.bindGroupInd], 0, nullptr); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, bindGroupOpacities[255], 0, nullptr); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.clear_depth); drawMeshFan(context, &renderData->meshDataBBox); diff --git a/src/renderer/wg_engine/tvgWgCompositor.h b/src/renderer/wg_engine/tvgWgCompositor.h index 648248d9..b04069c4 100644 --- a/src/renderer/wg_engine/tvgWgCompositor.h +++ b/src/renderer/wg_engine/tvgWgCompositor.h @@ -39,7 +39,8 @@ private: // pipelines WgPipelines pipelines{}; // stage buffers - WgRenderDataStageBuffer stageBuffer{}; + WgStageBufferGeometry stageBufferGeometry{}; + WgStageBufferUniform stageBufferPaint; // global stencil/depth buffer handles WGPUTexture texDepthStencil{}; WGPUTextureView texViewDepthStencil{}; diff --git a/src/renderer/wg_engine/tvgWgPipelines.cpp b/src/renderer/wg_engine/tvgWgPipelines.cpp index 4466cbbc..1f8b9a2f 100644 --- a/src/renderer/wg_engine/tvgWgPipelines.cpp +++ b/src/renderer/wg_engine/tvgWgPipelines.cpp @@ -167,17 +167,17 @@ void WgPipelines::initialize(WgContext& context) const WgBindGroupLayouts& layouts = context.layouts; // bind group layouts helpers - const WGPUBindGroupLayout bindGroupLayoutsStencil[] { layouts.layoutBuffer1Un, layouts.layoutBuffer2Un }; - const WGPUBindGroupLayout bindGroupLayoutsDepth[] { layouts.layoutBuffer1Un, layouts.layoutBuffer2Un, layouts.layoutBuffer1Un }; + const WGPUBindGroupLayout bindGroupLayoutsStencil[] { layouts.layoutBuffer1Un, layouts.layoutBuffer1Un }; + const WGPUBindGroupLayout bindGroupLayoutsDepth[] { layouts.layoutBuffer1Un, layouts.layoutBuffer1Un, layouts.layoutBuffer1Un }; // bind group layouts normal blend - const WGPUBindGroupLayout bindGroupLayoutsSolid[] { layouts.layoutBuffer1Un, layouts.layoutBuffer2Un, layouts.layoutBuffer1Un }; - const WGPUBindGroupLayout bindGroupLayoutsGradient[] { layouts.layoutBuffer1Un, layouts.layoutBuffer2Un, layouts.layoutTexSampledBuff2Un }; - const WGPUBindGroupLayout bindGroupLayoutsImage[] { layouts.layoutBuffer1Un, layouts.layoutBuffer2Un, layouts.layoutTexSampled }; + const WGPUBindGroupLayout bindGroupLayoutsSolid[] { layouts.layoutBuffer1Un, layouts.layoutBuffer1Un }; + const WGPUBindGroupLayout bindGroupLayoutsGradient[] { layouts.layoutBuffer1Un, layouts.layoutBuffer1Un, layouts.layoutTexSampled }; + const WGPUBindGroupLayout bindGroupLayoutsImage[] { layouts.layoutBuffer1Un, layouts.layoutBuffer1Un, layouts.layoutTexSampled }; const WGPUBindGroupLayout bindGroupLayoutsScene[] { layouts.layoutTexSampled, layouts.layoutBuffer1Un }; // bind group layouts custom blend - const WGPUBindGroupLayout bindGroupLayoutsSolidBlend[] { layouts.layoutBuffer1Un, layouts.layoutBuffer2Un, layouts.layoutBuffer1Un, layouts.layoutTexSampled }; - const WGPUBindGroupLayout bindGroupLayoutsGradientBlend[] { layouts.layoutBuffer1Un, layouts.layoutBuffer2Un, layouts.layoutTexSampledBuff2Un, layouts.layoutTexSampled }; - const WGPUBindGroupLayout bindGroupLayoutsImageBlend[] { layouts.layoutBuffer1Un, layouts.layoutBuffer2Un, layouts.layoutTexSampled, layouts.layoutTexSampled }; + const WGPUBindGroupLayout bindGroupLayoutsSolidBlend[] { layouts.layoutBuffer1Un, layouts.layoutBuffer1Un, layouts.layoutBuffer1Un, layouts.layoutTexSampled }; + const WGPUBindGroupLayout bindGroupLayoutsGradientBlend[] { layouts.layoutBuffer1Un, layouts.layoutBuffer1Un, layouts.layoutTexSampled, layouts.layoutTexSampled }; + const WGPUBindGroupLayout bindGroupLayoutsImageBlend[] { layouts.layoutBuffer1Un, layouts.layoutBuffer1Un, layouts.layoutTexSampled, layouts.layoutTexSampled }; const WGPUBindGroupLayout bindGroupLayoutsSceneBlend[] { layouts.layoutTexSampled, layouts.layoutTexSampled, layouts.layoutBuffer1Un }; // bind group layouts scene compose const WGPUBindGroupLayout bindGroupLayoutsSceneCompose[] { layouts.layoutTexSampled, layouts.layoutTexSampled }; @@ -229,7 +229,7 @@ void WgPipelines::initialize(WgContext& context) layout_stencil = createPipelineLayout(context.device, bindGroupLayoutsStencil, 2); layout_depth = createPipelineLayout(context.device, bindGroupLayoutsDepth, 3); // layouts normal blend - layout_solid = createPipelineLayout(context.device, bindGroupLayoutsSolid, 3); + layout_solid = createPipelineLayout(context.device, bindGroupLayoutsSolid, 2); layout_gradient = createPipelineLayout(context.device, bindGroupLayoutsGradient, 3); layout_image = createPipelineLayout(context.device, bindGroupLayoutsImage, 3); layout_scene = createPipelineLayout(context.device, bindGroupLayoutsScene, 2); diff --git a/src/renderer/wg_engine/tvgWgRenderData.cpp b/src/renderer/wg_engine/tvgWgRenderData.cpp index f6eea81e..b3cdf37c 100644 --- a/src/renderer/wg_engine/tvgWgRenderData.cpp +++ b/src/renderer/wg_engine/tvgWgRenderData.cpp @@ -202,12 +202,38 @@ void WgImageData::update(WgContext& context, const RenderSurface* surface) if (texHandleChanged) { context.releaseTextureView(textureView); textureView = context.createTextureView(texture); + // update bind group + context.layouts.releaseBindGroup(bindGroup); + bindGroup = context.layouts.createBindGroupTexSampled(context.samplerLinearRepeat, textureView); + } +}; + + +void WgImageData::update(WgContext& context, const Fill* fill) +{ + // compute gradient data + WgShaderTypeGradientData gradientData; + gradientData.update(fill); + // allocate new texture handle + bool texHandleChanged = context.allocateTexture(texture, WG_TEXTURE_GRADIENT_SIZE, 1, WGPUTextureFormat_RGBA8Unorm, gradientData.data); + // update texture view of texture handle was changed + if (texHandleChanged) { + context.releaseTextureView(textureView); + textureView = context.createTextureView(texture); + // get sampler by spread type + WGPUSampler sampler = context.samplerLinearClamp; + if (fill->spread() == FillSpread::Reflect) sampler = context.samplerLinearMirror; + if (fill->spread() == FillSpread::Repeat) sampler = context.samplerLinearRepeat; + // update bind group + context.layouts.releaseBindGroup(bindGroup); + bindGroup = context.layouts.createBindGroupTexSampled(sampler, textureView); } }; void WgImageData::release(WgContext& context) { + context.layouts.releaseBindGroup(bindGroup); context.releaseTextureView(textureView); context.releaseTexture(texture); }; @@ -216,52 +242,31 @@ void WgImageData::release(WgContext& context) // WgRenderSettings //*********************************************************************** -void WgRenderSettings::updateFill(WgContext& context, const Fill* fill) +void WgRenderSettings::update(WgContext& context, const tvg::Matrix& transform, tvg::ColorSpace cs, uint8_t opacity) { - rasterType = WgRenderRasterType::Gradient; - // get gradient transfrom matrix - Matrix invFillTransform; - WgShaderTypeMat4x4f gradientTrans; // identity by default - if (inverse(&fill->transform(), &invFillTransform)) - gradientTrans.update(invFillTransform); + settings.transform.update(transform); + settings.options.update(cs, opacity); +} + +void WgRenderSettings::update(WgContext& context, const Fill* fill) +{ + assert(fill); + settings.gradient.update(fill); + gradientData.update(context, fill); // get gradient rasterisation settings - WgShaderTypeGradient gradient; - if (fill->type() == Type::LinearGradient) { - gradient.update((LinearGradient*)fill); + rasterType = WgRenderRasterType::Gradient; + if (fill->type() == Type::LinearGradient) fillType = WgRenderSettingsType::Linear; - } else if (fill->type() == Type::RadialGradient) { - gradient.update((RadialGradient*)fill); + else if (fill->type() == Type::RadialGradient) fillType = WgRenderSettingsType::Radial; - } - // update gpu assets - bool bufferGradientSettingsChanged = context.allocateBufferUniform(bufferGroupGradient, &gradient.settings, sizeof(gradient.settings)); - bool bufferGradientTransformChanged = context.allocateBufferUniform(bufferGroupTransfromGrad, &gradientTrans.mat, sizeof(gradientTrans.mat)); - bool textureGradientChanged = context.allocateTexture(texGradient, WG_TEXTURE_GRADIENT_SIZE, 1, WGPUTextureFormat_RGBA8Unorm, gradient.texData); - if (bufferGradientSettingsChanged || textureGradientChanged || bufferGradientTransformChanged) { - // update texture view - context.releaseTextureView(texViewGradient); - texViewGradient = context.createTextureView(texGradient); - // get sampler by spread type - WGPUSampler sampler = context.samplerLinearClamp; - if (fill->spread() == FillSpread::Reflect) sampler = context.samplerLinearMirror; - if (fill->spread() == FillSpread::Repeat) sampler = context.samplerLinearRepeat; - // update bind group - context.layouts.releaseBindGroup(bindGroupGradient); - bindGroupGradient = context.layouts.createBindGroupTexSampledBuff2Un( - sampler, texViewGradient, bufferGroupGradient, bufferGroupTransfromGrad); - } skip = false; }; -void WgRenderSettings::updateColor(WgContext& context, const RenderColor& c) +void WgRenderSettings::update(WgContext& context, const RenderColor& c) { + settings.color.update(c); rasterType = WgRenderRasterType::Solid; - WgShaderTypeVec4f solidColor(c); - if (context.allocateBufferUniform(bufferGroupSolid, &solidColor, sizeof(solidColor))) { - context.layouts.releaseBindGroup(bindGroupSolid); - bindGroupSolid = context.layouts.createBindGroupBuffer1Un(bufferGroupSolid); - } fillType = WgRenderSettingsType::Solid; skip = (c.a == 0); }; @@ -269,13 +274,7 @@ void WgRenderSettings::updateColor(WgContext& context, const RenderColor& c) void WgRenderSettings::release(WgContext& context) { - context.layouts.releaseBindGroup(bindGroupSolid); - context.layouts.releaseBindGroup(bindGroupGradient); - context.releaseBuffer(bufferGroupSolid); - context.releaseBuffer(bufferGroupGradient); - context.releaseBuffer(bufferGroupTransfromGrad); - context.releaseTexture(texGradient); - context.releaseTextureView(texViewGradient); + gradientData.release(context); }; //*********************************************************************** @@ -284,26 +283,10 @@ void WgRenderSettings::release(WgContext& context) void WgRenderDataPaint::release(WgContext& context) { - context.layouts.releaseBindGroup(bindGroupPaint); - context.releaseBuffer(bufferModelMat); - context.releaseBuffer(bufferBlendSettings); clips.clear(); }; -void WgRenderDataPaint::update(WgContext& context, const tvg::Matrix& transform, tvg::ColorSpace cs, uint8_t opacity) -{ - WgShaderTypeMat4x4f modelMat(transform); - WgShaderTypeVec4f blendSettings(cs, opacity); - bool bufferModelMatChanged = context.allocateBufferUniform(bufferModelMat, &modelMat, sizeof(modelMat)); - bool bufferBlendSettingsChanged = context.allocateBufferUniform(bufferBlendSettings, &blendSettings, sizeof(blendSettings)); - if (bufferModelMatChanged || bufferBlendSettingsChanged) { - context.layouts.releaseBindGroup(bindGroupPaint); - bindGroupPaint = context.layouts.createBindGroupBuffer2Un(bufferModelMat, bufferBlendSettings); - } -} - - void WgRenderDataPaint::updateClips(tvg::Array &clips) { this->clips.clear(); ARRAY_FOREACH(p, clips) { @@ -467,17 +450,12 @@ void WgRenderDataPicture::updateSurface(WgContext& context, const RenderSurface* meshData.imageBox(context, surface->w, surface->h); // update texture data imageData.update(context, surface); - // update texture bind group - context.layouts.releaseBindGroup(bindGroupPicture); - bindGroupPicture = context.layouts.createBindGroupTexSampled( - context.samplerLinearRepeat, imageData.textureView - ); } void WgRenderDataPicture::release(WgContext& context) { - context.layouts.releaseBindGroup(bindGroupPicture); + renderSettings.release(context); imageData.release(context); meshData.release(context); WgRenderDataPaint::release(context); @@ -676,10 +654,10 @@ void WgRenderDataEffectParamsPool::release(WgContext& context) } //*********************************************************************** -// WgRenderDataStageBuffer +// WgStageBufferGeometry //*********************************************************************** -void WgRenderDataStageBuffer::append(WgMeshData* meshData) +void WgStageBufferGeometry::append(WgMeshData* meshData) { assert(meshData); uint32_t vsize = meshData->vbuffer.count * sizeof(meshData->vbuffer[0]); @@ -712,54 +690,50 @@ void WgRenderDataStageBuffer::append(WgMeshData* meshData) } -void WgRenderDataStageBuffer::append(WgMeshDataGroup* meshDataGroup) +void WgStageBufferGeometry::append(WgMeshDataGroup* meshDataGroup) { ARRAY_FOREACH(p, meshDataGroup->meshes) append(*p); } -void WgRenderDataStageBuffer::append(WgRenderDataShape* renderDataShape) +void WgStageBufferGeometry::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) +void WgStageBufferGeometry::append(WgRenderDataPicture* renderDataPicture) { append(&renderDataPicture->meshData); - ARRAY_FOREACH(p, renderDataPicture->clips) - append((WgRenderDataShape* )(*p)); } -void WgRenderDataStageBuffer::release(WgContext& context) +void WgStageBufferGeometry::release(WgContext& context) { context.releaseBuffer(vbuffer_gpu); context.releaseBuffer(ibuffer_gpu); } -void WgRenderDataStageBuffer::clear() +void WgStageBufferGeometry::clear() { vbuffer.clear(); ibuffer.clear(); } -void WgRenderDataStageBuffer::flush(WgContext& context) +void WgStageBufferGeometry::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) +void WgStageBufferGeometry::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); diff --git a/src/renderer/wg_engine/tvgWgRenderData.h b/src/renderer/wg_engine/tvgWgRenderData.h index ba3805a2..81ed9607 100644 --- a/src/renderer/wg_engine/tvgWgRenderData.h +++ b/src/renderer/wg_engine/tvgWgRenderData.h @@ -66,8 +66,10 @@ struct WgMeshDataGroup { struct WgImageData { WGPUTexture texture{}; WGPUTextureView textureView{}; + WGPUBindGroup bindGroup{}; void update(WgContext& context, const RenderSurface* surface); + void update(WgContext& context, const Fill* fill); void release(WgContext& context); }; @@ -76,37 +78,29 @@ enum class WgRenderRasterType { Solid = 0, Gradient, Image }; struct WgRenderSettings { - WGPUBuffer bufferGroupSolid{}; - WGPUBindGroup bindGroupSolid{}; - WGPUTexture texGradient{}; - WGPUTextureView texViewGradient{}; - WGPUBuffer bufferGroupGradient{}; - WGPUBuffer bufferGroupTransfromGrad{}; - WGPUBindGroup bindGroupGradient{}; + uint32_t bindGroupInd{}; + WgShaderTypePaintSettings settings; + WgImageData gradientData; WgRenderSettingsType fillType{}; WgRenderRasterType rasterType{}; bool skip{}; - void updateFill(WgContext& context, const Fill* fill); - void updateColor(WgContext& context, const RenderColor& c); + void update(WgContext& context, const tvg::Matrix& transform, tvg::ColorSpace cs, uint8_t opacity); + void update(WgContext& context, const Fill* fill); + void update(WgContext& context, const RenderColor& c); void release(WgContext& context); }; struct WgRenderDataPaint { - WGPUBuffer bufferModelMat{}; - WGPUBuffer bufferBlendSettings{}; - WGPUBindGroup bindGroupPaint{}; - RenderRegion viewport{}; BBox aabb{{},{}}; - float opacity{}; + RenderRegion viewport{}; Array clips; virtual ~WgRenderDataPaint() {}; virtual void release(WgContext& context); virtual Type type() { return Type::Undefined; }; - void update(WgContext& context, const tvg::Matrix& transform, tvg::ColorSpace cs, uint8_t opacity); void updateClips(tvg::Array &clips); }; @@ -147,7 +141,7 @@ public: struct WgRenderDataPicture: public WgRenderDataPaint { - WGPUBindGroup bindGroupPicture{}; + WgRenderSettings renderSettings{}; WgImageData imageData{}; WgMeshData meshData{}; @@ -221,7 +215,7 @@ public: void release(WgContext& context); }; -class WgRenderDataStageBuffer { +class WgStageBufferGeometry { private: Array vbuffer; Array ibuffer; @@ -240,4 +234,50 @@ public: void bind(WGPURenderPassEncoder renderPass, size_t voffset, size_t toffset); }; +// typed uniform stage buffer with related bind groups handling +template +class WgStageBufferUniform { +private: + Array ubuffer; + WGPUBuffer ubuffer_gpu{}; + Array bbuffer; +public: + // append uniform data to cpu staged buffer and return related bind group index + uint32_t append(const T& value) { + ubuffer.push(value); + return ubuffer.count - 1; + } + + void flush(WgContext& context) { + // flush data to gpu buffer from cpu memory including reserved data to prevent future gpu buffer reallocations + bool bufferChanged = context.allocateBufferUniform(ubuffer_gpu, (void*)ubuffer.data, ubuffer.reserved*sizeof(T)); + // if gpu buffer handle was changed we must to remove all created binding groups + if (bufferChanged) releaseBindGroups(context); + // allocate bind groups for all new data items + for (uint32_t i = bbuffer.count; i < ubuffer.count; i++) + bbuffer.push(context.layouts.createBindGroupBuffer1Un(ubuffer_gpu, i*sizeof(T), sizeof(T))); + assert(bbuffer.count >= ubuffer.count); + } + + // please, use index that was returned from append method + WGPUBindGroup operator[](const uint32_t index) const { + return bbuffer[index]; + } + + void clear() { + ubuffer.clear(); + } + + void release(WgContext& context) { + context.releaseBuffer(ubuffer_gpu); + releaseBindGroups(context); + } + + void releaseBindGroups(WgContext& context) { + ARRAY_FOREACH(p, bbuffer) + context.layouts.releaseBindGroup(*p); + bbuffer.clear(); + } +}; + #endif // _TVG_WG_RENDER_DATA_H_ diff --git a/src/renderer/wg_engine/tvgWgRenderer.cpp b/src/renderer/wg_engine/tvgWgRenderer.cpp index af860865..5de0eafd 100644 --- a/src/renderer/wg_engine/tvgWgRenderer.cpp +++ b/src/renderer/wg_engine/tvgWgRenderer.cpp @@ -147,18 +147,18 @@ RenderData WgRenderer::prepare(const RenderShape& rshape, RenderData data, const // update paint settings if ((!data) || (flags & (RenderUpdateFlag::Transform | RenderUpdateFlag::Blend))) { - renderDataShape->update(mContext, transform, mTargetSurface.cs, opacity); + renderDataShape->renderSettingsShape.update(mContext, transform, mTargetSurface.cs, opacity); + renderDataShape->renderSettingsStroke.update(mContext, transform, mTargetSurface.cs, opacity); renderDataShape->fillRule = rshape.rule; } // setup fill settings renderDataShape->viewport = mViewport; - renderDataShape->opacity = opacity; - if (flags & RenderUpdateFlag::Gradient && rshape.fill) renderDataShape->renderSettingsShape.updateFill(mContext, rshape.fill); - else if (flags & RenderUpdateFlag::Color) renderDataShape->renderSettingsShape.updateColor(mContext, rshape.color); + if (flags & RenderUpdateFlag::Gradient && rshape.fill) renderDataShape->renderSettingsShape.update(mContext, rshape.fill); + else if (flags & RenderUpdateFlag::Color) renderDataShape->renderSettingsShape.update(mContext, rshape.color); if (rshape.stroke) { - if (flags & RenderUpdateFlag::GradientStroke && rshape.stroke->fill) renderDataShape->renderSettingsStroke.updateFill(mContext, rshape.stroke->fill); - else if (flags & RenderUpdateFlag::Stroke) renderDataShape->renderSettingsStroke.updateColor(mContext, rshape.stroke->color); + if (flags & RenderUpdateFlag::GradientStroke && rshape.stroke->fill) renderDataShape->renderSettingsStroke.update(mContext, rshape.stroke->fill); + else if (flags & RenderUpdateFlag::Stroke) renderDataShape->renderSettingsStroke.update(mContext, rshape.stroke->color); } // store clips data @@ -177,9 +177,8 @@ RenderData WgRenderer::prepare(RenderSurface* surface, RenderData data, const Ma // update paint settings renderDataPicture->viewport = mViewport; - renderDataPicture->opacity = opacity; if (flags & (RenderUpdateFlag::Transform | RenderUpdateFlag::Blend)) { - renderDataPicture->update(mContext, transform, surface->cs, opacity); + renderDataPicture->renderSettings.update(mContext, transform, surface->cs, opacity); } // update image data @@ -193,6 +192,7 @@ RenderData WgRenderer::prepare(RenderSurface* surface, RenderData data, const Ma return renderDataPicture; } + bool WgRenderer::preRender() { // invalidate context diff --git a/src/renderer/wg_engine/tvgWgShaderSrc.cpp b/src/renderer/wg_engine/tvgWgShaderSrc.cpp index 53fa134a..75f61ead 100644 --- a/src/renderer/wg_engine/tvgWgShaderSrc.cpp +++ b/src/renderer/wg_engine/tvgWgShaderSrc.cpp @@ -23,8 +23,6 @@ #include "tvgWgShaderSrc.h" #include -#define WG_SHADER_SOURCE(...) #__VA_ARGS__ - //************************************************************************ // graphics shader source: stencil //************************************************************************ @@ -32,14 +30,15 @@ const char* cShaderSrc_Stencil = R"( struct VertexInput { @location(0) position: vec2f }; struct VertexOutput { @builtin(position) position: vec4f }; +struct PaintSettings { transform: mat4x4f }; @group(0) @binding(0) var uViewMat : mat4x4f; -@group(1) @binding(0) var uModelMat : mat4x4f; +@group(1) @binding(0) var uPaintSettings : PaintSettings; @vertex fn vs_main(in: VertexInput) -> VertexOutput { var out: VertexOutput; - out.position = uViewMat * uModelMat * vec4f(in.position.xy, 0.0, 1.0); + out.position = uViewMat * uPaintSettings.transform * vec4f(in.position.xy, 0.0, 1.0); return out; } @@ -56,15 +55,16 @@ fn fs_main(in: VertexOutput) -> @location(0) vec4f { const char* cShaderSrc_Depth = R"( struct VertexInput { @location(0) position: vec2f }; struct VertexOutput { @builtin(position) position: vec4f }; +struct PaintSettings { transform: mat4x4f }; @group(0) @binding(0) var uViewMat : mat4x4f; -@group(1) @binding(0) var uModelMat : mat4x4f; +@group(1) @binding(0) var uPaintSettings : PaintSettings; @group(2) @binding(0) var uDepth : f32; @vertex fn vs_main(in: VertexInput) -> VertexOutput { var out: VertexOutput; - out.position = uViewMat * uModelMat * vec4f(in.position.xy, 0.0, 1.0); + out.position = uViewMat * uPaintSettings.transform * vec4f(in.position.xy, 0.0, 1.0); out.position.z = uDepth; return out; } @@ -82,23 +82,22 @@ fn fs_main(in: VertexOutput) -> @location(0) vec4f { const char* cShaderSrc_Solid = R"( struct VertexInput { @location(0) position: vec2f }; struct VertexOutput { @builtin(position) position: vec4f }; +struct PaintSettings { transform: mat4x4f, options: vec4f, color: vec4f }; @group(0) @binding(0) var uViewMat : mat4x4f; -@group(1) @binding(0) var uModelMat : mat4x4f; -@group(1) @binding(1) var uBlendSettings : vec4f; -@group(2) @binding(0) var uSolidColor : vec4f; +@group(1) @binding(0) var uPaintSettings : PaintSettings; @vertex fn vs_main(in: VertexInput) -> VertexOutput { var out: VertexOutput; - out.position = uViewMat * uModelMat * vec4f(in.position.xy, 0.0, 1.0); + out.position = uViewMat * uPaintSettings.transform * vec4f(in.position.xy, 0.0, 1.0); return out; } @fragment fn fs_main(in: VertexOutput) -> @location(0) vec4f { - let Sc = uSolidColor; - let So = uBlendSettings.a; + let Sc = uPaintSettings.color; + let So = uPaintSettings.options.a; return vec4f(Sc.rgb * Sc.a * So, Sc.a * So); } )"; @@ -110,34 +109,32 @@ fn fs_main(in: VertexOutput) -> @location(0) vec4f { const char* cShaderSrc_Linear = R"( struct VertexInput { @location(0) position: vec2f }; struct VertexOutput { @builtin(position) position : vec4f, @location(0) vGradCoord : vec4f }; -struct GradSettings { settings: vec4f, focal: vec4f }; +struct GradSettings { transform: mat4x4f, coords: vec4f, focal: vec4f }; +struct PaintSettings { transform: mat4x4f, options: vec4f, color: vec4f, gradient: GradSettings }; // uniforms @group(0) @binding(0) var uViewMat : mat4x4f; -@group(1) @binding(0) var uModelMat : mat4x4f; -@group(1) @binding(1) var uBlendSettings : vec4f; +@group(1) @binding(0) var uPaintSettings : PaintSettings; @group(2) @binding(0) var uSamplerGrad : sampler; @group(2) @binding(1) var uTextureGrad : texture_2d; -@group(2) @binding(2) var uSettingGrad : GradSettings; -@group(2) @binding(3) var uTransformGrad : mat4x4f; @vertex fn vs_main(in: VertexInput) -> VertexOutput { var out: VertexOutput; - out.position = uViewMat * uModelMat * vec4f(in.position.xy, 0.0, 1.0); - out.vGradCoord = uTransformGrad * vec4f(in.position.xy, 0.0, 1.0); + out.position = uViewMat * uPaintSettings.transform * vec4f(in.position.xy, 0.0, 1.0); + out.vGradCoord = uPaintSettings.gradient.transform * vec4f(in.position.xy, 0.0, 1.0); return out; } @fragment fn fs_main(in: VertexOutput) -> @location(0) vec4f { let pos = in.vGradCoord.xy; - let st = uSettingGrad.settings.xy; - let ed = uSettingGrad.settings.zw; + let st = uPaintSettings.gradient.coords.xy; + let ed = uPaintSettings.gradient.coords.zw; let ba = ed - st; let t = dot(pos - st, ba) / dot(ba, ba); let Sc = textureSample(uTextureGrad, uSamplerGrad, vec2f(t, 0.5)); - let So = uBlendSettings.a; + let So = uPaintSettings.options.a; return vec4f(Sc.rgb * Sc.a * So, Sc.a * So); } )"; @@ -149,37 +146,35 @@ fn fs_main(in: VertexOutput) -> @location(0) vec4f { const char* cShaderSrc_Radial = R"( struct VertexInput { @location(0) position: vec2f }; struct VertexOutput { @builtin(position) position : vec4f, @location(0) vGradCoord : vec4f }; -struct GradSettings { settings: vec4f, focal: vec4f }; +struct GradSettings { transform: mat4x4f, coords: vec4f, focal: vec4f }; +struct PaintSettings { transform: mat4x4f, options: vec4f, color: vec4f, gradient: GradSettings }; @group(0) @binding(0) var uViewMat : mat4x4f; -@group(1) @binding(0) var uModelMat : mat4x4f; -@group(1) @binding(1) var uBlendSettings : vec4f; +@group(1) @binding(0) var uPaintSettings : PaintSettings; @group(2) @binding(0) var uSamplerGrad : sampler; @group(2) @binding(1) var uTextureGrad : texture_2d; -@group(2) @binding(2) var uSettingGrad : GradSettings; -@group(2) @binding(3) var uTransformGrad : mat4x4f; @vertex fn vs_main(in: VertexInput) -> VertexOutput { var out: VertexOutput; - out.position = uViewMat * uModelMat * vec4f(in.position.xy, 0.0, 1.0); - out.vGradCoord = uTransformGrad * vec4f(in.position.xy, 0.0, 1.0); + out.position = uViewMat * uPaintSettings.transform * vec4f(in.position.xy, 0.0, 1.0); + out.vGradCoord = uPaintSettings.gradient.transform * vec4f(in.position.xy, 0.0, 1.0); return out; } @fragment fn fs_main(in: VertexOutput) -> @location(0) vec4f { // orignal data - let d0 = in.vGradCoord.xy - uSettingGrad.settings.xy; - let d1 = uSettingGrad.settings.xy - uSettingGrad.focal.xy; - let r0 = uSettingGrad.settings.z; - let rd = uSettingGrad.focal.z - uSettingGrad.settings.z; + let d0 = in.vGradCoord.xy - uPaintSettings.gradient.coords.xy; + let d1 = uPaintSettings.gradient.coords.xy - uPaintSettings.gradient.focal.xy; + let r0 = uPaintSettings.gradient.coords.z; + let rd = uPaintSettings.gradient.focal.z - uPaintSettings.gradient.coords.z; let a = 1.0*dot(d1, d1) - 1.0*rd*rd; let b = 2.0*dot(d0, d1) - 2.0*r0*rd; let c = 1.0*dot(d0, d0) - 1.0*r0*r0; let t = (-b + sqrt(b*b - 4*a*c))/(2*a); let Sc = textureSample(uTextureGrad, uSamplerGrad, vec2f(1.0 - t, 0.5)); - let So = uBlendSettings.a; + let So = uPaintSettings.options.a; return vec4f(Sc.rgb * Sc.a * So, Sc.a * So); } )"; @@ -191,17 +186,17 @@ fn fs_main(in: VertexOutput) -> @location(0) vec4f { const char* cShaderSrc_Image = R"( struct VertexInput { @location(0) position: vec2f, @location(1) texCoord: vec2f }; struct VertexOutput { @builtin(position) position: vec4f, @location(0) vTexCoord: vec2f }; +struct PaintSettings { transform: mat4x4f, options: vec4f }; @group(0) @binding(0) var uViewMat : mat4x4f; -@group(1) @binding(0) var uModelMat : mat4x4f; -@group(1) @binding(1) var uBlendSettings : vec4f; +@group(1) @binding(0) var uPaintSettings : PaintSettings; @group(2) @binding(0) var uSampler : sampler; @group(2) @binding(1) var uTextureView : texture_2d; @vertex fn vs_main(in: VertexInput) -> VertexOutput { var out: VertexOutput; - out.position = uViewMat * uModelMat * vec4f(in.position.xy, 0.0, 1.0); + out.position = uViewMat * uPaintSettings.transform * vec4f(in.position.xy, 0.0, 1.0); out.vTexCoord = in.texCoord; return out; } @@ -209,7 +204,7 @@ fn vs_main(in: VertexInput) -> VertexOutput { @fragment fn fs_main(in: VertexOutput) -> @location(0) vec4f { var Sc: vec4f = textureSample(uTextureView, uSampler, in.vTexCoord.xy); - let So: f32 = uBlendSettings.a; + let So: f32 = uPaintSettings.options.a; return vec4f(Sc.rgb * Sc.a * So, Sc.a * So); }; )"; @@ -248,18 +243,18 @@ fn fs_main(in: VertexOutput) -> @location(0) vec4f { const char* cShaderSrc_Solid_Blend = R"( struct VertexInput { @location(0) position: vec2f }; struct VertexOutput { @builtin(position) position: vec4f, @location(1) vScrCoord: vec2f }; +struct PaintSettings { transform: mat4x4f, options: vec4f, color: vec4f }; @group(0) @binding(0) var uViewMat : mat4x4f; -@group(1) @binding(0) var uModelMat : mat4x4f; -@group(1) @binding(1) var uBlendSettings : vec4f; -@group(2) @binding(0) var uSolidColor : vec4f; +@group(1) @binding(0) var uPaintSettings : PaintSettings; +// @group(2) - empty @group(3) @binding(0) var uSamplerDst : sampler; @group(3) @binding(1) var uTextureDst : texture_2d; @vertex fn vs_main(in: VertexInput) -> VertexOutput { var out: VertexOutput; - let pos = uViewMat * uModelMat * vec4f(in.position.xy, 0.0, 1.0); + let pos = uViewMat * uPaintSettings.transform * vec4f(in.position.xy, 0.0, 1.0); out.position = pos; out.vScrCoord = vec2f(0.5 + pos.x * 0.5, 0.5 - pos.y * 0.5); return out; @@ -268,13 +263,13 @@ fn vs_main(in: VertexInput) -> VertexOutput { struct FragData { Sc: vec3f, Sa: f32, So: f32, Dc: vec3f, Da: f32 }; fn getFragData(in: VertexOutput) -> FragData { // get source data - let colorSrc = uSolidColor; + let colorSrc = uPaintSettings.color; let colorDst = textureSample(uTextureDst, uSamplerDst, in.vScrCoord.xy); // fill fragment data var data: FragData; data.Sc = colorSrc.rgb; data.Sa = colorSrc.a; - data.So = uBlendSettings.a; + data.So = uPaintSettings.options.a; data.Dc = colorDst.rgb; data.Da = colorDst.a; data.Sc = data.Sa * data.So * data.Sc; @@ -288,24 +283,22 @@ fn postProcess(d: FragData, R: vec4f) -> vec4f { return R; }; const char* cShaderSrc_Linear_Blend = R"( struct VertexInput { @location(0) position: vec2f }; struct VertexOutput { @builtin(position) position: vec4f, @location(0) vGradCoord : vec4f, @location(1) vScrCoord: vec2f }; -struct GradSettings { settings: vec4f, focal: vec4f }; +struct GradSettings { transform: mat4x4f, coords: vec4f, focal: vec4f }; +struct PaintSettings { transform: mat4x4f, options: vec4f, color: vec4f, gradient: GradSettings }; @group(0) @binding(0) var uViewMat : mat4x4f; -@group(1) @binding(0) var uModelMat : mat4x4f; -@group(1) @binding(1) var uBlendSettings : vec4f; +@group(1) @binding(0) var uPaintSettings : PaintSettings; @group(2) @binding(0) var uSamplerGrad : sampler; @group(2) @binding(1) var uTextureGrad : texture_2d; -@group(2) @binding(2) var uSettingGrad : vec4f; -@group(2) @binding(3) var uTransformGrad : mat4x4f; @group(3) @binding(0) var uSamplerDst : sampler; @group(3) @binding(1) var uTextureDst : texture_2d; @vertex fn vs_main(in: VertexInput) -> VertexOutput { var out: VertexOutput; - let pos = uViewMat * uModelMat * vec4f(in.position.xy, 0.0, 1.0); + let pos = uViewMat * uPaintSettings.transform * vec4f(in.position.xy, 0.0, 1.0); out.position = pos; - out.vGradCoord = uTransformGrad * vec4f(in.position.xy, 0.0, 1.0); + out.vGradCoord = uPaintSettings.gradient.transform * vec4f(in.position.xy, 0.0, 1.0); out.vScrCoord = vec2f(0.5 + pos.x * 0.5, 0.5 - pos.y * 0.5); return out; } @@ -314,8 +307,8 @@ struct FragData { Sc: vec3f, Sa: f32, So: f32, Dc: vec3f, Da: f32 }; fn getFragData(in: VertexOutput) -> FragData { // get source data let pos = in.vGradCoord.xy; - let st = uSettingGrad.xy; - let ed = uSettingGrad.zw; + let st = uPaintSettings.gradient.coords.xy; + let ed = uPaintSettings.gradient.coords.zw; let ba = ed - st; let t = dot(pos - st, ba) / dot(ba, ba); let colorSrc = textureSample(uTextureGrad, uSamplerGrad, vec2f(t, 0.5)); @@ -324,7 +317,7 @@ fn getFragData(in: VertexOutput) -> FragData { var data: FragData; data.Sc = colorSrc.rgb; data.Sa = colorSrc.a; - data.So = uBlendSettings.a; + data.So = uPaintSettings.options.a; data.Dc = colorDst.rgb; data.Da = colorDst.a; data.Sc = mix(data.Dc, data.Sc, data.Sa * data.So); @@ -338,34 +331,32 @@ fn postProcess(d: FragData, R: vec4f) -> vec4f { return R; }; const char* cShaderSrc_Radial_Blend = R"( struct VertexInput { @location(0) position: vec2f }; struct VertexOutput { @builtin(position) position: vec4f, @location(0) vGradCoord : vec4f, @location(1) vScrCoord: vec2f }; -struct GradSettings { settings: vec4f, focal: vec4f }; +struct GradSettings { transform: mat4x4f, coords: vec4f, focal: vec4f }; +struct PaintSettings { transform: mat4x4f, options: vec4f, color: vec4f, gradient: GradSettings }; @group(0) @binding(0) var uViewMat : mat4x4f; -@group(1) @binding(0) var uModelMat : mat4x4f; -@group(1) @binding(1) var uBlendSettings : vec4f; +@group(1) @binding(0) var uPaintSettings : PaintSettings; @group(2) @binding(0) var uSamplerGrad : sampler; @group(2) @binding(1) var uTextureGrad : texture_2d; -@group(2) @binding(2) var uSettingGrad : GradSettings; -@group(2) @binding(3) var uTransformGrad : mat4x4f; @group(3) @binding(0) var uSamplerDst : sampler; @group(3) @binding(1) var uTextureDst : texture_2d; @vertex fn vs_main(in: VertexInput) -> VertexOutput { var out: VertexOutput; - let pos = uViewMat * uModelMat * vec4f(in.position.xy, 0.0, 1.0); + let pos = uViewMat * uPaintSettings.transform * vec4f(in.position.xy, 0.0, 1.0); out.position = pos; - out.vGradCoord = uTransformGrad * vec4f(in.position.xy, 0.0, 1.0); + out.vGradCoord = uPaintSettings.gradient.transform * vec4f(in.position.xy, 0.0, 1.0); out.vScrCoord = vec2f(0.5 + pos.x * 0.5, 0.5 - pos.y * 0.5); return out; } struct FragData { Sc: vec3f, Sa: f32, So: f32, Dc: vec3f, Da: f32 }; fn getFragData(in: VertexOutput) -> FragData { - let d0 = in.vGradCoord.xy - uSettingGrad.settings.xy; - let d1 = uSettingGrad.settings.xy - uSettingGrad.focal.xy; - let r0 = uSettingGrad.settings.z; - let rd = uSettingGrad.focal.z - uSettingGrad.settings.z; + let d0 = in.vGradCoord.xy - uPaintSettings.gradient.coords.xy; + let d1 = uPaintSettings.gradient.coords.xy - uPaintSettings.gradient.focal.xy; + let r0 = uPaintSettings.gradient.coords.z; + let rd = uPaintSettings.gradient.focal.z - uPaintSettings.gradient.coords.z; let a = 1.0*dot(d1, d1) - 1.0*rd*rd; let b = 2.0*dot(d0, d1) - 2.0*r0*rd; let c = 1.0*dot(d0, d0) - 1.0*r0*r0; @@ -376,7 +367,7 @@ fn getFragData(in: VertexOutput) -> FragData { var data: FragData; data.Sc = colorSrc.rgb; data.Sa = colorSrc.a; - data.So = uBlendSettings.a; + data.So = uPaintSettings.options.a; data.Dc = colorDst.rgb; data.Da = colorDst.a; data.Sc = mix(data.Dc, data.Sc, data.Sa * data.So); @@ -390,11 +381,11 @@ fn postProcess(d: FragData, R: vec4f) -> vec4f { return R; }; const char* cShaderSrc_Image_Blend = R"( struct VertexInput { @location(0) position: vec2f, @location(1) texCoord: vec2f }; struct VertexOutput { @builtin(position) position: vec4f, @location(0) vTexCoord : vec2f, @location(1) vScrCoord: vec2f }; +struct PaintSettings { transform: mat4x4f, options: vec4f }; @group(0) @binding(0) var uViewMat : mat4x4f; -@group(1) @binding(0) var uModelMat : mat4x4f; -@group(1) @binding(1) var uBlendSettings : vec4f; -@group(2) @binding(0) var uSamplerSrc : sampler; +@group(1) @binding(0) var uPaintSettings : PaintSettings; +@group(2) @binding(0) var uSamplerSrc : sampler; @group(2) @binding(1) var uTextureSrc : texture_2d; @group(3) @binding(0) var uSamplerDst : sampler; @group(3) @binding(1) var uTextureDst : texture_2d; @@ -402,7 +393,7 @@ struct VertexOutput { @builtin(position) position: vec4f, @location(0) vTexCoord @vertex fn vs_main(in: VertexInput) -> VertexOutput { var out: VertexOutput; - let pos = uViewMat * uModelMat * vec4f(in.position.xy, 0.0, 1.0); + let pos = uViewMat * uPaintSettings.transform * vec4f(in.position.xy, 0.0, 1.0); out.position = pos; out.vTexCoord = in.texCoord; out.vScrCoord = vec2f(0.5 + pos.x * 0.5, 0.5 - pos.y * 0.5); @@ -418,7 +409,7 @@ fn getFragData(in: VertexOutput) -> FragData { var data: FragData; data.Sc = colorSrc.rgb; data.Sa = colorSrc.a; - data.So = uBlendSettings.a; + data.So = uPaintSettings.options.a; data.Dc = colorDst.rgb; data.Da = colorDst.a; data.Sc = data.Sc * data.So; diff --git a/src/renderer/wg_engine/tvgWgShaderTypes.cpp b/src/renderer/wg_engine/tvgWgShaderTypes.cpp index 7f99c189..7997c408 100644 --- a/src/renderer/wg_engine/tvgWgShaderTypes.cpp +++ b/src/renderer/wg_engine/tvgWgShaderTypes.cpp @@ -125,35 +125,34 @@ void WgShaderTypeVec4f::update(const RenderRegion& r) } //************************************************************************ -// WgShaderTypeGradient +// WgShaderTypeGradSettings //************************************************************************ -void WgShaderTypeGradient::update(const LinearGradient* linearGradient) +void WgShaderTypeGradSettings::update(const Fill* fill) { - // update gradient data + assert(fill); + // update transform matrix + Matrix invTransform; + if (inverse(&fill->transform(), &invTransform)) + transform.update(invTransform); + else transform.identity(); + // update gradient base points + if (fill->type() == Type::LinearGradient) + ((LinearGradient*)fill)->linear(&coords.vec[0], &coords.vec[1], &coords.vec[2], &coords.vec[3]); + else if (fill->type() == Type::RadialGradient) + ((RadialGradient*)fill)->radial(&coords.vec[0], &coords.vec[1], &coords.vec[2], &focal.vec[0], &focal.vec[1], &focal.vec[2]); +} + +//************************************************************************ +// WgShaderTypeGradientData +//************************************************************************ + +void WgShaderTypeGradientData::update(const Fill* fill) +{ + if (!fill) return; const Fill::ColorStop* stops = nullptr; - auto stopCnt = linearGradient->colorStops(&stops); - updateTexData(stops, stopCnt); - // update base points - linearGradient->linear(&settings[0], &settings[1], &settings[2], &settings[3]); -}; - - -void WgShaderTypeGradient::update(const RadialGradient* radialGradient) -{ - // update gradient data - const Fill::ColorStop* stops = nullptr; - auto stopCnt = radialGradient->colorStops(&stops); - updateTexData(stops, stopCnt); - // update base points - radialGradient->radial(&settings[0], &settings[1], &settings[2], &settings[4], &settings[5], &settings[6]); -}; - - -void WgShaderTypeGradient::updateTexData(const Fill::ColorStop* stops, uint32_t stopCnt) -{ + auto stopCnt = fill->colorStops(&stops); if (stopCnt == 0) return; - static Array sstops(stopCnt); sstops.clear(); sstops.push(stops[0]); @@ -167,10 +166,10 @@ void WgShaderTypeGradient::updateTexData(const Fill::ColorStop* stops, uint32_t uint32_t range_s = 0; uint32_t range_e = uint32_t(sstops[0].offset * (WG_TEXTURE_GRADIENT_SIZE-1)); for (uint32_t ti = range_s; (ti < range_e) && (ti < WG_TEXTURE_GRADIENT_SIZE); ti++) { - texData[ti * 4 + 0] = sstops[0].r; - texData[ti * 4 + 1] = sstops[0].g; - texData[ti * 4 + 2] = sstops[0].b; - texData[ti * 4 + 3] = sstops[0].a; + data[ti * 4 + 0] = sstops[0].r; + data[ti * 4 + 1] = sstops[0].g; + data[ti * 4 + 2] = sstops[0].b; + data[ti * 4 + 3] = sstops[0].a; } // body for (uint32_t di = 1; di < sstops.count; di++) { @@ -179,10 +178,10 @@ void WgShaderTypeGradient::updateTexData(const Fill::ColorStop* stops, uint32_t float delta = 1.0f/(range_e - range_s); for (uint32_t ti = range_s; (ti < range_e) && (ti < WG_TEXTURE_GRADIENT_SIZE); ti++) { float t = (ti - range_s) * delta; - texData[ti * 4 + 0] = tvg::lerp(sstops[di-1].r, sstops[di].r, t); - texData[ti * 4 + 1] = tvg::lerp(sstops[di-1].g, sstops[di].g, t); - texData[ti * 4 + 2] = tvg::lerp(sstops[di-1].b, sstops[di].b, t); - texData[ti * 4 + 3] = tvg::lerp(sstops[di-1].a, sstops[di].a, t); + data[ti * 4 + 0] = tvg::lerp(sstops[di-1].r, sstops[di].r, t); + data[ti * 4 + 1] = tvg::lerp(sstops[di-1].g, sstops[di].g, t); + data[ti * 4 + 2] = tvg::lerp(sstops[di-1].b, sstops[di].b, t); + data[ti * 4 + 3] = tvg::lerp(sstops[di-1].a, sstops[di].a, t); } } // tail @@ -190,10 +189,10 @@ void WgShaderTypeGradient::updateTexData(const Fill::ColorStop* stops, uint32_t range_s = uint32_t(colorStopLast.offset * (WG_TEXTURE_GRADIENT_SIZE-1)); range_e = WG_TEXTURE_GRADIENT_SIZE; for (uint32_t ti = range_s; ti < range_e; ti++) { - texData[ti * 4 + 0] = colorStopLast.r; - texData[ti * 4 + 1] = colorStopLast.g; - texData[ti * 4 + 2] = colorStopLast.b; - texData[ti * 4 + 3] = colorStopLast.a; + data[ti * 4 + 0] = colorStopLast.r; + data[ti * 4 + 1] = colorStopLast.g; + data[ti * 4 + 2] = colorStopLast.b; + data[ti * 4 + 3] = colorStopLast.a; } } diff --git a/src/renderer/wg_engine/tvgWgShaderTypes.h b/src/renderer/wg_engine/tvgWgShaderTypes.h index 66853217..b4f5f901 100644 --- a/src/renderer/wg_engine/tvgWgShaderTypes.h +++ b/src/renderer/wg_engine/tvgWgShaderTypes.h @@ -55,16 +55,44 @@ struct WgShaderTypeVec4f void update(const RenderRegion& r); }; -// sampler, texture, vec4f -#define WG_TEXTURE_GRADIENT_SIZE 512 -struct WgShaderTypeGradient +// WGSL: struct GradSettings { transform: mat4x4f, coords: vec4f, focal: vec4f }; +struct WgShaderTypeGradSettings { - float settings[4+4]{}; // WGSL: struct GradSettings { settings: vec4f, focal: vec4f; transform: mat4f }; - uint8_t texData[WG_TEXTURE_GRADIENT_SIZE * 4]; + // gradient transform matrix + WgShaderTypeMat4x4f transform; + // linear: [0] - x1, [1] - y1, [2] - x2, [3] - y2 + // radial: [0] - cx, [1] - cy, [2] - cr + WgShaderTypeVec4f coords; + // radial: [0] - fx, [1] - fy, [2] - fr + WgShaderTypeVec4f focal; + + void update(const Fill* fill); +}; - void update(const LinearGradient* linearGradient); - void update(const RadialGradient* radialGradient); - void updateTexData(const Fill::ColorStop* stops, uint32_t stopCnt); +// WGSL: struct PaintSettings { transform: mat4x4f, options: vec4f, color: vec4f, gradient: GradSettings }; +struct WgShaderTypePaintSettings +{ + // paint transform matrix (must be at offset 0) + WgShaderTypeMat4x4f transform; + // [0] - color space, [3] - opacity + WgShaderTypeVec4f options; + // solid color + WgShaderTypeVec4f color; + // gradient settings (linear/radial) + WgShaderTypeGradSettings gradient; + // align to 256 bytes (see webgpu spec: minUniformBufferOffsetAlignment) + uint8_t _padding[256 - sizeof(transform) - sizeof(options) - sizeof(color) - sizeof(gradient)]; +}; +// see webgpu spec: 3.6.2. Limits - minUniformBufferOffsetAlignment (256) +static_assert(sizeof(WgShaderTypePaintSettings) == 256, "Uniform shader data type size must be aligned to 256 bytes"); + +// gradient color map +#define WG_TEXTURE_GRADIENT_SIZE 512 +struct WgShaderTypeGradientData +{ + uint8_t data[WG_TEXTURE_GRADIENT_SIZE * 4]; + + void update(const Fill* fill); }; // gaussian params: sigma, scale, extend