From 392f59db9d140f6e35e462c34fad3821a6edc830 Mon Sep 17 00:00:00 2001 From: Sergii Liebodkin Date: Thu, 4 Apr 2024 17:23:54 +0300 Subject: [PATCH] wg_engine: vertex, index and unifroms buffers, render objects caching [issues 1479: lottie](#1479) Vertex, Index and uniform buffers now updates instead of recreate. Implemented pools form mesh objects and render shapes data it increase performance in 30-40% in massive animations scenes --- src/renderer/wg_engine/tvgWgBindGroups.cpp | 73 ++++++++++------- src/renderer/wg_engine/tvgWgCommon.cpp | 74 +++++++++++------ src/renderer/wg_engine/tvgWgCommon.h | 9 +- src/renderer/wg_engine/tvgWgRenderData.cpp | 95 ++++++++++++++++++---- src/renderer/wg_engine/tvgWgRenderData.h | 23 ++++++ src/renderer/wg_engine/tvgWgRenderer.cpp | 13 ++- src/renderer/wg_engine/tvgWgRenderer.h | 1 + 7 files changed, 215 insertions(+), 73 deletions(-) diff --git a/src/renderer/wg_engine/tvgWgBindGroups.cpp b/src/renderer/wg_engine/tvgWgBindGroups.cpp index 1341074f..74a30c7f 100644 --- a/src/renderer/wg_engine/tvgWgBindGroups.cpp +++ b/src/renderer/wg_engine/tvgWgBindGroups.cpp @@ -98,15 +98,19 @@ void WgBindGroupPaint::releaseLayout() void WgBindGroupPaint::initialize(WGPUDevice device, WGPUQueue queue, WgShaderTypeMat4x4f& uModelMat, WgShaderTypeBlendSettings& uBlendSettings) { - release(); - uBufferModelMat = createBuffer(device, queue, &uModelMat, sizeof(uModelMat)); - uBufferBlendSettings = createBuffer(device, queue, &uBlendSettings, sizeof(uBlendSettings)); - const WGPUBindGroupEntry bindGroupEntries[] { - makeBindGroupEntryBuffer(0, uBufferModelMat), - makeBindGroupEntryBuffer(1, uBufferBlendSettings) - }; - mBindGroup = createBindGroup(device, getLayout(device), bindGroupEntries, 2); - assert(mBindGroup); + if (!uBufferModelMat && !uBufferBlendSettings && !mBindGroup) { + uBufferModelMat = createBuffer(device, queue, &uModelMat, sizeof(uModelMat)); + uBufferBlendSettings = createBuffer(device, queue, &uBlendSettings, sizeof(uBlendSettings)); + const WGPUBindGroupEntry bindGroupEntries[] { + makeBindGroupEntryBuffer(0, uBufferModelMat), + makeBindGroupEntryBuffer(1, uBufferBlendSettings) + }; + mBindGroup = createBindGroup(device, getLayout(device), bindGroupEntries, 2); + assert(mBindGroup); + return; + } + wgpuQueueWriteBuffer(queue, uBufferModelMat, 0, &uModelMat, sizeof(uModelMat)); + wgpuQueueWriteBuffer(queue, uBufferBlendSettings, 0, &uBlendSettings, sizeof(uBlendSettings)); } @@ -138,13 +142,16 @@ void WgBindGroupSolidColor::releaseLayout() void WgBindGroupSolidColor::initialize(WGPUDevice device, WGPUQueue queue, WgShaderTypeSolidColor &uSolidColor) { - release(); - uBufferSolidColor = createBuffer(device, queue, &uSolidColor, sizeof(uSolidColor)); - const WGPUBindGroupEntry bindGroupEntries[] { - makeBindGroupEntryBuffer(0, uBufferSolidColor) - }; - mBindGroup = createBindGroup(device, getLayout(device), bindGroupEntries, 1); - assert(mBindGroup); + if (!uBufferSolidColor && !mBindGroup) { + uBufferSolidColor = createBuffer(device, queue, &uSolidColor, sizeof(uSolidColor)); + const WGPUBindGroupEntry bindGroupEntries[] { + makeBindGroupEntryBuffer(0, uBufferSolidColor) + }; + mBindGroup = createBindGroup(device, getLayout(device), bindGroupEntries, 1); + assert(mBindGroup); + return; + } + wgpuQueueWriteBuffer(queue, uBufferSolidColor, 0, &uSolidColor, sizeof(uSolidColor)); } @@ -175,13 +182,16 @@ void WgBindGroupLinearGradient::releaseLayout() void WgBindGroupLinearGradient::initialize(WGPUDevice device, WGPUQueue queue, WgShaderTypeLinearGradient &uLinearGradient) { - release(); - uBufferLinearGradient = createBuffer(device, queue, &uLinearGradient, sizeof(uLinearGradient)); - const WGPUBindGroupEntry bindGroupEntries[] { - makeBindGroupEntryBuffer(0, uBufferLinearGradient) - }; - mBindGroup = createBindGroup(device, getLayout(device), bindGroupEntries, 1); - assert(mBindGroup); + if (!uBufferLinearGradient && !mBindGroup) { + uBufferLinearGradient = createBuffer(device, queue, &uLinearGradient, sizeof(uLinearGradient)); + const WGPUBindGroupEntry bindGroupEntries[] { + makeBindGroupEntryBuffer(0, uBufferLinearGradient) + }; + mBindGroup = createBindGroup(device, getLayout(device), bindGroupEntries, 1); + assert(mBindGroup); + return; + } + wgpuQueueWriteBuffer(queue, uBufferLinearGradient, 0, &uLinearGradient, sizeof(uLinearGradient)); } @@ -212,13 +222,16 @@ void WgBindGroupRadialGradient::releaseLayout() void WgBindGroupRadialGradient::initialize(WGPUDevice device, WGPUQueue queue, WgShaderTypeRadialGradient &uRadialGradient) { - release(); - uBufferRadialGradient = createBuffer(device, queue, &uRadialGradient, sizeof(uRadialGradient)); - const WGPUBindGroupEntry bindGroupEntries[] { - makeBindGroupEntryBuffer(0, uBufferRadialGradient) - }; - mBindGroup = createBindGroup(device, getLayout(device), bindGroupEntries, 1); - assert(mBindGroup); + if (!uBufferRadialGradient && !mBindGroup) { + uBufferRadialGradient = createBuffer(device, queue, &uRadialGradient, sizeof(uRadialGradient)); + const WGPUBindGroupEntry bindGroupEntries[] { + makeBindGroupEntryBuffer(0, uBufferRadialGradient) + }; + mBindGroup = createBindGroup(device, getLayout(device), bindGroupEntries, 1); + assert(mBindGroup); + return; + } + wgpuQueueWriteBuffer(queue, uBufferRadialGradient, 0, &uRadialGradient, sizeof(uRadialGradient)); } diff --git a/src/renderer/wg_engine/tvgWgCommon.cpp b/src/renderer/wg_engine/tvgWgCommon.cpp index e7f798f2..2c7f9953 100644 --- a/src/renderer/wg_engine/tvgWgCommon.cpp +++ b/src/renderer/wg_engine/tvgWgCommon.cpp @@ -204,30 +204,6 @@ WGPUBuffer WgContext::createBuffer(WGPUBufferUsageFlags usage, uint64_t size,cha } -void WgContext::createOrUpdateBuffer(WGPUBuffer& buffer, WGPUBufferUsageFlags usage, const void *data, uint64_t size, char const * label) -{ - if ((buffer) && (wgpuBufferGetSize(buffer) >= size)) { - // update data in existing buffer - wgpuQueueWriteBuffer(queue, buffer, 0, data, size); - } else { - // create new buffer and upload data - releaseBuffer(buffer); - WGPUBufferDescriptor bufferDesc{}; - bufferDesc.nextInChain = nullptr; - bufferDesc.label = label; - bufferDesc.usage = usage; - bufferDesc.size = size; - bufferDesc.mappedAtCreation = true; - buffer = wgpuDeviceCreateBuffer(device, &bufferDesc); - assert(buffer); - void* buff = wgpuBufferGetMappedRange(buffer, 0, size); - assert(buff); - memcpy(buff, data, size); - wgpuBufferUnmap(buffer); - } -} - - void WgContext::releaseSampler(WGPUSampler& sampler) { if (sampler) { @@ -267,6 +243,56 @@ void WgContext::releaseBuffer(WGPUBuffer& buffer) } +void WgContext::allocateVertexBuffer(WGPUBuffer& buffer, const void *data, uint64_t size) +{ + if ((buffer) && (wgpuBufferGetSize(buffer) >= size)) + wgpuQueueWriteBuffer(queue, buffer, 0, data, size); + else { + // create new buffer and upload data + releaseBuffer(buffer); + WGPUBufferDescriptor bufferDesc{}; + bufferDesc.nextInChain = nullptr; + bufferDesc.label = "The vertex buffer"; + bufferDesc.usage = WGPUBufferUsage_CopyDst | WGPUBufferUsage_Vertex; + bufferDesc.size = size > WG_VERTEX_BUFFER_MIN_SIZE ? size : WG_VERTEX_BUFFER_MIN_SIZE; + bufferDesc.mappedAtCreation = false; + buffer = wgpuDeviceCreateBuffer(device, &bufferDesc); + wgpuQueueWriteBuffer(queue, buffer, 0, data, size); + } +} + + +void WgContext::allocateIndexBuffer(WGPUBuffer& buffer, const void *data, uint64_t size) +{ + if ((buffer) && (wgpuBufferGetSize(buffer) >= size)) + wgpuQueueWriteBuffer(queue, buffer, 0, data, size); + else { + // create new buffer and upload data + releaseBuffer(buffer); + WGPUBufferDescriptor bufferDesc{}; + bufferDesc.nextInChain = nullptr; + bufferDesc.label = "The index buffer"; + bufferDesc.usage = WGPUBufferUsage_CopyDst | WGPUBufferUsage_Index; + bufferDesc.size = size > WG_INDEX_BUFFER_MIN_SIZE ? size : WG_INDEX_BUFFER_MIN_SIZE; + bufferDesc.mappedAtCreation = false; + buffer = wgpuDeviceCreateBuffer(device, &bufferDesc); + wgpuQueueWriteBuffer(queue, buffer, 0, data, size); + } +} + + +void WgContext::releaseVertexBuffer(WGPUBuffer& buffer) +{ + releaseBuffer(buffer); +} + + +void WgContext::releaseIndexBuffer(WGPUBuffer& buffer) +{ + releaseBuffer(buffer); +} + + //***************************************************************************** // bind group //***************************************************************************** diff --git a/src/renderer/wg_engine/tvgWgCommon.h b/src/renderer/wg_engine/tvgWgCommon.h index 7b7a92b4..2415754a 100644 --- a/src/renderer/wg_engine/tvgWgCommon.h +++ b/src/renderer/wg_engine/tvgWgCommon.h @@ -28,6 +28,9 @@ #include "tvgCommon.h" #include "tvgRender.h" +#define WG_VERTEX_BUFFER_MIN_SIZE 2048 +#define WG_INDEX_BUFFER_MIN_SIZE 2048 + enum class WgPipelineBlendType { Src = 0, // S Normal, // (Sa * S) + (255 - Sa) * D @@ -64,12 +67,16 @@ struct WgContext { WGPUTexture createTexture2dMS(WGPUTextureUsageFlags usage, WGPUTextureFormat format, uint32_t width, uint32_t height, uint32_t sc, char const * label); WGPUTextureView createTextureView2d(WGPUTexture texture, char const * label); WGPUBuffer createBuffer(WGPUBufferUsageFlags usage, uint64_t size, char const * label); - void createOrUpdateBuffer(WGPUBuffer& buffer, WGPUBufferUsageFlags usage, const void *data, uint64_t size, char const * label); void releaseSampler(WGPUSampler& sampler); void releaseTexture(WGPUTexture& texture); void releaseTextureView(WGPUTextureView& textureView); void releaseBuffer(WGPUBuffer& buffer); + + void allocateVertexBuffer(WGPUBuffer& buffer, const void *data, uint64_t size); + void allocateIndexBuffer(WGPUBuffer& buffer, const void *data, uint64_t size); + void releaseVertexBuffer(WGPUBuffer& buffer); + void releaseIndexBuffer(WGPUBuffer& buffer); }; struct WgBindGroup diff --git a/src/renderer/wg_engine/tvgWgRenderData.cpp b/src/renderer/wg_engine/tvgWgRenderData.cpp index 534ab2ff..02cb07ea 100644 --- a/src/renderer/wg_engine/tvgWgRenderData.cpp +++ b/src/renderer/wg_engine/tvgWgRenderData.cpp @@ -53,22 +53,13 @@ void WgMeshData::update(WgContext& context, WgGeometryData* geometryData){ indexCount = geometryData->indexes.count; // buffer position data create and write if (geometryData->positions.count > 0) - context.createOrUpdateBuffer( - bufferPosition, WGPUBufferUsage_CopyDst | WGPUBufferUsage_Vertex, - &geometryData->positions[0], vertexCount * sizeof(float) * 2, - "Buffer position geometry data"); + context.allocateVertexBuffer(bufferPosition, &geometryData->positions[0], vertexCount * sizeof(float) * 2); // buffer tex coords data create and write if (geometryData->texCoords.count > 0) - context.createOrUpdateBuffer( - bufferTexCoord, WGPUBufferUsage_CopyDst | WGPUBufferUsage_Vertex, - &geometryData->texCoords[0], vertexCount * sizeof(float) * 2, - "Buffer tex coords geometry data"); + context.allocateVertexBuffer(bufferTexCoord, &geometryData->texCoords[0], vertexCount * sizeof(float) * 2); // buffer index data create and write if (geometryData->indexes.count > 0) - context.createOrUpdateBuffer( - bufferIndex, WGPUBufferUsage_CopyDst | WGPUBufferUsage_Index, - &geometryData->indexes[0], indexCount * sizeof(uint32_t), - "Buffer index geometry data"); + context.allocateIndexBuffer(bufferIndex, &geometryData->indexes[0], indexCount * sizeof(uint32_t)); }; @@ -79,6 +70,43 @@ void WgMeshData::release(WgContext& context) context.releaseBuffer(bufferPosition); }; + +//*********************************************************************** +// WgMeshDataPool +//*********************************************************************** + +WgMeshData* WgMeshDataPool::allocate(WgContext& context) +{ + WgMeshData* meshData{}; + if (mPool.count > 0) { + meshData = mPool.last(); + mPool.pop(); + } else { + meshData = new WgMeshData(); + mList.push(meshData); + } + return meshData; +} + + +void WgMeshDataPool::free(WgContext& context, WgMeshData* meshData) +{ + mPool.push(meshData); +} + + +void WgMeshDataPool::release(WgContext& context) +{ + for (uint32_t i = 0; i < mList.count; i++) { + mList[i]->release(context); + delete mList[i]; + } + mPool.clear(); + mList.clear(); +} + +WgMeshDataPool* WgMeshDataGroup::MeshDataPool = nullptr; + //*********************************************************************** // WgMeshDataGroup //*********************************************************************** @@ -89,7 +117,7 @@ void WgMeshDataGroup::update(WgContext& context, WgGeometryDataGroup* geometryDa assert(geometryDataGroup); for (uint32_t i = 0; i < geometryDataGroup->geometries.count; i++) { if (geometryDataGroup->geometries[i]->positions.count > 2) { - meshes.push(new WgMeshData()); + meshes.push(MeshDataPool->allocate(context)); meshes.last()->update(context, geometryDataGroup->geometries[i]); } } @@ -99,10 +127,11 @@ void WgMeshDataGroup::update(WgContext& context, WgGeometryDataGroup* geometryDa void WgMeshDataGroup::release(WgContext& context) { for (uint32_t i = 0; i < meshes.count; i++) - meshes[i]->release(context); + MeshDataPool->free(context, meshes[i]); meshes.clear(); }; + //*********************************************************************** // WgImageData //*********************************************************************** @@ -223,8 +252,6 @@ void WgRenderDataShape::updateMeshes(WgContext &context, const RenderShape &rsha void WgRenderDataShape::releaseMeshes(WgContext &context) { - meshBBoxStrokes.release(context); - meshBBoxShapes.release(context); meshGroupStrokes.release(context); meshGroupShapes.release(context); } @@ -232,12 +259,48 @@ void WgRenderDataShape::releaseMeshes(WgContext &context) void WgRenderDataShape::release(WgContext& context) { + meshBBoxStrokes.release(context); + meshBBoxShapes.release(context); releaseMeshes(context); renderSettingsStroke.release(context); renderSettingsShape.release(context); WgRenderDataPaint::release(context); }; +//*********************************************************************** +// WgRenderDataShapePool +//*********************************************************************** + +WgRenderDataShape* WgRenderDataShapePool::allocate(WgContext& context) +{ + WgRenderDataShape* dataShape{}; + if (mPool.count > 0) { + dataShape = mPool.last(); + mPool.pop(); + } else { + dataShape = new WgRenderDataShape(); + mList.push(dataShape); + } + return dataShape; +} + + +void WgRenderDataShapePool::free(WgContext& context, WgRenderDataShape* dataShape) +{ + mPool.push(dataShape); +} + + +void WgRenderDataShapePool::release(WgContext& context) +{ + for (uint32_t i = 0; i < mList.count; i++) { + mList[i]->release(context); + delete mList[i]; + } + mPool.clear(); + mList.clear(); +} + //*********************************************************************** // WgRenderDataPicture //*********************************************************************** diff --git a/src/renderer/wg_engine/tvgWgRenderData.h b/src/renderer/wg_engine/tvgWgRenderData.h index 0525b96e..ac3c9372 100644 --- a/src/renderer/wg_engine/tvgWgRenderData.h +++ b/src/renderer/wg_engine/tvgWgRenderData.h @@ -37,7 +37,19 @@ struct WgMeshData { void release(WgContext& context); }; +class WgMeshDataPool { +private: + Array mPool; + Array mList; +public: + WgMeshData* allocate(WgContext& context); + void free(WgContext& context, WgMeshData* meshData); + void release(WgContext& context); +}; + struct WgMeshDataGroup { + static WgMeshDataPool* MeshDataPool; + Array meshes{}; void update(WgContext& context, WgGeometryDataGroup* geometryDataGroup); @@ -69,6 +81,7 @@ struct WgRenderDataPaint { WgBindGroupPaint bindGroupPaint{}; + virtual ~WgRenderDataPaint() {}; virtual void release(WgContext& context); virtual uint32_t identifier() { return TVG_CLASS_ID_UNDEFINED; }; }; @@ -89,6 +102,16 @@ struct WgRenderDataShape: public WgRenderDataPaint uint32_t identifier() override { return TVG_CLASS_ID_SHAPE; }; }; +class WgRenderDataShapePool { +private: + Array mPool; + Array mList; +public: + WgRenderDataShape* allocate(WgContext& context); + void free(WgContext& context, WgRenderDataShape* dataShape); + void release(WgContext& context); +}; + struct WgRenderDataPicture: public WgRenderDataPaint { WgBindGroupPicture bindGroupPicture{}; diff --git a/src/renderer/wg_engine/tvgWgRenderer.cpp b/src/renderer/wg_engine/tvgWgRenderer.cpp index 6543bfa1..09bd893e 100644 --- a/src/renderer/wg_engine/tvgWgRenderer.cpp +++ b/src/renderer/wg_engine/tvgWgRenderer.cpp @@ -48,11 +48,15 @@ void WgRenderer::initialize() mOpacityPool.initialize(mContext); mBlendMethodPool.initialize(mContext); mCompositeMethodPool.initialize(mContext); + WgMeshDataGroup::MeshDataPool = new WgMeshDataPool(); } void WgRenderer::release() { + mRenderDataShapePool.release(mContext); + WgMeshDataGroup::MeshDataPool->release(mContext); + delete WgMeshDataGroup::MeshDataPool; mCompositorStack.clear(); mRenderStorageStack.clear(); mRenderStoragePool.release(mContext); @@ -74,7 +78,7 @@ RenderData WgRenderer::prepare(const RenderShape& rshape, RenderData data, const // get or create render data shape auto renderDataShape = (WgRenderDataShape*)data; if (!renderDataShape) - renderDataShape = new WgRenderDataShape(); + renderDataShape = mRenderDataShapePool.allocate(mContext); // update geometry if (flags & (RenderUpdateFlag::Path | RenderUpdateFlag::Stroke)) @@ -211,7 +215,12 @@ bool WgRenderer::postRender() void WgRenderer::dispose(RenderData data) { auto renderData = (WgRenderDataPaint*)data; - if (renderData) renderData->release(mContext); + if (renderData) { + if (renderData->identifier() == TVG_CLASS_ID_SHAPE) + mRenderDataShapePool.free(mContext, (WgRenderDataShape*)renderData); + else + renderData->release(mContext); + } } diff --git a/src/renderer/wg_engine/tvgWgRenderer.h b/src/renderer/wg_engine/tvgWgRenderer.h index d5433916..6790bad9 100644 --- a/src/renderer/wg_engine/tvgWgRenderer.h +++ b/src/renderer/wg_engine/tvgWgRenderer.h @@ -69,6 +69,7 @@ private: WgBindGroupOpacityPool mOpacityPool; WgBindGroupBlendMethodPool mBlendMethodPool; WgBindGroupCompositeMethodPool mCompositeMethodPool; + WgRenderDataShapePool mRenderDataShapePool; // render tree stacks Array mCompositorStack;