wg_engine: Blending optimization

[issues 1479: lottie](#1479)

To optimize bled operations hardware pipeline blend stage are used for some blend methods:
	BlendMethod::SrcOver
    BlendMethod::Normal
    BlendMethod::Add
    BlendMethod::Multiply
    BlendMethod::Darken
    BlendMethod::Lighten

Other types compute shaders used
This commit is contained in:
Sergii Liebodkin 2024-04-03 00:19:34 +03:00 committed by Hermet Park
parent 622b25a3b4
commit b0280150db
8 changed files with 302 additions and 230 deletions

View file

@ -494,7 +494,7 @@ void WgPipeline::destroyShaderModule(WGPUShaderModule& shaderModule)
// render pipeline // render pipeline
//***************************************************************************** //*****************************************************************************
void WgRenderPipeline::allocate(WGPUDevice device, void WgRenderPipeline::allocate(WGPUDevice device, WgPipelineBlendType blendType,
WGPUVertexBufferLayout vertexBufferLayouts[], uint32_t attribsCount, WGPUVertexBufferLayout vertexBufferLayouts[], uint32_t attribsCount,
WGPUBindGroupLayout bindGroupLayouts[], uint32_t bindGroupsCount, WGPUBindGroupLayout bindGroupLayouts[], uint32_t bindGroupsCount,
WGPUCompareFunction stencilCompareFunction, WGPUStencilOperation stencilOperation, WGPUCompareFunction stencilCompareFunction, WGPUStencilOperation stencilOperation,
@ -506,7 +506,7 @@ void WgRenderPipeline::allocate(WGPUDevice device,
mPipelineLayout = createPipelineLayout(device, bindGroupLayouts, bindGroupsCount); mPipelineLayout = createPipelineLayout(device, bindGroupLayouts, bindGroupsCount);
assert(mPipelineLayout); assert(mPipelineLayout);
mRenderPipeline = createRenderPipeline(device, mRenderPipeline = createRenderPipeline(device, blendType,
vertexBufferLayouts, attribsCount, vertexBufferLayouts, attribsCount,
stencilCompareFunction, stencilOperation, stencilCompareFunction, stencilOperation,
mPipelineLayout, mShaderModule, pipelineLabel); mPipelineLayout, mShaderModule, pipelineLabel);
@ -527,14 +527,42 @@ void WgRenderPipeline::set(WGPURenderPassEncoder renderPassEncoder)
}; };
WGPUBlendState WgRenderPipeline::makeBlendState() WGPUBlendState WgRenderPipeline::makeBlendState(WgPipelineBlendType blendType)
{ {
WGPUBlendState blendState{}; WGPUBlendState blendState{};
blendState.color.operation = WGPUBlendOperation_Add; // src
blendState.color.srcFactor = WGPUBlendFactor_One; if (blendType == WgPipelineBlendType::Src) {
blendState.color.dstFactor = WGPUBlendFactor_Zero; blendState.color.operation = WGPUBlendOperation_Add;
blendState.color.srcFactor = WGPUBlendFactor_One;
blendState.color.dstFactor = WGPUBlendFactor_Zero;
} else // normal
if (blendType == WgPipelineBlendType::Normal) {
blendState.color.operation = WGPUBlendOperation_Add;
blendState.color.srcFactor = WGPUBlendFactor_SrcAlpha;
blendState.color.dstFactor = WGPUBlendFactor_OneMinusSrcAlpha;
} else // add
if (blendType == WgPipelineBlendType::Add) {
blendState.color.operation = WGPUBlendOperation_Add;
blendState.color.srcFactor = WGPUBlendFactor_One;
blendState.color.dstFactor = WGPUBlendFactor_One;
} else // mult
if (blendType == WgPipelineBlendType::Mult) {
blendState.color.operation = WGPUBlendOperation_Add;
blendState.color.srcFactor = WGPUBlendFactor_Dst;
blendState.color.dstFactor = WGPUBlendFactor_Zero;
} else // min
if (blendType == WgPipelineBlendType::Min) {
blendState.color.operation = WGPUBlendOperation_Min;
blendState.color.srcFactor = WGPUBlendFactor_One;
blendState.color.dstFactor = WGPUBlendFactor_One;
} else // max
if (blendType == WgPipelineBlendType::Max) {
blendState.color.operation = WGPUBlendOperation_Max;
blendState.color.srcFactor = WGPUBlendFactor_One;
blendState.color.dstFactor = WGPUBlendFactor_One;
}
blendState.alpha.operation = WGPUBlendOperation_Add; blendState.alpha.operation = WGPUBlendOperation_Add;
blendState.alpha.srcFactor = WGPUBlendFactor_One; blendState.alpha.srcFactor = WGPUBlendFactor_SrcAlpha;
blendState.alpha.dstFactor = WGPUBlendFactor_Zero; blendState.alpha.dstFactor = WGPUBlendFactor_Zero;
return blendState; return blendState;
} }
@ -638,13 +666,13 @@ WGPUFragmentState WgRenderPipeline::makeFragmentState(WGPUShaderModule shaderMod
} }
WGPURenderPipeline WgRenderPipeline::createRenderPipeline(WGPUDevice device, WGPURenderPipeline WgRenderPipeline::createRenderPipeline(WGPUDevice device, WgPipelineBlendType blendType,
WGPUVertexBufferLayout vertexBufferLayouts[], uint32_t attribsCount, WGPUVertexBufferLayout vertexBufferLayouts[], uint32_t attribsCount,
WGPUCompareFunction stencilCompareFunction, WGPUStencilOperation stencilOperation, WGPUCompareFunction stencilCompareFunction, WGPUStencilOperation stencilOperation,
WGPUPipelineLayout pipelineLayout, WGPUShaderModule shaderModule, WGPUPipelineLayout pipelineLayout, WGPUShaderModule shaderModule,
const char* pipelineName) const char* pipelineName)
{ {
WGPUBlendState blendState = makeBlendState(); WGPUBlendState blendState = makeBlendState(blendType);
WGPUColorTargetState colorTargetStates[] = { WGPUColorTargetState colorTargetStates[] = {
makeColorTargetState(&blendState) makeColorTargetState(&blendState)
}; };

View file

@ -28,6 +28,15 @@
#include "tvgCommon.h" #include "tvgCommon.h"
#include "tvgRender.h" #include "tvgRender.h"
enum class WgPipelineBlendType {
Src = 0, // S
Normal, // (Sa * S) + (255 - Sa) * D
Add, // (S + D)
Mult, // (S * D)
Min, // min(S, D)
Max // max(S, D)
};
struct WgPipelines; struct WgPipelines;
struct WgContext { struct WgContext {
@ -107,7 +116,7 @@ struct WgRenderPipeline: public WgPipeline
{ {
protected: protected:
WGPURenderPipeline mRenderPipeline{}; WGPURenderPipeline mRenderPipeline{};
void allocate(WGPUDevice device, void allocate(WGPUDevice device, WgPipelineBlendType blendType,
WGPUVertexBufferLayout vertexBufferLayouts[], uint32_t attribsCount, WGPUVertexBufferLayout vertexBufferLayouts[], uint32_t attribsCount,
WGPUBindGroupLayout bindGroupLayouts[], uint32_t bindGroupsCount, WGPUBindGroupLayout bindGroupLayouts[], uint32_t bindGroupsCount,
WGPUCompareFunction stencilCompareFunction, WGPUStencilOperation stencilOperation, WGPUCompareFunction stencilCompareFunction, WGPUStencilOperation stencilOperation,
@ -116,7 +125,7 @@ public:
void release() override; void release() override;
void set(WGPURenderPassEncoder renderPassEncoder); void set(WGPURenderPassEncoder renderPassEncoder);
static WGPUBlendState makeBlendState(); static WGPUBlendState makeBlendState(WgPipelineBlendType blendType);
static WGPUColorTargetState makeColorTargetState(const WGPUBlendState* blendState); static WGPUColorTargetState makeColorTargetState(const WGPUBlendState* blendState);
static WGPUVertexBufferLayout makeVertexBufferLayout(const WGPUVertexAttribute* vertexAttributes, uint32_t count, uint64_t stride); static WGPUVertexBufferLayout makeVertexBufferLayout(const WGPUVertexAttribute* vertexAttributes, uint32_t count, uint64_t stride);
static WGPUVertexState makeVertexState(WGPUShaderModule shaderModule, const WGPUVertexBufferLayout* buffers, uint32_t count); static WGPUVertexState makeVertexState(WGPUShaderModule shaderModule, const WGPUVertexBufferLayout* buffers, uint32_t count);
@ -125,7 +134,7 @@ public:
static WGPUMultisampleState makeMultisampleState(); static WGPUMultisampleState makeMultisampleState();
static WGPUFragmentState makeFragmentState(WGPUShaderModule shaderModule, WGPUColorTargetState* targets, uint32_t size); static WGPUFragmentState makeFragmentState(WGPUShaderModule shaderModule, WGPUColorTargetState* targets, uint32_t size);
static WGPURenderPipeline createRenderPipeline(WGPUDevice device, static WGPURenderPipeline createRenderPipeline(WGPUDevice device, WgPipelineBlendType blendType,
WGPUVertexBufferLayout vertexBufferLayouts[], uint32_t attribsCount, WGPUVertexBufferLayout vertexBufferLayouts[], uint32_t attribsCount,
WGPUCompareFunction stencilCompareFunction, WGPUStencilOperation stencilOperation, WGPUCompareFunction stencilCompareFunction, WGPUStencilOperation stencilOperation,
WGPUPipelineLayout pipelineLayout, WGPUShaderModule shaderModule, WGPUPipelineLayout pipelineLayout, WGPUShaderModule shaderModule,

View file

@ -53,7 +53,7 @@ void WgPipelineFillShape::initialize(WGPUDevice device)
auto pipelineLabel = "The render pipeline fill shape"; auto pipelineLabel = "The render pipeline fill shape";
// allocate all pipeline handles // allocate all pipeline handles
allocate(device, allocate(device, WgPipelineBlendType::Src,
vertexBufferLayouts, ARRAY_ELEMENTS_COUNT(vertexBufferLayouts), vertexBufferLayouts, ARRAY_ELEMENTS_COUNT(vertexBufferLayouts),
bindGroupLayouts, ARRAY_ELEMENTS_COUNT(bindGroupLayouts), bindGroupLayouts, ARRAY_ELEMENTS_COUNT(bindGroupLayouts),
stencilFuncion, stencilOperation, stencilFuncion, stencilOperation,
@ -85,7 +85,7 @@ void WgPipelineFillStroke::initialize(WGPUDevice device)
auto pipelineLabel = "The render pipeline fill stroke"; auto pipelineLabel = "The render pipeline fill stroke";
// allocate all pipeline handles // allocate all pipeline handles
allocate(device, allocate(device, WgPipelineBlendType::Src,
vertexBufferLayouts, ARRAY_ELEMENTS_COUNT(vertexBufferLayouts), vertexBufferLayouts, ARRAY_ELEMENTS_COUNT(vertexBufferLayouts),
bindGroupLayouts, ARRAY_ELEMENTS_COUNT(bindGroupLayouts), bindGroupLayouts, ARRAY_ELEMENTS_COUNT(bindGroupLayouts),
stencilFuncion, stencilOperation, stencilFuncion, stencilOperation,
@ -93,7 +93,7 @@ void WgPipelineFillStroke::initialize(WGPUDevice device)
} }
void WgPipelineSolid::initialize(WGPUDevice device) void WgPipelineSolid::initialize(WGPUDevice device, WgPipelineBlendType blendType)
{ {
// vertex and buffers settings // vertex and buffers settings
WGPUVertexAttribute vertexAttributesPos = { WGPUVertexFormat_Float32x2, sizeof(float) * 0, 0 }; WGPUVertexAttribute vertexAttributesPos = { WGPUVertexFormat_Float32x2, sizeof(float) * 0, 0 };
@ -118,7 +118,7 @@ void WgPipelineSolid::initialize(WGPUDevice device)
auto pipelineLabel = "The render pipeline solid color"; auto pipelineLabel = "The render pipeline solid color";
// allocate all pipeline handles // allocate all pipeline handles
allocate(device, allocate(device, blendType,
vertexBufferLayouts, ARRAY_ELEMENTS_COUNT(vertexBufferLayouts), vertexBufferLayouts, ARRAY_ELEMENTS_COUNT(vertexBufferLayouts),
bindGroupLayouts, ARRAY_ELEMENTS_COUNT(bindGroupLayouts), bindGroupLayouts, ARRAY_ELEMENTS_COUNT(bindGroupLayouts),
stencilFuncion, stencilOperation, stencilFuncion, stencilOperation,
@ -126,7 +126,7 @@ void WgPipelineSolid::initialize(WGPUDevice device)
} }
void WgPipelineLinear::initialize(WGPUDevice device) void WgPipelineLinear::initialize(WGPUDevice device, WgPipelineBlendType blendType)
{ {
// vertex and buffers settings // vertex and buffers settings
WGPUVertexAttribute vertexAttributesPos = { WGPUVertexFormat_Float32x2, sizeof(float) * 0, 0 }; WGPUVertexAttribute vertexAttributesPos = { WGPUVertexFormat_Float32x2, sizeof(float) * 0, 0 };
@ -151,7 +151,7 @@ void WgPipelineLinear::initialize(WGPUDevice device)
auto pipelineLabel = "The render pipeline linear gradient"; auto pipelineLabel = "The render pipeline linear gradient";
// allocate all pipeline handles // allocate all pipeline handles
allocate(device, allocate(device, blendType,
vertexBufferLayouts, ARRAY_ELEMENTS_COUNT(vertexBufferLayouts), vertexBufferLayouts, ARRAY_ELEMENTS_COUNT(vertexBufferLayouts),
bindGroupLayouts, ARRAY_ELEMENTS_COUNT(bindGroupLayouts), bindGroupLayouts, ARRAY_ELEMENTS_COUNT(bindGroupLayouts),
stencilFuncion, stencilOperation, stencilFuncion, stencilOperation,
@ -159,7 +159,7 @@ void WgPipelineLinear::initialize(WGPUDevice device)
} }
void WgPipelineRadial::initialize(WGPUDevice device) void WgPipelineRadial::initialize(WGPUDevice device, WgPipelineBlendType blendType)
{ {
// vertex and buffers settings // vertex and buffers settings
WGPUVertexAttribute vertexAttributesPos = { WGPUVertexFormat_Float32x2, sizeof(float) * 0, 0 }; WGPUVertexAttribute vertexAttributesPos = { WGPUVertexFormat_Float32x2, sizeof(float) * 0, 0 };
@ -184,7 +184,7 @@ void WgPipelineRadial::initialize(WGPUDevice device)
auto pipelineLabel = "The render pipeline radial gradient"; auto pipelineLabel = "The render pipeline radial gradient";
// allocate all pipeline handles // allocate all pipeline handles
allocate(device, allocate(device, blendType,
vertexBufferLayouts, ARRAY_ELEMENTS_COUNT(vertexBufferLayouts), vertexBufferLayouts, ARRAY_ELEMENTS_COUNT(vertexBufferLayouts),
bindGroupLayouts, ARRAY_ELEMENTS_COUNT(bindGroupLayouts), bindGroupLayouts, ARRAY_ELEMENTS_COUNT(bindGroupLayouts),
stencilFuncion, stencilOperation, stencilFuncion, stencilOperation,
@ -192,7 +192,7 @@ void WgPipelineRadial::initialize(WGPUDevice device)
} }
void WgPipelineImage::initialize(WGPUDevice device) void WgPipelineImage::initialize(WGPUDevice device, WgPipelineBlendType blendType)
{ {
// vertex and buffers settings // vertex and buffers settings
WGPUVertexAttribute vertexAttributesPos = { WGPUVertexFormat_Float32x2, sizeof(float) * 0, 0 }; WGPUVertexAttribute vertexAttributesPos = { WGPUVertexFormat_Float32x2, sizeof(float) * 0, 0 };
@ -219,7 +219,7 @@ void WgPipelineImage::initialize(WGPUDevice device)
auto pipelineLabel = "The render pipeline image"; auto pipelineLabel = "The render pipeline image";
// allocate all pipeline handles // allocate all pipeline handles
allocate(device, allocate(device, blendType,
vertexBufferLayouts, ARRAY_ELEMENTS_COUNT(vertexBufferLayouts), vertexBufferLayouts, ARRAY_ELEMENTS_COUNT(vertexBufferLayouts),
bindGroupLayouts, ARRAY_ELEMENTS_COUNT(bindGroupLayouts), bindGroupLayouts, ARRAY_ELEMENTS_COUNT(bindGroupLayouts),
stencilFuncion, stencilOperation, stencilFuncion, stencilOperation,
@ -320,10 +320,12 @@ void WgPipelines::initialize(WgContext& context)
// fill pipelines // fill pipelines
fillShape.initialize(context.device); fillShape.initialize(context.device);
fillStroke.initialize(context.device); fillStroke.initialize(context.device);
solid.initialize(context.device); for (uint8_t type = (uint8_t)WgPipelineBlendType::Src; type <= (uint8_t)WgPipelineBlendType::Max; type++) {
linear.initialize(context.device); solid[type].initialize(context.device, (WgPipelineBlendType)type);
radial.initialize(context.device); linear[type].initialize(context.device, (WgPipelineBlendType)type);
image.initialize(context.device); radial[type].initialize(context.device, (WgPipelineBlendType)type);
image[type].initialize(context.device, (WgPipelineBlendType)type);
}
// compute pipelines // compute pipelines
computeClear.initialize(context.device); computeClear.initialize(context.device);
computeBlend.initialize(context.device); computeBlend.initialize(context.device);
@ -352,10 +354,41 @@ void WgPipelines::release()
computeBlend.release(); computeBlend.release();
computeClear.release(); computeClear.release();
// fill pipelines // fill pipelines
image.release(); for (uint8_t type = (uint8_t)WgPipelineBlendType::Src; type <= (uint8_t)WgPipelineBlendType::Max; type++) {
radial.release(); image[type].release();
linear.release(); radial[type].release();
solid.release(); linear[type].release();
solid[type].release();
}
fillStroke.release(); fillStroke.release();
fillShape.release(); fillShape.release();
} }
bool WgPipelines::isBlendMethodSupportsHW(BlendMethod blendMethod)
{
switch (blendMethod) {
case BlendMethod::SrcOver:
case BlendMethod::Normal:
case BlendMethod::Add:
case BlendMethod::Multiply:
case BlendMethod::Darken:
case BlendMethod::Lighten:
return true;
default: return false;
};
}
WgPipelineBlendType WgPipelines::blendMethodToBlendType(BlendMethod blendMethod)
{
switch (blendMethod) {
case BlendMethod::SrcOver: return WgPipelineBlendType::Src;
case BlendMethod::Normal: return WgPipelineBlendType::Normal;
case BlendMethod::Add: return WgPipelineBlendType::Add;
case BlendMethod::Multiply: return WgPipelineBlendType::Mult;
case BlendMethod::Darken: return WgPipelineBlendType::Min;
case BlendMethod::Lighten: return WgPipelineBlendType::Max;
default: return WgPipelineBlendType::Src;
};
}

View file

@ -53,7 +53,8 @@ struct WgPipelineFillStroke: public WgRenderPipeline
struct WgPipelineSolid: public WgRenderPipeline struct WgPipelineSolid: public WgRenderPipeline
{ {
void initialize(WGPUDevice device) override; void initialize(WGPUDevice device) override {}
void initialize(WGPUDevice device, WgPipelineBlendType blendType);
void use(WGPURenderPassEncoder encoder, WgBindGroupCanvas& groupCanvas,WgBindGroupPaint& groupPaint, WgBindGroupSolidColor& groupSolid) void use(WGPURenderPassEncoder encoder, WgBindGroupCanvas& groupCanvas,WgBindGroupPaint& groupPaint, WgBindGroupSolidColor& groupSolid)
{ {
set(encoder); set(encoder);
@ -65,7 +66,8 @@ struct WgPipelineSolid: public WgRenderPipeline
struct WgPipelineLinear: public WgRenderPipeline struct WgPipelineLinear: public WgRenderPipeline
{ {
void initialize(WGPUDevice device) override; void initialize(WGPUDevice device) override {}
void initialize(WGPUDevice device, WgPipelineBlendType blendType);
void use(WGPURenderPassEncoder encoder, WgBindGroupCanvas& groupCanvas, WgBindGroupPaint& groupPaint, WgBindGroupLinearGradient& groupLinear) void use(WGPURenderPassEncoder encoder, WgBindGroupCanvas& groupCanvas, WgBindGroupPaint& groupPaint, WgBindGroupLinearGradient& groupLinear)
{ {
set(encoder); set(encoder);
@ -77,7 +79,8 @@ struct WgPipelineLinear: public WgRenderPipeline
struct WgPipelineRadial: public WgRenderPipeline struct WgPipelineRadial: public WgRenderPipeline
{ {
void initialize(WGPUDevice device) override; void initialize(WGPUDevice device) override {}
void initialize(WGPUDevice device, WgPipelineBlendType blendType);
void use(WGPURenderPassEncoder encoder, WgBindGroupCanvas& groupCanvas, WgBindGroupPaint& groupPaint, WgBindGroupRadialGradient& groupRadial) void use(WGPURenderPassEncoder encoder, WgBindGroupCanvas& groupCanvas, WgBindGroupPaint& groupPaint, WgBindGroupRadialGradient& groupRadial)
{ {
set(encoder); set(encoder);
@ -89,7 +92,8 @@ struct WgPipelineRadial: public WgRenderPipeline
struct WgPipelineImage: public WgRenderPipeline struct WgPipelineImage: public WgRenderPipeline
{ {
void initialize(WGPUDevice device) override; void initialize(WGPUDevice device) override {}
void initialize(WGPUDevice device, WgPipelineBlendType blendType);
void use(WGPURenderPassEncoder encoder, WgBindGroupCanvas& groupCanvas, WgBindGroupPaint& groupPaint, WgBindGroupPicture& groupPicture) void use(WGPURenderPassEncoder encoder, WgBindGroupCanvas& groupCanvas, WgBindGroupPaint& groupPaint, WgBindGroupPicture& groupPicture)
{ {
set(encoder); set(encoder);
@ -161,10 +165,11 @@ struct WgPipelines
// render pipelines // render pipelines
WgPipelineFillShape fillShape; WgPipelineFillShape fillShape;
WgPipelineFillStroke fillStroke; WgPipelineFillStroke fillStroke;
WgPipelineSolid solid; // fill pipelines
WgPipelineLinear linear; WgPipelineSolid solid[6];
WgPipelineRadial radial; WgPipelineLinear linear[6];
WgPipelineImage image; WgPipelineRadial radial[6];
WgPipelineImage image[6];
// compute pipelines // compute pipelines
WgPipelineClear computeClear; WgPipelineClear computeClear;
WgPipelineBlend computeBlend; WgPipelineBlend computeBlend;
@ -173,6 +178,9 @@ struct WgPipelines
void initialize(WgContext& context); void initialize(WgContext& context);
void release(); void release();
static bool isBlendMethodSupportsHW(BlendMethod blendMethod);
static WgPipelineBlendType blendMethodToBlendType(BlendMethod blendMethod);
}; };
#endif // _TVG_WG_PIPELINES_H_ #endif // _TVG_WG_PIPELINES_H_

View file

@ -23,21 +23,30 @@
#include "tvgWgRenderTarget.h" #include "tvgWgRenderTarget.h"
//***************************************************************************** //*****************************************************************************
// render target // render storage
//***************************************************************************** //*****************************************************************************
void WgRenderTarget::initialize(WgContext& context, uint32_t w, uint32_t h, uint32_t samples) void WgRenderStorage::initialize(WgContext& context, uint32_t w, uint32_t h, uint32_t samples)
{ {
release(context); release(context);
// store target storage size
width = w * samples;
height = h * samples;
workgroupsCountX = (width + WG_COMPUTE_WORKGROUP_SIZE_X - 1) / WG_COMPUTE_WORKGROUP_SIZE_X; // workgroup size x == 8
workgroupsCountY = (height + WG_COMPUTE_WORKGROUP_SIZE_Y - 1) / WG_COMPUTE_WORKGROUP_SIZE_Y; // workgroup size y == 8
// create color and stencil textures // create color and stencil textures
texColor = context.createTexture2d( texColor = context.createTexture2d(
WGPUTextureUsage_RenderAttachment | WGPUTextureUsage_StorageBinding, WGPUTextureUsage_CopySrc |
WGPUTextureUsage_CopyDst |
WGPUTextureUsage_TextureBinding |
WGPUTextureUsage_StorageBinding |
WGPUTextureUsage_RenderAttachment,
WGPUTextureFormat_RGBA8Unorm, WGPUTextureFormat_RGBA8Unorm,
w * samples, h * samples, "The target texture color"); width, height, "The target texture color");
texStencil = context.createTexture2d( texStencil = context.createTexture2d(
WGPUTextureUsage_RenderAttachment, WGPUTextureUsage_RenderAttachment,
WGPUTextureFormat_Stencil8, WGPUTextureFormat_Stencil8,
w * samples, h * samples, "The target texture stencil"); width, height, "The target texture stencil");
assert(texColor); assert(texColor);
assert(texStencil); assert(texStencil);
texViewColor = context.createTextureView2d(texColor, "The target texture view color"); texViewColor = context.createTextureView2d(texColor, "The target texture view color");
@ -50,96 +59,150 @@ void WgRenderTarget::initialize(WgContext& context, uint32_t w, uint32_t h, uint
WgShaderTypeMat4x4f viewMat(w, h); WgShaderTypeMat4x4f viewMat(w, h);
mBindGroupCanvas.initialize(context.device, context.queue, viewMat); mBindGroupCanvas.initialize(context.device, context.queue, viewMat);
mPipelines = context.pipelines; mPipelines = context.pipelines;
} }
void WgRenderTarget::release(WgContext& context) void WgRenderStorage::release(WgContext& context)
{ {
mRenderPassEncoder = nullptr;
mBindGroupCanvas.release(); mBindGroupCanvas.release();
bindGroupTexStorage.release(); bindGroupTexStorage.release();
context.releaseTextureView(texViewStencil); context.releaseTextureView(texViewStencil);
context.releaseTextureView(texViewColor); context.releaseTextureView(texViewColor);
context.releaseTexture(texStencil); context.releaseTexture(texStencil);
context.releaseTexture(texColor); context.releaseTexture(texColor);
workgroupsCountX = 0;
workgroupsCountY = 0;
height = 0;
width = 0;
} }
void WgRenderTarget::renderShape(WGPUCommandEncoder commandEncoder, WgRenderDataShape* renderData) void WgRenderStorage::renderShape(WgRenderDataShape* renderData, WgPipelineBlendType blendType)
{ {
assert(renderData); assert(renderData);
assert(commandEncoder); assert(mRenderPassEncoder);
WGPURenderPassEncoder renderPassEncoder = beginRenderPass(commandEncoder);
if (renderData->strokeFirst) if (renderData->strokeFirst)
drawStroke(renderPassEncoder, renderData); drawStroke(renderData, blendType);
drawShape(renderPassEncoder, renderData); drawShape(renderData, blendType);
if (!renderData->strokeFirst) if (!renderData->strokeFirst)
drawStroke(renderPassEncoder, renderData); drawStroke(renderData, blendType);
endRenderPass(renderPassEncoder);
} }
void WgRenderTarget::renderPicture(WGPUCommandEncoder commandEncoder, WgRenderDataPicture* renderData) void WgRenderStorage::renderPicture(WgRenderDataPicture* renderData, WgPipelineBlendType blendType)
{ {
assert(renderData); assert(renderData);
assert(commandEncoder); assert(mRenderPassEncoder);
WGPURenderPassEncoder renderPassEncoder = beginRenderPass(commandEncoder); uint8_t blend = (uint8_t)blendType;
wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0); wgpuRenderPassEncoderSetStencilReference(mRenderPassEncoder, 0);
mPipelines->image.use(renderPassEncoder, mBindGroupCanvas, renderData->bindGroupPaint, renderData->bindGroupPicture); mPipelines->image[blend].use(mRenderPassEncoder, mBindGroupCanvas, renderData->bindGroupPaint, renderData->bindGroupPicture);
renderData->meshData.drawImage(renderPassEncoder); renderData->meshData.drawImage(mRenderPassEncoder);
endRenderPass(renderPassEncoder);
} }
void WgRenderTarget::drawShape(WGPURenderPassEncoder renderPassEncoder, WgRenderDataShape* renderData) void WgRenderStorage::drawShape(WgRenderDataShape* renderData, WgPipelineBlendType blendType)
{ {
assert(renderData); assert(renderData);
assert(renderPassEncoder); assert(mRenderPassEncoder);
// draw shape geometry // draw shape geometry
wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0); uint8_t blend = (uint8_t)blendType;
wgpuRenderPassEncoderSetStencilReference(mRenderPassEncoder, 0);
for (uint32_t i = 0; i < renderData->meshGroupShapes.meshes.count; i++) { for (uint32_t i = 0; i < renderData->meshGroupShapes.meshes.count; i++) {
// draw to stencil (first pass) // draw to stencil (first pass)
mPipelines->fillShape.use(renderPassEncoder, mBindGroupCanvas, renderData->bindGroupPaint); mPipelines->fillShape.use(mRenderPassEncoder, mBindGroupCanvas, renderData->bindGroupPaint);
renderData->meshGroupShapes.meshes[i]->draw(renderPassEncoder); renderData->meshGroupShapes.meshes[i]->draw(mRenderPassEncoder);
// fill shape (second pass) // fill shape (second pass)
WgRenderSettings& settings = renderData->renderSettingsShape; WgRenderSettings& settings = renderData->renderSettingsShape;
if (settings.fillType == WgRenderSettingsType::Solid) if (settings.fillType == WgRenderSettingsType::Solid)
mPipelines->solid.use(renderPassEncoder, mBindGroupCanvas, renderData->bindGroupPaint, settings.bindGroupSolid); mPipelines->solid[blend].use(mRenderPassEncoder, mBindGroupCanvas, renderData->bindGroupPaint, settings.bindGroupSolid);
else if (settings.fillType == WgRenderSettingsType::Linear) else if (settings.fillType == WgRenderSettingsType::Linear)
mPipelines->linear.use(renderPassEncoder, mBindGroupCanvas, renderData->bindGroupPaint, settings.bindGroupLinear); mPipelines->linear[blend].use(mRenderPassEncoder, mBindGroupCanvas, renderData->bindGroupPaint, settings.bindGroupLinear);
else if (settings.fillType == WgRenderSettingsType::Radial) else if (settings.fillType == WgRenderSettingsType::Radial)
mPipelines->radial.use(renderPassEncoder, mBindGroupCanvas, renderData->bindGroupPaint, settings.bindGroupRadial); mPipelines->radial[blend].use(mRenderPassEncoder, mBindGroupCanvas, renderData->bindGroupPaint, settings.bindGroupRadial);
renderData->meshBBoxShapes.draw(renderPassEncoder); renderData->meshBBoxShapes.draw(mRenderPassEncoder);
} }
} }
void WgRenderTarget::drawStroke(WGPURenderPassEncoder renderPassEncoder, WgRenderDataShape* renderData) void WgRenderStorage::drawStroke(WgRenderDataShape* renderData, WgPipelineBlendType blendType)
{ {
assert(renderData); assert(renderData);
assert(renderPassEncoder); assert(mRenderPassEncoder);
// draw stroke geometry // draw stroke geometry
uint8_t blend = (uint8_t)blendType;
if (renderData->meshGroupStrokes.meshes.count > 0) { if (renderData->meshGroupStrokes.meshes.count > 0) {
// draw strokes to stencil (first pass) // draw strokes to stencil (first pass)
wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 255); wgpuRenderPassEncoderSetStencilReference(mRenderPassEncoder, 255);
for (uint32_t i = 0; i < renderData->meshGroupStrokes.meshes.count; i++) { for (uint32_t i = 0; i < renderData->meshGroupStrokes.meshes.count; i++) {
mPipelines->fillStroke.use(renderPassEncoder, mBindGroupCanvas, renderData->bindGroupPaint); mPipelines->fillStroke.use(mRenderPassEncoder, mBindGroupCanvas, renderData->bindGroupPaint);
renderData->meshGroupStrokes.meshes[i]->draw(renderPassEncoder); renderData->meshGroupStrokes.meshes[i]->draw(mRenderPassEncoder);
} }
// fill shape (second pass) // fill shape (second pass)
wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0); wgpuRenderPassEncoderSetStencilReference(mRenderPassEncoder, 0);
WgRenderSettings& settings = renderData->renderSettingsStroke; WgRenderSettings& settings = renderData->renderSettingsStroke;
if (settings.fillType == WgRenderSettingsType::Solid) if (settings.fillType == WgRenderSettingsType::Solid)
mPipelines->solid.use(renderPassEncoder, mBindGroupCanvas, renderData->bindGroupPaint, settings.bindGroupSolid); mPipelines->solid[blend].use(mRenderPassEncoder, mBindGroupCanvas, renderData->bindGroupPaint, settings.bindGroupSolid);
else if (settings.fillType == WgRenderSettingsType::Linear) else if (settings.fillType == WgRenderSettingsType::Linear)
mPipelines->linear.use(renderPassEncoder, mBindGroupCanvas, renderData->bindGroupPaint, settings.bindGroupLinear); mPipelines->linear[blend].use(mRenderPassEncoder, mBindGroupCanvas, renderData->bindGroupPaint, settings.bindGroupLinear);
else if (settings.fillType == WgRenderSettingsType::Radial) else if (settings.fillType == WgRenderSettingsType::Radial)
mPipelines->radial.use(renderPassEncoder, mBindGroupCanvas, renderData->bindGroupPaint, settings.bindGroupRadial); mPipelines->radial[blend].use(mRenderPassEncoder, mBindGroupCanvas, renderData->bindGroupPaint, settings.bindGroupRadial);
renderData->meshBBoxStrokes.draw(renderPassEncoder); renderData->meshBBoxStrokes.draw(mRenderPassEncoder);
} }
} }
WGPURenderPassEncoder WgRenderTarget::beginRenderPass(WGPUCommandEncoder commandEncoder) void WgRenderStorage::clear(WGPUCommandEncoder commandEncoder)
{
assert(commandEncoder);
WGPUComputePassEncoder computePassEncoder = beginComputePass(commandEncoder);
mPipelines->computeClear.use(computePassEncoder, bindGroupTexStorage);
dispatchWorkgroups(computePassEncoder);
endComputePass(computePassEncoder);
}
void WgRenderStorage::blend(WGPUCommandEncoder commandEncoder, WgRenderStorage* targetSrc, WgBindGroupBlendMethod* blendMethod)
{
assert(commandEncoder);
assert(targetSrc);
WGPUComputePassEncoder computePassEncoder = beginComputePass(commandEncoder);
mPipelines->computeBlend.use(computePassEncoder, targetSrc->bindGroupTexStorage, bindGroupTexStorage, *blendMethod);
dispatchWorkgroups(computePassEncoder);
endComputePass(computePassEncoder);
};
void WgRenderStorage::compose(WGPUCommandEncoder commandEncoder, WgRenderStorage* targetMsk, WgBindGroupCompositeMethod* composeMethod, WgBindGroupOpacity* opacity)
{
assert(commandEncoder);
assert(targetMsk);
WGPUComputePassEncoder computePassEncoder = beginComputePass(commandEncoder);
mPipelines->computeCompose.use(computePassEncoder, bindGroupTexStorage, targetMsk->bindGroupTexStorage, *composeMethod, *opacity);
dispatchWorkgroups(computePassEncoder);
endComputePass(computePassEncoder);
};
void WgRenderStorage::antialias(WGPUCommandEncoder commandEncoder, WgRenderStorage* targetSrc)
{
assert(commandEncoder);
assert(targetSrc);
WGPUComputePassEncoder computePassEncoder = beginComputePass(commandEncoder);
mPipelines->computeAntiAliasing.use(computePassEncoder, targetSrc->bindGroupTexStorage, bindGroupTexStorage);
dispatchWorkgroups(computePassEncoder);
endComputePass(computePassEncoder);
}
void WgRenderStorage::dispatchWorkgroups(WGPUComputePassEncoder computePassEncoder)
{
assert(computePassEncoder);
wgpuComputePassEncoderDispatchWorkgroups(computePassEncoder, workgroupsCountX, workgroupsCountY, 1);
}
void WgRenderStorage::beginRenderPass(WGPUCommandEncoder commandEncoder, bool clear)
{ {
assert(commandEncoder); assert(commandEncoder);
// render pass depth stencil attachment // render pass depth stencil attachment
@ -157,7 +220,7 @@ WGPURenderPassEncoder WgRenderTarget::beginRenderPass(WGPUCommandEncoder command
WGPURenderPassColorAttachment colorAttachment{}; WGPURenderPassColorAttachment colorAttachment{};
colorAttachment.view = texViewColor; colorAttachment.view = texViewColor;
colorAttachment.resolveTarget = nullptr; colorAttachment.resolveTarget = nullptr;
colorAttachment.loadOp = WGPULoadOp_Clear; colorAttachment.loadOp = clear ? WGPULoadOp_Clear : WGPULoadOp_Load;
colorAttachment.clearValue = { 0, 0, 0, 0 }; colorAttachment.clearValue = { 0, 0, 0, 0 };
colorAttachment.storeOp = WGPUStoreOp_Store; colorAttachment.storeOp = WGPUStoreOp_Store;
// render pass descriptor // render pass descriptor
@ -171,111 +234,16 @@ WGPURenderPassEncoder WgRenderTarget::beginRenderPass(WGPUCommandEncoder command
renderPassDesc.occlusionQuerySet = nullptr; renderPassDesc.occlusionQuerySet = nullptr;
renderPassDesc.timestampWrites = nullptr; renderPassDesc.timestampWrites = nullptr;
// begin render pass // begin render pass
return wgpuCommandEncoderBeginRenderPass(commandEncoder, &renderPassDesc); mRenderPassEncoder = wgpuCommandEncoderBeginRenderPass(commandEncoder, &renderPassDesc);
} }
void WgRenderTarget::endRenderPass(WGPURenderPassEncoder renderPassEncoder) void WgRenderStorage::endRenderPass()
{ {
assert(renderPassEncoder); assert(mRenderPassEncoder);
wgpuRenderPassEncoderEnd(renderPassEncoder); wgpuRenderPassEncoderEnd(mRenderPassEncoder);
wgpuRenderPassEncoderRelease(renderPassEncoder); wgpuRenderPassEncoderRelease(mRenderPassEncoder);
} mRenderPassEncoder = nullptr;
//*****************************************************************************
// render storage
//*****************************************************************************
void WgRenderStorage::initialize(WgContext& context, uint32_t w, uint32_t h, uint32_t samples)
{
release(context);
// store target storage size
width = w * samples;
height = h * samples;
workgroupsCountX = (width + WG_COMPUTE_WORKGROUP_SIZE_X - 1) / WG_COMPUTE_WORKGROUP_SIZE_X; // workgroup size x == 8
workgroupsCountY = (height + WG_COMPUTE_WORKGROUP_SIZE_Y - 1) / WG_COMPUTE_WORKGROUP_SIZE_Y; // workgroup size y == 8
// create color and stencil textures
texStorage = context.createTexture2d(
WGPUTextureUsage_StorageBinding | WGPUTextureUsage_CopySrc | WGPUTextureUsage_CopyDst,
WGPUTextureFormat_RGBA8Unorm,
width, height, "The target texture storage color");
assert(texStorage);
texViewStorage = context.createTextureView2d(texStorage, "The target texture storage view color");
assert(texViewStorage);
// initialize bind group for blitting
bindGroupTexStorage.initialize(context.device, context.queue, texViewStorage);
mPipelines = context.pipelines;
}
void WgRenderStorage::release(WgContext& context)
{
bindGroupTexStorage.release();
context.releaseTextureView(texViewStorage);
context.releaseTexture(texStorage);
workgroupsCountX = 0;
workgroupsCountY = 0;
height = 0;
width = 0;
}
void WgRenderStorage::clear(WGPUCommandEncoder commandEncoder)
{
assert(commandEncoder);
WGPUComputePassEncoder computePassEncoder = beginComputePass(commandEncoder);
mPipelines->computeClear.use(computePassEncoder, bindGroupTexStorage);
dispatchWorkgroups(computePassEncoder);
endRenderPass(computePassEncoder);
}
void WgRenderStorage::blend(WGPUCommandEncoder commandEncoder, WgRenderTarget* targetSrc, WgBindGroupBlendMethod* blendMethod)
{
assert(commandEncoder);
assert(targetSrc);
WGPUComputePassEncoder computePassEncoder = beginComputePass(commandEncoder);
mPipelines->computeBlend.use(computePassEncoder, targetSrc->bindGroupTexStorage, bindGroupTexStorage, *blendMethod);
dispatchWorkgroups(computePassEncoder);
endRenderPass(computePassEncoder);
};
void WgRenderStorage::blend(WGPUCommandEncoder commandEncoder, WgRenderStorage* targetSrc, WgBindGroupBlendMethod* blendMethod)
{
assert(commandEncoder);
assert(targetSrc);
WGPUComputePassEncoder computePassEncoder = beginComputePass(commandEncoder);
mPipelines->computeBlend.use(computePassEncoder, targetSrc->bindGroupTexStorage, bindGroupTexStorage, *blendMethod);
dispatchWorkgroups(computePassEncoder);
endRenderPass(computePassEncoder);
};
void WgRenderStorage::compose(WGPUCommandEncoder commandEncoder, WgRenderStorage* targetMsk, WgBindGroupCompositeMethod* composeMethod, WgBindGroupOpacity* opacity)
{
assert(commandEncoder);
assert(targetMsk);
WGPUComputePassEncoder computePassEncoder = beginComputePass(commandEncoder);
mPipelines->computeCompose.use(computePassEncoder, bindGroupTexStorage, targetMsk->bindGroupTexStorage, *composeMethod, *opacity);
dispatchWorkgroups(computePassEncoder);
endRenderPass(computePassEncoder);
};
void WgRenderStorage::antialias(WGPUCommandEncoder commandEncoder, WgRenderStorage* targetSrc)
{
assert(commandEncoder);
assert(targetSrc);
WGPUComputePassEncoder computePassEncoder = beginComputePass(commandEncoder);
mPipelines->computeAntiAliasing.use(computePassEncoder, targetSrc->bindGroupTexStorage, bindGroupTexStorage);
dispatchWorkgroups(computePassEncoder);
endRenderPass(computePassEncoder);
}
void WgRenderStorage::dispatchWorkgroups(WGPUComputePassEncoder computePassEncoder)
{
assert(computePassEncoder);
wgpuComputePassEncoderDispatchWorkgroups(computePassEncoder, workgroupsCountX, workgroupsCountY, 1);
} }
@ -290,7 +258,7 @@ WGPUComputePassEncoder WgRenderStorage::beginComputePass(WGPUCommandEncoder comm
}; };
void WgRenderStorage::endRenderPass(WGPUComputePassEncoder computePassEncoder) void WgRenderStorage::endComputePass(WGPUComputePassEncoder computePassEncoder)
{ {
assert(computePassEncoder); assert(computePassEncoder);
wgpuComputePassEncoderEnd(computePassEncoder); wgpuComputePassEncoderEnd(computePassEncoder);

View file

@ -25,10 +25,11 @@
#include "tvgWgRenderData.h" #include "tvgWgRenderData.h"
class WgRenderTarget { class WgRenderStorage {
private: private:
// canvas info // texture buffers
WgBindGroupCanvas mBindGroupCanvas; WgBindGroupCanvas mBindGroupCanvas;
WGPURenderPassEncoder mRenderPassEncoder{};
WgPipelines* mPipelines{}; // external handle WgPipelines* mPipelines{}; // external handle
public: public:
WGPUTexture texColor{}; WGPUTexture texColor{};
@ -36,29 +37,6 @@ public:
WGPUTextureView texViewColor{}; WGPUTextureView texViewColor{};
WGPUTextureView texViewStencil{}; WGPUTextureView texViewStencil{};
WgBindGroupTextureStorage bindGroupTexStorage; WgBindGroupTextureStorage bindGroupTexStorage;
public:
void initialize(WgContext& context, uint32_t w, uint32_t h, uint32_t samples = 1);
void release(WgContext& context);
void renderShape(WGPUCommandEncoder commandEncoder, WgRenderDataShape* renderData);
void renderPicture(WGPUCommandEncoder commandEncoder, WgRenderDataPicture* renderData);
private:
void drawShape(WGPURenderPassEncoder renderPassEncoder, WgRenderDataShape* renderData);
void drawStroke(WGPURenderPassEncoder renderPassEncoder, WgRenderDataShape* renderData);
WGPURenderPassEncoder beginRenderPass(WGPUCommandEncoder commandEncoder);
void endRenderPass(WGPURenderPassEncoder renderPassEncoder);
};
class WgRenderStorage {
private:
// texture buffers
WgPipelines* mPipelines{}; // external handle
public:
WGPUTexture texStorage{};
WGPUTextureView texViewStorage{};
WgBindGroupTextureStorage bindGroupTexStorage;
uint32_t width{}; uint32_t width{};
uint32_t height{}; uint32_t height{};
uint32_t workgroupsCountX{}; uint32_t workgroupsCountX{};
@ -67,16 +45,24 @@ public:
void initialize(WgContext& context, uint32_t w, uint32_t h, uint32_t samples = 1); void initialize(WgContext& context, uint32_t w, uint32_t h, uint32_t samples = 1);
void release(WgContext& context); void release(WgContext& context);
void beginRenderPass(WGPUCommandEncoder commandEncoder, bool clear);
void endRenderPass();
void renderShape(WgRenderDataShape* renderData, WgPipelineBlendType blendType);
void renderPicture(WgRenderDataPicture* renderData, WgPipelineBlendType blendType);
void clear(WGPUCommandEncoder commandEncoder); void clear(WGPUCommandEncoder commandEncoder);
void blend(WGPUCommandEncoder commandEncoder, WgRenderTarget* targetSrc, WgBindGroupBlendMethod* blendMethod);
void blend(WGPUCommandEncoder commandEncoder, WgRenderStorage* targetSrc, WgBindGroupBlendMethod* blendMethod); void blend(WGPUCommandEncoder commandEncoder, WgRenderStorage* targetSrc, WgBindGroupBlendMethod* blendMethod);
void compose(WGPUCommandEncoder commandEncoder, WgRenderStorage* targetMsk, WgBindGroupCompositeMethod* composeMethod, WgBindGroupOpacity* opacity); void compose(WGPUCommandEncoder commandEncoder, WgRenderStorage* targetMsk, WgBindGroupCompositeMethod* composeMethod, WgBindGroupOpacity* opacity);
void antialias(WGPUCommandEncoder commandEncoder, WgRenderStorage* targetSrc); void antialias(WGPUCommandEncoder commandEncoder, WgRenderStorage* targetSrc);
private: private:
void drawShape(WgRenderDataShape* renderData, WgPipelineBlendType blendType);
void drawStroke(WgRenderDataShape* renderData, WgPipelineBlendType blendType);
void dispatchWorkgroups(WGPUComputePassEncoder computePassEncoder); void dispatchWorkgroups(WGPUComputePassEncoder computePassEncoder);
WGPUComputePassEncoder beginComputePass(WGPUCommandEncoder commandEncoder); WGPUComputePassEncoder beginComputePass(WGPUCommandEncoder commandEncoder);
void endRenderPass(WGPUComputePassEncoder computePassEncoder); void endComputePass(WGPUComputePassEncoder computePassEncoder);
}; };

View file

@ -133,43 +133,74 @@ RenderData WgRenderer::prepare(Surface* surface, const RenderMesh* mesh, RenderD
return renderDataPicture; return renderDataPicture;
} }
bool WgRenderer::preRender() bool WgRenderer::preRender()
{ {
WGPUCommandEncoderDescriptor commandEncoderDesc{}; WGPUCommandEncoderDescriptor commandEncoderDesc{};
commandEncoderDesc.nextInChain = nullptr; commandEncoderDesc.nextInChain = nullptr;
commandEncoderDesc.label = "The command encoder"; commandEncoderDesc.label = "The command encoder";
mCommandEncoder = wgpuDeviceCreateCommandEncoder(mContext.device, &commandEncoderDesc); mCommandEncoder = wgpuDeviceCreateCommandEncoder(mContext.device, &commandEncoderDesc);
mRenderStorageRoot.clear(mCommandEncoder);
mRenderStorageStack.push(&mRenderStorageRoot); mRenderStorageStack.push(&mRenderStorageRoot);
//mRenderStorageRoot.clear(mCommandEncoder);
mRenderStorageRoot.beginRenderPass(mCommandEncoder, true);
return true; return true;
} }
bool WgRenderer::renderShape(RenderData data) bool WgRenderer::renderShape(RenderData data)
{ {
// render shape to render target // get current render storage
mRenderTarget.renderShape(mCommandEncoder, (WgRenderDataShape *)data); WgPipelineBlendType blendType = WgPipelines::blendMethodToBlendType(mBlendMethod);
// blend shape with current render storage WgRenderStorage* renderStorage = mRenderStorageStack.last();
WgBindGroupBlendMethod* blendMethod = mBlendMethodPool.allocate(mContext, mBlendMethod); assert(renderStorage);
mRenderStorageStack.last()->blend(mCommandEncoder, &mRenderTarget, blendMethod); // use hardware blend
if (WgPipelines::isBlendMethodSupportsHW(mBlendMethod))
renderStorage->renderShape((WgRenderDataShape *)data, blendType);
else { // use custom blend
// terminate current render pass
renderStorage->endRenderPass();
// render image to render target
mRenderTarget.beginRenderPass(mCommandEncoder, true);
mRenderTarget.renderShape((WgRenderDataShape *)data, blendType);
mRenderTarget.endRenderPass();
// blend shape with current render storage
WgBindGroupBlendMethod* blendMethod = mBlendMethodPool.allocate(mContext, mBlendMethod);
renderStorage->blend(mCommandEncoder, &mRenderTarget, blendMethod);
// restore current render pass
renderStorage->beginRenderPass(mCommandEncoder, false);
}
return true; return true;
} }
bool WgRenderer::renderImage(RenderData data) bool WgRenderer::renderImage(RenderData data)
{ {
// render image to render target // get current render storage
mRenderTarget.renderPicture(mCommandEncoder, (WgRenderDataPicture *)data); WgPipelineBlendType blendType = WgPipelines::blendMethodToBlendType(mBlendMethod);
// blend image with current render storage WgRenderStorage* renderStorage = mRenderStorageStack.last();
WgBindGroupBlendMethod* blendMethod = mBlendMethodPool.allocate(mContext, mBlendMethod); assert(renderStorage);
mRenderStorageStack.last()->blend(mCommandEncoder, &mRenderTarget, blendMethod); // use hardware blend
if (WgPipelines::isBlendMethodSupportsHW(mBlendMethod))
renderStorage->renderPicture((WgRenderDataPicture *)data, blendType);
else { // use custom blend
// terminate current render pass
renderStorage->endRenderPass();
// render image to render target
mRenderTarget.beginRenderPass(mCommandEncoder, true);
mRenderTarget.renderPicture((WgRenderDataPicture *)data, blendType);
mRenderTarget.endRenderPass();
// blend shape with current render storage
WgBindGroupBlendMethod* blendMethod = mBlendMethodPool.allocate(mContext, mBlendMethod);
renderStorage->blend(mCommandEncoder, &mRenderTarget, blendMethod);
// restore current render pass
renderStorage->beginRenderPass(mCommandEncoder, false);
}
return true; return true;
} }
bool WgRenderer::postRender() bool WgRenderer::postRender()
{ {
mRenderStorageRoot.endRenderPass();
mRenderStorageStack.pop(); mRenderStorageStack.pop();
mContext.executeCommandEncoder(mCommandEncoder); mContext.executeCommandEncoder(mCommandEncoder);
wgpuCommandEncoderRelease(mCommandEncoder); wgpuCommandEncoderRelease(mCommandEncoder);
@ -233,7 +264,7 @@ bool WgRenderer::sync()
mRenderStorageScreen.antialias(commandEncoder, &mRenderStorageRoot); mRenderStorageScreen.antialias(commandEncoder, &mRenderStorageRoot);
WGPUImageCopyTexture source{}; WGPUImageCopyTexture source{};
source.texture = mRenderStorageScreen.texStorage; source.texture = mRenderStorageScreen.texColor;
WGPUImageCopyTexture dest{}; WGPUImageCopyTexture dest{};
dest.texture = backBuffer.texture; dest.texture = backBuffer.texture;
WGPUExtent3D copySize{}; WGPUExtent3D copySize{};
@ -313,15 +344,17 @@ Compositor* WgRenderer::target(TVG_UNUSED const RenderRegion& region, TVG_UNUSED
bool WgRenderer::beginComposite(TVG_UNUSED Compositor* cmp, TVG_UNUSED CompositeMethod method, TVG_UNUSED uint8_t opacity) bool WgRenderer::beginComposite(TVG_UNUSED Compositor* cmp, TVG_UNUSED CompositeMethod method, TVG_UNUSED uint8_t opacity)
{ {
// save current composition settings // save current composition settings
cmp->method = method; cmp->method = method;
cmp->opacity = opacity; cmp->opacity = opacity;
// end current render pass
mRenderStorageStack.last()->endRenderPass();
// allocate new render storage and push it to top of render tree // allocate new render storage and push it to top of render tree
WgRenderStorage* renderStorage = mRenderStoragePool.allocate(mContext, mTargetSurface.w * WG_SSAA_SAMPLES, mTargetSurface.h * WG_SSAA_SAMPLES); WgRenderStorage* renderStorage = mRenderStoragePool.allocate(mContext, mTargetSurface.w * WG_SSAA_SAMPLES, mTargetSurface.h * WG_SSAA_SAMPLES);
renderStorage->clear(mCommandEncoder);
mRenderStorageStack.push(renderStorage); mRenderStorageStack.push(renderStorage);
// begin last render pass
mRenderStorageStack.last()->beginRenderPass(mCommandEncoder, true);
return true; return true;
} }
@ -329,6 +362,8 @@ bool WgRenderer::beginComposite(TVG_UNUSED Compositor* cmp, TVG_UNUSED Composite
bool WgRenderer::endComposite(TVG_UNUSED Compositor* cmp) bool WgRenderer::endComposite(TVG_UNUSED Compositor* cmp)
{ {
if (cmp->method == CompositeMethod::None) { if (cmp->method == CompositeMethod::None) {
// end current render pass
mRenderStorageStack.last()->endRenderPass();
// get two last render targets // get two last render targets
WgRenderStorage* renderStorageSrc = mRenderStorageStack.last(); WgRenderStorage* renderStorageSrc = mRenderStorageStack.last();
mRenderStorageStack.pop(); mRenderStorageStack.pop();
@ -339,7 +374,11 @@ bool WgRenderer::endComposite(TVG_UNUSED Compositor* cmp)
// back render targets to the pool // back render targets to the pool
mRenderStoragePool.free(mContext, renderStorageSrc); mRenderStoragePool.free(mContext, renderStorageSrc);
// begin last render pass
mRenderStorageStack.last()->beginRenderPass(mCommandEncoder, false);
} else { } else {
// end current render pass
mRenderStorageStack.last()->endRenderPass();
// get two last render targets // get two last render targets
WgRenderStorage* renderStorageSrc = mRenderStorageStack.last(); WgRenderStorage* renderStorageSrc = mRenderStorageStack.last();
mRenderStorageStack.pop(); mRenderStorageStack.pop();
@ -358,6 +397,8 @@ bool WgRenderer::endComposite(TVG_UNUSED Compositor* cmp)
// back render targets to the pool // back render targets to the pool
mRenderStoragePool.free(mContext, renderStorageSrc); mRenderStoragePool.free(mContext, renderStorageSrc);
mRenderStoragePool.free(mContext, renderStorageMsk); mRenderStoragePool.free(mContext, renderStorageMsk);
// begin last render pass
mRenderStorageStack.last()->beginRenderPass(mCommandEncoder, false);
} }
// delete current compositor // delete current compositor

View file

@ -62,7 +62,7 @@ public:
private: private:
// render handles // render handles
WGPUCommandEncoder mCommandEncoder{}; WGPUCommandEncoder mCommandEncoder{};
WgRenderTarget mRenderTarget; WgRenderStorage mRenderTarget;
WgRenderStorage mRenderStorageRoot; WgRenderStorage mRenderStorageRoot;
WgRenderStorage mRenderStorageScreen; WgRenderStorage mRenderStorageScreen;
WgRenderStoragePool mRenderStoragePool; WgRenderStoragePool mRenderStoragePool;
@ -76,7 +76,6 @@ private:
// native window handles // native window handles
WGPUSurface mSurface{}; WGPUSurface mSurface{};
private:
WgContext mContext; WgContext mContext;
WgPipelines mPipelines; WgPipelines mPipelines;
Surface mTargetSurface; Surface mTargetSurface;