From e954631c533f37554eb5006d30630b56cec3b0f2 Mon Sep 17 00:00:00 2001 From: Daniel Rakos Date: Tue, 9 Jun 2026 12:44:41 +0200 Subject: [PATCH] vulkanscinfo: Add VK_KHR_display support and related fixes --- icd/generated-vksc/function_definitions.h | 27 +++- icd/generated/function_definitions.h | 27 +++- scripts/generators/mock_icd_generator.py | 33 ++++- vulkaninfo/CMakeLists.txt | 2 +- vulkaninfo/vulkaninfo.cpp | 64 ++++++++-- vulkaninfo/vulkaninfo.h | 142 +++++++++++++++++----- vulkaninfo/vulkaninfo_functions.h | 4 +- 7 files changed, 243 insertions(+), 56 deletions(-) diff --git a/icd/generated-vksc/function_definitions.h b/icd/generated-vksc/function_definitions.h index e3388cf1..159a2ddd 100644 --- a/icd/generated-vksc/function_definitions.h +++ b/icd/generated-vksc/function_definitions.h @@ -1579,7 +1579,9 @@ static VKAPI_ATTR VkResult VKAPI_CALL GetPhysicalDeviceDisplayPropertiesKHR(VkPh *pPropertyCount = 1; } else { unique_lock_t lock(global_lock); + *pPropertyCount = 1; pProperties[0].display = (VkDisplayKHR)global_unique_handle++; + pProperties[0].displayName = "Vulkan Mock Display"; display_map[physicalDevice].insert(pProperties[0].display); } return VK_SUCCESS; @@ -1587,18 +1589,28 @@ static VKAPI_ATTR VkResult VKAPI_CALL GetPhysicalDeviceDisplayPropertiesKHR(VkPh static VKAPI_ATTR VkResult VKAPI_CALL GetPhysicalDeviceDisplayPlanePropertiesKHR(VkPhysicalDevice physicalDevice, uint32_t* pPropertyCount, VkDisplayPlanePropertiesKHR* pProperties) { - // Not a CREATE or DESTROY function + *pPropertyCount = 1; + if (pProperties) { + pProperties[0].currentDisplay = VK_NULL_HANDLE; + pProperties[0].currentStackIndex = 0; + } return VK_SUCCESS; } static VKAPI_ATTR VkResult VKAPI_CALL GetDisplayPlaneSupportedDisplaysKHR(VkPhysicalDevice physicalDevice, uint32_t planeIndex, uint32_t* pDisplayCount, VkDisplayKHR* pDisplays) { - // Not a CREATE or DESTROY function + *pDisplayCount = 1; + if (pDisplays) { + pDisplays[0] = {}; + } return VK_SUCCESS; } static VKAPI_ATTR VkResult VKAPI_CALL GetDisplayModePropertiesKHR(VkPhysicalDevice physicalDevice, VkDisplayKHR display, uint32_t* pPropertyCount, VkDisplayModePropertiesKHR* pProperties) { - // Not a CREATE or DESTROY function + *pPropertyCount = 1; + if (pProperties) { + pProperties[0] = {}; + } return VK_SUCCESS; } static VKAPI_ATTR VkResult VKAPI_CALL CreateDisplayModeKHR(VkPhysicalDevice physicalDevice, VkDisplayKHR display, @@ -1728,12 +1740,17 @@ static VKAPI_ATTR VkResult VKAPI_CALL GetPhysicalDeviceSurfaceFormats2KHR(VkPhys pSurfaceFormats[1].surfaceFormat.colorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR; } if (*pSurfaceFormatCount >= 1) { - pSurfaceFormats[1].pNext = nullptr; + pSurfaceFormats[0].pNext = nullptr; pSurfaceFormats[0].surfaceFormat.format = VK_FORMAT_B8G8R8A8_UNORM; pSurfaceFormats[0].surfaceFormat.colorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR; } } - return VK_SUCCESS; + if (*pSurfaceFormatCount >= 2) { + *pSurfaceFormatCount = 2; + return VK_SUCCESS; + } else { + return VK_INCOMPLETE; + } } static VKAPI_ATTR VkResult VKAPI_CALL GetPhysicalDeviceDisplayProperties2KHR(VkPhysicalDevice physicalDevice, uint32_t* pPropertyCount, diff --git a/icd/generated/function_definitions.h b/icd/generated/function_definitions.h index c080684e..f0e8693f 100644 --- a/icd/generated/function_definitions.h +++ b/icd/generated/function_definitions.h @@ -1549,7 +1549,9 @@ static VKAPI_ATTR VkResult VKAPI_CALL GetPhysicalDeviceDisplayPropertiesKHR(VkPh *pPropertyCount = 1; } else { unique_lock_t lock(global_lock); + *pPropertyCount = 1; pProperties[0].display = (VkDisplayKHR)global_unique_handle++; + pProperties[0].displayName = "Vulkan Mock Display"; display_map[physicalDevice].insert(pProperties[0].display); } return VK_SUCCESS; @@ -1557,18 +1559,28 @@ static VKAPI_ATTR VkResult VKAPI_CALL GetPhysicalDeviceDisplayPropertiesKHR(VkPh static VKAPI_ATTR VkResult VKAPI_CALL GetPhysicalDeviceDisplayPlanePropertiesKHR(VkPhysicalDevice physicalDevice, uint32_t* pPropertyCount, VkDisplayPlanePropertiesKHR* pProperties) { - // Not a CREATE or DESTROY function + *pPropertyCount = 1; + if (pProperties) { + pProperties[0].currentDisplay = VK_NULL_HANDLE; + pProperties[0].currentStackIndex = 0; + } return VK_SUCCESS; } static VKAPI_ATTR VkResult VKAPI_CALL GetDisplayPlaneSupportedDisplaysKHR(VkPhysicalDevice physicalDevice, uint32_t planeIndex, uint32_t* pDisplayCount, VkDisplayKHR* pDisplays) { - // Not a CREATE or DESTROY function + *pDisplayCount = 1; + if (pDisplays) { + pDisplays[0] = {}; + } return VK_SUCCESS; } static VKAPI_ATTR VkResult VKAPI_CALL GetDisplayModePropertiesKHR(VkPhysicalDevice physicalDevice, VkDisplayKHR display, uint32_t* pPropertyCount, VkDisplayModePropertiesKHR* pProperties) { - // Not a CREATE or DESTROY function + *pPropertyCount = 1; + if (pProperties) { + pProperties[0] = {}; + } return VK_SUCCESS; } static VKAPI_ATTR VkResult VKAPI_CALL CreateDisplayModeKHR(VkPhysicalDevice physicalDevice, VkDisplayKHR display, @@ -2282,12 +2294,17 @@ static VKAPI_ATTR VkResult VKAPI_CALL GetPhysicalDeviceSurfaceFormats2KHR(VkPhys pSurfaceFormats[1].surfaceFormat.colorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR; } if (*pSurfaceFormatCount >= 1) { - pSurfaceFormats[1].pNext = nullptr; + pSurfaceFormats[0].pNext = nullptr; pSurfaceFormats[0].surfaceFormat.format = VK_FORMAT_B8G8R8A8_UNORM; pSurfaceFormats[0].surfaceFormat.colorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR; } } - return VK_SUCCESS; + if (*pSurfaceFormatCount >= 2) { + *pSurfaceFormatCount = 2; + return VK_SUCCESS; + } else { + return VK_INCOMPLETE; + } } static VKAPI_ATTR VkResult VKAPI_CALL GetPhysicalDeviceDisplayProperties2KHR(VkPhysicalDevice physicalDevice, uint32_t* pPropertyCount, diff --git a/scripts/generators/mock_icd_generator.py b/scripts/generators/mock_icd_generator.py index bcf2be06..9f14a8df 100644 --- a/scripts/generators/mock_icd_generator.py +++ b/scripts/generators/mock_icd_generator.py @@ -253,12 +253,17 @@ pSurfaceFormats[1].surfaceFormat.colorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR; } if (*pSurfaceFormatCount >= 1) { - pSurfaceFormats[1].pNext = nullptr; + pSurfaceFormats[0].pNext = nullptr; pSurfaceFormats[0].surfaceFormat.format = VK_FORMAT_B8G8R8A8_UNORM; pSurfaceFormats[0].surfaceFormat.colorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR; } } - return VK_SUCCESS; + if (*pSurfaceFormatCount >= 2) { + *pSurfaceFormatCount = 2; + return VK_SUCCESS; + } else { + return VK_INCOMPLETE; + } ''', 'vkGetPhysicalDeviceSurfaceSupportKHR': ''' // Currently say that all surface/queue combos are supported @@ -1162,11 +1167,35 @@ *pPropertyCount = 1; } else { unique_lock_t lock(global_lock); + *pPropertyCount = 1; pProperties[0].display = (VkDisplayKHR)global_unique_handle++; + pProperties[0].displayName = "Vulkan Mock Display"; display_map[physicalDevice].insert(pProperties[0].display); } return VK_SUCCESS; ''', +'vkGetPhysicalDeviceDisplayPlanePropertiesKHR': ''' + *pPropertyCount = 1; + if (pProperties) { + pProperties[0].currentDisplay = VK_NULL_HANDLE; + pProperties[0].currentStackIndex = 0; + } + return VK_SUCCESS; +''', +'vkGetDisplayPlaneSupportedDisplaysKHR': ''' + *pDisplayCount = 1; + if (pDisplays) { + pDisplays[0] = {}; + } + return VK_SUCCESS; +''', +'vkGetDisplayModePropertiesKHR': ''' + *pPropertyCount = 1; + if (pProperties) { + pProperties[0] = {}; + } + return VK_SUCCESS; +''', 'vkRegisterDisplayEventEXT': ''' unique_lock_t lock(global_lock); *pFence = (VkFence)global_unique_handle++; diff --git a/vulkaninfo/CMakeLists.txt b/vulkaninfo/CMakeLists.txt index 6696a2b4..c4cc82bf 100644 --- a/vulkaninfo/CMakeLists.txt +++ b/vulkaninfo/CMakeLists.txt @@ -66,6 +66,7 @@ target_include_directories(vulkaninfo PRIVATE ) target_compile_definitions(vulkaninfo PRIVATE VK_ENABLE_BETA_EXTENSIONS VK_NO_PROTOTYPES) +target_compile_definitions(vulkaninfo PRIVATE VK_USE_PLATFORM_DISPLAY_KHR) if (CMAKE_SYSTEM_NAME MATCHES "Linux|BSD|GNU|QNX") if(VULKANSC) @@ -109,7 +110,6 @@ if (CMAKE_SYSTEM_NAME MATCHES "Linux|BSD|GNU|QNX") if(BUILD_WSI_SCI_SUPPORT) target_compile_definitions(vulkaninfo INTERFACE VK_USE_PLATFORM_SCI) endif() - target_compile_definitions(vulkaninfo PRIVATE VK_USE_PLATFORM_DISPLAY) endif() if(APPLE) diff --git a/vulkaninfo/vulkaninfo.cpp b/vulkaninfo/vulkaninfo.cpp index 34d73879..2d3ff6c6 100644 --- a/vulkaninfo/vulkaninfo.cpp +++ b/vulkaninfo/vulkaninfo.cpp @@ -807,7 +807,7 @@ AppDisplayMode::AppDisplayMode(AppGpu &gpu, const VkDisplayModePropertiesKHR &in static std::string MakeName(uint32_t index, const VkDisplayPropertiesKHR &prop) { std::stringstream name; - name << "Display id : " << index << " (" << prop.displayName << ")"; + name << "Display id : " << index << " (" << (prop.displayName ? prop.displayName : "") << ")"; return name.str(); } @@ -1550,8 +1550,26 @@ int main(int argc, char **argv) { #if defined(VULKANINFO_WSI_ENABLED) for (auto &surface_extension : instance.surface_extensions) { - surface_extension.create_window(instance); - surface_extension.surface = surface_extension.create_surface(instance); + // If the surface extension has a create_window function then call it to create the single shared window + if (surface_extension.create_window) { + try { + surface_extension.create_window(instance); + } catch (std::exception &e) { + std::cerr << "ERROR while creating window for surface extension " << surface_extension.name << " : " << e.what() + << "\n"; + continue; + } + } + + // If the surface extension has a create_surface function then call it to create the single shared surface + if (surface_extension.create_surface) { + try { + surface_extension.surface = surface_extension.create_surface(instance); + } catch (std::exception &e) { + std::cerr << "ERROR while creating surface for extension " << surface_extension.name << " : " << e.what() + << "\n"; + } + } } #endif // defined(VULKANINFO_WSI_ENABLED) @@ -1559,14 +1577,31 @@ int main(int argc, char **argv) { uint32_t gpu_counter = 0; for (auto &phys_device : phys_devices) { - gpus.push_back( - std::unique_ptr(new AppGpu(instance, gpu_counter++, phys_device, parse_data.show.promoted_structs))); + // Take a copy of the surface extensions list as some may be per physical device (e.g. VK_KHR_display) + auto surface_extensions = instance.surface_extensions; +#if defined(VULKANINFO_WSI_ENABLED) + for (auto &surface_extension : surface_extensions) { + // If the surface extension has a create_surface_for_physical_device function then call it to create + // the physical device specific surface + if (surface_extension.create_surface_for_physical_device) { + try { + surface_extension.surface = surface_extension.create_surface_for_physical_device(instance, phys_device); + } catch (std::exception &e) { + std::cerr << "ERROR while creating surface for extension " << surface_extension.name << " : " << e.what() + << "\n"; + } + } + } +#endif // defined(VULKANINFO_WSI_ENABLED) + gpus.push_back(std::unique_ptr( + new AppGpu(instance, gpu_counter++, phys_device, parse_data.show.promoted_structs, std::move(surface_extensions)))); } std::vector> surfaces; #if defined(VULKANINFO_WSI_ENABLED) - for (auto &surface_extension : instance.surface_extensions) { - for (auto &gpu : gpus) { + for (auto &gpu : gpus) { + for (auto &surface_extension : gpu->surface_extensions) { + if (surface_extension.surface == VK_NULL_HANDLE) continue; try { // check if the surface is supported by the physical device before adding it to the list VkBool32 supported = VK_FALSE; @@ -1613,10 +1648,21 @@ int main(int argc, char **argv) { // Call the printer's destructor before the file handle gets closed printer.reset(nullptr); + + // Clean up the AppSurface objects to destroy the underlying VkSurfaceKHR objects + surfaces.clear(); + #if defined(VULKANINFO_WSI_ENABLED) for (auto &surface_extension : instance.surface_extensions) { - AppDestroySurface(instance, surface_extension.surface); - surface_extension.destroy_window(instance); + // If the surface is shared across physical devices then we have to destroy it here as there's a single shared + // surface for the AppInstance object (contrarily to per physical device surfaces that are maintained by AppSurface) + if (surface_extension.create_surface) { + vkDestroySurfaceKHR(instance.instance, surface_extension.surface, nullptr); + } + // If the surface extension has a destroy_window function then call it to destroy the single shared window + if (surface_extension.destroy_window) { + surface_extension.destroy_window(instance); + } } #endif // defined(VULKANINFO_WSI_ENABLED) } catch (std::exception &e) { diff --git a/vulkaninfo/vulkaninfo.h b/vulkaninfo/vulkaninfo.h index a7e3e1d6..ec55f81c 100644 --- a/vulkaninfo/vulkaninfo.h +++ b/vulkaninfo/vulkaninfo.h @@ -342,6 +342,7 @@ struct SurfaceExtension { std::string name; void (*create_window)(AppInstance &) = nullptr; VkSurfaceKHR (*create_surface)(AppInstance &) = nullptr; + VkSurfaceKHR (*create_surface_for_physical_device)(AppInstance &, VkPhysicalDevice) = nullptr; void (*destroy_window)(AppInstance &) = nullptr; VkSurfaceKHR surface = VK_NULL_HANDLE; @@ -549,8 +550,6 @@ struct AppInstance { int width = 256, height = 256; - VkSurfaceCapabilitiesKHR surface_capabilities; - #ifdef VK_USE_PLATFORM_WIN32_KHR HINSTANCE h_instance; // Windows Instance HWND h_wnd; // window handle @@ -776,7 +775,7 @@ struct AppInstance { inst_extensions.push_back(ext.extensionName); } #endif -#ifdef VK_USE_PLATFORM_DISPLAY +#ifdef VK_USE_PLATFORM_DISPLAY_KHR if (strcmp(VK_KHR_DISPLAY_EXTENSION_NAME, ext.extensionName) == 0) { inst_extensions.push_back(ext.extensionName); } @@ -818,19 +817,11 @@ struct AppInstance { #if defined(VK_USE_PLATFORM_XCB_KHR) || defined(VK_USE_PLATFORM_XLIB_KHR) || defined(VK_USE_PLATFORM_WIN32_KHR) || \ defined(VK_USE_PLATFORM_MACOS_MVK) || defined(VK_USE_PLATFORM_METAL_EXT) || defined(VK_USE_PLATFORM_WAYLAND_KHR) || \ defined(VK_USE_PLATFORM_DIRECTFB_EXT) || defined(VK_USE_PLATFORM_GGP) || defined(VK_USE_PLATFORM_SCREEN_QNX) || \ - defined(VK_USE_PLATFORM_DISPLAY) + defined(VK_USE_PLATFORM_DISPLAY_KHR) #define VULKANINFO_WSI_ENABLED #endif -//----------------------------------------------------------- -#if defined(VULKANINFO_WSI_ENABLED) -static void AppDestroySurface(AppInstance &inst, VkSurfaceKHR surface) { // same for all platforms - vkDestroySurfaceKHR(inst.instance, surface, nullptr); -} -#endif // defined(VULKANINFO_WSI_ENABLED) -//----------------------------------------------------------- - //---------------------------Win32--------------------------- #ifdef VK_USE_PLATFORM_WIN32_KHR @@ -976,7 +967,7 @@ static void AppCreateXlibWindow(AppInstance &inst) { inst.xlib_display = XOpenDisplay(nullptr); if (inst.xlib_display == nullptr) { - THROW_ERR("XLib failed to connect to the X server.\nExiting..."); + THROW_ERR("XLib failed to connect to the X server."); } XVisualInfo vInfoTemplate = {}; @@ -1020,7 +1011,7 @@ static void AppDestroyXlibWindow(AppInstance &inst) { static void AppCreateMacOSWindow(AppInstance &inst) { inst.macos_window = CreateMetalView(inst.width, inst.height); if (inst.macos_window == nullptr) { - THROW_ERR("Could not create a native Metal view.\nExiting..."); + THROW_ERR("Could not create a native Metal view."); } } @@ -1046,7 +1037,7 @@ static void AppDestroyMacOSWindow(AppInstance &inst) { DestroyMetalView(inst.mac static void AppCreateMetalWindow(AppInstance &inst) { inst.metal_window = CreateMetalView(inst.width, inst.height); if (inst.metal_window == nullptr) { - THROW_ERR("Could not create a native Metal view.\nExiting..."); + THROW_ERR("Could not create a native Metal view."); } } @@ -1113,12 +1104,12 @@ static void AppCreateDirectFBWindow(AppInstance &inst) { ret = DirectFBInit(NULL, NULL); if (ret) { - THROW_ERR("DirectFBInit failed to initialize DirectFB.\nExiting..."); + THROW_ERR("DirectFBInit failed to initialize DirectFB."); } ret = DirectFBCreate(&inst.dfb); if (ret) { - THROW_ERR("DirectFBCreate failed to create main interface of DirectFB.\nExiting..."); + THROW_ERR("DirectFBCreate failed to create main interface of DirectFB."); } DFBSurfaceDescription desc; @@ -1128,7 +1119,7 @@ static void AppCreateDirectFBWindow(AppInstance &inst) { desc.height = inst.height; ret = inst.dfb->CreateSurface(inst.dfb, &desc, &inst.directfb_surface); if (ret) { - THROW_ERR("CreateSurface failed to create DirectFB surface interface.\nExiting..."); + THROW_ERR("CreateSurface failed to create DirectFB surface interface."); } } @@ -1197,15 +1188,15 @@ static void AppCreateScreenWindow(AppInstance &inst) { rc = screen_create_context(&inst.context, 0); if (rc) { - THROW_ERR("Could not create a QNX Screen context.\nExiting..."); + THROW_ERR("Could not create a QNX Screen context."); } rc = screen_create_window(&inst.window, inst.context); if (rc) { - THROW_ERR("Could not create a QNX Screen window.\nExiting..."); + THROW_ERR("Could not create a QNX Screen window."); } rc = screen_set_window_property_iv(inst.window, SCREEN_PROPERTY_USAGE, &usage); if (rc) { - THROW_ERR("Could not set SCREEN_USAGE_VULKAN flag for QNX Screen window!\nExiting..."); + THROW_ERR("Could not set SCREEN_USAGE_VULKAN flag for QNX Screen window!"); } } @@ -1228,6 +1219,64 @@ static void AppDestroyScreenWindow(AppInstance &inst) { screen_destroy_context(inst.context); } #endif // VK_USE_PLATFORM_SCREEN_QNX + +//----------------------------------------------------------- +//----------------------KHR DISPLAY-------------------------- +#ifdef VK_USE_PLATFORM_DISPLAY_KHR +static VkSurfaceKHR AppCreateDisplaySurface(AppInstance &inst, VkPhysicalDevice phys_device) { + auto all_display_props = GetVector("vkGetPhysicalDeviceDisplayPropertiesKHR", + vkGetPhysicalDeviceDisplayPropertiesKHR, phys_device); + if (all_display_props.size() == 0) return VK_NULL_HANDLE; + + auto all_plane_props = GetVector("vkGetPhysicalDeviceDisplayPlanePropertiesKHR", + vkGetPhysicalDeviceDisplayPlanePropertiesKHR, phys_device); + if (all_plane_props.size() == 0) THROW_VK_ERR("No display plane properties for physical device.", VK_ERROR_UNKNOWN); + + // Always use the first plane + const uint32_t plane_index = 0; + const auto &plane_props = all_plane_props[plane_index]; + + auto supported_displays = GetVector("vkGetDisplayPlaneSupportedDisplaysKHR", + vkGetDisplayPlaneSupportedDisplaysKHR, phys_device, plane_index); + if (supported_displays.size() == 0) THROW_VK_ERR("No display supported by the display plane.", VK_ERROR_UNKNOWN); + + const VkDisplayKHR display = plane_props.currentDisplay != VK_NULL_HANDLE ? plane_props.currentDisplay : supported_displays[0]; + + auto all_mode_props = + GetVector("vkGetDisplayModePropertiesKHR", vkGetDisplayModePropertiesKHR, phys_device, display); + if (all_mode_props.size() == 0) THROW_VK_ERR("No display modes reported for display.", VK_ERROR_UNKNOWN); + + const auto &mode_props = all_mode_props[0]; + const VkDisplayModeKHR mode = mode_props.displayMode; + + VkDisplayPlaneCapabilitiesKHR plane_caps{}; + VkResult result = vkGetDisplayPlaneCapabilitiesKHR(phys_device, mode, plane_index, &plane_caps); + if (result != VK_SUCCESS) THROW_VK_ERR("vkGetDisplayPlaneCapabilitiesKHR", result); + + VkDisplaySurfaceCreateInfoKHR createInfo; + createInfo.sType = VK_STRUCTURE_TYPE_DISPLAY_SURFACE_CREATE_INFO_KHR; + createInfo.pNext = NULL; + createInfo.flags = 0; + createInfo.displayMode = mode; + createInfo.planeIndex = plane_index; + createInfo.planeStackIndex = plane_props.currentStackIndex; + createInfo.transform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; + createInfo.globalAlpha = 1.0f; + for (uint32_t i = 0; i < 32; ++i) { + if ((plane_caps.supportedAlpha & (1 << i)) != 0) { + createInfo.alphaMode = static_cast(1 << i); + break; + } + } + createInfo.imageExtent = mode_props.parameters.visibleRegion; + + VkSurfaceKHR surface; + VkResult err = vkCreateDisplayPlaneSurfaceKHR(inst.instance, &createInfo, NULL, &surface); + if (err) THROW_VK_ERR("vkCreateDisplayPlaneSurfaceKHR", err); + return surface; +} +#endif // VK_USE_PLATFORM_DISPLAY_KHR + //----------------------------------------------------------- // ------------ Setup Windows ------------- // @@ -1373,7 +1422,16 @@ void SetupWindowExtensions(AppInstance &inst) { inst.AddSurfaceExtension(surface_ext_qnx_screen); } #endif -// TODO: add support for VK_KHR_display surfaces +//--DISPLAY-- +#ifdef VK_USE_PLATFORM_DISPLAY_KHR + SurfaceExtension surface_ext_khr_display; + if (inst.CheckExtensionEnabled(VK_KHR_DISPLAY_EXTENSION_NAME)) { + surface_ext_khr_display.name = VK_KHR_DISPLAY_EXTENSION_NAME; + surface_ext_khr_display.create_surface_for_physical_device = AppCreateDisplaySurface; + + inst.AddSurfaceExtension(surface_ext_khr_display); + } +#endif } // ---------- Surfaces -------------- // @@ -1426,13 +1484,13 @@ class AppSurface { VkPhysicalDeviceSurfaceInfo2KHR surface_info{}; surface_info.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SURFACE_INFO_2_KHR; surface_info.surface = surface_extension.surface; -#if defined(WIN32) +#ifdef VK_USE_PLATFORM_WIN32_KHR VkSurfaceFullScreenExclusiveWin32InfoEXT win32_fullscreen_exclusive_info{}; win32_fullscreen_exclusive_info.sType = VK_STRUCTURE_TYPE_SURFACE_FULL_SCREEN_EXCLUSIVE_WIN32_INFO_EXT; win32_fullscreen_exclusive_info.hmonitor = MonitorFromWindow(inst.h_wnd, MONITOR_DEFAULTTOPRIMARY); surface_info.pNext = static_cast(&win32_fullscreen_exclusive_info); -#endif // defined(WIN32) +#endif // VK_USE_PLATFORM_WIN32_KHR VkResult err = vkGetPhysicalDeviceSurfaceCapabilities2KHR(phys_device, &surface_info, &surface_capabilities2_khr); if (err) THROW_VK_ERR("vkGetPhysicalDeviceSurfaceCapabilities2KHR", err); } @@ -1611,10 +1669,13 @@ struct AppQueueFamilyProperties { bool can_present = false; bool can_always_present = true; std::vector> present_support; - AppQueueFamilyProperties(AppInstance &inst, VkPhysicalDevice physical_device, VkQueueFamilyProperties family_properties, + AppQueueFamilyProperties(AppInstance &inst, VkPhysicalDevice physical_device, + const std::vector &surface_extensions, VkQueueFamilyProperties family_properties, uint32_t queue_index, void *pNext = nullptr) : props(family_properties), queue_index(queue_index), pNext(pNext) { - for (const auto &surface_ext : inst.surface_extensions) { + for (const auto &surface_ext : surface_extensions) { + if (surface_ext.surface == VK_NULL_HANDLE) continue; + present_support.push_back({surface_ext.name, VK_FALSE}); VkResult err = vkGetPhysicalDeviceSurfaceSupportKHR(physical_device, queue_index, surface_ext.surface, &present_support.back().second); @@ -1666,6 +1727,10 @@ struct AppGpu { std::vector device_extensions; + // There are certain surface extensions that are physical device specific such as VK_KHR_display + // The per physical device surfaces for these are maintained here instead at the AppInstance level + std::vector surface_extensions; + VkDevice dev = VK_NULL_HANDLE; VkPhysicalDeviceFeatures enabled_features{}; @@ -1683,8 +1748,9 @@ struct AppGpu { std::vector displays; std::vector display_planes; - AppGpu(AppInstance &inst, uint32_t id, VkPhysicalDevice phys_device, bool show_promoted_structs) - : inst(inst), id(id), phys_device(phys_device) { + AppGpu(AppInstance &inst, uint32_t id, VkPhysicalDevice phys_device, bool show_promoted_structs, + std::vector &&surface_extensions) + : inst(inst), id(id), phys_device(phys_device), surface_extensions(surface_extensions) { vkGetPhysicalDeviceProperties(phys_device, &props); // needs to find the minimum of the instance and device version, and use that to print the device info @@ -1785,12 +1851,13 @@ struct AppGpu { int queue_index = 0; if (queue_props2.size() > 0) { for (auto &queue_prop : queue_props2) { - extended_queue_props.push_back( - AppQueueFamilyProperties(inst, phys_device, queue_prop.queueFamilyProperties, queue_index++, queue_prop.pNext)); + extended_queue_props.push_back(AppQueueFamilyProperties( + inst, phys_device, surface_extensions, queue_prop.queueFamilyProperties, queue_index++, queue_prop.pNext)); } } else { for (auto &queue_prop : queue_props) { - extended_queue_props.push_back(AppQueueFamilyProperties(inst, phys_device, queue_prop, queue_index++, nullptr)); + extended_queue_props.push_back( + AppQueueFamilyProperties(inst, phys_device, surface_extensions, queue_prop, queue_index++, nullptr)); } } @@ -1935,7 +2002,18 @@ struct AppGpu { vkDestroyDevice(dev, nullptr); dev = VK_NULL_HANDLE; } - ~AppGpu() { vkDestroyDevice(dev, nullptr); } + + ~AppGpu() { + for (auto &surface_extension : surface_extensions) { + // If the surface is per physical device then we have to destroy it here as there's a separate surface for the + // AppGpu object (contrarily to surfaces shared across the instance that are maintained by AppInstance) + if (surface_extension.create_surface_for_physical_device) { + vkDestroySurfaceKHR(inst.instance, surface_extension.surface, nullptr); + } + } + + vkDestroyDevice(dev, nullptr); + } AppGpu(const AppGpu &) = delete; const AppGpu &operator=(const AppGpu &) = delete; diff --git a/vulkaninfo/vulkaninfo_functions.h b/vulkaninfo/vulkaninfo_functions.h index 8b4c1ce8..70ed5c31 100644 --- a/vulkaninfo/vulkaninfo_functions.h +++ b/vulkaninfo/vulkaninfo_functions.h @@ -71,7 +71,7 @@ PFN_vkCreateMacOSSurfaceMVK vkCreateMacOSSurfaceMVK; #if defined(VK_USE_PLATFORM_SCREEN_QNX) PFN_vkCreateScreenSurfaceQNX vkCreateScreenSurfaceQNX; #endif -#if defined(VK_USE_PLATFORM_DISPLAY) +#if defined(VK_USE_PLATFORM_DISPLAY_KHR) PFN_vkCreateDisplayPlaneSurfaceKHR vkCreateDisplayPlaneSurfaceKHR; #endif #if defined(VK_USE_PLATFORM_DIRECTFB_EXT) @@ -237,7 +237,7 @@ static void load_vulkan_instance_functions(VkInstance instance) { #if defined(VK_USE_PLATFORM_SCREEN_QNX) LOAD_INSTANCE_FUNCTION(instance, vkCreateScreenSurfaceQNX); #endif -#if defined(VK_USE_PLATFORM_DISPLAY) +#if defined(VK_USE_PLATFORM_DISPLAY_KHR) LOAD_INSTANCE_FUNCTION(instance, vkCreateDisplayPlaneSurfaceKHR); #endif #if defined(VK_USE_PLATFORM_DIRECTFB_EXT)