wg_engine: Introduce the stroke clipper

Issue: https://github.com/thorvg/thorvg/issues/3063
This commit is contained in:
Sergii Liebodkin 2025-02-26 09:48:17 +00:00 committed by Hermet Park
parent 173822b1d9
commit 889710ecee
3 changed files with 26 additions and 16 deletions

View file

@ -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);

View file

@ -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);

View file

@ -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)