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