mirror of
https://github.com/thorvg/thorvg.git
synced 2025-06-14 12:04:29 +00:00
wg_engine: introduced composition ability
[issues 1479: Masking](#1479) Supported composition methods: AlphaMask InvAlphaMask LumaMask InvLumaMask AddMask SubtractMask IntersectMask DifferenceMask Usage example: //Solid Rectangle auto shape = tvg::Shape::gen(); shape->appendRect(0, 0, 400, 400); shape->fill(0, 0, 255); //Mask auto mask = tvg::Shape::gen(); mask->appendCircle(200, 200, 125, 125); mask->fill(255, 255, 255); //AlphaMask RGB channels are unused. //Nested Mask auto nMask = tvg::Shape::gen(); nMask->appendCircle(220, 220, 125, 125); nMask->fill(255, 255, 255); //AlphaMask RGB channels are unused. mask->composite(std::move(nMask), tvg::CompositeMethod::AlphaMask); shape->composite(std::move(mask), tvg::CompositeMethod::AlphaMask); canvas->push(std::move(shape)); //Star auto star = tvg::Shape::gen(); star->fill(80, 80, 80); star->moveTo(599, 34); star->lineTo(653, 143); star->lineTo(774, 160); star->lineTo(687, 244); star->lineTo(707, 365); star->lineTo(599, 309); star->lineTo(497, 365); star->lineTo(512, 245); star->lineTo(426, 161); star->lineTo(546, 143); star->close(); star->strokeWidth(30); star->strokeJoin(tvg::StrokeJoin::Miter); star->strokeFill(255, 255, 255); //Mask3 auto mask3 = tvg::Shape::gen(); mask3->appendCircle(600, 200, 125, 125); mask3->fill(255, 255, 255); //AlphaMask RGB channels are unused. mask3->opacity(200); star->composite(std::move(mask3), tvg::CompositeMethod::AlphaMask); if (canvas->push(std::move(star)) != tvg::Result::Success) return;
This commit is contained in:
parent
ca0a1b909a
commit
af6969e15e
13 changed files with 811 additions and 103 deletions
|
@ -29,7 +29,7 @@ WGPUBindGroupLayout WgBindGroupSolidColor::layout = nullptr;
|
||||||
WGPUBindGroupLayout WgBindGroupLinearGradient::layout = nullptr;
|
WGPUBindGroupLayout WgBindGroupLinearGradient::layout = nullptr;
|
||||||
WGPUBindGroupLayout WgBindGroupRadialGradient::layout = nullptr;
|
WGPUBindGroupLayout WgBindGroupRadialGradient::layout = nullptr;
|
||||||
WGPUBindGroupLayout WgBindGroupPicture::layout = nullptr;
|
WGPUBindGroupLayout WgBindGroupPicture::layout = nullptr;
|
||||||
WGPUBindGroupLayout WgBindGroupCompose::layout = nullptr;
|
WGPUBindGroupLayout WgBindGroupBlit::layout = nullptr;
|
||||||
|
|
||||||
|
|
||||||
WGPUBindGroupLayout WgBindGroupCanvas::getLayout(WGPUDevice device)
|
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;
|
if (layout) return layout;
|
||||||
const WGPUBindGroupLayoutEntry bindGroupLayoutEntries[] {
|
const WGPUBindGroupLayoutEntry bindGroupLayoutEntries[] {
|
||||||
makeBindGroupLayoutEntrySampler(0),
|
makeBindGroupLayoutEntrySampler(0),
|
||||||
makeBindGroupLayoutEntryTextureView(1),
|
makeBindGroupLayoutEntryTextureView(1)
|
||||||
makeBindGroupLayoutEntryTextureView(2)
|
|
||||||
};
|
};
|
||||||
layout = createBindGroupLayout(device, bindGroupLayoutEntries, 3);
|
layout = createBindGroupLayout(device, bindGroupLayoutEntries, 2);
|
||||||
assert(layout);
|
assert(layout);
|
||||||
return layout;
|
return layout;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void WgBindGroupCompose::releaseLayout()
|
void WgBindGroupBlit::releaseLayout()
|
||||||
{
|
{
|
||||||
releaseBindGroupLayout(layout);
|
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();
|
release();
|
||||||
const WGPUBindGroupEntry bindGroupEntries[] {
|
const WGPUBindGroupEntry bindGroupEntries[] {
|
||||||
makeBindGroupEntrySampler(0, uSampler),
|
makeBindGroupEntrySampler(0, uSampler),
|
||||||
makeBindGroupEntryTextureView(1, uTextureSrc),
|
makeBindGroupEntryTextureView(1, uTexture)
|
||||||
makeBindGroupEntryTextureView(2, uTextureDst)
|
|
||||||
};
|
};
|
||||||
mBindGroup = createBindGroup(device, getLayout(device), bindGroupEntries, 3);
|
mBindGroup = createBindGroup(device, getLayout(device), bindGroupEntries, 2);
|
||||||
assert(mBindGroup);
|
assert(mBindGroup);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void WgBindGroupCompose::release()
|
void WgBindGroupBlit::release()
|
||||||
{
|
{
|
||||||
releaseBindGroup(mBindGroup);
|
releaseBindGroup(mBindGroup);
|
||||||
}
|
}
|
|
@ -107,8 +107,8 @@ struct WgBindGroupPicture : public WgBindGroup
|
||||||
void release();
|
void release();
|
||||||
};
|
};
|
||||||
|
|
||||||
// @group(2)
|
// @group(0 or 1)
|
||||||
struct WgBindGroupCompose : public WgBindGroup
|
struct WgBindGroupBlit : public WgBindGroup
|
||||||
{
|
{
|
||||||
static WGPUBindGroupLayout layout;
|
static WGPUBindGroupLayout layout;
|
||||||
static WGPUBindGroupLayout getLayout(WGPUDevice device);
|
static WGPUBindGroupLayout getLayout(WGPUDevice device);
|
||||||
|
@ -116,8 +116,7 @@ struct WgBindGroupCompose : public WgBindGroup
|
||||||
|
|
||||||
void initialize(WGPUDevice device, WGPUQueue queue,
|
void initialize(WGPUDevice device, WGPUQueue queue,
|
||||||
WGPUSampler uSampler,
|
WGPUSampler uSampler,
|
||||||
WGPUTextureView uTextureSrc,
|
WGPUTextureView uTexture);
|
||||||
WGPUTextureView uTextureDst);
|
|
||||||
void release();
|
void release();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -313,8 +313,8 @@ WGPUBlendState WgPipeline::makeBlendState()
|
||||||
blendState.color.srcFactor = WGPUBlendFactor_SrcAlpha;
|
blendState.color.srcFactor = WGPUBlendFactor_SrcAlpha;
|
||||||
blendState.color.dstFactor = WGPUBlendFactor_OneMinusSrcAlpha;
|
blendState.color.dstFactor = WGPUBlendFactor_OneMinusSrcAlpha;
|
||||||
blendState.alpha.operation = WGPUBlendOperation_Add;
|
blendState.alpha.operation = WGPUBlendOperation_Add;
|
||||||
blendState.alpha.srcFactor = WGPUBlendFactor_Zero;
|
blendState.alpha.srcFactor = WGPUBlendFactor_One;
|
||||||
blendState.alpha.dstFactor = WGPUBlendFactor_One;
|
blendState.alpha.dstFactor = WGPUBlendFactor_Zero;
|
||||||
return blendState;
|
return blendState;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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)
|
void WgGeometryData::appendMesh(const RenderMesh* rmesh)
|
||||||
{
|
{
|
||||||
assert(rmesh);
|
assert(rmesh);
|
||||||
|
|
|
@ -90,6 +90,7 @@ struct WgGeometryData
|
||||||
void appendRect(WgPoint p0, WgPoint p1, WgPoint p2, WgPoint p3);
|
void appendRect(WgPoint p0, WgPoint p1, WgPoint p2, WgPoint p3);
|
||||||
void appendCircle(WgPoint center, float radius);
|
void appendCircle(WgPoint center, float radius);
|
||||||
void appendImageBox(float w, float h);
|
void appendImageBox(float w, float h);
|
||||||
|
void appendBlitBox();
|
||||||
void appendMesh(const RenderMesh* rmesh);
|
void appendMesh(const RenderMesh* rmesh);
|
||||||
void close();
|
void close();
|
||||||
};
|
};
|
||||||
|
|
|
@ -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
|
// pipelines
|
||||||
//************************************************************************
|
//************************************************************************
|
||||||
|
|
||||||
void WgPipelines::initialize(WGPUDevice device)
|
void WgPipelines::initialize(WGPUDevice device)
|
||||||
{
|
{
|
||||||
mPipelineFillShape.initialize(device);
|
fillShape.initialize(device);
|
||||||
mPipelineFillStroke.initialize(device);
|
fillStroke.initialize(device);
|
||||||
mPipelineSolid.initialize(device);
|
solid.initialize(device);
|
||||||
mPipelineLinear.initialize(device);
|
linear.initialize(device);
|
||||||
mPipelineRadial.initialize(device);
|
radial.initialize(device);
|
||||||
mPipelineImage.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()
|
void WgPipelines::release()
|
||||||
{
|
{
|
||||||
WgBindGroupCompose::releaseLayout();
|
WgBindGroupBlit::releaseLayout();
|
||||||
WgBindGroupPicture::releaseLayout();
|
WgBindGroupPicture::releaseLayout();
|
||||||
WgBindGroupRadialGradient::releaseLayout();
|
WgBindGroupRadialGradient::releaseLayout();
|
||||||
WgBindGroupLinearGradient::releaseLayout();
|
WgBindGroupLinearGradient::releaseLayout();
|
||||||
WgBindGroupSolidColor::releaseLayout();
|
WgBindGroupSolidColor::releaseLayout();
|
||||||
WgBindGroupCanvas::releaseLayout();
|
WgBindGroupCanvas::releaseLayout();
|
||||||
mPipelineImage.release();
|
compDifferenceMask.release();
|
||||||
mPipelineRadial.release();
|
compIntersectMask.release();
|
||||||
mPipelineLinear.release();
|
compSubtractMask.release();
|
||||||
mPipelineSolid.release();
|
compAddMask.release();
|
||||||
mPipelineFillStroke.release();
|
compInvLumaMask.release();
|
||||||
mPipelineFillShape.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;
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
struct WgPipelines
|
||||||
{
|
{
|
||||||
WgPipelineFillShape mPipelineFillShape;
|
WgPipelineFillShape fillShape;
|
||||||
WgPipelineFillStroke mPipelineFillStroke;
|
WgPipelineFillStroke fillStroke;
|
||||||
WgPipelineSolid mPipelineSolid;
|
WgPipelineSolid solid;
|
||||||
WgPipelineLinear mPipelineLinear;
|
WgPipelineLinear linear;
|
||||||
WgPipelineRadial mPipelineRadial;
|
WgPipelineRadial radial;
|
||||||
WgPipelineImage mPipelineImage;
|
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 initialize(WGPUDevice device);
|
||||||
void release();
|
void release();
|
||||||
|
|
||||||
|
WgPipelineComposition* getCompositionPipeline(CompositeMethod method);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // _TVG_WG_PIPELINES_H_
|
#endif // _TVG_WG_PIPELINES_H_
|
||||||
|
|
|
@ -39,8 +39,8 @@ void WgRenderTarget::initialize(WgContext& context, WgPipelines& pipelines, uint
|
||||||
samplerDesc.lodMaxClamp = 32.0f;
|
samplerDesc.lodMaxClamp = 32.0f;
|
||||||
samplerDesc.compare = WGPUCompareFunction_Undefined;
|
samplerDesc.compare = WGPUCompareFunction_Undefined;
|
||||||
samplerDesc.maxAnisotropy = 1;
|
samplerDesc.maxAnisotropy = 1;
|
||||||
mSampler = wgpuDeviceCreateSampler(context.device, &samplerDesc);
|
sampler = wgpuDeviceCreateSampler(context.device, &samplerDesc);
|
||||||
assert(mSampler);
|
assert(sampler);
|
||||||
// texture descriptor
|
// texture descriptor
|
||||||
WGPUTextureDescriptor textureDescColor{};
|
WGPUTextureDescriptor textureDescColor{};
|
||||||
textureDescColor.nextInChain = nullptr;
|
textureDescColor.nextInChain = nullptr;
|
||||||
|
@ -48,7 +48,7 @@ void WgRenderTarget::initialize(WgContext& context, WgPipelines& pipelines, uint
|
||||||
textureDescColor.usage = WGPUTextureUsage_RenderAttachment | WGPUTextureUsage_TextureBinding | WGPUTextureUsage_CopyDst;
|
textureDescColor.usage = WGPUTextureUsage_RenderAttachment | WGPUTextureUsage_TextureBinding | WGPUTextureUsage_CopyDst;
|
||||||
textureDescColor.dimension = WGPUTextureDimension_2D;
|
textureDescColor.dimension = WGPUTextureDimension_2D;
|
||||||
textureDescColor.size = { w, h, 1 };
|
textureDescColor.size = { w, h, 1 };
|
||||||
textureDescColor.format = WGPUTextureFormat_RGBA8Unorm;
|
textureDescColor.format = WGPUTextureFormat_BGRA8Unorm;
|
||||||
textureDescColor.mipLevelCount = 1;
|
textureDescColor.mipLevelCount = 1;
|
||||||
textureDescColor.sampleCount = 1;
|
textureDescColor.sampleCount = 1;
|
||||||
textureDescColor.viewFormatCount = 0;
|
textureDescColor.viewFormatCount = 0;
|
||||||
|
@ -59,15 +59,15 @@ void WgRenderTarget::initialize(WgContext& context, WgPipelines& pipelines, uint
|
||||||
WGPUTextureViewDescriptor textureViewDescColor{};
|
WGPUTextureViewDescriptor textureViewDescColor{};
|
||||||
textureViewDescColor.nextInChain = nullptr;
|
textureViewDescColor.nextInChain = nullptr;
|
||||||
textureViewDescColor.label = "The target texture view color";
|
textureViewDescColor.label = "The target texture view color";
|
||||||
textureViewDescColor.format = WGPUTextureFormat_RGBA8Unorm;
|
textureViewDescColor.format = WGPUTextureFormat_BGRA8Unorm;
|
||||||
textureViewDescColor.dimension = WGPUTextureViewDimension_2D;
|
textureViewDescColor.dimension = WGPUTextureViewDimension_2D;
|
||||||
textureViewDescColor.baseMipLevel = 0;
|
textureViewDescColor.baseMipLevel = 0;
|
||||||
textureViewDescColor.mipLevelCount = 1;
|
textureViewDescColor.mipLevelCount = 1;
|
||||||
textureViewDescColor.baseArrayLayer = 0;
|
textureViewDescColor.baseArrayLayer = 0;
|
||||||
textureViewDescColor.arrayLayerCount = 1;
|
textureViewDescColor.arrayLayerCount = 1;
|
||||||
textureViewDescColor.aspect = WGPUTextureAspect_All;
|
textureViewDescColor.aspect = WGPUTextureAspect_All;
|
||||||
mTextureViewColor = wgpuTextureCreateView(mTextureColor, &textureViewDescColor);
|
textureViewColor = wgpuTextureCreateView(mTextureColor, &textureViewDescColor);
|
||||||
assert(mTextureViewColor);
|
assert(textureViewColor);
|
||||||
// stencil texture
|
// stencil texture
|
||||||
WGPUTextureDescriptor textureDescStencil{};
|
WGPUTextureDescriptor textureDescStencil{};
|
||||||
textureDescStencil.nextInChain = nullptr;
|
textureDescStencil.nextInChain = nullptr;
|
||||||
|
@ -93,49 +93,56 @@ void WgRenderTarget::initialize(WgContext& context, WgPipelines& pipelines, uint
|
||||||
textureViewDescStencil.baseArrayLayer = 0;
|
textureViewDescStencil.baseArrayLayer = 0;
|
||||||
textureViewDescStencil.arrayLayerCount = 1;
|
textureViewDescStencil.arrayLayerCount = 1;
|
||||||
textureViewDescStencil.aspect = WGPUTextureAspect_All;
|
textureViewDescStencil.aspect = WGPUTextureAspect_All;
|
||||||
mTextureViewStencil = wgpuTextureCreateView(mTextureStencil, &textureViewDescStencil);
|
textureViewStencil = wgpuTextureCreateView(mTextureStencil, &textureViewDescStencil);
|
||||||
assert(mTextureViewStencil);
|
assert(textureViewStencil);
|
||||||
|
// initialize bind group for blitting
|
||||||
|
bindGroupBlit.initialize(context.device, context.queue, sampler, textureViewColor);
|
||||||
// initialize window binding groups
|
// initialize window binding groups
|
||||||
WgShaderTypeMat4x4f viewMat(w, h);
|
WgShaderTypeMat4x4f viewMat(w, h);
|
||||||
mBindGroupCanvasWnd.initialize(context.device, context.queue, viewMat);
|
mBindGroupCanvasWnd.initialize(context.device, context.queue, viewMat);
|
||||||
|
WgGeometryData geometryDataWnd;
|
||||||
|
geometryDataWnd.appendBlitBox();
|
||||||
|
mMeshDataCanvasWnd.update(context, &geometryDataWnd);
|
||||||
mPipelines = &pipelines;
|
mPipelines = &pipelines;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void WgRenderTarget::release(WgContext& context)
|
void WgRenderTarget::release(WgContext& context)
|
||||||
{
|
{
|
||||||
|
mMeshDataCanvasWnd.release(context);
|
||||||
mBindGroupCanvasWnd.release();
|
mBindGroupCanvasWnd.release();
|
||||||
|
bindGroupBlit.release();
|
||||||
if (mTextureStencil) {
|
if (mTextureStencil) {
|
||||||
wgpuTextureDestroy(mTextureStencil);
|
wgpuTextureDestroy(mTextureStencil);
|
||||||
wgpuTextureRelease(mTextureStencil);
|
wgpuTextureRelease(mTextureStencil);
|
||||||
mTextureStencil = nullptr;
|
mTextureStencil = nullptr;
|
||||||
}
|
}
|
||||||
if (mTextureViewStencil) wgpuTextureViewRelease(mTextureViewStencil);
|
if (textureViewStencil) wgpuTextureViewRelease(textureViewStencil);
|
||||||
mTextureViewStencil = nullptr;
|
textureViewStencil = nullptr;
|
||||||
if (mTextureColor) {
|
if (mTextureColor) {
|
||||||
wgpuTextureDestroy(mTextureColor);
|
wgpuTextureDestroy(mTextureColor);
|
||||||
wgpuTextureRelease(mTextureColor);
|
wgpuTextureRelease(mTextureColor);
|
||||||
mTextureColor = nullptr;
|
mTextureColor = nullptr;
|
||||||
}
|
}
|
||||||
if (mTextureViewColor) wgpuTextureViewRelease(mTextureViewColor);
|
if (textureViewColor) wgpuTextureViewRelease(textureViewColor);
|
||||||
mTextureViewColor = nullptr;
|
textureViewColor = nullptr;
|
||||||
if (mSampler) wgpuSamplerRelease(mSampler);
|
if (sampler) wgpuSamplerRelease(sampler);
|
||||||
mSampler = nullptr;
|
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);
|
assert(!mRenderPassEncoder);
|
||||||
// render pass depth stencil attachment
|
// render pass depth stencil attachment
|
||||||
WGPURenderPassDepthStencilAttachment depthStencilAttachment{};
|
WGPURenderPassDepthStencilAttachment depthStencilAttachment{};
|
||||||
depthStencilAttachment.view = mTextureViewStencil;
|
depthStencilAttachment.view = textureViewStencil;
|
||||||
depthStencilAttachment.depthLoadOp = WGPULoadOp_Clear;
|
depthStencilAttachment.depthLoadOp = WGPULoadOp_Clear;
|
||||||
depthStencilAttachment.depthStoreOp = WGPUStoreOp_Store;
|
depthStencilAttachment.depthStoreOp = WGPUStoreOp_Store;
|
||||||
depthStencilAttachment.depthClearValue = 1.0f;
|
depthStencilAttachment.depthClearValue = 1.0f;
|
||||||
|
@ -148,8 +155,8 @@ void WgRenderTarget::beginRenderPass(WGPUCommandEncoder commandEncoder, WGPUText
|
||||||
WGPURenderPassColorAttachment colorAttachment{};
|
WGPURenderPassColorAttachment colorAttachment{};
|
||||||
colorAttachment.view = colorAttachement;
|
colorAttachment.view = colorAttachement;
|
||||||
colorAttachment.resolveTarget = nullptr;
|
colorAttachment.resolveTarget = nullptr;
|
||||||
colorAttachment.loadOp = WGPULoadOp_Clear;
|
colorAttachment.loadOp = clear ? WGPULoadOp_Clear : WGPULoadOp_Load;
|
||||||
colorAttachment.clearValue = {0, 0, 0, 0};
|
colorAttachment.clearValue = { 0, 0, 0, 0 };
|
||||||
colorAttachment.storeOp = WGPUStoreOp_Store;
|
colorAttachment.storeOp = WGPUStoreOp_Store;
|
||||||
// render pass descriptor
|
// render pass descriptor
|
||||||
WGPURenderPassDescriptor renderPassDesc{};
|
WGPURenderPassDescriptor renderPassDesc{};
|
||||||
|
@ -184,16 +191,16 @@ void WgRenderTarget::renderShape(WgRenderDataShape* renderData)
|
||||||
wgpuRenderPassEncoderSetStencilReference(mRenderPassEncoder, 0);
|
wgpuRenderPassEncoderSetStencilReference(mRenderPassEncoder, 0);
|
||||||
for (uint32_t i = 0; i < renderData->meshGroupShapes.meshes.count; i++) {
|
for (uint32_t i = 0; i < renderData->meshGroupShapes.meshes.count; i++) {
|
||||||
// draw to stencil (first pass)
|
// 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);
|
renderData->meshGroupShapes.meshes[i]->draw(mRenderPassEncoder);
|
||||||
// fill shape (second pass)
|
// fill shape (second pass)
|
||||||
WgRenderSettings& settings = renderData->renderSettingsShape;
|
WgRenderSettings& settings = renderData->renderSettingsShape;
|
||||||
if (settings.fillType == WgRenderSettingsType::Solid)
|
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)
|
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)
|
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);
|
renderData->meshBBoxShapes.draw(mRenderPassEncoder);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -208,18 +215,18 @@ void WgRenderTarget::renderStroke(WgRenderDataShape* renderData)
|
||||||
// draw strokes to stencil (first pass)
|
// draw strokes to stencil (first pass)
|
||||||
wgpuRenderPassEncoderSetStencilReference(mRenderPassEncoder, 255);
|
wgpuRenderPassEncoderSetStencilReference(mRenderPassEncoder, 255);
|
||||||
for (uint32_t i = 0; i < renderData->meshGroupStrokes.meshes.count; i++) {
|
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);
|
renderData->meshGroupStrokes.meshes[i]->draw(mRenderPassEncoder);
|
||||||
}
|
}
|
||||||
// fill shape (second pass)
|
// fill shape (second pass)
|
||||||
wgpuRenderPassEncoderSetStencilReference(mRenderPassEncoder, 0);
|
wgpuRenderPassEncoderSetStencilReference(mRenderPassEncoder, 0);
|
||||||
WgRenderSettings& settings = renderData->renderSettingsStroke;
|
WgRenderSettings& settings = renderData->renderSettingsStroke;
|
||||||
if (settings.fillType == WgRenderSettingsType::Solid)
|
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)
|
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)
|
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);
|
renderData->meshBBoxStrokes.draw(mRenderPassEncoder);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -231,7 +238,7 @@ void WgRenderTarget::renderPicture(WgRenderDataPicture* renderData)
|
||||||
assert(mRenderPassEncoder);
|
assert(mRenderPassEncoder);
|
||||||
if (renderData->meshData.bufferTexCoord) {
|
if (renderData->meshData.bufferTexCoord) {
|
||||||
wgpuRenderPassEncoderSetStencilReference(mRenderPassEncoder, 0);
|
wgpuRenderPassEncoderSetStencilReference(mRenderPassEncoder, 0);
|
||||||
mPipelines->mPipelineImage.use(
|
mPipelines->image.use(
|
||||||
mRenderPassEncoder,
|
mRenderPassEncoder,
|
||||||
mBindGroupCanvasWnd,
|
mBindGroupCanvasWnd,
|
||||||
renderData->bindGroupPaint,
|
renderData->bindGroupPaint,
|
||||||
|
@ -239,3 +246,29 @@ void WgRenderTarget::renderPicture(WgRenderDataPicture* renderData)
|
||||||
renderData->meshData.drawImage(mRenderPassEncoder);
|
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);
|
||||||
|
}
|
||||||
|
|
|
@ -31,24 +31,32 @@ private:
|
||||||
WGPURenderPassEncoder mRenderPassEncoder{};
|
WGPURenderPassEncoder mRenderPassEncoder{};
|
||||||
// fill and blit data
|
// fill and blit data
|
||||||
WgBindGroupCanvas mBindGroupCanvasWnd;
|
WgBindGroupCanvas mBindGroupCanvasWnd;
|
||||||
|
// composition handles
|
||||||
|
WgMeshData mMeshDataCanvasWnd;
|
||||||
// gpu buffers
|
// gpu buffers
|
||||||
WGPUSampler mSampler{};
|
|
||||||
WGPUTexture mTextureColor{};
|
WGPUTexture mTextureColor{};
|
||||||
WGPUTexture mTextureStencil{};
|
WGPUTexture mTextureStencil{};
|
||||||
WGPUTextureView mTextureViewColor{};
|
|
||||||
WGPUTextureView mTextureViewStencil{};
|
|
||||||
WgPipelines* mPipelines{}; // external handle
|
WgPipelines* mPipelines{}; // external handle
|
||||||
|
public:
|
||||||
|
WGPUSampler sampler{};
|
||||||
|
WGPUTextureView textureViewColor{};
|
||||||
|
WGPUTextureView textureViewStencil{};
|
||||||
|
WgBindGroupBlit bindGroupBlit;
|
||||||
public:
|
public:
|
||||||
void initialize(WgContext& context, WgPipelines& pipelines, uint32_t w, uint32_t h);
|
void initialize(WgContext& context, WgPipelines& pipelines, uint32_t w, uint32_t h);
|
||||||
void release(WgContext& context);
|
void release(WgContext& context);
|
||||||
|
|
||||||
void beginRenderPass(WGPUCommandEncoder commandEncoder, WGPUTextureView colorAttachement);
|
void beginRenderPass(WGPUCommandEncoder commandEncoder, WGPUTextureView colorAttachement, bool clear);
|
||||||
void beginRenderPass(WGPUCommandEncoder commandEncoder);
|
void beginRenderPass(WGPUCommandEncoder commandEncoder, bool clear);
|
||||||
void endRenderPass();
|
void endRenderPass();
|
||||||
|
|
||||||
void renderShape(WgRenderDataShape* renderData);
|
void renderShape(WgRenderDataShape* renderData);
|
||||||
void renderStroke(WgRenderDataShape* renderData);
|
void renderStroke(WgRenderDataShape* renderData);
|
||||||
void renderPicture(WgRenderDataPicture* 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
|
#endif
|
||||||
|
|
|
@ -48,7 +48,14 @@ void WgRenderer::initialize()
|
||||||
|
|
||||||
void WgRenderer::release()
|
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 (mSwapChain) wgpuSwapChainRelease(mSwapChain);
|
||||||
if (mSurface) wgpuSurfaceRelease(mSurface);
|
if (mSurface) wgpuSurfaceRelease(mSurface);
|
||||||
mPipelines.release();
|
mPipelines.release();
|
||||||
|
@ -123,26 +130,39 @@ RenderData WgRenderer::prepare(Surface* surface, const RenderMesh* mesh, RenderD
|
||||||
|
|
||||||
bool WgRenderer::preRender()
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool WgRenderer::renderShape(RenderData data)
|
bool WgRenderer::renderShape(RenderData data)
|
||||||
{
|
{
|
||||||
mRenderDatas.push(data);
|
mRenderTargetStack.last()->renderShape((WgRenderDataShape *)data);
|
||||||
|
mRenderTargetStack.last()->renderStroke((WgRenderDataShape *)data);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool WgRenderer::renderImage(RenderData data)
|
bool WgRenderer::renderImage(RenderData data)
|
||||||
{
|
{
|
||||||
mRenderDatas.push(data);
|
mRenderTargetStack.last()->renderPicture((WgRenderDataPicture *)data);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool WgRenderer::postRender()
|
bool WgRenderer::postRender()
|
||||||
{
|
{
|
||||||
|
mRenderTargetRoot.endRenderPass();
|
||||||
|
mRenderTargetStack.pop();
|
||||||
|
mContext.executeCommandEncoder(mCommandEncoder);
|
||||||
|
wgpuCommandEncoderRelease(mCommandEncoder);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -193,35 +213,17 @@ bool WgRenderer::clear()
|
||||||
bool WgRenderer::sync()
|
bool WgRenderer::sync()
|
||||||
{
|
{
|
||||||
WGPUTextureView backBufferView = wgpuSwapChainGetCurrentTextureView(mSwapChain);
|
WGPUTextureView backBufferView = wgpuSwapChainGetCurrentTextureView(mSwapChain);
|
||||||
|
|
||||||
// command encoder descriptor
|
|
||||||
WGPUCommandEncoderDescriptor commandEncoderDesc{};
|
WGPUCommandEncoderDescriptor commandEncoderDesc{};
|
||||||
commandEncoderDesc.nextInChain = nullptr;
|
commandEncoderDesc.nextInChain = nullptr;
|
||||||
commandEncoderDesc.label = "The command encoder";
|
commandEncoderDesc.label = "The command encoder";
|
||||||
WGPUCommandEncoder commandEncoder = wgpuDeviceCreateCommandEncoder(mContext.device, &commandEncoderDesc);
|
WGPUCommandEncoder commandEncoder = wgpuDeviceCreateCommandEncoder(mContext.device, &commandEncoderDesc);
|
||||||
|
mRenderTargetWnd.beginRenderPass(commandEncoder, backBufferView, true);
|
||||||
// render datas
|
mRenderTargetWnd.blitColor(mContext, &mRenderTargetRoot);
|
||||||
mRenderTarget.beginRenderPass(commandEncoder, backBufferView);
|
mRenderTargetWnd.endRenderPass();
|
||||||
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();
|
|
||||||
|
|
||||||
mContext.executeCommandEncoder(commandEncoder);
|
mContext.executeCommandEncoder(commandEncoder);
|
||||||
wgpuCommandEncoderRelease(commandEncoder);
|
wgpuCommandEncoderRelease(commandEncoder);
|
||||||
|
|
||||||
// go to the next frame
|
|
||||||
wgpuTextureViewRelease(backBufferView);
|
wgpuTextureViewRelease(backBufferView);
|
||||||
wgpuSwapChainPresent(mSwapChain);
|
wgpuSwapChainPresent(mSwapChain);
|
||||||
|
|
||||||
mRenderDatas.clear();
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -233,7 +235,7 @@ bool WgRenderer::target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t
|
||||||
mTargetSurface.w = w;
|
mTargetSurface.w = w;
|
||||||
mTargetSurface.h = h;
|
mTargetSurface.h = h;
|
||||||
|
|
||||||
// TODO: Add ability to render into offscreen buffer
|
mRenderTargetRoot.initialize(mContext, mPipelines, w, h);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -273,26 +275,99 @@ bool WgRenderer::target(void* window, uint32_t w, uint32_t h)
|
||||||
mSwapChain = wgpuDeviceCreateSwapChain(mContext.device, mSurface, &swapChainDesc);
|
mSwapChain = wgpuDeviceCreateSwapChain(mContext.device, mSurface, &swapChainDesc);
|
||||||
assert(mSwapChain);
|
assert(mSwapChain);
|
||||||
|
|
||||||
mRenderTarget.initialize(mContext, mPipelines, w, h);
|
mRenderTargetWnd.initialize(mContext, mPipelines, w, h);
|
||||||
|
mRenderTargetRoot.initialize(mContext, mPipelines, w, h);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Compositor* WgRenderer::target(TVG_UNUSED const RenderRegion& region, TVG_UNUSED ColorSpace cs)
|
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)
|
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)
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -60,11 +60,19 @@ public:
|
||||||
static bool init(uint32_t threads);
|
static bool init(uint32_t threads);
|
||||||
static bool term();
|
static bool term();
|
||||||
|
|
||||||
|
// render handles
|
||||||
|
WGPUCommandEncoder mCommandEncoder{};
|
||||||
|
Array<WgRenderTarget*> mRenderTargetStack;
|
||||||
|
Array<WgRenderTarget*> mRenderTargetPool;
|
||||||
|
Array<Compositor*> mCompositorStack;
|
||||||
|
|
||||||
|
WgRenderTarget* allocateRenderTarget();
|
||||||
|
void releaseRenderTarget(WgRenderTarget* renderTarget);
|
||||||
private:
|
private:
|
||||||
Array<RenderData> mRenderDatas{};
|
|
||||||
WgContext mContext;
|
WgContext mContext;
|
||||||
WgPipelines mPipelines;
|
WgPipelines mPipelines;
|
||||||
WgRenderTarget mRenderTarget;
|
WgRenderTarget mRenderTargetRoot;
|
||||||
|
WgRenderTarget mRenderTargetWnd;
|
||||||
WGPUSurface mSurface{};
|
WGPUSurface mSurface{};
|
||||||
WGPUSwapChain mSwapChain{};
|
WGPUSwapChain mSwapChain{};
|
||||||
Surface mTargetSurface;
|
Surface mTargetSurface;
|
||||||
|
|
|
@ -334,3 +334,373 @@ fn fs_main(in: VertexOutput) -> @location(0) vec4f {
|
||||||
return vec4f(result.rgb, result.a * uBlendSettigs.opacity);
|
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<f32>;
|
||||||
|
|
||||||
|
@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<f32>;
|
||||||
|
|
||||||
|
@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<f32>;
|
||||||
|
@group(1) @binding(0) var uSamplerMsk : sampler;
|
||||||
|
@group(1) @binding(1) var uTextureViewMsk : texture_2d<f32>;
|
||||||
|
|
||||||
|
@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<f32>;
|
||||||
|
@group(1) @binding(0) var uSamplerMsk : sampler;
|
||||||
|
@group(1) @binding(1) var uTextureViewMsk : texture_2d<f32>;
|
||||||
|
|
||||||
|
@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<f32>;
|
||||||
|
@group(1) @binding(0) var uSamplerMsk : sampler;
|
||||||
|
@group(1) @binding(1) var uTextureViewMsk : texture_2d<f32>;
|
||||||
|
|
||||||
|
@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<f32>;
|
||||||
|
@group(1) @binding(0) var uSamplerMsk : sampler;
|
||||||
|
@group(1) @binding(1) var uTextureViewMsk : texture_2d<f32>;
|
||||||
|
|
||||||
|
@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<f32>;
|
||||||
|
@group(1) @binding(0) var uSamplerMsk : sampler;
|
||||||
|
@group(1) @binding(1) var uTextureViewMsk : texture_2d<f32>;
|
||||||
|
|
||||||
|
@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<f32>;
|
||||||
|
@group(1) @binding(0) var uSamplerMsk : sampler;
|
||||||
|
@group(1) @binding(1) var uTextureViewMsk : texture_2d<f32>;
|
||||||
|
|
||||||
|
@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<f32>;
|
||||||
|
@group(1) @binding(0) var uSamplerMsk : sampler;
|
||||||
|
@group(1) @binding(1) var uTextureViewMsk : texture_2d<f32>;
|
||||||
|
|
||||||
|
@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<f32>;
|
||||||
|
@group(1) @binding(0) var uSamplerMsk : sampler;
|
||||||
|
@group(1) @binding(1) var uTextureViewMsk : texture_2d<f32>;
|
||||||
|
|
||||||
|
@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));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
)";
|
||||||
|
|
|
@ -40,4 +40,18 @@ extern const char* cShaderSource_PipelineRadial;
|
||||||
// pipeline shader module image
|
// pipeline shader module image
|
||||||
extern const char* cShaderSource_PipelineImage;
|
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_
|
#endif // _TVG_WG_SHADER_SRC_H_
|
||||||
|
|
Loading…
Add table
Reference in a new issue