wg_engine: fix resources disposing on context destroy

We must to dispose all paints render handles before the context will be destroyed to prevent handles leak
This commit is contained in:
Sergii Liebodkin 2024-11-22 11:51:53 +00:00 committed by Hermet Park
parent 951ea77f5d
commit 6c452c1fd3
4 changed files with 107 additions and 48 deletions

View file

@ -207,20 +207,15 @@ void WgMeshDataGroup::release(WgContext& context)
// WgImageData
//***********************************************************************
void WgImageData::update(WgContext& context, RenderSurface* surface)
void WgImageData::update(WgContext& context, const RenderSurface* surface)
{
release(context);
assert(surface);
texture = context.createTexture(surface->w, surface->h, WGPUTextureFormat_RGBA8Unorm);
assert(texture);
textureView = context.createTextureView(texture);
assert(textureView);
// update texture data
WGPUImageCopyTexture imageCopyTexture{ .texture = texture };
WGPUTextureDataLayout textureDataLayout{ .bytesPerRow = 4 * surface->w, .rowsPerImage = surface->h };
WGPUExtent3D writeSize{ .width = surface->w, .height = surface->h, .depthOrArrayLayers = 1 };
wgpuQueueWriteTexture(context.queue, &imageCopyTexture, surface->data, 4 * surface->w * surface->h, &textureDataLayout, &writeSize);
wgpuQueueSubmit(context.queue, 0, nullptr);
// allocate new texture handle
bool texHandleChanged = context.allocateTexture(texture, surface->w, surface->h, WGPUTextureFormat_RGBA8Unorm, surface->data);
// update texture view of texture handle was changed
if (texHandleChanged) {
context.releaseTextureView(textureView);
textureView = context.createTextureView(texture);
}
};
@ -506,26 +501,26 @@ void WgRenderDataShape::release(WgContext& context)
WgRenderDataShape* WgRenderDataShapePool::allocate(WgContext& context)
{
WgRenderDataShape* dataShape{};
WgRenderDataShape* renderData{};
if (mPool.count > 0) {
dataShape = mPool.last();
renderData = mPool.last();
mPool.pop();
} else {
dataShape = new WgRenderDataShape();
mList.push(dataShape);
renderData = new WgRenderDataShape();
mList.push(renderData);
}
return dataShape;
return renderData;
}
void WgRenderDataShapePool::free(WgContext& context, WgRenderDataShape* dataShape)
void WgRenderDataShapePool::free(WgContext& context, WgRenderDataShape* renderData)
{
dataShape->meshGroupShapes.release(context);
dataShape->meshGroupShapesBBox.release(context);
dataShape->meshGroupStrokes.release(context);
dataShape->meshGroupStrokesBBox.release(context);
dataShape->clips.clear();
mPool.push(dataShape);
renderData->meshGroupShapes.release(context);
renderData->meshGroupShapesBBox.release(context);
renderData->meshGroupStrokes.release(context);
renderData->meshGroupStrokesBBox.release(context);
renderData->clips.clear();
mPool.push(renderData);
}
@ -543,10 +538,59 @@ void WgRenderDataShapePool::release(WgContext& context)
// WgRenderDataPicture
//***********************************************************************
void WgRenderDataPicture::updateSurface(WgContext& context, const RenderSurface* surface)
{
// upoate mesh data
meshData.imageBox(context, surface->w, surface->h);
// update texture data
imageData.update(context, surface);
// update texture bind group
context.pipelines->layouts.releaseBindGroup(bindGroupPicture);
bindGroupPicture = context.pipelines->layouts.createBindGroupTexSampled(
context.samplerLinearRepeat, imageData.textureView
);
}
void WgRenderDataPicture::release(WgContext& context)
{
meshData.release(context);
imageData.release(context);
context.pipelines->layouts.releaseBindGroup(bindGroupPicture);
imageData.release(context);
meshData.release(context);
WgRenderDataPaint::release(context);
}
//***********************************************************************
// WgRenderDataPicturePool
//***********************************************************************
WgRenderDataPicture* WgRenderDataPicturePool::allocate(WgContext& context)
{
WgRenderDataPicture* renderData{};
if (mPool.count > 0) {
renderData = mPool.last();
mPool.pop();
} else {
renderData = new WgRenderDataPicture();
mList.push(renderData);
}
return renderData;
}
void WgRenderDataPicturePool::free(WgContext& context, WgRenderDataPicture* renderData)
{
renderData->clips.clear();
mPool.push(renderData);
}
void WgRenderDataPicturePool::release(WgContext& context)
{
for (uint32_t i = 0; i < mList.count; i++) {
mList[i]->release(context);
delete mList[i];
}
mPool.clear();
mList.clear();
}

View file

@ -69,7 +69,7 @@ struct WgImageData {
WGPUTexture texture{};
WGPUTextureView textureView{};
void update(WgContext& context, RenderSurface* surface);
void update(WgContext& context, const RenderSurface* surface);
void release(WgContext& context);
};
@ -142,7 +142,7 @@ private:
Array<WgRenderDataShape*> mList;
public:
WgRenderDataShape* allocate(WgContext& context);
void free(WgContext& context, WgRenderDataShape* dataShape);
void free(WgContext& context, WgRenderDataShape* renderData);
void release(WgContext& context);
};
@ -152,8 +152,19 @@ struct WgRenderDataPicture: public WgRenderDataPaint
WgImageData imageData{};
WgMeshData meshData{};
void updateSurface(WgContext& context, const RenderSurface* surface);
void release(WgContext& context) override;
Type type() override { return Type::Picture; };
};
class WgRenderDataPicturePool {
private:
Array<WgRenderDataPicture*> mPool;
Array<WgRenderDataPicture*> mList;
public:
WgRenderDataPicture* allocate(WgContext& context);
void free(WgContext& context, WgRenderDataPicture* dataPicture);
void release(WgContext& context);
};
#endif // _TVG_WG_RENDER_DATA_H_

