Skip to content

Commit

Permalink
Support VK_GOOGLE_surfaceless_query
Browse files Browse the repository at this point in the history
Requires bypassing the logic which dereferences VkSurfaceKHR in
vkGetPhysicalDeviceSurfaceFormatsKHR and
vkGetPhysicalDeviceSurfacePresentModesKHR. This should have been done
closer to the release of VK_GOOGLE_surfaceless_query, but because that
extension was meant for Android, which isn't supported by this loader,
it was not done. That said, SwiftShader can support the extension, so
support is now being added in this commit.
  • Loading branch information
charles-lunarg committed Jan 15, 2025
1 parent f51ed4e commit 757324b
Show file tree
Hide file tree
Showing 8 changed files with 172 additions and 53 deletions.
44 changes: 24 additions & 20 deletions loader/extension_manual.c
Original file line number Diff line number Diff line change
Expand Up @@ -274,16 +274,18 @@ VKAPI_ATTR VkResult VKAPI_CALL terminator_GetPhysicalDeviceSurfacePresentModes2E
"ICD associated with VkPhysicalDevice does not support GetPhysicalDeviceSurfacePresentModes2EXT");
abort();
}
VkIcdSurface *icd_surface = (VkIcdSurface *)(uintptr_t)(pSurfaceInfo->surface);
if (NULL != icd_term->surface_list.list &&
icd_term->surface_list.capacity > icd_surface->surface_index * sizeof(VkSurfaceKHR) &&
icd_term->surface_list.list[icd_surface->surface_index]) {
VkPhysicalDeviceSurfaceInfo2KHR surface_info_copy;
surface_info_copy.sType = pSurfaceInfo->sType;
surface_info_copy.pNext = pSurfaceInfo->pNext;
surface_info_copy.surface = icd_term->surface_list.list[icd_surface->surface_index];
return icd_term->dispatch.GetPhysicalDeviceSurfacePresentModes2EXT(phys_dev_term->phys_dev, &surface_info_copy,
pPresentModeCount, pPresentModes);
if (VK_NULL_HANDLE != pSurfaceInfo->surface) {
VkIcdSurface *icd_surface = (VkIcdSurface *)(uintptr_t)(pSurfaceInfo->surface);
if (NULL != icd_surface && NULL != icd_term->surface_list.list &&
icd_term->surface_list.capacity > icd_surface->surface_index * sizeof(VkSurfaceKHR) &&
icd_term->surface_list.list[icd_surface->surface_index]) {
VkPhysicalDeviceSurfaceInfo2KHR surface_info_copy;
surface_info_copy.sType = pSurfaceInfo->sType;
surface_info_copy.pNext = pSurfaceInfo->pNext;
surface_info_copy.surface = icd_term->surface_list.list[icd_surface->surface_index];
return icd_term->dispatch.GetPhysicalDeviceSurfacePresentModes2EXT(phys_dev_term->phys_dev, &surface_info_copy,
pPresentModeCount, pPresentModes);
}
}
return icd_term->dispatch.GetPhysicalDeviceSurfacePresentModes2EXT(phys_dev_term->phys_dev, pSurfaceInfo, pPresentModeCount,
pPresentModes);
Expand Down Expand Up @@ -321,16 +323,18 @@ VKAPI_ATTR VkResult VKAPI_CALL terminator_GetDeviceGroupSurfacePresentModes2EXT(
"[VUID-vkGetDeviceGroupSurfacePresentModes2EXT-pSurfaceInfo-parameter]");
abort(); /* Intentionally fail so user can correct issue. */
}
VkIcdSurface *icd_surface = (VkIcdSurface *)(uintptr_t)(pSurfaceInfo->surface);
if (NULL != icd_term->surface_list.list &&
icd_term->surface_list.capacity > icd_surface->surface_index * sizeof(VkSurfaceKHR) &&
icd_term->surface_list.list[icd_surface->surface_index]) {
VkPhysicalDeviceSurfaceInfo2KHR surface_info_copy;
surface_info_copy.sType = pSurfaceInfo->sType;
surface_info_copy.pNext = pSurfaceInfo->pNext;
surface_info_copy.surface = icd_term->surface_list.list[icd_surface->surface_index];
return dev->loader_dispatch.extension_terminator_dispatch.GetDeviceGroupSurfacePresentModes2EXT(device, &surface_info_copy,
pModes);
if (VK_NULL_HANDLE != pSurfaceInfo->surface) {
VkIcdSurface *icd_surface = (VkIcdSurface *)(uintptr_t)(pSurfaceInfo->surface);
if (NULL != icd_surface && NULL != icd_term->surface_list.list &&
icd_term->surface_list.capacity > icd_surface->surface_index * sizeof(VkSurfaceKHR) &&
icd_term->surface_list.list[icd_surface->surface_index]) {
VkPhysicalDeviceSurfaceInfo2KHR surface_info_copy;
surface_info_copy.sType = pSurfaceInfo->sType;
surface_info_copy.pNext = pSurfaceInfo->pNext;
surface_info_copy.surface = icd_term->surface_list.list[icd_surface->surface_index];
return dev->loader_dispatch.extension_terminator_dispatch.GetDeviceGroupSurfacePresentModes2EXT(
device, &surface_info_copy, pModes);
}
}
return dev->loader_dispatch.extension_terminator_dispatch.GetDeviceGroupSurfacePresentModes2EXT(device, pSurfaceInfo, pModes);
}
Expand Down
8 changes: 4 additions & 4 deletions loader/loader.rc
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//
// Copyright (c) 2014-2024 The Khronos Group Inc.
// Copyright (c) 2014-2024 Valve Corporation
// Copyright (c) 2014-2024 LunarG, Inc.
// Copyright (c) 2014-2025 The Khronos Group Inc.
// Copyright (c) 2014-2025 Valve Corporation
// Copyright (c) 2014-2025 LunarG, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand All @@ -25,7 +25,7 @@
#define VER_FILE_VERSION 1, 4, 304, 0
#define VER_FILE_DESCRIPTION_STR "1.4.304.Dev Build"
#define VER_FILE_VERSION_STR "Vulkan Loader - Dev Build"
#define VER_COPYRIGHT_STR "Copyright (C) 2015-2024"
#define VER_COPYRIGHT_STR "Copyright (C) 2015-2025"

