mirror of
https://github.com/thorvg/thorvg.git
synced 2025-06-07 13:13:23 +00:00
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
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:
parent
1f53f2d72f
commit
24509b0e41
13 changed files with 709 additions and 314 deletions
|
@ -7,6 +7,7 @@ source_file = [
|
|||
'tvgWgRenderData.h',
|
||||
'tvgWgRenderer.h',
|
||||
'tvgWgRenderTarget.h',
|
||||
'tvgWgRenderTask.h',
|
||||
'tvgWgShaderSrc.h',
|
||||
'tvgWgShaderTypes.h',
|
||||
'tvgWgBindGroups.cpp',
|
||||
|
@ -17,6 +18,7 @@ source_file = [
|
|||
'tvgWgRenderData.cpp',
|
||||
'tvgWgRenderer.cpp',
|
||||
'tvgWgRenderTarget.cpp',
|
||||
'tvgWgRenderTask.cpp',
|
||||
'tvgWgShaderSrc.cpp',
|
||||
'tvgWgShaderTypes.cpp'
|
||||
]
|
||||
|
|
|
@ -268,4 +268,35 @@ void WgContext::releaseQueue(WGPUQueue& queue)
|
|||
wgpuQueueRelease(queue);
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -71,10 +71,12 @@ struct WgContext {
|
|||
// release buffer objects
|
||||
void releaseBuffer(WGPUBuffer& buffer);
|
||||
|
||||
bool invalid()
|
||||
{
|
||||
return !instance || !device;
|
||||
}
|
||||
// command encoder
|
||||
WGPUCommandEncoder createCommandEncoder();
|
||||
void submitCommandEncoder(WGPUCommandEncoder encoder);
|
||||
void releaseCommandEncoder(WGPUCommandEncoder& encoder);
|
||||
|
||||
bool invalid();
|
||||
};
|
||||
|
||||
#endif // _TVG_WG_COMMON_H_
|
||||
|
|
|
@ -28,6 +28,7 @@ void WgCompositor::initialize(WgContext& context, uint32_t width, uint32_t heigh
|
|||
{
|
||||
// pipelines (external handle, do not release)
|
||||
pipelines.initialize(context);
|
||||
stageBuffer.initialize(context);
|
||||
// initialize opacity pool
|
||||
initPools(context);
|
||||
// allocate global view matrix handles
|
||||
|
@ -37,7 +38,7 @@ void WgCompositor::initialize(WgContext& context, uint32_t width, uint32_t heigh
|
|||
// create render targets handles
|
||||
resize(context, width, height);
|
||||
// composition and blend geometries
|
||||
meshData.blitBox(context);
|
||||
meshDataBlit.blitBox(context);
|
||||
}
|
||||
|
||||
|
||||
|
@ -54,7 +55,7 @@ void WgCompositor::initPools(WgContext& context)
|
|||
void WgCompositor::release(WgContext& context)
|
||||
{
|
||||
// composition and blend geometries
|
||||
meshData.release(context);
|
||||
meshDataBlit.release(context);
|
||||
// release render targets habdles
|
||||
resize(context, 0, 0);
|
||||
// release opacity pool
|
||||
|
@ -62,6 +63,8 @@ void WgCompositor::release(WgContext& context)
|
|||
// release global view matrix handles
|
||||
context.layouts.releaseBindGroup(bindGroupViewMat);
|
||||
context.releaseBuffer(bufferViewMat);
|
||||
// release stage buffer
|
||||
stageBuffer.release(context);
|
||||
// release pipelines
|
||||
pipelines.release(context);
|
||||
}
|
||||
|
@ -81,9 +84,9 @@ void WgCompositor::resize(WgContext& context, uint32_t width, uint32_t height) {
|
|||
// release existig handles
|
||||
if ((this->width != width) || (this->height != height)) {
|
||||
context.layouts.releaseBindGroup(bindGroupStorageTemp);
|
||||
// release intermediate render storages
|
||||
storageTemp1.release(context);
|
||||
storageTemp0.release(context);
|
||||
// release intermediate render target
|
||||
targetTemp1.release(context);
|
||||
targetTemp0.release(context);
|
||||
// release global stencil buffer handles
|
||||
context.releaseTextureView(texViewDepthStencilMS);
|
||||
context.releaseTexture(texDepthStencilMS);
|
||||
|
@ -107,10 +110,10 @@ void WgCompositor::resize(WgContext& context, uint32_t width, uint32_t height) {
|
|||
texViewDepthStencil = context.createTextureView(texDepthStencil);
|
||||
texDepthStencilMS = context.createTexAttachement(width, height, WGPUTextureFormat_Depth24PlusStencil8, 4);
|
||||
texViewDepthStencilMS = context.createTextureView(texDepthStencilMS);
|
||||
// initialize intermediate render storages
|
||||
storageTemp0.initialize(context, width, height);
|
||||
storageTemp1.initialize(context, width, height);
|
||||
bindGroupStorageTemp = context.layouts.createBindGroupStrorage2RO(storageTemp0.texView, storageTemp1.texView);
|
||||
// initialize intermediate render targets
|
||||
targetTemp0.initialize(context, width, height);
|
||||
targetTemp1.initialize(context, width, height);
|
||||
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}};
|
||||
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(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(commandEncoder);
|
||||
// do not start same render bass
|
||||
if (target == currentTarget) return;
|
||||
// we must to end render pass first
|
||||
endRenderPass();
|
||||
this->currentTarget = target;
|
||||
// start new render pass
|
||||
this->commandEncoder = commandEncoder;
|
||||
const WGPURenderPassDepthStencilAttachment depthStencilAttachment{
|
||||
.view = texViewDepthStencilMS,
|
||||
.depthLoadOp = WGPULoadOp_Clear, .depthStoreOp = WGPUStoreOp_Discard, .depthClearValue = 1.0f,
|
||||
.stencilLoadOp = WGPULoadOp_Clear, .stencilStoreOp = WGPUStoreOp_Discard, .stencilClearValue = 0
|
||||
.depthLoadOp = WGPULoadOp_Clear,
|
||||
.depthStoreOp = WGPUStoreOp_Discard,
|
||||
.depthClearValue = 1.0f,
|
||||
.stencilLoadOp = WGPULoadOp_Clear,
|
||||
.stencilStoreOp = WGPUStoreOp_Discard,
|
||||
.stencilClearValue = 0
|
||||
};
|
||||
const WGPURenderPassColorAttachment colorAttachment{
|
||||
.view = target->texViewMS,
|
||||
|
@ -158,7 +170,6 @@ void WgCompositor::beginRenderPass(WGPUCommandEncoder commandEncoder, WgRenderSt
|
|||
.loadOp = clear ? WGPULoadOp_Clear : WGPULoadOp_Load,
|
||||
.storeOp = WGPUStoreOp_Store,
|
||||
.clearValue = clearColor
|
||||
|
||||
};
|
||||
WGPURenderPassDescriptor renderPassDesc{ .colorAttachmentCount = 1, .colorAttachments = &colorAttachment, .depthStencilAttachment = &depthStencilAttachment };
|
||||
renderPassEncoder = wgpuCommandEncoderBeginRenderPass(commandEncoder, &renderPassDesc);
|
||||
|
@ -172,11 +183,37 @@ void WgCompositor::endRenderPass()
|
|||
assert(renderPassEncoder);
|
||||
wgpuRenderPassEncoderEnd(renderPassEncoder);
|
||||
wgpuRenderPassEncoderRelease(renderPassEncoder);
|
||||
this->renderPassEncoder = nullptr;
|
||||
this->currentTarget = nullptr;
|
||||
renderPassEncoder = 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)
|
||||
{
|
||||
|
@ -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(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(src);
|
||||
|
@ -257,15 +294,19 @@ void WgCompositor::composeScene(WgContext& context, WgRenderStorage* src, WgRend
|
|||
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 0, src->bindGroupTexure, 0, nullptr);
|
||||
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, mask->bindGroupTexure, 0, nullptr);
|
||||
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{
|
||||
.view = texViewDepthStencil,
|
||||
.depthLoadOp = WGPULoadOp_Load, .depthStoreOp = WGPUStoreOp_Discard,
|
||||
.stencilLoadOp = WGPULoadOp_Load, .stencilStoreOp = WGPUStoreOp_Discard
|
||||
.depthLoadOp = WGPULoadOp_Load,
|
||||
.depthStoreOp = WGPUStoreOp_Discard,
|
||||
.stencilLoadOp = WGPULoadOp_Load,
|
||||
.stencilStoreOp = WGPUStoreOp_Discard
|
||||
};
|
||||
const WGPURenderPassColorAttachment colorAttachment {
|
||||
.view = dstView,
|
||||
|
@ -274,15 +315,56 @@ void WgCompositor::blit(WgContext& context, WGPUCommandEncoder encoder, WgRender
|
|||
.storeOp = WGPUStoreOp_Store,
|
||||
};
|
||||
const WGPURenderPassDescriptor renderPassDesc{ .colorAttachmentCount = 1, .colorAttachments = &colorAttachment, .depthStencilAttachment = &depthStencilAttachment };
|
||||
WGPURenderPassEncoder renderPass = wgpuCommandEncoderBeginRenderPass(encoder, &renderPassDesc);
|
||||
wgpuRenderPassEncoderSetBindGroup(renderPass, 0, src->bindGroupTexure, 0, nullptr);
|
||||
wgpuRenderPassEncoderSetPipeline(renderPass, pipelines.blit);
|
||||
meshData.drawImage(context, renderPass);
|
||||
wgpuRenderPassEncoderEnd(renderPass);
|
||||
wgpuRenderPassEncoderRelease(renderPass);
|
||||
renderPassEncoder = wgpuCommandEncoderBeginRenderPass(encoder, &renderPassDesc);
|
||||
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 0, src->bindGroupTexure, 0, nullptr);
|
||||
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.blit);
|
||||
drawMeshImage(context, &meshDataBlit);
|
||||
wgpuRenderPassEncoderEnd(renderPassEncoder);
|
||||
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)
|
||||
{
|
||||
assert(renderData);
|
||||
|
@ -298,7 +380,7 @@ void WgCompositor::drawShape(WgContext& context, WgRenderDataShape* renderData)
|
|||
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, stencilPipeline);
|
||||
// draw to stencil (first pass)
|
||||
ARRAY_FOREACH(p, renderData->meshGroupShapes.meshes)
|
||||
(*p)->drawFan(context, renderPassEncoder);
|
||||
drawMeshFan(context, (*p));
|
||||
// setup fill rules
|
||||
wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0);
|
||||
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 0, bindGroupViewMat, 0, nullptr);
|
||||
|
@ -315,7 +397,7 @@ void WgCompositor::drawShape(WgContext& context, WgRenderDataShape* renderData)
|
|||
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.radial);
|
||||
}
|
||||
// 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(renderData->meshGroupShapes.meshes.count == renderData->meshGroupShapesBBox.meshes.count);
|
||||
if (renderData->renderSettingsShape.skip || renderData->meshGroupShapes.meshes.count == 0 || renderData->viewport.invalid()) return;
|
||||
// copy current render target data to dst storage
|
||||
WgRenderStorage *target = currentTarget;
|
||||
// copy current render target data to dst target
|
||||
WgRenderTarget *target = currentTarget;
|
||||
endRenderPass();
|
||||
copyTexture(&storageTemp0, target);
|
||||
copyTexture(&targetTemp0, target);
|
||||
beginRenderPass(commandEncoder, target, false);
|
||||
// render shape with blend settings
|
||||
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);
|
||||
// draw to stencil (first pass)
|
||||
ARRAY_FOREACH(p, renderData->meshGroupShapes.meshes)
|
||||
(*p)->drawFan(context, renderPassEncoder);
|
||||
drawMeshFan(context, (*p));
|
||||
// setup fill rules
|
||||
wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0);
|
||||
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 0, bindGroupViewMat, 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;
|
||||
WgRenderSettings& settings = renderData->renderSettingsShape;
|
||||
if (settings.fillType == WgRenderSettingsType::Solid) {
|
||||
|
@ -359,7 +441,7 @@ void WgCompositor::blendShape(WgContext& context, WgRenderDataShape* renderData,
|
|||
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.radial_blend[blendMethodInd]);
|
||||
}
|
||||
// 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);
|
||||
// draw to stencil (first pass)
|
||||
ARRAY_FOREACH(p, renderData->meshGroupShapes.meshes)
|
||||
(*p)->drawFan(context, renderPassEncoder);
|
||||
drawMeshFan(context, (*p));
|
||||
// merge depth and stencil buffer
|
||||
wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0);
|
||||
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, bindGroupOpacities[128], 0, nullptr);
|
||||
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.merge_depth_stencil);
|
||||
renderData->meshDataBBox.drawFan(context, renderPassEncoder);
|
||||
drawMeshFan(context, &renderData->meshDataBBox);
|
||||
// setup fill rules
|
||||
wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0);
|
||||
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 0, bindGroupViewMat, 0, nullptr);
|
||||
|
@ -401,7 +483,7 @@ void WgCompositor::clipShape(WgContext& context, WgRenderDataShape* renderData)
|
|||
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.radial);
|
||||
}
|
||||
// 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);
|
||||
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.direct);
|
||||
// draw to stencil (first pass)
|
||||
renderData->meshGroupStrokes.meshes[i]->draw(context, renderPassEncoder);
|
||||
drawMesh(context, renderData->meshGroupStrokes.meshes[i]);
|
||||
// setup fill rules
|
||||
wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0);
|
||||
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 0, bindGroupViewMat, 0, nullptr);
|
||||
|
@ -438,7 +520,7 @@ void WgCompositor::drawStrokes(WgContext& context, WgRenderDataShape* renderData
|
|||
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.radial);
|
||||
}
|
||||
// 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);
|
||||
if (renderData->renderSettingsStroke.skip || renderData->meshGroupStrokes.meshes.count == 0 || renderData->viewport.invalid()) return;
|
||||
|
||||
// copy current render target data to dst storage
|
||||
WgRenderStorage *target = currentTarget;
|
||||
// copy current render target data to dst target
|
||||
WgRenderTarget *target = currentTarget;
|
||||
endRenderPass();
|
||||
copyTexture(&storageTemp0, target);
|
||||
copyTexture(&targetTemp0, target);
|
||||
beginRenderPass(commandEncoder, target, false);
|
||||
wgpuRenderPassEncoderSetScissorRect(renderPassEncoder, renderData->viewport.x(), renderData->viewport.y(), renderData->viewport.w(), renderData->viewport.h());
|
||||
// draw strokes to stencil (first pass)
|
||||
|
@ -464,12 +546,12 @@ void WgCompositor::blendStrokes(WgContext& context, WgRenderDataShape* renderDat
|
|||
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, renderData->bindGroupPaint, 0, nullptr);
|
||||
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.direct);
|
||||
// draw to stencil (first pass)
|
||||
renderData->meshGroupStrokes.meshes[i]->draw(context, renderPassEncoder);
|
||||
drawMesh(context, renderData->meshGroupStrokes.meshes[i]);
|
||||
// setup fill rules
|
||||
wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0);
|
||||
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 0, bindGroupViewMat, 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;
|
||||
WgRenderSettings& settings = renderData->renderSettingsStroke;
|
||||
if (settings.fillType == WgRenderSettingsType::Solid) {
|
||||
|
@ -483,7 +565,7 @@ void WgCompositor::blendStrokes(WgContext& context, WgRenderDataShape* renderDat
|
|||
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.radial_blend[blendMethodInd]);
|
||||
}
|
||||
// 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);
|
||||
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.direct);
|
||||
// draw to stencil (first pass)
|
||||
renderData->meshGroupStrokes.meshes[i]->draw(context, renderPassEncoder);
|
||||
drawMesh(context, renderData->meshGroupStrokes.meshes[i]);
|
||||
// merge depth and stencil buffer
|
||||
wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0);
|
||||
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, bindGroupOpacities[128], 0, nullptr);
|
||||
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.merge_depth_stencil);
|
||||
renderData->meshDataBBox.drawFan(context, renderPassEncoder);
|
||||
drawMeshFan(context, &renderData->meshDataBBox);
|
||||
// setup fill rules
|
||||
wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0);
|
||||
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 0, bindGroupViewMat, 0, nullptr);
|
||||
|
@ -527,7 +609,7 @@ void WgCompositor::clipStrokes(WgContext& context, WgRenderDataShape* renderData
|
|||
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.radial);
|
||||
}
|
||||
// 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, 1, renderData->bindGroupPaint, 0, nullptr);
|
||||
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.direct);
|
||||
renderData->meshData.drawImage(context, renderPassEncoder);
|
||||
drawMeshImage(context, &renderData->meshData);
|
||||
// draw image
|
||||
wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0);
|
||||
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 0, bindGroupViewMat, 0, nullptr);
|
||||
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, renderData->bindGroupPaint, 0, nullptr);
|
||||
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, renderData->bindGroupPicture, 0, nullptr);
|
||||
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);
|
||||
if (renderData->viewport.invalid()) return;
|
||||
wgpuRenderPassEncoderSetScissorRect(renderPassEncoder, renderData->viewport.x(), renderData->viewport.y(), renderData->viewport.w(), renderData->viewport.h());
|
||||
// copy current render target data to dst storage
|
||||
WgRenderStorage *target = currentTarget;
|
||||
// copy current render target data to dst target
|
||||
WgRenderTarget *target = currentTarget;
|
||||
endRenderPass();
|
||||
copyTexture(&storageTemp0, target);
|
||||
copyTexture(&targetTemp0, target);
|
||||
beginRenderPass(commandEncoder, target, false);
|
||||
// setup stencil rules
|
||||
wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 255);
|
||||
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 0, bindGroupViewMat, 0, nullptr);
|
||||
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, renderData->bindGroupPaint, 0, nullptr);
|
||||
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.direct);
|
||||
renderData->meshData.drawImage(context, renderPassEncoder);
|
||||
drawMeshImage(context, &renderData->meshData);
|
||||
// blend image
|
||||
uint32_t blendMethodInd = (uint32_t)blendMethod;
|
||||
wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0);
|
||||
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 0, bindGroupViewMat, 0, nullptr);
|
||||
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, renderData->bindGroupPaint, 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]);
|
||||
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, 1, renderData->bindGroupPaint, 0, nullptr);
|
||||
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.direct);
|
||||
renderData->meshData.drawImage(context, renderPassEncoder);
|
||||
drawMeshImage(context, &renderData->meshData);
|
||||
// merge depth and stencil buffer
|
||||
wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0);
|
||||
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, bindGroupOpacities[128], 0, nullptr);
|
||||
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.merge_depth_stencil);
|
||||
renderData->meshData.drawImage(context, renderPassEncoder);
|
||||
drawMeshImage(context, &renderData->meshData);
|
||||
// draw image
|
||||
wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0);
|
||||
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 0, bindGroupViewMat, 0, nullptr);
|
||||
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, renderData->bindGroupPaint, 0, nullptr);
|
||||
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, renderData->bindGroupPicture, 0, nullptr);
|
||||
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(compose);
|
||||
|
@ -622,19 +704,19 @@ void WgCompositor::drawScene(WgContext& context, WgRenderStorage* scene, WgCompo
|
|||
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 0, scene->bindGroupTexure, 0, nullptr);
|
||||
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, bindGroupOpacities[compose->opacity], 0, nullptr);
|
||||
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(compose);
|
||||
assert(currentTarget);
|
||||
// copy current render target data to dst storage
|
||||
WgRenderStorage *target = currentTarget;
|
||||
// copy current render target data to dst target
|
||||
WgRenderTarget *target = currentTarget;
|
||||
endRenderPass();
|
||||
copyTexture(&storageTemp0, target);
|
||||
copyTexture(&targetTemp0, target);
|
||||
beginRenderPass(commandEncoder, target, false);
|
||||
// blend scene
|
||||
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());
|
||||
wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0);
|
||||
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);
|
||||
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);
|
||||
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.direct);
|
||||
ARRAY_FOREACH(p, renderData->meshGroupStrokes.meshes)
|
||||
(*p)->draw(context, renderPassEncoder);
|
||||
drawMesh(context, (*p));
|
||||
} else {
|
||||
WGPURenderPipeline stencilPipeline = (renderData->fillRule == FillRule::NonZero) ? pipelines.nonzero : pipelines.evenodd;
|
||||
wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0);
|
||||
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, stencilPipeline);
|
||||
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, 2, bindGroupOpacities[128], 0, nullptr);
|
||||
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.copy_stencil_to_depth);
|
||||
renderData0->meshDataBBox.drawFan(context, renderPassEncoder);
|
||||
drawMeshFan(context, &renderData0->meshDataBBox);
|
||||
// merge clip pathes with AND logic
|
||||
for (auto p = paint->clips.begin() + 1; p < paint->clips.end(); ++p) {
|
||||
// get render data
|
||||
|
@ -698,31 +780,31 @@ void WgCompositor::renderClipPath(WgContext& context, WgRenderDataPaint* paint)
|
|||
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, renderData->bindGroupPaint, 0, nullptr);
|
||||
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, bindGroupOpacities[190], 0, nullptr);
|
||||
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.copy_stencil_to_depth_interm);
|
||||
renderData->meshDataBBox.drawFan(context, renderPassEncoder);
|
||||
drawMeshFan(context, &renderData->meshDataBBox);
|
||||
// copy depth to stencil
|
||||
wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 1);
|
||||
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, renderData->bindGroupPaint, 0, nullptr);
|
||||
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, bindGroupOpacities[190], 0, nullptr);
|
||||
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.copy_depth_to_stencil);
|
||||
renderData->meshDataBBox.drawFan(context, renderPassEncoder);
|
||||
drawMeshFan(context, &renderData->meshDataBBox);
|
||||
// clear depth current (keep stencil)
|
||||
wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0);
|
||||
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, renderData->bindGroupPaint, 0, nullptr);
|
||||
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, bindGroupOpacities[255], 0, nullptr);
|
||||
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.clear_depth);
|
||||
renderData->meshDataBBox.drawFan(context, renderPassEncoder);
|
||||
drawMeshFan(context, &renderData->meshDataBBox);
|
||||
// clear depth original (keep stencil)
|
||||
wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0);
|
||||
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, renderData0->bindGroupPaint, 0, nullptr);
|
||||
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, bindGroupOpacities[255], 0, nullptr);
|
||||
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.clear_depth);
|
||||
renderData0->meshDataBBox.drawFan(context, renderPassEncoder);
|
||||
drawMeshFan(context, &renderData0->meshDataBBox);
|
||||
// copy stencil to depth (clear stencil)
|
||||
wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0);
|
||||
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, renderData->bindGroupPaint, 0, nullptr);
|
||||
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, bindGroupOpacities[128], 0, nullptr);
|
||||
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, 2, bindGroupOpacities[255], 0, nullptr);
|
||||
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(params);
|
||||
|
@ -758,8 +840,8 @@ bool WgCompositor::gaussianBlur(WgContext& context, WgRenderStorage* dst, const
|
|||
auto renderData = (WgRenderDataEffectParams*)params->rd;
|
||||
auto aabb = compose->aabb;
|
||||
auto viewport = compose->rdViewport;
|
||||
WgRenderStorage* sbuff = dst;
|
||||
WgRenderStorage* dbuff = &storageTemp0;
|
||||
WgRenderTarget* sbuff = dst;
|
||||
WgRenderTarget* dbuff = &targetTemp0;
|
||||
|
||||
// begin compute pass
|
||||
WGPUComputePassDescriptor computePassDesc{ .label = "Compute pass gaussian blur" };
|
||||
|
@ -791,14 +873,14 @@ bool WgCompositor::gaussianBlur(WgContext& context, WgRenderStorage* dst, const
|
|||
wgpuComputePassEncoderRelease(computePassEncoder);
|
||||
|
||||
// if final result stored in intermidiate buffer we must copy result to destination buffer
|
||||
if (sbuff == &storageTemp0)
|
||||
if (sbuff == &targetTemp0)
|
||||
copyTexture(sbuff, dbuff, aabb);
|
||||
|
||||
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(params);
|
||||
|
@ -811,9 +893,9 @@ bool WgCompositor::dropShadow(WgContext& context, WgRenderStorage* dst, const Re
|
|||
auto viewport = compose->rdViewport;
|
||||
|
||||
{ // apply blur
|
||||
copyTexture(&storageTemp1, dst, aabb);
|
||||
WgRenderStorage* sbuff = &storageTemp1;
|
||||
WgRenderStorage* dbuff = &storageTemp0;
|
||||
copyTexture(&targetTemp1, dst, aabb);
|
||||
WgRenderTarget* sbuff = &targetTemp1;
|
||||
WgRenderTarget* dbuff = &targetTemp0;
|
||||
WGPUComputePassDescriptor computePassDesc{ .label = "Compute pass drop shadow blur" };
|
||||
WGPUComputePassEncoder computePassEncoder = wgpuCommandEncoderBeginComputePass(commandEncoder, &computePassDesc);
|
||||
// horizontal blur
|
||||
|
@ -837,7 +919,7 @@ bool WgCompositor::dropShadow(WgContext& context, WgRenderStorage* dst, const Re
|
|||
}
|
||||
|
||||
{ // blend origin (temp0), shadow (temp1) to destination
|
||||
copyTexture(&storageTemp0, dst, aabb);
|
||||
copyTexture(&targetTemp0, dst, aabb);
|
||||
WGPUComputePassDescriptor computePassDesc{ .label = "Compute pass drop shadow blend" };
|
||||
WGPUComputePassEncoder computePassEncoder = wgpuCommandEncoderBeginComputePass(commandEncoder, &computePassDesc);
|
||||
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(params);
|
||||
|
@ -862,7 +944,7 @@ bool WgCompositor::fillEffect(WgContext& context, WgRenderStorage* dst, const Re
|
|||
assert(compose->rdViewport);
|
||||
assert(!renderPassEncoder);
|
||||
|
||||
copyTexture(&storageTemp0, dst, compose->aabb);
|
||||
copyTexture(&targetTemp0, dst, compose->aabb);
|
||||
WGPUComputePassDescriptor computePassDesc{ .label = "Compute pass fill" };
|
||||
WGPUComputePassEncoder computePassEncoder = wgpuCommandEncoderBeginComputePass(commandEncoder, &computePassDesc);
|
||||
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(params);
|
||||
|
@ -886,7 +968,7 @@ bool WgCompositor::tintEffect(WgContext& context, WgRenderStorage* dst, const Re
|
|||
assert(compose->rdViewport);
|
||||
assert(!renderPassEncoder);
|
||||
|
||||
copyTexture(&storageTemp0, dst, compose->aabb);
|
||||
copyTexture(&targetTemp0, dst, compose->aabb);
|
||||
WGPUComputePassDescriptor computePassDesc{ .label = "Compute pass tint" };
|
||||
WGPUComputePassEncoder computePassEncoder = wgpuCommandEncoderBeginComputePass(commandEncoder, &computePassDesc);
|
||||
wgpuComputePassEncoderSetBindGroup(computePassEncoder, 0, bindGroupStorageTemp, 0, nullptr);
|
||||
|
@ -901,7 +983,7 @@ bool WgCompositor::tintEffect(WgContext& context, WgRenderStorage* dst, const Re
|
|||
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(params);
|
||||
|
@ -909,7 +991,7 @@ bool WgCompositor::tritoneEffect(WgContext& context, WgRenderStorage* dst, const
|
|||
assert(compose->rdViewport);
|
||||
assert(!renderPassEncoder);
|
||||
|
||||
copyTexture(&storageTemp0, dst, compose->aabb);
|
||||
copyTexture(&targetTemp0, dst, compose->aabb);
|
||||
WGPUComputePassDescriptor computePassDesc{ .label = "Compute pass tritone" };
|
||||
WGPUComputePassEncoder computePassEncoder = wgpuCommandEncoderBeginComputePass(commandEncoder, &computePassDesc);
|
||||
wgpuComputePassEncoderSetBindGroup(computePassEncoder, 0, bindGroupStorageTemp, 0, nullptr);
|
||||
|
|
|
@ -38,6 +38,8 @@ class WgCompositor
|
|||
private:
|
||||
// pipelines
|
||||
WgPipelines pipelines{};
|
||||
// stage buffers
|
||||
WgRenderDataStageBuffer stageBuffer{};
|
||||
// global stencil/depth buffer handles
|
||||
WGPUTexture texDepthStencil{};
|
||||
WGPUTextureView texViewDepthStencil{};
|
||||
|
@ -52,21 +54,26 @@ private:
|
|||
// current render pass handles
|
||||
WGPURenderPassEncoder renderPassEncoder{};
|
||||
WGPUCommandEncoder commandEncoder{};
|
||||
WgRenderStorage* currentTarget{};
|
||||
// intermediate render storages
|
||||
WgRenderStorage storageTemp0;
|
||||
WgRenderStorage storageTemp1;
|
||||
WgRenderTarget* currentTarget{};
|
||||
// intermediate render targets
|
||||
WgRenderTarget targetTemp0;
|
||||
WgRenderTarget targetTemp1;
|
||||
WGPUBindGroup bindGroupStorageTemp{};
|
||||
// composition and blend geometries
|
||||
WgMeshData meshData;
|
||||
WgMeshData meshDataBlit;
|
||||
// render target dimensions
|
||||
uint32_t width{};
|
||||
uint32_t height{};
|
||||
|
||||
// viewport utilities
|
||||
RenderRegion shrinkRenderRegion(RenderRegion& rect);
|
||||
void copyTexture(const WgRenderStorage* dst, const WgRenderStorage* src);
|
||||
void copyTexture(const WgRenderStorage* dst, const WgRenderStorage* src, const RenderRegion& region);
|
||||
void copyTexture(const WgRenderTarget* dst, const WgRenderTarget* src);
|
||||
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
|
||||
void drawShape(WgContext& context, WgRenderDataShape* renderData);
|
||||
|
@ -84,8 +91,8 @@ private:
|
|||
void clipImage(WgContext& context, WgRenderDataPicture* renderData);
|
||||
|
||||
// scenes
|
||||
void drawScene(WgContext& context, WgRenderStorage* scene, WgCompose* compose);
|
||||
void blendScene(WgContext& context, WgRenderStorage* src, WgCompose* compose);
|
||||
void drawScene(WgContext& context, WgRenderTarget* scene, WgCompose* compose);
|
||||
void blendScene(WgContext& context, WgRenderTarget* src, WgCompose* compose);
|
||||
|
||||
// the renderer prioritizes clipping with the stroke over the shape's fill
|
||||
void markupClipPath(WgContext& context, WgRenderDataShape* renderData);
|
||||
|
@ -100,24 +107,32 @@ public:
|
|||
void resize(WgContext& context, uint32_t width, uint32_t height);
|
||||
|
||||
// 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();
|
||||
|
||||
// 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
|
||||
void renderShape(WgContext& context, WgRenderDataShape* renderData, BlendMethod blendMethod);
|
||||
void renderImage(WgContext& context, WgRenderDataPicture* renderData, BlendMethod blendMethod);
|
||||
void renderScene(WgContext& context, WgRenderStorage* scene, WgCompose* compose);
|
||||
void composeScene(WgContext& context, WgRenderStorage* src, WgRenderStorage* mask, WgCompose* compose);
|
||||
void renderScene(WgContext& context, WgRenderTarget* scene, WgCompose* compose);
|
||||
void composeScene(WgContext& context, WgRenderTarget* src, WgRenderTarget* mask, WgCompose* compose);
|
||||
|
||||
// blit render storage to texture view (f.e. screen buffer)
|
||||
void blit(WgContext& context, WGPUCommandEncoder encoder, WgRenderStorage* src, WGPUTextureView dstView);
|
||||
// blit render target to texture view (f.e. screen buffer)
|
||||
void blit(WgContext& context, WGPUCommandEncoder encoder, WgRenderTarget* src, WGPUTextureView dstView);
|
||||
|
||||
// effects
|
||||
bool gaussianBlur(WgContext& context, WgRenderStorage* dst, const RenderEffectGaussianBlur* params, const WgCompose* compose);
|
||||
bool dropShadow(WgContext& context, WgRenderStorage* dst, const RenderEffectDropShadow* params, const WgCompose* compose);
|
||||
bool fillEffect(WgContext& context, WgRenderStorage* dst, const RenderEffectFill* params, const WgCompose* compose);
|
||||
bool tintEffect(WgContext& context, WgRenderStorage* dst, const RenderEffectTint* params, const WgCompose* compose);
|
||||
bool tritoneEffect(WgContext& context, WgRenderStorage* dst, const RenderEffectTritone* params, const WgCompose* compose);
|
||||
bool gaussianBlur(WgContext& context, WgRenderTarget* dst, const RenderEffectGaussianBlur* params, const WgCompose* compose);
|
||||
bool dropShadow(WgContext& context, WgRenderTarget* dst, const RenderEffectDropShadow* params, const WgCompose* compose);
|
||||
bool fillEffect(WgContext& context, WgRenderTarget* dst, const RenderEffectFill* params, const WgCompose* compose);
|
||||
bool tintEffect(WgContext& context, WgRenderTarget* dst, const RenderEffectTint* params, const WgCompose* compose);
|
||||
bool tritoneEffect(WgContext& context, WgRenderTarget* dst, const RenderEffectTritone* params, const WgCompose* compose);
|
||||
};
|
||||
|
||||
#endif // _TVG_WG_COMPOSITOR_H_
|
||||
|
|
|
@ -30,95 +30,88 @@
|
|||
// 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)
|
||||
{
|
||||
assert(vertexBuffer.count > 2);
|
||||
vertexCount = vertexBuffer.count;
|
||||
indexCount = (vertexBuffer.count - 2) * 3;
|
||||
context.allocateBufferVertex(bufferPosition, (float*)vertexBuffer.data, vertexCount * sizeof(float) * 2);
|
||||
context.allocateBufferIndexFan(vertexCount);
|
||||
// setup vertex data
|
||||
vbuffer.reserve(vertexBuffer.count);
|
||||
vbuffer.count = vertexBuffer.count;
|
||||
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)
|
||||
{
|
||||
assert(vertexBufferInd.vcount > 2);
|
||||
vertexCount = vertexBufferInd.vcount;
|
||||
indexCount = vertexBufferInd.icount;
|
||||
if (vertexCount > 0) context.allocateBufferVertex(bufferPosition, (float*)vertexBufferInd.vbuff, vertexCount * sizeof(float) * 2);
|
||||
if (indexCount > 0) context.allocateBufferIndex(bufferIndex, vertexBufferInd.ibuff, indexCount * sizeof(uint32_t));
|
||||
// setup vertex data
|
||||
vbuffer.reserve(vertexBufferInd.vcount);
|
||||
vbuffer.count = vertexBufferInd.vcount;
|
||||
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)
|
||||
{
|
||||
vertexCount = 4;
|
||||
indexCount = 6;
|
||||
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));
|
||||
context.allocateBufferIndexFan(vertexCount);
|
||||
// setup vertex data
|
||||
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)
|
||||
{
|
||||
vertexCount = 4;
|
||||
indexCount = 6;
|
||||
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 uint32_t idata[] = {0, 1, 2, 0, 2, 3};
|
||||
context.allocateBufferVertex(bufferPosition, vdata, sizeof(vdata));
|
||||
context.allocateBufferVertex(bufferTexCoord, tdata, sizeof(tdata));
|
||||
context.allocateBufferIndex(bufferIndex, idata, sizeof(idata));
|
||||
// setup vertex data
|
||||
vbuffer.reserve(4);
|
||||
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)
|
||||
{
|
||||
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 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 };
|
||||
context.allocateBufferVertex(bufferPosition, vdata, sizeof(vdata));
|
||||
context.allocateBufferVertex(bufferTexCoord, tdata, sizeof(tdata));
|
||||
context.allocateBufferIndex(bufferIndex, idata, sizeof(idata));
|
||||
// setup vertex data
|
||||
vbuffer.reserve(4);
|
||||
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
|
||||
//***********************************************************************
|
||||
|
@ -681,3 +674,94 @@ void WgRenderDataEffectParamsPool::release(WgContext& context)
|
|||
mPool.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);
|
||||
}
|
||||
|
|
|
@ -28,22 +28,19 @@
|
|||
#include "tvgWgShaderTypes.h"
|
||||
|
||||
struct WgMeshData {
|
||||
WGPUBuffer bufferPosition{};
|
||||
WGPUBuffer bufferTexCoord{};
|
||||
WGPUBuffer bufferIndex{};
|
||||
size_t vertexCount{};
|
||||
size_t indexCount{};
|
||||
|
||||
void draw(WgContext& context, WGPURenderPassEncoder renderPassEncoder);
|
||||
void drawFan(WgContext& context, WGPURenderPassEncoder renderPassEncoder);
|
||||
void drawImage(WgContext& context, WGPURenderPassEncoder renderPassEncoder);
|
||||
Array<Point> vbuffer;
|
||||
Array<Point> tbuffer;
|
||||
Array<uint32_t> ibuffer;
|
||||
size_t voffset{};
|
||||
size_t toffset{};
|
||||
size_t ioffset{};
|
||||
|
||||
void update(WgContext& context, const WgVertexBuffer& vertexBuffer);
|
||||
void update(WgContext& context, const WgIndexedVertexBuffer& vertexBufferInd);
|
||||
void bbox(WgContext& context, const Point pmin, const Point pmax);
|
||||
void imageBox(WgContext& context, float w, float h);
|
||||
void blitBox(WgContext& context);
|
||||
void release(WgContext& context);
|
||||
void release(WgContext& context) {};
|
||||
};
|
||||
|
||||
class WgMeshDataPool {
|
||||
|
@ -224,4 +221,23 @@ public:
|
|||
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_
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
|
||||
#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->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(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) {
|
||||
renderStorage = pool.last();
|
||||
renderTarget = pool.last();
|
||||
pool.pop();
|
||||
} else {
|
||||
renderStorage = new WgRenderStorage;
|
||||
renderStorage->initialize(context, width, height);
|
||||
list.push(renderStorage);
|
||||
renderTarget = new WgRenderTarget;
|
||||
renderTarget->initialize(context, width, height);
|
||||
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->height = height;
|
||||
}
|
||||
|
||||
|
||||
void WgRenderStoragePool::release(WgContext& context)
|
||||
void WgRenderTargetPool::release(WgContext& context)
|
||||
{
|
||||
ARRAY_FOREACH(p, list) {
|
||||
(*p)->release(context);
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
#include "tvgWgPipelines.h"
|
||||
#include "tvgRender.h"
|
||||
|
||||
struct WgRenderStorage {
|
||||
struct WgRenderTarget {
|
||||
WGPUTexture texture{};
|
||||
WGPUTexture textureMS{};
|
||||
WGPUTextureView texView{};
|
||||
|
@ -42,15 +42,15 @@ struct WgRenderStorage {
|
|||
};
|
||||
|
||||
|
||||
class WgRenderStoragePool {
|
||||
class WgRenderTargetPool {
|
||||
private:
|
||||
Array<WgRenderStorage*> list;
|
||||
Array<WgRenderStorage*> pool;
|
||||
Array<WgRenderTarget*> list;
|
||||
Array<WgRenderTarget*> pool;
|
||||
uint32_t width{};
|
||||
uint32_t height{};
|
||||
public:
|
||||
WgRenderStorage* allocate(WgContext& context);
|
||||
void free(WgContext& context, WgRenderStorage* renderTarget);
|
||||
WgRenderTarget* allocate(WgContext& context);
|
||||
void free(WgContext& context, WgRenderTarget* renderTarget);
|
||||
|
||||
void initialize(WgContext& context, uint32_t width, uint32_t height);
|
||||
void release(WgContext& context);
|
||||
|
|
93
src/renderer/wg_engine/tvgWgRenderTask.cpp
Normal file
93
src/renderer/wg_engine/tvgWgRenderTask.cpp
Normal 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;
|
||||
}
|
||||
}
|
72
src/renderer/wg_engine/tvgWgRenderTask.h
Normal file
72
src/renderer/wg_engine/tvgWgRenderTask.h
Normal 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_
|
||||
|
|
@ -47,13 +47,13 @@ void WgRenderer::release()
|
|||
mRenderDataEffectParamsPool.release(mContext);
|
||||
WgMeshDataPool::gMeshDataPool->release(mContext);
|
||||
|
||||
// clear render storage pool
|
||||
mRenderStoragePool.release(mContext);
|
||||
// clear render pool
|
||||
mRenderTargetPool.release(mContext);
|
||||
|
||||
// clear rendering tree stacks
|
||||
mCompositorStack.clear();
|
||||
mRenderStorageStack.clear();
|
||||
mRenderStorageRoot.release(mContext);
|
||||
mCompositorList.clear();
|
||||
mRenderTargetStack.clear();
|
||||
mRenderTargetRoot.release(mContext);
|
||||
|
||||
// release context handles
|
||||
mCompositor.release(mContext);
|
||||
|
@ -195,50 +195,71 @@ RenderData WgRenderer::prepare(RenderSurface* surface, RenderData data, const Ma
|
|||
|
||||
bool WgRenderer::preRender()
|
||||
{
|
||||
// invalidate context
|
||||
if (mContext.invalid()) return false;
|
||||
|
||||
// push rot render storage to the render tree stack
|
||||
assert(mRenderStorageStack.count == 0);
|
||||
mRenderStorageStack.push(&mRenderStorageRoot);
|
||||
// create command encoder for drawing
|
||||
WGPUCommandEncoderDescriptor commandEncoderDesc{};
|
||||
mCommandEncoder = wgpuDeviceCreateCommandEncoder(mContext.device, &commandEncoderDesc);
|
||||
// start root render pass
|
||||
mCompositor.beginRenderPass(mCommandEncoder, mRenderStorageStack.last(), true);
|
||||
// reset stage data
|
||||
mCompositor.reset(mContext);
|
||||
// push root render target to the render tree stack
|
||||
assert(mRenderTargetStack.count == 0);
|
||||
mRenderTargetStack.push(&mRenderTargetRoot);
|
||||
// create root compose settings
|
||||
WgCompose* compose = new WgCompose();
|
||||
compose->aabb = { { 0, 0 }, { (int32_t)mTargetSurface.w, (int32_t)mTargetSurface.h } };
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
bool WgRenderer::renderShape(RenderData data)
|
||||
{
|
||||
// temporary simple render data to the current render target
|
||||
mCompositor.renderShape(mContext, (WgRenderDataShape*)data, mBlendMethod);
|
||||
WgPaintTask* paintTask = new WgPaintTask((WgRenderDataPaint*)data, mBlendMethod);
|
||||
WgSceneTask* sceneTask = mSceneTaskStack.last();
|
||||
sceneTask->children.push(paintTask);
|
||||
mRenderTaskList.push(paintTask);
|
||||
mCompositor.requestShape((WgRenderDataShape*)data);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool WgRenderer::renderImage(RenderData data)
|
||||
{
|
||||
// temporary simple render data to the current render target
|
||||
mCompositor.renderImage(mContext, (WgRenderDataPicture*)data, mBlendMethod);
|
||||
WgPaintTask* paintTask = new WgPaintTask((WgRenderDataPaint*)data, mBlendMethod);
|
||||
WgSceneTask* sceneTask = mSceneTaskStack.last();
|
||||
sceneTask->children.push(paintTask);
|
||||
mRenderTaskList.push(paintTask);
|
||||
mCompositor.requestImage((WgRenderDataPicture*)data);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool WgRenderer::postRender()
|
||||
{
|
||||
// end root render pass
|
||||
mCompositor.endRenderPass();
|
||||
// release command encoder
|
||||
const WGPUCommandBufferDescriptor commandBufferDesc{};
|
||||
WGPUCommandBuffer commandsBuffer = wgpuCommandEncoderFinish(mCommandEncoder, &commandBufferDesc);
|
||||
wgpuQueueSubmit(mContext.queue, 1, &commandsBuffer);
|
||||
wgpuCommandBufferRelease(commandsBuffer);
|
||||
wgpuCommandEncoderRelease(mCommandEncoder);
|
||||
// pop root render storage to the render tree stack
|
||||
mRenderStorageStack.pop();
|
||||
assert(mRenderStorageStack.count == 0);
|
||||
// clear viewport list and store allocated handles to pool
|
||||
// flush stage data to gpu
|
||||
mCompositor.flush(mContext);
|
||||
// create command encoder for drawing
|
||||
WGPUCommandEncoder commandEncoder = mContext.createCommandEncoder();
|
||||
// run rendering (all the fun is here)
|
||||
WgSceneTask* sceneTaskRoot = mSceneTaskStack.last();
|
||||
sceneTaskRoot->run(mContext, mCompositor, commandEncoder);
|
||||
// execute and release command encoder
|
||||
mContext.submitCommandEncoder(commandEncoder);
|
||||
mContext.releaseCommandEncoder(commandEncoder);
|
||||
// clear the render tasks tree
|
||||
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)
|
||||
mRenderDataViewportPool.free(mContext, *p);
|
||||
mRenderDataViewportList.clear();
|
||||
|
@ -325,18 +346,11 @@ bool WgRenderer::sync()
|
|||
WGPUTextureView dstTextureView = mContext.createTextureView(dstTexture);
|
||||
|
||||
// create command encoder
|
||||
const WGPUCommandEncoderDescriptor commandEncoderDesc{};
|
||||
WGPUCommandEncoder commandEncoder = wgpuDeviceCreateCommandEncoder(mContext.device, &commandEncoderDesc);
|
||||
|
||||
WGPUCommandEncoder commandEncoder = mContext.createCommandEncoder();
|
||||
// show root offscreen buffer
|
||||
mCompositor.blit(mContext, commandEncoder, &mRenderStorageRoot, dstTextureView);
|
||||
|
||||
// release command encoder
|
||||
const WGPUCommandBufferDescriptor commandBufferDesc{};
|
||||
WGPUCommandBuffer commandsBuffer = wgpuCommandEncoderFinish(commandEncoder, &commandBufferDesc);
|
||||
wgpuQueueSubmit(mContext.queue, 1, &commandsBuffer);
|
||||
wgpuCommandBufferRelease(commandsBuffer);
|
||||
wgpuCommandEncoderRelease(commandEncoder);
|
||||
mCompositor.blit(mContext, commandEncoder, &mRenderTargetRoot, dstTextureView);
|
||||
mContext.submitCommandEncoder(commandEncoder);
|
||||
mContext.releaseCommandEncoder(commandEncoder);
|
||||
|
||||
// release dest buffer view
|
||||
mContext.releaseTextureView(dstTextureView);
|
||||
|
@ -367,8 +381,8 @@ bool WgRenderer::target(WGPUDevice device, WGPUInstance instance, void* target,
|
|||
mContext.initialize(instance, device);
|
||||
|
||||
// initialize render tree instances
|
||||
mRenderStoragePool.initialize(mContext, width, height);
|
||||
mRenderStorageRoot.initialize(mContext, width, height);
|
||||
mRenderTargetPool.initialize(mContext, width, height);
|
||||
mRenderTargetRoot.initialize(mContext, width, height);
|
||||
mCompositor.initialize(mContext, width, height);
|
||||
|
||||
// store target properties
|
||||
|
@ -387,12 +401,12 @@ bool WgRenderer::target(WGPUDevice device, WGPUInstance instance, void* target,
|
|||
// update render targets dimentions
|
||||
if ((mTargetSurface.w != width) || (mTargetSurface.h != height) || (type == 0 ? (surface != (WGPUSurface)target) : (targetTexture != (WGPUTexture)target))) {
|
||||
// release render tagets
|
||||
mRenderStoragePool.release(mContext);
|
||||
mRenderStorageRoot.release(mContext);
|
||||
mRenderTargetPool.release(mContext);
|
||||
mRenderTargetRoot.release(mContext);
|
||||
clearTargets();
|
||||
|
||||
mRenderStoragePool.initialize(mContext, width, height);
|
||||
mRenderStorageRoot.initialize(mContext, width, height);
|
||||
mRenderTargetPool.initialize(mContext, width, height);
|
||||
mRenderTargetRoot.initialize(mContext, width, height);
|
||||
mCompositor.resize(mContext, width, height);
|
||||
|
||||
// store target properties
|
||||
|
@ -447,7 +461,7 @@ RenderCompositor* WgRenderer::target(const RenderRegion& region, TVG_UNUSED Colo
|
|||
compose->rdViewport->update(mContext, region);
|
||||
mRenderDataViewportList.push(compose->rdViewport);
|
||||
}
|
||||
mCompositorStack.push(compose);
|
||||
mCompositorList.push(compose);
|
||||
return compose;
|
||||
}
|
||||
|
||||
|
@ -459,57 +473,52 @@ bool WgRenderer::beginComposite(RenderCompositor* cmp, MaskMethod method, uint8_
|
|||
compose->method = method;
|
||||
compose->opacity = opacity;
|
||||
compose->blend = mBlendMethod;
|
||||
// end current render pass
|
||||
mCompositor.endRenderPass();
|
||||
// allocate new render storage and push to the render tree stack
|
||||
WgRenderStorage* storage = mRenderStoragePool.allocate(mContext);
|
||||
mRenderStorageStack.push(storage);
|
||||
// begin newly added render pass
|
||||
WGPUColor color{};
|
||||
if ((compose->method == MaskMethod::None) && (compose->blend != BlendMethod::Normal)) color = { 1.0, 1.0, 1.0, 0.0 };
|
||||
mCompositor.beginRenderPass(mCommandEncoder, mRenderStorageStack.last(), true, color);
|
||||
WgSceneTask* sceneTaskCurrent = mSceneTaskStack.last();
|
||||
// allocate new render target and push to the render tree stack
|
||||
WgRenderTarget* renderTarget = mRenderTargetPool.allocate(mContext);
|
||||
mRenderTargetStack.push(renderTarget);
|
||||
// create and setup new scene task
|
||||
WgSceneTask* sceneTask = new WgSceneTask(renderTarget, compose, sceneTaskCurrent);
|
||||
sceneTaskCurrent->children.push(sceneTask);
|
||||
mRenderTaskList.push(sceneTask);
|
||||
mSceneTaskStack.push(sceneTask);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
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
|
||||
if (comp->method == MaskMethod::None) {
|
||||
// get source and destination render storages
|
||||
WgRenderStorage* src = mRenderStorageStack.last();
|
||||
mRenderStorageStack.pop();
|
||||
WgRenderStorage* dst = mRenderStorageStack.last();
|
||||
// begin previous render pass
|
||||
mCompositor.beginRenderPass(mCommandEncoder, dst, false);
|
||||
// apply composition
|
||||
mCompositor.renderScene(mContext, src, comp);
|
||||
if (cmp->method == MaskMethod::None) {
|
||||
// get source and destination render targets
|
||||
WgRenderTarget* src = mRenderTargetStack.last();
|
||||
mRenderTargetStack.pop();
|
||||
// pop source scene
|
||||
WgSceneTask* srcScene = mSceneTaskStack.last();
|
||||
mSceneTaskStack.pop();
|
||||
// setup render target compose destitations
|
||||
srcScene->renderTargetDst = mSceneTaskStack.last()->renderTarget;
|
||||
srcScene->renderTargetMsk = nullptr;
|
||||
// back render targets to the pool
|
||||
mRenderStoragePool.free(mContext, src);
|
||||
} else { // finish composition
|
||||
// get source, mask and destination render storages
|
||||
WgRenderStorage* src = mRenderStorageStack.last();
|
||||
mRenderStorageStack.pop();
|
||||
WgRenderStorage* msk = mRenderStorageStack.last();
|
||||
mRenderStorageStack.pop();
|
||||
WgRenderStorage* dst = mRenderStorageStack.last();
|
||||
// begin previous render pass
|
||||
mCompositor.beginRenderPass(mCommandEncoder, dst, false);
|
||||
// apply composition
|
||||
mCompositor.composeScene(mContext, src, msk, comp);
|
||||
mRenderTargetPool.free(mContext, src);
|
||||
} else { // finish scene composition
|
||||
// get source, mask and destination render targets
|
||||
WgRenderTarget* src = mRenderTargetStack.last();
|
||||
mRenderTargetStack.pop();
|
||||
WgRenderTarget* msk = mRenderTargetStack.last();
|
||||
mRenderTargetStack.pop();
|
||||
// get source and mask scenes
|
||||
WgSceneTask* srcScene = mSceneTaskStack.last();
|
||||
mSceneTaskStack.pop();
|
||||
WgSceneTask* mskScene = mSceneTaskStack.last();
|
||||
mSceneTaskStack.pop();
|
||||
// setup render target compose destitations
|
||||
srcScene->renderTargetDst = mSceneTaskStack.last()->renderTarget;
|
||||
srcScene->renderTargetMsk = mskScene->renderTarget;
|
||||
// back render targets to the pool
|
||||
mRenderStoragePool.free(mContext, src);
|
||||
mRenderStoragePool.free(mContext, msk);
|
||||
mRenderTargetPool.free(mContext, src);
|
||||
mRenderTargetPool.free(mContext, msk);
|
||||
}
|
||||
|
||||
// delete current compositor settings
|
||||
delete mCompositorStack.last();
|
||||
mCompositorStack.pop();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -606,20 +615,8 @@ bool WgRenderer::region(RenderEffect* effect)
|
|||
|
||||
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
|
||||
mCompositor.endRenderPass();
|
||||
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;
|
||||
mSceneTaskStack.last()->effect = effect;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
#ifndef _TVG_WG_RENDERER_H_
|
||||
#define _TVG_WG_RENDERER_H_
|
||||
|
||||
#include "tvgWgCompositor.h"
|
||||
#include "tvgWgRenderTask.h"
|
||||
|
||||
class WgRenderer : public RenderMethod
|
||||
{
|
||||
|
@ -72,13 +72,15 @@ private:
|
|||
bool surfaceConfigure(WGPUSurface surface, WgContext& context, uint32_t width, uint32_t height);
|
||||
|
||||
// render tree stacks
|
||||
WgRenderStorage mRenderStorageRoot;
|
||||
Array<WgCompose*> mCompositorStack;
|
||||
Array<WgRenderStorage*> mRenderStorageStack;
|
||||
WgRenderTarget mRenderTargetRoot;
|
||||
Array<WgCompose*> mCompositorList;
|
||||
Array<WgRenderTarget*> mRenderTargetStack;
|
||||
Array<WgRenderDataViewport*> mRenderDataViewportList;
|
||||
Array<WgSceneTask*> mSceneTaskStack;
|
||||
Array<WgRenderTask*> mRenderTaskList;
|
||||
|
||||
// render storage pool
|
||||
WgRenderStoragePool mRenderStoragePool;
|
||||
// render target pool
|
||||
WgRenderTargetPool mRenderTargetPool;
|
||||
|
||||
// render data paint pools
|
||||
WgRenderDataShapePool mRenderDataShapePool;
|
||||
|
@ -100,7 +102,6 @@ private:
|
|||
Key mDisposeKey{};
|
||||
|
||||
// gpu handles
|
||||
WGPUCommandEncoder mCommandEncoder{};
|
||||
WGPUTexture targetTexture{}; // external handle
|
||||
WGPUSurfaceTexture surfaceTexture{};
|
||||
WGPUSurface surface{}; // external handle
|
||||
|
|
Loading…
Add table
Reference in a new issue