[mtl surface] fix crash on exit when metal GPU frame capture is enabled. Apparently, if we release resources (on exit) before all GPU work is completed, libMetalCapture crashes on bad access. To work around that, in mg_mtl_surface_destroy(), we enqueue a last (empty) command buffer and call waitUntilCompleted on it, to ensure all previous command buffers are also completed

This commit is contained in:
Martin Fouilleul 2023-03-15 13:02:18 +01:00
parent 5ce53001e2
commit 0c74e997ae
2 changed files with 13 additions and 5 deletions

View File

@ -103,7 +103,7 @@ void mg_mtl_canvas_begin(mg_canvas_backend* interface, mg_color clearColor)
}
@autoreleasepool
{
if(surface->commandBuffer == nil || surface->commandBuffer == nil)
if(surface->commandBuffer == nil)
{
mg_mtl_surface_acquire_drawable_and_command_buffer(surface);
}

View File

@ -42,6 +42,13 @@ void mg_mtl_surface_destroy(mg_surface_data* interface)
@autoreleasepool
{
//NOTE: when GPU frame capture is enabled, if we release resources before all work is completed,
// libMetalCapture crashes... the following hack avoids this crash by enqueuing a last (empty)
// command buffer and waiting for it to complete, ensuring all previous buffers have completed
id<MTLCommandBuffer> endBuffer = [surface->commandQueue commandBuffer];
[endBuffer commit];
[endBuffer waitUntilCompleted];
[surface->commandQueue release];
[surface->mtlLayer removeFromSuperlayer];
[surface->mtlLayer release];
@ -107,13 +114,14 @@ void mg_mtl_surface_present(mg_surface_data* interface)
//NOTE(martin): present drawable and commit command buffer
[surface->commandBuffer presentDrawable: surface->drawable];
[surface->commandBuffer commit];
[surface->commandBuffer waitUntilCompleted];
// [surface->commandBuffer waitUntilCompleted];
//NOTE(martin): acquire next frame resources
[surface->commandBuffer release];
surface->commandBuffer = nil;
//TODO: do we really need this?
[surface->drawable release];
surface->drawable = nil;
[surface->commandBuffer release];
surface->commandBuffer = nil;
}
}