View file

@ -46,13 +46,18 @@ void WgRenderer::release()
// dispose stored objects
disposeObjects();
// clear render data paint pools
mRenderDataShapePool.release(mContext);
mRenderDataPicturePool.release(mContext);
WgMeshDataPool::gMeshDataPool->release(mContext);
// clear render storage pool
mRenderStoragePool.release(mContext);
// clear rendering tree stacks
mCompositorStack.clear();
mRenderStorageStack.clear();
mRenderStoragePool.release(mContext);
mRenderDataShapePool.release(mContext);
WgMeshDataPool::gMeshDataPool->release(mContext);
mStorageRoot.release(mContext);
mRenderStorageRoot.release(mContext);
// release context handles
mCompositor.release(mContext);
@ -72,8 +77,7 @@ void WgRenderer::disposeObjects()
if (renderData->type() == Type::Shape) {
mRenderDataShapePool.free(mContext, (WgRenderDataShape*)renderData);
} else {
renderData->release(mContext);
delete renderData;
mRenderDataPicturePool.free(mContext, (WgRenderDataPicture*)renderData);
}
}
mDisposeRenderDatas.clear();
@ -117,7 +121,7 @@ RenderData WgRenderer::prepare(RenderSurface* surface, RenderData data, const Ma
// get or create render data shape
auto renderDataPicture = (WgRenderDataPicture*)data;
if (!renderDataPicture)
renderDataPicture = new WgRenderDataPicture();
renderDataPicture = mRenderDataPicturePool.allocate(mContext);
// update paint settings
renderDataPicture->viewport = mViewport;
@ -128,13 +132,7 @@ RenderData WgRenderer::prepare(RenderSurface* surface, RenderData data, const Ma
// update image data
if (flags & (RenderUpdateFlag::Path | RenderUpdateFlag::Image)) {
mContext.pipelines->layouts.releaseBindGroup(renderDataPicture->bindGroupPicture);
renderDataPicture->meshData.release(mContext);
renderDataPicture->meshData.imageBox(mContext, surface->w, surface->h);
renderDataPicture->imageData.update(mContext, surface);
renderDataPicture->bindGroupPicture = mContext.pipelines->layouts.createBindGroupTexSampled(
mContext.samplerLinearRepeat, renderDataPicture->imageData.textureView
);
renderDataPicture->updateSurface(mContext, surface);
}
// store clips data
@ -147,7 +145,7 @@ bool WgRenderer::preRender()
{
// push rot render storage to the render tree stack
assert(mRenderStorageStack.count == 0);
mRenderStorageStack.push(&mStorageRoot);
mRenderStorageStack.push(&mRenderStorageRoot);
// create command encoder for drawing
WGPUCommandEncoderDescriptor commandEncoderDesc{};
mCommandEncoder = wgpuDeviceCreateCommandEncoder(mContext.device, &commandEncoderDesc);
@ -191,6 +189,7 @@ bool WgRenderer::postRender()
void WgRenderer::dispose(RenderData data) {
if (!mContext.queue) return;
auto renderData = (WgRenderDataPaint*)data;
if (renderData) {
ScopedLock lock(mDisposeKey);
@ -277,7 +276,7 @@ bool WgRenderer::sync()
WGPUCommandEncoder commandEncoder = wgpuDeviceCreateCommandEncoder(mContext.device, &commandEncoderDesc);
// show root offscreen buffer
mCompositor.blit(mContext, commandEncoder, &mStorageRoot, dstTextureView);
mCompositor.blit(mContext, commandEncoder, &mRenderStorageRoot, dstTextureView);
// release command encoder
const WGPUCommandBufferDescriptor commandBufferDesc{};
@ -317,7 +316,7 @@ bool WgRenderer::target(WGPUDevice device, WGPUInstance instance, void* target,
// initialize render tree instances
mRenderStoragePool.initialize(mContext, width, height);
mStorageRoot.initialize(mContext, width, height);
mRenderStorageRoot.initialize(mContext, width, height);
mCompositor.initialize(mContext, width, height);
// configure surface (must be called after context creation)

View file

@ -71,12 +71,17 @@ private:
void clearTargets();
bool surfaceConfigure(WGPUSurface surface, WgContext& context, uint32_t width, uint32_t height);
// render tree stacks and pools
WgRenderStorage mStorageRoot;
// render tree stacks
WgRenderStorage mRenderStorageRoot;
Array<WgCompose*> mCompositorStack;
Array<WgRenderStorage*> mRenderStorageStack;
// render storage pool
WgRenderStoragePool mRenderStoragePool;
// render data paint pools
WgRenderDataShapePool mRenderDataShapePool;
WgRenderDataPicturePool mRenderDataPicturePool;
// rendering context
WgContext mContext;