rework uniform buffer implementation as a ring buffer

pull/50/head
cosmonaut 2024-02-16 17:27:33 -08:00
parent 4ed50a96c9
commit a3d69ace21
1 changed files with 125 additions and 575 deletions

View File

@ -715,16 +715,6 @@ struct VulkanBuffer
VulkanBufferContainer *container; VulkanBufferContainer *container;
}; };
typedef struct VulkanUniformBufferPool VulkanUniformBufferPool;
typedef struct VulkanUniformBuffer
{
VulkanUniformBufferPool *pool;
VkDeviceSize poolOffset; /* memory offset relative to the pool buffer */
VkDeviceSize offset; /* based on uniform pushes */
VkDescriptorSet descriptorSet;
} VulkanUniformBuffer;
typedef enum VulkanUniformBufferType typedef enum VulkanUniformBufferType
{ {
UNIFORM_BUFFER_VERTEX, UNIFORM_BUFFER_VERTEX,
@ -747,20 +737,16 @@ typedef struct VulkanUniformDescriptorPool
uint32_t availableDescriptorSetCount; uint32_t availableDescriptorSetCount;
} VulkanUniformDescriptorPool; } VulkanUniformDescriptorPool;
/* This is actually just one buffer that we carve slices out of. */ /* Uniform buffers are just one buffer that we carve slices out of. */
struct VulkanUniformBufferPool typedef struct VulkanUniformBufferObject
{ {
VulkanUniformBufferType type; VulkanUniformBufferType type;
VulkanUniformDescriptorPool descriptorPool; VkDescriptorSet descriptorSet;
VulkanBuffer *buffer; VulkanBuffer *buffer;
VkDeviceSize nextAvailableOffset; uint32_t currentOffset;
SDL_mutex *lock;
uint8_t *mapPointer; /* uniform buffers are permanently mapped */ uint8_t *mapPointer; /* uniform buffers are permanently mapped */
SDL_mutex *lock;
VulkanUniformBuffer **availableBuffers; } VulkanUniformBufferObject;
uint32_t availableBufferCount;
uint32_t availableBufferCapacity;
};
/* Renderer Structure */ /* Renderer Structure */
@ -1557,19 +1543,11 @@ typedef struct VulkanCommandBuffer
uint32_t renderPassColorTargetCount; uint32_t renderPassColorTargetCount;
VulkanTexture *renderPassDepthTexture; /* can be NULL */ VulkanTexture *renderPassDepthTexture; /* can be NULL */
VulkanUniformBuffer *vertexUniformBuffer;
VulkanUniformBuffer *fragmentUniformBuffer;
VulkanUniformBuffer *computeUniformBuffer;
VkDescriptorSet vertexSamplerDescriptorSet; /* updated by BindVertexSamplers */ VkDescriptorSet vertexSamplerDescriptorSet; /* updated by BindVertexSamplers */
VkDescriptorSet fragmentSamplerDescriptorSet; /* updated by BindFragmentSamplers */ VkDescriptorSet fragmentSamplerDescriptorSet; /* updated by BindFragmentSamplers */
VkDescriptorSet bufferDescriptorSet; /* updated by BindComputeBuffers */ VkDescriptorSet bufferDescriptorSet; /* updated by BindComputeBuffers */
VkDescriptorSet imageDescriptorSet; /* updated by BindComputeTextures */ VkDescriptorSet imageDescriptorSet; /* updated by BindComputeTextures */
VulkanUniformBuffer **boundUniformBuffers;
uint32_t boundUniformBufferCount;
uint32_t boundUniformBufferCapacity;
DescriptorSetData *boundDescriptorSetDatas; DescriptorSetData *boundDescriptorSetDatas;
uint32_t boundDescriptorSetDataCount; uint32_t boundDescriptorSetDataCount;
uint32_t boundDescriptorSetDataCapacity; uint32_t boundDescriptorSetDataCapacity;
@ -1763,19 +1741,14 @@ typedef struct VulkanRenderer
VkDescriptorSet emptyComputeBufferDescriptorSet; VkDescriptorSet emptyComputeBufferDescriptorSet;
VkDescriptorSet emptyComputeImageDescriptorSet; VkDescriptorSet emptyComputeImageDescriptorSet;
VulkanUniformBufferPool *vertexUniformBufferPool; VulkanUniformBufferObject *vertexUniformBufferObject;
VulkanUniformBufferPool *fragmentUniformBufferPool; VulkanUniformBufferObject *fragmentUniformBufferObject;
VulkanUniformBufferPool *computeUniformBufferPool; VulkanUniformBufferObject *computeUniformBufferObject;
VkDescriptorSetLayout vertexUniformDescriptorSetLayout; VkDescriptorSetLayout vertexUniformDescriptorSetLayout;
VkDescriptorSetLayout fragmentUniformDescriptorSetLayout; VkDescriptorSetLayout fragmentUniformDescriptorSetLayout;
VkDescriptorSetLayout computeUniformDescriptorSetLayout; VkDescriptorSetLayout computeUniformDescriptorSetLayout;
VulkanBuffer *dummyBuffer;
VulkanUniformBuffer *dummyVertexUniformBuffer;
VulkanUniformBuffer *dummyFragmentUniformBuffer;
VulkanUniformBuffer *dummyComputeUniformBuffer;
VkDeviceSize minUBOAlignment; VkDeviceSize minUBOAlignment;
/* Some drivers don't support D16 for some reason. Fun! */ /* Some drivers don't support D16 for some reason. Fun! */
@ -3612,7 +3585,6 @@ static void VULKAN_INTERNAL_DestroyCommandPool(
SDL_free(commandBuffer->presentDatas); SDL_free(commandBuffer->presentDatas);
SDL_free(commandBuffer->waitSemaphores); SDL_free(commandBuffer->waitSemaphores);
SDL_free(commandBuffer->signalSemaphores); SDL_free(commandBuffer->signalSemaphores);
SDL_free(commandBuffer->boundUniformBuffers);
SDL_free(commandBuffer->boundDescriptorSetDatas); SDL_free(commandBuffer->boundDescriptorSetDatas);
SDL_free(commandBuffer->boundComputeBuffers); SDL_free(commandBuffer->boundComputeBuffers);
SDL_free(commandBuffer->boundComputeTextures); SDL_free(commandBuffer->boundComputeTextures);
@ -4213,24 +4185,30 @@ static uint8_t VULKAN_INTERNAL_AddUniformDescriptorPool(
return 1; return 1;
} }
static VulkanUniformBufferPool* VULKAN_INTERNAL_CreateUniformBufferPool( static VulkanUniformBufferObject* VULKAN_INTERNAL_CreateUniformBufferObject(
VulkanRenderer *renderer, VulkanRenderer *renderer,
VulkanUniformBufferType uniformBufferType VulkanUniformBufferType uniformBufferType
) { ) {
VulkanUniformBufferPool* uniformBufferPool = SDL_malloc(sizeof(VulkanUniformBufferPool)); VulkanUniformBufferObject* uniformBufferObject = SDL_malloc(sizeof(VulkanUniformBufferObject));
VulkanResourceAccessType resourceAccessType; VulkanResourceAccessType resourceAccessType;
VkDescriptorSetLayout descriptorSetLayout;
VkWriteDescriptorSet writeDescriptorSet;
VkDescriptorBufferInfo descriptorBufferInfo;
if (uniformBufferType == UNIFORM_BUFFER_VERTEX) if (uniformBufferType == UNIFORM_BUFFER_VERTEX)
{ {
resourceAccessType = RESOURCE_ACCESS_VERTEX_SHADER_READ_UNIFORM_BUFFER; resourceAccessType = RESOURCE_ACCESS_VERTEX_SHADER_READ_UNIFORM_BUFFER;
descriptorSetLayout = renderer->vertexUniformDescriptorSetLayout;
} }
else if (uniformBufferType == UNIFORM_BUFFER_FRAGMENT) else if (uniformBufferType == UNIFORM_BUFFER_FRAGMENT)
{ {
resourceAccessType = RESOURCE_ACCESS_FRAGMENT_SHADER_READ_UNIFORM_BUFFER; resourceAccessType = RESOURCE_ACCESS_FRAGMENT_SHADER_READ_UNIFORM_BUFFER;
descriptorSetLayout = renderer->fragmentUniformDescriptorSetLayout;
} }
else if (uniformBufferType == UNIFORM_BUFFER_COMPUTE) else if (uniformBufferType == UNIFORM_BUFFER_COMPUTE)
{ {
resourceAccessType = RESOURCE_ACCESS_COMPUTE_SHADER_READ_UNIFORM_BUFFER; resourceAccessType = RESOURCE_ACCESS_COMPUTE_SHADER_READ_UNIFORM_BUFFER;
descriptorSetLayout = renderer->computeUniformDescriptorSetLayout;
} }
else else
{ {
@ -4238,59 +4216,66 @@ static VulkanUniformBufferPool* VULKAN_INTERNAL_CreateUniformBufferPool(
return 0; return 0;
} }
uniformBufferPool->buffer = VULKAN_INTERNAL_CreateBuffer( /* Allocate backing buffer */
uniformBufferObject->buffer = VULKAN_INTERNAL_CreateBuffer(
renderer, renderer,
UBO_BUFFER_SIZE, UBO_BUFFER_SIZE,
resourceAccessType, resourceAccessType,
VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
1, 1,
0, 1,
1 1
); );
uniformBufferPool->nextAvailableOffset = 0; uniformBufferObject->lock = SDL_CreateMutex();
uniformBufferPool->type = uniformBufferType; uniformBufferObject->currentOffset = 0;
uniformBufferPool->lock = SDL_CreateMutex(); uniformBufferObject->type = uniformBufferType;
uniformBufferPool->availableBufferCapacity = 16; /* Allocate a descriptor set for the uniform buffer */
uniformBufferPool->availableBufferCount = 0; VULKAN_INTERNAL_AllocateDescriptorSets(
uniformBufferPool->availableBuffers = SDL_malloc(uniformBufferPool->availableBufferCapacity * sizeof(VulkanUniformBuffer*)); renderer,
renderer->defaultDescriptorPool,
descriptorSetLayout,
1,
&uniformBufferObject->descriptorSet
);
uniformBufferPool->descriptorPool.availableDescriptorSetCount = 0; /* Update the descriptor set for the first and last time! */
uniformBufferPool->descriptorPool.descriptorPoolCount = 0; descriptorBufferInfo.buffer = uniformBufferObject->buffer->buffer;
uniformBufferPool->descriptorPool.descriptorPools = NULL; descriptorBufferInfo.offset = 0;
descriptorBufferInfo.range = VK_WHOLE_SIZE;
writeDescriptorSet.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
writeDescriptorSet.pNext = NULL;
writeDescriptorSet.descriptorCount = 1;
writeDescriptorSet.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;
writeDescriptorSet.dstArrayElement = 0;
writeDescriptorSet.dstBinding = 0;
writeDescriptorSet.dstSet = uniformBufferObject->descriptorSet;
writeDescriptorSet.pBufferInfo = &descriptorBufferInfo;
writeDescriptorSet.pImageInfo = NULL;
writeDescriptorSet.pTexelBufferView = NULL;
renderer->vkUpdateDescriptorSets(
renderer->logicalDevice,
1,
&writeDescriptorSet,
0,
NULL
);
/* Permanently map the memory */
renderer->vkMapMemory( renderer->vkMapMemory(
renderer->logicalDevice, renderer->logicalDevice,
uniformBufferPool->buffer->usedRegion->allocation->memory, uniformBufferObject->buffer->usedRegion->allocation->memory,
0, 0,
VK_WHOLE_SIZE, VK_WHOLE_SIZE,
0, 0,
(void**) &uniformBufferPool->mapPointer (void**) &uniformBufferObject->mapPointer
); );
VULKAN_INTERNAL_AddUniformDescriptorPool(renderer, &uniformBufferPool->descriptorPool); return uniformBufferObject;
return uniformBufferPool;
}
static void VULKAN_INTERNAL_BindUniformBuffer(
VulkanRenderer *renderer,
VulkanCommandBuffer *commandBuffer,
VulkanUniformBuffer *uniformBuffer
) {
if (commandBuffer->boundUniformBufferCount >= commandBuffer->boundUniformBufferCapacity)
{
commandBuffer->boundUniformBufferCapacity *= 2;
commandBuffer->boundUniformBuffers = SDL_realloc(
commandBuffer->boundUniformBuffers,
sizeof(VulkanUniformBuffer*) * commandBuffer->boundUniformBufferCapacity
);
}
commandBuffer->boundUniformBuffers[commandBuffer->boundUniformBufferCount] = uniformBuffer;
commandBuffer->boundUniformBufferCount += 1;
} }
/* Buffer indirection so we can cleanly defrag */ /* Buffer indirection so we can cleanly defrag */
@ -4329,244 +4314,19 @@ static VulkanBufferContainer* VULKAN_INTERNAL_CreateBufferContainer(
return (VulkanBufferContainer*) bufferContainer; return (VulkanBufferContainer*) bufferContainer;
} }
static uint8_t VULKAN_INTERNAL_CreateUniformBuffer( static void VULKAN_INTERNAL_DestroyUniformBufferObject(
VulkanRenderer *renderer, VulkanRenderer *renderer,
VulkanUniformBufferPool *bufferPool VulkanUniformBufferObject *uniformBufferObject
) { ) {
VkDescriptorSetLayout descriptorSetLayout;
if (bufferPool->type == UNIFORM_BUFFER_VERTEX)
{
descriptorSetLayout = renderer->vertexUniformDescriptorSetLayout;
}
else if (bufferPool->type == UNIFORM_BUFFER_FRAGMENT)
{
descriptorSetLayout = renderer->fragmentUniformDescriptorSetLayout;
}
else if (bufferPool->type == UNIFORM_BUFFER_COMPUTE)
{
descriptorSetLayout = renderer->computeUniformDescriptorSetLayout;
}
else
{
Refresh_LogError("Unrecognized uniform buffer type!");
return 0;
}
VulkanUniformBuffer *uniformBuffer = SDL_malloc(sizeof(VulkanUniformBuffer));
uniformBuffer->pool = bufferPool;
uniformBuffer->poolOffset = bufferPool->nextAvailableOffset;
uniformBuffer->offset = 0;
bufferPool->nextAvailableOffset += VULKAN_INTERNAL_NextHighestAlignment(UBO_SECTION_SIZE, renderer->minUBOAlignment);
if (bufferPool->nextAvailableOffset >= UBO_BUFFER_SIZE)
{
Refresh_LogError("Uniform buffer overflow!");
SDL_free(uniformBuffer);
return 0;
}
/* Allocate a descriptor set for the uniform buffer */
if (bufferPool->descriptorPool.availableDescriptorSetCount == 0)
{
if (!VULKAN_INTERNAL_AddUniformDescriptorPool(
renderer,
&bufferPool->descriptorPool
)) {
Refresh_LogError("Failed to add uniform descriptor pool!");
SDL_free(uniformBuffer);
return 0;
}
}
if (!VULKAN_INTERNAL_AllocateDescriptorSets(
renderer,
bufferPool->descriptorPool.descriptorPools[bufferPool->descriptorPool.descriptorPoolCount - 1],
descriptorSetLayout,
1,
&uniformBuffer->descriptorSet
)) {
Refresh_LogError("Failed to allocate uniform descriptor set!");
return 0;
}
bufferPool->descriptorPool.availableDescriptorSetCount -= 1;
if (bufferPool->availableBufferCount >= bufferPool->availableBufferCapacity)
{
bufferPool->availableBufferCapacity *= 2;
bufferPool->availableBuffers = SDL_realloc(
bufferPool->availableBuffers,
sizeof(VulkanUniformBuffer*) * bufferPool->availableBufferCapacity
);
}
bufferPool->availableBuffers[bufferPool->availableBufferCount] = uniformBuffer;
bufferPool->availableBufferCount += 1;
return 1;
}
static VulkanUniformBuffer* VULKAN_INTERNAL_CreateDummyUniformBuffer(
VulkanRenderer *renderer,
VulkanUniformBufferType uniformBufferType
) {
VkDescriptorSetLayout descriptorSetLayout;
VkWriteDescriptorSet writeDescriptorSet;
VkDescriptorBufferInfo descriptorBufferInfo;
if (uniformBufferType == UNIFORM_BUFFER_VERTEX)
{
descriptorSetLayout = renderer->vertexUniformDescriptorSetLayout;
}
else if (uniformBufferType == UNIFORM_BUFFER_FRAGMENT)
{
descriptorSetLayout = renderer->fragmentUniformDescriptorSetLayout;
}
else if (uniformBufferType == UNIFORM_BUFFER_COMPUTE)
{
descriptorSetLayout = renderer->computeUniformDescriptorSetLayout;
}
else
{
Refresh_LogError("Unrecognized uniform buffer type!");
return NULL;
}
VulkanUniformBuffer *uniformBuffer = SDL_malloc(sizeof(VulkanUniformBuffer));
uniformBuffer->poolOffset = 0;
uniformBuffer->offset = 0;
/* Allocate a descriptor set for the uniform buffer */
VULKAN_INTERNAL_AllocateDescriptorSets(
renderer,
renderer->defaultDescriptorPool,
descriptorSetLayout,
1,
&uniformBuffer->descriptorSet
);
/* Update the descriptor set for the first and last time! */
descriptorBufferInfo.buffer = renderer->dummyBuffer->buffer;
descriptorBufferInfo.offset = 0;
descriptorBufferInfo.range = VK_WHOLE_SIZE;
writeDescriptorSet.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
writeDescriptorSet.pNext = NULL;
writeDescriptorSet.descriptorCount = 1;
writeDescriptorSet.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;
writeDescriptorSet.dstArrayElement = 0;
writeDescriptorSet.dstBinding = 0;
writeDescriptorSet.dstSet = uniformBuffer->descriptorSet;
writeDescriptorSet.pBufferInfo = &descriptorBufferInfo;
writeDescriptorSet.pImageInfo = NULL;
writeDescriptorSet.pTexelBufferView = NULL;
renderer->vkUpdateDescriptorSets(
renderer->logicalDevice,
1,
&writeDescriptorSet,
0,
NULL
);
uniformBuffer->pool = NULL; /* No pool because this is a dummy */
return uniformBuffer;
}
static void VULKAN_INTERNAL_DestroyUniformBufferPool(
VulkanRenderer *renderer,
VulkanUniformBufferPool *uniformBufferPool
) {
uint32_t i;
for (i = 0; i < uniformBufferPool->descriptorPool.descriptorPoolCount; i += 1)
{
renderer->vkDestroyDescriptorPool(
renderer->logicalDevice,
uniformBufferPool->descriptorPool.descriptorPools[i],
NULL
);
}
SDL_free(uniformBufferPool->descriptorPool.descriptorPools);
/* This is always destroyed after submissions, so all buffers are available */
for (i = 0; i < uniformBufferPool->availableBufferCount; i += 1)
{
SDL_free(uniformBufferPool->availableBuffers[i]);
}
renderer->vkUnmapMemory( renderer->vkUnmapMemory(
renderer->logicalDevice, renderer->logicalDevice,
uniformBufferPool->buffer->usedRegion->allocation->memory uniformBufferObject->buffer->usedRegion->allocation->memory
); );
VULKAN_INTERNAL_DestroyBuffer(renderer, uniformBufferPool->buffer); VULKAN_INTERNAL_DestroyBuffer(renderer, uniformBufferObject->buffer);
SDL_DestroyMutex(uniformBufferPool->lock); SDL_DestroyMutex(uniformBufferObject->lock);
SDL_free(uniformBufferPool->availableBuffers); SDL_free(uniformBufferObject);
SDL_free(uniformBufferPool);
}
static VulkanUniformBuffer* VULKAN_INTERNAL_AcquireUniformBufferFromPool(
VulkanRenderer *renderer,
VulkanUniformBufferPool *bufferPool,
VkDeviceSize blockSize
) {
VkWriteDescriptorSet writeDescriptorSet;
VkDescriptorBufferInfo descriptorBufferInfo;
SDL_LockMutex(bufferPool->lock);
if (bufferPool->availableBufferCount == 0)
{
if (!VULKAN_INTERNAL_CreateUniformBuffer(renderer, bufferPool))
{
SDL_UnlockMutex(bufferPool->lock);
Refresh_LogError("Failed to create uniform buffer!");
return NULL;
}
}
VulkanUniformBuffer *uniformBuffer = bufferPool->availableBuffers[bufferPool->availableBufferCount - 1];
bufferPool->availableBufferCount -= 1;
SDL_UnlockMutex(bufferPool->lock);
uniformBuffer->offset = 0;
/* Update the descriptor set with the correct range */
descriptorBufferInfo.buffer = uniformBuffer->pool->buffer->buffer;
descriptorBufferInfo.offset = uniformBuffer->poolOffset;
descriptorBufferInfo.range = blockSize;
writeDescriptorSet.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
writeDescriptorSet.pNext = NULL;
writeDescriptorSet.descriptorCount = 1;
writeDescriptorSet.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;
writeDescriptorSet.dstArrayElement = 0;
writeDescriptorSet.dstBinding = 0;
writeDescriptorSet.dstSet = uniformBuffer->descriptorSet;
writeDescriptorSet.pBufferInfo = &descriptorBufferInfo;
writeDescriptorSet.pImageInfo = NULL;
writeDescriptorSet.pTexelBufferView = NULL;
renderer->vkUpdateDescriptorSets(
renderer->logicalDevice,
1,
&writeDescriptorSet,
0,
NULL
);
return uniformBuffer;
} }
/* Swapchain */ /* Swapchain */
@ -5211,12 +4971,6 @@ static void VULKAN_DestroyDevice(
SDL_free(renderer->submittedCommandBuffers); SDL_free(renderer->submittedCommandBuffers);
VULKAN_INTERNAL_DestroyBuffer(renderer, renderer->dummyBuffer);
SDL_free(renderer->dummyVertexUniformBuffer);
SDL_free(renderer->dummyFragmentUniformBuffer);
SDL_free(renderer->dummyComputeUniformBuffer);
for (i = 0; i < renderer->fencePool.availableFenceCount; i += 1) for (i = 0; i < renderer->fencePool.availableFenceCount; i += 1)
{ {
renderer->vkDestroyFence(renderer->logicalDevice, renderer->fencePool.availableFences[i], NULL); renderer->vkDestroyFence(renderer->logicalDevice, renderer->fencePool.availableFences[i], NULL);
@ -5361,9 +5115,9 @@ static void VULKAN_DestroyDevice(
NULL NULL
); );
VULKAN_INTERNAL_DestroyUniformBufferPool(renderer, renderer->vertexUniformBufferPool); VULKAN_INTERNAL_DestroyUniformBufferObject(renderer, renderer->vertexUniformBufferObject);
VULKAN_INTERNAL_DestroyUniformBufferPool(renderer, renderer->fragmentUniformBufferPool); VULKAN_INTERNAL_DestroyUniformBufferObject(renderer, renderer->fragmentUniformBufferObject);
VULKAN_INTERNAL_DestroyUniformBufferPool(renderer, renderer->computeUniformBufferPool); VULKAN_INTERNAL_DestroyUniformBufferObject(renderer, renderer->computeUniformBufferObject);
for (i = 0; i < renderer->framebufferHashArray.count; i += 1) for (i = 0; i < renderer->framebufferHashArray.count; i += 1)
{ {
@ -5460,8 +5214,8 @@ static void VULKAN_DrawInstancedPrimitives(
descriptorSets[0] = vulkanCommandBuffer->vertexSamplerDescriptorSet; descriptorSets[0] = vulkanCommandBuffer->vertexSamplerDescriptorSet;
descriptorSets[1] = vulkanCommandBuffer->fragmentSamplerDescriptorSet; descriptorSets[1] = vulkanCommandBuffer->fragmentSamplerDescriptorSet;
descriptorSets[2] = vulkanCommandBuffer->vertexUniformBuffer->descriptorSet; descriptorSets[2] = renderer->vertexUniformBufferObject->descriptorSet;
descriptorSets[3] = vulkanCommandBuffer->fragmentUniformBuffer->descriptorSet; descriptorSets[3] = renderer->fragmentUniformBufferObject->descriptorSet;
dynamicOffsets[0] = vertexParamOffset; dynamicOffsets[0] = vertexParamOffset;
dynamicOffsets[1] = fragmentParamOffset; dynamicOffsets[1] = fragmentParamOffset;
@ -5527,8 +5281,8 @@ static void VULKAN_DrawPrimitives(
descriptorSets[0] = vulkanCommandBuffer->vertexSamplerDescriptorSet; descriptorSets[0] = vulkanCommandBuffer->vertexSamplerDescriptorSet;
descriptorSets[1] = vulkanCommandBuffer->fragmentSamplerDescriptorSet; descriptorSets[1] = vulkanCommandBuffer->fragmentSamplerDescriptorSet;
descriptorSets[2] = vulkanCommandBuffer->vertexUniformBuffer->descriptorSet; descriptorSets[2] = renderer->vertexUniformBufferObject->descriptorSet;
descriptorSets[3] = vulkanCommandBuffer->fragmentUniformBuffer->descriptorSet; descriptorSets[3] = renderer->fragmentUniformBufferObject->descriptorSet;
dynamicOffsets[0] = vertexParamOffset; dynamicOffsets[0] = vertexParamOffset;
dynamicOffsets[1] = fragmentParamOffset; dynamicOffsets[1] = fragmentParamOffset;
@ -5574,8 +5328,8 @@ static void VULKAN_DrawPrimitivesIndirect(
descriptorSets[0] = vulkanCommandBuffer->vertexSamplerDescriptorSet; descriptorSets[0] = vulkanCommandBuffer->vertexSamplerDescriptorSet;
descriptorSets[1] = vulkanCommandBuffer->fragmentSamplerDescriptorSet; descriptorSets[1] = vulkanCommandBuffer->fragmentSamplerDescriptorSet;
descriptorSets[2] = vulkanCommandBuffer->vertexUniformBuffer->descriptorSet; descriptorSets[2] = renderer->vertexUniformBufferObject->descriptorSet;
descriptorSets[3] = vulkanCommandBuffer->fragmentUniformBuffer->descriptorSet; descriptorSets[3] = renderer->fragmentUniformBufferObject->descriptorSet;
dynamicOffsets[0] = vertexParamOffset; dynamicOffsets[0] = vertexParamOffset;
dynamicOffsets[1] = fragmentParamOffset; dynamicOffsets[1] = fragmentParamOffset;
@ -7057,15 +6811,14 @@ static Refresh_CpuBuffer* VULKAN_CreateCpuBuffer(
/* Setters */ /* Setters */
static void VULKAN_INTERNAL_SetUniformBufferData( static void VULKAN_INTERNAL_SetUniformBufferData(
VulkanUniformBuffer *uniformBuffer, VulkanUniformBufferObject *uniformBufferObject,
void* data, void* data,
uint32_t dataLength uint32_t dataLength
) { ) {
uint8_t *dst = uint8_t *dst =
uniformBuffer->pool->mapPointer + uniformBufferObject->mapPointer +
uniformBuffer->pool->buffer->usedRegion->resourceOffset + uniformBufferObject->buffer->usedRegion->resourceOffset +
uniformBuffer->poolOffset + uniformBufferObject->currentOffset;
uniformBuffer->offset;
SDL_memcpy( SDL_memcpy(
dst, dst,
@ -7085,45 +6838,30 @@ static uint32_t VULKAN_PushVertexShaderUniforms(
VulkanGraphicsPipeline* graphicsPipeline = vulkanCommandBuffer->currentGraphicsPipeline; VulkanGraphicsPipeline* graphicsPipeline = vulkanCommandBuffer->currentGraphicsPipeline;
uint32_t offset; uint32_t offset;
if (graphicsPipeline == NULL)
{
Refresh_LogError("Cannot push uniforms if a pipeline is not bound!");
return 0;
}
if (graphicsPipeline->vertexUniformBlockSize == 0) if (graphicsPipeline->vertexUniformBlockSize == 0)
{ {
Refresh_LogError("Bound pipeline's vertex stage does not declare uniforms!"); Refresh_LogError("Bound pipeline's vertex stage does not declare uniforms!");
return 0; return 0;
} }
if ( SDL_LockMutex(renderer->vertexUniformBufferObject->lock);
vulkanCommandBuffer->vertexUniformBuffer->offset +
graphicsPipeline->vertexUniformBlockSize >= if (renderer->vertexUniformBufferObject->currentOffset + dataLengthInBytes >= UBO_BUFFER_SIZE)
UBO_SECTION_SIZE {
) { renderer->vertexUniformBufferObject->currentOffset = 0;
/* We're out of space in this buffer, bind the old one and acquire a new one */
VULKAN_INTERNAL_BindUniformBuffer(
renderer,
vulkanCommandBuffer,
vulkanCommandBuffer->vertexUniformBuffer
);
vulkanCommandBuffer->vertexUniformBuffer = VULKAN_INTERNAL_AcquireUniformBufferFromPool(
renderer,
renderer->vertexUniformBufferPool,
graphicsPipeline->vertexUniformBlockSize
);
} }
offset = vulkanCommandBuffer->vertexUniformBuffer->offset; offset = renderer->vertexUniformBufferObject->currentOffset;
VULKAN_INTERNAL_SetUniformBufferData( VULKAN_INTERNAL_SetUniformBufferData(
vulkanCommandBuffer->vertexUniformBuffer, renderer->vertexUniformBufferObject,
data, data,
dataLengthInBytes dataLengthInBytes
); );
vulkanCommandBuffer->vertexUniformBuffer->offset += graphicsPipeline->vertexUniformBlockSize; renderer->vertexUniformBufferObject->currentOffset += graphicsPipeline->vertexUniformBlockSize;
SDL_UnlockMutex(renderer->vertexUniformBufferObject->lock);
return offset; return offset;
} }
@ -7139,33 +6877,30 @@ static uint32_t VULKAN_PushFragmentShaderUniforms(
VulkanGraphicsPipeline* graphicsPipeline = vulkanCommandBuffer->currentGraphicsPipeline; VulkanGraphicsPipeline* graphicsPipeline = vulkanCommandBuffer->currentGraphicsPipeline;
uint32_t offset; uint32_t offset;
if ( if (graphicsPipeline->fragmentUniformBlockSize == 0)
vulkanCommandBuffer->fragmentUniformBuffer->offset + {
graphicsPipeline->fragmentUniformBlockSize >= Refresh_LogError("Bound pipeline's fragment stage does not declare uniforms!");
UBO_SECTION_SIZE return 0;
) {
/* We're out of space in this buffer, bind the old one and acquire a new one */
VULKAN_INTERNAL_BindUniformBuffer(
renderer,
vulkanCommandBuffer,
vulkanCommandBuffer->fragmentUniformBuffer
);
vulkanCommandBuffer->fragmentUniformBuffer = VULKAN_INTERNAL_AcquireUniformBufferFromPool(
renderer,
renderer->fragmentUniformBufferPool,
graphicsPipeline->fragmentUniformBlockSize
);
} }
offset = vulkanCommandBuffer->fragmentUniformBuffer->offset; SDL_LockMutex(renderer->fragmentUniformBufferObject->lock);
if (renderer->fragmentUniformBufferObject->currentOffset + dataLengthInBytes >= UBO_BUFFER_SIZE)
{
renderer->fragmentUniformBufferObject->currentOffset = 0;
}
offset = renderer->fragmentUniformBufferObject->currentOffset;
VULKAN_INTERNAL_SetUniformBufferData( VULKAN_INTERNAL_SetUniformBufferData(
vulkanCommandBuffer->fragmentUniformBuffer, renderer->fragmentUniformBufferObject,
data, data,
dataLengthInBytes dataLengthInBytes
); );
vulkanCommandBuffer->fragmentUniformBuffer->offset += graphicsPipeline->fragmentUniformBlockSize; renderer->fragmentUniformBufferObject->currentOffset += graphicsPipeline->fragmentUniformBlockSize;
SDL_UnlockMutex(renderer->fragmentUniformBufferObject->lock);
return offset; return offset;
} }
@ -7181,33 +6916,30 @@ static uint32_t VULKAN_PushComputeShaderUniforms(
VulkanComputePipeline* computePipeline = vulkanCommandBuffer->currentComputePipeline; VulkanComputePipeline* computePipeline = vulkanCommandBuffer->currentComputePipeline;
uint32_t offset; uint32_t offset;
if ( if (computePipeline->uniformBlockSize == 0)
vulkanCommandBuffer->computeUniformBuffer->offset + {
computePipeline->uniformBlockSize >= Refresh_LogError("Bound pipeline's compute stage does not declare uniforms!");
UBO_SECTION_SIZE return 0;
) {
/* We're out of space in this buffer, bind the old one and acquire a new one */
VULKAN_INTERNAL_BindUniformBuffer(
renderer,
vulkanCommandBuffer,
vulkanCommandBuffer->computeUniformBuffer
);
vulkanCommandBuffer->computeUniformBuffer = VULKAN_INTERNAL_AcquireUniformBufferFromPool(
renderer,
renderer->computeUniformBufferPool,
computePipeline->uniformBlockSize
);
} }
offset = vulkanCommandBuffer->computeUniformBuffer->offset; SDL_LockMutex(renderer->computeUniformBufferObject->lock);
if (renderer->computeUniformBufferObject->currentOffset + dataLengthInBytes >= UBO_BUFFER_SIZE)
{
renderer->computeUniformBufferObject->currentOffset = 0;
}
offset = renderer->computeUniformBufferObject->currentOffset;
VULKAN_INTERNAL_SetUniformBufferData( VULKAN_INTERNAL_SetUniformBufferData(
vulkanCommandBuffer->computeUniformBuffer, renderer->computeUniformBufferObject,
data, data,
dataLengthInBytes dataLengthInBytes
); );
vulkanCommandBuffer->computeUniformBuffer->offset += computePipeline->uniformBlockSize; renderer->computeUniformBufferObject->currentOffset += computePipeline->uniformBlockSize;
SDL_UnlockMutex(renderer->computeUniformBufferObject->lock);
return offset; return offset;
} }
@ -8195,28 +7927,6 @@ static void VULKAN_EndRenderPass(
vulkanCommandBuffer->commandBuffer vulkanCommandBuffer->commandBuffer
); );
if ( vulkanCommandBuffer->vertexUniformBuffer != renderer->dummyVertexUniformBuffer &&
vulkanCommandBuffer->vertexUniformBuffer != NULL
) {
VULKAN_INTERNAL_BindUniformBuffer(
renderer,
vulkanCommandBuffer,
vulkanCommandBuffer->vertexUniformBuffer
);
}
vulkanCommandBuffer->vertexUniformBuffer = NULL;
if ( vulkanCommandBuffer->fragmentUniformBuffer != renderer->dummyFragmentUniformBuffer &&
vulkanCommandBuffer->fragmentUniformBuffer != NULL
) {
VULKAN_INTERNAL_BindUniformBuffer(
renderer,
vulkanCommandBuffer,
vulkanCommandBuffer->fragmentUniformBuffer
);
}
vulkanCommandBuffer->fragmentUniformBuffer = NULL;
/* If the render targets can be sampled, transition them to sample layout */ /* If the render targets can be sampled, transition them to sample layout */
for (i = 0; i < vulkanCommandBuffer->renderPassColorTargetCount; i += 1) for (i = 0; i < vulkanCommandBuffer->renderPassColorTargetCount; i += 1)
{ {
@ -8292,52 +8002,6 @@ static void VULKAN_BindGraphicsPipeline(
VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer*) commandBuffer; VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer*) commandBuffer;
VulkanGraphicsPipeline* pipeline = (VulkanGraphicsPipeline*) graphicsPipeline; VulkanGraphicsPipeline* pipeline = (VulkanGraphicsPipeline*) graphicsPipeline;
if ( vulkanCommandBuffer->vertexUniformBuffer != renderer->dummyVertexUniformBuffer &&
vulkanCommandBuffer->vertexUniformBuffer != NULL
) {
VULKAN_INTERNAL_BindUniformBuffer(
renderer,
vulkanCommandBuffer,
vulkanCommandBuffer->vertexUniformBuffer
);
}
if (pipeline->vertexUniformBlockSize == 0)
{
vulkanCommandBuffer->vertexUniformBuffer = renderer->dummyVertexUniformBuffer;
}
else
{
vulkanCommandBuffer->vertexUniformBuffer = VULKAN_INTERNAL_AcquireUniformBufferFromPool(
renderer,
renderer->vertexUniformBufferPool,
pipeline->vertexUniformBlockSize
);
}
if ( vulkanCommandBuffer->fragmentUniformBuffer != renderer->dummyFragmentUniformBuffer &&
vulkanCommandBuffer->fragmentUniformBuffer != NULL
) {
VULKAN_INTERNAL_BindUniformBuffer(
renderer,
vulkanCommandBuffer,
vulkanCommandBuffer->fragmentUniformBuffer
);
}
if (pipeline->fragmentUniformBlockSize == 0)
{
vulkanCommandBuffer->fragmentUniformBuffer = renderer->dummyFragmentUniformBuffer;
}
else
{
vulkanCommandBuffer->fragmentUniformBuffer = VULKAN_INTERNAL_AcquireUniformBufferFromPool(
renderer,
renderer->fragmentUniformBufferPool,
pipeline->fragmentUniformBlockSize
);
}
/* bind dummy sets if necessary */ /* bind dummy sets if necessary */
if (pipeline->pipelineLayout->vertexSamplerDescriptorSetCache == NULL) if (pipeline->pipelineLayout->vertexSamplerDescriptorSetCache == NULL)
{ {
@ -8446,7 +8110,7 @@ static void VULKAN_BindComputePipeline(
VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer*) commandBuffer; VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer*) commandBuffer;
VulkanComputePipeline *vulkanComputePipeline = (VulkanComputePipeline*) computePipeline; VulkanComputePipeline *vulkanComputePipeline = (VulkanComputePipeline*) computePipeline;
/* bind dummy sets */ /* bind dummy sets if necessary */
if (vulkanComputePipeline->pipelineLayout->bufferDescriptorSetCache == NULL) if (vulkanComputePipeline->pipelineLayout->bufferDescriptorSetCache == NULL)
{ {
vulkanCommandBuffer->bufferDescriptorSet = renderer->emptyComputeBufferDescriptorSet; vulkanCommandBuffer->bufferDescriptorSet = renderer->emptyComputeBufferDescriptorSet;
@ -8457,15 +8121,6 @@ static void VULKAN_BindComputePipeline(
vulkanCommandBuffer->imageDescriptorSet = renderer->emptyComputeImageDescriptorSet; vulkanCommandBuffer->imageDescriptorSet = renderer->emptyComputeImageDescriptorSet;
} }
if ( vulkanCommandBuffer->computeUniformBuffer != renderer->dummyComputeUniformBuffer &&
vulkanCommandBuffer->computeUniformBuffer != NULL
) {
VULKAN_INTERNAL_BindUniformBuffer(
renderer,
vulkanCommandBuffer,
vulkanCommandBuffer->computeUniformBuffer
);
}
renderer->vkCmdBindPipeline( renderer->vkCmdBindPipeline(
vulkanCommandBuffer->commandBuffer, vulkanCommandBuffer->commandBuffer,
VK_PIPELINE_BIND_POINT_COMPUTE, VK_PIPELINE_BIND_POINT_COMPUTE,
@ -8474,19 +8129,6 @@ static void VULKAN_BindComputePipeline(
vulkanCommandBuffer->currentComputePipeline = vulkanComputePipeline; vulkanCommandBuffer->currentComputePipeline = vulkanComputePipeline;
if (vulkanComputePipeline->uniformBlockSize == 0)
{
vulkanCommandBuffer->computeUniformBuffer = renderer->dummyComputeUniformBuffer;
}
else
{
vulkanCommandBuffer->computeUniformBuffer = VULKAN_INTERNAL_AcquireUniformBufferFromPool(
renderer,
renderer->computeUniformBufferPool,
vulkanComputePipeline->uniformBlockSize
);
}
VULKAN_INTERNAL_TrackComputePipeline(renderer, vulkanCommandBuffer, vulkanComputePipeline); VULKAN_INTERNAL_TrackComputePipeline(renderer, vulkanCommandBuffer, vulkanComputePipeline);
} }
@ -8606,7 +8248,7 @@ static void VULKAN_DispatchCompute(
descriptorSets[0] = vulkanCommandBuffer->bufferDescriptorSet; descriptorSets[0] = vulkanCommandBuffer->bufferDescriptorSet;
descriptorSets[1] = vulkanCommandBuffer->imageDescriptorSet; descriptorSets[1] = vulkanCommandBuffer->imageDescriptorSet;
descriptorSets[2] = vulkanCommandBuffer->computeUniformBuffer->descriptorSet; descriptorSets[2] = renderer->computeUniformBufferObject->descriptorSet;
renderer->vkCmdBindDescriptorSets( renderer->vkCmdBindDescriptorSets(
vulkanCommandBuffer->commandBuffer, vulkanCommandBuffer->commandBuffer,
@ -8692,17 +8334,6 @@ static void VULKAN_EndComputePass(
} }
} }
if ( vulkanCommandBuffer->computeUniformBuffer != renderer->dummyComputeUniformBuffer &&
vulkanCommandBuffer->computeUniformBuffer != NULL)
{
VULKAN_INTERNAL_BindUniformBuffer(
renderer,
vulkanCommandBuffer,
vulkanCommandBuffer->computeUniformBuffer
);
}
vulkanCommandBuffer->computeUniformBuffer = NULL;
vulkanCommandBuffer->currentComputePipeline = NULL; vulkanCommandBuffer->currentComputePipeline = NULL;
} }
@ -9459,14 +9090,6 @@ static void VULKAN_INTERNAL_AllocateCommandBuffers(
commandBuffer->signalSemaphoreCapacity * sizeof(VkSemaphore) commandBuffer->signalSemaphoreCapacity * sizeof(VkSemaphore)
); );
/* Bound buffer tracking */
commandBuffer->boundUniformBufferCapacity = 16;
commandBuffer->boundUniformBufferCount = 0;
commandBuffer->boundUniformBuffers = SDL_malloc(
commandBuffer->boundUniformBufferCapacity * sizeof(VulkanUniformBuffer*)
);
/* Descriptor set tracking */ /* Descriptor set tracking */
commandBuffer->boundDescriptorSetDataCapacity = 16; commandBuffer->boundDescriptorSetDataCapacity = 16;
@ -9656,10 +9279,6 @@ static Refresh_CommandBuffer* VULKAN_AcquireCommandBuffer(
commandBuffer->currentComputePipeline = NULL; commandBuffer->currentComputePipeline = NULL;
commandBuffer->currentGraphicsPipeline = NULL; commandBuffer->currentGraphicsPipeline = NULL;
commandBuffer->vertexUniformBuffer = NULL;
commandBuffer->fragmentUniformBuffer = NULL;
commandBuffer->computeUniformBuffer = NULL;
commandBuffer->renderPassColorTargetCount = 0; commandBuffer->renderPassColorTargetCount = 0;
commandBuffer->autoReleaseFence = 1; commandBuffer->autoReleaseFence = 1;
@ -10152,7 +9771,6 @@ static void VULKAN_INTERNAL_CleanCommandBuffer(
VulkanCommandBuffer *commandBuffer VulkanCommandBuffer *commandBuffer
) { ) {
uint32_t i; uint32_t i;
VulkanUniformBuffer *uniformBuffer;
DescriptorSetData *descriptorSetData; DescriptorSetData *descriptorSetData;
if (commandBuffer->autoReleaseFence) if (commandBuffer->autoReleaseFence)
@ -10165,29 +9783,6 @@ static void VULKAN_INTERNAL_CleanCommandBuffer(
commandBuffer->inFlightFence = VK_NULL_HANDLE; commandBuffer->inFlightFence = VK_NULL_HANDLE;
} }
/* Bound uniform buffers are now available */
for (i = 0; i < commandBuffer->boundUniformBufferCount; i += 1)
{
uniformBuffer = commandBuffer->boundUniformBuffers[i];
SDL_LockMutex(uniformBuffer->pool->lock);
if (uniformBuffer->pool->availableBufferCount == uniformBuffer->pool->availableBufferCapacity)
{
uniformBuffer->pool->availableBufferCapacity *= 2;
uniformBuffer->pool->availableBuffers = SDL_realloc(
uniformBuffer->pool->availableBuffers,
uniformBuffer->pool->availableBufferCapacity * sizeof(VulkanUniformBuffer*)
);
}
uniformBuffer->pool->availableBuffers[uniformBuffer->pool->availableBufferCount] = uniformBuffer;
uniformBuffer->pool->availableBufferCount += 1;
SDL_UnlockMutex(uniformBuffer->pool->lock);
}
commandBuffer->boundUniformBufferCount = 0;
/* Bound descriptor sets are now available */ /* Bound descriptor sets are now available */
for (i = 0; i < commandBuffer->boundDescriptorSetDataCount; i += 1) for (i = 0; i < commandBuffer->boundDescriptorSetDataCount; i += 1)
@ -11958,64 +11553,19 @@ static Refresh_Device* VULKAN_CreateDevice(
&renderer->emptyComputeImageDescriptorSet &renderer->emptyComputeImageDescriptorSet
); );
/* Dummy Uniform Buffers */ /* Initialize uniform buffer objects */
renderer->dummyBuffer = VULKAN_INTERNAL_CreateBuffer( renderer->vertexUniformBufferObject = VULKAN_INTERNAL_CreateUniformBufferObject(
renderer,
16,
RESOURCE_ACCESS_GENERAL,
VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
0,
0,
1
);
renderer->dummyVertexUniformBuffer = VULKAN_INTERNAL_CreateDummyUniformBuffer(
renderer, renderer,
UNIFORM_BUFFER_VERTEX UNIFORM_BUFFER_VERTEX
); );
if (renderer->dummyVertexUniformBuffer == NULL) renderer->fragmentUniformBufferObject = VULKAN_INTERNAL_CreateUniformBufferObject(
{
Refresh_LogError("Failed to create dummy vertex uniform buffer!");
return NULL;
}
renderer->dummyFragmentUniformBuffer = VULKAN_INTERNAL_CreateDummyUniformBuffer(
renderer, renderer,
UNIFORM_BUFFER_FRAGMENT UNIFORM_BUFFER_FRAGMENT
); );
if (renderer->dummyFragmentUniformBuffer == NULL) renderer->computeUniformBufferObject = VULKAN_INTERNAL_CreateUniformBufferObject(
{
Refresh_LogError("Failed to create dummy fragment uniform buffer!");
return NULL;
}
renderer->dummyComputeUniformBuffer = VULKAN_INTERNAL_CreateDummyUniformBuffer(
renderer,
UNIFORM_BUFFER_COMPUTE
);
if (renderer->dummyComputeUniformBuffer == NULL)
{
Refresh_LogError("Failed to create dummy compute uniform buffer!");
return NULL;
}
/* Initialize uniform buffer pools */
renderer->vertexUniformBufferPool = VULKAN_INTERNAL_CreateUniformBufferPool(
renderer,
UNIFORM_BUFFER_VERTEX
);
renderer->fragmentUniformBufferPool = VULKAN_INTERNAL_CreateUniformBufferPool(
renderer,
UNIFORM_BUFFER_FRAGMENT
);
renderer->computeUniformBufferPool = VULKAN_INTERNAL_CreateUniformBufferPool(
renderer, renderer,
UNIFORM_BUFFER_COMPUTE UNIFORM_BUFFER_COMPUTE
); );