diff --git a/include/Refresh.h b/include/Refresh.h index 27c61b0..f046988 100644 --- a/include/Refresh.h +++ b/include/Refresh.h @@ -553,17 +553,18 @@ typedef struct Refresh_ComputePipelineCreateInfo Refresh_ComputePipelineLayoutCreateInfo pipelineLayoutCreateInfo; } Refresh_ComputePipelineCreateInfo; -typedef struct Refresh_AttachmentDescription +typedef struct Refresh_ColorAttachmentDescription { Refresh_TextureFormat format; Refresh_SampleCount sampleCount; -} Refresh_AttachmentDescription; +} Refresh_ColorAttachmentDescription; typedef struct Refresh_GraphicsPipelineAttachmentInfo { - Refresh_AttachmentDescription colorAttachmentDescriptions[4]; + Refresh_ColorAttachmentDescription colorAttachmentDescriptions[4]; uint32_t colorAttachmentCount; - Refresh_AttachmentDescription *depthStencilAttachmentDescription; /* Can be NULL */ + uint8_t hasDepthStencilAttachment; + Refresh_TextureFormat depthStencilFormat; } Refresh_GraphicsPipelineAttachmentInfo; typedef struct Refresh_GraphicsPipelineCreateInfo @@ -1113,7 +1114,7 @@ REFRESHAPI void Refresh_QueueDestroyGraphicsPipeline( * The area affected by the render pass. * All load, store and resolve operations are restricted * to the given rectangle. - * pColorAttachmentInfos: + * colorAttachmentInfos: * A pointer to an array of Refresh_ColorAttachmentInfo structures * that contains render targets and clear values. May be NULL. * colorAttachmentCount: The amount of structs in the above array. @@ -1123,7 +1124,7 @@ REFRESHAPI void Refresh_BeginRenderPass( Refresh_Device *device, Refresh_CommandBuffer *commandBuffer, Refresh_Rect *renderArea, - Refresh_ColorAttachmentInfo *pColorAttachmentInfos, + Refresh_ColorAttachmentInfo *colorAttachmentInfos, uint32_t colorAttachmentCount, Refresh_DepthStencilAttachmentInfo *depthStencilAttachmentInfo ); diff --git a/src/Refresh.c b/src/Refresh.c index 3c68cb7..7936df7 100644 --- a/src/Refresh.c +++ b/src/Refresh.c @@ -613,7 +613,7 @@ void Refresh_BeginRenderPass( Refresh_Device *device, Refresh_CommandBuffer *commandBuffer, Refresh_Rect *renderArea, - Refresh_ColorAttachmentInfo *pColorAttachmentInfos, + Refresh_ColorAttachmentInfo *colorAttachmentInfos, uint32_t colorAttachmentCount, Refresh_DepthStencilAttachmentInfo *depthStencilAttachmentInfo ) { @@ -622,7 +622,7 @@ void Refresh_BeginRenderPass( device->driverData, commandBuffer, renderArea, - pColorAttachmentInfos, + colorAttachmentInfos, colorAttachmentCount, depthStencilAttachmentInfo ); diff --git a/src/Refresh_Driver.h b/src/Refresh_Driver.h index 438ec11..fb917e3 100644 --- a/src/Refresh_Driver.h +++ b/src/Refresh_Driver.h @@ -397,7 +397,7 @@ struct Refresh_Device Refresh_Renderer *driverData, Refresh_CommandBuffer *commandBuffer, Refresh_Rect *renderArea, - Refresh_ColorAttachmentInfo *pColorAttachmentInfos, + Refresh_ColorAttachmentInfo *colorAttachmentInfos, uint32_t colorAttachmentCount, Refresh_DepthStencilAttachmentInfo *depthStencilAttachmentInfo ); diff --git a/src/Refresh_Driver_Template.txt b/src/Refresh_Driver_Template.txt index 6f71659..0a01725 100644 --- a/src/Refresh_Driver_Template.txt +++ b/src/Refresh_Driver_Template.txt @@ -553,7 +553,7 @@ static void TEMPLATE_BeginRenderPass( Refresh_Renderer *driverData, Refresh_CommandBuffer *commandBuffer, Refresh_Rect *renderArea, - Refresh_ColorAttachmentInfo *pColorAttachmentInfos, + Refresh_ColorAttachmentInfo *colorAttachmentInfos, uint32_t colorAttachmentCount, Refresh_DepthStencilAttachmentInfo *depthStencilAttachmentInfo ) { diff --git a/src/Refresh_Driver_Vulkan.c b/src/Refresh_Driver_Vulkan.c index 51e61c9..08124ee 100644 --- a/src/Refresh_Driver_Vulkan.c +++ b/src/Refresh_Driver_Vulkan.c @@ -998,11 +998,11 @@ static inline VkRenderPass RenderPassHashArray_Fetch( RenderPassHashArray *arr, RenderPassHash *key ) { - int32_t i, j; + int32_t i; for (i = 0; i < arr->count; i += 1) { - const RenderPassHash *e = &arr->elements[i].key; + RenderPassHash *e = &arr->elements[i].key; if (RenderPassHash_Compare(e, key)) { @@ -1029,6 +1029,116 @@ static inline void RenderPassHashArray_Insert( arr->count += 1; } +typedef struct FramebufferHash +{ + VkImageView colorAttachmentViews[MAX_COLOR_TARGET_BINDINGS]; + VkImageView colorMultiSampleAttachmentViews[MAX_COLOR_TARGET_BINDINGS]; + uint32_t colorAttachmentCount; + VkImageView depthStencilAttachmentView; + uint32_t width; + uint32_t height; +} FramebufferHash; + +typedef struct FramebufferHashMap +{ + FramebufferHash key; + VkFramebuffer value; +} FramebufferHashMap; + +typedef struct FramebufferHashArray +{ + FramebufferHashMap *elements; + int32_t count; + int32_t capacity; +} FramebufferHashArray; + +static inline uint8_t FramebufferHash_Compare( + FramebufferHash *a, + FramebufferHash *b +) { + uint32_t i; + + if (a->colorAttachmentCount != b->colorAttachmentCount) + { + return 0; + } + + for (i = 0; i < a->colorAttachmentCount; i += 1) + { + if (a->colorAttachmentViews[i] != b->colorAttachmentViews[i]) + { + return 0; + } + + if (a->colorMultiSampleAttachmentViews[i] != b->colorMultiSampleAttachmentViews[i]) + { + return 0; + } + } + + if (a->depthStencilAttachmentView != b->depthStencilAttachmentView) + { + return 0; + } + + if (a->width != b->width) + { + return 0; + } + + if (a->height != b->height) + { + return 0; + } + + return 1; +} + +static inline VkFramebuffer FramebufferHashArray_Fetch( + FramebufferHashArray *arr, + FramebufferHash *key +) { + int32_t i; + + for (i = 0; i < arr->count; i += 1) + { + FramebufferHash *e = &arr->elements[i].key; + if (FramebufferHash_Compare(e, key)) + { + return arr->elements[i].value; + } + } + + return VK_NULL_HANDLE; +} + +static inline void FramebufferHashArray_Insert( + FramebufferHashArray *arr, + FramebufferHash key, + VkFramebuffer value +) { + FramebufferHashMap map; + map.key = key; + map.value = value; + + EXPAND_ELEMENTS_IF_NEEDED(arr, 4, FramebufferHashMap) + + arr->elements[arr->count] = map; + arr->count += 1; +} + +static inline void FramebufferHashArray_Remove( + FramebufferHashArray *arr, + uint32_t index +) { + if (index != arr->count - 1) + { + arr->elements[index] = arr->elements[arr->count - 1]; + } + + arr->count -= 1; +} + /* Descriptor Set Caches */ struct DescriptorSetCache @@ -1424,6 +1534,7 @@ typedef struct VulkanRenderer GraphicsPipelineLayoutHashTable graphicsPipelineLayoutHashTable; ComputePipelineLayoutHashTable computePipelineLayoutHashTable; RenderPassHashArray renderPassHashArray; + FramebufferHashArray framebufferHashArray; VkDescriptorPool defaultDescriptorPool; @@ -1454,6 +1565,8 @@ typedef struct VulkanRenderer SDL_mutex *submitLock; SDL_mutex *acquireFenceLock; SDL_mutex *acquireCommandBufferLock; + SDL_mutex *renderPassFetchLock; + SDL_mutex *framebufferFetchLock; #define VULKAN_INSTANCE_FUNCTION(ext, ret, func, params) \ vkfntype_##func func; @@ -2419,11 +2532,43 @@ static void VULKAN_INTERNAL_DestroyTexture( static void VULKAN_INTERNAL_DestroyRenderTarget( VulkanRenderer *renderer, - VulkanRenderTarget *renderTargetTarget + VulkanRenderTarget *renderTarget ) { + int32_t i, j; + FramebufferHash *hash; + + SDL_LockMutex(renderer->framebufferFetchLock); + + /* Remove all associated framebuffers */ + for (i = renderer->framebufferHashArray.count; i >= 0; i -= 1) + { + hash = &renderer->framebufferHashArray.elements[i].key; + + for (j = 0; j < hash->colorAttachmentCount; j += 1) + { + if (hash->colorAttachmentViews[i] == renderTarget->view) + { + renderer->vkDestroyFramebuffer( + renderer->logicalDevice, + renderer->framebufferHashArray.elements[i].value, + NULL + ); + + FramebufferHashArray_Remove( + &renderer->framebufferHashArray, + i + ); + + break; + } + } + } + + SDL_UnlockMutex(renderer->framebufferFetchLock); + renderer->vkDestroyImageView( renderer->logicalDevice, - renderTargetTarget->view, + renderTarget->view, NULL ); @@ -2431,15 +2576,15 @@ static void VULKAN_INTERNAL_DestroyRenderTarget( * so we don't free it here * But the multisampleTexture is! */ - if (renderTargetTarget->multisampleTexture != NULL) + if (renderTarget->multisampleTexture != NULL) { VULKAN_INTERNAL_DestroyTexture( renderer, - renderTargetTarget->multisampleTexture + renderTarget->multisampleTexture ); } - SDL_free(renderTargetTarget); + SDL_free(renderTarget); } static void VULKAN_INTERNAL_DestroyBuffer( @@ -2563,17 +2708,6 @@ static void VULKAN_INTERNAL_DestroySampler( ); } -static void VULKAN_INTERNAL_DestroyRenderPass( - VulkanRenderer *renderer, - VkRenderPass renderPass -) { - renderer->vkDestroyRenderPass( - renderer->logicalDevice, - renderPass, - NULL - ); -} - static void VULKAN_INTERNAL_DestroySwapchain( VulkanRenderer* renderer, void *windowHandle @@ -4286,6 +4420,8 @@ static void VULKAN_DestroyDevice( SDL_DestroyMutex(renderer->submitLock); SDL_DestroyMutex(renderer->acquireFenceLock); SDL_DestroyMutex(renderer->acquireCommandBufferLock); + SDL_DestroyMutex(renderer->renderPassFetchLock); + SDL_DestroyMutex(renderer->framebufferFetchLock); renderer->vkDestroyDevice(renderer->logicalDevice, NULL); renderer->vkDestroyInstance(renderer->instance, NULL); @@ -4531,9 +4667,7 @@ static void VULKAN_DispatchCompute( VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer*) commandBuffer; VulkanComputePipeline *computePipeline = vulkanCommandBuffer->currentComputePipeline; - VulkanBuffer *currentBuffer; VkDescriptorSet descriptorSets[3]; - uint32_t i; descriptorSets[0] = vulkanCommandBuffer->bufferDescriptorSet; descriptorSets[1] = vulkanCommandBuffer->imageDescriptorSet; @@ -4560,7 +4694,7 @@ static void VULKAN_DispatchCompute( static VkRenderPass VULKAN_INTERNAL_CreateRenderPass( VulkanRenderer *renderer, - Refresh_ColorAttachmentInfo *pColorAttachmentInfos, + Refresh_ColorAttachmentInfo *colorAttachmentInfos, uint32_t colorAttachmentCount, Refresh_DepthStencilAttachmentInfo *depthStencilAttachmentInfo ) { @@ -4569,7 +4703,7 @@ static VkRenderPass VULKAN_INTERNAL_CreateRenderPass( VkAttachmentReference colorAttachmentReferences[MAX_COLOR_TARGET_BINDINGS]; VkAttachmentReference resolveReferences[MAX_COLOR_TARGET_BINDINGS + 1]; VkAttachmentReference depthStencilAttachmentReference; - VkRenderPassCreateInfo vkRenderPassCreateInfo; + VkRenderPassCreateInfo renderPassCreateInfo; VkSubpassDescription subpass; VkRenderPass renderPass; uint32_t i; @@ -4584,7 +4718,7 @@ static VkRenderPass VULKAN_INTERNAL_CreateRenderPass( for (i = 0; i < colorAttachmentCount; i += 1) { - colorTarget = (VulkanRenderTarget*) pColorAttachmentInfos[attachmentDescriptionCount].pRenderTarget; + colorTarget = (VulkanRenderTarget*) colorAttachmentInfos[attachmentDescriptionCount].pRenderTarget; if (colorTarget->multisampleCount > VK_SAMPLE_COUNT_1_BIT) { @@ -4597,10 +4731,10 @@ static VkRenderPass VULKAN_INTERNAL_CreateRenderPass( attachmentDescriptions[attachmentDescriptionCount].samples = VK_SAMPLE_COUNT_1_BIT; attachmentDescriptions[attachmentDescriptionCount].loadOp = RefreshToVK_LoadOp[ - pColorAttachmentInfos[i].loadOp + colorAttachmentInfos[i].loadOp ]; attachmentDescriptions[attachmentDescriptionCount].storeOp = RefreshToVK_StoreOp[ - pColorAttachmentInfos[i].storeOp + colorAttachmentInfos[i].storeOp ]; attachmentDescriptions[attachmentDescriptionCount].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; @@ -4623,10 +4757,10 @@ static VkRenderPass VULKAN_INTERNAL_CreateRenderPass( attachmentDescriptions[attachmentDescriptionCount].format = colorTarget->texture->format; attachmentDescriptions[attachmentDescriptionCount].samples = colorTarget->multisampleCount; attachmentDescriptions[attachmentDescriptionCount].loadOp = RefreshToVK_LoadOp[ - pColorAttachmentInfos[i].loadOp + colorAttachmentInfos[i].loadOp ]; attachmentDescriptions[attachmentDescriptionCount].storeOp = RefreshToVK_StoreOp[ - pColorAttachmentInfos[i].storeOp + colorAttachmentInfos[i].storeOp ]; attachmentDescriptions[attachmentDescriptionCount].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; @@ -4652,10 +4786,10 @@ static VkRenderPass VULKAN_INTERNAL_CreateRenderPass( attachmentDescriptions[attachmentDescriptionCount].samples = VK_SAMPLE_COUNT_1_BIT; attachmentDescriptions[attachmentDescriptionCount].loadOp = RefreshToVK_LoadOp[ - pColorAttachmentInfos[i].loadOp + colorAttachmentInfos[i].loadOp ]; attachmentDescriptions[attachmentDescriptionCount].storeOp = RefreshToVK_StoreOp[ - pColorAttachmentInfos[i].storeOp + colorAttachmentInfos[i].storeOp ]; attachmentDescriptions[attachmentDescriptionCount].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; @@ -4666,12 +4800,12 @@ static VkRenderPass VULKAN_INTERNAL_CreateRenderPass( attachmentDescriptions[attachmentDescriptionCount].finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - attachmentDescriptionCount += 1; - colorAttachmentReferences[colorAttachmentReferenceCount].attachment = i; + colorAttachmentReferences[colorAttachmentReferenceCount].attachment = attachmentDescriptionCount; colorAttachmentReferences[colorAttachmentReferenceCount].layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + attachmentDescriptionCount += 1; colorAttachmentReferenceCount += 1; } } @@ -4733,32 +4867,207 @@ static VkRenderPass VULKAN_INTERNAL_CreateRenderPass( subpass.pResolveAttachments = NULL; } - vkRenderPassCreateInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; - vkRenderPassCreateInfo.pNext = NULL; - vkRenderPassCreateInfo.flags = 0; - vkRenderPassCreateInfo.pAttachments = attachmentDescriptions; - vkRenderPassCreateInfo.attachmentCount = attachmentDescriptionCount; - vkRenderPassCreateInfo.subpassCount = 1; - vkRenderPassCreateInfo.pSubpasses = &subpass; - vkRenderPassCreateInfo.dependencyCount = 0; - vkRenderPassCreateInfo.pDependencies = NULL; + renderPassCreateInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; + renderPassCreateInfo.pNext = NULL; + renderPassCreateInfo.flags = 0; + renderPassCreateInfo.pAttachments = attachmentDescriptions; + renderPassCreateInfo.attachmentCount = attachmentDescriptionCount; + renderPassCreateInfo.subpassCount = 1; + renderPassCreateInfo.pSubpasses = &subpass; + renderPassCreateInfo.dependencyCount = 0; + renderPassCreateInfo.pDependencies = NULL; vulkanResult = renderer->vkCreateRenderPass( renderer->logicalDevice, - &vkRenderPassCreateInfo, + &renderPassCreateInfo, NULL, &renderPass ); if (vulkanResult != VK_SUCCESS) { + renderPass = VK_NULL_HANDLE; LogVulkanResultAsError("vkCreateRenderPass", vulkanResult); - return VK_NULL_HANDLE; } return renderPass; } +static VkRenderPass VULKAN_INTERNAL_CreateTransientRenderPass( + VulkanRenderer *renderer, + Refresh_GraphicsPipelineAttachmentInfo attachmentInfo +) { + VkAttachmentDescription attachmentDescriptions[2 * MAX_COLOR_TARGET_BINDINGS + 1]; + VkAttachmentReference colorAttachmentReferences[MAX_COLOR_TARGET_BINDINGS]; + VkAttachmentReference resolveReferences[MAX_COLOR_TARGET_BINDINGS + 1]; + VkAttachmentReference depthStencilAttachmentReference; + Refresh_ColorAttachmentDescription attachmentDescription; + VkSubpassDescription subpass; + VkRenderPassCreateInfo renderPassCreateInfo; + VkRenderPass renderPass; + VkResult result; + + uint32_t multisampling = 0; + uint32_t attachmentDescriptionCount = 0; + uint32_t colorAttachmentReferenceCount = 0; + uint32_t resolveReferenceCount = 0; + uint32_t i; + + for (i = 0; i < attachmentInfo.colorAttachmentCount; i += 1) + { + attachmentDescription = attachmentInfo.colorAttachmentDescriptions[i]; + + if (attachmentDescription.sampleCount > REFRESH_SAMPLECOUNT_1) + { + multisampling = 1; + + /* Resolve attachment and multisample attachment */ + + attachmentDescriptions[attachmentDescriptionCount].flags = 0; + attachmentDescriptions[attachmentDescriptionCount].format = RefreshToVK_SurfaceFormat[ + attachmentDescription.format + ]; + attachmentDescriptions[attachmentDescriptionCount].samples = VK_SAMPLE_COUNT_1_BIT; + attachmentDescriptions[attachmentDescriptionCount].loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + attachmentDescriptions[attachmentDescriptionCount].storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + attachmentDescriptions[attachmentDescriptionCount].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + attachmentDescriptions[attachmentDescriptionCount].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + attachmentDescriptions[attachmentDescriptionCount].initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + attachmentDescriptions[attachmentDescriptionCount].finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + + resolveReferences[resolveReferenceCount].attachment = attachmentDescriptionCount; + resolveReferences[resolveReferenceCount].layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + + attachmentDescriptionCount += 1; + resolveReferenceCount += 1; + + attachmentDescriptions[attachmentDescriptionCount].flags = 0; + attachmentDescriptions[attachmentDescriptionCount].format = RefreshToVK_SurfaceFormat[ + attachmentDescription.format + ]; + attachmentDescriptions[attachmentDescriptionCount].samples = VK_SAMPLE_COUNT_1_BIT; + attachmentDescriptions[attachmentDescriptionCount].loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + attachmentDescriptions[attachmentDescriptionCount].storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + attachmentDescriptions[attachmentDescriptionCount].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + attachmentDescriptions[attachmentDescriptionCount].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + attachmentDescriptions[attachmentDescriptionCount].initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + attachmentDescriptions[attachmentDescriptionCount].finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + + colorAttachmentReferences[colorAttachmentReferenceCount].attachment = + attachmentDescriptionCount; + colorAttachmentReferences[colorAttachmentReferenceCount].layout = + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + + attachmentDescriptionCount += 1; + colorAttachmentReferenceCount += 1; + } + else + { + attachmentDescriptions[attachmentDescriptionCount].flags = 0; + attachmentDescriptions[attachmentDescriptionCount].format = RefreshToVK_SurfaceFormat[ + attachmentDescription.format + ]; + attachmentDescriptions[attachmentDescriptionCount].samples = + VK_SAMPLE_COUNT_1_BIT; + attachmentDescriptions[attachmentDescriptionCount].loadOp = + VK_ATTACHMENT_LOAD_OP_DONT_CARE; + attachmentDescriptions[attachmentDescriptionCount].storeOp = + VK_ATTACHMENT_STORE_OP_DONT_CARE; + attachmentDescriptions[attachmentDescriptionCount].stencilLoadOp = + VK_ATTACHMENT_LOAD_OP_DONT_CARE; + attachmentDescriptions[attachmentDescriptionCount].stencilStoreOp = + VK_ATTACHMENT_STORE_OP_DONT_CARE; + attachmentDescriptions[attachmentDescriptionCount].initialLayout = + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + attachmentDescriptions[attachmentDescriptionCount].finalLayout = + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + + + colorAttachmentReferences[colorAttachmentReferenceCount].attachment = attachmentDescriptionCount; + colorAttachmentReferences[colorAttachmentReferenceCount].layout = + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + + attachmentDescriptionCount += 1; + colorAttachmentReferenceCount += 1; + } + } + + subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; + subpass.flags = 0; + subpass.inputAttachmentCount = 0; + subpass.pInputAttachments = NULL; + subpass.colorAttachmentCount = attachmentInfo.colorAttachmentCount; + subpass.pColorAttachments = colorAttachmentReferences; + subpass.preserveAttachmentCount = 0; + subpass.pPreserveAttachments = NULL; + + if (attachmentInfo.hasDepthStencilAttachment) + { + attachmentDescriptions[attachmentDescriptionCount].flags = 0; + attachmentDescriptions[attachmentDescriptionCount].format = RefreshToVK_SurfaceFormat[ + attachmentInfo.depthStencilFormat + ]; + attachmentDescriptions[attachmentDescriptionCount].samples = + VK_SAMPLE_COUNT_1_BIT; /* FIXME: do these take multisamples? */ + attachmentDescriptions[attachmentDescriptionCount].loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + attachmentDescriptions[attachmentDescriptionCount].storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + attachmentDescriptions[attachmentDescriptionCount].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + attachmentDescriptions[attachmentDescriptionCount].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + attachmentDescriptions[attachmentDescriptionCount].initialLayout = + VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + attachmentDescriptions[attachmentDescriptionCount].finalLayout = + VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + + depthStencilAttachmentReference.attachment = + attachmentDescriptionCount; + depthStencilAttachmentReference.layout = + VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + + subpass.pDepthStencilAttachment = + &depthStencilAttachmentReference; + + attachmentDescriptionCount += 1; + } + else + { + subpass.pDepthStencilAttachment = NULL; + } + + if (multisampling) + { + subpass.pResolveAttachments = resolveReferences; + } + else + { + subpass.pResolveAttachments = NULL; + } + + renderPassCreateInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; + renderPassCreateInfo.pNext = NULL; + renderPassCreateInfo.flags = 0; + renderPassCreateInfo.pAttachments = attachmentDescriptions; + renderPassCreateInfo.attachmentCount = attachmentDescriptionCount; + renderPassCreateInfo.subpassCount = 1; + renderPassCreateInfo.pSubpasses = &subpass; + renderPassCreateInfo.dependencyCount = 0; + renderPassCreateInfo.pDependencies = NULL; + + result = renderer->vkCreateRenderPass( + renderer->logicalDevice, + &renderPassCreateInfo, + NULL, + &renderPass + ); + + if (result != VK_SUCCESS) + { + renderPass = VK_NULL_HANDLE; + LogVulkanResultAsError("vkCreateRenderPass", result); + } + + return renderPass; +} + static Refresh_GraphicsPipeline* VULKAN_CreateGraphicsPipeline( Refresh_Renderer *driverData, Refresh_GraphicsPipelineCreateInfo *pipelineCreateInfo @@ -4797,6 +5106,13 @@ static Refresh_GraphicsPipeline* VULKAN_CreateGraphicsPipeline( VulkanRenderer *renderer = (VulkanRenderer*) driverData; + /* Create a "compatible" render pass */ + + VkRenderPass transientRenderPass = VULKAN_INTERNAL_CreateTransientRenderPass( + renderer, + pipelineCreateInfo->attachmentInfo + ); + /* Shader stages */ shaderStageCreateInfos[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; @@ -5074,7 +5390,7 @@ static Refresh_GraphicsPipeline* VULKAN_CreateGraphicsPipeline( vkPipelineCreateInfo.pColorBlendState = &colorBlendStateCreateInfo; vkPipelineCreateInfo.pDynamicState = VK_NULL_HANDLE; vkPipelineCreateInfo.layout = graphicsPipeline->pipelineLayout->pipelineLayout; - vkPipelineCreateInfo.renderPass = (VkRenderPass) pipelineCreateInfo->renderPass; + vkPipelineCreateInfo.renderPass = transientRenderPass; vkPipelineCreateInfo.subpass = 0; vkPipelineCreateInfo.basePipelineHandle = VK_NULL_HANDLE; vkPipelineCreateInfo.basePipelineIndex = 0; @@ -5095,6 +5411,12 @@ static Refresh_GraphicsPipeline* VULKAN_CreateGraphicsPipeline( SDL_stack_free(scissors); SDL_stack_free(colorBlendAttachmentStates); + renderer->vkDestroyRenderPass( + renderer->logicalDevice, + transientRenderPass, + NULL + ); + if (vulkanResult != VK_SUCCESS) { LogVulkanResultAsError("vkCreateGraphicsPipelines", vulkanResult); @@ -5325,71 +5647,6 @@ static Refresh_Sampler* VULKAN_CreateSampler( return (Refresh_Sampler*) sampler; } -static VkFramebuffer VULKAN_INTERNAL_CreateFramebuffer( - Refresh_Renderer *driverData, - VkRenderPass renderPass, - uint32_t width, - uint32_t height, - VulkanRenderTarget **colorTargets, - uint32_t colorTargetCount, - VulkanRenderTarget *depthStencilTarget /* Can be NULL */ -) { - VkResult vulkanResult; - VkFramebuffer framebuffer; - VkFramebufferCreateInfo vkFramebufferCreateInfo; - - VkImageView *imageViews; - uint32_t colorAttachmentCount = colorTargetCount; - uint32_t attachmentCount = colorAttachmentCount; - uint32_t i; - - VulkanRenderer *renderer = (VulkanRenderer*) driverData; - - if (depthStencilTarget != NULL) - { - attachmentCount += 1; - } - - imageViews = SDL_stack_alloc(VkImageView, attachmentCount); - - for (i = 0; i < colorAttachmentCount; i += 1) - { - imageViews[i] = ((VulkanRenderTarget*)colorTargets[i])->view; - } - - if (depthStencilTarget != NULL) - { - imageViews[colorAttachmentCount] = ((VulkanRenderTarget*)depthStencilTarget)->view; - } - - vkFramebufferCreateInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; - vkFramebufferCreateInfo.pNext = NULL; - vkFramebufferCreateInfo.flags = 0; - vkFramebufferCreateInfo.renderPass = renderPass; - vkFramebufferCreateInfo.attachmentCount = attachmentCount; - vkFramebufferCreateInfo.pAttachments = imageViews; - vkFramebufferCreateInfo.width = width; - vkFramebufferCreateInfo.height = height; - vkFramebufferCreateInfo.layers = 1; - - vulkanResult = renderer->vkCreateFramebuffer( - renderer->logicalDevice, - &vkFramebufferCreateInfo, - NULL, - &framebuffer - ); - - SDL_stack_free(imageViews); - - if (vulkanResult != VK_SUCCESS) - { - LogVulkanResultAsError("vkCreateFramebuffer", vulkanResult); - return VK_NULL_HANDLE; - } - - return framebuffer; -} - static Refresh_ShaderModule* VULKAN_CreateShaderModule( Refresh_Renderer *driverData, Refresh_ShaderModuleCreateInfo *shaderModuleCreateInfo @@ -7072,7 +7329,7 @@ static void VULKAN_QueueDestroyGraphicsPipeline( static VkRenderPass VULKAN_INTERNAL_FetchRenderPass( VulkanRenderer *renderer, - Refresh_ColorAttachmentInfo *pColorAttachmentInfos, + Refresh_ColorAttachmentInfo *colorAttachmentInfos, uint32_t colorAttachmentCount, Refresh_DepthStencilAttachmentInfo *depthStencilAttachmentInfo ) { @@ -7080,11 +7337,13 @@ static VkRenderPass VULKAN_INTERNAL_FetchRenderPass( RenderPassHash hash; uint32_t i; + SDL_LockMutex(renderer->renderPassFetchLock); + for (i = 0; i < colorAttachmentCount; i += 1) { - hash.colorTargetDescriptions[i].clearColor = pColorAttachmentInfos[i].clearColor; - hash.colorTargetDescriptions[i].loadOp = pColorAttachmentInfos[i].loadOp; - hash.colorTargetDescriptions[i].storeOp = pColorAttachmentInfos[i].storeOp; + hash.colorTargetDescriptions[i].clearColor = colorAttachmentInfos[i].clearColor; + hash.colorTargetDescriptions[i].loadOp = colorAttachmentInfos[i].loadOp; + hash.colorTargetDescriptions[i].storeOp = colorAttachmentInfos[i].storeOp; } if (depthStencilAttachmentInfo == NULL) @@ -7109,30 +7368,170 @@ static VkRenderPass VULKAN_INTERNAL_FetchRenderPass( if (renderPass != VK_NULL_HANDLE) { + SDL_UnlockMutex(renderer->renderPassFetchLock); return renderPass; } renderPass = VULKAN_INTERNAL_CreateRenderPass( renderer, - pColorAttachmentInfos, + colorAttachmentInfos, colorAttachmentCount, depthStencilAttachmentInfo ); - RenderPassHashArray_Insert( - &renderer->renderPassHashArray, - hash, - renderPass + if (renderPass != VK_NULL_HANDLE) + { + RenderPassHashArray_Insert( + &renderer->renderPassHashArray, + hash, + renderPass + ); + } + + SDL_UnlockMutex(renderer->renderPassFetchLock); + return renderPass; +} + +static VkFramebuffer VULKAN_INTERNAL_FetchFramebuffer( + VulkanRenderer *renderer, + VkRenderPass renderPass, + Refresh_ColorAttachmentInfo *colorAttachmentInfos, + uint32_t colorAttachmentCount, + Refresh_DepthStencilAttachmentInfo *depthStencilAttachmentInfo +) { + VkFramebuffer framebuffer; + VkFramebufferCreateInfo framebufferInfo; + VkResult result; + VkImageView imageViewAttachments[2 * MAX_COLOR_TARGET_BINDINGS + 1]; + FramebufferHash hash; + VulkanRenderTarget *renderTarget; + uint32_t attachmentCount = 0; + uint32_t i; + + SDL_LockMutex(renderer->framebufferFetchLock); + + for (i = 0; i < MAX_COLOR_TARGET_BINDINGS; i += 1) + { + hash.colorAttachmentViews[i] = VK_NULL_HANDLE; + hash.colorMultiSampleAttachmentViews[i] = VK_NULL_HANDLE; + } + + hash.colorAttachmentCount = colorAttachmentCount; + + for (i = 0; i < colorAttachmentCount; i += 1) + { + renderTarget = (VulkanRenderTarget*) colorAttachmentInfos[i].pRenderTarget; + + hash.colorAttachmentViews[i] = ( + renderTarget->view + ); + + hash.colorMultiSampleAttachmentViews[i] = ( + renderTarget->multisampleTexture->view + ); + } + + if (depthStencilAttachmentInfo == NULL) + { + hash.depthStencilAttachmentView = VK_NULL_HANDLE; + } + else + { + hash.depthStencilAttachmentView = ((VulkanRenderTarget*)depthStencilAttachmentInfo->pDepthStencilTarget)->view; + } + + if (colorAttachmentCount > 0) + { + renderTarget = (VulkanRenderTarget*) colorAttachmentInfos[0].pRenderTarget; + } + else + { + renderTarget = (VulkanRenderTarget*) depthStencilAttachmentInfo->pDepthStencilTarget; + } + + hash.width = renderTarget->texture->dimensions.width; + hash.height = renderTarget->texture->dimensions.height; + + framebuffer = FramebufferHashArray_Fetch( + &renderer->framebufferHashArray, + &hash ); - return renderPass; + if (framebuffer != VK_NULL_HANDLE) + { + SDL_UnlockMutex(renderer->framebufferFetchLock); + return framebuffer; + } + + /* Create a new framebuffer */ + + for (i = 0; i < colorAttachmentCount; i += 1) + { + renderTarget = (VulkanRenderTarget*) colorAttachmentInfos[i].pRenderTarget; + + imageViewAttachments[attachmentCount] = + renderTarget->view; + + attachmentCount += 1; + + if (renderTarget->multisampleCount > VK_SAMPLE_COUNT_1_BIT) + { + imageViewAttachments[attachmentCount] = + renderTarget->multisampleTexture->view; + + attachmentCount += 1; + } + } + + if (depthStencilAttachmentInfo != NULL) + { + renderTarget = (VulkanRenderTarget*) depthStencilAttachmentInfo->pDepthStencilTarget; + + imageViewAttachments[attachmentCount] = renderTarget->view; + + attachmentCount += 1; + } + + framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; + framebufferInfo.pNext = NULL; + framebufferInfo.flags = 0; + framebufferInfo.renderPass = renderPass; + framebufferInfo.attachmentCount = attachmentCount; + framebufferInfo.pAttachments = imageViewAttachments; + framebufferInfo.width = hash.width; + framebufferInfo.height = hash.height; + framebufferInfo.layers = 1; + + result = renderer->vkCreateFramebuffer( + renderer->logicalDevice, + &framebufferInfo, + NULL, + &framebuffer + ); + + if (result == VK_SUCCESS) + { + FramebufferHashArray_Insert( + &renderer->framebufferHashArray, + hash, + framebuffer + ); + } + else + { + LogVulkanResultAsError("vkCreateFramebuffer", result); + framebuffer = VK_NULL_HANDLE; + } + + SDL_UnlockMutex(renderer->framebufferFetchLock); + return framebuffer; } static void VULKAN_BeginRenderPass( Refresh_Renderer *driverData, Refresh_CommandBuffer *commandBuffer, Refresh_Rect *renderArea, - Refresh_ColorAttachmentInfo *pColorAttachmentInfos, + Refresh_ColorAttachmentInfo *colorAttachmentInfos, uint32_t colorAttachmentCount, Refresh_DepthStencilAttachmentInfo *depthStencilAttachmentInfo ) { @@ -7141,27 +7540,38 @@ static void VULKAN_BeginRenderPass( VkRenderPass renderPass; VkFramebuffer framebuffer; - VulkanRenderTarget *colorTarget; VulkanRenderTarget *depthStencilTarget; VkClearValue *clearValues; uint32_t clearCount = colorAttachmentCount; uint32_t i; VkImageAspectFlags depthAspectFlags; + if (colorAttachmentCount == 0 && depthStencilAttachmentInfo == NULL) + { + Refresh_LogError("Render pass must have at least one render target!"); + return; + } + renderPass = VULKAN_INTERNAL_FetchRenderPass( renderer, - pColorAttachmentInfos, + colorAttachmentInfos, colorAttachmentCount, depthStencilAttachmentInfo ); - framebuffer = VULKAN_INTERNAL_FetchFramebuffer(renderer); + framebuffer = VULKAN_INTERNAL_FetchFramebuffer( + renderer, + renderPass, + colorAttachmentInfos, + colorAttachmentCount, + depthStencilAttachmentInfo + ); /* Layout transitions */ for (i = 0; i < colorAttachmentCount; i += 1) { - VulkanRenderTarget *colorTarget = (VulkanRenderTarget*) pColorAttachmentInfos->pRenderTarget; + VulkanRenderTarget *colorTarget = (VulkanRenderTarget*) colorAttachmentInfos->pRenderTarget; VULKAN_INTERNAL_ImageMemoryBarrier( renderer, @@ -7212,10 +7622,10 @@ static void VULKAN_BeginRenderPass( for (i = 0; i < colorAttachmentCount; i += 1) { - clearValues[i].color.float32[0] = pColorAttachmentInfos[i].clearColor.x; - clearValues[i].color.float32[1] = pColorAttachmentInfos[i].clearColor.y; - clearValues[i].color.float32[2] = pColorAttachmentInfos[i].clearColor.z; - clearValues[i].color.float32[3] = pColorAttachmentInfos[i].clearColor.w; + clearValues[i].color.float32[0] = colorAttachmentInfos[i].clearColor.x; + clearValues[i].color.float32[1] = colorAttachmentInfos[i].clearColor.y; + clearValues[i].color.float32[2] = colorAttachmentInfos[i].clearColor.z; + clearValues[i].color.float32[3] = colorAttachmentInfos[i].clearColor.w; } if (depthStencilAttachmentInfo != NULL) @@ -7255,9 +7665,6 @@ static void VULKAN_EndRenderPass( ) { VulkanRenderer* renderer = (VulkanRenderer*) driverData; VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer*) commandBuffer; - VulkanTexture *currentTexture; - VkImageAspectFlags depthAspectFlags; - uint32_t i; renderer->vkCmdEndRenderPass( vulkanCommandBuffer->commandBuffer @@ -7797,7 +8204,6 @@ static Refresh_CommandBuffer* VULKAN_AcquireCommandBuffer( uint8_t fixed ) { VulkanRenderer *renderer = (VulkanRenderer*) driverData; - uint32_t i; SDL_threadID threadID = SDL_ThreadID(); @@ -9245,6 +9651,8 @@ static Refresh_Device* VULKAN_CreateDevice( renderer->submitLock = SDL_CreateMutex(); renderer->acquireFenceLock = SDL_CreateMutex(); renderer->acquireCommandBufferLock = SDL_CreateMutex(); + renderer->renderPassFetchLock = SDL_CreateMutex(); + renderer->framebufferFetchLock = SDL_CreateMutex(); /* Create fence lists */ @@ -9552,6 +9960,14 @@ static Refresh_Device* VULKAN_CreateDevice( renderer->descriptorSetLayoutHashTable.buckets[i].capacity = 0; } + renderer->renderPassHashArray.elements = NULL; + renderer->renderPassHashArray.count = 0; + renderer->renderPassHashArray.capacity = 0; + + renderer->framebufferHashArray.elements = NULL; + renderer->framebufferHashArray.count = 0; + renderer->framebufferHashArray.capacity = 0; + /* Initialize transfer buffer pool */ renderer->transferBufferPool.lock = SDL_CreateMutex();