I recently ported the imgui implementation found here viewtopic.php?t=89081 to metal on macOS as part of my work there.
Graphically everything looks fine, and the gui renders. I thought the job was done, but I've recently noticed that it's leaking a lot of memory (about 10MB a second!). The leak only occurs if imgui is rendering, so something to do with my port must be up. Much of the port was done by others, but I did piece together bits of the psoCaching to get it to work with the newer ogre 2.1. The thing with imgui is that the vertices and indices are written to buffers each frame, so the pso also gets altered each frame.
I ran the code through the xcode memory profiler and I found that calls to MetalRenderSystem::_setPipelineStateObject() and subsequently MetalRenderSystem::createRenderEncoder() were causing the leaks. I'm 100% sure this is a problem with vertex data being allocated and not cleaned up.
The data gets written to the buffer like this:
Code: Select all
Ogre::v1::VertexBufferBinding* bind = mRenderOp.vertexData->vertexBufferBinding;
if (bind->getBindings().empty() || mVertexBufferSize != vtxCount)
{
mVertexBufferSize = vtxCount;
bind->setBinding(0, Ogre::v1::HardwareBufferManager::getSingleton().createVertexBuffer(sizeof(ImDrawVert), mVertexBufferSize, Ogre::v1::HardwareBuffer::HBU_WRITE_ONLY));
}
if (mRenderOp.indexData->indexBuffer.isNull() || mIndexBufferSize != idxCount)
{
mIndexBufferSize = idxCount;
mRenderOp.indexData->indexBuffer =
Ogre::v1::HardwareBufferManager::getSingleton().createIndexBuffer(Ogre::v1::HardwareIndexBuffer::IT_16BIT, mIndexBufferSize, Ogre::v1::HardwareBuffer::HBU_WRITE_ONLY);
}
// Copy all vertices
ImDrawVert* vtxDst = (ImDrawVert*)(bind->getBuffer(0)->lock(Ogre::v1::HardwareBuffer::HBL_DISCARD));
ImDrawIdx* idxDst = (ImDrawIdx*)(mRenderOp.indexData->indexBuffer->lock(Ogre::v1::HardwareBuffer::HBL_DISCARD));
memcpy(vtxDst, vtxBuf, mVertexBufferSize * sizeof(ImDrawVert));
memcpy(idxDst, idxBuf, mIndexBufferSize * sizeof(ImDrawIdx));
mRenderOp.vertexData->vertexStart = 0;
mRenderOp.vertexData->vertexCount = vtxCount;
mRenderOp.indexData->indexStart = 0;
mRenderOp.indexData->indexCount = idxCount;
bind->getBuffer(0)->unlock();
mRenderOp.indexData->indexBuffer->unlock();
But that's about as far as I was able to get with it.
Am I just using the api in completely the wrong way?
Is there something I should be calling to cleanup the buffers or memory?
I'd really appreciate some direction as to what I should be trying.
This is not happening on OpenGL under Linux. I haven't tried it on D3D and Windows yet.
You can see my full implementation here
https://gitlab.com/edherbert/avEngine/t ... /imguiOgre
I'm quite new to all this, and some guidance on what I've done wrong would be appreciated.