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