mirror of
https://github.com/thorvg/thorvg.git
synced 2025-06-14 12:04:29 +00:00
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:
parent
951ea77f5d
commit
6c452c1fd3
4 changed files with 107 additions and 48 deletions
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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_
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Add table
Reference in a new issue