VS_VERSION_INFO VERSIONINFO
FILEVERSION VER_FILE_VERSION
Expand Down
54 changes: 31 additions & 23 deletions loader/wsi.c
Original file line number Diff line number Diff line change
Expand Up @@ -366,15 +366,16 @@ VKAPI_ATTR VkResult VKAPI_CALL terminator_GetPhysicalDeviceSurfaceFormatsKHR(VkP
return VK_SUCCESS;
}

VkIcdSurface *icd_surface = (VkIcdSurface *)(uintptr_t)surface;
if (NULL != phys_dev_term->this_icd_term->surface_list.list &&
phys_dev_term->this_icd_term->surface_list.capacity > icd_surface->surface_index * sizeof(VkSurfaceKHR) &&
phys_dev_term->this_icd_term->surface_list.list[icd_surface->surface_index]) {
return icd_term->dispatch.GetPhysicalDeviceSurfaceFormatsKHR(
phys_dev_term->phys_dev, phys_dev_term->this_icd_term->surface_list.list[icd_surface->surface_index],
pSurfaceFormatCount, pSurfaceFormats);
if (VK_NULL_HANDLE != surface) {
VkIcdSurface *icd_surface = (VkIcdSurface *)(uintptr_t)surface;
if (NULL != phys_dev_term->this_icd_term->surface_list.list &&
phys_dev_term->this_icd_term->surface_list.capacity > icd_surface->surface_index * sizeof(VkSurfaceKHR) &&
phys_dev_term->this_icd_term->surface_list.list[icd_surface->surface_index]) {
return icd_term->dispatch.GetPhysicalDeviceSurfaceFormatsKHR(
phys_dev_term->phys_dev, phys_dev_term->this_icd_term->surface_list.list[icd_surface->surface_index],
pSurfaceFormatCount, pSurfaceFormats);
}
}

return icd_term->dispatch.GetPhysicalDeviceSurfaceFormatsKHR(phys_dev_term->phys_dev, surface, pSurfaceFormatCount,
pSurfaceFormats);
}
Expand Down Expand Up @@ -424,16 +425,17 @@ VKAPI_ATTR VkResult VKAPI_CALL terminator_GetPhysicalDeviceSurfacePresentModesKH
"ICD for selected physical device does not export vkGetPhysicalDeviceSurfacePresentModesKHR!");
return VK_SUCCESS;
}
if (VK_NULL_HANDLE != surface) {
VkIcdSurface *icd_surface = (VkIcdSurface *)(uintptr_t)surface;

VkIcdSurface *icd_surface = (VkIcdSurface *)(uintptr_t)surface;
if (NULL != phys_dev_term->this_icd_term->surface_list.list &&
phys_dev_term->this_icd_term->surface_list.capacity > icd_surface->surface_index * sizeof(VkSurfaceKHR) &&
phys_dev_term->this_icd_term->surface_list.list[icd_surface->surface_index]) {
return icd_term->dispatch.GetPhysicalDeviceSurfacePresentModesKHR(
phys_dev_term->phys_dev, phys_dev_term->this_icd_term->surface_list.list[icd_surface->surface_index], pPresentModeCount,
pPresentModes);
if (icd_surface != NULL && NULL != phys_dev_term->this_icd_term->surface_list.list &&
phys_dev_term->this_icd_term->surface_list.capacity > icd_surface->surface_index * sizeof(VkSurfaceKHR) &&
phys_dev_term->this_icd_term->surface_list.list[icd_surface->surface_index]) {
return icd_term->dispatch.GetPhysicalDeviceSurfacePresentModesKHR(
phys_dev_term->phys_dev, phys_dev_term->this_icd_term->surface_list.list[icd_surface->surface_index],
pPresentModeCount, pPresentModes);
}
}

return icd_term->dispatch.GetPhysicalDeviceSurfacePresentModesKHR(phys_dev_term->phys_dev, surface, pPresentModeCount,
pPresentModes);
}
Expand Down Expand Up @@ -2497,7 +2499,10 @@ VKAPI_ATTR VkResult VKAPI_CALL terminator_GetPhysicalDeviceSurfaceCapabilities2K
struct loader_physical_device_term *phys_dev_term = (struct loader_physical_device_term *)physicalDevice;
struct loader_icd_term *icd_term = phys_dev_term->this_icd_term;
struct loader_instance *loader_inst = (struct loader_instance *)icd_term->this_instance;
VkIcdSurface *icd_surface = (VkIcdSurface *)(uintptr_t)pSurfaceInfo->surface;
VkIcdSurface *icd_surface = NULL;
if (pSurfaceInfo->surface) {
icd_surface = (VkIcdSurface *)(uintptr_t)pSurfaceInfo->surface;
}

