mirror of
https://github.com/thorvg/thorvg.git
synced 2025-06-07 21:23:32 +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',
|
'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'
|
||||||
]
|
]
|
||||||
|
|
|
@ -268,4 +268,35 @@ void WgContext::releaseQueue(WGPUQueue& queue)
|
||||||
wgpuQueueRelease(queue);
|
wgpuQueueRelease(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;
|
||||||
|
}
|
||||||
|
|
|
@ -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_
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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_
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
|
@ -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_
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
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);
|
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Add table
Reference in a new issue