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