Atlas - SDL_gpu_vulkan.c
Home / ext / SDL / src / gpu / vulkan Lines: 1 | Size: 538330 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->buffersUsedInPendingTransfers); 3183 SDL_free(commandBuffer->usedTextures); 3184 SDL_free(commandBuffer->texturesUsedInPendingTransfers); 3185 SDL_free(commandBuffer->usedSamplers); 3186 SDL_free(commandBuffer->usedGraphicsPipelines); 3187 SDL_free(commandBuffer->usedComputePipelines); 3188 SDL_free(commandBuffer->usedFramebuffers); 3189 SDL_free(commandBuffer->usedUniformBuffers); 3190 3191 SDL_free(commandBuffer); 3192 } 3193 3194 SDL_free(commandPool->inactiveCommandBuffers); 3195 SDL_free(commandPool); 3196} 3197 3198static void VULKAN_INTERNAL_DestroyDescriptorSetLayout( 3199 VulkanRenderer *renderer, 3200 DescriptorSetLayout *layout) 3201{ 3202 if (layout == NULL) { 3203 return; 3204 } 3205 3206 if (layout->descriptorSetLayout != VK_NULL_HANDLE) { 3207 renderer->vkDestroyDescriptorSetLayout( 3208 renderer->logicalDevice, 3209 layout->descriptorSetLayout, 3210 NULL); 3211 } 3212 3213 SDL_free(layout); 3214} 3215 3216static void VULKAN_INTERNAL_DestroyGraphicsPipeline( 3217 VulkanRenderer *renderer, 3218 VulkanGraphicsPipeline *graphicsPipeline) 3219{ 3220 renderer->vkDestroyPipeline( 3221 renderer->logicalDevice, 3222 graphicsPipeline->pipeline, 3223 NULL); 3224 3225 (void)SDL_AtomicDecRef(&graphicsPipeline->vertexShader->referenceCount); 3226 (void)SDL_AtomicDecRef(&graphicsPipeline->fragmentShader->referenceCount); 3227 3228 SDL_free(graphicsPipeline); 3229} 3230 3231static void VULKAN_INTERNAL_DestroyComputePipeline( 3232 VulkanRenderer *renderer, 3233 VulkanComputePipeline *computePipeline) 3234{ 3235 if (computePipeline->pipeline != VK_NULL_HANDLE) { 3236 renderer->vkDestroyPipeline( 3237 renderer->logicalDevice, 3238 computePipeline->pipeline, 3239 NULL); 3240 } 3241 3242 if (computePipeline->shaderModule != VK_NULL_HANDLE) { 3243 renderer->vkDestroyShaderModule( 3244 renderer->logicalDevice, 3245 computePipeline->shaderModule, 3246 NULL); 3247 } 3248 3249 SDL_free(computePipeline); 3250} 3251 3252static void VULKAN_INTERNAL_DestroyShader( 3253 VulkanRenderer *renderer, 3254 VulkanShader *vulkanShader) 3255{ 3256 renderer->vkDestroyShaderModule( 3257 renderer->logicalDevice, 3258 vulkanShader->shaderModule, 3259 NULL); 3260 3261 SDL_free(vulkanShader->entrypointName); 3262 SDL_free(vulkanShader); 3263} 3264 3265static void VULKAN_INTERNAL_DestroySampler( 3266 VulkanRenderer *renderer, 3267 VulkanSampler *vulkanSampler) 3268{ 3269 renderer->vkDestroySampler( 3270 renderer->logicalDevice, 3271 vulkanSampler->sampler, 3272 NULL); 3273 3274 SDL_free(vulkanSampler); 3275} 3276 3277static void VULKAN_INTERNAL_DestroySwapchainImage( 3278 VulkanRenderer *renderer, 3279 WindowData *windowData) 3280{ 3281 Uint32 i; 3282 3283 if (windowData == NULL) { 3284 return; 3285 } 3286 3287 for (i = 0; i < windowData->imageCount; i += 1) { 3288 VULKAN_INTERNAL_RemoveFramebuffersContainingView( 3289 renderer, 3290 windowData->textureContainers[i].activeTexture->subresources[0].renderTargetViews[0]); 3291 renderer->vkDestroyImageView( 3292 renderer->logicalDevice, 3293 windowData->textureContainers[i].activeTexture->subresources[0].renderTargetViews[0], 3294 NULL); 3295 SDL_free(windowData->textureContainers[i].activeTexture->subresources[0].renderTargetViews); 3296 SDL_free(windowData->textureContainers[i].activeTexture->subresources); 3297 SDL_free(windowData->textureContainers[i].activeTexture); 3298 } 3299 3300 SDL_free(windowData->textureContainers); 3301 windowData->textureContainers = NULL; 3302 3303 for (i = 0; i < MAX_FRAMES_IN_FLIGHT; i += 1) { 3304 if (windowData->imageAvailableSemaphore[i]) { 3305 renderer->vkDestroySemaphore( 3306 renderer->logicalDevice, 3307 windowData->imageAvailableSemaphore[i], 3308 NULL); 3309 windowData->imageAvailableSemaphore[i] = VK_NULL_HANDLE; 3310 } 3311 } 3312 for (i = 0; i < windowData->imageCount; i += 1) { 3313 if (windowData->renderFinishedSemaphore[i]) { 3314 renderer->vkDestroySemaphore( 3315 renderer->logicalDevice, 3316 windowData->renderFinishedSemaphore[i], 3317 NULL); 3318 windowData->renderFinishedSemaphore[i] = VK_NULL_HANDLE; 3319 } 3320 } 3321 SDL_free(windowData->renderFinishedSemaphore); 3322 windowData->renderFinishedSemaphore = NULL; 3323 3324 windowData->imageCount = 0; 3325} 3326 3327static void VULKAN_INTERNAL_DestroySwapchain( 3328 VulkanRenderer *renderer, 3329 WindowData *windowData) 3330{ 3331 if (windowData == NULL) { 3332 return; 3333 } 3334 3335 VULKAN_INTERNAL_DestroySwapchainImage(renderer, windowData); 3336 3337 if (windowData->swapchain) { 3338 renderer->vkDestroySwapchainKHR( 3339 renderer->logicalDevice, 3340 windowData->swapchain, 3341 NULL); 3342 windowData->swapchain = VK_NULL_HANDLE; 3343 } 3344} 3345 3346static void VULKAN_INTERNAL_DestroyGraphicsPipelineResourceLayout( 3347 VulkanRenderer *renderer, 3348 VulkanGraphicsPipelineResourceLayout *resourceLayout) 3349{ 3350 if (resourceLayout->pipelineLayout != VK_NULL_HANDLE) { 3351 renderer->vkDestroyPipelineLayout( 3352 renderer->logicalDevice, 3353 resourceLayout->pipelineLayout, 3354 NULL); 3355 } 3356 3357 SDL_free(resourceLayout); 3358} 3359 3360static void VULKAN_INTERNAL_DestroyComputePipelineResourceLayout( 3361 VulkanRenderer *renderer, 3362 VulkanComputePipelineResourceLayout *resourceLayout) 3363{ 3364 if (resourceLayout->pipelineLayout != VK_NULL_HANDLE) { 3365 renderer->vkDestroyPipelineLayout( 3366 renderer->logicalDevice, 3367 resourceLayout->pipelineLayout, 3368 NULL); 3369 } 3370 3371 SDL_free(resourceLayout); 3372} 3373 3374static void VULKAN_INTERNAL_DestroyDescriptorSetCache( 3375 VulkanRenderer *renderer, 3376 DescriptorSetCache *descriptorSetCache) 3377{ 3378 for (Uint32 i = 0; i < descriptorSetCache->poolCount; i += 1) { 3379 for (Uint32 j = 0; j < descriptorSetCache->pools[i].poolCount; j += 1) { 3380 renderer->vkDestroyDescriptorPool( 3381 renderer->logicalDevice, 3382 descriptorSetCache->pools[i].descriptorPools[j], 3383 NULL); 3384 } 3385 SDL_free(descriptorSetCache->pools[i].descriptorSets); 3386 SDL_free(descriptorSetCache->pools[i].descriptorPools); 3387 } 3388 SDL_free(descriptorSetCache->pools); 3389 SDL_free(descriptorSetCache); 3390} 3391 3392// Hashtable functions 3393 3394static Uint32 SDLCALL VULKAN_INTERNAL_GraphicsPipelineResourceLayoutHashFunction(void *userdata, const void *key) 3395{ 3396 GraphicsPipelineResourceLayoutHashTableKey *hashTableKey = (GraphicsPipelineResourceLayoutHashTableKey *)key; 3397 /* The algorithm for this hashing function 3398 * is taken from Josh Bloch's "Effective Java". 3399 * (https://stackoverflow.com/a/113600/12492383) 3400 */ 3401 const Uint32 hashFactor = 31; 3402 Uint32 result = 1; 3403 result = result * hashFactor + hashTableKey->vertexSamplerCount; 3404 result = result * hashFactor + hashTableKey->vertexStorageBufferCount; 3405 result = result * hashFactor + hashTableKey->vertexStorageTextureCount; 3406 result = result * hashFactor + hashTableKey->vertexUniformBufferCount; 3407 result = result * hashFactor + hashTableKey->fragmentSamplerCount; 3408 result = result * hashFactor + hashTableKey->fragmentStorageBufferCount; 3409 result = result * hashFactor + hashTableKey->fragmentStorageTextureCount; 3410 result = result * hashFactor + hashTableKey->fragmentUniformBufferCount; 3411 return result; 3412} 3413static bool SDLCALL VULKAN_INTERNAL_GraphicsPipelineResourceLayoutHashKeyMatch(void *userdata, const void *aKey, const void *bKey) 3414{ 3415 return SDL_memcmp(aKey, bKey, sizeof(GraphicsPipelineResourceLayoutHashTableKey)) == 0; 3416} 3417static void SDLCALL VULKAN_INTERNAL_GraphicsPipelineResourceLayoutHashDestroy(void *userdata, const void *key, const void *value) 3418{ 3419 VulkanRenderer *renderer = (VulkanRenderer *)userdata; 3420 VulkanGraphicsPipelineResourceLayout *resourceLayout = (VulkanGraphicsPipelineResourceLayout *)value; 3421 VULKAN_INTERNAL_DestroyGraphicsPipelineResourceLayout(renderer, resourceLayout); 3422 SDL_free((void *)key); 3423} 3424 3425static Uint32 SDLCALL VULKAN_INTERNAL_ComputePipelineResourceLayoutHashFunction(void *userdata, const void *key) 3426{ 3427 ComputePipelineResourceLayoutHashTableKey *hashTableKey = (ComputePipelineResourceLayoutHashTableKey *)key; 3428 /* The algorithm for this hashing function 3429 * is taken from Josh Bloch's "Effective Java". 3430 * (https://stackoverflow.com/a/113600/12492383) 3431 */ 3432 const Uint32 hashFactor = 31; 3433 Uint32 result = 1; 3434 result = result * hashFactor + hashTableKey->samplerCount; 3435 result = result * hashFactor + hashTableKey->readonlyStorageTextureCount; 3436 result = result * hashFactor + hashTableKey->readonlyStorageBufferCount; 3437 result = result * hashFactor + hashTableKey->readWriteStorageTextureCount; 3438 result = result * hashFactor + hashTableKey->readWriteStorageBufferCount; 3439 result = result * hashFactor + hashTableKey->uniformBufferCount; 3440 return result; 3441} 3442 3443static bool SDLCALL VULKAN_INTERNAL_ComputePipelineResourceLayoutHashKeyMatch(void *userdata, const void *aKey, const void *bKey) 3444{ 3445 return SDL_memcmp(aKey, bKey, sizeof(ComputePipelineResourceLayoutHashTableKey)) == 0; 3446} 3447 3448static void SDLCALL VULKAN_INTERNAL_ComputePipelineResourceLayoutHashDestroy(void *userdata, const void *key, const void *value) 3449{ 3450 VulkanRenderer *renderer = (VulkanRenderer *)userdata; 3451 VulkanComputePipelineResourceLayout *resourceLayout = (VulkanComputePipelineResourceLayout *)value; 3452 VULKAN_INTERNAL_DestroyComputePipelineResourceLayout(renderer, resourceLayout); 3453 SDL_free((void *)key); 3454} 3455 3456static Uint32 SDLCALL VULKAN_INTERNAL_DescriptorSetLayoutHashFunction(void *userdata, const void *key) 3457{ 3458 DescriptorSetLayoutHashTableKey *hashTableKey = (DescriptorSetLayoutHashTableKey *)key; 3459 3460 /* The algorithm for this hashing function 3461 * is taken from Josh Bloch's "Effective Java". 3462 * (https://stackoverflow.com/a/113600/12492383) 3463 */ 3464 const Uint32 hashFactor = 31; 3465 Uint32 result = 1; 3466 result = result * hashFactor + hashTableKey->shaderStage; 3467 result = result * hashFactor + hashTableKey->samplerCount; 3468 result = result * hashFactor + hashTableKey->storageTextureCount; 3469 result = result * hashFactor + hashTableKey->storageBufferCount; 3470 result = result * hashFactor + hashTableKey->writeStorageTextureCount; 3471 result = result * hashFactor + hashTableKey->writeStorageBufferCount; 3472 result = result * hashFactor + hashTableKey->uniformBufferCount; 3473 return result; 3474} 3475 3476static bool SDLCALL VULKAN_INTERNAL_DescriptorSetLayoutHashKeyMatch(void *userdata, const void *aKey, const void *bKey) 3477{ 3478 return SDL_memcmp(aKey, bKey, sizeof(DescriptorSetLayoutHashTableKey)) == 0; 3479} 3480 3481static void SDLCALL VULKAN_INTERNAL_DescriptorSetLayoutHashDestroy(void *userdata, const void *key, const void *value) 3482{ 3483 VulkanRenderer *renderer = (VulkanRenderer *)userdata; 3484 DescriptorSetLayout *layout = (DescriptorSetLayout *)value; 3485 VULKAN_INTERNAL_DestroyDescriptorSetLayout(renderer, layout); 3486 SDL_free((void *)key); 3487} 3488 3489static Uint32 SDLCALL VULKAN_INTERNAL_CommandPoolHashFunction(void *userdata, const void *key) 3490{ 3491 return (Uint32)((CommandPoolHashTableKey *)key)->threadID; 3492} 3493 3494static bool SDLCALL VULKAN_INTERNAL_CommandPoolHashKeyMatch(void *userdata, const void *aKey, const void *bKey) 3495{ 3496 CommandPoolHashTableKey *a = (CommandPoolHashTableKey *)aKey; 3497 CommandPoolHashTableKey *b = (CommandPoolHashTableKey *)bKey; 3498 return a->threadID == b->threadID; 3499} 3500 3501static void SDLCALL VULKAN_INTERNAL_CommandPoolHashDestroy(void *userdata, const void *key, const void *value) 3502{ 3503 VulkanRenderer *renderer = (VulkanRenderer *)userdata; 3504 VulkanCommandPool *pool = (VulkanCommandPool *)value; 3505 VULKAN_INTERNAL_DestroyCommandPool(renderer, pool); 3506 SDL_free((void *)key); 3507} 3508 3509static Uint32 SDLCALL VULKAN_INTERNAL_RenderPassHashFunction(void *userdata, const void *key) 3510{ 3511 RenderPassHashTableKey *hashTableKey = (RenderPassHashTableKey *)key; 3512 3513 /* The algorithm for this hashing function 3514 * is taken from Josh Bloch's "Effective Java". 3515 * (https://stackoverflow.com/a/113600/12492383) 3516 */ 3517 const Uint32 hashFactor = 31; 3518 Uint32 result = 1; 3519 3520 for (Uint32 i = 0; i < hashTableKey->numColorTargets; i += 1) { 3521 result = result * hashFactor + hashTableKey->colorTargetDescriptions[i].loadOp; 3522 result = result * hashFactor + hashTableKey->colorTargetDescriptions[i].storeOp; 3523 result = result * hashFactor + hashTableKey->colorTargetDescriptions[i].format; 3524 } 3525 3526 for (Uint32 i = 0; i < hashTableKey->numResolveTargets; i += 1) { 3527 result = result * hashFactor + hashTableKey->resolveTargetFormats[i]; 3528 } 3529 3530 result = result * hashFactor + hashTableKey->depthStencilTargetDescription.loadOp; 3531 result = result * hashFactor + hashTableKey->depthStencilTargetDescription.storeOp; 3532 result = result * hashFactor + hashTableKey->depthStencilTargetDescription.stencilLoadOp; 3533 result = result * hashFactor + hashTableKey->depthStencilTargetDescription.stencilStoreOp; 3534 result = result * hashFactor + hashTableKey->depthStencilTargetDescription.format; 3535 3536 result = result * hashFactor + hashTableKey->sampleCount; 3537 3538 return result; 3539} 3540 3541static bool SDLCALL VULKAN_INTERNAL_RenderPassHashKeyMatch(void *userdata, const void *aKey, const void *bKey) 3542{ 3543 RenderPassHashTableKey *a = (RenderPassHashTableKey *)aKey; 3544 RenderPassHashTableKey *b = (RenderPassHashTableKey *)bKey; 3545 3546 if (a->numColorTargets != b->numColorTargets) { 3547 return 0; 3548 } 3549 3550 if (a->numResolveTargets != b->numResolveTargets) { 3551 return 0; 3552 } 3553 3554 if (a->sampleCount != b->sampleCount) { 3555 return 0; 3556 } 3557 3558 for (Uint32 i = 0; i < a->numColorTargets; i += 1) { 3559 if (a->colorTargetDescriptions[i].format != b->colorTargetDescriptions[i].format) { 3560 return 0; 3561 } 3562 3563 if (a->colorTargetDescriptions[i].loadOp != b->colorTargetDescriptions[i].loadOp) { 3564 return 0; 3565 } 3566 3567 if (a->colorTargetDescriptions[i].storeOp != b->colorTargetDescriptions[i].storeOp) { 3568 return 0; 3569 } 3570 } 3571 3572 for (Uint32 i = 0; i < a->numResolveTargets; i += 1) { 3573 if (a->resolveTargetFormats[i] != b->resolveTargetFormats[i]) { 3574 return 0; 3575 } 3576 } 3577 3578 if (a->depthStencilTargetDescription.format != b->depthStencilTargetDescription.format) { 3579 return 0; 3580 } 3581 3582 if (a->depthStencilTargetDescription.loadOp != b->depthStencilTargetDescription.loadOp) { 3583 return 0; 3584 } 3585 3586 if (a->depthStencilTargetDescription.storeOp != b->depthStencilTargetDescription.storeOp) { 3587 return 0; 3588 } 3589 3590 if (a->depthStencilTargetDescription.stencilLoadOp != b->depthStencilTargetDescription.stencilLoadOp) { 3591 return 0; 3592 } 3593 3594 if (a->depthStencilTargetDescription.stencilStoreOp != b->depthStencilTargetDescription.stencilStoreOp) { 3595 return 0; 3596 } 3597 3598 return 1; 3599} 3600 3601static void SDLCALL VULKAN_INTERNAL_RenderPassHashDestroy(void *userdata, const void *key, const void *value) 3602{ 3603 VulkanRenderer *renderer = (VulkanRenderer *)userdata; 3604 VulkanRenderPassHashTableValue *renderPassWrapper = (VulkanRenderPassHashTableValue *)value; 3605 renderer->vkDestroyRenderPass( 3606 renderer->logicalDevice, 3607 renderPassWrapper->handle, 3608 NULL); 3609 SDL_free(renderPassWrapper); 3610 SDL_free((void *)key); 3611} 3612 3613static Uint32 SDLCALL VULKAN_INTERNAL_FramebufferHashFunction(void *userdata, const void *key) 3614{ 3615 FramebufferHashTableKey *hashTableKey = (FramebufferHashTableKey *)key; 3616 3617 /* The algorithm for this hashing function 3618 * is taken from Josh Bloch's "Effective Java". 3619 * (https://stackoverflow.com/a/113600/12492383) 3620 */ 3621 const Uint32 hashFactor = 31; 3622 Uint32 result = 1; 3623 3624 for (Uint32 i = 0; i < hashTableKey->numColorTargets; i += 1) { 3625 result = result * hashFactor + (Uint32)(uintptr_t)hashTableKey->colorAttachmentViews[i]; 3626 } 3627 for (Uint32 i = 0; i < hashTableKey->numResolveAttachments; i += 1) { 3628 result = result * hashFactor + (Uint32)(uintptr_t)hashTableKey->resolveAttachmentViews[i]; 3629 } 3630 3631 result = result * hashFactor + (Uint32)(uintptr_t)hashTableKey->depthStencilAttachmentView; 3632 result = result * hashFactor + hashTableKey->width; 3633 result = result * hashFactor + hashTableKey->height; 3634 3635 return result; 3636} 3637 3638static bool SDLCALL VULKAN_INTERNAL_FramebufferHashKeyMatch(void *userdata, const void *aKey, const void *bKey) 3639{ 3640 FramebufferHashTableKey *a = (FramebufferHashTableKey *)aKey; 3641 FramebufferHashTableKey *b = (FramebufferHashTableKey *)bKey; 3642 3643 if (a->numColorTargets != b->numColorTargets) { 3644 return 0; 3645 } 3646 3647 if (a->numResolveAttachments != b->numResolveAttachments) { 3648 return 0; 3649 } 3650 3651 for (Uint32 i = 0; i < a->numColorTargets; i += 1) { 3652 if (a->colorAttachmentViews[i] != b->colorAttachmentViews[i]) { 3653 return 0; 3654 } 3655 } 3656 3657 for (Uint32 i = 0; i < a->numResolveAttachments; i += 1) { 3658 if (a->resolveAttachmentViews[i] != b->resolveAttachmentViews[i]) { 3659 return 0; 3660 } 3661 } 3662 3663 if (a->depthStencilAttachmentView != b->depthStencilAttachmentView) { 3664 return 0; 3665 } 3666 3667 if (a->width != b->width) { 3668 return 0; 3669 } 3670 3671 if (a->height != b->height) { 3672 return 0; 3673 } 3674 3675 return 1; 3676} 3677 3678static void SDLCALL VULKAN_INTERNAL_FramebufferHashDestroy(void *userdata, const void *key, const void *value) 3679{ 3680 VulkanRenderer *renderer = (VulkanRenderer *)userdata; 3681 VulkanFramebuffer *framebuffer = (VulkanFramebuffer *)value; 3682 VULKAN_INTERNAL_ReleaseFramebuffer(renderer, framebuffer); 3683 SDL_free((void *)key); 3684} 3685 3686// Descriptor pools 3687 3688static bool VULKAN_INTERNAL_AllocateDescriptorSets( 3689 VulkanRenderer *renderer, 3690 VkDescriptorPool descriptorPool, 3691 VkDescriptorSetLayout descriptorSetLayout, 3692 Uint32 descriptorSetCount, 3693 VkDescriptorSet *descriptorSetArray) 3694{ 3695 VkDescriptorSetAllocateInfo descriptorSetAllocateInfo; 3696 VkDescriptorSetLayout *descriptorSetLayouts = SDL_stack_alloc(VkDescriptorSetLayout, descriptorSetCount); 3697 VkResult vulkanResult; 3698 Uint32 i; 3699 3700 for (i = 0; i < descriptorSetCount; i += 1) { 3701 descriptorSetLayouts[i] = descriptorSetLayout; 3702 } 3703 3704 descriptorSetAllocateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; 3705 descriptorSetAllocateInfo.pNext = NULL; 3706 descriptorSetAllocateInfo.descriptorPool = descriptorPool; 3707 descriptorSetAllocateInfo.descriptorSetCount = descriptorSetCount; 3708 descriptorSetAllocateInfo.pSetLayouts = descriptorSetLayouts; 3709 3710 vulkanResult = renderer->vkAllocateDescriptorSets( 3711 renderer->logicalDevice, 3712 &descriptorSetAllocateInfo, 3713 descriptorSetArray); 3714 3715 SDL_stack_free(descriptorSetLayouts); 3716 3717 CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkAllocateDescriptorSets, false); 3718 3719 return true; 3720} 3721 3722static bool VULKAN_INTERNAL_AllocateDescriptorsFromPool( 3723 VulkanRenderer *renderer, 3724 DescriptorSetLayout *descriptorSetLayout, 3725 DescriptorSetPool *descriptorSetPool) 3726{ 3727 VkDescriptorPoolSize descriptorPoolSizes[ 3728 MAX_TEXTURE_SAMPLERS_PER_STAGE + 3729 MAX_STORAGE_TEXTURES_PER_STAGE + 3730 MAX_STORAGE_BUFFERS_PER_STAGE + 3731 MAX_COMPUTE_WRITE_TEXTURES + 3732 MAX_COMPUTE_WRITE_BUFFERS + 3733 MAX_UNIFORM_BUFFERS_PER_STAGE]; 3734 VkDescriptorPoolCreateInfo descriptorPoolInfo; 3735 VkDescriptorPool pool; 3736 VkResult vulkanResult; 3737 3738 // Category 1 3739 for (Uint32 i = 0; i < descriptorSetLayout->samplerCount; i += 1) { 3740 descriptorPoolSizes[i].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; 3741 descriptorPoolSizes[i].descriptorCount = DESCRIPTOR_POOL_SIZE; 3742 } 3743 3744 for (Uint32 i = descriptorSetLayout->samplerCount; i < descriptorSetLayout->samplerCount + descriptorSetLayout->storageTextureCount; i += 1) { 3745 descriptorPoolSizes[i].type = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE; // Yes, we are declaring the storage image as a sampled image, because shaders are stupid. 3746 descriptorPoolSizes[i].descriptorCount = DESCRIPTOR_POOL_SIZE; 3747 } 3748 3749 for (Uint32 i = descriptorSetLayout->samplerCount + descriptorSetLayout->storageTextureCount; i < descriptorSetLayout->samplerCount + descriptorSetLayout->storageTextureCount + descriptorSetLayout->storageBufferCount; i += 1) { 3750 descriptorPoolSizes[i].type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; 3751 descriptorPoolSizes[i].descriptorCount = DESCRIPTOR_POOL_SIZE; 3752 } 3753 3754 // Category 2 3755 for (Uint32 i = 0; i < descriptorSetLayout->writeStorageTextureCount; i += 1) { 3756 descriptorPoolSizes[i].type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; 3757 descriptorPoolSizes[i].descriptorCount = DESCRIPTOR_POOL_SIZE; 3758 } 3759 3760 for (Uint32 i = descriptorSetLayout->writeStorageTextureCount; i < descriptorSetLayout->writeStorageTextureCount + descriptorSetLayout->writeStorageBufferCount; i += 1) { 3761 descriptorPoolSizes[i].type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; 3762 descriptorPoolSizes[i].descriptorCount = DESCRIPTOR_POOL_SIZE; 3763 } 3764 3765 // Category 3 3766 for (Uint32 i = 0; i < descriptorSetLayout->uniformBufferCount; i += 1) { 3767 descriptorPoolSizes[i].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC; 3768 descriptorPoolSizes[i].descriptorCount = DESCRIPTOR_POOL_SIZE; 3769 } 3770 3771 descriptorPoolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; 3772 descriptorPoolInfo.pNext = NULL; 3773 descriptorPoolInfo.flags = 0; 3774 descriptorPoolInfo.maxSets = DESCRIPTOR_POOL_SIZE; 3775 descriptorPoolInfo.poolSizeCount = 3776 descriptorSetLayout->samplerCount + 3777 descriptorSetLayout->storageTextureCount + 3778 descriptorSetLayout->storageBufferCount + 3779 descriptorSetLayout->writeStorageTextureCount + 3780 descriptorSetLayout->writeStorageBufferCount + 3781 descriptorSetLayout->uniformBufferCount; 3782 descriptorPoolInfo.pPoolSizes = descriptorPoolSizes; 3783 3784 vulkanResult = renderer->vkCreateDescriptorPool( 3785 renderer->logicalDevice, 3786 &descriptorPoolInfo, 3787 NULL, 3788 &pool); 3789 3790 CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkCreateDescriptorPool, false); 3791 3792 descriptorSetPool->poolCount += 1; 3793 descriptorSetPool->descriptorPools = SDL_realloc( 3794 descriptorSetPool->descriptorPools, 3795 sizeof(VkDescriptorPool) * descriptorSetPool->poolCount); 3796 3797 descriptorSetPool->descriptorPools[descriptorSetPool->poolCount - 1] = pool; 3798 3799 descriptorSetPool->descriptorSets = SDL_realloc( 3800 descriptorSetPool->descriptorSets, 3801 sizeof(VkDescriptorSet) * descriptorSetPool->poolCount * DESCRIPTOR_POOL_SIZE); 3802 3803 if (!VULKAN_INTERNAL_AllocateDescriptorSets( 3804 renderer, 3805 pool, 3806 descriptorSetLayout->descriptorSetLayout, 3807 DESCRIPTOR_POOL_SIZE, 3808 &descriptorSetPool->descriptorSets[descriptorSetPool->descriptorSetCount])) { 3809 return false; 3810 } 3811 3812 descriptorSetPool->descriptorSetCount += DESCRIPTOR_POOL_SIZE; 3813 3814 return true; 3815} 3816 3817// NOTE: these categories should be mutually exclusive 3818static DescriptorSetLayout *VULKAN_INTERNAL_FetchDescriptorSetLayout( 3819 VulkanRenderer *renderer, 3820 VkShaderStageFlagBits shaderStage, 3821 // Category 1: read resources 3822 Uint32 samplerCount, 3823 Uint32 storageTextureCount, 3824 Uint32 storageBufferCount, 3825 // Category 2: write resources 3826 Uint32 writeStorageTextureCount, 3827 Uint32 writeStorageBufferCount, 3828 // Category 3: uniform buffers 3829 Uint32 uniformBufferCount) 3830{ 3831 DescriptorSetLayoutHashTableKey key; 3832 SDL_zero(key); 3833 DescriptorSetLayout *layout = NULL; 3834 3835 key.shaderStage = shaderStage; 3836 key.samplerCount = samplerCount; 3837 key.storageTextureCount = storageTextureCount; 3838 key.storageBufferCount = storageBufferCount; 3839 key.writeStorageTextureCount = writeStorageTextureCount; 3840 key.writeStorageBufferCount = writeStorageBufferCount; 3841 key.uniformBufferCount = uniformBufferCount; 3842 3843 SDL_LockMutex(renderer->descriptorSetLayoutFetchLock); 3844 3845 if (SDL_FindInHashTable( 3846 renderer->descriptorSetLayoutHashTable, 3847 (const void *)&key, 3848 (const void **)&layout)) { 3849 SDL_UnlockMutex(renderer->descriptorSetLayoutFetchLock); 3850 return layout; 3851 } 3852 3853 VkDescriptorSetLayout descriptorSetLayout; 3854 VkDescriptorSetLayoutBinding descriptorSetLayoutBindings[ 3855 MAX_TEXTURE_SAMPLERS_PER_STAGE + 3856 MAX_STORAGE_TEXTURES_PER_STAGE + 3857 MAX_STORAGE_BUFFERS_PER_STAGE + 3858 MAX_COMPUTE_WRITE_TEXTURES + 3859 MAX_COMPUTE_WRITE_BUFFERS]; 3860 3861 VkDescriptorSetLayoutCreateInfo descriptorSetLayoutCreateInfo; 3862 descriptorSetLayoutCreateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; 3863 descriptorSetLayoutCreateInfo.pNext = NULL; 3864 descriptorSetLayoutCreateInfo.flags = 0; 3865 3866 // Category 1 3867 for (Uint32 i = 0; i < samplerCount; i += 1) { 3868 descriptorSetLayoutBindings[i].binding = i; 3869 descriptorSetLayoutBindings[i].descriptorCount = 1; 3870 descriptorSetLayoutBindings[i].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; 3871 descriptorSetLayoutBindings[i].stageFlags = shaderStage; 3872 descriptorSetLayoutBindings[i].pImmutableSamplers = NULL; 3873 } 3874 3875 for (Uint32 i = samplerCount; i < samplerCount + storageTextureCount; i += 1) { 3876 descriptorSetLayoutBindings[i].binding = i; 3877 descriptorSetLayoutBindings[i].descriptorCount = 1; 3878 descriptorSetLayoutBindings[i].descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE; // Yes, we are declaring the storage image as a sampled image, because shaders are stupid. 3879 descriptorSetLayoutBindings[i].stageFlags = shaderStage; 3880 descriptorSetLayoutBindings[i].pImmutableSamplers = NULL; 3881 } 3882 3883 for (Uint32 i = samplerCount + storageTextureCount; i < samplerCount + storageTextureCount + storageBufferCount; i += 1) { 3884 descriptorSetLayoutBindings[i].binding = i; 3885 descriptorSetLayoutBindings[i].descriptorCount = 1; 3886 descriptorSetLayoutBindings[i].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; 3887 descriptorSetLayoutBindings[i].stageFlags = shaderStage; 3888 descriptorSetLayoutBindings[i].pImmutableSamplers = NULL; 3889 } 3890 3891 // Category 2 3892 for (Uint32 i = 0; i < writeStorageTextureCount; i += 1) { 3893 descriptorSetLayoutBindings[i].binding = i; 3894 descriptorSetLayoutBindings[i].descriptorCount = 1; 3895 descriptorSetLayoutBindings[i].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; 3896 descriptorSetLayoutBindings[i].stageFlags = shaderStage; 3897 descriptorSetLayoutBindings[i].pImmutableSamplers = NULL; 3898 } 3899 3900 for (Uint32 i = writeStorageTextureCount; i < writeStorageTextureCount + writeStorageBufferCount; i += 1) { 3901 descriptorSetLayoutBindings[i].binding = i; 3902 descriptorSetLayoutBindings[i].descriptorCount = 1; 3903 descriptorSetLayoutBindings[i].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; 3904 descriptorSetLayoutBindings[i].stageFlags = shaderStage; 3905 descriptorSetLayoutBindings[i].pImmutableSamplers = NULL; 3906 } 3907 3908 // Category 3 3909 for (Uint32 i = 0; i < uniformBufferCount; i += 1) { 3910 descriptorSetLayoutBindings[i].binding = i; 3911 descriptorSetLayoutBindings[i].descriptorCount = 1; 3912 descriptorSetLayoutBindings[i].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC; 3913 descriptorSetLayoutBindings[i].stageFlags = shaderStage; 3914 descriptorSetLayoutBindings[i].pImmutableSamplers = NULL; 3915 } 3916 3917 descriptorSetLayoutCreateInfo.pBindings = descriptorSetLayoutBindings; 3918 descriptorSetLayoutCreateInfo.bindingCount = 3919 samplerCount + 3920 storageTextureCount + 3921 storageBufferCount + 3922 writeStorageTextureCount + 3923 writeStorageBufferCount + 3924 uniformBufferCount; 3925 3926 VkResult vulkanResult = renderer->vkCreateDescriptorSetLayout( 3927 renderer->logicalDevice, 3928 &descriptorSetLayoutCreateInfo, 3929 NULL, 3930 &descriptorSetLayout); 3931 3932 if (vulkanResult != VK_SUCCESS) { 3933 SDL_UnlockMutex(renderer->descriptorSetLayoutFetchLock); 3934 CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkCreateDescriptorSetLayout, NULL); 3935 } 3936 3937 layout = SDL_malloc(sizeof(DescriptorSetLayout)); 3938 layout->descriptorSetLayout = descriptorSetLayout; 3939 3940 layout->samplerCount = samplerCount; 3941 layout->storageBufferCount = storageBufferCount; 3942 layout->storageTextureCount = storageTextureCount; 3943 layout->writeStorageBufferCount = writeStorageBufferCount; 3944 layout->writeStorageTextureCount = writeStorageTextureCount; 3945 layout->uniformBufferCount = uniformBufferCount; 3946 3947 layout->ID = SDL_AtomicIncRef(&renderer->layoutResourceID); 3948 3949 DescriptorSetLayoutHashTableKey *allocedKey = SDL_malloc(sizeof(DescriptorSetLayoutHashTableKey)); 3950 SDL_memcpy(allocedKey, &key, sizeof(DescriptorSetLayoutHashTableKey)); 3951 3952 SDL_InsertIntoHashTable( 3953 renderer->descriptorSetLayoutHashTable, 3954 (const void *)allocedKey, 3955 (const void *)layout, true); 3956 3957 SDL_UnlockMutex(renderer->descriptorSetLayoutFetchLock); 3958 return layout; 3959} 3960 3961static VulkanGraphicsPipelineResourceLayout *VULKAN_INTERNAL_FetchGraphicsPipelineResourceLayout( 3962 VulkanRenderer *renderer, 3963 VulkanShader *vertexShader, 3964 VulkanShader *fragmentShader) 3965{ 3966 GraphicsPipelineResourceLayoutHashTableKey key; 3967 SDL_zero(key); 3968 VulkanGraphicsPipelineResourceLayout *pipelineResourceLayout = NULL; 3969 3970 key.vertexSamplerCount = vertexShader->numSamplers; 3971 key.vertexStorageTextureCount = vertexShader->numStorageTextures; 3972 key.vertexStorageBufferCount = vertexShader->numStorageBuffers; 3973 key.vertexUniformBufferCount = vertexShader->numUniformBuffers; 3974 key.fragmentSamplerCount = fragmentShader->numSamplers; 3975 key.fragmentStorageTextureCount = fragmentShader->numStorageTextures; 3976 key.fragmentStorageBufferCount = fragmentShader->numStorageBuffers; 3977 key.fragmentUniformBufferCount = fragmentShader->numUniformBuffers; 3978 3979 SDL_LockMutex(renderer->graphicsPipelineLayoutFetchLock); 3980 3981 if (SDL_FindInHashTable( 3982 renderer->graphicsPipelineResourceLayoutHashTable, 3983 (const void *)&key, 3984 (const void **)&pipelineResourceLayout)) { 3985 SDL_UnlockMutex(renderer->graphicsPipelineLayoutFetchLock); 3986 return pipelineResourceLayout; 3987 } 3988 3989 VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo; 3990 VkDescriptorSetLayout descriptorSetLayouts[4]; 3991 VkResult vulkanResult; 3992 3993 pipelineResourceLayout = SDL_calloc(1, sizeof(VulkanGraphicsPipelineResourceLayout)); 3994 3995 pipelineResourceLayout->descriptorSetLayouts[0] = VULKAN_INTERNAL_FetchDescriptorSetLayout( 3996 renderer, 3997 VK_SHADER_STAGE_VERTEX_BIT, 3998 vertexShader->numSamplers, 3999 vertexShader->numStorageTextures, 4000 vertexShader->numStorageBuffers, 4001 0, 4002 0, 4003 0); 4004 4005 pipelineResourceLayout->descriptorSetLayouts[1] = VULKAN_INTERNAL_FetchDescriptorSetLayout( 4006 renderer, 4007 VK_SHADER_STAGE_VERTEX_BIT, 4008 0, 4009 0, 4010 0, 4011 0, 4012 0, 4013 vertexShader->numUniformBuffers); 4014 4015 pipelineResourceLayout->descriptorSetLayouts[2] = VULKAN_INTERNAL_FetchDescriptorSetLayout( 4016 renderer, 4017 VK_SHADER_STAGE_FRAGMENT_BIT, 4018 fragmentShader->numSamplers, 4019 fragmentShader->numStorageTextures, 4020 fragmentShader->numStorageBuffers, 4021 0, 4022 0, 4023 0); 4024 4025 pipelineResourceLayout->descriptorSetLayouts[3] = VULKAN_INTERNAL_FetchDescriptorSetLayout( 4026 renderer, 4027 VK_SHADER_STAGE_FRAGMENT_BIT, 4028 0, 4029 0, 4030 0, 4031 0, 4032 0, 4033 fragmentShader->numUniformBuffers); 4034 4035 descriptorSetLayouts[0] = pipelineResourceLayout->descriptorSetLayouts[0]->descriptorSetLayout; 4036 descriptorSetLayouts[1] = pipelineResourceLayout->descriptorSetLayouts[1]->descriptorSetLayout; 4037 descriptorSetLayouts[2] = pipelineResourceLayout->descriptorSetLayouts[2]->descriptorSetLayout; 4038 descriptorSetLayouts[3] = pipelineResourceLayout->descriptorSetLayouts[3]->descriptorSetLayout; 4039 4040 pipelineResourceLayout->vertexSamplerCount = vertexShader->numSamplers; 4041 pipelineResourceLayout->vertexStorageTextureCount = vertexShader->numStorageTextures; 4042 pipelineResourceLayout->vertexStorageBufferCount = vertexShader->numStorageBuffers; 4043 pipelineResourceLayout->vertexUniformBufferCount = vertexShader->numUniformBuffers; 4044 4045 pipelineResourceLayout->fragmentSamplerCount = fragmentShader->numSamplers; 4046 pipelineResourceLayout->fragmentStorageTextureCount = fragmentShader->numStorageTextures; 4047 pipelineResourceLayout->fragmentStorageBufferCount = fragmentShader->numStorageBuffers; 4048 pipelineResourceLayout->fragmentUniformBufferCount = fragmentShader->numUniformBuffers; 4049 4050 // Create the pipeline layout 4051 4052 pipelineLayoutCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; 4053 pipelineLayoutCreateInfo.pNext = NULL; 4054 pipelineLayoutCreateInfo.flags = 0; 4055 pipelineLayoutCreateInfo.setLayoutCount = 4; 4056 pipelineLayoutCreateInfo.pSetLayouts = descriptorSetLayouts; 4057 pipelineLayoutCreateInfo.pushConstantRangeCount = 0; 4058 pipelineLayoutCreateInfo.pPushConstantRanges = NULL; 4059 4060 vulkanResult = renderer->vkCreatePipelineLayout( 4061 renderer->logicalDevice, 4062 &pipelineLayoutCreateInfo, 4063 NULL, 4064 &pipelineResourceLayout->pipelineLayout); 4065 4066 if (vulkanResult != VK_SUCCESS) { 4067 VULKAN_INTERNAL_DestroyGraphicsPipelineResourceLayout(renderer, pipelineResourceLayout); 4068 SDL_UnlockMutex(renderer->graphicsPipelineLayoutFetchLock); 4069 CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkCreatePipelineLayout, NULL); 4070 } 4071 4072 GraphicsPipelineResourceLayoutHashTableKey *allocedKey = SDL_malloc(sizeof(GraphicsPipelineResourceLayoutHashTableKey)); 4073 SDL_memcpy(allocedKey, &key, sizeof(GraphicsPipelineResourceLayoutHashTableKey)); 4074 4075 SDL_InsertIntoHashTable( 4076 renderer->graphicsPipelineResourceLayoutHashTable, 4077 (const void *)allocedKey, 4078 (const void *)pipelineResourceLayout, true); 4079 4080 SDL_UnlockMutex(renderer->graphicsPipelineLayoutFetchLock); 4081 return pipelineResourceLayout; 4082} 4083 4084static VulkanComputePipelineResourceLayout *VULKAN_INTERNAL_FetchComputePipelineResourceLayout( 4085 VulkanRenderer *renderer, 4086 const SDL_GPUComputePipelineCreateInfo *createinfo) 4087{ 4088 ComputePipelineResourceLayoutHashTableKey key; 4089 SDL_zero(key); 4090 VulkanComputePipelineResourceLayout *pipelineResourceLayout = NULL; 4091 4092 key.samplerCount = createinfo->num_samplers; 4093 key.readonlyStorageTextureCount = createinfo->num_readonly_storage_textures; 4094 key.readonlyStorageBufferCount = createinfo->num_readonly_storage_buffers; 4095 key.readWriteStorageTextureCount = createinfo->num_readwrite_storage_textures; 4096 key.readWriteStorageBufferCount = createinfo->num_readwrite_storage_buffers; 4097 key.uniformBufferCount = createinfo->num_uniform_buffers; 4098 4099 SDL_LockMutex(renderer->computePipelineLayoutFetchLock); 4100 4101 if (SDL_FindInHashTable( 4102 renderer->computePipelineResourceLayoutHashTable, 4103 (const void *)&key, 4104 (const void **)&pipelineResourceLayout)) { 4105 SDL_UnlockMutex(renderer->computePipelineLayoutFetchLock); 4106 return pipelineResourceLayout; 4107 } 4108 4109 VkDescriptorSetLayout descriptorSetLayouts[3]; 4110 VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo; 4111 VkResult vulkanResult; 4112 4113 pipelineResourceLayout = SDL_calloc(1, sizeof(VulkanComputePipelineResourceLayout)); 4114 4115 pipelineResourceLayout->descriptorSetLayouts[0] = VULKAN_INTERNAL_FetchDescriptorSetLayout( 4116 renderer, 4117 VK_SHADER_STAGE_COMPUTE_BIT, 4118 createinfo->num_samplers, 4119 createinfo->num_readonly_storage_textures, 4120 createinfo->num_readonly_storage_buffers, 4121 0, 4122 0, 4123 0); 4124 4125 pipelineResourceLayout->descriptorSetLayouts[1] = VULKAN_INTERNAL_FetchDescriptorSetLayout( 4126 renderer, 4127 VK_SHADER_STAGE_COMPUTE_BIT, 4128 0, 4129 0, 4130 0, 4131 createinfo->num_readwrite_storage_textures, 4132 createinfo->num_readwrite_storage_buffers, 4133 0); 4134 4135 pipelineResourceLayout->descriptorSetLayouts[2] = VULKAN_INTERNAL_FetchDescriptorSetLayout( 4136 renderer, 4137 VK_SHADER_STAGE_COMPUTE_BIT, 4138 0, 4139 0, 4140 0, 4141 0, 4142 0, 4143 createinfo->num_uniform_buffers); 4144 4145 descriptorSetLayouts[0] = pipelineResourceLayout->descriptorSetLayouts[0]->descriptorSetLayout; 4146 descriptorSetLayouts[1] = pipelineResourceLayout->descriptorSetLayouts[1]->descriptorSetLayout; 4147 descriptorSetLayouts[2] = pipelineResourceLayout->descriptorSetLayouts[2]->descriptorSetLayout; 4148 4149 pipelineResourceLayout->numSamplers = createinfo->num_samplers; 4150 pipelineResourceLayout->numReadonlyStorageTextures = createinfo->num_readonly_storage_textures; 4151 pipelineResourceLayout->numReadonlyStorageBuffers = createinfo->num_readonly_storage_buffers; 4152 pipelineResourceLayout->numReadWriteStorageTextures = createinfo->num_readwrite_storage_textures; 4153 pipelineResourceLayout->numReadWriteStorageBuffers = createinfo->num_readwrite_storage_buffers; 4154 pipelineResourceLayout->numUniformBuffers = createinfo->num_uniform_buffers; 4155 4156 // Create the pipeline layout 4157 4158 pipelineLayoutCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; 4159 pipelineLayoutCreateInfo.pNext = NULL; 4160 pipelineLayoutCreateInfo.flags = 0; 4161 pipelineLayoutCreateInfo.setLayoutCount = 3; 4162 pipelineLayoutCreateInfo.pSetLayouts = descriptorSetLayouts; 4163 pipelineLayoutCreateInfo.pushConstantRangeCount = 0; 4164 pipelineLayoutCreateInfo.pPushConstantRanges = NULL; 4165 4166 vulkanResult = renderer->vkCreatePipelineLayout( 4167 renderer->logicalDevice, 4168 &pipelineLayoutCreateInfo, 4169 NULL, 4170 &pipelineResourceLayout->pipelineLayout); 4171 4172 if (vulkanResult != VK_SUCCESS) { 4173 VULKAN_INTERNAL_DestroyComputePipelineResourceLayout(renderer, pipelineResourceLayout); 4174 SDL_UnlockMutex(renderer->computePipelineLayoutFetchLock); 4175 CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkCreatePipelineLayout, NULL); 4176 } 4177 4178 ComputePipelineResourceLayoutHashTableKey *allocedKey = SDL_malloc(sizeof(ComputePipelineResourceLayoutHashTableKey)); 4179 SDL_memcpy(allocedKey, &key, sizeof(ComputePipelineResourceLayoutHashTableKey)); 4180 4181 SDL_InsertIntoHashTable( 4182 renderer->computePipelineResourceLayoutHashTable, 4183 (const void *)allocedKey, 4184 (const void *)pipelineResourceLayout, true); 4185 4186 SDL_UnlockMutex(renderer->computePipelineLayoutFetchLock); 4187 return pipelineResourceLayout; 4188} 4189 4190// Data Buffer 4191 4192static VulkanBuffer *VULKAN_INTERNAL_CreateBuffer( 4193 VulkanRenderer *renderer, 4194 VkDeviceSize size, 4195 SDL_GPUBufferUsageFlags usageFlags, 4196 VulkanBufferType type, 4197 bool dedicated, 4198 const char *debugName) 4199{ 4200 VulkanBuffer *buffer; 4201 VkResult vulkanResult; 4202 VkBufferCreateInfo createinfo; 4203 VkBufferUsageFlags vulkanUsageFlags = 0; 4204 Uint8 bindResult; 4205 4206 if (usageFlags & SDL_GPU_BUFFERUSAGE_VERTEX) { 4207 vulkanUsageFlags |= VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; 4208 } 4209 4210 if (usageFlags & SDL_GPU_BUFFERUSAGE_INDEX) { 4211 vulkanUsageFlags |= VK_BUFFER_USAGE_INDEX_BUFFER_BIT; 4212 } 4213 4214 if (usageFlags & (SDL_GPU_BUFFERUSAGE_GRAPHICS_STORAGE_READ | 4215 SDL_GPU_BUFFERUSAGE_COMPUTE_STORAGE_READ | 4216 SDL_GPU_BUFFERUSAGE_COMPUTE_STORAGE_WRITE)) { 4217 vulkanUsageFlags |= VK_BUFFER_USAGE_STORAGE_BUFFER_BIT; 4218 } 4219 4220 if (usageFlags & SDL_GPU_BUFFERUSAGE_INDIRECT) { 4221 vulkanUsageFlags |= VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT; 4222 } 4223 4224 if (type == VULKAN_BUFFER_TYPE_UNIFORM) { 4225 vulkanUsageFlags |= VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT; 4226 } else { 4227 // GPU buffers need transfer bits for defrag, transfer buffers need them for transfers 4228 vulkanUsageFlags |= VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT; 4229 } 4230 4231 buffer = SDL_calloc(1, sizeof(VulkanBuffer)); 4232 4233 buffer->size = size; 4234 buffer->usage = usageFlags; 4235 buffer->type = type; 4236 buffer->markedForDestroy = false; 4237 buffer->transitioned = false; 4238 4239 createinfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; 4240 createinfo.pNext = NULL; 4241 createinfo.flags = 0; 4242 createinfo.size = size; 4243 createinfo.usage = vulkanUsageFlags; 4244 createinfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; 4245 createinfo.queueFamilyIndexCount = 1; 4246 createinfo.pQueueFamilyIndices = &renderer->queueFamilyIndex; 4247 4248 // Set transfer bits so we can defrag 4249 createinfo.usage |= VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT; 4250 4251 vulkanResult = renderer->vkCreateBuffer( 4252 renderer->logicalDevice, 4253 &createinfo, 4254 NULL, 4255 &buffer->buffer); 4256 4257 if (vulkanResult != VK_SUCCESS) { 4258 SDL_free(buffer); 4259 CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkCreateBuffer, NULL); 4260 } 4261 4262 bindResult = VULKAN_INTERNAL_BindMemoryForBuffer( 4263 renderer, 4264 buffer->buffer, 4265 buffer->size, 4266 buffer->type, 4267 dedicated, 4268 &buffer->usedRegion); 4269 4270 if (bindResult != 1) { 4271 renderer->vkDestroyBuffer( 4272 renderer->logicalDevice, 4273 buffer->buffer, 4274 NULL); 4275 SDL_free(buffer); 4276 SET_STRING_ERROR_AND_RETURN("Failed to bind memory for buffer!", NULL); 4277 } 4278 4279 buffer->usedRegion->vulkanBuffer = buffer; // lol 4280 4281 SDL_SetAtomicInt(&buffer->referenceCount, 0); 4282 4283 if (renderer->debugMode && renderer->supportsDebugUtils && debugName != NULL) { 4284 VkDebugUtilsObjectNameInfoEXT nameInfo; 4285 nameInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT; 4286 nameInfo.pNext = NULL; 4287 nameInfo.pObjectName = debugName; 4288 nameInfo.objectType = VK_OBJECT_TYPE_BUFFER; 4289 nameInfo.objectHandle = (uint64_t)buffer->buffer; 4290 4291 renderer->vkSetDebugUtilsObjectNameEXT( 4292 renderer->logicalDevice, 4293 &nameInfo); 4294 } 4295 4296 return buffer; 4297} 4298 4299static VulkanBufferContainer *VULKAN_INTERNAL_CreateBufferContainer( 4300 VulkanRenderer *renderer, 4301 VkDeviceSize size, 4302 SDL_GPUBufferUsageFlags usageFlags, 4303 VulkanBufferType type, 4304 bool dedicated, 4305 const char *debugName) 4306{ 4307 VulkanBufferContainer *bufferContainer; 4308 VulkanBuffer *buffer; 4309 4310 buffer = VULKAN_INTERNAL_CreateBuffer( 4311 renderer, 4312 size, 4313 usageFlags, 4314 type, 4315 dedicated, 4316 debugName); 4317 4318 if (buffer == NULL) { 4319 return NULL; 4320 } 4321 4322 bufferContainer = SDL_calloc(1, sizeof(VulkanBufferContainer)); 4323 4324 bufferContainer->activeBuffer = buffer; 4325 buffer->container = bufferContainer; 4326 buffer->containerIndex = 0; 4327 4328 bufferContainer->bufferCapacity = 1; 4329 bufferContainer->bufferCount = 1; 4330 bufferContainer->buffers = SDL_calloc(bufferContainer->bufferCapacity, sizeof(VulkanBuffer *)); 4331 bufferContainer->buffers[0] = bufferContainer->activeBuffer; 4332 bufferContainer->dedicated = dedicated; 4333 bufferContainer->debugName = NULL; 4334 4335 if (debugName != NULL) { 4336 bufferContainer->debugName = SDL_strdup(debugName); 4337 } 4338 4339 return bufferContainer; 4340} 4341 4342// Texture Subresource Utilities 4343 4344static Uint32 VULKAN_INTERNAL_GetTextureSubresourceIndex( 4345 Uint32 mipLevel, 4346 Uint32 layer, 4347 Uint32 numLevels) 4348{ 4349 return mipLevel + (layer * numLevels); 4350} 4351 4352static VulkanTextureSubresource *VULKAN_INTERNAL_FetchTextureSubresource( 4353 VulkanTextureContainer *textureContainer, 4354 Uint32 layer, 4355 Uint32 level) 4356{ 4357 Uint32 index = VULKAN_INTERNAL_GetTextureSubresourceIndex( 4358 level, 4359 layer, 4360 textureContainer->header.info.num_levels); 4361 4362 return &textureContainer->activeTexture->subresources[index]; 4363} 4364 4365static bool VULKAN_INTERNAL_CreateRenderTargetView( 4366 VulkanRenderer *renderer, 4367 VulkanTexture *texture, 4368 Uint32 layerOrDepth, 4369 Uint32 level, 4370 VkFormat format, 4371 VkComponentMapping swizzle, 4372 VkImageView *pView) 4373{ 4374 VkResult vulkanResult; 4375 VkImageViewCreateInfo imageViewCreateInfo; 4376 4377 // create framebuffer compatible views for RenderTarget 4378 imageViewCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; 4379 imageViewCreateInfo.pNext = NULL; 4380 imageViewCreateInfo.flags = 0; 4381 imageViewCreateInfo.image = texture->image; 4382 imageViewCreateInfo.format = format; 4383 imageViewCreateInfo.components = swizzle; 4384 imageViewCreateInfo.subresourceRange.aspectMask = texture->aspectFlags; 4385 imageViewCreateInfo.subresourceRange.baseMipLevel = level; 4386 imageViewCreateInfo.subresourceRange.levelCount = 1; 4387 imageViewCreateInfo.subresourceRange.baseArrayLayer = layerOrDepth; 4388 imageViewCreateInfo.subresourceRange.layerCount = 1; 4389 imageViewCreateInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; 4390 4391 vulkanResult = renderer->vkCreateImageView( 4392 renderer->logicalDevice, 4393 &imageViewCreateInfo, 4394 NULL, 4395 pView); 4396 4397 if (vulkanResult != VK_SUCCESS) { 4398 *pView = (VkImageView)VK_NULL_HANDLE; 4399 CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkCreateImageView, false); 4400 } 4401 4402 return true; 4403} 4404 4405static bool VULKAN_INTERNAL_CreateSubresourceView( 4406 VulkanRenderer *renderer, 4407 const SDL_GPUTextureCreateInfo *createinfo, 4408 VulkanTexture *texture, 4409 Uint32 layer, 4410 Uint32 level, 4411 VkComponentMapping swizzle, 4412 VkImageView *pView) 4413{ 4414 VkResult vulkanResult; 4415 VkImageViewCreateInfo imageViewCreateInfo; 4416 4417 // create framebuffer compatible views for RenderTarget 4418 imageViewCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; 4419 imageViewCreateInfo.pNext = NULL; 4420 imageViewCreateInfo.flags = 0; 4421 imageViewCreateInfo.image = texture->image; 4422 imageViewCreateInfo.format = SDLToVK_TextureFormat[createinfo->format]; 4423 imageViewCreateInfo.components = swizzle; 4424 imageViewCreateInfo.subresourceRange.aspectMask = texture->aspectFlags; 4425 imageViewCreateInfo.subresourceRange.baseMipLevel = level; 4426 imageViewCreateInfo.subresourceRange.levelCount = 1; 4427 imageViewCreateInfo.subresourceRange.baseArrayLayer = layer; 4428 imageViewCreateInfo.subresourceRange.layerCount = 1; 4429 imageViewCreateInfo.viewType = (createinfo->type == SDL_GPU_TEXTURETYPE_3D) ? VK_IMAGE_VIEW_TYPE_3D : VK_IMAGE_VIEW_TYPE_2D; 4430 4431 vulkanResult = renderer->vkCreateImageView( 4432 renderer->logicalDevice, 4433 &imageViewCreateInfo, 4434 NULL, 4435 pView); 4436 4437 if (vulkanResult != VK_SUCCESS) { 4438 *pView = (VkImageView)VK_NULL_HANDLE; 4439 CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkCreateImageView, false); 4440 } 4441 4442 return true; 4443} 4444 4445// Swapchain 4446 4447static bool VULKAN_INTERNAL_QuerySwapchainSupport( 4448 VulkanRenderer *renderer, 4449 VkPhysicalDevice physicalDevice, 4450 VkSurfaceKHR surface, 4451 SwapchainSupportDetails *outputDetails) 4452{ 4453 VkResult result; 4454 VkBool32 supportsPresent; 4455 4456 renderer->vkGetPhysicalDeviceSurfaceSupportKHR( 4457 physicalDevice, 4458 renderer->queueFamilyIndex, 4459 surface, 4460 &supportsPresent); 4461 4462 // Initialize these in case anything fails 4463 outputDetails->formats = NULL; 4464 outputDetails->formatsLength = 0; 4465 outputDetails->presentModes = NULL; 4466 outputDetails->presentModesLength = 0; 4467 4468 if (!supportsPresent) { 4469 SET_STRING_ERROR_AND_RETURN("This surface does not support presenting!", false); 4470 } 4471 4472 // Run the device surface queries 4473 result = renderer->vkGetPhysicalDeviceSurfaceCapabilitiesKHR( 4474 physicalDevice, 4475 surface, 4476 &outputDetails->capabilities); 4477 CHECK_VULKAN_ERROR_AND_RETURN(result, vkGetPhysicalDeviceSurfaceCapabilitiesKHR, false); 4478 4479 if (!(outputDetails->capabilities.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR)) { 4480 SDL_LogWarn(SDL_LOG_CATEGORY_GPU, "Opaque presentation unsupported! Expect weird transparency bugs!"); 4481 } 4482 4483 result = renderer->vkGetPhysicalDeviceSurfaceFormatsKHR( 4484 physicalDevice, 4485 surface, 4486 &outputDetails->formatsLength, 4487 NULL); 4488 if (result != VK_SUCCESS) { 4489 // Make sure the driver didn't mess up this value. 4490 outputDetails->formatsLength = 0; 4491 CHECK_VULKAN_ERROR_AND_RETURN(result, vkGetPhysicalDeviceSurfaceFormatsKHR, false); 4492 } 4493 result = renderer->vkGetPhysicalDeviceSurfacePresentModesKHR( 4494 physicalDevice, 4495 surface, 4496 &outputDetails->presentModesLength, 4497 NULL); 4498 if (result != VK_SUCCESS) { 4499 // Make sure the driver didn't mess up this value. 4500 outputDetails->presentModesLength = 0; 4501 // Reset this one, too. 4502 outputDetails->formatsLength = 0; 4503 CHECK_VULKAN_ERROR_AND_RETURN(result, vkGetPhysicalDeviceSurfacePresentModesKHR, false); 4504 } 4505 4506 // Generate the arrays, if applicable 4507 4508 if (outputDetails->formatsLength != 0) { 4509 outputDetails->formats = (VkSurfaceFormatKHR *)SDL_malloc( 4510 sizeof(VkSurfaceFormatKHR) * outputDetails->formatsLength); 4511 4512 if (!outputDetails->formats) { // OOM 4513 outputDetails->formatsLength = 0; 4514 outputDetails->presentModesLength = 0; 4515 return false; 4516 } 4517 4518 result = renderer->vkGetPhysicalDeviceSurfaceFormatsKHR( 4519 physicalDevice, 4520 surface, 4521 &outputDetails->formatsLength, 4522 outputDetails->formats); 4523 if (result != VK_SUCCESS) { 4524 SDL_free(outputDetails->formats); 4525 outputDetails->formats = NULL; 4526 outputDetails->formatsLength = 0; 4527 outputDetails->presentModesLength = 0; 4528 CHECK_VULKAN_ERROR_AND_RETURN(result, vkGetPhysicalDeviceSurfaceFormatsKHR, false); 4529 } 4530 } 4531 4532 if (outputDetails->presentModesLength != 0) { 4533 outputDetails->presentModes = (VkPresentModeKHR *)SDL_malloc( 4534 sizeof(VkPresentModeKHR) * outputDetails->presentModesLength); 4535 4536 if (!outputDetails->presentModes) { // OOM 4537 SDL_free(outputDetails->formats); 4538 outputDetails->formats = NULL; 4539 outputDetails->formatsLength = 0; 4540 outputDetails->presentModesLength = 0; 4541 return false; 4542 } 4543 4544 result = renderer->vkGetPhysicalDeviceSurfacePresentModesKHR( 4545 physicalDevice, 4546 surface, 4547 &outputDetails->presentModesLength, 4548 outputDetails->presentModes); 4549 if (result != VK_SUCCESS) { 4550 SDL_free(outputDetails->formats); 4551 SDL_free(outputDetails->presentModes); 4552 outputDetails->formats = NULL; 4553 outputDetails->presentModes = NULL; 4554 outputDetails->formatsLength = 0; 4555 outputDetails->presentModesLength = 0; 4556 CHECK_VULKAN_ERROR_AND_RETURN(result, vkGetPhysicalDeviceSurfacePresentModesKHR, false); 4557 } 4558 } 4559 4560 /* If we made it here, all the queries were successful. This does NOT 4561 * necessarily mean there are any supported formats or present modes! 4562 */ 4563 return true; 4564} 4565 4566static bool VULKAN_INTERNAL_VerifySwapSurfaceFormat( 4567 VkFormat desiredFormat, 4568 VkColorSpaceKHR desiredColorSpace, 4569 VkSurfaceFormatKHR *availableFormats, 4570 Uint32 availableFormatsLength) 4571{ 4572 Uint32 i; 4573 for (i = 0; i < availableFormatsLength; i += 1) { 4574 if (availableFormats[i].format == desiredFormat && 4575 availableFormats[i].colorSpace == desiredColorSpace) { 4576 return true; 4577 } 4578 } 4579 return false; 4580} 4581 4582static bool VULKAN_INTERNAL_VerifySwapPresentMode( 4583 VkPresentModeKHR presentMode, 4584 const VkPresentModeKHR *availablePresentModes, 4585 Uint32 availablePresentModesLength) 4586{ 4587 Uint32 i; 4588 for (i = 0; i < availablePresentModesLength; i += 1) { 4589 if (availablePresentModes[i] == presentMode) { 4590 return true; 4591 } 4592 } 4593 return false; 4594} 4595 4596/* It would be nice if VULKAN_INTERNAL_CreateSwapchain could return a bool. 4597 * Unfortunately, some Win32 NVIDIA drivers are stupid 4598 * and will return surface extents of (0, 0) 4599 * in certain edge cases, and the swapchain extents are not allowed to be 0. 4600 * In this case, the client probably still wants to claim the window 4601 * or recreate the swapchain, so we should return 2 to indicate retry. 4602 * -cosmonaut 4603 */ 4604#define VULKAN_INTERNAL_TRY_AGAIN 2 4605 4606static Uint32 VULKAN_INTERNAL_CreateSwapchain( 4607 VulkanRenderer *renderer, 4608 WindowData *windowData) 4609{ 4610 VkResult vulkanResult; 4611 VkSwapchainCreateInfoKHR swapchainCreateInfo; 4612 VkImage *swapchainImages; 4613 VkSemaphoreCreateInfo semaphoreCreateInfo; 4614 SwapchainSupportDetails swapchainSupportDetails; 4615 bool hasValidSwapchainComposition, hasValidPresentMode; 4616 VkCompositeAlphaFlagsKHR compositeAlphaFlag = 0; 4617 Uint32 i; 4618 4619 windowData->frameCounter = 0; 4620 4621 if (!VULKAN_INTERNAL_QuerySwapchainSupport( 4622 renderer, 4623 renderer->physicalDevice, 4624 windowData->surface, 4625 &swapchainSupportDetails)) { 4626 return false; 4627 } 4628 4629 // Verify that we can use the requested composition and present mode 4630 windowData->format = SwapchainCompositionToFormat[windowData->swapchainComposition]; 4631 windowData->colorSpace = SwapchainCompositionToColorSpace[windowData->swapchainComposition]; 4632 windowData->swapchainSwizzle = SwapchainCompositionSwizzle[windowData->swapchainComposition]; 4633 windowData->usingFallbackFormat = false; 4634 4635 hasValidSwapchainComposition = VULKAN_INTERNAL_VerifySwapSurfaceFormat( 4636 windowData->format, 4637 windowData->colorSpace, 4638 swapchainSupportDetails.formats, 4639 swapchainSupportDetails.formatsLength); 4640 4641 if (!hasValidSwapchainComposition) { 4642 // Let's try again with the fallback format... 4643 windowData->format = SwapchainCompositionToFallbackFormat[windowData->swapchainComposition]; 4644 windowData->usingFallbackFormat = true; 4645 hasValidSwapchainComposition = VULKAN_INTERNAL_VerifySwapSurfaceFormat( 4646 windowData->format, 4647 windowData->colorSpace, 4648 swapchainSupportDetails.formats, 4649 swapchainSupportDetails.formatsLength); 4650 } 4651 4652 hasValidPresentMode = VULKAN_INTERNAL_VerifySwapPresentMode( 4653 SDLToVK_PresentMode[windowData->presentMode], 4654 swapchainSupportDetails.presentModes, 4655 swapchainSupportDetails.presentModesLength); 4656 4657 if (!hasValidSwapchainComposition || !hasValidPresentMode) { 4658 if (swapchainSupportDetails.formatsLength > 0) { 4659 SDL_free(swapchainSupportDetails.formats); 4660 } 4661 4662 if (swapchainSupportDetails.presentModesLength > 0) { 4663 SDL_free(swapchainSupportDetails.presentModes); 4664 } 4665 4666 if (!hasValidSwapchainComposition) { 4667 SET_STRING_ERROR_AND_RETURN("Device does not support requested swapchain composition!", false); 4668 } 4669 if (!hasValidPresentMode) { 4670 SET_STRING_ERROR_AND_RETURN("Device does not support requested present_mode!", false); 4671 } 4672 return false; 4673 } 4674 4675 // NVIDIA + Win32 can return 0 extent when the window is minimized. Try again! 4676 if (swapchainSupportDetails.capabilities.currentExtent.width == 0 || 4677 swapchainSupportDetails.capabilities.currentExtent.height == 0) { 4678 if (swapchainSupportDetails.formatsLength > 0) { 4679 SDL_free(swapchainSupportDetails.formats); 4680 } 4681 if (swapchainSupportDetails.presentModesLength > 0) { 4682 SDL_free(swapchainSupportDetails.presentModes); 4683 } 4684 return VULKAN_INTERNAL_TRY_AGAIN; 4685 } 4686 4687 Uint32 requestedImageCount = renderer->allowedFramesInFlight; 4688 4689#ifdef SDL_PLATFORM_APPLE 4690 windowData->width = swapchainSupportDetails.capabilities.currentExtent.width; 4691 windowData->height = swapchainSupportDetails.capabilities.currentExtent.height; 4692#else 4693 windowData->width = SDL_clamp( 4694 windowData->swapchainCreateWidth, 4695 swapchainSupportDetails.capabilities.minImageExtent.width, 4696 swapchainSupportDetails.capabilities.maxImageExtent.width); 4697 windowData->height = SDL_clamp(windowData->swapchainCreateHeight, 4698 swapchainSupportDetails.capabilities.minImageExtent.height, 4699 swapchainSupportDetails.capabilities.maxImageExtent.height); 4700#endif 4701 4702 if (swapchainSupportDetails.capabilities.maxImageCount > 0 && 4703 requestedImageCount > swapchainSupportDetails.capabilities.maxImageCount) { 4704 requestedImageCount = swapchainSupportDetails.capabilities.maxImageCount; 4705 } 4706 4707 if (requestedImageCount < swapchainSupportDetails.capabilities.minImageCount) { 4708 requestedImageCount = swapchainSupportDetails.capabilities.minImageCount; 4709 } 4710 4711 if (windowData->presentMode == SDL_GPU_PRESENTMODE_MAILBOX) { 4712 /* Required for proper triple-buffering. 4713 * Note that this is below the above maxImageCount check! 4714 * If the driver advertises MAILBOX but does not support 3 swap 4715 * images, it's not real mailbox support, so let it fail hard. 4716 * -flibit 4717 */ 4718 requestedImageCount = SDL_max(requestedImageCount, 3); 4719 } 4720 4721 // Default to opaque, if available, followed by inherit, and overwrite with a value that supports transparency, if necessary. 4722 if (swapchainSupportDetails.capabilities.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR) { 4723 compositeAlphaFlag = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; 4724 } else if (swapchainSupportDetails.capabilities.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR) { 4725 compositeAlphaFlag = VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR; 4726 } 4727 4728 if ((windowData->window->flags & SDL_WINDOW_TRANSPARENT) || !compositeAlphaFlag) { 4729 if (swapchainSupportDetails.capabilities.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR) { 4730 compositeAlphaFlag = VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR; 4731 } else if (swapchainSupportDetails.capabilities.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR) { 4732 compositeAlphaFlag = VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR; 4733 } else if (swapchainSupportDetails.capabilities.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR) { 4734 compositeAlphaFlag = VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR; 4735 } else { 4736 SDL_LogWarn(SDL_LOG_CATEGORY_GPU, "SDL_WINDOW_TRANSPARENT flag set, but no suitable swapchain composite alpha value supported!"); 4737 } 4738 } 4739 4740 swapchainCreateInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; 4741 swapchainCreateInfo.pNext = NULL; 4742 swapchainCreateInfo.flags = 0; 4743 swapchainCreateInfo.surface = windowData->surface; 4744 swapchainCreateInfo.minImageCount = requestedImageCount; 4745 swapchainCreateInfo.imageFormat = windowData->format; 4746 swapchainCreateInfo.imageColorSpace = windowData->colorSpace; 4747 swapchainCreateInfo.imageExtent.width = windowData->width; 4748 swapchainCreateInfo.imageExtent.height = windowData->height; 4749 swapchainCreateInfo.imageArrayLayers = 1; 4750 swapchainCreateInfo.imageUsage = 4751 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | 4752 VK_IMAGE_USAGE_TRANSFER_DST_BIT; 4753 swapchainCreateInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; 4754 swapchainCreateInfo.queueFamilyIndexCount = 0; 4755 swapchainCreateInfo.pQueueFamilyIndices = NULL; 4756#ifdef SDL_PLATFORM_ANDROID 4757 swapchainCreateInfo.preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; 4758#else 4759 swapchainCreateInfo.preTransform = swapchainSupportDetails.capabilities.currentTransform; 4760#endif 4761 swapchainCreateInfo.compositeAlpha = compositeAlphaFlag; 4762 swapchainCreateInfo.presentMode = SDLToVK_PresentMode[windowData->presentMode]; 4763 swapchainCreateInfo.clipped = VK_TRUE; 4764 // The old swapchain could belong to a surface that no longer exists due to app switching. 4765 swapchainCreateInfo.oldSwapchain = windowData->needsSurfaceRecreate ? (VkSwapchainKHR)0 : windowData->swapchain; 4766 vulkanResult = renderer->vkCreateSwapchainKHR( 4767 renderer->logicalDevice, 4768 &swapchainCreateInfo, 4769 NULL, 4770 &windowData->swapchain); 4771 4772 if (swapchainCreateInfo.oldSwapchain != VK_NULL_HANDLE) { 4773 renderer->vkDestroySwapchainKHR(renderer->logicalDevice, swapchainCreateInfo.oldSwapchain, NULL); 4774 } 4775 4776 if (swapchainSupportDetails.formatsLength > 0) { 4777 SDL_free(swapchainSupportDetails.formats); 4778 } 4779 if (swapchainSupportDetails.presentModesLength > 0) { 4780 SDL_free(swapchainSupportDetails.presentModes); 4781 } 4782 4783 if (vulkanResult != VK_SUCCESS) { 4784 windowData->swapchain = VK_NULL_HANDLE; 4785 CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkCreateSwapchainKHR, false); 4786 } 4787 4788 vulkanResult = renderer->vkGetSwapchainImagesKHR( 4789 renderer->logicalDevice, 4790 windowData->swapchain, 4791 &windowData->imageCount, 4792 NULL); 4793 CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkGetSwapchainImagesKHR, false); 4794 4795 windowData->textureContainers = SDL_malloc( 4796 sizeof(VulkanTextureContainer) * windowData->imageCount); 4797 4798 if (!windowData->textureContainers) { // OOM 4799 renderer->vkDestroySwapchainKHR( 4800 renderer->logicalDevice, 4801 windowData->swapchain, 4802 NULL); 4803 windowData->swapchain = VK_NULL_HANDLE; 4804 return false; 4805 } 4806 4807 swapchainImages = SDL_stack_alloc(VkImage, windowData->imageCount); 4808 4809 vulkanResult = renderer->vkGetSwapchainImagesKHR( 4810 renderer->logicalDevice, 4811 windowData->swapchain, 4812 &windowData->imageCount, 4813 swapchainImages); 4814 CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkGetSwapchainImagesKHR, false); 4815 4816 for (i = 0; i < windowData->imageCount; i += 1) { 4817 4818 // Initialize dummy container 4819 SDL_zero(windowData->textureContainers[i]); 4820 windowData->textureContainers[i].canBeCycled = false; 4821 windowData->textureContainers[i].header.info.width = windowData->width; 4822 windowData->textureContainers[i].header.info.height = windowData->height; 4823 windowData->textureContainers[i].header.info.layer_count_or_depth = 1; 4824 windowData->textureContainers[i].header.info.format = SwapchainCompositionToSDLFormat( 4825 windowData->swapchainComposition, 4826 windowData->usingFallbackFormat); 4827 windowData->textureContainers[i].header.info.type = SDL_GPU_TEXTURETYPE_2D; 4828 windowData->textureContainers[i].header.info.num_levels = 1; 4829 windowData->textureContainers[i].header.info.sample_count = SDL_GPU_SAMPLECOUNT_1; 4830 windowData->textureContainers[i].header.info.usage = SDL_GPU_TEXTUREUSAGE_COLOR_TARGET; 4831 4832 windowData->textureContainers[i].activeTexture = SDL_malloc(sizeof(VulkanTexture)); 4833 windowData->textureContainers[i].activeTexture->image = swapchainImages[i]; 4834 4835 // Swapchain memory is managed by the driver 4836 windowData->textureContainers[i].activeTexture->usedRegion = NULL; 4837 4838 windowData->textureContainers[i].activeTexture->swizzle = windowData->swapchainSwizzle; 4839 windowData->textureContainers[i].activeTexture->aspectFlags = VK_IMAGE_ASPECT_COLOR_BIT; 4840 windowData->textureContainers[i].activeTexture->depth = 1; 4841 windowData->textureContainers[i].activeTexture->usage = SDL_GPU_TEXTUREUSAGE_COLOR_TARGET; 4842 windowData->textureContainers[i].activeTexture->container = &windowData->textureContainers[i]; 4843 SDL_SetAtomicInt(&windowData->textureContainers[i].activeTexture->referenceCount, 0); 4844 4845 // Create slice 4846 windowData->textureContainers[i].activeTexture->subresourceCount = 1; 4847 windowData->textureContainers[i].activeTexture->subresources = SDL_malloc(sizeof(VulkanTextureSubresource)); 4848 windowData->textureContainers[i].activeTexture->subresources[0].parent = windowData->textureContainers[i].activeTexture; 4849 windowData->textureContainers[i].activeTexture->subresources[0].layer = 0; 4850 windowData->textureContainers[i].activeTexture->subresources[0].level = 0; 4851 windowData->textureContainers[i].activeTexture->subresources[0].renderTargetViews = SDL_malloc(sizeof(VkImageView)); 4852 if (!VULKAN_INTERNAL_CreateRenderTargetView( 4853 renderer, 4854 windowData->textureContainers[i].activeTexture, 4855 0, 4856 0, 4857 windowData->format, 4858 windowData->swapchainSwizzle, 4859 &windowData->textureContainers[i].activeTexture->subresources[0].renderTargetViews[0])) { 4860 renderer->vkDestroySwapchainKHR( 4861 renderer->logicalDevice, 4862 windowData->swapchain, 4863 NULL); 4864 windowData->swapchain = VK_NULL_HANDLE; 4865 return false; 4866 } 4867 } 4868 4869 SDL_stack_free(swapchainImages); 4870 4871 semaphoreCreateInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; 4872 semaphoreCreateInfo.pNext = NULL; 4873 semaphoreCreateInfo.flags = 0; 4874 4875 for (i = 0; i < MAX_FRAMES_IN_FLIGHT; i += 1) { 4876 vulkanResult = renderer->vkCreateSemaphore( 4877 renderer->logicalDevice, 4878 &semaphoreCreateInfo, 4879 NULL, 4880 &windowData->imageAvailableSemaphore[i]); 4881 4882 if (vulkanResult != VK_SUCCESS) { 4883 renderer->vkDestroySwapchainKHR( 4884 renderer->logicalDevice, 4885 windowData->swapchain, 4886 NULL); 4887 windowData->swapchain = VK_NULL_HANDLE; 4888 CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkCreateSemaphore, false); 4889 } 4890 4891 windowData->inFlightFences[i] = NULL; 4892 } 4893 4894 windowData->renderFinishedSemaphore = SDL_malloc( 4895 sizeof(VkSemaphore) * windowData->imageCount); 4896 for (i = 0; i < windowData->imageCount; i += 1) { 4897 vulkanResult = renderer->vkCreateSemaphore( 4898 renderer->logicalDevice, 4899 &semaphoreCreateInfo, 4900 NULL, 4901 &windowData->renderFinishedSemaphore[i]); 4902 4903 if (vulkanResult != VK_SUCCESS) { 4904 renderer->vkDestroySwapchainKHR( 4905 renderer->logicalDevice, 4906 windowData->swapchain, 4907 NULL); 4908 windowData->swapchain = VK_NULL_HANDLE; 4909 CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkCreateSemaphore, false); 4910 } 4911 } 4912 4913 windowData->needsSwapchainRecreate = false; 4914 return true; 4915} 4916 4917// Command Buffers 4918 4919static bool VULKAN_INTERNAL_BeginCommandBuffer( 4920 VulkanRenderer *renderer, 4921 VulkanCommandBuffer *commandBuffer) 4922{ 4923 VkCommandBufferBeginInfo beginInfo; 4924 VkResult result; 4925 4926 beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; 4927 beginInfo.pNext = NULL; 4928 beginInfo.flags = 0; 4929 beginInfo.pInheritanceInfo = NULL; 4930 beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; 4931 4932 result = renderer->vkBeginCommandBuffer( 4933 commandBuffer->commandBuffer, 4934 &beginInfo); 4935 4936 CHECK_VULKAN_ERROR_AND_RETURN(result, vkBeginCommandBuffer, false); 4937 4938 return true; 4939} 4940 4941static bool VULKAN_INTERNAL_EndCommandBuffer( 4942 VulkanRenderer *renderer, 4943 VulkanCommandBuffer *commandBuffer) 4944{ 4945 VkResult result = renderer->vkEndCommandBuffer( 4946 commandBuffer->commandBuffer); 4947 4948 CHECK_VULKAN_ERROR_AND_RETURN(result, vkEndCommandBuffer, false); 4949 4950 return true; 4951} 4952 4953static void VULKAN_DestroyDevice( 4954 SDL_GPUDevice *device) 4955{ 4956 VulkanRenderer *renderer = (VulkanRenderer *)device->driverData; 4957 VulkanMemorySubAllocator *allocator; 4958 4959 VULKAN_Wait(device->driverData); 4960 4961 for (Sint32 i = renderer->claimedWindowCount - 1; i >= 0; i -= 1) { 4962 VULKAN_ReleaseWindow(device->driverData, renderer->claimedWindows[i]->window); 4963 } 4964 4965 SDL_free(renderer->claimedWindows); 4966 4967 VULKAN_Wait(device->driverData); 4968 4969 SDL_free(renderer->submittedCommandBuffers); 4970 4971 for (Uint32 i = 0; i < renderer->uniformBufferPoolCount; i += 1) { 4972 VULKAN_INTERNAL_DestroyBuffer( 4973 renderer, 4974 renderer->uniformBufferPool[i]->buffer); 4975 SDL_free(renderer->uniformBufferPool[i]); 4976 } 4977 SDL_free(renderer->uniformBufferPool); 4978 4979 for (Uint32 i = 0; i < renderer->descriptorSetCachePoolCount; i += 1) { 4980 VULKAN_INTERNAL_DestroyDescriptorSetCache( 4981 renderer, 4982 renderer->descriptorSetCachePool[i]); 4983 } 4984 SDL_free(renderer->descriptorSetCachePool); 4985 4986 for (Uint32 i = 0; i < renderer->fencePool.availableFenceCount; i += 1) { 4987 renderer->vkDestroyFence( 4988 renderer->logicalDevice, 4989 renderer->fencePool.availableFences[i]->fence, 4990 NULL); 4991 4992 SDL_free(renderer->fencePool.availableFences[i]); 4993 } 4994 4995 SDL_free(renderer->fencePool.availableFences); 4996 SDL_DestroyMutex(renderer->fencePool.lock); 4997 4998 SDL_DestroyHashTable(renderer->commandPoolHashTable); 4999 SDL_DestroyHashTable(renderer->renderPassHashTable); 5000 SDL_DestroyHashTable(renderer->framebufferHashTable); 5001 SDL_DestroyHashTable(renderer->graphicsPipelineResourceLayoutHashTable); 5002 SDL_DestroyHashTable(renderer->computePipelineResourceLayoutHashTable); 5003 SDL_DestroyHashTable(renderer->descriptorSetLayoutHashTable); 5004 5005 for (Uint32 i = 0; i < VK_MAX_MEMORY_TYPES; i += 1) { 5006 allocator = &renderer->memoryAllocator->subAllocators[i]; 5007 5008 for (Sint32 j = allocator->allocationCount - 1; j >= 0; j -= 1) { 5009 for (Sint32 k = allocator->allocations[j]->usedRegionCount - 1; k >= 0; k -= 1) { 5010 VULKAN_INTERNAL_RemoveMemoryUsedRegion( 5011 renderer, 5012 allocator->allocations[j]->usedRegions[k]); 5013 } 5014 5015 VULKAN_INTERNAL_DeallocateMemory( 5016 renderer, 5017 allocator, 5018 j); 5019 } 5020 5021 SDL_free(renderer->memoryAllocator->subAllocators[i].allocations); 5022 5023 SDL_free(renderer->memoryAllocator->subAllocators[i].sortedFreeRegions); 5024 } 5025 5026 SDL_free(renderer->memoryAllocator); 5027 5028 SDL_free(renderer->texturesToDestroy); 5029 SDL_free(renderer->buffersToDestroy); 5030 SDL_free(renderer->graphicsPipelinesToDestroy); 5031 SDL_free(renderer->computePipelinesToDestroy); 5032 SDL_free(renderer->shadersToDestroy); 5033 SDL_free(renderer->samplersToDestroy); 5034 SDL_free(renderer->framebuffersToDestroy); 5035 SDL_free(renderer->allocationsToDefrag); 5036 5037 SDL_DestroyMutex(renderer->allocatorLock); 5038 SDL_DestroyMutex(renderer->disposeLock); 5039 SDL_DestroyMutex(renderer->submitLock); 5040 SDL_DestroyMutex(renderer->acquireCommandBufferLock); 5041 SDL_DestroyMutex(renderer->acquireUniformBufferLock); 5042 SDL_DestroyMutex(renderer->renderPassFetchLock); 5043 SDL_DestroyMutex(renderer->framebufferFetchLock); 5044 SDL_DestroyMutex(renderer->graphicsPipelineLayoutFetchLock); 5045 SDL_DestroyMutex(renderer->computePipelineLayoutFetchLock); 5046 SDL_DestroyMutex(renderer->descriptorSetLayoutFetchLock); 5047 SDL_DestroyMutex(renderer->windowLock); 5048 5049 renderer->vkDestroyDevice(renderer->logicalDevice, NULL); 5050 renderer->vkDestroyInstance(renderer->instance, NULL); 5051 5052 SDL_DestroyProperties(renderer->props); 5053 5054 SDL_free(renderer); 5055 SDL_free(device); 5056 SDL_Vulkan_UnloadLibrary(); 5057} 5058 5059static SDL_PropertiesID VULKAN_GetDeviceProperties( 5060 SDL_GPUDevice *device) 5061{ 5062 VulkanRenderer *renderer = (VulkanRenderer *)device->driverData; 5063 return renderer->props; 5064} 5065 5066static DescriptorSetCache *VULKAN_INTERNAL_AcquireDescriptorSetCache( 5067 VulkanRenderer *renderer) 5068{ 5069 DescriptorSetCache *cache; 5070 5071 if (renderer->descriptorSetCachePoolCount == 0) { 5072 cache = SDL_malloc(sizeof(DescriptorSetCache)); 5073 cache->poolCount = 0; 5074 cache->pools = NULL; 5075 } else { 5076 cache = renderer->descriptorSetCachePool[renderer->descriptorSetCachePoolCount - 1]; 5077 renderer->descriptorSetCachePoolCount -= 1; 5078 } 5079 5080 return cache; 5081} 5082 5083static void VULKAN_INTERNAL_ReturnDescriptorSetCacheToPool( 5084 VulkanRenderer *renderer, 5085 DescriptorSetCache *descriptorSetCache) 5086{ 5087 EXPAND_ARRAY_IF_NEEDED( 5088 renderer->descriptorSetCachePool, 5089 DescriptorSetCache *, 5090 renderer->descriptorSetCachePoolCount + 1, 5091 renderer->descriptorSetCachePoolCapacity, 5092 renderer->descriptorSetCachePoolCapacity * 2); 5093 5094 renderer->descriptorSetCachePool[renderer->descriptorSetCachePoolCount] = descriptorSetCache; 5095 renderer->descriptorSetCachePoolCount += 1; 5096 5097 for (Uint32 i = 0; i < descriptorSetCache->poolCount; i += 1) { 5098 descriptorSetCache->pools[i].descriptorSetIndex = 0; 5099 } 5100} 5101 5102static VkDescriptorSet VULKAN_INTERNAL_FetchDescriptorSet( 5103 VulkanRenderer *renderer, 5104 VulkanCommandBuffer *vulkanCommandBuffer, 5105 DescriptorSetLayout *descriptorSetLayout) 5106{ 5107 // Grow the pool to meet the descriptor set layout ID 5108 if (descriptorSetLayout->ID >= vulkanCommandBuffer->descriptorSetCache->poolCount) { 5109 vulkanCommandBuffer->descriptorSetCache->pools = SDL_realloc( 5110 vulkanCommandBuffer->descriptorSetCache->pools, 5111 sizeof(DescriptorSetPool) * (descriptorSetLayout->ID + 1)); 5112 5113 for (Uint32 i = vulkanCommandBuffer->descriptorSetCache->poolCount; i < descriptorSetLayout->ID + 1; i += 1) { 5114 SDL_zero(vulkanCommandBuffer->descriptorSetCache->pools[i]); 5115 } 5116 5117 vulkanCommandBuffer->descriptorSetCache->poolCount = descriptorSetLayout->ID + 1; 5118 } 5119 5120 DescriptorSetPool *pool = 5121 &vulkanCommandBuffer->descriptorSetCache->pools[descriptorSetLayout->ID]; 5122 5123 if (pool->descriptorSetIndex == pool->descriptorSetCount) { 5124 if (!VULKAN_INTERNAL_AllocateDescriptorsFromPool( 5125 renderer, 5126 descriptorSetLayout, 5127 pool)) { 5128 return VK_NULL_HANDLE; 5129 } 5130 } 5131 5132 VkDescriptorSet descriptorSet = pool->descriptorSets[pool->descriptorSetIndex]; 5133 pool->descriptorSetIndex += 1; 5134 5135 return descriptorSet; 5136} 5137 5138static void VULKAN_INTERNAL_BindGraphicsDescriptorSets( 5139 VulkanRenderer *renderer, 5140 VulkanCommandBuffer *commandBuffer) 5141{ 5142 VulkanGraphicsPipelineResourceLayout *resourceLayout; 5143 DescriptorSetLayout *descriptorSetLayout; 5144 VkWriteDescriptorSet writeDescriptorSets[ 5145 (MAX_TEXTURE_SAMPLERS_PER_STAGE + 5146 MAX_STORAGE_TEXTURES_PER_STAGE + 5147 MAX_STORAGE_BUFFERS_PER_STAGE + 5148 MAX_UNIFORM_BUFFERS_PER_STAGE) * 2]; 5149 VkDescriptorBufferInfo bufferInfos[MAX_STORAGE_BUFFERS_PER_STAGE * 2]; 5150 VkDescriptorImageInfo imageInfos[(MAX_TEXTURE_SAMPLERS_PER_STAGE + MAX_STORAGE_TEXTURES_PER_STAGE) * 2]; 5151 Uint32 dynamicOffsets[MAX_UNIFORM_BUFFERS_PER_STAGE * 2]; 5152 Uint32 writeCount = 0; 5153 Uint32 bufferInfoCount = 0; 5154 Uint32 imageInfoCount = 0; 5155 Uint32 dynamicOffsetCount = 0; 5156 5157 if ( 5158 !commandBuffer->needVertexBufferBind && 5159 !commandBuffer->needNewVertexResourceDescriptorSet && 5160 !commandBuffer->needNewVertexUniformDescriptorSet && 5161 !commandBuffer->needNewVertexUniformOffsets && 5162 !commandBuffer->needNewFragmentResourceDescriptorSet && 5163 !commandBuffer->needNewFragmentUniformDescriptorSet && 5164 !commandBuffer->needNewFragmentUniformOffsets 5165 ) { 5166 return; 5167 } 5168 5169 if (commandBuffer->needVertexBufferBind && commandBuffer->vertexBufferCount > 0) { 5170 renderer->vkCmdBindVertexBuffers( 5171 commandBuffer->commandBuffer, 5172 0, 5173 commandBuffer->vertexBufferCount, 5174 commandBuffer->vertexBuffers, 5175 commandBuffer->vertexBufferOffsets); 5176 5177 commandBuffer->needVertexBufferBind = false; 5178 } 5179 5180 resourceLayout = commandBuffer->currentGraphicsPipeline->resourceLayout; 5181 5182 if (commandBuffer->needNewVertexResourceDescriptorSet) { 5183 descriptorSetLayout = resourceLayout->descriptorSetLayouts[0]; 5184 5185 commandBuffer->vertexResourceDescriptorSet = VULKAN_INTERNAL_FetchDescriptorSet( 5186 renderer, 5187 commandBuffer, 5188 descriptorSetLayout); 5189 5190 for (Uint32 i = 0; i < resourceLayout->vertexSamplerCount; i += 1) { 5191 VkWriteDescriptorSet *currentWriteDescriptorSet = &writeDescriptorSets[writeCount]; 5192 5193 currentWriteDescriptorSet->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; 5194 currentWriteDescriptorSet->pNext = NULL; 5195 currentWriteDescriptorSet->descriptorCount = 1; 5196 currentWriteDescriptorSet->descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; 5197 currentWriteDescriptorSet->dstArrayElement = 0; 5198 currentWriteDescriptorSet->dstBinding = i; 5199 currentWriteDescriptorSet->dstSet = commandBuffer->vertexResourceDescriptorSet; 5200 currentWriteDescriptorSet->pTexelBufferView = NULL; 5201 currentWriteDescriptorSet->pBufferInfo = NULL; 5202 5203 imageInfos[imageInfoCount].sampler = commandBuffer->vertexSamplerBindings[i]; 5204 imageInfos[imageInfoCount].imageView = commandBuffer->vertexSamplerTextureViewBindings[i]; 5205 imageInfos[imageInfoCount].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; 5206 5207 currentWriteDescriptorSet->pImageInfo = &imageInfos[imageInfoCount]; 5208 5209 writeCount += 1; 5210 imageInfoCount += 1; 5211 } 5212 5213 for (Uint32 i = 0; i < resourceLayout->vertexStorageTextureCount; i += 1) { 5214 VkWriteDescriptorSet *currentWriteDescriptorSet = &writeDescriptorSets[writeCount]; 5215 5216 currentWriteDescriptorSet->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; 5217 currentWriteDescriptorSet->pNext = NULL; 5218 currentWriteDescriptorSet->descriptorCount = 1; 5219 currentWriteDescriptorSet->descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE; // Yes, we are declaring a storage image as a sampled image, because shaders are stupid. 5220 currentWriteDescriptorSet->dstArrayElement = 0; 5221 currentWriteDescriptorSet->dstBinding = resourceLayout->vertexSamplerCount + i; 5222 currentWriteDescriptorSet->dstSet = commandBuffer->vertexResourceDescriptorSet; 5223 currentWriteDescriptorSet->pTexelBufferView = NULL; 5224 currentWriteDescriptorSet->pBufferInfo = NULL; 5225 5226 imageInfos[imageInfoCount].sampler = VK_NULL_HANDLE; 5227 imageInfos[imageInfoCount].imageView = commandBuffer->vertexStorageTextureViewBindings[i]; 5228 imageInfos[imageInfoCount].imageLayout = VK_IMAGE_LAYOUT_GENERAL; 5229 5230 currentWriteDescriptorSet->pImageInfo = &imageInfos[imageInfoCount]; 5231 5232 writeCount += 1; 5233 imageInfoCount += 1; 5234 } 5235 5236 for (Uint32 i = 0; i < resourceLayout->vertexStorageBufferCount; i += 1) { 5237 VkWriteDescriptorSet *currentWriteDescriptorSet = &writeDescriptorSets[writeCount]; 5238 5239 currentWriteDescriptorSet->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; 5240 currentWriteDescriptorSet->pNext = NULL; 5241 currentWriteDescriptorSet->descriptorCount = 1; 5242 currentWriteDescriptorSet->descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; 5243 currentWriteDescriptorSet->dstArrayElement = 0; 5244 currentWriteDescriptorSet->dstBinding = resourceLayout->vertexSamplerCount + resourceLayout->vertexStorageTextureCount + i; 5245 currentWriteDescriptorSet->dstSet = commandBuffer->vertexResourceDescriptorSet; 5246 currentWriteDescriptorSet->pTexelBufferView = NULL; 5247 currentWriteDescriptorSet->pImageInfo = NULL; 5248 5249 bufferInfos[bufferInfoCount].buffer = commandBuffer->vertexStorageBufferBindings[i]; 5250 bufferInfos[bufferInfoCount].offset = 0; 5251 bufferInfos[bufferInfoCount].range = VK_WHOLE_SIZE; 5252 5253 currentWriteDescriptorSet->pBufferInfo = &bufferInfos[bufferInfoCount]; 5254 5255 writeCount += 1; 5256 bufferInfoCount += 1; 5257 } 5258 5259 commandBuffer->needNewVertexResourceDescriptorSet = false; 5260 } 5261 5262 if (commandBuffer->needNewVertexUniformDescriptorSet) { 5263 descriptorSetLayout = resourceLayout->descriptorSetLayouts[1]; 5264 5265 commandBuffer->vertexUniformDescriptorSet = VULKAN_INTERNAL_FetchDescriptorSet( 5266 renderer, 5267 commandBuffer, 5268 descriptorSetLayout); 5269 5270 for (Uint32 i = 0; i < resourceLayout->vertexUniformBufferCount; i += 1) { 5271 VkWriteDescriptorSet *currentWriteDescriptorSet = &writeDescriptorSets[writeCount]; 5272 5273 currentWriteDescriptorSet->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; 5274 currentWriteDescriptorSet->pNext = NULL; 5275 currentWriteDescriptorSet->descriptorCount = 1; 5276 currentWriteDescriptorSet->descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC; 5277 currentWriteDescriptorSet->dstArrayElement = 0; 5278 currentWriteDescriptorSet->dstBinding = i; 5279 currentWriteDescriptorSet->dstSet = commandBuffer->vertexUniformDescriptorSet; 5280 currentWriteDescriptorSet->pTexelBufferView = NULL; 5281 currentWriteDescriptorSet->pImageInfo = NULL; 5282 5283 bufferInfos[bufferInfoCount].buffer = commandBuffer->vertexUniformBuffers[i]->buffer->buffer; 5284 bufferInfos[bufferInfoCount].offset = 0; 5285 bufferInfos[bufferInfoCount].range = MAX_UBO_SECTION_SIZE; 5286 5287 currentWriteDescriptorSet->pBufferInfo = &bufferInfos[bufferInfoCount]; 5288 5289 writeCount += 1; 5290 bufferInfoCount += 1; 5291 } 5292 5293 commandBuffer->needNewVertexUniformDescriptorSet = false; 5294 } 5295 5296 for (Uint32 i = 0; i < resourceLayout->vertexUniformBufferCount; i += 1) { 5297 dynamicOffsets[dynamicOffsetCount] = commandBuffer->vertexUniformBuffers[i]->drawOffset; 5298 dynamicOffsetCount += 1; 5299 } 5300 5301 if (commandBuffer->needNewFragmentResourceDescriptorSet) { 5302 descriptorSetLayout = resourceLayout->descriptorSetLayouts[2]; 5303 5304 commandBuffer->fragmentResourceDescriptorSet = VULKAN_INTERNAL_FetchDescriptorSet( 5305 renderer, 5306 commandBuffer, 5307 descriptorSetLayout); 5308 5309 for (Uint32 i = 0; i < resourceLayout->fragmentSamplerCount; i += 1) { 5310 VkWriteDescriptorSet *currentWriteDescriptorSet = &writeDescriptorSets[writeCount]; 5311 5312 currentWriteDescriptorSet->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; 5313 currentWriteDescriptorSet->pNext = NULL; 5314 currentWriteDescriptorSet->descriptorCount = 1; 5315 currentWriteDescriptorSet->descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; 5316 currentWriteDescriptorSet->dstArrayElement = 0; 5317 currentWriteDescriptorSet->dstBinding = i; 5318 currentWriteDescriptorSet->dstSet = commandBuffer->fragmentResourceDescriptorSet; 5319 currentWriteDescriptorSet->pTexelBufferView = NULL; 5320 currentWriteDescriptorSet->pBufferInfo = NULL; 5321 5322 imageInfos[imageInfoCount].sampler = commandBuffer->fragmentSamplerBindings[i]; 5323 imageInfos[imageInfoCount].imageView = commandBuffer->fragmentSamplerTextureViewBindings[i]; 5324 imageInfos[imageInfoCount].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; 5325 5326 currentWriteDescriptorSet->pImageInfo = &imageInfos[imageInfoCount]; 5327 5328 writeCount += 1; 5329 imageInfoCount += 1; 5330 } 5331 5332 for (Uint32 i = 0; i < resourceLayout->fragmentStorageTextureCount; i += 1) { 5333 VkWriteDescriptorSet *currentWriteDescriptorSet = &writeDescriptorSets[writeCount]; 5334 5335 currentWriteDescriptorSet->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; 5336 currentWriteDescriptorSet->pNext = NULL; 5337 currentWriteDescriptorSet->descriptorCount = 1; 5338 currentWriteDescriptorSet->descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE; // Yes, we are declaring a storage image as a sampled image, because shaders are stupid. 5339 currentWriteDescriptorSet->dstArrayElement = 0; 5340 currentWriteDescriptorSet->dstBinding = resourceLayout->fragmentSamplerCount + i; 5341 currentWriteDescriptorSet->dstSet = commandBuffer->fragmentResourceDescriptorSet; 5342 currentWriteDescriptorSet->pTexelBufferView = NULL; 5343 currentWriteDescriptorSet->pBufferInfo = NULL; 5344 5345 imageInfos[imageInfoCount].sampler = VK_NULL_HANDLE; 5346 imageInfos[imageInfoCount].imageView = commandBuffer->fragmentStorageTextureViewBindings[i]; 5347 imageInfos[imageInfoCount].imageLayout = VK_IMAGE_LAYOUT_GENERAL; 5348 5349 currentWriteDescriptorSet->pImageInfo = &imageInfos[imageInfoCount]; 5350 5351 writeCount += 1; 5352 imageInfoCount += 1; 5353 } 5354 5355 for (Uint32 i = 0; i < resourceLayout->fragmentStorageBufferCount; i += 1) { 5356 VkWriteDescriptorSet *currentWriteDescriptorSet = &writeDescriptorSets[writeCount]; 5357 5358 currentWriteDescriptorSet->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; 5359 currentWriteDescriptorSet->pNext = NULL; 5360 currentWriteDescriptorSet->descriptorCount = 1; 5361 currentWriteDescriptorSet->descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; 5362 currentWriteDescriptorSet->dstArrayElement = 0; 5363 currentWriteDescriptorSet->dstBinding = resourceLayout->fragmentSamplerCount + resourceLayout->fragmentStorageTextureCount + i; 5364 currentWriteDescriptorSet->dstSet = commandBuffer->fragmentResourceDescriptorSet; 5365 currentWriteDescriptorSet->pTexelBufferView = NULL; 5366 currentWriteDescriptorSet->pImageInfo = NULL; 5367 5368 bufferInfos[bufferInfoCount].buffer = commandBuffer->fragmentStorageBufferBindings[i]; 5369 bufferInfos[bufferInfoCount].offset = 0; 5370 bufferInfos[bufferInfoCount].range = VK_WHOLE_SIZE; 5371 5372 currentWriteDescriptorSet->pBufferInfo = &bufferInfos[bufferInfoCount]; 5373 5374 writeCount += 1; 5375 bufferInfoCount += 1; 5376 } 5377 5378 commandBuffer->needNewFragmentResourceDescriptorSet = false; 5379 } 5380 5381 if (commandBuffer->needNewFragmentUniformDescriptorSet) { 5382 descriptorSetLayout = resourceLayout->descriptorSetLayouts[3]; 5383 5384 commandBuffer->fragmentUniformDescriptorSet = VULKAN_INTERNAL_FetchDescriptorSet( 5385 renderer, 5386 commandBuffer, 5387 descriptorSetLayout); 5388 5389 for (Uint32 i = 0; i < resourceLayout->fragmentUniformBufferCount; i += 1) { 5390 VkWriteDescriptorSet *currentWriteDescriptorSet = &writeDescriptorSets[writeCount]; 5391 5392 currentWriteDescriptorSet->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; 5393 currentWriteDescriptorSet->pNext = NULL; 5394 currentWriteDescriptorSet->descriptorCount = 1; 5395 currentWriteDescriptorSet->descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC; 5396 currentWriteDescriptorSet->dstArrayElement = 0; 5397 currentWriteDescriptorSet->dstBinding = i; 5398 currentWriteDescriptorSet->dstSet = commandBuffer->fragmentUniformDescriptorSet; 5399 currentWriteDescriptorSet->pTexelBufferView = NULL; 5400 currentWriteDescriptorSet->pImageInfo = NULL; 5401 5402 bufferInfos[bufferInfoCount].buffer = commandBuffer->fragmentUniformBuffers[i]->buffer->buffer; 5403 bufferInfos[bufferInfoCount].offset = 0; 5404 bufferInfos[bufferInfoCount].range = MAX_UBO_SECTION_SIZE; 5405 5406 currentWriteDescriptorSet->pBufferInfo = &bufferInfos[bufferInfoCount]; 5407 5408 writeCount += 1; 5409 bufferInfoCount += 1; 5410 } 5411 5412 commandBuffer->needNewFragmentUniformDescriptorSet = false; 5413 } 5414 5415 for (Uint32 i = 0; i < resourceLayout->fragmentUniformBufferCount; i += 1) { 5416 dynamicOffsets[dynamicOffsetCount] = commandBuffer->fragmentUniformBuffers[i]->drawOffset; 5417 dynamicOffsetCount += 1; 5418 } 5419 5420 renderer->vkUpdateDescriptorSets( 5421 renderer->logicalDevice, 5422 writeCount, 5423 writeDescriptorSets, 5424 0, 5425 NULL); 5426 5427 VkDescriptorSet sets[4]; 5428 sets[0] = commandBuffer->vertexResourceDescriptorSet; 5429 sets[1] = commandBuffer->vertexUniformDescriptorSet; 5430 sets[2] = commandBuffer->fragmentResourceDescriptorSet; 5431 sets[3] = commandBuffer->fragmentUniformDescriptorSet; 5432 5433 renderer->vkCmdBindDescriptorSets( 5434 commandBuffer->commandBuffer, 5435 VK_PIPELINE_BIND_POINT_GRAPHICS, 5436 resourceLayout->pipelineLayout, 5437 0, 5438 4, 5439 sets, 5440 dynamicOffsetCount, 5441 dynamicOffsets); 5442 5443 commandBuffer->needNewVertexUniformOffsets = false; 5444 commandBuffer->needNewFragmentUniformOffsets = false; 5445} 5446 5447static void VULKAN_DrawIndexedPrimitives( 5448 SDL_GPUCommandBuffer *commandBuffer, 5449 Uint32 numIndices, 5450 Uint32 numInstances, 5451 Uint32 firstIndex, 5452 Sint32 vertexOffset, 5453 Uint32 firstInstance) 5454{ 5455 VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; 5456 VulkanRenderer *renderer = vulkanCommandBuffer->renderer; 5457 5458 VULKAN_INTERNAL_BindGraphicsDescriptorSets(renderer, vulkanCommandBuffer); 5459 5460 renderer->vkCmdDrawIndexed( 5461 vulkanCommandBuffer->commandBuffer, 5462 numIndices, 5463 numInstances, 5464 firstIndex, 5465 vertexOffset, 5466 firstInstance); 5467} 5468 5469static void VULKAN_DrawPrimitives( 5470 SDL_GPUCommandBuffer *commandBuffer, 5471 Uint32 numVertices, 5472 Uint32 numInstances, 5473 Uint32 firstVertex, 5474 Uint32 firstInstance) 5475{ 5476 VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; 5477 VulkanRenderer *renderer = vulkanCommandBuffer->renderer; 5478 5479 VULKAN_INTERNAL_BindGraphicsDescriptorSets(renderer, vulkanCommandBuffer); 5480 5481 renderer->vkCmdDraw( 5482 vulkanCommandBuffer->commandBuffer, 5483 numVertices, 5484 numInstances, 5485 firstVertex, 5486 firstInstance); 5487} 5488 5489static void VULKAN_DrawPrimitivesIndirect( 5490 SDL_GPUCommandBuffer *commandBuffer, 5491 SDL_GPUBuffer *buffer, 5492 Uint32 offset, 5493 Uint32 drawCount) 5494{ 5495 VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; 5496 VulkanRenderer *renderer = vulkanCommandBuffer->renderer; 5497 VulkanBuffer *vulkanBuffer = ((VulkanBufferContainer *)buffer)->activeBuffer; 5498 Uint32 pitch = sizeof(SDL_GPUIndirectDrawCommand); 5499 Uint32 i; 5500 5501 VULKAN_INTERNAL_BindGraphicsDescriptorSets(renderer, vulkanCommandBuffer); 5502 5503 if (renderer->supportsMultiDrawIndirect) { 5504 // Real multi-draw! 5505 renderer->vkCmdDrawIndirect( 5506 vulkanCommandBuffer->commandBuffer, 5507 vulkanBuffer->buffer, 5508 offset, 5509 drawCount, 5510 pitch); 5511 } else { 5512 // Fake multi-draw... 5513 for (i = 0; i < drawCount; i += 1) { 5514 renderer->vkCmdDrawIndirect( 5515 vulkanCommandBuffer->commandBuffer, 5516 vulkanBuffer->buffer, 5517 offset + (pitch * i), 5518 1, 5519 pitch); 5520 } 5521 } 5522 5523 VULKAN_INTERNAL_TrackBuffer(vulkanCommandBuffer, vulkanBuffer); 5524} 5525 5526static void VULKAN_DrawIndexedPrimitivesIndirect( 5527 SDL_GPUCommandBuffer *commandBuffer, 5528 SDL_GPUBuffer *buffer, 5529 Uint32 offset, 5530 Uint32 drawCount) 5531{ 5532 VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; 5533 VulkanRenderer *renderer = vulkanCommandBuffer->renderer; 5534 VulkanBuffer *vulkanBuffer = ((VulkanBufferContainer *)buffer)->activeBuffer; 5535 Uint32 pitch = sizeof(SDL_GPUIndexedIndirectDrawCommand); 5536 Uint32 i; 5537 5538 VULKAN_INTERNAL_BindGraphicsDescriptorSets(renderer, vulkanCommandBuffer); 5539 5540 if (renderer->supportsMultiDrawIndirect) { 5541 // Real multi-draw! 5542 renderer->vkCmdDrawIndexedIndirect( 5543 vulkanCommandBuffer->commandBuffer, 5544 vulkanBuffer->buffer, 5545 offset, 5546 drawCount, 5547 pitch); 5548 } else { 5549 // Fake multi-draw... 5550 for (i = 0; i < drawCount; i += 1) { 5551 renderer->vkCmdDrawIndexedIndirect( 5552 vulkanCommandBuffer->commandBuffer, 5553 vulkanBuffer->buffer, 5554 offset + (pitch * i), 5555 1, 5556 pitch); 5557 } 5558 } 5559 5560 VULKAN_INTERNAL_TrackBuffer(vulkanCommandBuffer, vulkanBuffer); 5561} 5562 5563// Debug Naming 5564 5565static void VULKAN_INTERNAL_SetBufferName( 5566 VulkanRenderer *renderer, 5567 VulkanBuffer *buffer, 5568 const char *text) 5569{ 5570 VkDebugUtilsObjectNameInfoEXT nameInfo; 5571 5572 if (renderer->debugMode && renderer->supportsDebugUtils) { 5573 nameInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT; 5574 nameInfo.pNext = NULL; 5575 nameInfo.pObjectName = text; 5576 nameInfo.objectType = VK_OBJECT_TYPE_BUFFER; 5577 nameInfo.objectHandle = (uint64_t)buffer->buffer; 5578 5579 renderer->vkSetDebugUtilsObjectNameEXT( 5580 renderer->logicalDevice, 5581 &nameInfo); 5582 } 5583} 5584 5585static void VULKAN_SetBufferName( 5586 SDL_GPURenderer *driverData, 5587 SDL_GPUBuffer *buffer, 5588 const char *text) 5589{ 5590 VulkanRenderer *renderer = (VulkanRenderer *)driverData; 5591 VulkanBufferContainer *container = (VulkanBufferContainer *)buffer; 5592 size_t textLength = SDL_strlen(text) + 1; 5593 5594 if (renderer->debugMode && renderer->supportsDebugUtils) { 5595 container->debugName = SDL_realloc( 5596 container->debugName, 5597 textLength); 5598 5599 SDL_utf8strlcpy( 5600 container->debugName, 5601 text, 5602 textLength); 5603 5604 for (Uint32 i = 0; i < container->bufferCount; i += 1) { 5605 VULKAN_INTERNAL_SetBufferName( 5606 renderer, 5607 container->buffers[i], 5608 text); 5609 } 5610 } 5611} 5612 5613static void VULKAN_INTERNAL_SetTextureName( 5614 VulkanRenderer *renderer, 5615 VulkanTexture *texture, 5616 const char *text) 5617{ 5618 VkDebugUtilsObjectNameInfoEXT nameInfo; 5619 5620 if (renderer->debugMode && renderer->supportsDebugUtils) { 5621 nameInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT; 5622 nameInfo.pNext = NULL; 5623 nameInfo.pObjectName = text; 5624 nameInfo.objectType = VK_OBJECT_TYPE_IMAGE; 5625 nameInfo.objectHandle = (uint64_t)texture->image; 5626 5627 renderer->vkSetDebugUtilsObjectNameEXT( 5628 renderer->logicalDevice, 5629 &nameInfo); 5630 } 5631} 5632 5633static void VULKAN_SetTextureName( 5634 SDL_GPURenderer *driverData, 5635 SDL_GPUTexture *texture, 5636 const char *text) 5637{ 5638 VulkanRenderer *renderer = (VulkanRenderer *)driverData; 5639 VulkanTextureContainer *container = (VulkanTextureContainer *)texture; 5640 size_t textLength = SDL_strlen(text) + 1; 5641 5642 if (renderer->debugMode && renderer->supportsDebugUtils) { 5643 container->debugName = SDL_realloc( 5644 container->debugName, 5645 textLength); 5646 5647 SDL_utf8strlcpy( 5648 container->debugName, 5649 text, 5650 textLength); 5651 5652 for (Uint32 i = 0; i < container->textureCount; i += 1) { 5653 VULKAN_INTERNAL_SetTextureName( 5654 renderer, 5655 container->textures[i], 5656 text); 5657 } 5658 } 5659} 5660 5661static void VULKAN_InsertDebugLabel( 5662 SDL_GPUCommandBuffer *commandBuffer, 5663 const char *text) 5664{ 5665 VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; 5666 VulkanRenderer *renderer = vulkanCommandBuffer->renderer; 5667 VkDebugUtilsLabelEXT labelInfo; 5668 5669 if (renderer->supportsDebugUtils) { 5670 SDL_zero(labelInfo); 5671 labelInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT; 5672 labelInfo.pLabelName = text; 5673 5674 renderer->vkCmdInsertDebugUtilsLabelEXT( 5675 vulkanCommandBuffer->commandBuffer, 5676 &labelInfo); 5677 } 5678} 5679 5680static void VULKAN_PushDebugGroup( 5681 SDL_GPUCommandBuffer *commandBuffer, 5682 const char *name) 5683{ 5684 VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; 5685 VulkanRenderer *renderer = vulkanCommandBuffer->renderer; 5686 VkDebugUtilsLabelEXT labelInfo; 5687 5688 if (renderer->supportsDebugUtils) { 5689 SDL_zero(labelInfo); 5690 labelInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT; 5691 labelInfo.pLabelName = name; 5692 5693 renderer->vkCmdBeginDebugUtilsLabelEXT( 5694 vulkanCommandBuffer->commandBuffer, 5695 &labelInfo); 5696 } 5697} 5698 5699static void VULKAN_PopDebugGroup( 5700 SDL_GPUCommandBuffer *commandBuffer) 5701{ 5702 VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; 5703 VulkanRenderer *renderer = vulkanCommandBuffer->renderer; 5704 5705 if (renderer->supportsDebugUtils) { 5706 renderer->vkCmdEndDebugUtilsLabelEXT(vulkanCommandBuffer->commandBuffer); 5707 } 5708} 5709 5710static VulkanTexture *VULKAN_INTERNAL_CreateTexture( 5711 VulkanRenderer *renderer, 5712 const SDL_GPUTextureCreateInfo *createinfo) 5713{ 5714 VkResult vulkanResult; 5715 VkImageCreateInfo imageCreateInfo; 5716 VkImageCreateFlags imageCreateFlags = 0; 5717 VkImageViewCreateInfo imageViewCreateInfo; 5718 Uint8 bindResult; 5719 VkImageUsageFlags vkUsageFlags = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT; 5720 Uint32 layerCount = (createinfo->type == SDL_GPU_TEXTURETYPE_3D) ? 1 : createinfo->layer_count_or_depth; 5721 Uint32 depth = (createinfo->type == SDL_GPU_TEXTURETYPE_3D) ? createinfo->layer_count_or_depth : 1; 5722 5723 VulkanTexture *texture = SDL_calloc(1, sizeof(VulkanTexture)); 5724 texture->swizzle = SwizzleForSDLFormat(createinfo->format); 5725 texture->depth = depth; 5726 texture->usage = createinfo->usage; 5727 SDL_SetAtomicInt(&texture->referenceCount, 0); 5728 5729 if (IsDepthFormat(createinfo->format)) { 5730 texture->aspectFlags = VK_IMAGE_ASPECT_DEPTH_BIT; 5731 5732 if (IsStencilFormat(createinfo->format)) { 5733 texture->aspectFlags |= VK_IMAGE_ASPECT_STENCIL_BIT; 5734 } 5735 } else { 5736 texture->aspectFlags = VK_IMAGE_ASPECT_COLOR_BIT; 5737 } 5738 5739 if (createinfo->type == SDL_GPU_TEXTURETYPE_CUBE || createinfo->type == SDL_GPU_TEXTURETYPE_CUBE_ARRAY) { 5740 imageCreateFlags |= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT; 5741 } else if (createinfo->type == SDL_GPU_TEXTURETYPE_3D) { 5742 imageCreateFlags |= VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT; 5743 } 5744 5745 if (createinfo->usage & (SDL_GPU_TEXTUREUSAGE_SAMPLER | 5746 SDL_GPU_TEXTUREUSAGE_GRAPHICS_STORAGE_READ | 5747 SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_READ)) { 5748 vkUsageFlags |= VK_IMAGE_USAGE_SAMPLED_BIT; 5749 } 5750 if (createinfo->usage & SDL_GPU_TEXTUREUSAGE_COLOR_TARGET) { 5751 vkUsageFlags |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; 5752 } 5753 if (createinfo->usage & SDL_GPU_TEXTUREUSAGE_DEPTH_STENCIL_TARGET) { 5754 vkUsageFlags |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; 5755 } 5756 if (createinfo->usage & (SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_WRITE | 5757 SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_SIMULTANEOUS_READ_WRITE)) { 5758 vkUsageFlags |= VK_IMAGE_USAGE_STORAGE_BIT; 5759 } 5760 5761 imageCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; 5762 imageCreateInfo.pNext = NULL; 5763 imageCreateInfo.flags = imageCreateFlags; 5764 imageCreateInfo.imageType = createinfo->type == SDL_GPU_TEXTURETYPE_3D ? VK_IMAGE_TYPE_3D : VK_IMAGE_TYPE_2D; 5765 imageCreateInfo.format = SDLToVK_TextureFormat[createinfo->format]; 5766 imageCreateInfo.extent.width = createinfo->width; 5767 imageCreateInfo.extent.height = createinfo->height; 5768 imageCreateInfo.extent.depth = depth; 5769 imageCreateInfo.mipLevels = createinfo->num_levels; 5770 imageCreateInfo.arrayLayers = layerCount; 5771 imageCreateInfo.samples = SDLToVK_SampleCount[createinfo->sample_count]; 5772 imageCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL; 5773 imageCreateInfo.usage = vkUsageFlags; 5774 imageCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; 5775 imageCreateInfo.queueFamilyIndexCount = 0; 5776 imageCreateInfo.pQueueFamilyIndices = NULL; 5777 imageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; 5778 5779 vulkanResult = renderer->vkCreateImage( 5780 renderer->logicalDevice, 5781 &imageCreateInfo, 5782 NULL, 5783 &texture->image); 5784 5785 if (vulkanResult != VK_SUCCESS) { 5786 VULKAN_INTERNAL_DestroyTexture(renderer, texture); 5787 CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkCreateImage, NULL); 5788 } 5789 5790 bindResult = VULKAN_INTERNAL_BindMemoryForImage( 5791 renderer, 5792 texture->image, 5793 &texture->usedRegion); 5794 5795 if (bindResult != 1) { 5796 renderer->vkDestroyImage( 5797 renderer->logicalDevice, 5798 texture->image, 5799 NULL); 5800 5801 VULKAN_INTERNAL_DestroyTexture(renderer, texture); 5802 SET_STRING_ERROR_AND_RETURN("Unable to bind memory for texture!", NULL); 5803 } 5804 5805 texture->usedRegion->vulkanTexture = texture; // lol 5806 5807 if (createinfo->usage & (SDL_GPU_TEXTUREUSAGE_SAMPLER | SDL_GPU_TEXTUREUSAGE_GRAPHICS_STORAGE_READ | SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_READ)) { 5808 5809 imageViewCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; 5810 imageViewCreateInfo.pNext = NULL; 5811 imageViewCreateInfo.flags = 0; 5812 imageViewCreateInfo.image = texture->image; 5813 imageViewCreateInfo.format = SDLToVK_TextureFormat[createinfo->format]; 5814 imageViewCreateInfo.components = texture->swizzle; 5815 imageViewCreateInfo.subresourceRange.aspectMask = texture->aspectFlags & ~VK_IMAGE_ASPECT_STENCIL_BIT; // Can't sample stencil values 5816 imageViewCreateInfo.subresourceRange.baseMipLevel = 0; 5817 imageViewCreateInfo.subresourceRange.levelCount = createinfo->num_levels; 5818 imageViewCreateInfo.subresourceRange.baseArrayLayer = 0; 5819 imageViewCreateInfo.subresourceRange.layerCount = layerCount; 5820 5821 if (createinfo->type == SDL_GPU_TEXTURETYPE_CUBE) { 5822 imageViewCreateInfo.viewType = VK_IMAGE_VIEW_TYPE_CUBE; 5823 } else if (createinfo->type == SDL_GPU_TEXTURETYPE_CUBE_ARRAY) { 5824 imageViewCreateInfo.viewType = VK_IMAGE_VIEW_TYPE_CUBE_ARRAY; 5825 } else if (createinfo->type == SDL_GPU_TEXTURETYPE_3D) { 5826 imageViewCreateInfo.viewType = VK_IMAGE_VIEW_TYPE_3D; 5827 } else if (createinfo->type == SDL_GPU_TEXTURETYPE_2D_ARRAY) { 5828 imageViewCreateInfo.viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY; 5829 } else { 5830 imageViewCreateInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; 5831 } 5832 5833 vulkanResult = renderer->vkCreateImageView( 5834 renderer->logicalDevice, 5835 &imageViewCreateInfo, 5836 NULL, 5837 &texture->fullView); 5838 5839 if (vulkanResult != VK_SUCCESS) { 5840 VULKAN_INTERNAL_DestroyTexture(renderer, texture); 5841 CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, "vkCreateImageView", NULL); 5842 } 5843 } 5844 5845 // Define slices 5846 texture->subresourceCount = layerCount * createinfo->num_levels; 5847 texture->subresources = SDL_calloc( 5848 texture->subresourceCount, 5849 sizeof(VulkanTextureSubresource)); 5850 5851 for (Uint32 i = 0; i < layerCount; i += 1) { 5852 for (Uint32 j = 0; j < createinfo->num_levels; j += 1) { 5853 Uint32 subresourceIndex = VULKAN_INTERNAL_GetTextureSubresourceIndex( 5854 j, 5855 i, 5856 createinfo->num_levels); 5857 5858 if (createinfo->usage & SDL_GPU_TEXTUREUSAGE_COLOR_TARGET) { 5859 texture->subresources[subresourceIndex].renderTargetViews = SDL_malloc( 5860 depth * sizeof(VkImageView)); 5861 5862 if (depth > 1) { 5863 for (Uint32 k = 0; k < depth; k += 1) { 5864 if (!VULKAN_INTERNAL_CreateRenderTargetView( 5865 renderer, 5866 texture, 5867 k, 5868 j, 5869 SDLToVK_TextureFormat[createinfo->format], 5870 texture->swizzle, 5871 &texture->subresources[subresourceIndex].renderTargetViews[k])) { 5872 VULKAN_INTERNAL_DestroyTexture(renderer, texture); 5873 return NULL; 5874 } 5875 } 5876 } else { 5877 if (!VULKAN_INTERNAL_CreateRenderTargetView( 5878 renderer, 5879 texture, 5880 i, 5881 j, 5882 SDLToVK_TextureFormat[createinfo->format], 5883 texture->swizzle, 5884 &texture->subresources[subresourceIndex].renderTargetViews[0])) { 5885 VULKAN_INTERNAL_DestroyTexture(renderer, texture); 5886 return NULL; 5887 } 5888 } 5889 } 5890 5891 if ((createinfo->usage & SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_WRITE) || (createinfo->usage & SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_SIMULTANEOUS_READ_WRITE)) { 5892 if (!VULKAN_INTERNAL_CreateSubresourceView( 5893 renderer, 5894 createinfo, 5895 texture, 5896 i, 5897 j, 5898 texture->swizzle, 5899 &texture->subresources[subresourceIndex].computeWriteView)) { 5900 VULKAN_INTERNAL_DestroyTexture(renderer, texture); 5901 return NULL; 5902 } 5903 } 5904 5905 if (createinfo->usage & SDL_GPU_TEXTUREUSAGE_DEPTH_STENCIL_TARGET) { 5906 if (!VULKAN_INTERNAL_CreateSubresourceView( 5907 renderer, 5908 createinfo, 5909 texture, 5910 i, 5911 j, 5912 texture->swizzle, 5913 &texture->subresources[subresourceIndex].depthStencilView)) { 5914 VULKAN_INTERNAL_DestroyTexture(renderer, texture); 5915 return NULL; 5916 } 5917 } 5918 5919 texture->subresources[subresourceIndex].parent = texture; 5920 texture->subresources[subresourceIndex].layer = i; 5921 texture->subresources[subresourceIndex].level = j; 5922 } 5923 } 5924 5925 // Set debug name if applicable 5926 if (renderer->debugMode && renderer->supportsDebugUtils && SDL_HasProperty(createinfo->props, SDL_PROP_GPU_TEXTURE_CREATE_NAME_STRING)) { 5927 VkDebugUtilsObjectNameInfoEXT nameInfo; 5928 nameInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT; 5929 nameInfo.pNext = NULL; 5930 nameInfo.pObjectName = SDL_GetStringProperty(createinfo->props, SDL_PROP_GPU_TEXTURE_CREATE_NAME_STRING, NULL); 5931 nameInfo.objectType = VK_OBJECT_TYPE_IMAGE; 5932 nameInfo.objectHandle = (uint64_t)texture->image; 5933 5934 renderer->vkSetDebugUtilsObjectNameEXT( 5935 renderer->logicalDevice, 5936 &nameInfo); 5937 } 5938 5939 return texture; 5940} 5941 5942static void VULKAN_INTERNAL_CycleActiveBuffer( 5943 VulkanRenderer *renderer, 5944 VulkanBufferContainer *container) 5945{ 5946 VulkanBuffer *buffer; 5947 5948 // If a previously-cycled buffer is available, we can use that. 5949 for (Uint32 i = 0; i < container->bufferCount; i += 1) { 5950 buffer = container->buffers[i]; 5951 if (SDL_GetAtomicInt(&buffer->referenceCount) == 0) { 5952 container->activeBuffer = buffer; 5953 return; 5954 } 5955 } 5956 5957 // No buffer handle is available, create a new one. 5958 buffer = VULKAN_INTERNAL_CreateBuffer( 5959 renderer, 5960 container->activeBuffer->size, 5961 container->activeBuffer->usage, 5962 container->activeBuffer->type, 5963 container->dedicated, 5964 container->debugName); 5965 5966 if (!buffer) { 5967 return; 5968 } 5969 5970 EXPAND_ARRAY_IF_NEEDED( 5971 container->buffers, 5972 VulkanBuffer *, 5973 container->bufferCount + 1, 5974 container->bufferCapacity, 5975 container->bufferCapacity * 2); 5976 5977 container->buffers[container->bufferCount] = buffer; 5978 buffer->container = container; 5979 buffer->containerIndex = container->bufferCount; 5980 container->bufferCount += 1; 5981 5982 container->activeBuffer = buffer; 5983} 5984 5985static void VULKAN_INTERNAL_CycleActiveTexture( 5986 VulkanRenderer *renderer, 5987 VulkanCommandBuffer *commandBuffer, 5988 VulkanTextureContainer *container) 5989{ 5990 VulkanTexture *texture; 5991 5992 // If a previously-cycled texture is available, we can use that. 5993 for (Uint32 i = 0; i < container->textureCount; i += 1) { 5994 texture = container->textures[i]; 5995 5996 if (SDL_GetAtomicInt(&texture->referenceCount) == 0) { 5997 container->activeTexture = texture; 5998 return; 5999 } 6000 } 6001 6002 // No texture is available, generate a new one. 6003 texture = VULKAN_INTERNAL_CreateTexture( 6004 renderer, 6005 &container->header.info); 6006 6007 VULKAN_INTERNAL_TextureTransitionToDefaultUsage( 6008 renderer, 6009 commandBuffer, 6010 VULKAN_TEXTURE_USAGE_MODE_UNINITIALIZED, 6011 texture); 6012 6013 if (!texture) { 6014 return; 6015 } 6016 6017 EXPAND_ARRAY_IF_NEEDED( 6018 container->textures, 6019 VulkanTexture *, 6020 container->textureCount + 1, 6021 container->textureCapacity, 6022 container->textureCapacity * 2); 6023 6024 container->textures[container->textureCount] = texture; 6025 texture->container = container; 6026 texture->containerIndex = container->textureCount; 6027 container->textureCount += 1; 6028 6029 container->activeTexture = texture; 6030} 6031 6032static VulkanBuffer *VULKAN_INTERNAL_PrepareBufferForWrite( 6033 VulkanRenderer *renderer, 6034 VulkanCommandBuffer *commandBuffer, 6035 VulkanBufferContainer *bufferContainer, 6036 bool cycle, 6037 VulkanBufferUsageMode destinationUsageMode) 6038{ 6039 if ( 6040 cycle && 6041 SDL_GetAtomicInt(&bufferContainer->activeBuffer->referenceCount) > 0) { 6042 VULKAN_INTERNAL_CycleActiveBuffer( 6043 renderer, 6044 bufferContainer); 6045 } 6046 6047 VULKAN_INTERNAL_BufferTransitionFromDefaultUsage( 6048 renderer, 6049 commandBuffer, 6050 destinationUsageMode, 6051 bufferContainer->activeBuffer); 6052 6053 return bufferContainer->activeBuffer; 6054} 6055 6056static VulkanTextureSubresource *VULKAN_INTERNAL_PrepareTextureSubresourceForWrite( 6057 VulkanRenderer *renderer, 6058 VulkanCommandBuffer *commandBuffer, 6059 VulkanTextureContainer *textureContainer, 6060 Uint32 layer, 6061 Uint32 level, 6062 bool cycle, 6063 VulkanTextureUsageMode destinationUsageMode) 6064{ 6065 VulkanTextureSubresource *textureSubresource = VULKAN_INTERNAL_FetchTextureSubresource( 6066 textureContainer, 6067 layer, 6068 level); 6069 6070 if ( 6071 cycle && 6072 textureContainer->canBeCycled && 6073 SDL_GetAtomicInt(&textureContainer->activeTexture->referenceCount) > 0) { 6074 VULKAN_INTERNAL_CycleActiveTexture( 6075 renderer, 6076 commandBuffer, 6077 textureContainer); 6078 6079 textureSubresource = VULKAN_INTERNAL_FetchTextureSubresource( 6080 textureContainer, 6081 layer, 6082 level); 6083 } 6084 6085 // always do barrier because of layout transitions 6086 VULKAN_INTERNAL_TextureSubresourceTransitionFromDefaultUsage( 6087 renderer, 6088 commandBuffer, 6089 destinationUsageMode, 6090 textureSubresource); 6091 6092 return textureSubresource; 6093} 6094 6095static VkRenderPass VULKAN_INTERNAL_CreateRenderPass( 6096 VulkanRenderer *renderer, 6097 const SDL_GPUColorTargetInfo *colorTargetInfos, 6098 Uint32 numColorTargets, 6099 const SDL_GPUDepthStencilTargetInfo *depthStencilTargetInfo) 6100{ 6101 VkResult vulkanResult; 6102 VkAttachmentDescription attachmentDescriptions[2 * MAX_COLOR_TARGET_BINDINGS + 1 /* depth */]; 6103 VkAttachmentReference colorAttachmentReferences[MAX_COLOR_TARGET_BINDINGS]; 6104 VkAttachmentReference resolveReferences[MAX_COLOR_TARGET_BINDINGS]; 6105 VkAttachmentReference depthStencilAttachmentReference; 6106 VkRenderPassCreateInfo renderPassCreateInfo; 6107 VkSubpassDescription subpass; 6108 VkRenderPass renderPass; 6109 Uint32 i; 6110 6111 Uint32 attachmentDescriptionCount = 0; 6112 Uint32 colorAttachmentReferenceCount = 0; 6113 Uint32 resolveReferenceCount = 0; 6114 6115 for (i = 0; i < numColorTargets; i += 1) { 6116 VulkanTextureContainer *container = (VulkanTextureContainer *)colorTargetInfos[i].texture; 6117 attachmentDescriptions[attachmentDescriptionCount].flags = 0; 6118 attachmentDescriptions[attachmentDescriptionCount].format = SDLToVK_TextureFormat[container->header.info.format]; 6119 attachmentDescriptions[attachmentDescriptionCount].samples = SDLToVK_SampleCount[container->header.info.sample_count]; 6120 attachmentDescriptions[attachmentDescriptionCount].loadOp = SDLToVK_LoadOp[colorTargetInfos[i].load_op]; 6121 attachmentDescriptions[attachmentDescriptionCount].storeOp = SDLToVK_StoreOp[colorTargetInfos[i].store_op]; 6122 attachmentDescriptions[attachmentDescriptionCount].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; 6123 attachmentDescriptions[attachmentDescriptionCount].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; 6124 attachmentDescriptions[attachmentDescriptionCount].initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; 6125 attachmentDescriptions[attachmentDescriptionCount].finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; 6126 6127 colorAttachmentReferences[colorAttachmentReferenceCount].attachment = attachmentDescriptionCount; 6128 colorAttachmentReferences[colorAttachmentReferenceCount].layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; 6129 6130 attachmentDescriptionCount += 1; 6131 6132 if (colorTargetInfos[i].store_op == SDL_GPU_STOREOP_RESOLVE || colorTargetInfos[i].store_op == SDL_GPU_STOREOP_RESOLVE_AND_STORE) { 6133 VulkanTextureContainer *resolveContainer = (VulkanTextureContainer *)colorTargetInfos[i].resolve_texture; 6134 6135 attachmentDescriptions[attachmentDescriptionCount].flags = 0; 6136 attachmentDescriptions[attachmentDescriptionCount].format = SDLToVK_TextureFormat[resolveContainer->header.info.format]; 6137 attachmentDescriptions[attachmentDescriptionCount].samples = SDLToVK_SampleCount[resolveContainer->header.info.sample_count]; 6138 attachmentDescriptions[attachmentDescriptionCount].loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; // The texture will be overwritten anyway 6139 attachmentDescriptions[attachmentDescriptionCount].storeOp = VK_ATTACHMENT_STORE_OP_STORE; // Always store the resolve texture 6140 attachmentDescriptions[attachmentDescriptionCount].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; 6141 attachmentDescriptions[attachmentDescriptionCount].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; 6142 attachmentDescriptions[attachmentDescriptionCount].initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; 6143 attachmentDescriptions[attachmentDescriptionCount].finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; 6144 6145 resolveReferences[colorAttachmentReferenceCount].attachment = attachmentDescriptionCount; 6146 resolveReferences[colorAttachmentReferenceCount].layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; 6147 6148 attachmentDescriptionCount += 1; 6149 resolveReferenceCount += 1; 6150 } else { 6151 resolveReferences[colorAttachmentReferenceCount].attachment = VK_ATTACHMENT_UNUSED; 6152 } 6153 6154 colorAttachmentReferenceCount += 1; 6155 } 6156 6157 subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; 6158 subpass.flags = 0; 6159 subpass.inputAttachmentCount = 0; 6160 subpass.pInputAttachments = NULL; 6161 subpass.colorAttachmentCount = numColorTargets; 6162 subpass.pColorAttachments = colorAttachmentReferences; 6163 subpass.preserveAttachmentCount = 0; 6164 subpass.pPreserveAttachments = NULL; 6165 6166 if (depthStencilTargetInfo == NULL) { 6167 subpass.pDepthStencilAttachment = NULL; 6168 } else { 6169 VulkanTextureContainer *container = (VulkanTextureContainer *)depthStencilTargetInfo->texture; 6170 6171 attachmentDescriptions[attachmentDescriptionCount].flags = 0; 6172 attachmentDescriptions[attachmentDescriptionCount].format = SDLToVK_TextureFormat[container->header.info.format]; 6173 attachmentDescriptions[attachmentDescriptionCount].samples = SDLToVK_SampleCount[container->header.info.sample_count]; 6174 attachmentDescriptions[attachmentDescriptionCount].loadOp = SDLToVK_LoadOp[depthStencilTargetInfo->load_op]; 6175 attachmentDescriptions[attachmentDescriptionCount].storeOp = SDLToVK_StoreOp[depthStencilTargetInfo->store_op]; 6176 attachmentDescriptions[attachmentDescriptionCount].stencilLoadOp = SDLToVK_LoadOp[depthStencilTargetInfo->stencil_load_op]; 6177 attachmentDescriptions[attachmentDescriptionCount].stencilStoreOp = SDLToVK_StoreOp[depthStencilTargetInfo->stencil_store_op]; 6178 attachmentDescriptions[attachmentDescriptionCount].initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; 6179 attachmentDescriptions[attachmentDescriptionCount].finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; 6180 6181 depthStencilAttachmentReference.attachment = attachmentDescriptionCount; 6182 depthStencilAttachmentReference.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; 6183 6184 subpass.pDepthStencilAttachment = &depthStencilAttachmentReference; 6185 6186 attachmentDescriptionCount += 1; 6187 } 6188 6189 if (resolveReferenceCount > 0) { 6190 subpass.pResolveAttachments = resolveReferences; 6191 } else { 6192 subpass.pResolveAttachments = NULL; 6193 } 6194 6195 renderPassCreateInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; 6196 renderPassCreateInfo.pNext = NULL; 6197 renderPassCreateInfo.flags = 0; 6198 renderPassCreateInfo.pAttachments = attachmentDescriptions; 6199 renderPassCreateInfo.attachmentCount = attachmentDescriptionCount; 6200 renderPassCreateInfo.subpassCount = 1; 6201 renderPassCreateInfo.pSubpasses = &subpass; 6202 renderPassCreateInfo.dependencyCount = 0; 6203 renderPassCreateInfo.pDependencies = NULL; 6204 6205 vulkanResult = renderer->vkCreateRenderPass( 6206 renderer->logicalDevice, 6207 &renderPassCreateInfo, 6208 NULL, 6209 &renderPass); 6210 6211 CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkCreateRenderPass, VK_NULL_HANDLE); 6212 6213 return renderPass; 6214} 6215 6216static VkRenderPass VULKAN_INTERNAL_CreateTransientRenderPass( 6217 VulkanRenderer *renderer, 6218 SDL_GPUGraphicsPipelineTargetInfo targetInfo, 6219 VkSampleCountFlagBits sampleCount) 6220{ 6221 VkAttachmentDescription attachmentDescriptions[MAX_COLOR_TARGET_BINDINGS + 1 /* depth */]; 6222 VkAttachmentReference colorAttachmentReferences[MAX_COLOR_TARGET_BINDINGS]; 6223 VkAttachmentReference depthStencilAttachmentReference; 6224 SDL_GPUColorTargetDescription attachmentDescription; 6225 VkSubpassDescription subpass; 6226 VkRenderPassCreateInfo renderPassCreateInfo; 6227 VkRenderPass renderPass; 6228 VkResult result; 6229 6230 Uint32 attachmentDescriptionCount = 0; 6231 Uint32 colorAttachmentReferenceCount = 0; 6232 Uint32 i; 6233 6234 for (i = 0; i < targetInfo.num_color_targets; i += 1) { 6235 attachmentDescription = targetInfo.color_target_descriptions[i]; 6236 6237 attachmentDescriptions[attachmentDescriptionCount].flags = 0; 6238 attachmentDescriptions[attachmentDescriptionCount].format = SDLToVK_TextureFormat[attachmentDescription.format]; 6239 attachmentDescriptions[attachmentDescriptionCount].samples = sampleCount; 6240 attachmentDescriptions[attachmentDescriptionCount].loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; 6241 attachmentDescriptions[attachmentDescriptionCount].storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; 6242 attachmentDescriptions[attachmentDescriptionCount].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; 6243 attachmentDescriptions[attachmentDescriptionCount].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; 6244 attachmentDescriptions[attachmentDescriptionCount].initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; 6245 attachmentDescriptions[attachmentDescriptionCount].finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; 6246 6247 colorAttachmentReferences[colorAttachmentReferenceCount].attachment = attachmentDescriptionCount; 6248 colorAttachmentReferences[colorAttachmentReferenceCount].layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; 6249 6250 attachmentDescriptionCount += 1; 6251 colorAttachmentReferenceCount += 1; 6252 } 6253 6254 subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; 6255 subpass.flags = 0; 6256 subpass.inputAttachmentCount = 0; 6257 subpass.pInputAttachments = NULL; 6258 subpass.colorAttachmentCount = targetInfo.num_color_targets; 6259 subpass.pColorAttachments = colorAttachmentReferences; 6260 subpass.preserveAttachmentCount = 0; 6261 subpass.pPreserveAttachments = NULL; 6262 6263 if (targetInfo.has_depth_stencil_target) { 6264 attachmentDescriptions[attachmentDescriptionCount].flags = 0; 6265 attachmentDescriptions[attachmentDescriptionCount].format = SDLToVK_TextureFormat[targetInfo.depth_stencil_format]; 6266 attachmentDescriptions[attachmentDescriptionCount].samples = sampleCount; 6267 attachmentDescriptions[attachmentDescriptionCount].loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; 6268 attachmentDescriptions[attachmentDescriptionCount].storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; 6269 attachmentDescriptions[attachmentDescriptionCount].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; 6270 attachmentDescriptions[attachmentDescriptionCount].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; 6271 attachmentDescriptions[attachmentDescriptionCount].initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; 6272 attachmentDescriptions[attachmentDescriptionCount].finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; 6273 6274 depthStencilAttachmentReference.attachment = attachmentDescriptionCount; 6275 depthStencilAttachmentReference.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; 6276 6277 subpass.pDepthStencilAttachment = &depthStencilAttachmentReference; 6278 6279 attachmentDescriptionCount += 1; 6280 } else { 6281 subpass.pDepthStencilAttachment = NULL; 6282 } 6283 6284 // Resolve attachments aren't needed for transient passes 6285 subpass.pResolveAttachments = NULL; 6286 6287 renderPassCreateInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; 6288 renderPassCreateInfo.pNext = NULL; 6289 renderPassCreateInfo.flags = 0; 6290 renderPassCreateInfo.pAttachments = attachmentDescriptions; 6291 renderPassCreateInfo.attachmentCount = attachmentDescriptionCount; 6292 renderPassCreateInfo.subpassCount = 1; 6293 renderPassCreateInfo.pSubpasses = &subpass; 6294 renderPassCreateInfo.dependencyCount = 0; 6295 renderPassCreateInfo.pDependencies = NULL; 6296 6297 result = renderer->vkCreateRenderPass( 6298 renderer->logicalDevice, 6299 &renderPassCreateInfo, 6300 NULL, 6301 &renderPass); 6302 6303 CHECK_VULKAN_ERROR_AND_RETURN(result, vkCreateRenderPass, VK_NULL_HANDLE); 6304 6305 return renderPass; 6306} 6307 6308static SDL_GPUGraphicsPipeline *VULKAN_CreateGraphicsPipeline( 6309 SDL_GPURenderer *driverData, 6310 const SDL_GPUGraphicsPipelineCreateInfo *createinfo) 6311{ 6312 VkResult vulkanResult; 6313 Uint32 i; 6314 6315 VulkanGraphicsPipeline *graphicsPipeline = (VulkanGraphicsPipeline *)SDL_malloc(sizeof(VulkanGraphicsPipeline)); 6316 VkGraphicsPipelineCreateInfo vkPipelineCreateInfo; 6317 6318 VkPipelineShaderStageCreateInfo shaderStageCreateInfos[2]; 6319 6320 VkPipelineVertexInputStateCreateInfo vertexInputStateCreateInfo; 6321 VkVertexInputBindingDescription *vertexInputBindingDescriptions = SDL_stack_alloc(VkVertexInputBindingDescription, createinfo->vertex_input_state.num_vertex_buffers); 6322 VkVertexInputAttributeDescription *vertexInputAttributeDescriptions = SDL_stack_alloc(VkVertexInputAttributeDescription, createinfo->vertex_input_state.num_vertex_attributes); 6323 6324 VkPipelineInputAssemblyStateCreateInfo inputAssemblyStateCreateInfo; 6325 6326 VkPipelineViewportStateCreateInfo viewportStateCreateInfo; 6327 6328 VkPipelineRasterizationStateCreateInfo rasterizationStateCreateInfo; 6329 6330 VkPipelineMultisampleStateCreateInfo multisampleStateCreateInfo; 6331 6332 VkPipelineDepthStencilStateCreateInfo depthStencilStateCreateInfo; 6333 VkStencilOpState frontStencilState; 6334 VkStencilOpState backStencilState; 6335 6336 VkPipelineColorBlendStateCreateInfo colorBlendStateCreateInfo; 6337 VkPipelineColorBlendAttachmentState *colorBlendAttachmentStates = SDL_stack_alloc( 6338 VkPipelineColorBlendAttachmentState, 6339 createinfo->target_info.num_color_targets); 6340 6341 static const VkDynamicState dynamicStates[] = { 6342 VK_DYNAMIC_STATE_VIEWPORT, 6343 VK_DYNAMIC_STATE_SCISSOR, 6344 VK_DYNAMIC_STATE_BLEND_CONSTANTS, 6345 VK_DYNAMIC_STATE_STENCIL_REFERENCE 6346 }; 6347 VkPipelineDynamicStateCreateInfo dynamicStateCreateInfo; 6348 6349 VulkanRenderer *renderer = (VulkanRenderer *)driverData; 6350 6351 // Create a "compatible" render pass 6352 6353 VkRenderPass transientRenderPass = VULKAN_INTERNAL_CreateTransientRenderPass( 6354 renderer, 6355 createinfo->target_info, 6356 SDLToVK_SampleCount[createinfo->multisample_state.sample_count]); 6357 6358 // Dynamic state 6359 6360 dynamicStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; 6361 dynamicStateCreateInfo.pNext = NULL; 6362 dynamicStateCreateInfo.flags = 0; 6363 dynamicStateCreateInfo.dynamicStateCount = SDL_arraysize(dynamicStates); 6364 dynamicStateCreateInfo.pDynamicStates = dynamicStates; 6365 6366 // Shader stages 6367 6368 graphicsPipeline->vertexShader = (VulkanShader *)createinfo->vertex_shader; 6369 SDL_AtomicIncRef(&graphicsPipeline->vertexShader->referenceCount); 6370 6371 shaderStageCreateInfos[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; 6372 shaderStageCreateInfos[0].pNext = NULL; 6373 shaderStageCreateInfos[0].flags = 0; 6374 shaderStageCreateInfos[0].stage = VK_SHADER_STAGE_VERTEX_BIT; 6375 shaderStageCreateInfos[0].module = graphicsPipeline->vertexShader->shaderModule; 6376 shaderStageCreateInfos[0].pName = graphicsPipeline->vertexShader->entrypointName; 6377 shaderStageCreateInfos[0].pSpecializationInfo = NULL; 6378 6379 graphicsPipeline->fragmentShader = (VulkanShader *)createinfo->fragment_shader; 6380 SDL_AtomicIncRef(&graphicsPipeline->fragmentShader->referenceCount); 6381 6382 shaderStageCreateInfos[1].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; 6383 shaderStageCreateInfos[1].pNext = NULL; 6384 shaderStageCreateInfos[1].flags = 0; 6385 shaderStageCreateInfos[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT; 6386 shaderStageCreateInfos[1].module = graphicsPipeline->fragmentShader->shaderModule; 6387 shaderStageCreateInfos[1].pName = graphicsPipeline->fragmentShader->entrypointName; 6388 shaderStageCreateInfos[1].pSpecializationInfo = NULL; 6389 6390 if (renderer->debugMode) { 6391 if (graphicsPipeline->vertexShader->stage != SDL_GPU_SHADERSTAGE_VERTEX) { 6392 SDL_assert_release(!"CreateGraphicsPipeline was passed a fragment shader for the vertex stage"); 6393 } 6394 if (graphicsPipeline->fragmentShader->stage != SDL_GPU_SHADERSTAGE_FRAGMENT) { 6395 SDL_assert_release(!"CreateGraphicsPipeline was passed a vertex shader for the fragment stage"); 6396 } 6397 } 6398 6399 // Vertex input 6400 6401 for (i = 0; i < createinfo->vertex_input_state.num_vertex_buffers; i += 1) { 6402 vertexInputBindingDescriptions[i].binding = createinfo->vertex_input_state.vertex_buffer_descriptions[i].slot; 6403 vertexInputBindingDescriptions[i].inputRate = SDLToVK_VertexInputRate[createinfo->vertex_input_state.vertex_buffer_descriptions[i].input_rate]; 6404 vertexInputBindingDescriptions[i].stride = createinfo->vertex_input_state.vertex_buffer_descriptions[i].pitch; 6405 } 6406 6407 for (i = 0; i < createinfo->vertex_input_state.num_vertex_attributes; i += 1) { 6408 vertexInputAttributeDescriptions[i].binding = createinfo->vertex_input_state.vertex_attributes[i].buffer_slot; 6409 vertexInputAttributeDescriptions[i].format = SDLToVK_VertexFormat[createinfo->vertex_input_state.vertex_attributes[i].format]; 6410 vertexInputAttributeDescriptions[i].location = createinfo->vertex_input_state.vertex_attributes[i].location; 6411 vertexInputAttributeDescriptions[i].offset = createinfo->vertex_input_state.vertex_attributes[i].offset; 6412 } 6413 6414 vertexInputStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; 6415 vertexInputStateCreateInfo.pNext = NULL; 6416 vertexInputStateCreateInfo.flags = 0; 6417 vertexInputStateCreateInfo.vertexBindingDescriptionCount = createinfo->vertex_input_state.num_vertex_buffers; 6418 vertexInputStateCreateInfo.pVertexBindingDescriptions = vertexInputBindingDescriptions; 6419 vertexInputStateCreateInfo.vertexAttributeDescriptionCount = createinfo->vertex_input_state.num_vertex_attributes; 6420 vertexInputStateCreateInfo.pVertexAttributeDescriptions = vertexInputAttributeDescriptions; 6421 6422 // Topology 6423 6424 inputAssemblyStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; 6425 inputAssemblyStateCreateInfo.pNext = NULL; 6426 inputAssemblyStateCreateInfo.flags = 0; 6427 inputAssemblyStateCreateInfo.primitiveRestartEnable = VK_FALSE; 6428 inputAssemblyStateCreateInfo.topology = SDLToVK_PrimitiveType[createinfo->primitive_type]; 6429 6430 graphicsPipeline->primitiveType = createinfo->primitive_type; 6431 6432 // Viewport 6433 6434 // NOTE: viewport and scissor are dynamic, and must be set using the command buffer 6435 6436 viewportStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; 6437 viewportStateCreateInfo.pNext = NULL; 6438 viewportStateCreateInfo.flags = 0; 6439 viewportStateCreateInfo.viewportCount = 1; 6440 viewportStateCreateInfo.pViewports = NULL; 6441 viewportStateCreateInfo.scissorCount = 1; 6442 viewportStateCreateInfo.pScissors = NULL; 6443 6444 // Rasterization 6445 6446 rasterizationStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; 6447 rasterizationStateCreateInfo.pNext = NULL; 6448 rasterizationStateCreateInfo.flags = 0; 6449 rasterizationStateCreateInfo.depthClampEnable = !createinfo->rasterizer_state.enable_depth_clip; 6450 rasterizationStateCreateInfo.rasterizerDiscardEnable = VK_FALSE; 6451 rasterizationStateCreateInfo.polygonMode = SDLToVK_PolygonMode( 6452 renderer, 6453 createinfo->rasterizer_state.fill_mode); 6454 rasterizationStateCreateInfo.cullMode = SDLToVK_CullMode[createinfo->rasterizer_state.cull_mode]; 6455 rasterizationStateCreateInfo.frontFace = SDLToVK_FrontFace[createinfo->rasterizer_state.front_face]; 6456 rasterizationStateCreateInfo.depthBiasEnable = 6457 createinfo->rasterizer_state.enable_depth_bias; 6458 rasterizationStateCreateInfo.depthBiasConstantFactor = 6459 createinfo->rasterizer_state.depth_bias_constant_factor; 6460 rasterizationStateCreateInfo.depthBiasClamp = 6461 createinfo->rasterizer_state.depth_bias_clamp; 6462 rasterizationStateCreateInfo.depthBiasSlopeFactor = 6463 createinfo->rasterizer_state.depth_bias_slope_factor; 6464 rasterizationStateCreateInfo.lineWidth = 1.0f; 6465 6466 // Multisample 6467 6468 Uint32 sampleMask = 0xFFFFFFFF; 6469 6470 multisampleStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; 6471 multisampleStateCreateInfo.pNext = NULL; 6472 multisampleStateCreateInfo.flags = 0; 6473 multisampleStateCreateInfo.rasterizationSamples = SDLToVK_SampleCount[createinfo->multisample_state.sample_count]; 6474 multisampleStateCreateInfo.sampleShadingEnable = VK_FALSE; 6475 multisampleStateCreateInfo.minSampleShading = 1.0f; 6476 multisampleStateCreateInfo.pSampleMask = &sampleMask; 6477 multisampleStateCreateInfo.alphaToCoverageEnable = createinfo->multisample_state.enable_alpha_to_coverage; 6478 multisampleStateCreateInfo.alphaToOneEnable = VK_FALSE; 6479 6480 // Depth Stencil State 6481 6482 frontStencilState.failOp = SDLToVK_StencilOp[createinfo->depth_stencil_state.front_stencil_state.fail_op]; 6483 frontStencilState.passOp = SDLToVK_StencilOp[createinfo->depth_stencil_state.front_stencil_state.pass_op]; 6484 frontStencilState.depthFailOp = SDLToVK_StencilOp[createinfo->depth_stencil_state.front_stencil_state.depth_fail_op]; 6485 frontStencilState.compareOp = SDLToVK_CompareOp[createinfo->depth_stencil_state.front_stencil_state.compare_op]; 6486 frontStencilState.compareMask = 6487 createinfo->depth_stencil_state.compare_mask; 6488 frontStencilState.writeMask = 6489 createinfo->depth_stencil_state.write_mask; 6490 frontStencilState.reference = 0; 6491 6492 backStencilState.failOp = SDLToVK_StencilOp[createinfo->depth_stencil_state.back_stencil_state.fail_op]; 6493 backStencilState.passOp = SDLToVK_StencilOp[createinfo->depth_stencil_state.back_stencil_state.pass_op]; 6494 backStencilState.depthFailOp = SDLToVK_StencilOp[createinfo->depth_stencil_state.back_stencil_state.depth_fail_op]; 6495 backStencilState.compareOp = SDLToVK_CompareOp[createinfo->depth_stencil_state.back_stencil_state.compare_op]; 6496 backStencilState.compareMask = 6497 createinfo->depth_stencil_state.compare_mask; 6498 backStencilState.writeMask = 6499 createinfo->depth_stencil_state.write_mask; 6500 backStencilState.reference = 0; 6501 6502 depthStencilStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; 6503 depthStencilStateCreateInfo.pNext = NULL; 6504 depthStencilStateCreateInfo.flags = 0; 6505 depthStencilStateCreateInfo.depthTestEnable = 6506 createinfo->depth_stencil_state.enable_depth_test; 6507 depthStencilStateCreateInfo.depthWriteEnable = 6508 createinfo->depth_stencil_state.enable_depth_write; 6509 depthStencilStateCreateInfo.depthCompareOp = SDLToVK_CompareOp[createinfo->depth_stencil_state.compare_op]; 6510 depthStencilStateCreateInfo.depthBoundsTestEnable = VK_FALSE; 6511 depthStencilStateCreateInfo.stencilTestEnable = 6512 createinfo->depth_stencil_state.enable_stencil_test; 6513 depthStencilStateCreateInfo.front = frontStencilState; 6514 depthStencilStateCreateInfo.back = backStencilState; 6515 depthStencilStateCreateInfo.minDepthBounds = 0; // unused 6516 depthStencilStateCreateInfo.maxDepthBounds = 0; // unused 6517 6518 // Color Blend 6519 6520 for (i = 0; i < createinfo->target_info.num_color_targets; i += 1) { 6521 SDL_GPUColorTargetBlendState blendState = createinfo->target_info.color_target_descriptions[i].blend_state; 6522 SDL_GPUColorComponentFlags colorWriteMask = blendState.enable_color_write_mask ? 6523 blendState.color_write_mask : 6524 0xF; 6525 6526 colorBlendAttachmentStates[i].blendEnable = 6527 blendState.enable_blend; 6528 colorBlendAttachmentStates[i].srcColorBlendFactor = SDLToVK_BlendFactor[blendState.src_color_blendfactor]; 6529 colorBlendAttachmentStates[i].dstColorBlendFactor = SDLToVK_BlendFactor[blendState.dst_color_blendfactor]; 6530 colorBlendAttachmentStates[i].colorBlendOp = SDLToVK_BlendOp[blendState.color_blend_op]; 6531 colorBlendAttachmentStates[i].srcAlphaBlendFactor = SDLToVK_BlendFactor[blendState.src_alpha_blendfactor]; 6532 colorBlendAttachmentStates[i].dstAlphaBlendFactor = SDLToVK_BlendFactor[blendState.dst_alpha_blendfactor]; 6533 colorBlendAttachmentStates[i].alphaBlendOp = SDLToVK_BlendOp[blendState.alpha_blend_op]; 6534 colorBlendAttachmentStates[i].colorWriteMask = 6535 colorWriteMask; 6536 } 6537 6538 colorBlendStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; 6539 colorBlendStateCreateInfo.pNext = NULL; 6540 colorBlendStateCreateInfo.flags = 0; 6541 colorBlendStateCreateInfo.attachmentCount = 6542 createinfo->target_info.num_color_targets; 6543 colorBlendStateCreateInfo.pAttachments = 6544 colorBlendAttachmentStates; 6545 colorBlendStateCreateInfo.blendConstants[0] = 1.0f; 6546 colorBlendStateCreateInfo.blendConstants[1] = 1.0f; 6547 colorBlendStateCreateInfo.blendConstants[2] = 1.0f; 6548 colorBlendStateCreateInfo.blendConstants[3] = 1.0f; 6549 6550 // We don't support LogicOp, so this is easy. 6551 colorBlendStateCreateInfo.logicOpEnable = VK_FALSE; 6552 colorBlendStateCreateInfo.logicOp = 0; 6553 6554 // Pipeline Layout 6555 6556 graphicsPipeline->resourceLayout = 6557 VULKAN_INTERNAL_FetchGraphicsPipelineResourceLayout( 6558 renderer, 6559 graphicsPipeline->vertexShader, 6560 graphicsPipeline->fragmentShader); 6561 6562 if (graphicsPipeline->resourceLayout == NULL) { 6563 SDL_stack_free(vertexInputBindingDescriptions); 6564 SDL_stack_free(vertexInputAttributeDescriptions); 6565 SDL_stack_free(colorBlendAttachmentStates); 6566 SDL_free(graphicsPipeline); 6567 SET_STRING_ERROR_AND_RETURN("Failed to initialize pipeline resource layout!", NULL); 6568 } 6569 6570 // Pipeline 6571 6572 vkPipelineCreateInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; 6573 vkPipelineCreateInfo.pNext = NULL; 6574 vkPipelineCreateInfo.flags = 0; 6575 vkPipelineCreateInfo.stageCount = 2; 6576 vkPipelineCreateInfo.pStages = shaderStageCreateInfos; 6577 vkPipelineCreateInfo.pVertexInputState = &vertexInputStateCreateInfo; 6578 vkPipelineCreateInfo.pInputAssemblyState = &inputAssemblyStateCreateInfo; 6579 vkPipelineCreateInfo.pTessellationState = VK_NULL_HANDLE; 6580 vkPipelineCreateInfo.pViewportState = &viewportStateCreateInfo; 6581 vkPipelineCreateInfo.pRasterizationState = &rasterizationStateCreateInfo; 6582 vkPipelineCreateInfo.pMultisampleState = &multisampleStateCreateInfo; 6583 vkPipelineCreateInfo.pDepthStencilState = &depthStencilStateCreateInfo; 6584 vkPipelineCreateInfo.pColorBlendState = &colorBlendStateCreateInfo; 6585 vkPipelineCreateInfo.pDynamicState = &dynamicStateCreateInfo; 6586 vkPipelineCreateInfo.layout = graphicsPipeline->resourceLayout->pipelineLayout; 6587 vkPipelineCreateInfo.renderPass = transientRenderPass; 6588 vkPipelineCreateInfo.subpass = 0; 6589 vkPipelineCreateInfo.basePipelineHandle = VK_NULL_HANDLE; 6590 vkPipelineCreateInfo.basePipelineIndex = 0; 6591 6592 // TODO: enable pipeline caching 6593 vulkanResult = renderer->vkCreateGraphicsPipelines( 6594 renderer->logicalDevice, 6595 VK_NULL_HANDLE, 6596 1, 6597 &vkPipelineCreateInfo, 6598 NULL, 6599 &graphicsPipeline->pipeline); 6600 6601 SDL_stack_free(vertexInputBindingDescriptions); 6602 SDL_stack_free(vertexInputAttributeDescriptions); 6603 SDL_stack_free(colorBlendAttachmentStates); 6604 6605 renderer->vkDestroyRenderPass( 6606 renderer->logicalDevice, 6607 transientRenderPass, 6608 NULL); 6609 6610 if (vulkanResult != VK_SUCCESS) { 6611 SDL_free(graphicsPipeline); 6612 CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkCreateGraphicsPipelines, NULL); 6613 } 6614 6615 SDL_SetAtomicInt(&graphicsPipeline->referenceCount, 0); 6616 6617 if (renderer->debugMode && renderer->supportsDebugUtils && SDL_HasProperty(createinfo->props, SDL_PROP_GPU_GRAPHICSPIPELINE_CREATE_NAME_STRING)) { 6618 VkDebugUtilsObjectNameInfoEXT nameInfo; 6619 nameInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT; 6620 nameInfo.pNext = NULL; 6621 nameInfo.pObjectName = SDL_GetStringProperty(createinfo->props, SDL_PROP_GPU_GRAPHICSPIPELINE_CREATE_NAME_STRING, NULL); 6622 nameInfo.objectType = VK_OBJECT_TYPE_PIPELINE; 6623 nameInfo.objectHandle = (uint64_t)graphicsPipeline->pipeline; 6624 6625 renderer->vkSetDebugUtilsObjectNameEXT( 6626 renderer->logicalDevice, 6627 &nameInfo); 6628 } 6629 6630 // Put this data in the pipeline we can do validation in gpu.c 6631 graphicsPipeline->header.num_vertex_samplers = graphicsPipeline->resourceLayout->vertexSamplerCount; 6632 graphicsPipeline->header.num_vertex_storage_buffers = graphicsPipeline->resourceLayout->vertexStorageBufferCount; 6633 graphicsPipeline->header.num_vertex_storage_textures = graphicsPipeline->resourceLayout->vertexStorageTextureCount; 6634 graphicsPipeline->header.num_vertex_uniform_buffers = graphicsPipeline->resourceLayout->vertexUniformBufferCount; 6635 graphicsPipeline->header.num_fragment_samplers = graphicsPipeline->resourceLayout->fragmentSamplerCount; 6636 graphicsPipeline->header.num_fragment_storage_buffers = graphicsPipeline->resourceLayout->fragmentStorageBufferCount; 6637 graphicsPipeline->header.num_fragment_storage_textures = graphicsPipeline->resourceLayout->fragmentStorageTextureCount; 6638 graphicsPipeline->header.num_fragment_uniform_buffers = graphicsPipeline->resourceLayout->fragmentUniformBufferCount; 6639 6640 return (SDL_GPUGraphicsPipeline *)graphicsPipeline; 6641} 6642 6643static bool VULKAN_INTERNAL_IsValidShaderBytecode( 6644 const Uint8 *code, 6645 size_t codeSize) 6646{ 6647 // SPIR-V bytecode has a 4 byte header containing 0x07230203. SPIR-V is 6648 // defined as a stream of words and not a stream of bytes so both byte 6649 // orders need to be considered. 6650 // 6651 // FIXME: It is uncertain if drivers are able to load both byte orders. If 6652 // needed we may need to do an optional swizzle internally so apps can 6653 // continue to treat shader code as an opaque blob. 6654 if (codeSize < 4 || code == NULL) { 6655 return false; 6656 } 6657 const Uint32 magic = 0x07230203; 6658 const Uint32 magicInv = 0x03022307; 6659 return SDL_memcmp(code, &magic, 4) == 0 || SDL_memcmp(code, &magicInv, 4) == 0; 6660} 6661 6662static SDL_GPUComputePipeline *VULKAN_CreateComputePipeline( 6663 SDL_GPURenderer *driverData, 6664 const SDL_GPUComputePipelineCreateInfo *createinfo) 6665{ 6666 VkShaderModuleCreateInfo shaderModuleCreateInfo; 6667 VkComputePipelineCreateInfo vkShaderCreateInfo; 6668 VkPipelineShaderStageCreateInfo pipelineShaderStageCreateInfo; 6669 VkResult vulkanResult; 6670 VulkanRenderer *renderer = (VulkanRenderer *)driverData; 6671 VulkanComputePipeline *vulkanComputePipeline; 6672 6673 if (createinfo->format != SDL_GPU_SHADERFORMAT_SPIRV) { 6674 SET_STRING_ERROR_AND_RETURN("Incompatible shader format for Vulkan!", NULL); 6675 } 6676 6677 if (!VULKAN_INTERNAL_IsValidShaderBytecode(createinfo->code, createinfo->code_size)) { 6678 SET_STRING_ERROR_AND_RETURN("The provided shader code is not valid SPIR-V!", NULL); 6679 } 6680 6681 vulkanComputePipeline = SDL_malloc(sizeof(VulkanComputePipeline)); 6682 shaderModuleCreateInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; 6683 shaderModuleCreateInfo.pNext = NULL; 6684 shaderModuleCreateInfo.flags = 0; 6685 shaderModuleCreateInfo.codeSize = createinfo->code_size; 6686 shaderModuleCreateInfo.pCode = (Uint32 *)createinfo->code; 6687 6688 vulkanResult = renderer->vkCreateShaderModule( 6689 renderer->logicalDevice, 6690 &shaderModuleCreateInfo, 6691 NULL, 6692 &vulkanComputePipeline->shaderModule); 6693 6694 if (vulkanResult != VK_SUCCESS) { 6695 SDL_free(vulkanComputePipeline); 6696 CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkCreateShaderModule, NULL); 6697 } 6698 6699 pipelineShaderStageCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; 6700 pipelineShaderStageCreateInfo.pNext = NULL; 6701 pipelineShaderStageCreateInfo.flags = 0; 6702 pipelineShaderStageCreateInfo.stage = VK_SHADER_STAGE_COMPUTE_BIT; 6703 pipelineShaderStageCreateInfo.module = vulkanComputePipeline->shaderModule; 6704 pipelineShaderStageCreateInfo.pName = createinfo->entrypoint; 6705 pipelineShaderStageCreateInfo.pSpecializationInfo = NULL; 6706 6707 vulkanComputePipeline->resourceLayout = VULKAN_INTERNAL_FetchComputePipelineResourceLayout( 6708 renderer, 6709 createinfo); 6710 6711 if (vulkanComputePipeline->resourceLayout == NULL) { 6712 renderer->vkDestroyShaderModule( 6713 renderer->logicalDevice, 6714 vulkanComputePipeline->shaderModule, 6715 NULL); 6716 SDL_free(vulkanComputePipeline); 6717 return NULL; 6718 } 6719 6720 vkShaderCreateInfo.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO; 6721 vkShaderCreateInfo.pNext = NULL; 6722 vkShaderCreateInfo.flags = 0; 6723 vkShaderCreateInfo.stage = pipelineShaderStageCreateInfo; 6724 vkShaderCreateInfo.layout = vulkanComputePipeline->resourceLayout->pipelineLayout; 6725 vkShaderCreateInfo.basePipelineHandle = (VkPipeline)VK_NULL_HANDLE; 6726 vkShaderCreateInfo.basePipelineIndex = 0; 6727 6728 vulkanResult = renderer->vkCreateComputePipelines( 6729 renderer->logicalDevice, 6730 (VkPipelineCache)VK_NULL_HANDLE, 6731 1, 6732 &vkShaderCreateInfo, 6733 NULL, 6734 &vulkanComputePipeline->pipeline); 6735 6736 if (vulkanResult != VK_SUCCESS) { 6737 VULKAN_INTERNAL_DestroyComputePipeline(renderer, vulkanComputePipeline); 6738 CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkCreateComputePipeline, NULL); 6739 return NULL; 6740 } 6741 6742 SDL_SetAtomicInt(&vulkanComputePipeline->referenceCount, 0); 6743 6744 if (renderer->debugMode && renderer->supportsDebugUtils && SDL_HasProperty(createinfo->props, SDL_PROP_GPU_COMPUTEPIPELINE_CREATE_NAME_STRING)) { 6745 VkDebugUtilsObjectNameInfoEXT nameInfo; 6746 nameInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT; 6747 nameInfo.pNext = NULL; 6748 nameInfo.pObjectName = SDL_GetStringProperty(createinfo->props, SDL_PROP_GPU_COMPUTEPIPELINE_CREATE_NAME_STRING, NULL); 6749 nameInfo.objectType = VK_OBJECT_TYPE_PIPELINE; 6750 nameInfo.objectHandle = (uint64_t)vulkanComputePipeline->pipeline; 6751 6752 renderer->vkSetDebugUtilsObjectNameEXT( 6753 renderer->logicalDevice, 6754 &nameInfo); 6755 } 6756 6757 // Track these here for debug layer 6758 vulkanComputePipeline->header.numSamplers = vulkanComputePipeline->resourceLayout->numSamplers; 6759 vulkanComputePipeline->header.numReadonlyStorageTextures = vulkanComputePipeline->resourceLayout->numReadonlyStorageTextures; 6760 vulkanComputePipeline->header.numReadonlyStorageBuffers = vulkanComputePipeline->resourceLayout->numReadonlyStorageBuffers; 6761 vulkanComputePipeline->header.numReadWriteStorageTextures = vulkanComputePipeline->resourceLayout->numReadWriteStorageTextures; 6762 vulkanComputePipeline->header.numReadWriteStorageBuffers = vulkanComputePipeline->resourceLayout->numReadWriteStorageBuffers; 6763 vulkanComputePipeline->header.numUniformBuffers = vulkanComputePipeline->resourceLayout->numUniformBuffers; 6764 6765 return (SDL_GPUComputePipeline *)vulkanComputePipeline; 6766} 6767 6768static SDL_GPUSampler *VULKAN_CreateSampler( 6769 SDL_GPURenderer *driverData, 6770 const SDL_GPUSamplerCreateInfo *createinfo) 6771{ 6772 VulkanRenderer *renderer = (VulkanRenderer *)driverData; 6773 VulkanSampler *vulkanSampler = SDL_malloc(sizeof(VulkanSampler)); 6774 VkResult vulkanResult; 6775 6776 VkSamplerCreateInfo vkSamplerCreateInfo; 6777 vkSamplerCreateInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; 6778 vkSamplerCreateInfo.pNext = NULL; 6779 vkSamplerCreateInfo.flags = 0; 6780 vkSamplerCreateInfo.magFilter = SDLToVK_Filter[createinfo->mag_filter]; 6781 vkSamplerCreateInfo.minFilter = SDLToVK_Filter[createinfo->min_filter]; 6782 vkSamplerCreateInfo.mipmapMode = SDLToVK_SamplerMipmapMode[createinfo->mipmap_mode]; 6783 vkSamplerCreateInfo.addressModeU = SDLToVK_SamplerAddressMode[createinfo->address_mode_u]; 6784 vkSamplerCreateInfo.addressModeV = SDLToVK_SamplerAddressMode[createinfo->address_mode_v]; 6785 vkSamplerCreateInfo.addressModeW = SDLToVK_SamplerAddressMode[createinfo->address_mode_w]; 6786 vkSamplerCreateInfo.mipLodBias = createinfo->mip_lod_bias; 6787 vkSamplerCreateInfo.anisotropyEnable = createinfo->enable_anisotropy; 6788 vkSamplerCreateInfo.maxAnisotropy = createinfo->max_anisotropy; 6789 vkSamplerCreateInfo.compareEnable = createinfo->enable_compare; 6790 vkSamplerCreateInfo.compareOp = SDLToVK_CompareOp[createinfo->compare_op]; 6791 vkSamplerCreateInfo.minLod = createinfo->min_lod; 6792 vkSamplerCreateInfo.maxLod = createinfo->max_lod; 6793 vkSamplerCreateInfo.borderColor = VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK; // arbitrary, unused 6794 vkSamplerCreateInfo.unnormalizedCoordinates = VK_FALSE; 6795 6796 vulkanResult = renderer->vkCreateSampler( 6797 renderer->logicalDevice, 6798 &vkSamplerCreateInfo, 6799 NULL, 6800 &vulkanSampler->sampler); 6801 6802 if (vulkanResult != VK_SUCCESS) { 6803 SDL_free(vulkanSampler); 6804 CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkCreateSampler, NULL); 6805 } 6806 6807 SDL_SetAtomicInt(&vulkanSampler->referenceCount, 0); 6808 6809 if (renderer->debugMode && renderer->supportsDebugUtils && SDL_HasProperty(createinfo->props, SDL_PROP_GPU_SAMPLER_CREATE_NAME_STRING)) { 6810 VkDebugUtilsObjectNameInfoEXT nameInfo; 6811 nameInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT; 6812 nameInfo.pNext = NULL; 6813 nameInfo.pObjectName = SDL_GetStringProperty(createinfo->props, SDL_PROP_GPU_SAMPLER_CREATE_NAME_STRING, NULL); 6814 nameInfo.objectType = VK_OBJECT_TYPE_SAMPLER; 6815 nameInfo.objectHandle = (uint64_t)vulkanSampler->sampler; 6816 6817 renderer->vkSetDebugUtilsObjectNameEXT( 6818 renderer->logicalDevice, 6819 &nameInfo); 6820 } 6821 6822 return (SDL_GPUSampler *)vulkanSampler; 6823} 6824 6825static SDL_GPUShader *VULKAN_CreateShader( 6826 SDL_GPURenderer *driverData, 6827 const SDL_GPUShaderCreateInfo *createinfo) 6828{ 6829 VulkanShader *vulkanShader; 6830 VkResult vulkanResult; 6831 VkShaderModuleCreateInfo vkShaderModuleCreateInfo; 6832 VulkanRenderer *renderer = (VulkanRenderer *)driverData; 6833 6834 if (!VULKAN_INTERNAL_IsValidShaderBytecode(createinfo->code, createinfo->code_size)) { 6835 SET_STRING_ERROR_AND_RETURN("The provided shader code is not valid SPIR-V!", NULL); 6836 } 6837 6838 vulkanShader = SDL_malloc(sizeof(VulkanShader)); 6839 vkShaderModuleCreateInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; 6840 vkShaderModuleCreateInfo.pNext = NULL; 6841 vkShaderModuleCreateInfo.flags = 0; 6842 vkShaderModuleCreateInfo.codeSize = createinfo->code_size; 6843 vkShaderModuleCreateInfo.pCode = (Uint32 *)createinfo->code; 6844 6845 vulkanResult = renderer->vkCreateShaderModule( 6846 renderer->logicalDevice, 6847 &vkShaderModuleCreateInfo, 6848 NULL, 6849 &vulkanShader->shaderModule); 6850 6851 if (vulkanResult != VK_SUCCESS) { 6852 SDL_free(vulkanShader); 6853 CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkCreateShaderModule, NULL); 6854 } 6855 6856 const char *entrypoint = createinfo->entrypoint; 6857 if (!entrypoint) { 6858 entrypoint = "main"; 6859 } 6860 vulkanShader->entrypointName = SDL_strdup(entrypoint); 6861 vulkanShader->stage = createinfo->stage; 6862 vulkanShader->numSamplers = createinfo->num_samplers; 6863 vulkanShader->numStorageTextures = createinfo->num_storage_textures; 6864 vulkanShader->numStorageBuffers = createinfo->num_storage_buffers; 6865 vulkanShader->numUniformBuffers = createinfo->num_uniform_buffers; 6866 6867 SDL_SetAtomicInt(&vulkanShader->referenceCount, 0); 6868 6869 if (renderer->debugMode && SDL_HasProperty(createinfo->props, SDL_PROP_GPU_SHADER_CREATE_NAME_STRING)) { 6870 VkDebugUtilsObjectNameInfoEXT nameInfo; 6871 nameInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT; 6872 nameInfo.pNext = NULL; 6873 nameInfo.pObjectName = SDL_GetStringProperty(createinfo->props, SDL_PROP_GPU_SHADER_CREATE_NAME_STRING, NULL); 6874 nameInfo.objectType = VK_OBJECT_TYPE_SHADER_MODULE; 6875 nameInfo.objectHandle = (uint64_t)vulkanShader->shaderModule; 6876 6877 renderer->vkSetDebugUtilsObjectNameEXT( 6878 renderer->logicalDevice, 6879 &nameInfo); 6880 } 6881 6882 return (SDL_GPUShader *)vulkanShader; 6883} 6884 6885static bool VULKAN_SupportsSampleCount( 6886 SDL_GPURenderer *driverData, 6887 SDL_GPUTextureFormat format, 6888 SDL_GPUSampleCount sampleCount) 6889{ 6890 VulkanRenderer *renderer = (VulkanRenderer *)driverData; 6891 VkSampleCountFlags bits = IsDepthFormat(format) ? renderer->physicalDeviceProperties.properties.limits.framebufferDepthSampleCounts : renderer->physicalDeviceProperties.properties.limits.framebufferColorSampleCounts; 6892 VkSampleCountFlagBits vkSampleCount = SDLToVK_SampleCount[sampleCount]; 6893 return !!(bits & vkSampleCount); 6894} 6895 6896static SDL_GPUTexture *VULKAN_CreateTexture( 6897 SDL_GPURenderer *driverData, 6898 const SDL_GPUTextureCreateInfo *createinfo) 6899{ 6900 VulkanRenderer *renderer = (VulkanRenderer *)driverData; 6901 VulkanTexture *texture; 6902 VulkanTextureContainer *container; 6903 6904 texture = VULKAN_INTERNAL_CreateTexture( 6905 renderer, 6906 createinfo); 6907 6908 if (texture == NULL) { 6909 return NULL; 6910 } 6911 6912 container = SDL_malloc(sizeof(VulkanTextureContainer)); 6913 6914 // Copy properties so we don't lose information when the client destroys them 6915 container->header.info = *createinfo; 6916 container->header.info.props = SDL_CreateProperties(); 6917 if (createinfo->props) { 6918 SDL_CopyProperties(createinfo->props, container->header.info.props); 6919 } 6920 6921 container->canBeCycled = true; 6922 container->activeTexture = texture; 6923 container->textureCapacity = 1; 6924 container->textureCount = 1; 6925 container->textures = SDL_malloc( 6926 container->textureCapacity * sizeof(VulkanTexture *)); 6927 container->textures[0] = container->activeTexture; 6928 container->debugName = NULL; 6929 6930 if (SDL_HasProperty(createinfo->props, SDL_PROP_GPU_TEXTURE_CREATE_NAME_STRING)) { 6931 container->debugName = SDL_strdup(SDL_GetStringProperty(createinfo->props, SDL_PROP_GPU_TEXTURE_CREATE_NAME_STRING, NULL)); 6932 } 6933 6934 texture->container = container; 6935 texture->containerIndex = 0; 6936 6937 // Let's transition to the default barrier state, because for some reason Vulkan doesn't let us do that with initialLayout. 6938 // Only do this after "container" is set, so the texture 6939 // is fully initialized before any Submit that could trigger defrag. 6940 { 6941 VulkanCommandBuffer *barrierCommandBuffer = (VulkanCommandBuffer *)VULKAN_AcquireCommandBuffer((SDL_GPURenderer *)renderer); 6942 VULKAN_INTERNAL_TextureTransitionToDefaultUsage( 6943 renderer, 6944 barrierCommandBuffer, 6945 VULKAN_TEXTURE_USAGE_MODE_UNINITIALIZED, 6946 texture); 6947 VULKAN_INTERNAL_TrackTexture(barrierCommandBuffer, texture); 6948 if (!VULKAN_Submit((SDL_GPUCommandBuffer *)barrierCommandBuffer)) { 6949 VULKAN_ReleaseTexture((SDL_GPURenderer *)renderer, (SDL_GPUTexture *)container); 6950 return NULL; 6951 } 6952 } 6953 6954 return (SDL_GPUTexture *)container; 6955} 6956 6957static SDL_GPUBuffer *VULKAN_CreateBuffer( 6958 SDL_GPURenderer *driverData, 6959 SDL_GPUBufferUsageFlags usageFlags, 6960 Uint32 size, 6961 const char *debugName) 6962{ 6963 return (SDL_GPUBuffer *)VULKAN_INTERNAL_CreateBufferContainer( 6964 (VulkanRenderer *)driverData, 6965 (VkDeviceSize)size, 6966 usageFlags, 6967 VULKAN_BUFFER_TYPE_GPU, 6968 false, 6969 debugName); 6970} 6971 6972static VulkanUniformBuffer *VULKAN_INTERNAL_CreateUniformBuffer( 6973 VulkanRenderer *renderer, 6974 Uint32 size) 6975{ 6976 VulkanUniformBuffer *uniformBuffer = SDL_calloc(1, sizeof(VulkanUniformBuffer)); 6977 6978 uniformBuffer->buffer = VULKAN_INTERNAL_CreateBuffer( 6979 renderer, 6980 (VkDeviceSize)size, 6981 0, 6982 VULKAN_BUFFER_TYPE_UNIFORM, 6983 false, 6984 NULL); 6985 6986 uniformBuffer->drawOffset = 0; 6987 uniformBuffer->writeOffset = 0; 6988 uniformBuffer->buffer->uniformBufferForDefrag = uniformBuffer; 6989 6990 return uniformBuffer; 6991} 6992 6993static SDL_GPUTransferBuffer *VULKAN_CreateTransferBuffer( 6994 SDL_GPURenderer *driverData, 6995 SDL_GPUTransferBufferUsage usage, 6996 Uint32 size, 6997 const char *debugName) 6998{ 6999 return (SDL_GPUTransferBuffer *)VULKAN_INTERNAL_CreateBufferContainer( 7000 (VulkanRenderer *)driverData, 7001 (VkDeviceSize)size, 7002 0, 7003 VULKAN_BUFFER_TYPE_TRANSFER, 7004 true, // Dedicated allocations preserve the data even if a defrag is triggered. 7005 debugName); 7006} 7007 7008static void VULKAN_INTERNAL_ReleaseTexture( 7009 VulkanRenderer *renderer, 7010 VulkanTexture *vulkanTexture) 7011{ 7012 if (vulkanTexture->markedForDestroy) { 7013 return; 7014 } 7015 7016 SDL_LockMutex(renderer->disposeLock); 7017 7018 EXPAND_ARRAY_IF_NEEDED( 7019 renderer->texturesToDestroy, 7020 VulkanTexture *, 7021 renderer->texturesToDestroyCount + 1, 7022 renderer->texturesToDestroyCapacity, 7023 renderer->texturesToDestroyCapacity * 2); 7024 7025 renderer->texturesToDestroy[renderer->texturesToDestroyCount] = vulkanTexture; 7026 renderer->texturesToDestroyCount += 1; 7027 7028 vulkanTexture->markedForDestroy = true; 7029 7030 SDL_UnlockMutex(renderer->disposeLock); 7031} 7032 7033static void VULKAN_ReleaseTexture( 7034 SDL_GPURenderer *driverData, 7035 SDL_GPUTexture *texture) 7036{ 7037 VulkanRenderer *renderer = (VulkanRenderer *)driverData; 7038 VulkanTextureContainer *vulkanTextureContainer = (VulkanTextureContainer *)texture; 7039 Uint32 i; 7040 7041 SDL_LockMutex(renderer->disposeLock); 7042 7043 for (i = 0; i < vulkanTextureContainer->textureCount; i += 1) { 7044 VULKAN_INTERNAL_ReleaseTexture(renderer, vulkanTextureContainer->textures[i]); 7045 } 7046 7047 SDL_DestroyProperties(vulkanTextureContainer->header.info.props); 7048 7049 // Containers are just client handles, so we can destroy immediately 7050 SDL_free(vulkanTextureContainer->debugName); 7051 SDL_free(vulkanTextureContainer->textures); 7052 SDL_free(vulkanTextureContainer); 7053 7054 SDL_UnlockMutex(renderer->disposeLock); 7055} 7056 7057static void VULKAN_ReleaseSampler( 7058 SDL_GPURenderer *driverData, 7059 SDL_GPUSampler *sampler) 7060{ 7061 VulkanRenderer *renderer = (VulkanRenderer *)driverData; 7062 VulkanSampler *vulkanSampler = (VulkanSampler *)sampler; 7063 7064 SDL_LockMutex(renderer->disposeLock); 7065 7066 EXPAND_ARRAY_IF_NEEDED( 7067 renderer->samplersToDestroy, 7068 VulkanSampler *, 7069 renderer->samplersToDestroyCount + 1, 7070 renderer->samplersToDestroyCapacity, 7071 renderer->samplersToDestroyCapacity * 2); 7072 7073 renderer->samplersToDestroy[renderer->samplersToDestroyCount] = vulkanSampler; 7074 renderer->samplersToDestroyCount += 1; 7075 7076 SDL_UnlockMutex(renderer->disposeLock); 7077} 7078 7079static void VULKAN_INTERNAL_ReleaseBuffer( 7080 VulkanRenderer *renderer, 7081 VulkanBuffer *vulkanBuffer) 7082{ 7083 if (vulkanBuffer->markedForDestroy) { 7084 return; 7085 } 7086 7087 SDL_LockMutex(renderer->disposeLock); 7088 7089 EXPAND_ARRAY_IF_NEEDED( 7090 renderer->buffersToDestroy, 7091 VulkanBuffer *, 7092 renderer->buffersToDestroyCount + 1, 7093 renderer->buffersToDestroyCapacity, 7094 renderer->buffersToDestroyCapacity * 2); 7095 7096 renderer->buffersToDestroy[renderer->buffersToDestroyCount] = vulkanBuffer; 7097 renderer->buffersToDestroyCount += 1; 7098 7099 vulkanBuffer->markedForDestroy = true; 7100 vulkanBuffer->container = NULL; 7101 7102 SDL_UnlockMutex(renderer->disposeLock); 7103} 7104 7105static void VULKAN_INTERNAL_ReleaseBufferContainer( 7106 VulkanRenderer *renderer, 7107 VulkanBufferContainer *bufferContainer) 7108{ 7109 Uint32 i; 7110 7111 SDL_LockMutex(renderer->disposeLock); 7112 7113 for (i = 0; i < bufferContainer->bufferCount; i += 1) { 7114 VULKAN_INTERNAL_ReleaseBuffer(renderer, bufferContainer->buffers[i]); 7115 } 7116 7117 // Containers are just client handles, so we can free immediately 7118 if (bufferContainer->debugName != NULL) { 7119 SDL_free(bufferContainer->debugName); 7120 bufferContainer->debugName = NULL; 7121 } 7122 SDL_free(bufferContainer->buffers); 7123 SDL_free(bufferContainer); 7124 7125 SDL_UnlockMutex(renderer->disposeLock); 7126} 7127 7128static void VULKAN_ReleaseBuffer( 7129 SDL_GPURenderer *driverData, 7130 SDL_GPUBuffer *buffer) 7131{ 7132 VulkanRenderer *renderer = (VulkanRenderer *)driverData; 7133 VulkanBufferContainer *vulkanBufferContainer = (VulkanBufferContainer *)buffer; 7134 7135 VULKAN_INTERNAL_ReleaseBufferContainer( 7136 renderer, 7137 vulkanBufferContainer); 7138} 7139 7140static void VULKAN_ReleaseTransferBuffer( 7141 SDL_GPURenderer *driverData, 7142 SDL_GPUTransferBuffer *transferBuffer) 7143{ 7144 VulkanRenderer *renderer = (VulkanRenderer *)driverData; 7145 VulkanBufferContainer *transferBufferContainer = (VulkanBufferContainer *)transferBuffer; 7146 7147 VULKAN_INTERNAL_ReleaseBufferContainer( 7148 renderer, 7149 transferBufferContainer); 7150} 7151 7152static void VULKAN_ReleaseShader( 7153 SDL_GPURenderer *driverData, 7154 SDL_GPUShader *shader) 7155{ 7156 VulkanRenderer *renderer = (VulkanRenderer *)driverData; 7157 VulkanShader *vulkanShader = (VulkanShader *)shader; 7158 7159 SDL_LockMutex(renderer->disposeLock); 7160 7161 EXPAND_ARRAY_IF_NEEDED( 7162 renderer->shadersToDestroy, 7163 VulkanShader *, 7164 renderer->shadersToDestroyCount + 1, 7165 renderer->shadersToDestroyCapacity, 7166 renderer->shadersToDestroyCapacity * 2); 7167 7168 renderer->shadersToDestroy[renderer->shadersToDestroyCount] = vulkanShader; 7169 renderer->shadersToDestroyCount += 1; 7170 7171 SDL_UnlockMutex(renderer->disposeLock); 7172} 7173 7174static void VULKAN_ReleaseComputePipeline( 7175 SDL_GPURenderer *driverData, 7176 SDL_GPUComputePipeline *computePipeline) 7177{ 7178 VulkanRenderer *renderer = (VulkanRenderer *)driverData; 7179 VulkanComputePipeline *vulkanComputePipeline = (VulkanComputePipeline *)computePipeline; 7180 7181 SDL_LockMutex(renderer->disposeLock); 7182 7183 EXPAND_ARRAY_IF_NEEDED( 7184 renderer->computePipelinesToDestroy, 7185 VulkanComputePipeline *, 7186 renderer->computePipelinesToDestroyCount + 1, 7187 renderer->computePipelinesToDestroyCapacity, 7188 renderer->computePipelinesToDestroyCapacity * 2); 7189 7190 renderer->computePipelinesToDestroy[renderer->computePipelinesToDestroyCount] = vulkanComputePipeline; 7191 renderer->computePipelinesToDestroyCount += 1; 7192 7193 SDL_UnlockMutex(renderer->disposeLock); 7194} 7195 7196static void VULKAN_ReleaseGraphicsPipeline( 7197 SDL_GPURenderer *driverData, 7198 SDL_GPUGraphicsPipeline *graphicsPipeline) 7199{ 7200 VulkanRenderer *renderer = (VulkanRenderer *)driverData; 7201 VulkanGraphicsPipeline *vulkanGraphicsPipeline = (VulkanGraphicsPipeline *)graphicsPipeline; 7202 7203 SDL_LockMutex(renderer->disposeLock); 7204 7205 EXPAND_ARRAY_IF_NEEDED( 7206 renderer->graphicsPipelinesToDestroy, 7207 VulkanGraphicsPipeline *, 7208 renderer->graphicsPipelinesToDestroyCount + 1, 7209 renderer->graphicsPipelinesToDestroyCapacity, 7210 renderer->graphicsPipelinesToDestroyCapacity * 2); 7211 7212 renderer->graphicsPipelinesToDestroy[renderer->graphicsPipelinesToDestroyCount] = vulkanGraphicsPipeline; 7213 renderer->graphicsPipelinesToDestroyCount += 1; 7214 7215 SDL_UnlockMutex(renderer->disposeLock); 7216} 7217 7218// Command Buffer render state 7219 7220static VkRenderPass VULKAN_INTERNAL_FetchRenderPass( 7221 VulkanRenderer *renderer, 7222 const SDL_GPUColorTargetInfo *colorTargetInfos, 7223 Uint32 numColorTargets, 7224 const SDL_GPUDepthStencilTargetInfo *depthStencilTargetInfo) 7225{ 7226 VulkanRenderPassHashTableValue *renderPassWrapper = NULL; 7227 VkRenderPass renderPassHandle; 7228 RenderPassHashTableKey key; 7229 Uint32 i; 7230 7231 SDL_zero(key); 7232 7233 for (i = 0; i < numColorTargets; i += 1) { 7234 key.colorTargetDescriptions[i].format = SDLToVK_TextureFormat[((VulkanTextureContainer *)colorTargetInfos[i].texture)->header.info.format]; 7235 key.colorTargetDescriptions[i].loadOp = colorTargetInfos[i].load_op; 7236 key.colorTargetDescriptions[i].storeOp = colorTargetInfos[i].store_op; 7237 7238 if (colorTargetInfos[i].resolve_texture != NULL) { 7239 key.resolveTargetFormats[key.numResolveTargets] = SDLToVK_TextureFormat[((VulkanTextureContainer *)colorTargetInfos[i].resolve_texture)->header.info.format]; 7240 key.numResolveTargets += 1; 7241 } 7242 } 7243 7244 key.sampleCount = VK_SAMPLE_COUNT_1_BIT; 7245 if (numColorTargets > 0) { 7246 key.sampleCount = SDLToVK_SampleCount[((VulkanTextureContainer *)colorTargetInfos[0].texture)->header.info.sample_count]; 7247 } else if (numColorTargets == 0 && depthStencilTargetInfo != NULL) { 7248 key.sampleCount = SDLToVK_SampleCount[((VulkanTextureContainer *)depthStencilTargetInfo->texture)->header.info.sample_count]; 7249 } 7250 7251 key.numColorTargets = numColorTargets; 7252 7253 if (depthStencilTargetInfo == NULL) { 7254 key.depthStencilTargetDescription.format = 0; 7255 key.depthStencilTargetDescription.loadOp = SDL_GPU_LOADOP_DONT_CARE; 7256 key.depthStencilTargetDescription.storeOp = SDL_GPU_STOREOP_DONT_CARE; 7257 key.depthStencilTargetDescription.stencilLoadOp = SDL_GPU_LOADOP_DONT_CARE; 7258 key.depthStencilTargetDescription.stencilStoreOp = SDL_GPU_STOREOP_DONT_CARE; 7259 } else { 7260 key.depthStencilTargetDescription.format = SDLToVK_TextureFormat[((VulkanTextureContainer *)depthStencilTargetInfo->texture)->header.info.format]; 7261 key.depthStencilTargetDescription.loadOp = depthStencilTargetInfo->load_op; 7262 key.depthStencilTargetDescription.storeOp = depthStencilTargetInfo->store_op; 7263 key.depthStencilTargetDescription.stencilLoadOp = depthStencilTargetInfo->stencil_load_op; 7264 key.depthStencilTargetDescription.stencilStoreOp = depthStencilTargetInfo->stencil_store_op; 7265 } 7266 7267 SDL_LockMutex(renderer->renderPassFetchLock); 7268 7269 bool result = SDL_FindInHashTable( 7270 renderer->renderPassHashTable, 7271 (const void *)&key, 7272 (const void **)&renderPassWrapper); 7273 7274 if (result) { 7275 SDL_UnlockMutex(renderer->renderPassFetchLock); 7276 return renderPassWrapper->handle; 7277 } 7278 7279 renderPassHandle = VULKAN_INTERNAL_CreateRenderPass( 7280 renderer, 7281 colorTargetInfos, 7282 numColorTargets, 7283 depthStencilTargetInfo); 7284 7285 if (renderPassHandle == VK_NULL_HANDLE) { 7286 SDL_UnlockMutex(renderer->renderPassFetchLock); 7287 return VK_NULL_HANDLE; 7288 } 7289 7290 // Have to malloc the key to store it in the hashtable 7291 RenderPassHashTableKey *allocedKey = SDL_malloc(sizeof(RenderPassHashTableKey)); 7292 SDL_memcpy(allocedKey, &key, sizeof(RenderPassHashTableKey)); 7293 7294 renderPassWrapper = SDL_malloc(sizeof(VulkanRenderPassHashTableValue)); 7295 renderPassWrapper->handle = renderPassHandle; 7296 7297 SDL_InsertIntoHashTable( 7298 renderer->renderPassHashTable, 7299 (const void *)allocedKey, 7300 (const void *)renderPassWrapper, true); 7301 7302 SDL_UnlockMutex(renderer->renderPassFetchLock); 7303 7304 return renderPassHandle; 7305} 7306 7307static VulkanFramebuffer *VULKAN_INTERNAL_FetchFramebuffer( 7308 VulkanRenderer *renderer, 7309 VkRenderPass renderPass, 7310 const SDL_GPUColorTargetInfo *colorTargetInfos, 7311 Uint32 numColorTargets, 7312 const SDL_GPUDepthStencilTargetInfo *depthStencilTargetInfo, 7313 Uint32 width, 7314 Uint32 height) 7315{ 7316 VulkanFramebuffer *vulkanFramebuffer = NULL; 7317 VkFramebufferCreateInfo framebufferInfo; 7318 VkResult result; 7319 VkImageView imageViewAttachments[2 * MAX_COLOR_TARGET_BINDINGS + 1 /* depth */]; 7320 FramebufferHashTableKey key; 7321 Uint32 attachmentCount = 0; 7322 Uint32 i; 7323 7324 SDL_zero(imageViewAttachments); 7325 SDL_zero(key); 7326 7327 key.numColorTargets = numColorTargets; 7328 7329 for (i = 0; i < numColorTargets; i += 1) { 7330 VulkanTextureContainer *container = (VulkanTextureContainer *)colorTargetInfos[i].texture; 7331 VulkanTextureSubresource *subresource = VULKAN_INTERNAL_FetchTextureSubresource( 7332 container, 7333 container->header.info.type == SDL_GPU_TEXTURETYPE_3D ? 0 : colorTargetInfos[i].layer_or_depth_plane, 7334 colorTargetInfos[i].mip_level); 7335 7336 Uint32 rtvIndex = 7337 container->header.info.type == SDL_GPU_TEXTURETYPE_3D ? colorTargetInfos[i].layer_or_depth_plane : 0; 7338 key.colorAttachmentViews[i] = subresource->renderTargetViews[rtvIndex]; 7339 7340 if (colorTargetInfos[i].resolve_texture != NULL) { 7341 VulkanTextureContainer *resolveTextureContainer = (VulkanTextureContainer *)colorTargetInfos[i].resolve_texture; 7342 VulkanTextureSubresource *resolveSubresource = VULKAN_INTERNAL_FetchTextureSubresource( 7343 resolveTextureContainer, 7344 colorTargetInfos[i].layer_or_depth_plane, 7345 colorTargetInfos[i].mip_level); 7346 7347 key.resolveAttachmentViews[key.numResolveAttachments] = resolveSubresource->renderTargetViews[0]; 7348 key.numResolveAttachments += 1; 7349 } 7350 } 7351 7352 if (depthStencilTargetInfo == NULL) { 7353 key.depthStencilAttachmentView = VK_NULL_HANDLE; 7354 } else { 7355 VulkanTextureSubresource *subresource = VULKAN_INTERNAL_FetchTextureSubresource( 7356 (VulkanTextureContainer *)depthStencilTargetInfo->texture, 7357 depthStencilTargetInfo->layer, 7358 depthStencilTargetInfo->mip_level); 7359 key.depthStencilAttachmentView = subresource->depthStencilView; 7360 } 7361 7362 key.width = width; 7363 key.height = height; 7364 7365 SDL_LockMutex(renderer->framebufferFetchLock); 7366 7367 bool findResult = SDL_FindInHashTable( 7368 renderer->framebufferHashTable, 7369 (const void *)&key, 7370 (const void **)&vulkanFramebuffer); 7371 7372 if (findResult) { 7373 SDL_UnlockMutex(renderer->framebufferFetchLock); 7374 return vulkanFramebuffer; 7375 } 7376 7377 vulkanFramebuffer = SDL_malloc(sizeof(VulkanFramebuffer)); 7378 7379 SDL_SetAtomicInt(&vulkanFramebuffer->referenceCount, 0); 7380 7381 // Create a new framebuffer 7382 7383 for (i = 0; i < numColorTargets; i += 1) { 7384 VulkanTextureContainer *container = (VulkanTextureContainer *)colorTargetInfos[i].texture; 7385 VulkanTextureSubresource *subresource = VULKAN_INTERNAL_FetchTextureSubresource( 7386 container, 7387 container->header.info.type == SDL_GPU_TEXTURETYPE_3D ? 0 : colorTargetInfos[i].layer_or_depth_plane, 7388 colorTargetInfos[i].mip_level); 7389 7390 Uint32 rtvIndex = 7391 container->header.info.type == SDL_GPU_TEXTURETYPE_3D ? colorTargetInfos[i].layer_or_depth_plane : 0; 7392 7393 imageViewAttachments[attachmentCount] = subresource->renderTargetViews[rtvIndex]; 7394 7395 attachmentCount += 1; 7396 7397 if (colorTargetInfos[i].store_op == SDL_GPU_STOREOP_RESOLVE || colorTargetInfos[i].store_op == SDL_GPU_STOREOP_RESOLVE_AND_STORE) { 7398 VulkanTextureContainer *resolveContainer = (VulkanTextureContainer *)colorTargetInfos[i].resolve_texture; 7399 VulkanTextureSubresource *resolveSubresource = VULKAN_INTERNAL_FetchTextureSubresource( 7400 resolveContainer, 7401 colorTargetInfos[i].resolve_layer, 7402 colorTargetInfos[i].resolve_mip_level); 7403 7404 imageViewAttachments[attachmentCount] = resolveSubresource->renderTargetViews[0]; 7405 7406 attachmentCount += 1; 7407 } 7408 } 7409 7410 if (depthStencilTargetInfo != NULL) { 7411 VulkanTextureSubresource *subresource = VULKAN_INTERNAL_FetchTextureSubresource( 7412 (VulkanTextureContainer *)depthStencilTargetInfo->texture, 7413 depthStencilTargetInfo->layer, 7414 depthStencilTargetInfo->mip_level); 7415 imageViewAttachments[attachmentCount] = subresource->depthStencilView; 7416 7417 attachmentCount += 1; 7418 } 7419 7420 framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; 7421 framebufferInfo.pNext = NULL; 7422 framebufferInfo.flags = 0; 7423 framebufferInfo.renderPass = renderPass; 7424 framebufferInfo.attachmentCount = attachmentCount; 7425 framebufferInfo.pAttachments = imageViewAttachments; 7426 framebufferInfo.width = key.width; 7427 framebufferInfo.height = key.height; 7428 framebufferInfo.layers = 1; 7429 7430 result = renderer->vkCreateFramebuffer( 7431 renderer->logicalDevice, 7432 &framebufferInfo, 7433 NULL, 7434 &vulkanFramebuffer->framebuffer); 7435 7436 if (result == VK_SUCCESS) { 7437 // Have to malloc the key to store it in the hashtable 7438 FramebufferHashTableKey *allocedKey = SDL_malloc(sizeof(FramebufferHashTableKey)); 7439 SDL_memcpy(allocedKey, &key, sizeof(FramebufferHashTableKey)); 7440 7441 SDL_InsertIntoHashTable( 7442 renderer->framebufferHashTable, 7443 (const void *)allocedKey, 7444 (const void *)vulkanFramebuffer, true); 7445 7446 } else { 7447 SDL_free(vulkanFramebuffer); 7448 SDL_UnlockMutex(renderer->framebufferFetchLock); 7449 CHECK_VULKAN_ERROR_AND_RETURN(result, vkCreateFramebuffer, NULL); 7450 } 7451 7452 SDL_UnlockMutex(renderer->framebufferFetchLock); 7453 return vulkanFramebuffer; 7454} 7455 7456static void VULKAN_INTERNAL_SetCurrentViewport( 7457 VulkanCommandBuffer *commandBuffer, 7458 const SDL_GPUViewport *viewport) 7459{ 7460 VulkanCommandBuffer *vulkanCommandBuffer = commandBuffer; 7461 VulkanRenderer *renderer = vulkanCommandBuffer->renderer; 7462 7463 vulkanCommandBuffer->currentViewport.x = viewport->x; 7464 vulkanCommandBuffer->currentViewport.width = viewport->w; 7465 vulkanCommandBuffer->currentViewport.minDepth = viewport->min_depth; 7466 vulkanCommandBuffer->currentViewport.maxDepth = viewport->max_depth; 7467 7468 // Viewport flip for consistency with other backends 7469 vulkanCommandBuffer->currentViewport.y = viewport->y + viewport->h; 7470 vulkanCommandBuffer->currentViewport.height = -viewport->h; 7471 7472 renderer->vkCmdSetViewport( 7473 vulkanCommandBuffer->commandBuffer, 7474 0, 7475 1, 7476 &vulkanCommandBuffer->currentViewport); 7477} 7478 7479static void VULKAN_SetViewport( 7480 SDL_GPUCommandBuffer *commandBuffer, 7481 const SDL_GPUViewport *viewport) 7482{ 7483 VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; 7484 7485 VULKAN_INTERNAL_SetCurrentViewport( 7486 vulkanCommandBuffer, 7487 viewport); 7488} 7489 7490static void VULKAN_INTERNAL_SetCurrentScissor( 7491 VulkanCommandBuffer *vulkanCommandBuffer, 7492 const SDL_Rect *scissor) 7493{ 7494 VulkanRenderer *renderer = vulkanCommandBuffer->renderer; 7495 7496 vulkanCommandBuffer->currentScissor.offset.x = scissor->x; 7497 vulkanCommandBuffer->currentScissor.offset.y = scissor->y; 7498 vulkanCommandBuffer->currentScissor.extent.width = scissor->w; 7499 vulkanCommandBuffer->currentScissor.extent.height = scissor->h; 7500 7501 renderer->vkCmdSetScissor( 7502 vulkanCommandBuffer->commandBuffer, 7503 0, 7504 1, 7505 &vulkanCommandBuffer->currentScissor); 7506} 7507 7508static void VULKAN_SetScissor( 7509 SDL_GPUCommandBuffer *commandBuffer, 7510 const SDL_Rect *scissor) 7511{ 7512 VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; 7513 7514 VULKAN_INTERNAL_SetCurrentScissor( 7515 vulkanCommandBuffer, 7516 scissor); 7517} 7518 7519static void VULKAN_INTERNAL_SetCurrentBlendConstants( 7520 VulkanCommandBuffer *vulkanCommandBuffer, 7521 SDL_FColor blendConstants) 7522{ 7523 VulkanRenderer *renderer = vulkanCommandBuffer->renderer; 7524 7525 vulkanCommandBuffer->blendConstants[0] = blendConstants.r; 7526 vulkanCommandBuffer->blendConstants[1] = blendConstants.g; 7527 vulkanCommandBuffer->blendConstants[2] = blendConstants.b; 7528 vulkanCommandBuffer->blendConstants[3] = blendConstants.a; 7529 7530 renderer->vkCmdSetBlendConstants( 7531 vulkanCommandBuffer->commandBuffer, 7532 vulkanCommandBuffer->blendConstants); 7533} 7534 7535static void VULKAN_SetBlendConstants( 7536 SDL_GPUCommandBuffer *commandBuffer, 7537 SDL_FColor blendConstants) 7538{ 7539 VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; 7540 7541 VULKAN_INTERNAL_SetCurrentBlendConstants( 7542 vulkanCommandBuffer, 7543 blendConstants); 7544} 7545 7546static void VULKAN_INTERNAL_SetCurrentStencilReference( 7547 VulkanCommandBuffer *vulkanCommandBuffer, 7548 Uint8 reference) 7549{ 7550 VulkanRenderer *renderer = vulkanCommandBuffer->renderer; 7551 7552 vulkanCommandBuffer->stencilRef = reference; 7553 7554 renderer->vkCmdSetStencilReference( 7555 vulkanCommandBuffer->commandBuffer, 7556 VK_STENCIL_FACE_FRONT_AND_BACK, 7557 vulkanCommandBuffer->stencilRef); 7558} 7559 7560static void VULKAN_SetStencilReference( 7561 SDL_GPUCommandBuffer *commandBuffer, 7562 Uint8 reference) 7563{ 7564 VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; 7565 7566 VULKAN_INTERNAL_SetCurrentStencilReference( 7567 vulkanCommandBuffer, 7568 reference); 7569} 7570 7571static void VULKAN_BindVertexSamplers( 7572 SDL_GPUCommandBuffer *commandBuffer, 7573 Uint32 firstSlot, 7574 const SDL_GPUTextureSamplerBinding *textureSamplerBindings, 7575 Uint32 numBindings) 7576{ 7577 VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; 7578 7579 for (Uint32 i = 0; i < numBindings; i += 1) { 7580 VulkanTextureContainer *textureContainer = (VulkanTextureContainer *)textureSamplerBindings[i].texture; 7581 VulkanSampler *sampler = (VulkanSampler *)textureSamplerBindings[i].sampler; 7582 7583 if (vulkanCommandBuffer->vertexSamplerBindings[firstSlot + i] != sampler->sampler) { 7584 VULKAN_INTERNAL_TrackSampler( 7585 vulkanCommandBuffer, 7586 (VulkanSampler *)textureSamplerBindings[i].sampler); 7587 7588 vulkanCommandBuffer->vertexSamplerBindings[firstSlot + i] = sampler->sampler; 7589 vulkanCommandBuffer->needNewVertexResourceDescriptorSet = true; 7590 } 7591 7592 if (vulkanCommandBuffer->vertexSamplerTextureViewBindings[firstSlot + i] != textureContainer->activeTexture->fullView) { 7593 VULKAN_INTERNAL_TrackTexture( 7594 vulkanCommandBuffer, 7595 textureContainer->activeTexture); 7596 7597 vulkanCommandBuffer->vertexSamplerTextureViewBindings[firstSlot + i] = textureContainer->activeTexture->fullView; 7598 vulkanCommandBuffer->needNewVertexResourceDescriptorSet = true; 7599 } 7600 } 7601} 7602 7603static void VULKAN_BindVertexStorageTextures( 7604 SDL_GPUCommandBuffer *commandBuffer, 7605 Uint32 firstSlot, 7606 SDL_GPUTexture *const *storageTextures, 7607 Uint32 numBindings) 7608{ 7609 VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; 7610 7611 for (Uint32 i = 0; i < numBindings; i += 1) { 7612 VulkanTextureContainer *textureContainer = (VulkanTextureContainer *)storageTextures[i]; 7613 7614 if (vulkanCommandBuffer->vertexStorageTextureViewBindings[firstSlot + i] != textureContainer->activeTexture->fullView) { 7615 VULKAN_INTERNAL_TrackTexture( 7616 vulkanCommandBuffer, 7617 textureContainer->activeTexture); 7618 7619 vulkanCommandBuffer->vertexStorageTextureViewBindings[firstSlot + i] = textureContainer->activeTexture->fullView; 7620 vulkanCommandBuffer->needNewVertexResourceDescriptorSet = true; 7621 } 7622 } 7623} 7624 7625static void VULKAN_BindVertexStorageBuffers( 7626 SDL_GPUCommandBuffer *commandBuffer, 7627 Uint32 firstSlot, 7628 SDL_GPUBuffer *const *storageBuffers, 7629 Uint32 numBindings) 7630{ 7631 VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; 7632 7633 for (Uint32 i = 0; i < numBindings; i += 1) { 7634 VulkanBufferContainer *bufferContainer = (VulkanBufferContainer *)storageBuffers[i]; 7635 7636 if (vulkanCommandBuffer->vertexStorageBufferBindings[firstSlot + i] != bufferContainer->activeBuffer->buffer) { 7637 VULKAN_INTERNAL_TrackBuffer( 7638 vulkanCommandBuffer, 7639 bufferContainer->activeBuffer); 7640 7641 vulkanCommandBuffer->vertexStorageBufferBindings[firstSlot + i] = bufferContainer->activeBuffer->buffer; 7642 vulkanCommandBuffer->needNewVertexResourceDescriptorSet = true; 7643 } 7644 } 7645} 7646 7647static void VULKAN_BindFragmentSamplers( 7648 SDL_GPUCommandBuffer *commandBuffer, 7649 Uint32 firstSlot, 7650 const SDL_GPUTextureSamplerBinding *textureSamplerBindings, 7651 Uint32 numBindings) 7652{ 7653 VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; 7654 7655 for (Uint32 i = 0; i < numBindings; i += 1) { 7656 VulkanTextureContainer *textureContainer = (VulkanTextureContainer *)textureSamplerBindings[i].texture; 7657 VulkanSampler *sampler = (VulkanSampler *)textureSamplerBindings[i].sampler; 7658 7659 if (vulkanCommandBuffer->fragmentSamplerBindings[firstSlot + i] != sampler->sampler) { 7660 VULKAN_INTERNAL_TrackSampler( 7661 vulkanCommandBuffer, 7662 (VulkanSampler *)textureSamplerBindings[i].sampler); 7663 7664 vulkanCommandBuffer->fragmentSamplerBindings[firstSlot + i] = sampler->sampler; 7665 vulkanCommandBuffer->needNewFragmentResourceDescriptorSet = true; 7666 } 7667 7668 if (vulkanCommandBuffer->fragmentSamplerTextureViewBindings[firstSlot + i] != textureContainer->activeTexture->fullView) { 7669 VULKAN_INTERNAL_TrackTexture( 7670 vulkanCommandBuffer, 7671 textureContainer->activeTexture); 7672 7673 vulkanCommandBuffer->fragmentSamplerTextureViewBindings[firstSlot + i] = textureContainer->activeTexture->fullView; 7674 vulkanCommandBuffer->needNewFragmentResourceDescriptorSet = true; 7675 } 7676 } 7677} 7678 7679static void VULKAN_BindFragmentStorageTextures( 7680 SDL_GPUCommandBuffer *commandBuffer, 7681 Uint32 firstSlot, 7682 SDL_GPUTexture *const *storageTextures, 7683 Uint32 numBindings) 7684{ 7685 VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; 7686 7687 for (Uint32 i = 0; i < numBindings; i += 1) { 7688 VulkanTextureContainer *textureContainer = (VulkanTextureContainer *)storageTextures[i]; 7689 7690 if (vulkanCommandBuffer->fragmentStorageTextureViewBindings[firstSlot + i] != textureContainer->activeTexture->fullView) { 7691 VULKAN_INTERNAL_TrackTexture( 7692 vulkanCommandBuffer, 7693 textureContainer->activeTexture); 7694 7695 vulkanCommandBuffer->fragmentStorageTextureViewBindings[firstSlot + i] = textureContainer->activeTexture->fullView; 7696 vulkanCommandBuffer->needNewFragmentResourceDescriptorSet = true; 7697 } 7698 } 7699} 7700 7701static void VULKAN_BindFragmentStorageBuffers( 7702 SDL_GPUCommandBuffer *commandBuffer, 7703 Uint32 firstSlot, 7704 SDL_GPUBuffer *const *storageBuffers, 7705 Uint32 numBindings) 7706{ 7707 VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; 7708 VulkanBufferContainer *bufferContainer; 7709 Uint32 i; 7710 7711 for (i = 0; i < numBindings; i += 1) { 7712 bufferContainer = (VulkanBufferContainer *)storageBuffers[i]; 7713 7714 if (vulkanCommandBuffer->fragmentStorageBufferBindings[firstSlot + i] != bufferContainer->activeBuffer->buffer) { 7715 VULKAN_INTERNAL_TrackBuffer( 7716 vulkanCommandBuffer, 7717 bufferContainer->activeBuffer); 7718 7719 vulkanCommandBuffer->fragmentStorageBufferBindings[firstSlot + i] = bufferContainer->activeBuffer->buffer; 7720 vulkanCommandBuffer->needNewFragmentResourceDescriptorSet = true; 7721 } 7722 } 7723} 7724 7725static VulkanUniformBuffer *VULKAN_INTERNAL_AcquireUniformBufferFromPool( 7726 VulkanCommandBuffer *commandBuffer) 7727{ 7728 VulkanRenderer *renderer = commandBuffer->renderer; 7729 VulkanUniformBuffer *uniformBuffer; 7730 7731 SDL_LockMutex(renderer->acquireUniformBufferLock); 7732 7733 if (renderer->uniformBufferPoolCount > 0) { 7734 uniformBuffer = renderer->uniformBufferPool[renderer->uniformBufferPoolCount - 1]; 7735 renderer->uniformBufferPoolCount -= 1; 7736 } else { 7737 uniformBuffer = VULKAN_INTERNAL_CreateUniformBuffer( 7738 renderer, 7739 UNIFORM_BUFFER_SIZE); 7740 } 7741 7742 SDL_UnlockMutex(renderer->acquireUniformBufferLock); 7743 7744 VULKAN_INTERNAL_TrackUniformBuffer(commandBuffer, uniformBuffer); 7745 7746 return uniformBuffer; 7747} 7748 7749static void VULKAN_INTERNAL_ReturnUniformBufferToPool( 7750 VulkanRenderer *renderer, 7751 VulkanUniformBuffer *uniformBuffer) 7752{ 7753 if (renderer->uniformBufferPoolCount >= renderer->uniformBufferPoolCapacity) { 7754 renderer->uniformBufferPoolCapacity *= 2; 7755 renderer->uniformBufferPool = SDL_realloc( 7756 renderer->uniformBufferPool, 7757 renderer->uniformBufferPoolCapacity * sizeof(VulkanUniformBuffer *)); 7758 } 7759 7760 renderer->uniformBufferPool[renderer->uniformBufferPoolCount] = uniformBuffer; 7761 renderer->uniformBufferPoolCount += 1; 7762 7763 uniformBuffer->writeOffset = 0; 7764 uniformBuffer->drawOffset = 0; 7765} 7766 7767static void VULKAN_INTERNAL_PushUniformData( 7768 VulkanCommandBuffer *commandBuffer, 7769 VulkanUniformBufferStage uniformBufferStage, 7770 Uint32 slotIndex, 7771 const void *data, 7772 Uint32 length) 7773{ 7774 Uint32 blockSize = 7775 VULKAN_INTERNAL_NextHighestAlignment32( 7776 length, 7777 commandBuffer->renderer->minUBOAlignment); 7778 7779 VulkanUniformBuffer *uniformBuffer; 7780 7781 if (uniformBufferStage == VULKAN_UNIFORM_BUFFER_STAGE_VERTEX) { 7782 if (commandBuffer->vertexUniformBuffers[slotIndex] == NULL) { 7783 commandBuffer->vertexUniformBuffers[slotIndex] = VULKAN_INTERNAL_AcquireUniformBufferFromPool( 7784 commandBuffer); 7785 } 7786 uniformBuffer = commandBuffer->vertexUniformBuffers[slotIndex]; 7787 } else if (uniformBufferStage == VULKAN_UNIFORM_BUFFER_STAGE_FRAGMENT) { 7788 if (commandBuffer->fragmentUniformBuffers[slotIndex] == NULL) { 7789 commandBuffer->fragmentUniformBuffers[slotIndex] = VULKAN_INTERNAL_AcquireUniformBufferFromPool( 7790 commandBuffer); 7791 } 7792 uniformBuffer = commandBuffer->fragmentUniformBuffers[slotIndex]; 7793 } else if (uniformBufferStage == VULKAN_UNIFORM_BUFFER_STAGE_COMPUTE) { 7794 if (commandBuffer->computeUniformBuffers[slotIndex] == NULL) { 7795 commandBuffer->computeUniformBuffers[slotIndex] = VULKAN_INTERNAL_AcquireUniformBufferFromPool( 7796 commandBuffer); 7797 } 7798 uniformBuffer = commandBuffer->computeUniformBuffers[slotIndex]; 7799 } else { 7800 SDL_LogError(SDL_LOG_CATEGORY_GPU, "Unrecognized shader stage!"); 7801 return; 7802 } 7803 7804 // If there is no more room, acquire a new uniform buffer 7805 if (uniformBuffer->writeOffset + blockSize + MAX_UBO_SECTION_SIZE >= uniformBuffer->buffer->size) { 7806 uniformBuffer = VULKAN_INTERNAL_AcquireUniformBufferFromPool(commandBuffer); 7807 7808 uniformBuffer->drawOffset = 0; 7809 uniformBuffer->writeOffset = 0; 7810 7811 if (uniformBufferStage == VULKAN_UNIFORM_BUFFER_STAGE_VERTEX) { 7812 commandBuffer->vertexUniformBuffers[slotIndex] = uniformBuffer; 7813 commandBuffer->needNewVertexUniformDescriptorSet = true; 7814 } else if (uniformBufferStage == VULKAN_UNIFORM_BUFFER_STAGE_FRAGMENT) { 7815 commandBuffer->fragmentUniformBuffers[slotIndex] = uniformBuffer; 7816 commandBuffer->needNewFragmentUniformDescriptorSet = true; 7817 } else if (uniformBufferStage == VULKAN_UNIFORM_BUFFER_STAGE_COMPUTE) { 7818 commandBuffer->computeUniformBuffers[slotIndex] = uniformBuffer; 7819 commandBuffer->needNewComputeUniformDescriptorSet = true; 7820 } else { 7821 SDL_LogError(SDL_LOG_CATEGORY_GPU, "Unrecognized shader stage!"); 7822 return; 7823 } 7824 } 7825 7826 uniformBuffer->drawOffset = uniformBuffer->writeOffset; 7827 7828 Uint8 *dst = 7829 uniformBuffer->buffer->usedRegion->allocation->mapPointer + 7830 uniformBuffer->buffer->usedRegion->resourceOffset + 7831 uniformBuffer->writeOffset; 7832 7833 SDL_memcpy( 7834 dst, 7835 data, 7836 length); 7837 7838 uniformBuffer->writeOffset += blockSize; 7839 7840 if (uniformBufferStage == VULKAN_UNIFORM_BUFFER_STAGE_VERTEX) { 7841 commandBuffer->needNewVertexUniformOffsets = true; 7842 } else if (uniformBufferStage == VULKAN_UNIFORM_BUFFER_STAGE_FRAGMENT) { 7843 commandBuffer->needNewFragmentUniformOffsets = true; 7844 } else if (uniformBufferStage == VULKAN_UNIFORM_BUFFER_STAGE_COMPUTE) { 7845 commandBuffer->needNewComputeUniformOffsets = true; 7846 } else { 7847 SDL_LogError(SDL_LOG_CATEGORY_GPU, "Unrecognized shader stage!"); 7848 return; 7849 } 7850} 7851 7852static void VULKAN_BeginRenderPass( 7853 SDL_GPUCommandBuffer *commandBuffer, 7854 const SDL_GPUColorTargetInfo *colorTargetInfos, 7855 Uint32 numColorTargets, 7856 const SDL_GPUDepthStencilTargetInfo *depthStencilTargetInfo) 7857{ 7858 VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; 7859 VulkanRenderer *renderer = vulkanCommandBuffer->renderer; 7860 VkRenderPass renderPass; 7861 VulkanFramebuffer *framebuffer; 7862 7863 Uint32 w, h; 7864 VkClearValue *clearValues; 7865 Uint32 clearCount = 0; 7866 Uint32 totalColorAttachmentCount = 0; 7867 Uint32 i; 7868 SDL_GPUViewport defaultViewport; 7869 SDL_Rect defaultScissor; 7870 SDL_FColor defaultBlendConstants; 7871 Uint32 framebufferWidth = SDL_MAX_UINT32; 7872 Uint32 framebufferHeight = SDL_MAX_UINT32; 7873 7874 for (i = 0; i < numColorTargets; i += 1) { 7875 VulkanTextureContainer *textureContainer = (VulkanTextureContainer *)colorTargetInfos[i].texture; 7876 7877 w = textureContainer->header.info.width >> colorTargetInfos[i].mip_level; 7878 h = textureContainer->header.info.height >> colorTargetInfos[i].mip_level; 7879 7880 // The framebuffer cannot be larger than the smallest attachment. 7881 7882 if (w < framebufferWidth) { 7883 framebufferWidth = w; 7884 } 7885 7886 if (h < framebufferHeight) { 7887 framebufferHeight = h; 7888 } 7889 } 7890 7891 if (depthStencilTargetInfo != NULL) { 7892 VulkanTextureContainer *textureContainer = (VulkanTextureContainer *)depthStencilTargetInfo->texture; 7893 7894 w = textureContainer->header.info.width >> depthStencilTargetInfo->mip_level; 7895 h = textureContainer->header.info.height >> depthStencilTargetInfo->mip_level; 7896 7897 // The framebuffer cannot be larger than the smallest attachment. 7898 7899 if (w < framebufferWidth) { 7900 framebufferWidth = w; 7901 } 7902 7903 if (h < framebufferHeight) { 7904 framebufferHeight = h; 7905 } 7906 } 7907 7908 for (i = 0; i < numColorTargets; i += 1) { 7909 VulkanTextureContainer *textureContainer = (VulkanTextureContainer *)colorTargetInfos[i].texture; 7910 VulkanTextureSubresource *subresource = VULKAN_INTERNAL_PrepareTextureSubresourceForWrite( 7911 renderer, 7912 vulkanCommandBuffer, 7913 textureContainer, 7914 textureContainer->header.info.type == SDL_GPU_TEXTURETYPE_3D ? 0 : colorTargetInfos[i].layer_or_depth_plane, 7915 colorTargetInfos[i].mip_level, 7916 colorTargetInfos[i].cycle, 7917 VULKAN_TEXTURE_USAGE_MODE_COLOR_ATTACHMENT); 7918 7919 vulkanCommandBuffer->colorAttachmentSubresources[vulkanCommandBuffer->colorAttachmentSubresourceCount] = subresource; 7920 vulkanCommandBuffer->colorAttachmentSubresourceCount += 1; 7921 VULKAN_INTERNAL_TrackTexture(vulkanCommandBuffer, subresource->parent); 7922 totalColorAttachmentCount += 1; 7923 clearCount += 1; 7924 7925 if (colorTargetInfos[i].store_op == SDL_GPU_STOREOP_RESOLVE || colorTargetInfos[i].store_op == SDL_GPU_STOREOP_RESOLVE_AND_STORE) { 7926 VulkanTextureContainer *resolveContainer = (VulkanTextureContainer *)colorTargetInfos[i].resolve_texture; 7927 VulkanTextureSubresource *resolveSubresource = VULKAN_INTERNAL_PrepareTextureSubresourceForWrite( 7928 renderer, 7929 vulkanCommandBuffer, 7930 resolveContainer, 7931 colorTargetInfos[i].resolve_layer, 7932 colorTargetInfos[i].resolve_mip_level, 7933 colorTargetInfos[i].cycle_resolve_texture, 7934 VULKAN_TEXTURE_USAGE_MODE_COLOR_ATTACHMENT); 7935 7936 vulkanCommandBuffer->resolveAttachmentSubresources[vulkanCommandBuffer->resolveAttachmentSubresourceCount] = resolveSubresource; 7937 vulkanCommandBuffer->resolveAttachmentSubresourceCount += 1; 7938 VULKAN_INTERNAL_TrackTexture(vulkanCommandBuffer, resolveSubresource->parent); 7939 totalColorAttachmentCount += 1; 7940 clearCount += 1; 7941 } 7942 } 7943 7944 if (depthStencilTargetInfo != NULL) { 7945 VulkanTextureContainer *textureContainer = (VulkanTextureContainer *)depthStencilTargetInfo->texture; 7946 VulkanTextureSubresource *subresource = VULKAN_INTERNAL_PrepareTextureSubresourceForWrite( 7947 renderer, 7948 vulkanCommandBuffer, 7949 textureContainer, 7950 depthStencilTargetInfo->layer, 7951 depthStencilTargetInfo->mip_level, 7952 depthStencilTargetInfo->cycle, 7953 VULKAN_TEXTURE_USAGE_MODE_DEPTH_STENCIL_ATTACHMENT); 7954 7955 vulkanCommandBuffer->depthStencilAttachmentSubresource = subresource; 7956 VULKAN_INTERNAL_TrackTexture(vulkanCommandBuffer, subresource->parent); 7957 clearCount += 1; 7958 } 7959 7960 // Fetch required render objects 7961 7962 renderPass = VULKAN_INTERNAL_FetchRenderPass( 7963 renderer, 7964 colorTargetInfos, 7965 numColorTargets, 7966 depthStencilTargetInfo); 7967 7968 if (renderPass == VK_NULL_HANDLE) { 7969 return; 7970 } 7971 7972 framebuffer = VULKAN_INTERNAL_FetchFramebuffer( 7973 renderer, 7974 renderPass, 7975 colorTargetInfos, 7976 numColorTargets, 7977 depthStencilTargetInfo, 7978 framebufferWidth, 7979 framebufferHeight); 7980 7981 if (framebuffer == NULL) { 7982 return; 7983 } 7984 7985 VULKAN_INTERNAL_TrackFramebuffer(vulkanCommandBuffer, framebuffer); 7986 7987 // Set clear values 7988 7989 clearValues = SDL_stack_alloc(VkClearValue, clearCount); 7990 7991 int clearIndex = 0; 7992 for (i = 0; i < numColorTargets; i += 1) { 7993 clearValues[clearIndex].color.float32[0] = colorTargetInfos[i].clear_color.r; 7994 clearValues[clearIndex].color.float32[1] = colorTargetInfos[i].clear_color.g; 7995 clearValues[clearIndex].color.float32[2] = colorTargetInfos[i].clear_color.b; 7996 clearValues[clearIndex].color.float32[3] = colorTargetInfos[i].clear_color.a; 7997 clearIndex += 1; 7998 7999 if (colorTargetInfos[i].store_op == SDL_GPU_STOREOP_RESOLVE || colorTargetInfos[i].store_op == SDL_GPU_STOREOP_RESOLVE_AND_STORE) { 8000 // Skip over the resolve texture, we're not clearing it 8001 clearIndex += 1; 8002 } 8003 } 8004 8005 if (depthStencilTargetInfo != NULL) { 8006 clearValues[totalColorAttachmentCount].depthStencil.depth = 8007 depthStencilTargetInfo->clear_depth; 8008 clearValues[totalColorAttachmentCount].depthStencil.stencil = 8009 depthStencilTargetInfo->clear_stencil; 8010 } 8011 8012 VkRenderPassBeginInfo renderPassBeginInfo; 8013 renderPassBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; 8014 renderPassBeginInfo.pNext = NULL; 8015 renderPassBeginInfo.renderPass = renderPass; 8016 renderPassBeginInfo.framebuffer = framebuffer->framebuffer; 8017 renderPassBeginInfo.pClearValues = clearValues; 8018 renderPassBeginInfo.clearValueCount = clearCount; 8019 renderPassBeginInfo.renderArea.extent.width = framebufferWidth; 8020 renderPassBeginInfo.renderArea.extent.height = framebufferHeight; 8021 renderPassBeginInfo.renderArea.offset.x = 0; 8022 renderPassBeginInfo.renderArea.offset.y = 0; 8023 8024 renderer->vkCmdBeginRenderPass( 8025 vulkanCommandBuffer->commandBuffer, 8026 &renderPassBeginInfo, 8027 VK_SUBPASS_CONTENTS_INLINE); 8028 8029 SDL_stack_free(clearValues); 8030 8031 // Set sensible default states 8032 8033 defaultViewport.x = 0; 8034 defaultViewport.y = 0; 8035 defaultViewport.w = (float)framebufferWidth; 8036 defaultViewport.h = (float)framebufferHeight; 8037 defaultViewport.min_depth = 0; 8038 defaultViewport.max_depth = 1; 8039 8040 VULKAN_INTERNAL_SetCurrentViewport( 8041 vulkanCommandBuffer, 8042 &defaultViewport); 8043 8044 defaultScissor.x = 0; 8045 defaultScissor.y = 0; 8046 defaultScissor.w = (Sint32)framebufferWidth; 8047 defaultScissor.h = (Sint32)framebufferHeight; 8048 8049 VULKAN_INTERNAL_SetCurrentScissor( 8050 vulkanCommandBuffer, 8051 &defaultScissor); 8052 8053 defaultBlendConstants.r = 1.0f; 8054 defaultBlendConstants.g = 1.0f; 8055 defaultBlendConstants.b = 1.0f; 8056 defaultBlendConstants.a = 1.0f; 8057 8058 VULKAN_INTERNAL_SetCurrentBlendConstants( 8059 vulkanCommandBuffer, 8060 defaultBlendConstants); 8061 8062 VULKAN_INTERNAL_SetCurrentStencilReference( 8063 vulkanCommandBuffer, 8064 0); 8065} 8066 8067static void VULKAN_BindGraphicsPipeline( 8068 SDL_GPUCommandBuffer *commandBuffer, 8069 SDL_GPUGraphicsPipeline *graphicsPipeline) 8070{ 8071 VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; 8072 VulkanRenderer *renderer = vulkanCommandBuffer->renderer; 8073 VulkanGraphicsPipeline *pipeline = (VulkanGraphicsPipeline *)graphicsPipeline; 8074 8075 renderer->vkCmdBindPipeline( 8076 vulkanCommandBuffer->commandBuffer, 8077 VK_PIPELINE_BIND_POINT_GRAPHICS, 8078 pipeline->pipeline); 8079 8080 vulkanCommandBuffer->currentGraphicsPipeline = pipeline; 8081 8082 VULKAN_INTERNAL_TrackGraphicsPipeline(vulkanCommandBuffer, pipeline); 8083 8084 // Acquire uniform buffers if necessary 8085 for (Uint32 i = 0; i < pipeline->resourceLayout->vertexUniformBufferCount; i += 1) { 8086 if (vulkanCommandBuffer->vertexUniformBuffers[i] == NULL) { 8087 vulkanCommandBuffer->vertexUniformBuffers[i] = VULKAN_INTERNAL_AcquireUniformBufferFromPool( 8088 vulkanCommandBuffer); 8089 } 8090 } 8091 8092 for (Uint32 i = 0; i < pipeline->resourceLayout->fragmentUniformBufferCount; i += 1) { 8093 if (vulkanCommandBuffer->fragmentUniformBuffers[i] == NULL) { 8094 vulkanCommandBuffer->fragmentUniformBuffers[i] = VULKAN_INTERNAL_AcquireUniformBufferFromPool( 8095 vulkanCommandBuffer); 8096 } 8097 } 8098 8099 // Mark bindings as needed 8100 vulkanCommandBuffer->needNewVertexResourceDescriptorSet = true; 8101 vulkanCommandBuffer->needNewFragmentResourceDescriptorSet = true; 8102 vulkanCommandBuffer->needNewVertexUniformDescriptorSet = true; 8103 vulkanCommandBuffer->needNewFragmentUniformDescriptorSet = true; 8104 vulkanCommandBuffer->needNewVertexUniformOffsets = true; 8105 vulkanCommandBuffer->needNewFragmentUniformOffsets = true; 8106} 8107 8108static void VULKAN_BindVertexBuffers( 8109 SDL_GPUCommandBuffer *commandBuffer, 8110 Uint32 firstSlot, 8111 const SDL_GPUBufferBinding *bindings, 8112 Uint32 numBindings) 8113{ 8114 VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; 8115 8116 for (Uint32 i = 0; i < numBindings; i += 1) { 8117 VulkanBuffer *buffer = ((VulkanBufferContainer *)bindings[i].buffer)->activeBuffer; 8118 if (vulkanCommandBuffer->vertexBuffers[firstSlot + i] != buffer->buffer || vulkanCommandBuffer->vertexBufferOffsets[firstSlot + i] != bindings[i].offset) { 8119 VULKAN_INTERNAL_TrackBuffer(vulkanCommandBuffer, buffer); 8120 8121 vulkanCommandBuffer->vertexBuffers[firstSlot + i] = buffer->buffer; 8122 vulkanCommandBuffer->vertexBufferOffsets[firstSlot + i] = bindings[i].offset; 8123 vulkanCommandBuffer->needVertexBufferBind = true; 8124 } 8125 } 8126 8127 vulkanCommandBuffer->vertexBufferCount = 8128 SDL_max(vulkanCommandBuffer->vertexBufferCount, firstSlot + numBindings); 8129} 8130 8131static void VULKAN_BindIndexBuffer( 8132 SDL_GPUCommandBuffer *commandBuffer, 8133 const SDL_GPUBufferBinding *binding, 8134 SDL_GPUIndexElementSize indexElementSize) 8135{ 8136 VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; 8137 VulkanRenderer *renderer = vulkanCommandBuffer->renderer; 8138 VulkanBuffer *vulkanBuffer = ((VulkanBufferContainer *)binding->buffer)->activeBuffer; 8139 8140 VULKAN_INTERNAL_TrackBuffer(vulkanCommandBuffer, vulkanBuffer); 8141 8142 renderer->vkCmdBindIndexBuffer( 8143 vulkanCommandBuffer->commandBuffer, 8144 vulkanBuffer->buffer, 8145 (VkDeviceSize)binding->offset, 8146 SDLToVK_IndexType[indexElementSize]); 8147} 8148 8149static void VULKAN_PushVertexUniformData( 8150 SDL_GPUCommandBuffer *commandBuffer, 8151 Uint32 slotIndex, 8152 const void *data, 8153 Uint32 length) 8154{ 8155 VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; 8156 8157 VULKAN_INTERNAL_PushUniformData( 8158 vulkanCommandBuffer, 8159 VULKAN_UNIFORM_BUFFER_STAGE_VERTEX, 8160 slotIndex, 8161 data, 8162 length); 8163} 8164 8165static void VULKAN_PushFragmentUniformData( 8166 SDL_GPUCommandBuffer *commandBuffer, 8167 Uint32 slotIndex, 8168 const void *data, 8169 Uint32 length) 8170{ 8171 VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; 8172 8173 VULKAN_INTERNAL_PushUniformData( 8174 vulkanCommandBuffer, 8175 VULKAN_UNIFORM_BUFFER_STAGE_FRAGMENT, 8176 slotIndex, 8177 data, 8178 length); 8179} 8180 8181static void VULKAN_EndRenderPass( 8182 SDL_GPUCommandBuffer *commandBuffer) 8183{ 8184 VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; 8185 VulkanRenderer *renderer = vulkanCommandBuffer->renderer; 8186 Uint32 i; 8187 8188 renderer->vkCmdEndRenderPass( 8189 vulkanCommandBuffer->commandBuffer); 8190 8191 for (i = 0; i < vulkanCommandBuffer->colorAttachmentSubresourceCount; i += 1) { 8192 VULKAN_INTERNAL_TextureSubresourceTransitionToDefaultUsage( 8193 renderer, 8194 vulkanCommandBuffer, 8195 VULKAN_TEXTURE_USAGE_MODE_COLOR_ATTACHMENT, 8196 vulkanCommandBuffer->colorAttachmentSubresources[i]); 8197 } 8198 vulkanCommandBuffer->colorAttachmentSubresourceCount = 0; 8199 8200 for (i = 0; i < vulkanCommandBuffer->resolveAttachmentSubresourceCount; i += 1) { 8201 VULKAN_INTERNAL_TextureSubresourceTransitionToDefaultUsage( 8202 renderer, 8203 vulkanCommandBuffer, 8204 VULKAN_TEXTURE_USAGE_MODE_COLOR_ATTACHMENT, 8205 vulkanCommandBuffer->resolveAttachmentSubresources[i]); 8206 } 8207 vulkanCommandBuffer->resolveAttachmentSubresourceCount = 0; 8208 8209 if (vulkanCommandBuffer->depthStencilAttachmentSubresource != NULL) { 8210 VULKAN_INTERNAL_TextureSubresourceTransitionToDefaultUsage( 8211 renderer, 8212 vulkanCommandBuffer, 8213 VULKAN_TEXTURE_USAGE_MODE_DEPTH_STENCIL_ATTACHMENT, 8214 vulkanCommandBuffer->depthStencilAttachmentSubresource); 8215 vulkanCommandBuffer->depthStencilAttachmentSubresource = NULL; 8216 } 8217 8218 vulkanCommandBuffer->currentGraphicsPipeline = NULL; 8219 8220 vulkanCommandBuffer->vertexResourceDescriptorSet = VK_NULL_HANDLE; 8221 vulkanCommandBuffer->vertexUniformDescriptorSet = VK_NULL_HANDLE; 8222 vulkanCommandBuffer->fragmentResourceDescriptorSet = VK_NULL_HANDLE; 8223 vulkanCommandBuffer->fragmentUniformDescriptorSet = VK_NULL_HANDLE; 8224 8225 // Reset bind state 8226 SDL_zeroa(vulkanCommandBuffer->colorAttachmentSubresources); 8227 SDL_zeroa(vulkanCommandBuffer->resolveAttachmentSubresources); 8228 vulkanCommandBuffer->depthStencilAttachmentSubresource = NULL; 8229 8230 SDL_zeroa(vulkanCommandBuffer->vertexBuffers); 8231 SDL_zeroa(vulkanCommandBuffer->vertexBufferOffsets); 8232 vulkanCommandBuffer->vertexBufferCount = 0; 8233 8234 SDL_zeroa(vulkanCommandBuffer->vertexSamplerBindings); 8235 SDL_zeroa(vulkanCommandBuffer->vertexSamplerTextureViewBindings); 8236 SDL_zeroa(vulkanCommandBuffer->vertexStorageTextureViewBindings); 8237 SDL_zeroa(vulkanCommandBuffer->vertexStorageBufferBindings); 8238 8239 SDL_zeroa(vulkanCommandBuffer->fragmentSamplerBindings); 8240 SDL_zeroa(vulkanCommandBuffer->fragmentSamplerTextureViewBindings); 8241 SDL_zeroa(vulkanCommandBuffer->fragmentStorageTextureViewBindings); 8242 SDL_zeroa(vulkanCommandBuffer->fragmentStorageBufferBindings); 8243} 8244 8245static void VULKAN_BeginComputePass( 8246 SDL_GPUCommandBuffer *commandBuffer, 8247 const SDL_GPUStorageTextureReadWriteBinding *storageTextureBindings, 8248 Uint32 numStorageTextureBindings, 8249 const SDL_GPUStorageBufferReadWriteBinding *storageBufferBindings, 8250 Uint32 numStorageBufferBindings) 8251{ 8252 VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; 8253 VulkanRenderer *renderer = vulkanCommandBuffer->renderer; 8254 VulkanBufferContainer *bufferContainer; 8255 VulkanBuffer *buffer; 8256 Uint32 i; 8257 8258 vulkanCommandBuffer->readWriteComputeStorageTextureSubresourceCount = numStorageTextureBindings; 8259 8260 for (i = 0; i < numStorageTextureBindings; i += 1) { 8261 VulkanTextureContainer *textureContainer = (VulkanTextureContainer *)storageTextureBindings[i].texture; 8262 VulkanTextureSubresource *subresource = VULKAN_INTERNAL_PrepareTextureSubresourceForWrite( 8263 renderer, 8264 vulkanCommandBuffer, 8265 textureContainer, 8266 storageTextureBindings[i].layer, 8267 storageTextureBindings[i].mip_level, 8268 storageTextureBindings[i].cycle, 8269 VULKAN_TEXTURE_USAGE_MODE_COMPUTE_STORAGE_READ_WRITE); 8270 8271 vulkanCommandBuffer->readWriteComputeStorageTextureSubresources[i] = subresource; 8272 vulkanCommandBuffer->readWriteComputeStorageTextureViewBindings[i] = subresource->computeWriteView; 8273 8274 VULKAN_INTERNAL_TrackTexture( 8275 vulkanCommandBuffer, 8276 subresource->parent); 8277 } 8278 8279 for (i = 0; i < numStorageBufferBindings; i += 1) { 8280 bufferContainer = (VulkanBufferContainer *)storageBufferBindings[i].buffer; 8281 buffer = VULKAN_INTERNAL_PrepareBufferForWrite( 8282 renderer, 8283 vulkanCommandBuffer, 8284 bufferContainer, 8285 storageBufferBindings[i].cycle, 8286 VULKAN_BUFFER_USAGE_MODE_COMPUTE_STORAGE_READ_WRITE); 8287 8288 vulkanCommandBuffer->readWriteComputeStorageBuffers[i] = buffer; 8289 vulkanCommandBuffer->readWriteComputeStorageBufferBindings[i] = buffer->buffer; 8290 8291 VULKAN_INTERNAL_TrackBuffer( 8292 vulkanCommandBuffer, 8293 buffer); 8294 } 8295} 8296 8297static void VULKAN_BindComputePipeline( 8298 SDL_GPUCommandBuffer *commandBuffer, 8299 SDL_GPUComputePipeline *computePipeline) 8300{ 8301 VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; 8302 VulkanRenderer *renderer = vulkanCommandBuffer->renderer; 8303 VulkanComputePipeline *vulkanComputePipeline = (VulkanComputePipeline *)computePipeline; 8304 8305 renderer->vkCmdBindPipeline( 8306 vulkanCommandBuffer->commandBuffer, 8307 VK_PIPELINE_BIND_POINT_COMPUTE, 8308 vulkanComputePipeline->pipeline); 8309 8310 vulkanCommandBuffer->currentComputePipeline = vulkanComputePipeline; 8311 8312 VULKAN_INTERNAL_TrackComputePipeline(vulkanCommandBuffer, vulkanComputePipeline); 8313 8314 // Acquire uniform buffers if necessary 8315 for (Uint32 i = 0; i < vulkanComputePipeline->resourceLayout->numUniformBuffers; i += 1) { 8316 if (vulkanCommandBuffer->computeUniformBuffers[i] == NULL) { 8317 vulkanCommandBuffer->computeUniformBuffers[i] = VULKAN_INTERNAL_AcquireUniformBufferFromPool( 8318 vulkanCommandBuffer); 8319 } 8320 } 8321 8322 // Mark binding as needed 8323 vulkanCommandBuffer->needNewComputeReadWriteDescriptorSet = true; 8324 vulkanCommandBuffer->needNewComputeReadOnlyDescriptorSet = true; 8325 vulkanCommandBuffer->needNewComputeUniformDescriptorSet = true; 8326 vulkanCommandBuffer->needNewComputeUniformOffsets = true; 8327} 8328 8329static void VULKAN_BindComputeSamplers( 8330 SDL_GPUCommandBuffer *commandBuffer, 8331 Uint32 firstSlot, 8332 const SDL_GPUTextureSamplerBinding *textureSamplerBindings, 8333 Uint32 numBindings) 8334{ 8335 VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; 8336 8337 for (Uint32 i = 0; i < numBindings; i += 1) { 8338 VulkanTextureContainer *textureContainer = (VulkanTextureContainer *)textureSamplerBindings[i].texture; 8339 VulkanSampler *sampler = (VulkanSampler *)textureSamplerBindings[i].sampler; 8340 8341 if (vulkanCommandBuffer->computeSamplerBindings[firstSlot + i] != sampler->sampler) { 8342 VULKAN_INTERNAL_TrackSampler( 8343 vulkanCommandBuffer, 8344 sampler); 8345 8346 vulkanCommandBuffer->computeSamplerBindings[firstSlot + i] = sampler->sampler; 8347 vulkanCommandBuffer->needNewComputeReadOnlyDescriptorSet = true; 8348 } 8349 8350 if (vulkanCommandBuffer->computeSamplerTextureViewBindings[firstSlot + i] != textureContainer->activeTexture->fullView) { 8351 VULKAN_INTERNAL_TrackTexture( 8352 vulkanCommandBuffer, 8353 textureContainer->activeTexture); 8354 8355 vulkanCommandBuffer->computeSamplerTextureViewBindings[firstSlot + i] = textureContainer->activeTexture->fullView; 8356 vulkanCommandBuffer->needNewComputeReadOnlyDescriptorSet = true; 8357 } 8358 } 8359} 8360 8361static void VULKAN_BindComputeStorageTextures( 8362 SDL_GPUCommandBuffer *commandBuffer, 8363 Uint32 firstSlot, 8364 SDL_GPUTexture *const *storageTextures, 8365 Uint32 numBindings) 8366{ 8367 VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; 8368 VulkanRenderer *renderer = vulkanCommandBuffer->renderer; 8369 8370 for (Uint32 i = 0; i < numBindings; i += 1) { 8371 VulkanTextureContainer *textureContainer = (VulkanTextureContainer *)storageTextures[i]; 8372 8373 if (vulkanCommandBuffer->readOnlyComputeStorageTextures[firstSlot + i] != textureContainer->activeTexture) { 8374 /* If a different texture as in this slot, transition it back to its default usage */ 8375 if (vulkanCommandBuffer->readOnlyComputeStorageTextures[firstSlot + i] != NULL) { 8376 VULKAN_INTERNAL_TextureTransitionToDefaultUsage( 8377 renderer, 8378 vulkanCommandBuffer, 8379 VULKAN_TEXTURE_USAGE_MODE_COMPUTE_STORAGE_READ, 8380 vulkanCommandBuffer->readOnlyComputeStorageTextures[firstSlot + i]); 8381 } 8382 8383 /* Then transition the new texture and prepare it for binding */ 8384 VULKAN_INTERNAL_TextureTransitionFromDefaultUsage( 8385 renderer, 8386 vulkanCommandBuffer, 8387 VULKAN_TEXTURE_USAGE_MODE_COMPUTE_STORAGE_READ, 8388 textureContainer->activeTexture); 8389 8390 8391 VULKAN_INTERNAL_TrackTexture( 8392 vulkanCommandBuffer, 8393 textureContainer->activeTexture); 8394 8395 vulkanCommandBuffer->readOnlyComputeStorageTextures[firstSlot + i] = textureContainer->activeTexture; 8396 vulkanCommandBuffer->readOnlyComputeStorageTextureViewBindings[firstSlot + i] = textureContainer->activeTexture->fullView; 8397 vulkanCommandBuffer->needNewComputeReadOnlyDescriptorSet = true; 8398 } 8399 } 8400} 8401 8402static void VULKAN_BindComputeStorageBuffers( 8403 SDL_GPUCommandBuffer *commandBuffer, 8404 Uint32 firstSlot, 8405 SDL_GPUBuffer *const *storageBuffers, 8406 Uint32 numBindings) 8407{ 8408 VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; 8409 VulkanRenderer *renderer = vulkanCommandBuffer->renderer; 8410 8411 for (Uint32 i = 0; i < numBindings; i += 1) { 8412 VulkanBufferContainer *bufferContainer = (VulkanBufferContainer *)storageBuffers[i]; 8413 8414 if (vulkanCommandBuffer->readOnlyComputeStorageBuffers[firstSlot + i] != bufferContainer->activeBuffer) { 8415 /* If a different buffer was in this slot, transition it back to its default usage */ 8416 if (vulkanCommandBuffer->readOnlyComputeStorageBuffers[firstSlot + i] != NULL) { 8417 VULKAN_INTERNAL_BufferTransitionToDefaultUsage( 8418 renderer, 8419 vulkanCommandBuffer, 8420 VULKAN_BUFFER_USAGE_MODE_COMPUTE_STORAGE_READ, 8421 vulkanCommandBuffer->readOnlyComputeStorageBuffers[firstSlot + i]); 8422 } 8423 8424 /* Then transition the new buffer and prepare it for binding */ 8425 VULKAN_INTERNAL_BufferTransitionFromDefaultUsage( 8426 renderer, 8427 vulkanCommandBuffer, 8428 VULKAN_BUFFER_USAGE_MODE_COMPUTE_STORAGE_READ, 8429 bufferContainer->activeBuffer); 8430 8431 VULKAN_INTERNAL_TrackBuffer( 8432 vulkanCommandBuffer, 8433 bufferContainer->activeBuffer); 8434 8435 vulkanCommandBuffer->readOnlyComputeStorageBuffers[firstSlot + i] = bufferContainer->activeBuffer; 8436 vulkanCommandBuffer->readOnlyComputeStorageBufferBindings[firstSlot + i] = bufferContainer->activeBuffer->buffer; 8437 vulkanCommandBuffer->needNewComputeReadOnlyDescriptorSet = true; 8438 } 8439 } 8440} 8441 8442static void VULKAN_PushComputeUniformData( 8443 SDL_GPUCommandBuffer *commandBuffer, 8444 Uint32 slotIndex, 8445 const void *data, 8446 Uint32 length) 8447{ 8448 VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; 8449 8450 VULKAN_INTERNAL_PushUniformData( 8451 vulkanCommandBuffer, 8452 VULKAN_UNIFORM_BUFFER_STAGE_COMPUTE, 8453 slotIndex, 8454 data, 8455 length); 8456} 8457 8458static void VULKAN_INTERNAL_BindComputeDescriptorSets( 8459 VulkanRenderer *renderer, 8460 VulkanCommandBuffer *commandBuffer) 8461{ 8462 VulkanComputePipelineResourceLayout *resourceLayout; 8463 DescriptorSetLayout *descriptorSetLayout; 8464 VkWriteDescriptorSet writeDescriptorSets[ 8465 MAX_TEXTURE_SAMPLERS_PER_STAGE + 8466 MAX_STORAGE_TEXTURES_PER_STAGE + 8467 MAX_STORAGE_BUFFERS_PER_STAGE + 8468 MAX_COMPUTE_WRITE_TEXTURES + 8469 MAX_COMPUTE_WRITE_BUFFERS + 8470 MAX_UNIFORM_BUFFERS_PER_STAGE]; 8471 VkDescriptorBufferInfo bufferInfos[MAX_STORAGE_BUFFERS_PER_STAGE + MAX_COMPUTE_WRITE_BUFFERS + MAX_UNIFORM_BUFFERS_PER_STAGE]; 8472 VkDescriptorImageInfo imageInfos[MAX_TEXTURE_SAMPLERS_PER_STAGE + MAX_STORAGE_TEXTURES_PER_STAGE + MAX_COMPUTE_WRITE_TEXTURES]; 8473 Uint32 dynamicOffsets[MAX_UNIFORM_BUFFERS_PER_STAGE]; 8474 Uint32 writeCount = 0; 8475 Uint32 bufferInfoCount = 0; 8476 Uint32 imageInfoCount = 0; 8477 Uint32 dynamicOffsetCount = 0; 8478 8479 if ( 8480 !commandBuffer->needNewComputeReadOnlyDescriptorSet && 8481 !commandBuffer->needNewComputeReadWriteDescriptorSet && 8482 !commandBuffer->needNewComputeUniformDescriptorSet && 8483 !commandBuffer->needNewComputeUniformOffsets 8484 ) { 8485 return; 8486 } 8487 8488 resourceLayout = commandBuffer->currentComputePipeline->resourceLayout; 8489 8490 if (commandBuffer->needNewComputeReadOnlyDescriptorSet) { 8491 descriptorSetLayout = resourceLayout->descriptorSetLayouts[0]; 8492 8493 commandBuffer->computeReadOnlyDescriptorSet = VULKAN_INTERNAL_FetchDescriptorSet( 8494 renderer, 8495 commandBuffer, 8496 descriptorSetLayout); 8497 8498 for (Uint32 i = 0; i < resourceLayout->numSamplers; i += 1) { 8499 VkWriteDescriptorSet *currentWriteDescriptorSet = &writeDescriptorSets[writeCount]; 8500 8501 currentWriteDescriptorSet->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; 8502 currentWriteDescriptorSet->pNext = NULL; 8503 currentWriteDescriptorSet->descriptorCount = 1; 8504 currentWriteDescriptorSet->descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; 8505 currentWriteDescriptorSet->dstArrayElement = 0; 8506 currentWriteDescriptorSet->dstBinding = i; 8507 currentWriteDescriptorSet->dstSet = commandBuffer->computeReadOnlyDescriptorSet; 8508 currentWriteDescriptorSet->pTexelBufferView = NULL; 8509 currentWriteDescriptorSet->pBufferInfo = NULL; 8510 8511 imageInfos[imageInfoCount].sampler = commandBuffer->computeSamplerBindings[i]; 8512 imageInfos[imageInfoCount].imageView = commandBuffer->computeSamplerTextureViewBindings[i]; 8513 imageInfos[imageInfoCount].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; 8514 8515 currentWriteDescriptorSet->pImageInfo = &imageInfos[imageInfoCount]; 8516 8517 writeCount += 1; 8518 imageInfoCount += 1; 8519 } 8520 8521 for (Uint32 i = 0; i < resourceLayout->numReadonlyStorageTextures; i += 1) { 8522 VkWriteDescriptorSet *currentWriteDescriptorSet = &writeDescriptorSets[writeCount]; 8523 8524 currentWriteDescriptorSet->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; 8525 currentWriteDescriptorSet->pNext = NULL; 8526 currentWriteDescriptorSet->descriptorCount = 1; 8527 currentWriteDescriptorSet->descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE; // Yes, we are declaring the readonly storage texture as a sampled image, because shaders are stupid. 8528 currentWriteDescriptorSet->dstArrayElement = 0; 8529 currentWriteDescriptorSet->dstBinding = resourceLayout->numSamplers + i; 8530 currentWriteDescriptorSet->dstSet = commandBuffer->computeReadOnlyDescriptorSet; 8531 currentWriteDescriptorSet->pTexelBufferView = NULL; 8532 currentWriteDescriptorSet->pBufferInfo = NULL; 8533 8534 imageInfos[imageInfoCount].sampler = VK_NULL_HANDLE; 8535 imageInfos[imageInfoCount].imageView = commandBuffer->readOnlyComputeStorageTextureViewBindings[i]; 8536 imageInfos[imageInfoCount].imageLayout = VK_IMAGE_LAYOUT_GENERAL; 8537 8538 currentWriteDescriptorSet->pImageInfo = &imageInfos[imageInfoCount]; 8539 8540 writeCount += 1; 8541 imageInfoCount += 1; 8542 } 8543 8544 for (Uint32 i = 0; i < resourceLayout->numReadonlyStorageBuffers; i += 1) { 8545 VkWriteDescriptorSet *currentWriteDescriptorSet = &writeDescriptorSets[writeCount]; 8546 8547 currentWriteDescriptorSet->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; 8548 currentWriteDescriptorSet->pNext = NULL; 8549 currentWriteDescriptorSet->descriptorCount = 1; 8550 currentWriteDescriptorSet->descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; 8551 currentWriteDescriptorSet->dstArrayElement = 0; 8552 currentWriteDescriptorSet->dstBinding = resourceLayout->numSamplers + resourceLayout->numReadonlyStorageTextures + i; 8553 currentWriteDescriptorSet->dstSet = commandBuffer->computeReadOnlyDescriptorSet; 8554 currentWriteDescriptorSet->pTexelBufferView = NULL; 8555 currentWriteDescriptorSet->pImageInfo = NULL; 8556 8557 bufferInfos[bufferInfoCount].buffer = commandBuffer->readOnlyComputeStorageBufferBindings[i]; 8558 bufferInfos[bufferInfoCount].offset = 0; 8559 bufferInfos[bufferInfoCount].range = VK_WHOLE_SIZE; 8560 8561 currentWriteDescriptorSet->pBufferInfo = &bufferInfos[bufferInfoCount]; 8562 8563 writeCount += 1; 8564 bufferInfoCount += 1; 8565 } 8566 8567 commandBuffer->needNewComputeReadOnlyDescriptorSet = false; 8568 } 8569 8570 if (commandBuffer->needNewComputeReadWriteDescriptorSet) { 8571 descriptorSetLayout = resourceLayout->descriptorSetLayouts[1]; 8572 8573 commandBuffer->computeReadWriteDescriptorSet = VULKAN_INTERNAL_FetchDescriptorSet( 8574 renderer, 8575 commandBuffer, 8576 descriptorSetLayout); 8577 8578 for (Uint32 i = 0; i < resourceLayout->numReadWriteStorageTextures; i += 1) { 8579 VkWriteDescriptorSet *currentWriteDescriptorSet = &writeDescriptorSets[writeCount]; 8580 8581 currentWriteDescriptorSet->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; 8582 currentWriteDescriptorSet->pNext = NULL; 8583 currentWriteDescriptorSet->descriptorCount = 1; 8584 currentWriteDescriptorSet->descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; 8585 currentWriteDescriptorSet->dstArrayElement = 0; 8586 currentWriteDescriptorSet->dstBinding = i; 8587 currentWriteDescriptorSet->dstSet = commandBuffer->computeReadWriteDescriptorSet; 8588 currentWriteDescriptorSet->pTexelBufferView = NULL; 8589 currentWriteDescriptorSet->pBufferInfo = NULL; 8590 8591 imageInfos[imageInfoCount].sampler = VK_NULL_HANDLE; 8592 imageInfos[imageInfoCount].imageView = commandBuffer->readWriteComputeStorageTextureViewBindings[i]; 8593 imageInfos[imageInfoCount].imageLayout = VK_IMAGE_LAYOUT_GENERAL; 8594 8595 currentWriteDescriptorSet->pImageInfo = &imageInfos[imageInfoCount]; 8596 8597 writeCount += 1; 8598 imageInfoCount += 1; 8599 } 8600 8601 for (Uint32 i = 0; i < resourceLayout->numReadWriteStorageBuffers; i += 1) { 8602 VkWriteDescriptorSet *currentWriteDescriptorSet = &writeDescriptorSets[writeCount]; 8603 8604 currentWriteDescriptorSet->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; 8605 currentWriteDescriptorSet->pNext = NULL; 8606 currentWriteDescriptorSet->descriptorCount = 1; 8607 currentWriteDescriptorSet->descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; 8608 currentWriteDescriptorSet->dstArrayElement = 0; 8609 currentWriteDescriptorSet->dstBinding = resourceLayout->numReadWriteStorageTextures + i; 8610 currentWriteDescriptorSet->dstSet = commandBuffer->computeReadWriteDescriptorSet; 8611 currentWriteDescriptorSet->pTexelBufferView = NULL; 8612 currentWriteDescriptorSet->pImageInfo = NULL; 8613 8614 bufferInfos[bufferInfoCount].buffer = commandBuffer->readWriteComputeStorageBufferBindings[i]; 8615 bufferInfos[bufferInfoCount].offset = 0; 8616 bufferInfos[bufferInfoCount].range = VK_WHOLE_SIZE; 8617 8618 currentWriteDescriptorSet->pBufferInfo = &bufferInfos[bufferInfoCount]; 8619 8620 writeCount += 1; 8621 bufferInfoCount += 1; 8622 } 8623 8624 commandBuffer->needNewComputeReadWriteDescriptorSet = false; 8625 } 8626 8627 if (commandBuffer->needNewComputeUniformDescriptorSet) { 8628 descriptorSetLayout = resourceLayout->descriptorSetLayouts[2]; 8629 8630 commandBuffer->computeUniformDescriptorSet = VULKAN_INTERNAL_FetchDescriptorSet( 8631 renderer, 8632 commandBuffer, 8633 descriptorSetLayout); 8634 8635 8636 for (Uint32 i = 0; i < resourceLayout->numUniformBuffers; i += 1) { 8637 VkWriteDescriptorSet *currentWriteDescriptorSet = &writeDescriptorSets[writeCount]; 8638 8639 currentWriteDescriptorSet->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; 8640 currentWriteDescriptorSet->pNext = NULL; 8641 currentWriteDescriptorSet->descriptorCount = 1; 8642 currentWriteDescriptorSet->descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC; 8643 currentWriteDescriptorSet->dstArrayElement = 0; 8644 currentWriteDescriptorSet->dstBinding = i; 8645 currentWriteDescriptorSet->dstSet = commandBuffer->computeUniformDescriptorSet; 8646 currentWriteDescriptorSet->pTexelBufferView = NULL; 8647 currentWriteDescriptorSet->pImageInfo = NULL; 8648 8649 bufferInfos[bufferInfoCount].buffer = commandBuffer->computeUniformBuffers[i]->buffer->buffer; 8650 bufferInfos[bufferInfoCount].offset = 0; 8651 bufferInfos[bufferInfoCount].range = MAX_UBO_SECTION_SIZE; 8652 8653 currentWriteDescriptorSet->pBufferInfo = &bufferInfos[bufferInfoCount]; 8654 8655 writeCount += 1; 8656 bufferInfoCount += 1; 8657 } 8658 8659 commandBuffer->needNewComputeUniformDescriptorSet = false; 8660 } 8661 8662 for (Uint32 i = 0; i < resourceLayout->numUniformBuffers; i += 1) { 8663 dynamicOffsets[i] = commandBuffer->computeUniformBuffers[i]->drawOffset; 8664 dynamicOffsetCount += 1; 8665 } 8666 8667 renderer->vkUpdateDescriptorSets( 8668 renderer->logicalDevice, 8669 writeCount, 8670 writeDescriptorSets, 8671 0, 8672 NULL); 8673 8674 VkDescriptorSet sets[3]; 8675 sets[0] = commandBuffer->computeReadOnlyDescriptorSet; 8676 sets[1] = commandBuffer->computeReadWriteDescriptorSet; 8677 sets[2] = commandBuffer->computeUniformDescriptorSet; 8678 8679 renderer->vkCmdBindDescriptorSets( 8680 commandBuffer->commandBuffer, 8681 VK_PIPELINE_BIND_POINT_COMPUTE, 8682 resourceLayout->pipelineLayout, 8683 0, 8684 3, 8685 sets, 8686 dynamicOffsetCount, 8687 dynamicOffsets); 8688 8689 commandBuffer->needNewComputeUniformOffsets = false; 8690} 8691 8692static void VULKAN_DispatchCompute( 8693 SDL_GPUCommandBuffer *commandBuffer, 8694 Uint32 groupcountX, 8695 Uint32 groupcountY, 8696 Uint32 groupcountZ) 8697{ 8698 VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; 8699 VulkanRenderer *renderer = vulkanCommandBuffer->renderer; 8700 8701 VULKAN_INTERNAL_BindComputeDescriptorSets(renderer, vulkanCommandBuffer); 8702 8703 renderer->vkCmdDispatch( 8704 vulkanCommandBuffer->commandBuffer, 8705 groupcountX, 8706 groupcountY, 8707 groupcountZ); 8708} 8709 8710static void VULKAN_DispatchComputeIndirect( 8711 SDL_GPUCommandBuffer *commandBuffer, 8712 SDL_GPUBuffer *buffer, 8713 Uint32 offset) 8714{ 8715 VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; 8716 VulkanRenderer *renderer = vulkanCommandBuffer->renderer; 8717 VulkanBuffer *vulkanBuffer = ((VulkanBufferContainer *)buffer)->activeBuffer; 8718 8719 VULKAN_INTERNAL_BindComputeDescriptorSets(renderer, vulkanCommandBuffer); 8720 8721 renderer->vkCmdDispatchIndirect( 8722 vulkanCommandBuffer->commandBuffer, 8723 vulkanBuffer->buffer, 8724 offset); 8725 8726 VULKAN_INTERNAL_TrackBuffer(vulkanCommandBuffer, vulkanBuffer); 8727} 8728 8729static void VULKAN_EndComputePass( 8730 SDL_GPUCommandBuffer *commandBuffer) 8731{ 8732 VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; 8733 Uint32 i; 8734 8735 for (i = 0; i < vulkanCommandBuffer->readWriteComputeStorageTextureSubresourceCount; i += 1) { 8736 VULKAN_INTERNAL_TextureSubresourceTransitionToDefaultUsage( 8737 vulkanCommandBuffer->renderer, 8738 vulkanCommandBuffer, 8739 VULKAN_TEXTURE_USAGE_MODE_COMPUTE_STORAGE_READ_WRITE, 8740 vulkanCommandBuffer->readWriteComputeStorageTextureSubresources[i]); 8741 vulkanCommandBuffer->readWriteComputeStorageTextureSubresources[i] = NULL; 8742 } 8743 vulkanCommandBuffer->readWriteComputeStorageTextureSubresourceCount = 0; 8744 8745 for (i = 0; i < MAX_COMPUTE_WRITE_BUFFERS; i += 1) { 8746 if (vulkanCommandBuffer->readWriteComputeStorageBuffers[i] != NULL) { 8747 VULKAN_INTERNAL_BufferTransitionToDefaultUsage( 8748 vulkanCommandBuffer->renderer, 8749 vulkanCommandBuffer, 8750 VULKAN_BUFFER_USAGE_MODE_COMPUTE_STORAGE_READ_WRITE, 8751 vulkanCommandBuffer->readWriteComputeStorageBuffers[i]); 8752 8753 vulkanCommandBuffer->readWriteComputeStorageBuffers[i] = NULL; 8754 } 8755 } 8756 8757 for (i = 0; i < MAX_STORAGE_TEXTURES_PER_STAGE; i += 1) { 8758 if (vulkanCommandBuffer->readOnlyComputeStorageTextures[i] != NULL) { 8759 VULKAN_INTERNAL_TextureTransitionToDefaultUsage( 8760 vulkanCommandBuffer->renderer, 8761 vulkanCommandBuffer, 8762 VULKAN_TEXTURE_USAGE_MODE_COMPUTE_STORAGE_READ, 8763 vulkanCommandBuffer->readOnlyComputeStorageTextures[i]); 8764 8765 vulkanCommandBuffer->readOnlyComputeStorageTextures[i] = NULL; 8766 } 8767 } 8768 8769 for (i = 0; i < MAX_STORAGE_BUFFERS_PER_STAGE; i += 1) { 8770 if (vulkanCommandBuffer->readOnlyComputeStorageBuffers[i] != NULL) { 8771 VULKAN_INTERNAL_BufferTransitionToDefaultUsage( 8772 vulkanCommandBuffer->renderer, 8773 vulkanCommandBuffer, 8774 VULKAN_BUFFER_USAGE_MODE_COMPUTE_STORAGE_READ, 8775 vulkanCommandBuffer->readOnlyComputeStorageBuffers[i]); 8776 8777 vulkanCommandBuffer->readOnlyComputeStorageBuffers[i] = NULL; 8778 } 8779 } 8780 8781 // we don't need a barrier for sampler resources because sampler state is always the default if sampler bit is set 8782 SDL_zeroa(vulkanCommandBuffer->computeSamplerTextureViewBindings); 8783 SDL_zeroa(vulkanCommandBuffer->computeSamplerBindings); 8784 8785 SDL_zeroa(vulkanCommandBuffer->readWriteComputeStorageTextureViewBindings); 8786 SDL_zeroa(vulkanCommandBuffer->readWriteComputeStorageBufferBindings); 8787 8788 vulkanCommandBuffer->currentComputePipeline = NULL; 8789 8790 vulkanCommandBuffer->computeReadOnlyDescriptorSet = VK_NULL_HANDLE; 8791 vulkanCommandBuffer->computeReadWriteDescriptorSet = VK_NULL_HANDLE; 8792 vulkanCommandBuffer->computeUniformDescriptorSet = VK_NULL_HANDLE; 8793} 8794 8795static void *VULKAN_MapTransferBuffer( 8796 SDL_GPURenderer *driverData, 8797 SDL_GPUTransferBuffer *transferBuffer, 8798 bool cycle) 8799{ 8800 VulkanRenderer *renderer = (VulkanRenderer *)driverData; 8801 VulkanBufferContainer *transferBufferContainer = (VulkanBufferContainer *)transferBuffer; 8802 8803 if ( 8804 cycle && 8805 SDL_GetAtomicInt(&transferBufferContainer->activeBuffer->referenceCount) > 0) { 8806 VULKAN_INTERNAL_CycleActiveBuffer( 8807 renderer, 8808 transferBufferContainer); 8809 } 8810 8811 Uint8 *bufferPointer = 8812 transferBufferContainer->activeBuffer->usedRegion->allocation->mapPointer + 8813 transferBufferContainer->activeBuffer->usedRegion->resourceOffset; 8814 8815 return bufferPointer; 8816} 8817 8818static void VULKAN_UnmapTransferBuffer( 8819 SDL_GPURenderer *driverData, 8820 SDL_GPUTransferBuffer *transferBuffer) 8821{ 8822 // no-op because transfer buffers are persistently mapped 8823 (void)driverData; 8824 (void)transferBuffer; 8825} 8826 8827static void VULKAN_BeginCopyPass( 8828 SDL_GPUCommandBuffer *commandBuffer) 8829{ 8830 // no-op 8831 (void)commandBuffer; 8832} 8833 8834static void VULKAN_UploadToTexture( 8835 SDL_GPUCommandBuffer *commandBuffer, 8836 const SDL_GPUTextureTransferInfo *source, 8837 const SDL_GPUTextureRegion *destination, 8838 bool cycle) 8839{ 8840 VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; 8841 VulkanRenderer *renderer = vulkanCommandBuffer->renderer; 8842 VulkanBufferContainer *transferBufferContainer = (VulkanBufferContainer *)source->transfer_buffer; 8843 VulkanTextureContainer *vulkanTextureContainer = (VulkanTextureContainer *)destination->texture; 8844 VulkanTextureSubresource *vulkanTextureSubresource; 8845 VkBufferImageCopy imageCopy; 8846 8847 SDL_LockRWLockForReading(renderer->defragLock); 8848 8849 // Note that the transfer buffer does not need a barrier, as it is synced by the client 8850 vulkanTextureSubresource = VULKAN_INTERNAL_PrepareTextureSubresourceForWrite( 8851 renderer, 8852 vulkanCommandBuffer, 8853 vulkanTextureContainer, 8854 destination->layer, 8855 destination->mip_level, 8856 cycle, 8857 VULKAN_TEXTURE_USAGE_MODE_COPY_DESTINATION); 8858 8859 imageCopy.imageExtent.width = destination->w; 8860 imageCopy.imageExtent.height = destination->h; 8861 imageCopy.imageExtent.depth = destination->d; 8862 imageCopy.imageOffset.x = destination->x; 8863 imageCopy.imageOffset.y = destination->y; 8864 imageCopy.imageOffset.z = destination->z; 8865 imageCopy.imageSubresource.aspectMask = vulkanTextureSubresource->parent->aspectFlags; 8866 imageCopy.imageSubresource.baseArrayLayer = destination->layer; 8867 imageCopy.imageSubresource.layerCount = 1; 8868 imageCopy.imageSubresource.mipLevel = destination->mip_level; 8869 imageCopy.bufferOffset = source->offset; 8870 imageCopy.bufferRowLength = source->pixels_per_row; 8871 imageCopy.bufferImageHeight = source->rows_per_layer; 8872 8873 renderer->vkCmdCopyBufferToImage( 8874 vulkanCommandBuffer->commandBuffer, 8875 transferBufferContainer->activeBuffer->buffer, 8876 vulkanTextureSubresource->parent->image, 8877 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 8878 1, 8879 &imageCopy); 8880 8881 VULKAN_INTERNAL_TextureSubresourceTransitionToDefaultUsage( 8882 renderer, 8883 vulkanCommandBuffer, 8884 VULKAN_TEXTURE_USAGE_MODE_COPY_DESTINATION, 8885 vulkanTextureSubresource); 8886 8887 VULKAN_INTERNAL_TrackBuffer(vulkanCommandBuffer, transferBufferContainer->activeBuffer); 8888 VULKAN_INTERNAL_TrackTexture(vulkanCommandBuffer, vulkanTextureSubresource->parent); 8889 VULKAN_INTERNAL_TrackTextureTransfer(vulkanCommandBuffer, vulkanTextureSubresource->parent); 8890 8891 SDL_UnlockRWLock(renderer->defragLock); 8892} 8893 8894static void VULKAN_UploadToBuffer( 8895 SDL_GPUCommandBuffer *commandBuffer, 8896 const SDL_GPUTransferBufferLocation *source, 8897 const SDL_GPUBufferRegion *destination, 8898 bool cycle) 8899{ 8900 VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; 8901 VulkanRenderer *renderer = vulkanCommandBuffer->renderer; 8902 VulkanBufferContainer *transferBufferContainer = (VulkanBufferContainer *)source->transfer_buffer; 8903 VulkanBufferContainer *bufferContainer = (VulkanBufferContainer *)destination->buffer; 8904 VkBufferCopy bufferCopy; 8905 8906 SDL_LockRWLockForReading(renderer->defragLock); 8907 8908 // Note that the transfer buffer does not need a barrier, as it is synced by the client 8909 VulkanBuffer *vulkanBuffer = VULKAN_INTERNAL_PrepareBufferForWrite( 8910 renderer, 8911 vulkanCommandBuffer, 8912 bufferContainer, 8913 cycle, 8914 VULKAN_BUFFER_USAGE_MODE_COPY_DESTINATION); 8915 8916 8917 bufferCopy.srcOffset = source->offset; 8918 bufferCopy.dstOffset = destination->offset; 8919 bufferCopy.size = destination->size; 8920 8921 renderer->vkCmdCopyBuffer( 8922 vulkanCommandBuffer->commandBuffer, 8923 transferBufferContainer->activeBuffer->buffer, 8924 vulkanBuffer->buffer, 8925 1, 8926 &bufferCopy); 8927 8928 VULKAN_INTERNAL_BufferTransitionToDefaultUsage( 8929 renderer, 8930 vulkanCommandBuffer, 8931 VULKAN_BUFFER_USAGE_MODE_COPY_DESTINATION, 8932 vulkanBuffer); 8933 8934 VULKAN_INTERNAL_TrackBuffer(vulkanCommandBuffer, transferBufferContainer->activeBuffer); 8935 VULKAN_INTERNAL_TrackBuffer(vulkanCommandBuffer, vulkanBuffer); 8936 VULKAN_INTERNAL_TrackBufferTransfer(vulkanCommandBuffer, vulkanBuffer); 8937 8938 SDL_UnlockRWLock(renderer->defragLock); 8939} 8940 8941// Readback 8942 8943static void VULKAN_DownloadFromTexture( 8944 SDL_GPUCommandBuffer *commandBuffer, 8945 const SDL_GPUTextureRegion *source, 8946 const SDL_GPUTextureTransferInfo *destination) 8947{ 8948 VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; 8949 VulkanRenderer *renderer = vulkanCommandBuffer->renderer; 8950 VulkanTextureContainer *textureContainer = (VulkanTextureContainer *)source->texture; 8951 VulkanTextureSubresource *vulkanTextureSubresource; 8952 VulkanBufferContainer *transferBufferContainer = (VulkanBufferContainer *)destination->transfer_buffer; 8953 VkBufferImageCopy imageCopy; 8954 8955 SDL_LockRWLockForReading(renderer->defragLock); 8956 8957 vulkanTextureSubresource = VULKAN_INTERNAL_FetchTextureSubresource( 8958 textureContainer, 8959 source->layer, 8960 source->mip_level); 8961 8962 // Note that the transfer buffer does not need a barrier, as it is synced by the client 8963 8964 VULKAN_INTERNAL_TextureSubresourceTransitionFromDefaultUsage( 8965 renderer, 8966 vulkanCommandBuffer, 8967 VULKAN_TEXTURE_USAGE_MODE_COPY_SOURCE, 8968 vulkanTextureSubresource); 8969 8970 imageCopy.imageExtent.width = source->w; 8971 imageCopy.imageExtent.height = source->h; 8972 imageCopy.imageExtent.depth = source->d; 8973 imageCopy.imageOffset.x = source->x; 8974 imageCopy.imageOffset.y = source->y; 8975 imageCopy.imageOffset.z = source->z; 8976 imageCopy.imageSubresource.aspectMask = vulkanTextureSubresource->parent->aspectFlags; 8977 imageCopy.imageSubresource.baseArrayLayer = source->layer; 8978 imageCopy.imageSubresource.layerCount = 1; 8979 imageCopy.imageSubresource.mipLevel = source->mip_level; 8980 imageCopy.bufferOffset = destination->offset; 8981 imageCopy.bufferRowLength = destination->pixels_per_row; 8982 imageCopy.bufferImageHeight = destination->rows_per_layer; 8983 8984 renderer->vkCmdCopyImageToBuffer( 8985 vulkanCommandBuffer->commandBuffer, 8986 vulkanTextureSubresource->parent->image, 8987 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, 8988 transferBufferContainer->activeBuffer->buffer, 8989 1, 8990 &imageCopy); 8991 8992 VULKAN_INTERNAL_TextureSubresourceTransitionToDefaultUsage( 8993 renderer, 8994 vulkanCommandBuffer, 8995 VULKAN_TEXTURE_USAGE_MODE_COPY_SOURCE, 8996 vulkanTextureSubresource); 8997 8998 VULKAN_INTERNAL_TrackBuffer(vulkanCommandBuffer, transferBufferContainer->activeBuffer); 8999 VULKAN_INTERNAL_TrackTexture(vulkanCommandBuffer, vulkanTextureSubresource->parent); 9000 VULKAN_INTERNAL_TrackTextureTransfer(vulkanCommandBuffer, vulkanTextureSubresource->parent); 9001 9002 SDL_UnlockRWLock(renderer->defragLock); 9003} 9004 9005static void VULKAN_DownloadFromBuffer( 9006 SDL_GPUCommandBuffer *commandBuffer, 9007 const SDL_GPUBufferRegion *source, 9008 const SDL_GPUTransferBufferLocation *destination) 9009{ 9010 VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; 9011 VulkanRenderer *renderer = vulkanCommandBuffer->renderer; 9012 VulkanBufferContainer *bufferContainer = (VulkanBufferContainer *)source->buffer; 9013 VulkanBufferContainer *transferBufferContainer = (VulkanBufferContainer *)destination->transfer_buffer; 9014 VkBufferCopy bufferCopy; 9015 9016 SDL_LockRWLockForReading(renderer->defragLock); 9017 9018 // Note that transfer buffer does not need a barrier, as it is synced by the client 9019 VULKAN_INTERNAL_BufferTransitionFromDefaultUsage( 9020 renderer, 9021 vulkanCommandBuffer, 9022 VULKAN_BUFFER_USAGE_MODE_COPY_SOURCE, 9023 bufferContainer->activeBuffer); 9024 9025 bufferCopy.srcOffset = source->offset; 9026 bufferCopy.dstOffset = destination->offset; 9027 bufferCopy.size = source->size; 9028 9029 renderer->vkCmdCopyBuffer( 9030 vulkanCommandBuffer->commandBuffer, 9031 bufferContainer->activeBuffer->buffer, 9032 transferBufferContainer->activeBuffer->buffer, 9033 1, 9034 &bufferCopy); 9035 9036 VULKAN_INTERNAL_BufferTransitionToDefaultUsage( 9037 renderer, 9038 vulkanCommandBuffer, 9039 VULKAN_BUFFER_USAGE_MODE_COPY_SOURCE, 9040 bufferContainer->activeBuffer); 9041 9042 VULKAN_INTERNAL_TrackBuffer(vulkanCommandBuffer, transferBufferContainer->activeBuffer); 9043 VULKAN_INTERNAL_TrackBuffer(vulkanCommandBuffer, bufferContainer->activeBuffer); 9044 VULKAN_INTERNAL_TrackBufferTransfer(vulkanCommandBuffer, bufferContainer->activeBuffer); 9045 9046 SDL_UnlockRWLock(renderer->defragLock); 9047} 9048 9049static void VULKAN_CopyTextureToTexture( 9050 SDL_GPUCommandBuffer *commandBuffer, 9051 const SDL_GPUTextureLocation *source, 9052 const SDL_GPUTextureLocation *destination, 9053 Uint32 w, 9054 Uint32 h, 9055 Uint32 d, 9056 bool cycle) 9057{ 9058 VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; 9059 VulkanRenderer *renderer = vulkanCommandBuffer->renderer; 9060 VulkanTextureSubresource *srcSubresource; 9061 VulkanTextureSubresource *dstSubresource; 9062 VkImageCopy imageCopy; 9063 9064 SDL_LockRWLockForReading(renderer->defragLock); 9065 9066 srcSubresource = VULKAN_INTERNAL_FetchTextureSubresource( 9067 (VulkanTextureContainer *)source->texture, 9068 source->layer, 9069 source->mip_level); 9070 9071 dstSubresource = VULKAN_INTERNAL_PrepareTextureSubresourceForWrite( 9072 renderer, 9073 vulkanCommandBuffer, 9074 (VulkanTextureContainer *)destination->texture, 9075 destination->layer, 9076 destination->mip_level, 9077 cycle, 9078 VULKAN_TEXTURE_USAGE_MODE_COPY_DESTINATION); 9079 9080 VULKAN_INTERNAL_TextureSubresourceTransitionFromDefaultUsage( 9081 renderer, 9082 vulkanCommandBuffer, 9083 VULKAN_TEXTURE_USAGE_MODE_COPY_SOURCE, 9084 srcSubresource); 9085 9086 imageCopy.srcOffset.x = source->x; 9087 imageCopy.srcOffset.y = source->y; 9088 imageCopy.srcOffset.z = source->z; 9089 imageCopy.srcSubresource.aspectMask = srcSubresource->parent->aspectFlags; 9090 imageCopy.srcSubresource.baseArrayLayer = source->layer; 9091 imageCopy.srcSubresource.layerCount = 1; 9092 imageCopy.srcSubresource.mipLevel = source->mip_level; 9093 imageCopy.dstOffset.x = destination->x; 9094 imageCopy.dstOffset.y = destination->y; 9095 imageCopy.dstOffset.z = destination->z; 9096 imageCopy.dstSubresource.aspectMask = dstSubresource->parent->aspectFlags; 9097 imageCopy.dstSubresource.baseArrayLayer = destination->layer; 9098 imageCopy.dstSubresource.layerCount = 1; 9099 imageCopy.dstSubresource.mipLevel = destination->mip_level; 9100 imageCopy.extent.width = w; 9101 imageCopy.extent.height = h; 9102 imageCopy.extent.depth = d; 9103 9104 renderer->vkCmdCopyImage( 9105 vulkanCommandBuffer->commandBuffer, 9106 srcSubresource->parent->image, 9107 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, 9108 dstSubresource->parent->image, 9109 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 9110 1, 9111 &imageCopy); 9112 9113 VULKAN_INTERNAL_TextureSubresourceTransitionToDefaultUsage( 9114 renderer, 9115 vulkanCommandBuffer, 9116 VULKAN_TEXTURE_USAGE_MODE_COPY_SOURCE, 9117 srcSubresource); 9118 9119 VULKAN_INTERNAL_TextureSubresourceTransitionToDefaultUsage( 9120 renderer, 9121 vulkanCommandBuffer, 9122 VULKAN_TEXTURE_USAGE_MODE_COPY_DESTINATION, 9123 dstSubresource); 9124 9125 VULKAN_INTERNAL_TrackTexture(vulkanCommandBuffer, srcSubresource->parent); 9126 VULKAN_INTERNAL_TrackTexture(vulkanCommandBuffer, dstSubresource->parent); 9127 VULKAN_INTERNAL_TrackTextureTransfer(vulkanCommandBuffer, srcSubresource->parent); 9128 VULKAN_INTERNAL_TrackTextureTransfer(vulkanCommandBuffer, dstSubresource->parent); 9129 9130 SDL_UnlockRWLock(renderer->defragLock); 9131} 9132 9133static void VULKAN_CopyBufferToBuffer( 9134 SDL_GPUCommandBuffer *commandBuffer, 9135 const SDL_GPUBufferLocation *source, 9136 const SDL_GPUBufferLocation *destination, 9137 Uint32 size, 9138 bool cycle) 9139{ 9140 VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; 9141 VulkanRenderer *renderer = vulkanCommandBuffer->renderer; 9142 VulkanBufferContainer *srcContainer = (VulkanBufferContainer *)source->buffer; 9143 VulkanBufferContainer *dstContainer = (VulkanBufferContainer *)destination->buffer; 9144 VkBufferCopy bufferCopy; 9145 9146 SDL_LockRWLockForReading(renderer->defragLock); 9147 9148 VulkanBuffer *dstBuffer = VULKAN_INTERNAL_PrepareBufferForWrite( 9149 renderer, 9150 vulkanCommandBuffer, 9151 dstContainer, 9152 cycle, 9153 VULKAN_BUFFER_USAGE_MODE_COPY_DESTINATION); 9154 9155 VULKAN_INTERNAL_BufferTransitionFromDefaultUsage( 9156 renderer, 9157 vulkanCommandBuffer, 9158 VULKAN_BUFFER_USAGE_MODE_COPY_SOURCE, 9159 srcContainer->activeBuffer); 9160 9161 bufferCopy.srcOffset = source->offset; 9162 bufferCopy.dstOffset = destination->offset; 9163 bufferCopy.size = size; 9164 9165 renderer->vkCmdCopyBuffer( 9166 vulkanCommandBuffer->commandBuffer, 9167 srcContainer->activeBuffer->buffer, 9168 dstBuffer->buffer, 9169 1, 9170 &bufferCopy); 9171 9172 VULKAN_INTERNAL_BufferTransitionToDefaultUsage( 9173 renderer, 9174 vulkanCommandBuffer, 9175 VULKAN_BUFFER_USAGE_MODE_COPY_SOURCE, 9176 srcContainer->activeBuffer); 9177 9178 VULKAN_INTERNAL_BufferTransitionToDefaultUsage( 9179 renderer, 9180 vulkanCommandBuffer, 9181 VULKAN_BUFFER_USAGE_MODE_COPY_DESTINATION, 9182 dstBuffer); 9183 9184 VULKAN_INTERNAL_TrackBuffer(vulkanCommandBuffer, srcContainer->activeBuffer); 9185 VULKAN_INTERNAL_TrackBuffer(vulkanCommandBuffer, dstBuffer); 9186 VULKAN_INTERNAL_TrackBufferTransfer(vulkanCommandBuffer, srcContainer->activeBuffer); 9187 VULKAN_INTERNAL_TrackBufferTransfer(vulkanCommandBuffer, dstBuffer); 9188 9189 SDL_UnlockRWLock(renderer->defragLock); 9190} 9191 9192static void VULKAN_GenerateMipmaps( 9193 SDL_GPUCommandBuffer *commandBuffer, 9194 SDL_GPUTexture *texture) 9195{ 9196 VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; 9197 VulkanRenderer *renderer = vulkanCommandBuffer->renderer; 9198 VulkanTextureContainer *container = (VulkanTextureContainer *)texture; 9199 VulkanTextureSubresource *srcTextureSubresource; 9200 VulkanTextureSubresource *dstTextureSubresource; 9201 VkImageBlit blit; 9202 9203 SDL_LockRWLockForReading(renderer->defragLock); 9204 9205 // Blit each slice sequentially. Barriers, barriers everywhere! 9206 for (Uint32 layerOrDepthIndex = 0; layerOrDepthIndex < container->header.info.layer_count_or_depth; layerOrDepthIndex += 1) { 9207 for (Uint32 level = 1; level < container->header.info.num_levels; level += 1) { 9208 Uint32 layer = container->header.info.type == SDL_GPU_TEXTURETYPE_3D ? 0 : layerOrDepthIndex; 9209 Uint32 depth = container->header.info.type == SDL_GPU_TEXTURETYPE_3D ? layerOrDepthIndex : 0; 9210 9211 Uint32 srcSubresourceIndex = VULKAN_INTERNAL_GetTextureSubresourceIndex( 9212 level - 1, 9213 layer, 9214 container->header.info.num_levels); 9215 Uint32 dstSubresourceIndex = VULKAN_INTERNAL_GetTextureSubresourceIndex( 9216 level, 9217 layer, 9218 container->header.info.num_levels); 9219 9220 srcTextureSubresource = &container->activeTexture->subresources[srcSubresourceIndex]; 9221 dstTextureSubresource = &container->activeTexture->subresources[dstSubresourceIndex]; 9222 9223 VULKAN_INTERNAL_TextureSubresourceTransitionFromDefaultUsage( 9224 renderer, 9225 vulkanCommandBuffer, 9226 VULKAN_TEXTURE_USAGE_MODE_COPY_SOURCE, 9227 srcTextureSubresource); 9228 9229 VULKAN_INTERNAL_TextureSubresourceTransitionFromDefaultUsage( 9230 renderer, 9231 vulkanCommandBuffer, 9232 VULKAN_TEXTURE_USAGE_MODE_COPY_DESTINATION, 9233 dstTextureSubresource); 9234 9235 blit.srcOffsets[0].x = 0; 9236 blit.srcOffsets[0].y = 0; 9237 blit.srcOffsets[0].z = depth; 9238 9239 blit.srcOffsets[1].x = container->header.info.width >> (level - 1); 9240 blit.srcOffsets[1].y = container->header.info.height >> (level - 1); 9241 blit.srcOffsets[1].z = depth + 1; 9242 9243 blit.dstOffsets[0].x = 0; 9244 blit.dstOffsets[0].y = 0; 9245 blit.dstOffsets[0].z = depth; 9246 9247 blit.dstOffsets[1].x = container->header.info.width >> level; 9248 blit.dstOffsets[1].y = container->header.info.height >> level; 9249 blit.dstOffsets[1].z = depth + 1; 9250 9251 blit.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; 9252 blit.srcSubresource.baseArrayLayer = layer; 9253 blit.srcSubresource.layerCount = 1; 9254 blit.srcSubresource.mipLevel = level - 1; 9255 9256 blit.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; 9257 blit.dstSubresource.baseArrayLayer = layer; 9258 blit.dstSubresource.layerCount = 1; 9259 blit.dstSubresource.mipLevel = level; 9260 9261 renderer->vkCmdBlitImage( 9262 vulkanCommandBuffer->commandBuffer, 9263 container->activeTexture->image, 9264 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, 9265 container->activeTexture->image, 9266 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 9267 1, 9268 &blit, 9269 VK_FILTER_LINEAR); 9270 9271 VULKAN_INTERNAL_TextureSubresourceTransitionToDefaultUsage( 9272 renderer, 9273 vulkanCommandBuffer, 9274 VULKAN_TEXTURE_USAGE_MODE_COPY_SOURCE, 9275 srcTextureSubresource); 9276 9277 VULKAN_INTERNAL_TextureSubresourceTransitionToDefaultUsage( 9278 renderer, 9279 vulkanCommandBuffer, 9280 VULKAN_TEXTURE_USAGE_MODE_COPY_DESTINATION, 9281 dstTextureSubresource); 9282 9283 VULKAN_INTERNAL_TrackTexture(vulkanCommandBuffer, srcTextureSubresource->parent); 9284 VULKAN_INTERNAL_TrackTexture(vulkanCommandBuffer, dstTextureSubresource->parent); 9285 VULKAN_INTERNAL_TrackTextureTransfer(vulkanCommandBuffer, srcTextureSubresource->parent); 9286 VULKAN_INTERNAL_TrackTextureTransfer(vulkanCommandBuffer, dstTextureSubresource->parent); 9287 9288 } 9289 } 9290 9291 SDL_UnlockRWLock(renderer->defragLock); 9292} 9293 9294static void VULKAN_EndCopyPass( 9295 SDL_GPUCommandBuffer *commandBuffer) 9296{ 9297 // no-op 9298 (void)commandBuffer; 9299} 9300 9301static void VULKAN_Blit( 9302 SDL_GPUCommandBuffer *commandBuffer, 9303 const SDL_GPUBlitInfo *info) 9304{ 9305 VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; 9306 VulkanRenderer *renderer = vulkanCommandBuffer->renderer; 9307 TextureCommonHeader *srcHeader = (TextureCommonHeader *)info->source.texture; 9308 TextureCommonHeader *dstHeader = (TextureCommonHeader *)info->destination.texture; 9309 VkImageBlit region; 9310 Uint32 srcLayer = srcHeader->info.type == SDL_GPU_TEXTURETYPE_3D ? 0 : info->source.layer_or_depth_plane; 9311 Uint32 srcDepth = srcHeader->info.type == SDL_GPU_TEXTURETYPE_3D ? info->source.layer_or_depth_plane : 0; 9312 Uint32 dstLayer = dstHeader->info.type == SDL_GPU_TEXTURETYPE_3D ? 0 : info->destination.layer_or_depth_plane; 9313 Uint32 dstDepth = dstHeader->info.type == SDL_GPU_TEXTURETYPE_3D ? info->destination.layer_or_depth_plane : 0; 9314 int32_t swap; 9315 9316 // Using BeginRenderPass to clear because vkCmdClearColorImage requires barriers anyway 9317 if (info->load_op == SDL_GPU_LOADOP_CLEAR) { 9318 SDL_GPUColorTargetInfo targetInfo; 9319 SDL_zero(targetInfo); 9320 targetInfo.texture = info->destination.texture; 9321 targetInfo.mip_level = info->destination.mip_level; 9322 targetInfo.layer_or_depth_plane = info->destination.layer_or_depth_plane; 9323 targetInfo.load_op = SDL_GPU_LOADOP_CLEAR; 9324 targetInfo.store_op = SDL_GPU_STOREOP_STORE; 9325 targetInfo.clear_color = info->clear_color; 9326 targetInfo.cycle = info->cycle; 9327 VULKAN_BeginRenderPass( 9328 commandBuffer, 9329 &targetInfo, 9330 1, 9331 NULL); 9332 VULKAN_EndRenderPass(commandBuffer); 9333 } 9334 9335 VulkanTextureSubresource *srcSubresource = VULKAN_INTERNAL_FetchTextureSubresource( 9336 (VulkanTextureContainer *)info->source.texture, 9337 srcLayer, 9338 info->source.mip_level); 9339 9340 VulkanTextureSubresource *dstSubresource = VULKAN_INTERNAL_PrepareTextureSubresourceForWrite( 9341 renderer, 9342 vulkanCommandBuffer, 9343 (VulkanTextureContainer *)info->destination.texture, 9344 dstLayer, 9345 info->destination.mip_level, 9346 info->cycle, 9347 VULKAN_TEXTURE_USAGE_MODE_COPY_DESTINATION); 9348 9349 VULKAN_INTERNAL_TextureSubresourceTransitionFromDefaultUsage( 9350 renderer, 9351 vulkanCommandBuffer, 9352 VULKAN_TEXTURE_USAGE_MODE_COPY_SOURCE, 9353 srcSubresource); 9354 9355 region.srcSubresource.aspectMask = srcSubresource->parent->aspectFlags; 9356 region.srcSubresource.baseArrayLayer = srcSubresource->layer; 9357 region.srcSubresource.layerCount = 1; 9358 region.srcSubresource.mipLevel = srcSubresource->level; 9359 region.srcOffsets[0].x = info->source.x; 9360 region.srcOffsets[0].y = info->source.y; 9361 region.srcOffsets[0].z = srcDepth; 9362 region.srcOffsets[1].x = info->source.x + info->source.w; 9363 region.srcOffsets[1].y = info->source.y + info->source.h; 9364 region.srcOffsets[1].z = srcDepth + 1; 9365 9366 if (info->flip_mode & SDL_FLIP_HORIZONTAL) { 9367 // flip the x positions 9368 swap = region.srcOffsets[0].x; 9369 region.srcOffsets[0].x = region.srcOffsets[1].x; 9370 region.srcOffsets[1].x = swap; 9371 } 9372 9373 if (info->flip_mode & SDL_FLIP_VERTICAL) { 9374 // flip the y positions 9375 swap = region.srcOffsets[0].y; 9376 region.srcOffsets[0].y = region.srcOffsets[1].y; 9377 region.srcOffsets[1].y = swap; 9378 } 9379 9380 region.dstSubresource.aspectMask = dstSubresource->parent->aspectFlags; 9381 region.dstSubresource.baseArrayLayer = dstSubresource->layer; 9382 region.dstSubresource.layerCount = 1; 9383 region.dstSubresource.mipLevel = dstSubresource->level; 9384 region.dstOffsets[0].x = info->destination.x; 9385 region.dstOffsets[0].y = info->destination.y; 9386 region.dstOffsets[0].z = dstDepth; 9387 region.dstOffsets[1].x = info->destination.x + info->destination.w; 9388 region.dstOffsets[1].y = info->destination.y + info->destination.h; 9389 region.dstOffsets[1].z = dstDepth + 1; 9390 9391 renderer->vkCmdBlitImage( 9392 vulkanCommandBuffer->commandBuffer, 9393 srcSubresource->parent->image, 9394 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, 9395 dstSubresource->parent->image, 9396 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 9397 1, 9398 ®ion, 9399 SDLToVK_Filter[info->filter]); 9400 9401 VULKAN_INTERNAL_TextureSubresourceTransitionToDefaultUsage( 9402 renderer, 9403 vulkanCommandBuffer, 9404 VULKAN_TEXTURE_USAGE_MODE_COPY_SOURCE, 9405 srcSubresource); 9406 9407 VULKAN_INTERNAL_TextureSubresourceTransitionToDefaultUsage( 9408 renderer, 9409 vulkanCommandBuffer, 9410 VULKAN_TEXTURE_USAGE_MODE_COPY_DESTINATION, 9411 dstSubresource); 9412 9413 VULKAN_INTERNAL_TrackTexture(vulkanCommandBuffer, srcSubresource->parent); 9414 VULKAN_INTERNAL_TrackTexture(vulkanCommandBuffer, dstSubresource->parent); 9415} 9416 9417static bool VULKAN_INTERNAL_AllocateCommandBuffer( 9418 VulkanRenderer *renderer, 9419 VulkanCommandPool *vulkanCommandPool) 9420{ 9421 VkCommandBufferAllocateInfo allocateInfo; 9422 VkResult vulkanResult; 9423 VkCommandBuffer commandBufferHandle; 9424 VulkanCommandBuffer *commandBuffer; 9425 9426 vulkanCommandPool->inactiveCommandBufferCapacity += 1; 9427 9428 vulkanCommandPool->inactiveCommandBuffers = SDL_realloc( 9429 vulkanCommandPool->inactiveCommandBuffers, 9430 sizeof(VulkanCommandBuffer *) * 9431 vulkanCommandPool->inactiveCommandBufferCapacity); 9432 9433 allocateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; 9434 allocateInfo.pNext = NULL; 9435 allocateInfo.commandPool = vulkanCommandPool->commandPool; 9436 allocateInfo.commandBufferCount = 1; 9437 allocateInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; 9438 9439 vulkanResult = renderer->vkAllocateCommandBuffers( 9440 renderer->logicalDevice, 9441 &allocateInfo, 9442 &commandBufferHandle); 9443 9444 CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkAllocateCommandBuffers, false); 9445 9446 commandBuffer = SDL_malloc(sizeof(VulkanCommandBuffer)); 9447 commandBuffer->renderer = renderer; 9448 commandBuffer->commandPool = vulkanCommandPool; 9449 commandBuffer->commandBuffer = commandBufferHandle; 9450 9451 commandBuffer->inFlightFence = VK_NULL_HANDLE; 9452 9453 // Presentation tracking 9454 9455 commandBuffer->presentDataCapacity = 1; 9456 commandBuffer->presentDataCount = 0; 9457 commandBuffer->presentDatas = SDL_malloc( 9458 commandBuffer->presentDataCapacity * sizeof(VulkanPresentData)); 9459 9460 commandBuffer->waitSemaphoreCapacity = 1; 9461 commandBuffer->waitSemaphoreCount = 0; 9462 commandBuffer->waitSemaphores = SDL_malloc( 9463 commandBuffer->waitSemaphoreCapacity * sizeof(VkSemaphore)); 9464 9465 commandBuffer->signalSemaphoreCapacity = 1; 9466 commandBuffer->signalSemaphoreCount = 0; 9467 commandBuffer->signalSemaphores = SDL_malloc( 9468 commandBuffer->signalSemaphoreCapacity * sizeof(VkSemaphore)); 9469 9470 // Resource bind tracking 9471 9472 commandBuffer->needVertexBufferBind = false; 9473 commandBuffer->needNewVertexResourceDescriptorSet = true; 9474 commandBuffer->needNewVertexUniformDescriptorSet = true; 9475 commandBuffer->needNewVertexUniformOffsets = true; 9476 commandBuffer->needNewFragmentResourceDescriptorSet = true; 9477 commandBuffer->needNewFragmentUniformDescriptorSet = true; 9478 commandBuffer->needNewFragmentUniformOffsets = true; 9479 9480 commandBuffer->needNewComputeReadWriteDescriptorSet = true; 9481 commandBuffer->needNewComputeReadOnlyDescriptorSet = true; 9482 commandBuffer->needNewComputeUniformDescriptorSet = true; 9483 commandBuffer->needNewComputeUniformOffsets = true; 9484 9485 commandBuffer->vertexResourceDescriptorSet = VK_NULL_HANDLE; 9486 commandBuffer->vertexUniformDescriptorSet = VK_NULL_HANDLE; 9487 commandBuffer->fragmentResourceDescriptorSet = VK_NULL_HANDLE; 9488 commandBuffer->fragmentUniformDescriptorSet = VK_NULL_HANDLE; 9489 9490 commandBuffer->computeReadOnlyDescriptorSet = VK_NULL_HANDLE; 9491 commandBuffer->computeReadWriteDescriptorSet = VK_NULL_HANDLE; 9492 commandBuffer->computeUniformDescriptorSet = VK_NULL_HANDLE; 9493 9494 // Resource tracking 9495 9496 commandBuffer->usedBufferCapacity = 4; 9497 commandBuffer->usedBufferCount = 0; 9498 commandBuffer->usedBuffers = SDL_malloc( 9499 commandBuffer->usedBufferCapacity * sizeof(VulkanBuffer *)); 9500 9501 commandBuffer->buffersUsedInPendingTransfersCapacity = 4; 9502 commandBuffer->buffersUsedInPendingTransfersCount = 0; 9503 commandBuffer->buffersUsedInPendingTransfers = SDL_malloc( 9504 commandBuffer->buffersUsedInPendingTransfersCapacity * sizeof(VulkanBuffer *)); 9505 9506 commandBuffer->usedTextureCapacity = 4; 9507 commandBuffer->usedTextureCount = 0; 9508 commandBuffer->usedTextures = SDL_malloc( 9509 commandBuffer->usedTextureCapacity * sizeof(VulkanTexture *)); 9510 9511 commandBuffer->texturesUsedInPendingTransfersCapacity = 4; 9512 commandBuffer->texturesUsedInPendingTransfersCount = 0; 9513 commandBuffer->texturesUsedInPendingTransfers = SDL_malloc( 9514 commandBuffer->texturesUsedInPendingTransfersCapacity * sizeof(VulkanTexture *)); 9515 9516 commandBuffer->usedSamplerCapacity = 4; 9517 commandBuffer->usedSamplerCount = 0; 9518 commandBuffer->usedSamplers = SDL_malloc( 9519 commandBuffer->usedSamplerCapacity * sizeof(VulkanSampler *)); 9520 9521 commandBuffer->usedGraphicsPipelineCapacity = 4; 9522 commandBuffer->usedGraphicsPipelineCount = 0; 9523 commandBuffer->usedGraphicsPipelines = SDL_malloc( 9524 commandBuffer->usedGraphicsPipelineCapacity * sizeof(VulkanGraphicsPipeline *)); 9525 9526 commandBuffer->usedComputePipelineCapacity = 4; 9527 commandBuffer->usedComputePipelineCount = 0; 9528 commandBuffer->usedComputePipelines = SDL_malloc( 9529 commandBuffer->usedComputePipelineCapacity * sizeof(VulkanComputePipeline *)); 9530 9531 commandBuffer->usedFramebufferCapacity = 4; 9532 commandBuffer->usedFramebufferCount = 0; 9533 commandBuffer->usedFramebuffers = SDL_malloc( 9534 commandBuffer->usedFramebufferCapacity * sizeof(VulkanFramebuffer *)); 9535 9536 commandBuffer->usedUniformBufferCapacity = 4; 9537 commandBuffer->usedUniformBufferCount = 0; 9538 commandBuffer->usedUniformBuffers = SDL_malloc( 9539 commandBuffer->usedUniformBufferCapacity * sizeof(VulkanUniformBuffer *)); 9540 9541 commandBuffer->swapchainRequested = false; 9542 9543 // Pool it! 9544 9545 vulkanCommandPool->inactiveCommandBuffers[vulkanCommandPool->inactiveCommandBufferCount] = commandBuffer; 9546 vulkanCommandPool->inactiveCommandBufferCount += 1; 9547 9548 return true; 9549} 9550 9551static VulkanCommandPool *VULKAN_INTERNAL_FetchCommandPool( 9552 VulkanRenderer *renderer, 9553 SDL_ThreadID threadID) 9554{ 9555 VulkanCommandPool *vulkanCommandPool = NULL; 9556 VkCommandPoolCreateInfo commandPoolCreateInfo; 9557 VkResult vulkanResult; 9558 CommandPoolHashTableKey key; 9559 key.threadID = threadID; 9560 9561 bool result = SDL_FindInHashTable( 9562 renderer->commandPoolHashTable, 9563 (const void *)&key, 9564 (const void **)&vulkanCommandPool); 9565 9566 if (result) { 9567 return vulkanCommandPool; 9568 } 9569 9570 vulkanCommandPool = (VulkanCommandPool *)SDL_malloc(sizeof(VulkanCommandPool)); 9571 9572 commandPoolCreateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; 9573 commandPoolCreateInfo.pNext = NULL; 9574 commandPoolCreateInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; 9575 commandPoolCreateInfo.queueFamilyIndex = renderer->queueFamilyIndex; 9576 9577 vulkanResult = renderer->vkCreateCommandPool( 9578 renderer->logicalDevice, 9579 &commandPoolCreateInfo, 9580 NULL, 9581 &vulkanCommandPool->commandPool); 9582 9583 if (vulkanResult != VK_SUCCESS) { 9584 SDL_free(vulkanCommandPool); 9585 CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkCreateCommandPool, NULL); 9586 return NULL; 9587 } 9588 9589 vulkanCommandPool->threadID = threadID; 9590 9591 vulkanCommandPool->inactiveCommandBufferCapacity = 0; 9592 vulkanCommandPool->inactiveCommandBufferCount = 0; 9593 vulkanCommandPool->inactiveCommandBuffers = NULL; 9594 9595 if (!VULKAN_INTERNAL_AllocateCommandBuffer( 9596 renderer, 9597 vulkanCommandPool)) { 9598 VULKAN_INTERNAL_DestroyCommandPool(renderer, vulkanCommandPool); 9599 return NULL; 9600 } 9601 9602 CommandPoolHashTableKey *allocedKey = SDL_malloc(sizeof(CommandPoolHashTableKey)); 9603 allocedKey->threadID = threadID; 9604 9605 SDL_InsertIntoHashTable( 9606 renderer->commandPoolHashTable, 9607 (const void *)allocedKey, 9608 (const void *)vulkanCommandPool, true); 9609 9610 return vulkanCommandPool; 9611} 9612 9613static VulkanCommandBuffer *VULKAN_INTERNAL_GetInactiveCommandBufferFromPool( 9614 VulkanRenderer *renderer, 9615 SDL_ThreadID threadID) 9616{ 9617 VulkanCommandPool *commandPool = 9618 VULKAN_INTERNAL_FetchCommandPool(renderer, threadID); 9619 VulkanCommandBuffer *commandBuffer; 9620 9621 if (commandPool == NULL) { 9622 return NULL; 9623 } 9624 9625 if (commandPool->inactiveCommandBufferCount == 0) { 9626 if (!VULKAN_INTERNAL_AllocateCommandBuffer( 9627 renderer, 9628 commandPool)) { 9629 return NULL; 9630 } 9631 } 9632 9633 commandBuffer = commandPool->inactiveCommandBuffers[commandPool->inactiveCommandBufferCount - 1]; 9634 commandPool->inactiveCommandBufferCount -= 1; 9635 9636 return commandBuffer; 9637} 9638 9639static SDL_GPUCommandBuffer *VULKAN_AcquireCommandBuffer( 9640 SDL_GPURenderer *driverData) 9641{ 9642 VulkanRenderer *renderer = (VulkanRenderer *)driverData; 9643 VkResult result; 9644 Uint32 i; 9645 9646 SDL_ThreadID threadID = SDL_GetCurrentThreadID(); 9647 9648 SDL_LockMutex(renderer->acquireCommandBufferLock); 9649 9650 VulkanCommandBuffer *commandBuffer = 9651 VULKAN_INTERNAL_GetInactiveCommandBufferFromPool(renderer, threadID); 9652 9653 if (commandBuffer == NULL) { 9654 SDL_UnlockMutex(renderer->acquireCommandBufferLock); 9655 return NULL; 9656 } 9657 9658 DescriptorSetCache *descriptorSetCache = 9659 VULKAN_INTERNAL_AcquireDescriptorSetCache(renderer); 9660 9661 SDL_UnlockMutex(renderer->acquireCommandBufferLock); 9662 9663 commandBuffer->descriptorSetCache = descriptorSetCache; 9664 9665 // Reset state 9666 9667 commandBuffer->currentComputePipeline = NULL; 9668 commandBuffer->currentGraphicsPipeline = NULL; 9669 9670 SDL_zeroa(commandBuffer->colorAttachmentSubresources); 9671 SDL_zeroa(commandBuffer->resolveAttachmentSubresources); 9672 commandBuffer->depthStencilAttachmentSubresource = NULL; 9673 commandBuffer->colorAttachmentSubresourceCount = 0; 9674 commandBuffer->resolveAttachmentSubresourceCount = 0; 9675 9676 for (i = 0; i < MAX_UNIFORM_BUFFERS_PER_STAGE; i += 1) { 9677 commandBuffer->vertexUniformBuffers[i] = NULL; 9678 commandBuffer->fragmentUniformBuffers[i] = NULL; 9679 commandBuffer->computeUniformBuffers[i] = NULL; 9680 } 9681 9682 commandBuffer->needVertexBufferBind = false; 9683 commandBuffer->needNewVertexResourceDescriptorSet = true; 9684 commandBuffer->needNewVertexUniformDescriptorSet = true; 9685 commandBuffer->needNewVertexUniformOffsets = true; 9686 commandBuffer->needNewFragmentResourceDescriptorSet = true; 9687 commandBuffer->needNewFragmentUniformDescriptorSet = true; 9688 commandBuffer->needNewFragmentUniformOffsets = true; 9689 9690 commandBuffer->needNewComputeReadOnlyDescriptorSet = true; 9691 commandBuffer->needNewComputeUniformDescriptorSet = true; 9692 commandBuffer->needNewComputeUniformOffsets = true; 9693 9694 commandBuffer->vertexResourceDescriptorSet = VK_NULL_HANDLE; 9695 commandBuffer->vertexUniformDescriptorSet = VK_NULL_HANDLE; 9696 commandBuffer->fragmentResourceDescriptorSet = VK_NULL_HANDLE; 9697 commandBuffer->fragmentUniformDescriptorSet = VK_NULL_HANDLE; 9698 9699 commandBuffer->computeReadOnlyDescriptorSet = VK_NULL_HANDLE; 9700 commandBuffer->computeReadWriteDescriptorSet = VK_NULL_HANDLE; 9701 commandBuffer->computeUniformDescriptorSet = VK_NULL_HANDLE; 9702 9703 SDL_zeroa(commandBuffer->vertexBuffers); 9704 SDL_zeroa(commandBuffer->vertexBufferOffsets); 9705 commandBuffer->vertexBufferCount = 0; 9706 9707 SDL_zeroa(commandBuffer->vertexSamplerTextureViewBindings); 9708 SDL_zeroa(commandBuffer->vertexSamplerBindings); 9709 SDL_zeroa(commandBuffer->vertexStorageTextureViewBindings); 9710 SDL_zeroa(commandBuffer->vertexStorageBufferBindings); 9711 9712 SDL_zeroa(commandBuffer->fragmentSamplerTextureViewBindings); 9713 SDL_zeroa(commandBuffer->fragmentSamplerBindings); 9714 SDL_zeroa(commandBuffer->fragmentStorageTextureViewBindings); 9715 SDL_zeroa(commandBuffer->fragmentStorageBufferBindings); 9716 9717 SDL_zeroa(commandBuffer->readWriteComputeStorageTextureSubresources); 9718 commandBuffer->readWriteComputeStorageTextureSubresourceCount = 0; 9719 SDL_zeroa(commandBuffer->readWriteComputeStorageBuffers); 9720 SDL_zeroa(commandBuffer->computeSamplerTextureViewBindings); 9721 SDL_zeroa(commandBuffer->computeSamplerBindings); 9722 SDL_zeroa(commandBuffer->readOnlyComputeStorageTextureViewBindings); 9723 SDL_zeroa(commandBuffer->readOnlyComputeStorageBufferBindings); 9724 SDL_zeroa(commandBuffer->readOnlyComputeStorageTextures); 9725 SDL_zeroa(commandBuffer->readOnlyComputeStorageBuffers); 9726 9727 commandBuffer->autoReleaseFence = true; 9728 9729 commandBuffer->swapchainRequested = false; 9730 commandBuffer->isDefrag = 0; 9731 9732 /* Reset the command buffer here to avoid resets being called 9733 * from a separate thread than where the command buffer was acquired 9734 */ 9735 result = renderer->vkResetCommandBuffer( 9736 commandBuffer->commandBuffer, 9737 VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT); 9738 9739 CHECK_VULKAN_ERROR_AND_RETURN(result, vkResetCommandBuffer, NULL); 9740 9741 if (!VULKAN_INTERNAL_BeginCommandBuffer(renderer, commandBuffer)) { 9742 return NULL; 9743 } 9744 9745 return (SDL_GPUCommandBuffer *)commandBuffer; 9746} 9747 9748static bool VULKAN_QueryFence( 9749 SDL_GPURenderer *driverData, 9750 SDL_GPUFence *fence) 9751{ 9752 VulkanRenderer *renderer = (VulkanRenderer *)driverData; 9753 VkResult result; 9754 9755 result = renderer->vkGetFenceStatus( 9756 renderer->logicalDevice, 9757 ((VulkanFenceHandle *)fence)->fence); 9758 9759 if (result == VK_SUCCESS) { 9760 return true; 9761 } else if (result == VK_NOT_READY) { 9762 return false; 9763 } else { 9764 SET_ERROR_AND_RETURN("vkGetFenceStatus: %s", VkErrorMessages(result), false); 9765 } 9766} 9767 9768static void VULKAN_INTERNAL_ReturnFenceToPool( 9769 VulkanRenderer *renderer, 9770 VulkanFenceHandle *fenceHandle) 9771{ 9772 SDL_LockMutex(renderer->fencePool.lock); 9773 9774 EXPAND_ARRAY_IF_NEEDED( 9775 renderer->fencePool.availableFences, 9776 VulkanFenceHandle *, 9777 renderer->fencePool.availableFenceCount + 1, 9778 renderer->fencePool.availableFenceCapacity, 9779 renderer->fencePool.availableFenceCapacity * 2); 9780 9781 renderer->fencePool.availableFences[renderer->fencePool.availableFenceCount] = fenceHandle; 9782 renderer->fencePool.availableFenceCount += 1; 9783 9784 SDL_UnlockMutex(renderer->fencePool.lock); 9785} 9786 9787static void VULKAN_ReleaseFence( 9788 SDL_GPURenderer *driverData, 9789 SDL_GPUFence *fence) 9790{ 9791 VulkanFenceHandle *handle = (VulkanFenceHandle *)fence; 9792 9793 if (SDL_AtomicDecRef(&handle->referenceCount)) { 9794 VULKAN_INTERNAL_ReturnFenceToPool((VulkanRenderer *)driverData, handle); 9795 } 9796} 9797 9798static WindowData *VULKAN_INTERNAL_FetchWindowData( 9799 SDL_Window *window) 9800{ 9801 SDL_PropertiesID properties = SDL_GetWindowProperties(window); 9802 return (WindowData *)SDL_GetPointerProperty(properties, WINDOW_PROPERTY_DATA, NULL); 9803} 9804 9805static bool VULKAN_INTERNAL_OnWindowResize(void *userdata, SDL_Event *e) 9806{ 9807 SDL_Window *w = (SDL_Window *)userdata; 9808 WindowData *data; 9809 if (e->type == SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED && e->window.windowID == SDL_GetWindowID(w)) { 9810 data = VULKAN_INTERNAL_FetchWindowData(w); 9811 data->needsSwapchainRecreate = true; 9812 data->swapchainCreateWidth = e->window.data1; 9813 data->swapchainCreateHeight = e->window.data2; 9814 } 9815 9816 return true; 9817} 9818 9819static bool VULKAN_SupportsSwapchainComposition( 9820 SDL_GPURenderer *driverData, 9821 SDL_Window *window, 9822 SDL_GPUSwapchainComposition swapchainComposition) 9823{ 9824 VulkanRenderer *renderer = (VulkanRenderer *)driverData; 9825 WindowData *windowData = VULKAN_INTERNAL_FetchWindowData(window); 9826 VkSurfaceKHR surface; 9827 SwapchainSupportDetails supportDetails; 9828 bool result = false; 9829 9830 if (windowData == NULL) { 9831 SET_STRING_ERROR_AND_RETURN("Must claim window before querying swapchain composition support!", false); 9832 } 9833 9834 surface = windowData->surface; 9835 if (!surface) { 9836 SET_STRING_ERROR_AND_RETURN("Window has no Vulkan surface", false); 9837 } 9838 9839 if (VULKAN_INTERNAL_QuerySwapchainSupport( 9840 renderer, 9841 renderer->physicalDevice, 9842 surface, 9843 &supportDetails)) { 9844 9845 result = VULKAN_INTERNAL_VerifySwapSurfaceFormat( 9846 SwapchainCompositionToFormat[swapchainComposition], 9847 SwapchainCompositionToColorSpace[swapchainComposition], 9848 supportDetails.formats, 9849 supportDetails.formatsLength); 9850 9851 if (!result) { 9852 // Let's try again with the fallback format... 9853 result = VULKAN_INTERNAL_VerifySwapSurfaceFormat( 9854 SwapchainCompositionToFallbackFormat[swapchainComposition], 9855 SwapchainCompositionToColorSpace[swapchainComposition], 9856 supportDetails.formats, 9857 supportDetails.formatsLength); 9858 } 9859 9860 SDL_free(supportDetails.formats); 9861 SDL_free(supportDetails.presentModes); 9862 } 9863 9864 return result; 9865} 9866 9867static bool VULKAN_SupportsPresentMode( 9868 SDL_GPURenderer *driverData, 9869 SDL_Window *window, 9870 SDL_GPUPresentMode presentMode) 9871{ 9872 VulkanRenderer *renderer = (VulkanRenderer *)driverData; 9873 WindowData *windowData = VULKAN_INTERNAL_FetchWindowData(window); 9874 VkSurfaceKHR surface; 9875 SwapchainSupportDetails supportDetails; 9876 bool result = false; 9877 9878 if (windowData == NULL) { 9879 SET_STRING_ERROR_AND_RETURN("Must claim window before querying present mode support!", false); 9880 } 9881 9882 surface = windowData->surface; 9883 if (!surface) { 9884 SET_STRING_ERROR_AND_RETURN("Window has no Vulkan surface", false); 9885 } 9886 9887 if (VULKAN_INTERNAL_QuerySwapchainSupport( 9888 renderer, 9889 renderer->physicalDevice, 9890 surface, 9891 &supportDetails)) { 9892 9893 result = VULKAN_INTERNAL_VerifySwapPresentMode( 9894 SDLToVK_PresentMode[presentMode], 9895 supportDetails.presentModes, 9896 supportDetails.presentModesLength); 9897 9898 SDL_free(supportDetails.formats); 9899 SDL_free(supportDetails.presentModes); 9900 } 9901 9902 return result; 9903} 9904 9905static bool VULKAN_ClaimWindow( 9906 SDL_GPURenderer *driverData, 9907 SDL_Window *window) 9908{ 9909 VulkanRenderer *renderer = (VulkanRenderer *)driverData; 9910 WindowData *windowData = VULKAN_INTERNAL_FetchWindowData(window); 9911 9912 if (windowData == NULL) { 9913 windowData = (WindowData *)SDL_calloc(1, sizeof(WindowData)); 9914 if (!windowData) { 9915 return false; 9916 } 9917 windowData->window = window; 9918 windowData->renderer = renderer; 9919 windowData->refcount = 1; 9920 windowData->presentMode = SDL_GPU_PRESENTMODE_VSYNC; 9921 windowData->swapchainComposition = SDL_GPU_SWAPCHAINCOMPOSITION_SDR; 9922 9923 // On non-Apple platforms the swapchain capability currentExtent can be different from the window, 9924 // so we have to query the window size. 9925#ifndef SDL_PLATFORM_APPLE 9926 int w, h; 9927 SDL_SyncWindow(window); 9928 SDL_GetWindowSizeInPixels(window, &w, &h); 9929 windowData->swapchainCreateWidth = w; 9930 windowData->swapchainCreateHeight = h; 9931#endif 9932 9933 SDL_VideoDevice *videoDevice = SDL_GetVideoDevice(); 9934 if (!videoDevice) { 9935 SDL_free(windowData); 9936 return SDL_SetError("No video device found"); 9937 } 9938 9939 if (!videoDevice->Vulkan_CreateSurface) { 9940 SDL_free(windowData); 9941 return SDL_SetError("Video device does not implement Vulkan_CreateSurface"); 9942 } 9943 9944 // Each window must have its own surface. 9945 if (!videoDevice->Vulkan_CreateSurface( 9946 videoDevice, 9947 windowData->window, 9948 renderer->instance, 9949 NULL, // FIXME: VAllocationCallbacks 9950 &windowData->surface)) { 9951 SDL_free(windowData); 9952 return false; 9953 } 9954 9955 Uint32 createSwapchainResult = VULKAN_INTERNAL_CreateSwapchain(renderer, windowData); 9956 if (createSwapchainResult == 1) { 9957 SDL_SetPointerProperty(SDL_GetWindowProperties(window), WINDOW_PROPERTY_DATA, windowData); 9958 9959 SDL_LockMutex(renderer->windowLock); 9960 if (renderer->claimedWindowCount >= renderer->claimedWindowCapacity) { 9961 renderer->claimedWindowCapacity *= 2; 9962 renderer->claimedWindows = SDL_realloc( 9963 renderer->claimedWindows, 9964 renderer->claimedWindowCapacity * sizeof(WindowData *)); 9965 } 9966 9967 renderer->claimedWindows[renderer->claimedWindowCount] = windowData; 9968 renderer->claimedWindowCount += 1; 9969 SDL_UnlockMutex(renderer->windowLock); 9970 9971 SDL_AddWindowEventWatch(SDL_WINDOW_EVENT_WATCH_NORMAL, VULKAN_INTERNAL_OnWindowResize, window); 9972 9973 return true; 9974 } else if (createSwapchainResult == VULKAN_INTERNAL_TRY_AGAIN) { 9975 windowData->needsSwapchainRecreate = true; 9976 return true; 9977 } else { 9978 // Failed to create swapchain, destroy surface and free data 9979 renderer->vkDestroySurfaceKHR( 9980 renderer->instance, 9981 windowData->surface, 9982 NULL); 9983 SDL_free(windowData); 9984 return false; 9985 } 9986 } else if (windowData->renderer == renderer) { 9987 ++windowData->refcount; 9988 return true; 9989 } else { 9990 SET_STRING_ERROR_AND_RETURN("Window already claimed", false); 9991 } 9992} 9993 9994static void VULKAN_ReleaseWindow( 9995 SDL_GPURenderer *driverData, 9996 SDL_Window *window) 9997{ 9998 VulkanRenderer *renderer = (VulkanRenderer *)driverData; 9999 WindowData *windowData = VULKAN_INTERNAL_FetchWindowData(window); 10000 Uint32 i; 10001 10002 if (windowData == NULL) { 10003 return; 10004 } 10005 if (windowData->renderer != renderer) { 10006 SDL_SetError("Window not claimed by this device"); 10007 return; 10008 } 10009 if (windowData->refcount > 1) { 10010 --windowData->refcount; 10011 return; 10012 } 10013 10014 VULKAN_Wait(driverData); 10015 10016 for (i = 0; i < MAX_FRAMES_IN_FLIGHT; i += 1) { 10017 if (windowData->inFlightFences[i] != NULL) { 10018 VULKAN_ReleaseFence( 10019 driverData, 10020 windowData->inFlightFences[i]); 10021 } 10022 } 10023 10024 VULKAN_INTERNAL_DestroySwapchain( 10025 (VulkanRenderer *)driverData, 10026 windowData); 10027 10028 renderer->vkDestroySurfaceKHR( 10029 renderer->instance, 10030 windowData->surface, 10031 NULL); 10032 windowData->surface = VK_NULL_HANDLE; 10033 10034 SDL_LockMutex(renderer->windowLock); 10035 for (i = 0; i < renderer->claimedWindowCount; i += 1) { 10036 if (renderer->claimedWindows[i]->window == window) { 10037 renderer->claimedWindows[i] = renderer->claimedWindows[renderer->claimedWindowCount - 1]; 10038 renderer->claimedWindowCount -= 1; 10039 break; 10040 } 10041 } 10042 SDL_UnlockMutex(renderer->windowLock); 10043 10044 SDL_free(windowData); 10045 10046 SDL_ClearProperty(SDL_GetWindowProperties(window), WINDOW_PROPERTY_DATA); 10047 SDL_RemoveWindowEventWatch(SDL_WINDOW_EVENT_WATCH_NORMAL, VULKAN_INTERNAL_OnWindowResize, window); 10048} 10049 10050static Uint32 VULKAN_INTERNAL_RecreateSwapchain( 10051 VulkanRenderer *renderer, 10052 WindowData *windowData) 10053{ 10054 Uint32 i; 10055 10056 if (!VULKAN_Wait((SDL_GPURenderer *)renderer)) { 10057 return false; 10058 } 10059 10060 for (i = 0; i < MAX_FRAMES_IN_FLIGHT; i += 1) { 10061 if (windowData->inFlightFences[i] != NULL) { 10062 VULKAN_ReleaseFence( 10063 (SDL_GPURenderer *)renderer, 10064 windowData->inFlightFences[i]); 10065 windowData->inFlightFences[i] = NULL; 10066 } 10067 } 10068 10069#ifdef SDL_VIDEO_DRIVER_PRIVATE 10070 // Private platforms also invalidate the window, so don't try to preserve the surface/swapchain 10071 VULKAN_INTERNAL_DestroySwapchain(renderer, windowData); 10072#else 10073 VULKAN_INTERNAL_DestroySwapchainImage(renderer, windowData); 10074#endif 10075 return VULKAN_INTERNAL_CreateSwapchain(renderer, windowData); 10076} 10077 10078static bool VULKAN_WaitForSwapchain( 10079 SDL_GPURenderer *driverData, 10080 SDL_Window *window) 10081{ 10082 VulkanRenderer *renderer = (VulkanRenderer *)driverData; 10083 WindowData *windowData = VULKAN_INTERNAL_FetchWindowData(window); 10084 10085 if (windowData == NULL) { 10086 SET_STRING_ERROR_AND_RETURN("Cannot wait for a swapchain from an unclaimed window!", false); 10087 } 10088 10089 if (windowData->inFlightFences[windowData->frameCounter] != NULL) { 10090 if (!VULKAN_WaitForFences( 10091 driverData, 10092 true, 10093 &windowData->inFlightFences[windowData->frameCounter], 10094 1)) { 10095 return false; 10096 } 10097 } 10098 10099 return true; 10100} 10101 10102static bool VULKAN_INTERNAL_AcquireSwapchainTexture( 10103 bool block, 10104 SDL_GPUCommandBuffer *commandBuffer, 10105 SDL_Window *window, 10106 SDL_GPUTexture **swapchainTexture, 10107 Uint32 *swapchainTextureWidth, 10108 Uint32 *swapchainTextureHeight) 10109{ 10110 VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; 10111 VulkanRenderer *renderer = vulkanCommandBuffer->renderer; 10112 Uint32 swapchainImageIndex; 10113 WindowData *windowData; 10114 VkResult acquireResult = VK_SUCCESS; 10115 VulkanTextureContainer *swapchainTextureContainer = NULL; 10116 VulkanPresentData *presentData; 10117 10118 *swapchainTexture = NULL; 10119 if (swapchainTextureWidth) { 10120 *swapchainTextureWidth = 0; 10121 } 10122 if (swapchainTextureHeight) { 10123 *swapchainTextureHeight = 0; 10124 } 10125 10126 windowData = VULKAN_INTERNAL_FetchWindowData(window); 10127 if (windowData == NULL) { 10128 SET_STRING_ERROR_AND_RETURN("Cannot acquire a swapchain texture from an unclaimed window!", false); 10129 } 10130 10131 // The command buffer is flagged for cleanup when the swapchain is requested as a cleanup timing mechanism 10132 vulkanCommandBuffer->swapchainRequested = true; 10133 10134 if (window->flags & SDL_WINDOW_HIDDEN) { 10135 // Edge case, texture is filled in with NULL but not an error 10136 return true; 10137 } 10138 10139 if (windowData->needsSurfaceRecreate) { 10140 SDL_VideoDevice *videoDevice = SDL_GetVideoDevice(); 10141 SDL_assert(videoDevice); 10142 SDL_assert(videoDevice->Vulkan_CreateSurface); 10143 renderer->vkDestroySurfaceKHR( 10144 renderer->instance, 10145 windowData->surface, 10146 NULL); 10147 if (!videoDevice->Vulkan_CreateSurface( 10148 videoDevice, 10149 windowData->window, 10150 renderer->instance, 10151 NULL, // FIXME: VAllocationCallbacks 10152 &windowData->surface)) { 10153 SET_STRING_ERROR_AND_RETURN("Failed to recreate Vulkan surface!", false); 10154 } 10155 } 10156 10157 // If window data marked as needing swapchain recreate, try to recreate 10158 if (windowData->needsSwapchainRecreate) { 10159 Uint32 recreateSwapchainResult = VULKAN_INTERNAL_RecreateSwapchain(renderer, windowData); 10160 if (!recreateSwapchainResult) { 10161 return false; 10162 } else if (recreateSwapchainResult == VULKAN_INTERNAL_TRY_AGAIN) { 10163 // Edge case, texture is filled in with NULL but not an error 10164 if (windowData->inFlightFences[windowData->frameCounter] != NULL) { 10165 VULKAN_ReleaseFence( 10166 (SDL_GPURenderer *)renderer, 10167 windowData->inFlightFences[windowData->frameCounter]); 10168 windowData->inFlightFences[windowData->frameCounter] = NULL; 10169 } 10170 return true; 10171 } 10172 10173 // Unset this flag until after the swapchain has been recreated to let VULKAN_INTERNAL_CreateSwapchain() 10174 // know whether it needs to pass the old swapchain or not. 10175 windowData->needsSurfaceRecreate = false; 10176 } 10177 10178 if (windowData->inFlightFences[windowData->frameCounter] != NULL) { 10179 if (block) { 10180 // If we are blocking, just wait for the fence! 10181 if (!VULKAN_WaitForFences( 10182 (SDL_GPURenderer *)renderer, 10183 true, 10184 &windowData->inFlightFences[windowData->frameCounter], 10185 1)) { 10186 return false; 10187 } 10188 } else { 10189 // If we are not blocking and the least recent fence is not signaled, 10190 // return true to indicate that there is no error but rendering should be skipped. 10191 if (!VULKAN_QueryFence( 10192 (SDL_GPURenderer *)renderer, 10193 windowData->inFlightFences[windowData->frameCounter])) { 10194 return true; 10195 } 10196 } 10197 10198 VULKAN_ReleaseFence( 10199 (SDL_GPURenderer *)renderer, 10200 windowData->inFlightFences[windowData->frameCounter]); 10201 10202 windowData->inFlightFences[windowData->frameCounter] = NULL; 10203 } 10204 10205 // Finally, try to acquire! 10206 while (true) { 10207 acquireResult = renderer->vkAcquireNextImageKHR( 10208 renderer->logicalDevice, 10209 windowData->swapchain, 10210 SDL_MAX_UINT64, 10211 windowData->imageAvailableSemaphore[windowData->frameCounter], 10212 VK_NULL_HANDLE, 10213 &swapchainImageIndex); 10214 10215 if (acquireResult == VK_SUCCESS || acquireResult == VK_SUBOPTIMAL_KHR) { 10216 break; // we got the next image! 10217 } 10218 10219 // Surface lost — flag for surface + swapchain recreation on next call 10220 if (acquireResult == VK_ERROR_SURFACE_LOST_KHR) { 10221 windowData->needsSurfaceRecreate = true; 10222 windowData->needsSwapchainRecreate = true; 10223 return true; 10224 } 10225 10226 // If acquisition is invalid, let's try to recreate 10227 Uint32 recreateSwapchainResult = VULKAN_INTERNAL_RecreateSwapchain(renderer, windowData); 10228 if (!recreateSwapchainResult) { 10229 return false; 10230 } else if (recreateSwapchainResult == VULKAN_INTERNAL_TRY_AGAIN) { 10231 // Edge case, texture is filled in with NULL but not an error 10232 return true; 10233 } 10234 } 10235 10236 if (swapchainTextureWidth) { 10237 *swapchainTextureWidth = windowData->width; 10238 } 10239 10240 if (swapchainTextureHeight) { 10241 *swapchainTextureHeight = windowData->height; 10242 } 10243 10244 swapchainTextureContainer = &windowData->textureContainers[swapchainImageIndex]; 10245 10246 // We need a special execution dependency with pWaitDstStageMask or image transition can start before acquire finishes 10247 10248 VkImageMemoryBarrier imageBarrier; 10249 imageBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; 10250 imageBarrier.pNext = NULL; 10251 imageBarrier.srcAccessMask = 0; 10252 imageBarrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; 10253 imageBarrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; 10254 imageBarrier.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; 10255 imageBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; 10256 imageBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; 10257 imageBarrier.image = swapchainTextureContainer->activeTexture->image; 10258 imageBarrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; 10259 imageBarrier.subresourceRange.baseMipLevel = 0; 10260 imageBarrier.subresourceRange.levelCount = 1; 10261 imageBarrier.subresourceRange.baseArrayLayer = 0; 10262 imageBarrier.subresourceRange.layerCount = 1; 10263 10264 renderer->vkCmdPipelineBarrier( 10265 vulkanCommandBuffer->commandBuffer, 10266 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 10267 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 10268 0, 10269 0, 10270 NULL, 10271 0, 10272 NULL, 10273 1, 10274 &imageBarrier); 10275 10276 // Set up present struct 10277 10278 if (vulkanCommandBuffer->presentDataCount == vulkanCommandBuffer->presentDataCapacity) { 10279 vulkanCommandBuffer->presentDataCapacity += 1; 10280 vulkanCommandBuffer->presentDatas = SDL_realloc( 10281 vulkanCommandBuffer->presentDatas, 10282 vulkanCommandBuffer->presentDataCapacity * sizeof(VulkanPresentData)); 10283 } 10284 10285 presentData = &vulkanCommandBuffer->presentDatas[vulkanCommandBuffer->presentDataCount]; 10286 vulkanCommandBuffer->presentDataCount += 1; 10287 10288 presentData->windowData = windowData; 10289 presentData->swapchainImageIndex = swapchainImageIndex; 10290 10291 // Set up present semaphores 10292 10293 if (vulkanCommandBuffer->waitSemaphoreCount == vulkanCommandBuffer->waitSemaphoreCapacity) { 10294 vulkanCommandBuffer->waitSemaphoreCapacity += 1; 10295 vulkanCommandBuffer->waitSemaphores = SDL_realloc( 10296 vulkanCommandBuffer->waitSemaphores, 10297 vulkanCommandBuffer->waitSemaphoreCapacity * sizeof(VkSemaphore)); 10298 } 10299 10300 vulkanCommandBuffer->waitSemaphores[vulkanCommandBuffer->waitSemaphoreCount] = 10301 windowData->imageAvailableSemaphore[windowData->frameCounter]; 10302 vulkanCommandBuffer->waitSemaphoreCount += 1; 10303 10304 if (vulkanCommandBuffer->signalSemaphoreCount == vulkanCommandBuffer->signalSemaphoreCapacity) { 10305 vulkanCommandBuffer->signalSemaphoreCapacity += 1; 10306 vulkanCommandBuffer->signalSemaphores = SDL_realloc( 10307 vulkanCommandBuffer->signalSemaphores, 10308 vulkanCommandBuffer->signalSemaphoreCapacity * sizeof(VkSemaphore)); 10309 } 10310 10311 vulkanCommandBuffer->signalSemaphores[vulkanCommandBuffer->signalSemaphoreCount] = 10312 windowData->renderFinishedSemaphore[swapchainImageIndex]; 10313 vulkanCommandBuffer->signalSemaphoreCount += 1; 10314 10315 *swapchainTexture = (SDL_GPUTexture *)swapchainTextureContainer; 10316 return true; 10317} 10318 10319static bool VULKAN_AcquireSwapchainTexture( 10320 SDL_GPUCommandBuffer *command_buffer, 10321 SDL_Window *window, 10322 SDL_GPUTexture **swapchain_texture, 10323 Uint32 *swapchain_texture_width, 10324 Uint32 *swapchain_texture_height 10325) { 10326 return VULKAN_INTERNAL_AcquireSwapchainTexture( 10327 false, 10328 command_buffer, 10329 window, 10330 swapchain_texture, 10331 swapchain_texture_width, 10332 swapchain_texture_height); 10333} 10334 10335static bool VULKAN_WaitAndAcquireSwapchainTexture( 10336 SDL_GPUCommandBuffer *command_buffer, 10337 SDL_Window *window, 10338 SDL_GPUTexture **swapchain_texture, 10339 Uint32 *swapchain_texture_width, 10340 Uint32 *swapchain_texture_height 10341) { 10342 return VULKAN_INTERNAL_AcquireSwapchainTexture( 10343 true, 10344 command_buffer, 10345 window, 10346 swapchain_texture, 10347 swapchain_texture_width, 10348 swapchain_texture_height); 10349} 10350 10351static SDL_GPUTextureFormat VULKAN_GetSwapchainTextureFormat( 10352 SDL_GPURenderer *driverData, 10353 SDL_Window *window) 10354{ 10355 VulkanRenderer *renderer = (VulkanRenderer *)driverData; 10356 WindowData *windowData = VULKAN_INTERNAL_FetchWindowData(window); 10357 10358 if (windowData == NULL) { 10359 SET_STRING_ERROR_AND_RETURN("Cannot get swapchain format, window has not been claimed!", SDL_GPU_TEXTUREFORMAT_INVALID); 10360 } 10361 10362 return SwapchainCompositionToSDLFormat( 10363 windowData->swapchainComposition, 10364 windowData->usingFallbackFormat); 10365} 10366 10367static bool VULKAN_SetSwapchainParameters( 10368 SDL_GPURenderer *driverData, 10369 SDL_Window *window, 10370 SDL_GPUSwapchainComposition swapchainComposition, 10371 SDL_GPUPresentMode presentMode) 10372{ 10373 VulkanRenderer *renderer = (VulkanRenderer *)driverData; 10374 WindowData *windowData = VULKAN_INTERNAL_FetchWindowData(window); 10375 10376 if (windowData == NULL) { 10377 SET_STRING_ERROR_AND_RETURN("Cannot set swapchain parameters on unclaimed window!", false); 10378 } 10379 10380 if (!VULKAN_SupportsSwapchainComposition(driverData, window, swapchainComposition)) { 10381 SET_STRING_ERROR_AND_RETURN("Swapchain composition not supported!", false); 10382 } 10383 10384 if (!VULKAN_SupportsPresentMode(driverData, window, presentMode)) { 10385 SET_STRING_ERROR_AND_RETURN("Present mode not supported!", false); 10386 } 10387 10388 windowData->presentMode = presentMode; 10389 windowData->swapchainComposition = swapchainComposition; 10390 10391 Uint32 recreateSwapchainResult = VULKAN_INTERNAL_RecreateSwapchain(renderer, windowData); 10392 if (!recreateSwapchainResult) { 10393 return false; 10394 } else if (recreateSwapchainResult == VULKAN_INTERNAL_TRY_AGAIN) { 10395 // Edge case, swapchain extent is (0, 0) but this is not an error 10396 windowData->needsSwapchainRecreate = true; 10397 return true; 10398 } 10399 10400 return true; 10401} 10402 10403static bool VULKAN_SetAllowedFramesInFlight( 10404 SDL_GPURenderer *driverData, 10405 Uint32 allowedFramesInFlight) 10406{ 10407 VulkanRenderer *renderer = (VulkanRenderer *)driverData; 10408 10409 renderer->allowedFramesInFlight = allowedFramesInFlight; 10410 10411 for (Uint32 i = 0; i < renderer->claimedWindowCount; i += 1) { 10412 WindowData *windowData = renderer->claimedWindows[i]; 10413 10414 Uint32 recreateResult = VULKAN_INTERNAL_RecreateSwapchain(renderer, windowData); 10415 if (!recreateResult) { 10416 return false; 10417 } else if (recreateResult == VULKAN_INTERNAL_TRY_AGAIN) { 10418 // Edge case, swapchain extent is (0, 0) but this is not an error 10419 windowData->needsSwapchainRecreate = true; 10420 } 10421 } 10422 10423 return true; 10424} 10425 10426// Submission structure 10427 10428static VulkanFenceHandle *VULKAN_INTERNAL_AcquireFenceFromPool( 10429 VulkanRenderer *renderer) 10430{ 10431 VulkanFenceHandle *handle; 10432 VkFenceCreateInfo fenceCreateInfo; 10433 VkFence fence; 10434 VkResult vulkanResult; 10435 10436 if (renderer->fencePool.availableFenceCount == 0) { 10437 // Create fence 10438 fenceCreateInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; 10439 fenceCreateInfo.pNext = NULL; 10440 fenceCreateInfo.flags = 0; 10441 10442 vulkanResult = renderer->vkCreateFence( 10443 renderer->logicalDevice, 10444 &fenceCreateInfo, 10445 NULL, 10446 &fence); 10447 10448 CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkCreateFence, NULL); 10449 10450 handle = SDL_malloc(sizeof(VulkanFenceHandle)); 10451 handle->fence = fence; 10452 SDL_SetAtomicInt(&handle->referenceCount, 0); 10453 return handle; 10454 } 10455 10456 SDL_LockMutex(renderer->fencePool.lock); 10457 10458 handle = renderer->fencePool.availableFences[renderer->fencePool.availableFenceCount - 1]; 10459 renderer->fencePool.availableFenceCount -= 1; 10460 10461 vulkanResult = renderer->vkResetFences( 10462 renderer->logicalDevice, 10463 1, 10464 &handle->fence); 10465 10466 SDL_UnlockMutex(renderer->fencePool.lock); 10467 10468 CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkResetFences, NULL); 10469 10470 return handle; 10471} 10472 10473static void VULKAN_INTERNAL_PerformPendingDestroys( 10474 VulkanRenderer *renderer) 10475{ 10476 SDL_LockMutex(renderer->disposeLock); 10477 10478 for (Sint32 i = renderer->texturesToDestroyCount - 1; i >= 0; i -= 1) { 10479 if (SDL_GetAtomicInt(&renderer->texturesToDestroy[i]->referenceCount) == 0) { 10480 VULKAN_INTERNAL_DestroyTexture( 10481 renderer, 10482 renderer->texturesToDestroy[i]); 10483 10484 renderer->texturesToDestroy[i] = renderer->texturesToDestroy[renderer->texturesToDestroyCount - 1]; 10485 renderer->texturesToDestroyCount -= 1; 10486 } 10487 } 10488 10489 for (Sint32 i = renderer->buffersToDestroyCount - 1; i >= 0; i -= 1) { 10490 if (SDL_GetAtomicInt(&renderer->buffersToDestroy[i]->referenceCount) == 0) { 10491 VULKAN_INTERNAL_DestroyBuffer( 10492 renderer, 10493 renderer->buffersToDestroy[i]); 10494 10495 renderer->buffersToDestroy[i] = renderer->buffersToDestroy[renderer->buffersToDestroyCount - 1]; 10496 renderer->buffersToDestroyCount -= 1; 10497 } 10498 } 10499 10500 for (Sint32 i = renderer->graphicsPipelinesToDestroyCount - 1; i >= 0; i -= 1) { 10501 if (SDL_GetAtomicInt(&renderer->graphicsPipelinesToDestroy[i]->referenceCount) == 0) { 10502 VULKAN_INTERNAL_DestroyGraphicsPipeline( 10503 renderer, 10504 renderer->graphicsPipelinesToDestroy[i]); 10505 10506 renderer->graphicsPipelinesToDestroy[i] = renderer->graphicsPipelinesToDestroy[renderer->graphicsPipelinesToDestroyCount - 1]; 10507 renderer->graphicsPipelinesToDestroyCount -= 1; 10508 } 10509 } 10510 10511 for (Sint32 i = renderer->computePipelinesToDestroyCount - 1; i >= 0; i -= 1) { 10512 if (SDL_GetAtomicInt(&renderer->computePipelinesToDestroy[i]->referenceCount) == 0) { 10513 VULKAN_INTERNAL_DestroyComputePipeline( 10514 renderer, 10515 renderer->computePipelinesToDestroy[i]); 10516 10517 renderer->computePipelinesToDestroy[i] = renderer->computePipelinesToDestroy[renderer->computePipelinesToDestroyCount - 1]; 10518 renderer->computePipelinesToDestroyCount -= 1; 10519 } 10520 } 10521 10522 for (Sint32 i = renderer->shadersToDestroyCount - 1; i >= 0; i -= 1) { 10523 if (SDL_GetAtomicInt(&renderer->shadersToDestroy[i]->referenceCount) == 0) { 10524 VULKAN_INTERNAL_DestroyShader( 10525 renderer, 10526 renderer->shadersToDestroy[i]); 10527 10528 renderer->shadersToDestroy[i] = renderer->shadersToDestroy[renderer->shadersToDestroyCount - 1]; 10529 renderer->shadersToDestroyCount -= 1; 10530 } 10531 } 10532 10533 for (Sint32 i = renderer->samplersToDestroyCount - 1; i >= 0; i -= 1) { 10534 if (SDL_GetAtomicInt(&renderer->samplersToDestroy[i]->referenceCount) == 0) { 10535 VULKAN_INTERNAL_DestroySampler( 10536 renderer, 10537 renderer->samplersToDestroy[i]); 10538 10539 renderer->samplersToDestroy[i] = renderer->samplersToDestroy[renderer->samplersToDestroyCount - 1]; 10540 renderer->samplersToDestroyCount -= 1; 10541 } 10542 } 10543 10544 for (Sint32 i = renderer->framebuffersToDestroyCount - 1; i >= 0; i -= 1) { 10545 if (SDL_GetAtomicInt(&renderer->framebuffersToDestroy[i]->referenceCount) == 0) { 10546 VULKAN_INTERNAL_DestroyFramebuffer( 10547 renderer, 10548 renderer->framebuffersToDestroy[i]); 10549 10550 renderer->framebuffersToDestroy[i] = renderer->framebuffersToDestroy[renderer->framebuffersToDestroyCount - 1]; 10551 renderer->framebuffersToDestroyCount -= 1; 10552 } 10553 } 10554 10555 SDL_UnlockMutex(renderer->disposeLock); 10556} 10557 10558static void VULKAN_INTERNAL_CleanCommandBuffer( 10559 VulkanRenderer *renderer, 10560 VulkanCommandBuffer *commandBuffer, 10561 bool cancel) 10562{ 10563 if (commandBuffer->autoReleaseFence) { 10564 VULKAN_ReleaseFence( 10565 (SDL_GPURenderer *)renderer, 10566 (SDL_GPUFence *)commandBuffer->inFlightFence); 10567 10568 commandBuffer->inFlightFence = NULL; 10569 } 10570 10571 // Uniform buffers are now available 10572 10573 SDL_LockMutex(renderer->acquireUniformBufferLock); 10574 10575 for (Sint32 i = 0; i < commandBuffer->usedUniformBufferCount; i += 1) { 10576 VULKAN_INTERNAL_ReturnUniformBufferToPool( 10577 renderer, 10578 commandBuffer->usedUniformBuffers[i]); 10579 } 10580 commandBuffer->usedUniformBufferCount = 0; 10581 10582 SDL_UnlockMutex(renderer->acquireUniformBufferLock); 10583 10584 // Decrement reference counts 10585 10586 for (Sint32 i = 0; i < commandBuffer->usedBufferCount; i += 1) { 10587 (void)SDL_AtomicDecRef(&commandBuffer->usedBuffers[i]->referenceCount); 10588 } 10589 commandBuffer->usedBufferCount = 0; 10590 10591 for (Sint32 i = 0; i < commandBuffer->buffersUsedInPendingTransfersCount; i += 1) { 10592 (void)SDL_AtomicDecRef(&commandBuffer->buffersUsedInPendingTransfers[i]->usedRegion->allocation->referenceCount); 10593 } 10594 commandBuffer->buffersUsedInPendingTransfersCount = 0; 10595 10596 for (Sint32 i = 0; i < commandBuffer->usedTextureCount; i += 1) { 10597 (void)SDL_AtomicDecRef(&commandBuffer->usedTextures[i]->referenceCount); 10598 } 10599 commandBuffer->usedTextureCount = 0; 10600 10601 for (Sint32 i = 0; i < commandBuffer->texturesUsedInPendingTransfersCount; i += 1){ 10602 (void)SDL_AtomicDecRef(&commandBuffer->texturesUsedInPendingTransfers[i]->usedRegion->allocation->referenceCount); 10603 } 10604 commandBuffer->texturesUsedInPendingTransfersCount = 0; 10605 10606 for (Sint32 i = 0; i < commandBuffer->usedSamplerCount; i += 1) { 10607 (void)SDL_AtomicDecRef(&commandBuffer->usedSamplers[i]->referenceCount); 10608 } 10609 commandBuffer->usedSamplerCount = 0; 10610 10611 for (Sint32 i = 0; i < commandBuffer->usedGraphicsPipelineCount; i += 1) { 10612 (void)SDL_AtomicDecRef(&commandBuffer->usedGraphicsPipelines[i]->referenceCount); 10613 } 10614 commandBuffer->usedGraphicsPipelineCount = 0; 10615 10616 for (Sint32 i = 0; i < commandBuffer->usedComputePipelineCount; i += 1) { 10617 (void)SDL_AtomicDecRef(&commandBuffer->usedComputePipelines[i]->referenceCount); 10618 } 10619 commandBuffer->usedComputePipelineCount = 0; 10620 10621 for (Sint32 i = 0; i < commandBuffer->usedFramebufferCount; i += 1) { 10622 (void)SDL_AtomicDecRef(&commandBuffer->usedFramebuffers[i]->referenceCount); 10623 } 10624 commandBuffer->usedFramebufferCount = 0; 10625 10626 // Reset presentation data 10627 10628 commandBuffer->presentDataCount = 0; 10629 commandBuffer->waitSemaphoreCount = 0; 10630 commandBuffer->signalSemaphoreCount = 0; 10631 commandBuffer->swapchainRequested = false; 10632 10633 // Reset defrag state 10634 10635 if (commandBuffer->isDefrag) { 10636 renderer->defragInProgress = 0; 10637 } 10638 10639 // Return command buffer to pool 10640 10641 SDL_LockMutex(renderer->acquireCommandBufferLock); 10642 10643 if (commandBuffer->commandPool->inactiveCommandBufferCount == commandBuffer->commandPool->inactiveCommandBufferCapacity) { 10644 commandBuffer->commandPool->inactiveCommandBufferCapacity += 1; 10645 commandBuffer->commandPool->inactiveCommandBuffers = SDL_realloc( 10646 commandBuffer->commandPool->inactiveCommandBuffers, 10647 commandBuffer->commandPool->inactiveCommandBufferCapacity * sizeof(VulkanCommandBuffer *)); 10648 } 10649 10650 commandBuffer->commandPool->inactiveCommandBuffers[commandBuffer->commandPool->inactiveCommandBufferCount] = commandBuffer; 10651 commandBuffer->commandPool->inactiveCommandBufferCount += 1; 10652 10653 // Release descriptor set cache 10654 10655 VULKAN_INTERNAL_ReturnDescriptorSetCacheToPool( 10656 renderer, 10657 commandBuffer->descriptorSetCache); 10658 10659 commandBuffer->descriptorSetCache = NULL; 10660 10661 SDL_UnlockMutex(renderer->acquireCommandBufferLock); 10662 10663 // Remove this command buffer from the submitted list 10664 if (!cancel) { 10665 for (Uint32 i = 0; i < renderer->submittedCommandBufferCount; i += 1) { 10666 if (renderer->submittedCommandBuffers[i] == commandBuffer) { 10667 renderer->submittedCommandBuffers[i] = renderer->submittedCommandBuffers[renderer->submittedCommandBufferCount - 1]; 10668 renderer->submittedCommandBufferCount -= 1; 10669 } 10670 } 10671 } 10672} 10673 10674static bool VULKAN_WaitForFences( 10675 SDL_GPURenderer *driverData, 10676 bool waitAll, 10677 SDL_GPUFence *const *fences, 10678 Uint32 numFences) 10679{ 10680 VulkanRenderer *renderer = (VulkanRenderer *)driverData; 10681 VkFence *vkFences = SDL_stack_alloc(VkFence, numFences); 10682 VkResult result; 10683 10684 for (Uint32 i = 0; i < numFences; i += 1) { 10685 vkFences[i] = ((VulkanFenceHandle *)fences[i])->fence; 10686 } 10687 10688 result = renderer->vkWaitForFences( 10689 renderer->logicalDevice, 10690 numFences, 10691 vkFences, 10692 waitAll, 10693 SDL_MAX_UINT64); 10694 10695 CHECK_VULKAN_ERROR_AND_RETURN(result, vkWaitForFences, false); 10696 10697 SDL_stack_free(vkFences); 10698 10699 SDL_LockMutex(renderer->submitLock); 10700 10701 for (Sint32 i = renderer->submittedCommandBufferCount - 1; i >= 0; i -= 1) { 10702 result = renderer->vkGetFenceStatus( 10703 renderer->logicalDevice, 10704 renderer->submittedCommandBuffers[i]->inFlightFence->fence); 10705 10706 if (result == VK_SUCCESS) { 10707 VULKAN_INTERNAL_CleanCommandBuffer( 10708 renderer, 10709 renderer->submittedCommandBuffers[i], 10710 false); 10711 } 10712 } 10713 10714 VULKAN_INTERNAL_PerformPendingDestroys(renderer); 10715 10716 SDL_UnlockMutex(renderer->submitLock); 10717 10718 return true; 10719} 10720 10721static bool VULKAN_Wait( 10722 SDL_GPURenderer *driverData) 10723{ 10724 VulkanRenderer *renderer = (VulkanRenderer *)driverData; 10725 VulkanCommandBuffer *commandBuffer; 10726 VkResult result; 10727 Sint32 i; 10728 10729 SDL_LockMutex(renderer->submitLock); 10730 10731 result = renderer->vkDeviceWaitIdle(renderer->logicalDevice); 10732 10733 if (result != VK_SUCCESS) { 10734 if (renderer->debugMode) { 10735 SDL_LogError(SDL_LOG_CATEGORY_GPU, "%s %s", "vkDeviceWaitIdle", VkErrorMessages(result)); 10736 } 10737 SDL_SetError("%s %s", "vkDeviceWaitIdle", VkErrorMessages(result)); 10738 SDL_UnlockMutex(renderer->submitLock); 10739 return false; 10740 } 10741 10742 for (i = renderer->submittedCommandBufferCount - 1; i >= 0; i -= 1) { 10743 commandBuffer = renderer->submittedCommandBuffers[i]; 10744 VULKAN_INTERNAL_CleanCommandBuffer(renderer, commandBuffer, false); 10745 } 10746 10747 VULKAN_INTERNAL_PerformPendingDestroys(renderer); 10748 10749 SDL_UnlockMutex(renderer->submitLock); 10750 10751 return true; 10752} 10753 10754static SDL_GPUFence *VULKAN_SubmitAndAcquireFence( 10755 SDL_GPUCommandBuffer *commandBuffer) 10756{ 10757 VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; 10758 vulkanCommandBuffer->autoReleaseFence = false; 10759 if (!VULKAN_Submit(commandBuffer)) { 10760 return NULL; 10761 } 10762 return (SDL_GPUFence *)vulkanCommandBuffer->inFlightFence; 10763} 10764 10765static void VULKAN_INTERNAL_ReleaseCommandBuffer(VulkanCommandBuffer *vulkanCommandBuffer) 10766{ 10767 VulkanRenderer *renderer = vulkanCommandBuffer->renderer; 10768 10769 if (renderer->submittedCommandBufferCount + 1 >= renderer->submittedCommandBufferCapacity) { 10770 renderer->submittedCommandBufferCapacity = renderer->submittedCommandBufferCount + 1; 10771 10772 renderer->submittedCommandBuffers = SDL_realloc( 10773 renderer->submittedCommandBuffers, 10774 sizeof(VulkanCommandBuffer *) * renderer->submittedCommandBufferCapacity); 10775 } 10776 10777 renderer->submittedCommandBuffers[renderer->submittedCommandBufferCount] = vulkanCommandBuffer; 10778 renderer->submittedCommandBufferCount += 1; 10779} 10780 10781static bool VULKAN_Submit( 10782 SDL_GPUCommandBuffer *commandBuffer) 10783{ 10784 VulkanCommandBuffer *vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; 10785 VulkanRenderer *renderer = vulkanCommandBuffer->renderer; 10786 VkSubmitInfo submitInfo; 10787 VkPresentInfoKHR presentInfo; 10788 VulkanPresentData *presentData; 10789 VkResult vulkanResult, presentResult = VK_SUCCESS; 10790 VkPipelineStageFlags waitStages[MAX_PRESENT_COUNT]; 10791 Uint32 swapchainImageIndex; 10792 VulkanTextureSubresource *swapchainTextureSubresource; 10793 VulkanMemorySubAllocator *allocator; 10794 bool performCleanups = 10795 (renderer->claimedWindowCount > 0 && vulkanCommandBuffer->swapchainRequested) || 10796 renderer->claimedWindowCount == 0; 10797 10798 SDL_LockMutex(renderer->submitLock); 10799 10800 // FIXME: Can this just be permanent? 10801 for (Uint32 i = 0; i < MAX_PRESENT_COUNT; i += 1) { 10802 waitStages[i] = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; 10803 } 10804 10805 for (Uint32 j = 0; j < vulkanCommandBuffer->presentDataCount; j += 1) { 10806 swapchainImageIndex = vulkanCommandBuffer->presentDatas[j].swapchainImageIndex; 10807 swapchainTextureSubresource = VULKAN_INTERNAL_FetchTextureSubresource( 10808 &vulkanCommandBuffer->presentDatas[j].windowData->textureContainers[swapchainImageIndex], 10809 0, 10810 0); 10811 10812 VULKAN_INTERNAL_TextureSubresourceTransitionFromDefaultUsage( 10813 renderer, 10814 vulkanCommandBuffer, 10815 VULKAN_TEXTURE_USAGE_MODE_PRESENT, 10816 swapchainTextureSubresource); 10817 } 10818 10819 if (performCleanups && 10820 renderer->allocationsToDefragCount > 0 && 10821 !renderer->defragInProgress) { 10822 if (!VULKAN_INTERNAL_DefragmentMemory(renderer, vulkanCommandBuffer)) 10823 { 10824 SDL_LogError(SDL_LOG_CATEGORY_GPU, "%s", "Failed to defragment memory, likely OOM!"); 10825 } 10826 } 10827 10828 if (!VULKAN_INTERNAL_EndCommandBuffer(renderer, vulkanCommandBuffer)) { 10829 SDL_UnlockMutex(renderer->submitLock); 10830 return false; 10831 } 10832 10833 vulkanCommandBuffer->inFlightFence = VULKAN_INTERNAL_AcquireFenceFromPool(renderer); 10834 if (vulkanCommandBuffer->inFlightFence == NULL) { 10835 SDL_UnlockMutex(renderer->submitLock); 10836 return false; 10837 } 10838 10839 // Command buffer has a reference to the in-flight fence 10840 (void)SDL_AtomicIncRef(&vulkanCommandBuffer->inFlightFence->referenceCount); 10841 10842 submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; 10843 submitInfo.pNext = NULL; 10844 submitInfo.commandBufferCount = 1; 10845 submitInfo.pCommandBuffers = &vulkanCommandBuffer->commandBuffer; 10846 10847 submitInfo.pWaitDstStageMask = waitStages; 10848 submitInfo.pWaitSemaphores = vulkanCommandBuffer->waitSemaphores; 10849 submitInfo.waitSemaphoreCount = vulkanCommandBuffer->waitSemaphoreCount; 10850 submitInfo.pSignalSemaphores = vulkanCommandBuffer->signalSemaphores; 10851 submitInfo.signalSemaphoreCount = vulkanCommandBuffer->signalSemaphoreCount; 10852 10853 vulkanResult = renderer->vkQueueSubmit( 10854 renderer->unifiedQueue, 10855 1, 10856 &submitInfo, 10857 vulkanCommandBuffer->inFlightFence->fence); 10858 10859 if (vulkanResult != VK_SUCCESS) { 10860 SDL_UnlockMutex(renderer->submitLock); 10861 CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkQueueSubmit, false); 10862 } 10863 10864 // Present, if applicable 10865 for (Uint32 j = 0; j < vulkanCommandBuffer->presentDataCount; j += 1) { 10866 presentData = &vulkanCommandBuffer->presentDatas[j]; 10867 10868 presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; 10869 presentInfo.pNext = NULL; 10870 presentInfo.pWaitSemaphores = 10871 &presentData->windowData->renderFinishedSemaphore[presentData->swapchainImageIndex]; 10872 presentInfo.waitSemaphoreCount = 1; 10873 presentInfo.pSwapchains = &presentData->windowData->swapchain; 10874 presentInfo.swapchainCount = 1; 10875 presentInfo.pImageIndices = &presentData->swapchainImageIndex; 10876 presentInfo.pResults = NULL; 10877 10878 presentResult = renderer->vkQueuePresentKHR( 10879 renderer->unifiedQueue, 10880 &presentInfo); 10881 10882 if (presentResult == VK_SUCCESS || presentResult == VK_SUBOPTIMAL_KHR || presentResult == VK_ERROR_OUT_OF_DATE_KHR) { 10883 // If presenting, the swapchain is using the in-flight fence 10884 presentData->windowData->inFlightFences[presentData->windowData->frameCounter] = (SDL_GPUFence *)vulkanCommandBuffer->inFlightFence; 10885 (void)SDL_AtomicIncRef(&vulkanCommandBuffer->inFlightFence->referenceCount); 10886 10887// On the Android platform, VK_SUBOPTIMAL_KHR is returned whenever the device is rotated. We'll just ignore this for now. 10888#ifndef SDL_PLATFORM_ANDROID 10889 if (presentResult == VK_SUBOPTIMAL_KHR) { 10890 presentData->windowData->needsSwapchainRecreate = true; 10891 } 10892#endif 10893 if (presentResult == VK_ERROR_OUT_OF_DATE_KHR) { 10894 presentData->windowData->needsSwapchainRecreate = true; 10895 } 10896 } else if (presentResult == VK_ERROR_SURFACE_LOST_KHR) { 10897 // Android can destroy the surface at any time when the app goes into the background, 10898 // even after successfully acquiring a swapchain texture and before presenting it. 10899 presentData->windowData->needsSwapchainRecreate = true; 10900 presentData->windowData->needsSurfaceRecreate = true; 10901 } else { 10902 if (presentResult != VK_SUCCESS) { 10903 VULKAN_INTERNAL_ReleaseCommandBuffer(vulkanCommandBuffer); 10904 SDL_UnlockMutex(renderer->submitLock); 10905 } 10906 10907 CHECK_VULKAN_ERROR_AND_RETURN(presentResult, vkQueuePresentKHR, false); 10908 } 10909 10910 presentData->windowData->frameCounter = 10911 (presentData->windowData->frameCounter + 1) % renderer->allowedFramesInFlight; 10912 } 10913 10914 if (performCleanups) { 10915 for (Sint32 i = renderer->submittedCommandBufferCount - 1; i >= 0; i -= 1) { 10916 vulkanResult = renderer->vkGetFenceStatus( 10917 renderer->logicalDevice, 10918 renderer->submittedCommandBuffers[i]->inFlightFence->fence); 10919 10920 if (vulkanResult == VK_SUCCESS) { 10921 VULKAN_INTERNAL_CleanCommandBuffer( 10922 renderer, 10923 renderer->submittedCommandBuffers[i], 10924 false); 10925 } 10926 } 10927 10928 if (renderer->checkEmptyAllocations) { 10929 SDL_LockMutex(renderer->allocatorLock); 10930 10931 for (Uint32 i = 0; i < VK_MAX_MEMORY_TYPES; i += 1) { 10932 allocator = &renderer->memoryAllocator->subAllocators[i]; 10933 10934 for (Sint32 j = allocator->allocationCount - 1; j >= 0; j -= 1) { 10935 if (allocator->allocations[j]->usedRegionCount == 0) { 10936 VULKAN_INTERNAL_DeallocateMemory( 10937 renderer, 10938 allocator, 10939 j); 10940 } 10941 } 10942 } 10943 10944 renderer->checkEmptyAllocations = false; 10945 10946 SDL_UnlockMutex(renderer->allocatorLock); 10947 } 10948 10949 VULKAN_INTERNAL_PerformPendingDestroys(renderer); 10950 } 10951 10952 // Mark command buffer as submitted 10953 VULKAN_INTERNAL_ReleaseCommandBuffer(vulkanCommandBuffer); 10954 10955 SDL_UnlockMutex(renderer->submitLock); 10956 10957 return true; 10958} 10959 10960static bool VULKAN_Cancel( 10961 SDL_GPUCommandBuffer *commandBuffer) 10962{ 10963 VulkanRenderer *renderer; 10964 VulkanCommandBuffer *vulkanCommandBuffer; 10965 VkResult result; 10966 10967 vulkanCommandBuffer = (VulkanCommandBuffer *)commandBuffer; 10968 renderer = vulkanCommandBuffer->renderer; 10969 10970 result = renderer->vkResetCommandBuffer( 10971 vulkanCommandBuffer->commandBuffer, 10972 VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT); 10973 CHECK_VULKAN_ERROR_AND_RETURN(result, vkResetCommandBuffer, false); 10974 10975 vulkanCommandBuffer->autoReleaseFence = false; 10976 SDL_LockMutex(renderer->submitLock); 10977 VULKAN_INTERNAL_CleanCommandBuffer(renderer, vulkanCommandBuffer, true); 10978 SDL_UnlockMutex(renderer->submitLock); 10979 10980 return true; 10981} 10982 10983static bool VULKAN_INTERNAL_DefragmentMemory( 10984 VulkanRenderer *renderer, 10985 VulkanCommandBuffer *commandBuffer) 10986{ 10987 renderer->defragInProgress = 1; 10988 commandBuffer->isDefrag = 1; 10989 10990 SDL_LockMutex(renderer->allocatorLock); 10991 SDL_LockRWLockForWriting(renderer->defragLock); 10992 10993 // Find an allocation that doesn't have any pending transfer operations 10994 Sint32 indexToDefrag = -1; 10995 for (Sint32 i = renderer->allocationsToDefragCount - 1; i >= 0; i -= 1) { 10996 if (SDL_GetAtomicInt(&renderer->allocationsToDefrag[i]->referenceCount) == 0) { 10997 indexToDefrag = i; 10998 break; 10999 } 11000 } 11001 11002 if (indexToDefrag == -1) { 11003 // Nothing is available to defrag, but it's not an error 11004 SDL_UnlockRWLock(renderer->defragLock); 11005 SDL_UnlockMutex(renderer->allocatorLock); 11006 return true; 11007 } 11008 11009 VulkanMemoryAllocation *allocation = renderer->allocationsToDefrag[indexToDefrag]; 11010 11011 // Plug the hole 11012 if ((Uint32) indexToDefrag != renderer->allocationsToDefragCount - 1) { 11013 renderer->allocationsToDefrag[indexToDefrag] = renderer->allocationsToDefrag[renderer->allocationsToDefragCount - 1]; 11014 } 11015 renderer->allocationsToDefragCount -= 1; 11016 11017 /* For each used region in the allocation 11018 * create a new resource, copy the data 11019 * and re-point the resource containers 11020 */ 11021 for (Uint32 i = 0; i < allocation->usedRegionCount; i += 1) { 11022 VulkanMemoryUsedRegion *currentRegion = allocation->usedRegions[i]; 11023 11024 if (currentRegion->isBuffer && !currentRegion->vulkanBuffer->markedForDestroy) { 11025 VulkanBuffer *newBuffer = VULKAN_INTERNAL_CreateBuffer( 11026 renderer, 11027 currentRegion->vulkanBuffer->size, 11028 currentRegion->vulkanBuffer->usage, 11029 currentRegion->vulkanBuffer->type, 11030 false, 11031 currentRegion->vulkanBuffer->container != NULL ? currentRegion->vulkanBuffer->container->debugName : NULL); 11032 11033 if (newBuffer == NULL) { 11034 SDL_UnlockRWLock(renderer->defragLock); 11035 SDL_UnlockMutex(renderer->allocatorLock); 11036 SDL_LogError(SDL_LOG_CATEGORY_GPU, "%s", "Failed to allocate defrag buffer!"); 11037 return false; 11038 } 11039 11040 // Copy buffer contents if necessary 11041 if ( 11042 currentRegion->vulkanBuffer->type == VULKAN_BUFFER_TYPE_GPU && currentRegion->vulkanBuffer->transitioned) { 11043 VULKAN_INTERNAL_BufferTransitionFromDefaultUsage( 11044 renderer, 11045 commandBuffer, 11046 VULKAN_BUFFER_USAGE_MODE_COPY_SOURCE, 11047 currentRegion->vulkanBuffer); 11048 11049 VULKAN_INTERNAL_BufferTransitionFromDefaultUsage( 11050 renderer, 11051 commandBuffer, 11052 VULKAN_BUFFER_USAGE_MODE_COPY_DESTINATION, 11053 newBuffer); 11054 11055 VkBufferCopy bufferCopy; 11056 bufferCopy.srcOffset = 0; 11057 bufferCopy.dstOffset = 0; 11058 bufferCopy.size = currentRegion->resourceSize; 11059 11060 renderer->vkCmdCopyBuffer( 11061 commandBuffer->commandBuffer, 11062 currentRegion->vulkanBuffer->buffer, 11063 newBuffer->buffer, 11064 1, 11065 &bufferCopy); 11066 11067 VULKAN_INTERNAL_BufferTransitionToDefaultUsage( 11068 renderer, 11069 commandBuffer, 11070 VULKAN_BUFFER_USAGE_MODE_COPY_DESTINATION, 11071 newBuffer); 11072 11073 VULKAN_INTERNAL_TrackBuffer(commandBuffer, currentRegion->vulkanBuffer); 11074 VULKAN_INTERNAL_TrackBuffer(commandBuffer, newBuffer); 11075 } 11076 11077 // re-point original container to new buffer 11078 newBuffer->container = currentRegion->vulkanBuffer->container; 11079 newBuffer->containerIndex = currentRegion->vulkanBuffer->containerIndex; 11080 if (newBuffer->type == VULKAN_BUFFER_TYPE_UNIFORM) { 11081 currentRegion->vulkanBuffer->uniformBufferForDefrag->buffer = newBuffer; 11082 } else { 11083 newBuffer->container->buffers[newBuffer->containerIndex] = newBuffer; 11084 if (newBuffer->container->activeBuffer == currentRegion->vulkanBuffer) { 11085 newBuffer->container->activeBuffer = newBuffer; 11086 } 11087 } 11088 11089 if (currentRegion->vulkanBuffer->uniformBufferForDefrag) { 11090 newBuffer->uniformBufferForDefrag = currentRegion->vulkanBuffer->uniformBufferForDefrag; 11091 } 11092 11093 VULKAN_INTERNAL_ReleaseBuffer(renderer, currentRegion->vulkanBuffer); 11094 } else if (!currentRegion->isBuffer && !currentRegion->vulkanTexture->markedForDestroy) { 11095 VulkanTexture *newTexture = VULKAN_INTERNAL_CreateTexture( 11096 renderer, 11097 ¤tRegion->vulkanTexture->container->header.info); 11098 11099 if (newTexture == NULL) { 11100 SDL_UnlockRWLock(renderer->defragLock); 11101 SDL_UnlockMutex(renderer->allocatorLock); 11102 SDL_LogError(SDL_LOG_CATEGORY_GPU, "%s", "Failed to allocate defrag buffer!"); 11103 return false; 11104 } 11105 11106 SDL_GPUTextureCreateInfo info = currentRegion->vulkanTexture->container->header.info; 11107 for (Uint32 subresourceIndex = 0; subresourceIndex < currentRegion->vulkanTexture->subresourceCount; subresourceIndex += 1) { 11108 // copy subresource if necessary 11109 VulkanTextureSubresource *srcSubresource = ¤tRegion->vulkanTexture->subresources[subresourceIndex]; 11110 VulkanTextureSubresource *dstSubresource = &newTexture->subresources[subresourceIndex]; 11111 11112 VULKAN_INTERNAL_TextureSubresourceTransitionFromDefaultUsage( 11113 renderer, 11114 commandBuffer, 11115 VULKAN_TEXTURE_USAGE_MODE_COPY_SOURCE, 11116 srcSubresource); 11117 11118 VULKAN_INTERNAL_TextureSubresourceMemoryBarrier( 11119 renderer, 11120 commandBuffer, 11121 VULKAN_TEXTURE_USAGE_MODE_UNINITIALIZED, 11122 VULKAN_TEXTURE_USAGE_MODE_COPY_DESTINATION, 11123 dstSubresource); 11124 11125 VkImageCopy imageCopy; 11126 imageCopy.srcOffset.x = 0; 11127 imageCopy.srcOffset.y = 0; 11128 imageCopy.srcOffset.z = 0; 11129 imageCopy.srcSubresource.aspectMask = srcSubresource->parent->aspectFlags; 11130 imageCopy.srcSubresource.baseArrayLayer = srcSubresource->layer; 11131 imageCopy.srcSubresource.layerCount = 1; 11132 imageCopy.srcSubresource.mipLevel = srcSubresource->level; 11133 imageCopy.extent.width = SDL_max(1, info.width >> srcSubresource->level); 11134 imageCopy.extent.height = SDL_max(1, info.height >> srcSubresource->level); 11135 imageCopy.extent.depth = info.type == SDL_GPU_TEXTURETYPE_3D ? info.layer_count_or_depth : 1; 11136 imageCopy.dstOffset.x = 0; 11137 imageCopy.dstOffset.y = 0; 11138 imageCopy.dstOffset.z = 0; 11139 imageCopy.dstSubresource.aspectMask = dstSubresource->parent->aspectFlags; 11140 imageCopy.dstSubresource.baseArrayLayer = dstSubresource->layer; 11141 imageCopy.dstSubresource.layerCount = 1; 11142 imageCopy.dstSubresource.mipLevel = dstSubresource->level; 11143 11144 renderer->vkCmdCopyImage( 11145 commandBuffer->commandBuffer, 11146 currentRegion->vulkanTexture->image, 11147 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, 11148 newTexture->image, 11149 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 11150 1, 11151 &imageCopy); 11152 11153 VULKAN_INTERNAL_TextureSubresourceTransitionToDefaultUsage( 11154 renderer, 11155 commandBuffer, 11156 VULKAN_TEXTURE_USAGE_MODE_COPY_DESTINATION, 11157 dstSubresource); 11158 11159 VULKAN_INTERNAL_TrackTexture(commandBuffer, srcSubresource->parent); 11160 VULKAN_INTERNAL_TrackTexture(commandBuffer, dstSubresource->parent); 11161 } 11162 11163 // re-point original container to new texture 11164 newTexture->container = currentRegion->vulkanTexture->container; 11165 newTexture->containerIndex = currentRegion->vulkanTexture->containerIndex; 11166 newTexture->container->textures[currentRegion->vulkanTexture->containerIndex] = newTexture; 11167 if (currentRegion->vulkanTexture == currentRegion->vulkanTexture->container->activeTexture) { 11168 newTexture->container->activeTexture = newTexture; 11169 } 11170 11171 VULKAN_INTERNAL_ReleaseTexture(renderer, currentRegion->vulkanTexture); 11172 } 11173 } 11174 11175 SDL_UnlockRWLock(renderer->defragLock); 11176 SDL_UnlockMutex(renderer->allocatorLock); 11177 11178 return true; 11179} 11180 11181// Format Info 11182 11183static bool VULKAN_SupportsTextureFormat( 11184 SDL_GPURenderer *driverData, 11185 SDL_GPUTextureFormat format, 11186 SDL_GPUTextureType type, 11187 SDL_GPUTextureUsageFlags usage) 11188{ 11189 VulkanRenderer *renderer = (VulkanRenderer *)driverData; 11190 VkFormat vulkanFormat = SDLToVK_TextureFormat[format]; 11191 VkImageUsageFlags vulkanUsage = 0; 11192 VkImageCreateFlags createFlags = 0; 11193 VkImageFormatProperties properties; 11194 VkResult vulkanResult; 11195 11196 if (usage & SDL_GPU_TEXTUREUSAGE_SAMPLER) { 11197 vulkanUsage |= VK_IMAGE_USAGE_SAMPLED_BIT; 11198 } 11199 if (usage & SDL_GPU_TEXTUREUSAGE_COLOR_TARGET) { 11200 vulkanUsage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; 11201 } 11202 if (usage & SDL_GPU_TEXTUREUSAGE_DEPTH_STENCIL_TARGET) { 11203 vulkanUsage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; 11204 } 11205 if (usage & (SDL_GPU_TEXTUREUSAGE_GRAPHICS_STORAGE_READ | 11206 SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_READ | 11207 SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_WRITE | 11208 SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_SIMULTANEOUS_READ_WRITE)) { 11209 vulkanUsage |= VK_IMAGE_USAGE_STORAGE_BIT; 11210 } 11211 11212 if (type == SDL_GPU_TEXTURETYPE_CUBE || type == SDL_GPU_TEXTURETYPE_CUBE_ARRAY) { 11213 createFlags = VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT; 11214 } 11215 11216 vulkanResult = renderer->vkGetPhysicalDeviceImageFormatProperties( 11217 renderer->physicalDevice, 11218 vulkanFormat, 11219 (type == SDL_GPU_TEXTURETYPE_3D) ? VK_IMAGE_TYPE_3D : VK_IMAGE_TYPE_2D, 11220 VK_IMAGE_TILING_OPTIMAL, 11221 vulkanUsage, 11222 createFlags, 11223 &properties); 11224 11225 return vulkanResult == VK_SUCCESS; 11226} 11227 11228// Device instantiation 11229 11230static inline Uint8 CheckDeviceExtensions( 11231 VkExtensionProperties *extensions, 11232 Uint32 numExtensions, 11233 VulkanExtensions *supports) 11234{ 11235 Uint32 i; 11236 11237 SDL_memset(supports, '\0', sizeof(VulkanExtensions)); 11238 for (i = 0; i < numExtensions; i += 1) { 11239 const char *name = extensions[i].extensionName; 11240#define CHECK(ext) \ 11241 if (SDL_strcmp(name, "VK_" #ext) == 0) { \ 11242 supports->ext = 1; \ 11243 } 11244 CHECK(KHR_swapchain) 11245 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) 11246#undef CHECK 11247 } 11248 11249 return (supports->KHR_swapchain && 11250 supports->KHR_maintenance1); 11251} 11252 11253static inline Uint32 GetDeviceExtensionCount(VulkanExtensions *supports) 11254{ 11255 return ( 11256 supports->KHR_swapchain + 11257 supports->KHR_maintenance1 + 11258 supports->KHR_driver_properties + 11259 supports->KHR_portability_subset + 11260 supports->MSFT_layered_driver + 11261 supports->EXT_texture_compression_astc_hdr); 11262} 11263 11264static inline void CreateDeviceExtensionArray( 11265 VulkanExtensions *supports, 11266 const char **extensions) 11267{ 11268 Uint8 cur = 0; 11269#define CHECK(ext) \ 11270 if (supports->ext) { \ 11271 extensions[cur++] = "VK_" #ext; \ 11272 } 11273 CHECK(KHR_swapchain) 11274 CHECK(KHR_maintenance1) 11275 CHECK(KHR_driver_properties) 11276 CHECK(KHR_portability_subset) 11277 CHECK(MSFT_layered_driver) 11278 CHECK(EXT_texture_compression_astc_hdr) 11279#undef CHECK 11280} 11281 11282static inline Uint8 SupportsInstanceExtension( 11283 const char *ext, 11284 VkExtensionProperties *availableExtensions, 11285 Uint32 numAvailableExtensions) 11286{ 11287 Uint32 i; 11288 for (i = 0; i < numAvailableExtensions; i += 1) { 11289 if (SDL_strcmp(ext, availableExtensions[i].extensionName) == 0) { 11290 return 1; 11291 } 11292 } 11293 return 0; 11294} 11295 11296static Uint8 VULKAN_INTERNAL_CheckInstanceExtensions( 11297 const char **requiredExtensions, 11298 Uint32 requiredExtensionsLength, 11299 bool *supportsDebugUtils, 11300 bool *supportsColorspace, 11301 bool *supportsPhysicalDeviceProperties2, 11302 bool *supportsPortabilityEnumeration, 11303 int *firstUnsupportedExtensionIndex) 11304{ 11305 Uint32 extensionCount, i; 11306 VkExtensionProperties *availableExtensions; 11307 Uint8 allExtensionsSupported = 1; 11308 11309 vkEnumerateInstanceExtensionProperties( 11310 NULL, 11311 &extensionCount, 11312 NULL); 11313 availableExtensions = SDL_malloc( 11314 extensionCount * sizeof(VkExtensionProperties)); 11315 vkEnumerateInstanceExtensionProperties( 11316 NULL, 11317 &extensionCount, 11318 availableExtensions); 11319 11320 for (i = 0; i < requiredExtensionsLength; i += 1) { 11321 if (!SupportsInstanceExtension( 11322 requiredExtensions[i], 11323 availableExtensions, 11324 extensionCount)) { 11325 allExtensionsSupported = 0; 11326 *firstUnsupportedExtensionIndex = i; 11327 break; 11328 } 11329 } 11330 11331 // This is optional, but nice to have! 11332 *supportsDebugUtils = SupportsInstanceExtension( 11333 VK_EXT_DEBUG_UTILS_EXTENSION_NAME, 11334 availableExtensions, 11335 extensionCount); 11336 11337 // Also optional and nice to have! 11338 *supportsColorspace = SupportsInstanceExtension( 11339 VK_EXT_SWAPCHAIN_COLOR_SPACE_EXTENSION_NAME, 11340 availableExtensions, 11341 extensionCount); 11342 11343 // Only needed for KHR_driver_properties! 11344 *supportsPhysicalDeviceProperties2 = SupportsInstanceExtension( 11345 VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, 11346 availableExtensions, 11347 extensionCount); 11348 11349 // Only needed for MoltenVK! 11350 *supportsPortabilityEnumeration = SupportsInstanceExtension( 11351 VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME, 11352 availableExtensions, 11353 extensionCount); 11354 11355 SDL_free(availableExtensions); 11356 return allExtensionsSupported; 11357} 11358 11359static Uint8 CheckOptInDeviceExtensions(VulkanFeatures *features, 11360 Uint32 numExtensions, 11361 VkExtensionProperties *availableExtensions, 11362 const char **missingExtensionName) { 11363 Uint8 supportsAll = 1; 11364 for (Uint32 extensionIdx = 0; extensionIdx < features->additionalDeviceExtensionCount; extensionIdx++) { 11365 bool found = false; 11366 for (Uint32 searchIdx = 0; searchIdx < numExtensions; searchIdx++) { 11367 if (SDL_strcmp(features->additionalDeviceExtensionNames[extensionIdx], availableExtensions[searchIdx].extensionName) == 0) { 11368 found = true; 11369 break; 11370 } 11371 } 11372 if (!found) { 11373 supportsAll = 0; 11374 *missingExtensionName = features->additionalDeviceExtensionNames[extensionIdx]; 11375 break; 11376 } 11377 } 11378 11379 return supportsAll; 11380} 11381 11382static Uint8 VULKAN_INTERNAL_CheckDeviceExtensions( 11383 VulkanRenderer *renderer, 11384 VulkanFeatures *features, 11385 VkPhysicalDevice physicalDevice, 11386 VulkanExtensions *physicalDeviceExtensions) 11387{ 11388 Uint32 extensionCount; 11389 VkExtensionProperties *availableExtensions; 11390 Uint8 allExtensionsSupported; 11391 11392 renderer->vkEnumerateDeviceExtensionProperties( 11393 physicalDevice, 11394 NULL, 11395 &extensionCount, 11396 NULL); 11397 availableExtensions = (VkExtensionProperties *)SDL_malloc( 11398 extensionCount * sizeof(VkExtensionProperties)); 11399 renderer->vkEnumerateDeviceExtensionProperties( 11400 physicalDevice, 11401 NULL, 11402 &extensionCount, 11403 availableExtensions); 11404 11405 allExtensionsSupported = CheckDeviceExtensions( 11406 availableExtensions, 11407 extensionCount, 11408 physicalDeviceExtensions); 11409 11410 if (features->usesCustomVulkanOptions) { 11411 const char *missingExtensionName; 11412 if (!CheckOptInDeviceExtensions(features, extensionCount, availableExtensions, &missingExtensionName)) { 11413 SDL_assert(missingExtensionName); 11414 if (renderer->debugMode) { 11415 SDL_LogError(SDL_LOG_CATEGORY_GPU, 11416 "Required Vulkan device extension '%s' not supported", 11417 missingExtensionName); 11418 } 11419 allExtensionsSupported = 0; 11420 } 11421 } 11422 11423 SDL_free(availableExtensions); 11424 return allExtensionsSupported; 11425} 11426 11427static Uint8 VULKAN_INTERNAL_CheckValidationLayers( 11428 const char **validationLayers, 11429 Uint32 validationLayersLength) 11430{ 11431 Uint32 layerCount; 11432 VkLayerProperties *availableLayers; 11433 Uint32 i, j; 11434 Uint8 layerFound = 0; 11435 11436 vkEnumerateInstanceLayerProperties(&layerCount, NULL); 11437 availableLayers = (VkLayerProperties *)SDL_malloc( 11438 layerCount * sizeof(VkLayerProperties)); 11439 vkEnumerateInstanceLayerProperties(&layerCount, availableLayers); 11440 11441 for (i = 0; i < validationLayersLength; i += 1) { 11442 layerFound = 0; 11443 11444 for (j = 0; j < layerCount; j += 1) { 11445 if (SDL_strcmp(validationLayers[i], availableLayers[j].layerName) == 0) { 11446 layerFound = 1; 11447 break; 11448 } 11449 } 11450 11451 if (!layerFound) { 11452 break; 11453 } 11454 } 11455 11456 SDL_free(availableLayers); 11457 return layerFound; 11458} 11459 11460#define CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, feature, result) \ 11461 if (requested->feature && !supported->feature) { \ 11462 SDL_LogVerbose( \ 11463 SDL_LOG_CATEGORY_GPU, \ 11464 "SDL GPU Vulkan: Application requested unsupported physical device feature '" #feature "'"); \ 11465 result = false; \ 11466 } 11467 11468static bool VULKAN_INTERNAL_ValidateOptInVulkan10Features(VkPhysicalDeviceFeatures *requested, VkPhysicalDeviceFeatures *supported) 11469{ 11470 if (requested && supported) { 11471 bool result = true; 11472 11473 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, robustBufferAccess, result) 11474 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, fullDrawIndexUint32, result) 11475 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, imageCubeArray, result) 11476 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, independentBlend, result) 11477 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, geometryShader, result) 11478 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, tessellationShader, result) 11479 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, sampleRateShading, result) 11480 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, dualSrcBlend, result) 11481 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, logicOp, result) 11482 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, multiDrawIndirect, result) 11483 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, drawIndirectFirstInstance, result) 11484 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, depthClamp, result) 11485 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, depthBiasClamp, result) 11486 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, fillModeNonSolid, result) 11487 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, depthBounds, result) 11488 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, wideLines, result) 11489 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, largePoints, result) 11490 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, alphaToOne, result) 11491 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, multiViewport, result) 11492 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, samplerAnisotropy, result) 11493 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, textureCompressionETC2, result) 11494 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, textureCompressionASTC_LDR, result) 11495 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, textureCompressionBC, result) 11496 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, occlusionQueryPrecise, result) 11497 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, pipelineStatisticsQuery, result) 11498 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, vertexPipelineStoresAndAtomics, result) 11499 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, fragmentStoresAndAtomics, result) 11500 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, shaderTessellationAndGeometryPointSize, result) 11501 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, shaderImageGatherExtended, result) 11502 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, shaderStorageImageExtendedFormats, result) 11503 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, shaderStorageImageMultisample, result) 11504 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, shaderStorageImageReadWithoutFormat, result) 11505 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, shaderStorageImageWriteWithoutFormat, result) 11506 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, shaderUniformBufferArrayDynamicIndexing, result) 11507 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, shaderSampledImageArrayDynamicIndexing, result) 11508 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, shaderStorageBufferArrayDynamicIndexing, result) 11509 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, shaderStorageImageArrayDynamicIndexing, result) 11510 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, shaderClipDistance, result) 11511 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, shaderCullDistance, result) 11512 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, shaderFloat64, result) 11513 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, shaderInt64, result) 11514 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, shaderInt16, result) 11515 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, shaderResourceResidency, result) 11516 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, shaderResourceMinLod, result) 11517 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, sparseBinding, result) 11518 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, sparseResidencyBuffer, result) 11519 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, sparseResidencyImage2D, result) 11520 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, sparseResidencyImage3D, result) 11521 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, sparseResidency2Samples, result) 11522 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, sparseResidency4Samples, result) 11523 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, sparseResidency8Samples, result) 11524 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, sparseResidency16Samples, result) 11525 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, sparseResidencyAliased, result) 11526 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, variableMultisampleRate, result) 11527 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, inheritedQueries, result) 11528 11529 return result; 11530 } else { 11531 return false; 11532 } 11533} 11534 11535static bool VULKAN_INTERNAL_ValidateOptInVulkan11Features(VkPhysicalDeviceVulkan11Features *requested, VkPhysicalDeviceVulkan11Features *supported) 11536{ 11537 if (requested && supported) { 11538 bool result = true; 11539 11540 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, storageBuffer16BitAccess, result) 11541 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, uniformAndStorageBuffer16BitAccess, result) 11542 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, storagePushConstant16, result) 11543 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, storageInputOutput16, result) 11544 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, multiview, result) 11545 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, multiviewGeometryShader, result) 11546 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, multiviewTessellationShader, result) 11547 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, variablePointersStorageBuffer, result) 11548 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, variablePointers, result) 11549 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, protectedMemory, result) 11550 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, samplerYcbcrConversion, result) 11551 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, shaderDrawParameters, result) 11552 11553 return result; 11554 } else { 11555 return false; 11556 } 11557} 11558 11559static bool VULKAN_INTERNAL_ValidateOptInVulkan12Features(VkPhysicalDeviceVulkan12Features *requested, VkPhysicalDeviceVulkan12Features *supported) 11560{ 11561 if (requested && supported) { 11562 bool result = true; 11563 11564 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, samplerMirrorClampToEdge, result) 11565 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, drawIndirectCount, result) 11566 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, storageBuffer8BitAccess, result) 11567 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, uniformAndStorageBuffer8BitAccess, result) 11568 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, storagePushConstant8, result) 11569 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, shaderBufferInt64Atomics, result) 11570 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, shaderSharedInt64Atomics, result) 11571 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, shaderFloat16, result) 11572 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, shaderInt8, result) 11573 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, descriptorIndexing, result) 11574 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, shaderInputAttachmentArrayDynamicIndexing, result) 11575 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, shaderUniformTexelBufferArrayDynamicIndexing, result) 11576 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, shaderStorageTexelBufferArrayDynamicIndexing, result) 11577 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, shaderUniformBufferArrayNonUniformIndexing, result) 11578 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, shaderSampledImageArrayNonUniformIndexing, result) 11579 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, shaderStorageBufferArrayNonUniformIndexing, result) 11580 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, shaderStorageImageArrayNonUniformIndexing, result) 11581 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, shaderInputAttachmentArrayNonUniformIndexing, result) 11582 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, shaderUniformTexelBufferArrayNonUniformIndexing, result) 11583 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, shaderStorageTexelBufferArrayNonUniformIndexing, result) 11584 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, descriptorBindingUniformBufferUpdateAfterBind, result) 11585 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, descriptorBindingSampledImageUpdateAfterBind, result) 11586 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, descriptorBindingStorageImageUpdateAfterBind, result) 11587 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, descriptorBindingStorageBufferUpdateAfterBind, result) 11588 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, descriptorBindingUniformTexelBufferUpdateAfterBind, result) 11589 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, descriptorBindingStorageTexelBufferUpdateAfterBind, result) 11590 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, descriptorBindingUpdateUnusedWhilePending, result) 11591 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, descriptorBindingPartiallyBound, result) 11592 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, descriptorBindingVariableDescriptorCount, result) 11593 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, runtimeDescriptorArray, result) 11594 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, samplerFilterMinmax, result) 11595 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, scalarBlockLayout, result) 11596 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, imagelessFramebuffer, result) 11597 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, uniformBufferStandardLayout, result) 11598 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, shaderSubgroupExtendedTypes, result) 11599 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, separateDepthStencilLayouts, result) 11600 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, hostQueryReset, result) 11601 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, timelineSemaphore, result) 11602 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, bufferDeviceAddress, result) 11603 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, bufferDeviceAddressCaptureReplay, result) 11604 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, bufferDeviceAddressMultiDevice, result) 11605 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, vulkanMemoryModel, result) 11606 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, vulkanMemoryModelDeviceScope, result) 11607 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, vulkanMemoryModelAvailabilityVisibilityChains, result) 11608 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, shaderOutputViewportIndex, result) 11609 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, shaderOutputLayer, result) 11610 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, subgroupBroadcastDynamicId, result) 11611 11612 return result; 11613 } else { 11614 return false; 11615 } 11616} 11617 11618static bool VULKAN_INTERNAL_ValidateOptInVulkan13Features(VkPhysicalDeviceVulkan13Features *requested, VkPhysicalDeviceVulkan13Features *supported) 11619{ 11620 if (requested && supported) { 11621 bool result = true; 11622 11623 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, robustImageAccess, result) 11624 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, inlineUniformBlock, result) 11625 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, descriptorBindingInlineUniformBlockUpdateAfterBind, result) 11626 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, pipelineCreationCacheControl, result) 11627 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, privateData, result) 11628 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, shaderDemoteToHelperInvocation, result) 11629 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, shaderTerminateInvocation, result) 11630 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, subgroupSizeControl, result) 11631 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, computeFullSubgroups, result) 11632 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, synchronization2, result) 11633 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, textureCompressionASTC_HDR, result) 11634 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, shaderZeroInitializeWorkgroupMemory, result) 11635 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, dynamicRendering, result) 11636 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, shaderIntegerDotProduct, result) 11637 CHECK_OPTIONAL_DEVICE_FEATURE(requested, supported, maintenance4, result) 11638 11639 return result; 11640 } else { 11641 return false; 11642 } 11643} 11644 11645#undef CHECK_OPTIONAL_DEVICE_FEATURE 11646 11647static bool VULKAN_INTERNAL_ValidateOptInFeatures(VulkanRenderer *renderer, VulkanFeatures *features, VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures *vk10Features) 11648{ 11649 bool supportsAllFeatures = true; 11650 11651 int minorVersion = VK_API_VERSION_MINOR(features->desiredApiVersion); 11652 11653 if (minorVersion < 1) { 11654 supportsAllFeatures &= VULKAN_INTERNAL_ValidateOptInVulkan10Features(&features->desiredVulkan10DeviceFeatures, vk10Features); 11655 } else if (minorVersion < 2) { 11656 // Query device features using the pre-1.2 structures 11657 VkPhysicalDevice16BitStorageFeatures storage = { 0 }; 11658 storage.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES; 11659 11660 VkPhysicalDeviceMultiviewFeatures multiview = { 0 }; 11661 multiview.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES; 11662 11663 VkPhysicalDeviceProtectedMemoryFeatures protectedMem = { 0 }; 11664 protectedMem.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_FEATURES; 11665 11666 VkPhysicalDeviceSamplerYcbcrConversionFeatures ycbcr = { 0 }; 11667 ycbcr.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES; 11668 11669 VkPhysicalDeviceShaderDrawParametersFeatures drawParams = { 0 }; 11670 drawParams.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETERS_FEATURES; 11671 11672 VkPhysicalDeviceVariablePointersFeatures varPointers = { 0 }; 11673 varPointers.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTERS_FEATURES; 11674 11675 VkPhysicalDeviceFeatures2 supportedFeatureList = { 0 }; 11676 supportedFeatureList.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; 11677 supportedFeatureList.pNext = &storage; 11678 storage.pNext = &multiview; 11679 multiview.pNext = &protectedMem; 11680 protectedMem.pNext = &ycbcr; 11681 ycbcr.pNext = &drawParams; 11682 drawParams.pNext = &varPointers; 11683 11684 renderer->vkGetPhysicalDeviceFeatures2(physicalDevice, &supportedFeatureList); 11685 11686 // Pack the results into the post-1.2 structure for easier checking 11687 VkPhysicalDeviceVulkan11Features vk11Features = { 0 }; 11688 vk11Features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES; 11689 vk11Features.storageBuffer16BitAccess = storage.storageBuffer16BitAccess; 11690 vk11Features.uniformAndStorageBuffer16BitAccess = storage.uniformAndStorageBuffer16BitAccess; 11691 vk11Features.storagePushConstant16 = storage.storagePushConstant16; 11692 vk11Features.storageInputOutput16 = storage.storageInputOutput16; 11693 vk11Features.multiview = multiview.multiview; 11694 vk11Features.multiviewGeometryShader = multiview.multiviewGeometryShader; 11695 vk11Features.multiviewTessellationShader = multiview.multiviewTessellationShader; 11696 vk11Features.protectedMemory = protectedMem.protectedMemory; 11697 vk11Features.samplerYcbcrConversion = ycbcr.samplerYcbcrConversion; 11698 vk11Features.shaderDrawParameters = drawParams.shaderDrawParameters; 11699 vk11Features.variablePointers = varPointers.variablePointers; 11700 vk11Features.variablePointersStorageBuffer = varPointers.variablePointersStorageBuffer; 11701 11702 // Check support 11703 supportsAllFeatures &= VULKAN_INTERNAL_ValidateOptInVulkan10Features(&features->desiredVulkan10DeviceFeatures, vk10Features); 11704 supportsAllFeatures &= VULKAN_INTERNAL_ValidateOptInVulkan11Features(&features->desiredVulkan11DeviceFeatures, &vk11Features); 11705 } else { 11706 VkPhysicalDeviceVulkan11Features vk11Features = { 0 }; 11707 vk11Features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES; 11708 11709 VkPhysicalDeviceVulkan12Features vk12Features = { 0 }; 11710 vk12Features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES; 11711 11712 VkPhysicalDeviceVulkan13Features vk13Features = { 0 }; 11713 vk13Features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES; 11714 11715 VkPhysicalDeviceFeatures2 supportedFeatureList = { 0 }; 11716 supportedFeatureList.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; 11717 supportedFeatureList.pNext = &vk11Features; 11718 vk11Features.pNext = &vk12Features; 11719 vk12Features.pNext = &vk13Features; 11720 11721 renderer->vkGetPhysicalDeviceFeatures2(physicalDevice, &supportedFeatureList); 11722 11723 supportsAllFeatures &= VULKAN_INTERNAL_ValidateOptInVulkan10Features(&features->desiredVulkan10DeviceFeatures, vk10Features); 11724 supportsAllFeatures &= VULKAN_INTERNAL_ValidateOptInVulkan11Features(&features->desiredVulkan11DeviceFeatures, &vk11Features); 11725 supportsAllFeatures &= VULKAN_INTERNAL_ValidateOptInVulkan12Features(&features->desiredVulkan12DeviceFeatures, &vk12Features); 11726 supportsAllFeatures &= VULKAN_INTERNAL_ValidateOptInVulkan13Features(&features->desiredVulkan13DeviceFeatures, &vk13Features); 11727 } 11728 11729 return supportsAllFeatures; 11730} 11731 11732static void VULKAN_INTERNAL_AddDeviceFeatures(VkBool32 *firstFeature, VkBool32 *lastFeature, VkBool32 *firstFeatureToAdd) 11733{ 11734 while (firstFeature <= lastFeature) { 11735 *firstFeature = (*firstFeature | *firstFeatureToAdd); 11736 firstFeature++; 11737 firstFeatureToAdd++; 11738 } 11739} 11740 11741static bool VULKAN_INTERNAL_TryAddDeviceFeatures_Vulkan_11(VkPhysicalDeviceFeatures *dst10, 11742 VkPhysicalDeviceVulkan11Features *dst11, 11743 VkBaseOutStructure *src) 11744{ 11745 bool hasAdded = false; 11746 switch (src->sType) { 11747 case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2: 11748 { 11749 VkPhysicalDeviceFeatures2 *newFeatures = (VkPhysicalDeviceFeatures2 *)src; 11750 VULKAN_INTERNAL_AddDeviceFeatures(&dst10->robustBufferAccess, 11751 &dst10->inheritedQueries, 11752 &newFeatures->features.robustBufferAccess); 11753 hasAdded = true; 11754 } break; 11755 11756 case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES: 11757 { 11758 VkPhysicalDevice16BitStorageFeatures *newFeatures = (VkPhysicalDevice16BitStorageFeatures *)src; 11759 dst11->storageBuffer16BitAccess |= newFeatures->storageBuffer16BitAccess; 11760 dst11->uniformAndStorageBuffer16BitAccess |= newFeatures->uniformAndStorageBuffer16BitAccess; 11761 dst11->storagePushConstant16 |= newFeatures->storagePushConstant16; 11762 dst11->storageInputOutput16 |= newFeatures->storageInputOutput16; 11763 hasAdded = true; 11764 } break; 11765 11766 case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES: 11767 { 11768 VkPhysicalDeviceMultiviewFeatures *newFeatures = (VkPhysicalDeviceMultiviewFeatures *)src; 11769 dst11->multiview |= newFeatures->multiview; 11770 dst11->multiviewGeometryShader |= newFeatures->multiviewGeometryShader; 11771 dst11->multiviewTessellationShader |= newFeatures->multiviewTessellationShader; 11772 hasAdded = true; 11773 } break; 11774 11775 case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_FEATURES: 11776 { 11777 VkPhysicalDeviceProtectedMemoryFeatures *newFeatures = (VkPhysicalDeviceProtectedMemoryFeatures *)src; 11778 dst11->protectedMemory |= newFeatures->protectedMemory; 11779 hasAdded = true; 11780 } break; 11781 11782 case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES: 11783 { 11784 VkPhysicalDeviceSamplerYcbcrConversionFeatures *newFeatures = (VkPhysicalDeviceSamplerYcbcrConversionFeatures *)src; 11785 dst11->samplerYcbcrConversion |= newFeatures->samplerYcbcrConversion; 11786 hasAdded = true; 11787 } break; 11788 11789 case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETERS_FEATURES: 11790 { 11791 VkPhysicalDeviceShaderDrawParametersFeatures *newFeatures = (VkPhysicalDeviceShaderDrawParametersFeatures *)src; 11792 dst11->shaderDrawParameters |= newFeatures->shaderDrawParameters; 11793 hasAdded = true; 11794 } break; 11795 11796 case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTERS_FEATURES: 11797 { 11798 VkPhysicalDeviceVariablePointersFeatures *newFeatures = (VkPhysicalDeviceVariablePointersFeatures *)src; 11799 dst11->variablePointers |= newFeatures->variablePointers; 11800 dst11->variablePointersStorageBuffer |= newFeatures->variablePointersStorageBuffer; 11801 hasAdded = true; 11802 } break; 11803 11804 default: 11805 break; 11806 } 11807 11808 return hasAdded; 11809} 11810 11811static bool VULKAN_INTERNAL_TryAddDeviceFeatures_Vulkan_12_Or_Later(VkPhysicalDeviceFeatures *dst10, 11812 VkPhysicalDeviceVulkan11Features *dst11, 11813 VkPhysicalDeviceVulkan12Features *dst12, 11814 VkPhysicalDeviceVulkan13Features *dst13, 11815 Uint32 apiVersion, 11816 VkBaseOutStructure *src) 11817{ 11818 int minorVersion = VK_API_VERSION_MINOR(apiVersion); 11819 SDL_assert(apiVersion >= 2); 11820 bool hasAdded = VULKAN_INTERNAL_TryAddDeviceFeatures_Vulkan_11(dst10, dst11, src); 11821 if (!hasAdded) { 11822 switch (src->sType) { 11823 case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES: 11824 { 11825 VkPhysicalDeviceVulkan11Features *newFeatures = (VkPhysicalDeviceVulkan11Features *)src; 11826 VULKAN_INTERNAL_AddDeviceFeatures(&dst11->storageBuffer16BitAccess, 11827 &dst11->shaderDrawParameters, 11828 &newFeatures->storageBuffer16BitAccess); 11829 hasAdded = true; 11830 } break; 11831 11832 case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES: 11833 { 11834 VkPhysicalDeviceVulkan12Features *newFeatures = (VkPhysicalDeviceVulkan12Features *)src; 11835 VULKAN_INTERNAL_AddDeviceFeatures(&dst12->samplerMirrorClampToEdge, 11836 &dst12->subgroupBroadcastDynamicId, 11837 &newFeatures->samplerMirrorClampToEdge); 11838 hasAdded = true; 11839 } break; 11840 11841 case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES: 11842 { 11843 if (minorVersion >= 3) { 11844 VkPhysicalDeviceVulkan13Features *newFeatures = (VkPhysicalDeviceVulkan13Features *)src; 11845 VULKAN_INTERNAL_AddDeviceFeatures(&dst13->robustImageAccess, 11846 &dst13->maintenance4, 11847 &newFeatures->robustImageAccess); 11848 hasAdded = true; 11849 } 11850 } break; 11851 11852 default: 11853 break; 11854 } 11855 } 11856 11857 return hasAdded; 11858} 11859 11860static void VULKAN_INTERNAL_AddOptInVulkanOptions(SDL_PropertiesID props, VulkanRenderer *renderer, VulkanFeatures *features) 11861{ 11862 if (SDL_HasProperty(props, SDL_PROP_GPU_DEVICE_CREATE_VULKAN_OPTIONS_POINTER)) { 11863 SDL_GPUVulkanOptions *options = (SDL_GPUVulkanOptions *)SDL_GetPointerProperty(props, SDL_PROP_GPU_DEVICE_CREATE_VULKAN_OPTIONS_POINTER, NULL); 11864 if (options) { 11865 features->usesCustomVulkanOptions = true; 11866 features->desiredApiVersion = options->vulkan_api_version; 11867 11868 SDL_zero(features->desiredVulkan11DeviceFeatures); 11869 SDL_zero(features->desiredVulkan12DeviceFeatures); 11870 SDL_zero(features->desiredVulkan13DeviceFeatures); 11871 features->desiredVulkan11DeviceFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES; 11872 features->desiredVulkan12DeviceFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES; 11873 features->desiredVulkan13DeviceFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES; 11874 11875 // Handle requested device features 11876 VkPhysicalDeviceFeatures *vk10Features = &features->desiredVulkan10DeviceFeatures; 11877 VkPhysicalDeviceVulkan11Features *vk11Features = &features->desiredVulkan11DeviceFeatures; 11878 VkPhysicalDeviceVulkan12Features *vk12Features = &features->desiredVulkan12DeviceFeatures; 11879 VkPhysicalDeviceVulkan13Features *vk13Features = &features->desiredVulkan13DeviceFeatures; 11880 11881 if (options->vulkan_10_physical_device_features) { 11882 VkPhysicalDeviceFeatures *deviceFeatures = (VkPhysicalDeviceFeatures *)options->vulkan_10_physical_device_features; 11883 VULKAN_INTERNAL_AddDeviceFeatures(&vk10Features->robustBufferAccess, 11884 &vk10Features->inheritedQueries, 11885 &deviceFeatures->robustBufferAccess); 11886 } 11887 11888 int minorVersion = VK_API_VERSION_MINOR(features->desiredApiVersion); 11889 bool supportsHigherLevelFeatures = minorVersion > 0; 11890 if (supportsHigherLevelFeatures && options->feature_list) { 11891 if (minorVersion < 2) { 11892 // Iterate through the entire list and combine all requested features 11893 VkBaseOutStructure *nextStructure = (VkBaseOutStructure *)options->feature_list; 11894 while (nextStructure) { 11895 VULKAN_INTERNAL_TryAddDeviceFeatures_Vulkan_11(vk10Features, vk11Features, nextStructure); 11896 nextStructure = nextStructure->pNext; 11897 } 11898 } else { 11899 // Iterate through the entire list and combine all requested features 11900 VkBaseOutStructure *nextStructure = (VkBaseOutStructure *)options->feature_list; 11901 while (nextStructure) { 11902 VULKAN_INTERNAL_TryAddDeviceFeatures_Vulkan_12_Or_Later(vk10Features, 11903 vk11Features, 11904 vk12Features, 11905 vk13Features, 11906 features->desiredApiVersion, 11907 nextStructure); 11908 nextStructure = nextStructure->pNext; 11909 } 11910 } 11911 } 11912 11913 features->additionalDeviceExtensionCount = options->device_extension_count; 11914 features->additionalDeviceExtensionNames = options->device_extension_names; 11915 features->additionalInstanceExtensionCount = options->instance_extension_count; 11916 features->additionalInstanceExtensionNames = options->instance_extension_names; 11917 } else if (renderer->debugMode) { 11918 SDL_LogWarn(SDL_LOG_CATEGORY_GPU, 11919 "VULKAN_INTERNAL_AddOptInVulkanOptions: Additional options property was set, but value was null. This may be a bug."); 11920 } 11921 } 11922} 11923 11924static Uint8 VULKAN_INTERNAL_CreateInstance(VulkanRenderer *renderer, VulkanFeatures *features) 11925{ 11926 VkResult vulkanResult; 11927 VkApplicationInfo appInfo; 11928 VkInstanceCreateFlags createFlags; 11929 const char *const *originalInstanceExtensionNames; 11930 const char **instanceExtensionNames; 11931 Uint32 instanceExtensionCount; 11932 VkInstanceCreateInfo createInfo; 11933 static const char *layerNames[] = { "VK_LAYER_KHRONOS_validation" }; 11934 11935 appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; 11936 appInfo.pNext = NULL; 11937 appInfo.pApplicationName = NULL; 11938 appInfo.applicationVersion = 0; 11939 appInfo.pEngineName = "SDLGPU"; 11940 appInfo.engineVersion = SDL_VERSION; 11941 appInfo.apiVersion = features->usesCustomVulkanOptions 11942 ? features->desiredApiVersion 11943 : VK_MAKE_VERSION(1, 0, 0); 11944 11945 createFlags = 0; 11946 11947 originalInstanceExtensionNames = SDL_Vulkan_GetInstanceExtensions(&instanceExtensionCount); 11948 if (!originalInstanceExtensionNames) { 11949 SDL_LogError( 11950 SDL_LOG_CATEGORY_GPU, 11951 "SDL_Vulkan_GetInstanceExtensions(): getExtensionCount: %s", 11952 SDL_GetError()); 11953 11954 return 0; 11955 } 11956 11957 Uint32 extraInstanceExtensionCount = features->additionalInstanceExtensionCount; 11958 const char** extraInstanceExtensionNames = features->additionalInstanceExtensionNames; 11959 11960 /* Extra space for the following extensions: 11961 * VK_KHR_get_physical_device_properties2 11962 * VK_EXT_swapchain_colorspace 11963 * VK_EXT_debug_utils 11964 * VK_KHR_portability_enumeration 11965 * 11966 * Plus additional opt-in extensions. 11967 */ 11968 instanceExtensionNames = SDL_stack_alloc( 11969 const char *, 11970 instanceExtensionCount + 4 + extraInstanceExtensionCount); 11971 const char** nextInstanceExtensionNamePtr = instanceExtensionNames; 11972 SDL_memcpy((void *)nextInstanceExtensionNamePtr, originalInstanceExtensionNames, instanceExtensionCount * sizeof(const char *)); 11973 nextInstanceExtensionNamePtr += instanceExtensionCount; 11974 11975 if (extraInstanceExtensionCount > 0) { 11976 SDL_memcpy((void *)nextInstanceExtensionNamePtr, extraInstanceExtensionNames, extraInstanceExtensionCount * sizeof(const char *)); 11977 nextInstanceExtensionNamePtr += extraInstanceExtensionCount; 11978 } 11979 11980 int firstUnsupportedExtensionIndex = 0; 11981 if (!VULKAN_INTERNAL_CheckInstanceExtensions( 11982 instanceExtensionNames, 11983 instanceExtensionCount + extraInstanceExtensionCount, 11984 &renderer->supportsDebugUtils, 11985 &renderer->supportsColorspace, 11986 &renderer->supportsPhysicalDeviceProperties2, 11987 &renderer->supportsPortabilityEnumeration, 11988 &firstUnsupportedExtensionIndex)) { 11989 if (renderer->debugMode) { 11990 SDL_LogError(SDL_LOG_CATEGORY_GPU, 11991 "Required Vulkan instance extension '%s' not supported", 11992 instanceExtensionNames[firstUnsupportedExtensionIndex]); 11993 } 11994 SDL_SetError("Required Vulkan instance extension '%s' not supported", 11995 instanceExtensionNames[firstUnsupportedExtensionIndex]); 11996 SDL_stack_free((char *)instanceExtensionNames); 11997 return false; 11998 } 11999 12000 if (renderer->supportsDebugUtils) { 12001 // Append the debug extension 12002 *nextInstanceExtensionNamePtr++ = VK_EXT_DEBUG_UTILS_EXTENSION_NAME; 12003 instanceExtensionCount++; 12004 } else { 12005 SDL_LogWarn( 12006 SDL_LOG_CATEGORY_GPU, 12007 "%s is not supported!", 12008 VK_EXT_DEBUG_UTILS_EXTENSION_NAME); 12009 } 12010 12011 if (renderer->supportsColorspace) { 12012 // Append colorspace extension 12013 *nextInstanceExtensionNamePtr++ = VK_EXT_SWAPCHAIN_COLOR_SPACE_EXTENSION_NAME; 12014 instanceExtensionCount++; 12015 } 12016 12017 if (renderer->supportsPhysicalDeviceProperties2) { 12018 // Append KHR_physical_device_properties2 extension 12019 *nextInstanceExtensionNamePtr++ = VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME; 12020 instanceExtensionCount++; 12021 } 12022 12023 if (renderer->supportsPortabilityEnumeration) { 12024 *nextInstanceExtensionNamePtr++ = VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME; 12025 instanceExtensionCount++; 12026 createFlags |= VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR; 12027 } 12028 12029 createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; 12030 createInfo.pNext = NULL; 12031 createInfo.flags = createFlags; 12032 createInfo.pApplicationInfo = &appInfo; 12033 createInfo.ppEnabledLayerNames = layerNames; 12034 createInfo.enabledExtensionCount = instanceExtensionCount + extraInstanceExtensionCount; 12035 createInfo.ppEnabledExtensionNames = instanceExtensionNames; 12036 if (renderer->debugMode) { 12037 createInfo.enabledLayerCount = SDL_arraysize(layerNames); 12038 if (!VULKAN_INTERNAL_CheckValidationLayers( 12039 layerNames, 12040 createInfo.enabledLayerCount)) { 12041 SDL_LogWarn(SDL_LOG_CATEGORY_GPU, "Validation layers not found, continuing without validation"); 12042 createInfo.enabledLayerCount = 0; 12043 } else { 12044 SDL_LogInfo(SDL_LOG_CATEGORY_GPU, "Validation layers enabled, expect debug level performance!"); 12045 } 12046 } else { 12047 createInfo.enabledLayerCount = 0; 12048 } 12049 12050#ifdef HAVE_GPU_OPENXR 12051 if (renderer->xrInstance) { 12052 XrResult xrResult; 12053 PFN_xrCreateVulkanInstanceKHR xrCreateVulkanInstanceKHR; 12054 if ((xrResult = xrGetInstanceProcAddr(renderer->xrInstance, "xrCreateVulkanInstanceKHR", (PFN_xrVoidFunction *)&xrCreateVulkanInstanceKHR)) != XR_SUCCESS) { 12055 SDL_LogDebug(SDL_LOG_CATEGORY_GPU, "Failed to get xrCreateVulkanInstanceKHR"); 12056 SDL_stack_free((char *)instanceExtensionNames); 12057 return 0; 12058 } 12059 12060 XrVulkanInstanceCreateInfoKHR xrCreateInfo; 12061 SDL_zero(xrCreateInfo); 12062 xrCreateInfo.type = XR_TYPE_VULKAN_INSTANCE_CREATE_INFO_KHR; 12063 xrCreateInfo.vulkanCreateInfo = &createInfo; 12064 xrCreateInfo.systemId = renderer->xrSystemId; 12065 xrCreateInfo.pfnGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)SDL_Vulkan_GetVkGetInstanceProcAddr(); 12066 SDL_assert(xrCreateInfo.pfnGetInstanceProcAddr); 12067 if ((xrResult = xrCreateVulkanInstanceKHR(renderer->xrInstance, &xrCreateInfo, &renderer->instance, &vulkanResult)) != XR_SUCCESS) { 12068 SDL_LogDebug(SDL_LOG_CATEGORY_GPU, "Failed to create vulkan instance, reason %d, %d", xrResult, vulkanResult); 12069 SDL_stack_free((char *)instanceExtensionNames); 12070 return 0; 12071 } 12072 } else 12073#endif // HAVE_GPU_OPENXR 12074 { 12075 vulkanResult = vkCreateInstance(&createInfo, NULL, &renderer->instance); 12076 } 12077 SDL_stack_free((char *)instanceExtensionNames); 12078 12079 if (vulkanResult != VK_SUCCESS) { 12080 CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkCreateInstance, 0); 12081 } 12082 12083 return 1; 12084} 12085 12086static bool VULKAN_INTERNAL_GetDeviceRank( 12087 VulkanRenderer *renderer, 12088 VkPhysicalDevice physicalDevice, 12089 VulkanExtensions *physicalDeviceExtensions, 12090 Uint64 *deviceRank) 12091{ 12092 static const Uint8 DEVICE_PRIORITY_HIGHPERFORMANCE[] = { 12093 0, // VK_PHYSICAL_DEVICE_TYPE_OTHER 12094 3, // VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU 12095 4, // VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU 12096 2, // VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU 12097 1 // VK_PHYSICAL_DEVICE_TYPE_CPU 12098 }; 12099 static const Uint8 DEVICE_PRIORITY_LOWPOWER[] = { 12100 0, // VK_PHYSICAL_DEVICE_TYPE_OTHER 12101 4, // VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU 12102 3, // VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU 12103 2, // VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU 12104 1 // VK_PHYSICAL_DEVICE_TYPE_CPU 12105 }; 12106 const Uint8 *devicePriority = renderer->preferLowPower ? DEVICE_PRIORITY_LOWPOWER : DEVICE_PRIORITY_HIGHPERFORMANCE; 12107 bool isConformant; 12108 12109 VkPhysicalDeviceType deviceType; 12110 if (physicalDeviceExtensions->KHR_driver_properties || physicalDeviceExtensions->MSFT_layered_driver) { 12111 VkPhysicalDeviceProperties2KHR physicalDeviceProperties; 12112 VkPhysicalDeviceDriverPropertiesKHR physicalDeviceDriverProperties = { 0 }; 12113 VkPhysicalDeviceLayeredDriverPropertiesMSFT physicalDeviceLayeredDriverProperties = { 0 }; 12114 void** ppNext = &physicalDeviceProperties.pNext; 12115 12116 physicalDeviceProperties.sType = 12117 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2; 12118 12119 if (physicalDeviceExtensions->KHR_driver_properties) { 12120 *ppNext = &physicalDeviceDriverProperties; 12121 ppNext = &physicalDeviceDriverProperties.pNext; 12122 12123 physicalDeviceDriverProperties.sType = 12124 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES_KHR; 12125 } 12126 12127 if (physicalDeviceExtensions->MSFT_layered_driver) { 12128 *ppNext = &physicalDeviceLayeredDriverProperties; 12129 ppNext = &physicalDeviceLayeredDriverProperties.pNext; 12130 12131 physicalDeviceLayeredDriverProperties.sType = 12132 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LAYERED_DRIVER_PROPERTIES_MSFT; 12133 } 12134 12135 *ppNext = NULL; 12136 renderer->vkGetPhysicalDeviceProperties2KHR( 12137 physicalDevice, 12138 &physicalDeviceProperties); 12139 12140 if (physicalDeviceExtensions->KHR_driver_properties) { 12141 isConformant = (physicalDeviceDriverProperties.conformanceVersion.major >= 1); 12142 } else { 12143 isConformant = true; // We can't check this, so just assume it's conformant 12144 } 12145 12146 if (physicalDeviceExtensions->MSFT_layered_driver && physicalDeviceLayeredDriverProperties.underlyingAPI != VK_LAYERED_DRIVER_UNDERLYING_API_NONE_MSFT) { 12147 /* Rank Dozen above CPU, but below INTEGRATED. 12148 * This is needed for WSL specifically. 12149 */ 12150 deviceType = VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU; 12151 12152 /* Dozen hasn't been tested for conformance and it probably won't be, 12153 * but WSL may need this so let's be generous. 12154 * -flibit 12155 */ 12156 isConformant = true; 12157 } else { 12158 deviceType = physicalDeviceProperties.properties.deviceType; 12159 } 12160 } else { 12161 VkPhysicalDeviceProperties physicalDeviceProperties; 12162 renderer->vkGetPhysicalDeviceProperties( 12163 physicalDevice, 12164 &physicalDeviceProperties); 12165 deviceType = physicalDeviceProperties.deviceType; 12166 isConformant = true; // We can't check this, so just assume it's conformant 12167 } 12168 12169 if (renderer->requireHardwareAcceleration) { 12170 if (deviceType != VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU && 12171 deviceType != VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU && 12172 deviceType != VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU) { 12173 // In addition to CPU, "Other" drivers (including layered drivers) don't count as hardware-accelerated 12174 return 0; 12175 } 12176 } 12177 12178 /* As far as I know, the only drivers available to users that are also 12179 * non-conformant are incomplete Mesa drivers and Vulkan-on-12. hasvk is one 12180 * example of a non-conformant driver that's built by default. 12181 * -flibit 12182 */ 12183 if (!isConformant) { 12184 return 0; 12185 } 12186 12187 /* Apply a large bias on the devicePriority so that we always respect the order in the priority arrays. 12188 * We also rank by e.g. VRAM which should have less influence than the device type. 12189 */ 12190 Uint64 devicePriorityValue = devicePriority[deviceType] * 1000000; 12191 12192 if (*deviceRank < devicePriorityValue) { 12193 /* This device outranks the best device we've found so far! 12194 * This includes a dedicated GPU that has less features than an 12195 * integrated GPU, because this is a freak case that is almost 12196 * never intentionally desired by the end user 12197 */ 12198 *deviceRank = devicePriorityValue; 12199 } else if (*deviceRank > devicePriorityValue) { 12200 /* Device is outranked by a previous device, don't even try to 12201 * run a query and reset the rank to avoid overwrites 12202 */ 12203 *deviceRank = 0; 12204 return false; 12205 } 12206 12207 /* If we prefer high performance, sum up all device local memory (rounded to megabytes) 12208 * to deviceRank. In the niche case of someone having multiple dedicated GPUs in the same 12209 * system, this theoretically picks the most powerful one (or at least the one with the 12210 * most memory!) 12211 * 12212 * We do this *after* discarding all non suitable devices, which means if this computer 12213 * has multiple dedicated GPUs that all meet our criteria, *and* the user asked for high 12214 * performance, then we always pick the GPU with more VRAM. 12215 */ 12216 if (!renderer->preferLowPower) { 12217 Uint32 i; 12218 Uint64 videoMemory = 0; 12219 VkPhysicalDeviceMemoryProperties deviceMemory; 12220 renderer->vkGetPhysicalDeviceMemoryProperties(physicalDevice, &deviceMemory); 12221 for (i = 0; i < deviceMemory.memoryHeapCount; i++) { 12222 VkMemoryHeap heap = deviceMemory.memoryHeaps[i]; 12223 if (heap.flags & VK_MEMORY_HEAP_DEVICE_LOCAL_BIT) { 12224 videoMemory += heap.size; 12225 } 12226 } 12227 // Round it to megabytes (as per the vulkan spec videoMemory is in bytes) 12228 Uint64 videoMemoryRounded = videoMemory / 1024 / 1024; 12229 *deviceRank += videoMemoryRounded; 12230 } 12231 12232 return true; 12233} 12234 12235static Uint8 VULKAN_INTERNAL_IsDeviceSuitable( 12236 VulkanRenderer *renderer, 12237 VulkanFeatures *features, 12238 VkPhysicalDevice physicalDevice, 12239 VulkanExtensions *physicalDeviceExtensions, 12240 Uint32 *queueFamilyIndex) 12241{ 12242 Uint32 queueFamilyCount, queueFamilyRank, queueFamilyBest; 12243 VkQueueFamilyProperties *queueProps; 12244 bool supportsPresent; 12245 VkPhysicalDeviceFeatures deviceFeatures; 12246 Uint32 i; 12247 12248 renderer->vkGetPhysicalDeviceFeatures( 12249 physicalDevice, 12250 &deviceFeatures); 12251 12252 if ((!deviceFeatures.independentBlend && features->desiredVulkan10DeviceFeatures.independentBlend) || 12253 (!deviceFeatures.imageCubeArray && features->desiredVulkan10DeviceFeatures.imageCubeArray) || 12254 (!deviceFeatures.depthClamp && features->desiredVulkan10DeviceFeatures.depthClamp) || 12255 (!deviceFeatures.shaderClipDistance && features->desiredVulkan10DeviceFeatures.shaderClipDistance) || 12256 (!deviceFeatures.drawIndirectFirstInstance && features->desiredVulkan10DeviceFeatures.drawIndirectFirstInstance) || 12257 (!deviceFeatures.sampleRateShading && features->desiredVulkan10DeviceFeatures.sampleRateShading) || 12258 (!deviceFeatures.samplerAnisotropy && features->desiredVulkan10DeviceFeatures.samplerAnisotropy)) { 12259 return 0; 12260 } 12261 12262 // Check opt-in device features 12263 if (features->usesCustomVulkanOptions) { 12264 bool supportsAllFeatures = VULKAN_INTERNAL_ValidateOptInFeatures(renderer, features, physicalDevice, &deviceFeatures); 12265 if (!supportsAllFeatures) { 12266 return 0; 12267 } 12268 } 12269 12270 if (!VULKAN_INTERNAL_CheckDeviceExtensions( 12271 renderer, 12272 features, 12273 physicalDevice, 12274 physicalDeviceExtensions)) { 12275 return 0; 12276 } 12277 12278 renderer->vkGetPhysicalDeviceQueueFamilyProperties( 12279 physicalDevice, 12280 &queueFamilyCount, 12281 NULL); 12282 12283 queueProps = SDL_stack_alloc( 12284 VkQueueFamilyProperties, 12285 queueFamilyCount); 12286 renderer->vkGetPhysicalDeviceQueueFamilyProperties( 12287 physicalDevice, 12288 &queueFamilyCount, 12289 queueProps); 12290 12291 queueFamilyBest = 0; 12292 *queueFamilyIndex = SDL_MAX_UINT32; 12293 for (i = 0; i < queueFamilyCount; i += 1) { 12294 supportsPresent = SDL_Vulkan_GetPresentationSupport( 12295 renderer->instance, 12296 physicalDevice, 12297 i); 12298 if (!supportsPresent || 12299 !(queueProps[i].queueFlags & VK_QUEUE_GRAPHICS_BIT)) { 12300 // Not a graphics family, ignore. 12301 continue; 12302 } 12303 12304 /* The queue family bitflags are kind of annoying. 12305 * 12306 * We of course need a graphics family, but we ideally want the 12307 * _primary_ graphics family. The spec states that at least one 12308 * graphics family must also be a compute family, so generally 12309 * drivers make that the first one. But hey, maybe something 12310 * genuinely can't do compute or something, and FNA doesn't 12311 * need it, so we'll be open to a non-compute queue family. 12312 * 12313 * Additionally, it's common to see the primary queue family 12314 * have the transfer bit set, which is great! But this is 12315 * actually optional; it's impossible to NOT have transfers in 12316 * graphics/compute but it _is_ possible for a graphics/compute 12317 * family, even the primary one, to just decide not to set the 12318 * bitflag. Admittedly, a driver may want to isolate transfer 12319 * queues to a dedicated family so that queues made solely for 12320 * transfers can have an optimized DMA queue. 12321 * 12322 * That, or the driver author got lazy and decided not to set 12323 * the bit. Looking at you, Android. 12324 * 12325 * -flibit 12326 */ 12327 if (queueProps[i].queueFlags & VK_QUEUE_COMPUTE_BIT) { 12328 if (queueProps[i].queueFlags & VK_QUEUE_TRANSFER_BIT) { 12329 // Has all attribs! 12330 queueFamilyRank = 3; 12331 } else { 12332 // Probably has a DMA transfer queue family 12333 queueFamilyRank = 2; 12334 } 12335 } else { 12336 // Just a graphics family, probably has something better 12337 queueFamilyRank = 1; 12338 } 12339 if (queueFamilyRank > queueFamilyBest) { 12340 *queueFamilyIndex = i; 12341 queueFamilyBest = queueFamilyRank; 12342 } 12343 } 12344 12345 SDL_stack_free(queueProps); 12346 12347 if (*queueFamilyIndex == SDL_MAX_UINT32) { 12348 // Somehow no graphics queues existed. Compute-only device? 12349 return 0; 12350 } 12351 12352 // FIXME: Need better structure for checking vs storing swapchain support details 12353 return 1; 12354} 12355 12356static Uint8 VULKAN_INTERNAL_DeterminePhysicalDevice(VulkanRenderer *renderer, VulkanFeatures *features) 12357{ 12358 VkResult vulkanResult; 12359 VkPhysicalDevice *physicalDevices; 12360 VulkanExtensions *physicalDeviceExtensions; 12361 Uint32 i, physicalDeviceCount; 12362 Sint32 suitableIndex; 12363 Uint32 suitableQueueFamilyIndex; 12364 Uint64 highestRank; 12365 12366#ifdef HAVE_GPU_OPENXR 12367 // When XR is enabled, let the OpenXR runtime choose the physical device 12368 if (renderer->xrInstance) { 12369 XrResult xrResult; 12370 VulkanExtensions xrPhysicalDeviceExtensions; 12371 Uint32 queueFamilyIndex; 12372 PFN_xrGetVulkanGraphicsDevice2KHR xrGetVulkanGraphicsDevice2KHR; 12373 12374 xrResult = xrGetInstanceProcAddr( 12375 renderer->xrInstance, 12376 "xrGetVulkanGraphicsDevice2KHR", 12377 (PFN_xrVoidFunction *)&xrGetVulkanGraphicsDevice2KHR); 12378 if (xrResult != XR_SUCCESS) { 12379 SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to get xrGetVulkanGraphicsDevice2KHR, result: %d", xrResult); 12380 return 0; 12381 } 12382 12383 XrVulkanGraphicsDeviceGetInfoKHR graphicsDeviceGetInfo; 12384 SDL_zero(graphicsDeviceGetInfo); 12385 graphicsDeviceGetInfo.type = XR_TYPE_VULKAN_GRAPHICS_DEVICE_GET_INFO_KHR; 12386 graphicsDeviceGetInfo.systemId = renderer->xrSystemId; 12387 graphicsDeviceGetInfo.vulkanInstance = renderer->instance; 12388 12389 xrResult = xrGetVulkanGraphicsDevice2KHR( 12390 renderer->xrInstance, 12391 &graphicsDeviceGetInfo, 12392 &renderer->physicalDevice); 12393 if (xrResult != XR_SUCCESS) { 12394 SDL_LogError(SDL_LOG_CATEGORY_GPU, "xrGetVulkanGraphicsDevice2KHR failed, result: %d", xrResult); 12395 return 0; 12396 } 12397 12398 // Verify the XR-chosen device is suitable 12399 if (!VULKAN_INTERNAL_IsDeviceSuitable( 12400 renderer, 12401 features, 12402 renderer->physicalDevice, 12403 &xrPhysicalDeviceExtensions, 12404 &queueFamilyIndex)) { 12405 SDL_LogError(SDL_LOG_CATEGORY_GPU, "The physical device chosen by the OpenXR runtime is not suitable"); 12406 return 0; 12407 } 12408 12409 renderer->supports = xrPhysicalDeviceExtensions; 12410 renderer->queueFamilyIndex = queueFamilyIndex; 12411 } else 12412#endif // HAVE_GPU_OPENXR 12413 { 12414 vulkanResult = renderer->vkEnumeratePhysicalDevices( 12415 renderer->instance, 12416 &physicalDeviceCount, 12417 NULL); 12418 CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkEnumeratePhysicalDevices, 0); 12419 12420 if (physicalDeviceCount == 0) { 12421 SDL_LogInfo(SDL_LOG_CATEGORY_GPU, "Failed to find any GPUs with Vulkan support"); 12422 return 0; 12423 } 12424 12425 physicalDevices = SDL_stack_alloc(VkPhysicalDevice, physicalDeviceCount); 12426 physicalDeviceExtensions = SDL_stack_alloc(VulkanExtensions, physicalDeviceCount); 12427 12428 vulkanResult = renderer->vkEnumeratePhysicalDevices( 12429 renderer->instance, 12430 &physicalDeviceCount, 12431 physicalDevices); 12432 12433 /* This should be impossible to hit, but from what I can tell this can 12434 * be triggered not because the array is too small, but because there 12435 * were drivers that turned out to be bogus, so this is the loader's way 12436 * of telling us that the list is now smaller than expected :shrug: 12437 */ 12438 if (vulkanResult == VK_INCOMPLETE) { 12439 SDL_LogWarn(SDL_LOG_CATEGORY_GPU, "vkEnumeratePhysicalDevices returned VK_INCOMPLETE, will keep trying anyway..."); 12440 vulkanResult = VK_SUCCESS; 12441 } 12442 12443 if (vulkanResult != VK_SUCCESS) { 12444 SDL_LogWarn( 12445 SDL_LOG_CATEGORY_GPU, 12446 "vkEnumeratePhysicalDevices failed: %s", 12447 VkErrorMessages(vulkanResult)); 12448 SDL_stack_free(physicalDevices); 12449 SDL_stack_free(physicalDeviceExtensions); 12450 return 0; 12451 } 12452 12453 // Any suitable device will do, but we'd like the best 12454 suitableIndex = -1; 12455 suitableQueueFamilyIndex = 0; 12456 highestRank = 0; 12457 for (i = 0; i < physicalDeviceCount; i += 1) { 12458 Uint32 queueFamilyIndex; 12459 Uint64 deviceRank; 12460 12461 if (!VULKAN_INTERNAL_IsDeviceSuitable( 12462 renderer, 12463 features, 12464 physicalDevices[i], 12465 &physicalDeviceExtensions[i], 12466 &queueFamilyIndex)) { 12467 // Device does not meet the minimum requirements, skip it entirely 12468 continue; 12469 } 12470 12471 deviceRank = highestRank; 12472 if (VULKAN_INTERNAL_GetDeviceRank( 12473 renderer, 12474 physicalDevices[i], 12475 &physicalDeviceExtensions[i], 12476 &deviceRank)) { 12477 /* Use this for rendering. 12478 * Note that this may override a previous device that 12479 * supports rendering, but shares the same device rank. 12480 */ 12481 suitableIndex = i; 12482 suitableQueueFamilyIndex = queueFamilyIndex; 12483 highestRank = deviceRank; 12484 } 12485 } 12486 12487 if (suitableIndex != -1) { 12488 renderer->supports = physicalDeviceExtensions[suitableIndex]; 12489 renderer->physicalDevice = physicalDevices[suitableIndex]; 12490 renderer->queueFamilyIndex = suitableQueueFamilyIndex; 12491 } else { 12492 SDL_stack_free(physicalDevices); 12493 SDL_stack_free(physicalDeviceExtensions); 12494 return 0; 12495 } 12496 12497 SDL_stack_free(physicalDevices); 12498 SDL_stack_free(physicalDeviceExtensions); 12499 } 12500 12501 renderer->physicalDeviceProperties.sType = 12502 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2; 12503 if (renderer->supports.KHR_driver_properties) { 12504 renderer->physicalDeviceDriverProperties.sType = 12505 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES_KHR; 12506 renderer->physicalDeviceDriverProperties.pNext = NULL; 12507 12508 renderer->physicalDeviceProperties.pNext = 12509 &renderer->physicalDeviceDriverProperties; 12510 12511 renderer->vkGetPhysicalDeviceProperties2KHR( 12512 renderer->physicalDevice, 12513 &renderer->physicalDeviceProperties); 12514 } else { 12515 renderer->physicalDeviceProperties.pNext = NULL; 12516 12517 renderer->vkGetPhysicalDeviceProperties( 12518 renderer->physicalDevice, 12519 &renderer->physicalDeviceProperties.properties); 12520 } 12521 12522 renderer->vkGetPhysicalDeviceMemoryProperties( 12523 renderer->physicalDevice, 12524 &renderer->memoryProperties); 12525 12526 return 1; 12527} 12528 12529static Uint8 VULKAN_INTERNAL_CreateLogicalDevice( 12530 VulkanRenderer *renderer, 12531 VulkanFeatures *features) 12532{ 12533 VkResult vulkanResult; 12534 VkDeviceCreateInfo deviceCreateInfo; 12535 VkPhysicalDeviceFeatures haveDeviceFeatures; 12536 VkPhysicalDevicePortabilitySubsetFeaturesKHR portabilityFeatures; 12537 const char **deviceExtensions; 12538 12539 VkDeviceQueueCreateInfo queueCreateInfo; 12540 float queuePriority = 1.0f; 12541 12542 queueCreateInfo.sType = 12543 VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; 12544 queueCreateInfo.pNext = NULL; 12545 queueCreateInfo.flags = 0; 12546 queueCreateInfo.queueFamilyIndex = renderer->queueFamilyIndex; 12547 queueCreateInfo.queueCount = 1; 12548 queueCreateInfo.pQueuePriorities = &queuePriority; 12549 12550 // check feature support 12551 12552 renderer->vkGetPhysicalDeviceFeatures( 12553 renderer->physicalDevice, 12554 &haveDeviceFeatures); 12555 12556 // specifying used device features 12557 12558 if (haveDeviceFeatures.fillModeNonSolid) { 12559 features->desiredVulkan10DeviceFeatures.fillModeNonSolid = VK_TRUE; 12560 renderer->supportsFillModeNonSolid = true; 12561 } 12562 12563 if (haveDeviceFeatures.multiDrawIndirect) { 12564 features->desiredVulkan10DeviceFeatures.multiDrawIndirect = VK_TRUE; 12565 renderer->supportsMultiDrawIndirect = true; 12566 } 12567 12568 // creating the logical device 12569 12570 deviceCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; 12571 if (renderer->supports.KHR_portability_subset) { 12572 portabilityFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PORTABILITY_SUBSET_FEATURES_KHR; 12573 portabilityFeatures.pNext = NULL; 12574 portabilityFeatures.constantAlphaColorBlendFactors = VK_FALSE; 12575 portabilityFeatures.events = VK_FALSE; 12576 portabilityFeatures.imageViewFormatReinterpretation = VK_FALSE; 12577 portabilityFeatures.imageViewFormatSwizzle = VK_TRUE; 12578 portabilityFeatures.imageView2DOn3DImage = VK_FALSE; 12579 portabilityFeatures.multisampleArrayImage = VK_FALSE; 12580 portabilityFeatures.mutableComparisonSamplers = VK_FALSE; 12581 portabilityFeatures.pointPolygons = VK_FALSE; 12582 portabilityFeatures.samplerMipLodBias = VK_FALSE; // Technically should be true, but eh 12583 portabilityFeatures.separateStencilMaskRef = VK_FALSE; 12584 portabilityFeatures.shaderSampleRateInterpolationFunctions = VK_FALSE; 12585 portabilityFeatures.tessellationIsolines = VK_FALSE; 12586 portabilityFeatures.tessellationPointMode = VK_FALSE; 12587 portabilityFeatures.triangleFans = VK_FALSE; 12588 portabilityFeatures.vertexAttributeAccessBeyondStride = VK_FALSE; 12589 deviceCreateInfo.pNext = &portabilityFeatures; 12590 } else { 12591 deviceCreateInfo.pNext = NULL; 12592 } 12593 deviceCreateInfo.flags = 0; 12594 deviceCreateInfo.queueCreateInfoCount = 1; 12595 deviceCreateInfo.pQueueCreateInfos = &queueCreateInfo; 12596 deviceCreateInfo.enabledLayerCount = 0; 12597 deviceCreateInfo.ppEnabledLayerNames = NULL; 12598 deviceCreateInfo.enabledExtensionCount = GetDeviceExtensionCount( 12599 &renderer->supports); 12600 deviceExtensions = SDL_stack_alloc( 12601 const char *, 12602 deviceCreateInfo.enabledExtensionCount); 12603 CreateDeviceExtensionArray(&renderer->supports, deviceExtensions); 12604 deviceCreateInfo.ppEnabledExtensionNames = deviceExtensions; 12605 12606 VkPhysicalDeviceFeatures2 featureList; 12607 int minor = VK_VERSION_MINOR(features->desiredApiVersion); 12608 12609 struct { 12610 VkPhysicalDevice16BitStorageFeatures storage; 12611 VkPhysicalDeviceMultiviewFeatures multiview; 12612 VkPhysicalDeviceProtectedMemoryFeatures protectedMem; 12613 VkPhysicalDeviceSamplerYcbcrConversionFeatures ycbcr; 12614 VkPhysicalDeviceShaderDrawParametersFeatures drawParams; 12615 VkPhysicalDeviceVariablePointersFeatures varPointers; 12616 } legacyFeatures; 12617 12618 if (features->usesCustomVulkanOptions && minor > 0) { 12619 featureList.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; 12620 featureList.features = features->desiredVulkan10DeviceFeatures; 12621 if (minor > 1) { 12622 featureList.pNext = &features->desiredVulkan11DeviceFeatures; 12623 features->desiredVulkan11DeviceFeatures.pNext = &features->desiredVulkan12DeviceFeatures; 12624 features->desiredVulkan12DeviceFeatures.pNext = minor > 2 ? &features->desiredVulkan13DeviceFeatures : NULL; 12625 features->desiredVulkan13DeviceFeatures.pNext = NULL; 12626 } else { 12627 // Break VkPhysicalDeviceVulkan11Features into pre 1.2 structures for Vulkan 1.1 Support 12628 SDL_zero(legacyFeatures); 12629 12630 legacyFeatures.storage.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES; 12631 legacyFeatures.storage.storageBuffer16BitAccess = features->desiredVulkan11DeviceFeatures.storageBuffer16BitAccess; 12632 legacyFeatures.storage.storageInputOutput16 = features->desiredVulkan11DeviceFeatures.storageInputOutput16; 12633 legacyFeatures.storage.storagePushConstant16 = features->desiredVulkan11DeviceFeatures.storagePushConstant16; 12634 legacyFeatures.storage.uniformAndStorageBuffer16BitAccess = features->desiredVulkan11DeviceFeatures.uniformAndStorageBuffer16BitAccess; 12635 12636 legacyFeatures.multiview.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES; 12637 legacyFeatures.multiview.multiview = features->desiredVulkan11DeviceFeatures.multiview; 12638 legacyFeatures.multiview.multiviewGeometryShader = features->desiredVulkan11DeviceFeatures.multiviewGeometryShader; 12639 legacyFeatures.multiview.multiviewTessellationShader = features->desiredVulkan11DeviceFeatures.multiviewTessellationShader; 12640 12641 legacyFeatures.protectedMem.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_FEATURES; 12642 legacyFeatures.protectedMem.protectedMemory = features->desiredVulkan11DeviceFeatures.protectedMemory; 12643 12644 legacyFeatures.ycbcr.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES; 12645 legacyFeatures.ycbcr.samplerYcbcrConversion = features->desiredVulkan11DeviceFeatures.samplerYcbcrConversion; 12646 12647 legacyFeatures.drawParams.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETERS_FEATURES; 12648 legacyFeatures.drawParams.shaderDrawParameters = features->desiredVulkan11DeviceFeatures.shaderDrawParameters; 12649 12650 legacyFeatures.varPointers.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTERS_FEATURES; 12651 legacyFeatures.varPointers.variablePointers = features->desiredVulkan11DeviceFeatures.variablePointers; 12652 legacyFeatures.varPointers.variablePointersStorageBuffer = features->desiredVulkan11DeviceFeatures.variablePointersStorageBuffer; 12653 12654 featureList.pNext = &legacyFeatures.storage; 12655 legacyFeatures.storage.pNext = &legacyFeatures.multiview; 12656 legacyFeatures.multiview.pNext = &legacyFeatures.protectedMem; 12657 legacyFeatures.protectedMem.pNext = &legacyFeatures.ycbcr; 12658 legacyFeatures.ycbcr.pNext = &legacyFeatures.drawParams; 12659 legacyFeatures.drawParams.pNext = &legacyFeatures.varPointers; 12660 } 12661 deviceCreateInfo.pEnabledFeatures = NULL; 12662 deviceCreateInfo.pNext = &featureList; 12663 } else { 12664 deviceCreateInfo.pEnabledFeatures = &features->desiredVulkan10DeviceFeatures; 12665 } 12666 12667#ifdef HAVE_GPU_OPENXR 12668 if (renderer->xrInstance) { 12669 XrResult xrResult; 12670 PFN_xrCreateVulkanDeviceKHR xrCreateVulkanDeviceKHR; 12671 if ((xrResult = xrGetInstanceProcAddr(renderer->xrInstance, "xrCreateVulkanDeviceKHR", (PFN_xrVoidFunction *)&xrCreateVulkanDeviceKHR)) != XR_SUCCESS) { 12672 SDL_LogDebug(SDL_LOG_CATEGORY_GPU, "Failed to get xrCreateVulkanDeviceKHR"); 12673 SDL_stack_free((void *)deviceExtensions); 12674 return 0; 12675 } 12676 12677 XrVulkanDeviceCreateInfoKHR xrDeviceCreateInfo; 12678 SDL_zero(xrDeviceCreateInfo); 12679 xrDeviceCreateInfo.type = XR_TYPE_VULKAN_DEVICE_CREATE_INFO_KHR; 12680 xrDeviceCreateInfo.vulkanCreateInfo = &deviceCreateInfo; 12681 xrDeviceCreateInfo.systemId = renderer->xrSystemId; 12682 xrDeviceCreateInfo.vulkanPhysicalDevice = renderer->physicalDevice; 12683 xrDeviceCreateInfo.pfnGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)SDL_Vulkan_GetVkGetInstanceProcAddr(); 12684 SDL_assert(xrDeviceCreateInfo.pfnGetInstanceProcAddr); 12685 if ((xrResult = xrCreateVulkanDeviceKHR(renderer->xrInstance, &xrDeviceCreateInfo, &renderer->logicalDevice, &vulkanResult)) != XR_SUCCESS) { 12686 SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to create OpenXR Vulkan logical device, result %d, %d", xrResult, vulkanResult); 12687 SDL_stack_free((void *)deviceExtensions); 12688 return 0; 12689 } 12690 } else 12691#endif // HAVE_GPU_OPENXR 12692 { 12693 vulkanResult = renderer->vkCreateDevice( 12694 renderer->physicalDevice, 12695 &deviceCreateInfo, 12696 NULL, 12697 &renderer->logicalDevice); 12698 } 12699 SDL_stack_free((void *)deviceExtensions); 12700 CHECK_VULKAN_ERROR_AND_RETURN(vulkanResult, vkCreateDevice, 0); 12701 12702 // Load vkDevice entry points 12703 12704#define VULKAN_DEVICE_FUNCTION(func) \ 12705 renderer->func = (PFN_##func) \ 12706 renderer->vkGetDeviceProcAddr( \ 12707 renderer->logicalDevice, \ 12708 #func); 12709#include "SDL_gpu_vulkan_vkfuncs.h" 12710 12711 renderer->vkGetDeviceQueue( 12712 renderer->logicalDevice, 12713 renderer->queueFamilyIndex, 12714 0, 12715 &renderer->unifiedQueue); 12716 12717 return 1; 12718} 12719 12720static void VULKAN_INTERNAL_LoadEntryPoints(void) 12721{ 12722 // Required for MoltenVK support 12723 SDL_setenv_unsafe("MVK_CONFIG_FULL_IMAGE_VIEW_SWIZZLE", "1", 1); 12724 12725 // Load Vulkan entry points 12726 if (!SDL_Vulkan_LoadLibrary(NULL)) { 12727 SDL_LogWarn(SDL_LOG_CATEGORY_GPU, "Vulkan: SDL_Vulkan_LoadLibrary failed!"); 12728 return; 12729 } 12730 12731#ifdef HAVE_GCC_DIAGNOSTIC_PRAGMA 12732#pragma GCC diagnostic push 12733#pragma GCC diagnostic ignored "-Wpedantic" 12734#endif 12735 vkGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)SDL_Vulkan_GetVkGetInstanceProcAddr(); 12736#ifdef HAVE_GCC_DIAGNOSTIC_PRAGMA 12737#pragma GCC diagnostic pop 12738#endif 12739 if (vkGetInstanceProcAddr == NULL) { 12740 SDL_LogWarn( 12741 SDL_LOG_CATEGORY_GPU, 12742 "SDL_Vulkan_GetVkGetInstanceProcAddr(): %s", 12743 SDL_GetError()); 12744 return; 12745 } 12746 12747#define VULKAN_GLOBAL_FUNCTION(name) \ 12748 name = (PFN_##name)vkGetInstanceProcAddr(VK_NULL_HANDLE, #name); \ 12749 if (name == NULL) { \ 12750 SDL_LogWarn(SDL_LOG_CATEGORY_GPU, "vkGetInstanceProcAddr(VK_NULL_HANDLE, \"" #name "\") failed"); \ 12751 return; \ 12752 } 12753#include "SDL_gpu_vulkan_vkfuncs.h" 12754} 12755 12756static bool VULKAN_INTERNAL_PrepareVulkan( 12757 VulkanRenderer *renderer, 12758 VulkanFeatures *features, 12759 SDL_PropertiesID props) 12760{ 12761 VULKAN_INTERNAL_LoadEntryPoints(); 12762 12763 SDL_zerop(features); 12764 12765 // Opt out device features (higher compatibility in exchange for reduced functionality) 12766 features->desiredVulkan10DeviceFeatures.samplerAnisotropy = SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_FEATURE_ANISOTROPY_BOOLEAN, true) ? VK_TRUE : VK_FALSE; 12767 features->desiredVulkan10DeviceFeatures.depthClamp = SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_FEATURE_DEPTH_CLAMPING_BOOLEAN, true) ? VK_TRUE : VK_FALSE; 12768 features->desiredVulkan10DeviceFeatures.shaderClipDistance = SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_FEATURE_CLIP_DISTANCE_BOOLEAN, true) ? VK_TRUE : VK_FALSE; 12769 features->desiredVulkan10DeviceFeatures.drawIndirectFirstInstance = SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_FEATURE_INDIRECT_DRAW_FIRST_INSTANCE_BOOLEAN, true) ? VK_TRUE : VK_FALSE; 12770 12771 // These features have near universal support so they are always enabled 12772 features->desiredVulkan10DeviceFeatures.independentBlend = VK_TRUE; 12773 features->desiredVulkan10DeviceFeatures.sampleRateShading = VK_TRUE; 12774 features->desiredVulkan10DeviceFeatures.imageCubeArray = VK_TRUE; 12775 12776 // Handle opt-in device features 12777 VULKAN_INTERNAL_AddOptInVulkanOptions(props, renderer, features); 12778 12779 renderer->requireHardwareAcceleration = SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_VULKAN_REQUIRE_HARDWARE_ACCELERATION_BOOLEAN, false); 12780 12781 if (!VULKAN_INTERNAL_CreateInstance(renderer, features)) { 12782 SDL_LogWarn(SDL_LOG_CATEGORY_GPU, "Vulkan: Could not create Vulkan instance"); 12783 return false; 12784 } 12785 12786#define VULKAN_INSTANCE_FUNCTION(func) \ 12787 renderer->func = (PFN_##func)vkGetInstanceProcAddr(renderer->instance, #func); 12788#include "SDL_gpu_vulkan_vkfuncs.h" 12789 12790 if (!VULKAN_INTERNAL_DeterminePhysicalDevice(renderer, features)) { 12791 SDL_LogWarn(SDL_LOG_CATEGORY_GPU, "Vulkan: Failed to determine a suitable physical device"); 12792 return false; 12793 } 12794 return true; 12795} 12796 12797#ifdef HAVE_GPU_OPENXR 12798static bool VULKAN_INTERNAL_SearchForOpenXrGpuExtension(XrExtensionProperties *found_extension) 12799{ 12800 XrResult result; 12801 Uint32 extension_count; 12802 Uint32 i; 12803 12804 result = xrEnumerateInstanceExtensionProperties(NULL, 0, &extension_count, NULL); 12805 if (result != XR_SUCCESS) 12806 return false; 12807 12808 XrExtensionProperties *extension_properties = (XrExtensionProperties *)SDL_calloc(extension_count, sizeof(XrExtensionProperties)); 12809 for (i = 0; i < extension_count; i++) 12810 extension_properties[i].type = XR_TYPE_EXTENSION_PROPERTIES; 12811 12812 result = xrEnumerateInstanceExtensionProperties(NULL, extension_count, &extension_count, extension_properties); 12813 if (result != XR_SUCCESS) { 12814 SDL_free(extension_properties); 12815 return false; 12816 } 12817 12818 for (i = 0; i < extension_count; i++) { 12819 XrExtensionProperties extension = extension_properties[i]; 12820 12821 // NOTE: as generally recommended, we support KHR_vulkan_enable2 *only* 12822 // see https://fredemmott.com/blog/2024/11/25/best-practices-for-openxr-api-layers.html 12823 if (SDL_strcmp(extension.extensionName, XR_KHR_VULKAN_ENABLE2_EXTENSION_NAME) == 0) { 12824 SDL_LogInfo(SDL_LOG_CATEGORY_GPU, "Found " XR_KHR_VULKAN_ENABLE2_EXTENSION_NAME " extension"); 12825 12826 *found_extension = extension; 12827 12828 SDL_free(extension_properties); 12829 return true; 12830 } 12831 } 12832 12833 SDL_free(extension_properties); 12834 return false; 12835} 12836 12837static XrResult VULKAN_INTERNAL_GetXrMinimumVulkanApiVersion(XrVersion *minimumVulkanApiVersion, XrInstance instance, XrSystemId systemId) 12838{ 12839 XrResult xrResult; 12840 12841 PFN_xrGetVulkanGraphicsRequirements2KHR xrGetVulkanGraphicsRequirements2KHR; 12842 if ((xrResult = xrGetInstanceProcAddr(instance, "xrGetVulkanGraphicsRequirements2KHR", (PFN_xrVoidFunction *)&xrGetVulkanGraphicsRequirements2KHR)) != XR_SUCCESS) { 12843 SDL_LogDebug(SDL_LOG_CATEGORY_GPU, "Failed to get xrGetVulkanGraphicsRequirements2KHR"); 12844 return xrResult; 12845 } 12846 12847 XrGraphicsRequirementsVulkanKHR graphicsRequirementsVulkan; 12848 SDL_zero(graphicsRequirementsVulkan); 12849 graphicsRequirementsVulkan.type = XR_TYPE_GRAPHICS_REQUIREMENTS_VULKAN2_KHR; 12850 if ((xrResult = xrGetVulkanGraphicsRequirements2KHR(instance, systemId, &graphicsRequirementsVulkan)) != XR_SUCCESS) { 12851 SDL_LogDebug(SDL_LOG_CATEGORY_GPU, "Failed to get vulkan graphics requirements, got OpenXR error %d", xrResult); 12852 return xrResult; 12853 } 12854 12855 *minimumVulkanApiVersion = graphicsRequirementsVulkan.minApiVersionSupported; 12856 return XR_SUCCESS; 12857} 12858#endif // HAVE_GPU_OPENXR 12859 12860static bool VULKAN_PrepareDriver(SDL_VideoDevice *_this, SDL_PropertiesID props) 12861{ 12862 // Set up dummy VulkanRenderer 12863 VulkanRenderer *renderer; 12864 VulkanFeatures features; 12865 bool result = false; 12866 12867 if (!SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_SHADERS_SPIRV_BOOLEAN, false)) { 12868 return false; 12869 } 12870 12871 if (_this->Vulkan_CreateSurface == NULL) { 12872 return false; 12873 } 12874 12875 if (!SDL_Vulkan_LoadLibrary(NULL)) { 12876 return false; 12877 } 12878 12879#ifdef HAVE_GPU_OPENXR 12880 XrResult xrResult; 12881 XrInstancePfns *instancePfns = NULL; 12882 XrInstance xrInstance = XR_NULL_HANDLE; 12883 XrSystemId xrSystemId = XR_NULL_HANDLE; 12884 bool xr = SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_XR_ENABLE_BOOLEAN, false); 12885 12886#ifdef SDL_PLATFORM_ANDROID 12887 /* On Android/Quest, don't test XR in PrepareDriver. The Quest OpenXR runtime 12888 * can't handle having its instance created and destroyed during preparation 12889 * and then recreated during device creation. Just return true for XR mode 12890 * and let CreateDevice do the real work. */ 12891 if (xr) { 12892 SDL_Vulkan_UnloadLibrary(); 12893 return true; 12894 } 12895#endif 12896 12897 if (xr) { 12898 if (!SDL_OpenXR_LoadLibrary()) { 12899 SDL_LogWarn(SDL_LOG_CATEGORY_GPU, "Vulkan: Failed to load OpenXR: %s", SDL_GetError()); 12900 SDL_Vulkan_UnloadLibrary(); 12901 return false; 12902 } 12903 12904 XrExtensionProperties gpuExtension; 12905 if (!VULKAN_INTERNAL_SearchForOpenXrGpuExtension(&gpuExtension)) { 12906 SDL_SetError("Failed to find a suitable OpenXR GPU extension."); 12907 SDL_Vulkan_UnloadLibrary(); 12908 SDL_OpenXR_UnloadLibrary(); 12909 return false; 12910 } 12911 12912 const char *extensionName = gpuExtension.extensionName; 12913 if ((xrResult = xrCreateInstance(&(XrInstanceCreateInfo){ 12914 .type = XR_TYPE_INSTANCE_CREATE_INFO, 12915 .applicationInfo = { 12916 .apiVersion = SDL_GetNumberProperty(props, SDL_PROP_GPU_DEVICE_CREATE_XR_VERSION_NUMBER, XR_API_VERSION_1_0), 12917 .applicationName = "SDL", 12918 }, 12919 .enabledExtensionCount = 1, 12920 .enabledExtensionNames = &extensionName, 12921 }, 12922 &xrInstance)) != XR_SUCCESS) { 12923 SDL_LogDebug(SDL_LOG_CATEGORY_GPU, "Failed to create OpenXR instance"); 12924 SDL_Vulkan_UnloadLibrary(); 12925 SDL_OpenXR_UnloadLibrary(); 12926 return false; 12927 } 12928 12929 instancePfns = SDL_OPENXR_LoadInstanceSymbols(xrInstance); 12930 if (!instancePfns) { 12931 SDL_LogDebug(SDL_LOG_CATEGORY_GPU, "Failed to load needed OpenXR instance symbols"); 12932 SDL_Vulkan_UnloadLibrary(); 12933 SDL_OpenXR_UnloadLibrary(); 12934 return false; 12935 } 12936 12937 if ((xrResult = instancePfns->xrGetSystem(xrInstance, &(XrSystemGetInfo){ 12938 .type = XR_TYPE_SYSTEM_GET_INFO, 12939 .formFactor = (XrFormFactor)SDL_GetNumberProperty(props, SDL_PROP_GPU_DEVICE_CREATE_XR_FORM_FACTOR_NUMBER, XR_FORM_FACTOR_HEAD_MOUNTED_DISPLAY), 12940 }, 12941 &xrSystemId)) != XR_SUCCESS) { 12942 SDL_LogDebug(SDL_LOG_CATEGORY_GPU, "Failed to get OpenXR system"); 12943 instancePfns->xrDestroyInstance(xrInstance); 12944 SDL_Vulkan_UnloadLibrary(); 12945 SDL_OpenXR_UnloadLibrary(); 12946 SDL_free(instancePfns); 12947 return false; 12948 } 12949 } 12950#endif // HAVE_GPU_OPENXR 12951 12952 renderer = (VulkanRenderer *)SDL_calloc(1, sizeof(*renderer)); 12953 if (renderer) { 12954 // This needs to be set early for log filtering 12955 renderer->debugMode = SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_DEBUGMODE_BOOLEAN, false); 12956 12957 renderer->preferLowPower = SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_PREFERLOWPOWER_BOOLEAN, false); 12958 12959 renderer->minimumVkVersion = VK_API_VERSION_1_0; 12960#ifdef HAVE_GPU_OPENXR 12961 renderer->xrInstance = xrInstance; 12962 renderer->xrSystemId = xrSystemId; 12963 12964 if (xr) { 12965 XrVersion minimumVkVersionXr; 12966 xrResult = VULKAN_INTERNAL_GetXrMinimumVulkanApiVersion(&minimumVkVersionXr, xrInstance, xrSystemId); 12967 if (xrResult != XR_SUCCESS) { 12968 SDL_SetError("Failed to get the minimum supported Vulkan API version."); 12969 instancePfns->xrDestroyInstance(xrInstance); 12970 SDL_Vulkan_UnloadLibrary(); 12971 SDL_OpenXR_UnloadLibrary(); 12972 SDL_free(instancePfns); 12973 SDL_free(renderer); 12974 return false; 12975 } 12976 renderer->minimumVkVersion = VK_MAKE_API_VERSION( 12977 0, 12978 XR_VERSION_MAJOR(minimumVkVersionXr), 12979 XR_VERSION_MINOR(minimumVkVersionXr), 12980 XR_VERSION_PATCH(minimumVkVersionXr)); 12981 } 12982#endif // HAVE_GPU_OPENXR 12983 12984 result = VULKAN_INTERNAL_PrepareVulkan(renderer, &features, props); 12985 if (result) { 12986 renderer->vkDestroyInstance(renderer->instance, NULL); 12987 } 12988 12989#ifdef HAVE_GPU_OPENXR 12990 if (instancePfns) { 12991 instancePfns->xrDestroyInstance(xrInstance); 12992 SDL_free(instancePfns); 12993 SDL_OpenXR_UnloadLibrary(); 12994 } 12995#endif // HAVE_GPU_OPENXR 12996 12997 SDL_free(renderer); 12998 } 12999 SDL_Vulkan_UnloadLibrary(); 13000 13001 return result; 13002} 13003 13004static XrResult VULKAN_DestroyXRSwapchain( 13005 SDL_GPURenderer *driverData, 13006 XrSwapchain swapchain, 13007 SDL_GPUTexture **swapchainImages) 13008{ 13009#ifdef HAVE_GPU_OPENXR 13010 XrResult result; 13011 VulkanRenderer *renderer = (VulkanRenderer *)driverData; 13012 13013 VULKAN_Wait(driverData); 13014 13015 Uint32 swapchainCount; 13016 result = renderer->xr->xrEnumerateSwapchainImages(swapchain, 0, &swapchainCount, NULL); 13017 if (result != XR_SUCCESS) { 13018 return result; 13019 } 13020 13021 // We always want to destroy the swapchain images, so don't early return if xrDestroySwapchain fails for some reason 13022 for (Uint32 i = 0; i < swapchainCount; i++) { 13023 VulkanTextureContainer *container = (VulkanTextureContainer *)swapchainImages[i]; 13024 13025 if (!container->externallyManaged) { 13026 SDL_SetError("Invalid GPU Texture handle."); 13027 return XR_ERROR_HANDLE_INVALID; 13028 } 13029 13030 VULKAN_INTERNAL_DestroyTexture(renderer, container->activeTexture); 13031 13032 // Free the container now that it's unused 13033 SDL_free(container); 13034 } 13035 13036 SDL_free(swapchainImages); 13037 13038 return renderer->xr->xrDestroySwapchain(swapchain); 13039#else 13040 SDL_SetError("SDL not built with OpenXR support"); 13041 return XR_ERROR_FUNCTION_UNSUPPORTED; 13042#endif 13043} 13044 13045#ifdef HAVE_GPU_OPENXR 13046static bool VULKAN_INTERNAL_FindXRSrgbSwapchain(int64_t *supportedFormats, Uint32 numFormats, SDL_GPUTextureFormat *sdlFormat, int64_t *vkFormat) 13047{ 13048 for (Uint32 i = 0; i < SDL_arraysize(SDLToVK_TextureFormat_SrgbOnly); i++) { 13049 for (Uint32 j = 0; j < numFormats; j++) { 13050 if (SDLToVK_TextureFormat_SrgbOnly[i].vk == supportedFormats[j]) { 13051 *sdlFormat = SDLToVK_TextureFormat_SrgbOnly[i].sdl; 13052 *vkFormat = SDLToVK_TextureFormat_SrgbOnly[i].vk; 13053 return true; 13054 } 13055 } 13056 } 13057 13058 return false; 13059} 13060#endif // HAVE_GPU_OPENXR 13061 13062static SDL_GPUTextureFormat* VULKAN_GetXRSwapchainFormats( 13063 SDL_GPURenderer *driverData, 13064 XrSession session, 13065 int *num_formats) 13066{ 13067#ifdef HAVE_GPU_OPENXR 13068 XrResult result; 13069 Uint32 i, j, num_supported_formats; 13070 int64_t *supported_formats; 13071 VulkanRenderer *renderer = (VulkanRenderer *)driverData; 13072 13073 result = renderer->xr->xrEnumerateSwapchainFormats(session, 0, &num_supported_formats, NULL); 13074 if (result != XR_SUCCESS) return NULL; 13075 supported_formats = SDL_stack_alloc(int64_t, num_supported_formats); 13076 result = renderer->xr->xrEnumerateSwapchainFormats(session, num_supported_formats, &num_supported_formats, supported_formats); 13077 if (result != XR_SUCCESS) { 13078 SDL_stack_free(supported_formats); 13079 return NULL; 13080 } 13081 13082 // FIXME: For now we're just searching for the optimal format, not all supported formats. 13083 // FIXME: Expand this search for all SDL_GPU formats! 13084 13085 SDL_GPUTextureFormat sdlFormat = SDL_GPU_TEXTUREFORMAT_INVALID; 13086 int64_t vkFormat = VK_FORMAT_UNDEFINED; 13087 // 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 13088 if (!VULKAN_INTERNAL_FindXRSrgbSwapchain(supported_formats, num_supported_formats, &sdlFormat, &vkFormat)) { 13089 // Iterate over all formats the runtime supports 13090 for (i = 0; i < num_supported_formats && vkFormat == VK_FORMAT_UNDEFINED; i++) { 13091 // Iterate over all formats we support 13092 for (j = 0; j < SDL_arraysize(SDLToVK_TextureFormat); j++) { 13093 // Pick the first format the runtime wants that we also support, the runtime should return these in order of preference 13094 if (SDLToVK_TextureFormat[j] == supported_formats[i]) { 13095 vkFormat = supported_formats[i]; 13096 sdlFormat = j; 13097 break; 13098 } 13099 } 13100 } 13101 } 13102 13103 SDL_stack_free(supported_formats); 13104 13105 if (vkFormat == VK_FORMAT_UNDEFINED) { 13106 SDL_SetError("Failed to find a swapchain format supported by both OpenXR and SDL"); 13107 return NULL; 13108 } 13109 13110 SDL_GPUTextureFormat *retval = (SDL_GPUTextureFormat*) SDL_malloc(sizeof(SDL_GPUTextureFormat) * 2); 13111 retval[0] = sdlFormat; 13112 retval[1] = SDL_GPU_TEXTUREFORMAT_INVALID; 13113 *num_formats = 1; 13114 return retval; 13115#else 13116 SDL_SetError("SDL not built with OpenXR support"); 13117 return NULL; 13118#endif 13119} 13120 13121static XrResult VULKAN_CreateXRSwapchain( 13122 SDL_GPURenderer *driverData, 13123 XrSession session, 13124 const XrSwapchainCreateInfo *oldCreateInfo, 13125 SDL_GPUTextureFormat format, 13126 XrSwapchain *swapchain, 13127 SDL_GPUTexture ***textures) 13128{ 13129#ifdef HAVE_GPU_OPENXR 13130 XrResult result; 13131 Uint32 i, j; 13132 VulkanRenderer *renderer = (VulkanRenderer *)driverData; 13133 13134 XrSwapchainCreateInfo createInfo = *oldCreateInfo; 13135 createInfo.format = SDLToVK_TextureFormat[format]; 13136 13137 result = renderer->xr->xrCreateSwapchain(session, &createInfo, swapchain); 13138 if (result != XR_SUCCESS) return result; 13139 13140 Uint32 swapchainImageCount; 13141 result = renderer->xr->xrEnumerateSwapchainImages(*swapchain, 0, &swapchainImageCount, NULL); 13142 if (result != XR_SUCCESS) return result; 13143 13144 XrSwapchainImageVulkan2KHR *swapchainImages = (XrSwapchainImageVulkan2KHR *)SDL_calloc(swapchainImageCount, sizeof(XrSwapchainImageVulkan2KHR)); 13145 for (i = 0; i < swapchainImageCount; i++) swapchainImages[i].type = XR_TYPE_SWAPCHAIN_IMAGE_VULKAN2_KHR; 13146 13147 result = renderer->xr->xrEnumerateSwapchainImages(*swapchain, swapchainImageCount, &swapchainImageCount, (XrSwapchainImageBaseHeader *)swapchainImages); 13148 if (result != XR_SUCCESS) { 13149 SDL_free(swapchainImages); 13150 return result; 13151 } 13152 13153 VulkanTextureContainer **textureContainers = (VulkanTextureContainer **)SDL_calloc(swapchainImageCount, sizeof(VulkanTextureContainer *)); 13154 13155 for (Uint32 idx = 0; idx < swapchainImageCount; idx++) { 13156 VkImage vkImage = swapchainImages[idx].image; 13157 13158 VulkanTexture *texture = SDL_calloc(1, sizeof(VulkanTexture)); 13159 13160 texture->swizzle = SwizzleForSDLFormat(format); 13161 texture->depth = 1; 13162 texture->usage = SDL_GPU_TEXTUREUSAGE_COLOR_TARGET; 13163 SDL_SetAtomicInt(&texture->referenceCount, 0); 13164 texture->image = vkImage; 13165 texture->externallyManaged = true; 13166 texture->aspectFlags = VK_IMAGE_ASPECT_COLOR_BIT; 13167 13168 texture->subresourceCount = createInfo.arraySize * createInfo.mipCount; 13169 texture->subresources = SDL_calloc( 13170 texture->subresourceCount, 13171 sizeof(VulkanTextureSubresource)); 13172 13173 for (i = 0; i < createInfo.arraySize; i += 1) { 13174 for (j = 0; j < createInfo.mipCount; j += 1) { 13175 Uint32 subresourceIndex = VULKAN_INTERNAL_GetTextureSubresourceIndex( 13176 j, 13177 i, 13178 createInfo.mipCount); 13179 13180 if (createInfo.usageFlags & XR_SWAPCHAIN_USAGE_COLOR_ATTACHMENT_BIT) { 13181 texture->subresources[subresourceIndex].renderTargetViews = SDL_malloc(sizeof(VkImageView)); 13182 13183 if (!VULKAN_INTERNAL_CreateRenderTargetView( 13184 renderer, 13185 texture, 13186 i, 13187 j, 13188 SDLToVK_TextureFormat[format], 13189 texture->swizzle, 13190 &texture->subresources[subresourceIndex].renderTargetViews[0])) { 13191 VULKAN_INTERNAL_DestroyTexture(renderer, texture); 13192 SDL_SetError("Failed to create render target view"); 13193 return XR_ERROR_RUNTIME_FAILURE; 13194 } 13195 } 13196 13197 texture->subresources[subresourceIndex].parent = texture; 13198 texture->subresources[subresourceIndex].layer = i; 13199 texture->subresources[subresourceIndex].level = j; 13200 } 13201 } 13202 13203 // Transition to the default barrier state 13204 VulkanCommandBuffer *barrierCommandBuffer = (VulkanCommandBuffer *)VULKAN_AcquireCommandBuffer((SDL_GPURenderer *)renderer); 13205 VULKAN_INTERNAL_TextureTransitionToDefaultUsage( 13206 renderer, 13207 barrierCommandBuffer, 13208 VULKAN_TEXTURE_USAGE_MODE_UNINITIALIZED, 13209 texture); 13210 VULKAN_INTERNAL_TrackTexture(barrierCommandBuffer, texture); 13211 VULKAN_Submit((SDL_GPUCommandBuffer *)barrierCommandBuffer); 13212 13213 textureContainers[idx] = SDL_malloc(sizeof(VulkanTextureContainer)); 13214 VulkanTextureContainer *container = textureContainers[idx]; 13215 SDL_zero(container->header.info); 13216 container->header.info.width = createInfo.width; 13217 container->header.info.height = createInfo.height; 13218 container->header.info.format = format; 13219 container->header.info.layer_count_or_depth = createInfo.arraySize; 13220 container->header.info.num_levels = createInfo.mipCount; 13221 container->header.info.sample_count = SDL_GPU_SAMPLECOUNT_1; 13222 container->header.info.usage = SDL_GPU_TEXTUREUSAGE_COLOR_TARGET; 13223 13224 container->externallyManaged = true; 13225 container->canBeCycled = false; 13226 container->activeTexture = texture; 13227 container->textureCapacity = 1; 13228 container->textureCount = 1; 13229 container->textures = SDL_malloc( 13230 container->textureCapacity * sizeof(VulkanTexture *)); 13231 container->textures[0] = container->activeTexture; 13232 container->debugName = NULL; 13233 } 13234 13235 *textures = (SDL_GPUTexture **)textureContainers; 13236 13237 SDL_free(swapchainImages); 13238 return XR_SUCCESS; 13239#else 13240 SDL_SetError("SDL not built with OpenXR support"); 13241 return XR_ERROR_FUNCTION_UNSUPPORTED; 13242#endif 13243} 13244 13245static XrResult VULKAN_CreateXRSession( 13246 SDL_GPURenderer *driverData, 13247 const XrSessionCreateInfo *createinfo, 13248 XrSession *session) 13249{ 13250#ifdef HAVE_GPU_OPENXR 13251 VulkanRenderer *renderer = (VulkanRenderer *)driverData; 13252 13253 // Copy out the existing next ptr so that we can append it to the end of the chain we create 13254 const void *XR_MAY_ALIAS currentNextPtr = createinfo->next; 13255 13256 // KHR_vulkan_enable and KHR_vulkan_enable2 share this structure, so we don't need to change any logic here to handle both 13257 XrGraphicsBindingVulkanKHR graphicsBinding; 13258 SDL_zero(graphicsBinding); 13259 graphicsBinding.type = XR_TYPE_GRAPHICS_BINDING_VULKAN_KHR; 13260 graphicsBinding.instance = renderer->instance; 13261 graphicsBinding.physicalDevice = renderer->physicalDevice; 13262 graphicsBinding.device = renderer->logicalDevice; 13263 graphicsBinding.queueFamilyIndex = renderer->queueFamilyIndex; 13264 graphicsBinding.queueIndex = 0; // we only ever have one queue, so hardcode queue index 0 13265 graphicsBinding.next = currentNextPtr; 13266 13267 XrSessionCreateInfo sessionCreateInfo = *createinfo; 13268 sessionCreateInfo.systemId = renderer->xrSystemId; 13269 sessionCreateInfo.next = &graphicsBinding; 13270 13271 return renderer->xr->xrCreateSession(renderer->xrInstance, &sessionCreateInfo, session); 13272#else 13273 SDL_SetError("SDL not built with OpenXR support"); 13274 return XR_ERROR_FUNCTION_UNSUPPORTED; 13275#endif 13276} 13277 13278static SDL_GPUDevice *VULKAN_CreateDevice(bool debugMode, bool preferLowPower, SDL_PropertiesID props) 13279{ 13280 VulkanRenderer *renderer; 13281 VulkanFeatures features; 13282 13283 SDL_GPUDevice *result; 13284 Uint32 i; 13285 13286 bool verboseLogs = SDL_GetBooleanProperty( 13287 props, 13288 SDL_PROP_GPU_DEVICE_CREATE_VERBOSE_BOOLEAN, 13289 true); 13290 13291 if (!SDL_Vulkan_LoadLibrary(NULL)) { 13292 SDL_assert(!"This should have failed in PrepareDevice first!"); 13293 return NULL; 13294 } 13295 13296 renderer = (VulkanRenderer *)SDL_calloc(1, sizeof(*renderer)); 13297 if (!renderer) { 13298 SDL_Vulkan_UnloadLibrary(); 13299 return NULL; 13300 } 13301 13302 renderer->debugMode = debugMode; 13303 renderer->preferLowPower = preferLowPower; 13304 renderer->allowedFramesInFlight = 2; 13305 renderer->minimumVkVersion = VK_API_VERSION_1_0; 13306 13307#ifdef HAVE_GPU_OPENXR 13308 bool xr = SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_XR_ENABLE_BOOLEAN, false); 13309 XrInstance *xrInstance = SDL_GetPointerProperty(props, SDL_PROP_GPU_DEVICE_CREATE_XR_INSTANCE_POINTER, NULL); 13310 XrSystemId *xrSystemId = SDL_GetPointerProperty(props, SDL_PROP_GPU_DEVICE_CREATE_XR_SYSTEM_ID_POINTER, NULL); 13311 13312 if (xr) { 13313 XrExtensionProperties gpuExtension; 13314 13315 if (!xrInstance) { 13316 SDL_SetError("You must specify an out pointer for the OpenXR instance"); 13317 SDL_free(renderer); 13318 SDL_Vulkan_UnloadLibrary(); 13319 return NULL; 13320 } 13321 13322 if (!xrSystemId) { 13323 SDL_SetError("You must specify an out pointer for the OpenXR system ID"); 13324 SDL_free(renderer); 13325 SDL_Vulkan_UnloadLibrary(); 13326 return NULL; 13327 } 13328 13329 if (!SDL_OpenXR_LoadLibrary()) { 13330 SDL_assert(!"This should have failed in PrepareDevice first!"); 13331 SDL_free(renderer); 13332 SDL_Vulkan_UnloadLibrary(); 13333 return NULL; 13334 } 13335 13336 if (!VULKAN_INTERNAL_SearchForOpenXrGpuExtension(&gpuExtension)) { 13337 SDL_LogDebug(SDL_LOG_CATEGORY_GPU, "Failed to find a compatible OpenXR vulkan extension"); 13338 SDL_OpenXR_UnloadLibrary(); 13339 SDL_free(renderer); 13340 SDL_Vulkan_UnloadLibrary(); 13341 return NULL; 13342 } 13343 13344 if (!SDL_OPENXR_INTERNAL_GPUInitOpenXR(debugMode, gpuExtension, props, xrInstance, xrSystemId, &renderer->xr)) { 13345 SDL_LogDebug(SDL_LOG_CATEGORY_GPU, "Failed to init OpenXR"); 13346 SDL_OpenXR_UnloadLibrary(); 13347 SDL_free(renderer); 13348 SDL_Vulkan_UnloadLibrary(); 13349 return NULL; 13350 } 13351 13352 renderer->xrInstance = *xrInstance; 13353 renderer->xrSystemId = *xrSystemId; 13354 13355 XrVersion minimumVulkanApiVersion; 13356 if (VULKAN_INTERNAL_GetXrMinimumVulkanApiVersion(&minimumVulkanApiVersion, *xrInstance, *xrSystemId) != XR_SUCCESS) { 13357 SDL_LogDebug(SDL_LOG_CATEGORY_GPU, "Failed to get OpenXR graphics requirements"); 13358 renderer->xr->xrDestroyInstance(*xrInstance); 13359 SDL_OpenXR_UnloadLibrary(); 13360 SDL_free(renderer->xr); 13361 SDL_free(renderer); 13362 SDL_Vulkan_UnloadLibrary(); 13363 return NULL; 13364 } 13365 13366 renderer->minimumVkVersion = VK_MAKE_VERSION( 13367 XR_VERSION_MAJOR(minimumVulkanApiVersion), 13368 XR_VERSION_MINOR(minimumVulkanApiVersion), 13369 XR_VERSION_PATCH(minimumVulkanApiVersion)); 13370 } 13371#endif // HAVE_GPU_OPENXR 13372 13373 if (!VULKAN_INTERNAL_PrepareVulkan(renderer, &features, props)) { 13374 SET_STRING_ERROR("Failed to initialize Vulkan!"); 13375#ifdef HAVE_GPU_OPENXR 13376 if (xr) { 13377 renderer->xr->xrDestroyInstance(*xrInstance); 13378 SDL_OpenXR_UnloadLibrary(); 13379 SDL_free(renderer->xr); 13380 } 13381#endif // HAVE_GPU_OPENXR 13382 SDL_free(renderer); 13383 SDL_Vulkan_UnloadLibrary(); 13384 return NULL; 13385 } 13386 13387 renderer->props = SDL_CreateProperties(); 13388 if (verboseLogs) { 13389 SDL_LogInfo(SDL_LOG_CATEGORY_GPU, "SDL_GPU Driver: Vulkan"); 13390 } 13391 13392 // Record device name 13393 const char *deviceName = renderer->physicalDeviceProperties.properties.deviceName; 13394 SDL_SetStringProperty( 13395 renderer->props, 13396 SDL_PROP_GPU_DEVICE_NAME_STRING, 13397 deviceName); 13398 if (verboseLogs) { 13399 SDL_LogInfo(SDL_LOG_CATEGORY_GPU, "Vulkan Device: %s", deviceName); 13400 } 13401 13402 // Record driver version. This is provided as a backup if 13403 // VK_KHR_driver_properties is not available but as most drivers support it 13404 // this property should be rarely used. 13405 // 13406 // This uses a vendor-specific encoding and it isn't well documented. The 13407 // vendor ID is the registered PCI ID of the vendor and can be found in 13408 // online databases. 13409 char driverVer[64]; 13410 Uint32 rawDriverVer = renderer->physicalDeviceProperties.properties.driverVersion; 13411 Uint32 vendorId = renderer->physicalDeviceProperties.properties.vendorID; 13412 if (vendorId == 0x10de) { 13413 // Nvidia uses 10|8|8|6 encoding. 13414 (void)SDL_snprintf( 13415 driverVer, 13416 SDL_arraysize(driverVer), 13417 "%d.%d.%d.%d", 13418 (rawDriverVer >> 22) & 0x3ff, 13419 (rawDriverVer >> 14) & 0xff, 13420 (rawDriverVer >> 6) & 0xff, 13421 rawDriverVer & 0x3f); 13422 } 13423#ifdef SDL_PLATFORM_WINDOWS 13424 else if (vendorId == 0x8086) { 13425 // Intel uses 18|14 encoding on Windows only. 13426 (void)SDL_snprintf( 13427 driverVer, 13428 SDL_arraysize(driverVer), 13429 "%d.%d", 13430 (rawDriverVer >> 14) & 0x3ffff, 13431 rawDriverVer & 0x3fff); 13432 } 13433#endif 13434 else { 13435 // Assume standard Vulkan 10|10|12 encoding for everything else. AMD and 13436 // Mesa are known to use this encoding. 13437 (void)SDL_snprintf( 13438 driverVer, 13439 SDL_arraysize(driverVer), 13440 "%d.%d.%d", 13441 (rawDriverVer >> 22) & 0x3ff, 13442 (rawDriverVer >> 12) & 0x3ff, 13443 rawDriverVer & 0xfff); 13444 } 13445 SDL_SetStringProperty( 13446 renderer->props, 13447 SDL_PROP_GPU_DEVICE_DRIVER_VERSION_STRING, 13448 driverVer); 13449 // Log this only if VK_KHR_driver_properties is not available. 13450 13451 if (renderer->supports.KHR_driver_properties) { 13452 // Record driver name and version 13453 const char *driverName = renderer->physicalDeviceDriverProperties.driverName; 13454 const char *driverInfo = renderer->physicalDeviceDriverProperties.driverInfo; 13455 SDL_SetStringProperty( 13456 renderer->props, 13457 SDL_PROP_GPU_DEVICE_DRIVER_NAME_STRING, 13458 driverName); 13459 SDL_SetStringProperty( 13460 renderer->props, 13461 SDL_PROP_GPU_DEVICE_DRIVER_INFO_STRING, 13462 driverInfo); 13463 if (verboseLogs) { 13464 // FIXME: driverInfo can be a multiline string. 13465 SDL_LogInfo(SDL_LOG_CATEGORY_GPU, "Vulkan Driver: %s %s", driverName, driverInfo); 13466 } 13467 13468 // Record conformance level 13469 if (verboseLogs) { 13470 char conformance[64]; 13471 (void)SDL_snprintf( 13472 conformance, 13473 SDL_arraysize(conformance), 13474 "%u.%u.%u.%u", 13475 renderer->physicalDeviceDriverProperties.conformanceVersion.major, 13476 renderer->physicalDeviceDriverProperties.conformanceVersion.minor, 13477 renderer->physicalDeviceDriverProperties.conformanceVersion.subminor, 13478 renderer->physicalDeviceDriverProperties.conformanceVersion.patch); 13479 SDL_LogInfo(SDL_LOG_CATEGORY_GPU, "Vulkan Conformance: %s", conformance); 13480 } 13481 } else { 13482 if (verboseLogs) { 13483 SDL_LogInfo(SDL_LOG_CATEGORY_GPU, "Vulkan Driver: %s", driverVer); 13484 } 13485 } 13486 13487 if (!VULKAN_INTERNAL_CreateLogicalDevice(renderer, &features)) { 13488 SET_STRING_ERROR("Failed to create logical device!"); 13489 SDL_free(renderer); 13490 SDL_Vulkan_UnloadLibrary(); 13491 return NULL; 13492 } 13493 13494 // FIXME: just move this into this function 13495 result = (SDL_GPUDevice *)SDL_calloc(1, sizeof(SDL_GPUDevice)); 13496 ASSIGN_DRIVER(VULKAN) 13497 13498 result->driverData = (SDL_GPURenderer *)renderer; 13499 result->shader_formats = SDL_GPU_SHADERFORMAT_SPIRV; 13500 13501 /* 13502 * Create initial swapchain array 13503 */ 13504 13505 renderer->claimedWindowCapacity = 1; 13506 renderer->claimedWindowCount = 0; 13507 renderer->claimedWindows = SDL_malloc( 13508 renderer->claimedWindowCapacity * sizeof(WindowData *)); 13509 13510 // Threading 13511 13512 renderer->allocatorLock = SDL_CreateMutex(); 13513 renderer->disposeLock = SDL_CreateMutex(); 13514 renderer->submitLock = SDL_CreateMutex(); 13515 renderer->acquireCommandBufferLock = SDL_CreateMutex(); 13516 renderer->acquireUniformBufferLock = SDL_CreateMutex(); 13517 renderer->renderPassFetchLock = SDL_CreateMutex(); 13518 renderer->framebufferFetchLock = SDL_CreateMutex(); 13519 renderer->graphicsPipelineLayoutFetchLock = SDL_CreateMutex(); 13520 renderer->computePipelineLayoutFetchLock = SDL_CreateMutex(); 13521 renderer->descriptorSetLayoutFetchLock = SDL_CreateMutex(); 13522 renderer->windowLock = SDL_CreateMutex(); 13523 13524 /* 13525 * Create submitted command buffer list 13526 */ 13527 13528 renderer->submittedCommandBufferCapacity = 16; 13529 renderer->submittedCommandBufferCount = 0; 13530 renderer->submittedCommandBuffers = SDL_malloc(sizeof(VulkanCommandBuffer *) * renderer->submittedCommandBufferCapacity); 13531 13532 // Memory Allocator 13533 13534 renderer->memoryAllocator = (VulkanMemoryAllocator *)SDL_malloc( 13535 sizeof(VulkanMemoryAllocator)); 13536 13537 for (i = 0; i < VK_MAX_MEMORY_TYPES; i += 1) { 13538 renderer->memoryAllocator->subAllocators[i].memoryTypeIndex = i; 13539 renderer->memoryAllocator->subAllocators[i].allocations = NULL; 13540 renderer->memoryAllocator->subAllocators[i].allocationCount = 0; 13541 renderer->memoryAllocator->subAllocators[i].sortedFreeRegions = SDL_malloc( 13542 sizeof(VulkanMemoryFreeRegion *) * 4); 13543 renderer->memoryAllocator->subAllocators[i].sortedFreeRegionCount = 0; 13544 renderer->memoryAllocator->subAllocators[i].sortedFreeRegionCapacity = 4; 13545 } 13546 13547 // Create uniform buffer pool 13548 13549 renderer->uniformBufferPoolCount = 32; 13550 renderer->uniformBufferPoolCapacity = 32; 13551 renderer->uniformBufferPool = SDL_malloc( 13552 renderer->uniformBufferPoolCapacity * sizeof(VulkanUniformBuffer *)); 13553 13554 for (i = 0; i < renderer->uniformBufferPoolCount; i += 1) { 13555 renderer->uniformBufferPool[i] = VULKAN_INTERNAL_CreateUniformBuffer( 13556 renderer, 13557 UNIFORM_BUFFER_SIZE); 13558 } 13559 13560 renderer->descriptorSetCachePoolCapacity = 8; 13561 renderer->descriptorSetCachePoolCount = 0; 13562 renderer->descriptorSetCachePool = SDL_calloc(renderer->descriptorSetCachePoolCapacity, sizeof(DescriptorSetCache *)); 13563 13564 SDL_SetAtomicInt(&renderer->layoutResourceID, 0); 13565 13566 // Device limits 13567 13568 renderer->minUBOAlignment = (Uint32)renderer->physicalDeviceProperties.properties.limits.minUniformBufferOffsetAlignment; 13569 13570 // Initialize caches 13571 13572 renderer->commandPoolHashTable = SDL_CreateHashTable( 13573 0, // !!! FIXME: a real guess here, for a _minimum_ if not a maximum, could be useful. 13574 false, // manually synchronized due to submission timing 13575 VULKAN_INTERNAL_CommandPoolHashFunction, 13576 VULKAN_INTERNAL_CommandPoolHashKeyMatch, 13577 VULKAN_INTERNAL_CommandPoolHashDestroy, 13578 (void *)renderer); 13579 13580 renderer->renderPassHashTable = SDL_CreateHashTable( 13581 0, // !!! FIXME: a real guess here, for a _minimum_ if not a maximum, could be useful. 13582 false, // manually synchronized due to lookup timing 13583 VULKAN_INTERNAL_RenderPassHashFunction, 13584 VULKAN_INTERNAL_RenderPassHashKeyMatch, 13585 VULKAN_INTERNAL_RenderPassHashDestroy, 13586 (void *)renderer); 13587 13588 renderer->framebufferHashTable = SDL_CreateHashTable( 13589 0, // !!! FIXME: a real guess here, for a _minimum_ if not a maximum, could be useful. 13590 false, // manually synchronized due to iteration 13591 VULKAN_INTERNAL_FramebufferHashFunction, 13592 VULKAN_INTERNAL_FramebufferHashKeyMatch, 13593 VULKAN_INTERNAL_FramebufferHashDestroy, 13594 (void *)renderer); 13595 13596 renderer->graphicsPipelineResourceLayoutHashTable = SDL_CreateHashTable( 13597 0, // !!! FIXME: a real guess here, for a _minimum_ if not a maximum, could be useful. 13598 false, // manually synchronized due to lookup timing 13599 VULKAN_INTERNAL_GraphicsPipelineResourceLayoutHashFunction, 13600 VULKAN_INTERNAL_GraphicsPipelineResourceLayoutHashKeyMatch, 13601 VULKAN_INTERNAL_GraphicsPipelineResourceLayoutHashDestroy, 13602 (void *)renderer); 13603 13604 renderer->computePipelineResourceLayoutHashTable = SDL_CreateHashTable( 13605 0, // !!! FIXME: a real guess here, for a _minimum_ if not a maximum, could be useful. 13606 false, // manually synchronized due to lookup timing 13607 VULKAN_INTERNAL_ComputePipelineResourceLayoutHashFunction, 13608 VULKAN_INTERNAL_ComputePipelineResourceLayoutHashKeyMatch, 13609 VULKAN_INTERNAL_ComputePipelineResourceLayoutHashDestroy, 13610 (void *)renderer); 13611 13612 renderer->descriptorSetLayoutHashTable = SDL_CreateHashTable( 13613 0, // !!! FIXME: a real guess here, for a _minimum_ if not a maximum, could be useful. 13614 false, // manually synchronized due to lookup timing 13615 VULKAN_INTERNAL_DescriptorSetLayoutHashFunction, 13616 VULKAN_INTERNAL_DescriptorSetLayoutHashKeyMatch, 13617 VULKAN_INTERNAL_DescriptorSetLayoutHashDestroy, 13618 (void *)renderer); 13619 13620 // Initialize fence pool 13621 13622 renderer->fencePool.lock = SDL_CreateMutex(); 13623 13624 renderer->fencePool.availableFenceCapacity = 4; 13625 renderer->fencePool.availableFenceCount = 0; 13626 renderer->fencePool.availableFences = SDL_malloc( 13627 renderer->fencePool.availableFenceCapacity * sizeof(VulkanFenceHandle *)); 13628 13629 // Deferred destroy storage 13630 13631 renderer->texturesToDestroyCapacity = 16; 13632 renderer->texturesToDestroyCount = 0; 13633 13634 renderer->texturesToDestroy = (VulkanTexture **)SDL_malloc( 13635 sizeof(VulkanTexture *) * 13636 renderer->texturesToDestroyCapacity); 13637 13638 renderer->buffersToDestroyCapacity = 16; 13639 renderer->buffersToDestroyCount = 0; 13640 13641 renderer->buffersToDestroy = SDL_malloc( 13642 sizeof(VulkanBuffer *) * 13643 renderer->buffersToDestroyCapacity); 13644 13645 renderer->samplersToDestroyCapacity = 16; 13646 renderer->samplersToDestroyCount = 0; 13647 13648 renderer->samplersToDestroy = SDL_malloc( 13649 sizeof(VulkanSampler *) * 13650 renderer->samplersToDestroyCapacity); 13651 13652 renderer->graphicsPipelinesToDestroyCapacity = 16; 13653 renderer->graphicsPipelinesToDestroyCount = 0; 13654 13655 renderer->graphicsPipelinesToDestroy = SDL_malloc( 13656 sizeof(VulkanGraphicsPipeline *) * 13657 renderer->graphicsPipelinesToDestroyCapacity); 13658 13659 renderer->computePipelinesToDestroyCapacity = 16; 13660 renderer->computePipelinesToDestroyCount = 0; 13661 13662 renderer->computePipelinesToDestroy = SDL_malloc( 13663 sizeof(VulkanComputePipeline *) * 13664 renderer->computePipelinesToDestroyCapacity); 13665 13666 renderer->shadersToDestroyCapacity = 16; 13667 renderer->shadersToDestroyCount = 0; 13668 13669 renderer->shadersToDestroy = SDL_malloc( 13670 sizeof(VulkanShader *) * 13671 renderer->shadersToDestroyCapacity); 13672 13673 renderer->framebuffersToDestroyCapacity = 16; 13674 renderer->framebuffersToDestroyCount = 0; 13675 renderer->framebuffersToDestroy = SDL_malloc( 13676 sizeof(VulkanFramebuffer *) * 13677 renderer->framebuffersToDestroyCapacity); 13678 13679 // Defrag state 13680 13681 renderer->defragInProgress = 0; 13682 13683 renderer->allocationsToDefragCount = 0; 13684 renderer->allocationsToDefragCapacity = 4; 13685 renderer->allocationsToDefrag = SDL_malloc( 13686 renderer->allocationsToDefragCapacity * sizeof(VulkanMemoryAllocation *)); 13687 13688 return result; 13689} 13690 13691SDL_GPUBootstrap VulkanDriver = { 13692 "vulkan", 13693 VULKAN_PrepareDriver, 13694 VULKAN_CreateDevice 13695}; 13696 13697#endif // SDL_GPU_VULKAN 13698[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.