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) void WgCompositor::renderClipPath(WgContext& context, WgRenderDataPaint* paint)
{ {
assert(paint); assert(paint);
@ -669,17 +689,11 @@ void WgCompositor::renderClipPath(WgContext& context, WgRenderDataPaint* paint)
wgpuRenderPassEncoderSetScissorRect(renderPassEncoder, 0, 0, width, height); wgpuRenderPassEncoderSetScissorRect(renderPassEncoder, 0, 0, width, height);
// get render data // get render data
WgRenderDataShape* renderData0 = (WgRenderDataShape*)paint->clips[0]; WgRenderDataShape* renderData0 = (WgRenderDataShape*)paint->clips[0];
// set transformations
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 0, bindGroupViewMat, 0, nullptr);
// markup stencil // markup stencil
WGPURenderPipeline stencilPipeline = (renderData0->fillRule == FillRule::NonZero) ? pipelines.nonzero : pipelines.evenodd; markupClipPath(context, renderData0);
wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0);
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, renderData0->bindGroupPaint, 0, nullptr);
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, stencilPipeline);
ARRAY_FOREACH(p, renderData0->meshGroupShapes.meshes)
(*p)->drawFan(context, renderPassEncoder);
// copy stencil to depth // copy stencil to depth
wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0); wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0);
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 0, bindGroupViewMat, 0, nullptr);
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, renderData0->bindGroupPaint, 0, nullptr); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, renderData0->bindGroupPaint, 0, nullptr);
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, bindGroupOpacities[128], 0, nullptr); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, bindGroupOpacities[128], 0, nullptr);
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.copy_stencil_to_depth); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.copy_stencil_to_depth);
@ -689,12 +703,7 @@ void WgCompositor::renderClipPath(WgContext& context, WgRenderDataPaint* paint)
// get render data // get render data
WgRenderDataShape* renderData = (WgRenderDataShape*)(*p); WgRenderDataShape* renderData = (WgRenderDataShape*)(*p);
// markup stencil // markup stencil
WGPURenderPipeline stencilPipeline = (renderData->fillRule == FillRule::NonZero) ? pipelines.nonzero : pipelines.evenodd; markupClipPath(context, renderData);
wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0);
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, renderData->bindGroupPaint, 0, nullptr);
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, stencilPipeline);
ARRAY_FOREACH(p, renderData->meshGroupShapes.meshes)
(*p)->drawFan(context, renderPassEncoder);
// copy stencil to depth (clear stencil) // copy stencil to depth (clear stencil)
wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0); wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0);
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, renderData->bindGroupPaint, 0, nullptr); 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);
void copyTexture(const WgRenderStorage* dst, const WgRenderStorage* src, const RenderRegion& region); void copyTexture(const WgRenderStorage* dst, const WgRenderStorage* src, const RenderRegion& region);
// shapes // shapes
void drawShape(WgContext& context, WgRenderDataShape* renderData); void drawShape(WgContext& context, WgRenderDataShape* renderData);
void blendShape(WgContext& context, WgRenderDataShape* renderData, BlendMethod blendMethod); void blendShape(WgContext& context, WgRenderDataShape* renderData, BlendMethod blendMethod);
@ -88,6 +87,8 @@ private:
void drawScene(WgContext& context, WgRenderStorage* scene, WgCompose* compose); void drawScene(WgContext& context, WgRenderStorage* scene, WgCompose* compose);
void blendScene(WgContext& context, WgRenderStorage* src, 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 renderClipPath(WgContext& context, WgRenderDataPaint* paint);
void clearClipPath(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) { pbuff->decodePath(rshape, true, [&](const WgVertexBuffer& path_buff) {
appendShape(context, 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()); }, rshape.trimpath());
// update shapes bbox (with empty path handling) // update shapes bbox (with empty path handling)