if (!loader_inst->wsi_surface_enabled) {
loader_log(loader_inst, VULKAN_LOADER_ERROR_BIT, 0,
Expand All @@ -2522,7 +2527,7 @@ VKAPI_ATTR VkResult VKAPI_CALL terminator_GetPhysicalDeviceSurfaceCapabilities2K
VkResult res = VK_SUCCESS;

// Pass the call to the driver, possibly unwrapping the ICD surface
if (NULL != icd_term->surface_list.list &&
if (NULL != icd_surface && NULL != icd_term->surface_list.list &&
icd_term->surface_list.capacity > icd_surface->surface_index * sizeof(VkSurfaceKHR) &&
icd_term->surface_list.list[icd_surface->surface_index]) {
VkPhysicalDeviceSurfaceInfo2KHR info_copy = *pSurfaceInfo;
Expand All @@ -2549,8 +2554,8 @@ VKAPI_ATTR VkResult VKAPI_CALL terminator_GetPhysicalDeviceSurfaceCapabilities2K
icd_term->scanned_icd->lib_name);

// Write to the VkSurfaceCapabilities2KHR struct
VkSurfaceKHR surface = pSurfaceInfo->surface;
if (NULL != icd_term->surface_list.list &&
VkSurfaceKHR surface = VK_NULL_HANDLE;
if (NULL != icd_surface && NULL != icd_term->surface_list.list &&
icd_term->surface_list.capacity > icd_surface->surface_index * sizeof(VkSurfaceKHR) &&
icd_term->surface_list.list[icd_surface->surface_index]) {
surface = icd_term->surface_list.list[icd_surface->surface_index];
Expand Down Expand Up @@ -2600,11 +2605,14 @@ VKAPI_ATTR VkResult VKAPI_CALL terminator_GetPhysicalDeviceSurfaceFormats2KHR(Vk
return VK_SUCCESS;
}

VkIcdSurface *icd_surface = (VkIcdSurface *)(uintptr_t)(pSurfaceInfo->surface);
VkIcdSurface *icd_surface = NULL;
if (VK_NULL_HANDLE != pSurfaceInfo->surface) {
icd_surface = (VkIcdSurface *)(uintptr_t)(pSurfaceInfo->surface);
}

if (icd_term->dispatch.GetPhysicalDeviceSurfaceFormats2KHR != NULL) {
// Pass the call to the driver, possibly unwrapping the ICD surface
if (NULL != icd_term->surface_list.list &&
if (NULL != icd_surface && NULL != icd_term->surface_list.list &&
icd_term->surface_list.capacity > icd_surface->surface_index * sizeof(VkSurfaceKHR) &&
icd_term->surface_list.list[icd_surface->surface_index]) {
VkPhysicalDeviceSurfaceInfo2KHR info_copy = *pSurfaceInfo;
Expand All @@ -2628,7 +2636,7 @@ VKAPI_ATTR VkResult VKAPI_CALL terminator_GetPhysicalDeviceSurfaceFormats2KHR(Vk
}

VkSurfaceKHR surface = pSurfaceInfo->surface;
if (NULL != icd_term->surface_list.list &&
if (NULL != icd_surface && NULL != icd_term->surface_list.list &&
icd_term->surface_list.capacity > icd_surface->surface_index * sizeof(VkSurfaceKHR) &&
icd_term->surface_list.list[icd_surface->surface_index]) {
surface = icd_term->surface_list.list[icd_surface->surface_index];
Expand Down
7 changes: 5 additions & 2 deletions scripts/loader_extension_generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -1277,8 +1277,11 @@ def CreateTrampTermFuncs(self):
funcs += ' }\n'

if has_surface == 1:
funcs += f' VkIcdSurface *icd_surface = (VkIcdSurface *)(uintptr_t)({surface_var_name});\n'
funcs += ' if (NULL != icd_term->surface_list.list && icd_term->surface_list.capacity > icd_surface->surface_index * sizeof(VkSurfaceKHR) && icd_term->surface_list[icd_surface->surface_index]) {\n'
funcs += ' VkIcdSurface *icd_surface = NULL;\n'
funcs += f' if (NULL != {surface_var_name}) {{\n'
funcs += f' icd_surface = (VkIcdSurface *)(uintptr_t)({surface_var_name});\n'
funcs += ' }\n'
funcs += ' if (NULL != icd_surface && NULL != icd_term->surface_list.list && icd_term->surface_list.capacity > icd_surface->surface_index * sizeof(VkSurfaceKHR) && icd_term->surface_list[icd_surface->surface_index]) {\n'

# If there's a structure with a surface, we need to update its internals with the correct surface for the ICD
if update_structure_surface == 1:
Expand Down
39 changes: 39 additions & 0 deletions tests/framework/icd/test_icd.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -838,6 +838,11 @@ VKAPI_ATTR VkResult VKAPI_CALL test_vkGetPhysicalDeviceSurfaceFormatsKHR(VkPhysi
assert(false && "Surface not found during GetPhysicalDeviceSurfaceFormatsKHR query!");
return VK_ERROR_UNKNOWN;
}
} else {
if (!IsInstanceExtensionEnabled(VK_GOOGLE_SURFACELESS_QUERY_EXTENSION_NAME)) {
assert(false && "Surface is NULL but VK_GOOGLE_surfaceless_query was not enabled!");
return VK_ERROR_UNKNOWN;
}
}
FillCountPtr(icd.GetPhysDevice(physicalDevice).surface_formats, pSurfaceFormatCount, pSurfaceFormats);
return VK_SUCCESS;
Expand All @@ -852,11 +857,39 @@ VKAPI_ATTR VkResult VKAPI_CALL test_vkGetPhysicalDeviceSurfacePresentModesKHR(Vk
assert(false && "Surface not found during GetPhysicalDeviceSurfacePresentModesKHR query!");
return VK_ERROR_UNKNOWN;
}
} else {
if (!IsInstanceExtensionEnabled(VK_GOOGLE_SURFACELESS_QUERY_EXTENSION_NAME)) {
assert(false && "Surface is NULL but VK_GOOGLE_surfaceless_query was not enabled!");
return VK_ERROR_UNKNOWN;
}
}
FillCountPtr(icd.GetPhysDevice(physicalDevice).surface_present_modes, pPresentModeCount, pPresentModes);
return VK_SUCCESS;
}

#if defined(WIN32)
VKAPI_ATTR VkResult VKAPI_CALL test_vkGetPhysicalDeviceSurfacePresentModes2EXT(VkPhysicalDevice physicalDevice,
const VkPhysicalDeviceSurfaceInfo2KHR* pSurfaceInfo,
uint32_t* pPresentModeCount,
VkPresentModeKHR* pPresentModes) {
if (pSurfaceInfo->surface != VK_NULL_HANDLE) {
uint64_t fake_surf_handle = (uint64_t)(pSurfaceInfo->surface);
auto found_iter = std::find(icd.surface_handles.begin(), icd.surface_handles.end(), fake_surf_handle);
if (found_iter == icd.surface_handles.end()) {
assert(false && "Surface not found during GetPhysicalDeviceSurfacePresentModesKHR query!");
return VK_ERROR_UNKNOWN;
}
} else {
if (!IsInstanceExtensionEnabled(VK_GOOGLE_SURFACELESS_QUERY_EXTENSION_NAME)) {
assert(false && "Surface is NULL but VK_GOOGLE_surfaceless_query was not enabled!");
return VK_ERROR_UNKNOWN;
}
}
FillCountPtr(icd.GetPhysDevice(physicalDevice).surface_present_modes, pPresentModeCount, pPresentModes);
return VK_SUCCESS;
}
#endif

// VK_KHR_display
VKAPI_ATTR VkResult VKAPI_CALL test_vkGetPhysicalDeviceDisplayPropertiesKHR(VkPhysicalDevice physicalDevice,
uint32_t* pPropertyCount,
Expand Down Expand Up @@ -1310,6 +1343,12 @@ PFN_vkVoidFunction get_physical_device_func_wsi([[maybe_unused]] VkInstance inst
if (string_eq(pName, "vkGetPhysicalDeviceSurfacePresentModesKHR"))
return to_vkVoidFunction(test_vkGetPhysicalDeviceSurfacePresentModesKHR);
}
#if defined(WIN32)
if (IsInstanceExtensionEnabled("VK_EXT_full_screen_exclusive")) {
if (string_eq(pName, "vkGetPhysicalDeviceSurfacePresentModes2EXT"))
return to_vkVoidFunction(test_vkGetPhysicalDeviceSurfacePresentModes2EXT);
}
#endif
if (IsInstanceExtensionEnabled("VK_KHR_get_surface_capabilities2")) {
if (string_eq(pName, "vkGetPhysicalDeviceSurfaceCapabilities2KHR"))
return to_vkVoidFunction(test_vkGetPhysicalDeviceSurfaceCapabilities2KHR);
Expand Down
8 changes: 5 additions & 3 deletions tests/framework/test_environment.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,9 @@ void init_vulkan_functions(VulkanFunctions& funcs) {
funcs.vkCreateWin32SurfaceKHR = GPA(vkCreateWin32SurfaceKHR);
funcs.vkGetPhysicalDeviceWin32PresentationSupportKHR = GPA(vkGetPhysicalDeviceWin32PresentationSupportKHR);
#endif // VK_USE_PLATFORM_WIN32_KHR

#if defined(WIN32)
funcs.vkGetPhysicalDeviceSurfacePresentModes2EXT = GPA(vkGetPhysicalDeviceSurfacePresentModes2EXT);
#endif
funcs.vkDestroyDevice = GPA(vkDestroyDevice);
funcs.vkGetDeviceQueue = GPA(vkGetDeviceQueue);
#undef GPA
Expand Down Expand Up @@ -278,9 +280,9 @@ std::vector<VkExtensionProperties> InstWrapper::EnumerateLayerDeviceExtensions(V
}

DeviceWrapper::DeviceWrapper(InstWrapper& inst_wrapper, VkAllocationCallbacks* callbacks) noexcept
: functions(inst_wrapper.functions), callbacks(callbacks){};
: functions(inst_wrapper.functions), callbacks(callbacks) {};
DeviceWrapper::DeviceWrapper(VulkanFunctions& functions, VkDevice device, VkAllocationCallbacks* callbacks) noexcept
: functions(&functions), dev(device), callbacks(callbacks){};
: functions(&functions), dev(device), callbacks(callbacks) {};
DeviceWrapper::~DeviceWrapper() noexcept { functions->vkDestroyDevice(dev, callbacks); }

DeviceWrapper::DeviceWrapper(DeviceWrapper&& other) noexcept {
Expand Down
5 changes: 4 additions & 1 deletion tests/framework/test_environment.h
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,9 @@ struct VulkanFunctions {
PFN_vkCreateWin32SurfaceKHR vkCreateWin32SurfaceKHR = nullptr;
PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR vkGetPhysicalDeviceWin32PresentationSupportKHR = nullptr;
#endif // VK_USE_PLATFORM_WIN32_KHR
#if defined(WIN32)
PFN_vkGetPhysicalDeviceSurfaceCapabilities2KHR vkGetPhysicalDeviceSurfaceCapabilities2KHR = nullptr;
#endif
PFN_vkDestroySurfaceKHR vkDestroySurfaceKHR = nullptr;

// instance extensions functions (can only be loaded with a valid instance)
Expand Down Expand Up @@ -445,7 +448,7 @@ struct DebugUtilsWrapper {
local_vkCreateDebugUtilsMessengerEXT(
FromVoidStarFunc(inst_wrapper.functions->vkGetInstanceProcAddr(inst_wrapper.inst, "vkCreateDebugUtilsMessengerEXT"))),
local_vkDestroyDebugUtilsMessengerEXT(FromVoidStarFunc(
inst_wrapper.functions->vkGetInstanceProcAddr(inst_wrapper.inst, "vkDestroyDebugUtilsMessengerEXT"))){};
inst_wrapper.functions->vkGetInstanceProcAddr(inst_wrapper.inst, "vkDestroyDebugUtilsMessengerEXT"))) {};
~DebugUtilsWrapper() noexcept {
if (messenger) {
local_vkDestroyDebugUtilsMessengerEXT(inst, messenger, callbacks);
Expand Down
Loading

0 comments on commit 757324b

Please sign in to comment.