From 30f41c02aec763d32e62351452da9ef582bc3472 Mon Sep 17 00:00:00 2001 From: 3gg <3gg@shellblade.net> Date: Fri, 6 Mar 2026 13:30:59 -0800 Subject: Move contrib libraries to contrib repo --- contrib/SDL-3.2.8/src/gpu/vulkan/SDL_gpu_vulkan.c | 11841 ------------------- .../src/gpu/vulkan/SDL_gpu_vulkan_vkfuncs.h | 176 - 2 files changed, 12017 deletions(-) delete mode 100644 contrib/SDL-3.2.8/src/gpu/vulkan/SDL_gpu_vulkan.c delete mode 100644 contrib/SDL-3.2.8/src/gpu/vulkan/SDL_gpu_vulkan_vkfuncs.h (limited to 'contrib/SDL-3.2.8/src/gpu/vulkan') diff --git a/contrib/SDL-3.2.8/src/gpu/vulkan/SDL_gpu_vulkan.c b/contrib/SDL-3.2.8/src/gpu/vulkan/SDL_gpu_vulkan.c deleted file mode 100644 index ad08cf3..0000000 --- a/contrib/SDL-3.2.8/src/gpu/vulkan/SDL_gpu_vulkan.c +++ /dev/null @@ -1,11841 +0,0 @@ -/* - Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. -*/ - -#include "SDL_internal.h" - -#ifdef SDL_GPU_VULKAN - -// Needed for VK_KHR_portability_subset -#define VK_ENABLE_BETA_EXTENSIONS - -#define VK_NO_PROTOTYPES -#include "../../video/khronos/vulkan/vulkan.h" - -#include - -#include "../SDL_sysgpu.h" - -#define VULKAN_INTERNAL_clamp(val, min, max) SDL_max(min, SDL_min(val, max)) - -// Global Vulkan Loader Entry Points - -static PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = NULL; - -#define VULKAN_GLOBAL_FUNCTION(name) \ - static PFN_##name name = NULL; -#include "SDL_gpu_vulkan_vkfuncs.h" - -typedef struct VulkanExtensions -{ - // These extensions are required! - - // Globally supported - Uint8 KHR_swapchain; - // Core since 1.1, needed for negative VkViewport::height - Uint8 KHR_maintenance1; - - // These extensions are optional! - - // Core since 1.2, but requires annoying paperwork to implement - Uint8 KHR_driver_properties; - // Only required for special implementations (i.e. MoltenVK) - Uint8 KHR_portability_subset; - // Only required for decoding HDR ASTC textures - Uint8 EXT_texture_compression_astc_hdr; -} VulkanExtensions; - -// Defines - -#define SMALL_ALLOCATION_THRESHOLD 2097152 // 2 MiB -#define SMALL_ALLOCATION_SIZE 16777216 // 16 MiB -#define LARGE_ALLOCATION_INCREMENT 67108864 // 64 MiB -#define MAX_UBO_SECTION_SIZE 4096 // 4 KiB -#define DESCRIPTOR_POOL_SIZE 128 -#define WINDOW_PROPERTY_DATA "SDL_GPUVulkanWindowPropertyData" - -#define IDENTITY_SWIZZLE \ - { \ - VK_COMPONENT_SWIZZLE_IDENTITY, \ - VK_COMPONENT_SWIZZLE_IDENTITY, \ - VK_COMPONENT_SWIZZLE_IDENTITY, \ - VK_COMPONENT_SWIZZLE_IDENTITY \ - } - -#define NULL_DESC_LAYOUT (VkDescriptorSetLayout)0 -#define NULL_PIPELINE_LAYOUT (VkPipelineLayout)0 -#define NULL_RENDER_PASS (SDL_GPURenderPass *)0 - -#define EXPAND_ELEMENTS_IF_NEEDED(arr, initialValue, type) \ - do { \ - if (arr->count == arr->capacity) { \ - if (arr->capacity == 0) { \ - arr->capacity = initialValue; \ - } else { \ - arr->capacity *= 2; \ - } \ - arr->elements = (type *)SDL_realloc( \ - arr->elements, \ - arr->capacity * sizeof(type)); \ - } \ - } while (0) - -#define MOVE_ARRAY_CONTENTS_AND_RESET(i, dstArr, dstCount, srcArr, srcCount) \ - do { \ - for ((i) = 0; (i) < (srcCount); (i) += 1) { \ - (dstArr)[i] = (srcArr)[i]; \ - } \ - (dstCount) = (srcCount); \ - (srcCount) = 0; \ - while (0) - -// Conversions - -static const Uint8 DEVICE_PRIORITY_HIGHPERFORMANCE[] = { - 0, // VK_PHYSICAL_DEVICE_TYPE_OTHER - 3, // VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU - 4, // VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU - 2, // VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU - 1 // VK_PHYSICAL_DEVICE_TYPE_CPU -}; - -static const Uint8 DEVICE_PRIORITY_LOWPOWER[] = { - 0, // VK_PHYSICAL_DEVICE_TYPE_OTHER - 4, // VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU - 3, // VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU - 2, // VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU - 1 // VK_PHYSICAL_DEVICE_TYPE_CPU -}; - -static VkPresentModeKHR SDLToVK_PresentMode[] = { - VK_PRESENT_MODE_FIFO_KHR, - VK_PRESENT_MODE_IMMEDIATE_KHR, - VK_PRESENT_MODE_MAILBOX_KHR -}; - -static VkFormat SDLToVK_TextureFormat[] = { - VK_FORMAT_UNDEFINED, // INVALID - VK_FORMAT_R8_UNORM, // A8_UNORM - VK_FORMAT_R8_UNORM, // R8_UNORM - VK_FORMAT_R8G8_UNORM, // R8G8_UNORM - VK_FORMAT_R8G8B8A8_UNORM, // R8G8B8A8_UNORM - VK_FORMAT_R16_UNORM, // R16_UNORM - VK_FORMAT_R16G16_UNORM, // R16G16_UNORM - VK_FORMAT_R16G16B16A16_UNORM, // R16G16B16A16_UNORM - VK_FORMAT_A2B10G10R10_UNORM_PACK32, // R10G10B10A2_UNORM - VK_FORMAT_R5G6B5_UNORM_PACK16, // B5G6R5_UNORM - VK_FORMAT_A1R5G5B5_UNORM_PACK16, // B5G5R5A1_UNORM - VK_FORMAT_B4G4R4A4_UNORM_PACK16, // B4G4R4A4_UNORM - VK_FORMAT_B8G8R8A8_UNORM, // B8G8R8A8_UNORM - VK_FORMAT_BC1_RGBA_UNORM_BLOCK, // BC1_UNORM - VK_FORMAT_BC2_UNORM_BLOCK, // BC2_UNORM - VK_FORMAT_BC3_UNORM_BLOCK, // BC3_UNORM - VK_FORMAT_BC4_UNORM_BLOCK, // BC4_UNORM - VK_FORMAT_BC5_UNORM_BLOCK, // BC5_UNORM - VK_FORMAT_BC7_UNORM_BLOCK, // BC7_UNORM - VK_FORMAT_BC6H_SFLOAT_BLOCK, // BC6H_FLOAT - VK_FORMAT_BC6H_UFLOAT_BLOCK, // BC6H_UFLOAT - VK_FORMAT_R8_SNORM, // R8_SNORM - VK_FORMAT_R8G8_SNORM, // R8G8_SNORM - VK_FORMAT_R8G8B8A8_SNORM, // R8G8B8A8_SNORM - VK_FORMAT_R16_SNORM, // R16_SNORM - VK_FORMAT_R16G16_SNORM, // R16G16_SNORM - VK_FORMAT_R16G16B16A16_SNORM, // R16G16B16A16_SNORM - VK_FORMAT_R16_SFLOAT, // R16_FLOAT - VK_FORMAT_R16G16_SFLOAT, // R16G16_FLOAT - VK_FORMAT_R16G16B16A16_SFLOAT, // R16G16B16A16_FLOAT - VK_FORMAT_R32_SFLOAT, // R32_FLOAT - VK_FORMAT_R32G32_SFLOAT, // R32G32_FLOAT - VK_FORMAT_R32G32B32A32_SFLOAT, // R32G32B32A32_FLOAT - VK_FORMAT_B10G11R11_UFLOAT_PACK32, // R11G11B10_UFLOAT - VK_FORMAT_R8_UINT, // R8_UINT - VK_FORMAT_R8G8_UINT, // R8G8_UINT - VK_FORMAT_R8G8B8A8_UINT, // R8G8B8A8_UINT - VK_FORMAT_R16_UINT, // R16_UINT - VK_FORMAT_R16G16_UINT, // R16G16_UINT - VK_FORMAT_R16G16B16A16_UINT, // R16G16B16A16_UINT - VK_FORMAT_R32_UINT, // R32_UINT - VK_FORMAT_R32G32_UINT, // R32G32_UINT - VK_FORMAT_R32G32B32A32_UINT, // R32G32B32A32_UINT - VK_FORMAT_R8_SINT, // R8_INT - VK_FORMAT_R8G8_SINT, // R8G8_INT - VK_FORMAT_R8G8B8A8_SINT, // R8G8B8A8_INT - VK_FORMAT_R16_SINT, // R16_INT - VK_FORMAT_R16G16_SINT, // R16G16_INT - VK_FORMAT_R16G16B16A16_SINT, // R16G16B16A16_INT - VK_FORMAT_R32_SINT, // R32_INT - VK_FORMAT_R32G32_SINT, // R32G32_INT - VK_FORMAT_R32G32B32A32_SINT, // R32G32B32A32_INT - VK_FORMAT_R8G8B8A8_SRGB, // R8G8B8A8_UNORM_SRGB - VK_FORMAT_B8G8R8A8_SRGB, // B8G8R8A8_UNORM_SRGB - VK_FORMAT_BC1_RGBA_SRGB_BLOCK, // BC1_UNORM_SRGB - VK_FORMAT_BC2_SRGB_BLOCK, // BC3_UNORM_SRGB - VK_FORMAT_BC3_SRGB_BLOCK, // BC3_UNORM_SRGB - VK_FORMAT_BC7_SRGB_BLOCK, // BC7_UNORM_SRGB - VK_FORMAT_D16_UNORM, // D16_UNORM - VK_FORMAT_X8_D24_UNORM_PACK32, // D24_UNORM - VK_FORMAT_D32_SFLOAT, // D32_FLOAT - VK_FORMAT_D24_UNORM_S8_UINT, // D24_UNORM_S8_UINT - VK_FORMAT_D32_SFLOAT_S8_UINT, // D32_FLOAT_S8_UINT - VK_FORMAT_ASTC_4x4_UNORM_BLOCK, // ASTC_4x4_UNORM - VK_FORMAT_ASTC_5x4_UNORM_BLOCK, // ASTC_5x4_UNORM - VK_FORMAT_ASTC_5x5_UNORM_BLOCK, // ASTC_5x5_UNORM - VK_FORMAT_ASTC_6x5_UNORM_BLOCK, // ASTC_6x5_UNORM - VK_FORMAT_ASTC_6x6_UNORM_BLOCK, // ASTC_6x6_UNORM - VK_FORMAT_ASTC_8x5_UNORM_BLOCK, // ASTC_8x5_UNORM - VK_FORMAT_ASTC_8x6_UNORM_BLOCK, // ASTC_8x6_UNORM - VK_FORMAT_ASTC_8x8_UNORM_BLOCK, // ASTC_8x8_UNORM - VK_FORMAT_ASTC_10x5_UNORM_BLOCK, // ASTC_10x5_UNORM - VK_FORMAT_ASTC_10x6_UNORM_BLOCK, // ASTC_10x6_UNORM - VK_FORMAT_ASTC_10x8_UNORM_BLOCK, // ASTC_10x8_UNORM - VK_FORMAT_ASTC_10x10_UNORM_BLOCK, // ASTC_10x10_UNORM - VK_FORMAT_ASTC_12x10_UNORM_BLOCK, // ASTC_12x10_UNORM - VK_FORMAT_ASTC_12x12_UNORM_BLOCK, // ASTC_12x12_UNORM - VK_FORMAT_ASTC_4x4_SRGB_BLOCK, // ASTC_4x4_UNORM_SRGB - VK_FORMAT_ASTC_5x4_SRGB_BLOCK, // ASTC_5x4_UNORM_SRGB - VK_FORMAT_ASTC_5x5_SRGB_BLOCK, // ASTC_5x5_UNORM_SRGB - VK_FORMAT_ASTC_6x5_SRGB_BLOCK, // ASTC_6x5_UNORM_SRGB - VK_FORMAT_ASTC_6x6_SRGB_BLOCK, // ASTC_6x6_UNORM_SRGB - VK_FORMAT_ASTC_8x5_SRGB_BLOCK, // ASTC_8x5_UNORM_SRGB - VK_FORMAT_ASTC_8x6_SRGB_BLOCK, // ASTC_8x6_UNORM_SRGB - VK_FORMAT_ASTC_8x8_SRGB_BLOCK, // ASTC_8x8_UNORM_SRGB - VK_FORMAT_ASTC_10x5_SRGB_BLOCK, // ASTC_10x5_UNORM_SRGB - VK_FORMAT_ASTC_10x6_SRGB_BLOCK, // ASTC_10x6_UNORM_SRGB - VK_FORMAT_ASTC_10x8_SRGB_BLOCK, // ASTC_10x8_UNORM_SRGB - VK_FORMAT_ASTC_10x10_SRGB_BLOCK, // ASTC_10x10_UNORM_SRGB - VK_FORMAT_ASTC_12x10_SRGB_BLOCK, // ASTC_12x10_UNORM_SRGB - VK_FORMAT_ASTC_12x12_SRGB_BLOCK, // ASTC_12x12_UNORM_SRGB - VK_FORMAT_ASTC_4x4_SFLOAT_BLOCK_EXT, // ASTC_4x4_FLOAT - VK_FORMAT_ASTC_5x4_SFLOAT_BLOCK_EXT, // ASTC_5x4_FLOAT - VK_FORMAT_ASTC_5x5_SFLOAT_BLOCK_EXT, // ASTC_5x5_FLOAT - VK_FORMAT_ASTC_6x5_SFLOAT_BLOCK_EXT, // ASTC_6x5_FLOAT - VK_FORMAT_ASTC_6x6_SFLOAT_BLOCK_EXT, // ASTC_6x6_FLOAT - VK_FORMAT_ASTC_8x5_SFLOAT_BLOCK_EXT, // ASTC_8x5_FLOAT - VK_FORMAT_ASTC_8x6_SFLOAT_BLOCK_EXT, // ASTC_8x6_FLOAT - VK_FORMAT_ASTC_8x8_SFLOAT_BLOCK_EXT, // ASTC_8x8_FLOAT - VK_FORMAT_ASTC_10x5_SFLOAT_BLOCK_EXT, // ASTC_10x5_FLOAT - VK_FORMAT_ASTC_10x6_SFLOAT_BLOCK_EXT, // ASTC_10x6_FLOAT - VK_FORMAT_ASTC_10x8_SFLOAT_BLOCK_EXT, // ASTC_10x8_FLOAT - VK_FORMAT_ASTC_10x10_SFLOAT_BLOCK_EXT, // ASTC_10x10_FLOAT - VK_FORMAT_ASTC_12x10_SFLOAT_BLOCK_EXT, // ASTC_12x10_FLOAT - VK_FORMAT_ASTC_12x12_SFLOAT_BLOCK // ASTC_12x12_FLOAT -}; -SDL_COMPILE_TIME_ASSERT(SDLToVK_TextureFormat, SDL_arraysize(SDLToVK_TextureFormat) == SDL_GPU_TEXTUREFORMAT_MAX_ENUM_VALUE); - -static VkComponentMapping SwizzleForSDLFormat(SDL_GPUTextureFormat format) -{ - if (format == SDL_GPU_TEXTUREFORMAT_A8_UNORM) { - // TODO: use VK_FORMAT_A8_UNORM_KHR from VK_KHR_maintenance5 when available - return (VkComponentMapping){ - VK_COMPONENT_SWIZZLE_ZERO, - VK_COMPONENT_SWIZZLE_ZERO, - VK_COMPONENT_SWIZZLE_ZERO, - VK_COMPONENT_SWIZZLE_R, - }; - } - - if (format == SDL_GPU_TEXTUREFORMAT_B4G4R4A4_UNORM) { - // ARGB -> BGRA - // TODO: use VK_FORMAT_A4R4G4B4_UNORM_PACK16_EXT from VK_EXT_4444_formats when available - return (VkComponentMapping){ - VK_COMPONENT_SWIZZLE_G, - VK_COMPONENT_SWIZZLE_R, - VK_COMPONENT_SWIZZLE_A, - VK_COMPONENT_SWIZZLE_B, - }; - } - - return (VkComponentMapping)IDENTITY_SWIZZLE; -} - -static VkFormat SwapchainCompositionToFormat[] = { - VK_FORMAT_B8G8R8A8_UNORM, // SDR - VK_FORMAT_B8G8R8A8_SRGB, // SDR_LINEAR - VK_FORMAT_R16G16B16A16_SFLOAT, // HDR_EXTENDED_LINEAR - VK_FORMAT_A2B10G10R10_UNORM_PACK32 // HDR10_ST2084 -}; - -static VkFormat SwapchainCompositionToFallbackFormat[] = { - VK_FORMAT_R8G8B8A8_UNORM, // SDR - VK_FORMAT_R8G8B8A8_SRGB, // SDR_LINEAR - VK_FORMAT_UNDEFINED, // HDR_EXTENDED_LINEAR (no fallback) - VK_FORMAT_UNDEFINED // HDR10_ST2084 (no fallback) -}; - -static SDL_GPUTextureFormat SwapchainCompositionToSDLFormat( - SDL_GPUSwapchainComposition composition, - bool usingFallback) -{ - switch (composition) { - case SDL_GPU_SWAPCHAINCOMPOSITION_SDR: - return usingFallback ? SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM : SDL_GPU_TEXTUREFORMAT_B8G8R8A8_UNORM; - case SDL_GPU_SWAPCHAINCOMPOSITION_SDR_LINEAR: - return usingFallback ? SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM_SRGB : SDL_GPU_TEXTUREFORMAT_B8G8R8A8_UNORM_SRGB; - case SDL_GPU_SWAPCHAINCOMPOSITION_HDR_EXTENDED_LINEAR: - return SDL_GPU_TEXTUREFORMAT_R16G16B16A16_FLOAT; - case SDL_GPU_SWAPCHAINCOMPOSITION_HDR10_ST2084: - return SDL_GPU_TEXTUREFORMAT_R10G10B10A2_UNORM; - default: - return SDL_GPU_TEXTUREFORMAT_INVALID; - } -} - -static VkColorSpaceKHR SwapchainCompositionToColorSpace[] = { - VK_COLOR_SPACE_SRGB_NONLINEAR_KHR, // SDR - VK_COLOR_SPACE_SRGB_NONLINEAR_KHR, // SDR_LINEAR - VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT, // HDR_EXTENDED_LINEAR - VK_COLOR_SPACE_HDR10_ST2084_EXT // HDR10_ST2084 -}; - -static VkComponentMapping SwapchainCompositionSwizzle[] = { - IDENTITY_SWIZZLE, // SDR - IDENTITY_SWIZZLE, // SDR_LINEAR - IDENTITY_SWIZZLE, // HDR_EXTENDED_LINEAR - { - // HDR10_ST2084 - VK_COMPONENT_SWIZZLE_R, - VK_COMPONENT_SWIZZLE_G, - VK_COMPONENT_SWIZZLE_B, - VK_COMPONENT_SWIZZLE_A, - } -}; - -static VkFormat SDLToVK_VertexFormat[] = { - VK_FORMAT_UNDEFINED, // INVALID - VK_FORMAT_R32_SINT, // INT - VK_FORMAT_R32G32_SINT, // INT2 - VK_FORMAT_R32G32B32_SINT, // INT3 - VK_FORMAT_R32G32B32A32_SINT, // INT4 - VK_FORMAT_R32_UINT, // UINT - VK_FORMAT_R32G32_UINT, // UINT2 - VK_FORMAT_R32G32B32_UINT, // UINT3 - VK_FORMAT_R32G32B32A32_UINT, // UINT4 - VK_FORMAT_R32_SFLOAT, // FLOAT - VK_FORMAT_R32G32_SFLOAT, // FLOAT2 - VK_FORMAT_R32G32B32_SFLOAT, // FLOAT3 - VK_FORMAT_R32G32B32A32_SFLOAT, // FLOAT4 - VK_FORMAT_R8G8_SINT, // BYTE2 - VK_FORMAT_R8G8B8A8_SINT, // BYTE4 - VK_FORMAT_R8G8_UINT, // UBYTE2 - VK_FORMAT_R8G8B8A8_UINT, // UBYTE4 - VK_FORMAT_R8G8_SNORM, // BYTE2_NORM - VK_FORMAT_R8G8B8A8_SNORM, // BYTE4_NORM - VK_FORMAT_R8G8_UNORM, // UBYTE2_NORM - VK_FORMAT_R8G8B8A8_UNORM, // UBYTE4_NORM - VK_FORMAT_R16G16_SINT, // SHORT2 - VK_FORMAT_R16G16B16A16_SINT, // SHORT4 - VK_FORMAT_R16G16_UINT, // USHORT2 - VK_FORMAT_R16G16B16A16_UINT, // USHORT4 - VK_FORMAT_R16G16_SNORM, // SHORT2_NORM - VK_FORMAT_R16G16B16A16_SNORM, // SHORT4_NORM - VK_FORMAT_R16G16_UNORM, // USHORT2_NORM - VK_FORMAT_R16G16B16A16_UNORM, // USHORT4_NORM - VK_FORMAT_R16G16_SFLOAT, // HALF2 - VK_FORMAT_R16G16B16A16_SFLOAT // HALF4 -}; -SDL_COMPILE_TIME_ASSERT(SDLToVK_VertexFormat, SDL_arraysize(SDLToVK_VertexFormat) == SDL_GPU_VERTEXELEMENTFORMAT_MAX_ENUM_VALUE); - -static VkIndexType SDLToVK_IndexType[] = { - VK_INDEX_TYPE_UINT16, - VK_INDEX_TYPE_UINT32 -}; - -static VkPrimitiveTopology SDLToVK_PrimitiveType[] = { - VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, - VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, - VK_PRIMITIVE_TOPOLOGY_LINE_LIST, - VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, - VK_PRIMITIVE_TOPOLOGY_POINT_LIST -}; - -static VkCullModeFlags SDLToVK_CullMode[] = { - VK_CULL_MODE_NONE, - VK_CULL_MODE_FRONT_BIT, - VK_CULL_MODE_BACK_BIT, - VK_CULL_MODE_FRONT_AND_BACK -}; - -static VkFrontFace SDLToVK_FrontFace[] = { - VK_FRONT_FACE_COUNTER_CLOCKWISE, - VK_FRONT_FACE_CLOCKWISE -}; - -static VkBlendFactor SDLToVK_BlendFactor[] = { - VK_BLEND_FACTOR_ZERO, // INVALID - VK_BLEND_FACTOR_ZERO, - VK_BLEND_FACTOR_ONE, - VK_BLEND_FACTOR_SRC_COLOR, - VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR, - VK_BLEND_FACTOR_DST_COLOR, - VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR, - VK_BLEND_FACTOR_SRC_ALPHA, - VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA, - VK_BLEND_FACTOR_DST_ALPHA, - VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA, - VK_BLEND_FACTOR_CONSTANT_COLOR, - VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR, - VK_BLEND_FACTOR_SRC_ALPHA_SATURATE -}; -SDL_COMPILE_TIME_ASSERT(SDLToVK_BlendFactor, SDL_arraysize(SDLToVK_BlendFactor) == SDL_GPU_BLENDFACTOR_MAX_ENUM_VALUE); - -static VkBlendOp SDLToVK_BlendOp[] = { - VK_BLEND_OP_ADD, // INVALID - VK_BLEND_OP_ADD, - VK_BLEND_OP_SUBTRACT, - VK_BLEND_OP_REVERSE_SUBTRACT, - VK_BLEND_OP_MIN, - VK_BLEND_OP_MAX -}; -SDL_COMPILE_TIME_ASSERT(SDLToVK_BlendOp, SDL_arraysize(SDLToVK_BlendOp) == SDL_GPU_BLENDOP_MAX_ENUM_VALUE); - -static VkCompareOp SDLToVK_CompareOp[] = { - VK_COMPARE_OP_NEVER, // INVALID - VK_COMPARE_OP_NEVER, - VK_COMPARE_OP_LESS, - VK_COMPARE_OP_EQUAL, - VK_COMPARE_OP_LESS_OR_EQUAL, - VK_COMPARE_OP_GREATER, - VK_COMPARE_OP_NOT_EQUAL, - VK_COMPARE_OP_GREATER_OR_EQUAL, - VK_COMPARE_OP_ALWAYS -}; -SDL_COMPILE_TIME_ASSERT(SDLToVK_CompareOp, SDL_arraysize(SDLToVK_CompareOp) == SDL_GPU_COMPAREOP_MAX_ENUM_VALUE); - -static VkStencilOp SDLToVK_StencilOp[] = { - VK_STENCIL_OP_KEEP, // INVALID - VK_STENCIL_OP_KEEP, - VK_STENCIL_OP_ZERO, - VK_STENCIL_OP_REPLACE, - VK_STENCIL_OP_INCREMENT_AND_CLAMP, - VK_STENCIL_OP_DECREMENT_AND_CLAMP, - VK_STENCIL_OP_INVERT, - VK_STENCIL_OP_INCREMENT_AND_WRAP, - VK_STENCIL_OP_DECREMENT_AND_WRAP -}; -SDL_COMPILE_TIME_ASSERT(SDLToVK_StencilOp, SDL_arraysize(SDLToVK_StencilOp) == SDL_GPU_STENCILOP_MAX_ENUM_VALUE); - -static VkAttachmentLoadOp SDLToVK_LoadOp[] = { - VK_ATTACHMENT_LOAD_OP_LOAD, - VK_ATTACHMENT_LOAD_OP_CLEAR, - VK_ATTACHMENT_LOAD_OP_DONT_CARE -}; - -static VkAttachmentStoreOp SDLToVK_StoreOp[] = { - VK_ATTACHMENT_STORE_OP_STORE, - VK_ATTACHMENT_STORE_OP_DONT_CARE, - VK_ATTACHMENT_STORE_OP_DONT_CARE, - VK_ATTACHMENT_STORE_OP_STORE -}; - -static VkSampleCountFlagBits SDLToVK_SampleCount[] = { - VK_SAMPLE_COUNT_1_BIT, - VK_SAMPLE_COUNT_2_BIT, - VK_SAMPLE_COUNT_4_BIT, - VK_SAMPLE_COUNT_8_BIT -}; - -static VkVertexInputRate SDLToVK_VertexInputRate[] = { - VK_VERTEX_INPUT_RATE_VERTEX, - VK_VERTEX_INPUT_RATE_INSTANCE -}; - -static VkFilter SDLToVK_Filter[] = { - VK_FILTER_NEAREST, - VK_FILTER_LINEAR -}; - -static VkSamplerMipmapMode SDLToVK_SamplerMipmapMode[] = { - VK_SAMPLER_MIPMAP_MODE_NEAREST, - VK_SAMPLER_MIPMAP_MODE_LINEAR -}; - -static VkSamplerAddressMode SDLToVK_SamplerAddressMode[] = { - VK_SAMPLER_ADDRESS_MODE_REPEAT, - VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT, - VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE -}; - -// Structures - -typedef struct VulkanMemoryAllocation VulkanMemoryAllocation; -typedef struct VulkanBuffer VulkanBuffer; -typedef struct VulkanBufferContainer VulkanBufferContainer; -typedef struct VulkanUniformBuffer VulkanUniformBuffer; -typedef struct VulkanTexture VulkanTexture; -typedef struct VulkanTextureContainer VulkanTextureContainer; - -typedef struct VulkanFenceHandle -{ - VkFence fence; - SDL_AtomicInt referenceCount; -} VulkanFenceHandle; - -// Memory Allocation - -typedef struct VulkanMemoryFreeRegion -{ - VulkanMemoryAllocation *allocation; - VkDeviceSize offset; - VkDeviceSize size; - Uint32 allocationIndex; - Uint32 sortedIndex; -} VulkanMemoryFreeRegion; - -typedef struct VulkanMemoryUsedRegion -{ - VulkanMemoryAllocation *allocation; - VkDeviceSize offset; - VkDeviceSize size; - VkDeviceSize resourceOffset; // differs from offset based on alignment - VkDeviceSize resourceSize; // differs from size based on alignment - VkDeviceSize alignment; - Uint8 isBuffer; - union - { - VulkanBuffer *vulkanBuffer; - VulkanTexture *vulkanTexture; - }; -} VulkanMemoryUsedRegion; - -typedef struct VulkanMemorySubAllocator -{ - Uint32 memoryTypeIndex; - VulkanMemoryAllocation **allocations; - Uint32 allocationCount; - VulkanMemoryFreeRegion **sortedFreeRegions; - Uint32 sortedFreeRegionCount; - Uint32 sortedFreeRegionCapacity; -} VulkanMemorySubAllocator; - -struct VulkanMemoryAllocation -{ - VulkanMemorySubAllocator *allocator; - VkDeviceMemory memory; - VkDeviceSize size; - VulkanMemoryUsedRegion **usedRegions; - Uint32 usedRegionCount; - Uint32 usedRegionCapacity; - VulkanMemoryFreeRegion **freeRegions; - Uint32 freeRegionCount; - Uint32 freeRegionCapacity; - Uint8 availableForAllocation; - VkDeviceSize freeSpace; - VkDeviceSize usedSpace; - Uint8 *mapPointer; - SDL_Mutex *memoryLock; -}; - -typedef struct VulkanMemoryAllocator -{ - VulkanMemorySubAllocator subAllocators[VK_MAX_MEMORY_TYPES]; -} VulkanMemoryAllocator; - -// Memory structures - -typedef enum VulkanBufferType -{ - VULKAN_BUFFER_TYPE_GPU, - VULKAN_BUFFER_TYPE_UNIFORM, - VULKAN_BUFFER_TYPE_TRANSFER -} VulkanBufferType; - -struct VulkanBuffer -{ - VulkanBufferContainer *container; - Uint32 containerIndex; - - VkBuffer buffer; - VulkanMemoryUsedRegion *usedRegion; - - // Needed for uniforms and defrag - VulkanBufferType type; - SDL_GPUBufferUsageFlags usage; - VkDeviceSize size; - - SDL_AtomicInt referenceCount; - bool transitioned; - bool markedForDestroy; // so that defrag doesn't double-free - VulkanUniformBuffer *uniformBufferForDefrag; -}; - -struct VulkanBufferContainer -{ - VulkanBuffer *activeBuffer; - - VulkanBuffer **buffers; - Uint32 bufferCapacity; - Uint32 bufferCount; - - bool dedicated; - char *debugName; -}; - -// Renderer Structure - -typedef struct QueueFamilyIndices -{ - Uint32 graphicsFamily; - Uint32 presentFamily; - Uint32 computeFamily; - Uint32 transferFamily; -} QueueFamilyIndices; - -typedef struct VulkanSampler -{ - VkSampler sampler; - SDL_AtomicInt referenceCount; -} VulkanSampler; - -typedef struct VulkanShader -{ - VkShaderModule shaderModule; - const char *entrypointName; - SDL_GPUShaderStage stage; - Uint32 numSamplers; - Uint32 numStorageTextures; - Uint32 numStorageBuffers; - Uint32 numUniformBuffers; - SDL_AtomicInt referenceCount; -} VulkanShader; - -/* Textures are made up of individual subresources. - * This helps us barrier the resource efficiently. - */ -typedef struct VulkanTextureSubresource -{ - VulkanTexture *parent; - Uint32 layer; - Uint32 level; - - VkImageView *renderTargetViews; // One render target view per depth slice - VkImageView computeWriteView; - VkImageView depthStencilView; -} VulkanTextureSubresource; - -struct VulkanTexture -{ - VulkanTextureContainer *container; - Uint32 containerIndex; - - VulkanMemoryUsedRegion *usedRegion; - - VkImage image; - VkImageView fullView; // used for samplers and storage reads - VkComponentMapping swizzle; - VkImageAspectFlags aspectFlags; - Uint32 depth; // used for cleanup only - - // FIXME: It'd be nice if we didn't have to have this on the texture... - SDL_GPUTextureUsageFlags usage; // used for defrag transitions only. - - Uint32 subresourceCount; - VulkanTextureSubresource *subresources; - - bool markedForDestroy; // so that defrag doesn't double-free - SDL_AtomicInt referenceCount; -}; - -struct VulkanTextureContainer -{ - TextureCommonHeader header; - - VulkanTexture *activeTexture; - - Uint32 textureCapacity; - Uint32 textureCount; - VulkanTexture **textures; - - char *debugName; - bool canBeCycled; -}; - -typedef enum VulkanBufferUsageMode -{ - VULKAN_BUFFER_USAGE_MODE_COPY_SOURCE, - VULKAN_BUFFER_USAGE_MODE_COPY_DESTINATION, - VULKAN_BUFFER_USAGE_MODE_VERTEX_READ, - VULKAN_BUFFER_USAGE_MODE_INDEX_READ, - VULKAN_BUFFER_USAGE_MODE_INDIRECT, - VULKAN_BUFFER_USAGE_MODE_GRAPHICS_STORAGE_READ, - VULKAN_BUFFER_USAGE_MODE_COMPUTE_STORAGE_READ, - VULKAN_BUFFER_USAGE_MODE_COMPUTE_STORAGE_READ_WRITE, -} VulkanBufferUsageMode; - -typedef enum VulkanTextureUsageMode -{ - VULKAN_TEXTURE_USAGE_MODE_UNINITIALIZED, - VULKAN_TEXTURE_USAGE_MODE_COPY_SOURCE, - VULKAN_TEXTURE_USAGE_MODE_COPY_DESTINATION, - VULKAN_TEXTURE_USAGE_MODE_SAMPLER, - VULKAN_TEXTURE_USAGE_MODE_GRAPHICS_STORAGE_READ, - VULKAN_TEXTURE_USAGE_MODE_COMPUTE_STORAGE_READ, - VULKAN_TEXTURE_USAGE_MODE_COMPUTE_STORAGE_READ_WRITE, - VULKAN_TEXTURE_USAGE_MODE_COLOR_ATTACHMENT, - VULKAN_TEXTURE_USAGE_MODE_DEPTH_STENCIL_ATTACHMENT, - VULKAN_TEXTURE_USAGE_MODE_PRESENT -} VulkanTextureUsageMode; - -typedef enum VulkanUniformBufferStage -{ - VULKAN_UNIFORM_BUFFER_STAGE_VERTEX, - VULKAN_UNIFORM_BUFFER_STAGE_FRAGMENT, - VULKAN_UNIFORM_BUFFER_STAGE_COMPUTE -} VulkanUniformBufferStage; - -typedef struct VulkanFramebuffer -{ - VkFramebuffer framebuffer; - SDL_AtomicInt referenceCount; -} VulkanFramebuffer; - -typedef struct WindowData -{ - SDL_Window *window; - SDL_GPUSwapchainComposition swapchainComposition; - SDL_GPUPresentMode presentMode; - bool needsSwapchainRecreate; - Uint32 swapchainCreateWidth; - Uint32 swapchainCreateHeight; - - // Window surface - VkSurfaceKHR surface; - - // Swapchain for window surface - VkSwapchainKHR swapchain; - VkFormat format; - VkColorSpaceKHR colorSpace; - VkComponentMapping swapchainSwizzle; - bool usingFallbackFormat; - - // Swapchain images - VulkanTextureContainer *textureContainers; // use containers so that swapchain textures can use the same API as other textures - Uint32 imageCount; - Uint32 width; - Uint32 height; - - // Synchronization primitives - VkSemaphore imageAvailableSemaphore[MAX_FRAMES_IN_FLIGHT]; - VkSemaphore renderFinishedSemaphore[MAX_FRAMES_IN_FLIGHT]; - SDL_GPUFence *inFlightFences[MAX_FRAMES_IN_FLIGHT]; - - Uint32 frameCounter; -} WindowData; - -typedef struct SwapchainSupportDetails -{ - VkSurfaceCapabilitiesKHR capabilities; - VkSurfaceFormatKHR *formats; - Uint32 formatsLength; - VkPresentModeKHR *presentModes; - Uint32 presentModesLength; -} SwapchainSupportDetails; - -typedef struct VulkanPresentData -{ - WindowData *windowData; - Uint32 swapchainImageIndex; -} VulkanPresentData; - -struct VulkanUniformBuffer -{ - VulkanBuffer *buffer; - Uint32 drawOffset; - Uint32 writeOffset; -}; - -typedef struct VulkanDescriptorInfo -{ - VkDescriptorType descriptorType; - VkShaderStageFlagBits stageFlag; -} VulkanDescriptorInfo; - -typedef struct DescriptorSetPool -{ - // It's a pool... of pools!!! - Uint32 poolCount; - VkDescriptorPool *descriptorPools; - - // We'll just manage the descriptor sets ourselves instead of freeing the sets - VkDescriptorSet *descriptorSets; - Uint32 descriptorSetCount; - Uint32 descriptorSetIndex; -} DescriptorSetPool; - -// A command buffer acquires a cache at command buffer acquisition time -typedef struct DescriptorSetCache -{ - // Pools are indexed by DescriptorSetLayoutID which increases monotonically - // There's only a certain number of maximum layouts possible since we de-duplicate them. - DescriptorSetPool *pools; - Uint32 poolCount; -} DescriptorSetCache; - -typedef struct DescriptorSetLayoutHashTableKey -{ - VkShaderStageFlagBits shaderStage; - // Category 1: read resources - Uint32 samplerCount; - Uint32 storageBufferCount; - Uint32 storageTextureCount; - // Category 2: write resources - Uint32 writeStorageBufferCount; - Uint32 writeStorageTextureCount; - // Category 3: uniform buffers - Uint32 uniformBufferCount; -} DescriptorSetLayoutHashTableKey; - -typedef uint32_t DescriptorSetLayoutID; - -typedef struct DescriptorSetLayout -{ - DescriptorSetLayoutID ID; - VkDescriptorSetLayout descriptorSetLayout; - - // Category 1: read resources - Uint32 samplerCount; - Uint32 storageBufferCount; - Uint32 storageTextureCount; - // Category 2: write resources - Uint32 writeStorageBufferCount; - Uint32 writeStorageTextureCount; - // Category 3: uniform buffers - Uint32 uniformBufferCount; -} DescriptorSetLayout; - -typedef struct GraphicsPipelineResourceLayoutHashTableKey -{ - Uint32 vertexSamplerCount; - Uint32 vertexStorageBufferCount; - Uint32 vertexStorageTextureCount; - Uint32 vertexUniformBufferCount; - - Uint32 fragmentSamplerCount; - Uint32 fragmentStorageBufferCount; - Uint32 fragmentStorageTextureCount; - Uint32 fragmentUniformBufferCount; -} GraphicsPipelineResourceLayoutHashTableKey; - -typedef struct VulkanGraphicsPipelineResourceLayout -{ - VkPipelineLayout pipelineLayout; - - /* - * Descriptor set layout is as follows: - * 0: vertex resources - * 1: vertex uniform buffers - * 2: fragment resources - * 3: fragment uniform buffers - */ - DescriptorSetLayout *descriptorSetLayouts[4]; - - Uint32 vertexSamplerCount; - Uint32 vertexStorageBufferCount; - Uint32 vertexStorageTextureCount; - Uint32 vertexUniformBufferCount; - - Uint32 fragmentSamplerCount; - Uint32 fragmentStorageBufferCount; - Uint32 fragmentStorageTextureCount; - Uint32 fragmentUniformBufferCount; -} VulkanGraphicsPipelineResourceLayout; - -typedef struct VulkanGraphicsPipeline -{ - VkPipeline pipeline; - SDL_GPUPrimitiveType primitiveType; - - VulkanGraphicsPipelineResourceLayout *resourceLayout; - - VulkanShader *vertexShader; - VulkanShader *fragmentShader; - - SDL_AtomicInt referenceCount; -} VulkanGraphicsPipeline; - -typedef struct ComputePipelineResourceLayoutHashTableKey -{ - Uint32 samplerCount; - Uint32 readonlyStorageTextureCount; - Uint32 readonlyStorageBufferCount; - Uint32 readWriteStorageTextureCount; - Uint32 readWriteStorageBufferCount; - Uint32 uniformBufferCount; -} ComputePipelineResourceLayoutHashTableKey; - -typedef struct VulkanComputePipelineResourceLayout -{ - VkPipelineLayout pipelineLayout; - - /* - * Descriptor set layout is as follows: - * 0: samplers, then read-only textures, then read-only buffers - * 1: write-only textures, then write-only buffers - * 2: uniform buffers - */ - DescriptorSetLayout *descriptorSetLayouts[3]; - - Uint32 numSamplers; - Uint32 numReadonlyStorageTextures; - Uint32 numReadonlyStorageBuffers; - Uint32 numReadWriteStorageTextures; - Uint32 numReadWriteStorageBuffers; - Uint32 numUniformBuffers; -} VulkanComputePipelineResourceLayout; - -typedef struct VulkanComputePipeline -{ - VkShaderModule shaderModule; - VkPipeline pipeline; - VulkanComputePipelineResourceLayout *resourceLayout; - SDL_AtomicInt referenceCount; -} VulkanComputePipeline; - -typedef struct RenderPassColorTargetDescription -{ - VkFormat format; - SDL_GPULoadOp loadOp; - SDL_GPUStoreOp storeOp; -} RenderPassColorTargetDescription; - -typedef struct RenderPassDepthStencilTargetDescription -{ - VkFormat format; - SDL_GPULoadOp loadOp; - SDL_GPUStoreOp storeOp; - SDL_GPULoadOp stencilLoadOp; - SDL_GPUStoreOp stencilStoreOp; -} RenderPassDepthStencilTargetDescription; - -typedef struct CommandPoolHashTableKey -{ - SDL_ThreadID threadID; -} CommandPoolHashTableKey; - -typedef struct RenderPassHashTableKey -{ - RenderPassColorTargetDescription colorTargetDescriptions[MAX_COLOR_TARGET_BINDINGS]; - Uint32 numColorTargets; - VkFormat resolveTargetFormats[MAX_COLOR_TARGET_BINDINGS]; - Uint32 numResolveTargets; - RenderPassDepthStencilTargetDescription depthStencilTargetDescription; - VkSampleCountFlagBits sampleCount; -} RenderPassHashTableKey; - -typedef struct VulkanRenderPassHashTableValue -{ - VkRenderPass handle; -} VulkanRenderPassHashTableValue; - -typedef struct FramebufferHashTableKey -{ - VkImageView colorAttachmentViews[MAX_COLOR_TARGET_BINDINGS]; - Uint32 numColorTargets; - VkImageView resolveAttachmentViews[MAX_COLOR_TARGET_BINDINGS]; - Uint32 numResolveAttachments; - VkImageView depthStencilAttachmentView; - Uint32 width; - Uint32 height; -} FramebufferHashTableKey; - -// Command structures - -typedef struct VulkanFencePool -{ - SDL_Mutex *lock; - - VulkanFenceHandle **availableFences; - Uint32 availableFenceCount; - Uint32 availableFenceCapacity; -} VulkanFencePool; - -typedef struct VulkanCommandPool VulkanCommandPool; - -typedef struct VulkanRenderer VulkanRenderer; - -typedef struct VulkanCommandBuffer -{ - CommandBufferCommonHeader common; - VulkanRenderer *renderer; - - VkCommandBuffer commandBuffer; - VulkanCommandPool *commandPool; - - VulkanPresentData *presentDatas; - Uint32 presentDataCount; - Uint32 presentDataCapacity; - - VkSemaphore *waitSemaphores; - Uint32 waitSemaphoreCount; - Uint32 waitSemaphoreCapacity; - - VkSemaphore *signalSemaphores; - Uint32 signalSemaphoreCount; - Uint32 signalSemaphoreCapacity; - - VulkanComputePipeline *currentComputePipeline; - VulkanGraphicsPipeline *currentGraphicsPipeline; - - // Keep track of resources transitioned away from their default state to barrier them on pass end - - VulkanTextureSubresource *colorAttachmentSubresources[MAX_COLOR_TARGET_BINDINGS]; - Uint32 colorAttachmentSubresourceCount; - VulkanTextureSubresource *resolveAttachmentSubresources[MAX_COLOR_TARGET_BINDINGS]; - Uint32 resolveAttachmentSubresourceCount; - - VulkanTextureSubresource *depthStencilAttachmentSubresource; // may be NULL - - // Dynamic state - - VkViewport currentViewport; - VkRect2D currentScissor; - float blendConstants[4]; - Uint8 stencilRef; - - // Resource bind state - - DescriptorSetCache *descriptorSetCache; // acquired when command buffer is acquired - - bool needNewVertexResourceDescriptorSet; - bool needNewVertexUniformDescriptorSet; - bool needNewVertexUniformOffsets; - bool needNewFragmentResourceDescriptorSet; - bool needNewFragmentUniformDescriptorSet; - bool needNewFragmentUniformOffsets; - - bool needNewComputeReadOnlyDescriptorSet; - bool needNewComputeReadWriteDescriptorSet; - bool needNewComputeUniformDescriptorSet; - bool needNewComputeUniformOffsets; - - VkDescriptorSet vertexResourceDescriptorSet; - VkDescriptorSet vertexUniformDescriptorSet; - VkDescriptorSet fragmentResourceDescriptorSet; - VkDescriptorSet fragmentUniformDescriptorSet; - - VkDescriptorSet computeReadOnlyDescriptorSet; - VkDescriptorSet computeReadWriteDescriptorSet; - VkDescriptorSet computeUniformDescriptorSet; - - VkBuffer vertexBuffers[MAX_VERTEX_BUFFERS]; - VkDeviceSize vertexBufferOffsets[MAX_VERTEX_BUFFERS]; - Uint32 vertexBufferCount; - bool needVertexBufferBind; - - VulkanTexture *vertexSamplerTextures[MAX_TEXTURE_SAMPLERS_PER_STAGE]; - VulkanSampler *vertexSamplers[MAX_TEXTURE_SAMPLERS_PER_STAGE]; - VulkanTexture *vertexStorageTextures[MAX_STORAGE_TEXTURES_PER_STAGE]; - VulkanBuffer *vertexStorageBuffers[MAX_STORAGE_BUFFERS_PER_STAGE]; - - VulkanTexture *fragmentSamplerTextures[MAX_TEXTURE_SAMPLERS_PER_STAGE]; - VulkanSampler *fragmentSamplers[MAX_TEXTURE_SAMPLERS_PER_STAGE]; - VulkanTexture *fragmentStorageTextures[MAX_STORAGE_TEXTURES_PER_STAGE]; - VulkanBuffer *fragmentStorageBuffers[MAX_STORAGE_BUFFERS_PER_STAGE]; - - VulkanTextureSubresource *readWriteComputeStorageTextureSubresources[MAX_COMPUTE_WRITE_TEXTURES]; - Uint32 readWriteComputeStorageTextureSubresourceCount; - VulkanBuffer *readWriteComputeStorageBuffers[MAX_COMPUTE_WRITE_BUFFERS]; - - VulkanTexture *computeSamplerTextures[MAX_TEXTURE_SAMPLERS_PER_STAGE]; - VulkanSampler *computeSamplers[MAX_TEXTURE_SAMPLERS_PER_STAGE]; - VulkanTexture *readOnlyComputeStorageTextures[MAX_STORAGE_TEXTURES_PER_STAGE]; - VulkanBuffer *readOnlyComputeStorageBuffers[MAX_STORAGE_BUFFERS_PER_STAGE]; - - // Uniform buffers - - VulkanUniformBuffer *vertexUniformBuffers[MAX_UNIFORM_BUFFERS_PER_STAGE]; - VulkanUniformBuffer *fragmentUniformBuffers[MAX_UNIFORM_BUFFERS_PER_STAGE]; - VulkanUniformBuffer *computeUniformBuffers[MAX_UNIFORM_BUFFERS_PER_STAGE]; - - // Track used resources - - VulkanBuffer **usedBuffers; - Sint32 usedBufferCount; - Sint32 usedBufferCapacity; - - VulkanTexture **usedTextures; - Sint32 usedTextureCount; - Sint32 usedTextureCapacity; - - VulkanSampler **usedSamplers; - Sint32 usedSamplerCount; - Sint32 usedSamplerCapacity; - - VulkanGraphicsPipeline **usedGraphicsPipelines; - Sint32 usedGraphicsPipelineCount; - Sint32 usedGraphicsPipelineCapacity; - - VulkanComputePipeline **usedComputePipelines; - Sint32 usedComputePipelineCount; - Sint32 usedComputePipelineCapacity; - - VulkanFramebuffer **usedFramebuffers; - Sint32 usedFramebufferCount; - Sint32 usedFramebufferCapacity; - - VulkanUniformBuffer **usedUniformBuffers; - Sint32 usedUniformBufferCount; - Sint32 usedUniformBufferCapacity; - - VulkanFenceHandle *inFlightFence; - bool autoReleaseFence; - - bool isDefrag; // Whether this CB was created for defragging -} VulkanCommandBuffer; - -struct VulkanCommandPool -{ - SDL_ThreadID threadID; - VkCommandPool commandPool; - - VulkanCommandBuffer **inactiveCommandBuffers; - Uint32 inactiveCommandBufferCapacity; - Uint32 inactiveCommandBufferCount; -}; - -// Context - -struct VulkanRenderer -{ - VkInstance instance; - VkPhysicalDevice physicalDevice; - VkPhysicalDeviceProperties2KHR physicalDeviceProperties; - VkPhysicalDeviceDriverPropertiesKHR physicalDeviceDriverProperties; - VkDevice logicalDevice; - Uint8 integratedMemoryNotification; - Uint8 outOfDeviceLocalMemoryWarning; - Uint8 outofBARMemoryWarning; - Uint8 fillModeOnlyWarning; - - bool debugMode; - bool preferLowPower; - Uint32 allowedFramesInFlight; - - VulkanExtensions supports; - bool supportsDebugUtils; - bool supportsColorspace; - bool supportsFillModeNonSolid; - bool supportsMultiDrawIndirect; - - VulkanMemoryAllocator *memoryAllocator; - VkPhysicalDeviceMemoryProperties memoryProperties; - - WindowData **claimedWindows; - Uint32 claimedWindowCount; - Uint32 claimedWindowCapacity; - - Uint32 queueFamilyIndex; - VkQueue unifiedQueue; - - VulkanCommandBuffer **submittedCommandBuffers; - Uint32 submittedCommandBufferCount; - Uint32 submittedCommandBufferCapacity; - - VulkanFencePool fencePool; - - SDL_HashTable *commandPoolHashTable; - SDL_HashTable *renderPassHashTable; - SDL_HashTable *framebufferHashTable; - SDL_HashTable *graphicsPipelineResourceLayoutHashTable; - SDL_HashTable *computePipelineResourceLayoutHashTable; - SDL_HashTable *descriptorSetLayoutHashTable; - - VulkanUniformBuffer **uniformBufferPool; - Uint32 uniformBufferPoolCount; - Uint32 uniformBufferPoolCapacity; - - DescriptorSetCache **descriptorSetCachePool; - Uint32 descriptorSetCachePoolCount; - Uint32 descriptorSetCachePoolCapacity; - - SDL_AtomicInt layoutResourceID; - - Uint32 minUBOAlignment; - - // Deferred resource destruction - - VulkanTexture **texturesToDestroy; - Uint32 texturesToDestroyCount; - Uint32 texturesToDestroyCapacity; - - VulkanBuffer **buffersToDestroy; - Uint32 buffersToDestroyCount; - Uint32 buffersToDestroyCapacity; - - VulkanSampler **samplersToDestroy; - Uint32 samplersToDestroyCount; - Uint32 samplersToDestroyCapacity; - - VulkanGraphicsPipeline **graphicsPipelinesToDestroy; - Uint32 graphicsPipelinesToDestroyCount; - Uint32 graphicsPipelinesToDestroyCapacity; - - VulkanComputePipeline **computePipelinesToDestroy; - Uint32 computePipelinesToDestroyCount; - Uint32 computePipelinesToDestroyCapacity; - - VulkanShader **shadersToDestroy; - Uint32 shadersToDestroyCount; - Uint32 shadersToDestroyCapacity; - - VulkanFramebuffer **framebuffersToDestroy; - Uint32 framebuffersToDestroyCount; - Uint32 framebuffersToDestroyCapacity; - - SDL_Mutex *allocatorLock; - SDL_Mutex *disposeLock; - SDL_Mutex *submitLock; - SDL_Mutex *acquireCommandBufferLock; - SDL_Mutex *acquireUniformBufferLock; - SDL_Mutex *framebufferFetchLock; - SDL_Mutex *windowLock; - - Uint8 defragInProgress; - - VulkanMemoryAllocation **allocationsToDefrag; - Uint32 allocationsToDefragCount; - Uint32 allocationsToDefragCapacity; - -#define VULKAN_INSTANCE_FUNCTION(func) \ - PFN_##func func; -#define VULKAN_DEVICE_FUNCTION(func) \ - PFN_##func func; -#include "SDL_gpu_vulkan_vkfuncs.h" -}; - -// Forward declarations - -static bool VULKAN_INTERNAL_DefragmentMemory(VulkanRenderer *renderer); -static bool VULKAN_INTERNAL_BeginCommandBuffer(VulkanRenderer *renderer, VulkanCommandBuffer *commandBuffer); -static void VULKAN_ReleaseWindow(SDL_GPURenderer *driverData, SDL_Window *window); -static bool VULKAN_Wait(SDL_GPURenderer *driverData); -static bool VULKAN_WaitForFences(SDL_GPURenderer *driverData, bool waitAll, SDL_GPUFence *const *fences, Uint32 numFences); -static bool VULKAN_Submit(SDL_GPUCommandBuffer *commandBuffer); -static SDL_GPUCommandBuffer *VULKAN_AcquireCommandBuffer(SDL_GPURenderer *driverData); - -// Error Handling - -static inline const char *VkErrorMessages(VkResult code) -{ -#define ERR_TO_STR(e) \ - case e: \ - return #e; - switch (code) { - ERR_TO_STR(VK_ERROR_OUT_OF_HOST_MEMORY) - ERR_TO_STR(VK_ERROR_OUT_OF_DEVICE_MEMORY) - ERR_TO_STR(VK_ERROR_FRAGMENTED_POOL) - ERR_TO_STR(VK_ERROR_OUT_OF_POOL_MEMORY) - ERR_TO_STR(VK_ERROR_INITIALIZATION_FAILED) - ERR_TO_STR(VK_ERROR_LAYER_NOT_PRESENT) - ERR_TO_STR(VK_ERROR_EXTENSION_NOT_PRESENT) - ERR_TO_STR(VK_ERROR_FEATURE_NOT_PRESENT) - ERR_TO_STR(VK_ERROR_TOO_MANY_OBJECTS) - ERR_TO_STR(VK_ERROR_DEVICE_LOST) - ERR_TO_STR(VK_ERROR_INCOMPATIBLE_DRIVER) - ERR_TO_STR(VK_ERROR_OUT_OF_DATE_KHR) - ERR_TO_STR(VK_ERROR_SURFACE_LOST_KHR) - ERR_TO_STR(VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT) - ERR_TO_STR(VK_SUBOPTIMAL_KHR) - ERR_TO_STR(VK_ERROR_NATIVE_WINDOW_IN_USE_KHR) - default: - return "Unhandled VkResult!"; - } -#undef ERR_TO_STR -} - -#define SET_ERROR_AND_RETURN(fmt, msg, ret) \ - do { \ - if (renderer->debugMode) { \ - SDL_LogError(SDL_LOG_CATEGORY_GPU, fmt, msg); \ - } \ - SDL_SetError((fmt), (msg)); \ - return ret; \ - } while (0) - -#define SET_STRING_ERROR_AND_RETURN(msg, ret) SET_ERROR_AND_RETURN("%s", msg, ret) - -#define CHECK_VULKAN_ERROR_AND_RETURN(res, fn, ret) \ - do { \ - if ((res) != VK_SUCCESS) { \ - if (renderer->debugMode) { \ - SDL_LogError(SDL_LOG_CATEGORY_GPU, "%s %s", #fn, VkErrorMessages(res)); \ - } \ - SDL_SetError("%s %s", #fn, VkErrorMessages(res)); \ - return (ret); \ - } \ - } while (0) - -// Utility - -static inline VkPolygonMode SDLToVK_PolygonMode( - VulkanRenderer *renderer, - SDL_GPUFillMode mode) -{ - if (mode == SDL_GPU_FILLMODE_FILL) { - return VK_POLYGON_MODE_FILL; // always available! - } - - if (renderer->supportsFillModeNonSolid && mode == SDL_GPU_FILLMODE_LINE) { - return VK_POLYGON_MODE_LINE; - } - - if (!renderer->fillModeOnlyWarning) { - SDL_LogWarn(SDL_LOG_CATEGORY_GPU, "Unsupported fill mode requested, using FILL!"); - renderer->fillModeOnlyWarning = 1; - } - return VK_POLYGON_MODE_FILL; -} - -// Memory Management - -// Vulkan: Memory Allocation - -static inline VkDeviceSize VULKAN_INTERNAL_NextHighestAlignment( - VkDeviceSize n, - VkDeviceSize align) -{ - return align * ((n + align - 1) / align); -} - -static inline Uint32 VULKAN_INTERNAL_NextHighestAlignment32( - Uint32 n, - Uint32 align) -{ - return align * ((n + align - 1) / align); -} - -static void VULKAN_INTERNAL_MakeMemoryUnavailable( - VulkanRenderer *renderer, - VulkanMemoryAllocation *allocation) -{ - Uint32 i, j; - VulkanMemoryFreeRegion *freeRegion; - - allocation->availableForAllocation = 0; - - for (i = 0; i < allocation->freeRegionCount; i += 1) { - freeRegion = allocation->freeRegions[i]; - - // close the gap in the sorted list - if (allocation->allocator->sortedFreeRegionCount > 1) { - for (j = freeRegion->sortedIndex; j < allocation->allocator->sortedFreeRegionCount - 1; j += 1) { - allocation->allocator->sortedFreeRegions[j] = - allocation->allocator->sortedFreeRegions[j + 1]; - - allocation->allocator->sortedFreeRegions[j]->sortedIndex = j; - } - } - - allocation->allocator->sortedFreeRegionCount -= 1; - } -} - -static void VULKAN_INTERNAL_MarkAllocationsForDefrag( - VulkanRenderer *renderer) -{ - Uint32 memoryType, allocationIndex; - VulkanMemorySubAllocator *currentAllocator; - - for (memoryType = 0; memoryType < VK_MAX_MEMORY_TYPES; memoryType += 1) { - currentAllocator = &renderer->memoryAllocator->subAllocators[memoryType]; - - for (allocationIndex = 0; allocationIndex < currentAllocator->allocationCount; allocationIndex += 1) { - if (currentAllocator->allocations[allocationIndex]->availableForAllocation == 1) { - if (currentAllocator->allocations[allocationIndex]->freeRegionCount > 1) { - EXPAND_ARRAY_IF_NEEDED( - renderer->allocationsToDefrag, - VulkanMemoryAllocation *, - renderer->allocationsToDefragCount + 1, - renderer->allocationsToDefragCapacity, - renderer->allocationsToDefragCapacity * 2); - - renderer->allocationsToDefrag[renderer->allocationsToDefragCount] = - currentAllocator->allocations[allocationIndex]; - - renderer->allocationsToDefragCount += 1; - - VULKAN_INTERNAL_MakeMemoryUnavailable( - renderer, - currentAllocator->allocations[allocationIndex]); - } - } - } - } -} - -static void VULKAN_INTERNAL_RemoveMemoryFreeRegion( - VulkanRenderer *renderer, - VulkanMemoryFreeRegion *freeRegion) -{ - Uint32 i; - - SDL_LockMutex(renderer->allocatorLock); - - if (freeRegion->allocation->availableForAllocation) { - // close the gap in the sorted list - if (freeRegion->allocation->allocator->sortedFreeRegionCount > 1) { - for (i = freeRegion->sortedIndex; i < freeRegion->allocation->allocator->sortedFreeRegionCount - 1; i += 1) { - freeRegion->allocation->allocator->sortedFreeRegions[i] = - freeRegion->allocation->allocator->sortedFreeRegions[i + 1]; - - freeRegion->allocation->allocator->sortedFreeRegions[i]->sortedIndex = i; - } - } - - freeRegion->allocation->allocator->sortedFreeRegionCount -= 1; - } - - // close the gap in the buffer list - if (freeRegion->allocation->freeRegionCount > 1 && freeRegion->allocationIndex != freeRegion->allocation->freeRegionCount - 1) { - freeRegion->allocation->freeRegions[freeRegion->allocationIndex] = - freeRegion->allocation->freeRegions[freeRegion->allocation->freeRegionCount - 1]; - - freeRegion->allocation->freeRegions[freeRegion->allocationIndex]->allocationIndex = - freeRegion->allocationIndex; - } - - freeRegion->allocation->freeRegionCount -= 1; - - freeRegion->allocation->freeSpace -= freeRegion->size; - - SDL_free(freeRegion); - - SDL_UnlockMutex(renderer->allocatorLock); -} - -static void VULKAN_INTERNAL_NewMemoryFreeRegion( - VulkanRenderer *renderer, - VulkanMemoryAllocation *allocation, - VkDeviceSize offset, - VkDeviceSize size) -{ - VulkanMemoryFreeRegion *newFreeRegion; - VkDeviceSize newOffset, newSize; - Sint32 insertionIndex = 0; - - SDL_LockMutex(renderer->allocatorLock); - - // look for an adjacent region to merge - for (Sint32 i = allocation->freeRegionCount - 1; i >= 0; i -= 1) { - // check left side - if (allocation->freeRegions[i]->offset + allocation->freeRegions[i]->size == offset) { - newOffset = allocation->freeRegions[i]->offset; - newSize = allocation->freeRegions[i]->size + size; - - VULKAN_INTERNAL_RemoveMemoryFreeRegion(renderer, allocation->freeRegions[i]); - VULKAN_INTERNAL_NewMemoryFreeRegion(renderer, allocation, newOffset, newSize); - - SDL_UnlockMutex(renderer->allocatorLock); - return; - } - - // check right side - if (allocation->freeRegions[i]->offset == offset + size) { - newOffset = offset; - newSize = allocation->freeRegions[i]->size + size; - - VULKAN_INTERNAL_RemoveMemoryFreeRegion(renderer, allocation->freeRegions[i]); - VULKAN_INTERNAL_NewMemoryFreeRegion(renderer, allocation, newOffset, newSize); - - SDL_UnlockMutex(renderer->allocatorLock); - return; - } - } - - // region is not contiguous with another free region, make a new one - allocation->freeRegionCount += 1; - if (allocation->freeRegionCount > allocation->freeRegionCapacity) { - allocation->freeRegionCapacity *= 2; - allocation->freeRegions = SDL_realloc( - allocation->freeRegions, - sizeof(VulkanMemoryFreeRegion *) * allocation->freeRegionCapacity); - } - - newFreeRegion = SDL_malloc(sizeof(VulkanMemoryFreeRegion)); - newFreeRegion->offset = offset; - newFreeRegion->size = size; - newFreeRegion->allocation = allocation; - - allocation->freeSpace += size; - - allocation->freeRegions[allocation->freeRegionCount - 1] = newFreeRegion; - newFreeRegion->allocationIndex = allocation->freeRegionCount - 1; - - if (allocation->availableForAllocation) { - for (Uint32 i = 0; i < allocation->allocator->sortedFreeRegionCount; i += 1) { - if (allocation->allocator->sortedFreeRegions[i]->size < size) { - // this is where the new region should go - break; - } - - insertionIndex += 1; - } - - if (allocation->allocator->sortedFreeRegionCount + 1 > allocation->allocator->sortedFreeRegionCapacity) { - allocation->allocator->sortedFreeRegionCapacity *= 2; - allocation->allocator->sortedFreeRegions = SDL_realloc( - allocation->allocator->sortedFreeRegions, - sizeof(VulkanMemoryFreeRegion *) * allocation->allocator->sortedFreeRegionCapacity); - } - - // perform insertion sort - if (allocation->allocator->sortedFreeRegionCount > 0 && (Uint32)insertionIndex != allocation->allocator->sortedFreeRegionCount) { - for (Sint32 i = allocation->allocator->sortedFreeRegionCount; i > insertionIndex && i > 0; i -= 1) { - allocation->allocator->sortedFreeRegions[i] = allocation->allocator->sortedFreeRegions[i - 1]; - allocation->allocator->sortedFreeRegions[i]->sortedIndex = i; - } - } - - allocation->allocator->sortedFreeRegionCount += 1; - allocation->allocator->sortedFreeRegions[insertionIndex] = newFreeRegion; - newFreeRegion->sortedIndex = insertionIndex; - } - - SDL_UnlockMutex(renderer->allocatorLock); -} - -static VulkanMemoryUsedRegion *VULKAN_INTERNAL_NewMemoryUsedRegion( - VulkanRenderer *renderer, - VulkanMemoryAllocation *allocation, - VkDeviceSize offset, - VkDeviceSize size, - VkDeviceSize resourceOffset, - VkDeviceSize resourceSize, - VkDeviceSize alignment) -{ - VulkanMemoryUsedRegion *memoryUsedRegion; - - SDL_LockMutex(renderer->allocatorLock); - - if (allocation->usedRegionCount == allocation->usedRegionCapacity) { - allocation->usedRegionCapacity *= 2; - allocation->usedRegions = SDL_realloc( - allocation->usedRegions, - allocation->usedRegionCapacity * sizeof(VulkanMemoryUsedRegion *)); - } - - memoryUsedRegion = SDL_malloc(sizeof(VulkanMemoryUsedRegion)); - memoryUsedRegion->allocation = allocation; - memoryUsedRegion->offset = offset; - memoryUsedRegion->size = size; - memoryUsedRegion->resourceOffset = resourceOffset; - memoryUsedRegion->resourceSize = resourceSize; - memoryUsedRegion->alignment = alignment; - - allocation->usedSpace += size; - - allocation->usedRegions[allocation->usedRegionCount] = memoryUsedRegion; - allocation->usedRegionCount += 1; - - SDL_UnlockMutex(renderer->allocatorLock); - - return memoryUsedRegion; -} - -static void VULKAN_INTERNAL_RemoveMemoryUsedRegion( - VulkanRenderer *renderer, - VulkanMemoryUsedRegion *usedRegion) -{ - Uint32 i; - - SDL_LockMutex(renderer->allocatorLock); - - for (i = 0; i < usedRegion->allocation->usedRegionCount; i += 1) { - if (usedRegion->allocation->usedRegions[i] == usedRegion) { - // plug the hole - if (i != usedRegion->allocation->usedRegionCount - 1) { - usedRegion->allocation->usedRegions[i] = usedRegion->allocation->usedRegions[usedRegion->allocation->usedRegionCount - 1]; - } - - break; - } - } - - usedRegion->allocation->usedSpace -= usedRegion->size; - - usedRegion->allocation->usedRegionCount -= 1; - - VULKAN_INTERNAL_NewMemoryFreeRegion( - renderer, - usedRegion->allocation, - usedRegion->offset, - usedRegion->size); - - SDL_free(usedRegion); - - SDL_UnlockMutex(renderer->allocatorLock); -} - -static bool VULKAN_INTERNAL_CheckMemoryTypeArrayUnique( - Uint32 memoryTypeIndex, - const Uint32 *memoryTypeIndexArray, - Uint32 count) -{ - Uint32 i = 0; - - for (i = 0; i < count; i += 1) { - if (memoryTypeIndexArray[i] == memoryTypeIndex) { - return false; - } - } - - return true; -} - -/* Returns an array of memory type indices in order of preference. - * Memory types are requested with the following three guidelines: - * - * Required: Absolutely necessary - * Preferred: Nice to have, but not necessary - * Tolerable: Can be allowed if there are no other options - * - * We return memory types in this order: - * 1. Required and preferred. This is the best category. - * 2. Required only. - * 3. Required, preferred, and tolerable. - * 4. Required and tolerable. This is the worst category. - */ -static Uint32 *VULKAN_INTERNAL_FindBestMemoryTypes( - VulkanRenderer *renderer, - Uint32 typeFilter, - VkMemoryPropertyFlags requiredProperties, - VkMemoryPropertyFlags preferredProperties, - VkMemoryPropertyFlags tolerableProperties, - Uint32 *pCount) -{ - Uint32 i; - Uint32 index = 0; - Uint32 *result = SDL_malloc(sizeof(Uint32) * renderer->memoryProperties.memoryTypeCount); - - // required + preferred + !tolerable - for (i = 0; i < renderer->memoryProperties.memoryTypeCount; i += 1) { - if ((typeFilter & (1 << i)) && - (renderer->memoryProperties.memoryTypes[i].propertyFlags & requiredProperties) == requiredProperties && - (renderer->memoryProperties.memoryTypes[i].propertyFlags & preferredProperties) == preferredProperties && - (renderer->memoryProperties.memoryTypes[i].propertyFlags & tolerableProperties) == 0) { - if (VULKAN_INTERNAL_CheckMemoryTypeArrayUnique( - i, - result, - index)) { - result[index] = i; - index += 1; - } - } - } - - // required + !preferred + !tolerable - for (i = 0; i < renderer->memoryProperties.memoryTypeCount; i += 1) { - if ((typeFilter & (1 << i)) && - (renderer->memoryProperties.memoryTypes[i].propertyFlags & requiredProperties) == requiredProperties && - (renderer->memoryProperties.memoryTypes[i].propertyFlags & preferredProperties) == 0 && - (renderer->memoryProperties.memoryTypes[i].propertyFlags & tolerableProperties) == 0) { - if (VULKAN_INTERNAL_CheckMemoryTypeArrayUnique( - i, - result, - index)) { - result[index] = i; - index += 1; - } - } - } - - // required + preferred + tolerable - for (i = 0; i < renderer->memoryProperties.memoryTypeCount; i += 1) { - if ((typeFilter & (1 << i)) && - (renderer->memoryProperties.memoryTypes[i].propertyFlags & requiredProperties) == requiredProperties && - (renderer->memoryProperties.memoryTypes[i].propertyFlags & preferredProperties) == preferredProperties && - (renderer->memoryProperties.memoryTypes[i].propertyFlags & tolerableProperties) == tolerableProperties) { - if (VULKAN_INTERNAL_CheckMemoryTypeArrayUnique( - i, - result, - index)) { - result[index] = i; - index += 1; - } - } - } - - // required + !preferred + tolerable - for (i = 0; i < renderer->memoryProperties.memoryTypeCount; i += 1) { - if ((typeFilter & (1 << i)) && - (renderer->memoryProperties.memoryTypes[i].propertyFlags & requiredProperties) == requiredProperties && - (renderer->memoryProperties.memoryTypes[i].propertyFlags & preferredProperties) == 0 && - (renderer->memoryProperties.memoryTypes[i].propertyFlags & tolerableProperties) == tolerableProperties) { - if (VULKAN_INTERNAL_CheckMemoryTypeArrayUnique( - i, - result, - index)) { - result[index] = i; - index += 1; - } - } - } - - *pCount = index; - return result; -} - -static Uint32 *VULKAN_INTERNAL_FindBestBufferMemoryTypes( - VulkanRenderer *renderer, - VkBuffer buffer, - VkMemoryPropertyFlags requiredMemoryProperties, - VkMemoryPropertyFlags preferredMemoryProperties, - VkMemoryPropertyFlags tolerableMemoryProperties, - VkMemoryRequirements *pMemoryRequirements, - Uint32 *pCount) -{ - renderer->vkGetBufferMemoryRequirements( - renderer->logicalDevice, - buffer, - pMemoryRequirements); - - return VULKAN_INTERNAL_FindBestMemoryTypes( - renderer, - pMemoryRequirements->memoryTypeBits, - requiredMemoryProperties, - preferredMemoryProperties, - tolerableMemoryProperties, - pCount); -} - -static Uint32 *VULKAN_INTERNAL_FindBestImageMemoryTypes( - VulkanRenderer *renderer, - VkImage image, - VkMemoryPropertyFlags preferredMemoryPropertyFlags, - VkMemoryRequirements *pMemoryRequirements, - Uint32 *pCount) -{ - renderer->vkGetImageMemoryRequirements( - renderer->logicalDevice, - image, - pMemoryRequirements); - - return VULKAN_INTERNAL_FindBestMemoryTypes( - renderer, - pMemoryRequirements->memoryTypeBits, - 0, - preferredMemoryPropertyFlags, - 0, - pCount); -} - -static void VULKAN_INTERNAL_DeallocateMemory( - VulkanRenderer *renderer, - VulkanMemorySubAllocator *allocator, - Uint32 allocationIndex) -{ - Uint32 i; - - VulkanMemoryAllocation *allocation = allocator->allocations[allocationIndex]; - - SDL_LockMutex(renderer->allocatorLock); - - // If this allocation was marked for defrag, cancel that - for (i = 0; i < renderer->allocationsToDefragCount; i += 1) { - if (allocation == renderer->allocationsToDefrag[i]) { - renderer->allocationsToDefrag[i] = renderer->allocationsToDefrag[renderer->allocationsToDefragCount - 1]; - renderer->allocationsToDefragCount -= 1; - - break; - } - } - - for (i = 0; i < allocation->freeRegionCount; i += 1) { - VULKAN_INTERNAL_RemoveMemoryFreeRegion( - renderer, - allocation->freeRegions[i]); - } - SDL_free(allocation->freeRegions); - - /* no need to iterate used regions because deallocate - * only happens when there are 0 used regions - */ - SDL_free(allocation->usedRegions); - - renderer->vkFreeMemory( - renderer->logicalDevice, - allocation->memory, - NULL); - - SDL_DestroyMutex(allocation->memoryLock); - SDL_free(allocation); - - if (allocationIndex != allocator->allocationCount - 1) { - allocator->allocations[allocationIndex] = allocator->allocations[allocator->allocationCount - 1]; - } - - allocator->allocationCount -= 1; - - SDL_UnlockMutex(renderer->allocatorLock); -} - -static Uint8 VULKAN_INTERNAL_AllocateMemory( - VulkanRenderer *renderer, - VkBuffer buffer, - VkImage image, - Uint32 memoryTypeIndex, - VkDeviceSize allocationSize, - Uint8 isHostVisible, - VulkanMemoryAllocation **pMemoryAllocation) -{ - VulkanMemoryAllocation *allocation; - VulkanMemorySubAllocator *allocator = &renderer->memoryAllocator->subAllocators[memoryTypeIndex]; - VkMemoryAllocateInfo allocInfo; - VkResult result; - - allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; - allocInfo.pNext = NULL; - allocInfo.memoryTypeIndex = memoryTypeIndex; - allocInfo.allocationSize = allocationSize; - - allocation = SDL_malloc(sizeof(VulkanMemoryAllocation)); - allocation->size = allocationSize; - allocation->freeSpace = 0; // added by FreeRegions - allocation->usedSpace = 0; // added by UsedRegions - allocation->memoryLock = SDL_CreateMutex(); - - allocator->allocationCount += 1; - allocator->allocations = SDL_realloc( - allocator->allocations, - sizeof(VulkanMemoryAllocation *) * allocator->allocationCount); - - allocator->allocations[allocator->allocationCount - 1] = allocation; - - allocInfo.pNext = NULL; - allocation->availableForAllocation = 1; - - allocation->usedRegions = SDL_malloc(sizeof(VulkanMemoryUsedRegion *)); - allocation->usedRegionCount = 0; - allocation->usedRegionCapacity = 1; - - allocation->freeRegions = SDL_malloc(sizeof(VulkanMemoryFreeRegion *)); - allocation->freeRegionCount = 0; - allocation->freeRegionCapacity = 1; - - allocation->allocator = allocator; - - result = renderer->vkAllocateMemory( - renderer->logicalDevice, - &allocInfo, - NULL, - &allocation->memory); - - if (result != VK_SUCCESS) { - // Uh oh, we couldn't allocate, time to clean up - SDL_free(allocation->freeRegions); - - allocator->allocationCount -= 1; - allocator->allocations = SDL_realloc( - allocator->allocations, - sizeof(VulkanMemoryAllocation *) * allocator->allocationCount); - - SDL_free(allocation); - - return 0; - } - - // Persistent mapping for host-visible memory - if (isHostVisible) { - result = renderer->vkMapMemory( - renderer->logicalDevice, - allocation->memory, - 0, - VK_WHOLE_SIZE, - 0, - (void **)&allocation->mapPointer); - CHECK_VULKAN_ERROR_AND_RETURN(result, vkMapMemory, 0); - } else { - allocation->mapPointer = NULL; - } - - VULKAN_INTERNAL_NewMemoryFreeRegion( - renderer, - allocation, - 0, - allocation->size); - - *pMemoryAllocation = allocation; - return 1; -} - -static Uint8 VULKAN_INTERNAL_BindBufferMemory( - VulkanRenderer *renderer, - VulkanMemoryUsedRegion *usedRegion, - VkDeviceSize alignedOffset, - VkBuffer buffer) -{ - VkResult vulkanResult; - - SDL_LockMutex(usedRegion->allocation->memoryLock); - - vulkanResult = renderer->vkBindBufferMemory( - renderer->logicalDevice, - buffer, - usedRegion->allocation->memory, - alignedOffset); - - SDL_UnlockMutex(usedRegion->allocation->memoryLock); - - CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkBindBufferMemory, 0); - - return 1; -} - -static Uint8 VULKAN_INTERNAL_BindImageMemory( - VulkanRenderer *renderer, - VulkanMemoryUsedRegion *usedRegion, - VkDeviceSize alignedOffset, - VkImage image) -{ - VkResult vulkanResult; - - SDL_LockMutex(usedRegion->allocation->memoryLock); - - vulkanResult = renderer->vkBindImageMemory( - renderer->logicalDevice, - image, - usedRegion->allocation->memory, - alignedOffset); - - SDL_UnlockMutex(usedRegion->allocation->memoryLock); - - CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkBindImageMemory, 0); - - return 1; -} - -static Uint8 VULKAN_INTERNAL_BindResourceMemory( - VulkanRenderer *renderer, - Uint32 memoryTypeIndex, - VkMemoryRequirements *memoryRequirements, - VkDeviceSize resourceSize, // may be different from requirements size! - bool dedicated, // the entire memory allocation should be used for this resource - VkBuffer buffer, // may be VK_NULL_HANDLE - VkImage image, // may be VK_NULL_HANDLE - VulkanMemoryUsedRegion **pMemoryUsedRegion) -{ - VulkanMemoryAllocation *allocation; - VulkanMemorySubAllocator *allocator; - VulkanMemoryFreeRegion *region; - VulkanMemoryFreeRegion *selectedRegion; - VulkanMemoryUsedRegion *usedRegion; - - VkDeviceSize requiredSize, allocationSize; - VkDeviceSize alignedOffset = 0; - VkDeviceSize newRegionSize, newRegionOffset; - Uint8 isHostVisible, smallAllocation, allocationResult; - Sint32 i; - - isHostVisible = - (renderer->memoryProperties.memoryTypes[memoryTypeIndex].propertyFlags & - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) != 0; - - allocator = &renderer->memoryAllocator->subAllocators[memoryTypeIndex]; - requiredSize = memoryRequirements->size; - smallAllocation = requiredSize <= SMALL_ALLOCATION_THRESHOLD; - - if ((buffer == VK_NULL_HANDLE && image == VK_NULL_HANDLE) || - (buffer != VK_NULL_HANDLE && image != VK_NULL_HANDLE)) { - SDL_LogError(SDL_LOG_CATEGORY_GPU, "BindResourceMemory must be given either a VulkanBuffer or a VulkanTexture"); - return 0; - } - - SDL_LockMutex(renderer->allocatorLock); - - selectedRegion = NULL; - - if (dedicated) { - // Force an allocation - allocationSize = requiredSize; - } else { - // Search for a suitable existing free region - for (i = allocator->sortedFreeRegionCount - 1; i >= 0; i -= 1) { - region = allocator->sortedFreeRegions[i]; - - if (smallAllocation && region->allocation->size != SMALL_ALLOCATION_SIZE) { - // region is not in a small allocation - continue; - } - - if (!smallAllocation && region->allocation->size == SMALL_ALLOCATION_SIZE) { - // allocation is not small and current region is in a small allocation - continue; - } - - alignedOffset = VULKAN_INTERNAL_NextHighestAlignment( - region->offset, - memoryRequirements->alignment); - - if (alignedOffset + requiredSize <= region->offset + region->size) { - selectedRegion = region; - break; - } - } - - if (selectedRegion != NULL) { - region = selectedRegion; - allocation = region->allocation; - - usedRegion = VULKAN_INTERNAL_NewMemoryUsedRegion( - renderer, - allocation, - region->offset, - requiredSize + (alignedOffset - region->offset), - alignedOffset, - resourceSize, - memoryRequirements->alignment); - - usedRegion->isBuffer = buffer != VK_NULL_HANDLE; - - newRegionSize = region->size - ((alignedOffset - region->offset) + requiredSize); - newRegionOffset = alignedOffset + requiredSize; - - // remove and add modified region to re-sort - VULKAN_INTERNAL_RemoveMemoryFreeRegion(renderer, region); - - // if size is 0, no need to re-insert - if (newRegionSize != 0) { - VULKAN_INTERNAL_NewMemoryFreeRegion( - renderer, - allocation, - newRegionOffset, - newRegionSize); - } - - SDL_UnlockMutex(renderer->allocatorLock); - - if (buffer != VK_NULL_HANDLE) { - if (!VULKAN_INTERNAL_BindBufferMemory( - renderer, - usedRegion, - alignedOffset, - buffer)) { - VULKAN_INTERNAL_RemoveMemoryUsedRegion( - renderer, - usedRegion); - - return 0; - } - } else if (image != VK_NULL_HANDLE) { - if (!VULKAN_INTERNAL_BindImageMemory( - renderer, - usedRegion, - alignedOffset, - image)) { - VULKAN_INTERNAL_RemoveMemoryUsedRegion( - renderer, - usedRegion); - - return 0; - } - } - - *pMemoryUsedRegion = usedRegion; - return 1; - } - - // No suitable free regions exist, allocate a new memory region - if ( - renderer->allocationsToDefragCount == 0 && - !renderer->defragInProgress) { - // Mark currently fragmented allocations for defrag - VULKAN_INTERNAL_MarkAllocationsForDefrag(renderer); - } - - if (requiredSize > SMALL_ALLOCATION_THRESHOLD) { - // allocate a page of required size aligned to LARGE_ALLOCATION_INCREMENT increments - allocationSize = - VULKAN_INTERNAL_NextHighestAlignment(requiredSize, LARGE_ALLOCATION_INCREMENT); - } else { - allocationSize = SMALL_ALLOCATION_SIZE; - } - } - - allocationResult = VULKAN_INTERNAL_AllocateMemory( - renderer, - buffer, - image, - memoryTypeIndex, - allocationSize, - isHostVisible, - &allocation); - - // Uh oh, we're out of memory - if (allocationResult == 0) { - SDL_UnlockMutex(renderer->allocatorLock); - - // Responsibility of the caller to handle being out of memory - return 2; - } - - usedRegion = VULKAN_INTERNAL_NewMemoryUsedRegion( - renderer, - allocation, - 0, - requiredSize, - 0, - resourceSize, - memoryRequirements->alignment); - - usedRegion->isBuffer = buffer != VK_NULL_HANDLE; - - region = allocation->freeRegions[0]; - - newRegionOffset = region->offset + requiredSize; - newRegionSize = region->size - requiredSize; - - VULKAN_INTERNAL_RemoveMemoryFreeRegion(renderer, region); - - if (newRegionSize != 0) { - VULKAN_INTERNAL_NewMemoryFreeRegion( - renderer, - allocation, - newRegionOffset, - newRegionSize); - } - - SDL_UnlockMutex(renderer->allocatorLock); - - if (buffer != VK_NULL_HANDLE) { - if (!VULKAN_INTERNAL_BindBufferMemory( - renderer, - usedRegion, - 0, - buffer)) { - VULKAN_INTERNAL_RemoveMemoryUsedRegion( - renderer, - usedRegion); - - return 0; - } - } else if (image != VK_NULL_HANDLE) { - if (!VULKAN_INTERNAL_BindImageMemory( - renderer, - usedRegion, - 0, - image)) { - VULKAN_INTERNAL_RemoveMemoryUsedRegion( - renderer, - usedRegion); - - return 0; - } - } - - *pMemoryUsedRegion = usedRegion; - return 1; -} - -static Uint8 VULKAN_INTERNAL_BindMemoryForImage( - VulkanRenderer *renderer, - VkImage image, - VulkanMemoryUsedRegion **usedRegion) -{ - Uint8 bindResult = 0; - Uint32 memoryTypeCount = 0; - Uint32 *memoryTypesToTry = NULL; - Uint32 selectedMemoryTypeIndex = 0; - Uint32 i; - VkMemoryPropertyFlags preferredMemoryPropertyFlags; - VkMemoryRequirements memoryRequirements; - - /* Vulkan memory types have several memory properties. - * - * Unlike buffers, images are always optimally stored device-local, - * so that is the only property we prefer here. - * - * If memory is constrained, it is fine for the texture to not - * be device-local. - */ - preferredMemoryPropertyFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; - - memoryTypesToTry = VULKAN_INTERNAL_FindBestImageMemoryTypes( - renderer, - image, - preferredMemoryPropertyFlags, - &memoryRequirements, - &memoryTypeCount); - - for (i = 0; i < memoryTypeCount; i += 1) { - bindResult = VULKAN_INTERNAL_BindResourceMemory( - renderer, - memoryTypesToTry[i], - &memoryRequirements, - memoryRequirements.size, - false, - VK_NULL_HANDLE, - image, - usedRegion); - - if (bindResult == 1) { - selectedMemoryTypeIndex = memoryTypesToTry[i]; - break; - } - } - - SDL_free(memoryTypesToTry); - - // Check for warnings on success - if (bindResult == 1) { - if (!renderer->outOfDeviceLocalMemoryWarning) { - if ((renderer->memoryProperties.memoryTypes[selectedMemoryTypeIndex].propertyFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) == 0) { - SDL_LogWarn(SDL_LOG_CATEGORY_GPU, "Out of device-local memory, allocating textures on host-local memory!"); - renderer->outOfDeviceLocalMemoryWarning = 1; - } - } - } - - return bindResult; -} - -static Uint8 VULKAN_INTERNAL_BindMemoryForBuffer( - VulkanRenderer *renderer, - VkBuffer buffer, - VkDeviceSize size, - VulkanBufferType type, - bool dedicated, - VulkanMemoryUsedRegion **usedRegion) -{ - Uint8 bindResult = 0; - Uint32 memoryTypeCount = 0; - Uint32 *memoryTypesToTry = NULL; - Uint32 selectedMemoryTypeIndex = 0; - Uint32 i; - VkMemoryPropertyFlags requiredMemoryPropertyFlags = 0; - VkMemoryPropertyFlags preferredMemoryPropertyFlags = 0; - VkMemoryPropertyFlags tolerableMemoryPropertyFlags = 0; - VkMemoryRequirements memoryRequirements; - - /* Buffers need to be optimally bound to a memory type - * based on their use case and the architecture of the system. - * - * It is important to understand the distinction between device and host. - * - * On a traditional high-performance desktop computer, - * the "device" would be the GPU, and the "host" would be the CPU. - * Memory being copied between these two must cross the PCI bus. - * On these systems we have to be concerned about bandwidth limitations - * and causing memory stalls, so we have taken a great deal of care - * to structure this API to guide the client towards optimal usage. - * - * Other kinds of devices do not necessarily have this distinction. - * On an iPhone or Nintendo Switch, all memory is accessible both to the - * GPU and the CPU at all times. These kinds of systems are known as - * UMA, or Unified Memory Architecture. A desktop computer using the - * CPU's integrated graphics can also be thought of as UMA. - * - * Vulkan memory types have several memory properties. - * The relevant memory properties are as follows: - * - * DEVICE_LOCAL: - * This memory is on-device and most efficient for device access. - * On UMA systems all memory is device-local. - * If memory is not device-local, then it is host-local. - * - * HOST_VISIBLE: - * This memory can be mapped for host access, meaning we can obtain - * a pointer to directly access the memory. - * - * HOST_COHERENT: - * Host-coherent memory does not require cache management operations - * when mapped, so we always set this alongside HOST_VISIBLE - * to avoid extra record keeping. - * - * HOST_CACHED: - * Host-cached memory is faster to access than uncached memory - * but memory of this type might not always be available. - * - * GPU buffers, like vertex buffers, indirect buffers, etc - * are optimally stored in device-local memory. - * However, if device-local memory is low, these buffers - * can be accessed from host-local memory with a performance penalty. - * - * Uniform buffers must be host-visible and coherent because - * the client uses them to quickly push small amounts of data. - * We prefer uniform buffers to also be device-local because - * they are accessed by shaders, but the amount of memory - * that is both device-local and host-visible - * is often constrained, particularly on low-end devices. - * - * Transfer buffers must be host-visible and coherent because - * the client uses them to stage data to be transferred - * to device-local memory, or to read back data transferred - * from the device. We prefer the cache bit for performance - * but it isn't strictly necessary. We tolerate device-local - * memory in this situation because, as mentioned above, - * on certain devices all memory is device-local, and even - * though the transfer isn't strictly necessary it is still - * useful for correctly timelining data. - */ - if (type == VULKAN_BUFFER_TYPE_GPU) { - preferredMemoryPropertyFlags |= - VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; - } else if (type == VULKAN_BUFFER_TYPE_UNIFORM) { - requiredMemoryPropertyFlags |= - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | - VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; - - preferredMemoryPropertyFlags |= - VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; - } else if (type == VULKAN_BUFFER_TYPE_TRANSFER) { - requiredMemoryPropertyFlags |= - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | - VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; - - preferredMemoryPropertyFlags |= - VK_MEMORY_PROPERTY_HOST_CACHED_BIT; - - tolerableMemoryPropertyFlags |= - VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; - } else { - SDL_LogError(SDL_LOG_CATEGORY_GPU, "Unrecognized buffer type!"); - return 0; - } - - memoryTypesToTry = VULKAN_INTERNAL_FindBestBufferMemoryTypes( - renderer, - buffer, - requiredMemoryPropertyFlags, - preferredMemoryPropertyFlags, - tolerableMemoryPropertyFlags, - &memoryRequirements, - &memoryTypeCount); - - for (i = 0; i < memoryTypeCount; i += 1) { - bindResult = VULKAN_INTERNAL_BindResourceMemory( - renderer, - memoryTypesToTry[i], - &memoryRequirements, - size, - dedicated, - buffer, - VK_NULL_HANDLE, - usedRegion); - - if (bindResult == 1) { - selectedMemoryTypeIndex = memoryTypesToTry[i]; - break; - } - } - - SDL_free(memoryTypesToTry); - - // Check for warnings on success - if (bindResult == 1) { - if (type == VULKAN_BUFFER_TYPE_GPU) { - if (!renderer->outOfDeviceLocalMemoryWarning) { - if ((renderer->memoryProperties.memoryTypes[selectedMemoryTypeIndex].propertyFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) == 0) { - SDL_LogWarn(SDL_LOG_CATEGORY_GPU, "Out of device-local memory, allocating buffers on host-local memory, expect degraded performance!"); - renderer->outOfDeviceLocalMemoryWarning = 1; - } - } - } else if (type == VULKAN_BUFFER_TYPE_UNIFORM) { - if (!renderer->outofBARMemoryWarning) { - if ((renderer->memoryProperties.memoryTypes[selectedMemoryTypeIndex].propertyFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) == 0) { - SDL_LogWarn(SDL_LOG_CATEGORY_GPU, "Out of BAR memory, allocating uniform buffers on host-local memory, expect degraded performance!"); - renderer->outofBARMemoryWarning = 1; - } - } - } else if (type == VULKAN_BUFFER_TYPE_TRANSFER) { - if (!renderer->integratedMemoryNotification) { - if ((renderer->memoryProperties.memoryTypes[selectedMemoryTypeIndex].propertyFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) == VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) { - SDL_LogInfo(SDL_LOG_CATEGORY_GPU, "Integrated memory detected, allocating TransferBuffers on device-local memory!"); - renderer->integratedMemoryNotification = 1; - } - } - } - } - - return bindResult; -} - -// Resource tracking - -#define ADD_TO_ARRAY_UNIQUE(resource, type, array, count, capacity) \ - Uint32 i; \ - \ - for (i = 0; i < commandBuffer->count; i += 1) { \ - if (commandBuffer->array[i] == resource) { \ - return; \ - } \ - } \ - \ - if (commandBuffer->count == commandBuffer->capacity) { \ - commandBuffer->capacity += 1; \ - commandBuffer->array = SDL_realloc( \ - commandBuffer->array, \ - commandBuffer->capacity * sizeof(type)); \ - } \ - commandBuffer->array[commandBuffer->count] = resource; \ - commandBuffer->count += 1; - -#define TRACK_RESOURCE(resource, type, array, count, capacity) \ - for (Sint32 i = commandBuffer->count - 1; i >= 0; i -= 1) { \ - if (commandBuffer->array[i] == resource) { \ - return; \ - } \ - } \ - \ - if (commandBuffer->count == commandBuffer->capacity) { \ - commandBuffer->capacity += 1; \ - commandBuffer->array = SDL_realloc( \ - commandBuffer->array, \ - commandBuffer->capacity * sizeof(type)); \ - } \ - commandBuffer->array[commandBuffer->count] = resource; \ - commandBuffer->count += 1; \ - SDL_AtomicIncRef(&resource->referenceCount); - -static void VULKAN_INTERNAL_TrackBuffer( - VulkanCommandBuffer *commandBuffer, - VulkanBuffer *buffer) -{ - TRACK_RESOURCE( - buffer, - VulkanBuffer *, - usedBuffers, - usedBufferCount, - usedBufferCapacity) -} - -static void VULKAN_INTERNAL_TrackTexture( - VulkanCommandBuffer *commandBuffer, - VulkanTexture *texture) -{ - TRACK_RESOURCE( - texture, - VulkanTexture *, - usedTextures, - usedTextureCount, - usedTextureCapacity) -} - -static void VULKAN_INTERNAL_TrackSampler( - VulkanCommandBuffer *commandBuffer, - VulkanSampler *sampler) -{ - TRACK_RESOURCE( - sampler, - VulkanSampler *, - usedSamplers, - usedSamplerCount, - usedSamplerCapacity) -} - -static void VULKAN_INTERNAL_TrackGraphicsPipeline( - VulkanCommandBuffer *commandBuffer, - VulkanGraphicsPipeline *graphicsPipeline) -{ - TRACK_RESOURCE( - graphicsPipeline, - VulkanGraphicsPipeline *, - usedGraphicsPipelines, - usedGraphicsPipelineCount, - usedGraphicsPipelineCapacity) -} - -static void VULKAN_INTERNAL_TrackComputePipeline( - VulkanCommandBuffer *commandBuffer, - VulkanComputePipeline *computePipeline) -{ - TRACK_RESOURCE( - computePipeline, - VulkanComputePipeline *, - usedComputePipelines, - usedComputePipelineCount, - usedComputePipelineCapacity) -} - -static void VULKAN_INTERNAL_TrackFramebuffer( - VulkanRenderer *renderer, - VulkanCommandBuffer *commandBuffer, - VulkanFramebuffer *framebuffer) -{ - TRACK_RESOURCE( - framebuffer, - VulkanFramebuffer *, - usedFramebuffers, - usedFramebufferCount, - usedFramebufferCapacity); -} - -static void VULKAN_INTERNAL_TrackUniformBuffer( - VulkanCommandBuffer *commandBuffer, - VulkanUniformBuffer *uniformBuffer) -{ - for (Sint32 i = commandBuffer->usedUniformBufferCount - 1; i >= 0; i -= 1) { - if (commandBuffer->usedUniformBuffers[i] == uniformBuffer) { - return; - } - } - - if (commandBuffer->usedUniformBufferCount == commandBuffer->usedUniformBufferCapacity) { - commandBuffer->usedUniformBufferCapacity += 1; - commandBuffer->usedUniformBuffers = SDL_realloc( - commandBuffer->usedUniformBuffers, - commandBuffer->usedUniformBufferCapacity * sizeof(VulkanUniformBuffer *)); - } - commandBuffer->usedUniformBuffers[commandBuffer->usedUniformBufferCount] = uniformBuffer; - commandBuffer->usedUniformBufferCount += 1; - - VULKAN_INTERNAL_TrackBuffer( - commandBuffer, - uniformBuffer->buffer); -} - -#undef TRACK_RESOURCE - -// Memory Barriers - -/* - * In Vulkan, we must manually synchronize operations that write to resources on the GPU - * so that read-after-write, write-after-read, and write-after-write hazards do not occur. - * Additionally, textures are required to be in specific layouts for specific use cases. - * Both of these tasks are accomplished with vkCmdPipelineBarrier. - * - * To insert the correct barriers, we keep track of "usage modes" for buffers and textures. - * These indicate the current usage of that resource on the command buffer. - * The transition from one usage mode to another indicates how the barrier should be constructed. - * - * Pipeline barriers cannot be inserted during a render pass, but they can be inserted - * during a compute or copy pass. - * - * This means that the "default" usage mode of any given resource should be that it should be - * ready for a graphics-read operation, because we cannot barrier during a render pass. - * In the case where a resource is only used in compute, its default usage mode can be compute-read. - * This strategy allows us to avoid expensive record keeping of command buffer/resource usage mode pairs, - * and it fully covers synchronization between all combinations of stages. - * - * In Upload and Copy functions, we transition the resource immediately before and after the copy command. - * - * When binding a resource for compute, we transition when the Bind functions are called. - * If a bind slot containing a resource is overwritten, we transition the resource in that slot back to its default. - * When EndComputePass is called we transition all bound resources back to their default state. - * - * When binding a texture as a render pass attachment, we transition the resource on BeginRenderPass - * and transition it back to its default on EndRenderPass. - * - * This strategy imposes certain limitations on resource usage flags. - * For example, a texture cannot have both the SAMPLER and GRAPHICS_STORAGE usage flags, - * because then it is impossible for the backend to infer which default usage mode the texture should use. - * - * Sync hazards can be detected by setting VK_KHRONOS_VALIDATION_VALIDATE_SYNC=1 when using validation layers. - */ - -static void VULKAN_INTERNAL_BufferMemoryBarrier( - VulkanRenderer *renderer, - VulkanCommandBuffer *commandBuffer, - VulkanBufferUsageMode sourceUsageMode, - VulkanBufferUsageMode destinationUsageMode, - VulkanBuffer *buffer) -{ - VkPipelineStageFlags srcStages = 0; - VkPipelineStageFlags dstStages = 0; - VkBufferMemoryBarrier memoryBarrier; - - memoryBarrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER; - memoryBarrier.pNext = NULL; - memoryBarrier.srcAccessMask = 0; - memoryBarrier.dstAccessMask = 0; - memoryBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - memoryBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - memoryBarrier.buffer = buffer->buffer; - memoryBarrier.offset = 0; - memoryBarrier.size = buffer->size; - - if (sourceUsageMode == VULKAN_BUFFER_USAGE_MODE_COPY_SOURCE) { - srcStages = VK_PIPELINE_STAGE_TRANSFER_BIT; - memoryBarrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT; - } else if (sourceUsageMode == VULKAN_BUFFER_USAGE_MODE_COPY_DESTINATION) { - srcStages = VK_PIPELINE_STAGE_TRANSFER_BIT; - memoryBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - } else if (sourceUsageMode == VULKAN_BUFFER_USAGE_MODE_VERTEX_READ) { - srcStages = VK_PIPELINE_STAGE_VERTEX_INPUT_BIT; - memoryBarrier.srcAccessMask = VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT; - } else if (sourceUsageMode == VULKAN_BUFFER_USAGE_MODE_INDEX_READ) { - srcStages = VK_PIPELINE_STAGE_VERTEX_INPUT_BIT; - memoryBarrier.srcAccessMask = VK_ACCESS_INDEX_READ_BIT; - } else if (sourceUsageMode == VULKAN_BUFFER_USAGE_MODE_INDIRECT) { - srcStages = VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT; - memoryBarrier.srcAccessMask = VK_ACCESS_INDIRECT_COMMAND_READ_BIT; - } else if (sourceUsageMode == VULKAN_BUFFER_USAGE_MODE_GRAPHICS_STORAGE_READ) { - srcStages = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; - memoryBarrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT; - } else if (sourceUsageMode == VULKAN_BUFFER_USAGE_MODE_COMPUTE_STORAGE_READ) { - srcStages = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; - memoryBarrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT; - } else if (sourceUsageMode == VULKAN_BUFFER_USAGE_MODE_COMPUTE_STORAGE_READ_WRITE) { - srcStages = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; - memoryBarrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT; - } else { - SDL_LogError(SDL_LOG_CATEGORY_GPU, "Unrecognized buffer source barrier type!"); - return; - } - - if (destinationUsageMode == VULKAN_BUFFER_USAGE_MODE_COPY_SOURCE) { - dstStages = VK_PIPELINE_STAGE_TRANSFER_BIT; - memoryBarrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; - } else if (destinationUsageMode == VULKAN_BUFFER_USAGE_MODE_COPY_DESTINATION) { - dstStages = VK_PIPELINE_STAGE_TRANSFER_BIT; - memoryBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - } else if (destinationUsageMode == VULKAN_BUFFER_USAGE_MODE_VERTEX_READ) { - dstStages = VK_PIPELINE_STAGE_VERTEX_INPUT_BIT; - memoryBarrier.dstAccessMask = VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT; - } else if (destinationUsageMode == VULKAN_BUFFER_USAGE_MODE_INDEX_READ) { - dstStages = VK_PIPELINE_STAGE_VERTEX_INPUT_BIT; - memoryBarrier.dstAccessMask = VK_ACCESS_INDEX_READ_BIT; - } else if (destinationUsageMode == VULKAN_BUFFER_USAGE_MODE_INDIRECT) { - dstStages = VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT; - memoryBarrier.dstAccessMask = VK_ACCESS_INDIRECT_COMMAND_READ_BIT; - } else if (destinationUsageMode == VULKAN_BUFFER_USAGE_MODE_GRAPHICS_STORAGE_READ) { - dstStages = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; - memoryBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; - } else if (destinationUsageMode == VULKAN_BUFFER_USAGE_MODE_COMPUTE_STORAGE_READ) { - dstStages = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; - memoryBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; - } else if (destinationUsageMode == VULKAN_BUFFER_USAGE_MODE_COMPUTE_STORAGE_READ_WRITE) { - dstStages = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; - memoryBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT; - } else { - SDL_LogError(SDL_LOG_CATEGORY_GPU, "Unrecognized buffer destination barrier type!"); - return; - } - - renderer->vkCmdPipelineBarrier( - commandBuffer->commandBuffer, - srcStages, - dstStages, - 0, - 0, - NULL, - 1, - &memoryBarrier, - 0, - NULL); - - buffer->transitioned = true; -} - -static void VULKAN_INTERNAL_TextureSubresourceMemoryBarrier( - VulkanRenderer *renderer, - VulkanCommandBuffer *commandBuffer, - VulkanTextureUsageMode sourceUsageMode, - VulkanTextureUsageMode destinationUsageMode, - VulkanTextureSubresource *textureSubresource) -{ - VkPipelineStageFlags srcStages = 0; - VkPipelineStageFlags dstStages = 0; - VkImageMemoryBarrier memoryBarrier; - - memoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; - memoryBarrier.pNext = NULL; - memoryBarrier.srcAccessMask = 0; - memoryBarrier.dstAccessMask = 0; - memoryBarrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; - memoryBarrier.newLayout = VK_IMAGE_LAYOUT_UNDEFINED; - memoryBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - memoryBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - memoryBarrier.image = textureSubresource->parent->image; - memoryBarrier.subresourceRange.aspectMask = textureSubresource->parent->aspectFlags; - memoryBarrier.subresourceRange.baseArrayLayer = textureSubresource->layer; - memoryBarrier.subresourceRange.layerCount = 1; - memoryBarrier.subresourceRange.baseMipLevel = textureSubresource->level; - memoryBarrier.subresourceRange.levelCount = 1; - - if (sourceUsageMode == VULKAN_TEXTURE_USAGE_MODE_UNINITIALIZED) { - srcStages = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; - memoryBarrier.srcAccessMask = 0; - memoryBarrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; - } else if (sourceUsageMode == VULKAN_TEXTURE_USAGE_MODE_COPY_SOURCE) { - srcStages = VK_PIPELINE_STAGE_TRANSFER_BIT; - memoryBarrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT; - memoryBarrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; - } else if (sourceUsageMode == VULKAN_TEXTURE_USAGE_MODE_COPY_DESTINATION) { - srcStages = VK_PIPELINE_STAGE_TRANSFER_BIT; - memoryBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - memoryBarrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; - } else if (sourceUsageMode == VULKAN_TEXTURE_USAGE_MODE_SAMPLER) { - srcStages = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; - memoryBarrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT; - memoryBarrier.oldLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - } else if (sourceUsageMode == VULKAN_TEXTURE_USAGE_MODE_GRAPHICS_STORAGE_READ) { - srcStages = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; - memoryBarrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT; - memoryBarrier.oldLayout = VK_IMAGE_LAYOUT_GENERAL; - } else if (sourceUsageMode == VULKAN_TEXTURE_USAGE_MODE_COMPUTE_STORAGE_READ) { - srcStages = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; - memoryBarrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT; - memoryBarrier.oldLayout = VK_IMAGE_LAYOUT_GENERAL; - } else if (sourceUsageMode == VULKAN_TEXTURE_USAGE_MODE_COMPUTE_STORAGE_READ_WRITE) { - srcStages = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; - memoryBarrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT; - memoryBarrier.oldLayout = VK_IMAGE_LAYOUT_GENERAL; - } else if (sourceUsageMode == VULKAN_TEXTURE_USAGE_MODE_COLOR_ATTACHMENT) { - srcStages = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; - memoryBarrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; - memoryBarrier.oldLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - } else if (sourceUsageMode == VULKAN_TEXTURE_USAGE_MODE_DEPTH_STENCIL_ATTACHMENT) { - srcStages = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT; - memoryBarrier.srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; - memoryBarrier.oldLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; - } else { - SDL_LogError(SDL_LOG_CATEGORY_GPU, "Unrecognized texture source barrier type!"); - return; - } - - if (destinationUsageMode == VULKAN_TEXTURE_USAGE_MODE_COPY_SOURCE) { - dstStages = VK_PIPELINE_STAGE_TRANSFER_BIT; - memoryBarrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; - memoryBarrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; - } else if (destinationUsageMode == VULKAN_TEXTURE_USAGE_MODE_COPY_DESTINATION) { - dstStages = VK_PIPELINE_STAGE_TRANSFER_BIT; - memoryBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - memoryBarrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; - } else if (destinationUsageMode == VULKAN_TEXTURE_USAGE_MODE_SAMPLER) { - dstStages = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; - memoryBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; - memoryBarrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - } else if (destinationUsageMode == VULKAN_TEXTURE_USAGE_MODE_GRAPHICS_STORAGE_READ) { - dstStages = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; - memoryBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; - memoryBarrier.newLayout = VK_IMAGE_LAYOUT_GENERAL; - } else if (destinationUsageMode == VULKAN_TEXTURE_USAGE_MODE_COMPUTE_STORAGE_READ) { - dstStages = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; - memoryBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; - memoryBarrier.newLayout = VK_IMAGE_LAYOUT_GENERAL; - } else if (destinationUsageMode == VULKAN_TEXTURE_USAGE_MODE_COMPUTE_STORAGE_READ_WRITE) { - dstStages = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; - memoryBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT; - memoryBarrier.newLayout = VK_IMAGE_LAYOUT_GENERAL; - } else if (destinationUsageMode == VULKAN_TEXTURE_USAGE_MODE_COLOR_ATTACHMENT) { - dstStages = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; - memoryBarrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; - memoryBarrier.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - } else if (destinationUsageMode == VULKAN_TEXTURE_USAGE_MODE_DEPTH_STENCIL_ATTACHMENT) { - dstStages = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT; - memoryBarrier.dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; - memoryBarrier.newLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; - } else if (destinationUsageMode == VULKAN_TEXTURE_USAGE_MODE_PRESENT) { - dstStages = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; - memoryBarrier.dstAccessMask = 0; - memoryBarrier.newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; - } else { - SDL_LogError(SDL_LOG_CATEGORY_GPU, "Unrecognized texture destination barrier type!"); - return; - } - - renderer->vkCmdPipelineBarrier( - commandBuffer->commandBuffer, - srcStages, - dstStages, - 0, - 0, - NULL, - 0, - NULL, - 1, - &memoryBarrier); -} - -static VulkanBufferUsageMode VULKAN_INTERNAL_DefaultBufferUsageMode( - VulkanBuffer *buffer) -{ - // NOTE: order matters here! - - if (buffer->usage & SDL_GPU_BUFFERUSAGE_VERTEX) { - return VULKAN_BUFFER_USAGE_MODE_VERTEX_READ; - } else if (buffer->usage & SDL_GPU_BUFFERUSAGE_INDEX) { - return VULKAN_BUFFER_USAGE_MODE_INDEX_READ; - } else if (buffer->usage & SDL_GPU_BUFFERUSAGE_INDIRECT) { - return VULKAN_BUFFER_USAGE_MODE_INDIRECT; - } else if (buffer->usage & SDL_GPU_BUFFERUSAGE_GRAPHICS_STORAGE_READ) { - return VULKAN_BUFFER_USAGE_MODE_GRAPHICS_STORAGE_READ; - } else if (buffer->usage & SDL_GPU_BUFFERUSAGE_COMPUTE_STORAGE_READ) { - return VULKAN_BUFFER_USAGE_MODE_COMPUTE_STORAGE_READ; - } else if (buffer->usage & SDL_GPU_BUFFERUSAGE_COMPUTE_STORAGE_WRITE) { - return VULKAN_BUFFER_USAGE_MODE_COMPUTE_STORAGE_READ_WRITE; - } else { - SDL_LogError(SDL_LOG_CATEGORY_GPU, "Buffer has no default usage mode!"); - return VULKAN_BUFFER_USAGE_MODE_VERTEX_READ; - } -} - -static VulkanTextureUsageMode VULKAN_INTERNAL_DefaultTextureUsageMode( - VulkanTexture *texture) -{ - // NOTE: order matters here! - // NOTE: graphics storage bits and sampler bit are mutually exclusive! - - if (texture->usage & SDL_GPU_TEXTUREUSAGE_SAMPLER) { - return VULKAN_TEXTURE_USAGE_MODE_SAMPLER; - } else if (texture->usage & SDL_GPU_TEXTUREUSAGE_GRAPHICS_STORAGE_READ) { - return VULKAN_TEXTURE_USAGE_MODE_GRAPHICS_STORAGE_READ; - } else if (texture->usage & SDL_GPU_TEXTUREUSAGE_COLOR_TARGET) { - return VULKAN_TEXTURE_USAGE_MODE_COLOR_ATTACHMENT; - } else if (texture->usage & SDL_GPU_TEXTUREUSAGE_DEPTH_STENCIL_TARGET) { - return VULKAN_TEXTURE_USAGE_MODE_DEPTH_STENCIL_ATTACHMENT; - } else if (texture->usage & SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_READ) { - return VULKAN_TEXTURE_USAGE_MODE_COMPUTE_STORAGE_READ; - } else if (texture->usage & SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_WRITE) { - return VULKAN_TEXTURE_USAGE_MODE_COMPUTE_STORAGE_READ_WRITE; - } else if (texture->usage & SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_SIMULTANEOUS_READ_WRITE) { - return VULKAN_TEXTURE_USAGE_MODE_COMPUTE_STORAGE_READ_WRITE; - } else { - SDL_LogError(SDL_LOG_CATEGORY_GPU, "Texture has no default usage mode!"); - return VULKAN_TEXTURE_USAGE_MODE_SAMPLER; - } -} - -static void VULKAN_INTERNAL_BufferTransitionFromDefaultUsage( - VulkanRenderer *renderer, - VulkanCommandBuffer *commandBuffer, - VulkanBufferUsageMode destinationUsageMode, - VulkanBuffer *buffer) -{ - VULKAN_INTERNAL_BufferMemoryBarrier( - renderer, - commandBuffer, - VULKAN_INTERNAL_DefaultBufferUsageMode(buffer), - destinationUsageMode, - buffer); -} - -static void VULKAN_INTERNAL_BufferTransitionToDefaultUsage( - VulkanRenderer *renderer, - VulkanCommandBuffer *commandBuffer, - VulkanBufferUsageMode sourceUsageMode, - VulkanBuffer *buffer) -{ - VULKAN_INTERNAL_BufferMemoryBarrier( - renderer, - commandBuffer, - sourceUsageMode, - VULKAN_INTERNAL_DefaultBufferUsageMode(buffer), - buffer); -} - -static void VULKAN_INTERNAL_TextureSubresourceTransitionFromDefaultUsage( - VulkanRenderer *renderer, - VulkanCommandBuffer *commandBuffer, - VulkanTextureUsageMode destinationUsageMode, - VulkanTextureSubresource *textureSubresource) -{ - VULKAN_INTERNAL_TextureSubresourceMemoryBarrier( - renderer, - commandBuffer, - VULKAN_INTERNAL_DefaultTextureUsageMode(textureSubresource->parent), - destinationUsageMode, - textureSubresource); -} - -static void VULKAN_INTERNAL_TextureTransitionFromDefaultUsage( - VulkanRenderer *renderer, - VulkanCommandBuffer *commandBuffer, - VulkanTextureUsageMode destinationUsageMode, - VulkanTexture *texture) -{ - for (Uint32 i = 0; i < texture->subresourceCount; i += 1) { - VULKAN_INTERNAL_TextureSubresourceTransitionFromDefaultUsage( - renderer, - commandBuffer, - destinationUsageMode, - &texture->subresources[i]); - } -} - -static void VULKAN_INTERNAL_TextureSubresourceTransitionToDefaultUsage( - VulkanRenderer *renderer, - VulkanCommandBuffer *commandBuffer, - VulkanTextureUsageMode sourceUsageMode, - VulkanTextureSubresource *textureSubresource) -{ - VULKAN_INTERNAL_TextureSubresourceMemoryBarrier( - renderer, - commandBuffer, - sourceUsageMode, - VULKAN_INTERNAL_DefaultTextureUsageMode(textureSubresource->parent), - textureSubresource); -} - -static void VULKAN_INTERNAL_TextureTransitionToDefaultUsage( - VulkanRenderer *renderer, - VulkanCommandBuffer *commandBuffer, - VulkanTextureUsageMode sourceUsageMode, - VulkanTexture *texture) -{ - // FIXME: could optimize this barrier - for (Uint32 i = 0; i < texture->subresourceCount; i += 1) { - VULKAN_INTERNAL_TextureSubresourceTransitionToDefaultUsage( - renderer, - commandBuffer, - sourceUsageMode, - &texture->subresources[i]); - } -} - -// Resource Disposal - -static void VULKAN_INTERNAL_ReleaseFramebuffer( - VulkanRenderer *renderer, - VulkanFramebuffer *framebuffer) -{ - SDL_LockMutex(renderer->disposeLock); - - EXPAND_ARRAY_IF_NEEDED( - renderer->framebuffersToDestroy, - VulkanFramebuffer *, - renderer->framebuffersToDestroyCount + 1, - renderer->framebuffersToDestroyCapacity, - renderer->framebuffersToDestroyCapacity * 2); - - renderer->framebuffersToDestroy[renderer->framebuffersToDestroyCount] = framebuffer; - renderer->framebuffersToDestroyCount += 1; - - SDL_UnlockMutex(renderer->disposeLock); -} - -static void VULKAN_INTERNAL_DestroyFramebuffer( - VulkanRenderer *renderer, - VulkanFramebuffer *framebuffer) -{ - renderer->vkDestroyFramebuffer( - renderer->logicalDevice, - framebuffer->framebuffer, - NULL); - - SDL_free(framebuffer); -} - -typedef struct CheckOneFramebufferForRemovalData -{ - Uint32 keysToRemoveCapacity; - Uint32 keysToRemoveCount; - FramebufferHashTableKey **keysToRemove; - VkImageView view; -} CheckOneFramebufferForRemovalData; - -static bool SDLCALL CheckOneFramebufferForRemoval(void *userdata, const SDL_HashTable *table, const void *vkey, const void *vvalue) -{ - CheckOneFramebufferForRemovalData *data = (CheckOneFramebufferForRemovalData *) userdata; - FramebufferHashTableKey *key = (FramebufferHashTableKey *) vkey; - VkImageView view = data->view; - bool remove = false; - - for (Uint32 i = 0; i < key->numColorTargets; i += 1) { - if (key->colorAttachmentViews[i] == view) { - remove = true; - } - } - for (Uint32 i = 0; i < key->numResolveAttachments; i += 1) { - if (key->resolveAttachmentViews[i] == view) { - remove = true; - } - } - if (key->depthStencilAttachmentView == view) { - remove = true; - } - - if (remove) { - if (data->keysToRemoveCount == data->keysToRemoveCapacity) { - data->keysToRemoveCapacity *= 2; - void *ptr = SDL_realloc(data->keysToRemove, data->keysToRemoveCapacity * sizeof(FramebufferHashTableKey *)); - if (!ptr) { - return false; // ugh, stop iterating. We're in trouble. - } - data->keysToRemove = (FramebufferHashTableKey **) ptr; - } - data->keysToRemove[data->keysToRemoveCount] = key; - data->keysToRemoveCount++; - } - - return true; // keep iterating. -} - -static void VULKAN_INTERNAL_RemoveFramebuffersContainingView( - VulkanRenderer *renderer, - VkImageView view) -{ - // Can't remove while iterating! - - CheckOneFramebufferForRemovalData data = { 8, 0, NULL, view }; - data.keysToRemove = (FramebufferHashTableKey **) SDL_malloc(data.keysToRemoveCapacity * sizeof(FramebufferHashTableKey *)); - if (!data.keysToRemove) { - return; // uhoh. - } - - SDL_LockMutex(renderer->framebufferFetchLock); - - SDL_IterateHashTable(renderer->framebufferHashTable, CheckOneFramebufferForRemoval, &data); - - for (Uint32 i = 0; i < data.keysToRemoveCount; i += 1) { - SDL_RemoveFromHashTable(renderer->framebufferHashTable, (void *)data.keysToRemove[i]); - } - - SDL_UnlockMutex(renderer->framebufferFetchLock); - - SDL_free(data.keysToRemove); -} - -static void VULKAN_INTERNAL_DestroyTexture( - VulkanRenderer *renderer, - VulkanTexture *texture) -{ - // Clean up subresources - for (Uint32 subresourceIndex = 0; subresourceIndex < texture->subresourceCount; subresourceIndex += 1) { - if (texture->subresources[subresourceIndex].renderTargetViews != NULL) { - for (Uint32 depthIndex = 0; depthIndex < texture->depth; depthIndex += 1) { - VULKAN_INTERNAL_RemoveFramebuffersContainingView( - renderer, - texture->subresources[subresourceIndex].renderTargetViews[depthIndex]); - } - - for (Uint32 depthIndex = 0; depthIndex < texture->depth; depthIndex += 1) { - renderer->vkDestroyImageView( - renderer->logicalDevice, - texture->subresources[subresourceIndex].renderTargetViews[depthIndex], - NULL); - } - SDL_free(texture->subresources[subresourceIndex].renderTargetViews); - } - - if (texture->subresources[subresourceIndex].computeWriteView != VK_NULL_HANDLE) { - renderer->vkDestroyImageView( - renderer->logicalDevice, - texture->subresources[subresourceIndex].computeWriteView, - NULL); - } - - if (texture->subresources[subresourceIndex].depthStencilView != VK_NULL_HANDLE) { - VULKAN_INTERNAL_RemoveFramebuffersContainingView( - renderer, - texture->subresources[subresourceIndex].depthStencilView); - renderer->vkDestroyImageView( - renderer->logicalDevice, - texture->subresources[subresourceIndex].depthStencilView, - NULL); - } - } - - SDL_free(texture->subresources); - - if (texture->fullView) { - renderer->vkDestroyImageView( - renderer->logicalDevice, - texture->fullView, - NULL); - } - - if (texture->image) { - renderer->vkDestroyImage( - renderer->logicalDevice, - texture->image, - NULL); - } - - if (texture->usedRegion) { - VULKAN_INTERNAL_RemoveMemoryUsedRegion( - renderer, - texture->usedRegion); - } - - SDL_free(texture); -} - -static void VULKAN_INTERNAL_DestroyBuffer( - VulkanRenderer *renderer, - VulkanBuffer *buffer) -{ - renderer->vkDestroyBuffer( - renderer->logicalDevice, - buffer->buffer, - NULL); - - VULKAN_INTERNAL_RemoveMemoryUsedRegion( - renderer, - buffer->usedRegion); - - SDL_free(buffer); -} - -static void VULKAN_INTERNAL_DestroyCommandPool( - VulkanRenderer *renderer, - VulkanCommandPool *commandPool) -{ - Uint32 i; - VulkanCommandBuffer *commandBuffer; - - renderer->vkDestroyCommandPool( - renderer->logicalDevice, - commandPool->commandPool, - NULL); - - for (i = 0; i < commandPool->inactiveCommandBufferCount; i += 1) { - commandBuffer = commandPool->inactiveCommandBuffers[i]; - - SDL_free(commandBuffer->presentDatas); - SDL_free(commandBuffer->waitSemaphores); - SDL_free(commandBuffer->signalSemaphores); - SDL_free(commandBuffer->usedBuffers); - SDL_free(commandBuffer->usedTextures); - SDL_free(commandBuffer->usedSamplers); - SDL_free(commandBuffer->usedGraphicsPipelines); - SDL_free(commandBuffer->usedComputePipelines); - SDL_free(commandBuffer->usedFramebuffers); - SDL_free(commandBuffer->usedUniformBuffers); - - SDL_free(commandBuffer); - } - - SDL_free(commandPool->inactiveCommandBuffers); - SDL_free(commandPool); -} - -static void VULKAN_INTERNAL_DestroyDescriptorSetLayout( - VulkanRenderer *renderer, - DescriptorSetLayout *layout) -{ - if (layout == NULL) { - return; - } - - if (layout->descriptorSetLayout != VK_NULL_HANDLE) { - renderer->vkDestroyDescriptorSetLayout( - renderer->logicalDevice, - layout->descriptorSetLayout, - NULL); - } - - SDL_free(layout); -} - -static void VULKAN_INTERNAL_DestroyGraphicsPipeline( - VulkanRenderer *renderer, - VulkanGraphicsPipeline *graphicsPipeline) -{ - renderer->vkDestroyPipeline( - renderer->logicalDevice, - graphicsPipeline->pipeline, - NULL); - - (void)SDL_AtomicDecRef(&graphicsPipeline->vertexShader->referenceCount); - (void)SDL_AtomicDecRef(&graphicsPipeline->fragmentShader->referenceCount); - - SDL_free(graphicsPipeline); -} - -static void VULKAN_INTERNAL_DestroyComputePipeline( - VulkanRenderer *renderer, - VulkanComputePipeline *computePipeline) -{ - if (computePipeline->pipeline != VK_NULL_HANDLE) { - renderer->vkDestroyPipeline( - renderer->logicalDevice, - computePipeline->pipeline, - NULL); - } - - if (computePipeline->shaderModule != VK_NULL_HANDLE) { - renderer->vkDestroyShaderModule( - renderer->logicalDevice, - computePipeline->shaderModule, - NULL); - } - - SDL_free(computePipeline); -} - -static void VULKAN_INTERNAL_DestroyShader( - VulkanRenderer *renderer, - VulkanShader *vulkanShader) -{ - renderer->vkDestroyShaderModule( - renderer->logicalDevice, - vulkanShader->shaderModule, - NULL); - - SDL_free((void *)vulkanShader->entrypointName); - SDL_free(vulkanShader); -} - -static void VULKAN_INTERNAL_DestroySampler( - VulkanRenderer *renderer, - VulkanSampler *vulkanSampler) -{ - renderer->vkDestroySampler( - renderer->logicalDevice, - vulkanSampler->sampler, - NULL); - - SDL_free(vulkanSampler); -} - -static void VULKAN_INTERNAL_DestroySwapchain( - VulkanRenderer *renderer, - WindowData *windowData) -{ - Uint32 i; - - if (windowData == NULL) { - return; - } - - for (i = 0; i < windowData->imageCount; i += 1) { - VULKAN_INTERNAL_RemoveFramebuffersContainingView( - renderer, - windowData->textureContainers[i].activeTexture->subresources[0].renderTargetViews[0]); - renderer->vkDestroyImageView( - renderer->logicalDevice, - windowData->textureContainers[i].activeTexture->subresources[0].renderTargetViews[0], - NULL); - SDL_free(windowData->textureContainers[i].activeTexture->subresources[0].renderTargetViews); - SDL_free(windowData->textureContainers[i].activeTexture->subresources); - SDL_free(windowData->textureContainers[i].activeTexture); - } - windowData->imageCount = 0; - - SDL_free(windowData->textureContainers); - windowData->textureContainers = NULL; - - if (windowData->swapchain) { - renderer->vkDestroySwapchainKHR( - renderer->logicalDevice, - windowData->swapchain, - NULL); - windowData->swapchain = VK_NULL_HANDLE; - } - - if (windowData->surface) { - renderer->vkDestroySurfaceKHR( - renderer->instance, - windowData->surface, - NULL); - windowData->surface = VK_NULL_HANDLE; - } - - for (i = 0; i < MAX_FRAMES_IN_FLIGHT; i += 1) { - if (windowData->imageAvailableSemaphore[i]) { - renderer->vkDestroySemaphore( - renderer->logicalDevice, - windowData->imageAvailableSemaphore[i], - NULL); - windowData->imageAvailableSemaphore[i] = VK_NULL_HANDLE; - } - - if (windowData->renderFinishedSemaphore[i]) { - renderer->vkDestroySemaphore( - renderer->logicalDevice, - windowData->renderFinishedSemaphore[i], - NULL); - windowData->renderFinishedSemaphore[i] = VK_NULL_HANDLE; - } - } -} - -static void VULKAN_INTERNAL_DestroyGraphicsPipelineResourceLayout( - VulkanRenderer *renderer, - VulkanGraphicsPipelineResourceLayout *resourceLayout) -{ - if (resourceLayout->pipelineLayout != VK_NULL_HANDLE) { - renderer->vkDestroyPipelineLayout( - renderer->logicalDevice, - resourceLayout->pipelineLayout, - NULL); - } - - SDL_free(resourceLayout); -} - -static void VULKAN_INTERNAL_DestroyComputePipelineResourceLayout( - VulkanRenderer *renderer, - VulkanComputePipelineResourceLayout *resourceLayout) -{ - if (resourceLayout->pipelineLayout != VK_NULL_HANDLE) { - renderer->vkDestroyPipelineLayout( - renderer->logicalDevice, - resourceLayout->pipelineLayout, - NULL); - } - - SDL_free(resourceLayout); -} - -static void VULKAN_INTERNAL_DestroyDescriptorSetCache( - VulkanRenderer *renderer, - DescriptorSetCache *descriptorSetCache) -{ - for (Uint32 i = 0; i < descriptorSetCache->poolCount; i += 1) { - for (Uint32 j = 0; j < descriptorSetCache->pools[i].poolCount; j += 1) { - renderer->vkDestroyDescriptorPool( - renderer->logicalDevice, - descriptorSetCache->pools[i].descriptorPools[j], - NULL); - } - SDL_free(descriptorSetCache->pools[i].descriptorSets); - SDL_free(descriptorSetCache->pools[i].descriptorPools); - } - SDL_free(descriptorSetCache->pools); - SDL_free(descriptorSetCache); -} - -// Hashtable functions - -static Uint32 SDLCALL VULKAN_INTERNAL_GraphicsPipelineResourceLayoutHashFunction(void *userdata, const void *key) -{ - GraphicsPipelineResourceLayoutHashTableKey *hashTableKey = (GraphicsPipelineResourceLayoutHashTableKey *)key; - /* The algorithm for this hashing function - * is taken from Josh Bloch's "Effective Java". - * (https://stackoverflow.com/a/113600/12492383) - */ - const Uint32 hashFactor = 31; - Uint32 result = 1; - result = result * hashFactor + hashTableKey->vertexSamplerCount; - result = result * hashFactor + hashTableKey->vertexStorageBufferCount; - result = result * hashFactor + hashTableKey->vertexStorageTextureCount; - result = result * hashFactor + hashTableKey->vertexUniformBufferCount; - result = result * hashFactor + hashTableKey->fragmentSamplerCount; - result = result * hashFactor + hashTableKey->fragmentStorageBufferCount; - result = result * hashFactor + hashTableKey->fragmentStorageTextureCount; - result = result * hashFactor + hashTableKey->fragmentUniformBufferCount; - return result; -} -static bool SDLCALL VULKAN_INTERNAL_GraphicsPipelineResourceLayoutHashKeyMatch(void *userdata, const void *aKey, const void *bKey) -{ - return SDL_memcmp(aKey, bKey, sizeof(GraphicsPipelineResourceLayoutHashTableKey)) == 0; -} -static void SDLCALL VULKAN_INTERNAL_GraphicsPipelineResourceLayoutHashDestroy(void *userdata, const void *key, const void *value) -{ - VulkanRenderer *renderer = (VulkanRenderer *)userdata; - VulkanGraphicsPipelineResourceLayout *resourceLayout = (VulkanGraphicsPipelineResourceLayout *)value; - VULKAN_INTERNAL_DestroyGraphicsPipelineResourceLayout(renderer, resourceLayout); - SDL_free((void*)key); -} - -static Uint32 SDLCALL VULKAN_INTERNAL_ComputePipelineResourceLayoutHashFunction(void *userdata, const void *key) -{ - ComputePipelineResourceLayoutHashTableKey *hashTableKey = (ComputePipelineResourceLayoutHashTableKey *)key; - /* The algorithm for this hashing function - * is taken from Josh Bloch's "Effective Java". - * (https://stackoverflow.com/a/113600/12492383) - */ - const Uint32 hashFactor = 31; - Uint32 result = 1; - result = result * hashFactor + hashTableKey->samplerCount; - result = result * hashFactor + hashTableKey->readonlyStorageTextureCount; - result = result * hashFactor + hashTableKey->readonlyStorageBufferCount; - result = result * hashFactor + hashTableKey->readWriteStorageTextureCount; - result = result * hashFactor + hashTableKey->readWriteStorageBufferCount; - result = result * hashFactor + hashTableKey->uniformBufferCount; - return result; -} - -static bool SDLCALL VULKAN_INTERNAL_ComputePipelineResourceLayoutHashKeyMatch(void *userdata, const void *aKey, const void *bKey) -{ - return SDL_memcmp(aKey, bKey, sizeof(ComputePipelineResourceLayoutHashTableKey)) == 0; -} - -static void SDLCALL VULKAN_INTERNAL_ComputePipelineResourceLayoutHashDestroy(void *userdata, const void *key, const void *value) -{ - VulkanRenderer *renderer = (VulkanRenderer *)userdata; - VulkanComputePipelineResourceLayout *resourceLayout = (VulkanComputePipelineResourceLayout *)value; - VULKAN_INTERNAL_DestroyComputePipelineResourceLayout(renderer, resourceLayout); - SDL_free((void*)key); -} - -static Uint32 SDLCALL VULKAN_INTERNAL_DescriptorSetLayoutHashFunction(void *userdata, const void *key) -{ - DescriptorSetLayoutHashTableKey *hashTableKey = (DescriptorSetLayoutHashTableKey *)key; - - /* The algorithm for this hashing function - * is taken from Josh Bloch's "Effective Java". - * (https://stackoverflow.com/a/113600/12492383) - */ - const Uint32 hashFactor = 31; - Uint32 result = 1; - result = result * hashFactor + hashTableKey->shaderStage; - result = result * hashFactor + hashTableKey->samplerCount; - result = result * hashFactor + hashTableKey->storageTextureCount; - result = result * hashFactor + hashTableKey->storageBufferCount; - result = result * hashFactor + hashTableKey->writeStorageTextureCount; - result = result * hashFactor + hashTableKey->writeStorageBufferCount; - result = result * hashFactor + hashTableKey->uniformBufferCount; - return result; -} - -static bool SDLCALL VULKAN_INTERNAL_DescriptorSetLayoutHashKeyMatch(void *userdata, const void *aKey, const void *bKey) -{ - return SDL_memcmp(aKey, bKey, sizeof(DescriptorSetLayoutHashTableKey)) == 0; -} - -static void SDLCALL VULKAN_INTERNAL_DescriptorSetLayoutHashDestroy(void *userdata, const void *key, const void *value) -{ - VulkanRenderer *renderer = (VulkanRenderer *)userdata; - DescriptorSetLayout *layout = (DescriptorSetLayout *)value; - VULKAN_INTERNAL_DestroyDescriptorSetLayout(renderer, layout); - SDL_free((void*)key); -} - -static Uint32 SDLCALL VULKAN_INTERNAL_CommandPoolHashFunction(void *userdata, const void *key) -{ - return (Uint32)((CommandPoolHashTableKey *)key)->threadID; -} - -static bool SDLCALL VULKAN_INTERNAL_CommandPoolHashKeyMatch(void *userdata, const void *aKey, const void *bKey) -{ - CommandPoolHashTableKey *a = (CommandPoolHashTableKey *)aKey; - CommandPoolHashTableKey *b = (CommandPoolHashTableKey *)bKey; - return a->threadID == b->threadID; -} - -static void SDLCALL VULKAN_INTERNAL_CommandPoolHashDestroy(void *userdata, const void *key, const void *value) -{ - VulkanRenderer *renderer = (VulkanRenderer *)userdata; - VulkanCommandPool *pool = (VulkanCommandPool *)value; - VULKAN_INTERNAL_DestroyCommandPool(renderer, pool); - SDL_free((void *)key); -} - -static Uint32 SDLCALL VULKAN_INTERNAL_RenderPassHashFunction(void *userdata, const void *key) -{ - RenderPassHashTableKey *hashTableKey = (RenderPassHashTableKey *)key; - - /* The algorithm for this hashing function - * is taken from Josh Bloch's "Effective Java". - * (https://stackoverflow.com/a/113600/12492383) - */ - const Uint32 hashFactor = 31; - Uint32 result = 1; - - for (Uint32 i = 0; i < hashTableKey->numColorTargets; i += 1) { - result = result * hashFactor + hashTableKey->colorTargetDescriptions[i].loadOp; - result = result * hashFactor + hashTableKey->colorTargetDescriptions[i].storeOp; - result = result * hashFactor + hashTableKey->colorTargetDescriptions[i].format; - } - - for (Uint32 i = 0; i < hashTableKey->numResolveTargets; i += 1) { - result = result * hashFactor + hashTableKey->resolveTargetFormats[i]; - } - - result = result * hashFactor + hashTableKey->depthStencilTargetDescription.loadOp; - result = result * hashFactor + hashTableKey->depthStencilTargetDescription.storeOp; - result = result * hashFactor + hashTableKey->depthStencilTargetDescription.stencilLoadOp; - result = result * hashFactor + hashTableKey->depthStencilTargetDescription.stencilStoreOp; - result = result * hashFactor + hashTableKey->depthStencilTargetDescription.format; - - result = result * hashFactor + hashTableKey->sampleCount; - - return result; -} - -static bool SDLCALL VULKAN_INTERNAL_RenderPassHashKeyMatch(void *userdata, const void *aKey, const void *bKey) -{ - RenderPassHashTableKey *a = (RenderPassHashTableKey *)aKey; - RenderPassHashTableKey *b = (RenderPassHashTableKey *)bKey; - - if (a->numColorTargets != b->numColorTargets) { - return 0; - } - - if (a->numResolveTargets != b->numResolveTargets) { - return 0; - } - - if (a->sampleCount != b->sampleCount) { - return 0; - } - - for (Uint32 i = 0; i < a->numColorTargets; i += 1) { - if (a->colorTargetDescriptions[i].format != b->colorTargetDescriptions[i].format) { - return 0; - } - - if (a->colorTargetDescriptions[i].loadOp != b->colorTargetDescriptions[i].loadOp) { - return 0; - } - - if (a->colorTargetDescriptions[i].storeOp != b->colorTargetDescriptions[i].storeOp) { - return 0; - } - } - - for (Uint32 i = 0; i < a->numResolveTargets; i += 1) { - if (a->resolveTargetFormats[i] != b->resolveTargetFormats[i]) { - return 0; - } - } - - if (a->depthStencilTargetDescription.format != b->depthStencilTargetDescription.format) { - return 0; - } - - if (a->depthStencilTargetDescription.loadOp != b->depthStencilTargetDescription.loadOp) { - return 0; - } - - if (a->depthStencilTargetDescription.storeOp != b->depthStencilTargetDescription.storeOp) { - return 0; - } - - if (a->depthStencilTargetDescription.stencilLoadOp != b->depthStencilTargetDescription.stencilLoadOp) { - return 0; - } - - if (a->depthStencilTargetDescription.stencilStoreOp != b->depthStencilTargetDescription.stencilStoreOp) { - return 0; - } - - return 1; -} - -static void SDLCALL VULKAN_INTERNAL_RenderPassHashDestroy(void *userdata, const void *key, const void *value) -{ - VulkanRenderer *renderer = (VulkanRenderer *)userdata; - VulkanRenderPassHashTableValue *renderPassWrapper = (VulkanRenderPassHashTableValue *)value; - renderer->vkDestroyRenderPass( - renderer->logicalDevice, - renderPassWrapper->handle, - NULL); - SDL_free(renderPassWrapper); - SDL_free((void *)key); -} - -static Uint32 SDLCALL VULKAN_INTERNAL_FramebufferHashFunction(void *userdata, const void *key) -{ - FramebufferHashTableKey *hashTableKey = (FramebufferHashTableKey *)key; - - /* The algorithm for this hashing function - * is taken from Josh Bloch's "Effective Java". - * (https://stackoverflow.com/a/113600/12492383) - */ - const Uint32 hashFactor = 31; - Uint32 result = 1; - - for (Uint32 i = 0; i < hashTableKey->numColorTargets; i += 1) { - result = result * hashFactor + (Uint32)(uintptr_t)hashTableKey->colorAttachmentViews[i]; - } - for (Uint32 i = 0; i < hashTableKey->numResolveAttachments; i += 1) { - result = result * hashFactor + (Uint32)(uintptr_t)hashTableKey->resolveAttachmentViews[i]; - } - - result = result * hashFactor + (Uint32)(uintptr_t)hashTableKey->depthStencilAttachmentView; - result = result * hashFactor + hashTableKey->width; - result = result * hashFactor + hashTableKey->height; - - return result; -} - -static bool SDLCALL VULKAN_INTERNAL_FramebufferHashKeyMatch(void *userdata, const void *aKey, const void *bKey) -{ - FramebufferHashTableKey *a = (FramebufferHashTableKey *)aKey; - FramebufferHashTableKey *b = (FramebufferHashTableKey *)bKey; - - if (a->numColorTargets != b->numColorTargets) { - return 0; - } - - if (a->numResolveAttachments != b->numResolveAttachments) { - return 0; - } - - for (Uint32 i = 0; i < a->numColorTargets; i += 1) { - if (a->colorAttachmentViews[i] != b->colorAttachmentViews[i]) { - return 0; - } - } - - for (Uint32 i = 0; i < a->numResolveAttachments; i += 1) { - if (a->resolveAttachmentViews[i] != b->resolveAttachmentViews[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 void SDLCALL VULKAN_INTERNAL_FramebufferHashDestroy(void *userdata, const void *key, const void *value) -{ - VulkanRenderer *renderer = (VulkanRenderer *)userdata; - VulkanFramebuffer *framebuffer = (VulkanFramebuffer *)value; - VULKAN_INTERNAL_ReleaseFramebuffer(renderer, framebuffer); - SDL_free((void *)key); -} - -// Descriptor pools - -static bool VULKAN_INTERNAL_AllocateDescriptorSets( - VulkanRenderer *renderer, - VkDescriptorPool descriptorPool, - VkDescriptorSetLayout descriptorSetLayout, - Uint32 descriptorSetCount, - VkDescriptorSet *descriptorSetArray) -{ - VkDescriptorSetAllocateInfo descriptorSetAllocateInfo; - VkDescriptorSetLayout *descriptorSetLayouts = SDL_stack_alloc(VkDescriptorSetLayout, descriptorSetCount); - VkResult vulkanResult; - Uint32 i; - - for (i = 0; i < descriptorSetCount; i += 1) { - descriptorSetLayouts[i] = descriptorSetLayout; - } - - descriptorSetAllocateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; - descriptorSetAllocateInfo.pNext = NULL; - descriptorSetAllocateInfo.descriptorPool = descriptorPool; - descriptorSetAllocateInfo.descriptorSetCount = descriptorSetCount; - descriptorSetAllocateInfo.pSetLayouts = descriptorSetLayouts; - - vulkanResult = renderer->vkAllocateDescriptorSets( - renderer->logicalDevice, - &descriptorSetAllocateInfo, - descriptorSetArray); - - SDL_stack_free(descriptorSetLayouts); - - CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkAllocateDescriptorSets, false); - - return true; -} - -static bool VULKAN_INTERNAL_AllocateDescriptorsFromPool( - VulkanRenderer *renderer, - DescriptorSetLayout *descriptorSetLayout, - DescriptorSetPool *descriptorSetPool) -{ - VkDescriptorPoolSize descriptorPoolSizes[ - MAX_TEXTURE_SAMPLERS_PER_STAGE + - MAX_STORAGE_TEXTURES_PER_STAGE + - MAX_STORAGE_BUFFERS_PER_STAGE + - MAX_COMPUTE_WRITE_TEXTURES + - MAX_COMPUTE_WRITE_BUFFERS + - MAX_UNIFORM_BUFFERS_PER_STAGE]; - VkDescriptorPoolCreateInfo descriptorPoolInfo; - VkDescriptorPool pool; - VkResult vulkanResult; - - // Category 1 - for (Uint32 i = 0; i < descriptorSetLayout->samplerCount; i += 1) { - descriptorPoolSizes[i].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - descriptorPoolSizes[i].descriptorCount = DESCRIPTOR_POOL_SIZE; - } - - for (Uint32 i = descriptorSetLayout->samplerCount; i < descriptorSetLayout->samplerCount + descriptorSetLayout->storageTextureCount; i += 1) { - descriptorPoolSizes[i].type = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE; // Yes, we are declaring the storage image as a sampled image, because shaders are stupid. - descriptorPoolSizes[i].descriptorCount = DESCRIPTOR_POOL_SIZE; - } - - for (Uint32 i = descriptorSetLayout->samplerCount + descriptorSetLayout->storageTextureCount; i < descriptorSetLayout->samplerCount + descriptorSetLayout->storageTextureCount + descriptorSetLayout->storageBufferCount; i += 1) { - descriptorPoolSizes[i].type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; - descriptorPoolSizes[i].descriptorCount = DESCRIPTOR_POOL_SIZE; - } - - // Category 2 - for (Uint32 i = 0; i < descriptorSetLayout->writeStorageTextureCount; i += 1) { - descriptorPoolSizes[i].type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; - descriptorPoolSizes[i].descriptorCount = DESCRIPTOR_POOL_SIZE; - } - - for (Uint32 i = descriptorSetLayout->writeStorageTextureCount; i < descriptorSetLayout->writeStorageTextureCount + descriptorSetLayout->writeStorageBufferCount; i += 1) { - descriptorPoolSizes[i].type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; - descriptorPoolSizes[i].descriptorCount = DESCRIPTOR_POOL_SIZE; - } - - // Category 3 - for (Uint32 i = 0; i < descriptorSetLayout->uniformBufferCount; i += 1) { - descriptorPoolSizes[i].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC; - descriptorPoolSizes[i].descriptorCount = DESCRIPTOR_POOL_SIZE; - } - - descriptorPoolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; - descriptorPoolInfo.pNext = NULL; - descriptorPoolInfo.flags = 0; - descriptorPoolInfo.maxSets = DESCRIPTOR_POOL_SIZE; - descriptorPoolInfo.poolSizeCount = - descriptorSetLayout->samplerCount + - descriptorSetLayout->storageTextureCount + - descriptorSetLayout->storageBufferCount + - descriptorSetLayout->writeStorageTextureCount + - descriptorSetLayout->writeStorageBufferCount + - descriptorSetLayout->uniformBufferCount; - descriptorPoolInfo.pPoolSizes = descriptorPoolSizes; - - vulkanResult = renderer->vkCreateDescriptorPool( - renderer->logicalDevice, - &descriptorPoolInfo, - NULL, - &pool); - - CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkCreateDescriptorPool, false); - - descriptorSetPool->poolCount += 1; - descriptorSetPool->descriptorPools = SDL_realloc( - descriptorSetPool->descriptorPools, - sizeof(VkDescriptorPool) * descriptorSetPool->poolCount); - - descriptorSetPool->descriptorPools[descriptorSetPool->poolCount - 1] = pool; - - descriptorSetPool->descriptorSets = SDL_realloc( - descriptorSetPool->descriptorSets, - sizeof(VkDescriptorSet) * descriptorSetPool->poolCount * DESCRIPTOR_POOL_SIZE); - - if (!VULKAN_INTERNAL_AllocateDescriptorSets( - renderer, - pool, - descriptorSetLayout->descriptorSetLayout, - DESCRIPTOR_POOL_SIZE, - &descriptorSetPool->descriptorSets[descriptorSetPool->descriptorSetCount])) { - return false; - } - - descriptorSetPool->descriptorSetCount += DESCRIPTOR_POOL_SIZE; - - return true; -} - -// NOTE: these categories should be mutually exclusive -static DescriptorSetLayout *VULKAN_INTERNAL_FetchDescriptorSetLayout( - VulkanRenderer *renderer, - VkShaderStageFlagBits shaderStage, - // Category 1: read resources - Uint32 samplerCount, - Uint32 storageTextureCount, - Uint32 storageBufferCount, - // Category 2: write resources - Uint32 writeStorageTextureCount, - Uint32 writeStorageBufferCount, - // Category 3: uniform buffers - Uint32 uniformBufferCount) -{ - DescriptorSetLayoutHashTableKey key; - SDL_zero(key); - DescriptorSetLayout *layout = NULL; - - key.shaderStage = shaderStage; - key.samplerCount = samplerCount; - key.storageTextureCount = storageTextureCount; - key.storageBufferCount = storageBufferCount; - key.writeStorageTextureCount = writeStorageTextureCount; - key.writeStorageBufferCount = writeStorageBufferCount; - key.uniformBufferCount = uniformBufferCount; - - if (SDL_FindInHashTable( - renderer->descriptorSetLayoutHashTable, - (const void *)&key, - (const void **)&layout)) { - return layout; - } - - VkDescriptorSetLayout descriptorSetLayout; - VkDescriptorSetLayoutBinding descriptorSetLayoutBindings[ - MAX_TEXTURE_SAMPLERS_PER_STAGE + - MAX_STORAGE_TEXTURES_PER_STAGE + - MAX_STORAGE_BUFFERS_PER_STAGE + - MAX_COMPUTE_WRITE_TEXTURES + - MAX_COMPUTE_WRITE_BUFFERS]; - - VkDescriptorSetLayoutCreateInfo descriptorSetLayoutCreateInfo; - descriptorSetLayoutCreateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; - descriptorSetLayoutCreateInfo.pNext = NULL; - descriptorSetLayoutCreateInfo.flags = 0; - - // Category 1 - for (Uint32 i = 0; i < samplerCount; i += 1) { - descriptorSetLayoutBindings[i].binding = i; - descriptorSetLayoutBindings[i].descriptorCount = 1; - descriptorSetLayoutBindings[i].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - descriptorSetLayoutBindings[i].stageFlags = shaderStage; - descriptorSetLayoutBindings[i].pImmutableSamplers = NULL; - } - - for (Uint32 i = samplerCount; i < samplerCount + storageTextureCount; i += 1) { - descriptorSetLayoutBindings[i].binding = i; - descriptorSetLayoutBindings[i].descriptorCount = 1; - descriptorSetLayoutBindings[i].descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE; // Yes, we are declaring the storage image as a sampled image, because shaders are stupid. - descriptorSetLayoutBindings[i].stageFlags = shaderStage; - descriptorSetLayoutBindings[i].pImmutableSamplers = NULL; - } - - for (Uint32 i = samplerCount + storageTextureCount; i < samplerCount + storageTextureCount + storageBufferCount; i += 1) { - descriptorSetLayoutBindings[i].binding = i; - descriptorSetLayoutBindings[i].descriptorCount = 1; - descriptorSetLayoutBindings[i].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; - descriptorSetLayoutBindings[i].stageFlags = shaderStage; - descriptorSetLayoutBindings[i].pImmutableSamplers = NULL; - } - - // Category 2 - for (Uint32 i = 0; i < writeStorageTextureCount; i += 1) { - descriptorSetLayoutBindings[i].binding = i; - descriptorSetLayoutBindings[i].descriptorCount = 1; - descriptorSetLayoutBindings[i].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; - descriptorSetLayoutBindings[i].stageFlags = shaderStage; - descriptorSetLayoutBindings[i].pImmutableSamplers = NULL; - } - - for (Uint32 i = writeStorageTextureCount; i < writeStorageTextureCount + writeStorageBufferCount; i += 1) { - descriptorSetLayoutBindings[i].binding = i; - descriptorSetLayoutBindings[i].descriptorCount = 1; - descriptorSetLayoutBindings[i].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; - descriptorSetLayoutBindings[i].stageFlags = shaderStage; - descriptorSetLayoutBindings[i].pImmutableSamplers = NULL; - } - - // Category 3 - for (Uint32 i = 0; i < uniformBufferCount; i += 1) { - descriptorSetLayoutBindings[i].binding = i; - descriptorSetLayoutBindings[i].descriptorCount = 1; - descriptorSetLayoutBindings[i].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC; - descriptorSetLayoutBindings[i].stageFlags = shaderStage; - descriptorSetLayoutBindings[i].pImmutableSamplers = NULL; - } - - descriptorSetLayoutCreateInfo.pBindings = descriptorSetLayoutBindings; - descriptorSetLayoutCreateInfo.bindingCount = - samplerCount + - storageTextureCount + - storageBufferCount + - writeStorageTextureCount + - writeStorageBufferCount + - uniformBufferCount; - - VkResult vulkanResult = renderer->vkCreateDescriptorSetLayout( - renderer->logicalDevice, - &descriptorSetLayoutCreateInfo, - NULL, - &descriptorSetLayout); - - CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkCreateDescriptorSetLayout, NULL); - - layout = SDL_malloc(sizeof(DescriptorSetLayout)); - layout->descriptorSetLayout = descriptorSetLayout; - - layout->samplerCount = samplerCount; - layout->storageBufferCount = storageBufferCount; - layout->storageTextureCount = storageTextureCount; - layout->writeStorageBufferCount = writeStorageBufferCount; - layout->writeStorageTextureCount = writeStorageTextureCount; - layout->uniformBufferCount = uniformBufferCount; - - layout->ID = SDL_AtomicIncRef(&renderer->layoutResourceID); - - DescriptorSetLayoutHashTableKey *allocedKey = SDL_malloc(sizeof(DescriptorSetLayoutHashTableKey)); - SDL_memcpy(allocedKey, &key, sizeof(DescriptorSetLayoutHashTableKey)); - - SDL_InsertIntoHashTable( - renderer->descriptorSetLayoutHashTable, - (const void *)allocedKey, - (const void *)layout, true); - - return layout; -} - -static VulkanGraphicsPipelineResourceLayout *VULKAN_INTERNAL_FetchGraphicsPipelineResourceLayout( - VulkanRenderer *renderer, - VulkanShader *vertexShader, - VulkanShader *fragmentShader) -{ - GraphicsPipelineResourceLayoutHashTableKey key; - SDL_zero(key); - VulkanGraphicsPipelineResourceLayout *pipelineResourceLayout = NULL; - - key.vertexSamplerCount = vertexShader->numSamplers; - key.vertexStorageTextureCount = vertexShader->numStorageTextures; - key.vertexStorageBufferCount = vertexShader->numStorageBuffers; - key.vertexUniformBufferCount = vertexShader->numUniformBuffers; - key.fragmentSamplerCount = fragmentShader->numSamplers; - key.fragmentStorageTextureCount = fragmentShader->numStorageTextures; - key.fragmentStorageBufferCount = fragmentShader->numStorageBuffers; - key.fragmentUniformBufferCount = fragmentShader->numUniformBuffers; - if (SDL_FindInHashTable( - renderer->graphicsPipelineResourceLayoutHashTable, - (const void *)&key, - (const void **)&pipelineResourceLayout)) { - return pipelineResourceLayout; - } - - VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo; - VkDescriptorSetLayout descriptorSetLayouts[4]; - VkResult vulkanResult; - - pipelineResourceLayout = SDL_calloc(1, sizeof(VulkanGraphicsPipelineResourceLayout)); - - pipelineResourceLayout->descriptorSetLayouts[0] = VULKAN_INTERNAL_FetchDescriptorSetLayout( - renderer, - VK_SHADER_STAGE_VERTEX_BIT, - vertexShader->numSamplers, - vertexShader->numStorageTextures, - vertexShader->numStorageBuffers, - 0, - 0, - 0); - - pipelineResourceLayout->descriptorSetLayouts[1] = VULKAN_INTERNAL_FetchDescriptorSetLayout( - renderer, - VK_SHADER_STAGE_VERTEX_BIT, - 0, - 0, - 0, - 0, - 0, - vertexShader->numUniformBuffers); - - pipelineResourceLayout->descriptorSetLayouts[2] = VULKAN_INTERNAL_FetchDescriptorSetLayout( - renderer, - VK_SHADER_STAGE_FRAGMENT_BIT, - fragmentShader->numSamplers, - fragmentShader->numStorageTextures, - fragmentShader->numStorageBuffers, - 0, - 0, - 0); - - pipelineResourceLayout->descriptorSetLayouts[3] = VULKAN_INTERNAL_FetchDescriptorSetLayout( - renderer, - VK_SHADER_STAGE_FRAGMENT_BIT, - 0, - 0, - 0, - 0, - 0, - fragmentShader->numUniformBuffers); - - descriptorSetLayouts[0] = pipelineResourceLayout->descriptorSetLayouts[0]->descriptorSetLayout; - descriptorSetLayouts[1] = pipelineResourceLayout->descriptorSetLayouts[1]->descriptorSetLayout; - descriptorSetLayouts[2] = pipelineResourceLayout->descriptorSetLayouts[2]->descriptorSetLayout; - descriptorSetLayouts[3] = pipelineResourceLayout->descriptorSetLayouts[3]->descriptorSetLayout; - - pipelineResourceLayout->vertexSamplerCount = vertexShader->numSamplers; - pipelineResourceLayout->vertexStorageTextureCount = vertexShader->numStorageTextures; - pipelineResourceLayout->vertexStorageBufferCount = vertexShader->numStorageBuffers; - pipelineResourceLayout->vertexUniformBufferCount = vertexShader->numUniformBuffers; - - pipelineResourceLayout->fragmentSamplerCount = fragmentShader->numSamplers; - pipelineResourceLayout->fragmentStorageTextureCount = fragmentShader->numStorageTextures; - pipelineResourceLayout->fragmentStorageBufferCount = fragmentShader->numStorageBuffers; - pipelineResourceLayout->fragmentUniformBufferCount = fragmentShader->numUniformBuffers; - - // Create the pipeline layout - - pipelineLayoutCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; - pipelineLayoutCreateInfo.pNext = NULL; - pipelineLayoutCreateInfo.flags = 0; - pipelineLayoutCreateInfo.setLayoutCount = 4; - pipelineLayoutCreateInfo.pSetLayouts = descriptorSetLayouts; - pipelineLayoutCreateInfo.pushConstantRangeCount = 0; - pipelineLayoutCreateInfo.pPushConstantRanges = NULL; - - vulkanResult = renderer->vkCreatePipelineLayout( - renderer->logicalDevice, - &pipelineLayoutCreateInfo, - NULL, - &pipelineResourceLayout->pipelineLayout); - - if (vulkanResult != VK_SUCCESS) { - VULKAN_INTERNAL_DestroyGraphicsPipelineResourceLayout(renderer, pipelineResourceLayout); - CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkCreatePipelineLayout, NULL); - } - - GraphicsPipelineResourceLayoutHashTableKey *allocedKey = SDL_malloc(sizeof(GraphicsPipelineResourceLayoutHashTableKey)); - SDL_memcpy(allocedKey, &key, sizeof(GraphicsPipelineResourceLayoutHashTableKey)); - - SDL_InsertIntoHashTable( - renderer->graphicsPipelineResourceLayoutHashTable, - (const void *)allocedKey, - (const void *)pipelineResourceLayout, true); - - return pipelineResourceLayout; -} - -static VulkanComputePipelineResourceLayout *VULKAN_INTERNAL_FetchComputePipelineResourceLayout( - VulkanRenderer *renderer, - const SDL_GPUComputePipelineCreateInfo *createinfo) -{ - ComputePipelineResourceLayoutHashTableKey key; - SDL_zero(key); - VulkanComputePipelineResourceLayout *pipelineResourceLayout = NULL; - - key.samplerCount = createinfo->num_samplers; - key.readonlyStorageTextureCount = createinfo->num_readonly_storage_textures; - key.readonlyStorageBufferCount = createinfo->num_readonly_storage_buffers; - key.readWriteStorageTextureCount = createinfo->num_readwrite_storage_textures; - key.readWriteStorageBufferCount = createinfo->num_readwrite_storage_buffers; - key.uniformBufferCount = createinfo->num_uniform_buffers; - - if (SDL_FindInHashTable( - renderer->computePipelineResourceLayoutHashTable, - (const void *)&key, - (const void **)&pipelineResourceLayout)) { - return pipelineResourceLayout; - } - - VkDescriptorSetLayout descriptorSetLayouts[3]; - VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo; - VkResult vulkanResult; - - pipelineResourceLayout = SDL_calloc(1, sizeof(VulkanComputePipelineResourceLayout)); - - pipelineResourceLayout->descriptorSetLayouts[0] = VULKAN_INTERNAL_FetchDescriptorSetLayout( - renderer, - VK_SHADER_STAGE_COMPUTE_BIT, - createinfo->num_samplers, - createinfo->num_readonly_storage_textures, - createinfo->num_readonly_storage_buffers, - 0, - 0, - 0); - - pipelineResourceLayout->descriptorSetLayouts[1] = VULKAN_INTERNAL_FetchDescriptorSetLayout( - renderer, - VK_SHADER_STAGE_COMPUTE_BIT, - 0, - 0, - 0, - createinfo->num_readwrite_storage_textures, - createinfo->num_readwrite_storage_buffers, - 0); - - pipelineResourceLayout->descriptorSetLayouts[2] = VULKAN_INTERNAL_FetchDescriptorSetLayout( - renderer, - VK_SHADER_STAGE_COMPUTE_BIT, - 0, - 0, - 0, - 0, - 0, - createinfo->num_uniform_buffers); - - descriptorSetLayouts[0] = pipelineResourceLayout->descriptorSetLayouts[0]->descriptorSetLayout; - descriptorSetLayouts[1] = pipelineResourceLayout->descriptorSetLayouts[1]->descriptorSetLayout; - descriptorSetLayouts[2] = pipelineResourceLayout->descriptorSetLayouts[2]->descriptorSetLayout; - - pipelineResourceLayout->numSamplers = createinfo->num_samplers; - pipelineResourceLayout->numReadonlyStorageTextures = createinfo->num_readonly_storage_textures; - pipelineResourceLayout->numReadonlyStorageBuffers = createinfo->num_readonly_storage_buffers; - pipelineResourceLayout->numReadWriteStorageTextures = createinfo->num_readwrite_storage_textures; - pipelineResourceLayout->numReadWriteStorageBuffers = createinfo->num_readwrite_storage_buffers; - pipelineResourceLayout->numUniformBuffers = createinfo->num_uniform_buffers; - - // Create the pipeline layout - - pipelineLayoutCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; - pipelineLayoutCreateInfo.pNext = NULL; - pipelineLayoutCreateInfo.flags = 0; - pipelineLayoutCreateInfo.setLayoutCount = 3; - pipelineLayoutCreateInfo.pSetLayouts = descriptorSetLayouts; - pipelineLayoutCreateInfo.pushConstantRangeCount = 0; - pipelineLayoutCreateInfo.pPushConstantRanges = NULL; - - vulkanResult = renderer->vkCreatePipelineLayout( - renderer->logicalDevice, - &pipelineLayoutCreateInfo, - NULL, - &pipelineResourceLayout->pipelineLayout); - - if (vulkanResult != VK_SUCCESS) { - VULKAN_INTERNAL_DestroyComputePipelineResourceLayout(renderer, pipelineResourceLayout); - CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkCreatePipelineLayout, NULL); - } - - ComputePipelineResourceLayoutHashTableKey *allocedKey = SDL_malloc(sizeof(ComputePipelineResourceLayoutHashTableKey)); - SDL_memcpy(allocedKey, &key, sizeof(ComputePipelineResourceLayoutHashTableKey)); - - SDL_InsertIntoHashTable( - renderer->computePipelineResourceLayoutHashTable, - (const void *)allocedKey, - (const void *)pipelineResourceLayout, true); - - return pipelineResourceLayout; -} - -// Data Buffer - -static VulkanBuffer *VULKAN_INTERNAL_CreateBuffer( - VulkanRenderer *renderer, - VkDeviceSize size, - SDL_GPUBufferUsageFlags usageFlags, - VulkanBufferType type, - bool dedicated, - const char *debugName) -{ - VulkanBuffer *buffer; - VkResult vulkanResult; - VkBufferCreateInfo createinfo; - VkBufferUsageFlags vulkanUsageFlags = 0; - Uint8 bindResult; - - if (usageFlags & SDL_GPU_BUFFERUSAGE_VERTEX) { - vulkanUsageFlags |= VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; - } - - if (usageFlags & SDL_GPU_BUFFERUSAGE_INDEX) { - vulkanUsageFlags |= VK_BUFFER_USAGE_INDEX_BUFFER_BIT; - } - - if (usageFlags & (SDL_GPU_BUFFERUSAGE_GRAPHICS_STORAGE_READ | - SDL_GPU_BUFFERUSAGE_COMPUTE_STORAGE_READ | - SDL_GPU_BUFFERUSAGE_COMPUTE_STORAGE_WRITE)) { - vulkanUsageFlags |= VK_BUFFER_USAGE_STORAGE_BUFFER_BIT; - } - - if (usageFlags & SDL_GPU_BUFFERUSAGE_INDIRECT) { - vulkanUsageFlags |= VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT; - } - - if (type == VULKAN_BUFFER_TYPE_UNIFORM) { - vulkanUsageFlags |= VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT; - } else { - // GPU buffers need transfer bits for defrag, transfer buffers need them for transfers - vulkanUsageFlags |= VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT; - } - - buffer = SDL_calloc(1, sizeof(VulkanBuffer)); - - buffer->size = size; - buffer->usage = usageFlags; - buffer->type = type; - buffer->markedForDestroy = false; - buffer->transitioned = false; - - createinfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; - createinfo.pNext = NULL; - createinfo.flags = 0; - createinfo.size = size; - createinfo.usage = vulkanUsageFlags; - createinfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - createinfo.queueFamilyIndexCount = 1; - createinfo.pQueueFamilyIndices = &renderer->queueFamilyIndex; - - // Set transfer bits so we can defrag - createinfo.usage |= VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT; - - vulkanResult = renderer->vkCreateBuffer( - renderer->logicalDevice, - &createinfo, - NULL, - &buffer->buffer); - - if (vulkanResult != VK_SUCCESS) { - SDL_free(buffer); - CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkCreateBuffer, NULL); - } - - bindResult = VULKAN_INTERNAL_BindMemoryForBuffer( - renderer, - buffer->buffer, - buffer->size, - buffer->type, - dedicated, - &buffer->usedRegion); - - if (bindResult != 1) { - renderer->vkDestroyBuffer( - renderer->logicalDevice, - buffer->buffer, - NULL); - - SDL_free(buffer); - return NULL; - } - - buffer->usedRegion->vulkanBuffer = buffer; // lol - - SDL_SetAtomicInt(&buffer->referenceCount, 0); - - if (renderer->debugMode && renderer->supportsDebugUtils && debugName != NULL) { - VkDebugUtilsObjectNameInfoEXT nameInfo; - nameInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT; - nameInfo.pNext = NULL; - nameInfo.pObjectName = debugName; - nameInfo.objectType = VK_OBJECT_TYPE_BUFFER; - nameInfo.objectHandle = (uint64_t)buffer->buffer; - - renderer->vkSetDebugUtilsObjectNameEXT( - renderer->logicalDevice, - &nameInfo); - } - - return buffer; -} - -static VulkanBufferContainer *VULKAN_INTERNAL_CreateBufferContainer( - VulkanRenderer *renderer, - VkDeviceSize size, - SDL_GPUBufferUsageFlags usageFlags, - VulkanBufferType type, - bool dedicated, - const char *debugName) -{ - VulkanBufferContainer *bufferContainer; - VulkanBuffer *buffer; - - buffer = VULKAN_INTERNAL_CreateBuffer( - renderer, - size, - usageFlags, - type, - dedicated, - debugName); - - if (buffer == NULL) { - return NULL; - } - - bufferContainer = SDL_calloc(1, sizeof(VulkanBufferContainer)); - - bufferContainer->activeBuffer = buffer; - buffer->container = bufferContainer; - buffer->containerIndex = 0; - - bufferContainer->bufferCapacity = 1; - bufferContainer->bufferCount = 1; - bufferContainer->buffers = SDL_calloc(bufferContainer->bufferCapacity, sizeof(VulkanBuffer *)); - bufferContainer->buffers[0] = bufferContainer->activeBuffer; - bufferContainer->dedicated = dedicated; - bufferContainer->debugName = NULL; - - if (debugName != NULL) { - bufferContainer->debugName = SDL_strdup(debugName); - } - - return bufferContainer; -} - -// Texture Subresource Utilities - -static Uint32 VULKAN_INTERNAL_GetTextureSubresourceIndex( - Uint32 mipLevel, - Uint32 layer, - Uint32 numLevels) -{ - return mipLevel + (layer * numLevels); -} - -static VulkanTextureSubresource *VULKAN_INTERNAL_FetchTextureSubresource( - VulkanTextureContainer *textureContainer, - Uint32 layer, - Uint32 level) -{ - Uint32 index = VULKAN_INTERNAL_GetTextureSubresourceIndex( - level, - layer, - textureContainer->header.info.num_levels); - - return &textureContainer->activeTexture->subresources[index]; -} - -static bool VULKAN_INTERNAL_CreateRenderTargetView( - VulkanRenderer *renderer, - VulkanTexture *texture, - Uint32 layerOrDepth, - Uint32 level, - VkFormat format, - VkComponentMapping swizzle, - VkImageView *pView) -{ - VkResult vulkanResult; - VkImageViewCreateInfo imageViewCreateInfo; - - // create framebuffer compatible views for RenderTarget - 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 = texture->aspectFlags; - imageViewCreateInfo.subresourceRange.baseMipLevel = level; - imageViewCreateInfo.subresourceRange.levelCount = 1; - imageViewCreateInfo.subresourceRange.baseArrayLayer = layerOrDepth; - imageViewCreateInfo.subresourceRange.layerCount = 1; - imageViewCreateInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; - - vulkanResult = renderer->vkCreateImageView( - renderer->logicalDevice, - &imageViewCreateInfo, - NULL, - pView); - - if (vulkanResult != VK_SUCCESS) { - *pView = (VkImageView)VK_NULL_HANDLE; - CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkCreateImageView, false); - } - - return true; -} - -static bool VULKAN_INTERNAL_CreateSubresourceView( - VulkanRenderer *renderer, - const SDL_GPUTextureCreateInfo *createinfo, - VulkanTexture *texture, - Uint32 layer, - Uint32 level, - VkComponentMapping swizzle, - VkImageView *pView) -{ - VkResult vulkanResult; - VkImageViewCreateInfo imageViewCreateInfo; - - // create framebuffer compatible views for RenderTarget - imageViewCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; - imageViewCreateInfo.pNext = NULL; - imageViewCreateInfo.flags = 0; - imageViewCreateInfo.image = texture->image; - imageViewCreateInfo.format = SDLToVK_TextureFormat[createinfo->format]; - imageViewCreateInfo.components = swizzle; - imageViewCreateInfo.subresourceRange.aspectMask = texture->aspectFlags; - imageViewCreateInfo.subresourceRange.baseMipLevel = level; - imageViewCreateInfo.subresourceRange.levelCount = 1; - imageViewCreateInfo.subresourceRange.baseArrayLayer = layer; - imageViewCreateInfo.subresourceRange.layerCount = 1; - imageViewCreateInfo.viewType = (createinfo->type == SDL_GPU_TEXTURETYPE_3D) ? VK_IMAGE_VIEW_TYPE_3D : VK_IMAGE_VIEW_TYPE_2D; - - vulkanResult = renderer->vkCreateImageView( - renderer->logicalDevice, - &imageViewCreateInfo, - NULL, - pView); - - if (vulkanResult != VK_SUCCESS) { - *pView = (VkImageView)VK_NULL_HANDLE; - CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkCreateImageView, false); - } - - return true; -} - -// Swapchain - -static bool VULKAN_INTERNAL_QuerySwapchainSupport( - VulkanRenderer *renderer, - VkPhysicalDevice physicalDevice, - VkSurfaceKHR surface, - SwapchainSupportDetails *outputDetails) -{ - VkResult result; - VkBool32 supportsPresent; - - renderer->vkGetPhysicalDeviceSurfaceSupportKHR( - physicalDevice, - renderer->queueFamilyIndex, - surface, - &supportsPresent); - - // Initialize these in case anything fails - outputDetails->formatsLength = 0; - outputDetails->presentModesLength = 0; - - if (!supportsPresent) { - SET_STRING_ERROR_AND_RETURN("This surface does not support presenting!", false); - } - - // Run the device surface queries - result = renderer->vkGetPhysicalDeviceSurfaceCapabilitiesKHR( - physicalDevice, - surface, - &outputDetails->capabilities); - CHECK_VULKAN_ERROR_AND_RETURN(result, vkGetPhysicalDeviceSurfaceCapabilitiesKHR, false); - - if (!(outputDetails->capabilities.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR)) { - SDL_LogWarn(SDL_LOG_CATEGORY_GPU, "Opaque presentation unsupported! Expect weird transparency bugs!"); - } - - result = renderer->vkGetPhysicalDeviceSurfaceFormatsKHR( - physicalDevice, - surface, - &outputDetails->formatsLength, - NULL); - CHECK_VULKAN_ERROR_AND_RETURN(result, vkGetPhysicalDeviceSurfaceFormatsKHR, false); - result = renderer->vkGetPhysicalDeviceSurfacePresentModesKHR( - physicalDevice, - surface, - &outputDetails->presentModesLength, - NULL); - CHECK_VULKAN_ERROR_AND_RETURN(result, vkGetPhysicalDeviceSurfacePresentModesKHR, false); - - // Generate the arrays, if applicable - - outputDetails->formats = NULL; - if (outputDetails->formatsLength != 0) { - outputDetails->formats = (VkSurfaceFormatKHR *)SDL_malloc( - sizeof(VkSurfaceFormatKHR) * outputDetails->formatsLength); - - if (!outputDetails->formats) { // OOM - return false; - } - - result = renderer->vkGetPhysicalDeviceSurfaceFormatsKHR( - physicalDevice, - surface, - &outputDetails->formatsLength, - outputDetails->formats); - if (result != VK_SUCCESS) { - SDL_free(outputDetails->formats); - CHECK_VULKAN_ERROR_AND_RETURN(result, vkGetPhysicalDeviceSurfaceFormatsKHR, false); - } - } - - outputDetails->presentModes = NULL; - if (outputDetails->presentModesLength != 0) { - outputDetails->presentModes = (VkPresentModeKHR *)SDL_malloc( - sizeof(VkPresentModeKHR) * outputDetails->presentModesLength); - - if (!outputDetails->presentModes) { // OOM - SDL_free(outputDetails->formats); - return false; - } - - result = renderer->vkGetPhysicalDeviceSurfacePresentModesKHR( - physicalDevice, - surface, - &outputDetails->presentModesLength, - outputDetails->presentModes); - if (result != VK_SUCCESS) { - SDL_free(outputDetails->formats); - SDL_free(outputDetails->presentModes); - CHECK_VULKAN_ERROR_AND_RETURN(result, vkGetPhysicalDeviceSurfacePresentModesKHR, false); - } - } - - /* If we made it here, all the queries were successful. This does NOT - * necessarily mean there are any supported formats or present modes! - */ - return true; -} - -static bool VULKAN_INTERNAL_VerifySwapSurfaceFormat( - VkFormat desiredFormat, - VkColorSpaceKHR desiredColorSpace, - VkSurfaceFormatKHR *availableFormats, - Uint32 availableFormatsLength) -{ - Uint32 i; - for (i = 0; i < availableFormatsLength; i += 1) { - if (availableFormats[i].format == desiredFormat && - availableFormats[i].colorSpace == desiredColorSpace) { - return true; - } - } - return false; -} - -static bool VULKAN_INTERNAL_VerifySwapPresentMode( - VkPresentModeKHR presentMode, - const VkPresentModeKHR *availablePresentModes, - Uint32 availablePresentModesLength) -{ - Uint32 i; - for (i = 0; i < availablePresentModesLength; i += 1) { - if (availablePresentModes[i] == presentMode) { - return true; - } - } - return false; -} - -/* It would be nice if VULKAN_INTERNAL_CreateSwapchain could return a bool. - * Unfortunately, some Win32 NVIDIA drivers are stupid - * and will return surface extents of (0, 0) - * in certain edge cases, and the swapchain extents are not allowed to be 0. - * In this case, the client probably still wants to claim the window - * or recreate the swapchain, so we should return 2 to indicate retry. - * -cosmonaut - */ -#define VULKAN_INTERNAL_TRY_AGAIN 2 - -static Uint32 VULKAN_INTERNAL_CreateSwapchain( - VulkanRenderer *renderer, - WindowData *windowData) -{ - VkResult vulkanResult; - VkSwapchainCreateInfoKHR swapchainCreateInfo; - VkImage *swapchainImages; - VkSemaphoreCreateInfo semaphoreCreateInfo; - SwapchainSupportDetails swapchainSupportDetails; - bool hasValidSwapchainComposition, hasValidPresentMode; - Uint32 i; - - windowData->frameCounter = 0; - - SDL_VideoDevice *_this = SDL_GetVideoDevice(); - SDL_assert(_this && _this->Vulkan_CreateSurface); - - // Each swapchain must have its own surface. - if (!_this->Vulkan_CreateSurface( - _this, - windowData->window, - renderer->instance, - NULL, // FIXME: VAllocationCallbacks - &windowData->surface)) { - return false; - } - SDL_assert(windowData->surface); - - if (!VULKAN_INTERNAL_QuerySwapchainSupport( - renderer, - renderer->physicalDevice, - windowData->surface, - &swapchainSupportDetails)) { - renderer->vkDestroySurfaceKHR( - renderer->instance, - windowData->surface, - NULL); - windowData->surface = VK_NULL_HANDLE; - if (swapchainSupportDetails.formatsLength > 0) { - SDL_free(swapchainSupportDetails.formats); - } - if (swapchainSupportDetails.presentModesLength > 0) { - SDL_free(swapchainSupportDetails.presentModes); - } - return false; - } - - // Verify that we can use the requested composition and present mode - windowData->format = SwapchainCompositionToFormat[windowData->swapchainComposition]; - windowData->colorSpace = SwapchainCompositionToColorSpace[windowData->swapchainComposition]; - windowData->swapchainSwizzle = SwapchainCompositionSwizzle[windowData->swapchainComposition]; - windowData->usingFallbackFormat = false; - - hasValidSwapchainComposition = VULKAN_INTERNAL_VerifySwapSurfaceFormat( - windowData->format, - windowData->colorSpace, - swapchainSupportDetails.formats, - swapchainSupportDetails.formatsLength); - - if (!hasValidSwapchainComposition) { - // Let's try again with the fallback format... - windowData->format = SwapchainCompositionToFallbackFormat[windowData->swapchainComposition]; - windowData->usingFallbackFormat = true; - hasValidSwapchainComposition = VULKAN_INTERNAL_VerifySwapSurfaceFormat( - windowData->format, - windowData->colorSpace, - swapchainSupportDetails.formats, - swapchainSupportDetails.formatsLength); - } - - hasValidPresentMode = VULKAN_INTERNAL_VerifySwapPresentMode( - SDLToVK_PresentMode[windowData->presentMode], - swapchainSupportDetails.presentModes, - swapchainSupportDetails.presentModesLength); - - if (!hasValidSwapchainComposition || !hasValidPresentMode) { - renderer->vkDestroySurfaceKHR( - renderer->instance, - windowData->surface, - NULL); - windowData->surface = VK_NULL_HANDLE; - - if (swapchainSupportDetails.formatsLength > 0) { - SDL_free(swapchainSupportDetails.formats); - } - - if (swapchainSupportDetails.presentModesLength > 0) { - SDL_free(swapchainSupportDetails.presentModes); - } - - if (!hasValidSwapchainComposition) { - SET_STRING_ERROR_AND_RETURN("Device does not support requested swapchain composition!", false); - } - if (!hasValidPresentMode) { - SET_STRING_ERROR_AND_RETURN("Device does not support requested present_mode!", false); - } - return false; - } - - // NVIDIA + Win32 can return 0 extent when the window is minimized. Try again! - if (swapchainSupportDetails.capabilities.currentExtent.width == 0 || - swapchainSupportDetails.capabilities.currentExtent.height == 0) { - renderer->vkDestroySurfaceKHR( - renderer->instance, - windowData->surface, - NULL); - windowData->surface = VK_NULL_HANDLE; - if (swapchainSupportDetails.formatsLength > 0) { - SDL_free(swapchainSupportDetails.formats); - } - if (swapchainSupportDetails.presentModesLength > 0) { - SDL_free(swapchainSupportDetails.presentModes); - } - return VULKAN_INTERNAL_TRY_AGAIN; - } - - Uint32 requestedImageCount = renderer->allowedFramesInFlight; - -#ifdef SDL_PLATFORM_APPLE - windowData->width = swapchainSupportDetails.capabilities.currentExtent.width; - windowData->height = swapchainSupportDetails.capabilities.currentExtent.height; -#else - windowData->width = SDL_clamp( - windowData->swapchainCreateWidth, - swapchainSupportDetails.capabilities.minImageExtent.width, - swapchainSupportDetails.capabilities.maxImageExtent.width); - windowData->height = SDL_clamp(windowData->swapchainCreateHeight, - swapchainSupportDetails.capabilities.minImageExtent.height, - swapchainSupportDetails.capabilities.maxImageExtent.height); -#endif - - if (swapchainSupportDetails.capabilities.maxImageCount > 0 && - requestedImageCount > swapchainSupportDetails.capabilities.maxImageCount) { - requestedImageCount = swapchainSupportDetails.capabilities.maxImageCount; - } - - if (requestedImageCount < swapchainSupportDetails.capabilities.minImageCount) { - requestedImageCount = swapchainSupportDetails.capabilities.minImageCount; - } - - if (windowData->presentMode == SDL_GPU_PRESENTMODE_MAILBOX) { - /* Required for proper triple-buffering. - * Note that this is below the above maxImageCount check! - * If the driver advertises MAILBOX but does not support 3 swap - * images, it's not real mailbox support, so let it fail hard. - * -flibit - */ - requestedImageCount = SDL_max(requestedImageCount, 3); - } - - swapchainCreateInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; - swapchainCreateInfo.pNext = NULL; - swapchainCreateInfo.flags = 0; - swapchainCreateInfo.surface = windowData->surface; - swapchainCreateInfo.minImageCount = requestedImageCount; - swapchainCreateInfo.imageFormat = windowData->format; - swapchainCreateInfo.imageColorSpace = windowData->colorSpace; - swapchainCreateInfo.imageExtent.width = windowData->width; - swapchainCreateInfo.imageExtent.height = windowData->height; - swapchainCreateInfo.imageArrayLayers = 1; - swapchainCreateInfo.imageUsage = - VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | - VK_IMAGE_USAGE_TRANSFER_DST_BIT; - swapchainCreateInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; - swapchainCreateInfo.queueFamilyIndexCount = 0; - swapchainCreateInfo.pQueueFamilyIndices = NULL; -#ifdef SDL_PLATFORM_ANDROID - swapchainCreateInfo.preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; -#else - swapchainCreateInfo.preTransform = swapchainSupportDetails.capabilities.currentTransform; -#endif - swapchainCreateInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; - swapchainCreateInfo.presentMode = SDLToVK_PresentMode[windowData->presentMode]; - swapchainCreateInfo.clipped = VK_TRUE; - swapchainCreateInfo.oldSwapchain = VK_NULL_HANDLE; - - vulkanResult = renderer->vkCreateSwapchainKHR( - renderer->logicalDevice, - &swapchainCreateInfo, - NULL, - &windowData->swapchain); - - if (swapchainSupportDetails.formatsLength > 0) { - SDL_free(swapchainSupportDetails.formats); - } - if (swapchainSupportDetails.presentModesLength > 0) { - SDL_free(swapchainSupportDetails.presentModes); - } - - if (vulkanResult != VK_SUCCESS) { - renderer->vkDestroySurfaceKHR( - renderer->instance, - windowData->surface, - NULL); - windowData->surface = VK_NULL_HANDLE; - CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkCreateSwapchainKHR, false); - } - - vulkanResult = renderer->vkGetSwapchainImagesKHR( - renderer->logicalDevice, - windowData->swapchain, - &windowData->imageCount, - NULL); - CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkGetSwapchainImagesKHR, false); - - windowData->textureContainers = SDL_malloc( - sizeof(VulkanTextureContainer) * windowData->imageCount); - - if (!windowData->textureContainers) { // OOM - renderer->vkDestroySurfaceKHR( - renderer->instance, - windowData->surface, - NULL); - renderer->vkDestroySwapchainKHR( - renderer->logicalDevice, - windowData->swapchain, - NULL); - windowData->surface = VK_NULL_HANDLE; - windowData->swapchain = VK_NULL_HANDLE; - return false; - } - - swapchainImages = SDL_stack_alloc(VkImage, windowData->imageCount); - - vulkanResult = renderer->vkGetSwapchainImagesKHR( - renderer->logicalDevice, - windowData->swapchain, - &windowData->imageCount, - swapchainImages); - CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkGetSwapchainImagesKHR, false); - - for (i = 0; i < windowData->imageCount; i += 1) { - - // Initialize dummy container - SDL_zero(windowData->textureContainers[i]); - windowData->textureContainers[i].canBeCycled = false; - windowData->textureContainers[i].header.info.width = windowData->width; - windowData->textureContainers[i].header.info.height = windowData->height; - windowData->textureContainers[i].header.info.layer_count_or_depth = 1; - windowData->textureContainers[i].header.info.format = SwapchainCompositionToSDLFormat( - windowData->swapchainComposition, - windowData->usingFallbackFormat); - windowData->textureContainers[i].header.info.type = SDL_GPU_TEXTURETYPE_2D; - windowData->textureContainers[i].header.info.num_levels = 1; - windowData->textureContainers[i].header.info.sample_count = SDL_GPU_SAMPLECOUNT_1; - windowData->textureContainers[i].header.info.usage = SDL_GPU_TEXTUREUSAGE_COLOR_TARGET; - - windowData->textureContainers[i].activeTexture = SDL_malloc(sizeof(VulkanTexture)); - windowData->textureContainers[i].activeTexture->image = swapchainImages[i]; - - // Swapchain memory is managed by the driver - windowData->textureContainers[i].activeTexture->usedRegion = NULL; - - windowData->textureContainers[i].activeTexture->swizzle = windowData->swapchainSwizzle; - windowData->textureContainers[i].activeTexture->aspectFlags = VK_IMAGE_ASPECT_COLOR_BIT; - windowData->textureContainers[i].activeTexture->depth = 1; - windowData->textureContainers[i].activeTexture->usage = SDL_GPU_TEXTUREUSAGE_COLOR_TARGET; - windowData->textureContainers[i].activeTexture->container = &windowData->textureContainers[i]; - SDL_SetAtomicInt(&windowData->textureContainers[i].activeTexture->referenceCount, 0); - - // Create slice - windowData->textureContainers[i].activeTexture->subresourceCount = 1; - windowData->textureContainers[i].activeTexture->subresources = SDL_malloc(sizeof(VulkanTextureSubresource)); - windowData->textureContainers[i].activeTexture->subresources[0].parent = windowData->textureContainers[i].activeTexture; - windowData->textureContainers[i].activeTexture->subresources[0].layer = 0; - windowData->textureContainers[i].activeTexture->subresources[0].level = 0; - windowData->textureContainers[i].activeTexture->subresources[0].renderTargetViews = SDL_malloc(sizeof(VkImageView)); - if (!VULKAN_INTERNAL_CreateRenderTargetView( - renderer, - windowData->textureContainers[i].activeTexture, - 0, - 0, - windowData->format, - windowData->swapchainSwizzle, - &windowData->textureContainers[i].activeTexture->subresources[0].renderTargetViews[0])) { - renderer->vkDestroySurfaceKHR( - renderer->instance, - windowData->surface, - NULL); - renderer->vkDestroySwapchainKHR( - renderer->logicalDevice, - windowData->swapchain, - NULL); - windowData->surface = VK_NULL_HANDLE; - windowData->swapchain = VK_NULL_HANDLE; - return false; - } - } - - SDL_stack_free(swapchainImages); - - semaphoreCreateInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; - semaphoreCreateInfo.pNext = NULL; - semaphoreCreateInfo.flags = 0; - - for (i = 0; i < MAX_FRAMES_IN_FLIGHT; i += 1) { - vulkanResult = renderer->vkCreateSemaphore( - renderer->logicalDevice, - &semaphoreCreateInfo, - NULL, - &windowData->imageAvailableSemaphore[i]); - - if (vulkanResult != VK_SUCCESS) { - renderer->vkDestroySurfaceKHR( - renderer->instance, - windowData->surface, - NULL); - renderer->vkDestroySwapchainKHR( - renderer->logicalDevice, - windowData->swapchain, - NULL); - windowData->surface = VK_NULL_HANDLE; - windowData->swapchain = VK_NULL_HANDLE; - CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkCreateSemaphore, false); - } - - renderer->vkCreateSemaphore( - renderer->logicalDevice, - &semaphoreCreateInfo, - NULL, - &windowData->renderFinishedSemaphore[i]); - - if (vulkanResult != VK_SUCCESS) { - renderer->vkDestroySurfaceKHR( - renderer->instance, - windowData->surface, - NULL); - renderer->vkDestroySwapchainKHR( - renderer->logicalDevice, - windowData->swapchain, - NULL); - windowData->surface = VK_NULL_HANDLE; - windowData->swapchain = VK_NULL_HANDLE; - CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkCreateSemaphore, false); - } - - windowData->inFlightFences[i] = NULL; - } - - windowData->needsSwapchainRecreate = false; - return true; -} - -// Command Buffers - -static bool VULKAN_INTERNAL_BeginCommandBuffer( - VulkanRenderer *renderer, - VulkanCommandBuffer *commandBuffer) -{ - VkCommandBufferBeginInfo beginInfo; - VkResult result; - - beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; - beginInfo.pNext = NULL; - beginInfo.flags = 0; - beginInfo.pInheritanceInfo = NULL; - beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; - - result = renderer->vkBeginCommandBuffer( - commandBuffer->commandBuffer, - &beginInfo); - - CHECK_VULKAN_ERROR_AND_RETURN(result, vkBeginCommandBuffer, false); - - return true; -} - -static bool VULKAN_INTERNAL_EndCommandBuffer( - VulkanRenderer *renderer, - VulkanCommandBuffer *commandBuffer) -{ - VkResult result = renderer->vkEndCommandBuffer( - commandBuffer->commandBuffer); - - CHECK_VULKAN_ERROR_AND_RETURN(result, vkEndCommandBuffer, false); - - return true; -} - -static void VULKAN_DestroyDevice( - SDL_GPUDevice *device) -{ - VulkanRenderer *renderer = (VulkanRenderer *)device->driverData; - VulkanMemorySubAllocator *allocator; - - VULKAN_Wait(device->driverData); - - for (Sint32 i = renderer->claimedWindowCount - 1; i >= 0; i -= 1) { - VULKAN_ReleaseWindow(device->driverData, renderer->claimedWindows[i]->window); - } - - SDL_free(renderer->claimedWindows); - - VULKAN_Wait(device->driverData); - - SDL_free(renderer->submittedCommandBuffers); - - for (Uint32 i = 0; i < renderer->uniformBufferPoolCount; i += 1) { - VULKAN_INTERNAL_DestroyBuffer( - renderer, - renderer->uniformBufferPool[i]->buffer); - SDL_free(renderer->uniformBufferPool[i]); - } - SDL_free(renderer->uniformBufferPool); - - for (Uint32 i = 0; i < renderer->descriptorSetCachePoolCount; i += 1) { - VULKAN_INTERNAL_DestroyDescriptorSetCache( - renderer, - renderer->descriptorSetCachePool[i]); - } - SDL_free(renderer->descriptorSetCachePool); - - for (Uint32 i = 0; i < renderer->fencePool.availableFenceCount; i += 1) { - renderer->vkDestroyFence( - renderer->logicalDevice, - renderer->fencePool.availableFences[i]->fence, - NULL); - - SDL_free(renderer->fencePool.availableFences[i]); - } - - SDL_free(renderer->fencePool.availableFences); - SDL_DestroyMutex(renderer->fencePool.lock); - - SDL_DestroyHashTable(renderer->commandPoolHashTable); - SDL_DestroyHashTable(renderer->renderPassHashTable); - SDL_DestroyHashTable(renderer->framebufferHashTable); - SDL_DestroyHashTable(renderer->graphicsPipelineResourceLayoutHashTable); - SDL_DestroyHashTable(renderer->computePipelineResourceLayoutHashTable); - SDL_DestroyHashTable(renderer->descriptorSetLayoutHashTable); - - for (Uint32 i = 0; i < VK_MAX_MEMORY_TYPES; i += 1) { - allocator = &renderer->memoryAllocator->subAllocators[i]; - - for (Sint32 j = allocator->allocationCount - 1; j >= 0; j -= 1) { - for (Sint32 k = allocator->allocations[j]->usedRegionCount - 1; k >= 0; k -= 1) { - VULKAN_INTERNAL_RemoveMemoryUsedRegion( - renderer, - allocator->allocations[j]->usedRegions[k]); - } - - VULKAN_INTERNAL_DeallocateMemory( - renderer, - allocator, - j); - } - - if (renderer->memoryAllocator->subAllocators[i].allocations != NULL) { - SDL_free(renderer->memoryAllocator->subAllocators[i].allocations); - } - - SDL_free(renderer->memoryAllocator->subAllocators[i].sortedFreeRegions); - } - - SDL_free(renderer->memoryAllocator); - - SDL_free(renderer->texturesToDestroy); - SDL_free(renderer->buffersToDestroy); - SDL_free(renderer->graphicsPipelinesToDestroy); - SDL_free(renderer->computePipelinesToDestroy); - SDL_free(renderer->shadersToDestroy); - SDL_free(renderer->samplersToDestroy); - SDL_free(renderer->framebuffersToDestroy); - SDL_free(renderer->allocationsToDefrag); - - SDL_DestroyMutex(renderer->allocatorLock); - SDL_DestroyMutex(renderer->disposeLock); - SDL_DestroyMutex(renderer->submitLock); - SDL_DestroyMutex(renderer->acquireCommandBufferLock); - SDL_DestroyMutex(renderer->acquireUniformBufferLock); - SDL_DestroyMutex(renderer->framebufferFetchLock); - SDL_DestroyMutex(renderer->windowLock); - - renderer->vkDestroyDevice(renderer->logicalDevice, NULL); - renderer->vkDestroyInstance(renderer->instance, NULL); - - SDL_free(renderer); - SDL_free(device); - SDL_Vulkan_UnloadLibrary(); -} - -static DescriptorSetCache *VULKAN_INTERNAL_AcquireDescriptorSetCache( - VulkanRenderer *renderer) -{ - DescriptorSetCache *cache; - - if (renderer->descriptorSetCachePoolCount == 0) { - cache = SDL_malloc(sizeof(DescriptorSetCache)); - cache->poolCount = 0; - cache->pools = NULL; - } else { - cache = renderer->descriptorSetCachePool[renderer->descriptorSetCachePoolCount - 1]; - renderer->descriptorSetCachePoolCount -= 1; - } - - return cache; -} - -static void VULKAN_INTERNAL_ReturnDescriptorSetCacheToPool( - VulkanRenderer *renderer, - DescriptorSetCache *descriptorSetCache) -{ - EXPAND_ARRAY_IF_NEEDED( - renderer->descriptorSetCachePool, - DescriptorSetCache *, - renderer->descriptorSetCachePoolCount + 1, - renderer->descriptorSetCachePoolCapacity, - renderer->descriptorSetCachePoolCapacity * 2); - - renderer->descriptorSetCachePool[renderer->descriptorSetCachePoolCount] = descriptorSetCache; - renderer->descriptorSetCachePoolCount += 1; - - for (Uint32 i = 0; i < descriptorSetCache->poolCount; i += 1) { - descriptorSetCache->pools[i].descriptorSetIndex = 0; - } -} - -static VkDescriptorSet VULKAN_INTERNAL_FetchDescriptorSet( - VulkanRenderer *renderer, - VulkanCommandBuffer *vulkanCommandBuffer, - DescriptorSetLayout *descriptorSetLayout) -{ - // Grow the pool to meet the descriptor set layout ID - if (descriptorSetLayout->ID >= vulkanCommandBuffer->descriptorSetCache->poolCount) { - vulkanCommandBuffer->descriptorSetCache->pools = SDL_realloc( - vulkanCommandBuffer->descriptorSetCache->pools, - sizeof(DescriptorSetPool) * (descriptorSetLayout->ID + 1)); - - for (Uint32 i = vulkanCommandBuffer->descriptorSetCache->poolCount; i < descriptorSetLayout->ID + 1; i += 1) { - SDL_zero(vulkanCommandBuffer->descriptorSetCache->pools[i]); - } - - vulkanCommandBuffer->descriptorSetCache->poolCount = descriptorSetLayout->ID + 1; - } - - DescriptorSetPool *pool = - &vulkanCommandBuffer->descriptorSetCache->pools[descriptorSetLayout->ID]; - - if (pool->descriptorSetIndex == pool->descriptorSetCount) { - if (!VULKAN_INTERNAL_AllocateDescriptorsFromPool( - renderer, - descriptorSetLayout, - pool)) { - return VK_NULL_HANDLE; - } - } - - VkDescriptorSet descriptorSet = pool->descriptorSets[pool->descriptorSetIndex]; - pool->descriptorSetIndex += 1; - - return descriptorSet; -} - -static void VULKAN_INTERNAL_BindGraphicsDescriptorSets( - VulkanRenderer *renderer, - VulkanCommandBuffer *commandBuffer) -{ - VulkanGraphicsPipelineResourceLayout *resourceLayout; - DescriptorSetLayout *descriptorSetLayout; - VkWriteDescriptorSet writeDescriptorSets[ - (MAX_TEXTURE_SAMPLERS_PER_STAGE + - MAX_STORAGE_TEXTURES_PER_STAGE + - MAX_STORAGE_BUFFERS_PER_STAGE + - MAX_UNIFORM_BUFFERS_PER_STAGE) * 2]; - VkDescriptorBufferInfo bufferInfos[MAX_STORAGE_BUFFERS_PER_STAGE * 2]; - VkDescriptorImageInfo imageInfos[(MAX_TEXTURE_SAMPLERS_PER_STAGE + MAX_STORAGE_TEXTURES_PER_STAGE) * 2]; - Uint32 dynamicOffsets[MAX_UNIFORM_BUFFERS_PER_STAGE * 2]; - Uint32 writeCount = 0; - Uint32 bufferInfoCount = 0; - Uint32 imageInfoCount = 0; - Uint32 dynamicOffsetCount = 0; - - if ( - !commandBuffer->needVertexBufferBind && - !commandBuffer->needNewVertexResourceDescriptorSet && - !commandBuffer->needNewVertexUniformDescriptorSet && - !commandBuffer->needNewVertexUniformOffsets && - !commandBuffer->needNewFragmentResourceDescriptorSet && - !commandBuffer->needNewFragmentUniformDescriptorSet && - !commandBuffer->needNewFragmentUniformOffsets - ) { - return; - } - - if (commandBuffer->needVertexBufferBind && commandBuffer->vertexBufferCount > 0) { - renderer->vkCmdBindVertexBuffers( - commandBuffer->commandBuffer, - 0, - commandBuffer->vertexBufferCount, - commandBuffer->vertexBuffers, - commandBuffer->vertexBufferOffsets); - - commandBuffer->needVertexBufferBind = false; - } - - resourceLayout = commandBuffer->currentGraphicsPipeline->resourceLayout; - - if (commandBuffer->needNewVertexResourceDescriptorSet) { - descriptorSetLayout = resourceLayout->descriptorSetLayouts[0]; - - commandBuffer->vertexResourceDescriptorSet = VULKAN_INTERNAL_FetchDescriptorSet( - renderer, - commandBuffer, - descriptorSetLayout); - - for (Uint32 i = 0; i < resourceLayout->vertexSamplerCount; i += 1) { - VkWriteDescriptorSet *currentWriteDescriptorSet = &writeDescriptorSets[writeCount]; - - currentWriteDescriptorSet->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - currentWriteDescriptorSet->pNext = NULL; - currentWriteDescriptorSet->descriptorCount = 1; - currentWriteDescriptorSet->descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - currentWriteDescriptorSet->dstArrayElement = 0; - currentWriteDescriptorSet->dstBinding = i; - currentWriteDescriptorSet->dstSet = commandBuffer->vertexResourceDescriptorSet; - currentWriteDescriptorSet->pTexelBufferView = NULL; - currentWriteDescriptorSet->pBufferInfo = NULL; - - imageInfos[imageInfoCount].sampler = commandBuffer->vertexSamplers[i]->sampler; - imageInfos[imageInfoCount].imageView = commandBuffer->vertexSamplerTextures[i]->fullView; - imageInfos[imageInfoCount].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - - currentWriteDescriptorSet->pImageInfo = &imageInfos[imageInfoCount]; - - writeCount += 1; - imageInfoCount += 1; - } - - for (Uint32 i = 0; i < resourceLayout->vertexStorageTextureCount; i += 1) { - VkWriteDescriptorSet *currentWriteDescriptorSet = &writeDescriptorSets[writeCount]; - - currentWriteDescriptorSet->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - currentWriteDescriptorSet->pNext = NULL; - currentWriteDescriptorSet->descriptorCount = 1; - currentWriteDescriptorSet->descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE; // Yes, we are declaring a storage image as a sampled image, because shaders are stupid. - currentWriteDescriptorSet->dstArrayElement = 0; - currentWriteDescriptorSet->dstBinding = resourceLayout->vertexSamplerCount + i; - currentWriteDescriptorSet->dstSet = commandBuffer->vertexResourceDescriptorSet; - currentWriteDescriptorSet->pTexelBufferView = NULL; - currentWriteDescriptorSet->pBufferInfo = NULL; - - imageInfos[imageInfoCount].sampler = VK_NULL_HANDLE; - imageInfos[imageInfoCount].imageView = commandBuffer->vertexStorageTextures[i]->fullView; - imageInfos[imageInfoCount].imageLayout = VK_IMAGE_LAYOUT_GENERAL; - - currentWriteDescriptorSet->pImageInfo = &imageInfos[imageInfoCount]; - - writeCount += 1; - imageInfoCount += 1; - } - - for (Uint32 i = 0; i < resourceLayout->vertexStorageBufferCount; i += 1) { - VkWriteDescriptorSet *currentWriteDescriptorSet = &writeDescriptorSets[writeCount]; - - currentWriteDescriptorSet->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - currentWriteDescriptorSet->pNext = NULL; - currentWriteDescriptorSet->descriptorCount = 1; - currentWriteDescriptorSet->descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; - currentWriteDescriptorSet->dstArrayElement = 0; - currentWriteDescriptorSet->dstBinding = resourceLayout->vertexSamplerCount + resourceLayout->vertexStorageTextureCount + i; - currentWriteDescriptorSet->dstSet = commandBuffer->vertexResourceDescriptorSet; - currentWriteDescriptorSet->pTexelBufferView = NULL; - currentWriteDescriptorSet->pImageInfo = NULL; - - bufferInfos[bufferInfoCount].buffer = commandBuffer->vertexStorageBuffers[i]->buffer; - bufferInfos[bufferInfoCount].offset = 0; - bufferInfos[bufferInfoCount].range = VK_WHOLE_SIZE; - - currentWriteDescriptorSet->pBufferInfo = &bufferInfos[bufferInfoCount]; - - writeCount += 1; - bufferInfoCount += 1; - } - - commandBuffer->needNewVertexResourceDescriptorSet = false; - } - - if (commandBuffer->needNewVertexUniformDescriptorSet) { - descriptorSetLayout = resourceLayout->descriptorSetLayouts[1]; - - commandBuffer->vertexUniformDescriptorSet = VULKAN_INTERNAL_FetchDescriptorSet( - renderer, - commandBuffer, - descriptorSetLayout); - - for (Uint32 i = 0; i < resourceLayout->vertexUniformBufferCount; i += 1) { - VkWriteDescriptorSet *currentWriteDescriptorSet = &writeDescriptorSets[writeCount]; - - currentWriteDescriptorSet->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - currentWriteDescriptorSet->pNext = NULL; - currentWriteDescriptorSet->descriptorCount = 1; - currentWriteDescriptorSet->descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC; - currentWriteDescriptorSet->dstArrayElement = 0; - currentWriteDescriptorSet->dstBinding = i; - currentWriteDescriptorSet->dstSet = commandBuffer->vertexUniformDescriptorSet; - currentWriteDescriptorSet->pTexelBufferView = NULL; - currentWriteDescriptorSet->pImageInfo = NULL; - - bufferInfos[bufferInfoCount].buffer = commandBuffer->vertexUniformBuffers[i]->buffer->buffer; - bufferInfos[bufferInfoCount].offset = 0; - bufferInfos[bufferInfoCount].range = MAX_UBO_SECTION_SIZE; - - currentWriteDescriptorSet->pBufferInfo = &bufferInfos[bufferInfoCount]; - - writeCount += 1; - bufferInfoCount += 1; - } - - commandBuffer->needNewVertexUniformDescriptorSet = false; - } - - for (Uint32 i = 0; i < resourceLayout->vertexUniformBufferCount; i += 1) { - dynamicOffsets[dynamicOffsetCount] = commandBuffer->vertexUniformBuffers[i]->drawOffset; - dynamicOffsetCount += 1; - } - - if (commandBuffer->needNewFragmentResourceDescriptorSet) { - descriptorSetLayout = resourceLayout->descriptorSetLayouts[2]; - - commandBuffer->fragmentResourceDescriptorSet = VULKAN_INTERNAL_FetchDescriptorSet( - renderer, - commandBuffer, - descriptorSetLayout); - - for (Uint32 i = 0; i < resourceLayout->fragmentSamplerCount; i += 1) { - VkWriteDescriptorSet *currentWriteDescriptorSet = &writeDescriptorSets[writeCount]; - - currentWriteDescriptorSet->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - currentWriteDescriptorSet->pNext = NULL; - currentWriteDescriptorSet->descriptorCount = 1; - currentWriteDescriptorSet->descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - currentWriteDescriptorSet->dstArrayElement = 0; - currentWriteDescriptorSet->dstBinding = i; - currentWriteDescriptorSet->dstSet = commandBuffer->fragmentResourceDescriptorSet; - currentWriteDescriptorSet->pTexelBufferView = NULL; - currentWriteDescriptorSet->pBufferInfo = NULL; - - imageInfos[imageInfoCount].sampler = commandBuffer->fragmentSamplers[i]->sampler; - imageInfos[imageInfoCount].imageView = commandBuffer->fragmentSamplerTextures[i]->fullView; - imageInfos[imageInfoCount].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - - currentWriteDescriptorSet->pImageInfo = &imageInfos[imageInfoCount]; - - writeCount += 1; - imageInfoCount += 1; - } - - for (Uint32 i = 0; i < resourceLayout->fragmentStorageTextureCount; i += 1) { - VkWriteDescriptorSet *currentWriteDescriptorSet = &writeDescriptorSets[writeCount]; - - currentWriteDescriptorSet->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - currentWriteDescriptorSet->pNext = NULL; - currentWriteDescriptorSet->descriptorCount = 1; - currentWriteDescriptorSet->descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE; // Yes, we are declaring a storage image as a sampled image, because shaders are stupid. - currentWriteDescriptorSet->dstArrayElement = 0; - currentWriteDescriptorSet->dstBinding = resourceLayout->fragmentSamplerCount + i; - currentWriteDescriptorSet->dstSet = commandBuffer->fragmentResourceDescriptorSet; - currentWriteDescriptorSet->pTexelBufferView = NULL; - currentWriteDescriptorSet->pBufferInfo = NULL; - - imageInfos[imageInfoCount].sampler = VK_NULL_HANDLE; - imageInfos[imageInfoCount].imageView = commandBuffer->fragmentStorageTextures[i]->fullView; - imageInfos[imageInfoCount].imageLayout = VK_IMAGE_LAYOUT_GENERAL; - - currentWriteDescriptorSet->pImageInfo = &imageInfos[imageInfoCount]; - - writeCount += 1; - imageInfoCount += 1; - } - - for (Uint32 i = 0; i < resourceLayout->fragmentStorageBufferCount; i += 1) { - VkWriteDescriptorSet *currentWriteDescriptorSet = &writeDescriptorSets[writeCount]; - - currentWriteDescriptorSet->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - currentWriteDescriptorSet->pNext = NULL; - currentWriteDescriptorSet->descriptorCount = 1; - currentWriteDescriptorSet->descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; - currentWriteDescriptorSet->dstArrayElement = 0; - currentWriteDescriptorSet->dstBinding = resourceLayout->fragmentSamplerCount + resourceLayout->fragmentStorageTextureCount + i; - currentWriteDescriptorSet->dstSet = commandBuffer->fragmentResourceDescriptorSet; - currentWriteDescriptorSet->pTexelBufferView = NULL; - currentWriteDescriptorSet->pImageInfo = NULL; - - bufferInfos[bufferInfoCount].buffer = commandBuffer->fragmentStorageBuffers[i]->buffer; - bufferInfos[bufferInfoCount].offset = 0; - bufferInfos[bufferInfoCount].range = VK_WHOLE_SIZE; - - currentWriteDescriptorSet->pBufferInfo = &bufferInfos[bufferInfoCount]; - - writeCount += 1; - bufferInfoCount += 1; - } - - commandBuffer->needNewFragmentResourceDescriptorSet = false; - } - - if (commandBuffer->needNewFragmentUniformDescriptorSet) { - descriptorSetLayout = resourceLayout->descriptorSetLayouts[3]; - - commandBuffer->fragmentUniformDescriptorSet = VULKAN_INTERNAL_FetchDescriptorSet( - renderer, - commandBuffer, - descriptorSetLayout); - - for (Uint32 i = 0; i < resourceLayout->fragmentUniformBufferCount; i += 1) { - VkWriteDescriptorSet *currentWriteDescriptorSet = &writeDescriptorSets[writeCount]; - - currentWriteDescriptorSet->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - currentWriteDescriptorSet->pNext = NULL; - currentWriteDescriptorSet->descriptorCount = 1; - currentWriteDescriptorSet->descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC; - currentWriteDescriptorSet->dstArrayElement = 0; - currentWriteDescriptorSet->dstBinding = i; - currentWriteDescriptorSet->dstSet = commandBuffer->fragmentUniformDescriptorSet; - currentWriteDescriptorSet->pTexelBufferView = NULL; - currentWriteDescriptorSet->pImageInfo = NULL; - - bufferInfos[bufferInfoCount].buffer = commandBuffer->fragmentUniformBuffers[i]->buffer->buffer; - bufferInfos[bufferInfoCount].offset = 0; - bufferInfos[bufferInfoCount].range = MAX_UBO_SECTION_SIZE; - - currentWriteDescriptorSet->pBufferInfo = &bufferInfos[bufferInfoCount]; - - writeCount += 1; - bufferInfoCount += 1; - } - - commandBuffer->needNewFragmentUniformDescriptorSet = false; - } - - for (Uint32 i = 0; i < resourceLayout->fragmentUniformBufferCount; i += 1) { - dynamicOffsets[dynamicOffsetCount] = commandBuffer->fragmentUniformBuffers[i]->drawOffset; - dynamicOffsetCount += 1; - } - - renderer->vkUpdateDescriptorSets( - renderer->logicalDevice, - writeCount, - writeDescriptorSets, - 0, - NULL); - - VkDescriptorSet sets[4]; - sets[0] = commandBuffer->vertexResourceDescriptorSet; - sets[1] = commandBuffer->vertexUniformDescriptorSet; - sets[2] = commandBuffer->fragmentResourceDescriptorSet; - sets[3] = commandBuffer->fragmentUniformDescriptorSet; - - renderer->vkCmdBindDescriptorSets( - commandBuffer->commandBuffer, - VK_PIPELINE_BIND_POINT_GRAPHICS, - resourceLayout->pipelineLayout, - 0, - 4, - sets, - dynamicOffsetCount, - dynamicOffsets); - - commandBuffer->needNewVertexUniformOffsets = false; - commandBuffer->needNewFragmentUniformOffsets = false; -} - -static void VULKAN_DrawIndexedPrimitives( - SDL_GPUCommandBuffer *commandBuffer, - Uint32 numIndices, - Uint32 numInstances, - Uint32 firstIndex, - Sint32 vertexOffset, - Uint32 firstInstance) -{ - VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; - VulkanRenderer *renderer = vulkanCommandBuffer->renderer; - - VULKAN_INTERNAL_BindGraphicsDescriptorSets(renderer, vulkanCommandBuffer); - - renderer->vkCmdDrawIndexed( - vulkanCommandBuffer->commandBuffer, - numIndices, - numInstances, - firstIndex, - vertexOffset, - firstInstance); -} - -static void VULKAN_DrawPrimitives( - SDL_GPUCommandBuffer *commandBuffer, - Uint32 numVertices, - Uint32 numInstances, - Uint32 firstVertex, - Uint32 firstInstance) -{ - VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; - VulkanRenderer *renderer = vulkanCommandBuffer->renderer; - - VULKAN_INTERNAL_BindGraphicsDescriptorSets(renderer, vulkanCommandBuffer); - - renderer->vkCmdDraw( - vulkanCommandBuffer->commandBuffer, - numVertices, - numInstances, - firstVertex, - firstInstance); -} - -static void VULKAN_DrawPrimitivesIndirect( - SDL_GPUCommandBuffer *commandBuffer, - SDL_GPUBuffer *buffer, - Uint32 offset, - Uint32 drawCount) -{ - VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; - VulkanRenderer *renderer = vulkanCommandBuffer->renderer; - VulkanBuffer *vulkanBuffer = ((VulkanBufferContainer *)buffer)->activeBuffer; - Uint32 pitch = sizeof(SDL_GPUIndirectDrawCommand); - Uint32 i; - - VULKAN_INTERNAL_BindGraphicsDescriptorSets(renderer, vulkanCommandBuffer); - - if (renderer->supportsMultiDrawIndirect) { - // Real multi-draw! - renderer->vkCmdDrawIndirect( - vulkanCommandBuffer->commandBuffer, - vulkanBuffer->buffer, - offset, - drawCount, - pitch); - } else { - // Fake multi-draw... - for (i = 0; i < drawCount; i += 1) { - renderer->vkCmdDrawIndirect( - vulkanCommandBuffer->commandBuffer, - vulkanBuffer->buffer, - offset + (pitch * i), - 1, - pitch); - } - } - - VULKAN_INTERNAL_TrackBuffer(vulkanCommandBuffer, vulkanBuffer); -} - -static void VULKAN_DrawIndexedPrimitivesIndirect( - SDL_GPUCommandBuffer *commandBuffer, - SDL_GPUBuffer *buffer, - Uint32 offset, - Uint32 drawCount) -{ - VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; - VulkanRenderer *renderer = vulkanCommandBuffer->renderer; - VulkanBuffer *vulkanBuffer = ((VulkanBufferContainer *)buffer)->activeBuffer; - Uint32 pitch = sizeof(SDL_GPUIndexedIndirectDrawCommand); - Uint32 i; - - VULKAN_INTERNAL_BindGraphicsDescriptorSets(renderer, vulkanCommandBuffer); - - if (renderer->supportsMultiDrawIndirect) { - // Real multi-draw! - renderer->vkCmdDrawIndexedIndirect( - vulkanCommandBuffer->commandBuffer, - vulkanBuffer->buffer, - offset, - drawCount, - pitch); - } else { - // Fake multi-draw... - for (i = 0; i < drawCount; i += 1) { - renderer->vkCmdDrawIndexedIndirect( - vulkanCommandBuffer->commandBuffer, - vulkanBuffer->buffer, - offset + (pitch * i), - 1, - pitch); - } - } - - VULKAN_INTERNAL_TrackBuffer(vulkanCommandBuffer, vulkanBuffer); -} - -// Debug Naming - -static void VULKAN_INTERNAL_SetBufferName( - VulkanRenderer *renderer, - VulkanBuffer *buffer, - const char *text) -{ - VkDebugUtilsObjectNameInfoEXT nameInfo; - - if (renderer->debugMode && renderer->supportsDebugUtils) { - nameInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT; - nameInfo.pNext = NULL; - nameInfo.pObjectName = text; - nameInfo.objectType = VK_OBJECT_TYPE_BUFFER; - nameInfo.objectHandle = (uint64_t)buffer->buffer; - - renderer->vkSetDebugUtilsObjectNameEXT( - renderer->logicalDevice, - &nameInfo); - } -} - -static void VULKAN_SetBufferName( - SDL_GPURenderer *driverData, - SDL_GPUBuffer *buffer, - const char *text) -{ - VulkanRenderer *renderer = (VulkanRenderer *)driverData; - VulkanBufferContainer *container = (VulkanBufferContainer *)buffer; - size_t textLength = SDL_strlen(text) + 1; - - if (renderer->debugMode && renderer->supportsDebugUtils) { - container->debugName = SDL_realloc( - container->debugName, - textLength); - - SDL_utf8strlcpy( - container->debugName, - text, - textLength); - - for (Uint32 i = 0; i < container->bufferCount; i += 1) { - VULKAN_INTERNAL_SetBufferName( - renderer, - container->buffers[i], - text); - } - } -} - -static void VULKAN_INTERNAL_SetTextureName( - VulkanRenderer *renderer, - VulkanTexture *texture, - const char *text) -{ - VkDebugUtilsObjectNameInfoEXT nameInfo; - - if (renderer->debugMode && renderer->supportsDebugUtils) { - nameInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT; - nameInfo.pNext = NULL; - nameInfo.pObjectName = text; - nameInfo.objectType = VK_OBJECT_TYPE_IMAGE; - nameInfo.objectHandle = (uint64_t)texture->image; - - renderer->vkSetDebugUtilsObjectNameEXT( - renderer->logicalDevice, - &nameInfo); - } -} - -static void VULKAN_SetTextureName( - SDL_GPURenderer *driverData, - SDL_GPUTexture *texture, - const char *text) -{ - VulkanRenderer *renderer = (VulkanRenderer *)driverData; - VulkanTextureContainer *container = (VulkanTextureContainer *)texture; - size_t textLength = SDL_strlen(text) + 1; - - if (renderer->debugMode && renderer->supportsDebugUtils) { - container->debugName = SDL_realloc( - container->debugName, - textLength); - - SDL_utf8strlcpy( - container->debugName, - text, - textLength); - - for (Uint32 i = 0; i < container->textureCount; i += 1) { - VULKAN_INTERNAL_SetTextureName( - renderer, - container->textures[i], - text); - } - } -} - -static void VULKAN_InsertDebugLabel( - SDL_GPUCommandBuffer *commandBuffer, - const char *text) -{ - VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; - VulkanRenderer *renderer = vulkanCommandBuffer->renderer; - VkDebugUtilsLabelEXT labelInfo; - - if (renderer->supportsDebugUtils) { - SDL_zero(labelInfo); - labelInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT; - labelInfo.pLabelName = text; - - renderer->vkCmdInsertDebugUtilsLabelEXT( - vulkanCommandBuffer->commandBuffer, - &labelInfo); - } -} - -static void VULKAN_PushDebugGroup( - SDL_GPUCommandBuffer *commandBuffer, - const char *name) -{ - VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; - VulkanRenderer *renderer = vulkanCommandBuffer->renderer; - VkDebugUtilsLabelEXT labelInfo; - - if (renderer->supportsDebugUtils) { - SDL_zero(labelInfo); - labelInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT; - labelInfo.pLabelName = name; - - renderer->vkCmdBeginDebugUtilsLabelEXT( - vulkanCommandBuffer->commandBuffer, - &labelInfo); - } -} - -static void VULKAN_PopDebugGroup( - SDL_GPUCommandBuffer *commandBuffer) -{ - VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; - VulkanRenderer *renderer = vulkanCommandBuffer->renderer; - - if (renderer->supportsDebugUtils) { - renderer->vkCmdEndDebugUtilsLabelEXT(vulkanCommandBuffer->commandBuffer); - } -} - -static VulkanTexture *VULKAN_INTERNAL_CreateTexture( - VulkanRenderer *renderer, - const SDL_GPUTextureCreateInfo *createinfo) -{ - VkResult vulkanResult; - VkImageCreateInfo imageCreateInfo; - VkImageCreateFlags imageCreateFlags = 0; - VkImageViewCreateInfo imageViewCreateInfo; - Uint8 bindResult; - VkImageUsageFlags vkUsageFlags = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT; - Uint32 layerCount = (createinfo->type == SDL_GPU_TEXTURETYPE_3D) ? 1 : createinfo->layer_count_or_depth; - Uint32 depth = (createinfo->type == SDL_GPU_TEXTURETYPE_3D) ? createinfo->layer_count_or_depth : 1; - - VulkanTexture *texture = SDL_calloc(1, sizeof(VulkanTexture)); - texture->swizzle = SwizzleForSDLFormat(createinfo->format); - texture->depth = depth; - texture->usage = createinfo->usage; - SDL_SetAtomicInt(&texture->referenceCount, 0); - - if (IsDepthFormat(createinfo->format)) { - texture->aspectFlags = VK_IMAGE_ASPECT_DEPTH_BIT; - - if (IsStencilFormat(createinfo->format)) { - texture->aspectFlags |= VK_IMAGE_ASPECT_STENCIL_BIT; - } - } else { - texture->aspectFlags = VK_IMAGE_ASPECT_COLOR_BIT; - } - - if (createinfo->type == SDL_GPU_TEXTURETYPE_CUBE || createinfo->type == SDL_GPU_TEXTURETYPE_CUBE_ARRAY) { - imageCreateFlags |= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT; - } else if (createinfo->type == SDL_GPU_TEXTURETYPE_3D) { - imageCreateFlags |= VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT; - } - - if (createinfo->usage & (SDL_GPU_TEXTUREUSAGE_SAMPLER | - SDL_GPU_TEXTUREUSAGE_GRAPHICS_STORAGE_READ | - SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_READ)) { - vkUsageFlags |= VK_IMAGE_USAGE_SAMPLED_BIT; - } - if (createinfo->usage & SDL_GPU_TEXTUREUSAGE_COLOR_TARGET) { - vkUsageFlags |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; - } - if (createinfo->usage & SDL_GPU_TEXTUREUSAGE_DEPTH_STENCIL_TARGET) { - vkUsageFlags |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; - } - if (createinfo->usage & (SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_WRITE | - SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_SIMULTANEOUS_READ_WRITE)) { - vkUsageFlags |= VK_IMAGE_USAGE_STORAGE_BIT; - } - - imageCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; - imageCreateInfo.pNext = NULL; - imageCreateInfo.flags = imageCreateFlags; - imageCreateInfo.imageType = createinfo->type == SDL_GPU_TEXTURETYPE_3D ? VK_IMAGE_TYPE_3D : VK_IMAGE_TYPE_2D; - imageCreateInfo.format = SDLToVK_TextureFormat[createinfo->format]; - imageCreateInfo.extent.width = createinfo->width; - imageCreateInfo.extent.height = createinfo->height; - imageCreateInfo.extent.depth = depth; - imageCreateInfo.mipLevels = createinfo->num_levels; - imageCreateInfo.arrayLayers = layerCount; - imageCreateInfo.samples = SDLToVK_SampleCount[createinfo->sample_count]; - imageCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL; - imageCreateInfo.usage = vkUsageFlags; - 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) { - VULKAN_INTERNAL_DestroyTexture(renderer, texture); - CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkCreateImage, NULL); - } - - bindResult = VULKAN_INTERNAL_BindMemoryForImage( - renderer, - texture->image, - &texture->usedRegion); - - if (bindResult != 1) { - renderer->vkDestroyImage( - renderer->logicalDevice, - texture->image, - NULL); - - VULKAN_INTERNAL_DestroyTexture(renderer, texture); - SET_STRING_ERROR_AND_RETURN("Unable to bind memory for texture!", NULL); - } - - texture->usedRegion->vulkanTexture = texture; // lol - - if (createinfo->usage & (SDL_GPU_TEXTUREUSAGE_SAMPLER | SDL_GPU_TEXTUREUSAGE_GRAPHICS_STORAGE_READ | SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_READ)) { - - imageViewCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; - imageViewCreateInfo.pNext = NULL; - imageViewCreateInfo.flags = 0; - imageViewCreateInfo.image = texture->image; - imageViewCreateInfo.format = SDLToVK_TextureFormat[createinfo->format]; - imageViewCreateInfo.components = texture->swizzle; - imageViewCreateInfo.subresourceRange.aspectMask = texture->aspectFlags & ~VK_IMAGE_ASPECT_STENCIL_BIT; // Can't sample stencil values - imageViewCreateInfo.subresourceRange.baseMipLevel = 0; - imageViewCreateInfo.subresourceRange.levelCount = createinfo->num_levels; - imageViewCreateInfo.subresourceRange.baseArrayLayer = 0; - imageViewCreateInfo.subresourceRange.layerCount = layerCount; - - if (createinfo->type == SDL_GPU_TEXTURETYPE_CUBE) { - imageViewCreateInfo.viewType = VK_IMAGE_VIEW_TYPE_CUBE; - } else if (createinfo->type == SDL_GPU_TEXTURETYPE_CUBE_ARRAY) { - imageViewCreateInfo.viewType = VK_IMAGE_VIEW_TYPE_CUBE_ARRAY; - } else if (createinfo->type == SDL_GPU_TEXTURETYPE_3D) { - imageViewCreateInfo.viewType = VK_IMAGE_VIEW_TYPE_3D; - } else if (createinfo->type == SDL_GPU_TEXTURETYPE_2D_ARRAY) { - imageViewCreateInfo.viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY; - } else { - imageViewCreateInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; - } - - vulkanResult = renderer->vkCreateImageView( - renderer->logicalDevice, - &imageViewCreateInfo, - NULL, - &texture->fullView); - - if (vulkanResult != VK_SUCCESS) { - VULKAN_INTERNAL_DestroyTexture(renderer, texture); - CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, "vkCreateImageView", NULL); - } - } - - // Define slices - texture->subresourceCount = layerCount * createinfo->num_levels; - texture->subresources = SDL_calloc( - texture->subresourceCount, - sizeof(VulkanTextureSubresource)); - - for (Uint32 i = 0; i < layerCount; i += 1) { - for (Uint32 j = 0; j < createinfo->num_levels; j += 1) { - Uint32 subresourceIndex = VULKAN_INTERNAL_GetTextureSubresourceIndex( - j, - i, - createinfo->num_levels); - - if (createinfo->usage & SDL_GPU_TEXTUREUSAGE_COLOR_TARGET) { - texture->subresources[subresourceIndex].renderTargetViews = SDL_malloc( - depth * sizeof(VkImageView)); - - if (depth > 1) { - for (Uint32 k = 0; k < depth; k += 1) { - if (!VULKAN_INTERNAL_CreateRenderTargetView( - renderer, - texture, - k, - j, - SDLToVK_TextureFormat[createinfo->format], - texture->swizzle, - &texture->subresources[subresourceIndex].renderTargetViews[k])) { - VULKAN_INTERNAL_DestroyTexture(renderer, texture); - return NULL; - } - } - } else { - if (!VULKAN_INTERNAL_CreateRenderTargetView( - renderer, - texture, - i, - j, - SDLToVK_TextureFormat[createinfo->format], - texture->swizzle, - &texture->subresources[subresourceIndex].renderTargetViews[0])) { - VULKAN_INTERNAL_DestroyTexture(renderer, texture); - return NULL; - } - } - } - - if ((createinfo->usage & SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_WRITE) || (createinfo->usage & SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_SIMULTANEOUS_READ_WRITE)) { - if (!VULKAN_INTERNAL_CreateSubresourceView( - renderer, - createinfo, - texture, - i, - j, - texture->swizzle, - &texture->subresources[subresourceIndex].computeWriteView)) { - VULKAN_INTERNAL_DestroyTexture(renderer, texture); - return NULL; - } - } - - if (createinfo->usage & SDL_GPU_TEXTUREUSAGE_DEPTH_STENCIL_TARGET) { - if (!VULKAN_INTERNAL_CreateSubresourceView( - renderer, - createinfo, - texture, - i, - j, - texture->swizzle, - &texture->subresources[subresourceIndex].depthStencilView)) { - VULKAN_INTERNAL_DestroyTexture(renderer, texture); - return NULL; - } - } - - texture->subresources[subresourceIndex].parent = texture; - texture->subresources[subresourceIndex].layer = i; - texture->subresources[subresourceIndex].level = j; - } - } - - // Set debug name if applicable - if (renderer->debugMode && renderer->supportsDebugUtils && SDL_HasProperty(createinfo->props, SDL_PROP_GPU_TEXTURE_CREATE_NAME_STRING)) { - VkDebugUtilsObjectNameInfoEXT nameInfo; - nameInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT; - nameInfo.pNext = NULL; - nameInfo.pObjectName = SDL_GetStringProperty(createinfo->props, SDL_PROP_GPU_TEXTURE_CREATE_NAME_STRING, NULL); - nameInfo.objectType = VK_OBJECT_TYPE_IMAGE; - nameInfo.objectHandle = (uint64_t)texture->image; - - renderer->vkSetDebugUtilsObjectNameEXT( - renderer->logicalDevice, - &nameInfo); - } - - // Let's transition to the default barrier state, because for some reason Vulkan doesn't let us do that with initialLayout. - VulkanCommandBuffer *barrierCommandBuffer = (VulkanCommandBuffer *)VULKAN_AcquireCommandBuffer((SDL_GPURenderer *)renderer); - VULKAN_INTERNAL_TextureTransitionToDefaultUsage( - renderer, - barrierCommandBuffer, - VULKAN_TEXTURE_USAGE_MODE_UNINITIALIZED, - texture); - VULKAN_INTERNAL_TrackTexture(barrierCommandBuffer, texture); - VULKAN_Submit((SDL_GPUCommandBuffer *)barrierCommandBuffer); - - return texture; -} - -static void VULKAN_INTERNAL_CycleActiveBuffer( - VulkanRenderer *renderer, - VulkanBufferContainer *container) -{ - VulkanBuffer *buffer; - - // If a previously-cycled buffer is available, we can use that. - for (Uint32 i = 0; i < container->bufferCount; i += 1) { - buffer = container->buffers[i]; - if (SDL_GetAtomicInt(&buffer->referenceCount) == 0) { - container->activeBuffer = buffer; - return; - } - } - - // No buffer handle is available, create a new one. - buffer = VULKAN_INTERNAL_CreateBuffer( - renderer, - container->activeBuffer->size, - container->activeBuffer->usage, - container->activeBuffer->type, - container->dedicated, - container->debugName); - - if (!buffer) { - return; - } - - EXPAND_ARRAY_IF_NEEDED( - container->buffers, - VulkanBuffer *, - container->bufferCount + 1, - container->bufferCapacity, - container->bufferCapacity * 2); - - container->buffers[container->bufferCount] = buffer; - buffer->container = container; - buffer->containerIndex = container->bufferCount; - container->bufferCount += 1; - - container->activeBuffer = buffer; -} - -static void VULKAN_INTERNAL_CycleActiveTexture( - VulkanRenderer *renderer, - VulkanTextureContainer *container) -{ - VulkanTexture *texture; - - // If a previously-cycled texture is available, we can use that. - for (Uint32 i = 0; i < container->textureCount; i += 1) { - texture = container->textures[i]; - - if (SDL_GetAtomicInt(&texture->referenceCount) == 0) { - container->activeTexture = texture; - return; - } - } - - // No texture is available, generate a new one. - texture = VULKAN_INTERNAL_CreateTexture( - renderer, - &container->header.info); - - if (!texture) { - return; - } - - EXPAND_ARRAY_IF_NEEDED( - container->textures, - VulkanTexture *, - container->textureCount + 1, - container->textureCapacity, - container->textureCapacity * 2); - - container->textures[container->textureCount] = texture; - texture->container = container; - texture->containerIndex = container->textureCount; - container->textureCount += 1; - - container->activeTexture = texture; -} - -static VulkanBuffer *VULKAN_INTERNAL_PrepareBufferForWrite( - VulkanRenderer *renderer, - VulkanCommandBuffer *commandBuffer, - VulkanBufferContainer *bufferContainer, - bool cycle, - VulkanBufferUsageMode destinationUsageMode) -{ - if ( - cycle && - SDL_GetAtomicInt(&bufferContainer->activeBuffer->referenceCount) > 0) { - VULKAN_INTERNAL_CycleActiveBuffer( - renderer, - bufferContainer); - } - - VULKAN_INTERNAL_BufferTransitionFromDefaultUsage( - renderer, - commandBuffer, - destinationUsageMode, - bufferContainer->activeBuffer); - - return bufferContainer->activeBuffer; -} - -static VulkanTextureSubresource *VULKAN_INTERNAL_PrepareTextureSubresourceForWrite( - VulkanRenderer *renderer, - VulkanCommandBuffer *commandBuffer, - VulkanTextureContainer *textureContainer, - Uint32 layer, - Uint32 level, - bool cycle, - VulkanTextureUsageMode destinationUsageMode) -{ - VulkanTextureSubresource *textureSubresource = VULKAN_INTERNAL_FetchTextureSubresource( - textureContainer, - layer, - level); - - if ( - cycle && - textureContainer->canBeCycled && - SDL_GetAtomicInt(&textureContainer->activeTexture->referenceCount) > 0) { - VULKAN_INTERNAL_CycleActiveTexture( - renderer, - textureContainer); - - textureSubresource = VULKAN_INTERNAL_FetchTextureSubresource( - textureContainer, - layer, - level); - } - - // always do barrier because of layout transitions - VULKAN_INTERNAL_TextureSubresourceTransitionFromDefaultUsage( - renderer, - commandBuffer, - destinationUsageMode, - textureSubresource); - - return textureSubresource; -} - -static VkRenderPass VULKAN_INTERNAL_CreateRenderPass( - VulkanRenderer *renderer, - VulkanCommandBuffer *commandBuffer, - const SDL_GPUColorTargetInfo *colorTargetInfos, - Uint32 numColorTargets, - const SDL_GPUDepthStencilTargetInfo *depthStencilTargetInfo) -{ - VkResult vulkanResult; - VkAttachmentDescription attachmentDescriptions[2 * MAX_COLOR_TARGET_BINDINGS + 1 /* depth */]; - VkAttachmentReference colorAttachmentReferences[MAX_COLOR_TARGET_BINDINGS]; - VkAttachmentReference resolveReferences[MAX_COLOR_TARGET_BINDINGS]; - VkAttachmentReference depthStencilAttachmentReference; - VkRenderPassCreateInfo renderPassCreateInfo; - VkSubpassDescription subpass; - VkRenderPass renderPass; - Uint32 i; - - Uint32 attachmentDescriptionCount = 0; - Uint32 colorAttachmentReferenceCount = 0; - Uint32 resolveReferenceCount = 0; - - for (i = 0; i < numColorTargets; i += 1) { - VulkanTextureContainer *container = (VulkanTextureContainer *)colorTargetInfos[i].texture; - attachmentDescriptions[attachmentDescriptionCount].flags = 0; - attachmentDescriptions[attachmentDescriptionCount].format = SDLToVK_TextureFormat[container->header.info.format]; - attachmentDescriptions[attachmentDescriptionCount].samples = SDLToVK_SampleCount[container->header.info.sample_count]; - attachmentDescriptions[attachmentDescriptionCount].loadOp = SDLToVK_LoadOp[colorTargetInfos[i].load_op]; - attachmentDescriptions[attachmentDescriptionCount].storeOp = SDLToVK_StoreOp[colorTargetInfos[i].store_op]; - 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; - - if (colorTargetInfos[i].store_op == SDL_GPU_STOREOP_RESOLVE || colorTargetInfos[i].store_op == SDL_GPU_STOREOP_RESOLVE_AND_STORE) { - VulkanTextureContainer *resolveContainer = (VulkanTextureContainer *)colorTargetInfos[i].resolve_texture; - - attachmentDescriptions[attachmentDescriptionCount].flags = 0; - attachmentDescriptions[attachmentDescriptionCount].format = SDLToVK_TextureFormat[resolveContainer->header.info.format]; - attachmentDescriptions[attachmentDescriptionCount].samples = SDLToVK_SampleCount[resolveContainer->header.info.sample_count]; - attachmentDescriptions[attachmentDescriptionCount].loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; // The texture will be overwritten anyway - attachmentDescriptions[attachmentDescriptionCount].storeOp = VK_ATTACHMENT_STORE_OP_STORE; // Always store the resolve texture - 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; - } - } - - subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; - subpass.flags = 0; - subpass.inputAttachmentCount = 0; - subpass.pInputAttachments = NULL; - subpass.colorAttachmentCount = numColorTargets; - subpass.pColorAttachments = colorAttachmentReferences; - subpass.preserveAttachmentCount = 0; - subpass.pPreserveAttachments = NULL; - - if (depthStencilTargetInfo == NULL) { - subpass.pDepthStencilAttachment = NULL; - } else { - VulkanTextureContainer *container = (VulkanTextureContainer *)depthStencilTargetInfo->texture; - - attachmentDescriptions[attachmentDescriptionCount].flags = 0; - attachmentDescriptions[attachmentDescriptionCount].format = SDLToVK_TextureFormat[container->header.info.format]; - attachmentDescriptions[attachmentDescriptionCount].samples = SDLToVK_SampleCount[container->header.info.sample_count]; - attachmentDescriptions[attachmentDescriptionCount].loadOp = SDLToVK_LoadOp[depthStencilTargetInfo->load_op]; - attachmentDescriptions[attachmentDescriptionCount].storeOp = SDLToVK_StoreOp[depthStencilTargetInfo->store_op]; - attachmentDescriptions[attachmentDescriptionCount].stencilLoadOp = SDLToVK_LoadOp[depthStencilTargetInfo->stencil_load_op]; - attachmentDescriptions[attachmentDescriptionCount].stencilStoreOp = SDLToVK_StoreOp[depthStencilTargetInfo->stencil_store_op]; - 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; - } - - if (resolveReferenceCount > 0) { - 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; - - vulkanResult = renderer->vkCreateRenderPass( - renderer->logicalDevice, - &renderPassCreateInfo, - NULL, - &renderPass); - - CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkCreateRenderPass, VK_NULL_HANDLE); - - return renderPass; -} - -static VkRenderPass VULKAN_INTERNAL_CreateTransientRenderPass( - VulkanRenderer *renderer, - SDL_GPUGraphicsPipelineTargetInfo targetInfo, - VkSampleCountFlagBits sampleCount) -{ - VkAttachmentDescription attachmentDescriptions[MAX_COLOR_TARGET_BINDINGS + 1 /* depth */]; - VkAttachmentReference colorAttachmentReferences[MAX_COLOR_TARGET_BINDINGS]; - VkAttachmentReference depthStencilAttachmentReference; - SDL_GPUColorTargetDescription attachmentDescription; - VkSubpassDescription subpass; - VkRenderPassCreateInfo renderPassCreateInfo; - VkRenderPass renderPass; - VkResult result; - - Uint32 attachmentDescriptionCount = 0; - Uint32 colorAttachmentReferenceCount = 0; - Uint32 i; - - for (i = 0; i < targetInfo.num_color_targets; i += 1) { - attachmentDescription = targetInfo.color_target_descriptions[i]; - - attachmentDescriptions[attachmentDescriptionCount].flags = 0; - attachmentDescriptions[attachmentDescriptionCount].format = SDLToVK_TextureFormat[attachmentDescription.format]; - attachmentDescriptions[attachmentDescriptionCount].samples = sampleCount; - 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 = targetInfo.num_color_targets; - subpass.pColorAttachments = colorAttachmentReferences; - subpass.preserveAttachmentCount = 0; - subpass.pPreserveAttachments = NULL; - - if (targetInfo.has_depth_stencil_target) { - attachmentDescriptions[attachmentDescriptionCount].flags = 0; - attachmentDescriptions[attachmentDescriptionCount].format = SDLToVK_TextureFormat[targetInfo.depth_stencil_format]; - attachmentDescriptions[attachmentDescriptionCount].samples = sampleCount; - 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; - } - - // Resolve attachments aren't needed for transient passes - 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); - - CHECK_VULKAN_ERROR_AND_RETURN(result, vkCreateRenderPass, VK_NULL_HANDLE); - - return renderPass; -} - -static SDL_GPUGraphicsPipeline *VULKAN_CreateGraphicsPipeline( - SDL_GPURenderer *driverData, - const SDL_GPUGraphicsPipelineCreateInfo *createinfo) -{ - VkResult vulkanResult; - Uint32 i; - - VulkanGraphicsPipeline *graphicsPipeline = (VulkanGraphicsPipeline *)SDL_malloc(sizeof(VulkanGraphicsPipeline)); - VkGraphicsPipelineCreateInfo vkPipelineCreateInfo; - - VkPipelineShaderStageCreateInfo shaderStageCreateInfos[2]; - - VkPipelineVertexInputStateCreateInfo vertexInputStateCreateInfo; - VkVertexInputBindingDescription *vertexInputBindingDescriptions = SDL_stack_alloc(VkVertexInputBindingDescription, createinfo->vertex_input_state.num_vertex_buffers); - VkVertexInputAttributeDescription *vertexInputAttributeDescriptions = SDL_stack_alloc(VkVertexInputAttributeDescription, createinfo->vertex_input_state.num_vertex_attributes); - - VkPipelineInputAssemblyStateCreateInfo inputAssemblyStateCreateInfo; - - VkPipelineViewportStateCreateInfo viewportStateCreateInfo; - - VkPipelineRasterizationStateCreateInfo rasterizationStateCreateInfo; - - VkPipelineMultisampleStateCreateInfo multisampleStateCreateInfo; - - VkPipelineDepthStencilStateCreateInfo depthStencilStateCreateInfo; - VkStencilOpState frontStencilState; - VkStencilOpState backStencilState; - - VkPipelineColorBlendStateCreateInfo colorBlendStateCreateInfo; - VkPipelineColorBlendAttachmentState *colorBlendAttachmentStates = SDL_stack_alloc( - VkPipelineColorBlendAttachmentState, - createinfo->target_info.num_color_targets); - - static const VkDynamicState dynamicStates[] = { - VK_DYNAMIC_STATE_VIEWPORT, - VK_DYNAMIC_STATE_SCISSOR, - VK_DYNAMIC_STATE_BLEND_CONSTANTS, - VK_DYNAMIC_STATE_STENCIL_REFERENCE - }; - VkPipelineDynamicStateCreateInfo dynamicStateCreateInfo; - - VulkanRenderer *renderer = (VulkanRenderer *)driverData; - - // Create a "compatible" render pass - - VkRenderPass transientRenderPass = VULKAN_INTERNAL_CreateTransientRenderPass( - renderer, - createinfo->target_info, - SDLToVK_SampleCount[createinfo->multisample_state.sample_count]); - - // Dynamic state - - dynamicStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; - dynamicStateCreateInfo.pNext = NULL; - dynamicStateCreateInfo.flags = 0; - dynamicStateCreateInfo.dynamicStateCount = SDL_arraysize(dynamicStates); - dynamicStateCreateInfo.pDynamicStates = dynamicStates; - - // Shader stages - - graphicsPipeline->vertexShader = (VulkanShader *)createinfo->vertex_shader; - SDL_AtomicIncRef(&graphicsPipeline->vertexShader->referenceCount); - - shaderStageCreateInfos[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; - shaderStageCreateInfos[0].pNext = NULL; - shaderStageCreateInfos[0].flags = 0; - shaderStageCreateInfos[0].stage = VK_SHADER_STAGE_VERTEX_BIT; - shaderStageCreateInfos[0].module = graphicsPipeline->vertexShader->shaderModule; - shaderStageCreateInfos[0].pName = graphicsPipeline->vertexShader->entrypointName; - shaderStageCreateInfos[0].pSpecializationInfo = NULL; - - graphicsPipeline->fragmentShader = (VulkanShader *)createinfo->fragment_shader; - SDL_AtomicIncRef(&graphicsPipeline->fragmentShader->referenceCount); - - shaderStageCreateInfos[1].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; - shaderStageCreateInfos[1].pNext = NULL; - shaderStageCreateInfos[1].flags = 0; - shaderStageCreateInfos[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT; - shaderStageCreateInfos[1].module = graphicsPipeline->fragmentShader->shaderModule; - shaderStageCreateInfos[1].pName = graphicsPipeline->fragmentShader->entrypointName; - shaderStageCreateInfos[1].pSpecializationInfo = NULL; - - if (renderer->debugMode) { - if (graphicsPipeline->vertexShader->stage != SDL_GPU_SHADERSTAGE_VERTEX) { - SDL_assert_release(!"CreateGraphicsPipeline was passed a fragment shader for the vertex stage"); - } - if (graphicsPipeline->fragmentShader->stage != SDL_GPU_SHADERSTAGE_FRAGMENT) { - SDL_assert_release(!"CreateGraphicsPipeline was passed a vertex shader for the fragment stage"); - } - } - - // Vertex input - - for (i = 0; i < createinfo->vertex_input_state.num_vertex_buffers; i += 1) { - vertexInputBindingDescriptions[i].binding = createinfo->vertex_input_state.vertex_buffer_descriptions[i].slot; - vertexInputBindingDescriptions[i].inputRate = SDLToVK_VertexInputRate[createinfo->vertex_input_state.vertex_buffer_descriptions[i].input_rate]; - vertexInputBindingDescriptions[i].stride = createinfo->vertex_input_state.vertex_buffer_descriptions[i].pitch; - } - - for (i = 0; i < createinfo->vertex_input_state.num_vertex_attributes; i += 1) { - vertexInputAttributeDescriptions[i].binding = createinfo->vertex_input_state.vertex_attributes[i].buffer_slot; - vertexInputAttributeDescriptions[i].format = SDLToVK_VertexFormat[createinfo->vertex_input_state.vertex_attributes[i].format]; - vertexInputAttributeDescriptions[i].location = createinfo->vertex_input_state.vertex_attributes[i].location; - vertexInputAttributeDescriptions[i].offset = createinfo->vertex_input_state.vertex_attributes[i].offset; - } - - vertexInputStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; - vertexInputStateCreateInfo.pNext = NULL; - vertexInputStateCreateInfo.flags = 0; - vertexInputStateCreateInfo.vertexBindingDescriptionCount = createinfo->vertex_input_state.num_vertex_buffers; - vertexInputStateCreateInfo.pVertexBindingDescriptions = vertexInputBindingDescriptions; - vertexInputStateCreateInfo.vertexAttributeDescriptionCount = createinfo->vertex_input_state.num_vertex_attributes; - vertexInputStateCreateInfo.pVertexAttributeDescriptions = vertexInputAttributeDescriptions; - - // Topology - - inputAssemblyStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; - inputAssemblyStateCreateInfo.pNext = NULL; - inputAssemblyStateCreateInfo.flags = 0; - inputAssemblyStateCreateInfo.primitiveRestartEnable = VK_FALSE; - inputAssemblyStateCreateInfo.topology = SDLToVK_PrimitiveType[createinfo->primitive_type]; - - graphicsPipeline->primitiveType = createinfo->primitive_type; - - // Viewport - - // NOTE: viewport and scissor are dynamic, and must be set using the command buffer - - viewportStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; - viewportStateCreateInfo.pNext = NULL; - viewportStateCreateInfo.flags = 0; - viewportStateCreateInfo.viewportCount = 1; - viewportStateCreateInfo.pViewports = NULL; - viewportStateCreateInfo.scissorCount = 1; - viewportStateCreateInfo.pScissors = NULL; - - // Rasterization - - rasterizationStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; - rasterizationStateCreateInfo.pNext = NULL; - rasterizationStateCreateInfo.flags = 0; - rasterizationStateCreateInfo.depthClampEnable = !createinfo->rasterizer_state.enable_depth_clip; - rasterizationStateCreateInfo.rasterizerDiscardEnable = VK_FALSE; - rasterizationStateCreateInfo.polygonMode = SDLToVK_PolygonMode( - renderer, - createinfo->rasterizer_state.fill_mode); - rasterizationStateCreateInfo.cullMode = SDLToVK_CullMode[createinfo->rasterizer_state.cull_mode]; - rasterizationStateCreateInfo.frontFace = SDLToVK_FrontFace[createinfo->rasterizer_state.front_face]; - rasterizationStateCreateInfo.depthBiasEnable = - createinfo->rasterizer_state.enable_depth_bias; - rasterizationStateCreateInfo.depthBiasConstantFactor = - createinfo->rasterizer_state.depth_bias_constant_factor; - rasterizationStateCreateInfo.depthBiasClamp = - createinfo->rasterizer_state.depth_bias_clamp; - rasterizationStateCreateInfo.depthBiasSlopeFactor = - createinfo->rasterizer_state.depth_bias_slope_factor; - rasterizationStateCreateInfo.lineWidth = 1.0f; - - // Multisample - - Uint32 sampleMask = 0xFFFFFFFF; - - multisampleStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; - multisampleStateCreateInfo.pNext = NULL; - multisampleStateCreateInfo.flags = 0; - multisampleStateCreateInfo.rasterizationSamples = SDLToVK_SampleCount[createinfo->multisample_state.sample_count]; - multisampleStateCreateInfo.sampleShadingEnable = VK_FALSE; - multisampleStateCreateInfo.minSampleShading = 1.0f; - multisampleStateCreateInfo.pSampleMask = &sampleMask; - multisampleStateCreateInfo.alphaToCoverageEnable = VK_FALSE; - multisampleStateCreateInfo.alphaToOneEnable = VK_FALSE; - - // Depth Stencil State - - frontStencilState.failOp = SDLToVK_StencilOp[createinfo->depth_stencil_state.front_stencil_state.fail_op]; - frontStencilState.passOp = SDLToVK_StencilOp[createinfo->depth_stencil_state.front_stencil_state.pass_op]; - frontStencilState.depthFailOp = SDLToVK_StencilOp[createinfo->depth_stencil_state.front_stencil_state.depth_fail_op]; - frontStencilState.compareOp = SDLToVK_CompareOp[createinfo->depth_stencil_state.front_stencil_state.compare_op]; - frontStencilState.compareMask = - createinfo->depth_stencil_state.compare_mask; - frontStencilState.writeMask = - createinfo->depth_stencil_state.write_mask; - frontStencilState.reference = 0; - - backStencilState.failOp = SDLToVK_StencilOp[createinfo->depth_stencil_state.back_stencil_state.fail_op]; - backStencilState.passOp = SDLToVK_StencilOp[createinfo->depth_stencil_state.back_stencil_state.pass_op]; - backStencilState.depthFailOp = SDLToVK_StencilOp[createinfo->depth_stencil_state.back_stencil_state.depth_fail_op]; - backStencilState.compareOp = SDLToVK_CompareOp[createinfo->depth_stencil_state.back_stencil_state.compare_op]; - backStencilState.compareMask = - createinfo->depth_stencil_state.compare_mask; - backStencilState.writeMask = - createinfo->depth_stencil_state.write_mask; - backStencilState.reference = 0; - - depthStencilStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; - depthStencilStateCreateInfo.pNext = NULL; - depthStencilStateCreateInfo.flags = 0; - depthStencilStateCreateInfo.depthTestEnable = - createinfo->depth_stencil_state.enable_depth_test; - depthStencilStateCreateInfo.depthWriteEnable = - createinfo->depth_stencil_state.enable_depth_write; - depthStencilStateCreateInfo.depthCompareOp = SDLToVK_CompareOp[createinfo->depth_stencil_state.compare_op]; - depthStencilStateCreateInfo.depthBoundsTestEnable = VK_FALSE; - depthStencilStateCreateInfo.stencilTestEnable = - createinfo->depth_stencil_state.enable_stencil_test; - depthStencilStateCreateInfo.front = frontStencilState; - depthStencilStateCreateInfo.back = backStencilState; - depthStencilStateCreateInfo.minDepthBounds = 0; // unused - depthStencilStateCreateInfo.maxDepthBounds = 0; // unused - - // Color Blend - - for (i = 0; i < createinfo->target_info.num_color_targets; i += 1) { - SDL_GPUColorTargetBlendState blendState = createinfo->target_info.color_target_descriptions[i].blend_state; - SDL_GPUColorComponentFlags colorWriteMask = blendState.enable_color_write_mask ? - blendState.color_write_mask : - 0xF; - - colorBlendAttachmentStates[i].blendEnable = - blendState.enable_blend; - colorBlendAttachmentStates[i].srcColorBlendFactor = SDLToVK_BlendFactor[blendState.src_color_blendfactor]; - colorBlendAttachmentStates[i].dstColorBlendFactor = SDLToVK_BlendFactor[blendState.dst_color_blendfactor]; - colorBlendAttachmentStates[i].colorBlendOp = SDLToVK_BlendOp[blendState.color_blend_op]; - colorBlendAttachmentStates[i].srcAlphaBlendFactor = SDLToVK_BlendFactor[blendState.src_alpha_blendfactor]; - colorBlendAttachmentStates[i].dstAlphaBlendFactor = SDLToVK_BlendFactor[blendState.dst_alpha_blendfactor]; - colorBlendAttachmentStates[i].alphaBlendOp = SDLToVK_BlendOp[blendState.alpha_blend_op]; - colorBlendAttachmentStates[i].colorWriteMask = - colorWriteMask; - } - - colorBlendStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; - colorBlendStateCreateInfo.pNext = NULL; - colorBlendStateCreateInfo.flags = 0; - colorBlendStateCreateInfo.attachmentCount = - createinfo->target_info.num_color_targets; - colorBlendStateCreateInfo.pAttachments = - colorBlendAttachmentStates; - colorBlendStateCreateInfo.blendConstants[0] = 1.0f; - colorBlendStateCreateInfo.blendConstants[1] = 1.0f; - colorBlendStateCreateInfo.blendConstants[2] = 1.0f; - colorBlendStateCreateInfo.blendConstants[3] = 1.0f; - - // We don't support LogicOp, so this is easy. - colorBlendStateCreateInfo.logicOpEnable = VK_FALSE; - colorBlendStateCreateInfo.logicOp = 0; - - // Pipeline Layout - - graphicsPipeline->resourceLayout = - VULKAN_INTERNAL_FetchGraphicsPipelineResourceLayout( - renderer, - graphicsPipeline->vertexShader, - graphicsPipeline->fragmentShader); - - if (graphicsPipeline->resourceLayout == NULL) { - SDL_stack_free(vertexInputBindingDescriptions); - SDL_stack_free(vertexInputAttributeDescriptions); - SDL_stack_free(colorBlendAttachmentStates); - SDL_free(graphicsPipeline); - SET_STRING_ERROR_AND_RETURN("Failed to initialize pipeline resource layout!", NULL); - } - - // Pipeline - - vkPipelineCreateInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; - vkPipelineCreateInfo.pNext = NULL; - vkPipelineCreateInfo.flags = 0; - vkPipelineCreateInfo.stageCount = 2; - vkPipelineCreateInfo.pStages = shaderStageCreateInfos; - vkPipelineCreateInfo.pVertexInputState = &vertexInputStateCreateInfo; - vkPipelineCreateInfo.pInputAssemblyState = &inputAssemblyStateCreateInfo; - vkPipelineCreateInfo.pTessellationState = VK_NULL_HANDLE; - vkPipelineCreateInfo.pViewportState = &viewportStateCreateInfo; - vkPipelineCreateInfo.pRasterizationState = &rasterizationStateCreateInfo; - vkPipelineCreateInfo.pMultisampleState = &multisampleStateCreateInfo; - vkPipelineCreateInfo.pDepthStencilState = &depthStencilStateCreateInfo; - vkPipelineCreateInfo.pColorBlendState = &colorBlendStateCreateInfo; - vkPipelineCreateInfo.pDynamicState = &dynamicStateCreateInfo; - vkPipelineCreateInfo.layout = graphicsPipeline->resourceLayout->pipelineLayout; - vkPipelineCreateInfo.renderPass = transientRenderPass; - vkPipelineCreateInfo.subpass = 0; - vkPipelineCreateInfo.basePipelineHandle = VK_NULL_HANDLE; - vkPipelineCreateInfo.basePipelineIndex = 0; - - // TODO: enable pipeline caching - vulkanResult = renderer->vkCreateGraphicsPipelines( - renderer->logicalDevice, - VK_NULL_HANDLE, - 1, - &vkPipelineCreateInfo, - NULL, - &graphicsPipeline->pipeline); - - SDL_stack_free(vertexInputBindingDescriptions); - SDL_stack_free(vertexInputAttributeDescriptions); - SDL_stack_free(colorBlendAttachmentStates); - - renderer->vkDestroyRenderPass( - renderer->logicalDevice, - transientRenderPass, - NULL); - - if (vulkanResult != VK_SUCCESS) { - SDL_free(graphicsPipeline); - CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkCreateGraphicsPipelines, NULL); - } - - SDL_SetAtomicInt(&graphicsPipeline->referenceCount, 0); - - if (renderer->debugMode && renderer->supportsDebugUtils && SDL_HasProperty(createinfo->props, SDL_PROP_GPU_GRAPHICSPIPELINE_CREATE_NAME_STRING)) { - VkDebugUtilsObjectNameInfoEXT nameInfo; - nameInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT; - nameInfo.pNext = NULL; - nameInfo.pObjectName = SDL_GetStringProperty(createinfo->props, SDL_PROP_GPU_GRAPHICSPIPELINE_CREATE_NAME_STRING, NULL); - nameInfo.objectType = VK_OBJECT_TYPE_PIPELINE; - nameInfo.objectHandle = (uint64_t)graphicsPipeline->pipeline; - - renderer->vkSetDebugUtilsObjectNameEXT( - renderer->logicalDevice, - &nameInfo); - } - - return (SDL_GPUGraphicsPipeline *)graphicsPipeline; -} - -static SDL_GPUComputePipeline *VULKAN_CreateComputePipeline( - SDL_GPURenderer *driverData, - const SDL_GPUComputePipelineCreateInfo *createinfo) -{ - VkShaderModuleCreateInfo shaderModuleCreateInfo; - VkComputePipelineCreateInfo vkShaderCreateInfo; - VkPipelineShaderStageCreateInfo pipelineShaderStageCreateInfo; - VkResult vulkanResult; - VulkanRenderer *renderer = (VulkanRenderer *)driverData; - VulkanComputePipeline *vulkanComputePipeline; - - if (createinfo->format != SDL_GPU_SHADERFORMAT_SPIRV) { - SET_STRING_ERROR_AND_RETURN("Incompatible shader format for Vulkan!", NULL); - } - - vulkanComputePipeline = SDL_malloc(sizeof(VulkanComputePipeline)); - shaderModuleCreateInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; - shaderModuleCreateInfo.pNext = NULL; - shaderModuleCreateInfo.flags = 0; - shaderModuleCreateInfo.codeSize = createinfo->code_size; - shaderModuleCreateInfo.pCode = (Uint32 *)createinfo->code; - - vulkanResult = renderer->vkCreateShaderModule( - renderer->logicalDevice, - &shaderModuleCreateInfo, - NULL, - &vulkanComputePipeline->shaderModule); - - if (vulkanResult != VK_SUCCESS) { - SDL_free(vulkanComputePipeline); - CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkCreateShaderModule, NULL); - } - - pipelineShaderStageCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; - pipelineShaderStageCreateInfo.pNext = NULL; - pipelineShaderStageCreateInfo.flags = 0; - pipelineShaderStageCreateInfo.stage = VK_SHADER_STAGE_COMPUTE_BIT; - pipelineShaderStageCreateInfo.module = vulkanComputePipeline->shaderModule; - pipelineShaderStageCreateInfo.pName = createinfo->entrypoint; - pipelineShaderStageCreateInfo.pSpecializationInfo = NULL; - - vulkanComputePipeline->resourceLayout = VULKAN_INTERNAL_FetchComputePipelineResourceLayout( - renderer, - createinfo); - - if (vulkanComputePipeline->resourceLayout == NULL) { - renderer->vkDestroyShaderModule( - renderer->logicalDevice, - vulkanComputePipeline->shaderModule, - NULL); - SDL_free(vulkanComputePipeline); - return NULL; - } - - vkShaderCreateInfo.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO; - vkShaderCreateInfo.pNext = NULL; - vkShaderCreateInfo.flags = 0; - vkShaderCreateInfo.stage = pipelineShaderStageCreateInfo; - vkShaderCreateInfo.layout = vulkanComputePipeline->resourceLayout->pipelineLayout; - vkShaderCreateInfo.basePipelineHandle = (VkPipeline)VK_NULL_HANDLE; - vkShaderCreateInfo.basePipelineIndex = 0; - - vulkanResult = renderer->vkCreateComputePipelines( - renderer->logicalDevice, - (VkPipelineCache)VK_NULL_HANDLE, - 1, - &vkShaderCreateInfo, - NULL, - &vulkanComputePipeline->pipeline); - - if (vulkanResult != VK_SUCCESS) { - VULKAN_INTERNAL_DestroyComputePipeline(renderer, vulkanComputePipeline); - CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkCreateComputePipeline, NULL); - return NULL; - } - - SDL_SetAtomicInt(&vulkanComputePipeline->referenceCount, 0); - - if (renderer->debugMode && renderer->supportsDebugUtils && SDL_HasProperty(createinfo->props, SDL_PROP_GPU_COMPUTEPIPELINE_CREATE_NAME_STRING)) { - VkDebugUtilsObjectNameInfoEXT nameInfo; - nameInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT; - nameInfo.pNext = NULL; - nameInfo.pObjectName = SDL_GetStringProperty(createinfo->props, SDL_PROP_GPU_COMPUTEPIPELINE_CREATE_NAME_STRING, NULL); - nameInfo.objectType = VK_OBJECT_TYPE_PIPELINE; - nameInfo.objectHandle = (uint64_t)vulkanComputePipeline->pipeline; - - renderer->vkSetDebugUtilsObjectNameEXT( - renderer->logicalDevice, - &nameInfo); - } - - return (SDL_GPUComputePipeline *)vulkanComputePipeline; -} - -static SDL_GPUSampler *VULKAN_CreateSampler( - SDL_GPURenderer *driverData, - const SDL_GPUSamplerCreateInfo *createinfo) -{ - VulkanRenderer *renderer = (VulkanRenderer *)driverData; - VulkanSampler *vulkanSampler = SDL_malloc(sizeof(VulkanSampler)); - VkResult vulkanResult; - - VkSamplerCreateInfo vkSamplerCreateInfo; - vkSamplerCreateInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; - vkSamplerCreateInfo.pNext = NULL; - vkSamplerCreateInfo.flags = 0; - vkSamplerCreateInfo.magFilter = SDLToVK_Filter[createinfo->mag_filter]; - vkSamplerCreateInfo.minFilter = SDLToVK_Filter[createinfo->min_filter]; - vkSamplerCreateInfo.mipmapMode = SDLToVK_SamplerMipmapMode[createinfo->mipmap_mode]; - vkSamplerCreateInfo.addressModeU = SDLToVK_SamplerAddressMode[createinfo->address_mode_u]; - vkSamplerCreateInfo.addressModeV = SDLToVK_SamplerAddressMode[createinfo->address_mode_v]; - vkSamplerCreateInfo.addressModeW = SDLToVK_SamplerAddressMode[createinfo->address_mode_w]; - vkSamplerCreateInfo.mipLodBias = createinfo->mip_lod_bias; - vkSamplerCreateInfo.anisotropyEnable = createinfo->enable_anisotropy; - vkSamplerCreateInfo.maxAnisotropy = createinfo->max_anisotropy; - vkSamplerCreateInfo.compareEnable = createinfo->enable_compare; - vkSamplerCreateInfo.compareOp = SDLToVK_CompareOp[createinfo->compare_op]; - vkSamplerCreateInfo.minLod = createinfo->min_lod; - vkSamplerCreateInfo.maxLod = createinfo->max_lod; - vkSamplerCreateInfo.borderColor = VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK; // arbitrary, unused - vkSamplerCreateInfo.unnormalizedCoordinates = VK_FALSE; - - vulkanResult = renderer->vkCreateSampler( - renderer->logicalDevice, - &vkSamplerCreateInfo, - NULL, - &vulkanSampler->sampler); - - if (vulkanResult != VK_SUCCESS) { - SDL_free(vulkanSampler); - CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkCreateSampler, NULL); - } - - SDL_SetAtomicInt(&vulkanSampler->referenceCount, 0); - - if (renderer->debugMode && renderer->supportsDebugUtils && SDL_HasProperty(createinfo->props, SDL_PROP_GPU_SAMPLER_CREATE_NAME_STRING)) { - VkDebugUtilsObjectNameInfoEXT nameInfo; - nameInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT; - nameInfo.pNext = NULL; - nameInfo.pObjectName = SDL_GetStringProperty(createinfo->props, SDL_PROP_GPU_SAMPLER_CREATE_NAME_STRING, NULL); - nameInfo.objectType = VK_OBJECT_TYPE_SAMPLER; - nameInfo.objectHandle = (uint64_t)vulkanSampler->sampler; - - renderer->vkSetDebugUtilsObjectNameEXT( - renderer->logicalDevice, - &nameInfo); - } - - return (SDL_GPUSampler *)vulkanSampler; -} - -static SDL_GPUShader *VULKAN_CreateShader( - SDL_GPURenderer *driverData, - const SDL_GPUShaderCreateInfo *createinfo) -{ - VulkanShader *vulkanShader; - VkResult vulkanResult; - VkShaderModuleCreateInfo vkShaderModuleCreateInfo; - VulkanRenderer *renderer = (VulkanRenderer *)driverData; - size_t entryPointNameLength; - - vulkanShader = SDL_malloc(sizeof(VulkanShader)); - vkShaderModuleCreateInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; - vkShaderModuleCreateInfo.pNext = NULL; - vkShaderModuleCreateInfo.flags = 0; - vkShaderModuleCreateInfo.codeSize = createinfo->code_size; - vkShaderModuleCreateInfo.pCode = (Uint32 *)createinfo->code; - - vulkanResult = renderer->vkCreateShaderModule( - renderer->logicalDevice, - &vkShaderModuleCreateInfo, - NULL, - &vulkanShader->shaderModule); - - if (vulkanResult != VK_SUCCESS) { - SDL_free(vulkanShader); - CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkCreateShaderModule, NULL); - } - - entryPointNameLength = SDL_strlen(createinfo->entrypoint) + 1; - vulkanShader->entrypointName = SDL_malloc(entryPointNameLength); - SDL_utf8strlcpy((char *)vulkanShader->entrypointName, createinfo->entrypoint, entryPointNameLength); - - vulkanShader->stage = createinfo->stage; - vulkanShader->numSamplers = createinfo->num_samplers; - vulkanShader->numStorageTextures = createinfo->num_storage_textures; - vulkanShader->numStorageBuffers = createinfo->num_storage_buffers; - vulkanShader->numUniformBuffers = createinfo->num_uniform_buffers; - - SDL_SetAtomicInt(&vulkanShader->referenceCount, 0); - - if (renderer->debugMode && SDL_HasProperty(createinfo->props, SDL_PROP_GPU_SHADER_CREATE_NAME_STRING)) { - VkDebugUtilsObjectNameInfoEXT nameInfo; - nameInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT; - nameInfo.pNext = NULL; - nameInfo.pObjectName = SDL_GetStringProperty(createinfo->props, SDL_PROP_GPU_SHADER_CREATE_NAME_STRING, NULL); - nameInfo.objectType = VK_OBJECT_TYPE_SHADER_MODULE; - nameInfo.objectHandle = (uint64_t)vulkanShader->shaderModule; - - renderer->vkSetDebugUtilsObjectNameEXT( - renderer->logicalDevice, - &nameInfo); - } - - return (SDL_GPUShader *)vulkanShader; -} - -static bool VULKAN_SupportsSampleCount( - SDL_GPURenderer *driverData, - SDL_GPUTextureFormat format, - SDL_GPUSampleCount sampleCount) -{ - VulkanRenderer *renderer = (VulkanRenderer *)driverData; - VkSampleCountFlags bits = IsDepthFormat(format) ? renderer->physicalDeviceProperties.properties.limits.framebufferDepthSampleCounts : renderer->physicalDeviceProperties.properties.limits.framebufferColorSampleCounts; - VkSampleCountFlagBits vkSampleCount = SDLToVK_SampleCount[sampleCount]; - return !!(bits & vkSampleCount); -} - -static SDL_GPUTexture *VULKAN_CreateTexture( - SDL_GPURenderer *driverData, - const SDL_GPUTextureCreateInfo *createinfo) -{ - VulkanRenderer *renderer = (VulkanRenderer *)driverData; - VulkanTexture *texture; - VulkanTextureContainer *container; - - texture = VULKAN_INTERNAL_CreateTexture( - renderer, - createinfo); - - if (texture == NULL) { - return NULL; - } - - container = SDL_malloc(sizeof(VulkanTextureContainer)); - - // Copy properties so we don't lose information when the client destroys them - container->header.info = *createinfo; - container->header.info.props = SDL_CreateProperties(); - SDL_CopyProperties(createinfo->props, container->header.info.props); - - container->canBeCycled = true; - container->activeTexture = texture; - container->textureCapacity = 1; - container->textureCount = 1; - container->textures = SDL_malloc( - container->textureCapacity * sizeof(VulkanTexture *)); - container->textures[0] = container->activeTexture; - container->debugName = NULL; - - if (SDL_HasProperty(createinfo->props, SDL_PROP_GPU_TEXTURE_CREATE_NAME_STRING)) { - container->debugName = SDL_strdup(SDL_GetStringProperty(createinfo->props, SDL_PROP_GPU_TEXTURE_CREATE_NAME_STRING, NULL)); - } - - texture->container = container; - texture->containerIndex = 0; - - return (SDL_GPUTexture *)container; -} - -static SDL_GPUBuffer *VULKAN_CreateBuffer( - SDL_GPURenderer *driverData, - SDL_GPUBufferUsageFlags usageFlags, - Uint32 size, - const char *debugName) -{ - return (SDL_GPUBuffer *)VULKAN_INTERNAL_CreateBufferContainer( - (VulkanRenderer *)driverData, - (VkDeviceSize)size, - usageFlags, - VULKAN_BUFFER_TYPE_GPU, - false, - debugName); -} - -static VulkanUniformBuffer *VULKAN_INTERNAL_CreateUniformBuffer( - VulkanRenderer *renderer, - Uint32 size) -{ - VulkanUniformBuffer *uniformBuffer = SDL_calloc(1, sizeof(VulkanUniformBuffer)); - - uniformBuffer->buffer = VULKAN_INTERNAL_CreateBuffer( - renderer, - (VkDeviceSize)size, - 0, - VULKAN_BUFFER_TYPE_UNIFORM, - false, - NULL); - - uniformBuffer->drawOffset = 0; - uniformBuffer->writeOffset = 0; - uniformBuffer->buffer->uniformBufferForDefrag = uniformBuffer; - - return uniformBuffer; -} - -static SDL_GPUTransferBuffer *VULKAN_CreateTransferBuffer( - SDL_GPURenderer *driverData, - SDL_GPUTransferBufferUsage usage, - Uint32 size, - const char *debugName) -{ - return (SDL_GPUTransferBuffer *)VULKAN_INTERNAL_CreateBufferContainer( - (VulkanRenderer *)driverData, - (VkDeviceSize)size, - 0, - VULKAN_BUFFER_TYPE_TRANSFER, - true, // Dedicated allocations preserve the data even if a defrag is triggered. - debugName); -} - -static void VULKAN_INTERNAL_ReleaseTexture( - VulkanRenderer *renderer, - VulkanTexture *vulkanTexture) -{ - if (vulkanTexture->markedForDestroy) { - return; - } - - SDL_LockMutex(renderer->disposeLock); - - EXPAND_ARRAY_IF_NEEDED( - renderer->texturesToDestroy, - VulkanTexture *, - renderer->texturesToDestroyCount + 1, - renderer->texturesToDestroyCapacity, - renderer->texturesToDestroyCapacity * 2); - - renderer->texturesToDestroy[renderer->texturesToDestroyCount] = vulkanTexture; - renderer->texturesToDestroyCount += 1; - - vulkanTexture->markedForDestroy = true; - - SDL_UnlockMutex(renderer->disposeLock); -} - -static void VULKAN_ReleaseTexture( - SDL_GPURenderer *driverData, - SDL_GPUTexture *texture) -{ - VulkanRenderer *renderer = (VulkanRenderer *)driverData; - VulkanTextureContainer *vulkanTextureContainer = (VulkanTextureContainer *)texture; - Uint32 i; - - SDL_LockMutex(renderer->disposeLock); - - for (i = 0; i < vulkanTextureContainer->textureCount; i += 1) { - VULKAN_INTERNAL_ReleaseTexture(renderer, vulkanTextureContainer->textures[i]); - } - - // Containers are just client handles, so we can destroy immediately - if (vulkanTextureContainer->debugName != NULL) { - SDL_free(vulkanTextureContainer->debugName); - } - SDL_free(vulkanTextureContainer->textures); - SDL_free(vulkanTextureContainer); - - SDL_UnlockMutex(renderer->disposeLock); -} - -static void VULKAN_ReleaseSampler( - SDL_GPURenderer *driverData, - SDL_GPUSampler *sampler) -{ - VulkanRenderer *renderer = (VulkanRenderer *)driverData; - VulkanSampler *vulkanSampler = (VulkanSampler *)sampler; - - SDL_LockMutex(renderer->disposeLock); - - EXPAND_ARRAY_IF_NEEDED( - renderer->samplersToDestroy, - VulkanSampler *, - renderer->samplersToDestroyCount + 1, - renderer->samplersToDestroyCapacity, - renderer->samplersToDestroyCapacity * 2); - - renderer->samplersToDestroy[renderer->samplersToDestroyCount] = vulkanSampler; - renderer->samplersToDestroyCount += 1; - - SDL_UnlockMutex(renderer->disposeLock); -} - -static void VULKAN_INTERNAL_ReleaseBuffer( - VulkanRenderer *renderer, - VulkanBuffer *vulkanBuffer) -{ - if (vulkanBuffer->markedForDestroy) { - return; - } - - SDL_LockMutex(renderer->disposeLock); - - EXPAND_ARRAY_IF_NEEDED( - renderer->buffersToDestroy, - VulkanBuffer *, - renderer->buffersToDestroyCount + 1, - renderer->buffersToDestroyCapacity, - renderer->buffersToDestroyCapacity * 2); - - renderer->buffersToDestroy[renderer->buffersToDestroyCount] = vulkanBuffer; - renderer->buffersToDestroyCount += 1; - - vulkanBuffer->markedForDestroy = 1; - vulkanBuffer->container = NULL; - - SDL_UnlockMutex(renderer->disposeLock); -} - -static void VULKAN_INTERNAL_ReleaseBufferContainer( - VulkanRenderer *renderer, - VulkanBufferContainer *bufferContainer) -{ - Uint32 i; - - SDL_LockMutex(renderer->disposeLock); - - for (i = 0; i < bufferContainer->bufferCount; i += 1) { - VULKAN_INTERNAL_ReleaseBuffer(renderer, bufferContainer->buffers[i]); - } - - // Containers are just client handles, so we can free immediately - if (bufferContainer->debugName != NULL) { - SDL_free(bufferContainer->debugName); - bufferContainer->debugName = NULL; - } - SDL_free(bufferContainer->buffers); - SDL_free(bufferContainer); - - SDL_UnlockMutex(renderer->disposeLock); -} - -static void VULKAN_ReleaseBuffer( - SDL_GPURenderer *driverData, - SDL_GPUBuffer *buffer) -{ - VulkanRenderer *renderer = (VulkanRenderer *)driverData; - VulkanBufferContainer *vulkanBufferContainer = (VulkanBufferContainer *)buffer; - - VULKAN_INTERNAL_ReleaseBufferContainer( - renderer, - vulkanBufferContainer); -} - -static void VULKAN_ReleaseTransferBuffer( - SDL_GPURenderer *driverData, - SDL_GPUTransferBuffer *transferBuffer) -{ - VulkanRenderer *renderer = (VulkanRenderer *)driverData; - VulkanBufferContainer *transferBufferContainer = (VulkanBufferContainer *)transferBuffer; - - VULKAN_INTERNAL_ReleaseBufferContainer( - renderer, - transferBufferContainer); -} - -static void VULKAN_ReleaseShader( - SDL_GPURenderer *driverData, - SDL_GPUShader *shader) -{ - VulkanRenderer *renderer = (VulkanRenderer *)driverData; - VulkanShader *vulkanShader = (VulkanShader *)shader; - - SDL_LockMutex(renderer->disposeLock); - - EXPAND_ARRAY_IF_NEEDED( - renderer->shadersToDestroy, - VulkanShader *, - renderer->shadersToDestroyCount + 1, - renderer->shadersToDestroyCapacity, - renderer->shadersToDestroyCapacity * 2); - - renderer->shadersToDestroy[renderer->shadersToDestroyCount] = vulkanShader; - renderer->shadersToDestroyCount += 1; - - SDL_UnlockMutex(renderer->disposeLock); -} - -static void VULKAN_ReleaseComputePipeline( - SDL_GPURenderer *driverData, - SDL_GPUComputePipeline *computePipeline) -{ - VulkanRenderer *renderer = (VulkanRenderer *)driverData; - VulkanComputePipeline *vulkanComputePipeline = (VulkanComputePipeline *)computePipeline; - - SDL_LockMutex(renderer->disposeLock); - - EXPAND_ARRAY_IF_NEEDED( - renderer->computePipelinesToDestroy, - VulkanComputePipeline *, - renderer->computePipelinesToDestroyCount + 1, - renderer->computePipelinesToDestroyCapacity, - renderer->computePipelinesToDestroyCapacity * 2); - - renderer->computePipelinesToDestroy[renderer->computePipelinesToDestroyCount] = vulkanComputePipeline; - renderer->computePipelinesToDestroyCount += 1; - - SDL_UnlockMutex(renderer->disposeLock); -} - -static void VULKAN_ReleaseGraphicsPipeline( - SDL_GPURenderer *driverData, - SDL_GPUGraphicsPipeline *graphicsPipeline) -{ - VulkanRenderer *renderer = (VulkanRenderer *)driverData; - VulkanGraphicsPipeline *vulkanGraphicsPipeline = (VulkanGraphicsPipeline *)graphicsPipeline; - - SDL_LockMutex(renderer->disposeLock); - - EXPAND_ARRAY_IF_NEEDED( - renderer->graphicsPipelinesToDestroy, - VulkanGraphicsPipeline *, - renderer->graphicsPipelinesToDestroyCount + 1, - renderer->graphicsPipelinesToDestroyCapacity, - renderer->graphicsPipelinesToDestroyCapacity * 2); - - renderer->graphicsPipelinesToDestroy[renderer->graphicsPipelinesToDestroyCount] = vulkanGraphicsPipeline; - renderer->graphicsPipelinesToDestroyCount += 1; - - SDL_UnlockMutex(renderer->disposeLock); -} - -// Command Buffer render state - -static VkRenderPass VULKAN_INTERNAL_FetchRenderPass( - VulkanRenderer *renderer, - VulkanCommandBuffer *commandBuffer, - const SDL_GPUColorTargetInfo *colorTargetInfos, - Uint32 numColorTargets, - const SDL_GPUDepthStencilTargetInfo *depthStencilTargetInfo) -{ - VulkanRenderPassHashTableValue *renderPassWrapper = NULL; - VkRenderPass renderPassHandle; - RenderPassHashTableKey key; - Uint32 i; - - SDL_zero(key); - - for (i = 0; i < numColorTargets; i += 1) { - key.colorTargetDescriptions[i].format = SDLToVK_TextureFormat[((VulkanTextureContainer *)colorTargetInfos[i].texture)->header.info.format]; - key.colorTargetDescriptions[i].loadOp = colorTargetInfos[i].load_op; - key.colorTargetDescriptions[i].storeOp = colorTargetInfos[i].store_op; - - if (colorTargetInfos[i].resolve_texture != NULL) { - key.resolveTargetFormats[key.numResolveTargets] = SDLToVK_TextureFormat[((VulkanTextureContainer *)colorTargetInfos[i].resolve_texture)->header.info.format]; - key.numResolveTargets += 1; - } - } - - key.sampleCount = VK_SAMPLE_COUNT_1_BIT; - if (numColorTargets > 0) { - key.sampleCount = SDLToVK_SampleCount[((VulkanTextureContainer *)colorTargetInfos[0].texture)->header.info.sample_count]; - } - - key.numColorTargets = numColorTargets; - - if (depthStencilTargetInfo == NULL) { - key.depthStencilTargetDescription.format = 0; - key.depthStencilTargetDescription.loadOp = SDL_GPU_LOADOP_DONT_CARE; - key.depthStencilTargetDescription.storeOp = SDL_GPU_STOREOP_DONT_CARE; - key.depthStencilTargetDescription.stencilLoadOp = SDL_GPU_LOADOP_DONT_CARE; - key.depthStencilTargetDescription.stencilStoreOp = SDL_GPU_STOREOP_DONT_CARE; - } else { - key.depthStencilTargetDescription.format = SDLToVK_TextureFormat[((VulkanTextureContainer *)depthStencilTargetInfo->texture)->header.info.format]; - key.depthStencilTargetDescription.loadOp = depthStencilTargetInfo->load_op; - key.depthStencilTargetDescription.storeOp = depthStencilTargetInfo->store_op; - key.depthStencilTargetDescription.stencilLoadOp = depthStencilTargetInfo->stencil_load_op; - key.depthStencilTargetDescription.stencilStoreOp = depthStencilTargetInfo->stencil_store_op; - } - - bool result = SDL_FindInHashTable( - renderer->renderPassHashTable, - (const void *)&key, - (const void **)&renderPassWrapper); - - if (result) { - return renderPassWrapper->handle; - } - - renderPassHandle = VULKAN_INTERNAL_CreateRenderPass( - renderer, - commandBuffer, - colorTargetInfos, - numColorTargets, - depthStencilTargetInfo); - - if (renderPassHandle == VK_NULL_HANDLE) { - return VK_NULL_HANDLE; - } - - // Have to malloc the key to store it in the hashtable - RenderPassHashTableKey *allocedKey = SDL_malloc(sizeof(RenderPassHashTableKey)); - SDL_memcpy(allocedKey, &key, sizeof(RenderPassHashTableKey)); - - renderPassWrapper = SDL_malloc(sizeof(VulkanRenderPassHashTableValue)); - renderPassWrapper->handle = renderPassHandle; - - SDL_InsertIntoHashTable( - renderer->renderPassHashTable, - (const void *)allocedKey, - (const void *)renderPassWrapper, true); - - return renderPassHandle; -} - -static VulkanFramebuffer *VULKAN_INTERNAL_FetchFramebuffer( - VulkanRenderer *renderer, - VkRenderPass renderPass, - const SDL_GPUColorTargetInfo *colorTargetInfos, - Uint32 numColorTargets, - const SDL_GPUDepthStencilTargetInfo *depthStencilTargetInfo, - Uint32 width, - Uint32 height) -{ - VulkanFramebuffer *vulkanFramebuffer = NULL; - VkFramebufferCreateInfo framebufferInfo; - VkResult result; - VkImageView imageViewAttachments[2 * MAX_COLOR_TARGET_BINDINGS + 1 /* depth */]; - FramebufferHashTableKey key; - Uint32 attachmentCount = 0; - Uint32 i; - - SDL_zero(imageViewAttachments); - SDL_zero(key); - - key.numColorTargets = numColorTargets; - - for (i = 0; i < numColorTargets; i += 1) { - VulkanTextureContainer *container = (VulkanTextureContainer *)colorTargetInfos[i].texture; - VulkanTextureSubresource *subresource = VULKAN_INTERNAL_FetchTextureSubresource( - container, - container->header.info.type == SDL_GPU_TEXTURETYPE_3D ? 0 : colorTargetInfos[i].layer_or_depth_plane, - colorTargetInfos[i].mip_level); - - Uint32 rtvIndex = - container->header.info.type == SDL_GPU_TEXTURETYPE_3D ? colorTargetInfos[i].layer_or_depth_plane : 0; - key.colorAttachmentViews[i] = subresource->renderTargetViews[rtvIndex]; - - if (colorTargetInfos[i].resolve_texture != NULL) { - VulkanTextureContainer *resolveTextureContainer = (VulkanTextureContainer *)colorTargetInfos[i].resolve_texture; - VulkanTextureSubresource *resolveSubresource = VULKAN_INTERNAL_FetchTextureSubresource( - resolveTextureContainer, - colorTargetInfos[i].layer_or_depth_plane, - colorTargetInfos[i].mip_level); - - key.resolveAttachmentViews[key.numResolveAttachments] = resolveSubresource->renderTargetViews[0]; - key.numResolveAttachments += 1; - } - } - - if (depthStencilTargetInfo == NULL) { - key.depthStencilAttachmentView = VK_NULL_HANDLE; - } else { - VulkanTextureSubresource *subresource = VULKAN_INTERNAL_FetchTextureSubresource( - (VulkanTextureContainer *)depthStencilTargetInfo->texture, - 0, - 0); - key.depthStencilAttachmentView = subresource->depthStencilView; - } - - key.width = width; - key.height = height; - - SDL_LockMutex(renderer->framebufferFetchLock); - - bool findResult = SDL_FindInHashTable( - renderer->framebufferHashTable, - (const void *)&key, - (const void **)&vulkanFramebuffer); - - SDL_UnlockMutex(renderer->framebufferFetchLock); - - if (findResult) { - return vulkanFramebuffer; - } - - vulkanFramebuffer = SDL_malloc(sizeof(VulkanFramebuffer)); - - SDL_SetAtomicInt(&vulkanFramebuffer->referenceCount, 0); - - // Create a new framebuffer - - for (i = 0; i < numColorTargets; i += 1) { - VulkanTextureContainer *container = (VulkanTextureContainer *)colorTargetInfos[i].texture; - VulkanTextureSubresource *subresource = VULKAN_INTERNAL_FetchTextureSubresource( - container, - container->header.info.type == SDL_GPU_TEXTURETYPE_3D ? 0 : colorTargetInfos[i].layer_or_depth_plane, - colorTargetInfos[i].mip_level); - - Uint32 rtvIndex = - container->header.info.type == SDL_GPU_TEXTURETYPE_3D ? colorTargetInfos[i].layer_or_depth_plane : 0; - - imageViewAttachments[attachmentCount] = subresource->renderTargetViews[rtvIndex]; - - attachmentCount += 1; - - if (colorTargetInfos[i].store_op == SDL_GPU_STOREOP_RESOLVE || colorTargetInfos[i].store_op == SDL_GPU_STOREOP_RESOLVE_AND_STORE) { - VulkanTextureContainer *resolveContainer = (VulkanTextureContainer *)colorTargetInfos[i].resolve_texture; - VulkanTextureSubresource *resolveSubresource = VULKAN_INTERNAL_FetchTextureSubresource( - resolveContainer, - colorTargetInfos[i].resolve_layer, - colorTargetInfos[i].resolve_mip_level); - - imageViewAttachments[attachmentCount] = resolveSubresource->renderTargetViews[0]; - - attachmentCount += 1; - } - } - - if (depthStencilTargetInfo != NULL) { - VulkanTextureSubresource *subresource = VULKAN_INTERNAL_FetchTextureSubresource( - (VulkanTextureContainer *)depthStencilTargetInfo->texture, - 0, - 0); - imageViewAttachments[attachmentCount] = subresource->depthStencilView; - - 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 = key.width; - framebufferInfo.height = key.height; - framebufferInfo.layers = 1; - - result = renderer->vkCreateFramebuffer( - renderer->logicalDevice, - &framebufferInfo, - NULL, - &vulkanFramebuffer->framebuffer); - - if (result == VK_SUCCESS) { - // Have to malloc the key to store it in the hashtable - FramebufferHashTableKey *allocedKey = SDL_malloc(sizeof(FramebufferHashTableKey)); - SDL_memcpy(allocedKey, &key, sizeof(FramebufferHashTableKey)); - - SDL_LockMutex(renderer->framebufferFetchLock); - - SDL_InsertIntoHashTable( - renderer->framebufferHashTable, - (const void *)allocedKey, - (const void *)vulkanFramebuffer, true); - - SDL_UnlockMutex(renderer->framebufferFetchLock); - } else { - SDL_free(vulkanFramebuffer); - CHECK_VULKAN_ERROR_AND_RETURN(result, vkCreateFramebuffer, NULL); - } - - return vulkanFramebuffer; -} - -static void VULKAN_INTERNAL_SetCurrentViewport( - VulkanCommandBuffer *commandBuffer, - const SDL_GPUViewport *viewport) -{ - VulkanCommandBuffer *vulkanCommandBuffer = commandBuffer; - VulkanRenderer *renderer = vulkanCommandBuffer->renderer; - - vulkanCommandBuffer->currentViewport.x = viewport->x; - vulkanCommandBuffer->currentViewport.width = viewport->w; - vulkanCommandBuffer->currentViewport.minDepth = viewport->min_depth; - vulkanCommandBuffer->currentViewport.maxDepth = viewport->max_depth; - - // Viewport flip for consistency with other backends - vulkanCommandBuffer->currentViewport.y = viewport->y + viewport->h; - vulkanCommandBuffer->currentViewport.height = -viewport->h; - - renderer->vkCmdSetViewport( - vulkanCommandBuffer->commandBuffer, - 0, - 1, - &vulkanCommandBuffer->currentViewport); -} - -static void VULKAN_SetViewport( - SDL_GPUCommandBuffer *commandBuffer, - const SDL_GPUViewport *viewport) -{ - VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; - - VULKAN_INTERNAL_SetCurrentViewport( - vulkanCommandBuffer, - viewport); -} - -static void VULKAN_INTERNAL_SetCurrentScissor( - VulkanCommandBuffer *vulkanCommandBuffer, - const SDL_Rect *scissor) -{ - VulkanRenderer *renderer = vulkanCommandBuffer->renderer; - - vulkanCommandBuffer->currentScissor.offset.x = scissor->x; - vulkanCommandBuffer->currentScissor.offset.y = scissor->y; - vulkanCommandBuffer->currentScissor.extent.width = scissor->w; - vulkanCommandBuffer->currentScissor.extent.height = scissor->h; - - renderer->vkCmdSetScissor( - vulkanCommandBuffer->commandBuffer, - 0, - 1, - &vulkanCommandBuffer->currentScissor); -} - -static void VULKAN_SetScissor( - SDL_GPUCommandBuffer *commandBuffer, - const SDL_Rect *scissor) -{ - VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; - - VULKAN_INTERNAL_SetCurrentScissor( - vulkanCommandBuffer, - scissor); -} - -static void VULKAN_INTERNAL_SetCurrentBlendConstants( - VulkanCommandBuffer *vulkanCommandBuffer, - SDL_FColor blendConstants) -{ - VulkanRenderer *renderer = vulkanCommandBuffer->renderer; - - vulkanCommandBuffer->blendConstants[0] = blendConstants.r; - vulkanCommandBuffer->blendConstants[1] = blendConstants.g; - vulkanCommandBuffer->blendConstants[2] = blendConstants.b; - vulkanCommandBuffer->blendConstants[3] = blendConstants.a; - - renderer->vkCmdSetBlendConstants( - vulkanCommandBuffer->commandBuffer, - vulkanCommandBuffer->blendConstants); -} - -static void VULKAN_SetBlendConstants( - SDL_GPUCommandBuffer *commandBuffer, - SDL_FColor blendConstants) -{ - VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; - - VULKAN_INTERNAL_SetCurrentBlendConstants( - vulkanCommandBuffer, - blendConstants); -} - -static void VULKAN_INTERNAL_SetCurrentStencilReference( - VulkanCommandBuffer *vulkanCommandBuffer, - Uint8 reference) -{ - VulkanRenderer *renderer = vulkanCommandBuffer->renderer; - - vulkanCommandBuffer->stencilRef = reference; - - renderer->vkCmdSetStencilReference( - vulkanCommandBuffer->commandBuffer, - VK_STENCIL_FACE_FRONT_AND_BACK, - vulkanCommandBuffer->stencilRef); -} - -static void VULKAN_SetStencilReference( - SDL_GPUCommandBuffer *commandBuffer, - Uint8 reference) -{ - VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; - - VULKAN_INTERNAL_SetCurrentStencilReference( - vulkanCommandBuffer, - reference); -} - -static void VULKAN_BindVertexSamplers( - SDL_GPUCommandBuffer *commandBuffer, - Uint32 firstSlot, - const SDL_GPUTextureSamplerBinding *textureSamplerBindings, - Uint32 numBindings) -{ - VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; - - for (Uint32 i = 0; i < numBindings; i += 1) { - VulkanTextureContainer *textureContainer = (VulkanTextureContainer *)textureSamplerBindings[i].texture; - VulkanSampler *sampler = (VulkanSampler *)textureSamplerBindings[i].sampler; - - if (vulkanCommandBuffer->vertexSamplers[firstSlot + i] != sampler) { - VULKAN_INTERNAL_TrackSampler( - vulkanCommandBuffer, - (VulkanSampler *)textureSamplerBindings[i].sampler); - - vulkanCommandBuffer->vertexSamplers[firstSlot + i] = (VulkanSampler *)textureSamplerBindings[i].sampler; - vulkanCommandBuffer->needNewVertexResourceDescriptorSet = true; - } - - if (vulkanCommandBuffer->vertexSamplerTextures[firstSlot + i] != textureContainer->activeTexture) { - VULKAN_INTERNAL_TrackTexture( - vulkanCommandBuffer, - textureContainer->activeTexture); - - vulkanCommandBuffer->vertexSamplerTextures[firstSlot + i] = textureContainer->activeTexture; - vulkanCommandBuffer->needNewVertexResourceDescriptorSet = true; - } - } -} - -static void VULKAN_BindVertexStorageTextures( - SDL_GPUCommandBuffer *commandBuffer, - Uint32 firstSlot, - SDL_GPUTexture *const *storageTextures, - Uint32 numBindings) -{ - VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; - - for (Uint32 i = 0; i < numBindings; i += 1) { - VulkanTextureContainer *textureContainer = (VulkanTextureContainer *)storageTextures[i]; - - if (vulkanCommandBuffer->vertexStorageTextures[firstSlot + i] != textureContainer->activeTexture) { - VULKAN_INTERNAL_TrackTexture( - vulkanCommandBuffer, - textureContainer->activeTexture); - - vulkanCommandBuffer->vertexStorageTextures[firstSlot + i] = textureContainer->activeTexture; - vulkanCommandBuffer->needNewVertexResourceDescriptorSet = true; - } - } -} - -static void VULKAN_BindVertexStorageBuffers( - SDL_GPUCommandBuffer *commandBuffer, - Uint32 firstSlot, - SDL_GPUBuffer *const *storageBuffers, - Uint32 numBindings) -{ - VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; - - for (Uint32 i = 0; i < numBindings; i += 1) { - VulkanBufferContainer *bufferContainer = (VulkanBufferContainer *)storageBuffers[i]; - - if (vulkanCommandBuffer->vertexStorageBuffers[firstSlot + i] != bufferContainer->activeBuffer) { - VULKAN_INTERNAL_TrackBuffer( - vulkanCommandBuffer, - bufferContainer->activeBuffer); - - vulkanCommandBuffer->vertexStorageBuffers[firstSlot + i] = bufferContainer->activeBuffer; - vulkanCommandBuffer->needNewVertexResourceDescriptorSet = true; - } - } -} - -static void VULKAN_BindFragmentSamplers( - SDL_GPUCommandBuffer *commandBuffer, - Uint32 firstSlot, - const SDL_GPUTextureSamplerBinding *textureSamplerBindings, - Uint32 numBindings) -{ - VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; - - for (Uint32 i = 0; i < numBindings; i += 1) { - VulkanTextureContainer *textureContainer = (VulkanTextureContainer *)textureSamplerBindings[i].texture; - VulkanSampler *sampler = (VulkanSampler *)textureSamplerBindings[i].sampler; - - if (vulkanCommandBuffer->fragmentSamplers[firstSlot + i] != sampler) { - VULKAN_INTERNAL_TrackSampler( - vulkanCommandBuffer, - (VulkanSampler *)textureSamplerBindings[i].sampler); - - vulkanCommandBuffer->fragmentSamplers[firstSlot + i] = (VulkanSampler *)textureSamplerBindings[i].sampler; - vulkanCommandBuffer->needNewFragmentResourceDescriptorSet = true; - } - - if (vulkanCommandBuffer->fragmentSamplerTextures[firstSlot + i] != textureContainer->activeTexture) { - VULKAN_INTERNAL_TrackTexture( - vulkanCommandBuffer, - textureContainer->activeTexture); - - vulkanCommandBuffer->fragmentSamplerTextures[firstSlot + i] = textureContainer->activeTexture; - vulkanCommandBuffer->needNewFragmentResourceDescriptorSet = true; - } - } -} - -static void VULKAN_BindFragmentStorageTextures( - SDL_GPUCommandBuffer *commandBuffer, - Uint32 firstSlot, - SDL_GPUTexture *const *storageTextures, - Uint32 numBindings) -{ - VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; - - for (Uint32 i = 0; i < numBindings; i += 1) { - VulkanTextureContainer *textureContainer = (VulkanTextureContainer *)storageTextures[i]; - - if (vulkanCommandBuffer->fragmentStorageTextures[firstSlot + i] != textureContainer->activeTexture) { - VULKAN_INTERNAL_TrackTexture( - vulkanCommandBuffer, - textureContainer->activeTexture); - - vulkanCommandBuffer->fragmentStorageTextures[firstSlot + i] = textureContainer->activeTexture; - vulkanCommandBuffer->needNewFragmentResourceDescriptorSet = true; - } - } -} - -static void VULKAN_BindFragmentStorageBuffers( - SDL_GPUCommandBuffer *commandBuffer, - Uint32 firstSlot, - SDL_GPUBuffer *const *storageBuffers, - Uint32 numBindings) -{ - VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; - VulkanBufferContainer *bufferContainer; - Uint32 i; - - for (i = 0; i < numBindings; i += 1) { - bufferContainer = (VulkanBufferContainer *)storageBuffers[i]; - - if (vulkanCommandBuffer->fragmentStorageBuffers[firstSlot + i] != bufferContainer->activeBuffer) { - VULKAN_INTERNAL_TrackBuffer( - vulkanCommandBuffer, - bufferContainer->activeBuffer); - - vulkanCommandBuffer->fragmentStorageBuffers[firstSlot + i] = bufferContainer->activeBuffer; - vulkanCommandBuffer->needNewFragmentResourceDescriptorSet = true; - } - } -} - -static VulkanUniformBuffer *VULKAN_INTERNAL_AcquireUniformBufferFromPool( - VulkanCommandBuffer *commandBuffer) -{ - VulkanRenderer *renderer = commandBuffer->renderer; - VulkanUniformBuffer *uniformBuffer; - - SDL_LockMutex(renderer->acquireUniformBufferLock); - - if (renderer->uniformBufferPoolCount > 0) { - uniformBuffer = renderer->uniformBufferPool[renderer->uniformBufferPoolCount - 1]; - renderer->uniformBufferPoolCount -= 1; - } else { - uniformBuffer = VULKAN_INTERNAL_CreateUniformBuffer( - renderer, - UNIFORM_BUFFER_SIZE); - } - - SDL_UnlockMutex(renderer->acquireUniformBufferLock); - - VULKAN_INTERNAL_TrackUniformBuffer(commandBuffer, uniformBuffer); - - return uniformBuffer; -} - -static void VULKAN_INTERNAL_ReturnUniformBufferToPool( - VulkanRenderer *renderer, - VulkanUniformBuffer *uniformBuffer) -{ - if (renderer->uniformBufferPoolCount >= renderer->uniformBufferPoolCapacity) { - renderer->uniformBufferPoolCapacity *= 2; - renderer->uniformBufferPool = SDL_realloc( - renderer->uniformBufferPool, - renderer->uniformBufferPoolCapacity * sizeof(VulkanUniformBuffer *)); - } - - renderer->uniformBufferPool[renderer->uniformBufferPoolCount] = uniformBuffer; - renderer->uniformBufferPoolCount += 1; - - uniformBuffer->writeOffset = 0; - uniformBuffer->drawOffset = 0; -} - -static void VULKAN_INTERNAL_PushUniformData( - VulkanCommandBuffer *commandBuffer, - VulkanUniformBufferStage uniformBufferStage, - Uint32 slotIndex, - const void *data, - Uint32 length) -{ - Uint32 blockSize = - VULKAN_INTERNAL_NextHighestAlignment32( - length, - commandBuffer->renderer->minUBOAlignment); - - VulkanUniformBuffer *uniformBuffer; - - if (uniformBufferStage == VULKAN_UNIFORM_BUFFER_STAGE_VERTEX) { - if (commandBuffer->vertexUniformBuffers[slotIndex] == NULL) { - commandBuffer->vertexUniformBuffers[slotIndex] = VULKAN_INTERNAL_AcquireUniformBufferFromPool( - commandBuffer); - } - uniformBuffer = commandBuffer->vertexUniformBuffers[slotIndex]; - } else if (uniformBufferStage == VULKAN_UNIFORM_BUFFER_STAGE_FRAGMENT) { - if (commandBuffer->fragmentUniformBuffers[slotIndex] == NULL) { - commandBuffer->fragmentUniformBuffers[slotIndex] = VULKAN_INTERNAL_AcquireUniformBufferFromPool( - commandBuffer); - } - uniformBuffer = commandBuffer->fragmentUniformBuffers[slotIndex]; - } else if (uniformBufferStage == VULKAN_UNIFORM_BUFFER_STAGE_COMPUTE) { - if (commandBuffer->computeUniformBuffers[slotIndex] == NULL) { - commandBuffer->computeUniformBuffers[slotIndex] = VULKAN_INTERNAL_AcquireUniformBufferFromPool( - commandBuffer); - } - uniformBuffer = commandBuffer->computeUniformBuffers[slotIndex]; - } else { - SDL_LogError(SDL_LOG_CATEGORY_GPU, "Unrecognized shader stage!"); - return; - } - - // If there is no more room, acquire a new uniform buffer - if (uniformBuffer->writeOffset + blockSize + MAX_UBO_SECTION_SIZE >= uniformBuffer->buffer->size) { - uniformBuffer = VULKAN_INTERNAL_AcquireUniformBufferFromPool(commandBuffer); - - uniformBuffer->drawOffset = 0; - uniformBuffer->writeOffset = 0; - - if (uniformBufferStage == VULKAN_UNIFORM_BUFFER_STAGE_VERTEX) { - commandBuffer->vertexUniformBuffers[slotIndex] = uniformBuffer; - commandBuffer->needNewVertexUniformDescriptorSet = true; - } else if (uniformBufferStage == VULKAN_UNIFORM_BUFFER_STAGE_FRAGMENT) { - commandBuffer->fragmentUniformBuffers[slotIndex] = uniformBuffer; - commandBuffer->needNewFragmentUniformDescriptorSet = true; - } else if (uniformBufferStage == VULKAN_UNIFORM_BUFFER_STAGE_COMPUTE) { - commandBuffer->computeUniformBuffers[slotIndex] = uniformBuffer; - commandBuffer->needNewComputeUniformDescriptorSet = true; - } else { - SDL_LogError(SDL_LOG_CATEGORY_GPU, "Unrecognized shader stage!"); - return; - } - } - - uniformBuffer->drawOffset = uniformBuffer->writeOffset; - - Uint8 *dst = - uniformBuffer->buffer->usedRegion->allocation->mapPointer + - uniformBuffer->buffer->usedRegion->resourceOffset + - uniformBuffer->writeOffset; - - SDL_memcpy( - dst, - data, - length); - - uniformBuffer->writeOffset += blockSize; - - if (uniformBufferStage == VULKAN_UNIFORM_BUFFER_STAGE_VERTEX) { - commandBuffer->needNewVertexUniformOffsets = true; - } else if (uniformBufferStage == VULKAN_UNIFORM_BUFFER_STAGE_FRAGMENT) { - commandBuffer->needNewFragmentUniformOffsets = true; - } else if (uniformBufferStage == VULKAN_UNIFORM_BUFFER_STAGE_COMPUTE) { - commandBuffer->needNewComputeUniformOffsets = true; - } else { - SDL_LogError(SDL_LOG_CATEGORY_GPU, "Unrecognized shader stage!"); - return; - } -} - -static void VULKAN_BeginRenderPass( - SDL_GPUCommandBuffer *commandBuffer, - const SDL_GPUColorTargetInfo *colorTargetInfos, - Uint32 numColorTargets, - const SDL_GPUDepthStencilTargetInfo *depthStencilTargetInfo) -{ - VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; - VulkanRenderer *renderer = vulkanCommandBuffer->renderer; - VkRenderPass renderPass; - VulkanFramebuffer *framebuffer; - - Uint32 w, h; - VkClearValue *clearValues; - Uint32 clearCount = 0; - Uint32 totalColorAttachmentCount = 0; - Uint32 i; - SDL_GPUViewport defaultViewport; - SDL_Rect defaultScissor; - SDL_FColor defaultBlendConstants; - Uint32 framebufferWidth = SDL_MAX_UINT32; - Uint32 framebufferHeight = SDL_MAX_UINT32; - - for (i = 0; i < numColorTargets; i += 1) { - VulkanTextureContainer *textureContainer = (VulkanTextureContainer *)colorTargetInfos[i].texture; - - w = textureContainer->header.info.width >> colorTargetInfos[i].mip_level; - h = textureContainer->header.info.height >> colorTargetInfos[i].mip_level; - - // The framebuffer cannot be larger than the smallest attachment. - - if (w < framebufferWidth) { - framebufferWidth = w; - } - - if (h < framebufferHeight) { - framebufferHeight = h; - } - } - - if (depthStencilTargetInfo != NULL) { - VulkanTextureContainer *textureContainer = (VulkanTextureContainer *)depthStencilTargetInfo->texture; - - w = textureContainer->header.info.width; - h = textureContainer->header.info.height; - - // The framebuffer cannot be larger than the smallest attachment. - - if (w < framebufferWidth) { - framebufferWidth = w; - } - - if (h < framebufferHeight) { - framebufferHeight = h; - } - } - - for (i = 0; i < numColorTargets; i += 1) { - VulkanTextureContainer *textureContainer = (VulkanTextureContainer *)colorTargetInfos[i].texture; - VulkanTextureSubresource *subresource = VULKAN_INTERNAL_PrepareTextureSubresourceForWrite( - renderer, - vulkanCommandBuffer, - textureContainer, - textureContainer->header.info.type == SDL_GPU_TEXTURETYPE_3D ? 0 : colorTargetInfos[i].layer_or_depth_plane, - colorTargetInfos[i].mip_level, - colorTargetInfos[i].cycle, - VULKAN_TEXTURE_USAGE_MODE_COLOR_ATTACHMENT); - - vulkanCommandBuffer->colorAttachmentSubresources[vulkanCommandBuffer->colorAttachmentSubresourceCount] = subresource; - vulkanCommandBuffer->colorAttachmentSubresourceCount += 1; - VULKAN_INTERNAL_TrackTexture(vulkanCommandBuffer, subresource->parent); - totalColorAttachmentCount += 1; - clearCount += 1; - - if (colorTargetInfos[i].store_op == SDL_GPU_STOREOP_RESOLVE || colorTargetInfos[i].store_op == SDL_GPU_STOREOP_RESOLVE_AND_STORE) { - VulkanTextureContainer *resolveContainer = (VulkanTextureContainer *)colorTargetInfos[i].resolve_texture; - VulkanTextureSubresource *resolveSubresource = VULKAN_INTERNAL_PrepareTextureSubresourceForWrite( - renderer, - vulkanCommandBuffer, - resolveContainer, - colorTargetInfos[i].resolve_layer, - colorTargetInfos[i].resolve_mip_level, - colorTargetInfos[i].cycle_resolve_texture, - VULKAN_TEXTURE_USAGE_MODE_COLOR_ATTACHMENT); - - vulkanCommandBuffer->resolveAttachmentSubresources[vulkanCommandBuffer->resolveAttachmentSubresourceCount] = resolveSubresource; - vulkanCommandBuffer->resolveAttachmentSubresourceCount += 1; - VULKAN_INTERNAL_TrackTexture(vulkanCommandBuffer, resolveSubresource->parent); - totalColorAttachmentCount += 1; - clearCount += 1; - } - } - - if (depthStencilTargetInfo != NULL) { - VulkanTextureContainer *textureContainer = (VulkanTextureContainer *)depthStencilTargetInfo->texture; - VulkanTextureSubresource *subresource = VULKAN_INTERNAL_PrepareTextureSubresourceForWrite( - renderer, - vulkanCommandBuffer, - textureContainer, - 0, - 0, - depthStencilTargetInfo->cycle, - VULKAN_TEXTURE_USAGE_MODE_DEPTH_STENCIL_ATTACHMENT); - - vulkanCommandBuffer->depthStencilAttachmentSubresource = subresource; - VULKAN_INTERNAL_TrackTexture(vulkanCommandBuffer, subresource->parent); - clearCount += 1; - } - - // Fetch required render objects - - renderPass = VULKAN_INTERNAL_FetchRenderPass( - renderer, - vulkanCommandBuffer, - colorTargetInfos, - numColorTargets, - depthStencilTargetInfo); - - if (renderPass == VK_NULL_HANDLE) { - return; - } - - framebuffer = VULKAN_INTERNAL_FetchFramebuffer( - renderer, - renderPass, - colorTargetInfos, - numColorTargets, - depthStencilTargetInfo, - framebufferWidth, - framebufferHeight); - - if (framebuffer == NULL) { - return; - } - - VULKAN_INTERNAL_TrackFramebuffer(renderer, vulkanCommandBuffer, framebuffer); - - // Set clear values - - clearValues = SDL_stack_alloc(VkClearValue, clearCount); - - for (i = 0; i < totalColorAttachmentCount; i += 1) { - clearValues[i].color.float32[0] = colorTargetInfos[i].clear_color.r; - clearValues[i].color.float32[1] = colorTargetInfos[i].clear_color.g; - clearValues[i].color.float32[2] = colorTargetInfos[i].clear_color.b; - clearValues[i].color.float32[3] = colorTargetInfos[i].clear_color.a; - - if (colorTargetInfos[i].store_op == SDL_GPU_STOREOP_RESOLVE || colorTargetInfos[i].store_op == SDL_GPU_STOREOP_RESOLVE_AND_STORE) { - // Skip over the resolve texture, we're not clearing it - i += 1; - } - } - - if (depthStencilTargetInfo != NULL) { - clearValues[totalColorAttachmentCount].depthStencil.depth = - depthStencilTargetInfo->clear_depth; - clearValues[totalColorAttachmentCount].depthStencil.stencil = - depthStencilTargetInfo->clear_stencil; - } - - VkRenderPassBeginInfo renderPassBeginInfo; - renderPassBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; - renderPassBeginInfo.pNext = NULL; - renderPassBeginInfo.renderPass = renderPass; - renderPassBeginInfo.framebuffer = framebuffer->framebuffer; - renderPassBeginInfo.pClearValues = clearValues; - renderPassBeginInfo.clearValueCount = clearCount; - renderPassBeginInfo.renderArea.extent.width = framebufferWidth; - renderPassBeginInfo.renderArea.extent.height = framebufferHeight; - renderPassBeginInfo.renderArea.offset.x = 0; - renderPassBeginInfo.renderArea.offset.y = 0; - - renderer->vkCmdBeginRenderPass( - vulkanCommandBuffer->commandBuffer, - &renderPassBeginInfo, - VK_SUBPASS_CONTENTS_INLINE); - - SDL_stack_free(clearValues); - - // Set sensible default states - - defaultViewport.x = 0; - defaultViewport.y = 0; - defaultViewport.w = (float)framebufferWidth; - defaultViewport.h = (float)framebufferHeight; - defaultViewport.min_depth = 0; - defaultViewport.max_depth = 1; - - VULKAN_INTERNAL_SetCurrentViewport( - vulkanCommandBuffer, - &defaultViewport); - - defaultScissor.x = 0; - defaultScissor.y = 0; - defaultScissor.w = (Sint32)framebufferWidth; - defaultScissor.h = (Sint32)framebufferHeight; - - VULKAN_INTERNAL_SetCurrentScissor( - vulkanCommandBuffer, - &defaultScissor); - - defaultBlendConstants.r = 1.0f; - defaultBlendConstants.g = 1.0f; - defaultBlendConstants.b = 1.0f; - defaultBlendConstants.a = 1.0f; - - VULKAN_INTERNAL_SetCurrentBlendConstants( - vulkanCommandBuffer, - defaultBlendConstants); - - VULKAN_INTERNAL_SetCurrentStencilReference( - vulkanCommandBuffer, - 0); -} - -static void VULKAN_BindGraphicsPipeline( - SDL_GPUCommandBuffer *commandBuffer, - SDL_GPUGraphicsPipeline *graphicsPipeline) -{ - VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; - VulkanRenderer *renderer = vulkanCommandBuffer->renderer; - VulkanGraphicsPipeline *pipeline = (VulkanGraphicsPipeline *)graphicsPipeline; - - renderer->vkCmdBindPipeline( - vulkanCommandBuffer->commandBuffer, - VK_PIPELINE_BIND_POINT_GRAPHICS, - pipeline->pipeline); - - vulkanCommandBuffer->currentGraphicsPipeline = pipeline; - - VULKAN_INTERNAL_TrackGraphicsPipeline(vulkanCommandBuffer, pipeline); - - // Acquire uniform buffers if necessary - for (Uint32 i = 0; i < pipeline->resourceLayout->vertexUniformBufferCount; i += 1) { - if (vulkanCommandBuffer->vertexUniformBuffers[i] == NULL) { - vulkanCommandBuffer->vertexUniformBuffers[i] = VULKAN_INTERNAL_AcquireUniformBufferFromPool( - vulkanCommandBuffer); - } - } - - for (Uint32 i = 0; i < pipeline->resourceLayout->fragmentUniformBufferCount; i += 1) { - if (vulkanCommandBuffer->fragmentUniformBuffers[i] == NULL) { - vulkanCommandBuffer->fragmentUniformBuffers[i] = VULKAN_INTERNAL_AcquireUniformBufferFromPool( - vulkanCommandBuffer); - } - } - - // Mark bindings as needed - vulkanCommandBuffer->needNewVertexResourceDescriptorSet = true; - vulkanCommandBuffer->needNewFragmentResourceDescriptorSet = true; - vulkanCommandBuffer->needNewVertexUniformDescriptorSet = true; - vulkanCommandBuffer->needNewFragmentUniformDescriptorSet = true; - vulkanCommandBuffer->needNewVertexUniformOffsets = true; - vulkanCommandBuffer->needNewFragmentUniformOffsets = true; -} - -static void VULKAN_BindVertexBuffers( - SDL_GPUCommandBuffer *commandBuffer, - Uint32 firstSlot, - const SDL_GPUBufferBinding *bindings, - Uint32 numBindings) -{ - VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; - - for (Uint32 i = 0; i < numBindings; i += 1) { - VulkanBuffer *buffer = ((VulkanBufferContainer *)bindings[i].buffer)->activeBuffer; - if (vulkanCommandBuffer->vertexBuffers[i] != buffer->buffer || vulkanCommandBuffer->vertexBufferOffsets[i] != bindings[i].offset) { - VULKAN_INTERNAL_TrackBuffer(vulkanCommandBuffer, buffer); - - vulkanCommandBuffer->vertexBuffers[i] = buffer->buffer; - vulkanCommandBuffer->vertexBufferOffsets[i] = bindings[i].offset; - vulkanCommandBuffer->needVertexBufferBind = true; - } - } - - vulkanCommandBuffer->vertexBufferCount = - SDL_max(vulkanCommandBuffer->vertexBufferCount, firstSlot + numBindings); -} - -static void VULKAN_BindIndexBuffer( - SDL_GPUCommandBuffer *commandBuffer, - const SDL_GPUBufferBinding *binding, - SDL_GPUIndexElementSize indexElementSize) -{ - VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; - VulkanRenderer *renderer = vulkanCommandBuffer->renderer; - VulkanBuffer *vulkanBuffer = ((VulkanBufferContainer *)binding->buffer)->activeBuffer; - - VULKAN_INTERNAL_TrackBuffer(vulkanCommandBuffer, vulkanBuffer); - - renderer->vkCmdBindIndexBuffer( - vulkanCommandBuffer->commandBuffer, - vulkanBuffer->buffer, - (VkDeviceSize)binding->offset, - SDLToVK_IndexType[indexElementSize]); -} - -static void VULKAN_PushVertexUniformData( - SDL_GPUCommandBuffer *commandBuffer, - Uint32 slotIndex, - const void *data, - Uint32 length) -{ - VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; - - VULKAN_INTERNAL_PushUniformData( - vulkanCommandBuffer, - VULKAN_UNIFORM_BUFFER_STAGE_VERTEX, - slotIndex, - data, - length); -} - -static void VULKAN_PushFragmentUniformData( - SDL_GPUCommandBuffer *commandBuffer, - Uint32 slotIndex, - const void *data, - Uint32 length) -{ - VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; - - VULKAN_INTERNAL_PushUniformData( - vulkanCommandBuffer, - VULKAN_UNIFORM_BUFFER_STAGE_FRAGMENT, - slotIndex, - data, - length); -} - -static void VULKAN_EndRenderPass( - SDL_GPUCommandBuffer *commandBuffer) -{ - VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; - VulkanRenderer *renderer = vulkanCommandBuffer->renderer; - Uint32 i; - - renderer->vkCmdEndRenderPass( - vulkanCommandBuffer->commandBuffer); - - for (i = 0; i < vulkanCommandBuffer->colorAttachmentSubresourceCount; i += 1) { - VULKAN_INTERNAL_TextureSubresourceTransitionToDefaultUsage( - renderer, - vulkanCommandBuffer, - VULKAN_TEXTURE_USAGE_MODE_COLOR_ATTACHMENT, - vulkanCommandBuffer->colorAttachmentSubresources[i]); - } - vulkanCommandBuffer->colorAttachmentSubresourceCount = 0; - - for (i = 0; i < vulkanCommandBuffer->resolveAttachmentSubresourceCount; i += 1) { - VULKAN_INTERNAL_TextureSubresourceTransitionToDefaultUsage( - renderer, - vulkanCommandBuffer, - VULKAN_TEXTURE_USAGE_MODE_COLOR_ATTACHMENT, - vulkanCommandBuffer->resolveAttachmentSubresources[i]); - } - vulkanCommandBuffer->resolveAttachmentSubresourceCount = 0; - - if (vulkanCommandBuffer->depthStencilAttachmentSubresource != NULL) { - VULKAN_INTERNAL_TextureSubresourceTransitionToDefaultUsage( - renderer, - vulkanCommandBuffer, - VULKAN_TEXTURE_USAGE_MODE_DEPTH_STENCIL_ATTACHMENT, - vulkanCommandBuffer->depthStencilAttachmentSubresource); - vulkanCommandBuffer->depthStencilAttachmentSubresource = NULL; - } - - vulkanCommandBuffer->currentGraphicsPipeline = NULL; - - vulkanCommandBuffer->vertexResourceDescriptorSet = VK_NULL_HANDLE; - vulkanCommandBuffer->vertexUniformDescriptorSet = VK_NULL_HANDLE; - vulkanCommandBuffer->fragmentResourceDescriptorSet = VK_NULL_HANDLE; - vulkanCommandBuffer->fragmentUniformDescriptorSet = VK_NULL_HANDLE; - - // Reset bind state - SDL_zeroa(vulkanCommandBuffer->colorAttachmentSubresources); - SDL_zeroa(vulkanCommandBuffer->resolveAttachmentSubresources); - vulkanCommandBuffer->depthStencilAttachmentSubresource = NULL; - - SDL_zeroa(vulkanCommandBuffer->vertexBuffers); - SDL_zeroa(vulkanCommandBuffer->vertexBufferOffsets); - vulkanCommandBuffer->vertexBufferCount = 0; - - SDL_zeroa(vulkanCommandBuffer->vertexSamplers); - SDL_zeroa(vulkanCommandBuffer->vertexSamplerTextures); - SDL_zeroa(vulkanCommandBuffer->vertexStorageTextures); - SDL_zeroa(vulkanCommandBuffer->vertexStorageBuffers); - - SDL_zeroa(vulkanCommandBuffer->fragmentSamplers); - SDL_zeroa(vulkanCommandBuffer->fragmentSamplerTextures); - SDL_zeroa(vulkanCommandBuffer->fragmentStorageTextures); - SDL_zeroa(vulkanCommandBuffer->fragmentStorageBuffers); -} - -static void VULKAN_BeginComputePass( - SDL_GPUCommandBuffer *commandBuffer, - const SDL_GPUStorageTextureReadWriteBinding *storageTextureBindings, - Uint32 numStorageTextureBindings, - const SDL_GPUStorageBufferReadWriteBinding *storageBufferBindings, - Uint32 numStorageBufferBindings) -{ - VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; - VulkanRenderer *renderer = vulkanCommandBuffer->renderer; - VulkanBufferContainer *bufferContainer; - VulkanBuffer *buffer; - Uint32 i; - - vulkanCommandBuffer->readWriteComputeStorageTextureSubresourceCount = numStorageTextureBindings; - - for (i = 0; i < numStorageTextureBindings; i += 1) { - VulkanTextureContainer *textureContainer = (VulkanTextureContainer *)storageTextureBindings[i].texture; - VulkanTextureSubresource *subresource = VULKAN_INTERNAL_PrepareTextureSubresourceForWrite( - renderer, - vulkanCommandBuffer, - textureContainer, - storageTextureBindings[i].layer, - storageTextureBindings[i].mip_level, - storageTextureBindings[i].cycle, - VULKAN_TEXTURE_USAGE_MODE_COMPUTE_STORAGE_READ_WRITE); - - vulkanCommandBuffer->readWriteComputeStorageTextureSubresources[i] = subresource; - - VULKAN_INTERNAL_TrackTexture( - vulkanCommandBuffer, - subresource->parent); - } - - for (i = 0; i < numStorageBufferBindings; i += 1) { - bufferContainer = (VulkanBufferContainer *)storageBufferBindings[i].buffer; - buffer = VULKAN_INTERNAL_PrepareBufferForWrite( - renderer, - vulkanCommandBuffer, - bufferContainer, - storageBufferBindings[i].cycle, - VULKAN_BUFFER_USAGE_MODE_COMPUTE_STORAGE_READ); - - vulkanCommandBuffer->readWriteComputeStorageBuffers[i] = buffer; - - VULKAN_INTERNAL_TrackBuffer( - vulkanCommandBuffer, - buffer); - } -} - -static void VULKAN_BindComputePipeline( - SDL_GPUCommandBuffer *commandBuffer, - SDL_GPUComputePipeline *computePipeline) -{ - VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; - VulkanRenderer *renderer = vulkanCommandBuffer->renderer; - VulkanComputePipeline *vulkanComputePipeline = (VulkanComputePipeline *)computePipeline; - - renderer->vkCmdBindPipeline( - vulkanCommandBuffer->commandBuffer, - VK_PIPELINE_BIND_POINT_COMPUTE, - vulkanComputePipeline->pipeline); - - vulkanCommandBuffer->currentComputePipeline = vulkanComputePipeline; - - VULKAN_INTERNAL_TrackComputePipeline(vulkanCommandBuffer, vulkanComputePipeline); - - // Acquire uniform buffers if necessary - for (Uint32 i = 0; i < vulkanComputePipeline->resourceLayout->numUniformBuffers; i += 1) { - if (vulkanCommandBuffer->computeUniformBuffers[i] == NULL) { - vulkanCommandBuffer->computeUniformBuffers[i] = VULKAN_INTERNAL_AcquireUniformBufferFromPool( - vulkanCommandBuffer); - } - } - - // Mark binding as needed - vulkanCommandBuffer->needNewComputeReadWriteDescriptorSet = true; - vulkanCommandBuffer->needNewComputeReadOnlyDescriptorSet = true; - vulkanCommandBuffer->needNewComputeUniformDescriptorSet = true; - vulkanCommandBuffer->needNewComputeUniformOffsets = true; -} - -static void VULKAN_BindComputeSamplers( - SDL_GPUCommandBuffer *commandBuffer, - Uint32 firstSlot, - const SDL_GPUTextureSamplerBinding *textureSamplerBindings, - Uint32 numBindings) -{ - VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; - - for (Uint32 i = 0; i < numBindings; i += 1) { - VulkanTextureContainer *textureContainer = (VulkanTextureContainer *)textureSamplerBindings[i].texture; - VulkanSampler *sampler = (VulkanSampler *)textureSamplerBindings[i].sampler; - - if (vulkanCommandBuffer->computeSamplers[firstSlot + i] != sampler) { - VULKAN_INTERNAL_TrackSampler( - vulkanCommandBuffer, - sampler); - - vulkanCommandBuffer->computeSamplers[firstSlot + i] = sampler; - vulkanCommandBuffer->needNewComputeReadOnlyDescriptorSet = true; - } - - if (vulkanCommandBuffer->computeSamplerTextures[firstSlot + i] != textureContainer->activeTexture) { - VULKAN_INTERNAL_TrackTexture( - vulkanCommandBuffer, - textureContainer->activeTexture); - - vulkanCommandBuffer->computeSamplerTextures[firstSlot + i] = textureContainer->activeTexture; - vulkanCommandBuffer->needNewComputeReadOnlyDescriptorSet = true; - } - } -} - -static void VULKAN_BindComputeStorageTextures( - SDL_GPUCommandBuffer *commandBuffer, - Uint32 firstSlot, - SDL_GPUTexture *const *storageTextures, - Uint32 numBindings) -{ - VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; - VulkanRenderer *renderer = vulkanCommandBuffer->renderer; - - for (Uint32 i = 0; i < numBindings; i += 1) { - VulkanTextureContainer *textureContainer = (VulkanTextureContainer *)storageTextures[i]; - - if (vulkanCommandBuffer->readOnlyComputeStorageTextures[firstSlot + i] != textureContainer->activeTexture) { - /* If a different texture as in this slot, transition it back to its default usage */ - if (vulkanCommandBuffer->readOnlyComputeStorageTextures[firstSlot + i] != NULL) { - VULKAN_INTERNAL_TextureTransitionToDefaultUsage( - renderer, - vulkanCommandBuffer, - VULKAN_TEXTURE_USAGE_MODE_COMPUTE_STORAGE_READ, - vulkanCommandBuffer->readOnlyComputeStorageTextures[firstSlot + i]); - } - - /* Then transition the new texture and prepare it for binding */ - VULKAN_INTERNAL_TextureTransitionFromDefaultUsage( - renderer, - vulkanCommandBuffer, - VULKAN_TEXTURE_USAGE_MODE_COMPUTE_STORAGE_READ, - textureContainer->activeTexture); - - - VULKAN_INTERNAL_TrackTexture( - vulkanCommandBuffer, - textureContainer->activeTexture); - - vulkanCommandBuffer->readOnlyComputeStorageTextures[firstSlot + i] = textureContainer->activeTexture; - vulkanCommandBuffer->needNewComputeReadOnlyDescriptorSet = true; - } - } -} - -static void VULKAN_BindComputeStorageBuffers( - SDL_GPUCommandBuffer *commandBuffer, - Uint32 firstSlot, - SDL_GPUBuffer *const *storageBuffers, - Uint32 numBindings) -{ - VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; - VulkanRenderer *renderer = vulkanCommandBuffer->renderer; - - for (Uint32 i = 0; i < numBindings; i += 1) { - VulkanBufferContainer *bufferContainer = (VulkanBufferContainer *)storageBuffers[i]; - - if (vulkanCommandBuffer->readOnlyComputeStorageBuffers[firstSlot + i] != bufferContainer->activeBuffer) { - /* If a different buffer was in this slot, transition it back to its default usage */ - if (vulkanCommandBuffer->readOnlyComputeStorageBuffers[firstSlot + i] != NULL) { - VULKAN_INTERNAL_BufferTransitionToDefaultUsage( - renderer, - vulkanCommandBuffer, - VULKAN_BUFFER_USAGE_MODE_COMPUTE_STORAGE_READ, - vulkanCommandBuffer->readOnlyComputeStorageBuffers[firstSlot + i]); - } - - /* Then transition the new buffer and prepare it for binding */ - VULKAN_INTERNAL_BufferTransitionFromDefaultUsage( - renderer, - vulkanCommandBuffer, - VULKAN_BUFFER_USAGE_MODE_COMPUTE_STORAGE_READ, - bufferContainer->activeBuffer); - - VULKAN_INTERNAL_TrackBuffer( - vulkanCommandBuffer, - bufferContainer->activeBuffer); - - vulkanCommandBuffer->readOnlyComputeStorageBuffers[firstSlot + i] = bufferContainer->activeBuffer; - vulkanCommandBuffer->needNewComputeReadOnlyDescriptorSet = true; - } - } -} - -static void VULKAN_PushComputeUniformData( - SDL_GPUCommandBuffer *commandBuffer, - Uint32 slotIndex, - const void *data, - Uint32 length) -{ - VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; - - VULKAN_INTERNAL_PushUniformData( - vulkanCommandBuffer, - VULKAN_UNIFORM_BUFFER_STAGE_COMPUTE, - slotIndex, - data, - length); -} - -static void VULKAN_INTERNAL_BindComputeDescriptorSets( - VulkanRenderer *renderer, - VulkanCommandBuffer *commandBuffer) -{ - VulkanComputePipelineResourceLayout *resourceLayout; - DescriptorSetLayout *descriptorSetLayout; - VkWriteDescriptorSet writeDescriptorSets[ - MAX_TEXTURE_SAMPLERS_PER_STAGE + - MAX_STORAGE_TEXTURES_PER_STAGE + - MAX_STORAGE_BUFFERS_PER_STAGE + - MAX_COMPUTE_WRITE_TEXTURES + - MAX_COMPUTE_WRITE_BUFFERS + - MAX_UNIFORM_BUFFERS_PER_STAGE]; - VkDescriptorBufferInfo bufferInfos[MAX_STORAGE_BUFFERS_PER_STAGE + MAX_COMPUTE_WRITE_BUFFERS + MAX_UNIFORM_BUFFERS_PER_STAGE]; - VkDescriptorImageInfo imageInfos[MAX_TEXTURE_SAMPLERS_PER_STAGE + MAX_STORAGE_TEXTURES_PER_STAGE + MAX_COMPUTE_WRITE_TEXTURES]; - Uint32 dynamicOffsets[MAX_UNIFORM_BUFFERS_PER_STAGE]; - Uint32 writeCount = 0; - Uint32 bufferInfoCount = 0; - Uint32 imageInfoCount = 0; - Uint32 dynamicOffsetCount = 0; - - if ( - !commandBuffer->needNewComputeReadOnlyDescriptorSet && - !commandBuffer->needNewComputeReadWriteDescriptorSet && - !commandBuffer->needNewComputeUniformDescriptorSet && - !commandBuffer->needNewComputeUniformOffsets - ) { - return; - } - - resourceLayout = commandBuffer->currentComputePipeline->resourceLayout; - - if (commandBuffer->needNewComputeReadOnlyDescriptorSet) { - descriptorSetLayout = resourceLayout->descriptorSetLayouts[0]; - - commandBuffer->computeReadOnlyDescriptorSet = VULKAN_INTERNAL_FetchDescriptorSet( - renderer, - commandBuffer, - descriptorSetLayout); - - for (Uint32 i = 0; i < resourceLayout->numSamplers; i += 1) { - VkWriteDescriptorSet *currentWriteDescriptorSet = &writeDescriptorSets[writeCount]; - - currentWriteDescriptorSet->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - currentWriteDescriptorSet->pNext = NULL; - currentWriteDescriptorSet->descriptorCount = 1; - currentWriteDescriptorSet->descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - currentWriteDescriptorSet->dstArrayElement = 0; - currentWriteDescriptorSet->dstBinding = i; - currentWriteDescriptorSet->dstSet = commandBuffer->computeReadOnlyDescriptorSet; - currentWriteDescriptorSet->pTexelBufferView = NULL; - currentWriteDescriptorSet->pBufferInfo = NULL; - - imageInfos[imageInfoCount].sampler = commandBuffer->computeSamplers[i]->sampler; - imageInfos[imageInfoCount].imageView = commandBuffer->computeSamplerTextures[i]->fullView; - imageInfos[imageInfoCount].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - - currentWriteDescriptorSet->pImageInfo = &imageInfos[imageInfoCount]; - - writeCount += 1; - imageInfoCount += 1; - } - - for (Uint32 i = 0; i < resourceLayout->numReadonlyStorageTextures; i += 1) { - VkWriteDescriptorSet *currentWriteDescriptorSet = &writeDescriptorSets[writeCount]; - - currentWriteDescriptorSet->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - currentWriteDescriptorSet->pNext = NULL; - currentWriteDescriptorSet->descriptorCount = 1; - currentWriteDescriptorSet->descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE; // Yes, we are declaring the readonly storage texture as a sampled image, because shaders are stupid. - currentWriteDescriptorSet->dstArrayElement = 0; - currentWriteDescriptorSet->dstBinding = resourceLayout->numSamplers + i; - currentWriteDescriptorSet->dstSet = commandBuffer->computeReadOnlyDescriptorSet; - currentWriteDescriptorSet->pTexelBufferView = NULL; - currentWriteDescriptorSet->pBufferInfo = NULL; - - imageInfos[imageInfoCount].sampler = VK_NULL_HANDLE; - imageInfos[imageInfoCount].imageView = commandBuffer->readOnlyComputeStorageTextures[i]->fullView; - imageInfos[imageInfoCount].imageLayout = VK_IMAGE_LAYOUT_GENERAL; - - currentWriteDescriptorSet->pImageInfo = &imageInfos[imageInfoCount]; - - writeCount += 1; - imageInfoCount += 1; - } - - for (Uint32 i = 0; i < resourceLayout->numReadonlyStorageBuffers; i += 1) { - VkWriteDescriptorSet *currentWriteDescriptorSet = &writeDescriptorSets[writeCount]; - - currentWriteDescriptorSet->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - currentWriteDescriptorSet->pNext = NULL; - currentWriteDescriptorSet->descriptorCount = 1; - currentWriteDescriptorSet->descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; - currentWriteDescriptorSet->dstArrayElement = 0; - currentWriteDescriptorSet->dstBinding = resourceLayout->numSamplers + resourceLayout->numReadonlyStorageTextures + i; - currentWriteDescriptorSet->dstSet = commandBuffer->computeReadOnlyDescriptorSet; - currentWriteDescriptorSet->pTexelBufferView = NULL; - currentWriteDescriptorSet->pImageInfo = NULL; - - bufferInfos[bufferInfoCount].buffer = commandBuffer->readOnlyComputeStorageBuffers[i]->buffer; - bufferInfos[bufferInfoCount].offset = 0; - bufferInfos[bufferInfoCount].range = VK_WHOLE_SIZE; - - currentWriteDescriptorSet->pBufferInfo = &bufferInfos[bufferInfoCount]; - - writeCount += 1; - bufferInfoCount += 1; - } - - commandBuffer->needNewComputeReadOnlyDescriptorSet = false; - } - - if (commandBuffer->needNewComputeReadWriteDescriptorSet) { - descriptorSetLayout = resourceLayout->descriptorSetLayouts[1]; - - commandBuffer->computeReadWriteDescriptorSet = VULKAN_INTERNAL_FetchDescriptorSet( - renderer, - commandBuffer, - descriptorSetLayout); - - for (Uint32 i = 0; i < resourceLayout->numReadWriteStorageTextures; i += 1) { - VkWriteDescriptorSet *currentWriteDescriptorSet = &writeDescriptorSets[writeCount]; - - currentWriteDescriptorSet->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - currentWriteDescriptorSet->pNext = NULL; - currentWriteDescriptorSet->descriptorCount = 1; - currentWriteDescriptorSet->descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; - currentWriteDescriptorSet->dstArrayElement = 0; - currentWriteDescriptorSet->dstBinding = i; - currentWriteDescriptorSet->dstSet = commandBuffer->computeReadWriteDescriptorSet; - currentWriteDescriptorSet->pTexelBufferView = NULL; - currentWriteDescriptorSet->pBufferInfo = NULL; - - imageInfos[imageInfoCount].sampler = VK_NULL_HANDLE; - imageInfos[imageInfoCount].imageView = commandBuffer->readWriteComputeStorageTextureSubresources[i]->computeWriteView; - imageInfos[imageInfoCount].imageLayout = VK_IMAGE_LAYOUT_GENERAL; - - currentWriteDescriptorSet->pImageInfo = &imageInfos[imageInfoCount]; - - writeCount += 1; - imageInfoCount += 1; - } - - for (Uint32 i = 0; i < resourceLayout->numReadWriteStorageBuffers; i += 1) { - VkWriteDescriptorSet *currentWriteDescriptorSet = &writeDescriptorSets[writeCount]; - - currentWriteDescriptorSet->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - currentWriteDescriptorSet->pNext = NULL; - currentWriteDescriptorSet->descriptorCount = 1; - currentWriteDescriptorSet->descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; - currentWriteDescriptorSet->dstArrayElement = 0; - currentWriteDescriptorSet->dstBinding = resourceLayout->numReadWriteStorageTextures + i; - currentWriteDescriptorSet->dstSet = commandBuffer->computeReadWriteDescriptorSet; - currentWriteDescriptorSet->pTexelBufferView = NULL; - currentWriteDescriptorSet->pImageInfo = NULL; - - bufferInfos[bufferInfoCount].buffer = commandBuffer->readWriteComputeStorageBuffers[i]->buffer; - bufferInfos[bufferInfoCount].offset = 0; - bufferInfos[bufferInfoCount].range = VK_WHOLE_SIZE; - - currentWriteDescriptorSet->pBufferInfo = &bufferInfos[bufferInfoCount]; - - writeCount += 1; - bufferInfoCount += 1; - } - - commandBuffer->needNewComputeReadWriteDescriptorSet = false; - } - - if (commandBuffer->needNewComputeUniformDescriptorSet) { - descriptorSetLayout = resourceLayout->descriptorSetLayouts[2]; - - commandBuffer->computeUniformDescriptorSet = VULKAN_INTERNAL_FetchDescriptorSet( - renderer, - commandBuffer, - descriptorSetLayout); - - - for (Uint32 i = 0; i < resourceLayout->numUniformBuffers; i += 1) { - VkWriteDescriptorSet *currentWriteDescriptorSet = &writeDescriptorSets[writeCount]; - - currentWriteDescriptorSet->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - currentWriteDescriptorSet->pNext = NULL; - currentWriteDescriptorSet->descriptorCount = 1; - currentWriteDescriptorSet->descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC; - currentWriteDescriptorSet->dstArrayElement = 0; - currentWriteDescriptorSet->dstBinding = i; - currentWriteDescriptorSet->dstSet = commandBuffer->computeUniformDescriptorSet; - currentWriteDescriptorSet->pTexelBufferView = NULL; - currentWriteDescriptorSet->pImageInfo = NULL; - - bufferInfos[bufferInfoCount].buffer = commandBuffer->computeUniformBuffers[i]->buffer->buffer; - bufferInfos[bufferInfoCount].offset = 0; - bufferInfos[bufferInfoCount].range = MAX_UBO_SECTION_SIZE; - - currentWriteDescriptorSet->pBufferInfo = &bufferInfos[bufferInfoCount]; - - writeCount += 1; - bufferInfoCount += 1; - } - - commandBuffer->needNewComputeUniformDescriptorSet = false; - } - - for (Uint32 i = 0; i < resourceLayout->numUniformBuffers; i += 1) { - dynamicOffsets[i] = commandBuffer->computeUniformBuffers[i]->drawOffset; - dynamicOffsetCount += 1; - } - - renderer->vkUpdateDescriptorSets( - renderer->logicalDevice, - writeCount, - writeDescriptorSets, - 0, - NULL); - - VkDescriptorSet sets[3]; - sets[0] = commandBuffer->computeReadOnlyDescriptorSet; - sets[1] = commandBuffer->computeReadWriteDescriptorSet; - sets[2] = commandBuffer->computeUniformDescriptorSet; - - renderer->vkCmdBindDescriptorSets( - commandBuffer->commandBuffer, - VK_PIPELINE_BIND_POINT_COMPUTE, - resourceLayout->pipelineLayout, - 0, - 3, - sets, - dynamicOffsetCount, - dynamicOffsets); - - commandBuffer->needNewVertexUniformOffsets = false; -} - -static void VULKAN_DispatchCompute( - SDL_GPUCommandBuffer *commandBuffer, - Uint32 groupcountX, - Uint32 groupcountY, - Uint32 groupcountZ) -{ - VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; - VulkanRenderer *renderer = vulkanCommandBuffer->renderer; - - VULKAN_INTERNAL_BindComputeDescriptorSets(renderer, vulkanCommandBuffer); - - renderer->vkCmdDispatch( - vulkanCommandBuffer->commandBuffer, - groupcountX, - groupcountY, - groupcountZ); -} - -static void VULKAN_DispatchComputeIndirect( - SDL_GPUCommandBuffer *commandBuffer, - SDL_GPUBuffer *buffer, - Uint32 offset) -{ - VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; - VulkanRenderer *renderer = vulkanCommandBuffer->renderer; - VulkanBuffer *vulkanBuffer = ((VulkanBufferContainer *)buffer)->activeBuffer; - - VULKAN_INTERNAL_BindComputeDescriptorSets(renderer, vulkanCommandBuffer); - - renderer->vkCmdDispatchIndirect( - vulkanCommandBuffer->commandBuffer, - vulkanBuffer->buffer, - offset); - - VULKAN_INTERNAL_TrackBuffer(vulkanCommandBuffer, vulkanBuffer); -} - -static void VULKAN_EndComputePass( - SDL_GPUCommandBuffer *commandBuffer) -{ - VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; - Uint32 i; - - for (i = 0; i < vulkanCommandBuffer->readWriteComputeStorageTextureSubresourceCount; i += 1) { - VULKAN_INTERNAL_TextureSubresourceTransitionToDefaultUsage( - vulkanCommandBuffer->renderer, - vulkanCommandBuffer, - VULKAN_TEXTURE_USAGE_MODE_COMPUTE_STORAGE_READ_WRITE, - vulkanCommandBuffer->readWriteComputeStorageTextureSubresources[i]); - vulkanCommandBuffer->readWriteComputeStorageTextureSubresources[i] = NULL; - } - vulkanCommandBuffer->readWriteComputeStorageTextureSubresourceCount = 0; - - for (i = 0; i < MAX_COMPUTE_WRITE_BUFFERS; i += 1) { - if (vulkanCommandBuffer->readWriteComputeStorageBuffers[i] != NULL) { - VULKAN_INTERNAL_BufferTransitionToDefaultUsage( - vulkanCommandBuffer->renderer, - vulkanCommandBuffer, - VULKAN_BUFFER_USAGE_MODE_COMPUTE_STORAGE_READ_WRITE, - vulkanCommandBuffer->readWriteComputeStorageBuffers[i]); - - vulkanCommandBuffer->readWriteComputeStorageBuffers[i] = NULL; - } - } - - for (i = 0; i < MAX_STORAGE_TEXTURES_PER_STAGE; i += 1) { - if (vulkanCommandBuffer->readOnlyComputeStorageTextures[i] != NULL) { - VULKAN_INTERNAL_TextureTransitionToDefaultUsage( - vulkanCommandBuffer->renderer, - vulkanCommandBuffer, - VULKAN_TEXTURE_USAGE_MODE_COMPUTE_STORAGE_READ, - vulkanCommandBuffer->readOnlyComputeStorageTextures[i]); - - vulkanCommandBuffer->readOnlyComputeStorageTextures[i] = NULL; - } - } - - for (i = 0; i < MAX_STORAGE_BUFFERS_PER_STAGE; i += 1) { - if (vulkanCommandBuffer->readOnlyComputeStorageBuffers[i] != NULL) { - VULKAN_INTERNAL_BufferTransitionToDefaultUsage( - vulkanCommandBuffer->renderer, - vulkanCommandBuffer, - VULKAN_BUFFER_USAGE_MODE_COMPUTE_STORAGE_READ, - vulkanCommandBuffer->readOnlyComputeStorageBuffers[i]); - - vulkanCommandBuffer->readOnlyComputeStorageBuffers[i] = NULL; - } - } - - // we don't need a barrier because sampler state is always the default if sampler bit is set - SDL_zeroa(vulkanCommandBuffer->computeSamplerTextures); - SDL_zeroa(vulkanCommandBuffer->computeSamplers); - - vulkanCommandBuffer->currentComputePipeline = NULL; - - vulkanCommandBuffer->computeReadOnlyDescriptorSet = VK_NULL_HANDLE; - vulkanCommandBuffer->computeReadWriteDescriptorSet = VK_NULL_HANDLE; - vulkanCommandBuffer->computeUniformDescriptorSet = VK_NULL_HANDLE; -} - -static void *VULKAN_MapTransferBuffer( - SDL_GPURenderer *driverData, - SDL_GPUTransferBuffer *transferBuffer, - bool cycle) -{ - VulkanRenderer *renderer = (VulkanRenderer *)driverData; - VulkanBufferContainer *transferBufferContainer = (VulkanBufferContainer *)transferBuffer; - - if ( - cycle && - SDL_GetAtomicInt(&transferBufferContainer->activeBuffer->referenceCount) > 0) { - VULKAN_INTERNAL_CycleActiveBuffer( - renderer, - transferBufferContainer); - } - - Uint8 *bufferPointer = - transferBufferContainer->activeBuffer->usedRegion->allocation->mapPointer + - transferBufferContainer->activeBuffer->usedRegion->resourceOffset; - - return bufferPointer; -} - -static void VULKAN_UnmapTransferBuffer( - SDL_GPURenderer *driverData, - SDL_GPUTransferBuffer *transferBuffer) -{ - // no-op because transfer buffers are persistently mapped - (void)driverData; - (void)transferBuffer; -} - -static void VULKAN_BeginCopyPass( - SDL_GPUCommandBuffer *commandBuffer) -{ - // no-op - (void)commandBuffer; -} - -static void VULKAN_UploadToTexture( - SDL_GPUCommandBuffer *commandBuffer, - const SDL_GPUTextureTransferInfo *source, - const SDL_GPUTextureRegion *destination, - bool cycle) -{ - VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; - VulkanRenderer *renderer = vulkanCommandBuffer->renderer; - VulkanBufferContainer *transferBufferContainer = (VulkanBufferContainer *)source->transfer_buffer; - VulkanTextureContainer *vulkanTextureContainer = (VulkanTextureContainer *)destination->texture; - VulkanTextureSubresource *vulkanTextureSubresource; - VkBufferImageCopy imageCopy; - - // Note that the transfer buffer does not need a barrier, as it is synced by the client - - vulkanTextureSubresource = VULKAN_INTERNAL_PrepareTextureSubresourceForWrite( - renderer, - vulkanCommandBuffer, - vulkanTextureContainer, - destination->layer, - destination->mip_level, - cycle, - VULKAN_TEXTURE_USAGE_MODE_COPY_DESTINATION); - - imageCopy.imageExtent.width = destination->w; - imageCopy.imageExtent.height = destination->h; - imageCopy.imageExtent.depth = destination->d; - imageCopy.imageOffset.x = destination->x; - imageCopy.imageOffset.y = destination->y; - imageCopy.imageOffset.z = destination->z; - imageCopy.imageSubresource.aspectMask = vulkanTextureSubresource->parent->aspectFlags; - imageCopy.imageSubresource.baseArrayLayer = destination->layer; - imageCopy.imageSubresource.layerCount = 1; - imageCopy.imageSubresource.mipLevel = destination->mip_level; - imageCopy.bufferOffset = source->offset; - imageCopy.bufferRowLength = source->pixels_per_row; - imageCopy.bufferImageHeight = source->rows_per_layer; - - renderer->vkCmdCopyBufferToImage( - vulkanCommandBuffer->commandBuffer, - transferBufferContainer->activeBuffer->buffer, - vulkanTextureSubresource->parent->image, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - 1, - &imageCopy); - - VULKAN_INTERNAL_TextureSubresourceTransitionToDefaultUsage( - renderer, - vulkanCommandBuffer, - VULKAN_TEXTURE_USAGE_MODE_COPY_DESTINATION, - vulkanTextureSubresource); - - VULKAN_INTERNAL_TrackBuffer(vulkanCommandBuffer, transferBufferContainer->activeBuffer); - VULKAN_INTERNAL_TrackTexture(vulkanCommandBuffer, vulkanTextureSubresource->parent); -} - -static void VULKAN_UploadToBuffer( - SDL_GPUCommandBuffer *commandBuffer, - const SDL_GPUTransferBufferLocation *source, - const SDL_GPUBufferRegion *destination, - bool cycle) -{ - VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; - VulkanRenderer *renderer = vulkanCommandBuffer->renderer; - VulkanBufferContainer *transferBufferContainer = (VulkanBufferContainer *)source->transfer_buffer; - VulkanBufferContainer *bufferContainer = (VulkanBufferContainer *)destination->buffer; - VkBufferCopy bufferCopy; - - // Note that the transfer buffer does not need a barrier, as it is synced by the client - - VulkanBuffer *vulkanBuffer = VULKAN_INTERNAL_PrepareBufferForWrite( - renderer, - vulkanCommandBuffer, - bufferContainer, - cycle, - VULKAN_BUFFER_USAGE_MODE_COPY_DESTINATION); - - bufferCopy.srcOffset = source->offset; - bufferCopy.dstOffset = destination->offset; - bufferCopy.size = destination->size; - - renderer->vkCmdCopyBuffer( - vulkanCommandBuffer->commandBuffer, - transferBufferContainer->activeBuffer->buffer, - vulkanBuffer->buffer, - 1, - &bufferCopy); - - VULKAN_INTERNAL_BufferTransitionToDefaultUsage( - renderer, - vulkanCommandBuffer, - VULKAN_BUFFER_USAGE_MODE_COPY_DESTINATION, - vulkanBuffer); - - VULKAN_INTERNAL_TrackBuffer(vulkanCommandBuffer, transferBufferContainer->activeBuffer); - VULKAN_INTERNAL_TrackBuffer(vulkanCommandBuffer, vulkanBuffer); -} - -// Readback - -static void VULKAN_DownloadFromTexture( - SDL_GPUCommandBuffer *commandBuffer, - const SDL_GPUTextureRegion *source, - const SDL_GPUTextureTransferInfo *destination) -{ - VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; - VulkanRenderer *renderer = vulkanCommandBuffer->renderer; - VulkanTextureContainer *textureContainer = (VulkanTextureContainer *)source->texture; - VulkanTextureSubresource *vulkanTextureSubresource; - VulkanBufferContainer *transferBufferContainer = (VulkanBufferContainer *)destination->transfer_buffer; - VkBufferImageCopy imageCopy; - vulkanTextureSubresource = VULKAN_INTERNAL_FetchTextureSubresource( - textureContainer, - source->layer, - source->mip_level); - - // Note that the transfer buffer does not need a barrier, as it is synced by the client - - VULKAN_INTERNAL_TextureSubresourceTransitionFromDefaultUsage( - renderer, - vulkanCommandBuffer, - VULKAN_TEXTURE_USAGE_MODE_COPY_SOURCE, - vulkanTextureSubresource); - - imageCopy.imageExtent.width = source->w; - imageCopy.imageExtent.height = source->h; - imageCopy.imageExtent.depth = source->d; - imageCopy.imageOffset.x = source->x; - imageCopy.imageOffset.y = source->y; - imageCopy.imageOffset.z = source->z; - imageCopy.imageSubresource.aspectMask = vulkanTextureSubresource->parent->aspectFlags; - imageCopy.imageSubresource.baseArrayLayer = source->layer; - imageCopy.imageSubresource.layerCount = 1; - imageCopy.imageSubresource.mipLevel = source->mip_level; - imageCopy.bufferOffset = destination->offset; - imageCopy.bufferRowLength = destination->pixels_per_row; - imageCopy.bufferImageHeight = destination->rows_per_layer; - - renderer->vkCmdCopyImageToBuffer( - vulkanCommandBuffer->commandBuffer, - vulkanTextureSubresource->parent->image, - VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - transferBufferContainer->activeBuffer->buffer, - 1, - &imageCopy); - - VULKAN_INTERNAL_TextureSubresourceTransitionToDefaultUsage( - renderer, - vulkanCommandBuffer, - VULKAN_TEXTURE_USAGE_MODE_COPY_SOURCE, - vulkanTextureSubresource); - - VULKAN_INTERNAL_TrackBuffer(vulkanCommandBuffer, transferBufferContainer->activeBuffer); - VULKAN_INTERNAL_TrackTexture(vulkanCommandBuffer, vulkanTextureSubresource->parent); -} - -static void VULKAN_DownloadFromBuffer( - SDL_GPUCommandBuffer *commandBuffer, - const SDL_GPUBufferRegion *source, - const SDL_GPUTransferBufferLocation *destination) -{ - VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; - VulkanRenderer *renderer = vulkanCommandBuffer->renderer; - VulkanBufferContainer *bufferContainer = (VulkanBufferContainer *)source->buffer; - VulkanBufferContainer *transferBufferContainer = (VulkanBufferContainer *)destination->transfer_buffer; - VkBufferCopy bufferCopy; - - // Note that transfer buffer does not need a barrier, as it is synced by the client - - VULKAN_INTERNAL_BufferTransitionFromDefaultUsage( - renderer, - vulkanCommandBuffer, - VULKAN_BUFFER_USAGE_MODE_COPY_SOURCE, - bufferContainer->activeBuffer); - - bufferCopy.srcOffset = source->offset; - bufferCopy.dstOffset = destination->offset; - bufferCopy.size = source->size; - - renderer->vkCmdCopyBuffer( - vulkanCommandBuffer->commandBuffer, - bufferContainer->activeBuffer->buffer, - transferBufferContainer->activeBuffer->buffer, - 1, - &bufferCopy); - - VULKAN_INTERNAL_BufferTransitionToDefaultUsage( - renderer, - vulkanCommandBuffer, - VULKAN_BUFFER_USAGE_MODE_COPY_SOURCE, - bufferContainer->activeBuffer); - - VULKAN_INTERNAL_TrackBuffer(vulkanCommandBuffer, transferBufferContainer->activeBuffer); - VULKAN_INTERNAL_TrackBuffer(vulkanCommandBuffer, bufferContainer->activeBuffer); -} - -static void VULKAN_CopyTextureToTexture( - SDL_GPUCommandBuffer *commandBuffer, - const SDL_GPUTextureLocation *source, - const SDL_GPUTextureLocation *destination, - Uint32 w, - Uint32 h, - Uint32 d, - bool cycle) -{ - VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; - VulkanRenderer *renderer = vulkanCommandBuffer->renderer; - VulkanTextureSubresource *srcSubresource; - VulkanTextureSubresource *dstSubresource; - VkImageCopy imageCopy; - - srcSubresource = VULKAN_INTERNAL_FetchTextureSubresource( - (VulkanTextureContainer *)source->texture, - source->layer, - source->mip_level); - - dstSubresource = VULKAN_INTERNAL_PrepareTextureSubresourceForWrite( - renderer, - vulkanCommandBuffer, - (VulkanTextureContainer *)destination->texture, - destination->layer, - destination->mip_level, - cycle, - VULKAN_TEXTURE_USAGE_MODE_COPY_DESTINATION); - - VULKAN_INTERNAL_TextureSubresourceTransitionFromDefaultUsage( - renderer, - vulkanCommandBuffer, - VULKAN_TEXTURE_USAGE_MODE_COPY_SOURCE, - srcSubresource); - - imageCopy.srcOffset.x = source->x; - imageCopy.srcOffset.y = source->y; - imageCopy.srcOffset.z = source->z; - imageCopy.srcSubresource.aspectMask = srcSubresource->parent->aspectFlags; - imageCopy.srcSubresource.baseArrayLayer = source->layer; - imageCopy.srcSubresource.layerCount = 1; - imageCopy.srcSubresource.mipLevel = source->mip_level; - imageCopy.dstOffset.x = destination->x; - imageCopy.dstOffset.y = destination->y; - imageCopy.dstOffset.z = destination->z; - imageCopy.dstSubresource.aspectMask = dstSubresource->parent->aspectFlags; - imageCopy.dstSubresource.baseArrayLayer = destination->layer; - imageCopy.dstSubresource.layerCount = 1; - imageCopy.dstSubresource.mipLevel = destination->mip_level; - imageCopy.extent.width = w; - imageCopy.extent.height = h; - imageCopy.extent.depth = d; - - renderer->vkCmdCopyImage( - vulkanCommandBuffer->commandBuffer, - srcSubresource->parent->image, - VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - dstSubresource->parent->image, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - 1, - &imageCopy); - - VULKAN_INTERNAL_TextureSubresourceTransitionToDefaultUsage( - renderer, - vulkanCommandBuffer, - VULKAN_TEXTURE_USAGE_MODE_COPY_SOURCE, - srcSubresource); - - VULKAN_INTERNAL_TextureSubresourceTransitionToDefaultUsage( - renderer, - vulkanCommandBuffer, - VULKAN_TEXTURE_USAGE_MODE_COPY_DESTINATION, - dstSubresource); - - VULKAN_INTERNAL_TrackTexture(vulkanCommandBuffer, srcSubresource->parent); - VULKAN_INTERNAL_TrackTexture(vulkanCommandBuffer, dstSubresource->parent); -} - -static void VULKAN_CopyBufferToBuffer( - SDL_GPUCommandBuffer *commandBuffer, - const SDL_GPUBufferLocation *source, - const SDL_GPUBufferLocation *destination, - Uint32 size, - bool cycle) -{ - VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; - VulkanRenderer *renderer = vulkanCommandBuffer->renderer; - VulkanBufferContainer *srcContainer = (VulkanBufferContainer *)source->buffer; - VulkanBufferContainer *dstContainer = (VulkanBufferContainer *)destination->buffer; - VkBufferCopy bufferCopy; - - VulkanBuffer *dstBuffer = VULKAN_INTERNAL_PrepareBufferForWrite( - renderer, - vulkanCommandBuffer, - dstContainer, - cycle, - VULKAN_BUFFER_USAGE_MODE_COPY_DESTINATION); - - VULKAN_INTERNAL_BufferTransitionFromDefaultUsage( - renderer, - vulkanCommandBuffer, - VULKAN_BUFFER_USAGE_MODE_COPY_SOURCE, - srcContainer->activeBuffer); - - bufferCopy.srcOffset = source->offset; - bufferCopy.dstOffset = destination->offset; - bufferCopy.size = size; - - renderer->vkCmdCopyBuffer( - vulkanCommandBuffer->commandBuffer, - srcContainer->activeBuffer->buffer, - dstBuffer->buffer, - 1, - &bufferCopy); - - VULKAN_INTERNAL_BufferTransitionToDefaultUsage( - renderer, - vulkanCommandBuffer, - VULKAN_BUFFER_USAGE_MODE_COPY_SOURCE, - srcContainer->activeBuffer); - - VULKAN_INTERNAL_BufferTransitionToDefaultUsage( - renderer, - vulkanCommandBuffer, - VULKAN_BUFFER_USAGE_MODE_COPY_DESTINATION, - dstBuffer); - - VULKAN_INTERNAL_TrackBuffer(vulkanCommandBuffer, srcContainer->activeBuffer); - VULKAN_INTERNAL_TrackBuffer(vulkanCommandBuffer, dstBuffer); -} - -static void VULKAN_GenerateMipmaps( - SDL_GPUCommandBuffer *commandBuffer, - SDL_GPUTexture *texture) -{ - VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; - VulkanRenderer *renderer = vulkanCommandBuffer->renderer; - VulkanTextureContainer *container = (VulkanTextureContainer *)texture; - VulkanTextureSubresource *srcTextureSubresource; - VulkanTextureSubresource *dstTextureSubresource; - VkImageBlit blit; - - // Blit each slice sequentially. Barriers, barriers everywhere! - for (Uint32 layerOrDepthIndex = 0; layerOrDepthIndex < container->header.info.layer_count_or_depth; layerOrDepthIndex += 1) - for (Uint32 level = 1; level < container->header.info.num_levels; level += 1) { - Uint32 layer = container->header.info.type == SDL_GPU_TEXTURETYPE_3D ? 0 : layerOrDepthIndex; - Uint32 depth = container->header.info.type == SDL_GPU_TEXTURETYPE_3D ? layerOrDepthIndex : 0; - - Uint32 srcSubresourceIndex = VULKAN_INTERNAL_GetTextureSubresourceIndex( - level - 1, - layer, - container->header.info.num_levels); - Uint32 dstSubresourceIndex = VULKAN_INTERNAL_GetTextureSubresourceIndex( - level, - layer, - container->header.info.num_levels); - - srcTextureSubresource = &container->activeTexture->subresources[srcSubresourceIndex]; - dstTextureSubresource = &container->activeTexture->subresources[dstSubresourceIndex]; - - VULKAN_INTERNAL_TextureSubresourceTransitionFromDefaultUsage( - renderer, - vulkanCommandBuffer, - VULKAN_TEXTURE_USAGE_MODE_COPY_SOURCE, - srcTextureSubresource); - - VULKAN_INTERNAL_TextureSubresourceTransitionFromDefaultUsage( - renderer, - vulkanCommandBuffer, - VULKAN_TEXTURE_USAGE_MODE_COPY_DESTINATION, - dstTextureSubresource); - - blit.srcOffsets[0].x = 0; - blit.srcOffsets[0].y = 0; - blit.srcOffsets[0].z = depth; - - blit.srcOffsets[1].x = container->header.info.width >> (level - 1); - blit.srcOffsets[1].y = container->header.info.height >> (level - 1); - blit.srcOffsets[1].z = depth + 1; - - blit.dstOffsets[0].x = 0; - blit.dstOffsets[0].y = 0; - blit.dstOffsets[0].z = depth; - - blit.dstOffsets[1].x = container->header.info.width >> level; - blit.dstOffsets[1].y = container->header.info.height >> level; - blit.dstOffsets[1].z = depth + 1; - - blit.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - blit.srcSubresource.baseArrayLayer = layer; - blit.srcSubresource.layerCount = 1; - blit.srcSubresource.mipLevel = level - 1; - - blit.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - blit.dstSubresource.baseArrayLayer = layer; - blit.dstSubresource.layerCount = 1; - blit.dstSubresource.mipLevel = level; - - renderer->vkCmdBlitImage( - vulkanCommandBuffer->commandBuffer, - container->activeTexture->image, - VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - container->activeTexture->image, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - 1, - &blit, - VK_FILTER_LINEAR); - - VULKAN_INTERNAL_TextureSubresourceTransitionToDefaultUsage( - renderer, - vulkanCommandBuffer, - VULKAN_TEXTURE_USAGE_MODE_COPY_SOURCE, - srcTextureSubresource); - - VULKAN_INTERNAL_TextureSubresourceTransitionToDefaultUsage( - renderer, - vulkanCommandBuffer, - VULKAN_TEXTURE_USAGE_MODE_COPY_DESTINATION, - dstTextureSubresource); - - VULKAN_INTERNAL_TrackTexture(vulkanCommandBuffer, srcTextureSubresource->parent); - VULKAN_INTERNAL_TrackTexture(vulkanCommandBuffer, dstTextureSubresource->parent); - } -} - -static void VULKAN_EndCopyPass( - SDL_GPUCommandBuffer *commandBuffer) -{ - // no-op - (void)commandBuffer; -} - -static void VULKAN_Blit( - SDL_GPUCommandBuffer *commandBuffer, - const SDL_GPUBlitInfo *info) -{ - VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; - VulkanRenderer *renderer = vulkanCommandBuffer->renderer; - TextureCommonHeader *srcHeader = (TextureCommonHeader *)info->source.texture; - TextureCommonHeader *dstHeader = (TextureCommonHeader *)info->destination.texture; - VkImageBlit region; - Uint32 srcLayer = srcHeader->info.type == SDL_GPU_TEXTURETYPE_3D ? 0 : info->source.layer_or_depth_plane; - Uint32 srcDepth = srcHeader->info.type == SDL_GPU_TEXTURETYPE_3D ? info->source.layer_or_depth_plane : 0; - Uint32 dstLayer = dstHeader->info.type == SDL_GPU_TEXTURETYPE_3D ? 0 : info->destination.layer_or_depth_plane; - Uint32 dstDepth = dstHeader->info.type == SDL_GPU_TEXTURETYPE_3D ? info->destination.layer_or_depth_plane : 0; - int32_t swap; - - // Using BeginRenderPass to clear because vkCmdClearColorImage requires barriers anyway - if (info->load_op == SDL_GPU_LOADOP_CLEAR) { - SDL_GPUColorTargetInfo targetInfo; - SDL_zero(targetInfo); - targetInfo.texture = info->destination.texture; - targetInfo.mip_level = info->destination.mip_level; - targetInfo.layer_or_depth_plane = info->destination.layer_or_depth_plane; - targetInfo.load_op = SDL_GPU_LOADOP_CLEAR; - targetInfo.store_op = SDL_GPU_STOREOP_STORE; - targetInfo.clear_color = info->clear_color; - targetInfo.cycle = info->cycle; - VULKAN_BeginRenderPass( - commandBuffer, - &targetInfo, - 1, - NULL); - VULKAN_EndRenderPass(commandBuffer); - } - - VulkanTextureSubresource *srcSubresource = VULKAN_INTERNAL_FetchTextureSubresource( - (VulkanTextureContainer *)info->source.texture, - srcLayer, - info->source.mip_level); - - VulkanTextureSubresource *dstSubresource = VULKAN_INTERNAL_PrepareTextureSubresourceForWrite( - renderer, - vulkanCommandBuffer, - (VulkanTextureContainer *)info->destination.texture, - dstLayer, - info->destination.mip_level, - info->cycle, - VULKAN_TEXTURE_USAGE_MODE_COPY_DESTINATION); - - VULKAN_INTERNAL_TextureSubresourceTransitionFromDefaultUsage( - renderer, - vulkanCommandBuffer, - VULKAN_TEXTURE_USAGE_MODE_COPY_SOURCE, - srcSubresource); - - region.srcSubresource.aspectMask = srcSubresource->parent->aspectFlags; - region.srcSubresource.baseArrayLayer = srcSubresource->layer; - region.srcSubresource.layerCount = 1; - region.srcSubresource.mipLevel = srcSubresource->level; - region.srcOffsets[0].x = info->source.x; - region.srcOffsets[0].y = info->source.y; - region.srcOffsets[0].z = srcDepth; - region.srcOffsets[1].x = info->source.x + info->source.w; - region.srcOffsets[1].y = info->source.y + info->source.h; - region.srcOffsets[1].z = srcDepth + 1; - - if (info->flip_mode & SDL_FLIP_HORIZONTAL) { - // flip the x positions - swap = region.srcOffsets[0].x; - region.srcOffsets[0].x = region.srcOffsets[1].x; - region.srcOffsets[1].x = swap; - } - - if (info->flip_mode & SDL_FLIP_VERTICAL) { - // flip the y positions - swap = region.srcOffsets[0].y; - region.srcOffsets[0].y = region.srcOffsets[1].y; - region.srcOffsets[1].y = swap; - } - - region.dstSubresource.aspectMask = dstSubresource->parent->aspectFlags; - region.dstSubresource.baseArrayLayer = dstSubresource->layer; - region.dstSubresource.layerCount = 1; - region.dstSubresource.mipLevel = dstSubresource->level; - region.dstOffsets[0].x = info->destination.x; - region.dstOffsets[0].y = info->destination.y; - region.dstOffsets[0].z = dstDepth; - region.dstOffsets[1].x = info->destination.x + info->destination.w; - region.dstOffsets[1].y = info->destination.y + info->destination.h; - region.dstOffsets[1].z = dstDepth + 1; - - renderer->vkCmdBlitImage( - vulkanCommandBuffer->commandBuffer, - srcSubresource->parent->image, - VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - dstSubresource->parent->image, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - 1, - ®ion, - SDLToVK_Filter[info->filter]); - - VULKAN_INTERNAL_TextureSubresourceTransitionToDefaultUsage( - renderer, - vulkanCommandBuffer, - VULKAN_TEXTURE_USAGE_MODE_COPY_SOURCE, - srcSubresource); - - VULKAN_INTERNAL_TextureSubresourceTransitionToDefaultUsage( - renderer, - vulkanCommandBuffer, - VULKAN_TEXTURE_USAGE_MODE_COPY_DESTINATION, - dstSubresource); - - VULKAN_INTERNAL_TrackTexture(vulkanCommandBuffer, srcSubresource->parent); - VULKAN_INTERNAL_TrackTexture(vulkanCommandBuffer, dstSubresource->parent); -} - -static bool VULKAN_INTERNAL_AllocateCommandBuffer( - VulkanRenderer *renderer, - VulkanCommandPool *vulkanCommandPool) -{ - VkCommandBufferAllocateInfo allocateInfo; - VkResult vulkanResult; - VkCommandBuffer commandBufferHandle; - VulkanCommandBuffer *commandBuffer; - - vulkanCommandPool->inactiveCommandBufferCapacity += 1; - - vulkanCommandPool->inactiveCommandBuffers = SDL_realloc( - vulkanCommandPool->inactiveCommandBuffers, - sizeof(VulkanCommandBuffer *) * - vulkanCommandPool->inactiveCommandBufferCapacity); - - allocateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; - allocateInfo.pNext = NULL; - allocateInfo.commandPool = vulkanCommandPool->commandPool; - allocateInfo.commandBufferCount = 1; - allocateInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; - - vulkanResult = renderer->vkAllocateCommandBuffers( - renderer->logicalDevice, - &allocateInfo, - &commandBufferHandle); - - CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkAllocateCommandBuffers, false); - - commandBuffer = SDL_malloc(sizeof(VulkanCommandBuffer)); - commandBuffer->renderer = renderer; - commandBuffer->commandPool = vulkanCommandPool; - commandBuffer->commandBuffer = commandBufferHandle; - - commandBuffer->inFlightFence = VK_NULL_HANDLE; - - // Presentation tracking - - commandBuffer->presentDataCapacity = 1; - commandBuffer->presentDataCount = 0; - commandBuffer->presentDatas = SDL_malloc( - commandBuffer->presentDataCapacity * sizeof(VulkanPresentData)); - - 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)); - - // Resource bind tracking - - commandBuffer->needVertexBufferBind = false; - commandBuffer->needNewVertexResourceDescriptorSet = true; - commandBuffer->needNewVertexUniformDescriptorSet = true; - commandBuffer->needNewVertexUniformOffsets = true; - commandBuffer->needNewFragmentResourceDescriptorSet = true; - commandBuffer->needNewFragmentUniformDescriptorSet = true; - commandBuffer->needNewFragmentUniformOffsets = true; - - commandBuffer->needNewComputeReadWriteDescriptorSet = true; - commandBuffer->needNewComputeReadOnlyDescriptorSet = true; - commandBuffer->needNewComputeUniformDescriptorSet = true; - commandBuffer->needNewComputeUniformOffsets = true; - - commandBuffer->vertexResourceDescriptorSet = VK_NULL_HANDLE; - commandBuffer->vertexUniformDescriptorSet = VK_NULL_HANDLE; - commandBuffer->fragmentResourceDescriptorSet = VK_NULL_HANDLE; - commandBuffer->fragmentUniformDescriptorSet = VK_NULL_HANDLE; - - commandBuffer->computeReadOnlyDescriptorSet = VK_NULL_HANDLE; - commandBuffer->computeReadWriteDescriptorSet = VK_NULL_HANDLE; - commandBuffer->computeUniformDescriptorSet = VK_NULL_HANDLE; - - // Resource tracking - - commandBuffer->usedBufferCapacity = 4; - commandBuffer->usedBufferCount = 0; - commandBuffer->usedBuffers = SDL_malloc( - commandBuffer->usedBufferCapacity * sizeof(VulkanBuffer *)); - - commandBuffer->usedTextureCapacity = 4; - commandBuffer->usedTextureCount = 0; - commandBuffer->usedTextures = SDL_malloc( - commandBuffer->usedTextureCapacity * sizeof(VulkanTexture *)); - - commandBuffer->usedSamplerCapacity = 4; - commandBuffer->usedSamplerCount = 0; - commandBuffer->usedSamplers = SDL_malloc( - commandBuffer->usedSamplerCapacity * sizeof(VulkanSampler *)); - - commandBuffer->usedGraphicsPipelineCapacity = 4; - commandBuffer->usedGraphicsPipelineCount = 0; - commandBuffer->usedGraphicsPipelines = SDL_malloc( - commandBuffer->usedGraphicsPipelineCapacity * sizeof(VulkanGraphicsPipeline *)); - - commandBuffer->usedComputePipelineCapacity = 4; - commandBuffer->usedComputePipelineCount = 0; - commandBuffer->usedComputePipelines = SDL_malloc( - commandBuffer->usedComputePipelineCapacity * sizeof(VulkanComputePipeline *)); - - commandBuffer->usedFramebufferCapacity = 4; - commandBuffer->usedFramebufferCount = 0; - commandBuffer->usedFramebuffers = SDL_malloc( - commandBuffer->usedFramebufferCapacity * sizeof(VulkanFramebuffer *)); - - commandBuffer->usedUniformBufferCapacity = 4; - commandBuffer->usedUniformBufferCount = 0; - commandBuffer->usedUniformBuffers = SDL_malloc( - commandBuffer->usedUniformBufferCapacity * sizeof(VulkanUniformBuffer *)); - - // Pool it! - - vulkanCommandPool->inactiveCommandBuffers[vulkanCommandPool->inactiveCommandBufferCount] = commandBuffer; - vulkanCommandPool->inactiveCommandBufferCount += 1; - - return true; -} - -static VulkanCommandPool *VULKAN_INTERNAL_FetchCommandPool( - VulkanRenderer *renderer, - SDL_ThreadID threadID) -{ - VulkanCommandPool *vulkanCommandPool = NULL; - VkCommandPoolCreateInfo commandPoolCreateInfo; - VkResult vulkanResult; - CommandPoolHashTableKey key; - key.threadID = threadID; - - bool result = SDL_FindInHashTable( - renderer->commandPoolHashTable, - (const void *)&key, - (const void **)&vulkanCommandPool); - - if (result) { - return vulkanCommandPool; - } - - vulkanCommandPool = (VulkanCommandPool *)SDL_malloc(sizeof(VulkanCommandPool)); - - commandPoolCreateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; - commandPoolCreateInfo.pNext = NULL; - commandPoolCreateInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; - commandPoolCreateInfo.queueFamilyIndex = renderer->queueFamilyIndex; - - vulkanResult = renderer->vkCreateCommandPool( - renderer->logicalDevice, - &commandPoolCreateInfo, - NULL, - &vulkanCommandPool->commandPool); - - if (vulkanResult != VK_SUCCESS) { - SDL_free(vulkanCommandPool); - CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkCreateCommandPool, NULL); - return NULL; - } - - vulkanCommandPool->threadID = threadID; - - vulkanCommandPool->inactiveCommandBufferCapacity = 0; - vulkanCommandPool->inactiveCommandBufferCount = 0; - vulkanCommandPool->inactiveCommandBuffers = NULL; - - if (!VULKAN_INTERNAL_AllocateCommandBuffer( - renderer, - vulkanCommandPool)) { - VULKAN_INTERNAL_DestroyCommandPool(renderer, vulkanCommandPool); - return NULL; - } - - CommandPoolHashTableKey *allocedKey = SDL_malloc(sizeof(CommandPoolHashTableKey)); - allocedKey->threadID = threadID; - - SDL_InsertIntoHashTable( - renderer->commandPoolHashTable, - (const void *)allocedKey, - (const void *)vulkanCommandPool, true); - - return vulkanCommandPool; -} - -static VulkanCommandBuffer *VULKAN_INTERNAL_GetInactiveCommandBufferFromPool( - VulkanRenderer *renderer, - SDL_ThreadID threadID) -{ - VulkanCommandPool *commandPool = - VULKAN_INTERNAL_FetchCommandPool(renderer, threadID); - VulkanCommandBuffer *commandBuffer; - - if (commandPool == NULL) { - return NULL; - } - - if (commandPool->inactiveCommandBufferCount == 0) { - if (!VULKAN_INTERNAL_AllocateCommandBuffer( - renderer, - commandPool)) { - return NULL; - } - } - - commandBuffer = commandPool->inactiveCommandBuffers[commandPool->inactiveCommandBufferCount - 1]; - commandPool->inactiveCommandBufferCount -= 1; - - return commandBuffer; -} - -static SDL_GPUCommandBuffer *VULKAN_AcquireCommandBuffer( - SDL_GPURenderer *driverData) -{ - VulkanRenderer *renderer = (VulkanRenderer *)driverData; - VkResult result; - Uint32 i; - - SDL_ThreadID threadID = SDL_GetCurrentThreadID(); - - SDL_LockMutex(renderer->acquireCommandBufferLock); - - VulkanCommandBuffer *commandBuffer = - VULKAN_INTERNAL_GetInactiveCommandBufferFromPool(renderer, threadID); - - commandBuffer->descriptorSetCache = VULKAN_INTERNAL_AcquireDescriptorSetCache(renderer); - - SDL_UnlockMutex(renderer->acquireCommandBufferLock); - - if (commandBuffer == NULL) { - return NULL; - } - - // Reset state - - commandBuffer->currentComputePipeline = NULL; - commandBuffer->currentGraphicsPipeline = NULL; - - SDL_zeroa(commandBuffer->colorAttachmentSubresources); - SDL_zeroa(commandBuffer->resolveAttachmentSubresources); - commandBuffer->depthStencilAttachmentSubresource = NULL; - commandBuffer->colorAttachmentSubresourceCount = 0; - commandBuffer->resolveAttachmentSubresourceCount = 0; - - for (i = 0; i < MAX_UNIFORM_BUFFERS_PER_STAGE; i += 1) { - commandBuffer->vertexUniformBuffers[i] = NULL; - commandBuffer->fragmentUniformBuffers[i] = NULL; - commandBuffer->computeUniformBuffers[i] = NULL; - } - - commandBuffer->needVertexBufferBind = false; - commandBuffer->needNewVertexResourceDescriptorSet = true; - commandBuffer->needNewVertexUniformDescriptorSet = true; - commandBuffer->needNewVertexUniformOffsets = true; - commandBuffer->needNewFragmentResourceDescriptorSet = true; - commandBuffer->needNewFragmentUniformDescriptorSet = true; - commandBuffer->needNewFragmentUniformOffsets = true; - - commandBuffer->needNewComputeReadOnlyDescriptorSet = true; - commandBuffer->needNewComputeUniformDescriptorSet = true; - commandBuffer->needNewComputeUniformOffsets = true; - - commandBuffer->vertexResourceDescriptorSet = VK_NULL_HANDLE; - commandBuffer->vertexUniformDescriptorSet = VK_NULL_HANDLE; - commandBuffer->fragmentResourceDescriptorSet = VK_NULL_HANDLE; - commandBuffer->fragmentUniformDescriptorSet = VK_NULL_HANDLE; - - commandBuffer->computeReadOnlyDescriptorSet = VK_NULL_HANDLE; - commandBuffer->computeReadWriteDescriptorSet = VK_NULL_HANDLE; - commandBuffer->computeUniformDescriptorSet = VK_NULL_HANDLE; - - SDL_zeroa(commandBuffer->vertexBuffers); - SDL_zeroa(commandBuffer->vertexBufferOffsets); - commandBuffer->vertexBufferCount = 0; - - SDL_zeroa(commandBuffer->vertexSamplerTextures); - SDL_zeroa(commandBuffer->vertexSamplers); - SDL_zeroa(commandBuffer->vertexStorageTextures); - SDL_zeroa(commandBuffer->vertexStorageBuffers); - - SDL_zeroa(commandBuffer->fragmentSamplerTextures); - SDL_zeroa(commandBuffer->fragmentSamplers); - SDL_zeroa(commandBuffer->fragmentStorageTextures); - SDL_zeroa(commandBuffer->fragmentStorageBuffers); - - SDL_zeroa(commandBuffer->readWriteComputeStorageTextureSubresources); - commandBuffer->readWriteComputeStorageTextureSubresourceCount = 0; - SDL_zeroa(commandBuffer->readWriteComputeStorageBuffers); - SDL_zeroa(commandBuffer->computeSamplerTextures); - SDL_zeroa(commandBuffer->computeSamplers); - SDL_zeroa(commandBuffer->readOnlyComputeStorageTextures); - SDL_zeroa(commandBuffer->readOnlyComputeStorageBuffers); - - commandBuffer->autoReleaseFence = true; - - commandBuffer->isDefrag = 0; - - /* Reset the command buffer here to avoid resets being called - * from a separate thread than where the command buffer was acquired - */ - result = renderer->vkResetCommandBuffer( - commandBuffer->commandBuffer, - VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT); - - CHECK_VULKAN_ERROR_AND_RETURN(result, vkResetCommandBuffer, NULL); - - if (!VULKAN_INTERNAL_BeginCommandBuffer(renderer, commandBuffer)) { - return NULL; - } - - return (SDL_GPUCommandBuffer *)commandBuffer; -} - -static bool VULKAN_QueryFence( - SDL_GPURenderer *driverData, - SDL_GPUFence *fence) -{ - VulkanRenderer *renderer = (VulkanRenderer *)driverData; - VkResult result; - - result = renderer->vkGetFenceStatus( - renderer->logicalDevice, - ((VulkanFenceHandle *)fence)->fence); - - if (result == VK_SUCCESS) { - return true; - } else if (result == VK_NOT_READY) { - return false; - } else { - SET_ERROR_AND_RETURN("vkGetFenceStatus: %s", VkErrorMessages(result), false); - } -} - -static void VULKAN_INTERNAL_ReturnFenceToPool( - VulkanRenderer *renderer, - VulkanFenceHandle *fenceHandle) -{ - SDL_LockMutex(renderer->fencePool.lock); - - EXPAND_ARRAY_IF_NEEDED( - renderer->fencePool.availableFences, - VulkanFenceHandle *, - renderer->fencePool.availableFenceCount + 1, - renderer->fencePool.availableFenceCapacity, - renderer->fencePool.availableFenceCapacity * 2); - - renderer->fencePool.availableFences[renderer->fencePool.availableFenceCount] = fenceHandle; - renderer->fencePool.availableFenceCount += 1; - - SDL_UnlockMutex(renderer->fencePool.lock); -} - -static void VULKAN_ReleaseFence( - SDL_GPURenderer *driverData, - SDL_GPUFence *fence) -{ - VulkanFenceHandle *handle = (VulkanFenceHandle *)fence; - - if (SDL_AtomicDecRef(&handle->referenceCount)) { - VULKAN_INTERNAL_ReturnFenceToPool((VulkanRenderer *)driverData, handle); - } -} - -static WindowData *VULKAN_INTERNAL_FetchWindowData( - SDL_Window *window) -{ - SDL_PropertiesID properties = SDL_GetWindowProperties(window); - return (WindowData *)SDL_GetPointerProperty(properties, WINDOW_PROPERTY_DATA, NULL); -} - -static bool VULKAN_INTERNAL_OnWindowResize(void *userdata, SDL_Event *e) -{ - SDL_Window *w = (SDL_Window *)userdata; - WindowData *data; - if (e->type == SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED && e->window.windowID == SDL_GetWindowID(w)) { - data = VULKAN_INTERNAL_FetchWindowData(w); - data->needsSwapchainRecreate = true; - data->swapchainCreateWidth = e->window.data1; - data->swapchainCreateHeight = e->window.data2; - } - - return true; -} - -static bool VULKAN_SupportsSwapchainComposition( - SDL_GPURenderer *driverData, - SDL_Window *window, - SDL_GPUSwapchainComposition swapchainComposition) -{ - VulkanRenderer *renderer = (VulkanRenderer *)driverData; - WindowData *windowData = VULKAN_INTERNAL_FetchWindowData(window); - VkSurfaceKHR surface; - SwapchainSupportDetails supportDetails; - bool result = false; - - if (windowData == NULL) { - SET_STRING_ERROR_AND_RETURN("Must claim window before querying swapchain composition support!", false); - } - - surface = windowData->surface; - if (!surface) { - SET_STRING_ERROR_AND_RETURN("Window has no Vulkan surface", false); - } - - if (VULKAN_INTERNAL_QuerySwapchainSupport( - renderer, - renderer->physicalDevice, - surface, - &supportDetails)) { - - result = VULKAN_INTERNAL_VerifySwapSurfaceFormat( - SwapchainCompositionToFormat[swapchainComposition], - SwapchainCompositionToColorSpace[swapchainComposition], - supportDetails.formats, - supportDetails.formatsLength); - - if (!result) { - // Let's try again with the fallback format... - result = VULKAN_INTERNAL_VerifySwapSurfaceFormat( - SwapchainCompositionToFallbackFormat[swapchainComposition], - SwapchainCompositionToColorSpace[swapchainComposition], - supportDetails.formats, - supportDetails.formatsLength); - } - - SDL_free(supportDetails.formats); - SDL_free(supportDetails.presentModes); - } - - return result; -} - -static bool VULKAN_SupportsPresentMode( - SDL_GPURenderer *driverData, - SDL_Window *window, - SDL_GPUPresentMode presentMode) -{ - VulkanRenderer *renderer = (VulkanRenderer *)driverData; - WindowData *windowData = VULKAN_INTERNAL_FetchWindowData(window); - VkSurfaceKHR surface; - SwapchainSupportDetails supportDetails; - bool result = false; - - if (windowData == NULL) { - SET_STRING_ERROR_AND_RETURN("Must claim window before querying present mode support!", false); - } - - surface = windowData->surface; - if (!surface) { - SET_STRING_ERROR_AND_RETURN("Window has no Vulkan surface", false); - } - - if (VULKAN_INTERNAL_QuerySwapchainSupport( - renderer, - renderer->physicalDevice, - surface, - &supportDetails)) { - - result = VULKAN_INTERNAL_VerifySwapPresentMode( - SDLToVK_PresentMode[presentMode], - supportDetails.presentModes, - supportDetails.presentModesLength); - - SDL_free(supportDetails.formats); - SDL_free(supportDetails.presentModes); - } - - return result; -} - -static bool VULKAN_ClaimWindow( - SDL_GPURenderer *driverData, - SDL_Window *window) -{ - VulkanRenderer *renderer = (VulkanRenderer *)driverData; - WindowData *windowData = VULKAN_INTERNAL_FetchWindowData(window); - - if (windowData == NULL) { - windowData = SDL_calloc(1, sizeof(WindowData)); - windowData->window = window; - windowData->presentMode = SDL_GPU_PRESENTMODE_VSYNC; - windowData->swapchainComposition = SDL_GPU_SWAPCHAINCOMPOSITION_SDR; - - // On non-Apple platforms the swapchain capability currentExtent can be different from the window, - // so we have to query the window size. -#ifndef SDL_PLATFORM_APPLE - int w, h; - SDL_SyncWindow(window); - SDL_GetWindowSizeInPixels(window, &w, &h); - windowData->swapchainCreateWidth = w; - windowData->swapchainCreateHeight = h; -#endif - - Uint32 createSwapchainResult = VULKAN_INTERNAL_CreateSwapchain(renderer, windowData); - if (createSwapchainResult == 1) { - SDL_SetPointerProperty(SDL_GetWindowProperties(window), WINDOW_PROPERTY_DATA, windowData); - - SDL_LockMutex(renderer->windowLock); - if (renderer->claimedWindowCount >= renderer->claimedWindowCapacity) { - renderer->claimedWindowCapacity *= 2; - renderer->claimedWindows = SDL_realloc( - renderer->claimedWindows, - renderer->claimedWindowCapacity * sizeof(WindowData *)); - } - - renderer->claimedWindows[renderer->claimedWindowCount] = windowData; - renderer->claimedWindowCount += 1; - SDL_UnlockMutex(renderer->windowLock); - - SDL_AddEventWatch(VULKAN_INTERNAL_OnWindowResize, window); - - return true; - } else if (createSwapchainResult == VULKAN_INTERNAL_TRY_AGAIN) { - windowData->needsSwapchainRecreate = true; - return true; - } else { - SDL_free(windowData); - return false; - } - } else { - SET_STRING_ERROR_AND_RETURN("Window already claimed!", false); - } -} - -static void VULKAN_ReleaseWindow( - SDL_GPURenderer *driverData, - SDL_Window *window) -{ - VulkanRenderer *renderer = (VulkanRenderer *)driverData; - WindowData *windowData = VULKAN_INTERNAL_FetchWindowData(window); - Uint32 i; - - if (windowData == NULL) { - return; - } - - VULKAN_Wait(driverData); - - for (i = 0; i < MAX_FRAMES_IN_FLIGHT; i += 1) { - if (windowData->inFlightFences[i] != NULL) { - VULKAN_ReleaseFence( - driverData, - windowData->inFlightFences[i]); - } - } - - VULKAN_INTERNAL_DestroySwapchain( - (VulkanRenderer *)driverData, - windowData); - - - SDL_LockMutex(renderer->windowLock); - for (i = 0; i < renderer->claimedWindowCount; i += 1) { - if (renderer->claimedWindows[i]->window == window) { - renderer->claimedWindows[i] = renderer->claimedWindows[renderer->claimedWindowCount - 1]; - renderer->claimedWindowCount -= 1; - break; - } - } - SDL_UnlockMutex(renderer->windowLock); - - SDL_free(windowData); - - SDL_ClearProperty(SDL_GetWindowProperties(window), WINDOW_PROPERTY_DATA); - SDL_RemoveEventWatch(VULKAN_INTERNAL_OnWindowResize, window); -} - -static Uint32 VULKAN_INTERNAL_RecreateSwapchain( - VulkanRenderer *renderer, - WindowData *windowData) -{ - Uint32 i; - - if (!VULKAN_Wait((SDL_GPURenderer *)renderer)) { - return false; - } - - for (i = 0; i < MAX_FRAMES_IN_FLIGHT; i += 1) { - if (windowData->inFlightFences[i] != NULL) { - VULKAN_ReleaseFence( - (SDL_GPURenderer *)renderer, - windowData->inFlightFences[i]); - windowData->inFlightFences[i] = NULL; - } - } - - VULKAN_INTERNAL_DestroySwapchain(renderer, windowData); - return VULKAN_INTERNAL_CreateSwapchain(renderer, windowData); -} - -static bool VULKAN_WaitForSwapchain( - SDL_GPURenderer *driverData, - SDL_Window *window) -{ - VulkanRenderer *renderer = (VulkanRenderer *)driverData; - WindowData *windowData = VULKAN_INTERNAL_FetchWindowData(window); - - if (windowData == NULL) { - SET_STRING_ERROR_AND_RETURN("Cannot wait for a swapchain from an unclaimed window!", false); - } - - if (windowData->inFlightFences[windowData->frameCounter] != NULL) { - if (!VULKAN_WaitForFences( - driverData, - true, - &windowData->inFlightFences[windowData->frameCounter], - 1)) { - return false; - } - } - - return true; -} - -static bool VULKAN_INTERNAL_AcquireSwapchainTexture( - bool block, - SDL_GPUCommandBuffer *commandBuffer, - SDL_Window *window, - SDL_GPUTexture **swapchainTexture, - Uint32 *swapchainTextureWidth, - Uint32 *swapchainTextureHeight) -{ - VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; - VulkanRenderer *renderer = vulkanCommandBuffer->renderer; - Uint32 swapchainImageIndex; - WindowData *windowData; - VkResult acquireResult = VK_SUCCESS; - VulkanTextureContainer *swapchainTextureContainer = NULL; - VulkanPresentData *presentData; - - *swapchainTexture = NULL; - if (swapchainTextureWidth) { - *swapchainTextureWidth = 0; - } - if (swapchainTextureHeight) { - *swapchainTextureHeight = 0; - } - - windowData = VULKAN_INTERNAL_FetchWindowData(window); - if (windowData == NULL) { - SET_STRING_ERROR_AND_RETURN("Cannot acquire a swapchain texture from an unclaimed window!", false); - } - - // If window data marked as needing swapchain recreate, try to recreate - if (windowData->needsSwapchainRecreate) { - Uint32 recreateSwapchainResult = VULKAN_INTERNAL_RecreateSwapchain(renderer, windowData); - if (!recreateSwapchainResult) { - return false; - } else if (recreateSwapchainResult == VULKAN_INTERNAL_TRY_AGAIN) { - // Edge case, texture is filled in with NULL but not an error - if (windowData->inFlightFences[windowData->frameCounter] != NULL) { - VULKAN_ReleaseFence( - (SDL_GPURenderer *)renderer, - windowData->inFlightFences[windowData->frameCounter]); - windowData->inFlightFences[windowData->frameCounter] = NULL; - } - return true; - } - } - - if (swapchainTextureWidth) { - *swapchainTextureWidth = windowData->width; - } - if (swapchainTextureHeight) { - *swapchainTextureHeight = windowData->height; - } - - if (windowData->inFlightFences[windowData->frameCounter] != NULL) { - if (block) { - // If we are blocking, just wait for the fence! - if (!VULKAN_WaitForFences( - (SDL_GPURenderer *)renderer, - true, - &windowData->inFlightFences[windowData->frameCounter], - 1)) { - return false; - } - } else { - // If we are not blocking and the least recent fence is not signaled, - // return true to indicate that there is no error but rendering should be skipped. - if (!VULKAN_QueryFence( - (SDL_GPURenderer *)renderer, - windowData->inFlightFences[windowData->frameCounter])) { - return true; - } - } - - VULKAN_ReleaseFence( - (SDL_GPURenderer *)renderer, - windowData->inFlightFences[windowData->frameCounter]); - - windowData->inFlightFences[windowData->frameCounter] = NULL; - } - - // Finally, try to acquire! - while (true) { - acquireResult = renderer->vkAcquireNextImageKHR( - renderer->logicalDevice, - windowData->swapchain, - SDL_MAX_UINT64, - windowData->imageAvailableSemaphore[windowData->frameCounter], - VK_NULL_HANDLE, - &swapchainImageIndex); - - if (acquireResult == VK_SUCCESS || acquireResult == VK_SUBOPTIMAL_KHR) { - break; // we got the next image! - } - - // If acquisition is invalid, let's try to recreate - Uint32 recreateSwapchainResult = VULKAN_INTERNAL_RecreateSwapchain(renderer, windowData); - if (!recreateSwapchainResult) { - return false; - } else if (recreateSwapchainResult == VULKAN_INTERNAL_TRY_AGAIN) { - // Edge case, texture is filled in with NULL but not an error - return true; - } - } - - swapchainTextureContainer = &windowData->textureContainers[swapchainImageIndex]; - - // We need a special execution dependency with pWaitDstStageMask or image transition can start before acquire finishes - - VkImageMemoryBarrier imageBarrier; - imageBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; - imageBarrier.pNext = NULL; - imageBarrier.srcAccessMask = 0; - imageBarrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; - imageBarrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; - imageBarrier.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - imageBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - imageBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - imageBarrier.image = swapchainTextureContainer->activeTexture->image; - imageBarrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - imageBarrier.subresourceRange.baseMipLevel = 0; - imageBarrier.subresourceRange.levelCount = 1; - imageBarrier.subresourceRange.baseArrayLayer = 0; - imageBarrier.subresourceRange.layerCount = 1; - - renderer->vkCmdPipelineBarrier( - vulkanCommandBuffer->commandBuffer, - VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, - VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, - 0, - 0, - NULL, - 0, - NULL, - 1, - &imageBarrier); - - // Set up present struct - - if (vulkanCommandBuffer->presentDataCount == vulkanCommandBuffer->presentDataCapacity) { - vulkanCommandBuffer->presentDataCapacity += 1; - vulkanCommandBuffer->presentDatas = SDL_realloc( - vulkanCommandBuffer->presentDatas, - vulkanCommandBuffer->presentDataCapacity * sizeof(VulkanPresentData)); - } - - presentData = &vulkanCommandBuffer->presentDatas[vulkanCommandBuffer->presentDataCount]; - vulkanCommandBuffer->presentDataCount += 1; - - presentData->windowData = windowData; - 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] = - windowData->imageAvailableSemaphore[windowData->frameCounter]; - 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] = - windowData->renderFinishedSemaphore[windowData->frameCounter]; - vulkanCommandBuffer->signalSemaphoreCount += 1; - - *swapchainTexture = (SDL_GPUTexture *)swapchainTextureContainer; - return true; -} - -static bool VULKAN_AcquireSwapchainTexture( - SDL_GPUCommandBuffer *command_buffer, - SDL_Window *window, - SDL_GPUTexture **swapchain_texture, - Uint32 *swapchain_texture_width, - Uint32 *swapchain_texture_height -) { - return VULKAN_INTERNAL_AcquireSwapchainTexture( - false, - command_buffer, - window, - swapchain_texture, - swapchain_texture_width, - swapchain_texture_height); -} - -static bool VULKAN_WaitAndAcquireSwapchainTexture( - SDL_GPUCommandBuffer *command_buffer, - SDL_Window *window, - SDL_GPUTexture **swapchain_texture, - Uint32 *swapchain_texture_width, - Uint32 *swapchain_texture_height -) { - return VULKAN_INTERNAL_AcquireSwapchainTexture( - true, - command_buffer, - window, - swapchain_texture, - swapchain_texture_width, - swapchain_texture_height); -} - -static SDL_GPUTextureFormat VULKAN_GetSwapchainTextureFormat( - SDL_GPURenderer *driverData, - SDL_Window *window) -{ - VulkanRenderer *renderer = (VulkanRenderer*)driverData; - WindowData *windowData = VULKAN_INTERNAL_FetchWindowData(window); - - if (windowData == NULL) { - SET_STRING_ERROR_AND_RETURN("Cannot get swapchain format, window has not been claimed!", SDL_GPU_TEXTUREFORMAT_INVALID); - } - - return SwapchainCompositionToSDLFormat( - windowData->swapchainComposition, - windowData->usingFallbackFormat); -} - -static bool VULKAN_SetSwapchainParameters( - SDL_GPURenderer *driverData, - SDL_Window *window, - SDL_GPUSwapchainComposition swapchainComposition, - SDL_GPUPresentMode presentMode) -{ - VulkanRenderer *renderer = (VulkanRenderer *)driverData; - WindowData *windowData = VULKAN_INTERNAL_FetchWindowData(window); - - if (windowData == NULL) { - SET_STRING_ERROR_AND_RETURN("Cannot set swapchain parameters on unclaimed window!", false); - } - - if (!VULKAN_SupportsSwapchainComposition(driverData, window, swapchainComposition)) { - SET_STRING_ERROR_AND_RETURN("Swapchain composition not supported!", false); - } - - if (!VULKAN_SupportsPresentMode(driverData, window, presentMode)) { - SET_STRING_ERROR_AND_RETURN("Present mode not supported!", false); - } - - windowData->presentMode = presentMode; - windowData->swapchainComposition = swapchainComposition; - - Uint32 recreateSwapchainResult = VULKAN_INTERNAL_RecreateSwapchain(renderer, windowData); - if (!recreateSwapchainResult) { - return false; - } else if (recreateSwapchainResult == VULKAN_INTERNAL_TRY_AGAIN) { - // Edge case, swapchain extent is (0, 0) but this is not an error - windowData->needsSwapchainRecreate = true; - return true; - } - - return true; -} - -static bool VULKAN_SetAllowedFramesInFlight( - SDL_GPURenderer *driverData, - Uint32 allowedFramesInFlight) -{ - VulkanRenderer *renderer = (VulkanRenderer *)driverData; - - renderer->allowedFramesInFlight = allowedFramesInFlight; - - for (Uint32 i = 0; i < renderer->claimedWindowCount; i += 1) { - WindowData *windowData = renderer->claimedWindows[i]; - - Uint32 recreateResult = VULKAN_INTERNAL_RecreateSwapchain(renderer, windowData); - if (!recreateResult) { - return false; - } else if (recreateResult == VULKAN_INTERNAL_TRY_AGAIN) { - // Edge case, swapchain extent is (0, 0) but this is not an error - windowData->needsSwapchainRecreate = true; - } - } - - return true; -} - -// Submission structure - -static VulkanFenceHandle *VULKAN_INTERNAL_AcquireFenceFromPool( - VulkanRenderer *renderer) -{ - VulkanFenceHandle *handle; - VkFenceCreateInfo fenceCreateInfo; - VkFence fence; - VkResult vulkanResult; - - if (renderer->fencePool.availableFenceCount == 0) { - // Create fence - fenceCreateInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; - fenceCreateInfo.pNext = NULL; - fenceCreateInfo.flags = 0; - - vulkanResult = renderer->vkCreateFence( - renderer->logicalDevice, - &fenceCreateInfo, - NULL, - &fence); - - CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkCreateFence, NULL); - - handle = SDL_malloc(sizeof(VulkanFenceHandle)); - handle->fence = fence; - SDL_SetAtomicInt(&handle->referenceCount, 0); - return handle; - } - - SDL_LockMutex(renderer->fencePool.lock); - - handle = renderer->fencePool.availableFences[renderer->fencePool.availableFenceCount - 1]; - renderer->fencePool.availableFenceCount -= 1; - - vulkanResult = renderer->vkResetFences( - renderer->logicalDevice, - 1, - &handle->fence); - - SDL_UnlockMutex(renderer->fencePool.lock); - - CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkResetFences, NULL); - - return handle; -} - -static void VULKAN_INTERNAL_PerformPendingDestroys( - VulkanRenderer *renderer) -{ - SDL_LockMutex(renderer->disposeLock); - - for (Sint32 i = renderer->texturesToDestroyCount - 1; i >= 0; i -= 1) { - if (SDL_GetAtomicInt(&renderer->texturesToDestroy[i]->referenceCount) == 0) { - VULKAN_INTERNAL_DestroyTexture( - renderer, - renderer->texturesToDestroy[i]); - - renderer->texturesToDestroy[i] = renderer->texturesToDestroy[renderer->texturesToDestroyCount - 1]; - renderer->texturesToDestroyCount -= 1; - } - } - - for (Sint32 i = renderer->buffersToDestroyCount - 1; i >= 0; i -= 1) { - if (SDL_GetAtomicInt(&renderer->buffersToDestroy[i]->referenceCount) == 0) { - VULKAN_INTERNAL_DestroyBuffer( - renderer, - renderer->buffersToDestroy[i]); - - renderer->buffersToDestroy[i] = renderer->buffersToDestroy[renderer->buffersToDestroyCount - 1]; - renderer->buffersToDestroyCount -= 1; - } - } - - for (Sint32 i = renderer->graphicsPipelinesToDestroyCount - 1; i >= 0; i -= 1) { - if (SDL_GetAtomicInt(&renderer->graphicsPipelinesToDestroy[i]->referenceCount) == 0) { - VULKAN_INTERNAL_DestroyGraphicsPipeline( - renderer, - renderer->graphicsPipelinesToDestroy[i]); - - renderer->graphicsPipelinesToDestroy[i] = renderer->graphicsPipelinesToDestroy[renderer->graphicsPipelinesToDestroyCount - 1]; - renderer->graphicsPipelinesToDestroyCount -= 1; - } - } - - for (Sint32 i = renderer->computePipelinesToDestroyCount - 1; i >= 0; i -= 1) { - if (SDL_GetAtomicInt(&renderer->computePipelinesToDestroy[i]->referenceCount) == 0) { - VULKAN_INTERNAL_DestroyComputePipeline( - renderer, - renderer->computePipelinesToDestroy[i]); - - renderer->computePipelinesToDestroy[i] = renderer->computePipelinesToDestroy[renderer->computePipelinesToDestroyCount - 1]; - renderer->computePipelinesToDestroyCount -= 1; - } - } - - for (Sint32 i = renderer->shadersToDestroyCount - 1; i >= 0; i -= 1) { - if (SDL_GetAtomicInt(&renderer->shadersToDestroy[i]->referenceCount) == 0) { - VULKAN_INTERNAL_DestroyShader( - renderer, - renderer->shadersToDestroy[i]); - - renderer->shadersToDestroy[i] = renderer->shadersToDestroy[renderer->shadersToDestroyCount - 1]; - renderer->shadersToDestroyCount -= 1; - } - } - - for (Sint32 i = renderer->samplersToDestroyCount - 1; i >= 0; i -= 1) { - if (SDL_GetAtomicInt(&renderer->samplersToDestroy[i]->referenceCount) == 0) { - VULKAN_INTERNAL_DestroySampler( - renderer, - renderer->samplersToDestroy[i]); - - renderer->samplersToDestroy[i] = renderer->samplersToDestroy[renderer->samplersToDestroyCount - 1]; - renderer->samplersToDestroyCount -= 1; - } - } - - for (Sint32 i = renderer->framebuffersToDestroyCount - 1; i >= 0; i -= 1) { - if (SDL_GetAtomicInt(&renderer->framebuffersToDestroy[i]->referenceCount) == 0) { - VULKAN_INTERNAL_DestroyFramebuffer( - renderer, - renderer->framebuffersToDestroy[i]); - - renderer->framebuffersToDestroy[i] = renderer->framebuffersToDestroy[renderer->framebuffersToDestroyCount - 1]; - renderer->framebuffersToDestroyCount -= 1; - } - } - - SDL_UnlockMutex(renderer->disposeLock); -} - -static void VULKAN_INTERNAL_CleanCommandBuffer( - VulkanRenderer *renderer, - VulkanCommandBuffer *commandBuffer, - bool cancel) -{ - if (commandBuffer->autoReleaseFence) { - VULKAN_ReleaseFence( - (SDL_GPURenderer *)renderer, - (SDL_GPUFence *)commandBuffer->inFlightFence); - - commandBuffer->inFlightFence = NULL; - } - - // Uniform buffers are now available - - SDL_LockMutex(renderer->acquireUniformBufferLock); - - for (Sint32 i = 0; i < commandBuffer->usedUniformBufferCount; i += 1) { - VULKAN_INTERNAL_ReturnUniformBufferToPool( - renderer, - commandBuffer->usedUniformBuffers[i]); - } - commandBuffer->usedUniformBufferCount = 0; - - SDL_UnlockMutex(renderer->acquireUniformBufferLock); - - // Decrement reference counts - - for (Sint32 i = 0; i < commandBuffer->usedBufferCount; i += 1) { - (void)SDL_AtomicDecRef(&commandBuffer->usedBuffers[i]->referenceCount); - } - commandBuffer->usedBufferCount = 0; - - for (Sint32 i = 0; i < commandBuffer->usedTextureCount; i += 1) { - (void)SDL_AtomicDecRef(&commandBuffer->usedTextures[i]->referenceCount); - } - commandBuffer->usedTextureCount = 0; - - for (Sint32 i = 0; i < commandBuffer->usedSamplerCount; i += 1) { - (void)SDL_AtomicDecRef(&commandBuffer->usedSamplers[i]->referenceCount); - } - commandBuffer->usedSamplerCount = 0; - - for (Sint32 i = 0; i < commandBuffer->usedGraphicsPipelineCount; i += 1) { - (void)SDL_AtomicDecRef(&commandBuffer->usedGraphicsPipelines[i]->referenceCount); - } - commandBuffer->usedGraphicsPipelineCount = 0; - - for (Sint32 i = 0; i < commandBuffer->usedComputePipelineCount; i += 1) { - (void)SDL_AtomicDecRef(&commandBuffer->usedComputePipelines[i]->referenceCount); - } - commandBuffer->usedComputePipelineCount = 0; - - for (Sint32 i = 0; i < commandBuffer->usedFramebufferCount; i += 1) { - (void)SDL_AtomicDecRef(&commandBuffer->usedFramebuffers[i]->referenceCount); - } - commandBuffer->usedFramebufferCount = 0; - - // Reset presentation data - - commandBuffer->presentDataCount = 0; - commandBuffer->waitSemaphoreCount = 0; - commandBuffer->signalSemaphoreCount = 0; - - // Reset defrag state - - if (commandBuffer->isDefrag) { - renderer->defragInProgress = 0; - } - - // Return command buffer to pool - - SDL_LockMutex(renderer->acquireCommandBufferLock); - - if (commandBuffer->commandPool->inactiveCommandBufferCount == commandBuffer->commandPool->inactiveCommandBufferCapacity) { - commandBuffer->commandPool->inactiveCommandBufferCapacity += 1; - commandBuffer->commandPool->inactiveCommandBuffers = SDL_realloc( - commandBuffer->commandPool->inactiveCommandBuffers, - commandBuffer->commandPool->inactiveCommandBufferCapacity * sizeof(VulkanCommandBuffer *)); - } - - commandBuffer->commandPool->inactiveCommandBuffers[commandBuffer->commandPool->inactiveCommandBufferCount] = commandBuffer; - commandBuffer->commandPool->inactiveCommandBufferCount += 1; - - // Release descriptor set cache - - VULKAN_INTERNAL_ReturnDescriptorSetCacheToPool( - renderer, - commandBuffer->descriptorSetCache); - - commandBuffer->descriptorSetCache = NULL; - - SDL_UnlockMutex(renderer->acquireCommandBufferLock); - - // Remove this command buffer from the submitted list - if (!cancel) { - for (Uint32 i = 0; i < renderer->submittedCommandBufferCount; i += 1) { - if (renderer->submittedCommandBuffers[i] == commandBuffer) { - renderer->submittedCommandBuffers[i] = renderer->submittedCommandBuffers[renderer->submittedCommandBufferCount - 1]; - renderer->submittedCommandBufferCount -= 1; - } - } - } -} - -static bool VULKAN_WaitForFences( - SDL_GPURenderer *driverData, - bool waitAll, - SDL_GPUFence *const *fences, - Uint32 numFences) -{ - VulkanRenderer *renderer = (VulkanRenderer *)driverData; - VkFence *vkFences = SDL_stack_alloc(VkFence, numFences); - VkResult result; - - for (Uint32 i = 0; i < numFences; i += 1) { - vkFences[i] = ((VulkanFenceHandle *)fences[i])->fence; - } - - result = renderer->vkWaitForFences( - renderer->logicalDevice, - numFences, - vkFences, - waitAll, - SDL_MAX_UINT64); - - CHECK_VULKAN_ERROR_AND_RETURN(result, vkWaitForFences, false); - - SDL_stack_free(vkFences); - - SDL_LockMutex(renderer->submitLock); - - for (Sint32 i = renderer->submittedCommandBufferCount - 1; i >= 0; i -= 1) { - result = renderer->vkGetFenceStatus( - renderer->logicalDevice, - renderer->submittedCommandBuffers[i]->inFlightFence->fence); - - if (result == VK_SUCCESS) { - VULKAN_INTERNAL_CleanCommandBuffer( - renderer, - renderer->submittedCommandBuffers[i], - false); - } - } - - VULKAN_INTERNAL_PerformPendingDestroys(renderer); - - SDL_UnlockMutex(renderer->submitLock); - - return true; -} - -static bool VULKAN_Wait( - SDL_GPURenderer *driverData) -{ - VulkanRenderer *renderer = (VulkanRenderer *)driverData; - VulkanCommandBuffer *commandBuffer; - VkResult result; - Sint32 i; - - result = renderer->vkDeviceWaitIdle(renderer->logicalDevice); - - CHECK_VULKAN_ERROR_AND_RETURN(result, vkDeviceWaitIdle, false); - - SDL_LockMutex(renderer->submitLock); - - for (i = renderer->submittedCommandBufferCount - 1; i >= 0; i -= 1) { - commandBuffer = renderer->submittedCommandBuffers[i]; - VULKAN_INTERNAL_CleanCommandBuffer(renderer, commandBuffer, false); - } - - VULKAN_INTERNAL_PerformPendingDestroys(renderer); - - SDL_UnlockMutex(renderer->submitLock); - - return true; -} - -static SDL_GPUFence *VULKAN_SubmitAndAcquireFence( - SDL_GPUCommandBuffer *commandBuffer) -{ - VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; - vulkanCommandBuffer->autoReleaseFence = false; - if (!VULKAN_Submit(commandBuffer)) { - return NULL; - } - return (SDL_GPUFence *)vulkanCommandBuffer->inFlightFence; -} - -static void VULKAN_INTERNAL_ReleaseCommandBuffer(VulkanCommandBuffer *vulkanCommandBuffer) -{ - VulkanRenderer *renderer = vulkanCommandBuffer->renderer; - - if (renderer->submittedCommandBufferCount + 1 >= renderer->submittedCommandBufferCapacity) { - renderer->submittedCommandBufferCapacity = renderer->submittedCommandBufferCount + 1; - - renderer->submittedCommandBuffers = SDL_realloc( - renderer->submittedCommandBuffers, - sizeof(VulkanCommandBuffer *) * renderer->submittedCommandBufferCapacity); - } - - renderer->submittedCommandBuffers[renderer->submittedCommandBufferCount] = vulkanCommandBuffer; - renderer->submittedCommandBufferCount += 1; -} - -static bool VULKAN_Submit( - SDL_GPUCommandBuffer *commandBuffer) -{ - VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; - VulkanRenderer *renderer = vulkanCommandBuffer->renderer; - VkSubmitInfo submitInfo; - VkPresentInfoKHR presentInfo; - VulkanPresentData *presentData; - VkResult vulkanResult, presentResult = VK_SUCCESS; - VkPipelineStageFlags waitStages[MAX_PRESENT_COUNT]; - Uint32 swapchainImageIndex; - VulkanTextureSubresource *swapchainTextureSubresource; - Uint8 commandBufferCleaned = 0; - VulkanMemorySubAllocator *allocator; - bool presenting = false; - - SDL_LockMutex(renderer->submitLock); - - // FIXME: Can this just be permanent? - for (Uint32 i = 0; i < MAX_PRESENT_COUNT; i += 1) { - waitStages[i] = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; - } - - for (Uint32 j = 0; j < vulkanCommandBuffer->presentDataCount; j += 1) { - swapchainImageIndex = vulkanCommandBuffer->presentDatas[j].swapchainImageIndex; - swapchainTextureSubresource = VULKAN_INTERNAL_FetchTextureSubresource( - &vulkanCommandBuffer->presentDatas[j].windowData->textureContainers[swapchainImageIndex], - 0, - 0); - - VULKAN_INTERNAL_TextureSubresourceTransitionFromDefaultUsage( - renderer, - vulkanCommandBuffer, - VULKAN_TEXTURE_USAGE_MODE_PRESENT, - swapchainTextureSubresource); - } - - if (!VULKAN_INTERNAL_EndCommandBuffer(renderer, vulkanCommandBuffer)) { - SDL_UnlockMutex(renderer->submitLock); - return false; - } - - vulkanCommandBuffer->inFlightFence = VULKAN_INTERNAL_AcquireFenceFromPool(renderer); - if (vulkanCommandBuffer->inFlightFence == NULL) { - SDL_UnlockMutex(renderer->submitLock); - return false; - } - - // Command buffer has a reference to the in-flight fence - (void)SDL_AtomicIncRef(&vulkanCommandBuffer->inFlightFence->referenceCount); - - submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; - submitInfo.pNext = NULL; - submitInfo.commandBufferCount = 1; - submitInfo.pCommandBuffers = &vulkanCommandBuffer->commandBuffer; - - submitInfo.pWaitDstStageMask = waitStages; - submitInfo.pWaitSemaphores = vulkanCommandBuffer->waitSemaphores; - submitInfo.waitSemaphoreCount = vulkanCommandBuffer->waitSemaphoreCount; - submitInfo.pSignalSemaphores = vulkanCommandBuffer->signalSemaphores; - submitInfo.signalSemaphoreCount = vulkanCommandBuffer->signalSemaphoreCount; - - vulkanResult = renderer->vkQueueSubmit( - renderer->unifiedQueue, - 1, - &submitInfo, - vulkanCommandBuffer->inFlightFence->fence); - - if (vulkanResult != VK_SUCCESS) { - SDL_UnlockMutex(renderer->submitLock); - CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkQueueSubmit, false); - } - - // Present, if applicable - bool result = true; - - for (Uint32 j = 0; j < vulkanCommandBuffer->presentDataCount; j += 1) { - presenting = true; - - presentData = &vulkanCommandBuffer->presentDatas[j]; - - presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; - presentInfo.pNext = NULL; - presentInfo.pWaitSemaphores = - &presentData->windowData->renderFinishedSemaphore[presentData->windowData->frameCounter]; - presentInfo.waitSemaphoreCount = 1; - presentInfo.pSwapchains = &presentData->windowData->swapchain; - presentInfo.swapchainCount = 1; - presentInfo.pImageIndices = &presentData->swapchainImageIndex; - presentInfo.pResults = NULL; - - presentResult = renderer->vkQueuePresentKHR( - renderer->unifiedQueue, - &presentInfo); - - if (presentResult == VK_SUCCESS || presentResult == VK_SUBOPTIMAL_KHR || presentResult == VK_ERROR_OUT_OF_DATE_KHR) { - // If presenting, the swapchain is using the in-flight fence - presentData->windowData->inFlightFences[presentData->windowData->frameCounter] = (SDL_GPUFence*)vulkanCommandBuffer->inFlightFence; - (void)SDL_AtomicIncRef(&vulkanCommandBuffer->inFlightFence->referenceCount); - - if (presentResult == VK_SUBOPTIMAL_KHR || presentResult == VK_ERROR_OUT_OF_DATE_KHR) { - presentData->windowData->needsSwapchainRecreate = true; - } - } else { - if (presentResult != VK_SUCCESS) { - VULKAN_INTERNAL_ReleaseCommandBuffer(vulkanCommandBuffer); - SDL_UnlockMutex(renderer->submitLock); - } - - CHECK_VULKAN_ERROR_AND_RETURN(presentResult, vkQueuePresentKHR, false); - } - - presentData->windowData->frameCounter = - (presentData->windowData->frameCounter + 1) % renderer->allowedFramesInFlight; - } - - // Check if we can perform any cleanups - - for (Sint32 i = renderer->submittedCommandBufferCount - 1; i >= 0; i -= 1) { - vulkanResult = renderer->vkGetFenceStatus( - renderer->logicalDevice, - renderer->submittedCommandBuffers[i]->inFlightFence->fence); - - if (vulkanResult == VK_SUCCESS) { - VULKAN_INTERNAL_CleanCommandBuffer( - renderer, - renderer->submittedCommandBuffers[i], - false); - - commandBufferCleaned = 1; - } - } - - if (commandBufferCleaned) { - SDL_LockMutex(renderer->allocatorLock); - - for (Uint32 i = 0; i < VK_MAX_MEMORY_TYPES; i += 1) { - allocator = &renderer->memoryAllocator->subAllocators[i]; - - for (Sint32 j = allocator->allocationCount - 1; j >= 0; j -= 1) { - if (allocator->allocations[j]->usedRegionCount == 0) { - VULKAN_INTERNAL_DeallocateMemory( - renderer, - allocator, - j); - } - } - } - - SDL_UnlockMutex(renderer->allocatorLock); - } - - // Check pending destroys - VULKAN_INTERNAL_PerformPendingDestroys(renderer); - - // Defrag! - if ( - presenting && - renderer->allocationsToDefragCount > 0 && - !renderer->defragInProgress) { - result = VULKAN_INTERNAL_DefragmentMemory(renderer); - } - - // Mark command buffer as submitted - // This must happen after defrag, because it will try to acquire new command buffers. - VULKAN_INTERNAL_ReleaseCommandBuffer(vulkanCommandBuffer); - - SDL_UnlockMutex(renderer->submitLock); - - return result; -} - -static bool VULKAN_Cancel( - SDL_GPUCommandBuffer *commandBuffer) -{ - VulkanRenderer *renderer; - VulkanCommandBuffer *vulkanCommandBuffer; - VkResult result; - - vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; - renderer = vulkanCommandBuffer->renderer; - - result = renderer->vkResetCommandBuffer( - vulkanCommandBuffer->commandBuffer, - VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT); - CHECK_VULKAN_ERROR_AND_RETURN(result, vkResetCommandBuffer, false); - - vulkanCommandBuffer->autoReleaseFence = false; - SDL_LockMutex(renderer->submitLock); - VULKAN_INTERNAL_CleanCommandBuffer(renderer, vulkanCommandBuffer, true); - SDL_UnlockMutex(renderer->submitLock); - - return true; -} - -static bool VULKAN_INTERNAL_DefragmentMemory( - VulkanRenderer *renderer) -{ - VulkanMemoryAllocation *allocation; - VulkanMemoryUsedRegion *currentRegion; - VulkanBuffer *newBuffer; - VulkanTexture *newTexture; - VkBufferCopy bufferCopy; - VkImageCopy imageCopy; - VulkanCommandBuffer *commandBuffer; - VulkanTextureSubresource *srcSubresource; - VulkanTextureSubresource *dstSubresource; - Uint32 i, subresourceIndex; - - renderer->defragInProgress = 1; - - commandBuffer = (VulkanCommandBuffer *)VULKAN_AcquireCommandBuffer((SDL_GPURenderer *)renderer); - if (commandBuffer == NULL) { - return false; - } - commandBuffer->isDefrag = 1; - - SDL_LockMutex(renderer->allocatorLock); - - allocation = renderer->allocationsToDefrag[renderer->allocationsToDefragCount - 1]; - renderer->allocationsToDefragCount -= 1; - - /* For each used region in the allocation - * create a new resource, copy the data - * and re-point the resource containers - */ - for (i = 0; i < allocation->usedRegionCount; i += 1) { - currentRegion = allocation->usedRegions[i]; - - if (currentRegion->isBuffer && !currentRegion->vulkanBuffer->markedForDestroy) { - currentRegion->vulkanBuffer->usage |= VK_BUFFER_USAGE_TRANSFER_DST_BIT; - - newBuffer = VULKAN_INTERNAL_CreateBuffer( - renderer, - currentRegion->vulkanBuffer->size, - currentRegion->vulkanBuffer->usage, - currentRegion->vulkanBuffer->type, - false, - currentRegion->vulkanBuffer->container != NULL ? currentRegion->vulkanBuffer->container->debugName : NULL); - - if (newBuffer == NULL) { - SDL_UnlockMutex(renderer->allocatorLock); - return false; - } - - // Copy buffer contents if necessary - if ( - currentRegion->vulkanBuffer->type == VULKAN_BUFFER_TYPE_GPU && currentRegion->vulkanBuffer->transitioned) { - VULKAN_INTERNAL_BufferTransitionFromDefaultUsage( - renderer, - commandBuffer, - VULKAN_BUFFER_USAGE_MODE_COPY_SOURCE, - currentRegion->vulkanBuffer); - - VULKAN_INTERNAL_BufferTransitionFromDefaultUsage( - renderer, - commandBuffer, - VULKAN_BUFFER_USAGE_MODE_COPY_DESTINATION, - newBuffer); - - bufferCopy.srcOffset = 0; - bufferCopy.dstOffset = 0; - bufferCopy.size = currentRegion->resourceSize; - - renderer->vkCmdCopyBuffer( - commandBuffer->commandBuffer, - currentRegion->vulkanBuffer->buffer, - newBuffer->buffer, - 1, - &bufferCopy); - - VULKAN_INTERNAL_BufferTransitionToDefaultUsage( - renderer, - commandBuffer, - VULKAN_BUFFER_USAGE_MODE_COPY_DESTINATION, - newBuffer); - - VULKAN_INTERNAL_TrackBuffer(commandBuffer, currentRegion->vulkanBuffer); - VULKAN_INTERNAL_TrackBuffer(commandBuffer, newBuffer); - } - - // re-point original container to new buffer - newBuffer->container = currentRegion->vulkanBuffer->container; - newBuffer->containerIndex = currentRegion->vulkanBuffer->containerIndex; - if (newBuffer->type == VULKAN_BUFFER_TYPE_UNIFORM) { - currentRegion->vulkanBuffer->uniformBufferForDefrag->buffer = newBuffer; - } else { - newBuffer->container->buffers[newBuffer->containerIndex] = newBuffer; - if (newBuffer->container->activeBuffer == currentRegion->vulkanBuffer) { - newBuffer->container->activeBuffer = newBuffer; - } - } - - if (currentRegion->vulkanBuffer->uniformBufferForDefrag) { - newBuffer->uniformBufferForDefrag = currentRegion->vulkanBuffer->uniformBufferForDefrag; - } - - VULKAN_INTERNAL_ReleaseBuffer(renderer, currentRegion->vulkanBuffer); - } else if (!currentRegion->isBuffer && !currentRegion->vulkanTexture->markedForDestroy) { - newTexture = VULKAN_INTERNAL_CreateTexture( - renderer, - ¤tRegion->vulkanTexture->container->header.info); - - if (newTexture == NULL) { - SDL_UnlockMutex(renderer->allocatorLock); - return false; - } - - SDL_GPUTextureCreateInfo info = currentRegion->vulkanTexture->container->header.info; - for (subresourceIndex = 0; subresourceIndex < currentRegion->vulkanTexture->subresourceCount; subresourceIndex += 1) { - // copy subresource if necessary - srcSubresource = ¤tRegion->vulkanTexture->subresources[subresourceIndex]; - dstSubresource = &newTexture->subresources[subresourceIndex]; - - VULKAN_INTERNAL_TextureSubresourceTransitionFromDefaultUsage( - renderer, - commandBuffer, - VULKAN_TEXTURE_USAGE_MODE_COPY_SOURCE, - srcSubresource); - - VULKAN_INTERNAL_TextureSubresourceTransitionFromDefaultUsage( - renderer, - commandBuffer, - VULKAN_TEXTURE_USAGE_MODE_COPY_DESTINATION, - dstSubresource); - - imageCopy.srcOffset.x = 0; - imageCopy.srcOffset.y = 0; - imageCopy.srcOffset.z = 0; - imageCopy.srcSubresource.aspectMask = srcSubresource->parent->aspectFlags; - imageCopy.srcSubresource.baseArrayLayer = srcSubresource->layer; - imageCopy.srcSubresource.layerCount = 1; - imageCopy.srcSubresource.mipLevel = srcSubresource->level; - imageCopy.extent.width = SDL_max(1, info.width >> srcSubresource->level); - imageCopy.extent.height = SDL_max(1, info.height >> srcSubresource->level); - imageCopy.extent.depth = info.type == SDL_GPU_TEXTURETYPE_3D ? info.layer_count_or_depth : 1; - imageCopy.dstOffset.x = 0; - imageCopy.dstOffset.y = 0; - imageCopy.dstOffset.z = 0; - imageCopy.dstSubresource.aspectMask = dstSubresource->parent->aspectFlags; - imageCopy.dstSubresource.baseArrayLayer = dstSubresource->layer; - imageCopy.dstSubresource.layerCount = 1; - imageCopy.dstSubresource.mipLevel = dstSubresource->level; - - renderer->vkCmdCopyImage( - commandBuffer->commandBuffer, - currentRegion->vulkanTexture->image, - VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - newTexture->image, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - 1, - &imageCopy); - - VULKAN_INTERNAL_TextureSubresourceTransitionToDefaultUsage( - renderer, - commandBuffer, - VULKAN_TEXTURE_USAGE_MODE_COPY_DESTINATION, - dstSubresource); - - VULKAN_INTERNAL_TrackTexture(commandBuffer, srcSubresource->parent); - VULKAN_INTERNAL_TrackTexture(commandBuffer, dstSubresource->parent); - } - - // re-point original container to new texture - newTexture->container = currentRegion->vulkanTexture->container; - newTexture->containerIndex = currentRegion->vulkanTexture->containerIndex; - newTexture->container->textures[currentRegion->vulkanTexture->containerIndex] = newTexture; - if (currentRegion->vulkanTexture == currentRegion->vulkanTexture->container->activeTexture) { - newTexture->container->activeTexture = newTexture; - } - - VULKAN_INTERNAL_ReleaseTexture(renderer, currentRegion->vulkanTexture); - } - } - - SDL_UnlockMutex(renderer->allocatorLock); - - return VULKAN_Submit( - (SDL_GPUCommandBuffer *)commandBuffer); -} - -// Format Info - -static bool VULKAN_SupportsTextureFormat( - SDL_GPURenderer *driverData, - SDL_GPUTextureFormat format, - SDL_GPUTextureType type, - SDL_GPUTextureUsageFlags usage) -{ - VulkanRenderer *renderer = (VulkanRenderer *)driverData; - VkFormat vulkanFormat = SDLToVK_TextureFormat[format]; - VkImageUsageFlags vulkanUsage = 0; - VkImageCreateFlags createFlags = 0; - VkImageFormatProperties properties; - VkResult vulkanResult; - - if (usage & SDL_GPU_TEXTUREUSAGE_SAMPLER) { - vulkanUsage |= VK_IMAGE_USAGE_SAMPLED_BIT; - } - if (usage & SDL_GPU_TEXTUREUSAGE_COLOR_TARGET) { - vulkanUsage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; - } - if (usage & SDL_GPU_TEXTUREUSAGE_DEPTH_STENCIL_TARGET) { - vulkanUsage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; - } - if (usage & (SDL_GPU_TEXTUREUSAGE_GRAPHICS_STORAGE_READ | - SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_READ | - SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_WRITE | - SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_SIMULTANEOUS_READ_WRITE)) { - vulkanUsage |= VK_IMAGE_USAGE_STORAGE_BIT; - } - - if (type == SDL_GPU_TEXTURETYPE_CUBE || type == SDL_GPU_TEXTURETYPE_CUBE_ARRAY) { - createFlags = VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT; - } - - vulkanResult = renderer->vkGetPhysicalDeviceImageFormatProperties( - renderer->physicalDevice, - vulkanFormat, - (type == SDL_GPU_TEXTURETYPE_3D) ? VK_IMAGE_TYPE_3D : VK_IMAGE_TYPE_2D, - VK_IMAGE_TILING_OPTIMAL, - vulkanUsage, - createFlags, - &properties); - - return vulkanResult == VK_SUCCESS; -} - -// Device instantiation - -static inline Uint8 CheckDeviceExtensions( - VkExtensionProperties *extensions, - Uint32 numExtensions, - VulkanExtensions *supports) -{ - Uint32 i; - - SDL_memset(supports, '\0', sizeof(VulkanExtensions)); - for (i = 0; i < numExtensions; i += 1) { - const char *name = extensions[i].extensionName; -#define CHECK(ext) \ - if (SDL_strcmp(name, "VK_" #ext) == 0) { \ - supports->ext = 1; \ - } - CHECK(KHR_swapchain) - else CHECK(KHR_maintenance1) else CHECK(KHR_driver_properties) else CHECK(KHR_portability_subset) else CHECK(EXT_texture_compression_astc_hdr) -#undef CHECK - } - - return (supports->KHR_swapchain && - supports->KHR_maintenance1); -} - -static inline Uint32 GetDeviceExtensionCount(VulkanExtensions *supports) -{ - return ( - supports->KHR_swapchain + - supports->KHR_maintenance1 + - supports->KHR_driver_properties + - supports->KHR_portability_subset + - supports->EXT_texture_compression_astc_hdr); -} - -static inline void CreateDeviceExtensionArray( - VulkanExtensions *supports, - const char **extensions) -{ - Uint8 cur = 0; -#define CHECK(ext) \ - if (supports->ext) { \ - extensions[cur++] = "VK_" #ext; \ - } - CHECK(KHR_swapchain) - CHECK(KHR_maintenance1) - CHECK(KHR_driver_properties) - CHECK(KHR_portability_subset) - CHECK(EXT_texture_compression_astc_hdr) -#undef CHECK -} - -static inline Uint8 SupportsInstanceExtension( - const char *ext, - VkExtensionProperties *availableExtensions, - Uint32 numAvailableExtensions) -{ - Uint32 i; - for (i = 0; i < numAvailableExtensions; i += 1) { - if (SDL_strcmp(ext, availableExtensions[i].extensionName) == 0) { - return 1; - } - } - return 0; -} - -static Uint8 VULKAN_INTERNAL_CheckInstanceExtensions( - const char **requiredExtensions, - Uint32 requiredExtensionsLength, - bool *supportsDebugUtils, - bool *supportsColorspace) -{ - Uint32 extensionCount, i; - VkExtensionProperties *availableExtensions; - Uint8 allExtensionsSupported = 1; - - vkEnumerateInstanceExtensionProperties( - NULL, - &extensionCount, - NULL); - availableExtensions = SDL_malloc( - extensionCount * sizeof(VkExtensionProperties)); - vkEnumerateInstanceExtensionProperties( - NULL, - &extensionCount, - availableExtensions); - - for (i = 0; i < requiredExtensionsLength; i += 1) { - if (!SupportsInstanceExtension( - requiredExtensions[i], - availableExtensions, - extensionCount)) { - allExtensionsSupported = 0; - break; - } - } - - // This is optional, but nice to have! - *supportsDebugUtils = SupportsInstanceExtension( - VK_EXT_DEBUG_UTILS_EXTENSION_NAME, - availableExtensions, - extensionCount); - - // Also optional and nice to have! - *supportsColorspace = SupportsInstanceExtension( - VK_EXT_SWAPCHAIN_COLOR_SPACE_EXTENSION_NAME, - availableExtensions, - extensionCount); - - SDL_free(availableExtensions); - return allExtensionsSupported; -} - -static Uint8 VULKAN_INTERNAL_CheckDeviceExtensions( - VulkanRenderer *renderer, - VkPhysicalDevice physicalDevice, - VulkanExtensions *physicalDeviceExtensions) -{ - Uint32 extensionCount; - VkExtensionProperties *availableExtensions; - Uint8 allExtensionsSupported; - - renderer->vkEnumerateDeviceExtensionProperties( - physicalDevice, - NULL, - &extensionCount, - NULL); - availableExtensions = (VkExtensionProperties *)SDL_malloc( - extensionCount * sizeof(VkExtensionProperties)); - renderer->vkEnumerateDeviceExtensionProperties( - physicalDevice, - NULL, - &extensionCount, - availableExtensions); - - allExtensionsSupported = CheckDeviceExtensions( - availableExtensions, - extensionCount, - physicalDeviceExtensions); - - SDL_free(availableExtensions); - return allExtensionsSupported; -} - -static Uint8 VULKAN_INTERNAL_CheckValidationLayers( - const char **validationLayers, - Uint32 validationLayersLength) -{ - Uint32 layerCount; - VkLayerProperties *availableLayers; - Uint32 i, j; - Uint8 layerFound = 0; - - vkEnumerateInstanceLayerProperties(&layerCount, NULL); - availableLayers = (VkLayerProperties *)SDL_malloc( - layerCount * sizeof(VkLayerProperties)); - vkEnumerateInstanceLayerProperties(&layerCount, availableLayers); - - for (i = 0; i < validationLayersLength; i += 1) { - layerFound = 0; - - for (j = 0; j < layerCount; j += 1) { - if (SDL_strcmp(validationLayers[i], availableLayers[j].layerName) == 0) { - layerFound = 1; - break; - } - } - - if (!layerFound) { - break; - } - } - - SDL_free(availableLayers); - return layerFound; -} - -static Uint8 VULKAN_INTERNAL_CreateInstance(VulkanRenderer *renderer) -{ - VkResult vulkanResult; - VkApplicationInfo appInfo; - VkInstanceCreateFlags createFlags; - const char *const *originalInstanceExtensionNames; - const char **instanceExtensionNames; - Uint32 instanceExtensionCount; - VkInstanceCreateInfo createInfo; - static const char *layerNames[] = { "VK_LAYER_KHRONOS_validation" }; - - appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; - appInfo.pNext = NULL; - appInfo.pApplicationName = NULL; - appInfo.applicationVersion = 0; - appInfo.pEngineName = "SDLGPU"; - appInfo.engineVersion = SDL_VERSION; - appInfo.apiVersion = VK_MAKE_VERSION(1, 0, 0); - - createFlags = 0; - - originalInstanceExtensionNames = SDL_Vulkan_GetInstanceExtensions(&instanceExtensionCount); - if (!originalInstanceExtensionNames) { - SDL_LogError( - SDL_LOG_CATEGORY_GPU, - "SDL_Vulkan_GetInstanceExtensions(): getExtensionCount: %s", - SDL_GetError()); - - return 0; - } - - /* Extra space for the following extensions: - * VK_KHR_get_physical_device_properties2 - * VK_EXT_swapchain_colorspace - * VK_EXT_debug_utils - * VK_KHR_portability_enumeration - */ - instanceExtensionNames = SDL_stack_alloc( - const char *, - instanceExtensionCount + 4); - SDL_memcpy((void *)instanceExtensionNames, originalInstanceExtensionNames, instanceExtensionCount * sizeof(const char *)); - - // Core since 1.1 - instanceExtensionNames[instanceExtensionCount++] = - VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME; - -#ifdef SDL_PLATFORM_APPLE - instanceExtensionNames[instanceExtensionCount++] = - VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME; - createFlags |= VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR; -#endif - - if (!VULKAN_INTERNAL_CheckInstanceExtensions( - instanceExtensionNames, - instanceExtensionCount, - &renderer->supportsDebugUtils, - &renderer->supportsColorspace)) { - SDL_stack_free((char *)instanceExtensionNames); - SET_STRING_ERROR_AND_RETURN("Required Vulkan instance extensions not supported", false); - } - - if (renderer->supportsDebugUtils) { - // Append the debug extension - instanceExtensionNames[instanceExtensionCount++] = - VK_EXT_DEBUG_UTILS_EXTENSION_NAME; - } else { - SDL_LogWarn( - SDL_LOG_CATEGORY_GPU, - "%s is not supported!", - VK_EXT_DEBUG_UTILS_EXTENSION_NAME); - } - - if (renderer->supportsColorspace) { - // Append colorspace extension - instanceExtensionNames[instanceExtensionCount++] = - VK_EXT_SWAPCHAIN_COLOR_SPACE_EXTENSION_NAME; - } - - createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; - createInfo.pNext = NULL; - createInfo.flags = createFlags; - createInfo.pApplicationInfo = &appInfo; - createInfo.ppEnabledLayerNames = layerNames; - createInfo.enabledExtensionCount = instanceExtensionCount; - createInfo.ppEnabledExtensionNames = instanceExtensionNames; - if (renderer->debugMode) { - createInfo.enabledLayerCount = SDL_arraysize(layerNames); - if (!VULKAN_INTERNAL_CheckValidationLayers( - layerNames, - createInfo.enabledLayerCount)) { - SDL_LogWarn(SDL_LOG_CATEGORY_GPU, "Validation layers not found, continuing without validation"); - createInfo.enabledLayerCount = 0; - } else { - SDL_LogInfo(SDL_LOG_CATEGORY_GPU, "Validation layers enabled, expect debug level performance!"); - } - } else { - createInfo.enabledLayerCount = 0; - } - - vulkanResult = vkCreateInstance(&createInfo, NULL, &renderer->instance); - SDL_stack_free((char *)instanceExtensionNames); - - if (vulkanResult != VK_SUCCESS) { - CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkCreateInstance, 0); - } - - return 1; -} - -static Uint8 VULKAN_INTERNAL_IsDeviceSuitable( - VulkanRenderer *renderer, - VkPhysicalDevice physicalDevice, - VulkanExtensions *physicalDeviceExtensions, - Uint32 *queueFamilyIndex, - Uint8 *deviceRank) -{ - Uint32 queueFamilyCount, queueFamilyRank, queueFamilyBest; - VkQueueFamilyProperties *queueProps; - bool supportsPresent; - VkPhysicalDeviceProperties deviceProperties; - VkPhysicalDeviceFeatures deviceFeatures; - Uint32 i; - - const Uint8 *devicePriority = renderer->preferLowPower ? DEVICE_PRIORITY_LOWPOWER : DEVICE_PRIORITY_HIGHPERFORMANCE; - - /* Get the device rank before doing any checks, in case one fails. - * Note: If no dedicated device exists, one that supports our features - * would be fine - */ - renderer->vkGetPhysicalDeviceProperties( - physicalDevice, - &deviceProperties); - if (*deviceRank < devicePriority[deviceProperties.deviceType]) { - /* This device outranks the best device we've found so far! - * This includes a dedicated GPU that has less features than an - * integrated GPU, because this is a freak case that is almost - * never intentionally desired by the end user - */ - *deviceRank = devicePriority[deviceProperties.deviceType]; - } else if (*deviceRank > devicePriority[deviceProperties.deviceType]) { - /* Device is outranked by a previous device, don't even try to - * run a query and reset the rank to avoid overwrites - */ - *deviceRank = 0; - return 0; - } - - renderer->vkGetPhysicalDeviceFeatures( - physicalDevice, - &deviceFeatures); - if (!deviceFeatures.independentBlend || - !deviceFeatures.imageCubeArray || - !deviceFeatures.depthClamp || - !deviceFeatures.shaderClipDistance || - !deviceFeatures.drawIndirectFirstInstance) { - return 0; - } - - if (!VULKAN_INTERNAL_CheckDeviceExtensions( - renderer, - physicalDevice, - physicalDeviceExtensions)) { - return 0; - } - - renderer->vkGetPhysicalDeviceQueueFamilyProperties( - physicalDevice, - &queueFamilyCount, - NULL); - - queueProps = SDL_stack_alloc( - VkQueueFamilyProperties, - queueFamilyCount); - renderer->vkGetPhysicalDeviceQueueFamilyProperties( - physicalDevice, - &queueFamilyCount, - queueProps); - - queueFamilyBest = 0; - *queueFamilyIndex = SDL_MAX_UINT32; - for (i = 0; i < queueFamilyCount; i += 1) { - supportsPresent = SDL_Vulkan_GetPresentationSupport( - renderer->instance, - physicalDevice, - i); - if (!supportsPresent || - !(queueProps[i].queueFlags & VK_QUEUE_GRAPHICS_BIT)) { - // Not a graphics family, ignore. - continue; - } - - /* The queue family bitflags are kind of annoying. - * - * We of course need a graphics family, but we ideally want the - * _primary_ graphics family. The spec states that at least one - * graphics family must also be a compute family, so generally - * drivers make that the first one. But hey, maybe something - * genuinely can't do compute or something, and FNA doesn't - * need it, so we'll be open to a non-compute queue family. - * - * Additionally, it's common to see the primary queue family - * have the transfer bit set, which is great! But this is - * actually optional; it's impossible to NOT have transfers in - * graphics/compute but it _is_ possible for a graphics/compute - * family, even the primary one, to just decide not to set the - * bitflag. Admittedly, a driver may want to isolate transfer - * queues to a dedicated family so that queues made solely for - * transfers can have an optimized DMA queue. - * - * That, or the driver author got lazy and decided not to set - * the bit. Looking at you, Android. - * - * -flibit - */ - if (queueProps[i].queueFlags & VK_QUEUE_COMPUTE_BIT) { - if (queueProps[i].queueFlags & VK_QUEUE_TRANSFER_BIT) { - // Has all attribs! - queueFamilyRank = 3; - } else { - // Probably has a DMA transfer queue family - queueFamilyRank = 2; - } - } else { - // Just a graphics family, probably has something better - queueFamilyRank = 1; - } - if (queueFamilyRank > queueFamilyBest) { - *queueFamilyIndex = i; - queueFamilyBest = queueFamilyRank; - } - } - - SDL_stack_free(queueProps); - - if (*queueFamilyIndex == SDL_MAX_UINT32) { - // Somehow no graphics queues existed. Compute-only device? - return 0; - } - - // FIXME: Need better structure for checking vs storing swapchain support details - return 1; -} - -static Uint8 VULKAN_INTERNAL_DeterminePhysicalDevice(VulkanRenderer *renderer) -{ - VkResult vulkanResult; - VkPhysicalDevice *physicalDevices; - VulkanExtensions *physicalDeviceExtensions; - Uint32 i, physicalDeviceCount; - Sint32 suitableIndex; - Uint32 queueFamilyIndex, suitableQueueFamilyIndex; - Uint8 deviceRank, highestRank; - - vulkanResult = renderer->vkEnumeratePhysicalDevices( - renderer->instance, - &physicalDeviceCount, - NULL); - CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkEnumeratePhysicalDevices, 0); - - if (physicalDeviceCount == 0) { - SDL_LogInfo(SDL_LOG_CATEGORY_GPU, "Failed to find any GPUs with Vulkan support"); - return 0; - } - - physicalDevices = SDL_stack_alloc(VkPhysicalDevice, physicalDeviceCount); - physicalDeviceExtensions = SDL_stack_alloc(VulkanExtensions, physicalDeviceCount); - - vulkanResult = renderer->vkEnumeratePhysicalDevices( - renderer->instance, - &physicalDeviceCount, - physicalDevices); - - /* This should be impossible to hit, but from what I can tell this can - * be triggered not because the array is too small, but because there - * were drivers that turned out to be bogus, so this is the loader's way - * of telling us that the list is now smaller than expected :shrug: - */ - if (vulkanResult == VK_INCOMPLETE) { - SDL_LogWarn(SDL_LOG_CATEGORY_GPU, "vkEnumeratePhysicalDevices returned VK_INCOMPLETE, will keep trying anyway..."); - vulkanResult = VK_SUCCESS; - } - - if (vulkanResult != VK_SUCCESS) { - SDL_LogWarn( - SDL_LOG_CATEGORY_GPU, - "vkEnumeratePhysicalDevices failed: %s", - VkErrorMessages(vulkanResult)); - SDL_stack_free(physicalDevices); - SDL_stack_free(physicalDeviceExtensions); - return 0; - } - - // Any suitable device will do, but we'd like the best - suitableIndex = -1; - suitableQueueFamilyIndex = 0; - highestRank = 0; - for (i = 0; i < physicalDeviceCount; i += 1) { - deviceRank = highestRank; - if (VULKAN_INTERNAL_IsDeviceSuitable( - renderer, - physicalDevices[i], - &physicalDeviceExtensions[i], - &queueFamilyIndex, - &deviceRank)) { - /* Use this for rendering. - * Note that this may override a previous device that - * supports rendering, but shares the same device rank. - */ - suitableIndex = i; - suitableQueueFamilyIndex = queueFamilyIndex; - highestRank = deviceRank; - } else if (deviceRank > highestRank) { - /* In this case, we found a... "realer?" GPU, - * but it doesn't actually support our Vulkan. - * We should disqualify all devices below as a - * result, because if we don't we end up - * ignoring real hardware and risk using - * something like LLVMpipe instead! - * -flibit - */ - suitableIndex = -1; - highestRank = deviceRank; - } - } - - if (suitableIndex != -1) { - renderer->supports = physicalDeviceExtensions[suitableIndex]; - renderer->physicalDevice = physicalDevices[suitableIndex]; - renderer->queueFamilyIndex = suitableQueueFamilyIndex; - } else { - SDL_stack_free(physicalDevices); - SDL_stack_free(physicalDeviceExtensions); - return 0; - } - - renderer->physicalDeviceProperties.sType = - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2; - if (renderer->supports.KHR_driver_properties) { - renderer->physicalDeviceDriverProperties.sType = - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES_KHR; - renderer->physicalDeviceDriverProperties.pNext = NULL; - - renderer->physicalDeviceProperties.pNext = - &renderer->physicalDeviceDriverProperties; - - renderer->vkGetPhysicalDeviceProperties2KHR( - renderer->physicalDevice, - &renderer->physicalDeviceProperties); - } else { - renderer->physicalDeviceProperties.pNext = NULL; - - renderer->vkGetPhysicalDeviceProperties( - renderer->physicalDevice, - &renderer->physicalDeviceProperties.properties); - } - - renderer->vkGetPhysicalDeviceMemoryProperties( - renderer->physicalDevice, - &renderer->memoryProperties); - - SDL_stack_free(physicalDevices); - SDL_stack_free(physicalDeviceExtensions); - return 1; -} - -static Uint8 VULKAN_INTERNAL_CreateLogicalDevice( - VulkanRenderer *renderer) -{ - VkResult vulkanResult; - VkDeviceCreateInfo deviceCreateInfo; - VkPhysicalDeviceFeatures desiredDeviceFeatures; - VkPhysicalDeviceFeatures haveDeviceFeatures; - VkPhysicalDevicePortabilitySubsetFeaturesKHR portabilityFeatures; - const char **deviceExtensions; - - VkDeviceQueueCreateInfo queueCreateInfo; - float queuePriority = 1.0f; - - queueCreateInfo.sType = - VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; - queueCreateInfo.pNext = NULL; - queueCreateInfo.flags = 0; - queueCreateInfo.queueFamilyIndex = renderer->queueFamilyIndex; - queueCreateInfo.queueCount = 1; - queueCreateInfo.pQueuePriorities = &queuePriority; - - // check feature support - - renderer->vkGetPhysicalDeviceFeatures( - renderer->physicalDevice, - &haveDeviceFeatures); - - // specifying used device features - - SDL_zero(desiredDeviceFeatures); - desiredDeviceFeatures.independentBlend = VK_TRUE; - desiredDeviceFeatures.samplerAnisotropy = VK_TRUE; - desiredDeviceFeatures.imageCubeArray = VK_TRUE; - desiredDeviceFeatures.depthClamp = VK_TRUE; - desiredDeviceFeatures.shaderClipDistance = VK_TRUE; - desiredDeviceFeatures.drawIndirectFirstInstance = VK_TRUE; - - if (haveDeviceFeatures.fillModeNonSolid) { - desiredDeviceFeatures.fillModeNonSolid = VK_TRUE; - renderer->supportsFillModeNonSolid = true; - } - - if (haveDeviceFeatures.multiDrawIndirect) { - desiredDeviceFeatures.multiDrawIndirect = VK_TRUE; - renderer->supportsMultiDrawIndirect = true; - } - - // creating the logical device - - deviceCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; - if (renderer->supports.KHR_portability_subset) { - portabilityFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PORTABILITY_SUBSET_FEATURES_KHR; - portabilityFeatures.pNext = NULL; - portabilityFeatures.constantAlphaColorBlendFactors = VK_FALSE; - portabilityFeatures.events = VK_FALSE; - portabilityFeatures.imageViewFormatReinterpretation = VK_FALSE; - portabilityFeatures.imageViewFormatSwizzle = VK_TRUE; - portabilityFeatures.imageView2DOn3DImage = VK_FALSE; - portabilityFeatures.multisampleArrayImage = VK_FALSE; - portabilityFeatures.mutableComparisonSamplers = VK_FALSE; - portabilityFeatures.pointPolygons = VK_FALSE; - portabilityFeatures.samplerMipLodBias = VK_FALSE; // Technically should be true, but eh - portabilityFeatures.separateStencilMaskRef = VK_FALSE; - portabilityFeatures.shaderSampleRateInterpolationFunctions = VK_FALSE; - portabilityFeatures.tessellationIsolines = VK_FALSE; - portabilityFeatures.tessellationPointMode = VK_FALSE; - portabilityFeatures.triangleFans = VK_FALSE; - portabilityFeatures.vertexAttributeAccessBeyondStride = VK_FALSE; - deviceCreateInfo.pNext = &portabilityFeatures; - } else { - deviceCreateInfo.pNext = NULL; - } - deviceCreateInfo.flags = 0; - deviceCreateInfo.queueCreateInfoCount = 1; - deviceCreateInfo.pQueueCreateInfos = &queueCreateInfo; - deviceCreateInfo.enabledLayerCount = 0; - deviceCreateInfo.ppEnabledLayerNames = NULL; - deviceCreateInfo.enabledExtensionCount = GetDeviceExtensionCount( - &renderer->supports); - deviceExtensions = SDL_stack_alloc( - const char *, - deviceCreateInfo.enabledExtensionCount); - CreateDeviceExtensionArray(&renderer->supports, deviceExtensions); - deviceCreateInfo.ppEnabledExtensionNames = deviceExtensions; - deviceCreateInfo.pEnabledFeatures = &desiredDeviceFeatures; - - vulkanResult = renderer->vkCreateDevice( - renderer->physicalDevice, - &deviceCreateInfo, - NULL, - &renderer->logicalDevice); - SDL_stack_free((void *)deviceExtensions); - CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkCreateDevice, 0); - - // Load vkDevice entry points - -#define VULKAN_DEVICE_FUNCTION(func) \ - renderer->func = (PFN_##func) \ - renderer->vkGetDeviceProcAddr( \ - renderer->logicalDevice, \ - #func); -#include "SDL_gpu_vulkan_vkfuncs.h" - - renderer->vkGetDeviceQueue( - renderer->logicalDevice, - renderer->queueFamilyIndex, - 0, - &renderer->unifiedQueue); - - return 1; -} - -static void VULKAN_INTERNAL_LoadEntryPoints(void) -{ - // Required for MoltenVK support - SDL_setenv_unsafe("MVK_CONFIG_FULL_IMAGE_VIEW_SWIZZLE", "1", 1); - - // Load Vulkan entry points - if (!SDL_Vulkan_LoadLibrary(NULL)) { - SDL_LogWarn(SDL_LOG_CATEGORY_GPU, "Vulkan: SDL_Vulkan_LoadLibrary failed!"); - return; - } - -#ifdef HAVE_GCC_DIAGNOSTIC_PRAGMA -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wpedantic" -#endif - vkGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)SDL_Vulkan_GetVkGetInstanceProcAddr(); -#ifdef HAVE_GCC_DIAGNOSTIC_PRAGMA -#pragma GCC diagnostic pop -#endif - if (vkGetInstanceProcAddr == NULL) { - SDL_LogWarn( - SDL_LOG_CATEGORY_GPU, - "SDL_Vulkan_GetVkGetInstanceProcAddr(): %s", - SDL_GetError()); - return; - } - -#define VULKAN_GLOBAL_FUNCTION(name) \ - name = (PFN_##name)vkGetInstanceProcAddr(VK_NULL_HANDLE, #name); \ - if (name == NULL) { \ - SDL_LogWarn(SDL_LOG_CATEGORY_GPU, "vkGetInstanceProcAddr(VK_NULL_HANDLE, \"" #name "\") failed"); \ - return; \ - } -#include "SDL_gpu_vulkan_vkfuncs.h" -} - -static bool VULKAN_INTERNAL_PrepareVulkan( - VulkanRenderer *renderer) -{ - VULKAN_INTERNAL_LoadEntryPoints(); - - if (!VULKAN_INTERNAL_CreateInstance(renderer)) { - SDL_LogWarn(SDL_LOG_CATEGORY_GPU, "Vulkan: Could not create Vulkan instance"); - return false; - } - -#define VULKAN_INSTANCE_FUNCTION(func) \ - renderer->func = (PFN_##func)vkGetInstanceProcAddr(renderer->instance, #func); -#include "SDL_gpu_vulkan_vkfuncs.h" - - if (!VULKAN_INTERNAL_DeterminePhysicalDevice(renderer)) { - SDL_LogWarn(SDL_LOG_CATEGORY_GPU, "Vulkan: Failed to determine a suitable physical device"); - return false; - } - return true; -} - -static bool VULKAN_PrepareDriver(SDL_VideoDevice *_this) -{ - // Set up dummy VulkanRenderer - VulkanRenderer *renderer; - Uint8 result; - - if (_this->Vulkan_CreateSurface == NULL) { - return false; - } - - if (!SDL_Vulkan_LoadLibrary(NULL)) { - return false; - } - - renderer = (VulkanRenderer *)SDL_malloc(sizeof(VulkanRenderer)); - SDL_memset(renderer, '\0', sizeof(VulkanRenderer)); - - result = VULKAN_INTERNAL_PrepareVulkan(renderer); - - if (result) { - renderer->vkDestroyInstance(renderer->instance, NULL); - } - SDL_free(renderer); - SDL_Vulkan_UnloadLibrary(); - return result; -} - -static SDL_GPUDevice *VULKAN_CreateDevice(bool debugMode, bool preferLowPower, SDL_PropertiesID props) -{ - VulkanRenderer *renderer; - - SDL_GPUDevice *result; - Uint32 i; - - if (!SDL_Vulkan_LoadLibrary(NULL)) { - SDL_assert(!"This should have failed in PrepareDevice first!"); - return NULL; - } - - renderer = (VulkanRenderer *)SDL_malloc(sizeof(VulkanRenderer)); - SDL_memset(renderer, '\0', sizeof(VulkanRenderer)); - renderer->debugMode = debugMode; - renderer->preferLowPower = preferLowPower; - renderer->allowedFramesInFlight = 2; - - if (!VULKAN_INTERNAL_PrepareVulkan(renderer)) { - SDL_free(renderer); - SDL_Vulkan_UnloadLibrary(); - SET_STRING_ERROR_AND_RETURN("Failed to initialize Vulkan!", NULL); - } - - SDL_LogInfo(SDL_LOG_CATEGORY_GPU, "SDL_GPU Driver: Vulkan"); - SDL_LogInfo( - SDL_LOG_CATEGORY_GPU, - "Vulkan Device: %s", - renderer->physicalDeviceProperties.properties.deviceName); - if (renderer->supports.KHR_driver_properties) { - SDL_LogInfo( - SDL_LOG_CATEGORY_GPU, - "Vulkan Driver: %s %s", - renderer->physicalDeviceDriverProperties.driverName, - renderer->physicalDeviceDriverProperties.driverInfo); - SDL_LogInfo( - SDL_LOG_CATEGORY_GPU, - "Vulkan Conformance: %u.%u.%u", - renderer->physicalDeviceDriverProperties.conformanceVersion.major, - renderer->physicalDeviceDriverProperties.conformanceVersion.minor, - renderer->physicalDeviceDriverProperties.conformanceVersion.patch); - } else { - SDL_LogWarn(SDL_LOG_CATEGORY_GPU, "KHR_driver_properties unsupported! Bother your vendor about this!"); - } - - if (!VULKAN_INTERNAL_CreateLogicalDevice( - renderer)) { - SDL_free(renderer); - SDL_Vulkan_UnloadLibrary(); - SET_STRING_ERROR_AND_RETURN("Failed to create logical device!", NULL); - } - - // FIXME: just move this into this function - result = (SDL_GPUDevice *)SDL_malloc(sizeof(SDL_GPUDevice)); - ASSIGN_DRIVER(VULKAN) - - result->driverData = (SDL_GPURenderer *)renderer; - - /* - * Create initial swapchain array - */ - - renderer->claimedWindowCapacity = 1; - renderer->claimedWindowCount = 0; - renderer->claimedWindows = SDL_malloc( - renderer->claimedWindowCapacity * sizeof(WindowData *)); - - // Threading - - renderer->allocatorLock = SDL_CreateMutex(); - renderer->disposeLock = SDL_CreateMutex(); - renderer->submitLock = SDL_CreateMutex(); - renderer->acquireCommandBufferLock = SDL_CreateMutex(); - renderer->acquireUniformBufferLock = SDL_CreateMutex(); - renderer->framebufferFetchLock = SDL_CreateMutex(); - renderer->windowLock = SDL_CreateMutex(); - - /* - * Create submitted command buffer list - */ - - renderer->submittedCommandBufferCapacity = 16; - renderer->submittedCommandBufferCount = 0; - renderer->submittedCommandBuffers = SDL_malloc(sizeof(VulkanCommandBuffer *) * renderer->submittedCommandBufferCapacity); - - // Memory Allocator - - renderer->memoryAllocator = (VulkanMemoryAllocator *)SDL_malloc( - sizeof(VulkanMemoryAllocator)); - - for (i = 0; i < VK_MAX_MEMORY_TYPES; i += 1) { - renderer->memoryAllocator->subAllocators[i].memoryTypeIndex = i; - renderer->memoryAllocator->subAllocators[i].allocations = NULL; - renderer->memoryAllocator->subAllocators[i].allocationCount = 0; - renderer->memoryAllocator->subAllocators[i].sortedFreeRegions = SDL_malloc( - sizeof(VulkanMemoryFreeRegion *) * 4); - renderer->memoryAllocator->subAllocators[i].sortedFreeRegionCount = 0; - renderer->memoryAllocator->subAllocators[i].sortedFreeRegionCapacity = 4; - } - - // Create uniform buffer pool - - renderer->uniformBufferPoolCount = 32; - renderer->uniformBufferPoolCapacity = 32; - renderer->uniformBufferPool = SDL_malloc( - renderer->uniformBufferPoolCapacity * sizeof(VulkanUniformBuffer *)); - - for (i = 0; i < renderer->uniformBufferPoolCount; i += 1) { - renderer->uniformBufferPool[i] = VULKAN_INTERNAL_CreateUniformBuffer( - renderer, - UNIFORM_BUFFER_SIZE); - } - - renderer->descriptorSetCachePoolCapacity = 8; - renderer->descriptorSetCachePoolCount = 0; - renderer->descriptorSetCachePool = SDL_calloc(renderer->descriptorSetCachePoolCapacity, sizeof(DescriptorSetCache *)); - - SDL_SetAtomicInt(&renderer->layoutResourceID, 0); - - // Device limits - - renderer->minUBOAlignment = (Uint32)renderer->physicalDeviceProperties.properties.limits.minUniformBufferOffsetAlignment; - - // Initialize caches - - renderer->commandPoolHashTable = SDL_CreateHashTable( - 0, // !!! FIXME: a real guess here, for a _minimum_ if not a maximum, could be useful. - false, // manually synchronized due to submission timing - VULKAN_INTERNAL_CommandPoolHashFunction, - VULKAN_INTERNAL_CommandPoolHashKeyMatch, - VULKAN_INTERNAL_CommandPoolHashDestroy, - (void *)renderer); - - renderer->renderPassHashTable = SDL_CreateHashTable( - 0, // !!! FIXME: a real guess here, for a _minimum_ if not a maximum, could be useful. - true, // thread-safe - VULKAN_INTERNAL_RenderPassHashFunction, - VULKAN_INTERNAL_RenderPassHashKeyMatch, - VULKAN_INTERNAL_RenderPassHashDestroy, - (void *)renderer); - - renderer->framebufferHashTable = SDL_CreateHashTable( - 0, // !!! FIXME: a real guess here, for a _minimum_ if not a maximum, could be useful. - false, // manually synchronized due to iteration - VULKAN_INTERNAL_FramebufferHashFunction, - VULKAN_INTERNAL_FramebufferHashKeyMatch, - VULKAN_INTERNAL_FramebufferHashDestroy, - (void *)renderer); - - renderer->graphicsPipelineResourceLayoutHashTable = SDL_CreateHashTable( - 0, // !!! FIXME: a real guess here, for a _minimum_ if not a maximum, could be useful. - true, // thread-safe - VULKAN_INTERNAL_GraphicsPipelineResourceLayoutHashFunction, - VULKAN_INTERNAL_GraphicsPipelineResourceLayoutHashKeyMatch, - VULKAN_INTERNAL_GraphicsPipelineResourceLayoutHashDestroy, - (void *)renderer); - - renderer->computePipelineResourceLayoutHashTable = SDL_CreateHashTable( - 0, // !!! FIXME: a real guess here, for a _minimum_ if not a maximum, could be useful. - true, // thread-safe - VULKAN_INTERNAL_ComputePipelineResourceLayoutHashFunction, - VULKAN_INTERNAL_ComputePipelineResourceLayoutHashKeyMatch, - VULKAN_INTERNAL_ComputePipelineResourceLayoutHashDestroy, - (void *)renderer); - - renderer->descriptorSetLayoutHashTable = SDL_CreateHashTable( - 0, // !!! FIXME: a real guess here, for a _minimum_ if not a maximum, could be useful. - true, // thread-safe - VULKAN_INTERNAL_DescriptorSetLayoutHashFunction, - VULKAN_INTERNAL_DescriptorSetLayoutHashKeyMatch, - VULKAN_INTERNAL_DescriptorSetLayoutHashDestroy, - (void *)renderer); - - // Initialize fence pool - - renderer->fencePool.lock = SDL_CreateMutex(); - - renderer->fencePool.availableFenceCapacity = 4; - renderer->fencePool.availableFenceCount = 0; - renderer->fencePool.availableFences = SDL_malloc( - renderer->fencePool.availableFenceCapacity * sizeof(VulkanFenceHandle *)); - - // Deferred destroy storage - - renderer->texturesToDestroyCapacity = 16; - renderer->texturesToDestroyCount = 0; - - renderer->texturesToDestroy = (VulkanTexture **)SDL_malloc( - sizeof(VulkanTexture *) * - renderer->texturesToDestroyCapacity); - - renderer->buffersToDestroyCapacity = 16; - renderer->buffersToDestroyCount = 0; - - renderer->buffersToDestroy = SDL_malloc( - sizeof(VulkanBuffer *) * - renderer->buffersToDestroyCapacity); - - renderer->samplersToDestroyCapacity = 16; - renderer->samplersToDestroyCount = 0; - - renderer->samplersToDestroy = SDL_malloc( - sizeof(VulkanSampler *) * - renderer->samplersToDestroyCapacity); - - renderer->graphicsPipelinesToDestroyCapacity = 16; - renderer->graphicsPipelinesToDestroyCount = 0; - - renderer->graphicsPipelinesToDestroy = SDL_malloc( - sizeof(VulkanGraphicsPipeline *) * - renderer->graphicsPipelinesToDestroyCapacity); - - renderer->computePipelinesToDestroyCapacity = 16; - renderer->computePipelinesToDestroyCount = 0; - - renderer->computePipelinesToDestroy = SDL_malloc( - sizeof(VulkanComputePipeline *) * - renderer->computePipelinesToDestroyCapacity); - - renderer->shadersToDestroyCapacity = 16; - renderer->shadersToDestroyCount = 0; - - renderer->shadersToDestroy = SDL_malloc( - sizeof(VulkanShader *) * - renderer->shadersToDestroyCapacity); - - renderer->framebuffersToDestroyCapacity = 16; - renderer->framebuffersToDestroyCount = 0; - renderer->framebuffersToDestroy = SDL_malloc( - sizeof(VulkanFramebuffer *) * - renderer->framebuffersToDestroyCapacity); - - // Defrag state - - renderer->defragInProgress = 0; - - renderer->allocationsToDefragCount = 0; - renderer->allocationsToDefragCapacity = 4; - renderer->allocationsToDefrag = SDL_malloc( - renderer->allocationsToDefragCapacity * sizeof(VulkanMemoryAllocation *)); - - return result; -} - -SDL_GPUBootstrap VulkanDriver = { - "vulkan", - SDL_GPU_SHADERFORMAT_SPIRV, - VULKAN_PrepareDriver, - VULKAN_CreateDevice -}; - -#endif // SDL_GPU_VULKAN diff --git a/contrib/SDL-3.2.8/src/gpu/vulkan/SDL_gpu_vulkan_vkfuncs.h b/contrib/SDL-3.2.8/src/gpu/vulkan/SDL_gpu_vulkan_vkfuncs.h deleted file mode 100644 index 7316eb9..0000000 --- a/contrib/SDL-3.2.8/src/gpu/vulkan/SDL_gpu_vulkan_vkfuncs.h +++ /dev/null @@ -1,176 +0,0 @@ -/* - Simple DirectMedia Layer - Copyright (C) 1997-2025 Sam Lantinga - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. -*/ - -/* - * Global functions from the Vulkan Loader - */ - -#ifndef VULKAN_GLOBAL_FUNCTION -#define VULKAN_GLOBAL_FUNCTION(name) -#endif -VULKAN_GLOBAL_FUNCTION(vkCreateInstance) -VULKAN_GLOBAL_FUNCTION(vkEnumerateInstanceExtensionProperties) -VULKAN_GLOBAL_FUNCTION(vkEnumerateInstanceLayerProperties) - -/* - * vkInstance, created by global vkCreateInstance function - */ - -#ifndef VULKAN_INSTANCE_FUNCTION -#define VULKAN_INSTANCE_FUNCTION(name) -#endif - -// Vulkan 1.0 -VULKAN_INSTANCE_FUNCTION(vkGetDeviceProcAddr) -VULKAN_INSTANCE_FUNCTION(vkCreateDevice) -VULKAN_INSTANCE_FUNCTION(vkDestroyInstance) -VULKAN_INSTANCE_FUNCTION(vkEnumerateDeviceExtensionProperties) -VULKAN_INSTANCE_FUNCTION(vkEnumeratePhysicalDevices) -VULKAN_INSTANCE_FUNCTION(vkGetPhysicalDeviceFeatures) -VULKAN_INSTANCE_FUNCTION(vkGetPhysicalDeviceQueueFamilyProperties) -VULKAN_INSTANCE_FUNCTION(vkGetPhysicalDeviceFormatProperties) -VULKAN_INSTANCE_FUNCTION(vkGetPhysicalDeviceImageFormatProperties) -VULKAN_INSTANCE_FUNCTION(vkGetPhysicalDeviceMemoryProperties) -VULKAN_INSTANCE_FUNCTION(vkGetPhysicalDeviceProperties) - -// VK_KHR_get_physical_device_properties2, needed for KHR_driver_properties -VULKAN_INSTANCE_FUNCTION(vkGetPhysicalDeviceProperties2KHR) - -// VK_KHR_surface -VULKAN_INSTANCE_FUNCTION(vkDestroySurfaceKHR) -VULKAN_INSTANCE_FUNCTION(vkGetPhysicalDeviceSurfaceCapabilitiesKHR) -VULKAN_INSTANCE_FUNCTION(vkGetPhysicalDeviceSurfaceFormatsKHR) -VULKAN_INSTANCE_FUNCTION(vkGetPhysicalDeviceSurfacePresentModesKHR) -VULKAN_INSTANCE_FUNCTION(vkGetPhysicalDeviceSurfaceSupportKHR) - -// VK_EXT_debug_utils -VULKAN_INSTANCE_FUNCTION(vkCmdBeginDebugUtilsLabelEXT) -VULKAN_INSTANCE_FUNCTION(vkSetDebugUtilsObjectNameEXT) -VULKAN_INSTANCE_FUNCTION(vkCmdEndDebugUtilsLabelEXT) -VULKAN_INSTANCE_FUNCTION(vkCmdInsertDebugUtilsLabelEXT) - -/* - * vkDevice, created by a vkInstance - */ - -#ifndef VULKAN_DEVICE_FUNCTION -#define VULKAN_DEVICE_FUNCTION(name) -#endif - -// Vulkan 1.0 -VULKAN_DEVICE_FUNCTION(vkAllocateCommandBuffers) -VULKAN_DEVICE_FUNCTION(vkAllocateDescriptorSets) -VULKAN_DEVICE_FUNCTION(vkAllocateMemory) -VULKAN_DEVICE_FUNCTION(vkBeginCommandBuffer) -VULKAN_DEVICE_FUNCTION(vkBindBufferMemory) -VULKAN_DEVICE_FUNCTION(vkBindImageMemory) -VULKAN_DEVICE_FUNCTION(vkCmdBeginRenderPass) -VULKAN_DEVICE_FUNCTION(vkCmdBindDescriptorSets) -VULKAN_DEVICE_FUNCTION(vkCmdBindIndexBuffer) -VULKAN_DEVICE_FUNCTION(vkCmdBindPipeline) -VULKAN_DEVICE_FUNCTION(vkCmdBindVertexBuffers) -VULKAN_DEVICE_FUNCTION(vkCmdBlitImage) -VULKAN_DEVICE_FUNCTION(vkCmdClearAttachments) -VULKAN_DEVICE_FUNCTION(vkCmdClearColorImage) -VULKAN_DEVICE_FUNCTION(vkCmdClearDepthStencilImage) -VULKAN_DEVICE_FUNCTION(vkCmdCopyBuffer) -VULKAN_DEVICE_FUNCTION(vkCmdCopyImage) -VULKAN_DEVICE_FUNCTION(vkCmdCopyBufferToImage) -VULKAN_DEVICE_FUNCTION(vkCmdCopyImageToBuffer) -VULKAN_DEVICE_FUNCTION(vkCmdDispatch) -VULKAN_DEVICE_FUNCTION(vkCmdDispatchIndirect) -VULKAN_DEVICE_FUNCTION(vkCmdDraw) -VULKAN_DEVICE_FUNCTION(vkCmdDrawIndexed) -VULKAN_DEVICE_FUNCTION(vkCmdDrawIndexedIndirect) -VULKAN_DEVICE_FUNCTION(vkCmdDrawIndirect) -VULKAN_DEVICE_FUNCTION(vkCmdEndRenderPass) -VULKAN_DEVICE_FUNCTION(vkCmdPipelineBarrier) -VULKAN_DEVICE_FUNCTION(vkCmdResolveImage) -VULKAN_DEVICE_FUNCTION(vkCmdSetBlendConstants) -VULKAN_DEVICE_FUNCTION(vkCmdSetDepthBias) -VULKAN_DEVICE_FUNCTION(vkCmdSetScissor) -VULKAN_DEVICE_FUNCTION(vkCmdSetStencilReference) -VULKAN_DEVICE_FUNCTION(vkCmdSetViewport) -VULKAN_DEVICE_FUNCTION(vkCreateBuffer) -VULKAN_DEVICE_FUNCTION(vkCreateCommandPool) -VULKAN_DEVICE_FUNCTION(vkCreateDescriptorPool) -VULKAN_DEVICE_FUNCTION(vkCreateDescriptorSetLayout) -VULKAN_DEVICE_FUNCTION(vkCreateFence) -VULKAN_DEVICE_FUNCTION(vkCreateFramebuffer) -VULKAN_DEVICE_FUNCTION(vkCreateComputePipelines) -VULKAN_DEVICE_FUNCTION(vkCreateGraphicsPipelines) -VULKAN_DEVICE_FUNCTION(vkCreateImage) -VULKAN_DEVICE_FUNCTION(vkCreateImageView) -VULKAN_DEVICE_FUNCTION(vkCreatePipelineCache) -VULKAN_DEVICE_FUNCTION(vkCreatePipelineLayout) -VULKAN_DEVICE_FUNCTION(vkCreateRenderPass) -VULKAN_DEVICE_FUNCTION(vkCreateSampler) -VULKAN_DEVICE_FUNCTION(vkCreateSemaphore) -VULKAN_DEVICE_FUNCTION(vkCreateShaderModule) -VULKAN_DEVICE_FUNCTION(vkDestroyBuffer) -VULKAN_DEVICE_FUNCTION(vkDestroyCommandPool) -VULKAN_DEVICE_FUNCTION(vkDestroyDescriptorPool) -VULKAN_DEVICE_FUNCTION(vkDestroyDescriptorSetLayout) -VULKAN_DEVICE_FUNCTION(vkDestroyDevice) -VULKAN_DEVICE_FUNCTION(vkDestroyFence) -VULKAN_DEVICE_FUNCTION(vkDestroyFramebuffer) -VULKAN_DEVICE_FUNCTION(vkDestroyImage) -VULKAN_DEVICE_FUNCTION(vkDestroyImageView) -VULKAN_DEVICE_FUNCTION(vkDestroyPipeline) -VULKAN_DEVICE_FUNCTION(vkDestroyPipelineCache) -VULKAN_DEVICE_FUNCTION(vkDestroyPipelineLayout) -VULKAN_DEVICE_FUNCTION(vkDestroyRenderPass) -VULKAN_DEVICE_FUNCTION(vkDestroySampler) -VULKAN_DEVICE_FUNCTION(vkDestroySemaphore) -VULKAN_DEVICE_FUNCTION(vkDestroyShaderModule) -VULKAN_DEVICE_FUNCTION(vkDeviceWaitIdle) -VULKAN_DEVICE_FUNCTION(vkEndCommandBuffer) -VULKAN_DEVICE_FUNCTION(vkFreeCommandBuffers) -VULKAN_DEVICE_FUNCTION(vkFreeMemory) -VULKAN_DEVICE_FUNCTION(vkGetDeviceQueue) -VULKAN_DEVICE_FUNCTION(vkGetPipelineCacheData) -VULKAN_DEVICE_FUNCTION(vkGetFenceStatus) -VULKAN_DEVICE_FUNCTION(vkGetBufferMemoryRequirements) -VULKAN_DEVICE_FUNCTION(vkGetImageMemoryRequirements) -VULKAN_DEVICE_FUNCTION(vkMapMemory) -VULKAN_DEVICE_FUNCTION(vkQueueSubmit) -VULKAN_DEVICE_FUNCTION(vkQueueWaitIdle) -VULKAN_DEVICE_FUNCTION(vkResetCommandBuffer) -VULKAN_DEVICE_FUNCTION(vkResetCommandPool) -VULKAN_DEVICE_FUNCTION(vkResetDescriptorPool) -VULKAN_DEVICE_FUNCTION(vkResetFences) -VULKAN_DEVICE_FUNCTION(vkUnmapMemory) -VULKAN_DEVICE_FUNCTION(vkUpdateDescriptorSets) -VULKAN_DEVICE_FUNCTION(vkWaitForFences) - -// VK_KHR_swapchain -VULKAN_DEVICE_FUNCTION(vkAcquireNextImageKHR) -VULKAN_DEVICE_FUNCTION(vkCreateSwapchainKHR) -VULKAN_DEVICE_FUNCTION(vkDestroySwapchainKHR) -VULKAN_DEVICE_FUNCTION(vkQueuePresentKHR) -VULKAN_DEVICE_FUNCTION(vkGetSwapchainImagesKHR) - -/* - * Redefine these every time you include this header! - */ -#undef VULKAN_GLOBAL_FUNCTION -#undef VULKAN_INSTANCE_FUNCTION -#undef VULKAN_DEVICE_FUNCTION -- cgit v1.2.3