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 // WgImageData
//*********************************************************************** //***********************************************************************
void WgImageData::update(WgContext& context, RenderSurface* surface) void WgImageData::update(WgContext& context, const RenderSurface* surface)
{ {
release(context); // allocate new texture handle
assert(surface); bool texHandleChanged = context.allocateTexture(texture, surface->w, surface->h, WGPUTextureFormat_RGBA8Unorm, surface->data);
texture = context.createTexture(surface->w, surface->h, WGPUTextureFormat_RGBA8Unorm); // update texture view of texture handle was changed
assert(texture); if (texHandleChanged) {
context.releaseTextureView(textureView);
textureView = context.createTextureView(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);
}; };
@ -506,26 +501,26 @@ void WgRenderDataShape::release(WgContext& context)
WgRenderDataShape* WgRenderDataShapePool::allocate(WgContext& context) WgRenderDataShape* WgRenderDataShapePool::allocate(WgContext& context)
{ {
WgRenderDataShape* dataShape{}; WgRenderDataShape* renderData{};
if (mPool.count > 0) { if (mPool.count > 0) {
dataShape = mPool.last(); renderData = mPool.last();
mPool.pop(); mPool.pop();
} else { } else {
dataShape = new WgRenderDataShape(); renderData = new WgRenderDataShape();
mList.push(dataShape); 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); renderData->meshGroupShapes.release(context);
dataShape->meshGroupShapesBBox.release(context); renderData->meshGroupShapesBBox.release(context);
dataShape->meshGroupStrokes.release(context); renderData->meshGroupStrokes.release(context);
dataShape->meshGroupStrokesBBox.release(context); renderData->meshGroupStrokesBBox.release(context);
dataShape->clips.clear(); renderData->clips.clear();
mPool.push(dataShape); mPool.push(renderData);
} }
@ -543,10 +538,59 @@ void WgRenderDataShapePool::release(WgContext& context)
// WgRenderDataPicture // 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) void WgRenderDataPicture::release(WgContext& context)
{ {
meshData.release(context);
imageData.release(context);
context.pipelines->layouts.releaseBindGroup(bindGroupPicture); context.pipelines->layouts.releaseBindGroup(bindGroupPicture);
imageData.release(context);
meshData.release(context);
WgRenderDataPaint::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{}; WGPUTexture texture{};
WGPUTextureView textureView{}; WGPUTextureView textureView{};
void update(WgContext& context, RenderSurface* surface); void update(WgContext& context, const RenderSurface* surface);
void release(WgContext& context); void release(WgContext& context);
}; };
@ -142,7 +142,7 @@ private:
Array<WgRenderDataShape*> mList; Array<WgRenderDataShape*> mList;
public: public:
WgRenderDataShape* allocate(WgContext& context); WgRenderDataShape* allocate(WgContext& context);
void free(WgContext& context, WgRenderDataShape* dataShape); void free(WgContext& context, WgRenderDataShape* renderData);
void release(WgContext& context); void release(WgContext& context);
}; };
@ -152,8 +152,19 @@ struct WgRenderDataPicture: public WgRenderDataPaint
WgImageData imageData{}; WgImageData imageData{};
WgMeshData meshData{}; WgMeshData meshData{};
void updateSurface(WgContext& context, const RenderSurface* surface);
void release(WgContext& context) override; void release(WgContext& context) override;
Type type() override { return Type::Picture; }; 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_ #endif // _TVG_WG_RENDER_DATA_H_

View file

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

View file

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