Uniform buffers are now slices of dedicated allocs (#48)
continuous-integration/drone/push Build is passing Details

This should fix an issue where draw calls could flicker if a defrag was in progress and a uniform buffer was being used.

Uniform buffer "pools" are now just a single dedicated VulkanBuffer, and the uniform buffer objects are offsets into that buffer.

Reviewed-on: #48
pull/49/head
cosmonaut 2024-01-13 01:41:12 +00:00
parent b72b0b5fde
commit 7297eba889
1 changed files with 72 additions and 50 deletions

View File

@ -79,7 +79,8 @@ typedef struct VulkanExtensions
#define ALLOCATION_INCREMENT 16000000 /* 16MB */ #define ALLOCATION_INCREMENT 16000000 /* 16MB */
#define TRANSFER_BUFFER_STARTING_SIZE 8000000 /* 8MB */ #define TRANSFER_BUFFER_STARTING_SIZE 8000000 /* 8MB */
#define POOLED_TRANSFER_BUFFER_SIZE 16000000 /* 16MB */ #define POOLED_TRANSFER_BUFFER_SIZE 16000000 /* 16MB */
#define UBO_BUFFER_SIZE 16000 /* 16KB */ #define UBO_BUFFER_SIZE 16000000 /* 16MB */
#define UBO_SECTION_SIZE 4000 /* 4KB */
#define DESCRIPTOR_POOL_STARTING_SIZE 128 #define DESCRIPTOR_POOL_STARTING_SIZE 128
#define DEFRAG_TIME 200 #define DEFRAG_TIME 200
#define WINDOW_DATA "Refresh_VulkanWindowData" #define WINDOW_DATA "Refresh_VulkanWindowData"
@ -719,8 +720,8 @@ typedef struct VulkanUniformBufferPool VulkanUniformBufferPool;
typedef struct VulkanUniformBuffer typedef struct VulkanUniformBuffer
{ {
VulkanUniformBufferPool *pool; VulkanUniformBufferPool *pool;
VulkanBufferContainer *vulkanBufferContainer; /* use container to avoid defrag issues */ VkDeviceSize poolOffset; /* memory offset relative to the pool buffer */
VkDeviceSize offset; VkDeviceSize offset; /* based on uniform pushes */
VkDescriptorSet descriptorSet; VkDescriptorSet descriptorSet;
} VulkanUniformBuffer; } VulkanUniformBuffer;
@ -746,10 +747,13 @@ typedef struct VulkanUniformDescriptorPool
uint32_t availableDescriptorSetCount; uint32_t availableDescriptorSetCount;
} VulkanUniformDescriptorPool; } VulkanUniformDescriptorPool;
/* This is actually just one buffer that we carve slices out of. */
struct VulkanUniformBufferPool struct VulkanUniformBufferPool
{ {
VulkanUniformBufferType type; VulkanUniformBufferType type;
VulkanUniformDescriptorPool descriptorPool; VulkanUniformDescriptorPool descriptorPool;
VulkanBuffer *buffer;
VkDeviceSize nextAvailableOffset;
SDL_mutex *lock; SDL_mutex *lock;
VulkanUniformBuffer **availableBuffers; VulkanUniformBuffer **availableBuffers;
@ -1776,6 +1780,8 @@ typedef struct VulkanRenderer
VkDescriptorSetLayout vertexUniformDescriptorSetLayout; VkDescriptorSetLayout vertexUniformDescriptorSetLayout;
VkDescriptorSetLayout fragmentUniformDescriptorSetLayout; VkDescriptorSetLayout fragmentUniformDescriptorSetLayout;
VkDescriptorSetLayout computeUniformDescriptorSetLayout; VkDescriptorSetLayout computeUniformDescriptorSetLayout;
VulkanBuffer *dummyBuffer;
VulkanUniformBuffer *dummyVertexUniformBuffer; VulkanUniformBuffer *dummyVertexUniformBuffer;
VulkanUniformBuffer *dummyFragmentUniformBuffer; VulkanUniformBuffer *dummyFragmentUniformBuffer;
VulkanUniformBuffer *dummyComputeUniformBuffer; VulkanUniformBuffer *dummyComputeUniformBuffer;
@ -4197,6 +4203,36 @@ static VulkanUniformBufferPool* VULKAN_INTERNAL_CreateUniformBufferPool(
VulkanUniformBufferType uniformBufferType VulkanUniformBufferType uniformBufferType
) { ) {
VulkanUniformBufferPool* uniformBufferPool = SDL_malloc(sizeof(VulkanUniformBufferPool)); VulkanUniformBufferPool* uniformBufferPool = SDL_malloc(sizeof(VulkanUniformBufferPool));
VulkanResourceAccessType resourceAccessType;
if (uniformBufferType == UNIFORM_BUFFER_VERTEX)
{
resourceAccessType = RESOURCE_ACCESS_VERTEX_SHADER_READ_UNIFORM_BUFFER;
}
else if (uniformBufferType == UNIFORM_BUFFER_FRAGMENT)
{
resourceAccessType = RESOURCE_ACCESS_FRAGMENT_SHADER_READ_UNIFORM_BUFFER;
}
else if (uniformBufferType == UNIFORM_BUFFER_COMPUTE)
{
resourceAccessType = RESOURCE_ACCESS_COMPUTE_SHADER_READ_UNIFORM_BUFFER;
}
else
{
Refresh_LogError("Unrecognized uniform buffer type!");
return 0;
}
uniformBufferPool->buffer = VULKAN_INTERNAL_CreateBuffer(
renderer,
UBO_BUFFER_SIZE,
resourceAccessType,
VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
0,
1
);
uniformBufferPool->nextAvailableOffset = 0;
uniformBufferPool->type = uniformBufferType; uniformBufferPool->type = uniformBufferType;
uniformBufferPool->lock = SDL_CreateMutex(); uniformBufferPool->lock = SDL_CreateMutex();
@ -4230,12 +4266,6 @@ static void VULKAN_INTERNAL_BindUniformBuffer(
commandBuffer->boundUniformBuffers[commandBuffer->boundUniformBufferCount] = uniformBuffer; commandBuffer->boundUniformBuffers[commandBuffer->boundUniformBufferCount] = uniformBuffer;
commandBuffer->boundUniformBufferCount += 1; commandBuffer->boundUniformBufferCount += 1;
VULKAN_INTERNAL_TrackBuffer(
renderer,
commandBuffer,
uniformBuffer->vulkanBufferContainer->vulkanBuffer
);
} }
/* Buffer indirection so we can cleanly defrag */ /* Buffer indirection so we can cleanly defrag */
@ -4304,22 +4334,18 @@ static uint8_t VULKAN_INTERNAL_CreateUniformBuffer(
VulkanUniformBuffer *uniformBuffer = SDL_malloc(sizeof(VulkanUniformBuffer)); VulkanUniformBuffer *uniformBuffer = SDL_malloc(sizeof(VulkanUniformBuffer));
uniformBuffer->pool = bufferPool; uniformBuffer->pool = bufferPool;
uniformBuffer->vulkanBufferContainer = VULKAN_INTERNAL_CreateBufferContainer( uniformBuffer->poolOffset = bufferPool->nextAvailableOffset;
renderer, uniformBuffer->offset = 0;
UBO_BUFFER_SIZE,
resourceAccessType,
VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
0
);
if (uniformBuffer->vulkanBufferContainer == NULL) bufferPool->nextAvailableOffset += UBO_SECTION_SIZE;
if (bufferPool->nextAvailableOffset >= UBO_BUFFER_SIZE)
{ {
Refresh_LogError("Failed to create buffer for uniform buffer!"); Refresh_LogError("Uniform buffer overflow!");
SDL_free(uniformBuffer);
return 0; return 0;
} }
uniformBuffer->offset = 0;
/* Allocate a descriptor set for the uniform buffer */ /* Allocate a descriptor set for the uniform buffer */
if (bufferPool->descriptorPool.availableDescriptorSetCount == 0) if (bufferPool->descriptorPool.availableDescriptorSetCount == 0)
@ -4329,6 +4355,7 @@ static uint8_t VULKAN_INTERNAL_CreateUniformBuffer(
&bufferPool->descriptorPool &bufferPool->descriptorPool
)) { )) {
Refresh_LogError("Failed to add uniform descriptor pool!"); Refresh_LogError("Failed to add uniform descriptor pool!");
SDL_free(uniformBuffer);
return 0; return 0;
} }
} }
@ -4393,15 +4420,7 @@ static VulkanUniformBuffer* VULKAN_INTERNAL_CreateDummyUniformBuffer(
} }
VulkanUniformBuffer *uniformBuffer = SDL_malloc(sizeof(VulkanUniformBuffer)); VulkanUniformBuffer *uniformBuffer = SDL_malloc(sizeof(VulkanUniformBuffer));
uniformBuffer->pool = NULL; uniformBuffer->poolOffset = 0;
uniformBuffer->vulkanBufferContainer = VULKAN_INTERNAL_CreateBufferContainer(
renderer,
1,
resourceAccessType,
VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
1
);
uniformBuffer->offset = 0; uniformBuffer->offset = 0;
/* Allocate a descriptor set for the uniform buffer */ /* Allocate a descriptor set for the uniform buffer */
@ -4416,7 +4435,7 @@ static VulkanUniformBuffer* VULKAN_INTERNAL_CreateDummyUniformBuffer(
/* Update the descriptor set for the first and last time! */ /* Update the descriptor set for the first and last time! */
descriptorBufferInfo.buffer = uniformBuffer->vulkanBufferContainer->vulkanBuffer->buffer; descriptorBufferInfo.buffer = renderer->dummyBuffer->buffer;
descriptorBufferInfo.offset = 0; descriptorBufferInfo.offset = 0;
descriptorBufferInfo.range = VK_WHOLE_SIZE; descriptorBufferInfo.range = VK_WHOLE_SIZE;
@ -4463,11 +4482,11 @@ static void VULKAN_INTERNAL_DestroyUniformBufferPool(
/* This is always destroyed after submissions, so all buffers are available */ /* This is always destroyed after submissions, so all buffers are available */
for (i = 0; i < uniformBufferPool->availableBufferCount; i += 1) for (i = 0; i < uniformBufferPool->availableBufferCount; i += 1)
{ {
VULKAN_INTERNAL_DestroyBuffer(renderer, uniformBufferPool->availableBuffers[i]->vulkanBufferContainer->vulkanBuffer);
SDL_free(uniformBufferPool->availableBuffers[i]->vulkanBufferContainer);
SDL_free(uniformBufferPool->availableBuffers[i]); SDL_free(uniformBufferPool->availableBuffers[i]);
} }
VULKAN_INTERNAL_DestroyBuffer(renderer, uniformBufferPool->buffer);
SDL_DestroyMutex(uniformBufferPool->lock); SDL_DestroyMutex(uniformBufferPool->lock);
SDL_free(uniformBufferPool->availableBuffers); SDL_free(uniformBufferPool->availableBuffers);
SDL_free(uniformBufferPool); SDL_free(uniformBufferPool);
@ -4502,8 +4521,8 @@ static VulkanUniformBuffer* VULKAN_INTERNAL_AcquireUniformBufferFromPool(
/* Update the descriptor set with the correct range */ /* Update the descriptor set with the correct range */
descriptorBufferInfo.buffer = uniformBuffer->vulkanBufferContainer->vulkanBuffer->buffer; descriptorBufferInfo.buffer = uniformBuffer->pool->buffer->buffer;
descriptorBufferInfo.offset = 0; descriptorBufferInfo.offset = uniformBuffer->poolOffset;
descriptorBufferInfo.range = blockSize; descriptorBufferInfo.range = blockSize;
writeDescriptorSet.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; writeDescriptorSet.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
@ -5183,13 +5202,7 @@ static void VULKAN_DestroyDevice(
SDL_free(renderer->submittedCommandBuffers); SDL_free(renderer->submittedCommandBuffers);
VULKAN_INTERNAL_DestroyBuffer(renderer, renderer->dummyVertexUniformBuffer->vulkanBufferContainer->vulkanBuffer); VULKAN_INTERNAL_DestroyBuffer(renderer, renderer->dummyBuffer);
VULKAN_INTERNAL_DestroyBuffer(renderer, renderer->dummyFragmentUniformBuffer->vulkanBufferContainer->vulkanBuffer);
VULKAN_INTERNAL_DestroyBuffer(renderer, renderer->dummyComputeUniformBuffer->vulkanBufferContainer->vulkanBuffer);
SDL_free(renderer->dummyVertexUniformBuffer->vulkanBufferContainer);
SDL_free(renderer->dummyFragmentUniformBuffer->vulkanBufferContainer);
SDL_free(renderer->dummyComputeUniformBuffer->vulkanBufferContainer);
SDL_free(renderer->dummyVertexUniformBuffer); SDL_free(renderer->dummyVertexUniformBuffer);
SDL_free(renderer->dummyFragmentUniformBuffer); SDL_free(renderer->dummyFragmentUniformBuffer);
@ -7815,7 +7828,7 @@ static uint32_t VULKAN_PushVertexShaderUniforms(
if ( if (
vulkanCommandBuffer->vertexUniformBuffer->offset + vulkanCommandBuffer->vertexUniformBuffer->offset +
graphicsPipeline->vertexUniformBlockSize >= graphicsPipeline->vertexUniformBlockSize >=
UBO_BUFFER_SIZE UBO_SECTION_SIZE
) { ) {
/* We're out of space in this buffer, bind the old one and acquire a new one */ /* We're out of space in this buffer, bind the old one and acquire a new one */
VULKAN_INTERNAL_BindUniformBuffer( VULKAN_INTERNAL_BindUniformBuffer(
@ -7833,8 +7846,8 @@ static uint32_t VULKAN_PushVertexShaderUniforms(
offset = vulkanCommandBuffer->vertexUniformBuffer->offset; offset = vulkanCommandBuffer->vertexUniformBuffer->offset;
VULKAN_INTERNAL_SetBufferData( VULKAN_INTERNAL_SetBufferData(
vulkanCommandBuffer->vertexUniformBuffer->vulkanBufferContainer->vulkanBuffer, vulkanCommandBuffer->vertexUniformBuffer->pool->buffer,
vulkanCommandBuffer->vertexUniformBuffer->offset, vulkanCommandBuffer->vertexUniformBuffer->poolOffset + vulkanCommandBuffer->vertexUniformBuffer->offset,
data, data,
dataLengthInBytes dataLengthInBytes
); );
@ -7859,7 +7872,7 @@ static uint32_t VULKAN_PushFragmentShaderUniforms(
if ( if (
vulkanCommandBuffer->fragmentUniformBuffer->offset + vulkanCommandBuffer->fragmentUniformBuffer->offset +
graphicsPipeline->fragmentUniformBlockSize >= graphicsPipeline->fragmentUniformBlockSize >=
UBO_BUFFER_SIZE UBO_SECTION_SIZE
) { ) {
/* We're out of space in this buffer, bind the old one and acquire a new one */ /* We're out of space in this buffer, bind the old one and acquire a new one */
VULKAN_INTERNAL_BindUniformBuffer( VULKAN_INTERNAL_BindUniformBuffer(
@ -7877,8 +7890,8 @@ static uint32_t VULKAN_PushFragmentShaderUniforms(
offset = vulkanCommandBuffer->fragmentUniformBuffer->offset; offset = vulkanCommandBuffer->fragmentUniformBuffer->offset;
VULKAN_INTERNAL_SetBufferData( VULKAN_INTERNAL_SetBufferData(
vulkanCommandBuffer->fragmentUniformBuffer->vulkanBufferContainer->vulkanBuffer, vulkanCommandBuffer->fragmentUniformBuffer->pool->buffer,
vulkanCommandBuffer->fragmentUniformBuffer->offset, vulkanCommandBuffer->fragmentUniformBuffer->poolOffset + vulkanCommandBuffer->fragmentUniformBuffer->offset,
data, data,
dataLengthInBytes dataLengthInBytes
); );
@ -7902,7 +7915,7 @@ static uint32_t VULKAN_PushComputeShaderUniforms(
if ( if (
vulkanCommandBuffer->computeUniformBuffer->offset + vulkanCommandBuffer->computeUniformBuffer->offset +
computePipeline->uniformBlockSize >= computePipeline->uniformBlockSize >=
UBO_BUFFER_SIZE UBO_SECTION_SIZE
) { ) {
/* We're out of space in this buffer, bind the old one and acquire a new one */ /* We're out of space in this buffer, bind the old one and acquire a new one */
VULKAN_INTERNAL_BindUniformBuffer( VULKAN_INTERNAL_BindUniformBuffer(
@ -7920,8 +7933,8 @@ static uint32_t VULKAN_PushComputeShaderUniforms(
offset = vulkanCommandBuffer->computeUniformBuffer->offset; offset = vulkanCommandBuffer->computeUniformBuffer->offset;
VULKAN_INTERNAL_SetBufferData( VULKAN_INTERNAL_SetBufferData(
vulkanCommandBuffer->computeUniformBuffer->vulkanBufferContainer->vulkanBuffer, vulkanCommandBuffer->computeUniformBuffer->pool->buffer,
vulkanCommandBuffer->computeUniformBuffer->offset, vulkanCommandBuffer->computeUniformBuffer->poolOffset + vulkanCommandBuffer->computeUniformBuffer->offset,
data, data,
dataLengthInBytes dataLengthInBytes
); );
@ -11992,6 +12005,15 @@ static Refresh_Device* VULKAN_CreateDevice(
/* Dummy Uniform Buffers */ /* Dummy Uniform Buffers */
renderer->dummyBuffer = VULKAN_INTERNAL_CreateBuffer(
renderer,
1,
RESOURCE_ACCESS_GENERAL,
VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
0,
1
);
renderer->dummyVertexUniformBuffer = VULKAN_INTERNAL_CreateDummyUniformBuffer( renderer->dummyVertexUniformBuffer = VULKAN_INTERNAL_CreateDummyUniformBuffer(
renderer, renderer,
UNIFORM_BUFFER_VERTEX UNIFORM_BUFFER_VERTEX