wg_engine: clippath optimization

Full review of clipping workflow.

Before we are used separate render target for each clip path and compute shader to find clip path intersections with AND logic.
Now we are using depth buffer and transactions from depth to stencil and back to get AND logic intersections,
Compute shaders, layouts and pipelines was removed
This commit is contained in:
Sergii Liebodkin 2024-10-22 09:23:15 +00:00 committed by Hermet Park
parent a1296960eb
commit 0815366763
6 changed files with 330 additions and 214 deletions

View file

@ -31,7 +31,7 @@ void WgCompositor::initialize(WgContext& context, uint32_t width, uint32_t heigh
this->width = width;
this->height = height;
// allocate global stencil buffer handles
texStencil = context.createTexStencil(width, height, WGPUTextureFormat_Stencil8);
texStencil = context.createTexStencil(width, height, WGPUTextureFormat_Depth24PlusStencil8);
texViewStencil = context.createTextureView(texStencil);
// allocate global view matrix handles
WgShaderTypeMat4x4f viewMat(width, height);
@ -44,8 +44,6 @@ void WgCompositor::initialize(WgContext& context, uint32_t width, uint32_t heigh
bindGroupOpacities[i] = pipelines->layouts.createBindGroupBuffer1Un(bufferOpacities[i]);
}
// initialize intermediate render storages
storageClipPath.initialize(context, width, height);
storageInterm.initialize(context, width, height);
storageDstCopy.initialize(context, width, height);
// composition and blend geometries
meshData.blitBox(context);
@ -57,9 +55,7 @@ void WgCompositor::release(WgContext& context)
// composition and blend geometries
meshData.release(context);
// release intermediate render storages
storageInterm.release(context);
storageDstCopy.release(context);
storageClipPath.release(context);
// release opacity pool
for (uint32_t i = 0; i < 256; i++) {
context.pipelines->layouts.releaseBindGroup(bindGroupOpacities[i]);
@ -94,7 +90,12 @@ void WgCompositor::beginRenderPass(WGPUCommandEncoder commandEncoder, WgRenderSt
assert(target);
this->currentTarget = target;
this->commandEncoder = commandEncoder;
WGPURenderPassDepthStencilAttachment depthStencilAttachment{ .view = texViewStencil, .stencilLoadOp = WGPULoadOp_Clear, .stencilStoreOp = WGPUStoreOp_Discard };
const WGPURenderPassDepthStencilAttachment depthStencilAttachment{
.view = texViewStencil,
.depthLoadOp = WGPULoadOp_Load, .depthStoreOp = WGPUStoreOp_Discard, .depthClearValue = 1.0f,
.stencilLoadOp = WGPULoadOp_Load, .stencilStoreOp = WGPUStoreOp_Discard, .stencilClearValue = 0
};
//WGPURenderPassDepthStencilAttachment depthStencilAttachment{ .view = texViewStencil, .depthClearValue = 1.0f, .stencilLoadOp = WGPULoadOp_Clear, .stencilStoreOp = WGPUStoreOp_Discard };
WGPURenderPassColorAttachment colorAttachment{};
colorAttachment.view = target->texView,
colorAttachment.loadOp = clear ? WGPULoadOp_Clear : WGPULoadOp_Load,
@ -124,14 +125,15 @@ void WgCompositor::renderShape(WgContext& context, WgRenderDataShape* renderData
assert(renderPassEncoder);
// apply clip path if neccessary
if (renderData->clips.count != 0) {
renderClipPath(context, renderData, &storageClipPath);
renderClipPath(context, renderData);
if (renderData->strokeFirst) {
clipStrokes(context, renderData, &storageClipPath);
clipShape(context, renderData, &storageClipPath);
clipStrokes(context, renderData);
clipShape(context, renderData);
} else {
clipShape(context, renderData, &storageClipPath);
clipStrokes(context, renderData, &storageClipPath);
clipShape(context, renderData);
clipStrokes(context, renderData);
}
clearClipPath(context, renderData);
// use custom blending
} else if (blendMethod != BlendMethod::Normal) {
if (renderData->strokeFirst) {
@ -160,8 +162,9 @@ void WgCompositor::renderImage(WgContext& context, WgRenderDataPicture* renderDa
assert(renderPassEncoder);
// apply clip path if neccessary
if (renderData->clips.count != 0) {
renderClipPath(context, renderData, &storageClipPath);
clipImage(context, renderData, &storageClipPath);
renderClipPath(context, renderData);
clipImage(context, renderData);
clearClipPath(context, renderData);
// use custom blending
} else if (blendMethod != BlendMethod::Normal)
blendImage(context, renderData, blendMethod);
@ -200,12 +203,16 @@ void WgCompositor::composeScene(WgContext& context, WgRenderStorage* src, WgRend
void WgCompositor::blit(WgContext& context, WGPUCommandEncoder encoder, WgRenderStorage* src, WGPUTextureView dstView) {
WGPURenderPassDepthStencilAttachment depthStencilAttachment{ .view = texViewStencil, .stencilLoadOp = WGPULoadOp_Load, .stencilStoreOp = WGPUStoreOp_Discard };
const WGPURenderPassDepthStencilAttachment depthStencilAttachment{
.view = texViewStencil,
.depthLoadOp = WGPULoadOp_Load, .depthStoreOp = WGPUStoreOp_Discard,
.stencilLoadOp = WGPULoadOp_Load, .stencilStoreOp = WGPUStoreOp_Discard
};
WGPURenderPassColorAttachment colorAttachment { .view = dstView, .loadOp = WGPULoadOp_Load, .storeOp = WGPUStoreOp_Store };
#ifdef __EMSCRIPTEN__
colorAttachment.depthSlice = WGPU_DEPTH_SLICE_UNDEFINED;
#endif
WGPURenderPassDescriptor renderPassDesc{ .colorAttachmentCount = 1, .colorAttachments = &colorAttachment, .depthStencilAttachment = &depthStencilAttachment };
const WGPURenderPassDescriptor renderPassDesc{ .colorAttachmentCount = 1, .colorAttachments = &colorAttachment, .depthStencilAttachment = &depthStencilAttachment };
WGPURenderPassEncoder renderPass = wgpuCommandEncoderBeginRenderPass(encoder, &renderPassDesc);
wgpuRenderPassEncoderSetBindGroup(renderPass, 0, src->bindGroupTexure, 0, nullptr);
wgpuRenderPassEncoderSetPipeline(renderPass, pipelines->blit);
@ -302,26 +309,46 @@ void WgCompositor::blendShape(WgContext& context, WgRenderDataShape* renderData,
}
void WgCompositor::clipShape(WgContext& context, WgRenderDataShape* renderData, WgRenderStorage* mask)
void WgCompositor::clipShape(WgContext& context, WgRenderDataShape* renderData)
{
assert(mask);
assert(renderData);
assert(commandEncoder);
assert(currentTarget);
// skip shape composing if shape do not exist
assert(renderPassEncoder);
assert(renderData->meshGroupShapes.meshes.count == renderData->meshGroupShapesBBox.meshes.count);
if (renderData->renderSettingsShape.skip) return;
if (renderData->meshGroupShapes.meshes.count == 0) return;
// store current render pass
WgRenderStorage *target = currentTarget;
endRenderPass();
// render into intermediate buffer
beginRenderPass(commandEncoder, &storageInterm, true);
drawShape(context, renderData);
endRenderPass();
// restore current render pass
beginRenderPass(commandEncoder, target, false);
RenderRegion rect = shrinkRenderRegion(renderData->aabb);
clipRegion(context, &storageInterm, mask, rect);
if ((renderData->viewport.w <= 0) || (renderData->viewport.h <= 0)) return;
wgpuRenderPassEncoderSetScissorRect(renderPassEncoder, renderData->viewport.x, renderData->viewport.y, renderData->viewport.w, renderData->viewport.h);
// setup stencil rules
WGPURenderPipeline stencilPipeline = (renderData->fillRule == FillRule::Winding) ? pipelines->winding : pipelines->evenodd;
wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0);
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 0, bindGroupViewMat, 0, nullptr);
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, renderData->bindGroupPaint, 0, nullptr);
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, stencilPipeline);
// draw to stencil (first pass)
for (uint32_t i = 0; i < renderData->meshGroupShapes.meshes.count; i++)
renderData->meshGroupShapes.meshes[i]->drawFan(context, renderPassEncoder);
// merge depth and stencil buffer
wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0);
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, bindGroupOpacities[128], 0, nullptr);
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines->merge_depth_stencil);
renderData->meshDataBBox.drawFan(context, renderPassEncoder);
// setup fill rules
wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0);
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 0, bindGroupViewMat, 0, nullptr);
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, renderData->bindGroupPaint, 0, nullptr);
WgRenderSettings& settings = renderData->renderSettingsShape;
if (settings.fillType == WgRenderSettingsType::Solid) {
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, settings.bindGroupSolid, 0, nullptr);
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines->solid);
} else if (settings.fillType == WgRenderSettingsType::Linear) {
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, settings.bindGroupGradient, 0, nullptr);
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines->linear);
} else if (settings.fillType == WgRenderSettingsType::Radial) {
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, settings.bindGroupGradient, 0, nullptr);
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines->radial);
}
// draw to color (second pass)
renderData->meshDataBBox.drawFan(context, renderPassEncoder);
}
@ -413,26 +440,47 @@ void WgCompositor::blendStrokes(WgContext& context, WgRenderDataShape* renderDat
};
void WgCompositor::clipStrokes(WgContext& context, WgRenderDataShape* renderData, WgRenderStorage* mask)
void WgCompositor::clipStrokes(WgContext& context, WgRenderDataShape* renderData)
{
assert(mask);
assert(renderData);
assert(commandEncoder);
assert(currentTarget);
// skip shape composing if strokes do not exist
assert(renderPassEncoder);
assert(renderData->meshGroupStrokes.meshes.count == renderData->meshGroupStrokesBBox.meshes.count);
if (renderData->renderSettingsStroke.skip) return;
if (renderData->meshGroupStrokes.meshes.count == 0) return;
// store current render pass
WgRenderStorage *target = currentTarget;
endRenderPass();
// render into intermediate buffer
beginRenderPass(commandEncoder, &storageInterm, true);
drawStrokes(context, renderData);
endRenderPass();
// restore current render pass
beginRenderPass(commandEncoder, target, false);
RenderRegion rect = shrinkRenderRegion(renderData->aabb);
clipRegion(context, &storageInterm, mask, rect);
if ((renderData->viewport.w <= 0) || (renderData->viewport.h <= 0)) return;
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);
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines->direct);
// draw to stencil (first pass)
renderData->meshGroupStrokes.meshes[i]->draw(context, renderPassEncoder);
// merge depth and stencil buffer
wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0);
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, bindGroupOpacities[128], 0, nullptr);
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines->merge_depth_stencil);
renderData->meshDataBBox.drawFan(context, renderPassEncoder);
// setup fill rules
wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0);
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 0, bindGroupViewMat, 0, nullptr);
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, renderData->bindGroupPaint, 0, nullptr);
WgRenderSettings& settings = renderData->renderSettingsStroke;
if (settings.fillType == WgRenderSettingsType::Solid) {
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, settings.bindGroupSolid, 0, nullptr);
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines->solid);
} else if (settings.fillType == WgRenderSettingsType::Linear) {
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, settings.bindGroupGradient, 0, nullptr);
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines->linear);
} else if (settings.fillType == WgRenderSettingsType::Radial) {
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, settings.bindGroupGradient, 0, nullptr);
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines->radial);
}
// draw to color (second pass)
renderData->meshGroupStrokesBBox.meshes[i]->drawFan(context, renderPassEncoder);
}
}
@ -442,6 +490,13 @@ void WgCompositor::drawImage(WgContext& context, WgRenderDataPicture* renderData
assert(renderPassEncoder);
if ((renderData->viewport.w <= 0) || (renderData->viewport.h <= 0)) return;
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);
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines->direct);
renderData->meshData.drawImage(context, renderPassEncoder);
// draw image
wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0);
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 0, bindGroupViewMat, 0, nullptr);
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, renderData->bindGroupPaint, 0, nullptr);
@ -456,6 +511,7 @@ void WgCompositor::blendImage(WgContext& context, WgRenderDataPicture* renderDat
assert(renderData);
assert(renderPassEncoder);
if ((renderData->viewport.w <= 0) || (renderData->viewport.h <= 0)) return;
wgpuRenderPassEncoderSetScissorRect(renderPassEncoder, renderData->viewport.x, renderData->viewport.y, renderData->viewport.w, renderData->viewport.h);
// copy current render target data to dst storage
WgRenderStorage *target = currentTarget;
endRenderPass();
@ -464,9 +520,14 @@ void WgCompositor::blendImage(WgContext& context, WgRenderDataPicture* renderDat
const WGPUExtent3D copySize { .width = width, .height = height, .depthOrArrayLayers = 1 };
wgpuCommandEncoderCopyTextureToTexture(commandEncoder, &texSrc, &texDst, &copySize);
beginRenderPass(commandEncoder, target, false);
// setup stencil rules
wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 255);
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 0, bindGroupViewMat, 0, nullptr);
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, renderData->bindGroupPaint, 0, nullptr);
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines->direct);
renderData->meshData.drawImage(context, renderPassEncoder);
// blend image
uint32_t blendMethodInd = (uint32_t)blendMethod;
wgpuRenderPassEncoderSetScissorRect(renderPassEncoder, renderData->viewport.x, renderData->viewport.y, renderData->viewport.w, renderData->viewport.h);
wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0);
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 0, bindGroupViewMat, 0, nullptr);
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, renderData->bindGroupPaint, 0, nullptr);
@ -477,23 +538,30 @@ void WgCompositor::blendImage(WgContext& context, WgRenderDataPicture* renderDat
};
void WgCompositor::clipImage(WgContext& context, WgRenderDataPicture* renderData, WgRenderStorage* mask)
void WgCompositor::clipImage(WgContext& context, WgRenderDataPicture* renderData)
{
assert(mask);
assert(renderData);
assert(commandEncoder);
assert(currentTarget);
// store current render pass
WgRenderStorage *target = currentTarget;
endRenderPass();
// render into intermediate buffer
beginRenderPass(commandEncoder, &storageInterm, true);
drawImage(context, renderData);
endRenderPass();
// restore current render pass
beginRenderPass(commandEncoder, target, false);
RenderRegion rect { 0, 0, (int32_t)width, (int32_t)height };
clipRegion(context, &storageInterm, mask, rect);
assert(renderPassEncoder);
if ((renderData->viewport.w <= 0) || (renderData->viewport.h <= 0)) return;
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);
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines->direct);
renderData->meshData.drawImage(context, renderPassEncoder);
// merge depth and stencil buffer
wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0);
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, bindGroupOpacities[128], 0, nullptr);
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines->merge_depth_stencil);
renderData->meshData.drawImage(context, renderPassEncoder);
// draw image
wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0);
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 0, bindGroupViewMat, 0, nullptr);
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, renderData->bindGroupPaint, 0, nullptr);
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, renderData->bindGroupPicture, 0, nullptr);
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines->image);
renderData->meshData.drawImage(context, renderPassEncoder);
}
@ -539,85 +607,91 @@ void WgCompositor::blendScene(WgContext& context, WgRenderStorage* scene, WgComp
}
void WgCompositor::drawClipPath(WgContext& context, WgRenderDataShape* renderData)
void WgCompositor::renderClipPath(WgContext& context, WgRenderDataPaint* paint)
{
assert(renderData);
assert(paint);
assert(renderPassEncoder);
assert(renderData->meshGroupShapes.meshes.count == renderData->meshGroupShapesBBox.meshes.count);
if ((renderData->viewport.w <= 0) || (renderData->viewport.h <= 0)) return;
wgpuRenderPassEncoderSetScissorRect(renderPassEncoder, renderData->viewport.x, renderData->viewport.y, renderData->viewport.w, renderData->viewport.h);
// setup stencil rules
WGPURenderPipeline stencilPipeline = (renderData->fillRule == FillRule::Winding) ? pipelines->winding : pipelines->evenodd;
wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0);
assert(paint->clips.count > 0);
// reset scissor recr to full screen
wgpuRenderPassEncoderSetScissorRect(renderPassEncoder, 0, 0, width, height);
// get render data
WgRenderDataShape* renderData0 = (WgRenderDataShape*)paint->clips[0];
// set transformations
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 0, bindGroupViewMat, 0, nullptr);
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, renderData->bindGroupPaint, 0, nullptr);
// markup stencil
WGPURenderPipeline stencilPipeline = (renderData0->fillRule == FillRule::Winding) ? pipelines->winding : pipelines->evenodd;
wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0);
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, renderData0->bindGroupPaint, 0, nullptr);
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, stencilPipeline);
// draw to stencil (first pass)
for (uint32_t i = 0; i < renderData->meshGroupShapes.meshes.count; i++)
renderData->meshGroupShapes.meshes[i]->drawFan(context, renderPassEncoder);
// setup fill rules
for (uint32_t i = 0; i < renderData0->meshGroupShapes.meshes.count; i++)
renderData0->meshGroupShapes.meshes[i]->drawFan(context, renderPassEncoder);
// copy stencil to depth
wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0);
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 0, bindGroupViewMat, 0, nullptr);
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, renderData->bindGroupPaint, 0, nullptr);
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines->clip_path);
// draw to color (second pass)
renderData->meshDataBBox.drawFan(context, renderPassEncoder);
}
void WgCompositor::clipRegion(WgContext& context, WgRenderStorage* src, WgRenderStorage* mask, RenderRegion& rect)
{
wgpuRenderPassEncoderSetScissorRect(renderPassEncoder, rect.x, rect.y, rect.w, rect.h);
wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0);
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 0, storageInterm.bindGroupTexure, 0, nullptr);
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, mask->bindGroupTexure, 0, nullptr);
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines->scene_clip);
meshData.drawImage(context, renderPassEncoder);
}
void WgCompositor::renderClipPath(WgContext& context, WgRenderDataPaint* renderData, WgRenderStorage* dst)
{
assert(renderData);
if (renderData->clips.count == 0) return;
// store current render pass
WgRenderStorage *target = currentTarget;
endRenderPass();
// render first clip path
beginRenderPass(commandEncoder, dst, true);
drawClipPath(context, (WgRenderDataShape*)(renderData->clips[0]));
endRenderPass();
// render amd merge clip paths
for (uint32_t i = 1 ; i < renderData->clips.count; i++) {
// render clip path
beginRenderPass(commandEncoder, &storageInterm, true);
drawClipPath(context, (WgRenderDataShape*)(renderData->clips[i]));
endRenderPass();
// merge masks
mergeMasks(commandEncoder, &storageInterm, dst);
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, renderData0->bindGroupPaint, 0, nullptr);
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, bindGroupOpacities[128], 0, nullptr);
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines->copy_stencil_to_depth);
renderData0->meshDataBBox.drawFan(context, renderPassEncoder);
// merge clip pathes with AND logic
for (uint32_t clipIndex = 1; clipIndex < paint->clips.count; clipIndex++) {
// get render data
WgRenderDataShape* renderData = (WgRenderDataShape*)paint->clips[clipIndex];
// markup stencil
WGPURenderPipeline stencilPipeline = (renderData->fillRule == FillRule::Winding) ? pipelines->winding : pipelines->evenodd;
wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0);
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, renderData->bindGroupPaint, 0, nullptr);
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, stencilPipeline);
for (uint32_t i = 0; i < renderData->meshGroupShapes.meshes.count; i++)
renderData->meshGroupShapes.meshes[i]->drawFan(context, renderPassEncoder);
// copy stencil to depth (clear stencil)
wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0);
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, renderData->bindGroupPaint, 0, nullptr);
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, bindGroupOpacities[190], 0, nullptr);
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines->copy_stencil_to_depth_interm);
renderData->meshDataBBox.drawFan(context, renderPassEncoder);
// copy depth to stencil
wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 1);
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, renderData->bindGroupPaint, 0, nullptr);
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, bindGroupOpacities[190], 0, nullptr);
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines->copy_depth_to_stencil);
renderData->meshDataBBox.drawFan(context, renderPassEncoder);
// clear depth current (keep stencil)
wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0);
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, renderData->bindGroupPaint, 0, nullptr);
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, bindGroupOpacities[255], 0, nullptr);
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines->clear_depth);
renderData->meshDataBBox.drawFan(context, renderPassEncoder);
// clear depth original (keep stencil)
wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0);
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, renderData0->bindGroupPaint, 0, nullptr);
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, bindGroupOpacities[255], 0, nullptr);
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines->clear_depth);
renderData0->meshDataBBox.drawFan(context, renderPassEncoder);
// copy stencil to depth (clear stencil)
wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0);
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, renderData->bindGroupPaint, 0, nullptr);
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, bindGroupOpacities[128], 0, nullptr);
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines->copy_stencil_to_depth);
renderData->meshDataBBox.drawFan(context, renderPassEncoder);
}
// restore current render pass
beginRenderPass(commandEncoder, target, false);
}
void WgCompositor::mergeMasks(WGPUCommandEncoder encoder, WgRenderStorage* mask0, WgRenderStorage* mask1)
void WgCompositor::clearClipPath(WgContext& context, WgRenderDataPaint* paint)
{
assert(mask0);
assert(mask1);
assert(!renderPassEncoder);
// copy dst storage to temporary read only storage
const WGPUImageCopyTexture texSrc { .texture = mask1->texture };
const WGPUImageCopyTexture texDst { .texture = storageDstCopy.texture };
const WGPUExtent3D copySize { .width = width, .height = height, .depthOrArrayLayers = 1 };
wgpuCommandEncoderCopyTextureToTexture(encoder, &texSrc, &texDst, &copySize);
// execute compose shader
const WGPUComputePassDescriptor computePassDescriptor{};
WGPUComputePassEncoder computePassEncoder = wgpuCommandEncoderBeginComputePass(encoder, &computePassDescriptor);
wgpuComputePassEncoderSetBindGroup(computePassEncoder, 0, mask0->bindGroupRead, 0, nullptr);
wgpuComputePassEncoderSetBindGroup(computePassEncoder, 1, storageDstCopy.bindGroupRead, 0, nullptr);
wgpuComputePassEncoderSetBindGroup(computePassEncoder, 2, mask1->bindGroupWrite, 0, nullptr);
wgpuComputePassEncoderSetPipeline(computePassEncoder, pipelines->merge_masks);
wgpuComputePassEncoderDispatchWorkgroups(computePassEncoder, (width + 7) / 8, (height + 7) / 8, 1);
wgpuComputePassEncoderEnd(computePassEncoder);
assert(paint);
assert(renderPassEncoder);
assert(paint->clips.count > 0);
// reset scissor recr to full screen
wgpuRenderPassEncoderSetScissorRect(renderPassEncoder, 0, 0, width, height);
// get render data
for (uint32_t clipIndex = 0; clipIndex < paint->clips.count; clipIndex++) {
WgRenderDataShape* renderData = (WgRenderDataShape*)paint->clips[clipIndex];
// set transformations
wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0);
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 0, bindGroupViewMat, 0, nullptr);
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, renderData->bindGroupPaint, 0, nullptr);
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, bindGroupOpacities[255], 0, nullptr);
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines->clear_depth);
renderData->meshDataBBox.drawFan(context, renderPassEncoder);
}
}

