| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476 |
- /*
- Simple DirectMedia Layer
- Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
- This software is provided 'as-is', without any express or implied
- warranty. In no event will the authors be held liable for any damages
- arising from the use of this software.
- Permission is granted to anyone to use this software for any purpose,
- including commercial applications, and to alter it and redistribute it
- freely, subject to the following restrictions:
- 1. The origin of this software must not be misrepresented; you must not
- claim that you wrote the original software. If you use this software
- in a product, an acknowledgment in the product documentation would be
- appreciated but is not required.
- 2. Altered source versions must be plainly marked as such, and must not be
- misrepresented as being the original software.
- 3. This notice may not be removed or altered from any source distribution.
- */
- #include "SDL_internal.h"
- #include "SDL_vulkan_internal.h"
- #ifdef SDL_VIDEO_VULKAN
- const char *SDL_Vulkan_GetResultString(VkResult result)
- {
- switch ((int)result) {
- case VK_SUCCESS:
- return "VK_SUCCESS";
- case VK_NOT_READY:
- return "VK_NOT_READY";
- case VK_TIMEOUT:
- return "VK_TIMEOUT";
- case VK_EVENT_SET:
- return "VK_EVENT_SET";
- case VK_EVENT_RESET:
- return "VK_EVENT_RESET";
- case VK_INCOMPLETE:
- return "VK_INCOMPLETE";
- case VK_ERROR_OUT_OF_HOST_MEMORY:
- return "VK_ERROR_OUT_OF_HOST_MEMORY";
- case VK_ERROR_OUT_OF_DEVICE_MEMORY:
- return "VK_ERROR_OUT_OF_DEVICE_MEMORY";
- case VK_ERROR_INITIALIZATION_FAILED:
- return "VK_ERROR_INITIALIZATION_FAILED";
- case VK_ERROR_DEVICE_LOST:
- return "VK_ERROR_DEVICE_LOST";
- case VK_ERROR_MEMORY_MAP_FAILED:
- return "VK_ERROR_MEMORY_MAP_FAILED";
- case VK_ERROR_LAYER_NOT_PRESENT:
- return "VK_ERROR_LAYER_NOT_PRESENT";
- case VK_ERROR_EXTENSION_NOT_PRESENT:
- return "VK_ERROR_EXTENSION_NOT_PRESENT";
- case VK_ERROR_FEATURE_NOT_PRESENT:
- return "VK_ERROR_FEATURE_NOT_PRESENT";
- case VK_ERROR_INCOMPATIBLE_DRIVER:
- return "VK_ERROR_INCOMPATIBLE_DRIVER";
- case VK_ERROR_TOO_MANY_OBJECTS:
- return "VK_ERROR_TOO_MANY_OBJECTS";
- case VK_ERROR_FORMAT_NOT_SUPPORTED:
- return "VK_ERROR_FORMAT_NOT_SUPPORTED";
- case VK_ERROR_FRAGMENTED_POOL:
- return "VK_ERROR_FRAGMENTED_POOL";
- case VK_ERROR_UNKNOWN:
- return "VK_ERROR_UNKNOWN";
- case VK_ERROR_OUT_OF_POOL_MEMORY:
- return "VK_ERROR_OUT_OF_POOL_MEMORY";
- case VK_ERROR_INVALID_EXTERNAL_HANDLE:
- return "VK_ERROR_INVALID_EXTERNAL_HANDLE";
- case VK_ERROR_FRAGMENTATION:
- return "VK_ERROR_FRAGMENTATION";
- case VK_ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS:
- return "VK_ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS";
- case VK_ERROR_SURFACE_LOST_KHR:
- return "VK_ERROR_SURFACE_LOST_KHR";
- case VK_ERROR_NATIVE_WINDOW_IN_USE_KHR:
- return "VK_ERROR_NATIVE_WINDOW_IN_USE_KHR";
- case VK_SUBOPTIMAL_KHR:
- return "VK_SUBOPTIMAL_KHR";
- case VK_ERROR_OUT_OF_DATE_KHR:
- return "VK_ERROR_OUT_OF_DATE_KHR";
- case VK_ERROR_INCOMPATIBLE_DISPLAY_KHR:
- return "VK_ERROR_INCOMPATIBLE_DISPLAY_KHR";
- case VK_ERROR_VALIDATION_FAILED_EXT:
- return "VK_ERROR_VALIDATION_FAILED_EXT";
- case VK_ERROR_INVALID_SHADER_NV:
- return "VK_ERROR_INVALID_SHADER_NV";
- #if VK_HEADER_VERSION >= 135 && VK_HEADER_VERSION < 162
- case VK_ERROR_INCOMPATIBLE_VERSION_KHR:
- return "VK_ERROR_INCOMPATIBLE_VERSION_KHR";
- #endif
- case VK_ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT:
- return "VK_ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT";
- case VK_ERROR_NOT_PERMITTED_EXT:
- return "VK_ERROR_NOT_PERMITTED_EXT";
- case VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT:
- return "VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT";
- case VK_THREAD_IDLE_KHR:
- return "VK_THREAD_IDLE_KHR";
- case VK_THREAD_DONE_KHR:
- return "VK_THREAD_DONE_KHR";
- case VK_OPERATION_DEFERRED_KHR:
- return "VK_OPERATION_DEFERRED_KHR";
- case VK_OPERATION_NOT_DEFERRED_KHR:
- return "VK_OPERATION_NOT_DEFERRED_KHR";
- case VK_PIPELINE_COMPILE_REQUIRED_EXT:
- return "VK_PIPELINE_COMPILE_REQUIRED_EXT";
- default:
- break;
- }
- if (result < 0) {
- return "VK_ERROR_<Unknown>";
- }
- return "VK_<Unknown>";
- }
- VkExtensionProperties *SDL_Vulkan_CreateInstanceExtensionsList(
- PFN_vkEnumerateInstanceExtensionProperties vkEnumerateInstanceExtensionProperties,
- Uint32 *extensionCount)
- {
- Uint32 count = 0;
- VkResult result = vkEnumerateInstanceExtensionProperties(NULL, &count, NULL);
- VkExtensionProperties *retval;
- if (result == VK_ERROR_INCOMPATIBLE_DRIVER) {
- /* Avoid the ERR_MAX_STRLEN limit by passing part of the message as a string argument. */
- SDL_SetError(
- "You probably don't have a working Vulkan driver installed. %s %s %s(%d)",
- "Getting Vulkan extensions failed:",
- "vkEnumerateInstanceExtensionProperties returned",
- SDL_Vulkan_GetResultString(result),
- (int)result);
- return NULL;
- } else if (result != VK_SUCCESS) {
- SDL_SetError(
- "Getting Vulkan extensions failed: vkEnumerateInstanceExtensionProperties returned "
- "%s(%d)",
- SDL_Vulkan_GetResultString(result),
- (int)result);
- return NULL;
- }
- if (count == 0) {
- retval = SDL_calloc(1, sizeof(VkExtensionProperties)); // so we can return non-null
- } else {
- retval = SDL_calloc(count, sizeof(VkExtensionProperties));
- }
- if (retval == NULL) {
- SDL_OutOfMemory();
- return NULL;
- }
- result = vkEnumerateInstanceExtensionProperties(NULL, &count, retval);
- if (result != VK_SUCCESS) {
- SDL_SetError(
- "Getting Vulkan extensions failed: vkEnumerateInstanceExtensionProperties returned "
- "%s(%d)",
- SDL_Vulkan_GetResultString(result),
- (int)result);
- SDL_free(retval);
- return NULL;
- }
- *extensionCount = count;
- return retval;
- }
- /* Alpha modes, in order of preference */
- static const VkDisplayPlaneAlphaFlagBitsKHR alphaModes[4] = {
- VK_DISPLAY_PLANE_ALPHA_OPAQUE_BIT_KHR,
- VK_DISPLAY_PLANE_ALPHA_GLOBAL_BIT_KHR,
- VK_DISPLAY_PLANE_ALPHA_PER_PIXEL_BIT_KHR,
- VK_DISPLAY_PLANE_ALPHA_PER_PIXEL_PREMULTIPLIED_BIT_KHR,
- };
- SDL_bool SDL_Vulkan_Display_CreateSurface(void *vkGetInstanceProcAddr_,
- VkInstance instance,
- const struct VkAllocationCallbacks *allocator,
- VkSurfaceKHR *surface)
- {
- PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr =
- (PFN_vkGetInstanceProcAddr)vkGetInstanceProcAddr_;
- #define VULKAN_INSTANCE_FUNCTION(name) \
- PFN_##name name = (PFN_##name)vkGetInstanceProcAddr((VkInstance)instance, #name)
- VULKAN_INSTANCE_FUNCTION(vkEnumeratePhysicalDevices);
- VULKAN_INSTANCE_FUNCTION(vkGetPhysicalDeviceDisplayPropertiesKHR);
- VULKAN_INSTANCE_FUNCTION(vkGetDisplayModePropertiesKHR);
- VULKAN_INSTANCE_FUNCTION(vkGetPhysicalDeviceDisplayPlanePropertiesKHR);
- VULKAN_INSTANCE_FUNCTION(vkGetDisplayPlaneCapabilitiesKHR);
- VULKAN_INSTANCE_FUNCTION(vkGetDisplayPlaneSupportedDisplaysKHR);
- VULKAN_INSTANCE_FUNCTION(vkCreateDisplayPlaneSurfaceKHR);
- #undef VULKAN_INSTANCE_FUNCTION
- VkDisplaySurfaceCreateInfoKHR createInfo;
- VkResult result;
- uint32_t physicalDeviceCount = 0;
- VkPhysicalDevice *physicalDevices = NULL;
- uint32_t physicalDeviceIndex;
- const char *chosenDisplayId;
- int displayId = 0; /* Counting from physical device 0, display 0 */
- if (!vkEnumeratePhysicalDevices ||
- !vkGetPhysicalDeviceDisplayPropertiesKHR ||
- !vkGetDisplayModePropertiesKHR ||
- !vkGetPhysicalDeviceDisplayPlanePropertiesKHR ||
- !vkGetDisplayPlaneCapabilitiesKHR ||
- !vkGetDisplayPlaneSupportedDisplaysKHR ||
- !vkCreateDisplayPlaneSurfaceKHR) {
- SDL_SetError(VK_KHR_DISPLAY_EXTENSION_NAME " extension is not enabled in the Vulkan instance.");
- goto error;
- }
- chosenDisplayId = SDL_getenv("SDL_VULKAN_DISPLAY");
- if (chosenDisplayId != NULL) {
- displayId = SDL_atoi(chosenDisplayId);
- }
- /* Enumerate physical devices */
- result = vkEnumeratePhysicalDevices(instance, &physicalDeviceCount, NULL);
- if (result != VK_SUCCESS) {
- SDL_SetError("Could not enumerate Vulkan physical devices");
- goto error;
- }
- if (physicalDeviceCount == 0) {
- SDL_SetError("No Vulkan physical devices");
- goto error;
- }
- physicalDevices = SDL_malloc(sizeof(VkPhysicalDevice) * physicalDeviceCount);
- if (physicalDevices == NULL) {
- SDL_OutOfMemory();
- goto error;
- }
- result = vkEnumeratePhysicalDevices(instance, &physicalDeviceCount, physicalDevices);
- if (result != VK_SUCCESS) {
- SDL_SetError("Error enumerating physical devices");
- goto error;
- }
- for (physicalDeviceIndex = 0; physicalDeviceIndex < physicalDeviceCount; physicalDeviceIndex++) {
- VkPhysicalDevice physicalDevice = physicalDevices[physicalDeviceIndex];
- uint32_t displayPropertiesCount = 0;
- VkDisplayPropertiesKHR *displayProperties = NULL;
- uint32_t displayModePropertiesCount = 0;
- VkDisplayModePropertiesKHR *displayModeProperties = NULL;
- int bestMatchIndex = -1;
- uint32_t refreshRate = 0;
- uint32_t i;
- uint32_t displayPlanePropertiesCount = 0;
- int planeIndex = -1;
- VkDisplayKHR display;
- VkDisplayPlanePropertiesKHR *displayPlaneProperties = NULL;
- VkExtent2D extent;
- VkDisplayPlaneCapabilitiesKHR planeCaps = { 0 };
- /* Get information about the physical displays */
- result = vkGetPhysicalDeviceDisplayPropertiesKHR(physicalDevice, &displayPropertiesCount, NULL);
- if (result != VK_SUCCESS || displayPropertiesCount == 0) {
- /* This device has no physical device display properties, move on to next. */
- continue;
- }
- SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "vulkandisplay: Number of display properties for device %u: %u",
- physicalDeviceIndex, displayPropertiesCount);
- if (displayId < 0 || (uint32_t)displayId >= displayPropertiesCount) {
- /* Display id specified was higher than number of available displays, move to next physical device. */
- displayId -= displayPropertiesCount;
- continue;
- }
- displayProperties = SDL_malloc(sizeof(VkDisplayPropertiesKHR) * displayPropertiesCount);
- if (displayProperties == NULL) {
- SDL_OutOfMemory();
- goto error;
- }
- result = vkGetPhysicalDeviceDisplayPropertiesKHR(physicalDevice, &displayPropertiesCount, displayProperties);
- if (result != VK_SUCCESS || displayPropertiesCount == 0) {
- SDL_free(displayProperties);
- SDL_SetError("Error enumerating physical device displays");
- goto error;
- }
- display = displayProperties[displayId].display;
- extent = displayProperties[displayId].physicalResolution;
- SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "vulkandisplay: Display: %s Native resolution: %ux%u",
- displayProperties[displayId].displayName, extent.width, extent.height);
- SDL_free(displayProperties);
- displayProperties = NULL;
- /* Get display mode properties for the chosen display */
- result = vkGetDisplayModePropertiesKHR(physicalDevice, display, &displayModePropertiesCount, NULL);
- if (result != VK_SUCCESS || displayModePropertiesCount == 0) {
- SDL_SetError("Error enumerating display modes");
- goto error;
- }
- SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "vulkandisplay: Number of display modes: %u", displayModePropertiesCount);
- displayModeProperties = SDL_malloc(sizeof(VkDisplayModePropertiesKHR) * displayModePropertiesCount);
- if (displayModeProperties == NULL) {
- SDL_OutOfMemory();
- goto error;
- }
- result = vkGetDisplayModePropertiesKHR(physicalDevice, display, &displayModePropertiesCount, displayModeProperties);
- if (result != VK_SUCCESS || displayModePropertiesCount == 0) {
- SDL_SetError("Error enumerating display modes");
- SDL_free(displayModeProperties);
- goto error;
- }
- /* Try to find a display mode that matches the native resolution */
- for (i = 0; i < displayModePropertiesCount; ++i) {
- if (displayModeProperties[i].parameters.visibleRegion.width == extent.width &&
- displayModeProperties[i].parameters.visibleRegion.height == extent.height &&
- displayModeProperties[i].parameters.refreshRate > refreshRate) {
- bestMatchIndex = i;
- refreshRate = displayModeProperties[i].parameters.refreshRate;
- }
- }
- if (bestMatchIndex < 0) {
- SDL_SetError("Found no matching display mode");
- SDL_free(displayModeProperties);
- goto error;
- }
- SDL_zero(createInfo);
- createInfo.displayMode = displayModeProperties[bestMatchIndex].displayMode;
- SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "vulkandisplay: Matching mode %ux%u with refresh rate %u",
- displayModeProperties[bestMatchIndex].parameters.visibleRegion.width,
- displayModeProperties[bestMatchIndex].parameters.visibleRegion.height,
- refreshRate);
- SDL_free(displayModeProperties);
- displayModeProperties = NULL;
- /* Try to find a plane index that supports our display */
- result = vkGetPhysicalDeviceDisplayPlanePropertiesKHR(physicalDevice, &displayPlanePropertiesCount, NULL);
- if (result != VK_SUCCESS || displayPlanePropertiesCount == 0) {
- SDL_SetError("Error enumerating display planes");
- goto error;
- }
- SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "vulkandisplay: Number of display planes: %u", displayPlanePropertiesCount);
- displayPlaneProperties = SDL_malloc(sizeof(VkDisplayPlanePropertiesKHR) * displayPlanePropertiesCount);
- if (displayPlaneProperties == NULL) {
- SDL_OutOfMemory();
- goto error;
- }
- result = vkGetPhysicalDeviceDisplayPlanePropertiesKHR(physicalDevice, &displayPlanePropertiesCount, displayPlaneProperties);
- if (result != VK_SUCCESS || displayPlanePropertiesCount == 0) {
- SDL_SetError("Error enumerating display plane properties");
- SDL_free(displayPlaneProperties);
- goto error;
- }
- for (i = 0; i < displayPlanePropertiesCount; ++i) {
- uint32_t planeSupportedDisplaysCount = 0;
- VkDisplayKHR *planeSupportedDisplays = NULL;
- uint32_t j;
- /* Check if plane is attached to a display, if not, continue. */
- if (displayPlaneProperties[i].currentDisplay == VK_NULL_HANDLE) {
- continue;
- }
- /* Check supported displays for this plane. */
- result = vkGetDisplayPlaneSupportedDisplaysKHR(physicalDevice, i, &planeSupportedDisplaysCount, NULL);
- if (result != VK_SUCCESS || planeSupportedDisplaysCount == 0) {
- continue; /* No supported displays, on to next plane. */
- }
- SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "vulkandisplay: Number of supported displays for plane %u: %u", i, planeSupportedDisplaysCount);
- planeSupportedDisplays = SDL_malloc(sizeof(VkDisplayKHR) * planeSupportedDisplaysCount);
- if (planeSupportedDisplays == NULL) {
- SDL_free(displayPlaneProperties);
- SDL_OutOfMemory();
- goto error;
- }
- result = vkGetDisplayPlaneSupportedDisplaysKHR(physicalDevice, i, &planeSupportedDisplaysCount, planeSupportedDisplays);
- if (result != VK_SUCCESS || planeSupportedDisplaysCount == 0) {
- SDL_SetError("Error enumerating supported displays, or no supported displays");
- SDL_free(planeSupportedDisplays);
- SDL_free(displayPlaneProperties);
- goto error;
- }
- for (j = 0; j < planeSupportedDisplaysCount && planeSupportedDisplays[j] != display; ++j) {
- }
- SDL_free(planeSupportedDisplays);
- planeSupportedDisplays = NULL;
- if (j == planeSupportedDisplaysCount) {
- /* This display is not supported for this plane, move on. */
- continue;
- }
- result = vkGetDisplayPlaneCapabilitiesKHR(physicalDevice, createInfo.displayMode, i, &planeCaps);
- if (result != VK_SUCCESS) {
- SDL_SetError("Error getting display plane capabilities");
- SDL_free(displayPlaneProperties);
- goto error;
- }
- /* Check if plane fulfills extent requirements. */
- if (extent.width >= planeCaps.minDstExtent.width && extent.height >= planeCaps.minDstExtent.height &&
- extent.width <= planeCaps.maxDstExtent.width && extent.height <= planeCaps.maxDstExtent.height) {
- /* If it does, choose this plane. */
- SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "vulkandisplay: Choosing plane %d, minimum extent %dx%d maximum extent %dx%d", i,
- planeCaps.minDstExtent.width, planeCaps.minDstExtent.height,
- planeCaps.maxDstExtent.width, planeCaps.maxDstExtent.height);
- planeIndex = i;
- break;
- }
- }
- if (planeIndex < 0) {
- SDL_SetError("No plane supports the selected resolution");
- SDL_free(displayPlaneProperties);
- goto error;
- }
- createInfo.planeIndex = planeIndex;
- createInfo.planeStackIndex = displayPlaneProperties[planeIndex].currentStackIndex;
- SDL_free(displayPlaneProperties);
- displayPlaneProperties = NULL;
- /* Find a supported alpha mode. Not all planes support OPAQUE */
- createInfo.alphaMode = VK_DISPLAY_PLANE_ALPHA_OPAQUE_BIT_KHR;
- for (i = 0; i < SDL_arraysize(alphaModes); i++) {
- if (planeCaps.supportedAlpha & alphaModes[i]) {
- createInfo.alphaMode = alphaModes[i];
- break;
- }
- }
- SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "vulkandisplay: Chose alpha mode 0x%x", createInfo.alphaMode);
- /* Found a match, finally! Fill in extent, and break from loop */
- createInfo.imageExtent = extent;
- break;
- }
- SDL_free(physicalDevices);
- physicalDevices = NULL;
- if (physicalDeviceIndex == physicalDeviceCount) {
- SDL_SetError("No usable displays found or requested display out of range");
- return SDL_FALSE;
- }
- createInfo.sType = VK_STRUCTURE_TYPE_DISPLAY_SURFACE_CREATE_INFO_KHR;
- createInfo.transform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
- createInfo.globalAlpha = 1.0f;
- result = vkCreateDisplayPlaneSurfaceKHR(instance, &createInfo, allocator, surface);
- if (result != VK_SUCCESS) {
- SDL_SetError("vkCreateDisplayPlaneSurfaceKHR failed: %s", SDL_Vulkan_GetResultString(result));
- return SDL_FALSE;
- }
- SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "vulkandisplay: Created surface");
- return SDL_TRUE;
- error:
- SDL_free(physicalDevices);
- return SDL_FALSE;
- }
- #endif
|