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