diff --git a/src/gpu/vulkan/SDL_gpu_vulkan.c b/src/gpu/vulkan/SDL_gpu_vulkan.c index 6e215b908e..38f94eaf99 100644 --- a/src/gpu/vulkan/SDL_gpu_vulkan.c +++ b/src/gpu/vulkan/SDL_gpu_vulkan.c @@ -69,7 +69,7 @@ typedef struct VulkanExtensions #define SMALL_ALLOCATION_SIZE 16777216 // 16 MiB #define LARGE_ALLOCATION_INCREMENT 67108864 // 64 MiB #define MAX_UBO_SECTION_SIZE 4096 // 4 KiB -#define DESCRIPTOR_POOL_STARTING_SIZE 128 +#define DESCRIPTOR_POOL_SIZE 128 #define WINDOW_PROPERTY_DATA "SDL_GPUVulkanWindowPropertyData" #define IDENTITY_SWIZZLE \ @@ -723,23 +723,69 @@ typedef struct VulkanDescriptorInfo typedef struct DescriptorSetPool { - SDL_SpinLock lock; + // It's a pool... of pools!!! + Uint32 poolCount; + VkDescriptorPool *descriptorPools; + // We'll just manage the descriptor sets ourselves instead of freeing the sets + VkDescriptorSet *descriptorSets; + Uint32 descriptorSetCount; + Uint32 descriptorSetIndex; +} DescriptorSetPool; + +// A command buffer acquires a cache at command buffer acquisition time +typedef struct DescriptorSetCache +{ + // Pools are indexed by DescriptorSetLayoutID which increases monotonically + // There's only a certain number of maximum layouts possible since we de-duplicate them. + DescriptorSetPool *pools; + Uint32 poolCount; +} DescriptorSetCache; + +typedef struct DescriptorSetLayoutHashTableKey +{ + VkShaderStageFlagBits shaderStage; + // Category 1: read resources + Uint32 samplerCount; + Uint32 storageBufferCount; + Uint32 storageTextureCount; + // Category 2: write resources + Uint32 writeStorageBufferCount; + Uint32 writeStorageTextureCount; + // Category 3: uniform buffers + Uint32 uniformBufferCount; +} DescriptorSetLayoutHashTableKey; + +typedef uint32_t DescriptorSetLayoutID; + +typedef struct DescriptorSetLayout +{ + DescriptorSetLayoutID ID; VkDescriptorSetLayout descriptorSetLayout; - VulkanDescriptorInfo *descriptorInfos; - Uint32 descriptorInfoCount; + // Category 1: read resources + Uint32 samplerCount; + Uint32 storageBufferCount; + Uint32 storageTextureCount; + // Category 2: write resources + Uint32 writeStorageBufferCount; + Uint32 writeStorageTextureCount; + // Category 3: uniform buffers + Uint32 uniformBufferCount; +} DescriptorSetLayout; - // This is actually a descriptor set and descriptor pool simultaneously - VkDescriptorPool *descriptorPools; - Uint32 descriptorPoolCount; - Uint32 nextPoolSize; +typedef struct GraphicsPipelineResourceLayoutHashTableKey +{ + Uint32 vertexSamplerCount; + Uint32 vertexStorageBufferCount; + Uint32 vertexStorageTextureCount; + Uint32 vertexUniformBufferCount; - // We just manage a pool ourselves instead of freeing the sets - VkDescriptorSet *inactiveDescriptorSets; - Uint32 inactiveDescriptorSetCount; - Uint32 inactiveDescriptorSetCapacity; -} DescriptorSetPool; + Uint32 fragmentSamplerCount; + Uint32 fragmentStorageBufferCount; + Uint32 fragmentStorageTextureCount; + Uint32 fragmentUniformBufferCount; +} GraphicsPipelineResourceLayoutHashTableKey; typedef struct VulkanGraphicsPipelineResourceLayout { @@ -752,7 +798,7 @@ typedef struct VulkanGraphicsPipelineResourceLayout * 2: fragment resources * 3: fragment uniform buffers */ - DescriptorSetPool descriptorSetPools[4]; + DescriptorSetLayout *descriptorSetLayouts[4]; Uint32 vertexSamplerCount; Uint32 vertexStorageBufferCount; @@ -770,7 +816,7 @@ typedef struct VulkanGraphicsPipeline VkPipeline pipeline; SDL_GPUPrimitiveType primitiveType; - VulkanGraphicsPipelineResourceLayout resourceLayout; + VulkanGraphicsPipelineResourceLayout *resourceLayout; VulkanShader *vertexShader; VulkanShader *fragmentShader; @@ -778,6 +824,16 @@ typedef struct VulkanGraphicsPipeline SDL_AtomicInt referenceCount; } VulkanGraphicsPipeline; +typedef struct ComputePipelineResourceLayoutHashTableKey +{ + Uint32 samplerCount; + Uint32 readonlyStorageTextureCount; + Uint32 readonlyStorageBufferCount; + Uint32 writeonlyStorageTextureCount; + Uint32 writeonlyStorageBufferCount; + Uint32 uniformBufferCount; +} ComputePipelineResourceLayoutHashTableKey; + typedef struct VulkanComputePipelineResourceLayout { VkPipelineLayout pipelineLayout; @@ -788,7 +844,7 @@ typedef struct VulkanComputePipelineResourceLayout * 1: write-only textures, then write-only buffers * 2: uniform buffers */ - DescriptorSetPool descriptorSetPools[3]; + DescriptorSetLayout *descriptorSetLayouts[3]; Uint32 numSamplers; Uint32 numReadonlyStorageTextures; @@ -802,7 +858,7 @@ typedef struct VulkanComputePipeline { VkShaderModule shaderModule; VkPipeline pipeline; - VulkanComputePipelineResourceLayout resourceLayout; + VulkanComputePipelineResourceLayout *resourceLayout; SDL_AtomicInt referenceCount; } VulkanComputePipeline; @@ -851,12 +907,6 @@ typedef struct FramebufferHashTableKey // Command structures -typedef struct DescriptorSetData -{ - DescriptorSetPool *descriptorSetPool; - VkDescriptorSet descriptorSet; -} DescriptorSetData; - typedef struct VulkanFencePool { SDL_Mutex *lock; @@ -911,6 +961,8 @@ typedef struct VulkanCommandBuffer // Resource bind state + DescriptorSetCache *descriptorSetCache; // acquired when command buffer is acquired + bool needNewVertexResourceDescriptorSet; bool needNewVertexUniformDescriptorSet; bool needNewVertexUniformOffsets; @@ -932,10 +984,6 @@ typedef struct VulkanCommandBuffer VkDescriptorSet computeWriteOnlyDescriptorSet; VkDescriptorSet computeUniformDescriptorSet; - DescriptorSetData *boundDescriptorSetDatas; - Uint32 boundDescriptorSetDataCount; - Uint32 boundDescriptorSetDataCapacity; - VulkanTexture *vertexSamplerTextures[MAX_TEXTURE_SAMPLERS_PER_STAGE]; VulkanSampler *vertexSamplers[MAX_TEXTURE_SAMPLERS_PER_STAGE]; VulkanTexture *vertexStorageTextures[MAX_STORAGE_TEXTURES_PER_STAGE]; @@ -964,32 +1012,32 @@ typedef struct VulkanCommandBuffer // Track used resources VulkanBuffer **usedBuffers; - Uint32 usedBufferCount; - Uint32 usedBufferCapacity; + Sint32 usedBufferCount; + Sint32 usedBufferCapacity; VulkanTexture **usedTextures; - Uint32 usedTextureCount; - Uint32 usedTextureCapacity; + Sint32 usedTextureCount; + Sint32 usedTextureCapacity; VulkanSampler **usedSamplers; - Uint32 usedSamplerCount; - Uint32 usedSamplerCapacity; + Sint32 usedSamplerCount; + Sint32 usedSamplerCapacity; VulkanGraphicsPipeline **usedGraphicsPipelines; - Uint32 usedGraphicsPipelineCount; - Uint32 usedGraphicsPipelineCapacity; + Sint32 usedGraphicsPipelineCount; + Sint32 usedGraphicsPipelineCapacity; VulkanComputePipeline **usedComputePipelines; - Uint32 usedComputePipelineCount; - Uint32 usedComputePipelineCapacity; + Sint32 usedComputePipelineCount; + Sint32 usedComputePipelineCapacity; VulkanFramebuffer **usedFramebuffers; - Uint32 usedFramebufferCount; - Uint32 usedFramebufferCapacity; + Sint32 usedFramebufferCount; + Sint32 usedFramebufferCapacity; VulkanUniformBuffer **usedUniformBuffers; - Uint32 usedUniformBufferCount; - Uint32 usedUniformBufferCapacity; + Sint32 usedUniformBufferCount; + Sint32 usedUniformBufferCapacity; VulkanFenceHandle *inFlightFence; Uint8 autoReleaseFence; @@ -1048,11 +1096,20 @@ struct VulkanRenderer SDL_HashTable *commandPoolHashTable; SDL_HashTable *renderPassHashTable; SDL_HashTable *framebufferHashTable; + SDL_HashTable *graphicsPipelineResourceLayoutHashTable; + SDL_HashTable *computePipelineResourceLayoutHashTable; + SDL_HashTable *descriptorSetLayoutHashTable; VulkanUniformBuffer **uniformBufferPool; Uint32 uniformBufferPoolCount; Uint32 uniformBufferPoolCapacity; + DescriptorSetCache **descriptorSetCachePool; + Uint32 descriptorSetCachePoolCount; + Uint32 descriptorSetCachePoolCapacity; + + SDL_AtomicInt layoutResourceID; + Uint32 minUBOAlignment; // Deferred resource destruction @@ -2257,23 +2314,21 @@ static Uint8 VULKAN_INTERNAL_BindMemoryForBuffer( commandBuffer->array[commandBuffer->count] = resource; \ commandBuffer->count += 1; -#define TRACK_RESOURCE(resource, type, array, count, capacity) \ - Uint32 i; \ - \ - for (i = 0; i < commandBuffer->count; i += 1) { \ - if (commandBuffer->array[i] == resource) { \ - return; \ - } \ - } \ - \ - if (commandBuffer->count == commandBuffer->capacity) { \ - commandBuffer->capacity += 1; \ - commandBuffer->array = SDL_realloc( \ - commandBuffer->array, \ - commandBuffer->capacity * sizeof(type)); \ - } \ - commandBuffer->array[commandBuffer->count] = resource; \ - commandBuffer->count += 1; \ +#define TRACK_RESOURCE(resource, type, array, count, capacity) \ + for (Sint32 i = commandBuffer->count - 1; i >= 0; i -= 1) { \ + if (commandBuffer->array[i] == resource) { \ + return; \ + } \ + } \ + \ + if (commandBuffer->count == commandBuffer->capacity) { \ + commandBuffer->capacity += 1; \ + commandBuffer->array = SDL_realloc( \ + commandBuffer->array, \ + commandBuffer->capacity * sizeof(type)); \ + } \ + commandBuffer->array[commandBuffer->count] = resource; \ + commandBuffer->count += 1; \ SDL_AtomicIncRef(&resource->referenceCount); static void VULKAN_INTERNAL_TrackBuffer( @@ -2353,8 +2408,7 @@ static void VULKAN_INTERNAL_TrackUniformBuffer( VulkanCommandBuffer *commandBuffer, VulkanUniformBuffer *uniformBuffer) { - Uint32 i; - for (i = 0; i < commandBuffer->usedUniformBufferCount; i += 1) { + for (Sint32 i = commandBuffer->usedUniformBufferCount - 1; i >= 0; i -= 1) { if (commandBuffer->usedUniformBuffers[i] == uniformBuffer) { return; } @@ -2935,7 +2989,6 @@ static void VULKAN_INTERNAL_DestroyCommandPool( SDL_free(commandBuffer->presentDatas); SDL_free(commandBuffer->waitSemaphores); SDL_free(commandBuffer->signalSemaphores); - SDL_free(commandBuffer->boundDescriptorSetDatas); SDL_free(commandBuffer->usedBuffers); SDL_free(commandBuffer->usedTextures); SDL_free(commandBuffer->usedSamplers); @@ -2951,55 +3004,33 @@ static void VULKAN_INTERNAL_DestroyCommandPool( SDL_free(commandPool); } -static void VULKAN_INTERNAL_DestroyDescriptorSetPool( +static void VULKAN_INTERNAL_DestroyDescriptorSetLayout( VulkanRenderer *renderer, - DescriptorSetPool *pool) + DescriptorSetLayout *layout) { - Uint32 i; - - if (pool == NULL) { + if (layout == NULL) { return; } - for (i = 0; i < pool->descriptorPoolCount; i += 1) { - renderer->vkDestroyDescriptorPool( + if (layout->descriptorSetLayout != VK_NULL_HANDLE) { + renderer->vkDestroyDescriptorSetLayout( renderer->logicalDevice, - pool->descriptorPools[i], + layout->descriptorSetLayout, NULL); } - renderer->vkDestroyDescriptorSetLayout( - renderer->logicalDevice, - pool->descriptorSetLayout, - NULL); - - SDL_free(pool->descriptorInfos); - SDL_free(pool->descriptorPools); - SDL_free(pool->inactiveDescriptorSets); + SDL_free(layout); } static void VULKAN_INTERNAL_DestroyGraphicsPipeline( VulkanRenderer *renderer, VulkanGraphicsPipeline *graphicsPipeline) { - Uint32 i; - renderer->vkDestroyPipeline( renderer->logicalDevice, graphicsPipeline->pipeline, NULL); - renderer->vkDestroyPipelineLayout( - renderer->logicalDevice, - graphicsPipeline->resourceLayout.pipelineLayout, - NULL); - - for (i = 0; i < 4; i += 1) { - VULKAN_INTERNAL_DestroyDescriptorSetPool( - renderer, - &graphicsPipeline->resourceLayout.descriptorSetPools[i]); - } - (void)SDL_AtomicDecRef(&graphicsPipeline->vertexShader->referenceCount); (void)SDL_AtomicDecRef(&graphicsPipeline->fragmentShader->referenceCount); @@ -3010,28 +3041,19 @@ static void VULKAN_INTERNAL_DestroyComputePipeline( VulkanRenderer *renderer, VulkanComputePipeline *computePipeline) { - Uint32 i; - - renderer->vkDestroyPipeline( - renderer->logicalDevice, - computePipeline->pipeline, - NULL); - - renderer->vkDestroyPipelineLayout( - renderer->logicalDevice, - computePipeline->resourceLayout.pipelineLayout, - NULL); - - for (i = 0; i < 3; i += 1) { - VULKAN_INTERNAL_DestroyDescriptorSetPool( - renderer, - &computePipeline->resourceLayout.descriptorSetPools[i]); + if (computePipeline->pipeline != VK_NULL_HANDLE) { + renderer->vkDestroyPipeline( + renderer->logicalDevice, + computePipeline->pipeline, + NULL); } - renderer->vkDestroyShaderModule( - renderer->logicalDevice, - computePipeline->shaderModule, - NULL); + if (computePipeline->shaderModule != VK_NULL_HANDLE) { + renderer->vkDestroyShaderModule( + renderer->logicalDevice, + computePipeline->shaderModule, + NULL); + } SDL_free(computePipeline); } @@ -3119,8 +3141,148 @@ static void VULKAN_INTERNAL_DestroySwapchain( SDL_free(swapchainData); } +static void VULKAN_INTERNAL_DestroyGraphicsPipelineResourceLayout( + VulkanRenderer *renderer, + VulkanGraphicsPipelineResourceLayout *resourceLayout) +{ + if (resourceLayout->pipelineLayout != VK_NULL_HANDLE) { + renderer->vkDestroyPipelineLayout( + renderer->logicalDevice, + resourceLayout->pipelineLayout, + NULL); + } + + SDL_free(resourceLayout); +} + +static void VULKAN_INTERNAL_DestroyComputePipelineResourceLayout( + VulkanRenderer *renderer, + VulkanComputePipelineResourceLayout *resourceLayout) +{ + if (resourceLayout->pipelineLayout != VK_NULL_HANDLE) { + renderer->vkDestroyPipelineLayout( + renderer->logicalDevice, + resourceLayout->pipelineLayout, + NULL); + } + + SDL_free(resourceLayout); +} + +static void VULKAN_INTERNAL_DestroyDescriptorSetCache( + VulkanRenderer *renderer, + DescriptorSetCache *descriptorSetCache) +{ + for (Uint32 i = 0; i < descriptorSetCache->poolCount; i += 1) { + for (Uint32 j = 0; j < descriptorSetCache->pools[i].poolCount; j += 1) { + renderer->vkDestroyDescriptorPool( + renderer->logicalDevice, + descriptorSetCache->pools[i].descriptorPools[j], + NULL); + } + SDL_free(descriptorSetCache->pools[i].descriptorSets); + SDL_free(descriptorSetCache->pools[i].descriptorPools); + } + SDL_free(descriptorSetCache); +} + // Hashtable functions +static Uint32 VULKAN_INTERNAL_GraphicsPipelineResourceLayoutHashFunction(const void *key, void *data) +{ + GraphicsPipelineResourceLayoutHashTableKey *hashTableKey = (GraphicsPipelineResourceLayoutHashTableKey *)key; + /* The algorithm for this hashing function + * is taken from Josh Bloch's "Effective Java". + * (https://stackoverflow.com/a/113600/12492383) + */ + const Uint32 hashFactor = 31; + Uint32 result = 1; + result = result * hashFactor + hashTableKey->vertexSamplerCount; + result = result * hashFactor + hashTableKey->vertexStorageBufferCount; + result = result * hashFactor + hashTableKey->vertexStorageTextureCount; + result = result * hashFactor + hashTableKey->vertexUniformBufferCount; + result = result * hashFactor + hashTableKey->fragmentSamplerCount; + result = result * hashFactor + hashTableKey->fragmentStorageBufferCount; + result = result * hashFactor + hashTableKey->fragmentStorageTextureCount; + result = result * hashFactor + hashTableKey->fragmentUniformBufferCount; + return result; +} +static bool VULKAN_INTERNAL_GraphicsPipelineResourceLayoutHashKeyMatch(const void *aKey, const void *bKey, void *data) +{ + return SDL_memcmp(aKey, bKey, sizeof(GraphicsPipelineResourceLayoutHashTableKey)) == 0; +} +static void VULKAN_INTERNAL_GraphicsPipelineResourceLayoutHashNuke(const void *key, const void *value, void *data) +{ + VulkanRenderer *renderer = (VulkanRenderer *)data; + VulkanGraphicsPipelineResourceLayout *resourceLayout = (VulkanGraphicsPipelineResourceLayout *)value; + VULKAN_INTERNAL_DestroyGraphicsPipelineResourceLayout(renderer, resourceLayout); + SDL_free((void*)key); +} + +static Uint32 VULKAN_INTERNAL_ComputePipelineResourceLayoutHashFunction(const void *key, void *data) +{ + ComputePipelineResourceLayoutHashTableKey *hashTableKey = (ComputePipelineResourceLayoutHashTableKey *)key; + /* The algorithm for this hashing function + * is taken from Josh Bloch's "Effective Java". + * (https://stackoverflow.com/a/113600/12492383) + */ + const Uint32 hashFactor = 31; + Uint32 result = 1; + result = result * hashFactor + hashTableKey->samplerCount; + result = result * hashFactor + hashTableKey->readonlyStorageTextureCount; + result = result * hashFactor + hashTableKey->readonlyStorageBufferCount; + result = result * hashFactor + hashTableKey->writeonlyStorageTextureCount; + result = result * hashFactor + hashTableKey->writeonlyStorageBufferCount; + result = result * hashFactor + hashTableKey->uniformBufferCount; + return result; +} + +static bool VULKAN_INTERNAL_ComputePipelineResourceLayoutHashKeyMatch(const void *aKey, const void *bKey, void *data) +{ + return SDL_memcmp(aKey, bKey, sizeof(ComputePipelineResourceLayoutHashTableKey)) == 0; +} + +static void VULKAN_INTERNAL_ComputePipelineResourceLayoutHashNuke(const void *key, const void *value, void *data) +{ + VulkanRenderer *renderer = (VulkanRenderer *)data; + VulkanComputePipelineResourceLayout *resourceLayout = (VulkanComputePipelineResourceLayout *)value; + VULKAN_INTERNAL_DestroyComputePipelineResourceLayout(renderer, resourceLayout); + SDL_free((void*)key); +} + +static Uint32 VULKAN_INTERNAL_DescriptorSetLayoutHashFunction(const void *key, void *data) +{ + DescriptorSetLayoutHashTableKey *hashTableKey = (DescriptorSetLayoutHashTableKey *)key; + + /* The algorithm for this hashing function + * is taken from Josh Bloch's "Effective Java". + * (https://stackoverflow.com/a/113600/12492383) + */ + const Uint32 hashFactor = 31; + Uint32 result = 1; + result = result * hashFactor + hashTableKey->shaderStage; + result = result * hashFactor + hashTableKey->samplerCount; + result = result * hashFactor + hashTableKey->storageTextureCount; + result = result * hashFactor + hashTableKey->storageBufferCount; + result = result * hashFactor + hashTableKey->writeStorageTextureCount; + result = result * hashFactor + hashTableKey->writeStorageBufferCount; + result = result * hashFactor + hashTableKey->uniformBufferCount; + return result; +} + +static bool VULKAN_INTERNAL_DescriptorSetLayoutHashKeyMatch(const void *aKey, const void *bKey, void *data) +{ + return SDL_memcmp(aKey, bKey, sizeof(DescriptorSetLayoutHashTableKey)) == 0; +} + +static void VULKAN_INTERNAL_DescriptorSetLayoutHashNuke(const void *key, const void *value, void *data) +{ + VulkanRenderer *renderer = (VulkanRenderer *)data; + DescriptorSetLayout *layout = (DescriptorSetLayout *)value; + VULKAN_INTERNAL_DestroyDescriptorSetLayout(renderer, layout); + SDL_free((void*)key); +} + static Uint32 VULKAN_INTERNAL_CommandPoolHashFunction(const void *key, void *data) { return (Uint32)((CommandPoolHashTableKey *)key)->threadID; @@ -3301,53 +3463,7 @@ static void VULKAN_INTERNAL_FramebufferHashNuke(const void *key, const void *val SDL_free((void *)key); } -// Descriptor pool stuff - -static bool VULKAN_INTERNAL_CreateDescriptorPool( - VulkanRenderer *renderer, - VulkanDescriptorInfo *descriptorInfos, - Uint32 descriptorInfoCount, - Uint32 descriptorSetPoolSize, - VkDescriptorPool *pDescriptorPool) -{ - VkDescriptorPoolSize *descriptorPoolSizes; - VkDescriptorPoolCreateInfo descriptorPoolInfo; - VkResult vulkanResult; - Uint32 i; - - descriptorPoolSizes = NULL; - - if (descriptorInfoCount > 0) { - descriptorPoolSizes = SDL_stack_alloc(VkDescriptorPoolSize, descriptorInfoCount); - - for (i = 0; i < descriptorInfoCount; i += 1) { - descriptorPoolSizes[i].type = descriptorInfos[i].descriptorType; - descriptorPoolSizes[i].descriptorCount = descriptorSetPoolSize; - } - } - - descriptorPoolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; - descriptorPoolInfo.pNext = NULL; - descriptorPoolInfo.flags = 0; - descriptorPoolInfo.maxSets = descriptorSetPoolSize; - descriptorPoolInfo.poolSizeCount = descriptorInfoCount; - descriptorPoolInfo.pPoolSizes = descriptorPoolSizes; - - vulkanResult = renderer->vkCreateDescriptorPool( - renderer->logicalDevice, - &descriptorPoolInfo, - NULL, - pDescriptorPool); - - SDL_stack_free(descriptorPoolSizes); - - if (vulkanResult != VK_SUCCESS) { - LogVulkanResultAsError("vkCreateDescriptorPool", vulkanResult); - return false; - } - - return true; -} +// Descriptor pools static bool VULKAN_INTERNAL_AllocateDescriptorSets( VulkanRenderer *renderer, @@ -3376,61 +3492,324 @@ static bool VULKAN_INTERNAL_AllocateDescriptorSets( &descriptorSetAllocateInfo, descriptorSetArray); + SDL_stack_free(descriptorSetLayouts); + if (vulkanResult != VK_SUCCESS) { LogVulkanResultAsError("vkAllocateDescriptorSets", vulkanResult); - SDL_stack_free(descriptorSetLayouts); return false; } - SDL_stack_free(descriptorSetLayouts); return true; } -static void VULKAN_INTERNAL_InitializeDescriptorSetPool( +static void VULKAN_INTERNAL_AllocateDescriptorsFromPool( VulkanRenderer *renderer, + DescriptorSetLayout *descriptorSetLayout, DescriptorSetPool *descriptorSetPool) { - descriptorSetPool->lock = 0; + VkDescriptorPoolSize descriptorPoolSizes[ + MAX_TEXTURE_SAMPLERS_PER_STAGE + + MAX_STORAGE_TEXTURES_PER_STAGE + + MAX_STORAGE_BUFFERS_PER_STAGE + + MAX_COMPUTE_WRITE_TEXTURES + + MAX_COMPUTE_WRITE_BUFFERS + + MAX_UNIFORM_BUFFERS_PER_STAGE]; + VkDescriptorPoolCreateInfo descriptorPoolInfo; + VkDescriptorPool pool; + VkResult vulkanResult; - // Descriptor set layout and descriptor infos are already set when this function is called + // Category 1 + for (Uint32 i = 0; i < descriptorSetLayout->samplerCount; i += 1) { + descriptorPoolSizes[i].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + descriptorPoolSizes[i].descriptorCount = DESCRIPTOR_POOL_SIZE; + } - descriptorSetPool->descriptorPoolCount = 1; - descriptorSetPool->descriptorPools = SDL_malloc(sizeof(VkDescriptorPool)); - descriptorSetPool->nextPoolSize = DESCRIPTOR_POOL_STARTING_SIZE * 2; + for (Uint32 i = descriptorSetLayout->samplerCount; i < descriptorSetLayout->samplerCount + descriptorSetLayout->storageTextureCount; i += 1) { + descriptorPoolSizes[i].type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; + descriptorPoolSizes[i].descriptorCount = DESCRIPTOR_POOL_SIZE; + } - VULKAN_INTERNAL_CreateDescriptorPool( - renderer, - descriptorSetPool->descriptorInfos, - descriptorSetPool->descriptorInfoCount, - DESCRIPTOR_POOL_STARTING_SIZE, - &descriptorSetPool->descriptorPools[0]); + for (Uint32 i = descriptorSetLayout->samplerCount + descriptorSetLayout->storageTextureCount; i < descriptorSetLayout->samplerCount + descriptorSetLayout->storageTextureCount + descriptorSetLayout->storageBufferCount; i += 1) { + descriptorPoolSizes[i].type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; + descriptorPoolSizes[i].descriptorCount = DESCRIPTOR_POOL_SIZE; + } - descriptorSetPool->inactiveDescriptorSetCapacity = DESCRIPTOR_POOL_STARTING_SIZE; - descriptorSetPool->inactiveDescriptorSetCount = DESCRIPTOR_POOL_STARTING_SIZE; - descriptorSetPool->inactiveDescriptorSets = SDL_malloc( - sizeof(VkDescriptorSet) * DESCRIPTOR_POOL_STARTING_SIZE); + // Category 2 + for (Uint32 i = 0; i < descriptorSetLayout->writeStorageTextureCount; i += 1) { + descriptorPoolSizes[i].type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; + descriptorPoolSizes[i].descriptorCount = DESCRIPTOR_POOL_SIZE; + } + + for (Uint32 i = descriptorSetLayout->writeStorageTextureCount; i < descriptorSetLayout->writeStorageTextureCount + descriptorSetLayout->writeStorageBufferCount; i += 1) { + descriptorPoolSizes[i].type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; + descriptorPoolSizes[i].descriptorCount = DESCRIPTOR_POOL_SIZE; + } + + // Category 3 + for (Uint32 i = 0; i < descriptorSetLayout->uniformBufferCount; i += 1) { + descriptorPoolSizes[i].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC; + descriptorPoolSizes[i].descriptorCount = DESCRIPTOR_POOL_SIZE; + } + + descriptorPoolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; + descriptorPoolInfo.pNext = NULL; + descriptorPoolInfo.flags = 0; + descriptorPoolInfo.maxSets = DESCRIPTOR_POOL_SIZE; + descriptorPoolInfo.poolSizeCount = + descriptorSetLayout->samplerCount + + descriptorSetLayout->storageTextureCount + + descriptorSetLayout->storageBufferCount + + descriptorSetLayout->writeStorageTextureCount + + descriptorSetLayout->writeStorageBufferCount + + descriptorSetLayout->uniformBufferCount; + descriptorPoolInfo.pPoolSizes = descriptorPoolSizes; + + vulkanResult = renderer->vkCreateDescriptorPool( + renderer->logicalDevice, + &descriptorPoolInfo, + NULL, + &pool); + + if (vulkanResult != VK_SUCCESS) { + LogVulkanResultAsError("vkCreateDescriptorPool", vulkanResult); + return; + } + + descriptorSetPool->poolCount += 1; + descriptorSetPool->descriptorPools = SDL_realloc( + descriptorSetPool->descriptorPools, + sizeof(VkDescriptorPool) * descriptorSetPool->poolCount); + + descriptorSetPool->descriptorPools[descriptorSetPool->poolCount - 1] = pool; + + descriptorSetPool->descriptorSets = SDL_realloc( + descriptorSetPool->descriptorSets, + sizeof(VkDescriptorSet) * descriptorSetPool->poolCount * DESCRIPTOR_POOL_SIZE); VULKAN_INTERNAL_AllocateDescriptorSets( renderer, - descriptorSetPool->descriptorPools[0], - descriptorSetPool->descriptorSetLayout, - DESCRIPTOR_POOL_STARTING_SIZE, - descriptorSetPool->inactiveDescriptorSets); + pool, + descriptorSetLayout->descriptorSetLayout, + DESCRIPTOR_POOL_SIZE, + &descriptorSetPool->descriptorSets[descriptorSetPool->descriptorSetCount]); + + descriptorSetPool->descriptorSetCount += DESCRIPTOR_POOL_SIZE; } -static bool VULKAN_INTERNAL_InitializeGraphicsPipelineResourceLayout( +// NOTE: these categories should be mutually exclusive +static DescriptorSetLayout *VULKAN_INTERNAL_FetchDescriptorSetLayout( + VulkanRenderer *renderer, + VkShaderStageFlagBits shaderStage, + // Category 1: read resources + Uint32 samplerCount, + Uint32 storageTextureCount, + Uint32 storageBufferCount, + // Category 2: write resources + Uint32 writeStorageTextureCount, + Uint32 writeStorageBufferCount, + // Category 3: uniform buffers + Uint32 uniformBufferCount) +{ + DescriptorSetLayoutHashTableKey key; + SDL_zero(key); + DescriptorSetLayout *layout = NULL; + + key.shaderStage = shaderStage; + key.samplerCount = samplerCount; + key.storageTextureCount = storageTextureCount; + key.storageBufferCount = storageBufferCount; + key.writeStorageTextureCount = writeStorageTextureCount; + key.writeStorageBufferCount = writeStorageBufferCount; + key.uniformBufferCount = uniformBufferCount; + + if (SDL_FindInHashTable( + renderer->descriptorSetLayoutHashTable, + (const void *)&key, + (const void **)&layout)) { + return layout; + } + + VkDescriptorSetLayout descriptorSetLayout; + VkDescriptorSetLayoutBinding descriptorSetLayoutBindings[ + MAX_TEXTURE_SAMPLERS_PER_STAGE + + MAX_STORAGE_TEXTURES_PER_STAGE + + MAX_STORAGE_BUFFERS_PER_STAGE + + MAX_COMPUTE_WRITE_TEXTURES + + MAX_COMPUTE_WRITE_BUFFERS]; + + VkDescriptorSetLayoutCreateInfo descriptorSetLayoutCreateInfo; + descriptorSetLayoutCreateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; + descriptorSetLayoutCreateInfo.pNext = NULL; + descriptorSetLayoutCreateInfo.flags = 0; + + // Category 1 + for (Uint32 i = 0; i < samplerCount; i += 1) { + descriptorSetLayoutBindings[i].binding = i; + descriptorSetLayoutBindings[i].descriptorCount = 1; + descriptorSetLayoutBindings[i].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + descriptorSetLayoutBindings[i].stageFlags = shaderStage; + descriptorSetLayoutBindings[i].pImmutableSamplers = NULL; + } + + for (Uint32 i = samplerCount; i < samplerCount + storageTextureCount; i += 1) { + descriptorSetLayoutBindings[i].binding = i; + descriptorSetLayoutBindings[i].descriptorCount = 1; + descriptorSetLayoutBindings[i].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; + descriptorSetLayoutBindings[i].stageFlags = shaderStage; + descriptorSetLayoutBindings[i].pImmutableSamplers = NULL; + } + + for (Uint32 i = samplerCount + storageTextureCount; i < samplerCount + storageTextureCount + storageBufferCount; i += 1) { + descriptorSetLayoutBindings[i].binding = i; + descriptorSetLayoutBindings[i].descriptorCount = 1; + descriptorSetLayoutBindings[i].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; + descriptorSetLayoutBindings[i].stageFlags = shaderStage; + descriptorSetLayoutBindings[i].pImmutableSamplers = NULL; + } + + // Category 2 + for (Uint32 i = 0; i < writeStorageTextureCount; i += 1) { + descriptorSetLayoutBindings[i].binding = i; + descriptorSetLayoutBindings[i].descriptorCount = 1; + descriptorSetLayoutBindings[i].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; + descriptorSetLayoutBindings[i].stageFlags = shaderStage; + descriptorSetLayoutBindings[i].pImmutableSamplers = NULL; + } + + for (Uint32 i = writeStorageTextureCount; i < writeStorageTextureCount + writeStorageBufferCount; i += 1) { + descriptorSetLayoutBindings[i].binding = i; + descriptorSetLayoutBindings[i].descriptorCount = 1; + descriptorSetLayoutBindings[i].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; + descriptorSetLayoutBindings[i].stageFlags = shaderStage; + descriptorSetLayoutBindings[i].pImmutableSamplers = NULL; + } + + // Category 3 + for (Uint32 i = 0; i < uniformBufferCount; i += 1) { + descriptorSetLayoutBindings[i].binding = i; + descriptorSetLayoutBindings[i].descriptorCount = 1; + descriptorSetLayoutBindings[i].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC; + descriptorSetLayoutBindings[i].stageFlags = shaderStage; + descriptorSetLayoutBindings[i].pImmutableSamplers = NULL; + } + + descriptorSetLayoutCreateInfo.pBindings = descriptorSetLayoutBindings; + descriptorSetLayoutCreateInfo.bindingCount = + samplerCount + + storageTextureCount + + storageBufferCount + + writeStorageTextureCount + + writeStorageBufferCount + + uniformBufferCount; + + VkResult vulkanResult = renderer->vkCreateDescriptorSetLayout( + renderer->logicalDevice, + &descriptorSetLayoutCreateInfo, + NULL, + &descriptorSetLayout); + + if (vulkanResult != VK_SUCCESS) { + LogVulkanResultAsError("vkCreateDescriptorSetLayout", vulkanResult); + return NULL; + } + + layout = SDL_malloc(sizeof(DescriptorSetLayout)); + layout->descriptorSetLayout = descriptorSetLayout; + + layout->samplerCount = samplerCount; + layout->storageBufferCount = storageBufferCount; + layout->storageTextureCount = storageTextureCount; + layout->writeStorageBufferCount = writeStorageBufferCount; + layout->writeStorageTextureCount = writeStorageTextureCount; + layout->uniformBufferCount = uniformBufferCount; + + layout->ID = SDL_AtomicIncRef(&renderer->layoutResourceID); + + DescriptorSetLayoutHashTableKey *allocedKey = SDL_malloc(sizeof(DescriptorSetLayoutHashTableKey)); + SDL_memcpy(allocedKey, &key, sizeof(DescriptorSetLayoutHashTableKey)); + + SDL_InsertIntoHashTable( + renderer->descriptorSetLayoutHashTable, + (const void *)allocedKey, + (const void *)layout); + + return layout; +} + +static VulkanGraphicsPipelineResourceLayout *VULKAN_INTERNAL_FetchGraphicsPipelineResourceLayout( VulkanRenderer *renderer, VulkanShader *vertexShader, - VulkanShader *fragmentShader, - VulkanGraphicsPipelineResourceLayout *pipelineResourceLayout) + VulkanShader *fragmentShader) { - VkDescriptorSetLayoutBinding descriptorSetLayoutBindings[MAX_TEXTURE_SAMPLERS_PER_STAGE + MAX_STORAGE_TEXTURES_PER_STAGE + MAX_STORAGE_BUFFERS_PER_STAGE]; - VkDescriptorSetLayoutCreateInfo descriptorSetLayoutCreateInfo; - VkDescriptorSetLayout descriptorSetLayouts[4]; + GraphicsPipelineResourceLayoutHashTableKey key; + SDL_zero(key); + VulkanGraphicsPipelineResourceLayout *pipelineResourceLayout = NULL; + + key.vertexSamplerCount = vertexShader->numSamplers; + key.vertexStorageTextureCount = vertexShader->numStorageTextures; + key.vertexStorageBufferCount = vertexShader->numStorageBuffers; + key.vertexUniformBufferCount = vertexShader->numUniformBuffers; + key.fragmentSamplerCount = fragmentShader->numSamplers; + key.fragmentStorageTextureCount = fragmentShader->numStorageTextures; + key.fragmentStorageBufferCount = fragmentShader->numStorageBuffers; + key.fragmentUniformBufferCount = fragmentShader->numUniformBuffers; + if (SDL_FindInHashTable( + renderer->graphicsPipelineResourceLayoutHashTable, + (const void *)&key, + (const void **)&pipelineResourceLayout)) { + return pipelineResourceLayout; + } + VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo; - DescriptorSetPool *descriptorSetPool; + VkDescriptorSetLayout descriptorSetLayouts[4]; VkResult vulkanResult; - Uint32 i; + + pipelineResourceLayout = SDL_calloc(1, sizeof(VulkanGraphicsPipelineResourceLayout)); + + pipelineResourceLayout->descriptorSetLayouts[0] = VULKAN_INTERNAL_FetchDescriptorSetLayout( + renderer, + VK_SHADER_STAGE_VERTEX_BIT, + vertexShader->numSamplers, + vertexShader->numStorageTextures, + vertexShader->numStorageBuffers, + 0, + 0, + 0); + + pipelineResourceLayout->descriptorSetLayouts[1] = VULKAN_INTERNAL_FetchDescriptorSetLayout( + renderer, + VK_SHADER_STAGE_VERTEX_BIT, + 0, + 0, + 0, + 0, + 0, + vertexShader->numUniformBuffers); + + pipelineResourceLayout->descriptorSetLayouts[2] = VULKAN_INTERNAL_FetchDescriptorSetLayout( + renderer, + VK_SHADER_STAGE_FRAGMENT_BIT, + fragmentShader->numSamplers, + fragmentShader->numStorageTextures, + fragmentShader->numStorageBuffers, + 0, + 0, + 0); + + pipelineResourceLayout->descriptorSetLayouts[3] = VULKAN_INTERNAL_FetchDescriptorSetLayout( + renderer, + VK_SHADER_STAGE_FRAGMENT_BIT, + 0, + 0, + 0, + 0, + 0, + fragmentShader->numUniformBuffers); + + descriptorSetLayouts[0] = pipelineResourceLayout->descriptorSetLayouts[0]->descriptorSetLayout; + descriptorSetLayouts[1] = pipelineResourceLayout->descriptorSetLayouts[1]->descriptorSetLayout; + descriptorSetLayouts[2] = pipelineResourceLayout->descriptorSetLayouts[2]->descriptorSetLayout; + descriptorSetLayouts[3] = pipelineResourceLayout->descriptorSetLayouts[3]->descriptorSetLayout; pipelineResourceLayout->vertexSamplerCount = vertexShader->numSamplers; pipelineResourceLayout->vertexStorageTextureCount = vertexShader->numStorageTextures; @@ -3442,226 +3821,6 @@ static bool VULKAN_INTERNAL_InitializeGraphicsPipelineResourceLayout( pipelineResourceLayout->fragmentStorageBufferCount = fragmentShader->numStorageBuffers; pipelineResourceLayout->fragmentUniformBufferCount = fragmentShader->numUniformBuffers; - // Vertex Resources - - descriptorSetLayoutCreateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; - descriptorSetLayoutCreateInfo.pNext = NULL; - descriptorSetLayoutCreateInfo.flags = 0; - descriptorSetLayoutCreateInfo.pBindings = NULL; - descriptorSetLayoutCreateInfo.bindingCount = - vertexShader->numSamplers + - vertexShader->numStorageTextures + - vertexShader->numStorageBuffers; - - descriptorSetPool = &pipelineResourceLayout->descriptorSetPools[0]; - - descriptorSetPool->descriptorInfoCount = descriptorSetLayoutCreateInfo.bindingCount; - descriptorSetPool->descriptorInfos = NULL; - - if (descriptorSetLayoutCreateInfo.bindingCount > 0) { - descriptorSetPool->descriptorInfos = SDL_malloc( - descriptorSetPool->descriptorInfoCount * sizeof(VulkanDescriptorInfo)); - - for (i = 0; i < vertexShader->numSamplers; i += 1) { - descriptorSetLayoutBindings[i].binding = i; - descriptorSetLayoutBindings[i].descriptorCount = 1; - descriptorSetLayoutBindings[i].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - descriptorSetLayoutBindings[i].stageFlags = VK_SHADER_STAGE_VERTEX_BIT; - descriptorSetLayoutBindings[i].pImmutableSamplers = NULL; - - descriptorSetPool->descriptorInfos[i].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - descriptorSetPool->descriptorInfos[i].stageFlag = VK_SHADER_STAGE_VERTEX_BIT; - } - - for (i = vertexShader->numSamplers; i < vertexShader->numSamplers + vertexShader->numStorageTextures; i += 1) { - descriptorSetLayoutBindings[i].binding = i; - descriptorSetLayoutBindings[i].descriptorCount = 1; - descriptorSetLayoutBindings[i].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; - descriptorSetLayoutBindings[i].stageFlags = VK_SHADER_STAGE_VERTEX_BIT; - descriptorSetLayoutBindings[i].pImmutableSamplers = NULL; - - descriptorSetPool->descriptorInfos[i].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; - descriptorSetPool->descriptorInfos[i].stageFlag = VK_SHADER_STAGE_VERTEX_BIT; - } - - for (i = vertexShader->numSamplers + vertexShader->numStorageTextures; i < descriptorSetLayoutCreateInfo.bindingCount; i += 1) { - descriptorSetLayoutBindings[i].binding = i; - descriptorSetLayoutBindings[i].descriptorCount = 1; - descriptorSetLayoutBindings[i].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; - descriptorSetLayoutBindings[i].stageFlags = VK_SHADER_STAGE_VERTEX_BIT; - descriptorSetLayoutBindings[i].pImmutableSamplers = NULL; - - descriptorSetPool->descriptorInfos[i].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; - descriptorSetPool->descriptorInfos[i].stageFlag = VK_SHADER_STAGE_VERTEX_BIT; - } - - descriptorSetLayoutCreateInfo.pBindings = descriptorSetLayoutBindings; - } - - vulkanResult = renderer->vkCreateDescriptorSetLayout( - renderer->logicalDevice, - &descriptorSetLayoutCreateInfo, - NULL, - &descriptorSetPool->descriptorSetLayout); - - descriptorSetLayouts[0] = descriptorSetPool->descriptorSetLayout; - - if (vulkanResult != VK_SUCCESS) { - LogVulkanResultAsError("vkCreateDescriptorSetLayout", vulkanResult); - return false; - } - - // Vertex UBOs - - descriptorSetPool = &pipelineResourceLayout->descriptorSetPools[1]; - - descriptorSetLayoutCreateInfo.bindingCount = pipelineResourceLayout->vertexUniformBufferCount; - descriptorSetLayoutCreateInfo.pBindings = NULL; - - descriptorSetPool->descriptorInfoCount = descriptorSetLayoutCreateInfo.bindingCount; - descriptorSetPool->descriptorInfos = NULL; - - if (descriptorSetLayoutCreateInfo.bindingCount > 0) { - descriptorSetPool->descriptorInfos = SDL_malloc( - descriptorSetPool->descriptorInfoCount * sizeof(VulkanDescriptorInfo)); - - for (i = 0; i < vertexShader->numUniformBuffers; i += 1) { - descriptorSetLayoutBindings[i].binding = i; - descriptorSetLayoutBindings[i].descriptorCount = 1; - descriptorSetLayoutBindings[i].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC; - descriptorSetLayoutBindings[i].stageFlags = VK_SHADER_STAGE_VERTEX_BIT; - descriptorSetLayoutBindings[i].pImmutableSamplers = NULL; - - descriptorSetPool->descriptorInfos[i].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC; - descriptorSetPool->descriptorInfos[i].stageFlag = VK_SHADER_STAGE_VERTEX_BIT; - } - - descriptorSetLayoutCreateInfo.pBindings = descriptorSetLayoutBindings; - } - - vulkanResult = renderer->vkCreateDescriptorSetLayout( - renderer->logicalDevice, - &descriptorSetLayoutCreateInfo, - NULL, - &descriptorSetPool->descriptorSetLayout); - - descriptorSetLayouts[1] = descriptorSetPool->descriptorSetLayout; - - if (vulkanResult != VK_SUCCESS) { - LogVulkanResultAsError("vkCreateDescriptorSetLayout", vulkanResult); - return false; - } - - // Fragment resources - - descriptorSetPool = &pipelineResourceLayout->descriptorSetPools[2]; - - descriptorSetLayoutCreateInfo.bindingCount = - fragmentShader->numSamplers + - fragmentShader->numStorageTextures + - fragmentShader->numStorageBuffers; - - descriptorSetLayoutCreateInfo.pBindings = NULL; - - descriptorSetPool->descriptorInfoCount = descriptorSetLayoutCreateInfo.bindingCount; - descriptorSetPool->descriptorInfos = NULL; - - if (descriptorSetLayoutCreateInfo.bindingCount > 0) { - descriptorSetPool->descriptorInfos = SDL_malloc( - descriptorSetPool->descriptorInfoCount * sizeof(VulkanDescriptorInfo)); - - for (i = 0; i < fragmentShader->numSamplers; i += 1) { - descriptorSetLayoutBindings[i].binding = i; - descriptorSetLayoutBindings[i].descriptorCount = 1; - descriptorSetLayoutBindings[i].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - descriptorSetLayoutBindings[i].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; - descriptorSetLayoutBindings[i].pImmutableSamplers = NULL; - - descriptorSetPool->descriptorInfos[i].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - descriptorSetPool->descriptorInfos[i].stageFlag = VK_SHADER_STAGE_FRAGMENT_BIT; - } - - for (i = fragmentShader->numSamplers; i < fragmentShader->numSamplers + fragmentShader->numStorageTextures; i += 1) { - descriptorSetLayoutBindings[i].binding = i; - descriptorSetLayoutBindings[i].descriptorCount = 1; - descriptorSetLayoutBindings[i].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; - descriptorSetLayoutBindings[i].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; - descriptorSetLayoutBindings[i].pImmutableSamplers = NULL; - - descriptorSetPool->descriptorInfos[i].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; - descriptorSetPool->descriptorInfos[i].stageFlag = VK_SHADER_STAGE_FRAGMENT_BIT; - } - - for (i = fragmentShader->numSamplers + fragmentShader->numStorageTextures; i < descriptorSetLayoutCreateInfo.bindingCount; i += 1) { - descriptorSetLayoutBindings[i].binding = i; - descriptorSetLayoutBindings[i].descriptorCount = 1; - descriptorSetLayoutBindings[i].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; - descriptorSetLayoutBindings[i].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; - descriptorSetLayoutBindings[i].pImmutableSamplers = NULL; - - descriptorSetPool->descriptorInfos[i].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; - descriptorSetPool->descriptorInfos[i].stageFlag = VK_SHADER_STAGE_FRAGMENT_BIT; - } - - descriptorSetLayoutCreateInfo.pBindings = descriptorSetLayoutBindings; - } - - vulkanResult = renderer->vkCreateDescriptorSetLayout( - renderer->logicalDevice, - &descriptorSetLayoutCreateInfo, - NULL, - &descriptorSetPool->descriptorSetLayout); - - descriptorSetLayouts[2] = descriptorSetPool->descriptorSetLayout; - - if (vulkanResult != VK_SUCCESS) { - LogVulkanResultAsError("vkCreateDescriptorSetLayout", vulkanResult); - return false; - } - - // Fragment UBOs - - descriptorSetPool = &pipelineResourceLayout->descriptorSetPools[3]; - - descriptorSetLayoutCreateInfo.bindingCount = - pipelineResourceLayout->fragmentUniformBufferCount; - - descriptorSetLayoutCreateInfo.pBindings = NULL; - - descriptorSetPool->descriptorInfoCount = descriptorSetLayoutCreateInfo.bindingCount; - descriptorSetPool->descriptorInfos = NULL; - - if (descriptorSetLayoutCreateInfo.bindingCount > 0) { - descriptorSetPool->descriptorInfos = SDL_malloc( - descriptorSetPool->descriptorInfoCount * sizeof(VulkanDescriptorInfo)); - - for (i = 0; i < fragmentShader->numUniformBuffers; i += 1) { - descriptorSetLayoutBindings[i].binding = i; - descriptorSetLayoutBindings[i].descriptorCount = 1; - descriptorSetLayoutBindings[i].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC; - descriptorSetLayoutBindings[i].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; - descriptorSetLayoutBindings[i].pImmutableSamplers = NULL; - - descriptorSetPool->descriptorInfos[i].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC; - descriptorSetPool->descriptorInfos[i].stageFlag = VK_SHADER_STAGE_FRAGMENT_BIT; - } - - descriptorSetLayoutCreateInfo.pBindings = descriptorSetLayoutBindings; - } - - vulkanResult = renderer->vkCreateDescriptorSetLayout( - renderer->logicalDevice, - &descriptorSetLayoutCreateInfo, - NULL, - &descriptorSetPool->descriptorSetLayout); - - descriptorSetLayouts[3] = descriptorSetPool->descriptorSetLayout; - - if (vulkanResult != VK_SUCCESS) { - LogVulkanResultAsError("vkCreateDescriptorSetLayout", vulkanResult); - return false; - } - // Create the pipeline layout pipelineLayoutCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; @@ -3680,30 +3839,82 @@ static bool VULKAN_INTERNAL_InitializeGraphicsPipelineResourceLayout( if (vulkanResult != VK_SUCCESS) { LogVulkanResultAsError("vkCreatePipelineLayout", vulkanResult); - return false; + VULKAN_INTERNAL_DestroyGraphicsPipelineResourceLayout(renderer, pipelineResourceLayout); + return NULL; } - for (i = 0; i < 4; i += 1) { - VULKAN_INTERNAL_InitializeDescriptorSetPool( - renderer, - &pipelineResourceLayout->descriptorSetPools[i]); - } + GraphicsPipelineResourceLayoutHashTableKey *allocedKey = SDL_malloc(sizeof(GraphicsPipelineResourceLayoutHashTableKey)); + SDL_memcpy(allocedKey, &key, sizeof(GraphicsPipelineResourceLayoutHashTableKey)); - return true; + SDL_InsertIntoHashTable( + renderer->graphicsPipelineResourceLayoutHashTable, + (const void *)allocedKey, + (const void *)pipelineResourceLayout); + + return pipelineResourceLayout; } -static bool VULKAN_INTERNAL_InitializeComputePipelineResourceLayout( +static VulkanComputePipelineResourceLayout *VULKAN_INTERNAL_FetchComputePipelineResourceLayout( VulkanRenderer *renderer, - const SDL_GPUComputePipelineCreateInfo *createinfo, - VulkanComputePipelineResourceLayout *pipelineResourceLayout) + const SDL_GPUComputePipelineCreateInfo *createinfo) { - VkDescriptorSetLayoutBinding descriptorSetLayoutBindings[MAX_UNIFORM_BUFFERS_PER_STAGE]; - VkDescriptorSetLayoutCreateInfo descriptorSetLayoutCreateInfo; + ComputePipelineResourceLayoutHashTableKey key; + SDL_zero(key); + VulkanComputePipelineResourceLayout *pipelineResourceLayout = NULL; + + key.samplerCount = createinfo->num_samplers; + key.readonlyStorageTextureCount = createinfo->num_readonly_storage_textures; + key.readonlyStorageBufferCount = createinfo->num_readonly_storage_buffers; + key.writeonlyStorageTextureCount = createinfo->num_writeonly_storage_textures; + key.writeonlyStorageBufferCount = createinfo->num_writeonly_storage_buffers; + key.uniformBufferCount = createinfo->num_uniform_buffers; + + if (SDL_FindInHashTable( + renderer->computePipelineResourceLayoutHashTable, + (const void *)&key, + (const void **)&pipelineResourceLayout)) { + return pipelineResourceLayout; + } + VkDescriptorSetLayout descriptorSetLayouts[3]; VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo; - DescriptorSetPool *descriptorSetPool; VkResult vulkanResult; - Uint32 i; + + pipelineResourceLayout = SDL_calloc(1, sizeof(VulkanComputePipelineResourceLayout)); + + pipelineResourceLayout->descriptorSetLayouts[0] = VULKAN_INTERNAL_FetchDescriptorSetLayout( + renderer, + VK_SHADER_STAGE_COMPUTE_BIT, + createinfo->num_samplers, + createinfo->num_readonly_storage_textures, + createinfo->num_readonly_storage_buffers, + 0, + 0, + 0); + + pipelineResourceLayout->descriptorSetLayouts[1] = VULKAN_INTERNAL_FetchDescriptorSetLayout( + renderer, + VK_SHADER_STAGE_COMPUTE_BIT, + 0, + 0, + 0, + createinfo->num_writeonly_storage_textures, + createinfo->num_writeonly_storage_buffers, + 0); + + pipelineResourceLayout->descriptorSetLayouts[2] = VULKAN_INTERNAL_FetchDescriptorSetLayout( + renderer, + VK_SHADER_STAGE_COMPUTE_BIT, + 0, + 0, + 0, + 0, + 0, + createinfo->num_uniform_buffers); + + descriptorSetLayouts[0] = pipelineResourceLayout->descriptorSetLayouts[0]->descriptorSetLayout; + descriptorSetLayouts[1] = pipelineResourceLayout->descriptorSetLayouts[1]->descriptorSetLayout; + descriptorSetLayouts[2] = pipelineResourceLayout->descriptorSetLayouts[2]->descriptorSetLayout; pipelineResourceLayout->numSamplers = createinfo->num_samplers; pipelineResourceLayout->numReadonlyStorageTextures = createinfo->num_readonly_storage_textures; @@ -3712,171 +3923,6 @@ static bool VULKAN_INTERNAL_InitializeComputePipelineResourceLayout( pipelineResourceLayout->numWriteonlyStorageBuffers = createinfo->num_writeonly_storage_buffers; pipelineResourceLayout->numUniformBuffers = createinfo->num_uniform_buffers; - // Read-only resources - - descriptorSetLayoutCreateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; - descriptorSetLayoutCreateInfo.pNext = NULL; - descriptorSetLayoutCreateInfo.flags = 0; - descriptorSetLayoutCreateInfo.pBindings = NULL; - descriptorSetLayoutCreateInfo.bindingCount = - createinfo->num_samplers + - createinfo->num_readonly_storage_textures + - createinfo->num_readonly_storage_buffers; - - descriptorSetPool = &pipelineResourceLayout->descriptorSetPools[0]; - - descriptorSetPool->descriptorInfoCount = descriptorSetLayoutCreateInfo.bindingCount; - descriptorSetPool->descriptorInfos = NULL; - - if (descriptorSetLayoutCreateInfo.bindingCount > 0) { - descriptorSetPool->descriptorInfos = SDL_malloc( - descriptorSetPool->descriptorInfoCount * sizeof(VulkanDescriptorInfo)); - - for (i = 0; i < createinfo->num_samplers; i += 1) { - descriptorSetLayoutBindings[i].binding = i; - descriptorSetLayoutBindings[i].descriptorCount = 1; - descriptorSetLayoutBindings[i].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - descriptorSetLayoutBindings[i].stageFlags = VK_SHADER_STAGE_COMPUTE_BIT; - descriptorSetLayoutBindings[i].pImmutableSamplers = NULL; - - descriptorSetPool->descriptorInfos[i].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - descriptorSetPool->descriptorInfos[i].stageFlag = VK_SHADER_STAGE_COMPUTE_BIT; - } - - for (i = createinfo->num_samplers; i < createinfo->num_samplers + createinfo->num_readonly_storage_textures; i += 1) { - descriptorSetLayoutBindings[i].binding = i; - descriptorSetLayoutBindings[i].descriptorCount = 1; - descriptorSetLayoutBindings[i].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; - descriptorSetLayoutBindings[i].stageFlags = VK_SHADER_STAGE_COMPUTE_BIT; - descriptorSetLayoutBindings[i].pImmutableSamplers = NULL; - - descriptorSetPool->descriptorInfos[i].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; - descriptorSetPool->descriptorInfos[i].stageFlag = VK_SHADER_STAGE_COMPUTE_BIT; - } - - for (i = createinfo->num_samplers + createinfo->num_readonly_storage_textures; i < descriptorSetLayoutCreateInfo.bindingCount; i += 1) { - descriptorSetLayoutBindings[i].binding = i; - descriptorSetLayoutBindings[i].descriptorCount = 1; - descriptorSetLayoutBindings[i].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; - descriptorSetLayoutBindings[i].stageFlags = VK_SHADER_STAGE_COMPUTE_BIT; - descriptorSetLayoutBindings[i].pImmutableSamplers = NULL; - - descriptorSetPool->descriptorInfos[i].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; - descriptorSetPool->descriptorInfos[i].stageFlag = VK_SHADER_STAGE_COMPUTE_BIT; - } - - descriptorSetLayoutCreateInfo.pBindings = descriptorSetLayoutBindings; - } - - vulkanResult = renderer->vkCreateDescriptorSetLayout( - renderer->logicalDevice, - &descriptorSetLayoutCreateInfo, - NULL, - &descriptorSetPool->descriptorSetLayout); - - descriptorSetLayouts[0] = descriptorSetPool->descriptorSetLayout; - - if (vulkanResult != VK_SUCCESS) { - LogVulkanResultAsError("vkCreateDescriptorSetLayout", vulkanResult); - return false; - } - - // Write-only resources - - descriptorSetLayoutCreateInfo.bindingCount = - createinfo->num_writeonly_storage_textures + - createinfo->num_writeonly_storage_buffers; - - descriptorSetLayoutCreateInfo.pBindings = NULL; - - descriptorSetPool = &pipelineResourceLayout->descriptorSetPools[1]; - - descriptorSetPool->descriptorInfoCount = descriptorSetLayoutCreateInfo.bindingCount; - descriptorSetPool->descriptorInfos = NULL; - - if (descriptorSetLayoutCreateInfo.bindingCount > 0) { - descriptorSetPool->descriptorInfos = SDL_malloc( - descriptorSetPool->descriptorInfoCount * sizeof(VulkanDescriptorInfo)); - - for (i = 0; i < createinfo->num_writeonly_storage_textures; i += 1) { - descriptorSetLayoutBindings[i].binding = i; - descriptorSetLayoutBindings[i].descriptorCount = 1; - descriptorSetLayoutBindings[i].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; - descriptorSetLayoutBindings[i].stageFlags = VK_SHADER_STAGE_COMPUTE_BIT; - descriptorSetLayoutBindings[i].pImmutableSamplers = NULL; - - descriptorSetPool->descriptorInfos[i].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; - descriptorSetPool->descriptorInfos[i].stageFlag = VK_SHADER_STAGE_COMPUTE_BIT; - } - - for (i = createinfo->num_writeonly_storage_textures; i < descriptorSetLayoutCreateInfo.bindingCount; i += 1) { - descriptorSetLayoutBindings[i].binding = i; - descriptorSetLayoutBindings[i].descriptorCount = 1; - descriptorSetLayoutBindings[i].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; - descriptorSetLayoutBindings[i].stageFlags = VK_SHADER_STAGE_COMPUTE_BIT; - descriptorSetLayoutBindings[i].pImmutableSamplers = NULL; - - descriptorSetPool->descriptorInfos[i].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; - descriptorSetPool->descriptorInfos[i].stageFlag = VK_SHADER_STAGE_COMPUTE_BIT; - } - - descriptorSetLayoutCreateInfo.pBindings = descriptorSetLayoutBindings; - } - - vulkanResult = renderer->vkCreateDescriptorSetLayout( - renderer->logicalDevice, - &descriptorSetLayoutCreateInfo, - NULL, - &descriptorSetPool->descriptorSetLayout); - - descriptorSetLayouts[1] = descriptorSetPool->descriptorSetLayout; - - if (vulkanResult != VK_SUCCESS) { - LogVulkanResultAsError("vkCreateDescriptorSetLayout", vulkanResult); - return false; - } - - // Uniform buffers - - descriptorSetPool = &pipelineResourceLayout->descriptorSetPools[2]; - - descriptorSetLayoutCreateInfo.bindingCount = createinfo->num_uniform_buffers; - descriptorSetLayoutCreateInfo.pBindings = NULL; - - descriptorSetPool->descriptorInfoCount = descriptorSetLayoutCreateInfo.bindingCount; - descriptorSetPool->descriptorInfos = NULL; - - if (descriptorSetLayoutCreateInfo.bindingCount > 0) { - descriptorSetPool->descriptorInfos = SDL_malloc( - descriptorSetPool->descriptorInfoCount * sizeof(VulkanDescriptorInfo)); - - for (i = 0; i < createinfo->num_uniform_buffers; i += 1) { - descriptorSetLayoutBindings[i].binding = i; - descriptorSetLayoutBindings[i].descriptorCount = 1; - descriptorSetLayoutBindings[i].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC; - descriptorSetLayoutBindings[i].stageFlags = VK_SHADER_STAGE_COMPUTE_BIT; - descriptorSetLayoutBindings[i].pImmutableSamplers = NULL; - - descriptorSetPool->descriptorInfos[i].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC; - descriptorSetPool->descriptorInfos[i].stageFlag = VK_SHADER_STAGE_COMPUTE_BIT; - } - - descriptorSetLayoutCreateInfo.pBindings = descriptorSetLayoutBindings; - } - - vulkanResult = renderer->vkCreateDescriptorSetLayout( - renderer->logicalDevice, - &descriptorSetLayoutCreateInfo, - NULL, - &descriptorSetPool->descriptorSetLayout); - - descriptorSetLayouts[2] = descriptorSetPool->descriptorSetLayout; - - if (vulkanResult != VK_SUCCESS) { - LogVulkanResultAsError("vkCreateDescriptorSetLayout", vulkanResult); - return false; - } - // Create the pipeline layout pipelineLayoutCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; @@ -3895,16 +3941,19 @@ static bool VULKAN_INTERNAL_InitializeComputePipelineResourceLayout( if (vulkanResult != VK_SUCCESS) { LogVulkanResultAsError("vkCreatePipelineLayout", vulkanResult); - return false; + VULKAN_INTERNAL_DestroyComputePipelineResourceLayout(renderer, pipelineResourceLayout); + return NULL; } - for (i = 0; i < 3; i += 1) { - VULKAN_INTERNAL_InitializeDescriptorSetPool( - renderer, - &pipelineResourceLayout->descriptorSetPools[i]); - } + ComputePipelineResourceLayoutHashTableKey *allocedKey = SDL_malloc(sizeof(ComputePipelineResourceLayoutHashTableKey)); + SDL_memcpy(allocedKey, &key, sizeof(ComputePipelineResourceLayoutHashTableKey)); - return true; + SDL_InsertIntoHashTable( + renderer->computePipelineResourceLayoutHashTable, + (const void *)allocedKey, + (const void *)pipelineResourceLayout); + + return pipelineResourceLayout; } // Data Buffer @@ -4674,6 +4723,13 @@ static void VULKAN_DestroyDevice( } SDL_free(renderer->uniformBufferPool); + for (Uint32 i = 0; i < renderer->descriptorSetCachePoolCount; i += 1) { + VULKAN_INTERNAL_DestroyDescriptorSetCache( + renderer, + renderer->descriptorSetCachePool[i]); + } + SDL_free(renderer->descriptorSetCachePool); + for (Uint32 i = 0; i < renderer->fencePool.availableFenceCount; i += 1) { renderer->vkDestroyFence( renderer->logicalDevice, @@ -4689,6 +4745,9 @@ static void VULKAN_DestroyDevice( SDL_DestroyHashTable(renderer->commandPoolHashTable); SDL_DestroyHashTable(renderer->renderPassHashTable); SDL_DestroyHashTable(renderer->framebufferHashTable); + SDL_DestroyHashTable(renderer->graphicsPipelineResourceLayoutHashTable); + SDL_DestroyHashTable(renderer->computePipelineResourceLayoutHashTable); + SDL_DestroyHashTable(renderer->descriptorSetLayoutHashTable); for (Uint32 i = 0; i < VK_MAX_MEMORY_TYPES; i += 1) { allocator = &renderer->memoryAllocator->subAllocators[i]; @@ -4740,71 +4799,72 @@ static void VULKAN_DestroyDevice( SDL_Vulkan_UnloadLibrary(); } +static DescriptorSetCache *VULKAN_INTERNAL_AcquireDescriptorSetCache( + VulkanRenderer *renderer) +{ + DescriptorSetCache *cache; + + if (renderer->descriptorSetCachePoolCount == 0) { + cache = SDL_malloc(sizeof(DescriptorSetCache)); + cache->poolCount = 0; + cache->pools = NULL; + } else { + cache = renderer->descriptorSetCachePool[renderer->descriptorSetCachePoolCount - 1]; + renderer->descriptorSetCachePoolCount -= 1; + } + + return cache; +} + +static void VULKAN_INTERNAL_ReturnDescriptorSetCacheToPool( + VulkanRenderer *renderer, + DescriptorSetCache *descriptorSetCache) +{ + EXPAND_ARRAY_IF_NEEDED( + renderer->descriptorSetCachePool, + DescriptorSetCache *, + renderer->descriptorSetCachePoolCount + 1, + renderer->descriptorSetCachePoolCapacity, + renderer->descriptorSetCachePoolCapacity * 2) + + renderer->descriptorSetCachePool[renderer->descriptorSetCachePoolCount] = descriptorSetCache; + renderer->descriptorSetCachePoolCount += 1; + + for (Uint32 i = 0; i < descriptorSetCache->poolCount; i += 1) { + descriptorSetCache->pools[i].descriptorSetIndex = 0; + } +} + static VkDescriptorSet VULKAN_INTERNAL_FetchDescriptorSet( VulkanRenderer *renderer, VulkanCommandBuffer *vulkanCommandBuffer, - DescriptorSetPool *descriptorSetPool) + DescriptorSetLayout *descriptorSetLayout) { - VkDescriptorSet descriptorSet; + // Grow the pool to meet the descriptor set layout ID + if (descriptorSetLayout->ID >= vulkanCommandBuffer->descriptorSetCache->poolCount) { + vulkanCommandBuffer->descriptorSetCache->pools = SDL_realloc( + vulkanCommandBuffer->descriptorSetCache->pools, + sizeof(DescriptorSetPool) * (descriptorSetLayout->ID + 1)); - SDL_LockSpinlock(&descriptorSetPool->lock); - - // If no inactive descriptor sets remain, create a new pool and allocate new inactive sets - - if (descriptorSetPool->inactiveDescriptorSetCount == 0) { - descriptorSetPool->descriptorPoolCount += 1; - descriptorSetPool->descriptorPools = SDL_realloc( - descriptorSetPool->descriptorPools, - sizeof(VkDescriptorPool) * descriptorSetPool->descriptorPoolCount); - - if (!VULKAN_INTERNAL_CreateDescriptorPool( - renderer, - descriptorSetPool->descriptorInfos, - descriptorSetPool->descriptorInfoCount, - descriptorSetPool->nextPoolSize, - &descriptorSetPool->descriptorPools[descriptorSetPool->descriptorPoolCount - 1])) { - SDL_UnlockSpinlock(&descriptorSetPool->lock); - SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to create descriptor pool!"); - return VK_NULL_HANDLE; + for (Uint32 i = vulkanCommandBuffer->descriptorSetCache->poolCount; i < descriptorSetLayout->ID + 1; i += 1) { + SDL_zero(vulkanCommandBuffer->descriptorSetCache->pools[i]); } - descriptorSetPool->inactiveDescriptorSetCapacity += descriptorSetPool->nextPoolSize; - - descriptorSetPool->inactiveDescriptorSets = SDL_realloc( - descriptorSetPool->inactiveDescriptorSets, - sizeof(VkDescriptorSet) * descriptorSetPool->inactiveDescriptorSetCapacity); - - if (!VULKAN_INTERNAL_AllocateDescriptorSets( - renderer, - descriptorSetPool->descriptorPools[descriptorSetPool->descriptorPoolCount - 1], - descriptorSetPool->descriptorSetLayout, - descriptorSetPool->nextPoolSize, - descriptorSetPool->inactiveDescriptorSets)) { - SDL_UnlockSpinlock(&descriptorSetPool->lock); - SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to allocate descriptor sets!"); - return VK_NULL_HANDLE; - } - - descriptorSetPool->inactiveDescriptorSetCount = descriptorSetPool->nextPoolSize; - - descriptorSetPool->nextPoolSize *= 2; + vulkanCommandBuffer->descriptorSetCache->poolCount = descriptorSetLayout->ID + 1; } - descriptorSet = descriptorSetPool->inactiveDescriptorSets[descriptorSetPool->inactiveDescriptorSetCount - 1]; - descriptorSetPool->inactiveDescriptorSetCount -= 1; + DescriptorSetPool *pool = + &vulkanCommandBuffer->descriptorSetCache->pools[descriptorSetLayout->ID]; - SDL_UnlockSpinlock(&descriptorSetPool->lock); - - if (vulkanCommandBuffer->boundDescriptorSetDataCount == vulkanCommandBuffer->boundDescriptorSetDataCapacity) { - vulkanCommandBuffer->boundDescriptorSetDataCapacity *= 2; - vulkanCommandBuffer->boundDescriptorSetDatas = SDL_realloc( - vulkanCommandBuffer->boundDescriptorSetDatas, - vulkanCommandBuffer->boundDescriptorSetDataCapacity * sizeof(DescriptorSetData)); + if (pool->descriptorSetIndex == pool->descriptorSetCount) { + VULKAN_INTERNAL_AllocateDescriptorsFromPool( + renderer, + descriptorSetLayout, + pool); } - vulkanCommandBuffer->boundDescriptorSetDatas[vulkanCommandBuffer->boundDescriptorSetDataCount].descriptorSet = descriptorSet; - vulkanCommandBuffer->boundDescriptorSetDatas[vulkanCommandBuffer->boundDescriptorSetDataCount].descriptorSetPool = descriptorSetPool; - vulkanCommandBuffer->boundDescriptorSetDataCount += 1; + VkDescriptorSet descriptorSet = pool->descriptorSets[pool->descriptorSetIndex]; + pool->descriptorSetIndex += 1; return descriptorSet; } @@ -4814,34 +4874,44 @@ static void VULKAN_INTERNAL_BindGraphicsDescriptorSets( VulkanCommandBuffer *commandBuffer) { VulkanGraphicsPipelineResourceLayout *resourceLayout; - VkWriteDescriptorSet *writeDescriptorSets; - VkWriteDescriptorSet *currentWriteDescriptorSet; - DescriptorSetPool *descriptorSetPool; - VkDescriptorBufferInfo bufferInfos[MAX_STORAGE_BUFFERS_PER_STAGE]; - VkDescriptorImageInfo imageInfos[MAX_TEXTURE_SAMPLERS_PER_STAGE + MAX_STORAGE_TEXTURES_PER_STAGE]; - Uint32 dynamicOffsets[MAX_UNIFORM_BUFFERS_PER_STAGE]; + DescriptorSetLayout *descriptorSetLayout; + VkWriteDescriptorSet writeDescriptorSets[ + (MAX_TEXTURE_SAMPLERS_PER_STAGE + + MAX_STORAGE_TEXTURES_PER_STAGE + + MAX_STORAGE_BUFFERS_PER_STAGE + + MAX_UNIFORM_BUFFERS_PER_STAGE) * 2]; + VkDescriptorBufferInfo bufferInfos[MAX_STORAGE_BUFFERS_PER_STAGE * 2]; + VkDescriptorImageInfo imageInfos[(MAX_TEXTURE_SAMPLERS_PER_STAGE + MAX_STORAGE_TEXTURES_PER_STAGE) * 2]; + Uint32 dynamicOffsets[MAX_UNIFORM_BUFFERS_PER_STAGE * 2]; + Uint32 writeCount = 0; Uint32 bufferInfoCount = 0; Uint32 imageInfoCount = 0; - Uint32 i; + Uint32 dynamicOffsetCount = 0; - resourceLayout = &commandBuffer->currentGraphicsPipeline->resourceLayout; + if ( + !commandBuffer->needNewVertexResourceDescriptorSet && + !commandBuffer->needNewVertexUniformDescriptorSet && + !commandBuffer->needNewVertexUniformOffsets && + !commandBuffer->needNewFragmentResourceDescriptorSet && + !commandBuffer->needNewFragmentUniformDescriptorSet && + !commandBuffer->needNewFragmentUniformOffsets + ) { + return; + } + + resourceLayout = commandBuffer->currentGraphicsPipeline->resourceLayout; if (commandBuffer->needNewVertexResourceDescriptorSet) { - descriptorSetPool = &resourceLayout->descriptorSetPools[0]; + descriptorSetLayout = resourceLayout->descriptorSetLayouts[0]; commandBuffer->vertexResourceDescriptorSet = VULKAN_INTERNAL_FetchDescriptorSet( renderer, commandBuffer, - descriptorSetPool); + descriptorSetLayout); - writeDescriptorSets = SDL_stack_alloc( - VkWriteDescriptorSet, - resourceLayout->vertexSamplerCount + - resourceLayout->vertexStorageTextureCount + - resourceLayout->vertexStorageBufferCount); + for (Uint32 i = 0; i < resourceLayout->vertexSamplerCount; i += 1) { + VkWriteDescriptorSet *currentWriteDescriptorSet = &writeDescriptorSets[writeCount]; - for (i = 0; i < resourceLayout->vertexSamplerCount; i += 1) { - currentWriteDescriptorSet = &writeDescriptorSets[i]; currentWriteDescriptorSet->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; currentWriteDescriptorSet->pNext = NULL; currentWriteDescriptorSet->descriptorCount = 1; @@ -4858,11 +4928,12 @@ static void VULKAN_INTERNAL_BindGraphicsDescriptorSets( currentWriteDescriptorSet->pImageInfo = &imageInfos[imageInfoCount]; + writeCount += 1; imageInfoCount += 1; } - for (i = 0; i < resourceLayout->vertexStorageTextureCount; i += 1) { - currentWriteDescriptorSet = &writeDescriptorSets[resourceLayout->vertexSamplerCount + i]; + for (Uint32 i = 0; i < resourceLayout->vertexStorageTextureCount; i += 1) { + VkWriteDescriptorSet *currentWriteDescriptorSet = &writeDescriptorSets[writeCount]; currentWriteDescriptorSet->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; currentWriteDescriptorSet->pNext = NULL; @@ -4880,11 +4951,12 @@ static void VULKAN_INTERNAL_BindGraphicsDescriptorSets( currentWriteDescriptorSet->pImageInfo = &imageInfos[imageInfoCount]; + writeCount += 1; imageInfoCount += 1; } - for (i = 0; i < resourceLayout->vertexStorageBufferCount; i += 1) { - currentWriteDescriptorSet = &writeDescriptorSets[resourceLayout->vertexSamplerCount + resourceLayout->vertexStorageTextureCount + i]; + for (Uint32 i = 0; i < resourceLayout->vertexStorageBufferCount; i += 1) { + VkWriteDescriptorSet *currentWriteDescriptorSet = &writeDescriptorSets[writeCount]; currentWriteDescriptorSet->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; currentWriteDescriptorSet->pNext = NULL; @@ -4902,47 +4974,23 @@ static void VULKAN_INTERNAL_BindGraphicsDescriptorSets( currentWriteDescriptorSet->pBufferInfo = &bufferInfos[bufferInfoCount]; + writeCount += 1; bufferInfoCount += 1; } - renderer->vkUpdateDescriptorSets( - renderer->logicalDevice, - resourceLayout->vertexSamplerCount + resourceLayout->vertexStorageTextureCount + resourceLayout->vertexStorageBufferCount, - writeDescriptorSets, - 0, - NULL); - - renderer->vkCmdBindDescriptorSets( - commandBuffer->commandBuffer, - VK_PIPELINE_BIND_POINT_GRAPHICS, - resourceLayout->pipelineLayout, - 0, - 1, - &commandBuffer->vertexResourceDescriptorSet, - 0, - NULL); - - SDL_stack_free(writeDescriptorSets); - bufferInfoCount = 0; - imageInfoCount = 0; - commandBuffer->needNewVertexResourceDescriptorSet = false; } if (commandBuffer->needNewVertexUniformDescriptorSet) { - descriptorSetPool = &resourceLayout->descriptorSetPools[1]; + descriptorSetLayout = resourceLayout->descriptorSetLayouts[1]; commandBuffer->vertexUniformDescriptorSet = VULKAN_INTERNAL_FetchDescriptorSet( renderer, commandBuffer, - descriptorSetPool); + descriptorSetLayout); - writeDescriptorSets = SDL_stack_alloc( - VkWriteDescriptorSet, - resourceLayout->vertexUniformBufferCount); - - for (i = 0; i < resourceLayout->vertexUniformBufferCount; i += 1) { - currentWriteDescriptorSet = &writeDescriptorSets[i]; + for (Uint32 i = 0; i < resourceLayout->vertexUniformBufferCount; i += 1) { + VkWriteDescriptorSet *currentWriteDescriptorSet = &writeDescriptorSets[writeCount]; currentWriteDescriptorSet->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; currentWriteDescriptorSet->pNext = NULL; @@ -4960,58 +5008,29 @@ static void VULKAN_INTERNAL_BindGraphicsDescriptorSets( currentWriteDescriptorSet->pBufferInfo = &bufferInfos[bufferInfoCount]; + writeCount += 1; bufferInfoCount += 1; } - renderer->vkUpdateDescriptorSets( - renderer->logicalDevice, - resourceLayout->vertexUniformBufferCount, - writeDescriptorSets, - 0, - NULL); - - SDL_stack_free(writeDescriptorSets); - bufferInfoCount = 0; - imageInfoCount = 0; - commandBuffer->needNewVertexUniformDescriptorSet = false; - commandBuffer->needNewVertexUniformOffsets = true; } - if (commandBuffer->needNewVertexUniformOffsets) { - for (i = 0; i < resourceLayout->vertexUniformBufferCount; i += 1) { - dynamicOffsets[i] = commandBuffer->vertexUniformBuffers[i]->drawOffset; - } - - renderer->vkCmdBindDescriptorSets( - commandBuffer->commandBuffer, - VK_PIPELINE_BIND_POINT_GRAPHICS, - resourceLayout->pipelineLayout, - 1, - 1, - &commandBuffer->vertexUniformDescriptorSet, - resourceLayout->vertexUniformBufferCount, - dynamicOffsets); - - commandBuffer->needNewVertexUniformOffsets = false; + for (Uint32 i = 0; i < resourceLayout->vertexUniformBufferCount; i += 1) { + dynamicOffsets[dynamicOffsetCount] = commandBuffer->vertexUniformBuffers[i]->drawOffset; + dynamicOffsetCount += 1; } if (commandBuffer->needNewFragmentResourceDescriptorSet) { - descriptorSetPool = &resourceLayout->descriptorSetPools[2]; + descriptorSetLayout = resourceLayout->descriptorSetLayouts[2]; commandBuffer->fragmentResourceDescriptorSet = VULKAN_INTERNAL_FetchDescriptorSet( renderer, commandBuffer, - descriptorSetPool); + descriptorSetLayout); - writeDescriptorSets = SDL_stack_alloc( - VkWriteDescriptorSet, - resourceLayout->fragmentSamplerCount + - resourceLayout->fragmentStorageTextureCount + - resourceLayout->fragmentStorageBufferCount); + for (Uint32 i = 0; i < resourceLayout->fragmentSamplerCount; i += 1) { + VkWriteDescriptorSet *currentWriteDescriptorSet = &writeDescriptorSets[writeCount]; - for (i = 0; i < resourceLayout->fragmentSamplerCount; i += 1) { - currentWriteDescriptorSet = &writeDescriptorSets[i]; currentWriteDescriptorSet->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; currentWriteDescriptorSet->pNext = NULL; currentWriteDescriptorSet->descriptorCount = 1; @@ -5028,11 +5047,12 @@ static void VULKAN_INTERNAL_BindGraphicsDescriptorSets( currentWriteDescriptorSet->pImageInfo = &imageInfos[imageInfoCount]; + writeCount += 1; imageInfoCount += 1; } - for (i = 0; i < resourceLayout->fragmentStorageTextureCount; i += 1) { - currentWriteDescriptorSet = &writeDescriptorSets[resourceLayout->fragmentSamplerCount + i]; + for (Uint32 i = 0; i < resourceLayout->fragmentStorageTextureCount; i += 1) { + VkWriteDescriptorSet *currentWriteDescriptorSet = &writeDescriptorSets[writeCount]; currentWriteDescriptorSet->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; currentWriteDescriptorSet->pNext = NULL; @@ -5050,11 +5070,12 @@ static void VULKAN_INTERNAL_BindGraphicsDescriptorSets( currentWriteDescriptorSet->pImageInfo = &imageInfos[imageInfoCount]; + writeCount += 1; imageInfoCount += 1; } - for (i = 0; i < resourceLayout->fragmentStorageBufferCount; i += 1) { - currentWriteDescriptorSet = &writeDescriptorSets[resourceLayout->fragmentSamplerCount + resourceLayout->fragmentStorageTextureCount + i]; + for (Uint32 i = 0; i < resourceLayout->fragmentStorageBufferCount; i += 1) { + VkWriteDescriptorSet *currentWriteDescriptorSet = &writeDescriptorSets[writeCount]; currentWriteDescriptorSet->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; currentWriteDescriptorSet->pNext = NULL; @@ -5072,47 +5093,23 @@ static void VULKAN_INTERNAL_BindGraphicsDescriptorSets( currentWriteDescriptorSet->pBufferInfo = &bufferInfos[bufferInfoCount]; + writeCount += 1; bufferInfoCount += 1; } - renderer->vkUpdateDescriptorSets( - renderer->logicalDevice, - resourceLayout->fragmentSamplerCount + resourceLayout->fragmentStorageTextureCount + resourceLayout->fragmentStorageBufferCount, - writeDescriptorSets, - 0, - NULL); - - renderer->vkCmdBindDescriptorSets( - commandBuffer->commandBuffer, - VK_PIPELINE_BIND_POINT_GRAPHICS, - resourceLayout->pipelineLayout, - 2, - 1, - &commandBuffer->fragmentResourceDescriptorSet, - 0, - NULL); - - SDL_stack_free(writeDescriptorSets); - bufferInfoCount = 0; - imageInfoCount = 0; - commandBuffer->needNewFragmentResourceDescriptorSet = false; } if (commandBuffer->needNewFragmentUniformDescriptorSet) { - descriptorSetPool = &resourceLayout->descriptorSetPools[3]; + descriptorSetLayout = resourceLayout->descriptorSetLayouts[3]; commandBuffer->fragmentUniformDescriptorSet = VULKAN_INTERNAL_FetchDescriptorSet( renderer, commandBuffer, - descriptorSetPool); + descriptorSetLayout); - writeDescriptorSets = SDL_stack_alloc( - VkWriteDescriptorSet, - resourceLayout->fragmentUniformBufferCount); - - for (i = 0; i < resourceLayout->fragmentUniformBufferCount; i += 1) { - currentWriteDescriptorSet = &writeDescriptorSets[i]; + for (Uint32 i = 0; i < resourceLayout->fragmentUniformBufferCount; i += 1) { + VkWriteDescriptorSet *currentWriteDescriptorSet = &writeDescriptorSets[writeCount]; currentWriteDescriptorSet->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; currentWriteDescriptorSet->pNext = NULL; @@ -5130,41 +5127,43 @@ static void VULKAN_INTERNAL_BindGraphicsDescriptorSets( currentWriteDescriptorSet->pBufferInfo = &bufferInfos[bufferInfoCount]; + writeCount += 1; bufferInfoCount += 1; } - renderer->vkUpdateDescriptorSets( - renderer->logicalDevice, - resourceLayout->fragmentUniformBufferCount, - writeDescriptorSets, - 0, - NULL); - - SDL_stack_free(writeDescriptorSets); - bufferInfoCount = 0; - imageInfoCount = 0; - commandBuffer->needNewFragmentUniformDescriptorSet = false; - commandBuffer->needNewFragmentUniformOffsets = true; } - if (commandBuffer->needNewFragmentUniformOffsets) { - for (i = 0; i < resourceLayout->fragmentUniformBufferCount; i += 1) { - dynamicOffsets[i] = commandBuffer->fragmentUniformBuffers[i]->drawOffset; - } - - renderer->vkCmdBindDescriptorSets( - commandBuffer->commandBuffer, - VK_PIPELINE_BIND_POINT_GRAPHICS, - resourceLayout->pipelineLayout, - 3, - 1, - &commandBuffer->fragmentUniformDescriptorSet, - resourceLayout->fragmentUniformBufferCount, - dynamicOffsets); - - commandBuffer->needNewFragmentUniformOffsets = false; + for (Uint32 i = 0; i < resourceLayout->fragmentUniformBufferCount; i += 1) { + dynamicOffsets[dynamicOffsetCount] = commandBuffer->fragmentUniformBuffers[i]->drawOffset; + dynamicOffsetCount += 1; } + + renderer->vkUpdateDescriptorSets( + renderer->logicalDevice, + writeCount, + writeDescriptorSets, + 0, + NULL); + + VkDescriptorSet sets[4]; + sets[0] = commandBuffer->vertexResourceDescriptorSet; + sets[1] = commandBuffer->vertexUniformDescriptorSet; + sets[2] = commandBuffer->fragmentResourceDescriptorSet; + sets[3] = commandBuffer->fragmentUniformDescriptorSet; + + renderer->vkCmdBindDescriptorSets( + commandBuffer->commandBuffer, + VK_PIPELINE_BIND_POINT_GRAPHICS, + resourceLayout->pipelineLayout, + 0, + 4, + sets, + dynamicOffsetCount, + dynamicOffsets); + + commandBuffer->needNewVertexUniformOffsets = false; + commandBuffer->needNewFragmentUniformOffsets = false; } static void VULKAN_DrawIndexedPrimitives( @@ -6283,11 +6282,13 @@ static SDL_GPUGraphicsPipeline *VULKAN_CreateGraphicsPipeline( // Pipeline Layout - if (!VULKAN_INTERNAL_InitializeGraphicsPipelineResourceLayout( + graphicsPipeline->resourceLayout = + VULKAN_INTERNAL_FetchGraphicsPipelineResourceLayout( renderer, graphicsPipeline->vertexShader, - graphicsPipeline->fragmentShader, - &graphicsPipeline->resourceLayout)) { + graphicsPipeline->fragmentShader); + + if (graphicsPipeline->resourceLayout == NULL) { SDL_stack_free(vertexInputBindingDescriptions); SDL_stack_free(vertexInputAttributeDescriptions); SDL_stack_free(colorBlendAttachmentStates); @@ -6313,7 +6314,7 @@ static SDL_GPUGraphicsPipeline *VULKAN_CreateGraphicsPipeline( vkPipelineCreateInfo.pDepthStencilState = &depthStencilStateCreateInfo; vkPipelineCreateInfo.pColorBlendState = &colorBlendStateCreateInfo; vkPipelineCreateInfo.pDynamicState = &dynamicStateCreateInfo; - vkPipelineCreateInfo.layout = graphicsPipeline->resourceLayout.pipelineLayout; + vkPipelineCreateInfo.layout = graphicsPipeline->resourceLayout->pipelineLayout; vkPipelineCreateInfo.renderPass = transientRenderPass; vkPipelineCreateInfo.subpass = 0; vkPipelineCreateInfo.basePipelineHandle = VK_NULL_HANDLE; @@ -6358,7 +6359,6 @@ static SDL_GPUComputePipeline *VULKAN_CreateComputePipeline( VkComputePipelineCreateInfo vkShaderCreateInfo; VkPipelineShaderStageCreateInfo pipelineShaderStageCreateInfo; VkResult vulkanResult; - Uint32 i; VulkanRenderer *renderer = (VulkanRenderer *)driverData; VulkanComputePipeline *vulkanComputePipeline; @@ -6395,10 +6395,11 @@ static SDL_GPUComputePipeline *VULKAN_CreateComputePipeline( pipelineShaderStageCreateInfo.pName = createinfo->entrypoint; pipelineShaderStageCreateInfo.pSpecializationInfo = NULL; - if (!VULKAN_INTERNAL_InitializeComputePipelineResourceLayout( - renderer, - createinfo, - &vulkanComputePipeline->resourceLayout)) { + vulkanComputePipeline->resourceLayout = VULKAN_INTERNAL_FetchComputePipelineResourceLayout( + renderer, + createinfo); + + if (vulkanComputePipeline->resourceLayout == NULL) { renderer->vkDestroyShaderModule( renderer->logicalDevice, vulkanComputePipeline->shaderModule, @@ -6411,8 +6412,7 @@ static SDL_GPUComputePipeline *VULKAN_CreateComputePipeline( vkShaderCreateInfo.pNext = NULL; vkShaderCreateInfo.flags = 0; vkShaderCreateInfo.stage = pipelineShaderStageCreateInfo; - vkShaderCreateInfo.layout = - vulkanComputePipeline->resourceLayout.pipelineLayout; + vkShaderCreateInfo.layout = vulkanComputePipeline->resourceLayout->pipelineLayout; vkShaderCreateInfo.basePipelineHandle = (VkPipeline)VK_NULL_HANDLE; vkShaderCreateInfo.basePipelineIndex = 0; @@ -6425,24 +6425,9 @@ static SDL_GPUComputePipeline *VULKAN_CreateComputePipeline( &vulkanComputePipeline->pipeline); if (vulkanResult != VK_SUCCESS) { - renderer->vkDestroyPipelineLayout( - renderer->logicalDevice, - vulkanComputePipeline->resourceLayout.pipelineLayout, - NULL); - - for (i = 0; i < 3; i += 1) { - VULKAN_INTERNAL_DestroyDescriptorSetPool( - renderer, - &vulkanComputePipeline->resourceLayout.descriptorSetPools[i]); - } - - renderer->vkDestroyShaderModule( - renderer->logicalDevice, - vulkanComputePipeline->shaderModule, - NULL); - LogVulkanResultAsError("vkCreateComputePipeline", vulkanResult); SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to create compute pipeline!"); + VULKAN_INTERNAL_DestroyComputePipeline(renderer, vulkanComputePipeline); return NULL; } @@ -7667,14 +7652,14 @@ static void VULKAN_BindGraphicsPipeline( VULKAN_INTERNAL_TrackGraphicsPipeline(vulkanCommandBuffer, pipeline); // Acquire uniform buffers if necessary - for (Uint32 i = 0; i < pipeline->resourceLayout.vertexUniformBufferCount; i += 1) { + for (Uint32 i = 0; i < pipeline->resourceLayout->vertexUniformBufferCount; i += 1) { if (vulkanCommandBuffer->vertexUniformBuffers[i] == NULL) { vulkanCommandBuffer->vertexUniformBuffers[i] = VULKAN_INTERNAL_AcquireUniformBufferFromPool( vulkanCommandBuffer); } } - for (Uint32 i = 0; i < pipeline->resourceLayout.fragmentUniformBufferCount; i += 1) { + for (Uint32 i = 0; i < pipeline->resourceLayout->fragmentUniformBufferCount; i += 1) { if (vulkanCommandBuffer->fragmentUniformBuffers[i] == NULL) { vulkanCommandBuffer->fragmentUniformBuffers[i] = VULKAN_INTERNAL_AcquireUniformBufferFromPool( vulkanCommandBuffer); @@ -7899,7 +7884,7 @@ static void VULKAN_BindComputePipeline( VULKAN_INTERNAL_TrackComputePipeline(vulkanCommandBuffer, vulkanComputePipeline); // Acquire uniform buffers if necessary - for (Uint32 i = 0; i < vulkanComputePipeline->resourceLayout.numUniformBuffers; i += 1) { + for (Uint32 i = 0; i < vulkanComputePipeline->resourceLayout->numUniformBuffers; i += 1) { if (vulkanCommandBuffer->computeUniformBuffers[i] == NULL) { vulkanCommandBuffer->computeUniformBuffers[i] = VULKAN_INTERNAL_AcquireUniformBufferFromPool( vulkanCommandBuffer); @@ -8034,34 +8019,44 @@ static void VULKAN_INTERNAL_BindComputeDescriptorSets( VulkanCommandBuffer *commandBuffer) { VulkanComputePipelineResourceLayout *resourceLayout; - VkWriteDescriptorSet *writeDescriptorSets; - VkWriteDescriptorSet *currentWriteDescriptorSet; - DescriptorSetPool *descriptorSetPool; - VkDescriptorBufferInfo bufferInfos[MAX_STORAGE_BUFFERS_PER_STAGE]; // 8 is max for both read and write - VkDescriptorImageInfo imageInfos[MAX_TEXTURE_SAMPLERS_PER_STAGE + MAX_STORAGE_TEXTURES_PER_STAGE]; + DescriptorSetLayout *descriptorSetLayout; + VkWriteDescriptorSet writeDescriptorSets[ + MAX_TEXTURE_SAMPLERS_PER_STAGE + + MAX_STORAGE_TEXTURES_PER_STAGE + + MAX_STORAGE_BUFFERS_PER_STAGE + + MAX_COMPUTE_WRITE_TEXTURES + + MAX_COMPUTE_WRITE_BUFFERS + + MAX_UNIFORM_BUFFERS_PER_STAGE]; + VkDescriptorBufferInfo bufferInfos[MAX_STORAGE_BUFFERS_PER_STAGE + MAX_COMPUTE_WRITE_BUFFERS + MAX_UNIFORM_BUFFERS_PER_STAGE]; + VkDescriptorImageInfo imageInfos[MAX_TEXTURE_SAMPLERS_PER_STAGE + MAX_STORAGE_TEXTURES_PER_STAGE + MAX_COMPUTE_WRITE_TEXTURES]; Uint32 dynamicOffsets[MAX_UNIFORM_BUFFERS_PER_STAGE]; + Uint32 writeCount = 0; Uint32 bufferInfoCount = 0; Uint32 imageInfoCount = 0; - Uint32 i; + Uint32 dynamicOffsetCount = 0; - resourceLayout = &commandBuffer->currentComputePipeline->resourceLayout; + if ( + !commandBuffer->needNewComputeReadOnlyDescriptorSet && + !commandBuffer->needNewComputeWriteOnlyDescriptorSet && + !commandBuffer->needNewComputeUniformDescriptorSet && + !commandBuffer->needNewComputeUniformOffsets + ) { + return; + } + + resourceLayout = commandBuffer->currentComputePipeline->resourceLayout; if (commandBuffer->needNewComputeReadOnlyDescriptorSet) { - descriptorSetPool = &resourceLayout->descriptorSetPools[0]; + descriptorSetLayout = resourceLayout->descriptorSetLayouts[0]; commandBuffer->computeReadOnlyDescriptorSet = VULKAN_INTERNAL_FetchDescriptorSet( renderer, commandBuffer, - descriptorSetPool); + descriptorSetLayout); - writeDescriptorSets = SDL_stack_alloc( - VkWriteDescriptorSet, - resourceLayout->numSamplers + - resourceLayout->numReadonlyStorageTextures + - resourceLayout->numReadonlyStorageBuffers); + for (Uint32 i = 0; i < resourceLayout->numSamplers; i += 1) { + VkWriteDescriptorSet *currentWriteDescriptorSet = &writeDescriptorSets[writeCount]; - for (i = 0; i < resourceLayout->numSamplers; i += 1) { - currentWriteDescriptorSet = &writeDescriptorSets[i]; currentWriteDescriptorSet->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; currentWriteDescriptorSet->pNext = NULL; currentWriteDescriptorSet->descriptorCount = 1; @@ -8078,11 +8073,13 @@ static void VULKAN_INTERNAL_BindComputeDescriptorSets( currentWriteDescriptorSet->pImageInfo = &imageInfos[imageInfoCount]; + writeCount += 1; imageInfoCount += 1; } - for (i = 0; i < resourceLayout->numReadonlyStorageTextures; i += 1) { - currentWriteDescriptorSet = &writeDescriptorSets[i]; + for (Uint32 i = 0; i < resourceLayout->numReadonlyStorageTextures; i += 1) { + VkWriteDescriptorSet *currentWriteDescriptorSet = &writeDescriptorSets[writeCount]; + currentWriteDescriptorSet->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; currentWriteDescriptorSet->pNext = NULL; currentWriteDescriptorSet->descriptorCount = 1; @@ -8099,11 +8096,12 @@ static void VULKAN_INTERNAL_BindComputeDescriptorSets( currentWriteDescriptorSet->pImageInfo = &imageInfos[imageInfoCount]; + writeCount += 1; imageInfoCount += 1; } - for (i = 0; i < resourceLayout->numReadonlyStorageBuffers; i += 1) { - currentWriteDescriptorSet = &writeDescriptorSets[resourceLayout->numReadonlyStorageTextures + i]; + for (Uint32 i = 0; i < resourceLayout->numReadonlyStorageBuffers; i += 1) { + VkWriteDescriptorSet *currentWriteDescriptorSet = &writeDescriptorSets[writeCount]; currentWriteDescriptorSet->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; currentWriteDescriptorSet->pNext = NULL; @@ -8121,48 +8119,23 @@ static void VULKAN_INTERNAL_BindComputeDescriptorSets( currentWriteDescriptorSet->pBufferInfo = &bufferInfos[bufferInfoCount]; + writeCount += 1; bufferInfoCount += 1; } - renderer->vkUpdateDescriptorSets( - renderer->logicalDevice, - resourceLayout->numSamplers + resourceLayout->numReadonlyStorageTextures + resourceLayout->numReadonlyStorageBuffers, - writeDescriptorSets, - 0, - NULL); - - renderer->vkCmdBindDescriptorSets( - commandBuffer->commandBuffer, - VK_PIPELINE_BIND_POINT_COMPUTE, - resourceLayout->pipelineLayout, - 0, - 1, - &commandBuffer->computeReadOnlyDescriptorSet, - 0, - NULL); - - SDL_stack_free(writeDescriptorSets); - bufferInfoCount = 0; - imageInfoCount = 0; - commandBuffer->needNewComputeReadOnlyDescriptorSet = false; } if (commandBuffer->needNewComputeWriteOnlyDescriptorSet) { - descriptorSetPool = &resourceLayout->descriptorSetPools[1]; + descriptorSetLayout = resourceLayout->descriptorSetLayouts[1]; commandBuffer->computeWriteOnlyDescriptorSet = VULKAN_INTERNAL_FetchDescriptorSet( renderer, commandBuffer, - descriptorSetPool); + descriptorSetLayout); - writeDescriptorSets = SDL_stack_alloc( - VkWriteDescriptorSet, - resourceLayout->numWriteonlyStorageTextures + - resourceLayout->numWriteonlyStorageBuffers); - - for (i = 0; i < resourceLayout->numWriteonlyStorageTextures; i += 1) { - currentWriteDescriptorSet = &writeDescriptorSets[i]; + for (Uint32 i = 0; i < resourceLayout->numWriteonlyStorageTextures; i += 1) { + VkWriteDescriptorSet *currentWriteDescriptorSet = &writeDescriptorSets[writeCount]; currentWriteDescriptorSet->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; currentWriteDescriptorSet->pNext = NULL; @@ -8180,11 +8153,12 @@ static void VULKAN_INTERNAL_BindComputeDescriptorSets( currentWriteDescriptorSet->pImageInfo = &imageInfos[imageInfoCount]; + writeCount += 1; imageInfoCount += 1; } - for (i = 0; i < resourceLayout->numWriteonlyStorageBuffers; i += 1) { - currentWriteDescriptorSet = &writeDescriptorSets[resourceLayout->numWriteonlyStorageTextures + i]; + for (Uint32 i = 0; i < resourceLayout->numWriteonlyStorageBuffers; i += 1) { + VkWriteDescriptorSet *currentWriteDescriptorSet = &writeDescriptorSets[writeCount]; currentWriteDescriptorSet->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; currentWriteDescriptorSet->pNext = NULL; @@ -8202,47 +8176,24 @@ static void VULKAN_INTERNAL_BindComputeDescriptorSets( currentWriteDescriptorSet->pBufferInfo = &bufferInfos[bufferInfoCount]; + writeCount += 1; bufferInfoCount += 1; } - renderer->vkUpdateDescriptorSets( - renderer->logicalDevice, - resourceLayout->numWriteonlyStorageTextures + resourceLayout->numWriteonlyStorageBuffers, - writeDescriptorSets, - 0, - NULL); - - renderer->vkCmdBindDescriptorSets( - commandBuffer->commandBuffer, - VK_PIPELINE_BIND_POINT_COMPUTE, - resourceLayout->pipelineLayout, - 1, - 1, - &commandBuffer->computeWriteOnlyDescriptorSet, - 0, - NULL); - - SDL_stack_free(writeDescriptorSets); - bufferInfoCount = 0; - imageInfoCount = 0; - commandBuffer->needNewComputeWriteOnlyDescriptorSet = false; } if (commandBuffer->needNewComputeUniformDescriptorSet) { - descriptorSetPool = &resourceLayout->descriptorSetPools[2]; + descriptorSetLayout = resourceLayout->descriptorSetLayouts[2]; commandBuffer->computeUniformDescriptorSet = VULKAN_INTERNAL_FetchDescriptorSet( renderer, commandBuffer, - descriptorSetPool); + descriptorSetLayout); - writeDescriptorSets = SDL_stack_alloc( - VkWriteDescriptorSet, - resourceLayout->numUniformBuffers); - for (i = 0; i < resourceLayout->numUniformBuffers; i += 1) { - currentWriteDescriptorSet = &writeDescriptorSets[i]; + for (Uint32 i = 0; i < resourceLayout->numUniformBuffers; i += 1) { + VkWriteDescriptorSet *currentWriteDescriptorSet = &writeDescriptorSets[writeCount]; currentWriteDescriptorSet->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; currentWriteDescriptorSet->pNext = NULL; @@ -8260,41 +8211,41 @@ static void VULKAN_INTERNAL_BindComputeDescriptorSets( currentWriteDescriptorSet->pBufferInfo = &bufferInfos[bufferInfoCount]; + writeCount += 1; bufferInfoCount += 1; } - renderer->vkUpdateDescriptorSets( - renderer->logicalDevice, - resourceLayout->numUniformBuffers, - writeDescriptorSets, - 0, - NULL); - - SDL_stack_free(writeDescriptorSets); - bufferInfoCount = 0; - imageInfoCount = 0; - commandBuffer->needNewComputeUniformDescriptorSet = false; - commandBuffer->needNewComputeUniformOffsets = true; } - if (commandBuffer->needNewComputeUniformOffsets) { - for (i = 0; i < resourceLayout->numUniformBuffers; i += 1) { - dynamicOffsets[i] = commandBuffer->computeUniformBuffers[i]->drawOffset; - } - - renderer->vkCmdBindDescriptorSets( - commandBuffer->commandBuffer, - VK_PIPELINE_BIND_POINT_COMPUTE, - resourceLayout->pipelineLayout, - 2, - 1, - &commandBuffer->computeUniformDescriptorSet, - resourceLayout->numUniformBuffers, - dynamicOffsets); - - commandBuffer->needNewComputeUniformOffsets = false; + for (Uint32 i = 0; i < resourceLayout->numUniformBuffers; i += 1) { + dynamicOffsets[i] = commandBuffer->computeUniformBuffers[i]->drawOffset; + dynamicOffsetCount += 1; } + + renderer->vkUpdateDescriptorSets( + renderer->logicalDevice, + writeCount, + writeDescriptorSets, + 0, + NULL); + + VkDescriptorSet sets[3]; + sets[0] = commandBuffer->computeReadOnlyDescriptorSet; + sets[1] = commandBuffer->computeWriteOnlyDescriptorSet; + sets[2] = commandBuffer->computeUniformDescriptorSet; + + renderer->vkCmdBindDescriptorSets( + commandBuffer->commandBuffer, + VK_PIPELINE_BIND_POINT_COMPUTE, + resourceLayout->pipelineLayout, + 0, + 3, + sets, + dynamicOffsetCount, + dynamicOffsets); + + commandBuffer->needNewVertexUniformOffsets = false; } static void VULKAN_DispatchCompute( @@ -9039,13 +8990,6 @@ static void VULKAN_INTERNAL_AllocateCommandBuffers( commandBuffer->signalSemaphores = SDL_malloc( commandBuffer->signalSemaphoreCapacity * sizeof(VkSemaphore)); - // Descriptor set tracking - - commandBuffer->boundDescriptorSetDataCapacity = 16; - commandBuffer->boundDescriptorSetDataCount = 0; - commandBuffer->boundDescriptorSetDatas = SDL_malloc( - commandBuffer->boundDescriptorSetDataCapacity * sizeof(DescriptorSetData)); - // Resource bind tracking commandBuffer->needNewVertexResourceDescriptorSet = true; @@ -9215,6 +9159,8 @@ static SDL_GPUCommandBuffer *VULKAN_AcquireCommandBuffer( VulkanCommandBuffer *commandBuffer = VULKAN_INTERNAL_GetInactiveCommandBufferFromPool(renderer, threadID); + commandBuffer->descriptorSetCache = VULKAN_INTERNAL_AcquireDescriptorSetCache(renderer); + SDL_UnlockMutex(renderer->acquireCommandBufferLock); if (commandBuffer == NULL) { @@ -9933,9 +9879,6 @@ static void VULKAN_INTERNAL_CleanCommandBuffer( VulkanRenderer *renderer, VulkanCommandBuffer *commandBuffer) { - Uint32 i; - DescriptorSetData *descriptorSetData; - if (commandBuffer->autoReleaseFence) { VULKAN_ReleaseFence( (SDL_GPURenderer *)renderer, @@ -9944,33 +9887,11 @@ static void VULKAN_INTERNAL_CleanCommandBuffer( commandBuffer->inFlightFence = NULL; } - // Bound descriptor sets are now available - - for (i = 0; i < commandBuffer->boundDescriptorSetDataCount; i += 1) { - descriptorSetData = &commandBuffer->boundDescriptorSetDatas[i]; - - SDL_TryLockSpinlock(&descriptorSetData->descriptorSetPool->lock); - - if (descriptorSetData->descriptorSetPool->inactiveDescriptorSetCount == descriptorSetData->descriptorSetPool->inactiveDescriptorSetCapacity) { - descriptorSetData->descriptorSetPool->inactiveDescriptorSetCapacity *= 2; - descriptorSetData->descriptorSetPool->inactiveDescriptorSets = SDL_realloc( - descriptorSetData->descriptorSetPool->inactiveDescriptorSets, - descriptorSetData->descriptorSetPool->inactiveDescriptorSetCapacity * sizeof(VkDescriptorSet)); - } - - descriptorSetData->descriptorSetPool->inactiveDescriptorSets[descriptorSetData->descriptorSetPool->inactiveDescriptorSetCount] = descriptorSetData->descriptorSet; - descriptorSetData->descriptorSetPool->inactiveDescriptorSetCount += 1; - - SDL_UnlockSpinlock(&descriptorSetData->descriptorSetPool->lock); - } - - commandBuffer->boundDescriptorSetDataCount = 0; - // Uniform buffers are now available SDL_LockMutex(renderer->acquireUniformBufferLock); - for (i = 0; i < commandBuffer->usedUniformBufferCount; i += 1) { + for (Sint32 i = 0; i < commandBuffer->usedUniformBufferCount; i += 1) { VULKAN_INTERNAL_ReturnUniformBufferToPool( renderer, commandBuffer->usedUniformBuffers[i]); @@ -9981,32 +9902,32 @@ static void VULKAN_INTERNAL_CleanCommandBuffer( // Decrement reference counts - for (i = 0; i < commandBuffer->usedBufferCount; i += 1) { + for (Sint32 i = 0; i < commandBuffer->usedBufferCount; i += 1) { (void)SDL_AtomicDecRef(&commandBuffer->usedBuffers[i]->referenceCount); } commandBuffer->usedBufferCount = 0; - for (i = 0; i < commandBuffer->usedTextureCount; i += 1) { + for (Sint32 i = 0; i < commandBuffer->usedTextureCount; i += 1) { (void)SDL_AtomicDecRef(&commandBuffer->usedTextures[i]->referenceCount); } commandBuffer->usedTextureCount = 0; - for (i = 0; i < commandBuffer->usedSamplerCount; i += 1) { + for (Sint32 i = 0; i < commandBuffer->usedSamplerCount; i += 1) { (void)SDL_AtomicDecRef(&commandBuffer->usedSamplers[i]->referenceCount); } commandBuffer->usedSamplerCount = 0; - for (i = 0; i < commandBuffer->usedGraphicsPipelineCount; i += 1) { + for (Sint32 i = 0; i < commandBuffer->usedGraphicsPipelineCount; i += 1) { (void)SDL_AtomicDecRef(&commandBuffer->usedGraphicsPipelines[i]->referenceCount); } commandBuffer->usedGraphicsPipelineCount = 0; - for (i = 0; i < commandBuffer->usedComputePipelineCount; i += 1) { + for (Sint32 i = 0; i < commandBuffer->usedComputePipelineCount; i += 1) { (void)SDL_AtomicDecRef(&commandBuffer->usedComputePipelines[i]->referenceCount); } commandBuffer->usedComputePipelineCount = 0; - for (i = 0; i < commandBuffer->usedFramebufferCount; i += 1) { + for (Sint32 i = 0; i < commandBuffer->usedFramebufferCount; i += 1) { (void)SDL_AtomicDecRef(&commandBuffer->usedFramebuffers[i]->referenceCount); } commandBuffer->usedFramebufferCount = 0; @@ -10037,10 +9958,18 @@ static void VULKAN_INTERNAL_CleanCommandBuffer( commandBuffer->commandPool->inactiveCommandBuffers[commandBuffer->commandPool->inactiveCommandBufferCount] = commandBuffer; commandBuffer->commandPool->inactiveCommandBufferCount += 1; + // Release descriptor set cache + + VULKAN_INTERNAL_ReturnDescriptorSetCacheToPool( + renderer, + commandBuffer->descriptorSetCache); + + commandBuffer->descriptorSetCache = NULL; + SDL_UnlockMutex(renderer->acquireCommandBufferLock); // Remove this command buffer from the submitted list - for (i = 0; i < renderer->submittedCommandBufferCount; i += 1) { + for (Uint32 i = 0; i < renderer->submittedCommandBufferCount; i += 1) { if (renderer->submittedCommandBuffers[i] == commandBuffer) { renderer->submittedCommandBuffers[i] = renderer->submittedCommandBuffers[renderer->submittedCommandBufferCount - 1]; renderer->submittedCommandBufferCount -= 1; @@ -11397,6 +11326,12 @@ static SDL_GPUDevice *VULKAN_CreateDevice(bool debugMode, bool preferLowPower, S UNIFORM_BUFFER_SIZE); } + renderer->descriptorSetCachePoolCapacity = 8; + renderer->descriptorSetCachePoolCount = 0; + renderer->descriptorSetCachePool = SDL_calloc(renderer->descriptorSetCachePoolCapacity, sizeof(DescriptorSetCache *)); + + SDL_SetAtomicInt(&renderer->layoutResourceID, 0); + // Device limits renderer->minUBOAlignment = (Uint32)renderer->physicalDeviceProperties.properties.limits.minUniformBufferOffsetAlignment; @@ -11427,6 +11362,30 @@ static SDL_GPUDevice *VULKAN_CreateDevice(bool debugMode, bool preferLowPower, S VULKAN_INTERNAL_FramebufferHashNuke, false); + renderer->graphicsPipelineResourceLayoutHashTable = SDL_CreateHashTable( + (void *)renderer, + 64, + VULKAN_INTERNAL_GraphicsPipelineResourceLayoutHashFunction, + VULKAN_INTERNAL_GraphicsPipelineResourceLayoutHashKeyMatch, + VULKAN_INTERNAL_GraphicsPipelineResourceLayoutHashNuke, + false); + + renderer->computePipelineResourceLayoutHashTable = SDL_CreateHashTable( + (void *)renderer, + 64, + VULKAN_INTERNAL_ComputePipelineResourceLayoutHashFunction, + VULKAN_INTERNAL_ComputePipelineResourceLayoutHashKeyMatch, + VULKAN_INTERNAL_ComputePipelineResourceLayoutHashNuke, + false); + + renderer->descriptorSetLayoutHashTable = SDL_CreateHashTable( + (void *)renderer, + 64, + VULKAN_INTERNAL_DescriptorSetLayoutHashFunction, + VULKAN_INTERNAL_DescriptorSetLayoutHashKeyMatch, + VULKAN_INTERNAL_DescriptorSetLayoutHashNuke, + false); + // Initialize fence pool renderer->fencePool.lock = SDL_CreateMutex();