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;
} VulkanUniformDescriptorPool;
typedef struct VulkanUniformBufferPool
struct VulkanUniformBufferPool
{
VulkanUniformBufferType type;
VulkanUniformDescriptorPool descriptorPool;
@ -711,7 +711,7 @@ typedef struct VulkanUniformBufferPool
VulkanUniformBuffer **submittedBuffers;
uint32_t submittedBufferCount;
uint32_t submittedBufferCapacity;
} VulkanUniformBufferPool;
};
/* Renderer Structure */
@ -1173,6 +1173,17 @@ typedef struct VulkanTransferBuffer
VkDeviceSize offset;
} 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 VulkanCommandBuffer
@ -1343,6 +1354,8 @@ typedef struct VulkanRenderer
uint32_t submittedCommandBufferCount;
uint32_t submittedCommandBufferCapacity;
VulkanTransferBufferPool transferBufferPool;
CommandPoolHashTable commandPoolHashTable;
DescriptorSetLayoutHashTable descriptorSetLayoutHashTable;
GraphicsPipelineLayoutHashTable graphicsPipelineLayoutHashTable;
@ -3919,6 +3932,23 @@ static void VULKAN_INTERNAL_PostWorkCleanup(VulkanRenderer* renderer)
VULKAN_INTERNAL_RotateBoundUniformBuffers(renderer->fragmentUniformBufferPool);
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 */
VULKAN_INTERNAL_ResetDescriptorSetData(renderer);
}
@ -6251,15 +6281,51 @@ static Refresh_Buffer* VULKAN_CreateBuffer(
/* Setters */
static void VULKAN_INTERNAL_MaybeExpandTransferBuffer(
static VulkanTransferBuffer* VULKAN_INTERNAL_AcquireTransferBuffer(
VulkanRenderer *renderer,
VulkanCommandBuffer *commandBuffer,
VkDeviceSize requiredSize
) {
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)
{
transferBuffer = commandBuffer->transferBuffers[i];
if (transferBuffer->offset + requiredSize <= transferBuffer->buffer->size)
{
return transferBuffer;
}
}
/* Nothing fits, so let's get a transfer buffer from the pool */
for (i = 0; i < renderer->transferBufferPool.availableBufferCount; i += 1)
{
transferBuffer = renderer->transferBufferPool.availableBuffers[i];
if (transferBuffer->offset + requiredSize <= transferBuffer->buffer->size)
{
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;
}
}
/* Nothing fits still, so let's create a new transfer buffer */
size = TRANSFER_BUFFER_STARTING_SIZE;
while (size < requiredSize)
@ -6267,58 +6333,29 @@ static void VULKAN_INTERNAL_MaybeExpandTransferBuffer(
size *= 2;
}
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(
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 (commandBuffer->transferBuffers[0]->buffer == NULL)
if (transferBuffer == NULL)
{
Refresh_LogError("Failed to allocate transfer buffer!");
return;
return NULL;
}
commandBuffer->transferBufferCount += 1;
}
else
{
VkDeviceSize currentSize = commandBuffer->transferBuffers[commandBuffer->transferBufferCount - 1]->buffer->size;
VkDeviceSize nextStagingSize = currentSize * 2;
if (commandBuffer->transferBuffers[commandBuffer->transferBufferCount - 1]->offset + requiredSize <= currentSize)
{
return;
}
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
commandBuffer->transferBuffers = SDL_realloc(
commandBuffer->transferBuffers,
(commandBuffer->transferBufferCount + 1) * sizeof(VulkanTransferBuffer*)
);
if (commandBuffer->transferBuffers[commandBuffer->transferBufferCount]->buffer == NULL)
{
Refresh_LogError("Failed to expand texture staging buffer!");
}
commandBuffer->transferBuffers[commandBuffer->transferBufferCount] = transferBuffer;
commandBuffer->transferBufferCount += 1;
}
return transferBuffer;
}
static void VULKAN_SetTextureData(
@ -6331,6 +6368,7 @@ static void VULKAN_SetTextureData(
VulkanRenderer *renderer = (VulkanRenderer*) driverData;
VulkanTexture *vulkanTexture = (VulkanTexture*) textureSlice->texture;
VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer*) commandBuffer;
VulkanTransferBuffer *transferBuffer;
VkBufferImageCopy imageCopy;
uint8_t *stagingBufferPointer;
@ -6340,7 +6378,7 @@ static void VULKAN_SetTextureData(
return;
}
VULKAN_INTERNAL_MaybeExpandTransferBuffer(
transferBuffer = VULKAN_INTERNAL_AcquireTransferBuffer(
renderer,
vulkanCommandBuffer,
VULKAN_INTERNAL_BytesPerImage(
@ -6350,10 +6388,15 @@ static void VULKAN_SetTextureData(
)
);
if (transferBuffer == NULL)
{
return;
}
stagingBufferPointer =
vulkanCommandBuffer->transferBuffers[vulkanCommandBuffer->transferBufferCount - 1]->buffer->allocation->mapPointer +
vulkanCommandBuffer->transferBuffers[vulkanCommandBuffer->transferBufferCount - 1]->buffer->offset +
vulkanCommandBuffer->transferBuffers[vulkanCommandBuffer->transferBufferCount - 1]->offset;
transferBuffer->buffer->allocation->mapPointer +
transferBuffer->buffer->offset +
transferBuffer->offset;
SDL_memcpy(
stagingBufferPointer,
@ -6385,20 +6428,20 @@ static void VULKAN_SetTextureData(
imageCopy.imageSubresource.baseArrayLayer = textureSlice->layer;
imageCopy.imageSubresource.layerCount = 1;
imageCopy.imageSubresource.mipLevel = textureSlice->level;
imageCopy.bufferOffset = vulkanCommandBuffer->transferBuffers[vulkanCommandBuffer->transferBufferCount - 1]->offset;
imageCopy.bufferOffset = transferBuffer->offset;
imageCopy.bufferRowLength = 0;
imageCopy.bufferImageHeight = 0;
renderer->vkCmdCopyBufferToImage(
vulkanCommandBuffer->commandBuffer,
vulkanCommandBuffer->transferBuffers[vulkanCommandBuffer->transferBufferCount - 1]->buffer->buffer,
transferBuffer->buffer->buffer,
vulkanTexture->image,
AccessMap[vulkanTexture->resourceAccessType].imageLayout,
1,
&imageCopy
);
vulkanCommandBuffer->transferBuffers[vulkanCommandBuffer->transferBufferCount - 1]->offset += dataLengthInBytes;
transferBuffer->offset += dataLengthInBytes;
if (vulkanTexture->usageFlags & VK_IMAGE_USAGE_SAMPLED_BIT)
{
@ -6435,22 +6478,28 @@ static void VULKAN_SetTextureDataYUV(
VulkanTexture *tex;
VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer*)commandBuffer;
VulkanTransferBuffer *transferBuffer;
uint8_t *dataPtr = (uint8_t*) data;
int32_t yDataLength = BytesPerImage(yWidth, yHeight, REFRESH_TEXTUREFORMAT_R8);
int32_t uvDataLength = BytesPerImage(uvWidth, uvHeight, REFRESH_TEXTUREFORMAT_R8);
VkBufferImageCopy imageCopy;
uint8_t * stagingBufferPointer;
VULKAN_INTERNAL_MaybeExpandTransferBuffer(
transferBuffer = VULKAN_INTERNAL_AcquireTransferBuffer(
renderer,
vulkanCommandBuffer,
yDataLength + uvDataLength
);
if (transferBuffer == NULL)
{
return;
}
stagingBufferPointer =
vulkanCommandBuffer->transferBuffers[vulkanCommandBuffer->transferBufferCount - 1]->buffer->allocation->mapPointer +
vulkanCommandBuffer->transferBuffers[vulkanCommandBuffer->transferBufferCount - 1]->buffer->offset +
vulkanCommandBuffer->transferBuffers[vulkanCommandBuffer->transferBufferCount - 1]->offset;
transferBuffer->buffer->allocation->mapPointer +
transferBuffer->buffer->offset +
transferBuffer->offset;
/* 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.height = yHeight;
imageCopy.bufferOffset = vulkanCommandBuffer->transferBuffers[vulkanCommandBuffer->transferBufferCount - 1]->offset;
imageCopy.bufferOffset = transferBuffer->offset;
imageCopy.bufferRowLength = yWidth;
imageCopy.bufferImageHeight = yHeight;
renderer->vkCmdCopyBufferToImage(
vulkanCommandBuffer->commandBuffer,
vulkanCommandBuffer->transferBuffers[vulkanCommandBuffer->transferBufferCount - 1]->buffer->buffer,
transferBuffer->buffer->buffer,
tex->image,
AccessMap[tex->resourceAccessType].imageLayout,
1,
@ -6512,7 +6561,7 @@ static void VULKAN_SetTextureDataYUV(
/* U */
imageCopy.bufferOffset = vulkanCommandBuffer->transferBuffers[vulkanCommandBuffer->transferBufferCount - 1]->offset + yDataLength;
imageCopy.bufferOffset = transferBuffer->offset + yDataLength;
tex = (VulkanTexture*) u;
@ -6538,7 +6587,7 @@ static void VULKAN_SetTextureDataYUV(
renderer->vkCmdCopyBufferToImage(
vulkanCommandBuffer->commandBuffer,
vulkanCommandBuffer->transferBuffers[vulkanCommandBuffer->transferBufferCount - 1]->buffer->buffer,
transferBuffer->buffer->buffer,
tex->image,
AccessMap[tex->resourceAccessType].imageLayout,
1,
@ -6547,7 +6596,7 @@ static void VULKAN_SetTextureDataYUV(
/* V */
imageCopy.bufferOffset = vulkanCommandBuffer->transferBuffers[vulkanCommandBuffer->transferBufferCount - 1]->offset + yDataLength + uvDataLength;
imageCopy.bufferOffset = transferBuffer->offset + yDataLength + uvDataLength;
tex = (VulkanTexture*) v;
@ -6573,14 +6622,14 @@ static void VULKAN_SetTextureDataYUV(
renderer->vkCmdCopyBufferToImage(
vulkanCommandBuffer->commandBuffer,
vulkanCommandBuffer->transferBuffers[vulkanCommandBuffer->transferBufferCount - 1]->buffer->buffer,
transferBuffer->buffer->buffer,
tex->image,
AccessMap[tex->resourceAccessType].imageLayout,
1,
&imageCopy
);
vulkanCommandBuffer->transferBuffers[vulkanCommandBuffer->transferBufferCount - 1]->offset += yDataLength + uvDataLength;
transferBuffer->offset += yDataLength + uvDataLength;
if (tex->usageFlags & VK_IMAGE_USAGE_SAMPLED_BIT)
{
@ -6781,13 +6830,16 @@ static void VULKAN_SetBufferData(
return;
}
VULKAN_INTERNAL_MaybeExpandTransferBuffer(
transferBuffer = VULKAN_INTERNAL_AcquireTransferBuffer(
renderer,
vulkanCommandBuffer,
dataLength
);
transferBuffer = vulkanCommandBuffer->transferBuffers[vulkanCommandBuffer->transferBufferCount - 1];
if (transferBuffer == NULL)
{
return;
}
transferBufferPointer =
transferBuffer->buffer->allocation->mapPointer +
@ -8397,12 +8449,20 @@ static void VULKAN_INTERNAL_ResetCommandBuffer(
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)
{
VULKAN_INTERNAL_DestroyBuffer(
renderer,
commandBuffer->transferBuffers[i]->buffer
);
renderer->transferBufferPool.submittedBuffers[renderer->transferBufferPool.submittedBufferCount] = commandBuffer->transferBuffers[i];
renderer->transferBufferPool.submittedBufferCount += 1;
}
SDL_free(commandBuffer->transferBuffers);
@ -9779,6 +9839,16 @@ static Refresh_Device* VULKAN_INTERNAL_CreateDevice(
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 */
renderer->renderTargetsToDestroyCapacity = 16;