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