wg_engine: geometry stage buffers implementation
Some checks are pending
Android / build_x86_64 (push) Waiting to run
Android / build_aarch64 (push) Waiting to run
iOS / build_x86_64 (push) Waiting to run
iOS / build_arm64 (push) Waiting to run
macOS / build (push) Waiting to run
macOS / compact_test (push) Waiting to run
macOS / unit_test (push) Waiting to run
Ubuntu / build (push) Waiting to run
Ubuntu / compact_test (push) Waiting to run
Ubuntu / unit_test (push) Waiting to run
Windows / build (push) Waiting to run
Windows / compact_test (push) Waiting to run
Windows / unit_test (push) Waiting to run

Implemented task-based rendering and geometry stage buffers:
1. Get information about current frame objects
2. Accumulate geometry data into a stage buffer during frame rendering
3. Flush it to the GPU in single call
4. Run rendering process in post render stage

https://github.com/thorvg/thorvg/issues/3489
https://github.com/thorvg/thorvg/issues/3455
This commit is contained in:
Sergii Liebodkin 2025-05-28 10:53:17 +03:00 committed by Hermet Park
parent 1f53f2d72f
commit 24509b0e41
13 changed files with 709 additions and 314 deletions

View file

@ -7,6 +7,7 @@ source_file = [
'tvgWgRenderData.h', 'tvgWgRenderData.h',
'tvgWgRenderer.h', 'tvgWgRenderer.h',
'tvgWgRenderTarget.h', 'tvgWgRenderTarget.h',
'tvgWgRenderTask.h',
'tvgWgShaderSrc.h', 'tvgWgShaderSrc.h',
'tvgWgShaderTypes.h', 'tvgWgShaderTypes.h',
'tvgWgBindGroups.cpp', 'tvgWgBindGroups.cpp',
@ -17,6 +18,7 @@ source_file = [
'tvgWgRenderData.cpp', 'tvgWgRenderData.cpp',
'tvgWgRenderer.cpp', 'tvgWgRenderer.cpp',
'tvgWgRenderTarget.cpp', 'tvgWgRenderTarget.cpp',
'tvgWgRenderTask.cpp',
'tvgWgShaderSrc.cpp', 'tvgWgShaderSrc.cpp',
'tvgWgShaderTypes.cpp' 'tvgWgShaderTypes.cpp'
] ]

View file

@ -269,3 +269,34 @@ void WgContext::releaseQueue(WGPUQueue& queue)
queue = nullptr; queue = nullptr;
} }
} }
WGPUCommandEncoder WgContext::createCommandEncoder()
{
WGPUCommandEncoderDescriptor commandEncoderDesc{};
return wgpuDeviceCreateCommandEncoder(device, &commandEncoderDesc);
}
void WgContext::submitCommandEncoder(WGPUCommandEncoder commandEncoder)
{
const WGPUCommandBufferDescriptor commandBufferDesc{};
WGPUCommandBuffer commandsBuffer = wgpuCommandEncoderFinish(commandEncoder, &commandBufferDesc);
wgpuQueueSubmit(queue, 1, &commandsBuffer);
wgpuCommandBufferRelease(commandsBuffer);
}
void WgContext::releaseCommandEncoder(WGPUCommandEncoder& commandEncoder)
{
if (commandEncoder) {
wgpuCommandEncoderRelease(commandEncoder);
commandEncoder = nullptr;
}
}
bool WgContext::invalid()
{
return !instance || !device;
}

View file

@ -71,10 +71,12 @@ struct WgContext {
// release buffer objects // release buffer objects
void releaseBuffer(WGPUBuffer& buffer); void releaseBuffer(WGPUBuffer& buffer);
bool invalid() // command encoder
{ WGPUCommandEncoder createCommandEncoder();
return !instance || !device; void submitCommandEncoder(WGPUCommandEncoder encoder);
} void releaseCommandEncoder(WGPUCommandEncoder& encoder);
bool invalid();
}; };
#endif // _TVG_WG_COMMON_H_ #endif // _TVG_WG_COMMON_H_

View file

