SDL: [KMSDRM] Fix intermitent bug in Vulkan initialization on Raspberry Pi 4

From 9172e413ada9eea0a405b95f9b669b71853dc89d Mon Sep 17 00:00:00 2001
From: Vanfanel <[EMAIL REDACTED]>
Date: Sun, 21 Feb 2021 22:57:22 +0100
Subject: [PATCH] [KMSDRM] Fix intermitent bug in Vulkan initialization on
 Raspberry Pi 4.

---
 src/video/kmsdrm/SDL_kmsdrmvulkan.c | 42 ++++++++++++++++++++++++-----
 1 file changed, 35 insertions(+), 7 deletions(-)

diff --git a/src/video/kmsdrm/SDL_kmsdrmvulkan.c b/src/video/kmsdrm/SDL_kmsdrmvulkan.c
index a429f42c3..34922980a 100644
--- a/src/video/kmsdrm/SDL_kmsdrmvulkan.c
+++ b/src/video/kmsdrm/SDL_kmsdrmvulkan.c
@@ -189,6 +189,7 @@ SDL_bool KMSDRM_Vulkan_CreateSurface(_THIS,
     uint32_t plane_count;
 
     VkPhysicalDevice *physical_devices = NULL;
+    VkPhysicalDeviceProperties *device_props = NULL;
     VkDisplayPropertiesKHR *displays_props = NULL;
     VkDisplayModePropertiesKHR *modes_props = NULL;
     VkDisplayPlanePropertiesKHR *planes_props = NULL;
@@ -203,6 +204,7 @@ SDL_bool KMSDRM_Vulkan_CreateSurface(_THIS,
 
     VkResult result;
     SDL_bool ret = SDL_FALSE;
+    SDL_bool valid_gpu = SDL_FALSE;
     SDL_bool mode_found = SDL_FALSE;
 
     /* We don't receive a display index in KMSDRM_CreateDevice(), only
@@ -214,8 +216,6 @@ SDL_bool KMSDRM_Vulkan_CreateSurface(_THIS,
 
     int i;
 
-    SDL_VideoData *viddata = ((SDL_VideoData *)_this->driverdata);
-
     /* Get the function pointers for the functions we will use. */
     PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr =
         (PFN_vkGetInstanceProcAddr)_this->vulkan_config.vkGetInstanceProcAddr;
@@ -228,6 +228,10 @@ SDL_bool KMSDRM_Vulkan_CreateSurface(_THIS,
         (PFN_vkEnumeratePhysicalDevices)vkGetInstanceProcAddr(
             instance, "vkEnumeratePhysicalDevices");
 
+    PFN_vkGetPhysicalDeviceProperties vkGetPhysicalDeviceProperties =
+        (PFN_vkGetPhysicalDeviceProperties)vkGetInstanceProcAddr(
+            instance, "vkGetPhysicalDeviceProperties");
+
     PFN_vkGetPhysicalDeviceDisplayPropertiesKHR vkGetPhysicalDeviceDisplayPropertiesKHR =
         (PFN_vkGetPhysicalDeviceDisplayPropertiesKHR)vkGetInstanceProcAddr(
             instance, "vkGetPhysicalDeviceDisplayPropertiesKHR");
@@ -275,6 +279,12 @@ SDL_bool KMSDRM_Vulkan_CreateSurface(_THIS,
         goto clean;
     }
 
+    /* A GPU (or physical_device, in vkcube terms) is a physical GPU.
+       A machine with more than one video output doesn't need to have more than one GPU,
+       like the Pi4 which has 1 GPU and 2 video outputs.
+       Just in case, we test that the GPU we choose is Vulkan-capable. 
+    */
+
     /* Get the physical device count. */
     vkEnumeratePhysicalDevices(instance, &gpu_count, NULL);
 
@@ -285,13 +295,31 @@ SDL_bool KMSDRM_Vulkan_CreateSurface(_THIS,
 
     /* Get the physical devices. */
     physical_devices = SDL_malloc(sizeof(VkPhysicalDevice) * gpu_count);
+    device_props = SDL_malloc(sizeof(VkPhysicalDeviceProperties));
     vkEnumeratePhysicalDevices(instance, &gpu_count, physical_devices);
 
-    /* A GPU (or physical_device, in vkcube terms) is a GPU. A machine with more
-       than one video output doen't need to have more than one GPU, like the Pi4
-       which has 1 GPU and 2 video outputs.
-       We grab the GPU/physical_device with the index we got in KMSDR_CreateDevice(). */
-    gpu = physical_devices[viddata->devindex]; 
+    /* Iterate on the physical devices. */
+    for (i = 0; i < gpu_count; i++) {
+
+        /* Get the physical device properties. */
+        vkGetPhysicalDeviceProperties(
+            physical_devices[i],
+            device_props
+        );
+
+        /* Is this device a real GPU that supports API version 1 at least? */
+        if (device_props->apiVersion >= 1 && 
+           (device_props->deviceType == 1 || device_props->deviceType == 2))
+        {
+            gpu = physical_devices[i];
+            valid_gpu = SDL_TRUE;
+        }
+    }
+
+    if (!valid_gpu) {
+        SDL_SetError("Vulkan can't find a valid physical device (gpu).");
+        goto clean;
+    }
 
     /* A display is a video output. 1 GPU can have N displays.
        Vulkan only counts the connected displays.