mirror of
https://github.com/thorvg/thorvg.git
synced 2025-06-13 19:44:28 +00:00
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:
parent
1efb72ce94
commit
392f59db9d
7 changed files with 215 additions and 73 deletions
|
@ -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));
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
//*****************************************************************************
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
//***********************************************************************
|
||||
|
|
|
@ -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{};
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -69,6 +69,7 @@ private:
|
|||
WgBindGroupOpacityPool mOpacityPool;
|
||||
WgBindGroupBlendMethodPool mBlendMethodPool;
|
||||
WgBindGroupCompositeMethodPool mCompositeMethodPool;
|
||||
WgRenderDataShapePool mRenderDataShapePool;
|
||||
|
||||
// render tree stacks
|
||||
Array<Compositor*> mCompositorStack;
|
||||
|
|
Loading…
Add table
Reference in a new issue