From 889710ecee472b9d7d4111cd075255282f082f9f Mon Sep 17 00:00:00 2001 From: Sergii Liebodkin Date: Wed, 26 Feb 2025 09:48:17 +0000 Subject: [PATCH] wg_engine: Introduce the stroke clipper Issue: https://github.com/thorvg/thorvg/issues/3063 --- src/renderer/wg_engine/tvgWgCompositor.cpp | 37 ++++++++++++++-------- src/renderer/wg_engine/tvgWgCompositor.h | 3 +- src/renderer/wg_engine/tvgWgRenderData.cpp | 2 +- 3 files changed, 26 insertions(+), 16 deletions(-) diff --git a/src/renderer/wg_engine/tvgWgCompositor.cpp b/src/renderer/wg_engine/tvgWgCompositor.cpp index 435451be..a18f3b15 100755 --- a/src/renderer/wg_engine/tvgWgCompositor.cpp +++ b/src/renderer/wg_engine/tvgWgCompositor.cpp @@ -660,6 +660,26 @@ void WgCompositor::blendScene(WgContext& context, WgRenderStorage* scene, WgComp } +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) { + wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 255); + wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.direct); + ARRAY_FOREACH(p, renderData->meshGroupStrokes.meshes) + (*p)->draw(context, renderPassEncoder); + } 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); + } +} + + void WgCompositor::renderClipPath(WgContext& context, WgRenderDataPaint* paint) { assert(paint); @@ -669,17 +689,11 @@ void WgCompositor::renderClipPath(WgContext& context, WgRenderDataPaint* paint) wgpuRenderPassEncoderSetScissorRect(renderPassEncoder, 0, 0, width, height); // get render data WgRenderDataShape* renderData0 = (WgRenderDataShape*)paint->clips[0]; - // set transformations - wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 0, bindGroupViewMat, 0, nullptr); // markup stencil - WGPURenderPipeline stencilPipeline = (renderData0->fillRule == FillRule::NonZero) ? pipelines.nonzero : pipelines.evenodd; - wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0); - wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, renderData0->bindGroupPaint, 0, nullptr); - wgpuRenderPassEncoderSetPipeline(renderPassEncoder, stencilPipeline); - ARRAY_FOREACH(p, renderData0->meshGroupShapes.meshes) - (*p)->drawFan(context, renderPassEncoder); + 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, 2, bindGroupOpacities[128], 0, nullptr); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.copy_stencil_to_depth); @@ -689,12 +703,7 @@ void WgCompositor::renderClipPath(WgContext& context, WgRenderDataPaint* paint) // get render data WgRenderDataShape* renderData = (WgRenderDataShape*)(*p); // markup stencil - WGPURenderPipeline stencilPipeline = (renderData->fillRule == FillRule::NonZero) ? pipelines.nonzero : pipelines.evenodd; - wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0); - wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, renderData->bindGroupPaint, 0, nullptr); - wgpuRenderPassEncoderSetPipeline(renderPassEncoder, stencilPipeline); - ARRAY_FOREACH(p, renderData->meshGroupShapes.meshes) - (*p)->drawFan(context, renderPassEncoder); + markupClipPath(context, renderData); // copy stencil to depth (clear stencil) wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, renderData->bindGroupPaint, 0, nullptr); diff --git a/src/renderer/wg_engine/tvgWgCompositor.h b/src/renderer/wg_engine/tvgWgCompositor.h index 3bc9a209..14eed4f8 100755 --- a/src/renderer/wg_engine/tvgWgCompositor.h +++ b/src/renderer/wg_engine/tvgWgCompositor.h @@ -68,7 +68,6 @@ private: void copyTexture(const WgRenderStorage* dst, const WgRenderStorage* src); void copyTexture(const WgRenderStorage* dst, const WgRenderStorage* src, const RenderRegion& region); - // shapes void drawShape(WgContext& context, WgRenderDataShape* renderData); void blendShape(WgContext& context, WgRenderDataShape* renderData, BlendMethod blendMethod); @@ -88,6 +87,8 @@ private: void drawScene(WgContext& context, WgRenderStorage* scene, WgCompose* compose); void blendScene(WgContext& context, WgRenderStorage* src, WgCompose* compose); + // the renderer prioritizes clipping with the stroke over the shape's fill + void markupClipPath(WgContext& context, WgRenderDataShape* renderData); void renderClipPath(WgContext& context, WgRenderDataPaint* paint); void clearClipPath(WgContext& context, WgRenderDataPaint* paint); diff --git a/src/renderer/wg_engine/tvgWgRenderData.cpp b/src/renderer/wg_engine/tvgWgRenderData.cpp index 0f718c3d..a293be3e 100755 --- a/src/renderer/wg_engine/tvgWgRenderData.cpp +++ b/src/renderer/wg_engine/tvgWgRenderData.cpp @@ -376,7 +376,7 @@ void WgRenderDataShape::updateMeshes(WgContext& context, const RenderShape &rsha pbuff->decodePath(rshape, true, [&](const WgVertexBuffer& path_buff) { appendShape(context, path_buff); - if (rshape.stroke) proceedStrokes(context, rshape.stroke, path_buff, pool); + if ((rshape.stroke) && (rshape.stroke->width > 0)) proceedStrokes(context, rshape.stroke, path_buff, pool); }, rshape.trimpath()); // update shapes bbox (with empty path handling)