diff --git a/src/renderer/wg_engine/tvgWgBindGroups.cpp b/src/renderer/wg_engine/tvgWgBindGroups.cpp index 0497cf15..7ecb4a92 100644 --- a/src/renderer/wg_engine/tvgWgBindGroups.cpp +++ b/src/renderer/wg_engine/tvgWgBindGroups.cpp @@ -29,7 +29,7 @@ WGPUBindGroupLayout WgBindGroupSolidColor::layout = nullptr; WGPUBindGroupLayout WgBindGroupLinearGradient::layout = nullptr; WGPUBindGroupLayout WgBindGroupRadialGradient::layout = nullptr; WGPUBindGroupLayout WgBindGroupPicture::layout = nullptr; -WGPUBindGroupLayout WgBindGroupCompose::layout = nullptr; +WGPUBindGroupLayout WgBindGroupBlit::layout = nullptr; WGPUBindGroupLayout WgBindGroupCanvas::getLayout(WGPUDevice device) @@ -258,40 +258,38 @@ void WgBindGroupPicture::release() } -WGPUBindGroupLayout WgBindGroupCompose::getLayout(WGPUDevice device) +WGPUBindGroupLayout WgBindGroupBlit::getLayout(WGPUDevice device) { if (layout) return layout; const WGPUBindGroupLayoutEntry bindGroupLayoutEntries[] { makeBindGroupLayoutEntrySampler(0), - makeBindGroupLayoutEntryTextureView(1), - makeBindGroupLayoutEntryTextureView(2) + makeBindGroupLayoutEntryTextureView(1) }; - layout = createBindGroupLayout(device, bindGroupLayoutEntries, 3); + layout = createBindGroupLayout(device, bindGroupLayoutEntries, 2); assert(layout); return layout; } -void WgBindGroupCompose::releaseLayout() +void WgBindGroupBlit::releaseLayout() { releaseBindGroupLayout(layout); } -void WgBindGroupCompose::initialize(WGPUDevice device, WGPUQueue queue, WGPUSampler uSampler, WGPUTextureView uTextureSrc, WGPUTextureView uTextureDst) +void WgBindGroupBlit::initialize(WGPUDevice device, WGPUQueue queue, WGPUSampler uSampler, WGPUTextureView uTexture) { release(); const WGPUBindGroupEntry bindGroupEntries[] { makeBindGroupEntrySampler(0, uSampler), - makeBindGroupEntryTextureView(1, uTextureSrc), - makeBindGroupEntryTextureView(2, uTextureDst) + makeBindGroupEntryTextureView(1, uTexture) }; - mBindGroup = createBindGroup(device, getLayout(device), bindGroupEntries, 3); + mBindGroup = createBindGroup(device, getLayout(device), bindGroupEntries, 2); assert(mBindGroup); } -void WgBindGroupCompose::release() +void WgBindGroupBlit::release() { releaseBindGroup(mBindGroup); -} +} \ No newline at end of file diff --git a/src/renderer/wg_engine/tvgWgBindGroups.h b/src/renderer/wg_engine/tvgWgBindGroups.h index 42dc9f5a..a637f6e1 100644 --- a/src/renderer/wg_engine/tvgWgBindGroups.h +++ b/src/renderer/wg_engine/tvgWgBindGroups.h @@ -107,8 +107,8 @@ struct WgBindGroupPicture : public WgBindGroup void release(); }; -// @group(2) -struct WgBindGroupCompose : public WgBindGroup +// @group(0 or 1) +struct WgBindGroupBlit : public WgBindGroup { static WGPUBindGroupLayout layout; static WGPUBindGroupLayout getLayout(WGPUDevice device); @@ -116,8 +116,7 @@ struct WgBindGroupCompose : public WgBindGroup void initialize(WGPUDevice device, WGPUQueue queue, WGPUSampler uSampler, - WGPUTextureView uTextureSrc, - WGPUTextureView uTextureDst); + WGPUTextureView uTexture); void release(); }; diff --git a/src/renderer/wg_engine/tvgWgCommon.cpp b/src/renderer/wg_engine/tvgWgCommon.cpp index ca5f510e..25f56ff1 100644 --- a/src/renderer/wg_engine/tvgWgCommon.cpp +++ b/src/renderer/wg_engine/tvgWgCommon.cpp @@ -313,8 +313,8 @@ WGPUBlendState WgPipeline::makeBlendState() blendState.color.srcFactor = WGPUBlendFactor_SrcAlpha; blendState.color.dstFactor = WGPUBlendFactor_OneMinusSrcAlpha; blendState.alpha.operation = WGPUBlendOperation_Add; - blendState.alpha.srcFactor = WGPUBlendFactor_Zero; - blendState.alpha.dstFactor = WGPUBlendFactor_One; + blendState.alpha.srcFactor = WGPUBlendFactor_One; + blendState.alpha.dstFactor = WGPUBlendFactor_Zero; return blendState; } diff --git a/src/renderer/wg_engine/tvgWgGeometry.cpp b/src/renderer/wg_engine/tvgWgGeometry.cpp index f6c2dc56..ff4cd6cb 100644 --- a/src/renderer/wg_engine/tvgWgGeometry.cpp +++ b/src/renderer/wg_engine/tvgWgGeometry.cpp @@ -120,6 +120,25 @@ void WgGeometryData::appendImageBox(float w, float h) }; +void WgGeometryData::appendBlitBox() +{ + positions.push({ -1.0f, +1.0f }); + positions.push({ +1.0f, +1.0f }); + positions.push({ +1.0f, -1.0f }); + positions.push({ -1.0f, -1.0f }); + texCoords.push({ 0.0f, 0.0f }); + texCoords.push({ 1.0f, 0.0f }); + texCoords.push({ 1.0f, 1.0f }); + texCoords.push({ 0.0f, 1.0f }); + indexes.push(0); + indexes.push(1); + indexes.push(2); + indexes.push(0); + indexes.push(2); + indexes.push(3); +} + + void WgGeometryData::appendMesh(const RenderMesh* rmesh) { assert(rmesh); diff --git a/src/renderer/wg_engine/tvgWgGeometry.h b/src/renderer/wg_engine/tvgWgGeometry.h index fa275038..dcba0ab4 100644 --- a/src/renderer/wg_engine/tvgWgGeometry.h +++ b/src/renderer/wg_engine/tvgWgGeometry.h @@ -90,6 +90,7 @@ struct WgGeometryData void appendRect(WgPoint p0, WgPoint p1, WgPoint p2, WgPoint p3); void appendCircle(WgPoint center, float radius); void appendImageBox(float w, float h); + void appendBlitBox(); void appendMesh(const RenderMesh* rmesh); void close(); }; diff --git a/src/renderer/wg_engine/tvgWgPipelines.cpp b/src/renderer/wg_engine/tvgWgPipelines.cpp index a859243c..9e16a4d8 100644 --- a/src/renderer/wg_engine/tvgWgPipelines.cpp +++ b/src/renderer/wg_engine/tvgWgPipelines.cpp @@ -223,33 +223,171 @@ void WgPipelineImage::initialize(WGPUDevice device) } +void WgPipelineBlit::initialize(WGPUDevice device) +{ + // vertex and buffers settings + WGPUVertexAttribute vertexAttributesPos = { WGPUVertexFormat_Float32x2, sizeof(float) * 0, 0 }; + WGPUVertexAttribute vertexAttributesTex = { WGPUVertexFormat_Float32x2, sizeof(float) * 0, 1 }; + WGPUVertexBufferLayout vertexBufferLayouts[] = { + makeVertexBufferLayout(&vertexAttributesPos, 1, sizeof(float) * 2), + makeVertexBufferLayout(&vertexAttributesTex, 1, sizeof(float) * 2) + }; + + // bind groups and layouts + WGPUBindGroupLayout bindGroupLayouts[] = { + WgBindGroupBlit::getLayout(device) + }; + + // stencil function + WGPUCompareFunction stencilFuncion = WGPUCompareFunction_Always; + WGPUStencilOperation stencilOperation = WGPUStencilOperation_Zero; + + // sheder source and labels + auto shaderSource = cShaderSource_PipelineBlit; + auto shaderLabel = "The shader blit"; + auto pipelineLabel = "The render pipeline blit"; + + // allocate all pipeline handles + allocate(device, + vertexBufferLayouts, ARRAY_ELEMENTS_COUNT(vertexBufferLayouts), + bindGroupLayouts, ARRAY_ELEMENTS_COUNT(bindGroupLayouts), + stencilFuncion, stencilOperation, + shaderSource, shaderLabel, pipelineLabel); +} + + +void WgPipelineBlitColor::initialize(WGPUDevice device) +{ + // vertex and buffers settings + WGPUVertexAttribute vertexAttributesPos = { WGPUVertexFormat_Float32x2, sizeof(float) * 0, 0 }; + WGPUVertexAttribute vertexAttributesTex = { WGPUVertexFormat_Float32x2, sizeof(float) * 0, 1 }; + WGPUVertexBufferLayout vertexBufferLayouts[] = { + makeVertexBufferLayout(&vertexAttributesPos, 1, sizeof(float) * 2), + makeVertexBufferLayout(&vertexAttributesTex, 1, sizeof(float) * 2) + }; + + // bind groups and layouts + WGPUBindGroupLayout bindGroupLayouts[] = { + WgBindGroupBlit::getLayout(device) + }; + + // stencil function + WGPUCompareFunction stencilFuncion = WGPUCompareFunction_Always; + WGPUStencilOperation stencilOperation = WGPUStencilOperation_Zero; + + // sheder source and labels + auto shaderSource = cShaderSource_PipelineBlitColor; + auto shaderLabel = "The shader blit color"; + auto pipelineLabel = "The render pipeline blit color"; + + // allocate all pipeline handles + allocate(device, + vertexBufferLayouts, ARRAY_ELEMENTS_COUNT(vertexBufferLayouts), + bindGroupLayouts, ARRAY_ELEMENTS_COUNT(bindGroupLayouts), + stencilFuncion, stencilOperation, + shaderSource, shaderLabel, pipelineLabel); +} + + +void WgPipelineComposition::initialize(WGPUDevice device, const char* shaderSrc) +{ + // vertex and buffers settings + WGPUVertexAttribute vertexAttributesPos = { WGPUVertexFormat_Float32x2, sizeof(float) * 0, 0 }; + WGPUVertexAttribute vertexAttributesTex = { WGPUVertexFormat_Float32x2, sizeof(float) * 0, 1 }; + WGPUVertexBufferLayout vertexBufferLayouts[] = { + makeVertexBufferLayout(&vertexAttributesPos, 1, sizeof(float) * 2), + makeVertexBufferLayout(&vertexAttributesTex, 1, sizeof(float) * 2) + }; + + // bind groups and layouts + WGPUBindGroupLayout bindGroupLayouts[] = { + WgBindGroupBlit::getLayout(device), + WgBindGroupBlit::getLayout(device) + }; + + // stencil function + WGPUCompareFunction stencilFuncion = WGPUCompareFunction_Always; + WGPUStencilOperation stencilOperation = WGPUStencilOperation_Zero; + + // sheder source and labels + auto shaderSource = shaderSrc; + auto shaderLabel = "The shader compose alpha mask"; + auto pipelineLabel = "The render pipeline compose alpha mask"; + + // allocate all pipeline handles + allocate(device, + vertexBufferLayouts, ARRAY_ELEMENTS_COUNT(vertexBufferLayouts), + bindGroupLayouts, ARRAY_ELEMENTS_COUNT(bindGroupLayouts), + stencilFuncion, stencilOperation, + shaderSource, shaderLabel, pipelineLabel); +} + //************************************************************************ // pipelines //************************************************************************ void WgPipelines::initialize(WGPUDevice device) { - mPipelineFillShape.initialize(device); - mPipelineFillStroke.initialize(device); - mPipelineSolid.initialize(device); - mPipelineLinear.initialize(device); - mPipelineRadial.initialize(device); - mPipelineImage.initialize(device); + fillShape.initialize(device); + fillStroke.initialize(device); + solid.initialize(device); + linear.initialize(device); + radial.initialize(device); + image.initialize(device); + blit.initialize(device); + blitColor.initialize(device); + // composition pipelines + compAlphaMask.initialize(device, cShaderSource_PipelineCompAlphaMask); + compInvAlphaMask.initialize(device, cShaderSource_PipelineCompInvAlphaMask); + compLumaMask.initialize(device, cShaderSource_PipelineCompLumaMask); + compInvLumaMask.initialize(device, cShaderSource_PipelineCompInvLumaMask); + compAddMask.initialize(device, cShaderSource_PipelineCompAddMask); + compSubtractMask.initialize(device, cShaderSource_PipelineCompSubtractMask); + compIntersectMask.initialize(device, cShaderSource_PipelineCompIntersectMask); + compDifferenceMask.initialize(device, cShaderSource_PipelineCompDifferenceMask); } void WgPipelines::release() { - WgBindGroupCompose::releaseLayout(); + WgBindGroupBlit::releaseLayout(); WgBindGroupPicture::releaseLayout(); WgBindGroupRadialGradient::releaseLayout(); WgBindGroupLinearGradient::releaseLayout(); WgBindGroupSolidColor::releaseLayout(); WgBindGroupCanvas::releaseLayout(); - mPipelineImage.release(); - mPipelineRadial.release(); - mPipelineLinear.release(); - mPipelineSolid.release(); - mPipelineFillStroke.release(); - mPipelineFillShape.release(); -} \ No newline at end of file + compDifferenceMask.release(); + compIntersectMask.release(); + compSubtractMask.release(); + compAddMask.release(); + compInvLumaMask.release(); + compLumaMask.release(); + compInvAlphaMask.release(); + compAlphaMask.release(); + blitColor.release(); + blit.release(); + image.release(); + radial.release(); + linear.release(); + solid.release(); + fillStroke.release(); + fillShape.release(); +} + + +WgPipelineComposition* WgPipelines::getCompositionPipeline(CompositeMethod method) +{ + switch (method) { + case CompositeMethod::ClipPath: + case CompositeMethod::AlphaMask: return &compAlphaMask; break; + case CompositeMethod::InvAlphaMask: return &compInvAlphaMask; break; + case CompositeMethod::LumaMask: return &compLumaMask; break; + case CompositeMethod::InvLumaMask: return &compInvLumaMask; break; + case CompositeMethod::AddMask: return &compAddMask; break; + case CompositeMethod::SubtractMask: return &compSubtractMask; break; + case CompositeMethod::IntersectMask: return &compIntersectMask; break; + case CompositeMethod::DifferenceMask: return &compDifferenceMask; break; + default: return nullptr; break; + } + return nullptr; +} diff --git a/src/renderer/wg_engine/tvgWgPipelines.h b/src/renderer/wg_engine/tvgWgPipelines.h index a9530fc4..6b5274f0 100644 --- a/src/renderer/wg_engine/tvgWgPipelines.h +++ b/src/renderer/wg_engine/tvgWgPipelines.h @@ -95,17 +95,62 @@ struct WgPipelineImage: public WgPipeline } }; +struct WgPipelineBlit: public WgPipeline +{ + void initialize(WGPUDevice device) override; + void use(WGPURenderPassEncoder encoder, WgBindGroupBlit& groupBlit) + { + set(encoder); + groupBlit.set(encoder, 0); + } +}; + +struct WgPipelineBlitColor: public WgPipeline +{ + void initialize(WGPUDevice device) override; + void use(WGPURenderPassEncoder encoder, WgBindGroupBlit& groupBlit) + { + set(encoder); + groupBlit.set(encoder, 0); + } +}; + +struct WgPipelineComposition: public WgPipeline +{ + void initialize(WGPUDevice device) override {}; + void initialize(WGPUDevice device, const char* shaderSrc); + void use(WGPURenderPassEncoder encoder, WgBindGroupBlit& groupBlitSrc, WgBindGroupBlit& groupBlitMsk) + { + set(encoder); + groupBlitSrc.set(encoder, 0); + groupBlitMsk.set(encoder, 1); + } +}; + struct WgPipelines { - WgPipelineFillShape mPipelineFillShape; - WgPipelineFillStroke mPipelineFillStroke; - WgPipelineSolid mPipelineSolid; - WgPipelineLinear mPipelineLinear; - WgPipelineRadial mPipelineRadial; - WgPipelineImage mPipelineImage; + WgPipelineFillShape fillShape; + WgPipelineFillStroke fillStroke; + WgPipelineSolid solid; + WgPipelineLinear linear; + WgPipelineRadial radial; + WgPipelineImage image; + WgPipelineBlit blit; + WgPipelineBlitColor blitColor; + // composition pipelines + WgPipelineComposition compAlphaMask; + WgPipelineComposition compInvAlphaMask; + WgPipelineComposition compLumaMask; + WgPipelineComposition compInvLumaMask; + WgPipelineComposition compAddMask; + WgPipelineComposition compSubtractMask; + WgPipelineComposition compIntersectMask; + WgPipelineComposition compDifferenceMask; void initialize(WGPUDevice device); void release(); + + WgPipelineComposition* getCompositionPipeline(CompositeMethod method); }; #endif // _TVG_WG_PIPELINES_H_ diff --git a/src/renderer/wg_engine/tvgWgRenderTarget.cpp b/src/renderer/wg_engine/tvgWgRenderTarget.cpp index b5621952..e493854f 100644 --- a/src/renderer/wg_engine/tvgWgRenderTarget.cpp +++ b/src/renderer/wg_engine/tvgWgRenderTarget.cpp @@ -39,8 +39,8 @@ void WgRenderTarget::initialize(WgContext& context, WgPipelines& pipelines, uint samplerDesc.lodMaxClamp = 32.0f; samplerDesc.compare = WGPUCompareFunction_Undefined; samplerDesc.maxAnisotropy = 1; - mSampler = wgpuDeviceCreateSampler(context.device, &samplerDesc); - assert(mSampler); + sampler = wgpuDeviceCreateSampler(context.device, &samplerDesc); + assert(sampler); // texture descriptor WGPUTextureDescriptor textureDescColor{}; textureDescColor.nextInChain = nullptr; @@ -48,7 +48,7 @@ void WgRenderTarget::initialize(WgContext& context, WgPipelines& pipelines, uint textureDescColor.usage = WGPUTextureUsage_RenderAttachment | WGPUTextureUsage_TextureBinding | WGPUTextureUsage_CopyDst; textureDescColor.dimension = WGPUTextureDimension_2D; textureDescColor.size = { w, h, 1 }; - textureDescColor.format = WGPUTextureFormat_RGBA8Unorm; + textureDescColor.format = WGPUTextureFormat_BGRA8Unorm; textureDescColor.mipLevelCount = 1; textureDescColor.sampleCount = 1; textureDescColor.viewFormatCount = 0; @@ -59,15 +59,15 @@ void WgRenderTarget::initialize(WgContext& context, WgPipelines& pipelines, uint WGPUTextureViewDescriptor textureViewDescColor{}; textureViewDescColor.nextInChain = nullptr; textureViewDescColor.label = "The target texture view color"; - textureViewDescColor.format = WGPUTextureFormat_RGBA8Unorm; + textureViewDescColor.format = WGPUTextureFormat_BGRA8Unorm; textureViewDescColor.dimension = WGPUTextureViewDimension_2D; textureViewDescColor.baseMipLevel = 0; textureViewDescColor.mipLevelCount = 1; textureViewDescColor.baseArrayLayer = 0; textureViewDescColor.arrayLayerCount = 1; textureViewDescColor.aspect = WGPUTextureAspect_All; - mTextureViewColor = wgpuTextureCreateView(mTextureColor, &textureViewDescColor); - assert(mTextureViewColor); + textureViewColor = wgpuTextureCreateView(mTextureColor, &textureViewDescColor); + assert(textureViewColor); // stencil texture WGPUTextureDescriptor textureDescStencil{}; textureDescStencil.nextInChain = nullptr; @@ -93,49 +93,56 @@ void WgRenderTarget::initialize(WgContext& context, WgPipelines& pipelines, uint textureViewDescStencil.baseArrayLayer = 0; textureViewDescStencil.arrayLayerCount = 1; textureViewDescStencil.aspect = WGPUTextureAspect_All; - mTextureViewStencil = wgpuTextureCreateView(mTextureStencil, &textureViewDescStencil); - assert(mTextureViewStencil); + textureViewStencil = wgpuTextureCreateView(mTextureStencil, &textureViewDescStencil); + assert(textureViewStencil); + // initialize bind group for blitting + bindGroupBlit.initialize(context.device, context.queue, sampler, textureViewColor); // initialize window binding groups WgShaderTypeMat4x4f viewMat(w, h); mBindGroupCanvasWnd.initialize(context.device, context.queue, viewMat); + WgGeometryData geometryDataWnd; + geometryDataWnd.appendBlitBox(); + mMeshDataCanvasWnd.update(context, &geometryDataWnd); mPipelines = &pipelines; } void WgRenderTarget::release(WgContext& context) { + mMeshDataCanvasWnd.release(context); mBindGroupCanvasWnd.release(); + bindGroupBlit.release(); if (mTextureStencil) { wgpuTextureDestroy(mTextureStencil); wgpuTextureRelease(mTextureStencil); mTextureStencil = nullptr; } - if (mTextureViewStencil) wgpuTextureViewRelease(mTextureViewStencil); - mTextureViewStencil = nullptr; + if (textureViewStencil) wgpuTextureViewRelease(textureViewStencil); + textureViewStencil = nullptr; if (mTextureColor) { wgpuTextureDestroy(mTextureColor); wgpuTextureRelease(mTextureColor); mTextureColor = nullptr; } - if (mTextureViewColor) wgpuTextureViewRelease(mTextureViewColor); - mTextureViewColor = nullptr; - if (mSampler) wgpuSamplerRelease(mSampler); - mSampler = nullptr; + if (textureViewColor) wgpuTextureViewRelease(textureViewColor); + textureViewColor = nullptr; + if (sampler) wgpuSamplerRelease(sampler); + sampler = nullptr; } -void WgRenderTarget::beginRenderPass(WGPUCommandEncoder commandEncoder) +void WgRenderTarget::beginRenderPass(WGPUCommandEncoder commandEncoder, bool clear) { - beginRenderPass(commandEncoder, mTextureViewColor); + beginRenderPass(commandEncoder, textureViewColor, clear); } -void WgRenderTarget::beginRenderPass(WGPUCommandEncoder commandEncoder, WGPUTextureView colorAttachement) +void WgRenderTarget::beginRenderPass(WGPUCommandEncoder commandEncoder, WGPUTextureView colorAttachement, bool clear) { assert(!mRenderPassEncoder); // render pass depth stencil attachment WGPURenderPassDepthStencilAttachment depthStencilAttachment{}; - depthStencilAttachment.view = mTextureViewStencil; + depthStencilAttachment.view = textureViewStencil; depthStencilAttachment.depthLoadOp = WGPULoadOp_Clear; depthStencilAttachment.depthStoreOp = WGPUStoreOp_Store; depthStencilAttachment.depthClearValue = 1.0f; @@ -148,8 +155,8 @@ void WgRenderTarget::beginRenderPass(WGPUCommandEncoder commandEncoder, WGPUText WGPURenderPassColorAttachment colorAttachment{}; colorAttachment.view = colorAttachement; colorAttachment.resolveTarget = nullptr; - colorAttachment.loadOp = WGPULoadOp_Clear; - colorAttachment.clearValue = {0, 0, 0, 0}; + colorAttachment.loadOp = clear ? WGPULoadOp_Clear : WGPULoadOp_Load; + colorAttachment.clearValue = { 0, 0, 0, 0 }; colorAttachment.storeOp = WGPUStoreOp_Store; // render pass descriptor WGPURenderPassDescriptor renderPassDesc{}; @@ -184,16 +191,16 @@ void WgRenderTarget::renderShape(WgRenderDataShape* renderData) wgpuRenderPassEncoderSetStencilReference(mRenderPassEncoder, 0); for (uint32_t i = 0; i < renderData->meshGroupShapes.meshes.count; i++) { // draw to stencil (first pass) - mPipelines->mPipelineFillShape.use(mRenderPassEncoder, mBindGroupCanvasWnd, renderData->bindGroupPaint); + mPipelines->fillShape.use(mRenderPassEncoder, mBindGroupCanvasWnd, renderData->bindGroupPaint); renderData->meshGroupShapes.meshes[i]->draw(mRenderPassEncoder); // fill shape (second pass) WgRenderSettings& settings = renderData->renderSettingsShape; if (settings.fillType == WgRenderSettingsType::Solid) - mPipelines->mPipelineSolid.use(mRenderPassEncoder, mBindGroupCanvasWnd, renderData->bindGroupPaint, settings.bindGroupSolid); + mPipelines->solid.use(mRenderPassEncoder, mBindGroupCanvasWnd, renderData->bindGroupPaint, settings.bindGroupSolid); else if (settings.fillType == WgRenderSettingsType::Linear) - mPipelines->mPipelineLinear.use(mRenderPassEncoder, mBindGroupCanvasWnd, renderData->bindGroupPaint, settings.bindGroupLinear); + mPipelines->linear.use(mRenderPassEncoder, mBindGroupCanvasWnd, renderData->bindGroupPaint, settings.bindGroupLinear); else if (settings.fillType == WgRenderSettingsType::Radial) - mPipelines->mPipelineRadial.use(mRenderPassEncoder, mBindGroupCanvasWnd, renderData->bindGroupPaint, settings.bindGroupRadial); + mPipelines->radial.use(mRenderPassEncoder, mBindGroupCanvasWnd, renderData->bindGroupPaint, settings.bindGroupRadial); renderData->meshBBoxShapes.draw(mRenderPassEncoder); } } @@ -208,18 +215,18 @@ void WgRenderTarget::renderStroke(WgRenderDataShape* renderData) // draw strokes to stencil (first pass) wgpuRenderPassEncoderSetStencilReference(mRenderPassEncoder, 255); for (uint32_t i = 0; i < renderData->meshGroupStrokes.meshes.count; i++) { - mPipelines->mPipelineFillStroke.use(mRenderPassEncoder, mBindGroupCanvasWnd, renderData->bindGroupPaint); + mPipelines->fillStroke.use(mRenderPassEncoder, mBindGroupCanvasWnd, renderData->bindGroupPaint); renderData->meshGroupStrokes.meshes[i]->draw(mRenderPassEncoder); } // fill shape (second pass) wgpuRenderPassEncoderSetStencilReference(mRenderPassEncoder, 0); WgRenderSettings& settings = renderData->renderSettingsStroke; if (settings.fillType == WgRenderSettingsType::Solid) - mPipelines->mPipelineSolid.use(mRenderPassEncoder, mBindGroupCanvasWnd, renderData->bindGroupPaint, settings.bindGroupSolid); + mPipelines->solid.use(mRenderPassEncoder, mBindGroupCanvasWnd, renderData->bindGroupPaint, settings.bindGroupSolid); else if (settings.fillType == WgRenderSettingsType::Linear) - mPipelines->mPipelineLinear.use(mRenderPassEncoder, mBindGroupCanvasWnd, renderData->bindGroupPaint, settings.bindGroupLinear); + mPipelines->linear.use(mRenderPassEncoder, mBindGroupCanvasWnd, renderData->bindGroupPaint, settings.bindGroupLinear); else if (settings.fillType == WgRenderSettingsType::Radial) - mPipelines->mPipelineRadial.use(mRenderPassEncoder, mBindGroupCanvasWnd, renderData->bindGroupPaint, settings.bindGroupRadial); + mPipelines->radial.use(mRenderPassEncoder, mBindGroupCanvasWnd, renderData->bindGroupPaint, settings.bindGroupRadial); renderData->meshBBoxStrokes.draw(mRenderPassEncoder); } } @@ -231,7 +238,7 @@ void WgRenderTarget::renderPicture(WgRenderDataPicture* renderData) assert(mRenderPassEncoder); if (renderData->meshData.bufferTexCoord) { wgpuRenderPassEncoderSetStencilReference(mRenderPassEncoder, 0); - mPipelines->mPipelineImage.use( + mPipelines->image.use( mRenderPassEncoder, mBindGroupCanvasWnd, renderData->bindGroupPaint, @@ -239,3 +246,29 @@ void WgRenderTarget::renderPicture(WgRenderDataPicture* renderData) renderData->meshData.drawImage(mRenderPassEncoder); } } + + +void WgRenderTarget::blit(WgContext& context, WgRenderTarget* renderTargetSrc) +{ + assert(mRenderPassEncoder); + mPipelines->blit.use(mRenderPassEncoder, renderTargetSrc->bindGroupBlit); + mMeshDataCanvasWnd.drawImage(mRenderPassEncoder); +} + + +void WgRenderTarget::blitColor(WgContext& context, WgRenderTarget* renderTargetSrc) +{ + assert(mRenderPassEncoder); + mPipelines->blitColor.use(mRenderPassEncoder, renderTargetSrc->bindGroupBlit); + mMeshDataCanvasWnd.drawImage(mRenderPassEncoder); +} + + +void WgRenderTarget::compose(WgContext& context, WgRenderTarget* renderTargetSrc, WgRenderTarget* renderTargetMsk, CompositeMethod method) +{ + assert(mRenderPassEncoder); + WgPipelineComposition* pipeline = mPipelines->getCompositionPipeline(method); + assert(pipeline); + pipeline->use(mRenderPassEncoder, renderTargetSrc->bindGroupBlit, renderTargetMsk->bindGroupBlit); + mMeshDataCanvasWnd.drawImage(mRenderPassEncoder); +} diff --git a/src/renderer/wg_engine/tvgWgRenderTarget.h b/src/renderer/wg_engine/tvgWgRenderTarget.h index 7c0287cb..ff81a994 100644 --- a/src/renderer/wg_engine/tvgWgRenderTarget.h +++ b/src/renderer/wg_engine/tvgWgRenderTarget.h @@ -31,24 +31,32 @@ private: WGPURenderPassEncoder mRenderPassEncoder{}; // fill and blit data WgBindGroupCanvas mBindGroupCanvasWnd; + // composition handles + WgMeshData mMeshDataCanvasWnd; // gpu buffers - WGPUSampler mSampler{}; WGPUTexture mTextureColor{}; WGPUTexture mTextureStencil{}; - WGPUTextureView mTextureViewColor{}; - WGPUTextureView mTextureViewStencil{}; WgPipelines* mPipelines{}; // external handle +public: + WGPUSampler sampler{}; + WGPUTextureView textureViewColor{}; + WGPUTextureView textureViewStencil{}; + WgBindGroupBlit bindGroupBlit; public: void initialize(WgContext& context, WgPipelines& pipelines, uint32_t w, uint32_t h); void release(WgContext& context); - void beginRenderPass(WGPUCommandEncoder commandEncoder, WGPUTextureView colorAttachement); - void beginRenderPass(WGPUCommandEncoder commandEncoder); + void beginRenderPass(WGPUCommandEncoder commandEncoder, WGPUTextureView colorAttachement, bool clear); + void beginRenderPass(WGPUCommandEncoder commandEncoder, bool clear); void endRenderPass(); void renderShape(WgRenderDataShape* renderData); void renderStroke(WgRenderDataShape* renderData); void renderPicture(WgRenderDataPicture* renderData); + + void blit(WgContext& context, WgRenderTarget* renderTargetSrc); + void blitColor(WgContext& context, WgRenderTarget* renderTargetSrc); + void compose(WgContext& context, WgRenderTarget* renderTargetSrc, WgRenderTarget* renderTargetMsk, CompositeMethod method); }; #endif diff --git a/src/renderer/wg_engine/tvgWgRenderer.cpp b/src/renderer/wg_engine/tvgWgRenderer.cpp index b045050b..47edcf48 100644 --- a/src/renderer/wg_engine/tvgWgRenderer.cpp +++ b/src/renderer/wg_engine/tvgWgRenderer.cpp @@ -48,7 +48,14 @@ void WgRenderer::initialize() void WgRenderer::release() { - mPipelines.release(); + // clear render targets + for (uint32_t i = 0; i < mRenderTargetPool.count; i++) { + mRenderTargetPool[i]->release(mContext); + delete mRenderTargetPool[i]; + } + mRenderTargetPool.clear(); + mRenderTargetRoot.release(mContext); + mRenderTargetWnd.release(mContext); if (mSwapChain) wgpuSwapChainRelease(mSwapChain); if (mSurface) wgpuSurfaceRelease(mSurface); mPipelines.release(); @@ -123,26 +130,39 @@ RenderData WgRenderer::prepare(Surface* surface, const RenderMesh* mesh, RenderD bool WgRenderer::preRender() { + // command encoder descriptor + WGPUCommandEncoderDescriptor commandEncoderDesc{}; + commandEncoderDesc.nextInChain = nullptr; + commandEncoderDesc.label = "The command encoder"; + mCommandEncoder = wgpuDeviceCreateCommandEncoder(mContext.device, &commandEncoderDesc); + // render datas + mRenderTargetStack.push(&mRenderTargetRoot); + mRenderTargetRoot.beginRenderPass(mCommandEncoder, true); return true; } bool WgRenderer::renderShape(RenderData data) { - mRenderDatas.push(data); + mRenderTargetStack.last()->renderShape((WgRenderDataShape *)data); + mRenderTargetStack.last()->renderStroke((WgRenderDataShape *)data); return true; } bool WgRenderer::renderImage(RenderData data) { - mRenderDatas.push(data); + mRenderTargetStack.last()->renderPicture((WgRenderDataPicture *)data); return true; } bool WgRenderer::postRender() { + mRenderTargetRoot.endRenderPass(); + mRenderTargetStack.pop(); + mContext.executeCommandEncoder(mCommandEncoder); + wgpuCommandEncoderRelease(mCommandEncoder); return true; } @@ -193,35 +213,17 @@ bool WgRenderer::clear() bool WgRenderer::sync() { WGPUTextureView backBufferView = wgpuSwapChainGetCurrentTextureView(mSwapChain); - - // command encoder descriptor WGPUCommandEncoderDescriptor commandEncoderDesc{}; commandEncoderDesc.nextInChain = nullptr; commandEncoderDesc.label = "The command encoder"; WGPUCommandEncoder commandEncoder = wgpuDeviceCreateCommandEncoder(mContext.device, &commandEncoderDesc); - - // render datas - mRenderTarget.beginRenderPass(commandEncoder, backBufferView); - for (size_t i = 0; i < mRenderDatas.count; i++) { - WgRenderDataPaint* renderData = (WgRenderDataShape*)(mRenderDatas[i]); - if (renderData->identifier() == TVG_CLASS_ID_SHAPE) { - mRenderTarget.renderShape((WgRenderDataShape *)renderData); - mRenderTarget.renderStroke((WgRenderDataShape *)renderData); - } else if (renderData->identifier() == TVG_CLASS_ID_PICTURE) { - mRenderTarget.renderPicture((WgRenderDataPicture *)renderData); - } - } - mRenderTarget.endRenderPass(); - + mRenderTargetWnd.beginRenderPass(commandEncoder, backBufferView, true); + mRenderTargetWnd.blitColor(mContext, &mRenderTargetRoot); + mRenderTargetWnd.endRenderPass(); mContext.executeCommandEncoder(commandEncoder); wgpuCommandEncoderRelease(commandEncoder); - - // go to the next frame wgpuTextureViewRelease(backBufferView); wgpuSwapChainPresent(mSwapChain); - - mRenderDatas.clear(); - return true; } @@ -233,7 +235,7 @@ bool WgRenderer::target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t mTargetSurface.w = w; mTargetSurface.h = h; - // TODO: Add ability to render into offscreen buffer + mRenderTargetRoot.initialize(mContext, mPipelines, w, h); return true; } @@ -273,26 +275,99 @@ bool WgRenderer::target(void* window, uint32_t w, uint32_t h) mSwapChain = wgpuDeviceCreateSwapChain(mContext.device, mSurface, &swapChainDesc); assert(mSwapChain); - mRenderTarget.initialize(mContext, mPipelines, w, h); + mRenderTargetWnd.initialize(mContext, mPipelines, w, h); + mRenderTargetRoot.initialize(mContext, mPipelines, w, h); return true; } Compositor* WgRenderer::target(TVG_UNUSED const RenderRegion& region, TVG_UNUSED ColorSpace cs) { - return nullptr; + mCompositorStack.push(new Compositor); + return mCompositorStack.last(); } bool WgRenderer::beginComposite(TVG_UNUSED Compositor* cmp, TVG_UNUSED CompositeMethod method, TVG_UNUSED uint8_t opacity) { - return false; + // save current composition settings + cmp->method = method; + cmp->opacity = opacity; + + // end current render target + mRenderTargetStack.last()->endRenderPass(); + + // create new render target and begin new render pass + WgRenderTarget* renderTarget = allocateRenderTarget(); + renderTarget->beginRenderPass(mCommandEncoder, true); + mRenderTargetStack.push(renderTarget); + + return true; } bool WgRenderer::endComposite(TVG_UNUSED Compositor* cmp) { - return false; + if (cmp->method == CompositeMethod::None) { + // end current render pass + mRenderTargetStack.last()->endRenderPass(); + + // get two last render targets + WgRenderTarget* renderTargetSrc = mRenderTargetStack.last(); + mRenderTargetStack.pop(); + + // apply current render target + WgRenderTarget* renderTarget = mRenderTargetStack.last(); + renderTarget->beginRenderPass(mCommandEncoder, false); + renderTarget->blit(mContext, renderTargetSrc); + + // back render targets to the pool + releaseRenderTarget(renderTargetSrc); + } else { + // end current render pass + mRenderTargetStack.last()->endRenderPass(); + + // get two last render targets + WgRenderTarget* renderTargetSrc = mRenderTargetStack.last(); + mRenderTargetStack.pop(); + WgRenderTarget* renderTargetMsk = mRenderTargetStack.last(); + mRenderTargetStack.pop(); + + // apply current render target + WgRenderTarget* renderTarget = mRenderTargetStack.last(); + renderTarget->beginRenderPass(mCommandEncoder, false); + renderTarget->compose(mContext, renderTargetSrc, renderTargetMsk, cmp->method); + + // back render targets to the pool + releaseRenderTarget(renderTargetSrc); + releaseRenderTarget(renderTargetMsk); + } + + // delete current compositor + delete mCompositorStack.last(); + mCompositorStack.pop(); + + return true; +} + + +WgRenderTarget* WgRenderer::allocateRenderTarget() +{ + WgRenderTarget* renderTarget = nullptr; + if (mRenderTargetPool.count > 0) { + renderTarget = mRenderTargetPool.last(); + mRenderTargetPool.pop(); + } else { + renderTarget = new WgRenderTarget; + renderTarget->initialize(mContext, mPipelines, mTargetSurface.w, mTargetSurface.h); + } + return renderTarget; +} + + +void WgRenderer::releaseRenderTarget(WgRenderTarget* renderTarget) +{ + mRenderTargetPool.push(renderTarget); } diff --git a/src/renderer/wg_engine/tvgWgRenderer.h b/src/renderer/wg_engine/tvgWgRenderer.h index 19058bc2..31b85c08 100644 --- a/src/renderer/wg_engine/tvgWgRenderer.h +++ b/src/renderer/wg_engine/tvgWgRenderer.h @@ -60,11 +60,19 @@ public: static bool init(uint32_t threads); static bool term(); + // render handles + WGPUCommandEncoder mCommandEncoder{}; + Array mRenderTargetStack; + Array mRenderTargetPool; + Array mCompositorStack; + + WgRenderTarget* allocateRenderTarget(); + void releaseRenderTarget(WgRenderTarget* renderTarget); private: - Array mRenderDatas{}; WgContext mContext; WgPipelines mPipelines; - WgRenderTarget mRenderTarget; + WgRenderTarget mRenderTargetRoot; + WgRenderTarget mRenderTargetWnd; WGPUSurface mSurface{}; WGPUSwapChain mSwapChain{}; Surface mTargetSurface; diff --git a/src/renderer/wg_engine/tvgWgShaderSrc.cpp b/src/renderer/wg_engine/tvgWgShaderSrc.cpp index 59d30831..6ab2fafb 100644 --- a/src/renderer/wg_engine/tvgWgShaderSrc.cpp +++ b/src/renderer/wg_engine/tvgWgShaderSrc.cpp @@ -334,3 +334,373 @@ fn fs_main(in: VertexOutput) -> @location(0) vec4f { return vec4f(result.rgb, result.a * uBlendSettigs.opacity); }; )"; + +//************************************************************************ +// cShaderSource_PipelineBlit +//************************************************************************ + +const char* cShaderSource_PipelineBlit = R"( +// vertex input +struct VertexInput { + @location(0) position: vec2f, + @location(1) texCoord: vec2f +}; + +// vertex output +struct VertexOutput { + @builtin(position) position: vec4f, + @location(0) texCoord: vec2f +}; + +@group(0) @binding(0) var uSamplerSrc : sampler; +@group(0) @binding(1) var uTextureViewSrc : texture_2d; + +@vertex +fn vs_main(in: VertexInput) -> VertexOutput { + // fill output + 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(uTextureViewSrc, uSamplerSrc, in.texCoord.xy); +}; +)"; + +//************************************************************************ +// cShaderSource_PipelineBlitColor +//************************************************************************ + +const char* cShaderSource_PipelineBlitColor = R"( +// vertex input +struct VertexInput { + @location(0) position: vec2f, + @location(1) texCoord: vec2f +}; + +// vertex output +struct VertexOutput { + @builtin(position) position: vec4f, + @location(0) texCoord: vec2f +}; + +@group(0) @binding(0) var uSamplerSrc : sampler; +@group(0) @binding(1) var uTextureViewSrc : texture_2d; + +@vertex +fn vs_main(in: VertexInput) -> VertexOutput { + // fill output + 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 { + let color: vec4f = textureSample(uTextureViewSrc, uSamplerSrc, in.texCoord.xy); + return vec4f(color.rgb, 1.0); +}; +)"; + +//************************************************************************ +// cShaderSource_PipelineCompAlphaMask +//************************************************************************ + +const char* cShaderSource_PipelineCompAlphaMask = R"( +// vertex input +struct VertexInput { + @location(0) position: vec2f, + @location(1) texCoord: vec2f +}; + +// vertex output +struct VertexOutput { + @builtin(position) position: vec4f, + @location(0) texCoord: vec2f +}; + +@group(0) @binding(0) var uSamplerSrc : sampler; +@group(0) @binding(1) var uTextureViewSrc : texture_2d; +@group(1) @binding(0) var uSamplerMsk : sampler; +@group(1) @binding(1) var uTextureViewMsk : texture_2d; + +@vertex +fn vs_main(in: VertexInput) -> VertexOutput { + // fill output + 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 { + let colorSrc: vec4f = textureSample(uTextureViewSrc, uSamplerSrc, in.texCoord.xy); + let colorMsk: vec4f = textureSample(uTextureViewMsk, uSamplerMsk, in.texCoord.xy); + return vec4f(colorSrc.rgb, colorSrc.a * colorMsk.a); +}; +)"; + +const char* cShaderSource_PipelineCompInvAlphaMask = R"( +// vertex input +struct VertexInput { + @location(0) position: vec2f, + @location(1) texCoord: vec2f +}; + +// vertex output +struct VertexOutput { + @builtin(position) position: vec4f, + @location(0) texCoord: vec2f +}; + +@group(0) @binding(0) var uSamplerSrc : sampler; +@group(0) @binding(1) var uTextureViewSrc : texture_2d; +@group(1) @binding(0) var uSamplerMsk : sampler; +@group(1) @binding(1) var uTextureViewMsk : texture_2d; + +@vertex +fn vs_main(in: VertexInput) -> VertexOutput { + // fill output + 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 { + let colorSrc: vec4f = textureSample(uTextureViewSrc, uSamplerSrc, in.texCoord.xy); + let colorMsk: vec4f = textureSample(uTextureViewMsk, uSamplerMsk, in.texCoord.xy); + return vec4f(colorSrc.rgb, colorSrc.a * (1.0 - colorMsk.a)); +}; +)"; + +const char* cShaderSource_PipelineCompLumaMask = R"( +// vertex input +struct VertexInput { + @location(0) position: vec2f, + @location(1) texCoord: vec2f +}; + +// vertex output +struct VertexOutput { + @builtin(position) position: vec4f, + @location(0) texCoord: vec2f +}; + +@group(0) @binding(0) var uSamplerSrc : sampler; +@group(0) @binding(1) var uTextureViewSrc : texture_2d; +@group(1) @binding(0) var uSamplerMsk : sampler; +@group(1) @binding(1) var uTextureViewMsk : texture_2d; + +@vertex +fn vs_main(in: VertexInput) -> VertexOutput { + // fill output + 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 { + let colorSrc: vec4f = textureSample(uTextureViewSrc, uSamplerSrc, in.texCoord.xy); + let colorMsk: vec4f = textureSample(uTextureViewMsk, uSamplerMsk, in.texCoord.xy); + let luma: f32 = (0.299 * colorMsk.r + 0.587 * colorMsk.g + 0.114 * colorMsk.b); + return colorSrc * luma; +}; +)"; + +const char* cShaderSource_PipelineCompInvLumaMask = R"( +// vertex input +struct VertexInput { + @location(0) position: vec2f, + @location(1) texCoord: vec2f +}; + +// vertex output +struct VertexOutput { + @builtin(position) position: vec4f, + @location(0) texCoord: vec2f +}; + +@group(0) @binding(0) var uSamplerSrc : sampler; +@group(0) @binding(1) var uTextureViewSrc : texture_2d; +@group(1) @binding(0) var uSamplerMsk : sampler; +@group(1) @binding(1) var uTextureViewMsk : texture_2d; + +@vertex +fn vs_main(in: VertexInput) -> VertexOutput { + // fill output + 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 { + let colorSrc: vec4f = textureSample(uTextureViewSrc, uSamplerSrc, in.texCoord.xy); + let colorMsk: vec4f = textureSample(uTextureViewMsk, uSamplerMsk, in.texCoord.xy); + let luma: f32 = (0.299 * colorMsk.r + 0.587 * colorMsk.g + 0.114 * colorMsk.b); + return colorSrc * (1.0 - luma); +}; +)"; + +const char* cShaderSource_PipelineCompAddMask = R"( +// vertex input +struct VertexInput { + @location(0) position: vec2f, + @location(1) texCoord: vec2f +}; + +// vertex output +struct VertexOutput { + @builtin(position) position: vec4f, + @location(0) texCoord: vec2f +}; + +@group(0) @binding(0) var uSamplerSrc : sampler; +@group(0) @binding(1) var uTextureViewSrc : texture_2d; +@group(1) @binding(0) var uSamplerMsk : sampler; +@group(1) @binding(1) var uTextureViewMsk : texture_2d; + +@vertex +fn vs_main(in: VertexInput) -> VertexOutput { + // fill output + 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 { + let colorSrc: vec4f = textureSample(uTextureViewSrc, uSamplerSrc, in.texCoord.xy); + let colorMsk: vec4f = textureSample(uTextureViewMsk, uSamplerMsk, in.texCoord.xy); + let color: vec4f = colorSrc + colorMsk * (1.0 - colorSrc.a); + return min(color, vec4f(1.0)); +}; +)"; + +const char* cShaderSource_PipelineCompSubtractMask = R"( +// vertex input +struct VertexInput { + @location(0) position: vec2f, + @location(1) texCoord: vec2f +}; + +// vertex output +struct VertexOutput { + @builtin(position) position: vec4f, + @location(0) texCoord: vec2f +}; + +@group(0) @binding(0) var uSamplerSrc : sampler; +@group(0) @binding(1) var uTextureViewSrc : texture_2d; +@group(1) @binding(0) var uSamplerMsk : sampler; +@group(1) @binding(1) var uTextureViewMsk : texture_2d; + +@vertex +fn vs_main(in: VertexInput) -> VertexOutput { + // fill output + 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 { + let colorSrc: vec4f = textureSample(uTextureViewSrc, uSamplerSrc, in.texCoord.xy); + let colorMsk: vec4f = textureSample(uTextureViewMsk, uSamplerMsk, in.texCoord.xy); + + let a: f32 = colorSrc.a - colorMsk.a; + if (a <= 0.0) { + return vec4f(0.0, 0.0, 0.0, 0.0); + } else { + return vec4f(colorSrc.rgb, colorSrc.a * a); + } +}; +)"; + +const char* cShaderSource_PipelineCompIntersectMask = R"( +// vertex input +struct VertexInput { + @location(0) position: vec2f, + @location(1) texCoord: vec2f +}; + +// vertex output +struct VertexOutput { + @builtin(position) position: vec4f, + @location(0) texCoord: vec2f +}; + +@group(0) @binding(0) var uSamplerSrc : sampler; +@group(0) @binding(1) var uTextureViewSrc : texture_2d; +@group(1) @binding(0) var uSamplerMsk : sampler; +@group(1) @binding(1) var uTextureViewMsk : texture_2d; + +@vertex +fn vs_main(in: VertexInput) -> VertexOutput { + // fill output + 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 { + let colorSrc: vec4f = textureSample(uTextureViewSrc, uSamplerSrc, in.texCoord.xy); + let colorMsk: vec4f = textureSample(uTextureViewMsk, uSamplerMsk, in.texCoord.xy); + let intAlpha: f32 = colorSrc.a * colorMsk.a; + return vec4f(colorMsk.rgb, colorMsk.a * intAlpha); +}; +)"; + +const char* cShaderSource_PipelineCompDifferenceMask = R"( +// vertex input +struct VertexInput { + @location(0) position: vec2f, + @location(1) texCoord: vec2f +}; + +// vertex output +struct VertexOutput { + @builtin(position) position: vec4f, + @location(0) texCoord: vec2f +}; + +@group(0) @binding(0) var uSamplerSrc : sampler; +@group(0) @binding(1) var uTextureViewSrc : texture_2d; +@group(1) @binding(0) var uSamplerMsk : sampler; +@group(1) @binding(1) var uTextureViewMsk : texture_2d; + +@vertex +fn vs_main(in: VertexInput) -> VertexOutput { + // fill output + 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 { + let colorSrc: vec4f = textureSample(uTextureViewSrc, uSamplerSrc, in.texCoord.xy); + let colorMsk: vec4f = textureSample(uTextureViewMsk, uSamplerMsk, in.texCoord.xy); + let da: f32 = colorSrc.a - colorMsk.a; + if (da > 0.0) { + return vec4f(colorSrc.rgb, colorSrc.a * da); + } else { + return vec4f(colorMsk.rgb, colorMsk.a * (-da)); + } +}; +)"; diff --git a/src/renderer/wg_engine/tvgWgShaderSrc.h b/src/renderer/wg_engine/tvgWgShaderSrc.h index dad0c571..dfdebd26 100644 --- a/src/renderer/wg_engine/tvgWgShaderSrc.h +++ b/src/renderer/wg_engine/tvgWgShaderSrc.h @@ -40,4 +40,18 @@ extern const char* cShaderSource_PipelineRadial; // pipeline shader module image extern const char* cShaderSource_PipelineImage; +// pipeline shader module blit +extern const char* cShaderSource_PipelineBlit; +extern const char* cShaderSource_PipelineBlitColor; + +// pipeline shader module composes +extern const char* cShaderSource_PipelineCompAlphaMask; +extern const char* cShaderSource_PipelineCompInvAlphaMask; +extern const char* cShaderSource_PipelineCompLumaMask; +extern const char* cShaderSource_PipelineCompInvLumaMask; +extern const char* cShaderSource_PipelineCompAddMask; +extern const char* cShaderSource_PipelineCompSubtractMask; +extern const char* cShaderSource_PipelineCompIntersectMask; +extern const char* cShaderSource_PipelineCompDifferenceMask; + #endif // _TVG_WG_SHADER_SRC_H_