mirror of
https://github.com/thorvg/thorvg.git
synced 2025-06-08 05:33:36 +00:00
wg_engine: MSAA support, part 1 - move blending to fragment shaders
Apply custom blending using fragment shaders instead of compute shaders.
This commit is contained in:
parent
bb253dd3fb
commit
81cb7da9f3
7 changed files with 1174 additions and 949 deletions
|
@ -77,13 +77,6 @@ void WgCompositor::release(WgContext& context)
|
|||
}
|
||||
|
||||
|
||||
WgPipelineBlendType WgCompositor::blendMethodToBlendType(BlendMethod blendMethod)
|
||||
{
|
||||
if (blendMethod == BlendMethod::Normal) return WgPipelineBlendType::Normal;
|
||||
return WgPipelineBlendType::Custom;
|
||||
}
|
||||
|
||||
|
||||
RenderRegion WgCompositor::shrinkRenderRegion(RenderRegion& rect)
|
||||
{
|
||||
// cut viewport to screen dimensions
|
||||
|
@ -125,6 +118,464 @@ void WgCompositor::endRenderPass()
|
|||
}
|
||||
|
||||
|
||||
void WgCompositor::renderShape(WgContext& context, WgRenderDataShape* renderData, BlendMethod blendMethod)
|
||||
{
|
||||
assert(renderData);
|
||||
assert(renderPassEncoder);
|
||||
// apply clip path if neccessary
|
||||
if (renderData->clips.count != 0) {
|
||||
renderClipPath(context, renderData, &storageClipPath);
|
||||
if (renderData->strokeFirst) {
|
||||
clipStrokes(context, renderData, &storageClipPath);
|
||||
clipShape(context, renderData, &storageClipPath);
|
||||
} else {
|
||||
clipShape(context, renderData, &storageClipPath);
|
||||
clipStrokes(context, renderData, &storageClipPath);
|
||||
}
|
||||
// use custom blending
|
||||
} else if (blendMethod != BlendMethod::Normal) {
|
||||
if (renderData->strokeFirst) {
|
||||
blendStrokes(context, renderData, blendMethod);
|
||||
blendShape(context, renderData, blendMethod);
|
||||
} else {
|
||||
blendShape(context, renderData, blendMethod);
|
||||
blendStrokes(context, renderData, blendMethod);
|
||||
}
|
||||
// use direct hardware blending
|
||||
} else {
|
||||
if (renderData->strokeFirst) {
|
||||
drawStrokes(context, renderData);
|
||||
drawShape(context, renderData);
|
||||
} else {
|
||||
drawShape(context, renderData);
|
||||
drawStrokes(context, renderData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void WgCompositor::renderImage(WgContext& context, WgRenderDataPicture* renderData, BlendMethod blendMethod)
|
||||
{
|
||||
assert(renderData);
|
||||
assert(renderPassEncoder);
|
||||
// apply clip path if neccessary
|
||||
if (renderData->clips.count != 0) {
|
||||
renderClipPath(context, renderData, &storageClipPath);
|
||||
clipImage(context, renderData, &storageClipPath);
|
||||
// use custom blending
|
||||
} else if (blendMethod != BlendMethod::Normal)
|
||||
blendImage(context, renderData, blendMethod);
|
||||
// use direct hardware blending
|
||||
else drawImage(context, renderData);
|
||||
}
|
||||
|
||||
|
||||
void WgCompositor::renderScene(WgContext& context, WgRenderStorage* scene, WgCompose* compose)
|
||||
{
|
||||
assert(scene);
|
||||
assert(compose);
|
||||
assert(renderPassEncoder);
|
||||
// use custom blending
|
||||
if (compose->blend != BlendMethod::Normal)
|
||||
blendScene(context, scene, compose);
|
||||
// use direct hardware blending
|
||||
else drawScene(context, scene, compose);
|
||||
}
|
||||
|
||||
|
||||
void WgCompositor::composeScene(WgContext& context, WgRenderStorage* src, WgRenderStorage* mask, WgCompose* cmp)
|
||||
{
|
||||
assert(cmp);
|
||||
assert(src);
|
||||
assert(mask);
|
||||
assert(renderPassEncoder);
|
||||
RenderRegion rect = shrinkRenderRegion(cmp->aabb);
|
||||
wgpuRenderPassEncoderSetScissorRect(renderPassEncoder, rect.x, rect.y, rect.w, rect.h);
|
||||
wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0);
|
||||
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 0, src->bindGroupTexure, 0, nullptr);
|
||||
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, mask->bindGroupTexure, 0, nullptr);
|
||||
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines->scene_compose[(uint32_t)cmp->method]);
|
||||
meshData.drawImage(context, renderPassEncoder);
|
||||
}
|
||||
|
||||
|
||||
void WgCompositor::blit(WgContext& context, WGPUCommandEncoder encoder, WgRenderStorage* src, WGPUTextureView dstView) {
|
||||
WGPURenderPassDepthStencilAttachment depthStencilAttachment{ .view = texViewStencil, .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 };
|
||||
WGPURenderPassEncoder renderPass = wgpuCommandEncoderBeginRenderPass(encoder, &renderPassDesc);
|
||||
wgpuRenderPassEncoderSetBindGroup(renderPass, 0, src->bindGroupTexure, 0, nullptr);
|
||||
wgpuRenderPassEncoderSetPipeline(renderPass, pipelines->blit);
|
||||
meshData.drawImage(context, renderPass);
|
||||
wgpuRenderPassEncoderEnd(renderPass);
|
||||
wgpuRenderPassEncoderRelease(renderPass);
|
||||
}
|
||||
|
||||
|
||||
void WgCompositor::drawShape(WgContext& context, WgRenderDataShape* renderData)
|
||||
{
|
||||
assert(renderData);
|
||||
assert(renderPassEncoder);
|
||||
assert(renderData->meshGroupShapes.meshes.count == renderData->meshGroupShapesBBox.meshes.count);
|
||||
if (renderData->renderSettingsShape.skip) return;
|
||||
if (renderData->meshGroupShapes.meshes.count == 0) return;
|
||||
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);
|
||||
// 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);
|
||||
}
|
||||
|
||||
|
||||
void WgCompositor::blendShape(WgContext& context, WgRenderDataShape* renderData, BlendMethod blendMethod)
|
||||
{
|
||||
assert(renderData);
|
||||
assert(renderPassEncoder);
|
||||
assert(renderData->meshGroupShapes.meshes.count == renderData->meshGroupShapesBBox.meshes.count);
|
||||
if (renderData->renderSettingsShape.skip) return;
|
||||
if (renderData->meshGroupShapes.meshes.count == 0) return;
|
||||
if ((renderData->viewport.w <= 0) || (renderData->viewport.h <= 0)) return;
|
||||
// copy current render target data to dst storage
|
||||
WgRenderStorage *target = currentTarget;
|
||||
endRenderPass();
|
||||
const WGPUImageCopyTexture texSrc { .texture = target->texture };
|
||||
const WGPUImageCopyTexture texDst { .texture = storageDstCopy.texture };
|
||||
const WGPUExtent3D copySize { .width = width, .height = height, .depthOrArrayLayers = 1 };
|
||||
wgpuCommandEncoderCopyTextureToTexture(commandEncoder, &texSrc, &texDst, ©Size);
|
||||
beginRenderPass(commandEncoder, target, false);
|
||||
// render shape with blend settings
|
||||
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);
|
||||
// setup fill rules
|
||||
wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0);
|
||||
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 0, bindGroupViewMat, 0, nullptr);
|
||||
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, renderData->bindGroupPaint, 0, nullptr);
|
||||
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 3, storageDstCopy.bindGroupTexure, 0, nullptr);
|
||||
uint32_t blendMethodInd = (uint32_t)blendMethod;
|
||||
WgRenderSettings& settings = renderData->renderSettingsShape;
|
||||
if (settings.fillType == WgRenderSettingsType::Solid) {
|
||||
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, settings.bindGroupSolid, 0, nullptr);
|
||||
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines->solid_blend[blendMethodInd]);
|
||||
} else if (settings.fillType == WgRenderSettingsType::Linear) {
|
||||
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, settings.bindGroupGradient, 0, nullptr);
|
||||
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines->linear_blend[blendMethodInd]);
|
||||
} else if (settings.fillType == WgRenderSettingsType::Radial) {
|
||||
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, settings.bindGroupGradient, 0, nullptr);
|
||||
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines->radial_blend[blendMethodInd]);
|
||||
}
|
||||
// draw to color (second pass)
|
||||
renderData->meshDataBBox.drawFan(context, renderPassEncoder);
|
||||
}
|
||||
|
||||
|
||||
void WgCompositor::clipShape(WgContext& context, WgRenderDataShape* renderData, WgRenderStorage* mask)
|
||||
{
|
||||
assert(mask);
|
||||
assert(renderData);
|
||||
assert(commandEncoder);
|
||||
assert(currentTarget);
|
||||
// skip shape composing if shape do not exist
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
void WgCompositor::drawStrokes(WgContext& context, WgRenderDataShape* renderData)
|
||||
{
|
||||
assert(renderData);
|
||||
assert(renderPassEncoder);
|
||||
assert(renderData->meshGroupStrokes.meshes.count == renderData->meshGroupStrokesBBox.meshes.count);
|
||||
if (renderData->renderSettingsStroke.skip) return;
|
||||
if (renderData->meshGroupStrokes.meshes.count == 0) return;
|
||||
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);
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void WgCompositor::blendStrokes(WgContext& context, WgRenderDataShape* renderData, BlendMethod blendMethod)
|
||||
{
|
||||
assert(renderData);
|
||||
assert(renderPassEncoder);
|
||||
assert(renderData->meshGroupStrokes.meshes.count == renderData->meshGroupStrokesBBox.meshes.count);
|
||||
if (renderData->renderSettingsStroke.skip) return;
|
||||
if (renderData->meshGroupStrokes.meshes.count == 0) return;
|
||||
if ((renderData->viewport.w <= 0) || (renderData->viewport.h <= 0)) return;
|
||||
// copy current render target data to dst storage
|
||||
WgRenderStorage *target = currentTarget;
|
||||
endRenderPass();
|
||||
const WGPUImageCopyTexture texSrc { .texture = target->texture };
|
||||
const WGPUImageCopyTexture texDst { .texture = storageDstCopy.texture };
|
||||
const WGPUExtent3D copySize { .width = width, .height = height, .depthOrArrayLayers = 1 };
|
||||
wgpuCommandEncoderCopyTextureToTexture(commandEncoder, &texSrc, &texDst, ©Size);
|
||||
beginRenderPass(commandEncoder, target, false);
|
||||
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);
|
||||
// setup fill rules
|
||||
wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0);
|
||||
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 0, bindGroupViewMat, 0, nullptr);
|
||||
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, renderData->bindGroupPaint, 0, nullptr);
|
||||
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 3, storageDstCopy.bindGroupTexure, 0, nullptr);
|
||||
uint32_t blendMethodInd = (uint32_t)blendMethod;
|
||||
WgRenderSettings& settings = renderData->renderSettingsStroke;
|
||||
if (settings.fillType == WgRenderSettingsType::Solid) {
|
||||
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, settings.bindGroupSolid, 0, nullptr);
|
||||
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines->solid_blend[blendMethodInd]);
|
||||
} else if (settings.fillType == WgRenderSettingsType::Linear) {
|
||||
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, settings.bindGroupGradient, 0, nullptr);
|
||||
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines->linear_blend[blendMethodInd]);
|
||||
} else if (settings.fillType == WgRenderSettingsType::Radial) {
|
||||
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, settings.bindGroupGradient, 0, nullptr);
|
||||
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines->radial_blend[blendMethodInd]);
|
||||
}
|
||||
// draw to color (second pass)
|
||||
renderData->meshGroupStrokesBBox.meshes[i]->drawFan(context, renderPassEncoder);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
void WgCompositor::clipStrokes(WgContext& context, WgRenderDataShape* renderData, WgRenderStorage* mask)
|
||||
{
|
||||
assert(mask);
|
||||
assert(renderData);
|
||||
assert(commandEncoder);
|
||||
assert(currentTarget);
|
||||
// skip shape composing if strokes do not exist
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
void WgCompositor::drawImage(WgContext& context, WgRenderDataPicture* renderData)
|
||||
{
|
||||
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);
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
void WgCompositor::blendImage(WgContext& context, WgRenderDataPicture* renderData, BlendMethod blendMethod)
|
||||
{
|
||||
assert(renderData);
|
||||
assert(renderPassEncoder);
|
||||
if ((renderData->viewport.w <= 0) || (renderData->viewport.h <= 0)) return;
|
||||
// copy current render target data to dst storage
|
||||
WgRenderStorage *target = currentTarget;
|
||||
endRenderPass();
|
||||
const WGPUImageCopyTexture texSrc { .texture = target->texture };
|
||||
const WGPUImageCopyTexture texDst { .texture = storageDstCopy.texture };
|
||||
const WGPUExtent3D copySize { .width = width, .height = height, .depthOrArrayLayers = 1 };
|
||||
wgpuCommandEncoderCopyTextureToTexture(commandEncoder, &texSrc, &texDst, ©Size);
|
||||
beginRenderPass(commandEncoder, target, false);
|
||||
// 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);
|
||||
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, renderData->bindGroupPicture, 0, nullptr);
|
||||
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 3, storageDstCopy.bindGroupTexure, 0, nullptr);
|
||||
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines->image_blend[blendMethodInd]);
|
||||
renderData->meshData.drawImage(context, renderPassEncoder);
|
||||
};
|
||||
|
||||
|
||||
void WgCompositor::clipImage(WgContext& context, WgRenderDataPicture* renderData, WgRenderStorage* mask)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
void WgCompositor::drawScene(WgContext& context, WgRenderStorage* scene, WgCompose* compose)
|
||||
{
|
||||
assert(scene);
|
||||
assert(compose);
|
||||
assert(currentTarget);
|
||||
// draw scene
|
||||
RenderRegion rect = shrinkRenderRegion(compose->aabb);
|
||||
wgpuRenderPassEncoderSetScissorRect(renderPassEncoder, rect.x, rect.y, rect.w, rect.h);
|
||||
wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0);
|
||||
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 0, scene->bindGroupTexure, 0, nullptr);
|
||||
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, bindGroupOpacities[compose->opacity], 0, nullptr);
|
||||
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines->scene);
|
||||
meshData.drawImage(context, renderPassEncoder);
|
||||
}
|
||||
|
||||
|
||||
void WgCompositor::blendScene(WgContext& context, WgRenderStorage* scene, WgCompose* compose)
|
||||
{
|
||||
assert(scene);
|
||||
assert(compose);
|
||||
assert(currentTarget);
|
||||
// copy current render target data to dst storage
|
||||
WgRenderStorage *target = currentTarget;
|
||||
endRenderPass();
|
||||
const WGPUImageCopyTexture texSrc { .texture = target->texture };
|
||||
const WGPUImageCopyTexture texDst { .texture = storageDstCopy.texture };
|
||||
const WGPUExtent3D copySize { .width = width, .height = height, .depthOrArrayLayers = 1 };
|
||||
wgpuCommandEncoderCopyTextureToTexture(commandEncoder, &texSrc, &texDst, ©Size);
|
||||
beginRenderPass(commandEncoder, target, false);
|
||||
// blend scene
|
||||
uint32_t blendMethodInd = (uint32_t)compose->blend;
|
||||
RenderRegion rect = shrinkRenderRegion(compose->aabb);
|
||||
wgpuRenderPassEncoderSetScissorRect(renderPassEncoder, rect.x, rect.y, rect.w, rect.h);
|
||||
wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0);
|
||||
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 0, scene->bindGroupTexure, 0, nullptr);
|
||||
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, storageDstCopy.bindGroupTexure, 0, nullptr);
|
||||
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, bindGroupOpacities[compose->opacity], 0, nullptr);
|
||||
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines->scene_blend[blendMethodInd]);
|
||||
meshData.drawImage(context, renderPassEncoder);
|
||||
}
|
||||
|
||||
|
||||
void WgCompositor::drawClipPath(WgContext& context, WgRenderDataShape* renderData)
|
||||
{
|
||||
assert(renderData);
|
||||
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);
|
||||
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);
|
||||
// setup fill rules
|
||||
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);
|
||||
|
@ -150,350 +601,6 @@ void WgCompositor::renderClipPath(WgContext& context, WgRenderDataPaint* renderD
|
|||
}
|
||||
|
||||
|
||||
void WgCompositor::renderShape(WgContext& context, WgRenderDataShape* renderData, BlendMethod blendMethod)
|
||||
{
|
||||
assert(renderData);
|
||||
assert(renderPassEncoder);
|
||||
WgPipelineBlendType blentType = blendMethodToBlendType(blendMethod);
|
||||
// apply clip path if neccessary
|
||||
if (renderData->clips.count != 0) {
|
||||
renderClipPath(context, renderData, &storageClipPath);
|
||||
if (renderData->strokeFirst) {
|
||||
drawStrokesClipped(context, renderData, &storageClipPath);
|
||||
drawShapeClipped(context, renderData, &storageClipPath);
|
||||
} else {
|
||||
drawShapeClipped(context, renderData, &storageClipPath);
|
||||
drawStrokesClipped(context, renderData, &storageClipPath);
|
||||
}
|
||||
// use custom blending
|
||||
} else if (blentType == WgPipelineBlendType::Custom) {
|
||||
if (renderData->strokeFirst) {
|
||||
blendStrokes(context, renderData, blendMethod);
|
||||
blendShape(context, renderData, blendMethod);
|
||||
} else {
|
||||
blendShape(context, renderData, blendMethod);
|
||||
blendStrokes(context, renderData, blendMethod);
|
||||
}
|
||||
// use direct hardware blending
|
||||
} else {
|
||||
if (renderData->strokeFirst) {
|
||||
drawStrokes(context, renderData, blentType);
|
||||
drawShape(context, renderData, blentType);
|
||||
} else {
|
||||
drawShape(context, renderData, blentType);
|
||||
drawStrokes(context, renderData, blentType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void WgCompositor::renderImage(WgContext& context, WgRenderDataPicture* renderData, BlendMethod blendMethod)
|
||||
{
|
||||
assert(renderData);
|
||||
assert(renderPassEncoder);
|
||||
WgPipelineBlendType blentType = blendMethodToBlendType(blendMethod);
|
||||
// apply clip path if neccessary
|
||||
if (renderData->clips.count != 0) {
|
||||
renderClipPath(context, renderData, &storageClipPath);
|
||||
drawImageClipped(context, renderData, &storageClipPath);
|
||||
// use custom blending
|
||||
} else if (blentType == WgPipelineBlendType::Custom)
|
||||
blendImage(context, renderData, blendMethod);
|
||||
else // use direct hardware blending
|
||||
drawImage(context, renderData, blentType);
|
||||
};
|
||||
|
||||
|
||||
void WgCompositor::blendShape(WgContext& context, WgRenderDataShape* renderData, BlendMethod blendMethod)
|
||||
{
|
||||
assert(renderData);
|
||||
assert(commandEncoder);
|
||||
assert(currentTarget);
|
||||
// skip shape blending if shapes do not exist
|
||||
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, WgPipelineBlendType::Custom);
|
||||
endRenderPass();
|
||||
// run blend
|
||||
blend(commandEncoder, &storageInterm, target, 255, blendMethod, renderData->renderSettingsShape.rasterType);
|
||||
// restore current render pass
|
||||
beginRenderPass(commandEncoder, target, false);
|
||||
}
|
||||
|
||||
void WgCompositor::blendStrokes(WgContext& context, WgRenderDataShape* renderData, BlendMethod blendMethod)
|
||||
{
|
||||
assert(renderData);
|
||||
assert(commandEncoder);
|
||||
assert(currentTarget);
|
||||
// skip strokes blending if strokes do not exist
|
||||
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, WgPipelineBlendType::Custom);
|
||||
endRenderPass();
|
||||
// run blend
|
||||
blend(commandEncoder, &storageInterm, target, 255, blendMethod, renderData->renderSettingsStroke.rasterType);
|
||||
// restore current render pass
|
||||
beginRenderPass(commandEncoder, target, false);
|
||||
};
|
||||
|
||||
|
||||
void WgCompositor::blendImage(WgContext& context, WgRenderDataPicture* renderData, BlendMethod blendMethod)
|
||||
{
|
||||
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, WgPipelineBlendType::Custom);
|
||||
endRenderPass();
|
||||
// run blend
|
||||
blend(commandEncoder, &storageInterm, target, 255, blendMethod, WgRenderRasterType::Image);
|
||||
// restore current render pass
|
||||
beginRenderPass(commandEncoder, target, false);
|
||||
};
|
||||
|
||||
|
||||
void WgCompositor::blendScene(WgContext& context, WgRenderStorage* src, WgCompose* cmp)
|
||||
{
|
||||
assert(currentTarget);
|
||||
RenderRegion rect = shrinkRenderRegion(cmp->aabb);
|
||||
wgpuRenderPassEncoderSetScissorRect(renderPassEncoder, rect.x, rect.y, rect.w, rect.h);
|
||||
wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0);
|
||||
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 0, src->bindGroupTexure, 0, nullptr);
|
||||
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, bindGroupOpacities[cmp->opacity], 0, nullptr);
|
||||
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines->sceneBlend);
|
||||
meshData.drawImage(context, renderPassEncoder);
|
||||
}
|
||||
|
||||
|
||||
void WgCompositor::drawShapeClipped(WgContext& context, WgRenderDataShape* renderData, WgRenderStorage* mask)
|
||||
{
|
||||
assert(mask);
|
||||
assert(renderData);
|
||||
assert(commandEncoder);
|
||||
assert(currentTarget);
|
||||
// skip shape composing if shape do not exist
|
||||
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, WgPipelineBlendType::Custom);
|
||||
endRenderPass();
|
||||
// restore current render pass
|
||||
beginRenderPass(commandEncoder, target, false);
|
||||
RenderRegion rect = shrinkRenderRegion(renderData->aabb);
|
||||
clipRegion(context, &storageInterm, mask, rect);
|
||||
}
|
||||
|
||||
|
||||
void WgCompositor::drawStrokesClipped(WgContext& context, WgRenderDataShape* renderData, WgRenderStorage* mask)
|
||||
{
|
||||
assert(mask);
|
||||
assert(renderData);
|
||||
assert(commandEncoder);
|
||||
assert(currentTarget);
|
||||
// skip shape composing if strokes do not exist
|
||||
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, WgPipelineBlendType::Custom);
|
||||
endRenderPass();
|
||||
// restore current render pass
|
||||
beginRenderPass(commandEncoder, target, false);
|
||||
RenderRegion rect = shrinkRenderRegion(renderData->aabb);
|
||||
clipRegion(context, &storageInterm, mask, rect);
|
||||
}
|
||||
|
||||
|
||||
void WgCompositor::drawImageClipped(WgContext& context, WgRenderDataPicture* renderData, WgRenderStorage* mask)
|
||||
{
|
||||
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, WgPipelineBlendType::Custom);
|
||||
endRenderPass();
|
||||
// restore current render pass
|
||||
beginRenderPass(commandEncoder, target, false);
|
||||
RenderRegion rect { 0, 0, (int32_t)width, (int32_t)height };
|
||||
clipRegion(context, &storageInterm, mask, rect);
|
||||
}
|
||||
|
||||
|
||||
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->sceneClip);
|
||||
meshData.drawImage(context, renderPassEncoder);
|
||||
}
|
||||
|
||||
|
||||
void WgCompositor::composeScene(WgContext& context, WgRenderStorage* src, WgRenderStorage* mask, WgCompose* cmp)
|
||||
{
|
||||
assert(cmp);
|
||||
assert(src);
|
||||
assert(mask);
|
||||
assert(renderPassEncoder);
|
||||
RenderRegion rect = shrinkRenderRegion(cmp->aabb);
|
||||
wgpuRenderPassEncoderSetScissorRect(renderPassEncoder, rect.x, rect.y, rect.w, rect.h);
|
||||
wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0);
|
||||
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 0, src->bindGroupTexure, 0, nullptr);
|
||||
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, mask->bindGroupTexure, 0, nullptr);
|
||||
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines->sceneComp[(uint32_t)cmp->method]);
|
||||
meshData.drawImage(context, renderPassEncoder);
|
||||
}
|
||||
|
||||
void WgCompositor::drawClipPath(WgContext& context, WgRenderDataShape* renderData)
|
||||
{
|
||||
assert(renderData);
|
||||
assert(renderPassEncoder);
|
||||
assert(renderData->meshGroupShapes.meshes.count == renderData->meshGroupShapesBBox.meshes.count);
|
||||
if (renderData->renderSettingsShape.skip) return;
|
||||
if (renderData->meshGroupShapes.meshes.count == 0) return;
|
||||
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);
|
||||
// setup fill rules
|
||||
wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0);
|
||||
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 0, bindGroupViewMat, 0, nullptr);
|
||||
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, renderData->bindGroupPaint, 0, nullptr);
|
||||
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines->clipPath);
|
||||
// draw to color (second pass)
|
||||
renderData->meshDataBBox.drawFan(context, renderPassEncoder);
|
||||
}
|
||||
|
||||
|
||||
void WgCompositor::drawShape(WgContext& context, WgRenderDataShape* renderData, WgPipelineBlendType blendType)
|
||||
{
|
||||
assert(renderData);
|
||||
assert(renderPassEncoder);
|
||||
assert(renderData->meshGroupShapes.meshes.count == renderData->meshGroupShapesBBox.meshes.count);
|
||||
uint32_t blendTypeInd = (uint32_t)blendType;
|
||||
if (renderData->renderSettingsShape.skip) return;
|
||||
if (renderData->meshGroupShapes.meshes.count == 0) return;
|
||||
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);
|
||||
// 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[blendTypeInd]);
|
||||
} else if (settings.fillType == WgRenderSettingsType::Linear) {
|
||||
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, settings.bindGroupGradient, 0, nullptr);
|
||||
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines->linear[blendTypeInd]);
|
||||
} else if (settings.fillType == WgRenderSettingsType::Radial) {
|
||||
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, settings.bindGroupGradient, 0, nullptr);
|
||||
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines->radial[blendTypeInd]);
|
||||
}
|
||||
// draw to color (second pass)
|
||||
renderData->meshDataBBox.drawFan(context, renderPassEncoder);
|
||||
}
|
||||
|
||||
|
||||
void WgCompositor::drawStrokes(WgContext& context, WgRenderDataShape* renderData, WgPipelineBlendType blendType)
|
||||
{
|
||||
assert(renderData);
|
||||
assert(renderPassEncoder);
|
||||
assert(renderData->meshGroupStrokes.meshes.count == renderData->meshGroupStrokesBBox.meshes.count);
|
||||
uint32_t blendTypeInd = (uint32_t)blendType;
|
||||
if (renderData->renderSettingsStroke.skip) return;
|
||||
if (renderData->meshGroupStrokes.meshes.count == 0) return;
|
||||
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);
|
||||
// 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[blendTypeInd]);
|
||||
} else if (settings.fillType == WgRenderSettingsType::Linear) {
|
||||
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, settings.bindGroupGradient, 0, nullptr);
|
||||
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines->linear[blendTypeInd]);
|
||||
} else if (settings.fillType == WgRenderSettingsType::Radial) {
|
||||
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, settings.bindGroupGradient, 0, nullptr);
|
||||
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines->radial[blendTypeInd]);
|
||||
}
|
||||
// draw to color (second pass)
|
||||
renderData->meshGroupStrokesBBox.meshes[i]->drawFan(context, renderPassEncoder);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void WgCompositor::drawImage(WgContext& context, WgRenderDataPicture* renderData, WgPipelineBlendType blendType)
|
||||
{
|
||||
assert(renderData);
|
||||
assert(renderPassEncoder);
|
||||
uint32_t blendTypeInd = (uint32_t)blendType;
|
||||
if ((renderData->viewport.w <= 0) || (renderData->viewport.h <= 0)) return;
|
||||
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);
|
||||
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, renderData->bindGroupPicture, 0, nullptr);
|
||||
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines->image[blendTypeInd]);
|
||||
renderData->meshData.drawImage(context, renderPassEncoder);
|
||||
}
|
||||
|
||||
|
||||
void WgCompositor::mergeMasks(WGPUCommandEncoder encoder, WgRenderStorage* mask0, WgRenderStorage* mask1)
|
||||
{
|
||||
assert(mask0);
|
||||
|
@ -510,49 +617,7 @@ void WgCompositor::mergeMasks(WGPUCommandEncoder encoder, WgRenderStorage* mask0
|
|||
wgpuComputePassEncoderSetBindGroup(computePassEncoder, 0, mask0->bindGroupRead, 0, nullptr);
|
||||
wgpuComputePassEncoderSetBindGroup(computePassEncoder, 1, storageDstCopy.bindGroupRead, 0, nullptr);
|
||||
wgpuComputePassEncoderSetBindGroup(computePassEncoder, 2, mask1->bindGroupWrite, 0, nullptr);
|
||||
wgpuComputePassEncoderSetPipeline(computePassEncoder, pipelines->mergeMasks);
|
||||
wgpuComputePassEncoderSetPipeline(computePassEncoder, pipelines->merge_masks);
|
||||
wgpuComputePassEncoderDispatchWorkgroups(computePassEncoder, (width + 7) / 8, (height + 7) / 8, 1);
|
||||
wgpuComputePassEncoderEnd(computePassEncoder);
|
||||
}
|
||||
|
||||
|
||||
void WgCompositor::blend(WGPUCommandEncoder encoder, WgRenderStorage* src, WgRenderStorage* dst, uint8_t opacity, BlendMethod blendMethod, WgRenderRasterType rasterType)
|
||||
{
|
||||
assert(src);
|
||||
assert(dst);
|
||||
assert(!renderPassEncoder);
|
||||
WGPUComputePipeline pipeline = pipelines->blendImage[(size_t)blendMethod];
|
||||
if (rasterType == WgRenderRasterType::Solid) pipeline = pipelines->blendSolid[(size_t)blendMethod];
|
||||
if (rasterType == WgRenderRasterType::Gradient) pipeline = pipelines->blendGradient[(size_t)blendMethod];
|
||||
// copy texture to texture
|
||||
const WGPUImageCopyTexture texSrc { .texture = dst->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, src->bindGroupRead, 0, nullptr);
|
||||
wgpuComputePassEncoderSetBindGroup(computePassEncoder, 1, storageDstCopy.bindGroupRead, 0, nullptr);
|
||||
wgpuComputePassEncoderSetBindGroup(computePassEncoder, 2, dst->bindGroupWrite, 0, nullptr);
|
||||
wgpuComputePassEncoderSetBindGroup(computePassEncoder, 3, bindGroupOpacities[opacity], 0, nullptr);
|
||||
wgpuComputePassEncoderSetPipeline(computePassEncoder, pipeline);
|
||||
wgpuComputePassEncoderDispatchWorkgroups(computePassEncoder, (width + 7) / 8, (height + 7) / 8, 1);
|
||||
wgpuComputePassEncoderEnd(computePassEncoder);
|
||||
}
|
||||
|
||||
|
||||
void WgCompositor::blit(WgContext& context, WGPUCommandEncoder encoder, WgRenderStorage* src, WGPUTextureView dstView) {
|
||||
WGPURenderPassDepthStencilAttachment depthStencilAttachment{ .view = texViewStencil, .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 };
|
||||
WGPURenderPassEncoder renderPass = wgpuCommandEncoderBeginRenderPass(encoder, &renderPassDesc);
|
||||
wgpuRenderPassEncoderSetBindGroup(renderPass, 0, src->bindGroupTexure, 0, nullptr);
|
||||
wgpuRenderPassEncoderSetPipeline(renderPass, pipelines->blit);
|
||||
meshData.drawImage(context, renderPass);
|
||||
wgpuRenderPassEncoderEnd(renderPass);
|
||||
wgpuRenderPassEncoderRelease(renderPass);
|
||||
}
|
||||
|
|
|
@ -56,46 +56,53 @@ private:
|
|||
WgRenderStorage storageDstCopy;
|
||||
// composition and blend geometries
|
||||
WgMeshData meshData;
|
||||
|
||||
static WgPipelineBlendType blendMethodToBlendType(BlendMethod blendMethod);
|
||||
|
||||
void clipRegion(WgContext& context, WgRenderStorage* src, WgRenderStorage* mask, RenderRegion& rect);
|
||||
RenderRegion shrinkRenderRegion(RenderRegion& rect);
|
||||
public:
|
||||
// render target dimensions
|
||||
uint32_t width{};
|
||||
uint32_t height{};
|
||||
|
||||
// viewport utilities
|
||||
RenderRegion shrinkRenderRegion(RenderRegion& rect);
|
||||
public:
|
||||
void initialize(WgContext& context, uint32_t width, uint32_t height);
|
||||
void release(WgContext& context);
|
||||
|
||||
// render passes workflow
|
||||
void beginRenderPass(WGPUCommandEncoder encoder, WgRenderStorage* target, bool clear);
|
||||
void endRenderPass();
|
||||
|
||||
void renderClipPath(WgContext& context, WgRenderDataPaint* renderData, WgRenderStorage* dst);
|
||||
|
||||
// render shapes, images and scenes
|
||||
void renderShape(WgContext& context, WgRenderDataShape* renderData, BlendMethod blendMethod);
|
||||
void renderImage(WgContext& context, WgRenderDataPicture* renderData, BlendMethod blendMethod);
|
||||
void renderScene(WgContext& context, WgRenderStorage* scene, WgCompose* compose);
|
||||
void composeScene(WgContext& context, WgRenderStorage* src, WgRenderStorage* mask, WgCompose* compose);
|
||||
|
||||
void blendShape(WgContext& context, WgRenderDataShape* renderData, BlendMethod blendMethod);
|
||||
void blendStrokes(WgContext& context, WgRenderDataShape* renderData, BlendMethod blendMethod);
|
||||
void blendImage(WgContext& context, WgRenderDataPicture* renderData, BlendMethod blendMethod);
|
||||
void blendScene(WgContext& context, WgRenderStorage* src, WgCompose* cmp);
|
||||
|
||||
void drawShapeClipped(WgContext& context, WgRenderDataShape* renderData, WgRenderStorage* mask);
|
||||
void drawStrokesClipped(WgContext& context, WgRenderDataShape* renderData, WgRenderStorage* mask);
|
||||
void drawImageClipped(WgContext& context, WgRenderDataPicture* renderData, WgRenderStorage* mask);
|
||||
|
||||
void composeScene(WgContext& context, WgRenderStorage* src, WgRenderStorage* mask, WgCompose* cmp);
|
||||
|
||||
void drawClipPath(WgContext& context, WgRenderDataShape* renderData);
|
||||
void drawShape(WgContext& context, WgRenderDataShape* renderData, WgPipelineBlendType blendType);
|
||||
void drawStrokes(WgContext& context, WgRenderDataShape* renderData, WgPipelineBlendType blendType);
|
||||
void drawImage(WgContext& context, WgRenderDataPicture* renderData, WgPipelineBlendType blendType);
|
||||
|
||||
void mergeMasks(WGPUCommandEncoder encoder, WgRenderStorage* mask0, WgRenderStorage* mask1);
|
||||
void blend(WGPUCommandEncoder encoder, WgRenderStorage* src, WgRenderStorage* dst, uint8_t opacity, BlendMethod blendMethod, WgRenderRasterType rasterType);
|
||||
// blit render storage to texture view (f.e. screen buffer)
|
||||
void blit(WgContext& context, WGPUCommandEncoder encoder, WgRenderStorage* src, WGPUTextureView dstView);
|
||||
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
|
||||
|
||||
// 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
|
||||
|
||||
// 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
|
||||
|
||||
// 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);
|
||||
};
|
||||
|
||||
#endif // _TVG_WG_COMPOSITOR_H_
|
||||
|
|
|
@ -158,81 +158,68 @@ void WgPipelines::initialize(WgContext& context)
|
|||
.color = { .operation = WGPUBlendOperation_Add, .srcFactor = WGPUBlendFactor_One, .dstFactor = WGPUBlendFactor_OneMinusSrcAlpha },
|
||||
.alpha = { .operation = WGPUBlendOperation_Add, .srcFactor = WGPUBlendFactor_One, .dstFactor = WGPUBlendFactor_OneMinusSrcAlpha }
|
||||
};
|
||||
const WGPUBlendState blendStates[] {
|
||||
blendStateNrm, // WgPipelineBlendType::Normal
|
||||
blendStateSrc // WgPipelineBlendType::Custom (same as SrcOver)
|
||||
};
|
||||
|
||||
// bind group layouts
|
||||
const WGPUBindGroupLayout bindGroupLayoutsStencil[] = {
|
||||
layouts.layoutBuffer1Un,
|
||||
layouts.layoutBuffer2Un
|
||||
};
|
||||
const WGPUBindGroupLayout bindGroupLayoutsSolid[] = {
|
||||
layouts.layoutBuffer1Un,
|
||||
layouts.layoutBuffer2Un,
|
||||
layouts.layoutBuffer1Un
|
||||
};
|
||||
const WGPUBindGroupLayout bindGroupLayoutsGradient[] = {
|
||||
layouts.layoutBuffer1Un,
|
||||
layouts.layoutBuffer2Un,
|
||||
layouts.layoutTexSampledBuff2Un
|
||||
};
|
||||
const WGPUBindGroupLayout bindGroupLayoutsImage[] = {
|
||||
layouts.layoutBuffer1Un,
|
||||
layouts.layoutBuffer2Un,
|
||||
layouts.layoutTexSampled
|
||||
};
|
||||
const WGPUBindGroupLayout bindGroupLayoutsSceneComp[] = {
|
||||
layouts.layoutTexSampled,
|
||||
layouts.layoutTexSampled
|
||||
};
|
||||
const WGPUBindGroupLayout bindGroupLayoutsSceneBlend[] = {
|
||||
layouts.layoutTexSampled,
|
||||
layouts.layoutBuffer1Un
|
||||
};
|
||||
const WGPUBindGroupLayout bindGroupLayoutsBlit[] = {
|
||||
layouts.layoutTexSampled
|
||||
};
|
||||
const WGPUBindGroupLayout bindGroupLayoutsMergeMasks[] = {
|
||||
layouts.layoutTexStrorage1RO,
|
||||
layouts.layoutTexStrorage1RO,
|
||||
layouts.layoutTexStrorage1WO
|
||||
};
|
||||
const WGPUBindGroupLayout bindGroupLayoutsBlend[] = {
|
||||
layouts.layoutTexStrorage1RO,
|
||||
layouts.layoutTexStrorage1RO,
|
||||
layouts.layoutTexStrorage1WO,
|
||||
layouts.layoutBuffer1Un
|
||||
};
|
||||
// bind group layouts helpers
|
||||
const WGPUBindGroupLayout bindGroupLayoutsStencil[] = { layouts.layoutBuffer1Un, layouts.layoutBuffer2Un };
|
||||
// bind group layouts normal blend
|
||||
const WGPUBindGroupLayout bindGroupLayoutsSolid[] { layouts.layoutBuffer1Un, layouts.layoutBuffer2Un, layouts.layoutBuffer1Un };
|
||||
const WGPUBindGroupLayout bindGroupLayoutsGradient[] { layouts.layoutBuffer1Un, layouts.layoutBuffer2Un, layouts.layoutTexSampledBuff2Un };
|
||||
const WGPUBindGroupLayout bindGroupLayoutsImage[] { layouts.layoutBuffer1Un, layouts.layoutBuffer2Un, layouts.layoutTexSampled };
|
||||
const WGPUBindGroupLayout bindGroupLayoutsScene[] { layouts.layoutTexSampled, layouts.layoutBuffer1Un };
|
||||
// bind group layouts custom blend
|
||||
const WGPUBindGroupLayout bindGroupLayoutsSolidBlend[] { layouts.layoutBuffer1Un, layouts.layoutBuffer2Un, layouts.layoutBuffer1Un, layouts.layoutTexSampled };
|
||||
const WGPUBindGroupLayout bindGroupLayoutsGradientBlend[] { layouts.layoutBuffer1Un, layouts.layoutBuffer2Un, layouts.layoutTexSampledBuff2Un, layouts.layoutTexSampled };
|
||||
const WGPUBindGroupLayout bindGroupLayoutsImageBlend[] { layouts.layoutBuffer1Un, layouts.layoutBuffer2Un, layouts.layoutTexSampled, layouts.layoutTexSampled };
|
||||
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 };
|
||||
|
||||
// pipeline layouts
|
||||
layoutStencil = createPipelineLayout(context.device, bindGroupLayoutsStencil, 2);
|
||||
layoutSolid = createPipelineLayout(context.device, bindGroupLayoutsSolid, 3);
|
||||
layoutGradient = createPipelineLayout(context.device, bindGroupLayoutsGradient, 3);
|
||||
layoutImage = createPipelineLayout(context.device, bindGroupLayoutsImage, 3);
|
||||
layoutSceneComp = createPipelineLayout(context.device, bindGroupLayoutsSceneComp, 2);
|
||||
layoutSceneBlend = createPipelineLayout(context.device, bindGroupLayoutsSceneBlend, 2);
|
||||
layoutBlit = createPipelineLayout(context.device, bindGroupLayoutsBlit, 1);
|
||||
layoutBlend = createPipelineLayout(context.device, bindGroupLayoutsBlend, 4);
|
||||
layoutMergeMasks = createPipelineLayout(context.device, bindGroupLayoutsMergeMasks, 3);
|
||||
// shaders
|
||||
char shaderSourceBuff[16384]{};
|
||||
shader_stencil = createShaderModule(context.device, "The shader stencil", cShaderSrc_Stencil);
|
||||
// shader normal blend
|
||||
shader_solid = createShaderModule(context.device, "The shader solid", cShaderSrc_Solid);
|
||||
shader_radial = createShaderModule(context.device, "The shader radial", cShaderSrc_Radial);
|
||||
shader_linear = createShaderModule(context.device, "The shader linear", cShaderSrc_Linear);
|
||||
shader_image = createShaderModule(context.device, "The shader image", cShaderSrc_Image);
|
||||
shader_scene = createShaderModule(context.device, "The shader scene", cShaderSrc_Scene);
|
||||
// shader custom blend
|
||||
shader_solid_blend = createShaderModule(context.device, "The shader blend solid", strcat(strcpy(shaderSourceBuff, cShaderSrc_Solid_Blend), cShaderSrc_BlendFuncs));
|
||||
shader_linear_blend = createShaderModule(context.device, "The shader blend linear", strcat(strcpy(shaderSourceBuff, cShaderSrc_Linear_Blend), cShaderSrc_BlendFuncs));
|
||||
shader_radial_blend = createShaderModule(context.device, "The shader blend radial", strcat(strcpy(shaderSourceBuff, cShaderSrc_Radial_Blend), cShaderSrc_BlendFuncs));
|
||||
shader_image_blend = createShaderModule(context.device, "The shader blend image", strcat(strcpy(shaderSourceBuff, cShaderSrc_Image_Blend), cShaderSrc_BlendFuncs));
|
||||
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);
|
||||
|
||||
// graphics shader modules
|
||||
shaderStencil = createShaderModule(context.device, "The shader stencil", cShaderSrc_Stencil);
|
||||
shaderSolid = createShaderModule(context.device, "The shader solid", cShaderSrc_Solid);
|
||||
shaderRadial = createShaderModule(context.device, "The shader radial", cShaderSrc_Radial);
|
||||
shaderLinear = createShaderModule(context.device, "The shader linear", cShaderSrc_Linear);
|
||||
shaderImage = createShaderModule(context.device, "The shader image", cShaderSrc_Image);
|
||||
shaderSceneComp = createShaderModule(context.device, "The shader scene composition", cShaderSrc_Scene_Comp);
|
||||
shaderSceneBlend = createShaderModule(context.device, "The shader scene blend", cShaderSrc_Scene_Blend);
|
||||
shaderBlit = createShaderModule(context.device, "The shader blit", cShaderSrc_Blit);
|
||||
// computes shader modules
|
||||
shaderMergeMasks = createShaderModule(context.device, "The shader merge mask", cShaderSrc_MergeMasks);
|
||||
// layouts
|
||||
layout_stencil = createPipelineLayout(context.device, bindGroupLayoutsStencil, 2);
|
||||
// layouts normal blend
|
||||
layout_solid = createPipelineLayout(context.device, bindGroupLayoutsSolid, 3);
|
||||
layout_gradient = createPipelineLayout(context.device, bindGroupLayoutsGradient, 3);
|
||||
layout_image = createPipelineLayout(context.device, bindGroupLayoutsImage, 3);
|
||||
layout_scene = createPipelineLayout(context.device, bindGroupLayoutsScene, 2);
|
||||
// layouts custom blend
|
||||
layout_solid_blend = createPipelineLayout(context.device, bindGroupLayoutsSolidBlend, 4);
|
||||
layout_gradient_blend = createPipelineLayout(context.device, bindGroupLayoutsGradientBlend, 4);
|
||||
layout_image_blend = createPipelineLayout(context.device, bindGroupLayoutsImageBlend, 4);
|
||||
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);
|
||||
|
||||
// render pipeline winding
|
||||
winding = createRenderPipeline(
|
||||
context.device, "The render pipeline winding",
|
||||
shaderStencil, "vs_main", "fs_main", layoutStencil,
|
||||
shader_stencil, "vs_main", "fs_main", layout_stencil,
|
||||
vertexBufferLayoutsShape, 1,
|
||||
WGPUColorWriteMask_None, offscreenTargetFormat,
|
||||
WGPUCompareFunction_Always, WGPUStencilOperation_IncrementWrap,
|
||||
|
@ -241,7 +228,7 @@ void WgPipelines::initialize(WgContext& context)
|
|||
// render pipeline even-odd
|
||||
evenodd = createRenderPipeline(
|
||||
context.device, "The render pipeline even-odd",
|
||||
shaderStencil, "vs_main", "fs_main", layoutStencil,
|
||||
shader_stencil, "vs_main", "fs_main", layout_stencil,
|
||||
vertexBufferLayoutsShape, 1,
|
||||
WGPUColorWriteMask_None, offscreenTargetFormat,
|
||||
WGPUCompareFunction_Always, WGPUStencilOperation_Invert,
|
||||
|
@ -250,16 +237,16 @@ void WgPipelines::initialize(WgContext& context)
|
|||
// render pipeline direct
|
||||
direct = createRenderPipeline(
|
||||
context.device, "The render pipeline direct",
|
||||
shaderStencil,"vs_main", "fs_main", layoutStencil,
|
||||
shader_stencil, "vs_main", "fs_main", layout_stencil,
|
||||
vertexBufferLayoutsShape, 1,
|
||||
WGPUColorWriteMask_None, offscreenTargetFormat,
|
||||
WGPUCompareFunction_Always, WGPUStencilOperation_Replace,
|
||||
WGPUCompareFunction_Always, WGPUStencilOperation_Replace,
|
||||
primitiveState, multisampleState, blendStateSrc);
|
||||
// render pipeline clip path
|
||||
clipPath = createRenderPipeline(
|
||||
clip_path = createRenderPipeline(
|
||||
context.device, "The render pipeline clip path",
|
||||
shaderStencil, "vs_main", "fs_main", layoutStencil,
|
||||
shader_stencil, "vs_main", "fs_main", layout_stencil,
|
||||
vertexBufferLayoutsShape, 1,
|
||||
WGPUColorWriteMask_All, offscreenTargetFormat,
|
||||
WGPUCompareFunction_NotEqual, WGPUStencilOperation_Zero,
|
||||
|
@ -267,81 +254,116 @@ void WgPipelines::initialize(WgContext& context)
|
|||
primitiveState, multisampleState, blendStateSrc);
|
||||
|
||||
// render pipeline solid
|
||||
for (uint32_t i = 0; i < 2; i++) {
|
||||
solid[i] = createRenderPipeline(
|
||||
context.device, "The render pipeline solid",
|
||||
shaderSolid, "vs_main", "fs_main", layoutSolid,
|
||||
vertexBufferLayoutsShape, 1,
|
||||
WGPUColorWriteMask_All, offscreenTargetFormat,
|
||||
WGPUCompareFunction_NotEqual, WGPUStencilOperation_Zero,
|
||||
WGPUCompareFunction_NotEqual, WGPUStencilOperation_Zero,
|
||||
primitiveState, multisampleState, blendStates[i]);
|
||||
}
|
||||
|
||||
solid = createRenderPipeline(
|
||||
context.device, "The render pipeline solid",
|
||||
shader_solid, "vs_main", "fs_main", layout_solid,
|
||||
vertexBufferLayoutsShape, 1,
|
||||
WGPUColorWriteMask_All, offscreenTargetFormat,
|
||||
WGPUCompareFunction_NotEqual, WGPUStencilOperation_Zero,
|
||||
WGPUCompareFunction_NotEqual, WGPUStencilOperation_Zero,
|
||||
primitiveState, multisampleState, blendStateNrm);
|
||||
// render pipeline radial
|
||||
for (uint32_t i = 0; i < 2; i++) {
|
||||
radial[i] = createRenderPipeline(
|
||||
context.device, "The render pipeline radial",
|
||||
shaderRadial, "vs_main", "fs_main", layoutGradient,
|
||||
vertexBufferLayoutsShape, 1,
|
||||
WGPUColorWriteMask_All, offscreenTargetFormat,
|
||||
WGPUCompareFunction_NotEqual, WGPUStencilOperation_Zero,
|
||||
WGPUCompareFunction_NotEqual, WGPUStencilOperation_Zero,
|
||||
primitiveState, multisampleState, blendStates[i]);
|
||||
}
|
||||
|
||||
radial = createRenderPipeline(
|
||||
context.device, "The render pipeline radial",
|
||||
shader_radial, "vs_main", "fs_main", layout_gradient,
|
||||
vertexBufferLayoutsShape, 1,
|
||||
WGPUColorWriteMask_All, offscreenTargetFormat,
|
||||
WGPUCompareFunction_NotEqual, WGPUStencilOperation_Zero,
|
||||
WGPUCompareFunction_NotEqual, WGPUStencilOperation_Zero,
|
||||
primitiveState, multisampleState, blendStateNrm);
|
||||
// render pipeline linear
|
||||
for (uint32_t i = 0; i < 2; i++) {
|
||||
linear[i] = createRenderPipeline(
|
||||
context.device, "The render pipeline linear",
|
||||
shaderLinear, "vs_main", "fs_main", layoutGradient,
|
||||
vertexBufferLayoutsShape, 1,
|
||||
WGPUColorWriteMask_All, offscreenTargetFormat,
|
||||
WGPUCompareFunction_NotEqual, WGPUStencilOperation_Zero,
|
||||
WGPUCompareFunction_NotEqual, WGPUStencilOperation_Zero,
|
||||
primitiveState, multisampleState, blendStates[i]);
|
||||
}
|
||||
|
||||
linear = createRenderPipeline(
|
||||
context.device, "The render pipeline linear",
|
||||
shader_linear, "vs_main", "fs_main", layout_gradient,
|
||||
vertexBufferLayoutsShape, 1,
|
||||
WGPUColorWriteMask_All, offscreenTargetFormat,
|
||||
WGPUCompareFunction_NotEqual, WGPUStencilOperation_Zero,
|
||||
WGPUCompareFunction_NotEqual, WGPUStencilOperation_Zero,
|
||||
primitiveState, multisampleState, blendStateNrm);
|
||||
// render pipeline image
|
||||
for (uint32_t i = 0; i < 2; i++) {
|
||||
image[i] = createRenderPipeline(
|
||||
context.device, "The render pipeline image",
|
||||
shaderImage, "vs_main", "fs_main", layoutImage,
|
||||
vertexBufferLayoutsImage, 2,
|
||||
WGPUColorWriteMask_All, offscreenTargetFormat,
|
||||
WGPUCompareFunction_Always, WGPUStencilOperation_Zero,
|
||||
WGPUCompareFunction_Always, WGPUStencilOperation_Zero,
|
||||
primitiveState, multisampleState, blendStates[i]);
|
||||
}
|
||||
|
||||
// render pipeline blit
|
||||
blit = createRenderPipeline(context.device, "The render pipeline blit",
|
||||
shaderBlit, "vs_main", "fs_main", layoutBlit,
|
||||
vertexBufferLayoutsImage, 2,
|
||||
// must be preferred screen pixel format
|
||||
WGPUColorWriteMask_All, context.preferredFormat,
|
||||
WGPUCompareFunction_Always, WGPUStencilOperation_Zero,
|
||||
WGPUCompareFunction_Always, WGPUStencilOperation_Zero,
|
||||
primitiveState, multisampleState, blendStateSrc);
|
||||
|
||||
// render pipeline blend
|
||||
sceneBlend = createRenderPipeline(context.device, "The render pipeline scene blend",
|
||||
shaderSceneBlend, "vs_main", "fs_main", layoutSceneBlend,
|
||||
vertexBufferLayoutsImage, 2,
|
||||
WGPUColorWriteMask_All, offscreenTargetFormat,
|
||||
WGPUCompareFunction_Always, WGPUStencilOperation_Zero,
|
||||
WGPUCompareFunction_Always, WGPUStencilOperation_Zero,
|
||||
primitiveState, multisampleState, blendStateNrm);
|
||||
|
||||
// render pipeline scene clip path
|
||||
sceneClip = createRenderPipeline(
|
||||
context.device, "The render pipeline scene clip path",
|
||||
shaderSceneComp, "vs_main", "fs_main_ClipPath", layoutSceneComp,
|
||||
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);
|
||||
// render pipeline scene
|
||||
scene = createRenderPipeline(
|
||||
context.device, "The render pipeline scene",
|
||||
shader_scene, "vs_main", "fs_main", layout_scene,
|
||||
vertexBufferLayoutsImage, 2,
|
||||
WGPUColorWriteMask_All, offscreenTargetFormat,
|
||||
WGPUCompareFunction_Always, WGPUStencilOperation_Zero,
|
||||
WGPUCompareFunction_Always, WGPUStencilOperation_Zero,
|
||||
primitiveState, multisampleState, blendStateNrm);
|
||||
|
||||
// blend shader names
|
||||
const char* shaderBlendNames[] {
|
||||
"fs_main_Normal",
|
||||
"fs_main_Multiply",
|
||||
"fs_main_Screen",
|
||||
"fs_main_Overlay",
|
||||
"fs_main_Darken",
|
||||
"fs_main_Lighten",
|
||||
"fs_main_ColorDodge",
|
||||
"fs_main_ColorBurn",
|
||||
"fs_main_HardLight",
|
||||
"fs_main_SoftLight",
|
||||
"fs_main_Difference",
|
||||
"fs_main_Exclusion",
|
||||
"fs_main_Normal", //TODO: a padding for reserved Hue.
|
||||
"fs_main_Normal", //TODO: a padding for reserved Saturation.
|
||||
"fs_main_Normal", //TODO: a padding for reserved Color.
|
||||
"fs_main_Normal", //TODO: a padding for reserved Luminosity.
|
||||
"fs_main_Add",
|
||||
"fs_main_Normal" //TODO: a padding for reserved Hardmix.
|
||||
};
|
||||
|
||||
// render pipeline shape blend
|
||||
for (uint32_t i = 0; i < 18; i++) {
|
||||
// blend solid
|
||||
solid_blend[i] = createRenderPipeline(context.device, "The render pipeline solid blend",
|
||||
shader_solid_blend, "vs_main", shaderBlendNames[i], layout_solid_blend,
|
||||
vertexBufferLayoutsShape, 1,
|
||||
WGPUColorWriteMask_All, offscreenTargetFormat,
|
||||
WGPUCompareFunction_NotEqual, WGPUStencilOperation_Zero,
|
||||
WGPUCompareFunction_NotEqual, WGPUStencilOperation_Zero,
|
||||
primitiveState, 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,
|
||||
vertexBufferLayoutsShape, 1,
|
||||
WGPUColorWriteMask_All, offscreenTargetFormat,
|
||||
WGPUCompareFunction_NotEqual, WGPUStencilOperation_Zero,
|
||||
WGPUCompareFunction_NotEqual, WGPUStencilOperation_Zero,
|
||||
primitiveState, 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,
|
||||
vertexBufferLayoutsShape, 1,
|
||||
WGPUColorWriteMask_All, offscreenTargetFormat,
|
||||
WGPUCompareFunction_NotEqual, WGPUStencilOperation_Zero,
|
||||
WGPUCompareFunction_NotEqual, WGPUStencilOperation_Zero,
|
||||
primitiveState, 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);
|
||||
// blend scene
|
||||
scene_blend[i] = createRenderPipeline(context.device, "The render pipeline scene blend",
|
||||
shader_scene_blend, "vs_main", shaderBlendNames[i], layout_scene_blend,
|
||||
vertexBufferLayoutsImage, 2,
|
||||
WGPUColorWriteMask_All, offscreenTargetFormat,
|
||||
WGPUCompareFunction_Always, WGPUStencilOperation_Zero,
|
||||
WGPUCompareFunction_Always, WGPUStencilOperation_Zero,
|
||||
primitiveState, multisampleState, blendStateSrc);
|
||||
}
|
||||
|
||||
// compose shader names
|
||||
const char* shaderComposeNames[] {
|
||||
|
@ -374,15 +396,10 @@ void WgPipelines::initialize(WgContext& context)
|
|||
};
|
||||
|
||||
// render pipeline scene composition
|
||||
size_t shaderComposeNamesCnt = sizeof(shaderComposeNames) / sizeof(shaderComposeNames[0]);
|
||||
size_t composeBlendspCnt = sizeof(composeBlends) / sizeof(composeBlends[0]);
|
||||
size_t sceneCompCnt = sizeof(sceneComp) / sizeof(sceneComp[0]);
|
||||
assert(shaderComposeNamesCnt == composeBlendspCnt);
|
||||
assert(composeBlendspCnt == sceneCompCnt);
|
||||
for (uint32_t i = 0; i < sceneCompCnt; i++) {
|
||||
sceneComp[i] = createRenderPipeline(
|
||||
for (uint32_t i = 0; i < 11; i++) {
|
||||
scene_compose[i] = createRenderPipeline(
|
||||
context.device, "The render pipeline scene composition",
|
||||
shaderSceneComp, "vs_main", shaderComposeNames[i], layoutSceneComp,
|
||||
shader_scene_compose, "vs_main", shaderComposeNames[i], layout_scene_compose,
|
||||
vertexBufferLayoutsImage, 2,
|
||||
WGPUColorWriteMask_All, offscreenTargetFormat,
|
||||
WGPUCompareFunction_Always, WGPUStencilOperation_Zero,
|
||||
|
@ -390,99 +407,95 @@ void WgPipelines::initialize(WgContext& context)
|
|||
primitiveState, 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
|
||||
mergeMasks = createComputePipeline(context.device, "The pipeline merge masks", shaderMergeMasks, "cs_main", layoutMergeMasks);
|
||||
merge_masks = createComputePipeline(
|
||||
context.device, "The compute pipeline merge masks",
|
||||
shader_merge_masks, "cs_main", layout_merge_masks);
|
||||
|
||||
// compute shader blend names
|
||||
const char* shaderBlendNames[] {
|
||||
"cs_main_Normal",
|
||||
"cs_main_Multiply",
|
||||
"cs_main_Screen",
|
||||
"cs_main_Overlay",
|
||||
"cs_main_Darken",
|
||||
"cs_main_Lighten",
|
||||
"cs_main_ColorDodge",
|
||||
"cs_main_ColorBurn",
|
||||
"cs_main_HardLight",
|
||||
"cs_main_SoftLight",
|
||||
"cs_main_Difference",
|
||||
"cs_main_Exclusion",
|
||||
"cs_main_Normal", //TODO: a padding for reserved Hue.
|
||||
"cs_main_Normal", //TODO: a padding for reserved Saturation.
|
||||
"cs_main_Normal", //TODO: a padding for reserved Color.
|
||||
"cs_main_Normal", //TODO: a padding for reserved Luminosity.
|
||||
"cs_main_Add",
|
||||
"cs_main_Normal" //TODO: a padding for reserved Hardmix.
|
||||
};
|
||||
|
||||
// create blend shaders
|
||||
char shaderSourceBuff[16384];
|
||||
shaderBlendSolid = createShaderModule(context.device, "The shader blend solid", strcat(strcpy(shaderSourceBuff, cShaderSrc_BlendHeader_Solid), cShaderSrc_Blend_Funcs));
|
||||
shaderBlendGradient = createShaderModule(context.device, "The shader blend gradient", strcat(strcpy(shaderSourceBuff, cShaderSrc_BlendHeader_Gradient), cShaderSrc_Blend_Funcs));
|
||||
shaderBlendImage = createShaderModule(context.device, "The shader blend image", strcat(strcpy(shaderSourceBuff, cShaderSrc_BlendHeader_Image), cShaderSrc_Blend_Funcs));
|
||||
|
||||
// create blend pipelines
|
||||
const size_t shaderBlendNamesCnt = sizeof(shaderBlendNames) / sizeof(shaderBlendNames[0]);
|
||||
const size_t pipesBlendCnt = sizeof(blendSolid) / sizeof(blendSolid[0]);
|
||||
assert(shaderBlendNamesCnt == pipesBlendCnt);
|
||||
for (uint32_t i = 0; i < pipesBlendCnt; i++) {
|
||||
blendSolid[i] = createComputePipeline(context.device, "The pipeline blend solid", shaderBlendSolid, shaderBlendNames[i], layoutBlend);
|
||||
blendGradient[i] = createComputePipeline(context.device, "The pipeline blend gradient", shaderBlendGradient, shaderBlendNames[i], layoutBlend);
|
||||
blendImage[i] = createComputePipeline(context.device, "The pipeline blend image", shaderBlendImage, shaderBlendNames[i], layoutBlend);
|
||||
}
|
||||
// render pipeline blit
|
||||
blit = createRenderPipeline(context.device, "The render pipeline blit",
|
||||
shader_blit, "vs_main", "fs_main", layout_blit,
|
||||
vertexBufferLayoutsImage, 2,
|
||||
// must be preferred screen pixel format
|
||||
WGPUColorWriteMask_All, context.preferredFormat,
|
||||
WGPUCompareFunction_Always, WGPUStencilOperation_Zero,
|
||||
WGPUCompareFunction_Always, WGPUStencilOperation_Zero,
|
||||
primitiveState, multisampleState, blendStateSrc);
|
||||
}
|
||||
|
||||
void WgPipelines::releaseGraphicHandles(WgContext& context)
|
||||
{
|
||||
// pipeline blit
|
||||
releaseRenderPipeline(blit);
|
||||
releaseRenderPipeline(clipPath);
|
||||
releaseRenderPipeline(sceneBlend);
|
||||
releaseRenderPipeline(sceneClip);
|
||||
size_t pipesSceneCompCnt = sizeof(sceneComp) / sizeof(sceneComp[0]);
|
||||
for (uint32_t i = 0; i < pipesSceneCompCnt; i++)
|
||||
releaseRenderPipeline(sceneComp[i]);
|
||||
for (uint32_t i = 0; i < 2; i++) {
|
||||
releaseRenderPipeline(image[i]);
|
||||
releaseRenderPipeline(linear[i]);
|
||||
releaseRenderPipeline(radial[i]);
|
||||
releaseRenderPipeline(solid[i]);
|
||||
// pipelines compose
|
||||
releaseRenderPipeline(scene_clip);
|
||||
for (uint32_t i = 0; i < 11; i++)
|
||||
releaseRenderPipeline(scene_compose[i]);
|
||||
// pipelines custom blend
|
||||
for (uint32_t i = 0; i < 18; i++) {
|
||||
releaseRenderPipeline(scene_blend[i]);
|
||||
releaseRenderPipeline(image_blend[i]);
|
||||
releaseRenderPipeline(linear_blend[i]);
|
||||
releaseRenderPipeline(radial_blend[i]);
|
||||
releaseRenderPipeline(solid_blend[i]);
|
||||
}
|
||||
// pipelines normal blend
|
||||
releaseRenderPipeline(scene);
|
||||
releaseRenderPipeline(image);
|
||||
releaseRenderPipeline(linear);
|
||||
releaseRenderPipeline(radial);
|
||||
releaseRenderPipeline(solid);
|
||||
// pipelines helpers
|
||||
releaseRenderPipeline(clip_path);
|
||||
releaseRenderPipeline(direct);
|
||||
releaseRenderPipeline(evenodd);
|
||||
releaseRenderPipeline(winding);
|
||||
releasePipelineLayout(layoutBlit);
|
||||
releasePipelineLayout(layoutSceneBlend);
|
||||
releasePipelineLayout(layoutSceneComp);
|
||||
releasePipelineLayout(layoutImage);
|
||||
releasePipelineLayout(layoutGradient);
|
||||
releasePipelineLayout(layoutSolid);
|
||||
releasePipelineLayout(layoutStencil);
|
||||
releaseShaderModule(shaderBlit);
|
||||
releaseShaderModule(shaderSceneBlend);
|
||||
releaseShaderModule(shaderSceneComp);
|
||||
releaseShaderModule(shaderImage);
|
||||
releaseShaderModule(shaderLinear);
|
||||
releaseShaderModule(shaderRadial);
|
||||
releaseShaderModule(shaderSolid);
|
||||
releaseShaderModule(shaderStencil);
|
||||
// layouts
|
||||
releasePipelineLayout(layout_blit);
|
||||
releasePipelineLayout(layout_merge_masks);
|
||||
releasePipelineLayout(layout_scene_compose);
|
||||
releasePipelineLayout(layout_scene_blend);
|
||||
releasePipelineLayout(layout_image_blend);
|
||||
releasePipelineLayout(layout_gradient_blend);
|
||||
releasePipelineLayout(layout_solid_blend);
|
||||
releasePipelineLayout(layout_scene);
|
||||
releasePipelineLayout(layout_image);
|
||||
releasePipelineLayout(layout_gradient);
|
||||
releasePipelineLayout(layout_solid);
|
||||
releasePipelineLayout(layout_stencil);
|
||||
// shaders
|
||||
releaseShaderModule(shader_blit);
|
||||
releaseShaderModule(shader_merge_masks);
|
||||
releaseShaderModule(shader_scene_compose);
|
||||
releaseShaderModule(shader_scene_blend);
|
||||
releaseShaderModule(shader_image_blend);
|
||||
releaseShaderModule(shader_linear_blend);
|
||||
releaseShaderModule(shader_radial_blend);
|
||||
releaseShaderModule(shader_solid_blend);
|
||||
releaseShaderModule(shader_scene);
|
||||
releaseShaderModule(shader_image);
|
||||
releaseShaderModule(shader_linear);
|
||||
releaseShaderModule(shader_radial);
|
||||
releaseShaderModule(shader_solid);
|
||||
releaseShaderModule(shader_stencil);
|
||||
}
|
||||
|
||||
|
||||
void WgPipelines::releaseComputeHandles(WgContext& context)
|
||||
{
|
||||
const size_t pipesBlendCnt = sizeof(blendSolid)/sizeof(blendSolid[0]);
|
||||
for (uint32_t i = 0; i < pipesBlendCnt; i++) {
|
||||
releaseComputePipeline(blendImage[i]);
|
||||
releaseComputePipeline(blendSolid[i]);
|
||||
releaseComputePipeline(blendGradient[i]);
|
||||
}
|
||||
releaseComputePipeline(mergeMasks);
|
||||
releasePipelineLayout(layoutBlend);
|
||||
releasePipelineLayout(layoutMergeMasks);
|
||||
releaseShaderModule(shaderBlendImage);
|
||||
releaseShaderModule(shaderBlendGradient);
|
||||
releaseShaderModule(shaderBlendSolid);
|
||||
releaseShaderModule(shaderMergeMasks);
|
||||
releaseComputePipeline(merge_masks);
|
||||
releasePipelineLayout(layout_merge_masks);
|
||||
releaseShaderModule(shader_merge_masks);
|
||||
}
|
||||
|
||||
void WgPipelines::release(WgContext& context)
|
||||
|
|
|
@ -25,56 +25,72 @@
|
|||
|
||||
#include "tvgWgBindGroups.h"
|
||||
|
||||
enum class WgPipelineBlendType { Normal, Custom };
|
||||
|
||||
class WgPipelines {
|
||||
private:
|
||||
// graphics pipeline shaders
|
||||
WGPUShaderModule shaderStencil{};
|
||||
WGPUShaderModule shaderSolid{};
|
||||
WGPUShaderModule shaderRadial{};
|
||||
WGPUShaderModule shaderLinear{};
|
||||
WGPUShaderModule shaderImage{};
|
||||
WGPUShaderModule shaderSceneComp{};
|
||||
WGPUShaderModule shaderSceneBlend{};
|
||||
WGPUShaderModule shaderBlit{};
|
||||
// compute pipeline shaders
|
||||
WGPUShaderModule shaderMergeMasks;
|
||||
WGPUShaderModule shaderBlendSolid;
|
||||
WGPUShaderModule shaderBlendGradient;
|
||||
WGPUShaderModule shaderBlendImage;
|
||||
// shaders helpers
|
||||
WGPUShaderModule shader_stencil{};
|
||||
// shaders normal blend
|
||||
WGPUShaderModule shader_solid{};
|
||||
WGPUShaderModule shader_radial{};
|
||||
WGPUShaderModule shader_linear{};
|
||||
WGPUShaderModule shader_image{};
|
||||
WGPUShaderModule shader_scene{};
|
||||
// shaders custom blend
|
||||
WGPUShaderModule shader_solid_blend{};
|
||||
WGPUShaderModule shader_radial_blend{};
|
||||
WGPUShaderModule shader_linear_blend{};
|
||||
WGPUShaderModule shader_image_blend{};
|
||||
WGPUShaderModule shader_scene_blend{};
|
||||
// shader scene compose
|
||||
WGPUShaderModule shader_scene_compose{};
|
||||
WGPUShaderModule shader_merge_masks;
|
||||
// shader blit
|
||||
WGPUShaderModule shader_blit{};
|
||||
private:
|
||||
// graphics pipeline layouts
|
||||
WGPUPipelineLayout layoutStencil{};
|
||||
WGPUPipelineLayout layoutSolid{};
|
||||
WGPUPipelineLayout layoutGradient{};
|
||||
WGPUPipelineLayout layoutImage{};
|
||||
WGPUPipelineLayout layoutSceneComp{};
|
||||
WGPUPipelineLayout layoutSceneBlend{};
|
||||
WGPUPipelineLayout layoutBlit{};
|
||||
// compute pipeline layouts
|
||||
WGPUPipelineLayout layoutMergeMasks{};
|
||||
WGPUPipelineLayout layoutBlend{};
|
||||
// layouts helpers
|
||||
WGPUPipelineLayout layout_stencil{};
|
||||
// layouts normal blend
|
||||
WGPUPipelineLayout layout_solid{};
|
||||
WGPUPipelineLayout layout_gradient{};
|
||||
WGPUPipelineLayout layout_image{};
|
||||
WGPUPipelineLayout layout_scene{};
|
||||
// layouts custom blend
|
||||
WGPUPipelineLayout layout_solid_blend{};
|
||||
WGPUPipelineLayout layout_gradient_blend{};
|
||||
WGPUPipelineLayout layout_image_blend{};
|
||||
WGPUPipelineLayout layout_scene_blend{};
|
||||
// layouts scene compose
|
||||
WGPUPipelineLayout layout_scene_compose{};
|
||||
WGPUPipelineLayout layout_merge_masks{};
|
||||
// layouts blit
|
||||
WGPUPipelineLayout layout_blit{};
|
||||
public:
|
||||
// graphics pipeline
|
||||
WgBindGroupLayouts layouts;
|
||||
// pipelines helpers
|
||||
WGPURenderPipeline winding{};
|
||||
WGPURenderPipeline evenodd{};
|
||||
WGPURenderPipeline direct{};
|
||||
WGPURenderPipeline solid[2]{};
|
||||
WGPURenderPipeline radial[2]{};
|
||||
WGPURenderPipeline linear[2]{};
|
||||
WGPURenderPipeline image[2]{};
|
||||
WGPURenderPipeline sceneClip;
|
||||
WGPURenderPipeline sceneComp[11];
|
||||
WGPURenderPipeline sceneBlend;
|
||||
WGPURenderPipeline clip_path{};
|
||||
// pipelines normal blend
|
||||
WGPURenderPipeline solid{};
|
||||
WGPURenderPipeline radial{};
|
||||
WGPURenderPipeline linear{};
|
||||
WGPURenderPipeline image{};
|
||||
WGPURenderPipeline scene{};
|
||||
// pipelines custom blend
|
||||
WGPURenderPipeline solid_blend[18]{};
|
||||
WGPURenderPipeline radial_blend[18]{};
|
||||
WGPURenderPipeline linear_blend[18]{};
|
||||
WGPURenderPipeline image_blend[18]{};
|
||||
WGPURenderPipeline scene_blend[18]{};
|
||||
// pipelines compose
|
||||
WGPURenderPipeline scene_compose[11]{};
|
||||
WGPURenderPipeline scene_clip{};
|
||||
WGPUComputePipeline merge_masks{};
|
||||
// pipeline blit
|
||||
WGPURenderPipeline blit{};
|
||||
WGPURenderPipeline clipPath{};
|
||||
// compute pipeline
|
||||
WGPUComputePipeline mergeMasks;
|
||||
WGPUComputePipeline blendSolid[18];
|
||||
WGPUComputePipeline blendGradient[18];
|
||||
WGPUComputePipeline blendImage[18];
|
||||
public:
|
||||
// layouts
|
||||
WgBindGroupLayouts layouts;
|
||||
private:
|
||||
void releaseGraphicHandles(WgContext& context);
|
||||
void releaseComputeHandles(WgContext& context);
|
||||
|
|
|
@ -385,19 +385,10 @@ bool WgRenderer::endComposite(RenderCompositor* cmp)
|
|||
WgRenderStorage* src = mRenderStorageStack.last();
|
||||
mRenderStorageStack.pop();
|
||||
WgRenderStorage* dst = mRenderStorageStack.last();
|
||||
// apply normal blend
|
||||
if (comp->blend == BlendMethod::Normal) {
|
||||
// begin previous render pass
|
||||
mCompositor.beginRenderPass(mCommandEncoder, dst, false);
|
||||
// apply blend
|
||||
mCompositor.blendScene(mContext, src, comp);
|
||||
// apply custom blend
|
||||
} else {
|
||||
// apply custom blend
|
||||
mCompositor.blend(mCommandEncoder, src, dst, comp->opacity, comp->blend, WgRenderRasterType::Image);
|
||||
// begin previous render pass
|
||||
mCompositor.beginRenderPass(mCommandEncoder, dst, false);
|
||||
}
|
||||
// begin previous render pass
|
||||
mCompositor.beginRenderPass(mCommandEncoder, dst, false);
|
||||
// apply composition
|
||||
mCompositor.renderScene(mContext, src, comp);
|
||||
// back render targets to the pool
|
||||
mRenderStoragePool.free(mContext, src);
|
||||
} else { // finish composition
|
||||
|
|
|
@ -50,7 +50,7 @@ fn fs_main(in: VertexOutput) -> @location(0) vec4f {
|
|||
)";
|
||||
|
||||
//************************************************************************
|
||||
// graphics shader source: solid
|
||||
// graphics shader source: solid normal blend
|
||||
//************************************************************************
|
||||
|
||||
const char* cShaderSrc_Solid = R"(
|
||||
|
@ -79,12 +79,12 @@ fn fs_main(in: VertexOutput) -> @location(0) vec4f {
|
|||
)";
|
||||
|
||||
//************************************************************************
|
||||
// graphics shader source: linear
|
||||
// graphics shader source: linear normal blend
|
||||
//************************************************************************
|
||||
|
||||
const char* cShaderSrc_Linear = R"(
|
||||
struct VertexInput { @location(0) position: vec2f };
|
||||
struct VertexOutput { @builtin(position) position : vec4f, @location(0) vScreenCoord : vec4f };
|
||||
struct VertexOutput { @builtin(position) position : vec4f, @location(0) vGradCoord : vec4f };
|
||||
|
||||
// uniforms
|
||||
@group(0) @binding(0) var<uniform> uViewMat : mat4x4f;
|
||||
|
@ -99,13 +99,13 @@ struct VertexOutput { @builtin(position) position : vec4f, @location(0) vScreenC
|
|||
fn vs_main(in: VertexInput) -> VertexOutput {
|
||||
var out: VertexOutput;
|
||||
out.position = uViewMat * uModelMat * vec4f(in.position.xy, 0.0, 1.0);
|
||||
out.vScreenCoord = uTransformGrad * vec4f(in.position.xy, 0.0, 1.0);
|
||||
out.vGradCoord = uTransformGrad * vec4f(in.position.xy, 0.0, 1.0);
|
||||
return out;
|
||||
}
|
||||
|
||||
@fragment
|
||||
fn fs_main(in: VertexOutput) -> @location(0) vec4f {
|
||||
let pos = in.vScreenCoord.xy;
|
||||
let pos = in.vGradCoord.xy;
|
||||
let st = uSettingGrad.xy;
|
||||
let ed = uSettingGrad.zw;
|
||||
let ba = ed - st;
|
||||
|
@ -117,12 +117,12 @@ fn fs_main(in: VertexOutput) -> @location(0) vec4f {
|
|||
)";
|
||||
|
||||
//************************************************************************
|
||||
// graphics shader source: radial
|
||||
// graphics shader source: radial normal blend
|
||||
//************************************************************************
|
||||
|
||||
const char* cShaderSrc_Radial = R"(
|
||||
struct VertexInput { @location(0) position: vec2f };
|
||||
struct VertexOutput { @builtin(position) position : vec4f, @location(0) vScreenCoord : vec4f };
|
||||
struct VertexOutput { @builtin(position) position : vec4f, @location(0) vGradCoord : vec4f };
|
||||
|
||||
@group(0) @binding(0) var<uniform> uViewMat : mat4x4f;
|
||||
@group(1) @binding(0) var<uniform> uModelMat : mat4x4f;
|
||||
|
@ -136,13 +136,13 @@ struct VertexOutput { @builtin(position) position : vec4f, @location(0) vScreenC
|
|||
fn vs_main(in: VertexInput) -> VertexOutput {
|
||||
var out: VertexOutput;
|
||||
out.position = uViewMat * uModelMat * vec4f(in.position.xy, 0.0, 1.0);
|
||||
out.vScreenCoord = uTransformGrad * vec4f(in.position.xy, 0.0, 1.0);
|
||||
out.vGradCoord = uTransformGrad * vec4f(in.position.xy, 0.0, 1.0);
|
||||
return out;
|
||||
}
|
||||
|
||||
@fragment
|
||||
fn fs_main(in: VertexOutput) -> @location(0) vec4f {
|
||||
let t: f32 = distance(uSettingGrad.zw, in.vScreenCoord.xy) / uSettingGrad.r;
|
||||
let t: f32 = distance(uSettingGrad.zw, in.vGradCoord.xy) / uSettingGrad.r;
|
||||
let Sc = textureSample(uTextureGrad, uSamplerGrad, vec2f(t, 0.5));
|
||||
let So = uBlendSettings.a;
|
||||
return vec4f(Sc.rgb * Sc.a * So, Sc.a * So);
|
||||
|
@ -150,12 +150,12 @@ fn fs_main(in: VertexOutput) -> @location(0) vec4f {
|
|||
)";
|
||||
|
||||
//************************************************************************
|
||||
// graphics shader source: image
|
||||
// graphics shader source: image normal blend
|
||||
//************************************************************************
|
||||
|
||||
const char* cShaderSrc_Image = R"(
|
||||
struct VertexInput { @location(0) position: vec2f, @location(1) texCoord: vec2f };
|
||||
struct VertexOutput { @builtin(position) position: vec4f, @location(0) texCoord: vec2f };
|
||||
struct VertexOutput { @builtin(position) position: vec4f, @location(0) vTexCoord: vec2f };
|
||||
|
||||
@group(0) @binding(0) var<uniform> uViewMat : mat4x4f;
|
||||
@group(1) @binding(0) var<uniform> uModelMat : mat4x4f;
|
||||
|
@ -167,13 +167,13 @@ struct VertexOutput { @builtin(position) position: vec4f, @location(0) texCoord:
|
|||
fn vs_main(in: VertexInput) -> VertexOutput {
|
||||
var out: VertexOutput;
|
||||
out.position = uViewMat * uModelMat * vec4f(in.position.xy, 0.0, 1.0);
|
||||
out.texCoord = in.texCoord;
|
||||
out.vTexCoord = in.texCoord;
|
||||
return out;
|
||||
}
|
||||
|
||||
@fragment
|
||||
fn fs_main(in: VertexOutput) -> @location(0) vec4f {
|
||||
var Sc: vec4f = textureSample(uTextureView, uSampler, in.texCoord.xy);
|
||||
var Sc: vec4f = textureSample(uTextureView, uSampler, in.vTexCoord.xy);
|
||||
let So: f32 = uBlendSettings.a;
|
||||
switch u32(uBlendSettings.r) {
|
||||
case 0u: { Sc = Sc.rgba; }
|
||||
|
@ -186,11 +186,367 @@ fn fs_main(in: VertexOutput) -> @location(0) vec4f {
|
|||
};
|
||||
)";
|
||||
|
||||
//************************************************************************
|
||||
// graphics shader source: scene normal blend
|
||||
//************************************************************************
|
||||
|
||||
const char* cShaderSrc_Scene = R"(
|
||||
struct VertexInput { @location(0) position: vec2f, @location(1) texCoord: vec2f };
|
||||
struct VertexOutput { @builtin(position) position: vec4f, @location(0) vTexCoord: vec2f };
|
||||
|
||||
@group(0) @binding(0) var uSamplerSrc : sampler;
|
||||
@group(0) @binding(1) var uTextureSrc : texture_2d<f32>;
|
||||
@group(1) @binding(0) var<uniform> So : f32;
|
||||
|
||||
@vertex
|
||||
fn vs_main(in: VertexInput) -> VertexOutput {
|
||||
var out: VertexOutput;
|
||||
out.position = vec4f(in.position.xy, 0.0, 1.0);
|
||||
out.vTexCoord = in.texCoord;
|
||||
return out;
|
||||
}
|
||||
|
||||
@fragment
|
||||
fn fs_main(in: VertexOutput) -> @location(0) vec4f {
|
||||
return textureSample(uTextureSrc, uSamplerSrc, in.vTexCoord.xy) * So;
|
||||
};
|
||||
)";
|
||||
|
||||
//************************************************************************
|
||||
// graphics shader source: custom shaders
|
||||
//************************************************************************
|
||||
|
||||
const char* cShaderSrc_Solid_Blend = R"(
|
||||
struct VertexInput { @location(0) position: vec2f };
|
||||
struct VertexOutput { @builtin(position) position: vec4f, @location(1) vScrCoord: vec2f };
|
||||
|
||||
@group(0) @binding(0) var<uniform> uViewMat : mat4x4f;
|
||||
@group(1) @binding(0) var<uniform> uModelMat : mat4x4f;
|
||||
@group(1) @binding(1) var<uniform> uBlendSettings : vec4f;
|
||||
@group(2) @binding(0) var<uniform> uSolidColor : vec4f;
|
||||
@group(3) @binding(0) var uSamplerDst : sampler;
|
||||
@group(3) @binding(1) var uTextureDst : texture_2d<f32>;
|
||||
|
||||
@vertex
|
||||
fn vs_main(in: VertexInput) -> VertexOutput {
|
||||
var out: VertexOutput;
|
||||
let pos = uViewMat * uModelMat * vec4f(in.position.xy, 0.0, 1.0);
|
||||
out.position = pos;
|
||||
out.vScrCoord = vec2f(0.5 + pos.x * 0.5, 0.5 - pos.y * 0.5);
|
||||
return out;
|
||||
}
|
||||
|
||||
struct FragData { Sc: vec3f, Sa: f32, So: f32, Dc: vec3f, Da: f32 };
|
||||
fn getFragData(in: VertexOutput) -> FragData {
|
||||
// get source data
|
||||
let colorSrc = uSolidColor;
|
||||
let colorDst = textureSample(uTextureDst, uSamplerDst, in.vScrCoord.xy);
|
||||
// fill fragment data
|
||||
var data: FragData;
|
||||
data.Sc = colorSrc.rgb;
|
||||
data.Sa = colorSrc.a;
|
||||
data.So = uBlendSettings.a;
|
||||
data.Dc = colorDst.rgb;
|
||||
data.Da = colorDst.a;
|
||||
data.Sc = data.Sa * data.So * data.Sc;
|
||||
data.Sa = data.Sa * data.So;
|
||||
return data;
|
||||
};
|
||||
|
||||
fn postProcess(d: FragData, R: vec4f) -> vec4f { return R; };
|
||||
)";
|
||||
|
||||
const char* cShaderSrc_Linear_Blend = R"(
|
||||
struct VertexInput { @location(0) position: vec2f };
|
||||
struct VertexOutput { @builtin(position) position: vec4f, @location(0) vGradCoord : vec4f, @location(1) vScrCoord: vec2f };
|
||||
|
||||
@group(0) @binding(0) var<uniform> uViewMat : mat4x4f;
|
||||
@group(1) @binding(0) var<uniform> uModelMat : mat4x4f;
|
||||
@group(1) @binding(1) var<uniform> uBlendSettings : vec4f;
|
||||
@group(2) @binding(0) var uSamplerGrad : sampler;
|
||||
@group(2) @binding(1) var uTextureGrad : texture_2d<f32>;
|
||||
@group(2) @binding(2) var<uniform> uSettingGrad : vec4f;
|
||||
@group(2) @binding(3) var<uniform> uTransformGrad : mat4x4f;
|
||||
@group(3) @binding(0) var uSamplerDst : sampler;
|
||||
@group(3) @binding(1) var uTextureDst : texture_2d<f32>;
|
||||
|
||||
@vertex
|
||||
fn vs_main(in: VertexInput) -> VertexOutput {
|
||||
var out: VertexOutput;
|
||||
let pos = uViewMat * uModelMat * vec4f(in.position.xy, 0.0, 1.0);
|
||||
out.position = pos;
|
||||
out.vGradCoord = uTransformGrad * vec4f(in.position.xy, 0.0, 1.0);
|
||||
out.vScrCoord = vec2f(0.5 + pos.x * 0.5, 0.5 - pos.y * 0.5);
|
||||
return out;
|
||||
}
|
||||
|
||||
struct FragData { Sc: vec3f, Sa: f32, So: f32, Dc: vec3f, Da: f32 };
|
||||
fn getFragData(in: VertexOutput) -> FragData {
|
||||
// get source data
|
||||
let pos = in.vGradCoord.xy;
|
||||
let st = uSettingGrad.xy;
|
||||
let ed = uSettingGrad.zw;
|
||||
let ba = ed - st;
|
||||
let t = dot(pos - st, ba) / dot(ba, ba);
|
||||
let colorSrc = textureSample(uTextureGrad, uSamplerGrad, vec2f(t, 0.5));
|
||||
let colorDst = textureSample(uTextureDst, uSamplerDst, in.vScrCoord.xy);
|
||||
// fill fragment data
|
||||
var data: FragData;
|
||||
data.Sc = colorSrc.rgb;
|
||||
data.Sa = colorSrc.a;
|
||||
data.So = uBlendSettings.a;
|
||||
data.Dc = colorDst.rgb;
|
||||
data.Da = colorDst.a;
|
||||
data.Sc = mix(data.Dc, data.Sc, data.Sa * data.So);
|
||||
data.Sa = mix(data.Da, 1.0, data.Sa * data.So);
|
||||
return data;
|
||||
};
|
||||
|
||||
fn postProcess(d: FragData, R: vec4f) -> vec4f { return R; };
|
||||
)";
|
||||
|
||||
const char* cShaderSrc_Radial_Blend = R"(
|
||||
struct VertexInput { @location(0) position: vec2f };
|
||||
struct VertexOutput { @builtin(position) position: vec4f, @location(0) vGradCoord : vec4f, @location(1) vScrCoord: vec2f };
|
||||
|
||||
@group(0) @binding(0) var<uniform> uViewMat : mat4x4f;
|
||||
@group(1) @binding(0) var<uniform> uModelMat : mat4x4f;
|
||||
@group(1) @binding(1) var<uniform> uBlendSettings : vec4f;
|
||||
@group(2) @binding(0) var uSamplerGrad : sampler;
|
||||
@group(2) @binding(1) var uTextureGrad : texture_2d<f32>;
|
||||
@group(2) @binding(2) var<uniform> uSettingGrad : vec4f;
|
||||
@group(2) @binding(3) var<uniform> uTransformGrad : mat4x4f;
|
||||
@group(3) @binding(0) var uSamplerDst : sampler;
|
||||
@group(3) @binding(1) var uTextureDst : texture_2d<f32>;
|
||||
|
||||
@vertex
|
||||
fn vs_main(in: VertexInput) -> VertexOutput {
|
||||
var out: VertexOutput;
|
||||
let pos = uViewMat * uModelMat * vec4f(in.position.xy, 0.0, 1.0);
|
||||
out.position = pos;
|
||||
out.vGradCoord = uTransformGrad * vec4f(in.position.xy, 0.0, 1.0);
|
||||
out.vScrCoord = vec2f(0.5 + pos.x * 0.5, 0.5 - pos.y * 0.5);
|
||||
return out;
|
||||
}
|
||||
|
||||
struct FragData { Sc: vec3f, Sa: f32, So: f32, Dc: vec3f, Da: f32 };
|
||||
fn getFragData(in: VertexOutput) -> FragData {
|
||||
// get source data
|
||||
let t: f32 = distance(uSettingGrad.zw, in.vGradCoord.xy) / uSettingGrad.r;
|
||||
let colorSrc = textureSample(uTextureGrad, uSamplerGrad, vec2f(t, 0.5));
|
||||
let colorDst = textureSample(uTextureDst, uSamplerDst, in.vScrCoord.xy);
|
||||
// fill fragment data
|
||||
var data: FragData;
|
||||
data.Sc = colorSrc.rgb;
|
||||
data.Sa = colorSrc.a;
|
||||
data.So = uBlendSettings.a;
|
||||
data.Dc = colorDst.rgb;
|
||||
data.Da = colorDst.a;
|
||||
data.Sc = mix(data.Dc, data.Sc, data.Sa * data.So);
|
||||
data.Sa = mix(data.Da, 1.0, data.Sa * data.So);
|
||||
return data;
|
||||
};
|
||||
|
||||
fn postProcess(d: FragData, R: vec4f) -> vec4f { return R; };
|
||||
)";
|
||||
|
||||
const char* cShaderSrc_Image_Blend = R"(
|
||||
struct VertexInput { @location(0) position: vec2f, @location(1) texCoord: vec2f };
|
||||
struct VertexOutput { @builtin(position) position: vec4f, @location(0) vTexCoord : vec2f, @location(1) vScrCoord: vec2f };
|
||||
|
||||
@group(0) @binding(0) var<uniform> uViewMat : mat4x4f;
|
||||
@group(1) @binding(0) var<uniform> uModelMat : mat4x4f;
|
||||
@group(1) @binding(1) var<uniform> uBlendSettings : vec4f;
|
||||
@group(2) @binding(0) var uSamplerSrc : sampler;
|
||||
@group(2) @binding(1) var uTextureSrc : texture_2d<f32>;
|
||||
@group(3) @binding(0) var uSamplerDst : sampler;
|
||||
@group(3) @binding(1) var uTextureDst : texture_2d<f32>;
|
||||
|
||||
@vertex
|
||||
fn vs_main(in: VertexInput) -> VertexOutput {
|
||||
var out: VertexOutput;
|
||||
let pos = uViewMat * uModelMat * vec4f(in.position.xy, 0.0, 1.0);
|
||||
out.position = pos;
|
||||
out.vTexCoord = in.texCoord;
|
||||
out.vScrCoord = vec2f(0.5 + pos.x * 0.5, 0.5 - pos.y * 0.5);
|
||||
return out;
|
||||
}
|
||||
|
||||
struct FragData { Sc: vec3f, Sa: f32, So: f32, Dc: vec3f, Da: f32 };
|
||||
fn getFragData(in: VertexOutput) -> FragData {
|
||||
// get source data
|
||||
let colorSrc = textureSample(uTextureSrc, uSamplerSrc, in.vTexCoord.xy);
|
||||
let colorDst = textureSample(uTextureDst, uSamplerDst, in.vScrCoord.xy);
|
||||
// fill fragment data
|
||||
var data: FragData;
|
||||
data.Sc = colorSrc.rgb;
|
||||
data.Sa = colorSrc.a;
|
||||
data.So = uBlendSettings.a;
|
||||
data.Dc = colorDst.rgb;
|
||||
data.Da = colorDst.a;
|
||||
switch u32(uBlendSettings.r) {
|
||||
case 0u: { data.Sc = data.Sc.rgb; }
|
||||
case 1u: { data.Sc = data.Sc.bgr; }
|
||||
case 2u: { data.Sc = data.Sc.rgb; }
|
||||
case 3u: { data.Sc = data.Sc.bgr; }
|
||||
default: {}
|
||||
}
|
||||
data.Sc = data.Sc * data.So;
|
||||
data.Sa = data.Sa * data.So;
|
||||
return data;
|
||||
};
|
||||
|
||||
fn postProcess(d: FragData, R: vec4f) -> vec4f { return mix(vec4(d.Dc, d.Da), R, d.Sa); };
|
||||
)";
|
||||
|
||||
const char* cShaderSrc_Scene_Blend = R"(
|
||||
struct VertexInput { @location(0) position: vec2f, @location(1) texCoord: vec2f };
|
||||
struct VertexOutput { @builtin(position) position: vec4f, @location(0) vScrCoord: vec2f };
|
||||
|
||||
@group(0) @binding(0) var uSamplerSrc : sampler;
|
||||
@group(0) @binding(1) var uTextureSrc : texture_2d<f32>;
|
||||
@group(1) @binding(0) var uSamplerDst : sampler;
|
||||
@group(1) @binding(1) var uTextureDst : texture_2d<f32>;
|
||||
@group(2) @binding(0) var<uniform> So : f32;
|
||||
|
||||
@vertex
|
||||
fn vs_main(in: VertexInput) -> VertexOutput {
|
||||
var out: VertexOutput;
|
||||
out.position = vec4f(in.position.xy, 0.0, 1.0);
|
||||
out.vScrCoord = in.texCoord;
|
||||
return out;
|
||||
}
|
||||
|
||||
struct FragData { Sc: vec3f, Sa: f32, So: f32, Dc: vec3f, Da: f32 };
|
||||
fn getFragData(in: VertexOutput) -> FragData {
|
||||
// get source data
|
||||
let colorSrc = textureSample(uTextureSrc, uSamplerSrc, in.vScrCoord.xy);
|
||||
let colorDst = textureSample(uTextureDst, uSamplerDst, in.vScrCoord.xy);
|
||||
// fill fragment data
|
||||
var data: FragData;
|
||||
data.Sc = colorSrc.rgb;
|
||||
data.Sa = colorSrc.a;
|
||||
data.Dc = colorDst.rgb;
|
||||
data.Da = colorDst.a;
|
||||
return data;
|
||||
};
|
||||
|
||||
fn postProcess(d: FragData, R: vec4f) -> vec4f { return mix(vec4(d.Dc, d.Da), R, d.Sa * So); };
|
||||
)";
|
||||
|
||||
const char* cShaderSrc_BlendFuncs = R"(
|
||||
@fragment
|
||||
fn fs_main_Normal(in: VertexOutput) -> @location(0) vec4f {
|
||||
// used as debug blend method
|
||||
return vec4f(1.0, 0.0, 0.0, 1.0);
|
||||
}
|
||||
|
||||
@fragment
|
||||
fn fs_main_Multiply(in: VertexOutput) -> @location(0) vec4f {
|
||||
let d: FragData = getFragData(in);
|
||||
let Rc = d.Sc * d.Dc;
|
||||
return postProcess(d, vec4f(Rc, 1.0));
|
||||
}
|
||||
|
||||
@fragment
|
||||
fn fs_main_Screen(in: VertexOutput) -> @location(0) vec4f {
|
||||
let d: FragData = getFragData(in);
|
||||
let Rc = d.Sc + d.Dc - d.Sc * d.Dc;
|
||||
return postProcess(d, vec4f(Rc, 1.0));
|
||||
}
|
||||
|
||||
@fragment
|
||||
fn fs_main_Overlay(in: VertexOutput) -> @location(0) vec4f {
|
||||
let d: FragData = getFragData(in);
|
||||
var Rc: vec3f;
|
||||
Rc.r = select(1.0 - min(1.0, 2 * (1 - d.Sc.r) * (1 - d.Dc.r)), min(1.0, 2 * d.Sc.r * d.Dc.r), (d.Dc.r < 0.5));
|
||||
Rc.g = select(1.0 - min(1.0, 2 * (1 - d.Sc.g) * (1 - d.Dc.g)), min(1.0, 2 * d.Sc.g * d.Dc.g), (d.Dc.g < 0.5));
|
||||
Rc.b = select(1.0 - min(1.0, 2 * (1 - d.Sc.b) * (1 - d.Dc.b)), min(1.0, 2 * d.Sc.b * d.Dc.b), (d.Dc.b < 0.5));
|
||||
return postProcess(d, vec4f(Rc, 1.0));
|
||||
}
|
||||
|
||||
@fragment
|
||||
fn fs_main_Darken(in: VertexOutput) -> @location(0) vec4f {
|
||||
let d: FragData = getFragData(in);
|
||||
let Rc = min(d.Sc, d.Dc);
|
||||
return postProcess(d, vec4f(Rc, 1.0));
|
||||
|
||||
}
|
||||
|
||||
@fragment
|
||||
fn fs_main_Lighten(in: VertexOutput) -> @location(0) vec4f {
|
||||
let d: FragData = getFragData(in);
|
||||
let Rc = max(d.Sc, d.Dc);
|
||||
return postProcess(d, vec4f(Rc, 1.0));
|
||||
}
|
||||
|
||||
@fragment
|
||||
fn fs_main_ColorDodge(in: VertexOutput) -> @location(0) vec4f {
|
||||
let d: FragData = getFragData(in);
|
||||
var Rc: vec3f;
|
||||
Rc.r = select(d.Dc.r, (d.Dc.r * 255.0 / (255.0 - d.Sc.r * 255.0))/255.0, (1.0 - d.Sc.r > 0.0));
|
||||
Rc.g = select(d.Dc.g, (d.Dc.g * 255.0 / (255.0 - d.Sc.g * 255.0))/255.0, (1.0 - d.Sc.g > 0.0));
|
||||
Rc.b = select(d.Dc.b, (d.Dc.b * 255.0 / (255.0 - d.Sc.b * 255.0))/255.0, (1.0 - d.Sc.b > 0.0));
|
||||
return postProcess(d, vec4f(Rc, 1.0));
|
||||
}
|
||||
|
||||
@fragment
|
||||
fn fs_main_ColorBurn(in: VertexOutput) -> @location(0) vec4f {
|
||||
let d: FragData = getFragData(in);
|
||||
var Rc: vec3f;
|
||||
Rc.r = select(1.0 - d.Dc.r, (255.0 - (255.0 - d.Dc.r * 255.0) / (d.Sc.r * 255.0)) / 255.0, (d.Sc.r > 0.0));
|
||||
Rc.g = select(1.0 - d.Dc.g, (255.0 - (255.0 - d.Dc.g * 255.0) / (d.Sc.g * 255.0)) / 255.0, (d.Sc.g > 0.0));
|
||||
Rc.b = select(1.0 - d.Dc.b, (255.0 - (255.0 - d.Dc.b * 255.0) / (d.Sc.b * 255.0)) / 255.0, (d.Sc.b > 0.0));
|
||||
return postProcess(d, vec4f(Rc, 1.0));
|
||||
}
|
||||
|
||||
@fragment
|
||||
fn fs_main_HardLight(in: VertexOutput) -> @location(0) vec4f {
|
||||
let d: FragData = getFragData(in);
|
||||
var Rc: vec3f;
|
||||
Rc.r = select(1.0 - min(1.0, 2 * (1 - d.Sc.r) * (1 - d.Dc.r)), min(1.0, 2 * d.Sc.r * d.Dc.r), (d.Sc.r < 0.5));
|
||||
Rc.g = select(1.0 - min(1.0, 2 * (1 - d.Sc.g) * (1 - d.Dc.g)), min(1.0, 2 * d.Sc.g * d.Dc.g), (d.Sc.g < 0.5));
|
||||
Rc.b = select(1.0 - min(1.0, 2 * (1 - d.Sc.b) * (1 - d.Dc.b)), min(1.0, 2 * d.Sc.b * d.Dc.b), (d.Sc.b < 0.5));
|
||||
return postProcess(d, vec4f(Rc, 1.0));
|
||||
}
|
||||
|
||||
@fragment
|
||||
fn fs_main_SoftLight(in: VertexOutput) -> @location(0) vec4f {
|
||||
let d: FragData = getFragData(in);
|
||||
let One = vec3f(1.0, 1.0, 1.0);
|
||||
let Rc = min(One, (One - 2 * d.Sc) * d.Dc * d.Dc + 2.0 * d.Sc * d.Dc);
|
||||
return postProcess(d, vec4f(Rc, 1.0));
|
||||
}
|
||||
|
||||
@fragment
|
||||
fn fs_main_Difference(in: VertexOutput) -> @location(0) vec4f {
|
||||
let d: FragData = getFragData(in);
|
||||
let One = vec3f(1.0, 1.0, 1.0);
|
||||
let Rc = abs(d.Dc - d.Sc);
|
||||
return postProcess(d, vec4f(Rc, 1.0));
|
||||
}
|
||||
|
||||
@fragment
|
||||
fn fs_main_Exclusion(in: VertexOutput) -> @location(0) vec4f {
|
||||
let d: FragData = getFragData(in);
|
||||
let One = vec3f(1.0, 1.0, 1.0);
|
||||
let Rc = d.Sc + d.Dc - 2 * d.Sc * d.Dc;
|
||||
return postProcess(d, vec4f(Rc, 1.0));
|
||||
}
|
||||
|
||||
@fragment
|
||||
fn fs_main_Add(in: VertexOutput) -> @location(0) vec4f {
|
||||
let d: FragData = getFragData(in);
|
||||
let Rc = d.Sc + d.Dc;
|
||||
return postProcess(d, vec4f(Rc, 1.0));
|
||||
}
|
||||
)";
|
||||
|
||||
//************************************************************************
|
||||
// graphics shader source: scene compose
|
||||
//************************************************************************
|
||||
|
||||
const char* cShaderSrc_Scene_Comp = R"(
|
||||
const char* cShaderSrc_Scene_Compose = R"(
|
||||
struct VertexInput { @location(0) position: vec2f, @location(1) texCoord: vec2f };
|
||||
struct VertexOutput { @builtin(position) position: vec4f, @location(0) texCoord: vec2f };
|
||||
|
||||
|
@ -293,33 +649,6 @@ fn fs_main_DarkenMask(in: VertexOutput) -> @location(0) vec4f {
|
|||
};
|
||||
)";
|
||||
|
||||
|
||||
//************************************************************************
|
||||
// graphics shader source: scene blend
|
||||
//************************************************************************
|
||||
|
||||
const char* cShaderSrc_Scene_Blend = R"(
|
||||
struct VertexInput { @location(0) position: vec2f, @location(1) texCoord: vec2f };
|
||||
struct VertexOutput { @builtin(position) position: vec4f, @location(0) texCoord: vec2f };
|
||||
|
||||
@group(0) @binding(0) var uSamplerSrc : sampler;
|
||||
@group(0) @binding(1) var uTextureSrc : texture_2d<f32>;
|
||||
@group(1) @binding(0) var<uniform> So : f32;
|
||||
|
||||
@vertex
|
||||
fn vs_main(in: VertexInput) -> VertexOutput {
|
||||
var out: VertexOutput;
|
||||
out.position = vec4f(in.position.xy, 0.0, 1.0);
|
||||
out.texCoord = in.texCoord;
|
||||
return out;
|
||||
}
|
||||
|
||||
@fragment
|
||||
fn fs_main(in: VertexOutput) -> @location(0) vec4f {
|
||||
return textureSample(uTextureSrc, uSamplerSrc, in.texCoord.xy) * So;
|
||||
};
|
||||
)";
|
||||
|
||||
//************************************************************************
|
||||
// graphics shader source: texture blit
|
||||
//************************************************************************
|
||||
|
@ -360,206 +689,4 @@ fn cs_main(@builtin(global_invocation_id) id: vec3u) {
|
|||
let colorMsk1 = textureLoad(imageMsk1, id.xy);
|
||||
textureStore(imageTrg, id.xy, colorMsk0 * colorMsk1);
|
||||
}
|
||||
)";
|
||||
|
||||
//************************************************************************
|
||||
// compute shader source: blend
|
||||
//************************************************************************
|
||||
|
||||
const char* cShaderSrc_BlendHeader_Solid = R"(
|
||||
@group(0) @binding(0) var imageSrc : texture_storage_2d<rgba8unorm, read>;
|
||||
@group(1) @binding(0) var imageDst : texture_storage_2d<rgba8unorm, read>;
|
||||
@group(2) @binding(0) var imageTgt : texture_storage_2d<rgba8unorm, write>;
|
||||
@group(3) @binding(0) var<uniform> So : f32;
|
||||
|
||||
struct FragData { Sc: vec3f, Sa: f32, Dc: vec3f, Da: f32, skip: bool };
|
||||
fn getFragData(id: vec2u) -> FragData {
|
||||
var data: FragData;
|
||||
data.skip = true;
|
||||
let colorSrc = textureLoad(imageSrc, id.xy);
|
||||
if (colorSrc.a == 0.0) { return data; }
|
||||
let colorDst = textureLoad(imageDst, id.xy);
|
||||
data.Sc = colorSrc.rgb;
|
||||
data.Sa = colorSrc.a;
|
||||
data.Dc = colorDst.rgb;
|
||||
data.Da = colorDst.a;
|
||||
data.skip = false;
|
||||
return data;
|
||||
};
|
||||
|
||||
fn postProcess(d: FragData, R: vec4f) -> vec4f { return R; };
|
||||
)";
|
||||
|
||||
|
||||
const char* cShaderSrc_BlendHeader_Gradient = R"(
|
||||
@group(0) @binding(0) var imageSrc : texture_storage_2d<rgba8unorm, read>;
|
||||
@group(1) @binding(0) var imageDst : texture_storage_2d<rgba8unorm, read>;
|
||||
@group(2) @binding(0) var imageTgt : texture_storage_2d<rgba8unorm, write>;
|
||||
@group(3) @binding(0) var<uniform> So : f32;
|
||||
|
||||
struct FragData { Sc: vec3f, Sa: f32, Dc: vec3f, Da: f32, skip: bool };
|
||||
fn getFragData(id: vec2u) -> FragData {
|
||||
var data: FragData;
|
||||
data.skip = true;
|
||||
let colorSrc = textureLoad(imageSrc, id.xy);
|
||||
if (colorSrc.a == 0.0) { return data; }
|
||||
let colorDst = textureLoad(imageDst, id.xy);
|
||||
data.Sc = colorSrc.rgb;
|
||||
data.Sa = colorSrc.a;
|
||||
data.Dc = colorDst.rgb;
|
||||
data.Da = colorDst.a;
|
||||
data.skip = false;
|
||||
data.Sc = data.Sc + data.Dc * (1.0 - data.Sa);
|
||||
data.Sa = data.Sa + data.Da * (1.0 - data.Sa);
|
||||
return data;
|
||||
};
|
||||
|
||||
fn postProcess(d: FragData, R: vec4f) -> vec4f { return R; };
|
||||
)";
|
||||
|
||||
const char* cShaderSrc_BlendHeader_Image = R"(
|
||||
@group(0) @binding(0) var imageSrc : texture_storage_2d<rgba8unorm, read>;
|
||||
@group(1) @binding(0) var imageDst : texture_storage_2d<rgba8unorm, read>;
|
||||
@group(2) @binding(0) var imageTgt : texture_storage_2d<rgba8unorm, write>;
|
||||
@group(3) @binding(0) var<uniform> So : f32;
|
||||
|
||||
struct FragData { Sc: vec3f, Sa: f32, Dc: vec3f, Da: f32, skip: bool };
|
||||
fn getFragData(id: vec2u) -> FragData {
|
||||
var data: FragData;
|
||||
data.skip = true;
|
||||
let colorSrc = textureLoad(imageSrc, id.xy);
|
||||
if (colorSrc.a == 0.0) { return data; }
|
||||
let colorDst = textureLoad(imageDst, id.xy);
|
||||
data.Sc = colorSrc.rgb;
|
||||
data.Sa = colorSrc.a;
|
||||
data.Dc = colorDst.rgb;
|
||||
data.Da = colorDst.a;
|
||||
data.skip = false;
|
||||
return data;
|
||||
};
|
||||
|
||||
fn postProcess(d: FragData, R: vec4f) -> vec4f {
|
||||
return mix(vec4(d.Dc, d.Da), R, d.Sa * So);
|
||||
};
|
||||
)";
|
||||
|
||||
const char* cShaderSrc_Blend_Funcs = R"(
|
||||
@compute @workgroup_size(8, 8)
|
||||
fn cs_main_Normal(@builtin(global_invocation_id) id: vec3u) {
|
||||
let d: FragData = getFragData(id.xy);
|
||||
if (d.skip) { return; }
|
||||
let Rc = d.Sc + d.Dc * (1.0 - d.Sa);
|
||||
let Ra = d.Sa + d.Da * (1.0 - d.Sa);
|
||||
textureStore(imageTgt, id.xy, vec4f(Rc, Ra));
|
||||
};
|
||||
|
||||
@compute @workgroup_size(8, 8)
|
||||
fn cs_main_Add(@builtin(global_invocation_id) id: vec3u) {
|
||||
let d: FragData = getFragData(id.xy);
|
||||
if (d.skip) { return; }
|
||||
let Rc = d.Sc + d.Dc;
|
||||
textureStore(imageTgt, id.xy, postProcess(d, vec4f(Rc, 1.0)));
|
||||
};
|
||||
|
||||
@compute @workgroup_size(8, 8)
|
||||
fn cs_main_Screen(@builtin(global_invocation_id) id: vec3u) {
|
||||
let d: FragData = getFragData(id.xy);
|
||||
if (d.skip) { return; }
|
||||
let Rc = d.Sc + d.Dc - d.Sc * d.Dc;
|
||||
textureStore(imageTgt, id.xy, postProcess(d, vec4f(Rc, 1.0)));
|
||||
};
|
||||
|
||||
@compute @workgroup_size(8, 8)
|
||||
fn cs_main_Multiply(@builtin(global_invocation_id) id: vec3u) {
|
||||
let d: FragData = getFragData(id.xy);
|
||||
if (d.skip) { return; }
|
||||
let Rc = d.Sc * d.Dc;
|
||||
textureStore(imageTgt, id.xy, postProcess(d, vec4f(Rc, 1.0)));
|
||||
};
|
||||
|
||||
@compute @workgroup_size(8, 8)
|
||||
fn cs_main_Overlay(@builtin(global_invocation_id) id: vec3u) {
|
||||
let d: FragData = getFragData(id.xy);
|
||||
if (d.skip) { return; }
|
||||
var Rc: vec3f;
|
||||
Rc.r = select(1.0 - min(1.0, 2 * (1 - d.Sc.r) * (1 - d.Dc.r)), min(1.0, 2 * d.Sc.r * d.Dc.r), (d.Dc.r < 0.5));
|
||||
Rc.g = select(1.0 - min(1.0, 2 * (1 - d.Sc.g) * (1 - d.Dc.g)), min(1.0, 2 * d.Sc.g * d.Dc.g), (d.Dc.g < 0.5));
|
||||
Rc.b = select(1.0 - min(1.0, 2 * (1 - d.Sc.b) * (1 - d.Dc.b)), min(1.0, 2 * d.Sc.b * d.Dc.b), (d.Dc.b < 0.5));
|
||||
textureStore(imageTgt, id.xy, postProcess(d, vec4f(Rc, 1.0)));
|
||||
};
|
||||
|
||||
@compute @workgroup_size(8, 8)
|
||||
fn cs_main_Difference(@builtin(global_invocation_id) id: vec3u) {
|
||||
let d: FragData = getFragData(id.xy);
|
||||
if (d.skip) { return; }
|
||||
let Rc = abs(d.Dc - d.Sc);
|
||||
textureStore(imageTgt, id.xy, postProcess(d, vec4f(Rc, 1.0)));
|
||||
};
|
||||
|
||||
@compute @workgroup_size(8, 8)
|
||||
fn cs_main_Exclusion(@builtin(global_invocation_id) id: vec3u) {
|
||||
let d: FragData = getFragData(id.xy);
|
||||
if (d.skip) { return; }
|
||||
let One = vec3f(1.0, 1.0, 1.0);
|
||||
let Rc = min(One, d.Sc + d.Dc - min(One, 2 * d.Sc * d.Dc));
|
||||
textureStore(imageTgt, id.xy, postProcess(d, vec4f(Rc, 1.0)));
|
||||
};
|
||||
|
||||
@compute @workgroup_size(8, 8)
|
||||
fn cs_main_Darken(@builtin(global_invocation_id) id: vec3u) {
|
||||
let d: FragData = getFragData(id.xy);
|
||||
if (d.skip) { return; }
|
||||
let Rc = min(d.Sc, d.Dc);
|
||||
textureStore(imageTgt, id.xy, postProcess(d, vec4f(Rc, 1.0)));
|
||||
};
|
||||
|
||||
@compute @workgroup_size(8, 8)
|
||||
fn cs_main_Lighten(@builtin(global_invocation_id) id: vec3u) {
|
||||
let d: FragData = getFragData(id.xy);
|
||||
if (d.skip) { return; }
|
||||
let Rc = max(d.Sc, d.Dc);
|
||||
textureStore(imageTgt, id.xy, postProcess(d, vec4f(Rc, 1.0)));
|
||||
};
|
||||
|
||||
@compute @workgroup_size(8, 8)
|
||||
fn cs_main_ColorDodge(@builtin(global_invocation_id) id: vec3u) {
|
||||
let d: FragData = getFragData(id.xy);
|
||||
if (d.skip) { return; }
|
||||
var Rc: vec3f;
|
||||
Rc.r = select(d.Dc.r, (d.Dc.r * 255.0 / (255.0 - d.Sc.r * 255.0))/255.0, (1.0 - d.Sc.r > 0.0));
|
||||
Rc.g = select(d.Dc.g, (d.Dc.g * 255.0 / (255.0 - d.Sc.g * 255.0))/255.0, (1.0 - d.Sc.g > 0.0));
|
||||
Rc.b = select(d.Dc.b, (d.Dc.b * 255.0 / (255.0 - d.Sc.b * 255.0))/255.0, (1.0 - d.Sc.b > 0.0));
|
||||
textureStore(imageTgt, id.xy, postProcess(d, vec4f(Rc, 1.0)));
|
||||
};
|
||||
|
||||
@compute @workgroup_size(8, 8)
|
||||
fn cs_main_ColorBurn(@builtin(global_invocation_id) id: vec3u) {
|
||||
let d: FragData = getFragData(id.xy);
|
||||
if (d.skip) { return; }
|
||||
var Rc: vec3f;
|
||||
Rc.r = select(1.0 - d.Dc.r, (255.0 - (255.0 - d.Dc.r * 255.0) / (d.Sc.r * 255.0)) / 255.0, (d.Sc.r > 0.0));
|
||||
Rc.g = select(1.0 - d.Dc.g, (255.0 - (255.0 - d.Dc.g * 255.0) / (d.Sc.g * 255.0)) / 255.0, (d.Sc.g > 0.0));
|
||||
Rc.b = select(1.0 - d.Dc.b, (255.0 - (255.0 - d.Dc.b * 255.0) / (d.Sc.b * 255.0)) / 255.0, (d.Sc.b > 0.0));
|
||||
textureStore(imageTgt, id.xy, postProcess(d, vec4f(Rc, 1.0)));
|
||||
};
|
||||
|
||||
@compute @workgroup_size(8, 8)
|
||||
fn cs_main_HardLight(@builtin(global_invocation_id) id: vec3u) {
|
||||
let d: FragData = getFragData(id.xy);
|
||||
if (d.skip) { return; }
|
||||
var Rc: vec3f;
|
||||
Rc.r = select(1.0 - min(1.0, 2 * (1 - d.Sc.r) * (1 - d.Dc.r)), min(1.0, 2 * d.Sc.r * d.Dc.r), (d.Sc.r < 0.5));
|
||||
Rc.g = select(1.0 - min(1.0, 2 * (1 - d.Sc.g) * (1 - d.Dc.g)), min(1.0, 2 * d.Sc.g * d.Dc.g), (d.Sc.g < 0.5));
|
||||
Rc.b = select(1.0 - min(1.0, 2 * (1 - d.Sc.b) * (1 - d.Dc.b)), min(1.0, 2 * d.Sc.b * d.Dc.b), (d.Sc.b < 0.5));
|
||||
textureStore(imageTgt, id.xy, postProcess(d, vec4f(Rc, 1.0)));
|
||||
};
|
||||
|
||||
@compute @workgroup_size(8, 8)
|
||||
fn cs_main_SoftLight(@builtin(global_invocation_id) id: vec3u) {
|
||||
let d: FragData = getFragData(id.xy);
|
||||
if (d.skip) { return; }
|
||||
let One = vec3f(1.0, 1.0, 1.0);
|
||||
let Rc = min(One, (One - 2 * d.Sc) * d.Dc * d.Dc + 2.0 * d.Sc * d.Dc);
|
||||
textureStore(imageTgt, id.xy, postProcess(d, vec4f(Rc, 1.0)));
|
||||
};
|
||||
)";
|
||||
)";
|
|
@ -23,21 +23,27 @@
|
|||
#ifndef _TVG_WG_SHADER_SRC_H_
|
||||
#define _TVG_WG_SHADER_SRC_H_
|
||||
|
||||
// graphics shader sources
|
||||
// helper shaders
|
||||
extern const char* cShaderSrc_Stencil;
|
||||
// shaders normal blend
|
||||
extern const char* cShaderSrc_Solid;
|
||||
extern const char* cShaderSrc_Linear;
|
||||
extern const char* cShaderSrc_Radial;
|
||||
extern const char* cShaderSrc_Image;
|
||||
extern const char* cShaderSrc_Scene_Comp;
|
||||
extern const char* cShaderSrc_Scene;
|
||||
// shaders custrom blend
|
||||
extern const char* cShaderSrc_Solid_Blend;
|
||||
extern const char* cShaderSrc_Linear_Blend;
|
||||
extern const char* cShaderSrc_Radial_Blend;
|
||||
extern const char* cShaderSrc_Image_Blend;
|
||||
extern const char* cShaderSrc_Scene_Blend;
|
||||
extern const char* cShaderSrc_BlendFuncs;
|
||||
// shaders scene compose
|
||||
extern const char* cShaderSrc_Scene_Compose;
|
||||
// shaders blit
|
||||
extern const char* cShaderSrc_Blit;
|
||||
|
||||
// compute shader sources: blend, compose and merge path
|
||||
extern const char* cShaderSrc_MergeMasks;
|
||||
extern const char* cShaderSrc_BlendHeader_Solid;
|
||||
extern const char* cShaderSrc_BlendHeader_Gradient;
|
||||
extern const char* cShaderSrc_BlendHeader_Image;
|
||||
extern const char* cShaderSrc_Blend_Funcs;
|
||||
|
||||
#endif // _TVG_WG_SHEDER_SRC_H_
|
||||
|
|
Loading…
Add table
Reference in a new issue