From 5ebbd8ac63ed7eb2e198b9115f11fe203eb6205e Mon Sep 17 00:00:00 2001
From: Caleb Cornett <caleb.cornett@outlook.com>
Date: Mon, 7 Mar 2022 22:30:06 -0500
Subject: [PATCH] Added mutexes for command buffer acquisition and command list
 execution

---
 src/Refresh_Driver_D3D11.c | 28 ++++++++++++++++++----------
 1 file changed, 18 insertions(+), 10 deletions(-)

diff --git a/src/Refresh_Driver_D3D11.c b/src/Refresh_Driver_D3D11.c
index b49903c..5d8c0d0 100644
--- a/src/Refresh_Driver_D3D11.c
+++ b/src/Refresh_Driver_D3D11.c
@@ -61,14 +61,6 @@
 		return ret; \
 	}
 
-#define ERROR_CHECK_UNLOCK_RETURN(msg, ret) \
-	if (FAILED(res)) \
-	{ \
-		D3D11_INTERNAL_LogError(renderer->device, msg, res); \
-		SDL_UnlockMutex(renderer->ctxLock); \
-		return ret; \
-	}
-
 #define EXPAND_ELEMENTS_IF_NEEDED(arr, initialValue, type)	\
 	if (arr->count == arr->capacity)			\
 	{							\
@@ -278,8 +270,10 @@ typedef struct D3D11Renderer
 	IDXGIAdapter1* adapter;
 	void *d3d11_dll;
 	void *dxgi_dll;
+	SDL_mutex *immediateContextMutex;
 
 	D3D11CommandBufferPool *commandBufferPool;
+	SDL_mutex *commandBufferAcquisitionMutex;
 
 	D3D11SwapchainData** swapchainDatas;
 	uint32_t swapchainDataCount;
@@ -993,6 +987,9 @@ static Refresh_CommandBuffer* D3D11_AcquireCommandBuffer(
 	uint32_t i;
 	HRESULT res;
 
+	/* Make sure multiple threads can't acquire the same command buffer. */
+	SDL_LockMutex(renderer->commandBufferAcquisitionMutex);
+
 	/* Try to use an existing command buffer, if one is available. */
 	for (i = 0; i < renderer->commandBufferPool->count; i += 1)
 	{
@@ -1025,7 +1022,11 @@ static Refresh_CommandBuffer* D3D11_AcquireCommandBuffer(
 			0,
 			&renderer->commandBufferPool->elements[i]->context
 		);
-		ERROR_CHECK_RETURN("Could not create deferred context for command buffer", NULL);
+		if (FAILED(res))
+		{
+			SDL_UnlockMutex(renderer->commandBufferAcquisitionMutex);
+			ERROR_CHECK_RETURN("Could not create deferred context for command buffer", NULL);
+		}
 
 		/* Now we have a new command buffer we can use! */
 		commandBuffer = renderer->commandBufferPool->elements[i];
@@ -1039,6 +1040,8 @@ static Refresh_CommandBuffer* D3D11_AcquireCommandBuffer(
 	commandBuffer->swapchainData = NULL;
 	commandBuffer->commandList = NULL;
 
+	SDL_UnlockMutex(renderer->commandBufferAcquisitionMutex);
+
 	return (Refresh_CommandBuffer*) commandBuffer;
 }
 
@@ -1144,12 +1147,13 @@ static void D3D11_Submit(
 		}
 
 		/* Submit the command list to the immediate context */
-		/* FIXME: Mutex lock me! */
+		SDL_LockMutex(renderer->immediateContextMutex);
 		ID3D11DeviceContext_ExecuteCommandList(
 			renderer->immediateContext,
 			commandList,
 			0
 		);
+		SDL_UnlockMutex(renderer->immediateContextMutex);
 
 		/* Now that we're done, either save the command list or release it. */
 		if (commandBuffer->fixed)
@@ -1315,6 +1319,10 @@ tryCreateDevice:
 	);
 	SDL_memset(renderer->commandBufferPool, 0, sizeof(D3D11CommandBufferPool));
 
+	/* Create mutexes */
+	renderer->immediateContextMutex = SDL_CreateMutex();
+	renderer->commandBufferAcquisitionMutex = SDL_CreateMutex();
+
 	/* Initialize miscellaneous renderer members */
 	renderer->debugMode = (flags & D3D11_CREATE_DEVICE_DEBUG) != 0;
 	renderer->blendFactor.x = 1.0f;