Simple Directmedia Layer
at main 4343 lines 199 kB view raw
1/* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org> 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\n", 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\n", 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(vkGetPhysicalDeviceProperties) \ 138 VULKAN_INSTANCE_FUNCTION(vkGetPhysicalDeviceMemoryProperties) \ 139 VULKAN_INSTANCE_FUNCTION(vkGetPhysicalDeviceQueueFamilyProperties) \ 140 VULKAN_INSTANCE_FUNCTION(vkGetPhysicalDeviceSurfaceCapabilitiesKHR) \ 141 VULKAN_INSTANCE_FUNCTION(vkGetPhysicalDeviceSurfaceFormatsKHR) \ 142 VULKAN_INSTANCE_FUNCTION(vkGetPhysicalDeviceSurfacePresentModesKHR) \ 143 VULKAN_INSTANCE_FUNCTION(vkGetPhysicalDeviceSurfaceSupportKHR) \ 144 VULKAN_INSTANCE_FUNCTION(vkQueueWaitIdle) \ 145 VULKAN_OPTIONAL_INSTANCE_FUNCTION(vkGetPhysicalDeviceFeatures2KHR) \ 146 VULKAN_OPTIONAL_INSTANCE_FUNCTION(vkGetPhysicalDeviceFormatProperties2KHR) \ 147 VULKAN_OPTIONAL_INSTANCE_FUNCTION(vkGetPhysicalDeviceImageFormatProperties2KHR) \ 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// Sampler types 173typedef enum 174{ 175 VULKAN_SAMPLER_NEAREST_CLAMP, 176 VULKAN_SAMPLER_NEAREST_WRAP, 177 VULKAN_SAMPLER_LINEAR_CLAMP, 178 VULKAN_SAMPLER_LINEAR_WRAP, 179 VULKAN_SAMPLER_COUNT 180} VULKAN_Sampler; 181 182// Vertex shader, common values 183typedef struct 184{ 185 Float4X4 model; 186 Float4X4 projectionAndView; 187} VULKAN_VertexShaderConstants; 188 189// These should mirror the definitions in VULKAN_PixelShader_Common.hlsli 190//static const float TONEMAP_NONE = 0; 191//static const float TONEMAP_LINEAR = 1; 192static const float TONEMAP_CHROME = 2; 193 194static const float INPUTTYPE_UNSPECIFIED = 0; 195static const float INPUTTYPE_SRGB = 1; 196static const float INPUTTYPE_SCRGB = 2; 197static const float INPUTTYPE_HDR10 = 3; 198 199typedef enum 200{ 201 SAMPLER_POINT_CLAMP, 202 SAMPLER_POINT_WRAP, 203 SAMPLER_LINEAR_CLAMP, 204 SAMPLER_LINEAR_WRAP, 205 NUM_SAMPLERS 206} Sampler; 207 208// Pixel shader constants, common values 209typedef struct 210{ 211 float scRGB_output; 212 float input_type; 213 float color_scale; 214 float unused_pad0; 215 216 float tonemap_method; 217 float tonemap_factor1; 218 float tonemap_factor2; 219 float sdr_white_point; 220} VULKAN_PixelShaderConstants; 221 222// Per-vertex data 223typedef struct 224{ 225 float pos[2]; 226 float tex[2]; 227 SDL_FColor color; 228} VULKAN_VertexPositionColor; 229 230// Vulkan Buffer 231typedef struct 232{ 233 VkDeviceMemory deviceMemory; 234 VkBuffer buffer; 235 VkDeviceSize size; 236 void *mappedBufferPtr; 237 238} VULKAN_Buffer; 239 240// Vulkan image 241typedef struct 242{ 243 bool allocatedImage; 244 VkImage image; 245 VkImageView imageView; 246 VkDeviceMemory deviceMemory; 247 VkImageLayout imageLayout; 248 VkFormat format; 249} VULKAN_Image; 250 251// Per-texture data 252typedef struct 253{ 254 VULKAN_Image mainImage; 255 VkRenderPass mainRenderpasses[VULKAN_RENDERPASS_COUNT]; 256 VkFramebuffer mainFramebuffer; 257 VULKAN_Buffer stagingBuffer; 258 VkFilter scaleMode; 259 SDL_Rect lockedRect; 260 int width; 261 int height; 262 VULKAN_Shader shader; 263 264 // Object passed to VkImageView and VkSampler for doing Ycbcr -> RGB conversion 265 VkSamplerYcbcrConversion samplerYcbcrConversion; 266 // Sampler created with samplerYcbcrConversion, passed to PSO as immutable sampler 267 VkSampler samplerYcbcr; 268 // Descriptor set layout with samplerYcbcr baked as immutable sampler 269 VkDescriptorSetLayout descriptorSetLayoutYcbcr; 270 // Pipeline layout with immutable sampler descriptor set layout 271 VkPipelineLayout pipelineLayoutYcbcr; 272 273} VULKAN_TextureData; 274 275// Pipeline State Object data 276typedef struct 277{ 278 VULKAN_Shader shader; 279 VULKAN_PixelShaderConstants shader_constants; 280 SDL_BlendMode blendMode; 281 VkPrimitiveTopology topology; 282 VkFormat format; 283 VkPipelineLayout pipelineLayout; 284 VkDescriptorSetLayout descriptorSetLayout; 285 VkPipeline pipeline; 286} VULKAN_PipelineState; 287 288typedef struct 289{ 290 VkBuffer vertexBuffer; 291} VULKAN_DrawStateCache; 292 293// Private renderer data 294typedef struct 295{ 296 PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr; 297 VkInstance instance; 298 bool instance_external; 299 VkSurfaceKHR surface; 300 bool surface_external; 301 VkPhysicalDevice physicalDevice; 302 VkPhysicalDeviceProperties physicalDeviceProperties; 303 VkPhysicalDeviceMemoryProperties physicalDeviceMemoryProperties; 304 VkPhysicalDeviceFeatures physicalDeviceFeatures; 305 VkQueue graphicsQueue; 306 VkQueue presentQueue; 307 VkDevice device; 308 bool device_external; 309 uint32_t graphicsQueueFamilyIndex; 310 uint32_t presentQueueFamilyIndex; 311 VkSwapchainKHR swapchain; 312 VkCommandPool commandPool; 313 VkCommandBuffer *commandBuffers; 314 uint32_t currentCommandBufferIndex; 315 VkCommandBuffer currentCommandBuffer; 316 VkFence *fences; 317 VkSurfaceCapabilitiesKHR surfaceCapabilities; 318 VkSurfaceFormatKHR *surfaceFormats; 319 bool recreateSwapchain; 320 int vsync; 321 SDL_PropertiesID create_props; 322 323 VkFramebuffer *framebuffers; 324 VkRenderPass renderPasses[VULKAN_RENDERPASS_COUNT]; 325 VkRenderPass currentRenderPass; 326 327 VkShaderModule vertexShaderModules[NUM_SHADERS]; 328 VkShaderModule fragmentShaderModules[NUM_SHADERS]; 329 VkDescriptorSetLayout descriptorSetLayout; 330 VkPipelineLayout pipelineLayout; 331 332 // Vertex buffer data 333 VULKAN_Buffer vertexBuffers[SDL_VULKAN_NUM_VERTEX_BUFFERS]; 334 VULKAN_VertexShaderConstants vertexShaderConstantsData; 335 336 // Data for staging/allocating textures 337 VULKAN_Buffer **uploadBuffers; 338 int *currentUploadBuffer; 339 340 // Data for updating constants 341 VULKAN_Buffer **constantBuffers; 342 uint32_t *numConstantBuffers; 343 uint32_t currentConstantBufferIndex; 344 int32_t currentConstantBufferOffset; 345 346 VkSampler samplers[VULKAN_SAMPLER_COUNT]; 347 VkDescriptorPool **descriptorPools; 348 uint32_t *numDescriptorPools; 349 uint32_t currentDescriptorPoolIndex; 350 uint32_t currentDescriptorSetIndex; 351 352 int pipelineStateCount; 353 VULKAN_PipelineState *pipelineStates; 354 VULKAN_PipelineState *currentPipelineState; 355 356 bool supportsEXTSwapchainColorspace; 357 bool supportsKHRGetPhysicalDeviceProperties2; 358 bool supportsKHRSamplerYCbCrConversion; 359 uint32_t surfaceFormatsAllocatedCount; 360 uint32_t surfaceFormatsCount; 361 uint32_t swapchainDesiredImageCount; 362 VkSurfaceFormatKHR surfaceFormat; 363 VkExtent2D swapchainSize; 364 VkSurfaceTransformFlagBitsKHR swapChainPreTransform; 365 uint32_t swapchainImageCount; 366 VkImage *swapchainImages; 367 VkImageView *swapchainImageViews; 368 VkImageLayout *swapchainImageLayouts; 369 VkSemaphore *imageAvailableSemaphores; 370 VkSemaphore *renderingFinishedSemaphores; 371 VkSemaphore currentImageAvailableSemaphore; 372 uint32_t currentSwapchainImageIndex; 373 374 VkPipelineStageFlags *waitDestStageMasks; 375 VkSemaphore *waitRenderSemaphores; 376 uint32_t waitRenderSemaphoreCount; 377 uint32_t waitRenderSemaphoreMax; 378 VkSemaphore *signalRenderSemaphores; 379 uint32_t signalRenderSemaphoreCount; 380 uint32_t signalRenderSemaphoreMax; 381 382 // Cached renderer properties 383 VULKAN_TextureData *textureRenderTarget; 384 bool cliprectDirty; 385 bool currentCliprectEnabled; 386 SDL_Rect currentCliprect; 387 SDL_Rect currentViewport; 388 int currentViewportRotation; 389 bool viewportDirty; 390 Float4X4 identity; 391 VkComponentMapping identitySwizzle; 392 int currentVertexBuffer; 393 bool issueBatch; 394} VULKAN_RenderData; 395 396static SDL_PixelFormat VULKAN_VkFormatToSDLPixelFormat(VkFormat vkFormat) 397{ 398 switch (vkFormat) { 399 case VK_FORMAT_B8G8R8A8_UNORM: 400 return SDL_PIXELFORMAT_ARGB8888; 401 case VK_FORMAT_A2R10G10B10_UNORM_PACK32: 402 return SDL_PIXELFORMAT_XBGR2101010; 403 case VK_FORMAT_R16G16B16A16_SFLOAT: 404 return SDL_PIXELFORMAT_RGBA64_FLOAT; 405 default: 406 return SDL_PIXELFORMAT_UNKNOWN; 407 } 408} 409 410static int VULKAN_VkFormatGetNumPlanes(VkFormat vkFormat) 411{ 412 switch (vkFormat) { 413 case VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM: 414 return 3; 415 case VK_FORMAT_G8_B8R8_2PLANE_420_UNORM: 416 case VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16: 417 return 2; 418 default: 419 return 1; 420 } 421} 422 423static VkDeviceSize VULKAN_GetBytesPerPixel(VkFormat vkFormat) 424{ 425 switch (vkFormat) { 426 case VK_FORMAT_R8_UNORM: 427 return 1; 428 case VK_FORMAT_R8G8_UNORM: 429 return 2; 430 case VK_FORMAT_R16G16_UNORM: 431 return 4; 432 case VK_FORMAT_B8G8R8A8_SRGB: 433 case VK_FORMAT_B8G8R8A8_UNORM: 434 case VK_FORMAT_A2R10G10B10_UNORM_PACK32: 435 return 4; 436 case VK_FORMAT_R16G16B16A16_SFLOAT: 437 return 8; 438 default: 439 return 4; 440 } 441} 442 443static VkFormat SDLPixelFormatToVkTextureFormat(Uint32 format, Uint32 output_colorspace) 444{ 445 switch (format) { 446 case SDL_PIXELFORMAT_RGBA64_FLOAT: 447 return VK_FORMAT_R16G16B16A16_SFLOAT; 448 case SDL_PIXELFORMAT_XBGR2101010: 449 return VK_FORMAT_A2B10G10R10_UNORM_PACK32; 450 case SDL_PIXELFORMAT_ARGB8888: 451 case SDL_PIXELFORMAT_XRGB8888: 452 if (output_colorspace == SDL_COLORSPACE_SRGB_LINEAR) { 453 return VK_FORMAT_B8G8R8A8_SRGB; 454 } 455 return VK_FORMAT_B8G8R8A8_UNORM; 456 case SDL_PIXELFORMAT_YUY2: 457 return VK_FORMAT_G8B8G8R8_422_UNORM; 458 case SDL_PIXELFORMAT_UYVY: 459 return VK_FORMAT_B8G8R8G8_422_UNORM; 460 case SDL_PIXELFORMAT_YV12: 461 case SDL_PIXELFORMAT_IYUV: 462 return VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM; 463 case SDL_PIXELFORMAT_NV12: 464 case SDL_PIXELFORMAT_NV21: 465 return VK_FORMAT_G8_B8R8_2PLANE_420_UNORM; 466 case SDL_PIXELFORMAT_P010: 467 return VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16; 468 default: 469 return VK_FORMAT_UNDEFINED; 470 } 471} 472 473static void VULKAN_DestroyTexture(SDL_Renderer *renderer, SDL_Texture *texture); 474static void VULKAN_DestroyBuffer(VULKAN_RenderData *rendererData, VULKAN_Buffer *vulkanBuffer); 475static void VULKAN_DestroyImage(VULKAN_RenderData *rendererData, VULKAN_Image *vulkanImage); 476static void VULKAN_ResetCommandList(VULKAN_RenderData *rendererData); 477static bool VULKAN_FindMemoryTypeIndex(VULKAN_RenderData *rendererData, uint32_t typeBits, VkMemoryPropertyFlags requiredFlags, VkMemoryPropertyFlags desiredFlags, uint32_t *memoryTypeIndexOut); 478static VkResult VULKAN_CreateWindowSizeDependentResources(SDL_Renderer *renderer); 479static VkDescriptorPool VULKAN_AllocateDescriptorPool(VULKAN_RenderData *rendererData); 480static VkResult VULKAN_CreateDescriptorSetAndPipelineLayout(VULKAN_RenderData *rendererData, VkSampler samplerYcbcr, VkDescriptorSetLayout *descriptorSetLayoutOut, VkPipelineLayout *pipelineLayoutOut); 481static VkSurfaceTransformFlagBitsKHR VULKAN_GetRotationForCurrentRenderTarget(VULKAN_RenderData *rendererData); 482static bool VULKAN_IsDisplayRotated90Degrees(VkSurfaceTransformFlagBitsKHR rotation); 483 484static void VULKAN_DestroyAll(SDL_Renderer *renderer) 485{ 486 VULKAN_RenderData *rendererData; 487 if (renderer == NULL) { 488 return; 489 } 490 rendererData = (VULKAN_RenderData *)renderer->internal; 491 if (rendererData == NULL) { 492 return; 493 } 494 495 // Release all textures 496 for (SDL_Texture *texture = renderer->textures; texture; texture = texture->next) { 497 VULKAN_DestroyTexture(renderer, texture); 498 } 499 500 if (rendererData->waitDestStageMasks) { 501 SDL_free(rendererData->waitDestStageMasks); 502 rendererData->waitDestStageMasks = NULL; 503 } 504 if (rendererData->waitRenderSemaphores) { 505 SDL_free(rendererData->waitRenderSemaphores); 506 rendererData->waitRenderSemaphores = NULL; 507 } 508 if (rendererData->signalRenderSemaphores) { 509 SDL_free(rendererData->signalRenderSemaphores); 510 rendererData->signalRenderSemaphores = NULL; 511 } 512 if (rendererData->surfaceFormats != NULL) { 513 SDL_free(rendererData->surfaceFormats); 514 rendererData->surfaceFormats = NULL; 515 rendererData->surfaceFormatsAllocatedCount = 0; 516 } 517 if (rendererData->swapchainImages != NULL) { 518 SDL_free(rendererData->swapchainImages); 519 rendererData->swapchainImages = NULL; 520 } 521 if (rendererData->swapchain) { 522 vkDestroySwapchainKHR(rendererData->device, rendererData->swapchain, NULL); 523 rendererData->swapchain = VK_NULL_HANDLE; 524 } 525 if (rendererData->fences != NULL) { 526 for (uint32_t i = 0; i < rendererData->swapchainImageCount; i++) { 527 if (rendererData->fences[i] != VK_NULL_HANDLE) { 528 vkDestroyFence(rendererData->device, rendererData->fences[i], NULL); 529 rendererData->fences[i] = VK_NULL_HANDLE; 530 } 531 } 532 SDL_free(rendererData->fences); 533 rendererData->fences = NULL; 534 } 535 if (rendererData->swapchainImageViews) { 536 for (uint32_t i = 0; i < rendererData->swapchainImageCount; i++) { 537 if (rendererData->swapchainImageViews[i] != VK_NULL_HANDLE) { 538 vkDestroyImageView(rendererData->device, rendererData->swapchainImageViews[i], NULL); 539 } 540 } 541 SDL_free(rendererData->swapchainImageViews); 542 rendererData->swapchainImageViews = NULL; 543 } 544 if (rendererData->swapchainImageLayouts) { 545 SDL_free(rendererData->swapchainImageLayouts); 546 rendererData->swapchainImageLayouts = NULL; 547 } 548 if (rendererData->framebuffers) { 549 for (uint32_t i = 0; i < rendererData->swapchainImageCount; i++) { 550 if (rendererData->framebuffers[i] != VK_NULL_HANDLE) { 551 vkDestroyFramebuffer(rendererData->device, rendererData->framebuffers[i], NULL); 552 } 553 } 554 SDL_free(rendererData->framebuffers); 555 rendererData->framebuffers = NULL; 556 } 557 for (uint32_t i = 0; i < SDL_arraysize(rendererData->samplers); i++) { 558 if (rendererData->samplers[i] != VK_NULL_HANDLE) { 559 vkDestroySampler(rendererData->device, rendererData->samplers[i], NULL); 560 rendererData->samplers[i] = VK_NULL_HANDLE; 561 } 562 } 563 for (uint32_t i = 0; i < SDL_arraysize(rendererData->vertexBuffers); i++ ) { 564 VULKAN_DestroyBuffer(rendererData, &rendererData->vertexBuffers[i]); 565 } 566 SDL_memset(rendererData->vertexBuffers, 0, sizeof(rendererData->vertexBuffers)); 567 for (uint32_t i = 0; i < VULKAN_RENDERPASS_COUNT; i++) { 568 if (rendererData->renderPasses[i] != VK_NULL_HANDLE) { 569 vkDestroyRenderPass(rendererData->device, rendererData->renderPasses[i], NULL); 570 rendererData->renderPasses[i] = VK_NULL_HANDLE; 571 } 572 } 573 if (rendererData->imageAvailableSemaphores) { 574 for (uint32_t i = 0; i < rendererData->swapchainImageCount; ++i) { 575 if (rendererData->imageAvailableSemaphores[i] != VK_NULL_HANDLE) { 576 vkDestroySemaphore(rendererData->device, rendererData->imageAvailableSemaphores[i], NULL); 577 } 578 } 579 SDL_free(rendererData->imageAvailableSemaphores); 580 rendererData->imageAvailableSemaphores = NULL; 581 } 582 if (rendererData->renderingFinishedSemaphores) { 583 for (uint32_t i = 0; i < rendererData->swapchainImageCount; ++i) { 584 if (rendererData->renderingFinishedSemaphores[i] != VK_NULL_HANDLE) { 585 vkDestroySemaphore(rendererData->device, rendererData->renderingFinishedSemaphores[i], NULL); 586 } 587 } 588 SDL_free(rendererData->renderingFinishedSemaphores); 589 rendererData->renderingFinishedSemaphores = NULL; 590 } 591 if (rendererData->commandBuffers) { 592 vkFreeCommandBuffers(rendererData->device, rendererData->commandPool, rendererData->swapchainImageCount, rendererData->commandBuffers); 593 SDL_free(rendererData->commandBuffers); 594 rendererData->commandBuffers = NULL; 595 rendererData->currentCommandBuffer = VK_NULL_HANDLE; 596 rendererData->currentCommandBufferIndex = 0; 597 } 598 if (rendererData->commandPool) { 599 vkDestroyCommandPool(rendererData->device, rendererData->commandPool, NULL); 600 rendererData->commandPool = VK_NULL_HANDLE; 601 } 602 if (rendererData->descriptorPools) { 603 SDL_assert(rendererData->numDescriptorPools); 604 for (uint32_t i = 0; i < rendererData->swapchainImageCount; i++) { 605 for (uint32_t j = 0; j < rendererData->numDescriptorPools[i]; j++) { 606 if (rendererData->descriptorPools[i][j] != VK_NULL_HANDLE) { 607 vkDestroyDescriptorPool(rendererData->device, rendererData->descriptorPools[i][j], NULL); 608 } 609 } 610 SDL_free(rendererData->descriptorPools[i]); 611 } 612 SDL_free(rendererData->descriptorPools); 613 rendererData->descriptorPools = NULL; 614 SDL_free(rendererData->numDescriptorPools); 615 rendererData->numDescriptorPools = NULL; 616 } 617 for (uint32_t i = 0; i < NUM_SHADERS; i++) { 618 if (rendererData->vertexShaderModules[i] != VK_NULL_HANDLE) { 619 vkDestroyShaderModule(rendererData->device, rendererData->vertexShaderModules[i], NULL); 620 rendererData->vertexShaderModules[i] = VK_NULL_HANDLE; 621 } 622 if (rendererData->fragmentShaderModules[i] != VK_NULL_HANDLE) { 623 vkDestroyShaderModule(rendererData->device, rendererData->fragmentShaderModules[i], NULL); 624 rendererData->fragmentShaderModules[i] = VK_NULL_HANDLE; 625 } 626 } 627 if (rendererData->descriptorSetLayout != VK_NULL_HANDLE) { 628 vkDestroyDescriptorSetLayout(rendererData->device, rendererData->descriptorSetLayout, NULL); 629 rendererData->descriptorSetLayout = VK_NULL_HANDLE; 630 } 631 if (rendererData->pipelineLayout != VK_NULL_HANDLE) { 632 vkDestroyPipelineLayout(rendererData->device, rendererData->pipelineLayout, NULL); 633 rendererData->pipelineLayout = VK_NULL_HANDLE; 634 } 635 for (int i = 0; i < rendererData->pipelineStateCount; i++) { 636 vkDestroyPipeline(rendererData->device, rendererData->pipelineStates[i].pipeline, NULL); 637 } 638 SDL_free(rendererData->pipelineStates); 639 rendererData->pipelineStates = NULL; 640 rendererData->pipelineStateCount = 0; 641 642 if (rendererData->currentUploadBuffer) { 643 for (uint32_t i = 0; i < rendererData->swapchainImageCount; ++i) { 644 for (int j = 0; j < rendererData->currentUploadBuffer[i]; ++j) { 645 VULKAN_DestroyBuffer(rendererData, &rendererData->uploadBuffers[i][j]); 646 } 647 SDL_free(rendererData->uploadBuffers[i]); 648 } 649 SDL_free(rendererData->uploadBuffers); 650 rendererData->uploadBuffers = NULL; 651 SDL_free(rendererData->currentUploadBuffer); 652 rendererData->currentUploadBuffer = NULL; 653 } 654 655 if (rendererData->constantBuffers) { 656 SDL_assert(rendererData->numConstantBuffers); 657 for (uint32_t i = 0; i < rendererData->swapchainImageCount; ++i) { 658 for (uint32_t j = 0; j < rendererData->numConstantBuffers[i]; j++) { 659 VULKAN_DestroyBuffer(rendererData, &rendererData->constantBuffers[i][j]); 660 } 661 SDL_free(rendererData->constantBuffers[i]); 662 } 663 SDL_free(rendererData->constantBuffers); 664 rendererData->constantBuffers = NULL; 665 SDL_free(rendererData->numConstantBuffers); 666 rendererData->numConstantBuffers = NULL; 667 } 668 669 if (rendererData->device != VK_NULL_HANDLE && !rendererData->device_external) { 670 vkDestroyDevice(rendererData->device, NULL); 671 rendererData->device = VK_NULL_HANDLE; 672 } 673 if (rendererData->surface != VK_NULL_HANDLE && !rendererData->surface_external) { 674 vkDestroySurfaceKHR(rendererData->instance, rendererData->surface, NULL); 675 rendererData->surface = VK_NULL_HANDLE; 676 } 677 if (rendererData->instance != VK_NULL_HANDLE && !rendererData->instance_external) { 678 vkDestroyInstance(rendererData->instance, NULL); 679 rendererData->instance = VK_NULL_HANDLE; 680 } 681} 682 683static void VULKAN_DestroyBuffer(VULKAN_RenderData *rendererData, VULKAN_Buffer *vulkanBuffer) 684{ 685 if (vulkanBuffer->buffer != VK_NULL_HANDLE) { 686 vkDestroyBuffer(rendererData->device, vulkanBuffer->buffer, NULL); 687 vulkanBuffer->buffer = VK_NULL_HANDLE; 688 } 689 if (vulkanBuffer->deviceMemory != VK_NULL_HANDLE) { 690 vkFreeMemory(rendererData->device, vulkanBuffer->deviceMemory, NULL); 691 vulkanBuffer->deviceMemory = VK_NULL_HANDLE; 692 } 693 SDL_memset(vulkanBuffer, 0, sizeof(VULKAN_Buffer)); 694} 695 696static VkResult VULKAN_AllocateBuffer(VULKAN_RenderData *rendererData, VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags requiredMemoryProps, VkMemoryPropertyFlags desiredMemoryProps, VULKAN_Buffer *bufferOut) 697{ 698 VkResult result; 699 VkBufferCreateInfo bufferCreateInfo = { 0 }; 700 bufferCreateInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; 701 bufferCreateInfo.size = size; 702 bufferCreateInfo.usage = usage; 703 result = vkCreateBuffer(rendererData->device, &bufferCreateInfo, NULL, &bufferOut->buffer); 704 if (result != VK_SUCCESS) { 705 SET_ERROR_CODE("vkCreateBuffer()", result); 706 return result; 707 } 708 709 VkMemoryRequirements memoryRequirements = { 0 }; 710 vkGetBufferMemoryRequirements(rendererData->device, bufferOut->buffer, &memoryRequirements); 711 if (result != VK_SUCCESS) { 712 VULKAN_DestroyBuffer(rendererData, bufferOut); 713 SET_ERROR_CODE("vkGetBufferMemoryRequirements()", result); 714 return result; 715 } 716 717 uint32_t memoryTypeIndex = 0; 718 if (!VULKAN_FindMemoryTypeIndex(rendererData, memoryRequirements.memoryTypeBits, requiredMemoryProps, desiredMemoryProps, &memoryTypeIndex)) { 719 VULKAN_DestroyBuffer(rendererData, bufferOut); 720 return VK_ERROR_UNKNOWN; 721 } 722 723 VkMemoryAllocateInfo memoryAllocateInfo = { 0 }; 724 memoryAllocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; 725 memoryAllocateInfo.allocationSize = memoryRequirements.size; 726 memoryAllocateInfo.memoryTypeIndex = memoryTypeIndex; 727 result = vkAllocateMemory(rendererData->device, &memoryAllocateInfo, NULL, &bufferOut->deviceMemory); 728 if (result != VK_SUCCESS) { 729 VULKAN_DestroyBuffer(rendererData, bufferOut); 730 SET_ERROR_CODE("vkAllocateMemory()", result); 731 return result; 732 } 733 result = vkBindBufferMemory(rendererData->device, bufferOut->buffer, bufferOut->deviceMemory, 0); 734 if (result != VK_SUCCESS) { 735 VULKAN_DestroyBuffer(rendererData, bufferOut); 736 SET_ERROR_CODE("vkBindBufferMemory()", result); 737 return result; 738 } 739 740 result = vkMapMemory(rendererData->device, bufferOut->deviceMemory, 0, size, 0, &bufferOut->mappedBufferPtr); 741 if (result != VK_SUCCESS) { 742 VULKAN_DestroyBuffer(rendererData, bufferOut); 743 SET_ERROR_CODE("vkMapMemory()", result); 744 return result; 745 } 746 bufferOut->size = size; 747 return result; 748} 749 750static void VULKAN_DestroyImage(VULKAN_RenderData *rendererData, VULKAN_Image *vulkanImage) 751{ 752 if (vulkanImage->imageView != VK_NULL_HANDLE) { 753 vkDestroyImageView(rendererData->device, vulkanImage->imageView, NULL); 754 vulkanImage->imageView = VK_NULL_HANDLE; 755 } 756 if (vulkanImage->image != VK_NULL_HANDLE) { 757 if (vulkanImage->allocatedImage) { 758 vkDestroyImage(rendererData->device, vulkanImage->image, NULL); 759 } 760 vulkanImage->image = VK_NULL_HANDLE; 761 } 762 763 if (vulkanImage->deviceMemory != VK_NULL_HANDLE) { 764 if (vulkanImage->allocatedImage) { 765 vkFreeMemory(rendererData->device, vulkanImage->deviceMemory, NULL); 766 } 767 vulkanImage->deviceMemory = VK_NULL_HANDLE; 768 } 769 SDL_memset(vulkanImage, 0, sizeof(VULKAN_Image)); 770} 771 772static 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) 773{ 774 VkResult result; 775 VkSamplerYcbcrConversionInfoKHR samplerYcbcrConversionInfo = { 0 }; 776 777 SDL_memset(imageOut, 0, sizeof(VULKAN_Image)); 778 imageOut->format = format; 779 imageOut->image = (VkImage)SDL_GetNumberProperty(create_props, SDL_PROP_TEXTURE_CREATE_VULKAN_TEXTURE_NUMBER, 0); 780 781 if (imageOut->image == VK_NULL_HANDLE) { 782 imageOut->allocatedImage = VK_TRUE; 783 784 VkImageCreateInfo imageCreateInfo = { 0 }; 785 imageCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; 786 imageCreateInfo.flags = 0; 787 imageCreateInfo.imageType = VK_IMAGE_TYPE_2D; 788 imageCreateInfo.format = format; 789 imageCreateInfo.extent.width = width; 790 imageCreateInfo.extent.height = height; 791 imageCreateInfo.extent.depth = 1; 792 imageCreateInfo.mipLevels = 1; 793 imageCreateInfo.arrayLayers = 1; 794 imageCreateInfo.samples = VK_SAMPLE_COUNT_1_BIT; 795 imageCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL; 796 imageCreateInfo.usage = imageUsage; 797 imageCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; 798 imageCreateInfo.queueFamilyIndexCount = 0; 799 imageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; 800 801 result = vkCreateImage(rendererData->device, &imageCreateInfo, NULL, &imageOut->image); 802 if (result != VK_SUCCESS) { 803 VULKAN_DestroyImage(rendererData, imageOut); 804 SET_ERROR_CODE("vkCreateImage()", result); 805 return result; 806 } 807 808 VkMemoryRequirements memoryRequirements = { 0 }; 809 vkGetImageMemoryRequirements(rendererData->device, imageOut->image, &memoryRequirements); 810 if (result != VK_SUCCESS) { 811 VULKAN_DestroyImage(rendererData, imageOut); 812 SET_ERROR_CODE("vkGetImageMemoryRequirements()", result); 813 return result; 814 } 815 816 uint32_t memoryTypeIndex = 0; 817 if (!VULKAN_FindMemoryTypeIndex(rendererData, memoryRequirements.memoryTypeBits, 0, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &memoryTypeIndex)) { 818 VULKAN_DestroyImage(rendererData, imageOut); 819 return VK_ERROR_UNKNOWN; 820 } 821 822 VkMemoryAllocateInfo memoryAllocateInfo = { 0 }; 823 memoryAllocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; 824 memoryAllocateInfo.allocationSize = memoryRequirements.size; 825 memoryAllocateInfo.memoryTypeIndex = memoryTypeIndex; 826 result = vkAllocateMemory(rendererData->device, &memoryAllocateInfo, NULL, &imageOut->deviceMemory); 827 if (result != VK_SUCCESS) { 828 VULKAN_DestroyImage(rendererData, imageOut); 829 SET_ERROR_CODE("vkAllocateMemory()", result); 830 return result; 831 } 832 result = vkBindImageMemory(rendererData->device, imageOut->image, imageOut->deviceMemory, 0); 833 if (result != VK_SUCCESS) { 834 VULKAN_DestroyImage(rendererData, imageOut); 835 SET_ERROR_CODE("vkBindImageMemory()", result); 836 return result; 837 } 838 } else { 839 imageOut->imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; 840 } 841 842 VkImageViewCreateInfo imageViewCreateInfo = { 0 }; 843 imageViewCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; 844 imageViewCreateInfo.image = imageOut->image; 845 imageViewCreateInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; 846 imageViewCreateInfo.format = format; 847 imageViewCreateInfo.components = swizzle; 848 imageViewCreateInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; 849 imageViewCreateInfo.subresourceRange.baseMipLevel = 0; 850 imageViewCreateInfo.subresourceRange.levelCount = 1; 851 imageViewCreateInfo.subresourceRange.baseArrayLayer = 0; 852 imageViewCreateInfo.subresourceRange.layerCount = 1; 853 854 // If it's a YCbCr image, we need to pass the conversion info to the VkImageView (and the VkSampler) 855 if (samplerYcbcrConversion != VK_NULL_HANDLE) { 856 samplerYcbcrConversionInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO_KHR; 857 samplerYcbcrConversionInfo.conversion = samplerYcbcrConversion; 858 imageViewCreateInfo.pNext = &samplerYcbcrConversionInfo; 859 } 860 861 result = vkCreateImageView(rendererData->device, &imageViewCreateInfo, NULL, &imageOut->imageView); 862 if (result != VK_SUCCESS) { 863 VULKAN_DestroyImage(rendererData, imageOut); 864 SET_ERROR_CODE("vkCreateImageView()", result); 865 return result; 866 } 867 868 return result; 869} 870 871 872static void VULKAN_RecordPipelineImageBarrier(VULKAN_RenderData *rendererData, VkAccessFlags sourceAccessMask, VkAccessFlags destAccessMask, 873 VkPipelineStageFlags srcStageFlags, VkPipelineStageFlags dstStageFlags, VkImageLayout destLayout, VkImage image, VkImageLayout *imageLayout) 874{ 875 // Stop any outstanding renderpass if open 876 if (rendererData->currentRenderPass != VK_NULL_HANDLE) { 877 vkCmdEndRenderPass(rendererData->currentCommandBuffer); 878 rendererData->currentRenderPass = VK_NULL_HANDLE; 879 } 880 881 VkImageMemoryBarrier barrier = { 0 }; 882 barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; 883 barrier.srcAccessMask = sourceAccessMask; 884 barrier.dstAccessMask = destAccessMask; 885 barrier.oldLayout = *imageLayout; 886 barrier.newLayout = destLayout; 887 barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; 888 barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; 889 barrier.image = image; 890 barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; 891 barrier.subresourceRange.baseMipLevel = 0; 892 barrier.subresourceRange.levelCount = 1; 893 barrier.subresourceRange.baseArrayLayer = 0; 894 barrier.subresourceRange.layerCount = 1; 895 vkCmdPipelineBarrier(rendererData->currentCommandBuffer, srcStageFlags, dstStageFlags, 0, 0, NULL, 0, NULL, 1, &barrier); 896 *imageLayout = destLayout; 897} 898 899static VkResult VULKAN_AcquireNextSwapchainImage(SDL_Renderer *renderer) 900{ 901 VULKAN_RenderData *rendererData = ( VULKAN_RenderData * )renderer->internal; 902 903 VkResult result; 904 905 rendererData->currentImageAvailableSemaphore = VK_NULL_HANDLE; 906 result = vkAcquireNextImageKHR(rendererData->device, rendererData->swapchain, UINT64_MAX, 907 rendererData->imageAvailableSemaphores[rendererData->currentCommandBufferIndex], VK_NULL_HANDLE, &rendererData->currentSwapchainImageIndex); 908 if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_ERROR_SURFACE_LOST_KHR) { 909 result = VULKAN_CreateWindowSizeDependentResources(renderer); 910 return result; 911 } else if(result == VK_SUBOPTIMAL_KHR) { 912 // Suboptimal, but we can contiue 913 } else if (result != VK_SUCCESS) { 914 SET_ERROR_CODE("vkAcquireNextImageKHR()", result); 915 return result; 916 } 917 rendererData->currentImageAvailableSemaphore = rendererData->imageAvailableSemaphores[rendererData->currentCommandBufferIndex]; 918 return result; 919} 920 921static void VULKAN_BeginRenderPass(VULKAN_RenderData *rendererData, VkAttachmentLoadOp loadOp, VkClearColorValue *clearColor) 922{ 923 int width = rendererData->swapchainSize.width; 924 int height = rendererData->swapchainSize.height; 925 if (rendererData->textureRenderTarget) { 926 width = rendererData->textureRenderTarget->width; 927 height = rendererData->textureRenderTarget->height; 928 } 929 930 switch (loadOp) { 931 case VK_ATTACHMENT_LOAD_OP_CLEAR: 932 rendererData->currentRenderPass = rendererData->textureRenderTarget ? 933 rendererData->textureRenderTarget->mainRenderpasses[VULKAN_RENDERPASS_CLEAR] : 934 rendererData->renderPasses[VULKAN_RENDERPASS_CLEAR]; 935 break; 936 937 case VK_ATTACHMENT_LOAD_OP_LOAD: 938 default: 939 rendererData->currentRenderPass = rendererData->textureRenderTarget ? 940 rendererData->textureRenderTarget->mainRenderpasses[VULKAN_RENDERPASS_LOAD] : 941 rendererData->renderPasses[VULKAN_RENDERPASS_LOAD]; 942 break; 943 } 944 945 VkFramebuffer framebuffer = rendererData->textureRenderTarget ? 946 rendererData->textureRenderTarget->mainFramebuffer : 947 rendererData->framebuffers[rendererData->currentSwapchainImageIndex]; 948 949 VkRenderPassBeginInfo renderPassBeginInfo = { 0 }; 950 renderPassBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; 951 renderPassBeginInfo.pNext = NULL; 952 renderPassBeginInfo.renderPass = rendererData->currentRenderPass; 953 renderPassBeginInfo.framebuffer = framebuffer; 954 renderPassBeginInfo.renderArea.offset.x = 0; 955 renderPassBeginInfo.renderArea.offset.y = 0; 956 renderPassBeginInfo.renderArea.extent.width = width; 957 renderPassBeginInfo.renderArea.extent.height = height; 958 renderPassBeginInfo.clearValueCount = (clearColor == NULL) ? 0 : 1; 959 VkClearValue clearValue; 960 if (clearColor != NULL) { 961 clearValue.color = *clearColor; 962 renderPassBeginInfo.pClearValues = &clearValue; 963 } 964 vkCmdBeginRenderPass(rendererData->currentCommandBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); 965} 966 967static void VULKAN_EnsureCommandBuffer(VULKAN_RenderData *rendererData) 968{ 969 if (rendererData->currentCommandBuffer == VK_NULL_HANDLE) { 970 rendererData->currentCommandBuffer = rendererData->commandBuffers[rendererData->currentCommandBufferIndex]; 971 VULKAN_ResetCommandList(rendererData); 972 973 // Ensure the swapchain is in the correct layout 974 if (rendererData->swapchainImageLayouts[rendererData->currentSwapchainImageIndex] == VK_IMAGE_LAYOUT_UNDEFINED) { 975 VULKAN_RecordPipelineImageBarrier(rendererData, 976 0, 977 VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, 978 VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, 979 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 980 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, 981 rendererData->swapchainImages[rendererData->currentSwapchainImageIndex], 982 &rendererData->swapchainImageLayouts[rendererData->currentSwapchainImageIndex]); 983 } 984 else if (rendererData->swapchainImageLayouts[rendererData->currentCommandBufferIndex] != VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) { 985 VULKAN_RecordPipelineImageBarrier(rendererData, 986 VK_ACCESS_COLOR_ATTACHMENT_READ_BIT, 987 VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, 988 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 989 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 990 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, 991 rendererData->swapchainImages[rendererData->currentSwapchainImageIndex], 992 &rendererData->swapchainImageLayouts[rendererData->currentSwapchainImageIndex]); 993 } 994 } 995} 996 997static bool VULKAN_ActivateCommandBuffer(SDL_Renderer *renderer, VkAttachmentLoadOp loadOp, VkClearColorValue *clearColor, VULKAN_DrawStateCache *stateCache) 998{ 999 VULKAN_RenderData *rendererData = (VULKAN_RenderData *)renderer->internal; 1000 1001 VULKAN_EnsureCommandBuffer(rendererData); 1002 1003 if (rendererData->currentRenderPass == VK_NULL_HANDLE || loadOp == VK_ATTACHMENT_LOAD_OP_CLEAR) { 1004 if (rendererData->currentRenderPass != VK_NULL_HANDLE) { 1005 vkCmdEndRenderPass(rendererData->currentCommandBuffer); 1006 rendererData->currentRenderPass = VK_NULL_HANDLE; 1007 } 1008 VULKAN_BeginRenderPass(rendererData, loadOp, clearColor); 1009 } 1010 1011 // Bind cached VB now 1012 if (stateCache->vertexBuffer != VK_NULL_HANDLE) { 1013 VkDeviceSize offset = 0; 1014 vkCmdBindVertexBuffers(rendererData->currentCommandBuffer, 0, 1, &stateCache->vertexBuffer, &offset); 1015 } 1016 1017 return true; 1018} 1019 1020static void VULKAN_WaitForGPU(VULKAN_RenderData *rendererData) 1021{ 1022 vkQueueWaitIdle(rendererData->graphicsQueue); 1023} 1024 1025 1026static void VULKAN_ResetCommandList(VULKAN_RenderData *rendererData) 1027{ 1028 vkResetCommandBuffer(rendererData->currentCommandBuffer, 0); 1029 for (uint32_t i = 0; i < rendererData->numDescriptorPools[rendererData->currentCommandBufferIndex]; i++) { 1030 vkResetDescriptorPool(rendererData->device, rendererData->descriptorPools[rendererData->currentCommandBufferIndex][i], 0); 1031 } 1032 1033 VkCommandBufferBeginInfo beginInfo = { 0 }; 1034 beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; 1035 beginInfo.flags = 0; 1036 vkBeginCommandBuffer(rendererData->currentCommandBuffer, &beginInfo); 1037 1038 rendererData->currentPipelineState = NULL; 1039 rendererData->currentVertexBuffer = 0; 1040 rendererData->issueBatch = false; 1041 rendererData->cliprectDirty = true; 1042 rendererData->currentDescriptorSetIndex = 0; 1043 rendererData->currentDescriptorPoolIndex = 0; 1044 rendererData->currentConstantBufferOffset = -1; 1045 rendererData->currentConstantBufferIndex = 0; 1046 1047 // Release any upload buffers that were inflight 1048 for (int i = 0; i < rendererData->currentUploadBuffer[rendererData->currentCommandBufferIndex]; ++i) { 1049 VULKAN_DestroyBuffer(rendererData, &rendererData->uploadBuffers[rendererData->currentCommandBufferIndex][i]); 1050 } 1051 rendererData->currentUploadBuffer[rendererData->currentCommandBufferIndex] = 0; 1052} 1053 1054static VkResult VULKAN_IssueBatch(VULKAN_RenderData *rendererData) 1055{ 1056 VkResult result; 1057 if (rendererData->currentCommandBuffer == VK_NULL_HANDLE) { 1058 return VK_SUCCESS; 1059 } 1060 1061 if (rendererData->currentRenderPass) { 1062 vkCmdEndRenderPass(rendererData->currentCommandBuffer); 1063 rendererData->currentRenderPass = VK_NULL_HANDLE; 1064 } 1065 1066 rendererData->currentPipelineState = VK_NULL_HANDLE; 1067 rendererData->viewportDirty = true; 1068 1069 vkEndCommandBuffer(rendererData->currentCommandBuffer); 1070 1071 VkSubmitInfo submitInfo = { 0 }; 1072 VkPipelineStageFlags waitDestStageMask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT; 1073 submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; 1074 submitInfo.commandBufferCount = 1; 1075 submitInfo.pCommandBuffers = &rendererData->currentCommandBuffer; 1076 if (rendererData->waitRenderSemaphoreCount > 0) { 1077 Uint32 additionalSemaphoreCount = (rendererData->currentImageAvailableSemaphore != VK_NULL_HANDLE) ? 1 : 0; 1078 submitInfo.waitSemaphoreCount = rendererData->waitRenderSemaphoreCount + additionalSemaphoreCount; 1079 if (additionalSemaphoreCount > 0) { 1080 rendererData->waitRenderSemaphores[rendererData->waitRenderSemaphoreCount] = rendererData->currentImageAvailableSemaphore; 1081 rendererData->waitDestStageMasks[rendererData->waitRenderSemaphoreCount] = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT; 1082 } 1083 submitInfo.pWaitSemaphores = rendererData->waitRenderSemaphores; 1084 submitInfo.pWaitDstStageMask = rendererData->waitDestStageMasks; 1085 rendererData->waitRenderSemaphoreCount = 0; 1086 } else if (rendererData->currentImageAvailableSemaphore != VK_NULL_HANDLE) { 1087 submitInfo.waitSemaphoreCount = 1; 1088 submitInfo.pWaitSemaphores = &rendererData->currentImageAvailableSemaphore; 1089 submitInfo.pWaitDstStageMask = &waitDestStageMask; 1090 } 1091 1092 result = vkQueueSubmit(rendererData->graphicsQueue, 1, &submitInfo, VK_NULL_HANDLE); 1093 rendererData->currentImageAvailableSemaphore = VK_NULL_HANDLE; 1094 1095 VULKAN_WaitForGPU(rendererData); 1096 1097 VULKAN_ResetCommandList(rendererData); 1098 1099 return result; 1100} 1101 1102static void VULKAN_DestroyRenderer(SDL_Renderer *renderer) 1103{ 1104 VULKAN_RenderData *rendererData = (VULKAN_RenderData *)renderer->internal; 1105 if (rendererData) { 1106 if (rendererData->device != VK_NULL_HANDLE) { 1107 vkDeviceWaitIdle(rendererData->device); 1108 VULKAN_DestroyAll(renderer); 1109 } 1110 SDL_free(rendererData); 1111 } 1112} 1113 1114static VkBlendFactor GetBlendFactor(SDL_BlendFactor factor) 1115{ 1116 switch (factor) { 1117 case SDL_BLENDFACTOR_ZERO: 1118 return VK_BLEND_FACTOR_ZERO; 1119 case SDL_BLENDFACTOR_ONE: 1120 return VK_BLEND_FACTOR_ONE; 1121 case SDL_BLENDFACTOR_SRC_COLOR: 1122 return VK_BLEND_FACTOR_SRC_COLOR; 1123 case SDL_BLENDFACTOR_ONE_MINUS_SRC_COLOR: 1124 return VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR; 1125 case SDL_BLENDFACTOR_SRC_ALPHA: 1126 return VK_BLEND_FACTOR_SRC_ALPHA; 1127 case SDL_BLENDFACTOR_ONE_MINUS_SRC_ALPHA: 1128 return VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; 1129 case SDL_BLENDFACTOR_DST_COLOR: 1130 return VK_BLEND_FACTOR_DST_COLOR; 1131 case SDL_BLENDFACTOR_ONE_MINUS_DST_COLOR: 1132 return VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR; 1133 case SDL_BLENDFACTOR_DST_ALPHA: 1134 return VK_BLEND_FACTOR_DST_ALPHA; 1135 case SDL_BLENDFACTOR_ONE_MINUS_DST_ALPHA: 1136 return VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA; 1137 default: 1138 return VK_BLEND_FACTOR_MAX_ENUM; 1139 } 1140} 1141 1142static VkBlendOp GetBlendOp(SDL_BlendOperation operation) 1143{ 1144 switch (operation) { 1145 case SDL_BLENDOPERATION_ADD: 1146 return VK_BLEND_OP_ADD; 1147 case SDL_BLENDOPERATION_SUBTRACT: 1148 return VK_BLEND_OP_SUBTRACT; 1149 case SDL_BLENDOPERATION_REV_SUBTRACT: 1150 return VK_BLEND_OP_REVERSE_SUBTRACT; 1151 case SDL_BLENDOPERATION_MINIMUM: 1152 return VK_BLEND_OP_MIN; 1153 case SDL_BLENDOPERATION_MAXIMUM: 1154 return VK_BLEND_OP_MAX; 1155 default: 1156 return VK_BLEND_OP_MAX_ENUM; 1157 } 1158} 1159 1160 1161static VULKAN_PipelineState *VULKAN_CreatePipelineState(SDL_Renderer *renderer, 1162 VULKAN_Shader shader, VkPipelineLayout pipelineLayout, VkDescriptorSetLayout descriptorSetLayout, SDL_BlendMode blendMode, VkPrimitiveTopology topology, VkFormat format) 1163{ 1164 VULKAN_RenderData *rendererData = (VULKAN_RenderData *)renderer->internal; 1165 VULKAN_PipelineState *pipelineStates; 1166 VkPipeline pipeline = VK_NULL_HANDLE; 1167 VkResult result = VK_SUCCESS; 1168 VkPipelineVertexInputStateCreateInfo vertexInputCreateInfo = { 0 }; 1169 VkPipelineInputAssemblyStateCreateInfo inputAssemblyStateCreateInfo = { 0 }; 1170 VkVertexInputAttributeDescription attributeDescriptions[3]; 1171 VkVertexInputBindingDescription bindingDescriptions[1]; 1172 VkPipelineShaderStageCreateInfo shaderStageCreateInfo[2]; 1173 VkPipelineDynamicStateCreateInfo dynamicStateCreateInfo = { 0 }; 1174 VkPipelineViewportStateCreateInfo viewportStateCreateInfo = { 0 }; 1175 VkPipelineRasterizationStateCreateInfo rasterizationStateCreateInfo = { 0 }; 1176 VkPipelineMultisampleStateCreateInfo multisampleStateCreateInfo = { 0 }; 1177 VkPipelineDepthStencilStateCreateInfo depthStencilStateCreateInfo = { 0 }; 1178 VkPipelineColorBlendStateCreateInfo colorBlendStateCreateInfo = { 0 }; 1179 1180 VkGraphicsPipelineCreateInfo pipelineCreateInfo = { 0 }; 1181 pipelineCreateInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; 1182 pipelineCreateInfo.flags = 0; 1183 pipelineCreateInfo.pStages = shaderStageCreateInfo; 1184 pipelineCreateInfo.pVertexInputState = &vertexInputCreateInfo; 1185 pipelineCreateInfo.pInputAssemblyState = &inputAssemblyStateCreateInfo; 1186 pipelineCreateInfo.pViewportState = &viewportStateCreateInfo; 1187 pipelineCreateInfo.pRasterizationState = &rasterizationStateCreateInfo; 1188 pipelineCreateInfo.pMultisampleState = &multisampleStateCreateInfo; 1189 pipelineCreateInfo.pDepthStencilState = &depthStencilStateCreateInfo; 1190 pipelineCreateInfo.pColorBlendState = &colorBlendStateCreateInfo; 1191 pipelineCreateInfo.pDynamicState = &dynamicStateCreateInfo; 1192 1193 // Shaders 1194 const char *name = "main"; 1195 for (uint32_t i = 0; i < 2; i++) { 1196 SDL_memset(&shaderStageCreateInfo[i], 0, sizeof(shaderStageCreateInfo[i])); 1197 shaderStageCreateInfo[i].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; 1198 shaderStageCreateInfo[i].module = (i == 0) ? rendererData->vertexShaderModules[shader] : rendererData->fragmentShaderModules[shader]; 1199 shaderStageCreateInfo[i].stage = (i == 0) ? VK_SHADER_STAGE_VERTEX_BIT : VK_SHADER_STAGE_FRAGMENT_BIT; 1200 shaderStageCreateInfo[i].pName = name; 1201 } 1202 pipelineCreateInfo.stageCount = 2; 1203 pipelineCreateInfo.pStages = &shaderStageCreateInfo[0]; 1204 1205 1206 // Vertex input 1207 vertexInputCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; 1208 vertexInputCreateInfo.vertexAttributeDescriptionCount = 3; 1209 vertexInputCreateInfo.pVertexAttributeDescriptions = &attributeDescriptions[0]; 1210 vertexInputCreateInfo.vertexBindingDescriptionCount = 1; 1211 vertexInputCreateInfo.pVertexBindingDescriptions = &bindingDescriptions[0]; 1212 1213 attributeDescriptions[ 0 ].binding = 0; 1214 attributeDescriptions[ 0 ].format = VK_FORMAT_R32G32_SFLOAT; 1215 attributeDescriptions[ 0 ].location = 0; 1216 attributeDescriptions[ 0 ].offset = 0; 1217 attributeDescriptions[ 1 ].binding = 0; 1218 attributeDescriptions[ 1 ].format = VK_FORMAT_R32G32_SFLOAT; 1219 attributeDescriptions[ 1 ].location = 1; 1220 attributeDescriptions[ 1 ].offset = 8; 1221 attributeDescriptions[ 2 ].binding = 0; 1222 attributeDescriptions[ 2 ].format = VK_FORMAT_R32G32B32A32_SFLOAT; 1223 attributeDescriptions[ 2 ].location = 2; 1224 attributeDescriptions[ 2 ].offset = 16; 1225 1226 bindingDescriptions[ 0 ].binding = 0; 1227 bindingDescriptions[ 0 ].inputRate = VK_VERTEX_INPUT_RATE_VERTEX; 1228 bindingDescriptions[ 0 ].stride = 32; 1229 1230 // Input assembly 1231 inputAssemblyStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; 1232 inputAssemblyStateCreateInfo.topology = ( VkPrimitiveTopology ) topology; 1233 inputAssemblyStateCreateInfo.primitiveRestartEnable = VK_FALSE; 1234 1235 viewportStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; 1236 viewportStateCreateInfo.scissorCount = 1; 1237 viewportStateCreateInfo.viewportCount = 1; 1238 1239 // Dynamic states 1240 dynamicStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; 1241 VkDynamicState dynamicStates[2] = { 1242 VK_DYNAMIC_STATE_VIEWPORT, 1243 VK_DYNAMIC_STATE_SCISSOR 1244 }; 1245 dynamicStateCreateInfo.dynamicStateCount = SDL_arraysize(dynamicStates); 1246 dynamicStateCreateInfo.pDynamicStates = dynamicStates; 1247 1248 // Rasterization state 1249 rasterizationStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; 1250 rasterizationStateCreateInfo.depthClampEnable = VK_FALSE; 1251 rasterizationStateCreateInfo.rasterizerDiscardEnable = VK_FALSE; 1252 rasterizationStateCreateInfo.cullMode = VK_CULL_MODE_NONE; 1253 rasterizationStateCreateInfo.polygonMode = VK_POLYGON_MODE_FILL; 1254 rasterizationStateCreateInfo.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE; 1255 rasterizationStateCreateInfo.depthBiasEnable = VK_FALSE; 1256 rasterizationStateCreateInfo.depthBiasConstantFactor = 0.0f; 1257 rasterizationStateCreateInfo.depthBiasClamp = 0.0f; 1258 rasterizationStateCreateInfo.depthBiasSlopeFactor = 0.0f; 1259 rasterizationStateCreateInfo.lineWidth = 1.0f; 1260 1261 // MSAA state 1262 multisampleStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; 1263 VkSampleMask multiSampleMask = 0xFFFFFFFF; 1264 multisampleStateCreateInfo.pSampleMask = &multiSampleMask; 1265 multisampleStateCreateInfo.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; 1266 1267 // Depth Stencil 1268 depthStencilStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; 1269 1270 // Color blend 1271 VkPipelineColorBlendAttachmentState colorBlendAttachment = { 0 }; 1272 colorBlendStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; 1273 colorBlendStateCreateInfo.attachmentCount = 1; 1274 colorBlendStateCreateInfo.pAttachments = &colorBlendAttachment; 1275 colorBlendAttachment.blendEnable = VK_TRUE; 1276 colorBlendAttachment.srcColorBlendFactor = GetBlendFactor(SDL_GetBlendModeSrcColorFactor(blendMode)); 1277 colorBlendAttachment.srcAlphaBlendFactor = GetBlendFactor(SDL_GetBlendModeSrcAlphaFactor(blendMode)); 1278 colorBlendAttachment.colorBlendOp = GetBlendOp(SDL_GetBlendModeColorOperation(blendMode)); 1279 colorBlendAttachment.dstColorBlendFactor = GetBlendFactor(SDL_GetBlendModeDstColorFactor(blendMode)); 1280 colorBlendAttachment.dstAlphaBlendFactor = GetBlendFactor(SDL_GetBlendModeDstAlphaFactor(blendMode)); 1281 colorBlendAttachment.alphaBlendOp = GetBlendOp(SDL_GetBlendModeAlphaOperation(blendMode)); 1282 colorBlendAttachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; 1283 1284 // Renderpass / layout 1285 pipelineCreateInfo.renderPass = rendererData->currentRenderPass; 1286 pipelineCreateInfo.subpass = 0; 1287 pipelineCreateInfo.layout = pipelineLayout; 1288 1289 result = vkCreateGraphicsPipelines(rendererData->device, VK_NULL_HANDLE, 1, &pipelineCreateInfo, NULL, &pipeline); 1290 if (result != VK_SUCCESS) { 1291 SET_ERROR_CODE("vkCreateGraphicsPipelines()", result); 1292 return NULL; 1293 } 1294 1295 pipelineStates = (VULKAN_PipelineState *)SDL_realloc(rendererData->pipelineStates, (rendererData->pipelineStateCount + 1) * sizeof(*pipelineStates)); 1296 if (!pipelineStates) { 1297 return NULL; 1298 } 1299 pipelineStates[rendererData->pipelineStateCount].shader = shader; 1300 pipelineStates[rendererData->pipelineStateCount].blendMode = blendMode; 1301 pipelineStates[rendererData->pipelineStateCount].topology = topology; 1302 pipelineStates[rendererData->pipelineStateCount].format = format; 1303 pipelineStates[rendererData->pipelineStateCount].pipeline = pipeline; 1304 pipelineStates[rendererData->pipelineStateCount].descriptorSetLayout = descriptorSetLayout; 1305 pipelineStates[rendererData->pipelineStateCount].pipelineLayout = pipelineCreateInfo.layout; 1306 rendererData->pipelineStates = pipelineStates; 1307 ++rendererData->pipelineStateCount; 1308 1309 return &pipelineStates[rendererData->pipelineStateCount - 1]; 1310} 1311 1312static bool VULKAN_FindMemoryTypeIndex(VULKAN_RenderData *rendererData, uint32_t typeBits, VkMemoryPropertyFlags requiredFlags, VkMemoryPropertyFlags desiredFlags, uint32_t *memoryTypeIndexOut) 1313{ 1314 uint32_t memoryTypeIndex = 0; 1315 bool foundExactMatch = false; 1316 1317 // Desired flags must be a superset of required flags. 1318 desiredFlags |= requiredFlags; 1319 1320 for (memoryTypeIndex = 0; memoryTypeIndex < rendererData->physicalDeviceMemoryProperties.memoryTypeCount; memoryTypeIndex++) { 1321 if (typeBits & (1 << memoryTypeIndex)) { 1322 if (rendererData->physicalDeviceMemoryProperties.memoryTypes[memoryTypeIndex].propertyFlags == desiredFlags) { 1323 foundExactMatch = true; 1324 break; 1325 } 1326 } 1327 } 1328 if (!foundExactMatch) { 1329 for (memoryTypeIndex = 0; memoryTypeIndex < rendererData->physicalDeviceMemoryProperties.memoryTypeCount; memoryTypeIndex++) { 1330 if (typeBits & (1 << memoryTypeIndex)) { 1331 if ((rendererData->physicalDeviceMemoryProperties.memoryTypes[memoryTypeIndex].propertyFlags & requiredFlags) == requiredFlags) { 1332 break; 1333 } 1334 } 1335 } 1336 } 1337 1338 if (memoryTypeIndex >= rendererData->physicalDeviceMemoryProperties.memoryTypeCount) { 1339 SET_ERROR_MESSAGE("Unable to find memory type for allocation"); 1340 return false; 1341 } 1342 *memoryTypeIndexOut = memoryTypeIndex; 1343 return true; 1344} 1345 1346static VkResult VULKAN_CreateVertexBuffer(VULKAN_RenderData *rendererData, size_t vbidx, size_t size) 1347{ 1348 VkResult result; 1349 1350 VULKAN_DestroyBuffer(rendererData, &rendererData->vertexBuffers[vbidx]); 1351 1352 result = VULKAN_AllocateBuffer(rendererData, size, 1353 VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, 1354 VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | 1355 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, 1356 VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, 1357 &rendererData->vertexBuffers[vbidx]); 1358 if (result != VK_SUCCESS) { 1359 return result; 1360 } 1361 return result; 1362} 1363 1364static bool VULKAN_LoadGlobalFunctions(VULKAN_RenderData *rendererData) 1365{ 1366#define VULKAN_DEVICE_FUNCTION(name) 1367#define VULKAN_GLOBAL_FUNCTION(name) \ 1368 name = (PFN_##name)rendererData->vkGetInstanceProcAddr(VK_NULL_HANDLE, #name); \ 1369 if (!name) { \ 1370 SET_ERROR_MESSAGE("vkGetInstanceProcAddr(VK_NULL_HANDLE, \"" #name "\") failed"); \ 1371 return false; \ 1372 } 1373#define VULKAN_INSTANCE_FUNCTION(name) 1374#define VULKAN_OPTIONAL_INSTANCE_FUNCTION(name) 1375#define VULKAN_OPTIONAL_DEVICE_FUNCTION(name) 1376 VULKAN_FUNCTIONS() 1377#undef VULKAN_DEVICE_FUNCTION 1378#undef VULKAN_GLOBAL_FUNCTION 1379#undef VULKAN_INSTANCE_FUNCTION 1380#undef VULKAN_OPTIONAL_INSTANCE_FUNCTION 1381#undef VULKAN_OPTIONAL_DEVICE_FUNCTION 1382 1383 return true; 1384} 1385 1386static bool VULKAN_LoadInstanceFunctions(VULKAN_RenderData *rendererData) 1387{ 1388#define VULKAN_DEVICE_FUNCTION(name) 1389#define VULKAN_GLOBAL_FUNCTION(name) 1390#define VULKAN_INSTANCE_FUNCTION(name) \ 1391 name = (PFN_##name)rendererData->vkGetInstanceProcAddr(rendererData->instance, #name); \ 1392 if (!name) { \ 1393 SET_ERROR_MESSAGE("vkGetInstanceProcAddr(instance, \"" #name "\") failed"); \ 1394 return false; \ 1395 } 1396#define VULKAN_OPTIONAL_INSTANCE_FUNCTION(name) \ 1397 name = (PFN_##name)rendererData->vkGetInstanceProcAddr(rendererData->instance, #name); 1398#define VULKAN_OPTIONAL_DEVICE_FUNCTION(name) 1399 1400 VULKAN_FUNCTIONS() 1401#undef VULKAN_DEVICE_FUNCTION 1402#undef VULKAN_GLOBAL_FUNCTION 1403#undef VULKAN_INSTANCE_FUNCTION 1404#undef VULKAN_OPTIONAL_INSTANCE_FUNCTION 1405#undef VULKAN_OPTIONAL_DEVICE_FUNCTION 1406 1407 return true; 1408} 1409 1410static bool VULKAN_LoadDeviceFunctions(VULKAN_RenderData *rendererData) 1411{ 1412#define VULKAN_DEVICE_FUNCTION(name) \ 1413 name = (PFN_##name)vkGetDeviceProcAddr(rendererData->device, #name); \ 1414 if (!name) { \ 1415 SET_ERROR_MESSAGE("vkGetDeviceProcAddr(device, \"" #name "\") failed"); \ 1416 return false; \ 1417 } 1418#define VULKAN_GLOBAL_FUNCTION(name) 1419#define VULKAN_OPTIONAL_DEVICE_FUNCTION(name) \ 1420 name = (PFN_##name)vkGetDeviceProcAddr(rendererData->device, #name); 1421#define VULKAN_INSTANCE_FUNCTION(name) 1422#define VULKAN_OPTIONAL_INSTANCE_FUNCTION(name) 1423 VULKAN_FUNCTIONS() 1424#undef VULKAN_DEVICE_FUNCTION 1425#undef VULKAN_GLOBAL_FUNCTION 1426#undef VULKAN_INSTANCE_FUNCTION 1427#undef VULKAN_OPTIONAL_INSTANCE_FUNCTION 1428#undef VULKAN_OPTIONAL_DEVICE_FUNCTION 1429 return true; 1430} 1431 1432static VkResult VULKAN_FindPhysicalDevice(VULKAN_RenderData *rendererData) 1433{ 1434 uint32_t physicalDeviceCount = 0; 1435 VkPhysicalDevice *physicalDevices; 1436 VkQueueFamilyProperties *queueFamiliesProperties = NULL; 1437 uint32_t queueFamiliesPropertiesAllocatedSize = 0; 1438 VkExtensionProperties *deviceExtensions = NULL; 1439 uint32_t deviceExtensionsAllocatedSize = 0; 1440 uint32_t physicalDeviceIndex; 1441 VkResult result; 1442 1443 result = vkEnumeratePhysicalDevices(rendererData->instance, &physicalDeviceCount, NULL); 1444 if (result != VK_SUCCESS) { 1445 SET_ERROR_CODE("vkEnumeratePhysicalDevices()", result); 1446 return result; 1447 } 1448 if (physicalDeviceCount == 0) { 1449 SET_ERROR_MESSAGE("vkEnumeratePhysicalDevices(): no physical devices"); 1450 return VK_ERROR_UNKNOWN; 1451 } 1452 physicalDevices = (VkPhysicalDevice *)SDL_malloc(sizeof(VkPhysicalDevice) * physicalDeviceCount); 1453 result = vkEnumeratePhysicalDevices(rendererData->instance, &physicalDeviceCount, physicalDevices); 1454 if (result != VK_SUCCESS) { 1455 SDL_free(physicalDevices); 1456 SET_ERROR_CODE("vkEnumeratePhysicalDevices()", result); 1457 return result; 1458 } 1459 rendererData->physicalDevice = NULL; 1460 for (physicalDeviceIndex = 0; physicalDeviceIndex < physicalDeviceCount; physicalDeviceIndex++) { 1461 uint32_t queueFamiliesCount = 0; 1462 uint32_t queueFamilyIndex; 1463 uint32_t deviceExtensionCount = 0; 1464 bool hasSwapchainExtension = false; 1465 uint32_t i; 1466 1467 VkPhysicalDevice physicalDevice = physicalDevices[physicalDeviceIndex]; 1468 vkGetPhysicalDeviceProperties(physicalDevice, &rendererData->physicalDeviceProperties); 1469 if (VK_VERSION_MAJOR(rendererData->physicalDeviceProperties.apiVersion) < 1) { 1470 continue; 1471 } 1472 vkGetPhysicalDeviceMemoryProperties(physicalDevice, &rendererData->physicalDeviceMemoryProperties); 1473 vkGetPhysicalDeviceFeatures(physicalDevice, &rendererData->physicalDeviceFeatures); 1474 vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueFamiliesCount, NULL); 1475 if (queueFamiliesCount == 0) { 1476 continue; 1477 } 1478 if (queueFamiliesPropertiesAllocatedSize < queueFamiliesCount) { 1479 SDL_free(queueFamiliesProperties); 1480 queueFamiliesPropertiesAllocatedSize = queueFamiliesCount; 1481 queueFamiliesProperties = (VkQueueFamilyProperties *)SDL_malloc(sizeof(VkQueueFamilyProperties) * queueFamiliesPropertiesAllocatedSize); 1482 if (!queueFamiliesProperties) { 1483 SDL_free(physicalDevices); 1484 SDL_free(deviceExtensions); 1485 return VK_ERROR_UNKNOWN; 1486 } 1487 } 1488 vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueFamiliesCount, queueFamiliesProperties); 1489 rendererData->graphicsQueueFamilyIndex = queueFamiliesCount; 1490 rendererData->presentQueueFamilyIndex = queueFamiliesCount; 1491 for (queueFamilyIndex = 0; queueFamilyIndex < queueFamiliesCount; queueFamilyIndex++) { 1492 VkBool32 supported = 0; 1493 1494 if (queueFamiliesProperties[queueFamilyIndex].queueCount == 0) { 1495 continue; 1496 } 1497 1498 if (queueFamiliesProperties[queueFamilyIndex].queueFlags & VK_QUEUE_GRAPHICS_BIT) { 1499 rendererData->graphicsQueueFamilyIndex = queueFamilyIndex; 1500 } 1501 1502 result = vkGetPhysicalDeviceSurfaceSupportKHR(physicalDevice, queueFamilyIndex, rendererData->surface, &supported); 1503 if (result != VK_SUCCESS) { 1504 SDL_free(physicalDevices); 1505 SDL_free(queueFamiliesProperties); 1506 SDL_free(deviceExtensions); 1507 SET_ERROR_CODE("vkGetPhysicalDeviceSurfaceSupportKHR()", result); 1508 return VK_ERROR_UNKNOWN; 1509 } 1510 if (supported) { 1511 rendererData->presentQueueFamilyIndex = queueFamilyIndex; 1512 if (queueFamiliesProperties[queueFamilyIndex].queueFlags & VK_QUEUE_GRAPHICS_BIT) { 1513 break; // use this queue because it can present and do graphics 1514 } 1515 } 1516 } 1517 1518 if (rendererData->graphicsQueueFamilyIndex == queueFamiliesCount) { // no good queues found 1519 continue; 1520 } 1521 if (rendererData->presentQueueFamilyIndex == queueFamiliesCount) { // no good queues found 1522 continue; 1523 } 1524 result = vkEnumerateDeviceExtensionProperties(physicalDevice, NULL, &deviceExtensionCount, NULL); 1525 if (result != VK_SUCCESS) { 1526 SDL_free(physicalDevices); 1527 SDL_free(queueFamiliesProperties); 1528 SDL_free(deviceExtensions); 1529 SET_ERROR_CODE("vkEnumerateDeviceExtensionProperties()", result); 1530 return VK_ERROR_UNKNOWN; 1531 } 1532 if (deviceExtensionCount == 0) { 1533 continue; 1534 } 1535 if (deviceExtensionsAllocatedSize < deviceExtensionCount) { 1536 SDL_free(deviceExtensions); 1537 deviceExtensionsAllocatedSize = deviceExtensionCount; 1538 deviceExtensions = (VkExtensionProperties *)SDL_malloc(sizeof(VkExtensionProperties) * deviceExtensionsAllocatedSize); 1539 if (!deviceExtensions) { 1540 SDL_free(physicalDevices); 1541 SDL_free(queueFamiliesProperties); 1542 return VK_ERROR_UNKNOWN; 1543 } 1544 } 1545 result = vkEnumerateDeviceExtensionProperties(physicalDevice, NULL, &deviceExtensionCount, deviceExtensions); 1546 if (result != VK_SUCCESS) { 1547 SDL_free(physicalDevices); 1548 SDL_free(queueFamiliesProperties); 1549 SDL_free(deviceExtensions); 1550 SET_ERROR_CODE("vkEnumerateDeviceExtensionProperties()", result); 1551 return result; 1552 } 1553 for (i = 0; i < deviceExtensionCount; i++) { 1554 if (SDL_strcmp(deviceExtensions[i].extensionName, VK_KHR_SWAPCHAIN_EXTENSION_NAME) == 0) { 1555 hasSwapchainExtension = true; 1556 break; 1557 } 1558 } 1559 if (!hasSwapchainExtension) { 1560 continue; 1561 } 1562 rendererData->physicalDevice = physicalDevice; 1563 break; 1564 } 1565 SDL_free(physicalDevices); 1566 SDL_free(queueFamiliesProperties); 1567 SDL_free(deviceExtensions); 1568 if (!rendererData->physicalDevice) { 1569 SET_ERROR_MESSAGE("No viable physical devices found"); 1570 return VK_ERROR_UNKNOWN; 1571 } 1572 return VK_SUCCESS; 1573} 1574 1575static VkResult VULKAN_GetSurfaceFormats(VULKAN_RenderData *rendererData) 1576{ 1577 VkResult result = vkGetPhysicalDeviceSurfaceFormatsKHR(rendererData->physicalDevice, 1578 rendererData->surface, 1579 &rendererData->surfaceFormatsCount, 1580 NULL); 1581 if (result != VK_SUCCESS) { 1582 rendererData->surfaceFormatsCount = 0; 1583 SET_ERROR_CODE("vkGetPhysicalDeviceSurfaceFormatsKHR()", result); 1584 return result; 1585 } 1586 if (rendererData->surfaceFormatsCount > rendererData->surfaceFormatsAllocatedCount) { 1587 rendererData->surfaceFormatsAllocatedCount = rendererData->surfaceFormatsCount; 1588 SDL_free(rendererData->surfaceFormats); 1589 rendererData->surfaceFormats = (VkSurfaceFormatKHR *)SDL_malloc(sizeof(VkSurfaceFormatKHR) * rendererData->surfaceFormatsAllocatedCount); 1590 } 1591 result = vkGetPhysicalDeviceSurfaceFormatsKHR(rendererData->physicalDevice, 1592 rendererData->surface, 1593 &rendererData->surfaceFormatsCount, 1594 rendererData->surfaceFormats); 1595 if (result != VK_SUCCESS) { 1596 rendererData->surfaceFormatsCount = 0; 1597 SET_ERROR_CODE("vkGetPhysicalDeviceSurfaceFormatsKHR()", result); 1598 return result; 1599 } 1600 1601 return VK_SUCCESS; 1602} 1603 1604static VkSemaphore VULKAN_CreateSemaphore(VULKAN_RenderData *rendererData) 1605{ 1606 VkResult result; 1607 VkSemaphore semaphore = VK_NULL_HANDLE; 1608 1609 VkSemaphoreCreateInfo semaphoreCreateInfo = { 0 }; 1610 semaphoreCreateInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; 1611 result = vkCreateSemaphore(rendererData->device, &semaphoreCreateInfo, NULL, &semaphore); 1612 if (result != VK_SUCCESS) { 1613 SET_ERROR_CODE("vkCreateSemaphore()", result); 1614 return VK_NULL_HANDLE; 1615 } 1616 return semaphore; 1617} 1618 1619static bool VULKAN_DeviceExtensionsFound(VULKAN_RenderData *rendererData, int extensionsToCheck, const char* const* extNames) 1620{ 1621 uint32_t extensionCount; 1622 bool foundExtensions = true; 1623 VkResult result = vkEnumerateDeviceExtensionProperties(rendererData->physicalDevice, NULL, &extensionCount, NULL); 1624 if (result != VK_SUCCESS ) { 1625 SET_ERROR_CODE("vkEnumerateDeviceExtensionProperties()", result); 1626 return false; 1627 } 1628 if (extensionCount > 0 ) { 1629 VkExtensionProperties *extensionProperties = (VkExtensionProperties *)SDL_calloc(extensionCount, sizeof(VkExtensionProperties)); 1630 result = vkEnumerateDeviceExtensionProperties(rendererData->physicalDevice, NULL, &extensionCount, extensionProperties); 1631 if (result != VK_SUCCESS ) { 1632 SET_ERROR_CODE("vkEnumerateDeviceExtensionProperties()", result); 1633 SDL_free(extensionProperties); 1634 return false; 1635 } 1636 for (int ext = 0; ext < extensionsToCheck && foundExtensions; ext++) { 1637 bool foundExtension = false; 1638 for (uint32_t i = 0; i < extensionCount; i++) { 1639 if (SDL_strcmp(extensionProperties[i].extensionName, extNames[ext]) == 0) { 1640 foundExtension = true; 1641 break; 1642 } 1643 } 1644 foundExtensions &= foundExtension; 1645 } 1646 1647 SDL_free(extensionProperties); 1648 } 1649 1650 return foundExtensions; 1651} 1652 1653static bool VULKAN_InstanceExtensionFound(VULKAN_RenderData *rendererData, const char *extName) 1654{ 1655 uint32_t extensionCount; 1656 VkResult result = vkEnumerateInstanceExtensionProperties(NULL, &extensionCount, NULL); 1657 if (result != VK_SUCCESS ) { 1658 SET_ERROR_CODE("vkEnumerateInstanceExtensionProperties()", result); 1659 return false; 1660 } 1661 if (extensionCount > 0 ) { 1662 VkExtensionProperties *extensionProperties = (VkExtensionProperties *)SDL_calloc(extensionCount, sizeof(VkExtensionProperties)); 1663 result = vkEnumerateInstanceExtensionProperties(NULL, &extensionCount, extensionProperties); 1664 if (result != VK_SUCCESS ) { 1665 SET_ERROR_CODE("vkEnumerateInstanceExtensionProperties()", result); 1666 SDL_free(extensionProperties); 1667 return false; 1668 } 1669 for (uint32_t i = 0; i< extensionCount; i++) { 1670 if (SDL_strcmp(extensionProperties[i].extensionName, extName) == 0) { 1671 SDL_free(extensionProperties); 1672 return true; 1673 } 1674 } 1675 SDL_free(extensionProperties); 1676 } 1677 1678 return false; 1679} 1680 1681static bool VULKAN_ValidationLayersFound(void) 1682{ 1683 uint32_t instanceLayerCount = 0; 1684 uint32_t i; 1685 bool foundValidation = false; 1686 1687 vkEnumerateInstanceLayerProperties(&instanceLayerCount, NULL); 1688 if (instanceLayerCount > 0) { 1689 VkLayerProperties *instanceLayers = (VkLayerProperties *)SDL_calloc(instanceLayerCount, sizeof(VkLayerProperties)); 1690 vkEnumerateInstanceLayerProperties(&instanceLayerCount, instanceLayers); 1691 for (i = 0; i < instanceLayerCount; i++) { 1692 if (!SDL_strcmp(SDL_VULKAN_VALIDATION_LAYER_NAME, instanceLayers[i].layerName)) { 1693 foundValidation = true; 1694 break; 1695 } 1696 } 1697 SDL_free(instanceLayers); 1698 } 1699 1700 return foundValidation; 1701} 1702 1703// Create resources that depend on the device. 1704static VkResult VULKAN_CreateDeviceResources(SDL_Renderer *renderer, SDL_PropertiesID create_props) 1705{ 1706 static const char *const deviceExtensionNames[] = { 1707 VK_KHR_SWAPCHAIN_EXTENSION_NAME, 1708 /* VK_KHR_sampler_ycbcr_conversion + dependent extensions. 1709 Note VULKAN_DeviceExtensionsFound() call below, if these get moved in this 1710 array, update that check too. 1711 */ 1712 VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME, 1713 VK_KHR_MAINTENANCE1_EXTENSION_NAME, 1714 VK_KHR_BIND_MEMORY_2_EXTENSION_NAME, 1715 VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME, 1716 }; 1717 VULKAN_RenderData *rendererData = (VULKAN_RenderData *)renderer->internal; 1718 SDL_VideoDevice *device = SDL_GetVideoDevice(); 1719 VkResult result = VK_SUCCESS; 1720 PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = NULL; 1721 bool createDebug = SDL_GetHintBoolean(SDL_HINT_RENDER_VULKAN_DEBUG, false); 1722 const char *validationLayerName[] = { SDL_VULKAN_VALIDATION_LAYER_NAME }; 1723 1724 if (!SDL_Vulkan_LoadLibrary(NULL)) { 1725 SDL_LogDebug(SDL_LOG_CATEGORY_RENDER, "SDL_Vulkan_LoadLibrary failed" ); 1726 return VK_ERROR_UNKNOWN; 1727 } 1728 vkGetInstanceProcAddr = device ? (PFN_vkGetInstanceProcAddr)device->vulkan_config.vkGetInstanceProcAddr : NULL; 1729 if(!vkGetInstanceProcAddr) { 1730 SDL_LogDebug(SDL_LOG_CATEGORY_RENDER, "vkGetInstanceProcAddr is NULL" ); 1731 return VK_ERROR_UNKNOWN; 1732 } 1733 1734 // Load global Vulkan functions 1735 rendererData->vkGetInstanceProcAddr = vkGetInstanceProcAddr; 1736 if (!VULKAN_LoadGlobalFunctions(rendererData)) { 1737 return VK_ERROR_UNKNOWN; 1738 } 1739 1740 // Check for colorspace extension 1741 rendererData->supportsEXTSwapchainColorspace = VK_FALSE; 1742 if (renderer->output_colorspace == SDL_COLORSPACE_SRGB_LINEAR || 1743 renderer->output_colorspace == SDL_COLORSPACE_HDR10) { 1744 rendererData->supportsEXTSwapchainColorspace = VULKAN_InstanceExtensionFound(rendererData, VK_EXT_SWAPCHAIN_COLOR_SPACE_EXTENSION_NAME); 1745 if (!rendererData->supportsEXTSwapchainColorspace) { 1746 SDL_SetError("Using HDR output but %s not supported", VK_EXT_SWAPCHAIN_COLOR_SPACE_EXTENSION_NAME); 1747 return VK_ERROR_UNKNOWN; 1748 } 1749 } 1750 1751 // Check for VK_KHR_get_physical_device_properties2 1752 rendererData->supportsKHRGetPhysicalDeviceProperties2 = VULKAN_InstanceExtensionFound(rendererData, VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME); 1753 1754 // Create VkInstance 1755 rendererData->instance = (VkInstance)SDL_GetPointerProperty(create_props, SDL_PROP_RENDERER_CREATE_VULKAN_INSTANCE_POINTER, NULL); 1756 if (rendererData->instance) { 1757 rendererData->instance_external = true; 1758 } else { 1759 VkInstanceCreateInfo instanceCreateInfo = { 0 }; 1760 VkApplicationInfo appInfo = { 0 }; 1761 appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; 1762 appInfo.apiVersion = VK_API_VERSION_1_0; 1763 instanceCreateInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; 1764 instanceCreateInfo.pApplicationInfo = &appInfo; 1765 char const *const *instanceExtensions = SDL_Vulkan_GetInstanceExtensions(&instanceCreateInfo.enabledExtensionCount); 1766 1767 const char **instanceExtensionsCopy = (const char **)SDL_calloc(instanceCreateInfo.enabledExtensionCount + 2, sizeof(const char *)); 1768 for (uint32_t i = 0; i < instanceCreateInfo.enabledExtensionCount; i++) { 1769 instanceExtensionsCopy[i] = instanceExtensions[i]; 1770 } 1771 if (rendererData->supportsEXTSwapchainColorspace) { 1772 instanceExtensionsCopy[instanceCreateInfo.enabledExtensionCount] = VK_EXT_SWAPCHAIN_COLOR_SPACE_EXTENSION_NAME; 1773 instanceCreateInfo.enabledExtensionCount++; 1774 } 1775 if (rendererData->supportsKHRGetPhysicalDeviceProperties2) { 1776 instanceExtensionsCopy[instanceCreateInfo.enabledExtensionCount] = VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME; 1777 instanceCreateInfo.enabledExtensionCount++; 1778 } 1779 instanceCreateInfo.ppEnabledExtensionNames = (const char *const *)instanceExtensionsCopy; 1780 if (createDebug && VULKAN_ValidationLayersFound()) { 1781 instanceCreateInfo.ppEnabledLayerNames = validationLayerName; 1782 instanceCreateInfo.enabledLayerCount = 1; 1783 } 1784 result = vkCreateInstance(&instanceCreateInfo, NULL, &rendererData->instance); 1785 SDL_free((void *)instanceExtensionsCopy); 1786 if (result != VK_SUCCESS) { 1787 SET_ERROR_CODE("vkCreateInstance()", result); 1788 return result; 1789 } 1790 } 1791 1792 // Load instance Vulkan functions 1793 if (!VULKAN_LoadInstanceFunctions(rendererData)) { 1794 VULKAN_DestroyAll(renderer); 1795 return VK_ERROR_UNKNOWN; 1796 } 1797 1798 // Create Vulkan surface 1799 rendererData->surface = (VkSurfaceKHR)SDL_GetNumberProperty(create_props, SDL_PROP_RENDERER_CREATE_VULKAN_SURFACE_NUMBER, 0); 1800 if (rendererData->surface) { 1801 rendererData->surface_external = true; 1802 } else { 1803 if (!device->Vulkan_CreateSurface || !device->Vulkan_CreateSurface(device, renderer->window, rendererData->instance, NULL, &rendererData->surface)) { 1804 VULKAN_DestroyAll(renderer); 1805 SET_ERROR_MESSAGE("Vulkan_CreateSurface() failed"); 1806 return VK_ERROR_UNKNOWN; 1807 } 1808 } 1809 1810 // Choose Vulkan physical device 1811 rendererData->physicalDevice = (VkPhysicalDevice)SDL_GetPointerProperty(create_props, SDL_PROP_RENDERER_CREATE_VULKAN_PHYSICAL_DEVICE_POINTER, NULL); 1812 if (rendererData->physicalDevice) { 1813 vkGetPhysicalDeviceMemoryProperties(rendererData->physicalDevice, &rendererData->physicalDeviceMemoryProperties); 1814 vkGetPhysicalDeviceFeatures(rendererData->physicalDevice, &rendererData->physicalDeviceFeatures); 1815 } else { 1816 if (VULKAN_FindPhysicalDevice(rendererData) != VK_SUCCESS) { 1817 VULKAN_DestroyAll(renderer); 1818 return VK_ERROR_UNKNOWN; 1819 } 1820 } 1821 1822 if (SDL_HasProperty(create_props, SDL_PROP_RENDERER_CREATE_VULKAN_GRAPHICS_QUEUE_FAMILY_INDEX_NUMBER)) { 1823 rendererData->graphicsQueueFamilyIndex = (uint32_t)SDL_GetNumberProperty(create_props, SDL_PROP_RENDERER_CREATE_VULKAN_GRAPHICS_QUEUE_FAMILY_INDEX_NUMBER, 0); 1824 } 1825 if (SDL_HasProperty(create_props, SDL_PROP_RENDERER_CREATE_VULKAN_PRESENT_QUEUE_FAMILY_INDEX_NUMBER)) { 1826 rendererData->presentQueueFamilyIndex = (uint32_t)SDL_GetNumberProperty(create_props, SDL_PROP_RENDERER_CREATE_VULKAN_PRESENT_QUEUE_FAMILY_INDEX_NUMBER, 0); 1827 } 1828 1829 if (rendererData->supportsKHRGetPhysicalDeviceProperties2 && 1830 VULKAN_DeviceExtensionsFound(rendererData, 4, &deviceExtensionNames[1])) { 1831 rendererData->supportsKHRSamplerYCbCrConversion = true; 1832 } 1833 1834 // Create Vulkan device 1835 rendererData->device = (VkDevice)SDL_GetPointerProperty(create_props, SDL_PROP_RENDERER_CREATE_VULKAN_DEVICE_POINTER, NULL); 1836 if (rendererData->device) { 1837 rendererData->device_external = true; 1838 } else { 1839 VkPhysicalDeviceSamplerYcbcrConversionFeatures deviceSamplerYcbcrConversionFeatures = { 0 }; 1840 VkDeviceQueueCreateInfo deviceQueueCreateInfo[2] = { { 0 }, { 0 } }; 1841 static const float queuePriority[] = { 1.0f }; 1842 1843 VkDeviceCreateInfo deviceCreateInfo = { 0 }; 1844 deviceCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; 1845 deviceCreateInfo.queueCreateInfoCount = 0; 1846 deviceCreateInfo.pQueueCreateInfos = deviceQueueCreateInfo; 1847 deviceCreateInfo.pEnabledFeatures = NULL; 1848 deviceCreateInfo.enabledExtensionCount = (rendererData->supportsKHRSamplerYCbCrConversion) ? 5 : 1; 1849 deviceCreateInfo.ppEnabledExtensionNames = deviceExtensionNames; 1850 1851 deviceQueueCreateInfo[0].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; 1852 deviceQueueCreateInfo[0].queueFamilyIndex = rendererData->graphicsQueueFamilyIndex; 1853 deviceQueueCreateInfo[0].queueCount = 1; 1854 deviceQueueCreateInfo[0].pQueuePriorities = queuePriority; 1855 ++deviceCreateInfo.queueCreateInfoCount; 1856 1857 if (rendererData->presentQueueFamilyIndex != rendererData->graphicsQueueFamilyIndex) { 1858 deviceQueueCreateInfo[1].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; 1859 deviceQueueCreateInfo[1].queueFamilyIndex = rendererData->presentQueueFamilyIndex; 1860 deviceQueueCreateInfo[1].queueCount = 1; 1861 deviceQueueCreateInfo[1].pQueuePriorities = queuePriority; 1862 ++deviceCreateInfo.queueCreateInfoCount; 1863 } 1864 1865 if (rendererData->supportsKHRSamplerYCbCrConversion) { 1866 deviceSamplerYcbcrConversionFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES; 1867 deviceSamplerYcbcrConversionFeatures.samplerYcbcrConversion = VK_TRUE; 1868 deviceSamplerYcbcrConversionFeatures.pNext = (void *)deviceCreateInfo.pNext; 1869 deviceCreateInfo.pNext = &deviceSamplerYcbcrConversionFeatures; 1870 } 1871 1872 result = vkCreateDevice(rendererData->physicalDevice, &deviceCreateInfo, NULL, &rendererData->device); 1873 if (result != VK_SUCCESS) { 1874 SET_ERROR_CODE("vkCreateDevice()", result); 1875 VULKAN_DestroyAll(renderer); 1876 return result; 1877 } 1878 } 1879 1880 if (!VULKAN_LoadDeviceFunctions(rendererData)) { 1881 VULKAN_DestroyAll(renderer); 1882 return VK_ERROR_UNKNOWN; 1883 } 1884 1885 // Get graphics/present queues 1886 vkGetDeviceQueue(rendererData->device, rendererData->graphicsQueueFamilyIndex, 0, &rendererData->graphicsQueue); 1887 if (rendererData->graphicsQueueFamilyIndex != rendererData->presentQueueFamilyIndex) { 1888 vkGetDeviceQueue(rendererData->device, rendererData->presentQueueFamilyIndex, 0, &rendererData->presentQueue); 1889 } else { 1890 rendererData->presentQueue = rendererData->graphicsQueue; 1891 } 1892 1893 // Create command pool/command buffers 1894 VkCommandPoolCreateInfo commandPoolCreateInfo = { 0 }; 1895 commandPoolCreateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; 1896 commandPoolCreateInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; 1897 commandPoolCreateInfo.queueFamilyIndex = rendererData->graphicsQueueFamilyIndex; 1898 result = vkCreateCommandPool(rendererData->device, &commandPoolCreateInfo, NULL, &rendererData->commandPool); 1899 if (result != VK_SUCCESS) { 1900 VULKAN_DestroyAll(renderer); 1901 SET_ERROR_CODE("vkCreateCommandPool()", result); 1902 return result; 1903 } 1904 1905 if (VULKAN_GetSurfaceFormats(rendererData) != VK_SUCCESS) { 1906 VULKAN_DestroyAll(renderer); 1907 return result; 1908 } 1909 1910 // Create shaders / layouts 1911 for (uint32_t i = 0; i < NUM_SHADERS; i++) { 1912 VULKAN_Shader shader = (VULKAN_Shader)i; 1913 VkShaderModuleCreateInfo shaderModuleCreateInfo = { 0 }; 1914 shaderModuleCreateInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; 1915 VULKAN_GetVertexShader(shader, &shaderModuleCreateInfo.pCode, &shaderModuleCreateInfo.codeSize); 1916 result = vkCreateShaderModule(rendererData->device, &shaderModuleCreateInfo, NULL, &rendererData->vertexShaderModules[i]); 1917 if (result != VK_SUCCESS) { 1918 VULKAN_DestroyAll(renderer); 1919 SET_ERROR_CODE("vkCreateShaderModule()", result); 1920 return result; 1921 } 1922 VULKAN_GetPixelShader(shader, &shaderModuleCreateInfo.pCode, &shaderModuleCreateInfo.codeSize); 1923 result = vkCreateShaderModule(rendererData->device, &shaderModuleCreateInfo, NULL, &rendererData->fragmentShaderModules[i]); 1924 if (result != VK_SUCCESS) { 1925 VULKAN_DestroyAll(renderer); 1926 SET_ERROR_CODE("vkCreateShaderModule()", result); 1927 return result; 1928 } 1929 } 1930 1931 // Descriptor set layout / pipeline layout 1932 result = VULKAN_CreateDescriptorSetAndPipelineLayout(rendererData, VK_NULL_HANDLE, &rendererData->descriptorSetLayout, &rendererData->pipelineLayout); 1933 if (result != VK_SUCCESS) { 1934 VULKAN_DestroyAll(renderer); 1935 return result; 1936 } 1937 1938 // Create default vertex buffers 1939 for (uint32_t i = 0; i < SDL_VULKAN_NUM_VERTEX_BUFFERS; ++i) { 1940 VULKAN_CreateVertexBuffer(rendererData, i, SDL_VULKAN_VERTEX_BUFFER_DEFAULT_SIZE); 1941 } 1942 1943 // Create samplers 1944 { 1945 static struct 1946 { 1947 VkFilter filter; 1948 VkSamplerAddressMode address; 1949 } samplerParams[] = { 1950 { VK_FILTER_NEAREST, VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE }, 1951 { VK_FILTER_NEAREST, VK_SAMPLER_ADDRESS_MODE_REPEAT }, 1952 { VK_FILTER_LINEAR, VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE }, 1953 { VK_FILTER_LINEAR, VK_SAMPLER_ADDRESS_MODE_REPEAT }, 1954 }; 1955 SDL_COMPILE_TIME_ASSERT(samplerParams_SIZE, SDL_arraysize(samplerParams) == VULKAN_SAMPLER_COUNT); 1956 VkSamplerCreateInfo samplerCreateInfo = { 0 }; 1957 samplerCreateInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; 1958 samplerCreateInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST; 1959 samplerCreateInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; 1960 samplerCreateInfo.mipLodBias = 0.0f; 1961 samplerCreateInfo.anisotropyEnable = VK_FALSE; 1962 samplerCreateInfo.maxAnisotropy = 1.0f; 1963 samplerCreateInfo.minLod = 0.0f; 1964 samplerCreateInfo.maxLod = 1000.0f; 1965 for (int i = 0; i < SDL_arraysize(samplerParams); ++i) { 1966 samplerCreateInfo.magFilter = samplerParams[i].filter; 1967 samplerCreateInfo.minFilter = samplerParams[i].filter; 1968 samplerCreateInfo.addressModeU = samplerParams[i].address; 1969 samplerCreateInfo.addressModeV = samplerParams[i].address; 1970 result = vkCreateSampler(rendererData->device, &samplerCreateInfo, NULL, &rendererData->samplers[i]); 1971 if (result != VK_SUCCESS) { 1972 VULKAN_DestroyAll(renderer); 1973 SET_ERROR_CODE("vkCreateSampler()", result); 1974 return result; 1975 } 1976 } 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 = VK_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\n", 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 2549static bool VULKAN_SupportsBlendMode(SDL_Renderer *renderer, SDL_BlendMode blendMode) 2550{ 2551 SDL_BlendFactor srcColorFactor = SDL_GetBlendModeSrcColorFactor(blendMode); 2552 SDL_BlendFactor srcAlphaFactor = SDL_GetBlendModeSrcAlphaFactor(blendMode); 2553 SDL_BlendOperation colorOperation = SDL_GetBlendModeColorOperation(blendMode); 2554 SDL_BlendFactor dstColorFactor = SDL_GetBlendModeDstColorFactor(blendMode); 2555 SDL_BlendFactor dstAlphaFactor = SDL_GetBlendModeDstAlphaFactor(blendMode); 2556 SDL_BlendOperation alphaOperation = SDL_GetBlendModeAlphaOperation(blendMode); 2557 2558 if (GetBlendFactor(srcColorFactor) == VK_BLEND_FACTOR_MAX_ENUM || 2559 GetBlendFactor(srcAlphaFactor) == VK_BLEND_FACTOR_MAX_ENUM || 2560 GetBlendOp(colorOperation) == VK_BLEND_OP_MAX_ENUM || 2561 GetBlendFactor(dstColorFactor) == VK_BLEND_FACTOR_MAX_ENUM || 2562 GetBlendFactor(dstAlphaFactor) == VK_BLEND_FACTOR_MAX_ENUM || 2563 GetBlendOp(alphaOperation) == VK_BLEND_OP_MAX_ENUM) { 2564 return false; 2565 } 2566 return true; 2567} 2568 2569static bool VULKAN_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SDL_PropertiesID create_props) 2570{ 2571 VULKAN_RenderData *rendererData = (VULKAN_RenderData *)renderer->internal; 2572 VULKAN_TextureData *textureData; 2573 VkResult result; 2574 VkFormat textureFormat = SDLPixelFormatToVkTextureFormat(texture->format, renderer->output_colorspace); 2575 uint32_t width = texture->w; 2576 uint32_t height = texture->h; 2577 VkComponentMapping imageViewSwizzle = rendererData->identitySwizzle; 2578 2579 if (!rendererData->device) { 2580 return SDL_SetError("Device lost and couldn't be recovered"); 2581 } 2582 2583 if (textureFormat == VK_FORMAT_UNDEFINED) { 2584 return SDL_SetError("%s, An unsupported SDL pixel format (0x%x) was specified", __FUNCTION__, texture->format); 2585 } 2586 2587 textureData = (VULKAN_TextureData *)SDL_calloc(1, sizeof(*textureData)); 2588 if (!textureData) { 2589 return false; 2590 } 2591 texture->internal = textureData; 2592 if (SDL_COLORSPACETRANSFER(texture->colorspace) == SDL_TRANSFER_CHARACTERISTICS_SRGB) { 2593 textureData->shader = SHADER_RGB; 2594 } else { 2595 textureData->shader = SHADER_ADVANCED; 2596 } 2597 textureData->scaleMode = (texture->scaleMode == SDL_SCALEMODE_NEAREST) ? VK_FILTER_NEAREST : VK_FILTER_LINEAR; 2598 2599#ifdef SDL_HAVE_YUV 2600 // YUV textures must have even width and height. Also create Ycbcr conversion 2601 if (texture->format == SDL_PIXELFORMAT_YV12 || 2602 texture->format == SDL_PIXELFORMAT_IYUV || 2603 texture->format == SDL_PIXELFORMAT_NV12 || 2604 texture->format == SDL_PIXELFORMAT_NV21 || 2605 texture->format == SDL_PIXELFORMAT_P010) { 2606 const uint32_t YUV_SD_THRESHOLD = 576; 2607 2608 // Check that we have VK_KHR_sampler_ycbcr_conversion support 2609 if (!rendererData->supportsKHRSamplerYCbCrConversion) { 2610 return SDL_SetError("YUV textures require a Vulkan device that supports VK_KHR_sampler_ycbcr_conversion"); 2611 } 2612 2613 VkSamplerYcbcrConversionCreateInfoKHR samplerYcbcrConversionCreateInfo = { 0 }; 2614 samplerYcbcrConversionCreateInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO_KHR; 2615 2616 // Pad width/height to multiple of 2 2617 width = (width + 1) & ~1; 2618 height = (height + 1) & ~1; 2619 2620 // Create samplerYcbcrConversion which will be used on the VkImageView and VkSampler 2621 samplerYcbcrConversionCreateInfo.format = textureFormat; 2622 switch (SDL_COLORSPACEMATRIX(texture->colorspace)) { 2623 case SDL_MATRIX_COEFFICIENTS_BT470BG: 2624 case SDL_MATRIX_COEFFICIENTS_BT601: 2625 samplerYcbcrConversionCreateInfo.ycbcrModel = VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_601_KHR; 2626 break; 2627 case SDL_MATRIX_COEFFICIENTS_BT709: 2628 samplerYcbcrConversionCreateInfo.ycbcrModel = VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_709_KHR; 2629 break; 2630 case SDL_MATRIX_COEFFICIENTS_BT2020_NCL: 2631 samplerYcbcrConversionCreateInfo.ycbcrModel = VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_2020_KHR; 2632 break; 2633 case SDL_MATRIX_COEFFICIENTS_UNSPECIFIED: 2634 if (texture->format == SDL_PIXELFORMAT_P010) { 2635 samplerYcbcrConversionCreateInfo.ycbcrModel = VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_2020_KHR; 2636 } else if (height > YUV_SD_THRESHOLD) { 2637 samplerYcbcrConversionCreateInfo.ycbcrModel = VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_709_KHR; 2638 } else { 2639 samplerYcbcrConversionCreateInfo.ycbcrModel = VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_601_KHR; 2640 } 2641 break; 2642 default: 2643 return SDL_SetError("Unsupported Ycbcr colorspace: %d", SDL_COLORSPACEMATRIX(texture->colorspace)); 2644 } 2645 samplerYcbcrConversionCreateInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY; 2646 samplerYcbcrConversionCreateInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY; 2647 samplerYcbcrConversionCreateInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY; 2648 samplerYcbcrConversionCreateInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY; 2649 if (texture->format == SDL_PIXELFORMAT_YV12 || 2650 texture->format == SDL_PIXELFORMAT_NV21) { 2651 samplerYcbcrConversionCreateInfo.components.r = VK_COMPONENT_SWIZZLE_B; 2652 samplerYcbcrConversionCreateInfo.components.b = VK_COMPONENT_SWIZZLE_R; 2653 } 2654 2655 switch (SDL_COLORSPACERANGE(texture->colorspace)) { 2656 case SDL_COLOR_RANGE_LIMITED: 2657 samplerYcbcrConversionCreateInfo.ycbcrRange = VK_SAMPLER_YCBCR_RANGE_ITU_NARROW_KHR; 2658 break; 2659 case SDL_COLOR_RANGE_FULL: 2660 default: 2661 samplerYcbcrConversionCreateInfo.ycbcrRange = VK_SAMPLER_YCBCR_RANGE_ITU_FULL_KHR; 2662 break; 2663 } 2664 2665 switch (SDL_COLORSPACECHROMA(texture->colorspace)) { 2666 case SDL_CHROMA_LOCATION_LEFT: 2667 samplerYcbcrConversionCreateInfo.xChromaOffset = VK_CHROMA_LOCATION_COSITED_EVEN_KHR; 2668 samplerYcbcrConversionCreateInfo.yChromaOffset = VK_CHROMA_LOCATION_MIDPOINT_KHR; 2669 break; 2670 case SDL_CHROMA_LOCATION_TOPLEFT: 2671 samplerYcbcrConversionCreateInfo.xChromaOffset = VK_CHROMA_LOCATION_COSITED_EVEN_KHR; 2672 samplerYcbcrConversionCreateInfo.yChromaOffset = VK_CHROMA_LOCATION_COSITED_EVEN_KHR; 2673 break; 2674 case SDL_CHROMA_LOCATION_NONE: 2675 case SDL_CHROMA_LOCATION_CENTER: 2676 default: 2677 samplerYcbcrConversionCreateInfo.xChromaOffset = VK_CHROMA_LOCATION_MIDPOINT_KHR; 2678 samplerYcbcrConversionCreateInfo.yChromaOffset = VK_CHROMA_LOCATION_MIDPOINT_KHR; 2679 break; 2680 } 2681 samplerYcbcrConversionCreateInfo.chromaFilter = VK_FILTER_LINEAR; 2682 samplerYcbcrConversionCreateInfo.forceExplicitReconstruction = VK_FALSE; 2683 2684 result = vkCreateSamplerYcbcrConversionKHR(rendererData->device, &samplerYcbcrConversionCreateInfo, NULL, &textureData->samplerYcbcrConversion); 2685 if (result != VK_SUCCESS) { 2686 SET_ERROR_CODE("vkCreateSamplerYcbcrConversionKHR()", result); 2687 return false; 2688 } 2689 2690 // Also create VkSampler object which we will need to pass to the PSO as an immutable sampler 2691 VkSamplerCreateInfo samplerCreateInfo = { 0 }; 2692 samplerCreateInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; 2693 samplerCreateInfo.magFilter = VK_FILTER_NEAREST; 2694 samplerCreateInfo.minFilter = VK_FILTER_NEAREST; 2695 samplerCreateInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST; 2696 samplerCreateInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT; 2697 samplerCreateInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT; 2698 samplerCreateInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; 2699 samplerCreateInfo.mipLodBias = 0.0f; 2700 samplerCreateInfo.anisotropyEnable = VK_FALSE; 2701 samplerCreateInfo.maxAnisotropy = 1.0f; 2702 samplerCreateInfo.minLod = 0.0f; 2703 samplerCreateInfo.maxLod = 1000.0f; 2704 2705 VkSamplerYcbcrConversionInfoKHR samplerYcbcrConversionInfo = { 0 }; 2706 samplerYcbcrConversionInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO_KHR; 2707 samplerYcbcrConversionInfo.conversion = textureData->samplerYcbcrConversion; 2708 samplerCreateInfo.pNext = &samplerYcbcrConversionInfo; 2709 result = vkCreateSampler(rendererData->device, &samplerCreateInfo, NULL, &textureData->samplerYcbcr); 2710 if (result != VK_SUCCESS) { 2711 SET_ERROR_CODE("vkCreateSampler()", result); 2712 return false; 2713 } 2714 2715 // Allocate special descriptor set layout with samplerYcbcr baked as an immutable sampler 2716 result = VULKAN_CreateDescriptorSetAndPipelineLayout(rendererData, textureData->samplerYcbcr, &textureData->descriptorSetLayoutYcbcr, &textureData->pipelineLayoutYcbcr); 2717 if (result != VK_SUCCESS) { 2718 return false; 2719 } 2720 } 2721#endif 2722 textureData->width = width; 2723 textureData->height = height; 2724 2725 VkImageUsageFlags usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT; 2726 if (texture->access == SDL_TEXTUREACCESS_TARGET) { 2727 usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; 2728 } 2729 2730 result = VULKAN_AllocateImage(rendererData, create_props, width, height, textureFormat, usage, imageViewSwizzle, textureData->samplerYcbcrConversion, &textureData->mainImage); 2731 if (result != VK_SUCCESS) { 2732 SET_ERROR_CODE("VULKAN_AllocateImage()", result); 2733 return false; 2734 } 2735 2736 SDL_PropertiesID props = SDL_GetTextureProperties(texture); 2737 SDL_SetNumberProperty(props, SDL_PROP_TEXTURE_CREATE_VULKAN_TEXTURE_NUMBER, (Sint64)textureData->mainImage.image); 2738 2739 if (texture->access == SDL_TEXTUREACCESS_TARGET) { 2740 result = VULKAN_CreateFramebuffersAndRenderPasses(renderer, 2741 texture->w, 2742 texture->h, 2743 textureFormat, 2744 1, 2745 &textureData->mainImage.imageView, 2746 &textureData->mainFramebuffer, 2747 textureData->mainRenderpasses); 2748 if (result != VK_SUCCESS) { 2749 SET_ERROR_CODE("VULKAN_CreateFramebuffersAndRenderPasses()", result); 2750 return false; 2751 } 2752 } 2753 return true; 2754} 2755 2756static void VULKAN_DestroyTexture(SDL_Renderer *renderer, 2757 SDL_Texture *texture) 2758{ 2759 VULKAN_RenderData *rendererData = (VULKAN_RenderData *)renderer->internal; 2760 VULKAN_TextureData *textureData = (VULKAN_TextureData *)texture->internal; 2761 2762 if (!textureData) { 2763 return; 2764 } 2765 2766 /* Because SDL_DestroyTexture might be called while the data is in-flight, we need to issue the batch first 2767 Unfortunately, this means that deleting a lot of textures mid-frame will have poor performance. */ 2768 VULKAN_IssueBatch(rendererData); 2769 VULKAN_WaitForGPU(rendererData); 2770 2771 VULKAN_DestroyImage(rendererData, &textureData->mainImage); 2772 2773#ifdef SDL_HAVE_YUV 2774 if (textureData->samplerYcbcrConversion != VK_NULL_HANDLE) { 2775 vkDestroySamplerYcbcrConversionKHR(rendererData->device, textureData->samplerYcbcrConversion, NULL); 2776 textureData->samplerYcbcrConversion = VK_NULL_HANDLE; 2777 } 2778 if (textureData->samplerYcbcr != VK_NULL_HANDLE) { 2779 vkDestroySampler(rendererData->device, textureData->samplerYcbcr, NULL); 2780 textureData->samplerYcbcr = VK_NULL_HANDLE; 2781 } 2782 if (textureData->pipelineLayoutYcbcr != VK_NULL_HANDLE) { 2783 vkDestroyPipelineLayout(rendererData->device, textureData->pipelineLayoutYcbcr, NULL); 2784 textureData->pipelineLayoutYcbcr = VK_NULL_HANDLE; 2785 } 2786 if (textureData->descriptorSetLayoutYcbcr != VK_NULL_HANDLE) { 2787 vkDestroyDescriptorSetLayout(rendererData->device, textureData->descriptorSetLayoutYcbcr, NULL); 2788 textureData->descriptorSetLayoutYcbcr = VK_NULL_HANDLE; 2789 } 2790#endif 2791 2792 VULKAN_DestroyBuffer(rendererData, &textureData->stagingBuffer); 2793 if (textureData->mainFramebuffer != VK_NULL_HANDLE) { 2794 vkDestroyFramebuffer(rendererData->device, textureData->mainFramebuffer, NULL); 2795 textureData->mainFramebuffer = VK_NULL_HANDLE; 2796 } 2797 for (uint32_t i = 0; i < SDL_arraysize(textureData->mainRenderpasses); i++) { 2798 if (textureData->mainRenderpasses[i] != VK_NULL_HANDLE) { 2799 vkDestroyRenderPass(rendererData->device, textureData->mainRenderpasses[i], NULL); 2800 textureData->mainRenderpasses[i] = VK_NULL_HANDLE; 2801 } 2802 } 2803 2804 SDL_free(textureData); 2805 texture->internal = NULL; 2806} 2807 2808static 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) 2809{ 2810 VkDeviceSize pixelSize = VULKAN_GetBytesPerPixel(format); 2811 VkDeviceSize length = w * pixelSize; 2812 VkDeviceSize uploadBufferSize = length * h; 2813 const Uint8 *src; 2814 Uint8 *dst; 2815 VkResult rc; 2816 int planeCount = VULKAN_VkFormatGetNumPlanes(format); 2817 2818 VULKAN_EnsureCommandBuffer(rendererData); 2819 2820 int currentUploadBufferIndex = rendererData->currentUploadBuffer[rendererData->currentCommandBufferIndex]; 2821 VULKAN_Buffer *uploadBuffer = &rendererData->uploadBuffers[rendererData->currentCommandBufferIndex][currentUploadBufferIndex]; 2822 2823 rc = VULKAN_AllocateBuffer(rendererData, uploadBufferSize, 2824 VK_BUFFER_USAGE_TRANSFER_SRC_BIT, 2825 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | 2826 VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, 2827 VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, 2828 uploadBuffer); 2829 if (rc != VK_SUCCESS) { 2830 return false; 2831 } 2832 2833 src = (const Uint8 *)pixels; 2834 dst = (Uint8 *)uploadBuffer->mappedBufferPtr; 2835 if (length == (VkDeviceSize)pitch) { 2836 SDL_memcpy(dst, src, (size_t)length * h); 2837 } else { 2838 if (length > (VkDeviceSize)pitch) { 2839 length = pitch; 2840 } 2841 for (VkDeviceSize row = h; row--; ) { 2842 SDL_memcpy(dst, src, (size_t)length); 2843 src += pitch; 2844 dst += length; 2845 } 2846 } 2847 2848 // Make sure the destination is in the correct resource state 2849 VULKAN_RecordPipelineImageBarrier(rendererData, 2850 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, 2851 VK_ACCESS_TRANSFER_WRITE_BIT, 2852 VK_PIPELINE_STAGE_TRANSFER_BIT | VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 2853 VK_PIPELINE_STAGE_TRANSFER_BIT, 2854 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 2855 image, 2856 imageLayout); 2857 2858 VkBufferImageCopy region; 2859 region.bufferOffset = 0; 2860 region.bufferRowLength = 0; 2861 region.bufferImageHeight = 0; 2862 region.imageSubresource.baseArrayLayer = 0; 2863 region.imageSubresource.layerCount = 1; 2864 region.imageSubresource.mipLevel = 0; 2865 if (planeCount <= 1) { 2866 region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; 2867 } else { 2868 region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_PLANE_0_BIT << plane; 2869 } 2870 region.imageOffset.x = x; 2871 region.imageOffset.y = y; 2872 region.imageOffset.z = 0; 2873 region.imageExtent.width = w; 2874 region.imageExtent.height = h; 2875 region.imageExtent.depth = 1; 2876 2877 vkCmdCopyBufferToImage(rendererData->currentCommandBuffer, uploadBuffer->buffer, image, *imageLayout, 1, &region); 2878 2879 // Transition the texture to be shader accessible 2880 VULKAN_RecordPipelineImageBarrier(rendererData, 2881 VK_ACCESS_TRANSFER_WRITE_BIT, 2882 VK_ACCESS_SHADER_READ_BIT, 2883 VK_PIPELINE_STAGE_TRANSFER_BIT, 2884 VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 2885 VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, 2886 image, 2887 imageLayout); 2888 2889 rendererData->currentUploadBuffer[rendererData->currentCommandBufferIndex]++; 2890 2891 // If we've used up all the upload buffers, we need to issue the batch 2892 if (rendererData->currentUploadBuffer[rendererData->currentCommandBufferIndex] == SDL_VULKAN_NUM_UPLOAD_BUFFERS) { 2893 VULKAN_IssueBatch(rendererData); 2894 } 2895 2896 return true; 2897} 2898 2899 2900static bool VULKAN_UpdateTexture(SDL_Renderer *renderer, SDL_Texture *texture, 2901 const SDL_Rect *rect, const void *srcPixels, 2902 int srcPitch) 2903{ 2904 VULKAN_RenderData *rendererData = (VULKAN_RenderData *)renderer->internal; 2905 VULKAN_TextureData *textureData = (VULKAN_TextureData *)texture->internal; 2906 2907 if (!textureData) { 2908 return SDL_SetError("Texture is not currently available"); 2909 } 2910 2911 if (!VULKAN_UpdateTextureInternal(rendererData, textureData->mainImage.image, textureData->mainImage.format, 0, rect->x, rect->y, rect->w, rect->h, srcPixels, srcPitch, &textureData->mainImage.imageLayout)) { 2912 return false; 2913 } 2914#ifdef SDL_HAVE_YUV 2915 Uint32 numPlanes = VULKAN_VkFormatGetNumPlanes(textureData->mainImage.format); 2916 // Skip to the correct offset into the next texture 2917 srcPixels = (const void *)((const Uint8 *)srcPixels + rect->h * srcPitch); 2918 // YUV data 2919 if (numPlanes == 3) { 2920 for (Uint32 plane = 1; plane < numPlanes; plane++) { 2921 if (!VULKAN_UpdateTextureInternal(rendererData, textureData->mainImage.image, textureData->mainImage.format, plane, rect->x / 2, rect->y / 2, (rect->w + 1) / 2, (rect->h + 1) / 2, srcPixels, (srcPitch + 1) / 2, &textureData->mainImage.imageLayout)) { 2922 return false; 2923 } 2924 2925 // Skip to the correct offset into the next texture 2926 srcPixels = (const void *)((const Uint8 *)srcPixels + ((rect->h + 1) / 2) * ((srcPitch + 1) / 2)); 2927 } 2928 } 2929 // NV12/NV21 data 2930 else if (numPlanes == 2) 2931 { 2932 if (texture->format == SDL_PIXELFORMAT_P010) { 2933 srcPitch = (srcPitch + 3) & ~3; 2934 } else { 2935 srcPitch = (srcPitch + 1) & ~1; 2936 } 2937 2938 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, srcPixels, srcPitch, &textureData->mainImage.imageLayout)) { 2939 return false; 2940 } 2941 } 2942#endif 2943 return true; 2944} 2945 2946#ifdef SDL_HAVE_YUV 2947static bool VULKAN_UpdateTextureYUV(SDL_Renderer *renderer, SDL_Texture *texture, 2948 const SDL_Rect *rect, 2949 const Uint8 *Yplane, int Ypitch, 2950 const Uint8 *Uplane, int Upitch, 2951 const Uint8 *Vplane, int Vpitch) 2952{ 2953 VULKAN_RenderData *rendererData = (VULKAN_RenderData *)renderer->internal; 2954 VULKAN_TextureData *textureData = (VULKAN_TextureData *)texture->internal; 2955 2956 if (!textureData) { 2957 return SDL_SetError("Texture is not currently available"); 2958 } 2959 2960 if (!VULKAN_UpdateTextureInternal(rendererData, textureData->mainImage.image, textureData->mainImage.format, 0, rect->x, rect->y, rect->w, rect->h, Yplane, Ypitch, &textureData->mainImage.imageLayout)) { 2961 return false; 2962 } 2963 if (!VULKAN_UpdateTextureInternal(rendererData, textureData->mainImage.image, textureData->mainImage.format, 1, rect->x / 2, rect->y / 2, rect->w / 2, rect->h / 2, Uplane, Upitch, &textureData->mainImage.imageLayout)) { 2964 return false; 2965 } 2966 if (!VULKAN_UpdateTextureInternal(rendererData, textureData->mainImage.image, textureData->mainImage.format, 2, rect->x / 2, rect->y / 2, rect->w / 2, rect->h / 2, Vplane, Vpitch, &textureData->mainImage.imageLayout)) { 2967 return false; 2968 } 2969 return true; 2970} 2971 2972static bool VULKAN_UpdateTextureNV(SDL_Renderer *renderer, SDL_Texture *texture, 2973 const SDL_Rect *rect, 2974 const Uint8 *Yplane, int Ypitch, 2975 const Uint8 *UVplane, int UVpitch) 2976{ 2977 VULKAN_RenderData *rendererData = (VULKAN_RenderData *)renderer->internal; 2978 VULKAN_TextureData *textureData = (VULKAN_TextureData *)texture->internal; 2979 2980 if (!textureData) { 2981 return SDL_SetError("Texture is not currently available"); 2982 } 2983 2984 if (!VULKAN_UpdateTextureInternal(rendererData, textureData->mainImage.image, textureData->mainImage.format, 0, rect->x, rect->y, rect->w, rect->h, Yplane, Ypitch, &textureData->mainImage.imageLayout)) { 2985 return false; 2986 } 2987 2988 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)) { 2989 return false; 2990 } 2991 return true; 2992} 2993#endif 2994 2995static bool VULKAN_LockTexture(SDL_Renderer *renderer, SDL_Texture *texture, 2996 const SDL_Rect *rect, void **pixels, int *pitch) 2997{ 2998 VULKAN_RenderData *rendererData = (VULKAN_RenderData *)renderer->internal; 2999 VULKAN_TextureData *textureData = (VULKAN_TextureData *)texture->internal; 3000 VkResult rc; 3001 if (!textureData) { 3002 return SDL_SetError("Texture is not currently available"); 3003 } 3004 3005 if (textureData->stagingBuffer.buffer != VK_NULL_HANDLE) { 3006 return SDL_SetError("texture is already locked"); 3007 } 3008 3009 VkDeviceSize pixelSize = VULKAN_GetBytesPerPixel(textureData->mainImage.format); 3010 VkDeviceSize length = rect->w * pixelSize; 3011 VkDeviceSize stagingBufferSize = length * rect->h; 3012 rc = VULKAN_AllocateBuffer(rendererData, 3013 stagingBufferSize, 3014 VK_BUFFER_USAGE_TRANSFER_SRC_BIT, 3015 VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | 3016 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, 3017 VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, 3018 &textureData->stagingBuffer); 3019 if (rc != VK_SUCCESS) { 3020 return false; 3021 } 3022 3023 /* Make note of where the staging texture will be written to 3024 * (on a call to SDL_UnlockTexture): 3025 */ 3026 textureData->lockedRect = *rect; 3027 3028 /* Make sure the caller has information on the texture's pixel buffer, 3029 * then return: 3030 */ 3031 *pixels = textureData->stagingBuffer.mappedBufferPtr; 3032 *pitch = (int)length; 3033 return true; 3034 3035} 3036 3037static void VULKAN_UnlockTexture(SDL_Renderer *renderer, SDL_Texture *texture) 3038{ 3039 VULKAN_RenderData *rendererData = (VULKAN_RenderData *)renderer->internal; 3040 VULKAN_TextureData *textureData = (VULKAN_TextureData *)texture->internal; 3041 3042 if (!textureData) { 3043 return; 3044 } 3045 3046 VULKAN_EnsureCommandBuffer(rendererData); 3047 3048 // Make sure the destination is in the correct resource state 3049 VULKAN_RecordPipelineImageBarrier(rendererData, 3050 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, 3051 VK_ACCESS_TRANSFER_WRITE_BIT, 3052 VK_PIPELINE_STAGE_TRANSFER_BIT | VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 3053 VK_PIPELINE_STAGE_TRANSFER_BIT, 3054 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 3055 textureData->mainImage.image, 3056 &textureData->mainImage.imageLayout); 3057 3058 VkBufferImageCopy region; 3059 region.bufferOffset = 0; 3060 region.bufferRowLength = 0; 3061 region.bufferImageHeight = 0; 3062 region.imageSubresource.baseArrayLayer = 0; 3063 region.imageSubresource.layerCount = 1; 3064 region.imageSubresource.mipLevel = 0; 3065 region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; 3066 region.imageOffset.x = textureData->lockedRect.x; 3067 region.imageOffset.y = textureData->lockedRect.y; 3068 region.imageOffset.z = 0; 3069 region.imageExtent.width = textureData->lockedRect.w; 3070 region.imageExtent.height = textureData->lockedRect.h; 3071 region.imageExtent.depth = 1; 3072 vkCmdCopyBufferToImage(rendererData->currentCommandBuffer, textureData->stagingBuffer.buffer, textureData->mainImage.image, textureData->mainImage.imageLayout, 1, &region); 3073 3074 // Transition the texture to be shader accessible 3075 VULKAN_RecordPipelineImageBarrier(rendererData, 3076 VK_ACCESS_TRANSFER_WRITE_BIT, 3077 VK_ACCESS_SHADER_READ_BIT, 3078 VK_PIPELINE_STAGE_TRANSFER_BIT, 3079 VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 3080 VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, 3081 textureData->mainImage.image, 3082 &textureData->mainImage.imageLayout); 3083 3084 // Execute the command list before releasing the staging buffer 3085 VULKAN_IssueBatch(rendererData); 3086 3087 VULKAN_DestroyBuffer(rendererData, &textureData->stagingBuffer); 3088} 3089 3090static void VULKAN_SetTextureScaleMode(SDL_Renderer *renderer, SDL_Texture *texture, SDL_ScaleMode scaleMode) 3091{ 3092 VULKAN_TextureData *textureData = (VULKAN_TextureData *)texture->internal; 3093 3094 if (!textureData) { 3095 return; 3096 } 3097 3098 textureData->scaleMode = (scaleMode == SDL_SCALEMODE_NEAREST) ? VK_FILTER_NEAREST : VK_FILTER_LINEAR; 3099} 3100 3101static bool VULKAN_SetRenderTarget(SDL_Renderer *renderer, SDL_Texture *texture) 3102{ 3103 VULKAN_RenderData *rendererData = (VULKAN_RenderData *)renderer->internal; 3104 VULKAN_TextureData *textureData = NULL; 3105 3106 VULKAN_EnsureCommandBuffer(rendererData); 3107 3108 if (!texture) { 3109 if (rendererData->textureRenderTarget) { 3110 3111 VULKAN_RecordPipelineImageBarrier(rendererData, 3112 VK_ACCESS_TRANSFER_WRITE_BIT | VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, 3113 VK_ACCESS_SHADER_READ_BIT, 3114 VK_PIPELINE_STAGE_TRANSFER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 3115 VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 3116 VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, 3117 rendererData->textureRenderTarget->mainImage.image, 3118 &rendererData->textureRenderTarget->mainImage.imageLayout); 3119 } 3120 rendererData->textureRenderTarget = NULL; 3121 return true; 3122 } 3123 3124 textureData = (VULKAN_TextureData *)texture->internal; 3125 3126 if (textureData->mainImage.imageView == VK_NULL_HANDLE) { 3127 return SDL_SetError("specified texture is not a render target"); 3128 } 3129 3130 rendererData->textureRenderTarget = textureData; 3131 VULKAN_RecordPipelineImageBarrier(rendererData, 3132 VK_ACCESS_TRANSFER_WRITE_BIT | VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, 3133 VK_ACCESS_TRANSFER_WRITE_BIT | VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, 3134 VK_PIPELINE_STAGE_TRANSFER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 3135 VK_PIPELINE_STAGE_TRANSFER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 3136 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, 3137 rendererData->textureRenderTarget->mainImage.image, 3138 &rendererData->textureRenderTarget->mainImage.imageLayout); 3139 3140 return true; 3141} 3142 3143static bool VULKAN_QueueNoOp(SDL_Renderer *renderer, SDL_RenderCommand *cmd) 3144{ 3145 return true; // nothing to do in this backend. 3146} 3147 3148static bool VULKAN_QueueDrawPoints(SDL_Renderer *renderer, SDL_RenderCommand *cmd, const SDL_FPoint *points, int count) 3149{ 3150 VULKAN_VertexPositionColor *verts = (VULKAN_VertexPositionColor *)SDL_AllocateRenderVertices(renderer, count * sizeof(VULKAN_VertexPositionColor), 0, &cmd->data.draw.first); 3151 int i; 3152 bool convert_color = SDL_RenderingLinearSpace(renderer); 3153 3154 if (!verts) { 3155 return false; 3156 } 3157 3158 cmd->data.draw.count = count; 3159 for (i = 0; i < count; i++) { 3160 verts->pos[0] = points[i].x + 0.5f; 3161 verts->pos[1] = points[i].y + 0.5f; 3162 verts->tex[0] = 0.0f; 3163 verts->tex[1] = 0.0f; 3164 verts->color = cmd->data.draw.color; 3165 if (convert_color) { 3166 SDL_ConvertToLinear(&verts->color); 3167 } 3168 verts++; 3169 } 3170 return true; 3171} 3172 3173static bool VULKAN_QueueGeometry(SDL_Renderer *renderer, SDL_RenderCommand *cmd, SDL_Texture *texture, 3174 const float *xy, int xy_stride, const SDL_FColor *color, int color_stride, const float *uv, int uv_stride, 3175 int num_vertices, const void *indices, int num_indices, int size_indices, 3176 float scale_x, float scale_y) 3177{ 3178 int i; 3179 int count = indices ? num_indices : num_vertices; 3180 VULKAN_VertexPositionColor *verts = (VULKAN_VertexPositionColor *)SDL_AllocateRenderVertices(renderer, count * sizeof(VULKAN_VertexPositionColor), 0, &cmd->data.draw.first); 3181 bool convert_color = SDL_RenderingLinearSpace(renderer); 3182 VULKAN_TextureData *textureData = texture ? (VULKAN_TextureData *)texture->internal : NULL; 3183 float u_scale = textureData ? (float)texture->w / textureData->width : 0.0f; 3184 float v_scale = textureData ? (float)texture->h / textureData->height : 0.0f; 3185 3186 if (!verts) { 3187 return false; 3188 } 3189 3190 cmd->data.draw.count = count; 3191 size_indices = indices ? size_indices : 0; 3192 3193 for (i = 0; i < count; i++) { 3194 int j; 3195 float *xy_; 3196 if (size_indices == 4) { 3197 j = ((const Uint32 *)indices)[i]; 3198 } else if (size_indices == 2) { 3199 j = ((const Uint16 *)indices)[i]; 3200 } else if (size_indices == 1) { 3201 j = ((const Uint8 *)indices)[i]; 3202 } else { 3203 j = i; 3204 } 3205 3206 xy_ = (float *)((char *)xy + j * xy_stride); 3207 3208 verts->pos[0] = xy_[0] * scale_x; 3209 verts->pos[1] = xy_[1] * scale_y; 3210 verts->color = *(SDL_FColor *)((char *)color + j * color_stride); 3211 if (convert_color) { 3212 SDL_ConvertToLinear(&verts->color); 3213 } 3214 3215 if (texture) { 3216 float *uv_ = (float *)((char *)uv + j * uv_stride); 3217 verts->tex[0] = uv_[0] * u_scale; 3218 verts->tex[1] = uv_[1] * v_scale; 3219 } else { 3220 verts->tex[0] = 0.0f; 3221 verts->tex[1] = 0.0f; 3222 } 3223 3224 verts += 1; 3225 } 3226 return true; 3227} 3228 3229static bool VULKAN_UpdateVertexBuffer(SDL_Renderer *renderer, 3230 const void *vertexData, size_t dataSizeInBytes, VULKAN_DrawStateCache *stateCache) 3231{ 3232 VULKAN_RenderData *rendererData = (VULKAN_RenderData *)renderer->internal; 3233 const int vbidx = rendererData->currentVertexBuffer; 3234 VULKAN_Buffer *vertexBuffer; 3235 3236 if (dataSizeInBytes == 0) { 3237 return true; // nothing to do. 3238 } 3239 3240 if (rendererData->issueBatch) { 3241 if (VULKAN_IssueBatch(rendererData) != VK_SUCCESS) { 3242 return SDL_SetError("Failed to issue intermediate batch"); 3243 } 3244 } 3245 // If the existing vertex buffer isn't big enough, we need to recreate a big enough one 3246 if (dataSizeInBytes > rendererData->vertexBuffers[vbidx].size) { 3247 VULKAN_IssueBatch(rendererData); 3248 VULKAN_WaitForGPU(rendererData); 3249 VULKAN_CreateVertexBuffer(rendererData, vbidx, dataSizeInBytes); 3250 } 3251 3252 vertexBuffer = &rendererData->vertexBuffers[vbidx]; 3253 SDL_memcpy(vertexBuffer->mappedBufferPtr, vertexData, dataSizeInBytes); 3254 3255 stateCache->vertexBuffer = vertexBuffer->buffer; 3256 3257 rendererData->currentVertexBuffer++; 3258 if (rendererData->currentVertexBuffer >= SDL_VULKAN_NUM_VERTEX_BUFFERS) { 3259 rendererData->currentVertexBuffer = 0; 3260 rendererData->issueBatch = true; 3261 } 3262 3263 return true; 3264} 3265 3266static VkSurfaceTransformFlagBitsKHR VULKAN_GetRotationForCurrentRenderTarget(VULKAN_RenderData *rendererData) 3267{ 3268 if (rendererData->textureRenderTarget) { 3269 return VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; 3270 } else { 3271 return rendererData->swapChainPreTransform; 3272 } 3273} 3274 3275static bool VULKAN_IsDisplayRotated90Degrees(VkSurfaceTransformFlagBitsKHR rotation) 3276{ 3277 switch (rotation) { 3278 case VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR: 3279 case VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR: 3280 return true; 3281 default: 3282 return false; 3283 } 3284} 3285 3286static bool VULKAN_UpdateViewport(SDL_Renderer *renderer) 3287{ 3288 VULKAN_RenderData *rendererData = (VULKAN_RenderData *)renderer->internal; 3289 const SDL_Rect *viewport = &rendererData->currentViewport; 3290 Float4X4 projection; 3291 Float4X4 view; 3292 VkSurfaceTransformFlagBitsKHR rotation = VULKAN_GetRotationForCurrentRenderTarget(rendererData); 3293 bool swapDimensions; 3294 3295 if (viewport->w == 0 || viewport->h == 0) { 3296 /* If the viewport is empty, assume that it is because 3297 * SDL_CreateRenderer is calling it, and will call it again later 3298 * with a non-empty viewport. 3299 */ 3300 // SDL_Log("%s, no viewport was set!\n", __FUNCTION__); 3301 return false; 3302 } 3303 3304 switch (rotation) { 3305 case VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR: 3306 projection = MatrixRotationZ(SDL_PI_F * 0.5f); 3307 break; 3308 case VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR: 3309 projection = MatrixRotationZ(SDL_PI_F); 3310 break; 3311 case VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR: 3312 projection = MatrixRotationZ(-SDL_PI_F * 0.5f); 3313 break; 3314 case VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR: 3315 default: 3316 projection = MatrixIdentity(); 3317 break; 3318 3319 } 3320 3321 // Update the view matrix 3322 SDL_zero(view); 3323 view.m[0][0] = 2.0f / viewport->w; 3324 view.m[1][1] = -2.0f / viewport->h; 3325 view.m[2][2] = 1.0f; 3326 view.m[3][0] = -1.0f; 3327 view.m[3][1] = 1.0f; 3328 view.m[3][3] = 1.0f; 3329 3330 rendererData->vertexShaderConstantsData.projectionAndView = MatrixMultiply( 3331 view, 3332 projection); 3333 3334 VkViewport vkViewport; 3335 3336 swapDimensions = VULKAN_IsDisplayRotated90Degrees(rotation); 3337 if (swapDimensions) { 3338 vkViewport.x = viewport->y; 3339 vkViewport.y = viewport->x; 3340 vkViewport.width = viewport->h; 3341 vkViewport.height = viewport->w; 3342 } 3343 else { 3344 vkViewport.x = viewport->x; 3345 vkViewport.y = viewport->y; 3346 vkViewport.width = viewport->w; 3347 vkViewport.height = viewport->h; 3348 } 3349 vkViewport.minDepth = 0.0f; 3350 vkViewport.maxDepth = 1.0f; 3351 vkCmdSetViewport(rendererData->currentCommandBuffer, 0, 1, &vkViewport); 3352 3353 rendererData->viewportDirty = false; 3354 return true; 3355} 3356 3357static bool VULKAN_UpdateClipRect(SDL_Renderer *renderer) 3358{ 3359 VULKAN_RenderData *rendererData = (VULKAN_RenderData *)renderer->internal; 3360 const SDL_Rect *viewport = &rendererData->currentViewport; 3361 VkSurfaceTransformFlagBitsKHR rotation = VULKAN_GetRotationForCurrentRenderTarget(rendererData); 3362 bool swapDimensions = VULKAN_IsDisplayRotated90Degrees(rotation); 3363 3364 VkRect2D scissor; 3365 if (rendererData->currentCliprectEnabled) { 3366 scissor.offset.x = viewport->x + rendererData->currentCliprect.x; 3367 scissor.offset.y = viewport->y + rendererData->currentCliprect.y; 3368 scissor.extent.width = rendererData->currentCliprect.w; 3369 scissor.extent.height = rendererData->currentCliprect.h; 3370 } else { 3371 scissor.offset.x = viewport->x; 3372 scissor.offset.y = viewport->y; 3373 scissor.extent.width = viewport->w; 3374 scissor.extent.height = viewport->h; 3375 } 3376 if (swapDimensions) { 3377 VkRect2D scissorTemp = scissor; 3378 scissor.offset.x = scissorTemp.offset.y; 3379 scissor.offset.y = scissorTemp.offset.x; 3380 scissor.extent.width = scissorTemp.extent.height; 3381 scissor.extent.height = scissorTemp.extent.width; 3382 } 3383 vkCmdSetScissor(rendererData->currentCommandBuffer, 0, 1, &scissor); 3384 3385 rendererData->cliprectDirty = false; 3386 return true; 3387} 3388 3389static void VULKAN_SetupShaderConstants(SDL_Renderer *renderer, const SDL_RenderCommand *cmd, const SDL_Texture *texture, VULKAN_PixelShaderConstants *constants) 3390{ 3391 float output_headroom; 3392 3393 SDL_zerop(constants); 3394 3395 constants->scRGB_output = (float)SDL_RenderingLinearSpace(renderer); 3396 constants->color_scale = cmd->data.draw.color_scale; 3397 3398 if (texture) { 3399 switch (texture->format) { 3400 case SDL_PIXELFORMAT_YV12: 3401 case SDL_PIXELFORMAT_IYUV: 3402 case SDL_PIXELFORMAT_NV12: 3403 case SDL_PIXELFORMAT_NV21: 3404 constants->input_type = INPUTTYPE_SRGB; 3405 break; 3406 case SDL_PIXELFORMAT_P010: 3407 constants->input_type = INPUTTYPE_HDR10; 3408 break; 3409 default: 3410 if (texture->colorspace == SDL_COLORSPACE_SRGB_LINEAR) { 3411 constants->input_type = INPUTTYPE_SCRGB; 3412 } else if (SDL_COLORSPACEPRIMARIES(texture->colorspace) == SDL_COLOR_PRIMARIES_BT2020 && 3413 SDL_COLORSPACETRANSFER(texture->colorspace) == SDL_TRANSFER_CHARACTERISTICS_PQ) { 3414 constants->input_type = INPUTTYPE_HDR10; 3415 } else { 3416 // The sampler will convert from sRGB to linear on load if working in linear colorspace 3417 constants->input_type = INPUTTYPE_UNSPECIFIED; 3418 } 3419 break; 3420 } 3421 3422 constants->sdr_white_point = texture->SDR_white_point; 3423 3424 if (renderer->target) { 3425 output_headroom = renderer->target->HDR_headroom; 3426 } else { 3427 output_headroom = renderer->HDR_headroom; 3428 } 3429 3430 if (texture->HDR_headroom > output_headroom) { 3431 constants->tonemap_method = TONEMAP_CHROME; 3432 constants->tonemap_factor1 = (output_headroom / (texture->HDR_headroom * texture->HDR_headroom)); 3433 constants->tonemap_factor2 = (1.0f / output_headroom); 3434 } 3435 } 3436} 3437 3438static VkDescriptorPool VULKAN_AllocateDescriptorPool(VULKAN_RenderData *rendererData) 3439{ 3440 VkDescriptorPool descriptorPool = VK_NULL_HANDLE; 3441 VkDescriptorPoolSize descriptorPoolSizes[3]; 3442 VkResult result; 3443 descriptorPoolSizes[0].descriptorCount = SDL_VULKAN_MAX_DESCRIPTOR_SETS; 3444 descriptorPoolSizes[0].type = VK_DESCRIPTOR_TYPE_SAMPLER; 3445 3446 descriptorPoolSizes[1].descriptorCount = SDL_VULKAN_MAX_DESCRIPTOR_SETS; 3447 descriptorPoolSizes[1].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; 3448 3449 descriptorPoolSizes[2].descriptorCount = SDL_VULKAN_MAX_DESCRIPTOR_SETS; 3450 descriptorPoolSizes[2].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; 3451 3452 VkDescriptorPoolCreateInfo descriptorPoolCreateInfo = { 0 }; 3453 descriptorPoolCreateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; 3454 descriptorPoolCreateInfo.poolSizeCount = SDL_arraysize(descriptorPoolSizes); 3455 descriptorPoolCreateInfo.pPoolSizes = descriptorPoolSizes; 3456 descriptorPoolCreateInfo.maxSets = SDL_VULKAN_MAX_DESCRIPTOR_SETS; 3457 result = vkCreateDescriptorPool(rendererData->device, &descriptorPoolCreateInfo, NULL, &descriptorPool); 3458 if (result != VK_SUCCESS) { 3459 SET_ERROR_CODE("vkCreateDescrptorPool()", result); 3460 return VK_NULL_HANDLE; 3461 } 3462 3463 return descriptorPool; 3464} 3465 3466static VkResult VULKAN_CreateDescriptorSetAndPipelineLayout(VULKAN_RenderData *rendererData, VkSampler samplerYcbcr, VkDescriptorSetLayout *descriptorSetLayoutOut, 3467 VkPipelineLayout *pipelineLayoutOut) 3468{ 3469 VkResult result; 3470 3471 // Descriptor set layout 3472 VkDescriptorSetLayoutCreateInfo descriptorSetLayoutCreateInfo = { 0 }; 3473 descriptorSetLayoutCreateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; 3474 descriptorSetLayoutCreateInfo.flags = 0; 3475 VkDescriptorSetLayoutBinding layoutBindings[2]; 3476 // PixelShaderConstants 3477 layoutBindings[0].binding = 1; 3478 layoutBindings[0].descriptorCount = 1; 3479 layoutBindings[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; 3480 layoutBindings[0].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; 3481 layoutBindings[0].pImmutableSamplers = NULL; 3482 3483 // Combined image/sampler 3484 layoutBindings[1].binding = 0; 3485 layoutBindings[1].descriptorCount = 1; 3486 layoutBindings[1].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; 3487 layoutBindings[1].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; 3488 layoutBindings[1].pImmutableSamplers = (samplerYcbcr != VK_NULL_HANDLE) ? &samplerYcbcr : NULL; 3489 3490 descriptorSetLayoutCreateInfo.bindingCount = 2; 3491 descriptorSetLayoutCreateInfo.pBindings = layoutBindings; 3492 result = vkCreateDescriptorSetLayout(rendererData->device, &descriptorSetLayoutCreateInfo, NULL, descriptorSetLayoutOut); 3493 if (result != VK_SUCCESS) { 3494 SET_ERROR_CODE("vkCreateDescriptorSetLayout()", result); 3495 return result; 3496 } 3497 3498 // Pipeline layout 3499 VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo = { 0 }; 3500 VkPushConstantRange pushConstantRange; 3501 pushConstantRange.size = sizeof( VULKAN_VertexShaderConstants ); 3502 pushConstantRange.offset = 0; 3503 pushConstantRange.stageFlags = VK_SHADER_STAGE_VERTEX_BIT; 3504 pipelineLayoutCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; 3505 pipelineLayoutCreateInfo.setLayoutCount = 1; 3506 pipelineLayoutCreateInfo.pSetLayouts = descriptorSetLayoutOut; 3507 pipelineLayoutCreateInfo.pushConstantRangeCount = 1; 3508 pipelineLayoutCreateInfo.pPushConstantRanges = &pushConstantRange; 3509 result = vkCreatePipelineLayout(rendererData->device, &pipelineLayoutCreateInfo, NULL, pipelineLayoutOut); 3510 if (result != VK_SUCCESS) { 3511 SET_ERROR_CODE("vkCreatePipelineLayout()", result); 3512 return result; 3513 } 3514 3515 return result; 3516} 3517 3518static VkDescriptorSet VULKAN_AllocateDescriptorSet(SDL_Renderer *renderer, VULKAN_Shader shader, VkDescriptorSetLayout descriptorSetLayout, 3519 VkSampler sampler, VkBuffer constantBuffer, VkDeviceSize constantBufferOffset, VkImageView imageView) 3520{ 3521 VULKAN_RenderData *rendererData = (VULKAN_RenderData *)renderer->internal; 3522 uint32_t currentDescriptorPoolIndex = rendererData->currentDescriptorPoolIndex; 3523 VkDescriptorPool descriptorPool = rendererData->descriptorPools[rendererData->currentCommandBufferIndex][currentDescriptorPoolIndex]; 3524 3525 VkDescriptorSetAllocateInfo descriptorSetAllocateInfo = { 0 }; 3526 descriptorSetAllocateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; 3527 descriptorSetAllocateInfo.descriptorSetCount = 1; 3528 descriptorSetAllocateInfo.descriptorPool = descriptorPool; 3529 descriptorSetAllocateInfo.pSetLayouts = &descriptorSetLayout; 3530 3531 VkDescriptorSet descriptorSet = VK_NULL_HANDLE; 3532 VkResult result = (rendererData->currentDescriptorSetIndex >= SDL_VULKAN_MAX_DESCRIPTOR_SETS) ? VK_ERROR_OUT_OF_DEVICE_MEMORY : VK_SUCCESS; 3533 if (result == VK_SUCCESS) { 3534 result = vkAllocateDescriptorSets(rendererData->device, &descriptorSetAllocateInfo, &descriptorSet); 3535 } 3536 if (result != VK_SUCCESS) { 3537 // Out of descriptor sets in this pool - see if we have more pools allocated 3538 currentDescriptorPoolIndex++; 3539 if (currentDescriptorPoolIndex < rendererData->numDescriptorPools[rendererData->currentCommandBufferIndex]) { 3540 descriptorPool = rendererData->descriptorPools[rendererData->currentCommandBufferIndex][currentDescriptorPoolIndex]; 3541 descriptorSetAllocateInfo.descriptorPool = descriptorPool; 3542 result = vkAllocateDescriptorSets(rendererData->device, &descriptorSetAllocateInfo, &descriptorSet); 3543 if (result != VK_SUCCESS) { 3544 // This should not fail - we are allocating from the front of the descriptor set 3545 SDL_SetError("Unable to allocate descriptor set"); 3546 return VK_NULL_HANDLE; 3547 } 3548 rendererData->currentDescriptorPoolIndex = currentDescriptorPoolIndex; 3549 rendererData->currentDescriptorSetIndex = 0; 3550 3551 } 3552 // We are out of pools, create a new one 3553 else { 3554 descriptorPool = VULKAN_AllocateDescriptorPool(rendererData); 3555 if (descriptorPool == VK_NULL_HANDLE) { 3556 // SDL_SetError called in VULKAN_AllocateDescriptorPool if we failed to allocate a new pool 3557 return VK_NULL_HANDLE; 3558 } 3559 rendererData->numDescriptorPools[rendererData->currentCommandBufferIndex]++; 3560 VkDescriptorPool *descriptorPools = (VkDescriptorPool *)SDL_realloc(rendererData->descriptorPools[rendererData->currentCommandBufferIndex], 3561 sizeof(VkDescriptorPool) * rendererData->numDescriptorPools[rendererData->currentCommandBufferIndex]); 3562 descriptorPools[rendererData->numDescriptorPools[rendererData->currentCommandBufferIndex] - 1] = descriptorPool; 3563 rendererData->descriptorPools[rendererData->currentCommandBufferIndex] = descriptorPools; 3564 rendererData->currentDescriptorPoolIndex = currentDescriptorPoolIndex; 3565 rendererData->currentDescriptorSetIndex = 0; 3566 3567 // Call recursively to allocate from the new pool 3568 return VULKAN_AllocateDescriptorSet(renderer, shader, descriptorSetLayout, sampler, constantBuffer, constantBufferOffset, imageView); 3569 } 3570 } 3571 rendererData->currentDescriptorSetIndex++; 3572 VkDescriptorImageInfo combinedImageSamplerDescriptor = { 0 }; 3573 VkDescriptorBufferInfo bufferDescriptor = { 0 }; 3574 bufferDescriptor.buffer = constantBuffer; 3575 bufferDescriptor.offset = constantBufferOffset; 3576 bufferDescriptor.range = sizeof(VULKAN_PixelShaderConstants); 3577 3578 VkWriteDescriptorSet descriptorWrites[2]; 3579 SDL_memset(descriptorWrites, 0, sizeof(descriptorWrites)); 3580 uint32_t descriptorCount = 1; // Always have the uniform buffer 3581 3582 descriptorWrites[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; 3583 descriptorWrites[0].dstSet = descriptorSet; 3584 descriptorWrites[0].dstBinding = 1; 3585 descriptorWrites[0].dstArrayElement = 0; 3586 descriptorWrites[0].descriptorCount = 1; 3587 descriptorWrites[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; 3588 descriptorWrites[0].pBufferInfo = &bufferDescriptor; 3589 3590 if (sampler != VK_NULL_HANDLE && imageView != VK_NULL_HANDLE) { 3591 descriptorCount++; 3592 descriptorWrites[1].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; 3593 descriptorWrites[1].dstSet = descriptorSet; 3594 descriptorWrites[1].dstBinding = 0; 3595 descriptorWrites[1].dstArrayElement = 0; 3596 descriptorWrites[1].descriptorCount = 1; 3597 descriptorWrites[1].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; 3598 descriptorWrites[1].pImageInfo = &combinedImageSamplerDescriptor; 3599 3600 // Ignore the sampler if we're using YcBcCr data since it will be baked in the descriptor set layout 3601 if (descriptorSetLayout == rendererData->descriptorSetLayout) { 3602 combinedImageSamplerDescriptor.sampler = sampler; 3603 } 3604 combinedImageSamplerDescriptor.imageView = imageView; 3605 combinedImageSamplerDescriptor.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; 3606 } 3607 3608 vkUpdateDescriptorSets(rendererData->device, descriptorCount, descriptorWrites, 0, NULL); 3609 3610 return descriptorSet; 3611} 3612 3613static bool VULKAN_SetDrawState(SDL_Renderer *renderer, const SDL_RenderCommand *cmd, VULKAN_Shader shader, VkPipelineLayout pipelineLayout, VkDescriptorSetLayout descriptorSetLayout, 3614 const VULKAN_PixelShaderConstants *shader_constants, VkPrimitiveTopology topology, VkImageView imageView, VkSampler sampler, const Float4X4 *matrix, VULKAN_DrawStateCache *stateCache) 3615 3616{ 3617 VULKAN_RenderData *rendererData = (VULKAN_RenderData *)renderer->internal; 3618 const SDL_BlendMode blendMode = cmd->data.draw.blend; 3619 VkFormat format = rendererData->surfaceFormat.format; 3620 const Float4X4 *newmatrix = matrix ? matrix : &rendererData->identity; 3621 bool updateConstants = false; 3622 VULKAN_PixelShaderConstants solid_constants; 3623 VkDescriptorSet descriptorSet; 3624 VkBuffer constantBuffer; 3625 VkDeviceSize constantBufferOffset; 3626 int i; 3627 3628 if (!VULKAN_ActivateCommandBuffer(renderer, VK_ATTACHMENT_LOAD_OP_LOAD, NULL, stateCache)) { 3629 return false; 3630 } 3631 3632 // See if we need to change the pipeline state 3633 if (!rendererData->currentPipelineState || 3634 rendererData->currentPipelineState->shader != shader || 3635 rendererData->currentPipelineState->blendMode != blendMode || 3636 rendererData->currentPipelineState->topology != topology || 3637 rendererData->currentPipelineState->format != format || 3638 rendererData->currentPipelineState->pipelineLayout != pipelineLayout || 3639 rendererData->currentPipelineState->descriptorSetLayout != descriptorSetLayout) { 3640 3641 rendererData->currentPipelineState = NULL; 3642 for (i = 0; i < rendererData->pipelineStateCount; ++i) { 3643 VULKAN_PipelineState *candidatePiplineState = &rendererData->pipelineStates[i]; 3644 if (candidatePiplineState->shader == shader && 3645 candidatePiplineState->blendMode == blendMode && 3646 candidatePiplineState->topology == topology && 3647 candidatePiplineState->format == format && 3648 candidatePiplineState->pipelineLayout == pipelineLayout && 3649 candidatePiplineState->descriptorSetLayout == descriptorSetLayout) { 3650 rendererData->currentPipelineState = candidatePiplineState; 3651 break; 3652 } 3653 } 3654 3655 // If we didn't find a match, create a new one -- it must mean the blend mode is non-standard 3656 if (!rendererData->currentPipelineState) { 3657 rendererData->currentPipelineState = VULKAN_CreatePipelineState(renderer, shader, pipelineLayout, descriptorSetLayout, blendMode, topology, format); 3658 } 3659 3660 if (!rendererData->currentPipelineState) { 3661 return SDL_SetError("Unable to create required pipeline state"); 3662 } 3663 3664 vkCmdBindPipeline(rendererData->currentCommandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, rendererData->currentPipelineState->pipeline); 3665 updateConstants = true; 3666 } 3667 3668 if (rendererData->viewportDirty) { 3669 if (VULKAN_UpdateViewport(renderer)) { 3670 // vertexShaderConstantsData.projectionAndView has changed 3671 updateConstants = true; 3672 } 3673 } 3674 3675 if (rendererData->cliprectDirty) { 3676 VULKAN_UpdateClipRect(renderer); 3677 } 3678 3679 if (updateConstants == true || SDL_memcmp(&rendererData->vertexShaderConstantsData.model, newmatrix, sizeof(*newmatrix)) != 0) { 3680 SDL_memcpy(&rendererData->vertexShaderConstantsData.model, newmatrix, sizeof(*newmatrix)); 3681 vkCmdPushConstants(rendererData->currentCommandBuffer, rendererData->currentPipelineState->pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, 0, 3682 sizeof(rendererData->vertexShaderConstantsData), 3683 &rendererData->vertexShaderConstantsData); 3684 } 3685 3686 if (!shader_constants) { 3687 VULKAN_SetupShaderConstants(renderer, cmd, NULL, &solid_constants); 3688 shader_constants = &solid_constants; 3689 } 3690 3691 constantBuffer = rendererData->constantBuffers[rendererData->currentCommandBufferIndex][rendererData->currentConstantBufferIndex].buffer; 3692 constantBufferOffset = (rendererData->currentConstantBufferOffset < 0) ? 0 : rendererData->currentConstantBufferOffset; 3693 if (updateConstants || 3694 SDL_memcmp(shader_constants, &rendererData->currentPipelineState->shader_constants, sizeof(*shader_constants)) != 0) { 3695 3696 if (rendererData->currentConstantBufferOffset == -1) { 3697 // First time, grab offset 0 3698 rendererData->currentConstantBufferOffset = 0; 3699 constantBufferOffset = 0; 3700 } 3701 else { 3702 // Align the next address to the minUniformBufferOffsetAlignment 3703 VkDeviceSize alignment = rendererData->physicalDeviceProperties.limits.minUniformBufferOffsetAlignment; 3704 SDL_assert(rendererData->currentConstantBufferOffset >= 0 ); 3705 rendererData->currentConstantBufferOffset += (int32_t)(sizeof(VULKAN_PixelShaderConstants) + alignment - 1) & ~(alignment - 1); 3706 constantBufferOffset = rendererData->currentConstantBufferOffset; 3707 } 3708 3709 // If we have run out of size in this constant buffer, create another if needed 3710 if (rendererData->currentConstantBufferOffset >= SDL_VULKAN_CONSTANT_BUFFER_DEFAULT_SIZE) { 3711 uint32_t newConstantBufferIndex = (rendererData->currentConstantBufferIndex + 1); 3712 // We need a new constant buffer 3713 if (newConstantBufferIndex >= rendererData->numConstantBuffers[rendererData->currentCommandBufferIndex]) { 3714 VULKAN_Buffer newConstantBuffer; 3715 VkResult result = VULKAN_AllocateBuffer(rendererData, 3716 SDL_VULKAN_CONSTANT_BUFFER_DEFAULT_SIZE, 3717 VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, 3718 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | 3719 VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, 3720 VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, 3721 &newConstantBuffer); 3722 if (result != VK_SUCCESS) { 3723 return false; 3724 } 3725 3726 rendererData->numConstantBuffers[rendererData->currentCommandBufferIndex]++; 3727 VULKAN_Buffer *newConstantBuffers = (VULKAN_Buffer *)SDL_realloc(rendererData->constantBuffers[rendererData->currentCommandBufferIndex], 3728 sizeof(VULKAN_Buffer) * rendererData->numConstantBuffers[rendererData->currentCommandBufferIndex]); 3729 newConstantBuffers[rendererData->numConstantBuffers[rendererData->currentCommandBufferIndex] - 1] = newConstantBuffer; 3730 rendererData->constantBuffers[rendererData->currentCommandBufferIndex] = newConstantBuffers; 3731 } 3732 rendererData->currentConstantBufferIndex = newConstantBufferIndex; 3733 rendererData->currentConstantBufferOffset = 0; 3734 constantBufferOffset = 0; 3735 constantBuffer = rendererData->constantBuffers[rendererData->currentCommandBufferIndex][rendererData->currentConstantBufferIndex].buffer; 3736 } 3737 3738 SDL_memcpy(&rendererData->currentPipelineState->shader_constants, shader_constants, sizeof(*shader_constants)); 3739 3740 // Upload constants to persistently mapped buffer 3741 uint8_t *dst = (uint8_t *)rendererData->constantBuffers[rendererData->currentCommandBufferIndex][rendererData->currentConstantBufferIndex].mappedBufferPtr; 3742 dst += constantBufferOffset; 3743 SDL_memcpy(dst, &rendererData->currentPipelineState->shader_constants, sizeof(VULKAN_PixelShaderConstants)); 3744 } 3745 3746 // Allocate/update descriptor set with the bindings 3747 descriptorSet = VULKAN_AllocateDescriptorSet(renderer, shader, descriptorSetLayout, sampler, constantBuffer, constantBufferOffset, imageView); 3748 if (descriptorSet == VK_NULL_HANDLE) { 3749 return false; 3750 } 3751 3752 // Bind the descriptor set with the sampler/UBO/image views 3753 vkCmdBindDescriptorSets(rendererData->currentCommandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, rendererData->currentPipelineState->pipelineLayout, 3754 0, 1, &descriptorSet, 0, NULL); 3755 3756 return true; 3757} 3758 3759 3760static bool VULKAN_SetCopyState(SDL_Renderer *renderer, const SDL_RenderCommand *cmd, const Float4X4 *matrix, VULKAN_DrawStateCache *stateCache) 3761{ 3762 SDL_Texture *texture = cmd->data.draw.texture; 3763 VULKAN_RenderData *rendererData = (VULKAN_RenderData *)renderer->internal; 3764 VULKAN_TextureData *textureData = (VULKAN_TextureData *)texture->internal; 3765 VkSampler textureSampler = VK_NULL_HANDLE; 3766 VULKAN_PixelShaderConstants constants; 3767 VkDescriptorSetLayout descriptorSetLayout = (textureData->descriptorSetLayoutYcbcr != VK_NULL_HANDLE) ? textureData->descriptorSetLayoutYcbcr : rendererData->descriptorSetLayout; 3768 VkPipelineLayout pipelineLayout = (textureData->pipelineLayoutYcbcr != VK_NULL_HANDLE) ? textureData->pipelineLayoutYcbcr : rendererData->pipelineLayout; 3769 3770 VULKAN_SetupShaderConstants(renderer, cmd, texture, &constants); 3771 3772 switch (textureData->scaleMode) { 3773 case VK_FILTER_NEAREST: 3774 switch (cmd->data.draw.texture_address_mode) { 3775 case SDL_TEXTURE_ADDRESS_CLAMP: 3776 textureSampler = rendererData->samplers[VULKAN_SAMPLER_NEAREST_CLAMP]; 3777 break; 3778 case SDL_TEXTURE_ADDRESS_WRAP: 3779 textureSampler = rendererData->samplers[VULKAN_SAMPLER_NEAREST_WRAP]; 3780 break; 3781 default: 3782 return SDL_SetError("Unknown texture address mode: %d\n", cmd->data.draw.texture_address_mode); 3783 } 3784 break; 3785 case VK_FILTER_LINEAR: 3786 switch (cmd->data.draw.texture_address_mode) { 3787 case SDL_TEXTURE_ADDRESS_CLAMP: 3788 textureSampler = rendererData->samplers[VULKAN_SAMPLER_LINEAR_CLAMP]; 3789 break; 3790 case SDL_TEXTURE_ADDRESS_WRAP: 3791 textureSampler = rendererData->samplers[VULKAN_SAMPLER_LINEAR_WRAP]; 3792 break; 3793 default: 3794 return SDL_SetError("Unknown texture address mode: %d\n", cmd->data.draw.texture_address_mode); 3795 } 3796 break; 3797 default: 3798 return SDL_SetError("Unknown scale mode: %d", textureData->scaleMode); 3799 } 3800 3801 if (textureData->mainImage.imageLayout != VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) { 3802 bool stoppedRenderPass = false; 3803 if (rendererData->currentRenderPass != VK_NULL_HANDLE) { 3804 vkCmdEndRenderPass(rendererData->currentCommandBuffer); 3805 rendererData->currentRenderPass = VK_NULL_HANDLE; 3806 stoppedRenderPass = true; 3807 } 3808 3809 VULKAN_RecordPipelineImageBarrier(rendererData, 3810 VK_ACCESS_TRANSFER_WRITE_BIT | VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, 3811 VK_ACCESS_SHADER_READ_BIT, 3812 VK_PIPELINE_STAGE_TRANSFER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 3813 VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 3814 VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, 3815 textureData->mainImage.image, 3816 &textureData->mainImage.imageLayout); 3817 3818 if (stoppedRenderPass) { 3819 VULKAN_BeginRenderPass(rendererData, VK_ATTACHMENT_LOAD_OP_LOAD, NULL); 3820 } 3821 } 3822 3823 return VULKAN_SetDrawState(renderer, cmd, textureData->shader, pipelineLayout, descriptorSetLayout, &constants, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, textureData->mainImage.imageView, textureSampler, matrix, stateCache); 3824} 3825 3826static void VULKAN_DrawPrimitives(SDL_Renderer *renderer, VkPrimitiveTopology primitiveTopology, const size_t vertexStart, const size_t vertexCount) 3827{ 3828 VULKAN_RenderData *rendererData = (VULKAN_RenderData *)renderer->internal; 3829 vkCmdDraw(rendererData->currentCommandBuffer, (uint32_t)vertexCount, 1, (uint32_t)vertexStart, 0); 3830} 3831 3832static void VULKAN_InvalidateCachedState(SDL_Renderer *renderer) 3833{ 3834 VULKAN_RenderData *rendererData = (VULKAN_RenderData *)renderer->internal; 3835 rendererData->currentPipelineState = NULL; 3836 rendererData->cliprectDirty = true; 3837} 3838 3839static bool VULKAN_RunCommandQueue(SDL_Renderer *renderer, SDL_RenderCommand *cmd, void *vertices, size_t vertsize) 3840{ 3841 VULKAN_RenderData *rendererData = (VULKAN_RenderData *)renderer->internal; 3842 VkSurfaceTransformFlagBitsKHR currentRotation = VULKAN_GetRotationForCurrentRenderTarget(rendererData); 3843 VULKAN_DrawStateCache stateCache; 3844 SDL_memset(&stateCache, 0, sizeof(stateCache)); 3845 3846 if (!rendererData->device) { 3847 return SDL_SetError("Device lost and couldn't be recovered"); 3848 } 3849 3850 if(rendererData->currentViewportRotation != currentRotation) { 3851 rendererData->currentViewportRotation = currentRotation; 3852 rendererData->viewportDirty = true; 3853 rendererData->cliprectDirty = true; 3854 } 3855 3856 if (rendererData->recreateSwapchain) { 3857 if (VULKAN_UpdateForWindowSizeChange(renderer) != VK_SUCCESS) { 3858 return false; 3859 } 3860 rendererData->recreateSwapchain = false; 3861 } 3862 3863 if (!VULKAN_UpdateVertexBuffer(renderer, vertices, vertsize, &stateCache)) { 3864 return false; 3865 } 3866 3867 while (cmd) { 3868 switch (cmd->command) { 3869 case SDL_RENDERCMD_SETDRAWCOLOR: 3870 { 3871 break; // this isn't currently used in this render backend. 3872 } 3873 3874 case SDL_RENDERCMD_SETVIEWPORT: 3875 { 3876 SDL_Rect *viewport = &rendererData->currentViewport; 3877 if (SDL_memcmp(viewport, &cmd->data.viewport.rect, sizeof(cmd->data.viewport.rect)) != 0) { 3878 SDL_copyp(viewport, &cmd->data.viewport.rect); 3879 rendererData->viewportDirty = true; 3880 rendererData->cliprectDirty = true; 3881 } 3882 break; 3883 } 3884 3885 case SDL_RENDERCMD_SETCLIPRECT: 3886 { 3887 const SDL_Rect *rect = &cmd->data.cliprect.rect; 3888 if (rendererData->currentCliprectEnabled != cmd->data.cliprect.enabled) { 3889 rendererData->currentCliprectEnabled = cmd->data.cliprect.enabled; 3890 rendererData->cliprectDirty = true; 3891 } 3892 if (SDL_memcmp(&rendererData->currentCliprect, rect, sizeof(*rect)) != 0) { 3893 SDL_copyp(&rendererData->currentCliprect, rect); 3894 rendererData->cliprectDirty = true; 3895 } 3896 break; 3897 } 3898 3899 case SDL_RENDERCMD_CLEAR: 3900 { 3901 bool convert_color = SDL_RenderingLinearSpace(renderer); 3902 SDL_FColor color = cmd->data.color.color; 3903 if (convert_color) { 3904 SDL_ConvertToLinear(&color); 3905 } 3906 color.r *= cmd->data.color.color_scale; 3907 color.g *= cmd->data.color.color_scale; 3908 color.b *= cmd->data.color.color_scale; 3909 3910 VkClearColorValue clearColor; 3911 clearColor.float32[0] = color.r; 3912 clearColor.float32[1] = color.g; 3913 clearColor.float32[2] = color.b; 3914 clearColor.float32[3] = color.a; 3915 VULKAN_ActivateCommandBuffer(renderer, VK_ATTACHMENT_LOAD_OP_CLEAR, &clearColor, &stateCache); 3916 break; 3917 } 3918 3919 case SDL_RENDERCMD_DRAW_POINTS: 3920 { 3921 const size_t count = cmd->data.draw.count; 3922 const size_t first = cmd->data.draw.first; 3923 const size_t start = first / sizeof(VULKAN_VertexPositionColor); 3924 VULKAN_SetDrawState(renderer, cmd, SHADER_SOLID, rendererData->pipelineLayout, rendererData->descriptorSetLayout, NULL, VK_PRIMITIVE_TOPOLOGY_POINT_LIST, VK_NULL_HANDLE, VK_NULL_HANDLE, NULL, &stateCache); 3925 VULKAN_DrawPrimitives(renderer, VK_PRIMITIVE_TOPOLOGY_POINT_LIST, start, count); 3926 break; 3927 } 3928 3929 case SDL_RENDERCMD_DRAW_LINES: 3930 { 3931 const size_t count = cmd->data.draw.count; 3932 const size_t first = cmd->data.draw.first; 3933 const size_t start = first / sizeof(VULKAN_VertexPositionColor); 3934 const VULKAN_VertexPositionColor *verts = (VULKAN_VertexPositionColor *)(((Uint8 *)vertices) + first); 3935 VULKAN_SetDrawState(renderer, cmd, SHADER_SOLID, rendererData->pipelineLayout, rendererData->descriptorSetLayout, NULL, VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, VK_NULL_HANDLE, VK_NULL_HANDLE, NULL, &stateCache); 3936 VULKAN_DrawPrimitives(renderer, VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, start, count); 3937 if (verts[0].pos[0] != verts[count - 1].pos[0] || verts[0].pos[1] != verts[count - 1].pos[1]) { 3938 VULKAN_SetDrawState(renderer, cmd, SHADER_SOLID, rendererData->pipelineLayout, rendererData->descriptorSetLayout, NULL, VK_PRIMITIVE_TOPOLOGY_POINT_LIST, VK_NULL_HANDLE, VK_NULL_HANDLE, NULL, &stateCache); 3939 VULKAN_DrawPrimitives(renderer, VK_PRIMITIVE_TOPOLOGY_POINT_LIST, start + (count - 1), 1); 3940 } 3941 break; 3942 } 3943 3944 case SDL_RENDERCMD_FILL_RECTS: // unused 3945 break; 3946 3947 case SDL_RENDERCMD_COPY: // unused 3948 break; 3949 3950 case SDL_RENDERCMD_COPY_EX: // unused 3951 break; 3952 3953 case SDL_RENDERCMD_GEOMETRY: 3954 { 3955 SDL_Texture *texture = cmd->data.draw.texture; 3956 const size_t count = cmd->data.draw.count; 3957 const size_t first = cmd->data.draw.first; 3958 const size_t start = first / sizeof(VULKAN_VertexPositionColor); 3959 3960 if (texture) { 3961 VULKAN_SetCopyState(renderer, cmd, NULL, &stateCache); 3962 } else { 3963 VULKAN_SetDrawState(renderer, cmd, SHADER_SOLID, rendererData->pipelineLayout, rendererData->descriptorSetLayout, NULL, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, VK_NULL_HANDLE, VK_NULL_HANDLE, NULL, &stateCache); 3964 } 3965 3966 VULKAN_DrawPrimitives(renderer, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, start, count); 3967 break; 3968 } 3969 3970 case SDL_RENDERCMD_NO_OP: 3971 break; 3972 } 3973 3974 cmd = cmd->next; 3975 } 3976 return true; 3977} 3978 3979static SDL_Surface* VULKAN_RenderReadPixels(SDL_Renderer *renderer, const SDL_Rect *rect) 3980{ 3981 VULKAN_RenderData *rendererData = (VULKAN_RenderData *)renderer->internal; 3982 VkImage backBuffer; 3983 VkImageLayout *imageLayout; 3984 VULKAN_Buffer readbackBuffer; 3985 VkDeviceSize pixelSize; 3986 VkDeviceSize length; 3987 VkDeviceSize readbackBufferSize; 3988 VkFormat vkFormat; 3989 SDL_Surface *output; 3990 3991 VULKAN_EnsureCommandBuffer(rendererData); 3992 3993 // Stop any outstanding renderpass if open 3994 if (rendererData->currentRenderPass != VK_NULL_HANDLE) { 3995 vkCmdEndRenderPass(rendererData->currentCommandBuffer); 3996 rendererData->currentRenderPass = VK_NULL_HANDLE; 3997 } 3998 3999 if (rendererData->textureRenderTarget) { 4000 backBuffer = rendererData->textureRenderTarget->mainImage.image; 4001 imageLayout = &rendererData->textureRenderTarget->mainImage.imageLayout; 4002 vkFormat = rendererData->textureRenderTarget->mainImage.format; 4003 } else { 4004 backBuffer = rendererData->swapchainImages[rendererData->currentSwapchainImageIndex]; 4005 imageLayout = &rendererData->swapchainImageLayouts[rendererData->currentSwapchainImageIndex]; 4006 vkFormat = rendererData->surfaceFormat.format; 4007 } 4008 4009 pixelSize = VULKAN_GetBytesPerPixel(vkFormat); 4010 length = rect->w * pixelSize; 4011 readbackBufferSize = length * rect->h; 4012 if (VULKAN_AllocateBuffer(rendererData, readbackBufferSize, 4013 VK_BUFFER_USAGE_TRANSFER_DST_BIT, 4014 VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | 4015 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, 4016 VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, 4017 &readbackBuffer) != VK_SUCCESS) { 4018 return NULL; 4019 } 4020 4021 4022 // Make sure the source is in the correct resource state 4023 VULKAN_RecordPipelineImageBarrier(rendererData, 4024 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, 4025 VK_ACCESS_TRANSFER_READ_BIT, 4026 VK_PIPELINE_STAGE_TRANSFER_BIT | VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 4027 VK_PIPELINE_STAGE_TRANSFER_BIT, 4028 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, 4029 backBuffer, 4030 imageLayout); 4031 4032 // Copy the image to the readback buffer 4033 VkBufferImageCopy region; 4034 region.bufferOffset = 0; 4035 region.bufferRowLength = 0; 4036 region.bufferImageHeight = 0; 4037 region.imageSubresource.baseArrayLayer = 0; 4038 region.imageSubresource.layerCount = 1; 4039 region.imageSubresource.mipLevel = 0; 4040 region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; 4041 region.imageOffset.x = rect->x; 4042 region.imageOffset.y = rect->y; 4043 region.imageOffset.z = 0; 4044 region.imageExtent.width = rect->w; 4045 region.imageExtent.height = rect->h; 4046 region.imageExtent.depth = 1; 4047 vkCmdCopyImageToBuffer(rendererData->currentCommandBuffer, backBuffer, *imageLayout, readbackBuffer.buffer, 1, &region); 4048 4049 // We need to issue the command list for the copy to finish 4050 VULKAN_IssueBatch(rendererData); 4051 4052 // Transition the render target back to a render target 4053 VULKAN_RecordPipelineImageBarrier(rendererData, 4054 VK_ACCESS_TRANSFER_WRITE_BIT, 4055 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, 4056 VK_PIPELINE_STAGE_TRANSFER_BIT, 4057 VK_PIPELINE_STAGE_TRANSFER_BIT | VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 4058 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, 4059 backBuffer, 4060 imageLayout); 4061 4062 output = SDL_DuplicatePixels( 4063 rect->w, rect->h, 4064 VULKAN_VkFormatToSDLPixelFormat(vkFormat), 4065 renderer->target ? renderer->target->colorspace : renderer->output_colorspace, 4066 readbackBuffer.mappedBufferPtr, 4067 (int)length); 4068 4069 VULKAN_DestroyBuffer(rendererData, &readbackBuffer); 4070 4071 return output; 4072} 4073 4074static bool VULKAN_AddVulkanRenderSemaphores(SDL_Renderer *renderer, Uint32 wait_stage_mask, Sint64 wait_semaphore, Sint64 signal_semaphore) 4075{ 4076 VULKAN_RenderData *rendererData = (VULKAN_RenderData *)renderer->internal; 4077 4078 if (wait_semaphore) { 4079 if (rendererData->waitRenderSemaphoreCount == rendererData->waitRenderSemaphoreMax) { 4080 // Allocate an additional one at the end for the normal present wait 4081 VkPipelineStageFlags *waitDestStageMasks = (VkPipelineStageFlags *)SDL_realloc(rendererData->waitDestStageMasks, (rendererData->waitRenderSemaphoreMax + 2) * sizeof(*waitDestStageMasks)); 4082 if (!waitDestStageMasks) { 4083 return false; 4084 } 4085 rendererData->waitDestStageMasks = waitDestStageMasks; 4086 4087 VkSemaphore *semaphores = (VkSemaphore *)SDL_realloc(rendererData->waitRenderSemaphores, (rendererData->waitRenderSemaphoreMax + 2) * sizeof(*semaphores)); 4088 if (!semaphores) { 4089 return false; 4090 } 4091 rendererData->waitRenderSemaphores = semaphores; 4092 ++rendererData->waitRenderSemaphoreMax; 4093 } 4094 rendererData->waitDestStageMasks[rendererData->waitRenderSemaphoreCount] = wait_stage_mask; 4095 rendererData->waitRenderSemaphores[rendererData->waitRenderSemaphoreCount] = (VkSemaphore)wait_semaphore; 4096 ++rendererData->waitRenderSemaphoreCount; 4097 } 4098 4099 if (signal_semaphore) { 4100 if (rendererData->signalRenderSemaphoreCount == rendererData->signalRenderSemaphoreMax) { 4101 // Allocate an additional one at the end for the normal present signal 4102 VkSemaphore *semaphores = (VkSemaphore *)SDL_realloc(rendererData->signalRenderSemaphores, (rendererData->signalRenderSemaphoreMax + 2) * sizeof(*semaphores)); 4103 if (!semaphores) { 4104 return false; 4105 } 4106 rendererData->signalRenderSemaphores = semaphores; 4107 ++rendererData->signalRenderSemaphoreMax; 4108 } 4109 rendererData->signalRenderSemaphores[rendererData->signalRenderSemaphoreCount] = (VkSemaphore)signal_semaphore; 4110 ++rendererData->signalRenderSemaphoreCount; 4111 } 4112 4113 return true; 4114} 4115 4116static bool VULKAN_RenderPresent(SDL_Renderer *renderer) 4117{ 4118 VULKAN_RenderData *rendererData = (VULKAN_RenderData *)renderer->internal; 4119 VkResult result = VK_SUCCESS; 4120 4121 if (!rendererData->device) { 4122 return SDL_SetError("Device lost and couldn't be recovered"); 4123 } 4124 4125 if (rendererData->currentCommandBuffer) { 4126 rendererData->currentPipelineState = VK_NULL_HANDLE; 4127 rendererData->viewportDirty = true; 4128 4129 VULKAN_RecordPipelineImageBarrier(rendererData, 4130 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, 4131 VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, 4132 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 4133 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 4134 VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, 4135 rendererData->swapchainImages[rendererData->currentSwapchainImageIndex], 4136 &rendererData->swapchainImageLayouts[rendererData->currentSwapchainImageIndex]); 4137 4138 vkEndCommandBuffer(rendererData->currentCommandBuffer); 4139 4140 result = vkResetFences(rendererData->device, 1, &rendererData->fences[rendererData->currentCommandBufferIndex]); 4141 if (result != VK_SUCCESS) { 4142 SET_ERROR_CODE("vkResetFences()", result); 4143 return false; 4144 } 4145 4146 VkPipelineStageFlags waitDestStageMask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT; 4147 VkSubmitInfo submitInfo = { 0 }; 4148 submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; 4149 if (rendererData->waitRenderSemaphoreCount > 0) { 4150 Uint32 additionalSemaphoreCount = (rendererData->currentImageAvailableSemaphore != VK_NULL_HANDLE) ? 1 : 0; 4151 submitInfo.waitSemaphoreCount = rendererData->waitRenderSemaphoreCount + additionalSemaphoreCount; 4152 if (additionalSemaphoreCount > 0) { 4153 rendererData->waitRenderSemaphores[rendererData->waitRenderSemaphoreCount] = rendererData->currentImageAvailableSemaphore; 4154 rendererData->waitDestStageMasks[rendererData->waitRenderSemaphoreCount] = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT; 4155 } 4156 submitInfo.pWaitSemaphores = rendererData->waitRenderSemaphores; 4157 submitInfo.pWaitDstStageMask = rendererData->waitDestStageMasks; 4158 rendererData->waitRenderSemaphoreCount = 0; 4159 } else if (rendererData->currentImageAvailableSemaphore != VK_NULL_HANDLE) { 4160 submitInfo.waitSemaphoreCount = 1; 4161 submitInfo.pWaitSemaphores = &rendererData->currentImageAvailableSemaphore; 4162 submitInfo.pWaitDstStageMask = &waitDestStageMask; 4163 } 4164 submitInfo.commandBufferCount = 1; 4165 submitInfo.pCommandBuffers = &rendererData->currentCommandBuffer; 4166 if (rendererData->signalRenderSemaphoreCount > 0) { 4167 submitInfo.signalSemaphoreCount = rendererData->signalRenderSemaphoreCount + 1; 4168 rendererData->signalRenderSemaphores[rendererData->signalRenderSemaphoreCount] = rendererData->renderingFinishedSemaphores[rendererData->currentCommandBufferIndex]; 4169 submitInfo.pSignalSemaphores = rendererData->signalRenderSemaphores; 4170 rendererData->signalRenderSemaphoreCount = 0; 4171 } else { 4172 submitInfo.signalSemaphoreCount = 1; 4173 submitInfo.pSignalSemaphores = &rendererData->renderingFinishedSemaphores[rendererData->currentCommandBufferIndex]; 4174 } 4175 result = vkQueueSubmit(rendererData->graphicsQueue, 1, &submitInfo, rendererData->fences[rendererData->currentCommandBufferIndex]); 4176 if (result != VK_SUCCESS) { 4177 if (result == VK_ERROR_DEVICE_LOST) { 4178 if (VULKAN_HandleDeviceLost(renderer)) { 4179 SDL_SetError("Present failed, device lost"); 4180 } else { 4181 // Recovering from device lost failed, error is already set 4182 } 4183 } else { 4184 SET_ERROR_CODE("vkQueueSubmit()", result); 4185 } 4186 return false; 4187 } 4188 rendererData->currentCommandBuffer = VK_NULL_HANDLE; 4189 rendererData->currentImageAvailableSemaphore = VK_NULL_HANDLE; 4190 4191 VkPresentInfoKHR presentInfo = { 0 }; 4192 presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; 4193 presentInfo.waitSemaphoreCount = 1; 4194 presentInfo.pWaitSemaphores = &rendererData->renderingFinishedSemaphores[rendererData->currentCommandBufferIndex]; 4195 presentInfo.swapchainCount = 1; 4196 presentInfo.pSwapchains = &rendererData->swapchain; 4197 presentInfo.pImageIndices = &rendererData->currentSwapchainImageIndex; 4198 result = vkQueuePresentKHR(rendererData->presentQueue, &presentInfo); 4199 if ((result != VK_SUCCESS) && (result != VK_ERROR_OUT_OF_DATE_KHR) && (result != VK_ERROR_SURFACE_LOST_KHR) && (result != VK_SUBOPTIMAL_KHR )) { 4200 SET_ERROR_CODE("vkQueuePresentKHR()", result); 4201 return false; 4202 } 4203 4204 rendererData->currentCommandBufferIndex = ( rendererData->currentCommandBufferIndex + 1 ) % rendererData->swapchainImageCount; 4205 4206 // Wait for previous time this command buffer was submitted, will be N frames ago 4207 result = vkWaitForFences(rendererData->device, 1, &rendererData->fences[rendererData->currentCommandBufferIndex], VK_TRUE, UINT64_MAX); 4208 if (result != VK_SUCCESS) { 4209 if (result == VK_ERROR_DEVICE_LOST) { 4210 if (VULKAN_HandleDeviceLost(renderer)) { 4211 SDL_SetError("Present failed, device lost"); 4212 } else { 4213 // Recovering from device lost failed, error is already set 4214 } 4215 } else { 4216 SET_ERROR_CODE("vkWaitForFences()", result); 4217 } 4218 return false; 4219 } 4220 4221 VULKAN_AcquireNextSwapchainImage(renderer); 4222 } 4223 4224 return true; 4225} 4226 4227static bool VULKAN_SetVSync(SDL_Renderer *renderer, const int vsync) 4228{ 4229 VULKAN_RenderData *rendererData = (VULKAN_RenderData *)renderer->internal; 4230 4231 switch (vsync) { 4232 case -1: 4233 case 0: 4234 case 1: 4235 // Supported 4236 break; 4237 default: 4238 return SDL_Unsupported(); 4239 } 4240 if (vsync != rendererData->vsync) { 4241 rendererData->vsync = vsync; 4242 rendererData->recreateSwapchain = true; 4243 } 4244 return true; 4245} 4246 4247static bool VULKAN_CreateRenderer(SDL_Renderer *renderer, SDL_Window *window, SDL_PropertiesID create_props) 4248{ 4249 VULKAN_RenderData *rendererData; 4250 4251 SDL_SetupRendererColorspace(renderer, create_props); 4252 4253 if (renderer->output_colorspace != SDL_COLORSPACE_SRGB && 4254 renderer->output_colorspace != SDL_COLORSPACE_SRGB_LINEAR 4255 /*&& renderer->output_colorspace != SDL_COLORSPACE_HDR10*/) { 4256 return SDL_SetError("Unsupported output colorspace"); 4257 } 4258 4259 rendererData = (VULKAN_RenderData *)SDL_calloc(1, sizeof(*rendererData)); 4260 if (!rendererData) { 4261 return false; 4262 } 4263 4264 rendererData->identity = MatrixIdentity(); 4265 rendererData->identitySwizzle.r = VK_COMPONENT_SWIZZLE_IDENTITY; 4266 rendererData->identitySwizzle.g = VK_COMPONENT_SWIZZLE_IDENTITY; 4267 rendererData->identitySwizzle.b = VK_COMPONENT_SWIZZLE_IDENTITY; 4268 rendererData->identitySwizzle.a = VK_COMPONENT_SWIZZLE_IDENTITY; 4269 4270 // Save the create props in case we need to recreate on device lost 4271 rendererData->create_props = SDL_CreateProperties(); 4272 if (!SDL_CopyProperties(create_props, rendererData->create_props)) { 4273 SDL_free(rendererData); 4274 return false; 4275 } 4276 4277 renderer->WindowEvent = VULKAN_WindowEvent; 4278 renderer->SupportsBlendMode = VULKAN_SupportsBlendMode; 4279 renderer->CreateTexture = VULKAN_CreateTexture; 4280 renderer->UpdateTexture = VULKAN_UpdateTexture; 4281#ifdef SDL_HAVE_YUV 4282 renderer->UpdateTextureYUV = VULKAN_UpdateTextureYUV; 4283 renderer->UpdateTextureNV = VULKAN_UpdateTextureNV; 4284#endif 4285 renderer->LockTexture = VULKAN_LockTexture; 4286 renderer->UnlockTexture = VULKAN_UnlockTexture; 4287 renderer->SetTextureScaleMode = VULKAN_SetTextureScaleMode; 4288 renderer->SetRenderTarget = VULKAN_SetRenderTarget; 4289 renderer->QueueSetViewport = VULKAN_QueueNoOp; 4290 renderer->QueueSetDrawColor = VULKAN_QueueNoOp; 4291 renderer->QueueDrawPoints = VULKAN_QueueDrawPoints; 4292 renderer->QueueDrawLines = VULKAN_QueueDrawPoints; // lines and points queue vertices the same way. 4293 renderer->QueueGeometry = VULKAN_QueueGeometry; 4294 renderer->InvalidateCachedState = VULKAN_InvalidateCachedState; 4295 renderer->RunCommandQueue = VULKAN_RunCommandQueue; 4296 renderer->RenderReadPixels = VULKAN_RenderReadPixels; 4297 renderer->AddVulkanRenderSemaphores = VULKAN_AddVulkanRenderSemaphores; 4298 renderer->RenderPresent = VULKAN_RenderPresent; 4299 renderer->DestroyTexture = VULKAN_DestroyTexture; 4300 renderer->DestroyRenderer = VULKAN_DestroyRenderer; 4301 renderer->SetVSync = VULKAN_SetVSync; 4302 renderer->internal = rendererData; 4303 VULKAN_InvalidateCachedState(renderer); 4304 4305 renderer->name = VULKAN_RenderDriver.name; 4306 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_ARGB8888); 4307 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_XRGB8888); 4308 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_XBGR2101010); 4309 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_RGBA64_FLOAT); 4310 SDL_SetNumberProperty(SDL_GetRendererProperties(renderer), SDL_PROP_RENDERER_MAX_TEXTURE_SIZE_NUMBER, 16384); 4311 4312 /* HACK: make sure the SDL_Renderer references the SDL_Window data now, in 4313 * order to give init functions access to the underlying window handle: 4314 */ 4315 renderer->window = window; 4316 4317 // Initialize Vulkan resources 4318 if (VULKAN_CreateDeviceResources(renderer, create_props) != VK_SUCCESS) { 4319 return false; 4320 } 4321 4322 if (VULKAN_CreateWindowSizeDependentResources(renderer) != VK_SUCCESS) { 4323 return false; 4324 } 4325 4326#ifdef SDL_HAVE_YUV 4327 if (rendererData->supportsKHRSamplerYCbCrConversion) { 4328 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_YV12); 4329 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_IYUV); 4330 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_NV12); 4331 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_NV21); 4332 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_P010); 4333 } 4334#endif 4335 4336 return true; 4337} 4338 4339SDL_RenderDriver VULKAN_RenderDriver = { 4340 VULKAN_CreateRenderer, "vulkan" 4341}; 4342 4343#endif // SDL_VIDEO_RENDER_VULKAN