Atlas - SDL_render_vulkan.c

Home / ext / SDL / src / render / vulkan Lines: 1 | Size: 214637 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#include "SDL_internal.h" 22 23#ifdef SDL_VIDEO_RENDER_VULKAN 24 25#define SDL_VULKAN_FRAME_QUEUE_DEPTH 2 26#define SDL_VULKAN_NUM_VERTEX_BUFFERS 256 27#define SDL_VULKAN_VERTEX_BUFFER_DEFAULT_SIZE 65536 28#define SDL_VULKAN_CONSTANT_BUFFER_DEFAULT_SIZE 65536 29#define SDL_VULKAN_NUM_UPLOAD_BUFFERS 32 30#define SDL_VULKAN_MAX_DESCRIPTOR_SETS 4096 31 32#define SDL_VULKAN_VALIDATION_LAYER_NAME "VK_LAYER_KHRONOS_validation" 33 34#define VK_NO_PROTOTYPES 35#include "../../video/SDL_vulkan_internal.h" 36#include "../../video/SDL_sysvideo.h" 37#include "../SDL_sysrender.h" 38#include "../SDL_d3dmath.h" 39#include "../../video/SDL_pixels_c.h" 40#include "SDL_shaders_vulkan.h" 41 42#define SET_ERROR_CODE(message, rc) \ 43 if (SDL_GetHintBoolean(SDL_HINT_RENDER_VULKAN_DEBUG, false)) { \ 44 SDL_LogError(SDL_LOG_CATEGORY_RENDER, "%s: %s", message, SDL_Vulkan_GetResultString(rc)); \ 45 SDL_TriggerBreakpoint(); \ 46 } \ 47 SDL_SetError("%s: %s", message, SDL_Vulkan_GetResultString(rc)) \ 48 49#define SET_ERROR_MESSAGE(message) \ 50 if (SDL_GetHintBoolean(SDL_HINT_RENDER_VULKAN_DEBUG, false)) { \ 51 SDL_LogError(SDL_LOG_CATEGORY_RENDER, "%s", message); \ 52 SDL_TriggerBreakpoint(); \ 53 } \ 54 SDL_SetError("%s", message) \ 55 56#define VULKAN_FUNCTIONS() \ 57 VULKAN_DEVICE_FUNCTION(vkAcquireNextImageKHR) \ 58 VULKAN_DEVICE_FUNCTION(vkAllocateCommandBuffers) \ 59 VULKAN_DEVICE_FUNCTION(vkAllocateDescriptorSets) \ 60 VULKAN_DEVICE_FUNCTION(vkAllocateMemory) \ 61 VULKAN_DEVICE_FUNCTION(vkBeginCommandBuffer) \ 62 VULKAN_DEVICE_FUNCTION(vkBindBufferMemory) \ 63 VULKAN_DEVICE_FUNCTION(vkBindImageMemory) \ 64 VULKAN_DEVICE_FUNCTION(vkCmdBeginRenderPass) \ 65 VULKAN_DEVICE_FUNCTION(vkCmdBindDescriptorSets) \ 66 VULKAN_DEVICE_FUNCTION(vkCmdBindPipeline) \ 67 VULKAN_DEVICE_FUNCTION(vkCmdBindVertexBuffers) \ 68 VULKAN_DEVICE_FUNCTION(vkCmdClearColorImage) \ 69 VULKAN_DEVICE_FUNCTION(vkCmdCopyBufferToImage) \ 70 VULKAN_DEVICE_FUNCTION(vkCmdCopyImageToBuffer) \ 71 VULKAN_DEVICE_FUNCTION(vkCmdDraw) \ 72 VULKAN_DEVICE_FUNCTION(vkCmdEndRenderPass) \ 73 VULKAN_DEVICE_FUNCTION(vkCmdPipelineBarrier) \ 74 VULKAN_DEVICE_FUNCTION(vkCmdPushConstants) \ 75 VULKAN_DEVICE_FUNCTION(vkCmdSetScissor) \ 76 VULKAN_DEVICE_FUNCTION(vkCmdSetViewport) \ 77 VULKAN_DEVICE_FUNCTION(vkCreateBuffer) \ 78 VULKAN_DEVICE_FUNCTION(vkCreateCommandPool) \ 79 VULKAN_DEVICE_FUNCTION(vkCreateDescriptorPool) \ 80 VULKAN_DEVICE_FUNCTION(vkCreateDescriptorSetLayout) \ 81 VULKAN_DEVICE_FUNCTION(vkCreateFence) \ 82 VULKAN_DEVICE_FUNCTION(vkCreateFramebuffer) \ 83 VULKAN_DEVICE_FUNCTION(vkCreateGraphicsPipelines) \ 84 VULKAN_DEVICE_FUNCTION(vkCreateImage) \ 85 VULKAN_DEVICE_FUNCTION(vkCreateImageView) \ 86 VULKAN_DEVICE_FUNCTION(vkCreatePipelineLayout) \ 87 VULKAN_DEVICE_FUNCTION(vkCreateRenderPass) \ 88 VULKAN_DEVICE_FUNCTION(vkCreateSampler) \ 89 VULKAN_DEVICE_FUNCTION(vkCreateSemaphore) \ 90 VULKAN_DEVICE_FUNCTION(vkCreateShaderModule) \ 91 VULKAN_DEVICE_FUNCTION(vkCreateSwapchainKHR) \ 92 VULKAN_DEVICE_FUNCTION(vkDestroyBuffer) \ 93 VULKAN_DEVICE_FUNCTION(vkDestroyCommandPool) \ 94 VULKAN_DEVICE_FUNCTION(vkDestroyDevice) \ 95 VULKAN_DEVICE_FUNCTION(vkDestroyDescriptorPool) \ 96 VULKAN_DEVICE_FUNCTION(vkDestroyDescriptorSetLayout) \ 97 VULKAN_DEVICE_FUNCTION(vkDestroyFence) \ 98 VULKAN_DEVICE_FUNCTION(vkDestroyFramebuffer) \ 99 VULKAN_DEVICE_FUNCTION(vkDestroyImage) \ 100 VULKAN_DEVICE_FUNCTION(vkDestroyImageView) \ 101 VULKAN_DEVICE_FUNCTION(vkDestroyPipeline) \ 102 VULKAN_DEVICE_FUNCTION(vkDestroyPipelineLayout) \ 103 VULKAN_DEVICE_FUNCTION(vkDestroyRenderPass) \ 104 VULKAN_DEVICE_FUNCTION(vkDestroySampler) \ 105 VULKAN_DEVICE_FUNCTION(vkDestroySemaphore) \ 106 VULKAN_DEVICE_FUNCTION(vkDestroyShaderModule) \ 107 VULKAN_DEVICE_FUNCTION(vkDestroySwapchainKHR) \ 108 VULKAN_DEVICE_FUNCTION(vkDeviceWaitIdle) \ 109 VULKAN_DEVICE_FUNCTION(vkEndCommandBuffer) \ 110 VULKAN_DEVICE_FUNCTION(vkFreeCommandBuffers) \ 111 VULKAN_DEVICE_FUNCTION(vkFreeMemory) \ 112 VULKAN_DEVICE_FUNCTION(vkGetBufferMemoryRequirements) \ 113 VULKAN_DEVICE_FUNCTION(vkGetImageMemoryRequirements) \ 114 VULKAN_DEVICE_FUNCTION(vkGetDeviceQueue) \ 115 VULKAN_DEVICE_FUNCTION(vkGetFenceStatus) \ 116 VULKAN_DEVICE_FUNCTION(vkGetSwapchainImagesKHR) \ 117 VULKAN_DEVICE_FUNCTION(vkMapMemory) \ 118 VULKAN_DEVICE_FUNCTION(vkQueuePresentKHR) \ 119 VULKAN_DEVICE_FUNCTION(vkQueueSubmit) \ 120 VULKAN_DEVICE_FUNCTION(vkResetCommandBuffer) \ 121 VULKAN_DEVICE_FUNCTION(vkResetCommandPool) \ 122 VULKAN_DEVICE_FUNCTION(vkResetDescriptorPool) \ 123 VULKAN_DEVICE_FUNCTION(vkResetFences) \ 124 VULKAN_DEVICE_FUNCTION(vkUnmapMemory) \ 125 VULKAN_DEVICE_FUNCTION(vkUpdateDescriptorSets) \ 126 VULKAN_DEVICE_FUNCTION(vkWaitForFences) \ 127 VULKAN_GLOBAL_FUNCTION(vkCreateInstance) \ 128 VULKAN_GLOBAL_FUNCTION(vkEnumerateInstanceExtensionProperties) \ 129 VULKAN_GLOBAL_FUNCTION(vkEnumerateInstanceLayerProperties) \ 130 VULKAN_INSTANCE_FUNCTION(vkCreateDevice) \ 131 VULKAN_INSTANCE_FUNCTION(vkDestroyInstance) \ 132 VULKAN_INSTANCE_FUNCTION(vkDestroySurfaceKHR) \ 133 VULKAN_INSTANCE_FUNCTION(vkEnumerateDeviceExtensionProperties) \ 134 VULKAN_INSTANCE_FUNCTION(vkEnumeratePhysicalDevices) \ 135 VULKAN_INSTANCE_FUNCTION(vkGetDeviceProcAddr) \ 136 VULKAN_INSTANCE_FUNCTION(vkGetPhysicalDeviceFeatures) \ 137 VULKAN_INSTANCE_FUNCTION(vkGetPhysicalDeviceImageFormatProperties) \ 138 VULKAN_INSTANCE_FUNCTION(vkGetPhysicalDeviceProperties) \ 139 VULKAN_INSTANCE_FUNCTION(vkGetPhysicalDeviceMemoryProperties) \ 140 VULKAN_INSTANCE_FUNCTION(vkGetPhysicalDeviceQueueFamilyProperties) \ 141 VULKAN_INSTANCE_FUNCTION(vkGetPhysicalDeviceSurfaceCapabilitiesKHR) \ 142 VULKAN_INSTANCE_FUNCTION(vkGetPhysicalDeviceSurfaceFormatsKHR) \ 143 VULKAN_INSTANCE_FUNCTION(vkGetPhysicalDeviceSurfacePresentModesKHR) \ 144 VULKAN_INSTANCE_FUNCTION(vkGetPhysicalDeviceSurfaceSupportKHR) \ 145 VULKAN_INSTANCE_FUNCTION(vkQueueWaitIdle) \ 146 VULKAN_OPTIONAL_INSTANCE_FUNCTION(vkGetPhysicalDeviceFeatures2KHR) \ 147 VULKAN_OPTIONAL_INSTANCE_FUNCTION(vkGetPhysicalDeviceFormatProperties2KHR) \ 148 VULKAN_OPTIONAL_INSTANCE_FUNCTION(vkGetPhysicalDeviceMemoryProperties2KHR) \ 149 VULKAN_OPTIONAL_INSTANCE_FUNCTION(vkGetPhysicalDeviceProperties2KHR) \ 150 VULKAN_OPTIONAL_DEVICE_FUNCTION(vkCreateSamplerYcbcrConversionKHR) \ 151 VULKAN_OPTIONAL_DEVICE_FUNCTION(vkDestroySamplerYcbcrConversionKHR) \ 152 153#define VULKAN_DEVICE_FUNCTION(name) static PFN_##name name = NULL; 154#define VULKAN_GLOBAL_FUNCTION(name) static PFN_##name name = NULL; 155#define VULKAN_INSTANCE_FUNCTION(name) static PFN_##name name = NULL; 156#define VULKAN_OPTIONAL_INSTANCE_FUNCTION(name) static PFN_##name name = NULL; 157#define VULKAN_OPTIONAL_DEVICE_FUNCTION(name) static PFN_##name name = NULL; 158VULKAN_FUNCTIONS() 159#undef VULKAN_DEVICE_FUNCTION 160#undef VULKAN_GLOBAL_FUNCTION 161#undef VULKAN_INSTANCE_FUNCTION 162#undef VULKAN_OPTIONAL_INSTANCE_FUNCTION 163#undef VULKAN_OPTIONAL_DEVICE_FUNCTION 164 165// Renderpass types 166typedef enum { 167 VULKAN_RENDERPASS_LOAD = 0, 168 VULKAN_RENDERPASS_CLEAR = 1, 169 VULKAN_RENDERPASS_COUNT 170} VULKAN_RenderPass; 171 172// Vertex shader, common values 173typedef struct 174{ 175 Float4X4 model; 176 Float4X4 projectionAndView; 177} VULKAN_VertexShaderConstants; 178 179// These should mirror the definitions in VULKAN_PixelShader_Common.hlsli 180static const float TONEMAP_NONE = 0; 181//static const float TONEMAP_LINEAR = 1; 182static const float TONEMAP_CHROME = 2; 183 184//static const float TEXTURETYPE_NONE = 0; 185static const float TEXTURETYPE_RGB = 1; 186static const float TEXTURETYPE_RGB_PIXELART = 2; 187static const float TEXTURETYPE_PALETTE_NEAREST = 3; 188static const float TEXTURETYPE_PALETTE_LINEAR = 4; 189static const float TEXTURETYPE_PALETTE_PIXELART = 5; 190 191static const float INPUTTYPE_UNSPECIFIED = 0; 192static const float INPUTTYPE_SRGB = 1; 193static const float INPUTTYPE_SCRGB = 2; 194static const float INPUTTYPE_HDR10 = 3; 195 196// Pixel shader constants, common values 197typedef struct 198{ 199 float scRGB_output; 200 float texture_type; 201 float input_type; 202 float color_scale; 203 204 float texel_width; 205 float texel_height; 206 float texture_width; 207 float texture_height; 208 209 float tonemap_method; 210 float tonemap_factor1; 211 float tonemap_factor2; 212 float sdr_white_point; 213} VULKAN_PixelShaderConstants; 214 215// Per-vertex data 216typedef struct 217{ 218 float pos[2]; 219 float tex[2]; 220 SDL_FColor color; 221} VULKAN_VertexPositionColor; 222 223// Vulkan Buffer 224typedef struct 225{ 226 VkDeviceMemory deviceMemory; 227 VkBuffer buffer; 228 VkDeviceSize size; 229 void *mappedBufferPtr; 230 231} VULKAN_Buffer; 232 233// Vulkan image 234typedef struct 235{ 236 bool allocatedImage; 237 VkImage image; 238 VkImageView imageView; 239 VkDeviceMemory deviceMemory; 240 VkImageLayout imageLayout; 241 VkFormat format; 242} VULKAN_Image; 243 244// Per-palette data 245typedef struct 246{ 247 VULKAN_Image image; 248} VULKAN_PaletteData; 249 250// Per-texture data 251typedef struct 252{ 253 VULKAN_Image mainImage; 254 VkRenderPass mainRenderpasses[VULKAN_RENDERPASS_COUNT]; 255 VkFramebuffer mainFramebuffer; 256 VULKAN_Buffer stagingBuffer; 257 SDL_Rect lockedRect; 258 int width; 259 int height; 260 261 // Object passed to VkImageView and VkSampler for doing Ycbcr -> RGB conversion 262 VkSamplerYcbcrConversion samplerYcbcrConversion; 263 // Sampler created with samplerYcbcrConversion, passed to PSO as immutable sampler 264 VkSampler samplerYcbcr; 265 // Descriptor set layout with samplerYcbcr baked as immutable sampler 266 VkDescriptorSetLayout descriptorSetLayoutYcbcr; 267 // Pipeline layout with immutable sampler descriptor set layout 268 VkPipelineLayout pipelineLayoutYcbcr; 269 270} VULKAN_TextureData; 271 272// Pipeline State Object data 273typedef struct 274{ 275 VULKAN_Shader shader; 276 VULKAN_PixelShaderConstants shader_constants; 277 SDL_BlendMode blendMode; 278 VkPrimitiveTopology topology; 279 VkFormat format; 280 VkPipelineLayout pipelineLayout; 281 VkDescriptorSetLayout descriptorSetLayout; 282 VkPipeline pipeline; 283} VULKAN_PipelineState; 284 285typedef struct 286{ 287 VkBuffer vertexBuffer; 288} VULKAN_DrawStateCache; 289 290// Private renderer data 291typedef struct 292{ 293 PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr; 294 VkInstance instance; 295 bool instance_external; 296 VkSurfaceKHR surface; 297 bool surface_external; 298 VkPhysicalDevice physicalDevice; 299 VkPhysicalDeviceProperties physicalDeviceProperties; 300 VkPhysicalDeviceMemoryProperties physicalDeviceMemoryProperties; 301 VkPhysicalDeviceFeatures physicalDeviceFeatures; 302 VkQueue graphicsQueue; 303 VkQueue presentQueue; 304 VkDevice device; 305 bool device_external; 306 uint32_t graphicsQueueFamilyIndex; 307 uint32_t presentQueueFamilyIndex; 308 VkSwapchainKHR swapchain; 309 VkCommandPool commandPool; 310 VkCommandBuffer *commandBuffers; 311 uint32_t currentCommandBufferIndex; 312 VkCommandBuffer currentCommandBuffer; 313 VkFence *fences; 314 VkSurfaceCapabilitiesKHR surfaceCapabilities; 315 VkSurfaceFormatKHR *surfaceFormats; 316 bool recreateSwapchain; 317 int vsync; 318 SDL_PropertiesID create_props; 319 320 VkFramebuffer *framebuffers; 321 VkRenderPass renderPasses[VULKAN_RENDERPASS_COUNT]; 322 VkRenderPass currentRenderPass; 323 324 VkShaderModule vertexShaderModules[NUM_SHADERS]; 325 VkShaderModule fragmentShaderModules[NUM_SHADERS]; 326 VkDescriptorSetLayout descriptorSetLayout; 327 VkPipelineLayout pipelineLayout; 328 329 // Vertex buffer data 330 VULKAN_Buffer vertexBuffers[SDL_VULKAN_NUM_VERTEX_BUFFERS]; 331 VULKAN_VertexShaderConstants vertexShaderConstantsData; 332 333 // Data for staging/allocating textures 334 VULKAN_Buffer **uploadBuffers; 335 int *currentUploadBuffer; 336 337 // Data for updating constants 338 VULKAN_Buffer **constantBuffers; 339 uint32_t *numConstantBuffers; 340 uint32_t currentConstantBufferIndex; 341 int32_t currentConstantBufferOffset; 342 343 VkSampler samplers[RENDER_SAMPLER_COUNT]; 344 VkDescriptorPool **descriptorPools; 345 uint32_t *numDescriptorPools; 346 uint32_t currentDescriptorPoolIndex; 347 uint32_t currentDescriptorSetIndex; 348 349 int pipelineStateCount; 350 VULKAN_PipelineState *pipelineStates; 351 VULKAN_PipelineState *currentPipelineState; 352 353 bool supportsEXTSwapchainColorspace; 354 bool supportsKHRGetPhysicalDeviceProperties2; 355 bool supportsKHRSamplerYCbCrConversion; 356 uint32_t surfaceFormatsAllocatedCount; 357 uint32_t surfaceFormatsCount; 358 uint32_t swapchainDesiredImageCount; 359 VkSurfaceFormatKHR surfaceFormat; 360 VkExtent2D swapchainSize; 361 VkSurfaceTransformFlagBitsKHR swapChainPreTransform; 362 uint32_t swapchainImageCount; 363 VkImage *swapchainImages; 364 VkImageView *swapchainImageViews; 365 VkImageLayout *swapchainImageLayouts; 366 VkSemaphore *imageAvailableSemaphores; 367 VkSemaphore *renderingFinishedSemaphores; 368 VkSemaphore currentImageAvailableSemaphore; 369 uint32_t currentSwapchainImageIndex; 370 371 VkPipelineStageFlags *waitDestStageMasks; 372 VkSemaphore *waitRenderSemaphores; 373 uint32_t waitRenderSemaphoreCount; 374 uint32_t waitRenderSemaphoreMax; 375 VkSemaphore *signalRenderSemaphores; 376 uint32_t signalRenderSemaphoreCount; 377 uint32_t signalRenderSemaphoreMax; 378 379 // Cached renderer properties 380 VULKAN_TextureData *textureRenderTarget; 381 bool cliprectDirty; 382 bool currentCliprectEnabled; 383 SDL_Rect currentCliprect; 384 SDL_Rect currentViewport; 385 int currentViewportRotation; 386 bool viewportDirty; 387 Float4X4 identity; 388 VkComponentMapping identitySwizzle; 389 int currentVertexBuffer; 390 bool issueBatch; 391} VULKAN_RenderData; 392 393static bool VULKAN_UpdateTextureInternal(VULKAN_RenderData *rendererData, VkImage image, VkFormat format, int plane, int x, int y, int w, int h, const void *pixels, int pitch, VkImageLayout *imageLayout); 394 395// TODO: Sort this list based on what the Vulkan driver prefers? 396static const struct 397{ 398 SDL_PixelFormat sdl; 399 VkFormat unorm; 400 VkFormat srgb; 401} vk_format_map[] = { 402 { SDL_PIXELFORMAT_BGRA32, VK_FORMAT_B8G8R8A8_UNORM, VK_FORMAT_B8G8R8A8_SRGB }, // SDL_PIXELFORMAT_ARGB8888 on little endian systems 403 { SDL_PIXELFORMAT_RGBA32, VK_FORMAT_R8G8B8A8_UNORM, VK_FORMAT_R8G8B8A8_SRGB }, 404#if SDL_BYTEORDER == SDL_BIG_ENDIAN 405 { SDL_PIXELFORMAT_ABGR8888, VK_FORMAT_A8B8G8R8_UNORM_PACK32, VK_FORMAT_A8B8G8R8_SRGB_PACK32 }, 406#endif 407 { SDL_PIXELFORMAT_ABGR2101010, VK_FORMAT_A2B10G10R10_UNORM_PACK32, VK_FORMAT_A2B10G10R10_UNORM_PACK32 }, 408 { SDL_PIXELFORMAT_RGBA64_FLOAT, VK_FORMAT_R16G16B16A16_SFLOAT, VK_FORMAT_R16G16B16A16_SFLOAT }, 409 { SDL_PIXELFORMAT_RGB565, VK_FORMAT_R5G6B5_UNORM_PACK16, VK_FORMAT_R5G6B5_UNORM_PACK16 }, 410 { SDL_PIXELFORMAT_BGR565, VK_FORMAT_B5G6R5_UNORM_PACK16, VK_FORMAT_B5G6R5_UNORM_PACK16 }, 411 { SDL_PIXELFORMAT_RGBA5551, VK_FORMAT_R5G5B5A1_UNORM_PACK16, VK_FORMAT_R5G5B5A1_UNORM_PACK16 }, 412 { SDL_PIXELFORMAT_BGRA5551, VK_FORMAT_B5G5R5A1_UNORM_PACK16, VK_FORMAT_B5G5R5A1_UNORM_PACK16 }, 413 { SDL_PIXELFORMAT_ARGB1555, VK_FORMAT_A1R5G5B5_UNORM_PACK16, VK_FORMAT_A1R5G5B5_UNORM_PACK16 }, 414 { SDL_PIXELFORMAT_RGBA4444, VK_FORMAT_R4G4B4A4_UNORM_PACK16, VK_FORMAT_R4G4B4A4_UNORM_PACK16 }, 415 { SDL_PIXELFORMAT_BGRA4444, VK_FORMAT_B4G4R4A4_UNORM_PACK16, VK_FORMAT_B4G4R4A4_UNORM_PACK16 }, 416 { SDL_PIXELFORMAT_ARGB4444, VK_FORMAT_A4R4G4B4_UNORM_PACK16_EXT, VK_FORMAT_A4R4G4B4_UNORM_PACK16_EXT }, 417 { SDL_PIXELFORMAT_ABGR4444, VK_FORMAT_A4B4G4R4_UNORM_PACK16_EXT, VK_FORMAT_A4B4G4R4_UNORM_PACK16_EXT } 418}; 419 420static SDL_PixelFormat VULKAN_VkFormatToSDLPixelFormat(VkFormat vkFormat) 421{ 422 for (int i = 0; i < SDL_arraysize(vk_format_map); i++) { 423 if (vk_format_map[i].unorm == vkFormat || 424 vk_format_map[i].srgb == vkFormat) { 425 return vk_format_map[i].sdl; 426 } 427 } 428 return SDL_PIXELFORMAT_UNKNOWN; 429} 430 431static int VULKAN_VkFormatGetNumPlanes(VkFormat vkFormat) 432{ 433 switch (vkFormat) { 434 case VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM: 435 return 3; 436 case VK_FORMAT_G8_B8R8_2PLANE_420_UNORM: 437 case VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16: 438 return 2; 439 default: 440 return 1; 441 } 442} 443 444static VkDeviceSize VULKAN_GetBytesPerPixel(VkFormat vkFormat, int plane) 445{ 446 switch (vkFormat) { 447 case VK_FORMAT_R8_UNORM: 448 return 1; 449 case VK_FORMAT_R8G8_UNORM: 450 return 2; 451 case VK_FORMAT_R16G16_UNORM: 452 return 4; 453 case VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM: 454 return 1; 455 case VK_FORMAT_G8_B8R8_2PLANE_420_UNORM: 456 return (plane == 0) ? 1 : 2; 457 case VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16: 458 return (plane == 0) ? 2 : 4; 459 default: 460 return SDL_BYTESPERPIXEL(VULKAN_VkFormatToSDLPixelFormat(vkFormat)); 461 } 462} 463 464static VkFormat SDLPixelFormatToVkTextureFormat(SDL_PixelFormat format, Uint32 output_colorspace) 465{ 466 switch (format) { 467 case SDL_PIXELFORMAT_INDEX8: 468 return VK_FORMAT_R8_UNORM; 469 case SDL_PIXELFORMAT_YUY2: 470 return VK_FORMAT_G8B8G8R8_422_UNORM; 471 case SDL_PIXELFORMAT_UYVY: 472 return VK_FORMAT_B8G8R8G8_422_UNORM; 473 case SDL_PIXELFORMAT_YV12: 474 case SDL_PIXELFORMAT_IYUV: 475 return VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM; 476 case SDL_PIXELFORMAT_NV12: 477 case SDL_PIXELFORMAT_NV21: 478 return VK_FORMAT_G8_B8R8_2PLANE_420_UNORM; 479 case SDL_PIXELFORMAT_P010: 480 return VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16; 481 default: 482 for (int i = 0; i < SDL_arraysize(vk_format_map); i++) { 483 if (vk_format_map[i].sdl == format) { 484 if (output_colorspace == SDL_COLORSPACE_SRGB_LINEAR) { 485 return vk_format_map[i].srgb; 486 } else { 487 return vk_format_map[i].unorm; 488 } 489 } 490 } 491 return VK_FORMAT_UNDEFINED; 492 } 493} 494 495static void VULKAN_DestroyTexture(SDL_Renderer *renderer, SDL_Texture *texture); 496static void VULKAN_DestroyBuffer(VULKAN_RenderData *rendererData, VULKAN_Buffer *vulkanBuffer); 497static void VULKAN_DestroyImage(VULKAN_RenderData *rendererData, VULKAN_Image *vulkanImage); 498static void VULKAN_ResetCommandList(VULKAN_RenderData *rendererData); 499static void VULKAN_EnsureCommandBuffer(VULKAN_RenderData *rendererData); 500static void VULKAN_RecordPipelineImageBarrier(VULKAN_RenderData *rendererData, VkAccessFlags sourceAccessMask, VkAccessFlags destAccessMask, VkPipelineStageFlags srcStageFlags, VkPipelineStageFlags dstStageFlags, VkImageLayout destLayout, VkImage image, VkImageLayout *imageLayout); 501static bool VULKAN_FindMemoryTypeIndex(VULKAN_RenderData *rendererData, uint32_t typeBits, VkMemoryPropertyFlags requiredFlags, VkMemoryPropertyFlags desiredFlags, uint32_t *memoryTypeIndexOut); 502static VkResult VULKAN_CreateWindowSizeDependentResources(SDL_Renderer *renderer); 503static VkDescriptorPool VULKAN_AllocateDescriptorPool(VULKAN_RenderData *rendererData); 504static VkResult VULKAN_CreateDescriptorSetAndPipelineLayout(VULKAN_RenderData *rendererData, VkSampler samplerYcbcr, VkDescriptorSetLayout *descriptorSetLayoutOut, VkPipelineLayout *pipelineLayoutOut); 505static VkSurfaceTransformFlagBitsKHR VULKAN_GetRotationForCurrentRenderTarget(VULKAN_RenderData *rendererData); 506static bool VULKAN_IsDisplayRotated90Degrees(VkSurfaceTransformFlagBitsKHR rotation); 507 508static void VULKAN_DestroyAll(SDL_Renderer *renderer) 509{ 510 VULKAN_RenderData *rendererData; 511 if (renderer == NULL) { 512 return; 513 } 514 rendererData = (VULKAN_RenderData *)renderer->internal; 515 if (rendererData == NULL) { 516 return; 517 } 518 519 // Release all textures 520 for (SDL_Texture *texture = renderer->textures; texture; texture = texture->next) { 521 VULKAN_DestroyTexture(renderer, texture); 522 } 523 524 if (rendererData->waitDestStageMasks) { 525 SDL_free(rendererData->waitDestStageMasks); 526 rendererData->waitDestStageMasks = NULL; 527 } 528 if (rendererData->waitRenderSemaphores) { 529 SDL_free(rendererData->waitRenderSemaphores); 530 rendererData->waitRenderSemaphores = NULL; 531 } 532 if (rendererData->signalRenderSemaphores) { 533 SDL_free(rendererData->signalRenderSemaphores); 534 rendererData->signalRenderSemaphores = NULL; 535 } 536 if (rendererData->surfaceFormats != NULL) { 537 SDL_free(rendererData->surfaceFormats); 538 rendererData->surfaceFormats = NULL; 539 rendererData->surfaceFormatsAllocatedCount = 0; 540 } 541 if (rendererData->swapchainImages != NULL) { 542 SDL_free(rendererData->swapchainImages); 543 rendererData->swapchainImages = NULL; 544 } 545 if (rendererData->swapchain) { 546 vkDestroySwapchainKHR(rendererData->device, rendererData->swapchain, NULL); 547 rendererData->swapchain = VK_NULL_HANDLE; 548 } 549 if (rendererData->fences != NULL) { 550 for (uint32_t i = 0; i < rendererData->swapchainImageCount; i++) { 551 if (rendererData->fences[i] != VK_NULL_HANDLE) { 552 vkDestroyFence(rendererData->device, rendererData->fences[i], NULL); 553 rendererData->fences[i] = VK_NULL_HANDLE; 554 } 555 } 556 SDL_free(rendererData->fences); 557 rendererData->fences = NULL; 558 } 559 if (rendererData->swapchainImageViews) { 560 for (uint32_t i = 0; i < rendererData->swapchainImageCount; i++) { 561 if (rendererData->swapchainImageViews[i] != VK_NULL_HANDLE) { 562 vkDestroyImageView(rendererData->device, rendererData->swapchainImageViews[i], NULL); 563 } 564 } 565 SDL_free(rendererData->swapchainImageViews); 566 rendererData->swapchainImageViews = NULL; 567 } 568 if (rendererData->swapchainImageLayouts) { 569 SDL_free(rendererData->swapchainImageLayouts); 570 rendererData->swapchainImageLayouts = NULL; 571 } 572 if (rendererData->framebuffers) { 573 for (uint32_t i = 0; i < rendererData->swapchainImageCount; i++) { 574 if (rendererData->framebuffers[i] != VK_NULL_HANDLE) { 575 vkDestroyFramebuffer(rendererData->device, rendererData->framebuffers[i], NULL); 576 } 577 } 578 SDL_free(rendererData->framebuffers); 579 rendererData->framebuffers = NULL; 580 } 581 for (uint32_t i = 0; i < SDL_arraysize(rendererData->samplers); i++) { 582 if (rendererData->samplers[i] != VK_NULL_HANDLE) { 583 vkDestroySampler(rendererData->device, rendererData->samplers[i], NULL); 584 rendererData->samplers[i] = VK_NULL_HANDLE; 585 } 586 } 587 for (uint32_t i = 0; i < SDL_arraysize(rendererData->vertexBuffers); i++ ) { 588 VULKAN_DestroyBuffer(rendererData, &rendererData->vertexBuffers[i]); 589 } 590 SDL_zeroa(rendererData->vertexBuffers); 591 for (uint32_t i = 0; i < VULKAN_RENDERPASS_COUNT; i++) { 592 if (rendererData->renderPasses[i] != VK_NULL_HANDLE) { 593 vkDestroyRenderPass(rendererData->device, rendererData->renderPasses[i], NULL); 594 rendererData->renderPasses[i] = VK_NULL_HANDLE; 595 } 596 } 597 if (rendererData->imageAvailableSemaphores) { 598 for (uint32_t i = 0; i < rendererData->swapchainImageCount; ++i) { 599 if (rendererData->imageAvailableSemaphores[i] != VK_NULL_HANDLE) { 600 vkDestroySemaphore(rendererData->device, rendererData->imageAvailableSemaphores[i], NULL); 601 } 602 } 603 SDL_free(rendererData->imageAvailableSemaphores); 604 rendererData->imageAvailableSemaphores = NULL; 605 } 606 if (rendererData->renderingFinishedSemaphores) { 607 for (uint32_t i = 0; i < rendererData->swapchainImageCount; ++i) { 608 if (rendererData->renderingFinishedSemaphores[i] != VK_NULL_HANDLE) { 609 vkDestroySemaphore(rendererData->device, rendererData->renderingFinishedSemaphores[i], NULL); 610 } 611 } 612 SDL_free(rendererData->renderingFinishedSemaphores); 613 rendererData->renderingFinishedSemaphores = NULL; 614 } 615 if (rendererData->commandBuffers) { 616 vkFreeCommandBuffers(rendererData->device, rendererData->commandPool, rendererData->swapchainImageCount, rendererData->commandBuffers); 617 SDL_free(rendererData->commandBuffers); 618 rendererData->commandBuffers = NULL; 619 rendererData->currentCommandBuffer = VK_NULL_HANDLE; 620 rendererData->currentCommandBufferIndex = 0; 621 } 622 if (rendererData->commandPool) { 623 vkDestroyCommandPool(rendererData->device, rendererData->commandPool, NULL); 624 rendererData->commandPool = VK_NULL_HANDLE; 625 } 626 if (rendererData->descriptorPools) { 627 SDL_assert(rendererData->numDescriptorPools); 628 for (uint32_t i = 0; i < rendererData->swapchainImageCount; i++) { 629 for (uint32_t j = 0; j < rendererData->numDescriptorPools[i]; j++) { 630 if (rendererData->descriptorPools[i][j] != VK_NULL_HANDLE) { 631 vkDestroyDescriptorPool(rendererData->device, rendererData->descriptorPools[i][j], NULL); 632 } 633 } 634 SDL_free(rendererData->descriptorPools[i]); 635 } 636 SDL_free(rendererData->descriptorPools); 637 rendererData->descriptorPools = NULL; 638 SDL_free(rendererData->numDescriptorPools); 639 rendererData->numDescriptorPools = NULL; 640 } 641 for (uint32_t i = 0; i < NUM_SHADERS; i++) { 642 if (rendererData->vertexShaderModules[i] != VK_NULL_HANDLE) { 643 vkDestroyShaderModule(rendererData->device, rendererData->vertexShaderModules[i], NULL); 644 rendererData->vertexShaderModules[i] = VK_NULL_HANDLE; 645 } 646 if (rendererData->fragmentShaderModules[i] != VK_NULL_HANDLE) { 647 vkDestroyShaderModule(rendererData->device, rendererData->fragmentShaderModules[i], NULL); 648 rendererData->fragmentShaderModules[i] = VK_NULL_HANDLE; 649 } 650 } 651 if (rendererData->descriptorSetLayout != VK_NULL_HANDLE) { 652 vkDestroyDescriptorSetLayout(rendererData->device, rendererData->descriptorSetLayout, NULL); 653 rendererData->descriptorSetLayout = VK_NULL_HANDLE; 654 } 655 if (rendererData->pipelineLayout != VK_NULL_HANDLE) { 656 vkDestroyPipelineLayout(rendererData->device, rendererData->pipelineLayout, NULL); 657 rendererData->pipelineLayout = VK_NULL_HANDLE; 658 } 659 for (int i = 0; i < rendererData->pipelineStateCount; i++) { 660 vkDestroyPipeline(rendererData->device, rendererData->pipelineStates[i].pipeline, NULL); 661 } 662 SDL_free(rendererData->pipelineStates); 663 rendererData->pipelineStates = NULL; 664 rendererData->pipelineStateCount = 0; 665 666 if (rendererData->currentUploadBuffer) { 667 for (uint32_t i = 0; i < rendererData->swapchainImageCount; ++i) { 668 for (int j = 0; j < rendererData->currentUploadBuffer[i]; ++j) { 669 VULKAN_DestroyBuffer(rendererData, &rendererData->uploadBuffers[i][j]); 670 } 671 SDL_free(rendererData->uploadBuffers[i]); 672 } 673 SDL_free(rendererData->uploadBuffers); 674 rendererData->uploadBuffers = NULL; 675 SDL_free(rendererData->currentUploadBuffer); 676 rendererData->currentUploadBuffer = NULL; 677 } 678 679 if (rendererData->constantBuffers) { 680 SDL_assert(rendererData->numConstantBuffers); 681 for (uint32_t i = 0; i < rendererData->swapchainImageCount; ++i) { 682 for (uint32_t j = 0; j < rendererData->numConstantBuffers[i]; j++) { 683 VULKAN_DestroyBuffer(rendererData, &rendererData->constantBuffers[i][j]); 684 } 685 SDL_free(rendererData->constantBuffers[i]); 686 } 687 SDL_free(rendererData->constantBuffers); 688 rendererData->constantBuffers = NULL; 689 SDL_free(rendererData->numConstantBuffers); 690 rendererData->numConstantBuffers = NULL; 691 } 692 693 if (rendererData->device != VK_NULL_HANDLE && !rendererData->device_external) { 694 vkDestroyDevice(rendererData->device, NULL); 695 rendererData->device = VK_NULL_HANDLE; 696 } 697 if (rendererData->surface != VK_NULL_HANDLE && !rendererData->surface_external) { 698 vkDestroySurfaceKHR(rendererData->instance, rendererData->surface, NULL); 699 rendererData->surface = VK_NULL_HANDLE; 700 } 701 if (rendererData->instance != VK_NULL_HANDLE && !rendererData->instance_external) { 702 vkDestroyInstance(rendererData->instance, NULL); 703 rendererData->instance = VK_NULL_HANDLE; 704 } 705} 706 707static void VULKAN_DestroyBuffer(VULKAN_RenderData *rendererData, VULKAN_Buffer *vulkanBuffer) 708{ 709 if (vulkanBuffer->buffer != VK_NULL_HANDLE) { 710 vkDestroyBuffer(rendererData->device, vulkanBuffer->buffer, NULL); 711 vulkanBuffer->buffer = VK_NULL_HANDLE; 712 } 713 if (vulkanBuffer->deviceMemory != VK_NULL_HANDLE) { 714 vkFreeMemory(rendererData->device, vulkanBuffer->deviceMemory, NULL); 715 vulkanBuffer->deviceMemory = VK_NULL_HANDLE; 716 } 717 SDL_zerop(vulkanBuffer); 718} 719 720static VkResult VULKAN_AllocateBuffer(VULKAN_RenderData *rendererData, VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags requiredMemoryProps, VkMemoryPropertyFlags desiredMemoryProps, VULKAN_Buffer *bufferOut) 721{ 722 VkResult result; 723 VkBufferCreateInfo bufferCreateInfo = { 0 }; 724 bufferCreateInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; 725 bufferCreateInfo.size = size; 726 bufferCreateInfo.usage = usage; 727 result = vkCreateBuffer(rendererData->device, &bufferCreateInfo, NULL, &bufferOut->buffer); 728 if (result != VK_SUCCESS) { 729 SET_ERROR_CODE("vkCreateBuffer()", result); 730 return result; 731 } 732 733 VkMemoryRequirements memoryRequirements = { 0 }; 734 vkGetBufferMemoryRequirements(rendererData->device, bufferOut->buffer, &memoryRequirements); 735 if (result != VK_SUCCESS) { 736 VULKAN_DestroyBuffer(rendererData, bufferOut); 737 SET_ERROR_CODE("vkGetBufferMemoryRequirements()", result); 738 return result; 739 } 740 741 uint32_t memoryTypeIndex = 0; 742 if (!VULKAN_FindMemoryTypeIndex(rendererData, memoryRequirements.memoryTypeBits, requiredMemoryProps, desiredMemoryProps, &memoryTypeIndex)) { 743 VULKAN_DestroyBuffer(rendererData, bufferOut); 744 return VK_ERROR_UNKNOWN; 745 } 746 747 VkMemoryAllocateInfo memoryAllocateInfo = { 0 }; 748 memoryAllocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; 749 memoryAllocateInfo.allocationSize = memoryRequirements.size; 750 memoryAllocateInfo.memoryTypeIndex = memoryTypeIndex; 751 result = vkAllocateMemory(rendererData->device, &memoryAllocateInfo, NULL, &bufferOut->deviceMemory); 752 if (result != VK_SUCCESS) { 753 VULKAN_DestroyBuffer(rendererData, bufferOut); 754 SET_ERROR_CODE("vkAllocateMemory()", result); 755 return result; 756 } 757 result = vkBindBufferMemory(rendererData->device, bufferOut->buffer, bufferOut->deviceMemory, 0); 758 if (result != VK_SUCCESS) { 759 VULKAN_DestroyBuffer(rendererData, bufferOut); 760 SET_ERROR_CODE("vkBindBufferMemory()", result); 761 return result; 762 } 763 764 result = vkMapMemory(rendererData->device, bufferOut->deviceMemory, 0, size, 0, &bufferOut->mappedBufferPtr); 765 if (result != VK_SUCCESS) { 766 VULKAN_DestroyBuffer(rendererData, bufferOut); 767 SET_ERROR_CODE("vkMapMemory()", result); 768 return result; 769 } 770 bufferOut->size = size; 771 return result; 772} 773 774static void VULKAN_DestroyImage(VULKAN_RenderData *rendererData, VULKAN_Image *vulkanImage) 775{ 776 if (vulkanImage->imageView != VK_NULL_HANDLE) { 777 vkDestroyImageView(rendererData->device, vulkanImage->imageView, NULL); 778 vulkanImage->imageView = VK_NULL_HANDLE; 779 } 780 if (vulkanImage->image != VK_NULL_HANDLE) { 781 if (vulkanImage->allocatedImage) { 782 vkDestroyImage(rendererData->device, vulkanImage->image, NULL); 783 } 784 vulkanImage->image = VK_NULL_HANDLE; 785 } 786 787 if (vulkanImage->deviceMemory != VK_NULL_HANDLE) { 788 if (vulkanImage->allocatedImage) { 789 vkFreeMemory(rendererData->device, vulkanImage->deviceMemory, NULL); 790 } 791 vulkanImage->deviceMemory = VK_NULL_HANDLE; 792 } 793 SDL_zerop(vulkanImage); 794} 795 796static VkResult VULKAN_AllocateImage(VULKAN_RenderData *rendererData, SDL_PropertiesID create_props, uint32_t width, uint32_t height, VkFormat format, VkImageUsageFlags imageUsage, VkComponentMapping swizzle, VkSamplerYcbcrConversionKHR samplerYcbcrConversion, VULKAN_Image *imageOut) 797{ 798 VkResult result; 799 VkSamplerYcbcrConversionInfoKHR samplerYcbcrConversionInfo = { 0 }; 800 801 SDL_zerop(imageOut); 802 imageOut->format = format; 803 imageOut->image = (VkImage)SDL_GetNumberProperty(create_props, SDL_PROP_TEXTURE_CREATE_VULKAN_TEXTURE_NUMBER, 0); 804 805 if (imageOut->image == VK_NULL_HANDLE) { 806 imageOut->allocatedImage = VK_TRUE; 807 808 VkImageCreateInfo imageCreateInfo = { 0 }; 809 imageCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; 810 imageCreateInfo.flags = 0; 811 imageCreateInfo.imageType = VK_IMAGE_TYPE_2D; 812 imageCreateInfo.format = format; 813 imageCreateInfo.extent.width = width; 814 imageCreateInfo.extent.height = height; 815 imageCreateInfo.extent.depth = 1; 816 imageCreateInfo.mipLevels = 1; 817 imageCreateInfo.arrayLayers = 1; 818 imageCreateInfo.samples = VK_SAMPLE_COUNT_1_BIT; 819 imageCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL; 820 imageCreateInfo.usage = imageUsage; 821 imageCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; 822 imageCreateInfo.queueFamilyIndexCount = 0; 823 imageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; 824 825 result = vkCreateImage(rendererData->device, &imageCreateInfo, NULL, &imageOut->image); 826 if (result != VK_SUCCESS) { 827 VULKAN_DestroyImage(rendererData, imageOut); 828 SET_ERROR_CODE("vkCreateImage()", result); 829 return result; 830 } 831 832 VkMemoryRequirements memoryRequirements = { 0 }; 833 vkGetImageMemoryRequirements(rendererData->device, imageOut->image, &memoryRequirements); 834 if (result != VK_SUCCESS) { 835 VULKAN_DestroyImage(rendererData, imageOut); 836 SET_ERROR_CODE("vkGetImageMemoryRequirements()", result); 837 return result; 838 } 839 840 uint32_t memoryTypeIndex = 0; 841 if (!VULKAN_FindMemoryTypeIndex(rendererData, memoryRequirements.memoryTypeBits, 0, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &memoryTypeIndex)) { 842 VULKAN_DestroyImage(rendererData, imageOut); 843 return VK_ERROR_UNKNOWN; 844 } 845 846 VkMemoryAllocateInfo memoryAllocateInfo = { 0 }; 847 memoryAllocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; 848 memoryAllocateInfo.allocationSize = memoryRequirements.size; 849 memoryAllocateInfo.memoryTypeIndex = memoryTypeIndex; 850 result = vkAllocateMemory(rendererData->device, &memoryAllocateInfo, NULL, &imageOut->deviceMemory); 851 if (result != VK_SUCCESS) { 852 VULKAN_DestroyImage(rendererData, imageOut); 853 SET_ERROR_CODE("vkAllocateMemory()", result); 854 return result; 855 } 856 result = vkBindImageMemory(rendererData->device, imageOut->image, imageOut->deviceMemory, 0); 857 if (result != VK_SUCCESS) { 858 VULKAN_DestroyImage(rendererData, imageOut); 859 SET_ERROR_CODE("vkBindImageMemory()", result); 860 return result; 861 } 862 } else { 863 imageOut->imageLayout = (VkImageLayout)SDL_GetNumberProperty(create_props, SDL_PROP_TEXTURE_CREATE_VULKAN_LAYOUT_NUMBER, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); 864 } 865 866 if (imageOut->imageLayout != VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) { 867 VULKAN_EnsureCommandBuffer(rendererData); 868 VULKAN_RecordPipelineImageBarrier(rendererData, 869 VK_ACCESS_NONE, 870 VK_ACCESS_SHADER_READ_BIT, 871 VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 872 VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 873 VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, 874 imageOut->image, 875 &imageOut->imageLayout); 876 } 877 878 VkImageViewCreateInfo imageViewCreateInfo = { 0 }; 879 imageViewCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; 880 imageViewCreateInfo.image = imageOut->image; 881 imageViewCreateInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; 882 imageViewCreateInfo.format = format; 883 imageViewCreateInfo.components = swizzle; 884 imageViewCreateInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; 885 imageViewCreateInfo.subresourceRange.baseMipLevel = 0; 886 imageViewCreateInfo.subresourceRange.levelCount = 1; 887 imageViewCreateInfo.subresourceRange.baseArrayLayer = 0; 888 imageViewCreateInfo.subresourceRange.layerCount = 1; 889 890 // If it's a YCbCr image, we need to pass the conversion info to the VkImageView (and the VkSampler) 891 if (samplerYcbcrConversion != VK_NULL_HANDLE) { 892 samplerYcbcrConversionInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO_KHR; 893 samplerYcbcrConversionInfo.conversion = samplerYcbcrConversion; 894 imageViewCreateInfo.pNext = &samplerYcbcrConversionInfo; 895 } 896 897 result = vkCreateImageView(rendererData->device, &imageViewCreateInfo, NULL, &imageOut->imageView); 898 if (result != VK_SUCCESS) { 899 VULKAN_DestroyImage(rendererData, imageOut); 900 SET_ERROR_CODE("vkCreateImageView()", result); 901 return result; 902 } 903 904 return result; 905} 906 907 908static void VULKAN_RecordPipelineImageBarrier(VULKAN_RenderData *rendererData, VkAccessFlags sourceAccessMask, VkAccessFlags destAccessMask, 909 VkPipelineStageFlags srcStageFlags, VkPipelineStageFlags dstStageFlags, VkImageLayout destLayout, VkImage image, VkImageLayout *imageLayout) 910{ 911 // Stop any outstanding renderpass if open 912 if (rendererData->currentRenderPass != VK_NULL_HANDLE) { 913 vkCmdEndRenderPass(rendererData->currentCommandBuffer); 914 rendererData->currentRenderPass = VK_NULL_HANDLE; 915 } 916 917 VkImageMemoryBarrier barrier = { 0 }; 918 barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; 919 barrier.srcAccessMask = sourceAccessMask; 920 barrier.dstAccessMask = destAccessMask; 921 barrier.oldLayout = *imageLayout; 922 barrier.newLayout = destLayout; 923 barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; 924 barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; 925 barrier.image = image; 926 barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; 927 barrier.subresourceRange.baseMipLevel = 0; 928 barrier.subresourceRange.levelCount = 1; 929 barrier.subresourceRange.baseArrayLayer = 0; 930 barrier.subresourceRange.layerCount = 1; 931 vkCmdPipelineBarrier(rendererData->currentCommandBuffer, srcStageFlags, dstStageFlags, 0, 0, NULL, 0, NULL, 1, &barrier); 932 *imageLayout = destLayout; 933} 934 935static VkResult VULKAN_AcquireNextSwapchainImage(SDL_Renderer *renderer) 936{ 937 VULKAN_RenderData *rendererData = (VULKAN_RenderData *)renderer->internal; 938 939 VkResult result; 940 941 rendererData->currentImageAvailableSemaphore = VK_NULL_HANDLE; 942 result = vkAcquireNextImageKHR(rendererData->device, rendererData->swapchain, UINT64_MAX, 943 rendererData->imageAvailableSemaphores[rendererData->currentCommandBufferIndex], VK_NULL_HANDLE, &rendererData->currentSwapchainImageIndex); 944 if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_ERROR_SURFACE_LOST_KHR) { 945 if (!(renderer->window->flags & SDL_WINDOW_MINIMIZED)) { 946 result = VULKAN_CreateWindowSizeDependentResources(renderer); 947 } 948 return result; 949 } else if(result == VK_SUBOPTIMAL_KHR) { 950 // Suboptimal, but we can continue 951 } else if (result != VK_SUCCESS) { 952 SET_ERROR_CODE("vkAcquireNextImageKHR()", result); 953 return result; 954 } 955 rendererData->currentImageAvailableSemaphore = rendererData->imageAvailableSemaphores[rendererData->currentCommandBufferIndex]; 956 return result; 957} 958 959static void VULKAN_BeginRenderPass(VULKAN_RenderData *rendererData, VkAttachmentLoadOp loadOp, VkClearColorValue *clearColor) 960{ 961 int width = rendererData->swapchainSize.width; 962 int height = rendererData->swapchainSize.height; 963 if (rendererData->textureRenderTarget) { 964 width = rendererData->textureRenderTarget->width; 965 height = rendererData->textureRenderTarget->height; 966 } 967 968 switch (loadOp) { 969 case VK_ATTACHMENT_LOAD_OP_CLEAR: 970 rendererData->currentRenderPass = rendererData->textureRenderTarget ? 971 rendererData->textureRenderTarget->mainRenderpasses[VULKAN_RENDERPASS_CLEAR] : 972 rendererData->renderPasses[VULKAN_RENDERPASS_CLEAR]; 973 break; 974 975 case VK_ATTACHMENT_LOAD_OP_LOAD: 976 default: 977 rendererData->currentRenderPass = rendererData->textureRenderTarget ? 978 rendererData->textureRenderTarget->mainRenderpasses[VULKAN_RENDERPASS_LOAD] : 979 rendererData->renderPasses[VULKAN_RENDERPASS_LOAD]; 980 break; 981 } 982 983 VkFramebuffer framebuffer = rendererData->textureRenderTarget ? 984 rendererData->textureRenderTarget->mainFramebuffer : 985 rendererData->framebuffers[rendererData->currentSwapchainImageIndex]; 986 987 VkRenderPassBeginInfo renderPassBeginInfo = { 0 }; 988 renderPassBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; 989 renderPassBeginInfo.pNext = NULL; 990 renderPassBeginInfo.renderPass = rendererData->currentRenderPass; 991 renderPassBeginInfo.framebuffer = framebuffer; 992 renderPassBeginInfo.renderArea.offset.x = 0; 993 renderPassBeginInfo.renderArea.offset.y = 0; 994 renderPassBeginInfo.renderArea.extent.width = width; 995 renderPassBeginInfo.renderArea.extent.height = height; 996 renderPassBeginInfo.clearValueCount = (clearColor == NULL) ? 0 : 1; 997 VkClearValue clearValue; 998 if (clearColor != NULL) { 999 clearValue.color = *clearColor; 1000 renderPassBeginInfo.pClearValues = &clearValue; 1001 } 1002 vkCmdBeginRenderPass(rendererData->currentCommandBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); 1003} 1004 1005static void VULKAN_EnsureCommandBuffer(VULKAN_RenderData *rendererData) 1006{ 1007 if (rendererData->currentCommandBuffer == VK_NULL_HANDLE) { 1008 rendererData->currentCommandBuffer = rendererData->commandBuffers[rendererData->currentCommandBufferIndex]; 1009 VULKAN_ResetCommandList(rendererData); 1010 1011 // Ensure the swapchain is in the correct layout 1012 if (rendererData->swapchainImageLayouts[rendererData->currentSwapchainImageIndex] == VK_IMAGE_LAYOUT_UNDEFINED) { 1013 VULKAN_RecordPipelineImageBarrier(rendererData, 1014 0, 1015 VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, 1016 VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, 1017 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 1018 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, 1019 rendererData->swapchainImages[rendererData->currentSwapchainImageIndex], 1020 &rendererData->swapchainImageLayouts[rendererData->currentSwapchainImageIndex]); 1021 } 1022 else if (rendererData->swapchainImageLayouts[rendererData->currentCommandBufferIndex] != VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) { 1023 VULKAN_RecordPipelineImageBarrier(rendererData, 1024 VK_ACCESS_COLOR_ATTACHMENT_READ_BIT, 1025 VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, 1026 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 1027 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 1028 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, 1029 rendererData->swapchainImages[rendererData->currentSwapchainImageIndex], 1030 &rendererData->swapchainImageLayouts[rendererData->currentSwapchainImageIndex]); 1031 } 1032 } 1033} 1034 1035static bool VULKAN_ActivateCommandBuffer(SDL_Renderer *renderer, VkAttachmentLoadOp loadOp, VkClearColorValue *clearColor, VULKAN_DrawStateCache *stateCache) 1036{ 1037 VULKAN_RenderData *rendererData = (VULKAN_RenderData *)renderer->internal; 1038 1039 VULKAN_EnsureCommandBuffer(rendererData); 1040 1041 if (rendererData->currentRenderPass == VK_NULL_HANDLE || loadOp == VK_ATTACHMENT_LOAD_OP_CLEAR) { 1042 if (rendererData->currentRenderPass != VK_NULL_HANDLE) { 1043 vkCmdEndRenderPass(rendererData->currentCommandBuffer); 1044 rendererData->currentRenderPass = VK_NULL_HANDLE; 1045 } 1046 VULKAN_BeginRenderPass(rendererData, loadOp, clearColor); 1047 } 1048 1049 // Bind cached VB now 1050 if (stateCache->vertexBuffer != VK_NULL_HANDLE) { 1051 VkDeviceSize offset = 0; 1052 vkCmdBindVertexBuffers(rendererData->currentCommandBuffer, 0, 1, &stateCache->vertexBuffer, &offset); 1053 } 1054 1055 return true; 1056} 1057 1058static void VULKAN_WaitForGPU(VULKAN_RenderData *rendererData) 1059{ 1060 vkQueueWaitIdle(rendererData->graphicsQueue); 1061} 1062 1063 1064static void VULKAN_ResetCommandList(VULKAN_RenderData *rendererData) 1065{ 1066 vkResetCommandBuffer(rendererData->currentCommandBuffer, 0); 1067 for (uint32_t i = 0; i < rendererData->numDescriptorPools[rendererData->currentCommandBufferIndex]; i++) { 1068 vkResetDescriptorPool(rendererData->device, rendererData->descriptorPools[rendererData->currentCommandBufferIndex][i], 0); 1069 } 1070 1071 VkCommandBufferBeginInfo beginInfo = { 0 }; 1072 beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; 1073 beginInfo.flags = 0; 1074 vkBeginCommandBuffer(rendererData->currentCommandBuffer, &beginInfo); 1075 1076 rendererData->currentPipelineState = NULL; 1077 rendererData->currentVertexBuffer = 0; 1078 rendererData->issueBatch = false; 1079 rendererData->cliprectDirty = true; 1080 rendererData->currentDescriptorSetIndex = 0; 1081 rendererData->currentDescriptorPoolIndex = 0; 1082 rendererData->currentConstantBufferOffset = -1; 1083 rendererData->currentConstantBufferIndex = 0; 1084 1085 // Release any upload buffers that were inflight 1086 for (int i = 0; i < rendererData->currentUploadBuffer[rendererData->currentCommandBufferIndex]; ++i) { 1087 VULKAN_DestroyBuffer(rendererData, &rendererData->uploadBuffers[rendererData->currentCommandBufferIndex][i]); 1088 } 1089 rendererData->currentUploadBuffer[rendererData->currentCommandBufferIndex] = 0; 1090} 1091 1092static VkResult VULKAN_IssueBatch(VULKAN_RenderData *rendererData) 1093{ 1094 VkResult result; 1095 if (rendererData->currentCommandBuffer == VK_NULL_HANDLE) { 1096 return VK_SUCCESS; 1097 } 1098 1099 if (rendererData->currentRenderPass) { 1100 vkCmdEndRenderPass(rendererData->currentCommandBuffer); 1101 rendererData->currentRenderPass = VK_NULL_HANDLE; 1102 } 1103 1104 rendererData->currentPipelineState = VK_NULL_HANDLE; 1105 rendererData->viewportDirty = true; 1106 1107 vkEndCommandBuffer(rendererData->currentCommandBuffer); 1108 1109 VkSubmitInfo submitInfo = { 0 }; 1110 VkPipelineStageFlags waitDestStageMask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT; 1111 submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; 1112 submitInfo.commandBufferCount = 1; 1113 submitInfo.pCommandBuffers = &rendererData->currentCommandBuffer; 1114 if (rendererData->waitRenderSemaphoreCount > 0) { 1115 Uint32 additionalSemaphoreCount = (rendererData->currentImageAvailableSemaphore != VK_NULL_HANDLE) ? 1 : 0; 1116 submitInfo.waitSemaphoreCount = rendererData->waitRenderSemaphoreCount + additionalSemaphoreCount; 1117 if (additionalSemaphoreCount > 0) { 1118 rendererData->waitRenderSemaphores[rendererData->waitRenderSemaphoreCount] = rendererData->currentImageAvailableSemaphore; 1119 rendererData->waitDestStageMasks[rendererData->waitRenderSemaphoreCount] = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT; 1120 } 1121 submitInfo.pWaitSemaphores = rendererData->waitRenderSemaphores; 1122 submitInfo.pWaitDstStageMask = rendererData->waitDestStageMasks; 1123 rendererData->waitRenderSemaphoreCount = 0; 1124 } else if (rendererData->currentImageAvailableSemaphore != VK_NULL_HANDLE) { 1125 submitInfo.waitSemaphoreCount = 1; 1126 submitInfo.pWaitSemaphores = &rendererData->currentImageAvailableSemaphore; 1127 submitInfo.pWaitDstStageMask = &waitDestStageMask; 1128 } 1129 1130 result = vkQueueSubmit(rendererData->graphicsQueue, 1, &submitInfo, VK_NULL_HANDLE); 1131 rendererData->currentImageAvailableSemaphore = VK_NULL_HANDLE; 1132 1133 VULKAN_WaitForGPU(rendererData); 1134 1135 VULKAN_ResetCommandList(rendererData); 1136 1137 return result; 1138} 1139 1140static void VULKAN_DestroyRenderer(SDL_Renderer *renderer) 1141{ 1142 VULKAN_RenderData *rendererData = (VULKAN_RenderData *)renderer->internal; 1143 if (rendererData) { 1144 if (rendererData->device != VK_NULL_HANDLE) { 1145 vkDeviceWaitIdle(rendererData->device); 1146 VULKAN_DestroyAll(renderer); 1147 } 1148 SDL_free(rendererData); 1149 } 1150} 1151 1152static VkBlendFactor GetBlendFactor(SDL_BlendFactor factor) 1153{ 1154 switch (factor) { 1155 case SDL_BLENDFACTOR_ZERO: 1156 return VK_BLEND_FACTOR_ZERO; 1157 case SDL_BLENDFACTOR_ONE: 1158 return VK_BLEND_FACTOR_ONE; 1159 case SDL_BLENDFACTOR_SRC_COLOR: 1160 return VK_BLEND_FACTOR_SRC_COLOR; 1161 case SDL_BLENDFACTOR_ONE_MINUS_SRC_COLOR: 1162 return VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR; 1163 case SDL_BLENDFACTOR_SRC_ALPHA: 1164 return VK_BLEND_FACTOR_SRC_ALPHA; 1165 case SDL_BLENDFACTOR_ONE_MINUS_SRC_ALPHA: 1166 return VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; 1167 case SDL_BLENDFACTOR_DST_COLOR: 1168 return VK_BLEND_FACTOR_DST_COLOR; 1169 case SDL_BLENDFACTOR_ONE_MINUS_DST_COLOR: 1170 return VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR; 1171 case SDL_BLENDFACTOR_DST_ALPHA: 1172 return VK_BLEND_FACTOR_DST_ALPHA; 1173 case SDL_BLENDFACTOR_ONE_MINUS_DST_ALPHA: 1174 return VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA; 1175 default: 1176 return VK_BLEND_FACTOR_MAX_ENUM; 1177 } 1178} 1179 1180static VkBlendOp GetBlendOp(SDL_BlendOperation operation) 1181{ 1182 switch (operation) { 1183 case SDL_BLENDOPERATION_ADD: 1184 return VK_BLEND_OP_ADD; 1185 case SDL_BLENDOPERATION_SUBTRACT: 1186 return VK_BLEND_OP_SUBTRACT; 1187 case SDL_BLENDOPERATION_REV_SUBTRACT: 1188 return VK_BLEND_OP_REVERSE_SUBTRACT; 1189 case SDL_BLENDOPERATION_MINIMUM: 1190 return VK_BLEND_OP_MIN; 1191 case SDL_BLENDOPERATION_MAXIMUM: 1192 return VK_BLEND_OP_MAX; 1193 default: 1194 return VK_BLEND_OP_MAX_ENUM; 1195 } 1196} 1197 1198 1199static VULKAN_PipelineState *VULKAN_CreatePipelineState(SDL_Renderer *renderer, 1200 VULKAN_Shader shader, VkPipelineLayout pipelineLayout, VkDescriptorSetLayout descriptorSetLayout, SDL_BlendMode blendMode, VkPrimitiveTopology topology, VkFormat format) 1201{ 1202 VULKAN_RenderData *rendererData = (VULKAN_RenderData *)renderer->internal; 1203 VULKAN_PipelineState *pipelineStates; 1204 VkPipeline pipeline = VK_NULL_HANDLE; 1205 VkResult result = VK_SUCCESS; 1206 VkPipelineVertexInputStateCreateInfo vertexInputCreateInfo = { 0 }; 1207 VkPipelineInputAssemblyStateCreateInfo inputAssemblyStateCreateInfo = { 0 }; 1208 VkVertexInputAttributeDescription attributeDescriptions[3]; 1209 VkVertexInputBindingDescription bindingDescriptions[1]; 1210 VkPipelineShaderStageCreateInfo shaderStageCreateInfo[2]; 1211 VkPipelineDynamicStateCreateInfo dynamicStateCreateInfo = { 0 }; 1212 VkPipelineViewportStateCreateInfo viewportStateCreateInfo = { 0 }; 1213 VkPipelineRasterizationStateCreateInfo rasterizationStateCreateInfo = { 0 }; 1214 VkPipelineMultisampleStateCreateInfo multisampleStateCreateInfo = { 0 }; 1215 VkPipelineDepthStencilStateCreateInfo depthStencilStateCreateInfo = { 0 }; 1216 VkPipelineColorBlendStateCreateInfo colorBlendStateCreateInfo = { 0 }; 1217 1218 VkGraphicsPipelineCreateInfo pipelineCreateInfo = { 0 }; 1219 pipelineCreateInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; 1220 pipelineCreateInfo.flags = 0; 1221 pipelineCreateInfo.pStages = shaderStageCreateInfo; 1222 pipelineCreateInfo.pVertexInputState = &vertexInputCreateInfo; 1223 pipelineCreateInfo.pInputAssemblyState = &inputAssemblyStateCreateInfo; 1224 pipelineCreateInfo.pViewportState = &viewportStateCreateInfo; 1225 pipelineCreateInfo.pRasterizationState = &rasterizationStateCreateInfo; 1226 pipelineCreateInfo.pMultisampleState = &multisampleStateCreateInfo; 1227 pipelineCreateInfo.pDepthStencilState = &depthStencilStateCreateInfo; 1228 pipelineCreateInfo.pColorBlendState = &colorBlendStateCreateInfo; 1229 pipelineCreateInfo.pDynamicState = &dynamicStateCreateInfo; 1230 1231 // Shaders 1232 const char *name = "main"; 1233 for (uint32_t i = 0; i < 2; i++) { 1234 SDL_zero(shaderStageCreateInfo[i]); 1235 shaderStageCreateInfo[i].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; 1236 shaderStageCreateInfo[i].module = (i == 0) ? rendererData->vertexShaderModules[shader] : rendererData->fragmentShaderModules[shader]; 1237 shaderStageCreateInfo[i].stage = (i == 0) ? VK_SHADER_STAGE_VERTEX_BIT : VK_SHADER_STAGE_FRAGMENT_BIT; 1238 shaderStageCreateInfo[i].pName = name; 1239 } 1240 pipelineCreateInfo.stageCount = 2; 1241 pipelineCreateInfo.pStages = &shaderStageCreateInfo[0]; 1242 1243 1244 // Vertex input 1245 vertexInputCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; 1246 vertexInputCreateInfo.vertexAttributeDescriptionCount = 3; 1247 vertexInputCreateInfo.pVertexAttributeDescriptions = &attributeDescriptions[0]; 1248 vertexInputCreateInfo.vertexBindingDescriptionCount = 1; 1249 vertexInputCreateInfo.pVertexBindingDescriptions = &bindingDescriptions[0]; 1250 1251 attributeDescriptions[ 0 ].binding = 0; 1252 attributeDescriptions[ 0 ].format = VK_FORMAT_R32G32_SFLOAT; 1253 attributeDescriptions[ 0 ].location = 0; 1254 attributeDescriptions[ 0 ].offset = 0; 1255 attributeDescriptions[ 1 ].binding = 0; 1256 attributeDescriptions[ 1 ].format = VK_FORMAT_R32G32_SFLOAT; 1257 attributeDescriptions[ 1 ].location = 1; 1258 attributeDescriptions[ 1 ].offset = 8; 1259 attributeDescriptions[ 2 ].binding = 0; 1260 attributeDescriptions[ 2 ].format = VK_FORMAT_R32G32B32A32_SFLOAT; 1261 attributeDescriptions[ 2 ].location = 2; 1262 attributeDescriptions[ 2 ].offset = 16; 1263 1264 bindingDescriptions[ 0 ].binding = 0; 1265 bindingDescriptions[ 0 ].inputRate = VK_VERTEX_INPUT_RATE_VERTEX; 1266 bindingDescriptions[ 0 ].stride = 32; 1267 1268 // Input assembly 1269 inputAssemblyStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; 1270 inputAssemblyStateCreateInfo.topology = topology; 1271 inputAssemblyStateCreateInfo.primitiveRestartEnable = VK_FALSE; 1272 1273 viewportStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; 1274 viewportStateCreateInfo.scissorCount = 1; 1275 viewportStateCreateInfo.viewportCount = 1; 1276 1277 // Dynamic states 1278 dynamicStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; 1279 VkDynamicState dynamicStates[2] = { 1280 VK_DYNAMIC_STATE_VIEWPORT, 1281 VK_DYNAMIC_STATE_SCISSOR 1282 }; 1283 dynamicStateCreateInfo.dynamicStateCount = SDL_arraysize(dynamicStates); 1284 dynamicStateCreateInfo.pDynamicStates = dynamicStates; 1285 1286 // Rasterization state 1287 rasterizationStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; 1288 rasterizationStateCreateInfo.depthClampEnable = VK_FALSE; 1289 rasterizationStateCreateInfo.rasterizerDiscardEnable = VK_FALSE; 1290 rasterizationStateCreateInfo.cullMode = VK_CULL_MODE_NONE; 1291 rasterizationStateCreateInfo.polygonMode = VK_POLYGON_MODE_FILL; 1292 rasterizationStateCreateInfo.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE; 1293 rasterizationStateCreateInfo.depthBiasEnable = VK_FALSE; 1294 rasterizationStateCreateInfo.depthBiasConstantFactor = 0.0f; 1295 rasterizationStateCreateInfo.depthBiasClamp = 0.0f; 1296 rasterizationStateCreateInfo.depthBiasSlopeFactor = 0.0f; 1297 rasterizationStateCreateInfo.lineWidth = 1.0f; 1298 1299 // MSAA state 1300 multisampleStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; 1301 VkSampleMask multiSampleMask = 0xFFFFFFFF; 1302 multisampleStateCreateInfo.pSampleMask = &multiSampleMask; 1303 multisampleStateCreateInfo.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; 1304 1305 // Depth Stencil 1306 depthStencilStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; 1307 1308 // Color blend 1309 VkPipelineColorBlendAttachmentState colorBlendAttachment = { 0 }; 1310 colorBlendStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; 1311 colorBlendStateCreateInfo.attachmentCount = 1; 1312 colorBlendStateCreateInfo.pAttachments = &colorBlendAttachment; 1313 colorBlendAttachment.blendEnable = VK_TRUE; 1314 colorBlendAttachment.srcColorBlendFactor = GetBlendFactor(SDL_GetBlendModeSrcColorFactor(blendMode)); 1315 colorBlendAttachment.srcAlphaBlendFactor = GetBlendFactor(SDL_GetBlendModeSrcAlphaFactor(blendMode)); 1316 colorBlendAttachment.colorBlendOp = GetBlendOp(SDL_GetBlendModeColorOperation(blendMode)); 1317 colorBlendAttachment.dstColorBlendFactor = GetBlendFactor(SDL_GetBlendModeDstColorFactor(blendMode)); 1318 colorBlendAttachment.dstAlphaBlendFactor = GetBlendFactor(SDL_GetBlendModeDstAlphaFactor(blendMode)); 1319 colorBlendAttachment.alphaBlendOp = GetBlendOp(SDL_GetBlendModeAlphaOperation(blendMode)); 1320 colorBlendAttachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; 1321 1322 // Renderpass / layout 1323 pipelineCreateInfo.renderPass = rendererData->currentRenderPass; 1324 pipelineCreateInfo.subpass = 0; 1325 pipelineCreateInfo.layout = pipelineLayout; 1326 1327 result = vkCreateGraphicsPipelines(rendererData->device, VK_NULL_HANDLE, 1, &pipelineCreateInfo, NULL, &pipeline); 1328 if (result != VK_SUCCESS) { 1329 SET_ERROR_CODE("vkCreateGraphicsPipelines()", result); 1330 return NULL; 1331 } 1332 1333 pipelineStates = (VULKAN_PipelineState *)SDL_realloc(rendererData->pipelineStates, (rendererData->pipelineStateCount + 1) * sizeof(*pipelineStates)); 1334 if (!pipelineStates) { 1335 return NULL; 1336 } 1337 pipelineStates[rendererData->pipelineStateCount].shader = shader; 1338 pipelineStates[rendererData->pipelineStateCount].blendMode = blendMode; 1339 pipelineStates[rendererData->pipelineStateCount].topology = topology; 1340 pipelineStates[rendererData->pipelineStateCount].format = format; 1341 pipelineStates[rendererData->pipelineStateCount].pipeline = pipeline; 1342 pipelineStates[rendererData->pipelineStateCount].descriptorSetLayout = descriptorSetLayout; 1343 pipelineStates[rendererData->pipelineStateCount].pipelineLayout = pipelineCreateInfo.layout; 1344 rendererData->pipelineStates = pipelineStates; 1345 ++rendererData->pipelineStateCount; 1346 1347 return &pipelineStates[rendererData->pipelineStateCount - 1]; 1348} 1349 1350static bool VULKAN_FindMemoryTypeIndex(VULKAN_RenderData *rendererData, uint32_t typeBits, VkMemoryPropertyFlags requiredFlags, VkMemoryPropertyFlags desiredFlags, uint32_t *memoryTypeIndexOut) 1351{ 1352 uint32_t memoryTypeIndex = 0; 1353 bool foundExactMatch = false; 1354 1355 // Desired flags must be a superset of required flags. 1356 desiredFlags |= requiredFlags; 1357 1358 for (memoryTypeIndex = 0; memoryTypeIndex < rendererData->physicalDeviceMemoryProperties.memoryTypeCount; memoryTypeIndex++) { 1359 if (typeBits & (1 << memoryTypeIndex)) { 1360 if (rendererData->physicalDeviceMemoryProperties.memoryTypes[memoryTypeIndex].propertyFlags == desiredFlags) { 1361 foundExactMatch = true; 1362 break; 1363 } 1364 } 1365 } 1366 if (!foundExactMatch) { 1367 for (memoryTypeIndex = 0; memoryTypeIndex < rendererData->physicalDeviceMemoryProperties.memoryTypeCount; memoryTypeIndex++) { 1368 if (typeBits & (1 << memoryTypeIndex)) { 1369 if ((rendererData->physicalDeviceMemoryProperties.memoryTypes[memoryTypeIndex].propertyFlags & requiredFlags) == requiredFlags) { 1370 break; 1371 } 1372 } 1373 } 1374 } 1375 1376 if (memoryTypeIndex >= rendererData->physicalDeviceMemoryProperties.memoryTypeCount) { 1377 SET_ERROR_MESSAGE("Unable to find memory type for allocation"); 1378 return false; 1379 } 1380 *memoryTypeIndexOut = memoryTypeIndex; 1381 return true; 1382} 1383 1384static VkResult VULKAN_CreateVertexBuffer(VULKAN_RenderData *rendererData, size_t vbidx, size_t size) 1385{ 1386 VkResult result; 1387 1388 VULKAN_DestroyBuffer(rendererData, &rendererData->vertexBuffers[vbidx]); 1389 1390 result = VULKAN_AllocateBuffer(rendererData, size, 1391 VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, 1392 VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | 1393 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, 1394 VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, 1395 &rendererData->vertexBuffers[vbidx]); 1396 if (result != VK_SUCCESS) { 1397 return result; 1398 } 1399 return result; 1400} 1401 1402static bool VULKAN_LoadGlobalFunctions(VULKAN_RenderData *rendererData) 1403{ 1404#define VULKAN_DEVICE_FUNCTION(name) 1405#define VULKAN_GLOBAL_FUNCTION(name) \ 1406 name = (PFN_##name)rendererData->vkGetInstanceProcAddr(VK_NULL_HANDLE, #name); \ 1407 if (!name) { \ 1408 SET_ERROR_MESSAGE("vkGetInstanceProcAddr(VK_NULL_HANDLE, \"" #name "\") failed"); \ 1409 return false; \ 1410 } 1411#define VULKAN_INSTANCE_FUNCTION(name) 1412#define VULKAN_OPTIONAL_INSTANCE_FUNCTION(name) 1413#define VULKAN_OPTIONAL_DEVICE_FUNCTION(name) 1414 VULKAN_FUNCTIONS() 1415#undef VULKAN_DEVICE_FUNCTION 1416#undef VULKAN_GLOBAL_FUNCTION 1417#undef VULKAN_INSTANCE_FUNCTION 1418#undef VULKAN_OPTIONAL_INSTANCE_FUNCTION 1419#undef VULKAN_OPTIONAL_DEVICE_FUNCTION 1420 1421 return true; 1422} 1423 1424static bool VULKAN_LoadInstanceFunctions(VULKAN_RenderData *rendererData) 1425{ 1426#define VULKAN_DEVICE_FUNCTION(name) 1427#define VULKAN_GLOBAL_FUNCTION(name) 1428#define VULKAN_INSTANCE_FUNCTION(name) \ 1429 name = (PFN_##name)rendererData->vkGetInstanceProcAddr(rendererData->instance, #name); \ 1430 if (!name) { \ 1431 SET_ERROR_MESSAGE("vkGetInstanceProcAddr(instance, \"" #name "\") failed"); \ 1432 return false; \ 1433 } 1434#define VULKAN_OPTIONAL_INSTANCE_FUNCTION(name) \ 1435 name = (PFN_##name)rendererData->vkGetInstanceProcAddr(rendererData->instance, #name); 1436#define VULKAN_OPTIONAL_DEVICE_FUNCTION(name) 1437 1438 VULKAN_FUNCTIONS() 1439#undef VULKAN_DEVICE_FUNCTION 1440#undef VULKAN_GLOBAL_FUNCTION 1441#undef VULKAN_INSTANCE_FUNCTION 1442#undef VULKAN_OPTIONAL_INSTANCE_FUNCTION 1443#undef VULKAN_OPTIONAL_DEVICE_FUNCTION 1444 1445 return true; 1446} 1447 1448static bool VULKAN_LoadDeviceFunctions(VULKAN_RenderData *rendererData) 1449{ 1450#define VULKAN_DEVICE_FUNCTION(name) \ 1451 name = (PFN_##name)vkGetDeviceProcAddr(rendererData->device, #name); \ 1452 if (!name) { \ 1453 SET_ERROR_MESSAGE("vkGetDeviceProcAddr(device, \"" #name "\") failed"); \ 1454 return false; \ 1455 } 1456#define VULKAN_GLOBAL_FUNCTION(name) 1457#define VULKAN_OPTIONAL_DEVICE_FUNCTION(name) \ 1458 name = (PFN_##name)vkGetDeviceProcAddr(rendererData->device, #name); 1459#define VULKAN_INSTANCE_FUNCTION(name) 1460#define VULKAN_OPTIONAL_INSTANCE_FUNCTION(name) 1461 VULKAN_FUNCTIONS() 1462#undef VULKAN_DEVICE_FUNCTION 1463#undef VULKAN_GLOBAL_FUNCTION 1464#undef VULKAN_INSTANCE_FUNCTION 1465#undef VULKAN_OPTIONAL_INSTANCE_FUNCTION 1466#undef VULKAN_OPTIONAL_DEVICE_FUNCTION 1467 return true; 1468} 1469 1470static VkResult VULKAN_FindPhysicalDevice(VULKAN_RenderData *rendererData) 1471{ 1472 uint32_t physicalDeviceCount = 0; 1473 VkPhysicalDevice *physicalDevices; 1474 VkQueueFamilyProperties *queueFamiliesProperties = NULL; 1475 uint32_t queueFamiliesPropertiesAllocatedSize = 0; 1476 VkExtensionProperties *deviceExtensions = NULL; 1477 uint32_t deviceExtensionsAllocatedSize = 0; 1478 uint32_t physicalDeviceIndex; 1479 VkResult result; 1480 1481 result = vkEnumeratePhysicalDevices(rendererData->instance, &physicalDeviceCount, NULL); 1482 if (result != VK_SUCCESS) { 1483 SET_ERROR_CODE("vkEnumeratePhysicalDevices()", result); 1484 return result; 1485 } 1486 if (physicalDeviceCount == 0) { 1487 SET_ERROR_MESSAGE("vkEnumeratePhysicalDevices(): no physical devices"); 1488 return VK_ERROR_UNKNOWN; 1489 } 1490 physicalDevices = (VkPhysicalDevice *)SDL_malloc(sizeof(VkPhysicalDevice) * physicalDeviceCount); 1491 result = vkEnumeratePhysicalDevices(rendererData->instance, &physicalDeviceCount, physicalDevices); 1492 if (result != VK_SUCCESS) { 1493 SDL_free(physicalDevices); 1494 SET_ERROR_CODE("vkEnumeratePhysicalDevices()", result); 1495 return result; 1496 } 1497 rendererData->physicalDevice = NULL; 1498 for (physicalDeviceIndex = 0; physicalDeviceIndex < physicalDeviceCount; physicalDeviceIndex++) { 1499 uint32_t queueFamiliesCount = 0; 1500 uint32_t queueFamilyIndex; 1501 uint32_t deviceExtensionCount = 0; 1502 bool hasSwapchainExtension = false; 1503 uint32_t i; 1504 1505 VkPhysicalDevice physicalDevice = physicalDevices[physicalDeviceIndex]; 1506 vkGetPhysicalDeviceProperties(physicalDevice, &rendererData->physicalDeviceProperties); 1507 if (VK_VERSION_MAJOR(rendererData->physicalDeviceProperties.apiVersion) < 1) { 1508 continue; 1509 } 1510 vkGetPhysicalDeviceMemoryProperties(physicalDevice, &rendererData->physicalDeviceMemoryProperties); 1511 vkGetPhysicalDeviceFeatures(physicalDevice, &rendererData->physicalDeviceFeatures); 1512 vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueFamiliesCount, NULL); 1513 if (queueFamiliesCount == 0) { 1514 continue; 1515 } 1516 if (queueFamiliesPropertiesAllocatedSize < queueFamiliesCount) { 1517 SDL_free(queueFamiliesProperties); 1518 queueFamiliesPropertiesAllocatedSize = queueFamiliesCount; 1519 queueFamiliesProperties = (VkQueueFamilyProperties *)SDL_malloc(sizeof(VkQueueFamilyProperties) * queueFamiliesPropertiesAllocatedSize); 1520 if (!queueFamiliesProperties) { 1521 SDL_free(physicalDevices); 1522 SDL_free(deviceExtensions); 1523 return VK_ERROR_UNKNOWN; 1524 } 1525 } 1526 vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueFamiliesCount, queueFamiliesProperties); 1527 rendererData->graphicsQueueFamilyIndex = queueFamiliesCount; 1528 rendererData->presentQueueFamilyIndex = queueFamiliesCount; 1529 for (queueFamilyIndex = 0; queueFamilyIndex < queueFamiliesCount; queueFamilyIndex++) { 1530 VkBool32 supported = 0; 1531 1532 if (queueFamiliesProperties[queueFamilyIndex].queueCount == 0) { 1533 continue; 1534 } 1535 1536 if (queueFamiliesProperties[queueFamilyIndex].queueFlags & VK_QUEUE_GRAPHICS_BIT) { 1537 rendererData->graphicsQueueFamilyIndex = queueFamilyIndex; 1538 } 1539 1540 result = vkGetPhysicalDeviceSurfaceSupportKHR(physicalDevice, queueFamilyIndex, rendererData->surface, &supported); 1541 if (result != VK_SUCCESS) { 1542 SDL_free(physicalDevices); 1543 SDL_free(queueFamiliesProperties); 1544 SDL_free(deviceExtensions); 1545 SET_ERROR_CODE("vkGetPhysicalDeviceSurfaceSupportKHR()", result); 1546 return VK_ERROR_UNKNOWN; 1547 } 1548 if (supported) { 1549 rendererData->presentQueueFamilyIndex = queueFamilyIndex; 1550 if (queueFamiliesProperties[queueFamilyIndex].queueFlags & VK_QUEUE_GRAPHICS_BIT) { 1551 break; // use this queue because it can present and do graphics 1552 } 1553 } 1554 } 1555 1556 if (rendererData->graphicsQueueFamilyIndex == queueFamiliesCount) { // no good queues found 1557 continue; 1558 } 1559 if (rendererData->presentQueueFamilyIndex == queueFamiliesCount) { // no good queues found 1560 continue; 1561 } 1562 result = vkEnumerateDeviceExtensionProperties(physicalDevice, NULL, &deviceExtensionCount, NULL); 1563 if (result != VK_SUCCESS) { 1564 SDL_free(physicalDevices); 1565 SDL_free(queueFamiliesProperties); 1566 SDL_free(deviceExtensions); 1567 SET_ERROR_CODE("vkEnumerateDeviceExtensionProperties()", result); 1568 return VK_ERROR_UNKNOWN; 1569 } 1570 if (deviceExtensionCount == 0) { 1571 continue; 1572 } 1573 if (deviceExtensionsAllocatedSize < deviceExtensionCount) { 1574 SDL_free(deviceExtensions); 1575 deviceExtensionsAllocatedSize = deviceExtensionCount; 1576 deviceExtensions = (VkExtensionProperties *)SDL_malloc(sizeof(VkExtensionProperties) * deviceExtensionsAllocatedSize); 1577 if (!deviceExtensions) { 1578 SDL_free(physicalDevices); 1579 SDL_free(queueFamiliesProperties); 1580 return VK_ERROR_UNKNOWN; 1581 } 1582 } 1583 result = vkEnumerateDeviceExtensionProperties(physicalDevice, NULL, &deviceExtensionCount, deviceExtensions); 1584 if (result != VK_SUCCESS) { 1585 SDL_free(physicalDevices); 1586 SDL_free(queueFamiliesProperties); 1587 SDL_free(deviceExtensions); 1588 SET_ERROR_CODE("vkEnumerateDeviceExtensionProperties()", result); 1589 return result; 1590 } 1591 for (i = 0; i < deviceExtensionCount; i++) { 1592 if (SDL_strcmp(deviceExtensions[i].extensionName, VK_KHR_SWAPCHAIN_EXTENSION_NAME) == 0) { 1593 hasSwapchainExtension = true; 1594 break; 1595 } 1596 } 1597 if (!hasSwapchainExtension) { 1598 continue; 1599 } 1600 rendererData->physicalDevice = physicalDevice; 1601 break; 1602 } 1603 SDL_free(physicalDevices); 1604 SDL_free(queueFamiliesProperties); 1605 SDL_free(deviceExtensions); 1606 if (!rendererData->physicalDevice) { 1607 SET_ERROR_MESSAGE("No viable physical devices found"); 1608 return VK_ERROR_UNKNOWN; 1609 } 1610 return VK_SUCCESS; 1611} 1612 1613static VkResult VULKAN_GetSurfaceFormats(VULKAN_RenderData *rendererData) 1614{ 1615 VkResult result = vkGetPhysicalDeviceSurfaceFormatsKHR(rendererData->physicalDevice, 1616 rendererData->surface, 1617 &rendererData->surfaceFormatsCount, 1618 NULL); 1619 if (result != VK_SUCCESS) { 1620 rendererData->surfaceFormatsCount = 0; 1621 SET_ERROR_CODE("vkGetPhysicalDeviceSurfaceFormatsKHR()", result); 1622 return result; 1623 } 1624 if (rendererData->surfaceFormatsCount > rendererData->surfaceFormatsAllocatedCount) { 1625 rendererData->surfaceFormatsAllocatedCount = rendererData->surfaceFormatsCount; 1626 SDL_free(rendererData->surfaceFormats); 1627 rendererData->surfaceFormats = (VkSurfaceFormatKHR *)SDL_malloc(sizeof(VkSurfaceFormatKHR) * rendererData->surfaceFormatsAllocatedCount); 1628 } 1629 result = vkGetPhysicalDeviceSurfaceFormatsKHR(rendererData->physicalDevice, 1630 rendererData->surface, 1631 &rendererData->surfaceFormatsCount, 1632 rendererData->surfaceFormats); 1633 if (result != VK_SUCCESS) { 1634 rendererData->surfaceFormatsCount = 0; 1635 SET_ERROR_CODE("vkGetPhysicalDeviceSurfaceFormatsKHR()", result); 1636 return result; 1637 } 1638 1639 return VK_SUCCESS; 1640} 1641 1642static VkSemaphore VULKAN_CreateSemaphore(VULKAN_RenderData *rendererData) 1643{ 1644 VkResult result; 1645 VkSemaphore semaphore = VK_NULL_HANDLE; 1646 1647 VkSemaphoreCreateInfo semaphoreCreateInfo = { 0 }; 1648 semaphoreCreateInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; 1649 result = vkCreateSemaphore(rendererData->device, &semaphoreCreateInfo, NULL, &semaphore); 1650 if (result != VK_SUCCESS) { 1651 SET_ERROR_CODE("vkCreateSemaphore()", result); 1652 return VK_NULL_HANDLE; 1653 } 1654 return semaphore; 1655} 1656 1657static bool VULKAN_DeviceExtensionsFound(VULKAN_RenderData *rendererData, int extensionsToCheck, const char * const *extNames) 1658{ 1659 uint32_t extensionCount; 1660 bool foundExtensions = true; 1661 VkResult result = vkEnumerateDeviceExtensionProperties(rendererData->physicalDevice, NULL, &extensionCount, NULL); 1662 if (result != VK_SUCCESS ) { 1663 SET_ERROR_CODE("vkEnumerateDeviceExtensionProperties()", result); 1664 return false; 1665 } 1666 if (extensionCount > 0 ) { 1667 VkExtensionProperties *extensionProperties = (VkExtensionProperties *)SDL_calloc(extensionCount, sizeof(VkExtensionProperties)); 1668 result = vkEnumerateDeviceExtensionProperties(rendererData->physicalDevice, NULL, &extensionCount, extensionProperties); 1669 if (result != VK_SUCCESS ) { 1670 SET_ERROR_CODE("vkEnumerateDeviceExtensionProperties()", result); 1671 SDL_free(extensionProperties); 1672 return false; 1673 } 1674 for (int ext = 0; ext < extensionsToCheck && foundExtensions; ext++) { 1675 bool foundExtension = false; 1676 for (uint32_t i = 0; i < extensionCount; i++) { 1677 if (SDL_strcmp(extensionProperties[i].extensionName, extNames[ext]) == 0) { 1678 foundExtension = true; 1679 break; 1680 } 1681 } 1682 foundExtensions &= foundExtension; 1683 } 1684 1685 SDL_free(extensionProperties); 1686 } 1687 1688 return foundExtensions; 1689} 1690 1691static bool VULKAN_InstanceExtensionFound(VULKAN_RenderData *rendererData, const char *extName) 1692{ 1693 uint32_t extensionCount; 1694 VkResult result = vkEnumerateInstanceExtensionProperties(NULL, &extensionCount, NULL); 1695 if (result != VK_SUCCESS ) { 1696 SET_ERROR_CODE("vkEnumerateInstanceExtensionProperties()", result); 1697 return false; 1698 } 1699 if (extensionCount > 0 ) { 1700 VkExtensionProperties *extensionProperties = (VkExtensionProperties *)SDL_calloc(extensionCount, sizeof(VkExtensionProperties)); 1701 result = vkEnumerateInstanceExtensionProperties(NULL, &extensionCount, extensionProperties); 1702 if (result != VK_SUCCESS ) { 1703 SET_ERROR_CODE("vkEnumerateInstanceExtensionProperties()", result); 1704 SDL_free(extensionProperties); 1705 return false; 1706 } 1707 for (uint32_t i = 0; i< extensionCount; i++) { 1708 if (SDL_strcmp(extensionProperties[i].extensionName, extName) == 0) { 1709 SDL_free(extensionProperties); 1710 return true; 1711 } 1712 } 1713 SDL_free(extensionProperties); 1714 } 1715 1716 return false; 1717} 1718 1719static bool VULKAN_ValidationLayersFound(void) 1720{ 1721 uint32_t instanceLayerCount = 0; 1722 uint32_t i; 1723 bool foundValidation = false; 1724 1725 vkEnumerateInstanceLayerProperties(&instanceLayerCount, NULL); 1726 if (instanceLayerCount > 0) { 1727 VkLayerProperties *instanceLayers = (VkLayerProperties *)SDL_calloc(instanceLayerCount, sizeof(VkLayerProperties)); 1728 vkEnumerateInstanceLayerProperties(&instanceLayerCount, instanceLayers); 1729 for (i = 0; i < instanceLayerCount; i++) { 1730 if (!SDL_strcmp(SDL_VULKAN_VALIDATION_LAYER_NAME, instanceLayers[i].layerName)) { 1731 foundValidation = true; 1732 break; 1733 } 1734 } 1735 SDL_free(instanceLayers); 1736 } 1737 1738 return foundValidation; 1739} 1740 1741// Create resources that depend on the device. 1742static VkResult VULKAN_CreateDeviceResources(SDL_Renderer *renderer, SDL_PropertiesID create_props) 1743{ 1744 static const char *const deviceExtensionNames[] = { 1745 VK_KHR_SWAPCHAIN_EXTENSION_NAME, 1746 /* VK_KHR_sampler_ycbcr_conversion + dependent extensions. 1747 Note VULKAN_DeviceExtensionsFound() call below, if these get moved in this 1748 array, update that check too. 1749 */ 1750 VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME, 1751 VK_KHR_MAINTENANCE1_EXTENSION_NAME, 1752 VK_KHR_BIND_MEMORY_2_EXTENSION_NAME, 1753 VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME, 1754 }; 1755 VULKAN_RenderData *rendererData = (VULKAN_RenderData *)renderer->internal; 1756 VkResult result = VK_SUCCESS; 1757 PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = NULL; 1758 bool createDebug = SDL_GetHintBoolean(SDL_HINT_RENDER_VULKAN_DEBUG, false); 1759 const char *validationLayerName[] = { SDL_VULKAN_VALIDATION_LAYER_NAME }; 1760 1761 if (!SDL_Vulkan_LoadLibrary(NULL)) { 1762 SDL_LogDebug(SDL_LOG_CATEGORY_RENDER, "SDL_Vulkan_LoadLibrary failed" ); 1763 return VK_ERROR_UNKNOWN; 1764 } 1765 vkGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)SDL_Vulkan_GetVkGetInstanceProcAddr(); 1766 if(!vkGetInstanceProcAddr) { 1767 SDL_LogDebug(SDL_LOG_CATEGORY_RENDER, "vkGetInstanceProcAddr is NULL" ); 1768 return VK_ERROR_UNKNOWN; 1769 } 1770 1771 // Load global Vulkan functions 1772 rendererData->vkGetInstanceProcAddr = vkGetInstanceProcAddr; 1773 if (!VULKAN_LoadGlobalFunctions(rendererData)) { 1774 return VK_ERROR_UNKNOWN; 1775 } 1776 1777 // Check for colorspace extension 1778 rendererData->supportsEXTSwapchainColorspace = VK_FALSE; 1779 if (renderer->output_colorspace == SDL_COLORSPACE_SRGB_LINEAR || 1780 renderer->output_colorspace == SDL_COLORSPACE_HDR10) { 1781 rendererData->supportsEXTSwapchainColorspace = VULKAN_InstanceExtensionFound(rendererData, VK_EXT_SWAPCHAIN_COLOR_SPACE_EXTENSION_NAME); 1782 if (!rendererData->supportsEXTSwapchainColorspace) { 1783 SDL_SetError("Using HDR output but %s not supported", VK_EXT_SWAPCHAIN_COLOR_SPACE_EXTENSION_NAME); 1784 return VK_ERROR_UNKNOWN; 1785 } 1786 } 1787 1788 // Check for VK_KHR_get_physical_device_properties2 1789 rendererData->supportsKHRGetPhysicalDeviceProperties2 = VULKAN_InstanceExtensionFound(rendererData, VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME); 1790 1791 // Create VkInstance 1792 rendererData->instance = (VkInstance)SDL_GetPointerProperty(create_props, SDL_PROP_RENDERER_CREATE_VULKAN_INSTANCE_POINTER, NULL); 1793 if (rendererData->instance) { 1794 rendererData->instance_external = true; 1795 } else { 1796 VkInstanceCreateInfo instanceCreateInfo = { 0 }; 1797 VkApplicationInfo appInfo = { 0 }; 1798 appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; 1799 appInfo.apiVersion = VK_API_VERSION_1_0; 1800 instanceCreateInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; 1801 instanceCreateInfo.pApplicationInfo = &appInfo; 1802 char const *const *instanceExtensions = SDL_Vulkan_GetInstanceExtensions(&instanceCreateInfo.enabledExtensionCount); 1803 1804 const char **instanceExtensionsCopy = (const char **)SDL_calloc(instanceCreateInfo.enabledExtensionCount + 2, sizeof(const char *)); 1805 for (uint32_t i = 0; i < instanceCreateInfo.enabledExtensionCount; i++) { 1806 instanceExtensionsCopy[i] = instanceExtensions[i]; 1807 } 1808 if (rendererData->supportsEXTSwapchainColorspace) { 1809 instanceExtensionsCopy[instanceCreateInfo.enabledExtensionCount] = VK_EXT_SWAPCHAIN_COLOR_SPACE_EXTENSION_NAME; 1810 instanceCreateInfo.enabledExtensionCount++; 1811 } 1812 if (rendererData->supportsKHRGetPhysicalDeviceProperties2) { 1813 instanceExtensionsCopy[instanceCreateInfo.enabledExtensionCount] = VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME; 1814 instanceCreateInfo.enabledExtensionCount++; 1815 } 1816 instanceCreateInfo.ppEnabledExtensionNames = (const char *const *)instanceExtensionsCopy; 1817 if (createDebug && VULKAN_ValidationLayersFound()) { 1818 instanceCreateInfo.ppEnabledLayerNames = validationLayerName; 1819 instanceCreateInfo.enabledLayerCount = 1; 1820 } 1821 result = vkCreateInstance(&instanceCreateInfo, NULL, &rendererData->instance); 1822 SDL_free((void *)instanceExtensionsCopy); 1823 if (result != VK_SUCCESS) { 1824 SET_ERROR_CODE("vkCreateInstance()", result); 1825 return result; 1826 } 1827 } 1828 1829 // Load instance Vulkan functions 1830 if (!VULKAN_LoadInstanceFunctions(rendererData)) { 1831 VULKAN_DestroyAll(renderer); 1832 return VK_ERROR_UNKNOWN; 1833 } 1834 1835 // Create Vulkan surface 1836 rendererData->surface = (VkSurfaceKHR)SDL_GetNumberProperty(create_props, SDL_PROP_RENDERER_CREATE_VULKAN_SURFACE_NUMBER, 0); 1837 if (rendererData->surface) { 1838 rendererData->surface_external = true; 1839 } else { 1840 if (!SDL_Vulkan_CreateSurface(renderer->window, rendererData->instance, NULL, &rendererData->surface)) { 1841 VULKAN_DestroyAll(renderer); 1842 return VK_ERROR_UNKNOWN; 1843 } 1844 } 1845 1846 // Choose Vulkan physical device 1847 rendererData->physicalDevice = (VkPhysicalDevice)SDL_GetPointerProperty(create_props, SDL_PROP_RENDERER_CREATE_VULKAN_PHYSICAL_DEVICE_POINTER, NULL); 1848 if (rendererData->physicalDevice) { 1849 vkGetPhysicalDeviceMemoryProperties(rendererData->physicalDevice, &rendererData->physicalDeviceMemoryProperties); 1850 vkGetPhysicalDeviceFeatures(rendererData->physicalDevice, &rendererData->physicalDeviceFeatures); 1851 } else { 1852 if (VULKAN_FindPhysicalDevice(rendererData) != VK_SUCCESS) { 1853 VULKAN_DestroyAll(renderer); 1854 return VK_ERROR_UNKNOWN; 1855 } 1856 } 1857 1858 if (SDL_HasProperty(create_props, SDL_PROP_RENDERER_CREATE_VULKAN_GRAPHICS_QUEUE_FAMILY_INDEX_NUMBER)) { 1859 rendererData->graphicsQueueFamilyIndex = (uint32_t)SDL_GetNumberProperty(create_props, SDL_PROP_RENDERER_CREATE_VULKAN_GRAPHICS_QUEUE_FAMILY_INDEX_NUMBER, 0); 1860 } 1861 if (SDL_HasProperty(create_props, SDL_PROP_RENDERER_CREATE_VULKAN_PRESENT_QUEUE_FAMILY_INDEX_NUMBER)) { 1862 rendererData->presentQueueFamilyIndex = (uint32_t)SDL_GetNumberProperty(create_props, SDL_PROP_RENDERER_CREATE_VULKAN_PRESENT_QUEUE_FAMILY_INDEX_NUMBER, 0); 1863 } 1864 1865 if (rendererData->supportsKHRGetPhysicalDeviceProperties2 && 1866 VULKAN_DeviceExtensionsFound(rendererData, 4, &deviceExtensionNames[1])) { 1867 rendererData->supportsKHRSamplerYCbCrConversion = true; 1868 } 1869 1870 // Create Vulkan device 1871 rendererData->device = (VkDevice)SDL_GetPointerProperty(create_props, SDL_PROP_RENDERER_CREATE_VULKAN_DEVICE_POINTER, NULL); 1872 if (rendererData->device) { 1873 rendererData->device_external = true; 1874 } else { 1875 VkPhysicalDeviceSamplerYcbcrConversionFeatures deviceSamplerYcbcrConversionFeatures = { 0 }; 1876 VkDeviceQueueCreateInfo deviceQueueCreateInfo[2] = { { 0 }, { 0 } }; 1877 static const float queuePriority[] = { 1.0f }; 1878 1879 VkDeviceCreateInfo deviceCreateInfo = { 0 }; 1880 deviceCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; 1881 deviceCreateInfo.queueCreateInfoCount = 0; 1882 deviceCreateInfo.pQueueCreateInfos = deviceQueueCreateInfo; 1883 deviceCreateInfo.pEnabledFeatures = NULL; 1884 deviceCreateInfo.enabledExtensionCount = (rendererData->supportsKHRSamplerYCbCrConversion) ? 5 : 1; 1885 deviceCreateInfo.ppEnabledExtensionNames = deviceExtensionNames; 1886 1887 deviceQueueCreateInfo[0].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; 1888 deviceQueueCreateInfo[0].queueFamilyIndex = rendererData->graphicsQueueFamilyIndex; 1889 deviceQueueCreateInfo[0].queueCount = 1; 1890 deviceQueueCreateInfo[0].pQueuePriorities = queuePriority; 1891 ++deviceCreateInfo.queueCreateInfoCount; 1892 1893 if (rendererData->presentQueueFamilyIndex != rendererData->graphicsQueueFamilyIndex) { 1894 deviceQueueCreateInfo[1].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; 1895 deviceQueueCreateInfo[1].queueFamilyIndex = rendererData->presentQueueFamilyIndex; 1896 deviceQueueCreateInfo[1].queueCount = 1; 1897 deviceQueueCreateInfo[1].pQueuePriorities = queuePriority; 1898 ++deviceCreateInfo.queueCreateInfoCount; 1899 } 1900 1901 if (rendererData->supportsKHRSamplerYCbCrConversion) { 1902 deviceSamplerYcbcrConversionFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES; 1903 deviceSamplerYcbcrConversionFeatures.samplerYcbcrConversion = VK_TRUE; 1904 deviceSamplerYcbcrConversionFeatures.pNext = (void *)deviceCreateInfo.pNext; 1905 deviceCreateInfo.pNext = &deviceSamplerYcbcrConversionFeatures; 1906 } 1907 1908 result = vkCreateDevice(rendererData->physicalDevice, &deviceCreateInfo, NULL, &rendererData->device); 1909 if (result != VK_SUCCESS) { 1910 SET_ERROR_CODE("vkCreateDevice()", result); 1911 VULKAN_DestroyAll(renderer); 1912 return result; 1913 } 1914 } 1915 1916 if (!VULKAN_LoadDeviceFunctions(rendererData)) { 1917 VULKAN_DestroyAll(renderer); 1918 return VK_ERROR_UNKNOWN; 1919 } 1920 1921 // Get graphics/present queues 1922 vkGetDeviceQueue(rendererData->device, rendererData->graphicsQueueFamilyIndex, 0, &rendererData->graphicsQueue); 1923 if (rendererData->graphicsQueueFamilyIndex != rendererData->presentQueueFamilyIndex) { 1924 vkGetDeviceQueue(rendererData->device, rendererData->presentQueueFamilyIndex, 0, &rendererData->presentQueue); 1925 } else { 1926 rendererData->presentQueue = rendererData->graphicsQueue; 1927 } 1928 1929 // Create command pool/command buffers 1930 VkCommandPoolCreateInfo commandPoolCreateInfo = { 0 }; 1931 commandPoolCreateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; 1932 commandPoolCreateInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; 1933 commandPoolCreateInfo.queueFamilyIndex = rendererData->graphicsQueueFamilyIndex; 1934 result = vkCreateCommandPool(rendererData->device, &commandPoolCreateInfo, NULL, &rendererData->commandPool); 1935 if (result != VK_SUCCESS) { 1936 VULKAN_DestroyAll(renderer); 1937 SET_ERROR_CODE("vkCreateCommandPool()", result); 1938 return result; 1939 } 1940 1941 if (VULKAN_GetSurfaceFormats(rendererData) != VK_SUCCESS) { 1942 VULKAN_DestroyAll(renderer); 1943 return result; 1944 } 1945 1946 // Create shaders / layouts 1947 for (uint32_t i = 0; i < NUM_SHADERS; i++) { 1948 VULKAN_Shader shader = (VULKAN_Shader)i; 1949 VkShaderModuleCreateInfo shaderModuleCreateInfo = { 0 }; 1950 shaderModuleCreateInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; 1951 VULKAN_GetVertexShader(shader, &shaderModuleCreateInfo.pCode, &shaderModuleCreateInfo.codeSize); 1952 result = vkCreateShaderModule(rendererData->device, &shaderModuleCreateInfo, NULL, &rendererData->vertexShaderModules[i]); 1953 if (result != VK_SUCCESS) { 1954 VULKAN_DestroyAll(renderer); 1955 SET_ERROR_CODE("vkCreateShaderModule()", result); 1956 return result; 1957 } 1958 VULKAN_GetPixelShader(shader, &shaderModuleCreateInfo.pCode, &shaderModuleCreateInfo.codeSize); 1959 result = vkCreateShaderModule(rendererData->device, &shaderModuleCreateInfo, NULL, &rendererData->fragmentShaderModules[i]); 1960 if (result != VK_SUCCESS) { 1961 VULKAN_DestroyAll(renderer); 1962 SET_ERROR_CODE("vkCreateShaderModule()", result); 1963 return result; 1964 } 1965 } 1966 1967 // Descriptor set layout / pipeline layout 1968 result = VULKAN_CreateDescriptorSetAndPipelineLayout(rendererData, VK_NULL_HANDLE, &rendererData->descriptorSetLayout, &rendererData->pipelineLayout); 1969 if (result != VK_SUCCESS) { 1970 VULKAN_DestroyAll(renderer); 1971 return result; 1972 } 1973 1974 // Create default vertex buffers 1975 for (uint32_t i = 0; i < SDL_VULKAN_NUM_VERTEX_BUFFERS; ++i) { 1976 VULKAN_CreateVertexBuffer(rendererData, i, SDL_VULKAN_VERTEX_BUFFER_DEFAULT_SIZE); 1977 } 1978 1979 SDL_PropertiesID props = SDL_GetRendererProperties(renderer); 1980 SDL_SetPointerProperty(props, SDL_PROP_RENDERER_VULKAN_INSTANCE_POINTER, rendererData->instance); 1981 SDL_SetNumberProperty(props, SDL_PROP_RENDERER_VULKAN_SURFACE_NUMBER, (Sint64)rendererData->surface); 1982 SDL_SetPointerProperty(props, SDL_PROP_RENDERER_VULKAN_PHYSICAL_DEVICE_POINTER, rendererData->physicalDevice); 1983 SDL_SetPointerProperty(props, SDL_PROP_RENDERER_VULKAN_DEVICE_POINTER, rendererData->device); 1984 SDL_SetNumberProperty(props, SDL_PROP_RENDERER_VULKAN_GRAPHICS_QUEUE_FAMILY_INDEX_NUMBER, rendererData->graphicsQueueFamilyIndex); 1985 SDL_SetNumberProperty(props, SDL_PROP_RENDERER_VULKAN_PRESENT_QUEUE_FAMILY_INDEX_NUMBER, rendererData->presentQueueFamilyIndex); 1986 1987 return VK_SUCCESS; 1988} 1989 1990static VkResult VULKAN_CreateFramebuffersAndRenderPasses(SDL_Renderer *renderer, int w, int h, 1991 VkFormat format, int imageViewCount, VkImageView *imageViews, VkFramebuffer *framebuffers, VkRenderPass renderPasses[VULKAN_RENDERPASS_COUNT]) 1992{ 1993 VULKAN_RenderData *rendererData = (VULKAN_RenderData *) renderer->internal; 1994 VkResult result; 1995 1996 VkAttachmentDescription attachmentDescription = { 0 }; 1997 attachmentDescription.format = format; 1998 attachmentDescription.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; 1999 attachmentDescription.storeOp = VK_ATTACHMENT_STORE_OP_STORE; 2000 attachmentDescription.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; 2001 attachmentDescription.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; 2002 attachmentDescription.initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; 2003 attachmentDescription.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; 2004 attachmentDescription.samples = VK_SAMPLE_COUNT_1_BIT; 2005 attachmentDescription.flags = 0; 2006 2007 VkAttachmentReference colorAttachmentReference = { 0 }; 2008 colorAttachmentReference.attachment = 0; 2009 colorAttachmentReference.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; 2010 2011 VkSubpassDescription subpassDescription = { 0 }; 2012 subpassDescription.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; 2013 subpassDescription.flags = 0; 2014 subpassDescription.inputAttachmentCount = 0; 2015 subpassDescription.pInputAttachments = NULL; 2016 subpassDescription.colorAttachmentCount = 1; 2017 subpassDescription.pColorAttachments = &colorAttachmentReference; 2018 subpassDescription.pResolveAttachments = NULL; 2019 subpassDescription.pDepthStencilAttachment = NULL; 2020 subpassDescription.preserveAttachmentCount = 0; 2021 subpassDescription.pPreserveAttachments = NULL; 2022 2023 VkSubpassDependency subPassDependency = { 0 }; 2024 subPassDependency.srcSubpass = VK_SUBPASS_EXTERNAL; 2025 subPassDependency.dstSubpass = 0; 2026 subPassDependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; 2027 subPassDependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; 2028 subPassDependency.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; 2029 subPassDependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT; 2030 subPassDependency.dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT; 2031 2032 VkRenderPassCreateInfo renderPassCreateInfo = { 0 }; 2033 renderPassCreateInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; 2034 renderPassCreateInfo.flags = 0; 2035 renderPassCreateInfo.attachmentCount = 1; 2036 renderPassCreateInfo.pAttachments = &attachmentDescription; 2037 renderPassCreateInfo.subpassCount = 1; 2038 renderPassCreateInfo.pSubpasses = &subpassDescription; 2039 renderPassCreateInfo.dependencyCount = 1; 2040 renderPassCreateInfo.pDependencies = &subPassDependency; 2041 2042 result = vkCreateRenderPass(rendererData->device, &renderPassCreateInfo, NULL, &renderPasses[VULKAN_RENDERPASS_LOAD]); 2043 if (result != VK_SUCCESS) { 2044 SET_ERROR_CODE("vkCreateRenderPass()", result); 2045 return result; 2046 } 2047 2048 attachmentDescription.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; 2049 result = vkCreateRenderPass(rendererData->device, &renderPassCreateInfo, NULL, &renderPasses[VULKAN_RENDERPASS_CLEAR]); 2050 if (result != VK_SUCCESS) { 2051 SET_ERROR_CODE("vkCreateRenderPass()", result); 2052 return result; 2053 } 2054 2055 VkFramebufferCreateInfo framebufferCreateInfo = { 0 }; 2056 framebufferCreateInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; 2057 framebufferCreateInfo.pNext = NULL; 2058 framebufferCreateInfo.renderPass = rendererData->renderPasses[VULKAN_RENDERPASS_LOAD]; 2059 framebufferCreateInfo.attachmentCount = 1; 2060 framebufferCreateInfo.width = w; 2061 framebufferCreateInfo.height = h; 2062 framebufferCreateInfo.layers = 1; 2063 2064 for (int i = 0; i < imageViewCount; i++) { 2065 framebufferCreateInfo.pAttachments = &imageViews[i]; 2066 result = vkCreateFramebuffer(rendererData->device, &framebufferCreateInfo, NULL, &framebuffers[i]); 2067 if (result != VK_SUCCESS) { 2068 SET_ERROR_CODE("vkCreateFramebuffer()", result); 2069 return result; 2070 } 2071 } 2072 2073 return result; 2074} 2075 2076static VkResult VULKAN_CreateSwapChain(SDL_Renderer *renderer, int w, int h) 2077{ 2078 VULKAN_RenderData *rendererData = (VULKAN_RenderData *)renderer->internal; 2079 VkResult result = vkGetPhysicalDeviceSurfaceCapabilitiesKHR(rendererData->physicalDevice, rendererData->surface, &rendererData->surfaceCapabilities); 2080 if (result != VK_SUCCESS) { 2081 SET_ERROR_CODE("vkGetPhysicalDeviceSurfaceCapabilitiesKHR()", result); 2082 return result; 2083 } 2084 2085 // clean up previous swapchain resources 2086 if (rendererData->swapchainImageViews) { 2087 for (uint32_t i = 0; i < rendererData->swapchainImageCount; i++) { 2088 vkDestroyImageView(rendererData->device, rendererData->swapchainImageViews[i], NULL); 2089 } 2090 SDL_free(rendererData->swapchainImageViews); 2091 rendererData->swapchainImageViews = NULL; 2092 } 2093 if (rendererData->fences) { 2094 for (uint32_t i = 0; i < rendererData->swapchainImageCount; i++) { 2095 if (rendererData->fences[i] != VK_NULL_HANDLE) { 2096 vkDestroyFence(rendererData->device, rendererData->fences[i], NULL); 2097 } 2098 } 2099 SDL_free(rendererData->fences); 2100 rendererData->fences = NULL; 2101 } 2102 if (rendererData->commandBuffers) { 2103 vkResetCommandPool(rendererData->device, rendererData->commandPool, 0); 2104 SDL_free(rendererData->commandBuffers); 2105 rendererData->commandBuffers = NULL; 2106 rendererData->currentCommandBuffer = VK_NULL_HANDLE; 2107 rendererData->currentCommandBufferIndex = 0; 2108 } 2109 if (rendererData->framebuffers) { 2110 for (uint32_t i = 0; i < rendererData->swapchainImageCount; i++) { 2111 if (rendererData->framebuffers[i] != VK_NULL_HANDLE) { 2112 vkDestroyFramebuffer(rendererData->device, rendererData->framebuffers[i], NULL); 2113 } 2114 } 2115 SDL_free(rendererData->framebuffers); 2116 rendererData->framebuffers = NULL; 2117 } 2118 if (rendererData->descriptorPools) { 2119 SDL_assert(rendererData->numDescriptorPools); 2120 for (uint32_t i = 0; i < rendererData->swapchainImageCount; i++) { 2121 for (uint32_t j = 0; j < rendererData->numDescriptorPools[i]; j++) { 2122 if (rendererData->descriptorPools[i][j] != VK_NULL_HANDLE) { 2123 vkDestroyDescriptorPool(rendererData->device, rendererData->descriptorPools[i][j], NULL); 2124 } 2125 } 2126 SDL_free(rendererData->descriptorPools[i]); 2127 } 2128 SDL_free(rendererData->descriptorPools); 2129 rendererData->descriptorPools = NULL; 2130 SDL_free(rendererData->numDescriptorPools); 2131 rendererData->numDescriptorPools = NULL; 2132 } 2133 if (rendererData->imageAvailableSemaphores) { 2134 for (uint32_t i = 0; i < rendererData->swapchainImageCount; ++i) { 2135 if (rendererData->imageAvailableSemaphores[i] != VK_NULL_HANDLE) { 2136 vkDestroySemaphore(rendererData->device, rendererData->imageAvailableSemaphores[i], NULL); 2137 } 2138 } 2139 SDL_free(rendererData->imageAvailableSemaphores); 2140 rendererData->imageAvailableSemaphores = NULL; 2141 } 2142 if (rendererData->renderingFinishedSemaphores) { 2143 for (uint32_t i = 0; i < rendererData->swapchainImageCount; ++i) { 2144 if (rendererData->renderingFinishedSemaphores[i] != VK_NULL_HANDLE) { 2145 vkDestroySemaphore(rendererData->device, rendererData->renderingFinishedSemaphores[i], NULL); 2146 } 2147 } 2148 SDL_free(rendererData->renderingFinishedSemaphores); 2149 rendererData->renderingFinishedSemaphores = NULL; 2150 } 2151 if (rendererData->uploadBuffers) { 2152 for (uint32_t i = 0; i < rendererData->swapchainImageCount; i++) { 2153 for (uint32_t j = 0; j < SDL_VULKAN_NUM_UPLOAD_BUFFERS; j++) { 2154 VULKAN_DestroyBuffer(rendererData, &rendererData->uploadBuffers[i][j]); 2155 } 2156 SDL_free(rendererData->uploadBuffers[i]); 2157 } 2158 SDL_free(rendererData->uploadBuffers); 2159 rendererData->uploadBuffers = NULL; 2160 } 2161 if (rendererData->constantBuffers) { 2162 SDL_assert(rendererData->numConstantBuffers); 2163 for (uint32_t i = 0; i < rendererData->swapchainImageCount; ++i) { 2164 for (uint32_t j = 0; j < rendererData->numConstantBuffers[i]; j++) { 2165 VULKAN_DestroyBuffer(rendererData, &rendererData->constantBuffers[i][j]); 2166 } 2167 SDL_free(rendererData->constantBuffers[i]); 2168 } 2169 SDL_free(rendererData->constantBuffers); 2170 rendererData->constantBuffers = NULL; 2171 SDL_free(rendererData->numConstantBuffers); 2172 rendererData->numConstantBuffers = NULL; 2173 } 2174 2175 // pick an image count 2176 rendererData->swapchainDesiredImageCount = rendererData->surfaceCapabilities.minImageCount + SDL_VULKAN_FRAME_QUEUE_DEPTH; 2177 if ((rendererData->swapchainDesiredImageCount > rendererData->surfaceCapabilities.maxImageCount) && 2178 (rendererData->surfaceCapabilities.maxImageCount > 0)) { 2179 rendererData->swapchainDesiredImageCount = rendererData->surfaceCapabilities.maxImageCount; 2180 } 2181 2182 VkFormat desiredFormat = VK_FORMAT_B8G8R8A8_UNORM; 2183 VkColorSpaceKHR desiredColorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR; 2184 if (renderer->output_colorspace == SDL_COLORSPACE_SRGB_LINEAR) { 2185 desiredFormat = VK_FORMAT_R16G16B16A16_SFLOAT; 2186 desiredColorSpace = VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT; 2187 } 2188 else if (renderer->output_colorspace == SDL_COLORSPACE_HDR10) { 2189 desiredFormat = VK_FORMAT_A2B10G10R10_UNORM_PACK32; 2190 desiredColorSpace = VK_COLOR_SPACE_HDR10_ST2084_EXT; 2191 } 2192 2193 if ((rendererData->surfaceFormatsCount == 1) && 2194 (rendererData->surfaceFormats[0].format == VK_FORMAT_UNDEFINED)) { 2195 // aren't any preferred formats, so we pick 2196 rendererData->surfaceFormat.colorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR; 2197 rendererData->surfaceFormat.format = desiredFormat; 2198 } else { 2199 rendererData->surfaceFormat = rendererData->surfaceFormats[0]; 2200 rendererData->surfaceFormat.colorSpace = rendererData->surfaceFormats[0].colorSpace; 2201 for (uint32_t i = 0; i < rendererData->surfaceFormatsCount; i++) { 2202 if (rendererData->surfaceFormats[i].format == desiredFormat && 2203 rendererData->surfaceFormats[i].colorSpace == desiredColorSpace) { 2204 rendererData->surfaceFormat.colorSpace = rendererData->surfaceFormats[i].colorSpace; 2205 rendererData->surfaceFormat = rendererData->surfaceFormats[i]; 2206 break; 2207 } 2208 } 2209 } 2210 2211 rendererData->swapchainSize.width = SDL_clamp((uint32_t)w, 2212 rendererData->surfaceCapabilities.minImageExtent.width, 2213 rendererData->surfaceCapabilities.maxImageExtent.width); 2214 2215 rendererData->swapchainSize.height = SDL_clamp((uint32_t)h, 2216 rendererData->surfaceCapabilities.minImageExtent.height, 2217 rendererData->surfaceCapabilities.maxImageExtent.height); 2218 2219 // Handle rotation 2220 rendererData->swapChainPreTransform = rendererData->surfaceCapabilities.currentTransform; 2221 if (rendererData->swapChainPreTransform == VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR || 2222 rendererData->swapChainPreTransform == VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR) { 2223 uint32_t tempWidth = rendererData->swapchainSize.width; 2224 rendererData->swapchainSize.width = rendererData->swapchainSize.height; 2225 rendererData->swapchainSize.height = tempWidth; 2226 } 2227 2228 if (rendererData->swapchainSize.width == 0 && rendererData->swapchainSize.height == 0) { 2229 // Don't recreate the swapchain if size is (0,0), just fail and continue attempting creation 2230 return VK_ERROR_OUT_OF_DATE_KHR; 2231 } 2232 2233 // Choose a present mode. If vsync is requested, then use VK_PRESENT_MODE_FIFO_KHR which is guaranteed to be supported 2234 VkPresentModeKHR presentMode = VK_PRESENT_MODE_FIFO_KHR; 2235 if (rendererData->vsync <= 0) { 2236 uint32_t presentModeCount = 0; 2237 result = vkGetPhysicalDeviceSurfacePresentModesKHR(rendererData->physicalDevice, rendererData->surface, &presentModeCount, NULL); 2238 if (result != VK_SUCCESS) { 2239 SET_ERROR_CODE("vkGetPhysicalDeviceSurfacePresentModesKHR()", result); 2240 return result; 2241 } 2242 if (presentModeCount > 0) { 2243 VkPresentModeKHR *presentModes = (VkPresentModeKHR *)SDL_calloc(presentModeCount, sizeof(VkPresentModeKHR)); 2244 result = vkGetPhysicalDeviceSurfacePresentModesKHR(rendererData->physicalDevice, rendererData->surface, &presentModeCount, presentModes); 2245 if (result != VK_SUCCESS) { 2246 SET_ERROR_CODE("vkGetPhysicalDeviceSurfacePresentModesKHR()", result); 2247 SDL_free(presentModes); 2248 return result; 2249 } 2250 2251 if (rendererData->vsync == 0) { 2252 /* If vsync is not requested, in favor these options in order: 2253 VK_PRESENT_MODE_IMMEDIATE_KHR - no v-sync with tearing 2254 VK_PRESENT_MODE_MAILBOX_KHR - no v-sync without tearing 2255 VK_PRESENT_MODE_FIFO_RELAXED_KHR - no v-sync, may tear */ 2256 for (uint32_t i = 0; i < presentModeCount; i++) { 2257 if (presentModes[i] == VK_PRESENT_MODE_IMMEDIATE_KHR) { 2258 presentMode = VK_PRESENT_MODE_IMMEDIATE_KHR; 2259 break; 2260 } 2261 else if (presentModes[i] == VK_PRESENT_MODE_MAILBOX_KHR) { 2262 presentMode = VK_PRESENT_MODE_MAILBOX_KHR; 2263 } 2264 else if ((presentMode != VK_PRESENT_MODE_MAILBOX_KHR) && 2265 (presentModes[i] == VK_PRESENT_MODE_FIFO_RELAXED_KHR)) { 2266 presentMode = VK_PRESENT_MODE_FIFO_RELAXED_KHR; 2267 } 2268 } 2269 } else if (rendererData->vsync == -1) { 2270 for (uint32_t i = 0; i < presentModeCount; i++) { 2271 if (presentModes[i] == VK_PRESENT_MODE_FIFO_RELAXED_KHR) { 2272 presentMode = VK_PRESENT_MODE_FIFO_RELAXED_KHR; 2273 break; 2274 } 2275 } 2276 } 2277 SDL_free(presentModes); 2278 } 2279 } 2280 2281 VkSwapchainCreateInfoKHR swapchainCreateInfo = { 0 }; 2282 swapchainCreateInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; 2283 swapchainCreateInfo.surface = rendererData->surface; 2284 swapchainCreateInfo.minImageCount = rendererData->swapchainDesiredImageCount; 2285 swapchainCreateInfo.imageFormat = rendererData->surfaceFormat.format; 2286 swapchainCreateInfo.imageColorSpace = rendererData->surfaceFormat.colorSpace; 2287 swapchainCreateInfo.imageExtent = rendererData->swapchainSize; 2288 swapchainCreateInfo.imageArrayLayers = 1; 2289 swapchainCreateInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT; 2290 swapchainCreateInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; 2291 swapchainCreateInfo.preTransform = rendererData->swapChainPreTransform; 2292 swapchainCreateInfo.compositeAlpha = (renderer->window->flags & SDL_WINDOW_TRANSPARENT) ? (VkCompositeAlphaFlagBitsKHR)0 : VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; 2293 swapchainCreateInfo.presentMode = presentMode; 2294 swapchainCreateInfo.clipped = VK_TRUE; 2295 swapchainCreateInfo.oldSwapchain = rendererData->swapchain; 2296 result = vkCreateSwapchainKHR(rendererData->device, &swapchainCreateInfo, NULL, &rendererData->swapchain); 2297 2298 if (swapchainCreateInfo.oldSwapchain != VK_NULL_HANDLE) { 2299 vkDestroySwapchainKHR(rendererData->device, swapchainCreateInfo.oldSwapchain, NULL); 2300 } 2301 2302 if (result != VK_SUCCESS) { 2303 rendererData->swapchain = VK_NULL_HANDLE; 2304 SET_ERROR_CODE("vkCreateSwapchainKHR()", result); 2305 return result; 2306 } 2307 2308 SDL_free(rendererData->swapchainImages); 2309 rendererData->swapchainImages = NULL; 2310 result = vkGetSwapchainImagesKHR(rendererData->device, rendererData->swapchain, &rendererData->swapchainImageCount, NULL); 2311 if (result != VK_SUCCESS) { 2312 rendererData->swapchainImageCount = 0; 2313 SET_ERROR_CODE("vkGetSwapchainImagesKHR()", result); 2314 return result; 2315 } 2316 2317 rendererData->swapchainImages = (VkImage *)SDL_malloc(sizeof(VkImage) * rendererData->swapchainImageCount); 2318 result = vkGetSwapchainImagesKHR(rendererData->device, 2319 rendererData->swapchain, 2320 &rendererData->swapchainImageCount, 2321 rendererData->swapchainImages); 2322 if (result != VK_SUCCESS) { 2323 SDL_free(rendererData->swapchainImages); 2324 rendererData->swapchainImages = NULL; 2325 rendererData->swapchainImageCount = 0; 2326 SET_ERROR_CODE("vkGetSwapchainImagesKHR()", result); 2327 return result; 2328 } 2329 2330 // Create VkImageView's for swapchain images 2331 { 2332 VkImageViewCreateInfo imageViewCreateInfo = { 0 }; 2333 imageViewCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; 2334 imageViewCreateInfo.flags = 0; 2335 imageViewCreateInfo.format = rendererData->surfaceFormat.format; 2336 imageViewCreateInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY; 2337 imageViewCreateInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY; 2338 imageViewCreateInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY; 2339 imageViewCreateInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY; 2340 imageViewCreateInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; 2341 imageViewCreateInfo.subresourceRange.baseArrayLayer = 0; 2342 imageViewCreateInfo.subresourceRange.baseMipLevel = 0; 2343 imageViewCreateInfo.subresourceRange.layerCount = 1; 2344 imageViewCreateInfo.subresourceRange.levelCount = 1; 2345 imageViewCreateInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; 2346 rendererData->swapchainImageViews = (VkImageView *)SDL_calloc(rendererData->swapchainImageCount, sizeof(VkImageView)); 2347 SDL_free(rendererData->swapchainImageLayouts); 2348 rendererData->swapchainImageLayouts = (VkImageLayout *)SDL_calloc(rendererData->swapchainImageCount, sizeof(VkImageLayout)); 2349 for (uint32_t i = 0; i < rendererData->swapchainImageCount; i++) { 2350 imageViewCreateInfo.image = rendererData->swapchainImages[i]; 2351 result = vkCreateImageView(rendererData->device, &imageViewCreateInfo, NULL, &rendererData->swapchainImageViews[i]); 2352 if (result != VK_SUCCESS) { 2353 VULKAN_DestroyAll(renderer); 2354 SET_ERROR_CODE("vkCreateImageView()", result); 2355 return result; 2356 } 2357 rendererData->swapchainImageLayouts[i] = VK_IMAGE_LAYOUT_UNDEFINED; 2358 } 2359 2360 } 2361 2362 VkCommandBufferAllocateInfo commandBufferAllocateInfo = { 0 }; 2363 commandBufferAllocateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; 2364 commandBufferAllocateInfo.commandPool = rendererData->commandPool; 2365 commandBufferAllocateInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; 2366 commandBufferAllocateInfo.commandBufferCount = rendererData->swapchainImageCount; 2367 rendererData->commandBuffers = (VkCommandBuffer *)SDL_calloc(rendererData->swapchainImageCount, sizeof(VkCommandBuffer)); 2368 result = vkAllocateCommandBuffers(rendererData->device, &commandBufferAllocateInfo, rendererData->commandBuffers); 2369 if (result != VK_SUCCESS) { 2370 VULKAN_DestroyAll(renderer); 2371 SET_ERROR_CODE("vkAllocateCommandBuffers()", result); 2372 return result; 2373 } 2374 2375 // Create fences 2376 rendererData->fences = (VkFence *)SDL_calloc(rendererData->swapchainImageCount, sizeof(VkFence)); 2377 for (uint32_t i = 0; i < rendererData->swapchainImageCount; i++) { 2378 VkFenceCreateInfo fenceCreateInfo = { 0 }; 2379 fenceCreateInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; 2380 fenceCreateInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT; 2381 result = vkCreateFence(rendererData->device, &fenceCreateInfo, NULL, &rendererData->fences[i]); 2382 if (result != VK_SUCCESS) { 2383 VULKAN_DestroyAll(renderer); 2384 SET_ERROR_CODE("vkCreateFence()", result); 2385 return result; 2386 } 2387 } 2388 2389 // Create renderpasses and framebuffer 2390 for (uint32_t i = 0; i < SDL_arraysize(rendererData->renderPasses); i++) { 2391 if (rendererData->renderPasses[i] != VK_NULL_HANDLE) { 2392 vkDestroyRenderPass(rendererData->device, rendererData->renderPasses[i], NULL); 2393 rendererData->renderPasses[i] = VK_NULL_HANDLE; 2394 } 2395 } 2396 rendererData->framebuffers = (VkFramebuffer *)SDL_calloc(rendererData->swapchainImageCount, sizeof(VkFramebuffer)); 2397 result = VULKAN_CreateFramebuffersAndRenderPasses(renderer, 2398 rendererData->swapchainSize.width, 2399 rendererData->swapchainSize.height, 2400 rendererData->surfaceFormat.format, 2401 rendererData->swapchainImageCount, 2402 rendererData->swapchainImageViews, 2403 rendererData->framebuffers, 2404 rendererData->renderPasses); 2405 if (result != VK_SUCCESS) { 2406 VULKAN_DestroyAll(renderer); 2407 SET_ERROR_CODE("VULKAN_CreateFramebuffersAndRenderPasses()", result); 2408 return result; 2409 } 2410 2411 // Create descriptor pools - start by allocating one per swapchain image, let it grow if more are needed 2412 rendererData->descriptorPools = (VkDescriptorPool **)SDL_calloc(rendererData->swapchainImageCount, sizeof(VkDescriptorPool *)); 2413 rendererData->numDescriptorPools = (uint32_t *)SDL_calloc(rendererData->swapchainImageCount, sizeof(uint32_t)); 2414 for (uint32_t i = 0; i < rendererData->swapchainImageCount; i++) { 2415 // Start by just allocating one pool, it will grow if needed 2416 rendererData->numDescriptorPools[i] = 1; 2417 rendererData->descriptorPools[i] = (VkDescriptorPool *)SDL_calloc(1, sizeof(VkDescriptorPool)); 2418 rendererData->descriptorPools[i][0] = VULKAN_AllocateDescriptorPool(rendererData); 2419 if (result != VK_SUCCESS) { 2420 VULKAN_DestroyAll(renderer); 2421 return result; 2422 } 2423 } 2424 2425 // Create semaphores 2426 rendererData->imageAvailableSemaphores = (VkSemaphore *)SDL_calloc(rendererData->swapchainImageCount, sizeof(VkSemaphore)); 2427 rendererData->renderingFinishedSemaphores = (VkSemaphore *)SDL_calloc(rendererData->swapchainImageCount, sizeof(VkSemaphore)); 2428 for (uint32_t i = 0; i < rendererData->swapchainImageCount; i++) { 2429 rendererData->imageAvailableSemaphores[i] = VULKAN_CreateSemaphore(rendererData); 2430 if (rendererData->imageAvailableSemaphores[i] == VK_NULL_HANDLE) { 2431 VULKAN_DestroyAll(renderer); 2432 return VK_ERROR_UNKNOWN; 2433 } 2434 rendererData->renderingFinishedSemaphores[i] = VULKAN_CreateSemaphore(rendererData); 2435 if (rendererData->renderingFinishedSemaphores[i] == VK_NULL_HANDLE) { 2436 VULKAN_DestroyAll(renderer); 2437 return VK_ERROR_UNKNOWN; 2438 } 2439 } 2440 2441 // Upload buffers 2442 rendererData->uploadBuffers = (VULKAN_Buffer **)SDL_calloc(rendererData->swapchainImageCount, sizeof(VULKAN_Buffer *)); 2443 for (uint32_t i = 0; i < rendererData->swapchainImageCount; i++) { 2444 rendererData->uploadBuffers[i] = (VULKAN_Buffer *)SDL_calloc(SDL_VULKAN_NUM_UPLOAD_BUFFERS, sizeof(VULKAN_Buffer)); 2445 } 2446 SDL_free(rendererData->currentUploadBuffer); 2447 rendererData->currentUploadBuffer = (int *)SDL_calloc(rendererData->swapchainImageCount, sizeof(int)); 2448 2449 // Constant buffers 2450 rendererData->constantBuffers = (VULKAN_Buffer **)SDL_calloc(rendererData->swapchainImageCount, sizeof(VULKAN_Buffer *)); 2451 rendererData->numConstantBuffers = (uint32_t *)SDL_calloc(rendererData->swapchainImageCount, sizeof(uint32_t)); 2452 for (uint32_t i = 0; i < rendererData->swapchainImageCount; i++) { 2453 // Start with just allocating one, will grow if needed 2454 rendererData->numConstantBuffers[i] = 1; 2455 rendererData->constantBuffers[i] = (VULKAN_Buffer *)SDL_calloc(1, sizeof(VULKAN_Buffer)); 2456 result = VULKAN_AllocateBuffer(rendererData, 2457 SDL_VULKAN_CONSTANT_BUFFER_DEFAULT_SIZE, 2458 VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, 2459 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | 2460 VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, 2461 VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, 2462 &rendererData->constantBuffers[i][0]); 2463 if (result != VK_SUCCESS) { 2464 VULKAN_DestroyAll(renderer); 2465 return result; 2466 } 2467 } 2468 rendererData->currentConstantBufferOffset = -1; 2469 rendererData->currentConstantBufferIndex = 0; 2470 2471 VULKAN_AcquireNextSwapchainImage(renderer); 2472 2473 SDL_PropertiesID props = SDL_GetRendererProperties(renderer); 2474 SDL_SetNumberProperty(props, SDL_PROP_RENDERER_VULKAN_SWAPCHAIN_IMAGE_COUNT_NUMBER, rendererData->swapchainImageCount); 2475 2476 return result; 2477} 2478 2479// Initialize all resources that change when the window's size changes. 2480static VkResult VULKAN_CreateWindowSizeDependentResources(SDL_Renderer *renderer) 2481{ 2482 VULKAN_RenderData *rendererData = (VULKAN_RenderData *)renderer->internal; 2483 VkResult result = VK_SUCCESS; 2484 int w, h; 2485 2486 // Release resources in the current command list 2487 VULKAN_IssueBatch(rendererData); 2488 VULKAN_WaitForGPU(rendererData); 2489 2490 /* The width and height of the swap chain must be based on the display's 2491 * non-rotated size. 2492 */ 2493 SDL_GetWindowSizeInPixels(renderer->window, &w, &h); 2494 2495 result = VULKAN_CreateSwapChain(renderer, w, h); 2496 if (result != VK_SUCCESS) { 2497 rendererData->recreateSwapchain = true; 2498 } 2499 2500 rendererData->viewportDirty = true; 2501 2502 return result; 2503} 2504 2505static bool VULKAN_HandleDeviceLost(SDL_Renderer *renderer) 2506{ 2507 VULKAN_RenderData *rendererData = (VULKAN_RenderData *)renderer->internal; 2508 bool recovered = false; 2509 2510 VULKAN_DestroyAll(renderer); 2511 2512 if (VULKAN_CreateDeviceResources(renderer, rendererData->create_props) == VK_SUCCESS && 2513 VULKAN_CreateWindowSizeDependentResources(renderer) == VK_SUCCESS) { 2514 recovered = true; 2515 } else { 2516 SDL_LogError(SDL_LOG_CATEGORY_RENDER, "Renderer couldn't recover from device lost: %s", SDL_GetError()); 2517 VULKAN_DestroyAll(renderer); 2518 } 2519 2520 // Let the application know that the device has been reset or lost 2521 SDL_Event event; 2522 SDL_zero(event); 2523 event.type = recovered ? SDL_EVENT_RENDER_DEVICE_RESET : SDL_EVENT_RENDER_DEVICE_LOST; 2524 event.render.windowID = SDL_GetWindowID(SDL_GetRenderWindow(renderer)); 2525 SDL_PushEvent(&event); 2526 2527 return recovered; 2528} 2529 2530// This method is called when the window's size changes. 2531static VkResult VULKAN_UpdateForWindowSizeChange(SDL_Renderer *renderer) 2532{ 2533 VULKAN_RenderData *rendererData = (VULKAN_RenderData *)renderer->internal; 2534 // If the GPU has previous work, wait for it to be done first 2535 VULKAN_WaitForGPU(rendererData); 2536 2537 return VULKAN_CreateWindowSizeDependentResources(renderer); 2538} 2539 2540static void VULKAN_WindowEvent(SDL_Renderer *renderer, const SDL_WindowEvent *event) 2541{ 2542 VULKAN_RenderData *rendererData = (VULKAN_RenderData *)renderer->internal; 2543 2544 if (event->type == SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED) { 2545 rendererData->recreateSwapchain = true; 2546 } 2547 2548#ifdef SDL_PLATFORM_ANDROID 2549 // Prevent black screen when app returns from background 2550 if (event->type == SDL_EVENT_WINDOW_RESTORED) { 2551 VULKAN_HandleDeviceLost(renderer); 2552 } 2553#endif 2554} 2555 2556static bool VULKAN_SupportsBlendMode(SDL_Renderer *renderer, SDL_BlendMode blendMode) 2557{ 2558 SDL_BlendFactor srcColorFactor = SDL_GetBlendModeSrcColorFactor(blendMode); 2559 SDL_BlendFactor srcAlphaFactor = SDL_GetBlendModeSrcAlphaFactor(blendMode); 2560 SDL_BlendOperation colorOperation = SDL_GetBlendModeColorOperation(blendMode); 2561 SDL_BlendFactor dstColorFactor = SDL_GetBlendModeDstColorFactor(blendMode); 2562 SDL_BlendFactor dstAlphaFactor = SDL_GetBlendModeDstAlphaFactor(blendMode); 2563 SDL_BlendOperation alphaOperation = SDL_GetBlendModeAlphaOperation(blendMode); 2564 2565 if (GetBlendFactor(srcColorFactor) == VK_BLEND_FACTOR_MAX_ENUM || 2566 GetBlendFactor(srcAlphaFactor) == VK_BLEND_FACTOR_MAX_ENUM || 2567 GetBlendOp(colorOperation) == VK_BLEND_OP_MAX_ENUM || 2568 GetBlendFactor(dstColorFactor) == VK_BLEND_FACTOR_MAX_ENUM || 2569 GetBlendFactor(dstAlphaFactor) == VK_BLEND_FACTOR_MAX_ENUM || 2570 GetBlendOp(alphaOperation) == VK_BLEND_OP_MAX_ENUM) { 2571 return false; 2572 } 2573 return true; 2574} 2575 2576static bool VULKAN_CreatePalette(SDL_Renderer *renderer, SDL_TexturePalette *palette) 2577{ 2578 VULKAN_RenderData *data = (VULKAN_RenderData *)renderer->internal; 2579 VULKAN_PaletteData *palettedata = (VULKAN_PaletteData *)SDL_calloc(1, sizeof(*palettedata)); 2580 if (!palettedata) { 2581 return false; 2582 } 2583 palette->internal = palettedata; 2584 2585 VkFormat format = SDLPixelFormatToVkTextureFormat(SDL_PIXELFORMAT_RGBA32, renderer->output_colorspace); 2586 VkImageUsageFlags usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT; 2587 VkComponentMapping imageViewSwizzle = data->identitySwizzle; 2588 VkResult result = VULKAN_AllocateImage(data, 0, 256, 1, format, usage, imageViewSwizzle, VK_NULL_HANDLE, &palettedata->image); 2589 if (result != VK_SUCCESS) { 2590 SET_ERROR_CODE("VULKAN_AllocateImage()", result); 2591 return false; 2592 } 2593 return true; 2594} 2595 2596static bool VULKAN_UpdatePalette(SDL_Renderer *renderer, SDL_TexturePalette *palette, int ncolors, SDL_Color *colors) 2597{ 2598 VULKAN_RenderData *data = (VULKAN_RenderData *)renderer->internal; 2599 VULKAN_PaletteData *palettedata = (VULKAN_PaletteData *)palette->internal; 2600 2601 return VULKAN_UpdateTextureInternal(data, palettedata->image.image, palettedata->image.format, 0, 0, 0, ncolors, 1, colors, ncolors * sizeof(*colors), &palettedata->image.imageLayout); 2602} 2603 2604static void VULKAN_DestroyPalette(SDL_Renderer *renderer, SDL_TexturePalette *palette) 2605{ 2606 VULKAN_RenderData *data = (VULKAN_RenderData *)renderer->internal; 2607 VULKAN_PaletteData *palettedata = (VULKAN_PaletteData *)palette->internal; 2608 2609 if (palettedata) { 2610 VULKAN_DestroyImage(data, &palettedata->image); 2611 SDL_free(palettedata); 2612 } 2613} 2614 2615static bool VULKAN_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SDL_PropertiesID create_props) 2616{ 2617 VULKAN_RenderData *rendererData = (VULKAN_RenderData *)renderer->internal; 2618 VULKAN_TextureData *textureData; 2619 VkResult result; 2620 VkFormat textureFormat = SDLPixelFormatToVkTextureFormat(texture->format, renderer->output_colorspace); 2621 uint32_t width = texture->w; 2622 uint32_t height = texture->h; 2623 VkComponentMapping imageViewSwizzle = rendererData->identitySwizzle; 2624 2625 if (!rendererData->device) { 2626 return SDL_SetError("Device lost and couldn't be recovered"); 2627 } 2628 2629 if (textureFormat == VK_FORMAT_UNDEFINED) { 2630 return SDL_SetError("%s, An unsupported SDL pixel format (0x%x) was specified", SDL_FUNCTION, texture->format); 2631 } 2632 2633 textureData = (VULKAN_TextureData *)SDL_calloc(1, sizeof(*textureData)); 2634 if (!textureData) { 2635 return false; 2636 } 2637 texture->internal = textureData; 2638 2639#ifdef SDL_HAVE_YUV 2640 // YUV textures must have even width and height. Also create Ycbcr conversion 2641 if (texture->format == SDL_PIXELFORMAT_YV12 || 2642 texture->format == SDL_PIXELFORMAT_IYUV || 2643 texture->format == SDL_PIXELFORMAT_NV12 || 2644 texture->format == SDL_PIXELFORMAT_NV21 || 2645 texture->format == SDL_PIXELFORMAT_P010) { 2646 const uint32_t YUV_SD_THRESHOLD = 576; 2647 2648 // Check that we have VK_KHR_sampler_ycbcr_conversion support 2649 if (!rendererData->supportsKHRSamplerYCbCrConversion) { 2650 return SDL_SetError("YUV textures require a Vulkan device that supports VK_KHR_sampler_ycbcr_conversion"); 2651 } 2652 2653 VkSamplerYcbcrConversionCreateInfoKHR samplerYcbcrConversionCreateInfo = { 0 }; 2654 samplerYcbcrConversionCreateInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO_KHR; 2655 2656 // Pad width/height to multiple of 2 2657 width = (width + 1) & ~1; 2658 height = (height + 1) & ~1; 2659 2660 // Create samplerYcbcrConversion which will be used on the VkImageView and VkSampler 2661 samplerYcbcrConversionCreateInfo.format = textureFormat; 2662 switch (SDL_COLORSPACEMATRIX(texture->colorspace)) { 2663 case SDL_MATRIX_COEFFICIENTS_BT470BG: 2664 case SDL_MATRIX_COEFFICIENTS_BT601: 2665 samplerYcbcrConversionCreateInfo.ycbcrModel = VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_601_KHR; 2666 break; 2667 case SDL_MATRIX_COEFFICIENTS_BT709: 2668 samplerYcbcrConversionCreateInfo.ycbcrModel = VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_709_KHR; 2669 break; 2670 case SDL_MATRIX_COEFFICIENTS_BT2020_NCL: 2671 samplerYcbcrConversionCreateInfo.ycbcrModel = VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_2020_KHR; 2672 break; 2673 case SDL_MATRIX_COEFFICIENTS_UNSPECIFIED: 2674 if (texture->format == SDL_PIXELFORMAT_P010) { 2675 samplerYcbcrConversionCreateInfo.ycbcrModel = VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_2020_KHR; 2676 } else if (height > YUV_SD_THRESHOLD) { 2677 samplerYcbcrConversionCreateInfo.ycbcrModel = VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_709_KHR; 2678 } else { 2679 samplerYcbcrConversionCreateInfo.ycbcrModel = VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_601_KHR; 2680 } 2681 break; 2682 default: 2683 return SDL_SetError("Unsupported Ycbcr colorspace: %d", SDL_COLORSPACEMATRIX(texture->colorspace)); 2684 } 2685 samplerYcbcrConversionCreateInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY; 2686 samplerYcbcrConversionCreateInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY; 2687 samplerYcbcrConversionCreateInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY; 2688 samplerYcbcrConversionCreateInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY; 2689 if (texture->format == SDL_PIXELFORMAT_YV12 || 2690 texture->format == SDL_PIXELFORMAT_NV21) { 2691 samplerYcbcrConversionCreateInfo.components.r = VK_COMPONENT_SWIZZLE_B; 2692 samplerYcbcrConversionCreateInfo.components.b = VK_COMPONENT_SWIZZLE_R; 2693 } 2694 2695 switch (SDL_COLORSPACERANGE(texture->colorspace)) { 2696 case SDL_COLOR_RANGE_LIMITED: 2697 samplerYcbcrConversionCreateInfo.ycbcrRange = VK_SAMPLER_YCBCR_RANGE_ITU_NARROW_KHR; 2698 break; 2699 case SDL_COLOR_RANGE_FULL: 2700 default: 2701 samplerYcbcrConversionCreateInfo.ycbcrRange = VK_SAMPLER_YCBCR_RANGE_ITU_FULL_KHR; 2702 break; 2703 } 2704 2705 switch (SDL_COLORSPACECHROMA(texture->colorspace)) { 2706 case SDL_CHROMA_LOCATION_LEFT: 2707 samplerYcbcrConversionCreateInfo.xChromaOffset = VK_CHROMA_LOCATION_COSITED_EVEN_KHR; 2708 samplerYcbcrConversionCreateInfo.yChromaOffset = VK_CHROMA_LOCATION_MIDPOINT_KHR; 2709 break; 2710 case SDL_CHROMA_LOCATION_TOPLEFT: 2711 samplerYcbcrConversionCreateInfo.xChromaOffset = VK_CHROMA_LOCATION_COSITED_EVEN_KHR; 2712 samplerYcbcrConversionCreateInfo.yChromaOffset = VK_CHROMA_LOCATION_COSITED_EVEN_KHR; 2713 break; 2714 case SDL_CHROMA_LOCATION_NONE: 2715 case SDL_CHROMA_LOCATION_CENTER: 2716 default: 2717 samplerYcbcrConversionCreateInfo.xChromaOffset = VK_CHROMA_LOCATION_MIDPOINT_KHR; 2718 samplerYcbcrConversionCreateInfo.yChromaOffset = VK_CHROMA_LOCATION_MIDPOINT_KHR; 2719 break; 2720 } 2721 samplerYcbcrConversionCreateInfo.chromaFilter = VK_FILTER_LINEAR; 2722 samplerYcbcrConversionCreateInfo.forceExplicitReconstruction = VK_FALSE; 2723 2724 result = vkCreateSamplerYcbcrConversionKHR(rendererData->device, &samplerYcbcrConversionCreateInfo, NULL, &textureData->samplerYcbcrConversion); 2725 if (result != VK_SUCCESS) { 2726 SET_ERROR_CODE("vkCreateSamplerYcbcrConversionKHR()", result); 2727 return false; 2728 } 2729 2730 // Also create VkSampler object which we will need to pass to the PSO as an immutable sampler 2731 VkSamplerCreateInfo samplerCreateInfo = { 0 }; 2732 samplerCreateInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; 2733 samplerCreateInfo.magFilter = VK_FILTER_NEAREST; 2734 samplerCreateInfo.minFilter = VK_FILTER_NEAREST; 2735 samplerCreateInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST; 2736 samplerCreateInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; 2737 samplerCreateInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; 2738 samplerCreateInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; 2739 samplerCreateInfo.mipLodBias = 0.0f; 2740 samplerCreateInfo.anisotropyEnable = VK_FALSE; 2741 samplerCreateInfo.maxAnisotropy = 1.0f; 2742 samplerCreateInfo.minLod = 0.0f; 2743 samplerCreateInfo.maxLod = 1000.0f; 2744 2745 VkSamplerYcbcrConversionInfoKHR samplerYcbcrConversionInfo = { 0 }; 2746 samplerYcbcrConversionInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO_KHR; 2747 samplerYcbcrConversionInfo.conversion = textureData->samplerYcbcrConversion; 2748 samplerCreateInfo.pNext = &samplerYcbcrConversionInfo; 2749 result = vkCreateSampler(rendererData->device, &samplerCreateInfo, NULL, &textureData->samplerYcbcr); 2750 if (result != VK_SUCCESS) { 2751 SET_ERROR_CODE("vkCreateSampler()", result); 2752 return false; 2753 } 2754 2755 // Allocate special descriptor set layout with samplerYcbcr baked as an immutable sampler 2756 result = VULKAN_CreateDescriptorSetAndPipelineLayout(rendererData, textureData->samplerYcbcr, &textureData->descriptorSetLayoutYcbcr, &textureData->pipelineLayoutYcbcr); 2757 if (result != VK_SUCCESS) { 2758 return false; 2759 } 2760 } 2761#endif 2762 textureData->width = width; 2763 textureData->height = height; 2764 2765 VkImageUsageFlags usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT; 2766 if (texture->access == SDL_TEXTUREACCESS_TARGET) { 2767 usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; 2768 } 2769 2770 result = VULKAN_AllocateImage(rendererData, create_props, width, height, textureFormat, usage, imageViewSwizzle, textureData->samplerYcbcrConversion, &textureData->mainImage); 2771 if (result != VK_SUCCESS) { 2772 SET_ERROR_CODE("VULKAN_AllocateImage()", result); 2773 return false; 2774 } 2775 2776 SDL_PropertiesID props = SDL_GetTextureProperties(texture); 2777 SDL_SetNumberProperty(props, SDL_PROP_TEXTURE_VULKAN_TEXTURE_NUMBER, (Sint64)textureData->mainImage.image); 2778 2779 if (texture->access == SDL_TEXTUREACCESS_TARGET) { 2780 result = VULKAN_CreateFramebuffersAndRenderPasses(renderer, 2781 texture->w, 2782 texture->h, 2783 textureFormat, 2784 1, 2785 &textureData->mainImage.imageView, 2786 &textureData->mainFramebuffer, 2787 textureData->mainRenderpasses); 2788 if (result != VK_SUCCESS) { 2789 SET_ERROR_CODE("VULKAN_CreateFramebuffersAndRenderPasses()", result); 2790 return false; 2791 } 2792 } 2793 return true; 2794} 2795 2796static void VULKAN_DestroyTexture(SDL_Renderer *renderer, 2797 SDL_Texture *texture) 2798{ 2799 VULKAN_RenderData *rendererData = (VULKAN_RenderData *)renderer->internal; 2800 VULKAN_TextureData *textureData = (VULKAN_TextureData *)texture->internal; 2801 2802 if (!textureData) { 2803 return; 2804 } 2805 2806 /* Because SDL_DestroyTexture might be called while the data is in-flight, we need to issue the batch first 2807 Unfortunately, this means that deleting a lot of textures mid-frame will have poor performance. */ 2808 VULKAN_IssueBatch(rendererData); 2809 VULKAN_WaitForGPU(rendererData); 2810 2811 VULKAN_DestroyImage(rendererData, &textureData->mainImage); 2812 2813#ifdef SDL_HAVE_YUV 2814 if (textureData->samplerYcbcrConversion != VK_NULL_HANDLE) { 2815 vkDestroySamplerYcbcrConversionKHR(rendererData->device, textureData->samplerYcbcrConversion, NULL); 2816 textureData->samplerYcbcrConversion = VK_NULL_HANDLE; 2817 } 2818 if (textureData->samplerYcbcr != VK_NULL_HANDLE) { 2819 vkDestroySampler(rendererData->device, textureData->samplerYcbcr, NULL); 2820 textureData->samplerYcbcr = VK_NULL_HANDLE; 2821 } 2822 if (textureData->pipelineLayoutYcbcr != VK_NULL_HANDLE) { 2823 vkDestroyPipelineLayout(rendererData->device, textureData->pipelineLayoutYcbcr, NULL); 2824 textureData->pipelineLayoutYcbcr = VK_NULL_HANDLE; 2825 } 2826 if (textureData->descriptorSetLayoutYcbcr != VK_NULL_HANDLE) { 2827 vkDestroyDescriptorSetLayout(rendererData->device, textureData->descriptorSetLayoutYcbcr, NULL); 2828 textureData->descriptorSetLayoutYcbcr = VK_NULL_HANDLE; 2829 } 2830#endif 2831 2832 VULKAN_DestroyBuffer(rendererData, &textureData->stagingBuffer); 2833 if (textureData->mainFramebuffer != VK_NULL_HANDLE) { 2834 vkDestroyFramebuffer(rendererData->device, textureData->mainFramebuffer, NULL); 2835 textureData->mainFramebuffer = VK_NULL_HANDLE; 2836 } 2837 for (uint32_t i = 0; i < SDL_arraysize(textureData->mainRenderpasses); i++) { 2838 if (textureData->mainRenderpasses[i] != VK_NULL_HANDLE) { 2839 vkDestroyRenderPass(rendererData->device, textureData->mainRenderpasses[i], NULL); 2840 textureData->mainRenderpasses[i] = VK_NULL_HANDLE; 2841 } 2842 } 2843 2844 SDL_free(textureData); 2845 texture->internal = NULL; 2846} 2847 2848static bool VULKAN_UpdateTextureInternal(VULKAN_RenderData *rendererData, VkImage image, VkFormat format, int plane, int x, int y, int w, int h, const void *pixels, int pitch, VkImageLayout *imageLayout) 2849{ 2850 VkDeviceSize pixelSize = VULKAN_GetBytesPerPixel(format, plane); 2851 VkDeviceSize length = w * pixelSize; 2852 VkDeviceSize uploadBufferSize = length * h; 2853 const Uint8 *src; 2854 Uint8 *dst; 2855 VkResult rc; 2856 int planeCount = VULKAN_VkFormatGetNumPlanes(format); 2857 2858 VULKAN_EnsureCommandBuffer(rendererData); 2859 2860 int currentUploadBufferIndex = rendererData->currentUploadBuffer[rendererData->currentCommandBufferIndex]; 2861 VULKAN_Buffer *uploadBuffer = &rendererData->uploadBuffers[rendererData->currentCommandBufferIndex][currentUploadBufferIndex]; 2862 2863 rc = VULKAN_AllocateBuffer(rendererData, uploadBufferSize, 2864 VK_BUFFER_USAGE_TRANSFER_SRC_BIT, 2865 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | 2866 VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, 2867 VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, 2868 uploadBuffer); 2869 if (rc != VK_SUCCESS) { 2870 return false; 2871 } 2872 2873 src = (const Uint8 *)pixels; 2874 dst = (Uint8 *)uploadBuffer->mappedBufferPtr; 2875 if (length == (VkDeviceSize)pitch) { 2876 SDL_memcpy(dst, src, (size_t)length * h); 2877 } else { 2878 if (length > (VkDeviceSize)pitch) { 2879 length = pitch; 2880 } 2881 for (VkDeviceSize row = h; row--; ) { 2882 SDL_memcpy(dst, src, (size_t)length); 2883 src += pitch; 2884 dst += length; 2885 } 2886 } 2887 2888 // Make sure the destination is in the correct resource state 2889 VULKAN_RecordPipelineImageBarrier(rendererData, 2890 VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_TRANSFER_WRITE_BIT, 2891 VK_ACCESS_TRANSFER_WRITE_BIT, 2892 VK_PIPELINE_STAGE_TRANSFER_BIT | VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 2893 VK_PIPELINE_STAGE_TRANSFER_BIT, 2894 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 2895 image, 2896 imageLayout); 2897 2898 VkBufferImageCopy region; 2899 region.bufferOffset = 0; 2900 region.bufferRowLength = 0; 2901 region.bufferImageHeight = 0; 2902 region.imageSubresource.baseArrayLayer = 0; 2903 region.imageSubresource.layerCount = 1; 2904 region.imageSubresource.mipLevel = 0; 2905 if (planeCount <= 1) { 2906 region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; 2907 } else { 2908 region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_PLANE_0_BIT << plane; 2909 } 2910 region.imageOffset.x = x; 2911 region.imageOffset.y = y; 2912 region.imageOffset.z = 0; 2913 region.imageExtent.width = w; 2914 region.imageExtent.height = h; 2915 region.imageExtent.depth = 1; 2916 2917 vkCmdCopyBufferToImage(rendererData->currentCommandBuffer, uploadBuffer->buffer, image, *imageLayout, 1, &region); 2918 2919 // Transition the texture to be shader accessible 2920 VULKAN_RecordPipelineImageBarrier(rendererData, 2921 VK_ACCESS_TRANSFER_WRITE_BIT, 2922 VK_ACCESS_SHADER_READ_BIT, 2923 VK_PIPELINE_STAGE_TRANSFER_BIT, 2924 VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 2925 VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, 2926 image, 2927 imageLayout); 2928 2929 rendererData->currentUploadBuffer[rendererData->currentCommandBufferIndex]++; 2930 2931 // If we've used up all the upload buffers, we need to issue the batch 2932 if (rendererData->currentUploadBuffer[rendererData->currentCommandBufferIndex] == SDL_VULKAN_NUM_UPLOAD_BUFFERS) { 2933 VULKAN_IssueBatch(rendererData); 2934 } 2935 2936 return true; 2937} 2938 2939#ifdef SDL_HAVE_YUV 2940static bool VULKAN_UpdateTextureNV(SDL_Renderer *renderer, SDL_Texture *texture, 2941 const SDL_Rect *rect, 2942 const Uint8 *Yplane, int Ypitch, 2943 const Uint8 *UVplane, int UVpitch); 2944 2945static bool VULKAN_UpdateTextureYUV(SDL_Renderer *renderer, SDL_Texture *texture, 2946 const SDL_Rect *rect, 2947 const Uint8 *Yplane, int Ypitch, 2948 const Uint8 *Uplane, int Upitch, 2949 const Uint8 *Vplane, int Vpitch); 2950#endif 2951 2952static bool VULKAN_UpdateTexture(SDL_Renderer *renderer, SDL_Texture *texture, 2953 const SDL_Rect *rect, const void *srcPixels, 2954 int srcPitch) 2955{ 2956 VULKAN_RenderData *rendererData = (VULKAN_RenderData *)renderer->internal; 2957 VULKAN_TextureData *textureData = (VULKAN_TextureData *)texture->internal; 2958 2959 if (!textureData) { 2960 return SDL_SetError("Texture is not currently available"); 2961 } 2962 2963#ifdef SDL_HAVE_YUV 2964 Uint32 numPlanes = VULKAN_VkFormatGetNumPlanes(textureData->mainImage.format); 2965 if (numPlanes == 2) { 2966 // NV12/NV21 data 2967 int UVbpp = (int)VULKAN_GetBytesPerPixel(textureData->mainImage.format, 1); 2968 int Ypitch = srcPitch; 2969 int UVpitch = (srcPitch + (UVbpp - 1)) & ~(UVbpp - 1); 2970 const Uint8 *plane0 = (const Uint8 *)srcPixels; 2971 const Uint8 *plane1 = plane0 + rect->h * srcPitch; 2972 2973 return VULKAN_UpdateTextureNV(renderer, texture, rect, plane0, Ypitch, plane1, UVpitch); 2974 2975 } else if (numPlanes == 3) { 2976 // YUV data 2977 int Ypitch = srcPitch; 2978 int UVpitch = ((Ypitch + 1) / 2); 2979 const Uint8 *plane0 = (const Uint8 *)srcPixels; 2980 const Uint8 *plane1 = plane0 + rect->h * Ypitch; 2981 const Uint8 *plane2 = plane1 + ((rect->h + 1) / 2) * UVpitch; 2982 2983 if (texture->format == SDL_PIXELFORMAT_YV12) { 2984 return VULKAN_UpdateTextureYUV(renderer, texture, rect, plane0, Ypitch, plane2, UVpitch, plane1, UVpitch); 2985 } else { 2986 return VULKAN_UpdateTextureYUV(renderer, texture, rect, plane0, Ypitch, plane1, UVpitch, plane2, UVpitch); 2987 } 2988 } 2989#endif 2990 if (!VULKAN_UpdateTextureInternal(rendererData, textureData->mainImage.image, textureData->mainImage.format, 0, rect->x, rect->y, rect->w, rect->h, srcPixels, srcPitch, &textureData->mainImage.imageLayout)) { 2991 return false; 2992 } 2993 return true; 2994} 2995 2996#ifdef SDL_HAVE_YUV 2997static bool VULKAN_UpdateTextureYUV(SDL_Renderer *renderer, SDL_Texture *texture, 2998 const SDL_Rect *rect, 2999 const Uint8 *Yplane, int Ypitch, 3000 const Uint8 *Uplane, int Upitch, 3001 const Uint8 *Vplane, int Vpitch) 3002{ 3003 VULKAN_RenderData *rendererData = (VULKAN_RenderData *)renderer->internal; 3004 VULKAN_TextureData *textureData = (VULKAN_TextureData *)texture->internal; 3005 3006 if (!textureData) { 3007 return SDL_SetError("Texture is not currently available"); 3008 } 3009 3010 if (!VULKAN_UpdateTextureInternal(rendererData, textureData->mainImage.image, textureData->mainImage.format, 0, rect->x, rect->y, rect->w, rect->h, Yplane, Ypitch, &textureData->mainImage.imageLayout)) { 3011 return false; 3012 } 3013 if (texture->format == SDL_PIXELFORMAT_YV12) { 3014 if (!VULKAN_UpdateTextureInternal(rendererData, textureData->mainImage.image, textureData->mainImage.format, 1, rect->x / 2, rect->y / 2, (rect->w + 1) / 2, (rect->h + 1) / 2, Vplane, Vpitch, &textureData->mainImage.imageLayout)) { 3015 return false; 3016 } 3017 if (!VULKAN_UpdateTextureInternal(rendererData, textureData->mainImage.image, textureData->mainImage.format, 2, rect->x / 2, rect->y / 2, (rect->w + 1) / 2, (rect->h + 1) / 2, Uplane, Upitch, &textureData->mainImage.imageLayout)) { 3018 return false; 3019 } 3020 } else { 3021 if (!VULKAN_UpdateTextureInternal(rendererData, textureData->mainImage.image, textureData->mainImage.format, 1, rect->x / 2, rect->y / 2, (rect->w + 1) / 2, (rect->h + 1) / 2, Uplane, Upitch, &textureData->mainImage.imageLayout)) { 3022 return false; 3023 } 3024 if (!VULKAN_UpdateTextureInternal(rendererData, textureData->mainImage.image, textureData->mainImage.format, 2, rect->x / 2, rect->y / 2, (rect->w + 1) / 2, (rect->h + 1) / 2, Vplane, Vpitch, &textureData->mainImage.imageLayout)) { 3025 return false; 3026 } 3027 } 3028 return true; 3029} 3030 3031static bool VULKAN_UpdateTextureNV(SDL_Renderer *renderer, SDL_Texture *texture, 3032 const SDL_Rect *rect, 3033 const Uint8 *Yplane, int Ypitch, 3034 const Uint8 *UVplane, int UVpitch) 3035{ 3036 VULKAN_RenderData *rendererData = (VULKAN_RenderData *)renderer->internal; 3037 VULKAN_TextureData *textureData = (VULKAN_TextureData *)texture->internal; 3038 3039 if (!textureData) { 3040 return SDL_SetError("Texture is not currently available"); 3041 } 3042 3043 if (!VULKAN_UpdateTextureInternal(rendererData, textureData->mainImage.image, textureData->mainImage.format, 0, rect->x, rect->y, rect->w, rect->h, Yplane, Ypitch, &textureData->mainImage.imageLayout)) { 3044 return false; 3045 } 3046 3047 if (!VULKAN_UpdateTextureInternal(rendererData, textureData->mainImage.image, textureData->mainImage.format, 1, rect->x / 2, rect->y / 2, (rect->w + 1) / 2, (rect->h + 1) / 2, UVplane, UVpitch, &textureData->mainImage.imageLayout)) { 3048 return false; 3049 } 3050 return true; 3051} 3052#endif 3053 3054static bool VULKAN_LockTexture(SDL_Renderer *renderer, SDL_Texture *texture, 3055 const SDL_Rect *rect, void **pixels, int *pitch) 3056{ 3057 VULKAN_RenderData *rendererData = (VULKAN_RenderData *)renderer->internal; 3058 VULKAN_TextureData *textureData = (VULKAN_TextureData *)texture->internal; 3059 VkResult rc; 3060 if (!textureData) { 3061 return SDL_SetError("Texture is not currently available"); 3062 } 3063 3064 if (textureData->stagingBuffer.buffer != VK_NULL_HANDLE) { 3065 return SDL_SetError("texture is already locked"); 3066 } 3067 3068 VkDeviceSize pixelSize = VULKAN_GetBytesPerPixel(textureData->mainImage.format, 0); 3069 VkDeviceSize length = rect->w * pixelSize; 3070 VkDeviceSize stagingBufferSize = length * rect->h; 3071 rc = VULKAN_AllocateBuffer(rendererData, 3072 stagingBufferSize, 3073 VK_BUFFER_USAGE_TRANSFER_SRC_BIT, 3074 VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | 3075 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, 3076 VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, 3077 &textureData->stagingBuffer); 3078 if (rc != VK_SUCCESS) { 3079 return false; 3080 } 3081 3082 /* Make note of where the staging texture will be written to 3083 * (on a call to SDL_UnlockTexture): 3084 */ 3085 textureData->lockedRect = *rect; 3086 3087 /* Make sure the caller has information on the texture's pixel buffer, 3088 * then return: 3089 */ 3090 *pixels = textureData->stagingBuffer.mappedBufferPtr; 3091 *pitch = (int)length; 3092 return true; 3093 3094} 3095 3096static void VULKAN_UnlockTexture(SDL_Renderer *renderer, SDL_Texture *texture) 3097{ 3098 VULKAN_RenderData *rendererData = (VULKAN_RenderData *)renderer->internal; 3099 VULKAN_TextureData *textureData = (VULKAN_TextureData *)texture->internal; 3100 3101 if (!textureData) { 3102 return; 3103 } 3104 3105 VULKAN_EnsureCommandBuffer(rendererData); 3106 3107 // Make sure the destination is in the correct resource state 3108 VULKAN_RecordPipelineImageBarrier(rendererData, 3109 VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_TRANSFER_WRITE_BIT, 3110 VK_ACCESS_TRANSFER_WRITE_BIT, 3111 VK_PIPELINE_STAGE_TRANSFER_BIT | VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 3112 VK_PIPELINE_STAGE_TRANSFER_BIT, 3113 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 3114 textureData->mainImage.image, 3115 &textureData->mainImage.imageLayout); 3116 3117 VkBufferImageCopy region; 3118 region.bufferOffset = 0; 3119 region.bufferRowLength = 0; 3120 region.bufferImageHeight = 0; 3121 region.imageSubresource.baseArrayLayer = 0; 3122 region.imageSubresource.layerCount = 1; 3123 region.imageSubresource.mipLevel = 0; 3124 region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; 3125 region.imageOffset.x = textureData->lockedRect.x; 3126 region.imageOffset.y = textureData->lockedRect.y; 3127 region.imageOffset.z = 0; 3128 region.imageExtent.width = textureData->lockedRect.w; 3129 region.imageExtent.height = textureData->lockedRect.h; 3130 region.imageExtent.depth = 1; 3131 vkCmdCopyBufferToImage(rendererData->currentCommandBuffer, textureData->stagingBuffer.buffer, textureData->mainImage.image, textureData->mainImage.imageLayout, 1, &region); 3132 3133 // Transition the texture to be shader accessible 3134 VULKAN_RecordPipelineImageBarrier(rendererData, 3135 VK_ACCESS_TRANSFER_WRITE_BIT, 3136 VK_ACCESS_SHADER_READ_BIT, 3137 VK_PIPELINE_STAGE_TRANSFER_BIT, 3138 VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 3139 VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, 3140 textureData->mainImage.image, 3141 &textureData->mainImage.imageLayout); 3142 3143 // Execute the command list before releasing the staging buffer 3144 VULKAN_IssueBatch(rendererData); 3145 3146 VULKAN_DestroyBuffer(rendererData, &textureData->stagingBuffer); 3147} 3148 3149static bool VULKAN_SetRenderTarget(SDL_Renderer *renderer, SDL_Texture *texture) 3150{ 3151 VULKAN_RenderData *rendererData = (VULKAN_RenderData *)renderer->internal; 3152 VULKAN_TextureData *textureData = NULL; 3153 3154 VULKAN_EnsureCommandBuffer(rendererData); 3155 3156 if (!texture) { 3157 if (rendererData->textureRenderTarget) { 3158 3159 VULKAN_RecordPipelineImageBarrier(rendererData, 3160 VK_ACCESS_TRANSFER_WRITE_BIT | VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, 3161 VK_ACCESS_SHADER_READ_BIT, 3162 VK_PIPELINE_STAGE_TRANSFER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 3163 VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 3164 VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, 3165 rendererData->textureRenderTarget->mainImage.image, 3166 &rendererData->textureRenderTarget->mainImage.imageLayout); 3167 } 3168 rendererData->textureRenderTarget = NULL; 3169 return true; 3170 } 3171 3172 textureData = (VULKAN_TextureData *)texture->internal; 3173 3174 if (textureData->mainImage.imageView == VK_NULL_HANDLE) { 3175 return SDL_SetError("specified texture is not a render target"); 3176 } 3177 3178 rendererData->textureRenderTarget = textureData; 3179 VULKAN_RecordPipelineImageBarrier(rendererData, 3180 VK_ACCESS_TRANSFER_WRITE_BIT | VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, 3181 VK_ACCESS_TRANSFER_WRITE_BIT | VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, 3182 VK_PIPELINE_STAGE_TRANSFER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 3183 VK_PIPELINE_STAGE_TRANSFER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 3184 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, 3185 rendererData->textureRenderTarget->mainImage.image, 3186 &rendererData->textureRenderTarget->mainImage.imageLayout); 3187 3188 return true; 3189} 3190 3191static bool VULKAN_QueueNoOp(SDL_Renderer *renderer, SDL_RenderCommand *cmd) 3192{ 3193 return true; // nothing to do in this backend. 3194} 3195 3196static bool VULKAN_QueueDrawPoints(SDL_Renderer *renderer, SDL_RenderCommand *cmd, const SDL_FPoint *points, int count) 3197{ 3198 VULKAN_VertexPositionColor *verts = (VULKAN_VertexPositionColor *)SDL_AllocateRenderVertices(renderer, count * sizeof(VULKAN_VertexPositionColor), 0, &cmd->data.draw.first); 3199 int i; 3200 SDL_FColor color = cmd->data.draw.color; 3201 bool convert_color = SDL_RenderingLinearSpace(renderer); 3202 3203 if (!verts) { 3204 return false; 3205 } 3206 3207 cmd->data.draw.count = count; 3208 3209 if (convert_color) { 3210 SDL_ConvertToLinear(&color); 3211 } 3212 3213 for (i = 0; i < count; i++) { 3214 verts->pos[0] = points[i].x + 0.5f; 3215 verts->pos[1] = points[i].y + 0.5f; 3216 verts->tex[0] = 0.0f; 3217 verts->tex[1] = 0.0f; 3218 verts->color = color; 3219 verts++; 3220 } 3221 return true; 3222} 3223 3224static bool VULKAN_QueueGeometry(SDL_Renderer *renderer, SDL_RenderCommand *cmd, SDL_Texture *texture, 3225 const float *xy, int xy_stride, const SDL_FColor *color, int color_stride, const float *uv, int uv_stride, 3226 int num_vertices, const void *indices, int num_indices, int size_indices, 3227 float scale_x, float scale_y) 3228{ 3229 int i; 3230 int count = indices ? num_indices : num_vertices; 3231 VULKAN_VertexPositionColor *verts = (VULKAN_VertexPositionColor *)SDL_AllocateRenderVertices(renderer, count * sizeof(VULKAN_VertexPositionColor), 0, &cmd->data.draw.first); 3232 bool convert_color = SDL_RenderingLinearSpace(renderer); 3233 VULKAN_TextureData *textureData = texture ? (VULKAN_TextureData *)texture->internal : NULL; 3234 float u_scale = textureData ? (float)texture->w / textureData->width : 0.0f; 3235 float v_scale = textureData ? (float)texture->h / textureData->height : 0.0f; 3236 3237 if (!verts) { 3238 return false; 3239 } 3240 3241 cmd->data.draw.count = count; 3242 size_indices = indices ? size_indices : 0; 3243 3244 for (i = 0; i < count; i++) { 3245 int j; 3246 float *xy_; 3247 if (size_indices == 4) { 3248 j = ((const Uint32 *)indices)[i]; 3249 } else if (size_indices == 2) { 3250 j = ((const Uint16 *)indices)[i]; 3251 } else if (size_indices == 1) { 3252 j = ((const Uint8 *)indices)[i]; 3253 } else { 3254 j = i; 3255 } 3256 3257 xy_ = (float *)((char *)xy + j * xy_stride); 3258 3259 verts->pos[0] = xy_[0] * scale_x; 3260 verts->pos[1] = xy_[1] * scale_y; 3261 verts->color = *(SDL_FColor *)((char *)color + j * color_stride); 3262 if (convert_color) { 3263 SDL_ConvertToLinear(&verts->color); 3264 } 3265 3266 if (texture) { 3267 float *uv_ = (float *)((char *)uv + j * uv_stride); 3268 verts->tex[0] = uv_[0] * u_scale; 3269 verts->tex[1] = uv_[1] * v_scale; 3270 } else { 3271 verts->tex[0] = 0.0f; 3272 verts->tex[1] = 0.0f; 3273 } 3274 3275 verts += 1; 3276 } 3277 return true; 3278} 3279 3280static bool VULKAN_UpdateVertexBuffer(SDL_Renderer *renderer, 3281 const void *vertexData, size_t dataSizeInBytes, VULKAN_DrawStateCache *stateCache) 3282{ 3283 VULKAN_RenderData *rendererData = (VULKAN_RenderData *)renderer->internal; 3284 const int vbidx = rendererData->currentVertexBuffer; 3285 VULKAN_Buffer *vertexBuffer; 3286 3287 if (dataSizeInBytes == 0) { 3288 return true; // nothing to do. 3289 } 3290 3291 if (rendererData->issueBatch) { 3292 if (VULKAN_IssueBatch(rendererData) != VK_SUCCESS) { 3293 return SDL_SetError("Failed to issue intermediate batch"); 3294 } 3295 } 3296 // If the existing vertex buffer isn't big enough, we need to recreate a big enough one 3297 if (dataSizeInBytes > rendererData->vertexBuffers[vbidx].size) { 3298 VULKAN_IssueBatch(rendererData); 3299 VULKAN_WaitForGPU(rendererData); 3300 VULKAN_CreateVertexBuffer(rendererData, vbidx, dataSizeInBytes); 3301 } 3302 3303 vertexBuffer = &rendererData->vertexBuffers[vbidx]; 3304 SDL_memcpy(vertexBuffer->mappedBufferPtr, vertexData, dataSizeInBytes); 3305 3306 stateCache->vertexBuffer = vertexBuffer->buffer; 3307 3308 rendererData->currentVertexBuffer = vbidx + 1; 3309 if (rendererData->currentVertexBuffer >= SDL_VULKAN_NUM_VERTEX_BUFFERS) { 3310 rendererData->currentVertexBuffer = 0; 3311 rendererData->issueBatch = true; 3312 } 3313 3314 return true; 3315} 3316 3317static VkSurfaceTransformFlagBitsKHR VULKAN_GetRotationForCurrentRenderTarget(VULKAN_RenderData *rendererData) 3318{ 3319 if (rendererData->textureRenderTarget) { 3320 return VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; 3321 } else { 3322 return rendererData->swapChainPreTransform; 3323 } 3324} 3325 3326static bool VULKAN_IsDisplayRotated90Degrees(VkSurfaceTransformFlagBitsKHR rotation) 3327{ 3328 switch (rotation) { 3329 case VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR: 3330 case VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR: 3331 return true; 3332 default: 3333 return false; 3334 } 3335} 3336 3337static bool VULKAN_UpdateViewport(SDL_Renderer *renderer) 3338{ 3339 VULKAN_RenderData *rendererData = (VULKAN_RenderData *)renderer->internal; 3340 const SDL_Rect *viewport = &rendererData->currentViewport; 3341 Float4X4 projection; 3342 Float4X4 view; 3343 VkSurfaceTransformFlagBitsKHR rotation = VULKAN_GetRotationForCurrentRenderTarget(rendererData); 3344 bool swapDimensions; 3345 3346 if (viewport->w == 0 || viewport->h == 0) { 3347 /* If the viewport is empty, assume that it is because 3348 * SDL_CreateRenderer is calling it, and will call it again later 3349 * with a non-empty viewport. 3350 */ 3351 // SDL_Log("%s, no viewport was set!", SDL_FUNCTION); 3352 return false; 3353 } 3354 3355 switch (rotation) { 3356 case VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR: 3357 projection = MatrixRotationZ(SDL_PI_F * 0.5f); 3358 break; 3359 case VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR: 3360 projection = MatrixRotationZ(SDL_PI_F); 3361 break; 3362 case VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR: 3363 projection = MatrixRotationZ(-SDL_PI_F * 0.5f); 3364 break; 3365 case VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR: 3366 default: 3367 projection = MatrixIdentity(); 3368 break; 3369 3370 } 3371 3372 // Update the view matrix 3373 SDL_zero(view); 3374 view.m[0][0] = 2.0f / viewport->w; 3375 view.m[1][1] = -2.0f / viewport->h; 3376 view.m[2][2] = 1.0f; 3377 view.m[3][0] = -1.0f; 3378 view.m[3][1] = 1.0f; 3379 view.m[3][3] = 1.0f; 3380 3381 rendererData->vertexShaderConstantsData.projectionAndView = MatrixMultiply( 3382 view, 3383 projection); 3384 3385 VkViewport vkViewport; 3386 3387 swapDimensions = VULKAN_IsDisplayRotated90Degrees(rotation); 3388 if (swapDimensions) { 3389 vkViewport.x = viewport->y; 3390 vkViewport.y = viewport->x; 3391 vkViewport.width = viewport->h; 3392 vkViewport.height = viewport->w; 3393 } 3394 else { 3395 vkViewport.x = viewport->x; 3396 vkViewport.y = viewport->y; 3397 vkViewport.width = viewport->w; 3398 vkViewport.height = viewport->h; 3399 } 3400 vkViewport.minDepth = 0.0f; 3401 vkViewport.maxDepth = 1.0f; 3402 vkCmdSetViewport(rendererData->currentCommandBuffer, 0, 1, &vkViewport); 3403 3404 rendererData->viewportDirty = false; 3405 return true; 3406} 3407 3408static bool VULKAN_UpdateClipRect(SDL_Renderer *renderer) 3409{ 3410 VULKAN_RenderData *rendererData = (VULKAN_RenderData *)renderer->internal; 3411 const SDL_Rect *viewport = &rendererData->currentViewport; 3412 VkSurfaceTransformFlagBitsKHR rotation = VULKAN_GetRotationForCurrentRenderTarget(rendererData); 3413 bool swapDimensions = VULKAN_IsDisplayRotated90Degrees(rotation); 3414 3415 VkRect2D scissor; 3416 if (rendererData->currentCliprectEnabled) { 3417 scissor.offset.x = viewport->x + rendererData->currentCliprect.x; 3418 scissor.offset.y = viewport->y + rendererData->currentCliprect.y; 3419 scissor.extent.width = rendererData->currentCliprect.w; 3420 scissor.extent.height = rendererData->currentCliprect.h; 3421 } else { 3422 scissor.offset.x = viewport->x; 3423 scissor.offset.y = viewport->y; 3424 scissor.extent.width = viewport->w; 3425 scissor.extent.height = viewport->h; 3426 } 3427 if (swapDimensions) { 3428 VkRect2D scissorTemp = scissor; 3429 scissor.offset.x = scissorTemp.offset.y; 3430 scissor.offset.y = scissorTemp.offset.x; 3431 scissor.extent.width = scissorTemp.extent.height; 3432 scissor.extent.height = scissorTemp.extent.width; 3433 } 3434 vkCmdSetScissor(rendererData->currentCommandBuffer, 0, 1, &scissor); 3435 3436 rendererData->cliprectDirty = false; 3437 return true; 3438} 3439 3440static void VULKAN_SetupShaderConstants(SDL_Renderer *renderer, const SDL_RenderCommand *cmd, const SDL_Texture *texture, VULKAN_PixelShaderConstants *constants) 3441{ 3442 float output_headroom; 3443 3444 SDL_zerop(constants); 3445 3446 constants->scRGB_output = (float)SDL_RenderingLinearSpace(renderer); 3447 constants->color_scale = cmd->data.draw.color_scale; 3448 3449 if (texture) { 3450 switch (texture->format) { 3451 case SDL_PIXELFORMAT_YV12: 3452 case SDL_PIXELFORMAT_IYUV: 3453 case SDL_PIXELFORMAT_NV12: 3454 case SDL_PIXELFORMAT_NV21: 3455 constants->input_type = INPUTTYPE_SRGB; 3456 break; 3457 case SDL_PIXELFORMAT_P010: 3458 constants->input_type = INPUTTYPE_HDR10; 3459 break; 3460 default: 3461 if (texture->colorspace == SDL_COLORSPACE_SRGB_LINEAR) { 3462 constants->input_type = INPUTTYPE_SCRGB; 3463 } else if (SDL_COLORSPACEPRIMARIES(texture->colorspace) == SDL_COLOR_PRIMARIES_BT2020 && 3464 SDL_COLORSPACETRANSFER(texture->colorspace) == SDL_TRANSFER_CHARACTERISTICS_PQ) { 3465 constants->input_type = INPUTTYPE_HDR10; 3466 } else { 3467 // The sampler will convert from sRGB to linear on load if working in linear colorspace 3468 constants->input_type = INPUTTYPE_UNSPECIFIED; 3469 } 3470 break; 3471 } 3472 3473 if (texture->format == SDL_PIXELFORMAT_INDEX8) { 3474 switch (cmd->data.draw.texture_scale_mode) { 3475 case SDL_SCALEMODE_NEAREST: 3476 constants->texture_type = TEXTURETYPE_PALETTE_NEAREST; 3477 break; 3478 case SDL_SCALEMODE_LINEAR: 3479 constants->texture_type = TEXTURETYPE_PALETTE_LINEAR; 3480 break; 3481 case SDL_SCALEMODE_PIXELART: 3482 constants->texture_type = TEXTURETYPE_PALETTE_PIXELART; 3483 break; 3484 default: 3485 SDL_assert(!"Unknown scale mode"); 3486 break; 3487 } 3488 } else { 3489 if (cmd->data.draw.texture_scale_mode == SDL_SCALEMODE_PIXELART) { 3490 constants->texture_type = TEXTURETYPE_RGB_PIXELART; 3491 } else { 3492 constants->texture_type = TEXTURETYPE_RGB; 3493 } 3494 } 3495 3496 if (constants->texture_type == TEXTURETYPE_PALETTE_LINEAR || 3497 constants->texture_type == TEXTURETYPE_PALETTE_PIXELART || 3498 constants->texture_type == TEXTURETYPE_RGB_PIXELART) { 3499 constants->texture_width = texture->w; 3500 constants->texture_height = texture->h; 3501 constants->texel_width = 1.0f / constants->texture_width; 3502 constants->texel_height = 1.0f / constants->texture_height; 3503 } 3504 3505 constants->sdr_white_point = texture->SDR_white_point; 3506 3507 if (renderer->target) { 3508 output_headroom = renderer->target->HDR_headroom; 3509 } else { 3510 output_headroom = renderer->HDR_headroom; 3511 } 3512 3513 if (texture->HDR_headroom > output_headroom && output_headroom > 0.0f) { 3514 constants->tonemap_method = TONEMAP_CHROME; 3515 constants->tonemap_factor1 = (output_headroom / (texture->HDR_headroom * texture->HDR_headroom)); 3516 constants->tonemap_factor2 = (1.0f / output_headroom); 3517 } 3518 } 3519} 3520 3521static VULKAN_Shader SelectShader(const VULKAN_PixelShaderConstants *shader_constants) 3522{ 3523 if (!shader_constants) { 3524 return SHADER_SOLID; 3525 } 3526 3527 if (shader_constants->texture_type == TEXTURETYPE_RGB && 3528 shader_constants->input_type == INPUTTYPE_UNSPECIFIED && 3529 shader_constants->tonemap_method == TONEMAP_NONE) { 3530 return SHADER_RGB; 3531 } 3532 3533 return SHADER_ADVANCED; 3534} 3535 3536static VkDescriptorPool VULKAN_AllocateDescriptorPool(VULKAN_RenderData *rendererData) 3537{ 3538 VkDescriptorPool descriptorPool = VK_NULL_HANDLE; 3539 VkDescriptorPoolSize descriptorPoolSizes[3]; 3540 VkResult result; 3541 descriptorPoolSizes[0].descriptorCount = SDL_VULKAN_MAX_DESCRIPTOR_SETS; 3542 descriptorPoolSizes[0].type = VK_DESCRIPTOR_TYPE_SAMPLER; 3543 3544 descriptorPoolSizes[1].descriptorCount = SDL_VULKAN_MAX_DESCRIPTOR_SETS; 3545 descriptorPoolSizes[1].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; 3546 3547 descriptorPoolSizes[2].descriptorCount = SDL_VULKAN_MAX_DESCRIPTOR_SETS; 3548 descriptorPoolSizes[2].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; 3549 3550 VkDescriptorPoolCreateInfo descriptorPoolCreateInfo = { 0 }; 3551 descriptorPoolCreateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; 3552 descriptorPoolCreateInfo.poolSizeCount = SDL_arraysize(descriptorPoolSizes); 3553 descriptorPoolCreateInfo.pPoolSizes = descriptorPoolSizes; 3554 descriptorPoolCreateInfo.maxSets = SDL_VULKAN_MAX_DESCRIPTOR_SETS; 3555 result = vkCreateDescriptorPool(rendererData->device, &descriptorPoolCreateInfo, NULL, &descriptorPool); 3556 if (result != VK_SUCCESS) { 3557 SET_ERROR_CODE("vkCreateDescrptorPool()", result); 3558 return VK_NULL_HANDLE; 3559 } 3560 3561 return descriptorPool; 3562} 3563 3564static VkResult VULKAN_CreateDescriptorSetAndPipelineLayout(VULKAN_RenderData *rendererData, VkSampler samplerYcbcr, VkDescriptorSetLayout *descriptorSetLayoutOut, 3565 VkPipelineLayout *pipelineLayoutOut) 3566{ 3567 VkResult result; 3568 3569 // Descriptor set layout 3570 VkDescriptorSetLayoutCreateInfo descriptorSetLayoutCreateInfo = { 0 }; 3571 descriptorSetLayoutCreateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; 3572 descriptorSetLayoutCreateInfo.flags = 0; 3573 VkDescriptorSetLayoutBinding layoutBindings[3]; 3574 // PixelShaderConstants 3575 layoutBindings[0].binding = 0; 3576 layoutBindings[0].descriptorCount = 1; 3577 layoutBindings[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; 3578 layoutBindings[0].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; 3579 layoutBindings[0].pImmutableSamplers = NULL; 3580 3581 // Combined image/sampler 3582 layoutBindings[1].binding = 1; 3583 layoutBindings[1].descriptorCount = 1; 3584 layoutBindings[1].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; 3585 layoutBindings[1].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; 3586 layoutBindings[1].pImmutableSamplers = (samplerYcbcr != VK_NULL_HANDLE) ? &samplerYcbcr : NULL; 3587 3588 // Combined image/sampler 3589 layoutBindings[2].binding = 2; 3590 layoutBindings[2].descriptorCount = 1; 3591 layoutBindings[2].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; 3592 layoutBindings[2].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; 3593 layoutBindings[2].pImmutableSamplers = (samplerYcbcr != VK_NULL_HANDLE) ? &samplerYcbcr : NULL; 3594 3595 descriptorSetLayoutCreateInfo.bindingCount = 3; 3596 descriptorSetLayoutCreateInfo.pBindings = layoutBindings; 3597 result = vkCreateDescriptorSetLayout(rendererData->device, &descriptorSetLayoutCreateInfo, NULL, descriptorSetLayoutOut); 3598 if (result != VK_SUCCESS) { 3599 SET_ERROR_CODE("vkCreateDescriptorSetLayout()", result); 3600 return result; 3601 } 3602 3603 // Pipeline layout 3604 VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo = { 0 }; 3605 VkPushConstantRange pushConstantRange; 3606 pushConstantRange.size = sizeof( VULKAN_VertexShaderConstants ); 3607 pushConstantRange.offset = 0; 3608 pushConstantRange.stageFlags = VK_SHADER_STAGE_VERTEX_BIT; 3609 pipelineLayoutCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; 3610 pipelineLayoutCreateInfo.setLayoutCount = 1; 3611 pipelineLayoutCreateInfo.pSetLayouts = descriptorSetLayoutOut; 3612 pipelineLayoutCreateInfo.pushConstantRangeCount = 1; 3613 pipelineLayoutCreateInfo.pPushConstantRanges = &pushConstantRange; 3614 result = vkCreatePipelineLayout(rendererData->device, &pipelineLayoutCreateInfo, NULL, pipelineLayoutOut); 3615 if (result != VK_SUCCESS) { 3616 SET_ERROR_CODE("vkCreatePipelineLayout()", result); 3617 return result; 3618 } 3619 3620 return result; 3621} 3622 3623static VkDescriptorSet VULKAN_AllocateDescriptorSet(SDL_Renderer *renderer, VULKAN_Shader shader, VkDescriptorSetLayout descriptorSetLayout, 3624 VkBuffer constantBuffer, VkDeviceSize constantBufferOffset, int numImages, VkImageView *imageViews, int numSamplers, VkSampler *samplers) 3625{ 3626 VULKAN_RenderData *rendererData = (VULKAN_RenderData *)renderer->internal; 3627 uint32_t currentDescriptorPoolIndex = rendererData->currentDescriptorPoolIndex; 3628 VkDescriptorPool descriptorPool = rendererData->descriptorPools[rendererData->currentCommandBufferIndex][currentDescriptorPoolIndex]; 3629 3630 VkDescriptorSetAllocateInfo descriptorSetAllocateInfo = { 0 }; 3631 descriptorSetAllocateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; 3632 descriptorSetAllocateInfo.descriptorSetCount = 1; 3633 descriptorSetAllocateInfo.descriptorPool = descriptorPool; 3634 descriptorSetAllocateInfo.pSetLayouts = &descriptorSetLayout; 3635 3636 VkDescriptorSet descriptorSet = VK_NULL_HANDLE; 3637 VkResult result = (rendererData->currentDescriptorSetIndex >= SDL_VULKAN_MAX_DESCRIPTOR_SETS) ? VK_ERROR_OUT_OF_DEVICE_MEMORY : VK_SUCCESS; 3638 if (result == VK_SUCCESS) { 3639 result = vkAllocateDescriptorSets(rendererData->device, &descriptorSetAllocateInfo, &descriptorSet); 3640 } 3641 if (result != VK_SUCCESS) { 3642 // Out of descriptor sets in this pool - see if we have more pools allocated 3643 currentDescriptorPoolIndex++; 3644 if (currentDescriptorPoolIndex < rendererData->numDescriptorPools[rendererData->currentCommandBufferIndex]) { 3645 descriptorPool = rendererData->descriptorPools[rendererData->currentCommandBufferIndex][currentDescriptorPoolIndex]; 3646 descriptorSetAllocateInfo.descriptorPool = descriptorPool; 3647 result = vkAllocateDescriptorSets(rendererData->device, &descriptorSetAllocateInfo, &descriptorSet); 3648 if (result != VK_SUCCESS) { 3649 // This should not fail - we are allocating from the front of the descriptor set 3650 SDL_SetError("Unable to allocate descriptor set"); 3651 return VK_NULL_HANDLE; 3652 } 3653 rendererData->currentDescriptorPoolIndex = currentDescriptorPoolIndex; 3654 rendererData->currentDescriptorSetIndex = 0; 3655 3656 } 3657 // We are out of pools, create a new one 3658 else { 3659 descriptorPool = VULKAN_AllocateDescriptorPool(rendererData); 3660 if (descriptorPool == VK_NULL_HANDLE) { 3661 // SDL_SetError called in VULKAN_AllocateDescriptorPool if we failed to allocate a new pool 3662 return VK_NULL_HANDLE; 3663 } 3664 rendererData->numDescriptorPools[rendererData->currentCommandBufferIndex]++; 3665 VkDescriptorPool *descriptorPools = (VkDescriptorPool *)SDL_realloc(rendererData->descriptorPools[rendererData->currentCommandBufferIndex], 3666 sizeof(VkDescriptorPool) * rendererData->numDescriptorPools[rendererData->currentCommandBufferIndex]); 3667 descriptorPools[rendererData->numDescriptorPools[rendererData->currentCommandBufferIndex] - 1] = descriptorPool; 3668 rendererData->descriptorPools[rendererData->currentCommandBufferIndex] = descriptorPools; 3669 rendererData->currentDescriptorPoolIndex = currentDescriptorPoolIndex; 3670 rendererData->currentDescriptorSetIndex = 0; 3671 3672 // Call recursively to allocate from the new pool 3673 return VULKAN_AllocateDescriptorSet(renderer, shader, descriptorSetLayout, constantBuffer, constantBufferOffset, numImages, imageViews, numSamplers, samplers); 3674 } 3675 } 3676 rendererData->currentDescriptorSetIndex++; 3677 VkDescriptorImageInfo combinedImageSamplerDescriptor[2]; 3678 VkDescriptorBufferInfo bufferDescriptor = { 0 }; 3679 bufferDescriptor.buffer = constantBuffer; 3680 bufferDescriptor.offset = constantBufferOffset; 3681 bufferDescriptor.range = sizeof(VULKAN_PixelShaderConstants); 3682 3683 VkWriteDescriptorSet descriptorWrites[3]; 3684 SDL_zero(descriptorWrites); 3685 uint32_t descriptorCount = 1; // Always have the uniform buffer 3686 3687 descriptorWrites[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; 3688 descriptorWrites[0].dstSet = descriptorSet; 3689 descriptorWrites[0].dstBinding = 0; 3690 descriptorWrites[0].dstArrayElement = 0; 3691 descriptorWrites[0].descriptorCount = 1; 3692 descriptorWrites[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; 3693 descriptorWrites[0].pBufferInfo = &bufferDescriptor; 3694 3695 SDL_assert(numSamplers == numImages); 3696 for (int i = 0; i < numImages; ++i) { 3697 SDL_assert(i < SDL_arraysize(combinedImageSamplerDescriptor)); 3698 VkDescriptorImageInfo *pImageInfo = &combinedImageSamplerDescriptor[i]; 3699 SDL_zerop(pImageInfo); 3700 if (descriptorSetLayout == rendererData->descriptorSetLayout) { 3701 pImageInfo->sampler = samplers[i]; 3702 } else { 3703 // Ignore the sampler if we're using YcBcCr data since it will be baked in the descriptor set layout 3704 } 3705 pImageInfo->imageView = imageViews[i]; 3706 pImageInfo->imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; 3707 3708 SDL_assert(descriptorCount < SDL_arraysize(descriptorWrites)); 3709 VkWriteDescriptorSet *pDescriptorSet = &descriptorWrites[descriptorCount++]; 3710 pDescriptorSet->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; 3711 pDescriptorSet->dstSet = descriptorSet; 3712 pDescriptorSet->dstBinding = 1 + i; 3713 pDescriptorSet->dstArrayElement = 0; 3714 pDescriptorSet->descriptorCount = 1; 3715 pDescriptorSet->descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; 3716 pDescriptorSet->pImageInfo = pImageInfo; 3717 } 3718 3719 vkUpdateDescriptorSets(rendererData->device, descriptorCount, descriptorWrites, 0, NULL); 3720 3721 return descriptorSet; 3722} 3723 3724static bool VULKAN_SetDrawState(SDL_Renderer *renderer, const SDL_RenderCommand *cmd, VkPipelineLayout pipelineLayout, VkDescriptorSetLayout descriptorSetLayout, 3725 const VULKAN_PixelShaderConstants *shader_constants, VkPrimitiveTopology topology, int numImages, VkImageView *imageViews, int numSamplers, VkSampler *samplers, const Float4X4 *matrix, VULKAN_DrawStateCache *stateCache) 3726 3727{ 3728 VULKAN_RenderData *rendererData = (VULKAN_RenderData *)renderer->internal; 3729 const SDL_BlendMode blendMode = cmd->data.draw.blend; 3730 VkFormat format = rendererData->surfaceFormat.format; 3731 const Float4X4 *newmatrix = matrix ? matrix : &rendererData->identity; 3732 bool updateConstants = false; 3733 VULKAN_Shader shader = SelectShader(shader_constants); 3734 VULKAN_PixelShaderConstants solid_constants; 3735 VkDescriptorSet descriptorSet; 3736 VkBuffer constantBuffer; 3737 VkDeviceSize constantBufferOffset; 3738 int i; 3739 3740 if (!VULKAN_ActivateCommandBuffer(renderer, VK_ATTACHMENT_LOAD_OP_LOAD, NULL, stateCache)) { 3741 return false; 3742 } 3743 3744 // See if we need to change the pipeline state 3745 if (!rendererData->currentPipelineState || 3746 rendererData->currentPipelineState->shader != shader || 3747 rendererData->currentPipelineState->blendMode != blendMode || 3748 rendererData->currentPipelineState->topology != topology || 3749 rendererData->currentPipelineState->format != format || 3750 rendererData->currentPipelineState->pipelineLayout != pipelineLayout || 3751 rendererData->currentPipelineState->descriptorSetLayout != descriptorSetLayout) { 3752 3753 rendererData->currentPipelineState = NULL; 3754 for (i = 0; i < rendererData->pipelineStateCount; ++i) { 3755 VULKAN_PipelineState *candidatePiplineState = &rendererData->pipelineStates[i]; 3756 if (candidatePiplineState->shader == shader && 3757 candidatePiplineState->blendMode == blendMode && 3758 candidatePiplineState->topology == topology && 3759 candidatePiplineState->format == format && 3760 candidatePiplineState->pipelineLayout == pipelineLayout && 3761 candidatePiplineState->descriptorSetLayout == descriptorSetLayout) { 3762 rendererData->currentPipelineState = candidatePiplineState; 3763 break; 3764 } 3765 } 3766 3767 // If we didn't find a match, create a new one -- it must mean the blend mode is non-standard 3768 if (!rendererData->currentPipelineState) { 3769 rendererData->currentPipelineState = VULKAN_CreatePipelineState(renderer, shader, pipelineLayout, descriptorSetLayout, blendMode, topology, format); 3770 } 3771 3772 if (!rendererData->currentPipelineState) { 3773 return SDL_SetError("Unable to create required pipeline state"); 3774 } 3775 3776 vkCmdBindPipeline(rendererData->currentCommandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, rendererData->currentPipelineState->pipeline); 3777 updateConstants = true; 3778 } 3779 3780 if (rendererData->viewportDirty) { 3781 if (VULKAN_UpdateViewport(renderer)) { 3782 // vertexShaderConstantsData.projectionAndView has changed 3783 updateConstants = true; 3784 } 3785 } 3786 3787 if (rendererData->cliprectDirty) { 3788 VULKAN_UpdateClipRect(renderer); 3789 } 3790 3791 if (updateConstants == true || SDL_memcmp(&rendererData->vertexShaderConstantsData.model, newmatrix, sizeof(*newmatrix)) != 0) { 3792 SDL_memcpy(&rendererData->vertexShaderConstantsData.model, newmatrix, sizeof(*newmatrix)); 3793 vkCmdPushConstants(rendererData->currentCommandBuffer, rendererData->currentPipelineState->pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, 0, 3794 sizeof(rendererData->vertexShaderConstantsData), 3795 &rendererData->vertexShaderConstantsData); 3796 } 3797 3798 if (!shader_constants) { 3799 VULKAN_SetupShaderConstants(renderer, cmd, NULL, &solid_constants); 3800 shader_constants = &solid_constants; 3801 } 3802 3803 constantBuffer = rendererData->constantBuffers[rendererData->currentCommandBufferIndex][rendererData->currentConstantBufferIndex].buffer; 3804 constantBufferOffset = (rendererData->currentConstantBufferOffset < 0) ? 0 : rendererData->currentConstantBufferOffset; 3805 if (updateConstants || 3806 SDL_memcmp(shader_constants, &rendererData->currentPipelineState->shader_constants, sizeof(*shader_constants)) != 0) { 3807 3808 if (rendererData->currentConstantBufferOffset == -1) { 3809 // First time, grab offset 0 3810 rendererData->currentConstantBufferOffset = 0; 3811 constantBufferOffset = 0; 3812 } 3813 else { 3814 // Align the next address to the minUniformBufferOffsetAlignment 3815 VkDeviceSize alignment = rendererData->physicalDeviceProperties.limits.minUniformBufferOffsetAlignment; 3816 SDL_assert(rendererData->currentConstantBufferOffset >= 0 ); 3817 rendererData->currentConstantBufferOffset += (int32_t)(sizeof(VULKAN_PixelShaderConstants) + alignment - 1) & ~(alignment - 1); 3818 constantBufferOffset = rendererData->currentConstantBufferOffset; 3819 } 3820 3821 // If we have run out of size in this constant buffer, create another if needed 3822 if (rendererData->currentConstantBufferOffset >= SDL_VULKAN_CONSTANT_BUFFER_DEFAULT_SIZE) { 3823 uint32_t newConstantBufferIndex = (rendererData->currentConstantBufferIndex + 1); 3824 // We need a new constant buffer 3825 if (newConstantBufferIndex >= rendererData->numConstantBuffers[rendererData->currentCommandBufferIndex]) { 3826 VULKAN_Buffer newConstantBuffer; 3827 VkResult result = VULKAN_AllocateBuffer(rendererData, 3828 SDL_VULKAN_CONSTANT_BUFFER_DEFAULT_SIZE, 3829 VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, 3830 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | 3831 VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, 3832 VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, 3833 &newConstantBuffer); 3834 if (result != VK_SUCCESS) { 3835 return false; 3836 } 3837 3838 rendererData->numConstantBuffers[rendererData->currentCommandBufferIndex]++; 3839 VULKAN_Buffer *newConstantBuffers = (VULKAN_Buffer *)SDL_realloc(rendererData->constantBuffers[rendererData->currentCommandBufferIndex], 3840 sizeof(VULKAN_Buffer) * rendererData->numConstantBuffers[rendererData->currentCommandBufferIndex]); 3841 newConstantBuffers[rendererData->numConstantBuffers[rendererData->currentCommandBufferIndex] - 1] = newConstantBuffer; 3842 rendererData->constantBuffers[rendererData->currentCommandBufferIndex] = newConstantBuffers; 3843 } 3844 rendererData->currentConstantBufferIndex = newConstantBufferIndex; 3845 rendererData->currentConstantBufferOffset = 0; 3846 constantBufferOffset = 0; 3847 constantBuffer = rendererData->constantBuffers[rendererData->currentCommandBufferIndex][rendererData->currentConstantBufferIndex].buffer; 3848 } 3849 3850 SDL_memcpy(&rendererData->currentPipelineState->shader_constants, shader_constants, sizeof(*shader_constants)); 3851 3852 // Upload constants to persistently mapped buffer 3853 uint8_t *dst = (uint8_t *)rendererData->constantBuffers[rendererData->currentCommandBufferIndex][rendererData->currentConstantBufferIndex].mappedBufferPtr; 3854 dst += constantBufferOffset; 3855 SDL_memcpy(dst, &rendererData->currentPipelineState->shader_constants, sizeof(VULKAN_PixelShaderConstants)); 3856 } 3857 3858 // Allocate/update descriptor set with the bindings 3859 descriptorSet = VULKAN_AllocateDescriptorSet(renderer, shader, descriptorSetLayout, constantBuffer, constantBufferOffset, numImages, imageViews, numSamplers, samplers); 3860 if (descriptorSet == VK_NULL_HANDLE) { 3861 return false; 3862 } 3863 3864 // Bind the descriptor set with the sampler/UBO/image views 3865 vkCmdBindDescriptorSets(rendererData->currentCommandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, rendererData->currentPipelineState->pipelineLayout, 3866 0, 1, &descriptorSet, 0, NULL); 3867 3868 return true; 3869} 3870 3871static VkSampler VULKAN_GetSampler(VULKAN_RenderData *data, SDL_PixelFormat format, SDL_ScaleMode scale_mode, SDL_TextureAddressMode address_u, SDL_TextureAddressMode address_v) 3872{ 3873 if (format == SDL_PIXELFORMAT_INDEX8) { 3874 // We'll do linear sampling in the shader if needed 3875 scale_mode = SDL_SCALEMODE_NEAREST; 3876 } 3877 3878 Uint32 key = RENDER_SAMPLER_HASHKEY(scale_mode, address_u, address_v); 3879 SDL_assert(key < SDL_arraysize(data->samplers)); 3880 if (!data->samplers[key]) { 3881 VkSamplerCreateInfo samplerCreateInfo = { 0 }; 3882 samplerCreateInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; 3883 samplerCreateInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST; 3884 samplerCreateInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; 3885 samplerCreateInfo.mipLodBias = 0.0f; 3886 samplerCreateInfo.anisotropyEnable = VK_FALSE; 3887 samplerCreateInfo.maxAnisotropy = 1.0f; 3888 samplerCreateInfo.minLod = 0.0f; 3889 samplerCreateInfo.maxLod = 1000.0f; 3890 switch (scale_mode) { 3891 case SDL_SCALEMODE_NEAREST: 3892 samplerCreateInfo.magFilter = VK_FILTER_NEAREST; 3893 samplerCreateInfo.minFilter = VK_FILTER_NEAREST; 3894 break; 3895 case SDL_SCALEMODE_PIXELART: // Uses linear sampling 3896 case SDL_SCALEMODE_LINEAR: 3897 samplerCreateInfo.magFilter = VK_FILTER_LINEAR; 3898 samplerCreateInfo.minFilter = VK_FILTER_LINEAR; 3899 break; 3900 default: 3901 SDL_SetError("Unknown scale mode: %d", scale_mode); 3902 return VK_NULL_HANDLE; 3903 } 3904 switch (address_u) { 3905 case SDL_TEXTURE_ADDRESS_CLAMP: 3906 samplerCreateInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; 3907 break; 3908 case SDL_TEXTURE_ADDRESS_WRAP: 3909 samplerCreateInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT; 3910 break; 3911 default: 3912 SDL_SetError("Unknown texture address mode: %d", address_u); 3913 return VK_NULL_HANDLE; 3914 } 3915 switch (address_v) { 3916 case SDL_TEXTURE_ADDRESS_CLAMP: 3917 samplerCreateInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; 3918 break; 3919 case SDL_TEXTURE_ADDRESS_WRAP: 3920 samplerCreateInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT; 3921 break; 3922 default: 3923 SDL_SetError("Unknown texture address mode: %d", address_v); 3924 return VK_NULL_HANDLE; 3925 } 3926 VkResult result = vkCreateSampler(data->device, &samplerCreateInfo, NULL, &data->samplers[key]); 3927 if (result != VK_SUCCESS) { 3928 SET_ERROR_CODE("vkCreateSampler()", result); 3929 return VK_NULL_HANDLE; 3930 } 3931 } 3932 return data->samplers[key]; 3933} 3934 3935static bool VULKAN_SetCopyState(SDL_Renderer *renderer, const SDL_RenderCommand *cmd, const Float4X4 *matrix, VULKAN_DrawStateCache *stateCache) 3936{ 3937 SDL_Texture *texture = cmd->data.draw.texture; 3938 VULKAN_RenderData *rendererData = (VULKAN_RenderData *)renderer->internal; 3939 VULKAN_TextureData *textureData = (VULKAN_TextureData *)texture->internal; 3940 int numImageViews = 0; 3941 VkImageView imageViews[2]; 3942 int numSamplers = 0; 3943 VkSampler samplers[2]; 3944 VULKAN_PixelShaderConstants constants; 3945 VkDescriptorSetLayout descriptorSetLayout = (textureData->descriptorSetLayoutYcbcr != VK_NULL_HANDLE) ? textureData->descriptorSetLayoutYcbcr : rendererData->descriptorSetLayout; 3946 VkPipelineLayout pipelineLayout = (textureData->pipelineLayoutYcbcr != VK_NULL_HANDLE) ? textureData->pipelineLayoutYcbcr : rendererData->pipelineLayout; 3947 3948 VULKAN_SetupShaderConstants(renderer, cmd, texture, &constants); 3949 3950 if (textureData->mainImage.imageLayout != VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) { 3951 bool stoppedRenderPass = false; 3952 if (rendererData->currentRenderPass != VK_NULL_HANDLE) { 3953 vkCmdEndRenderPass(rendererData->currentCommandBuffer); 3954 rendererData->currentRenderPass = VK_NULL_HANDLE; 3955 stoppedRenderPass = true; 3956 } 3957 3958 VULKAN_RecordPipelineImageBarrier(rendererData, 3959 VK_ACCESS_TRANSFER_WRITE_BIT | VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, 3960 VK_ACCESS_SHADER_READ_BIT, 3961 VK_PIPELINE_STAGE_TRANSFER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 3962 VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 3963 VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, 3964 textureData->mainImage.image, 3965 &textureData->mainImage.imageLayout); 3966 3967 if (stoppedRenderPass) { 3968 VULKAN_BeginRenderPass(rendererData, VK_ATTACHMENT_LOAD_OP_LOAD, NULL); 3969 } 3970 } 3971 imageViews[numImageViews++] = textureData->mainImage.imageView; 3972 3973 samplers[numSamplers] = VULKAN_GetSampler(rendererData, texture->format, cmd->data.draw.texture_scale_mode, cmd->data.draw.texture_address_mode_u, cmd->data.draw.texture_address_mode_v); 3974 if (samplers[numSamplers] == VK_NULL_HANDLE) { 3975 return false; 3976 } 3977 ++numSamplers; 3978 3979 if (texture->palette) { 3980 VULKAN_PaletteData *palette = (VULKAN_PaletteData *)texture->palette->internal; 3981 if (palette->image.imageLayout != VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) { 3982 bool stoppedRenderPass = false; 3983 if (rendererData->currentRenderPass != VK_NULL_HANDLE) { 3984 vkCmdEndRenderPass(rendererData->currentCommandBuffer); 3985 rendererData->currentRenderPass = VK_NULL_HANDLE; 3986 stoppedRenderPass = true; 3987 } 3988 3989 VULKAN_RecordPipelineImageBarrier(rendererData, 3990 VK_ACCESS_TRANSFER_WRITE_BIT | VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, 3991 VK_ACCESS_SHADER_READ_BIT, 3992 VK_PIPELINE_STAGE_TRANSFER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 3993 VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 3994 VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, 3995 palette->image.image, 3996 &palette->image.imageLayout); 3997 3998 if (stoppedRenderPass) { 3999 VULKAN_BeginRenderPass(rendererData, VK_ATTACHMENT_LOAD_OP_LOAD, NULL); 4000 } 4001 } 4002 imageViews[numImageViews++] = palette->image.imageView; 4003 4004 samplers[numSamplers] = VULKAN_GetSampler(rendererData, SDL_PIXELFORMAT_UNKNOWN, SDL_SCALEMODE_NEAREST, SDL_TEXTURE_ADDRESS_CLAMP, SDL_TEXTURE_ADDRESS_CLAMP); 4005 if (samplers[numSamplers] == VK_NULL_HANDLE) { 4006 return false; 4007 } 4008 ++numSamplers; 4009 } else { 4010 // We need a valid image view and sampler, but we know we're not going to reference them in the shader 4011 imageViews[numImageViews++] = imageViews[0]; 4012 samplers[numSamplers++] = samplers[0]; 4013 } 4014 4015 return VULKAN_SetDrawState(renderer, cmd, pipelineLayout, descriptorSetLayout, &constants, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, numImageViews, imageViews, numSamplers, samplers, matrix, stateCache); 4016} 4017 4018static void VULKAN_DrawPrimitives(SDL_Renderer *renderer, VkPrimitiveTopology primitiveTopology, const size_t vertexStart, const size_t vertexCount) 4019{ 4020 VULKAN_RenderData *rendererData = (VULKAN_RenderData *)renderer->internal; 4021 vkCmdDraw(rendererData->currentCommandBuffer, (uint32_t)vertexCount, 1, (uint32_t)vertexStart, 0); 4022} 4023 4024static void VULKAN_InvalidateCachedState(SDL_Renderer *renderer) 4025{ 4026 VULKAN_RenderData *rendererData = (VULKAN_RenderData *)renderer->internal; 4027 rendererData->currentPipelineState = NULL; 4028 rendererData->cliprectDirty = true; 4029} 4030 4031static bool VULKAN_RunCommandQueue(SDL_Renderer *renderer, SDL_RenderCommand *cmd, void *vertices, size_t vertsize) 4032{ 4033 VULKAN_RenderData *rendererData = (VULKAN_RenderData *)renderer->internal; 4034 VkSurfaceTransformFlagBitsKHR currentRotation = VULKAN_GetRotationForCurrentRenderTarget(rendererData); 4035 VULKAN_DrawStateCache stateCache; 4036 SDL_zero(stateCache); 4037 4038 if (!rendererData->device) { 4039 return SDL_SetError("Device lost and couldn't be recovered"); 4040 } 4041 4042 if(rendererData->currentViewportRotation != currentRotation) { 4043 rendererData->currentViewportRotation = currentRotation; 4044 rendererData->viewportDirty = true; 4045 rendererData->cliprectDirty = true; 4046 } 4047 4048 if (rendererData->recreateSwapchain) { 4049 if (VULKAN_UpdateForWindowSizeChange(renderer) != VK_SUCCESS) { 4050 return false; 4051 } 4052 rendererData->recreateSwapchain = false; 4053 } 4054 4055 if (!VULKAN_UpdateVertexBuffer(renderer, vertices, vertsize, &stateCache)) { 4056 return false; 4057 } 4058 4059 while (cmd) { 4060 switch (cmd->command) { 4061 case SDL_RENDERCMD_SETDRAWCOLOR: 4062 { 4063 break; // this isn't currently used in this render backend. 4064 } 4065 4066 case SDL_RENDERCMD_SETVIEWPORT: 4067 { 4068 SDL_Rect *viewport = &rendererData->currentViewport; 4069 if (SDL_memcmp(viewport, &cmd->data.viewport.rect, sizeof(cmd->data.viewport.rect)) != 0) { 4070 SDL_copyp(viewport, &cmd->data.viewport.rect); 4071 rendererData->viewportDirty = true; 4072 rendererData->cliprectDirty = true; 4073 } 4074 break; 4075 } 4076 4077 case SDL_RENDERCMD_SETCLIPRECT: 4078 { 4079 const SDL_Rect *rect = &cmd->data.cliprect.rect; 4080 if (rendererData->currentCliprectEnabled != cmd->data.cliprect.enabled) { 4081 rendererData->currentCliprectEnabled = cmd->data.cliprect.enabled; 4082 rendererData->cliprectDirty = true; 4083 } 4084 if (SDL_memcmp(&rendererData->currentCliprect, rect, sizeof(*rect)) != 0) { 4085 SDL_copyp(&rendererData->currentCliprect, rect); 4086 rendererData->cliprectDirty = true; 4087 } 4088 break; 4089 } 4090 4091 case SDL_RENDERCMD_CLEAR: 4092 { 4093 bool convert_color = SDL_RenderingLinearSpace(renderer); 4094 SDL_FColor color = cmd->data.color.color; 4095 if (convert_color) { 4096 SDL_ConvertToLinear(&color); 4097 } 4098 color.r *= cmd->data.color.color_scale; 4099 color.g *= cmd->data.color.color_scale; 4100 color.b *= cmd->data.color.color_scale; 4101 4102 VkClearColorValue clearColor; 4103 clearColor.float32[0] = color.r; 4104 clearColor.float32[1] = color.g; 4105 clearColor.float32[2] = color.b; 4106 clearColor.float32[3] = color.a; 4107 VULKAN_ActivateCommandBuffer(renderer, VK_ATTACHMENT_LOAD_OP_CLEAR, &clearColor, &stateCache); 4108 break; 4109 } 4110 4111 case SDL_RENDERCMD_DRAW_LINES: 4112 { 4113 size_t count = cmd->data.draw.count; 4114 const size_t first = cmd->data.draw.first; 4115 const size_t start = first / sizeof(VULKAN_VertexPositionColor); 4116 const VULKAN_VertexPositionColor *verts = (VULKAN_VertexPositionColor *)(((Uint8 *)vertices) + first); 4117 bool have_point_draw_state = false; 4118 4119 // Add the final point in the line 4120 size_t line_start = 0; 4121 size_t line_end = line_start + count - 1; 4122 if (verts[line_start].pos[0] != verts[line_end].pos[0] || verts[line_start].pos[1] != verts[line_end].pos[1]) { 4123 VULKAN_SetDrawState(renderer, cmd, rendererData->pipelineLayout, rendererData->descriptorSetLayout, NULL, VK_PRIMITIVE_TOPOLOGY_POINT_LIST, 0, NULL, 0, NULL, NULL, &stateCache); 4124 VULKAN_DrawPrimitives(renderer, VK_PRIMITIVE_TOPOLOGY_POINT_LIST, start + line_end, 1); 4125 have_point_draw_state = true; 4126 } 4127 4128 if (count > 2) { 4129 // joined lines cannot be grouped 4130 VULKAN_SetDrawState(renderer, cmd, rendererData->pipelineLayout, rendererData->descriptorSetLayout, NULL, VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, 0, NULL, 0, NULL, NULL, &stateCache); 4131 VULKAN_DrawPrimitives(renderer, VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, start, count); 4132 } else { 4133 // let's group non joined lines 4134 SDL_RenderCommand *finalcmd = cmd; 4135 SDL_RenderCommand *nextcmd; 4136 float thiscolorscale = cmd->data.draw.color_scale; 4137 SDL_BlendMode thisblend = cmd->data.draw.blend; 4138 4139 for (nextcmd = cmd->next; nextcmd; nextcmd = nextcmd->next) { 4140 const SDL_RenderCommandType nextcmdtype = nextcmd->command; 4141 if (nextcmdtype != SDL_RENDERCMD_DRAW_LINES) { 4142 if (nextcmdtype == SDL_RENDERCMD_SETDRAWCOLOR) { 4143 // The vertex data has the draw color built in, ignore this 4144 continue; 4145 } 4146 break; // can't go any further on this draw call, different render command up next. 4147 } else if (nextcmd->data.draw.count != 2) { 4148 break; // can't go any further on this draw call, those are joined lines 4149 } else if (nextcmd->data.draw.blend != thisblend || 4150 nextcmd->data.draw.color_scale != thiscolorscale) { 4151 break; // can't go any further on this draw call, different blendmode copy up next. 4152 } else { 4153 finalcmd = nextcmd; // we can combine copy operations here. Mark this one as the furthest okay command. 4154 4155 // Add the final point in the line 4156 line_start = count; 4157 line_end = line_start + nextcmd->data.draw.count - 1; 4158 if (verts[line_start].pos[0] != verts[line_end].pos[0] || verts[line_start].pos[1] != verts[line_end].pos[1]) { 4159 if (!have_point_draw_state) { 4160 VULKAN_SetDrawState(renderer, cmd, rendererData->pipelineLayout, rendererData->descriptorSetLayout, NULL, VK_PRIMITIVE_TOPOLOGY_POINT_LIST, 0, NULL, 0, NULL, NULL, &stateCache); 4161 have_point_draw_state = true; 4162 } 4163 VULKAN_DrawPrimitives(renderer, VK_PRIMITIVE_TOPOLOGY_POINT_LIST, start + line_end, 1); 4164 } 4165 count += nextcmd->data.draw.count; 4166 } 4167 } 4168 4169 VULKAN_SetDrawState(renderer, cmd, rendererData->pipelineLayout, rendererData->descriptorSetLayout, NULL, VK_PRIMITIVE_TOPOLOGY_LINE_LIST, 0, NULL, 0, NULL, NULL, &stateCache); 4170 VULKAN_DrawPrimitives(renderer, VK_PRIMITIVE_TOPOLOGY_LINE_LIST, start, count); 4171 4172 cmd = finalcmd; // skip any copy commands we just combined in here. 4173 } 4174 break; 4175 } 4176 4177 case SDL_RENDERCMD_FILL_RECTS: // unused 4178 break; 4179 4180 case SDL_RENDERCMD_COPY: // unused 4181 break; 4182 4183 case SDL_RENDERCMD_COPY_EX: // unused 4184 break; 4185 4186 case SDL_RENDERCMD_DRAW_POINTS: 4187 case SDL_RENDERCMD_GEOMETRY: 4188 { 4189 /* as long as we have the same copy command in a row, with the 4190 same texture, we can combine them all into a single draw call. */ 4191 float thiscolorscale = cmd->data.draw.color_scale; 4192 SDL_Texture *thistexture = cmd->data.draw.texture; 4193 SDL_BlendMode thisblend = cmd->data.draw.blend; 4194 SDL_ScaleMode thisscalemode = cmd->data.draw.texture_scale_mode; 4195 SDL_TextureAddressMode thisaddressmode_u = cmd->data.draw.texture_address_mode_u; 4196 SDL_TextureAddressMode thisaddressmode_v = cmd->data.draw.texture_address_mode_v; 4197 const SDL_RenderCommandType thiscmdtype = cmd->command; 4198 SDL_RenderCommand *finalcmd = cmd; 4199 SDL_RenderCommand *nextcmd; 4200 size_t count = cmd->data.draw.count; 4201 const size_t first = cmd->data.draw.first; 4202 const size_t start = first / sizeof(VULKAN_VertexPositionColor); 4203 for (nextcmd = cmd->next; nextcmd; nextcmd = nextcmd->next) { 4204 const SDL_RenderCommandType nextcmdtype = nextcmd->command; 4205 if (nextcmdtype != thiscmdtype) { 4206 if (nextcmdtype == SDL_RENDERCMD_SETDRAWCOLOR) { 4207 // The vertex data has the draw color built in, ignore this 4208 continue; 4209 } 4210 break; // can't go any further on this draw call, different render command up next. 4211 } else if (nextcmd->data.draw.texture != thistexture || 4212 nextcmd->data.draw.texture_scale_mode != thisscalemode || 4213 nextcmd->data.draw.texture_address_mode_u != thisaddressmode_u || 4214 nextcmd->data.draw.texture_address_mode_v != thisaddressmode_v || 4215 nextcmd->data.draw.blend != thisblend || 4216 nextcmd->data.draw.color_scale != thiscolorscale) { 4217 break; // can't go any further on this draw call, different texture/blendmode copy up next. 4218 } else { 4219 finalcmd = nextcmd; // we can combine copy operations here. Mark this one as the furthest okay command. 4220 count += nextcmd->data.draw.count; 4221 } 4222 } 4223 4224 if (thiscmdtype == SDL_RENDERCMD_GEOMETRY) { 4225 if (thistexture) { 4226 VULKAN_SetCopyState(renderer, cmd, NULL, &stateCache); 4227 } else { 4228 VULKAN_SetDrawState(renderer, cmd, rendererData->pipelineLayout, rendererData->descriptorSetLayout, NULL, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, 0, NULL, 0, NULL, NULL, &stateCache); 4229 } 4230 4231 VULKAN_DrawPrimitives(renderer, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, start, count); 4232 } else { 4233 VULKAN_SetDrawState(renderer, cmd, rendererData->pipelineLayout, rendererData->descriptorSetLayout, NULL, VK_PRIMITIVE_TOPOLOGY_POINT_LIST, 0, NULL, 0, NULL, NULL, &stateCache); 4234 VULKAN_DrawPrimitives(renderer, VK_PRIMITIVE_TOPOLOGY_POINT_LIST, start, count); 4235 } 4236 cmd = finalcmd; // skip any copy commands we just combined in here. 4237 break; 4238 } 4239 4240 case SDL_RENDERCMD_NO_OP: 4241 break; 4242 } 4243 4244 cmd = cmd->next; 4245 } 4246 return true; 4247} 4248 4249static SDL_Surface *VULKAN_RenderReadPixels(SDL_Renderer *renderer, const SDL_Rect *rect) 4250{ 4251 VULKAN_RenderData *rendererData = (VULKAN_RenderData *)renderer->internal; 4252 VkImage backBuffer; 4253 VkImageLayout *imageLayout; 4254 VULKAN_Buffer readbackBuffer; 4255 VkDeviceSize pixelSize; 4256 VkDeviceSize length; 4257 VkDeviceSize readbackBufferSize; 4258 VkFormat vkFormat; 4259 SDL_Surface *output; 4260 4261 VULKAN_EnsureCommandBuffer(rendererData); 4262 4263 // Stop any outstanding renderpass if open 4264 if (rendererData->currentRenderPass != VK_NULL_HANDLE) { 4265 vkCmdEndRenderPass(rendererData->currentCommandBuffer); 4266 rendererData->currentRenderPass = VK_NULL_HANDLE; 4267 } 4268 4269 if (rendererData->textureRenderTarget) { 4270 backBuffer = rendererData->textureRenderTarget->mainImage.image; 4271 imageLayout = &rendererData->textureRenderTarget->mainImage.imageLayout; 4272 vkFormat = rendererData->textureRenderTarget->mainImage.format; 4273 } else { 4274 backBuffer = rendererData->swapchainImages[rendererData->currentSwapchainImageIndex]; 4275 imageLayout = &rendererData->swapchainImageLayouts[rendererData->currentSwapchainImageIndex]; 4276 vkFormat = rendererData->surfaceFormat.format; 4277 } 4278 4279 pixelSize = VULKAN_GetBytesPerPixel(vkFormat, 0); 4280 length = rect->w * pixelSize; 4281 readbackBufferSize = length * rect->h; 4282 if (VULKAN_AllocateBuffer(rendererData, readbackBufferSize, 4283 VK_BUFFER_USAGE_TRANSFER_DST_BIT, 4284 VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | 4285 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, 4286 VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, 4287 &readbackBuffer) != VK_SUCCESS) { 4288 return NULL; 4289 } 4290 4291 4292 // Make sure the source is in the correct resource state 4293 VULKAN_RecordPipelineImageBarrier(rendererData, 4294 VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_TRANSFER_WRITE_BIT, 4295 VK_ACCESS_TRANSFER_READ_BIT, 4296 VK_PIPELINE_STAGE_TRANSFER_BIT | VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 4297 VK_PIPELINE_STAGE_TRANSFER_BIT, 4298 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, 4299 backBuffer, 4300 imageLayout); 4301 4302 // Copy the image to the readback buffer 4303 VkBufferImageCopy region; 4304 region.bufferOffset = 0; 4305 region.bufferRowLength = 0; 4306 region.bufferImageHeight = 0; 4307 region.imageSubresource.baseArrayLayer = 0; 4308 region.imageSubresource.layerCount = 1; 4309 region.imageSubresource.mipLevel = 0; 4310 region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; 4311 region.imageOffset.x = rect->x; 4312 region.imageOffset.y = rect->y; 4313 region.imageOffset.z = 0; 4314 region.imageExtent.width = rect->w; 4315 region.imageExtent.height = rect->h; 4316 region.imageExtent.depth = 1; 4317 vkCmdCopyImageToBuffer(rendererData->currentCommandBuffer, backBuffer, *imageLayout, readbackBuffer.buffer, 1, &region); 4318 4319 // We need to issue the command list for the copy to finish 4320 VULKAN_IssueBatch(rendererData); 4321 4322 // Transition the render target back to a render target 4323 VULKAN_RecordPipelineImageBarrier(rendererData, 4324 VK_ACCESS_TRANSFER_WRITE_BIT, 4325 VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_TRANSFER_WRITE_BIT, 4326 VK_PIPELINE_STAGE_TRANSFER_BIT, 4327 VK_PIPELINE_STAGE_TRANSFER_BIT | VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 4328 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, 4329 backBuffer, 4330 imageLayout); 4331 4332 output = SDL_DuplicatePixels( 4333 rect->w, rect->h, 4334 VULKAN_VkFormatToSDLPixelFormat(vkFormat), 4335 renderer->target ? renderer->target->colorspace : renderer->output_colorspace, 4336 readbackBuffer.mappedBufferPtr, 4337 (int)length); 4338 4339 VULKAN_DestroyBuffer(rendererData, &readbackBuffer); 4340 4341 return output; 4342} 4343 4344static bool VULKAN_AddVulkanRenderSemaphores(SDL_Renderer *renderer, Uint32 wait_stage_mask, Sint64 wait_semaphore, Sint64 signal_semaphore) 4345{ 4346 VULKAN_RenderData *rendererData = (VULKAN_RenderData *)renderer->internal; 4347 4348 if (wait_semaphore) { 4349 if (rendererData->waitRenderSemaphoreCount == rendererData->waitRenderSemaphoreMax) { 4350 // Allocate an additional one at the end for the normal present wait 4351 VkPipelineStageFlags *waitDestStageMasks = (VkPipelineStageFlags *)SDL_realloc(rendererData->waitDestStageMasks, (rendererData->waitRenderSemaphoreMax + 2) * sizeof(*waitDestStageMasks)); 4352 if (!waitDestStageMasks) { 4353 return false; 4354 } 4355 rendererData->waitDestStageMasks = waitDestStageMasks; 4356 4357 VkSemaphore *semaphores = (VkSemaphore *)SDL_realloc(rendererData->waitRenderSemaphores, (rendererData->waitRenderSemaphoreMax + 2) * sizeof(*semaphores)); 4358 if (!semaphores) { 4359 return false; 4360 } 4361 rendererData->waitRenderSemaphores = semaphores; 4362 ++rendererData->waitRenderSemaphoreMax; 4363 } 4364 rendererData->waitDestStageMasks[rendererData->waitRenderSemaphoreCount] = wait_stage_mask; 4365 rendererData->waitRenderSemaphores[rendererData->waitRenderSemaphoreCount] = (VkSemaphore)wait_semaphore; 4366 ++rendererData->waitRenderSemaphoreCount; 4367 } 4368 4369 if (signal_semaphore) { 4370 if (rendererData->signalRenderSemaphoreCount == rendererData->signalRenderSemaphoreMax) { 4371 // Allocate an additional one at the end for the normal present signal 4372 VkSemaphore *semaphores = (VkSemaphore *)SDL_realloc(rendererData->signalRenderSemaphores, (rendererData->signalRenderSemaphoreMax + 2) * sizeof(*semaphores)); 4373 if (!semaphores) { 4374 return false; 4375 } 4376 rendererData->signalRenderSemaphores = semaphores; 4377 ++rendererData->signalRenderSemaphoreMax; 4378 } 4379 rendererData->signalRenderSemaphores[rendererData->signalRenderSemaphoreCount] = (VkSemaphore)signal_semaphore; 4380 ++rendererData->signalRenderSemaphoreCount; 4381 } 4382 4383 return true; 4384} 4385 4386static bool VULKAN_RenderPresent(SDL_Renderer *renderer) 4387{ 4388 VULKAN_RenderData *rendererData = (VULKAN_RenderData *)renderer->internal; 4389 VkResult result = VK_SUCCESS; 4390 4391 if (!rendererData->device) { 4392 return SDL_SetError("Device lost and couldn't be recovered"); 4393 } 4394 4395 if (rendererData->currentCommandBuffer) { 4396 rendererData->currentPipelineState = VK_NULL_HANDLE; 4397 rendererData->viewportDirty = true; 4398 4399 VULKAN_RecordPipelineImageBarrier(rendererData, 4400 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, 4401 VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, 4402 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 4403 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 4404 VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, 4405 rendererData->swapchainImages[rendererData->currentSwapchainImageIndex], 4406 &rendererData->swapchainImageLayouts[rendererData->currentSwapchainImageIndex]); 4407 4408 vkEndCommandBuffer(rendererData->currentCommandBuffer); 4409 4410 result = vkResetFences(rendererData->device, 1, &rendererData->fences[rendererData->currentCommandBufferIndex]); 4411 if (result != VK_SUCCESS) { 4412 SET_ERROR_CODE("vkResetFences()", result); 4413 return false; 4414 } 4415 4416 VkPipelineStageFlags waitDestStageMask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT; 4417 VkSubmitInfo submitInfo = { 0 }; 4418 submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; 4419 if (rendererData->waitRenderSemaphoreCount > 0) { 4420 Uint32 additionalSemaphoreCount = (rendererData->currentImageAvailableSemaphore != VK_NULL_HANDLE) ? 1 : 0; 4421 submitInfo.waitSemaphoreCount = rendererData->waitRenderSemaphoreCount + additionalSemaphoreCount; 4422 if (additionalSemaphoreCount > 0) { 4423 rendererData->waitRenderSemaphores[rendererData->waitRenderSemaphoreCount] = rendererData->currentImageAvailableSemaphore; 4424 rendererData->waitDestStageMasks[rendererData->waitRenderSemaphoreCount] = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT; 4425 } 4426 submitInfo.pWaitSemaphores = rendererData->waitRenderSemaphores; 4427 submitInfo.pWaitDstStageMask = rendererData->waitDestStageMasks; 4428 rendererData->waitRenderSemaphoreCount = 0; 4429 } else if (rendererData->currentImageAvailableSemaphore != VK_NULL_HANDLE) { 4430 submitInfo.waitSemaphoreCount = 1; 4431 submitInfo.pWaitSemaphores = &rendererData->currentImageAvailableSemaphore; 4432 submitInfo.pWaitDstStageMask = &waitDestStageMask; 4433 } 4434 submitInfo.commandBufferCount = 1; 4435 submitInfo.pCommandBuffers = &rendererData->currentCommandBuffer; 4436 if (rendererData->signalRenderSemaphoreCount > 0) { 4437 submitInfo.signalSemaphoreCount = rendererData->signalRenderSemaphoreCount + 1; 4438 rendererData->signalRenderSemaphores[rendererData->signalRenderSemaphoreCount] = rendererData->renderingFinishedSemaphores[rendererData->currentCommandBufferIndex]; 4439 submitInfo.pSignalSemaphores = rendererData->signalRenderSemaphores; 4440 rendererData->signalRenderSemaphoreCount = 0; 4441 } else { 4442 submitInfo.signalSemaphoreCount = 1; 4443 submitInfo.pSignalSemaphores = &rendererData->renderingFinishedSemaphores[rendererData->currentCommandBufferIndex]; 4444 } 4445 result = vkQueueSubmit(rendererData->graphicsQueue, 1, &submitInfo, rendererData->fences[rendererData->currentCommandBufferIndex]); 4446 if (result != VK_SUCCESS) { 4447 if (result == VK_ERROR_DEVICE_LOST) { 4448 if (VULKAN_HandleDeviceLost(renderer)) { 4449 SDL_SetError("Present failed, device lost"); 4450 } else { 4451 // Recovering from device lost failed, error is already set 4452 } 4453 } else { 4454 SET_ERROR_CODE("vkQueueSubmit()", result); 4455 } 4456 return false; 4457 } 4458 rendererData->currentCommandBuffer = VK_NULL_HANDLE; 4459 rendererData->currentImageAvailableSemaphore = VK_NULL_HANDLE; 4460 4461 VkPresentInfoKHR presentInfo = { 0 }; 4462 presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; 4463 presentInfo.waitSemaphoreCount = 1; 4464 presentInfo.pWaitSemaphores = &rendererData->renderingFinishedSemaphores[rendererData->currentCommandBufferIndex]; 4465 presentInfo.swapchainCount = 1; 4466 presentInfo.pSwapchains = &rendererData->swapchain; 4467 presentInfo.pImageIndices = &rendererData->currentSwapchainImageIndex; 4468 result = vkQueuePresentKHR(rendererData->presentQueue, &presentInfo); 4469 if ((result != VK_SUCCESS) && (result != VK_ERROR_OUT_OF_DATE_KHR) && (result != VK_ERROR_SURFACE_LOST_KHR) && (result != VK_SUBOPTIMAL_KHR )) { 4470 SET_ERROR_CODE("vkQueuePresentKHR()", result); 4471 return false; 4472 } 4473 4474 rendererData->currentCommandBufferIndex = ( rendererData->currentCommandBufferIndex + 1 ) % rendererData->swapchainImageCount; 4475 4476 // Wait for previous time this command buffer was submitted, will be N frames ago 4477 result = vkWaitForFences(rendererData->device, 1, &rendererData->fences[rendererData->currentCommandBufferIndex], VK_TRUE, UINT64_MAX); 4478 if (result != VK_SUCCESS) { 4479 if (result == VK_ERROR_DEVICE_LOST) { 4480 if (VULKAN_HandleDeviceLost(renderer)) { 4481 SDL_SetError("Present failed, device lost"); 4482 } else { 4483 // Recovering from device lost failed, error is already set 4484 } 4485 } else { 4486 SET_ERROR_CODE("vkWaitForFences()", result); 4487 } 4488 return false; 4489 } 4490 4491 VULKAN_AcquireNextSwapchainImage(renderer); 4492 } 4493 4494 return true; 4495} 4496 4497static bool VULKAN_SetVSync(SDL_Renderer *renderer, const int vsync) 4498{ 4499 VULKAN_RenderData *rendererData = (VULKAN_RenderData *)renderer->internal; 4500 4501 switch (vsync) { 4502 case -1: 4503 case 0: 4504 case 1: 4505 // Supported 4506 break; 4507 default: 4508 return SDL_Unsupported(); 4509 } 4510 if (vsync != rendererData->vsync) { 4511 rendererData->vsync = vsync; 4512 rendererData->recreateSwapchain = true; 4513 } 4514 return true; 4515} 4516 4517static bool VULKAN_CreateRenderer(SDL_Renderer *renderer, SDL_Window *window, SDL_PropertiesID create_props) 4518{ 4519 VULKAN_RenderData *rendererData; 4520 4521 SDL_SetupRendererColorspace(renderer, create_props); 4522 4523 if (renderer->output_colorspace != SDL_COLORSPACE_SRGB && 4524 renderer->output_colorspace != SDL_COLORSPACE_SRGB_LINEAR 4525 /*&& renderer->output_colorspace != SDL_COLORSPACE_HDR10*/) { 4526 return SDL_SetError("Unsupported output colorspace"); 4527 } 4528 4529 rendererData = (VULKAN_RenderData *)SDL_calloc(1, sizeof(*rendererData)); 4530 if (!rendererData) { 4531 return false; 4532 } 4533 4534 rendererData->identity = MatrixIdentity(); 4535 rendererData->identitySwizzle.r = VK_COMPONENT_SWIZZLE_IDENTITY; 4536 rendererData->identitySwizzle.g = VK_COMPONENT_SWIZZLE_IDENTITY; 4537 rendererData->identitySwizzle.b = VK_COMPONENT_SWIZZLE_IDENTITY; 4538 rendererData->identitySwizzle.a = VK_COMPONENT_SWIZZLE_IDENTITY; 4539 4540 // Save the create props in case we need to recreate on device lost 4541 rendererData->create_props = SDL_CreateProperties(); 4542 if (!SDL_CopyProperties(create_props, rendererData->create_props)) { 4543 SDL_free(rendererData); 4544 return false; 4545 } 4546 4547 renderer->WindowEvent = VULKAN_WindowEvent; 4548 renderer->SupportsBlendMode = VULKAN_SupportsBlendMode; 4549 renderer->CreatePalette = VULKAN_CreatePalette; 4550 renderer->UpdatePalette = VULKAN_UpdatePalette; 4551 renderer->DestroyPalette = VULKAN_DestroyPalette; 4552 renderer->CreateTexture = VULKAN_CreateTexture; 4553 renderer->UpdateTexture = VULKAN_UpdateTexture; 4554#ifdef SDL_HAVE_YUV 4555 renderer->UpdateTextureYUV = VULKAN_UpdateTextureYUV; 4556 renderer->UpdateTextureNV = VULKAN_UpdateTextureNV; 4557#endif 4558 renderer->LockTexture = VULKAN_LockTexture; 4559 renderer->UnlockTexture = VULKAN_UnlockTexture; 4560 renderer->SetRenderTarget = VULKAN_SetRenderTarget; 4561 renderer->QueueSetViewport = VULKAN_QueueNoOp; 4562 renderer->QueueSetDrawColor = VULKAN_QueueNoOp; 4563 renderer->QueueDrawPoints = VULKAN_QueueDrawPoints; 4564 renderer->QueueDrawLines = VULKAN_QueueDrawPoints; // lines and points queue vertices the same way. 4565 renderer->QueueGeometry = VULKAN_QueueGeometry; 4566 renderer->InvalidateCachedState = VULKAN_InvalidateCachedState; 4567 renderer->RunCommandQueue = VULKAN_RunCommandQueue; 4568 renderer->RenderReadPixels = VULKAN_RenderReadPixels; 4569 renderer->AddVulkanRenderSemaphores = VULKAN_AddVulkanRenderSemaphores; 4570 renderer->RenderPresent = VULKAN_RenderPresent; 4571 renderer->DestroyTexture = VULKAN_DestroyTexture; 4572 renderer->DestroyRenderer = VULKAN_DestroyRenderer; 4573 renderer->SetVSync = VULKAN_SetVSync; 4574 renderer->internal = rendererData; 4575 VULKAN_InvalidateCachedState(renderer); 4576 4577 renderer->name = VULKAN_RenderDriver.name; 4578 SDL_SetNumberProperty(SDL_GetRendererProperties(renderer), SDL_PROP_RENDERER_MAX_TEXTURE_SIZE_NUMBER, 16384); 4579 4580 /* HACK: make sure the SDL_Renderer references the SDL_Window data now, in 4581 * order to give init functions access to the underlying window handle: 4582 */ 4583 renderer->window = window; 4584 4585 // Initialize Vulkan resources 4586 if (VULKAN_CreateDeviceResources(renderer, create_props) != VK_SUCCESS) { 4587 return false; 4588 } 4589 4590 if (VULKAN_CreateWindowSizeDependentResources(renderer) != VK_SUCCESS) { 4591 return false; 4592 } 4593 4594 for (int i = 0; i < SDL_arraysize(vk_format_map); i++) { 4595 VkImageFormatProperties properties; 4596 4597 if (vkGetPhysicalDeviceImageFormatProperties(rendererData->physicalDevice, 4598 vk_format_map[i].unorm, 4599 VK_IMAGE_TYPE_2D, 4600 VK_IMAGE_TILING_OPTIMAL, 4601 VK_IMAGE_USAGE_SAMPLED_BIT, 4602 0, 4603 &properties) != VK_SUCCESS) { 4604 continue; 4605 } 4606 4607 if (vkGetPhysicalDeviceImageFormatProperties(rendererData->physicalDevice, 4608 vk_format_map[i].srgb, 4609 VK_IMAGE_TYPE_2D, 4610 VK_IMAGE_TILING_OPTIMAL, 4611 VK_IMAGE_USAGE_SAMPLED_BIT, 4612 0, 4613 &properties) != VK_SUCCESS) { 4614 continue; 4615 } 4616 4617 SDL_AddSupportedTextureFormat(renderer, vk_format_map[i].sdl); 4618 } 4619 4620 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_INDEX8); 4621 4622#ifdef SDL_HAVE_YUV 4623 if (rendererData->supportsKHRSamplerYCbCrConversion) { 4624 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_YV12); 4625 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_IYUV); 4626 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_NV12); 4627 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_NV21); 4628 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_P010); 4629 } 4630#endif 4631 4632 return true; 4633} 4634 4635SDL_RenderDriver VULKAN_RenderDriver = { 4636 VULKAN_CreateRenderer, "vulkan" 4637}; 4638 4639#endif // SDL_VIDEO_RENDER_VULKAN 4640
[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.