reduce transfer buffer alloc count + fix use after free

d3d11
cosmonaut 2024-03-06 14:17:43 -08:00
parent efd26f474a
commit bb57528242
1 changed files with 90 additions and 32 deletions

View File

@ -1,4 +1,4 @@
/* Refresh - XNA-inspired 3D Graphics Library with modern capabilities
/* Refresh - XNA-inspired 3D Graphics Library with modern capabilities
*
* Copyright (c) 2020 Evan Hemsley
*
@ -453,7 +453,7 @@ typedef struct D3D11TransferBufferContainer
*/
uint32_t bufferCapacity;
uint32_t bufferCount;
D3D11TransferBuffer **buffers;
D3D11TransferBuffer *buffers;
} D3D11TransferBufferContainer;
typedef struct D3D11UniformBuffer
@ -551,6 +551,10 @@ typedef struct D3D11Renderer
uint32_t availableFenceCount;
uint32_t availableFenceCapacity;
D3D11TransferBufferContainer **transferBufferContainersToDestroy;
uint32_t transferBufferContainersToDestroyCount;
uint32_t transferBufferContainersToDestroyCapacity;
SDL_mutex *contextLock;
SDL_mutex *acquireCommandBufferLock;
SDL_mutex *uniformBufferLock;
@ -1887,17 +1891,14 @@ static void D3D11_INTERNAL_TrackTransferBuffer(
commandBuffer->usedTransferBufferCount += 1;
}
static D3D11TransferBuffer* D3D11_INTERNAL_CreateTransferBuffer(
static void D3D11_INTERNAL_InitTransferBuffer(
D3D11Renderer *renderer,
uint32_t sizeInBytes
uint32_t sizeInBytes,
D3D11TransferBuffer *pTransferBuffer
) {
D3D11TransferBuffer *transferBuffer = (D3D11TransferBuffer*) SDL_malloc(sizeof(D3D11TransferBuffer));
transferBuffer->data = (uint8_t*) SDL_malloc(sizeInBytes);
transferBuffer->size = sizeInBytes;
SDL_AtomicSet(&transferBuffer->referenceCount, 0);
return transferBuffer;
pTransferBuffer->data = (uint8_t*) SDL_malloc(sizeInBytes);
pTransferBuffer->size = sizeInBytes;
SDL_AtomicSet(&pTransferBuffer->referenceCount, 0);
}
/* This actually returns a container handle so we can rotate buffers on Discard. */
@ -1907,15 +1908,19 @@ static Refresh_TransferBuffer* D3D11_CreateTransferBuffer(
) {
D3D11Renderer *renderer = (D3D11Renderer*) driverData;
D3D11TransferBufferContainer *container = (D3D11TransferBufferContainer*) SDL_malloc(sizeof(D3D11TransferBufferContainer));
D3D11TransferBuffer *transferBuffer = D3D11_INTERNAL_CreateTransferBuffer(renderer, sizeInBytes);
container->activeBuffer = transferBuffer;
container->bufferCapacity = 1;
container->bufferCount = 1;
container->buffers = SDL_malloc(
container->bufferCapacity * sizeof(D3D11TransferBuffer*)
container->bufferCapacity * sizeof(D3D11TransferBuffer)
);
container->buffers[0] = transferBuffer;
D3D11_INTERNAL_InitTransferBuffer(
renderer,
sizeInBytes,
&container->buffers[0]
);
container->activeBuffer = &container->buffers[0];
return (Refresh_TransferBuffer*) container;
}
@ -1928,30 +1933,29 @@ static void D3D11_INTERNAL_DiscardActiveTransferBuffer(
) {
for (uint32_t i = 0; i < container->bufferCount; i += 1)
{
if (SDL_AtomicGet(&container->buffers[i]->referenceCount) == 0)
if (SDL_AtomicGet(&container->buffers[i].referenceCount) == 0)
{
container->activeBuffer = container->buffers[i];
container->activeBuffer = &container->buffers[i];
return;
}
}
container->activeBuffer = D3D11_INTERNAL_CreateTransferBuffer(
renderer,
container->activeBuffer->size
);
EXPAND_ARRAY_IF_NEEDED(
container->buffers,
D3D11TransferBuffer*,
D3D11TransferBuffer,
container->bufferCount + 1,
container->bufferCapacity,
container->bufferCapacity * 2
container->bufferCapacity + 1
);
container->buffers[
container->bufferCapacity
] = container->activeBuffer;
D3D11_INTERNAL_InitTransferBuffer(
renderer,
container->activeBuffer->size,
&container->buffers[container->bufferCount]
);
container->bufferCount += 1;
container->activeBuffer = &container->buffers[container->bufferCount - 1];
}
static void D3D11_SetTransferData(
@ -2774,14 +2778,34 @@ static void D3D11_QueueDestroyTransferBuffer(
Refresh_Renderer *driverData,
Refresh_TransferBuffer *transferBuffer
) {
D3D11TransferBufferContainer *container = (D3D11TransferBufferContainer*) transferBuffer;
D3D11Renderer *renderer = (D3D11Renderer*) driverData;
for (uint32_t i = 0; i < container->bufferCount; i += 1)
{
SDL_free(container->buffers[i]->data);
SDL_free(container->buffers[i]);
SDL_LockMutex(renderer->contextLock);
EXPAND_ARRAY_IF_NEEDED(
renderer->transferBufferContainersToDestroy,
D3D11TransferBufferContainer*,
renderer->transferBufferContainersToDestroyCount + 1,
renderer->transferBufferContainersToDestroyCapacity,
renderer->transferBufferContainersToDestroyCapacity + 1
);
renderer->transferBufferContainersToDestroy[
renderer->transferBufferContainersToDestroyCount
] = (D3D11TransferBufferContainer*) transferBuffer;
renderer->transferBufferContainersToDestroyCount += 1;
SDL_UnlockMutex(renderer->contextLock);
}
SDL_free(container->buffers);
static void D3D11_INTERNAL_DestroyTransferBufferContainer(
D3D11TransferBufferContainer *transferBufferContainer
) {
for (uint32_t i = 0; i < transferBufferContainer->bufferCount; i += 1)
{
SDL_free(transferBufferContainer->buffers[i].data);
}
SDL_free(transferBufferContainer->buffers);
}
static void D3D11_QueueDestroyShaderModule(
@ -4035,6 +4059,29 @@ static void D3D11_INTERNAL_WaitForFence(
SDL_UnlockMutex(renderer->contextLock);
}
static void D3D11_INTERNAL_PerformPendingDestroys(
D3D11Renderer *renderer
) {
for (int32_t i = renderer->transferBufferContainersToDestroyCount - 1; i >= 0; i -= 1)
{
int32_t referenceCount = 0;
for (uint32_t j = 0; j < renderer->transferBufferContainersToDestroy[i]->bufferCount; j += 1)
{
referenceCount += SDL_AtomicGet(&renderer->transferBufferContainersToDestroy[i]->buffers[j].referenceCount);
}
if (referenceCount == 0)
{
D3D11_INTERNAL_DestroyTransferBufferContainer(
renderer->transferBufferContainersToDestroy[i]
);
renderer->transferBufferContainersToDestroy[i] = renderer->transferBufferContainersToDestroy[renderer->transferBufferContainersToDestroyCount - 1];
renderer->transferBufferContainersToDestroyCount -= 1;
}
}
}
static void D3D11_Submit(
Refresh_Renderer *driverData,
Refresh_CommandBuffer *commandBuffer
@ -4130,6 +4177,8 @@ static void D3D11_Submit(
}
}
D3D11_INTERNAL_PerformPendingDestroys(renderer);
SDL_UnlockMutex(renderer->contextLock);
}
@ -4172,6 +4221,8 @@ static void D3D11_Wait(
D3D11_INTERNAL_CleanCommandBuffer(renderer, commandBuffer);
}
D3D11_INTERNAL_PerformPendingDestroys(renderer);
SDL_UnlockMutex(renderer->contextLock);
}
@ -4636,6 +4687,13 @@ tryCreateDevice:
sizeof(D3D11Fence*) * renderer->availableFenceCapacity
);
/* Create deferred transfer array */
renderer->transferBufferContainersToDestroyCapacity = 2;
renderer->transferBufferContainersToDestroyCount = 0;
renderer->transferBufferContainersToDestroy = SDL_malloc(
renderer->transferBufferContainersToDestroyCapacity * sizeof(D3D11TransferBufferContainer*)
);
/* Create claimed window list */
renderer->claimedWindowCapacity = 1;
renderer->claimedWindows = SDL_malloc(