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 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);
|
||||
}
|
|
@ -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();
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
};
|
||||
|
|
|
@ -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();
|
||||
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;
|
||||
}
|
|
@ -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_
|
||||
|
|
|
@ -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,7 +155,7 @@ void WgRenderTarget::beginRenderPass(WGPUCommandEncoder commandEncoder, WGPUText
|
|||
WGPURenderPassColorAttachment colorAttachment{};
|
||||
colorAttachment.view = colorAttachement;
|
||||
colorAttachment.resolveTarget = nullptr;
|
||||
colorAttachment.loadOp = WGPULoadOp_Clear;
|
||||
colorAttachment.loadOp = clear ? WGPULoadOp_Clear : WGPULoadOp_Load;
|
||||
colorAttachment.clearValue = { 0, 0, 0, 0 };
|
||||
colorAttachment.storeOp = WGPUStoreOp_Store;
|
||||
// render pass descriptor
|
||||
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -60,11 +60,19 @@ public:
|
|||
static bool init(uint32_t threads);
|
||||
static bool term();
|
||||
|
||||
// render handles
|
||||
WGPUCommandEncoder mCommandEncoder{};
|
||||
Array<WgRenderTarget*> mRenderTargetStack;
|
||||
Array<WgRenderTarget*> mRenderTargetPool;
|
||||
Array<Compositor*> mCompositorStack;
|
||||
|
||||
WgRenderTarget* allocateRenderTarget();
|
||||
void releaseRenderTarget(WgRenderTarget* renderTarget);
|
||||
private:
|
||||
Array<RenderData> mRenderDatas{};
|
||||
WgContext mContext;
|
||||
WgPipelines mPipelines;
|
||||
WgRenderTarget mRenderTarget;
|
||||
WgRenderTarget mRenderTargetRoot;
|
||||
WgRenderTarget mRenderTargetWnd;
|
||||
WGPUSurface mSurface{};
|
||||
WGPUSwapChain mSwapChain{};
|
||||
Surface mTargetSurface;
|
||||
|
|
|
@ -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<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
|
||||
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_
|
||||
|
|
Loading…
Add table
Reference in a new issue