View file

@ -51,8 +51,6 @@ private:
WGPUCommandEncoder commandEncoder{};
WgRenderStorage* currentTarget{};
// intermediate render storages
WgRenderStorage storageInterm;
WgRenderStorage storageClipPath;
WgRenderStorage storageDstCopy;
// composition and blend geometries
WgMeshData meshData;
@ -82,27 +80,24 @@ private:
// shapes
void drawShape(WgContext& context, WgRenderDataShape* renderData);
void blendShape(WgContext& context, WgRenderDataShape* renderData, BlendMethod blendMethod);
void clipShape(WgContext& context, WgRenderDataShape* renderData, WgRenderStorage* mask); // TODO: optimize
void clipShape(WgContext& context, WgRenderDataShape* renderData);
// strokes
void drawStrokes(WgContext& context, WgRenderDataShape* renderData);
void blendStrokes(WgContext& context, WgRenderDataShape* renderData, BlendMethod blendMethod);
void clipStrokes(WgContext& context, WgRenderDataShape* renderData, WgRenderStorage* mask); // TODO: optimize
void clipStrokes(WgContext& context, WgRenderDataShape* renderData);
// images
void drawImage(WgContext& context, WgRenderDataPicture* renderData);
void blendImage(WgContext& context, WgRenderDataPicture* renderData, BlendMethod blendMethod);
void clipImage(WgContext& context, WgRenderDataPicture* renderData, WgRenderStorage* mask); // TODO: optimize
void clipImage(WgContext& context, WgRenderDataPicture* renderData);
// scenes
void drawScene(WgContext& context, WgRenderStorage* scene, WgCompose* compose);
void blendScene(WgContext& context, WgRenderStorage* src, WgCompose* compose);
private:
// clip path utils (TODO: optimize)
void drawClipPath(WgContext& context, WgRenderDataShape* renderData);
void clipRegion(WgContext& context, WgRenderStorage* src, WgRenderStorage* mask, RenderRegion& rect);
void renderClipPath(WgContext& context, WgRenderDataPaint* renderData, WgRenderStorage* dst);
void mergeMasks(WGPUCommandEncoder encoder, WgRenderStorage* mask0, WgRenderStorage* mask1);
void renderClipPath(WgContext& context, WgRenderDataPaint* paint);
void clearClipPath(WgContext& context, WgRenderDataPaint* paint);
};
#endif // _TVG_WG_COMPOSITOR_H_

