Atlas - SDL_gpu_vulkan.c

Home / ext / SDL / src / gpu / vulkan Lines: 1 | Size: 537882 bytes [Download] [Show on GitHub] [Search similar files] [Raw] [Raw (proxy)]
[FILE BEGIN]
1/* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2026 Sam Lantinga <[email protected]> 4 5 This software is provided 'as-is', without any express or implied 6 warranty. In no event will the authors be held liable for any damages 7 arising from the use of this software. 8 9 Permission is granted to anyone to use this software for any purpose, 10 including commercial applications, and to alter it and redistribute it 11 freely, subject to the following restrictions: 12 13 1. The origin of this software must not be misrepresented; you must not 14 claim that you wrote the original software. If you use this software 15 in a product, an acknowledgment in the product documentation would be 16 appreciated but is not required. 17 2. Altered source versions must be plainly marked as such, and must not be 18 misrepresented as being the original software. 19 3. This notice may not be removed or altered from any source distribution. 20*/ 21 22#include "SDL_internal.h" 23 24#ifdef SDL_GPU_VULKAN 25 26// Needed for VK_KHR_portability_subset 27#define VK_ENABLE_BETA_EXTENSIONS 28 29#define VK_NO_PROTOTYPES 30#include "../../video/khronos/vulkan/vulkan.h" 31 32#ifdef HAVE_GPU_OPENXR 33#define XR_USE_GRAPHICS_API_VULKAN 1 34#include "../xr/SDL_openxr_internal.h" 35#include "../xr/SDL_openxrdyn.h" 36#include "../xr/SDL_gpu_openxr.h" 37#endif 38 39#include <SDL3/SDL_vulkan.h> 40 41#include "../SDL_sysgpu.h" 42#include "../../events/SDL_windowevents_c.h" 43 44// Global Vulkan Loader Entry Points 45 46static PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = NULL; 47 48#define VULKAN_GLOBAL_FUNCTION(name) \ 49 static PFN_##name name = NULL; 50#include "SDL_gpu_vulkan_vkfuncs.h" 51 52typedef struct VulkanExtensions 53{ 54 // These extensions are required! 55 56 // Globally supported 57 Uint8 KHR_swapchain; 58 // Core since 1.1, needed for negative VkViewport::height 59 Uint8 KHR_maintenance1; 60 61 // These extensions are optional! 62 63 // Core since 1.2, but requires annoying paperwork to implement 64 Uint8 KHR_driver_properties; 65 // Only required for special implementations (i.e. MoltenVK) 66 Uint8 KHR_portability_subset; 67 // Only required to detect devices using Dozen D3D12 driver 68 Uint8 MSFT_layered_driver; 69 // Only required for decoding HDR ASTC textures 70 Uint8 EXT_texture_compression_astc_hdr; 71} VulkanExtensions; 72 73// Defines 74 75#define SMALL_ALLOCATION_THRESHOLD 2097152 // 2 MiB 76#define SMALL_ALLOCATION_SIZE 16777216 // 16 MiB 77#define LARGE_ALLOCATION_INCREMENT 67108864 // 64 MiB 78#define MAX_UBO_SECTION_SIZE 4096 // 4 KiB 79#define DESCRIPTOR_POOL_SIZE 128 80#define WINDOW_PROPERTY_DATA "SDL.internal.gpu.vulkan.data" 81 82#define IDENTITY_SWIZZLE \ 83 { \ 84 VK_COMPONENT_SWIZZLE_IDENTITY, \ 85 VK_COMPONENT_SWIZZLE_IDENTITY, \ 86 VK_COMPONENT_SWIZZLE_IDENTITY, \ 87 VK_COMPONENT_SWIZZLE_IDENTITY \ 88 } 89 90// Conversions 91 92static VkPresentModeKHR SDLToVK_PresentMode[] = { 93 VK_PRESENT_MODE_FIFO_KHR, 94 VK_PRESENT_MODE_IMMEDIATE_KHR, 95 VK_PRESENT_MODE_MAILBOX_KHR 96}; 97 98// NOTE: this is behind an ifdef guard because without, it would trigger an "unused variable" error when OpenXR support is disabled 99#ifdef HAVE_GPU_OPENXR 100typedef struct TextureFormatPair { 101 VkFormat vk; 102 SDL_GPUTextureFormat sdl; 103} TextureFormatPair; 104 105static TextureFormatPair SDLToVK_TextureFormat_SrgbOnly[] = { 106 {VK_FORMAT_R8G8B8A8_SRGB, SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM_SRGB}, 107 {VK_FORMAT_B8G8R8A8_SRGB, SDL_GPU_TEXTUREFORMAT_B8G8R8A8_UNORM_SRGB}, 108 {VK_FORMAT_BC1_RGBA_SRGB_BLOCK, SDL_GPU_TEXTUREFORMAT_BC1_RGBA_UNORM_SRGB}, 109 {VK_FORMAT_BC2_SRGB_BLOCK, SDL_GPU_TEXTUREFORMAT_BC2_RGBA_UNORM_SRGB}, 110 {VK_FORMAT_BC3_SRGB_BLOCK, SDL_GPU_TEXTUREFORMAT_BC3_RGBA_UNORM_SRGB}, 111 {VK_FORMAT_BC7_SRGB_BLOCK, SDL_GPU_TEXTUREFORMAT_BC7_RGBA_UNORM_SRGB}, 112 {VK_FORMAT_ASTC_4x4_SRGB_BLOCK, SDL_GPU_TEXTUREFORMAT_ASTC_4x4_UNORM_SRGB}, 113 {VK_FORMAT_ASTC_5x4_SRGB_BLOCK, SDL_GPU_TEXTUREFORMAT_ASTC_5x4_UNORM_SRGB}, 114 {VK_FORMAT_ASTC_5x5_SRGB_BLOCK, SDL_GPU_TEXTUREFORMAT_ASTC_5x5_UNORM_SRGB}, 115 {VK_FORMAT_ASTC_6x5_SRGB_BLOCK, SDL_GPU_TEXTUREFORMAT_ASTC_6x5_UNORM_SRGB}, 116 {VK_FORMAT_ASTC_6x6_SRGB_BLOCK, SDL_GPU_TEXTUREFORMAT_ASTC_6x6_UNORM_SRGB}, 117 {VK_FORMAT_ASTC_8x5_SRGB_BLOCK, SDL_GPU_TEXTUREFORMAT_ASTC_8x5_UNORM_SRGB}, 118 {VK_FORMAT_ASTC_8x6_SRGB_BLOCK, SDL_GPU_TEXTUREFORMAT_ASTC_8x6_UNORM_SRGB}, 119 {VK_FORMAT_ASTC_8x8_SRGB_BLOCK, SDL_GPU_TEXTUREFORMAT_ASTC_8x8_UNORM_SRGB}, 120 {VK_FORMAT_ASTC_10x5_SRGB_BLOCK, SDL_GPU_TEXTUREFORMAT_ASTC_10x5_UNORM_SRGB}, 121 {VK_FORMAT_ASTC_10x6_SRGB_BLOCK, SDL_GPU_TEXTUREFORMAT_ASTC_10x6_UNORM_SRGB}, 122 {VK_FORMAT_ASTC_10x8_SRGB_BLOCK, SDL_GPU_TEXTUREFORMAT_ASTC_10x8_UNORM_SRGB}, 123 {VK_FORMAT_ASTC_10x10_SRGB_BLOCK, SDL_GPU_TEXTUREFORMAT_ASTC_10x10_UNORM_SRGB}, 124 {VK_FORMAT_ASTC_12x10_SRGB_BLOCK, SDL_GPU_TEXTUREFORMAT_ASTC_12x10_UNORM_SRGB}, 125 {VK_FORMAT_ASTC_12x12_SRGB_BLOCK, SDL_GPU_TEXTUREFORMAT_ASTC_12x12_UNORM_SRGB}, 126}; 127#endif // HAVE_GPU_OPENXR 128 129static VkFormat SDLToVK_TextureFormat[] = { 130 VK_FORMAT_UNDEFINED, // INVALID 131 VK_FORMAT_R8_UNORM, // A8_UNORM 132 VK_FORMAT_R8_UNORM, // R8_UNORM 133 VK_FORMAT_R8G8_UNORM, // R8G8_UNORM 134 VK_FORMAT_R8G8B8A8_UNORM, // R8G8B8A8_UNORM 135 VK_FORMAT_R16_UNORM, // R16_UNORM 136 VK_FORMAT_R16G16_UNORM, // R16G16_UNORM 137 VK_FORMAT_R16G16B16A16_UNORM, // R16G16B16A16_UNORM 138 VK_FORMAT_A2B10G10R10_UNORM_PACK32, // R10G10B10A2_UNORM 139 VK_FORMAT_R5G6B5_UNORM_PACK16, // B5G6R5_UNORM 140 VK_FORMAT_A1R5G5B5_UNORM_PACK16, // B5G5R5A1_UNORM 141 VK_FORMAT_B4G4R4A4_UNORM_PACK16, // B4G4R4A4_UNORM 142 VK_FORMAT_B8G8R8A8_UNORM, // B8G8R8A8_UNORM 143 VK_FORMAT_BC1_RGBA_UNORM_BLOCK, // BC1_UNORM 144 VK_FORMAT_BC2_UNORM_BLOCK, // BC2_UNORM 145 VK_FORMAT_BC3_UNORM_BLOCK, // BC3_UNORM 146 VK_FORMAT_BC4_UNORM_BLOCK, // BC4_UNORM 147 VK_FORMAT_BC5_UNORM_BLOCK, // BC5_UNORM 148 VK_FORMAT_BC7_UNORM_BLOCK, // BC7_UNORM 149 VK_FORMAT_BC6H_SFLOAT_BLOCK, // BC6H_FLOAT 150 VK_FORMAT_BC6H_UFLOAT_BLOCK, // BC6H_UFLOAT 151 VK_FORMAT_R8_SNORM, // R8_SNORM 152 VK_FORMAT_R8G8_SNORM, // R8G8_SNORM 153 VK_FORMAT_R8G8B8A8_SNORM, // R8G8B8A8_SNORM 154 VK_FORMAT_R16_SNORM, // R16_SNORM 155 VK_FORMAT_R16G16_SNORM, // R16G16_SNORM 156 VK_FORMAT_R16G16B16A16_SNORM, // R16G16B16A16_SNORM 157 VK_FORMAT_R16_SFLOAT, // R16_FLOAT 158 VK_FORMAT_R16G16_SFLOAT, // R16G16_FLOAT 159 VK_FORMAT_R16G16B16A16_SFLOAT, // R16G16B16A16_FLOAT 160 VK_FORMAT_R32_SFLOAT, // R32_FLOAT 161 VK_FORMAT_R32G32_SFLOAT, // R32G32_FLOAT 162 VK_FORMAT_R32G32B32A32_SFLOAT, // R32G32B32A32_FLOAT 163 VK_FORMAT_B10G11R11_UFLOAT_PACK32, // R11G11B10_UFLOAT 164 VK_FORMAT_R8_UINT, // R8_UINT 165 VK_FORMAT_R8G8_UINT, // R8G8_UINT 166 VK_FORMAT_R8G8B8A8_UINT, // R8G8B8A8_UINT 167 VK_FORMAT_R16_UINT, // R16_UINT 168 VK_FORMAT_R16G16_UINT, // R16G16_UINT 169 VK_FORMAT_R16G16B16A16_UINT, // R16G16B16A16_UINT 170 VK_FORMAT_R32_UINT, // R32_UINT 171 VK_FORMAT_R32G32_UINT, // R32G32_UINT 172 VK_FORMAT_R32G32B32A32_UINT, // R32G32B32A32_UINT 173 VK_FORMAT_R8_SINT, // R8_INT 174 VK_FORMAT_R8G8_SINT, // R8G8_INT 175 VK_FORMAT_R8G8B8A8_SINT, // R8G8B8A8_INT 176 VK_FORMAT_R16_SINT, // R16_INT 177 VK_FORMAT_R16G16_SINT, // R16G16_INT 178 VK_FORMAT_R16G16B16A16_SINT, // R16G16B16A16_INT 179 VK_FORMAT_R32_SINT, // R32_INT 180 VK_FORMAT_R32G32_SINT, // R32G32_INT 181 VK_FORMAT_R32G32B32A32_SINT, // R32G32B32A32_INT 182 VK_FORMAT_R8G8B8A8_SRGB, // R8G8B8A8_UNORM_SRGB 183 VK_FORMAT_B8G8R8A8_SRGB, // B8G8R8A8_UNORM_SRGB 184 VK_FORMAT_BC1_RGBA_SRGB_BLOCK, // BC1_UNORM_SRGB 185 VK_FORMAT_BC2_SRGB_BLOCK, // BC3_UNORM_SRGB 186 VK_FORMAT_BC3_SRGB_BLOCK, // BC3_UNORM_SRGB 187 VK_FORMAT_BC7_SRGB_BLOCK, // BC7_UNORM_SRGB 188 VK_FORMAT_D16_UNORM, // D16_UNORM 189 VK_FORMAT_X8_D24_UNORM_PACK32, // D24_UNORM 190 VK_FORMAT_D32_SFLOAT, // D32_FLOAT 191 VK_FORMAT_D24_UNORM_S8_UINT, // D24_UNORM_S8_UINT 192 VK_FORMAT_D32_SFLOAT_S8_UINT, // D32_FLOAT_S8_UINT 193 VK_FORMAT_ASTC_4x4_UNORM_BLOCK, // ASTC_4x4_UNORM 194 VK_FORMAT_ASTC_5x4_UNORM_BLOCK, // ASTC_5x4_UNORM 195 VK_FORMAT_ASTC_5x5_UNORM_BLOCK, // ASTC_5x5_UNORM 196 VK_FORMAT_ASTC_6x5_UNORM_BLOCK, // ASTC_6x5_UNORM 197 VK_FORMAT_ASTC_6x6_UNORM_BLOCK, // ASTC_6x6_UNORM 198 VK_FORMAT_ASTC_8x5_UNORM_BLOCK, // ASTC_8x5_UNORM 199 VK_FORMAT_ASTC_8x6_UNORM_BLOCK, // ASTC_8x6_UNORM 200 VK_FORMAT_ASTC_8x8_UNORM_BLOCK, // ASTC_8x8_UNORM 201 VK_FORMAT_ASTC_10x5_UNORM_BLOCK, // ASTC_10x5_UNORM 202 VK_FORMAT_ASTC_10x6_UNORM_BLOCK, // ASTC_10x6_UNORM 203 VK_FORMAT_ASTC_10x8_UNORM_BLOCK, // ASTC_10x8_UNORM 204 VK_FORMAT_ASTC_10x10_UNORM_BLOCK, // ASTC_10x10_UNORM 205 VK_FORMAT_ASTC_12x10_UNORM_BLOCK, // ASTC_12x10_UNORM 206 VK_FORMAT_ASTC_12x12_UNORM_BLOCK, // ASTC_12x12_UNORM 207 VK_FORMAT_ASTC_4x4_SRGB_BLOCK, // ASTC_4x4_UNORM_SRGB 208 VK_FORMAT_ASTC_5x4_SRGB_BLOCK, // ASTC_5x4_UNORM_SRGB 209 VK_FORMAT_ASTC_5x5_SRGB_BLOCK, // ASTC_5x5_UNORM_SRGB 210 VK_FORMAT_ASTC_6x5_SRGB_BLOCK, // ASTC_6x5_UNORM_SRGB 211 VK_FORMAT_ASTC_6x6_SRGB_BLOCK, // ASTC_6x6_UNORM_SRGB 212 VK_FORMAT_ASTC_8x5_SRGB_BLOCK, // ASTC_8x5_UNORM_SRGB 213 VK_FORMAT_ASTC_8x6_SRGB_BLOCK, // ASTC_8x6_UNORM_SRGB 214 VK_FORMAT_ASTC_8x8_SRGB_BLOCK, // ASTC_8x8_UNORM_SRGB 215 VK_FORMAT_ASTC_10x5_SRGB_BLOCK, // ASTC_10x5_UNORM_SRGB 216 VK_FORMAT_ASTC_10x6_SRGB_BLOCK, // ASTC_10x6_UNORM_SRGB 217 VK_FORMAT_ASTC_10x8_SRGB_BLOCK, // ASTC_10x8_UNORM_SRGB 218 VK_FORMAT_ASTC_10x10_SRGB_BLOCK, // ASTC_10x10_UNORM_SRGB 219 VK_FORMAT_ASTC_12x10_SRGB_BLOCK, // ASTC_12x10_UNORM_SRGB 220 VK_FORMAT_ASTC_12x12_SRGB_BLOCK, // ASTC_12x12_UNORM_SRGB 221 VK_FORMAT_ASTC_4x4_SFLOAT_BLOCK_EXT, // ASTC_4x4_FLOAT 222 VK_FORMAT_ASTC_5x4_SFLOAT_BLOCK_EXT, // ASTC_5x4_FLOAT 223 VK_FORMAT_ASTC_5x5_SFLOAT_BLOCK_EXT, // ASTC_5x5_FLOAT 224 VK_FORMAT_ASTC_6x5_SFLOAT_BLOCK_EXT, // ASTC_6x5_FLOAT 225 VK_FORMAT_ASTC_6x6_SFLOAT_BLOCK_EXT, // ASTC_6x6_FLOAT 226 VK_FORMAT_ASTC_8x5_SFLOAT_BLOCK_EXT, // ASTC_8x5_FLOAT 227 VK_FORMAT_ASTC_8x6_SFLOAT_BLOCK_EXT, // ASTC_8x6_FLOAT 228 VK_FORMAT_ASTC_8x8_SFLOAT_BLOCK_EXT, // ASTC_8x8_FLOAT 229 VK_FORMAT_ASTC_10x5_SFLOAT_BLOCK_EXT, // ASTC_10x5_FLOAT 230 VK_FORMAT_ASTC_10x6_SFLOAT_BLOCK_EXT, // ASTC_10x6_FLOAT 231 VK_FORMAT_ASTC_10x8_SFLOAT_BLOCK_EXT, // ASTC_10x8_FLOAT 232 VK_FORMAT_ASTC_10x10_SFLOAT_BLOCK_EXT, // ASTC_10x10_FLOAT 233 VK_FORMAT_ASTC_12x10_SFLOAT_BLOCK_EXT, // ASTC_12x10_FLOAT 234 VK_FORMAT_ASTC_12x12_SFLOAT_BLOCK // ASTC_12x12_FLOAT 235}; 236SDL_COMPILE_TIME_ASSERT(SDLToVK_TextureFormat, SDL_arraysize(SDLToVK_TextureFormat) == SDL_GPU_TEXTUREFORMAT_MAX_ENUM_VALUE); 237 238static VkComponentMapping SwizzleForSDLFormat(SDL_GPUTextureFormat format) 239{ 240 if (format == SDL_GPU_TEXTUREFORMAT_A8_UNORM) { 241 // TODO: use VK_FORMAT_A8_UNORM_KHR from VK_KHR_maintenance5 when available 242 return (VkComponentMapping){ 243 VK_COMPONENT_SWIZZLE_ZERO, 244 VK_COMPONENT_SWIZZLE_ZERO, 245 VK_COMPONENT_SWIZZLE_ZERO, 246 VK_COMPONENT_SWIZZLE_R, 247 }; 248 } 249 250 if (format == SDL_GPU_TEXTUREFORMAT_B4G4R4A4_UNORM) { 251 // ARGB -> BGRA 252 // TODO: use VK_FORMAT_A4R4G4B4_UNORM_PACK16_EXT from VK_EXT_4444_formats when available 253 return (VkComponentMapping){ 254 VK_COMPONENT_SWIZZLE_G, 255 VK_COMPONENT_SWIZZLE_R, 256 VK_COMPONENT_SWIZZLE_A, 257 VK_COMPONENT_SWIZZLE_B, 258 }; 259 } 260 261 return (VkComponentMapping)IDENTITY_SWIZZLE; 262} 263 264static VkFormat SwapchainCompositionToFormat[] = { 265 VK_FORMAT_B8G8R8A8_UNORM, // SDR 266 VK_FORMAT_B8G8R8A8_SRGB, // SDR_LINEAR 267 VK_FORMAT_R16G16B16A16_SFLOAT, // HDR_EXTENDED_LINEAR 268 VK_FORMAT_A2B10G10R10_UNORM_PACK32 // HDR10_ST2084 269}; 270 271static VkFormat SwapchainCompositionToFallbackFormat[] = { 272 VK_FORMAT_R8G8B8A8_UNORM, // SDR 273 VK_FORMAT_R8G8B8A8_SRGB, // SDR_LINEAR 274 VK_FORMAT_UNDEFINED, // HDR_EXTENDED_LINEAR (no fallback) 275 VK_FORMAT_UNDEFINED // HDR10_ST2084 (no fallback) 276}; 277 278static SDL_GPUTextureFormat SwapchainCompositionToSDLFormat( 279 SDL_GPUSwapchainComposition composition, 280 bool usingFallback) 281{ 282 switch (composition) { 283 case SDL_GPU_SWAPCHAINCOMPOSITION_SDR: 284 return usingFallback ? SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM : SDL_GPU_TEXTUREFORMAT_B8G8R8A8_UNORM; 285 case SDL_GPU_SWAPCHAINCOMPOSITION_SDR_LINEAR: 286 return usingFallback ? SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM_SRGB : SDL_GPU_TEXTUREFORMAT_B8G8R8A8_UNORM_SRGB; 287 case SDL_GPU_SWAPCHAINCOMPOSITION_HDR_EXTENDED_LINEAR: 288 return SDL_GPU_TEXTUREFORMAT_R16G16B16A16_FLOAT; 289 case SDL_GPU_SWAPCHAINCOMPOSITION_HDR10_ST2084: 290 return SDL_GPU_TEXTUREFORMAT_R10G10B10A2_UNORM; 291 default: 292 return SDL_GPU_TEXTUREFORMAT_INVALID; 293 } 294} 295 296static VkColorSpaceKHR SwapchainCompositionToColorSpace[] = { 297 VK_COLOR_SPACE_SRGB_NONLINEAR_KHR, // SDR 298 VK_COLOR_SPACE_SRGB_NONLINEAR_KHR, // SDR_LINEAR 299 VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT, // HDR_EXTENDED_LINEAR 300 VK_COLOR_SPACE_HDR10_ST2084_EXT // HDR10_ST2084 301}; 302 303static VkComponentMapping SwapchainCompositionSwizzle[] = { 304 IDENTITY_SWIZZLE, // SDR 305 IDENTITY_SWIZZLE, // SDR_LINEAR 306 IDENTITY_SWIZZLE, // HDR_EXTENDED_LINEAR 307 { 308 // HDR10_ST2084 309 VK_COMPONENT_SWIZZLE_R, 310 VK_COMPONENT_SWIZZLE_G, 311 VK_COMPONENT_SWIZZLE_B, 312 VK_COMPONENT_SWIZZLE_A, 313 } 314}; 315 316static VkFormat SDLToVK_VertexFormat[] = { 317 VK_FORMAT_UNDEFINED, // INVALID 318 VK_FORMAT_R32_SINT, // INT 319 VK_FORMAT_R32G32_SINT, // INT2 320 VK_FORMAT_R32G32B32_SINT, // INT3 321 VK_FORMAT_R32G32B32A32_SINT, // INT4 322 VK_FORMAT_R32_UINT, // UINT 323 VK_FORMAT_R32G32_UINT, // UINT2 324 VK_FORMAT_R32G32B32_UINT, // UINT3 325 VK_FORMAT_R32G32B32A32_UINT, // UINT4 326 VK_FORMAT_R32_SFLOAT, // FLOAT 327 VK_FORMAT_R32G32_SFLOAT, // FLOAT2 328 VK_FORMAT_R32G32B32_SFLOAT, // FLOAT3 329 VK_FORMAT_R32G32B32A32_SFLOAT, // FLOAT4 330 VK_FORMAT_R8G8_SINT, // BYTE2 331 VK_FORMAT_R8G8B8A8_SINT, // BYTE4 332 VK_FORMAT_R8G8_UINT, // UBYTE2 333 VK_FORMAT_R8G8B8A8_UINT, // UBYTE4 334 VK_FORMAT_R8G8_SNORM, // BYTE2_NORM 335 VK_FORMAT_R8G8B8A8_SNORM, // BYTE4_NORM 336 VK_FORMAT_R8G8_UNORM, // UBYTE2_NORM 337 VK_FORMAT_R8G8B8A8_UNORM, // UBYTE4_NORM 338 VK_FORMAT_R16G16_SINT, // SHORT2 339 VK_FORMAT_R16G16B16A16_SINT, // SHORT4 340 VK_FORMAT_R16G16_UINT, // USHORT2 341 VK_FORMAT_R16G16B16A16_UINT, // USHORT4 342 VK_FORMAT_R16G16_SNORM, // SHORT2_NORM 343 VK_FORMAT_R16G16B16A16_SNORM, // SHORT4_NORM 344 VK_FORMAT_R16G16_UNORM, // USHORT2_NORM 345 VK_FORMAT_R16G16B16A16_UNORM, // USHORT4_NORM 346 VK_FORMAT_R16G16_SFLOAT, // HALF2 347 VK_FORMAT_R16G16B16A16_SFLOAT // HALF4 348}; 349SDL_COMPILE_TIME_ASSERT(SDLToVK_VertexFormat, SDL_arraysize(SDLToVK_VertexFormat) == SDL_GPU_VERTEXELEMENTFORMAT_MAX_ENUM_VALUE); 350 351static VkIndexType SDLToVK_IndexType[] = { 352 VK_INDEX_TYPE_UINT16, 353 VK_INDEX_TYPE_UINT32 354}; 355 356static VkPrimitiveTopology SDLToVK_PrimitiveType[] = { 357 VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, 358 VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, 359 VK_PRIMITIVE_TOPOLOGY_LINE_LIST, 360 VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, 361 VK_PRIMITIVE_TOPOLOGY_POINT_LIST 362}; 363 364static VkCullModeFlags SDLToVK_CullMode[] = { 365 VK_CULL_MODE_NONE, 366 VK_CULL_MODE_FRONT_BIT, 367 VK_CULL_MODE_BACK_BIT, 368 VK_CULL_MODE_FRONT_AND_BACK 369}; 370 371static VkFrontFace SDLToVK_FrontFace[] = { 372 VK_FRONT_FACE_COUNTER_CLOCKWISE, 373 VK_FRONT_FACE_CLOCKWISE 374}; 375 376static VkBlendFactor SDLToVK_BlendFactor[] = { 377 VK_BLEND_FACTOR_ZERO, // INVALID 378 VK_BLEND_FACTOR_ZERO, 379 VK_BLEND_FACTOR_ONE, 380 VK_BLEND_FACTOR_SRC_COLOR, 381 VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR, 382 VK_BLEND_FACTOR_DST_COLOR, 383 VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR, 384 VK_BLEND_FACTOR_SRC_ALPHA, 385 VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA, 386 VK_BLEND_FACTOR_DST_ALPHA, 387 VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA, 388 VK_BLEND_FACTOR_CONSTANT_COLOR, 389 VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR, 390 VK_BLEND_FACTOR_SRC_ALPHA_SATURATE 391}; 392SDL_COMPILE_TIME_ASSERT(SDLToVK_BlendFactor, SDL_arraysize(SDLToVK_BlendFactor) == SDL_GPU_BLENDFACTOR_MAX_ENUM_VALUE); 393 394static VkBlendOp SDLToVK_BlendOp[] = { 395 VK_BLEND_OP_ADD, // INVALID 396 VK_BLEND_OP_ADD, 397 VK_BLEND_OP_SUBTRACT, 398 VK_BLEND_OP_REVERSE_SUBTRACT, 399 VK_BLEND_OP_MIN, 400 VK_BLEND_OP_MAX 401}; 402SDL_COMPILE_TIME_ASSERT(SDLToVK_BlendOp, SDL_arraysize(SDLToVK_BlendOp) == SDL_GPU_BLENDOP_MAX_ENUM_VALUE); 403 404static VkCompareOp SDLToVK_CompareOp[] = { 405 VK_COMPARE_OP_NEVER, // INVALID 406 VK_COMPARE_OP_NEVER, 407 VK_COMPARE_OP_LESS, 408 VK_COMPARE_OP_EQUAL, 409 VK_COMPARE_OP_LESS_OR_EQUAL, 410 VK_COMPARE_OP_GREATER, 411 VK_COMPARE_OP_NOT_EQUAL, 412 VK_COMPARE_OP_GREATER_OR_EQUAL, 413 VK_COMPARE_OP_ALWAYS 414}; 415SDL_COMPILE_TIME_ASSERT(SDLToVK_CompareOp, SDL_arraysize(SDLToVK_CompareOp) == SDL_GPU_COMPAREOP_MAX_ENUM_VALUE); 416 417static VkStencilOp SDLToVK_StencilOp[] = { 418 VK_STENCIL_OP_KEEP, // INVALID 419 VK_STENCIL_OP_KEEP, 420 VK_STENCIL_OP_ZERO, 421 VK_STENCIL_OP_REPLACE, 422 VK_STENCIL_OP_INCREMENT_AND_CLAMP, 423 VK_STENCIL_OP_DECREMENT_AND_CLAMP, 424 VK_STENCIL_OP_INVERT, 425 VK_STENCIL_OP_INCREMENT_AND_WRAP, 426 VK_STENCIL_OP_DECREMENT_AND_WRAP 427}; 428SDL_COMPILE_TIME_ASSERT(SDLToVK_StencilOp, SDL_arraysize(SDLToVK_StencilOp) == SDL_GPU_STENCILOP_MAX_ENUM_VALUE); 429 430static VkAttachmentLoadOp SDLToVK_LoadOp[] = { 431 VK_ATTACHMENT_LOAD_OP_LOAD, 432 VK_ATTACHMENT_LOAD_OP_CLEAR, 433 VK_ATTACHMENT_LOAD_OP_DONT_CARE 434}; 435 436static VkAttachmentStoreOp SDLToVK_StoreOp[] = { 437 VK_ATTACHMENT_STORE_OP_STORE, 438 VK_ATTACHMENT_STORE_OP_DONT_CARE, 439 VK_ATTACHMENT_STORE_OP_DONT_CARE, 440 VK_ATTACHMENT_STORE_OP_STORE 441}; 442 443static VkSampleCountFlagBits SDLToVK_SampleCount[] = { 444 VK_SAMPLE_COUNT_1_BIT, 445 VK_SAMPLE_COUNT_2_BIT, 446 VK_SAMPLE_COUNT_4_BIT, 447 VK_SAMPLE_COUNT_8_BIT 448}; 449 450static VkVertexInputRate SDLToVK_VertexInputRate[] = { 451 VK_VERTEX_INPUT_RATE_VERTEX, 452 VK_VERTEX_INPUT_RATE_INSTANCE 453}; 454 455static VkFilter SDLToVK_Filter[] = { 456 VK_FILTER_NEAREST, 457 VK_FILTER_LINEAR 458}; 459 460static VkSamplerMipmapMode SDLToVK_SamplerMipmapMode[] = { 461 VK_SAMPLER_MIPMAP_MODE_NEAREST, 462 VK_SAMPLER_MIPMAP_MODE_LINEAR 463}; 464 465static VkSamplerAddressMode SDLToVK_SamplerAddressMode[] = { 466 VK_SAMPLER_ADDRESS_MODE_REPEAT, 467 VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT, 468 VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE 469}; 470 471// Structures 472 473typedef struct VulkanRenderer VulkanRenderer; 474typedef struct VulkanCommandPool VulkanCommandPool; 475typedef struct VulkanMemoryAllocation VulkanMemoryAllocation; 476typedef struct VulkanBuffer VulkanBuffer; 477typedef struct VulkanBufferContainer VulkanBufferContainer; 478typedef struct VulkanUniformBuffer VulkanUniformBuffer; 479typedef struct VulkanTexture VulkanTexture; 480typedef struct VulkanTextureContainer VulkanTextureContainer; 481 482typedef struct VulkanFenceHandle 483{ 484 VkFence fence; 485 SDL_AtomicInt referenceCount; 486} VulkanFenceHandle; 487 488// Memory Allocation 489 490typedef struct VulkanMemoryFreeRegion 491{ 492 VulkanMemoryAllocation *allocation; 493 VkDeviceSize offset; 494 VkDeviceSize size; 495 Uint32 allocationIndex; 496 Uint32 sortedIndex; 497} VulkanMemoryFreeRegion; 498 499typedef struct VulkanMemoryUsedRegion 500{ 501 VulkanMemoryAllocation *allocation; 502 VkDeviceSize offset; 503 VkDeviceSize size; 504 VkDeviceSize resourceOffset; // differs from offset based on alignment 505 VkDeviceSize resourceSize; // differs from size based on alignment 506 VkDeviceSize alignment; 507 Uint8 isBuffer; 508 union 509 { 510 VulkanBuffer *vulkanBuffer; 511 VulkanTexture *vulkanTexture; 512 }; 513} VulkanMemoryUsedRegion; 514 515typedef struct VulkanMemorySubAllocator 516{ 517 Uint32 memoryTypeIndex; 518 VulkanMemoryAllocation **allocations; 519 Uint32 allocationCount; 520 VulkanMemoryFreeRegion **sortedFreeRegions; 521 Uint32 sortedFreeRegionCount; 522 Uint32 sortedFreeRegionCapacity; 523} VulkanMemorySubAllocator; 524 525struct VulkanMemoryAllocation 526{ 527 VulkanMemorySubAllocator *allocator; 528 VkDeviceMemory memory; 529 VkDeviceSize size; 530 VulkanMemoryUsedRegion **usedRegions; 531 Uint32 usedRegionCount; 532 Uint32 usedRegionCapacity; 533 VulkanMemoryFreeRegion **freeRegions; 534 Uint32 freeRegionCount; 535 Uint32 freeRegionCapacity; 536 Uint8 availableForAllocation; 537 VkDeviceSize freeSpace; 538 VkDeviceSize usedSpace; 539 Uint8 *mapPointer; 540 SDL_Mutex *memoryLock; 541 SDL_AtomicInt referenceCount; // Used to avoid defrag races 542}; 543 544typedef struct VulkanMemoryAllocator 545{ 546 VulkanMemorySubAllocator subAllocators[VK_MAX_MEMORY_TYPES]; 547} VulkanMemoryAllocator; 548 549// Memory structures 550 551typedef enum VulkanBufferType 552{ 553 VULKAN_BUFFER_TYPE_GPU, 554 VULKAN_BUFFER_TYPE_UNIFORM, 555 VULKAN_BUFFER_TYPE_TRANSFER 556} VulkanBufferType; 557 558struct VulkanBuffer 559{ 560 VulkanBufferContainer *container; 561 Uint32 containerIndex; 562 563 VkBuffer buffer; 564 VulkanMemoryUsedRegion *usedRegion; 565 566 // Needed for uniforms and defrag 567 VulkanBufferType type; 568 SDL_GPUBufferUsageFlags usage; 569 VkDeviceSize size; 570 571 SDL_AtomicInt referenceCount; 572 bool transitioned; 573 bool markedForDestroy; // so that defrag doesn't double-free 574 VulkanUniformBuffer *uniformBufferForDefrag; 575}; 576 577struct VulkanBufferContainer 578{ 579 VulkanBuffer *activeBuffer; 580 581 VulkanBuffer **buffers; 582 Uint32 bufferCapacity; 583 Uint32 bufferCount; 584 585 bool dedicated; 586 char *debugName; 587}; 588 589// Renderer Structure 590 591typedef struct QueueFamilyIndices 592{ 593 Uint32 graphicsFamily; 594 Uint32 presentFamily; 595 Uint32 computeFamily; 596 Uint32 transferFamily; 597} QueueFamilyIndices; 598 599typedef struct VulkanSampler 600{ 601 VkSampler sampler; 602 SDL_AtomicInt referenceCount; 603} VulkanSampler; 604 605typedef struct VulkanShader 606{ 607 VkShaderModule shaderModule; 608 char *entrypointName; 609 SDL_GPUShaderStage stage; 610 Uint32 numSamplers; 611 Uint32 numStorageTextures; 612 Uint32 numStorageBuffers; 613 Uint32 numUniformBuffers; 614 SDL_AtomicInt referenceCount; 615} VulkanShader; 616 617/* Textures are made up of individual subresources. 618 * This helps us barrier the resource efficiently. 619 */ 620typedef struct VulkanTextureSubresource 621{ 622 VulkanTexture *parent; 623 Uint32 layer; 624 Uint32 level; 625 626 VkImageView *renderTargetViews; // One render target view per depth slice 627 VkImageView computeWriteView; 628 VkImageView depthStencilView; 629} VulkanTextureSubresource; 630 631struct VulkanTexture 632{ 633 VulkanTextureContainer *container; 634 Uint32 containerIndex; 635 636 VulkanMemoryUsedRegion *usedRegion; 637 638 VkImage image; 639 VkImageView fullView; // used for samplers and storage reads 640 VkComponentMapping swizzle; 641 VkImageAspectFlags aspectFlags; 642 Uint32 depth; // used for cleanup only 643 644 // FIXME: It'd be nice if we didn't have to have this on the texture... 645 SDL_GPUTextureUsageFlags usage; // used for defrag transitions only. 646 647 Uint32 subresourceCount; 648 VulkanTextureSubresource *subresources; 649 650 bool markedForDestroy; // so that defrag doesn't double-free 651 bool externallyManaged; // true for XR swapchain images 652 SDL_AtomicInt referenceCount; 653}; 654 655struct VulkanTextureContainer 656{ 657 TextureCommonHeader header; 658 659 VulkanTexture *activeTexture; 660 661 Uint32 textureCapacity; 662 Uint32 textureCount; 663 VulkanTexture **textures; 664 665 char *debugName; 666 bool canBeCycled; 667 bool externallyManaged; // true for XR swapchain images 668}; 669 670typedef enum VulkanBufferUsageMode 671{ 672 VULKAN_BUFFER_USAGE_MODE_COPY_SOURCE, 673 VULKAN_BUFFER_USAGE_MODE_COPY_DESTINATION, 674 VULKAN_BUFFER_USAGE_MODE_VERTEX_READ, 675 VULKAN_BUFFER_USAGE_MODE_INDEX_READ, 676 VULKAN_BUFFER_USAGE_MODE_INDIRECT, 677 VULKAN_BUFFER_USAGE_MODE_GRAPHICS_STORAGE_READ, 678 VULKAN_BUFFER_USAGE_MODE_COMPUTE_STORAGE_READ, 679 VULKAN_BUFFER_USAGE_MODE_COMPUTE_STORAGE_READ_WRITE, 680} VulkanBufferUsageMode; 681 682typedef enum VulkanTextureUsageMode 683{ 684 VULKAN_TEXTURE_USAGE_MODE_UNINITIALIZED, 685 VULKAN_TEXTURE_USAGE_MODE_COPY_SOURCE, 686 VULKAN_TEXTURE_USAGE_MODE_COPY_DESTINATION, 687 VULKAN_TEXTURE_USAGE_MODE_SAMPLER, 688 VULKAN_TEXTURE_USAGE_MODE_GRAPHICS_STORAGE_READ, 689 VULKAN_TEXTURE_USAGE_MODE_COMPUTE_STORAGE_READ, 690 VULKAN_TEXTURE_USAGE_MODE_COMPUTE_STORAGE_READ_WRITE, 691 VULKAN_TEXTURE_USAGE_MODE_COLOR_ATTACHMENT, 692 VULKAN_TEXTURE_USAGE_MODE_DEPTH_STENCIL_ATTACHMENT, 693 VULKAN_TEXTURE_USAGE_MODE_PRESENT 694} VulkanTextureUsageMode; 695 696typedef enum VulkanUniformBufferStage 697{ 698 VULKAN_UNIFORM_BUFFER_STAGE_VERTEX, 699 VULKAN_UNIFORM_BUFFER_STAGE_FRAGMENT, 700 VULKAN_UNIFORM_BUFFER_STAGE_COMPUTE 701} VulkanUniformBufferStage; 702 703typedef struct VulkanFramebuffer 704{ 705 VkFramebuffer framebuffer; 706 SDL_AtomicInt referenceCount; 707} VulkanFramebuffer; 708 709typedef struct WindowData 710{ 711 SDL_Window *window; 712 VulkanRenderer *renderer; 713 int refcount; 714 SDL_GPUSwapchainComposition swapchainComposition; 715 SDL_GPUPresentMode presentMode; 716 bool needsSwapchainRecreate; 717 bool needsSurfaceRecreate; 718 Uint32 swapchainCreateWidth; 719 Uint32 swapchainCreateHeight; 720 721 // Window surface 722 VkSurfaceKHR surface; 723 724 // Swapchain for window surface 725 VkSwapchainKHR swapchain; 726 VkFormat format; 727 VkColorSpaceKHR colorSpace; 728 VkComponentMapping swapchainSwizzle; 729 bool usingFallbackFormat; 730 731 // Swapchain images 732 VulkanTextureContainer *textureContainers; // use containers so that swapchain textures can use the same API as other textures 733 Uint32 imageCount; 734 Uint32 width; 735 Uint32 height; 736 737 // Synchronization primitives 738 VkSemaphore imageAvailableSemaphore[MAX_FRAMES_IN_FLIGHT]; 739 VkSemaphore *renderFinishedSemaphore; 740 SDL_GPUFence *inFlightFences[MAX_FRAMES_IN_FLIGHT]; 741 742 Uint32 frameCounter; 743} WindowData; 744 745typedef struct SwapchainSupportDetails 746{ 747 VkSurfaceCapabilitiesKHR capabilities; 748 VkSurfaceFormatKHR *formats; 749 Uint32 formatsLength; 750 VkPresentModeKHR *presentModes; 751 Uint32 presentModesLength; 752} SwapchainSupportDetails; 753 754typedef struct VulkanPresentData 755{ 756 WindowData *windowData; 757 Uint32 swapchainImageIndex; 758} VulkanPresentData; 759 760struct VulkanUniformBuffer 761{ 762 VulkanBuffer *buffer; 763 Uint32 drawOffset; 764 Uint32 writeOffset; 765}; 766 767typedef struct VulkanDescriptorInfo 768{ 769 VkDescriptorType descriptorType; 770 VkShaderStageFlagBits stageFlag; 771} VulkanDescriptorInfo; 772 773typedef struct DescriptorSetPool 774{ 775 // It's a pool... of pools!!! 776 Uint32 poolCount; 777 VkDescriptorPool *descriptorPools; 778 779 // We'll just manage the descriptor sets ourselves instead of freeing the sets 780 VkDescriptorSet *descriptorSets; 781 Uint32 descriptorSetCount; 782 Uint32 descriptorSetIndex; 783} DescriptorSetPool; 784 785// A command buffer acquires a cache at command buffer acquisition time 786typedef struct DescriptorSetCache 787{ 788 // Pools are indexed by DescriptorSetLayoutID which increases monotonically 789 // There's only a certain number of maximum layouts possible since we de-duplicate them. 790 DescriptorSetPool *pools; 791 Uint32 poolCount; 792} DescriptorSetCache; 793 794typedef struct DescriptorSetLayoutHashTableKey 795{ 796 VkShaderStageFlagBits shaderStage; 797 // Category 1: read resources 798 Uint32 samplerCount; 799 Uint32 storageBufferCount; 800 Uint32 storageTextureCount; 801 // Category 2: write resources 802 Uint32 writeStorageBufferCount; 803 Uint32 writeStorageTextureCount; 804 // Category 3: uniform buffers 805 Uint32 uniformBufferCount; 806} DescriptorSetLayoutHashTableKey; 807 808typedef uint32_t DescriptorSetLayoutID; 809 810typedef struct DescriptorSetLayout 811{ 812 DescriptorSetLayoutID ID; 813 VkDescriptorSetLayout descriptorSetLayout; 814 815 // Category 1: read resources 816 Uint32 samplerCount; 817 Uint32 storageBufferCount; 818 Uint32 storageTextureCount; 819 // Category 2: write resources 820 Uint32 writeStorageBufferCount; 821 Uint32 writeStorageTextureCount; 822 // Category 3: uniform buffers 823 Uint32 uniformBufferCount; 824} DescriptorSetLayout; 825 826typedef struct GraphicsPipelineResourceLayoutHashTableKey 827{ 828 Uint32 vertexSamplerCount; 829 Uint32 vertexStorageTextureCount; 830 Uint32 vertexStorageBufferCount; 831 Uint32 vertexUniformBufferCount; 832 833 Uint32 fragmentSamplerCount; 834 Uint32 fragmentStorageTextureCount; 835 Uint32 fragmentStorageBufferCount; 836 Uint32 fragmentUniformBufferCount; 837} GraphicsPipelineResourceLayoutHashTableKey; 838 839typedef struct VulkanGraphicsPipelineResourceLayout 840{ 841 VkPipelineLayout pipelineLayout; 842 843 /* 844 * Descriptor set layout is as follows: 845 * 0: vertex resources 846 * 1: vertex uniform buffers 847 * 2: fragment resources 848 * 3: fragment uniform buffers 849 */ 850 DescriptorSetLayout *descriptorSetLayouts[4]; 851 852 Uint32 vertexSamplerCount; 853 Uint32 vertexStorageTextureCount; 854 Uint32 vertexStorageBufferCount; 855 Uint32 vertexUniformBufferCount; 856 857 Uint32 fragmentSamplerCount; 858 Uint32 fragmentStorageTextureCount; 859 Uint32 fragmentStorageBufferCount; 860 Uint32 fragmentUniformBufferCount; 861} VulkanGraphicsPipelineResourceLayout; 862 863typedef struct VulkanGraphicsPipeline 864{ 865 GraphicsPipelineCommonHeader header; 866 867 VkPipeline pipeline; 868 SDL_GPUPrimitiveType primitiveType; 869 870 VulkanGraphicsPipelineResourceLayout *resourceLayout; 871 872 VulkanShader *vertexShader; 873 VulkanShader *fragmentShader; 874 875 SDL_AtomicInt referenceCount; 876} VulkanGraphicsPipeline; 877 878typedef struct ComputePipelineResourceLayoutHashTableKey 879{ 880 Uint32 samplerCount; 881 Uint32 readonlyStorageTextureCount; 882 Uint32 readonlyStorageBufferCount; 883 Uint32 readWriteStorageTextureCount; 884 Uint32 readWriteStorageBufferCount; 885 Uint32 uniformBufferCount; 886} ComputePipelineResourceLayoutHashTableKey; 887 888typedef struct VulkanComputePipelineResourceLayout 889{ 890 VkPipelineLayout pipelineLayout; 891 892 /* 893 * Descriptor set layout is as follows: 894 * 0: samplers, then read-only textures, then read-only buffers 895 * 1: write-only textures, then write-only buffers 896 * 2: uniform buffers 897 */ 898 DescriptorSetLayout *descriptorSetLayouts[3]; 899 900 Uint32 numSamplers; 901 Uint32 numReadonlyStorageTextures; 902 Uint32 numReadonlyStorageBuffers; 903 Uint32 numReadWriteStorageTextures; 904 Uint32 numReadWriteStorageBuffers; 905 Uint32 numUniformBuffers; 906} VulkanComputePipelineResourceLayout; 907 908typedef struct VulkanComputePipeline 909{ 910 ComputePipelineCommonHeader header; 911 912 VkShaderModule shaderModule; 913 VkPipeline pipeline; 914 VulkanComputePipelineResourceLayout *resourceLayout; 915 SDL_AtomicInt referenceCount; 916} VulkanComputePipeline; 917 918typedef struct RenderPassColorTargetDescription 919{ 920 VkFormat format; 921 SDL_GPULoadOp loadOp; 922 SDL_GPUStoreOp storeOp; 923} RenderPassColorTargetDescription; 924 925typedef struct RenderPassDepthStencilTargetDescription 926{ 927 VkFormat format; 928 SDL_GPULoadOp loadOp; 929 SDL_GPUStoreOp storeOp; 930 SDL_GPULoadOp stencilLoadOp; 931 SDL_GPUStoreOp stencilStoreOp; 932} RenderPassDepthStencilTargetDescription; 933 934typedef struct CommandPoolHashTableKey 935{ 936 SDL_ThreadID threadID; 937} CommandPoolHashTableKey; 938 939typedef struct RenderPassHashTableKey 940{ 941 RenderPassColorTargetDescription colorTargetDescriptions[MAX_COLOR_TARGET_BINDINGS]; 942 Uint32 numColorTargets; 943 VkFormat resolveTargetFormats[MAX_COLOR_TARGET_BINDINGS]; 944 Uint32 numResolveTargets; 945 RenderPassDepthStencilTargetDescription depthStencilTargetDescription; 946 VkSampleCountFlagBits sampleCount; 947} RenderPassHashTableKey; 948 949typedef struct VulkanRenderPassHashTableValue 950{ 951 VkRenderPass handle; 952} VulkanRenderPassHashTableValue; 953 954typedef struct FramebufferHashTableKey 955{ 956 VkImageView colorAttachmentViews[MAX_COLOR_TARGET_BINDINGS]; 957 Uint32 numColorTargets; 958 VkImageView resolveAttachmentViews[MAX_COLOR_TARGET_BINDINGS]; 959 Uint32 numResolveAttachments; 960 VkImageView depthStencilAttachmentView; 961 Uint32 width; 962 Uint32 height; 963} FramebufferHashTableKey; 964 965// Command structures 966 967typedef struct VulkanFencePool 968{ 969 SDL_Mutex *lock; 970 971 VulkanFenceHandle **availableFences; 972 Uint32 availableFenceCount; 973 Uint32 availableFenceCapacity; 974} VulkanFencePool; 975 976typedef struct VulkanCommandBuffer 977{ 978 CommandBufferCommonHeader common; 979 VulkanRenderer *renderer; 980 981 VkCommandBuffer commandBuffer; 982 VulkanCommandPool *commandPool; 983 984 VulkanPresentData *presentDatas; 985 Uint32 presentDataCount; 986 Uint32 presentDataCapacity; 987 988 VkSemaphore *waitSemaphores; 989 Uint32 waitSemaphoreCount; 990 Uint32 waitSemaphoreCapacity; 991 992 VkSemaphore *signalSemaphores; 993 Uint32 signalSemaphoreCount; 994 Uint32 signalSemaphoreCapacity; 995 996 VulkanComputePipeline *currentComputePipeline; 997 VulkanGraphicsPipeline *currentGraphicsPipeline; 998 999 // Keep track of resources transitioned away from their default state to barrier them on pass end 1000 1001 VulkanTextureSubresource *colorAttachmentSubresources[MAX_COLOR_TARGET_BINDINGS]; 1002 Uint32 colorAttachmentSubresourceCount; 1003 VulkanTextureSubresource *resolveAttachmentSubresources[MAX_COLOR_TARGET_BINDINGS]; 1004 Uint32 resolveAttachmentSubresourceCount; 1005 1006 VulkanTextureSubresource *depthStencilAttachmentSubresource; // may be NULL 1007 1008 // Dynamic state 1009 1010 VkViewport currentViewport; 1011 VkRect2D currentScissor; 1012 float blendConstants[4]; 1013 Uint8 stencilRef; 1014 1015 // Resource bind state 1016 1017 DescriptorSetCache *descriptorSetCache; // acquired when command buffer is acquired 1018 1019 bool needNewVertexResourceDescriptorSet; 1020 bool needNewVertexUniformDescriptorSet; 1021 bool needNewVertexUniformOffsets; 1022 bool needNewFragmentResourceDescriptorSet; 1023 bool needNewFragmentUniformDescriptorSet; 1024 bool needNewFragmentUniformOffsets; 1025 1026 bool needNewComputeReadOnlyDescriptorSet; 1027 bool needNewComputeReadWriteDescriptorSet; 1028 bool needNewComputeUniformDescriptorSet; 1029 bool needNewComputeUniformOffsets; 1030 1031 VkDescriptorSet vertexResourceDescriptorSet; 1032 VkDescriptorSet vertexUniformDescriptorSet; 1033 VkDescriptorSet fragmentResourceDescriptorSet; 1034 VkDescriptorSet fragmentUniformDescriptorSet; 1035 1036 VkDescriptorSet computeReadOnlyDescriptorSet; 1037 VkDescriptorSet computeReadWriteDescriptorSet; 1038 VkDescriptorSet computeUniformDescriptorSet; 1039 1040 VkBuffer vertexBuffers[MAX_VERTEX_BUFFERS]; 1041 VkDeviceSize vertexBufferOffsets[MAX_VERTEX_BUFFERS]; 1042 Uint32 vertexBufferCount; 1043 bool needVertexBufferBind; 1044 1045 VkImageView vertexSamplerTextureViewBindings[MAX_TEXTURE_SAMPLERS_PER_STAGE]; 1046 VkSampler vertexSamplerBindings[MAX_TEXTURE_SAMPLERS_PER_STAGE]; 1047 VkImageView vertexStorageTextureViewBindings[MAX_STORAGE_TEXTURES_PER_STAGE]; 1048 VkBuffer vertexStorageBufferBindings[MAX_STORAGE_BUFFERS_PER_STAGE]; 1049 1050 VkImageView fragmentSamplerTextureViewBindings[MAX_TEXTURE_SAMPLERS_PER_STAGE]; 1051 VkSampler fragmentSamplerBindings[MAX_TEXTURE_SAMPLERS_PER_STAGE]; 1052 VkImageView fragmentStorageTextureViewBindings[MAX_STORAGE_TEXTURES_PER_STAGE]; 1053 VkBuffer fragmentStorageBufferBindings[MAX_STORAGE_BUFFERS_PER_STAGE]; 1054 1055 VkImageView computeSamplerTextureViewBindings[MAX_TEXTURE_SAMPLERS_PER_STAGE]; 1056 VkSampler computeSamplerBindings[MAX_TEXTURE_SAMPLERS_PER_STAGE]; 1057 VkImageView readOnlyComputeStorageTextureViewBindings[MAX_STORAGE_TEXTURES_PER_STAGE]; 1058 VkBuffer readOnlyComputeStorageBufferBindings[MAX_STORAGE_BUFFERS_PER_STAGE]; 1059 1060 // Track these separately because barriers can happen mid compute pass 1061 VulkanTexture *readOnlyComputeStorageTextures[MAX_STORAGE_TEXTURES_PER_STAGE]; 1062 VulkanBuffer *readOnlyComputeStorageBuffers[MAX_STORAGE_BUFFERS_PER_STAGE]; 1063 1064 VkImageView readWriteComputeStorageTextureViewBindings[MAX_COMPUTE_WRITE_TEXTURES]; 1065 VkBuffer readWriteComputeStorageBufferBindings[MAX_COMPUTE_WRITE_BUFFERS]; 1066 1067 // Track these separately because they are barriered when the compute pass begins 1068 VulkanTextureSubresource *readWriteComputeStorageTextureSubresources[MAX_COMPUTE_WRITE_TEXTURES]; 1069 Uint32 readWriteComputeStorageTextureSubresourceCount; 1070 VulkanBuffer *readWriteComputeStorageBuffers[MAX_COMPUTE_WRITE_BUFFERS]; 1071 1072 // Uniform buffers 1073 1074 VulkanUniformBuffer *vertexUniformBuffers[MAX_UNIFORM_BUFFERS_PER_STAGE]; 1075 VulkanUniformBuffer *fragmentUniformBuffers[MAX_UNIFORM_BUFFERS_PER_STAGE]; 1076 VulkanUniformBuffer *computeUniformBuffers[MAX_UNIFORM_BUFFERS_PER_STAGE]; 1077 1078 // Track used resources 1079 1080 VulkanBuffer **usedBuffers; 1081 Sint32 usedBufferCount; 1082 Sint32 usedBufferCapacity; 1083 1084 VulkanBuffer **buffersUsedInPendingTransfers; 1085 Sint32 buffersUsedInPendingTransfersCount; 1086 Sint32 buffersUsedInPendingTransfersCapacity; 1087 1088 VulkanTexture **usedTextures; 1089 Sint32 usedTextureCount; 1090 Sint32 usedTextureCapacity; 1091 1092 VulkanTexture **texturesUsedInPendingTransfers; 1093 Sint32 texturesUsedInPendingTransfersCount; 1094 Sint32 texturesUsedInPendingTransfersCapacity; 1095 1096 VulkanSampler **usedSamplers; 1097 Sint32 usedSamplerCount; 1098 Sint32 usedSamplerCapacity; 1099 1100 VulkanGraphicsPipeline **usedGraphicsPipelines; 1101 Sint32 usedGraphicsPipelineCount; 1102 Sint32 usedGraphicsPipelineCapacity; 1103 1104 VulkanComputePipeline **usedComputePipelines; 1105 Sint32 usedComputePipelineCount; 1106 Sint32 usedComputePipelineCapacity; 1107 1108 VulkanFramebuffer **usedFramebuffers; 1109 Sint32 usedFramebufferCount; 1110 Sint32 usedFramebufferCapacity; 1111 1112 VulkanUniformBuffer **usedUniformBuffers; 1113 Sint32 usedUniformBufferCount; 1114 Sint32 usedUniformBufferCapacity; 1115 1116 VulkanFenceHandle *inFlightFence; 1117 bool autoReleaseFence; 1118 1119 bool swapchainRequested; 1120 bool isDefrag; // Whether this CB was created for defragging 1121} VulkanCommandBuffer; 1122 1123struct VulkanCommandPool 1124{ 1125 SDL_ThreadID threadID; 1126 VkCommandPool commandPool; 1127 1128 VulkanCommandBuffer **inactiveCommandBuffers; 1129 Uint32 inactiveCommandBufferCapacity; 1130 Uint32 inactiveCommandBufferCount; 1131}; 1132 1133// Feature Checks 1134 1135typedef struct VulkanFeatures 1136{ 1137 Uint32 desiredApiVersion; 1138 VkPhysicalDeviceFeatures desiredVulkan10DeviceFeatures; 1139 VkPhysicalDeviceVulkan11Features desiredVulkan11DeviceFeatures; 1140 VkPhysicalDeviceVulkan12Features desiredVulkan12DeviceFeatures; 1141 VkPhysicalDeviceVulkan13Features desiredVulkan13DeviceFeatures; 1142 1143 bool usesCustomVulkanOptions; 1144 1145 Uint32 additionalDeviceExtensionCount; 1146 const char **additionalDeviceExtensionNames; 1147 Uint32 additionalInstanceExtensionCount; 1148 const char **additionalInstanceExtensionNames; 1149} VulkanFeatures; 1150 1151// Context 1152 1153struct VulkanRenderer 1154{ 1155 VkInstance instance; 1156 VkPhysicalDevice physicalDevice; 1157 VkPhysicalDeviceProperties2KHR physicalDeviceProperties; 1158 VkPhysicalDeviceDriverPropertiesKHR physicalDeviceDriverProperties; 1159 VkDevice logicalDevice; 1160 Uint8 integratedMemoryNotification; 1161 Uint8 outOfDeviceLocalMemoryWarning; 1162 Uint8 outofBARMemoryWarning; 1163 Uint8 fillModeOnlyWarning; 1164 1165 // OpenXR 1166 Uint32 minimumVkVersion; 1167#ifdef HAVE_GPU_OPENXR 1168 XrInstance xrInstance; // a non-null instance also states this vk device was created by OpenXR 1169 XrSystemId xrSystemId; 1170 XrInstancePfns *xr; 1171#endif 1172 1173 bool debugMode; 1174 bool preferLowPower; 1175 bool requireHardwareAcceleration; 1176 SDL_PropertiesID props; 1177 Uint32 allowedFramesInFlight; 1178 1179 VulkanExtensions supports; 1180 bool supportsDebugUtils; 1181 bool supportsColorspace; 1182 bool supportsPhysicalDeviceProperties2; 1183 bool supportsPortabilityEnumeration; 1184 bool supportsFillModeNonSolid; 1185 bool supportsMultiDrawIndirect; 1186 1187 VulkanMemoryAllocator *memoryAllocator; 1188 VkPhysicalDeviceMemoryProperties memoryProperties; 1189 bool checkEmptyAllocations; 1190 1191 WindowData **claimedWindows; 1192 Uint32 claimedWindowCount; 1193 Uint32 claimedWindowCapacity; 1194 1195 Uint32 queueFamilyIndex; 1196 VkQueue unifiedQueue; 1197 1198 VulkanCommandBuffer **submittedCommandBuffers; 1199 Uint32 submittedCommandBufferCount; 1200 Uint32 submittedCommandBufferCapacity; 1201 1202 VulkanFencePool fencePool; 1203 1204 SDL_HashTable *commandPoolHashTable; 1205 SDL_HashTable *renderPassHashTable; 1206 SDL_HashTable *framebufferHashTable; 1207 SDL_HashTable *graphicsPipelineResourceLayoutHashTable; 1208 SDL_HashTable *computePipelineResourceLayoutHashTable; 1209 SDL_HashTable *descriptorSetLayoutHashTable; 1210 1211 VulkanUniformBuffer **uniformBufferPool; 1212 Uint32 uniformBufferPoolCount; 1213 Uint32 uniformBufferPoolCapacity; 1214 1215 DescriptorSetCache **descriptorSetCachePool; 1216 Uint32 descriptorSetCachePoolCount; 1217 Uint32 descriptorSetCachePoolCapacity; 1218 1219 SDL_AtomicInt layoutResourceID; 1220 1221 Uint32 minUBOAlignment; 1222 1223 // Deferred resource destruction 1224 1225 VulkanTexture **texturesToDestroy; 1226 Uint32 texturesToDestroyCount; 1227 Uint32 texturesToDestroyCapacity; 1228 1229 VulkanBuffer **buffersToDestroy; 1230 Uint32 buffersToDestroyCount; 1231 Uint32 buffersToDestroyCapacity; 1232 1233 VulkanSampler **samplersToDestroy; 1234 Uint32 samplersToDestroyCount; 1235 Uint32 samplersToDestroyCapacity; 1236 1237 VulkanGraphicsPipeline **graphicsPipelinesToDestroy; 1238 Uint32 graphicsPipelinesToDestroyCount; 1239 Uint32 graphicsPipelinesToDestroyCapacity; 1240 1241 VulkanComputePipeline **computePipelinesToDestroy; 1242 Uint32 computePipelinesToDestroyCount; 1243 Uint32 computePipelinesToDestroyCapacity; 1244 1245 VulkanShader **shadersToDestroy; 1246 Uint32 shadersToDestroyCount; 1247 Uint32 shadersToDestroyCapacity; 1248 1249 VulkanFramebuffer **framebuffersToDestroy; 1250 Uint32 framebuffersToDestroyCount; 1251 Uint32 framebuffersToDestroyCapacity; 1252 1253 SDL_Mutex *allocatorLock; 1254 SDL_Mutex *disposeLock; 1255 SDL_Mutex *submitLock; 1256 SDL_Mutex *acquireCommandBufferLock; 1257 SDL_Mutex *acquireUniformBufferLock; 1258 SDL_Mutex *renderPassFetchLock; 1259 SDL_Mutex *framebufferFetchLock; 1260 SDL_Mutex *graphicsPipelineLayoutFetchLock; 1261 SDL_Mutex *computePipelineLayoutFetchLock; 1262 SDL_Mutex *descriptorSetLayoutFetchLock; 1263 SDL_Mutex *windowLock; 1264 1265 // We don't want transfer commands to block each other, 1266 // but we want all transfers to block during defrag. 1267 SDL_RWLock *defragLock; 1268 1269 Uint8 defragInProgress; 1270 1271 VulkanMemoryAllocation **allocationsToDefrag; 1272 Uint32 allocationsToDefragCount; 1273 Uint32 allocationsToDefragCapacity; 1274 1275#define VULKAN_INSTANCE_FUNCTION(func) \ 1276 PFN_##func func; 1277#define VULKAN_DEVICE_FUNCTION(func) \ 1278 PFN_##func func; 1279#include "SDL_gpu_vulkan_vkfuncs.h" 1280}; 1281 1282// Forward declarations 1283 1284static bool VULKAN_INTERNAL_DefragmentMemory(VulkanRenderer *renderer, VulkanCommandBuffer *commandBuffer); 1285static bool VULKAN_INTERNAL_BeginCommandBuffer(VulkanRenderer *renderer, VulkanCommandBuffer *commandBuffer); 1286static void VULKAN_ReleaseTexture(SDL_GPURenderer *driverData, SDL_GPUTexture *texture); 1287static void VULKAN_ReleaseWindow(SDL_GPURenderer *driverData, SDL_Window *window); 1288static bool VULKAN_Wait(SDL_GPURenderer *driverData); 1289static bool VULKAN_WaitForFences(SDL_GPURenderer *driverData, bool waitAll, SDL_GPUFence *const *fences, Uint32 numFences); 1290static bool VULKAN_Submit(SDL_GPUCommandBuffer *commandBuffer); 1291static SDL_GPUCommandBuffer *VULKAN_AcquireCommandBuffer(SDL_GPURenderer *driverData); 1292 1293// Error Handling 1294 1295static inline const char *VkErrorMessages(VkResult code) 1296{ 1297#define ERR_TO_STR(e) \ 1298 case e: \ 1299 return #e; 1300 switch (code) { 1301 ERR_TO_STR(VK_ERROR_OUT_OF_HOST_MEMORY) 1302 ERR_TO_STR(VK_ERROR_OUT_OF_DEVICE_MEMORY) 1303 ERR_TO_STR(VK_ERROR_FRAGMENTED_POOL) 1304 ERR_TO_STR(VK_ERROR_OUT_OF_POOL_MEMORY) 1305 ERR_TO_STR(VK_ERROR_INITIALIZATION_FAILED) 1306 ERR_TO_STR(VK_ERROR_LAYER_NOT_PRESENT) 1307 ERR_TO_STR(VK_ERROR_EXTENSION_NOT_PRESENT) 1308 ERR_TO_STR(VK_ERROR_FEATURE_NOT_PRESENT) 1309 ERR_TO_STR(VK_ERROR_TOO_MANY_OBJECTS) 1310 ERR_TO_STR(VK_ERROR_DEVICE_LOST) 1311 ERR_TO_STR(VK_ERROR_INCOMPATIBLE_DRIVER) 1312 ERR_TO_STR(VK_ERROR_OUT_OF_DATE_KHR) 1313 ERR_TO_STR(VK_ERROR_SURFACE_LOST_KHR) 1314 ERR_TO_STR(VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT) 1315 ERR_TO_STR(VK_SUBOPTIMAL_KHR) 1316 ERR_TO_STR(VK_ERROR_NATIVE_WINDOW_IN_USE_KHR) 1317 ERR_TO_STR(VK_ERROR_INVALID_SHADER_NV) 1318 default: 1319 return "Unhandled VkResult!"; 1320 } 1321#undef ERR_TO_STR 1322} 1323 1324#define SET_ERROR(fmt, msg) \ 1325 do { \ 1326 if (renderer->debugMode) { \ 1327 SDL_LogError(SDL_LOG_CATEGORY_GPU, fmt, msg); \ 1328 } \ 1329 SDL_SetError((fmt), (msg)); \ 1330 } while (0) 1331 1332#define SET_STRING_ERROR(msg) SET_ERROR("%s", msg) 1333 1334#define SET_ERROR_AND_RETURN(fmt, msg, ret) \ 1335 do { \ 1336 SET_ERROR(fmt, msg); \ 1337 return ret; \ 1338 } while (0) 1339 1340#define SET_STRING_ERROR_AND_RETURN(msg, ret) SET_ERROR_AND_RETURN("%s", msg, ret) 1341 1342#define CHECK_VULKAN_ERROR_AND_RETURN(res, fn, ret) \ 1343 do { \ 1344 if ((res) != VK_SUCCESS) { \ 1345 if (renderer->debugMode) { \ 1346 SDL_LogError(SDL_LOG_CATEGORY_GPU, "%s %s", #fn, VkErrorMessages(res)); \ 1347 } \ 1348 SDL_SetError("%s %s", #fn, VkErrorMessages(res)); \ 1349 return (ret); \ 1350 } \ 1351 } while (0) 1352 1353// Utility 1354 1355static inline VkPolygonMode SDLToVK_PolygonMode( 1356 VulkanRenderer *renderer, 1357 SDL_GPUFillMode mode) 1358{ 1359 if (mode == SDL_GPU_FILLMODE_FILL) { 1360 return VK_POLYGON_MODE_FILL; // always available! 1361 } 1362 1363 if (renderer->supportsFillModeNonSolid && mode == SDL_GPU_FILLMODE_LINE) { 1364 return VK_POLYGON_MODE_LINE; 1365 } 1366 1367 if (!renderer->fillModeOnlyWarning) { 1368 SDL_LogWarn(SDL_LOG_CATEGORY_GPU, "Unsupported fill mode requested, using FILL!"); 1369 renderer->fillModeOnlyWarning = 1; 1370 } 1371 return VK_POLYGON_MODE_FILL; 1372} 1373 1374// Memory Management 1375 1376// Vulkan: Memory Allocation 1377 1378static inline VkDeviceSize VULKAN_INTERNAL_NextHighestAlignment( 1379 VkDeviceSize n, 1380 VkDeviceSize align) 1381{ 1382 return align * ((n + align - 1) / align); 1383} 1384 1385static inline Uint32 VULKAN_INTERNAL_NextHighestAlignment32( 1386 Uint32 n, 1387 Uint32 align) 1388{ 1389 return align * ((n + align - 1) / align); 1390} 1391 1392static void VULKAN_INTERNAL_MakeMemoryUnavailable( 1393 VulkanMemoryAllocation *allocation) 1394{ 1395 Uint32 i, j; 1396 VulkanMemoryFreeRegion *freeRegion; 1397 1398 allocation->availableForAllocation = 0; 1399 1400 for (i = 0; i < allocation->freeRegionCount; i += 1) { 1401 freeRegion = allocation->freeRegions[i]; 1402 1403 // close the gap in the sorted list 1404 if (allocation->allocator->sortedFreeRegionCount > 1) { 1405 for (j = freeRegion->sortedIndex; j < allocation->allocator->sortedFreeRegionCount - 1; j += 1) { 1406 allocation->allocator->sortedFreeRegions[j] = 1407 allocation->allocator->sortedFreeRegions[j + 1]; 1408 1409 allocation->allocator->sortedFreeRegions[j]->sortedIndex = j; 1410 } 1411 } 1412 1413 allocation->allocator->sortedFreeRegionCount -= 1; 1414 } 1415} 1416 1417static void VULKAN_INTERNAL_MarkAllocationsForDefrag( 1418 VulkanRenderer *renderer) 1419{ 1420 Uint32 memoryType, allocationIndex; 1421 VulkanMemorySubAllocator *currentAllocator; 1422 1423 for (memoryType = 0; memoryType < VK_MAX_MEMORY_TYPES; memoryType += 1) { 1424 currentAllocator = &renderer->memoryAllocator->subAllocators[memoryType]; 1425 1426 for (allocationIndex = 0; allocationIndex < currentAllocator->allocationCount; allocationIndex += 1) { 1427 if (currentAllocator->allocations[allocationIndex]->availableForAllocation == 1) { 1428 if (currentAllocator->allocations[allocationIndex]->freeRegionCount > 1) { 1429 EXPAND_ARRAY_IF_NEEDED( 1430 renderer->allocationsToDefrag, 1431 VulkanMemoryAllocation *, 1432 renderer->allocationsToDefragCount + 1, 1433 renderer->allocationsToDefragCapacity, 1434 renderer->allocationsToDefragCapacity * 2); 1435 1436 renderer->allocationsToDefrag[renderer->allocationsToDefragCount] = 1437 currentAllocator->allocations[allocationIndex]; 1438 1439 renderer->allocationsToDefragCount += 1; 1440 1441 VULKAN_INTERNAL_MakeMemoryUnavailable( 1442 currentAllocator->allocations[allocationIndex]); 1443 } 1444 } 1445 } 1446 } 1447} 1448 1449static void VULKAN_INTERNAL_RemoveMemoryFreeRegion( 1450 VulkanRenderer *renderer, 1451 VulkanMemoryFreeRegion *freeRegion) 1452{ 1453 Uint32 i; 1454 1455 SDL_LockMutex(renderer->allocatorLock); 1456 1457 if (freeRegion->allocation->availableForAllocation) { 1458 // close the gap in the sorted list 1459 if (freeRegion->allocation->allocator->sortedFreeRegionCount > 1) { 1460 for (i = freeRegion->sortedIndex; i < freeRegion->allocation->allocator->sortedFreeRegionCount - 1; i += 1) { 1461 freeRegion->allocation->allocator->sortedFreeRegions[i] = 1462 freeRegion->allocation->allocator->sortedFreeRegions[i + 1]; 1463 1464 freeRegion->allocation->allocator->sortedFreeRegions[i]->sortedIndex = i; 1465 } 1466 } 1467 1468 freeRegion->allocation->allocator->sortedFreeRegionCount -= 1; 1469 } 1470 1471 // close the gap in the buffer list 1472 if (freeRegion->allocation->freeRegionCount > 1 && freeRegion->allocationIndex != freeRegion->allocation->freeRegionCount - 1) { 1473 freeRegion->allocation->freeRegions[freeRegion->allocationIndex] = 1474 freeRegion->allocation->freeRegions[freeRegion->allocation->freeRegionCount - 1]; 1475 1476 freeRegion->allocation->freeRegions[freeRegion->allocationIndex]->allocationIndex = 1477 freeRegion->allocationIndex; 1478 } 1479 1480 freeRegion->allocation->freeRegionCount -= 1; 1481 1482 freeRegion->allocation->freeSpace -= freeRegion->size; 1483 1484 SDL_free(freeRegion); 1485 1486 SDL_UnlockMutex(renderer->allocatorLock); 1487} 1488 1489static void VULKAN_INTERNAL_NewMemoryFreeRegion( 1490 VulkanRenderer *renderer, 1491 VulkanMemoryAllocation *allocation, 1492 VkDeviceSize offset, 1493 VkDeviceSize size) 1494{ 1495 VulkanMemoryFreeRegion *newFreeRegion; 1496 VkDeviceSize newOffset, newSize; 1497 Sint32 insertionIndex = 0; 1498 1499 SDL_LockMutex(renderer->allocatorLock); 1500 1501 // look for an adjacent region to merge 1502 for (Sint32 i = allocation->freeRegionCount - 1; i >= 0; i -= 1) { 1503 // check left side 1504 if (allocation->freeRegions[i]->offset + allocation->freeRegions[i]->size == offset) { 1505 newOffset = allocation->freeRegions[i]->offset; 1506 newSize = allocation->freeRegions[i]->size + size; 1507 1508 VULKAN_INTERNAL_RemoveMemoryFreeRegion(renderer, allocation->freeRegions[i]); 1509 VULKAN_INTERNAL_NewMemoryFreeRegion(renderer, allocation, newOffset, newSize); 1510 1511 SDL_UnlockMutex(renderer->allocatorLock); 1512 return; 1513 } 1514 1515 // check right side 1516 if (allocation->freeRegions[i]->offset == offset + size) { 1517 newOffset = offset; 1518 newSize = allocation->freeRegions[i]->size + size; 1519 1520 VULKAN_INTERNAL_RemoveMemoryFreeRegion(renderer, allocation->freeRegions[i]); 1521 VULKAN_INTERNAL_NewMemoryFreeRegion(renderer, allocation, newOffset, newSize); 1522 1523 SDL_UnlockMutex(renderer->allocatorLock); 1524 return; 1525 } 1526 } 1527 1528 // region is not contiguous with another free region, make a new one 1529 allocation->freeRegionCount += 1; 1530 if (allocation->freeRegionCount > allocation->freeRegionCapacity) { 1531 allocation->freeRegionCapacity *= 2; 1532 allocation->freeRegions = SDL_realloc( 1533 allocation->freeRegions, 1534 sizeof(VulkanMemoryFreeRegion *) * allocation->freeRegionCapacity); 1535 } 1536 1537 newFreeRegion = SDL_malloc(sizeof(VulkanMemoryFreeRegion)); 1538 newFreeRegion->offset = offset; 1539 newFreeRegion->size = size; 1540 newFreeRegion->allocation = allocation; 1541 1542 allocation->freeSpace += size; 1543 1544 allocation->freeRegions[allocation->freeRegionCount - 1] = newFreeRegion; 1545 newFreeRegion->allocationIndex = allocation->freeRegionCount - 1; 1546 1547 if (allocation->availableForAllocation) { 1548 for (Uint32 i = 0; i < allocation->allocator->sortedFreeRegionCount; i += 1) { 1549 if (allocation->allocator->sortedFreeRegions[i]->size < size) { 1550 // this is where the new region should go 1551 break; 1552 } 1553 1554 insertionIndex += 1; 1555 } 1556 1557 if (allocation->allocator->sortedFreeRegionCount + 1 > allocation->allocator->sortedFreeRegionCapacity) { 1558 allocation->allocator->sortedFreeRegionCapacity *= 2; 1559 allocation->allocator->sortedFreeRegions = SDL_realloc( 1560 allocation->allocator->sortedFreeRegions, 1561 sizeof(VulkanMemoryFreeRegion *) * allocation->allocator->sortedFreeRegionCapacity); 1562 } 1563 1564 // perform insertion sort 1565 if (allocation->allocator->sortedFreeRegionCount > 0 && (Uint32)insertionIndex != allocation->allocator->sortedFreeRegionCount) { 1566 for (Sint32 i = allocation->allocator->sortedFreeRegionCount; i > insertionIndex && i > 0; i -= 1) { 1567 allocation->allocator->sortedFreeRegions[i] = allocation->allocator->sortedFreeRegions[i - 1]; 1568 allocation->allocator->sortedFreeRegions[i]->sortedIndex = i; 1569 } 1570 } 1571 1572 allocation->allocator->sortedFreeRegionCount += 1; 1573 allocation->allocator->sortedFreeRegions[insertionIndex] = newFreeRegion; 1574 newFreeRegion->sortedIndex = insertionIndex; 1575 } 1576 1577 SDL_UnlockMutex(renderer->allocatorLock); 1578} 1579 1580static VulkanMemoryUsedRegion *VULKAN_INTERNAL_NewMemoryUsedRegion( 1581 VulkanRenderer *renderer, 1582 VulkanMemoryAllocation *allocation, 1583 VkDeviceSize offset, 1584 VkDeviceSize size, 1585 VkDeviceSize resourceOffset, 1586 VkDeviceSize resourceSize, 1587 VkDeviceSize alignment) 1588{ 1589 VulkanMemoryUsedRegion *memoryUsedRegion; 1590 1591 SDL_LockMutex(renderer->allocatorLock); 1592 1593 if (allocation->usedRegionCount == allocation->usedRegionCapacity) { 1594 allocation->usedRegionCapacity *= 2; 1595 allocation->usedRegions = SDL_realloc( 1596 allocation->usedRegions, 1597 allocation->usedRegionCapacity * sizeof(VulkanMemoryUsedRegion *)); 1598 } 1599 1600 memoryUsedRegion = SDL_malloc(sizeof(VulkanMemoryUsedRegion)); 1601 memoryUsedRegion->allocation = allocation; 1602 memoryUsedRegion->offset = offset; 1603 memoryUsedRegion->size = size; 1604 memoryUsedRegion->resourceOffset = resourceOffset; 1605 memoryUsedRegion->resourceSize = resourceSize; 1606 memoryUsedRegion->alignment = alignment; 1607 1608 allocation->usedSpace += size; 1609 1610 allocation->usedRegions[allocation->usedRegionCount] = memoryUsedRegion; 1611 allocation->usedRegionCount += 1; 1612 1613 SDL_UnlockMutex(renderer->allocatorLock); 1614 1615 return memoryUsedRegion; 1616} 1617 1618static void VULKAN_INTERNAL_RemoveMemoryUsedRegion( 1619 VulkanRenderer *renderer, 1620 VulkanMemoryUsedRegion *usedRegion) 1621{ 1622 Uint32 i; 1623 1624 SDL_LockMutex(renderer->allocatorLock); 1625 1626 for (i = 0; i < usedRegion->allocation->usedRegionCount; i += 1) { 1627 if (usedRegion->allocation->usedRegions[i] == usedRegion) { 1628 // plug the hole 1629 if (i != usedRegion->allocation->usedRegionCount - 1) { 1630 usedRegion->allocation->usedRegions[i] = usedRegion->allocation->usedRegions[usedRegion->allocation->usedRegionCount - 1]; 1631 } 1632 1633 break; 1634 } 1635 } 1636 1637 usedRegion->allocation->usedSpace -= usedRegion->size; 1638 1639 usedRegion->allocation->usedRegionCount -= 1; 1640 1641 VULKAN_INTERNAL_NewMemoryFreeRegion( 1642 renderer, 1643 usedRegion->allocation, 1644 usedRegion->offset, 1645 usedRegion->size); 1646 1647 if (usedRegion->allocation->usedRegionCount == 0) { 1648 renderer->checkEmptyAllocations = true; 1649 } 1650 1651 SDL_free(usedRegion); 1652 1653 SDL_UnlockMutex(renderer->allocatorLock); 1654} 1655 1656static bool VULKAN_INTERNAL_CheckMemoryTypeArrayUnique( 1657 Uint32 memoryTypeIndex, 1658 const Uint32 *memoryTypeIndexArray, 1659 Uint32 count) 1660{ 1661 Uint32 i = 0; 1662 1663 for (i = 0; i < count; i += 1) { 1664 if (memoryTypeIndexArray[i] == memoryTypeIndex) { 1665 return false; 1666 } 1667 } 1668 1669 return true; 1670} 1671 1672/* Returns an array of memory type indices in order of preference. 1673 * Memory types are requested with the following three guidelines: 1674 * 1675 * Required: Absolutely necessary 1676 * Preferred: Nice to have, but not necessary 1677 * Tolerable: Can be allowed if there are no other options 1678 * 1679 * We return memory types in this order: 1680 * 1. Required and preferred. This is the best category. 1681 * 2. Required only. 1682 * 3. Required, preferred, and tolerable. 1683 * 4. Required and tolerable. This is the worst category. 1684 */ 1685static Uint32 *VULKAN_INTERNAL_FindBestMemoryTypes( 1686 VulkanRenderer *renderer, 1687 Uint32 typeFilter, 1688 VkMemoryPropertyFlags requiredProperties, 1689 VkMemoryPropertyFlags preferredProperties, 1690 VkMemoryPropertyFlags tolerableProperties, 1691 Uint32 *pCount) 1692{ 1693 Uint32 i; 1694 Uint32 index = 0; 1695 Uint32 *result = SDL_malloc(sizeof(Uint32) * renderer->memoryProperties.memoryTypeCount); 1696 1697 // required + preferred + !tolerable 1698 for (i = 0; i < renderer->memoryProperties.memoryTypeCount; i += 1) { 1699 if ((typeFilter & (1 << i)) && 1700 (renderer->memoryProperties.memoryTypes[i].propertyFlags & requiredProperties) == requiredProperties && 1701 (renderer->memoryProperties.memoryTypes[i].propertyFlags & preferredProperties) == preferredProperties && 1702 (renderer->memoryProperties.memoryTypes[i].propertyFlags & tolerableProperties) == 0) { 1703 if (VULKAN_INTERNAL_CheckMemoryTypeArrayUnique( 1704 i, 1705 result, 1706 index)) { 1707 result[index] = i; 1708 index += 1; 1709 } 1710 } 1711 } 1712 1713 // required + !preferred + !tolerable 1714 for (i = 0; i < renderer->memoryProperties.memoryTypeCount; i += 1) { 1715 if ((typeFilter & (1 << i)) && 1716 (renderer->memoryProperties.memoryTypes[i].propertyFlags & requiredProperties) == requiredProperties && 1717 (renderer->memoryProperties.memoryTypes[i].propertyFlags & preferredProperties) == 0 && 1718 (renderer->memoryProperties.memoryTypes[i].propertyFlags & tolerableProperties) == 0) { 1719 if (VULKAN_INTERNAL_CheckMemoryTypeArrayUnique( 1720 i, 1721 result, 1722 index)) { 1723 result[index] = i; 1724 index += 1; 1725 } 1726 } 1727 } 1728 1729 // required + preferred + tolerable 1730 for (i = 0; i < renderer->memoryProperties.memoryTypeCount; i += 1) { 1731 if ((typeFilter & (1 << i)) && 1732 (renderer->memoryProperties.memoryTypes[i].propertyFlags & requiredProperties) == requiredProperties && 1733 (renderer->memoryProperties.memoryTypes[i].propertyFlags & preferredProperties) == preferredProperties && 1734 (renderer->memoryProperties.memoryTypes[i].propertyFlags & tolerableProperties) == tolerableProperties) { 1735 if (VULKAN_INTERNAL_CheckMemoryTypeArrayUnique( 1736 i, 1737 result, 1738 index)) { 1739 result[index] = i; 1740 index += 1; 1741 } 1742 } 1743 } 1744 1745 // required + !preferred + tolerable 1746 for (i = 0; i < renderer->memoryProperties.memoryTypeCount; i += 1) { 1747 if ((typeFilter & (1 << i)) && 1748 (renderer->memoryProperties.memoryTypes[i].propertyFlags & requiredProperties) == requiredProperties && 1749 (renderer->memoryProperties.memoryTypes[i].propertyFlags & preferredProperties) == 0 && 1750 (renderer->memoryProperties.memoryTypes[i].propertyFlags & tolerableProperties) == tolerableProperties) { 1751 if (VULKAN_INTERNAL_CheckMemoryTypeArrayUnique( 1752 i, 1753 result, 1754 index)) { 1755 result[index] = i; 1756 index += 1; 1757 } 1758 } 1759 } 1760 1761 *pCount = index; 1762 return result; 1763} 1764 1765static Uint32 *VULKAN_INTERNAL_FindBestBufferMemoryTypes( 1766 VulkanRenderer *renderer, 1767 VkBuffer buffer, 1768 VkMemoryPropertyFlags requiredMemoryProperties, 1769 VkMemoryPropertyFlags preferredMemoryProperties, 1770 VkMemoryPropertyFlags tolerableMemoryProperties, 1771 VkMemoryRequirements *pMemoryRequirements, 1772 Uint32 *pCount) 1773{ 1774 renderer->vkGetBufferMemoryRequirements( 1775 renderer->logicalDevice, 1776 buffer, 1777 pMemoryRequirements); 1778 1779 return VULKAN_INTERNAL_FindBestMemoryTypes( 1780 renderer, 1781 pMemoryRequirements->memoryTypeBits, 1782 requiredMemoryProperties, 1783 preferredMemoryProperties, 1784 tolerableMemoryProperties, 1785 pCount); 1786} 1787 1788static Uint32 *VULKAN_INTERNAL_FindBestImageMemoryTypes( 1789 VulkanRenderer *renderer, 1790 VkImage image, 1791 VkMemoryPropertyFlags preferredMemoryPropertyFlags, 1792 VkMemoryRequirements *pMemoryRequirements, 1793 Uint32 *pCount) 1794{ 1795 renderer->vkGetImageMemoryRequirements( 1796 renderer->logicalDevice, 1797 image, 1798 pMemoryRequirements); 1799 1800 return VULKAN_INTERNAL_FindBestMemoryTypes( 1801 renderer, 1802 pMemoryRequirements->memoryTypeBits, 1803 0, 1804 preferredMemoryPropertyFlags, 1805 0, 1806 pCount); 1807} 1808 1809static void VULKAN_INTERNAL_DeallocateMemory( 1810 VulkanRenderer *renderer, 1811 VulkanMemorySubAllocator *allocator, 1812 Uint32 allocationIndex) 1813{ 1814 Uint32 i; 1815 1816 VulkanMemoryAllocation *allocation = allocator->allocations[allocationIndex]; 1817 1818 SDL_LockMutex(renderer->allocatorLock); 1819 1820 // If this allocation was marked for defrag, cancel that 1821 for (i = 0; i < renderer->allocationsToDefragCount; i += 1) { 1822 if (allocation == renderer->allocationsToDefrag[i]) { 1823 renderer->allocationsToDefrag[i] = renderer->allocationsToDefrag[renderer->allocationsToDefragCount - 1]; 1824 renderer->allocationsToDefragCount -= 1; 1825 1826 break; 1827 } 1828 } 1829 1830 for (i = 0; i < allocation->freeRegionCount; i += 1) { 1831 VULKAN_INTERNAL_RemoveMemoryFreeRegion( 1832 renderer, 1833 allocation->freeRegions[i]); 1834 } 1835 SDL_free(allocation->freeRegions); 1836 1837 /* no need to iterate used regions because deallocate 1838 * only happens when there are 0 used regions 1839 */ 1840 SDL_free(allocation->usedRegions); 1841 1842 renderer->vkFreeMemory( 1843 renderer->logicalDevice, 1844 allocation->memory, 1845 NULL); 1846 1847 SDL_DestroyMutex(allocation->memoryLock); 1848 SDL_free(allocation); 1849 1850 if (allocationIndex != allocator->allocationCount - 1) { 1851 allocator->allocations[allocationIndex] = allocator->allocations[allocator->allocationCount - 1]; 1852 } 1853 1854 allocator->allocationCount -= 1; 1855 1856 SDL_UnlockMutex(renderer->allocatorLock); 1857} 1858 1859static Uint8 VULKAN_INTERNAL_AllocateMemory( 1860 VulkanRenderer *renderer, 1861 Uint32 memoryTypeIndex, 1862 VkDeviceSize allocationSize, 1863 Uint8 isHostVisible, 1864 VulkanMemoryAllocation **pMemoryAllocation) 1865{ 1866 VulkanMemoryAllocation *allocation; 1867 VulkanMemorySubAllocator *allocator = &renderer->memoryAllocator->subAllocators[memoryTypeIndex]; 1868 VkMemoryAllocateInfo allocInfo; 1869 VkResult result; 1870 1871 allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; 1872 allocInfo.pNext = NULL; 1873 allocInfo.memoryTypeIndex = memoryTypeIndex; 1874 allocInfo.allocationSize = allocationSize; 1875 1876 allocation = SDL_malloc(sizeof(VulkanMemoryAllocation)); 1877 allocation->size = allocationSize; 1878 allocation->freeSpace = 0; // added by FreeRegions 1879 allocation->usedSpace = 0; // added by UsedRegions 1880 allocation->memoryLock = SDL_CreateMutex(); 1881 1882 allocator->allocationCount += 1; 1883 allocator->allocations = SDL_realloc( 1884 allocator->allocations, 1885 sizeof(VulkanMemoryAllocation *) * allocator->allocationCount); 1886 1887 allocator->allocations[allocator->allocationCount - 1] = allocation; 1888 1889 allocInfo.pNext = NULL; 1890 allocation->availableForAllocation = 1; 1891 1892 allocation->usedRegions = SDL_malloc(sizeof(VulkanMemoryUsedRegion *)); 1893 allocation->usedRegionCount = 0; 1894 allocation->usedRegionCapacity = 1; 1895 1896 allocation->freeRegions = SDL_malloc(sizeof(VulkanMemoryFreeRegion *)); 1897 allocation->freeRegionCount = 0; 1898 allocation->freeRegionCapacity = 1; 1899 1900 SDL_SetAtomicInt(&allocation->referenceCount, 0); 1901 1902 allocation->allocator = allocator; 1903 1904 result = renderer->vkAllocateMemory( 1905 renderer->logicalDevice, 1906 &allocInfo, 1907 NULL, 1908 &allocation->memory); 1909 1910 if (result != VK_SUCCESS) { 1911 // Uh oh, we couldn't allocate, time to clean up 1912 SDL_free(allocation->freeRegions); 1913 1914 allocator->allocationCount -= 1; 1915 allocator->allocations = SDL_realloc( 1916 allocator->allocations, 1917 sizeof(VulkanMemoryAllocation *) * allocator->allocationCount); 1918 1919 SDL_free(allocation); 1920 1921 return 0; 1922 } 1923 1924 // Persistent mapping for host-visible memory 1925 if (isHostVisible) { 1926 result = renderer->vkMapMemory( 1927 renderer->logicalDevice, 1928 allocation->memory, 1929 0, 1930 VK_WHOLE_SIZE, 1931 0, 1932 (void **)&allocation->mapPointer); 1933 CHECK_VULKAN_ERROR_AND_RETURN(result, vkMapMemory, 0); 1934 } else { 1935 allocation->mapPointer = NULL; 1936 } 1937 1938 VULKAN_INTERNAL_NewMemoryFreeRegion( 1939 renderer, 1940 allocation, 1941 0, 1942 allocation->size); 1943 1944 *pMemoryAllocation = allocation; 1945 return 1; 1946} 1947 1948static Uint8 VULKAN_INTERNAL_BindBufferMemory( 1949 VulkanRenderer *renderer, 1950 VulkanMemoryUsedRegion *usedRegion, 1951 VkDeviceSize alignedOffset, 1952 VkBuffer buffer) 1953{ 1954 VkResult vulkanResult; 1955 1956 SDL_LockMutex(usedRegion->allocation->memoryLock); 1957 1958 vulkanResult = renderer->vkBindBufferMemory( 1959 renderer->logicalDevice, 1960 buffer, 1961 usedRegion->allocation->memory, 1962 alignedOffset); 1963 1964 SDL_UnlockMutex(usedRegion->allocation->memoryLock); 1965 1966 CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkBindBufferMemory, 0); 1967 1968 return 1; 1969} 1970 1971static Uint8 VULKAN_INTERNAL_BindImageMemory( 1972 VulkanRenderer *renderer, 1973 VulkanMemoryUsedRegion *usedRegion, 1974 VkDeviceSize alignedOffset, 1975 VkImage image) 1976{ 1977 VkResult vulkanResult; 1978 1979 SDL_LockMutex(usedRegion->allocation->memoryLock); 1980 1981 vulkanResult = renderer->vkBindImageMemory( 1982 renderer->logicalDevice, 1983 image, 1984 usedRegion->allocation->memory, 1985 alignedOffset); 1986 1987 SDL_UnlockMutex(usedRegion->allocation->memoryLock); 1988 1989 CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkBindImageMemory, 0); 1990 1991 return 1; 1992} 1993 1994static Uint8 VULKAN_INTERNAL_BindResourceMemory( 1995 VulkanRenderer *renderer, 1996 Uint32 memoryTypeIndex, 1997 VkMemoryRequirements *memoryRequirements, 1998 VkDeviceSize resourceSize, // may be different from requirements size! 1999 bool dedicated, // the entire memory allocation should be used for this resource 2000 VkBuffer buffer, // may be VK_NULL_HANDLE 2001 VkImage image, // may be VK_NULL_HANDLE 2002 VulkanMemoryUsedRegion **pMemoryUsedRegion) 2003{ 2004 VulkanMemoryAllocation *allocation; 2005 VulkanMemorySubAllocator *allocator; 2006 VulkanMemoryFreeRegion *region; 2007 VulkanMemoryFreeRegion *selectedRegion; 2008 VulkanMemoryUsedRegion *usedRegion; 2009 2010 VkDeviceSize requiredSize, allocationSize; 2011 VkDeviceSize alignedOffset = 0; 2012 VkDeviceSize newRegionSize, newRegionOffset; 2013 Uint8 isHostVisible, smallAllocation, allocationResult; 2014 Sint32 i; 2015 2016 isHostVisible = 2017 (renderer->memoryProperties.memoryTypes[memoryTypeIndex].propertyFlags & 2018 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) != 0; 2019 2020 allocator = &renderer->memoryAllocator->subAllocators[memoryTypeIndex]; 2021 requiredSize = memoryRequirements->size; 2022 smallAllocation = requiredSize <= SMALL_ALLOCATION_THRESHOLD; 2023 2024 if ((buffer == VK_NULL_HANDLE && image == VK_NULL_HANDLE) || 2025 (buffer != VK_NULL_HANDLE && image != VK_NULL_HANDLE)) { 2026 SDL_LogError(SDL_LOG_CATEGORY_GPU, "BindResourceMemory must be given either a VulkanBuffer or a VulkanTexture"); 2027 return 0; 2028 } 2029 2030 SDL_LockMutex(renderer->allocatorLock); 2031 2032 selectedRegion = NULL; 2033 2034 if (dedicated) { 2035 // Force an allocation 2036 allocationSize = requiredSize; 2037 } else { 2038 // Search for a suitable existing free region 2039 for (i = allocator->sortedFreeRegionCount - 1; i >= 0; i -= 1) { 2040 region = allocator->sortedFreeRegions[i]; 2041 2042 if (smallAllocation && region->allocation->size != SMALL_ALLOCATION_SIZE) { 2043 // region is not in a small allocation 2044 continue; 2045 } 2046 2047 if (!smallAllocation && region->allocation->size == SMALL_ALLOCATION_SIZE) { 2048 // allocation is not small and current region is in a small allocation 2049 continue; 2050 } 2051 2052 alignedOffset = VULKAN_INTERNAL_NextHighestAlignment( 2053 region->offset, 2054 memoryRequirements->alignment); 2055 2056 if (alignedOffset + requiredSize <= region->offset + region->size) { 2057 selectedRegion = region; 2058 break; 2059 } 2060 } 2061 2062 if (selectedRegion != NULL) { 2063 region = selectedRegion; 2064 allocation = region->allocation; 2065 2066 usedRegion = VULKAN_INTERNAL_NewMemoryUsedRegion( 2067 renderer, 2068 allocation, 2069 region->offset, 2070 requiredSize + (alignedOffset - region->offset), 2071 alignedOffset, 2072 resourceSize, 2073 memoryRequirements->alignment); 2074 2075 usedRegion->isBuffer = buffer != VK_NULL_HANDLE; 2076 2077 newRegionSize = region->size - ((alignedOffset - region->offset) + requiredSize); 2078 newRegionOffset = alignedOffset + requiredSize; 2079 2080 // remove and add modified region to re-sort 2081 VULKAN_INTERNAL_RemoveMemoryFreeRegion(renderer, region); 2082 2083 // if size is 0, no need to re-insert 2084 if (newRegionSize != 0) { 2085 VULKAN_INTERNAL_NewMemoryFreeRegion( 2086 renderer, 2087 allocation, 2088 newRegionOffset, 2089 newRegionSize); 2090 } 2091 2092 SDL_UnlockMutex(renderer->allocatorLock); 2093 2094 if (buffer != VK_NULL_HANDLE) { 2095 if (!VULKAN_INTERNAL_BindBufferMemory( 2096 renderer, 2097 usedRegion, 2098 alignedOffset, 2099 buffer)) { 2100 VULKAN_INTERNAL_RemoveMemoryUsedRegion( 2101 renderer, 2102 usedRegion); 2103 2104 return 0; 2105 } 2106 } else if (image != VK_NULL_HANDLE) { 2107 if (!VULKAN_INTERNAL_BindImageMemory( 2108 renderer, 2109 usedRegion, 2110 alignedOffset, 2111 image)) { 2112 VULKAN_INTERNAL_RemoveMemoryUsedRegion( 2113 renderer, 2114 usedRegion); 2115 2116 return 0; 2117 } 2118 } 2119 2120 *pMemoryUsedRegion = usedRegion; 2121 return 1; 2122 } 2123 2124 // No suitable free regions exist, allocate a new memory region 2125 if ( 2126 renderer->allocationsToDefragCount == 0 && 2127 !renderer->defragInProgress) { 2128 // Mark currently fragmented allocations for defrag 2129 VULKAN_INTERNAL_MarkAllocationsForDefrag(renderer); 2130 } 2131 2132 if (requiredSize > SMALL_ALLOCATION_THRESHOLD) { 2133 // allocate a page of required size aligned to LARGE_ALLOCATION_INCREMENT increments 2134 allocationSize = 2135 VULKAN_INTERNAL_NextHighestAlignment(requiredSize, LARGE_ALLOCATION_INCREMENT); 2136 } else { 2137 allocationSize = SMALL_ALLOCATION_SIZE; 2138 } 2139 } 2140 2141 allocationResult = VULKAN_INTERNAL_AllocateMemory( 2142 renderer, 2143 memoryTypeIndex, 2144 allocationSize, 2145 isHostVisible, 2146 &allocation); 2147 2148 // Uh oh, we're out of memory 2149 if (allocationResult == 0) { 2150 SDL_UnlockMutex(renderer->allocatorLock); 2151 2152 // Responsibility of the caller to handle being out of memory 2153 return 2; 2154 } 2155 2156 usedRegion = VULKAN_INTERNAL_NewMemoryUsedRegion( 2157 renderer, 2158 allocation, 2159 0, 2160 requiredSize, 2161 0, 2162 resourceSize, 2163 memoryRequirements->alignment); 2164 2165 usedRegion->isBuffer = buffer != VK_NULL_HANDLE; 2166 2167 region = allocation->freeRegions[0]; 2168 2169 newRegionOffset = region->offset + requiredSize; 2170 newRegionSize = region->size - requiredSize; 2171 2172 VULKAN_INTERNAL_RemoveMemoryFreeRegion(renderer, region); 2173 2174 if (newRegionSize != 0) { 2175 VULKAN_INTERNAL_NewMemoryFreeRegion( 2176 renderer, 2177 allocation, 2178 newRegionOffset, 2179 newRegionSize); 2180 } 2181 2182 SDL_UnlockMutex(renderer->allocatorLock); 2183 2184 if (buffer != VK_NULL_HANDLE) { 2185 if (!VULKAN_INTERNAL_BindBufferMemory( 2186 renderer, 2187 usedRegion, 2188 0, 2189 buffer)) { 2190 VULKAN_INTERNAL_RemoveMemoryUsedRegion( 2191 renderer, 2192 usedRegion); 2193 2194 return 0; 2195 } 2196 } else if (image != VK_NULL_HANDLE) { 2197 if (!VULKAN_INTERNAL_BindImageMemory( 2198 renderer, 2199 usedRegion, 2200 0, 2201 image)) { 2202 VULKAN_INTERNAL_RemoveMemoryUsedRegion( 2203 renderer, 2204 usedRegion); 2205 2206 return 0; 2207 } 2208 } 2209 2210 *pMemoryUsedRegion = usedRegion; 2211 return 1; 2212} 2213 2214static Uint8 VULKAN_INTERNAL_BindMemoryForImage( 2215 VulkanRenderer *renderer, 2216 VkImage image, 2217 VulkanMemoryUsedRegion **usedRegion) 2218{ 2219 Uint8 bindResult = 0; 2220 Uint32 memoryTypeCount = 0; 2221 Uint32 *memoryTypesToTry = NULL; 2222 Uint32 selectedMemoryTypeIndex = 0; 2223 Uint32 i; 2224 VkMemoryPropertyFlags preferredMemoryPropertyFlags; 2225 VkMemoryRequirements memoryRequirements; 2226 2227 /* Vulkan memory types have several memory properties. 2228 * 2229 * Unlike buffers, images are always optimally stored device-local, 2230 * so that is the only property we prefer here. 2231 * 2232 * If memory is constrained, it is fine for the texture to not 2233 * be device-local. 2234 */ 2235 preferredMemoryPropertyFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; 2236 2237 memoryTypesToTry = VULKAN_INTERNAL_FindBestImageMemoryTypes( 2238 renderer, 2239 image, 2240 preferredMemoryPropertyFlags, 2241 &memoryRequirements, 2242 &memoryTypeCount); 2243 2244 for (i = 0; i < memoryTypeCount; i += 1) { 2245 bindResult = VULKAN_INTERNAL_BindResourceMemory( 2246 renderer, 2247 memoryTypesToTry[i], 2248 &memoryRequirements, 2249 memoryRequirements.size, 2250 false, 2251 VK_NULL_HANDLE, 2252 image, 2253 usedRegion); 2254 2255 if (bindResult == 1) { 2256 selectedMemoryTypeIndex = memoryTypesToTry[i]; 2257 break; 2258 } 2259 } 2260 2261 SDL_free(memoryTypesToTry); 2262 2263 // Check for warnings on success 2264 if (bindResult == 1) { 2265 if (!renderer->outOfDeviceLocalMemoryWarning) { 2266 if ((renderer->memoryProperties.memoryTypes[selectedMemoryTypeIndex].propertyFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) == 0) { 2267 SDL_LogWarn(SDL_LOG_CATEGORY_GPU, "Out of device-local memory, allocating textures on host-local memory!"); 2268 renderer->outOfDeviceLocalMemoryWarning = 1; 2269 } 2270 } 2271 } 2272 2273 return bindResult; 2274} 2275 2276static Uint8 VULKAN_INTERNAL_BindMemoryForBuffer( 2277 VulkanRenderer *renderer, 2278 VkBuffer buffer, 2279 VkDeviceSize size, 2280 VulkanBufferType type, 2281 bool dedicated, 2282 VulkanMemoryUsedRegion **usedRegion) 2283{ 2284 Uint8 bindResult = 0; 2285 Uint32 memoryTypeCount = 0; 2286 Uint32 *memoryTypesToTry = NULL; 2287 Uint32 selectedMemoryTypeIndex = 0; 2288 Uint32 i; 2289 VkMemoryPropertyFlags requiredMemoryPropertyFlags = 0; 2290 VkMemoryPropertyFlags preferredMemoryPropertyFlags = 0; 2291 VkMemoryPropertyFlags tolerableMemoryPropertyFlags = 0; 2292 VkMemoryRequirements memoryRequirements; 2293 2294 /* Buffers need to be optimally bound to a memory type 2295 * based on their use case and the architecture of the system. 2296 * 2297 * It is important to understand the distinction between device and host. 2298 * 2299 * On a traditional high-performance desktop computer, 2300 * the "device" would be the GPU, and the "host" would be the CPU. 2301 * Memory being copied between these two must cross the PCI bus. 2302 * On these systems we have to be concerned about bandwidth limitations 2303 * and causing memory stalls, so we have taken a great deal of care 2304 * to structure this API to guide the client towards optimal usage. 2305 * 2306 * Other kinds of devices do not necessarily have this distinction. 2307 * On an iPhone or Nintendo Switch, all memory is accessible both to the 2308 * GPU and the CPU at all times. These kinds of systems are known as 2309 * UMA, or Unified Memory Architecture. A desktop computer using the 2310 * CPU's integrated graphics can also be thought of as UMA. 2311 * 2312 * Vulkan memory types have several memory properties. 2313 * The relevant memory properties are as follows: 2314 * 2315 * DEVICE_LOCAL: 2316 * This memory is on-device and most efficient for device access. 2317 * On UMA systems all memory is device-local. 2318 * If memory is not device-local, then it is host-local. 2319 * 2320 * HOST_VISIBLE: 2321 * This memory can be mapped for host access, meaning we can obtain 2322 * a pointer to directly access the memory. 2323 * 2324 * HOST_COHERENT: 2325 * Host-coherent memory does not require cache management operations 2326 * when mapped, so we always set this alongside HOST_VISIBLE 2327 * to avoid extra record keeping. 2328 * 2329 * HOST_CACHED: 2330 * Host-cached memory is faster to access than uncached memory 2331 * but memory of this type might not always be available. 2332 * 2333 * GPU buffers, like vertex buffers, indirect buffers, etc 2334 * are optimally stored in device-local memory. 2335 * However, if device-local memory is low, these buffers 2336 * can be accessed from host-local memory with a performance penalty. 2337 * 2338 * Uniform buffers must be host-visible and coherent because 2339 * the client uses them to quickly push small amounts of data. 2340 * We prefer uniform buffers to also be device-local because 2341 * they are accessed by shaders, but the amount of memory 2342 * that is both device-local and host-visible 2343 * is often constrained, particularly on low-end devices. 2344 * 2345 * Transfer buffers must be host-visible and coherent because 2346 * the client uses them to stage data to be transferred 2347 * to device-local memory, or to read back data transferred 2348 * from the device. We prefer the cache bit for performance 2349 * but it isn't strictly necessary. We tolerate device-local 2350 * memory in this situation because, as mentioned above, 2351 * on certain devices all memory is device-local, and even 2352 * though the transfer isn't strictly necessary it is still 2353 * useful for correctly timelining data. 2354 */ 2355 if (type == VULKAN_BUFFER_TYPE_GPU) { 2356 preferredMemoryPropertyFlags |= 2357 VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; 2358 } else if (type == VULKAN_BUFFER_TYPE_UNIFORM) { 2359 requiredMemoryPropertyFlags |= 2360 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | 2361 VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; 2362 2363 preferredMemoryPropertyFlags |= 2364 VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; 2365 } else if (type == VULKAN_BUFFER_TYPE_TRANSFER) { 2366 requiredMemoryPropertyFlags |= 2367 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | 2368 VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; 2369 2370 preferredMemoryPropertyFlags |= 2371 VK_MEMORY_PROPERTY_HOST_CACHED_BIT; 2372 2373 tolerableMemoryPropertyFlags |= 2374 VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; 2375 } else { 2376 SDL_LogError(SDL_LOG_CATEGORY_GPU, "Unrecognized buffer type!"); 2377 return 0; 2378 } 2379 2380 memoryTypesToTry = VULKAN_INTERNAL_FindBestBufferMemoryTypes( 2381 renderer, 2382 buffer, 2383 requiredMemoryPropertyFlags, 2384 preferredMemoryPropertyFlags, 2385 tolerableMemoryPropertyFlags, 2386 &memoryRequirements, 2387 &memoryTypeCount); 2388 2389 for (i = 0; i < memoryTypeCount; i += 1) { 2390 bindResult = VULKAN_INTERNAL_BindResourceMemory( 2391 renderer, 2392 memoryTypesToTry[i], 2393 &memoryRequirements, 2394 size, 2395 dedicated, 2396 buffer, 2397 VK_NULL_HANDLE, 2398 usedRegion); 2399 2400 if (bindResult == 1) { 2401 selectedMemoryTypeIndex = memoryTypesToTry[i]; 2402 break; 2403 } 2404 } 2405 2406 SDL_free(memoryTypesToTry); 2407 2408 // Check for warnings on success 2409 if (bindResult == 1) { 2410 if (type == VULKAN_BUFFER_TYPE_GPU) { 2411 if (!renderer->outOfDeviceLocalMemoryWarning) { 2412 if ((renderer->memoryProperties.memoryTypes[selectedMemoryTypeIndex].propertyFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) == 0) { 2413 SDL_LogWarn(SDL_LOG_CATEGORY_GPU, "Out of device-local memory, allocating buffers on host-local memory, expect degraded performance!"); 2414 renderer->outOfDeviceLocalMemoryWarning = 1; 2415 } 2416 } 2417 } else if (type == VULKAN_BUFFER_TYPE_UNIFORM) { 2418 if (!renderer->outofBARMemoryWarning) { 2419 if ((renderer->memoryProperties.memoryTypes[selectedMemoryTypeIndex].propertyFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) == 0) { 2420 SDL_LogWarn(SDL_LOG_CATEGORY_GPU, "Out of BAR memory, allocating uniform buffers on host-local memory, expect degraded performance!"); 2421 renderer->outofBARMemoryWarning = 1; 2422 } 2423 } 2424 } else if (type == VULKAN_BUFFER_TYPE_TRANSFER) { 2425 if (!renderer->integratedMemoryNotification) { 2426 if ((renderer->memoryProperties.memoryTypes[selectedMemoryTypeIndex].propertyFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) == VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) { 2427 SDL_LogInfo(SDL_LOG_CATEGORY_GPU, "Integrated memory detected, allocating TransferBuffers on device-local memory!"); 2428 renderer->integratedMemoryNotification = 1; 2429 } 2430 } 2431 } 2432 } 2433 2434 return bindResult; 2435} 2436 2437// Resource tracking 2438 2439#define TRACK_RESOURCE(resource, type, array, count, capacity, refcountvar) \ 2440 for (Sint32 i = commandBuffer->count - 1; i >= 0; i -= 1) { \ 2441 if (commandBuffer->array[i] == resource) { \ 2442 return; \ 2443 } \ 2444 } \ 2445 \ 2446 if (commandBuffer->count == commandBuffer->capacity) { \ 2447 commandBuffer->capacity += 1; \ 2448 commandBuffer->array = SDL_realloc( \ 2449 commandBuffer->array, \ 2450 commandBuffer->capacity * sizeof(type)); \ 2451 } \ 2452 commandBuffer->array[commandBuffer->count] = resource; \ 2453 commandBuffer->count += 1; \ 2454 SDL_AtomicIncRef(&refcountvar) 2455 2456 2457static void VULKAN_INTERNAL_TrackBuffer( 2458 VulkanCommandBuffer *commandBuffer, 2459 VulkanBuffer *buffer) 2460{ 2461 TRACK_RESOURCE( 2462 buffer, 2463 VulkanBuffer *, 2464 usedBuffers, 2465 usedBufferCount, 2466 usedBufferCapacity, 2467 buffer->referenceCount); 2468} 2469 2470// Use this function when a GPU buffer is part of a transfer operation. 2471// Note that this isn't for transfer buffers, those don't need to refcount their allocations. 2472static void VULKAN_INTERNAL_TrackBufferTransfer( 2473 VulkanCommandBuffer *commandBuffer, 2474 VulkanBuffer *buffer) 2475{ 2476 TRACK_RESOURCE( 2477 buffer, 2478 VulkanBuffer *, 2479 buffersUsedInPendingTransfers, 2480 buffersUsedInPendingTransfersCount, 2481 buffersUsedInPendingTransfersCapacity, 2482 buffer->usedRegion->allocation->referenceCount); 2483} 2484 2485static void VULKAN_INTERNAL_TrackTexture( 2486 VulkanCommandBuffer *commandBuffer, 2487 VulkanTexture *texture) 2488{ 2489 TRACK_RESOURCE( 2490 texture, 2491 VulkanTexture *, 2492 usedTextures, 2493 usedTextureCount, 2494 usedTextureCapacity, 2495 texture->referenceCount); 2496} 2497 2498// Use this when a texture is part of a transfer operation. 2499static void VULKAN_INTERNAL_TrackTextureTransfer( 2500 VulkanCommandBuffer *commandBuffer, 2501 VulkanTexture *texture) 2502{ 2503 TRACK_RESOURCE( 2504 texture, 2505 VulkanTexture *, 2506 texturesUsedInPendingTransfers, 2507 texturesUsedInPendingTransfersCount, 2508 texturesUsedInPendingTransfersCapacity, 2509 texture->usedRegion->allocation->referenceCount); 2510} 2511 2512static void VULKAN_INTERNAL_TrackSampler( 2513 VulkanCommandBuffer *commandBuffer, 2514 VulkanSampler *sampler) 2515{ 2516 TRACK_RESOURCE( 2517 sampler, 2518 VulkanSampler *, 2519 usedSamplers, 2520 usedSamplerCount, 2521 usedSamplerCapacity, 2522 sampler->referenceCount); 2523} 2524 2525static void VULKAN_INTERNAL_TrackGraphicsPipeline( 2526 VulkanCommandBuffer *commandBuffer, 2527 VulkanGraphicsPipeline *graphicsPipeline) 2528{ 2529 TRACK_RESOURCE( 2530 graphicsPipeline, 2531 VulkanGraphicsPipeline *, 2532 usedGraphicsPipelines, 2533 usedGraphicsPipelineCount, 2534 usedGraphicsPipelineCapacity, 2535 graphicsPipeline->referenceCount); 2536} 2537 2538static void VULKAN_INTERNAL_TrackComputePipeline( 2539 VulkanCommandBuffer *commandBuffer, 2540 VulkanComputePipeline *computePipeline) 2541{ 2542 TRACK_RESOURCE( 2543 computePipeline, 2544 VulkanComputePipeline *, 2545 usedComputePipelines, 2546 usedComputePipelineCount, 2547 usedComputePipelineCapacity, 2548 computePipeline->referenceCount); 2549} 2550 2551static void VULKAN_INTERNAL_TrackFramebuffer( 2552 VulkanCommandBuffer *commandBuffer, 2553 VulkanFramebuffer *framebuffer) 2554{ 2555 TRACK_RESOURCE( 2556 framebuffer, 2557 VulkanFramebuffer *, 2558 usedFramebuffers, 2559 usedFramebufferCount, 2560 usedFramebufferCapacity, 2561 framebuffer->referenceCount); 2562} 2563 2564static void VULKAN_INTERNAL_TrackUniformBuffer( 2565 VulkanCommandBuffer *commandBuffer, 2566 VulkanUniformBuffer *uniformBuffer) 2567{ 2568 for (Sint32 i = commandBuffer->usedUniformBufferCount - 1; i >= 0; i -= 1) { 2569 if (commandBuffer->usedUniformBuffers[i] == uniformBuffer) { 2570 return; 2571 } 2572 } 2573 2574 if (commandBuffer->usedUniformBufferCount == commandBuffer->usedUniformBufferCapacity) { 2575 commandBuffer->usedUniformBufferCapacity += 1; 2576 commandBuffer->usedUniformBuffers = SDL_realloc( 2577 commandBuffer->usedUniformBuffers, 2578 commandBuffer->usedUniformBufferCapacity * sizeof(VulkanUniformBuffer *)); 2579 } 2580 commandBuffer->usedUniformBuffers[commandBuffer->usedUniformBufferCount] = uniformBuffer; 2581 commandBuffer->usedUniformBufferCount += 1; 2582 2583 VULKAN_INTERNAL_TrackBuffer( 2584 commandBuffer, 2585 uniformBuffer->buffer); 2586} 2587 2588#undef TRACK_RESOURCE 2589 2590// Memory Barriers 2591 2592/* 2593 * In Vulkan, we must manually synchronize operations that write to resources on the GPU 2594 * so that read-after-write, write-after-read, and write-after-write hazards do not occur. 2595 * Additionally, textures are required to be in specific layouts for specific use cases. 2596 * Both of these tasks are accomplished with vkCmdPipelineBarrier. 2597 * 2598 * To insert the correct barriers, we keep track of "usage modes" for buffers and textures. 2599 * These indicate the current usage of that resource on the command buffer. 2600 * The transition from one usage mode to another indicates how the barrier should be constructed. 2601 * 2602 * Pipeline barriers cannot be inserted during a render pass, but they can be inserted 2603 * during a compute or copy pass. 2604 * 2605 * This means that the "default" usage mode of any given resource should be that it should be 2606 * ready for a graphics-read operation, because we cannot barrier during a render pass. 2607 * In the case where a resource is only used in compute, its default usage mode can be compute-read. 2608 * This strategy allows us to avoid expensive record keeping of command buffer/resource usage mode pairs, 2609 * and it fully covers synchronization between all combinations of stages. 2610 * 2611 * In Upload and Copy functions, we transition the resource immediately before and after the copy command. 2612 * 2613 * When binding a resource for compute, we transition when the Bind functions are called. 2614 * If a bind slot containing a resource is overwritten, we transition the resource in that slot back to its default. 2615 * When EndComputePass is called we transition all bound resources back to their default state. 2616 * 2617 * When binding a texture as a render pass attachment, we transition the resource on BeginRenderPass 2618 * and transition it back to its default on EndRenderPass. 2619 * 2620 * This strategy imposes certain limitations on resource usage flags. 2621 * For example, a texture cannot have both the SAMPLER and GRAPHICS_STORAGE usage flags, 2622 * because then it is impossible for the backend to infer which default usage mode the texture should use. 2623 * 2624 * Sync hazards can be detected by setting VK_KHRONOS_VALIDATION_VALIDATE_SYNC=1 when using validation layers. 2625 */ 2626 2627static void VULKAN_INTERNAL_BufferMemoryBarrier( 2628 VulkanRenderer *renderer, 2629 VulkanCommandBuffer *commandBuffer, 2630 VulkanBufferUsageMode sourceUsageMode, 2631 VulkanBufferUsageMode destinationUsageMode, 2632 VulkanBuffer *buffer) 2633{ 2634 VkPipelineStageFlags srcStages = 0; 2635 VkPipelineStageFlags dstStages = 0; 2636 VkBufferMemoryBarrier memoryBarrier; 2637 2638 memoryBarrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER; 2639 memoryBarrier.pNext = NULL; 2640 memoryBarrier.srcAccessMask = 0; 2641 memoryBarrier.dstAccessMask = 0; 2642 memoryBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; 2643 memoryBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; 2644 memoryBarrier.buffer = buffer->buffer; 2645 memoryBarrier.offset = 0; 2646 memoryBarrier.size = buffer->size; 2647 2648 if (sourceUsageMode == VULKAN_BUFFER_USAGE_MODE_COPY_SOURCE) { 2649 srcStages = VK_PIPELINE_STAGE_TRANSFER_BIT; 2650 memoryBarrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT; 2651 } else if (sourceUsageMode == VULKAN_BUFFER_USAGE_MODE_COPY_DESTINATION) { 2652 srcStages = VK_PIPELINE_STAGE_TRANSFER_BIT; 2653 memoryBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; 2654 } else if (sourceUsageMode == VULKAN_BUFFER_USAGE_MODE_VERTEX_READ) { 2655 srcStages = VK_PIPELINE_STAGE_VERTEX_INPUT_BIT; 2656 memoryBarrier.srcAccessMask = VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT; 2657 } else if (sourceUsageMode == VULKAN_BUFFER_USAGE_MODE_INDEX_READ) { 2658 srcStages = VK_PIPELINE_STAGE_VERTEX_INPUT_BIT; 2659 memoryBarrier.srcAccessMask = VK_ACCESS_INDEX_READ_BIT; 2660 } else if (sourceUsageMode == VULKAN_BUFFER_USAGE_MODE_INDIRECT) { 2661 srcStages = VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT; 2662 memoryBarrier.srcAccessMask = VK_ACCESS_INDIRECT_COMMAND_READ_BIT; 2663 } else if (sourceUsageMode == VULKAN_BUFFER_USAGE_MODE_GRAPHICS_STORAGE_READ) { 2664 srcStages = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; 2665 memoryBarrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT; 2666 } else if (sourceUsageMode == VULKAN_BUFFER_USAGE_MODE_COMPUTE_STORAGE_READ) { 2667 srcStages = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; 2668 memoryBarrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT; 2669 } else if (sourceUsageMode == VULKAN_BUFFER_USAGE_MODE_COMPUTE_STORAGE_READ_WRITE) { 2670 srcStages = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; 2671 memoryBarrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT; 2672 } else { 2673 SDL_LogError(SDL_LOG_CATEGORY_GPU, "Unrecognized buffer source barrier type!"); 2674 return; 2675 } 2676 2677 if (destinationUsageMode == VULKAN_BUFFER_USAGE_MODE_COPY_SOURCE) { 2678 dstStages = VK_PIPELINE_STAGE_TRANSFER_BIT; 2679 memoryBarrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; 2680 } else if (destinationUsageMode == VULKAN_BUFFER_USAGE_MODE_COPY_DESTINATION) { 2681 dstStages = VK_PIPELINE_STAGE_TRANSFER_BIT; 2682 memoryBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; 2683 } else if (destinationUsageMode == VULKAN_BUFFER_USAGE_MODE_VERTEX_READ) { 2684 dstStages = VK_PIPELINE_STAGE_VERTEX_INPUT_BIT; 2685 memoryBarrier.dstAccessMask = VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT; 2686 } else if (destinationUsageMode == VULKAN_BUFFER_USAGE_MODE_INDEX_READ) { 2687 dstStages = VK_PIPELINE_STAGE_VERTEX_INPUT_BIT; 2688 memoryBarrier.dstAccessMask = VK_ACCESS_INDEX_READ_BIT; 2689 } else if (destinationUsageMode == VULKAN_BUFFER_USAGE_MODE_INDIRECT) { 2690 dstStages = VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT; 2691 memoryBarrier.dstAccessMask = VK_ACCESS_INDIRECT_COMMAND_READ_BIT; 2692 } else if (destinationUsageMode == VULKAN_BUFFER_USAGE_MODE_GRAPHICS_STORAGE_READ) { 2693 dstStages = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; 2694 memoryBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; 2695 } else if (destinationUsageMode == VULKAN_BUFFER_USAGE_MODE_COMPUTE_STORAGE_READ) { 2696 dstStages = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; 2697 memoryBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; 2698 } else if (destinationUsageMode == VULKAN_BUFFER_USAGE_MODE_COMPUTE_STORAGE_READ_WRITE) { 2699 dstStages = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; 2700 memoryBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT; 2701 } else { 2702 SDL_LogError(SDL_LOG_CATEGORY_GPU, "Unrecognized buffer destination barrier type!"); 2703 return; 2704 } 2705 2706 renderer->vkCmdPipelineBarrier( 2707 commandBuffer->commandBuffer, 2708 srcStages, 2709 dstStages, 2710 0, 2711 0, 2712 NULL, 2713 1, 2714 &memoryBarrier, 2715 0, 2716 NULL); 2717 2718 buffer->transitioned = true; 2719} 2720 2721static void VULKAN_INTERNAL_TextureSubresourceMemoryBarrier( 2722 VulkanRenderer *renderer, 2723 VulkanCommandBuffer *commandBuffer, 2724 VulkanTextureUsageMode sourceUsageMode, 2725 VulkanTextureUsageMode destinationUsageMode, 2726 VulkanTextureSubresource *textureSubresource) 2727{ 2728 VkPipelineStageFlags srcStages = 0; 2729 VkPipelineStageFlags dstStages = 0; 2730 VkImageMemoryBarrier memoryBarrier; 2731 2732 memoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; 2733 memoryBarrier.pNext = NULL; 2734 memoryBarrier.srcAccessMask = 0; 2735 memoryBarrier.dstAccessMask = 0; 2736 memoryBarrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; 2737 memoryBarrier.newLayout = VK_IMAGE_LAYOUT_UNDEFINED; 2738 memoryBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; 2739 memoryBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; 2740 memoryBarrier.image = textureSubresource->parent->image; 2741 memoryBarrier.subresourceRange.aspectMask = textureSubresource->parent->aspectFlags; 2742 memoryBarrier.subresourceRange.baseArrayLayer = textureSubresource->layer; 2743 memoryBarrier.subresourceRange.layerCount = 1; 2744 memoryBarrier.subresourceRange.baseMipLevel = textureSubresource->level; 2745 memoryBarrier.subresourceRange.levelCount = 1; 2746 2747 if (sourceUsageMode == VULKAN_TEXTURE_USAGE_MODE_UNINITIALIZED) { 2748 srcStages = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; 2749 memoryBarrier.srcAccessMask = 0; 2750 memoryBarrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; 2751 } else if (sourceUsageMode == VULKAN_TEXTURE_USAGE_MODE_COPY_SOURCE) { 2752 srcStages = VK_PIPELINE_STAGE_TRANSFER_BIT; 2753 memoryBarrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT; 2754 memoryBarrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; 2755 } else if (sourceUsageMode == VULKAN_TEXTURE_USAGE_MODE_COPY_DESTINATION) { 2756 srcStages = VK_PIPELINE_STAGE_TRANSFER_BIT; 2757 memoryBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; 2758 memoryBarrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; 2759 } else if (sourceUsageMode == VULKAN_TEXTURE_USAGE_MODE_SAMPLER) { 2760 srcStages = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; 2761 memoryBarrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT; 2762 memoryBarrier.oldLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; 2763 } else if (sourceUsageMode == VULKAN_TEXTURE_USAGE_MODE_GRAPHICS_STORAGE_READ) { 2764 srcStages = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; 2765 memoryBarrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT; 2766 memoryBarrier.oldLayout = VK_IMAGE_LAYOUT_GENERAL; 2767 } else if (sourceUsageMode == VULKAN_TEXTURE_USAGE_MODE_COMPUTE_STORAGE_READ) { 2768 srcStages = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; 2769 memoryBarrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT; 2770 memoryBarrier.oldLayout = VK_IMAGE_LAYOUT_GENERAL; 2771 } else if (sourceUsageMode == VULKAN_TEXTURE_USAGE_MODE_COMPUTE_STORAGE_READ_WRITE) { 2772 srcStages = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; 2773 memoryBarrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT; 2774 memoryBarrier.oldLayout = VK_IMAGE_LAYOUT_GENERAL; 2775 } else if (sourceUsageMode == VULKAN_TEXTURE_USAGE_MODE_COLOR_ATTACHMENT) { 2776 srcStages = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; 2777 memoryBarrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; 2778 memoryBarrier.oldLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; 2779 } else if (sourceUsageMode == VULKAN_TEXTURE_USAGE_MODE_DEPTH_STENCIL_ATTACHMENT) { 2780 srcStages = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT; 2781 memoryBarrier.srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; 2782 memoryBarrier.oldLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; 2783 } else { 2784 SDL_LogError(SDL_LOG_CATEGORY_GPU, "Unrecognized texture source barrier type!"); 2785 return; 2786 } 2787 2788 if (destinationUsageMode == VULKAN_TEXTURE_USAGE_MODE_COPY_SOURCE) { 2789 dstStages = VK_PIPELINE_STAGE_TRANSFER_BIT; 2790 memoryBarrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; 2791 memoryBarrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; 2792 } else if (destinationUsageMode == VULKAN_TEXTURE_USAGE_MODE_COPY_DESTINATION) { 2793 dstStages = VK_PIPELINE_STAGE_TRANSFER_BIT; 2794 memoryBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; 2795 memoryBarrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; 2796 } else if (destinationUsageMode == VULKAN_TEXTURE_USAGE_MODE_SAMPLER) { 2797 dstStages = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; 2798 memoryBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; 2799 memoryBarrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; 2800 } else if (destinationUsageMode == VULKAN_TEXTURE_USAGE_MODE_GRAPHICS_STORAGE_READ) { 2801 dstStages = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; 2802 memoryBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; 2803 memoryBarrier.newLayout = VK_IMAGE_LAYOUT_GENERAL; 2804 } else if (destinationUsageMode == VULKAN_TEXTURE_USAGE_MODE_COMPUTE_STORAGE_READ) { 2805 dstStages = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; 2806 memoryBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; 2807 memoryBarrier.newLayout = VK_IMAGE_LAYOUT_GENERAL; 2808 } else if (destinationUsageMode == VULKAN_TEXTURE_USAGE_MODE_COMPUTE_STORAGE_READ_WRITE) { 2809 dstStages = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; 2810 memoryBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT; 2811 memoryBarrier.newLayout = VK_IMAGE_LAYOUT_GENERAL; 2812 } else if (destinationUsageMode == VULKAN_TEXTURE_USAGE_MODE_COLOR_ATTACHMENT) { 2813 dstStages = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; 2814 memoryBarrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; 2815 memoryBarrier.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; 2816 } else if (destinationUsageMode == VULKAN_TEXTURE_USAGE_MODE_DEPTH_STENCIL_ATTACHMENT) { 2817 dstStages = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT; 2818 memoryBarrier.dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; 2819 memoryBarrier.newLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; 2820 } else if (destinationUsageMode == VULKAN_TEXTURE_USAGE_MODE_PRESENT) { 2821 dstStages = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; 2822 memoryBarrier.dstAccessMask = 0; 2823 memoryBarrier.newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; 2824 } else { 2825 SDL_LogError(SDL_LOG_CATEGORY_GPU, "Unrecognized texture destination barrier type!"); 2826 return; 2827 } 2828 2829 renderer->vkCmdPipelineBarrier( 2830 commandBuffer->commandBuffer, 2831 srcStages, 2832 dstStages, 2833 0, 2834 0, 2835 NULL, 2836 0, 2837 NULL, 2838 1, 2839 &memoryBarrier); 2840} 2841 2842static VulkanBufferUsageMode VULKAN_INTERNAL_DefaultBufferUsageMode( 2843 VulkanBuffer *buffer) 2844{ 2845 // NOTE: order matters here! 2846 2847 if (buffer->usage & SDL_GPU_BUFFERUSAGE_VERTEX) { 2848 return VULKAN_BUFFER_USAGE_MODE_VERTEX_READ; 2849 } else if (buffer->usage & SDL_GPU_BUFFERUSAGE_INDEX) { 2850 return VULKAN_BUFFER_USAGE_MODE_INDEX_READ; 2851 } else if (buffer->usage & SDL_GPU_BUFFERUSAGE_INDIRECT) { 2852 return VULKAN_BUFFER_USAGE_MODE_INDIRECT; 2853 } else if (buffer->usage & SDL_GPU_BUFFERUSAGE_GRAPHICS_STORAGE_READ) { 2854 return VULKAN_BUFFER_USAGE_MODE_GRAPHICS_STORAGE_READ; 2855 } else if (buffer->usage & SDL_GPU_BUFFERUSAGE_COMPUTE_STORAGE_READ) { 2856 return VULKAN_BUFFER_USAGE_MODE_COMPUTE_STORAGE_READ; 2857 } else if (buffer->usage & SDL_GPU_BUFFERUSAGE_COMPUTE_STORAGE_WRITE) { 2858 return VULKAN_BUFFER_USAGE_MODE_COMPUTE_STORAGE_READ_WRITE; 2859 } else { 2860 SDL_LogError(SDL_LOG_CATEGORY_GPU, "Buffer has no default usage mode!"); 2861 return VULKAN_BUFFER_USAGE_MODE_VERTEX_READ; 2862 } 2863} 2864 2865static VulkanTextureUsageMode VULKAN_INTERNAL_DefaultTextureUsageMode( 2866 VulkanTexture *texture) 2867{ 2868 // NOTE: order matters here! 2869 // NOTE: graphics storage bits and sampler bit are mutually exclusive! 2870 2871 if (texture->usage & SDL_GPU_TEXTUREUSAGE_SAMPLER) { 2872 return VULKAN_TEXTURE_USAGE_MODE_SAMPLER; 2873 } else if (texture->usage & SDL_GPU_TEXTUREUSAGE_GRAPHICS_STORAGE_READ) { 2874 return VULKAN_TEXTURE_USAGE_MODE_GRAPHICS_STORAGE_READ; 2875 } else if (texture->usage & SDL_GPU_TEXTUREUSAGE_COLOR_TARGET) { 2876 return VULKAN_TEXTURE_USAGE_MODE_COLOR_ATTACHMENT; 2877 } else if (texture->usage & SDL_GPU_TEXTUREUSAGE_DEPTH_STENCIL_TARGET) { 2878 return VULKAN_TEXTURE_USAGE_MODE_DEPTH_STENCIL_ATTACHMENT; 2879 } else if (texture->usage & SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_READ) { 2880 return VULKAN_TEXTURE_USAGE_MODE_COMPUTE_STORAGE_READ; 2881 } else if (texture->usage & SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_WRITE) { 2882 return VULKAN_TEXTURE_USAGE_MODE_COMPUTE_STORAGE_READ_WRITE; 2883 } else if (texture->usage & SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_SIMULTANEOUS_READ_WRITE) { 2884 return VULKAN_TEXTURE_USAGE_MODE_COMPUTE_STORAGE_READ_WRITE; 2885 } else { 2886 SDL_LogError(SDL_LOG_CATEGORY_GPU, "Texture has no default usage mode!"); 2887 return VULKAN_TEXTURE_USAGE_MODE_SAMPLER; 2888 } 2889} 2890 2891static void VULKAN_INTERNAL_BufferTransitionFromDefaultUsage( 2892 VulkanRenderer *renderer, 2893 VulkanCommandBuffer *commandBuffer, 2894 VulkanBufferUsageMode destinationUsageMode, 2895 VulkanBuffer *buffer) 2896{ 2897 VULKAN_INTERNAL_BufferMemoryBarrier( 2898 renderer, 2899 commandBuffer, 2900 VULKAN_INTERNAL_DefaultBufferUsageMode(buffer), 2901 destinationUsageMode, 2902 buffer); 2903} 2904 2905static void VULKAN_INTERNAL_BufferTransitionToDefaultUsage( 2906 VulkanRenderer *renderer, 2907 VulkanCommandBuffer *commandBuffer, 2908 VulkanBufferUsageMode sourceUsageMode, 2909 VulkanBuffer *buffer) 2910{ 2911 VULKAN_INTERNAL_BufferMemoryBarrier( 2912 renderer, 2913 commandBuffer, 2914 sourceUsageMode, 2915 VULKAN_INTERNAL_DefaultBufferUsageMode(buffer), 2916 buffer); 2917} 2918 2919static void VULKAN_INTERNAL_TextureSubresourceTransitionFromDefaultUsage( 2920 VulkanRenderer *renderer, 2921 VulkanCommandBuffer *commandBuffer, 2922 VulkanTextureUsageMode destinationUsageMode, 2923 VulkanTextureSubresource *textureSubresource) 2924{ 2925 VULKAN_INTERNAL_TextureSubresourceMemoryBarrier( 2926 renderer, 2927 commandBuffer, 2928 VULKAN_INTERNAL_DefaultTextureUsageMode(textureSubresource->parent), 2929 destinationUsageMode, 2930 textureSubresource); 2931} 2932 2933static void VULKAN_INTERNAL_TextureTransitionFromDefaultUsage( 2934 VulkanRenderer *renderer, 2935 VulkanCommandBuffer *commandBuffer, 2936 VulkanTextureUsageMode destinationUsageMode, 2937 VulkanTexture *texture) 2938{ 2939 for (Uint32 i = 0; i < texture->subresourceCount; i += 1) { 2940 VULKAN_INTERNAL_TextureSubresourceTransitionFromDefaultUsage( 2941 renderer, 2942 commandBuffer, 2943 destinationUsageMode, 2944 &texture->subresources[i]); 2945 } 2946} 2947 2948static void VULKAN_INTERNAL_TextureSubresourceTransitionToDefaultUsage( 2949 VulkanRenderer *renderer, 2950 VulkanCommandBuffer *commandBuffer, 2951 VulkanTextureUsageMode sourceUsageMode, 2952 VulkanTextureSubresource *textureSubresource) 2953{ 2954 VULKAN_INTERNAL_TextureSubresourceMemoryBarrier( 2955 renderer, 2956 commandBuffer, 2957 sourceUsageMode, 2958 VULKAN_INTERNAL_DefaultTextureUsageMode(textureSubresource->parent), 2959 textureSubresource); 2960} 2961 2962static void VULKAN_INTERNAL_TextureTransitionToDefaultUsage( 2963 VulkanRenderer *renderer, 2964 VulkanCommandBuffer *commandBuffer, 2965 VulkanTextureUsageMode sourceUsageMode, 2966 VulkanTexture *texture) 2967{ 2968 // FIXME: could optimize this barrier 2969 for (Uint32 i = 0; i < texture->subresourceCount; i += 1) { 2970 VULKAN_INTERNAL_TextureSubresourceTransitionToDefaultUsage( 2971 renderer, 2972 commandBuffer, 2973 sourceUsageMode, 2974 &texture->subresources[i]); 2975 } 2976} 2977 2978// Resource Disposal 2979 2980static void VULKAN_INTERNAL_ReleaseFramebuffer( 2981 VulkanRenderer *renderer, 2982 VulkanFramebuffer *framebuffer) 2983{ 2984 SDL_LockMutex(renderer->disposeLock); 2985 2986 EXPAND_ARRAY_IF_NEEDED( 2987 renderer->framebuffersToDestroy, 2988 VulkanFramebuffer *, 2989 renderer->framebuffersToDestroyCount + 1, 2990 renderer->framebuffersToDestroyCapacity, 2991 renderer->framebuffersToDestroyCapacity * 2); 2992 2993 renderer->framebuffersToDestroy[renderer->framebuffersToDestroyCount] = framebuffer; 2994 renderer->framebuffersToDestroyCount += 1; 2995 2996 SDL_UnlockMutex(renderer->disposeLock); 2997} 2998 2999static void VULKAN_INTERNAL_DestroyFramebuffer( 3000 VulkanRenderer *renderer, 3001 VulkanFramebuffer *framebuffer) 3002{ 3003 renderer->vkDestroyFramebuffer( 3004 renderer->logicalDevice, 3005 framebuffer->framebuffer, 3006 NULL); 3007 3008 SDL_free(framebuffer); 3009} 3010 3011typedef struct CheckOneFramebufferForRemovalData 3012{ 3013 Uint32 keysToRemoveCapacity; 3014 Uint32 keysToRemoveCount; 3015 FramebufferHashTableKey **keysToRemove; 3016 VkImageView view; 3017} CheckOneFramebufferForRemovalData; 3018 3019static bool SDLCALL CheckOneFramebufferForRemoval(void *userdata, const SDL_HashTable *table, const void *vkey, const void *vvalue) 3020{ 3021 CheckOneFramebufferForRemovalData *data = (CheckOneFramebufferForRemovalData *) userdata; 3022 FramebufferHashTableKey *key = (FramebufferHashTableKey *) vkey; 3023 VkImageView view = data->view; 3024 bool remove = false; 3025 3026 for (Uint32 i = 0; i < key->numColorTargets; i += 1) { 3027 if (key->colorAttachmentViews[i] == view) { 3028 remove = true; 3029 } 3030 } 3031 for (Uint32 i = 0; i < key->numResolveAttachments; i += 1) { 3032 if (key->resolveAttachmentViews[i] == view) { 3033 remove = true; 3034 } 3035 } 3036 if (key->depthStencilAttachmentView == view) { 3037 remove = true; 3038 } 3039 3040 if (remove) { 3041 if (data->keysToRemoveCount == data->keysToRemoveCapacity) { 3042 data->keysToRemoveCapacity *= 2; 3043 void *ptr = SDL_realloc(data->keysToRemove, data->keysToRemoveCapacity * sizeof(FramebufferHashTableKey *)); 3044 if (!ptr) { 3045 return false; // ugh, stop iterating. We're in trouble. 3046 } 3047 data->keysToRemove = (FramebufferHashTableKey **) ptr; 3048 } 3049 data->keysToRemove[data->keysToRemoveCount] = key; 3050 data->keysToRemoveCount++; 3051 } 3052 3053 return true; // keep iterating. 3054} 3055 3056static void VULKAN_INTERNAL_RemoveFramebuffersContainingView( 3057 VulkanRenderer *renderer, 3058 VkImageView view) 3059{ 3060 // Can't remove while iterating! 3061 3062 CheckOneFramebufferForRemovalData data = { 8, 0, NULL, view }; 3063 data.keysToRemove = (FramebufferHashTableKey **) SDL_malloc(data.keysToRemoveCapacity * sizeof(FramebufferHashTableKey *)); 3064 if (!data.keysToRemove) { 3065 return; // uhoh. 3066 } 3067 3068 SDL_LockMutex(renderer->framebufferFetchLock); 3069 3070 SDL_IterateHashTable(renderer->framebufferHashTable, CheckOneFramebufferForRemoval, &data); 3071 3072 for (Uint32 i = 0; i < data.keysToRemoveCount; i += 1) { 3073 SDL_RemoveFromHashTable(renderer->framebufferHashTable, (void *)data.keysToRemove[i]); 3074 } 3075 3076 SDL_UnlockMutex(renderer->framebufferFetchLock); 3077 3078 SDL_free(data.keysToRemove); 3079} 3080 3081static void VULKAN_INTERNAL_DestroyTexture( 3082 VulkanRenderer *renderer, 3083 VulkanTexture *texture) 3084{ 3085 // Clean up subresources 3086 for (Uint32 subresourceIndex = 0; subresourceIndex < texture->subresourceCount; subresourceIndex += 1) { 3087 if (texture->subresources[subresourceIndex].renderTargetViews != NULL) { 3088 for (Uint32 depthIndex = 0; depthIndex < texture->depth; depthIndex += 1) { 3089 VULKAN_INTERNAL_RemoveFramebuffersContainingView( 3090 renderer, 3091 texture->subresources[subresourceIndex].renderTargetViews[depthIndex]); 3092 } 3093 3094 for (Uint32 depthIndex = 0; depthIndex < texture->depth; depthIndex += 1) { 3095 renderer->vkDestroyImageView( 3096 renderer->logicalDevice, 3097 texture->subresources[subresourceIndex].renderTargetViews[depthIndex], 3098 NULL); 3099 } 3100 SDL_free(texture->subresources[subresourceIndex].renderTargetViews); 3101 } 3102 3103 if (texture->subresources[subresourceIndex].computeWriteView != VK_NULL_HANDLE) { 3104 renderer->vkDestroyImageView( 3105 renderer->logicalDevice, 3106 texture->subresources[subresourceIndex].computeWriteView, 3107 NULL); 3108 } 3109 3110 if (texture->subresources[subresourceIndex].depthStencilView != VK_NULL_HANDLE) { 3111 VULKAN_INTERNAL_RemoveFramebuffersContainingView( 3112 renderer, 3113 texture->subresources[subresourceIndex].depthStencilView); 3114 renderer->vkDestroyImageView( 3115 renderer->logicalDevice, 3116 texture->subresources[subresourceIndex].depthStencilView, 3117 NULL); 3118 } 3119 } 3120 3121 SDL_free(texture->subresources); 3122 3123 if (texture->fullView) { 3124 renderer->vkDestroyImageView( 3125 renderer->logicalDevice, 3126 texture->fullView, 3127 NULL); 3128 } 3129 3130 /* Don't free an externally managed VkImage (e.g. XR swapchain images) */ 3131 if (texture->image && !texture->externallyManaged) { 3132 renderer->vkDestroyImage( 3133 renderer->logicalDevice, 3134 texture->image, 3135 NULL); 3136 } 3137 3138 if (texture->usedRegion) { 3139 VULKAN_INTERNAL_RemoveMemoryUsedRegion( 3140 renderer, 3141 texture->usedRegion); 3142 } 3143 3144 SDL_free(texture); 3145} 3146 3147static void VULKAN_INTERNAL_DestroyBuffer( 3148 VulkanRenderer *renderer, 3149 VulkanBuffer *buffer) 3150{ 3151 renderer->vkDestroyBuffer( 3152 renderer->logicalDevice, 3153 buffer->buffer, 3154 NULL); 3155 3156 VULKAN_INTERNAL_RemoveMemoryUsedRegion( 3157 renderer, 3158 buffer->usedRegion); 3159 3160 SDL_free(buffer); 3161} 3162 3163static void VULKAN_INTERNAL_DestroyCommandPool( 3164 VulkanRenderer *renderer, 3165 VulkanCommandPool *commandPool) 3166{ 3167 Uint32 i; 3168 VulkanCommandBuffer *commandBuffer; 3169 3170 renderer->vkDestroyCommandPool( 3171 renderer->logicalDevice, 3172 commandPool->commandPool, 3173 NULL); 3174 3175 for (i = 0; i < commandPool->inactiveCommandBufferCount; i += 1) { 3176 commandBuffer = commandPool->inactiveCommandBuffers[i]; 3177 3178 SDL_free(commandBuffer->presentDatas); 3179 SDL_free(commandBuffer->waitSemaphores); 3180 SDL_free(commandBuffer->signalSemaphores); 3181 SDL_free(commandBuffer->usedBuffers); 3182 SDL_free(commandBuffer->usedTextures); 3183 SDL_free(commandBuffer->usedSamplers); 3184 SDL_free(commandBuffer->usedGraphicsPipelines); 3185 SDL_free(commandBuffer->usedComputePipelines); 3186 SDL_free(commandBuffer->usedFramebuffers); 3187 SDL_free(commandBuffer->usedUniformBuffers); 3188 3189 SDL_free(commandBuffer); 3190 } 3191 3192 SDL_free(commandPool->inactiveCommandBuffers); 3193 SDL_free(commandPool); 3194} 3195 3196static void VULKAN_INTERNAL_DestroyDescriptorSetLayout( 3197 VulkanRenderer *renderer, 3198 DescriptorSetLayout *layout) 3199{ 3200 if (layout == NULL) { 3201 return; 3202 } 3203 3204 if (layout->descriptorSetLayout != VK_NULL_HANDLE) { 3205 renderer->vkDestroyDescriptorSetLayout( 3206 renderer->logicalDevice, 3207 layout->descriptorSetLayout, 3208 NULL); 3209 } 3210 3211 SDL_free(layout); 3212} 3213 3214static void VULKAN_INTERNAL_DestroyGraphicsPipeline( 3215 VulkanRenderer *renderer, 3216 VulkanGraphicsPipeline *graphicsPipeline) 3217{ 3218 renderer->vkDestroyPipeline( 3219 renderer->logicalDevice, 3220 graphicsPipeline->pipeline, 3221 NULL); 3222 3223 (void)SDL_AtomicDecRef(&graphicsPipeline->vertexShader->referenceCount); 3224 (void)SDL_AtomicDecRef(&graphicsPipeline->fragmentShader->referenceCount); 3225 3226 SDL_free(graphicsPipeline); 3227} 3228 3229static void VULKAN_INTERNAL_DestroyComputePipeline( 3230 VulkanRenderer *renderer, 3231 VulkanComputePipeline *computePipeline) 3232{ 3233 if (computePipeline->pipeline != VK_NULL_HANDLE) { 3234 renderer->vkDestroyPipeline( 3235 renderer->logicalDevice, 3236 computePipeline->pipeline, 3237 NULL); 3238 } 3239 3240 if (computePipeline->shaderModule != VK_NULL_HANDLE) { 3241 renderer->vkDestroyShaderModule( 3242 renderer->logicalDevice, 3243 computePipeline->shaderModule, 3244 NULL); 3245 } 3246 3247 SDL_free(computePipeline); 3248} 3249 3250static void VULKAN_INTERNAL_DestroyShader( 3251 VulkanRenderer *renderer, 3252 VulkanShader *vulkanShader) 3253{ 3254 renderer->vkDestroyShaderModule( 3255 renderer->logicalDevice, 3256 vulkanShader->shaderModule, 3257 NULL); 3258 3259 SDL_free(vulkanShader->entrypointName); 3260 SDL_free(vulkanShader); 3261} 3262 3263static void VULKAN_INTERNAL_DestroySampler( 3264 VulkanRenderer *renderer, 3265 VulkanSampler *vulkanSampler) 3266{ 3267 renderer->vkDestroySampler( 3268 renderer->logicalDevice, 3269 vulkanSampler->sampler, 3270 NULL); 3271 3272 SDL_free(vulkanSampler); 3273} 3274 3275static void VULKAN_INTERNAL_DestroySwapchainImage( 3276 VulkanRenderer *renderer, 3277 WindowData *windowData) 3278{ 3279 Uint32 i; 3280 3281 if (windowData == NULL) { 3282 return; 3283 } 3284 3285 for (i = 0; i < windowData->imageCount; i += 1) { 3286 VULKAN_INTERNAL_RemoveFramebuffersContainingView( 3287 renderer, 3288 windowData->textureContainers[i].activeTexture->subresources[0].renderTargetViews[0]); 3289 renderer->vkDestroyImageView( 3290 renderer->logicalDevice, 3291 windowData->textureContainers[i].activeTexture->subresources[0].renderTargetViews[0], 3292 NULL); 3293 SDL_free(windowData->textureContainers[i].activeTexture->subresources[0].renderTargetViews); 3294 SDL_free(windowData->textureContainers[i].activeTexture->subresources); 3295 SDL_free(windowData->textureContainers[i].activeTexture); 3296 } 3297 3298 SDL_free(windowData->textureContainers); 3299 windowData->textureContainers = NULL; 3300 3301 for (i = 0; i < MAX_FRAMES_IN_FLIGHT; i += 1) { 3302 if (windowData->imageAvailableSemaphore[i]) { 3303 renderer->vkDestroySemaphore( 3304 renderer->logicalDevice, 3305 windowData->imageAvailableSemaphore[i], 3306 NULL); 3307 windowData->imageAvailableSemaphore[i] = VK_NULL_HANDLE; 3308 } 3309 } 3310 for (i = 0; i < windowData->imageCount; i += 1) { 3311 if (windowData->renderFinishedSemaphore[i]) { 3312 renderer->vkDestroySemaphore( 3313 renderer->logicalDevice, 3314 windowData->renderFinishedSemaphore[i], 3315 NULL); 3316 windowData->renderFinishedSemaphore[i] = VK_NULL_HANDLE; 3317 } 3318 } 3319 SDL_free(windowData->renderFinishedSemaphore); 3320 windowData->renderFinishedSemaphore = NULL; 3321 3322 windowData->imageCount = 0; 3323} 3324 3325static void VULKAN_INTERNAL_DestroySwapchain( 3326 VulkanRenderer *renderer, 3327 WindowData *windowData) 3328{ 3329 if (windowData == NULL) { 3330 return; 3331 } 3332 3333 VULKAN_INTERNAL_DestroySwapchainImage(renderer, windowData); 3334 3335 if (windowData->swapchain) { 3336 renderer->vkDestroySwapchainKHR( 3337 renderer->logicalDevice, 3338 windowData->swapchain, 3339 NULL); 3340 windowData->swapchain = VK_NULL_HANDLE; 3341 } 3342} 3343 3344static void VULKAN_INTERNAL_DestroyGraphicsPipelineResourceLayout( 3345 VulkanRenderer *renderer, 3346 VulkanGraphicsPipelineResourceLayout *resourceLayout) 3347{ 3348 if (resourceLayout->pipelineLayout != VK_NULL_HANDLE) { 3349 renderer->vkDestroyPipelineLayout( 3350 renderer->logicalDevice, 3351 resourceLayout->pipelineLayout, 3352 NULL); 3353 } 3354 3355 SDL_free(resourceLayout); 3356} 3357 3358static void VULKAN_INTERNAL_DestroyComputePipelineResourceLayout( 3359 VulkanRenderer *renderer, 3360 VulkanComputePipelineResourceLayout *resourceLayout) 3361{ 3362 if (resourceLayout->pipelineLayout != VK_NULL_HANDLE) { 3363 renderer->vkDestroyPipelineLayout( 3364 renderer->logicalDevice, 3365 resourceLayout->pipelineLayout, 3366 NULL); 3367 } 3368 3369 SDL_free(resourceLayout); 3370} 3371 3372static void VULKAN_INTERNAL_DestroyDescriptorSetCache( 3373 VulkanRenderer *renderer, 3374 DescriptorSetCache *descriptorSetCache) 3375{ 3376 for (Uint32 i = 0; i < descriptorSetCache->poolCount; i += 1) { 3377 for (Uint32 j = 0; j < descriptorSetCache->pools[i].poolCount; j += 1) { 3378 renderer->vkDestroyDescriptorPool( 3379 renderer->logicalDevice, 3380 descriptorSetCache->pools[i].descriptorPools[j], 3381 NULL); 3382 } 3383 SDL_free(descriptorSetCache->pools[i].descriptorSets); 3384 SDL_free(descriptorSetCache->pools[i].descriptorPools); 3385 } 3386 SDL_free(descriptorSetCache->pools); 3387 SDL_free(descriptorSetCache); 3388} 3389 3390// Hashtable functions 3391 3392static Uint32 SDLCALL VULKAN_INTERNAL_GraphicsPipelineResourceLayoutHashFunction(void *userdata, const void *key) 3393{ 3394 GraphicsPipelineResourceLayoutHashTableKey *hashTableKey = (GraphicsPipelineResourceLayoutHashTableKey *)key; 3395 /* The algorithm for this hashing function 3396 * is taken from Josh Bloch's "Effective Java". 3397 * (https://stackoverflow.com/a/113600/12492383) 3398 */ 3399 const Uint32 hashFactor = 31; 3400 Uint32 result = 1; 3401 result = result * hashFactor + hashTableKey->vertexSamplerCount; 3402 result = result * hashFactor + hashTableKey->vertexStorageBufferCount; 3403 result = result * hashFactor + hashTableKey->vertexStorageTextureCount; 3404 result = result * hashFactor + hashTableKey->vertexUniformBufferCount; 3405 result = result * hashFactor + hashTableKey->fragmentSamplerCount; 3406 result = result * hashFactor + hashTableKey->fragmentStorageBufferCount; 3407 result = result * hashFactor + hashTableKey->fragmentStorageTextureCount; 3408 result = result * hashFactor + hashTableKey->fragmentUniformBufferCount; 3409 return result; 3410} 3411static bool SDLCALL VULKAN_INTERNAL_GraphicsPipelineResourceLayoutHashKeyMatch(void *userdata, const void *aKey, const void *bKey) 3412{ 3413 return SDL_memcmp(aKey, bKey, sizeof(GraphicsPipelineResourceLayoutHashTableKey)) == 0; 3414} 3415static void SDLCALL VULKAN_INTERNAL_GraphicsPipelineResourceLayoutHashDestroy(void *userdata, const void *key, const void *value) 3416{ 3417 VulkanRenderer *renderer = (VulkanRenderer *)userdata; 3418 VulkanGraphicsPipelineResourceLayout *resourceLayout = (VulkanGraphicsPipelineResourceLayout *)value; 3419 VULKAN_INTERNAL_DestroyGraphicsPipelineResourceLayout(renderer, resourceLayout); 3420 SDL_free((void *)key); 3421} 3422 3423static Uint32 SDLCALL VULKAN_INTERNAL_ComputePipelineResourceLayoutHashFunction(void *userdata, const void *key) 3424{ 3425 ComputePipelineResourceLayoutHashTableKey *hashTableKey = (ComputePipelineResourceLayoutHashTableKey *)key; 3426 /* The algorithm for this hashing function 3427 * is taken from Josh Bloch's "Effective Java". 3428 * (https://stackoverflow.com/a/113600/12492383) 3429 */ 3430 const Uint32 hashFactor = 31; 3431 Uint32 result = 1; 3432 result = result * hashFactor + hashTableKey->samplerCount; 3433 result = result * hashFactor + hashTableKey->readonlyStorageTextureCount; 3434 result = result * hashFactor + hashTableKey->readonlyStorageBufferCount; 3435 result = result * hashFactor + hashTableKey->readWriteStorageTextureCount; 3436 result = result * hashFactor + hashTableKey->readWriteStorageBufferCount; 3437 result = result * hashFactor + hashTableKey->uniformBufferCount; 3438 return result; 3439} 3440 3441static bool SDLCALL VULKAN_INTERNAL_ComputePipelineResourceLayoutHashKeyMatch(void *userdata, const void *aKey, const void *bKey) 3442{ 3443 return SDL_memcmp(aKey, bKey, sizeof(ComputePipelineResourceLayoutHashTableKey)) == 0; 3444} 3445 3446static void SDLCALL VULKAN_INTERNAL_ComputePipelineResourceLayoutHashDestroy(void *userdata, const void *key, const void *value) 3447{ 3448 VulkanRenderer *renderer = (VulkanRenderer *)userdata; 3449 VulkanComputePipelineResourceLayout *resourceLayout = (VulkanComputePipelineResourceLayout *)value; 3450 VULKAN_INTERNAL_DestroyComputePipelineResourceLayout(renderer, resourceLayout); 3451 SDL_free((void *)key); 3452} 3453 3454static Uint32 SDLCALL VULKAN_INTERNAL_DescriptorSetLayoutHashFunction(void *userdata, const void *key) 3455{ 3456 DescriptorSetLayoutHashTableKey *hashTableKey = (DescriptorSetLayoutHashTableKey *)key; 3457 3458 /* The algorithm for this hashing function 3459 * is taken from Josh Bloch's "Effective Java". 3460 * (https://stackoverflow.com/a/113600/12492383) 3461 */ 3462 const Uint32 hashFactor = 31; 3463 Uint32 result = 1; 3464 result = result * hashFactor + hashTableKey->shaderStage; 3465 result = result * hashFactor + hashTableKey->samplerCount; 3466 result = result * hashFactor + hashTableKey->storageTextureCount; 3467 result = result * hashFactor + hashTableKey->storageBufferCount; 3468 result = result * hashFactor + hashTableKey->writeStorageTextureCount; 3469 result = result * hashFactor + hashTableKey->writeStorageBufferCount; 3470 result = result * hashFactor + hashTableKey->uniformBufferCount; 3471 return result; 3472} 3473 3474static bool SDLCALL VULKAN_INTERNAL_DescriptorSetLayoutHashKeyMatch(void *userdata, const void *aKey, const void *bKey) 3475{ 3476 return SDL_memcmp(aKey, bKey, sizeof(DescriptorSetLayoutHashTableKey)) == 0; 3477} 3478 3479static void SDLCALL VULKAN_INTERNAL_DescriptorSetLayoutHashDestroy(void *userdata, const void *key, const void *value) 3480{ 3481 VulkanRenderer *renderer = (VulkanRenderer *)userdata; 3482 DescriptorSetLayout *layout = (DescriptorSetLayout *)value; 3483 VULKAN_INTERNAL_DestroyDescriptorSetLayout(renderer, layout); 3484 SDL_free((void *)key); 3485} 3486 3487static Uint32 SDLCALL VULKAN_INTERNAL_CommandPoolHashFunction(void *userdata, const void *key) 3488{ 3489 return (Uint32)((CommandPoolHashTableKey *)key)->threadID; 3490} 3491 3492static bool SDLCALL VULKAN_INTERNAL_CommandPoolHashKeyMatch(void *userdata, const void *aKey, const void *bKey) 3493{ 3494 CommandPoolHashTableKey *a = (CommandPoolHashTableKey *)aKey; 3495 CommandPoolHashTableKey *b = (CommandPoolHashTableKey *)bKey; 3496 return a->threadID == b->threadID; 3497} 3498 3499static void SDLCALL VULKAN_INTERNAL_CommandPoolHashDestroy(void *userdata, const void *key, const void *value) 3500{ 3501 VulkanRenderer *renderer = (VulkanRenderer *)userdata; 3502 VulkanCommandPool *pool = (VulkanCommandPool *)value; 3503 VULKAN_INTERNAL_DestroyCommandPool(renderer, pool); 3504 SDL_free((void *)key); 3505} 3506 3507static Uint32 SDLCALL VULKAN_INTERNAL_RenderPassHashFunction(void *userdata, const void *key) 3508{ 3509 RenderPassHashTableKey *hashTableKey = (RenderPassHashTableKey *)key; 3510 3511 /* The algorithm for this hashing function 3512 * is taken from Josh Bloch's "Effective Java". 3513 * (https://stackoverflow.com/a/113600/12492383) 3514 */ 3515 const Uint32 hashFactor = 31; 3516 Uint32 result = 1; 3517 3518 for (Uint32 i = 0; i < hashTableKey->numColorTargets; i += 1) { 3519 result = result * hashFactor + hashTableKey->colorTargetDescriptions[i].loadOp; 3520 result = result * hashFactor + hashTableKey->colorTargetDescriptions[i].storeOp; 3521 result = result * hashFactor + hashTableKey->colorTargetDescriptions[i].format; 3522 } 3523 3524 for (Uint32 i = 0; i < hashTableKey->numResolveTargets; i += 1) { 3525 result = result * hashFactor + hashTableKey->resolveTargetFormats[i]; 3526 } 3527 3528 result = result * hashFactor + hashTableKey->depthStencilTargetDescription.loadOp; 3529 result = result * hashFactor + hashTableKey->depthStencilTargetDescription.storeOp; 3530 result = result * hashFactor + hashTableKey->depthStencilTargetDescription.stencilLoadOp; 3531 result = result * hashFactor + hashTableKey->depthStencilTargetDescription.stencilStoreOp; 3532 result = result * hashFactor + hashTableKey->depthStencilTargetDescription.format; 3533 3534 result = result * hashFactor + hashTableKey->sampleCount; 3535 3536 return result; 3537} 3538 3539static bool SDLCALL VULKAN_INTERNAL_RenderPassHashKeyMatch(void *userdata, const void *aKey, const void *bKey) 3540{ 3541 RenderPassHashTableKey *a = (RenderPassHashTableKey *)aKey; 3542 RenderPassHashTableKey *b = (RenderPassHashTableKey *)bKey; 3543 3544 if (a->numColorTargets != b->numColorTargets) { 3545 return 0; 3546 } 3547 3548 if (a->numResolveTargets != b->numResolveTargets) { 3549 return 0; 3550 } 3551 3552 if (a->sampleCount != b->sampleCount) { 3553 return 0; 3554 } 3555 3556 for (Uint32 i = 0; i < a->numColorTargets; i += 1) { 3557 if (a->colorTargetDescriptions[i].format != b->colorTargetDescriptions[i].format) { 3558 return 0; 3559 } 3560 3561 if (a->colorTargetDescriptions[i].loadOp != b->colorTargetDescriptions[i].loadOp) { 3562 return 0; 3563 } 3564 3565 if (a->colorTargetDescriptions[i].storeOp != b->colorTargetDescriptions[i].storeOp) { 3566 return 0; 3567 } 3568 } 3569 3570 for (Uint32 i = 0; i < a->numResolveTargets; i += 1) { 3571 if (a->resolveTargetFormats[i] != b->resolveTargetFormats[i]) { 3572 return 0; 3573 } 3574 } 3575 3576 if (a->depthStencilTargetDescription.format != b->depthStencilTargetDescription.format) { 3577 return 0; 3578 } 3579 3580 if (a->depthStencilTargetDescription.loadOp != b->depthStencilTargetDescription.loadOp) { 3581 return 0; 3582 } 3583 3584 if (a->depthStencilTargetDescription.storeOp != b->depthStencilTargetDescription.storeOp) { 3585 return 0; 3586 } 3587 3588 if (a->depthStencilTargetDescription.stencilLoadOp != b->depthStencilTargetDescription.stencilLoadOp) { 3589 return 0; 3590 } 3591 3592 if (a->depthStencilTargetDescription.stencilStoreOp != b->depthStencilTargetDescription.stencilStoreOp) { 3593 return 0; 3594 } 3595 3596 return 1; 3597} 3598 3599static void SDLCALL VULKAN_INTERNAL_RenderPassHashDestroy(void *userdata, const void *key, const void *value) 3600{ 3601 VulkanRenderer *renderer = (VulkanRenderer *)userdata; 3602 VulkanRenderPassHashTableValue *renderPassWrapper = (VulkanRenderPassHashTableValue *)value; 3603 renderer->vkDestroyRenderPass( 3604 renderer->logicalDevice, 3605 renderPassWrapper->handle, 3606 NULL); 3607 SDL_free(renderPassWrapper); 3608 SDL_free((void *)key); 3609} 3610 3611static Uint32 SDLCALL VULKAN_INTERNAL_FramebufferHashFunction(void *userdata, const void *key) 3612{ 3613 FramebufferHashTableKey *hashTableKey = (FramebufferHashTableKey *)key; 3614 3615 /* The algorithm for this hashing function 3616 * is taken from Josh Bloch's "Effective Java". 3617 * (https://stackoverflow.com/a/113600/12492383) 3618 */ 3619 const Uint32 hashFactor = 31; 3620 Uint32 result = 1; 3621 3622 for (Uint32 i = 0; i < hashTableKey->numColorTargets; i += 1) { 3623 result = result * hashFactor + (Uint32)(uintptr_t)hashTableKey->colorAttachmentViews[i]; 3624 } 3625 for (Uint32 i = 0; i < hashTableKey->numResolveAttachments; i += 1) { 3626 result = result * hashFactor + (Uint32)(uintptr_t)hashTableKey->resolveAttachmentViews[i]; 3627 } 3628 3629 result = result * hashFactor + (Uint32)(uintptr_t)hashTableKey->depthStencilAttachmentView; 3630 result = result * hashFactor + hashTableKey->width; 3631 result = result * hashFactor + hashTableKey->height; 3632 3633 return result; 3634} 3635 3636static bool SDLCALL VULKAN_INTERNAL_FramebufferHashKeyMatch(void *userdata, const void *aKey, const void *bKey) 3637{ 3638 FramebufferHashTableKey *a = (FramebufferHashTableKey *)aKey; 3639 FramebufferHashTableKey *b = (FramebufferHashTableKey *)bKey; 3640 3641 if (a->numColorTargets != b->numColorTargets) { 3642 return 0; 3643 } 3644 3645 if (a->numResolveAttachments != b->numResolveAttachments) { 3646 return 0; 3647 } 3648 3649 for (Uint32 i = 0; i < a->numColorTargets; i += 1) { 3650 if (a->colorAttachmentViews[i] != b->colorAttachmentViews[i]) { 3651 return 0; 3652 } 3653 } 3654 3655 for (Uint32 i = 0; i < a->numResolveAttachments; i += 1) { 3656 if (a->resolveAttachmentViews[i] != b->resolveAttachmentViews[i]) { 3657 return 0; 3658 } 3659 } 3660 3661 if (a->depthStencilAttachmentView != b->depthStencilAttachmentView) { 3662 return 0; 3663 } 3664 3665 if (a->width != b->width) { 3666 return 0; 3667 } 3668 3669 if (a->height != b->height) { 3670 return 0; 3671 } 3672 3673 return 1; 3674} 3675 3676static void SDLCALL VULKAN_INTERNAL_FramebufferHashDestroy(void *userdata, const void *key, const void *value) 3677{ 3678 VulkanRenderer *renderer = (VulkanRenderer *)userdata; 3679 VulkanFramebuffer *framebuffer = (VulkanFramebuffer *)value; 3680 VULKAN_INTERNAL_ReleaseFramebuffer(renderer, framebuffer); 3681 SDL_free((void *)key); 3682} 3683 3684// Descriptor pools 3685 3686static bool VULKAN_INTERNAL_AllocateDescriptorSets( 3687 VulkanRenderer *renderer, 3688 VkDescriptorPool descriptorPool, 3689 VkDescriptorSetLayout descriptorSetLayout, 3690 Uint32 descriptorSetCount, 3691 VkDescriptorSet *descriptorSetArray) 3692{ 3693 VkDescriptorSetAllocateInfo descriptorSetAllocateInfo; 3694 VkDescriptorSetLayout *descriptorSetLayouts = SDL_stack_alloc(VkDescriptorSetLayout, descriptorSetCount); 3695 VkResult vulkanResult; 3696 Uint32 i; 3697 3698 for (i = 0; i < descriptorSetCount; i += 1) { 3699 descriptorSetLayouts[i] = descriptorSetLayout; 3700 } 3701 3702 descriptorSetAllocateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; 3703 descriptorSetAllocateInfo.pNext = NULL; 3704 descriptorSetAllocateInfo.descriptorPool = descriptorPool; 3705 descriptorSetAllocateInfo.descriptorSetCount = descriptorSetCount; 3706 descriptorSetAllocateInfo.pSetLayouts = descriptorSetLayouts; 3707 3708 vulkanResult = renderer->vkAllocateDescriptorSets( 3709 renderer->logicalDevice, 3710 &descriptorSetAllocateInfo, 3711 descriptorSetArray); 3712 3713 SDL_stack_free(descriptorSetLayouts); 3714 3715 CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkAllocateDescriptorSets, false); 3716 3717 return true; 3718} 3719 3720static bool VULKAN_INTERNAL_AllocateDescriptorsFromPool( 3721 VulkanRenderer *renderer, 3722 DescriptorSetLayout *descriptorSetLayout, 3723 DescriptorSetPool *descriptorSetPool) 3724{ 3725 VkDescriptorPoolSize descriptorPoolSizes[ 3726 MAX_TEXTURE_SAMPLERS_PER_STAGE + 3727 MAX_STORAGE_TEXTURES_PER_STAGE + 3728 MAX_STORAGE_BUFFERS_PER_STAGE + 3729 MAX_COMPUTE_WRITE_TEXTURES + 3730 MAX_COMPUTE_WRITE_BUFFERS + 3731 MAX_UNIFORM_BUFFERS_PER_STAGE]; 3732 VkDescriptorPoolCreateInfo descriptorPoolInfo; 3733 VkDescriptorPool pool; 3734 VkResult vulkanResult; 3735 3736 // Category 1 3737 for (Uint32 i = 0; i < descriptorSetLayout->samplerCount; i += 1) { 3738 descriptorPoolSizes[i].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; 3739 descriptorPoolSizes[i].descriptorCount = DESCRIPTOR_POOL_SIZE; 3740 } 3741 3742 for (Uint32 i = descriptorSetLayout->samplerCount; i < descriptorSetLayout->samplerCount + descriptorSetLayout->storageTextureCount; i += 1) { 3743 descriptorPoolSizes[i].type = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE; // Yes, we are declaring the storage image as a sampled image, because shaders are stupid. 3744 descriptorPoolSizes[i].descriptorCount = DESCRIPTOR_POOL_SIZE; 3745 } 3746 3747 for (Uint32 i = descriptorSetLayout->samplerCount + descriptorSetLayout->storageTextureCount; i < descriptorSetLayout->samplerCount + descriptorSetLayout->storageTextureCount + descriptorSetLayout->storageBufferCount; i += 1) { 3748 descriptorPoolSizes[i].type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; 3749 descriptorPoolSizes[i].descriptorCount = DESCRIPTOR_POOL_SIZE; 3750 } 3751 3752 // Category 2 3753 for (Uint32 i = 0; i < descriptorSetLayout->writeStorageTextureCount; i += 1) { 3754 descriptorPoolSizes[i].type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; 3755 descriptorPoolSizes[i].descriptorCount = DESCRIPTOR_POOL_SIZE; 3756 } 3757 3758 for (Uint32 i = descriptorSetLayout->writeStorageTextureCount; i < descriptorSetLayout->writeStorageTextureCount + descriptorSetLayout->writeStorageBufferCount; i += 1) { 3759 descriptorPoolSizes[i].type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; 3760 descriptorPoolSizes[i].descriptorCount = DESCRIPTOR_POOL_SIZE; 3761 } 3762 3763 // Category 3 3764 for (Uint32 i = 0; i < descriptorSetLayout->uniformBufferCount; i += 1) { 3765 descriptorPoolSizes[i].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC; 3766 descriptorPoolSizes[i].descriptorCount = DESCRIPTOR_POOL_SIZE; 3767 } 3768 3769 descriptorPoolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; 3770 descriptorPoolInfo.pNext = NULL; 3771 descriptorPoolInfo.flags = 0; 3772 descriptorPoolInfo.maxSets = DESCRIPTOR_POOL_SIZE; 3773 descriptorPoolInfo.poolSizeCount = 3774 descriptorSetLayout->samplerCount + 3775 descriptorSetLayout->storageTextureCount + 3776 descriptorSetLayout->storageBufferCount + 3777 descriptorSetLayout->writeStorageTextureCount + 3778 descriptorSetLayout->writeStorageBufferCount + 3779 descriptorSetLayout->uniformBufferCount; 3780 descriptorPoolInfo.pPoolSizes = descriptorPoolSizes; 3781 3782 vulkanResult = renderer->vkCreateDescriptorPool( 3783 renderer->logicalDevice, 3784 &descriptorPoolInfo, 3785 NULL, 3786 &pool); 3787 3788 CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkCreateDescriptorPool, false); 3789 3790 descriptorSetPool->poolCount += 1; 3791 descriptorSetPool->descriptorPools = SDL_realloc( 3792 descriptorSetPool->descriptorPools, 3793 sizeof(VkDescriptorPool) * descriptorSetPool->poolCount); 3794 3795 descriptorSetPool->descriptorPools[descriptorSetPool->poolCount - 1] = pool; 3796 3797 descriptorSetPool->descriptorSets = SDL_realloc( 3798 descriptorSetPool->descriptorSets, 3799 sizeof(VkDescriptorSet) * descriptorSetPool->poolCount * DESCRIPTOR_POOL_SIZE); 3800 3801 if (!VULKAN_INTERNAL_AllocateDescriptorSets( 3802 renderer, 3803 pool, 3804 descriptorSetLayout->descriptorSetLayout, 3805 DESCRIPTOR_POOL_SIZE, 3806 &descriptorSetPool->descriptorSets[descriptorSetPool->descriptorSetCount])) { 3807 return false; 3808 } 3809 3810 descriptorSetPool->descriptorSetCount += DESCRIPTOR_POOL_SIZE; 3811 3812 return true; 3813} 3814 3815// NOTE: these categories should be mutually exclusive 3816static DescriptorSetLayout *VULKAN_INTERNAL_FetchDescriptorSetLayout( 3817 VulkanRenderer *renderer, 3818 VkShaderStageFlagBits shaderStage, 3819 // Category 1: read resources 3820 Uint32 samplerCount, 3821 Uint32 storageTextureCount, 3822 Uint32 storageBufferCount, 3823 // Category 2: write resources 3824 Uint32 writeStorageTextureCount, 3825 Uint32 writeStorageBufferCount, 3826 // Category 3: uniform buffers 3827 Uint32 uniformBufferCount) 3828{ 3829 DescriptorSetLayoutHashTableKey key; 3830 SDL_zero(key); 3831 DescriptorSetLayout *layout = NULL; 3832 3833 key.shaderStage = shaderStage; 3834 key.samplerCount = samplerCount; 3835 key.storageTextureCount = storageTextureCount; 3836 key.storageBufferCount = storageBufferCount; 3837 key.writeStorageTextureCount = writeStorageTextureCount; 3838 key.writeStorageBufferCount = writeStorageBufferCount; 3839 key.uniformBufferCount = uniformBufferCount; 3840 3841 SDL_LockMutex(renderer->descriptorSetLayoutFetchLock); 3842 3843 if (SDL_FindInHashTable( 3844 renderer->descriptorSetLayoutHashTable, 3845 (const void *)&key, 3846 (const void **)&layout)) { 3847 SDL_UnlockMutex(renderer->descriptorSetLayoutFetchLock); 3848 return layout; 3849 } 3850 3851 VkDescriptorSetLayout descriptorSetLayout; 3852 VkDescriptorSetLayoutBinding descriptorSetLayoutBindings[ 3853 MAX_TEXTURE_SAMPLERS_PER_STAGE + 3854 MAX_STORAGE_TEXTURES_PER_STAGE + 3855 MAX_STORAGE_BUFFERS_PER_STAGE + 3856 MAX_COMPUTE_WRITE_TEXTURES + 3857 MAX_COMPUTE_WRITE_BUFFERS]; 3858 3859 VkDescriptorSetLayoutCreateInfo descriptorSetLayoutCreateInfo; 3860 descriptorSetLayoutCreateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; 3861 descriptorSetLayoutCreateInfo.pNext = NULL; 3862 descriptorSetLayoutCreateInfo.flags = 0; 3863 3864 // Category 1 3865 for (Uint32 i = 0; i < samplerCount; i += 1) { 3866 descriptorSetLayoutBindings[i].binding = i; 3867 descriptorSetLayoutBindings[i].descriptorCount = 1; 3868 descriptorSetLayoutBindings[i].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; 3869 descriptorSetLayoutBindings[i].stageFlags = shaderStage; 3870 descriptorSetLayoutBindings[i].pImmutableSamplers = NULL; 3871 } 3872 3873 for (Uint32 i = samplerCount; i < samplerCount + storageTextureCount; i += 1) { 3874 descriptorSetLayoutBindings[i].binding = i; 3875 descriptorSetLayoutBindings[i].descriptorCount = 1; 3876 descriptorSetLayoutBindings[i].descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE; // Yes, we are declaring the storage image as a sampled image, because shaders are stupid. 3877 descriptorSetLayoutBindings[i].stageFlags = shaderStage; 3878 descriptorSetLayoutBindings[i].pImmutableSamplers = NULL; 3879 } 3880 3881 for (Uint32 i = samplerCount + storageTextureCount; i < samplerCount + storageTextureCount + storageBufferCount; i += 1) { 3882 descriptorSetLayoutBindings[i].binding = i; 3883 descriptorSetLayoutBindings[i].descriptorCount = 1; 3884 descriptorSetLayoutBindings[i].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; 3885 descriptorSetLayoutBindings[i].stageFlags = shaderStage; 3886 descriptorSetLayoutBindings[i].pImmutableSamplers = NULL; 3887 } 3888 3889 // Category 2 3890 for (Uint32 i = 0; i < writeStorageTextureCount; i += 1) { 3891 descriptorSetLayoutBindings[i].binding = i; 3892 descriptorSetLayoutBindings[i].descriptorCount = 1; 3893 descriptorSetLayoutBindings[i].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; 3894 descriptorSetLayoutBindings[i].stageFlags = shaderStage; 3895 descriptorSetLayoutBindings[i].pImmutableSamplers = NULL; 3896 } 3897 3898 for (Uint32 i = writeStorageTextureCount; i < writeStorageTextureCount + writeStorageBufferCount; i += 1) { 3899 descriptorSetLayoutBindings[i].binding = i; 3900 descriptorSetLayoutBindings[i].descriptorCount = 1; 3901 descriptorSetLayoutBindings[i].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; 3902 descriptorSetLayoutBindings[i].stageFlags = shaderStage; 3903 descriptorSetLayoutBindings[i].pImmutableSamplers = NULL; 3904 } 3905 3906 // Category 3 3907 for (Uint32 i = 0; i < uniformBufferCount; i += 1) { 3908 descriptorSetLayoutBindings[i].binding = i; 3909 descriptorSetLayoutBindings[i].descriptorCount = 1; 3910 descriptorSetLayoutBindings[i].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC; 3911 descriptorSetLayoutBindings[i].stageFlags = shaderStage; 3912 descriptorSetLayoutBindings[i].pImmutableSamplers = NULL; 3913 } 3914 3915 descriptorSetLayoutCreateInfo.pBindings = descriptorSetLayoutBindings; 3916 descriptorSetLayoutCreateInfo.bindingCount = 3917 samplerCount + 3918 storageTextureCount + 3919 storageBufferCount + 3920 writeStorageTextureCount + 3921 writeStorageBufferCount + 3922 uniformBufferCount; 3923 3924 VkResult vulkanResult = renderer->vkCreateDescriptorSetLayout( 3925 renderer->logicalDevice, 3926 &descriptorSetLayoutCreateInfo, 3927 NULL, 3928 &descriptorSetLayout); 3929 3930 if (vulkanResult != VK_SUCCESS) { 3931 SDL_UnlockMutex(renderer->descriptorSetLayoutFetchLock); 3932 CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkCreateDescriptorSetLayout, NULL); 3933 } 3934 3935 layout = SDL_malloc(sizeof(DescriptorSetLayout)); 3936 layout->descriptorSetLayout = descriptorSetLayout; 3937 3938 layout->samplerCount = samplerCount; 3939 layout->storageBufferCount = storageBufferCount; 3940 layout->storageTextureCount = storageTextureCount; 3941 layout->writeStorageBufferCount = writeStorageBufferCount; 3942 layout->writeStorageTextureCount = writeStorageTextureCount; 3943 layout->uniformBufferCount = uniformBufferCount; 3944 3945 layout->ID = SDL_AtomicIncRef(&renderer->layoutResourceID); 3946 3947 DescriptorSetLayoutHashTableKey *allocedKey = SDL_malloc(sizeof(DescriptorSetLayoutHashTableKey)); 3948 SDL_memcpy(allocedKey, &key, sizeof(DescriptorSetLayoutHashTableKey)); 3949 3950 SDL_InsertIntoHashTable( 3951 renderer->descriptorSetLayoutHashTable, 3952 (const void *)allocedKey, 3953 (const void *)layout, true); 3954 3955 SDL_UnlockMutex(renderer->descriptorSetLayoutFetchLock); 3956 return layout; 3957} 3958 3959static VulkanGraphicsPipelineResourceLayout *VULKAN_INTERNAL_FetchGraphicsPipelineResourceLayout( 3960 VulkanRenderer *renderer, 3961 VulkanShader *vertexShader, 3962 VulkanShader *fragmentShader) 3963{ 3964 GraphicsPipelineResourceLayoutHashTableKey key; 3965 SDL_zero(key); 3966 VulkanGraphicsPipelineResourceLayout *pipelineResourceLayout = NULL; 3967 3968 key.vertexSamplerCount = vertexShader->numSamplers; 3969 key.vertexStorageTextureCount = vertexShader->numStorageTextures; 3970 key.vertexStorageBufferCount = vertexShader->numStorageBuffers; 3971 key.vertexUniformBufferCount = vertexShader->numUniformBuffers; 3972 key.fragmentSamplerCount = fragmentShader->numSamplers; 3973 key.fragmentStorageTextureCount = fragmentShader->numStorageTextures; 3974 key.fragmentStorageBufferCount = fragmentShader->numStorageBuffers; 3975 key.fragmentUniformBufferCount = fragmentShader->numUniformBuffers; 3976 3977 SDL_LockMutex(renderer->graphicsPipelineLayoutFetchLock); 3978 3979 if (SDL_FindInHashTable( 3980 renderer->graphicsPipelineResourceLayoutHashTable, 3981 (const void *)&key, 3982 (const void **)&pipelineResourceLayout)) { 3983 SDL_UnlockMutex(renderer->graphicsPipelineLayoutFetchLock); 3984 return pipelineResourceLayout; 3985 } 3986 3987 VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo; 3988 VkDescriptorSetLayout descriptorSetLayouts[4]; 3989 VkResult vulkanResult; 3990 3991 pipelineResourceLayout = SDL_calloc(1, sizeof(VulkanGraphicsPipelineResourceLayout)); 3992 3993 pipelineResourceLayout->descriptorSetLayouts[0] = VULKAN_INTERNAL_FetchDescriptorSetLayout( 3994 renderer, 3995 VK_SHADER_STAGE_VERTEX_BIT, 3996 vertexShader->numSamplers, 3997 vertexShader->numStorageTextures, 3998 vertexShader->numStorageBuffers, 3999 0, 4000 0, 4001 0); 4002 4003 pipelineResourceLayout->descriptorSetLayouts[1] = VULKAN_INTERNAL_FetchDescriptorSetLayout( 4004 renderer, 4005 VK_SHADER_STAGE_VERTEX_BIT, 4006 0, 4007 0, 4008 0, 4009 0, 4010 0, 4011 vertexShader->numUniformBuffers); 4012 4013 pipelineResourceLayout->descriptorSetLayouts[2] = VULKAN_INTERNAL_FetchDescriptorSetLayout( 4014 renderer, 4015 VK_SHADER_STAGE_FRAGMENT_BIT, 4016 fragmentShader->numSamplers, 4017 fragmentShader->numStorageTextures, 4018 fragmentShader->numStorageBuffers, 4019 0, 4020 0, 4021 0); 4022 4023 pipelineResourceLayout->descriptorSetLayouts[3] = VULKAN_INTERNAL_FetchDescriptorSetLayout( 4024 renderer, 4025 VK_SHADER_STAGE_FRAGMENT_BIT, 4026 0, 4027 0, 4028 0, 4029 0, 4030 0, 4031 fragmentShader->numUniformBuffers); 4032 4033 descriptorSetLayouts[0] = pipelineResourceLayout->descriptorSetLayouts[0]->descriptorSetLayout; 4034 descriptorSetLayouts[1] = pipelineResourceLayout->descriptorSetLayouts[1]->descriptorSetLayout; 4035 descriptorSetLayouts[2] = pipelineResourceLayout->descriptorSetLayouts[2]->descriptorSetLayout; 4036 descriptorSetLayouts[3] = pipelineResourceLayout->descriptorSetLayouts[3]->descriptorSetLayout; 4037 4038 pipelineResourceLayout->vertexSamplerCount = vertexShader->numSamplers; 4039 pipelineResourceLayout->vertexStorageTextureCount = vertexShader->numStorageTextures; 4040 pipelineResourceLayout->vertexStorageBufferCount = vertexShader->numStorageBuffers; 4041 pipelineResourceLayout->vertexUniformBufferCount = vertexShader->numUniformBuffers; 4042 4043 pipelineResourceLayout->fragmentSamplerCount = fragmentShader->numSamplers; 4044 pipelineResourceLayout->fragmentStorageTextureCount = fragmentShader->numStorageTextures; 4045 pipelineResourceLayout->fragmentStorageBufferCount = fragmentShader->numStorageBuffers; 4046 pipelineResourceLayout->fragmentUniformBufferCount = fragmentShader->numUniformBuffers; 4047 4048 // Create the pipeline layout 4049 4050 pipelineLayoutCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; 4051 pipelineLayoutCreateInfo.pNext = NULL; 4052 pipelineLayoutCreateInfo.flags = 0; 4053 pipelineLayoutCreateInfo.setLayoutCount = 4; 4054 pipelineLayoutCreateInfo.pSetLayouts = descriptorSetLayouts; 4055 pipelineLayoutCreateInfo.pushConstantRangeCount = 0; 4056 pipelineLayoutCreateInfo.pPushConstantRanges = NULL; 4057 4058 vulkanResult = renderer->vkCreatePipelineLayout( 4059 renderer->logicalDevice, 4060 &pipelineLayoutCreateInfo, 4061 NULL, 4062 &pipelineResourceLayout->pipelineLayout); 4063 4064 if (vulkanResult != VK_SUCCESS) { 4065 VULKAN_INTERNAL_DestroyGraphicsPipelineResourceLayout(renderer, pipelineResourceLayout); 4066 SDL_UnlockMutex(renderer->graphicsPipelineLayoutFetchLock); 4067 CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkCreatePipelineLayout, NULL); 4068 } 4069 4070 GraphicsPipelineResourceLayoutHashTableKey *allocedKey = SDL_malloc(sizeof(GraphicsPipelineResourceLayoutHashTableKey)); 4071 SDL_memcpy(allocedKey, &key, sizeof(GraphicsPipelineResourceLayoutHashTableKey)); 4072 4073 SDL_InsertIntoHashTable( 4074 renderer->graphicsPipelineResourceLayoutHashTable, 4075 (const void *)allocedKey, 4076 (const void *)pipelineResourceLayout, true); 4077 4078 SDL_UnlockMutex(renderer->graphicsPipelineLayoutFetchLock); 4079 return pipelineResourceLayout; 4080} 4081 4082static VulkanComputePipelineResourceLayout *VULKAN_INTERNAL_FetchComputePipelineResourceLayout( 4083 VulkanRenderer *renderer, 4084 const SDL_GPUComputePipelineCreateInfo *createinfo) 4085{ 4086 ComputePipelineResourceLayoutHashTableKey key; 4087 SDL_zero(key); 4088 VulkanComputePipelineResourceLayout *pipelineResourceLayout = NULL; 4089 4090 key.samplerCount = createinfo->num_samplers; 4091 key.readonlyStorageTextureCount = createinfo->num_readonly_storage_textures; 4092 key.readonlyStorageBufferCount = createinfo->num_readonly_storage_buffers; 4093 key.readWriteStorageTextureCount = createinfo->num_readwrite_storage_textures; 4094 key.readWriteStorageBufferCount = createinfo->num_readwrite_storage_buffers; 4095 key.uniformBufferCount = createinfo->num_uniform_buffers; 4096 4097 SDL_LockMutex(renderer->computePipelineLayoutFetchLock); 4098 4099 if (SDL_FindInHashTable( 4100 renderer->computePipelineResourceLayoutHashTable, 4101 (const void *)&key, 4102 (const void **)&pipelineResourceLayout)) { 4103 SDL_UnlockMutex(renderer->computePipelineLayoutFetchLock); 4104 return pipelineResourceLayout; 4105 } 4106 4107 VkDescriptorSetLayout descriptorSetLayouts[3]; 4108 VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo; 4109 VkResult vulkanResult; 4110 4111 pipelineResourceLayout = SDL_calloc(1, sizeof(VulkanComputePipelineResourceLayout)); 4112 4113 pipelineResourceLayout->descriptorSetLayouts[0] = VULKAN_INTERNAL_FetchDescriptorSetLayout( 4114 renderer, 4115 VK_SHADER_STAGE_COMPUTE_BIT, 4116 createinfo->num_samplers, 4117 createinfo->num_readonly_storage_textures, 4118 createinfo->num_readonly_storage_buffers, 4119 0, 4120 0, 4121 0); 4122 4123 pipelineResourceLayout->descriptorSetLayouts[1] = VULKAN_INTERNAL_FetchDescriptorSetLayout( 4124 renderer, 4125 VK_SHADER_STAGE_COMPUTE_BIT, 4126 0, 4127 0, 4128 0, 4129 createinfo->num_readwrite_storage_textures, 4130 createinfo->num_readwrite_storage_buffers, 4131 0); 4132 4133 pipelineResourceLayout->descriptorSetLayouts[2] = VULKAN_INTERNAL_FetchDescriptorSetLayout( 4134 renderer, 4135 VK_SHADER_STAGE_COMPUTE_BIT, 4136 0, 4137 0, 4138 0, 4139 0, 4140 0, 4141 createinfo->num_uniform_buffers); 4142 4143 descriptorSetLayouts[0] = pipelineResourceLayout->descriptorSetLayouts[0]->descriptorSetLayout; 4144 descriptorSetLayouts[1] = pipelineResourceLayout->descriptorSetLayouts[1]->descriptorSetLayout; 4145 descriptorSetLayouts[2] = pipelineResourceLayout->descriptorSetLayouts[2]->descriptorSetLayout; 4146 4147 pipelineResourceLayout->numSamplers = createinfo->num_samplers; 4148 pipelineResourceLayout->numReadonlyStorageTextures = createinfo->num_readonly_storage_textures; 4149 pipelineResourceLayout->numReadonlyStorageBuffers = createinfo->num_readonly_storage_buffers; 4150 pipelineResourceLayout->numReadWriteStorageTextures = createinfo->num_readwrite_storage_textures; 4151 pipelineResourceLayout->numReadWriteStorageBuffers = createinfo->num_readwrite_storage_buffers; 4152 pipelineResourceLayout->numUniformBuffers = createinfo->num_uniform_buffers; 4153 4154 // Create the pipeline layout 4155 4156 pipelineLayoutCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; 4157 pipelineLayoutCreateInfo.pNext = NULL; 4158 pipelineLayoutCreateInfo.flags = 0; 4159 pipelineLayoutCreateInfo.setLayoutCount = 3; 4160 pipelineLayoutCreateInfo.pSetLayouts = descriptorSetLayouts; 4161 pipelineLayoutCreateInfo.pushConstantRangeCount = 0; 4162 pipelineLayoutCreateInfo.pPushConstantRanges = NULL; 4163 4164 vulkanResult = renderer->vkCreatePipelineLayout( 4165 renderer->logicalDevice, 4166 &pipelineLayoutCreateInfo, 4167 NULL, 4168 &pipelineResourceLayout->pipelineLayout); 4169 4170 if (vulkanResult != VK_SUCCESS) { 4171 VULKAN_INTERNAL_DestroyComputePipelineResourceLayout(renderer, pipelineResourceLayout); 4172 SDL_UnlockMutex(renderer->computePipelineLayoutFetchLock); 4173 CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkCreatePipelineLayout, NULL); 4174 } 4175 4176 ComputePipelineResourceLayoutHashTableKey *allocedKey = SDL_malloc(sizeof(ComputePipelineResourceLayoutHashTableKey)); 4177 SDL_memcpy(allocedKey, &key, sizeof(ComputePipelineResourceLayoutHashTableKey)); 4178 4179 SDL_InsertIntoHashTable( 4180 renderer->computePipelineResourceLayoutHashTable, 4181 (const void *)allocedKey, 4182 (const void *)pipelineResourceLayout, true); 4183 4184 SDL_UnlockMutex(renderer->computePipelineLayoutFetchLock); 4185 return pipelineResourceLayout; 4186} 4187 4188// Data Buffer 4189 4190static VulkanBuffer *VULKAN_INTERNAL_CreateBuffer( 4191 VulkanRenderer *renderer, 4192 VkDeviceSize size, 4193 SDL_GPUBufferUsageFlags usageFlags, 4194 VulkanBufferType type, 4195 bool dedicated, 4196 const char *debugName) 4197{ 4198 VulkanBuffer *buffer; 4199 VkResult vulkanResult; 4200 VkBufferCreateInfo createinfo; 4201 VkBufferUsageFlags vulkanUsageFlags = 0; 4202 Uint8 bindResult; 4203 4204 if (usageFlags & SDL_GPU_BUFFERUSAGE_VERTEX) { 4205 vulkanUsageFlags |= VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; 4206 } 4207 4208 if (usageFlags & SDL_GPU_BUFFERUSAGE_INDEX) { 4209 vulkanUsageFlags |= VK_BUFFER_USAGE_INDEX_BUFFER_BIT; 4210 } 4211 4212 if (usageFlags & (SDL_GPU_BUFFERUSAGE_GRAPHICS_STORAGE_READ | 4213 SDL_GPU_BUFFERUSAGE_COMPUTE_STORAGE_READ | 4214 SDL_GPU_BUFFERUSAGE_COMPUTE_STORAGE_WRITE)) { 4215 vulkanUsageFlags |= VK_BUFFER_USAGE_STORAGE_BUFFER_BIT; 4216 } 4217 4218 if (usageFlags & SDL_GPU_BUFFERUSAGE_INDIRECT) { 4219 vulkanUsageFlags |= VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT; 4220 } 4221 4222 if (type == VULKAN_BUFFER_TYPE_UNIFORM) { 4223 vulkanUsageFlags |= VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT; 4224 } else { 4225 // GPU buffers need transfer bits for defrag, transfer buffers need them for transfers 4226 vulkanUsageFlags |= VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT; 4227 } 4228 4229 buffer = SDL_calloc(1, sizeof(VulkanBuffer)); 4230 4231 buffer->size = size; 4232 buffer->usage = usageFlags; 4233 buffer->type = type; 4234 buffer->markedForDestroy = false; 4235 buffer->transitioned = false; 4236 4237 createinfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; 4238 createinfo.pNext = NULL; 4239 createinfo.flags = 0; 4240 createinfo.size = size; 4241 createinfo.usage = vulkanUsageFlags; 4242 createinfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; 4243 createinfo.queueFamilyIndexCount = 1; 4244 createinfo.pQueueFamilyIndices = &renderer->queueFamilyIndex; 4245 4246 // Set transfer bits so we can defrag 4247 createinfo.usage |= VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT; 4248 4249 vulkanResult = renderer->vkCreateBuffer( 4250 renderer->logicalDevice, 4251 &createinfo, 4252 NULL, 4253 &buffer->buffer); 4254 4255 if (vulkanResult != VK_SUCCESS) { 4256 SDL_free(buffer); 4257 CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkCreateBuffer, NULL); 4258 } 4259 4260 bindResult = VULKAN_INTERNAL_BindMemoryForBuffer( 4261 renderer, 4262 buffer->buffer, 4263 buffer->size, 4264 buffer->type, 4265 dedicated, 4266 &buffer->usedRegion); 4267 4268 if (bindResult != 1) { 4269 renderer->vkDestroyBuffer( 4270 renderer->logicalDevice, 4271 buffer->buffer, 4272 NULL); 4273 SDL_free(buffer); 4274 SET_STRING_ERROR_AND_RETURN("Failed to bind memory for buffer!", NULL); 4275 } 4276 4277 buffer->usedRegion->vulkanBuffer = buffer; // lol 4278 4279 SDL_SetAtomicInt(&buffer->referenceCount, 0); 4280 4281 if (renderer->debugMode && renderer->supportsDebugUtils && debugName != NULL) { 4282 VkDebugUtilsObjectNameInfoEXT nameInfo; 4283 nameInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT; 4284 nameInfo.pNext = NULL; 4285 nameInfo.pObjectName = debugName; 4286 nameInfo.objectType = VK_OBJECT_TYPE_BUFFER; 4287 nameInfo.objectHandle = (uint64_t)buffer->buffer; 4288 4289 renderer->vkSetDebugUtilsObjectNameEXT( 4290 renderer->logicalDevice, 4291 &nameInfo); 4292 } 4293 4294 return buffer; 4295} 4296 4297static VulkanBufferContainer *VULKAN_INTERNAL_CreateBufferContainer( 4298 VulkanRenderer *renderer, 4299 VkDeviceSize size, 4300 SDL_GPUBufferUsageFlags usageFlags, 4301 VulkanBufferType type, 4302 bool dedicated, 4303 const char *debugName) 4304{ 4305 VulkanBufferContainer *bufferContainer; 4306 VulkanBuffer *buffer; 4307 4308 buffer = VULKAN_INTERNAL_CreateBuffer( 4309 renderer, 4310 size, 4311 usageFlags, 4312 type, 4313 dedicated, 4314 debugName); 4315 4316 if (buffer == NULL) { 4317 return NULL; 4318 } 4319 4320 bufferContainer = SDL_calloc(1, sizeof(VulkanBufferContainer)); 4321 4322 bufferContainer->activeBuffer = buffer; 4323 buffer->container = bufferContainer; 4324 buffer->containerIndex = 0; 4325 4326 bufferContainer->bufferCapacity = 1; 4327 bufferContainer->bufferCount = 1; 4328 bufferContainer->buffers = SDL_calloc(bufferContainer->bufferCapacity, sizeof(VulkanBuffer *)); 4329 bufferContainer->buffers[0] = bufferContainer->activeBuffer; 4330 bufferContainer->dedicated = dedicated; 4331 bufferContainer->debugName = NULL; 4332 4333 if (debugName != NULL) { 4334 bufferContainer->debugName = SDL_strdup(debugName); 4335 } 4336 4337 return bufferContainer; 4338} 4339 4340// Texture Subresource Utilities 4341 4342static Uint32 VULKAN_INTERNAL_GetTextureSubresourceIndex( 4343 Uint32 mipLevel, 4344 Uint32 layer, 4345 Uint32 numLevels) 4346{ 4347 return mipLevel + (layer * numLevels); 4348} 4349 4350static VulkanTextureSubresource *VULKAN_INTERNAL_FetchTextureSubresource( 4351 VulkanTextureContainer *textureContainer, 4352 Uint32 layer, 4353 Uint32 level) 4354{ 4355 Uint32 index = VULKAN_INTERNAL_GetTextureSubresourceIndex( 4356 level, 4357 layer, 4358 textureContainer->header.info.num_levels); 4359 4360 return &textureContainer->activeTexture->subresources[index]; 4361} 4362 4363static bool VULKAN_INTERNAL_CreateRenderTargetView( 4364 VulkanRenderer *renderer, 4365 VulkanTexture *texture, 4366 Uint32 layerOrDepth, 4367 Uint32 level, 4368 VkFormat format, 4369 VkComponentMapping swizzle, 4370 VkImageView *pView) 4371{ 4372 VkResult vulkanResult; 4373 VkImageViewCreateInfo imageViewCreateInfo; 4374 4375 // create framebuffer compatible views for RenderTarget 4376 imageViewCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; 4377 imageViewCreateInfo.pNext = NULL; 4378 imageViewCreateInfo.flags = 0; 4379 imageViewCreateInfo.image = texture->image; 4380 imageViewCreateInfo.format = format; 4381 imageViewCreateInfo.components = swizzle; 4382 imageViewCreateInfo.subresourceRange.aspectMask = texture->aspectFlags; 4383 imageViewCreateInfo.subresourceRange.baseMipLevel = level; 4384 imageViewCreateInfo.subresourceRange.levelCount = 1; 4385 imageViewCreateInfo.subresourceRange.baseArrayLayer = layerOrDepth; 4386 imageViewCreateInfo.subresourceRange.layerCount = 1; 4387 imageViewCreateInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; 4388 4389 vulkanResult = renderer->vkCreateImageView( 4390 renderer->logicalDevice, 4391 &imageViewCreateInfo, 4392 NULL, 4393 pView); 4394 4395 if (vulkanResult != VK_SUCCESS) { 4396 *pView = (VkImageView)VK_NULL_HANDLE; 4397 CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkCreateImageView, false); 4398 } 4399 4400 return true; 4401} 4402 4403static bool VULKAN_INTERNAL_CreateSubresourceView( 4404 VulkanRenderer *renderer, 4405 const SDL_GPUTextureCreateInfo *createinfo, 4406 VulkanTexture *texture, 4407 Uint32 layer, 4408 Uint32 level, 4409 VkComponentMapping swizzle, 4410 VkImageView *pView) 4411{ 4412 VkResult vulkanResult; 4413 VkImageViewCreateInfo imageViewCreateInfo; 4414 4415 // create framebuffer compatible views for RenderTarget 4416 imageViewCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; 4417 imageViewCreateInfo.pNext = NULL; 4418 imageViewCreateInfo.flags = 0; 4419 imageViewCreateInfo.image = texture->image; 4420 imageViewCreateInfo.format = SDLToVK_TextureFormat[createinfo->format]; 4421 imageViewCreateInfo.components = swizzle; 4422 imageViewCreateInfo.subresourceRange.aspectMask = texture->aspectFlags; 4423 imageViewCreateInfo.subresourceRange.baseMipLevel = level; 4424 imageViewCreateInfo.subresourceRange.levelCount = 1; 4425 imageViewCreateInfo.subresourceRange.baseArrayLayer = layer; 4426 imageViewCreateInfo.subresourceRange.layerCount = 1; 4427 imageViewCreateInfo.viewType = (createinfo->type == SDL_GPU_TEXTURETYPE_3D) ? VK_IMAGE_VIEW_TYPE_3D : VK_IMAGE_VIEW_TYPE_2D; 4428 4429 vulkanResult = renderer->vkCreateImageView( 4430 renderer->logicalDevice, 4431 &imageViewCreateInfo, 4432 NULL, 4433 pView); 4434 4435 if (vulkanResult != VK_SUCCESS) { 4436 *pView = (VkImageView)VK_NULL_HANDLE; 4437 CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkCreateImageView, false); 4438 } 4439 4440 return true; 4441} 4442 4443// Swapchain 4444 4445static bool VULKAN_INTERNAL_QuerySwapchainSupport( 4446 VulkanRenderer *renderer, 4447 VkPhysicalDevice physicalDevice, 4448 VkSurfaceKHR surface, 4449 SwapchainSupportDetails *outputDetails) 4450{ 4451 VkResult result; 4452 VkBool32 supportsPresent; 4453 4454 renderer->vkGetPhysicalDeviceSurfaceSupportKHR( 4455 physicalDevice, 4456 renderer->queueFamilyIndex, 4457 surface, 4458 &supportsPresent); 4459 4460 // Initialize these in case anything fails 4461 outputDetails->formats = NULL; 4462 outputDetails->formatsLength = 0; 4463 outputDetails->presentModes = NULL; 4464 outputDetails->presentModesLength = 0; 4465 4466 if (!supportsPresent) { 4467 SET_STRING_ERROR_AND_RETURN("This surface does not support presenting!", false); 4468 } 4469 4470 // Run the device surface queries 4471 result = renderer->vkGetPhysicalDeviceSurfaceCapabilitiesKHR( 4472 physicalDevice, 4473 surface, 4474 &outputDetails->capabilities); 4475 CHECK_VULKAN_ERROR_AND_RETURN(result, vkGetPhysicalDeviceSurfaceCapabilitiesKHR, false); 4476 4477 if (!(outputDetails->capabilities.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR)) { 4478 SDL_LogWarn(SDL_LOG_CATEGORY_GPU, "Opaque presentation unsupported! Expect weird transparency bugs!"); 4479 } 4480 4481 result = renderer->vkGetPhysicalDeviceSurfaceFormatsKHR( 4482 physicalDevice, 4483 surface, 4484 &outputDetails->formatsLength, 4485 NULL); 4486 if (result != VK_SUCCESS) { 4487 // Make sure the driver didn't mess up this value. 4488 outputDetails->formatsLength = 0; 4489 CHECK_VULKAN_ERROR_AND_RETURN(result, vkGetPhysicalDeviceSurfaceFormatsKHR, false); 4490 } 4491 result = renderer->vkGetPhysicalDeviceSurfacePresentModesKHR( 4492 physicalDevice, 4493 surface, 4494 &outputDetails->presentModesLength, 4495 NULL); 4496 if (result != VK_SUCCESS) { 4497 // Make sure the driver didn't mess up this value. 4498 outputDetails->presentModesLength = 0; 4499 // Reset this one, too. 4500 outputDetails->formatsLength = 0; 4501 CHECK_VULKAN_ERROR_AND_RETURN(result, vkGetPhysicalDeviceSurfacePresentModesKHR, false); 4502 } 4503 4504 // Generate the arrays, if applicable 4505 4506 if (outputDetails->formatsLength != 0) { 4507 outputDetails->formats = (VkSurfaceFormatKHR *)SDL_malloc( 4508 sizeof(VkSurfaceFormatKHR) * outputDetails->formatsLength); 4509 4510 if (!outputDetails->formats) { // OOM 4511 outputDetails->formatsLength = 0; 4512 outputDetails->presentModesLength = 0; 4513 return false; 4514 } 4515 4516 result = renderer->vkGetPhysicalDeviceSurfaceFormatsKHR( 4517 physicalDevice, 4518 surface, 4519 &outputDetails->formatsLength, 4520 outputDetails->formats); 4521 if (result != VK_SUCCESS) { 4522 SDL_free(outputDetails->formats); 4523 outputDetails->formats = NULL; 4524 outputDetails->formatsLength = 0; 4525 outputDetails->presentModesLength = 0; 4526 CHECK_VULKAN_ERROR_AND_RETURN(result, vkGetPhysicalDeviceSurfaceFormatsKHR, false); 4527 } 4528 } 4529 4530 if (outputDetails->presentModesLength != 0) { 4531 outputDetails->presentModes = (VkPresentModeKHR *)SDL_malloc( 4532 sizeof(VkPresentModeKHR) * outputDetails->presentModesLength); 4533 4534 if (!outputDetails->presentModes) { // OOM 4535 SDL_free(outputDetails->formats); 4536 outputDetails->formats = NULL; 4537 outputDetails->formatsLength = 0; 4538 outputDetails->presentModesLength = 0; 4539 return false; 4540 } 4541 4542 result = renderer->vkGetPhysicalDeviceSurfacePresentModesKHR( 4543 physicalDevice, 4544 surface, 4545 &outputDetails->presentModesLength, 4546 outputDetails->presentModes); 4547 if (result != VK_SUCCESS) { 4548 SDL_free(outputDetails->formats); 4549 SDL_free(outputDetails->presentModes); 4550 outputDetails->formats = NULL; 4551 outputDetails->presentModes = NULL; 4552 outputDetails->formatsLength = 0; 4553 outputDetails->presentModesLength = 0; 4554 CHECK_VULKAN_ERROR_AND_RETURN(result, vkGetPhysicalDeviceSurfacePresentModesKHR, false); 4555 } 4556 } 4557 4558 /* If we made it here, all the queries were successful. This does NOT 4559 * necessarily mean there are any supported formats or present modes! 4560 */ 4561 return true; 4562} 4563 4564static bool VULKAN_INTERNAL_VerifySwapSurfaceFormat( 4565 VkFormat desiredFormat, 4566 VkColorSpaceKHR desiredColorSpace, 4567 VkSurfaceFormatKHR *availableFormats, 4568 Uint32 availableFormatsLength) 4569{ 4570 Uint32 i; 4571 for (i = 0; i < availableFormatsLength; i += 1) { 4572 if (availableFormats[i].format == desiredFormat && 4573 availableFormats[i].colorSpace == desiredColorSpace) { 4574 return true; 4575 } 4576 } 4577 return false; 4578} 4579 4580static bool VULKAN_INTERNAL_VerifySwapPresentMode( 4581 VkPresentModeKHR presentMode, 4582 const VkPresentModeKHR *availablePresentModes, 4583 Uint32 availablePresentModesLength) 4584{ 4585 Uint32 i; 4586 for (i = 0; i < availablePresentModesLength; i += 1) { 4587 if (availablePresentModes[i] == presentMode) { 4588 return true; 4589 } 4590 } 4591 return false; 4592} 4593 4594/* It would be nice if VULKAN_INTERNAL_CreateSwapchain could return a bool. 4595 * Unfortunately, some Win32 NVIDIA drivers are stupid 4596 * and will return surface extents of (0, 0) 4597 * in certain edge cases, and the swapchain extents are not allowed to be 0. 4598 * In this case, the client probably still wants to claim the window 4599 * or recreate the swapchain, so we should return 2 to indicate retry. 4600 * -cosmonaut 4601 */ 4602#define VULKAN_INTERNAL_TRY_AGAIN 2 4603 4604static Uint32 VULKAN_INTERNAL_CreateSwapchain( 4605 VulkanRenderer *renderer, 4606 WindowData *windowData) 4607{ 4608 VkResult vulkanResult; 4609 VkSwapchainCreateInfoKHR swapchainCreateInfo; 4610 VkImage *swapchainImages; 4611 VkSemaphoreCreateInfo semaphoreCreateInfo; 4612 SwapchainSupportDetails swapchainSupportDetails; 4613 bool hasValidSwapchainComposition, hasValidPresentMode; 4614 VkCompositeAlphaFlagsKHR compositeAlphaFlag = 0; 4615 Uint32 i; 4616 4617 windowData->frameCounter = 0; 4618 4619 if (!VULKAN_INTERNAL_QuerySwapchainSupport( 4620 renderer, 4621 renderer->physicalDevice, 4622 windowData->surface, 4623 &swapchainSupportDetails)) { 4624 return false; 4625 } 4626 4627 // Verify that we can use the requested composition and present mode 4628 windowData->format = SwapchainCompositionToFormat[windowData->swapchainComposition]; 4629 windowData->colorSpace = SwapchainCompositionToColorSpace[windowData->swapchainComposition]; 4630 windowData->swapchainSwizzle = SwapchainCompositionSwizzle[windowData->swapchainComposition]; 4631 windowData->usingFallbackFormat = false; 4632 4633 hasValidSwapchainComposition = VULKAN_INTERNAL_VerifySwapSurfaceFormat( 4634 windowData->format, 4635 windowData->colorSpace, 4636 swapchainSupportDetails.formats, 4637 swapchainSupportDetails.formatsLength); 4638 4639 if (!hasValidSwapchainComposition) { 4640 // Let's try again with the fallback format... 4641 windowData->format = SwapchainCompositionToFallbackFormat[windowData->swapchainComposition]; 4642 windowData->usingFallbackFormat = true; 4643 hasValidSwapchainComposition = VULKAN_INTERNAL_VerifySwapSurfaceFormat( 4644 windowData->format, 4645 windowData->colorSpace, 4646 swapchainSupportDetails.formats, 4647 swapchainSupportDetails.formatsLength); 4648 } 4649 4650 hasValidPresentMode = VULKAN_INTERNAL_VerifySwapPresentMode( 4651 SDLToVK_PresentMode[windowData->presentMode], 4652 swapchainSupportDetails.presentModes, 4653 swapchainSupportDetails.presentModesLength); 4654 4655 if (!hasValidSwapchainComposition || !hasValidPresentMode) { 4656 if (swapchainSupportDetails.formatsLength > 0) { 4657 SDL_free(swapchainSupportDetails.formats); 4658 } 4659 4660 if (swapchainSupportDetails.presentModesLength > 0) { 4661 SDL_free(swapchainSupportDetails.presentModes); 4662 } 4663 4664 if (!hasValidSwapchainComposition) { 4665 SET_STRING_ERROR_AND_RETURN("Device does not support requested swapchain composition!", false); 4666 } 4667 if (!hasValidPresentMode) { 4668 SET_STRING_ERROR_AND_RETURN("Device does not support requested present_mode!", false); 4669 } 4670 return false; 4671 } 4672 4673 // NVIDIA + Win32 can return 0 extent when the window is minimized. Try again! 4674 if (swapchainSupportDetails.capabilities.currentExtent.width == 0 || 4675 swapchainSupportDetails.capabilities.currentExtent.height == 0) { 4676 if (swapchainSupportDetails.formatsLength > 0) { 4677 SDL_free(swapchainSupportDetails.formats); 4678 } 4679 if (swapchainSupportDetails.presentModesLength > 0) { 4680 SDL_free(swapchainSupportDetails.presentModes); 4681 } 4682 return VULKAN_INTERNAL_TRY_AGAIN; 4683 } 4684 4685 Uint32 requestedImageCount = renderer->allowedFramesInFlight; 4686 4687#ifdef SDL_PLATFORM_APPLE 4688 windowData->width = swapchainSupportDetails.capabilities.currentExtent.width; 4689 windowData->height = swapchainSupportDetails.capabilities.currentExtent.height; 4690#else 4691 windowData->width = SDL_clamp( 4692 windowData->swapchainCreateWidth, 4693 swapchainSupportDetails.capabilities.minImageExtent.width, 4694 swapchainSupportDetails.capabilities.maxImageExtent.width); 4695 windowData->height = SDL_clamp(windowData->swapchainCreateHeight, 4696 swapchainSupportDetails.capabilities.minImageExtent.height, 4697 swapchainSupportDetails.capabilities.maxImageExtent.height); 4698#endif 4699 4700 if (swapchainSupportDetails.capabilities.maxImageCount > 0 && 4701 requestedImageCount > swapchainSupportDetails.capabilities.maxImageCount) { 4702 requestedImageCount = swapchainSupportDetails.capabilities.maxImageCount; 4703 } 4704 4705 if (requestedImageCount < swapchainSupportDetails.capabilities.minImageCount) { 4706 requestedImageCount = swapchainSupportDetails.capabilities.minImageCount; 4707 } 4708 4709 if (windowData->presentMode == SDL_GPU_PRESENTMODE_MAILBOX) { 4710 /* Required for proper triple-buffering. 4711 * Note that this is below the above maxImageCount check! 4712 * If the driver advertises MAILBOX but does not support 3 swap 4713 * images, it's not real mailbox support, so let it fail hard. 4714 * -flibit 4715 */ 4716 requestedImageCount = SDL_max(requestedImageCount, 3); 4717 } 4718 4719 // Default to opaque, if available, followed by inherit, and overwrite with a value that supports transparency, if necessary. 4720 if (swapchainSupportDetails.capabilities.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR) { 4721 compositeAlphaFlag = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; 4722 } else if (swapchainSupportDetails.capabilities.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR) { 4723 compositeAlphaFlag = VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR; 4724 } 4725 4726 if ((windowData->window->flags & SDL_WINDOW_TRANSPARENT) || !compositeAlphaFlag) { 4727 if (swapchainSupportDetails.capabilities.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR) { 4728 compositeAlphaFlag = VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR; 4729 } else if (swapchainSupportDetails.capabilities.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR) { 4730 compositeAlphaFlag = VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR; 4731 } else if (swapchainSupportDetails.capabilities.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR) { 4732 compositeAlphaFlag = VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR; 4733 } else { 4734 SDL_LogWarn(SDL_LOG_CATEGORY_GPU, "SDL_WINDOW_TRANSPARENT flag set, but no suitable swapchain composite alpha value supported!"); 4735 } 4736 } 4737 4738 swapchainCreateInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; 4739 swapchainCreateInfo.pNext = NULL; 4740 swapchainCreateInfo.flags = 0; 4741 swapchainCreateInfo.surface = windowData->surface; 4742 swapchainCreateInfo.minImageCount = requestedImageCount; 4743 swapchainCreateInfo.imageFormat = windowData->format; 4744 swapchainCreateInfo.imageColorSpace = windowData->colorSpace; 4745 swapchainCreateInfo.imageExtent.width = windowData->width; 4746 swapchainCreateInfo.imageExtent.height = windowData->height; 4747 swapchainCreateInfo.imageArrayLayers = 1; 4748 swapchainCreateInfo.imageUsage = 4749 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | 4750 VK_IMAGE_USAGE_TRANSFER_DST_BIT; 4751 swapchainCreateInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; 4752 swapchainCreateInfo.queueFamilyIndexCount = 0; 4753 swapchainCreateInfo.pQueueFamilyIndices = NULL; 4754#ifdef SDL_PLATFORM_ANDROID 4755 swapchainCreateInfo.preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; 4756#else 4757 swapchainCreateInfo.preTransform = swapchainSupportDetails.capabilities.currentTransform; 4758#endif 4759 swapchainCreateInfo.compositeAlpha = compositeAlphaFlag; 4760 swapchainCreateInfo.presentMode = SDLToVK_PresentMode[windowData->presentMode]; 4761 swapchainCreateInfo.clipped = VK_TRUE; 4762 // The old swapchain could belong to a surface that no longer exists due to app switching. 4763 swapchainCreateInfo.oldSwapchain = windowData->needsSurfaceRecreate ? (VkSwapchainKHR)0 : windowData->swapchain; 4764 vulkanResult = renderer->vkCreateSwapchainKHR( 4765 renderer->logicalDevice, 4766 &swapchainCreateInfo, 4767 NULL, 4768 &windowData->swapchain); 4769 4770 if (swapchainCreateInfo.oldSwapchain != VK_NULL_HANDLE) { 4771 renderer->vkDestroySwapchainKHR(renderer->logicalDevice, swapchainCreateInfo.oldSwapchain, NULL); 4772 } 4773 4774 if (swapchainSupportDetails.formatsLength > 0) { 4775 SDL_free(swapchainSupportDetails.formats); 4776 } 4777 if (swapchainSupportDetails.presentModesLength > 0) { 4778 SDL_free(swapchainSupportDetails.presentModes); 4779 } 4780 4781 if (vulkanResult != VK_SUCCESS) { 4782 windowData->swapchain = VK_NULL_HANDLE; 4783 CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkCreateSwapchainKHR, false); 4784 } 4785 4786 vulkanResult = renderer->vkGetSwapchainImagesKHR( 4787 renderer->logicalDevice, 4788 windowData->swapchain, 4789 &windowData->imageCount, 4790 NULL); 4791 CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkGetSwapchainImagesKHR, false); 4792 4793 windowData->textureContainers = SDL_malloc( 4794 sizeof(VulkanTextureContainer) * windowData->imageCount); 4795 4796 if (!windowData->textureContainers) { // OOM 4797 renderer->vkDestroySwapchainKHR( 4798 renderer->logicalDevice, 4799 windowData->swapchain, 4800 NULL); 4801 windowData->swapchain = VK_NULL_HANDLE; 4802 return false; 4803 } 4804 4805 swapchainImages = SDL_stack_alloc(VkImage, windowData->imageCount); 4806 4807 vulkanResult = renderer->vkGetSwapchainImagesKHR( 4808 renderer->logicalDevice, 4809 windowData->swapchain, 4810 &windowData->imageCount, 4811 swapchainImages); 4812 CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkGetSwapchainImagesKHR, false); 4813 4814 for (i = 0; i < windowData->imageCount; i += 1) { 4815 4816 // Initialize dummy container 4817 SDL_zero(windowData->textureContainers[i]); 4818 windowData->textureContainers[i].canBeCycled = false; 4819 windowData->textureContainers[i].header.info.width = windowData->width; 4820 windowData->textureContainers[i].header.info.height = windowData->height; 4821 windowData->textureContainers[i].header.info.layer_count_or_depth = 1; 4822 windowData->textureContainers[i].header.info.format = SwapchainCompositionToSDLFormat( 4823 windowData->swapchainComposition, 4824 windowData->usingFallbackFormat); 4825 windowData->textureContainers[i].header.info.type = SDL_GPU_TEXTURETYPE_2D; 4826 windowData->textureContainers[i].header.info.num_levels = 1; 4827 windowData->textureContainers[i].header.info.sample_count = SDL_GPU_SAMPLECOUNT_1; 4828 windowData->textureContainers[i].header.info.usage = SDL_GPU_TEXTUREUSAGE_COLOR_TARGET; 4829 4830 windowData->textureContainers[i].activeTexture = SDL_malloc(sizeof(VulkanTexture)); 4831 windowData->textureContainers[i].activeTexture->image = swapchainImages[i]; 4832 4833 // Swapchain memory is managed by the driver 4834 windowData->textureContainers[i].activeTexture->usedRegion = NULL; 4835 4836 windowData->textureContainers[i].activeTexture->swizzle = windowData->swapchainSwizzle; 4837 windowData->textureContainers[i].activeTexture->aspectFlags = VK_IMAGE_ASPECT_COLOR_BIT; 4838 windowData->textureContainers[i].activeTexture->depth = 1; 4839 windowData->textureContainers[i].activeTexture->usage = SDL_GPU_TEXTUREUSAGE_COLOR_TARGET; 4840 windowData->textureContainers[i].activeTexture->container = &windowData->textureContainers[i]; 4841 SDL_SetAtomicInt(&windowData->textureContainers[i].activeTexture->referenceCount, 0); 4842 4843 // Create slice 4844 windowData->textureContainers[i].activeTexture->subresourceCount = 1; 4845 windowData->textureContainers[i].activeTexture->subresources = SDL_malloc(sizeof(VulkanTextureSubresource)); 4846 windowData->textureContainers[i].activeTexture->subresources[0].parent = windowData->textureContainers[i].activeTexture; 4847 windowData->textureContainers[i].activeTexture->subresources[0].layer = 0; 4848 windowData->textureContainers[i].activeTexture->subresources[0].level = 0; 4849 windowData->textureContainers[i].activeTexture->subresources[0].renderTargetViews = SDL_malloc(sizeof(VkImageView)); 4850 if (!VULKAN_INTERNAL_CreateRenderTargetView( 4851 renderer, 4852 windowData->textureContainers[i].activeTexture, 4853 0, 4854 0, 4855 windowData->format, 4856 windowData->swapchainSwizzle, 4857 &windowData->textureContainers[i].activeTexture->subresources[0].renderTargetViews[0])) { 4858 renderer->vkDestroySwapchainKHR( 4859 renderer->logicalDevice, 4860 windowData->swapchain, 4861 NULL); 4862 windowData->swapchain = VK_NULL_HANDLE; 4863 return false; 4864 } 4865 } 4866 4867 SDL_stack_free(swapchainImages); 4868 4869 semaphoreCreateInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; 4870 semaphoreCreateInfo.pNext = NULL; 4871 semaphoreCreateInfo.flags = 0; 4872 4873 for (i = 0; i < MAX_FRAMES_IN_FLIGHT; i += 1) { 4874 vulkanResult = renderer->vkCreateSemaphore( 4875 renderer->logicalDevice, 4876 &semaphoreCreateInfo, 4877 NULL, 4878 &windowData->imageAvailableSemaphore[i]); 4879 4880 if (vulkanResult != VK_SUCCESS) { 4881 renderer->vkDestroySwapchainKHR( 4882 renderer->logicalDevice, 4883 windowData->swapchain, 4884 NULL); 4885 windowData->swapchain = VK_NULL_HANDLE; 4886 CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkCreateSemaphore, false); 4887 } 4888 4889 windowData->inFlightFences[i] = NULL; 4890 } 4891 4892 windowData->renderFinishedSemaphore = SDL_malloc( 4893 sizeof(VkSemaphore) * windowData->imageCount); 4894 for (i = 0; i < windowData->imageCount; i += 1) { 4895 vulkanResult = renderer->vkCreateSemaphore( 4896 renderer->logicalDevice, 4897 &semaphoreCreateInfo, 4898 NULL, 4899 &windowData->renderFinishedSemaphore[i]); 4900 4901 if (vulkanResult != VK_SUCCESS) { 4902 renderer->vkDestroySwapchainKHR( 4903 renderer->logicalDevice, 4904 windowData->swapchain, 4905 NULL); 4906 windowData->swapchain = VK_NULL_HANDLE; 4907 CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkCreateSemaphore, false); 4908 } 4909 } 4910 4911 windowData->needsSwapchainRecreate = false; 4912 return true; 4913} 4914 4915// Command Buffers 4916 4917static bool VULKAN_INTERNAL_BeginCommandBuffer( 4918 VulkanRenderer *renderer, 4919 VulkanCommandBuffer *commandBuffer) 4920{ 4921 VkCommandBufferBeginInfo beginInfo; 4922 VkResult result; 4923 4924 beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; 4925 beginInfo.pNext = NULL; 4926 beginInfo.flags = 0; 4927 beginInfo.pInheritanceInfo = NULL; 4928 beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; 4929 4930 result = renderer->vkBeginCommandBuffer( 4931 commandBuffer->commandBuffer, 4932 &beginInfo); 4933 4934 CHECK_VULKAN_ERROR_AND_RETURN(result, vkBeginCommandBuffer, false); 4935 4936 return true; 4937} 4938 4939static bool VULKAN_INTERNAL_EndCommandBuffer( 4940 VulkanRenderer *renderer, 4941 VulkanCommandBuffer *commandBuffer) 4942{ 4943 VkResult result = renderer->vkEndCommandBuffer( 4944 commandBuffer->commandBuffer); 4945 4946 CHECK_VULKAN_ERROR_AND_RETURN(result, vkEndCommandBuffer, false); 4947 4948 return true; 4949} 4950 4951static void VULKAN_DestroyDevice( 4952 SDL_GPUDevice *device) 4953{ 4954 VulkanRenderer *renderer = (VulkanRenderer *)device->driverData; 4955 VulkanMemorySubAllocator *allocator; 4956 4957 VULKAN_Wait(device->driverData); 4958 4959 for (Sint32 i = renderer->claimedWindowCount - 1; i >= 0; i -= 1) { 4960 VULKAN_ReleaseWindow(device->driverData, renderer->claimedWindows[i]->window); 4961 } 4962 4963 SDL_free(renderer->claimedWindows); 4964 4965 VULKAN_Wait(device->driverData); 4966 4967 SDL_free(renderer->submittedCommandBuffers); 4968 4969 for (Uint32 i = 0; i < renderer->uniformBufferPoolCount; i += 1) { 4970 VULKAN_INTERNAL_DestroyBuffer( 4971 renderer, 4972 renderer->uniformBufferPool[i]->buffer); 4973 SDL_free(renderer->uniformBufferPool[i]); 4974 } 4975 SDL_free(renderer->uniformBufferPool); 4976 4977 for (Uint32 i = 0; i < renderer->descriptorSetCachePoolCount; i += 1) { 4978 VULKAN_INTERNAL_DestroyDescriptorSetCache( 4979 renderer, 4980 renderer->descriptorSetCachePool[i]); 4981 } 4982 SDL_free(renderer->descriptorSetCachePool); 4983 4984 for (Uint32 i = 0; i < renderer->fencePool.availableFenceCount; i += 1) { 4985 renderer->vkDestroyFence( 4986 renderer->logicalDevice, 4987 renderer->fencePool.availableFences[i]->fence, 4988 NULL); 4989 4990 SDL_free(renderer->fencePool.availableFences[i]); 4991 } 4992 4993 SDL_free(renderer->fencePool.availableFences); 4994 SDL_DestroyMutex(renderer->fencePool.lock); 4995 4996 SDL_DestroyHashTable(renderer->commandPoolHashTable); 4997 SDL_DestroyHashTable(renderer->renderPassHashTable); 4998 SDL_DestroyHashTable(renderer->framebufferHashTable); 4999 SDL_DestroyHashTable(renderer->graphicsPipelineResourceLayoutHashTable); 5000 SDL_DestroyHashTable(renderer->computePipelineResourceLayoutHashTable); 5001 SDL_DestroyHashTable(renderer->descriptorSetLayoutHashTable); 5002 5003 for (Uint32 i = 0; i < VK_MAX_MEMORY_TYPES; i += 1) { 5004 allocator = &renderer->memoryAllocator->subAllocators[i]; 5005 5006 for (Sint32 j = allocator->allocationCount - 1; j >= 0; j -= 1) { 5007 for (Sint32 k = allocator->allocations[j]->usedRegionCount - 1; k >= 0; k -= 1) { 5008 VULKAN_INTERNAL_RemoveMemoryUsedRegion( 5009 renderer, 5010 allocator->allocations[j]->usedRegions[k]); 5011 } 5012 5013 VULKAN_INTERNAL_DeallocateMemory( 5014 renderer, 5015 allocator, 5016 j); 5017 } 5018 5019 SDL_free(renderer->memoryAllocator->subAllocators[i].allocations); 5020 5021 SDL_free(renderer->memoryAllocator->subAllocators[i].sortedFreeRegions); 5022 } 5023 5024 SDL_free(renderer->memoryAllocator); 5025 5026 SDL_free(renderer->texturesToDestroy); 5027 SDL_free(renderer->buffersToDestroy); 5028 SDL_free(renderer->graphicsPipelinesToDestroy); 5029 SDL_free(renderer->computePipelinesToDestroy); 5030 SDL_free(renderer->shadersToDestroy); 5031 SDL_free(renderer->samplersToDestroy); 5032 SDL_free(renderer->framebuffersToDestroy); 5033 SDL_free(renderer->allocationsToDefrag); 5034 5035 SDL_DestroyMutex(renderer->allocatorLock); 5036 SDL_DestroyMutex(renderer->disposeLock); 5037 SDL_DestroyMutex(renderer->submitLock); 5038 SDL_DestroyMutex(renderer->acquireCommandBufferLock); 5039 SDL_DestroyMutex(renderer->acquireUniformBufferLock); 5040 SDL_DestroyMutex(renderer->renderPassFetchLock); 5041 SDL_DestroyMutex(renderer->framebufferFetchLock); 5042 SDL_DestroyMutex(renderer->graphicsPipelineLayoutFetchLock); 5043 SDL_DestroyMutex(renderer->computePipelineLayoutFetchLock); 5044 SDL_DestroyMutex(renderer->descriptorSetLayoutFetchLock); 5045 SDL_DestroyMutex(renderer->windowLock); 5046 5047 renderer->vkDestroyDevice(renderer->logicalDevice, NULL); 5048 renderer->vkDestroyInstance(renderer->instance, NULL); 5049 5050 SDL_DestroyProperties(renderer->props); 5051 5052 SDL_free(renderer); 5053 SDL_free(device); 5054 SDL_Vulkan_UnloadLibrary(); 5055} 5056 5057static SDL_PropertiesID VULKAN_GetDeviceProperties( 5058 SDL_GPUDevice *device) 5059{ 5060 VulkanRenderer *renderer = (VulkanRenderer *)device->driverData; 5061 return renderer->props; 5062} 5063 5064static DescriptorSetCache *VULKAN_INTERNAL_AcquireDescriptorSetCache( 5065 VulkanRenderer *renderer) 5066{ 5067 DescriptorSetCache *cache; 5068 5069 if (renderer->descriptorSetCachePoolCount == 0) { 5070 cache = SDL_malloc(sizeof(DescriptorSetCache)); 5071 cache->poolCount = 0; 5072 cache->pools = NULL; 5073 } else { 5074 cache = renderer->descriptorSetCachePool[renderer->descriptorSetCachePoolCount - 1]; 5075 renderer->descriptorSetCachePoolCount -= 1; 5076 } 5077 5078 return cache; 5079} 5080 5081static void VULKAN_INTERNAL_ReturnDescriptorSetCacheToPool( 5082 VulkanRenderer *renderer, 5083 DescriptorSetCache *descriptorSetCache) 5084{ 5085 EXPAND_ARRAY_IF_NEEDED( 5086 renderer->descriptorSetCachePool, 5087 DescriptorSetCache *, 5088 renderer->descriptorSetCachePoolCount + 1, 5089 renderer->descriptorSetCachePoolCapacity, 5090 renderer->descriptorSetCachePoolCapacity * 2); 5091 5092 renderer->descriptorSetCachePool[renderer->descriptorSetCachePoolCount] = descriptorSetCache; 5093 renderer->descriptorSetCachePoolCount += 1; 5094 5095 for (Uint32 i = 0; i < descriptorSetCache->poolCount; i += 1) { 5096 descriptorSetCache->pools[i].descriptorSetIndex = 0; 5097 } 5098} 5099 5100static VkDescriptorSet VULKAN_INTERNAL_FetchDescriptorSet( 5101 VulkanRenderer *renderer, 5102 VulkanCommandBuffer *vulkanCommandBuffer, 5103 DescriptorSetLayout *descriptorSetLayout) 5104{ 5105 // Grow the pool to meet the descriptor set layout ID 5106 if (descriptorSetLayout->ID >= vulkanCommandBuffer->descriptorSetCache->poolCount) { 5107 vulkanCommandBuffer->descriptorSetCache->pools = SDL_realloc( 5108 vulkanCommandBuffer->descriptorSetCache->pools, 5109 sizeof(DescriptorSetPool) * (descriptorSetLayout->ID + 1)); 5110 5111 for (Uint32 i = vulkanCommandBuffer->descriptorSetCache->poolCount; i < descriptorSetLayout->ID + 1; i += 1) { 5112 SDL_zero(vulkanCommandBuffer->descriptorSetCache->pools[i]); 5113 } 5114 5115 vulkanCommandBuffer->descriptorSetCache->poolCount = descriptorSetLayout->ID + 1; 5116 } 5117 5118 DescriptorSetPool *pool = 5119 &vulkanCommandBuffer->descriptorSetCache->pools[descriptorSetLayout->ID]; 5120 5121 if (pool->descriptorSetIndex == pool->descriptorSetCount) { 5122 if (!VULKAN_INTERNAL_AllocateDescriptorsFromPool( 5123 renderer, 5124 descriptorSetLayout, 5125 pool)) { 5126 return VK_NULL_HANDLE; 5127 } 5128 } 5129 5130 VkDescriptorSet descriptorSet = pool->descriptorSets[pool->descriptorSetIndex]; 5131 pool->descriptorSetIndex += 1; 5132 5133 return descriptorSet; 5134} 5135 5136static void VULKAN_INTERNAL_BindGraphicsDescriptorSets( 5137 VulkanRenderer *renderer, 5138 VulkanCommandBuffer *commandBuffer) 5139{ 5140 VulkanGraphicsPipelineResourceLayout *resourceLayout; 5141 DescriptorSetLayout *descriptorSetLayout; 5142 VkWriteDescriptorSet writeDescriptorSets[ 5143 (MAX_TEXTURE_SAMPLERS_PER_STAGE + 5144 MAX_STORAGE_TEXTURES_PER_STAGE + 5145 MAX_STORAGE_BUFFERS_PER_STAGE + 5146 MAX_UNIFORM_BUFFERS_PER_STAGE) * 2]; 5147 VkDescriptorBufferInfo bufferInfos[MAX_STORAGE_BUFFERS_PER_STAGE * 2]; 5148 VkDescriptorImageInfo imageInfos[(MAX_TEXTURE_SAMPLERS_PER_STAGE + MAX_STORAGE_TEXTURES_PER_STAGE) * 2]; 5149 Uint32 dynamicOffsets[MAX_UNIFORM_BUFFERS_PER_STAGE * 2]; 5150 Uint32 writeCount = 0; 5151 Uint32 bufferInfoCount = 0; 5152 Uint32 imageInfoCount = 0; 5153 Uint32 dynamicOffsetCount = 0; 5154 5155 if ( 5156 !commandBuffer->needVertexBufferBind && 5157 !commandBuffer->needNewVertexResourceDescriptorSet && 5158 !commandBuffer->needNewVertexUniformDescriptorSet && 5159 !commandBuffer->needNewVertexUniformOffsets && 5160 !commandBuffer->needNewFragmentResourceDescriptorSet && 5161 !commandBuffer->needNewFragmentUniformDescriptorSet && 5162 !commandBuffer->needNewFragmentUniformOffsets 5163 ) { 5164 return; 5165 } 5166 5167 if (commandBuffer->needVertexBufferBind && commandBuffer->vertexBufferCount > 0) { 5168 renderer->vkCmdBindVertexBuffers( 5169 commandBuffer->commandBuffer, 5170 0, 5171 commandBuffer->vertexBufferCount, 5172 commandBuffer->vertexBuffers, 5173 commandBuffer->vertexBufferOffsets); 5174 5175 commandBuffer->needVertexBufferBind = false; 5176 } 5177 5178 resourceLayout = commandBuffer->currentGraphicsPipeline->resourceLayout; 5179 5180 if (commandBuffer->needNewVertexResourceDescriptorSet) { 5181 descriptorSetLayout = resourceLayout->descriptorSetLayouts[0]; 5182 5183 commandBuffer->vertexResourceDescriptorSet = VULKAN_INTERNAL_FetchDescriptorSet( 5184 renderer, 5185 commandBuffer, 5186 descriptorSetLayout); 5187 5188 for (Uint32 i = 0; i < resourceLayout->vertexSamplerCount; i += 1) { 5189 VkWriteDescriptorSet *currentWriteDescriptorSet = &writeDescriptorSets[writeCount]; 5190 5191 currentWriteDescriptorSet->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; 5192 currentWriteDescriptorSet->pNext = NULL; 5193 currentWriteDescriptorSet->descriptorCount = 1; 5194 currentWriteDescriptorSet->descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; 5195 currentWriteDescriptorSet->dstArrayElement = 0; 5196 currentWriteDescriptorSet->dstBinding = i; 5197 currentWriteDescriptorSet->dstSet = commandBuffer->vertexResourceDescriptorSet; 5198 currentWriteDescriptorSet->pTexelBufferView = NULL; 5199 currentWriteDescriptorSet->pBufferInfo = NULL; 5200 5201 imageInfos[imageInfoCount].sampler = commandBuffer->vertexSamplerBindings[i]; 5202 imageInfos[imageInfoCount].imageView = commandBuffer->vertexSamplerTextureViewBindings[i]; 5203 imageInfos[imageInfoCount].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; 5204 5205 currentWriteDescriptorSet->pImageInfo = &imageInfos[imageInfoCount]; 5206 5207 writeCount += 1; 5208 imageInfoCount += 1; 5209 } 5210 5211 for (Uint32 i = 0; i < resourceLayout->vertexStorageTextureCount; i += 1) { 5212 VkWriteDescriptorSet *currentWriteDescriptorSet = &writeDescriptorSets[writeCount]; 5213 5214 currentWriteDescriptorSet->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; 5215 currentWriteDescriptorSet->pNext = NULL; 5216 currentWriteDescriptorSet->descriptorCount = 1; 5217 currentWriteDescriptorSet->descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE; // Yes, we are declaring a storage image as a sampled image, because shaders are stupid. 5218 currentWriteDescriptorSet->dstArrayElement = 0; 5219 currentWriteDescriptorSet->dstBinding = resourceLayout->vertexSamplerCount + i; 5220 currentWriteDescriptorSet->dstSet = commandBuffer->vertexResourceDescriptorSet; 5221 currentWriteDescriptorSet->pTexelBufferView = NULL; 5222 currentWriteDescriptorSet->pBufferInfo = NULL; 5223 5224 imageInfos[imageInfoCount].sampler = VK_NULL_HANDLE; 5225 imageInfos[imageInfoCount].imageView = commandBuffer->vertexStorageTextureViewBindings[i]; 5226 imageInfos[imageInfoCount].imageLayout = VK_IMAGE_LAYOUT_GENERAL; 5227 5228 currentWriteDescriptorSet->pImageInfo = &imageInfos[imageInfoCount]; 5229 5230 writeCount += 1; 5231 imageInfoCount += 1; 5232 } 5233 5234 for (Uint32 i = 0; i < resourceLayout->vertexStorageBufferCount; i += 1) { 5235 VkWriteDescriptorSet *currentWriteDescriptorSet = &writeDescriptorSets[writeCount]; 5236 5237 currentWriteDescriptorSet->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; 5238 currentWriteDescriptorSet->pNext = NULL; 5239 currentWriteDescriptorSet->descriptorCount = 1; 5240 currentWriteDescriptorSet->descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; 5241 currentWriteDescriptorSet->dstArrayElement = 0; 5242 currentWriteDescriptorSet->dstBinding = resourceLayout->vertexSamplerCount + resourceLayout->vertexStorageTextureCount + i; 5243 currentWriteDescriptorSet->dstSet = commandBuffer->vertexResourceDescriptorSet; 5244 currentWriteDescriptorSet->pTexelBufferView = NULL; 5245 currentWriteDescriptorSet->pImageInfo = NULL; 5246 5247 bufferInfos[bufferInfoCount].buffer = commandBuffer->vertexStorageBufferBindings[i]; 5248 bufferInfos[bufferInfoCount].offset = 0; 5249 bufferInfos[bufferInfoCount].range = VK_WHOLE_SIZE; 5250 5251 currentWriteDescriptorSet->pBufferInfo = &bufferInfos[bufferInfoCount]; 5252 5253 writeCount += 1; 5254 bufferInfoCount += 1; 5255 } 5256 5257 commandBuffer->needNewVertexResourceDescriptorSet = false; 5258 } 5259 5260 if (commandBuffer->needNewVertexUniformDescriptorSet) { 5261 descriptorSetLayout = resourceLayout->descriptorSetLayouts[1]; 5262 5263 commandBuffer->vertexUniformDescriptorSet = VULKAN_INTERNAL_FetchDescriptorSet( 5264 renderer, 5265 commandBuffer, 5266 descriptorSetLayout); 5267 5268 for (Uint32 i = 0; i < resourceLayout->vertexUniformBufferCount; i += 1) { 5269 VkWriteDescriptorSet *currentWriteDescriptorSet = &writeDescriptorSets[writeCount]; 5270 5271 currentWriteDescriptorSet->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; 5272 currentWriteDescriptorSet->pNext = NULL; 5273 currentWriteDescriptorSet->descriptorCount = 1; 5274 currentWriteDescriptorSet->descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC; 5275 currentWriteDescriptorSet->dstArrayElement = 0; 5276 currentWriteDescriptorSet->dstBinding = i; 5277 currentWriteDescriptorSet->dstSet = commandBuffer->vertexUniformDescriptorSet; 5278 currentWriteDescriptorSet->pTexelBufferView = NULL; 5279 currentWriteDescriptorSet->pImageInfo = NULL; 5280 5281 bufferInfos[bufferInfoCount].buffer = commandBuffer->vertexUniformBuffers[i]->buffer->buffer; 5282 bufferInfos[bufferInfoCount].offset = 0; 5283 bufferInfos[bufferInfoCount].range = MAX_UBO_SECTION_SIZE; 5284 5285 currentWriteDescriptorSet->pBufferInfo = &bufferInfos[bufferInfoCount]; 5286 5287 writeCount += 1; 5288 bufferInfoCount += 1; 5289 } 5290 5291 commandBuffer->needNewVertexUniformDescriptorSet = false; 5292 } 5293 5294 for (Uint32 i = 0; i < resourceLayout->vertexUniformBufferCount; i += 1) { 5295 dynamicOffsets[dynamicOffsetCount] = commandBuffer->vertexUniformBuffers[i]->drawOffset; 5296 dynamicOffsetCount += 1; 5297 } 5298 5299 if (commandBuffer->needNewFragmentResourceDescriptorSet) { 5300 descriptorSetLayout = resourceLayout->descriptorSetLayouts[2]; 5301 5302 commandBuffer->fragmentResourceDescriptorSet = VULKAN_INTERNAL_FetchDescriptorSet( 5303 renderer, 5304 commandBuffer, 5305 descriptorSetLayout); 5306 5307 for (Uint32 i = 0; i < resourceLayout->fragmentSamplerCount; i += 1) { 5308 VkWriteDescriptorSet *currentWriteDescriptorSet = &writeDescriptorSets[writeCount]; 5309 5310 currentWriteDescriptorSet->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; 5311 currentWriteDescriptorSet->pNext = NULL; 5312 currentWriteDescriptorSet->descriptorCount = 1; 5313 currentWriteDescriptorSet->descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; 5314 currentWriteDescriptorSet->dstArrayElement = 0; 5315 currentWriteDescriptorSet->dstBinding = i; 5316 currentWriteDescriptorSet->dstSet = commandBuffer->fragmentResourceDescriptorSet; 5317 currentWriteDescriptorSet->pTexelBufferView = NULL; 5318 currentWriteDescriptorSet->pBufferInfo = NULL; 5319 5320 imageInfos[imageInfoCount].sampler = commandBuffer->fragmentSamplerBindings[i]; 5321 imageInfos[imageInfoCount].imageView = commandBuffer->fragmentSamplerTextureViewBindings[i]; 5322 imageInfos[imageInfoCount].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; 5323 5324 currentWriteDescriptorSet->pImageInfo = &imageInfos[imageInfoCount]; 5325 5326 writeCount += 1; 5327 imageInfoCount += 1; 5328 } 5329 5330 for (Uint32 i = 0; i < resourceLayout->fragmentStorageTextureCount; i += 1) { 5331 VkWriteDescriptorSet *currentWriteDescriptorSet = &writeDescriptorSets[writeCount]; 5332 5333 currentWriteDescriptorSet->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; 5334 currentWriteDescriptorSet->pNext = NULL; 5335 currentWriteDescriptorSet->descriptorCount = 1; 5336 currentWriteDescriptorSet->descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE; // Yes, we are declaring a storage image as a sampled image, because shaders are stupid. 5337 currentWriteDescriptorSet->dstArrayElement = 0; 5338 currentWriteDescriptorSet->dstBinding = resourceLayout->fragmentSamplerCount + i; 5339 currentWriteDescriptorSet->dstSet = commandBuffer->fragmentResourceDescriptorSet; 5340 currentWriteDescriptorSet->pTexelBufferView = NULL; 5341 currentWriteDescriptorSet->pBufferInfo = NULL; 5342 5343 imageInfos[imageInfoCount].sampler = VK_NULL_HANDLE; 5344 imageInfos[imageInfoCount].imageView = commandBuffer->fragmentStorageTextureViewBindings[i]; 5345 imageInfos[imageInfoCount].imageLayout = VK_IMAGE_LAYOUT_GENERAL; 5346 5347 currentWriteDescriptorSet->pImageInfo = &imageInfos[imageInfoCount]; 5348 5349 writeCount += 1; 5350 imageInfoCount += 1; 5351 } 5352 5353 for (Uint32 i = 0; i < resourceLayout->fragmentStorageBufferCount; i += 1) { 5354 VkWriteDescriptorSet *currentWriteDescriptorSet = &writeDescriptorSets[writeCount]; 5355 5356 currentWriteDescriptorSet->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; 5357 currentWriteDescriptorSet->pNext = NULL; 5358 currentWriteDescriptorSet->descriptorCount = 1; 5359 currentWriteDescriptorSet->descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; 5360 currentWriteDescriptorSet->dstArrayElement = 0; 5361 currentWriteDescriptorSet->dstBinding = resourceLayout->fragmentSamplerCount + resourceLayout->fragmentStorageTextureCount + i; 5362 currentWriteDescriptorSet->dstSet = commandBuffer->fragmentResourceDescriptorSet; 5363 currentWriteDescriptorSet->pTexelBufferView = NULL; 5364 currentWriteDescriptorSet->pImageInfo = NULL; 5365 5366 bufferInfos[bufferInfoCount].buffer = commandBuffer->fragmentStorageBufferBindings[i]; 5367 bufferInfos[bufferInfoCount].offset = 0; 5368 bufferInfos[bufferInfoCount].range = VK_WHOLE_SIZE; 5369 5370 currentWriteDescriptorSet->pBufferInfo = &bufferInfos[bufferInfoCount]; 5371 5372 writeCount += 1; 5373 bufferInfoCount += 1; 5374 } 5375 5376 commandBuffer->needNewFragmentResourceDescriptorSet = false; 5377 } 5378 5379 if (commandBuffer->needNewFragmentUniformDescriptorSet) { 5380 descriptorSetLayout = resourceLayout->descriptorSetLayouts[3]; 5381 5382 commandBuffer->fragmentUniformDescriptorSet = VULKAN_INTERNAL_FetchDescriptorSet( 5383 renderer, 5384 commandBuffer, 5385 descriptorSetLayout); 5386 5387 for (Uint32 i = 0; i < resourceLayout->fragmentUniformBufferCount; i += 1) { 5388 VkWriteDescriptorSet *currentWriteDescriptorSet = &writeDescriptorSets[writeCount]; 5389 5390 currentWriteDescriptorSet->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; 5391 currentWriteDescriptorSet->pNext = NULL; 5392 currentWriteDescriptorSet->descriptorCount = 1; 5393 currentWriteDescriptorSet->descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC; 5394 currentWriteDescriptorSet->dstArrayElement = 0; 5395 currentWriteDescriptorSet->dstBinding = i; 5396 currentWriteDescriptorSet->dstSet = commandBuffer->fragmentUniformDescriptorSet; 5397 currentWriteDescriptorSet->pTexelBufferView = NULL; 5398 currentWriteDescriptorSet->pImageInfo = NULL; 5399 5400 bufferInfos[bufferInfoCount].buffer = commandBuffer->fragmentUniformBuffers[i]->buffer->buffer; 5401 bufferInfos[bufferInfoCount].offset = 0; 5402 bufferInfos[bufferInfoCount].range = MAX_UBO_SECTION_SIZE; 5403 5404 currentWriteDescriptorSet->pBufferInfo = &bufferInfos[bufferInfoCount]; 5405 5406 writeCount += 1; 5407 bufferInfoCount += 1; 5408 } 5409 5410 commandBuffer->needNewFragmentUniformDescriptorSet = false; 5411 } 5412 5413 for (Uint32 i = 0; i < resourceLayout->fragmentUniformBufferCount; i += 1) { 5414 dynamicOffsets[dynamicOffsetCount] = commandBuffer->fragmentUniformBuffers[i]->drawOffset; 5415 dynamicOffsetCount += 1; 5416 } 5417 5418 renderer->vkUpdateDescriptorSets( 5419 renderer->logicalDevice, 5420 writeCount, 5421 writeDescriptorSets, 5422 0, 5423 NULL); 5424 5425 VkDescriptorSet sets[4]; 5426 sets[0] = commandBuffer->vertexResourceDescriptorSet; 5427 sets[1] = commandBuffer->vertexUniformDescriptorSet; 5428 sets[2] = commandBuffer->fragmentResourceDescriptorSet; 5429 sets[3] = commandBuffer->fragmentUniformDescriptorSet; 5430 5431 renderer->vkCmdBindDescriptorSets( 5432 commandBuffer->commandBuffer, 5433 VK_PIPELINE_BIND_POINT_GRAPHICS, 5434 resourceLayout->pipelineLayout, 5435 0, 5436 4, 5437 sets, 5438 dynamicOffsetCount, 5439 dynamicOffsets); 5440 5441 commandBuffer->needNewVertexUniformOffsets = false; 5442 commandBuffer->needNewFragmentUniformOffsets = false; 5443} 5444 5445static void VULKAN_DrawIndexedPrimitives( 5446 SDL_GPUCommandBuffer *commandBuffer, 5447 Uint32 numIndices, 5448 Uint32 numInstances, 5449 Uint32 firstIndex, 5450 Sint32 vertexOffset, 5451 Uint32 firstInstance) 5452{ 5453 VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; 5454 VulkanRenderer *renderer = vulkanCommandBuffer->renderer; 5455 5456 VULKAN_INTERNAL_BindGraphicsDescriptorSets(renderer, vulkanCommandBuffer); 5457 5458 renderer->vkCmdDrawIndexed( 5459 vulkanCommandBuffer->commandBuffer, 5460 numIndices, 5461 numInstances, 5462 firstIndex, 5463 vertexOffset, 5464 firstInstance); 5465} 5466 5467static void VULKAN_DrawPrimitives( 5468 SDL_GPUCommandBuffer *commandBuffer, 5469 Uint32 numVertices, 5470 Uint32 numInstances, 5471 Uint32 firstVertex, 5472 Uint32 firstInstance) 5473{ 5474 VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; 5475 VulkanRenderer *renderer = vulkanCommandBuffer->renderer; 5476 5477 VULKAN_INTERNAL_BindGraphicsDescriptorSets(renderer, vulkanCommandBuffer); 5478 5479 renderer->vkCmdDraw( 5480 vulkanCommandBuffer->commandBuffer, 5481 numVertices, 5482 numInstances, 5483 firstVertex, 5484 firstInstance); 5485} 5486 5487static void VULKAN_DrawPrimitivesIndirect( 5488 SDL_GPUCommandBuffer *commandBuffer, 5489 SDL_GPUBuffer *buffer, 5490 Uint32 offset, 5491 Uint32 drawCount) 5492{ 5493 VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; 5494 VulkanRenderer *renderer = vulkanCommandBuffer->renderer; 5495 VulkanBuffer *vulkanBuffer = ((VulkanBufferContainer *)buffer)->activeBuffer; 5496 Uint32 pitch = sizeof(SDL_GPUIndirectDrawCommand); 5497 Uint32 i; 5498 5499 VULKAN_INTERNAL_BindGraphicsDescriptorSets(renderer, vulkanCommandBuffer); 5500 5501 if (renderer->supportsMultiDrawIndirect) { 5502 // Real multi-draw! 5503 renderer->vkCmdDrawIndirect( 5504 vulkanCommandBuffer->commandBuffer, 5505 vulkanBuffer->buffer, 5506 offset, 5507 drawCount, 5508 pitch); 5509 } else { 5510 // Fake multi-draw... 5511 for (i = 0; i < drawCount; i += 1) { 5512 renderer->vkCmdDrawIndirect( 5513 vulkanCommandBuffer->commandBuffer, 5514 vulkanBuffer->buffer, 5515 offset + (pitch * i), 5516 1, 5517 pitch); 5518 } 5519 } 5520 5521 VULKAN_INTERNAL_TrackBuffer(vulkanCommandBuffer, vulkanBuffer); 5522} 5523 5524static void VULKAN_DrawIndexedPrimitivesIndirect( 5525 SDL_GPUCommandBuffer *commandBuffer, 5526 SDL_GPUBuffer *buffer, 5527 Uint32 offset, 5528 Uint32 drawCount) 5529{ 5530 VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; 5531 VulkanRenderer *renderer = vulkanCommandBuffer->renderer; 5532 VulkanBuffer *vulkanBuffer = ((VulkanBufferContainer *)buffer)->activeBuffer; 5533 Uint32 pitch = sizeof(SDL_GPUIndexedIndirectDrawCommand); 5534 Uint32 i; 5535 5536 VULKAN_INTERNAL_BindGraphicsDescriptorSets(renderer, vulkanCommandBuffer); 5537 5538 if (renderer->supportsMultiDrawIndirect) { 5539 // Real multi-draw! 5540 renderer->vkCmdDrawIndexedIndirect( 5541 vulkanCommandBuffer->commandBuffer, 5542 vulkanBuffer->buffer, 5543 offset, 5544 drawCount, 5545 pitch); 5546 } else { 5547 // Fake multi-draw... 5548 for (i = 0; i < drawCount; i += 1) { 5549 renderer->vkCmdDrawIndexedIndirect( 5550 vulkanCommandBuffer->commandBuffer, 5551 vulkanBuffer->buffer, 5552 offset + (pitch * i), 5553 1, 5554 pitch); 5555 } 5556 } 5557 5558 VULKAN_INTERNAL_TrackBuffer(vulkanCommandBuffer, vulkanBuffer); 5559} 5560 5561// Debug Naming 5562 5563static void VULKAN_INTERNAL_SetBufferName( 5564 VulkanRenderer *renderer, 5565 VulkanBuffer *buffer, 5566 const char *text) 5567{ 5568 VkDebugUtilsObjectNameInfoEXT nameInfo; 5569 5570 if (renderer->debugMode && renderer->supportsDebugUtils) { 5571 nameInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT; 5572 nameInfo.pNext = NULL; 5573 nameInfo.pObjectName = text; 5574 nameInfo.objectType = VK_OBJECT_TYPE_BUFFER; 5575 nameInfo.objectHandle = (uint64_t)buffer->buffer; 5576 5577 renderer->vkSetDebugUtilsObjectNameEXT( 5578 renderer->logicalDevice, 5579 &nameInfo); 5580 } 5581} 5582 5583static void VULKAN_SetBufferName( 5584 SDL_GPURenderer *driverData, 5585 SDL_GPUBuffer *buffer, 5586 const char *text) 5587{ 5588 VulkanRenderer *renderer = (VulkanRenderer *)driverData; 5589 VulkanBufferContainer *container = (VulkanBufferContainer *)buffer; 5590 size_t textLength = SDL_strlen(text) + 1; 5591 5592 if (renderer->debugMode && renderer->supportsDebugUtils) { 5593 container->debugName = SDL_realloc( 5594 container->debugName, 5595 textLength); 5596 5597 SDL_utf8strlcpy( 5598 container->debugName, 5599 text, 5600 textLength); 5601 5602 for (Uint32 i = 0; i < container->bufferCount; i += 1) { 5603 VULKAN_INTERNAL_SetBufferName( 5604 renderer, 5605 container->buffers[i], 5606 text); 5607 } 5608 } 5609} 5610 5611static void VULKAN_INTERNAL_SetTextureName( 5612 VulkanRenderer *renderer, 5613 VulkanTexture *texture, 5614 const char *text) 5615{ 5616 VkDebugUtilsObjectNameInfoEXT nameInfo; 5617 5618 if (renderer->debugMode && renderer->supportsDebugUtils) { 5619 nameInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT; 5620 nameInfo.pNext = NULL; 5621 nameInfo.pObjectName = text; 5622 nameInfo.objectType = VK_OBJECT_TYPE_IMAGE; 5623 nameInfo.objectHandle = (uint64_t)texture->image; 5624 5625 renderer->vkSetDebugUtilsObjectNameEXT( 5626 renderer->logicalDevice, 5627 &nameInfo); 5628 } 5629} 5630 5631static void VULKAN_SetTextureName( 5632 SDL_GPURenderer *driverData, 5633 SDL_GPUTexture *texture, 5634 const char *text) 5635{ 5636 VulkanRenderer *renderer = (VulkanRenderer *)driverData; 5637 VulkanTextureContainer *container = (VulkanTextureContainer *)texture; 5638 size_t textLength = SDL_strlen(text) + 1; 5639 5640 if (renderer->debugMode && renderer->supportsDebugUtils) { 5641 container->debugName = SDL_realloc( 5642 container->debugName, 5643 textLength); 5644 5645 SDL_utf8strlcpy( 5646 container->debugName, 5647 text, 5648 textLength); 5649 5650 for (Uint32 i = 0; i < container->textureCount; i += 1) { 5651 VULKAN_INTERNAL_SetTextureName( 5652 renderer, 5653 container->textures[i], 5654 text); 5655 } 5656 } 5657} 5658 5659static void VULKAN_InsertDebugLabel( 5660 SDL_GPUCommandBuffer *commandBuffer, 5661 const char *text) 5662{ 5663 VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; 5664 VulkanRenderer *renderer = vulkanCommandBuffer->renderer; 5665 VkDebugUtilsLabelEXT labelInfo; 5666 5667 if (renderer->supportsDebugUtils) { 5668 SDL_zero(labelInfo); 5669 labelInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT; 5670 labelInfo.pLabelName = text; 5671 5672 renderer->vkCmdInsertDebugUtilsLabelEXT( 5673 vulkanCommandBuffer->commandBuffer, 5674 &labelInfo); 5675 } 5676} 5677 5678static void VULKAN_PushDebugGroup( 5679 SDL_GPUCommandBuffer *commandBuffer, 5680 const char *name) 5681{ 5682 VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; 5683 VulkanRenderer *renderer = vulkanCommandBuffer->renderer; 5684 VkDebugUtilsLabelEXT labelInfo; 5685 5686 if (renderer->supportsDebugUtils) { 5687 SDL_zero(labelInfo); 5688 labelInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT; 5689 labelInfo.pLabelName = name; 5690 5691 renderer->vkCmdBeginDebugUtilsLabelEXT( 5692 vulkanCommandBuffer->commandBuffer, 5693 &labelInfo); 5694 } 5695} 5696 5697static void VULKAN_PopDebugGroup( 5698 SDL_GPUCommandBuffer *commandBuffer) 5699{ 5700 VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; 5701 VulkanRenderer *renderer = vulkanCommandBuffer->renderer; 5702 5703 if (renderer->supportsDebugUtils) { 5704 renderer->vkCmdEndDebugUtilsLabelEXT(vulkanCommandBuffer->commandBuffer); 5705 } 5706} 5707 5708static VulkanTexture *VULKAN_INTERNAL_CreateTexture( 5709 VulkanRenderer *renderer, 5710 const SDL_GPUTextureCreateInfo *createinfo) 5711{ 5712 VkResult vulkanResult; 5713 VkImageCreateInfo imageCreateInfo; 5714 VkImageCreateFlags imageCreateFlags = 0; 5715 VkImageViewCreateInfo imageViewCreateInfo; 5716 Uint8 bindResult; 5717 VkImageUsageFlags vkUsageFlags = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT; 5718 Uint32 layerCount = (createinfo->type == SDL_GPU_TEXTURETYPE_3D) ? 1 : createinfo->layer_count_or_depth; 5719 Uint32 depth = (createinfo->type == SDL_GPU_TEXTURETYPE_3D) ? createinfo->layer_count_or_depth : 1; 5720 5721 VulkanTexture *texture = SDL_calloc(1, sizeof(VulkanTexture)); 5722 texture->swizzle = SwizzleForSDLFormat(createinfo->format); 5723 texture->depth = depth; 5724 texture->usage = createinfo->usage; 5725 SDL_SetAtomicInt(&texture->referenceCount, 0); 5726 5727 if (IsDepthFormat(createinfo->format)) { 5728 texture->aspectFlags = VK_IMAGE_ASPECT_DEPTH_BIT; 5729 5730 if (IsStencilFormat(createinfo->format)) { 5731 texture->aspectFlags |= VK_IMAGE_ASPECT_STENCIL_BIT; 5732 } 5733 } else { 5734 texture->aspectFlags = VK_IMAGE_ASPECT_COLOR_BIT; 5735 } 5736 5737 if (createinfo->type == SDL_GPU_TEXTURETYPE_CUBE || createinfo->type == SDL_GPU_TEXTURETYPE_CUBE_ARRAY) { 5738 imageCreateFlags |= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT; 5739 } else if (createinfo->type == SDL_GPU_TEXTURETYPE_3D) { 5740 imageCreateFlags |= VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT; 5741 } 5742 5743 if (createinfo->usage & (SDL_GPU_TEXTUREUSAGE_SAMPLER | 5744 SDL_GPU_TEXTUREUSAGE_GRAPHICS_STORAGE_READ | 5745 SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_READ)) { 5746 vkUsageFlags |= VK_IMAGE_USAGE_SAMPLED_BIT; 5747 } 5748 if (createinfo->usage & SDL_GPU_TEXTUREUSAGE_COLOR_TARGET) { 5749 vkUsageFlags |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; 5750 } 5751 if (createinfo->usage & SDL_GPU_TEXTUREUSAGE_DEPTH_STENCIL_TARGET) { 5752 vkUsageFlags |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; 5753 } 5754 if (createinfo->usage & (SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_WRITE | 5755 SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_SIMULTANEOUS_READ_WRITE)) { 5756 vkUsageFlags |= VK_IMAGE_USAGE_STORAGE_BIT; 5757 } 5758 5759 imageCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; 5760 imageCreateInfo.pNext = NULL; 5761 imageCreateInfo.flags = imageCreateFlags; 5762 imageCreateInfo.imageType = createinfo->type == SDL_GPU_TEXTURETYPE_3D ? VK_IMAGE_TYPE_3D : VK_IMAGE_TYPE_2D; 5763 imageCreateInfo.format = SDLToVK_TextureFormat[createinfo->format]; 5764 imageCreateInfo.extent.width = createinfo->width; 5765 imageCreateInfo.extent.height = createinfo->height; 5766 imageCreateInfo.extent.depth = depth; 5767 imageCreateInfo.mipLevels = createinfo->num_levels; 5768 imageCreateInfo.arrayLayers = layerCount; 5769 imageCreateInfo.samples = SDLToVK_SampleCount[createinfo->sample_count]; 5770 imageCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL; 5771 imageCreateInfo.usage = vkUsageFlags; 5772 imageCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; 5773 imageCreateInfo.queueFamilyIndexCount = 0; 5774 imageCreateInfo.pQueueFamilyIndices = NULL; 5775 imageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; 5776 5777 vulkanResult = renderer->vkCreateImage( 5778 renderer->logicalDevice, 5779 &imageCreateInfo, 5780 NULL, 5781 &texture->image); 5782 5783 if (vulkanResult != VK_SUCCESS) { 5784 VULKAN_INTERNAL_DestroyTexture(renderer, texture); 5785 CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkCreateImage, NULL); 5786 } 5787 5788 bindResult = VULKAN_INTERNAL_BindMemoryForImage( 5789 renderer, 5790 texture->image, 5791 &texture->usedRegion); 5792 5793 if (bindResult != 1) { 5794 renderer->vkDestroyImage( 5795 renderer->logicalDevice, 5796 texture->image, 5797 NULL); 5798 5799 VULKAN_INTERNAL_DestroyTexture(renderer, texture); 5800 SET_STRING_ERROR_AND_RETURN("Unable to bind memory for texture!", NULL); 5801 } 5802 5803 texture->usedRegion->vulkanTexture = texture; // lol 5804 5805 if (createinfo->usage & (SDL_GPU_TEXTUREUSAGE_SAMPLER | SDL_GPU_TEXTUREUSAGE_GRAPHICS_STORAGE_READ | SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_READ)) { 5806 5807 imageViewCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; 5808 imageViewCreateInfo.pNext = NULL; 5809 imageViewCreateInfo.flags = 0; 5810 imageViewCreateInfo.image = texture->image; 5811 imageViewCreateInfo.format = SDLToVK_TextureFormat[createinfo->format]; 5812 imageViewCreateInfo.components = texture->swizzle; 5813 imageViewCreateInfo.subresourceRange.aspectMask = texture->aspectFlags & ~VK_IMAGE_ASPECT_STENCIL_BIT; // Can't sample stencil values 5814 imageViewCreateInfo.subresourceRange.baseMipLevel = 0; 5815 imageViewCreateInfo.subresourceRange.levelCount = createinfo->num_levels; 5816 imageViewCreateInfo.subresourceRange.baseArrayLayer = 0; 5817 imageViewCreateInfo.subresourceRange.layerCount = layerCount; 5818 5819 if (createinfo->type == SDL_GPU_TEXTURETYPE_CUBE) { 5820 imageViewCreateInfo.viewType = VK_IMAGE_VIEW_TYPE_CUBE; 5821 } else if (createinfo->type == SDL_GPU_TEXTURETYPE_CUBE_ARRAY) { 5822 imageViewCreateInfo.viewType = VK_IMAGE_VIEW_TYPE_CUBE_ARRAY; 5823 } else if (createinfo->type == SDL_GPU_TEXTURETYPE_3D) { 5824 imageViewCreateInfo.viewType = VK_IMAGE_VIEW_TYPE_3D; 5825 } else if (createinfo->type == SDL_GPU_TEXTURETYPE_2D_ARRAY) { 5826 imageViewCreateInfo.viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY; 5827 } else { 5828 imageViewCreateInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; 5829 } 5830 5831 vulkanResult = renderer->vkCreateImageView( 5832 renderer->logicalDevice, 5833 &imageViewCreateInfo, 5834 NULL, 5835 &texture->fullView); 5836 5837 if (vulkanResult != VK_SUCCESS) { 5838 VULKAN_INTERNAL_DestroyTexture(renderer, texture); 5839 CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, "vkCreateImageView", NULL); 5840 } 5841 } 5842 5843 // Define slices 5844 texture->subresourceCount = layerCount * createinfo->num_levels; 5845 texture->subresources = SDL_calloc( 5846 texture->subresourceCount, 5847 sizeof(VulkanTextureSubresource)); 5848 5849 for (Uint32 i = 0; i < layerCount; i += 1) { 5850 for (Uint32 j = 0; j < createinfo->num_levels; j += 1) { 5851 Uint32 subresourceIndex = VULKAN_INTERNAL_GetTextureSubresourceIndex( 5852 j, 5853 i, 5854 createinfo->num_levels); 5855 5856 if (createinfo->usage & SDL_GPU_TEXTUREUSAGE_COLOR_TARGET) { 5857 texture->subresources[subresourceIndex].renderTargetViews = SDL_malloc( 5858 depth * sizeof(VkImageView)); 5859 5860 if (depth > 1) { 5861 for (Uint32 k = 0; k < depth; k += 1) { 5862 if (!VULKAN_INTERNAL_CreateRenderTargetView( 5863 renderer, 5864 texture, 5865 k, 5866 j, 5867 SDLToVK_TextureFormat[createinfo->format], 5868 texture->swizzle, 5869 &texture->subresources[subresourceIndex].renderTargetViews[k])) { 5870 VULKAN_INTERNAL_DestroyTexture(renderer, texture); 5871 return NULL; 5872 } 5873 } 5874 } else { 5875 if (!VULKAN_INTERNAL_CreateRenderTargetView( 5876 renderer, 5877 texture, 5878 i, 5879 j, 5880 SDLToVK_TextureFormat[createinfo->format], 5881 texture->swizzle, 5882 &texture->subresources[subresourceIndex].renderTargetViews[0])) { 5883 VULKAN_INTERNAL_DestroyTexture(renderer, texture); 5884 return NULL; 5885 } 5886 } 5887 } 5888 5889 if ((createinfo->usage & SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_WRITE) || (createinfo->usage & SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_SIMULTANEOUS_READ_WRITE)) { 5890 if (!VULKAN_INTERNAL_CreateSubresourceView( 5891 renderer, 5892 createinfo, 5893 texture, 5894 i, 5895 j, 5896 texture->swizzle, 5897 &texture->subresources[subresourceIndex].computeWriteView)) { 5898 VULKAN_INTERNAL_DestroyTexture(renderer, texture); 5899 return NULL; 5900 } 5901 } 5902 5903 if (createinfo->usage & SDL_GPU_TEXTUREUSAGE_DEPTH_STENCIL_TARGET) { 5904 if (!VULKAN_INTERNAL_CreateSubresourceView( 5905 renderer, 5906 createinfo, 5907 texture, 5908 i, 5909 j, 5910 texture->swizzle, 5911 &texture->subresources[subresourceIndex].depthStencilView)) { 5912 VULKAN_INTERNAL_DestroyTexture(renderer, texture); 5913 return NULL; 5914 } 5915 } 5916 5917 texture->subresources[subresourceIndex].parent = texture; 5918 texture->subresources[subresourceIndex].layer = i; 5919 texture->subresources[subresourceIndex].level = j; 5920 } 5921 } 5922 5923 // Set debug name if applicable 5924 if (renderer->debugMode && renderer->supportsDebugUtils && SDL_HasProperty(createinfo->props, SDL_PROP_GPU_TEXTURE_CREATE_NAME_STRING)) { 5925 VkDebugUtilsObjectNameInfoEXT nameInfo; 5926 nameInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT; 5927 nameInfo.pNext = NULL; 5928 nameInfo.pObjectName = SDL_GetStringProperty(createinfo->props, SDL_PROP_GPU_TEXTURE_CREATE_NAME_STRING, NULL); 5929 nameInfo.objectType = VK_OBJECT_TYPE_IMAGE; 5930 nameInfo.objectHandle = (uint64_t)texture->image; 5931 5932 renderer->vkSetDebugUtilsObjectNameEXT( 5933 renderer->logicalDevice, 5934 &nameInfo); 5935 } 5936 5937 return texture; 5938} 5939 5940static void VULKAN_INTERNAL_CycleActiveBuffer( 5941 VulkanRenderer *renderer, 5942 VulkanBufferContainer *container) 5943{ 5944 VulkanBuffer *buffer; 5945 5946 // If a previously-cycled buffer is available, we can use that. 5947 for (Uint32 i = 0; i < container->bufferCount; i += 1) { 5948 buffer = container->buffers[i]; 5949 if (SDL_GetAtomicInt(&buffer->referenceCount) == 0) { 5950 container->activeBuffer = buffer; 5951 return; 5952 } 5953 } 5954 5955 // No buffer handle is available, create a new one. 5956 buffer = VULKAN_INTERNAL_CreateBuffer( 5957 renderer, 5958 container->activeBuffer->size, 5959 container->activeBuffer->usage, 5960 container->activeBuffer->type, 5961 container->dedicated, 5962 container->debugName); 5963 5964 if (!buffer) { 5965 return; 5966 } 5967 5968 EXPAND_ARRAY_IF_NEEDED( 5969 container->buffers, 5970 VulkanBuffer *, 5971 container->bufferCount + 1, 5972 container->bufferCapacity, 5973 container->bufferCapacity * 2); 5974 5975 container->buffers[container->bufferCount] = buffer; 5976 buffer->container = container; 5977 buffer->containerIndex = container->bufferCount; 5978 container->bufferCount += 1; 5979 5980 container->activeBuffer = buffer; 5981} 5982 5983static void VULKAN_INTERNAL_CycleActiveTexture( 5984 VulkanRenderer *renderer, 5985 VulkanCommandBuffer *commandBuffer, 5986 VulkanTextureContainer *container) 5987{ 5988 VulkanTexture *texture; 5989 5990 // If a previously-cycled texture is available, we can use that. 5991 for (Uint32 i = 0; i < container->textureCount; i += 1) { 5992 texture = container->textures[i]; 5993 5994 if (SDL_GetAtomicInt(&texture->referenceCount) == 0) { 5995 container->activeTexture = texture; 5996 return; 5997 } 5998 } 5999 6000 // No texture is available, generate a new one. 6001 texture = VULKAN_INTERNAL_CreateTexture( 6002 renderer, 6003 &container->header.info); 6004 6005 VULKAN_INTERNAL_TextureTransitionToDefaultUsage( 6006 renderer, 6007 commandBuffer, 6008 VULKAN_TEXTURE_USAGE_MODE_UNINITIALIZED, 6009 texture); 6010 6011 if (!texture) { 6012 return; 6013 } 6014 6015 EXPAND_ARRAY_IF_NEEDED( 6016 container->textures, 6017 VulkanTexture *, 6018 container->textureCount + 1, 6019 container->textureCapacity, 6020 container->textureCapacity * 2); 6021 6022 container->textures[container->textureCount] = texture; 6023 texture->container = container; 6024 texture->containerIndex = container->textureCount; 6025 container->textureCount += 1; 6026 6027 container->activeTexture = texture; 6028} 6029 6030static VulkanBuffer *VULKAN_INTERNAL_PrepareBufferForWrite( 6031 VulkanRenderer *renderer, 6032 VulkanCommandBuffer *commandBuffer, 6033 VulkanBufferContainer *bufferContainer, 6034 bool cycle, 6035 VulkanBufferUsageMode destinationUsageMode) 6036{ 6037 if ( 6038 cycle && 6039 SDL_GetAtomicInt(&bufferContainer->activeBuffer->referenceCount) > 0) { 6040 VULKAN_INTERNAL_CycleActiveBuffer( 6041 renderer, 6042 bufferContainer); 6043 } 6044 6045 VULKAN_INTERNAL_BufferTransitionFromDefaultUsage( 6046 renderer, 6047 commandBuffer, 6048 destinationUsageMode, 6049 bufferContainer->activeBuffer); 6050 6051 return bufferContainer->activeBuffer; 6052} 6053 6054static VulkanTextureSubresource *VULKAN_INTERNAL_PrepareTextureSubresourceForWrite( 6055 VulkanRenderer *renderer, 6056 VulkanCommandBuffer *commandBuffer, 6057 VulkanTextureContainer *textureContainer, 6058 Uint32 layer, 6059 Uint32 level, 6060 bool cycle, 6061 VulkanTextureUsageMode destinationUsageMode) 6062{ 6063 VulkanTextureSubresource *textureSubresource = VULKAN_INTERNAL_FetchTextureSubresource( 6064 textureContainer, 6065 layer, 6066 level); 6067 6068 if ( 6069 cycle && 6070 textureContainer->canBeCycled && 6071 SDL_GetAtomicInt(&textureContainer->activeTexture->referenceCount) > 0) { 6072 VULKAN_INTERNAL_CycleActiveTexture( 6073 renderer, 6074 commandBuffer, 6075 textureContainer); 6076 6077 textureSubresource = VULKAN_INTERNAL_FetchTextureSubresource( 6078 textureContainer, 6079 layer, 6080 level); 6081 } 6082 6083 // always do barrier because of layout transitions 6084 VULKAN_INTERNAL_TextureSubresourceTransitionFromDefaultUsage( 6085 renderer, 6086 commandBuffer, 6087 destinationUsageMode, 6088 textureSubresource); 6089 6090 return textureSubresource; 6091} 6092 6093static VkRenderPass VULKAN_INTERNAL_CreateRenderPass( 6094 VulkanRenderer *renderer, 6095 const SDL_GPUColorTargetInfo *colorTargetInfos, 6096 Uint32 numColorTargets, 6097 const SDL_GPUDepthStencilTargetInfo *depthStencilTargetInfo) 6098{ 6099 VkResult vulkanResult; 6100 VkAttachmentDescription attachmentDescriptions[2 * MAX_COLOR_TARGET_BINDINGS + 1 /* depth */]; 6101 VkAttachmentReference colorAttachmentReferences[MAX_COLOR_TARGET_BINDINGS]; 6102 VkAttachmentReference resolveReferences[MAX_COLOR_TARGET_BINDINGS]; 6103 VkAttachmentReference depthStencilAttachmentReference; 6104 VkRenderPassCreateInfo renderPassCreateInfo; 6105 VkSubpassDescription subpass; 6106 VkRenderPass renderPass; 6107 Uint32 i; 6108 6109 Uint32 attachmentDescriptionCount = 0; 6110 Uint32 colorAttachmentReferenceCount = 0; 6111 Uint32 resolveReferenceCount = 0; 6112 6113 for (i = 0; i < numColorTargets; i += 1) { 6114 VulkanTextureContainer *container = (VulkanTextureContainer *)colorTargetInfos[i].texture; 6115 attachmentDescriptions[attachmentDescriptionCount].flags = 0; 6116 attachmentDescriptions[attachmentDescriptionCount].format = SDLToVK_TextureFormat[container->header.info.format]; 6117 attachmentDescriptions[attachmentDescriptionCount].samples = SDLToVK_SampleCount[container->header.info.sample_count]; 6118 attachmentDescriptions[attachmentDescriptionCount].loadOp = SDLToVK_LoadOp[colorTargetInfos[i].load_op]; 6119 attachmentDescriptions[attachmentDescriptionCount].storeOp = SDLToVK_StoreOp[colorTargetInfos[i].store_op]; 6120 attachmentDescriptions[attachmentDescriptionCount].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; 6121 attachmentDescriptions[attachmentDescriptionCount].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; 6122 attachmentDescriptions[attachmentDescriptionCount].initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; 6123 attachmentDescriptions[attachmentDescriptionCount].finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; 6124 6125 colorAttachmentReferences[colorAttachmentReferenceCount].attachment = attachmentDescriptionCount; 6126 colorAttachmentReferences[colorAttachmentReferenceCount].layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; 6127 6128 attachmentDescriptionCount += 1; 6129 6130 if (colorTargetInfos[i].store_op == SDL_GPU_STOREOP_RESOLVE || colorTargetInfos[i].store_op == SDL_GPU_STOREOP_RESOLVE_AND_STORE) { 6131 VulkanTextureContainer *resolveContainer = (VulkanTextureContainer *)colorTargetInfos[i].resolve_texture; 6132 6133 attachmentDescriptions[attachmentDescriptionCount].flags = 0; 6134 attachmentDescriptions[attachmentDescriptionCount].format = SDLToVK_TextureFormat[resolveContainer->header.info.format]; 6135 attachmentDescriptions[attachmentDescriptionCount].samples = SDLToVK_SampleCount[resolveContainer->header.info.sample_count]; 6136 attachmentDescriptions[attachmentDescriptionCount].loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; // The texture will be overwritten anyway 6137 attachmentDescriptions[attachmentDescriptionCount].storeOp = VK_ATTACHMENT_STORE_OP_STORE; // Always store the resolve texture 6138 attachmentDescriptions[attachmentDescriptionCount].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; 6139 attachmentDescriptions[attachmentDescriptionCount].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; 6140 attachmentDescriptions[attachmentDescriptionCount].initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; 6141 attachmentDescriptions[attachmentDescriptionCount].finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; 6142 6143 resolveReferences[colorAttachmentReferenceCount].attachment = attachmentDescriptionCount; 6144 resolveReferences[colorAttachmentReferenceCount].layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; 6145 6146 attachmentDescriptionCount += 1; 6147 resolveReferenceCount += 1; 6148 } else { 6149 resolveReferences[colorAttachmentReferenceCount].attachment = VK_ATTACHMENT_UNUSED; 6150 } 6151 6152 colorAttachmentReferenceCount += 1; 6153 } 6154 6155 subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; 6156 subpass.flags = 0; 6157 subpass.inputAttachmentCount = 0; 6158 subpass.pInputAttachments = NULL; 6159 subpass.colorAttachmentCount = numColorTargets; 6160 subpass.pColorAttachments = colorAttachmentReferences; 6161 subpass.preserveAttachmentCount = 0; 6162 subpass.pPreserveAttachments = NULL; 6163 6164 if (depthStencilTargetInfo == NULL) { 6165 subpass.pDepthStencilAttachment = NULL; 6166 } else { 6167 VulkanTextureContainer *container = (VulkanTextureContainer *)depthStencilTargetInfo->texture; 6168 6169 attachmentDescriptions[attachmentDescriptionCount].flags = 0; 6170 attachmentDescriptions[attachmentDescriptionCount].format = SDLToVK_TextureFormat[container->header.info.format]; 6171 attachmentDescriptions[attachmentDescriptionCount].samples = SDLToVK_SampleCount[container->header.info.sample_count]; 6172 attachmentDescriptions[attachmentDescriptionCount].loadOp = SDLToVK_LoadOp[depthStencilTargetInfo->load_op]; 6173 attachmentDescriptions[attachmentDescriptionCount].storeOp = SDLToVK_StoreOp[depthStencilTargetInfo->store_op]; 6174 attachmentDescriptions[attachmentDescriptionCount].stencilLoadOp = SDLToVK_LoadOp[depthStencilTargetInfo->stencil_load_op]; 6175 attachmentDescriptions[attachmentDescriptionCount].stencilStoreOp = SDLToVK_StoreOp[depthStencilTargetInfo->stencil_store_op]; 6176 attachmentDescriptions[attachmentDescriptionCount].initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; 6177 attachmentDescriptions[attachmentDescriptionCount].finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; 6178 6179 depthStencilAttachmentReference.attachment = attachmentDescriptionCount; 6180 depthStencilAttachmentReference.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; 6181 6182 subpass.pDepthStencilAttachment = &depthStencilAttachmentReference; 6183 6184 attachmentDescriptionCount += 1; 6185 } 6186 6187 if (resolveReferenceCount > 0) { 6188 subpass.pResolveAttachments = resolveReferences; 6189 } else { 6190 subpass.pResolveAttachments = NULL; 6191 } 6192 6193 renderPassCreateInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; 6194 renderPassCreateInfo.pNext = NULL; 6195 renderPassCreateInfo.flags = 0; 6196 renderPassCreateInfo.pAttachments = attachmentDescriptions; 6197 renderPassCreateInfo.attachmentCount = attachmentDescriptionCount; 6198 renderPassCreateInfo.subpassCount = 1; 6199 renderPassCreateInfo.pSubpasses = &subpass; 6200 renderPassCreateInfo.dependencyCount = 0; 6201 renderPassCreateInfo.pDependencies = NULL; 6202 6203 vulkanResult = renderer->vkCreateRenderPass( 6204 renderer->logicalDevice, 6205 &renderPassCreateInfo, 6206 NULL, 6207 &renderPass); 6208 6209 CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkCreateRenderPass, VK_NULL_HANDLE); 6210 6211 return renderPass; 6212} 6213 6214static VkRenderPass VULKAN_INTERNAL_CreateTransientRenderPass( 6215 VulkanRenderer *renderer, 6216 SDL_GPUGraphicsPipelineTargetInfo targetInfo, 6217 VkSampleCountFlagBits sampleCount) 6218{ 6219 VkAttachmentDescription attachmentDescriptions[MAX_COLOR_TARGET_BINDINGS + 1 /* depth */]; 6220 VkAttachmentReference colorAttachmentReferences[MAX_COLOR_TARGET_BINDINGS]; 6221 VkAttachmentReference depthStencilAttachmentReference; 6222 SDL_GPUColorTargetDescription attachmentDescription; 6223 VkSubpassDescription subpass; 6224 VkRenderPassCreateInfo renderPassCreateInfo; 6225 VkRenderPass renderPass; 6226 VkResult result; 6227 6228 Uint32 attachmentDescriptionCount = 0; 6229 Uint32 colorAttachmentReferenceCount = 0; 6230 Uint32 i; 6231 6232 for (i = 0; i < targetInfo.num_color_targets; i += 1) { 6233 attachmentDescription = targetInfo.color_target_descriptions[i]; 6234 6235 attachmentDescriptions[attachmentDescriptionCount].flags = 0; 6236 attachmentDescriptions[attachmentDescriptionCount].format = SDLToVK_TextureFormat[attachmentDescription.format]; 6237 attachmentDescriptions[attachmentDescriptionCount].samples = sampleCount; 6238 attachmentDescriptions[attachmentDescriptionCount].loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; 6239 attachmentDescriptions[attachmentDescriptionCount].storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; 6240 attachmentDescriptions[attachmentDescriptionCount].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; 6241 attachmentDescriptions[attachmentDescriptionCount].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; 6242 attachmentDescriptions[attachmentDescriptionCount].initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; 6243 attachmentDescriptions[attachmentDescriptionCount].finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; 6244 6245 colorAttachmentReferences[colorAttachmentReferenceCount].attachment = attachmentDescriptionCount; 6246 colorAttachmentReferences[colorAttachmentReferenceCount].layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; 6247 6248 attachmentDescriptionCount += 1; 6249 colorAttachmentReferenceCount += 1; 6250 } 6251 6252 subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; 6253 subpass.flags = 0; 6254 subpass.inputAttachmentCount = 0; 6255 subpass.pInputAttachments = NULL; 6256 subpass.colorAttachmentCount = targetInfo.num_color_targets; 6257 subpass.pColorAttachments = colorAttachmentReferences; 6258 subpass.preserveAttachmentCount = 0; 6259 subpass.pPreserveAttachments = NULL; 6260 6261 if (targetInfo.has_depth_stencil_target) { 6262 attachmentDescriptions[attachmentDescriptionCount].flags = 0; 6263 attachmentDescriptions[attachmentDescriptionCount].format = SDLToVK_TextureFormat[targetInfo.depth_stencil_format]; 6264 attachmentDescriptions[attachmentDescriptionCount].samples = sampleCount; 6265 attachmentDescriptions[attachmentDescriptionCount].loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; 6266 attachmentDescriptions[attachmentDescriptionCount].storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; 6267 attachmentDescriptions[attachmentDescriptionCount].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; 6268 attachmentDescriptions[attachmentDescriptionCount].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; 6269 attachmentDescriptions[attachmentDescriptionCount].initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; 6270 attachmentDescriptions[attachmentDescriptionCount].finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; 6271 6272 depthStencilAttachmentReference.attachment = attachmentDescriptionCount; 6273 depthStencilAttachmentReference.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; 6274 6275 subpass.pDepthStencilAttachment = &depthStencilAttachmentReference; 6276 6277 attachmentDescriptionCount += 1; 6278 } else { 6279 subpass.pDepthStencilAttachment = NULL; 6280 } 6281 6282 // Resolve attachments aren't needed for transient passes 6283 subpass.pResolveAttachments = NULL; 6284 6285 renderPassCreateInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; 6286 renderPassCreateInfo.pNext = NULL; 6287 renderPassCreateInfo.flags = 0; 6288 renderPassCreateInfo.pAttachments = attachmentDescriptions; 6289 renderPassCreateInfo.attachmentCount = attachmentDescriptionCount; 6290 renderPassCreateInfo.subpassCount = 1; 6291 renderPassCreateInfo.pSubpasses = &subpass; 6292 renderPassCreateInfo.dependencyCount = 0; 6293 renderPassCreateInfo.pDependencies = NULL; 6294 6295 result = renderer->vkCreateRenderPass( 6296 renderer->logicalDevice, 6297 &renderPassCreateInfo, 6298 NULL, 6299 &renderPass); 6300 6301 CHECK_VULKAN_ERROR_AND_RETURN(result, vkCreateRenderPass, VK_NULL_HANDLE); 6302 6303 return renderPass; 6304} 6305 6306static SDL_GPUGraphicsPipeline *VULKAN_CreateGraphicsPipeline( 6307 SDL_GPURenderer *driverData, 6308 const SDL_GPUGraphicsPipelineCreateInfo *createinfo) 6309{ 6310 VkResult vulkanResult; 6311 Uint32 i; 6312 6313 VulkanGraphicsPipeline *graphicsPipeline = (VulkanGraphicsPipeline *)SDL_malloc(sizeof(VulkanGraphicsPipeline)); 6314 VkGraphicsPipelineCreateInfo vkPipelineCreateInfo; 6315 6316 VkPipelineShaderStageCreateInfo shaderStageCreateInfos[2]; 6317 6318 VkPipelineVertexInputStateCreateInfo vertexInputStateCreateInfo; 6319 VkVertexInputBindingDescription *vertexInputBindingDescriptions = SDL_stack_alloc(VkVertexInputBindingDescription, createinfo->vertex_input_state.num_vertex_buffers); 6320 VkVertexInputAttributeDescription *vertexInputAttributeDescriptions = SDL_stack_alloc(VkVertexInputAttributeDescription, createinfo->vertex_input_state.num_vertex_attributes); 6321 6322 VkPipelineInputAssemblyStateCreateInfo inputAssemblyStateCreateInfo; 6323 6324 VkPipelineViewportStateCreateInfo viewportStateCreateInfo; 6325 6326 VkPipelineRasterizationStateCreateInfo rasterizationStateCreateInfo; 6327 6328 VkPipelineMultisampleStateCreateInfo multisampleStateCreateInfo; 6329 6330 VkPipelineDepthStencilStateCreateInfo depthStencilStateCreateInfo; 6331 VkStencilOpState frontStencilState; 6332 VkStencilOpState backStencilState; 6333 6334 VkPipelineColorBlendStateCreateInfo colorBlendStateCreateInfo; 6335 VkPipelineColorBlendAttachmentState *colorBlendAttachmentStates = SDL_stack_alloc( 6336 VkPipelineColorBlendAttachmentState, 6337 createinfo->target_info.num_color_targets); 6338 6339 static const VkDynamicState dynamicStates[] = { 6340 VK_DYNAMIC_STATE_VIEWPORT, 6341 VK_DYNAMIC_STATE_SCISSOR, 6342 VK_DYNAMIC_STATE_BLEND_CONSTANTS, 6343 VK_DYNAMIC_STATE_STENCIL_REFERENCE 6344 }; 6345 VkPipelineDynamicStateCreateInfo dynamicStateCreateInfo; 6346 6347 VulkanRenderer *renderer = (VulkanRenderer *)driverData; 6348 6349 // Create a "compatible" render pass 6350 6351 VkRenderPass transientRenderPass = VULKAN_INTERNAL_CreateTransientRenderPass( 6352 renderer, 6353 createinfo->target_info, 6354 SDLToVK_SampleCount[createinfo->multisample_state.sample_count]); 6355 6356 // Dynamic state 6357 6358 dynamicStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; 6359 dynamicStateCreateInfo.pNext = NULL; 6360 dynamicStateCreateInfo.flags = 0; 6361 dynamicStateCreateInfo.dynamicStateCount = SDL_arraysize(dynamicStates); 6362 dynamicStateCreateInfo.pDynamicStates = dynamicStates; 6363 6364 // Shader stages 6365 6366 graphicsPipeline->vertexShader = (VulkanShader *)createinfo->vertex_shader; 6367 SDL_AtomicIncRef(&graphicsPipeline->vertexShader->referenceCount); 6368 6369 shaderStageCreateInfos[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; 6370 shaderStageCreateInfos[0].pNext = NULL; 6371 shaderStageCreateInfos[0].flags = 0; 6372 shaderStageCreateInfos[0].stage = VK_SHADER_STAGE_VERTEX_BIT; 6373 shaderStageCreateInfos[0].module = graphicsPipeline->vertexShader->shaderModule; 6374 shaderStageCreateInfos[0].pName = graphicsPipeline->vertexShader->entrypointName; 6375 shaderStageCreateInfos[0].pSpecializationInfo = NULL; 6376 6377 graphicsPipeline->fragmentShader = (VulkanShader *)createinfo->fragment_shader; 6378 SDL_AtomicIncRef(&graphicsPipeline->fragmentShader->referenceCount); 6379 6380 shaderStageCreateInfos[1].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; 6381 shaderStageCreateInfos[1].pNext = NULL; 6382 shaderStageCreateInfos[1].flags = 0; 6383 shaderStageCreateInfos[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT; 6384 shaderStageCreateInfos[1].module = graphicsPipeline->fragmentShader->shaderModule; 6385 shaderStageCreateInfos[1].pName = graphicsPipeline->fragmentShader->entrypointName; 6386 shaderStageCreateInfos[1].pSpecializationInfo = NULL; 6387 6388 if (renderer->debugMode) { 6389 if (graphicsPipeline->vertexShader->stage != SDL_GPU_SHADERSTAGE_VERTEX) { 6390 SDL_assert_release(!"CreateGraphicsPipeline was passed a fragment shader for the vertex stage"); 6391 } 6392 if (graphicsPipeline->fragmentShader->stage != SDL_GPU_SHADERSTAGE_FRAGMENT) { 6393 SDL_assert_release(!"CreateGraphicsPipeline was passed a vertex shader for the fragment stage"); 6394 } 6395 } 6396 6397 // Vertex input 6398 6399 for (i = 0; i < createinfo->vertex_input_state.num_vertex_buffers; i += 1) { 6400 vertexInputBindingDescriptions[i].binding = createinfo->vertex_input_state.vertex_buffer_descriptions[i].slot; 6401 vertexInputBindingDescriptions[i].inputRate = SDLToVK_VertexInputRate[createinfo->vertex_input_state.vertex_buffer_descriptions[i].input_rate]; 6402 vertexInputBindingDescriptions[i].stride = createinfo->vertex_input_state.vertex_buffer_descriptions[i].pitch; 6403 } 6404 6405 for (i = 0; i < createinfo->vertex_input_state.num_vertex_attributes; i += 1) { 6406 vertexInputAttributeDescriptions[i].binding = createinfo->vertex_input_state.vertex_attributes[i].buffer_slot; 6407 vertexInputAttributeDescriptions[i].format = SDLToVK_VertexFormat[createinfo->vertex_input_state.vertex_attributes[i].format]; 6408 vertexInputAttributeDescriptions[i].location = createinfo->vertex_input_state.vertex_attributes[i].location; 6409 vertexInputAttributeDescriptions[i].offset = createinfo->vertex_input_state.vertex_attributes[i].offset; 6410 } 6411 6412 vertexInputStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; 6413 vertexInputStateCreateInfo.pNext = NULL; 6414 vertexInputStateCreateInfo.flags = 0; 6415 vertexInputStateCreateInfo.vertexBindingDescriptionCount = createinfo->vertex_input_state.num_vertex_buffers; 6416 vertexInputStateCreateInfo.pVertexBindingDescriptions = vertexInputBindingDescriptions; 6417 vertexInputStateCreateInfo.vertexAttributeDescriptionCount = createinfo->vertex_input_state.num_vertex_attributes; 6418 vertexInputStateCreateInfo.pVertexAttributeDescriptions = vertexInputAttributeDescriptions; 6419 6420 // Topology 6421 6422 inputAssemblyStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; 6423 inputAssemblyStateCreateInfo.pNext = NULL; 6424 inputAssemblyStateCreateInfo.flags = 0; 6425 inputAssemblyStateCreateInfo.primitiveRestartEnable = VK_FALSE; 6426 inputAssemblyStateCreateInfo.topology = SDLToVK_PrimitiveType[createinfo->primitive_type]; 6427 6428 graphicsPipeline->primitiveType = createinfo->primitive_type; 6429 6430 // Viewport 6431 6432 // NOTE: viewport and scissor are dynamic, and must be set using the command buffer 6433 6434 viewportStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; 6435 viewportStateCreateInfo.pNext = NULL; 6436 viewportStateCreateInfo.flags = 0; 6437 viewportStateCreateInfo.viewportCount = 1; 6438 viewportStateCreateInfo.pViewports = NULL; 6439 viewportStateCreateInfo.scissorCount = 1; 6440 viewportStateCreateInfo.pScissors = NULL; 6441 6442 // Rasterization 6443 6444 rasterizationStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; 6445 rasterizationStateCreateInfo.pNext = NULL; 6446 rasterizationStateCreateInfo.flags = 0; 6447 rasterizationStateCreateInfo.depthClampEnable = !createinfo->rasterizer_state.enable_depth_clip; 6448 rasterizationStateCreateInfo.rasterizerDiscardEnable = VK_FALSE; 6449 rasterizationStateCreateInfo.polygonMode = SDLToVK_PolygonMode( 6450 renderer, 6451 createinfo->rasterizer_state.fill_mode); 6452 rasterizationStateCreateInfo.cullMode = SDLToVK_CullMode[createinfo->rasterizer_state.cull_mode]; 6453 rasterizationStateCreateInfo.frontFace = SDLToVK_FrontFace[createinfo->rasterizer_state.front_face]; 6454 rasterizationStateCreateInfo.depthBiasEnable = 6455 createinfo->rasterizer_state.enable_depth_bias; 6456 rasterizationStateCreateInfo.depthBiasConstantFactor = 6457 createinfo->rasterizer_state.depth_bias_constant_factor; 6458 rasterizationStateCreateInfo.depthBiasClamp = 6459 createinfo->rasterizer_state.depth_bias_clamp; 6460 rasterizationStateCreateInfo.depthBiasSlopeFactor = 6461 createinfo->rasterizer_state.depth_bias_slope_factor; 6462 rasterizationStateCreateInfo.lineWidth = 1.0f; 6463 6464 // Multisample 6465 6466 Uint32 sampleMask = 0xFFFFFFFF; 6467 6468 multisampleStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; 6469 multisampleStateCreateInfo.pNext = NULL; 6470 multisampleStateCreateInfo.flags = 0; 6471 multisampleStateCreateInfo.rasterizationSamples = SDLToVK_SampleCount[createinfo->multisample_state.sample_count]; 6472 multisampleStateCreateInfo.sampleShadingEnable = VK_FALSE; 6473 multisampleStateCreateInfo.minSampleShading = 1.0f; 6474 multisampleStateCreateInfo.pSampleMask = &sampleMask; 6475 multisampleStateCreateInfo.alphaToCoverageEnable = createinfo->multisample_state.enable_alpha_to_coverage; 6476 multisampleStateCreateInfo.alphaToOneEnable = VK_FALSE; 6477 6478 // Depth Stencil State 6479 6480 frontStencilState.failOp = SDLToVK_StencilOp[createinfo->depth_stencil_state.front_stencil_state.fail_op]; 6481 frontStencilState.passOp = SDLToVK_StencilOp[createinfo->depth_stencil_state.front_stencil_state.pass_op]; 6482 frontStencilState.depthFailOp = SDLToVK_StencilOp[createinfo->depth_stencil_state.front_stencil_state.depth_fail_op]; 6483 frontStencilState.compareOp = SDLToVK_CompareOp[createinfo->depth_stencil_state.front_stencil_state.compare_op]; 6484 frontStencilState.compareMask = 6485 createinfo->depth_stencil_state.compare_mask; 6486 frontStencilState.writeMask = 6487 createinfo->depth_stencil_state.write_mask; 6488 frontStencilState.reference = 0; 6489 6490 backStencilState.failOp = SDLToVK_StencilOp[createinfo->depth_stencil_state.back_stencil_state.fail_op]; 6491 backStencilState.passOp = SDLToVK_StencilOp[createinfo->depth_stencil_state.back_stencil_state.pass_op]; 6492 backStencilState.depthFailOp = SDLToVK_StencilOp[createinfo->depth_stencil_state.back_stencil_state.depth_fail_op]; 6493 backStencilState.compareOp = SDLToVK_CompareOp[createinfo->depth_stencil_state.back_stencil_state.compare_op]; 6494 backStencilState.compareMask = 6495 createinfo->depth_stencil_state.compare_mask; 6496 backStencilState.writeMask = 6497 createinfo->depth_stencil_state.write_mask; 6498 backStencilState.reference = 0; 6499 6500 depthStencilStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; 6501 depthStencilStateCreateInfo.pNext = NULL; 6502 depthStencilStateCreateInfo.flags = 0; 6503 depthStencilStateCreateInfo.depthTestEnable = 6504 createinfo->depth_stencil_state.enable_depth_test; 6505 depthStencilStateCreateInfo.depthWriteEnable = 6506 createinfo->depth_stencil_state.enable_depth_write; 6507 depthStencilStateCreateInfo.depthCompareOp = SDLToVK_CompareOp[createinfo->depth_stencil_state.compare_op]; 6508 depthStencilStateCreateInfo.depthBoundsTestEnable = VK_FALSE; 6509 depthStencilStateCreateInfo.stencilTestEnable = 6510 createinfo->depth_stencil_state.enable_stencil_test; 6511 depthStencilStateCreateInfo.front = frontStencilState; 6512 depthStencilStateCreateInfo.back = backStencilState; 6513 depthStencilStateCreateInfo.minDepthBounds = 0; // unused 6514 depthStencilStateCreateInfo.maxDepthBounds = 0; // unused 6515 6516 // Color Blend 6517 6518 for (i = 0; i < createinfo->target_info.num_color_targets; i += 1) { 6519 SDL_GPUColorTargetBlendState blendState = createinfo->target_info.color_target_descriptions[i].blend_state; 6520 SDL_GPUColorComponentFlags colorWriteMask = blendState.enable_color_write_mask ? 6521 blendState.color_write_mask : 6522 0xF; 6523 6524 colorBlendAttachmentStates[i].blendEnable = 6525 blendState.enable_blend; 6526 colorBlendAttachmentStates[i].srcColorBlendFactor = SDLToVK_BlendFactor[blendState.src_color_blendfactor]; 6527 colorBlendAttachmentStates[i].dstColorBlendFactor = SDLToVK_BlendFactor[blendState.dst_color_blendfactor]; 6528 colorBlendAttachmentStates[i].colorBlendOp = SDLToVK_BlendOp[blendState.color_blend_op]; 6529 colorBlendAttachmentStates[i].srcAlphaBlendFactor = SDLToVK_BlendFactor[blendState.src_alpha_blendfactor]; 6530 colorBlendAttachmentStates[i].dstAlphaBlendFactor = SDLToVK_BlendFactor[blendState.dst_alpha_blendfactor]; 6531 colorBlendAttachmentStates[i].alphaBlendOp = SDLToVK_BlendOp[blendState.alpha_blend_op]; 6532 colorBlendAttachmentStates[i].colorWriteMask = 6533 colorWriteMask; 6534 } 6535 6536 colorBlendStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; 6537 colorBlendStateCreateInfo.pNext = NULL; 6538 colorBlendStateCreateInfo.flags = 0; 6539 colorBlendStateCreateInfo.attachmentCount = 6540 createinfo->target_info.num_color_targets; 6541 colorBlendStateCreateInfo.pAttachments = 6542 colorBlendAttachmentStates; 6543 colorBlendStateCreateInfo.blendConstants[0] = 1.0f; 6544 colorBlendStateCreateInfo.blendConstants[1] = 1.0f; 6545 colorBlendStateCreateInfo.blendConstants[2] = 1.0f; 6546 colorBlendStateCreateInfo.blendConstants[3] = 1.0f; 6547 6548 // We don't support LogicOp, so this is easy. 6549 colorBlendStateCreateInfo.logicOpEnable = VK_FALSE; 6550 colorBlendStateCreateInfo.logicOp = 0; 6551 6552 // Pipeline Layout 6553 6554 graphicsPipeline->resourceLayout = 6555 VULKAN_INTERNAL_FetchGraphicsPipelineResourceLayout( 6556 renderer, 6557 graphicsPipeline->vertexShader, 6558 graphicsPipeline->fragmentShader); 6559 6560 if (graphicsPipeline->resourceLayout == NULL) { 6561 SDL_stack_free(vertexInputBindingDescriptions); 6562 SDL_stack_free(vertexInputAttributeDescriptions); 6563 SDL_stack_free(colorBlendAttachmentStates); 6564 SDL_free(graphicsPipeline); 6565 SET_STRING_ERROR_AND_RETURN("Failed to initialize pipeline resource layout!", NULL); 6566 } 6567 6568 // Pipeline 6569 6570 vkPipelineCreateInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; 6571 vkPipelineCreateInfo.pNext = NULL; 6572 vkPipelineCreateInfo.flags = 0; 6573 vkPipelineCreateInfo.stageCount = 2; 6574 vkPipelineCreateInfo.pStages = shaderStageCreateInfos; 6575 vkPipelineCreateInfo.pVertexInputState = &vertexInputStateCreateInfo; 6576 vkPipelineCreateInfo.pInputAssemblyState = &inputAssemblyStateCreateInfo; 6577 vkPipelineCreateInfo.pTessellationState = VK_NULL_HANDLE; 6578 vkPipelineCreateInfo.pViewportState = &viewportStateCreateInfo; 6579 vkPipelineCreateInfo.pRasterizationState = &rasterizationStateCreateInfo; 6580 vkPipelineCreateInfo.pMultisampleState = &multisampleStateCreateInfo; 6581 vkPipelineCreateInfo.pDepthStencilState = &depthStencilStateCreateInfo; 6582 vkPipelineCreateInfo.pColorBlendState = &colorBlendStateCreateInfo; 6583 vkPipelineCreateInfo.pDynamicState = &dynamicStateCreateInfo; 6584 vkPipelineCreateInfo.layout = graphicsPipeline->resourceLayout->pipelineLayout; 6585 vkPipelineCreateInfo.renderPass = transientRenderPass; 6586 vkPipelineCreateInfo.subpass = 0; 6587 vkPipelineCreateInfo.basePipelineHandle = VK_NULL_HANDLE; 6588 vkPipelineCreateInfo.basePipelineIndex = 0; 6589 6590 // TODO: enable pipeline caching 6591 vulkanResult = renderer->vkCreateGraphicsPipelines( 6592 renderer->logicalDevice, 6593 VK_NULL_HANDLE, 6594 1, 6595 &vkPipelineCreateInfo, 6596 NULL, 6597 &graphicsPipeline->pipeline); 6598 6599 SDL_stack_free(vertexInputBindingDescriptions); 6600 SDL_stack_free(vertexInputAttributeDescriptions); 6601 SDL_stack_free(colorBlendAttachmentStates); 6602 6603 renderer->vkDestroyRenderPass( 6604 renderer->logicalDevice, 6605 transientRenderPass, 6606 NULL); 6607 6608 if (vulkanResult != VK_SUCCESS) { 6609 SDL_free(graphicsPipeline); 6610 CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkCreateGraphicsPipelines, NULL); 6611 } 6612 6613 SDL_SetAtomicInt(&graphicsPipeline->referenceCount, 0); 6614 6615 if (renderer->debugMode && renderer->supportsDebugUtils && SDL_HasProperty(createinfo->props, SDL_PROP_GPU_GRAPHICSPIPELINE_CREATE_NAME_STRING)) { 6616 VkDebugUtilsObjectNameInfoEXT nameInfo; 6617 nameInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT; 6618 nameInfo.pNext = NULL; 6619 nameInfo.pObjectName = SDL_GetStringProperty(createinfo->props, SDL_PROP_GPU_GRAPHICSPIPELINE_CREATE_NAME_STRING, NULL); 6620 nameInfo.objectType = VK_OBJECT_TYPE_PIPELINE; 6621 nameInfo.objectHandle = (uint64_t)graphicsPipeline->pipeline; 6622 6623 renderer->vkSetDebugUtilsObjectNameEXT( 6624 renderer->logicalDevice, 6625 &nameInfo); 6626 } 6627 6628 // Put this data in the pipeline we can do validation in gpu.c 6629 graphicsPipeline->header.num_vertex_samplers = graphicsPipeline->resourceLayout->vertexSamplerCount; 6630 graphicsPipeline->header.num_vertex_storage_buffers = graphicsPipeline->resourceLayout->vertexStorageBufferCount; 6631 graphicsPipeline->header.num_vertex_storage_textures = graphicsPipeline->resourceLayout->vertexStorageTextureCount; 6632 graphicsPipeline->header.num_vertex_uniform_buffers = graphicsPipeline->resourceLayout->vertexUniformBufferCount; 6633 graphicsPipeline->header.num_fragment_samplers = graphicsPipeline->resourceLayout->fragmentSamplerCount; 6634 graphicsPipeline->header.num_fragment_storage_buffers = graphicsPipeline->resourceLayout->fragmentStorageBufferCount; 6635 graphicsPipeline->header.num_fragment_storage_textures = graphicsPipeline->resourceLayout->fragmentStorageTextureCount; 6636 graphicsPipeline->header.num_fragment_uniform_buffers = graphicsPipeline->resourceLayout->fragmentUniformBufferCount; 6637 6638 return (SDL_GPUGraphicsPipeline *)graphicsPipeline; 6639} 6640 6641static bool VULKAN_INTERNAL_IsValidShaderBytecode( 6642 const Uint8 *code, 6643 size_t codeSize) 6644{ 6645 // SPIR-V bytecode has a 4 byte header containing 0x07230203. SPIR-V is 6646 // defined as a stream of words and not a stream of bytes so both byte 6647 // orders need to be considered. 6648 // 6649 // FIXME: It is uncertain if drivers are able to load both byte orders. If 6650 // needed we may need to do an optional swizzle internally so apps can 6651 // continue to treat shader code as an opaque blob. 6652 if (codeSize < 4 || code == NULL) { 6653 return false; 6654 } 6655 const Uint32 magic = 0x07230203; 6656 const Uint32 magicInv = 0x03022307; 6657 return SDL_memcmp(code, &magic, 4) == 0 || SDL_memcmp(code, &magicInv, 4) == 0; 6658} 6659 6660static SDL_GPUComputePipeline *VULKAN_CreateComputePipeline( 6661 SDL_GPURenderer *driverData, 6662 const SDL_GPUComputePipelineCreateInfo *createinfo) 6663{ 6664 VkShaderModuleCreateInfo shaderModuleCreateInfo; 6665 VkComputePipelineCreateInfo vkShaderCreateInfo; 6666 VkPipelineShaderStageCreateInfo pipelineShaderStageCreateInfo; 6667 VkResult vulkanResult; 6668 VulkanRenderer *renderer = (VulkanRenderer *)driverData; 6669 VulkanComputePipeline *vulkanComputePipeline; 6670 6671 if (createinfo->format != SDL_GPU_SHADERFORMAT_SPIRV) { 6672 SET_STRING_ERROR_AND_RETURN("Incompatible shader format for Vulkan!", NULL); 6673 } 6674 6675 if (!VULKAN_INTERNAL_IsValidShaderBytecode(createinfo->code, createinfo->code_size)) { 6676 SET_STRING_ERROR_AND_RETURN("The provided shader code is not valid SPIR-V!", NULL); 6677 } 6678 6679 vulkanComputePipeline = SDL_malloc(sizeof(VulkanComputePipeline)); 6680 shaderModuleCreateInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; 6681 shaderModuleCreateInfo.pNext = NULL; 6682 shaderModuleCreateInfo.flags = 0; 6683 shaderModuleCreateInfo.codeSize = createinfo->code_size; 6684 shaderModuleCreateInfo.pCode = (Uint32 *)createinfo->code; 6685 6686 vulkanResult = renderer->vkCreateShaderModule( 6687 renderer->logicalDevice, 6688 &shaderModuleCreateInfo, 6689 NULL, 6690 &vulkanComputePipeline->shaderModule); 6691 6692 if (vulkanResult != VK_SUCCESS) { 6693 SDL_free(vulkanComputePipeline); 6694 CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkCreateShaderModule, NULL); 6695 } 6696 6697 pipelineShaderStageCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; 6698 pipelineShaderStageCreateInfo.pNext = NULL; 6699 pipelineShaderStageCreateInfo.flags = 0; 6700 pipelineShaderStageCreateInfo.stage = VK_SHADER_STAGE_COMPUTE_BIT; 6701 pipelineShaderStageCreateInfo.module = vulkanComputePipeline->shaderModule; 6702 pipelineShaderStageCreateInfo.pName = createinfo->entrypoint; 6703 pipelineShaderStageCreateInfo.pSpecializationInfo = NULL; 6704 6705 vulkanComputePipeline->resourceLayout = VULKAN_INTERNAL_FetchComputePipelineResourceLayout( 6706 renderer, 6707 createinfo); 6708 6709 if (vulkanComputePipeline->resourceLayout == NULL) { 6710 renderer->vkDestroyShaderModule( 6711 renderer->logicalDevice, 6712 vulkanComputePipeline->shaderModule, 6713 NULL); 6714 SDL_free(vulkanComputePipeline); 6715 return NULL; 6716 } 6717 6718 vkShaderCreateInfo.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO; 6719 vkShaderCreateInfo.pNext = NULL; 6720 vkShaderCreateInfo.flags = 0; 6721 vkShaderCreateInfo.stage = pipelineShaderStageCreateInfo; 6722 vkShaderCreateInfo.layout = vulkanComputePipeline->resourceLayout->pipelineLayout; 6723 vkShaderCreateInfo.basePipelineHandle = (VkPipeline)VK_NULL_HANDLE; 6724 vkShaderCreateInfo.basePipelineIndex = 0; 6725 6726 vulkanResult = renderer->vkCreateComputePipelines( 6727 renderer->logicalDevice, 6728 (VkPipelineCache)VK_NULL_HANDLE, 6729 1, 6730 &vkShaderCreateInfo, 6731 NULL, 6732 &vulkanComputePipeline->pipeline); 6733 6734 if (vulkanResult != VK_SUCCESS) { 6735 VULKAN_INTERNAL_DestroyComputePipeline(renderer, vulkanComputePipeline); 6736 CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkCreateComputePipeline, NULL); 6737 return NULL; 6738 } 6739 6740 SDL_SetAtomicInt(&vulkanComputePipeline->referenceCount, 0); 6741 6742 if (renderer->debugMode && renderer->supportsDebugUtils && SDL_HasProperty(createinfo->props, SDL_PROP_GPU_COMPUTEPIPELINE_CREATE_NAME_STRING)) { 6743 VkDebugUtilsObjectNameInfoEXT nameInfo; 6744 nameInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT; 6745 nameInfo.pNext = NULL; 6746 nameInfo.pObjectName = SDL_GetStringProperty(createinfo->props, SDL_PROP_GPU_COMPUTEPIPELINE_CREATE_NAME_STRING, NULL); 6747 nameInfo.objectType = VK_OBJECT_TYPE_PIPELINE; 6748 nameInfo.objectHandle = (uint64_t)vulkanComputePipeline->pipeline; 6749 6750 renderer->vkSetDebugUtilsObjectNameEXT( 6751 renderer->logicalDevice, 6752 &nameInfo); 6753 } 6754 6755 // Track these here for debug layer 6756 vulkanComputePipeline->header.numSamplers = vulkanComputePipeline->resourceLayout->numSamplers; 6757 vulkanComputePipeline->header.numReadonlyStorageTextures = vulkanComputePipeline->resourceLayout->numReadonlyStorageTextures; 6758 vulkanComputePipeline->header.numReadonlyStorageBuffers = vulkanComputePipeline->resourceLayout->numReadonlyStorageBuffers; 6759 vulkanComputePipeline->header.numReadWriteStorageTextures = vulkanComputePipeline->resourceLayout->numReadWriteStorageTextures; 6760 vulkanComputePipeline->header.numReadWriteStorageBuffers = vulkanComputePipeline->resourceLayout->numReadWriteStorageBuffers; 6761 vulkanComputePipeline->header.numUniformBuffers = vulkanComputePipeline->resourceLayout->numUniformBuffers; 6762 6763 return (SDL_GPUComputePipeline *)vulkanComputePipeline; 6764} 6765 6766static SDL_GPUSampler *VULKAN_CreateSampler( 6767 SDL_GPURenderer *driverData, 6768 const SDL_GPUSamplerCreateInfo *createinfo) 6769{ 6770 VulkanRenderer *renderer = (VulkanRenderer *)driverData; 6771 VulkanSampler *vulkanSampler = SDL_malloc(sizeof(VulkanSampler)); 6772 VkResult vulkanResult; 6773 6774 VkSamplerCreateInfo vkSamplerCreateInfo; 6775 vkSamplerCreateInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; 6776 vkSamplerCreateInfo.pNext = NULL; 6777 vkSamplerCreateInfo.flags = 0; 6778 vkSamplerCreateInfo.magFilter = SDLToVK_Filter[createinfo->mag_filter]; 6779 vkSamplerCreateInfo.minFilter = SDLToVK_Filter[createinfo->min_filter]; 6780 vkSamplerCreateInfo.mipmapMode = SDLToVK_SamplerMipmapMode[createinfo->mipmap_mode]; 6781 vkSamplerCreateInfo.addressModeU = SDLToVK_SamplerAddressMode[createinfo->address_mode_u]; 6782 vkSamplerCreateInfo.addressModeV = SDLToVK_SamplerAddressMode[createinfo->address_mode_v]; 6783 vkSamplerCreateInfo.addressModeW = SDLToVK_SamplerAddressMode[createinfo->address_mode_w]; 6784 vkSamplerCreateInfo.mipLodBias = createinfo->mip_lod_bias; 6785 vkSamplerCreateInfo.anisotropyEnable = createinfo->enable_anisotropy; 6786 vkSamplerCreateInfo.maxAnisotropy = createinfo->max_anisotropy; 6787 vkSamplerCreateInfo.compareEnable = createinfo->enable_compare; 6788 vkSamplerCreateInfo.compareOp = SDLToVK_CompareOp[createinfo->compare_op]; 6789 vkSamplerCreateInfo.minLod = createinfo->min_lod; 6790 vkSamplerCreateInfo.maxLod = createinfo->max_lod; 6791 vkSamplerCreateInfo.borderColor = VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK; // arbitrary, unused 6792 vkSamplerCreateInfo.unnormalizedCoordinates = VK_FALSE; 6793 6794 vulkanResult = renderer->vkCreateSampler( 6795 renderer->logicalDevice, 6796 &vkSamplerCreateInfo, 6797 NULL, 6798 &vulkanSampler->sampler); 6799 6800 if (vulkanResult != VK_SUCCESS) { 6801 SDL_free(vulkanSampler); 6802 CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkCreateSampler, NULL); 6803 } 6804 6805 SDL_SetAtomicInt(&vulkanSampler->referenceCount, 0); 6806 6807 if (renderer->debugMode && renderer->supportsDebugUtils && SDL_HasProperty(createinfo->props, SDL_PROP_GPU_SAMPLER_CREATE_NAME_STRING)) { 6808 VkDebugUtilsObjectNameInfoEXT nameInfo; 6809 nameInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT; 6810 nameInfo.pNext = NULL; 6811 nameInfo.pObjectName = SDL_GetStringProperty(createinfo->props, SDL_PROP_GPU_SAMPLER_CREATE_NAME_STRING, NULL); 6812 nameInfo.objectType = VK_OBJECT_TYPE_SAMPLER; 6813 nameInfo.objectHandle = (uint64_t)vulkanSampler->sampler; 6814 6815 renderer->vkSetDebugUtilsObjectNameEXT( 6816 renderer->logicalDevice, 6817 &nameInfo); 6818 } 6819 6820 return (SDL_GPUSampler *)vulkanSampler; 6821} 6822 6823static SDL_GPUShader *VULKAN_CreateShader( 6824 SDL_GPURenderer *driverData, 6825 const SDL_GPUShaderCreateInfo *createinfo) 6826{ 6827 VulkanShader *vulkanShader; 6828 VkResult vulkanResult; 6829 VkShaderModuleCreateInfo vkShaderModuleCreateInfo; 6830 VulkanRenderer *renderer = (VulkanRenderer *)driverData; 6831 6832 if (!VULKAN_INTERNAL_IsValidShaderBytecode(createinfo->code, createinfo->code_size)) { 6833 SET_STRING_ERROR_AND_RETURN("The provided shader code is not valid SPIR-V!", NULL); 6834 } 6835 6836 vulkanShader = SDL_malloc(sizeof(VulkanShader)); 6837 vkShaderModuleCreateInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; 6838 vkShaderModuleCreateInfo.pNext = NULL; 6839 vkShaderModuleCreateInfo.flags = 0; 6840 vkShaderModuleCreateInfo.codeSize = createinfo->code_size; 6841 vkShaderModuleCreateInfo.pCode = (Uint32 *)createinfo->code; 6842 6843 vulkanResult = renderer->vkCreateShaderModule( 6844 renderer->logicalDevice, 6845 &vkShaderModuleCreateInfo, 6846 NULL, 6847 &vulkanShader->shaderModule); 6848 6849 if (vulkanResult != VK_SUCCESS) { 6850 SDL_free(vulkanShader); 6851 CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkCreateShaderModule, NULL); 6852 } 6853 6854 const char *entrypoint = createinfo->entrypoint; 6855 if (!entrypoint) { 6856 entrypoint = "main"; 6857 } 6858 vulkanShader->entrypointName = SDL_strdup(entrypoint); 6859 vulkanShader->stage = createinfo->stage; 6860 vulkanShader->numSamplers = createinfo->num_samplers; 6861 vulkanShader->numStorageTextures = createinfo->num_storage_textures; 6862 vulkanShader->numStorageBuffers = createinfo->num_storage_buffers; 6863 vulkanShader->numUniformBuffers = createinfo->num_uniform_buffers; 6864 6865 SDL_SetAtomicInt(&vulkanShader->referenceCount, 0); 6866 6867 if (renderer->debugMode && SDL_HasProperty(createinfo->props, SDL_PROP_GPU_SHADER_CREATE_NAME_STRING)) { 6868 VkDebugUtilsObjectNameInfoEXT nameInfo; 6869 nameInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT; 6870 nameInfo.pNext = NULL; 6871 nameInfo.pObjectName = SDL_GetStringProperty(createinfo->props, SDL_PROP_GPU_SHADER_CREATE_NAME_STRING, NULL); 6872 nameInfo.objectType = VK_OBJECT_TYPE_SHADER_MODULE; 6873 nameInfo.objectHandle = (uint64_t)vulkanShader->shaderModule; 6874 6875 renderer->vkSetDebugUtilsObjectNameEXT( 6876 renderer->logicalDevice, 6877 &nameInfo); 6878 } 6879 6880 return (SDL_GPUShader *)vulkanShader; 6881} 6882 6883static bool VULKAN_SupportsSampleCount( 6884 SDL_GPURenderer *driverData, 6885 SDL_GPUTextureFormat format, 6886 SDL_GPUSampleCount sampleCount) 6887{ 6888 VulkanRenderer *renderer = (VulkanRenderer *)driverData; 6889 VkSampleCountFlags bits = IsDepthFormat(format) ? renderer->physicalDeviceProperties.properties.limits.framebufferDepthSampleCounts : renderer->physicalDeviceProperties.properties.limits.framebufferColorSampleCounts; 6890 VkSampleCountFlagBits vkSampleCount = SDLToVK_SampleCount[sampleCount]; 6891 return !!(bits & vkSampleCount); 6892} 6893 6894static SDL_GPUTexture *VULKAN_CreateTexture( 6895 SDL_GPURenderer *driverData, 6896 const SDL_GPUTextureCreateInfo *createinfo) 6897{ 6898 VulkanRenderer *renderer = (VulkanRenderer *)driverData; 6899 VulkanTexture *texture; 6900 VulkanTextureContainer *container; 6901 6902 texture = VULKAN_INTERNAL_CreateTexture( 6903 renderer, 6904 createinfo); 6905 6906 if (texture == NULL) { 6907 return NULL; 6908 } 6909 6910 container = SDL_malloc(sizeof(VulkanTextureContainer)); 6911 6912 // Copy properties so we don't lose information when the client destroys them 6913 container->header.info = *createinfo; 6914 container->header.info.props = SDL_CreateProperties(); 6915 if (createinfo->props) { 6916 SDL_CopyProperties(createinfo->props, container->header.info.props); 6917 } 6918 6919 container->canBeCycled = true; 6920 container->activeTexture = texture; 6921 container->textureCapacity = 1; 6922 container->textureCount = 1; 6923 container->textures = SDL_malloc( 6924 container->textureCapacity * sizeof(VulkanTexture *)); 6925 container->textures[0] = container->activeTexture; 6926 container->debugName = NULL; 6927 6928 if (SDL_HasProperty(createinfo->props, SDL_PROP_GPU_TEXTURE_CREATE_NAME_STRING)) { 6929 container->debugName = SDL_strdup(SDL_GetStringProperty(createinfo->props, SDL_PROP_GPU_TEXTURE_CREATE_NAME_STRING, NULL)); 6930 } 6931 6932 texture->container = container; 6933 texture->containerIndex = 0; 6934 6935 // Let's transition to the default barrier state, because for some reason Vulkan doesn't let us do that with initialLayout. 6936 // Only do this after "container" is set, so the texture 6937 // is fully initialized before any Submit that could trigger defrag. 6938 { 6939 VulkanCommandBuffer *barrierCommandBuffer = (VulkanCommandBuffer *)VULKAN_AcquireCommandBuffer((SDL_GPURenderer *)renderer); 6940 VULKAN_INTERNAL_TextureTransitionToDefaultUsage( 6941 renderer, 6942 barrierCommandBuffer, 6943 VULKAN_TEXTURE_USAGE_MODE_UNINITIALIZED, 6944 texture); 6945 VULKAN_INTERNAL_TrackTexture(barrierCommandBuffer, texture); 6946 if (!VULKAN_Submit((SDL_GPUCommandBuffer *)barrierCommandBuffer)) { 6947 VULKAN_ReleaseTexture((SDL_GPURenderer *)renderer, (SDL_GPUTexture *)container); 6948 return NULL; 6949 } 6950 } 6951 6952 return (SDL_GPUTexture *)container; 6953} 6954 6955static SDL_GPUBuffer *VULKAN_CreateBuffer( 6956 SDL_GPURenderer *driverData, 6957 SDL_GPUBufferUsageFlags usageFlags, 6958 Uint32 size, 6959 const char *debugName) 6960{ 6961 return (SDL_GPUBuffer *)VULKAN_INTERNAL_CreateBufferContainer( 6962 (VulkanRenderer *)driverData, 6963 (VkDeviceSize)size, 6964 usageFlags, 6965 VULKAN_BUFFER_TYPE_GPU, 6966 false, 6967 debugName); 6968} 6969 6970static VulkanUniformBuffer *VULKAN_INTERNAL_CreateUniformBuffer( 6971 VulkanRenderer *renderer, 6972 Uint32 size) 6973{ 6974 VulkanUniformBuffer *uniformBuffer = SDL_calloc(1, sizeof(VulkanUniformBuffer)); 6975 6976 uniformBuffer->buffer = VULKAN_INTERNAL_CreateBuffer( 6977 renderer, 6978 (VkDeviceSize)size, 6979 0, 6980 VULKAN_BUFFER_TYPE_UNIFORM, 6981 false, 6982 NULL); 6983 6984 uniformBuffer->drawOffset = 0; 6985 uniformBuffer->writeOffset = 0; 6986 uniformBuffer->buffer->uniformBufferForDefrag = uniformBuffer; 6987 6988 return uniformBuffer; 6989} 6990 6991static SDL_GPUTransferBuffer *VULKAN_CreateTransferBuffer( 6992 SDL_GPURenderer *driverData, 6993 SDL_GPUTransferBufferUsage usage, 6994 Uint32 size, 6995 const char *debugName) 6996{ 6997 return (SDL_GPUTransferBuffer *)VULKAN_INTERNAL_CreateBufferContainer( 6998 (VulkanRenderer *)driverData, 6999 (VkDeviceSize)size, 7000 0, 7001 VULKAN_BUFFER_TYPE_TRANSFER, 7002 true, // Dedicated allocations preserve the data even if a defrag is triggered. 7003 debugName); 7004} 7005 7006static void VULKAN_INTERNAL_ReleaseTexture( 7007 VulkanRenderer *renderer, 7008 VulkanTexture *vulkanTexture) 7009{ 7010 if (vulkanTexture->markedForDestroy) { 7011 return; 7012 } 7013 7014 SDL_LockMutex(renderer->disposeLock); 7015 7016 EXPAND_ARRAY_IF_NEEDED( 7017 renderer->texturesToDestroy, 7018 VulkanTexture *, 7019 renderer->texturesToDestroyCount + 1, 7020 renderer->texturesToDestroyCapacity, 7021 renderer->texturesToDestroyCapacity * 2); 7022 7023 renderer->texturesToDestroy[renderer->texturesToDestroyCount] = vulkanTexture; 7024 renderer->texturesToDestroyCount += 1; 7025 7026 vulkanTexture->markedForDestroy = true; 7027 7028 SDL_UnlockMutex(renderer->disposeLock); 7029} 7030 7031static void VULKAN_ReleaseTexture( 7032 SDL_GPURenderer *driverData, 7033 SDL_GPUTexture *texture) 7034{ 7035 VulkanRenderer *renderer = (VulkanRenderer *)driverData; 7036 VulkanTextureContainer *vulkanTextureContainer = (VulkanTextureContainer *)texture; 7037 Uint32 i; 7038 7039 SDL_LockMutex(renderer->disposeLock); 7040 7041 for (i = 0; i < vulkanTextureContainer->textureCount; i += 1) { 7042 VULKAN_INTERNAL_ReleaseTexture(renderer, vulkanTextureContainer->textures[i]); 7043 } 7044 7045 SDL_DestroyProperties(vulkanTextureContainer->header.info.props); 7046 7047 // Containers are just client handles, so we can destroy immediately 7048 SDL_free(vulkanTextureContainer->debugName); 7049 SDL_free(vulkanTextureContainer->textures); 7050 SDL_free(vulkanTextureContainer); 7051 7052 SDL_UnlockMutex(renderer->disposeLock); 7053} 7054 7055static void VULKAN_ReleaseSampler( 7056 SDL_GPURenderer *driverData, 7057 SDL_GPUSampler *sampler) 7058{ 7059 VulkanRenderer *renderer = (VulkanRenderer *)driverData; 7060 VulkanSampler *vulkanSampler = (VulkanSampler *)sampler; 7061 7062 SDL_LockMutex(renderer->disposeLock); 7063 7064 EXPAND_ARRAY_IF_NEEDED( 7065 renderer->samplersToDestroy, 7066 VulkanSampler *, 7067 renderer->samplersToDestroyCount + 1, 7068 renderer->samplersToDestroyCapacity, 7069 renderer->samplersToDestroyCapacity * 2); 7070 7071 renderer->samplersToDestroy[renderer->samplersToDestroyCount] = vulkanSampler; 7072 renderer->samplersToDestroyCount += 1; 7073 7074 SDL_UnlockMutex(renderer->disposeLock); 7075} 7076 7077static void VULKAN_INTERNAL_ReleaseBuffer( 7078 VulkanRenderer *renderer, 7079 VulkanBuffer *vulkanBuffer) 7080{ 7081 if (vulkanBuffer->markedForDestroy) { 7082 return; 7083 } 7084 7085 SDL_LockMutex(renderer->disposeLock); 7086 7087 EXPAND_ARRAY_IF_NEEDED( 7088 renderer->buffersToDestroy, 7089 VulkanBuffer *, 7090 renderer->buffersToDestroyCount + 1, 7091 renderer->buffersToDestroyCapacity, 7092 renderer->buffersToDestroyCapacity * 2); 7093 7094 renderer->buffersToDestroy[renderer->buffersToDestroyCount] = vulkanBuffer; 7095 renderer->buffersToDestroyCount += 1; 7096 7097 vulkanBuffer->markedForDestroy = true; 7098 vulkanBuffer->container = NULL; 7099 7100 SDL_UnlockMutex(renderer->disposeLock); 7101} 7102 7103static void VULKAN_INTERNAL_ReleaseBufferContainer( 7104 VulkanRenderer *renderer, 7105 VulkanBufferContainer *bufferContainer) 7106{ 7107 Uint32 i; 7108 7109 SDL_LockMutex(renderer->disposeLock); 7110 7111 for (i = 0; i < bufferContainer->bufferCount; i += 1) { 7112 VULKAN_INTERNAL_ReleaseBuffer(renderer, bufferContainer->buffers[i]); 7113 } 7114 7115 // Containers are just client handles, so we can free immediately 7116 if (bufferContainer->debugName != NULL) { 7117 SDL_free(bufferContainer->debugName); 7118 bufferContainer->debugName = NULL; 7119 } 7120 SDL_free(bufferContainer->buffers); 7121 SDL_free(bufferContainer); 7122 7123 SDL_UnlockMutex(renderer->disposeLock); 7124} 7125 7126static void VULKAN_ReleaseBuffer( 7127 SDL_GPURenderer *driverData, 7128 SDL_GPUBuffer *buffer) 7129{ 7130 VulkanRenderer *renderer = (VulkanRenderer *)driverData; 7131 VulkanBufferContainer *vulkanBufferContainer = (VulkanBufferContainer *)buffer; 7132 7133 VULKAN_INTERNAL_ReleaseBufferContainer( 7134 renderer, 7135 vulkanBufferContainer); 7136} 7137 7138static void VULKAN_ReleaseTransferBuffer( 7139 SDL_GPURenderer *driverData, 7140 SDL_GPUTransferBuffer *transferBuffer) 7141{ 7142 VulkanRenderer *renderer = (VulkanRenderer *)driverData; 7143 VulkanBufferContainer *transferBufferContainer = (VulkanBufferContainer *)transferBuffer; 7144 7145 VULKAN_INTERNAL_ReleaseBufferContainer( 7146 renderer, 7147 transferBufferContainer); 7148} 7149 7150static void VULKAN_ReleaseShader( 7151 SDL_GPURenderer *driverData, 7152 SDL_GPUShader *shader) 7153{ 7154 VulkanRenderer *renderer = (VulkanRenderer *)driverData; 7155 VulkanShader *vulkanShader = (VulkanShader *)shader; 7156 7157 SDL_LockMutex(renderer->disposeLock); 7158 7159 EXPAND_ARRAY_IF_NEEDED( 7160 renderer->shadersToDestroy, 7161 VulkanShader *, 7162 renderer->shadersToDestroyCount + 1, 7163 renderer->shadersToDestroyCapacity, 7164 renderer->shadersToDestroyCapacity * 2); 7165 7166 renderer->shadersToDestroy[renderer->shadersToDestroyCount] = vulkanShader; 7167 renderer->shadersToDestroyCount += 1; 7168 7169 SDL_UnlockMutex(renderer->disposeLock); 7170} 7171 7172static void VULKAN_ReleaseComputePipeline( 7173 SDL_GPURenderer *driverData, 7174 SDL_GPUComputePipeline *computePipeline) 7175{ 7176 VulkanRenderer *renderer = (VulkanRenderer *)driverData; 7177 VulkanComputePipeline *vulkanComputePipeline = (VulkanComputePipeline *)computePipeline; 7178 7179 SDL_LockMutex(renderer->disposeLock); 7180 7181 EXPAND_ARRAY_IF_NEEDED( 7182 renderer->computePipelinesToDestroy, 7183 VulkanComputePipeline *, 7184 renderer->computePipelinesToDestroyCount + 1, 7185 renderer->computePipelinesToDestroyCapacity, 7186 renderer->computePipelinesToDestroyCapacity * 2); 7187 7188 renderer->computePipelinesToDestroy[renderer->computePipelinesToDestroyCount] = vulkanComputePipeline; 7189 renderer->computePipelinesToDestroyCount += 1; 7190 7191 SDL_UnlockMutex(renderer->disposeLock); 7192} 7193 7194static void VULKAN_ReleaseGraphicsPipeline( 7195 SDL_GPURenderer *driverData, 7196 SDL_GPUGraphicsPipeline *graphicsPipeline) 7197{ 7198 VulkanRenderer *renderer = (VulkanRenderer *)driverData; 7199 VulkanGraphicsPipeline *vulkanGraphicsPipeline = (VulkanGraphicsPipeline *)graphicsPipeline; 7200 7201 SDL_LockMutex(renderer->disposeLock); 7202 7203 EXPAND_ARRAY_IF_NEEDED( 7204 renderer->graphicsPipelinesToDestroy, 7205 VulkanGraphicsPipeline *, 7206 renderer->graphicsPipelinesToDestroyCount + 1, 7207 renderer->graphicsPipelinesToDestroyCapacity, 7208 renderer->graphicsPipelinesToDestroyCapacity * 2); 7209 7210 renderer->graphicsPipelinesToDestroy[renderer->graphicsPipelinesToDestroyCount] = vulkanGraphicsPipeline; 7211 renderer->graphicsPipelinesToDestroyCount += 1; 7212 7213 SDL_UnlockMutex(renderer->disposeLock); 7214} 7215 7216// Command Buffer render state 7217 7218static VkRenderPass VULKAN_INTERNAL_FetchRenderPass( 7219 VulkanRenderer *renderer, 7220 const SDL_GPUColorTargetInfo *colorTargetInfos, 7221 Uint32 numColorTargets, 7222 const SDL_GPUDepthStencilTargetInfo *depthStencilTargetInfo) 7223{ 7224 VulkanRenderPassHashTableValue *renderPassWrapper = NULL; 7225 VkRenderPass renderPassHandle; 7226 RenderPassHashTableKey key; 7227 Uint32 i; 7228 7229 SDL_zero(key); 7230 7231 for (i = 0; i < numColorTargets; i += 1) { 7232 key.colorTargetDescriptions[i].format = SDLToVK_TextureFormat[((VulkanTextureContainer *)colorTargetInfos[i].texture)->header.info.format]; 7233 key.colorTargetDescriptions[i].loadOp = colorTargetInfos[i].load_op; 7234 key.colorTargetDescriptions[i].storeOp = colorTargetInfos[i].store_op; 7235 7236 if (colorTargetInfos[i].resolve_texture != NULL) { 7237 key.resolveTargetFormats[key.numResolveTargets] = SDLToVK_TextureFormat[((VulkanTextureContainer *)colorTargetInfos[i].resolve_texture)->header.info.format]; 7238 key.numResolveTargets += 1; 7239 } 7240 } 7241 7242 key.sampleCount = VK_SAMPLE_COUNT_1_BIT; 7243 if (numColorTargets > 0) { 7244 key.sampleCount = SDLToVK_SampleCount[((VulkanTextureContainer *)colorTargetInfos[0].texture)->header.info.sample_count]; 7245 } else if (numColorTargets == 0 && depthStencilTargetInfo != NULL) { 7246 key.sampleCount = SDLToVK_SampleCount[((VulkanTextureContainer *)depthStencilTargetInfo->texture)->header.info.sample_count]; 7247 } 7248 7249 key.numColorTargets = numColorTargets; 7250 7251 if (depthStencilTargetInfo == NULL) { 7252 key.depthStencilTargetDescription.format = 0; 7253 key.depthStencilTargetDescription.loadOp = SDL_GPU_LOADOP_DONT_CARE; 7254 key.depthStencilTargetDescription.storeOp = SDL_GPU_STOREOP_DONT_CARE; 7255 key.depthStencilTargetDescription.stencilLoadOp = SDL_GPU_LOADOP_DONT_CARE; 7256 key.depthStencilTargetDescription.stencilStoreOp = SDL_GPU_STOREOP_DONT_CARE; 7257 } else { 7258 key.depthStencilTargetDescription.format = SDLToVK_TextureFormat[((VulkanTextureContainer *)depthStencilTargetInfo->texture)->header.info.format]; 7259 key.depthStencilTargetDescription.loadOp = depthStencilTargetInfo->load_op; 7260 key.depthStencilTargetDescription.storeOp = depthStencilTargetInfo->store_op; 7261 key.depthStencilTargetDescription.stencilLoadOp = depthStencilTargetInfo->stencil_load_op; 7262 key.depthStencilTargetDescription.stencilStoreOp = depthStencilTargetInfo->stencil_store_op; 7263 } 7264 7265 SDL_LockMutex(renderer->renderPassFetchLock); 7266 7267 bool result = SDL_FindInHashTable( 7268 renderer->renderPassHashTable, 7269 (const void *)&key, 7270 (const void **)&renderPassWrapper); 7271 7272 if (result) { 7273 SDL_UnlockMutex(renderer->renderPassFetchLock); 7274 return renderPassWrapper->handle; 7275 } 7276 7277 renderPassHandle = VULKAN_INTERNAL_CreateRenderPass( 7278 renderer, 7279 colorTargetInfos, 7280 numColorTargets, 7281 depthStencilTargetInfo); 7282 7283 if (renderPassHandle == VK_NULL_HANDLE) { 7284 SDL_UnlockMutex(renderer->renderPassFetchLock); 7285 return VK_NULL_HANDLE; 7286 } 7287 7288 // Have to malloc the key to store it in the hashtable 7289 RenderPassHashTableKey *allocedKey = SDL_malloc(sizeof(RenderPassHashTableKey)); 7290 SDL_memcpy(allocedKey, &key, sizeof(RenderPassHashTableKey)); 7291 7292 renderPassWrapper = SDL_malloc(sizeof(VulkanRenderPassHashTableValue)); 7293 renderPassWrapper->handle = renderPassHandle; 7294 7295 SDL_InsertIntoHashTable( 7296 renderer->renderPassHashTable, 7297 (const void *)allocedKey, 7298 (const void *)renderPassWrapper, true); 7299 7300 SDL_UnlockMutex(renderer->renderPassFetchLock); 7301 7302 return renderPassHandle; 7303} 7304 7305static VulkanFramebuffer *VULKAN_INTERNAL_FetchFramebuffer( 7306 VulkanRenderer *renderer, 7307 VkRenderPass renderPass, 7308 const SDL_GPUColorTargetInfo *colorTargetInfos, 7309 Uint32 numColorTargets, 7310 const SDL_GPUDepthStencilTargetInfo *depthStencilTargetInfo, 7311 Uint32 width, 7312 Uint32 height) 7313{ 7314 VulkanFramebuffer *vulkanFramebuffer = NULL; 7315 VkFramebufferCreateInfo framebufferInfo; 7316 VkResult result; 7317 VkImageView imageViewAttachments[2 * MAX_COLOR_TARGET_BINDINGS + 1 /* depth */]; 7318 FramebufferHashTableKey key; 7319 Uint32 attachmentCount = 0; 7320 Uint32 i; 7321 7322 SDL_zero(imageViewAttachments); 7323 SDL_zero(key); 7324 7325 key.numColorTargets = numColorTargets; 7326 7327 for (i = 0; i < numColorTargets; i += 1) { 7328 VulkanTextureContainer *container = (VulkanTextureContainer *)colorTargetInfos[i].texture; 7329 VulkanTextureSubresource *subresource = VULKAN_INTERNAL_FetchTextureSubresource( 7330 container, 7331 container->header.info.type == SDL_GPU_TEXTURETYPE_3D ? 0 : colorTargetInfos[i].layer_or_depth_plane, 7332 colorTargetInfos[i].mip_level); 7333 7334 Uint32 rtvIndex = 7335 container->header.info.type == SDL_GPU_TEXTURETYPE_3D ? colorTargetInfos[i].layer_or_depth_plane : 0; 7336 key.colorAttachmentViews[i] = subresource->renderTargetViews[rtvIndex]; 7337 7338 if (colorTargetInfos[i].resolve_texture != NULL) { 7339 VulkanTextureContainer *resolveTextureContainer = (VulkanTextureContainer *)colorTargetInfos[i].resolve_texture; 7340 VulkanTextureSubresource *resolveSubresource = VULKAN_INTERNAL_FetchTextureSubresource( 7341 resolveTextureContainer, 7342 colorTargetInfos[i].layer_or_depth_plane, 7343 colorTargetInfos[i].mip_level); 7344 7345 key.resolveAttachmentViews[key.numResolveAttachments] = resolveSubresource->renderTargetViews[0]; 7346 key.numResolveAttachments += 1; 7347 } 7348 } 7349 7350 if (depthStencilTargetInfo == NULL) { 7351 key.depthStencilAttachmentView = VK_NULL_HANDLE; 7352 } else { 7353 VulkanTextureSubresource *subresource = VULKAN_INTERNAL_FetchTextureSubresource( 7354 (VulkanTextureContainer *)depthStencilTargetInfo->texture, 7355 depthStencilTargetInfo->layer, 7356 depthStencilTargetInfo->mip_level); 7357 key.depthStencilAttachmentView = subresource->depthStencilView; 7358 } 7359 7360 key.width = width; 7361 key.height = height; 7362 7363 SDL_LockMutex(renderer->framebufferFetchLock); 7364 7365 bool findResult = SDL_FindInHashTable( 7366 renderer->framebufferHashTable, 7367 (const void *)&key, 7368 (const void **)&vulkanFramebuffer); 7369 7370 if (findResult) { 7371 SDL_UnlockMutex(renderer->framebufferFetchLock); 7372 return vulkanFramebuffer; 7373 } 7374 7375 vulkanFramebuffer = SDL_malloc(sizeof(VulkanFramebuffer)); 7376 7377 SDL_SetAtomicInt(&vulkanFramebuffer->referenceCount, 0); 7378 7379 // Create a new framebuffer 7380 7381 for (i = 0; i < numColorTargets; i += 1) { 7382 VulkanTextureContainer *container = (VulkanTextureContainer *)colorTargetInfos[i].texture; 7383 VulkanTextureSubresource *subresource = VULKAN_INTERNAL_FetchTextureSubresource( 7384 container, 7385 container->header.info.type == SDL_GPU_TEXTURETYPE_3D ? 0 : colorTargetInfos[i].layer_or_depth_plane, 7386 colorTargetInfos[i].mip_level); 7387 7388 Uint32 rtvIndex = 7389 container->header.info.type == SDL_GPU_TEXTURETYPE_3D ? colorTargetInfos[i].layer_or_depth_plane : 0; 7390 7391 imageViewAttachments[attachmentCount] = subresource->renderTargetViews[rtvIndex]; 7392 7393 attachmentCount += 1; 7394 7395 if (colorTargetInfos[i].store_op == SDL_GPU_STOREOP_RESOLVE || colorTargetInfos[i].store_op == SDL_GPU_STOREOP_RESOLVE_AND_STORE) { 7396 VulkanTextureContainer *resolveContainer = (VulkanTextureContainer *)colorTargetInfos[i].resolve_texture; 7397 VulkanTextureSubresource *resolveSubresource = VULKAN_INTERNAL_FetchTextureSubresource( 7398 resolveContainer, 7399 colorTargetInfos[i].resolve_layer, 7400 colorTargetInfos[i].resolve_mip_level); 7401 7402 imageViewAttachments[attachmentCount] = resolveSubresource->renderTargetViews[0]; 7403 7404 attachmentCount += 1; 7405 } 7406 } 7407 7408 if (depthStencilTargetInfo != NULL) { 7409 VulkanTextureSubresource *subresource = VULKAN_INTERNAL_FetchTextureSubresource( 7410 (VulkanTextureContainer *)depthStencilTargetInfo->texture, 7411 depthStencilTargetInfo->layer, 7412 depthStencilTargetInfo->mip_level); 7413 imageViewAttachments[attachmentCount] = subresource->depthStencilView; 7414 7415 attachmentCount += 1; 7416 } 7417 7418 framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; 7419 framebufferInfo.pNext = NULL; 7420 framebufferInfo.flags = 0; 7421 framebufferInfo.renderPass = renderPass; 7422 framebufferInfo.attachmentCount = attachmentCount; 7423 framebufferInfo.pAttachments = imageViewAttachments; 7424 framebufferInfo.width = key.width; 7425 framebufferInfo.height = key.height; 7426 framebufferInfo.layers = 1; 7427 7428 result = renderer->vkCreateFramebuffer( 7429 renderer->logicalDevice, 7430 &framebufferInfo, 7431 NULL, 7432 &vulkanFramebuffer->framebuffer); 7433 7434 if (result == VK_SUCCESS) { 7435 // Have to malloc the key to store it in the hashtable 7436 FramebufferHashTableKey *allocedKey = SDL_malloc(sizeof(FramebufferHashTableKey)); 7437 SDL_memcpy(allocedKey, &key, sizeof(FramebufferHashTableKey)); 7438 7439 SDL_InsertIntoHashTable( 7440 renderer->framebufferHashTable, 7441 (const void *)allocedKey, 7442 (const void *)vulkanFramebuffer, true); 7443 7444 } else { 7445 SDL_free(vulkanFramebuffer); 7446 SDL_UnlockMutex(renderer->framebufferFetchLock); 7447 CHECK_VULKAN_ERROR_AND_RETURN(result, vkCreateFramebuffer, NULL); 7448 } 7449 7450 SDL_UnlockMutex(renderer->framebufferFetchLock); 7451 return vulkanFramebuffer; 7452} 7453 7454static void VULKAN_INTERNAL_SetCurrentViewport( 7455 VulkanCommandBuffer *commandBuffer, 7456 const SDL_GPUViewport *viewport) 7457{ 7458 VulkanCommandBuffer *vulkanCommandBuffer = commandBuffer; 7459 VulkanRenderer *renderer = vulkanCommandBuffer->renderer; 7460 7461 vulkanCommandBuffer->currentViewport.x = viewport->x; 7462 vulkanCommandBuffer->currentViewport.width = viewport->w; 7463 vulkanCommandBuffer->currentViewport.minDepth = viewport->min_depth; 7464 vulkanCommandBuffer->currentViewport.maxDepth = viewport->max_depth; 7465 7466 // Viewport flip for consistency with other backends 7467 vulkanCommandBuffer->currentViewport.y = viewport->y + viewport->h; 7468 vulkanCommandBuffer->currentViewport.height = -viewport->h; 7469 7470 renderer->vkCmdSetViewport( 7471 vulkanCommandBuffer->commandBuffer, 7472 0, 7473 1, 7474 &vulkanCommandBuffer->currentViewport); 7475} 7476 7477static void VULKAN_SetViewport( 7478 SDL_GPUCommandBuffer *commandBuffer, 7479 const SDL_GPUViewport *viewport) 7480{ 7481 VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; 7482 7483 VULKAN_INTERNAL_SetCurrentViewport( 7484 vulkanCommandBuffer, 7485 viewport); 7486} 7487 7488static void VULKAN_INTERNAL_SetCurrentScissor( 7489 VulkanCommandBuffer *vulkanCommandBuffer, 7490 const SDL_Rect *scissor) 7491{ 7492 VulkanRenderer *renderer = vulkanCommandBuffer->renderer; 7493 7494 vulkanCommandBuffer->currentScissor.offset.x = scissor->x; 7495 vulkanCommandBuffer->currentScissor.offset.y = scissor->y; 7496 vulkanCommandBuffer->currentScissor.extent.width = scissor->w; 7497 vulkanCommandBuffer->currentScissor.extent.height = scissor->h; 7498 7499 renderer->vkCmdSetScissor( 7500 vulkanCommandBuffer->commandBuffer, 7501 0, 7502 1, 7503 &vulkanCommandBuffer->currentScissor); 7504} 7505 7506static void VULKAN_SetScissor( 7507 SDL_GPUCommandBuffer *commandBuffer, 7508 const SDL_Rect *scissor) 7509{ 7510 VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; 7511 7512 VULKAN_INTERNAL_SetCurrentScissor( 7513 vulkanCommandBuffer, 7514 scissor); 7515} 7516 7517static void VULKAN_INTERNAL_SetCurrentBlendConstants( 7518 VulkanCommandBuffer *vulkanCommandBuffer, 7519 SDL_FColor blendConstants) 7520{ 7521 VulkanRenderer *renderer = vulkanCommandBuffer->renderer; 7522 7523 vulkanCommandBuffer->blendConstants[0] = blendConstants.r; 7524 vulkanCommandBuffer->blendConstants[1] = blendConstants.g; 7525 vulkanCommandBuffer->blendConstants[2] = blendConstants.b; 7526 vulkanCommandBuffer->blendConstants[3] = blendConstants.a; 7527 7528 renderer->vkCmdSetBlendConstants( 7529 vulkanCommandBuffer->commandBuffer, 7530 vulkanCommandBuffer->blendConstants); 7531} 7532 7533static void VULKAN_SetBlendConstants( 7534 SDL_GPUCommandBuffer *commandBuffer, 7535 SDL_FColor blendConstants) 7536{ 7537 VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; 7538 7539 VULKAN_INTERNAL_SetCurrentBlendConstants( 7540 vulkanCommandBuffer, 7541 blendConstants); 7542} 7543 7544static void VULKAN_INTERNAL_SetCurrentStencilReference( 7545 VulkanCommandBuffer *vulkanCommandBuffer, 7546 Uint8 reference) 7547{ 7548 VulkanRenderer *renderer = vulkanCommandBuffer->renderer; 7549 7550 vulkanCommandBuffer->stencilRef = reference; 7551 7552 renderer->vkCmdSetStencilReference( 7553 vulkanCommandBuffer->commandBuffer, 7554 VK_STENCIL_FACE_FRONT_AND_BACK, 7555 vulkanCommandBuffer->stencilRef); 7556} 7557 7558static void VULKAN_SetStencilReference( 7559 SDL_GPUCommandBuffer *commandBuffer, 7560 Uint8 reference) 7561{ 7562 VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; 7563 7564 VULKAN_INTERNAL_SetCurrentStencilReference( 7565 vulkanCommandBuffer, 7566 reference); 7567} 7568 7569static void VULKAN_BindVertexSamplers( 7570 SDL_GPUCommandBuffer *commandBuffer, 7571 Uint32 firstSlot, 7572 const SDL_GPUTextureSamplerBinding *textureSamplerBindings, 7573 Uint32 numBindings) 7574{ 7575 VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; 7576 7577 for (Uint32 i = 0; i < numBindings; i += 1) { 7578 VulkanTextureContainer *textureContainer = (VulkanTextureContainer *)textureSamplerBindings[i].texture; 7579 VulkanSampler *sampler = (VulkanSampler *)textureSamplerBindings[i].sampler; 7580 7581 if (vulkanCommandBuffer->vertexSamplerBindings[firstSlot + i] != sampler->sampler) { 7582 VULKAN_INTERNAL_TrackSampler( 7583 vulkanCommandBuffer, 7584 (VulkanSampler *)textureSamplerBindings[i].sampler); 7585 7586 vulkanCommandBuffer->vertexSamplerBindings[firstSlot + i] = sampler->sampler; 7587 vulkanCommandBuffer->needNewVertexResourceDescriptorSet = true; 7588 } 7589 7590 if (vulkanCommandBuffer->vertexSamplerTextureViewBindings[firstSlot + i] != textureContainer->activeTexture->fullView) { 7591 VULKAN_INTERNAL_TrackTexture( 7592 vulkanCommandBuffer, 7593 textureContainer->activeTexture); 7594 7595 vulkanCommandBuffer->vertexSamplerTextureViewBindings[firstSlot + i] = textureContainer->activeTexture->fullView; 7596 vulkanCommandBuffer->needNewVertexResourceDescriptorSet = true; 7597 } 7598 } 7599} 7600 7601static void VULKAN_BindVertexStorageTextures( 7602 SDL_GPUCommandBuffer *commandBuffer, 7603 Uint32 firstSlot, 7604 SDL_GPUTexture *const *storageTextures, 7605 Uint32 numBindings) 7606{ 7607 VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; 7608 7609 for (Uint32 i = 0; i < numBindings; i += 1) { 7610 VulkanTextureContainer *textureContainer = (VulkanTextureContainer *)storageTextures[i]; 7611 7612 if (vulkanCommandBuffer->vertexStorageTextureViewBindings[firstSlot + i] != textureContainer->activeTexture->fullView) { 7613 VULKAN_INTERNAL_TrackTexture( 7614 vulkanCommandBuffer, 7615 textureContainer->activeTexture); 7616 7617 vulkanCommandBuffer->vertexStorageTextureViewBindings[firstSlot + i] = textureContainer->activeTexture->fullView; 7618 vulkanCommandBuffer->needNewVertexResourceDescriptorSet = true; 7619 } 7620 } 7621} 7622 7623static void VULKAN_BindVertexStorageBuffers( 7624 SDL_GPUCommandBuffer *commandBuffer, 7625 Uint32 firstSlot, 7626 SDL_GPUBuffer *const *storageBuffers, 7627 Uint32 numBindings) 7628{ 7629 VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; 7630 7631 for (Uint32 i = 0; i < numBindings; i += 1) { 7632 VulkanBufferContainer *bufferContainer = (VulkanBufferContainer *)storageBuffers[i]; 7633 7634 if (vulkanCommandBuffer->vertexStorageBufferBindings[firstSlot + i] != bufferContainer->activeBuffer->buffer) { 7635 VULKAN_INTERNAL_TrackBuffer( 7636 vulkanCommandBuffer, 7637 bufferContainer->activeBuffer); 7638 7639 vulkanCommandBuffer->vertexStorageBufferBindings[firstSlot + i] = bufferContainer->activeBuffer->buffer; 7640 vulkanCommandBuffer->needNewVertexResourceDescriptorSet = true; 7641 } 7642 } 7643} 7644 7645static void VULKAN_BindFragmentSamplers( 7646 SDL_GPUCommandBuffer *commandBuffer, 7647 Uint32 firstSlot, 7648 const SDL_GPUTextureSamplerBinding *textureSamplerBindings, 7649 Uint32 numBindings) 7650{ 7651 VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; 7652 7653 for (Uint32 i = 0; i < numBindings; i += 1) { 7654 VulkanTextureContainer *textureContainer = (VulkanTextureContainer *)textureSamplerBindings[i].texture; 7655 VulkanSampler *sampler = (VulkanSampler *)textureSamplerBindings[i].sampler; 7656 7657 if (vulkanCommandBuffer->fragmentSamplerBindings[firstSlot + i] != sampler->sampler) { 7658 VULKAN_INTERNAL_TrackSampler( 7659 vulkanCommandBuffer, 7660 (VulkanSampler *)textureSamplerBindings[i].sampler); 7661 7662 vulkanCommandBuffer->fragmentSamplerBindings[firstSlot + i] = sampler->sampler; 7663 vulkanCommandBuffer->needNewFragmentResourceDescriptorSet = true; 7664 } 7665 7666 if (vulkanCommandBuffer->fragmentSamplerTextureViewBindings[firstSlot + i] != textureContainer->activeTexture->fullView) { 7667 VULKAN_INTERNAL_TrackTexture( 7668 vulkanCommandBuffer, 7669 textureContainer->activeTexture); 7670 7671 vulkanCommandBuffer->fragmentSamplerTextureViewBindings[firstSlot + i] = textureContainer->activeTexture->fullView; 7672 vulkanCommandBuffer->needNewFragmentResourceDescriptorSet = true; 7673 } 7674 } 7675} 7676 7677static void VULKAN_BindFragmentStorageTextures( 7678 SDL_GPUCommandBuffer *commandBuffer, 7679 Uint32 firstSlot, 7680 SDL_GPUTexture *const *storageTextures, 7681 Uint32 numBindings) 7682{ 7683 VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; 7684 7685 for (Uint32 i = 0; i < numBindings; i += 1) { 7686 VulkanTextureContainer *textureContainer = (VulkanTextureContainer *)storageTextures[i]; 7687 7688 if (vulkanCommandBuffer->fragmentStorageTextureViewBindings[firstSlot + i] != textureContainer->activeTexture->fullView) { 7689 VULKAN_INTERNAL_TrackTexture( 7690 vulkanCommandBuffer, 7691 textureContainer->activeTexture); 7692 7693 vulkanCommandBuffer->fragmentStorageTextureViewBindings[firstSlot + i] = textureContainer->activeTexture->fullView; 7694 vulkanCommandBuffer->needNewFragmentResourceDescriptorSet = true; 7695 } 7696 } 7697} 7698 7699static void VULKAN_BindFragmentStorageBuffers( 7700 SDL_GPUCommandBuffer *commandBuffer, 7701 Uint32 firstSlot, 7702 SDL_GPUBuffer *const *storageBuffers, 7703 Uint32 numBindings) 7704{ 7705 VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; 7706 VulkanBufferContainer *bufferContainer; 7707 Uint32 i; 7708 7709 for (i = 0; i < numBindings; i += 1) { 7710 bufferContainer = (VulkanBufferContainer *)storageBuffers[i]; 7711 7712 if (vulkanCommandBuffer->fragmentStorageBufferBindings[firstSlot + i] != bufferContainer->activeBuffer->buffer) { 7713 VULKAN_INTERNAL_TrackBuffer( 7714 vulkanCommandBuffer, 7715 bufferContainer->activeBuffer); 7716 7717 vulkanCommandBuffer->fragmentStorageBufferBindings[firstSlot + i] = bufferContainer->activeBuffer->buffer; 7718 vulkanCommandBuffer->needNewFragmentResourceDescriptorSet = true; 7719 } 7720 } 7721} 7722 7723static VulkanUniformBuffer *VULKAN_INTERNAL_AcquireUniformBufferFromPool( 7724 VulkanCommandBuffer *commandBuffer) 7725{ 7726 VulkanRenderer *renderer = commandBuffer->renderer; 7727 VulkanUniformBuffer *uniformBuffer; 7728 7729 SDL_LockMutex(renderer->acquireUniformBufferLock); 7730 7731 if (renderer->uniformBufferPoolCount > 0) { 7732 uniformBuffer = renderer->uniformBufferPool[renderer->uniformBufferPoolCount - 1]; 7733 renderer->uniformBufferPoolCount -= 1; 7734 } else { 7735 uniformBuffer = VULKAN_INTERNAL_CreateUniformBuffer( 7736 renderer, 7737 UNIFORM_BUFFER_SIZE); 7738 } 7739 7740 SDL_UnlockMutex(renderer->acquireUniformBufferLock); 7741 7742 VULKAN_INTERNAL_TrackUniformBuffer(commandBuffer, uniformBuffer); 7743 7744 return uniformBuffer; 7745} 7746 7747static void VULKAN_INTERNAL_ReturnUniformBufferToPool( 7748 VulkanRenderer *renderer, 7749 VulkanUniformBuffer *uniformBuffer) 7750{ 7751 if (renderer->uniformBufferPoolCount >= renderer->uniformBufferPoolCapacity) { 7752 renderer->uniformBufferPoolCapacity *= 2; 7753 renderer->uniformBufferPool = SDL_realloc( 7754 renderer->uniformBufferPool, 7755 renderer->uniformBufferPoolCapacity * sizeof(VulkanUniformBuffer *)); 7756 } 7757 7758 renderer->uniformBufferPool[renderer->uniformBufferPoolCount] = uniformBuffer; 7759 renderer->uniformBufferPoolCount += 1; 7760 7761 uniformBuffer->writeOffset = 0; 7762 uniformBuffer->drawOffset = 0; 7763} 7764 7765static void VULKAN_INTERNAL_PushUniformData( 7766 VulkanCommandBuffer *commandBuffer, 7767 VulkanUniformBufferStage uniformBufferStage, 7768 Uint32 slotIndex, 7769 const void *data, 7770 Uint32 length) 7771{ 7772 Uint32 blockSize = 7773 VULKAN_INTERNAL_NextHighestAlignment32( 7774 length, 7775 commandBuffer->renderer->minUBOAlignment); 7776 7777 VulkanUniformBuffer *uniformBuffer; 7778 7779 if (uniformBufferStage == VULKAN_UNIFORM_BUFFER_STAGE_VERTEX) { 7780 if (commandBuffer->vertexUniformBuffers[slotIndex] == NULL) { 7781 commandBuffer->vertexUniformBuffers[slotIndex] = VULKAN_INTERNAL_AcquireUniformBufferFromPool( 7782 commandBuffer); 7783 } 7784 uniformBuffer = commandBuffer->vertexUniformBuffers[slotIndex]; 7785 } else if (uniformBufferStage == VULKAN_UNIFORM_BUFFER_STAGE_FRAGMENT) { 7786 if (commandBuffer->fragmentUniformBuffers[slotIndex] == NULL) { 7787 commandBuffer->fragmentUniformBuffers[slotIndex] = VULKAN_INTERNAL_AcquireUniformBufferFromPool( 7788 commandBuffer); 7789 } 7790 uniformBuffer = commandBuffer->fragmentUniformBuffers[slotIndex]; 7791 } else if (uniformBufferStage == VULKAN_UNIFORM_BUFFER_STAGE_COMPUTE) { 7792 if (commandBuffer->computeUniformBuffers[slotIndex] == NULL) { 7793 commandBuffer->computeUniformBuffers[slotIndex] = VULKAN_INTERNAL_AcquireUniformBufferFromPool( 7794 commandBuffer); 7795 } 7796 uniformBuffer = commandBuffer->computeUniformBuffers[slotIndex]; 7797 } else { 7798 SDL_LogError(SDL_LOG_CATEGORY_GPU, "Unrecognized shader stage!"); 7799 return; 7800 } 7801 7802 // If there is no more room, acquire a new uniform buffer 7803 if (uniformBuffer->writeOffset + blockSize + MAX_UBO_SECTION_SIZE >= uniformBuffer->buffer->size) { 7804 uniformBuffer = VULKAN_INTERNAL_AcquireUniformBufferFromPool(commandBuffer); 7805 7806 uniformBuffer->drawOffset = 0; 7807 uniformBuffer->writeOffset = 0; 7808 7809 if (uniformBufferStage == VULKAN_UNIFORM_BUFFER_STAGE_VERTEX) { 7810 commandBuffer->vertexUniformBuffers[slotIndex] = uniformBuffer; 7811 commandBuffer->needNewVertexUniformDescriptorSet = true; 7812 } else if (uniformBufferStage == VULKAN_UNIFORM_BUFFER_STAGE_FRAGMENT) { 7813 commandBuffer->fragmentUniformBuffers[slotIndex] = uniformBuffer; 7814 commandBuffer->needNewFragmentUniformDescriptorSet = true; 7815 } else if (uniformBufferStage == VULKAN_UNIFORM_BUFFER_STAGE_COMPUTE) { 7816 commandBuffer->computeUniformBuffers[slotIndex] = uniformBuffer; 7817 commandBuffer->needNewComputeUniformDescriptorSet = true; 7818 } else { 7819 SDL_LogError(SDL_LOG_CATEGORY_GPU, "Unrecognized shader stage!"); 7820 return; 7821 } 7822 } 7823 7824 uniformBuffer->drawOffset = uniformBuffer->writeOffset; 7825 7826 Uint8 *dst = 7827 uniformBuffer->buffer->usedRegion->allocation->mapPointer + 7828 uniformBuffer->buffer->usedRegion->resourceOffset + 7829 uniformBuffer->writeOffset; 7830 7831 SDL_memcpy( 7832 dst, 7833 data, 7834 length); 7835 7836 uniformBuffer->writeOffset += blockSize; 7837 7838 if (uniformBufferStage == VULKAN_UNIFORM_BUFFER_STAGE_VERTEX) { 7839 commandBuffer->needNewVertexUniformOffsets = true; 7840 } else if (uniformBufferStage == VULKAN_UNIFORM_BUFFER_STAGE_FRAGMENT) { 7841 commandBuffer->needNewFragmentUniformOffsets = true; 7842 } else if (uniformBufferStage == VULKAN_UNIFORM_BUFFER_STAGE_COMPUTE) { 7843 commandBuffer->needNewComputeUniformOffsets = true; 7844 } else { 7845 SDL_LogError(SDL_LOG_CATEGORY_GPU, "Unrecognized shader stage!"); 7846 return; 7847 } 7848} 7849 7850static void VULKAN_BeginRenderPass( 7851 SDL_GPUCommandBuffer *commandBuffer, 7852 const SDL_GPUColorTargetInfo *colorTargetInfos, 7853 Uint32 numColorTargets, 7854 const SDL_GPUDepthStencilTargetInfo *depthStencilTargetInfo) 7855{ 7856 VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; 7857 VulkanRenderer *renderer = vulkanCommandBuffer->renderer; 7858 VkRenderPass renderPass; 7859 VulkanFramebuffer *framebuffer; 7860 7861 Uint32 w, h; 7862 VkClearValue *clearValues; 7863 Uint32 clearCount = 0; 7864 Uint32 totalColorAttachmentCount = 0; 7865 Uint32 i; 7866 SDL_GPUViewport defaultViewport; 7867 SDL_Rect defaultScissor; 7868 SDL_FColor defaultBlendConstants; 7869 Uint32 framebufferWidth = SDL_MAX_UINT32; 7870 Uint32 framebufferHeight = SDL_MAX_UINT32; 7871 7872 for (i = 0; i < numColorTargets; i += 1) { 7873 VulkanTextureContainer *textureContainer = (VulkanTextureContainer *)colorTargetInfos[i].texture; 7874 7875 w = textureContainer->header.info.width >> colorTargetInfos[i].mip_level; 7876 h = textureContainer->header.info.height >> colorTargetInfos[i].mip_level; 7877 7878 // The framebuffer cannot be larger than the smallest attachment. 7879 7880 if (w < framebufferWidth) { 7881 framebufferWidth = w; 7882 } 7883 7884 if (h < framebufferHeight) { 7885 framebufferHeight = h; 7886 } 7887 } 7888 7889 if (depthStencilTargetInfo != NULL) { 7890 VulkanTextureContainer *textureContainer = (VulkanTextureContainer *)depthStencilTargetInfo->texture; 7891 7892 w = textureContainer->header.info.width >> depthStencilTargetInfo->mip_level; 7893 h = textureContainer->header.info.height >> depthStencilTargetInfo->mip_level; 7894 7895 // The framebuffer cannot be larger than the smallest attachment. 7896 7897 if (w < framebufferWidth) { 7898 framebufferWidth = w; 7899 } 7900 7901 if (h < framebufferHeight) { 7902 framebufferHeight = h; 7903 } 7904 } 7905 7906 for (i = 0; i < numColorTargets; i += 1) { 7907 VulkanTextureContainer *textureContainer = (VulkanTextureContainer *)colorTargetInfos[i].texture; 7908 VulkanTextureSubresource *subresource = VULKAN_INTERNAL_PrepareTextureSubresourceForWrite( 7909 renderer, 7910 vulkanCommandBuffer, 7911 textureContainer, 7912 textureContainer->header.info.type == SDL_GPU_TEXTURETYPE_3D ? 0 : colorTargetInfos[i].layer_or_depth_plane, 7913 colorTargetInfos[i].mip_level, 7914 colorTargetInfos[i].cycle, 7915 VULKAN_TEXTURE_USAGE_MODE_COLOR_ATTACHMENT); 7916 7917 vulkanCommandBuffer->colorAttachmentSubresources[vulkanCommandBuffer->colorAttachmentSubresourceCount] = subresource; 7918 vulkanCommandBuffer->colorAttachmentSubresourceCount += 1; 7919 VULKAN_INTERNAL_TrackTexture(vulkanCommandBuffer, subresource->parent); 7920 totalColorAttachmentCount += 1; 7921 clearCount += 1; 7922 7923 if (colorTargetInfos[i].store_op == SDL_GPU_STOREOP_RESOLVE || colorTargetInfos[i].store_op == SDL_GPU_STOREOP_RESOLVE_AND_STORE) { 7924 VulkanTextureContainer *resolveContainer = (VulkanTextureContainer *)colorTargetInfos[i].resolve_texture; 7925 VulkanTextureSubresource *resolveSubresource = VULKAN_INTERNAL_PrepareTextureSubresourceForWrite( 7926 renderer, 7927 vulkanCommandBuffer, 7928 resolveContainer, 7929 colorTargetInfos[i].resolve_layer, 7930 colorTargetInfos[i].resolve_mip_level, 7931 colorTargetInfos[i].cycle_resolve_texture, 7932 VULKAN_TEXTURE_USAGE_MODE_COLOR_ATTACHMENT); 7933 7934 vulkanCommandBuffer->resolveAttachmentSubresources[vulkanCommandBuffer->resolveAttachmentSubresourceCount] = resolveSubresource; 7935 vulkanCommandBuffer->resolveAttachmentSubresourceCount += 1; 7936 VULKAN_INTERNAL_TrackTexture(vulkanCommandBuffer, resolveSubresource->parent); 7937 totalColorAttachmentCount += 1; 7938 clearCount += 1; 7939 } 7940 } 7941 7942 if (depthStencilTargetInfo != NULL) { 7943 VulkanTextureContainer *textureContainer = (VulkanTextureContainer *)depthStencilTargetInfo->texture; 7944 VulkanTextureSubresource *subresource = VULKAN_INTERNAL_PrepareTextureSubresourceForWrite( 7945 renderer, 7946 vulkanCommandBuffer, 7947 textureContainer, 7948 depthStencilTargetInfo->layer, 7949 depthStencilTargetInfo->mip_level, 7950 depthStencilTargetInfo->cycle, 7951 VULKAN_TEXTURE_USAGE_MODE_DEPTH_STENCIL_ATTACHMENT); 7952 7953 vulkanCommandBuffer->depthStencilAttachmentSubresource = subresource; 7954 VULKAN_INTERNAL_TrackTexture(vulkanCommandBuffer, subresource->parent); 7955 clearCount += 1; 7956 } 7957 7958 // Fetch required render objects 7959 7960 renderPass = VULKAN_INTERNAL_FetchRenderPass( 7961 renderer, 7962 colorTargetInfos, 7963 numColorTargets, 7964 depthStencilTargetInfo); 7965 7966 if (renderPass == VK_NULL_HANDLE) { 7967 return; 7968 } 7969 7970 framebuffer = VULKAN_INTERNAL_FetchFramebuffer( 7971 renderer, 7972 renderPass, 7973 colorTargetInfos, 7974 numColorTargets, 7975 depthStencilTargetInfo, 7976 framebufferWidth, 7977 framebufferHeight); 7978 7979 if (framebuffer == NULL) { 7980 return; 7981 } 7982 7983 VULKAN_INTERNAL_TrackFramebuffer(vulkanCommandBuffer, framebuffer); 7984 7985 // Set clear values 7986 7987 clearValues = SDL_stack_alloc(VkClearValue, clearCount); 7988 7989 int clearIndex = 0; 7990 for (i = 0; i < numColorTargets; i += 1) { 7991 clearValues[clearIndex].color.float32[0] = colorTargetInfos[i].clear_color.r; 7992 clearValues[clearIndex].color.float32[1] = colorTargetInfos[i].clear_color.g; 7993 clearValues[clearIndex].color.float32[2] = colorTargetInfos[i].clear_color.b; 7994 clearValues[clearIndex].color.float32[3] = colorTargetInfos[i].clear_color.a; 7995 clearIndex += 1; 7996 7997 if (colorTargetInfos[i].store_op == SDL_GPU_STOREOP_RESOLVE || colorTargetInfos[i].store_op == SDL_GPU_STOREOP_RESOLVE_AND_STORE) { 7998 // Skip over the resolve texture, we're not clearing it 7999 clearIndex += 1; 8000 } 8001 } 8002 8003 if (depthStencilTargetInfo != NULL) { 8004 clearValues[totalColorAttachmentCount].depthStencil.depth = 8005 depthStencilTargetInfo->clear_depth; 8006 clearValues[totalColorAttachmentCount].depthStencil.stencil = 8007 depthStencilTargetInfo->clear_stencil; 8008 } 8009 8010 VkRenderPassBeginInfo renderPassBeginInfo; 8011 renderPassBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; 8012 renderPassBeginInfo.pNext = NULL; 8013 renderPassBeginInfo.renderPass = renderPass; 8014 renderPassBeginInfo.framebuffer = framebuffer->framebuffer; 8015 renderPassBeginInfo.pClearValues = clearValues; 8016 renderPassBeginInfo.clearValueCount = clearCount; 8017 renderPassBeginInfo.renderArea.extent.width = framebufferWidth; 8018 renderPassBeginInfo.renderArea.extent.height = framebufferHeight; 8019 renderPassBeginInfo.renderArea.offset.x = 0; 8020 renderPassBeginInfo.renderArea.offset.y = 0; 8021 8022 renderer->vkCmdBeginRenderPass( 8023 vulkanCommandBuffer->commandBuffer, 8024 &renderPassBeginInfo, 8025 VK_SUBPASS_CONTENTS_INLINE); 8026 8027 SDL_stack_free(clearValues); 8028 8029 // Set sensible default states 8030 8031 defaultViewport.x = 0; 8032 defaultViewport.y = 0; 8033 defaultViewport.w = (float)framebufferWidth; 8034 defaultViewport.h = (float)framebufferHeight; 8035 defaultViewport.min_depth = 0; 8036 defaultViewport.max_depth = 1; 8037 8038 VULKAN_INTERNAL_SetCurrentViewport( 8039 vulkanCommandBuffer, 8040 &defaultViewport); 8041 8042 defaultScissor.x = 0; 8043 defaultScissor.y = 0; 8044 defaultScissor.w = (Sint32)framebufferWidth; 8045 defaultScissor.h = (Sint32)framebufferHeight; 8046 8047 VULKAN_INTERNAL_SetCurrentScissor( 8048 vulkanCommandBuffer, 8049 &defaultScissor); 8050 8051 defaultBlendConstants.r = 1.0f; 8052 defaultBlendConstants.g = 1.0f; 8053 defaultBlendConstants.b = 1.0f; 8054 defaultBlendConstants.a = 1.0f; 8055 8056 VULKAN_INTERNAL_SetCurrentBlendConstants( 8057 vulkanCommandBuffer, 8058 defaultBlendConstants); 8059 8060 VULKAN_INTERNAL_SetCurrentStencilReference( 8061 vulkanCommandBuffer, 8062 0); 8063} 8064 8065static void VULKAN_BindGraphicsPipeline( 8066 SDL_GPUCommandBuffer *commandBuffer, 8067 SDL_GPUGraphicsPipeline *graphicsPipeline) 8068{ 8069 VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; 8070 VulkanRenderer *renderer = vulkanCommandBuffer->renderer; 8071 VulkanGraphicsPipeline *pipeline = (VulkanGraphicsPipeline *)graphicsPipeline; 8072 8073 renderer->vkCmdBindPipeline( 8074 vulkanCommandBuffer->commandBuffer, 8075 VK_PIPELINE_BIND_POINT_GRAPHICS, 8076 pipeline->pipeline); 8077 8078 vulkanCommandBuffer->currentGraphicsPipeline = pipeline; 8079 8080 VULKAN_INTERNAL_TrackGraphicsPipeline(vulkanCommandBuffer, pipeline); 8081 8082 // Acquire uniform buffers if necessary 8083 for (Uint32 i = 0; i < pipeline->resourceLayout->vertexUniformBufferCount; i += 1) { 8084 if (vulkanCommandBuffer->vertexUniformBuffers[i] == NULL) { 8085 vulkanCommandBuffer->vertexUniformBuffers[i] = VULKAN_INTERNAL_AcquireUniformBufferFromPool( 8086 vulkanCommandBuffer); 8087 } 8088 } 8089 8090 for (Uint32 i = 0; i < pipeline->resourceLayout->fragmentUniformBufferCount; i += 1) { 8091 if (vulkanCommandBuffer->fragmentUniformBuffers[i] == NULL) { 8092 vulkanCommandBuffer->fragmentUniformBuffers[i] = VULKAN_INTERNAL_AcquireUniformBufferFromPool( 8093 vulkanCommandBuffer); 8094 } 8095 } 8096 8097 // Mark bindings as needed 8098 vulkanCommandBuffer->needNewVertexResourceDescriptorSet = true; 8099 vulkanCommandBuffer->needNewFragmentResourceDescriptorSet = true; 8100 vulkanCommandBuffer->needNewVertexUniformDescriptorSet = true; 8101 vulkanCommandBuffer->needNewFragmentUniformDescriptorSet = true; 8102 vulkanCommandBuffer->needNewVertexUniformOffsets = true; 8103 vulkanCommandBuffer->needNewFragmentUniformOffsets = true; 8104} 8105 8106static void VULKAN_BindVertexBuffers( 8107 SDL_GPUCommandBuffer *commandBuffer, 8108 Uint32 firstSlot, 8109 const SDL_GPUBufferBinding *bindings, 8110 Uint32 numBindings) 8111{ 8112 VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; 8113 8114 for (Uint32 i = 0; i < numBindings; i += 1) { 8115 VulkanBuffer *buffer = ((VulkanBufferContainer *)bindings[i].buffer)->activeBuffer; 8116 if (vulkanCommandBuffer->vertexBuffers[firstSlot + i] != buffer->buffer || vulkanCommandBuffer->vertexBufferOffsets[firstSlot + i] != bindings[i].offset) { 8117 VULKAN_INTERNAL_TrackBuffer(vulkanCommandBuffer, buffer); 8118 8119 vulkanCommandBuffer->vertexBuffers[firstSlot + i] = buffer->buffer; 8120 vulkanCommandBuffer->vertexBufferOffsets[firstSlot + i] = bindings[i].offset; 8121 vulkanCommandBuffer->needVertexBufferBind = true; 8122 } 8123 } 8124 8125 vulkanCommandBuffer->vertexBufferCount = 8126 SDL_max(vulkanCommandBuffer->vertexBufferCount, firstSlot + numBindings); 8127} 8128 8129static void VULKAN_BindIndexBuffer( 8130 SDL_GPUCommandBuffer *commandBuffer, 8131 const SDL_GPUBufferBinding *binding, 8132 SDL_GPUIndexElementSize indexElementSize) 8133{ 8134 VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; 8135 VulkanRenderer *renderer = vulkanCommandBuffer->renderer; 8136 VulkanBuffer *vulkanBuffer = ((VulkanBufferContainer *)binding->buffer)->activeBuffer; 8137 8138 VULKAN_INTERNAL_TrackBuffer(vulkanCommandBuffer, vulkanBuffer); 8139 8140 renderer->vkCmdBindIndexBuffer( 8141 vulkanCommandBuffer->commandBuffer, 8142 vulkanBuffer->buffer, 8143 (VkDeviceSize)binding->offset, 8144 SDLToVK_IndexType[indexElementSize]); 8145} 8146 8147static void VULKAN_PushVertexUniformData( 8148 SDL_GPUCommandBuffer *commandBuffer, 8149 Uint32 slotIndex, 8150 const void *data, 8151 Uint32 length) 8152{ 8153 VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; 8154 8155 VULKAN_INTERNAL_PushUniformData( 8156 vulkanCommandBuffer, 8157 VULKAN_UNIFORM_BUFFER_STAGE_VERTEX, 8158 slotIndex, 8159 data, 8160 length); 8161} 8162 8163static void VULKAN_PushFragmentUniformData( 8164 SDL_GPUCommandBuffer *commandBuffer, 8165 Uint32 slotIndex, 8166 const void *data, 8167 Uint32 length) 8168{ 8169 VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; 8170 8171 VULKAN_INTERNAL_PushUniformData( 8172 vulkanCommandBuffer, 8173 VULKAN_UNIFORM_BUFFER_STAGE_FRAGMENT, 8174 slotIndex, 8175 data, 8176 length); 8177} 8178 8179static void VULKAN_EndRenderPass( 8180 SDL_GPUCommandBuffer *commandBuffer) 8181{ 8182 VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; 8183 VulkanRenderer *renderer = vulkanCommandBuffer->renderer; 8184 Uint32 i; 8185 8186 renderer->vkCmdEndRenderPass( 8187 vulkanCommandBuffer->commandBuffer); 8188 8189 for (i = 0; i < vulkanCommandBuffer->colorAttachmentSubresourceCount; i += 1) { 8190 VULKAN_INTERNAL_TextureSubresourceTransitionToDefaultUsage( 8191 renderer, 8192 vulkanCommandBuffer, 8193 VULKAN_TEXTURE_USAGE_MODE_COLOR_ATTACHMENT, 8194 vulkanCommandBuffer->colorAttachmentSubresources[i]); 8195 } 8196 vulkanCommandBuffer->colorAttachmentSubresourceCount = 0; 8197 8198 for (i = 0; i < vulkanCommandBuffer->resolveAttachmentSubresourceCount; i += 1) { 8199 VULKAN_INTERNAL_TextureSubresourceTransitionToDefaultUsage( 8200 renderer, 8201 vulkanCommandBuffer, 8202 VULKAN_TEXTURE_USAGE_MODE_COLOR_ATTACHMENT, 8203 vulkanCommandBuffer->resolveAttachmentSubresources[i]); 8204 } 8205 vulkanCommandBuffer->resolveAttachmentSubresourceCount = 0; 8206 8207 if (vulkanCommandBuffer->depthStencilAttachmentSubresource != NULL) { 8208 VULKAN_INTERNAL_TextureSubresourceTransitionToDefaultUsage( 8209 renderer, 8210 vulkanCommandBuffer, 8211 VULKAN_TEXTURE_USAGE_MODE_DEPTH_STENCIL_ATTACHMENT, 8212 vulkanCommandBuffer->depthStencilAttachmentSubresource); 8213 vulkanCommandBuffer->depthStencilAttachmentSubresource = NULL; 8214 } 8215 8216 vulkanCommandBuffer->currentGraphicsPipeline = NULL; 8217 8218 vulkanCommandBuffer->vertexResourceDescriptorSet = VK_NULL_HANDLE; 8219 vulkanCommandBuffer->vertexUniformDescriptorSet = VK_NULL_HANDLE; 8220 vulkanCommandBuffer->fragmentResourceDescriptorSet = VK_NULL_HANDLE; 8221 vulkanCommandBuffer->fragmentUniformDescriptorSet = VK_NULL_HANDLE; 8222 8223 // Reset bind state 8224 SDL_zeroa(vulkanCommandBuffer->colorAttachmentSubresources); 8225 SDL_zeroa(vulkanCommandBuffer->resolveAttachmentSubresources); 8226 vulkanCommandBuffer->depthStencilAttachmentSubresource = NULL; 8227 8228 SDL_zeroa(vulkanCommandBuffer->vertexBuffers); 8229 SDL_zeroa(vulkanCommandBuffer->vertexBufferOffsets); 8230 vulkanCommandBuffer->vertexBufferCount = 0; 8231 8232 SDL_zeroa(vulkanCommandBuffer->vertexSamplerBindings); 8233 SDL_zeroa(vulkanCommandBuffer->vertexSamplerTextureViewBindings); 8234 SDL_zeroa(vulkanCommandBuffer->vertexStorageTextureViewBindings); 8235 SDL_zeroa(vulkanCommandBuffer->vertexStorageBufferBindings); 8236 8237 SDL_zeroa(vulkanCommandBuffer->fragmentSamplerBindings); 8238 SDL_zeroa(vulkanCommandBuffer->fragmentSamplerTextureViewBindings); 8239 SDL_zeroa(vulkanCommandBuffer->fragmentStorageTextureViewBindings); 8240 SDL_zeroa(vulkanCommandBuffer->fragmentStorageBufferBindings); 8241} 8242 8243static void VULKAN_BeginComputePass( 8244 SDL_GPUCommandBuffer *commandBuffer, 8245 const SDL_GPUStorageTextureReadWriteBinding *storageTextureBindings, 8246 Uint32 numStorageTextureBindings, 8247 const SDL_GPUStorageBufferReadWriteBinding *storageBufferBindings, 8248 Uint32 numStorageBufferBindings) 8249{ 8250 VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; 8251 VulkanRenderer *renderer = vulkanCommandBuffer->renderer; 8252 VulkanBufferContainer *bufferContainer; 8253 VulkanBuffer *buffer; 8254 Uint32 i; 8255 8256 vulkanCommandBuffer->readWriteComputeStorageTextureSubresourceCount = numStorageTextureBindings; 8257 8258 for (i = 0; i < numStorageTextureBindings; i += 1) { 8259 VulkanTextureContainer *textureContainer = (VulkanTextureContainer *)storageTextureBindings[i].texture; 8260 VulkanTextureSubresource *subresource = VULKAN_INTERNAL_PrepareTextureSubresourceForWrite( 8261 renderer, 8262 vulkanCommandBuffer, 8263 textureContainer, 8264 storageTextureBindings[i].layer, 8265 storageTextureBindings[i].mip_level, 8266 storageTextureBindings[i].cycle, 8267 VULKAN_TEXTURE_USAGE_MODE_COMPUTE_STORAGE_READ_WRITE); 8268 8269 vulkanCommandBuffer->readWriteComputeStorageTextureSubresources[i] = subresource; 8270 vulkanCommandBuffer->readWriteComputeStorageTextureViewBindings[i] = subresource->computeWriteView; 8271 8272 VULKAN_INTERNAL_TrackTexture( 8273 vulkanCommandBuffer, 8274 subresource->parent); 8275 } 8276 8277 for (i = 0; i < numStorageBufferBindings; i += 1) { 8278 bufferContainer = (VulkanBufferContainer *)storageBufferBindings[i].buffer; 8279 buffer = VULKAN_INTERNAL_PrepareBufferForWrite( 8280 renderer, 8281 vulkanCommandBuffer, 8282 bufferContainer, 8283 storageBufferBindings[i].cycle, 8284 VULKAN_BUFFER_USAGE_MODE_COMPUTE_STORAGE_READ_WRITE); 8285 8286 vulkanCommandBuffer->readWriteComputeStorageBuffers[i] = buffer; 8287 vulkanCommandBuffer->readWriteComputeStorageBufferBindings[i] = buffer->buffer; 8288 8289 VULKAN_INTERNAL_TrackBuffer( 8290 vulkanCommandBuffer, 8291 buffer); 8292 } 8293} 8294 8295static void VULKAN_BindComputePipeline( 8296 SDL_GPUCommandBuffer *commandBuffer, 8297 SDL_GPUComputePipeline *computePipeline) 8298{ 8299 VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; 8300 VulkanRenderer *renderer = vulkanCommandBuffer->renderer; 8301 VulkanComputePipeline *vulkanComputePipeline = (VulkanComputePipeline *)computePipeline; 8302 8303 renderer->vkCmdBindPipeline( 8304 vulkanCommandBuffer->commandBuffer, 8305 VK_PIPELINE_BIND_POINT_COMPUTE, 8306 vulkanComputePipeline->pipeline); 8307 8308 vulkanCommandBuffer->currentComputePipeline = vulkanComputePipeline; 8309 8310 VULKAN_INTERNAL_TrackComputePipeline(vulkanCommandBuffer, vulkanComputePipeline); 8311 8312 // Acquire uniform buffers if necessary 8313 for (Uint32 i = 0; i < vulkanComputePipeline->resourceLayout->numUniformBuffers; i += 1) { 8314 if (vulkanCommandBuffer->computeUniformBuffers[i] == NULL) { 8315 vulkanCommandBuffer->computeUniformBuffers[i] = VULKAN_INTERNAL_AcquireUniformBufferFromPool( 8316 vulkanCommandBuffer); 8317 } 8318 } 8319 8320 // Mark binding as needed 8321 vulkanCommandBuffer->needNewComputeReadWriteDescriptorSet = true; 8322 vulkanCommandBuffer->needNewComputeReadOnlyDescriptorSet = true; 8323 vulkanCommandBuffer->needNewComputeUniformDescriptorSet = true; 8324 vulkanCommandBuffer->needNewComputeUniformOffsets = true; 8325} 8326 8327static void VULKAN_BindComputeSamplers( 8328 SDL_GPUCommandBuffer *commandBuffer, 8329 Uint32 firstSlot, 8330 const SDL_GPUTextureSamplerBinding *textureSamplerBindings, 8331 Uint32 numBindings) 8332{ 8333 VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; 8334 8335 for (Uint32 i = 0; i < numBindings; i += 1) { 8336 VulkanTextureContainer *textureContainer = (VulkanTextureContainer *)textureSamplerBindings[i].texture; 8337 VulkanSampler *sampler = (VulkanSampler *)textureSamplerBindings[i].sampler; 8338 8339 if (vulkanCommandBuffer->computeSamplerBindings[firstSlot + i] != sampler->sampler) { 8340 VULKAN_INTERNAL_TrackSampler( 8341 vulkanCommandBuffer, 8342 sampler); 8343 8344 vulkanCommandBuffer->computeSamplerBindings[firstSlot + i] = sampler->sampler; 8345 vulkanCommandBuffer->needNewComputeReadOnlyDescriptorSet = true; 8346 } 8347 8348 if (vulkanCommandBuffer->computeSamplerTextureViewBindings[firstSlot + i] != textureContainer->activeTexture->fullView) { 8349 VULKAN_INTERNAL_TrackTexture( 8350 vulkanCommandBuffer, 8351 textureContainer->activeTexture); 8352 8353 vulkanCommandBuffer->computeSamplerTextureViewBindings[firstSlot + i] = textureContainer->activeTexture->fullView; 8354 vulkanCommandBuffer->needNewComputeReadOnlyDescriptorSet = true; 8355 } 8356 } 8357} 8358 8359static void VULKAN_BindComputeStorageTextures( 8360 SDL_GPUCommandBuffer *commandBuffer, 8361 Uint32 firstSlot, 8362 SDL_GPUTexture *const *storageTextures, 8363 Uint32 numBindings) 8364{ 8365 VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; 8366 VulkanRenderer *renderer = vulkanCommandBuffer->renderer; 8367 8368 for (Uint32 i = 0; i < numBindings; i += 1) { 8369 VulkanTextureContainer *textureContainer = (VulkanTextureContainer *)storageTextures[i]; 8370 8371 if (vulkanCommandBuffer->readOnlyComputeStorageTextures[firstSlot + i] != textureContainer->activeTexture) { 8372 /* If a different texture as in this slot, transition it back to its default usage */ 8373 if (vulkanCommandBuffer->readOnlyComputeStorageTextures[firstSlot + i] != NULL) { 8374 VULKAN_INTERNAL_TextureTransitionToDefaultUsage( 8375 renderer, 8376 vulkanCommandBuffer, 8377 VULKAN_TEXTURE_USAGE_MODE_COMPUTE_STORAGE_READ, 8378 vulkanCommandBuffer->readOnlyComputeStorageTextures[firstSlot + i]); 8379 } 8380 8381 /* Then transition the new texture and prepare it for binding */ 8382 VULKAN_INTERNAL_TextureTransitionFromDefaultUsage( 8383 renderer, 8384 vulkanCommandBuffer, 8385 VULKAN_TEXTURE_USAGE_MODE_COMPUTE_STORAGE_READ, 8386 textureContainer->activeTexture); 8387 8388 8389 VULKAN_INTERNAL_TrackTexture( 8390 vulkanCommandBuffer, 8391 textureContainer->activeTexture); 8392 8393 vulkanCommandBuffer->readOnlyComputeStorageTextures[firstSlot + i] = textureContainer->activeTexture; 8394 vulkanCommandBuffer->readOnlyComputeStorageTextureViewBindings[firstSlot + i] = textureContainer->activeTexture->fullView; 8395 vulkanCommandBuffer->needNewComputeReadOnlyDescriptorSet = true; 8396 } 8397 } 8398} 8399 8400static void VULKAN_BindComputeStorageBuffers( 8401 SDL_GPUCommandBuffer *commandBuffer, 8402 Uint32 firstSlot, 8403 SDL_GPUBuffer *const *storageBuffers, 8404 Uint32 numBindings) 8405{ 8406 VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; 8407 VulkanRenderer *renderer = vulkanCommandBuffer->renderer; 8408 8409 for (Uint32 i = 0; i < numBindings; i += 1) { 8410 VulkanBufferContainer *bufferContainer = (VulkanBufferContainer *)storageBuffers[i]; 8411 8412 if (vulkanCommandBuffer->readOnlyComputeStorageBuffers[firstSlot + i] != bufferContainer->activeBuffer) { 8413 /* If a different buffer was in this slot, transition it back to its default usage */ 8414 if (vulkanCommandBuffer->readOnlyComputeStorageBuffers[firstSlot + i] != NULL) { 8415 VULKAN_INTERNAL_BufferTransitionToDefaultUsage( 8416 renderer, 8417 vulkanCommandBuffer, 8418 VULKAN_BUFFER_USAGE_MODE_COMPUTE_STORAGE_READ, 8419 vulkanCommandBuffer->readOnlyComputeStorageBuffers[firstSlot + i]); 8420 } 8421 8422 /* Then transition the new buffer and prepare it for binding */ 8423 VULKAN_INTERNAL_BufferTransitionFromDefaultUsage( 8424 renderer, 8425 vulkanCommandBuffer, 8426 VULKAN_BUFFER_USAGE_MODE_COMPUTE_STORAGE_READ, 8427 bufferContainer->activeBuffer); 8428 8429 VULKAN_INTERNAL_TrackBuffer( 8430 vulkanCommandBuffer, 8431 bufferContainer->activeBuffer); 8432 8433 vulkanCommandBuffer->readOnlyComputeStorageBuffers[firstSlot + i] = bufferContainer->activeBuffer; 8434 vulkanCommandBuffer->readOnlyComputeStorageBufferBindings[firstSlot + i] = bufferContainer->activeBuffer->buffer; 8435 vulkanCommandBuffer->needNewComputeReadOnlyDescriptorSet = true; 8436 } 8437 } 8438} 8439 8440static void VULKAN_PushComputeUniformData( 8441 SDL_GPUCommandBuffer *commandBuffer, 8442 Uint32 slotIndex, 8443 const void *data, 8444 Uint32 length) 8445{ 8446 VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; 8447 8448 VULKAN_INTERNAL_PushUniformData( 8449 vulkanCommandBuffer, 8450 VULKAN_UNIFORM_BUFFER_STAGE_COMPUTE, 8451 slotIndex, 8452 data, 8453 length); 8454} 8455 8456static void VULKAN_INTERNAL_BindComputeDescriptorSets( 8457 VulkanRenderer *renderer, 8458 VulkanCommandBuffer *commandBuffer) 8459{ 8460 VulkanComputePipelineResourceLayout *resourceLayout; 8461 DescriptorSetLayout *descriptorSetLayout; 8462 VkWriteDescriptorSet writeDescriptorSets[ 8463 MAX_TEXTURE_SAMPLERS_PER_STAGE + 8464 MAX_STORAGE_TEXTURES_PER_STAGE + 8465 MAX_STORAGE_BUFFERS_PER_STAGE + 8466 MAX_COMPUTE_WRITE_TEXTURES + 8467 MAX_COMPUTE_WRITE_BUFFERS + 8468 MAX_UNIFORM_BUFFERS_PER_STAGE]; 8469 VkDescriptorBufferInfo bufferInfos[MAX_STORAGE_BUFFERS_PER_STAGE + MAX_COMPUTE_WRITE_BUFFERS + MAX_UNIFORM_BUFFERS_PER_STAGE]; 8470 VkDescriptorImageInfo imageInfos[MAX_TEXTURE_SAMPLERS_PER_STAGE + MAX_STORAGE_TEXTURES_PER_STAGE + MAX_COMPUTE_WRITE_TEXTURES]; 8471 Uint32 dynamicOffsets[MAX_UNIFORM_BUFFERS_PER_STAGE]; 8472 Uint32 writeCount = 0; 8473 Uint32 bufferInfoCount = 0; 8474 Uint32 imageInfoCount = 0; 8475 Uint32 dynamicOffsetCount = 0; 8476 8477 if ( 8478 !commandBuffer->needNewComputeReadOnlyDescriptorSet && 8479 !commandBuffer->needNewComputeReadWriteDescriptorSet && 8480 !commandBuffer->needNewComputeUniformDescriptorSet && 8481 !commandBuffer->needNewComputeUniformOffsets 8482 ) { 8483 return; 8484 } 8485 8486 resourceLayout = commandBuffer->currentComputePipeline->resourceLayout; 8487 8488 if (commandBuffer->needNewComputeReadOnlyDescriptorSet) { 8489 descriptorSetLayout = resourceLayout->descriptorSetLayouts[0]; 8490 8491 commandBuffer->computeReadOnlyDescriptorSet = VULKAN_INTERNAL_FetchDescriptorSet( 8492 renderer, 8493 commandBuffer, 8494 descriptorSetLayout); 8495 8496 for (Uint32 i = 0; i < resourceLayout->numSamplers; i += 1) { 8497 VkWriteDescriptorSet *currentWriteDescriptorSet = &writeDescriptorSets[writeCount]; 8498 8499 currentWriteDescriptorSet->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; 8500 currentWriteDescriptorSet->pNext = NULL; 8501 currentWriteDescriptorSet->descriptorCount = 1; 8502 currentWriteDescriptorSet->descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; 8503 currentWriteDescriptorSet->dstArrayElement = 0; 8504 currentWriteDescriptorSet->dstBinding = i; 8505 currentWriteDescriptorSet->dstSet = commandBuffer->computeReadOnlyDescriptorSet; 8506 currentWriteDescriptorSet->pTexelBufferView = NULL; 8507 currentWriteDescriptorSet->pBufferInfo = NULL; 8508 8509 imageInfos[imageInfoCount].sampler = commandBuffer->computeSamplerBindings[i]; 8510 imageInfos[imageInfoCount].imageView = commandBuffer->computeSamplerTextureViewBindings[i]; 8511 imageInfos[imageInfoCount].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; 8512 8513 currentWriteDescriptorSet->pImageInfo = &imageInfos[imageInfoCount]; 8514 8515 writeCount += 1; 8516 imageInfoCount += 1; 8517 } 8518 8519 for (Uint32 i = 0; i < resourceLayout->numReadonlyStorageTextures; i += 1) { 8520 VkWriteDescriptorSet *currentWriteDescriptorSet = &writeDescriptorSets[writeCount]; 8521 8522 currentWriteDescriptorSet->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; 8523 currentWriteDescriptorSet->pNext = NULL; 8524 currentWriteDescriptorSet->descriptorCount = 1; 8525 currentWriteDescriptorSet->descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE; // Yes, we are declaring the readonly storage texture as a sampled image, because shaders are stupid. 8526 currentWriteDescriptorSet->dstArrayElement = 0; 8527 currentWriteDescriptorSet->dstBinding = resourceLayout->numSamplers + i; 8528 currentWriteDescriptorSet->dstSet = commandBuffer->computeReadOnlyDescriptorSet; 8529 currentWriteDescriptorSet->pTexelBufferView = NULL; 8530 currentWriteDescriptorSet->pBufferInfo = NULL; 8531 8532 imageInfos[imageInfoCount].sampler = VK_NULL_HANDLE; 8533 imageInfos[imageInfoCount].imageView = commandBuffer->readOnlyComputeStorageTextureViewBindings[i]; 8534 imageInfos[imageInfoCount].imageLayout = VK_IMAGE_LAYOUT_GENERAL; 8535 8536 currentWriteDescriptorSet->pImageInfo = &imageInfos[imageInfoCount]; 8537 8538 writeCount += 1; 8539 imageInfoCount += 1; 8540 } 8541 8542 for (Uint32 i = 0; i < resourceLayout->numReadonlyStorageBuffers; i += 1) { 8543 VkWriteDescriptorSet *currentWriteDescriptorSet = &writeDescriptorSets[writeCount]; 8544 8545 currentWriteDescriptorSet->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; 8546 currentWriteDescriptorSet->pNext = NULL; 8547 currentWriteDescriptorSet->descriptorCount = 1; 8548 currentWriteDescriptorSet->descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; 8549 currentWriteDescriptorSet->dstArrayElement = 0; 8550 currentWriteDescriptorSet->dstBinding = resourceLayout->numSamplers + resourceLayout->numReadonlyStorageTextures + i; 8551 currentWriteDescriptorSet->dstSet = commandBuffer->computeReadOnlyDescriptorSet; 8552 currentWriteDescriptorSet->pTexelBufferView = NULL; 8553 currentWriteDescriptorSet->pImageInfo = NULL; 8554 8555 bufferInfos[bufferInfoCount].buffer = commandBuffer->readOnlyComputeStorageBufferBindings[i]; 8556 bufferInfos[bufferInfoCount].offset = 0; 8557 bufferInfos[bufferInfoCount].range = VK_WHOLE_SIZE; 8558 8559 currentWriteDescriptorSet->pBufferInfo = &bufferInfos[bufferInfoCount]; 8560 8561 writeCount += 1; 8562 bufferInfoCount += 1; 8563 } 8564 8565 commandBuffer->needNewComputeReadOnlyDescriptorSet = false; 8566 } 8567 8568 if (commandBuffer->needNewComputeReadWriteDescriptorSet) { 8569 descriptorSetLayout = resourceLayout->descriptorSetLayouts[1]; 8570 8571 commandBuffer->computeReadWriteDescriptorSet = VULKAN_INTERNAL_FetchDescriptorSet( 8572 renderer, 8573 commandBuffer, 8574 descriptorSetLayout); 8575 8576 for (Uint32 i = 0; i < resourceLayout->numReadWriteStorageTextures; i += 1) { 8577 VkWriteDescriptorSet *currentWriteDescriptorSet = &writeDescriptorSets[writeCount]; 8578 8579 currentWriteDescriptorSet->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; 8580 currentWriteDescriptorSet->pNext = NULL; 8581 currentWriteDescriptorSet->descriptorCount = 1; 8582 currentWriteDescriptorSet->descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; 8583 currentWriteDescriptorSet->dstArrayElement = 0; 8584 currentWriteDescriptorSet->dstBinding = i; 8585 currentWriteDescriptorSet->dstSet = commandBuffer->computeReadWriteDescriptorSet; 8586 currentWriteDescriptorSet->pTexelBufferView = NULL; 8587 currentWriteDescriptorSet->pBufferInfo = NULL; 8588 8589 imageInfos[imageInfoCount].sampler = VK_NULL_HANDLE; 8590 imageInfos[imageInfoCount].imageView = commandBuffer->readWriteComputeStorageTextureViewBindings[i]; 8591 imageInfos[imageInfoCount].imageLayout = VK_IMAGE_LAYOUT_GENERAL; 8592 8593 currentWriteDescriptorSet->pImageInfo = &imageInfos[imageInfoCount]; 8594 8595 writeCount += 1; 8596 imageInfoCount += 1; 8597 } 8598 8599 for (Uint32 i = 0; i < resourceLayout->numReadWriteStorageBuffers; i += 1) { 8600 VkWriteDescriptorSet *currentWriteDescriptorSet = &writeDescriptorSets[writeCount]; 8601 8602 currentWriteDescriptorSet->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; 8603 currentWriteDescriptorSet->pNext = NULL; 8604 currentWriteDescriptorSet->descriptorCount = 1; 8605 currentWriteDescriptorSet->descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; 8606 currentWriteDescriptorSet->dstArrayElement = 0; 8607 currentWriteDescriptorSet->dstBinding = resourceLayout->numReadWriteStorageTextures + i; 8608 currentWriteDescriptorSet->dstSet = commandBuffer->computeReadWriteDescriptorSet; 8609 currentWriteDescriptorSet->pTexelBufferView = NULL; 8610 currentWriteDescriptorSet->pImageInfo = NULL; 8611 8612 bufferInfos[bufferInfoCount].buffer = commandBuffer->readWriteComputeStorageBufferBindings[i]; 8613 bufferInfos[bufferInfoCount].offset = 0; 8614 bufferInfos[bufferInfoCount].range = VK_WHOLE_SIZE; 8615 8616 currentWriteDescriptorSet->pBufferInfo = &bufferInfos[bufferInfoCount]; 8617 8618 writeCount += 1; 8619 bufferInfoCount += 1; 8620 } 8621 8622 commandBuffer->needNewComputeReadWriteDescriptorSet = false; 8623 } 8624 8625 if (commandBuffer->needNewComputeUniformDescriptorSet) { 8626 descriptorSetLayout = resourceLayout->descriptorSetLayouts[2]; 8627 8628 commandBuffer->computeUniformDescriptorSet = VULKAN_INTERNAL_FetchDescriptorSet( 8629 renderer, 8630 commandBuffer, 8631 descriptorSetLayout); 8632 8633 8634 for (Uint32 i = 0; i < resourceLayout->numUniformBuffers; i += 1) { 8635 VkWriteDescriptorSet *currentWriteDescriptorSet = &writeDescriptorSets[writeCount]; 8636 8637 currentWriteDescriptorSet->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; 8638 currentWriteDescriptorSet->pNext = NULL; 8639 currentWriteDescriptorSet->descriptorCount = 1; 8640 currentWriteDescriptorSet->descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC; 8641 currentWriteDescriptorSet->dstArrayElement = 0; 8642 currentWriteDescriptorSet->dstBinding = i; 8643 currentWriteDescriptorSet->dstSet = commandBuffer->computeUniformDescriptorSet; 8644 currentWriteDescriptorSet->pTexelBufferView = NULL; 8645 currentWriteDescriptorSet->pImageInfo = NULL; 8646 8647 bufferInfos[bufferInfoCount].buffer = commandBuffer->computeUniformBuffers[i]->buffer->buffer; 8648 bufferInfos[bufferInfoCount].offset = 0; 8649 bufferInfos[bufferInfoCount].range = MAX_UBO_SECTION_SIZE; 8650 8651 currentWriteDescriptorSet->pBufferInfo = &bufferInfos[bufferInfoCount]; 8652 8653 writeCount += 1; 8654 bufferInfoCount += 1; 8655 } 8656 8657 commandBuffer->needNewComputeUniformDescriptorSet = false; 8658 } 8659 8660 for (Uint32 i = 0; i < resourceLayout->numUniformBuffers; i += 1) { 8661 dynamicOffsets[i] = commandBuffer->computeUniformBuffers[i]->drawOffset; 8662 dynamicOffsetCount += 1; 8663 } 8664 8665 renderer->vkUpdateDescriptorSets( 8666 renderer->logicalDevice, 8667 writeCount, 8668 writeDescriptorSets, 8669 0, 8670 NULL); 8671 8672 VkDescriptorSet sets[3]; 8673 sets[0] = commandBuffer->computeReadOnlyDescriptorSet; 8674 sets[1] = commandBuffer->computeReadWriteDescriptorSet; 8675 sets[2] = commandBuffer->computeUniformDescriptorSet; 8676 8677 renderer->vkCmdBindDescriptorSets( 8678 commandBuffer->commandBuffer, 8679 VK_PIPELINE_BIND_POINT_COMPUTE, 8680 resourceLayout->pipelineLayout, 8681 0, 8682 3, 8683 sets, 8684 dynamicOffsetCount, 8685 dynamicOffsets); 8686 8687 commandBuffer->needNewComputeUniformOffsets = false; 8688} 8689 8690static void VULKAN_DispatchCompute( 8691 SDL_GPUCommandBuffer *commandBuffer, 8692 Uint32 groupcountX, 8693 Uint32 groupcountY, 8694 Uint32 groupcountZ) 8695{ 8696 VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; 8697 VulkanRenderer *renderer = vulkanCommandBuffer->renderer; 8698 8699 VULKAN_INTERNAL_BindComputeDescriptorSets(renderer, vulkanCommandBuffer); 8700 8701 renderer->vkCmdDispatch( 8702 vulkanCommandBuffer->commandBuffer, 8703 groupcountX, 8704 groupcountY, 8705 groupcountZ); 8706} 8707 8708static void VULKAN_DispatchComputeIndirect( 8709 SDL_GPUCommandBuffer *commandBuffer, 8710 SDL_GPUBuffer *buffer, 8711 Uint32 offset) 8712{ 8713 VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; 8714 VulkanRenderer *renderer = vulkanCommandBuffer->renderer; 8715 VulkanBuffer *vulkanBuffer = ((VulkanBufferContainer *)buffer)->activeBuffer; 8716 8717 VULKAN_INTERNAL_BindComputeDescriptorSets(renderer, vulkanCommandBuffer); 8718 8719 renderer->vkCmdDispatchIndirect( 8720 vulkanCommandBuffer->commandBuffer, 8721 vulkanBuffer->buffer, 8722 offset); 8723 8724 VULKAN_INTERNAL_TrackBuffer(vulkanCommandBuffer, vulkanBuffer); 8725} 8726 8727static void VULKAN_EndComputePass( 8728 SDL_GPUCommandBuffer *commandBuffer) 8729{ 8730 VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; 8731 Uint32 i; 8732 8733 for (i = 0; i < vulkanCommandBuffer->readWriteComputeStorageTextureSubresourceCount; i += 1) { 8734 VULKAN_INTERNAL_TextureSubresourceTransitionToDefaultUsage( 8735 vulkanCommandBuffer->renderer, 8736 vulkanCommandBuffer, 8737 VULKAN_TEXTURE_USAGE_MODE_COMPUTE_STORAGE_READ_WRITE, 8738 vulkanCommandBuffer->readWriteComputeStorageTextureSubresources[i]); 8739 vulkanCommandBuffer->readWriteComputeStorageTextureSubresources[i] = NULL; 8740 } 8741 vulkanCommandBuffer->readWriteComputeStorageTextureSubresourceCount = 0; 8742 8743 for (i = 0; i < MAX_COMPUTE_WRITE_BUFFERS; i += 1) { 8744 if (vulkanCommandBuffer->readWriteComputeStorageBuffers[i] != NULL) { 8745 VULKAN_INTERNAL_BufferTransitionToDefaultUsage( 8746 vulkanCommandBuffer->renderer, 8747 vulkanCommandBuffer, 8748 VULKAN_BUFFER_USAGE_MODE_COMPUTE_STORAGE_READ_WRITE, 8749 vulkanCommandBuffer->readWriteComputeStorageBuffers[i]); 8750 8751 vulkanCommandBuffer->readWriteComputeStorageBuffers[i] = NULL; 8752 } 8753 } 8754 8755 for (i = 0; i < MAX_STORAGE_TEXTURES_PER_STAGE; i += 1) { 8756 if (vulkanCommandBuffer->readOnlyComputeStorageTextures[i] != NULL) { 8757 VULKAN_INTERNAL_TextureTransitionToDefaultUsage( 8758 vulkanCommandBuffer->renderer, 8759 vulkanCommandBuffer, 8760 VULKAN_TEXTURE_USAGE_MODE_COMPUTE_STORAGE_READ, 8761 vulkanCommandBuffer->readOnlyComputeStorageTextures[i]); 8762 8763 vulkanCommandBuffer->readOnlyComputeStorageTextures[i] = NULL; 8764 } 8765 } 8766 8767 for (i = 0; i < MAX_STORAGE_BUFFERS_PER_STAGE; i += 1) { 8768 if (vulkanCommandBuffer->readOnlyComputeStorageBuffers[i] != NULL) { 8769 VULKAN_INTERNAL_BufferTransitionToDefaultUsage( 8770 vulkanCommandBuffer->renderer, 8771 vulkanCommandBuffer, 8772 VULKAN_BUFFER_USAGE_MODE_COMPUTE_STORAGE_READ, 8773 vulkanCommandBuffer->readOnlyComputeStorageBuffers[i]); 8774 8775 vulkanCommandBuffer->readOnlyComputeStorageBuffers[i] = NULL; 8776 } 8777 } 8778 8779 // we don't need a barrier for sampler resources because sampler state is always the default if sampler bit is set 8780 SDL_zeroa(vulkanCommandBuffer->computeSamplerTextureViewBindings); 8781 SDL_zeroa(vulkanCommandBuffer->computeSamplerBindings); 8782 8783 SDL_zeroa(vulkanCommandBuffer->readWriteComputeStorageTextureViewBindings); 8784 SDL_zeroa(vulkanCommandBuffer->readWriteComputeStorageBufferBindings); 8785 8786 vulkanCommandBuffer->currentComputePipeline = NULL; 8787 8788 vulkanCommandBuffer->computeReadOnlyDescriptorSet = VK_NULL_HANDLE; 8789 vulkanCommandBuffer->computeReadWriteDescriptorSet = VK_NULL_HANDLE; 8790 vulkanCommandBuffer->computeUniformDescriptorSet = VK_NULL_HANDLE; 8791} 8792 8793static void *VULKAN_MapTransferBuffer( 8794 SDL_GPURenderer *driverData, 8795 SDL_GPUTransferBuffer *transferBuffer, 8796 bool cycle) 8797{ 8798 VulkanRenderer *renderer = (VulkanRenderer *)driverData; 8799 VulkanBufferContainer *transferBufferContainer = (VulkanBufferContainer *)transferBuffer; 8800 8801 if ( 8802 cycle && 8803 SDL_GetAtomicInt(&transferBufferContainer->activeBuffer->referenceCount) > 0) { 8804 VULKAN_INTERNAL_CycleActiveBuffer( 8805 renderer, 8806 transferBufferContainer); 8807 } 8808 8809 Uint8 *bufferPointer = 8810 transferBufferContainer->activeBuffer->usedRegion->allocation->mapPointer + 8811 transferBufferContainer->activeBuffer->usedRegion->resourceOffset; 8812 8813 return bufferPointer; 8814} 8815 8816static void VULKAN_UnmapTransferBuffer( 8817 SDL_GPURenderer *driverData, 8818 SDL_GPUTransferBuffer *transferBuffer) 8819{ 8820 // no-op because transfer buffers are persistently mapped 8821 (void)driverData; 8822 (void)transferBuffer; 8823} 8824 8825static void VULKAN_BeginCopyPass( 8826 SDL_GPUCommandBuffer *commandBuffer) 8827{ 8828 // no-op 8829 (void)commandBuffer; 8830} 8831 8832static void VULKAN_UploadToTexture( 8833 SDL_GPUCommandBuffer *commandBuffer, 8834 const SDL_GPUTextureTransferInfo *source, 8835 const SDL_GPUTextureRegion *destination, 8836 bool cycle) 8837{ 8838 VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; 8839 VulkanRenderer *renderer = vulkanCommandBuffer->renderer; 8840 VulkanBufferContainer *transferBufferContainer = (VulkanBufferContainer *)source->transfer_buffer; 8841 VulkanTextureContainer *vulkanTextureContainer = (VulkanTextureContainer *)destination->texture; 8842 VulkanTextureSubresource *vulkanTextureSubresource; 8843 VkBufferImageCopy imageCopy; 8844 8845 SDL_LockRWLockForReading(renderer->defragLock); 8846 8847 // Note that the transfer buffer does not need a barrier, as it is synced by the client 8848 vulkanTextureSubresource = VULKAN_INTERNAL_PrepareTextureSubresourceForWrite( 8849 renderer, 8850 vulkanCommandBuffer, 8851 vulkanTextureContainer, 8852 destination->layer, 8853 destination->mip_level, 8854 cycle, 8855 VULKAN_TEXTURE_USAGE_MODE_COPY_DESTINATION); 8856 8857 imageCopy.imageExtent.width = destination->w; 8858 imageCopy.imageExtent.height = destination->h; 8859 imageCopy.imageExtent.depth = destination->d; 8860 imageCopy.imageOffset.x = destination->x; 8861 imageCopy.imageOffset.y = destination->y; 8862 imageCopy.imageOffset.z = destination->z; 8863 imageCopy.imageSubresource.aspectMask = vulkanTextureSubresource->parent->aspectFlags; 8864 imageCopy.imageSubresource.baseArrayLayer = destination->layer; 8865 imageCopy.imageSubresource.layerCount = 1; 8866 imageCopy.imageSubresource.mipLevel = destination->mip_level; 8867 imageCopy.bufferOffset = source->offset; 8868 imageCopy.bufferRowLength = source->pixels_per_row; 8869 imageCopy.bufferImageHeight = source->rows_per_layer; 8870 8871 renderer->vkCmdCopyBufferToImage( 8872 vulkanCommandBuffer->commandBuffer, 8873 transferBufferContainer->activeBuffer->buffer, 8874 vulkanTextureSubresource->parent->image, 8875 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 8876 1, 8877 &imageCopy); 8878 8879 VULKAN_INTERNAL_TextureSubresourceTransitionToDefaultUsage( 8880 renderer, 8881 vulkanCommandBuffer, 8882 VULKAN_TEXTURE_USAGE_MODE_COPY_DESTINATION, 8883 vulkanTextureSubresource); 8884 8885 VULKAN_INTERNAL_TrackBuffer(vulkanCommandBuffer, transferBufferContainer->activeBuffer); 8886 VULKAN_INTERNAL_TrackTexture(vulkanCommandBuffer, vulkanTextureSubresource->parent); 8887 VULKAN_INTERNAL_TrackTextureTransfer(vulkanCommandBuffer, vulkanTextureSubresource->parent); 8888 8889 SDL_UnlockRWLock(renderer->defragLock); 8890} 8891 8892static void VULKAN_UploadToBuffer( 8893 SDL_GPUCommandBuffer *commandBuffer, 8894 const SDL_GPUTransferBufferLocation *source, 8895 const SDL_GPUBufferRegion *destination, 8896 bool cycle) 8897{ 8898 VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; 8899 VulkanRenderer *renderer = vulkanCommandBuffer->renderer; 8900 VulkanBufferContainer *transferBufferContainer = (VulkanBufferContainer *)source->transfer_buffer; 8901 VulkanBufferContainer *bufferContainer = (VulkanBufferContainer *)destination->buffer; 8902 VkBufferCopy bufferCopy; 8903 8904 SDL_LockRWLockForReading(renderer->defragLock); 8905 8906 // Note that the transfer buffer does not need a barrier, as it is synced by the client 8907 VulkanBuffer *vulkanBuffer = VULKAN_INTERNAL_PrepareBufferForWrite( 8908 renderer, 8909 vulkanCommandBuffer, 8910 bufferContainer, 8911 cycle, 8912 VULKAN_BUFFER_USAGE_MODE_COPY_DESTINATION); 8913 8914 8915 bufferCopy.srcOffset = source->offset; 8916 bufferCopy.dstOffset = destination->offset; 8917 bufferCopy.size = destination->size; 8918 8919 renderer->vkCmdCopyBuffer( 8920 vulkanCommandBuffer->commandBuffer, 8921 transferBufferContainer->activeBuffer->buffer, 8922 vulkanBuffer->buffer, 8923 1, 8924 &bufferCopy); 8925 8926 VULKAN_INTERNAL_BufferTransitionToDefaultUsage( 8927 renderer, 8928 vulkanCommandBuffer, 8929 VULKAN_BUFFER_USAGE_MODE_COPY_DESTINATION, 8930 vulkanBuffer); 8931 8932 VULKAN_INTERNAL_TrackBuffer(vulkanCommandBuffer, transferBufferContainer->activeBuffer); 8933 VULKAN_INTERNAL_TrackBuffer(vulkanCommandBuffer, vulkanBuffer); 8934 VULKAN_INTERNAL_TrackBufferTransfer(vulkanCommandBuffer, vulkanBuffer); 8935 8936 SDL_UnlockRWLock(renderer->defragLock); 8937} 8938 8939// Readback 8940 8941static void VULKAN_DownloadFromTexture( 8942 SDL_GPUCommandBuffer *commandBuffer, 8943 const SDL_GPUTextureRegion *source, 8944 const SDL_GPUTextureTransferInfo *destination) 8945{ 8946 VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; 8947 VulkanRenderer *renderer = vulkanCommandBuffer->renderer; 8948 VulkanTextureContainer *textureContainer = (VulkanTextureContainer *)source->texture; 8949 VulkanTextureSubresource *vulkanTextureSubresource; 8950 VulkanBufferContainer *transferBufferContainer = (VulkanBufferContainer *)destination->transfer_buffer; 8951 VkBufferImageCopy imageCopy; 8952 8953 SDL_LockRWLockForReading(renderer->defragLock); 8954 8955 vulkanTextureSubresource = VULKAN_INTERNAL_FetchTextureSubresource( 8956 textureContainer, 8957 source->layer, 8958 source->mip_level); 8959 8960 // Note that the transfer buffer does not need a barrier, as it is synced by the client 8961 8962 VULKAN_INTERNAL_TextureSubresourceTransitionFromDefaultUsage( 8963 renderer, 8964 vulkanCommandBuffer, 8965 VULKAN_TEXTURE_USAGE_MODE_COPY_SOURCE, 8966 vulkanTextureSubresource); 8967 8968 imageCopy.imageExtent.width = source->w; 8969 imageCopy.imageExtent.height = source->h; 8970 imageCopy.imageExtent.depth = source->d; 8971 imageCopy.imageOffset.x = source->x; 8972 imageCopy.imageOffset.y = source->y; 8973 imageCopy.imageOffset.z = source->z; 8974 imageCopy.imageSubresource.aspectMask = vulkanTextureSubresource->parent->aspectFlags; 8975 imageCopy.imageSubresource.baseArrayLayer = source->layer; 8976 imageCopy.imageSubresource.layerCount = 1; 8977 imageCopy.imageSubresource.mipLevel = source->mip_level; 8978 imageCopy.bufferOffset = destination->offset; 8979 imageCopy.bufferRowLength = destination->pixels_per_row; 8980 imageCopy.bufferImageHeight = destination->rows_per_layer; 8981 8982 renderer->vkCmdCopyImageToBuffer( 8983 vulkanCommandBuffer->commandBuffer, 8984 vulkanTextureSubresource->parent->image, 8985 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, 8986 transferBufferContainer->activeBuffer->buffer, 8987 1, 8988 &imageCopy); 8989 8990 VULKAN_INTERNAL_TextureSubresourceTransitionToDefaultUsage( 8991 renderer, 8992 vulkanCommandBuffer, 8993 VULKAN_TEXTURE_USAGE_MODE_COPY_SOURCE, 8994 vulkanTextureSubresource); 8995 8996 VULKAN_INTERNAL_TrackBuffer(vulkanCommandBuffer, transferBufferContainer->activeBuffer); 8997 VULKAN_INTERNAL_TrackTexture(vulkanCommandBuffer, vulkanTextureSubresource->parent); 8998 VULKAN_INTERNAL_TrackTextureTransfer(vulkanCommandBuffer, vulkanTextureSubresource->parent); 8999 9000 SDL_UnlockRWLock(renderer->defragLock); 9001} 9002 9003static void VULKAN_DownloadFromBuffer( 9004 SDL_GPUCommandBuffer *commandBuffer, 9005 const SDL_GPUBufferRegion *source, 9006 const SDL_GPUTransferBufferLocation *destination) 9007{ 9008 VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; 9009 VulkanRenderer *renderer = vulkanCommandBuffer->renderer; 9010 VulkanBufferContainer *bufferContainer = (VulkanBufferContainer *)source->buffer; 9011 VulkanBufferContainer *transferBufferContainer = (VulkanBufferContainer *)destination->transfer_buffer; 9012 VkBufferCopy bufferCopy; 9013 9014 SDL_LockRWLockForReading(renderer->defragLock); 9015 9016 // Note that transfer buffer does not need a barrier, as it is synced by the client 9017 VULKAN_INTERNAL_BufferTransitionFromDefaultUsage( 9018 renderer, 9019 vulkanCommandBuffer, 9020 VULKAN_BUFFER_USAGE_MODE_COPY_SOURCE, 9021 bufferContainer->activeBuffer); 9022 9023 bufferCopy.srcOffset = source->offset; 9024 bufferCopy.dstOffset = destination->offset; 9025 bufferCopy.size = source->size; 9026 9027 renderer->vkCmdCopyBuffer( 9028 vulkanCommandBuffer->commandBuffer, 9029 bufferContainer->activeBuffer->buffer, 9030 transferBufferContainer->activeBuffer->buffer, 9031 1, 9032 &bufferCopy); 9033 9034 VULKAN_INTERNAL_BufferTransitionToDefaultUsage( 9035 renderer, 9036 vulkanCommandBuffer, 9037 VULKAN_BUFFER_USAGE_MODE_COPY_SOURCE, 9038 bufferContainer->activeBuffer); 9039 9040 VULKAN_INTERNAL_TrackBuffer(vulkanCommandBuffer, transferBufferContainer->activeBuffer); 9041 VULKAN_INTERNAL_TrackBuffer(vulkanCommandBuffer, bufferContainer->activeBuffer); 9042 VULKAN_INTERNAL_TrackBufferTransfer(vulkanCommandBuffer, bufferContainer->activeBuffer); 9043 9044 SDL_UnlockRWLock(renderer->defragLock); 9045} 9046 9047static void VULKAN_CopyTextureToTexture( 9048 SDL_GPUCommandBuffer *commandBuffer, 9049 const SDL_GPUTextureLocation *source, 9050 const SDL_GPUTextureLocation *destination, 9051 Uint32 w, 9052 Uint32 h, 9053 Uint32 d, 9054 bool cycle) 9055{ 9056 VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; 9057 VulkanRenderer *renderer = vulkanCommandBuffer->renderer; 9058 VulkanTextureSubresource *srcSubresource; 9059 VulkanTextureSubresource *dstSubresource; 9060 VkImageCopy imageCopy; 9061 9062 SDL_LockRWLockForReading(renderer->defragLock); 9063 9064 srcSubresource = VULKAN_INTERNAL_FetchTextureSubresource( 9065 (VulkanTextureContainer *)source->texture, 9066 source->layer, 9067 source->mip_level); 9068 9069 dstSubresource = VULKAN_INTERNAL_PrepareTextureSubresourceForWrite( 9070 renderer, 9071 vulkanCommandBuffer, 9072 (VulkanTextureContainer *)destination->texture, 9073 destination->layer, 9074 destination->mip_level, 9075 cycle, 9076 VULKAN_TEXTURE_USAGE_MODE_COPY_DESTINATION); 9077 9078 VULKAN_INTERNAL_TextureSubresourceTransitionFromDefaultUsage( 9079 renderer, 9080 vulkanCommandBuffer, 9081 VULKAN_TEXTURE_USAGE_MODE_COPY_SOURCE, 9082 srcSubresource); 9083 9084 imageCopy.srcOffset.x = source->x; 9085 imageCopy.srcOffset.y = source->y; 9086 imageCopy.srcOffset.z = source->z; 9087 imageCopy.srcSubresource.aspectMask = srcSubresource->parent->aspectFlags; 9088 imageCopy.srcSubresource.baseArrayLayer = source->layer; 9089 imageCopy.srcSubresource.layerCount = 1; 9090 imageCopy.srcSubresource.mipLevel = source->mip_level; 9091 imageCopy.dstOffset.x = destination->x; 9092 imageCopy.dstOffset.y = destination->y; 9093 imageCopy.dstOffset.z = destination->z; 9094 imageCopy.dstSubresource.aspectMask = dstSubresource->parent->aspectFlags; 9095 imageCopy.dstSubresource.baseArrayLayer = destination->layer; 9096 imageCopy.dstSubresource.layerCount = 1; 9097 imageCopy.dstSubresource.mipLevel = destination->mip_level; 9098 imageCopy.extent.width = w; 9099 imageCopy.extent.height = h; 9100 imageCopy.extent.depth = d; 9101 9102 renderer->vkCmdCopyImage( 9103 vulkanCommandBuffer->commandBuffer, 9104 srcSubresource->parent->image, 9105 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, 9106 dstSubresource->parent->image, 9107 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 9108 1, 9109 &imageCopy); 9110 9111 VULKAN_INTERNAL_TextureSubresourceTransitionToDefaultUsage( 9112 renderer, 9113 vulkanCommandBuffer, 9114 VULKAN_TEXTURE_USAGE_MODE_COPY_SOURCE, 9115 srcSubresource); 9116 9117 VULKAN_INTERNAL_TextureSubresourceTransitionToDefaultUsage( 9118 renderer, 9119 vulkanCommandBuffer, 9120 VULKAN_TEXTURE_USAGE_MODE_COPY_DESTINATION, 9121 dstSubresource); 9122 9123 VULKAN_INTERNAL_TrackTexture(vulkanCommandBuffer, srcSubresource->parent); 9124 VULKAN_INTERNAL_TrackTexture(vulkanCommandBuffer, dstSubresource->parent); 9125 VULKAN_INTERNAL_TrackTextureTransfer(vulkanCommandBuffer, srcSubresource->parent); 9126 VULKAN_INTERNAL_TrackTextureTransfer(vulkanCommandBuffer, dstSubresource->parent); 9127 9128 SDL_UnlockRWLock(renderer->defragLock); 9129} 9130 9131static void VULKAN_CopyBufferToBuffer( 9132 SDL_GPUCommandBuffer *commandBuffer, 9133 const SDL_GPUBufferLocation *source, 9134 const SDL_GPUBufferLocation *destination, 9135 Uint32 size, 9136 bool cycle) 9137{ 9138 VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; 9139 VulkanRenderer *renderer = vulkanCommandBuffer->renderer; 9140 VulkanBufferContainer *srcContainer = (VulkanBufferContainer *)source->buffer; 9141 VulkanBufferContainer *dstContainer = (VulkanBufferContainer *)destination->buffer; 9142 VkBufferCopy bufferCopy; 9143 9144 SDL_LockRWLockForReading(renderer->defragLock); 9145 9146 VulkanBuffer *dstBuffer = VULKAN_INTERNAL_PrepareBufferForWrite( 9147 renderer, 9148 vulkanCommandBuffer, 9149 dstContainer, 9150 cycle, 9151 VULKAN_BUFFER_USAGE_MODE_COPY_DESTINATION); 9152 9153 VULKAN_INTERNAL_BufferTransitionFromDefaultUsage( 9154 renderer, 9155 vulkanCommandBuffer, 9156 VULKAN_BUFFER_USAGE_MODE_COPY_SOURCE, 9157 srcContainer->activeBuffer); 9158 9159 bufferCopy.srcOffset = source->offset; 9160 bufferCopy.dstOffset = destination->offset; 9161 bufferCopy.size = size; 9162 9163 renderer->vkCmdCopyBuffer( 9164 vulkanCommandBuffer->commandBuffer, 9165 srcContainer->activeBuffer->buffer, 9166 dstBuffer->buffer, 9167 1, 9168 &bufferCopy); 9169 9170 VULKAN_INTERNAL_BufferTransitionToDefaultUsage( 9171 renderer, 9172 vulkanCommandBuffer, 9173 VULKAN_BUFFER_USAGE_MODE_COPY_SOURCE, 9174 srcContainer->activeBuffer); 9175 9176 VULKAN_INTERNAL_BufferTransitionToDefaultUsage( 9177 renderer, 9178 vulkanCommandBuffer, 9179 VULKAN_BUFFER_USAGE_MODE_COPY_DESTINATION, 9180 dstBuffer); 9181 9182 VULKAN_INTERNAL_TrackBuffer(vulkanCommandBuffer, srcContainer->activeBuffer); 9183 VULKAN_INTERNAL_TrackBuffer(vulkanCommandBuffer, dstBuffer); 9184 VULKAN_INTERNAL_TrackBufferTransfer(vulkanCommandBuffer, srcContainer->activeBuffer); 9185 VULKAN_INTERNAL_TrackBufferTransfer(vulkanCommandBuffer, dstBuffer); 9186 9187 SDL_UnlockRWLock(renderer->defragLock); 9188} 9189 9190static void VULKAN_GenerateMipmaps( 9191 SDL_GPUCommandBuffer *commandBuffer, 9192 SDL_GPUTexture *texture) 9193{ 9194 VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; 9195 VulkanRenderer *renderer = vulkanCommandBuffer->renderer; 9196 VulkanTextureContainer *container = (VulkanTextureContainer *)texture; 9197 VulkanTextureSubresource *srcTextureSubresource; 9198 VulkanTextureSubresource *dstTextureSubresource; 9199 VkImageBlit blit; 9200 9201 SDL_LockRWLockForReading(renderer->defragLock); 9202 9203 // Blit each slice sequentially. Barriers, barriers everywhere! 9204 for (Uint32 layerOrDepthIndex = 0; layerOrDepthIndex < container->header.info.layer_count_or_depth; layerOrDepthIndex += 1) { 9205 for (Uint32 level = 1; level < container->header.info.num_levels; level += 1) { 9206 Uint32 layer = container->header.info.type == SDL_GPU_TEXTURETYPE_3D ? 0 : layerOrDepthIndex; 9207 Uint32 depth = container->header.info.type == SDL_GPU_TEXTURETYPE_3D ? layerOrDepthIndex : 0; 9208 9209 Uint32 srcSubresourceIndex = VULKAN_INTERNAL_GetTextureSubresourceIndex( 9210 level - 1, 9211 layer, 9212 container->header.info.num_levels); 9213 Uint32 dstSubresourceIndex = VULKAN_INTERNAL_GetTextureSubresourceIndex( 9214 level, 9215 layer, 9216 container->header.info.num_levels); 9217 9218 srcTextureSubresource = &container->activeTexture->subresources[srcSubresourceIndex]; 9219 dstTextureSubresource = &container->activeTexture->subresources[dstSubresourceIndex]; 9220 9221 VULKAN_INTERNAL_TextureSubresourceTransitionFromDefaultUsage( 9222 renderer, 9223 vulkanCommandBuffer, 9224 VULKAN_TEXTURE_USAGE_MODE_COPY_SOURCE, 9225 srcTextureSubresource); 9226 9227 VULKAN_INTERNAL_TextureSubresourceTransitionFromDefaultUsage( 9228 renderer, 9229 vulkanCommandBuffer, 9230 VULKAN_TEXTURE_USAGE_MODE_COPY_DESTINATION, 9231 dstTextureSubresource); 9232 9233 blit.srcOffsets[0].x = 0; 9234 blit.srcOffsets[0].y = 0; 9235 blit.srcOffsets[0].z = depth; 9236 9237 blit.srcOffsets[1].x = container->header.info.width >> (level - 1); 9238 blit.srcOffsets[1].y = container->header.info.height >> (level - 1); 9239 blit.srcOffsets[1].z = depth + 1; 9240 9241 blit.dstOffsets[0].x = 0; 9242 blit.dstOffsets[0].y = 0; 9243 blit.dstOffsets[0].z = depth; 9244 9245 blit.dstOffsets[1].x = container->header.info.width >> level; 9246 blit.dstOffsets[1].y = container->header.info.height >> level; 9247 blit.dstOffsets[1].z = depth + 1; 9248 9249 blit.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; 9250 blit.srcSubresource.baseArrayLayer = layer; 9251 blit.srcSubresource.layerCount = 1; 9252 blit.srcSubresource.mipLevel = level - 1; 9253 9254 blit.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; 9255 blit.dstSubresource.baseArrayLayer = layer; 9256 blit.dstSubresource.layerCount = 1; 9257 blit.dstSubresource.mipLevel = level; 9258 9259 renderer->vkCmdBlitImage( 9260 vulkanCommandBuffer->commandBuffer, 9261 container->activeTexture->image, 9262 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, 9263 container->activeTexture->image, 9264 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 9265 1, 9266 &blit, 9267 VK_FILTER_LINEAR); 9268 9269 VULKAN_INTERNAL_TextureSubresourceTransitionToDefaultUsage( 9270 renderer, 9271 vulkanCommandBuffer, 9272 VULKAN_TEXTURE_USAGE_MODE_COPY_SOURCE, 9273 srcTextureSubresource); 9274 9275 VULKAN_INTERNAL_TextureSubresourceTransitionToDefaultUsage( 9276 renderer, 9277 vulkanCommandBuffer, 9278 VULKAN_TEXTURE_USAGE_MODE_COPY_DESTINATION, 9279 dstTextureSubresource); 9280 9281 VULKAN_INTERNAL_TrackTexture(vulkanCommandBuffer, srcTextureSubresource->parent); 9282 VULKAN_INTERNAL_TrackTexture(vulkanCommandBuffer, dstTextureSubresource->parent); 9283 VULKAN_INTERNAL_TrackTextureTransfer(vulkanCommandBuffer, srcTextureSubresource->parent); 9284 VULKAN_INTERNAL_TrackTextureTransfer(vulkanCommandBuffer, dstTextureSubresource->parent); 9285 9286 } 9287 } 9288 9289 SDL_UnlockRWLock(renderer->defragLock); 9290} 9291 9292static void VULKAN_EndCopyPass( 9293 SDL_GPUCommandBuffer *commandBuffer) 9294{ 9295 // no-op 9296 (void)commandBuffer; 9297} 9298 9299static void VULKAN_Blit( 9300 SDL_GPUCommandBuffer *commandBuffer, 9301 const SDL_GPUBlitInfo *info) 9302{ 9303 VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; 9304 VulkanRenderer *renderer = vulkanCommandBuffer->renderer; 9305 TextureCommonHeader *srcHeader = (TextureCommonHeader *)info->source.texture; 9306 TextureCommonHeader *dstHeader = (TextureCommonHeader *)info->destination.texture; 9307 VkImageBlit region; 9308 Uint32 srcLayer = srcHeader->info.type == SDL_GPU_TEXTURETYPE_3D ? 0 : info->source.layer_or_depth_plane; 9309 Uint32 srcDepth = srcHeader->info.type == SDL_GPU_TEXTURETYPE_3D ? info->source.layer_or_depth_plane : 0; 9310 Uint32 dstLayer = dstHeader->info.type == SDL_GPU_TEXTURETYPE_3D ? 0 : info->destination.layer_or_depth_plane; 9311 Uint32 dstDepth = dstHeader->info.type == SDL_GPU_TEXTURETYPE_3D ? info->destination.layer_or_depth_plane : 0; 9312 int32_t swap; 9313 9314 // Using BeginRenderPass to clear because vkCmdClearColorImage requires barriers anyway 9315 if (info->load_op == SDL_GPU_LOADOP_CLEAR) { 9316 SDL_GPUColorTargetInfo targetInfo; 9317 SDL_zero(targetInfo); 9318 targetInfo.texture = info->destination.texture; 9319 targetInfo.mip_level = info->destination.mip_level; 9320 targetInfo.layer_or_depth_plane = info->destination.layer_or_depth_plane; 9321 targetInfo.load_op = SDL_GPU_LOADOP_CLEAR; 9322 targetInfo.store_op = SDL_GPU_STOREOP_STORE; 9323 targetInfo.clear_color = info->clear_color; 9324 targetInfo.cycle = info->cycle; 9325 VULKAN_BeginRenderPass( 9326 commandBuffer, 9327 &targetInfo, 9328 1, 9329 NULL); 9330 VULKAN_EndRenderPass(commandBuffer); 9331 } 9332 9333 VulkanTextureSubresource *srcSubresource = VULKAN_INTERNAL_FetchTextureSubresource( 9334 (VulkanTextureContainer *)info->source.texture, 9335 srcLayer, 9336 info->source.mip_level); 9337 9338 VulkanTextureSubresource *dstSubresource = VULKAN_INTERNAL_PrepareTextureSubresourceForWrite( 9339 renderer, 9340 vulkanCommandBuffer, 9341 (VulkanTextureContainer *)info->destination.texture, 9342 dstLayer, 9343 info->destination.mip_level, 9344 info->cycle, 9345 VULKAN_TEXTURE_USAGE_MODE_COPY_DESTINATION); 9346 9347 VULKAN_INTERNAL_TextureSubresourceTransitionFromDefaultUsage( 9348 renderer, 9349 vulkanCommandBuffer, 9350 VULKAN_TEXTURE_USAGE_MODE_COPY_SOURCE, 9351 srcSubresource); 9352 9353 region.srcSubresource.aspectMask = srcSubresource->parent->aspectFlags; 9354 region.srcSubresource.baseArrayLayer = srcSubresource->layer; 9355 region.srcSubresource.layerCount = 1; 9356 region.srcSubresource.mipLevel = srcSubresource->level; 9357 region.srcOffsets[0].x = info->source.x; 9358 region.srcOffsets[0].y = info->source.y; 9359 region.srcOffsets[0].z = srcDepth; 9360 region.srcOffsets[1].x = info->source.x + info->source.w; 9361 region.srcOffsets[1].y = info->source.y + info->source.h; 9362 region.srcOffsets[1].z = srcDepth + 1; 9363 9364 if (info->flip_mode & SDL_FLIP_HORIZONTAL) { 9365 // flip the x positions 9366 swap = region.srcOffsets[0].x; 9367 region.srcOffsets[0].x = region.srcOffsets[1].x; 9368 region.srcOffsets[1].x = swap; 9369 } 9370 9371 if (info->flip_mode & SDL_FLIP_VERTICAL) { 9372 // flip the y positions 9373 swap = region.srcOffsets[0].y; 9374 region.srcOffsets[0].y = region.srcOffsets[1].y; 9375 region.srcOffsets[1].y = swap; 9376 } 9377 9378 region.dstSubresource.aspectMask = dstSubresource->parent->aspectFlags; 9379 region.dstSubresource.baseArrayLayer = dstSubresource->layer; 9380 region.dstSubresource.layerCount = 1; 9381 region.dstSubresource.mipLevel = dstSubresource->level; 9382 region.dstOffsets[0].x = info->destination.x; 9383 region.dstOffsets[0].y = info->destination.y; 9384 region.dstOffsets[0].z = dstDepth; 9385 region.dstOffsets[1].x = info->destination.x + info->destination.w; 9386 region.dstOffsets[1].y = info->destination.y + info->destination.h; 9387 region.dstOffsets[1].z = dstDepth + 1; 9388 9389 renderer->vkCmdBlitImage( 9390 vulkanCommandBuffer->commandBuffer, 9391 srcSubresource->parent->image, 9392 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, 9393 dstSubresource->parent->image, 9394 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 9395 1, 9396 &region, 9397 SDLToVK_Filter[info->filter]); 9398 9399 VULKAN_INTERNAL_TextureSubresourceTransitionToDefaultUsage( 9400 renderer, 9401 vulkanCommandBuffer, 9402 VULKAN_TEXTURE_USAGE_MODE_COPY_SOURCE, 9403 srcSubresource); 9404 9405 VULKAN_INTERNAL_TextureSubresourceTransitionToDefaultUsage( 9406 renderer, 9407 vulkanCommandBuffer, 9408 VULKAN_TEXTURE_USAGE_MODE_COPY_DESTINATION, 9409 dstSubresource); 9410 9411 VULKAN_INTERNAL_TrackTexture(vulkanCommandBuffer, srcSubresource->parent); 9412 VULKAN_INTERNAL_TrackTexture(vulkanCommandBuffer, dstSubresource->parent); 9413} 9414 9415static bool VULKAN_INTERNAL_AllocateCommandBuffer( 9416 VulkanRenderer *renderer, 9417 VulkanCommandPool *vulkanCommandPool) 9418{ 9419 VkCommandBufferAllocateInfo allocateInfo; 9420 VkResult vulkanResult; 9421 VkCommandBuffer commandBufferHandle; 9422 VulkanCommandBuffer *commandBuffer; 9423 9424 vulkanCommandPool->inactiveCommandBufferCapacity += 1; 9425 9426 vulkanCommandPool->inactiveCommandBuffers = SDL_realloc( 9427 vulkanCommandPool->inactiveCommandBuffers, 9428 sizeof(VulkanCommandBuffer *) * 9429 vulkanCommandPool->inactiveCommandBufferCapacity); 9430 9431 allocateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; 9432 allocateInfo.pNext = NULL; 9433 allocateInfo.commandPool = vulkanCommandPool->commandPool; 9434 allocateInfo.commandBufferCount = 1; 9435 allocateInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; 9436 9437 vulkanResult = renderer->vkAllocateCommandBuffers( 9438 renderer->logicalDevice, 9439 &allocateInfo, 9440 &commandBufferHandle); 9441 9442 CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkAllocateCommandBuffers, false); 9443 9444 commandBuffer = SDL_malloc(sizeof(VulkanCommandBuffer)); 9445 commandBuffer->renderer = renderer; 9446 commandBuffer->commandPool = vulkanCommandPool; 9447 commandBuffer->commandBuffer = commandBufferHandle; 9448 9449 commandBuffer->inFlightFence = VK_NULL_HANDLE; 9450 9451 // Presentation tracking 9452 9453 commandBuffer->presentDataCapacity = 1; 9454 commandBuffer->presentDataCount = 0; 9455 commandBuffer->presentDatas = SDL_malloc( 9456 commandBuffer->presentDataCapacity * sizeof(VulkanPresentData)); 9457 9458 commandBuffer->waitSemaphoreCapacity = 1; 9459 commandBuffer->waitSemaphoreCount = 0; 9460 commandBuffer->waitSemaphores = SDL_malloc( 9461 commandBuffer->waitSemaphoreCapacity * sizeof(VkSemaphore)); 9462 9463 commandBuffer->signalSemaphoreCapacity = 1; 9464 commandBuffer->signalSemaphoreCount = 0; 9465 commandBuffer->signalSemaphores = SDL_malloc( 9466 commandBuffer->signalSemaphoreCapacity * sizeof(VkSemaphore)); 9467 9468 // Resource bind tracking 9469 9470 commandBuffer->needVertexBufferBind = false; 9471 commandBuffer->needNewVertexResourceDescriptorSet = true; 9472 commandBuffer->needNewVertexUniformDescriptorSet = true; 9473 commandBuffer->needNewVertexUniformOffsets = true; 9474 commandBuffer->needNewFragmentResourceDescriptorSet = true; 9475 commandBuffer->needNewFragmentUniformDescriptorSet = true; 9476 commandBuffer->needNewFragmentUniformOffsets = true; 9477 9478 commandBuffer->needNewComputeReadWriteDescriptorSet = true; 9479 commandBuffer->needNewComputeReadOnlyDescriptorSet = true; 9480 commandBuffer->needNewComputeUniformDescriptorSet = true; 9481 commandBuffer->needNewComputeUniformOffsets = true; 9482 9483 commandBuffer->vertexResourceDescriptorSet = VK_NULL_HANDLE; 9484 commandBuffer->vertexUniformDescriptorSet = VK_NULL_HANDLE; 9485 commandBuffer->fragmentResourceDescriptorSet = VK_NULL_HANDLE; 9486 commandBuffer->fragmentUniformDescriptorSet = VK_NULL_HANDLE; 9487 9488 commandBuffer->computeReadOnlyDescriptorSet = VK_NULL_HANDLE; 9489 commandBuffer->computeReadWriteDescriptorSet = VK_NULL_HANDLE; 9490 commandBuffer->computeUniformDescriptorSet = VK_NULL_HANDLE; 9491 9492 // Resource tracking 9493 9494 commandBuffer->usedBufferCapacity = 4; 9495 commandBuffer->usedBufferCount = 0; 9496 commandBuffer->usedBuffers = SDL_malloc( 9497 commandBuffer->usedBufferCapacity * sizeof(VulkanBuffer *)); 9498 9499 commandBuffer->buffersUsedInPendingTransfersCapacity = 4; 9500 commandBuffer->buffersUsedInPendingTransfersCount = 0; 9501 commandBuffer->buffersUsedInPendingTransfers = SDL_malloc( 9502 commandBuffer->buffersUsedInPendingTransfersCapacity * sizeof(VulkanBuffer *)); 9503 9504 commandBuffer->usedTextureCapacity = 4; 9505 commandBuffer->usedTextureCount = 0; 9506 commandBuffer->usedTextures = SDL_malloc( 9507 commandBuffer->usedTextureCapacity * sizeof(VulkanTexture *)); 9508 9509 commandBuffer->texturesUsedInPendingTransfersCapacity = 4; 9510 commandBuffer->texturesUsedInPendingTransfersCount = 0; 9511 commandBuffer->texturesUsedInPendingTransfers = SDL_malloc( 9512 commandBuffer->texturesUsedInPendingTransfersCapacity * sizeof(VulkanTexture *)); 9513 9514 commandBuffer->usedSamplerCapacity = 4; 9515 commandBuffer->usedSamplerCount = 0; 9516 commandBuffer->usedSamplers = SDL_malloc( 9517 commandBuffer->usedSamplerCapacity * sizeof(VulkanSampler *)); 9518 9519 commandBuffer->usedGraphicsPipelineCapacity = 4; 9520 commandBuffer->usedGraphicsPipelineCount = 0; 9521 commandBuffer->usedGraphicsPipelines = SDL_malloc( 9522 commandBuffer->usedGraphicsPipelineCapacity * sizeof(VulkanGraphicsPipeline *)); 9523 9524 commandBuffer->usedComputePipelineCapacity = 4; 9525 commandBuffer->usedComputePipelineCount = 0; 9526 commandBuffer->usedComputePipelines = SDL_malloc( 9527 commandBuffer->usedComputePipelineCapacity * sizeof(VulkanComputePipeline *)); 9528 9529 commandBuffer->usedFramebufferCapacity = 4; 9530 commandBuffer->usedFramebufferCount = 0; 9531 commandBuffer->usedFramebuffers = SDL_malloc( 9532 commandBuffer->usedFramebufferCapacity * sizeof(VulkanFramebuffer *)); 9533 9534 commandBuffer->usedUniformBufferCapacity = 4; 9535 commandBuffer->usedUniformBufferCount = 0; 9536 commandBuffer->usedUniformBuffers = SDL_malloc( 9537 commandBuffer->usedUniformBufferCapacity * sizeof(VulkanUniformBuffer *)); 9538 9539 commandBuffer->swapchainRequested = false; 9540 9541 // Pool it! 9542 9543 vulkanCommandPool->inactiveCommandBuffers[vulkanCommandPool->inactiveCommandBufferCount] = commandBuffer; 9544 vulkanCommandPool->inactiveCommandBufferCount += 1; 9545 9546 return true; 9547} 9548 9549static VulkanCommandPool *VULKAN_INTERNAL_FetchCommandPool( 9550 VulkanRenderer *renderer, 9551 SDL_ThreadID threadID) 9552{ 9553 VulkanCommandPool *vulkanCommandPool = NULL; 9554 VkCommandPoolCreateInfo commandPoolCreateInfo; 9555 VkResult vulkanResult; 9556 CommandPoolHashTableKey key; 9557 key.threadID = threadID; 9558 9559 bool result = SDL_FindInHashTable( 9560 renderer->commandPoolHashTable, 9561 (const void *)&key, 9562 (const void **)&vulkanCommandPool); 9563 9564 if (result) { 9565 return vulkanCommandPool; 9566 } 9567 9568 vulkanCommandPool = (VulkanCommandPool *)SDL_malloc(sizeof(VulkanCommandPool)); 9569 9570 commandPoolCreateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; 9571 commandPoolCreateInfo.pNext = NULL; 9572 commandPoolCreateInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; 9573 commandPoolCreateInfo.queueFamilyIndex = renderer->queueFamilyIndex; 9574 9575 vulkanResult = renderer->vkCreateCommandPool( 9576 renderer->logicalDevice, 9577 &commandPoolCreateInfo, 9578 NULL, 9579 &vulkanCommandPool->commandPool); 9580 9581 if (vulkanResult != VK_SUCCESS) { 9582 SDL_free(vulkanCommandPool); 9583 CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkCreateCommandPool, NULL); 9584 return NULL; 9585 } 9586 9587 vulkanCommandPool->threadID = threadID; 9588 9589 vulkanCommandPool->inactiveCommandBufferCapacity = 0; 9590 vulkanCommandPool->inactiveCommandBufferCount = 0; 9591 vulkanCommandPool->inactiveCommandBuffers = NULL; 9592 9593 if (!VULKAN_INTERNAL_AllocateCommandBuffer( 9594 renderer, 9595 vulkanCommandPool)) { 9596 VULKAN_INTERNAL_DestroyCommandPool(renderer, vulkanCommandPool); 9597 return NULL; 9598 } 9599 9600 CommandPoolHashTableKey *allocedKey = SDL_malloc(sizeof(CommandPoolHashTableKey)); 9601 allocedKey->threadID = threadID; 9602 9603 SDL_InsertIntoHashTable( 9604 renderer->commandPoolHashTable, 9605 (const void *)allocedKey, 9606 (const void *)vulkanCommandPool, true); 9607 9608 return vulkanCommandPool; 9609} 9610 9611static VulkanCommandBuffer *VULKAN_INTERNAL_GetInactiveCommandBufferFromPool( 9612 VulkanRenderer *renderer, 9613 SDL_ThreadID threadID) 9614{ 9615 VulkanCommandPool *commandPool = 9616 VULKAN_INTERNAL_FetchCommandPool(renderer, threadID); 9617 VulkanCommandBuffer *commandBuffer; 9618 9619 if (commandPool == NULL) { 9620 return NULL; 9621 } 9622 9623 if (commandPool->inactiveCommandBufferCount == 0) { 9624 if (!VULKAN_INTERNAL_AllocateCommandBuffer( 9625 renderer, 9626 commandPool)) { 9627 return NULL; 9628 } 9629 } 9630 9631 commandBuffer = commandPool->inactiveCommandBuffers[commandPool->inactiveCommandBufferCount - 1]; 9632 commandPool->inactiveCommandBufferCount -= 1; 9633 9634 return commandBuffer; 9635} 9636 9637static SDL_GPUCommandBuffer *VULKAN_AcquireCommandBuffer( 9638 SDL_GPURenderer *driverData) 9639{ 9640 VulkanRenderer *renderer = (VulkanRenderer *)driverData; 9641 VkResult result; 9642 Uint32 i; 9643 9644 SDL_ThreadID threadID = SDL_GetCurrentThreadID(); 9645 9646 SDL_LockMutex(renderer->acquireCommandBufferLock); 9647 9648 VulkanCommandBuffer *commandBuffer = 9649 VULKAN_INTERNAL_GetInactiveCommandBufferFromPool(renderer, threadID); 9650 9651 if (commandBuffer == NULL) { 9652 SDL_UnlockMutex(renderer->acquireCommandBufferLock); 9653 return NULL; 9654 } 9655 9656 DescriptorSetCache *descriptorSetCache = 9657 VULKAN_INTERNAL_AcquireDescriptorSetCache(renderer); 9658 9659 SDL_UnlockMutex(renderer->acquireCommandBufferLock); 9660 9661 commandBuffer->descriptorSetCache = descriptorSetCache; 9662 9663 // Reset state 9664 9665 commandBuffer->currentComputePipeline = NULL; 9666 commandBuffer->currentGraphicsPipeline = NULL; 9667 9668 SDL_zeroa(commandBuffer->colorAttachmentSubresources); 9669 SDL_zeroa(commandBuffer->resolveAttachmentSubresources); 9670 commandBuffer->depthStencilAttachmentSubresource = NULL; 9671 commandBuffer->colorAttachmentSubresourceCount = 0; 9672 commandBuffer->resolveAttachmentSubresourceCount = 0; 9673 9674 for (i = 0; i < MAX_UNIFORM_BUFFERS_PER_STAGE; i += 1) { 9675 commandBuffer->vertexUniformBuffers[i] = NULL; 9676 commandBuffer->fragmentUniformBuffers[i] = NULL; 9677 commandBuffer->computeUniformBuffers[i] = NULL; 9678 } 9679 9680 commandBuffer->needVertexBufferBind = false; 9681 commandBuffer->needNewVertexResourceDescriptorSet = true; 9682 commandBuffer->needNewVertexUniformDescriptorSet = true; 9683 commandBuffer->needNewVertexUniformOffsets = true; 9684 commandBuffer->needNewFragmentResourceDescriptorSet = true; 9685 commandBuffer->needNewFragmentUniformDescriptorSet = true; 9686 commandBuffer->needNewFragmentUniformOffsets = true; 9687 9688 commandBuffer->needNewComputeReadOnlyDescriptorSet = true; 9689 commandBuffer->needNewComputeUniformDescriptorSet = true; 9690 commandBuffer->needNewComputeUniformOffsets = true; 9691 9692 commandBuffer->vertexResourceDescriptorSet = VK_NULL_HANDLE; 9693 commandBuffer->vertexUniformDescriptorSet = VK_NULL_HANDLE; 9694 commandBuffer->fragmentResourceDescriptorSet = VK_NULL_HANDLE; 9695 commandBuffer->fragmentUniformDescriptorSet = VK_NULL_HANDLE; 9696 9697 commandBuffer->computeReadOnlyDescriptorSet = VK_NULL_HANDLE; 9698 commandBuffer->computeReadWriteDescriptorSet = VK_NULL_HANDLE; 9699 commandBuffer->computeUniformDescriptorSet = VK_NULL_HANDLE; 9700 9701 SDL_zeroa(commandBuffer->vertexBuffers); 9702 SDL_zeroa(commandBuffer->vertexBufferOffsets); 9703 commandBuffer->vertexBufferCount = 0; 9704 9705 SDL_zeroa(commandBuffer->vertexSamplerTextureViewBindings); 9706 SDL_zeroa(commandBuffer->vertexSamplerBindings); 9707 SDL_zeroa(commandBuffer->vertexStorageTextureViewBindings); 9708 SDL_zeroa(commandBuffer->vertexStorageBufferBindings); 9709 9710 SDL_zeroa(commandBuffer->fragmentSamplerTextureViewBindings); 9711 SDL_zeroa(commandBuffer->fragmentSamplerBindings); 9712 SDL_zeroa(commandBuffer->fragmentStorageTextureViewBindings); 9713 SDL_zeroa(commandBuffer->fragmentStorageBufferBindings); 9714 9715 SDL_zeroa(commandBuffer->readWriteComputeStorageTextureSubresources); 9716 commandBuffer->readWriteComputeStorageTextureSubresourceCount = 0; 9717 SDL_zeroa(commandBuffer->readWriteComputeStorageBuffers); 9718 SDL_zeroa(commandBuffer->computeSamplerTextureViewBindings); 9719 SDL_zeroa(commandBuffer->computeSamplerBindings); 9720 SDL_zeroa(commandBuffer->readOnlyComputeStorageTextureViewBindings); 9721 SDL_zeroa(commandBuffer->readOnlyComputeStorageBufferBindings); 9722 SDL_zeroa(commandBuffer->readOnlyComputeStorageTextures); 9723 SDL_zeroa(commandBuffer->readOnlyComputeStorageBuffers); 9724 9725 commandBuffer->autoReleaseFence = true; 9726 9727 commandBuffer->swapchainRequested = false; 9728 commandBuffer->isDefrag = 0; 9729 9730 /* Reset the command buffer here to avoid resets being called 9731 * from a separate thread than where the command buffer was acquired 9732 */ 9733 result = renderer->vkResetCommandBuffer( 9734 commandBuffer->commandBuffer, 9735 VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT); 9736 9737 CHECK_VULKAN_ERROR_AND_RETURN(result, vkResetCommandBuffer, NULL); 9738 9739 if (!VULKAN_INTERNAL_BeginCommandBuffer(renderer, commandBuffer)) { 9740 return NULL; 9741 } 9742 9743 return (SDL_GPUCommandBuffer *)commandBuffer; 9744} 9745 9746static bool VULKAN_QueryFence( 9747 SDL_GPURenderer *driverData, 9748 SDL_GPUFence *fence) 9749{ 9750 VulkanRenderer *renderer = (VulkanRenderer *)driverData; 9751 VkResult result; 9752 9753 result = renderer->vkGetFenceStatus( 9754 renderer->logicalDevice, 9755 ((VulkanFenceHandle *)fence)->fence); 9756 9757 if (result == VK_SUCCESS) { 9758 return true; 9759 } else if (result == VK_NOT_READY) { 9760 return false; 9761 } else { 9762 SET_ERROR_AND_RETURN("vkGetFenceStatus: %s", VkErrorMessages(result), false); 9763 } 9764} 9765 9766static void VULKAN_INTERNAL_ReturnFenceToPool( 9767 VulkanRenderer *renderer, 9768 VulkanFenceHandle *fenceHandle) 9769{ 9770 SDL_LockMutex(renderer->fencePool.lock); 9771 9772 EXPAND_ARRAY_IF_NEEDED( 9773 renderer->fencePool.availableFences, 9774 VulkanFenceHandle *, 9775 renderer->fencePool.availableFenceCount + 1, 9776 renderer->fencePool.availableFenceCapacity, 9777 renderer->fencePool.availableFenceCapacity * 2); 9778 9779 renderer->fencePool.availableFences[renderer->fencePool.availableFenceCount] = fenceHandle; 9780 renderer->fencePool.availableFenceCount += 1; 9781 9782 SDL_UnlockMutex(renderer->fencePool.lock); 9783} 9784 9785static void VULKAN_ReleaseFence( 9786 SDL_GPURenderer *driverData, 9787 SDL_GPUFence *fence) 9788{ 9789 VulkanFenceHandle *handle = (VulkanFenceHandle *)fence; 9790 9791 if (SDL_AtomicDecRef(&handle->referenceCount)) { 9792 VULKAN_INTERNAL_ReturnFenceToPool((VulkanRenderer *)driverData, handle); 9793 } 9794} 9795 9796static WindowData *VULKAN_INTERNAL_FetchWindowData( 9797 SDL_Window *window) 9798{ 9799 SDL_PropertiesID properties = SDL_GetWindowProperties(window); 9800 return (WindowData *)SDL_GetPointerProperty(properties, WINDOW_PROPERTY_DATA, NULL); 9801} 9802 9803static bool VULKAN_INTERNAL_OnWindowResize(void *userdata, SDL_Event *e) 9804{ 9805 SDL_Window *w = (SDL_Window *)userdata; 9806 WindowData *data; 9807 if (e->type == SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED && e->window.windowID == SDL_GetWindowID(w)) { 9808 data = VULKAN_INTERNAL_FetchWindowData(w); 9809 data->needsSwapchainRecreate = true; 9810 data->swapchainCreateWidth = e->window.data1; 9811 data->swapchainCreateHeight = e->window.data2; 9812 } 9813 9814 return true; 9815} 9816 9817static bool VULKAN_SupportsSwapchainComposition( 9818 SDL_GPURenderer *driverData, 9819 SDL_Window *window, 9820 SDL_GPUSwapchainComposition swapchainComposition) 9821{ 9822 VulkanRenderer *renderer = (VulkanRenderer *)driverData; 9823 WindowData *windowData = VULKAN_INTERNAL_FetchWindowData(window); 9824 VkSurfaceKHR surface; 9825 SwapchainSupportDetails supportDetails; 9826 bool result = false; 9827 9828 if (windowData == NULL) { 9829 SET_STRING_ERROR_AND_RETURN("Must claim window before querying swapchain composition support!", false); 9830 } 9831 9832 surface = windowData->surface; 9833 if (!surface) { 9834 SET_STRING_ERROR_AND_RETURN("Window has no Vulkan surface", false); 9835 } 9836 9837 if (VULKAN_INTERNAL_QuerySwapchainSupport( 9838 renderer, 9839 renderer->physicalDevice, 9840 surface, 9841 &supportDetails)) { 9842 9843 result = VULKAN_INTERNAL_VerifySwapSurfaceFormat( 9844 SwapchainCompositionToFormat[swapchainComposition], 9845 SwapchainCompositionToColorSpace[swapchainComposition], 9846 supportDetails.formats, 9847 supportDetails.formatsLength); 9848 9849 if (!result) { 9850 // Let's try again with the fallback format... 9851 result = VULKAN_INTERNAL_VerifySwapSurfaceFormat( 9852 SwapchainCompositionToFallbackFormat[swapchainComposition], 9853 SwapchainCompositionToColorSpace[swapchainComposition], 9854 supportDetails.formats, 9855 supportDetails.formatsLength); 9856 } 9857 9858 SDL_free(supportDetails.formats); 9859 SDL_free(supportDetails.presentModes); 9860 } 9861 9862 return result; 9863} 9864 9865static bool VULKAN_SupportsPresentMode( 9866 SDL_GPURenderer *driverData, 9867 SDL_Window *window, 9868 SDL_GPUPresentMode presentMode) 9869{ 9870 VulkanRenderer *renderer = (VulkanRenderer *)driverData; 9871 WindowData *windowData = VULKAN_INTERNAL_FetchWindowData(window); 9872 VkSurfaceKHR surface; 9873 SwapchainSupportDetails supportDetails; 9874 bool result = false; 9875 9876 if (windowData == NULL) { 9877 SET_STRING_ERROR_AND_RETURN("Must claim window before querying present mode support!", false); 9878 } 9879 9880 surface = windowData->surface; 9881 if (!surface) { 9882 SET_STRING_ERROR_AND_RETURN("Window has no Vulkan surface", false); 9883 } 9884 9885 if (VULKAN_INTERNAL_QuerySwapchainSupport( 9886 renderer, 9887 renderer->physicalDevice, 9888 surface, 9889 &supportDetails)) { 9890 9891 result = VULKAN_INTERNAL_VerifySwapPresentMode( 9892 SDLToVK_PresentMode[presentMode], 9893 supportDetails.presentModes, 9894 supportDetails.presentModesLength); 9895 9896 SDL_free(supportDetails.formats); 9897 SDL_free(supportDetails.presentModes); 9898 } 9899 9900 return result; 9901} 9902 9903static bool VULKAN_ClaimWindow( 9904 SDL_GPURenderer *driverData, 9905 SDL_Window *window) 9906{ 9907 VulkanRenderer *renderer = (VulkanRenderer *)driverData; 9908 WindowData *windowData = VULKAN_INTERNAL_FetchWindowData(window); 9909 9910 if (windowData == NULL) { 9911 windowData = (WindowData *)SDL_calloc(1, sizeof(WindowData)); 9912 if (!windowData) { 9913 return false; 9914 } 9915 windowData->window = window; 9916 windowData->renderer = renderer; 9917 windowData->refcount = 1; 9918 windowData->presentMode = SDL_GPU_PRESENTMODE_VSYNC; 9919 windowData->swapchainComposition = SDL_GPU_SWAPCHAINCOMPOSITION_SDR; 9920 9921 // On non-Apple platforms the swapchain capability currentExtent can be different from the window, 9922 // so we have to query the window size. 9923#ifndef SDL_PLATFORM_APPLE 9924 int w, h; 9925 SDL_SyncWindow(window); 9926 SDL_GetWindowSizeInPixels(window, &w, &h); 9927 windowData->swapchainCreateWidth = w; 9928 windowData->swapchainCreateHeight = h; 9929#endif 9930 9931 SDL_VideoDevice *videoDevice = SDL_GetVideoDevice(); 9932 if (!videoDevice) { 9933 SDL_free(windowData); 9934 return SDL_SetError("No video device found"); 9935 } 9936 9937 if (!videoDevice->Vulkan_CreateSurface) { 9938 SDL_free(windowData); 9939 return SDL_SetError("Video device does not implement Vulkan_CreateSurface"); 9940 } 9941 9942 // Each window must have its own surface. 9943 if (!videoDevice->Vulkan_CreateSurface( 9944 videoDevice, 9945 windowData->window, 9946 renderer->instance, 9947 NULL, // FIXME: VAllocationCallbacks 9948 &windowData->surface)) { 9949 SDL_free(windowData); 9950 return false; 9951 } 9952 9953 Uint32 createSwapchainResult = VULKAN_INTERNAL_CreateSwapchain(renderer, windowData); 9954 if (createSwapchainResult == 1) { 9955 SDL_SetPointerProperty(SDL_GetWindowProperties(window), WINDOW_PROPERTY_DATA, windowData); 9956 9957 SDL_LockMutex(renderer->windowLock); 9958 if (renderer->claimedWindowCount >= renderer->claimedWindowCapacity) { 9959 renderer->claimedWindowCapacity *= 2; 9960 renderer->claimedWindows = SDL_realloc( 9961 renderer->claimedWindows, 9962 renderer->claimedWindowCapacity * sizeof(WindowData *)); 9963 } 9964 9965 renderer->claimedWindows[renderer->claimedWindowCount] = windowData; 9966 renderer->claimedWindowCount += 1; 9967 SDL_UnlockMutex(renderer->windowLock); 9968 9969 SDL_AddWindowEventWatch(SDL_WINDOW_EVENT_WATCH_NORMAL, VULKAN_INTERNAL_OnWindowResize, window); 9970 9971 return true; 9972 } else if (createSwapchainResult == VULKAN_INTERNAL_TRY_AGAIN) { 9973 windowData->needsSwapchainRecreate = true; 9974 return true; 9975 } else { 9976 // Failed to create swapchain, destroy surface and free data 9977 renderer->vkDestroySurfaceKHR( 9978 renderer->instance, 9979 windowData->surface, 9980 NULL); 9981 SDL_free(windowData); 9982 return false; 9983 } 9984 } else if (windowData->renderer == renderer) { 9985 ++windowData->refcount; 9986 return true; 9987 } else { 9988 SET_STRING_ERROR_AND_RETURN("Window already claimed", false); 9989 } 9990} 9991 9992static void VULKAN_ReleaseWindow( 9993 SDL_GPURenderer *driverData, 9994 SDL_Window *window) 9995{ 9996 VulkanRenderer *renderer = (VulkanRenderer *)driverData; 9997 WindowData *windowData = VULKAN_INTERNAL_FetchWindowData(window); 9998 Uint32 i; 9999 10000 if (windowData == NULL) { 10001 return; 10002 } 10003 if (windowData->renderer != renderer) { 10004 SDL_SetError("Window not claimed by this device"); 10005 return; 10006 } 10007 if (windowData->refcount > 1) { 10008 --windowData->refcount; 10009 return; 10010 } 10011 10012 VULKAN_Wait(driverData); 10013 10014 for (i = 0; i < MAX_FRAMES_IN_FLIGHT; i += 1) { 10015 if (windowData->inFlightFences[i] != NULL) { 10016 VULKAN_ReleaseFence( 10017 driverData, 10018 windowData->inFlightFences[i]); 10019 } 10020 } 10021 10022 VULKAN_INTERNAL_DestroySwapchain( 10023 (VulkanRenderer *)driverData, 10024 windowData); 10025 10026 renderer->vkDestroySurfaceKHR( 10027 renderer->instance, 10028 windowData->surface, 10029 NULL); 10030 windowData->surface = VK_NULL_HANDLE; 10031 10032 SDL_LockMutex(renderer->windowLock); 10033 for (i = 0; i < renderer->claimedWindowCount; i += 1) { 10034 if (renderer->claimedWindows[i]->window == window) { 10035 renderer->claimedWindows[i] = renderer->claimedWindows[renderer->claimedWindowCount - 1]; 10036 renderer->claimedWindowCount -= 1; 10037 break; 10038 } 10039 } 10040 SDL_UnlockMutex(renderer->windowLock); 10041 10042 SDL_free(windowData); 10043 10044 SDL_ClearProperty(SDL_GetWindowProperties(window), WINDOW_PROPERTY_DATA); 10045 SDL_RemoveWindowEventWatch(SDL_WINDOW_EVENT_WATCH_NORMAL, VULKAN_INTERNAL_OnWindowResize, window); 10046} 10047 10048static Uint32 VULKAN_INTERNAL_RecreateSwapchain( 10049 VulkanRenderer *renderer, 10050 WindowData *windowData) 10051{ 10052 Uint32 i; 10053 10054 if (!VULKAN_Wait((SDL_GPURenderer *)renderer)) { 10055 return false; 10056 } 10057 10058 for (i = 0; i < MAX_FRAMES_IN_FLIGHT; i += 1) { 10059 if (windowData->inFlightFences[i] != NULL) { 10060 VULKAN_ReleaseFence( 10061 (SDL_GPURenderer *)renderer, 10062 windowData->inFlightFences[i]); 10063 windowData->inFlightFences[i] = NULL; 10064 } 10065 } 10066 10067#ifdef SDL_VIDEO_DRIVER_PRIVATE 10068 // Private platforms also invalidate the window, so don't try to preserve the surface/swapchain 10069 VULKAN_INTERNAL_DestroySwapchain(renderer, windowData); 10070#else 10071 VULKAN_INTERNAL_DestroySwapchainImage(renderer, windowData); 10072#endif 10073 return VULKAN_INTERNAL_CreateSwapchain(renderer, windowData); 10074} 10075 10076static bool VULKAN_WaitForSwapchain( 10077 SDL_GPURenderer *driverData, 10078 SDL_Window *window) 10079{ 10080 VulkanRenderer *renderer = (VulkanRenderer *)driverData; 10081 WindowData *windowData = VULKAN_INTERNAL_FetchWindowData(window); 10082 10083 if (windowData == NULL) { 10084 SET_STRING_ERROR_AND_RETURN("Cannot wait for a swapchain from an unclaimed window!", false); 10085 } 10086 10087 if (windowData->inFlightFences[windowData->frameCounter] != NULL) { 10088 if (!VULKAN_WaitForFences( 10089 driverData, 10090 true, 10091 &windowData->inFlightFences[windowData->frameCounter], 10092 1)) { 10093 return false; 10094 } 10095 } 10096 10097 return true; 10098} 10099 10100static bool VULKAN_INTERNAL_AcquireSwapchainTexture( 10101 bool block, 10102 SDL_GPUCommandBuffer *commandBuffer, 10103 SDL_Window *window, 10104 SDL_GPUTexture **swapchainTexture, 10105 Uint32 *swapchainTextureWidth, 10106 Uint32 *swapchainTextureHeight) 10107{ 10108 VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; 10109 VulkanRenderer *renderer = vulkanCommandBuffer->renderer; 10110 Uint32 swapchainImageIndex; 10111 WindowData *windowData; 10112 VkResult acquireResult = VK_SUCCESS; 10113 VulkanTextureContainer *swapchainTextureContainer = NULL; 10114 VulkanPresentData *presentData; 10115 10116 *swapchainTexture = NULL; 10117 if (swapchainTextureWidth) { 10118 *swapchainTextureWidth = 0; 10119 } 10120 if (swapchainTextureHeight) { 10121 *swapchainTextureHeight = 0; 10122 } 10123 10124 windowData = VULKAN_INTERNAL_FetchWindowData(window); 10125 if (windowData == NULL) { 10126 SET_STRING_ERROR_AND_RETURN("Cannot acquire a swapchain texture from an unclaimed window!", false); 10127 } 10128 10129 // The command buffer is flagged for cleanup when the swapchain is requested as a cleanup timing mechanism 10130 vulkanCommandBuffer->swapchainRequested = true; 10131 10132 if (window->flags & SDL_WINDOW_HIDDEN) { 10133 // Edge case, texture is filled in with NULL but not an error 10134 return true; 10135 } 10136 10137 if (windowData->needsSurfaceRecreate) { 10138 SDL_VideoDevice *videoDevice = SDL_GetVideoDevice(); 10139 SDL_assert(videoDevice); 10140 SDL_assert(videoDevice->Vulkan_CreateSurface); 10141 renderer->vkDestroySurfaceKHR( 10142 renderer->instance, 10143 windowData->surface, 10144 NULL); 10145 if (!videoDevice->Vulkan_CreateSurface( 10146 videoDevice, 10147 windowData->window, 10148 renderer->instance, 10149 NULL, // FIXME: VAllocationCallbacks 10150 &windowData->surface)) { 10151 SET_STRING_ERROR_AND_RETURN("Failed to recreate Vulkan surface!", false); 10152 } 10153 } 10154 10155 // If window data marked as needing swapchain recreate, try to recreate 10156 if (windowData->needsSwapchainRecreate) { 10157 Uint32 recreateSwapchainResult = VULKAN_INTERNAL_RecreateSwapchain(renderer, windowData); 10158 if (!recreateSwapchainResult) { 10159 return false; 10160 } else if (recreateSwapchainResult == VULKAN_INTERNAL_TRY_AGAIN) { 10161 // Edge case, texture is filled in with NULL but not an error 10162 if (windowData->inFlightFences[windowData->frameCounter] != NULL) { 10163 VULKAN_ReleaseFence( 10164 (SDL_GPURenderer *)renderer, 10165 windowData->inFlightFences[windowData->frameCounter]); 10166 windowData->inFlightFences[windowData->frameCounter] = NULL; 10167 } 10168 return true; 10169 } 10170 10171 // Unset this flag until after the swapchain has been recreated to let VULKAN_INTERNAL_CreateSwapchain() 10172 // know whether it needs to pass the old swapchain or not. 10173 windowData->needsSurfaceRecreate = false; 10174 } 10175 10176 if (windowData->inFlightFences[windowData->frameCounter] != NULL) { 10177 if (block) { 10178 // If we are blocking, just wait for the fence! 10179 if (!VULKAN_WaitForFences( 10180 (SDL_GPURenderer *)renderer, 10181 true, 10182 &windowData->inFlightFences[windowData->frameCounter], 10183 1)) { 10184 return false; 10185 } 10186 } else { 10187 // If we are not blocking and the least recent fence is not signaled, 10188 // return true to indicate that there is no error but rendering should be skipped. 10189 if (!VULKAN_QueryFence( 10190 (SDL_GPURenderer *)renderer, 10191 windowData->inFlightFences[windowData->frameCounter])) { 10192 return true; 10193 } 10194 } 10195 10196 VULKAN_ReleaseFence( 10197 (SDL_GPURenderer *)renderer, 10198 windowData->inFlightFences[windowData->frameCounter]); 10199 10200 windowData->inFlightFences[windowData->frameCounter] = NULL; 10201 } 10202 10203 // Finally, try to acquire! 10204 while (true) { 10205 acquireResult = renderer->vkAcquireNextImageKHR( 10206 renderer->logicalDevice, 10207 windowData->swapchain, 10208 SDL_MAX_UINT64, 10209 windowData->imageAvailableSemaphore[windowData->frameCounter], 10210 VK_NULL_HANDLE, 10211 &swapchainImageIndex); 10212 10213 if (acquireResult == VK_SUCCESS || acquireResult == VK_SUBOPTIMAL_KHR) { 10214 break; // we got the next image! 10215 } 10216 10217 // If acquisition is invalid, let's try to recreate 10218 Uint32 recreateSwapchainResult = VULKAN_INTERNAL_RecreateSwapchain(renderer, windowData); 10219 if (!recreateSwapchainResult) { 10220 return false; 10221 } else if (recreateSwapchainResult == VULKAN_INTERNAL_TRY_AGAIN) { 10222 // Edge case, texture is filled in with NULL but not an error 10223 return true; 10224 } 10225 } 10226 10227 if (swapchainTextureWidth) { 10228 *swapchainTextureWidth = windowData->width; 10229 } 10230 10231 if (swapchainTextureHeight) { 10232 *swapchainTextureHeight = windowData->height; 10233 } 10234 10235 swapchainTextureContainer = &windowData->textureContainers[swapchainImageIndex]; 10236 10237 // We need a special execution dependency with pWaitDstStageMask or image transition can start before acquire finishes 10238 10239 VkImageMemoryBarrier imageBarrier; 10240 imageBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; 10241 imageBarrier.pNext = NULL; 10242 imageBarrier.srcAccessMask = 0; 10243 imageBarrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; 10244 imageBarrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; 10245 imageBarrier.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; 10246 imageBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; 10247 imageBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; 10248 imageBarrier.image = swapchainTextureContainer->activeTexture->image; 10249 imageBarrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; 10250 imageBarrier.subresourceRange.baseMipLevel = 0; 10251 imageBarrier.subresourceRange.levelCount = 1; 10252 imageBarrier.subresourceRange.baseArrayLayer = 0; 10253 imageBarrier.subresourceRange.layerCount = 1; 10254 10255 renderer->vkCmdPipelineBarrier( 10256 vulkanCommandBuffer->commandBuffer, 10257 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 10258 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 10259 0, 10260 0, 10261 NULL, 10262 0, 10263 NULL, 10264 1, 10265 &imageBarrier); 10266 10267 // Set up present struct 10268 10269 if (vulkanCommandBuffer->presentDataCount == vulkanCommandBuffer->presentDataCapacity) { 10270 vulkanCommandBuffer->presentDataCapacity += 1; 10271 vulkanCommandBuffer->presentDatas = SDL_realloc( 10272 vulkanCommandBuffer->presentDatas, 10273 vulkanCommandBuffer->presentDataCapacity * sizeof(VulkanPresentData)); 10274 } 10275 10276 presentData = &vulkanCommandBuffer->presentDatas[vulkanCommandBuffer->presentDataCount]; 10277 vulkanCommandBuffer->presentDataCount += 1; 10278 10279 presentData->windowData = windowData; 10280 presentData->swapchainImageIndex = swapchainImageIndex; 10281 10282 // Set up present semaphores 10283 10284 if (vulkanCommandBuffer->waitSemaphoreCount == vulkanCommandBuffer->waitSemaphoreCapacity) { 10285 vulkanCommandBuffer->waitSemaphoreCapacity += 1; 10286 vulkanCommandBuffer->waitSemaphores = SDL_realloc( 10287 vulkanCommandBuffer->waitSemaphores, 10288 vulkanCommandBuffer->waitSemaphoreCapacity * sizeof(VkSemaphore)); 10289 } 10290 10291 vulkanCommandBuffer->waitSemaphores[vulkanCommandBuffer->waitSemaphoreCount] = 10292 windowData->imageAvailableSemaphore[windowData->frameCounter]; 10293 vulkanCommandBuffer->waitSemaphoreCount += 1; 10294 10295 if (vulkanCommandBuffer->signalSemaphoreCount == vulkanCommandBuffer->signalSemaphoreCapacity) { 10296 vulkanCommandBuffer->signalSemaphoreCapacity += 1; 10297 vulkanCommandBuffer->signalSemaphores = SDL_realloc( 10298 vulkanCommandBuffer->signalSemaphores, 10299 vulkanCommandBuffer->signalSemaphoreCapacity * sizeof(VkSemaphore)); 10300 } 10301 10302 vulkanCommandBuffer->signalSemaphores[vulkanCommandBuffer->signalSemaphoreCount] = 10303 windowData->renderFinishedSemaphore[swapchainImageIndex]; 10304 vulkanCommandBuffer->signalSemaphoreCount += 1; 10305 10306 *swapchainTexture = (SDL_GPUTexture *)swapchainTextureContainer; 10307 return true; 10308} 10309 10310static bool VULKAN_AcquireSwapchainTexture( 10311 SDL_GPUCommandBuffer *command_buffer, 10312 SDL_Window *window, 10313 SDL_GPUTexture **swapchain_texture, 10314 Uint32 *swapchain_texture_width, 10315 Uint32 *swapchain_texture_height 10316) { 10317 return VULKAN_INTERNAL_AcquireSwapchainTexture( 10318 false, 10319 command_buffer, 10320 window, 10321 swapchain_texture, 10322 swapchain_texture_width, 10323 swapchain_texture_height); 10324} 10325 10326static bool VULKAN_WaitAndAcquireSwapchainTexture( 10327 SDL_GPUCommandBuffer *command_buffer, 10328 SDL_Window *window, 10329 SDL_GPUTexture **swapchain_texture, 10330 Uint32 *swapchain_texture_width, 10331 Uint32 *swapchain_texture_height 10332) { 10333 return VULKAN_INTERNAL_AcquireSwapchainTexture( 10334 true, 10335 command_buffer, 10336 window, 10337 swapchain_texture, 10338 swapchain_texture_width, 10339 swapchain_texture_height); 10340} 10341 10342static SDL_GPUTextureFormat VULKAN_GetSwapchainTextureFormat( 10343 SDL_GPURenderer *driverData, 10344 SDL_Window *window) 10345{ 10346 VulkanRenderer *renderer = (VulkanRenderer *)driverData; 10347 WindowData *windowData = VULKAN_INTERNAL_FetchWindowData(window); 10348 10349 if (windowData == NULL) { 10350 SET_STRING_ERROR_AND_RETURN("Cannot get swapchain format, window has not been claimed!", SDL_GPU_TEXTUREFORMAT_INVALID); 10351 } 10352 10353 return SwapchainCompositionToSDLFormat( 10354 windowData->swapchainComposition, 10355 windowData->usingFallbackFormat); 10356} 10357 10358static bool VULKAN_SetSwapchainParameters( 10359 SDL_GPURenderer *driverData, 10360 SDL_Window *window, 10361 SDL_GPUSwapchainComposition swapchainComposition, 10362 SDL_GPUPresentMode presentMode) 10363{ 10364 VulkanRenderer *renderer = (VulkanRenderer *)driverData; 10365 WindowData *windowData = VULKAN_INTERNAL_FetchWindowData(window); 10366 10367 if (windowData == NULL) { 10368 SET_STRING_ERROR_AND_RETURN("Cannot set swapchain parameters on unclaimed window!", false); 10369 } 10370 10371 if (!VULKAN_SupportsSwapchainComposition(driverData, window, swapchainComposition)) { 10372 SET_STRING_ERROR_AND_RETURN("Swapchain composition not supported!", false); 10373 } 10374 10375 if (!VULKAN_SupportsPresentMode(driverData, window, presentMode)) { 10376 SET_STRING_ERROR_AND_RETURN("Present mode not supported!", false); 10377 } 10378 10379 windowData->presentMode = presentMode; 10380 windowData->swapchainComposition = swapchainComposition; 10381 10382 Uint32 recreateSwapchainResult = VULKAN_INTERNAL_RecreateSwapchain(renderer, windowData); 10383 if (!recreateSwapchainResult) { 10384 return false; 10385 } else if (recreateSwapchainResult == VULKAN_INTERNAL_TRY_AGAIN) { 10386 // Edge case, swapchain extent is (0, 0) but this is not an error 10387 windowData->needsSwapchainRecreate = true; 10388 return true; 10389 } 10390 10391 return true; 10392} 10393 10394static bool VULKAN_SetAllowedFramesInFlight( 10395 SDL_GPURenderer *driverData, 10396 Uint32 allowedFramesInFlight) 10397{ 10398 VulkanRenderer *renderer = (VulkanRenderer *)driverData; 10399 10400 renderer->allowedFramesInFlight = allowedFramesInFlight; 10401 10402 for (Uint32 i = 0; i < renderer->claimedWindowCount; i += 1) { 10403 WindowData *windowData = renderer->claimedWindows[i]; 10404 10405 Uint32 recreateResult = VULKAN_INTERNAL_RecreateSwapchain(renderer, windowData); 10406 if (!recreateResult) { 10407 return false; 10408 } else if (recreateResult == VULKAN_INTERNAL_TRY_AGAIN) { 10409 // Edge case, swapchain extent is (0, 0) but this is not an error 10410 windowData->needsSwapchainRecreate = true; 10411 } 10412 } 10413 10414 return true; 10415} 10416 10417// Submission structure 10418 10419static VulkanFenceHandle *VULKAN_INTERNAL_AcquireFenceFromPool( 10420 VulkanRenderer *renderer) 10421{ 10422 VulkanFenceHandle *handle; 10423 VkFenceCreateInfo fenceCreateInfo; 10424 VkFence fence; 10425 VkResult vulkanResult; 10426 10427 if (renderer->fencePool.availableFenceCount == 0) { 10428 // Create fence 10429 fenceCreateInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; 10430 fenceCreateInfo.pNext = NULL; 10431 fenceCreateInfo.flags = 0; 10432 10433 vulkanResult = renderer->vkCreateFence( 10434 renderer->logicalDevice, 10435 &fenceCreateInfo, 10436 NULL, 10437 &fence); 10438 10439 CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkCreateFence, NULL); 10440 10441 handle = SDL_malloc(sizeof(VulkanFenceHandle)); 10442 handle->fence = fence; 10443 SDL_SetAtomicInt(&handle->referenceCount, 0); 10444 return handle; 10445 } 10446 10447 SDL_LockMutex(renderer->fencePool.lock); 10448 10449 handle = renderer->fencePool.availableFences[renderer->fencePool.availableFenceCount - 1]; 10450 renderer->fencePool.availableFenceCount -= 1; 10451 10452 vulkanResult = renderer->vkResetFences( 10453 renderer->logicalDevice, 10454 1, 10455 &handle->fence); 10456 10457 SDL_UnlockMutex(renderer->fencePool.lock); 10458 10459 CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkResetFences, NULL); 10460 10461 return handle; 10462} 10463 10464static void VULKAN_INTERNAL_PerformPendingDestroys( 10465 VulkanRenderer *renderer) 10466{ 10467 SDL_LockMutex(renderer->disposeLock); 10468 10469 for (Sint32 i = renderer->texturesToDestroyCount - 1; i >= 0; i -= 1) { 10470 if (SDL_GetAtomicInt(&renderer->texturesToDestroy[i]->referenceCount) == 0) { 10471 VULKAN_INTERNAL_DestroyTexture( 10472 renderer, 10473 renderer->texturesToDestroy[i]); 10474 10475 renderer->texturesToDestroy[i] = renderer->texturesToDestroy[renderer->texturesToDestroyCount - 1]; 10476 renderer->texturesToDestroyCount -= 1; 10477 } 10478 } 10479 10480 for (Sint32 i = renderer->buffersToDestroyCount - 1; i >= 0; i -= 1) { 10481 if (SDL_GetAtomicInt(&renderer->buffersToDestroy[i]->referenceCount) == 0) { 10482 VULKAN_INTERNAL_DestroyBuffer( 10483 renderer, 10484 renderer->buffersToDestroy[i]); 10485 10486 renderer->buffersToDestroy[i] = renderer->buffersToDestroy[renderer->buffersToDestroyCount - 1]; 10487 renderer->buffersToDestroyCount -= 1; 10488 } 10489 } 10490 10491 for (Sint32 i = renderer->graphicsPipelinesToDestroyCount - 1; i >= 0; i -= 1) { 10492 if (SDL_GetAtomicInt(&renderer->graphicsPipelinesToDestroy[i]->referenceCount) == 0) { 10493 VULKAN_INTERNAL_DestroyGraphicsPipeline( 10494 renderer, 10495 renderer->graphicsPipelinesToDestroy[i]); 10496 10497 renderer->graphicsPipelinesToDestroy[i] = renderer->graphicsPipelinesToDestroy[renderer->graphicsPipelinesToDestroyCount - 1]; 10498 renderer->graphicsPipelinesToDestroyCount -= 1; 10499 } 10500 } 10501 10502 for (Sint32 i = renderer->computePipelinesToDestroyCount - 1; i >= 0; i -= 1) { 10503 if (SDL_GetAtomicInt(&renderer->computePipelinesToDestroy[i]->referenceCount) == 0) { 10504 VULKAN_INTERNAL_DestroyComputePipeline( 10505 renderer, 10506 renderer->computePipelinesToDestroy[i]); 10507 10508 renderer->computePipelinesToDestroy[i] = renderer->computePipelinesToDestroy[renderer->computePipelinesToDestroyCount - 1]; 10509 renderer->computePipelinesToDestroyCount -= 1; 10510 } 10511 } 10512 10513 for (Sint32 i = renderer->shadersToDestroyCount - 1; i >= 0; i -= 1) { 10514 if (SDL_GetAtomicInt(&renderer->shadersToDestroy[i]->referenceCount) == 0) { 10515 VULKAN_INTERNAL_DestroyShader( 10516 renderer, 10517 renderer->shadersToDestroy[i]); 10518 10519 renderer->shadersToDestroy[i] = renderer->shadersToDestroy[renderer->shadersToDestroyCount - 1]; 10520 renderer->shadersToDestroyCount -= 1; 10521 } 10522 } 10523 10524 for (Sint32 i = renderer->samplersToDestroyCount - 1; i >= 0; i -= 1) { 10525 if (SDL_GetAtomicInt(&renderer->samplersToDestroy[i]->referenceCount) == 0) { 10526 VULKAN_INTERNAL_DestroySampler( 10527 renderer, 10528 renderer->samplersToDestroy[i]); 10529 10530 renderer->samplersToDestroy[i] = renderer->samplersToDestroy[renderer->samplersToDestroyCount - 1]; 10531 renderer->samplersToDestroyCount -= 1; 10532 } 10533 } 10534 10535 for (Sint32 i = renderer->framebuffersToDestroyCount - 1; i >= 0; i -= 1) { 10536 if (SDL_GetAtomicInt(&renderer->framebuffersToDestroy[i]->referenceCount) == 0) { 10537 VULKAN_INTERNAL_DestroyFramebuffer( 10538 renderer, 10539 renderer->framebuffersToDestroy[i]); 10540 10541 renderer->framebuffersToDestroy[i] = renderer->framebuffersToDestroy[renderer->framebuffersToDestroyCount - 1]; 10542 renderer->framebuffersToDestroyCount -= 1; 10543 } 10544 } 10545 10546 SDL_UnlockMutex(renderer->disposeLock); 10547} 10548 10549static void VULKAN_INTERNAL_CleanCommandBuffer( 10550 VulkanRenderer *renderer, 10551 VulkanCommandBuffer *commandBuffer, 10552 bool cancel) 10553{ 10554 if (commandBuffer->autoReleaseFence) { 10555 VULKAN_ReleaseFence( 10556 (SDL_GPURenderer *)renderer, 10557 (SDL_GPUFence *)commandBuffer->inFlightFence); 10558 10559 commandBuffer->inFlightFence = NULL; 10560 } 10561 10562 // Uniform buffers are now available 10563 10564 SDL_LockMutex(renderer->acquireUniformBufferLock); 10565 10566 for (Sint32 i = 0; i < commandBuffer->usedUniformBufferCount; i += 1) { 10567 VULKAN_INTERNAL_ReturnUniformBufferToPool( 10568 renderer, 10569 commandBuffer->usedUniformBuffers[i]); 10570 } 10571 commandBuffer->usedUniformBufferCount = 0; 10572 10573 SDL_UnlockMutex(renderer->acquireUniformBufferLock); 10574 10575 // Decrement reference counts 10576 10577 for (Sint32 i = 0; i < commandBuffer->usedBufferCount; i += 1) { 10578 (void)SDL_AtomicDecRef(&commandBuffer->usedBuffers[i]->referenceCount); 10579 } 10580 commandBuffer->usedBufferCount = 0; 10581 10582 for (Sint32 i = 0; i < commandBuffer->buffersUsedInPendingTransfersCount; i += 1) { 10583 (void)SDL_AtomicDecRef(&commandBuffer->usedBuffers[i]->usedRegion->allocation->referenceCount); 10584 } 10585 commandBuffer->buffersUsedInPendingTransfersCount = 0; 10586 10587 for (Sint32 i = 0; i < commandBuffer->usedTextureCount; i += 1) { 10588 (void)SDL_AtomicDecRef(&commandBuffer->usedTextures[i]->referenceCount); 10589 } 10590 commandBuffer->usedTextureCount = 0; 10591 10592 for (Sint32 i = 0; i < commandBuffer->texturesUsedInPendingTransfersCount; i += 1){ 10593 (void)SDL_AtomicDecRef(&commandBuffer->usedTextures[i]->usedRegion->allocation->referenceCount); 10594 } 10595 commandBuffer->texturesUsedInPendingTransfersCount = 0; 10596 10597 for (Sint32 i = 0; i < commandBuffer->usedSamplerCount; i += 1) { 10598 (void)SDL_AtomicDecRef(&commandBuffer->usedSamplers[i]->referenceCount); 10599 } 10600 commandBuffer->usedSamplerCount = 0; 10601 10602 for (Sint32 i = 0; i < commandBuffer->usedGraphicsPipelineCount; i += 1) { 10603 (void)SDL_AtomicDecRef(&commandBuffer->usedGraphicsPipelines[i]->referenceCount); 10604 } 10605 commandBuffer->usedGraphicsPipelineCount = 0; 10606 10607 for (Sint32 i = 0; i < commandBuffer->usedComputePipelineCount; i += 1) { 10608 (void)SDL_AtomicDecRef(&commandBuffer->usedComputePipelines[i]->referenceCount); 10609 } 10610 commandBuffer->usedComputePipelineCount = 0; 10611 10612 for (Sint32 i = 0; i < commandBuffer->usedFramebufferCount; i += 1) { 10613 (void)SDL_AtomicDecRef(&commandBuffer->usedFramebuffers[i]->referenceCount); 10614 } 10615 commandBuffer->usedFramebufferCount = 0; 10616 10617 // Reset presentation data 10618 10619 commandBuffer->presentDataCount = 0; 10620 commandBuffer->waitSemaphoreCount = 0; 10621 commandBuffer->signalSemaphoreCount = 0; 10622 commandBuffer->swapchainRequested = false; 10623 10624 // Reset defrag state 10625 10626 if (commandBuffer->isDefrag) { 10627 renderer->defragInProgress = 0; 10628 } 10629 10630 // Return command buffer to pool 10631 10632 SDL_LockMutex(renderer->acquireCommandBufferLock); 10633 10634 if (commandBuffer->commandPool->inactiveCommandBufferCount == commandBuffer->commandPool->inactiveCommandBufferCapacity) { 10635 commandBuffer->commandPool->inactiveCommandBufferCapacity += 1; 10636 commandBuffer->commandPool->inactiveCommandBuffers = SDL_realloc( 10637 commandBuffer->commandPool->inactiveCommandBuffers, 10638 commandBuffer->commandPool->inactiveCommandBufferCapacity * sizeof(VulkanCommandBuffer *)); 10639 } 10640 10641 commandBuffer->commandPool->inactiveCommandBuffers[commandBuffer->commandPool->inactiveCommandBufferCount] = commandBuffer; 10642 commandBuffer->commandPool->inactiveCommandBufferCount += 1; 10643 10644 // Release descriptor set cache 10645 10646 VULKAN_INTERNAL_ReturnDescriptorSetCacheToPool( 10647 renderer, 10648 commandBuffer->descriptorSetCache); 10649 10650 commandBuffer->descriptorSetCache = NULL; 10651 10652 SDL_UnlockMutex(renderer->acquireCommandBufferLock); 10653 10654 // Remove this command buffer from the submitted list 10655 if (!cancel) { 10656 for (Uint32 i = 0; i < renderer->submittedCommandBufferCount; i += 1) { 10657 if (renderer->submittedCommandBuffers[i] == commandBuffer) { 10658 renderer->submittedCommandBuffers[i] = renderer->submittedCommandBuffers[renderer->submittedCommandBufferCount - 1]; 10659 renderer->submittedCommandBufferCount -= 1; 10660 } 10661 } 10662 } 10663} 10664 10665static bool VULKAN_WaitForFences( 10666 SDL_GPURenderer *driverData, 10667 bool waitAll, 10668 SDL_GPUFence *const *fences, 10669 Uint32 numFences) 10670{ 10671 VulkanRenderer *renderer = (VulkanRenderer *)driverData; 10672 VkFence *vkFences = SDL_stack_alloc(VkFence, numFences); 10673 VkResult result; 10674 10675 for (Uint32 i = 0; i < numFences; i += 1) { 10676 vkFences[i] = ((VulkanFenceHandle *)fences[i])->fence; 10677 } 10678 10679 result = renderer->vkWaitForFences( 10680 renderer->logicalDevice, 10681 numFences, 10682 vkFences, 10683 waitAll, 10684 SDL_MAX_UINT64); 10685 10686 CHECK_VULKAN_ERROR_AND_RETURN(result, vkWaitForFences, false); 10687 10688 SDL_stack_free(vkFences); 10689 10690 SDL_LockMutex(renderer->submitLock); 10691 10692 for (Sint32 i = renderer->submittedCommandBufferCount - 1; i >= 0; i -= 1) { 10693 result = renderer->vkGetFenceStatus( 10694 renderer->logicalDevice, 10695 renderer->submittedCommandBuffers[i]->inFlightFence->fence); 10696 10697 if (result == VK_SUCCESS) { 10698 VULKAN_INTERNAL_CleanCommandBuffer( 10699 renderer, 10700 renderer->submittedCommandBuffers[i], 10701 false); 10702 } 10703 } 10704 10705 VULKAN_INTERNAL_PerformPendingDestroys(renderer); 10706 10707 SDL_UnlockMutex(renderer->submitLock); 10708 10709 return true; 10710} 10711 10712static bool VULKAN_Wait( 10713 SDL_GPURenderer *driverData) 10714{ 10715 VulkanRenderer *renderer = (VulkanRenderer *)driverData; 10716 VulkanCommandBuffer *commandBuffer; 10717 VkResult result; 10718 Sint32 i; 10719 10720 SDL_LockMutex(renderer->submitLock); 10721 10722 result = renderer->vkDeviceWaitIdle(renderer->logicalDevice); 10723 10724 if (result != VK_SUCCESS) { 10725 if (renderer->debugMode) { 10726 SDL_LogError(SDL_LOG_CATEGORY_GPU, "%s %s", "vkDeviceWaitIdle", VkErrorMessages(result)); 10727 } 10728 SDL_SetError("%s %s", "vkDeviceWaitIdle", VkErrorMessages(result)); 10729 SDL_UnlockMutex(renderer->submitLock); 10730 return false; 10731 } 10732 10733 for (i = renderer->submittedCommandBufferCount - 1; i >= 0; i -= 1) { 10734 commandBuffer = renderer->submittedCommandBuffers[i]; 10735 VULKAN_INTERNAL_CleanCommandBuffer(renderer, commandBuffer, false); 10736 } 10737 10738 VULKAN_INTERNAL_PerformPendingDestroys(renderer); 10739 10740 SDL_UnlockMutex(renderer->submitLock); 10741 10742 return true; 10743} 10744 10745static SDL_GPUFence *VULKAN_SubmitAndAcquireFence( 10746 SDL_GPUCommandBuffer *commandBuffer) 10747{ 10748 VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; 10749 vulkanCommandBuffer->autoReleaseFence = false; 10750 if (!VULKAN_Submit(commandBuffer)) { 10751 return NULL; 10752 } 10753 return (SDL_GPUFence *)vulkanCommandBuffer->inFlightFence; 10754} 10755 10756static void VULKAN_INTERNAL_ReleaseCommandBuffer(VulkanCommandBuffer *vulkanCommandBuffer) 10757{ 10758 VulkanRenderer *renderer = vulkanCommandBuffer->renderer; 10759 10760 if (renderer->submittedCommandBufferCount + 1 >= renderer->submittedCommandBufferCapacity) { 10761 renderer->submittedCommandBufferCapacity = renderer->submittedCommandBufferCount + 1; 10762 10763 renderer->submittedCommandBuffers = SDL_realloc( 10764 renderer->submittedCommandBuffers, 10765 sizeof(VulkanCommandBuffer *) * renderer->submittedCommandBufferCapacity); 10766 } 10767 10768 renderer->submittedCommandBuffers[renderer->submittedCommandBufferCount] = vulkanCommandBuffer; 10769 renderer->submittedCommandBufferCount += 1; 10770} 10771 10772static bool VULKAN_Submit( 10773 SDL_GPUCommandBuffer *commandBuffer) 10774{ 10775 VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; 10776 VulkanRenderer *renderer = vulkanCommandBuffer->renderer; 10777 VkSubmitInfo submitInfo; 10778 VkPresentInfoKHR presentInfo; 10779 VulkanPresentData *presentData; 10780 VkResult vulkanResult, presentResult = VK_SUCCESS; 10781 VkPipelineStageFlags waitStages[MAX_PRESENT_COUNT]; 10782 Uint32 swapchainImageIndex; 10783 VulkanTextureSubresource *swapchainTextureSubresource; 10784 VulkanMemorySubAllocator *allocator; 10785 bool performCleanups = 10786 (renderer->claimedWindowCount > 0 && vulkanCommandBuffer->swapchainRequested) || 10787 renderer->claimedWindowCount == 0; 10788 10789 SDL_LockMutex(renderer->submitLock); 10790 10791 // FIXME: Can this just be permanent? 10792 for (Uint32 i = 0; i < MAX_PRESENT_COUNT; i += 1) { 10793 waitStages[i] = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; 10794 } 10795 10796 for (Uint32 j = 0; j < vulkanCommandBuffer->presentDataCount; j += 1) { 10797 swapchainImageIndex = vulkanCommandBuffer->presentDatas[j].swapchainImageIndex; 10798 swapchainTextureSubresource = VULKAN_INTERNAL_FetchTextureSubresource( 10799 &vulkanCommandBuffer->presentDatas[j].windowData->textureContainers[swapchainImageIndex], 10800 0, 10801 0); 10802 10803 VULKAN_INTERNAL_TextureSubresourceTransitionFromDefaultUsage( 10804 renderer, 10805 vulkanCommandBuffer, 10806 VULKAN_TEXTURE_USAGE_MODE_PRESENT, 10807 swapchainTextureSubresource); 10808 } 10809 10810 if (performCleanups && 10811 renderer->allocationsToDefragCount > 0 && 10812 !renderer->defragInProgress) { 10813 if (!VULKAN_INTERNAL_DefragmentMemory(renderer, vulkanCommandBuffer)) 10814 { 10815 SDL_LogError(SDL_LOG_CATEGORY_GPU, "%s", "Failed to defragment memory, likely OOM!"); 10816 } 10817 } 10818 10819 if (!VULKAN_INTERNAL_EndCommandBuffer(renderer, vulkanCommandBuffer)) { 10820 SDL_UnlockMutex(renderer->submitLock); 10821 return false; 10822 } 10823 10824 vulkanCommandBuffer->inFlightFence = VULKAN_INTERNAL_AcquireFenceFromPool(renderer); 10825 if (vulkanCommandBuffer->inFlightFence == NULL) { 10826 SDL_UnlockMutex(renderer->submitLock); 10827 return false; 10828 } 10829 10830 // Command buffer has a reference to the in-flight fence 10831 (void)SDL_AtomicIncRef(&vulkanCommandBuffer->inFlightFence->referenceCount); 10832 10833 submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; 10834 submitInfo.pNext = NULL; 10835 submitInfo.commandBufferCount = 1; 10836 submitInfo.pCommandBuffers = &vulkanCommandBuffer->commandBuffer; 10837 10838 submitInfo.pWaitDstStageMask = waitStages; 10839 submitInfo.pWaitSemaphores = vulkanCommandBuffer->waitSemaphores; 10840 submitInfo.waitSemaphoreCount = vulkanCommandBuffer->waitSemaphoreCount; 10841 submitInfo.pSignalSemaphores = vulkanCommandBuffer->signalSemaphores; 10842 submitInfo.signalSemaphoreCount = vulkanCommandBuffer->signalSemaphoreCount; 10843 10844 vulkanResult = renderer->vkQueueSubmit( 10845 renderer->unifiedQueue, 10846 1, 10847 &submitInfo, 10848 vulkanCommandBuffer->inFlightFence->fence); 10849 10850 if (vulkanResult != VK_SUCCESS) { 10851 SDL_UnlockMutex(renderer->submitLock); 10852 CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkQueueSubmit, false); 10853 } 10854 10855 // Present, if applicable 10856 for (Uint32 j = 0; j < vulkanCommandBuffer->presentDataCount; j += 1) { 10857 presentData = &vulkanCommandBuffer->presentDatas[j]; 10858 10859 presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; 10860 presentInfo.pNext = NULL; 10861 presentInfo.pWaitSemaphores = 10862 &presentData->windowData->renderFinishedSemaphore[presentData->swapchainImageIndex]; 10863 presentInfo.waitSemaphoreCount = 1; 10864 presentInfo.pSwapchains = &presentData->windowData->swapchain; 10865 presentInfo.swapchainCount = 1; 10866 presentInfo.pImageIndices = &presentData->swapchainImageIndex; 10867 presentInfo.pResults = NULL; 10868 10869 presentResult = renderer->vkQueuePresentKHR( 10870 renderer->unifiedQueue, 10871 &presentInfo); 10872 10873 if (presentResult == VK_SUCCESS || presentResult == VK_SUBOPTIMAL_KHR || presentResult == VK_ERROR_OUT_OF_DATE_KHR) { 10874 // If presenting, the swapchain is using the in-flight fence 10875 presentData->windowData->inFlightFences[presentData->windowData->frameCounter] = (SDL_GPUFence *)vulkanCommandBuffer->inFlightFence; 10876 (void)SDL_AtomicIncRef(&vulkanCommandBuffer->inFlightFence->referenceCount); 10877 10878// On the Android platform, VK_SUBOPTIMAL_KHR is returned whenever the device is rotated. We'll just ignore this for now. 10879#ifndef SDL_PLATFORM_ANDROID 10880 if (presentResult == VK_SUBOPTIMAL_KHR) { 10881 presentData->windowData->needsSwapchainRecreate = true; 10882 } 10883#endif 10884 if (presentResult == VK_ERROR_OUT_OF_DATE_KHR) { 10885 presentData->windowData->needsSwapchainRecreate = true; 10886 } 10887 } else if (presentResult == VK_ERROR_SURFACE_LOST_KHR) { 10888 // Android can destroy the surface at any time when the app goes into the background, 10889 // even after successfully acquiring a swapchain texture and before presenting it. 10890 presentData->windowData->needsSwapchainRecreate = true; 10891 presentData->windowData->needsSurfaceRecreate = true; 10892 } else { 10893 if (presentResult != VK_SUCCESS) { 10894 VULKAN_INTERNAL_ReleaseCommandBuffer(vulkanCommandBuffer); 10895 SDL_UnlockMutex(renderer->submitLock); 10896 } 10897 10898 CHECK_VULKAN_ERROR_AND_RETURN(presentResult, vkQueuePresentKHR, false); 10899 } 10900 10901 presentData->windowData->frameCounter = 10902 (presentData->windowData->frameCounter + 1) % renderer->allowedFramesInFlight; 10903 } 10904 10905 if (performCleanups) { 10906 for (Sint32 i = renderer->submittedCommandBufferCount - 1; i >= 0; i -= 1) { 10907 vulkanResult = renderer->vkGetFenceStatus( 10908 renderer->logicalDevice, 10909 renderer->submittedCommandBuffers[i]->inFlightFence->fence); 10910 10911 if (vulkanResult == VK_SUCCESS) { 10912 VULKAN_INTERNAL_CleanCommandBuffer( 10913 renderer, 10914 renderer->submittedCommandBuffers[i], 10915 false); 10916 } 10917 } 10918 10919 if (renderer->checkEmptyAllocations) { 10920 SDL_LockMutex(renderer->allocatorLock); 10921 10922 for (Uint32 i = 0; i < VK_MAX_MEMORY_TYPES; i += 1) { 10923 allocator = &renderer->memoryAllocator->subAllocators[i]; 10924 10925 for (Sint32 j = allocator->allocationCount - 1; j >= 0; j -= 1) { 10926 if (allocator->allocations[j]->usedRegionCount == 0) { 10927 VULKAN_INTERNAL_DeallocateMemory( 10928 renderer, 10929 allocator, 10930 j); 10931 } 10932 } 10933 } 10934 10935 renderer->checkEmptyAllocations = false; 10936 10937 SDL_UnlockMutex(renderer->allocatorLock); 10938 } 10939 10940 VULKAN_INTERNAL_PerformPendingDestroys(renderer); 10941 } 10942 10943 // Mark command buffer as submitted 10944 VULKAN_INTERNAL_ReleaseCommandBuffer(vulkanCommandBuffer); 10945 10946 SDL_UnlockMutex(renderer->submitLock); 10947 10948 return true; 10949} 10950 10951static bool VULKAN_Cancel( 10952 SDL_GPUCommandBuffer *commandBuffer) 10953{ 10954 VulkanRenderer *renderer; 10955 VulkanCommandBuffer *vulkanCommandBuffer; 10956 VkResult result; 10957 10958 vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; 10959 renderer = vulkanCommandBuffer->renderer; 10960 10961 result = renderer->vkResetCommandBuffer( 10962 vulkanCommandBuffer->commandBuffer, 10963 VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT); 10964 CHECK_VULKAN_ERROR_AND_RETURN(result, vkResetCommandBuffer, false); 10965 10966 vulkanCommandBuffer->autoReleaseFence = false; 10967 SDL_LockMutex(renderer->submitLock); 10968 VULKAN_INTERNAL_CleanCommandBuffer(renderer, vulkanCommandBuffer, true); 10969 SDL_UnlockMutex(renderer->submitLock); 10970 10971 return true; 10972} 10973 10974static bool VULKAN_INTERNAL_DefragmentMemory( 10975 VulkanRenderer *renderer, 10976 VulkanCommandBuffer *commandBuffer) 10977{ 10978 renderer->defragInProgress = 1; 10979 commandBuffer->isDefrag = 1; 10980 10981 SDL_LockMutex(renderer->allocatorLock); 10982 SDL_LockRWLockForWriting(renderer->defragLock); 10983 10984 // Find an allocation that doesn't have any pending transfer operations 10985 Sint32 indexToDefrag = -1; 10986 for (Sint32 i = renderer->allocationsToDefragCount - 1; i >= 0; i -= 1) { 10987 if (SDL_GetAtomicInt(&renderer->allocationsToDefrag[i]->referenceCount) == 0) { 10988 indexToDefrag = i; 10989 break; 10990 } 10991 } 10992 10993 if (indexToDefrag == -1) { 10994 // Nothing is available to defrag, but it's not an error 10995 SDL_UnlockRWLock(renderer->defragLock); 10996 SDL_UnlockMutex(renderer->allocatorLock); 10997 return true; 10998 } 10999 11000 VulkanMemoryAllocation *allocation = renderer->allocationsToDefrag[indexToDefrag]; 11001 11002 // Plug the hole 11003 if ((Uint32) indexToDefrag != renderer->allocationsToDefragCount - 1) { 11004 renderer->allocationsToDefrag[indexToDefrag] = renderer->allocationsToDefrag[renderer->allocationsToDefragCount - 1]; 11005 } 11006 renderer->allocationsToDefragCount -= 1; 11007 11008 /* For each used region in the allocation 11009 * create a new resource, copy the data 11010 * and re-point the resource containers 11011 */ 11012 for (Uint32 i = 0; i < allocation->usedRegionCount; i += 1) { 11013 VulkanMemoryUsedRegion *currentRegion = allocation->usedRegions[i]; 11014 11015 if (currentRegion->isBuffer && !currentRegion->vulkanBuffer->markedForDestroy) { 11016 VulkanBuffer *newBuffer = VULKAN_INTERNAL_CreateBuffer( 11017 renderer, 11018 currentRegion->vulkanBuffer->size, 11019 currentRegion->vulkanBuffer->usage, 11020 currentRegion->vulkanBuffer->type, 11021 false, 11022 currentRegion->vulkanBuffer->container != NULL ? currentRegion->vulkanBuffer->container->debugName : NULL); 11023 11024 if (newBuffer == NULL) { 11025 SDL_UnlockRWLock(renderer->defragLock); 11026 SDL_UnlockMutex(renderer->allocatorLock); 11027 SDL_LogError(SDL_LOG_CATEGORY_GPU, "%s", "Failed to allocate defrag buffer!"); 11028 return false; 11029 } 11030 11031 // Copy buffer contents if necessary 11032 if ( 11033 currentRegion->vulkanBuffer->type == VULKAN_BUFFER_TYPE_GPU && currentRegion->vulkanBuffer->transitioned) { 11034 VULKAN_INTERNAL_BufferTransitionFromDefaultUsage( 11035 renderer, 11036 commandBuffer, 11037 VULKAN_BUFFER_USAGE_MODE_COPY_SOURCE, 11038 currentRegion->vulkanBuffer); 11039 11040 VULKAN_INTERNAL_BufferTransitionFromDefaultUsage( 11041 renderer, 11042 commandBuffer, 11043 VULKAN_BUFFER_USAGE_MODE_COPY_DESTINATION, 11044 newBuffer); 11045 11046 VkBufferCopy bufferCopy; 11047 bufferCopy.srcOffset = 0; 11048 bufferCopy.dstOffset = 0; 11049 bufferCopy.size = currentRegion->resourceSize; 11050 11051 renderer->vkCmdCopyBuffer( 11052 commandBuffer->commandBuffer, 11053 currentRegion->vulkanBuffer->buffer, 11054 newBuffer->buffer, 11055 1, 11056 &bufferCopy); 11057 11058 VULKAN_INTERNAL_BufferTransitionToDefaultUsage( 11059 renderer, 11060 commandBuffer, 11061 VULKAN_BUFFER_USAGE_MODE_COPY_DESTINATION, 11062 newBuffer); 11063 11064 VULKAN_INTERNAL_TrackBuffer(commandBuffer, currentRegion->vulkanBuffer); 11065 VULKAN_INTERNAL_TrackBuffer(commandBuffer, newBuffer); 11066 } 11067 11068 // re-point original container to new buffer 11069 newBuffer->container = currentRegion->vulkanBuffer->container; 11070 newBuffer->containerIndex = currentRegion->vulkanBuffer->containerIndex; 11071 if (newBuffer->type == VULKAN_BUFFER_TYPE_UNIFORM) { 11072 currentRegion->vulkanBuffer->uniformBufferForDefrag->buffer = newBuffer; 11073 } else { 11074 newBuffer->container->buffers[newBuffer->containerIndex] = newBuffer; 11075 if (newBuffer->container->activeBuffer == currentRegion->vulkanBuffer) { 11076 newBuffer->container->activeBuffer = newBuffer; 11077 } 11078 } 11079 11080 if (currentRegion->vulkanBuffer->uniformBufferForDefrag) { 11081 newBuffer->uniformBufferForDefrag = currentRegion->vulkanBuffer->uniformBufferForDefrag; 11082 } 11083 11084 VULKAN_INTERNAL_ReleaseBuffer(renderer, currentRegion->vulkanBuffer); 11085 } else if (!currentRegion->isBuffer && !currentRegion->vulkanTexture->markedForDestroy) { 11086 VulkanTexture *newTexture = VULKAN_INTERNAL_CreateTexture( 11087 renderer, 11088 &currentRegion->vulkanTexture->container->header.info); 11089 11090 if (newTexture == NULL) { 11091 SDL_UnlockRWLock(renderer->defragLock); 11092 SDL_UnlockMutex(renderer->allocatorLock); 11093 SDL_LogError(SDL_LOG_CATEGORY_GPU, "%s", "Failed to allocate defrag buffer!"); 11094 return false; 11095 } 11096 11097 SDL_GPUTextureCreateInfo info = currentRegion->vulkanTexture->container->header.info; 11098 for (Uint32 subresourceIndex = 0; subresourceIndex < currentRegion->vulkanTexture->subresourceCount; subresourceIndex += 1) { 11099 // copy subresource if necessary 11100 VulkanTextureSubresource *srcSubresource = &currentRegion->vulkanTexture->subresources[subresourceIndex]; 11101 VulkanTextureSubresource *dstSubresource = &newTexture->subresources[subresourceIndex]; 11102 11103 VULKAN_INTERNAL_TextureSubresourceTransitionFromDefaultUsage( 11104 renderer, 11105 commandBuffer, 11106 VULKAN_TEXTURE_USAGE_MODE_COPY_SOURCE, 11107 srcSubresource); 11108 11109 VULKAN_INTERNAL_TextureSubresourceMemoryBarrier( 11110 renderer, 11111 commandBuffer, 11112 VULKAN_TEXTURE_USAGE_MODE_UNINITIALIZED, 11113 VULKAN_TEXTURE_USAGE_MODE_COPY_DESTINATION, 11114 dstSubresource); 11115 11116 VkImageCopy imageCopy; 11117 imageCopy.srcOffset.x = 0; 11118 imageCopy.srcOffset.y = 0; 11119 imageCopy.srcOffset.z = 0; 11120 imageCopy.srcSubresource.aspectMask = srcSubresource->parent->aspectFlags; 11121 imageCopy.srcSubresource.baseArrayLayer = srcSubresource->layer; 11122 imageCopy.srcSubresource.layerCount = 1; 11123 imageCopy.srcSubresource.mipLevel = srcSubresource->level; 11124 imageCopy.extent.width = SDL_max(1, info.width >> srcSubresource->level); 11125 imageCopy.extent.height = SDL_max(1, info.height >> srcSubresource->level); 11126 imageCopy.extent.depth = info.type == SDL_GPU_TEXTURETYPE_3D ? info.layer_count_or_depth : 1; 11127 imageCopy.dstOffset.x = 0; 11128 imageCopy.dstOffset.y = 0; 11129 imageCopy.dstOffset.z = 0; 11130 imageCopy.dstSubresource.aspectMask = dstSubresource->parent->aspectFlags; 11131 imageCopy.dstSubresource.baseArrayLayer = dstSubresource->layer; 11132 imageCopy.dstSubresource.layerCount = 1; 11133 imageCopy.dstSubresource.mipLevel = dstSubresource->level; 11134 11135 renderer->vkCmdCopyImage( 11136 commandBuffer->commandBuffer, 11137 currentRegion->vulkanTexture->image, 11138 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, 11139 newTexture->image, 11140 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 11141 1, 11142 &imageCopy); 11143 11144 VULKAN_INTERNAL_TextureSubresourceTransitionToDefaultUsage( 11145 renderer, 11146 commandBuffer, 11147 VULKAN_TEXTURE_USAGE_MODE_COPY_DESTINATION, 11148 dstSubresource); 11149 11150 VULKAN_INTERNAL_TrackTexture(commandBuffer, srcSubresource->parent); 11151 VULKAN_INTERNAL_TrackTexture(commandBuffer, dstSubresource->parent); 11152 } 11153 11154 // re-point original container to new texture 11155 newTexture->container = currentRegion->vulkanTexture->container; 11156 newTexture->containerIndex = currentRegion->vulkanTexture->containerIndex; 11157 newTexture->container->textures[currentRegion->vulkanTexture->containerIndex] = newTexture; 11158 if (currentRegion->vulkanTexture == currentRegion->vulkanTexture->container->activeTexture) { 11159 newTexture->container->activeTexture = newTexture; 11160 } 11161 11162 VULKAN_INTERNAL_ReleaseTexture(renderer, currentRegion->vulkanTexture); 11163 } 11164 } 11165 11166 SDL_UnlockRWLock(renderer->defragLock); 11167 SDL_UnlockMutex(renderer->allocatorLock); 11168 11169 return true; 11170} 11171 11172// Format Info 11173 11174static bool VULKAN_SupportsTextureFormat( 11175 SDL_GPURenderer *driverData, 11176 SDL_GPUTextureFormat format, 11177 SDL_GPUTextureType type, 11178 SDL_GPUTextureUsageFlags usage) 11179{ 11180 VulkanRenderer *renderer = (VulkanRenderer *)driverData; 11181 VkFormat vulkanFormat = SDLToVK_TextureFormat[format]; 11182 VkImageUsageFlags vulkanUsage = 0; 11183 VkImageCreateFlags createFlags = 0; 11184 VkImageFormatProperties properties; 11185 VkResult vulkanResult; 11186 11187 if (usage & SDL_GPU_TEXTUREUSAGE_SAMPLER) { 11188 vulkanUsage |= VK_IMAGE_USAGE_SAMPLED_BIT; 11189 } 11190 if (usage & SDL_GPU_TEXTUREUSAGE_COLOR_TARGET) { 11191 vulkanUsage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; 11192 } 11193 if (usage & SDL_GPU_TEXTUREUSAGE_DEPTH_STENCIL_TARGET) { 11194 vulkanUsage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; 11195 } 11196 if (usage & (SDL_GPU_TEXTUREUSAGE_GRAPHICS_STORAGE_READ | 11197 SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_READ | 11198 SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_WRITE | 11199 SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_SIMULTANEOUS_READ_WRITE)) { 11200 vulkanUsage |= VK_IMAGE_USAGE_STORAGE_BIT; 11201 } 11202 11203 if (type == SDL_GPU_TEXTURETYPE_CUBE || type == SDL_GPU_TEXTURETYPE_CUBE_ARRAY) { 11204 createFlags = VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT; 11205 } 11206 11207 vulkanResult = renderer->vkGetPhysicalDeviceImageFormatProperties( 11208 renderer->physicalDevice, 11209 vulkanFormat, 11210 (type == SDL_GPU_TEXTURETYPE_3D) ? VK_IMAGE_TYPE_3D : VK_IMAGE_TYPE_2D, 11211 VK_IMAGE_TILING_OPTIMAL, 11212 vulkanUsage, 11213 createFlags, 11214 &properties); 11215 11216 return vulkanResult == VK_SUCCESS; 11217} 11218 11219// Device instantiation 11220 11221static inline Uint8 CheckDeviceExtensions( 11222 VkExtensionProperties *extensions, 11223 Uint32 numExtensions, 11224 VulkanExtensions *supports) 11225{ 11226 Uint32 i; 11227 11228 SDL_memset(supports, '\0', sizeof(VulkanExtensions)); 11229 for (i = 0; i < numExtensions; i += 1) { 11230 const char *name = extensions[i].extensionName; 11231#define CHECK(ext) \ 11232 if (SDL_strcmp(name, "VK_" #ext) == 0) { \ 11233 supports->ext = 1; \ 11234 } 11235 CHECK(KHR_swapchain) 11236 else CHECK(KHR_maintenance1) else CHECK(KHR_driver_properties) else CHECK(KHR_portability_subset) else CHECK(MSFT_layered_driver) else CHECK(EXT_texture_compression_astc_hdr) 11237#undef CHECK 11238 } 11239 11240 return (supports->KHR_swapchain && 11241 supports->KHR_maintenance1); 11242} 11243 11244static inline Uint32 GetDeviceExtensionCount(VulkanExtensions *supports) 11245{ 11246 return ( 11247 supports->KHR_swapchain + 11248 supports->KHR_maintenance1 + 11249 supports->KHR_driver_properties + 11250 supports->KHR_portability_subset + 11251 supports->MSFT_layered_driver + 11252 supports->EXT_texture_compression_astc_hdr); 11253} 11254 11255static inline void CreateDeviceExtensionArray( 11256 VulkanExtensions *supports, 11257 const char **extensions) 11258{ 11259 Uint8 cur = 0; 11260#define CHECK(ext) \ 11261 if (supports->ext) { \ 11262 extensions[cur++] = "VK_" #ext; \ 11263 } 11264 CHECK(KHR_swapchain) 11265 CHECK(KHR_maintenance1) 11266 CHECK(KHR_driver_properties) 11267 CHECK(KHR_portability_subset) 11268 CHECK(MSFT_layered_driver) 11269 CHECK(EXT_texture_compression_astc_hdr) 11270#undef CHECK 11271} 11272 11273static inline Uint8 SupportsInstanceExtension( 11274 const char *ext, 11275 VkExtensionProperties *availableExtensions, 11276 Uint32 numAvailableExtensions) 11277{ 11278 Uint32 i; 11279 for (i = 0; i < numAvailableExtensions; i += 1) { 11280 if (SDL_strcmp(ext, availableExtensions[i].extensionName) == 0) { 11281 return 1; 11282 } 11283 } 11284 return 0; 11285} 11286 11287static Uint8 VULKAN_INTERNAL_CheckInstanceExtensions( 11288 const char **requiredExtensions, 11289 Uint32 requiredExtensionsLength, 11290 bool *supportsDebugUtils, 11291 bool *supportsColorspace, 11292 bool *supportsPhysicalDeviceProperties2, 11293 bool *supportsPortabilityEnumeration, 11294 int *firstUnsupportedExtensionIndex) 11295{ 11296 Uint32 extensionCount, i; 11297 VkExtensionProperties *availableExtensions; 11298 Uint8 allExtensionsSupported = 1; 11299 11300 vkEnumerateInstanceExtensionProperties( 11301 NULL, 11302 &extensionCount, 11303 NULL); 11304 availableExtensions = SDL_malloc( 11305 extensionCount * sizeof(VkExtensionProperties)); 11306 vkEnumerateInstanceExtensionProperties( 11307 NULL, 11308 &extensionCount, 11309 availableExtensions); 11310 11311 for (i = 0; i < requiredExtensionsLength; i += 1) { 11312 if (!SupportsInstanceExtension( 11313 requiredExtensions[i], 11314 availableExtensions, 11315 extensionCount)) { 11316 allExtensionsSupported = 0; 11317 *firstUnsupportedExtensionIndex = i; 11318 break; 11319 } 11320 } 11321 11322 // This is optional, but nice to have! 11323 *supportsDebugUtils = SupportsInstanceExtension( 11324 VK_EXT_DEBUG_UTILS_EXTENSION_NAME, 11325 availableExtensions, 11326 extensionCount); 11327 11328 // Also optional and nice to have! 11329 *supportsColorspace = SupportsInstanceExtension( 11330 VK_EXT_SWAPCHAIN_COLOR_SPACE_EXTENSION_NAME, 11331 availableExtensions, 11332 extensionCount); 11333 11334 // Only needed for KHR_driver_properties! 11335 *supportsPhysicalDeviceProperties2 = SupportsInstanceExtension( 11336 VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, 11337 availableExtensions, 11338 extensionCount); 11339 11340 // Only needed for MoltenVK! 11341 *supportsPortabilityEnumeration = SupportsInstanceExtension( 11342 VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME, 11343 availableExtensions, 11344 extensionCount); 11345 11346 SDL_free(availableExtensions); 11347 return allExtensionsSupported; 11348} 11349 11350static Uint8 CheckOptInDeviceExtensions(VulkanFeatures *features, 11351 Uint32 numExtensions, 11352 VkExtensionProperties *availableExtensions, 11353 const char **missingExtensionName) { 11354 Uint8 supportsAll = 1; 11355 for (Uint32 extensionIdx = 0; extensionIdx < features->additionalDeviceExtensionCount; extensionIdx++) { 11356 bool found = false; 11357 for (Uint32 searchIdx = 0; searchIdx < numExtensions; searchIdx++) { 11358 if (SDL_strcmp(features->additionalDeviceExtensionNames[extensionIdx], availableExtensions[searchIdx].extensionName) == 0) { 11359 found = true; 11360 break; 11361 } 11362 } 11363 if (!found) { 11364 supportsAll = 0; 11365 *missingExtensionName = features->additionalDeviceExtensionNames[extensionIdx]; 11366 break; 11367 } 11368 } 11369 11370 return supportsAll; 11371} 11372 11373static Uint8 VULKAN_INTERNAL_CheckDeviceExtensions( 11374 VulkanRenderer *renderer, 11375 VulkanFeatures *features, 11376 VkPhysicalDevice physicalDevice, 11377 VulkanExtensions *physicalDeviceExtensions) 11378{ 11379 Uint32 extensionCount; 11380 VkExtensionProperties *availableExtensions; 11381 Uint8 allExtensionsSupported; 11382 11383 renderer->vkEnumerateDeviceExtensionProperties( 11384 physicalDevice, 11385 NULL, 11386 &extensionCount, 11387 NULL); 11388 availableExtensions = (VkExtensionProperties *)SDL_malloc( 11389 extensionCount * sizeof(VkExtensionProperties)); 11390 renderer->vkEnumerateDeviceExtensionProperties( 11391 physicalDevice, 11392 NULL, 11393 &extensionCount, 11394 availableExtensions); 11395 11396 allExtensionsSupported = CheckDeviceExtensions( 11397 availableExtensions, 11398 extensionCount, 11399 physicalDeviceExtensions); 11400 11401 if (features->usesCustomVulkanOptions) { 11402 const char *missingExtensionName; 11403 if (!CheckOptInDeviceExtensions(features, extensionCount, availableExtensions, &missingExtensionName)) { 11404 SDL_assert(missingExtensionName); 11405 if (renderer->debugMode) { 11406 SDL_LogError(SDL_LOG_CATEGORY_GPU, 11407 "Required Vulkan device extension '%s' not supported", 11408 missingExtensionName); 11409 } 11410 allExtensionsSupported = 0; 11411 } 11412 } 11413 11414 SDL_free(availableExtensions); 11415 return allExtensionsSupported; 11416} 11417 11418static Uint8 VULKAN_INTERNAL_CheckValidationLayers( 11419 const char **validationLayers, 11420 Uint32 validationLayersLength) 11421{ 11422 Uint32 layerCount; 11423 VkLayerProperties *availableLayers; 11424 Uint32 i, j; 11425 Uint8 layerFound = 0; 11426 11427 vkEnumerateInstanceLayerProperties(&layerCount, NULL); 11428 availableLayers = (VkLayerProperties *)SDL_malloc( 11429 layerCount * sizeof(VkLayerProperties)); 11430 vkEnumerateInstanceLayerProperties(&layerCount, availableLayers); 11431 11432 for (i = 0; i < validationLayersLength; i += 1) { 11433 layerFound = 0; 11434 11435 for (j = 0; j < layerCount; j += 1) { 11436 if (SDL_strcmp(validationLayers[i], availableLayers[j].layerName) == 0) { 11437 layerFound = 1; 11438 break; 11439 } 11440 } 11441 11442 if (!layerFound) { 11443 break; 11444 } 11445 } 11446 11447 SDL_free(availableLayers); 11448 return layerFound; 11449} 11450 11451#define CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, feature, result) \ 11452 if (requested->feature && !supported->feature) { \ 11453 SDL_LogVerbose( \ 11454 SDL_LOG_CATEGORY_GPU, \ 11455 "SDL GPU Vulkan: Application requested unsupported physical device feature '" #feature "'"); \ 11456 result = false; \ 11457 } 11458 11459static bool VULKAN_INTERNAL_ValidateOptInVulkan10Features(VkPhysicalDeviceFeatures *requested, VkPhysicalDeviceFeatures *supported) 11460{ 11461 if (requested && supported) { 11462 bool result = true; 11463 11464 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, robustBufferAccess, result) 11465 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, fullDrawIndexUint32, result) 11466 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, imageCubeArray, result) 11467 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, independentBlend, result) 11468 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, geometryShader, result) 11469 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, tessellationShader, result) 11470 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, sampleRateShading, result) 11471 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, dualSrcBlend, result) 11472 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, logicOp, result) 11473 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, multiDrawIndirect, result) 11474 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, drawIndirectFirstInstance, result) 11475 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, depthClamp, result) 11476 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, depthBiasClamp, result) 11477 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, fillModeNonSolid, result) 11478 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, depthBounds, result) 11479 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, wideLines, result) 11480 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, largePoints, result) 11481 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, alphaToOne, result) 11482 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, multiViewport, result) 11483 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, samplerAnisotropy, result) 11484 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, textureCompressionETC2, result) 11485 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, textureCompressionASTC_LDR, result) 11486 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, textureCompressionBC, result) 11487 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, occlusionQueryPrecise, result) 11488 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, pipelineStatisticsQuery, result) 11489 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, vertexPipelineStoresAndAtomics, result) 11490 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, fragmentStoresAndAtomics, result) 11491 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, shaderTessellationAndGeometryPointSize, result) 11492 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, shaderImageGatherExtended, result) 11493 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, shaderStorageImageExtendedFormats, result) 11494 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, shaderStorageImageMultisample, result) 11495 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, shaderStorageImageReadWithoutFormat, result) 11496 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, shaderStorageImageWriteWithoutFormat, result) 11497 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, shaderUniformBufferArrayDynamicIndexing, result) 11498 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, shaderSampledImageArrayDynamicIndexing, result) 11499 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, shaderStorageBufferArrayDynamicIndexing, result) 11500 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, shaderStorageImageArrayDynamicIndexing, result) 11501 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, shaderClipDistance, result) 11502 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, shaderCullDistance, result) 11503 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, shaderFloat64, result) 11504 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, shaderInt64, result) 11505 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, shaderInt16, result) 11506 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, shaderResourceResidency, result) 11507 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, shaderResourceMinLod, result) 11508 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, sparseBinding, result) 11509 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, sparseResidencyBuffer, result) 11510 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, sparseResidencyImage2D, result) 11511 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, sparseResidencyImage3D, result) 11512 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, sparseResidency2Samples, result) 11513 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, sparseResidency4Samples, result) 11514 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, sparseResidency8Samples, result) 11515 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, sparseResidency16Samples, result) 11516 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, sparseResidencyAliased, result) 11517 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, variableMultisampleRate, result) 11518 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, inheritedQueries, result) 11519 11520 return result; 11521 } else { 11522 return false; 11523 } 11524} 11525 11526static bool VULKAN_INTERNAL_ValidateOptInVulkan11Features(VkPhysicalDeviceVulkan11Features *requested, VkPhysicalDeviceVulkan11Features *supported) 11527{ 11528 if (requested && supported) { 11529 bool result = true; 11530 11531 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, storageBuffer16BitAccess, result) 11532 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, uniformAndStorageBuffer16BitAccess, result) 11533 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, storagePushConstant16, result) 11534 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, storageInputOutput16, result) 11535 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, multiview, result) 11536 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, multiviewGeometryShader, result) 11537 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, multiviewTessellationShader, result) 11538 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, variablePointersStorageBuffer, result) 11539 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, variablePointers, result) 11540 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, protectedMemory, result) 11541 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, samplerYcbcrConversion, result) 11542 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, shaderDrawParameters, result) 11543 11544 return result; 11545 } else { 11546 return false; 11547 } 11548} 11549 11550static bool VULKAN_INTERNAL_ValidateOptInVulkan12Features(VkPhysicalDeviceVulkan12Features *requested, VkPhysicalDeviceVulkan12Features *supported) 11551{ 11552 if (requested && supported) { 11553 bool result = true; 11554 11555 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, samplerMirrorClampToEdge, result) 11556 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, drawIndirectCount, result) 11557 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, storageBuffer8BitAccess, result) 11558 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, uniformAndStorageBuffer8BitAccess, result) 11559 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, storagePushConstant8, result) 11560 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, shaderBufferInt64Atomics, result) 11561 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, shaderSharedInt64Atomics, result) 11562 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, shaderFloat16, result) 11563 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, shaderInt8, result) 11564 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, descriptorIndexing, result) 11565 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, shaderInputAttachmentArrayDynamicIndexing, result) 11566 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, shaderUniformTexelBufferArrayDynamicIndexing, result) 11567 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, shaderStorageTexelBufferArrayDynamicIndexing, result) 11568 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, shaderUniformBufferArrayNonUniformIndexing, result) 11569 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, shaderSampledImageArrayNonUniformIndexing, result) 11570 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, shaderStorageBufferArrayNonUniformIndexing, result) 11571 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, shaderStorageImageArrayNonUniformIndexing, result) 11572 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, shaderInputAttachmentArrayNonUniformIndexing, result) 11573 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, shaderUniformTexelBufferArrayNonUniformIndexing, result) 11574 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, shaderStorageTexelBufferArrayNonUniformIndexing, result) 11575 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, descriptorBindingUniformBufferUpdateAfterBind, result) 11576 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, descriptorBindingSampledImageUpdateAfterBind, result) 11577 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, descriptorBindingStorageImageUpdateAfterBind, result) 11578 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, descriptorBindingStorageBufferUpdateAfterBind, result) 11579 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, descriptorBindingUniformTexelBufferUpdateAfterBind, result) 11580 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, descriptorBindingStorageTexelBufferUpdateAfterBind, result) 11581 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, descriptorBindingUpdateUnusedWhilePending, result) 11582 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, descriptorBindingPartiallyBound, result) 11583 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, descriptorBindingVariableDescriptorCount, result) 11584 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, runtimeDescriptorArray, result) 11585 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, samplerFilterMinmax, result) 11586 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, scalarBlockLayout, result) 11587 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, imagelessFramebuffer, result) 11588 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, uniformBufferStandardLayout, result) 11589 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, shaderSubgroupExtendedTypes, result) 11590 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, separateDepthStencilLayouts, result) 11591 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, hostQueryReset, result) 11592 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, timelineSemaphore, result) 11593 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, bufferDeviceAddress, result) 11594 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, bufferDeviceAddressCaptureReplay, result) 11595 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, bufferDeviceAddressMultiDevice, result) 11596 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, vulkanMemoryModel, result) 11597 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, vulkanMemoryModelDeviceScope, result) 11598 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, vulkanMemoryModelAvailabilityVisibilityChains, result) 11599 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, shaderOutputViewportIndex, result) 11600 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, shaderOutputLayer, result) 11601 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, subgroupBroadcastDynamicId, result) 11602 11603 return result; 11604 } else { 11605 return false; 11606 } 11607} 11608 11609static bool VULKAN_INTERNAL_ValidateOptInVulkan13Features(VkPhysicalDeviceVulkan13Features *requested, VkPhysicalDeviceVulkan13Features *supported) 11610{ 11611 if (requested && supported) { 11612 bool result = true; 11613 11614 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, robustImageAccess, result) 11615 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, inlineUniformBlock, result) 11616 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, descriptorBindingInlineUniformBlockUpdateAfterBind, result) 11617 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, pipelineCreationCacheControl, result) 11618 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, privateData, result) 11619 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, shaderDemoteToHelperInvocation, result) 11620 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, shaderTerminateInvocation, result) 11621 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, subgroupSizeControl, result) 11622 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, computeFullSubgroups, result) 11623 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, synchronization2, result) 11624 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, textureCompressionASTC_HDR, result) 11625 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, shaderZeroInitializeWorkgroupMemory, result) 11626 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, dynamicRendering, result) 11627 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, shaderIntegerDotProduct, result) 11628 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, maintenance4, result) 11629 11630 return result; 11631 } else { 11632 return false; 11633 } 11634} 11635 11636#undef CHECK_OPTIONAL_DEVICE_FEATURE 11637 11638static bool VULKAN_INTERNAL_ValidateOptInFeatures(VulkanRenderer *renderer, VulkanFeatures *features, VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures *vk10Features) 11639{ 11640 bool supportsAllFeatures = true; 11641 11642 int minorVersion = VK_API_VERSION_MINOR(features->desiredApiVersion); 11643 11644 if (minorVersion < 1) { 11645 supportsAllFeatures &= VULKAN_INTERNAL_ValidateOptInVulkan10Features(&features->desiredVulkan10DeviceFeatures, vk10Features); 11646 } else if (minorVersion < 2) { 11647 // Query device features using the pre-1.2 structures 11648 VkPhysicalDevice16BitStorageFeatures storage = { 0 }; 11649 storage.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES; 11650 11651 VkPhysicalDeviceMultiviewFeatures multiview = { 0 }; 11652 multiview.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES; 11653 11654 VkPhysicalDeviceProtectedMemoryFeatures protectedMem = { 0 }; 11655 protectedMem.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_FEATURES; 11656 11657 VkPhysicalDeviceSamplerYcbcrConversionFeatures ycbcr = { 0 }; 11658 ycbcr.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES; 11659 11660 VkPhysicalDeviceShaderDrawParametersFeatures drawParams = { 0 }; 11661 drawParams.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETERS_FEATURES; 11662 11663 VkPhysicalDeviceVariablePointersFeatures varPointers = { 0 }; 11664 varPointers.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTERS_FEATURES; 11665 11666 VkPhysicalDeviceFeatures2 supportedFeatureList = { 0 }; 11667 supportedFeatureList.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; 11668 supportedFeatureList.pNext = &storage; 11669 storage.pNext = &multiview; 11670 multiview.pNext = &protectedMem; 11671 protectedMem.pNext = &ycbcr; 11672 ycbcr.pNext = &drawParams; 11673 drawParams.pNext = &varPointers; 11674 11675 renderer->vkGetPhysicalDeviceFeatures2(physicalDevice, &supportedFeatureList); 11676 11677 // Pack the results into the post-1.2 structure for easier checking 11678 VkPhysicalDeviceVulkan11Features vk11Features = { 0 }; 11679 vk11Features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES; 11680 vk11Features.storageBuffer16BitAccess = storage.storageBuffer16BitAccess; 11681 vk11Features.uniformAndStorageBuffer16BitAccess = storage.uniformAndStorageBuffer16BitAccess; 11682 vk11Features.storagePushConstant16 = storage.storagePushConstant16; 11683 vk11Features.storageInputOutput16 = storage.storageInputOutput16; 11684 vk11Features.multiview = multiview.multiview; 11685 vk11Features.multiviewGeometryShader = multiview.multiviewGeometryShader; 11686 vk11Features.multiviewTessellationShader = multiview.multiviewTessellationShader; 11687 vk11Features.protectedMemory = protectedMem.protectedMemory; 11688 vk11Features.samplerYcbcrConversion = ycbcr.samplerYcbcrConversion; 11689 vk11Features.shaderDrawParameters = drawParams.shaderDrawParameters; 11690 vk11Features.variablePointers = varPointers.variablePointers; 11691 vk11Features.variablePointersStorageBuffer = varPointers.variablePointersStorageBuffer; 11692 11693 // Check support 11694 supportsAllFeatures &= VULKAN_INTERNAL_ValidateOptInVulkan10Features(&features->desiredVulkan10DeviceFeatures, vk10Features); 11695 supportsAllFeatures &= VULKAN_INTERNAL_ValidateOptInVulkan11Features(&features->desiredVulkan11DeviceFeatures, &vk11Features); 11696 } else { 11697 VkPhysicalDeviceVulkan11Features vk11Features = { 0 }; 11698 vk11Features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES; 11699 11700 VkPhysicalDeviceVulkan12Features vk12Features = { 0 }; 11701 vk12Features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES; 11702 11703 VkPhysicalDeviceVulkan13Features vk13Features = { 0 }; 11704 vk13Features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES; 11705 11706 VkPhysicalDeviceFeatures2 supportedFeatureList = { 0 }; 11707 supportedFeatureList.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; 11708 supportedFeatureList.pNext = &vk11Features; 11709 vk11Features.pNext = &vk12Features; 11710 vk12Features.pNext = &vk13Features; 11711 11712 renderer->vkGetPhysicalDeviceFeatures2(physicalDevice, &supportedFeatureList); 11713 11714 supportsAllFeatures &= VULKAN_INTERNAL_ValidateOptInVulkan10Features(&features->desiredVulkan10DeviceFeatures, vk10Features); 11715 supportsAllFeatures &= VULKAN_INTERNAL_ValidateOptInVulkan11Features(&features->desiredVulkan11DeviceFeatures, &vk11Features); 11716 supportsAllFeatures &= VULKAN_INTERNAL_ValidateOptInVulkan12Features(&features->desiredVulkan12DeviceFeatures, &vk12Features); 11717 supportsAllFeatures &= VULKAN_INTERNAL_ValidateOptInVulkan13Features(&features->desiredVulkan13DeviceFeatures, &vk13Features); 11718 } 11719 11720 return supportsAllFeatures; 11721} 11722 11723static void VULKAN_INTERNAL_AddDeviceFeatures(VkBool32 *firstFeature, VkBool32 *lastFeature, VkBool32 *firstFeatureToAdd) 11724{ 11725 while (firstFeature <= lastFeature) { 11726 *firstFeature = (*firstFeature | *firstFeatureToAdd); 11727 firstFeature++; 11728 firstFeatureToAdd++; 11729 } 11730} 11731 11732static bool VULKAN_INTERNAL_TryAddDeviceFeatures_Vulkan_11(VkPhysicalDeviceFeatures *dst10, 11733 VkPhysicalDeviceVulkan11Features *dst11, 11734 VkBaseOutStructure *src) 11735{ 11736 bool hasAdded = false; 11737 switch (src->sType) { 11738 case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2: 11739 { 11740 VkPhysicalDeviceFeatures2 *newFeatures = (VkPhysicalDeviceFeatures2 *)src; 11741 VULKAN_INTERNAL_AddDeviceFeatures(&dst10->robustBufferAccess, 11742 &dst10->inheritedQueries, 11743 &newFeatures->features.robustBufferAccess); 11744 hasAdded = true; 11745 } break; 11746 11747 case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES: 11748 { 11749 VkPhysicalDevice16BitStorageFeatures *newFeatures = (VkPhysicalDevice16BitStorageFeatures *)src; 11750 dst11->storageBuffer16BitAccess |= newFeatures->storageBuffer16BitAccess; 11751 dst11->uniformAndStorageBuffer16BitAccess |= newFeatures->uniformAndStorageBuffer16BitAccess; 11752 dst11->storagePushConstant16 |= newFeatures->storagePushConstant16; 11753 dst11->storageInputOutput16 |= newFeatures->storageInputOutput16; 11754 hasAdded = true; 11755 } break; 11756 11757 case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES: 11758 { 11759 VkPhysicalDeviceMultiviewFeatures *newFeatures = (VkPhysicalDeviceMultiviewFeatures *)src; 11760 dst11->multiview |= newFeatures->multiview; 11761 dst11->multiviewGeometryShader |= newFeatures->multiviewGeometryShader; 11762 dst11->multiviewTessellationShader |= newFeatures->multiviewTessellationShader; 11763 hasAdded = true; 11764 } break; 11765 11766 case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_FEATURES: 11767 { 11768 VkPhysicalDeviceProtectedMemoryFeatures *newFeatures = (VkPhysicalDeviceProtectedMemoryFeatures *)src; 11769 dst11->protectedMemory |= newFeatures->protectedMemory; 11770 hasAdded = true; 11771 } break; 11772 11773 case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES: 11774 { 11775 VkPhysicalDeviceSamplerYcbcrConversionFeatures *newFeatures = (VkPhysicalDeviceSamplerYcbcrConversionFeatures *)src; 11776 dst11->samplerYcbcrConversion |= newFeatures->samplerYcbcrConversion; 11777 hasAdded = true; 11778 } break; 11779 11780 case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETERS_FEATURES: 11781 { 11782 VkPhysicalDeviceShaderDrawParametersFeatures *newFeatures = (VkPhysicalDeviceShaderDrawParametersFeatures *)src; 11783 dst11->shaderDrawParameters |= newFeatures->shaderDrawParameters; 11784 hasAdded = true; 11785 } break; 11786 11787 case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTERS_FEATURES: 11788 { 11789 VkPhysicalDeviceVariablePointersFeatures *newFeatures = (VkPhysicalDeviceVariablePointersFeatures *)src; 11790 dst11->variablePointers |= newFeatures->variablePointers; 11791 dst11->variablePointersStorageBuffer |= newFeatures->variablePointersStorageBuffer; 11792 hasAdded = true; 11793 } break; 11794 11795 default: 11796 break; 11797 } 11798 11799 return hasAdded; 11800} 11801 11802static bool VULKAN_INTERNAL_TryAddDeviceFeatures_Vulkan_12_Or_Later(VkPhysicalDeviceFeatures *dst10, 11803 VkPhysicalDeviceVulkan11Features *dst11, 11804 VkPhysicalDeviceVulkan12Features *dst12, 11805 VkPhysicalDeviceVulkan13Features *dst13, 11806 Uint32 apiVersion, 11807 VkBaseOutStructure *src) 11808{ 11809 int minorVersion = VK_API_VERSION_MINOR(apiVersion); 11810 SDL_assert(apiVersion >= 2); 11811 bool hasAdded = VULKAN_INTERNAL_TryAddDeviceFeatures_Vulkan_11(dst10, dst11, src); 11812 if (!hasAdded) { 11813 switch (src->sType) { 11814 case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES: 11815 { 11816 VkPhysicalDeviceVulkan11Features *newFeatures = (VkPhysicalDeviceVulkan11Features *)src; 11817 VULKAN_INTERNAL_AddDeviceFeatures(&dst11->storageBuffer16BitAccess, 11818 &dst11->shaderDrawParameters, 11819 &newFeatures->storageBuffer16BitAccess); 11820 hasAdded = true; 11821 } break; 11822 11823 case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES: 11824 { 11825 VkPhysicalDeviceVulkan12Features *newFeatures = (VkPhysicalDeviceVulkan12Features *)src; 11826 VULKAN_INTERNAL_AddDeviceFeatures(&dst12->samplerMirrorClampToEdge, 11827 &dst12->subgroupBroadcastDynamicId, 11828 &newFeatures->samplerMirrorClampToEdge); 11829 hasAdded = true; 11830 } break; 11831 11832 case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES: 11833 { 11834 if (minorVersion >= 3) { 11835 VkPhysicalDeviceVulkan13Features *newFeatures = (VkPhysicalDeviceVulkan13Features *)src; 11836 VULKAN_INTERNAL_AddDeviceFeatures(&dst13->robustImageAccess, 11837 &dst13->maintenance4, 11838 &newFeatures->robustImageAccess); 11839 hasAdded = true; 11840 } 11841 } break; 11842 11843 default: 11844 break; 11845 } 11846 } 11847 11848 return hasAdded; 11849} 11850 11851static void VULKAN_INTERNAL_AddOptInVulkanOptions(SDL_PropertiesID props, VulkanRenderer *renderer, VulkanFeatures *features) 11852{ 11853 if (SDL_HasProperty(props, SDL_PROP_GPU_DEVICE_CREATE_VULKAN_OPTIONS_POINTER)) { 11854 SDL_GPUVulkanOptions *options = (SDL_GPUVulkanOptions *)SDL_GetPointerProperty(props, SDL_PROP_GPU_DEVICE_CREATE_VULKAN_OPTIONS_POINTER, NULL); 11855 if (options) { 11856 features->usesCustomVulkanOptions = true; 11857 features->desiredApiVersion = options->vulkan_api_version; 11858 11859 SDL_zero(features->desiredVulkan11DeviceFeatures); 11860 SDL_zero(features->desiredVulkan12DeviceFeatures); 11861 SDL_zero(features->desiredVulkan13DeviceFeatures); 11862 features->desiredVulkan11DeviceFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES; 11863 features->desiredVulkan12DeviceFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES; 11864 features->desiredVulkan13DeviceFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES; 11865 11866 // Handle requested device features 11867 VkPhysicalDeviceFeatures *vk10Features = &features->desiredVulkan10DeviceFeatures; 11868 VkPhysicalDeviceVulkan11Features *vk11Features = &features->desiredVulkan11DeviceFeatures; 11869 VkPhysicalDeviceVulkan12Features *vk12Features = &features->desiredVulkan12DeviceFeatures; 11870 VkPhysicalDeviceVulkan13Features *vk13Features = &features->desiredVulkan13DeviceFeatures; 11871 11872 if (options->vulkan_10_physical_device_features) { 11873 VkPhysicalDeviceFeatures *deviceFeatures = (VkPhysicalDeviceFeatures *)options->vulkan_10_physical_device_features; 11874 VULKAN_INTERNAL_AddDeviceFeatures(&vk10Features->robustBufferAccess, 11875 &vk10Features->inheritedQueries, 11876 &deviceFeatures->robustBufferAccess); 11877 } 11878 11879 int minorVersion = VK_API_VERSION_MINOR(features->desiredApiVersion); 11880 bool supportsHigherLevelFeatures = minorVersion > 0; 11881 if (supportsHigherLevelFeatures && options->feature_list) { 11882 if (minorVersion < 2) { 11883 // Iterate through the entire list and combine all requested features 11884 VkBaseOutStructure *nextStructure = (VkBaseOutStructure *)options->feature_list; 11885 while (nextStructure) { 11886 VULKAN_INTERNAL_TryAddDeviceFeatures_Vulkan_11(vk10Features, vk11Features, nextStructure); 11887 nextStructure = nextStructure->pNext; 11888 } 11889 } else { 11890 // Iterate through the entire list and combine all requested features 11891 VkBaseOutStructure *nextStructure = (VkBaseOutStructure *)options->feature_list; 11892 while (nextStructure) { 11893 VULKAN_INTERNAL_TryAddDeviceFeatures_Vulkan_12_Or_Later(vk10Features, 11894 vk11Features, 11895 vk12Features, 11896 vk13Features, 11897 features->desiredApiVersion, 11898 nextStructure); 11899 nextStructure = nextStructure->pNext; 11900 } 11901 } 11902 } 11903 11904 features->additionalDeviceExtensionCount = options->device_extension_count; 11905 features->additionalDeviceExtensionNames = options->device_extension_names; 11906 features->additionalInstanceExtensionCount = options->instance_extension_count; 11907 features->additionalInstanceExtensionNames = options->instance_extension_names; 11908 } else if (renderer->debugMode) { 11909 SDL_LogWarn(SDL_LOG_CATEGORY_GPU, 11910 "VULKAN_INTERNAL_AddOptInVulkanOptions: Additional options property was set, but value was null. This may be a bug."); 11911 } 11912 } 11913} 11914 11915static Uint8 VULKAN_INTERNAL_CreateInstance(VulkanRenderer *renderer, VulkanFeatures *features) 11916{ 11917 VkResult vulkanResult; 11918 VkApplicationInfo appInfo; 11919 VkInstanceCreateFlags createFlags; 11920 const char *const *originalInstanceExtensionNames; 11921 const char **instanceExtensionNames; 11922 Uint32 instanceExtensionCount; 11923 VkInstanceCreateInfo createInfo; 11924 static const char *layerNames[] = { "VK_LAYER_KHRONOS_validation" }; 11925 11926 appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; 11927 appInfo.pNext = NULL; 11928 appInfo.pApplicationName = NULL; 11929 appInfo.applicationVersion = 0; 11930 appInfo.pEngineName = "SDLGPU"; 11931 appInfo.engineVersion = SDL_VERSION; 11932 appInfo.apiVersion = features->usesCustomVulkanOptions 11933 ? features->desiredApiVersion 11934 : VK_MAKE_VERSION(1, 0, 0); 11935 11936 createFlags = 0; 11937 11938 originalInstanceExtensionNames = SDL_Vulkan_GetInstanceExtensions(&instanceExtensionCount); 11939 if (!originalInstanceExtensionNames) { 11940 SDL_LogError( 11941 SDL_LOG_CATEGORY_GPU, 11942 "SDL_Vulkan_GetInstanceExtensions(): getExtensionCount: %s", 11943 SDL_GetError()); 11944 11945 return 0; 11946 } 11947 11948 Uint32 extraInstanceExtensionCount = features->additionalInstanceExtensionCount; 11949 const char** extraInstanceExtensionNames = features->additionalInstanceExtensionNames; 11950 11951 /* Extra space for the following extensions: 11952 * VK_KHR_get_physical_device_properties2 11953 * VK_EXT_swapchain_colorspace 11954 * VK_EXT_debug_utils 11955 * VK_KHR_portability_enumeration 11956 * 11957 * Plus additional opt-in extensions. 11958 */ 11959 instanceExtensionNames = SDL_stack_alloc( 11960 const char *, 11961 instanceExtensionCount + 4 + extraInstanceExtensionCount); 11962 const char** nextInstanceExtensionNamePtr = instanceExtensionNames; 11963 SDL_memcpy((void *)nextInstanceExtensionNamePtr, originalInstanceExtensionNames, instanceExtensionCount * sizeof(const char *)); 11964 nextInstanceExtensionNamePtr += instanceExtensionCount; 11965 11966 if (extraInstanceExtensionCount > 0) { 11967 SDL_memcpy((void *)nextInstanceExtensionNamePtr, extraInstanceExtensionNames, extraInstanceExtensionCount * sizeof(const char *)); 11968 nextInstanceExtensionNamePtr += extraInstanceExtensionCount; 11969 } 11970 11971 int firstUnsupportedExtensionIndex = 0; 11972 if (!VULKAN_INTERNAL_CheckInstanceExtensions( 11973 instanceExtensionNames, 11974 instanceExtensionCount + extraInstanceExtensionCount, 11975 &renderer->supportsDebugUtils, 11976 &renderer->supportsColorspace, 11977 &renderer->supportsPhysicalDeviceProperties2, 11978 &renderer->supportsPortabilityEnumeration, 11979 &firstUnsupportedExtensionIndex)) { 11980 if (renderer->debugMode) { 11981 SDL_LogError(SDL_LOG_CATEGORY_GPU, 11982 "Required Vulkan instance extension '%s' not supported", 11983 instanceExtensionNames[firstUnsupportedExtensionIndex]); 11984 } 11985 SDL_SetError("Required Vulkan instance extension '%s' not supported", 11986 instanceExtensionNames[firstUnsupportedExtensionIndex]); 11987 SDL_stack_free((char *)instanceExtensionNames); 11988 return false; 11989 } 11990 11991 if (renderer->supportsDebugUtils) { 11992 // Append the debug extension 11993 *nextInstanceExtensionNamePtr++ = VK_EXT_DEBUG_UTILS_EXTENSION_NAME; 11994 instanceExtensionCount++; 11995 } else { 11996 SDL_LogWarn( 11997 SDL_LOG_CATEGORY_GPU, 11998 "%s is not supported!", 11999 VK_EXT_DEBUG_UTILS_EXTENSION_NAME); 12000 } 12001 12002 if (renderer->supportsColorspace) { 12003 // Append colorspace extension 12004 *nextInstanceExtensionNamePtr++ = VK_EXT_SWAPCHAIN_COLOR_SPACE_EXTENSION_NAME; 12005 instanceExtensionCount++; 12006 } 12007 12008 if (renderer->supportsPhysicalDeviceProperties2) { 12009 // Append KHR_physical_device_properties2 extension 12010 *nextInstanceExtensionNamePtr++ = VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME; 12011 instanceExtensionCount++; 12012 } 12013 12014 if (renderer->supportsPortabilityEnumeration) { 12015 *nextInstanceExtensionNamePtr++ = VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME; 12016 instanceExtensionCount++; 12017 createFlags |= VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR; 12018 } 12019 12020 createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; 12021 createInfo.pNext = NULL; 12022 createInfo.flags = createFlags; 12023 createInfo.pApplicationInfo = &appInfo; 12024 createInfo.ppEnabledLayerNames = layerNames; 12025 createInfo.enabledExtensionCount = instanceExtensionCount + extraInstanceExtensionCount; 12026 createInfo.ppEnabledExtensionNames = instanceExtensionNames; 12027 if (renderer->debugMode) { 12028 createInfo.enabledLayerCount = SDL_arraysize(layerNames); 12029 if (!VULKAN_INTERNAL_CheckValidationLayers( 12030 layerNames, 12031 createInfo.enabledLayerCount)) { 12032 SDL_LogWarn(SDL_LOG_CATEGORY_GPU, "Validation layers not found, continuing without validation"); 12033 createInfo.enabledLayerCount = 0; 12034 } else { 12035 SDL_LogInfo(SDL_LOG_CATEGORY_GPU, "Validation layers enabled, expect debug level performance!"); 12036 } 12037 } else { 12038 createInfo.enabledLayerCount = 0; 12039 } 12040 12041#ifdef HAVE_GPU_OPENXR 12042 if (renderer->xrInstance) { 12043 XrResult xrResult; 12044 PFN_xrCreateVulkanInstanceKHR xrCreateVulkanInstanceKHR; 12045 if ((xrResult = xrGetInstanceProcAddr(renderer->xrInstance, "xrCreateVulkanInstanceKHR", (PFN_xrVoidFunction *)&xrCreateVulkanInstanceKHR)) != XR_SUCCESS) { 12046 SDL_LogDebug(SDL_LOG_CATEGORY_GPU, "Failed to get xrCreateVulkanInstanceKHR"); 12047 SDL_stack_free((char *)instanceExtensionNames); 12048 return 0; 12049 } 12050 12051 XrVulkanInstanceCreateInfoKHR xrCreateInfo; 12052 SDL_zero(xrCreateInfo); 12053 xrCreateInfo.type = XR_TYPE_VULKAN_INSTANCE_CREATE_INFO_KHR; 12054 xrCreateInfo.vulkanCreateInfo = &createInfo; 12055 xrCreateInfo.systemId = renderer->xrSystemId; 12056 xrCreateInfo.pfnGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)SDL_Vulkan_GetVkGetInstanceProcAddr(); 12057 SDL_assert(xrCreateInfo.pfnGetInstanceProcAddr); 12058 if ((xrResult = xrCreateVulkanInstanceKHR(renderer->xrInstance, &xrCreateInfo, &renderer->instance, &vulkanResult)) != XR_SUCCESS) { 12059 SDL_LogDebug(SDL_LOG_CATEGORY_GPU, "Failed to create vulkan instance, reason %d, %d", xrResult, vulkanResult); 12060 SDL_stack_free((char *)instanceExtensionNames); 12061 return 0; 12062 } 12063 } else 12064#endif // HAVE_GPU_OPENXR 12065 { 12066 vulkanResult = vkCreateInstance(&createInfo, NULL, &renderer->instance); 12067 } 12068 SDL_stack_free((char *)instanceExtensionNames); 12069 12070 if (vulkanResult != VK_SUCCESS) { 12071 CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkCreateInstance, 0); 12072 } 12073 12074 return 1; 12075} 12076 12077static bool VULKAN_INTERNAL_GetDeviceRank( 12078 VulkanRenderer *renderer, 12079 VkPhysicalDevice physicalDevice, 12080 VulkanExtensions *physicalDeviceExtensions, 12081 Uint64 *deviceRank) 12082{ 12083 static const Uint8 DEVICE_PRIORITY_HIGHPERFORMANCE[] = { 12084 0, // VK_PHYSICAL_DEVICE_TYPE_OTHER 12085 3, // VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU 12086 4, // VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU 12087 2, // VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU 12088 1 // VK_PHYSICAL_DEVICE_TYPE_CPU 12089 }; 12090 static const Uint8 DEVICE_PRIORITY_LOWPOWER[] = { 12091 0, // VK_PHYSICAL_DEVICE_TYPE_OTHER 12092 4, // VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU 12093 3, // VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU 12094 2, // VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU 12095 1 // VK_PHYSICAL_DEVICE_TYPE_CPU 12096 }; 12097 const Uint8 *devicePriority = renderer->preferLowPower ? DEVICE_PRIORITY_LOWPOWER : DEVICE_PRIORITY_HIGHPERFORMANCE; 12098 bool isConformant; 12099 12100 VkPhysicalDeviceType deviceType; 12101 if (physicalDeviceExtensions->KHR_driver_properties || physicalDeviceExtensions->MSFT_layered_driver) { 12102 VkPhysicalDeviceProperties2KHR physicalDeviceProperties; 12103 VkPhysicalDeviceDriverPropertiesKHR physicalDeviceDriverProperties = { 0 }; 12104 VkPhysicalDeviceLayeredDriverPropertiesMSFT physicalDeviceLayeredDriverProperties = { 0 }; 12105 void** ppNext = &physicalDeviceProperties.pNext; 12106 12107 physicalDeviceProperties.sType = 12108 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2; 12109 12110 if (physicalDeviceExtensions->KHR_driver_properties) { 12111 *ppNext = &physicalDeviceDriverProperties; 12112 ppNext = &physicalDeviceDriverProperties.pNext; 12113 12114 physicalDeviceDriverProperties.sType = 12115 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES_KHR; 12116 } 12117 12118 if (physicalDeviceExtensions->MSFT_layered_driver) { 12119 *ppNext = &physicalDeviceLayeredDriverProperties; 12120 ppNext = &physicalDeviceLayeredDriverProperties.pNext; 12121 12122 physicalDeviceLayeredDriverProperties.sType = 12123 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LAYERED_DRIVER_PROPERTIES_MSFT; 12124 } 12125 12126 *ppNext = NULL; 12127 renderer->vkGetPhysicalDeviceProperties2KHR( 12128 physicalDevice, 12129 &physicalDeviceProperties); 12130 12131 if (physicalDeviceExtensions->KHR_driver_properties) { 12132 isConformant = (physicalDeviceDriverProperties.conformanceVersion.major >= 1); 12133 } else { 12134 isConformant = true; // We can't check this, so just assume it's conformant 12135 } 12136 12137 if (physicalDeviceExtensions->MSFT_layered_driver && physicalDeviceLayeredDriverProperties.underlyingAPI != VK_LAYERED_DRIVER_UNDERLYING_API_NONE_MSFT) { 12138 /* Rank Dozen above CPU, but below INTEGRATED. 12139 * This is needed for WSL specifically. 12140 */ 12141 deviceType = VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU; 12142 12143 /* Dozen hasn't been tested for conformance and it probably won't be, 12144 * but WSL may need this so let's be generous. 12145 * -flibit 12146 */ 12147 isConformant = true; 12148 } else { 12149 deviceType = physicalDeviceProperties.properties.deviceType; 12150 } 12151 } else { 12152 VkPhysicalDeviceProperties physicalDeviceProperties; 12153 renderer->vkGetPhysicalDeviceProperties( 12154 physicalDevice, 12155 &physicalDeviceProperties); 12156 deviceType = physicalDeviceProperties.deviceType; 12157 isConformant = true; // We can't check this, so just assume it's conformant 12158 } 12159 12160 if (renderer->requireHardwareAcceleration) { 12161 if (deviceType != VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU && 12162 deviceType != VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU && 12163 deviceType != VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU) { 12164 // In addition to CPU, "Other" drivers (including layered drivers) don't count as hardware-accelerated 12165 return 0; 12166 } 12167 } 12168 12169 /* As far as I know, the only drivers available to users that are also 12170 * non-conformant are incomplete Mesa drivers and Vulkan-on-12. hasvk is one 12171 * example of a non-conformant driver that's built by default. 12172 * -flibit 12173 */ 12174 if (!isConformant) { 12175 return 0; 12176 } 12177 12178 /* Apply a large bias on the devicePriority so that we always respect the order in the priority arrays. 12179 * We also rank by e.g. VRAM which should have less influence than the device type. 12180 */ 12181 Uint64 devicePriorityValue = devicePriority[deviceType] * 1000000; 12182 12183 if (*deviceRank < devicePriorityValue) { 12184 /* This device outranks the best device we've found so far! 12185 * This includes a dedicated GPU that has less features than an 12186 * integrated GPU, because this is a freak case that is almost 12187 * never intentionally desired by the end user 12188 */ 12189 *deviceRank = devicePriorityValue; 12190 } else if (*deviceRank > devicePriorityValue) { 12191 /* Device is outranked by a previous device, don't even try to 12192 * run a query and reset the rank to avoid overwrites 12193 */ 12194 *deviceRank = 0; 12195 return false; 12196 } 12197 12198 /* If we prefer high performance, sum up all device local memory (rounded to megabytes) 12199 * to deviceRank. In the niche case of someone having multiple dedicated GPUs in the same 12200 * system, this theoretically picks the most powerful one (or at least the one with the 12201 * most memory!) 12202 * 12203 * We do this *after* discarding all non suitable devices, which means if this computer 12204 * has multiple dedicated GPUs that all meet our criteria, *and* the user asked for high 12205 * performance, then we always pick the GPU with more VRAM. 12206 */ 12207 if (!renderer->preferLowPower) { 12208 Uint32 i; 12209 Uint64 videoMemory = 0; 12210 VkPhysicalDeviceMemoryProperties deviceMemory; 12211 renderer->vkGetPhysicalDeviceMemoryProperties(physicalDevice, &deviceMemory); 12212 for (i = 0; i < deviceMemory.memoryHeapCount; i++) { 12213 VkMemoryHeap heap = deviceMemory.memoryHeaps[i]; 12214 if (heap.flags & VK_MEMORY_HEAP_DEVICE_LOCAL_BIT) { 12215 videoMemory += heap.size; 12216 } 12217 } 12218 // Round it to megabytes (as per the vulkan spec videoMemory is in bytes) 12219 Uint64 videoMemoryRounded = videoMemory / 1024 / 1024; 12220 *deviceRank += videoMemoryRounded; 12221 } 12222 12223 return true; 12224} 12225 12226static Uint8 VULKAN_INTERNAL_IsDeviceSuitable( 12227 VulkanRenderer *renderer, 12228 VulkanFeatures *features, 12229 VkPhysicalDevice physicalDevice, 12230 VulkanExtensions *physicalDeviceExtensions, 12231 Uint32 *queueFamilyIndex) 12232{ 12233 Uint32 queueFamilyCount, queueFamilyRank, queueFamilyBest; 12234 VkQueueFamilyProperties *queueProps; 12235 bool supportsPresent; 12236 VkPhysicalDeviceFeatures deviceFeatures; 12237 Uint32 i; 12238 12239 renderer->vkGetPhysicalDeviceFeatures( 12240 physicalDevice, 12241 &deviceFeatures); 12242 12243 if ((!deviceFeatures.independentBlend && features->desiredVulkan10DeviceFeatures.independentBlend) || 12244 (!deviceFeatures.imageCubeArray && features->desiredVulkan10DeviceFeatures.imageCubeArray) || 12245 (!deviceFeatures.depthClamp && features->desiredVulkan10DeviceFeatures.depthClamp) || 12246 (!deviceFeatures.shaderClipDistance && features->desiredVulkan10DeviceFeatures.shaderClipDistance) || 12247 (!deviceFeatures.drawIndirectFirstInstance && features->desiredVulkan10DeviceFeatures.drawIndirectFirstInstance) || 12248 (!deviceFeatures.sampleRateShading && features->desiredVulkan10DeviceFeatures.sampleRateShading) || 12249 (!deviceFeatures.samplerAnisotropy && features->desiredVulkan10DeviceFeatures.samplerAnisotropy)) { 12250 return 0; 12251 } 12252 12253 // Check opt-in device features 12254 if (features->usesCustomVulkanOptions) { 12255 bool supportsAllFeatures = VULKAN_INTERNAL_ValidateOptInFeatures(renderer, features, physicalDevice, &deviceFeatures); 12256 if (!supportsAllFeatures) { 12257 return 0; 12258 } 12259 } 12260 12261 if (!VULKAN_INTERNAL_CheckDeviceExtensions( 12262 renderer, 12263 features, 12264 physicalDevice, 12265 physicalDeviceExtensions)) { 12266 return 0; 12267 } 12268 12269 renderer->vkGetPhysicalDeviceQueueFamilyProperties( 12270 physicalDevice, 12271 &queueFamilyCount, 12272 NULL); 12273 12274 queueProps = SDL_stack_alloc( 12275 VkQueueFamilyProperties, 12276 queueFamilyCount); 12277 renderer->vkGetPhysicalDeviceQueueFamilyProperties( 12278 physicalDevice, 12279 &queueFamilyCount, 12280 queueProps); 12281 12282 queueFamilyBest = 0; 12283 *queueFamilyIndex = SDL_MAX_UINT32; 12284 for (i = 0; i < queueFamilyCount; i += 1) { 12285 supportsPresent = SDL_Vulkan_GetPresentationSupport( 12286 renderer->instance, 12287 physicalDevice, 12288 i); 12289 if (!supportsPresent || 12290 !(queueProps[i].queueFlags & VK_QUEUE_GRAPHICS_BIT)) { 12291 // Not a graphics family, ignore. 12292 continue; 12293 } 12294 12295 /* The queue family bitflags are kind of annoying. 12296 * 12297 * We of course need a graphics family, but we ideally want the 12298 * _primary_ graphics family. The spec states that at least one 12299 * graphics family must also be a compute family, so generally 12300 * drivers make that the first one. But hey, maybe something 12301 * genuinely can't do compute or something, and FNA doesn't 12302 * need it, so we'll be open to a non-compute queue family. 12303 * 12304 * Additionally, it's common to see the primary queue family 12305 * have the transfer bit set, which is great! But this is 12306 * actually optional; it's impossible to NOT have transfers in 12307 * graphics/compute but it _is_ possible for a graphics/compute 12308 * family, even the primary one, to just decide not to set the 12309 * bitflag. Admittedly, a driver may want to isolate transfer 12310 * queues to a dedicated family so that queues made solely for 12311 * transfers can have an optimized DMA queue. 12312 * 12313 * That, or the driver author got lazy and decided not to set 12314 * the bit. Looking at you, Android. 12315 * 12316 * -flibit 12317 */ 12318 if (queueProps[i].queueFlags & VK_QUEUE_COMPUTE_BIT) { 12319 if (queueProps[i].queueFlags & VK_QUEUE_TRANSFER_BIT) { 12320 // Has all attribs! 12321 queueFamilyRank = 3; 12322 } else { 12323 // Probably has a DMA transfer queue family 12324 queueFamilyRank = 2; 12325 } 12326 } else { 12327 // Just a graphics family, probably has something better 12328 queueFamilyRank = 1; 12329 } 12330 if (queueFamilyRank > queueFamilyBest) { 12331 *queueFamilyIndex = i; 12332 queueFamilyBest = queueFamilyRank; 12333 } 12334 } 12335 12336 SDL_stack_free(queueProps); 12337 12338 if (*queueFamilyIndex == SDL_MAX_UINT32) { 12339 // Somehow no graphics queues existed. Compute-only device? 12340 return 0; 12341 } 12342 12343 // FIXME: Need better structure for checking vs storing swapchain support details 12344 return 1; 12345} 12346 12347static Uint8 VULKAN_INTERNAL_DeterminePhysicalDevice(VulkanRenderer *renderer, VulkanFeatures *features) 12348{ 12349 VkResult vulkanResult; 12350 VkPhysicalDevice *physicalDevices; 12351 VulkanExtensions *physicalDeviceExtensions; 12352 Uint32 i, physicalDeviceCount; 12353 Sint32 suitableIndex; 12354 Uint32 suitableQueueFamilyIndex; 12355 Uint64 highestRank; 12356 12357#ifdef HAVE_GPU_OPENXR 12358 // When XR is enabled, let the OpenXR runtime choose the physical device 12359 if (renderer->xrInstance) { 12360 XrResult xrResult; 12361 VulkanExtensions xrPhysicalDeviceExtensions; 12362 Uint32 queueFamilyIndex; 12363 PFN_xrGetVulkanGraphicsDevice2KHR xrGetVulkanGraphicsDevice2KHR; 12364 12365 xrResult = xrGetInstanceProcAddr( 12366 renderer->xrInstance, 12367 "xrGetVulkanGraphicsDevice2KHR", 12368 (PFN_xrVoidFunction *)&xrGetVulkanGraphicsDevice2KHR); 12369 if (xrResult != XR_SUCCESS) { 12370 SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to get xrGetVulkanGraphicsDevice2KHR, result: %d", xrResult); 12371 return 0; 12372 } 12373 12374 XrVulkanGraphicsDeviceGetInfoKHR graphicsDeviceGetInfo; 12375 SDL_zero(graphicsDeviceGetInfo); 12376 graphicsDeviceGetInfo.type = XR_TYPE_VULKAN_GRAPHICS_DEVICE_GET_INFO_KHR; 12377 graphicsDeviceGetInfo.systemId = renderer->xrSystemId; 12378 graphicsDeviceGetInfo.vulkanInstance = renderer->instance; 12379 12380 xrResult = xrGetVulkanGraphicsDevice2KHR( 12381 renderer->xrInstance, 12382 &graphicsDeviceGetInfo, 12383 &renderer->physicalDevice); 12384 if (xrResult != XR_SUCCESS) { 12385 SDL_LogError(SDL_LOG_CATEGORY_GPU, "xrGetVulkanGraphicsDevice2KHR failed, result: %d", xrResult); 12386 return 0; 12387 } 12388 12389 // Verify the XR-chosen device is suitable 12390 if (!VULKAN_INTERNAL_IsDeviceSuitable( 12391 renderer, 12392 features, 12393 renderer->physicalDevice, 12394 &xrPhysicalDeviceExtensions, 12395 &queueFamilyIndex)) { 12396 SDL_LogError(SDL_LOG_CATEGORY_GPU, "The physical device chosen by the OpenXR runtime is not suitable"); 12397 return 0; 12398 } 12399 12400 renderer->supports = xrPhysicalDeviceExtensions; 12401 renderer->queueFamilyIndex = queueFamilyIndex; 12402 } else 12403#endif // HAVE_GPU_OPENXR 12404 { 12405 vulkanResult = renderer->vkEnumeratePhysicalDevices( 12406 renderer->instance, 12407 &physicalDeviceCount, 12408 NULL); 12409 CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkEnumeratePhysicalDevices, 0); 12410 12411 if (physicalDeviceCount == 0) { 12412 SDL_LogInfo(SDL_LOG_CATEGORY_GPU, "Failed to find any GPUs with Vulkan support"); 12413 return 0; 12414 } 12415 12416 physicalDevices = SDL_stack_alloc(VkPhysicalDevice, physicalDeviceCount); 12417 physicalDeviceExtensions = SDL_stack_alloc(VulkanExtensions, physicalDeviceCount); 12418 12419 vulkanResult = renderer->vkEnumeratePhysicalDevices( 12420 renderer->instance, 12421 &physicalDeviceCount, 12422 physicalDevices); 12423 12424 /* This should be impossible to hit, but from what I can tell this can 12425 * be triggered not because the array is too small, but because there 12426 * were drivers that turned out to be bogus, so this is the loader's way 12427 * of telling us that the list is now smaller than expected :shrug: 12428 */ 12429 if (vulkanResult == VK_INCOMPLETE) { 12430 SDL_LogWarn(SDL_LOG_CATEGORY_GPU, "vkEnumeratePhysicalDevices returned VK_INCOMPLETE, will keep trying anyway..."); 12431 vulkanResult = VK_SUCCESS; 12432 } 12433 12434 if (vulkanResult != VK_SUCCESS) { 12435 SDL_LogWarn( 12436 SDL_LOG_CATEGORY_GPU, 12437 "vkEnumeratePhysicalDevices failed: %s", 12438 VkErrorMessages(vulkanResult)); 12439 SDL_stack_free(physicalDevices); 12440 SDL_stack_free(physicalDeviceExtensions); 12441 return 0; 12442 } 12443 12444 // Any suitable device will do, but we'd like the best 12445 suitableIndex = -1; 12446 suitableQueueFamilyIndex = 0; 12447 highestRank = 0; 12448 for (i = 0; i < physicalDeviceCount; i += 1) { 12449 Uint32 queueFamilyIndex; 12450 Uint64 deviceRank; 12451 12452 if (!VULKAN_INTERNAL_IsDeviceSuitable( 12453 renderer, 12454 features, 12455 physicalDevices[i], 12456 &physicalDeviceExtensions[i], 12457 &queueFamilyIndex)) { 12458 // Device does not meet the minimum requirements, skip it entirely 12459 continue; 12460 } 12461 12462 deviceRank = highestRank; 12463 if (VULKAN_INTERNAL_GetDeviceRank( 12464 renderer, 12465 physicalDevices[i], 12466 &physicalDeviceExtensions[i], 12467 &deviceRank)) { 12468 /* Use this for rendering. 12469 * Note that this may override a previous device that 12470 * supports rendering, but shares the same device rank. 12471 */ 12472 suitableIndex = i; 12473 suitableQueueFamilyIndex = queueFamilyIndex; 12474 highestRank = deviceRank; 12475 } 12476 } 12477 12478 if (suitableIndex != -1) { 12479 renderer->supports = physicalDeviceExtensions[suitableIndex]; 12480 renderer->physicalDevice = physicalDevices[suitableIndex]; 12481 renderer->queueFamilyIndex = suitableQueueFamilyIndex; 12482 } else { 12483 SDL_stack_free(physicalDevices); 12484 SDL_stack_free(physicalDeviceExtensions); 12485 return 0; 12486 } 12487 12488 SDL_stack_free(physicalDevices); 12489 SDL_stack_free(physicalDeviceExtensions); 12490 } 12491 12492 renderer->physicalDeviceProperties.sType = 12493 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2; 12494 if (renderer->supports.KHR_driver_properties) { 12495 renderer->physicalDeviceDriverProperties.sType = 12496 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES_KHR; 12497 renderer->physicalDeviceDriverProperties.pNext = NULL; 12498 12499 renderer->physicalDeviceProperties.pNext = 12500 &renderer->physicalDeviceDriverProperties; 12501 12502 renderer->vkGetPhysicalDeviceProperties2KHR( 12503 renderer->physicalDevice, 12504 &renderer->physicalDeviceProperties); 12505 } else { 12506 renderer->physicalDeviceProperties.pNext = NULL; 12507 12508 renderer->vkGetPhysicalDeviceProperties( 12509 renderer->physicalDevice, 12510 &renderer->physicalDeviceProperties.properties); 12511 } 12512 12513 renderer->vkGetPhysicalDeviceMemoryProperties( 12514 renderer->physicalDevice, 12515 &renderer->memoryProperties); 12516 12517 return 1; 12518} 12519 12520static Uint8 VULKAN_INTERNAL_CreateLogicalDevice( 12521 VulkanRenderer *renderer, 12522 VulkanFeatures *features) 12523{ 12524 VkResult vulkanResult; 12525 VkDeviceCreateInfo deviceCreateInfo; 12526 VkPhysicalDeviceFeatures haveDeviceFeatures; 12527 VkPhysicalDevicePortabilitySubsetFeaturesKHR portabilityFeatures; 12528 const char **deviceExtensions; 12529 12530 VkDeviceQueueCreateInfo queueCreateInfo; 12531 float queuePriority = 1.0f; 12532 12533 queueCreateInfo.sType = 12534 VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; 12535 queueCreateInfo.pNext = NULL; 12536 queueCreateInfo.flags = 0; 12537 queueCreateInfo.queueFamilyIndex = renderer->queueFamilyIndex; 12538 queueCreateInfo.queueCount = 1; 12539 queueCreateInfo.pQueuePriorities = &queuePriority; 12540 12541 // check feature support 12542 12543 renderer->vkGetPhysicalDeviceFeatures( 12544 renderer->physicalDevice, 12545 &haveDeviceFeatures); 12546 12547 // specifying used device features 12548 12549 if (haveDeviceFeatures.fillModeNonSolid) { 12550 features->desiredVulkan10DeviceFeatures.fillModeNonSolid = VK_TRUE; 12551 renderer->supportsFillModeNonSolid = true; 12552 } 12553 12554 if (haveDeviceFeatures.multiDrawIndirect) { 12555 features->desiredVulkan10DeviceFeatures.multiDrawIndirect = VK_TRUE; 12556 renderer->supportsMultiDrawIndirect = true; 12557 } 12558 12559 // creating the logical device 12560 12561 deviceCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; 12562 if (renderer->supports.KHR_portability_subset) { 12563 portabilityFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PORTABILITY_SUBSET_FEATURES_KHR; 12564 portabilityFeatures.pNext = NULL; 12565 portabilityFeatures.constantAlphaColorBlendFactors = VK_FALSE; 12566 portabilityFeatures.events = VK_FALSE; 12567 portabilityFeatures.imageViewFormatReinterpretation = VK_FALSE; 12568 portabilityFeatures.imageViewFormatSwizzle = VK_TRUE; 12569 portabilityFeatures.imageView2DOn3DImage = VK_FALSE; 12570 portabilityFeatures.multisampleArrayImage = VK_FALSE; 12571 portabilityFeatures.mutableComparisonSamplers = VK_FALSE; 12572 portabilityFeatures.pointPolygons = VK_FALSE; 12573 portabilityFeatures.samplerMipLodBias = VK_FALSE; // Technically should be true, but eh 12574 portabilityFeatures.separateStencilMaskRef = VK_FALSE; 12575 portabilityFeatures.shaderSampleRateInterpolationFunctions = VK_FALSE; 12576 portabilityFeatures.tessellationIsolines = VK_FALSE; 12577 portabilityFeatures.tessellationPointMode = VK_FALSE; 12578 portabilityFeatures.triangleFans = VK_FALSE; 12579 portabilityFeatures.vertexAttributeAccessBeyondStride = VK_FALSE; 12580 deviceCreateInfo.pNext = &portabilityFeatures; 12581 } else { 12582 deviceCreateInfo.pNext = NULL; 12583 } 12584 deviceCreateInfo.flags = 0; 12585 deviceCreateInfo.queueCreateInfoCount = 1; 12586 deviceCreateInfo.pQueueCreateInfos = &queueCreateInfo; 12587 deviceCreateInfo.enabledLayerCount = 0; 12588 deviceCreateInfo.ppEnabledLayerNames = NULL; 12589 deviceCreateInfo.enabledExtensionCount = GetDeviceExtensionCount( 12590 &renderer->supports); 12591 deviceExtensions = SDL_stack_alloc( 12592 const char *, 12593 deviceCreateInfo.enabledExtensionCount); 12594 CreateDeviceExtensionArray(&renderer->supports, deviceExtensions); 12595 deviceCreateInfo.ppEnabledExtensionNames = deviceExtensions; 12596 12597 VkPhysicalDeviceFeatures2 featureList; 12598 int minor = VK_VERSION_MINOR(features->desiredApiVersion); 12599 12600 struct { 12601 VkPhysicalDevice16BitStorageFeatures storage; 12602 VkPhysicalDeviceMultiviewFeatures multiview; 12603 VkPhysicalDeviceProtectedMemoryFeatures protectedMem; 12604 VkPhysicalDeviceSamplerYcbcrConversionFeatures ycbcr; 12605 VkPhysicalDeviceShaderDrawParametersFeatures drawParams; 12606 VkPhysicalDeviceVariablePointersFeatures varPointers; 12607 } legacyFeatures; 12608 12609 if (features->usesCustomVulkanOptions && minor > 0) { 12610 featureList.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; 12611 featureList.features = features->desiredVulkan10DeviceFeatures; 12612 if (minor > 1) { 12613 featureList.pNext = &features->desiredVulkan11DeviceFeatures; 12614 features->desiredVulkan11DeviceFeatures.pNext = &features->desiredVulkan12DeviceFeatures; 12615 features->desiredVulkan12DeviceFeatures.pNext = minor > 2 ? &features->desiredVulkan13DeviceFeatures : NULL; 12616 features->desiredVulkan13DeviceFeatures.pNext = NULL; 12617 } else { 12618 // Break VkPhysicalDeviceVulkan11Features into pre 1.2 structures for Vulkan 1.1 Support 12619 SDL_zero(legacyFeatures); 12620 12621 legacyFeatures.storage.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES; 12622 legacyFeatures.storage.storageBuffer16BitAccess = features->desiredVulkan11DeviceFeatures.storageBuffer16BitAccess; 12623 legacyFeatures.storage.storageInputOutput16 = features->desiredVulkan11DeviceFeatures.storageInputOutput16; 12624 legacyFeatures.storage.storagePushConstant16 = features->desiredVulkan11DeviceFeatures.storagePushConstant16; 12625 legacyFeatures.storage.uniformAndStorageBuffer16BitAccess = features->desiredVulkan11DeviceFeatures.uniformAndStorageBuffer16BitAccess; 12626 12627 legacyFeatures.multiview.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES; 12628 legacyFeatures.multiview.multiview = features->desiredVulkan11DeviceFeatures.multiview; 12629 legacyFeatures.multiview.multiviewGeometryShader = features->desiredVulkan11DeviceFeatures.multiviewGeometryShader; 12630 legacyFeatures.multiview.multiviewTessellationShader = features->desiredVulkan11DeviceFeatures.multiviewTessellationShader; 12631 12632 legacyFeatures.protectedMem.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_FEATURES; 12633 legacyFeatures.protectedMem.protectedMemory = features->desiredVulkan11DeviceFeatures.protectedMemory; 12634 12635 legacyFeatures.ycbcr.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES; 12636 legacyFeatures.ycbcr.samplerYcbcrConversion = features->desiredVulkan11DeviceFeatures.samplerYcbcrConversion; 12637 12638 legacyFeatures.drawParams.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETERS_FEATURES; 12639 legacyFeatures.drawParams.shaderDrawParameters = features->desiredVulkan11DeviceFeatures.shaderDrawParameters; 12640 12641 legacyFeatures.varPointers.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTERS_FEATURES; 12642 legacyFeatures.varPointers.variablePointers = features->desiredVulkan11DeviceFeatures.variablePointers; 12643 legacyFeatures.varPointers.variablePointersStorageBuffer = features->desiredVulkan11DeviceFeatures.variablePointersStorageBuffer; 12644 12645 featureList.pNext = &legacyFeatures.storage; 12646 legacyFeatures.storage.pNext = &legacyFeatures.multiview; 12647 legacyFeatures.multiview.pNext = &legacyFeatures.protectedMem; 12648 legacyFeatures.protectedMem.pNext = &legacyFeatures.ycbcr; 12649 legacyFeatures.ycbcr.pNext = &legacyFeatures.drawParams; 12650 legacyFeatures.drawParams.pNext = &legacyFeatures.varPointers; 12651 } 12652 deviceCreateInfo.pEnabledFeatures = NULL; 12653 deviceCreateInfo.pNext = &featureList; 12654 } else { 12655 deviceCreateInfo.pEnabledFeatures = &features->desiredVulkan10DeviceFeatures; 12656 } 12657 12658#ifdef HAVE_GPU_OPENXR 12659 if (renderer->xrInstance) { 12660 XrResult xrResult; 12661 PFN_xrCreateVulkanDeviceKHR xrCreateVulkanDeviceKHR; 12662 if ((xrResult = xrGetInstanceProcAddr(renderer->xrInstance, "xrCreateVulkanDeviceKHR", (PFN_xrVoidFunction *)&xrCreateVulkanDeviceKHR)) != XR_SUCCESS) { 12663 SDL_LogDebug(SDL_LOG_CATEGORY_GPU, "Failed to get xrCreateVulkanDeviceKHR"); 12664 SDL_stack_free((void *)deviceExtensions); 12665 return 0; 12666 } 12667 12668 XrVulkanDeviceCreateInfoKHR xrDeviceCreateInfo; 12669 SDL_zero(xrDeviceCreateInfo); 12670 xrDeviceCreateInfo.type = XR_TYPE_VULKAN_DEVICE_CREATE_INFO_KHR; 12671 xrDeviceCreateInfo.vulkanCreateInfo = &deviceCreateInfo; 12672 xrDeviceCreateInfo.systemId = renderer->xrSystemId; 12673 xrDeviceCreateInfo.vulkanPhysicalDevice = renderer->physicalDevice; 12674 xrDeviceCreateInfo.pfnGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)SDL_Vulkan_GetVkGetInstanceProcAddr(); 12675 SDL_assert(xrDeviceCreateInfo.pfnGetInstanceProcAddr); 12676 if ((xrResult = xrCreateVulkanDeviceKHR(renderer->xrInstance, &xrDeviceCreateInfo, &renderer->logicalDevice, &vulkanResult)) != XR_SUCCESS) { 12677 SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to create OpenXR Vulkan logical device, result %d, %d", xrResult, vulkanResult); 12678 SDL_stack_free((void *)deviceExtensions); 12679 return 0; 12680 } 12681 } else 12682#endif // HAVE_GPU_OPENXR 12683 { 12684 vulkanResult = renderer->vkCreateDevice( 12685 renderer->physicalDevice, 12686 &deviceCreateInfo, 12687 NULL, 12688 &renderer->logicalDevice); 12689 } 12690 SDL_stack_free((void *)deviceExtensions); 12691 CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkCreateDevice, 0); 12692 12693 // Load vkDevice entry points 12694 12695#define VULKAN_DEVICE_FUNCTION(func) \ 12696 renderer->func = (PFN_##func) \ 12697 renderer->vkGetDeviceProcAddr( \ 12698 renderer->logicalDevice, \ 12699 #func); 12700#include "SDL_gpu_vulkan_vkfuncs.h" 12701 12702 renderer->vkGetDeviceQueue( 12703 renderer->logicalDevice, 12704 renderer->queueFamilyIndex, 12705 0, 12706 &renderer->unifiedQueue); 12707 12708 return 1; 12709} 12710 12711static void VULKAN_INTERNAL_LoadEntryPoints(void) 12712{ 12713 // Required for MoltenVK support 12714 SDL_setenv_unsafe("MVK_CONFIG_FULL_IMAGE_VIEW_SWIZZLE", "1", 1); 12715 12716 // Load Vulkan entry points 12717 if (!SDL_Vulkan_LoadLibrary(NULL)) { 12718 SDL_LogWarn(SDL_LOG_CATEGORY_GPU, "Vulkan: SDL_Vulkan_LoadLibrary failed!"); 12719 return; 12720 } 12721 12722#ifdef HAVE_GCC_DIAGNOSTIC_PRAGMA 12723#pragma GCC diagnostic push 12724#pragma GCC diagnostic ignored "-Wpedantic" 12725#endif 12726 vkGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)SDL_Vulkan_GetVkGetInstanceProcAddr(); 12727#ifdef HAVE_GCC_DIAGNOSTIC_PRAGMA 12728#pragma GCC diagnostic pop 12729#endif 12730 if (vkGetInstanceProcAddr == NULL) { 12731 SDL_LogWarn( 12732 SDL_LOG_CATEGORY_GPU, 12733 "SDL_Vulkan_GetVkGetInstanceProcAddr(): %s", 12734 SDL_GetError()); 12735 return; 12736 } 12737 12738#define VULKAN_GLOBAL_FUNCTION(name) \ 12739 name = (PFN_##name)vkGetInstanceProcAddr(VK_NULL_HANDLE, #name); \ 12740 if (name == NULL) { \ 12741 SDL_LogWarn(SDL_LOG_CATEGORY_GPU, "vkGetInstanceProcAddr(VK_NULL_HANDLE, \"" #name "\") failed"); \ 12742 return; \ 12743 } 12744#include "SDL_gpu_vulkan_vkfuncs.h" 12745} 12746 12747static bool VULKAN_INTERNAL_PrepareVulkan( 12748 VulkanRenderer *renderer, 12749 VulkanFeatures *features, 12750 SDL_PropertiesID props) 12751{ 12752 VULKAN_INTERNAL_LoadEntryPoints(); 12753 12754 SDL_zerop(features); 12755 12756 // Opt out device features (higher compatibility in exchange for reduced functionality) 12757 features->desiredVulkan10DeviceFeatures.samplerAnisotropy = SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_FEATURE_ANISOTROPY_BOOLEAN, true) ? VK_TRUE : VK_FALSE; 12758 features->desiredVulkan10DeviceFeatures.depthClamp = SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_FEATURE_DEPTH_CLAMPING_BOOLEAN, true) ? VK_TRUE : VK_FALSE; 12759 features->desiredVulkan10DeviceFeatures.shaderClipDistance = SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_FEATURE_CLIP_DISTANCE_BOOLEAN, true) ? VK_TRUE : VK_FALSE; 12760 features->desiredVulkan10DeviceFeatures.drawIndirectFirstInstance = SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_FEATURE_INDIRECT_DRAW_FIRST_INSTANCE_BOOLEAN, true) ? VK_TRUE : VK_FALSE; 12761 12762 // These features have near universal support so they are always enabled 12763 features->desiredVulkan10DeviceFeatures.independentBlend = VK_TRUE; 12764 features->desiredVulkan10DeviceFeatures.sampleRateShading = VK_TRUE; 12765 features->desiredVulkan10DeviceFeatures.imageCubeArray = VK_TRUE; 12766 12767 // Handle opt-in device features 12768 VULKAN_INTERNAL_AddOptInVulkanOptions(props, renderer, features); 12769 12770 renderer->requireHardwareAcceleration = SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_VULKAN_REQUIRE_HARDWARE_ACCELERATION_BOOLEAN, false); 12771 12772 if (!VULKAN_INTERNAL_CreateInstance(renderer, features)) { 12773 SDL_LogWarn(SDL_LOG_CATEGORY_GPU, "Vulkan: Could not create Vulkan instance"); 12774 return false; 12775 } 12776 12777#define VULKAN_INSTANCE_FUNCTION(func) \ 12778 renderer->func = (PFN_##func)vkGetInstanceProcAddr(renderer->instance, #func); 12779#include "SDL_gpu_vulkan_vkfuncs.h" 12780 12781 if (!VULKAN_INTERNAL_DeterminePhysicalDevice(renderer, features)) { 12782 SDL_LogWarn(SDL_LOG_CATEGORY_GPU, "Vulkan: Failed to determine a suitable physical device"); 12783 return false; 12784 } 12785 return true; 12786} 12787 12788#ifdef HAVE_GPU_OPENXR 12789static bool VULKAN_INTERNAL_SearchForOpenXrGpuExtension(XrExtensionProperties *found_extension) 12790{ 12791 XrResult result; 12792 Uint32 extension_count; 12793 Uint32 i; 12794 12795 result = xrEnumerateInstanceExtensionProperties(NULL, 0, &extension_count, NULL); 12796 if (result != XR_SUCCESS) 12797 return false; 12798 12799 XrExtensionProperties *extension_properties = (XrExtensionProperties *)SDL_calloc(extension_count, sizeof(XrExtensionProperties)); 12800 for (i = 0; i < extension_count; i++) 12801 extension_properties[i].type = XR_TYPE_EXTENSION_PROPERTIES; 12802 12803 result = xrEnumerateInstanceExtensionProperties(NULL, extension_count, &extension_count, extension_properties); 12804 if (result != XR_SUCCESS) { 12805 SDL_free(extension_properties); 12806 return false; 12807 } 12808 12809 for (i = 0; i < extension_count; i++) { 12810 XrExtensionProperties extension = extension_properties[i]; 12811 12812 // NOTE: as generally recommended, we support KHR_vulkan_enable2 *only* 12813 // see https://fredemmott.com/blog/2024/11/25/best-practices-for-openxr-api-layers.html 12814 if (SDL_strcmp(extension.extensionName, XR_KHR_VULKAN_ENABLE2_EXTENSION_NAME) == 0) { 12815 SDL_LogInfo(SDL_LOG_CATEGORY_GPU, "Found " XR_KHR_VULKAN_ENABLE2_EXTENSION_NAME " extension"); 12816 12817 *found_extension = extension; 12818 12819 SDL_free(extension_properties); 12820 return true; 12821 } 12822 } 12823 12824 SDL_free(extension_properties); 12825 return false; 12826} 12827 12828static XrResult VULKAN_INTERNAL_GetXrMinimumVulkanApiVersion(XrVersion *minimumVulkanApiVersion, XrInstance instance, XrSystemId systemId) 12829{ 12830 XrResult xrResult; 12831 12832 PFN_xrGetVulkanGraphicsRequirements2KHR xrGetVulkanGraphicsRequirements2KHR; 12833 if ((xrResult = xrGetInstanceProcAddr(instance, "xrGetVulkanGraphicsRequirements2KHR", (PFN_xrVoidFunction *)&xrGetVulkanGraphicsRequirements2KHR)) != XR_SUCCESS) { 12834 SDL_LogDebug(SDL_LOG_CATEGORY_GPU, "Failed to get xrGetVulkanGraphicsRequirements2KHR"); 12835 return xrResult; 12836 } 12837 12838 XrGraphicsRequirementsVulkanKHR graphicsRequirementsVulkan; 12839 SDL_zero(graphicsRequirementsVulkan); 12840 graphicsRequirementsVulkan.type = XR_TYPE_GRAPHICS_REQUIREMENTS_VULKAN2_KHR; 12841 if ((xrResult = xrGetVulkanGraphicsRequirements2KHR(instance, systemId, &graphicsRequirementsVulkan)) != XR_SUCCESS) { 12842 SDL_LogDebug(SDL_LOG_CATEGORY_GPU, "Failed to get vulkan graphics requirements, got OpenXR error %d", xrResult); 12843 return xrResult; 12844 } 12845 12846 *minimumVulkanApiVersion = graphicsRequirementsVulkan.minApiVersionSupported; 12847 return XR_SUCCESS; 12848} 12849#endif // HAVE_GPU_OPENXR 12850 12851static bool VULKAN_PrepareDriver(SDL_VideoDevice *_this, SDL_PropertiesID props) 12852{ 12853 // Set up dummy VulkanRenderer 12854 VulkanRenderer *renderer; 12855 VulkanFeatures features; 12856 bool result = false; 12857 12858 if (!SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_SHADERS_SPIRV_BOOLEAN, false)) { 12859 return false; 12860 } 12861 12862 if (_this->Vulkan_CreateSurface == NULL) { 12863 return false; 12864 } 12865 12866 if (!SDL_Vulkan_LoadLibrary(NULL)) { 12867 return false; 12868 } 12869 12870#ifdef HAVE_GPU_OPENXR 12871 XrResult xrResult; 12872 XrInstancePfns *instancePfns = NULL; 12873 XrInstance xrInstance = XR_NULL_HANDLE; 12874 XrSystemId xrSystemId = XR_NULL_HANDLE; 12875 bool xr = SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_XR_ENABLE_BOOLEAN, false); 12876 12877#ifdef SDL_PLATFORM_ANDROID 12878 /* On Android/Quest, don't test XR in PrepareDriver. The Quest OpenXR runtime 12879 * can't handle having its instance created and destroyed during preparation 12880 * and then recreated during device creation. Just return true for XR mode 12881 * and let CreateDevice do the real work. */ 12882 if (xr) { 12883 SDL_Vulkan_UnloadLibrary(); 12884 return true; 12885 } 12886#endif 12887 12888 if (xr) { 12889 if (!SDL_OpenXR_LoadLibrary()) { 12890 SDL_LogWarn(SDL_LOG_CATEGORY_GPU, "Vulkan: Failed to load OpenXR: %s", SDL_GetError()); 12891 SDL_Vulkan_UnloadLibrary(); 12892 return false; 12893 } 12894 12895 XrExtensionProperties gpuExtension; 12896 if (!VULKAN_INTERNAL_SearchForOpenXrGpuExtension(&gpuExtension)) { 12897 SDL_SetError("Failed to find a suitable OpenXR GPU extension."); 12898 SDL_Vulkan_UnloadLibrary(); 12899 SDL_OpenXR_UnloadLibrary(); 12900 return false; 12901 } 12902 12903 const char *extensionName = gpuExtension.extensionName; 12904 if ((xrResult = xrCreateInstance(&(XrInstanceCreateInfo){ 12905 .type = XR_TYPE_INSTANCE_CREATE_INFO, 12906 .applicationInfo = { 12907 .apiVersion = SDL_GetNumberProperty(props, SDL_PROP_GPU_DEVICE_CREATE_XR_VERSION_NUMBER, XR_API_VERSION_1_0), 12908 .applicationName = "SDL", 12909 }, 12910 .enabledExtensionCount = 1, 12911 .enabledExtensionNames = &extensionName, 12912 }, 12913 &xrInstance)) != XR_SUCCESS) { 12914 SDL_LogDebug(SDL_LOG_CATEGORY_GPU, "Failed to create OpenXR instance"); 12915 SDL_Vulkan_UnloadLibrary(); 12916 SDL_OpenXR_UnloadLibrary(); 12917 return false; 12918 } 12919 12920 instancePfns = SDL_OPENXR_LoadInstanceSymbols(xrInstance); 12921 if (!instancePfns) { 12922 SDL_LogDebug(SDL_LOG_CATEGORY_GPU, "Failed to load needed OpenXR instance symbols"); 12923 SDL_Vulkan_UnloadLibrary(); 12924 SDL_OpenXR_UnloadLibrary(); 12925 return false; 12926 } 12927 12928 if ((xrResult = instancePfns->xrGetSystem(xrInstance, &(XrSystemGetInfo){ 12929 .type = XR_TYPE_SYSTEM_GET_INFO, 12930 .formFactor = (XrFormFactor)SDL_GetNumberProperty(props, SDL_PROP_GPU_DEVICE_CREATE_XR_FORM_FACTOR_NUMBER, XR_FORM_FACTOR_HEAD_MOUNTED_DISPLAY), 12931 }, 12932 &xrSystemId)) != XR_SUCCESS) { 12933 SDL_LogDebug(SDL_LOG_CATEGORY_GPU, "Failed to get OpenXR system"); 12934 instancePfns->xrDestroyInstance(xrInstance); 12935 SDL_Vulkan_UnloadLibrary(); 12936 SDL_OpenXR_UnloadLibrary(); 12937 SDL_free(instancePfns); 12938 return false; 12939 } 12940 } 12941#endif // HAVE_GPU_OPENXR 12942 12943 renderer = (VulkanRenderer *)SDL_calloc(1, sizeof(*renderer)); 12944 if (renderer) { 12945 // This needs to be set early for log filtering 12946 renderer->debugMode = SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_DEBUGMODE_BOOLEAN, false); 12947 12948 renderer->preferLowPower = SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_PREFERLOWPOWER_BOOLEAN, false); 12949 12950 renderer->minimumVkVersion = VK_API_VERSION_1_0; 12951#ifdef HAVE_GPU_OPENXR 12952 renderer->xrInstance = xrInstance; 12953 renderer->xrSystemId = xrSystemId; 12954 12955 if (xr) { 12956 XrVersion minimumVkVersionXr; 12957 xrResult = VULKAN_INTERNAL_GetXrMinimumVulkanApiVersion(&minimumVkVersionXr, xrInstance, xrSystemId); 12958 if (xrResult != XR_SUCCESS) { 12959 SDL_SetError("Failed to get the minimum supported Vulkan API version."); 12960 instancePfns->xrDestroyInstance(xrInstance); 12961 SDL_Vulkan_UnloadLibrary(); 12962 SDL_OpenXR_UnloadLibrary(); 12963 SDL_free(instancePfns); 12964 SDL_free(renderer); 12965 return false; 12966 } 12967 renderer->minimumVkVersion = VK_MAKE_API_VERSION( 12968 0, 12969 XR_VERSION_MAJOR(minimumVkVersionXr), 12970 XR_VERSION_MINOR(minimumVkVersionXr), 12971 XR_VERSION_PATCH(minimumVkVersionXr)); 12972 } 12973#endif // HAVE_GPU_OPENXR 12974 12975 result = VULKAN_INTERNAL_PrepareVulkan(renderer, &features, props); 12976 if (result) { 12977 renderer->vkDestroyInstance(renderer->instance, NULL); 12978 } 12979 12980#ifdef HAVE_GPU_OPENXR 12981 if (instancePfns) { 12982 instancePfns->xrDestroyInstance(xrInstance); 12983 SDL_free(instancePfns); 12984 SDL_OpenXR_UnloadLibrary(); 12985 } 12986#endif // HAVE_GPU_OPENXR 12987 12988 SDL_free(renderer); 12989 } 12990 SDL_Vulkan_UnloadLibrary(); 12991 12992 return result; 12993} 12994 12995static XrResult VULKAN_DestroyXRSwapchain( 12996 SDL_GPURenderer *driverData, 12997 XrSwapchain swapchain, 12998 SDL_GPUTexture **swapchainImages) 12999{ 13000#ifdef HAVE_GPU_OPENXR 13001 XrResult result; 13002 VulkanRenderer *renderer = (VulkanRenderer *)driverData; 13003 13004 VULKAN_Wait(driverData); 13005 13006 Uint32 swapchainCount; 13007 result = renderer->xr->xrEnumerateSwapchainImages(swapchain, 0, &swapchainCount, NULL); 13008 if (result != XR_SUCCESS) { 13009 return result; 13010 } 13011 13012 // We always want to destroy the swapchain images, so don't early return if xrDestroySwapchain fails for some reason 13013 for (Uint32 i = 0; i < swapchainCount; i++) { 13014 VulkanTextureContainer *container = (VulkanTextureContainer *)swapchainImages[i]; 13015 13016 if (!container->externallyManaged) { 13017 SDL_SetError("Invalid GPU Texture handle."); 13018 return XR_ERROR_HANDLE_INVALID; 13019 } 13020 13021 VULKAN_INTERNAL_DestroyTexture(renderer, container->activeTexture); 13022 13023 // Free the container now that it's unused 13024 SDL_free(container); 13025 } 13026 13027 SDL_free(swapchainImages); 13028 13029 return renderer->xr->xrDestroySwapchain(swapchain); 13030#else 13031 SDL_SetError("SDL not built with OpenXR support"); 13032 return XR_ERROR_FUNCTION_UNSUPPORTED; 13033#endif 13034} 13035 13036#ifdef HAVE_GPU_OPENXR 13037static bool VULKAN_INTERNAL_FindXRSrgbSwapchain(int64_t *supportedFormats, Uint32 numFormats, SDL_GPUTextureFormat *sdlFormat, int64_t *vkFormat) 13038{ 13039 for (Uint32 i = 0; i < SDL_arraysize(SDLToVK_TextureFormat_SrgbOnly); i++) { 13040 for (Uint32 j = 0; j < numFormats; j++) { 13041 if (SDLToVK_TextureFormat_SrgbOnly[i].vk == supportedFormats[j]) { 13042 *sdlFormat = SDLToVK_TextureFormat_SrgbOnly[i].sdl; 13043 *vkFormat = SDLToVK_TextureFormat_SrgbOnly[i].vk; 13044 return true; 13045 } 13046 } 13047 } 13048 13049 return false; 13050} 13051#endif // HAVE_GPU_OPENXR 13052 13053static SDL_GPUTextureFormat* VULKAN_GetXRSwapchainFormats( 13054 SDL_GPURenderer *driverData, 13055 XrSession session, 13056 int *num_formats) 13057{ 13058#ifdef HAVE_GPU_OPENXR 13059 XrResult result; 13060 Uint32 i, j, num_supported_formats; 13061 int64_t *supported_formats; 13062 VulkanRenderer *renderer = (VulkanRenderer *)driverData; 13063 13064 result = renderer->xr->xrEnumerateSwapchainFormats(session, 0, &num_supported_formats, NULL); 13065 if (result != XR_SUCCESS) return NULL; 13066 supported_formats = SDL_stack_alloc(int64_t, num_supported_formats); 13067 result = renderer->xr->xrEnumerateSwapchainFormats(session, num_supported_formats, &num_supported_formats, supported_formats); 13068 if (result != XR_SUCCESS) { 13069 SDL_stack_free(supported_formats); 13070 return NULL; 13071 } 13072 13073 // FIXME: For now we're just searching for the optimal format, not all supported formats. 13074 // FIXME: Expand this search for all SDL_GPU formats! 13075 13076 SDL_GPUTextureFormat sdlFormat = SDL_GPU_TEXTUREFORMAT_INVALID; 13077 int64_t vkFormat = VK_FORMAT_UNDEFINED; 13078 // The OpenXR spec recommends applications not submit linear data, so let's try to explicitly find an sRGB swapchain before we search the whole list 13079 if (!VULKAN_INTERNAL_FindXRSrgbSwapchain(supported_formats, num_supported_formats, &sdlFormat, &vkFormat)) { 13080 // Iterate over all formats the runtime supports 13081 for (i = 0; i < num_supported_formats && vkFormat == VK_FORMAT_UNDEFINED; i++) { 13082 // Iterate over all formats we support 13083 for (j = 0; j < SDL_arraysize(SDLToVK_TextureFormat); j++) { 13084 // Pick the first format the runtime wants that we also support, the runtime should return these in order of preference 13085 if (SDLToVK_TextureFormat[j] == supported_formats[i]) { 13086 vkFormat = supported_formats[i]; 13087 sdlFormat = j; 13088 break; 13089 } 13090 } 13091 } 13092 } 13093 13094 SDL_stack_free(supported_formats); 13095 13096 if (vkFormat == VK_FORMAT_UNDEFINED) { 13097 SDL_SetError("Failed to find a swapchain format supported by both OpenXR and SDL"); 13098 return NULL; 13099 } 13100 13101 SDL_GPUTextureFormat *retval = (SDL_GPUTextureFormat*) SDL_malloc(sizeof(SDL_GPUTextureFormat) * 2); 13102 retval[0] = sdlFormat; 13103 retval[1] = SDL_GPU_TEXTUREFORMAT_INVALID; 13104 *num_formats = 1; 13105 return retval; 13106#else 13107 SDL_SetError("SDL not built with OpenXR support"); 13108 return NULL; 13109#endif 13110} 13111 13112static XrResult VULKAN_CreateXRSwapchain( 13113 SDL_GPURenderer *driverData, 13114 XrSession session, 13115 const XrSwapchainCreateInfo *oldCreateInfo, 13116 SDL_GPUTextureFormat format, 13117 XrSwapchain *swapchain, 13118 SDL_GPUTexture ***textures) 13119{ 13120#ifdef HAVE_GPU_OPENXR 13121 XrResult result; 13122 Uint32 i, j; 13123 VulkanRenderer *renderer = (VulkanRenderer *)driverData; 13124 13125 XrSwapchainCreateInfo createInfo = *oldCreateInfo; 13126 createInfo.format = SDLToVK_TextureFormat[format]; 13127 13128 result = renderer->xr->xrCreateSwapchain(session, &createInfo, swapchain); 13129 if (result != XR_SUCCESS) return result; 13130 13131 Uint32 swapchainImageCount; 13132 result = renderer->xr->xrEnumerateSwapchainImages(*swapchain, 0, &swapchainImageCount, NULL); 13133 if (result != XR_SUCCESS) return result; 13134 13135 XrSwapchainImageVulkan2KHR *swapchainImages = (XrSwapchainImageVulkan2KHR *)SDL_calloc(swapchainImageCount, sizeof(XrSwapchainImageVulkan2KHR)); 13136 for (i = 0; i < swapchainImageCount; i++) swapchainImages[i].type = XR_TYPE_SWAPCHAIN_IMAGE_VULKAN2_KHR; 13137 13138 result = renderer->xr->xrEnumerateSwapchainImages(*swapchain, swapchainImageCount, &swapchainImageCount, (XrSwapchainImageBaseHeader *)swapchainImages); 13139 if (result != XR_SUCCESS) { 13140 SDL_free(swapchainImages); 13141 return result; 13142 } 13143 13144 VulkanTextureContainer **textureContainers = (VulkanTextureContainer **)SDL_calloc(swapchainImageCount, sizeof(VulkanTextureContainer *)); 13145 13146 for (Uint32 idx = 0; idx < swapchainImageCount; idx++) { 13147 VkImage vkImage = swapchainImages[idx].image; 13148 13149 VulkanTexture *texture = SDL_calloc(1, sizeof(VulkanTexture)); 13150 13151 texture->swizzle = SwizzleForSDLFormat(format); 13152 texture->depth = 1; 13153 texture->usage = SDL_GPU_TEXTUREUSAGE_COLOR_TARGET; 13154 SDL_SetAtomicInt(&texture->referenceCount, 0); 13155 texture->image = vkImage; 13156 texture->externallyManaged = true; 13157 texture->aspectFlags = VK_IMAGE_ASPECT_COLOR_BIT; 13158 13159 texture->subresourceCount = createInfo.arraySize * createInfo.mipCount; 13160 texture->subresources = SDL_calloc( 13161 texture->subresourceCount, 13162 sizeof(VulkanTextureSubresource)); 13163 13164 for (i = 0; i < createInfo.arraySize; i += 1) { 13165 for (j = 0; j < createInfo.mipCount; j += 1) { 13166 Uint32 subresourceIndex = VULKAN_INTERNAL_GetTextureSubresourceIndex( 13167 j, 13168 i, 13169 createInfo.mipCount); 13170 13171 if (createInfo.usageFlags & XR_SWAPCHAIN_USAGE_COLOR_ATTACHMENT_BIT) { 13172 texture->subresources[subresourceIndex].renderTargetViews = SDL_malloc(sizeof(VkImageView)); 13173 13174 if (!VULKAN_INTERNAL_CreateRenderTargetView( 13175 renderer, 13176 texture, 13177 i, 13178 j, 13179 SDLToVK_TextureFormat[format], 13180 texture->swizzle, 13181 &texture->subresources[subresourceIndex].renderTargetViews[0])) { 13182 VULKAN_INTERNAL_DestroyTexture(renderer, texture); 13183 SDL_SetError("Failed to create render target view"); 13184 return XR_ERROR_RUNTIME_FAILURE; 13185 } 13186 } 13187 13188 texture->subresources[subresourceIndex].parent = texture; 13189 texture->subresources[subresourceIndex].layer = i; 13190 texture->subresources[subresourceIndex].level = j; 13191 } 13192 } 13193 13194 // Transition to the default barrier state 13195 VulkanCommandBuffer *barrierCommandBuffer = (VulkanCommandBuffer *)VULKAN_AcquireCommandBuffer((SDL_GPURenderer *)renderer); 13196 VULKAN_INTERNAL_TextureTransitionToDefaultUsage( 13197 renderer, 13198 barrierCommandBuffer, 13199 VULKAN_TEXTURE_USAGE_MODE_UNINITIALIZED, 13200 texture); 13201 VULKAN_INTERNAL_TrackTexture(barrierCommandBuffer, texture); 13202 VULKAN_Submit((SDL_GPUCommandBuffer *)barrierCommandBuffer); 13203 13204 textureContainers[idx] = SDL_malloc(sizeof(VulkanTextureContainer)); 13205 VulkanTextureContainer *container = textureContainers[idx]; 13206 SDL_zero(container->header.info); 13207 container->header.info.width = createInfo.width; 13208 container->header.info.height = createInfo.height; 13209 container->header.info.format = format; 13210 container->header.info.layer_count_or_depth = createInfo.arraySize; 13211 container->header.info.num_levels = createInfo.mipCount; 13212 container->header.info.sample_count = SDL_GPU_SAMPLECOUNT_1; 13213 container->header.info.usage = SDL_GPU_TEXTUREUSAGE_COLOR_TARGET; 13214 13215 container->externallyManaged = true; 13216 container->canBeCycled = false; 13217 container->activeTexture = texture; 13218 container->textureCapacity = 1; 13219 container->textureCount = 1; 13220 container->textures = SDL_malloc( 13221 container->textureCapacity * sizeof(VulkanTexture *)); 13222 container->textures[0] = container->activeTexture; 13223 container->debugName = NULL; 13224 } 13225 13226 *textures = (SDL_GPUTexture **)textureContainers; 13227 13228 SDL_free(swapchainImages); 13229 return XR_SUCCESS; 13230#else 13231 SDL_SetError("SDL not built with OpenXR support"); 13232 return XR_ERROR_FUNCTION_UNSUPPORTED; 13233#endif 13234} 13235 13236static XrResult VULKAN_CreateXRSession( 13237 SDL_GPURenderer *driverData, 13238 const XrSessionCreateInfo *createinfo, 13239 XrSession *session) 13240{ 13241#ifdef HAVE_GPU_OPENXR 13242 VulkanRenderer *renderer = (VulkanRenderer *)driverData; 13243 13244 // Copy out the existing next ptr so that we can append it to the end of the chain we create 13245 const void *XR_MAY_ALIAS currentNextPtr = createinfo->next; 13246 13247 // KHR_vulkan_enable and KHR_vulkan_enable2 share this structure, so we don't need to change any logic here to handle both 13248 XrGraphicsBindingVulkanKHR graphicsBinding; 13249 SDL_zero(graphicsBinding); 13250 graphicsBinding.type = XR_TYPE_GRAPHICS_BINDING_VULKAN_KHR; 13251 graphicsBinding.instance = renderer->instance; 13252 graphicsBinding.physicalDevice = renderer->physicalDevice; 13253 graphicsBinding.device = renderer->logicalDevice; 13254 graphicsBinding.queueFamilyIndex = renderer->queueFamilyIndex; 13255 graphicsBinding.queueIndex = 0; // we only ever have one queue, so hardcode queue index 0 13256 graphicsBinding.next = currentNextPtr; 13257 13258 XrSessionCreateInfo sessionCreateInfo = *createinfo; 13259 sessionCreateInfo.systemId = renderer->xrSystemId; 13260 sessionCreateInfo.next = &graphicsBinding; 13261 13262 return renderer->xr->xrCreateSession(renderer->xrInstance, &sessionCreateInfo, session); 13263#else 13264 SDL_SetError("SDL not built with OpenXR support"); 13265 return XR_ERROR_FUNCTION_UNSUPPORTED; 13266#endif 13267} 13268 13269static SDL_GPUDevice *VULKAN_CreateDevice(bool debugMode, bool preferLowPower, SDL_PropertiesID props) 13270{ 13271 VulkanRenderer *renderer; 13272 VulkanFeatures features; 13273 13274 SDL_GPUDevice *result; 13275 Uint32 i; 13276 13277 bool verboseLogs = SDL_GetBooleanProperty( 13278 props, 13279 SDL_PROP_GPU_DEVICE_CREATE_VERBOSE_BOOLEAN, 13280 true); 13281 13282 if (!SDL_Vulkan_LoadLibrary(NULL)) { 13283 SDL_assert(!"This should have failed in PrepareDevice first!"); 13284 return NULL; 13285 } 13286 13287 renderer = (VulkanRenderer *)SDL_calloc(1, sizeof(*renderer)); 13288 if (!renderer) { 13289 SDL_Vulkan_UnloadLibrary(); 13290 return NULL; 13291 } 13292 13293 renderer->debugMode = debugMode; 13294 renderer->preferLowPower = preferLowPower; 13295 renderer->allowedFramesInFlight = 2; 13296 renderer->minimumVkVersion = VK_API_VERSION_1_0; 13297 13298#ifdef HAVE_GPU_OPENXR 13299 bool xr = SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_XR_ENABLE_BOOLEAN, false); 13300 XrInstance *xrInstance = SDL_GetPointerProperty(props, SDL_PROP_GPU_DEVICE_CREATE_XR_INSTANCE_POINTER, NULL); 13301 XrSystemId *xrSystemId = SDL_GetPointerProperty(props, SDL_PROP_GPU_DEVICE_CREATE_XR_SYSTEM_ID_POINTER, NULL); 13302 13303 if (xr) { 13304 XrExtensionProperties gpuExtension; 13305 13306 if (!xrInstance) { 13307 SDL_SetError("You must specify an out pointer for the OpenXR instance"); 13308 SDL_free(renderer); 13309 SDL_Vulkan_UnloadLibrary(); 13310 return NULL; 13311 } 13312 13313 if (!xrSystemId) { 13314 SDL_SetError("You must specify an out pointer for the OpenXR system ID"); 13315 SDL_free(renderer); 13316 SDL_Vulkan_UnloadLibrary(); 13317 return NULL; 13318 } 13319 13320 if (!SDL_OpenXR_LoadLibrary()) { 13321 SDL_assert(!"This should have failed in PrepareDevice first!"); 13322 SDL_free(renderer); 13323 SDL_Vulkan_UnloadLibrary(); 13324 return NULL; 13325 } 13326 13327 if (!VULKAN_INTERNAL_SearchForOpenXrGpuExtension(&gpuExtension)) { 13328 SDL_LogDebug(SDL_LOG_CATEGORY_GPU, "Failed to find a compatible OpenXR vulkan extension"); 13329 SDL_OpenXR_UnloadLibrary(); 13330 SDL_free(renderer); 13331 SDL_Vulkan_UnloadLibrary(); 13332 return NULL; 13333 } 13334 13335 if (!SDL_OPENXR_INTERNAL_GPUInitOpenXR(debugMode, gpuExtension, props, xrInstance, xrSystemId, &renderer->xr)) { 13336 SDL_LogDebug(SDL_LOG_CATEGORY_GPU, "Failed to init OpenXR"); 13337 SDL_OpenXR_UnloadLibrary(); 13338 SDL_free(renderer); 13339 SDL_Vulkan_UnloadLibrary(); 13340 return NULL; 13341 } 13342 13343 renderer->xrInstance = *xrInstance; 13344 renderer->xrSystemId = *xrSystemId; 13345 13346 XrVersion minimumVulkanApiVersion; 13347 if (VULKAN_INTERNAL_GetXrMinimumVulkanApiVersion(&minimumVulkanApiVersion, *xrInstance, *xrSystemId) != XR_SUCCESS) { 13348 SDL_LogDebug(SDL_LOG_CATEGORY_GPU, "Failed to get OpenXR graphics requirements"); 13349 renderer->xr->xrDestroyInstance(*xrInstance); 13350 SDL_OpenXR_UnloadLibrary(); 13351 SDL_free(renderer->xr); 13352 SDL_free(renderer); 13353 SDL_Vulkan_UnloadLibrary(); 13354 return NULL; 13355 } 13356 13357 renderer->minimumVkVersion = VK_MAKE_VERSION( 13358 XR_VERSION_MAJOR(minimumVulkanApiVersion), 13359 XR_VERSION_MINOR(minimumVulkanApiVersion), 13360 XR_VERSION_PATCH(minimumVulkanApiVersion)); 13361 } 13362#endif // HAVE_GPU_OPENXR 13363 13364 if (!VULKAN_INTERNAL_PrepareVulkan(renderer, &features, props)) { 13365 SET_STRING_ERROR("Failed to initialize Vulkan!"); 13366#ifdef HAVE_GPU_OPENXR 13367 if (xr) { 13368 renderer->xr->xrDestroyInstance(*xrInstance); 13369 SDL_OpenXR_UnloadLibrary(); 13370 SDL_free(renderer->xr); 13371 } 13372#endif // HAVE_GPU_OPENXR 13373 SDL_free(renderer); 13374 SDL_Vulkan_UnloadLibrary(); 13375 return NULL; 13376 } 13377 13378 renderer->props = SDL_CreateProperties(); 13379 if (verboseLogs) { 13380 SDL_LogInfo(SDL_LOG_CATEGORY_GPU, "SDL_GPU Driver: Vulkan"); 13381 } 13382 13383 // Record device name 13384 const char *deviceName = renderer->physicalDeviceProperties.properties.deviceName; 13385 SDL_SetStringProperty( 13386 renderer->props, 13387 SDL_PROP_GPU_DEVICE_NAME_STRING, 13388 deviceName); 13389 if (verboseLogs) { 13390 SDL_LogInfo(SDL_LOG_CATEGORY_GPU, "Vulkan Device: %s", deviceName); 13391 } 13392 13393 // Record driver version. This is provided as a backup if 13394 // VK_KHR_driver_properties is not available but as most drivers support it 13395 // this property should be rarely used. 13396 // 13397 // This uses a vendor-specific encoding and it isn't well documented. The 13398 // vendor ID is the registered PCI ID of the vendor and can be found in 13399 // online databases. 13400 char driverVer[64]; 13401 Uint32 rawDriverVer = renderer->physicalDeviceProperties.properties.driverVersion; 13402 Uint32 vendorId = renderer->physicalDeviceProperties.properties.vendorID; 13403 if (vendorId == 0x10de) { 13404 // Nvidia uses 10|8|8|6 encoding. 13405 (void)SDL_snprintf( 13406 driverVer, 13407 SDL_arraysize(driverVer), 13408 "%d.%d.%d.%d", 13409 (rawDriverVer >> 22) & 0x3ff, 13410 (rawDriverVer >> 14) & 0xff, 13411 (rawDriverVer >> 6) & 0xff, 13412 rawDriverVer & 0x3f); 13413 } 13414#ifdef SDL_PLATFORM_WINDOWS 13415 else if (vendorId == 0x8086) { 13416 // Intel uses 18|14 encoding on Windows only. 13417 (void)SDL_snprintf( 13418 driverVer, 13419 SDL_arraysize(driverVer), 13420 "%d.%d", 13421 (rawDriverVer >> 14) & 0x3ffff, 13422 rawDriverVer & 0x3fff); 13423 } 13424#endif 13425 else { 13426 // Assume standard Vulkan 10|10|12 encoding for everything else. AMD and 13427 // Mesa are known to use this encoding. 13428 (void)SDL_snprintf( 13429 driverVer, 13430 SDL_arraysize(driverVer), 13431 "%d.%d.%d", 13432 (rawDriverVer >> 22) & 0x3ff, 13433 (rawDriverVer >> 12) & 0x3ff, 13434 rawDriverVer & 0xfff); 13435 } 13436 SDL_SetStringProperty( 13437 renderer->props, 13438 SDL_PROP_GPU_DEVICE_DRIVER_VERSION_STRING, 13439 driverVer); 13440 // Log this only if VK_KHR_driver_properties is not available. 13441 13442 if (renderer->supports.KHR_driver_properties) { 13443 // Record driver name and version 13444 const char *driverName = renderer->physicalDeviceDriverProperties.driverName; 13445 const char *driverInfo = renderer->physicalDeviceDriverProperties.driverInfo; 13446 SDL_SetStringProperty( 13447 renderer->props, 13448 SDL_PROP_GPU_DEVICE_DRIVER_NAME_STRING, 13449 driverName); 13450 SDL_SetStringProperty( 13451 renderer->props, 13452 SDL_PROP_GPU_DEVICE_DRIVER_INFO_STRING, 13453 driverInfo); 13454 if (verboseLogs) { 13455 // FIXME: driverInfo can be a multiline string. 13456 SDL_LogInfo(SDL_LOG_CATEGORY_GPU, "Vulkan Driver: %s %s", driverName, driverInfo); 13457 } 13458 13459 // Record conformance level 13460 if (verboseLogs) { 13461 char conformance[64]; 13462 (void)SDL_snprintf( 13463 conformance, 13464 SDL_arraysize(conformance), 13465 "%u.%u.%u.%u", 13466 renderer->physicalDeviceDriverProperties.conformanceVersion.major, 13467 renderer->physicalDeviceDriverProperties.conformanceVersion.minor, 13468 renderer->physicalDeviceDriverProperties.conformanceVersion.subminor, 13469 renderer->physicalDeviceDriverProperties.conformanceVersion.patch); 13470 SDL_LogInfo(SDL_LOG_CATEGORY_GPU, "Vulkan Conformance: %s", conformance); 13471 } 13472 } else { 13473 if (verboseLogs) { 13474 SDL_LogInfo(SDL_LOG_CATEGORY_GPU, "Vulkan Driver: %s", driverVer); 13475 } 13476 } 13477 13478 if (!VULKAN_INTERNAL_CreateLogicalDevice(renderer, &features)) { 13479 SET_STRING_ERROR("Failed to create logical device!"); 13480 SDL_free(renderer); 13481 SDL_Vulkan_UnloadLibrary(); 13482 return NULL; 13483 } 13484 13485 // FIXME: just move this into this function 13486 result = (SDL_GPUDevice *)SDL_calloc(1, sizeof(SDL_GPUDevice)); 13487 ASSIGN_DRIVER(VULKAN) 13488 13489 result->driverData = (SDL_GPURenderer *)renderer; 13490 result->shader_formats = SDL_GPU_SHADERFORMAT_SPIRV; 13491 13492 /* 13493 * Create initial swapchain array 13494 */ 13495 13496 renderer->claimedWindowCapacity = 1; 13497 renderer->claimedWindowCount = 0; 13498 renderer->claimedWindows = SDL_malloc( 13499 renderer->claimedWindowCapacity * sizeof(WindowData *)); 13500 13501 // Threading 13502 13503 renderer->allocatorLock = SDL_CreateMutex(); 13504 renderer->disposeLock = SDL_CreateMutex(); 13505 renderer->submitLock = SDL_CreateMutex(); 13506 renderer->acquireCommandBufferLock = SDL_CreateMutex(); 13507 renderer->acquireUniformBufferLock = SDL_CreateMutex(); 13508 renderer->renderPassFetchLock = SDL_CreateMutex(); 13509 renderer->framebufferFetchLock = SDL_CreateMutex(); 13510 renderer->graphicsPipelineLayoutFetchLock = SDL_CreateMutex(); 13511 renderer->computePipelineLayoutFetchLock = SDL_CreateMutex(); 13512 renderer->descriptorSetLayoutFetchLock = SDL_CreateMutex(); 13513 renderer->windowLock = SDL_CreateMutex(); 13514 13515 /* 13516 * Create submitted command buffer list 13517 */ 13518 13519 renderer->submittedCommandBufferCapacity = 16; 13520 renderer->submittedCommandBufferCount = 0; 13521 renderer->submittedCommandBuffers = SDL_malloc(sizeof(VulkanCommandBuffer *) * renderer->submittedCommandBufferCapacity); 13522 13523 // Memory Allocator 13524 13525 renderer->memoryAllocator = (VulkanMemoryAllocator *)SDL_malloc( 13526 sizeof(VulkanMemoryAllocator)); 13527 13528 for (i = 0; i < VK_MAX_MEMORY_TYPES; i += 1) { 13529 renderer->memoryAllocator->subAllocators[i].memoryTypeIndex = i; 13530 renderer->memoryAllocator->subAllocators[i].allocations = NULL; 13531 renderer->memoryAllocator->subAllocators[i].allocationCount = 0; 13532 renderer->memoryAllocator->subAllocators[i].sortedFreeRegions = SDL_malloc( 13533 sizeof(VulkanMemoryFreeRegion *) * 4); 13534 renderer->memoryAllocator->subAllocators[i].sortedFreeRegionCount = 0; 13535 renderer->memoryAllocator->subAllocators[i].sortedFreeRegionCapacity = 4; 13536 } 13537 13538 // Create uniform buffer pool 13539 13540 renderer->uniformBufferPoolCount = 32; 13541 renderer->uniformBufferPoolCapacity = 32; 13542 renderer->uniformBufferPool = SDL_malloc( 13543 renderer->uniformBufferPoolCapacity * sizeof(VulkanUniformBuffer *)); 13544 13545 for (i = 0; i < renderer->uniformBufferPoolCount; i += 1) { 13546 renderer->uniformBufferPool[i] = VULKAN_INTERNAL_CreateUniformBuffer( 13547 renderer, 13548 UNIFORM_BUFFER_SIZE); 13549 } 13550 13551 renderer->descriptorSetCachePoolCapacity = 8; 13552 renderer->descriptorSetCachePoolCount = 0; 13553 renderer->descriptorSetCachePool = SDL_calloc(renderer->descriptorSetCachePoolCapacity, sizeof(DescriptorSetCache *)); 13554 13555 SDL_SetAtomicInt(&renderer->layoutResourceID, 0); 13556 13557 // Device limits 13558 13559 renderer->minUBOAlignment = (Uint32)renderer->physicalDeviceProperties.properties.limits.minUniformBufferOffsetAlignment; 13560 13561 // Initialize caches 13562 13563 renderer->commandPoolHashTable = SDL_CreateHashTable( 13564 0, // !!! FIXME: a real guess here, for a _minimum_ if not a maximum, could be useful. 13565 false, // manually synchronized due to submission timing 13566 VULKAN_INTERNAL_CommandPoolHashFunction, 13567 VULKAN_INTERNAL_CommandPoolHashKeyMatch, 13568 VULKAN_INTERNAL_CommandPoolHashDestroy, 13569 (void *)renderer); 13570 13571 renderer->renderPassHashTable = SDL_CreateHashTable( 13572 0, // !!! FIXME: a real guess here, for a _minimum_ if not a maximum, could be useful. 13573 false, // manually synchronized due to lookup timing 13574 VULKAN_INTERNAL_RenderPassHashFunction, 13575 VULKAN_INTERNAL_RenderPassHashKeyMatch, 13576 VULKAN_INTERNAL_RenderPassHashDestroy, 13577 (void *)renderer); 13578 13579 renderer->framebufferHashTable = SDL_CreateHashTable( 13580 0, // !!! FIXME: a real guess here, for a _minimum_ if not a maximum, could be useful. 13581 false, // manually synchronized due to iteration 13582 VULKAN_INTERNAL_FramebufferHashFunction, 13583 VULKAN_INTERNAL_FramebufferHashKeyMatch, 13584 VULKAN_INTERNAL_FramebufferHashDestroy, 13585 (void *)renderer); 13586 13587 renderer->graphicsPipelineResourceLayoutHashTable = SDL_CreateHashTable( 13588 0, // !!! FIXME: a real guess here, for a _minimum_ if not a maximum, could be useful. 13589 false, // manually synchronized due to lookup timing 13590 VULKAN_INTERNAL_GraphicsPipelineResourceLayoutHashFunction, 13591 VULKAN_INTERNAL_GraphicsPipelineResourceLayoutHashKeyMatch, 13592 VULKAN_INTERNAL_GraphicsPipelineResourceLayoutHashDestroy, 13593 (void *)renderer); 13594 13595 renderer->computePipelineResourceLayoutHashTable = SDL_CreateHashTable( 13596 0, // !!! FIXME: a real guess here, for a _minimum_ if not a maximum, could be useful. 13597 false, // manually synchronized due to lookup timing 13598 VULKAN_INTERNAL_ComputePipelineResourceLayoutHashFunction, 13599 VULKAN_INTERNAL_ComputePipelineResourceLayoutHashKeyMatch, 13600 VULKAN_INTERNAL_ComputePipelineResourceLayoutHashDestroy, 13601 (void *)renderer); 13602 13603 renderer->descriptorSetLayoutHashTable = SDL_CreateHashTable( 13604 0, // !!! FIXME: a real guess here, for a _minimum_ if not a maximum, could be useful. 13605 false, // manually synchronized due to lookup timing 13606 VULKAN_INTERNAL_DescriptorSetLayoutHashFunction, 13607 VULKAN_INTERNAL_DescriptorSetLayoutHashKeyMatch, 13608 VULKAN_INTERNAL_DescriptorSetLayoutHashDestroy, 13609 (void *)renderer); 13610 13611 // Initialize fence pool 13612 13613 renderer->fencePool.lock = SDL_CreateMutex(); 13614 13615 renderer->fencePool.availableFenceCapacity = 4; 13616 renderer->fencePool.availableFenceCount = 0; 13617 renderer->fencePool.availableFences = SDL_malloc( 13618 renderer->fencePool.availableFenceCapacity * sizeof(VulkanFenceHandle *)); 13619 13620 // Deferred destroy storage 13621 13622 renderer->texturesToDestroyCapacity = 16; 13623 renderer->texturesToDestroyCount = 0; 13624 13625 renderer->texturesToDestroy = (VulkanTexture **)SDL_malloc( 13626 sizeof(VulkanTexture *) * 13627 renderer->texturesToDestroyCapacity); 13628 13629 renderer->buffersToDestroyCapacity = 16; 13630 renderer->buffersToDestroyCount = 0; 13631 13632 renderer->buffersToDestroy = SDL_malloc( 13633 sizeof(VulkanBuffer *) * 13634 renderer->buffersToDestroyCapacity); 13635 13636 renderer->samplersToDestroyCapacity = 16; 13637 renderer->samplersToDestroyCount = 0; 13638 13639 renderer->samplersToDestroy = SDL_malloc( 13640 sizeof(VulkanSampler *) * 13641 renderer->samplersToDestroyCapacity); 13642 13643 renderer->graphicsPipelinesToDestroyCapacity = 16; 13644 renderer->graphicsPipelinesToDestroyCount = 0; 13645 13646 renderer->graphicsPipelinesToDestroy = SDL_malloc( 13647 sizeof(VulkanGraphicsPipeline *) * 13648 renderer->graphicsPipelinesToDestroyCapacity); 13649 13650 renderer->computePipelinesToDestroyCapacity = 16; 13651 renderer->computePipelinesToDestroyCount = 0; 13652 13653 renderer->computePipelinesToDestroy = SDL_malloc( 13654 sizeof(VulkanComputePipeline *) * 13655 renderer->computePipelinesToDestroyCapacity); 13656 13657 renderer->shadersToDestroyCapacity = 16; 13658 renderer->shadersToDestroyCount = 0; 13659 13660 renderer->shadersToDestroy = SDL_malloc( 13661 sizeof(VulkanShader *) * 13662 renderer->shadersToDestroyCapacity); 13663 13664 renderer->framebuffersToDestroyCapacity = 16; 13665 renderer->framebuffersToDestroyCount = 0; 13666 renderer->framebuffersToDestroy = SDL_malloc( 13667 sizeof(VulkanFramebuffer *) * 13668 renderer->framebuffersToDestroyCapacity); 13669 13670 // Defrag state 13671 13672 renderer->defragInProgress = 0; 13673 13674 renderer->allocationsToDefragCount = 0; 13675 renderer->allocationsToDefragCapacity = 4; 13676 renderer->allocationsToDefrag = SDL_malloc( 13677 renderer->allocationsToDefragCapacity * sizeof(VulkanMemoryAllocation *)); 13678 13679 return result; 13680} 13681 13682SDL_GPUBootstrap VulkanDriver = { 13683 "vulkan", 13684 VULKAN_PrepareDriver, 13685 VULKAN_CreateDevice 13686}; 13687 13688#endif // SDL_GPU_VULKAN 13689
[FILE END]
(C) 2025 0x4248 (C) 2025 4248 Media and 4248 Systems, All part of 0x4248 See LICENCE files for more information. Not all files are by 0x4248 always check Licencing.