mirror of
https://github.com/thorvg/thorvg.git
synced 2025-06-21 15:32:49 +00:00
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:
parent
a1296960eb
commit
0815366763
6 changed files with 330 additions and 214 deletions
|
@ -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, ©Size);
|
||||
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, ©Size);
|
||||
// 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);
|
||||
}
|
||||
}
|
|
@ -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_
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
//************************************************************************
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Add table
Reference in a new issue