diff --git a/src/Refresh_Driver_D3D11.c b/src/Refresh_Driver_D3D11.c index b42777c..a4a6235 100644 --- a/src/Refresh_Driver_D3D11.c +++ b/src/Refresh_Driver_D3D11.c @@ -443,6 +443,11 @@ typedef struct D3D11UniformBuffer uint32_t offset; } D3D11UniformBuffer; +typedef struct D3D11Fence +{ + ID3D11Query *handle; +} D3D11Fence; + typedef struct D3D11CommandBuffer { /* D3D11 Object References */ @@ -459,7 +464,7 @@ typedef struct D3D11CommandBuffer /* State */ SDL_threadID threadID; - ID3D11Query *completionQuery; + D3D11Fence *fence; /* Uniforms */ D3D11UniformBuffer *vertexUniformBuffer; @@ -509,9 +514,14 @@ typedef struct D3D11Renderer uint32_t availableUniformBufferCount; uint32_t availableUniformBufferCapacity; + D3D11Fence **availableFences; + uint32_t availableFenceCount; + uint32_t availableFenceCapacity; + SDL_mutex *contextLock; SDL_mutex *acquireCommandBufferLock; SDL_mutex *uniformBufferLock; + SDL_mutex *acquireFenceLock; } D3D11Renderer; /* Logging */ @@ -606,7 +616,6 @@ static void D3D11_DestroyDevice( for (uint32_t i = 0; i < renderer->availableCommandBufferCount; i += 1) { D3D11CommandBuffer *commandBuffer = renderer->availableCommandBuffers[i]; - ID3D11Query_Release(commandBuffer->completionQuery); ID3D11DeviceContext_Release(commandBuffer->context); SDL_free(commandBuffer); } @@ -623,10 +632,20 @@ static void D3D11_DestroyDevice( } SDL_free(renderer->availableUniformBuffers); + /* Release fence infrastructure */ + for (uint32_t i = 0; i < renderer->availableFenceCount; i += 1) + { + D3D11Fence *fence = renderer->availableFences[i]; + ID3D11Query_Release(fence->handle); + SDL_free(fence); + } + SDL_free(renderer->availableFences); + /* Release the mutexes */ SDL_DestroyMutex(renderer->acquireCommandBufferLock); SDL_DestroyMutex(renderer->contextLock); SDL_DestroyMutex(renderer->uniformBufferLock); + SDL_DestroyMutex(renderer->acquireFenceLock); /* Release the device and associated objects */ ID3D11DeviceContext_Release(renderer->immediateContext); @@ -2193,7 +2212,6 @@ static void D3D11_INTERNAL_AllocateCommandBuffers( uint32_t allocateCount ) { D3D11CommandBuffer *commandBuffer; - D3D11_QUERY_DESC queryDesc; HRESULT res; renderer->availableCommandBufferCapacity += allocateCount; @@ -2215,16 +2233,6 @@ static void D3D11_INTERNAL_AllocateCommandBuffers( ); ERROR_CHECK("Could not create deferred context"); - /* Fence Query */ - queryDesc.Query = D3D11_QUERY_EVENT; - queryDesc.MiscFlags = 0; - res = ID3D11Device_CreateQuery( - renderer->device, - &queryDesc, - &commandBuffer->completionQuery - ); - ERROR_CHECK("Could not create query"); - /* Bound Uniform Buffers */ commandBuffer->boundUniformBufferCapacity = 16; commandBuffer->boundUniformBufferCount = 0; @@ -2232,8 +2240,6 @@ static void D3D11_INTERNAL_AllocateCommandBuffers( commandBuffer->boundUniformBufferCapacity * sizeof(D3D11UniformBuffer*) ); - /* FIXME: Resource tracking? */ - renderer->availableCommandBuffers[renderer->availableCommandBufferCount] = commandBuffer; renderer->availableCommandBufferCount += 1; } @@ -2258,6 +2264,59 @@ static D3D11CommandBuffer* D3D11_INTERNAL_GetInactiveCommandBufferFromPool( return commandBuffer; } +static void D3D11_INTERNAL_AllocateFences( + D3D11Renderer *renderer, + uint32_t allocateCount +) { + D3D11Fence *fence; + D3D11_QUERY_DESC queryDesc; + HRESULT res; + + renderer->availableFenceCapacity += allocateCount; + + renderer->availableFences = SDL_realloc( + renderer->availableFences, + sizeof(D3D11Fence*) * renderer->availableFenceCapacity + ); + + for (uint32_t i = 0; i < allocateCount; i += 1) + { + fence = SDL_malloc(sizeof(D3D11Fence)); + + queryDesc.Query = D3D11_QUERY_EVENT; + queryDesc.MiscFlags = 0; + res = ID3D11Device_CreateQuery( + renderer->device, + &queryDesc, + &fence->handle + ); + ERROR_CHECK("Could not create query"); /* FIXME: Should this return an error code? */ + + renderer->availableFences[renderer->availableFenceCount] = fence; + renderer->availableFenceCount += 1; + } +} + +static D3D11Fence* D3D11_INTERNAL_GetFenceFromPool( + D3D11Renderer* renderer +) { + D3D11Fence *fence; + + SDL_LockMutex(renderer->acquireFenceLock); + + if (renderer->availableFenceCount == 0) + { + D3D11_INTERNAL_AllocateFences(renderer, renderer->availableFenceCapacity); + } + + fence = renderer->availableFences[renderer->availableFenceCount - 1]; + renderer->availableFenceCount -= 1; + + SDL_UnlockMutex(renderer->acquireFenceLock); + + return fence; +} + static Refresh_CommandBuffer* D3D11_AcquireCommandBuffer( Refresh_Renderer *driverData ) { @@ -2267,8 +2326,8 @@ static Refresh_CommandBuffer* D3D11_AcquireCommandBuffer( SDL_LockMutex(renderer->acquireCommandBufferLock); - /* Set up the command buffer */ commandBuffer = D3D11_INTERNAL_GetInactiveCommandBufferFromPool(renderer); + commandBuffer->threadID = SDL_ThreadID(); commandBuffer->swapchainData = NULL; commandBuffer->graphicsPipeline = NULL; @@ -2277,11 +2336,16 @@ static Refresh_CommandBuffer* D3D11_AcquireCommandBuffer( commandBuffer->fragmentUniformBuffer = NULL; commandBuffer->computeUniformBuffer = NULL; commandBuffer->dsView = NULL; + for (i = 0; i < MAX_COLOR_TARGET_BINDINGS; i += 1) { commandBuffer->rtViews[i] = NULL; } + SDL_LockMutex(renderer->acquireFenceLock); + commandBuffer->fence = D3D11_INTERNAL_GetFenceFromPool(renderer); + SDL_UnlockMutex(renderer->acquireFenceLock); + SDL_UnlockMutex(renderer->acquireCommandBufferLock); return (Refresh_CommandBuffer*) commandBuffer; @@ -3111,6 +3175,22 @@ static void D3D11_INTERNAL_CleanCommandBuffer( commandBuffer->boundUniformBufferCount = 0; + /* The fence is now available */ + /* FIXME: Not if auto-release is false! */ + SDL_LockMutex(renderer->acquireFenceLock); + if (renderer->availableFenceCount == renderer->availableFenceCapacity) + { + renderer->availableFenceCapacity *= 2; + renderer->availableFences = SDL_realloc( + renderer->availableFences, + renderer->availableFenceCapacity * sizeof(D3D11Fence*) + ); + } + + renderer->availableFences[renderer->availableFenceCount] = commandBuffer->fence; + renderer->availableFenceCount += 1; + SDL_UnlockMutex(renderer->acquireFenceLock); + /* Return command buffer to pool */ SDL_LockMutex(renderer->acquireCommandBufferLock); @@ -3155,7 +3235,7 @@ static void D3D11_Submit( /* Notify the command buffer completion query that we have completed recording */ ID3D11DeviceContext_End( renderer->immediateContext, - (ID3D11Asynchronous*) d3d11CommandBuffer->completionQuery + (ID3D11Asynchronous*) d3d11CommandBuffer->fence->handle ); /* Serialize the commands into the command list */ @@ -3205,7 +3285,7 @@ static void D3D11_Submit( res = ID3D11DeviceContext_GetData( renderer->immediateContext, - (ID3D11Asynchronous*) renderer->submittedCommandBuffers[i]->completionQuery, + (ID3D11Asynchronous*) renderer->submittedCommandBuffers[i]->fence->handle, &queryData, sizeof(queryData), 0 @@ -3245,7 +3325,7 @@ static void D3D11_Wait( { while (S_OK != ID3D11DeviceContext_GetData( renderer->immediateContext, - (ID3D11Asynchronous*) renderer->submittedCommandBuffers[i]->completionQuery, + (ID3D11Asynchronous*) renderer->submittedCommandBuffers[i]->fence->handle, &queryData, sizeof(queryData), 0 @@ -3262,8 +3342,6 @@ static void D3D11_Wait( D3D11_INTERNAL_CleanCommandBuffer(renderer, commandBuffer); } - /* FIXME: D3D11_INTERNAL_PerformPendingDestroys(renderer); */ - SDL_UnlockMutex(renderer->contextLock); } @@ -3615,17 +3693,21 @@ tryCreateDevice: renderer->contextLock = SDL_CreateMutex(); renderer->acquireCommandBufferLock = SDL_CreateMutex(); renderer->uniformBufferLock = SDL_CreateMutex(); + renderer->acquireFenceLock = SDL_CreateMutex(); /* Initialize miscellaneous renderer members */ renderer->debugMode = (flags & D3D11_CREATE_DEVICE_DEBUG); - /* Create command buffers to initialize the pool */ + /* Create command buffer pool */ D3D11_INTERNAL_AllocateCommandBuffers(renderer, 2); /* Create uniform buffer pool */ renderer->availableUniformBufferCapacity = 2; renderer->availableUniformBuffers = SDL_malloc(sizeof(D3D11UniformBuffer*) * renderer->availableUniformBufferCapacity); + /* Create fence pool */ + D3D11_INTERNAL_AllocateFences(renderer, 2); + /* Create the Refresh Device */ result = (Refresh_Device*) SDL_malloc(sizeof(Refresh_Device)); ASSIGN_DRIVER(D3D11)