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 | #include "SDL_vulkan_internal.h" |
24 | |
25 | #ifdef SDL_VIDEO_VULKAN |
26 | |
27 | const char *SDL_Vulkan_GetResultString(VkResult result) |
28 | { |
29 | switch ((int)result) { |
30 | case VK_SUCCESS: |
31 | return "VK_SUCCESS" ; |
32 | case VK_NOT_READY: |
33 | return "VK_NOT_READY" ; |
34 | case VK_TIMEOUT: |
35 | return "VK_TIMEOUT" ; |
36 | case VK_EVENT_SET: |
37 | return "VK_EVENT_SET" ; |
38 | case VK_EVENT_RESET: |
39 | return "VK_EVENT_RESET" ; |
40 | case VK_INCOMPLETE: |
41 | return "VK_INCOMPLETE" ; |
42 | case VK_ERROR_OUT_OF_HOST_MEMORY: |
43 | return "VK_ERROR_OUT_OF_HOST_MEMORY" ; |
44 | case VK_ERROR_OUT_OF_DEVICE_MEMORY: |
45 | return "VK_ERROR_OUT_OF_DEVICE_MEMORY" ; |
46 | case VK_ERROR_INITIALIZATION_FAILED: |
47 | return "VK_ERROR_INITIALIZATION_FAILED" ; |
48 | case VK_ERROR_DEVICE_LOST: |
49 | return "VK_ERROR_DEVICE_LOST" ; |
50 | case VK_ERROR_MEMORY_MAP_FAILED: |
51 | return "VK_ERROR_MEMORY_MAP_FAILED" ; |
52 | case VK_ERROR_LAYER_NOT_PRESENT: |
53 | return "VK_ERROR_LAYER_NOT_PRESENT" ; |
54 | case VK_ERROR_EXTENSION_NOT_PRESENT: |
55 | return "VK_ERROR_EXTENSION_NOT_PRESENT" ; |
56 | case VK_ERROR_FEATURE_NOT_PRESENT: |
57 | return "VK_ERROR_FEATURE_NOT_PRESENT" ; |
58 | case VK_ERROR_INCOMPATIBLE_DRIVER: |
59 | return "VK_ERROR_INCOMPATIBLE_DRIVER" ; |
60 | case VK_ERROR_TOO_MANY_OBJECTS: |
61 | return "VK_ERROR_TOO_MANY_OBJECTS" ; |
62 | case VK_ERROR_FORMAT_NOT_SUPPORTED: |
63 | return "VK_ERROR_FORMAT_NOT_SUPPORTED" ; |
64 | case VK_ERROR_FRAGMENTED_POOL: |
65 | return "VK_ERROR_FRAGMENTED_POOL" ; |
66 | case VK_ERROR_UNKNOWN: |
67 | return "VK_ERROR_UNKNOWN" ; |
68 | case VK_ERROR_OUT_OF_POOL_MEMORY: |
69 | return "VK_ERROR_OUT_OF_POOL_MEMORY" ; |
70 | case VK_ERROR_INVALID_EXTERNAL_HANDLE: |
71 | return "VK_ERROR_INVALID_EXTERNAL_HANDLE" ; |
72 | case VK_ERROR_FRAGMENTATION: |
73 | return "VK_ERROR_FRAGMENTATION" ; |
74 | case VK_ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS: |
75 | return "VK_ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS" ; |
76 | case VK_ERROR_SURFACE_LOST_KHR: |
77 | return "VK_ERROR_SURFACE_LOST_KHR" ; |
78 | case VK_ERROR_NATIVE_WINDOW_IN_USE_KHR: |
79 | return "VK_ERROR_NATIVE_WINDOW_IN_USE_KHR" ; |
80 | case VK_SUBOPTIMAL_KHR: |
81 | return "VK_SUBOPTIMAL_KHR" ; |
82 | case VK_ERROR_OUT_OF_DATE_KHR: |
83 | return "VK_ERROR_OUT_OF_DATE_KHR" ; |
84 | case VK_ERROR_INCOMPATIBLE_DISPLAY_KHR: |
85 | return "VK_ERROR_INCOMPATIBLE_DISPLAY_KHR" ; |
86 | case VK_ERROR_VALIDATION_FAILED_EXT: |
87 | return "VK_ERROR_VALIDATION_FAILED_EXT" ; |
88 | case VK_ERROR_INVALID_SHADER_NV: |
89 | return "VK_ERROR_INVALID_SHADER_NV" ; |
90 | #if VK_HEADER_VERSION >= 135 && VK_HEADER_VERSION < 162 |
91 | case VK_ERROR_INCOMPATIBLE_VERSION_KHR: |
92 | return "VK_ERROR_INCOMPATIBLE_VERSION_KHR" ; |
93 | #endif |
94 | case VK_ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT: |
95 | return "VK_ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT" ; |
96 | case VK_ERROR_NOT_PERMITTED_EXT: |
97 | return "VK_ERROR_NOT_PERMITTED_EXT" ; |
98 | case VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT: |
99 | return "VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT" ; |
100 | case VK_THREAD_IDLE_KHR: |
101 | return "VK_THREAD_IDLE_KHR" ; |
102 | case VK_THREAD_DONE_KHR: |
103 | return "VK_THREAD_DONE_KHR" ; |
104 | case VK_OPERATION_DEFERRED_KHR: |
105 | return "VK_OPERATION_DEFERRED_KHR" ; |
106 | case VK_OPERATION_NOT_DEFERRED_KHR: |
107 | return "VK_OPERATION_NOT_DEFERRED_KHR" ; |
108 | case VK_PIPELINE_COMPILE_REQUIRED_EXT: |
109 | return "VK_PIPELINE_COMPILE_REQUIRED_EXT" ; |
110 | default: |
111 | break; |
112 | } |
113 | if (result < 0) { |
114 | return "VK_ERROR_<Unknown>" ; |
115 | } |
116 | return "VK_<Unknown>" ; |
117 | } |
118 | |
119 | VkExtensionProperties *SDL_Vulkan_CreateInstanceExtensionsList( |
120 | PFN_vkEnumerateInstanceExtensionProperties vkEnumerateInstanceExtensionProperties, |
121 | Uint32 *extensionCount) |
122 | { |
123 | Uint32 count = 0; |
124 | VkResult rc = vkEnumerateInstanceExtensionProperties(NULL, &count, NULL); |
125 | VkExtensionProperties *result; |
126 | |
127 | if (rc == VK_ERROR_INCOMPATIBLE_DRIVER) { |
128 | // Avoid the ERR_MAX_STRLEN limit by passing part of the message as a string argument. |
129 | SDL_SetError( |
130 | "You probably don't have a working Vulkan driver installed. %s %s %s(%d)" , |
131 | "Getting Vulkan extensions failed:" , |
132 | "vkEnumerateInstanceExtensionProperties returned" , |
133 | SDL_Vulkan_GetResultString(rc), |
134 | (int)rc); |
135 | return NULL; |
136 | } else if (rc != VK_SUCCESS) { |
137 | SDL_SetError( |
138 | "Getting Vulkan extensions failed: vkEnumerateInstanceExtensionProperties returned " |
139 | "%s(%d)" , |
140 | SDL_Vulkan_GetResultString(rc), |
141 | (int)rc); |
142 | return NULL; |
143 | } |
144 | |
145 | if (count == 0) { |
146 | result = (VkExtensionProperties *)SDL_calloc(1, sizeof(VkExtensionProperties)); // so we can return non-null |
147 | } else { |
148 | result = (VkExtensionProperties *)SDL_calloc(count, sizeof(VkExtensionProperties)); |
149 | } |
150 | |
151 | if (!result) { |
152 | return NULL; |
153 | } |
154 | |
155 | rc = vkEnumerateInstanceExtensionProperties(NULL, &count, result); |
156 | if (rc != VK_SUCCESS) { |
157 | SDL_SetError( |
158 | "Getting Vulkan extensions failed: vkEnumerateInstanceExtensionProperties returned " |
159 | "%s(%d)" , |
160 | SDL_Vulkan_GetResultString(rc), |
161 | (int)rc); |
162 | SDL_free(result); |
163 | return NULL; |
164 | } |
165 | *extensionCount = count; |
166 | return result; |
167 | } |
168 | |
169 | // Alpha modes, in order of preference |
170 | static const VkDisplayPlaneAlphaFlagBitsKHR alphaModes[4] = { |
171 | VK_DISPLAY_PLANE_ALPHA_OPAQUE_BIT_KHR, |
172 | VK_DISPLAY_PLANE_ALPHA_GLOBAL_BIT_KHR, |
173 | VK_DISPLAY_PLANE_ALPHA_PER_PIXEL_BIT_KHR, |
174 | VK_DISPLAY_PLANE_ALPHA_PER_PIXEL_PREMULTIPLIED_BIT_KHR, |
175 | }; |
176 | |
177 | bool SDL_Vulkan_Display_CreateSurface(void *vkGetInstanceProcAddr_, |
178 | VkInstance instance, |
179 | const struct VkAllocationCallbacks *allocator, |
180 | VkSurfaceKHR *surface) |
181 | { |
182 | PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = |
183 | (PFN_vkGetInstanceProcAddr)vkGetInstanceProcAddr_; |
184 | #define VULKAN_INSTANCE_FUNCTION(name) \ |
185 | PFN_##name name = (PFN_##name)vkGetInstanceProcAddr((VkInstance)instance, #name) |
186 | VULKAN_INSTANCE_FUNCTION(vkEnumeratePhysicalDevices); |
187 | VULKAN_INSTANCE_FUNCTION(vkGetPhysicalDeviceDisplayPropertiesKHR); |
188 | VULKAN_INSTANCE_FUNCTION(vkGetDisplayModePropertiesKHR); |
189 | VULKAN_INSTANCE_FUNCTION(vkGetPhysicalDeviceDisplayPlanePropertiesKHR); |
190 | VULKAN_INSTANCE_FUNCTION(vkGetDisplayPlaneCapabilitiesKHR); |
191 | VULKAN_INSTANCE_FUNCTION(vkGetDisplayPlaneSupportedDisplaysKHR); |
192 | VULKAN_INSTANCE_FUNCTION(vkCreateDisplayPlaneSurfaceKHR); |
193 | #undef VULKAN_INSTANCE_FUNCTION |
194 | VkDisplaySurfaceCreateInfoKHR createInfo; |
195 | VkResult rc; |
196 | uint32_t physicalDeviceCount = 0; |
197 | VkPhysicalDevice *physicalDevices = NULL; |
198 | uint32_t physicalDeviceIndex; |
199 | const char *chosenDisplayId; |
200 | int displayId = 0; // Counting from physical device 0, display 0 |
201 | |
202 | if (!vkEnumeratePhysicalDevices || |
203 | !vkGetPhysicalDeviceDisplayPropertiesKHR || |
204 | !vkGetDisplayModePropertiesKHR || |
205 | !vkGetPhysicalDeviceDisplayPlanePropertiesKHR || |
206 | !vkGetDisplayPlaneCapabilitiesKHR || |
207 | !vkGetDisplayPlaneSupportedDisplaysKHR || |
208 | !vkCreateDisplayPlaneSurfaceKHR) { |
209 | SDL_SetError(VK_KHR_DISPLAY_EXTENSION_NAME " extension is not enabled in the Vulkan instance." ); |
210 | goto error; |
211 | } |
212 | chosenDisplayId = SDL_GetHint(SDL_HINT_VULKAN_DISPLAY); |
213 | if (chosenDisplayId) { |
214 | displayId = SDL_atoi(chosenDisplayId); |
215 | } |
216 | |
217 | // Enumerate physical devices |
218 | rc = vkEnumeratePhysicalDevices(instance, &physicalDeviceCount, NULL); |
219 | if (rc != VK_SUCCESS) { |
220 | SDL_SetError("Could not enumerate Vulkan physical devices" ); |
221 | goto error; |
222 | } |
223 | |
224 | if (physicalDeviceCount == 0) { |
225 | SDL_SetError("No Vulkan physical devices" ); |
226 | goto error; |
227 | } |
228 | |
229 | physicalDevices = (VkPhysicalDevice *)SDL_malloc(sizeof(VkPhysicalDevice) * physicalDeviceCount); |
230 | if (!physicalDevices) { |
231 | goto error; |
232 | } |
233 | |
234 | rc = vkEnumeratePhysicalDevices(instance, &physicalDeviceCount, physicalDevices); |
235 | if (rc != VK_SUCCESS) { |
236 | SDL_SetError("Error enumerating physical devices" ); |
237 | goto error; |
238 | } |
239 | |
240 | for (physicalDeviceIndex = 0; physicalDeviceIndex < physicalDeviceCount; physicalDeviceIndex++) { |
241 | VkPhysicalDevice physicalDevice = physicalDevices[physicalDeviceIndex]; |
242 | uint32_t displayPropertiesCount = 0; |
243 | VkDisplayPropertiesKHR *displayProperties = NULL; |
244 | uint32_t displayModePropertiesCount = 0; |
245 | VkDisplayModePropertiesKHR *displayModeProperties = NULL; |
246 | int bestMatchIndex = -1; |
247 | uint32_t refreshRate = 0; |
248 | uint32_t i; |
249 | uint32_t displayPlanePropertiesCount = 0; |
250 | int planeIndex = -1; |
251 | VkDisplayKHR display; |
252 | VkDisplayPlanePropertiesKHR *displayPlaneProperties = NULL; |
253 | VkExtent2D extent; |
254 | VkDisplayPlaneCapabilitiesKHR planeCaps = { 0 }; |
255 | |
256 | // Get information about the physical displays |
257 | rc = vkGetPhysicalDeviceDisplayPropertiesKHR(physicalDevice, &displayPropertiesCount, NULL); |
258 | if (rc != VK_SUCCESS || displayPropertiesCount == 0) { |
259 | // This device has no physical device display properties, move on to next. |
260 | continue; |
261 | } |
262 | SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "vulkandisplay: Number of display properties for device %u: %u" , |
263 | physicalDeviceIndex, displayPropertiesCount); |
264 | |
265 | if (displayId < 0 || (uint32_t)displayId >= displayPropertiesCount) { |
266 | // Display id specified was higher than number of available displays, move to next physical device. |
267 | displayId -= displayPropertiesCount; |
268 | continue; |
269 | } |
270 | |
271 | displayProperties = (VkDisplayPropertiesKHR *)SDL_malloc(sizeof(VkDisplayPropertiesKHR) * displayPropertiesCount); |
272 | if (!displayProperties) { |
273 | goto error; |
274 | } |
275 | |
276 | rc = vkGetPhysicalDeviceDisplayPropertiesKHR(physicalDevice, &displayPropertiesCount, displayProperties); |
277 | if (rc != VK_SUCCESS || displayPropertiesCount == 0) { |
278 | SDL_free(displayProperties); |
279 | SDL_SetError("Error enumerating physical device displays" ); |
280 | goto error; |
281 | } |
282 | |
283 | display = displayProperties[displayId].display; |
284 | extent = displayProperties[displayId].physicalResolution; |
285 | SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "vulkandisplay: Display: %s Native resolution: %ux%u" , |
286 | displayProperties[displayId].displayName, extent.width, extent.height); |
287 | |
288 | SDL_free(displayProperties); |
289 | displayProperties = NULL; |
290 | |
291 | // Get display mode properties for the chosen display |
292 | rc = vkGetDisplayModePropertiesKHR(physicalDevice, display, &displayModePropertiesCount, NULL); |
293 | if (rc != VK_SUCCESS || displayModePropertiesCount == 0) { |
294 | SDL_SetError("Error enumerating display modes" ); |
295 | goto error; |
296 | } |
297 | SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "vulkandisplay: Number of display modes: %u" , displayModePropertiesCount); |
298 | |
299 | displayModeProperties = (VkDisplayModePropertiesKHR *)SDL_malloc(sizeof(VkDisplayModePropertiesKHR) * displayModePropertiesCount); |
300 | if (!displayModeProperties) { |
301 | goto error; |
302 | } |
303 | |
304 | rc = vkGetDisplayModePropertiesKHR(physicalDevice, display, &displayModePropertiesCount, displayModeProperties); |
305 | if (rc != VK_SUCCESS || displayModePropertiesCount == 0) { |
306 | SDL_SetError("Error enumerating display modes" ); |
307 | SDL_free(displayModeProperties); |
308 | goto error; |
309 | } |
310 | |
311 | // Try to find a display mode that matches the native resolution |
312 | for (i = 0; i < displayModePropertiesCount; ++i) { |
313 | if (displayModeProperties[i].parameters.visibleRegion.width == extent.width && |
314 | displayModeProperties[i].parameters.visibleRegion.height == extent.height && |
315 | displayModeProperties[i].parameters.refreshRate > refreshRate) { |
316 | bestMatchIndex = i; |
317 | refreshRate = displayModeProperties[i].parameters.refreshRate; |
318 | } |
319 | } |
320 | |
321 | if (bestMatchIndex < 0) { |
322 | SDL_SetError("Found no matching display mode" ); |
323 | SDL_free(displayModeProperties); |
324 | goto error; |
325 | } |
326 | |
327 | SDL_zero(createInfo); |
328 | createInfo.displayMode = displayModeProperties[bestMatchIndex].displayMode; |
329 | SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "vulkandisplay: Matching mode %ux%u with refresh rate %u" , |
330 | displayModeProperties[bestMatchIndex].parameters.visibleRegion.width, |
331 | displayModeProperties[bestMatchIndex].parameters.visibleRegion.height, |
332 | refreshRate); |
333 | |
334 | SDL_free(displayModeProperties); |
335 | displayModeProperties = NULL; |
336 | |
337 | // Try to find a plane index that supports our display |
338 | rc = vkGetPhysicalDeviceDisplayPlanePropertiesKHR(physicalDevice, &displayPlanePropertiesCount, NULL); |
339 | if (rc != VK_SUCCESS || displayPlanePropertiesCount == 0) { |
340 | SDL_SetError("Error enumerating display planes" ); |
341 | goto error; |
342 | } |
343 | SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "vulkandisplay: Number of display planes: %u" , displayPlanePropertiesCount); |
344 | |
345 | displayPlaneProperties = (VkDisplayPlanePropertiesKHR *)SDL_malloc(sizeof(VkDisplayPlanePropertiesKHR) * displayPlanePropertiesCount); |
346 | if (!displayPlaneProperties) { |
347 | goto error; |
348 | } |
349 | |
350 | rc = vkGetPhysicalDeviceDisplayPlanePropertiesKHR(physicalDevice, &displayPlanePropertiesCount, displayPlaneProperties); |
351 | if (rc != VK_SUCCESS || displayPlanePropertiesCount == 0) { |
352 | SDL_SetError("Error enumerating display plane properties" ); |
353 | SDL_free(displayPlaneProperties); |
354 | goto error; |
355 | } |
356 | |
357 | for (i = 0; i < displayPlanePropertiesCount; ++i) { |
358 | uint32_t planeSupportedDisplaysCount = 0; |
359 | VkDisplayKHR *planeSupportedDisplays = NULL; |
360 | uint32_t j; |
361 | |
362 | // Check if plane is attached to a display, if not, continue. |
363 | if (displayPlaneProperties[i].currentDisplay == VK_NULL_HANDLE) { |
364 | continue; |
365 | } |
366 | |
367 | // Check supported displays for this plane. |
368 | rc = vkGetDisplayPlaneSupportedDisplaysKHR(physicalDevice, i, &planeSupportedDisplaysCount, NULL); |
369 | if (rc != VK_SUCCESS || planeSupportedDisplaysCount == 0) { |
370 | continue; // No supported displays, on to next plane. |
371 | } |
372 | |
373 | SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "vulkandisplay: Number of supported displays for plane %u: %u" , i, planeSupportedDisplaysCount); |
374 | |
375 | planeSupportedDisplays = (VkDisplayKHR *)SDL_malloc(sizeof(VkDisplayKHR) * planeSupportedDisplaysCount); |
376 | if (!planeSupportedDisplays) { |
377 | SDL_free(displayPlaneProperties); |
378 | goto error; |
379 | } |
380 | |
381 | rc = vkGetDisplayPlaneSupportedDisplaysKHR(physicalDevice, i, &planeSupportedDisplaysCount, planeSupportedDisplays); |
382 | if (rc != VK_SUCCESS || planeSupportedDisplaysCount == 0) { |
383 | SDL_SetError("Error enumerating supported displays, or no supported displays" ); |
384 | SDL_free(planeSupportedDisplays); |
385 | SDL_free(displayPlaneProperties); |
386 | goto error; |
387 | } |
388 | |
389 | for (j = 0; j < planeSupportedDisplaysCount && planeSupportedDisplays[j] != display; ++j) { |
390 | } |
391 | |
392 | SDL_free(planeSupportedDisplays); |
393 | planeSupportedDisplays = NULL; |
394 | |
395 | if (j == planeSupportedDisplaysCount) { |
396 | // This display is not supported for this plane, move on. |
397 | continue; |
398 | } |
399 | |
400 | rc = vkGetDisplayPlaneCapabilitiesKHR(physicalDevice, createInfo.displayMode, i, &planeCaps); |
401 | if (rc != VK_SUCCESS) { |
402 | SDL_SetError("Error getting display plane capabilities" ); |
403 | SDL_free(displayPlaneProperties); |
404 | goto error; |
405 | } |
406 | |
407 | // Check if plane fulfills extent requirements. |
408 | if (extent.width >= planeCaps.minDstExtent.width && extent.height >= planeCaps.minDstExtent.height && |
409 | extent.width <= planeCaps.maxDstExtent.width && extent.height <= planeCaps.maxDstExtent.height) { |
410 | // If it does, choose this plane. |
411 | SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "vulkandisplay: Choosing plane %u, minimum extent %ux%u maximum extent %ux%u" , i, |
412 | planeCaps.minDstExtent.width, planeCaps.minDstExtent.height, |
413 | planeCaps.maxDstExtent.width, planeCaps.maxDstExtent.height); |
414 | planeIndex = i; |
415 | break; |
416 | } |
417 | } |
418 | |
419 | if (planeIndex < 0) { |
420 | SDL_SetError("No plane supports the selected resolution" ); |
421 | SDL_free(displayPlaneProperties); |
422 | goto error; |
423 | } |
424 | |
425 | createInfo.planeIndex = planeIndex; |
426 | createInfo.planeStackIndex = displayPlaneProperties[planeIndex].currentStackIndex; |
427 | SDL_free(displayPlaneProperties); |
428 | displayPlaneProperties = NULL; |
429 | |
430 | // Find a supported alpha mode. Not all planes support OPAQUE |
431 | createInfo.alphaMode = VK_DISPLAY_PLANE_ALPHA_OPAQUE_BIT_KHR; |
432 | for (i = 0; i < SDL_arraysize(alphaModes); i++) { |
433 | if (planeCaps.supportedAlpha & alphaModes[i]) { |
434 | createInfo.alphaMode = alphaModes[i]; |
435 | break; |
436 | } |
437 | } |
438 | SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "vulkandisplay: Chose alpha mode 0x%x" , createInfo.alphaMode); |
439 | |
440 | // Found a match, finally! Fill in extent, and break from loop |
441 | createInfo.imageExtent = extent; |
442 | break; |
443 | } |
444 | |
445 | SDL_free(physicalDevices); |
446 | physicalDevices = NULL; |
447 | |
448 | if (physicalDeviceIndex == physicalDeviceCount) { |
449 | SDL_SetError("No usable displays found or requested display out of range" ); |
450 | goto error; |
451 | } |
452 | |
453 | createInfo.sType = VK_STRUCTURE_TYPE_DISPLAY_SURFACE_CREATE_INFO_KHR; |
454 | createInfo.transform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; |
455 | createInfo.globalAlpha = 1.0f; |
456 | |
457 | rc = vkCreateDisplayPlaneSurfaceKHR(instance, &createInfo, allocator, surface); |
458 | if (rc != VK_SUCCESS) { |
459 | SDL_SetError("vkCreateDisplayPlaneSurfaceKHR failed: %s" , SDL_Vulkan_GetResultString(rc)); |
460 | goto error; |
461 | } |
462 | SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "vulkandisplay: Created surface" ); |
463 | return true; |
464 | |
465 | error: |
466 | SDL_free(physicalDevices); |
467 | return false; |
468 | } |
469 | |
470 | void SDL_Vulkan_DestroySurface_Internal(void *vkGetInstanceProcAddr_, |
471 | VkInstance instance, |
472 | VkSurfaceKHR surface, |
473 | const struct VkAllocationCallbacks *allocator) |
474 | { |
475 | PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = |
476 | (PFN_vkGetInstanceProcAddr)vkGetInstanceProcAddr_; |
477 | PFN_vkDestroySurfaceKHR vkDestroySurfaceKHR = |
478 | (PFN_vkDestroySurfaceKHR)vkGetInstanceProcAddr( |
479 | instance, |
480 | "vkDestroySurfaceKHR" ); |
481 | |
482 | if (vkDestroySurfaceKHR) { |
483 | vkDestroySurfaceKHR(instance, surface, allocator); |
484 | } |
485 | } |
486 | |
487 | #endif |
488 | |