mirror of
https://github.com/thorvg/thorvg.git
synced 2025-06-08 13:43:43 +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)
|
RenderRegion WgCompositor::shrinkRenderRegion(RenderRegion& rect)
|
||||||
{
|
{
|
||||||
// cut viewport to screen dimensions
|
// 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)
|
void WgCompositor::renderClipPath(WgContext& context, WgRenderDataPaint* renderData, WgRenderStorage* dst)
|
||||||
{
|
{
|
||||||
assert(renderData);
|
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)
|
void WgCompositor::mergeMasks(WGPUCommandEncoder encoder, WgRenderStorage* mask0, WgRenderStorage* mask1)
|
||||||
{
|
{
|
||||||
assert(mask0);
|
assert(mask0);
|
||||||
|
@ -510,49 +617,7 @@ void WgCompositor::mergeMasks(WGPUCommandEncoder encoder, WgRenderStorage* mask0
|
||||||
wgpuComputePassEncoderSetBindGroup(computePassEncoder, 0, mask0->bindGroupRead, 0, nullptr);
|
wgpuComputePassEncoderSetBindGroup(computePassEncoder, 0, mask0->bindGroupRead, 0, nullptr);
|
||||||
wgpuComputePassEncoderSetBindGroup(computePassEncoder, 1, storageDstCopy.bindGroupRead, 0, nullptr);
|
wgpuComputePassEncoderSetBindGroup(computePassEncoder, 1, storageDstCopy.bindGroupRead, 0, nullptr);
|
||||||
wgpuComputePassEncoderSetBindGroup(computePassEncoder, 2, mask1->bindGroupWrite, 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);
|
wgpuComputePassEncoderDispatchWorkgroups(computePassEncoder, (width + 7) / 8, (height + 7) / 8, 1);
|
||||||
wgpuComputePassEncoderEnd(computePassEncoder);
|
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;
|
WgRenderStorage storageDstCopy;
|
||||||
// composition and blend geometries
|
// composition and blend geometries
|
||||||
WgMeshData meshData;
|
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
|
// render target dimensions
|
||||||
uint32_t width{};
|
uint32_t width{};
|
||||||
uint32_t height{};
|
uint32_t height{};
|
||||||
|
|
||||||
|
// viewport utilities
|
||||||
|
RenderRegion shrinkRenderRegion(RenderRegion& rect);
|
||||||
public:
|
public:
|
||||||
void initialize(WgContext& context, uint32_t width, uint32_t height);
|
void initialize(WgContext& context, uint32_t width, uint32_t height);
|
||||||
void release(WgContext& context);
|
void release(WgContext& context);
|
||||||
|
|
||||||
|
// render passes workflow
|
||||||
void beginRenderPass(WGPUCommandEncoder encoder, WgRenderStorage* target, bool clear);
|
void beginRenderPass(WGPUCommandEncoder encoder, WgRenderStorage* target, bool clear);
|
||||||
void endRenderPass();
|
void endRenderPass();
|
||||||
|
|
||||||
void renderClipPath(WgContext& context, WgRenderDataPaint* renderData, WgRenderStorage* dst);
|
// render shapes, images and scenes
|
||||||
|
|
||||||
void renderShape(WgContext& context, WgRenderDataShape* renderData, BlendMethod blendMethod);
|
void renderShape(WgContext& context, WgRenderDataShape* renderData, BlendMethod blendMethod);
|
||||||
void renderImage(WgContext& context, WgRenderDataPicture* 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);
|
// blit render storage to texture view (f.e. screen buffer)
|
||||||
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);
|
|
||||||
void blit(WgContext& context, WGPUCommandEncoder encoder, WgRenderStorage* src, WGPUTextureView dstView);
|
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_
|
#endif // _TVG_WG_COMPOSITOR_H_
|
||||||
|
|
|
@ -158,81 +158,68 @@ void WgPipelines::initialize(WgContext& context)
|
||||||
.color = { .operation = WGPUBlendOperation_Add, .srcFactor = WGPUBlendFactor_One, .dstFactor = WGPUBlendFactor_OneMinusSrcAlpha },
|
.color = { .operation = WGPUBlendOperation_Add, .srcFactor = WGPUBlendFactor_One, .dstFactor = WGPUBlendFactor_OneMinusSrcAlpha },
|
||||||
.alpha = { .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
|
// bind group layouts helpers
|
||||||
const WGPUBindGroupLayout bindGroupLayoutsStencil[] = {
|
const WGPUBindGroupLayout bindGroupLayoutsStencil[] = { layouts.layoutBuffer1Un, layouts.layoutBuffer2Un };
|
||||||
layouts.layoutBuffer1Un,
|
// bind group layouts normal blend
|
||||||
layouts.layoutBuffer2Un
|
const WGPUBindGroupLayout bindGroupLayoutsSolid[] { layouts.layoutBuffer1Un, layouts.layoutBuffer2Un, layouts.layoutBuffer1Un };
|
||||||
};
|
const WGPUBindGroupLayout bindGroupLayoutsGradient[] { layouts.layoutBuffer1Un, layouts.layoutBuffer2Un, layouts.layoutTexSampledBuff2Un };
|
||||||
const WGPUBindGroupLayout bindGroupLayoutsSolid[] = {
|
const WGPUBindGroupLayout bindGroupLayoutsImage[] { layouts.layoutBuffer1Un, layouts.layoutBuffer2Un, layouts.layoutTexSampled };
|
||||||
layouts.layoutBuffer1Un,
|
const WGPUBindGroupLayout bindGroupLayoutsScene[] { layouts.layoutTexSampled, layouts.layoutBuffer1Un };
|
||||||
layouts.layoutBuffer2Un,
|
// bind group layouts custom blend
|
||||||
layouts.layoutBuffer1Un
|
const WGPUBindGroupLayout bindGroupLayoutsSolidBlend[] { layouts.layoutBuffer1Un, layouts.layoutBuffer2Un, layouts.layoutBuffer1Un, layouts.layoutTexSampled };
|
||||||
};
|
const WGPUBindGroupLayout bindGroupLayoutsGradientBlend[] { layouts.layoutBuffer1Un, layouts.layoutBuffer2Un, layouts.layoutTexSampledBuff2Un, layouts.layoutTexSampled };
|
||||||
const WGPUBindGroupLayout bindGroupLayoutsGradient[] = {
|
const WGPUBindGroupLayout bindGroupLayoutsImageBlend[] { layouts.layoutBuffer1Un, layouts.layoutBuffer2Un, layouts.layoutTexSampled, layouts.layoutTexSampled };
|
||||||
layouts.layoutBuffer1Un,
|
const WGPUBindGroupLayout bindGroupLayoutsSceneBlend[] { layouts.layoutTexSampled, layouts.layoutTexSampled, layouts.layoutBuffer1Un };
|
||||||
layouts.layoutBuffer2Un,
|
// bind group layouts scene compose
|
||||||
layouts.layoutTexSampledBuff2Un
|
const WGPUBindGroupLayout bindGroupLayoutsSceneCompose[] { layouts.layoutTexSampled, layouts.layoutTexSampled };
|
||||||
};
|
const WGPUBindGroupLayout bindGroupLayoutsMergeMasks[] { layouts.layoutTexStrorage1RO, layouts.layoutTexStrorage1RO, layouts.layoutTexStrorage1WO };
|
||||||
const WGPUBindGroupLayout bindGroupLayoutsImage[] = {
|
// bind group layouts blit
|
||||||
layouts.layoutBuffer1Un,
|
const WGPUBindGroupLayout bindGroupLayoutsBlit[] { layouts.layoutTexSampled };
|
||||||
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
|
|
||||||
};
|
|
||||||
|
|
||||||
// pipeline layouts
|
// shaders
|
||||||
layoutStencil = createPipelineLayout(context.device, bindGroupLayoutsStencil, 2);
|
char shaderSourceBuff[16384]{};
|
||||||
layoutSolid = createPipelineLayout(context.device, bindGroupLayoutsSolid, 3);
|
shader_stencil = createShaderModule(context.device, "The shader stencil", cShaderSrc_Stencil);
|
||||||
layoutGradient = createPipelineLayout(context.device, bindGroupLayoutsGradient, 3);
|
// shader normal blend
|
||||||
layoutImage = createPipelineLayout(context.device, bindGroupLayoutsImage, 3);
|
shader_solid = createShaderModule(context.device, "The shader solid", cShaderSrc_Solid);
|
||||||
layoutSceneComp = createPipelineLayout(context.device, bindGroupLayoutsSceneComp, 2);
|
shader_radial = createShaderModule(context.device, "The shader radial", cShaderSrc_Radial);
|
||||||
layoutSceneBlend = createPipelineLayout(context.device, bindGroupLayoutsSceneBlend, 2);
|
shader_linear = createShaderModule(context.device, "The shader linear", cShaderSrc_Linear);
|
||||||
layoutBlit = createPipelineLayout(context.device, bindGroupLayoutsBlit, 1);
|
shader_image = createShaderModule(context.device, "The shader image", cShaderSrc_Image);
|
||||||
layoutBlend = createPipelineLayout(context.device, bindGroupLayoutsBlend, 4);
|
shader_scene = createShaderModule(context.device, "The shader scene", cShaderSrc_Scene);
|
||||||
layoutMergeMasks = createPipelineLayout(context.device, bindGroupLayoutsMergeMasks, 3);
|
// 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
|
// layouts
|
||||||
shaderStencil = createShaderModule(context.device, "The shader stencil", cShaderSrc_Stencil);
|
layout_stencil = createPipelineLayout(context.device, bindGroupLayoutsStencil, 2);
|
||||||
shaderSolid = createShaderModule(context.device, "The shader solid", cShaderSrc_Solid);
|
// layouts normal blend
|
||||||
shaderRadial = createShaderModule(context.device, "The shader radial", cShaderSrc_Radial);
|
layout_solid = createPipelineLayout(context.device, bindGroupLayoutsSolid, 3);
|
||||||
shaderLinear = createShaderModule(context.device, "The shader linear", cShaderSrc_Linear);
|
layout_gradient = createPipelineLayout(context.device, bindGroupLayoutsGradient, 3);
|
||||||
shaderImage = createShaderModule(context.device, "The shader image", cShaderSrc_Image);
|
layout_image = createPipelineLayout(context.device, bindGroupLayoutsImage, 3);
|
||||||
shaderSceneComp = createShaderModule(context.device, "The shader scene composition", cShaderSrc_Scene_Comp);
|
layout_scene = createPipelineLayout(context.device, bindGroupLayoutsScene, 2);
|
||||||
shaderSceneBlend = createShaderModule(context.device, "The shader scene blend", cShaderSrc_Scene_Blend);
|
// layouts custom blend
|
||||||
shaderBlit = createShaderModule(context.device, "The shader blit", cShaderSrc_Blit);
|
layout_solid_blend = createPipelineLayout(context.device, bindGroupLayoutsSolidBlend, 4);
|
||||||
// computes shader modules
|
layout_gradient_blend = createPipelineLayout(context.device, bindGroupLayoutsGradientBlend, 4);
|
||||||
shaderMergeMasks = createShaderModule(context.device, "The shader merge mask", cShaderSrc_MergeMasks);
|
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
|
// render pipeline winding
|
||||||
winding = createRenderPipeline(
|
winding = createRenderPipeline(
|
||||||
context.device, "The render pipeline winding",
|
context.device, "The render pipeline winding",
|
||||||
shaderStencil, "vs_main", "fs_main", layoutStencil,
|
shader_stencil, "vs_main", "fs_main", layout_stencil,
|
||||||
vertexBufferLayoutsShape, 1,
|
vertexBufferLayoutsShape, 1,
|
||||||
WGPUColorWriteMask_None, offscreenTargetFormat,
|
WGPUColorWriteMask_None, offscreenTargetFormat,
|
||||||
WGPUCompareFunction_Always, WGPUStencilOperation_IncrementWrap,
|
WGPUCompareFunction_Always, WGPUStencilOperation_IncrementWrap,
|
||||||
|
@ -241,7 +228,7 @@ void WgPipelines::initialize(WgContext& context)
|
||||||
// render pipeline even-odd
|
// render pipeline even-odd
|
||||||
evenodd = createRenderPipeline(
|
evenodd = createRenderPipeline(
|
||||||
context.device, "The render pipeline even-odd",
|
context.device, "The render pipeline even-odd",
|
||||||
shaderStencil, "vs_main", "fs_main", layoutStencil,
|
shader_stencil, "vs_main", "fs_main", layout_stencil,
|
||||||
vertexBufferLayoutsShape, 1,
|
vertexBufferLayoutsShape, 1,
|
||||||
WGPUColorWriteMask_None, offscreenTargetFormat,
|
WGPUColorWriteMask_None, offscreenTargetFormat,
|
||||||
WGPUCompareFunction_Always, WGPUStencilOperation_Invert,
|
WGPUCompareFunction_Always, WGPUStencilOperation_Invert,
|
||||||
|
@ -250,16 +237,16 @@ void WgPipelines::initialize(WgContext& context)
|
||||||
// render pipeline direct
|
// render pipeline direct
|
||||||
direct = createRenderPipeline(
|
direct = createRenderPipeline(
|
||||||
context.device, "The render pipeline direct",
|
context.device, "The render pipeline direct",
|
||||||
shaderStencil,"vs_main", "fs_main", layoutStencil,
|
shader_stencil, "vs_main", "fs_main", layout_stencil,
|
||||||
vertexBufferLayoutsShape, 1,
|
vertexBufferLayoutsShape, 1,
|
||||||
WGPUColorWriteMask_None, offscreenTargetFormat,
|
WGPUColorWriteMask_None, offscreenTargetFormat,
|
||||||
WGPUCompareFunction_Always, WGPUStencilOperation_Replace,
|
WGPUCompareFunction_Always, WGPUStencilOperation_Replace,
|
||||||
WGPUCompareFunction_Always, WGPUStencilOperation_Replace,
|
WGPUCompareFunction_Always, WGPUStencilOperation_Replace,
|
||||||
primitiveState, multisampleState, blendStateSrc);
|
primitiveState, multisampleState, blendStateSrc);
|
||||||
// render pipeline clip path
|
// render pipeline clip path
|
||||||
clipPath = createRenderPipeline(
|
clip_path = createRenderPipeline(
|
||||||
context.device, "The render pipeline clip path",
|
context.device, "The render pipeline clip path",
|
||||||
shaderStencil, "vs_main", "fs_main", layoutStencil,
|
shader_stencil, "vs_main", "fs_main", layout_stencil,
|
||||||
vertexBufferLayoutsShape, 1,
|
vertexBufferLayoutsShape, 1,
|
||||||
WGPUColorWriteMask_All, offscreenTargetFormat,
|
WGPUColorWriteMask_All, offscreenTargetFormat,
|
||||||
WGPUCompareFunction_NotEqual, WGPUStencilOperation_Zero,
|
WGPUCompareFunction_NotEqual, WGPUStencilOperation_Zero,
|
||||||
|
@ -267,81 +254,116 @@ void WgPipelines::initialize(WgContext& context)
|
||||||
primitiveState, multisampleState, blendStateSrc);
|
primitiveState, multisampleState, blendStateSrc);
|
||||||
|
|
||||||
// render pipeline solid
|
// render pipeline solid
|
||||||
for (uint32_t i = 0; i < 2; i++) {
|
solid = createRenderPipeline(
|
||||||
solid[i] = createRenderPipeline(
|
|
||||||
context.device, "The render pipeline solid",
|
context.device, "The render pipeline solid",
|
||||||
shaderSolid, "vs_main", "fs_main", layoutSolid,
|
shader_solid, "vs_main", "fs_main", layout_solid,
|
||||||
vertexBufferLayoutsShape, 1,
|
vertexBufferLayoutsShape, 1,
|
||||||
WGPUColorWriteMask_All, offscreenTargetFormat,
|
WGPUColorWriteMask_All, offscreenTargetFormat,
|
||||||
WGPUCompareFunction_NotEqual, WGPUStencilOperation_Zero,
|
WGPUCompareFunction_NotEqual, WGPUStencilOperation_Zero,
|
||||||
WGPUCompareFunction_NotEqual, WGPUStencilOperation_Zero,
|
WGPUCompareFunction_NotEqual, WGPUStencilOperation_Zero,
|
||||||
primitiveState, multisampleState, blendStates[i]);
|
primitiveState, multisampleState, blendStateNrm);
|
||||||
}
|
|
||||||
|
|
||||||
// render pipeline radial
|
// render pipeline radial
|
||||||
for (uint32_t i = 0; i < 2; i++) {
|
radial = createRenderPipeline(
|
||||||
radial[i] = createRenderPipeline(
|
|
||||||
context.device, "The render pipeline radial",
|
context.device, "The render pipeline radial",
|
||||||
shaderRadial, "vs_main", "fs_main", layoutGradient,
|
shader_radial, "vs_main", "fs_main", layout_gradient,
|
||||||
vertexBufferLayoutsShape, 1,
|
vertexBufferLayoutsShape, 1,
|
||||||
WGPUColorWriteMask_All, offscreenTargetFormat,
|
WGPUColorWriteMask_All, offscreenTargetFormat,
|
||||||
WGPUCompareFunction_NotEqual, WGPUStencilOperation_Zero,
|
WGPUCompareFunction_NotEqual, WGPUStencilOperation_Zero,
|
||||||
WGPUCompareFunction_NotEqual, WGPUStencilOperation_Zero,
|
WGPUCompareFunction_NotEqual, WGPUStencilOperation_Zero,
|
||||||
primitiveState, multisampleState, blendStates[i]);
|
primitiveState, multisampleState, blendStateNrm);
|
||||||
}
|
|
||||||
|
|
||||||
// render pipeline linear
|
// render pipeline linear
|
||||||
for (uint32_t i = 0; i < 2; i++) {
|
linear = createRenderPipeline(
|
||||||
linear[i] = createRenderPipeline(
|
|
||||||
context.device, "The render pipeline linear",
|
context.device, "The render pipeline linear",
|
||||||
shaderLinear, "vs_main", "fs_main", layoutGradient,
|
shader_linear, "vs_main", "fs_main", layout_gradient,
|
||||||
vertexBufferLayoutsShape, 1,
|
vertexBufferLayoutsShape, 1,
|
||||||
WGPUColorWriteMask_All, offscreenTargetFormat,
|
WGPUColorWriteMask_All, offscreenTargetFormat,
|
||||||
WGPUCompareFunction_NotEqual, WGPUStencilOperation_Zero,
|
WGPUCompareFunction_NotEqual, WGPUStencilOperation_Zero,
|
||||||
WGPUCompareFunction_NotEqual, WGPUStencilOperation_Zero,
|
WGPUCompareFunction_NotEqual, WGPUStencilOperation_Zero,
|
||||||
primitiveState, multisampleState, blendStates[i]);
|
primitiveState, multisampleState, blendStateNrm);
|
||||||
}
|
|
||||||
|
|
||||||
// render pipeline image
|
// render pipeline image
|
||||||
for (uint32_t i = 0; i < 2; i++) {
|
image = createRenderPipeline(
|
||||||
image[i] = createRenderPipeline(
|
|
||||||
context.device, "The render pipeline image",
|
context.device, "The render pipeline image",
|
||||||
shaderImage, "vs_main", "fs_main", layoutImage,
|
shader_image, "vs_main", "fs_main", layout_image,
|
||||||
vertexBufferLayoutsImage, 2,
|
vertexBufferLayoutsImage, 2,
|
||||||
WGPUColorWriteMask_All, offscreenTargetFormat,
|
WGPUColorWriteMask_All, offscreenTargetFormat,
|
||||||
WGPUCompareFunction_Always, WGPUStencilOperation_Zero,
|
WGPUCompareFunction_Always, WGPUStencilOperation_Zero,
|
||||||
WGPUCompareFunction_Always, WGPUStencilOperation_Zero,
|
WGPUCompareFunction_Always, WGPUStencilOperation_Zero,
|
||||||
primitiveState, multisampleState, blendStates[i]);
|
primitiveState, multisampleState, blendStateNrm);
|
||||||
}
|
// render pipeline scene
|
||||||
|
scene = createRenderPipeline(
|
||||||
// render pipeline blit
|
context.device, "The render pipeline scene",
|
||||||
blit = createRenderPipeline(context.device, "The render pipeline blit",
|
shader_scene, "vs_main", "fs_main", layout_scene,
|
||||||
shaderBlit, "vs_main", "fs_main", layoutBlit,
|
|
||||||
vertexBufferLayoutsImage, 2,
|
vertexBufferLayoutsImage, 2,
|
||||||
// must be preferred screen pixel format
|
WGPUColorWriteMask_All, offscreenTargetFormat,
|
||||||
WGPUColorWriteMask_All, context.preferredFormat,
|
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,
|
||||||
WGPUCompareFunction_Always, WGPUStencilOperation_Zero,
|
WGPUCompareFunction_Always, WGPUStencilOperation_Zero,
|
||||||
primitiveState, multisampleState, blendStateSrc);
|
primitiveState, multisampleState, blendStateSrc);
|
||||||
|
// blend scene
|
||||||
// render pipeline blend
|
scene_blend[i] = createRenderPipeline(context.device, "The render pipeline scene blend",
|
||||||
sceneBlend = createRenderPipeline(context.device, "The render pipeline scene blend",
|
shader_scene_blend, "vs_main", shaderBlendNames[i], layout_scene_blend,
|
||||||
shaderSceneBlend, "vs_main", "fs_main", layoutSceneBlend,
|
|
||||||
vertexBufferLayoutsImage, 2,
|
vertexBufferLayoutsImage, 2,
|
||||||
WGPUColorWriteMask_All, offscreenTargetFormat,
|
WGPUColorWriteMask_All, offscreenTargetFormat,
|
||||||
WGPUCompareFunction_Always, WGPUStencilOperation_Zero,
|
WGPUCompareFunction_Always, WGPUStencilOperation_Zero,
|
||||||
WGPUCompareFunction_Always, WGPUStencilOperation_Zero,
|
WGPUCompareFunction_Always, WGPUStencilOperation_Zero,
|
||||||
primitiveState, multisampleState, blendStateNrm);
|
primitiveState, multisampleState, blendStateSrc);
|
||||||
|
}
|
||||||
// render pipeline scene clip path
|
|
||||||
sceneClip = createRenderPipeline(
|
|
||||||
context.device, "The render pipeline scene clip path",
|
|
||||||
shaderSceneComp, "vs_main", "fs_main_ClipPath", layoutSceneComp,
|
|
||||||
vertexBufferLayoutsImage, 2,
|
|
||||||
WGPUColorWriteMask_All, offscreenTargetFormat,
|
|
||||||
WGPUCompareFunction_Always, WGPUStencilOperation_Zero,
|
|
||||||
WGPUCompareFunction_Always, WGPUStencilOperation_Zero,
|
|
||||||
primitiveState, multisampleState, blendStateNrm);
|
|
||||||
|
|
||||||
// compose shader names
|
// compose shader names
|
||||||
const char* shaderComposeNames[] {
|
const char* shaderComposeNames[] {
|
||||||
|
@ -374,15 +396,10 @@ void WgPipelines::initialize(WgContext& context)
|
||||||
};
|
};
|
||||||
|
|
||||||
// render pipeline scene composition
|
// render pipeline scene composition
|
||||||
size_t shaderComposeNamesCnt = sizeof(shaderComposeNames) / sizeof(shaderComposeNames[0]);
|
for (uint32_t i = 0; i < 11; i++) {
|
||||||
size_t composeBlendspCnt = sizeof(composeBlends) / sizeof(composeBlends[0]);
|
scene_compose[i] = createRenderPipeline(
|
||||||
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(
|
|
||||||
context.device, "The render pipeline scene composition",
|
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,
|
vertexBufferLayoutsImage, 2,
|
||||||
WGPUColorWriteMask_All, offscreenTargetFormat,
|
WGPUColorWriteMask_All, offscreenTargetFormat,
|
||||||
WGPUCompareFunction_Always, WGPUStencilOperation_Zero,
|
WGPUCompareFunction_Always, WGPUStencilOperation_Zero,
|
||||||
|
@ -390,99 +407,95 @@ void WgPipelines::initialize(WgContext& context)
|
||||||
primitiveState, multisampleState, composeBlends[i]);
|
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
|
// 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
|
// render pipeline blit
|
||||||
const char* shaderBlendNames[] {
|
blit = createRenderPipeline(context.device, "The render pipeline blit",
|
||||||
"cs_main_Normal",
|
shader_blit, "vs_main", "fs_main", layout_blit,
|
||||||
"cs_main_Multiply",
|
vertexBufferLayoutsImage, 2,
|
||||||
"cs_main_Screen",
|
// must be preferred screen pixel format
|
||||||
"cs_main_Overlay",
|
WGPUColorWriteMask_All, context.preferredFormat,
|
||||||
"cs_main_Darken",
|
WGPUCompareFunction_Always, WGPUStencilOperation_Zero,
|
||||||
"cs_main_Lighten",
|
WGPUCompareFunction_Always, WGPUStencilOperation_Zero,
|
||||||
"cs_main_ColorDodge",
|
primitiveState, multisampleState, blendStateSrc);
|
||||||
"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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void WgPipelines::releaseGraphicHandles(WgContext& context)
|
void WgPipelines::releaseGraphicHandles(WgContext& context)
|
||||||
{
|
{
|
||||||
|
// pipeline blit
|
||||||
releaseRenderPipeline(blit);
|
releaseRenderPipeline(blit);
|
||||||
releaseRenderPipeline(clipPath);
|
// pipelines compose
|
||||||
releaseRenderPipeline(sceneBlend);
|
releaseRenderPipeline(scene_clip);
|
||||||
releaseRenderPipeline(sceneClip);
|
for (uint32_t i = 0; i < 11; i++)
|
||||||
size_t pipesSceneCompCnt = sizeof(sceneComp) / sizeof(sceneComp[0]);
|
releaseRenderPipeline(scene_compose[i]);
|
||||||
for (uint32_t i = 0; i < pipesSceneCompCnt; i++)
|
// pipelines custom blend
|
||||||
releaseRenderPipeline(sceneComp[i]);
|
for (uint32_t i = 0; i < 18; i++) {
|
||||||
for (uint32_t i = 0; i < 2; i++) {
|
releaseRenderPipeline(scene_blend[i]);
|
||||||
releaseRenderPipeline(image[i]);
|
releaseRenderPipeline(image_blend[i]);
|
||||||
releaseRenderPipeline(linear[i]);
|
releaseRenderPipeline(linear_blend[i]);
|
||||||
releaseRenderPipeline(radial[i]);
|
releaseRenderPipeline(radial_blend[i]);
|
||||||
releaseRenderPipeline(solid[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(direct);
|
||||||
releaseRenderPipeline(evenodd);
|
releaseRenderPipeline(evenodd);
|
||||||
releaseRenderPipeline(winding);
|
releaseRenderPipeline(winding);
|
||||||
releasePipelineLayout(layoutBlit);
|
// layouts
|
||||||
releasePipelineLayout(layoutSceneBlend);
|
releasePipelineLayout(layout_blit);
|
||||||
releasePipelineLayout(layoutSceneComp);
|
releasePipelineLayout(layout_merge_masks);
|
||||||
releasePipelineLayout(layoutImage);
|
releasePipelineLayout(layout_scene_compose);
|
||||||
releasePipelineLayout(layoutGradient);
|
releasePipelineLayout(layout_scene_blend);
|
||||||
releasePipelineLayout(layoutSolid);
|
releasePipelineLayout(layout_image_blend);
|
||||||
releasePipelineLayout(layoutStencil);
|
releasePipelineLayout(layout_gradient_blend);
|
||||||
releaseShaderModule(shaderBlit);
|
releasePipelineLayout(layout_solid_blend);
|
||||||
releaseShaderModule(shaderSceneBlend);
|
releasePipelineLayout(layout_scene);
|
||||||
releaseShaderModule(shaderSceneComp);
|
releasePipelineLayout(layout_image);
|
||||||
releaseShaderModule(shaderImage);
|
releasePipelineLayout(layout_gradient);
|
||||||
releaseShaderModule(shaderLinear);
|
releasePipelineLayout(layout_solid);
|
||||||
releaseShaderModule(shaderRadial);
|
releasePipelineLayout(layout_stencil);
|
||||||
releaseShaderModule(shaderSolid);
|
// shaders
|
||||||
releaseShaderModule(shaderStencil);
|
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)
|
void WgPipelines::releaseComputeHandles(WgContext& context)
|
||||||
{
|
{
|
||||||
const size_t pipesBlendCnt = sizeof(blendSolid)/sizeof(blendSolid[0]);
|
releaseComputePipeline(merge_masks);
|
||||||
for (uint32_t i = 0; i < pipesBlendCnt; i++) {
|
releasePipelineLayout(layout_merge_masks);
|
||||||
releaseComputePipeline(blendImage[i]);
|
releaseShaderModule(shader_merge_masks);
|
||||||
releaseComputePipeline(blendSolid[i]);
|
|
||||||
releaseComputePipeline(blendGradient[i]);
|
|
||||||
}
|
|
||||||
releaseComputePipeline(mergeMasks);
|
|
||||||
releasePipelineLayout(layoutBlend);
|
|
||||||
releasePipelineLayout(layoutMergeMasks);
|
|
||||||
releaseShaderModule(shaderBlendImage);
|
|
||||||
releaseShaderModule(shaderBlendGradient);
|
|
||||||
releaseShaderModule(shaderBlendSolid);
|
|
||||||
releaseShaderModule(shaderMergeMasks);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void WgPipelines::release(WgContext& context)
|
void WgPipelines::release(WgContext& context)
|
||||||
|
|
|
@ -25,56 +25,72 @@
|
||||||
|
|
||||||
#include "tvgWgBindGroups.h"
|
#include "tvgWgBindGroups.h"
|
||||||
|
|
||||||
enum class WgPipelineBlendType { Normal, Custom };
|
|
||||||
|
|
||||||
class WgPipelines {
|
class WgPipelines {
|
||||||
private:
|
private:
|
||||||
// graphics pipeline shaders
|
// shaders helpers
|
||||||
WGPUShaderModule shaderStencil{};
|
WGPUShaderModule shader_stencil{};
|
||||||
WGPUShaderModule shaderSolid{};
|
// shaders normal blend
|
||||||
WGPUShaderModule shaderRadial{};
|
WGPUShaderModule shader_solid{};
|
||||||
WGPUShaderModule shaderLinear{};
|
WGPUShaderModule shader_radial{};
|
||||||
WGPUShaderModule shaderImage{};
|
WGPUShaderModule shader_linear{};
|
||||||
WGPUShaderModule shaderSceneComp{};
|
WGPUShaderModule shader_image{};
|
||||||
WGPUShaderModule shaderSceneBlend{};
|
WGPUShaderModule shader_scene{};
|
||||||
WGPUShaderModule shaderBlit{};
|
// shaders custom blend
|
||||||
// compute pipeline shaders
|
WGPUShaderModule shader_solid_blend{};
|
||||||
WGPUShaderModule shaderMergeMasks;
|
WGPUShaderModule shader_radial_blend{};
|
||||||
WGPUShaderModule shaderBlendSolid;
|
WGPUShaderModule shader_linear_blend{};
|
||||||
WGPUShaderModule shaderBlendGradient;
|
WGPUShaderModule shader_image_blend{};
|
||||||
WGPUShaderModule shaderBlendImage;
|
WGPUShaderModule shader_scene_blend{};
|
||||||
|
// shader scene compose
|
||||||
|
WGPUShaderModule shader_scene_compose{};
|
||||||
|
WGPUShaderModule shader_merge_masks;
|
||||||
|
// shader blit
|
||||||
|
WGPUShaderModule shader_blit{};
|
||||||
private:
|
private:
|
||||||
// graphics pipeline layouts
|
// layouts helpers
|
||||||
WGPUPipelineLayout layoutStencil{};
|
WGPUPipelineLayout layout_stencil{};
|
||||||
WGPUPipelineLayout layoutSolid{};
|
// layouts normal blend
|
||||||
WGPUPipelineLayout layoutGradient{};
|
WGPUPipelineLayout layout_solid{};
|
||||||
WGPUPipelineLayout layoutImage{};
|
WGPUPipelineLayout layout_gradient{};
|
||||||
WGPUPipelineLayout layoutSceneComp{};
|
WGPUPipelineLayout layout_image{};
|
||||||
WGPUPipelineLayout layoutSceneBlend{};
|
WGPUPipelineLayout layout_scene{};
|
||||||
WGPUPipelineLayout layoutBlit{};
|
// layouts custom blend
|
||||||
// compute pipeline layouts
|
WGPUPipelineLayout layout_solid_blend{};
|
||||||
WGPUPipelineLayout layoutMergeMasks{};
|
WGPUPipelineLayout layout_gradient_blend{};
|
||||||
WGPUPipelineLayout layoutBlend{};
|
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:
|
public:
|
||||||
// graphics pipeline
|
// pipelines helpers
|
||||||
WgBindGroupLayouts layouts;
|
|
||||||
WGPURenderPipeline winding{};
|
WGPURenderPipeline winding{};
|
||||||
WGPURenderPipeline evenodd{};
|
WGPURenderPipeline evenodd{};
|
||||||
WGPURenderPipeline direct{};
|
WGPURenderPipeline direct{};
|
||||||
WGPURenderPipeline solid[2]{};
|
WGPURenderPipeline clip_path{};
|
||||||
WGPURenderPipeline radial[2]{};
|
// pipelines normal blend
|
||||||
WGPURenderPipeline linear[2]{};
|
WGPURenderPipeline solid{};
|
||||||
WGPURenderPipeline image[2]{};
|
WGPURenderPipeline radial{};
|
||||||
WGPURenderPipeline sceneClip;
|
WGPURenderPipeline linear{};
|
||||||
WGPURenderPipeline sceneComp[11];
|
WGPURenderPipeline image{};
|
||||||
WGPURenderPipeline sceneBlend;
|
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 blit{};
|
||||||
WGPURenderPipeline clipPath{};
|
public:
|
||||||
// compute pipeline
|
// layouts
|
||||||
WGPUComputePipeline mergeMasks;
|
WgBindGroupLayouts layouts;
|
||||||
WGPUComputePipeline blendSolid[18];
|
|
||||||
WGPUComputePipeline blendGradient[18];
|
|
||||||
WGPUComputePipeline blendImage[18];
|
|
||||||
private:
|
private:
|
||||||
void releaseGraphicHandles(WgContext& context);
|
void releaseGraphicHandles(WgContext& context);
|
||||||
void releaseComputeHandles(WgContext& context);
|
void releaseComputeHandles(WgContext& context);
|
||||||
|
|
|
@ -385,19 +385,10 @@ bool WgRenderer::endComposite(RenderCompositor* cmp)
|
||||||
WgRenderStorage* src = mRenderStorageStack.last();
|
WgRenderStorage* src = mRenderStorageStack.last();
|
||||||
mRenderStorageStack.pop();
|
mRenderStorageStack.pop();
|
||||||
WgRenderStorage* dst = mRenderStorageStack.last();
|
WgRenderStorage* dst = mRenderStorageStack.last();
|
||||||
// apply normal blend
|
|
||||||
if (comp->blend == BlendMethod::Normal) {
|
|
||||||
// begin previous render pass
|
// begin previous render pass
|
||||||
mCompositor.beginRenderPass(mCommandEncoder, dst, false);
|
mCompositor.beginRenderPass(mCommandEncoder, dst, false);
|
||||||
// apply blend
|
// apply composition
|
||||||
mCompositor.blendScene(mContext, src, comp);
|
mCompositor.renderScene(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);
|
|
||||||
}
|
|
||||||
// back render targets to the pool
|
// back render targets to the pool
|
||||||
mRenderStoragePool.free(mContext, src);
|
mRenderStoragePool.free(mContext, src);
|
||||||
} else { // finish composition
|
} 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"(
|
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"(
|
const char* cShaderSrc_Linear = R"(
|
||||||
struct VertexInput { @location(0) position: vec2f };
|
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
|
// uniforms
|
||||||
@group(0) @binding(0) var<uniform> uViewMat : mat4x4f;
|
@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 {
|
fn vs_main(in: VertexInput) -> VertexOutput {
|
||||||
var out: VertexOutput;
|
var out: VertexOutput;
|
||||||
out.position = uViewMat * uModelMat * vec4f(in.position.xy, 0.0, 1.0);
|
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;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
@fragment
|
@fragment
|
||||||
fn fs_main(in: VertexOutput) -> @location(0) vec4f {
|
fn fs_main(in: VertexOutput) -> @location(0) vec4f {
|
||||||
let pos = in.vScreenCoord.xy;
|
let pos = in.vGradCoord.xy;
|
||||||
let st = uSettingGrad.xy;
|
let st = uSettingGrad.xy;
|
||||||
let ed = uSettingGrad.zw;
|
let ed = uSettingGrad.zw;
|
||||||
let ba = ed - st;
|
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"(
|
const char* cShaderSrc_Radial = R"(
|
||||||
struct VertexInput { @location(0) position: vec2f };
|
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(0) @binding(0) var<uniform> uViewMat : mat4x4f;
|
||||||
@group(1) @binding(0) var<uniform> uModelMat : 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 {
|
fn vs_main(in: VertexInput) -> VertexOutput {
|
||||||
var out: VertexOutput;
|
var out: VertexOutput;
|
||||||
out.position = uViewMat * uModelMat * vec4f(in.position.xy, 0.0, 1.0);
|
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;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
@fragment
|
@fragment
|
||||||
fn fs_main(in: VertexOutput) -> @location(0) vec4f {
|
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 Sc = textureSample(uTextureGrad, uSamplerGrad, vec2f(t, 0.5));
|
||||||
let So = uBlendSettings.a;
|
let So = uBlendSettings.a;
|
||||||
return vec4f(Sc.rgb * Sc.a * So, Sc.a * So);
|
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"(
|
const char* cShaderSrc_Image = R"(
|
||||||
struct VertexInput { @location(0) position: vec2f, @location(1) texCoord: vec2f };
|
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(0) @binding(0) var<uniform> uViewMat : mat4x4f;
|
||||||
@group(1) @binding(0) var<uniform> uModelMat : 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 {
|
fn vs_main(in: VertexInput) -> VertexOutput {
|
||||||
var out: VertexOutput;
|
var out: VertexOutput;
|
||||||
out.position = uViewMat * uModelMat * vec4f(in.position.xy, 0.0, 1.0);
|
out.position = uViewMat * uModelMat * vec4f(in.position.xy, 0.0, 1.0);
|
||||||
out.texCoord = in.texCoord;
|
out.vTexCoord = in.texCoord;
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
@fragment
|
@fragment
|
||||||
fn fs_main(in: VertexOutput) -> @location(0) vec4f {
|
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;
|
let So: f32 = uBlendSettings.a;
|
||||||
switch u32(uBlendSettings.r) {
|
switch u32(uBlendSettings.r) {
|
||||||
case 0u: { Sc = Sc.rgba; }
|
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
|
// 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 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) 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
|
// graphics shader source: texture blit
|
||||||
//************************************************************************
|
//************************************************************************
|
||||||
|
@ -361,205 +690,3 @@ fn cs_main(@builtin(global_invocation_id) id: vec3u) {
|
||||||
textureStore(imageTrg, id.xy, colorMsk0 * colorMsk1);
|
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_
|
#ifndef _TVG_WG_SHADER_SRC_H_
|
||||||
#define _TVG_WG_SHADER_SRC_H_
|
#define _TVG_WG_SHADER_SRC_H_
|
||||||
|
|
||||||
// graphics shader sources
|
// helper shaders
|
||||||
extern const char* cShaderSrc_Stencil;
|
extern const char* cShaderSrc_Stencil;
|
||||||
|
// shaders normal blend
|
||||||
extern const char* cShaderSrc_Solid;
|
extern const char* cShaderSrc_Solid;
|
||||||
extern const char* cShaderSrc_Linear;
|
extern const char* cShaderSrc_Linear;
|
||||||
extern const char* cShaderSrc_Radial;
|
extern const char* cShaderSrc_Radial;
|
||||||
extern const char* cShaderSrc_Image;
|
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_Scene_Blend;
|
||||||
|
extern const char* cShaderSrc_BlendFuncs;
|
||||||
|
// shaders scene compose
|
||||||
|
extern const char* cShaderSrc_Scene_Compose;
|
||||||
|
// shaders blit
|
||||||
extern const char* cShaderSrc_Blit;
|
extern const char* cShaderSrc_Blit;
|
||||||
|
|
||||||
// compute shader sources: blend, compose and merge path
|
// compute shader sources: blend, compose and merge path
|
||||||
extern const char* cShaderSrc_MergeMasks;
|
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_
|
#endif // _TVG_WG_SHEDER_SRC_H_
|
||||||
|
|
Loading…
Add table
Reference in a new issue