@ -28,6 +28,7 @@ void WgCompositor::initialize(WgContext& context, uint32_t width, uint32_t heigh
{ {
// pipelines (external handle, do not release) // pipelines (external handle, do not release)
pipelines.initialize(context); pipelines.initialize(context);
stageBuffer.initialize(context);
// initialize opacity pool // initialize opacity pool
initPools(context); initPools(context);
// allocate global view matrix handles // allocate global view matrix handles
@ -37,7 +38,7 @@ void WgCompositor::initialize(WgContext& context, uint32_t width, uint32_t heigh
// create render targets handles // create render targets handles
resize(context, width, height); resize(context, width, height);
// composition and blend geometries // composition and blend geometries
meshData.blitBox(context); meshDataBlit.blitBox(context);
} }
@ -54,7 +55,7 @@ void WgCompositor::initPools(WgContext& context)
void WgCompositor::release(WgContext& context) void WgCompositor::release(WgContext& context)
{ {
// composition and blend geometries // composition and blend geometries
meshData.release(context); meshDataBlit.release(context);
// release render targets habdles // release render targets habdles
resize(context, 0, 0); resize(context, 0, 0);
// release opacity pool // release opacity pool
@ -62,6 +63,8 @@ void WgCompositor::release(WgContext& context)
// release global view matrix handles // release global view matrix handles
context.layouts.releaseBindGroup(bindGroupViewMat); context.layouts.releaseBindGroup(bindGroupViewMat);
context.releaseBuffer(bufferViewMat); context.releaseBuffer(bufferViewMat);
// release stage buffer
stageBuffer.release(context);
// release pipelines // release pipelines
pipelines.release(context); pipelines.release(context);
} }
@ -81,9 +84,9 @@ void WgCompositor::resize(WgContext& context, uint32_t width, uint32_t height) {
// release existig handles // release existig handles
if ((this->width != width) || (this->height != height)) { if ((this->width != width) || (this->height != height)) {
context.layouts.releaseBindGroup(bindGroupStorageTemp); context.layouts.releaseBindGroup(bindGroupStorageTemp);
// release intermediate render storages // release intermediate render target
storageTemp1.release(context); targetTemp1.release(context);
storageTemp0.release(context); targetTemp0.release(context);
// release global stencil buffer handles // release global stencil buffer handles
context.releaseTextureView(texViewDepthStencilMS); context.releaseTextureView(texViewDepthStencilMS);
context.releaseTexture(texDepthStencilMS); context.releaseTexture(texDepthStencilMS);
@ -107,10 +110,10 @@ void WgCompositor::resize(WgContext& context, uint32_t width, uint32_t height) {
texViewDepthStencil = context.createTextureView(texDepthStencil); texViewDepthStencil = context.createTextureView(texDepthStencil);
texDepthStencilMS = context.createTexAttachement(width, height, WGPUTextureFormat_Depth24PlusStencil8, 4); texDepthStencilMS = context.createTexAttachement(width, height, WGPUTextureFormat_Depth24PlusStencil8, 4);
texViewDepthStencilMS = context.createTextureView(texDepthStencilMS); texViewDepthStencilMS = context.createTextureView(texDepthStencilMS);
// initialize intermediate render storages // initialize intermediate render targets
storageTemp0.initialize(context, width, height); targetTemp0.initialize(context, width, height);
storageTemp1.initialize(context, width, height); targetTemp1.initialize(context, width, height);
bindGroupStorageTemp = context.layouts.createBindGroupStrorage2RO(storageTemp0.texView, storageTemp1.texView); bindGroupStorageTemp = context.layouts.createBindGroupStrorage2RO(targetTemp0.texView, targetTemp1.texView);
} }
} }
@ -121,14 +124,14 @@ RenderRegion WgCompositor::shrinkRenderRegion(RenderRegion& rect)
} }
void WgCompositor::copyTexture(const WgRenderStorage* dst, const WgRenderStorage* src) void WgCompositor::copyTexture(const WgRenderTarget* dst, const WgRenderTarget* src)
{ {
const RenderRegion region = {{0, 0}, {(int32_t)src->width, (int32_t)src->height}}; const RenderRegion region = {{0, 0}, {(int32_t)src->width, (int32_t)src->height}};
copyTexture(dst, src, region); copyTexture(dst, src, region);
} }
void WgCompositor::copyTexture(const WgRenderStorage* dst, const WgRenderStorage* src, const RenderRegion& region) void WgCompositor::copyTexture(const WgRenderTarget* dst, const WgRenderTarget* src, const RenderRegion& region)
{ {
assert(dst); assert(dst);
assert(src); assert(src);
@ -140,16 +143,25 @@ void WgCompositor::copyTexture(const WgRenderStorage* dst, const WgRenderStorage
} }
void WgCompositor::beginRenderPass(WGPUCommandEncoder commandEncoder, WgRenderStorage* target, bool clear, WGPUColor clearColor) void WgCompositor::beginRenderPass(WGPUCommandEncoder commandEncoder, WgRenderTarget* target, bool clear, WGPUColor clearColor)
{ {
assert(commandEncoder);
assert(target); assert(target);
assert(commandEncoder);
// do not start same render bass
if (target == currentTarget) return;
// we must to end render pass first
endRenderPass();
this->currentTarget = target; this->currentTarget = target;
// start new render pass
this->commandEncoder = commandEncoder; this->commandEncoder = commandEncoder;
const WGPURenderPassDepthStencilAttachment depthStencilAttachment{ const WGPURenderPassDepthStencilAttachment depthStencilAttachment{
.view = texViewDepthStencilMS, .view = texViewDepthStencilMS,
.depthLoadOp = WGPULoadOp_Clear, .depthStoreOp = WGPUStoreOp_Discard, .depthClearValue = 1.0f, .depthLoadOp = WGPULoadOp_Clear,
.stencilLoadOp = WGPULoadOp_Clear, .stencilStoreOp = WGPUStoreOp_Discard, .stencilClearValue = 0 .depthStoreOp = WGPUStoreOp_Discard,
.depthClearValue = 1.0f,
.stencilLoadOp = WGPULoadOp_Clear,
.stencilStoreOp = WGPUStoreOp_Discard,
.stencilClearValue = 0
}; };
const WGPURenderPassColorAttachment colorAttachment{ const WGPURenderPassColorAttachment colorAttachment{
.view = target->texViewMS, .view = target->texViewMS,
@ -158,7 +170,6 @@ void WgCompositor::beginRenderPass(WGPUCommandEncoder commandEncoder, WgRenderSt
.loadOp = clear ? WGPULoadOp_Clear : WGPULoadOp_Load, .loadOp = clear ? WGPULoadOp_Clear : WGPULoadOp_Load,
.storeOp = WGPUStoreOp_Store, .storeOp = WGPUStoreOp_Store,
.clearValue = clearColor .clearValue = clearColor
}; };
WGPURenderPassDescriptor renderPassDesc{ .colorAttachmentCount = 1, .colorAttachments = &colorAttachment, .depthStencilAttachment = &depthStencilAttachment }; WGPURenderPassDescriptor renderPassDesc{ .colorAttachmentCount = 1, .colorAttachments = &colorAttachment, .depthStencilAttachment = &depthStencilAttachment };
renderPassEncoder = wgpuCommandEncoderBeginRenderPass(commandEncoder, &renderPassDesc); renderPassEncoder = wgpuCommandEncoderBeginRenderPass(commandEncoder, &renderPassDesc);
@ -172,11 +183,37 @@ void WgCompositor::endRenderPass()
assert(renderPassEncoder); assert(renderPassEncoder);
wgpuRenderPassEncoderEnd(renderPassEncoder); wgpuRenderPassEncoderEnd(renderPassEncoder);
wgpuRenderPassEncoderRelease(renderPassEncoder); wgpuRenderPassEncoderRelease(renderPassEncoder);
this->renderPassEncoder = nullptr; renderPassEncoder = nullptr;
this->currentTarget = nullptr; currentTarget = nullptr;
} }
} }
void WgCompositor::reset(WgContext& context)
{
stageBuffer.clear();
}
void WgCompositor::flush(WgContext& context)
{
stageBuffer.append(&meshDataBlit);
stageBuffer.flush(context);
}
void WgCompositor::requestShape(WgRenderDataShape* renderData)
{
stageBuffer.append(renderData);
// TODO: expand for fill settings
}
void WgCompositor::requestImage(WgRenderDataPicture* renderData)
{
stageBuffer.append(renderData);
// TODO: expand for fill settings
}
void WgCompositor::renderShape(WgContext& context, WgRenderDataShape* renderData, BlendMethod blendMethod) void WgCompositor::renderShape(WgContext& context, WgRenderDataShape* renderData, BlendMethod blendMethod)
{ {
@ -232,7 +269,7 @@ void WgCompositor::renderImage(WgContext& context, WgRenderDataPicture* renderDa
} }
void WgCompositor::renderScene(WgContext& context, WgRenderStorage* scene, WgCompose* compose) void WgCompositor::renderScene(WgContext& context, WgRenderTarget* scene, WgCompose* compose)
{ {
assert(scene); assert(scene);
assert(compose); assert(compose);
@ -245,7 +282,7 @@ void WgCompositor::renderScene(WgContext& context, WgRenderStorage* scene, WgCom
} }
void WgCompositor::composeScene(WgContext& context, WgRenderStorage* src, WgRenderStorage* mask, WgCompose* cmp) void WgCompositor::composeScene(WgContext& context, WgRenderTarget* src, WgRenderTarget* mask, WgCompose* cmp)
{ {
assert(cmp); assert(cmp);
assert(src); assert(src);
@ -257,15 +294,19 @@ void WgCompositor::composeScene(WgContext& context, WgRenderStorage* src, WgRend
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 0, src->bindGroupTexure, 0, nullptr); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 0, src->bindGroupTexure, 0, nullptr);
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, mask->bindGroupTexure, 0, nullptr); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, mask->bindGroupTexure, 0, nullptr);
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.scene_compose[(uint32_t)cmp->method]); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.scene_compose[(uint32_t)cmp->method]);
meshData.drawImage(context, renderPassEncoder); drawMeshImage(context, &meshDataBlit);
} }
void WgCompositor::blit(WgContext& context, WGPUCommandEncoder encoder, WgRenderStorage* src, WGPUTextureView dstView) { void WgCompositor::blit(WgContext& context, WGPUCommandEncoder encoder, WgRenderTarget* src, WGPUTextureView dstView)
{
assert(!renderPassEncoder);
const WGPURenderPassDepthStencilAttachment depthStencilAttachment{ const WGPURenderPassDepthStencilAttachment depthStencilAttachment{
.view = texViewDepthStencil, .view = texViewDepthStencil,
.depthLoadOp = WGPULoadOp_Load, .depthStoreOp = WGPUStoreOp_Discard, .depthLoadOp = WGPULoadOp_Load,
.stencilLoadOp = WGPULoadOp_Load, .stencilStoreOp = WGPUStoreOp_Discard .depthStoreOp = WGPUStoreOp_Discard,
.stencilLoadOp = WGPULoadOp_Load,
.stencilStoreOp = WGPUStoreOp_Discard
}; };
const WGPURenderPassColorAttachment colorAttachment { const WGPURenderPassColorAttachment colorAttachment {
.view = dstView, .view = dstView,
@ -274,15 +315,56 @@ void WgCompositor::blit(WgContext& context, WGPUCommandEncoder encoder, WgRender
.storeOp = WGPUStoreOp_Store, .storeOp = WGPUStoreOp_Store,
}; };
const WGPURenderPassDescriptor renderPassDesc{ .colorAttachmentCount = 1, .colorAttachments = &colorAttachment, .depthStencilAttachment = &depthStencilAttachment }; const WGPURenderPassDescriptor renderPassDesc{ .colorAttachmentCount = 1, .colorAttachments = &colorAttachment, .depthStencilAttachment = &depthStencilAttachment };
WGPURenderPassEncoder renderPass = wgpuCommandEncoderBeginRenderPass(encoder, &renderPassDesc); renderPassEncoder = wgpuCommandEncoderBeginRenderPass(encoder, &renderPassDesc);
wgpuRenderPassEncoderSetBindGroup(renderPass, 0, src->bindGroupTexure, 0, nullptr); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 0, src->bindGroupTexure, 0, nullptr);
wgpuRenderPassEncoderSetPipeline(renderPass, pipelines.blit); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.blit);
meshData.drawImage(context, renderPass); drawMeshImage(context, &meshDataBlit);
wgpuRenderPassEncoderEnd(renderPass); wgpuRenderPassEncoderEnd(renderPassEncoder);
wgpuRenderPassEncoderRelease(renderPass); wgpuRenderPassEncoderRelease(renderPassEncoder);
renderPassEncoder = nullptr;
} }
void WgCompositor::drawMesh(WgContext& context, WgMeshData* meshData)
{
assert(meshData);
assert(renderPassEncoder);
uint64_t icount = meshData->ibuffer.count;
uint64_t vsize = meshData->vbuffer.count * sizeof(Point);
uint64_t isize = icount * sizeof(uint32_t);
wgpuRenderPassEncoderSetVertexBuffer(renderPassEncoder, 0, stageBuffer.vbuffer_gpu, meshData->voffset, vsize);
wgpuRenderPassEncoderSetIndexBuffer(renderPassEncoder, stageBuffer.ibuffer_gpu, WGPUIndexFormat_Uint32, meshData->ioffset, isize);
wgpuRenderPassEncoderDrawIndexed(renderPassEncoder, icount, 1, 0, 0, 0);
};
void WgCompositor::drawMeshFan(WgContext& context, WgMeshData* meshData)
{
assert(meshData);
assert(renderPassEncoder);
uint64_t icount = (meshData->vbuffer.count - 2) * 3;
uint64_t vsize = meshData->vbuffer.count * sizeof(Point);
uint64_t isize = icount * sizeof(uint32_t);
wgpuRenderPassEncoderSetVertexBuffer(renderPassEncoder, 0, stageBuffer.vbuffer_gpu, meshData->voffset, vsize);
wgpuRenderPassEncoderSetIndexBuffer(renderPassEncoder, context.bufferIndexFan, WGPUIndexFormat_Uint32, 0, isize);
wgpuRenderPassEncoderDrawIndexed(renderPassEncoder, icount, 1, 0, 0, 0);
};
void WgCompositor::drawMeshImage(WgContext& context, WgMeshData* meshData)
{
assert(meshData);
assert(renderPassEncoder);
uint64_t icount = meshData->ibuffer.count;
uint64_t vsize = meshData->vbuffer.count * sizeof(Point);
uint64_t isize = icount * sizeof(uint32_t);
wgpuRenderPassEncoderSetVertexBuffer(renderPassEncoder, 0, stageBuffer.vbuffer_gpu, meshData->voffset, vsize);
wgpuRenderPassEncoderSetVertexBuffer(renderPassEncoder, 1, stageBuffer.vbuffer_gpu, meshData->toffset, vsize);
wgpuRenderPassEncoderSetIndexBuffer(renderPassEncoder, stageBuffer.ibuffer_gpu, WGPUIndexFormat_Uint32, meshData->ioffset, isize);
wgpuRenderPassEncoderDrawIndexed(renderPassEncoder, icount, 1, 0, 0, 0);
};
void WgCompositor::drawShape(WgContext& context, WgRenderDataShape* renderData) void WgCompositor::drawShape(WgContext& context, WgRenderDataShape* renderData)
{ {
assert(renderData); assert(renderData);
@ -298,7 +380,7 @@ void WgCompositor::drawShape(WgContext& context, WgRenderDataShape* renderData)
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, stencilPipeline); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, stencilPipeline);
// draw to stencil (first pass) // draw to stencil (first pass)
ARRAY_FOREACH(p, renderData->meshGroupShapes.meshes) ARRAY_FOREACH(p, renderData->meshGroupShapes.meshes)
(*p)->drawFan(context, renderPassEncoder); drawMeshFan(context, (*p));
// setup fill rules // setup fill rules
wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0); wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0);
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 0, bindGroupViewMat, 0, nullptr); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 0, bindGroupViewMat, 0, nullptr);
@ -315,7 +397,7 @@ void WgCompositor::drawShape(WgContext& context, WgRenderDataShape* renderData)
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.radial); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.radial);
} }
// draw to color (second pass) // draw to color (second pass)
renderData->meshDataBBox.drawFan(context, renderPassEncoder); drawMeshFan(context, &renderData->meshDataBBox);
} }
@ -325,10 +407,10 @@ void WgCompositor::blendShape(WgContext& context, WgRenderDataShape* renderData,
assert(renderPassEncoder); assert(renderPassEncoder);
assert(renderData->meshGroupShapes.meshes.count == renderData->meshGroupShapesBBox.meshes.count); assert(renderData->meshGroupShapes.meshes.count == renderData->meshGroupShapesBBox.meshes.count);
if (renderData->renderSettingsShape.skip || renderData->meshGroupShapes.meshes.count == 0 || renderData->viewport.invalid()) return; if (renderData->renderSettingsShape.skip || renderData->meshGroupShapes.meshes.count == 0 || renderData->viewport.invalid()) return;
// copy current render target data to dst storage // copy current render target data to dst target
WgRenderStorage *target = currentTarget; WgRenderTarget *target = currentTarget;
endRenderPass(); endRenderPass();
copyTexture(&storageTemp0, target); copyTexture(&targetTemp0, target);
beginRenderPass(commandEncoder, target, false); beginRenderPass(commandEncoder, target, false);
// render shape with blend settings // render shape with blend settings
wgpuRenderPassEncoderSetScissorRect(renderPassEncoder, renderData->viewport.x(), renderData->viewport.y(), renderData->viewport.w(), renderData->viewport.h()); wgpuRenderPassEncoderSetScissorRect(renderPassEncoder, renderData->viewport.x(), renderData->viewport.y(), renderData->viewport.w(), renderData->viewport.h());
@ -340,12 +422,12 @@ void WgCompositor::blendShape(WgContext& context, WgRenderDataShape* renderData,
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, stencilPipeline); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, stencilPipeline);
// draw to stencil (first pass) // draw to stencil (first pass)
ARRAY_FOREACH(p, renderData->meshGroupShapes.meshes) ARRAY_FOREACH(p, renderData->meshGroupShapes.meshes)
(*p)->drawFan(context, renderPassEncoder); drawMeshFan(context, (*p));
// setup fill rules // setup fill rules
wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0); wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0);
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 0, bindGroupViewMat, 0, nullptr); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 0, bindGroupViewMat, 0, nullptr);
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, renderData->bindGroupPaint, 0, nullptr); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, renderData->bindGroupPaint, 0, nullptr);
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 3, storageTemp0.bindGroupTexure, 0, nullptr); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 3, targetTemp0.bindGroupTexure, 0, nullptr);
uint32_t blendMethodInd = (uint32_t)blendMethod; uint32_t blendMethodInd = (uint32_t)blendMethod;
WgRenderSettings& settings = renderData->renderSettingsShape; WgRenderSettings& settings = renderData->renderSettingsShape;
if (settings.fillType == WgRenderSettingsType::Solid) { if (settings.fillType == WgRenderSettingsType::Solid) {
@ -359,7 +441,7 @@ void WgCompositor::blendShape(WgContext& context, WgRenderDataShape* renderData,
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.radial_blend[blendMethodInd]); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.radial_blend[blendMethodInd]);
} }
// draw to color (second pass) // draw to color (second pass)
renderData->meshDataBBox.drawFan(context, renderPassEncoder); drawMeshFan(context, &renderData->meshDataBBox);
} }
@ -379,12 +461,12 @@ void WgCompositor::clipShape(WgContext& context, WgRenderDataShape* renderData)
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, stencilPipeline); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, stencilPipeline);
// draw to stencil (first pass) // draw to stencil (first pass)
ARRAY_FOREACH(p, renderData->meshGroupShapes.meshes) ARRAY_FOREACH(p, renderData->meshGroupShapes.meshes)
(*p)->drawFan(context, renderPassEncoder); drawMeshFan(context, (*p));
// merge depth and stencil buffer // merge depth and stencil buffer
wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0); wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0);
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, bindGroupOpacities[128], 0, nullptr); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, bindGroupOpacities[128], 0, nullptr);
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.merge_depth_stencil); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.merge_depth_stencil);
renderData->meshDataBBox.drawFan(context, renderPassEncoder); drawMeshFan(context, &renderData->meshDataBBox);
// setup fill rules // setup fill rules
wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0); wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0);
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 0, bindGroupViewMat, 0, nullptr); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 0, bindGroupViewMat, 0, nullptr);
@ -401,7 +483,7 @@ void WgCompositor::clipShape(WgContext& context, WgRenderDataShape* renderData)
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.radial); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.radial);
} }
// draw to color (second pass) // draw to color (second pass)
renderData->meshDataBBox.drawFan(context, renderPassEncoder); drawMeshFan(context, &renderData->meshDataBBox);
} }
@ -421,7 +503,7 @@ void WgCompositor::drawStrokes(WgContext& context, WgRenderDataShape* renderData
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, renderData->bindGroupPaint, 0, nullptr); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, renderData->bindGroupPaint, 0, nullptr);
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.direct); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.direct);
// draw to stencil (first pass) // draw to stencil (first pass)
renderData->meshGroupStrokes.meshes[i]->draw(context, renderPassEncoder); drawMesh(context, renderData->meshGroupStrokes.meshes[i]);
// setup fill rules // setup fill rules
wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0); wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0);
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 0, bindGroupViewMat, 0, nullptr); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 0, bindGroupViewMat, 0, nullptr);
@ -438,7 +520,7 @@ void WgCompositor::drawStrokes(WgContext& context, WgRenderDataShape* renderData
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.radial); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.radial);
} }
// draw to color (second pass) // draw to color (second pass)
renderData->meshGroupStrokesBBox.meshes[i]->drawFan(context, renderPassEncoder); drawMeshFan(context, renderData->meshGroupStrokesBBox.meshes[i]);
} }
} }
@ -450,10 +532,10 @@ void WgCompositor::blendStrokes(WgContext& context, WgRenderDataShape* renderDat
assert(renderData->meshGroupStrokes.meshes.count == renderData->meshGroupStrokesBBox.meshes.count); assert(renderData->meshGroupStrokes.meshes.count == renderData->meshGroupStrokesBBox.meshes.count);
if (renderData->renderSettingsStroke.skip || renderData->meshGroupStrokes.meshes.count == 0 || renderData->viewport.invalid()) return; if (renderData->renderSettingsStroke.skip || renderData->meshGroupStrokes.meshes.count == 0 || renderData->viewport.invalid()) return;
// copy current render target data to dst storage // copy current render target data to dst target
WgRenderStorage *target = currentTarget; WgRenderTarget *target = currentTarget;
endRenderPass(); endRenderPass();
copyTexture(&storageTemp0, target); copyTexture(&targetTemp0, target);
beginRenderPass(commandEncoder, target, false); beginRenderPass(commandEncoder, target, false);
wgpuRenderPassEncoderSetScissorRect(renderPassEncoder, renderData->viewport.x(), renderData->viewport.y(), renderData->viewport.w(), renderData->viewport.h()); wgpuRenderPassEncoderSetScissorRect(renderPassEncoder, renderData->viewport.x(), renderData->viewport.y(), renderData->viewport.w(), renderData->viewport.h());
// draw strokes to stencil (first pass) // draw strokes to stencil (first pass)
@ -464,12 +546,12 @@ void WgCompositor::blendStrokes(WgContext& context, WgRenderDataShape* renderDat
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, renderData->bindGroupPaint, 0, nullptr); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, renderData->bindGroupPaint, 0, nullptr);
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.direct); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.direct);
// draw to stencil (first pass) // draw to stencil (first pass)
renderData->meshGroupStrokes.meshes[i]->draw(context, renderPassEncoder); drawMesh(context, renderData->meshGroupStrokes.meshes[i]);
// setup fill rules // setup fill rules
wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0); wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0);
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 0, bindGroupViewMat, 0, nullptr); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 0, bindGroupViewMat, 0, nullptr);
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, renderData->bindGroupPaint, 0, nullptr); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, renderData->bindGroupPaint, 0, nullptr);
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 3, storageTemp0.bindGroupTexure, 0, nullptr); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 3, targetTemp0.bindGroupTexure, 0, nullptr);
uint32_t blendMethodInd = (uint32_t)blendMethod; uint32_t blendMethodInd = (uint32_t)blendMethod;
WgRenderSettings& settings = renderData->renderSettingsStroke; WgRenderSettings& settings = renderData->renderSettingsStroke;
if (settings.fillType == WgRenderSettingsType::Solid) { if (settings.fillType == WgRenderSettingsType::Solid) {
@ -483,7 +565,7 @@ void WgCompositor::blendStrokes(WgContext& context, WgRenderDataShape* renderDat
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.radial_blend[blendMethodInd]); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.radial_blend[blendMethodInd]);
} }
// draw to color (second pass) // draw to color (second pass)
renderData->meshGroupStrokesBBox.meshes[i]->drawFan(context, renderPassEncoder); drawMeshFan(context, renderData->meshGroupStrokesBBox.meshes[i]);
} }
}; };
@ -505,12 +587,12 @@ void WgCompositor::clipStrokes(WgContext& context, WgRenderDataShape* renderData
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, renderData->bindGroupPaint, 0, nullptr); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, renderData->bindGroupPaint, 0, nullptr);
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.direct); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.direct);
// draw to stencil (first pass) // draw to stencil (first pass)
renderData->meshGroupStrokes.meshes[i]->draw(context, renderPassEncoder); drawMesh(context, renderData->meshGroupStrokes.meshes[i]);
// merge depth and stencil buffer // merge depth and stencil buffer
wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0); wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0);
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, bindGroupOpacities[128], 0, nullptr); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, bindGroupOpacities[128], 0, nullptr);
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.merge_depth_stencil); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.merge_depth_stencil);
renderData->meshDataBBox.drawFan(context, renderPassEncoder); drawMeshFan(context, &renderData->meshDataBBox);
// setup fill rules // setup fill rules
wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0); wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0);
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 0, bindGroupViewMat, 0, nullptr); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 0, bindGroupViewMat, 0, nullptr);
@ -527,7 +609,7 @@ void WgCompositor::clipStrokes(WgContext& context, WgRenderDataShape* renderData
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.radial); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.radial);
} }
// draw to color (second pass) // draw to color (second pass)
renderData->meshGroupStrokesBBox.meshes[i]->drawFan(context, renderPassEncoder); drawMeshFan(context, renderData->meshGroupStrokesBBox.meshes[i]);
} }
} }
@ -543,14 +625,14 @@ void WgCompositor::drawImage(WgContext& context, WgRenderDataPicture* renderData
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 0, bindGroupViewMat, 0, nullptr); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 0, bindGroupViewMat, 0, nullptr);
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, renderData->bindGroupPaint, 0, nullptr); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, renderData->bindGroupPaint, 0, nullptr);
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.direct); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.direct);
renderData->meshData.drawImage(context, renderPassEncoder); drawMeshImage(context, &renderData->meshData);
// draw image // draw image
wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0); wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0);
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 0, bindGroupViewMat, 0, nullptr); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 0, bindGroupViewMat, 0, nullptr);
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, renderData->bindGroupPaint, 0, nullptr); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, renderData->bindGroupPaint, 0, nullptr);
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, renderData->bindGroupPicture, 0, nullptr); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, renderData->bindGroupPicture, 0, nullptr);
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.image); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.image);
renderData->meshData.drawImage(context, renderPassEncoder); drawMeshImage(context, &renderData->meshData);
} }
@ -560,26 +642,26 @@ void WgCompositor::blendImage(WgContext& context, WgRenderDataPicture* renderDat
assert(renderPassEncoder); assert(renderPassEncoder);
if (renderData->viewport.invalid()) return; if (renderData->viewport.invalid()) return;
wgpuRenderPassEncoderSetScissorRect(renderPassEncoder, renderData->viewport.x(), renderData->viewport.y(), renderData->viewport.w(), renderData->viewport.h()); wgpuRenderPassEncoderSetScissorRect(renderPassEncoder, renderData->viewport.x(), renderData->viewport.y(), renderData->viewport.w(), renderData->viewport.h());
// copy current render target data to dst storage // copy current render target data to dst target
WgRenderStorage *target = currentTarget; WgRenderTarget *target = currentTarget;
endRenderPass(); endRenderPass();
copyTexture(&storageTemp0, target); copyTexture(&targetTemp0, target);
beginRenderPass(commandEncoder, target, false); beginRenderPass(commandEncoder, target, false);
// setup stencil rules // setup stencil rules
wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 255); wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 255);
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 0, bindGroupViewMat, 0, nullptr); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 0, bindGroupViewMat, 0, nullptr);
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, renderData->bindGroupPaint, 0, nullptr); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, renderData->bindGroupPaint, 0, nullptr);
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.direct); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.direct);
renderData->meshData.drawImage(context, renderPassEncoder); drawMeshImage(context, &renderData->meshData);
// blend image // blend image
uint32_t blendMethodInd = (uint32_t)blendMethod; uint32_t blendMethodInd = (uint32_t)blendMethod;
wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0); wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0);
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 0, bindGroupViewMat, 0, nullptr); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 0, bindGroupViewMat, 0, nullptr);
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, renderData->bindGroupPaint, 0, nullptr); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, renderData->bindGroupPaint, 0, nullptr);
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, renderData->bindGroupPicture, 0, nullptr); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, renderData->bindGroupPicture, 0, nullptr);
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 3, storageTemp0.bindGroupTexure, 0, nullptr); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 3, targetTemp0.bindGroupTexure, 0, nullptr);
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.image_blend[blendMethodInd]); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.image_blend[blendMethodInd]);
renderData->meshData.drawImage(context, renderPassEncoder); drawMeshImage(context, &renderData->meshData);
}; };
@ -594,23 +676,23 @@ void WgCompositor::clipImage(WgContext& context, WgRenderDataPicture* renderData
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 0, bindGroupViewMat, 0, nullptr); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 0, bindGroupViewMat, 0, nullptr);
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, renderData->bindGroupPaint, 0, nullptr); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, renderData->bindGroupPaint, 0, nullptr);
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.direct); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.direct);
renderData->meshData.drawImage(context, renderPassEncoder); drawMeshImage(context, &renderData->meshData);
// merge depth and stencil buffer // merge depth and stencil buffer
wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0); wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0);
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, bindGroupOpacities[128], 0, nullptr); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, bindGroupOpacities[128], 0, nullptr);
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.merge_depth_stencil); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.merge_depth_stencil);
renderData->meshData.drawImage(context, renderPassEncoder); drawMeshImage(context, &renderData->meshData);
// draw image // draw image
wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0); wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0);
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 0, bindGroupViewMat, 0, nullptr); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 0, bindGroupViewMat, 0, nullptr);
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, renderData->bindGroupPaint, 0, nullptr); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, renderData->bindGroupPaint, 0, nullptr);
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, renderData->bindGroupPicture, 0, nullptr); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, renderData->bindGroupPicture, 0, nullptr);
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.image); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.image);
renderData->meshData.drawImage(context, renderPassEncoder); drawMeshImage(context, &renderData->meshData);
} }
void WgCompositor::drawScene(WgContext& context, WgRenderStorage* scene, WgCompose* compose) void WgCompositor::drawScene(WgContext& context, WgRenderTarget* scene, WgCompose* compose)
{ {
assert(scene); assert(scene);
assert(compose); assert(compose);
@ -622,19 +704,19 @@ void WgCompositor::drawScene(WgContext& context, WgRenderStorage* scene, WgCompo
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 0, scene->bindGroupTexure, 0, nullptr); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 0, scene->bindGroupTexure, 0, nullptr);
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, bindGroupOpacities[compose->opacity], 0, nullptr); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, bindGroupOpacities[compose->opacity], 0, nullptr);
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.scene); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.scene);
meshData.drawImage(context, renderPassEncoder); drawMeshImage(context, &meshDataBlit);
} }
void WgCompositor::blendScene(WgContext& context, WgRenderStorage* scene, WgCompose* compose) void WgCompositor::blendScene(WgContext& context, WgRenderTarget* scene, WgCompose* compose)
{ {
assert(scene); assert(scene);
assert(compose); assert(compose);
assert(currentTarget); assert(currentTarget);
// copy current render target data to dst storage // copy current render target data to dst target
WgRenderStorage *target = currentTarget; WgRenderTarget *target = currentTarget;
endRenderPass(); endRenderPass();
copyTexture(&storageTemp0, target); copyTexture(&targetTemp0, target);
beginRenderPass(commandEncoder, target, false); beginRenderPass(commandEncoder, target, false);
// blend scene // blend scene
uint32_t blendMethodInd = (uint32_t)compose->blend; uint32_t blendMethodInd = (uint32_t)compose->blend;
@ -642,10 +724,10 @@ void WgCompositor::blendScene(WgContext& context, WgRenderStorage* scene, WgComp
wgpuRenderPassEncoderSetScissorRect(renderPassEncoder, rect.x(), rect.y(), rect.w(), rect.h()); wgpuRenderPassEncoderSetScissorRect(renderPassEncoder, rect.x(), rect.y(), rect.w(), rect.h());
wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0); wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0);
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 0, scene->bindGroupTexure, 0, nullptr); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 0, scene->bindGroupTexure, 0, nullptr);
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, storageTemp0.bindGroupTexure, 0, nullptr); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, targetTemp0.bindGroupTexure, 0, nullptr);
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, bindGroupOpacities[compose->opacity], 0, nullptr); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, bindGroupOpacities[compose->opacity], 0, nullptr);
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.scene_blend[blendMethodInd]); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.scene_blend[blendMethodInd]);
meshData.drawImage(context, renderPassEncoder); drawMeshImage(context, &meshDataBlit);
} }
@ -658,13 +740,13 @@ void WgCompositor::markupClipPath(WgContext& context, WgRenderDataShape* renderD
wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 255); wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 255);
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.direct); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.direct);
ARRAY_FOREACH(p, renderData->meshGroupStrokes.meshes) ARRAY_FOREACH(p, renderData->meshGroupStrokes.meshes)
(*p)->draw(context, renderPassEncoder); drawMesh(context, (*p));
} else { } else {
WGPURenderPipeline stencilPipeline = (renderData->fillRule == FillRule::NonZero) ? pipelines.nonzero : pipelines.evenodd; WGPURenderPipeline stencilPipeline = (renderData->fillRule == FillRule::NonZero) ? pipelines.nonzero : pipelines.evenodd;
wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0); wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0);
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, stencilPipeline); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, stencilPipeline);
ARRAY_FOREACH(p, renderData->meshGroupShapes.meshes) ARRAY_FOREACH(p, renderData->meshGroupShapes.meshes)
(*p)->drawFan(context, renderPassEncoder); drawMeshFan(context, (*p));
} }
} }
@ -686,7 +768,7 @@ void WgCompositor::renderClipPath(WgContext& context, WgRenderDataPaint* paint)
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, renderData0->bindGroupPaint, 0, nullptr); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, renderData0->bindGroupPaint, 0, nullptr);
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, bindGroupOpacities[128], 0, nullptr); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, bindGroupOpacities[128], 0, nullptr);
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.copy_stencil_to_depth); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.copy_stencil_to_depth);
renderData0->meshDataBBox.drawFan(context, renderPassEncoder); drawMeshFan(context, &renderData0->meshDataBBox);
// merge clip pathes with AND logic // merge clip pathes with AND logic
for (auto p = paint->clips.begin() + 1; p < paint->clips.end(); ++p) { for (auto p = paint->clips.begin() + 1; p < paint->clips.end(); ++p) {
// get render data // get render data
@ -698,31 +780,31 @@ void WgCompositor::renderClipPath(WgContext& context, WgRenderDataPaint* paint)
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, renderData->bindGroupPaint, 0, nullptr); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, renderData->bindGroupPaint, 0, nullptr);
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, bindGroupOpacities[190], 0, nullptr); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, bindGroupOpacities[190], 0, nullptr);
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.copy_stencil_to_depth_interm); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.copy_stencil_to_depth_interm);
renderData->meshDataBBox.drawFan(context, renderPassEncoder); drawMeshFan(context, &renderData->meshDataBBox);
// copy depth to stencil // copy depth to stencil
wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 1); wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 1);
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, renderData->bindGroupPaint, 0, nullptr); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, renderData->bindGroupPaint, 0, nullptr);
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, bindGroupOpacities[190], 0, nullptr); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, bindGroupOpacities[190], 0, nullptr);
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.copy_depth_to_stencil); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.copy_depth_to_stencil);
renderData->meshDataBBox.drawFan(context, renderPassEncoder); drawMeshFan(context, &renderData->meshDataBBox);
// clear depth current (keep stencil) // clear depth current (keep stencil)
wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0); wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0);
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, renderData->bindGroupPaint, 0, nullptr); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, renderData->bindGroupPaint, 0, nullptr);
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, bindGroupOpacities[255], 0, nullptr); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, bindGroupOpacities[255], 0, nullptr);
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.clear_depth); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.clear_depth);
renderData->meshDataBBox.drawFan(context, renderPassEncoder); drawMeshFan(context, &renderData->meshDataBBox);
// clear depth original (keep stencil) // clear depth original (keep stencil)
wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0); wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0);
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, renderData0->bindGroupPaint, 0, nullptr); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, renderData0->bindGroupPaint, 0, nullptr);
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, bindGroupOpacities[255], 0, nullptr); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, bindGroupOpacities[255], 0, nullptr);
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.clear_depth); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.clear_depth);
renderData0->meshDataBBox.drawFan(context, renderPassEncoder); drawMeshFan(context, &renderData0->meshDataBBox);
// copy stencil to depth (clear stencil) // copy stencil to depth (clear stencil)
wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0); wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0);
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, renderData->bindGroupPaint, 0, nullptr); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, renderData->bindGroupPaint, 0, nullptr);
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, bindGroupOpacities[128], 0, nullptr); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, bindGroupOpacities[128], 0, nullptr);
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.copy_stencil_to_depth); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.copy_stencil_to_depth);
renderData->meshDataBBox.drawFan(context, renderPassEncoder); drawMeshFan(context, &renderData->meshDataBBox);
} }
} }
@ -743,12 +825,12 @@ void WgCompositor::clearClipPath(WgContext& context, WgRenderDataPaint* paint)
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, renderData->bindGroupPaint, 0, nullptr); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, renderData->bindGroupPaint, 0, nullptr);
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, bindGroupOpacities[255], 0, nullptr); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, bindGroupOpacities[255], 0, nullptr);
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.clear_depth); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.clear_depth);
renderData->meshDataBBox.drawFan(context, renderPassEncoder); drawMeshFan(context, &renderData->meshDataBBox);
} }
} }
bool WgCompositor::gaussianBlur(WgContext& context, WgRenderStorage* dst, const RenderEffectGaussianBlur* params, const WgCompose* compose) bool WgCompositor::gaussianBlur(WgContext& context, WgRenderTarget* dst, const RenderEffectGaussianBlur* params, const WgCompose* compose)
{ {
assert(dst); assert(dst);
assert(params); assert(params);
@ -758,8 +840,8 @@ bool WgCompositor::gaussianBlur(WgContext& context, WgRenderStorage* dst, const
auto renderData = (WgRenderDataEffectParams*)params->rd; auto renderData = (WgRenderDataEffectParams*)params->rd;
auto aabb = compose->aabb; auto aabb = compose->aabb;
auto viewport = compose->rdViewport; auto viewport = compose->rdViewport;
WgRenderStorage* sbuff = dst; WgRenderTarget* sbuff = dst;
WgRenderStorage* dbuff = &storageTemp0; WgRenderTarget* dbuff = &targetTemp0;
// begin compute pass // begin compute pass
WGPUComputePassDescriptor computePassDesc{ .label = "Compute pass gaussian blur" }; WGPUComputePassDescriptor computePassDesc{ .label = "Compute pass gaussian blur" };
@ -791,14 +873,14 @@ bool WgCompositor::gaussianBlur(WgContext& context, WgRenderStorage* dst, const
wgpuComputePassEncoderRelease(computePassEncoder); wgpuComputePassEncoderRelease(computePassEncoder);
// if final result stored in intermidiate buffer we must copy result to destination buffer // if final result stored in intermidiate buffer we must copy result to destination buffer
if (sbuff == &storageTemp0) if (sbuff == &targetTemp0)
copyTexture(sbuff, dbuff, aabb); copyTexture(sbuff, dbuff, aabb);
return true; return true;
} }
bool WgCompositor::dropShadow(WgContext& context, WgRenderStorage* dst, const RenderEffectDropShadow* params, const WgCompose* compose) bool WgCompositor::dropShadow(WgContext& context, WgRenderTarget* dst, const RenderEffectDropShadow* params, const WgCompose* compose)
{ {
assert(dst); assert(dst);
assert(params); assert(params);
@ -811,9 +893,9 @@ bool WgCompositor::dropShadow(WgContext& context, WgRenderStorage* dst, const Re
auto viewport = compose->rdViewport; auto viewport = compose->rdViewport;
{ // apply blur { // apply blur
copyTexture(&storageTemp1, dst, aabb); copyTexture(&targetTemp1, dst, aabb);
WgRenderStorage* sbuff = &storageTemp1; WgRenderTarget* sbuff = &targetTemp1;
WgRenderStorage* dbuff = &storageTemp0; WgRenderTarget* dbuff = &targetTemp0;
WGPUComputePassDescriptor computePassDesc{ .label = "Compute pass drop shadow blur" }; WGPUComputePassDescriptor computePassDesc{ .label = "Compute pass drop shadow blur" };
WGPUComputePassEncoder computePassEncoder = wgpuCommandEncoderBeginComputePass(commandEncoder, &computePassDesc); WGPUComputePassEncoder computePassEncoder = wgpuCommandEncoderBeginComputePass(commandEncoder, &computePassDesc);
// horizontal blur // horizontal blur
@ -837,7 +919,7 @@ bool WgCompositor::dropShadow(WgContext& context, WgRenderStorage* dst, const Re
} }
{ // blend origin (temp0), shadow (temp1) to destination { // blend origin (temp0), shadow (temp1) to destination
copyTexture(&storageTemp0, dst, aabb); copyTexture(&targetTemp0, dst, aabb);
WGPUComputePassDescriptor computePassDesc{ .label = "Compute pass drop shadow blend" }; WGPUComputePassDescriptor computePassDesc{ .label = "Compute pass drop shadow blend" };
WGPUComputePassEncoder computePassEncoder = wgpuCommandEncoderBeginComputePass(commandEncoder, &computePassDesc); WGPUComputePassEncoder computePassEncoder = wgpuCommandEncoderBeginComputePass(commandEncoder, &computePassDesc);
wgpuComputePassEncoderSetBindGroup(computePassEncoder, 0, bindGroupStorageTemp, 0, nullptr); wgpuComputePassEncoderSetBindGroup(computePassEncoder, 0, bindGroupStorageTemp, 0, nullptr);
@ -854,7 +936,7 @@ bool WgCompositor::dropShadow(WgContext& context, WgRenderStorage* dst, const Re
} }
bool WgCompositor::fillEffect(WgContext& context, WgRenderStorage* dst, const RenderEffectFill* params, const WgCompose* compose) bool WgCompositor::fillEffect(WgContext& context, WgRenderTarget* dst, const RenderEffectFill* params, const WgCompose* compose)
{ {
assert(dst); assert(dst);
assert(params); assert(params);
@ -862,7 +944,7 @@ bool WgCompositor::fillEffect(WgContext& context, WgRenderStorage* dst, const Re
assert(compose->rdViewport); assert(compose->rdViewport);
assert(!renderPassEncoder); assert(!renderPassEncoder);
copyTexture(&storageTemp0, dst, compose->aabb); copyTexture(&targetTemp0, dst, compose->aabb);
WGPUComputePassDescriptor computePassDesc{ .label = "Compute pass fill" }; WGPUComputePassDescriptor computePassDesc{ .label = "Compute pass fill" };
WGPUComputePassEncoder computePassEncoder = wgpuCommandEncoderBeginComputePass(commandEncoder, &computePassDesc); WGPUComputePassEncoder computePassEncoder = wgpuCommandEncoderBeginComputePass(commandEncoder, &computePassDesc);
wgpuComputePassEncoderSetBindGroup(computePassEncoder, 0, bindGroupStorageTemp, 0, nullptr); wgpuComputePassEncoderSetBindGroup(computePassEncoder, 0, bindGroupStorageTemp, 0, nullptr);
@ -878,7 +960,7 @@ bool WgCompositor::fillEffect(WgContext& context, WgRenderStorage* dst, const Re
} }
bool WgCompositor::tintEffect(WgContext& context, WgRenderStorage* dst, const RenderEffectTint* params, const WgCompose* compose) bool WgCompositor::tintEffect(WgContext& context, WgRenderTarget* dst, const RenderEffectTint* params, const WgCompose* compose)
{ {
assert(dst); assert(dst);
assert(params); assert(params);
@ -886,7 +968,7 @@ bool WgCompositor::tintEffect(WgContext& context, WgRenderStorage* dst, const Re
assert(compose->rdViewport); assert(compose->rdViewport);
assert(!renderPassEncoder); assert(!renderPassEncoder);
copyTexture(&storageTemp0, dst, compose->aabb); copyTexture(&targetTemp0, dst, compose->aabb);
WGPUComputePassDescriptor computePassDesc{ .label = "Compute pass tint" }; WGPUComputePassDescriptor computePassDesc{ .label = "Compute pass tint" };
WGPUComputePassEncoder computePassEncoder = wgpuCommandEncoderBeginComputePass(commandEncoder, &computePassDesc); WGPUComputePassEncoder computePassEncoder = wgpuCommandEncoderBeginComputePass(commandEncoder, &computePassDesc);
wgpuComputePassEncoderSetBindGroup(computePassEncoder, 0, bindGroupStorageTemp, 0, nullptr); wgpuComputePassEncoderSetBindGroup(computePassEncoder, 0, bindGroupStorageTemp, 0, nullptr);
@ -901,7 +983,7 @@ bool WgCompositor::tintEffect(WgContext& context, WgRenderStorage* dst, const Re
return true; return true;
} }
bool WgCompositor::tritoneEffect(WgContext& context, WgRenderStorage* dst, const RenderEffectTritone* params, const WgCompose* compose) bool WgCompositor::tritoneEffect(WgContext& context, WgRenderTarget* dst, const RenderEffectTritone* params, const WgCompose* compose)
{ {
assert(dst); assert(dst);
assert(params); assert(params);
@ -909,7 +991,7 @@ bool WgCompositor::tritoneEffect(WgContext& context, WgRenderStorage* dst, const
assert(compose->rdViewport); assert(compose->rdViewport);
assert(!renderPassEncoder); assert(!renderPassEncoder);
copyTexture(&storageTemp0, dst, compose->aabb); copyTexture(&targetTemp0, dst, compose->aabb);
WGPUComputePassDescriptor computePassDesc{ .label = "Compute pass tritone" }; WGPUComputePassDescriptor computePassDesc{ .label = "Compute pass tritone" };
WGPUComputePassEncoder computePassEncoder = wgpuCommandEncoderBeginComputePass(commandEncoder, &computePassDesc); WGPUComputePassEncoder computePassEncoder = wgpuCommandEncoderBeginComputePass(commandEncoder, &computePassDesc);
wgpuComputePassEncoderSetBindGroup(computePassEncoder, 0, bindGroupStorageTemp, 0, nullptr); wgpuComputePassEncoderSetBindGroup(computePassEncoder, 0, bindGroupStorageTemp, 0, nullptr);

View file

@ -38,6 +38,8 @@ class WgCompositor
private: private:
// pipelines // pipelines
WgPipelines pipelines{}; WgPipelines pipelines{};
// stage buffers
WgRenderDataStageBuffer stageBuffer{};
// global stencil/depth buffer handles // global stencil/depth buffer handles
WGPUTexture texDepthStencil{}; WGPUTexture texDepthStencil{};
WGPUTextureView texViewDepthStencil{}; WGPUTextureView texViewDepthStencil{};
@ -52,21 +54,26 @@ private:
// current render pass handles // current render pass handles
WGPURenderPassEncoder renderPassEncoder{}; WGPURenderPassEncoder renderPassEncoder{};
WGPUCommandEncoder commandEncoder{}; WGPUCommandEncoder commandEncoder{};
WgRenderStorage* currentTarget{}; WgRenderTarget* currentTarget{};
// intermediate render storages // intermediate render targets
WgRenderStorage storageTemp0; WgRenderTarget targetTemp0;
WgRenderStorage storageTemp1; WgRenderTarget targetTemp1;
WGPUBindGroup bindGroupStorageTemp{}; WGPUBindGroup bindGroupStorageTemp{};
// composition and blend geometries // composition and blend geometries
WgMeshData meshData; WgMeshData meshDataBlit;
// render target dimensions // render target dimensions
uint32_t width{}; uint32_t width{};
uint32_t height{}; uint32_t height{};
// viewport utilities // viewport utilities
RenderRegion shrinkRenderRegion(RenderRegion& rect); RenderRegion shrinkRenderRegion(RenderRegion& rect);
void copyTexture(const WgRenderStorage* dst, const WgRenderStorage* src); void copyTexture(const WgRenderTarget* dst, const WgRenderTarget* src);
void copyTexture(const WgRenderStorage* dst, const WgRenderStorage* src, const RenderRegion& region); void copyTexture(const WgRenderTarget* dst, const WgRenderTarget* src, const RenderRegion& region);
// base meshes draw
void drawMesh(WgContext& context, WgMeshData* meshData);
void drawMeshFan(WgContext& context, WgMeshData* meshData);
void drawMeshImage(WgContext& context, WgMeshData* meshData);
// shapes // shapes
void drawShape(WgContext& context, WgRenderDataShape* renderData); void drawShape(WgContext& context, WgRenderDataShape* renderData);
@ -84,8 +91,8 @@ private:
void clipImage(WgContext& context, WgRenderDataPicture* renderData); void clipImage(WgContext& context, WgRenderDataPicture* renderData);
// scenes // scenes
void drawScene(WgContext& context, WgRenderStorage* scene, WgCompose* compose); void drawScene(WgContext& context, WgRenderTarget* scene, WgCompose* compose);
void blendScene(WgContext& context, WgRenderStorage* src, WgCompose* compose); void blendScene(WgContext& context, WgRenderTarget* src, WgCompose* compose);
// the renderer prioritizes clipping with the stroke over the shape's fill // the renderer prioritizes clipping with the stroke over the shape's fill
void markupClipPath(WgContext& context, WgRenderDataShape* renderData); void markupClipPath(WgContext& context, WgRenderDataShape* renderData);
@ -100,24 +107,32 @@ public:
void resize(WgContext& context, uint32_t width, uint32_t height); void resize(WgContext& context, uint32_t width, uint32_t height);
// render passes workflow // render passes workflow
void beginRenderPass(WGPUCommandEncoder encoder, WgRenderStorage* target, bool clear, WGPUColor clearColor = { 0.0, 0.0, 0.0, 0.0 }); void beginRenderPass(WGPUCommandEncoder encoder, WgRenderTarget* target, bool clear, WGPUColor clearColor = { 0.0, 0.0, 0.0, 0.0 });
void endRenderPass(); void endRenderPass();
// request shapes for drawing (staging)
// stage data
void reset(WgContext& context);
void flush(WgContext& context);
void requestShape(WgRenderDataShape* renderData);
void requestImage(WgRenderDataPicture* renderData);
// render shapes, images and scenes // render shapes, images and scenes
void renderShape(WgContext& context, WgRenderDataShape* renderData, BlendMethod blendMethod); void renderShape(WgContext& context, WgRenderDataShape* renderData, BlendMethod blendMethod);
void renderImage(WgContext& context, WgRenderDataPicture* renderData, BlendMethod blendMethod); void renderImage(WgContext& context, WgRenderDataPicture* renderData, BlendMethod blendMethod);
void renderScene(WgContext& context, WgRenderStorage* scene, WgCompose* compose); void renderScene(WgContext& context, WgRenderTarget* scene, WgCompose* compose);
void composeScene(WgContext& context, WgRenderStorage* src, WgRenderStorage* mask, WgCompose* compose); void composeScene(WgContext& context, WgRenderTarget* src, WgRenderTarget* mask, WgCompose* compose);
// blit render storage to texture view (f.e. screen buffer) // blit render target to texture view (f.e. screen buffer)
void blit(WgContext& context, WGPUCommandEncoder encoder, WgRenderStorage* src, WGPUTextureView dstView); void blit(WgContext& context, WGPUCommandEncoder encoder, WgRenderTarget* src, WGPUTextureView dstView);
// effects // effects
bool gaussianBlur(WgContext& context, WgRenderStorage* dst, const RenderEffectGaussianBlur* params, const WgCompose* compose); bool gaussianBlur(WgContext& context, WgRenderTarget* dst, const RenderEffectGaussianBlur* params, const WgCompose* compose);
bool dropShadow(WgContext& context, WgRenderStorage* dst, const RenderEffectDropShadow* params, const WgCompose* compose); bool dropShadow(WgContext& context, WgRenderTarget* dst, const RenderEffectDropShadow* params, const WgCompose* compose);
bool fillEffect(WgContext& context, WgRenderStorage* dst, const RenderEffectFill* params, const WgCompose* compose); bool fillEffect(WgContext& context, WgRenderTarget* dst, const RenderEffectFill* params, const WgCompose* compose);
bool tintEffect(WgContext& context, WgRenderStorage* dst, const RenderEffectTint* params, const WgCompose* compose); bool tintEffect(WgContext& context, WgRenderTarget* dst, const RenderEffectTint* params, const WgCompose* compose);
bool tritoneEffect(WgContext& context, WgRenderStorage* dst, const RenderEffectTritone* params, const WgCompose* compose); bool tritoneEffect(WgContext& context, WgRenderTarget* dst, const RenderEffectTritone* params, const WgCompose* compose);
}; };
#endif // _TVG_WG_COMPOSITOR_H_ #endif // _TVG_WG_COMPOSITOR_H_

View file

@ -30,95 +30,88 @@
// WgMeshData // WgMeshData
//*********************************************************************** //***********************************************************************
void WgMeshData::draw(WgContext& context, WGPURenderPassEncoder renderPassEncoder)
{
wgpuRenderPassEncoderSetVertexBuffer(renderPassEncoder, 0, bufferPosition, 0, vertexCount * sizeof(float) * 2);
wgpuRenderPassEncoderSetIndexBuffer(renderPassEncoder, bufferIndex, WGPUIndexFormat_Uint32, 0, indexCount * sizeof(uint32_t));
wgpuRenderPassEncoderDrawIndexed(renderPassEncoder, indexCount, 1, 0, 0, 0);
}
void WgMeshData::drawFan(WgContext& context, WGPURenderPassEncoder renderPassEncoder)
{
wgpuRenderPassEncoderSetVertexBuffer(renderPassEncoder, 0, bufferPosition, 0, vertexCount * sizeof(float) * 2);
wgpuRenderPassEncoderSetIndexBuffer(renderPassEncoder, context.bufferIndexFan, WGPUIndexFormat_Uint32, 0, indexCount * sizeof(uint32_t));
wgpuRenderPassEncoderDrawIndexed(renderPassEncoder, indexCount, 1, 0, 0, 0);
}
void WgMeshData::drawImage(WgContext& context, WGPURenderPassEncoder renderPassEncoder)
{
wgpuRenderPassEncoderSetVertexBuffer(renderPassEncoder, 0, bufferPosition, 0, vertexCount * sizeof(float) * 2);
wgpuRenderPassEncoderSetVertexBuffer(renderPassEncoder, 1, bufferTexCoord, 0, vertexCount * sizeof(float) * 2);
wgpuRenderPassEncoderSetIndexBuffer(renderPassEncoder, bufferIndex, WGPUIndexFormat_Uint32, 0, indexCount * sizeof(uint32_t));
wgpuRenderPassEncoderDrawIndexed(renderPassEncoder, indexCount, 1, 0, 0, 0);
};
void WgMeshData::update(WgContext& context, const WgVertexBuffer& vertexBuffer) void WgMeshData::update(WgContext& context, const WgVertexBuffer& vertexBuffer)
{ {
assert(vertexBuffer.count > 2); assert(vertexBuffer.count > 2);
vertexCount = vertexBuffer.count; // setup vertex data
indexCount = (vertexBuffer.count - 2) * 3; vbuffer.reserve(vertexBuffer.count);
context.allocateBufferVertex(bufferPosition, (float*)vertexBuffer.data, vertexCount * sizeof(float) * 2); vbuffer.count = vertexBuffer.count;
context.allocateBufferIndexFan(vertexCount); memcpy(vbuffer.data, vertexBuffer.data, sizeof(vertexBuffer.data[0])*vertexBuffer.count);
// setup tex coords data
tbuffer.clear();
context.allocateBufferIndexFan(vbuffer.count);
} }
void WgMeshData::update(WgContext& context, const WgIndexedVertexBuffer& vertexBufferInd) void WgMeshData::update(WgContext& context, const WgIndexedVertexBuffer& vertexBufferInd)
{ {
assert(vertexBufferInd.vcount > 2); assert(vertexBufferInd.vcount > 2);
vertexCount = vertexBufferInd.vcount; // setup vertex data
indexCount = vertexBufferInd.icount; vbuffer.reserve(vertexBufferInd.vcount);
if (vertexCount > 0) context.allocateBufferVertex(bufferPosition, (float*)vertexBufferInd.vbuff, vertexCount * sizeof(float) * 2); vbuffer.count = vertexBufferInd.vcount;
if (indexCount > 0) context.allocateBufferIndex(bufferIndex, vertexBufferInd.ibuff, indexCount * sizeof(uint32_t)); memcpy(vbuffer.data, vertexBufferInd.vbuff, sizeof(vertexBufferInd.vbuff[0])*vertexBufferInd.vcount);
// setup tex coords data
tbuffer.clear();
// copy index data
ibuffer.reserve(vertexBufferInd.icount);
ibuffer.count = vertexBufferInd.icount;
memcpy(ibuffer.data, vertexBufferInd.ibuff, sizeof(vertexBufferInd.ibuff[0])*vertexBufferInd.icount);
}; };
void WgMeshData::bbox(WgContext& context, const Point pmin, const Point pmax) void WgMeshData::bbox(WgContext& context, const Point pmin, const Point pmax)
{ {
vertexCount = 4;
indexCount = 6;
const float data[] = {pmin.x, pmin.y, pmax.x, pmin.y, pmax.x, pmax.y, pmin.x, pmax.y}; const float data[] = {pmin.x, pmin.y, pmax.x, pmin.y, pmax.x, pmax.y, pmin.x, pmax.y};
context.allocateBufferVertex(bufferPosition, data, sizeof(data)); // setup vertex data
context.allocateBufferIndexFan(vertexCount); vbuffer.reserve(4);
vbuffer.count = 4;
memcpy(vbuffer.data, data, sizeof(data));
// setup tex coords data
tbuffer.clear();
context.allocateBufferIndexFan(vbuffer.count);
} }
void WgMeshData::imageBox(WgContext& context, float w, float h) void WgMeshData::imageBox(WgContext& context, float w, float h)
{ {
vertexCount = 4;
indexCount = 6;
const float vdata[] = {0.0f, 0.0f, w, 0.0f, w, h, 0.0f, h}; const float vdata[] = {0.0f, 0.0f, w, 0.0f, w, h, 0.0f, h};
const float tdata[] = {0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f}; const float tdata[] = {0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f};
const uint32_t idata[] = {0, 1, 2, 0, 2, 3}; const uint32_t idata[] = {0, 1, 2, 0, 2, 3};
context.allocateBufferVertex(bufferPosition, vdata, sizeof(vdata)); // setup vertex data
context.allocateBufferVertex(bufferTexCoord, tdata, sizeof(tdata)); vbuffer.reserve(4);
context.allocateBufferIndex(bufferIndex, idata, sizeof(idata)); vbuffer.count = 4;
memcpy(vbuffer.data, vdata, sizeof(vdata));
// setup tex coords data
tbuffer.reserve(4);
tbuffer.count = 4;
memcpy(tbuffer.data, tdata, sizeof(tdata));
// setup indexes data
ibuffer.reserve(6);
ibuffer.count = 6;
memcpy(ibuffer.data, idata, sizeof(idata));
} }
void WgMeshData::blitBox(WgContext& context) void WgMeshData::blitBox(WgContext& context)
{ {
vertexCount = 4;
indexCount = 6;
const float vdata[] = {-1.0f, +1.0f, +1.0f, +1.0f, +1.0f, -1.0f, -1.0f, -1.0f}; const float vdata[] = {-1.0f, +1.0f, +1.0f, +1.0f, +1.0f, -1.0f, -1.0f, -1.0f};
const float tdata[] = {+0.0f, +0.0f, +1.0f, +0.0f, +1.0f, +1.0f, +0.0f, +1.0f}; const float tdata[] = {+0.0f, +0.0f, +1.0f, +0.0f, +1.0f, +1.0f, +0.0f, +1.0f};
const uint32_t idata[] = { 0, 1, 2, 0, 2, 3 }; const uint32_t idata[] = { 0, 1, 2, 0, 2, 3 };
context.allocateBufferVertex(bufferPosition, vdata, sizeof(vdata)); // setup vertex data
context.allocateBufferVertex(bufferTexCoord, tdata, sizeof(tdata)); vbuffer.reserve(4);
context.allocateBufferIndex(bufferIndex, idata, sizeof(idata)); vbuffer.count = 4;
memcpy(vbuffer.data, vdata, sizeof(vdata));
// setup tex coords data
tbuffer.reserve(4);
tbuffer.count = 4;
memcpy(tbuffer.data, tdata, sizeof(tdata));
// setup indexes data
ibuffer.reserve(6);
ibuffer.count = 6;
memcpy(ibuffer.data, idata, sizeof(idata));
} }
void WgMeshData::release(WgContext& context)
{
context.releaseBuffer(bufferIndex);
context.releaseBuffer(bufferTexCoord);
context.releaseBuffer(bufferPosition);
};
//*********************************************************************** //***********************************************************************
// WgMeshDataPool // WgMeshDataPool
//*********************************************************************** //***********************************************************************
@ -681,3 +674,94 @@ void WgRenderDataEffectParamsPool::release(WgContext& context)
mPool.clear(); mPool.clear();
mList.clear(); mList.clear();
} }
//***********************************************************************
// WgRenderDataStageBuffer
//***********************************************************************
void WgRenderDataStageBuffer::append(WgMeshData* meshData)
{
assert(meshData);
uint32_t vsize = meshData->vbuffer.count * sizeof(meshData->vbuffer[0]);
uint32_t tsize = meshData->tbuffer.count * sizeof(meshData->tbuffer[0]);
uint32_t isize = meshData->ibuffer.count * sizeof(meshData->ibuffer[0]);
// append vertex data
if (vbuffer.reserved < vbuffer.count + vsize)
vbuffer.grow(std::max(vsize, vbuffer.reserved));
if (meshData->vbuffer.count > 0) {
meshData->voffset = vbuffer.count;
memcpy(vbuffer.data + vbuffer.count, meshData->vbuffer.data, vsize);
vbuffer.count += vsize;
}
// append tex coords data
if (vbuffer.reserved < vbuffer.count + tsize)
vbuffer.grow(std::max(tsize, vbuffer.reserved));
if (meshData->tbuffer.count > 0) {
meshData->toffset = vbuffer.count;
memcpy(vbuffer.data + vbuffer.count, meshData->tbuffer.data, tsize);
vbuffer.count += tsize;
}
// append index data
if (ibuffer.reserved < ibuffer.count + isize)
ibuffer.grow(std::max(isize, ibuffer.reserved));
if (meshData->ibuffer.count > 0) {
meshData->ioffset = ibuffer.count;
memcpy(ibuffer.data + ibuffer.count, meshData->ibuffer.data, isize);
ibuffer.count += isize;
}
}
void WgRenderDataStageBuffer::append(WgMeshDataGroup* meshDataGroup)
{
ARRAY_FOREACH(p, meshDataGroup->meshes) append(*p);
}
void WgRenderDataStageBuffer::append(WgRenderDataShape* renderDataShape)
{
append(&renderDataShape->meshGroupShapes);
append(&renderDataShape->meshGroupShapesBBox);
append(&renderDataShape->meshGroupStrokes);
append(&renderDataShape->meshGroupStrokesBBox);
append(&renderDataShape->meshDataBBox);
ARRAY_FOREACH(p, renderDataShape->clips)
append((WgRenderDataShape* )(*p));
}
void WgRenderDataStageBuffer::append(WgRenderDataPicture* renderDataPicture)
{
append(&renderDataPicture->meshData);
ARRAY_FOREACH(p, renderDataPicture->clips)
append((WgRenderDataShape* )(*p));
}
void WgRenderDataStageBuffer::release(WgContext& context)
{
context.releaseBuffer(vbuffer_gpu);
context.releaseBuffer(ibuffer_gpu);
}
void WgRenderDataStageBuffer::clear()
{
vbuffer.clear();
ibuffer.clear();
}
void WgRenderDataStageBuffer::flush(WgContext& context)
{
context.allocateBufferVertex(vbuffer_gpu, (float *)vbuffer.data, vbuffer.count);
context.allocateBufferIndex(ibuffer_gpu, (uint32_t *)ibuffer.data, ibuffer.count);
}
void WgRenderDataStageBuffer::bind(WGPURenderPassEncoder renderPass, size_t voffset, size_t toffset)
{
wgpuRenderPassEncoderSetVertexBuffer(renderPass, 0, vbuffer_gpu, voffset, vbuffer.count - voffset);
wgpuRenderPassEncoderSetVertexBuffer(renderPass, 1, vbuffer_gpu, toffset, vbuffer.count - toffset);
wgpuRenderPassEncoderSetIndexBuffer(renderPass, ibuffer_gpu, WGPUIndexFormat_Uint32, 0, ibuffer.count);
}

View file

@ -28,22 +28,19 @@
#include "tvgWgShaderTypes.h" #include "tvgWgShaderTypes.h"
struct WgMeshData { struct WgMeshData {
WGPUBuffer bufferPosition{}; Array<Point> vbuffer;
WGPUBuffer bufferTexCoord{}; Array<Point> tbuffer;
WGPUBuffer bufferIndex{}; Array<uint32_t> ibuffer;
size_t vertexCount{}; size_t voffset{};
size_t indexCount{}; size_t toffset{};
size_t ioffset{};
void draw(WgContext& context, WGPURenderPassEncoder renderPassEncoder);
void drawFan(WgContext& context, WGPURenderPassEncoder renderPassEncoder);
void drawImage(WgContext& context, WGPURenderPassEncoder renderPassEncoder);
void update(WgContext& context, const WgVertexBuffer& vertexBuffer); void update(WgContext& context, const WgVertexBuffer& vertexBuffer);
void update(WgContext& context, const WgIndexedVertexBuffer& vertexBufferInd); void update(WgContext& context, const WgIndexedVertexBuffer& vertexBufferInd);
void bbox(WgContext& context, const Point pmin, const Point pmax); void bbox(WgContext& context, const Point pmin, const Point pmax);
void imageBox(WgContext& context, float w, float h); void imageBox(WgContext& context, float w, float h);
void blitBox(WgContext& context); void blitBox(WgContext& context);
void release(WgContext& context); void release(WgContext& context) {};
}; };
class WgMeshDataPool { class WgMeshDataPool {
@ -224,4 +221,23 @@ public:
void release(WgContext& context); void release(WgContext& context);
}; };
class WgRenderDataStageBuffer {
private:
Array<uint8_t> vbuffer;
Array<uint8_t> ibuffer;
public:
WGPUBuffer vbuffer_gpu{};
WGPUBuffer ibuffer_gpu{};
void append(WgMeshData* meshData);
void append(WgMeshDataGroup* meshDataGroup);
void append(WgRenderDataShape* renderDataShape);
void append(WgRenderDataPicture* renderDataPicture);
void initialize(WgContext& context){};
void release(WgContext& context);
void clear();
void flush(WgContext& context);
void bind(WGPURenderPassEncoder renderPass, size_t voffset, size_t toffset);
};
#endif // _TVG_WG_RENDER_DATA_H_ #endif // _TVG_WG_RENDER_DATA_H_

View file

@ -22,7 +22,7 @@
#include "tvgWgRenderTarget.h" #include "tvgWgRenderTarget.h"
void WgRenderStorage::initialize(WgContext& context, uint32_t width, uint32_t height) void WgRenderTarget::initialize(WgContext& context, uint32_t width, uint32_t height)
{ {
this->width = width; this->width = width;
this->height = height; this->height = height;
@ -36,7 +36,7 @@ void WgRenderStorage::initialize(WgContext& context, uint32_t width, uint32_t he
} }
void WgRenderStorage::release(WgContext& context) void WgRenderTarget::release(WgContext& context)
{ {
context.layouts.releaseBindGroup(bindGroupTexure); context.layouts.releaseBindGroup(bindGroupTexure);
context.layouts.releaseBindGroup(bindGroupWrite); context.layouts.releaseBindGroup(bindGroupWrite);
@ -50,38 +50,38 @@ void WgRenderStorage::release(WgContext& context)
} }
//***************************************************************************** //*****************************************************************************
// render storage pool // render target pool
//***************************************************************************** //*****************************************************************************
WgRenderStorage* WgRenderStoragePool::allocate(WgContext& context) WgRenderTarget* WgRenderTargetPool::allocate(WgContext& context)
{ {
WgRenderStorage* renderStorage{}; WgRenderTarget* renderTarget{};
if (pool.count > 0) { if (pool.count > 0) {
renderStorage = pool.last(); renderTarget = pool.last();
pool.pop(); pool.pop();
} else { } else {
renderStorage = new WgRenderStorage; renderTarget = new WgRenderTarget;
renderStorage->initialize(context, width, height); renderTarget->initialize(context, width, height);
list.push(renderStorage); list.push(renderTarget);
} }
return renderStorage; return renderTarget;
}; };
void WgRenderStoragePool::free(WgContext& context, WgRenderStorage* renderStorage) void WgRenderTargetPool::free(WgContext& context, WgRenderTarget* renderTarget)
{ {
pool.push(renderStorage); pool.push(renderTarget);
}; };
void WgRenderStoragePool::initialize(WgContext& context, uint32_t width, uint32_t height) void WgRenderTargetPool::initialize(WgContext& context, uint32_t width, uint32_t height)
{ {
this->width = width; this->width = width;
this->height = height; this->height = height;
} }
void WgRenderStoragePool::release(WgContext& context) void WgRenderTargetPool::release(WgContext& context)
{ {
ARRAY_FOREACH(p, list) { ARRAY_FOREACH(p, list) {
(*p)->release(context); (*p)->release(context);

View file

@ -26,7 +26,7 @@
#include "tvgWgPipelines.h" #include "tvgWgPipelines.h"
#include "tvgRender.h" #include "tvgRender.h"
struct WgRenderStorage { struct WgRenderTarget {
WGPUTexture texture{}; WGPUTexture texture{};
WGPUTexture textureMS{}; WGPUTexture textureMS{};
WGPUTextureView texView{}; WGPUTextureView texView{};
@ -42,15 +42,15 @@ struct WgRenderStorage {
}; };
class WgRenderStoragePool { class WgRenderTargetPool {
private: private:
Array<WgRenderStorage*> list; Array<WgRenderTarget*> list;
Array<WgRenderStorage*> pool; Array<WgRenderTarget*> pool;
uint32_t width{}; uint32_t width{};
uint32_t height{}; uint32_t height{};
public: public:
WgRenderStorage* allocate(WgContext& context); WgRenderTarget* allocate(WgContext& context);
void free(WgContext& context, WgRenderStorage* renderTarget); void free(WgContext& context, WgRenderTarget* renderTarget);
void initialize(WgContext& context, uint32_t width, uint32_t height); void initialize(WgContext& context, uint32_t width, uint32_t height);
void release(WgContext& context); void release(WgContext& context);

View file

@ -0,0 +1,93 @@
/*
* Copyright (c) 2025 the ThorVG project. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "tvgWgRenderTask.h"
#include <iostream>
//***********************************************************************
// WgPaintTask
//***********************************************************************
void WgPaintTask::run(WgContext& context, WgCompositor& compositor, WGPUCommandEncoder encoder)
{
if (renderData->type() == tvg::Type::Shape)
compositor.renderShape(context, (WgRenderDataShape*)renderData, blendMethod);
if (renderData->type() == tvg::Type::Picture)
compositor.renderImage(context, (WgRenderDataPicture*)renderData, blendMethod);
else assert(true);
}
//***********************************************************************
// WgSceneTask
//***********************************************************************
void WgSceneTask::run(WgContext& context, WgCompositor& compositor, WGPUCommandEncoder encoder)
{
// begin the render pass for the current scene and clear the target content
WGPUColor color{};
if ((compose->method == MaskMethod::None) && (compose->blend != BlendMethod::Normal)) color = { 1.0, 1.0, 1.0, 0.0 };
compositor.beginRenderPass(encoder, renderTarget, true, color);
// run all childs (scenes and shapes)
runChildren(context, compositor, encoder);
// we must to end current render pass for current scene
compositor.endRenderPass();
// we must to apply effect for current scene
if (effect)
runEffect(context, compositor, encoder);
// there's no point in continuing if the scene has no destination target (e.g., the root scene)
if (!renderTargetDst) return;
// apply scene blending
if (compose->method == MaskMethod::None) {
compositor.beginRenderPass(encoder, renderTargetDst, false);
compositor.renderScene(context, renderTarget, compose);
// apply scene composition (for scenes, that have a handle to mask)
} else if (renderTargetMsk) {
compositor.beginRenderPass(encoder, renderTargetDst, false);
compositor.composeScene(context, renderTarget, renderTargetMsk, compose);
}
}
void WgSceneTask::runChildren(WgContext& context, WgCompositor& compositor, WGPUCommandEncoder encoder)
{
ARRAY_FOREACH(task, children) {
WgRenderTask* renderTask = *task;
// we need to restore current render pass without clear
compositor.beginRenderPass(encoder, renderTarget, false);
// run children (shape or scene)
renderTask->run(context, compositor, encoder);
}
}
void WgSceneTask::runEffect(WgContext& context, WgCompositor& compositor, WGPUCommandEncoder encoder)
{
assert(effect);
switch (effect->type) {
case SceneEffect::GaussianBlur: compositor.gaussianBlur(context, renderTarget, (RenderEffectGaussianBlur*)effect, compose); break;
case SceneEffect::DropShadow: compositor.dropShadow(context, renderTarget, (RenderEffectDropShadow*)effect, compose); break;
case SceneEffect::Fill: compositor.fillEffect(context, renderTarget, (RenderEffectFill*)effect, compose); break;
case SceneEffect::Tint: compositor.tintEffect(context, renderTarget, (RenderEffectTint*)effect, compose); break;
case SceneEffect::Tritone : compositor.tritoneEffect(context, renderTarget, (RenderEffectTritone*)effect, compose); break;
default: break;
}
}

View file

@ -0,0 +1,72 @@
/*
* Copyright (c) 2025 the ThorVG project. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef _TVG_WG_RENDER_TASK_H_
#define _TVG_WG_RENDER_TASK_H_
#include "tvgWgCompositor.h"
// base class for any renderable objects
struct WgRenderTask {
virtual ~WgRenderTask() {}
virtual void run(WgContext& context, WgCompositor& compositor, WGPUCommandEncoder encoder) = 0;
};
// task for sinlge shape rendering
struct WgPaintTask: public WgRenderTask {
// shape render properties
WgRenderDataPaint* renderData{};
BlendMethod blendMethod{};
WgPaintTask(WgRenderDataPaint* renderData, BlendMethod blendMethod) :
renderData(renderData), blendMethod(blendMethod) {}
// apply shape execution, including custom blending and clipping
void run(WgContext& context, WgCompositor& compositor, WGPUCommandEncoder encoder) override;
};
// task for scene rendering with blending, composition and effect
struct WgSceneTask: public WgRenderTask {
public:
// parent scene (nullptr for root scene)
WgSceneTask* parent{};
// childs can be shapes or scenes tesks
Array<WgRenderTask*> children;
// scene blend/compose targets
WgRenderTarget* renderTarget{};
WgRenderTarget* renderTargetMsk{};
WgRenderTarget* renderTargetDst{};
// scene blend/compose properties
WgCompose* compose{};
// scene effect properties
const RenderEffect* effect{};
WgSceneTask(WgRenderTarget* renderTarget, WgCompose* compose, WgSceneTask* parent) :
parent(parent), renderTarget(renderTarget), compose(compose) {}
// run all, including all shapes drawing, blending, composition and effect
void run(WgContext& context, WgCompositor& compositor, WGPUCommandEncoder encoder) override;
private:
void runChildren(WgContext& context, WgCompositor& compositor, WGPUCommandEncoder encoder);
void runEffect(WgContext& context, WgCompositor& compositor, WGPUCommandEncoder encoder);
};
#endif // _TVG_WG_RENDER_TASK_H_

View file

@ -47,13 +47,13 @@ void WgRenderer::release()
mRenderDataEffectParamsPool.release(mContext); mRenderDataEffectParamsPool.release(mContext);
WgMeshDataPool::gMeshDataPool->release(mContext); WgMeshDataPool::gMeshDataPool->release(mContext);
// clear render storage pool // clear render pool
mRenderStoragePool.release(mContext); mRenderTargetPool.release(mContext);
// clear rendering tree stacks // clear rendering tree stacks
mCompositorStack.clear(); mCompositorList.clear();
mRenderStorageStack.clear(); mRenderTargetStack.clear();
mRenderStorageRoot.release(mContext); mRenderTargetRoot.release(mContext);
// release context handles // release context handles
mCompositor.release(mContext); mCompositor.release(mContext);
@ -195,50 +195,71 @@ RenderData WgRenderer::prepare(RenderSurface* surface, RenderData data, const Ma
bool WgRenderer::preRender() bool WgRenderer::preRender()
{ {
// invalidate context
if (mContext.invalid()) return false; if (mContext.invalid()) return false;
// reset stage data
// push rot render storage to the render tree stack mCompositor.reset(mContext);
assert(mRenderStorageStack.count == 0); // push root render target to the render tree stack
mRenderStorageStack.push(&mRenderStorageRoot); assert(mRenderTargetStack.count == 0);
// create command encoder for drawing mRenderTargetStack.push(&mRenderTargetRoot);
WGPUCommandEncoderDescriptor commandEncoderDesc{}; // create root compose settings
mCommandEncoder = wgpuDeviceCreateCommandEncoder(mContext.device, &commandEncoderDesc); WgCompose* compose = new WgCompose();
// start root render pass compose->aabb = { { 0, 0 }, { (int32_t)mTargetSurface.w, (int32_t)mTargetSurface.h } };
mCompositor.beginRenderPass(mCommandEncoder, mRenderStorageStack.last(), true); compose->blend = BlendMethod::Normal;
compose->method = MaskMethod::None;
compose->opacity = 255;
mCompositorList.push(compose);
// create root scene
WgSceneTask* sceneTask = new WgSceneTask(&mRenderTargetRoot, compose, nullptr);
mRenderTaskList.push(sceneTask);
mSceneTaskStack.push(sceneTask);
return true; return true;
} }
bool WgRenderer::renderShape(RenderData data) bool WgRenderer::renderShape(RenderData data)
{ {
// temporary simple render data to the current render target WgPaintTask* paintTask = new WgPaintTask((WgRenderDataPaint*)data, mBlendMethod);
mCompositor.renderShape(mContext, (WgRenderDataShape*)data, mBlendMethod); WgSceneTask* sceneTask = mSceneTaskStack.last();
sceneTask->children.push(paintTask);
mRenderTaskList.push(paintTask);
mCompositor.requestShape((WgRenderDataShape*)data);
return true; return true;
} }
bool WgRenderer::renderImage(RenderData data) bool WgRenderer::renderImage(RenderData data)
{ {
// temporary simple render data to the current render target WgPaintTask* paintTask = new WgPaintTask((WgRenderDataPaint*)data, mBlendMethod);
mCompositor.renderImage(mContext, (WgRenderDataPicture*)data, mBlendMethod); WgSceneTask* sceneTask = mSceneTaskStack.last();
sceneTask->children.push(paintTask);
mRenderTaskList.push(paintTask);
mCompositor.requestImage((WgRenderDataPicture*)data);
return true; return true;
} }
bool WgRenderer::postRender() bool WgRenderer::postRender()
{ {
// end root render pass // flush stage data to gpu
mCompositor.endRenderPass(); mCompositor.flush(mContext);
// release command encoder // create command encoder for drawing
const WGPUCommandBufferDescriptor commandBufferDesc{}; WGPUCommandEncoder commandEncoder = mContext.createCommandEncoder();
WGPUCommandBuffer commandsBuffer = wgpuCommandEncoderFinish(mCommandEncoder, &commandBufferDesc); // run rendering (all the fun is here)
wgpuQueueSubmit(mContext.queue, 1, &commandsBuffer); WgSceneTask* sceneTaskRoot = mSceneTaskStack.last();
wgpuCommandBufferRelease(commandsBuffer); sceneTaskRoot->run(mContext, mCompositor, commandEncoder);
wgpuCommandEncoderRelease(mCommandEncoder); // execute and release command encoder
// pop root render storage to the render tree stack mContext.submitCommandEncoder(commandEncoder);
mRenderStorageStack.pop(); mContext.releaseCommandEncoder(commandEncoder);
assert(mRenderStorageStack.count == 0); // clear the render tasks tree
// clear viewport list and store allocated handles to pool mSceneTaskStack.pop();
assert(mSceneTaskStack.count == 0);
mRenderTargetStack.pop();
assert(mRenderTargetStack.count == 0);
ARRAY_FOREACH(p, mRenderTaskList) { delete (*p); };
mRenderTaskList.clear();
ARRAY_FOREACH(p, mCompositorList) { delete (*p); };
mCompositorList.clear();
ARRAY_FOREACH(p, mRenderDataViewportList) ARRAY_FOREACH(p, mRenderDataViewportList)
mRenderDataViewportPool.free(mContext, *p); mRenderDataViewportPool.free(mContext, *p);
mRenderDataViewportList.clear(); mRenderDataViewportList.clear();
@ -325,18 +346,11 @@ bool WgRenderer::sync()
WGPUTextureView dstTextureView = mContext.createTextureView(dstTexture); WGPUTextureView dstTextureView = mContext.createTextureView(dstTexture);
// create command encoder // create command encoder
const WGPUCommandEncoderDescriptor commandEncoderDesc{}; WGPUCommandEncoder commandEncoder = mContext.createCommandEncoder();
WGPUCommandEncoder commandEncoder = wgpuDeviceCreateCommandEncoder(mContext.device, &commandEncoderDesc);
// show root offscreen buffer // show root offscreen buffer
mCompositor.blit(mContext, commandEncoder, &mRenderStorageRoot, dstTextureView); mCompositor.blit(mContext, commandEncoder, &mRenderTargetRoot, dstTextureView);
mContext.submitCommandEncoder(commandEncoder);
// release command encoder mContext.releaseCommandEncoder(commandEncoder);
const WGPUCommandBufferDescriptor commandBufferDesc{};
WGPUCommandBuffer commandsBuffer = wgpuCommandEncoderFinish(commandEncoder, &commandBufferDesc);
wgpuQueueSubmit(mContext.queue, 1, &commandsBuffer);
wgpuCommandBufferRelease(commandsBuffer);
wgpuCommandEncoderRelease(commandEncoder);
// release dest buffer view // release dest buffer view
mContext.releaseTextureView(dstTextureView); mContext.releaseTextureView(dstTextureView);
@ -367,8 +381,8 @@ bool WgRenderer::target(WGPUDevice device, WGPUInstance instance, void* target,
mContext.initialize(instance, device); mContext.initialize(instance, device);
// initialize render tree instances // initialize render tree instances
mRenderStoragePool.initialize(mContext, width, height); mRenderTargetPool.initialize(mContext, width, height);
mRenderStorageRoot.initialize(mContext, width, height); mRenderTargetRoot.initialize(mContext, width, height);
mCompositor.initialize(mContext, width, height); mCompositor.initialize(mContext, width, height);
// store target properties // store target properties
@ -387,12 +401,12 @@ bool WgRenderer::target(WGPUDevice device, WGPUInstance instance, void* target,
// update render targets dimentions // update render targets dimentions
if ((mTargetSurface.w != width) || (mTargetSurface.h != height) || (type == 0 ? (surface != (WGPUSurface)target) : (targetTexture != (WGPUTexture)target))) { if ((mTargetSurface.w != width) || (mTargetSurface.h != height) || (type == 0 ? (surface != (WGPUSurface)target) : (targetTexture != (WGPUTexture)target))) {
// release render tagets // release render tagets
mRenderStoragePool.release(mContext); mRenderTargetPool.release(mContext);
mRenderStorageRoot.release(mContext); mRenderTargetRoot.release(mContext);
clearTargets(); clearTargets();
mRenderStoragePool.initialize(mContext, width, height); mRenderTargetPool.initialize(mContext, width, height);
mRenderStorageRoot.initialize(mContext, width, height); mRenderTargetRoot.initialize(mContext, width, height);
mCompositor.resize(mContext, width, height); mCompositor.resize(mContext, width, height);
// store target properties // store target properties
@ -447,7 +461,7 @@ RenderCompositor* WgRenderer::target(const RenderRegion& region, TVG_UNUSED Colo
compose->rdViewport->update(mContext, region); compose->rdViewport->update(mContext, region);
mRenderDataViewportList.push(compose->rdViewport); mRenderDataViewportList.push(compose->rdViewport);
} }
mCompositorStack.push(compose); mCompositorList.push(compose);
return compose; return compose;
} }
@ -459,57 +473,52 @@ bool WgRenderer::beginComposite(RenderCompositor* cmp, MaskMethod method, uint8_
compose->method = method; compose->method = method;
compose->opacity = opacity; compose->opacity = opacity;
compose->blend = mBlendMethod; compose->blend = mBlendMethod;
// end current render pass WgSceneTask* sceneTaskCurrent = mSceneTaskStack.last();
mCompositor.endRenderPass(); // allocate new render target and push to the render tree stack
// allocate new render storage and push to the render tree stack WgRenderTarget* renderTarget = mRenderTargetPool.allocate(mContext);
WgRenderStorage* storage = mRenderStoragePool.allocate(mContext); mRenderTargetStack.push(renderTarget);
mRenderStorageStack.push(storage); // create and setup new scene task
// begin newly added render pass WgSceneTask* sceneTask = new WgSceneTask(renderTarget, compose, sceneTaskCurrent);
WGPUColor color{}; sceneTaskCurrent->children.push(sceneTask);
if ((compose->method == MaskMethod::None) && (compose->blend != BlendMethod::Normal)) color = { 1.0, 1.0, 1.0, 0.0 }; mRenderTaskList.push(sceneTask);
mCompositor.beginRenderPass(mCommandEncoder, mRenderStorageStack.last(), true, color); mSceneTaskStack.push(sceneTask);
return true; return true;
} }
bool WgRenderer::endComposite(RenderCompositor* cmp) bool WgRenderer::endComposite(RenderCompositor* cmp)
{ {
// get current composition settings
WgCompose* comp = (WgCompose*)cmp;
// we must to end current render pass to run blend/composition mechanics
mCompositor.endRenderPass();
// finish scene blending // finish scene blending
if (comp->method == MaskMethod::None) { if (cmp->method == MaskMethod::None) {
// get source and destination render storages // get source and destination render targets
WgRenderStorage* src = mRenderStorageStack.last(); WgRenderTarget* src = mRenderTargetStack.last();
mRenderStorageStack.pop(); mRenderTargetStack.pop();
WgRenderStorage* dst = mRenderStorageStack.last(); // pop source scene
// begin previous render pass WgSceneTask* srcScene = mSceneTaskStack.last();
mCompositor.beginRenderPass(mCommandEncoder, dst, false); mSceneTaskStack.pop();
// apply composition // setup render target compose destitations
mCompositor.renderScene(mContext, src, comp); srcScene->renderTargetDst = mSceneTaskStack.last()->renderTarget;
srcScene->renderTargetMsk = nullptr;
// back render targets to the pool // back render targets to the pool
mRenderStoragePool.free(mContext, src); mRenderTargetPool.free(mContext, src);
} else { // finish composition } else { // finish scene composition
// get source, mask and destination render storages // get source, mask and destination render targets
WgRenderStorage* src = mRenderStorageStack.last(); WgRenderTarget* src = mRenderTargetStack.last();
mRenderStorageStack.pop(); mRenderTargetStack.pop();
WgRenderStorage* msk = mRenderStorageStack.last(); WgRenderTarget* msk = mRenderTargetStack.last();
mRenderStorageStack.pop(); mRenderTargetStack.pop();
WgRenderStorage* dst = mRenderStorageStack.last(); // get source and mask scenes
// begin previous render pass WgSceneTask* srcScene = mSceneTaskStack.last();
mCompositor.beginRenderPass(mCommandEncoder, dst, false); mSceneTaskStack.pop();
// apply composition WgSceneTask* mskScene = mSceneTaskStack.last();
mCompositor.composeScene(mContext, src, msk, comp); mSceneTaskStack.pop();
// setup render target compose destitations
srcScene->renderTargetDst = mSceneTaskStack.last()->renderTarget;
srcScene->renderTargetMsk = mskScene->renderTarget;
// back render targets to the pool // back render targets to the pool
mRenderStoragePool.free(mContext, src); mRenderTargetPool.free(mContext, src);
mRenderStoragePool.free(mContext, msk); mRenderTargetPool.free(mContext, msk);
} }
// delete current compositor settings
delete mCompositorStack.last();
mCompositorStack.pop();
return true; return true;
} }
@ -606,20 +615,8 @@ bool WgRenderer::region(RenderEffect* effect)
bool WgRenderer::render(RenderCompositor* cmp, const RenderEffect* effect, TVG_UNUSED bool direct) bool WgRenderer::render(RenderCompositor* cmp, const RenderEffect* effect, TVG_UNUSED bool direct)
{ {
// we must to end current render pass to resolve ms texture before effect mSceneTaskStack.last()->effect = effect;
mCompositor.endRenderPass(); return true;
WgCompose* comp = (WgCompose*)cmp;
WgRenderStorage* dst = mRenderStorageStack.last();
switch (effect->type) {
case SceneEffect::GaussianBlur: return mCompositor.gaussianBlur(mContext, dst, (RenderEffectGaussianBlur*)effect, comp);
case SceneEffect::DropShadow: return mCompositor.dropShadow(mContext, dst, (RenderEffectDropShadow*)effect, comp);
case SceneEffect::Fill: return mCompositor.fillEffect(mContext, dst, (RenderEffectFill*)effect, comp);
case SceneEffect::Tint: return mCompositor.tintEffect(mContext, dst, (RenderEffectTint*)effect, comp);
case SceneEffect::Tritone : return mCompositor.tritoneEffect(mContext, dst, (RenderEffectTritone*)effect, comp);
default: return false;
}
return false;
} }

View file

@ -23,7 +23,7 @@
#ifndef _TVG_WG_RENDERER_H_ #ifndef _TVG_WG_RENDERER_H_
#define _TVG_WG_RENDERER_H_ #define _TVG_WG_RENDERER_H_
#include "tvgWgCompositor.h" #include "tvgWgRenderTask.h"
class WgRenderer : public RenderMethod class WgRenderer : public RenderMethod
{ {
@ -72,13 +72,15 @@ private:
bool surfaceConfigure(WGPUSurface surface, WgContext& context, uint32_t width, uint32_t height); bool surfaceConfigure(WGPUSurface surface, WgContext& context, uint32_t width, uint32_t height);
// render tree stacks // render tree stacks
WgRenderStorage mRenderStorageRoot; WgRenderTarget mRenderTargetRoot;
Array<WgCompose*> mCompositorStack; Array<WgCompose*> mCompositorList;
Array<WgRenderStorage*> mRenderStorageStack; Array<WgRenderTarget*> mRenderTargetStack;
Array<WgRenderDataViewport*> mRenderDataViewportList; Array<WgRenderDataViewport*> mRenderDataViewportList;
Array<WgSceneTask*> mSceneTaskStack;
Array<WgRenderTask*> mRenderTaskList;
// render storage pool // render target pool
WgRenderStoragePool mRenderStoragePool; WgRenderTargetPool mRenderTargetPool;
// render data paint pools // render data paint pools
WgRenderDataShapePool mRenderDataShapePool; WgRenderDataShapePool mRenderDataShapePool;
@ -100,7 +102,6 @@ private:
Key mDisposeKey{}; Key mDisposeKey{};
// gpu handles // gpu handles
WGPUCommandEncoder mCommandEncoder{};
WGPUTexture targetTexture{}; // external handle WGPUTexture targetTexture{}; // external handle
WGPUSurfaceTexture surfaceTexture{}; WGPUSurfaceTexture surfaceTexture{};
WGPUSurface surface{}; // external handle WGPUSurface surface{}; // external handle