wg_engine: uniform stage buffers implementation

Introduced stage buffer for uniforms to reduce number of memory shafles from cpu to gpu memory

https://github.com/thorvg/thorvg/issues/3505
This commit is contained in:
Sergii Liebodkin 2025-06-11 01:29:25 +03:00 committed by Hermet Park
parent 4c3c5d9d06
commit 92e3c243ec
11 changed files with 354 additions and 300 deletions

View file

@ -103,9 +103,15 @@ WGPUBindGroup WgBindGroupLayouts::createBindGroupStrorage3RO(WGPUTextureView tex
WGPUBindGroup WgBindGroupLayouts::createBindGroupBuffer1Un(WGPUBuffer buff) WGPUBindGroup WgBindGroupLayouts::createBindGroupBuffer1Un(WGPUBuffer buff)
{
return createBindGroupBuffer1Un(buff, 0, wgpuBufferGetSize(buff));
}
WGPUBindGroup WgBindGroupLayouts::createBindGroupBuffer1Un(WGPUBuffer buff, uint64_t offset, uint64_t size)
{ {
const WGPUBindGroupEntry bindGroupEntrys[] = { const WGPUBindGroupEntry bindGroupEntrys[] = {
{ .binding = 0, .buffer = buff, .size = wgpuBufferGetSize(buff) } { .binding = 0, .buffer = buff, .offset = offset, .size = size }
}; };
const WGPUBindGroupDescriptor bindGroupDesc { .layout = layoutBuffer1Un, .entryCount = 1, .entries = bindGroupEntrys }; const WGPUBindGroupDescriptor bindGroupDesc { .layout = layoutBuffer1Un, .entryCount = 1, .entries = bindGroupEntrys };
return wgpuDeviceCreateBindGroup(device, &bindGroupDesc); return wgpuDeviceCreateBindGroup(device, &bindGroupDesc);

View file

@ -49,6 +49,7 @@ public:
WGPUBindGroup createBindGroupStrorage2RO(WGPUTextureView texView0, WGPUTextureView texView1); WGPUBindGroup createBindGroupStrorage2RO(WGPUTextureView texView0, WGPUTextureView texView1);
WGPUBindGroup createBindGroupStrorage3RO(WGPUTextureView texView0, WGPUTextureView texView1, WGPUTextureView texView2); WGPUBindGroup createBindGroupStrorage3RO(WGPUTextureView texView0, WGPUTextureView texView1, WGPUTextureView texView2);
WGPUBindGroup createBindGroupBuffer1Un(WGPUBuffer buff); WGPUBindGroup createBindGroupBuffer1Un(WGPUBuffer buff);
WGPUBindGroup createBindGroupBuffer1Un(WGPUBuffer buff, uint64_t offset, uint64_t size);
WGPUBindGroup createBindGroupBuffer2Un(WGPUBuffer buff0, WGPUBuffer buff1); WGPUBindGroup createBindGroupBuffer2Un(WGPUBuffer buff0, WGPUBuffer buff1);
WGPUBindGroup createBindGroupBuffer3Un(WGPUBuffer buff0, WGPUBuffer buff1, WGPUBuffer buff2); WGPUBindGroup createBindGroupBuffer3Un(WGPUBuffer buff0, WGPUBuffer buff1, WGPUBuffer buff2);
void releaseBindGroup(WGPUBindGroup& bindGroup); void releaseBindGroup(WGPUBindGroup& bindGroup);

View file

@ -28,7 +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); stageBufferGeometry.initialize(context);
// initialize opacity pool // initialize opacity pool
initPools(context); initPools(context);
// allocate global view matrix handles // allocate global view matrix handles
@ -64,7 +64,8 @@ void WgCompositor::release(WgContext& context)
context.layouts.releaseBindGroup(bindGroupViewMat); context.layouts.releaseBindGroup(bindGroupViewMat);
context.releaseBuffer(bufferViewMat); context.releaseBuffer(bufferViewMat);
// release stage buffer // release stage buffer
stageBuffer.release(context); stageBufferPaint.release(context);
stageBufferGeometry.release(context);
// release pipelines // release pipelines
pipelines.release(context); pipelines.release(context);
} }
@ -190,28 +191,35 @@ void WgCompositor::endRenderPass()
void WgCompositor::reset(WgContext& context) void WgCompositor::reset(WgContext& context)
{ {
stageBuffer.clear(); stageBufferGeometry.clear();
stageBufferPaint.clear();
} }
void WgCompositor::flush(WgContext& context) void WgCompositor::flush(WgContext& context)
{ {
stageBuffer.append(&meshDataBlit); stageBufferGeometry.append(&meshDataBlit);
stageBuffer.flush(context); stageBufferGeometry.flush(context);
stageBufferPaint.flush(context);
} }
void WgCompositor::requestShape(WgRenderDataShape* renderData) void WgCompositor::requestShape(WgRenderDataShape* renderData)
{ {
stageBuffer.append(renderData); stageBufferGeometry.append(renderData);
// TODO: expand for fill settings renderData->renderSettingsShape.bindGroupInd = stageBufferPaint.append(renderData->renderSettingsShape.settings);
renderData->renderSettingsStroke.bindGroupInd = stageBufferPaint.append(renderData->renderSettingsStroke.settings);
ARRAY_FOREACH(p, renderData->clips)
requestShape((WgRenderDataShape* )(*p));
} }
void WgCompositor::requestImage(WgRenderDataPicture* renderData) void WgCompositor::requestImage(WgRenderDataPicture* renderData)
{ {
stageBuffer.append(renderData); stageBufferGeometry.append(renderData);
// TODO: expand for fill settings renderData->renderSettings.bindGroupInd = stageBufferPaint.append(renderData->renderSettings.settings);
ARRAY_FOREACH(p, renderData->clips)
requestShape((WgRenderDataShape* )(*p));
} }
@ -332,8 +340,8 @@ void WgCompositor::drawMesh(WgContext& context, WgMeshData* meshData)
uint64_t icount = meshData->ibuffer.count; uint64_t icount = meshData->ibuffer.count;
uint64_t vsize = meshData->vbuffer.count * sizeof(Point); uint64_t vsize = meshData->vbuffer.count * sizeof(Point);
uint64_t isize = icount * sizeof(uint32_t); uint64_t isize = icount * sizeof(uint32_t);
wgpuRenderPassEncoderSetVertexBuffer(renderPassEncoder, 0, stageBuffer.vbuffer_gpu, meshData->voffset, vsize); wgpuRenderPassEncoderSetVertexBuffer(renderPassEncoder, 0, stageBufferGeometry.vbuffer_gpu, meshData->voffset, vsize);
wgpuRenderPassEncoderSetIndexBuffer(renderPassEncoder, stageBuffer.ibuffer_gpu, WGPUIndexFormat_Uint32, meshData->ioffset, isize); wgpuRenderPassEncoderSetIndexBuffer(renderPassEncoder, stageBufferGeometry.ibuffer_gpu, WGPUIndexFormat_Uint32, meshData->ioffset, isize);
wgpuRenderPassEncoderDrawIndexed(renderPassEncoder, icount, 1, 0, 0, 0); wgpuRenderPassEncoderDrawIndexed(renderPassEncoder, icount, 1, 0, 0, 0);
}; };
@ -345,7 +353,7 @@ void WgCompositor::drawMeshFan(WgContext& context, WgMeshData* meshData)
uint64_t icount = (meshData->vbuffer.count - 2) * 3; uint64_t icount = (meshData->vbuffer.count - 2) * 3;
uint64_t vsize = meshData->vbuffer.count * sizeof(Point); uint64_t vsize = meshData->vbuffer.count * sizeof(Point);
uint64_t isize = icount * sizeof(uint32_t); uint64_t isize = icount * sizeof(uint32_t);
wgpuRenderPassEncoderSetVertexBuffer(renderPassEncoder, 0, stageBuffer.vbuffer_gpu, meshData->voffset, vsize); wgpuRenderPassEncoderSetVertexBuffer(renderPassEncoder, 0, stageBufferGeometry.vbuffer_gpu, meshData->voffset, vsize);
wgpuRenderPassEncoderSetIndexBuffer(renderPassEncoder, context.bufferIndexFan, WGPUIndexFormat_Uint32, 0, isize); wgpuRenderPassEncoderSetIndexBuffer(renderPassEncoder, context.bufferIndexFan, WGPUIndexFormat_Uint32, 0, isize);
wgpuRenderPassEncoderDrawIndexed(renderPassEncoder, icount, 1, 0, 0, 0); wgpuRenderPassEncoderDrawIndexed(renderPassEncoder, icount, 1, 0, 0, 0);
}; };
@ -358,9 +366,9 @@ void WgCompositor::drawMeshImage(WgContext& context, WgMeshData* meshData)
uint64_t icount = meshData->ibuffer.count; uint64_t icount = meshData->ibuffer.count;
uint64_t vsize = meshData->vbuffer.count * sizeof(Point); uint64_t vsize = meshData->vbuffer.count * sizeof(Point);
uint64_t isize = icount * sizeof(uint32_t); uint64_t isize = icount * sizeof(uint32_t);
wgpuRenderPassEncoderSetVertexBuffer(renderPassEncoder, 0, stageBuffer.vbuffer_gpu, meshData->voffset, vsize); wgpuRenderPassEncoderSetVertexBuffer(renderPassEncoder, 0, stageBufferGeometry.vbuffer_gpu, meshData->voffset, vsize);
wgpuRenderPassEncoderSetVertexBuffer(renderPassEncoder, 1, stageBuffer.vbuffer_gpu, meshData->toffset, vsize); wgpuRenderPassEncoderSetVertexBuffer(renderPassEncoder, 1, stageBufferGeometry.vbuffer_gpu, meshData->toffset, vsize);
wgpuRenderPassEncoderSetIndexBuffer(renderPassEncoder, stageBuffer.ibuffer_gpu, WGPUIndexFormat_Uint32, meshData->ioffset, isize); wgpuRenderPassEncoderSetIndexBuffer(renderPassEncoder, stageBufferGeometry.ibuffer_gpu, WGPUIndexFormat_Uint32, meshData->ioffset, isize);
wgpuRenderPassEncoderDrawIndexed(renderPassEncoder, icount, 1, 0, 0, 0); wgpuRenderPassEncoderDrawIndexed(renderPassEncoder, icount, 1, 0, 0, 0);
}; };
@ -371,12 +379,13 @@ void WgCompositor::drawShape(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;
WgRenderSettings& settings = renderData->renderSettingsShape;
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());
// setup stencil rules // setup stencil rules
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);
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 0, bindGroupViewMat, 0, nullptr); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 0, bindGroupViewMat, 0, nullptr);
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, renderData->bindGroupPaint, 0, nullptr); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, stageBufferPaint[settings.bindGroupInd], 0, nullptr);
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)
@ -384,16 +393,15 @@ void WgCompositor::drawShape(WgContext& context, WgRenderDataShape* renderData)
// 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, stageBufferPaint[settings.bindGroupInd], 0, nullptr);
WgRenderSettings& settings = renderData->renderSettingsShape;
if (settings.fillType == WgRenderSettingsType::Solid) { if (settings.fillType == WgRenderSettingsType::Solid) {
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, settings.bindGroupSolid, 0, nullptr); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, stageBufferPaint[settings.bindGroupInd], 0, nullptr);
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.solid); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.solid);
} else if (settings.fillType == WgRenderSettingsType::Linear) { } else if (settings.fillType == WgRenderSettingsType::Linear) {
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, settings.bindGroupGradient, 0, nullptr); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, settings.gradientData.bindGroup, 0, nullptr);
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.linear); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.linear);
} else if (settings.fillType == WgRenderSettingsType::Radial) { } else if (settings.fillType == WgRenderSettingsType::Radial) {
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, settings.bindGroupGradient, 0, nullptr); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, settings.gradientData.bindGroup, 0, nullptr);
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.radial); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.radial);
} }
// draw to color (second pass) // draw to color (second pass)
@ -407,6 +415,7 @@ 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;
WgRenderSettings& settings = renderData->renderSettingsShape;
// copy current render target data to dst target // copy current render target data to dst target
WgRenderTarget *target = currentTarget; WgRenderTarget *target = currentTarget;
endRenderPass(); endRenderPass();
@ -418,7 +427,7 @@ void WgCompositor::blendShape(WgContext& context, WgRenderDataShape* renderData,
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);
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 0, bindGroupViewMat, 0, nullptr); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 0, bindGroupViewMat, 0, nullptr);
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, renderData->bindGroupPaint, 0, nullptr); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, stageBufferPaint[settings.bindGroupInd], 0, nullptr);
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)
@ -426,18 +435,17 @@ void WgCompositor::blendShape(WgContext& context, WgRenderDataShape* renderData,
// 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, stageBufferPaint[settings.bindGroupInd], 0, nullptr);
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 3, targetTemp0.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;
if (settings.fillType == WgRenderSettingsType::Solid) { if (settings.fillType == WgRenderSettingsType::Solid) {
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, settings.bindGroupSolid, 0, nullptr); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, stageBufferPaint[settings.bindGroupInd], 0, nullptr);
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.solid_blend[blendMethodInd]); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.solid_blend[blendMethodInd]);
} else if (settings.fillType == WgRenderSettingsType::Linear) { } else if (settings.fillType == WgRenderSettingsType::Linear) {
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, settings.bindGroupGradient, 0, nullptr); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, settings.gradientData.bindGroup, 0, nullptr);
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.linear_blend[blendMethodInd]); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.linear_blend[blendMethodInd]);
} else if (settings.fillType == WgRenderSettingsType::Radial) { } else if (settings.fillType == WgRenderSettingsType::Radial) {
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, settings.bindGroupGradient, 0, nullptr); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, settings.gradientData.bindGroup, 0, nullptr);
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.radial_blend[blendMethodInd]); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.radial_blend[blendMethodInd]);
} }
// draw to color (second pass) // draw to color (second pass)
@ -451,13 +459,13 @@ void WgCompositor::clipShape(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;
WgRenderSettings& settings = renderData->renderSettingsShape;
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());
// setup stencil rules // setup stencil rules
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);
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 0, bindGroupViewMat, 0, nullptr); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 0, bindGroupViewMat, 0, nullptr);
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, renderData->bindGroupPaint, 0, nullptr); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, stageBufferPaint[settings.bindGroupInd], 0, nullptr);
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)
@ -470,16 +478,15 @@ void WgCompositor::clipShape(WgContext& context, WgRenderDataShape* renderData)
// 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, stageBufferPaint[settings.bindGroupInd], 0, nullptr);
WgRenderSettings& settings = renderData->renderSettingsShape;
if (settings.fillType == WgRenderSettingsType::Solid) { if (settings.fillType == WgRenderSettingsType::Solid) {
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, settings.bindGroupSolid, 0, nullptr); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, stageBufferPaint[settings.bindGroupInd], 0, nullptr);
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.solid); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.solid);
} else if (settings.fillType == WgRenderSettingsType::Linear) { } else if (settings.fillType == WgRenderSettingsType::Linear) {
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, settings.bindGroupGradient, 0, nullptr); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, settings.gradientData.bindGroup, 0, nullptr);
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.linear); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.linear);
} else if (settings.fillType == WgRenderSettingsType::Radial) { } else if (settings.fillType == WgRenderSettingsType::Radial) {
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, settings.bindGroupGradient, 0, nullptr); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, settings.gradientData.bindGroup, 0, nullptr);
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.radial); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.radial);
} }
// draw to color (second pass) // draw to color (second pass)
@ -493,30 +500,29 @@ void WgCompositor::drawStrokes(WgContext& context, WgRenderDataShape* renderData
assert(renderPassEncoder); assert(renderPassEncoder);
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;
WgRenderSettings& settings = renderData->renderSettingsStroke;
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)
for (uint32_t i = 0; i < renderData->meshGroupStrokes.meshes.count; i++) { for (uint32_t i = 0; i < renderData->meshGroupStrokes.meshes.count; i++) {
// 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, stageBufferPaint[settings.bindGroupInd], 0, nullptr);
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.direct); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.direct);
// draw to stencil (first pass) // draw to stencil (first pass)
drawMesh(context, renderData->meshGroupStrokes.meshes[i]); 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, stageBufferPaint[settings.bindGroupInd], 0, nullptr);
WgRenderSettings& settings = renderData->renderSettingsStroke;
if (settings.fillType == WgRenderSettingsType::Solid) { if (settings.fillType == WgRenderSettingsType::Solid) {
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, settings.bindGroupSolid, 0, nullptr); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, stageBufferPaint[settings.bindGroupInd], 0, nullptr);
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.solid); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.solid);
} else if (settings.fillType == WgRenderSettingsType::Linear) { } else if (settings.fillType == WgRenderSettingsType::Linear) {
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, settings.bindGroupGradient, 0, nullptr); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, settings.gradientData.bindGroup, 0, nullptr);
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.linear); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.linear);
} else if (settings.fillType == WgRenderSettingsType::Radial) { } else if (settings.fillType == WgRenderSettingsType::Radial) {
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, settings.bindGroupGradient, 0, nullptr); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, settings.gradientData.bindGroup, 0, nullptr);
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.radial); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.radial);
} }
// draw to color (second pass) // draw to color (second pass)
@ -531,7 +537,7 @@ void WgCompositor::blendStrokes(WgContext& context, WgRenderDataShape* renderDat
assert(renderPassEncoder); assert(renderPassEncoder);
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;
WgRenderSettings& settings = renderData->renderSettingsStroke;
// copy current render target data to dst target // copy current render target data to dst target
WgRenderTarget *target = currentTarget; WgRenderTarget *target = currentTarget;
endRenderPass(); endRenderPass();
@ -543,25 +549,24 @@ void WgCompositor::blendStrokes(WgContext& context, WgRenderDataShape* renderDat
// 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, stageBufferPaint[settings.bindGroupInd], 0, nullptr);
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.direct); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.direct);
// draw to stencil (first pass) // draw to stencil (first pass)
drawMesh(context, renderData->meshGroupStrokes.meshes[i]); 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, stageBufferPaint[settings.bindGroupInd], 0, nullptr);
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 3, targetTemp0.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;
if (settings.fillType == WgRenderSettingsType::Solid) { if (settings.fillType == WgRenderSettingsType::Solid) {
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, settings.bindGroupSolid, 0, nullptr); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, stageBufferPaint[settings.bindGroupInd], 0, nullptr);
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.solid_blend[blendMethodInd]); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.solid_blend[blendMethodInd]);
} else if (settings.fillType == WgRenderSettingsType::Linear) { } else if (settings.fillType == WgRenderSettingsType::Linear) {
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, settings.bindGroupGradient, 0, nullptr); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, settings.gradientData.bindGroup, 0, nullptr);
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.linear_blend[blendMethodInd]); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.linear_blend[blendMethodInd]);
} else if (settings.fillType == WgRenderSettingsType::Radial) { } else if (settings.fillType == WgRenderSettingsType::Radial) {
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, settings.bindGroupGradient, 0, nullptr); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, settings.gradientData.bindGroup, 0, nullptr);
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.radial_blend[blendMethodInd]); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.radial_blend[blendMethodInd]);
} }
// draw to color (second pass) // draw to color (second pass)
@ -578,13 +583,14 @@ void WgCompositor::clipStrokes(WgContext& context, WgRenderDataShape* renderData
if (renderData->renderSettingsStroke.skip) return; if (renderData->renderSettingsStroke.skip) return;
if (renderData->meshGroupStrokes.meshes.count == 0) return; if (renderData->meshGroupStrokes.meshes.count == 0) return;
if (renderData->viewport.invalid()) return; if (renderData->viewport.invalid()) return;
WgRenderSettings& settings = renderData->renderSettingsStroke;
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)
for (uint32_t i = 0; i < renderData->meshGroupStrokes.meshes.count; i++) { for (uint32_t i = 0; i < renderData->meshGroupStrokes.meshes.count; i++) {
// 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, stageBufferPaint[settings.bindGroupInd], 0, nullptr);
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.direct); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.direct);
// draw to stencil (first pass) // draw to stencil (first pass)
drawMesh(context, renderData->meshGroupStrokes.meshes[i]); drawMesh(context, renderData->meshGroupStrokes.meshes[i]);
@ -596,16 +602,15 @@ void WgCompositor::clipStrokes(WgContext& context, WgRenderDataShape* renderData
// 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, stageBufferPaint[settings.bindGroupInd], 0, nullptr);
WgRenderSettings& settings = renderData->renderSettingsStroke;
if (settings.fillType == WgRenderSettingsType::Solid) { if (settings.fillType == WgRenderSettingsType::Solid) {
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, settings.bindGroupSolid, 0, nullptr); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, stageBufferPaint[settings.bindGroupInd], 0, nullptr);
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.solid); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.solid);
} else if (settings.fillType == WgRenderSettingsType::Linear) { } else if (settings.fillType == WgRenderSettingsType::Linear) {
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, settings.bindGroupGradient, 0, nullptr); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, settings.gradientData.bindGroup, 0, nullptr);
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.linear); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.linear);
} else if (settings.fillType == WgRenderSettingsType::Radial) { } else if (settings.fillType == WgRenderSettingsType::Radial) {
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, settings.bindGroupGradient, 0, nullptr); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, settings.gradientData.bindGroup, 0, nullptr);
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.radial); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.radial);
} }
// draw to color (second pass) // draw to color (second pass)
@ -619,18 +624,19 @@ void WgCompositor::drawImage(WgContext& context, WgRenderDataPicture* renderData
assert(renderData); assert(renderData);
assert(renderPassEncoder); assert(renderPassEncoder);
if (renderData->viewport.invalid()) return; if (renderData->viewport.invalid()) return;
WgRenderSettings& settings = renderData->renderSettings;
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 stencil // draw stencil
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, stageBufferPaint[settings.bindGroupInd], 0, nullptr);
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.direct); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.direct);
drawMeshImage(context, &renderData->meshData); 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, stageBufferPaint[settings.bindGroupInd], 0, nullptr);
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, renderData->bindGroupPicture, 0, nullptr); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, renderData->imageData.bindGroup, 0, nullptr);
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.image); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.image);
drawMeshImage(context, &renderData->meshData); drawMeshImage(context, &renderData->meshData);
} }
@ -641,6 +647,7 @@ void WgCompositor::blendImage(WgContext& context, WgRenderDataPicture* renderDat
assert(renderData); assert(renderData);
assert(renderPassEncoder); assert(renderPassEncoder);
if (renderData->viewport.invalid()) return; if (renderData->viewport.invalid()) return;
WgRenderSettings& settings = renderData->renderSettings;
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 target // copy current render target data to dst target
WgRenderTarget *target = currentTarget; WgRenderTarget *target = currentTarget;
@ -650,15 +657,15 @@ void WgCompositor::blendImage(WgContext& context, WgRenderDataPicture* renderDat
// 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, stageBufferPaint[settings.bindGroupInd], 0, nullptr);
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.direct); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.direct);
drawMeshImage(context, &renderData->meshData); 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, stageBufferPaint[settings.bindGroupInd], 0, nullptr);
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, renderData->bindGroupPicture, 0, nullptr); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, renderData->imageData.bindGroup, 0, nullptr);
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 3, targetTemp0.bindGroupTexure, 0, nullptr); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 3, targetTemp0.bindGroupTexure, 0, nullptr);
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.image_blend[blendMethodInd]); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.image_blend[blendMethodInd]);
drawMeshImage(context, &renderData->meshData); drawMeshImage(context, &renderData->meshData);
@ -670,11 +677,12 @@ void WgCompositor::clipImage(WgContext& context, WgRenderDataPicture* renderData
assert(renderData); assert(renderData);
assert(renderPassEncoder); assert(renderPassEncoder);
if (renderData->viewport.invalid()) return; if (renderData->viewport.invalid()) return;
WgRenderSettings& settings = renderData->renderSettings;
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());
// 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, stageBufferPaint[settings.bindGroupInd], 0, nullptr);
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.direct); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.direct);
drawMeshImage(context, &renderData->meshData); drawMeshImage(context, &renderData->meshData);
// merge depth and stencil buffer // merge depth and stencil buffer
@ -685,8 +693,8 @@ void WgCompositor::clipImage(WgContext& context, WgRenderDataPicture* renderData
// 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, stageBufferPaint[settings.bindGroupInd], 0, nullptr);
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, renderData->bindGroupPicture, 0, nullptr); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 2, renderData->imageData.bindGroup, 0, nullptr);
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.image); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.image);
drawMeshImage(context, &renderData->meshData); drawMeshImage(context, &renderData->meshData);
} }
@ -734,16 +742,19 @@ void WgCompositor::blendScene(WgContext& context, WgRenderTarget* scene, WgCompo
void WgCompositor::markupClipPath(WgContext& context, WgRenderDataShape* renderData) void WgCompositor::markupClipPath(WgContext& context, WgRenderDataShape* renderData)
{ {
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 0, bindGroupViewMat, 0, nullptr); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 0, bindGroupViewMat, 0, nullptr);
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, renderData->bindGroupPaint, 0, nullptr);
// markup stencil // markup stencil
if (renderData->meshGroupStrokes.meshes.count > 0) { if (renderData->meshGroupStrokes.meshes.count > 0) {
WgRenderSettings& settings = renderData->renderSettingsStroke;
wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 255); wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 255);
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, stageBufferPaint[settings.bindGroupInd], 0, nullptr);
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.direct); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, pipelines.direct);
ARRAY_FOREACH(p, renderData->meshGroupStrokes.meshes) ARRAY_FOREACH(p, renderData->meshGroupStrokes.meshes)
drawMesh(context, (*p)); 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;
WgRenderSettings& settings = renderData->renderSettingsShape;
wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0); wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0);
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, stageBufferPaint[settings.bindGroupInd], 0, nullptr);
wgpuRenderPassEncoderSetPipeline(renderPassEncoder, stencilPipeline); wgpuRenderPassEncoderSetPipeline(renderPassEncoder, stencilPipeline);
ARRAY_FOREACH(p, renderData->meshGroupShapes.meshes) ARRAY_FOREACH(p, renderData->meshGroupShapes.meshes)
drawMeshFan(context, (*p)); drawMeshFan(context, (*p));
@ -760,12 +771,13 @@ void WgCompositor::renderClipPath(WgContext& context, WgRenderDataPaint* paint)
wgpuRenderPassEncoderSetScissorRect(renderPassEncoder, 0, 0, width, height); wgpuRenderPassEncoderSetScissorRect(renderPassEncoder, 0, 0, width, height);
// get render data // get render data
WgRenderDataShape* renderData0 = (WgRenderDataShape*)paint->clips[0]; WgRenderDataShape* renderData0 = (WgRenderDataShape*)paint->clips[0];
WgRenderSettings& settings0 = renderData0->renderSettingsShape;
// markup stencil // markup stencil
markupClipPath(context, renderData0); markupClipPath(context, renderData0);
// copy stencil to depth // copy stencil to depth
wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0); wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0);
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 0, bindGroupViewMat, 0, nullptr); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 0, bindGroupViewMat, 0, nullptr);
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, renderData0->bindGroupPaint, 0, nullptr); wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, stageBufferPaint[settings0.bindGroupInd], 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);
drawMeshFan(context, &renderData0->meshDataBBox); drawMeshFan(context, &renderData0->meshDataBBox);
@ -773,35 +785,36 @@ void WgCompositor::renderClipPath(WgContext& context, WgRenderDataPaint* paint)
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
WgRenderDataShape* renderData = (WgRenderDataShape*)(*p); WgRenderDataShape* renderData = (WgRenderDataShape*)(*p);
WgRenderSettings& settings = renderData->renderSettingsShape;
// markup stencil // markup stencil
markupClipPath(context, renderData); markupClipPath(context, renderData);
// 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, stageBufferPaint[settings.bindGroupInd], 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);
drawMeshFan(context, &renderData->meshDataBBox); 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, stageBufferPaint[settings.bindGroupInd], 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);
drawMeshFan(context, &renderData->meshDataBBox); 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, stageBufferPaint[settings.bindGroupInd], 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);
drawMeshFan(context, &renderData->meshDataBBox); 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, stageBufferPaint[settings0.bindGroupInd], 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);
drawMeshFan(context, &renderData0->meshDataBBox); 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, stageBufferPaint[settings.bindGroupInd], 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);
drawMeshFan(context, &renderData->meshDataBBox); drawMeshFan(context, &renderData->meshDataBBox);
@ -819,10 +832,11 @@ void WgCompositor::clearClipPath(WgContext& context, WgRenderDataPaint* paint)
// get render data // get render data
ARRAY_FOREACH(p, paint->clips) { ARRAY_FOREACH(p, paint->clips) {
WgRenderDataShape* renderData = (WgRenderDataShape*)(*p); WgRenderDataShape* renderData = (WgRenderDataShape*)(*p);
WgRenderSettings& settings = renderData->renderSettingsShape;
// set transformations // set transformations
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, stageBufferPaint[settings.bindGroupInd], 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);
drawMeshFan(context, &renderData->meshDataBBox); drawMeshFan(context, &renderData->meshDataBBox);

View file

@ -39,7 +39,8 @@ private:
// pipelines // pipelines
WgPipelines pipelines{}; WgPipelines pipelines{};
// stage buffers // stage buffers
WgRenderDataStageBuffer stageBuffer{}; WgStageBufferGeometry stageBufferGeometry{};
WgStageBufferUniform<WgShaderTypePaintSettings> stageBufferPaint;
// global stencil/depth buffer handles // global stencil/depth buffer handles
WGPUTexture texDepthStencil{}; WGPUTexture texDepthStencil{};
WGPUTextureView texViewDepthStencil{}; WGPUTextureView texViewDepthStencil{};

View file

@ -167,17 +167,17 @@ void WgPipelines::initialize(WgContext& context)
const WgBindGroupLayouts& layouts = context.layouts; const WgBindGroupLayouts& layouts = context.layouts;
// bind group layouts helpers // bind group layouts helpers
const WGPUBindGroupLayout bindGroupLayoutsStencil[] { layouts.layoutBuffer1Un, layouts.layoutBuffer2Un }; const WGPUBindGroupLayout bindGroupLayoutsStencil[] { layouts.layoutBuffer1Un, layouts.layoutBuffer1Un };
const WGPUBindGroupLayout bindGroupLayoutsDepth[] { layouts.layoutBuffer1Un, layouts.layoutBuffer2Un, layouts.layoutBuffer1Un }; const WGPUBindGroupLayout bindGroupLayoutsDepth[] { layouts.layoutBuffer1Un, layouts.layoutBuffer1Un, layouts.layoutBuffer1Un };
// bind group layouts normal blend // bind group layouts normal blend
const WGPUBindGroupLayout bindGroupLayoutsSolid[] { layouts.layoutBuffer1Un, layouts.layoutBuffer2Un, layouts.layoutBuffer1Un }; const WGPUBindGroupLayout bindGroupLayoutsSolid[] { layouts.layoutBuffer1Un, layouts.layoutBuffer1Un };
const WGPUBindGroupLayout bindGroupLayoutsGradient[] { layouts.layoutBuffer1Un, layouts.layoutBuffer2Un, layouts.layoutTexSampledBuff2Un }; const WGPUBindGroupLayout bindGroupLayoutsGradient[] { layouts.layoutBuffer1Un, layouts.layoutBuffer1Un, layouts.layoutTexSampled };
const WGPUBindGroupLayout bindGroupLayoutsImage[] { layouts.layoutBuffer1Un, layouts.layoutBuffer2Un, layouts.layoutTexSampled }; const WGPUBindGroupLayout bindGroupLayoutsImage[] { layouts.layoutBuffer1Un, layouts.layoutBuffer1Un, layouts.layoutTexSampled };
const WGPUBindGroupLayout bindGroupLayoutsScene[] { layouts.layoutTexSampled, layouts.layoutBuffer1Un }; const WGPUBindGroupLayout bindGroupLayoutsScene[] { layouts.layoutTexSampled, layouts.layoutBuffer1Un };
// bind group layouts custom blend // bind group layouts custom blend
const WGPUBindGroupLayout bindGroupLayoutsSolidBlend[] { layouts.layoutBuffer1Un, layouts.layoutBuffer2Un, layouts.layoutBuffer1Un, layouts.layoutTexSampled }; const WGPUBindGroupLayout bindGroupLayoutsSolidBlend[] { layouts.layoutBuffer1Un, layouts.layoutBuffer1Un, layouts.layoutBuffer1Un, layouts.layoutTexSampled };
const WGPUBindGroupLayout bindGroupLayoutsGradientBlend[] { layouts.layoutBuffer1Un, layouts.layoutBuffer2Un, layouts.layoutTexSampledBuff2Un, layouts.layoutTexSampled }; const WGPUBindGroupLayout bindGroupLayoutsGradientBlend[] { layouts.layoutBuffer1Un, layouts.layoutBuffer1Un, layouts.layoutTexSampled, layouts.layoutTexSampled };
const WGPUBindGroupLayout bindGroupLayoutsImageBlend[] { layouts.layoutBuffer1Un, layouts.layoutBuffer2Un, layouts.layoutTexSampled, layouts.layoutTexSampled }; const WGPUBindGroupLayout bindGroupLayoutsImageBlend[] { layouts.layoutBuffer1Un, layouts.layoutBuffer1Un, layouts.layoutTexSampled, layouts.layoutTexSampled };
const WGPUBindGroupLayout bindGroupLayoutsSceneBlend[] { layouts.layoutTexSampled, layouts.layoutTexSampled, layouts.layoutBuffer1Un }; const WGPUBindGroupLayout bindGroupLayoutsSceneBlend[] { layouts.layoutTexSampled, layouts.layoutTexSampled, layouts.layoutBuffer1Un };
// bind group layouts scene compose // bind group layouts scene compose
const WGPUBindGroupLayout bindGroupLayoutsSceneCompose[] { layouts.layoutTexSampled, layouts.layoutTexSampled }; const WGPUBindGroupLayout bindGroupLayoutsSceneCompose[] { layouts.layoutTexSampled, layouts.layoutTexSampled };
@ -229,7 +229,7 @@ void WgPipelines::initialize(WgContext& context)
layout_stencil = createPipelineLayout(context.device, bindGroupLayoutsStencil, 2); layout_stencil = createPipelineLayout(context.device, bindGroupLayoutsStencil, 2);
layout_depth = createPipelineLayout(context.device, bindGroupLayoutsDepth, 3); layout_depth = createPipelineLayout(context.device, bindGroupLayoutsDepth, 3);
// layouts normal blend // layouts normal blend
layout_solid = createPipelineLayout(context.device, bindGroupLayoutsSolid, 3); layout_solid = createPipelineLayout(context.device, bindGroupLayoutsSolid, 2);
layout_gradient = createPipelineLayout(context.device, bindGroupLayoutsGradient, 3); layout_gradient = createPipelineLayout(context.device, bindGroupLayoutsGradient, 3);
layout_image = createPipelineLayout(context.device, bindGroupLayoutsImage, 3); layout_image = createPipelineLayout(context.device, bindGroupLayoutsImage, 3);
layout_scene = createPipelineLayout(context.device, bindGroupLayoutsScene, 2); layout_scene = createPipelineLayout(context.device, bindGroupLayoutsScene, 2);

View file

@ -202,12 +202,38 @@ void WgImageData::update(WgContext& context, const RenderSurface* surface)
if (texHandleChanged) { if (texHandleChanged) {
context.releaseTextureView(textureView); context.releaseTextureView(textureView);
textureView = context.createTextureView(texture); textureView = context.createTextureView(texture);
// update bind group
context.layouts.releaseBindGroup(bindGroup);
bindGroup = context.layouts.createBindGroupTexSampled(context.samplerLinearRepeat, textureView);
}
};
void WgImageData::update(WgContext& context, const Fill* fill)
{
// compute gradient data
WgShaderTypeGradientData gradientData;
gradientData.update(fill);
// allocate new texture handle
bool texHandleChanged = context.allocateTexture(texture, WG_TEXTURE_GRADIENT_SIZE, 1, WGPUTextureFormat_RGBA8Unorm, gradientData.data);
// update texture view of texture handle was changed
if (texHandleChanged) {
context.releaseTextureView(textureView);
textureView = context.createTextureView(texture);
// get sampler by spread type
WGPUSampler sampler = context.samplerLinearClamp;
if (fill->spread() == FillSpread::Reflect) sampler = context.samplerLinearMirror;
if (fill->spread() == FillSpread::Repeat) sampler = context.samplerLinearRepeat;
// update bind group
context.layouts.releaseBindGroup(bindGroup);
bindGroup = context.layouts.createBindGroupTexSampled(sampler, textureView);
} }
}; };
void WgImageData::release(WgContext& context) void WgImageData::release(WgContext& context)
{ {
context.layouts.releaseBindGroup(bindGroup);
context.releaseTextureView(textureView); context.releaseTextureView(textureView);
context.releaseTexture(texture); context.releaseTexture(texture);
}; };
@ -216,52 +242,31 @@ void WgImageData::release(WgContext& context)
// WgRenderSettings // WgRenderSettings
//*********************************************************************** //***********************************************************************
void WgRenderSettings::updateFill(WgContext& context, const Fill* fill) void WgRenderSettings::update(WgContext& context, const tvg::Matrix& transform, tvg::ColorSpace cs, uint8_t opacity)
{ {
rasterType = WgRenderRasterType::Gradient; settings.transform.update(transform);
// get gradient transfrom matrix settings.options.update(cs, opacity);
Matrix invFillTransform; }
WgShaderTypeMat4x4f gradientTrans; // identity by default
if (inverse(&fill->transform(), &invFillTransform)) void WgRenderSettings::update(WgContext& context, const Fill* fill)
gradientTrans.update(invFillTransform); {
assert(fill);
settings.gradient.update(fill);
gradientData.update(context, fill);
// get gradient rasterisation settings // get gradient rasterisation settings
WgShaderTypeGradient gradient; rasterType = WgRenderRasterType::Gradient;
if (fill->type() == Type::LinearGradient) { if (fill->type() == Type::LinearGradient)
gradient.update((LinearGradient*)fill);
fillType = WgRenderSettingsType::Linear; fillType = WgRenderSettingsType::Linear;
} else if (fill->type() == Type::RadialGradient) { else if (fill->type() == Type::RadialGradient)
gradient.update((RadialGradient*)fill);
fillType = WgRenderSettingsType::Radial; fillType = WgRenderSettingsType::Radial;
}
// update gpu assets
bool bufferGradientSettingsChanged = context.allocateBufferUniform(bufferGroupGradient, &gradient.settings, sizeof(gradient.settings));
bool bufferGradientTransformChanged = context.allocateBufferUniform(bufferGroupTransfromGrad, &gradientTrans.mat, sizeof(gradientTrans.mat));
bool textureGradientChanged = context.allocateTexture(texGradient, WG_TEXTURE_GRADIENT_SIZE, 1, WGPUTextureFormat_RGBA8Unorm, gradient.texData);
if (bufferGradientSettingsChanged || textureGradientChanged || bufferGradientTransformChanged) {
// update texture view
context.releaseTextureView(texViewGradient);
texViewGradient = context.createTextureView(texGradient);
// get sampler by spread type
WGPUSampler sampler = context.samplerLinearClamp;
if (fill->spread() == FillSpread::Reflect) sampler = context.samplerLinearMirror;
if (fill->spread() == FillSpread::Repeat) sampler = context.samplerLinearRepeat;
// update bind group
context.layouts.releaseBindGroup(bindGroupGradient);
bindGroupGradient = context.layouts.createBindGroupTexSampledBuff2Un(
sampler, texViewGradient, bufferGroupGradient, bufferGroupTransfromGrad);
}
skip = false; skip = false;
}; };
void WgRenderSettings::updateColor(WgContext& context, const RenderColor& c) void WgRenderSettings::update(WgContext& context, const RenderColor& c)
{ {
settings.color.update(c);
rasterType = WgRenderRasterType::Solid; rasterType = WgRenderRasterType::Solid;
WgShaderTypeVec4f solidColor(c);
if (context.allocateBufferUniform(bufferGroupSolid, &solidColor, sizeof(solidColor))) {
context.layouts.releaseBindGroup(bindGroupSolid);
bindGroupSolid = context.layouts.createBindGroupBuffer1Un(bufferGroupSolid);
}
fillType = WgRenderSettingsType::Solid; fillType = WgRenderSettingsType::Solid;
skip = (c.a == 0); skip = (c.a == 0);
}; };
@ -269,13 +274,7 @@ void WgRenderSettings::updateColor(WgContext& context, const RenderColor& c)
void WgRenderSettings::release(WgContext& context) void WgRenderSettings::release(WgContext& context)
{ {
context.layouts.releaseBindGroup(bindGroupSolid); gradientData.release(context);
context.layouts.releaseBindGroup(bindGroupGradient);
context.releaseBuffer(bufferGroupSolid);
context.releaseBuffer(bufferGroupGradient);
context.releaseBuffer(bufferGroupTransfromGrad);
context.releaseTexture(texGradient);
context.releaseTextureView(texViewGradient);
}; };
//*********************************************************************** //***********************************************************************
@ -284,26 +283,10 @@ void WgRenderSettings::release(WgContext& context)
void WgRenderDataPaint::release(WgContext& context) void WgRenderDataPaint::release(WgContext& context)
{ {
context.layouts.releaseBindGroup(bindGroupPaint);
context.releaseBuffer(bufferModelMat);
context.releaseBuffer(bufferBlendSettings);
clips.clear(); clips.clear();
}; };
void WgRenderDataPaint::update(WgContext& context, const tvg::Matrix& transform, tvg::ColorSpace cs, uint8_t opacity)
{
WgShaderTypeMat4x4f modelMat(transform);
WgShaderTypeVec4f blendSettings(cs, opacity);
bool bufferModelMatChanged = context.allocateBufferUniform(bufferModelMat, &modelMat, sizeof(modelMat));
bool bufferBlendSettingsChanged = context.allocateBufferUniform(bufferBlendSettings, &blendSettings, sizeof(blendSettings));
if (bufferModelMatChanged || bufferBlendSettingsChanged) {
context.layouts.releaseBindGroup(bindGroupPaint);
bindGroupPaint = context.layouts.createBindGroupBuffer2Un(bufferModelMat, bufferBlendSettings);
}
}
void WgRenderDataPaint::updateClips(tvg::Array<tvg::RenderData> &clips) { void WgRenderDataPaint::updateClips(tvg::Array<tvg::RenderData> &clips) {
this->clips.clear(); this->clips.clear();
ARRAY_FOREACH(p, clips) { ARRAY_FOREACH(p, clips) {
@ -467,17 +450,12 @@ void WgRenderDataPicture::updateSurface(WgContext& context, const RenderSurface*
meshData.imageBox(context, surface->w, surface->h); meshData.imageBox(context, surface->w, surface->h);
// update texture data // update texture data
imageData.update(context, surface); imageData.update(context, surface);
// update texture bind group
context.layouts.releaseBindGroup(bindGroupPicture);
bindGroupPicture = context.layouts.createBindGroupTexSampled(
context.samplerLinearRepeat, imageData.textureView
);
} }
void WgRenderDataPicture::release(WgContext& context) void WgRenderDataPicture::release(WgContext& context)
{ {
context.layouts.releaseBindGroup(bindGroupPicture); renderSettings.release(context);
imageData.release(context); imageData.release(context);
meshData.release(context); meshData.release(context);
WgRenderDataPaint::release(context); WgRenderDataPaint::release(context);
@ -676,10 +654,10 @@ void WgRenderDataEffectParamsPool::release(WgContext& context)
} }
//*********************************************************************** //***********************************************************************
// WgRenderDataStageBuffer // WgStageBufferGeometry
//*********************************************************************** //***********************************************************************
void WgRenderDataStageBuffer::append(WgMeshData* meshData) void WgStageBufferGeometry::append(WgMeshData* meshData)
{ {
assert(meshData); assert(meshData);
uint32_t vsize = meshData->vbuffer.count * sizeof(meshData->vbuffer[0]); uint32_t vsize = meshData->vbuffer.count * sizeof(meshData->vbuffer[0]);
@ -712,54 +690,50 @@ void WgRenderDataStageBuffer::append(WgMeshData* meshData)
} }
void WgRenderDataStageBuffer::append(WgMeshDataGroup* meshDataGroup) void WgStageBufferGeometry::append(WgMeshDataGroup* meshDataGroup)
{ {
ARRAY_FOREACH(p, meshDataGroup->meshes) append(*p); ARRAY_FOREACH(p, meshDataGroup->meshes) append(*p);
} }
void WgRenderDataStageBuffer::append(WgRenderDataShape* renderDataShape) void WgStageBufferGeometry::append(WgRenderDataShape* renderDataShape)
{ {
append(&renderDataShape->meshGroupShapes); append(&renderDataShape->meshGroupShapes);
append(&renderDataShape->meshGroupShapesBBox); append(&renderDataShape->meshGroupShapesBBox);
append(&renderDataShape->meshGroupStrokes); append(&renderDataShape->meshGroupStrokes);
append(&renderDataShape->meshGroupStrokesBBox); append(&renderDataShape->meshGroupStrokesBBox);
append(&renderDataShape->meshDataBBox); append(&renderDataShape->meshDataBBox);
ARRAY_FOREACH(p, renderDataShape->clips)
append((WgRenderDataShape* )(*p));
} }
void WgRenderDataStageBuffer::append(WgRenderDataPicture* renderDataPicture) void WgStageBufferGeometry::append(WgRenderDataPicture* renderDataPicture)
{ {
append(&renderDataPicture->meshData); append(&renderDataPicture->meshData);
ARRAY_FOREACH(p, renderDataPicture->clips)
append((WgRenderDataShape* )(*p));
} }
void WgRenderDataStageBuffer::release(WgContext& context) void WgStageBufferGeometry::release(WgContext& context)
{ {
context.releaseBuffer(vbuffer_gpu); context.releaseBuffer(vbuffer_gpu);
context.releaseBuffer(ibuffer_gpu); context.releaseBuffer(ibuffer_gpu);
} }
void WgRenderDataStageBuffer::clear() void WgStageBufferGeometry::clear()
{ {
vbuffer.clear(); vbuffer.clear();
ibuffer.clear(); ibuffer.clear();
} }
void WgRenderDataStageBuffer::flush(WgContext& context) void WgStageBufferGeometry::flush(WgContext& context)
{ {
context.allocateBufferVertex(vbuffer_gpu, (float *)vbuffer.data, vbuffer.count); context.allocateBufferVertex(vbuffer_gpu, (float *)vbuffer.data, vbuffer.count);
context.allocateBufferIndex(ibuffer_gpu, (uint32_t *)ibuffer.data, ibuffer.count); context.allocateBufferIndex(ibuffer_gpu, (uint32_t *)ibuffer.data, ibuffer.count);
} }
void WgRenderDataStageBuffer::bind(WGPURenderPassEncoder renderPass, size_t voffset, size_t toffset) void WgStageBufferGeometry::bind(WGPURenderPassEncoder renderPass, size_t voffset, size_t toffset)
{ {
wgpuRenderPassEncoderSetVertexBuffer(renderPass, 0, vbuffer_gpu, voffset, vbuffer.count - voffset); wgpuRenderPassEncoderSetVertexBuffer(renderPass, 0, vbuffer_gpu, voffset, vbuffer.count - voffset);
wgpuRenderPassEncoderSetVertexBuffer(renderPass, 1, vbuffer_gpu, toffset, vbuffer.count - toffset); wgpuRenderPassEncoderSetVertexBuffer(renderPass, 1, vbuffer_gpu, toffset, vbuffer.count - toffset);

View file

@ -66,8 +66,10 @@ struct WgMeshDataGroup {
struct WgImageData { struct WgImageData {
WGPUTexture texture{}; WGPUTexture texture{};
WGPUTextureView textureView{}; WGPUTextureView textureView{};
WGPUBindGroup bindGroup{};
void update(WgContext& context, const RenderSurface* surface); void update(WgContext& context, const RenderSurface* surface);
void update(WgContext& context, const Fill* fill);
void release(WgContext& context); void release(WgContext& context);
}; };
@ -76,37 +78,29 @@ enum class WgRenderRasterType { Solid = 0, Gradient, Image };
struct WgRenderSettings struct WgRenderSettings
{ {
WGPUBuffer bufferGroupSolid{}; uint32_t bindGroupInd{};
WGPUBindGroup bindGroupSolid{}; WgShaderTypePaintSettings settings;
WGPUTexture texGradient{}; WgImageData gradientData;
WGPUTextureView texViewGradient{};
WGPUBuffer bufferGroupGradient{};
WGPUBuffer bufferGroupTransfromGrad{};
WGPUBindGroup bindGroupGradient{};
WgRenderSettingsType fillType{}; WgRenderSettingsType fillType{};
WgRenderRasterType rasterType{}; WgRenderRasterType rasterType{};
bool skip{}; bool skip{};
void updateFill(WgContext& context, const Fill* fill); void update(WgContext& context, const tvg::Matrix& transform, tvg::ColorSpace cs, uint8_t opacity);
void updateColor(WgContext& context, const RenderColor& c); void update(WgContext& context, const Fill* fill);
void update(WgContext& context, const RenderColor& c);
void release(WgContext& context); void release(WgContext& context);
}; };
struct WgRenderDataPaint struct WgRenderDataPaint
{ {
WGPUBuffer bufferModelMat{};
WGPUBuffer bufferBlendSettings{};
WGPUBindGroup bindGroupPaint{};
RenderRegion viewport{};
BBox aabb{{},{}}; BBox aabb{{},{}};
float opacity{}; RenderRegion viewport{};
Array<WgRenderDataPaint*> clips; Array<WgRenderDataPaint*> clips;
virtual ~WgRenderDataPaint() {}; virtual ~WgRenderDataPaint() {};
virtual void release(WgContext& context); virtual void release(WgContext& context);
virtual Type type() { return Type::Undefined; }; virtual Type type() { return Type::Undefined; };
void update(WgContext& context, const tvg::Matrix& transform, tvg::ColorSpace cs, uint8_t opacity);
void updateClips(tvg::Array<tvg::RenderData> &clips); void updateClips(tvg::Array<tvg::RenderData> &clips);
}; };
@ -147,7 +141,7 @@ public:
struct WgRenderDataPicture: public WgRenderDataPaint struct WgRenderDataPicture: public WgRenderDataPaint
{ {
WGPUBindGroup bindGroupPicture{}; WgRenderSettings renderSettings{};
WgImageData imageData{}; WgImageData imageData{};
WgMeshData meshData{}; WgMeshData meshData{};
@ -221,7 +215,7 @@ public:
void release(WgContext& context); void release(WgContext& context);
}; };
class WgRenderDataStageBuffer { class WgStageBufferGeometry {
private: private:
Array<uint8_t> vbuffer; Array<uint8_t> vbuffer;
Array<uint8_t> ibuffer; Array<uint8_t> ibuffer;
@ -240,4 +234,50 @@ public:
void bind(WGPURenderPassEncoder renderPass, size_t voffset, size_t toffset); void bind(WGPURenderPassEncoder renderPass, size_t voffset, size_t toffset);
}; };
// typed uniform stage buffer with related bind groups handling
template<typename T>
class WgStageBufferUniform {
private:
Array<T> ubuffer;
WGPUBuffer ubuffer_gpu{};
Array<WGPUBindGroup> bbuffer;
public:
// append uniform data to cpu staged buffer and return related bind group index
uint32_t append(const T& value) {
ubuffer.push(value);
return ubuffer.count - 1;
}
void flush(WgContext& context) {
// flush data to gpu buffer from cpu memory including reserved data to prevent future gpu buffer reallocations
bool bufferChanged = context.allocateBufferUniform(ubuffer_gpu, (void*)ubuffer.data, ubuffer.reserved*sizeof(T));
// if gpu buffer handle was changed we must to remove all created binding groups
if (bufferChanged) releaseBindGroups(context);
// allocate bind groups for all new data items
for (uint32_t i = bbuffer.count; i < ubuffer.count; i++)
bbuffer.push(context.layouts.createBindGroupBuffer1Un(ubuffer_gpu, i*sizeof(T), sizeof(T)));
assert(bbuffer.count >= ubuffer.count);
}
// please, use index that was returned from append method
WGPUBindGroup operator[](const uint32_t index) const {
return bbuffer[index];
}
void clear() {
ubuffer.clear();
}
void release(WgContext& context) {
context.releaseBuffer(ubuffer_gpu);
releaseBindGroups(context);
}
void releaseBindGroups(WgContext& context) {
ARRAY_FOREACH(p, bbuffer)
context.layouts.releaseBindGroup(*p);
bbuffer.clear();
}
};
#endif // _TVG_WG_RENDER_DATA_H_ #endif // _TVG_WG_RENDER_DATA_H_

View file

@ -147,18 +147,18 @@ RenderData WgRenderer::prepare(const RenderShape& rshape, RenderData data, const
// update paint settings // update paint settings
if ((!data) || (flags & (RenderUpdateFlag::Transform | RenderUpdateFlag::Blend))) { if ((!data) || (flags & (RenderUpdateFlag::Transform | RenderUpdateFlag::Blend))) {
renderDataShape->update(mContext, transform, mTargetSurface.cs, opacity); renderDataShape->renderSettingsShape.update(mContext, transform, mTargetSurface.cs, opacity);
renderDataShape->renderSettingsStroke.update(mContext, transform, mTargetSurface.cs, opacity);
renderDataShape->fillRule = rshape.rule; renderDataShape->fillRule = rshape.rule;
} }
// setup fill settings // setup fill settings
renderDataShape->viewport = mViewport; renderDataShape->viewport = mViewport;
renderDataShape->opacity = opacity; if (flags & RenderUpdateFlag::Gradient && rshape.fill) renderDataShape->renderSettingsShape.update(mContext, rshape.fill);
if (flags & RenderUpdateFlag::Gradient && rshape.fill) renderDataShape->renderSettingsShape.updateFill(mContext, rshape.fill); else if (flags & RenderUpdateFlag::Color) renderDataShape->renderSettingsShape.update(mContext, rshape.color);
else if (flags & RenderUpdateFlag::Color) renderDataShape->renderSettingsShape.updateColor(mContext, rshape.color);
if (rshape.stroke) { if (rshape.stroke) {
if (flags & RenderUpdateFlag::GradientStroke && rshape.stroke->fill) renderDataShape->renderSettingsStroke.updateFill(mContext, rshape.stroke->fill); if (flags & RenderUpdateFlag::GradientStroke && rshape.stroke->fill) renderDataShape->renderSettingsStroke.update(mContext, rshape.stroke->fill);
else if (flags & RenderUpdateFlag::Stroke) renderDataShape->renderSettingsStroke.updateColor(mContext, rshape.stroke->color); else if (flags & RenderUpdateFlag::Stroke) renderDataShape->renderSettingsStroke.update(mContext, rshape.stroke->color);
} }
// store clips data // store clips data
@ -177,9 +177,8 @@ RenderData WgRenderer::prepare(RenderSurface* surface, RenderData data, const Ma
// update paint settings // update paint settings
renderDataPicture->viewport = mViewport; renderDataPicture->viewport = mViewport;
renderDataPicture->opacity = opacity;
if (flags & (RenderUpdateFlag::Transform | RenderUpdateFlag::Blend)) { if (flags & (RenderUpdateFlag::Transform | RenderUpdateFlag::Blend)) {
renderDataPicture->update(mContext, transform, surface->cs, opacity); renderDataPicture->renderSettings.update(mContext, transform, surface->cs, opacity);
} }
// update image data // update image data
@ -193,6 +192,7 @@ RenderData WgRenderer::prepare(RenderSurface* surface, RenderData data, const Ma
return renderDataPicture; return renderDataPicture;
} }
bool WgRenderer::preRender() bool WgRenderer::preRender()
{ {
// invalidate context // invalidate context

View file

@ -23,8 +23,6 @@
#include "tvgWgShaderSrc.h" #include "tvgWgShaderSrc.h"
#include <string> #include <string>
#define WG_SHADER_SOURCE(...) #__VA_ARGS__
//************************************************************************ //************************************************************************
// graphics shader source: stencil // graphics shader source: stencil
//************************************************************************ //************************************************************************
@ -32,14 +30,15 @@
const char* cShaderSrc_Stencil = R"( const char* cShaderSrc_Stencil = R"(
struct VertexInput { @location(0) position: vec2f }; struct VertexInput { @location(0) position: vec2f };
struct VertexOutput { @builtin(position) position: vec4f }; struct VertexOutput { @builtin(position) position: vec4f };
struct PaintSettings { transform: mat4x4f };
@group(0) @binding(0) var<uniform> uViewMat : mat4x4f; @group(0) @binding(0) var<uniform> uViewMat : mat4x4f;
@group(1) @binding(0) var<uniform> uModelMat : mat4x4f; @group(1) @binding(0) var<uniform> uPaintSettings : PaintSettings;
@vertex @vertex
fn vs_main(in: VertexInput) -> VertexOutput { fn vs_main(in: VertexInput) -> VertexOutput {
var out: VertexOutput; var out: VertexOutput;
out.position = uViewMat * uModelMat * vec4f(in.position.xy, 0.0, 1.0); out.position = uViewMat * uPaintSettings.transform * vec4f(in.position.xy, 0.0, 1.0);
return out; return out;
} }
@ -56,15 +55,16 @@ fn fs_main(in: VertexOutput) -> @location(0) vec4f {
const char* cShaderSrc_Depth = R"( const char* cShaderSrc_Depth = R"(
struct VertexInput { @location(0) position: vec2f }; struct VertexInput { @location(0) position: vec2f };
struct VertexOutput { @builtin(position) position: vec4f }; struct VertexOutput { @builtin(position) position: vec4f };
struct PaintSettings { transform: mat4x4f };
@group(0) @binding(0) var<uniform> uViewMat : mat4x4f; @group(0) @binding(0) var<uniform> uViewMat : mat4x4f;
@group(1) @binding(0) var<uniform> uModelMat : mat4x4f; @group(1) @binding(0) var<uniform> uPaintSettings : PaintSettings;
@group(2) @binding(0) var<uniform> uDepth : f32; @group(2) @binding(0) var<uniform> uDepth : f32;
@vertex @vertex
fn vs_main(in: VertexInput) -> VertexOutput { fn vs_main(in: VertexInput) -> VertexOutput {
var out: VertexOutput; var out: VertexOutput;
out.position = uViewMat * uModelMat * vec4f(in.position.xy, 0.0, 1.0); out.position = uViewMat * uPaintSettings.transform * vec4f(in.position.xy, 0.0, 1.0);
out.position.z = uDepth; out.position.z = uDepth;
return out; return out;
} }
@ -82,23 +82,22 @@ fn fs_main(in: VertexOutput) -> @location(0) vec4f {
const char* cShaderSrc_Solid = R"( const char* cShaderSrc_Solid = R"(
struct VertexInput { @location(0) position: vec2f }; struct VertexInput { @location(0) position: vec2f };
struct VertexOutput { @builtin(position) position: vec4f }; struct VertexOutput { @builtin(position) position: vec4f };
struct PaintSettings { transform: mat4x4f, options: vec4f, color: vec4f };
@group(0) @binding(0) var<uniform> uViewMat : mat4x4f; @group(0) @binding(0) var<uniform> uViewMat : mat4x4f;
@group(1) @binding(0) var<uniform> uModelMat : mat4x4f; @group(1) @binding(0) var<uniform> uPaintSettings : PaintSettings;
@group(1) @binding(1) var<uniform> uBlendSettings : vec4f;
@group(2) @binding(0) var<uniform> uSolidColor : vec4f;
@vertex @vertex
fn vs_main(in: VertexInput) -> VertexOutput { fn vs_main(in: VertexInput) -> VertexOutput {
var out: VertexOutput; var out: VertexOutput;
out.position = uViewMat * uModelMat * vec4f(in.position.xy, 0.0, 1.0); out.position = uViewMat * uPaintSettings.transform * vec4f(in.position.xy, 0.0, 1.0);
return out; return out;
} }
@fragment @fragment
fn fs_main(in: VertexOutput) -> @location(0) vec4f { fn fs_main(in: VertexOutput) -> @location(0) vec4f {
let Sc = uSolidColor; let Sc = uPaintSettings.color;
let So = uBlendSettings.a; let So = uPaintSettings.options.a;
return vec4f(Sc.rgb * Sc.a * So, Sc.a * So); return vec4f(Sc.rgb * Sc.a * So, Sc.a * So);
} }
)"; )";
@ -110,34 +109,32 @@ fn fs_main(in: VertexOutput) -> @location(0) vec4f {
const char* cShaderSrc_Linear = R"( const char* cShaderSrc_Linear = R"(
struct VertexInput { @location(0) position: vec2f }; struct VertexInput { @location(0) position: vec2f };
struct VertexOutput { @builtin(position) position : vec4f, @location(0) vGradCoord : vec4f }; struct VertexOutput { @builtin(position) position : vec4f, @location(0) vGradCoord : vec4f };
struct GradSettings { settings: vec4f, focal: vec4f }; struct GradSettings { transform: mat4x4f, coords: vec4f, focal: vec4f };
struct PaintSettings { transform: mat4x4f, options: vec4f, color: vec4f, gradient: GradSettings };
// uniforms // uniforms
@group(0) @binding(0) var<uniform> uViewMat : mat4x4f; @group(0) @binding(0) var<uniform> uViewMat : mat4x4f;
@group(1) @binding(0) var<uniform> uModelMat : mat4x4f; @group(1) @binding(0) var<uniform> uPaintSettings : PaintSettings;
@group(1) @binding(1) var<uniform> uBlendSettings : vec4f;
@group(2) @binding(0) var uSamplerGrad : sampler; @group(2) @binding(0) var uSamplerGrad : sampler;
@group(2) @binding(1) var uTextureGrad : texture_2d<f32>; @group(2) @binding(1) var uTextureGrad : texture_2d<f32>;
@group(2) @binding(2) var<uniform> uSettingGrad : GradSettings;
@group(2) @binding(3) var<uniform> uTransformGrad : mat4x4f;
@vertex @vertex
fn vs_main(in: VertexInput) -> VertexOutput { fn vs_main(in: VertexInput) -> VertexOutput {
var out: VertexOutput; var out: VertexOutput;
out.position = uViewMat * uModelMat * vec4f(in.position.xy, 0.0, 1.0); out.position = uViewMat * uPaintSettings.transform * vec4f(in.position.xy, 0.0, 1.0);
out.vGradCoord = uTransformGrad * vec4f(in.position.xy, 0.0, 1.0); out.vGradCoord = uPaintSettings.gradient.transform * vec4f(in.position.xy, 0.0, 1.0);
return out; return out;
} }
@fragment @fragment
fn fs_main(in: VertexOutput) -> @location(0) vec4f { fn fs_main(in: VertexOutput) -> @location(0) vec4f {
let pos = in.vGradCoord.xy; let pos = in.vGradCoord.xy;
let st = uSettingGrad.settings.xy; let st = uPaintSettings.gradient.coords.xy;
let ed = uSettingGrad.settings.zw; let ed = uPaintSettings.gradient.coords.zw;
let ba = ed - st; let ba = ed - st;
let t = dot(pos - st, ba) / dot(ba, ba); let t = dot(pos - st, ba) / dot(ba, ba);
let Sc = textureSample(uTextureGrad, uSamplerGrad, vec2f(t, 0.5)); let Sc = textureSample(uTextureGrad, uSamplerGrad, vec2f(t, 0.5));
let So = uBlendSettings.a; let So = uPaintSettings.options.a;
return vec4f(Sc.rgb * Sc.a * So, Sc.a * So); return vec4f(Sc.rgb * Sc.a * So, Sc.a * So);
} }
)"; )";
@ -149,37 +146,35 @@ fn fs_main(in: VertexOutput) -> @location(0) vec4f {
const char* cShaderSrc_Radial = R"( const char* cShaderSrc_Radial = R"(
struct VertexInput { @location(0) position: vec2f }; struct VertexInput { @location(0) position: vec2f };
struct VertexOutput { @builtin(position) position : vec4f, @location(0) vGradCoord : vec4f }; struct VertexOutput { @builtin(position) position : vec4f, @location(0) vGradCoord : vec4f };
struct GradSettings { settings: vec4f, focal: vec4f }; struct GradSettings { transform: mat4x4f, coords: vec4f, focal: vec4f };
struct PaintSettings { transform: mat4x4f, options: vec4f, color: vec4f, gradient: GradSettings };
@group(0) @binding(0) var<uniform> uViewMat : mat4x4f; @group(0) @binding(0) var<uniform> uViewMat : mat4x4f;
@group(1) @binding(0) var<uniform> uModelMat : mat4x4f; @group(1) @binding(0) var<uniform> uPaintSettings : PaintSettings;
@group(1) @binding(1) var<uniform> uBlendSettings : vec4f;
@group(2) @binding(0) var uSamplerGrad : sampler; @group(2) @binding(0) var uSamplerGrad : sampler;
@group(2) @binding(1) var uTextureGrad : texture_2d<f32>; @group(2) @binding(1) var uTextureGrad : texture_2d<f32>;
@group(2) @binding(2) var<uniform> uSettingGrad : GradSettings;
@group(2) @binding(3) var<uniform> uTransformGrad : mat4x4f;
@vertex @vertex
fn vs_main(in: VertexInput) -> VertexOutput { fn vs_main(in: VertexInput) -> VertexOutput {
var out: VertexOutput; var out: VertexOutput;
out.position = uViewMat * uModelMat * vec4f(in.position.xy, 0.0, 1.0); out.position = uViewMat * uPaintSettings.transform * vec4f(in.position.xy, 0.0, 1.0);
out.vGradCoord = uTransformGrad * vec4f(in.position.xy, 0.0, 1.0); out.vGradCoord = uPaintSettings.gradient.transform * vec4f(in.position.xy, 0.0, 1.0);
return out; return out;
} }
@fragment @fragment
fn fs_main(in: VertexOutput) -> @location(0) vec4f { fn fs_main(in: VertexOutput) -> @location(0) vec4f {
// orignal data // orignal data
let d0 = in.vGradCoord.xy - uSettingGrad.settings.xy; let d0 = in.vGradCoord.xy - uPaintSettings.gradient.coords.xy;
let d1 = uSettingGrad.settings.xy - uSettingGrad.focal.xy; let d1 = uPaintSettings.gradient.coords.xy - uPaintSettings.gradient.focal.xy;
let r0 = uSettingGrad.settings.z; let r0 = uPaintSettings.gradient.coords.z;
let rd = uSettingGrad.focal.z - uSettingGrad.settings.z; let rd = uPaintSettings.gradient.focal.z - uPaintSettings.gradient.coords.z;
let a = 1.0*dot(d1, d1) - 1.0*rd*rd; let a = 1.0*dot(d1, d1) - 1.0*rd*rd;
let b = 2.0*dot(d0, d1) - 2.0*r0*rd; let b = 2.0*dot(d0, d1) - 2.0*r0*rd;
let c = 1.0*dot(d0, d0) - 1.0*r0*r0; let c = 1.0*dot(d0, d0) - 1.0*r0*r0;
let t = (-b + sqrt(b*b - 4*a*c))/(2*a); let t = (-b + sqrt(b*b - 4*a*c))/(2*a);
let Sc = textureSample(uTextureGrad, uSamplerGrad, vec2f(1.0 - t, 0.5)); let Sc = textureSample(uTextureGrad, uSamplerGrad, vec2f(1.0 - t, 0.5));
let So = uBlendSettings.a; let So = uPaintSettings.options.a;
return vec4f(Sc.rgb * Sc.a * So, Sc.a * So); return vec4f(Sc.rgb * Sc.a * So, Sc.a * So);
} }
)"; )";
@ -191,17 +186,17 @@ fn fs_main(in: VertexOutput) -> @location(0) vec4f {
const char* cShaderSrc_Image = R"( const char* cShaderSrc_Image = R"(
struct VertexInput { @location(0) position: vec2f, @location(1) texCoord: vec2f }; struct VertexInput { @location(0) position: vec2f, @location(1) texCoord: vec2f };
struct VertexOutput { @builtin(position) position: vec4f, @location(0) vTexCoord: vec2f }; struct VertexOutput { @builtin(position) position: vec4f, @location(0) vTexCoord: vec2f };
struct PaintSettings { transform: mat4x4f, options: vec4f };
@group(0) @binding(0) var<uniform> uViewMat : mat4x4f; @group(0) @binding(0) var<uniform> uViewMat : mat4x4f;
@group(1) @binding(0) var<uniform> uModelMat : mat4x4f; @group(1) @binding(0) var<uniform> uPaintSettings : PaintSettings;
@group(1) @binding(1) var<uniform> uBlendSettings : vec4f;
@group(2) @binding(0) var uSampler : sampler; @group(2) @binding(0) var uSampler : sampler;
@group(2) @binding(1) var uTextureView : texture_2d<f32>; @group(2) @binding(1) var uTextureView : texture_2d<f32>;
@vertex @vertex
fn vs_main(in: VertexInput) -> VertexOutput { fn vs_main(in: VertexInput) -> VertexOutput {
var out: VertexOutput; var out: VertexOutput;
out.position = uViewMat * uModelMat * vec4f(in.position.xy, 0.0, 1.0); out.position = uViewMat * uPaintSettings.transform * vec4f(in.position.xy, 0.0, 1.0);
out.vTexCoord = in.texCoord; out.vTexCoord = in.texCoord;
return out; return out;
} }
@ -209,7 +204,7 @@ fn vs_main(in: VertexInput) -> VertexOutput {
@fragment @fragment
fn fs_main(in: VertexOutput) -> @location(0) vec4f { fn fs_main(in: VertexOutput) -> @location(0) vec4f {
var Sc: vec4f = textureSample(uTextureView, uSampler, in.vTexCoord.xy); var Sc: vec4f = textureSample(uTextureView, uSampler, in.vTexCoord.xy);
let So: f32 = uBlendSettings.a; let So: f32 = uPaintSettings.options.a;
return vec4f(Sc.rgb * Sc.a * So, Sc.a * So); return vec4f(Sc.rgb * Sc.a * So, Sc.a * So);
}; };
)"; )";
@ -248,18 +243,18 @@ fn fs_main(in: VertexOutput) -> @location(0) vec4f {
const char* cShaderSrc_Solid_Blend = R"( const char* cShaderSrc_Solid_Blend = R"(
struct VertexInput { @location(0) position: vec2f }; struct VertexInput { @location(0) position: vec2f };
struct VertexOutput { @builtin(position) position: vec4f, @location(1) vScrCoord: vec2f }; struct VertexOutput { @builtin(position) position: vec4f, @location(1) vScrCoord: vec2f };
struct PaintSettings { transform: mat4x4f, options: vec4f, color: vec4f };
@group(0) @binding(0) var<uniform> uViewMat : mat4x4f; @group(0) @binding(0) var<uniform> uViewMat : mat4x4f;
@group(1) @binding(0) var<uniform> uModelMat : mat4x4f; @group(1) @binding(0) var<uniform> uPaintSettings : PaintSettings;
@group(1) @binding(1) var<uniform> uBlendSettings : vec4f; // @group(2) - empty
@group(2) @binding(0) var<uniform> uSolidColor : vec4f;
@group(3) @binding(0) var uSamplerDst : sampler; @group(3) @binding(0) var uSamplerDst : sampler;
@group(3) @binding(1) var uTextureDst : texture_2d<f32>; @group(3) @binding(1) var uTextureDst : texture_2d<f32>;
@vertex @vertex
fn vs_main(in: VertexInput) -> VertexOutput { fn vs_main(in: VertexInput) -> VertexOutput {
var out: VertexOutput; var out: VertexOutput;
let pos = uViewMat * uModelMat * vec4f(in.position.xy, 0.0, 1.0); let pos = uViewMat * uPaintSettings.transform * vec4f(in.position.xy, 0.0, 1.0);
out.position = pos; out.position = pos;
out.vScrCoord = vec2f(0.5 + pos.x * 0.5, 0.5 - pos.y * 0.5); out.vScrCoord = vec2f(0.5 + pos.x * 0.5, 0.5 - pos.y * 0.5);
return out; return out;
@ -268,13 +263,13 @@ fn vs_main(in: VertexInput) -> VertexOutput {
struct FragData { Sc: vec3f, Sa: f32, So: f32, Dc: vec3f, Da: f32 }; struct FragData { Sc: vec3f, Sa: f32, So: f32, Dc: vec3f, Da: f32 };
fn getFragData(in: VertexOutput) -> FragData { fn getFragData(in: VertexOutput) -> FragData {
// get source data // get source data
let colorSrc = uSolidColor; let colorSrc = uPaintSettings.color;
let colorDst = textureSample(uTextureDst, uSamplerDst, in.vScrCoord.xy); let colorDst = textureSample(uTextureDst, uSamplerDst, in.vScrCoord.xy);
// fill fragment data // fill fragment data
var data: FragData; var data: FragData;
data.Sc = colorSrc.rgb; data.Sc = colorSrc.rgb;
data.Sa = colorSrc.a; data.Sa = colorSrc.a;
data.So = uBlendSettings.a; data.So = uPaintSettings.options.a;
data.Dc = colorDst.rgb; data.Dc = colorDst.rgb;
data.Da = colorDst.a; data.Da = colorDst.a;
data.Sc = data.Sa * data.So * data.Sc; data.Sc = data.Sa * data.So * data.Sc;
@ -288,24 +283,22 @@ fn postProcess(d: FragData, R: vec4f) -> vec4f { return R; };
const char* cShaderSrc_Linear_Blend = R"( const char* cShaderSrc_Linear_Blend = R"(
struct VertexInput { @location(0) position: vec2f }; struct VertexInput { @location(0) position: vec2f };
struct VertexOutput { @builtin(position) position: vec4f, @location(0) vGradCoord : vec4f, @location(1) vScrCoord: vec2f }; struct VertexOutput { @builtin(position) position: vec4f, @location(0) vGradCoord : vec4f, @location(1) vScrCoord: vec2f };
struct GradSettings { settings: vec4f, focal: vec4f }; struct GradSettings { transform: mat4x4f, coords: vec4f, focal: vec4f };
struct PaintSettings { transform: mat4x4f, options: vec4f, color: vec4f, gradient: GradSettings };
@group(0) @binding(0) var<uniform> uViewMat : mat4x4f; @group(0) @binding(0) var<uniform> uViewMat : mat4x4f;
@group(1) @binding(0) var<uniform> uModelMat : mat4x4f; @group(1) @binding(0) var<uniform> uPaintSettings : PaintSettings;
@group(1) @binding(1) var<uniform> uBlendSettings : vec4f;
@group(2) @binding(0) var uSamplerGrad : sampler; @group(2) @binding(0) var uSamplerGrad : sampler;
@group(2) @binding(1) var uTextureGrad : texture_2d<f32>; @group(2) @binding(1) var uTextureGrad : texture_2d<f32>;
@group(2) @binding(2) var<uniform> uSettingGrad : vec4f;
@group(2) @binding(3) var<uniform> uTransformGrad : mat4x4f;
@group(3) @binding(0) var uSamplerDst : sampler; @group(3) @binding(0) var uSamplerDst : sampler;
@group(3) @binding(1) var uTextureDst : texture_2d<f32>; @group(3) @binding(1) var uTextureDst : texture_2d<f32>;
@vertex @vertex
fn vs_main(in: VertexInput) -> VertexOutput { fn vs_main(in: VertexInput) -> VertexOutput {
var out: VertexOutput; var out: VertexOutput;
let pos = uViewMat * uModelMat * vec4f(in.position.xy, 0.0, 1.0); let pos = uViewMat * uPaintSettings.transform * vec4f(in.position.xy, 0.0, 1.0);
out.position = pos; out.position = pos;
out.vGradCoord = uTransformGrad * vec4f(in.position.xy, 0.0, 1.0); out.vGradCoord = uPaintSettings.gradient.transform * vec4f(in.position.xy, 0.0, 1.0);
out.vScrCoord = vec2f(0.5 + pos.x * 0.5, 0.5 - pos.y * 0.5); out.vScrCoord = vec2f(0.5 + pos.x * 0.5, 0.5 - pos.y * 0.5);
return out; return out;
} }
@ -314,8 +307,8 @@ struct FragData { Sc: vec3f, Sa: f32, So: f32, Dc: vec3f, Da: f32 };
fn getFragData(in: VertexOutput) -> FragData { fn getFragData(in: VertexOutput) -> FragData {
// get source data // get source data
let pos = in.vGradCoord.xy; let pos = in.vGradCoord.xy;
let st = uSettingGrad.xy; let st = uPaintSettings.gradient.coords.xy;
let ed = uSettingGrad.zw; let ed = uPaintSettings.gradient.coords.zw;
let ba = ed - st; let ba = ed - st;
let t = dot(pos - st, ba) / dot(ba, ba); let t = dot(pos - st, ba) / dot(ba, ba);
let colorSrc = textureSample(uTextureGrad, uSamplerGrad, vec2f(t, 0.5)); let colorSrc = textureSample(uTextureGrad, uSamplerGrad, vec2f(t, 0.5));
@ -324,7 +317,7 @@ fn getFragData(in: VertexOutput) -> FragData {
var data: FragData; var data: FragData;
data.Sc = colorSrc.rgb; data.Sc = colorSrc.rgb;
data.Sa = colorSrc.a; data.Sa = colorSrc.a;
data.So = uBlendSettings.a; data.So = uPaintSettings.options.a;
data.Dc = colorDst.rgb; data.Dc = colorDst.rgb;
data.Da = colorDst.a; data.Da = colorDst.a;
data.Sc = mix(data.Dc, data.Sc, data.Sa * data.So); data.Sc = mix(data.Dc, data.Sc, data.Sa * data.So);
@ -338,34 +331,32 @@ fn postProcess(d: FragData, R: vec4f) -> vec4f { return R; };
const char* cShaderSrc_Radial_Blend = R"( const char* cShaderSrc_Radial_Blend = R"(
struct VertexInput { @location(0) position: vec2f }; struct VertexInput { @location(0) position: vec2f };
struct VertexOutput { @builtin(position) position: vec4f, @location(0) vGradCoord : vec4f, @location(1) vScrCoord: vec2f }; struct VertexOutput { @builtin(position) position: vec4f, @location(0) vGradCoord : vec4f, @location(1) vScrCoord: vec2f };
struct GradSettings { settings: vec4f, focal: vec4f }; struct GradSettings { transform: mat4x4f, coords: vec4f, focal: vec4f };
struct PaintSettings { transform: mat4x4f, options: vec4f, color: vec4f, gradient: GradSettings };
@group(0) @binding(0) var<uniform> uViewMat : mat4x4f; @group(0) @binding(0) var<uniform> uViewMat : mat4x4f;
@group(1) @binding(0) var<uniform> uModelMat : mat4x4f; @group(1) @binding(0) var<uniform> uPaintSettings : PaintSettings;
@group(1) @binding(1) var<uniform> uBlendSettings : vec4f;
@group(2) @binding(0) var uSamplerGrad : sampler; @group(2) @binding(0) var uSamplerGrad : sampler;
@group(2) @binding(1) var uTextureGrad : texture_2d<f32>; @group(2) @binding(1) var uTextureGrad : texture_2d<f32>;
@group(2) @binding(2) var<uniform> uSettingGrad : GradSettings;
@group(2) @binding(3) var<uniform> uTransformGrad : mat4x4f;
@group(3) @binding(0) var uSamplerDst : sampler; @group(3) @binding(0) var uSamplerDst : sampler;
@group(3) @binding(1) var uTextureDst : texture_2d<f32>; @group(3) @binding(1) var uTextureDst : texture_2d<f32>;
@vertex @vertex
fn vs_main(in: VertexInput) -> VertexOutput { fn vs_main(in: VertexInput) -> VertexOutput {
var out: VertexOutput; var out: VertexOutput;
let pos = uViewMat * uModelMat * vec4f(in.position.xy, 0.0, 1.0); let pos = uViewMat * uPaintSettings.transform * vec4f(in.position.xy, 0.0, 1.0);
out.position = pos; out.position = pos;
out.vGradCoord = uTransformGrad * vec4f(in.position.xy, 0.0, 1.0); out.vGradCoord = uPaintSettings.gradient.transform * vec4f(in.position.xy, 0.0, 1.0);
out.vScrCoord = vec2f(0.5 + pos.x * 0.5, 0.5 - pos.y * 0.5); out.vScrCoord = vec2f(0.5 + pos.x * 0.5, 0.5 - pos.y * 0.5);
return out; return out;
} }
struct FragData { Sc: vec3f, Sa: f32, So: f32, Dc: vec3f, Da: f32 }; struct FragData { Sc: vec3f, Sa: f32, So: f32, Dc: vec3f, Da: f32 };
fn getFragData(in: VertexOutput) -> FragData { fn getFragData(in: VertexOutput) -> FragData {
let d0 = in.vGradCoord.xy - uSettingGrad.settings.xy; let d0 = in.vGradCoord.xy - uPaintSettings.gradient.coords.xy;
let d1 = uSettingGrad.settings.xy - uSettingGrad.focal.xy; let d1 = uPaintSettings.gradient.coords.xy - uPaintSettings.gradient.focal.xy;
let r0 = uSettingGrad.settings.z; let r0 = uPaintSettings.gradient.coords.z;
let rd = uSettingGrad.focal.z - uSettingGrad.settings.z; let rd = uPaintSettings.gradient.focal.z - uPaintSettings.gradient.coords.z;
let a = 1.0*dot(d1, d1) - 1.0*rd*rd; let a = 1.0*dot(d1, d1) - 1.0*rd*rd;
let b = 2.0*dot(d0, d1) - 2.0*r0*rd; let b = 2.0*dot(d0, d1) - 2.0*r0*rd;
let c = 1.0*dot(d0, d0) - 1.0*r0*r0; let c = 1.0*dot(d0, d0) - 1.0*r0*r0;
@ -376,7 +367,7 @@ fn getFragData(in: VertexOutput) -> FragData {
var data: FragData; var data: FragData;
data.Sc = colorSrc.rgb; data.Sc = colorSrc.rgb;
data.Sa = colorSrc.a; data.Sa = colorSrc.a;
data.So = uBlendSettings.a; data.So = uPaintSettings.options.a;
data.Dc = colorDst.rgb; data.Dc = colorDst.rgb;
data.Da = colorDst.a; data.Da = colorDst.a;
data.Sc = mix(data.Dc, data.Sc, data.Sa * data.So); data.Sc = mix(data.Dc, data.Sc, data.Sa * data.So);
@ -390,11 +381,11 @@ fn postProcess(d: FragData, R: vec4f) -> vec4f { return R; };
const char* cShaderSrc_Image_Blend = R"( const char* cShaderSrc_Image_Blend = R"(
struct VertexInput { @location(0) position: vec2f, @location(1) texCoord: vec2f }; struct VertexInput { @location(0) position: vec2f, @location(1) texCoord: vec2f };
struct VertexOutput { @builtin(position) position: vec4f, @location(0) vTexCoord : vec2f, @location(1) vScrCoord: vec2f }; struct VertexOutput { @builtin(position) position: vec4f, @location(0) vTexCoord : vec2f, @location(1) vScrCoord: vec2f };
struct PaintSettings { transform: mat4x4f, options: vec4f };
@group(0) @binding(0) var<uniform> uViewMat : mat4x4f; @group(0) @binding(0) var<uniform> uViewMat : mat4x4f;
@group(1) @binding(0) var<uniform> uModelMat : mat4x4f; @group(1) @binding(0) var<uniform> uPaintSettings : PaintSettings;
@group(1) @binding(1) var<uniform> uBlendSettings : vec4f; @group(2) @binding(0) var uSamplerSrc : sampler;
@group(2) @binding(0) var uSamplerSrc : sampler;
@group(2) @binding(1) var uTextureSrc : texture_2d<f32>; @group(2) @binding(1) var uTextureSrc : texture_2d<f32>;
@group(3) @binding(0) var uSamplerDst : sampler; @group(3) @binding(0) var uSamplerDst : sampler;
@group(3) @binding(1) var uTextureDst : texture_2d<f32>; @group(3) @binding(1) var uTextureDst : texture_2d<f32>;
@ -402,7 +393,7 @@ struct VertexOutput { @builtin(position) position: vec4f, @location(0) vTexCoord
@vertex @vertex
fn vs_main(in: VertexInput) -> VertexOutput { fn vs_main(in: VertexInput) -> VertexOutput {
var out: VertexOutput; var out: VertexOutput;
let pos = uViewMat * uModelMat * vec4f(in.position.xy, 0.0, 1.0); let pos = uViewMat * uPaintSettings.transform * vec4f(in.position.xy, 0.0, 1.0);
out.position = pos; out.position = pos;
out.vTexCoord = in.texCoord; out.vTexCoord = in.texCoord;
out.vScrCoord = vec2f(0.5 + pos.x * 0.5, 0.5 - pos.y * 0.5); out.vScrCoord = vec2f(0.5 + pos.x * 0.5, 0.5 - pos.y * 0.5);
@ -418,7 +409,7 @@ fn getFragData(in: VertexOutput) -> FragData {
var data: FragData; var data: FragData;
data.Sc = colorSrc.rgb; data.Sc = colorSrc.rgb;
data.Sa = colorSrc.a; data.Sa = colorSrc.a;
data.So = uBlendSettings.a; data.So = uPaintSettings.options.a;
data.Dc = colorDst.rgb; data.Dc = colorDst.rgb;
data.Da = colorDst.a; data.Da = colorDst.a;
data.Sc = data.Sc * data.So; data.Sc = data.Sc * data.So;

View file

@ -125,35 +125,34 @@ void WgShaderTypeVec4f::update(const RenderRegion& r)
} }
//************************************************************************ //************************************************************************
// WgShaderTypeGradient // WgShaderTypeGradSettings
//************************************************************************ //************************************************************************
void WgShaderTypeGradient::update(const LinearGradient* linearGradient) void WgShaderTypeGradSettings::update(const Fill* fill)
{ {
// update gradient data assert(fill);
// update transform matrix
Matrix invTransform;
if (inverse(&fill->transform(), &invTransform))
transform.update(invTransform);
else transform.identity();
// update gradient base points
if (fill->type() == Type::LinearGradient)
((LinearGradient*)fill)->linear(&coords.vec[0], &coords.vec[1], &coords.vec[2], &coords.vec[3]);
else if (fill->type() == Type::RadialGradient)
((RadialGradient*)fill)->radial(&coords.vec[0], &coords.vec[1], &coords.vec[2], &focal.vec[0], &focal.vec[1], &focal.vec[2]);
}
//************************************************************************
// WgShaderTypeGradientData
//************************************************************************
void WgShaderTypeGradientData::update(const Fill* fill)
{
if (!fill) return;
const Fill::ColorStop* stops = nullptr; const Fill::ColorStop* stops = nullptr;
auto stopCnt = linearGradient->colorStops(&stops); auto stopCnt = fill->colorStops(&stops);
updateTexData(stops, stopCnt);
// update base points
linearGradient->linear(&settings[0], &settings[1], &settings[2], &settings[3]);
};
void WgShaderTypeGradient::update(const RadialGradient* radialGradient)
{
// update gradient data
const Fill::ColorStop* stops = nullptr;
auto stopCnt = radialGradient->colorStops(&stops);
updateTexData(stops, stopCnt);
// update base points
radialGradient->radial(&settings[0], &settings[1], &settings[2], &settings[4], &settings[5], &settings[6]);
};
void WgShaderTypeGradient::updateTexData(const Fill::ColorStop* stops, uint32_t stopCnt)
{
if (stopCnt == 0) return; if (stopCnt == 0) return;
static Array<Fill::ColorStop> sstops(stopCnt); static Array<Fill::ColorStop> sstops(stopCnt);
sstops.clear(); sstops.clear();
sstops.push(stops[0]); sstops.push(stops[0]);
@ -167,10 +166,10 @@ void WgShaderTypeGradient::updateTexData(const Fill::ColorStop* stops, uint32_t
uint32_t range_s = 0; uint32_t range_s = 0;
uint32_t range_e = uint32_t(sstops[0].offset * (WG_TEXTURE_GRADIENT_SIZE-1)); uint32_t range_e = uint32_t(sstops[0].offset * (WG_TEXTURE_GRADIENT_SIZE-1));
for (uint32_t ti = range_s; (ti < range_e) && (ti < WG_TEXTURE_GRADIENT_SIZE); ti++) { for (uint32_t ti = range_s; (ti < range_e) && (ti < WG_TEXTURE_GRADIENT_SIZE); ti++) {
texData[ti * 4 + 0] = sstops[0].r; data[ti * 4 + 0] = sstops[0].r;
texData[ti * 4 + 1] = sstops[0].g; data[ti * 4 + 1] = sstops[0].g;
texData[ti * 4 + 2] = sstops[0].b; data[ti * 4 + 2] = sstops[0].b;
texData[ti * 4 + 3] = sstops[0].a; data[ti * 4 + 3] = sstops[0].a;
} }
// body // body
for (uint32_t di = 1; di < sstops.count; di++) { for (uint32_t di = 1; di < sstops.count; di++) {
@ -179,10 +178,10 @@ void WgShaderTypeGradient::updateTexData(const Fill::ColorStop* stops, uint32_t
float delta = 1.0f/(range_e - range_s); float delta = 1.0f/(range_e - range_s);
for (uint32_t ti = range_s; (ti < range_e) && (ti < WG_TEXTURE_GRADIENT_SIZE); ti++) { for (uint32_t ti = range_s; (ti < range_e) && (ti < WG_TEXTURE_GRADIENT_SIZE); ti++) {
float t = (ti - range_s) * delta; float t = (ti - range_s) * delta;
texData[ti * 4 + 0] = tvg::lerp(sstops[di-1].r, sstops[di].r, t); data[ti * 4 + 0] = tvg::lerp(sstops[di-1].r, sstops[di].r, t);
texData[ti * 4 + 1] = tvg::lerp(sstops[di-1].g, sstops[di].g, t); data[ti * 4 + 1] = tvg::lerp(sstops[di-1].g, sstops[di].g, t);
texData[ti * 4 + 2] = tvg::lerp(sstops[di-1].b, sstops[di].b, t); data[ti * 4 + 2] = tvg::lerp(sstops[di-1].b, sstops[di].b, t);
texData[ti * 4 + 3] = tvg::lerp(sstops[di-1].a, sstops[di].a, t); data[ti * 4 + 3] = tvg::lerp(sstops[di-1].a, sstops[di].a, t);
} }
} }
// tail // tail
@ -190,10 +189,10 @@ void WgShaderTypeGradient::updateTexData(const Fill::ColorStop* stops, uint32_t
range_s = uint32_t(colorStopLast.offset * (WG_TEXTURE_GRADIENT_SIZE-1)); range_s = uint32_t(colorStopLast.offset * (WG_TEXTURE_GRADIENT_SIZE-1));
range_e = WG_TEXTURE_GRADIENT_SIZE; range_e = WG_TEXTURE_GRADIENT_SIZE;
for (uint32_t ti = range_s; ti < range_e; ti++) { for (uint32_t ti = range_s; ti < range_e; ti++) {
texData[ti * 4 + 0] = colorStopLast.r; data[ti * 4 + 0] = colorStopLast.r;
texData[ti * 4 + 1] = colorStopLast.g; data[ti * 4 + 1] = colorStopLast.g;
texData[ti * 4 + 2] = colorStopLast.b; data[ti * 4 + 2] = colorStopLast.b;
texData[ti * 4 + 3] = colorStopLast.a; data[ti * 4 + 3] = colorStopLast.a;
} }
} }

View file

@ -55,16 +55,44 @@ struct WgShaderTypeVec4f
void update(const RenderRegion& r); void update(const RenderRegion& r);
}; };
// sampler, texture, vec4f // WGSL: struct GradSettings { transform: mat4x4f, coords: vec4f, focal: vec4f };
#define WG_TEXTURE_GRADIENT_SIZE 512 struct WgShaderTypeGradSettings
struct WgShaderTypeGradient
{ {
float settings[4+4]{}; // WGSL: struct GradSettings { settings: vec4f, focal: vec4f; transform: mat4f }; // gradient transform matrix
uint8_t texData[WG_TEXTURE_GRADIENT_SIZE * 4]; WgShaderTypeMat4x4f transform;
// linear: [0] - x1, [1] - y1, [2] - x2, [3] - y2
// radial: [0] - cx, [1] - cy, [2] - cr
WgShaderTypeVec4f coords;
// radial: [0] - fx, [1] - fy, [2] - fr
WgShaderTypeVec4f focal;
void update(const Fill* fill);
};
void update(const LinearGradient* linearGradient); // WGSL: struct PaintSettings { transform: mat4x4f, options: vec4f, color: vec4f, gradient: GradSettings };
void update(const RadialGradient* radialGradient); struct WgShaderTypePaintSettings
void updateTexData(const Fill::ColorStop* stops, uint32_t stopCnt); {
// paint transform matrix (must be at offset 0)
WgShaderTypeMat4x4f transform;
// [0] - color space, [3] - opacity
WgShaderTypeVec4f options;
// solid color
WgShaderTypeVec4f color;
// gradient settings (linear/radial)
WgShaderTypeGradSettings gradient;
// align to 256 bytes (see webgpu spec: minUniformBufferOffsetAlignment)
uint8_t _padding[256 - sizeof(transform) - sizeof(options) - sizeof(color) - sizeof(gradient)];
};
// see webgpu spec: 3.6.2. Limits - minUniformBufferOffsetAlignment (256)
static_assert(sizeof(WgShaderTypePaintSettings) == 256, "Uniform shader data type size must be aligned to 256 bytes");
// gradient color map
#define WG_TEXTURE_GRADIENT_SIZE 512
struct WgShaderTypeGradientData
{
uint8_t data[WG_TEXTURE_GRADIENT_SIZE * 4];
void update(const Fill* fill);
}; };
// gaussian params: sigma, scale, extend // gaussian params: sigma, scale, extend