Transfer Buffer Pool (#7)
continuous-integration/drone/push Build is passing Details

Reviewed-on: #7
Co-authored-by: cosmonaut <evan@moonside.games>
Co-committed-by: cosmonaut <evan@moonside.games>
pull/12/head
cosmonaut 2022-01-20 22:56:28 +00:00
parent c5a689c6d6
commit 42f5f84524
1 changed files with 149 additions and 79 deletions

View File

@ -694,7 +694,7 @@ typedef struct VulkanUniformDescriptorPool
uint32_t availableDescriptorSetCount; uint32_t availableDescriptorSetCount;
} VulkanUniformDescriptorPool; } VulkanUniformDescriptorPool;
typedef struct VulkanUniformBufferPool struct VulkanUniformBufferPool
{ {
VulkanUniformBufferType type; VulkanUniformBufferType type;
VulkanUniformDescriptorPool descriptorPool; VulkanUniformDescriptorPool descriptorPool;
@ -711,7 +711,7 @@ typedef struct VulkanUniformBufferPool
VulkanUniformBuffer **submittedBuffers; VulkanUniformBuffer **submittedBuffers;
uint32_t submittedBufferCount; uint32_t submittedBufferCount;
uint32_t submittedBufferCapacity; uint32_t submittedBufferCapacity;
} VulkanUniformBufferPool; };
/* Renderer Structure */ /* Renderer Structure */
@ -1173,6 +1173,17 @@ typedef struct VulkanTransferBuffer
VkDeviceSize offset; VkDeviceSize offset;
} VulkanTransferBuffer; } VulkanTransferBuffer;
typedef struct VulkanTransferBufferPool
{
VulkanTransferBuffer **availableBuffers;
uint32_t availableBufferCount;
uint32_t availableBufferCapacity;
VulkanTransferBuffer **submittedBuffers;
uint32_t submittedBufferCount;
uint32_t submittedBufferCapacity;
} VulkanTransferBufferPool;
typedef struct VulkanCommandPool VulkanCommandPool; typedef struct VulkanCommandPool VulkanCommandPool;
typedef struct VulkanCommandBuffer typedef struct VulkanCommandBuffer
@ -1343,6 +1354,8 @@ typedef struct VulkanRenderer
uint32_t submittedCommandBufferCount; uint32_t submittedCommandBufferCount;
uint32_t submittedCommandBufferCapacity; uint32_t submittedCommandBufferCapacity;
VulkanTransferBufferPool transferBufferPool;
CommandPoolHashTable commandPoolHashTable; CommandPoolHashTable commandPoolHashTable;
DescriptorSetLayoutHashTable descriptorSetLayoutHashTable; DescriptorSetLayoutHashTable descriptorSetLayoutHashTable;
GraphicsPipelineLayoutHashTable graphicsPipelineLayoutHashTable; GraphicsPipelineLayoutHashTable graphicsPipelineLayoutHashTable;
@ -3919,6 +3932,23 @@ static void VULKAN_INTERNAL_PostWorkCleanup(VulkanRenderer* renderer)
VULKAN_INTERNAL_RotateBoundUniformBuffers(renderer->fragmentUniformBufferPool); VULKAN_INTERNAL_RotateBoundUniformBuffers(renderer->fragmentUniformBufferPool);
VULKAN_INTERNAL_RotateBoundUniformBuffers(renderer->computeUniformBufferPool); VULKAN_INTERNAL_RotateBoundUniformBuffers(renderer->computeUniformBufferPool);
if (renderer->transferBufferPool.submittedBufferCount + renderer->transferBufferPool.availableBufferCount > renderer->transferBufferPool.availableBufferCapacity)
{
renderer->transferBufferPool.availableBufferCapacity = renderer->transferBufferPool.submittedBufferCount + renderer->transferBufferPool.availableBufferCount;
renderer->transferBufferPool.availableBuffers = SDL_realloc(
renderer->transferBufferPool.availableBuffers,
renderer->transferBufferPool.availableBufferCapacity * sizeof(VulkanTransferBuffer*)
);
}
for (i = 0; i < renderer->transferBufferPool.submittedBufferCount; i += 1)
{
renderer->transferBufferPool.submittedBuffers[i]->offset = 0;
renderer->transferBufferPool.availableBuffers[renderer->transferBufferPool.availableBufferCount] = renderer->transferBufferPool.submittedBuffers[i];
renderer->transferBufferPool.availableBufferCount += 1;
}
renderer->transferBufferPool.submittedBufferCount = 0;
/* Reset descriptor set data */ /* Reset descriptor set data */
VULKAN_INTERNAL_ResetDescriptorSetData(renderer); VULKAN_INTERNAL_ResetDescriptorSetData(renderer);
} }
@ -6251,74 +6281,81 @@ static Refresh_Buffer* VULKAN_CreateBuffer(
/* Setters */ /* Setters */
static void VULKAN_INTERNAL_MaybeExpandTransferBuffer( static VulkanTransferBuffer* VULKAN_INTERNAL_AcquireTransferBuffer(
VulkanRenderer *renderer, VulkanRenderer *renderer,
VulkanCommandBuffer *commandBuffer, VulkanCommandBuffer *commandBuffer,
VkDeviceSize requiredSize VkDeviceSize requiredSize
) { ) {
VkDeviceSize size; VkDeviceSize size;
uint32_t i;
VulkanTransferBuffer *transferBuffer;
if (commandBuffer->transferBufferCount == 0) /* Search the command buffer's current transfer buffers */
for (i = 0; i < commandBuffer->transferBufferCount; i += 1)
{ {
size = TRANSFER_BUFFER_STARTING_SIZE; transferBuffer = commandBuffer->transferBuffers[i];
while (size < requiredSize) if (transferBuffer->offset + requiredSize <= transferBuffer->buffer->size)
{ {
size *= 2; return transferBuffer;
} }
commandBuffer->transferBuffers = SDL_realloc(commandBuffer->transferBuffers, sizeof(VulkanTransferBuffer*));
commandBuffer->transferBuffers[0] = SDL_malloc(sizeof(VulkanTransferBuffer));
commandBuffer->transferBuffers[0]->offset = 0;
commandBuffer->transferBuffers[0]->buffer = VULKAN_INTERNAL_CreateBuffer(
renderer,
size,
RESOURCE_ACCESS_MEMORY_TRANSFER_READ_WRITE,
VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT
);
if (commandBuffer->transferBuffers[0]->buffer == NULL)
{
Refresh_LogError("Failed to allocate transfer buffer!");
return;
}
commandBuffer->transferBufferCount += 1;
} }
else
/* Nothing fits, so let's get a transfer buffer from the pool */
for (i = 0; i < renderer->transferBufferPool.availableBufferCount; i += 1)
{ {
VkDeviceSize currentSize = commandBuffer->transferBuffers[commandBuffer->transferBufferCount - 1]->buffer->size; transferBuffer = renderer->transferBufferPool.availableBuffers[i];
VkDeviceSize nextStagingSize = currentSize * 2;
if (commandBuffer->transferBuffers[commandBuffer->transferBufferCount - 1]->offset + requiredSize <= currentSize) if (transferBuffer->offset + requiredSize <= transferBuffer->buffer->size)
{ {
return; commandBuffer->transferBuffers = SDL_realloc(
commandBuffer->transferBuffers,
(commandBuffer->transferBufferCount + 1) * sizeof(VulkanTransferBuffer*)
);
commandBuffer->transferBuffers[commandBuffer->transferBufferCount] = transferBuffer;
commandBuffer->transferBufferCount += 1;
renderer->transferBufferPool.availableBuffers[i] = renderer->transferBufferPool.availableBuffers[renderer->transferBufferPool.availableBufferCount - 1];
renderer->transferBufferPool.availableBufferCount -= 1;
return transferBuffer;
} }
while (nextStagingSize < requiredSize)
{
nextStagingSize *= 2;
}
commandBuffer->transferBuffers = SDL_realloc(commandBuffer->transferBuffers, sizeof(VulkanTransferBuffer*) * (commandBuffer->transferBufferCount + 1));
commandBuffer->transferBuffers[commandBuffer->transferBufferCount] = SDL_malloc(sizeof(VulkanTransferBuffer));
commandBuffer->transferBuffers[commandBuffer->transferBufferCount]->offset = 0;
commandBuffer->transferBuffers[commandBuffer->transferBufferCount]->buffer = VULKAN_INTERNAL_CreateBuffer(
renderer,
nextStagingSize,
RESOURCE_ACCESS_MEMORY_TRANSFER_READ_WRITE,
VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT
);
if (commandBuffer->transferBuffers[commandBuffer->transferBufferCount]->buffer == NULL)
{
Refresh_LogError("Failed to expand texture staging buffer!");
}
commandBuffer->transferBufferCount += 1;
} }
/* Nothing fits still, so let's create a new transfer buffer */
size = TRANSFER_BUFFER_STARTING_SIZE;
while (size < requiredSize)
{
size *= 2;
}
transferBuffer = SDL_malloc(sizeof(VulkanTransferBuffer));
transferBuffer->offset = 0;
transferBuffer->buffer = VULKAN_INTERNAL_CreateBuffer(
renderer,
size,
RESOURCE_ACCESS_MEMORY_TRANSFER_READ_WRITE,
VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT
);
if (transferBuffer == NULL)
{
Refresh_LogError("Failed to allocate transfer buffer!");
return NULL;
}
commandBuffer->transferBuffers = SDL_realloc(
commandBuffer->transferBuffers,
(commandBuffer->transferBufferCount + 1) * sizeof(VulkanTransferBuffer*)
);
commandBuffer->transferBuffers[commandBuffer->transferBufferCount] = transferBuffer;
commandBuffer->transferBufferCount += 1;
return transferBuffer;
} }
static void VULKAN_SetTextureData( static void VULKAN_SetTextureData(
@ -6331,6 +6368,7 @@ static void VULKAN_SetTextureData(
VulkanRenderer *renderer = (VulkanRenderer*) driverData; VulkanRenderer *renderer = (VulkanRenderer*) driverData;
VulkanTexture *vulkanTexture = (VulkanTexture*) textureSlice->texture; VulkanTexture *vulkanTexture = (VulkanTexture*) textureSlice->texture;
VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer*) commandBuffer; VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer*) commandBuffer;
VulkanTransferBuffer *transferBuffer;
VkBufferImageCopy imageCopy; VkBufferImageCopy imageCopy;
uint8_t *stagingBufferPointer; uint8_t *stagingBufferPointer;
@ -6340,7 +6378,7 @@ static void VULKAN_SetTextureData(
return; return;
} }
VULKAN_INTERNAL_MaybeExpandTransferBuffer( transferBuffer = VULKAN_INTERNAL_AcquireTransferBuffer(
renderer, renderer,
vulkanCommandBuffer, vulkanCommandBuffer,
VULKAN_INTERNAL_BytesPerImage( VULKAN_INTERNAL_BytesPerImage(
@ -6350,10 +6388,15 @@ static void VULKAN_SetTextureData(
) )
); );
if (transferBuffer == NULL)
{
return;
}
stagingBufferPointer = stagingBufferPointer =
vulkanCommandBuffer->transferBuffers[vulkanCommandBuffer->transferBufferCount - 1]->buffer->allocation->mapPointer + transferBuffer->buffer->allocation->mapPointer +
vulkanCommandBuffer->transferBuffers[vulkanCommandBuffer->transferBufferCount - 1]->buffer->offset + transferBuffer->buffer->offset +
vulkanCommandBuffer->transferBuffers[vulkanCommandBuffer->transferBufferCount - 1]->offset; transferBuffer->offset;
SDL_memcpy( SDL_memcpy(
stagingBufferPointer, stagingBufferPointer,
@ -6385,20 +6428,20 @@ static void VULKAN_SetTextureData(
imageCopy.imageSubresource.baseArrayLayer = textureSlice->layer; imageCopy.imageSubresource.baseArrayLayer = textureSlice->layer;
imageCopy.imageSubresource.layerCount = 1; imageCopy.imageSubresource.layerCount = 1;
imageCopy.imageSubresource.mipLevel = textureSlice->level; imageCopy.imageSubresource.mipLevel = textureSlice->level;
imageCopy.bufferOffset = vulkanCommandBuffer->transferBuffers[vulkanCommandBuffer->transferBufferCount - 1]->offset; imageCopy.bufferOffset = transferBuffer->offset;
imageCopy.bufferRowLength = 0; imageCopy.bufferRowLength = 0;
imageCopy.bufferImageHeight = 0; imageCopy.bufferImageHeight = 0;
renderer->vkCmdCopyBufferToImage( renderer->vkCmdCopyBufferToImage(
vulkanCommandBuffer->commandBuffer, vulkanCommandBuffer->commandBuffer,
vulkanCommandBuffer->transferBuffers[vulkanCommandBuffer->transferBufferCount - 1]->buffer->buffer, transferBuffer->buffer->buffer,
vulkanTexture->image, vulkanTexture->image,
AccessMap[vulkanTexture->resourceAccessType].imageLayout, AccessMap[vulkanTexture->resourceAccessType].imageLayout,
1, 1,
&imageCopy &imageCopy
); );
vulkanCommandBuffer->transferBuffers[vulkanCommandBuffer->transferBufferCount - 1]->offset += dataLengthInBytes; transferBuffer->offset += dataLengthInBytes;
if (vulkanTexture->usageFlags & VK_IMAGE_USAGE_SAMPLED_BIT) if (vulkanTexture->usageFlags & VK_IMAGE_USAGE_SAMPLED_BIT)
{ {
@ -6434,23 +6477,29 @@ static void VULKAN_SetTextureDataYUV(
VulkanRenderer *renderer = (VulkanRenderer*) driverData; VulkanRenderer *renderer = (VulkanRenderer*) driverData;
VulkanTexture *tex; VulkanTexture *tex;
VulkanCommandBuffer* vulkanCommandBuffer = (VulkanCommandBuffer*)commandBuffer; VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer*)commandBuffer;
VulkanTransferBuffer *transferBuffer;
uint8_t *dataPtr = (uint8_t*) data; uint8_t *dataPtr = (uint8_t*) data;
int32_t yDataLength = BytesPerImage(yWidth, yHeight, REFRESH_TEXTUREFORMAT_R8); int32_t yDataLength = BytesPerImage(yWidth, yHeight, REFRESH_TEXTUREFORMAT_R8);
int32_t uvDataLength = BytesPerImage(uvWidth, uvHeight, REFRESH_TEXTUREFORMAT_R8); int32_t uvDataLength = BytesPerImage(uvWidth, uvHeight, REFRESH_TEXTUREFORMAT_R8);
VkBufferImageCopy imageCopy; VkBufferImageCopy imageCopy;
uint8_t * stagingBufferPointer; uint8_t * stagingBufferPointer;
VULKAN_INTERNAL_MaybeExpandTransferBuffer( transferBuffer = VULKAN_INTERNAL_AcquireTransferBuffer(
renderer, renderer,
vulkanCommandBuffer, vulkanCommandBuffer,
yDataLength + uvDataLength yDataLength + uvDataLength
); );
if (transferBuffer == NULL)
{
return;
}
stagingBufferPointer = stagingBufferPointer =
vulkanCommandBuffer->transferBuffers[vulkanCommandBuffer->transferBufferCount - 1]->buffer->allocation->mapPointer + transferBuffer->buffer->allocation->mapPointer +
vulkanCommandBuffer->transferBuffers[vulkanCommandBuffer->transferBufferCount - 1]->buffer->offset + transferBuffer->buffer->offset +
vulkanCommandBuffer->transferBuffers[vulkanCommandBuffer->transferBufferCount - 1]->offset; transferBuffer->offset;
/* Initialize values that are the same for Y, U, and V */ /* Initialize values that are the same for Y, U, and V */
@ -6490,13 +6539,13 @@ static void VULKAN_SetTextureDataYUV(
imageCopy.imageExtent.width = yWidth; imageCopy.imageExtent.width = yWidth;
imageCopy.imageExtent.height = yHeight; imageCopy.imageExtent.height = yHeight;
imageCopy.bufferOffset = vulkanCommandBuffer->transferBuffers[vulkanCommandBuffer->transferBufferCount - 1]->offset; imageCopy.bufferOffset = transferBuffer->offset;
imageCopy.bufferRowLength = yWidth; imageCopy.bufferRowLength = yWidth;
imageCopy.bufferImageHeight = yHeight; imageCopy.bufferImageHeight = yHeight;
renderer->vkCmdCopyBufferToImage( renderer->vkCmdCopyBufferToImage(
vulkanCommandBuffer->commandBuffer, vulkanCommandBuffer->commandBuffer,
vulkanCommandBuffer->transferBuffers[vulkanCommandBuffer->transferBufferCount - 1]->buffer->buffer, transferBuffer->buffer->buffer,
tex->image, tex->image,
AccessMap[tex->resourceAccessType].imageLayout, AccessMap[tex->resourceAccessType].imageLayout,
1, 1,
@ -6512,7 +6561,7 @@ static void VULKAN_SetTextureDataYUV(
/* U */ /* U */
imageCopy.bufferOffset = vulkanCommandBuffer->transferBuffers[vulkanCommandBuffer->transferBufferCount - 1]->offset + yDataLength; imageCopy.bufferOffset = transferBuffer->offset + yDataLength;
tex = (VulkanTexture*) u; tex = (VulkanTexture*) u;
@ -6538,7 +6587,7 @@ static void VULKAN_SetTextureDataYUV(
renderer->vkCmdCopyBufferToImage( renderer->vkCmdCopyBufferToImage(
vulkanCommandBuffer->commandBuffer, vulkanCommandBuffer->commandBuffer,
vulkanCommandBuffer->transferBuffers[vulkanCommandBuffer->transferBufferCount - 1]->buffer->buffer, transferBuffer->buffer->buffer,
tex->image, tex->image,
AccessMap[tex->resourceAccessType].imageLayout, AccessMap[tex->resourceAccessType].imageLayout,
1, 1,
@ -6547,7 +6596,7 @@ static void VULKAN_SetTextureDataYUV(
/* V */ /* V */
imageCopy.bufferOffset = vulkanCommandBuffer->transferBuffers[vulkanCommandBuffer->transferBufferCount - 1]->offset + yDataLength + uvDataLength; imageCopy.bufferOffset = transferBuffer->offset + yDataLength + uvDataLength;
tex = (VulkanTexture*) v; tex = (VulkanTexture*) v;
@ -6573,14 +6622,14 @@ static void VULKAN_SetTextureDataYUV(
renderer->vkCmdCopyBufferToImage( renderer->vkCmdCopyBufferToImage(
vulkanCommandBuffer->commandBuffer, vulkanCommandBuffer->commandBuffer,
vulkanCommandBuffer->transferBuffers[vulkanCommandBuffer->transferBufferCount - 1]->buffer->buffer, transferBuffer->buffer->buffer,
tex->image, tex->image,
AccessMap[tex->resourceAccessType].imageLayout, AccessMap[tex->resourceAccessType].imageLayout,
1, 1,
&imageCopy &imageCopy
); );
vulkanCommandBuffer->transferBuffers[vulkanCommandBuffer->transferBufferCount - 1]->offset += yDataLength + uvDataLength; transferBuffer->offset += yDataLength + uvDataLength;
if (tex->usageFlags & VK_IMAGE_USAGE_SAMPLED_BIT) if (tex->usageFlags & VK_IMAGE_USAGE_SAMPLED_BIT)
{ {
@ -6781,13 +6830,16 @@ static void VULKAN_SetBufferData(
return; return;
} }
VULKAN_INTERNAL_MaybeExpandTransferBuffer( transferBuffer = VULKAN_INTERNAL_AcquireTransferBuffer(
renderer, renderer,
vulkanCommandBuffer, vulkanCommandBuffer,
dataLength dataLength
); );
transferBuffer = vulkanCommandBuffer->transferBuffers[vulkanCommandBuffer->transferBufferCount - 1]; if (transferBuffer == NULL)
{
return;
}
transferBufferPointer = transferBufferPointer =
transferBuffer->buffer->allocation->mapPointer + transferBuffer->buffer->allocation->mapPointer +
@ -8397,12 +8449,20 @@ static void VULKAN_INTERNAL_ResetCommandBuffer(
LogVulkanResultAsError("vkResetCommandBuffer", vulkanResult); LogVulkanResultAsError("vkResetCommandBuffer", vulkanResult);
} }
/* Return transfer buffers to the pool */
if (renderer->transferBufferPool.submittedBufferCount + commandBuffer->transferBufferCount > renderer->transferBufferPool.submittedBufferCapacity)
{
renderer->transferBufferPool.submittedBufferCapacity = renderer->transferBufferPool.submittedBufferCount + commandBuffer->transferBufferCount;
renderer->transferBufferPool.submittedBuffers = SDL_realloc(
renderer->transferBufferPool.submittedBuffers,
renderer->transferBufferPool.submittedBufferCapacity * sizeof(VulkanTransferBuffer*)
);
}
for (i = 0; i < commandBuffer->transferBufferCount; i+= 1) for (i = 0; i < commandBuffer->transferBufferCount; i+= 1)
{ {
VULKAN_INTERNAL_DestroyBuffer( renderer->transferBufferPool.submittedBuffers[renderer->transferBufferPool.submittedBufferCount] = commandBuffer->transferBuffers[i];
renderer, renderer->transferBufferPool.submittedBufferCount += 1;
commandBuffer->transferBuffers[i]->buffer
);
} }
SDL_free(commandBuffer->transferBuffers); SDL_free(commandBuffer->transferBuffers);
@ -9779,6 +9839,16 @@ static Refresh_Device* VULKAN_INTERNAL_CreateDevice(
renderer->descriptorSetLayoutHashTable.buckets[i].capacity = 0; renderer->descriptorSetLayoutHashTable.buckets[i].capacity = 0;
} }
/* Initialize transfer buffer pool */
renderer->transferBufferPool.availableBufferCapacity = 4;
renderer->transferBufferPool.availableBufferCount = 0;
renderer->transferBufferPool.availableBuffers = SDL_malloc(renderer->transferBufferPool.availableBufferCapacity * sizeof(VulkanTransferBuffer*));
renderer->transferBufferPool.submittedBufferCapacity = 4;
renderer->transferBufferPool.submittedBufferCount = 0;
renderer->transferBufferPool.submittedBuffers = SDL_malloc(renderer->transferBufferPool.submittedBufferCapacity * sizeof(VulkanTransferBuffer*));
/* Deferred destroy storage */ /* Deferred destroy storage */
renderer->renderTargetsToDestroyCapacity = 16; renderer->renderTargetsToDestroyCapacity = 16;