mirror of
https://github.com/thorvg/thorvg.git
synced 2025-06-08 05:33:36 +00:00
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:
parent
622b25a3b4
commit
b0280150db
8 changed files with 302 additions and 230 deletions
|
@ -494,7 +494,7 @@ void WgPipeline::destroyShaderModule(WGPUShaderModule& shaderModule)
|
|||
// render pipeline
|
||||
//*****************************************************************************
|
||||
|
||||
void WgRenderPipeline::allocate(WGPUDevice device,
|
||||
void WgRenderPipeline::allocate(WGPUDevice device, WgPipelineBlendType blendType,
|
||||
WGPUVertexBufferLayout vertexBufferLayouts[], uint32_t attribsCount,
|
||||
WGPUBindGroupLayout bindGroupLayouts[], uint32_t bindGroupsCount,
|
||||
WGPUCompareFunction stencilCompareFunction, WGPUStencilOperation stencilOperation,
|
||||
|
@ -506,7 +506,7 @@ void WgRenderPipeline::allocate(WGPUDevice device,
|
|||
mPipelineLayout = createPipelineLayout(device, bindGroupLayouts, bindGroupsCount);
|
||||
assert(mPipelineLayout);
|
||||
|
||||
mRenderPipeline = createRenderPipeline(device,
|
||||
mRenderPipeline = createRenderPipeline(device, blendType,
|
||||
vertexBufferLayouts, attribsCount,
|
||||
stencilCompareFunction, stencilOperation,
|
||||
mPipelineLayout, mShaderModule, pipelineLabel);
|
||||
|
@ -527,14 +527,42 @@ void WgRenderPipeline::set(WGPURenderPassEncoder renderPassEncoder)
|
|||
};
|
||||
|
||||
|
||||
WGPUBlendState WgRenderPipeline::makeBlendState()
|
||||
WGPUBlendState WgRenderPipeline::makeBlendState(WgPipelineBlendType blendType)
|
||||
{
|
||||
WGPUBlendState blendState{};
|
||||
blendState.color.operation = WGPUBlendOperation_Add;
|
||||
blendState.color.srcFactor = WGPUBlendFactor_One;
|
||||
blendState.color.dstFactor = WGPUBlendFactor_Zero;
|
||||
// src
|
||||
if (blendType == WgPipelineBlendType::Src) {
|
||||
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.srcFactor = WGPUBlendFactor_One;
|
||||
blendState.alpha.srcFactor = WGPUBlendFactor_SrcAlpha;
|
||||
blendState.alpha.dstFactor = WGPUBlendFactor_Zero;
|
||||
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,
|
||||
WGPUCompareFunction stencilCompareFunction, WGPUStencilOperation stencilOperation,
|
||||
WGPUPipelineLayout pipelineLayout, WGPUShaderModule shaderModule,
|
||||
const char* pipelineName)
|
||||
{
|
||||
WGPUBlendState blendState = makeBlendState();
|
||||
WGPUBlendState blendState = makeBlendState(blendType);
|
||||
WGPUColorTargetState colorTargetStates[] = {
|
||||
makeColorTargetState(&blendState)
|
||||
};
|
||||
|
|
|
@ -28,6 +28,15 @@
|
|||
#include "tvgCommon.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 WgContext {
|
||||
|
@ -107,7 +116,7 @@ struct WgRenderPipeline: public WgPipeline
|
|||
{
|
||||
protected:
|
||||
WGPURenderPipeline mRenderPipeline{};
|
||||
void allocate(WGPUDevice device,
|
||||
void allocate(WGPUDevice device, WgPipelineBlendType blendType,
|
||||
WGPUVertexBufferLayout vertexBufferLayouts[], uint32_t attribsCount,
|
||||
WGPUBindGroupLayout bindGroupLayouts[], uint32_t bindGroupsCount,
|
||||
WGPUCompareFunction stencilCompareFunction, WGPUStencilOperation stencilOperation,
|
||||
|
@ -116,7 +125,7 @@ public:
|
|||
void release() override;
|
||||
void set(WGPURenderPassEncoder renderPassEncoder);
|
||||
|
||||
static WGPUBlendState makeBlendState();
|
||||
static WGPUBlendState makeBlendState(WgPipelineBlendType blendType);
|
||||
static WGPUColorTargetState makeColorTargetState(const WGPUBlendState* blendState);
|
||||
static WGPUVertexBufferLayout makeVertexBufferLayout(const WGPUVertexAttribute* vertexAttributes, uint32_t count, uint64_t stride);
|
||||
static WGPUVertexState makeVertexState(WGPUShaderModule shaderModule, const WGPUVertexBufferLayout* buffers, uint32_t count);
|
||||
|
@ -125,7 +134,7 @@ public:
|
|||
static WGPUMultisampleState makeMultisampleState();
|
||||
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,
|
||||
WGPUCompareFunction stencilCompareFunction, WGPUStencilOperation stencilOperation,
|
||||
WGPUPipelineLayout pipelineLayout, WGPUShaderModule shaderModule,
|
||||
|
|
|
@ -53,7 +53,7 @@ void WgPipelineFillShape::initialize(WGPUDevice device)
|
|||
auto pipelineLabel = "The render pipeline fill shape";
|
||||
|
||||
// allocate all pipeline handles
|
||||
allocate(device,
|
||||
allocate(device, WgPipelineBlendType::Src,
|
||||
vertexBufferLayouts, ARRAY_ELEMENTS_COUNT(vertexBufferLayouts),
|
||||
bindGroupLayouts, ARRAY_ELEMENTS_COUNT(bindGroupLayouts),
|
||||
stencilFuncion, stencilOperation,
|
||||
|
@ -85,7 +85,7 @@ void WgPipelineFillStroke::initialize(WGPUDevice device)
|
|||
auto pipelineLabel = "The render pipeline fill stroke";
|
||||
|
||||
// allocate all pipeline handles
|
||||
allocate(device,
|
||||
allocate(device, WgPipelineBlendType::Src,
|
||||
vertexBufferLayouts, ARRAY_ELEMENTS_COUNT(vertexBufferLayouts),
|
||||
bindGroupLayouts, ARRAY_ELEMENTS_COUNT(bindGroupLayouts),
|
||||
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
|
||||
WGPUVertexAttribute vertexAttributesPos = { WGPUVertexFormat_Float32x2, sizeof(float) * 0, 0 };
|
||||
|
@ -118,7 +118,7 @@ void WgPipelineSolid::initialize(WGPUDevice device)
|
|||
auto pipelineLabel = "The render pipeline solid color";
|
||||
|
||||
// allocate all pipeline handles
|
||||
allocate(device,
|
||||
allocate(device, blendType,
|
||||
vertexBufferLayouts, ARRAY_ELEMENTS_COUNT(vertexBufferLayouts),
|
||||
bindGroupLayouts, ARRAY_ELEMENTS_COUNT(bindGroupLayouts),
|
||||
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
|
||||
WGPUVertexAttribute vertexAttributesPos = { WGPUVertexFormat_Float32x2, sizeof(float) * 0, 0 };
|
||||
|
@ -151,7 +151,7 @@ void WgPipelineLinear::initialize(WGPUDevice device)
|
|||
auto pipelineLabel = "The render pipeline linear gradient";
|
||||
|
||||
// allocate all pipeline handles
|
||||
allocate(device,
|
||||
allocate(device, blendType,
|
||||
vertexBufferLayouts, ARRAY_ELEMENTS_COUNT(vertexBufferLayouts),
|
||||
bindGroupLayouts, ARRAY_ELEMENTS_COUNT(bindGroupLayouts),
|
||||
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
|
||||
WGPUVertexAttribute vertexAttributesPos = { WGPUVertexFormat_Float32x2, sizeof(float) * 0, 0 };
|
||||
|
@ -184,7 +184,7 @@ void WgPipelineRadial::initialize(WGPUDevice device)
|
|||
auto pipelineLabel = "The render pipeline radial gradient";
|
||||
|
||||
// allocate all pipeline handles
|
||||
allocate(device,
|
||||
allocate(device, blendType,
|
||||
vertexBufferLayouts, ARRAY_ELEMENTS_COUNT(vertexBufferLayouts),
|
||||
bindGroupLayouts, ARRAY_ELEMENTS_COUNT(bindGroupLayouts),
|
||||
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
|
||||
WGPUVertexAttribute vertexAttributesPos = { WGPUVertexFormat_Float32x2, sizeof(float) * 0, 0 };
|
||||
|
@ -219,7 +219,7 @@ void WgPipelineImage::initialize(WGPUDevice device)
|
|||
auto pipelineLabel = "The render pipeline image";
|
||||
|
||||
// allocate all pipeline handles
|
||||
allocate(device,
|
||||
allocate(device, blendType,
|
||||
vertexBufferLayouts, ARRAY_ELEMENTS_COUNT(vertexBufferLayouts),
|
||||
bindGroupLayouts, ARRAY_ELEMENTS_COUNT(bindGroupLayouts),
|
||||
stencilFuncion, stencilOperation,
|
||||
|
@ -320,10 +320,12 @@ void WgPipelines::initialize(WgContext& context)
|
|||
// fill pipelines
|
||||
fillShape.initialize(context.device);
|
||||
fillStroke.initialize(context.device);
|
||||
solid.initialize(context.device);
|
||||
linear.initialize(context.device);
|
||||
radial.initialize(context.device);
|
||||
image.initialize(context.device);
|
||||
for (uint8_t type = (uint8_t)WgPipelineBlendType::Src; type <= (uint8_t)WgPipelineBlendType::Max; type++) {
|
||||
solid[type].initialize(context.device, (WgPipelineBlendType)type);
|
||||
linear[type].initialize(context.device, (WgPipelineBlendType)type);
|
||||
radial[type].initialize(context.device, (WgPipelineBlendType)type);
|
||||
image[type].initialize(context.device, (WgPipelineBlendType)type);
|
||||
}
|
||||
// compute pipelines
|
||||
computeClear.initialize(context.device);
|
||||
computeBlend.initialize(context.device);
|
||||
|
@ -352,10 +354,41 @@ void WgPipelines::release()
|
|||
computeBlend.release();
|
||||
computeClear.release();
|
||||
// fill pipelines
|
||||
image.release();
|
||||
radial.release();
|
||||
linear.release();
|
||||
solid.release();
|
||||
for (uint8_t type = (uint8_t)WgPipelineBlendType::Src; type <= (uint8_t)WgPipelineBlendType::Max; type++) {
|
||||
image[type].release();
|
||||
radial[type].release();
|
||||
linear[type].release();
|
||||
solid[type].release();
|
||||
}
|
||||
fillStroke.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;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -53,7 +53,8 @@ struct WgPipelineFillStroke: 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)
|
||||
{
|
||||
set(encoder);
|
||||
|
@ -65,7 +66,8 @@ struct WgPipelineSolid: 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)
|
||||
{
|
||||
set(encoder);
|
||||
|
@ -77,7 +79,8 @@ struct WgPipelineLinear: 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)
|
||||
{
|
||||
set(encoder);
|
||||
|
@ -89,7 +92,8 @@ struct WgPipelineRadial: 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)
|
||||
{
|
||||
set(encoder);
|
||||
|
@ -161,10 +165,11 @@ struct WgPipelines
|
|||
// render pipelines
|
||||
WgPipelineFillShape fillShape;
|
||||
WgPipelineFillStroke fillStroke;
|
||||
WgPipelineSolid solid;
|
||||
WgPipelineLinear linear;
|
||||
WgPipelineRadial radial;
|
||||
WgPipelineImage image;
|
||||
// fill pipelines
|
||||
WgPipelineSolid solid[6];
|
||||
WgPipelineLinear linear[6];
|
||||
WgPipelineRadial radial[6];
|
||||
WgPipelineImage image[6];
|
||||
// compute pipelines
|
||||
WgPipelineClear computeClear;
|
||||
WgPipelineBlend computeBlend;
|
||||
|
@ -173,6 +178,9 @@ struct WgPipelines
|
|||
|
||||
void initialize(WgContext& context);
|
||||
void release();
|
||||
|
||||
static bool isBlendMethodSupportsHW(BlendMethod blendMethod);
|
||||
static WgPipelineBlendType blendMethodToBlendType(BlendMethod blendMethod);
|
||||
};
|
||||
|
||||
#endif // _TVG_WG_PIPELINES_H_
|
||||
|
|
|
@ -23,21 +23,30 @@
|
|||
#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);
|
||||
// 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
|
||||
texColor = context.createTexture2d(
|
||||
WGPUTextureUsage_RenderAttachment | WGPUTextureUsage_StorageBinding,
|
||||
WGPUTextureFormat_RGBA8Unorm,
|
||||
w * samples, h * samples, "The target texture color");
|
||||
WGPUTextureUsage_CopySrc |
|
||||
WGPUTextureUsage_CopyDst |
|
||||
WGPUTextureUsage_TextureBinding |
|
||||
WGPUTextureUsage_StorageBinding |
|
||||
WGPUTextureUsage_RenderAttachment,
|
||||
WGPUTextureFormat_RGBA8Unorm,
|
||||
width, height, "The target texture color");
|
||||
texStencil = context.createTexture2d(
|
||||
WGPUTextureUsage_RenderAttachment,
|
||||
WGPUTextureFormat_Stencil8,
|
||||
w * samples, h * samples, "The target texture stencil");
|
||||
WGPUTextureFormat_Stencil8,
|
||||
width, height, "The target texture stencil");
|
||||
assert(texColor);
|
||||
assert(texStencil);
|
||||
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);
|
||||
mBindGroupCanvas.initialize(context.device, context.queue, viewMat);
|
||||
mPipelines = context.pipelines;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void WgRenderTarget::release(WgContext& context)
|
||||
void WgRenderStorage::release(WgContext& context)
|
||||
{
|
||||
mRenderPassEncoder = nullptr;
|
||||
mBindGroupCanvas.release();
|
||||
bindGroupTexStorage.release();
|
||||
context.releaseTextureView(texViewStencil);
|
||||
context.releaseTextureView(texViewColor);
|
||||
context.releaseTexture(texStencil);
|
||||
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(commandEncoder);
|
||||
WGPURenderPassEncoder renderPassEncoder = beginRenderPass(commandEncoder);
|
||||
assert(mRenderPassEncoder);
|
||||
if (renderData->strokeFirst)
|
||||
drawStroke(renderPassEncoder, renderData);
|
||||
drawShape(renderPassEncoder, renderData);
|
||||
drawStroke(renderData, blendType);
|
||||
drawShape(renderData, blendType);
|
||||
if (!renderData->strokeFirst)
|
||||
drawStroke(renderPassEncoder, renderData);
|
||||
endRenderPass(renderPassEncoder);
|
||||
drawStroke(renderData, blendType);
|
||||
}
|
||||
|
||||
|
||||
void WgRenderTarget::renderPicture(WGPUCommandEncoder commandEncoder, WgRenderDataPicture* renderData)
|
||||
void WgRenderStorage::renderPicture(WgRenderDataPicture* renderData, WgPipelineBlendType blendType)
|
||||
{
|
||||
assert(renderData);
|
||||
assert(commandEncoder);
|
||||
WGPURenderPassEncoder renderPassEncoder = beginRenderPass(commandEncoder);
|
||||
wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0);
|
||||
mPipelines->image.use(renderPassEncoder, mBindGroupCanvas, renderData->bindGroupPaint, renderData->bindGroupPicture);
|
||||
renderData->meshData.drawImage(renderPassEncoder);
|
||||
endRenderPass(renderPassEncoder);
|
||||
assert(mRenderPassEncoder);
|
||||
uint8_t blend = (uint8_t)blendType;
|
||||
wgpuRenderPassEncoderSetStencilReference(mRenderPassEncoder, 0);
|
||||
mPipelines->image[blend].use(mRenderPassEncoder, mBindGroupCanvas, renderData->bindGroupPaint, renderData->bindGroupPicture);
|
||||
renderData->meshData.drawImage(mRenderPassEncoder);
|
||||
}
|
||||
|
||||
|
||||
void WgRenderTarget::drawShape(WGPURenderPassEncoder renderPassEncoder, WgRenderDataShape* renderData)
|
||||
void WgRenderStorage::drawShape(WgRenderDataShape* renderData, WgPipelineBlendType blendType)
|
||||
{
|
||||
assert(renderData);
|
||||
assert(renderPassEncoder);
|
||||
assert(mRenderPassEncoder);
|
||||
// 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++) {
|
||||
// draw to stencil (first pass)
|
||||
mPipelines->fillShape.use(renderPassEncoder, mBindGroupCanvas, renderData->bindGroupPaint);
|
||||
renderData->meshGroupShapes.meshes[i]->draw(renderPassEncoder);
|
||||
mPipelines->fillShape.use(mRenderPassEncoder, mBindGroupCanvas, renderData->bindGroupPaint);
|
||||
renderData->meshGroupShapes.meshes[i]->draw(mRenderPassEncoder);
|
||||
// fill shape (second pass)
|
||||
WgRenderSettings& settings = renderData->renderSettingsShape;
|
||||
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)
|
||||
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)
|
||||
mPipelines->radial.use(renderPassEncoder, mBindGroupCanvas, renderData->bindGroupPaint, settings.bindGroupRadial);
|
||||
renderData->meshBBoxShapes.draw(renderPassEncoder);
|
||||
mPipelines->radial[blend].use(mRenderPassEncoder, mBindGroupCanvas, renderData->bindGroupPaint, settings.bindGroupRadial);
|
||||
renderData->meshBBoxShapes.draw(mRenderPassEncoder);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void WgRenderTarget::drawStroke(WGPURenderPassEncoder renderPassEncoder, WgRenderDataShape* renderData)
|
||||
void WgRenderStorage::drawStroke(WgRenderDataShape* renderData, WgPipelineBlendType blendType)
|
||||
{
|
||||
assert(renderData);
|
||||
assert(renderPassEncoder);
|
||||
assert(mRenderPassEncoder);
|
||||
// draw stroke geometry
|
||||
uint8_t blend = (uint8_t)blendType;
|
||||
if (renderData->meshGroupStrokes.meshes.count > 0) {
|
||||
// draw strokes to stencil (first pass)
|
||||
wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 255);
|
||||
wgpuRenderPassEncoderSetStencilReference(mRenderPassEncoder, 255);
|
||||
for (uint32_t i = 0; i < renderData->meshGroupStrokes.meshes.count; i++) {
|
||||
mPipelines->fillStroke.use(renderPassEncoder, mBindGroupCanvas, renderData->bindGroupPaint);
|
||||
renderData->meshGroupStrokes.meshes[i]->draw(renderPassEncoder);
|
||||
mPipelines->fillStroke.use(mRenderPassEncoder, mBindGroupCanvas, renderData->bindGroupPaint);
|
||||
renderData->meshGroupStrokes.meshes[i]->draw(mRenderPassEncoder);
|
||||
}
|
||||
// fill shape (second pass)
|
||||
wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0);
|
||||
wgpuRenderPassEncoderSetStencilReference(mRenderPassEncoder, 0);
|
||||
WgRenderSettings& settings = renderData->renderSettingsStroke;
|
||||
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)
|
||||
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)
|
||||
mPipelines->radial.use(renderPassEncoder, mBindGroupCanvas, renderData->bindGroupPaint, settings.bindGroupRadial);
|
||||
renderData->meshBBoxStrokes.draw(renderPassEncoder);
|
||||
mPipelines->radial[blend].use(mRenderPassEncoder, mBindGroupCanvas, renderData->bindGroupPaint, settings.bindGroupRadial);
|
||||
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);
|
||||
// render pass depth stencil attachment
|
||||
|
@ -157,7 +220,7 @@ WGPURenderPassEncoder WgRenderTarget::beginRenderPass(WGPUCommandEncoder command
|
|||
WGPURenderPassColorAttachment colorAttachment{};
|
||||
colorAttachment.view = texViewColor;
|
||||
colorAttachment.resolveTarget = nullptr;
|
||||
colorAttachment.loadOp = WGPULoadOp_Clear;
|
||||
colorAttachment.loadOp = clear ? WGPULoadOp_Clear : WGPULoadOp_Load;
|
||||
colorAttachment.clearValue = { 0, 0, 0, 0 };
|
||||
colorAttachment.storeOp = WGPUStoreOp_Store;
|
||||
// render pass descriptor
|
||||
|
@ -171,111 +234,16 @@ WGPURenderPassEncoder WgRenderTarget::beginRenderPass(WGPUCommandEncoder command
|
|||
renderPassDesc.occlusionQuerySet = nullptr;
|
||||
renderPassDesc.timestampWrites = nullptr;
|
||||
// begin render pass
|
||||
return wgpuCommandEncoderBeginRenderPass(commandEncoder, &renderPassDesc);
|
||||
mRenderPassEncoder = wgpuCommandEncoderBeginRenderPass(commandEncoder, &renderPassDesc);
|
||||
}
|
||||
|
||||
|
||||
void WgRenderTarget::endRenderPass(WGPURenderPassEncoder renderPassEncoder)
|
||||
void WgRenderStorage::endRenderPass()
|
||||
{
|
||||
assert(renderPassEncoder);
|
||||
wgpuRenderPassEncoderEnd(renderPassEncoder);
|
||||
wgpuRenderPassEncoderRelease(renderPassEncoder);
|
||||
}
|
||||
|
||||
//*****************************************************************************
|
||||
// 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);
|
||||
assert(mRenderPassEncoder);
|
||||
wgpuRenderPassEncoderEnd(mRenderPassEncoder);
|
||||
wgpuRenderPassEncoderRelease(mRenderPassEncoder);
|
||||
mRenderPassEncoder = nullptr;
|
||||
}
|
||||
|
||||
|
||||
|
@ -290,7 +258,7 @@ WGPUComputePassEncoder WgRenderStorage::beginComputePass(WGPUCommandEncoder comm
|
|||
};
|
||||
|
||||
|
||||
void WgRenderStorage::endRenderPass(WGPUComputePassEncoder computePassEncoder)
|
||||
void WgRenderStorage::endComputePass(WGPUComputePassEncoder computePassEncoder)
|
||||
{
|
||||
assert(computePassEncoder);
|
||||
wgpuComputePassEncoderEnd(computePassEncoder);
|
||||
|
|
|
@ -25,10 +25,11 @@
|
|||
|
||||
#include "tvgWgRenderData.h"
|
||||
|
||||
class WgRenderTarget {
|
||||
class WgRenderStorage {
|
||||
private:
|
||||
// canvas info
|
||||
// texture buffers
|
||||
WgBindGroupCanvas mBindGroupCanvas;
|
||||
WGPURenderPassEncoder mRenderPassEncoder{};
|
||||
WgPipelines* mPipelines{}; // external handle
|
||||
public:
|
||||
WGPUTexture texColor{};
|
||||
|
@ -36,29 +37,6 @@ public:
|
|||
WGPUTextureView texViewColor{};
|
||||
WGPUTextureView texViewStencil{};
|
||||
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 height{};
|
||||
uint32_t workgroupsCountX{};
|
||||
|
@ -67,16 +45,24 @@ public:
|
|||
void initialize(WgContext& context, uint32_t w, uint32_t h, uint32_t samples = 1);
|
||||
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 blend(WGPUCommandEncoder commandEncoder, WgRenderTarget* targetSrc, WgBindGroupBlendMethod* blendMethod);
|
||||
void blend(WGPUCommandEncoder commandEncoder, WgRenderStorage* targetSrc, WgBindGroupBlendMethod* blendMethod);
|
||||
void compose(WGPUCommandEncoder commandEncoder, WgRenderStorage* targetMsk, WgBindGroupCompositeMethod* composeMethod, WgBindGroupOpacity* opacity);
|
||||
void antialias(WGPUCommandEncoder commandEncoder, WgRenderStorage* targetSrc);
|
||||
private:
|
||||
void drawShape(WgRenderDataShape* renderData, WgPipelineBlendType blendType);
|
||||
void drawStroke(WgRenderDataShape* renderData, WgPipelineBlendType blendType);
|
||||
|
||||
void dispatchWorkgroups(WGPUComputePassEncoder computePassEncoder);
|
||||
|
||||
WGPUComputePassEncoder beginComputePass(WGPUCommandEncoder commandEncoder);
|
||||
void endRenderPass(WGPUComputePassEncoder computePassEncoder);
|
||||
void endComputePass(WGPUComputePassEncoder computePassEncoder);
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -133,43 +133,74 @@ RenderData WgRenderer::prepare(Surface* surface, const RenderMesh* mesh, RenderD
|
|||
return renderDataPicture;
|
||||
}
|
||||
|
||||
|
||||
bool WgRenderer::preRender()
|
||||
{
|
||||
WGPUCommandEncoderDescriptor commandEncoderDesc{};
|
||||
commandEncoderDesc.nextInChain = nullptr;
|
||||
commandEncoderDesc.label = "The command encoder";
|
||||
mCommandEncoder = wgpuDeviceCreateCommandEncoder(mContext.device, &commandEncoderDesc);
|
||||
mRenderStorageRoot.clear(mCommandEncoder);
|
||||
mRenderStorageStack.push(&mRenderStorageRoot);
|
||||
//mRenderStorageRoot.clear(mCommandEncoder);
|
||||
mRenderStorageRoot.beginRenderPass(mCommandEncoder, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool WgRenderer::renderShape(RenderData data)
|
||||
{
|
||||
// render shape to render target
|
||||
mRenderTarget.renderShape(mCommandEncoder, (WgRenderDataShape *)data);
|
||||
// blend shape with current render storage
|
||||
WgBindGroupBlendMethod* blendMethod = mBlendMethodPool.allocate(mContext, mBlendMethod);
|
||||
mRenderStorageStack.last()->blend(mCommandEncoder, &mRenderTarget, blendMethod);
|
||||
// get current render storage
|
||||
WgPipelineBlendType blendType = WgPipelines::blendMethodToBlendType(mBlendMethod);
|
||||
WgRenderStorage* renderStorage = mRenderStorageStack.last();
|
||||
assert(renderStorage);
|
||||
// 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;
|
||||
}
|
||||
|
||||
|
||||
bool WgRenderer::renderImage(RenderData data)
|
||||
{
|
||||
// render image to render target
|
||||
mRenderTarget.renderPicture(mCommandEncoder, (WgRenderDataPicture *)data);
|
||||
// blend image with current render storage
|
||||
WgBindGroupBlendMethod* blendMethod = mBlendMethodPool.allocate(mContext, mBlendMethod);
|
||||
mRenderStorageStack.last()->blend(mCommandEncoder, &mRenderTarget, blendMethod);
|
||||
// get current render storage
|
||||
WgPipelineBlendType blendType = WgPipelines::blendMethodToBlendType(mBlendMethod);
|
||||
WgRenderStorage* renderStorage = mRenderStorageStack.last();
|
||||
assert(renderStorage);
|
||||
// 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;
|
||||
}
|
||||
|
||||
|
||||
bool WgRenderer::postRender()
|
||||
{
|
||||
mRenderStorageRoot.endRenderPass();
|
||||
mRenderStorageStack.pop();
|
||||
mContext.executeCommandEncoder(mCommandEncoder);
|
||||
wgpuCommandEncoderRelease(mCommandEncoder);
|
||||
|
@ -233,7 +264,7 @@ bool WgRenderer::sync()
|
|||
mRenderStorageScreen.antialias(commandEncoder, &mRenderStorageRoot);
|
||||
|
||||
WGPUImageCopyTexture source{};
|
||||
source.texture = mRenderStorageScreen.texStorage;
|
||||
source.texture = mRenderStorageScreen.texColor;
|
||||
WGPUImageCopyTexture dest{};
|
||||
dest.texture = backBuffer.texture;
|
||||
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)
|
||||
{
|
||||
// save current composition settings
|
||||
// save current composition settings
|
||||
cmp->method = method;
|
||||
cmp->opacity = opacity;
|
||||
|
||||
// end current render pass
|
||||
mRenderStorageStack.last()->endRenderPass();
|
||||
// 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);
|
||||
renderStorage->clear(mCommandEncoder);
|
||||
mRenderStorageStack.push(renderStorage);
|
||||
|
||||
// begin last render pass
|
||||
mRenderStorageStack.last()->beginRenderPass(mCommandEncoder, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -329,6 +362,8 @@ bool WgRenderer::beginComposite(TVG_UNUSED Compositor* cmp, TVG_UNUSED Composite
|
|||
bool WgRenderer::endComposite(TVG_UNUSED Compositor* cmp)
|
||||
{
|
||||
if (cmp->method == CompositeMethod::None) {
|
||||
// end current render pass
|
||||
mRenderStorageStack.last()->endRenderPass();
|
||||
// get two last render targets
|
||||
WgRenderStorage* renderStorageSrc = mRenderStorageStack.last();
|
||||
mRenderStorageStack.pop();
|
||||
|
@ -339,7 +374,11 @@ bool WgRenderer::endComposite(TVG_UNUSED Compositor* cmp)
|
|||
|
||||
// back render targets to the pool
|
||||
mRenderStoragePool.free(mContext, renderStorageSrc);
|
||||
// begin last render pass
|
||||
mRenderStorageStack.last()->beginRenderPass(mCommandEncoder, false);
|
||||
} else {
|
||||
// end current render pass
|
||||
mRenderStorageStack.last()->endRenderPass();
|
||||
// get two last render targets
|
||||
WgRenderStorage* renderStorageSrc = mRenderStorageStack.last();
|
||||
mRenderStorageStack.pop();
|
||||
|
@ -358,6 +397,8 @@ bool WgRenderer::endComposite(TVG_UNUSED Compositor* cmp)
|
|||
// back render targets to the pool
|
||||
mRenderStoragePool.free(mContext, renderStorageSrc);
|
||||
mRenderStoragePool.free(mContext, renderStorageMsk);
|
||||
// begin last render pass
|
||||
mRenderStorageStack.last()->beginRenderPass(mCommandEncoder, false);
|
||||
}
|
||||
|
||||
// delete current compositor
|
||||
|
|
|
@ -62,7 +62,7 @@ public:
|
|||
private:
|
||||
// render handles
|
||||
WGPUCommandEncoder mCommandEncoder{};
|
||||
WgRenderTarget mRenderTarget;
|
||||
WgRenderStorage mRenderTarget;
|
||||
WgRenderStorage mRenderStorageRoot;
|
||||
WgRenderStorage mRenderStorageScreen;
|
||||
WgRenderStoragePool mRenderStoragePool;
|
||||
|
@ -76,7 +76,6 @@ private:
|
|||
|
||||
// native window handles
|
||||
WGPUSurface mSurface{};
|
||||
private:
|
||||
WgContext mContext;
|
||||
WgPipelines mPipelines;
|
||||
Surface mTargetSurface;
|
||||
|
|
Loading…
Add table
Reference in a new issue