From 4c73c6c200563069dc93b7dae78a5c40f8e635e9 Mon Sep 17 00:00:00 2001 From: cosmonaut Date: Tue, 1 Mar 2022 16:37:00 -0800 Subject: [PATCH] initial present rewrite --- include/Refresh.h | 58 +- src/Refresh.c | 38 +- src/Refresh_Driver.h | 22 +- src/Refresh_Driver_Vulkan.c | 1248 +++++++++++++++++++++-------------- 4 files changed, 771 insertions(+), 595 deletions(-) diff --git a/include/Refresh.h b/include/Refresh.h index 04be0b5..d9b8c16 100644 --- a/include/Refresh.h +++ b/include/Refresh.h @@ -58,7 +58,6 @@ typedef struct Refresh_Device Refresh_Device; typedef struct Refresh_Buffer Refresh_Buffer; typedef struct Refresh_Texture Refresh_Texture; typedef struct Refresh_Sampler Refresh_Sampler; -typedef struct Refresh_RenderTarget Refresh_RenderTarget; typedef struct Refresh_ShaderModule Refresh_ShaderModule; typedef struct Refresh_ComputePipeline Refresh_ComputePipeline; typedef struct Refresh_GraphicsPipeline Refresh_GraphicsPipeline; @@ -113,6 +112,7 @@ typedef enum Refresh_TextureFormat { /* Color Formats */ REFRESH_TEXTUREFORMAT_R8G8B8A8, + REFRESH_TEXTUREFORMAT_B8G8R8A8, REFRESH_TEXTUREFORMAT_R5G6B5, REFRESH_TEXTUREFORMAT_A1R5G5B5, REFRESH_TEXTUREFORMAT_B4G4R4A4, @@ -585,7 +585,11 @@ typedef struct Refresh_GraphicsPipelineCreateInfo typedef struct Refresh_ColorAttachmentInfo { - Refresh_RenderTarget *pRenderTarget; + Refresh_Texture *texture; /* We can't use TextureSlice because render passes take a single rectangle. */ + 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; @@ -593,8 +597,11 @@ typedef struct Refresh_ColorAttachmentInfo typedef struct Refresh_DepthStencilAttachmentInfo { - Refresh_RenderTarget *pDepthStencilTarget; - Refresh_DepthStencilValue depthStencilValue; /* Can be ignored by RenderPass */ + Refresh_Texture *texture; /* We can't use TextureSlice because render passes take a single rectangle. */ + uint32_t depth; + uint32_t layer; + uint32_t level; + Refresh_DepthStencilValue depthStencilClearValue; /* Can be ignored by RenderPass */ Refresh_LoadOp loadOp; Refresh_StoreOp storeOp; Refresh_LoadOp stencilLoadOp; @@ -831,17 +838,6 @@ REFRESHAPI Refresh_Texture* Refresh_CreateTexture( Refresh_TextureCreateInfo *textureCreateInfo ); -/* Creates a color target. - * - * textureSlice: The texture slice that the color target will resolve to. - * multisampleCount: The MSAA value for the color target. - */ -REFRESHAPI Refresh_RenderTarget* Refresh_CreateRenderTarget( - Refresh_Device *device, - Refresh_TextureSlice *textureSlice, - Refresh_SampleCount multisampleCount -); - /* Creates a buffer. * * usageFlags: Specifies how the buffer will be used. @@ -1053,19 +1049,6 @@ REFRESHAPI void Refresh_QueueDestroyBuffer( Refresh_Buffer *buffer ); -/* Sends a color target to be destroyed by the renderer. Note that we call it - * "QueueDestroy" because it may not be immediately destroyed by the renderer if - * this is not called from the main thread (for example, if a garbage collector - * deletes the resource instead of the programmer). - * - * renderTarget: The Refresh_ColorTarget to be destroyed. - */ -REFRESHAPI void Refresh_QueueDestroyRenderTarget( - Refresh_Device *device, - Refresh_CommandBuffer *commandBuffer, - Refresh_RenderTarget *renderTarget -); - /* Sends a shader module to be destroyed by the renderer. Note that we call it * "QueueDestroy" because it may not be immediately destroyed by the renderer if * this is not called from the main thread (for example, if a garbage collector @@ -1244,23 +1227,18 @@ REFRESHAPI Refresh_CommandBuffer* Refresh_AcquireCommandBuffer( uint8_t fixed ); -/* Queues an image to be presented to a window. - * The image will be presented upon the next Refresh_Submit call. +/* Acquires a texture to use for presentation. + * May return NULL under certain conditions. + * If NULL, the user must ensure to not present. + * Once a swapchain texture is acquired, + * it will automatically be presented on command buffer submission. * * NOTE: - * It is an error to call this function in headless mode. - * - * textureSlice: The texture slice to present. - * destinationRectangle: The region of the window to update. Can be NULL. - * filter: The filter to use if scaling is required. - * windowHandle: The window to present to. + * It is not recommended to hold a reference to this texture long term. */ -REFRESHAPI void Refresh_QueuePresent( +REFRESHAPI Refresh_Texture* Refresh_AcquireSwapchainTexture( Refresh_Device *device, Refresh_CommandBuffer *commandBuffer, - Refresh_TextureSlice *textureSlice, - Refresh_Rect *destinationRectangle, - Refresh_Filter filter, void *windowHandle ); diff --git a/src/Refresh.c b/src/Refresh.c index 6802771..f6dfe94 100644 --- a/src/Refresh.c +++ b/src/Refresh.c @@ -305,19 +305,6 @@ Refresh_Texture* Refresh_CreateTexture( ); } -Refresh_RenderTarget* Refresh_CreateRenderTarget( - Refresh_Device *device, - Refresh_TextureSlice *textureSlice, - Refresh_SampleCount multisampleCount -) { - NULL_RETURN_NULL(device); - return device->CreateRenderTarget( - device->driverData, - textureSlice, - multisampleCount - ); -} - Refresh_Buffer* Refresh_CreateBuffer( Refresh_Device *device, Refresh_BufferUsageFlags usageFlags, @@ -557,19 +544,6 @@ void Refresh_QueueDestroyBuffer( ); } -void Refresh_QueueDestroyRenderTarget( - Refresh_Device *device, - Refresh_CommandBuffer *commandBuffer, - Refresh_RenderTarget *renderTarget -) { - NULL_RETURN(device); - device->QueueDestroyRenderTarget( - device->driverData, - commandBuffer, - renderTarget - ); -} - void Refresh_QueueDestroyShaderModule( Refresh_Device *device, Refresh_CommandBuffer *commandBuffer, @@ -738,21 +712,15 @@ Refresh_CommandBuffer* Refresh_AcquireCommandBuffer( ); } -void Refresh_QueuePresent( +Refresh_Texture* Refresh_AcquireSwapchainTexture( Refresh_Device *device, Refresh_CommandBuffer *commandBuffer, - Refresh_TextureSlice* textureSlice, - Refresh_Rect *destinationRectangle, - Refresh_Filter filter, void *windowHandle ) { - NULL_RETURN(device); - device->QueuePresent( + NULL_RETURN_NULL(device); + return device->AcquireSwapchainTexture( device->driverData, commandBuffer, - textureSlice, - destinationRectangle, - filter, windowHandle ); } diff --git a/src/Refresh_Driver.h b/src/Refresh_Driver.h index d7e6538..95abaaa 100644 --- a/src/Refresh_Driver.h +++ b/src/Refresh_Driver.h @@ -154,6 +154,7 @@ static inline int32_t BytesPerImage( #define MAX_BUFFER_BINDINGS 16 #define MAX_COLOR_TARGET_BINDINGS 4 +#define MAX_PRESENT_COUNT 16 /* Refresh_Device Definition */ @@ -243,12 +244,6 @@ struct Refresh_Device Refresh_TextureCreateInfo *textureCreateInfo ); - Refresh_RenderTarget* (*CreateRenderTarget)( - Refresh_Renderer *driverData, - Refresh_TextureSlice *textureSlice, - Refresh_SampleCount multisampleCount - ); - Refresh_Buffer* (*CreateBuffer)( Refresh_Renderer *driverData, Refresh_BufferUsageFlags usageFlags, @@ -367,12 +362,6 @@ struct Refresh_Device Refresh_Buffer *buffer ); - void(*QueueDestroyRenderTarget)( - Refresh_Renderer *driverData, - Refresh_CommandBuffer *commandBuffer, - Refresh_RenderTarget *renderTarget - ); - void(*QueueDestroyShaderModule)( Refresh_Renderer *driverData, Refresh_CommandBuffer *commandBuffer, @@ -453,12 +442,9 @@ struct Refresh_Device uint8_t fixed ); - void(*QueuePresent)( + Refresh_Texture* (*AcquireSwapchainTexture)( Refresh_Renderer *driverData, Refresh_CommandBuffer *commandBuffer, - Refresh_TextureSlice *textureSlice, - Refresh_Rect *destinationRectangle, - Refresh_Filter filter, void *windowHandle ); @@ -490,7 +476,6 @@ struct Refresh_Device ASSIGN_DRIVER_FUNC(CreateSampler, name) \ ASSIGN_DRIVER_FUNC(CreateShaderModule, name) \ ASSIGN_DRIVER_FUNC(CreateTexture, name) \ - ASSIGN_DRIVER_FUNC(CreateRenderTarget, name) \ ASSIGN_DRIVER_FUNC(CreateBuffer, name) \ ASSIGN_DRIVER_FUNC(SetTextureData, name) \ ASSIGN_DRIVER_FUNC(SetTextureDataYUV, name) \ @@ -506,7 +491,6 @@ struct Refresh_Device ASSIGN_DRIVER_FUNC(QueueDestroyTexture, name) \ ASSIGN_DRIVER_FUNC(QueueDestroySampler, name) \ ASSIGN_DRIVER_FUNC(QueueDestroyBuffer, name) \ - ASSIGN_DRIVER_FUNC(QueueDestroyRenderTarget, name) \ ASSIGN_DRIVER_FUNC(QueueDestroyShaderModule, name) \ ASSIGN_DRIVER_FUNC(QueueDestroyComputePipeline, name) \ ASSIGN_DRIVER_FUNC(QueueDestroyGraphicsPipeline, name) \ @@ -519,7 +503,7 @@ struct Refresh_Device ASSIGN_DRIVER_FUNC(BindComputeBuffers, name) \ ASSIGN_DRIVER_FUNC(BindComputeTextures, name) \ ASSIGN_DRIVER_FUNC(AcquireCommandBuffer, name) \ - ASSIGN_DRIVER_FUNC(QueuePresent, name) \ + ASSIGN_DRIVER_FUNC(AcquireSwapchainTexture, name) \ ASSIGN_DRIVER_FUNC(Submit, name) \ ASSIGN_DRIVER_FUNC(Wait, name) diff --git a/src/Refresh_Driver_Vulkan.c b/src/Refresh_Driver_Vulkan.c index a6443dd..9ab5e97 100644 --- a/src/Refresh_Driver_Vulkan.c +++ b/src/Refresh_Driver_Vulkan.c @@ -190,6 +190,7 @@ static const uint8_t DEVICE_PRIORITY[] = static VkFormat RefreshToVK_SurfaceFormat[] = { VK_FORMAT_R8G8B8A8_UNORM, /* R8G8B8A8 */ + VK_FORMAT_B8G8R8A8_UNORM, /* B8G8R8A8 */ VK_FORMAT_R5G6B5_UNORM_PACK16, /* R5G6B5 */ VK_FORMAT_A1R5G5B5_UNORM_PACK16, /* A1R5G5B5 */ VK_FORMAT_B4G4R4A4_UNORM_PACK16, /* B4G4R4A4 */ @@ -747,7 +748,16 @@ typedef struct VulkanTexture VkImageUsageFlags usageFlags; } VulkanTexture; -typedef struct VulkanSwapchainData +typedef struct VulkanSwapchainData VulkanSwapchainData; + +typedef struct VulkanRenderTarget +{ + VkImageView view; + VulkanTexture *multisampleTexture; + VkSampleCountFlags multisampleCount; +} VulkanRenderTarget; + +struct VulkanSwapchainData { /* Window surface */ VkSurfaceKHR surface; @@ -765,11 +775,14 @@ typedef struct VulkanSwapchainData VulkanTexture *textures; uint32_t imageCount; + /* Recreate flag */ + uint8_t needsRecreate; + /* Synchronization primitives */ VkSemaphore imageAvailableSemaphore; VkSemaphore renderFinishedSemaphore; VkFence inFlightFence; /* borrowed from VulkanRenderer */ -} VulkanSwapchainData; +}; typedef struct SwapChainSupportDetails { @@ -780,6 +793,12 @@ typedef struct SwapChainSupportDetails uint32_t presentModesLength; } SwapChainSupportDetails; +typedef struct VulkanPresentData +{ + VulkanSwapchainData *swapchainData; + uint32_t swapchainImageIndex; +} VulkanPresentData; + typedef struct DescriptorSetCache DescriptorSetCache; typedef struct VulkanGraphicsPipelineLayout @@ -812,15 +831,6 @@ typedef struct VulkanComputePipeline VkDeviceSize uniformBlockSize; /* permanently set in Create function */ } VulkanComputePipeline; -typedef struct VulkanRenderTarget -{ - VulkanTexture *texture; - uint32_t layer; - VkImageView view; - VulkanTexture *multisampleTexture; - VkSampleCountFlags multisampleCount; -} VulkanRenderTarget; - /* Cache structures */ /* Descriptor Set Layout Caches*/ @@ -1137,6 +1147,105 @@ static inline void FramebufferHashArray_Remove( arr->count -= 1; } +typedef struct RenderTargetHash +{ + Refresh_Texture *texture; + uint32_t depth; + uint32_t layer; + uint32_t level; + Refresh_SampleCount sampleCount; +} RenderTargetHash; + +typedef struct RenderTargetHashMap +{ + RenderTargetHash key; + VulkanRenderTarget *value; +} RenderTargetHashMap; + +typedef struct RenderTargetHashArray +{ + RenderTargetHashMap *elements; + int32_t count; + int32_t capacity; +} RenderTargetHashArray; + +static inline uint8_t RenderTargetHash_Compare( + RenderTargetHash *a, + RenderTargetHash *b +) { + if (a->texture != b->texture) + { + return 0; + } + + if (a->layer != b->layer) + { + return 0; + } + + if (a->level != b->level) + { + return 0; + } + + if (a->depth != b->depth) + { + return 0; + } + + if (a->sampleCount != b->sampleCount) + { + return 0; + } + + return 1; +} + +static inline VulkanRenderTarget* RenderTargetHash_Fetch( + RenderTargetHashArray *arr, + RenderTargetHash *key +) { + int32_t i; + + for (i = 0; i < arr->count; i += 1) + { + RenderTargetHash *e = &arr->elements[i].key; + if (RenderTargetHash_Compare(e, key)) + { + return arr->elements[i].value; + } + } + + return NULL; +} + +static inline void RenderTargetHash_Insert( + RenderTargetHashArray *arr, + RenderTargetHash key, + VulkanRenderTarget *value +) { + RenderTargetHashMap map; + map.key = key; + map.value = value; + + EXPAND_ELEMENTS_IF_NEEDED(arr, 4, RenderTargetHashMap) + + arr->elements[arr->count] = map; + arr->count += 1; +} + +static inline void RenderTargetHash_Remove( + RenderTargetHashArray *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 @@ -1344,17 +1453,24 @@ typedef struct VulkanCommandBuffer uint8_t submitted; uint8_t renderPassInProgress; - uint8_t present; - void *presentWindowHandle; - uint32_t presentSwapchainImageIndex; - uint8_t needNewSwapchain; - VulkanCommandPool *commandPool; + VulkanPresentData *presentDatas; + uint32_t presentDataCount; + uint32_t presentDataCapacity; + + VkSemaphore *waitSemaphores; + uint32_t waitSemaphoreCount; + uint32_t waitSemaphoreCapacity; + + VkSemaphore *signalSemaphores; + uint32_t signalSemaphoreCount; + uint32_t signalSemaphoreCapacity; + VulkanComputePipeline *currentComputePipeline; VulkanGraphicsPipeline *currentGraphicsPipeline; - VulkanRenderTarget *renderPassColorTargets[MAX_COLOR_TARGET_BINDINGS]; + VulkanTexture *renderPassColorTargetTextures[MAX_COLOR_TARGET_BINDINGS]; uint32_t renderPassColorTargetCount; VulkanUniformBuffer *vertexUniformBuffer; @@ -1380,10 +1496,6 @@ typedef struct VulkanCommandBuffer /* Deferred destroy storage */ - VulkanRenderTarget **renderTargetsToDestroy; - uint32_t renderTargetsToDestroyCount; - uint32_t renderTargetsToDestroyCapacity; - VulkanTexture **texturesToDestroy; uint32_t texturesToDestroyCount; uint32_t texturesToDestroyCapacity; @@ -1536,6 +1648,7 @@ typedef struct VulkanRenderer ComputePipelineLayoutHashTable computePipelineLayoutHashTable; RenderPassHashArray renderPassHashArray; FramebufferHashArray framebufferHashArray; + RenderTargetHashArray renderTargetHashArray; VkDescriptorPool defaultDescriptorPool; @@ -1568,6 +1681,7 @@ typedef struct VulkanRenderer SDL_mutex *acquireCommandBufferLock; SDL_mutex *renderPassFetchLock; SDL_mutex *framebufferFetchLock; + SDL_mutex *renderTargetFetchLock; #define VULKAN_INSTANCE_FUNCTION(ext, ret, func, params) \ vkfntype_##func func; @@ -2487,6 +2601,7 @@ static void VULKAN_INTERNAL_ImageMemoryBarrier( /* Resource Disposal */ +/* TODO: destroy associated framebuffers and render targets */ static void VULKAN_INTERNAL_DestroyTexture( VulkanRenderer* renderer, VulkanTexture* texture @@ -2531,23 +2646,22 @@ static void VULKAN_INTERNAL_DestroyTexture( SDL_free(texture); } -static void VULKAN_INTERNAL_DestroyRenderTarget( +static void VULKAN_INTERNAL_RemoveFramebuffersContainingView( VulkanRenderer *renderer, - VulkanRenderTarget *renderTarget + VkImageView view ) { - int32_t i, j; FramebufferHash *hash; + int32_t i, j; SDL_LockMutex(renderer->framebufferFetchLock); - /* Remove all associated framebuffers */ for (i = renderer->framebufferHashArray.count - 1; i >= 0; i -= 1) { hash = &renderer->framebufferHashArray.elements[i].key; for (j = 0; j < hash->colorAttachmentCount; j += 1) { - if (hash->colorAttachmentViews[i] == renderTarget->view) + if (hash->colorAttachmentViews[i] == view) { renderer->vkDestroyFramebuffer( renderer->logicalDevice, @@ -2566,6 +2680,16 @@ static void VULKAN_INTERNAL_DestroyRenderTarget( } SDL_UnlockMutex(renderer->framebufferFetchLock); +} + +static void VULKAN_INTERNAL_DestroyRenderTarget( + VulkanRenderer *renderer, + VulkanRenderTarget *renderTarget +) { + VULKAN_INTERNAL_RemoveFramebuffersContainingView( + renderer, + renderTarget->view + ); renderer->vkDestroyImageView( renderer->logicalDevice, @@ -2646,7 +2770,6 @@ static void VULKAN_INTERNAL_DestroyCommandPool( SDL_free(commandBuffer->transferBuffers); SDL_free(commandBuffer->boundUniformBuffers); SDL_free(commandBuffer->boundDescriptorSetDatas); - SDL_free(commandBuffer->renderTargetsToDestroy); SDL_free(commandBuffer->texturesToDestroy); SDL_free(commandBuffer->buffersToDestroy); SDL_free(commandBuffer->graphicsPipelinesToDestroy); @@ -2725,6 +2848,11 @@ static void VULKAN_INTERNAL_DestroySwapchain( for (i = 0; i < swapchainData->imageCount; i += 1) { + VULKAN_INTERNAL_RemoveFramebuffersContainingView( + renderer, + swapchainData->textures[i].view + ); + renderer->vkDestroyImageView( renderer->logicalDevice, swapchainData->textures[i].view, @@ -4068,6 +4196,7 @@ static CreateSwapchainResult VULKAN_INTERNAL_CreateSwapchain( swapchainData->textures[i].usageFlags = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; + swapchainData->textures[i].resourceAccessType = RESOURCE_ACCESS_NONE; } SDL_stack_free(swapchainImages); @@ -4091,6 +4220,7 @@ static CreateSwapchainResult VULKAN_INTERNAL_CreateSwapchain( ); swapchainData->inFlightFence = VK_NULL_HANDLE; + swapchainData->needsRecreate = 0; SDL_SetWindowData(windowHandle, WINDOW_SWAPCHAIN_DATA, swapchainData); @@ -4432,6 +4562,7 @@ static void VULKAN_DestroyDevice( SDL_DestroyMutex(renderer->acquireCommandBufferLock); SDL_DestroyMutex(renderer->renderPassFetchLock); SDL_DestroyMutex(renderer->framebufferFetchLock); + SDL_DestroyMutex(renderer->renderTargetFetchLock); renderer->vkDestroyDevice(renderer->logicalDevice, NULL); renderer->vkDestroyInstance(renderer->instance, NULL); @@ -4702,6 +4833,337 @@ static void VULKAN_DispatchCompute( ); } +static VulkanTexture* VULKAN_INTERNAL_CreateTexture( + VulkanRenderer *renderer, + uint32_t width, + uint32_t height, + uint32_t depth, + uint32_t isCube, + VkSampleCountFlagBits samples, + uint32_t levelCount, + VkFormat format, + VkImageAspectFlags aspectMask, + VkImageType imageType, + VkImageUsageFlags imageUsageFlags +) { + VkResult vulkanResult; + VkImageCreateInfo imageCreateInfo; + VkImageCreateFlags imageCreateFlags = 0; + VkImageViewCreateInfo imageViewCreateInfo; + uint8_t findMemoryResult; + uint8_t is3D = depth > 1 ? 1 : 0; + uint8_t layerCount = isCube ? 6 : 1; + uint8_t isRenderTarget = + ((imageUsageFlags & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) != 0) || + ((imageUsageFlags & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) != 0); + VkComponentMapping swizzle = IDENTITY_SWIZZLE; + + VulkanTexture *texture = SDL_malloc(sizeof(VulkanTexture)); + + texture->isCube = 0; + texture->is3D = 0; + + if (isCube) + { + imageCreateFlags |= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT; + texture->isCube = 1; + } + else if (is3D) + { + imageCreateFlags |= VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT; + texture->is3D = 1; + } + + imageCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; + imageCreateInfo.pNext = NULL; + imageCreateInfo.flags = imageCreateFlags; + imageCreateInfo.imageType = imageType; + imageCreateInfo.format = format; + imageCreateInfo.extent.width = width; + imageCreateInfo.extent.height = height; + imageCreateInfo.extent.depth = depth; + imageCreateInfo.mipLevels = levelCount; + imageCreateInfo.arrayLayers = layerCount; + imageCreateInfo.samples = samples; + imageCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL; + imageCreateInfo.usage = imageUsageFlags; + imageCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + imageCreateInfo.queueFamilyIndexCount = 0; + imageCreateInfo.pQueueFamilyIndices = NULL; + imageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + + vulkanResult = renderer->vkCreateImage( + renderer->logicalDevice, + &imageCreateInfo, + NULL, + &texture->image + ); + + if (vulkanResult != VK_SUCCESS) + { + LogVulkanResultAsError("vkCreateImage", vulkanResult); + Refresh_LogError("Failed to create texture!"); + } + + /* Prefer GPU allocation */ + findMemoryResult = VULKAN_INTERNAL_FindAvailableTextureMemory( + renderer, + texture->image, + 0, + &texture->allocation, + &texture->offset, + &texture->memorySize + ); + + /* No device local memory available */ + if (findMemoryResult == 2) + { + if (isRenderTarget) + { + Refresh_LogWarn("RenderTarget is allocated in host memory, pre-allocate your targets!"); + } + + Refresh_LogWarn("Out of device local memory, falling back to host memory"); + + /* Attempt CPU allocation */ + findMemoryResult = VULKAN_INTERNAL_FindAvailableTextureMemory( + renderer, + texture->image, + 1, + &texture->allocation, + &texture->offset, + &texture->memorySize + ); + + /* Memory alloc completely failed, time to die */ + if (findMemoryResult == 0) + { + Refresh_LogError("Something went very wrong allocating memory!"); + return 0; + } + else if (findMemoryResult == 2) + { + Refresh_LogError("Out of memory!"); + return 0; + } + } + + SDL_LockMutex(texture->allocation->memoryLock); + + vulkanResult = renderer->vkBindImageMemory( + renderer->logicalDevice, + texture->image, + texture->allocation->memory, + texture->offset + ); + + SDL_UnlockMutex(texture->allocation->memoryLock); + + if (vulkanResult != VK_SUCCESS) + { + LogVulkanResultAsError("vkBindImageMemory", vulkanResult); + Refresh_LogError("Failed to bind texture memory!"); + return 0; + } + + imageViewCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + imageViewCreateInfo.pNext = NULL; + imageViewCreateInfo.flags = 0; + imageViewCreateInfo.image = texture->image; + imageViewCreateInfo.format = format; + imageViewCreateInfo.components = swizzle; + imageViewCreateInfo.subresourceRange.aspectMask = aspectMask; + imageViewCreateInfo.subresourceRange.baseMipLevel = 0; + imageViewCreateInfo.subresourceRange.levelCount = levelCount; + imageViewCreateInfo.subresourceRange.baseArrayLayer = 0; + imageViewCreateInfo.subresourceRange.layerCount = layerCount; + + if (isCube) + { + imageViewCreateInfo.viewType = VK_IMAGE_VIEW_TYPE_CUBE; + } + else if (imageType == VK_IMAGE_TYPE_2D) + { + imageViewCreateInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; + } + else if (imageType == VK_IMAGE_TYPE_3D) + { + imageViewCreateInfo.viewType = VK_IMAGE_VIEW_TYPE_3D; + } + else + { + Refresh_LogError("invalid image type: %u", imageType); + } + + vulkanResult = renderer->vkCreateImageView( + renderer->logicalDevice, + &imageViewCreateInfo, + NULL, + &texture->view + ); + + if (vulkanResult != VK_SUCCESS) + { + LogVulkanResultAsError("vkCreateImageView", vulkanResult); + Refresh_LogError("Failed to create texture image view"); + return 0; + } + + texture->dimensions.width = width; + texture->dimensions.height = height; + texture->depth = depth; + texture->format = format; + texture->levelCount = levelCount; + texture->layerCount = layerCount; + texture->resourceAccessType = RESOURCE_ACCESS_NONE; + texture->usageFlags = imageUsageFlags; + + return texture; +} + +static VulkanRenderTarget* VULKAN_INTERNAL_CreateRenderTarget( + VulkanRenderer *renderer, + Refresh_Texture *texture, + uint32_t depth, + uint32_t layer, + uint32_t level, + Refresh_SampleCount multisampleCount +) { + 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)) + { + aspectFlags |= VK_IMAGE_ASPECT_DEPTH_BIT; + + if (IsStencilFormat(vulkanTexture->format)) + { + aspectFlags |= VK_IMAGE_ASPECT_STENCIL_BIT; + } + } + else + { + aspectFlags |= VK_IMAGE_ASPECT_COLOR_BIT; + } + + + /* create resolve target for multisample */ + if (multisampleCount > REFRESH_SAMPLECOUNT_1) + { + renderTarget->multisampleTexture = + VULKAN_INTERNAL_CreateTexture( + renderer, + vulkanTexture->dimensions.width, + vulkanTexture->dimensions.height, + 1, + 0, + RefreshToVK_SampleCount[multisampleCount], + 1, + vulkanTexture->format, + aspectFlags, + VK_IMAGE_TYPE_2D, + VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT + ); + + renderTarget->multisampleCount = 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.components = swizzle; + imageViewCreateInfo.subresourceRange.aspectMask = aspectFlags; + imageViewCreateInfo.subresourceRange.baseMipLevel = level; + imageViewCreateInfo.subresourceRange.levelCount = 1; + imageViewCreateInfo.subresourceRange.baseArrayLayer = 0; + if (vulkanTexture->is3D) + { + imageViewCreateInfo.subresourceRange.baseArrayLayer = depth; + } + else if (vulkanTexture->isCube) + { + imageViewCreateInfo.subresourceRange.baseArrayLayer = layer; + } + imageViewCreateInfo.subresourceRange.layerCount = 1; + imageViewCreateInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; + + vulkanResult = renderer->vkCreateImageView( + renderer->logicalDevice, + &imageViewCreateInfo, + NULL, + &renderTarget->view + ); + + if (vulkanResult != VK_SUCCESS) + { + LogVulkanResultAsError( + "vkCreateImageView", + vulkanResult + ); + Refresh_LogError("Failed to create color attachment image view"); + return NULL; + } + + return renderTarget; +} + +static VulkanRenderTarget* VULKAN_INTERNAL_FetchRenderTarget( + VulkanRenderer *renderer, + Refresh_Texture *texture, + uint32_t depth, + uint32_t layer, + uint32_t level, + Refresh_SampleCount sampleCount +) { + RenderTargetHash hash; + VulkanRenderTarget *renderTarget; + + hash.texture = texture; + hash.depth = depth; + hash.layer = layer; + hash.level = level; + hash.sampleCount = sampleCount; + + SDL_LockMutex(renderer->renderTargetFetchLock); + + renderTarget = RenderTargetHash_Fetch( + &renderer->renderTargetHashArray, + &hash + ); + + if (renderTarget == NULL) + { + renderTarget = VULKAN_INTERNAL_CreateRenderTarget( + renderer, + texture, + depth, + layer, + level, + sampleCount + ); + + RenderTargetHash_Insert( + &renderer->renderTargetHashArray, + hash, + renderTarget + ); + } + + SDL_UnlockMutex(renderer->renderTargetFetchLock); + + return renderTarget; +} + static VkRenderPass VULKAN_INTERNAL_CreateRenderPass( VulkanRenderer *renderer, Refresh_ColorAttachmentInfo *colorAttachmentInfos, @@ -4723,21 +5185,30 @@ static VkRenderPass VULKAN_INTERNAL_CreateRenderPass( uint32_t colorAttachmentReferenceCount = 0; uint32_t resolveReferenceCount = 0; - VulkanRenderTarget *colorTarget; - VulkanRenderTarget *depthStencilTarget; + VulkanRenderTarget *renderTarget; + VulkanTexture *texture; for (i = 0; i < colorAttachmentCount; i += 1) { - colorTarget = (VulkanRenderTarget*) colorAttachmentInfos[attachmentDescriptionCount].pRenderTarget; + texture = (VulkanTexture*) colorAttachmentInfos[i].texture; - if (colorTarget->multisampleCount > VK_SAMPLE_COUNT_1_BIT) + 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) { multisampling = 1; /* Resolve attachment and multisample attachment */ attachmentDescriptions[attachmentDescriptionCount].flags = 0; - attachmentDescriptions[attachmentDescriptionCount].format = colorTarget->texture->format; + attachmentDescriptions[attachmentDescriptionCount].format = texture->format; attachmentDescriptions[attachmentDescriptionCount].samples = VK_SAMPLE_COUNT_1_BIT; attachmentDescriptions[attachmentDescriptionCount].loadOp = RefreshToVK_LoadOp[ @@ -4764,8 +5235,8 @@ static VkRenderPass VULKAN_INTERNAL_CreateRenderPass( resolveReferenceCount += 1; attachmentDescriptions[attachmentDescriptionCount].flags = 0; - attachmentDescriptions[attachmentDescriptionCount].format = colorTarget->texture->format; - attachmentDescriptions[attachmentDescriptionCount].samples = colorTarget->multisampleCount; + attachmentDescriptions[attachmentDescriptionCount].format = texture->format; + attachmentDescriptions[attachmentDescriptionCount].samples = renderTarget->multisampleCount; attachmentDescriptions[attachmentDescriptionCount].loadOp = RefreshToVK_LoadOp[ colorAttachmentInfos[i].loadOp ]; @@ -4792,7 +5263,7 @@ static VkRenderPass VULKAN_INTERNAL_CreateRenderPass( else { attachmentDescriptions[attachmentDescriptionCount].flags = 0; - attachmentDescriptions[attachmentDescriptionCount].format = colorTarget->texture->format; + attachmentDescriptions[attachmentDescriptionCount].format = texture->format; attachmentDescriptions[attachmentDescriptionCount].samples = VK_SAMPLE_COUNT_1_BIT; attachmentDescriptions[attachmentDescriptionCount].loadOp = RefreshToVK_LoadOp[ @@ -4835,11 +5306,21 @@ static VkRenderPass VULKAN_INTERNAL_CreateRenderPass( } else { - depthStencilTarget = (VulkanRenderTarget*) depthStencilAttachmentInfo->pDepthStencilTarget; + renderTarget = VULKAN_INTERNAL_FetchRenderTarget( + renderer, + depthStencilAttachmentInfo->texture, + depthStencilAttachmentInfo->depth, + depthStencilAttachmentInfo->layer, + depthStencilAttachmentInfo->level, + REFRESH_SAMPLECOUNT_1 + ); + + texture = (VulkanTexture*) depthStencilAttachmentInfo->texture; + attachmentDescriptions[attachmentDescriptionCount].flags = 0; - attachmentDescriptions[attachmentDescriptionCount].format = depthStencilTarget->texture->format; + attachmentDescriptions[attachmentDescriptionCount].format = texture->format; attachmentDescriptions[attachmentDescriptionCount].samples = - VK_SAMPLE_COUNT_1_BIT; /* FIXME: do these take multisamples? */ + VK_SAMPLE_COUNT_1_BIT; attachmentDescriptions[attachmentDescriptionCount].loadOp = RefreshToVK_LoadOp[ depthStencilAttachmentInfo->loadOp ]; @@ -5691,194 +6172,6 @@ static Refresh_ShaderModule* VULKAN_CreateShaderModule( return (Refresh_ShaderModule*) shaderModule; } -static VulkanTexture* VULKAN_INTERNAL_CreateTexture( - VulkanRenderer *renderer, - uint32_t width, - uint32_t height, - uint32_t depth, - uint32_t isCube, - VkSampleCountFlagBits samples, - uint32_t levelCount, - VkFormat format, - VkImageAspectFlags aspectMask, - VkImageType imageType, - VkImageUsageFlags imageUsageFlags -) { - VkResult vulkanResult; - VkImageCreateInfo imageCreateInfo; - VkImageCreateFlags imageCreateFlags = 0; - VkImageViewCreateInfo imageViewCreateInfo; - uint8_t findMemoryResult; - uint8_t is3D = depth > 1 ? 1 : 0; - uint8_t layerCount = isCube ? 6 : 1; - uint8_t isRenderTarget = - ((imageUsageFlags & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) != 0) || - ((imageUsageFlags & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) != 0); - VkComponentMapping swizzle = IDENTITY_SWIZZLE; - - VulkanTexture *texture = SDL_malloc(sizeof(VulkanTexture)); - - texture->isCube = 0; - texture->is3D = 0; - - if (isCube) - { - imageCreateFlags |= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT; - texture->isCube = 1; - } - else if (is3D) - { - imageCreateFlags |= VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT; - texture->is3D = 1; - } - - imageCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; - imageCreateInfo.pNext = NULL; - imageCreateInfo.flags = imageCreateFlags; - imageCreateInfo.imageType = imageType; - imageCreateInfo.format = format; - imageCreateInfo.extent.width = width; - imageCreateInfo.extent.height = height; - imageCreateInfo.extent.depth = depth; - imageCreateInfo.mipLevels = levelCount; - imageCreateInfo.arrayLayers = layerCount; - imageCreateInfo.samples = samples; - imageCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL; - imageCreateInfo.usage = imageUsageFlags; - imageCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - imageCreateInfo.queueFamilyIndexCount = 0; - imageCreateInfo.pQueueFamilyIndices = NULL; - imageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - - vulkanResult = renderer->vkCreateImage( - renderer->logicalDevice, - &imageCreateInfo, - NULL, - &texture->image - ); - - if (vulkanResult != VK_SUCCESS) - { - LogVulkanResultAsError("vkCreateImage", vulkanResult); - Refresh_LogError("Failed to create texture!"); - } - - /* Prefer GPU allocation */ - findMemoryResult = VULKAN_INTERNAL_FindAvailableTextureMemory( - renderer, - texture->image, - 0, - &texture->allocation, - &texture->offset, - &texture->memorySize - ); - - /* No device local memory available */ - if (findMemoryResult == 2) - { - if (isRenderTarget) - { - Refresh_LogWarn("RenderTarget is allocated in host memory, pre-allocate your targets!"); - } - - Refresh_LogWarn("Out of device local memory, falling back to host memory"); - - /* Attempt CPU allocation */ - findMemoryResult = VULKAN_INTERNAL_FindAvailableTextureMemory( - renderer, - texture->image, - 1, - &texture->allocation, - &texture->offset, - &texture->memorySize - ); - - /* Memory alloc completely failed, time to die */ - if (findMemoryResult == 0) - { - Refresh_LogError("Something went very wrong allocating memory!"); - return 0; - } - else if (findMemoryResult == 2) - { - Refresh_LogError("Out of memory!"); - return 0; - } - } - - SDL_LockMutex(texture->allocation->memoryLock); - - vulkanResult = renderer->vkBindImageMemory( - renderer->logicalDevice, - texture->image, - texture->allocation->memory, - texture->offset - ); - - SDL_UnlockMutex(texture->allocation->memoryLock); - - if (vulkanResult != VK_SUCCESS) - { - LogVulkanResultAsError("vkBindImageMemory", vulkanResult); - Refresh_LogError("Failed to bind texture memory!"); - return 0; - } - - imageViewCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; - imageViewCreateInfo.pNext = NULL; - imageViewCreateInfo.flags = 0; - imageViewCreateInfo.image = texture->image; - imageViewCreateInfo.format = format; - imageViewCreateInfo.components = swizzle; - imageViewCreateInfo.subresourceRange.aspectMask = aspectMask; - imageViewCreateInfo.subresourceRange.baseMipLevel = 0; - imageViewCreateInfo.subresourceRange.levelCount = levelCount; - imageViewCreateInfo.subresourceRange.baseArrayLayer = 0; - imageViewCreateInfo.subresourceRange.layerCount = layerCount; - - if (isCube) - { - imageViewCreateInfo.viewType = VK_IMAGE_VIEW_TYPE_CUBE; - } - else if (imageType == VK_IMAGE_TYPE_2D) - { - imageViewCreateInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; - } - else if (imageType == VK_IMAGE_TYPE_3D) - { - imageViewCreateInfo.viewType = VK_IMAGE_VIEW_TYPE_3D; - } - else - { - Refresh_LogError("invalid image type: %u", imageType); - } - - vulkanResult = renderer->vkCreateImageView( - renderer->logicalDevice, - &imageViewCreateInfo, - NULL, - &texture->view - ); - - if (vulkanResult != VK_SUCCESS) - { - LogVulkanResultAsError("vkCreateImageView", vulkanResult); - Refresh_LogError("Failed to create texture image view"); - return 0; - } - - texture->dimensions.width = width; - texture->dimensions.height = height; - texture->depth = depth; - texture->format = format; - texture->levelCount = levelCount; - texture->layerCount = layerCount; - texture->resourceAccessType = RESOURCE_ACCESS_NONE; - texture->usageFlags = imageUsageFlags; - - return texture; -} - static Refresh_Texture* VULKAN_CreateTexture( Refresh_Renderer *driverData, Refresh_TextureCreateInfo *textureCreateInfo @@ -5935,101 +6228,6 @@ static Refresh_Texture* VULKAN_CreateTexture( ); } -static Refresh_RenderTarget* VULKAN_CreateRenderTarget( - Refresh_Renderer *driverData, - Refresh_TextureSlice *textureSlice, - Refresh_SampleCount multisampleCount -) { - VkResult vulkanResult; - VulkanRenderer *renderer = (VulkanRenderer*) driverData; - VulkanRenderTarget *renderTarget = (VulkanRenderTarget*) SDL_malloc(sizeof(VulkanRenderTarget)); - VkImageViewCreateInfo imageViewCreateInfo; - VkComponentMapping swizzle = IDENTITY_SWIZZLE; - VkImageAspectFlags aspectFlags = 0; - - renderTarget->texture = (VulkanTexture*) textureSlice->texture; - renderTarget->layer = textureSlice->layer; - renderTarget->multisampleTexture = NULL; - renderTarget->multisampleCount = 1; - - if (IsDepthFormat(renderTarget->texture->format)) - { - aspectFlags |= VK_IMAGE_ASPECT_DEPTH_BIT; - - if (IsStencilFormat(renderTarget->texture->format)) - { - aspectFlags |= VK_IMAGE_ASPECT_STENCIL_BIT; - } - } - else - { - aspectFlags |= VK_IMAGE_ASPECT_COLOR_BIT; - } - - - /* create resolve target for multisample */ - if (multisampleCount > REFRESH_SAMPLECOUNT_1) - { - renderTarget->multisampleTexture = - VULKAN_INTERNAL_CreateTexture( - renderer, - renderTarget->texture->dimensions.width, - renderTarget->texture->dimensions.height, - 1, - 0, - RefreshToVK_SampleCount[multisampleCount], - 1, - renderTarget->texture->format, - aspectFlags, - VK_IMAGE_TYPE_2D, - VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT - ); - - renderTarget->multisampleCount = multisampleCount; - } - - /* create framebuffer compatible views for RenderTarget */ - imageViewCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; - imageViewCreateInfo.pNext = NULL; - imageViewCreateInfo.flags = 0; - imageViewCreateInfo.image = renderTarget->texture->image; - imageViewCreateInfo.format = renderTarget->texture->format; - imageViewCreateInfo.components = swizzle; - imageViewCreateInfo.subresourceRange.aspectMask = aspectFlags; - imageViewCreateInfo.subresourceRange.baseMipLevel = 0; - imageViewCreateInfo.subresourceRange.levelCount = 1; - imageViewCreateInfo.subresourceRange.baseArrayLayer = 0; - if (renderTarget->texture->is3D) - { - imageViewCreateInfo.subresourceRange.baseArrayLayer = textureSlice->depth; - } - else if (renderTarget->texture->isCube) - { - imageViewCreateInfo.subresourceRange.baseArrayLayer = textureSlice->layer; - } - imageViewCreateInfo.subresourceRange.layerCount = 1; - imageViewCreateInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; - - vulkanResult = renderer->vkCreateImageView( - renderer->logicalDevice, - &imageViewCreateInfo, - NULL, - &renderTarget->view - ); - - if (vulkanResult != VK_SUCCESS) - { - LogVulkanResultAsError( - "vkCreateImageView", - vulkanResult - ); - Refresh_LogError("Failed to create color attachment image view"); - return NULL; - } - - return (Refresh_RenderTarget*) renderTarget; -} - static Refresh_Buffer* VULKAN_CreateBuffer( Refresh_Renderer *driverData, Refresh_BufferUsageFlags usageFlags, @@ -7205,26 +7403,6 @@ static void VULKAN_QueueDestroyBuffer( vulkanCommandBuffer->buffersToDestroyCount += 1; } -static void VULKAN_QueueDestroyRenderTarget( - Refresh_Renderer *driverData, - Refresh_CommandBuffer *commandBuffer, - Refresh_RenderTarget *renderTarget -) { - VulkanCommandBuffer* vulkanCommandBuffer = (VulkanCommandBuffer*)commandBuffer; - VulkanRenderTarget *vulkanRenderTarget = (VulkanRenderTarget*) renderTarget; - - EXPAND_ARRAY_IF_NEEDED( - vulkanCommandBuffer->renderTargetsToDestroy, - VulkanRenderTarget*, - vulkanCommandBuffer->renderTargetsToDestroyCount + 1, - vulkanCommandBuffer->renderTargetsToDestroyCapacity, - vulkanCommandBuffer->renderTargetsToDestroyCapacity * 2 - ) - - vulkanCommandBuffer->renderTargetsToDestroy[vulkanCommandBuffer->renderTargetsToDestroyCount] = vulkanRenderTarget; - vulkanCommandBuffer->renderTargetsToDestroyCount += 1; -} - static void VULKAN_QueueDestroyShaderModule( Refresh_Renderer *driverData, Refresh_CommandBuffer *commandBuffer, @@ -7367,7 +7545,10 @@ static VkFramebuffer VULKAN_INTERNAL_FetchFramebuffer( VkImageView imageViewAttachments[2 * MAX_COLOR_TARGET_BINDINGS + 1]; FramebufferHash hash; VulkanRenderTarget *renderTarget; + VulkanTexture *texture; uint32_t attachmentCount = 0; + uint32_t maxWidth = 0; + uint32_t maxHeight = 0; uint32_t i; SDL_LockMutex(renderer->framebufferFetchLock); @@ -7382,7 +7563,16 @@ static VkFramebuffer VULKAN_INTERNAL_FetchFramebuffer( for (i = 0; i < colorAttachmentCount; i += 1) { - renderTarget = (VulkanRenderTarget*) colorAttachmentInfos[i].pRenderTarget; + renderTarget = VULKAN_INTERNAL_FetchRenderTarget( + renderer, + colorAttachmentInfos[i].texture, + colorAttachmentInfos[i].depth, + colorAttachmentInfos[i].layer, + colorAttachmentInfos[i].level, + colorAttachmentInfos[i].sampleCount + ); + + texture = (VulkanTexture*) colorAttachmentInfos[i].texture; hash.colorAttachmentViews[i] = ( renderTarget->view @@ -7394,6 +7584,16 @@ static VkFramebuffer VULKAN_INTERNAL_FetchFramebuffer( renderTarget->multisampleTexture->view ); } + + if (texture->dimensions.width > maxWidth) + { + maxWidth = texture->dimensions.width; + } + + if (texture->dimensions.height > maxHeight) + { + maxHeight = texture->dimensions.height; + } } if (depthStencilAttachmentInfo == NULL) @@ -7402,20 +7602,29 @@ static VkFramebuffer VULKAN_INTERNAL_FetchFramebuffer( } else { - hash.depthStencilAttachmentView = ((VulkanRenderTarget*)depthStencilAttachmentInfo->pDepthStencilTarget)->view; + renderTarget = VULKAN_INTERNAL_FetchRenderTarget( + renderer, + depthStencilAttachmentInfo->texture, + depthStencilAttachmentInfo->depth, + depthStencilAttachmentInfo->layer, + depthStencilAttachmentInfo->level, + REFRESH_SAMPLECOUNT_1 + ); + hash.depthStencilAttachmentView = renderTarget->view; + + if (texture->dimensions.width > maxWidth) + { + maxWidth = texture->dimensions.width; + } + + if (texture->dimensions.height > maxHeight) + { + maxHeight = texture->dimensions.height; + } } - 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; + hash.width = maxWidth; + hash.height = maxHeight; framebuffer = FramebufferHashArray_Fetch( &renderer->framebufferHashArray, @@ -7432,7 +7641,14 @@ static VkFramebuffer VULKAN_INTERNAL_FetchFramebuffer( for (i = 0; i < colorAttachmentCount; i += 1) { - renderTarget = (VulkanRenderTarget*) colorAttachmentInfos[i].pRenderTarget; + renderTarget = VULKAN_INTERNAL_FetchRenderTarget( + renderer, + colorAttachmentInfos[i].texture, + colorAttachmentInfos[i].depth, + colorAttachmentInfos[i].layer, + colorAttachmentInfos[i].level, + colorAttachmentInfos[i].sampleCount + ); imageViewAttachments[attachmentCount] = renderTarget->view; @@ -7450,7 +7666,14 @@ static VkFramebuffer VULKAN_INTERNAL_FetchFramebuffer( if (depthStencilAttachmentInfo != NULL) { - renderTarget = (VulkanRenderTarget*) depthStencilAttachmentInfo->pDepthStencilTarget; + renderTarget = VULKAN_INTERNAL_FetchRenderTarget( + renderer, + depthStencilAttachmentInfo->texture, + depthStencilAttachmentInfo->depth, + depthStencilAttachmentInfo->layer, + depthStencilAttachmentInfo->level, + REFRESH_SAMPLECOUNT_1 + ); imageViewAttachments[attachmentCount] = renderTarget->view; @@ -7505,7 +7728,7 @@ static void VULKAN_BeginRenderPass( VkRenderPass renderPass; VkFramebuffer framebuffer; - VulkanRenderTarget *depthStencilTarget; + VulkanTexture *texture; VkClearValue *clearValues; uint32_t clearCount = colorAttachmentCount; uint32_t i; @@ -7536,7 +7759,7 @@ static void VULKAN_BeginRenderPass( for (i = 0; i < colorAttachmentCount; i += 1) { - VulkanRenderTarget *colorTarget = (VulkanRenderTarget*) colorAttachmentInfos->pRenderTarget; + texture = (VulkanTexture*) colorAttachmentInfos[i].texture; VULKAN_INTERNAL_ImageMemoryBarrier( renderer, @@ -7544,22 +7767,22 @@ static void VULKAN_BeginRenderPass( RESOURCE_ACCESS_COLOR_ATTACHMENT_READ_WRITE, VK_IMAGE_ASPECT_COLOR_BIT, 0, - colorTarget->texture->layerCount, + texture->layerCount, 0, - colorTarget->texture->levelCount, + texture->levelCount, 0, - colorTarget->texture->image, - &colorTarget->texture->resourceAccessType + texture->image, + &texture->resourceAccessType ); } if (depthStencilAttachmentInfo != NULL) { - depthStencilTarget = (VulkanRenderTarget*) depthStencilAttachmentInfo->pDepthStencilTarget; + texture = (VulkanTexture*) depthStencilAttachmentInfo->texture; depthAspectFlags = VK_IMAGE_ASPECT_DEPTH_BIT; if (IsStencilFormat( - depthStencilTarget->texture->format + texture->format )) { depthAspectFlags |= VK_IMAGE_ASPECT_STENCIL_BIT; } @@ -7570,12 +7793,12 @@ static void VULKAN_BeginRenderPass( RESOURCE_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_WRITE, depthAspectFlags, 0, - depthStencilTarget->texture->layerCount, + texture->layerCount, 0, - depthStencilTarget->texture->levelCount, + texture->levelCount, 0, - depthStencilTarget->texture->image, - &depthStencilTarget->texture->resourceAccessType + texture->image, + &texture->resourceAccessType ); clearCount += 1; @@ -7596,9 +7819,9 @@ static void VULKAN_BeginRenderPass( if (depthStencilAttachmentInfo != NULL) { clearValues[colorAttachmentCount].depthStencil.depth = - depthStencilAttachmentInfo->depthStencilValue.depth; + depthStencilAttachmentInfo->depthStencilClearValue.depth; clearValues[colorAttachmentCount].depthStencil.stencil = - depthStencilAttachmentInfo->depthStencilValue.stencil; + depthStencilAttachmentInfo->depthStencilClearValue.stencil; } VkRenderPassBeginInfo renderPassBeginInfo; @@ -7625,8 +7848,8 @@ static void VULKAN_BeginRenderPass( for (i = 0; i < colorAttachmentCount; i += 1) { - vulkanCommandBuffer->renderPassColorTargets[i] = - (VulkanRenderTarget*) colorAttachmentInfos[i].pRenderTarget; + vulkanCommandBuffer->renderPassColorTargetTextures[i] = + (VulkanTexture*) colorAttachmentInfos[i].texture; } vulkanCommandBuffer->renderPassColorTargetCount = colorAttachmentCount; } @@ -7667,7 +7890,7 @@ static void VULKAN_EndRenderPass( /* If the render targets can be sampled, transition them to sample layout */ for (i = 0; i < vulkanCommandBuffer->renderPassColorTargetCount; i += 1) { - currentTexture = vulkanCommandBuffer->renderPassColorTargets[i]->texture; + currentTexture = vulkanCommandBuffer->renderPassColorTargetTextures[i]; if (currentTexture->usageFlags & VK_IMAGE_USAGE_SAMPLED_BIT) { @@ -8001,10 +8224,25 @@ static void VULKAN_INTERNAL_AllocateCommandBuffers( commandBuffer->commandPool = vulkanCommandPool; commandBuffer->commandBuffer = commandBuffers[i]; - commandBuffer->present = 0; - commandBuffer->presentWindowHandle = NULL; - commandBuffer->presentSwapchainImageIndex = 0; - commandBuffer->needNewSwapchain = 0; + /* Presentation tracking */ + + commandBuffer->presentDataCapacity = 1; + commandBuffer->presentDataCount = 0; + commandBuffer->presentDatas = SDL_malloc( + commandBuffer->presentDataCapacity * sizeof(VkPresentInfoKHR) + ); + + commandBuffer->waitSemaphoreCapacity = 1; + commandBuffer->waitSemaphoreCount = 0; + commandBuffer->waitSemaphores = SDL_malloc( + commandBuffer->waitSemaphoreCapacity * sizeof(VkSemaphore) + ); + + commandBuffer->signalSemaphoreCapacity = 1; + commandBuffer->signalSemaphoreCount = 0; + commandBuffer->signalSemaphores = SDL_malloc( + commandBuffer->signalSemaphoreCapacity * sizeof(VkSemaphore) + ); /* Transfer buffer tracking */ @@ -8032,14 +8270,6 @@ static void VULKAN_INTERNAL_AllocateCommandBuffers( /* Deferred destroy storage */ - commandBuffer->renderTargetsToDestroyCapacity = 16; - commandBuffer->renderTargetsToDestroyCount = 0; - - commandBuffer->renderTargetsToDestroy = (VulkanRenderTarget**) SDL_malloc( - sizeof(VulkanRenderTarget*) * - commandBuffer->renderTargetsToDestroyCapacity - ); - commandBuffer->texturesToDestroyCapacity = 16; commandBuffer->texturesToDestroyCount = 0; @@ -8210,7 +8440,6 @@ static Refresh_CommandBuffer* VULKAN_AcquireCommandBuffer( commandBuffer->fixed = fixed; commandBuffer->submitted = 0; - commandBuffer->present = 0; commandBuffer->renderPassInProgress = 0; commandBuffer->renderPassColorTargetCount = 0; @@ -8230,33 +8459,20 @@ static Refresh_CommandBuffer* VULKAN_AcquireCommandBuffer( return (Refresh_CommandBuffer*) commandBuffer; } -static void VULKAN_QueuePresent( +static Refresh_Texture* VULKAN_AcquireSwapchainTexture( Refresh_Renderer *driverData, Refresh_CommandBuffer *commandBuffer, - Refresh_TextureSlice *textureSlice, - Refresh_Rect *destinationRectangle, - Refresh_Filter filter, void *windowHandle ) { - VkResult acquireResult; - Refresh_Rect dstRect; - - VulkanRenderer* renderer = (VulkanRenderer*) driverData; + VulkanRenderer *renderer = (VulkanRenderer*) driverData; VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer*) commandBuffer; - Refresh_TextureSlice destinationTextureSlice; + uint32_t swapchainImageIndex; VulkanSwapchainData *swapchainData = NULL; CreateSwapchainResult createSwapchainResult = 0; uint8_t validSwapchainExists = 1; - uint8_t acquireSuccess = 0; - uint32_t swapchainImageIndex; - - if (vulkanCommandBuffer->present) - { - Refresh_LogError("This command buffer already has a present queued!"); - return; - } - - vulkanCommandBuffer->presentWindowHandle = windowHandle; + VkResult acquireResult = VK_SUCCESS; + VulkanTexture *swapchainTexture = NULL; + VulkanPresentData *presentData; swapchainData = (VulkanSwapchainData*) SDL_GetWindowData(windowHandle, WINDOW_SWAPCHAIN_DATA); @@ -8293,49 +8509,73 @@ static void VULKAN_QueuePresent( if (acquireResult == VK_SUCCESS || acquireResult == VK_SUBOPTIMAL_KHR) { - if (destinationRectangle != NULL) - { - dstRect = *destinationRectangle; - } - else - { - dstRect.x = 0; - dstRect.y = 0; - dstRect.w = swapchainData->extent.width; - dstRect.h = swapchainData->extent.height; - } + swapchainTexture = &swapchainData->textures[swapchainImageIndex]; - /* Blit! */ - - destinationTextureSlice.depth = 0; - destinationTextureSlice.layer = 0; - destinationTextureSlice.level = 0; - destinationTextureSlice.rectangle = dstRect; - destinationTextureSlice.texture = (Refresh_Texture*) &swapchainData->textures[swapchainImageIndex]; - - VULKAN_INTERNAL_BlitImage( + VULKAN_INTERNAL_ImageMemoryBarrier( renderer, vulkanCommandBuffer->commandBuffer, - textureSlice, - &destinationTextureSlice, - RESOURCE_ACCESS_PRESENT, - RefreshToVK_Filter[filter] + RESOURCE_ACCESS_COLOR_ATTACHMENT_WRITE, + VK_IMAGE_ASPECT_COLOR_BIT, + 0, + 1, + 0, + 1, + 0, + swapchainTexture->image, + &swapchainTexture->resourceAccessType ); - acquireSuccess = 1; - } - } + /* Set up present struct */ - if (acquireSuccess) - { - vulkanCommandBuffer->present = 1; - vulkanCommandBuffer->presentSwapchainImageIndex = swapchainImageIndex; + if (vulkanCommandBuffer->presentDataCount == vulkanCommandBuffer->presentDataCapacity) + { + vulkanCommandBuffer->presentDataCapacity += 1; + vulkanCommandBuffer->presentDatas = SDL_realloc( + vulkanCommandBuffer->presentDatas, + vulkanCommandBuffer->presentDataCapacity * sizeof(VkPresentInfoKHR) + ); + } + + presentData = &vulkanCommandBuffer->presentDatas[vulkanCommandBuffer->presentDataCount]; + vulkanCommandBuffer->presentDataCount += 1; + + presentData->swapchainData = swapchainData; + presentData->swapchainImageIndex = swapchainImageIndex; + + /* Set up present semaphores */ + + if (vulkanCommandBuffer->waitSemaphoreCount == vulkanCommandBuffer->waitSemaphoreCapacity) + { + vulkanCommandBuffer->waitSemaphoreCapacity += 1; + vulkanCommandBuffer->waitSemaphores = SDL_realloc( + vulkanCommandBuffer->waitSemaphores, + vulkanCommandBuffer->waitSemaphoreCapacity * sizeof(VkSemaphore) + ); + } + + vulkanCommandBuffer->waitSemaphores[vulkanCommandBuffer->waitSemaphoreCount] = swapchainData->imageAvailableSemaphore; + vulkanCommandBuffer->waitSemaphoreCount += 1; + + if (vulkanCommandBuffer->signalSemaphoreCount == vulkanCommandBuffer->signalSemaphoreCapacity) + { + vulkanCommandBuffer->signalSemaphoreCapacity += 1; + vulkanCommandBuffer->signalSemaphores = SDL_realloc( + vulkanCommandBuffer->signalSemaphores, + vulkanCommandBuffer->signalSemaphoreCapacity * sizeof(VkSemaphore) + ); + } + + vulkanCommandBuffer->signalSemaphores[vulkanCommandBuffer->signalSemaphoreCount] = swapchainData->renderFinishedSemaphore; + vulkanCommandBuffer->signalSemaphoreCount += 1; + } } if (!validSwapchainExists || acquireResult == VK_SUBOPTIMAL_KHR) { - vulkanCommandBuffer->needNewSwapchain = 1; + swapchainData->needsRecreate = 1; } + + return (Refresh_Texture*) swapchainTexture; } /* Synchronization management */ @@ -8468,15 +8708,6 @@ static void VULKAN_INTERNAL_CleanCommandBuffer( /* Perform pending destroys */ - for (i = 0; i < commandBuffer->renderTargetsToDestroyCount; i += 1) - { - VULKAN_INTERNAL_DestroyRenderTarget( - renderer, - commandBuffer->renderTargetsToDestroy[i] - ); - } - commandBuffer->renderTargetsToDestroyCount = 0; - for (i = 0; i < commandBuffer->texturesToDestroyCount; i += 1) { VULKAN_INTERNAL_DestroyTexture( @@ -8566,6 +8797,9 @@ static void VULKAN_INTERNAL_CleanCommandBuffer( SDL_UnlockMutex(renderer->acquireFenceLock); commandBuffer->inFlightFence = VK_NULL_HANDLE; + commandBuffer->presentDataCount = 0; + commandBuffer->waitSemaphoreCount = 0; + commandBuffer->signalSemaphoreCount = 0; /* Remove this command buffer from the submitted list */ for (i = 0; i < renderer->submittedCommandBufferCount; i += 1) @@ -8614,31 +8848,49 @@ static void VULKAN_Submit( ) { VulkanRenderer* renderer = (VulkanRenderer*)driverData; VkSubmitInfo *submitInfos; - VkPresentInfoKHR *presentInfos; - void **presentWindowHandles; - uint8_t *needsNewSwapchain; - uint32_t presentCount = 0; + VkPresentInfoKHR presentInfo; + VulkanPresentData *presentData; VkResult vulkanResult, presentResult = VK_SUCCESS; VulkanCommandBuffer *currentCommandBuffer; VkCommandBuffer *commandBuffers; - VkPipelineStageFlags waitStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; - VulkanSwapchainData *swapchainData; + VkPipelineStageFlags waitStages[MAX_PRESENT_COUNT]; VkFence fence; - int32_t i; + uint32_t swapchainImageIndex; + int32_t i, j; SDL_LockMutex(renderer->submitLock); + for (i = 0; i < MAX_PRESENT_COUNT; i += 1) + { + waitStages[i] = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + } + commandBuffers = SDL_stack_alloc(VkCommandBuffer, commandBufferCount); submitInfos = SDL_stack_alloc(VkSubmitInfo, commandBufferCount); - /* In the worst case we will need 1 semaphore per CB so let's allocate appropriately. */ - presentInfos = SDL_stack_alloc(VkPresentInfoKHR, commandBufferCount); - presentWindowHandles = SDL_stack_alloc(void*, commandBufferCount); - needsNewSwapchain = SDL_stack_alloc(uint8_t, commandBufferCount); - for (i = 0; i < commandBufferCount; i += 1) { currentCommandBuffer = (VulkanCommandBuffer*)pCommandBuffers[i]; + + for (j = 0; j < currentCommandBuffer->presentDataCount; j += 1) + { + swapchainImageIndex = currentCommandBuffer->presentDatas[j].swapchainImageIndex; + + VULKAN_INTERNAL_ImageMemoryBarrier( + renderer, + currentCommandBuffer->commandBuffer, + RESOURCE_ACCESS_PRESENT, + VK_IMAGE_ASPECT_COLOR_BIT, + 0, + 1, + 0, + 1, + 0, + currentCommandBuffer->presentDatas[j].swapchainData->textures[swapchainImageIndex].image, + ¤tCommandBuffer->presentDatas[j].swapchainData->textures[swapchainImageIndex].resourceAccessType + ); + } + VULKAN_INTERNAL_EndCommandBuffer(renderer, currentCommandBuffer); commandBuffers[i] = currentCommandBuffer->commandBuffer; @@ -8647,42 +8899,15 @@ static void VULKAN_Submit( submitInfos[i].commandBufferCount = 1; submitInfos[i].pCommandBuffers = &commandBuffers[i]; - if (currentCommandBuffer->present) - { - swapchainData = (VulkanSwapchainData*) SDL_GetWindowData(currentCommandBuffer->presentWindowHandle, WINDOW_SWAPCHAIN_DATA); - - submitInfos[i].pWaitDstStageMask = &waitStage; - submitInfos[i].pWaitSemaphores = &swapchainData->imageAvailableSemaphore; - submitInfos[i].waitSemaphoreCount = 1; - submitInfos[i].pSignalSemaphores = &swapchainData->renderFinishedSemaphore; - submitInfos[i].signalSemaphoreCount = 1; - - presentInfos[presentCount].sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; - presentInfos[presentCount].pNext = NULL; - presentInfos[presentCount].waitSemaphoreCount = 1; - presentInfos[presentCount].pWaitSemaphores = &swapchainData->renderFinishedSemaphore; - - presentInfos[presentCount].swapchainCount = 1; - presentInfos[presentCount].pSwapchains = &swapchainData->swapchain; - presentInfos[presentCount].pImageIndices = ¤tCommandBuffer->presentSwapchainImageIndex; - presentInfos[presentCount].pResults = NULL; - - presentWindowHandles[presentCount] = currentCommandBuffer->presentWindowHandle; - needsNewSwapchain[presentCount] = currentCommandBuffer->needNewSwapchain; - - presentCount += 1; - } - else - { - submitInfos[i].pWaitDstStageMask = NULL; - submitInfos[i].pWaitSemaphores = NULL; - submitInfos[i].waitSemaphoreCount = 0; - submitInfos[i].pSignalSemaphores = NULL; - submitInfos[i].signalSemaphoreCount = 0; - } + submitInfos[i].pWaitDstStageMask = waitStages; + submitInfos[i].pWaitSemaphores = currentCommandBuffer->waitSemaphores; + submitInfos[i].waitSemaphoreCount = currentCommandBuffer->waitSemaphoreCount; + submitInfos[i].pSignalSemaphores = currentCommandBuffer->signalSemaphores; + submitInfos[i].signalSemaphoreCount = currentCommandBuffer->signalSemaphoreCount; } /* Wait for any previous submissions on swapchains */ + /* for (i = 0; i < commandBufferCount; i += 1) { currentCommandBuffer = (VulkanCommandBuffer*)pCommandBuffers[i]; @@ -8712,6 +8937,7 @@ static void VULKAN_Submit( } } } + */ /* Check if we can perform any cleanups */ for (i = renderer->submittedCommandBufferCount - 1; i >= 0; i -= 1) @@ -8764,11 +8990,13 @@ static void VULKAN_Submit( currentCommandBuffer = (VulkanCommandBuffer*)pCommandBuffers[i]; currentCommandBuffer->inFlightFence = fence; + /* if (currentCommandBuffer->present) { swapchainData = (VulkanSwapchainData*) SDL_GetWindowData(currentCommandBuffer->presentWindowHandle, WINDOW_SWAPCHAIN_DATA); swapchainData->inFlightFence = fence; } + */ } if (renderer->submittedCommandBufferCount + commandBufferCount >= renderer->submittedCommandBufferCapacity) @@ -8791,24 +9019,37 @@ static void VULKAN_Submit( /* Present, if applicable */ - for (i = 0; i < presentCount; i += 1) + for (i = 0; i < commandBufferCount; i += 1) { - presentResult = renderer->vkQueuePresentKHR( - renderer->presentQueue, - &presentInfos[i] - ); + currentCommandBuffer = (VulkanCommandBuffer*) pCommandBuffers[i]; - if (presentResult != VK_SUCCESS || needsNewSwapchain[i]) + for (j = 0; j < currentCommandBuffer->presentDataCount; j += 1) { - VULKAN_INTERNAL_RecreateSwapchain(renderer, presentWindowHandles[i]); + presentData = ¤tCommandBuffer->presentDatas[j]; + + presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; + presentInfo.pNext = NULL; + presentInfo.pWaitSemaphores = &presentData->swapchainData->renderFinishedSemaphore; + presentInfo.waitSemaphoreCount = 1; + presentInfo.pSwapchains = &presentData->swapchainData->swapchain; + presentInfo.swapchainCount = 1; + presentInfo.pImageIndices = &presentData->swapchainImageIndex; + presentInfo.pResults = NULL; + + presentResult = renderer->vkQueuePresentKHR( + renderer->presentQueue, + &presentInfo + ); + + if (presentResult != VK_SUCCESS || presentData->swapchainData->needsRecreate) + { + VULKAN_INTERNAL_RecreateSwapchain(renderer, presentData->swapchainData->windowHandle); + } } } SDL_stack_free(commandBuffers); SDL_stack_free(submitInfos); - SDL_stack_free(presentInfos); - SDL_stack_free(presentWindowHandles); - SDL_stack_free(needsNewSwapchain); SDL_UnlockMutex(renderer->submitLock); } @@ -9633,6 +9874,7 @@ static Refresh_Device* VULKAN_CreateDevice( renderer->acquireCommandBufferLock = SDL_CreateMutex(); renderer->renderPassFetchLock = SDL_CreateMutex(); renderer->framebufferFetchLock = SDL_CreateMutex(); + renderer->renderTargetFetchLock = SDL_CreateMutex(); /* Create fence lists */ @@ -9948,6 +10190,10 @@ static Refresh_Device* VULKAN_CreateDevice( renderer->framebufferHashArray.count = 0; renderer->framebufferHashArray.capacity = 0; + renderer->renderTargetHashArray.elements = NULL; + renderer->renderTargetHashArray.count = 0; + renderer->renderTargetHashArray.capacity = 0; + /* Initialize transfer buffer pool */ renderer->transferBufferPool.lock = SDL_CreateMutex();