From 643951683554ec7e012872071158d2d965b779c4 Mon Sep 17 00:00:00 2001 From: TheSpydog Date: Mon, 30 Jan 2023 18:22:16 +0000 Subject: [PATCH] ABI break: Textures now have a sample count, not render passes (#37) This change makes Refresh behave more like FNA and other rendering APIs, where user-side textures have a sample count instead of generating MSAA RTs on the fly. This should theoretically reduce memory consumption since subresource views no longer generate their own MSAA textures. Instead, each texture with a sample count > 1 now has a reference to an MSAA texture baked into the root texture itself, so views can just reference that. This also simplifies VulkanRenderTarget significantly, to the point where it's just a wrapper around VkImageView. We could probably remove the abstraction entirely at this point. Since VkRenderPass objects still require knowing the sample count, we can use the first bound texture's sample count. This means users only have to specify sample count in two places -- the graphics pipeline, and the texture. Easy enough. I also noticed and fixed a bug with clear values with MSAA levels > 1. Co-authored-by: Caleb Cornett Reviewed-on: https://gitea.moonside.games/MoonsideGames/Refresh/pulls/37 Co-authored-by: TheSpydog Co-committed-by: TheSpydog --- include/Refresh.h | 2 +- src/Refresh_Driver_Vulkan.c | 244 ++++++++++++++++++------------------ 2 files changed, 120 insertions(+), 126 deletions(-) diff --git a/include/Refresh.h b/include/Refresh.h index a64524a..39110d4 100644 --- a/include/Refresh.h +++ b/include/Refresh.h @@ -463,6 +463,7 @@ typedef struct Refresh_TextureCreateInfo uint32_t depth; uint8_t isCube; uint32_t levelCount; + Refresh_SampleCount sampleCount; Refresh_TextureFormat format; Refresh_TextureUsageFlags usageFlags; } Refresh_TextureCreateInfo; @@ -551,7 +552,6 @@ typedef struct Refresh_ColorAttachmentInfo uint32_t depth; uint32_t layer; uint32_t level; - Refresh_SampleCount sampleCount; Refresh_Vec4 clearColor; /* Can be ignored by RenderPass */ Refresh_LoadOp loadOp; Refresh_StoreOp storeOp; diff --git a/src/Refresh_Driver_Vulkan.c b/src/Refresh_Driver_Vulkan.c index b79d0b4..1bada36 100644 --- a/src/Refresh_Driver_Vulkan.c +++ b/src/Refresh_Driver_Vulkan.c @@ -758,20 +758,21 @@ typedef struct VulkanTexture uint32_t depth; uint32_t layerCount; uint32_t levelCount; + Refresh_SampleCount sampleCount; VkFormat format; VulkanResourceAccessType resourceAccessType; VkImageUsageFlags usageFlags; VkImageAspectFlags aspectFlags; + struct VulkanTexture *msaaTex; + SDL_atomic_t referenceCount; } VulkanTexture; typedef struct VulkanRenderTarget { VkImageView view; - VulkanTexture *multisampleTexture; - VkSampleCountFlags multisampleCount; } VulkanRenderTarget; typedef struct VulkanFramebuffer @@ -1200,11 +1201,10 @@ static inline void FramebufferHashArray_Remove( typedef struct RenderTargetHash { - Refresh_Texture *texture; + VulkanTexture *texture; uint32_t depth; uint32_t layer; uint32_t level; - Refresh_SampleCount sampleCount; } RenderTargetHash; typedef struct RenderTargetHashMap @@ -1244,11 +1244,6 @@ static inline uint8_t RenderTargetHash_Compare( return 0; } - if (a->sampleCount != b->sampleCount) - { - return 0; - } - return 1; } @@ -3068,6 +3063,15 @@ static void VULKAN_INTERNAL_DestroyTexture( NULL ); + /* destroy the msaa texture, if there is one */ + if (texture->msaaTex != NULL) + { + VULKAN_INTERNAL_DestroyTexture( + renderer, + texture->msaaTex + ); + } + SDL_free(texture); } @@ -3086,18 +3090,6 @@ static void VULKAN_INTERNAL_DestroyRenderTarget( NULL ); - /* The texture is not owned by the RenderTarget - * so we don't free it here - * But the multisampleTexture is! - */ - if (renderTarget->multisampleTexture != NULL) - { - VULKAN_INTERNAL_DestroyTexture( - renderer, - renderTarget->multisampleTexture - ); - } - SDL_free(renderTarget); } @@ -4605,11 +4597,13 @@ static uint8_t VULKAN_INTERNAL_CreateSwapchain( swapchainData->textures[i].isCube = 0; swapchainData->textures[i].layerCount = 1; swapchainData->textures[i].levelCount = 1; + swapchainData->textures[i].sampleCount = REFRESH_SAMPLECOUNT_1; swapchainData->textures[i].usageFlags = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; swapchainData->textures[i].aspectFlags = VK_IMAGE_ASPECT_COLOR_BIT; swapchainData->textures[i].resourceAccessType = RESOURCE_ACCESS_NONE; + swapchainData->textures[i].msaaTex = NULL; } SDL_stack_free(swapchainImages); @@ -5217,8 +5211,8 @@ static VulkanTexture* VULKAN_INTERNAL_CreateTexture( uint32_t height, uint32_t depth, uint32_t isCube, - VkSampleCountFlagBits samples, uint32_t levelCount, + Refresh_SampleCount sampleCount, VkFormat format, VkImageAspectFlags aspectMask, VkImageUsageFlags imageUsageFlags @@ -5261,7 +5255,7 @@ static VulkanTexture* VULKAN_INTERNAL_CreateTexture( imageCreateInfo.extent.depth = depth; imageCreateInfo.mipLevels = levelCount; imageCreateInfo.arrayLayers = layerCount; - imageCreateInfo.samples = samples; + imageCreateInfo.samples = RefreshToVK_SampleCount[sampleCount]; imageCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL; imageCreateInfo.usage = imageUsageFlags; imageCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; @@ -5388,9 +5382,11 @@ static VulkanTexture* VULKAN_INTERNAL_CreateTexture( texture->format = format; texture->levelCount = levelCount; texture->layerCount = layerCount; + texture->sampleCount = sampleCount; texture->resourceAccessType = RESOURCE_ACCESS_NONE; texture->usageFlags = imageUsageFlags; texture->aspectFlags = aspectMask; + texture->msaaTex = NULL; SDL_AtomicSet(&texture->referenceCount, 0); @@ -5399,27 +5395,22 @@ static VulkanTexture* VULKAN_INTERNAL_CreateTexture( static VulkanRenderTarget* VULKAN_INTERNAL_CreateRenderTarget( VulkanRenderer *renderer, - Refresh_Texture *texture, + VulkanTexture *texture, uint32_t depth, uint32_t layer, - uint32_t level, - Refresh_SampleCount multisampleCount + uint32_t level ) { VkResult vulkanResult; VulkanRenderTarget *renderTarget = (VulkanRenderTarget*) SDL_malloc(sizeof(VulkanRenderTarget)); - VulkanTexture *vulkanTexture = (VulkanTexture*) texture; VkImageViewCreateInfo imageViewCreateInfo; VkComponentMapping swizzle = IDENTITY_SWIZZLE; VkImageAspectFlags aspectFlags = 0; - renderTarget->multisampleTexture = NULL; - renderTarget->multisampleCount = 1; - - if (IsDepthFormat(vulkanTexture->format)) + if (IsDepthFormat(texture->format)) { aspectFlags |= VK_IMAGE_ASPECT_DEPTH_BIT; - if (IsStencilFormat(vulkanTexture->format)) + if (IsStencilFormat(texture->format)) { aspectFlags |= VK_IMAGE_ASPECT_STENCIL_BIT; } @@ -5429,48 +5420,22 @@ static VulkanRenderTarget* VULKAN_INTERNAL_CreateRenderTarget( aspectFlags |= VK_IMAGE_ASPECT_COLOR_BIT; } - /* create resolve target for multisample */ - if (multisampleCount > REFRESH_SAMPLECOUNT_1) - { - /* Find a compatible sample count to use */ - multisampleCount = VULKAN_INTERNAL_GetMaxMultiSampleCount( - renderer, - multisampleCount - ); - - renderTarget->multisampleTexture = - VULKAN_INTERNAL_CreateTexture( - renderer, - vulkanTexture->dimensions.width, - vulkanTexture->dimensions.height, - 1, - 0, - RefreshToVK_SampleCount[multisampleCount], - 1, - vulkanTexture->format, - aspectFlags, - VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT - ); - - renderTarget->multisampleCount = RefreshToVK_SampleCount[multisampleCount]; - } - /* create framebuffer compatible views for RenderTarget */ imageViewCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; imageViewCreateInfo.pNext = NULL; imageViewCreateInfo.flags = 0; - imageViewCreateInfo.image = vulkanTexture->image; - imageViewCreateInfo.format = vulkanTexture->format; + imageViewCreateInfo.image = texture->image; + imageViewCreateInfo.format = texture->format; imageViewCreateInfo.components = swizzle; imageViewCreateInfo.subresourceRange.aspectMask = aspectFlags; imageViewCreateInfo.subresourceRange.baseMipLevel = level; imageViewCreateInfo.subresourceRange.levelCount = 1; imageViewCreateInfo.subresourceRange.baseArrayLayer = 0; - if (vulkanTexture->is3D) + if (texture->is3D) { imageViewCreateInfo.subresourceRange.baseArrayLayer = depth; } - else if (vulkanTexture->isCube) + else if (texture->isCube) { imageViewCreateInfo.subresourceRange.baseArrayLayer = layer; } @@ -5499,11 +5464,10 @@ static VulkanRenderTarget* VULKAN_INTERNAL_CreateRenderTarget( static VulkanRenderTarget* VULKAN_INTERNAL_FetchRenderTarget( VulkanRenderer *renderer, - Refresh_Texture *texture, + VulkanTexture *texture, uint32_t depth, uint32_t layer, - uint32_t level, - Refresh_SampleCount sampleCount + uint32_t level ) { RenderTargetHash hash; VulkanRenderTarget *renderTarget; @@ -5512,7 +5476,6 @@ static VulkanRenderTarget* VULKAN_INTERNAL_FetchRenderTarget( hash.depth = depth; hash.layer = layer; hash.level = level; - hash.sampleCount = sampleCount; SDL_LockMutex(renderer->renderTargetFetchLock); @@ -5528,8 +5491,7 @@ static VulkanRenderTarget* VULKAN_INTERNAL_FetchRenderTarget( texture, depth, layer, - level, - sampleCount + level ); RenderTargetHash_Insert( @@ -5560,31 +5522,21 @@ static VkRenderPass VULKAN_INTERNAL_CreateRenderPass( VkSubpassDescription subpass; VkRenderPass renderPass; uint32_t i; - uint8_t multisampling = 0; uint32_t attachmentDescriptionCount = 0; uint32_t colorAttachmentReferenceCount = 0; uint32_t resolveReferenceCount = 0; - VulkanRenderTarget *renderTarget; VulkanTexture *texture; + VulkanTexture *msaaTexture = NULL; for (i = 0; i < colorAttachmentCount; i += 1) { texture = (VulkanTexture*) colorAttachmentInfos[i].texture; - renderTarget = VULKAN_INTERNAL_FetchRenderTarget( - renderer, - colorAttachmentInfos[i].texture, - colorAttachmentInfos[i].depth, - colorAttachmentInfos[i].layer, - colorAttachmentInfos[i].level, - colorAttachmentInfos[i].sampleCount - ); - - if (renderTarget->multisampleCount > VK_SAMPLE_COUNT_1_BIT) + if (texture->msaaTex != NULL) { - multisampling = 1; + msaaTexture = texture->msaaTex; /* Transition the multisample attachment */ @@ -5594,12 +5546,12 @@ static VkRenderPass VULKAN_INTERNAL_CreateRenderPass( RESOURCE_ACCESS_COLOR_ATTACHMENT_WRITE, VK_IMAGE_ASPECT_COLOR_BIT, 0, - renderTarget->multisampleTexture->layerCount, + msaaTexture->layerCount, 0, - renderTarget->multisampleTexture->levelCount, + msaaTexture->levelCount, 0, - renderTarget->multisampleTexture->image, - &renderTarget->multisampleTexture->resourceAccessType + msaaTexture->image, + &msaaTexture->resourceAccessType ); /* Resolve attachment and multisample attachment */ @@ -5631,8 +5583,10 @@ static VkRenderPass VULKAN_INTERNAL_CreateRenderPass( resolveReferenceCount += 1; attachmentDescriptions[attachmentDescriptionCount].flags = 0; - attachmentDescriptions[attachmentDescriptionCount].format = texture->format; - attachmentDescriptions[attachmentDescriptionCount].samples = renderTarget->multisampleCount; + attachmentDescriptions[attachmentDescriptionCount].format = msaaTexture->format; + attachmentDescriptions[attachmentDescriptionCount].samples = RefreshToVK_SampleCount[ + msaaTexture->sampleCount + ]; attachmentDescriptions[attachmentDescriptionCount].loadOp = RefreshToVK_LoadOp[ colorAttachmentInfos[i].loadOp ]; @@ -5701,17 +5655,10 @@ static VkRenderPass VULKAN_INTERNAL_CreateRenderPass( } else { - renderTarget = VULKAN_INTERNAL_FetchRenderTarget( - renderer, - depthStencilAttachmentInfo->texture, - depthStencilAttachmentInfo->depth, - depthStencilAttachmentInfo->layer, - depthStencilAttachmentInfo->level, - REFRESH_SAMPLECOUNT_1 - ); - texture = (VulkanTexture*) depthStencilAttachmentInfo->texture; + /* FIXME: MSAA? */ + attachmentDescriptions[attachmentDescriptionCount].flags = 0; attachmentDescriptions[attachmentDescriptionCount].format = texture->format; attachmentDescriptions[attachmentDescriptionCount].samples = @@ -5744,7 +5691,7 @@ static VkRenderPass VULKAN_INTERNAL_CreateRenderPass( attachmentDescriptionCount += 1; } - if (multisampling) + if (msaaTexture != NULL) { subpass.pResolveAttachments = resolveReferences; } @@ -6601,6 +6548,7 @@ static Refresh_Texture* VULKAN_CreateTexture( ); VkImageAspectFlags imageAspectFlags; VkFormat format; + VulkanTexture *result; if (IsRefreshDepthFormat(textureCreateInfo->format)) { @@ -6645,18 +6593,37 @@ static Refresh_Texture* VULKAN_CreateTexture( imageAspectFlags = VK_IMAGE_ASPECT_COLOR_BIT; } - return (Refresh_Texture*) VULKAN_INTERNAL_CreateTexture( + result = VULKAN_INTERNAL_CreateTexture( renderer, textureCreateInfo->width, textureCreateInfo->height, textureCreateInfo->depth, textureCreateInfo->isCube, - VK_SAMPLE_COUNT_1_BIT, textureCreateInfo->levelCount, + REFRESH_SAMPLECOUNT_1, format, imageAspectFlags, imageUsageFlags ); + + /* create the MSAA texture */ + if (result != NULL && textureCreateInfo->sampleCount > REFRESH_SAMPLECOUNT_1) + { + result->msaaTex = VULKAN_INTERNAL_CreateTexture( + renderer, + textureCreateInfo->width, + textureCreateInfo->height, + textureCreateInfo->depth, + textureCreateInfo->isCube, + textureCreateInfo->levelCount, + textureCreateInfo->sampleCount, + format, + imageAspectFlags, + imageUsageFlags + ); + } + + return (Refresh_Texture*) result; } static Refresh_Buffer* VULKAN_CreateBuffer( @@ -7842,7 +7809,7 @@ static void VULKAN_QueueDestroyTexture( Refresh_Texture *texture ) { VulkanRenderer *renderer = (VulkanRenderer*) driverData; - VulkanTexture* vulkanTexture = (VulkanTexture*)texture; + VulkanTexture* vulkanTexture = (VulkanTexture*) texture; SDL_LockMutex(renderer->disposeLock); @@ -7989,6 +7956,7 @@ static VkRenderPass VULKAN_INTERNAL_FetchRenderPass( VkRenderPass renderPass; RenderPassHash hash; uint32_t i; + VulkanTexture *texture; SDL_LockMutex(renderer->renderPassFetchLock); @@ -8000,9 +7968,15 @@ static VkRenderPass VULKAN_INTERNAL_FetchRenderPass( hash.colorTargetDescriptions[i].storeOp = colorAttachmentInfos[i].storeOp; } - hash.colorAttachmentSampleCount = (colorAttachmentCount > 0) ? - colorAttachmentInfos[0].sampleCount : - REFRESH_SAMPLECOUNT_1; + hash.colorAttachmentSampleCount = REFRESH_SAMPLECOUNT_1; + if (colorAttachmentCount > 0) + { + texture = (VulkanTexture*) colorAttachmentInfos[0].texture; + if (texture->msaaTex != NULL) + { + hash.colorAttachmentSampleCount = texture->msaaTex->sampleCount; + } + } hash.colorAttachmentCount = colorAttachmentCount; @@ -8069,6 +8043,7 @@ static VulkanFramebuffer* VULKAN_INTERNAL_FetchFramebuffer( VkResult result; VkImageView imageViewAttachments[2 * MAX_COLOR_TARGET_BINDINGS + 1]; FramebufferHash hash; + VulkanTexture *texture; VulkanRenderTarget *renderTarget; uint32_t attachmentCount = 0; uint32_t i; @@ -8085,23 +8060,32 @@ static VulkanFramebuffer* VULKAN_INTERNAL_FetchFramebuffer( for (i = 0; i < colorAttachmentCount; i += 1) { + texture = (VulkanTexture*) colorAttachmentInfos[i].texture; + renderTarget = VULKAN_INTERNAL_FetchRenderTarget( renderer, - colorAttachmentInfos[i].texture, + texture, colorAttachmentInfos[i].depth, colorAttachmentInfos[i].layer, - colorAttachmentInfos[i].level, - colorAttachmentInfos[i].sampleCount + colorAttachmentInfos[i].level ); hash.colorAttachmentViews[i] = ( renderTarget->view ); - if (renderTarget->multisampleTexture != NULL) + if (texture->msaaTex != NULL) { + renderTarget = VULKAN_INTERNAL_FetchRenderTarget( + renderer, + texture->msaaTex, + colorAttachmentInfos[i].depth, + colorAttachmentInfos[i].layer, + colorAttachmentInfos[i].level + ); + hash.colorMultiSampleAttachmentViews[i] = ( - renderTarget->multisampleTexture->view + renderTarget->view ); } } @@ -8112,13 +8096,13 @@ static VulkanFramebuffer* VULKAN_INTERNAL_FetchFramebuffer( } else { + texture = (VulkanTexture*) depthStencilAttachmentInfo->texture; renderTarget = VULKAN_INTERNAL_FetchRenderTarget( renderer, - depthStencilAttachmentInfo->texture, + texture, depthStencilAttachmentInfo->depth, depthStencilAttachmentInfo->layer, - depthStencilAttachmentInfo->level, - REFRESH_SAMPLECOUNT_1 + depthStencilAttachmentInfo->level ); hash.depthStencilAttachmentView = renderTarget->view; } @@ -8145,13 +8129,14 @@ static VulkanFramebuffer* VULKAN_INTERNAL_FetchFramebuffer( for (i = 0; i < colorAttachmentCount; i += 1) { + texture = (VulkanTexture*) colorAttachmentInfos[i].texture; + renderTarget = VULKAN_INTERNAL_FetchRenderTarget( renderer, - colorAttachmentInfos[i].texture, + texture, colorAttachmentInfos[i].depth, colorAttachmentInfos[i].layer, - colorAttachmentInfos[i].level, - colorAttachmentInfos[i].sampleCount + colorAttachmentInfos[i].level ); imageViewAttachments[attachmentCount] = @@ -8159,10 +8144,18 @@ static VulkanFramebuffer* VULKAN_INTERNAL_FetchFramebuffer( attachmentCount += 1; - if (renderTarget->multisampleTexture != NULL) + if (texture->msaaTex != NULL) { + renderTarget = VULKAN_INTERNAL_FetchRenderTarget( + renderer, + texture->msaaTex, + colorAttachmentInfos[i].depth, + colorAttachmentInfos[i].layer, + colorAttachmentInfos[i].level + ); + imageViewAttachments[attachmentCount] = - renderTarget->multisampleTexture->view; + renderTarget->view; attachmentCount += 1; } @@ -8170,13 +8163,13 @@ static VulkanFramebuffer* VULKAN_INTERNAL_FetchFramebuffer( if (depthStencilAttachmentInfo != NULL) { + texture = (VulkanTexture*) depthStencilAttachmentInfo->texture; renderTarget = VULKAN_INTERNAL_FetchRenderTarget( renderer, - depthStencilAttachmentInfo->texture, + texture, depthStencilAttachmentInfo->depth, depthStencilAttachmentInfo->layer, - depthStencilAttachmentInfo->level, - REFRESH_SAMPLECOUNT_1 + depthStencilAttachmentInfo->level ); imageViewAttachments[attachmentCount] = renderTarget->view; @@ -8388,7 +8381,7 @@ static void VULKAN_BeginRenderPass( &texture->resourceAccessType ); - if (colorAttachmentInfos[i].sampleCount > REFRESH_SAMPLECOUNT_1) + if (texture->msaaTex != NULL) { clearCount += 1; multisampleAttachmentCount += 1; @@ -8438,13 +8431,14 @@ static void VULKAN_BeginRenderPass( clearValues[i].color.float32[2] = colorAttachmentInfos[i].clearColor.z; clearValues[i].color.float32[3] = colorAttachmentInfos[i].clearColor.w; - if (colorAttachmentInfos[i].sampleCount > REFRESH_SAMPLECOUNT_1) + texture = (VulkanTexture*) colorAttachmentInfos[i].texture; + if (texture->msaaTex != NULL) { + clearValues[i+1].color.float32[0] = colorAttachmentInfos[i].clearColor.x; + clearValues[i+1].color.float32[1] = colorAttachmentInfos[i].clearColor.y; + clearValues[i+1].color.float32[2] = colorAttachmentInfos[i].clearColor.z; + clearValues[i+1].color.float32[3] = colorAttachmentInfos[i].clearColor.w; i += 1; - 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; } }