mirror of
https://github.com/thorvg/thorvg.git
synced 2025-06-09 14:13:43 +00:00
wg_engine: ClipPath support
[issues 1479: ClipPath](#1479) Supports ClipPath composition. Clip path composition is an only composition type who doesn't ignore blend method. Clip path is a combination of composition approach and blend approach using compute shader
This commit is contained in:
parent
f06127ab93
commit
2c948a33d3
12 changed files with 530 additions and 45 deletions
|
@ -36,11 +36,15 @@ WGPUBindGroupLayout WgBindGroupTexture::layout = nullptr;
|
|||
WGPUBindGroupLayout WgBindGroupTextureStorageRgba::layout = nullptr;
|
||||
WGPUBindGroupLayout WgBindGroupTextureStorageBgra::layout = nullptr;
|
||||
WGPUBindGroupLayout WgBindGroupTextureSampled::layout = nullptr;
|
||||
WGPUBindGroupLayout WgBindGroupTexMaskCompose::layout = nullptr;
|
||||
WGPUBindGroupLayout WgBindGroupTexComposeBlend::layout = nullptr;
|
||||
WGPUBindGroupLayout WgBindGroupOpacity::layout = nullptr;
|
||||
WGPUBindGroupLayout WgBindGroupBlendMethod::layout = nullptr;
|
||||
WGPUBindGroupLayout WgBindGroupCompositeMethod::layout = nullptr;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// WgBindGroupCanvas
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
WGPUBindGroupLayout WgBindGroupCanvas::getLayout(WGPUDevice device)
|
||||
{
|
||||
|
@ -78,6 +82,9 @@ void WgBindGroupCanvas::release()
|
|||
releaseBuffer(uBufferViewMat);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// WgBindGroupPaint
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
WGPUBindGroupLayout WgBindGroupPaint::getLayout(WGPUDevice device)
|
||||
{
|
||||
|
@ -123,6 +130,9 @@ void WgBindGroupPaint::release()
|
|||
releaseBuffer(uBufferModelMat);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// WgBindGroupSolidColor
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
WGPUBindGroupLayout WgBindGroupSolidColor::getLayout(WGPUDevice device)
|
||||
{
|
||||
|
@ -163,6 +173,9 @@ void WgBindGroupSolidColor::release()
|
|||
releaseBuffer(uBufferSolidColor);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// WgBindGroupLinearGradient
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
WGPUBindGroupLayout WgBindGroupLinearGradient::getLayout(WGPUDevice device)
|
||||
{
|
||||
|
@ -203,6 +216,9 @@ void WgBindGroupLinearGradient::release()
|
|||
releaseBuffer(uBufferLinearGradient);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// WgBindGroupRadialGradient
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
WGPUBindGroupLayout WgBindGroupRadialGradient::getLayout(WGPUDevice device)
|
||||
{
|
||||
|
@ -243,6 +259,9 @@ void WgBindGroupRadialGradient::release()
|
|||
releaseBindGroup(mBindGroup);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// WgBindGroupPicture
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
WGPUBindGroupLayout WgBindGroupPicture::getLayout(WGPUDevice device)
|
||||
{
|
||||
|
@ -280,6 +299,9 @@ void WgBindGroupPicture::release()
|
|||
releaseBindGroup(mBindGroup);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// WgBindGroupTexture
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
WGPUBindGroupLayout WgBindGroupTexture::getLayout(WGPUDevice device)
|
||||
{
|
||||
|
@ -315,6 +337,9 @@ void WgBindGroupTexture::release()
|
|||
releaseBindGroup(mBindGroup);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// WgBindGroupTextureStorageRgba
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
WGPUBindGroupLayout WgBindGroupTextureStorageRgba::getLayout(WGPUDevice device)
|
||||
{
|
||||
|
@ -350,6 +375,9 @@ void WgBindGroupTextureStorageRgba::release()
|
|||
releaseBindGroup(mBindGroup);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// WgBindGroupTextureStorageBgra
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
WGPUBindGroupLayout WgBindGroupTextureStorageBgra::getLayout(WGPUDevice device)
|
||||
{
|
||||
|
@ -385,6 +413,9 @@ void WgBindGroupTextureStorageBgra::release()
|
|||
releaseBindGroup(mBindGroup);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// WgBindGroupTextureSampled
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
WGPUBindGroupLayout WgBindGroupTextureSampled::getLayout(WGPUDevice device)
|
||||
{
|
||||
|
@ -422,6 +453,9 @@ void WgBindGroupTextureSampled::release()
|
|||
releaseBindGroup(mBindGroup);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// WgBindGroupTexComposeBlend
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
WGPUBindGroupLayout WgBindGroupTexComposeBlend::getLayout(WGPUDevice device)
|
||||
{
|
||||
|
@ -461,7 +495,49 @@ void WgBindGroupTexComposeBlend::release()
|
|||
releaseBindGroup(mBindGroup);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// WgBindGroupTexMaskCompose
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
WGPUBindGroupLayout WgBindGroupTexMaskCompose::getLayout(WGPUDevice device)
|
||||
{
|
||||
if (layout) return layout;
|
||||
const WGPUBindGroupLayoutEntry bindGroupLayoutEntries[] {
|
||||
makeBindGroupLayoutEntryStorage(0, WGPUStorageTextureAccess_ReadOnly, WGPUTextureFormat_RGBA8Unorm),
|
||||
makeBindGroupLayoutEntryStorage(1, WGPUStorageTextureAccess_ReadWrite, WGPUTextureFormat_RGBA8Unorm)
|
||||
};
|
||||
layout = createBindGroupLayout(device, bindGroupLayoutEntries, 2);
|
||||
assert(layout);
|
||||
return layout;
|
||||
}
|
||||
|
||||
|
||||
void WgBindGroupTexMaskCompose::releaseLayout()
|
||||
{
|
||||
releaseBindGroupLayout(layout);
|
||||
}
|
||||
|
||||
|
||||
void WgBindGroupTexMaskCompose::initialize(WGPUDevice device, WGPUQueue queue, WGPUTextureView uTexMsk0, WGPUTextureView uTexMsk1)
|
||||
{
|
||||
release();
|
||||
const WGPUBindGroupEntry bindGroupEntries[] {
|
||||
makeBindGroupEntryTextureView(0, uTexMsk0),
|
||||
makeBindGroupEntryTextureView(1, uTexMsk1),
|
||||
};
|
||||
mBindGroup = createBindGroup(device, getLayout(device), bindGroupEntries, 2);
|
||||
assert(mBindGroup);
|
||||
}
|
||||
|
||||
|
||||
void WgBindGroupTexMaskCompose::release()
|
||||
{
|
||||
releaseBindGroup(mBindGroup);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// WgBindGroupOpacity
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
WGPUBindGroupLayout WgBindGroupOpacity::getLayout(WGPUDevice device)
|
||||
{
|
||||
|
@ -500,6 +576,9 @@ void WgBindGroupOpacity::release()
|
|||
releaseBindGroup(mBindGroup);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// WgBindGroupBlendMethod
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
WGPUBindGroupLayout WgBindGroupBlendMethod::getLayout(WGPUDevice device)
|
||||
{
|
||||
|
@ -538,6 +617,9 @@ void WgBindGroupBlendMethod::release()
|
|||
releaseBindGroup(mBindGroup);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// WgBindGroupCompositeMethod
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
WGPUBindGroupLayout WgBindGroupCompositeMethod::getLayout(WGPUDevice device)
|
||||
{
|
||||
|
|
|
@ -170,6 +170,20 @@ struct WgBindGroupTexComposeBlend : public WgBindGroup
|
|||
};
|
||||
|
||||
|
||||
// @group(0)
|
||||
struct WgBindGroupTexMaskCompose : public WgBindGroup
|
||||
{
|
||||
static WGPUBindGroupLayout layout;
|
||||
static WGPUBindGroupLayout getLayout(WGPUDevice device);
|
||||
static void releaseLayout();
|
||||
|
||||
void initialize(WGPUDevice device, WGPUQueue queue,
|
||||
WGPUTextureView uTexMsk0,
|
||||
WGPUTextureView uTexMsk1);
|
||||
void release();
|
||||
};
|
||||
|
||||
|
||||
// @group(1 or 2)
|
||||
struct WgBindGroupOpacity : public WgBindGroup
|
||||
{
|
||||
|
|
|
@ -49,7 +49,7 @@ void WgPipelineFillShapeWinding::initialize(WGPUDevice device)
|
|||
WGPUCompareFunction stencilFunctionBack = WGPUCompareFunction_Always;
|
||||
WGPUStencilOperation stencilOperationBack = WGPUStencilOperation_DecrementWrap;
|
||||
|
||||
// sheder source and labels
|
||||
// shader source and labels
|
||||
auto shaderSource = cShaderSource_PipelineFill;
|
||||
auto shaderLabel = "The shader fill";
|
||||
auto pipelineLabel = "The render pipeline fill shape winding";
|
||||
|
@ -83,7 +83,7 @@ void WgPipelineFillShapeEvenOdd::initialize(WGPUDevice device)
|
|||
WGPUCompareFunction stencilFunctionBack = WGPUCompareFunction_Always;
|
||||
WGPUStencilOperation stencilOperationBack = WGPUStencilOperation_Invert;
|
||||
|
||||
// sheder source and labels
|
||||
// shader source and labels
|
||||
auto shaderSource = cShaderSource_PipelineFill;
|
||||
auto shaderLabel = "The shader fill";
|
||||
auto pipelineLabel = "The render pipeline fill shape Even Odd";
|
||||
|
@ -115,7 +115,7 @@ void WgPipelineFillStroke::initialize(WGPUDevice device)
|
|||
WGPUCompareFunction stencilFunction = WGPUCompareFunction_Always;
|
||||
WGPUStencilOperation stencilOperation = WGPUStencilOperation_Replace;
|
||||
|
||||
// sheder source and labels
|
||||
// shader source and labels
|
||||
auto shaderSource = cShaderSource_PipelineFill;
|
||||
auto shaderLabel = "The shader fill";
|
||||
auto pipelineLabel = "The render pipeline fill stroke";
|
||||
|
@ -129,6 +129,38 @@ void WgPipelineFillStroke::initialize(WGPUDevice device)
|
|||
}
|
||||
|
||||
|
||||
void WgPipelineClipMask::initialize(WGPUDevice device)
|
||||
{
|
||||
// vertex and buffers settings
|
||||
WGPUVertexAttribute vertexAttributesPos = { WGPUVertexFormat_Float32x2, sizeof(float) * 0, 0 };
|
||||
WGPUVertexBufferLayout vertexBufferLayouts[] = {
|
||||
makeVertexBufferLayout(&vertexAttributesPos, 1, sizeof(float) * 2)
|
||||
};
|
||||
|
||||
// bind groups
|
||||
WGPUBindGroupLayout bindGroupLayouts[] = {
|
||||
WgBindGroupCanvas::getLayout(device),
|
||||
WgBindGroupPaint::getLayout(device)
|
||||
};
|
||||
|
||||
// stencil function
|
||||
WGPUCompareFunction stencilFunction = WGPUCompareFunction_NotEqual;
|
||||
WGPUStencilOperation stencilOperation = WGPUStencilOperation_Zero;
|
||||
|
||||
// shader source and labels
|
||||
auto shaderSource = cShaderSource_PipelineFill;
|
||||
auto shaderLabel = "The shader fill";
|
||||
auto pipelineLabel = "The render pipeline clip mask";
|
||||
|
||||
// allocate all pipeline handles
|
||||
allocate(device, WgPipelineBlendType::SrcOver, WGPUColorWriteMask_All,
|
||||
vertexBufferLayouts, ARRAY_ELEMENTS_COUNT(vertexBufferLayouts),
|
||||
bindGroupLayouts, ARRAY_ELEMENTS_COUNT(bindGroupLayouts),
|
||||
stencilFunction, stencilOperation, stencilFunction, stencilOperation,
|
||||
shaderSource, shaderLabel, pipelineLabel);
|
||||
}
|
||||
|
||||
|
||||
void WgPipelineSolid::initialize(WGPUDevice device, WgPipelineBlendType blendType)
|
||||
{
|
||||
// vertex and buffers settings
|
||||
|
@ -148,7 +180,7 @@ void WgPipelineSolid::initialize(WGPUDevice device, WgPipelineBlendType blendTyp
|
|||
WGPUCompareFunction stencilFunction = WGPUCompareFunction_NotEqual;
|
||||
WGPUStencilOperation stencilOperation = WGPUStencilOperation_Zero;
|
||||
|
||||
// sheder source and labels
|
||||
// shader source and labels
|
||||
auto shaderSource = cShaderSource_PipelineSolid;
|
||||
auto shaderLabel = "The shader solid color";
|
||||
auto pipelineLabel = "The render pipeline solid color";
|
||||
|
@ -181,7 +213,7 @@ void WgPipelineLinear::initialize(WGPUDevice device, WgPipelineBlendType blendTy
|
|||
WGPUCompareFunction stencilFunction = WGPUCompareFunction_NotEqual;
|
||||
WGPUStencilOperation stencilOperation = WGPUStencilOperation_Zero;
|
||||
|
||||
// sheder source and labels
|
||||
// shader source and labels
|
||||
auto shaderSource = cShaderSource_PipelineLinear;
|
||||
auto shaderLabel = "The shader linear gradient";
|
||||
auto pipelineLabel = "The render pipeline linear gradient";
|
||||
|
@ -214,7 +246,7 @@ void WgPipelineRadial::initialize(WGPUDevice device, WgPipelineBlendType blendTy
|
|||
WGPUCompareFunction stencilFunction = WGPUCompareFunction_NotEqual;
|
||||
WGPUStencilOperation stencilOperation = WGPUStencilOperation_Zero;
|
||||
|
||||
// sheder source and labels
|
||||
// shader source and labels
|
||||
auto shaderSource = cShaderSource_PipelineRadial;
|
||||
auto shaderLabel = "The shader radial gradient";
|
||||
auto pipelineLabel = "The render pipeline radial gradient";
|
||||
|
@ -249,7 +281,7 @@ void WgPipelineImage::initialize(WGPUDevice device, WgPipelineBlendType blendTyp
|
|||
WGPUCompareFunction stencilFunction = WGPUCompareFunction_Always;
|
||||
WGPUStencilOperation stencilOperation = WGPUStencilOperation_Zero;
|
||||
|
||||
// sheder source and labels
|
||||
// shader source and labels
|
||||
auto shaderSource = cShaderSource_PipelineImage;
|
||||
auto shaderLabel = "The shader image";
|
||||
auto pipelineLabel = "The render pipeline image";
|
||||
|
@ -273,7 +305,7 @@ void WgPipelineClear::initialize(WGPUDevice device)
|
|||
WgBindGroupTextureStorageRgba::getLayout(device)
|
||||
};
|
||||
|
||||
// sheder source and labels
|
||||
// shader source and labels
|
||||
auto shaderSource = cShaderSource_PipelineComputeClear;
|
||||
auto shaderLabel = "The compute shader clear";
|
||||
auto pipelineLabel = "The compute pipeline clear";
|
||||
|
@ -295,7 +327,7 @@ void WgPipelineBlend::initialize(WGPUDevice device, const char *shaderSource)
|
|||
WgBindGroupOpacity::getLayout(device)
|
||||
};
|
||||
|
||||
// sheder source and labels
|
||||
// shader source and labels
|
||||
auto shaderLabel = "The compute shader blend";
|
||||
auto pipelineLabel = "The compute pipeline blend";
|
||||
|
||||
|
@ -306,7 +338,46 @@ void WgPipelineBlend::initialize(WGPUDevice device, const char *shaderSource)
|
|||
}
|
||||
|
||||
|
||||
void WgPipelineComposeBlend::initialize(WGPUDevice device)
|
||||
void WgPipelineBlendMask::initialize(WGPUDevice device, const char *shaderSource)
|
||||
{
|
||||
// bind groups and layouts
|
||||
WGPUBindGroupLayout bindGroupLayouts[] = {
|
||||
WgBindGroupTexComposeBlend::getLayout(device),
|
||||
WgBindGroupBlendMethod::getLayout(device),
|
||||
WgBindGroupOpacity::getLayout(device)
|
||||
};
|
||||
|
||||
// shader source and labels
|
||||
auto shaderLabel = "The compute shader blend mask";
|
||||
auto pipelineLabel = "The compute pipeline blend mask";
|
||||
|
||||
// allocate all pipeline handles
|
||||
allocate(device,
|
||||
bindGroupLayouts, ARRAY_ELEMENTS_COUNT(bindGroupLayouts),
|
||||
shaderSource, shaderLabel, pipelineLabel);
|
||||
}
|
||||
|
||||
|
||||
void WgPipelineMaskCompose::initialize(WGPUDevice device)
|
||||
{
|
||||
// bind groups and layouts
|
||||
WGPUBindGroupLayout bindGroupLayouts[] = {
|
||||
WgBindGroupTexMaskCompose::getLayout(device),
|
||||
};
|
||||
|
||||
// shader source and labels
|
||||
auto shaderSource = cShaderSource_PipelineComputeMaskCompose;
|
||||
auto shaderLabel = "The compute shader mask compose";
|
||||
auto pipelineLabel = "The compute pipeline mask compose";
|
||||
|
||||
// allocate all pipeline handles
|
||||
allocate(device,
|
||||
bindGroupLayouts, ARRAY_ELEMENTS_COUNT(bindGroupLayouts),
|
||||
shaderSource, shaderLabel, pipelineLabel);
|
||||
}
|
||||
|
||||
|
||||
void WgPipelineCompose::initialize(WGPUDevice device)
|
||||
{
|
||||
// bind groups and layouts
|
||||
WGPUBindGroupLayout bindGroupLayouts[] = {
|
||||
|
@ -316,8 +387,8 @@ void WgPipelineComposeBlend::initialize(WGPUDevice device)
|
|||
WgBindGroupOpacity::getLayout(device)
|
||||
};
|
||||
|
||||
// sheder source and labels
|
||||
auto shaderSource = cShaderSource_PipelineComputeComposeBlend;
|
||||
// shader source and labels
|
||||
auto shaderSource = cShaderSource_PipelineComputeCompose;
|
||||
auto shaderLabel = "The compute shader compose blend";
|
||||
auto pipelineLabel = "The compute pipeline compose blend";
|
||||
|
||||
|
@ -336,7 +407,7 @@ void WgPipelineAntiAliasing::initialize(WGPUDevice device)
|
|||
WgBindGroupTextureStorageBgra::getLayout(device)
|
||||
};
|
||||
|
||||
// sheder source and labels
|
||||
// shader source and labels
|
||||
auto shaderSource = cShaderSource_PipelineComputeAntiAlias;
|
||||
auto shaderLabel = "The compute shader anti-aliasing";
|
||||
auto pipelineLabel = "The compute pipeline anti-aliasing";
|
||||
|
@ -357,6 +428,7 @@ void WgPipelines::initialize(WgContext& context)
|
|||
fillShapeWinding.initialize(context.device);
|
||||
fillShapeEvenOdd.initialize(context.device);
|
||||
fillStroke.initialize(context.device);
|
||||
clipMask.initialize(context.device);
|
||||
for (uint8_t type = (uint8_t)WgPipelineBlendType::SrcOver; type <= (uint8_t)WgPipelineBlendType::Custom; type++) {
|
||||
solid[type].initialize(context.device, (WgPipelineBlendType)type);
|
||||
linear[type].initialize(context.device, (WgPipelineBlendType)type);
|
||||
|
@ -368,7 +440,11 @@ void WgPipelines::initialize(WgContext& context)
|
|||
computeBlendSolid.initialize(context.device, cShaderSource_PipelineComputeBlendSolid);
|
||||
computeBlendGradient.initialize(context.device, cShaderSource_PipelineComputeBlendGradient);
|
||||
computeBlendImage.initialize(context.device, cShaderSource_PipelineComputeBlendImage);
|
||||
computeComposeBlend.initialize(context.device);
|
||||
computeBlendSolidMask.initialize(context.device, cShaderSource_PipelineComputeBlendSolidMask);
|
||||
computeBlendGradientMask.initialize(context.device, cShaderSource_PipelineComputeBlendGradientMask);
|
||||
computeBlendImageMask.initialize(context.device, cShaderSource_PipelineComputeBlendImageMask);
|
||||
computeMaskCompose.initialize(context.device);
|
||||
computeCompose.initialize(context.device);
|
||||
computeAntiAliasing.initialize(context.device);
|
||||
// store pipelines to context
|
||||
context.pipelines = this;
|
||||
|
@ -377,7 +453,8 @@ void WgPipelines::initialize(WgContext& context)
|
|||
|
||||
void WgPipelines::release()
|
||||
{
|
||||
WgBindGroupTexComposeBlend::layout = nullptr;
|
||||
WgBindGroupTexMaskCompose::releaseLayout();
|
||||
WgBindGroupTexComposeBlend::releaseLayout();
|
||||
WgBindGroupTextureSampled::releaseLayout();
|
||||
WgBindGroupTextureStorageBgra::releaseLayout();
|
||||
WgBindGroupTextureStorageRgba::releaseLayout();
|
||||
|
@ -391,7 +468,11 @@ void WgPipelines::release()
|
|||
WgBindGroupCanvas::releaseLayout();
|
||||
// compute pipelines
|
||||
computeAntiAliasing.release();
|
||||
computeComposeBlend.release();
|
||||
computeCompose.release();
|
||||
computeMaskCompose.release();
|
||||
computeBlendImageMask.release();
|
||||
computeBlendGradientMask.release();
|
||||
computeBlendSolidMask.release();
|
||||
computeBlendImage.release();
|
||||
computeBlendGradient.release();
|
||||
computeBlendSolid.release();
|
||||
|
@ -403,6 +484,7 @@ void WgPipelines::release()
|
|||
linear[type].release();
|
||||
solid[type].release();
|
||||
}
|
||||
clipMask.release();
|
||||
fillStroke.release();
|
||||
fillShapeEvenOdd.release();
|
||||
fillShapeWinding.release();
|
||||
|
|
|
@ -62,6 +62,17 @@ struct WgPipelineFillStroke: public WgRenderPipeline
|
|||
}
|
||||
};
|
||||
|
||||
struct WgPipelineClipMask: public WgRenderPipeline
|
||||
{
|
||||
void initialize(WGPUDevice device) override;
|
||||
void use(WGPURenderPassEncoder encoder, WgBindGroupCanvas& groupCanvas,WgBindGroupPaint& groupPaint)
|
||||
{
|
||||
set(encoder);
|
||||
groupCanvas.set(encoder, 0);
|
||||
groupPaint.set(encoder, 1);
|
||||
}
|
||||
};
|
||||
|
||||
struct WgPipelineSolid: public WgRenderPipeline
|
||||
{
|
||||
void initialize(WGPUDevice device) override {}
|
||||
|
@ -144,7 +155,32 @@ struct WgPipelineBlend: public WgComputePipeline
|
|||
};
|
||||
|
||||
|
||||
struct WgPipelineComposeBlend: public WgComputePipeline
|
||||
struct WgPipelineBlendMask: public WgComputePipeline
|
||||
{
|
||||
void initialize(WGPUDevice device) override { assert(false); };
|
||||
void initialize(WGPUDevice device, const char *shaderSource);
|
||||
void use(WGPUComputePassEncoder encoder, WgBindGroupTexComposeBlend& groupTexs, WgBindGroupBlendMethod& blendMethod, WgBindGroupOpacity& groupOpacity)
|
||||
{
|
||||
set(encoder);
|
||||
groupTexs.set(encoder, 0);
|
||||
blendMethod.set(encoder, 1);
|
||||
groupOpacity.set(encoder, 2);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct WgPipelineMaskCompose: public WgComputePipeline
|
||||
{
|
||||
void initialize(WGPUDevice device) override;
|
||||
void use(WGPUComputePassEncoder encoder, WgBindGroupTexMaskCompose& groupTexs)
|
||||
{
|
||||
set(encoder);
|
||||
groupTexs.set(encoder, 0);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct WgPipelineCompose: public WgComputePipeline
|
||||
{
|
||||
void initialize(WGPUDevice device) override;
|
||||
void use(WGPUComputePassEncoder encoder, WgBindGroupTexComposeBlend& groupTexs, WgBindGroupCompositeMethod& groupComposeMethod, WgBindGroupBlendMethod& groupBlendMethod, WgBindGroupOpacity& groupOpacity)
|
||||
|
@ -180,6 +216,7 @@ struct WgPipelines
|
|||
WgPipelineFillShapeEvenOdd fillShapeEvenOdd;
|
||||
WgPipelineFillStroke fillStroke;
|
||||
// fill pipelines
|
||||
WgPipelineClipMask clipMask;
|
||||
WgPipelineSolid solid[3];
|
||||
WgPipelineLinear linear[3];
|
||||
WgPipelineRadial radial[3];
|
||||
|
@ -189,7 +226,11 @@ struct WgPipelines
|
|||
WgPipelineBlend computeBlendSolid;
|
||||
WgPipelineBlend computeBlendGradient;
|
||||
WgPipelineBlend computeBlendImage;
|
||||
WgPipelineComposeBlend computeComposeBlend;
|
||||
WgPipelineBlendMask computeBlendSolidMask;
|
||||
WgPipelineBlendMask computeBlendGradientMask;
|
||||
WgPipelineBlendMask computeBlendImageMask;
|
||||
WgPipelineMaskCompose computeMaskCompose;
|
||||
WgPipelineCompose computeCompose;
|
||||
WgPipelineAntiAliasing computeAntiAliasing;
|
||||
|
||||
void initialize(WgContext& context);
|
||||
|
|
|
@ -262,8 +262,17 @@ void WgRenderSettings::release(WgContext& context)
|
|||
void WgRenderDataPaint::release(WgContext& context)
|
||||
{
|
||||
bindGroupPaint.release();
|
||||
clips.clear();
|
||||
};
|
||||
|
||||
|
||||
void WgRenderDataPaint::updateClips(tvg::Array<tvg::RenderData> &clips) {
|
||||
this->clips.clear();
|
||||
for (uint32_t i = 0; i < clips.count; i++)
|
||||
if (clips[i])
|
||||
this->clips.push((WgRenderDataPaint*)clips[i]);
|
||||
}
|
||||
|
||||
//***********************************************************************
|
||||
// WgRenderDataShape
|
||||
//***********************************************************************
|
||||
|
@ -371,6 +380,7 @@ void WgRenderDataShape::releaseMeshes(WgContext &context)
|
|||
meshGroupShapes.release(context);
|
||||
pMin = {FLT_MAX, FLT_MAX};
|
||||
pMax = {0.0f, 0.0f};
|
||||
clips.clear();
|
||||
}
|
||||
|
||||
|
||||
|
@ -407,6 +417,7 @@ void WgRenderDataShapePool::free(WgContext& context, WgRenderDataShape* dataShap
|
|||
dataShape->meshGroupShapesBBox.release(context);
|
||||
dataShape->meshGroupStrokes.release(context);
|
||||
dataShape->meshGroupStrokesBBox.release(context);
|
||||
dataShape->clips.clear();
|
||||
mPool.push(dataShape);
|
||||
}
|
||||
|
||||
|
|
|
@ -88,10 +88,13 @@ struct WgRenderDataPaint
|
|||
WgBindGroupPaint bindGroupPaint{};
|
||||
RenderRegion viewport{};
|
||||
float opacity{};
|
||||
Array<WgRenderDataPaint*> clips;
|
||||
|
||||
virtual ~WgRenderDataPaint() {};
|
||||
virtual void release(WgContext& context);
|
||||
virtual Type type() { return Type::Undefined; };
|
||||
|
||||
void updateClips(tvg::Array<tvg::RenderData> &clips);
|
||||
};
|
||||
|
||||
struct WgRenderDataShape: public WgRenderDataPaint
|
||||
|
|
|
@ -85,7 +85,6 @@ void WgRenderStorage::renderShape(WgContext& context, WgRenderDataShape* renderD
|
|||
{
|
||||
assert(renderData);
|
||||
assert(mRenderPassEncoder);
|
||||
// draw strokes
|
||||
if (renderData->strokeFirst) {
|
||||
drawStroke(context, renderData, blendType);
|
||||
drawShape(context, renderData, blendType);
|
||||
|
@ -102,12 +101,21 @@ void WgRenderStorage::renderPicture(WgContext& context, WgRenderDataPicture* ren
|
|||
assert(mRenderPassEncoder);
|
||||
uint8_t blend = (uint8_t)blendType;
|
||||
auto& vp = renderData->viewport;
|
||||
if ((vp.w <= 0) || (vp.h <= 0)) return;
|
||||
wgpuRenderPassEncoderSetScissorRect(mRenderPassEncoder, vp.x * samples, vp.y * samples, vp.w * samples, vp.h * samples);
|
||||
wgpuRenderPassEncoderSetStencilReference(mRenderPassEncoder, 0);
|
||||
mPipelines->image[blend].use(mRenderPassEncoder, mBindGroupCanvas, renderData->bindGroupPaint, renderData->bindGroupPicture);
|
||||
renderData->meshData.drawImage(context, mRenderPassEncoder);
|
||||
}
|
||||
|
||||
void WgRenderStorage::renderClipPath(WgContext& context, WgRenderDataPaint* renderData) {
|
||||
assert(renderData);
|
||||
assert(mRenderPassEncoder);
|
||||
if (renderData->type() == Type::Shape)
|
||||
drawShapeClipPath(context, (WgRenderDataShape*)renderData);
|
||||
else if (renderData->type() == Type::Picture)
|
||||
drawPictureClipPath(context, (WgRenderDataPicture*)renderData);
|
||||
}
|
||||
|
||||
void WgRenderStorage::drawShape(WgContext& context, WgRenderDataShape* renderData, WgPipelineBlendType blendType)
|
||||
{
|
||||
|
@ -115,10 +123,12 @@ void WgRenderStorage::drawShape(WgContext& context, WgRenderDataShape* renderDat
|
|||
assert(mRenderPassEncoder);
|
||||
assert(renderData->meshGroupShapes.meshes.count == renderData->meshGroupShapesBBox.meshes.count);
|
||||
if (renderData->renderSettingsShape.skip) return;
|
||||
// apply viewport
|
||||
auto& vp = renderData->viewport;
|
||||
if ((vp.w <= 0) || (vp.h <= 0)) return;
|
||||
wgpuRenderPassEncoderSetScissorRect(mRenderPassEncoder, vp.x * samples, vp.y * samples, vp.w * samples, vp.h * samples);
|
||||
wgpuRenderPassEncoderSetStencilReference(mRenderPassEncoder, 0);
|
||||
// setup fill rule
|
||||
wgpuRenderPassEncoderSetStencilReference(mRenderPassEncoder, 0);
|
||||
if (renderData->fillRule == FillRule::Winding)
|
||||
mPipelines->fillShapeWinding.use(mRenderPassEncoder, mBindGroupCanvas, renderData->bindGroupPaint);
|
||||
else
|
||||
|
@ -145,7 +155,9 @@ void WgRenderStorage::drawStroke(WgContext& context, WgRenderDataShape* renderDa
|
|||
assert(mRenderPassEncoder);
|
||||
assert(renderData->meshGroupStrokes.meshes.count == renderData->meshGroupStrokesBBox.meshes.count);
|
||||
if (renderData->renderSettingsStroke.skip) return;
|
||||
// apply viewport
|
||||
auto& vp = renderData->viewport;
|
||||
if ((vp.w <= 0) || (vp.h <= 0)) return;
|
||||
wgpuRenderPassEncoderSetScissorRect(mRenderPassEncoder, vp.x * samples, vp.y * samples, vp.w * samples, vp.h * samples);
|
||||
// draw stroke geometry
|
||||
uint8_t blend = (uint8_t)blendType;
|
||||
|
@ -169,6 +181,35 @@ void WgRenderStorage::drawStroke(WgContext& context, WgRenderDataShape* renderDa
|
|||
}
|
||||
|
||||
|
||||
void WgRenderStorage::drawShapeClipPath(WgContext& context, WgRenderDataShape* renderData) {
|
||||
assert(renderData);
|
||||
assert(renderData->type() == Type::Shape);
|
||||
assert(renderData->meshGroupShapes.meshes.count == renderData->meshGroupShapesBBox.meshes.count);
|
||||
// draw shape geometry
|
||||
wgpuRenderPassEncoderSetStencilReference(mRenderPassEncoder, 0);
|
||||
// setup fill rule
|
||||
if (renderData->fillRule == FillRule::Winding)
|
||||
mPipelines->fillShapeWinding.use(mRenderPassEncoder, mBindGroupCanvas, renderData->bindGroupPaint);
|
||||
else
|
||||
mPipelines->fillShapeEvenOdd.use(mRenderPassEncoder, mBindGroupCanvas, renderData->bindGroupPaint);
|
||||
// draw to stencil (first pass)
|
||||
for (uint32_t i = 0; i < renderData->meshGroupShapes.meshes.count; i++)
|
||||
renderData->meshGroupShapes.meshes[i]->drawFan(context, mRenderPassEncoder);
|
||||
// fill shape geometry (second pass)
|
||||
mPipelines->clipMask.use(mRenderPassEncoder, mBindGroupCanvas, renderData->bindGroupPaint);
|
||||
renderData->meshDataBBox.drawFan(context, mRenderPassEncoder);
|
||||
}
|
||||
|
||||
void WgRenderStorage::drawPictureClipPath(WgContext& context, WgRenderDataPicture* renderData) {
|
||||
assert(renderData);
|
||||
assert(renderData->type() == Type::Picture);
|
||||
assert(mRenderPassEncoder);
|
||||
wgpuRenderPassEncoderSetStencilReference(mRenderPassEncoder, 0);
|
||||
mPipelines->clipMask.use(mRenderPassEncoder, mBindGroupCanvas, renderData->bindGroupPaint);
|
||||
renderData->meshData.drawImage(context, mRenderPassEncoder);
|
||||
}
|
||||
|
||||
|
||||
void WgRenderStorage::clear(WGPUCommandEncoder commandEncoder)
|
||||
{
|
||||
assert(commandEncoder);
|
||||
|
@ -179,7 +220,14 @@ void WgRenderStorage::clear(WGPUCommandEncoder commandEncoder)
|
|||
}
|
||||
|
||||
|
||||
void WgRenderStorage::blend(WGPUCommandEncoder commandEncoder, WgRenderStorage* targetSrc, WgPipelineBlend* pipeline, WgBindGroupBlendMethod* blendMethod, WgBindGroupOpacity* opacity) {
|
||||
void WgRenderStorage::blend(
|
||||
WgContext& context,
|
||||
WGPUCommandEncoder commandEncoder,
|
||||
WgPipelineBlend* pipeline,
|
||||
WgRenderStorage* targetSrc,
|
||||
WgBindGroupBlendMethod* blendMethod,
|
||||
WgBindGroupOpacity* opacity)
|
||||
{
|
||||
assert(commandEncoder);
|
||||
assert(targetSrc);
|
||||
assert(pipeline);
|
||||
|
@ -190,7 +238,46 @@ void WgRenderStorage::blend(WGPUCommandEncoder commandEncoder, WgRenderStorage*
|
|||
}
|
||||
|
||||
|
||||
void WgRenderStorage::composeBlend(
|
||||
void WgRenderStorage::blendMask(
|
||||
WgContext& context,
|
||||
WGPUCommandEncoder commandEncoder,
|
||||
WgPipelineBlendMask* pipeline,
|
||||
WgRenderStorage* texMsk,
|
||||
WgRenderStorage* texSrc,
|
||||
WgBindGroupBlendMethod* blendMethod,
|
||||
WgBindGroupOpacity* opacity)
|
||||
{
|
||||
assert(commandEncoder);
|
||||
assert(texSrc);
|
||||
assert(texMsk);
|
||||
WgBindGroupTexComposeBlend composeBlend;
|
||||
composeBlend.initialize(context.device, context.queue, texSrc->texViewColor, texMsk->texViewColor, texViewColor);
|
||||
WGPUComputePassEncoder computePassEncoder = beginComputePass(commandEncoder);
|
||||
pipeline->use(computePassEncoder, composeBlend, *blendMethod, *opacity);
|
||||
dispatchWorkgroups(computePassEncoder);
|
||||
endComputePass(computePassEncoder);
|
||||
composeBlend.release();
|
||||
};
|
||||
|
||||
|
||||
void WgRenderStorage::maskCompose(
|
||||
WgContext& context,
|
||||
WGPUCommandEncoder commandEncoder,
|
||||
WgRenderStorage* texMsk0)
|
||||
{
|
||||
assert(commandEncoder);
|
||||
assert(texMsk0);
|
||||
WgBindGroupTexMaskCompose maskCompose;
|
||||
maskCompose.initialize(context.device, context.queue, texMsk0->texViewColor, texViewColor);
|
||||
WGPUComputePassEncoder computePassEncoder = beginComputePass(commandEncoder);
|
||||
mPipelines->computeMaskCompose.use(computePassEncoder, maskCompose);
|
||||
dispatchWorkgroups(computePassEncoder);
|
||||
endComputePass(computePassEncoder);
|
||||
maskCompose.release();
|
||||
}
|
||||
|
||||
|
||||
void WgRenderStorage::compose(
|
||||
WgContext& context,
|
||||
WGPUCommandEncoder commandEncoder,
|
||||
WgRenderStorage* texSrc,
|
||||
|
@ -205,7 +292,7 @@ void WgRenderStorage::composeBlend(
|
|||
WgBindGroupTexComposeBlend composeBlend;
|
||||
composeBlend.initialize(context.device, context.queue, texSrc->texViewColor, texMsk->texViewColor, texViewColor);
|
||||
WGPUComputePassEncoder computePassEncoder = beginComputePass(commandEncoder);
|
||||
mPipelines->computeComposeBlend.use(computePassEncoder, composeBlend, *composeMethod, *blendMethod, *opacity);
|
||||
mPipelines->computeCompose.use(computePassEncoder, composeBlend, *composeMethod, *blendMethod, *opacity);
|
||||
dispatchWorkgroups(computePassEncoder);
|
||||
endComputePass(computePassEncoder);
|
||||
composeBlend.release();
|
||||
|
|
|
@ -52,10 +52,29 @@ public:
|
|||
|
||||
void renderShape(WgContext& context, WgRenderDataShape* renderData, WgPipelineBlendType blendType);
|
||||
void renderPicture(WgContext& context, WgRenderDataPicture* renderData, WgPipelineBlendType blendType);
|
||||
void renderClipPath(WgContext& context, WgRenderDataPaint* renderData);
|
||||
|
||||
void clear(WGPUCommandEncoder commandEncoder);
|
||||
void blend(WGPUCommandEncoder commandEncoder, WgRenderStorage* targetSrc, WgPipelineBlend* pipeline, WgBindGroupBlendMethod* blendMethod, WgBindGroupOpacity* opacity);
|
||||
void composeBlend(
|
||||
void blend(
|
||||
WgContext& context,
|
||||
WGPUCommandEncoder commandEncoder,
|
||||
WgPipelineBlend* pipeline,
|
||||
WgRenderStorage* targetSrc,
|
||||
WgBindGroupBlendMethod* blendMethod,
|
||||
WgBindGroupOpacity* opacity);
|
||||
void blendMask(
|
||||
WgContext& context,
|
||||
WGPUCommandEncoder commandEncoder,
|
||||
WgPipelineBlendMask* pipeline,
|
||||
WgRenderStorage* texMsk,
|
||||
WgRenderStorage* texSrc,
|
||||
WgBindGroupBlendMethod* blendMethod,
|
||||
WgBindGroupOpacity* opacity);
|
||||
void maskCompose(
|
||||
WgContext& context,
|
||||
WGPUCommandEncoder commandEncoder,
|
||||
WgRenderStorage* texMsk0);
|
||||
void compose(
|
||||
WgContext& context,
|
||||
WGPUCommandEncoder commandEncoder,
|
||||
WgRenderStorage* texMsk,
|
||||
|
@ -68,6 +87,9 @@ private:
|
|||
void drawShape(WgContext& context, WgRenderDataShape* renderData, WgPipelineBlendType blendType);
|
||||
void drawStroke(WgContext& context, WgRenderDataShape* renderData, WgPipelineBlendType blendType);
|
||||
|
||||
void drawShapeClipPath(WgContext& context, WgRenderDataShape* renderData);
|
||||
void drawPictureClipPath(WgContext& context, WgRenderDataPicture* renderData);
|
||||
|
||||
void dispatchWorkgroups(WGPUComputePassEncoder computePassEncoder);
|
||||
|
||||
WGPUComputePassEncoder beginComputePass(WGPUCommandEncoder commandEncoder);
|
||||
|
|
|
@ -67,6 +67,7 @@ void WgRenderer::release()
|
|||
mBlendMethodPool.release(mContext);
|
||||
mOpacityPool.release(mContext);
|
||||
mRenderStorageRoot.release(mContext);
|
||||
mRenderStorageMask.release(mContext);
|
||||
mRenderStorageScreen.release(mContext);
|
||||
mRenderStorageInterm.release(mContext);
|
||||
mPipelines.release();
|
||||
|
@ -119,6 +120,9 @@ RenderData WgRenderer::prepare(const RenderShape& rshape, RenderData data, const
|
|||
if (rshape.stroke)
|
||||
renderDataShape->renderSettingsStroke.update(mContext, rshape.stroke->fill, rshape.stroke->color, flags);
|
||||
|
||||
// store clips data
|
||||
renderDataShape->updateClips(clips);
|
||||
|
||||
return renderDataShape;
|
||||
}
|
||||
|
||||
|
@ -159,6 +163,9 @@ RenderData WgRenderer::prepare(Surface* surface, const RenderMesh* mesh, RenderD
|
|||
renderDataPicture->imageData.textureView);
|
||||
}
|
||||
|
||||
// store clips data
|
||||
renderDataPicture->updateClips(clips);
|
||||
|
||||
return renderDataPicture;
|
||||
}
|
||||
|
||||
|
@ -175,6 +182,19 @@ bool WgRenderer::preRender()
|
|||
}
|
||||
|
||||
|
||||
void WgRenderer::renderClipPath(Array<WgRenderDataPaint*>& clips)
|
||||
{
|
||||
for (uint32_t i = 0; i < clips.count; i++) {
|
||||
renderClipPath(clips[i]->clips);
|
||||
// render image to render target
|
||||
mRenderStorageInterm.beginRenderPass(mCommandEncoder, true);
|
||||
mRenderStorageInterm.renderClipPath(mContext, clips[i]);
|
||||
mRenderStorageInterm.endRenderPass();
|
||||
mRenderStorageMask.maskCompose(mContext, mCommandEncoder, &mRenderStorageInterm);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool WgRenderer::renderShape(RenderData data)
|
||||
{
|
||||
// get current render storage
|
||||
|
@ -183,11 +203,34 @@ bool WgRenderer::renderShape(RenderData data)
|
|||
WgPipelineBlendType blendType = WgPipelines::blendMethodToBlendType(mBlendMethod);
|
||||
WgRenderStorage* renderStorage = mRenderStorageStack.last();
|
||||
assert(renderStorage);
|
||||
// use masked blend
|
||||
if (dataShape->clips.count > 0) {
|
||||
// terminate current render pass
|
||||
renderStorage->endRenderPass();
|
||||
// render clip path
|
||||
mRenderStorageMask.beginRenderPass(mCommandEncoder, true);
|
||||
mRenderStorageMask.renderClipPath(mContext, dataShape->clips[0]);
|
||||
mRenderStorageMask.endRenderPass();
|
||||
renderClipPath(dataShape->clips);
|
||||
// render image to render target
|
||||
mRenderStorageInterm.beginRenderPass(mCommandEncoder, true);
|
||||
mRenderStorageInterm.renderShape(mContext, dataShape, blendType);
|
||||
mRenderStorageInterm.endRenderPass();
|
||||
// blend shape with current render storage
|
||||
WgBindGroupBlendMethod* blendMethod = mBlendMethodPool.allocate(mContext, mBlendMethod);
|
||||
WgBindGroupOpacity* opacity = mOpacityPool.allocate(mContext, 255);
|
||||
WgPipelineBlendMask* pipeline = &mContext.pipelines->computeBlendSolidMask;
|
||||
if (dataShape->renderSettingsShape.fillType != WgRenderSettingsType::Solid)
|
||||
pipeline = &mContext.pipelines->computeBlendGradientMask;
|
||||
renderStorage->blendMask(mContext, mCommandEncoder,
|
||||
pipeline, &mRenderStorageMask, &mRenderStorageInterm, blendMethod, opacity);
|
||||
// restore current render pass
|
||||
renderStorage->beginRenderPass(mCommandEncoder, false);
|
||||
// use hardware blend
|
||||
if (WgPipelines::isBlendMethodSupportsHW(mBlendMethod))
|
||||
} else if (WgPipelines::isBlendMethodSupportsHW(mBlendMethod)) {
|
||||
renderStorage->renderShape(mContext, dataShape, blendType);
|
||||
// use custom blend
|
||||
else {
|
||||
} else {
|
||||
// terminate current render pass
|
||||
renderStorage->endRenderPass();
|
||||
// render image to render target
|
||||
|
@ -200,7 +243,8 @@ bool WgRenderer::renderShape(RenderData data)
|
|||
WgPipelineBlend* pipeline = &mContext.pipelines->computeBlendSolid;
|
||||
if (dataShape->renderSettingsShape.fillType != WgRenderSettingsType::Solid)
|
||||
pipeline = &mContext.pipelines->computeBlendGradient;
|
||||
renderStorage->blend(mCommandEncoder, &mRenderStorageInterm, pipeline, blendMethod, opacity);
|
||||
renderStorage->blend(mContext, mCommandEncoder,
|
||||
pipeline, &mRenderStorageInterm, blendMethod, opacity);
|
||||
// restore current render pass
|
||||
renderStorage->beginRenderPass(mCommandEncoder, false);
|
||||
}
|
||||
|
@ -210,26 +254,50 @@ bool WgRenderer::renderShape(RenderData data)
|
|||
|
||||
bool WgRenderer::renderImage(RenderData data)
|
||||
{
|
||||
// get current render storage
|
||||
WgRenderDataPicture *dataPicture = (WgRenderDataPicture*)data;
|
||||
// get current render storage
|
||||
WgPipelineBlendType blendType = WgPipelines::blendMethodToBlendType(mBlendMethod);
|
||||
WgRenderStorage* renderStorage = mRenderStorageStack.last();
|
||||
assert(renderStorage);
|
||||
// use masked blend
|
||||
if (dataPicture->clips.count > 0) {
|
||||
// terminate current render pass
|
||||
renderStorage->endRenderPass();
|
||||
// render clip path
|
||||
mRenderStorageMask.beginRenderPass(mCommandEncoder, true);
|
||||
mRenderStorageMask.renderClipPath(mContext, dataPicture->clips[0]);
|
||||
mRenderStorageMask.endRenderPass();
|
||||
renderClipPath(dataPicture->clips);
|
||||
// render image to render target
|
||||
mRenderStorageInterm.beginRenderPass(mCommandEncoder, true);
|
||||
mRenderStorageInterm.renderPicture(mContext, dataPicture, blendType);
|
||||
mRenderStorageInterm.endRenderPass();
|
||||
// blend shape with current render storage
|
||||
WgBindGroupBlendMethod* blendMethod = mBlendMethodPool.allocate(mContext, mBlendMethod);
|
||||
WgBindGroupOpacity* opacity = mOpacityPool.allocate(mContext, 255);
|
||||
WgPipelineBlendMask* pipeline = &mContext.pipelines->computeBlendImageMask;
|
||||
renderStorage->blendMask(mContext, mCommandEncoder,
|
||||
pipeline, &mRenderStorageMask, &mRenderStorageInterm, blendMethod, opacity);
|
||||
// restore current render pass
|
||||
renderStorage->beginRenderPass(mCommandEncoder, false);
|
||||
// use hardware blend
|
||||
if (WgPipelines::isBlendMethodSupportsHW(mBlendMethod))
|
||||
renderStorage->renderPicture(mContext, (WgRenderDataPicture *)data, blendType);
|
||||
} else if (WgPipelines::isBlendMethodSupportsHW(mBlendMethod))
|
||||
renderStorage->renderPicture(mContext, dataPicture, blendType);
|
||||
// use custom blend
|
||||
else {
|
||||
// terminate current render pass
|
||||
renderStorage->endRenderPass();
|
||||
// render image to render target
|
||||
mRenderStorageInterm.beginRenderPass(mCommandEncoder, true);
|
||||
mRenderStorageInterm.renderPicture(mContext, (WgRenderDataPicture *)data, blendType);
|
||||
mRenderStorageInterm.renderPicture(mContext, dataPicture, blendType);
|
||||
mRenderStorageInterm.endRenderPass();
|
||||
// blend shape with current render storage
|
||||
WgBindGroupBlendMethod* blendMethod = mBlendMethodPool.allocate(mContext, mBlendMethod);
|
||||
WgBindGroupOpacity* opacity = mOpacityPool.allocate(mContext, 255);
|
||||
WgPipelineBlend* pipeline = &mContext.pipelines->computeBlendImage;
|
||||
renderStorage->blend(mCommandEncoder, &mRenderStorageInterm, pipeline, blendMethod, opacity);
|
||||
renderStorage->blend(mContext, mCommandEncoder,
|
||||
pipeline, &mRenderStorageInterm, blendMethod, opacity);
|
||||
// restore current render pass
|
||||
renderStorage->beginRenderPass(mCommandEncoder, false);
|
||||
}
|
||||
|
@ -258,7 +326,7 @@ void WgRenderer::dispose(RenderData data) {
|
|||
|
||||
RenderRegion WgRenderer::region(TVG_UNUSED RenderData data)
|
||||
{
|
||||
return { 0, 0, INT32_MAX, INT32_MAX };
|
||||
return { 0, 0, (int32_t)mTargetSurface.w, (int32_t)mTargetSurface.h };
|
||||
}
|
||||
|
||||
|
||||
|
@ -355,6 +423,7 @@ bool WgRenderer::target(WGPUInstance instance, WGPUSurface surface, uint32_t w,
|
|||
|
||||
initialize();
|
||||
mRenderStorageInterm.initialize(mContext, w, h, WG_SSAA_SAMPLES);
|
||||
mRenderStorageMask.initialize(mContext, w, h, WG_SSAA_SAMPLES);
|
||||
mRenderStorageRoot.initialize(mContext, w, h, WG_SSAA_SAMPLES);
|
||||
mRenderStorageScreen.initialize(mContext, w, h, 1, WGPUTextureFormat_BGRA8Unorm);
|
||||
return true;
|
||||
|
@ -400,7 +469,9 @@ bool WgRenderer::endComposite(TVG_UNUSED Compositor* cmp)
|
|||
// blent scene to current render storage
|
||||
WgBindGroupBlendMethod* blendMethod = mBlendMethodPool.allocate(mContext, comp->blendMethod);
|
||||
WgBindGroupOpacity* opacity = mOpacityPool.allocate(mContext, comp->opacity);
|
||||
mRenderStorageStack.last()->blend(mCommandEncoder, renderStorageSrc, &mContext.pipelines->computeBlendImage, blendMethod, opacity);
|
||||
mRenderStorageStack.last()->blend(mContext, mCommandEncoder,
|
||||
&mContext.pipelines->computeBlendImage,
|
||||
renderStorageSrc, blendMethod, opacity);
|
||||
|
||||
// back render targets to the pool
|
||||
mRenderStoragePool.free(mContext, renderStorageSrc);
|
||||
|
@ -424,7 +495,7 @@ bool WgRenderer::endComposite(TVG_UNUSED Compositor* cmp)
|
|||
|
||||
// compose and blend
|
||||
// dest = blend(dest, compose(src, msk, composeMethod), blendMethod, opacity)
|
||||
renderStorageDst->composeBlend(mContext, mCommandEncoder,
|
||||
renderStorageDst->compose(mContext, mCommandEncoder,
|
||||
renderStorageSrc, renderStorageMsk,
|
||||
composeMethod, blendMethod, opacity);
|
||||
|
||||
|
|
|
@ -62,9 +62,11 @@ private:
|
|||
void initialize();
|
||||
void release();
|
||||
void clearDisposes();
|
||||
void renderClipPath(Array<WgRenderDataPaint*>& clips);
|
||||
|
||||
WGPUCommandEncoder mCommandEncoder{}; // render handles
|
||||
WGPUCommandEncoder mCommandEncoder{};
|
||||
WgRenderStorage mRenderStorageInterm; // intermidiate buffer to render
|
||||
WgRenderStorage mRenderStorageMask; // buffer to render mask
|
||||
WgRenderStorage mRenderStorageRoot; // root render storage
|
||||
WgRenderStorage mRenderStorageScreen; // storage with data after antializing
|
||||
WgRenderStoragePool mRenderStoragePool; // pool to hold render tree storages
|
||||
|
|
|
@ -53,8 +53,8 @@ fn vs_main(in: VertexInput) -> VertexOutput {
|
|||
}
|
||||
|
||||
@fragment
|
||||
fn fs_main(in: VertexOutput) -> void {
|
||||
// nothing to draw, just stencil value
|
||||
fn fs_main(in: VertexOutput) -> @location(0) vec4f {
|
||||
return vec4f(0.0, 0.0, 0.0, 1.0);
|
||||
}
|
||||
);
|
||||
|
||||
|
@ -393,6 +393,34 @@ fn cs_main( @builtin(global_invocation_id) id: vec3u) {
|
|||
var Ra: f32 = 1.0;
|
||||
);
|
||||
|
||||
const std::string strBlendMaskShaderHeader = WG_SHADER_SOURCE(
|
||||
@group(0) @binding(0) var imageSrc : texture_storage_2d<rgba8unorm, read>;
|
||||
@group(0) @binding(1) var imageMsk : texture_storage_2d<rgba8unorm, read>;
|
||||
@group(0) @binding(2) var imageDst : texture_storage_2d<rgba8unorm, read_write>;
|
||||
@group(1) @binding(0) var<uniform> blendMethod : u32;
|
||||
@group(2) @binding(0) var<uniform> opacity : f32;
|
||||
|
||||
@compute @workgroup_size(8, 8)
|
||||
fn cs_main( @builtin(global_invocation_id) id: vec3u) {
|
||||
let texSize = textureDimensions(imageSrc);
|
||||
if ((id.x >= texSize.x) || (id.y >= texSize.y)) { return; };
|
||||
|
||||
let colorMsk = textureLoad(imageMsk, id.xy);
|
||||
if (colorMsk.a == 0.0) { return; }
|
||||
let colorSrc = textureLoad(imageSrc, id.xy);
|
||||
if (colorSrc.a == 0.0) { return; }
|
||||
let colorDst = textureLoad(imageDst, id.xy);
|
||||
|
||||
var One: vec3f = vec3(1.0);
|
||||
var So: f32 = opacity;
|
||||
var Sc: vec3f = colorSrc.rgb;
|
||||
var Sa: f32 = colorSrc.a;
|
||||
var Dc: vec3f = colorDst.rgb;
|
||||
var Da: f32 = colorDst.a;
|
||||
var Rc: vec3f = colorDst.rgb;
|
||||
var Ra: f32 = 1.0;
|
||||
);
|
||||
|
||||
const std::string strBlendShaderPreConditionsGradient = WG_SHADER_SOURCE(
|
||||
Sc = Sc + Dc.rgb * (1.0 - Sa);
|
||||
Sa = Sa + Da * (1.0 - Sa);
|
||||
|
@ -484,6 +512,31 @@ const std::string strComputeBlendImage =
|
|||
strBlendShaderFooter;
|
||||
const char* cShaderSource_PipelineComputeBlendImage = strComputeBlendImage.c_str();
|
||||
|
||||
// pipeline shader modules blend solid mask
|
||||
const std::string strComputeBlendSolidMask =
|
||||
strBlendMaskShaderHeader +
|
||||
strBlendShaderBlendMethod +
|
||||
strBlendShaderFooter;
|
||||
const char* cShaderSource_PipelineComputeBlendSolidMask = strComputeBlendSolidMask.c_str();
|
||||
|
||||
// pipeline shader modules blend gradient mask
|
||||
const std::string strComputeBlendGradientMask =
|
||||
strBlendMaskShaderHeader +
|
||||
strBlendShaderPreConditionsGradient +
|
||||
strBlendShaderBlendMethod +
|
||||
strBlendShaderPostConditionsGradient +
|
||||
strBlendShaderFooter;
|
||||
const char* cShaderSource_PipelineComputeBlendGradientMask = strComputeBlendGradientMask.c_str();
|
||||
|
||||
// pipeline shader modules blend image mask
|
||||
const std::string strComputeBlendImageMask =
|
||||
strBlendMaskShaderHeader +
|
||||
strBlendShaderPreConditionsImage +
|
||||
strBlendShaderBlendMethod +
|
||||
strBlendShaderPostConditionsImage +
|
||||
strBlendShaderFooter;
|
||||
const char* cShaderSource_PipelineComputeBlendImageMask = strComputeBlendImageMask.c_str();
|
||||
|
||||
// pipeline shader modules clear
|
||||
const char* cShaderSource_PipelineComputeClear = WG_SHADER_SOURCE(
|
||||
@group(0) @binding(0) var imageDst : texture_storage_2d<rgba8unorm, read_write>;
|
||||
|
@ -494,8 +547,21 @@ fn cs_main( @builtin(global_invocation_id) id: vec3u) {
|
|||
}
|
||||
);
|
||||
|
||||
// pipeline shader modules compose blend
|
||||
const char* cShaderSource_PipelineComputeComposeBlend = WG_SHADER_SOURCE(
|
||||
// pipeline shader modules compose
|
||||
const char* cShaderSource_PipelineComputeMaskCompose = WG_SHADER_SOURCE(
|
||||
@group(0) @binding(0) var imageMsk0 : texture_storage_2d<rgba8unorm, read>;
|
||||
@group(0) @binding(1) var imageMsk1 : texture_storage_2d<rgba8unorm, read_write>;
|
||||
|
||||
@compute @workgroup_size(8, 8)
|
||||
fn cs_main( @builtin(global_invocation_id) id: vec3u) {
|
||||
let colorMsk0 = textureLoad(imageMsk0, id.xy);
|
||||
let colorMsk1 = textureLoad(imageMsk1, id.xy);
|
||||
textureStore(imageMsk1, id.xy, colorMsk0 * colorMsk1);
|
||||
}
|
||||
);
|
||||
|
||||
// pipeline shader modules compose
|
||||
const char* cShaderSource_PipelineComputeCompose = WG_SHADER_SOURCE(
|
||||
@group(0) @binding(0) var imageSrc : texture_storage_2d<rgba8unorm, read>;
|
||||
@group(0) @binding(1) var imageMsk : texture_storage_2d<rgba8unorm, read>;
|
||||
@group(0) @binding(2) var imageDst : texture_storage_2d<rgba8unorm, read_write>;
|
||||
|
|
|
@ -45,7 +45,11 @@ extern const char* cShaderSource_PipelineComputeClear;
|
|||
extern const char* cShaderSource_PipelineComputeBlendSolid;
|
||||
extern const char* cShaderSource_PipelineComputeBlendGradient;
|
||||
extern const char* cShaderSource_PipelineComputeBlendImage;
|
||||
extern const char* cShaderSource_PipelineComputeComposeBlend;
|
||||
extern const char* cShaderSource_PipelineComputeBlendSolidMask;
|
||||
extern const char* cShaderSource_PipelineComputeBlendGradientMask;
|
||||
extern const char* cShaderSource_PipelineComputeBlendImageMask;
|
||||
extern const char* cShaderSource_PipelineComputeMaskCompose;
|
||||
extern const char* cShaderSource_PipelineComputeCompose;
|
||||
extern const char* cShaderSource_PipelineComputeAntiAlias;
|
||||
|
||||
#endif // _TVG_WG_SHADER_SRC_H_
|
||||
|
|
Loading…
Add table
Reference in a new issue