forked from MoonsideGames/Refresh
Reworked Wait and Submit logic to use D3D11 Query objects as fences
parent
413095923b
commit
ce984f58d1
|
@ -298,7 +298,6 @@ typedef struct D3D11CommandBuffer
|
||||||
{
|
{
|
||||||
/* D3D11 Object References */
|
/* D3D11 Object References */
|
||||||
ID3D11DeviceContext *context;
|
ID3D11DeviceContext *context;
|
||||||
ID3D11CommandList *commandList;
|
|
||||||
D3D11SwapchainData *swapchainData;
|
D3D11SwapchainData *swapchainData;
|
||||||
|
|
||||||
/* Render Pass */
|
/* Render Pass */
|
||||||
|
@ -308,7 +307,7 @@ typedef struct D3D11CommandBuffer
|
||||||
|
|
||||||
/* State */
|
/* State */
|
||||||
SDL_threadID threadID;
|
SDL_threadID threadID;
|
||||||
uint8_t recording;
|
ID3D11Query *completionQuery;
|
||||||
} D3D11CommandBuffer;
|
} D3D11CommandBuffer;
|
||||||
|
|
||||||
typedef struct D3D11CommandBufferPool
|
typedef struct D3D11CommandBufferPool
|
||||||
|
@ -339,7 +338,11 @@ typedef struct D3D11Renderer
|
||||||
D3D11CommandBufferPool *commandBufferPool;
|
D3D11CommandBufferPool *commandBufferPool;
|
||||||
|
|
||||||
SDL_mutex *contextLock;
|
SDL_mutex *contextLock;
|
||||||
SDL_mutex *commandBufferAcquisitionLock;
|
SDL_mutex *acquireCommandBufferLock;
|
||||||
|
|
||||||
|
D3D11CommandBuffer **submittedCommandBuffers;
|
||||||
|
uint32_t submittedCommandBufferCount;
|
||||||
|
uint32_t submittedCommandBufferCapacity;
|
||||||
} D3D11Renderer;
|
} D3D11Renderer;
|
||||||
|
|
||||||
/* Logging */
|
/* Logging */
|
||||||
|
@ -690,65 +693,82 @@ static void D3D11_QueueDestroyGraphicsPipeline(
|
||||||
|
|
||||||
/* Graphics State */
|
/* Graphics State */
|
||||||
|
|
||||||
|
static void D3D11_INTERNAL_AllocateCommandBuffers(
|
||||||
|
D3D11Renderer *renderer,
|
||||||
|
uint32_t allocateCount
|
||||||
|
) {
|
||||||
|
D3D11CommandBufferPool *pool = renderer->commandBufferPool;
|
||||||
|
D3D11CommandBuffer *commandBuffer;
|
||||||
|
D3D11_QUERY_DESC queryDesc;
|
||||||
|
HRESULT res;
|
||||||
|
|
||||||
|
pool->capacity += allocateCount;
|
||||||
|
|
||||||
|
pool->elements = SDL_realloc(
|
||||||
|
pool->elements,
|
||||||
|
sizeof(D3D11CommandBuffer*) * pool->capacity
|
||||||
|
);
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < allocateCount; i += 1)
|
||||||
|
{
|
||||||
|
commandBuffer = SDL_malloc(sizeof(D3D11CommandBuffer));
|
||||||
|
|
||||||
|
res = ID3D11Device_CreateDeferredContext(
|
||||||
|
renderer->device,
|
||||||
|
0,
|
||||||
|
&commandBuffer->context
|
||||||
|
);
|
||||||
|
ERROR_CHECK("Could not create deferred context! Error Code: %08X");
|
||||||
|
|
||||||
|
queryDesc.Query = D3D11_QUERY_EVENT;
|
||||||
|
queryDesc.MiscFlags = 0;
|
||||||
|
res = ID3D11Device_CreateQuery(
|
||||||
|
renderer->device,
|
||||||
|
&queryDesc,
|
||||||
|
&commandBuffer->completionQuery
|
||||||
|
);
|
||||||
|
ERROR_CHECK("Could not create query! Error Code: %08X");
|
||||||
|
|
||||||
|
/* FIXME: Resource tracking? */
|
||||||
|
|
||||||
|
pool->elements[pool->count] = commandBuffer;
|
||||||
|
pool->count += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static D3D11CommandBuffer* D3D11_INTERNAL_GetInactiveCommandBufferFromPool(
|
||||||
|
D3D11Renderer *renderer
|
||||||
|
) {
|
||||||
|
D3D11CommandBufferPool *commandPool = renderer->commandBufferPool;
|
||||||
|
D3D11CommandBuffer *commandBuffer;
|
||||||
|
|
||||||
|
if (commandPool->count == 0)
|
||||||
|
{
|
||||||
|
D3D11_INTERNAL_AllocateCommandBuffers(
|
||||||
|
renderer,
|
||||||
|
commandPool->capacity
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
commandBuffer = commandPool->elements[commandPool->count - 1];
|
||||||
|
commandPool->count -= 1;
|
||||||
|
|
||||||
|
return commandBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
static Refresh_CommandBuffer* D3D11_AcquireCommandBuffer(
|
static Refresh_CommandBuffer* D3D11_AcquireCommandBuffer(
|
||||||
Refresh_Renderer *driverData
|
Refresh_Renderer *driverData
|
||||||
) {
|
) {
|
||||||
D3D11Renderer *renderer = (D3D11Renderer*) driverData;
|
D3D11Renderer *renderer = (D3D11Renderer*) driverData;
|
||||||
D3D11CommandBuffer *commandBuffer = NULL;
|
D3D11CommandBuffer *commandBuffer;
|
||||||
uint32_t i;
|
uint32_t i;
|
||||||
HRESULT res;
|
|
||||||
|
|
||||||
/* Make sure multiple threads can't acquire the same command buffer. */
|
SDL_LockMutex(renderer->acquireCommandBufferLock);
|
||||||
SDL_LockMutex(renderer->commandBufferAcquisitionLock);
|
|
||||||
|
|
||||||
/* Try to use an existing command buffer, if one is available. */
|
|
||||||
for (i = 0; i < renderer->commandBufferPool->count; i += 1)
|
|
||||||
{
|
|
||||||
/* Search for a command buffer in the pool that is not recording. */
|
|
||||||
if (!renderer->commandBufferPool->elements[i]->recording)
|
|
||||||
{
|
|
||||||
commandBuffer = renderer->commandBufferPool->elements[i];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If there are no free command buffers, make a new one. */
|
|
||||||
if (commandBuffer == NULL)
|
|
||||||
{
|
|
||||||
/* Expand the capacity as needed */
|
|
||||||
EXPAND_ELEMENTS_IF_NEEDED(
|
|
||||||
renderer->commandBufferPool,
|
|
||||||
2,
|
|
||||||
D3D11CommandBuffer*
|
|
||||||
);
|
|
||||||
|
|
||||||
/* Create a new command buffer */
|
|
||||||
renderer->commandBufferPool->elements[i] = (D3D11CommandBuffer*) SDL_malloc(
|
|
||||||
sizeof(D3D11CommandBuffer)
|
|
||||||
);
|
|
||||||
|
|
||||||
/* Assign it a new deferred context */
|
|
||||||
res = ID3D11Device_CreateDeferredContext(
|
|
||||||
renderer->device,
|
|
||||||
0,
|
|
||||||
&renderer->commandBufferPool->elements[i]->context
|
|
||||||
);
|
|
||||||
if (FAILED(res))
|
|
||||||
{
|
|
||||||
SDL_UnlockMutex(renderer->commandBufferAcquisitionLock);
|
|
||||||
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];
|
|
||||||
renderer->commandBufferPool->count += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Set up the command buffer */
|
/* Set up the command buffer */
|
||||||
|
commandBuffer = D3D11_INTERNAL_GetInactiveCommandBufferFromPool(renderer);
|
||||||
commandBuffer->threadID = SDL_ThreadID();
|
commandBuffer->threadID = SDL_ThreadID();
|
||||||
commandBuffer->recording = 1;
|
|
||||||
commandBuffer->swapchainData = NULL;
|
commandBuffer->swapchainData = NULL;
|
||||||
commandBuffer->commandList = NULL;
|
|
||||||
commandBuffer->dsView = NULL;
|
commandBuffer->dsView = NULL;
|
||||||
commandBuffer->numBoundColorAttachments = 0;
|
commandBuffer->numBoundColorAttachments = 0;
|
||||||
for (i = 0; i < MAX_COLOR_TARGET_BINDINGS; i += 1)
|
for (i = 0; i < MAX_COLOR_TARGET_BINDINGS; i += 1)
|
||||||
|
@ -756,7 +776,7 @@ static Refresh_CommandBuffer* D3D11_AcquireCommandBuffer(
|
||||||
commandBuffer->rtViews[i] = NULL;
|
commandBuffer->rtViews[i] = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_UnlockMutex(renderer->commandBufferAcquisitionLock);
|
SDL_UnlockMutex(renderer->acquireCommandBufferLock);
|
||||||
|
|
||||||
return (Refresh_CommandBuffer*) commandBuffer;
|
return (Refresh_CommandBuffer*) commandBuffer;
|
||||||
}
|
}
|
||||||
|
@ -1335,6 +1355,41 @@ static void D3D11_SetSwapchainPresentMode(
|
||||||
|
|
||||||
/* Submission and Fences */
|
/* Submission and Fences */
|
||||||
|
|
||||||
|
static void D3D11_INTERNAL_CleanCommandBuffer(
|
||||||
|
D3D11Renderer *renderer,
|
||||||
|
D3D11CommandBuffer *commandBuffer
|
||||||
|
) {
|
||||||
|
uint32_t i;
|
||||||
|
|
||||||
|
/* FIXME: All kinds of stuff should go here... */
|
||||||
|
|
||||||
|
SDL_LockMutex(renderer->acquireCommandBufferLock);
|
||||||
|
|
||||||
|
if (renderer->commandBufferPool->count == renderer->commandBufferPool->capacity)
|
||||||
|
{
|
||||||
|
renderer->commandBufferPool->capacity += 1;
|
||||||
|
renderer->commandBufferPool->elements = SDL_realloc(
|
||||||
|
renderer->commandBufferPool->elements,
|
||||||
|
renderer->commandBufferPool->capacity * sizeof(D3D11CommandBuffer*)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderer->commandBufferPool->elements[renderer->commandBufferPool->count] = commandBuffer;
|
||||||
|
renderer->commandBufferPool->count += 1;
|
||||||
|
|
||||||
|
SDL_UnlockMutex(renderer->acquireCommandBufferLock);
|
||||||
|
|
||||||
|
/* Remove this command buffer from the submitted list */
|
||||||
|
for (i = 0; i < renderer->submittedCommandBufferCount; i += 1)
|
||||||
|
{
|
||||||
|
if (renderer->submittedCommandBuffers[i] == commandBuffer)
|
||||||
|
{
|
||||||
|
renderer->submittedCommandBuffers[i] = renderer->submittedCommandBuffers[renderer->submittedCommandBufferCount - 1];
|
||||||
|
renderer->submittedCommandBufferCount -= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void D3D11_Submit(
|
static void D3D11_Submit(
|
||||||
Refresh_Renderer *driverData,
|
Refresh_Renderer *driverData,
|
||||||
Refresh_CommandBuffer *commandBuffer
|
Refresh_CommandBuffer *commandBuffer
|
||||||
|
@ -1346,6 +1401,8 @@ static void D3D11_Submit(
|
||||||
|
|
||||||
/* FIXME: Should add sanity check that current thread ID matches the command buffer's threadID. */
|
/* FIXME: Should add sanity check that current thread ID matches the command buffer's threadID. */
|
||||||
|
|
||||||
|
SDL_LockMutex(renderer->contextLock);
|
||||||
|
|
||||||
/* Serialize the commands into the command list */
|
/* Serialize the commands into the command list */
|
||||||
res = ID3D11DeviceContext_FinishCommandList(
|
res = ID3D11DeviceContext_FinishCommandList(
|
||||||
d3d11CommandBuffer->context,
|
d3d11CommandBuffer->context,
|
||||||
|
@ -1355,31 +1412,40 @@ static void D3D11_Submit(
|
||||||
ERROR_CHECK("Could not finish command list recording!");
|
ERROR_CHECK("Could not finish command list recording!");
|
||||||
|
|
||||||
/* Submit the command list to the immediate context */
|
/* Submit the command list to the immediate context */
|
||||||
SDL_LockMutex(renderer->contextLock);
|
|
||||||
ID3D11DeviceContext_ExecuteCommandList(
|
ID3D11DeviceContext_ExecuteCommandList(
|
||||||
renderer->immediateContext,
|
renderer->immediateContext,
|
||||||
commandList,
|
commandList,
|
||||||
0
|
0
|
||||||
);
|
);
|
||||||
SDL_UnlockMutex(renderer->contextLock);
|
|
||||||
|
|
||||||
/* Now that we're done with the command list, release it! */
|
|
||||||
ID3D11CommandList_Release(commandList);
|
ID3D11CommandList_Release(commandList);
|
||||||
|
|
||||||
/* Mark the command buffer as not-recording so that it can be used to record again. */
|
/* Mark the command buffer as submitted */
|
||||||
d3d11CommandBuffer->recording = 0;
|
if (renderer->submittedCommandBufferCount + 1 >= renderer->submittedCommandBufferCapacity)
|
||||||
|
{
|
||||||
|
renderer->submittedCommandBufferCapacity = renderer->submittedCommandBufferCount + 1;
|
||||||
|
|
||||||
|
renderer->submittedCommandBuffers = SDL_realloc(
|
||||||
|
renderer->submittedCommandBuffers,
|
||||||
|
sizeof(D3D11CommandBuffer*) * renderer->submittedCommandBufferCapacity
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderer->submittedCommandBuffers[renderer->submittedCommandBufferCount] = d3d11CommandBuffer;
|
||||||
|
renderer->submittedCommandBufferCount += 1;
|
||||||
|
|
||||||
|
SDL_UnlockMutex(renderer->contextLock);
|
||||||
|
|
||||||
/* Present, if applicable */
|
/* Present, if applicable */
|
||||||
if (d3d11CommandBuffer->swapchainData)
|
if (d3d11CommandBuffer->swapchainData)
|
||||||
{
|
{
|
||||||
SDL_LockMutex(renderer->contextLock);
|
|
||||||
IDXGISwapChain_Present(
|
IDXGISwapChain_Present(
|
||||||
d3d11CommandBuffer->swapchainData->swapchain,
|
d3d11CommandBuffer->swapchainData->swapchain,
|
||||||
1, /* FIXME: Assumes vsync! */
|
1, /* FIXME: Assumes vsync! */
|
||||||
0
|
0
|
||||||
);
|
);
|
||||||
SDL_UnlockMutex(renderer->contextLock);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SDL_UnlockMutex(renderer->contextLock);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Refresh_Fence* D3D11_SubmitAndAcquireFence(
|
static Refresh_Fence* D3D11_SubmitAndAcquireFence(
|
||||||
|
@ -1393,7 +1459,38 @@ static Refresh_Fence* D3D11_SubmitAndAcquireFence(
|
||||||
static void D3D11_Wait(
|
static void D3D11_Wait(
|
||||||
Refresh_Renderer *driverData
|
Refresh_Renderer *driverData
|
||||||
) {
|
) {
|
||||||
/* FIXME: Anything we need to do here? */
|
D3D11Renderer *renderer = (D3D11Renderer*) driverData;
|
||||||
|
D3D11CommandBuffer *commandBuffer;
|
||||||
|
BOOL queryData;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Wait for all submitted command buffers to complete.
|
||||||
|
* Sort of equivalent to vkDeviceWaitIdle.
|
||||||
|
*/
|
||||||
|
for (uint32_t i = 0; i < renderer->submittedCommandBufferCount; i += 1)
|
||||||
|
{
|
||||||
|
while (S_OK != ID3D11DeviceContext_GetData(
|
||||||
|
renderer->immediateContext,
|
||||||
|
(ID3D11Asynchronous*) renderer->submittedCommandBuffers[i]->completionQuery,
|
||||||
|
&queryData,
|
||||||
|
sizeof(queryData),
|
||||||
|
0
|
||||||
|
)) {
|
||||||
|
/* Spin until we get a result back... */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_LockMutex(renderer->contextLock);
|
||||||
|
|
||||||
|
for (int32_t i = renderer->submittedCommandBufferCount - 1; i >= 0; i -= 1)
|
||||||
|
{
|
||||||
|
commandBuffer = renderer->submittedCommandBuffers[i];
|
||||||
|
D3D11_INTERNAL_CleanCommandBuffer(renderer, commandBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* FIXME: D3D11_INTERNAL_PerformPendingDestroys(renderer); */
|
||||||
|
|
||||||
|
SDL_UnlockMutex(renderer->contextLock);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void D3D11_WaitForFences(
|
static void D3D11_WaitForFences(
|
||||||
|
@ -1673,7 +1770,7 @@ tryCreateDevice:
|
||||||
|
|
||||||
/* Create mutexes */
|
/* Create mutexes */
|
||||||
renderer->contextLock = SDL_CreateMutex();
|
renderer->contextLock = SDL_CreateMutex();
|
||||||
renderer->commandBufferAcquisitionLock = SDL_CreateMutex();
|
renderer->acquireCommandBufferLock = SDL_CreateMutex();
|
||||||
|
|
||||||
/* Initialize miscellaneous renderer members */
|
/* Initialize miscellaneous renderer members */
|
||||||
renderer->debugMode = (flags & D3D11_CREATE_DEVICE_DEBUG);
|
renderer->debugMode = (flags & D3D11_CREATE_DEVICE_DEBUG);
|
||||||
|
|
Loading…
Reference in New Issue