Browse Source

metal: fix a crash on quit

Sasha Szpakowski 2 years ago
parent
commit
02427c3ddc
2 changed files with 29 additions and 10 deletions
  1. 3 1
      src/modules/graphics/metal/Graphics.h
  2. 26 9
      src/modules/graphics/metal/Graphics.mm

+ 3 - 1
src/modules/graphics/metal/Graphics.h

@@ -208,6 +208,8 @@ private:
 	void initCapabilities() override;
 	void getAPIStats(int &shaderswitches) const override;
 
+	void processCompletedCommandBuffers();
+
 	void endPass(bool presenting);
 
 	id<MTLDepthStencilState> getCachedDepthStencilState(const DepthState &depth, const StencilState &stencil);
@@ -251,7 +253,7 @@ private:
 	std::map<uint64, void *> cachedSamplers;
 	std::unordered_map<uint64, void *> cachedDepthStencilStates;
 
-	std::atomic<int64> completeCommandBufferIndex;
+	std::vector<id<MTLCommandBuffer>> activeCommandBuffers;
 
 	DeviceFamilies families;
 

+ 26 - 9
src/modules/graphics/metal/Graphics.mm

@@ -408,8 +408,20 @@ Graphics::Graphics()
 Graphics::~Graphics()
 { @autoreleasepool {
 	submitCommandBuffer(SUBMIT_DONE);
-	delete uniformBuffer;
-	delete defaultAttributesBuffer;
+	processCompletedCommandBuffers();
+
+	// Wait for all active command buffers to complete before returning from
+	// the destructor.
+	for (id<MTLCommandBuffer> cmd : activeCommandBuffers)
+	{
+		if (cmd.status == MTLCommandBufferStatusNotEnqueued || cmd.status == MTLCommandBufferStatusEnqueued)
+			[cmd commit];
+
+		[cmd waitUntilCompleted];
+	}
+
+	uniformBuffer->release();
+	defaultAttributesBuffer->release();
 	passDesc = nil;
 	commandQueue = nil;
 	device = nil;
@@ -562,18 +574,22 @@ id<MTLCommandBuffer> Graphics::useCommandBuffer()
 	if (commandBuffer == nil)
 	{
 		commandBuffer = [commandQueue commandBuffer];
-
-		Graphics *pthis = this;
-		pthis->retain();
-		[commandBuffer addCompletedHandler:^(id<MTLCommandBuffer> _Nonnull) {
-			pthis->completeCommandBufferIndex.fetch_add(1, std::memory_order_relaxed);
-			pthis->release();
-		}];
+		activeCommandBuffers.push_back(commandBuffer);
 	}
 
 	return commandBuffer;
 }
 
+void Graphics::processCompletedCommandBuffers()
+{
+	for (int i = (int) activeCommandBuffers.size() - 1; i >= 0; i--)
+	{
+		auto status = activeCommandBuffers[i].status;
+		if (status == MTLCommandBufferStatusCompleted || status == MTLCommandBufferStatusError)
+			activeCommandBuffers.erase(activeCommandBuffers.begin() + i);
+	}
+}
+
 void Graphics::submitCommandBuffer(SubmitType type)
 {
 	submitAllEncoders(type);
@@ -1717,6 +1733,7 @@ void Graphics::present(void *screenshotCallbackData)
 
 	updatePendingReadbacks();
 	updateTemporaryResources();
+	processCompletedCommandBuffers();
 }}
 
 int Graphics::getRequestedBackbufferMSAA() const