View file

@ -49,14 +49,15 @@ WGPURenderPipeline WgPipelines::createRenderPipeline(
const WGPUColorWriteMaskFlags writeMask, const WGPUTextureFormat colorTargetFormat,
const WGPUCompareFunction stencilFunctionFrnt, const WGPUStencilOperation stencilOperationFrnt,
const WGPUCompareFunction stencilFunctionBack, const WGPUStencilOperation stencilOperationBack,
const WGPUPrimitiveState primitiveState, const WGPUMultisampleState multisampleState, const WGPUBlendState blendState)
const WGPUCompareFunction depthCompare, WGPUBool depthWriteEnabled, const WGPUMultisampleState multisampleState, const WGPUBlendState blendState)
{
const WGPUColorTargetState colorTargetState { .format = colorTargetFormat, .blend = &blendState, .writeMask = writeMask };
const WGPUColorTargetState colorTargetStates[] { colorTargetState };
const WGPUPrimitiveState primitiveState { .topology = WGPUPrimitiveTopology_TriangleList };
const WGPUDepthStencilState depthStencilState {
.format = WGPUTextureFormat_Stencil8, .depthCompare = WGPUCompareFunction_Always,
.stencilFront = { .compare = stencilFunctionFrnt, .failOp = stencilOperationFrnt, .depthFailOp = stencilOperationFrnt, .passOp = stencilOperationFrnt },
.stencilBack = { .compare = stencilFunctionBack, .failOp = stencilOperationBack, .depthFailOp = stencilOperationBack, .passOp = stencilOperationBack },
.format = WGPUTextureFormat_Depth24PlusStencil8, .depthWriteEnabled = depthWriteEnabled, .depthCompare = depthCompare,
.stencilFront = { .compare = stencilFunctionFrnt, .failOp = stencilOperationFrnt, .depthFailOp = WGPUStencilOperation_Zero, .passOp = stencilOperationFrnt },
.stencilBack = { .compare = stencilFunctionBack, .failOp = stencilOperationBack, .depthFailOp = WGPUStencilOperation_Zero, .passOp = stencilOperationBack },
.stencilReadMask = 0xFFFFFFFF, .stencilWriteMask = 0xFFFFFFFF
};
const WGPUVertexState vertexState { .module = shaderModule, .entryPoint = vsEntryPoint, .bufferCount = vertexBufferLayoutsCount, .buffers = vertexBufferLayouts };
@ -145,7 +146,6 @@ void WgPipelines::initialize(WgContext& context)
const WGPUVertexBufferLayout vertexBufferLayoutTex { .arrayStride = 8, .stepMode = WGPUVertexStepMode_Vertex, .attributeCount = 1, .attributes = vertexAttributesTex };
const WGPUVertexBufferLayout vertexBufferLayoutsShape[] { vertexBufferLayoutPos };
const WGPUVertexBufferLayout vertexBufferLayoutsImage[] { vertexBufferLayoutPos, vertexBufferLayoutTex };
const WGPUPrimitiveState primitiveState { .topology = WGPUPrimitiveTopology_TriangleList };
const WGPUMultisampleState multisampleState { .count = 1, .mask = 0xFFFFFFFF, .alphaToCoverageEnabled = false };
const WGPUTextureFormat offscreenTargetFormat = WGPUTextureFormat_RGBA8Unorm;
@ -161,6 +161,7 @@ void WgPipelines::initialize(WgContext& context)
// bind group layouts helpers
const WGPUBindGroupLayout bindGroupLayoutsStencil[] = { layouts.layoutBuffer1Un, layouts.layoutBuffer2Un };
const WGPUBindGroupLayout bindGroupLayoutsDepth[] = { layouts.layoutBuffer1Un, layouts.layoutBuffer2Un, 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 };
@ -173,13 +174,13 @@ void WgPipelines::initialize(WgContext& context)
const WGPUBindGroupLayout bindGroupLayoutsSceneBlend[] { layouts.layoutTexSampled, layouts.layoutTexSampled, layouts.layoutBuffer1Un };
// bind group layouts scene compose
const WGPUBindGroupLayout bindGroupLayoutsSceneCompose[] { layouts.layoutTexSampled, layouts.layoutTexSampled };
const WGPUBindGroupLayout bindGroupLayoutsMergeMasks[] { layouts.layoutTexStrorage1RO, layouts.layoutTexStrorage1RO, layouts.layoutTexStrorage1WO };
// bind group layouts blit
const WGPUBindGroupLayout bindGroupLayoutsBlit[] { layouts.layoutTexSampled };
// shaders
char shaderSourceBuff[16384]{};
shader_stencil = createShaderModule(context.device, "The shader stencil", cShaderSrc_Stencil);
shader_depth = createShaderModule(context.device, "The shader depth", cShaderSrc_Depth);
// shader normal blend
shader_solid = createShaderModule(context.device, "The shader solid", cShaderSrc_Solid);
shader_radial = createShaderModule(context.device, "The shader radial", cShaderSrc_Radial);
@ -194,12 +195,12 @@ void WgPipelines::initialize(WgContext& context)
shader_scene_blend = createShaderModule(context.device, "The shader blend scene", strcat(strcpy(shaderSourceBuff, cShaderSrc_Scene_Blend), cShaderSrc_BlendFuncs));
// shader compose
shader_scene_compose = createShaderModule(context.device, "The shader scene composition", cShaderSrc_Scene_Compose);
shader_merge_masks = createShaderModule(context.device, "The shader merge mask", cShaderSrc_MergeMasks);
// shader blit
shader_blit = createShaderModule(context.device, "The shader blit", cShaderSrc_Blit);
// layouts
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_gradient = createPipelineLayout(context.device, bindGroupLayoutsGradient, 3);
@ -212,7 +213,6 @@ void WgPipelines::initialize(WgContext& context)
layout_scene_blend = createPipelineLayout(context.device, bindGroupLayoutsSceneBlend, 3);
// layout compose
layout_scene_compose = createPipelineLayout(context.device, bindGroupLayoutsSceneCompose, 2);
layout_merge_masks = createPipelineLayout(context.device, bindGroupLayoutsMergeMasks, 3);
// layout blit
layout_blit = createPipelineLayout(context.device, bindGroupLayoutsBlit, 1);
@ -224,7 +224,7 @@ void WgPipelines::initialize(WgContext& context)
WGPUColorWriteMask_None, offscreenTargetFormat,
WGPUCompareFunction_Always, WGPUStencilOperation_IncrementWrap,
WGPUCompareFunction_Always, WGPUStencilOperation_DecrementWrap,
primitiveState, multisampleState, blendStateSrc);
WGPUCompareFunction_Always, false, multisampleState, blendStateSrc);
// render pipeline even-odd
evenodd = createRenderPipeline(
context.device, "The render pipeline even-odd",
@ -233,7 +233,7 @@ void WgPipelines::initialize(WgContext& context)
WGPUColorWriteMask_None, offscreenTargetFormat,
WGPUCompareFunction_Always, WGPUStencilOperation_Invert,
WGPUCompareFunction_Always, WGPUStencilOperation_Invert,
primitiveState, multisampleState, blendStateSrc);
WGPUCompareFunction_Always, false, multisampleState, blendStateSrc);
// render pipeline direct
direct = createRenderPipeline(
context.device, "The render pipeline direct",
@ -242,16 +242,53 @@ void WgPipelines::initialize(WgContext& context)
WGPUColorWriteMask_None, offscreenTargetFormat,
WGPUCompareFunction_Always, WGPUStencilOperation_Replace,
WGPUCompareFunction_Always, WGPUStencilOperation_Replace,
primitiveState, multisampleState, blendStateSrc);
// render pipeline clip path
clip_path = createRenderPipeline(
context.device, "The render pipeline clip path",
shader_stencil, "vs_main", "fs_main", layout_stencil,
WGPUCompareFunction_Always, false, multisampleState, blendStateSrc);
// render pipeline copy stencil to depth (front)
copy_stencil_to_depth = createRenderPipeline(
context.device, "The render pipeline copy stencil to depth front",
shader_depth, "vs_main", "fs_main", layout_depth,
vertexBufferLayoutsShape, 1,
WGPUColorWriteMask_All, offscreenTargetFormat,
WGPUColorWriteMask_None, offscreenTargetFormat,
WGPUCompareFunction_NotEqual, WGPUStencilOperation_Zero,
WGPUCompareFunction_NotEqual, WGPUStencilOperation_Zero,
primitiveState, multisampleState, blendStateSrc);
WGPUCompareFunction_Always, true, multisampleState, blendStateSrc);
// render pipeline copy stencil to depth (intermidiate)
copy_stencil_to_depth_interm = createRenderPipeline(
context.device, "The render pipeline copy stencil to depth intermidiate",
shader_depth, "vs_main", "fs_main", layout_depth,
vertexBufferLayoutsShape, 1,
WGPUColorWriteMask_None, offscreenTargetFormat,
WGPUCompareFunction_NotEqual, WGPUStencilOperation_Zero,
WGPUCompareFunction_NotEqual, WGPUStencilOperation_Zero,
WGPUCompareFunction_Greater, true, multisampleState, blendStateSrc);
// render pipeline depth to stencil
copy_depth_to_stencil = createRenderPipeline(
context.device, "The render pipeline depth to stencil",
shader_depth, "vs_main", "fs_main", layout_depth,
vertexBufferLayoutsShape, 1,
WGPUColorWriteMask_None, offscreenTargetFormat,
WGPUCompareFunction_Always, WGPUStencilOperation_Replace,
WGPUCompareFunction_Always, WGPUStencilOperation_Replace,
WGPUCompareFunction_Equal, false, multisampleState, blendStateSrc);
// render pipeline merge depth with stencil
merge_depth_stencil = createRenderPipeline(
context.device, "The render pipeline merge depth with stencil",
shader_depth, "vs_main", "fs_main", layout_depth,
vertexBufferLayoutsShape, 1,
WGPUColorWriteMask_None, offscreenTargetFormat,
WGPUCompareFunction_Always, WGPUStencilOperation_Keep,
WGPUCompareFunction_Always, WGPUStencilOperation_Keep,
WGPUCompareFunction_Equal, true, multisampleState, blendStateSrc);
// render pipeline clear depth
clear_depth = createRenderPipeline(
context.device, "The render pipeline clear depth",
shader_depth, "vs_main", "fs_main", layout_depth,
vertexBufferLayoutsShape, 1,
WGPUColorWriteMask_None, offscreenTargetFormat,
WGPUCompareFunction_Always, WGPUStencilOperation_Keep,
WGPUCompareFunction_Always, WGPUStencilOperation_Keep,
WGPUCompareFunction_Always, true, multisampleState, blendStateSrc);
// render pipeline solid
solid = createRenderPipeline(
@ -261,7 +298,7 @@ void WgPipelines::initialize(WgContext& context)
WGPUColorWriteMask_All, offscreenTargetFormat,
WGPUCompareFunction_NotEqual, WGPUStencilOperation_Zero,
WGPUCompareFunction_NotEqual, WGPUStencilOperation_Zero,
primitiveState, multisampleState, blendStateNrm);
WGPUCompareFunction_Always, false, multisampleState, blendStateNrm);
// render pipeline radial
radial = createRenderPipeline(
context.device, "The render pipeline radial",
@ -270,7 +307,7 @@ void WgPipelines::initialize(WgContext& context)
WGPUColorWriteMask_All, offscreenTargetFormat,
WGPUCompareFunction_NotEqual, WGPUStencilOperation_Zero,
WGPUCompareFunction_NotEqual, WGPUStencilOperation_Zero,
primitiveState, multisampleState, blendStateNrm);
WGPUCompareFunction_Always, false, multisampleState, blendStateNrm);
// render pipeline linear
linear = createRenderPipeline(
context.device, "The render pipeline linear",
@ -279,16 +316,16 @@ void WgPipelines::initialize(WgContext& context)
WGPUColorWriteMask_All, offscreenTargetFormat,
WGPUCompareFunction_NotEqual, WGPUStencilOperation_Zero,
WGPUCompareFunction_NotEqual, WGPUStencilOperation_Zero,
primitiveState, multisampleState, blendStateNrm);
WGPUCompareFunction_Always, false, multisampleState, blendStateNrm);
// render pipeline image
image = createRenderPipeline(
context.device, "The render pipeline image",
shader_image, "vs_main", "fs_main", layout_image,
vertexBufferLayoutsImage, 2,
WGPUColorWriteMask_All, offscreenTargetFormat,
WGPUCompareFunction_Always, WGPUStencilOperation_Zero,
WGPUCompareFunction_Always, WGPUStencilOperation_Zero,
primitiveState, multisampleState, blendStateNrm);
WGPUCompareFunction_NotEqual, WGPUStencilOperation_Zero,
WGPUCompareFunction_NotEqual, WGPUStencilOperation_Zero,
WGPUCompareFunction_Always, false, multisampleState, blendStateNrm);
// render pipeline scene
scene = createRenderPipeline(
context.device, "The render pipeline scene",
@ -297,7 +334,7 @@ void WgPipelines::initialize(WgContext& context)
WGPUColorWriteMask_All, offscreenTargetFormat,
WGPUCompareFunction_Always, WGPUStencilOperation_Zero,
WGPUCompareFunction_Always, WGPUStencilOperation_Zero,
primitiveState, multisampleState, blendStateNrm);
WGPUCompareFunction_Always, false, multisampleState, blendStateNrm);
// blend shader names
const char* shaderBlendNames[] {
@ -330,7 +367,7 @@ void WgPipelines::initialize(WgContext& context)
WGPUColorWriteMask_All, offscreenTargetFormat,
WGPUCompareFunction_NotEqual, WGPUStencilOperation_Zero,
WGPUCompareFunction_NotEqual, WGPUStencilOperation_Zero,
primitiveState, multisampleState, blendStateSrc);
WGPUCompareFunction_Always, false, multisampleState, blendStateSrc);
// blend radial
radial_blend[i] = createRenderPipeline(context.device, "The render pipeline radial blend",
shader_radial_blend, "vs_main", shaderBlendNames[i], layout_gradient_blend,
@ -338,7 +375,7 @@ void WgPipelines::initialize(WgContext& context)
WGPUColorWriteMask_All, offscreenTargetFormat,
WGPUCompareFunction_NotEqual, WGPUStencilOperation_Zero,
WGPUCompareFunction_NotEqual, WGPUStencilOperation_Zero,
primitiveState, multisampleState, blendStateSrc);
WGPUCompareFunction_Always, false, multisampleState, blendStateSrc);
// blend linear
linear_blend[i] = createRenderPipeline(context.device, "The render pipeline linear blend",
shader_linear_blend, "vs_main", shaderBlendNames[i], layout_gradient_blend,
@ -346,15 +383,15 @@ void WgPipelines::initialize(WgContext& context)
WGPUColorWriteMask_All, offscreenTargetFormat,
WGPUCompareFunction_NotEqual, WGPUStencilOperation_Zero,
WGPUCompareFunction_NotEqual, WGPUStencilOperation_Zero,
primitiveState, multisampleState, blendStateSrc);
WGPUCompareFunction_Always, false, multisampleState, blendStateSrc);
// blend image
image_blend[i] = createRenderPipeline(context.device, "The render pipeline image blend",
shader_image_blend, "vs_main", shaderBlendNames[i], layout_image_blend,
vertexBufferLayoutsImage, 2,
WGPUColorWriteMask_All, offscreenTargetFormat,
WGPUCompareFunction_Always, WGPUStencilOperation_Zero,
WGPUCompareFunction_Always, WGPUStencilOperation_Zero,
primitiveState, multisampleState, blendStateSrc);
WGPUCompareFunction_NotEqual, WGPUStencilOperation_Zero,
WGPUCompareFunction_NotEqual, WGPUStencilOperation_Zero,
WGPUCompareFunction_Always, false, multisampleState, blendStateSrc);
// blend scene
scene_blend[i] = createRenderPipeline(context.device, "The render pipeline scene blend",
shader_scene_blend, "vs_main", shaderBlendNames[i], layout_scene_blend,
@ -362,7 +399,7 @@ void WgPipelines::initialize(WgContext& context)
WGPUColorWriteMask_All, offscreenTargetFormat,
WGPUCompareFunction_Always, WGPUStencilOperation_Zero,
WGPUCompareFunction_Always, WGPUStencilOperation_Zero,
primitiveState, multisampleState, blendStateSrc);
WGPUCompareFunction_Always, false, multisampleState, blendStateSrc);
}
// compose shader names
@ -404,24 +441,9 @@ void WgPipelines::initialize(WgContext& context)
WGPUColorWriteMask_All, offscreenTargetFormat,
WGPUCompareFunction_Always, WGPUStencilOperation_Zero,
WGPUCompareFunction_Always, WGPUStencilOperation_Zero,
primitiveState, multisampleState, composeBlends[i]);
WGPUCompareFunction_Always, false, multisampleState, composeBlends[i]);
}
// render pipeline scene clip path
scene_clip = createRenderPipeline(
context.device, "The render pipeline scene clip path",
shader_scene_compose, "vs_main", "fs_main_ClipPath", layout_scene_compose,
vertexBufferLayoutsImage, 2,
WGPUColorWriteMask_All, offscreenTargetFormat,
WGPUCompareFunction_Always, WGPUStencilOperation_Zero,
WGPUCompareFunction_Always, WGPUStencilOperation_Zero,
primitiveState, multisampleState, blendStateNrm);
// compute pipelines
merge_masks = createComputePipeline(
context.device, "The compute pipeline merge masks",
shader_merge_masks, "cs_main", layout_merge_masks);
// render pipeline blit
blit = createRenderPipeline(context.device, "The render pipeline blit",
shader_blit, "vs_main", "fs_main", layout_blit,
@ -430,7 +452,7 @@ void WgPipelines::initialize(WgContext& context)
WGPUColorWriteMask_All, context.preferredFormat,
WGPUCompareFunction_Always, WGPUStencilOperation_Zero,
WGPUCompareFunction_Always, WGPUStencilOperation_Zero,
primitiveState, multisampleState, blendStateSrc);
WGPUCompareFunction_Always, false, multisampleState, blendStateSrc);
}
void WgPipelines::releaseGraphicHandles(WgContext& context)
@ -438,7 +460,6 @@ void WgPipelines::releaseGraphicHandles(WgContext& context)
// pipeline blit
releaseRenderPipeline(blit);
// pipelines compose
releaseRenderPipeline(scene_clip);
for (uint32_t i = 0; i < 11; i++)
releaseRenderPipeline(scene_compose[i]);
// pipelines custom blend
@ -455,14 +476,18 @@ void WgPipelines::releaseGraphicHandles(WgContext& context)
releaseRenderPipeline(linear);
releaseRenderPipeline(radial);
releaseRenderPipeline(solid);
// pipelines helpers
releaseRenderPipeline(clip_path);
// pipelines clip path markup
releaseRenderPipeline(clear_depth);
releaseRenderPipeline(merge_depth_stencil);
releaseRenderPipeline(copy_depth_to_stencil);
releaseRenderPipeline(copy_stencil_to_depth_interm);
releaseRenderPipeline(copy_stencil_to_depth);
// pipelines stencil markup
releaseRenderPipeline(direct);
releaseRenderPipeline(evenodd);
releaseRenderPipeline(winding);
// layouts
releasePipelineLayout(layout_blit);
releasePipelineLayout(layout_merge_masks);
releasePipelineLayout(layout_scene_compose);
releasePipelineLayout(layout_scene_blend);
releasePipelineLayout(layout_image_blend);
@ -472,10 +497,10 @@ void WgPipelines::releaseGraphicHandles(WgContext& context)
releasePipelineLayout(layout_image);
releasePipelineLayout(layout_gradient);
releasePipelineLayout(layout_solid);
releasePipelineLayout(layout_depth);
releasePipelineLayout(layout_stencil);
// shaders
releaseShaderModule(shader_blit);
releaseShaderModule(shader_merge_masks);
releaseShaderModule(shader_scene_compose);
releaseShaderModule(shader_scene_blend);
releaseShaderModule(shader_image_blend);
@ -487,20 +512,13 @@ void WgPipelines::releaseGraphicHandles(WgContext& context)
releaseShaderModule(shader_linear);
releaseShaderModule(shader_radial);
releaseShaderModule(shader_solid);
releaseShaderModule(shader_depth);
releaseShaderModule(shader_stencil);
}
void WgPipelines::releaseComputeHandles(WgContext& context)
{
releaseComputePipeline(merge_masks);
releasePipelineLayout(layout_merge_masks);
releaseShaderModule(shader_merge_masks);
}
void WgPipelines::release(WgContext& context)
{
releaseComputeHandles(context);
releaseGraphicHandles(context);
layouts.release(context);
}

