Commit a6dc838d52df3e4d02c7882f377d94149bdfb6c0

Manuel Alfayate Corchete 2020-12-23T16:22:46

[KMS/DRM][Vulkan] Only try to create a display mode when no suitable mode is found.

diff --git a/src/video/kmsdrm/SDL_kmsdrmvulkan.c b/src/video/kmsdrm/SDL_kmsdrmvulkan.c
index b3160ed..bd7f8e4 100644
--- a/src/video/kmsdrm/SDL_kmsdrmvulkan.c
+++ b/src/video/kmsdrm/SDL_kmsdrmvulkan.c
@@ -197,11 +197,13 @@ SDL_bool KMSDRM_Vulkan_CreateSurface(_THIS,
     VkDisplaySurfaceCreateInfoKHR display_plane_surface_create_info;
 
     VkExtent2D image_size;
-    VkDisplayModeKHR display_mode;
+    VkDisplayModeKHR *display_mode = NULL;
     VkDisplayModePropertiesKHR display_mode_props = {0};
+    VkDisplayModeParametersKHR new_mode_parameters = {0};
 
     VkResult result;
     SDL_bool ret = SDL_FALSE;
+    SDL_bool mode_found = SDL_FALSE;
 
     /* We don't receive a display index in KMSDRM_CreateDevice(), only
        a device index, which determines the GPU to use, but not the output.
@@ -282,7 +284,7 @@ SDL_bool KMSDRM_Vulkan_CreateSurface(_THIS,
     }
 
     /* Get the physical devices. */
-    physical_devices = malloc(sizeof(VkPhysicalDevice) * gpu_count);
+    physical_devices = SDL_malloc(sizeof(VkPhysicalDevice) * gpu_count);
     vkEnumeratePhysicalDevices(instance, &gpu_count, physical_devices);
 
     /* A GPU (or physical_device, in vkcube terms) is a GPU. A machine with more
@@ -301,7 +303,7 @@ SDL_bool KMSDRM_Vulkan_CreateSurface(_THIS,
     }
 
     /* Get the props of the displays of the physical device. */
-    displays_props = (VkDisplayPropertiesKHR *) malloc(display_count * sizeof(*displays_props));
+    displays_props = (VkDisplayPropertiesKHR *) SDL_malloc(display_count * sizeof(*displays_props));
     vkGetPhysicalDeviceDisplayPropertiesKHR(gpu,
                                            &display_count,
                                            displays_props);
@@ -318,7 +320,7 @@ SDL_bool KMSDRM_Vulkan_CreateSurface(_THIS,
     }
 
     /* Get the props of the videomodes for the first display. */
-    modes_props = (VkDisplayModePropertiesKHR *) malloc(mode_count * sizeof(*modes_props));
+    modes_props = (VkDisplayModePropertiesKHR *) SDL_malloc(mode_count * sizeof(*modes_props));
     vkGetDisplayModePropertiesKHR(gpu,
                                  displays_props[display_index].display,
                                  &mode_count, modes_props);
@@ -331,7 +333,7 @@ SDL_bool KMSDRM_Vulkan_CreateSurface(_THIS,
     }
 
     /* Get the props of the planes for the physical device. */
-    planes_props = malloc(sizeof(VkDisplayPlanePropertiesKHR) * plane_count);
+    planes_props = SDL_malloc(sizeof(VkDisplayPlanePropertiesKHR) * plane_count);
     vkGetPhysicalDeviceDisplayPlanePropertiesKHR(gpu, &plane_count, planes_props);
 
     /* Get a video mode equal or smaller than the window size. REMEMBER:
@@ -344,36 +346,48 @@ SDL_bool KMSDRM_Vulkan_CreateSurface(_THIS,
             modes_props[i].parameters.visibleRegion.height <= window->h)
         {
             display_mode_props = modes_props[i];
+            mode_found = SDL_TRUE;
             break;
         }
     }
 
-    if (display_mode_props.parameters.visibleRegion.width == 0
-        || display_mode_props.parameters.visibleRegion.height == 0)
-    {
-        SDL_SetError("Vulkan can't find a proper display mode for the window size.");
-        goto clean;
+    if (mode_found &&
+        display_mode_props.parameters.visibleRegion.width > 0 &&
+        display_mode_props.parameters.visibleRegion.height > 0 ) {
+        /* Found a suitable mode among the predefined ones. Use that. */
+        display_mode = &(display_mode_props.displayMode);
+    } else {
+        /* Can't find a suitable mode among the predefined ones, so try to create our own. */
+        new_mode_parameters.visibleRegion.width = window->w;
+        new_mode_parameters.visibleRegion.height = window->h;
+        new_mode_parameters.refreshRate = 60000; /* Always use 60Hz for now. */
+	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_mode_create_info,
+				  NULL, display_mode);
+	if (result != VK_SUCCESS) {
+	    SDL_SetError("Vulkan couldn't find a predefined mode for that window size and couldn't create a suitable mode.");
+	    goto clean;
+	}
     }
 
-    /* We have the props of the display mode, but we need an actual display mode. */
-    display_mode_create_info.sType = VK_STRUCTURE_TYPE_DISPLAY_MODE_CREATE_INFO_KHR;
-    display_mode_create_info.parameters = display_mode_props.parameters;
-    result = vkCreateDisplayModeKHR(gpu,
-			      displays_props[display_index].display,
-			      &display_mode_create_info,
-			      NULL, &display_mode);
-    if (result != VK_SUCCESS) {
-        SDL_SetError("Vulkan can't create the display mode.");
-        goto clean;
+    /* Just in case we get here without a display_mode. */
+    if (!display_mode) {
+	    SDL_SetError("Vulkan couldn't get a display mode.");
+	    goto clean;
     }
 
+    /********************************************/
     /* Let's finally create the Vulkan surface! */
+    /********************************************/
 
     image_size.width = window->w;
     image_size.height = window->h;
     
     display_plane_surface_create_info.sType = VK_STRUCTURE_TYPE_DISPLAY_SURFACE_CREATE_INFO_KHR;
-    display_plane_surface_create_info.displayMode = display_mode;
+    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.imageExtent = image_size;
@@ -392,13 +406,13 @@ SDL_bool KMSDRM_Vulkan_CreateSurface(_THIS,
 
 clean:
     if (physical_devices)
-        free (physical_devices);
+        SDL_free (physical_devices);
     if (displays_props)
-        free (displays_props);
+        SDL_free (displays_props);
     if (planes_props)
-        free (planes_props);
+        SDL_free (planes_props);
     if (modes_props)
-        free (modes_props);
+        SDL_free (modes_props);
 
     return ret;
 }