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
This commit is contained in:
Sergii Liebodkin 2024-04-04 17:23:54 +03:00 committed by Hermet Park
parent 1efb72ce94
commit 392f59db9d
7 changed files with 215 additions and 73 deletions

View file

@ -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));
}

View file

@ -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
//*****************************************************************************

View file

@ -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

View file

@ -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
//***********************************************************************

View file

@ -37,7 +37,19 @@ struct WgMeshData {
void release(WgContext& context);
};
class WgMeshDataPool {
private:
Array<WgMeshData*> mPool;
Array<WgMeshData*> mList;
public:
WgMeshData* allocate(WgContext& context);
void free(WgContext& context, WgMeshData* meshData);
void release(WgContext& context);
};
struct WgMeshDataGroup {
static WgMeshDataPool* MeshDataPool;
Array<WgMeshData*> 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<WgRenderDataShape*> mPool;
Array<WgRenderDataShape*> mList;
public:
WgRenderDataShape* allocate(WgContext& context);
void free(WgContext& context, WgRenderDataShape* dataShape);
void release(WgContext& context);
};
struct WgRenderDataPicture: public WgRenderDataPaint
{
WgBindGroupPicture bindGroupPicture{};

View file

@ -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);
}
}

View file

@ -69,6 +69,7 @@ private:
WgBindGroupOpacityPool mOpacityPool;
WgBindGroupBlendMethodPool mBlendMethodPool;
WgBindGroupCompositeMethodPool mCompositeMethodPool;
WgRenderDataShapePool mRenderDataShapePool;
// render tree stacks
Array<Compositor*> mCompositorStack;