View file

@ -29,6 +29,7 @@ class WgPipelines {
private:
// shaders helpers
WGPUShaderModule shader_stencil{};
WGPUShaderModule shader_depth{};
// shaders normal blend
WGPUShaderModule shader_solid{};
WGPUShaderModule shader_radial{};
@ -43,12 +44,12 @@ private:
WGPUShaderModule shader_scene_blend{};
// shader scene compose
WGPUShaderModule shader_scene_compose{};
WGPUShaderModule shader_merge_masks;
// shader blit
WGPUShaderModule shader_blit{};
private:
// layouts helpers
WGPUPipelineLayout layout_stencil{};
WGPUPipelineLayout layout_depth{};
// layouts normal blend
WGPUPipelineLayout layout_solid{};
WGPUPipelineLayout layout_gradient{};
@ -61,15 +62,19 @@ private:
WGPUPipelineLayout layout_scene_blend{};
// layouts scene compose
WGPUPipelineLayout layout_scene_compose{};
WGPUPipelineLayout layout_merge_masks{};
// layouts blit
WGPUPipelineLayout layout_blit{};
public:
// pipelines helpers
// pipelines stencil markup
WGPURenderPipeline winding{};
WGPURenderPipeline evenodd{};
WGPURenderPipeline direct{};
WGPURenderPipeline clip_path{};
// pipelines clip path markup
WGPURenderPipeline copy_stencil_to_depth{}; // depth 0.50, clear stencil
WGPURenderPipeline copy_stencil_to_depth_interm{}; // depth 0.75, clear stencil
WGPURenderPipeline copy_depth_to_stencil{}; // depth 0.50 and 0.75, update stencil
WGPURenderPipeline merge_depth_stencil{}; // depth 0.75, update stencil
WGPURenderPipeline clear_depth{}; // depth 1.00, clear ctencil
// pipelines normal blend
WGPURenderPipeline solid{};
WGPURenderPipeline radial{};
@ -84,8 +89,6 @@ public:
WGPURenderPipeline scene_blend[18]{};
// pipelines compose
WGPURenderPipeline scene_compose[11]{};
WGPURenderPipeline scene_clip{};
WGPUComputePipeline merge_masks{};
// pipeline blit
WGPURenderPipeline blit{};
public:
@ -93,7 +96,6 @@ public:
WgBindGroupLayouts layouts;
private:
void releaseGraphicHandles(WgContext& context);
void releaseComputeHandles(WgContext& context);
private:
WGPUShaderModule createShaderModule(WGPUDevice device, const char* label, const char* code);
WGPUPipelineLayout createPipelineLayout(WGPUDevice device, const WGPUBindGroupLayout* bindGroupLayouts, const uint32_t bindGroupLayoutsCount);
@ -105,7 +107,7 @@ private:
const WGPUColorWriteMaskFlags writeMask, const WGPUTextureFormat colorTargetFormat,
const WGPUCompareFunction stencilFunctionFrnt, const WGPUStencilOperation stencilOperationFrnt,
const WGPUCompareFunction stencilFunctionBack, const WGPUStencilOperation stencilOperationBack,
const WGPUPrimitiveState primitiveState, const WGPUMultisampleState multisampleState, const WGPUBlendState blendState);
const WGPUCompareFunction depthCompare, WGPUBool depthWriteEnabled, const WGPUMultisampleState multisampleState, const WGPUBlendState blendState);
WGPUComputePipeline createComputePipeline(
WGPUDevice device, const char* pipelineLabel,
const WGPUShaderModule shaderModule, const char* entryPoint,

View file

@ -49,6 +49,32 @@ fn fs_main(in: VertexOutput) -> @location(0) vec4f {
}
)";
//************************************************************************
// graphics shader source: depth
//************************************************************************
const char* cShaderSrc_Depth = R"(
struct VertexInput { @location(0) position: vec2f };
struct VertexOutput { @builtin(position) position: vec4f };
@group(0) @binding(0) var<uniform> uViewMat : mat4x4f;
@group(1) @binding(0) var<uniform> uModelMat : mat4x4f;
@group(2) @binding(0) var<uniform> 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.z = uDepth;
return out;
}
@fragment
fn fs_main(in: VertexOutput) -> @location(0) vec4f {
return vec4f(1.0, 0.5, 0.0, 1.0);
}
)";
//************************************************************************
// graphics shader source: solid normal blend
//************************************************************************

View file

@ -25,6 +25,7 @@
// helper shaders
extern const char* cShaderSrc_Stencil;
extern const char* cShaderSrc_Depth;
// shaders normal blend
extern const char* cShaderSrc_Solid;
extern const char* cShaderSrc_Linear;