From b1e492d1fc9ee1e6f35147e04e34364f0dc56304 Mon Sep 17 00:00:00 2001
From: Vanfanel <[EMAIL REDACTED]>
Date: Wed, 25 Aug 2021 19:31:47 +0200
Subject: [PATCH] Search for an appropiate plane instead of simply using the
first one.
---
src/video/kmsdrm/SDL_kmsdrmvulkan.c | 146 ++++++++++++++++++++--------
1 file changed, 106 insertions(+), 40 deletions(-)
diff --git a/src/video/kmsdrm/SDL_kmsdrmvulkan.c b/src/video/kmsdrm/SDL_kmsdrmvulkan.c
index 3b80ac566d..4e9d208c4b 100644
--- a/src/video/kmsdrm/SDL_kmsdrmvulkan.c
+++ b/src/video/kmsdrm/SDL_kmsdrmvulkan.c
@@ -187,29 +187,35 @@ SDL_bool KMSDRM_Vulkan_CreateSurface(_THIS,
uint32_t display_count;
uint32_t mode_count;
uint32_t plane_count;
+ uint32_t plane = UINT32_MAX;
VkPhysicalDevice *physical_devices = NULL;
VkPhysicalDeviceProperties *device_props = NULL;
- VkDisplayPropertiesKHR *displays_props = NULL;
- VkDisplayModePropertiesKHR *modes_props = NULL;
- VkDisplayPlanePropertiesKHR *planes_props = NULL;
+ VkDisplayPropertiesKHR *display_props = NULL;
+ VkDisplayModePropertiesKHR *mode_props = NULL;
+ VkDisplayPlanePropertiesKHR *plane_props = NULL;
+ VkDisplayPlaneCapabilitiesKHR plane_caps;
VkDisplayModeCreateInfoKHR display_mode_create_info;
VkDisplaySurfaceCreateInfoKHR display_plane_surface_create_info;
VkExtent2D image_size;
+ VkDisplayKHR display;
VkDisplayModeKHR display_mode = (VkDisplayModeKHR)0;
VkDisplayModePropertiesKHR display_mode_props = {0};
VkDisplayModeParametersKHR new_mode_parameters = { {0, 0}, 0};
+ /* Prefer a plane that supports per-pixel alpha. */
+ VkDisplayPlaneAlphaFlagBitsKHR alpha_mode = VK_DISPLAY_PLANE_ALPHA_OPAQUE_BIT_KHR;
VkResult result;
SDL_bool ret = SDL_FALSE;
SDL_bool valid_gpu = SDL_FALSE;
SDL_bool mode_found = SDL_FALSE;
+ SDL_bool plane_supports_display = SDL_FALSE;
/* Get the display index from the display being used by the window. */
int display_index = SDL_atoi(SDL_GetDisplayForWindow(window)->name);
- int i;
+ int i, j;
/* Get the function pointers for the functions we will use. */
PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr =
@@ -239,14 +245,13 @@ SDL_bool KMSDRM_Vulkan_CreateSurface(_THIS,
(PFN_vkGetPhysicalDeviceDisplayPlanePropertiesKHR)vkGetInstanceProcAddr(
instance, "vkGetPhysicalDeviceDisplayPlanePropertiesKHR");
- /*PFN_vkGetDisplayPlaneSupportedDisplaysKHR vkGetDisplayPlaneSupportedDisplaysKHR =
+ PFN_vkGetDisplayPlaneSupportedDisplaysKHR vkGetDisplayPlaneSupportedDisplaysKHR =
(PFN_vkGetDisplayPlaneSupportedDisplaysKHR)vkGetInstanceProcAddr(
instance, "vkGetDisplayPlaneSupportedDisplaysKHR");
-
+
PFN_vkGetDisplayPlaneCapabilitiesKHR vkGetDisplayPlaneCapabilitiesKHR =
(PFN_vkGetDisplayPlaneCapabilitiesKHR)vkGetInstanceProcAddr(
instance, "vkGetDisplayPlaneCapabilitiesKHR");
- */
PFN_vkCreateDisplayModeKHR vkCreateDisplayModeKHR =
(PFN_vkCreateDisplayModeKHR)vkGetInstanceProcAddr(
@@ -329,38 +334,29 @@ SDL_bool KMSDRM_Vulkan_CreateSurface(_THIS,
}
/* Get the props of the displays of the physical device. */
- displays_props = (VkDisplayPropertiesKHR *) SDL_malloc(display_count * sizeof(*displays_props));
+ display_props = (VkDisplayPropertiesKHR *) SDL_malloc(display_count * sizeof(*display_props));
vkGetPhysicalDeviceDisplayPropertiesKHR(gpu,
&display_count,
- displays_props);
+ display_props);
+
+ /* Get the chosen display based on the display index. */
+ display = display_props[display_index].display;
- /* Get the videomode count for the first display. */
+ /* Get the list of the display videomodes. */
vkGetDisplayModePropertiesKHR(gpu,
- displays_props[display_index].display,
+ display,
&mode_count, NULL);
if (mode_count == 0) {
SDL_SetError("Vulkan can't find any video modes for display %i (%s)\n", 0,
- displays_props[display_index].displayName);
+ display_props[display_index].displayName);
goto clean;
}
- /* Get the props of the videomodes for the display. */
- modes_props = (VkDisplayModePropertiesKHR *) SDL_malloc(mode_count * sizeof(*modes_props));
+ mode_props = (VkDisplayModePropertiesKHR *) SDL_malloc(mode_count * sizeof(*mode_props));
vkGetDisplayModePropertiesKHR(gpu,
- displays_props[display_index].display,
- &mode_count, modes_props);
-
- /* Get the planes count of the physical device. */
- vkGetPhysicalDeviceDisplayPlanePropertiesKHR(gpu, &plane_count, NULL);
- if (plane_count == 0) {
- SDL_SetError("Vulkan can't find any planes.");
- goto clean;
- }
-
- /* Get the props of the planes for the physical device. */
- planes_props = SDL_malloc(sizeof(VkDisplayPlanePropertiesKHR) * plane_count);
- vkGetPhysicalDeviceDisplayPlanePropertiesKHR(gpu, &plane_count, planes_props);
+ display,
+ &mode_count, mode_props);
/* Get a video mode equal to the window size among the predefined ones,
if possible.
@@ -369,10 +365,10 @@ SDL_bool KMSDRM_Vulkan_CreateSurface(_THIS,
scanout a region bigger than the window (we would be reading past the
buffer, and Vulkan would give us a confusing VK_ERROR_SURFACE_LOST_KHR). */
for (i = 0; i < mode_count; i++) {
- if (modes_props[i].parameters.visibleRegion.width == window->w &&
- modes_props[i].parameters.visibleRegion.height == window->h)
+ if (mode_props[i].parameters.visibleRegion.width == window->w &&
+ mode_props[i].parameters.visibleRegion.height == window->h)
{
- display_mode_props = modes_props[i];
+ display_mode_props = mode_props[i];
mode_found = SDL_TRUE;
break;
}
@@ -399,7 +395,7 @@ SDL_bool KMSDRM_Vulkan_CreateSurface(_THIS,
display_mode_create_info.sType = VK_STRUCTURE_TYPE_DISPLAY_MODE_CREATE_INFO_KHR;
display_mode_create_info.parameters = new_mode_parameters;
result = vkCreateDisplayModeKHR(gpu,
- displays_props[display_index].display,
+ display,
&display_mode_create_info,
NULL, &display_mode);
if (result != VK_SUCCESS) {
@@ -414,6 +410,77 @@ SDL_bool KMSDRM_Vulkan_CreateSurface(_THIS,
goto clean;
}
+ /* Get the list of the physical device planes. */
+ vkGetPhysicalDeviceDisplayPlanePropertiesKHR(gpu, &plane_count, NULL);
+ if (plane_count == 0) {
+ SDL_SetError("Vulkan can't find any planes.");
+ goto clean;
+ }
+ plane_props = SDL_malloc(sizeof(VkDisplayPlanePropertiesKHR) * plane_count);
+ vkGetPhysicalDeviceDisplayPlanePropertiesKHR(gpu, &plane_count, plane_props);
+
+ /* Iterate on the list of planes of the physical device
+ to find a plane that matches these criteria:
+ -It must be compatible with the chosen display + mode.
+ -It isn't currently bound to another display.
+ -It supports per-pixel alpha, if possible. */
+ for (i = 0; i < plane_count; i++) {
+
+ uint32_t supported_displays_count = 0;
+ VkDisplayKHR* supported_displays;
+
+ /* See if the plane is compatible with the current display. */
+ vkGetDisplayPlaneSupportedDisplaysKHR(gpu, i, &supported_displays_count, NULL);
+ if (supported_displays_count == 0) {
+ /* This plane doesn't support any displays. Continue to the next plane. */
+ continue;
+ }
+
+ /* Get the list of displays supported by this plane. */
+ supported_displays = (VkDisplayKHR*)malloc(sizeof(VkDisplayKHR) * supported_displays_count);
+ vkGetDisplayPlaneSupportedDisplaysKHR(gpu, i,
+ &supported_displays_count, supported_displays);
+
+ /* The plane must be bound to the chosen display, or not in use.
+ If none of these is true, iterate to another plane. */
+ if (!((plane_props[i].currentDisplay == display) ||
+ (plane_props[i].currentDisplay == VK_NULL_HANDLE)))
+ continue;
+
+ /* Iterate the list of displays supported by this plane
+ in order to find out if the chosen display is among them. */
+ plane_supports_display = SDL_FALSE;
+ for (j = 0; j < supported_displays_count; j++) {
+ if (supported_displays[j] == display) {
+ plane_supports_display = SDL_TRUE;
+ break;
+ }
+ }
+
+ /* Free the list of displays supported by this plane. */
+ if (supported_displays)
+ free(supported_displays);
+
+ /* If the display is not supported by this plane, iterate to the next plane. */
+ if (!plane_supports_display) {
+ continue;
+ }
+
+ /* Want a plane that supports the alpha mode we have chosen. */
+ vkGetDisplayPlaneCapabilitiesKHR(gpu, display_mode, i, &plane_caps);
+ if (plane_caps.supportedAlpha == alpha_mode) {
+ /* Yep, this plane is alright. */
+ plane = i;
+ break;
+ }
+ }
+
+ /* If we couldn't find an appropiate plane, error out. */
+ if (plane == UINT32_MAX) {
+ SDL_SetError("Vulkan couldn't find an appropiate plane.");
+ goto clean;
+ }
+
/********************************************/
/* Let's finally create the Vulkan surface! */
/********************************************/
@@ -424,11 +491,10 @@ SDL_bool KMSDRM_Vulkan_CreateSurface(_THIS,
SDL_zero(display_plane_surface_create_info);
display_plane_surface_create_info.sType = VK_STRUCTURE_TYPE_DISPLAY_SURFACE_CREATE_INFO_KHR;
display_plane_surface_create_info.displayMode = display_mode;
- /* For now, simply use the first plane. */
- display_plane_surface_create_info.planeIndex = 0;
+ display_plane_surface_create_info.planeIndex = plane;
display_plane_surface_create_info.imageExtent = image_size;
display_plane_surface_create_info.transform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
- display_plane_surface_create_info.alphaMode = VK_DISPLAY_PLANE_ALPHA_OPAQUE_BIT_KHR;
+ display_plane_surface_create_info.alphaMode = alpha_mode;
result = vkCreateDisplayPlaneSurfaceKHR(instance,
&display_plane_surface_create_info,
NULL,
@@ -445,14 +511,14 @@ SDL_bool KMSDRM_Vulkan_CreateSurface(_THIS,
clean:
if (physical_devices)
SDL_free (physical_devices);
- if (displays_props)
- SDL_free (displays_props);
+ if (display_props)
+ SDL_free (display_props);
if (device_props)
SDL_free (device_props);
- if (planes_props)
- SDL_free (planes_props);
- if (modes_props)
- SDL_free (modes_props);
+ if (plane_props)
+ SDL_free (plane_props);
+ if (mode_props)
+ SDL_free (mode_props);
return ret;
}