mirror of https://github.com/encounter/SDL.git
[KMS/DRM] Add the missing files for Vulkan support to the KMSDRM_LEGACY backend, had forgotted to do -hg add-.
This commit is contained in:
parent
661bacfe27
commit
335d78ff86
|
@ -0,0 +1,422 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2021 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @author Manuel Alfayate Corchere <redwindwanderer@gmail.com>.
|
||||
* Based on Jacob Lifshay's SDL_x11vulkan.c.
|
||||
*/
|
||||
|
||||
#include "../../SDL_internal.h"
|
||||
|
||||
#if SDL_VIDEO_VULKAN && SDL_VIDEO_DRIVER_KMSDRM
|
||||
|
||||
#include "SDL_kmsdrm_legacy_video.h"
|
||||
#include "SDL_kmsdrm_legacy_dyn.h"
|
||||
#include "SDL_assert.h"
|
||||
|
||||
#include "SDL_loadso.h"
|
||||
#include "SDL_kmsdrm_legacy_vulkan.h"
|
||||
#include "SDL_syswm.h"
|
||||
#include "sys/ioctl.h"
|
||||
|
||||
#if defined(__OpenBSD__)
|
||||
#define DEFAULT_VULKAN "libvulkan.so"
|
||||
#else
|
||||
#define DEFAULT_VULKAN "libvulkan.so.1"
|
||||
#endif
|
||||
|
||||
int KMSDRM_LEGACY_Vulkan_LoadLibrary(_THIS, const char *path)
|
||||
{
|
||||
VkExtensionProperties *extensions = NULL;
|
||||
Uint32 i, extensionCount = 0;
|
||||
SDL_bool hasSurfaceExtension = SDL_FALSE;
|
||||
SDL_bool hasDisplayExtension = SDL_FALSE;
|
||||
PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = NULL;
|
||||
|
||||
if(_this->vulkan_config.loader_handle)
|
||||
return SDL_SetError("Vulkan already loaded");
|
||||
|
||||
/* Load the Vulkan library */
|
||||
if(!path)
|
||||
path = SDL_getenv("SDL_VULKAN_LIBRARY");
|
||||
if(!path)
|
||||
path = DEFAULT_VULKAN;
|
||||
|
||||
_this->vulkan_config.loader_handle = SDL_LoadObject(path);
|
||||
|
||||
if(!_this->vulkan_config.loader_handle)
|
||||
return -1;
|
||||
|
||||
SDL_strlcpy(_this->vulkan_config.loader_path, path,
|
||||
SDL_arraysize(_this->vulkan_config.loader_path));
|
||||
|
||||
vkGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)SDL_LoadFunction(
|
||||
_this->vulkan_config.loader_handle, "vkGetInstanceProcAddr");
|
||||
|
||||
if(!vkGetInstanceProcAddr)
|
||||
goto fail;
|
||||
|
||||
_this->vulkan_config.vkGetInstanceProcAddr = (void *)vkGetInstanceProcAddr;
|
||||
_this->vulkan_config.vkEnumerateInstanceExtensionProperties =
|
||||
(void *)((PFN_vkGetInstanceProcAddr)_this->vulkan_config.vkGetInstanceProcAddr)(
|
||||
VK_NULL_HANDLE, "vkEnumerateInstanceExtensionProperties");
|
||||
|
||||
if(!_this->vulkan_config.vkEnumerateInstanceExtensionProperties)
|
||||
goto fail;
|
||||
|
||||
extensions = SDL_Vulkan_CreateInstanceExtensionsList(
|
||||
(PFN_vkEnumerateInstanceExtensionProperties)
|
||||
_this->vulkan_config.vkEnumerateInstanceExtensionProperties,
|
||||
&extensionCount);
|
||||
|
||||
if(!extensions)
|
||||
goto fail;
|
||||
|
||||
for(i = 0; i < extensionCount; i++)
|
||||
{
|
||||
if(SDL_strcmp(VK_KHR_SURFACE_EXTENSION_NAME, extensions[i].extensionName) == 0)
|
||||
hasSurfaceExtension = SDL_TRUE;
|
||||
else if(SDL_strcmp(VK_KHR_DISPLAY_EXTENSION_NAME, extensions[i].extensionName) == 0)
|
||||
hasDisplayExtension = SDL_TRUE;
|
||||
}
|
||||
|
||||
SDL_free(extensions);
|
||||
|
||||
if(!hasSurfaceExtension)
|
||||
{
|
||||
SDL_SetError("Installed Vulkan doesn't implement the "
|
||||
VK_KHR_SURFACE_EXTENSION_NAME " extension");
|
||||
goto fail;
|
||||
}
|
||||
else if(!hasDisplayExtension)
|
||||
{
|
||||
SDL_SetError("Installed Vulkan doesn't implement the "
|
||||
VK_KHR_DISPLAY_EXTENSION_NAME "extension");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
SDL_UnloadObject(_this->vulkan_config.loader_handle);
|
||||
_this->vulkan_config.loader_handle = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
void KMSDRM_LEGACY_Vulkan_UnloadLibrary(_THIS)
|
||||
{
|
||||
if(_this->vulkan_config.loader_handle)
|
||||
{
|
||||
SDL_UnloadObject(_this->vulkan_config.loader_handle);
|
||||
_this->vulkan_config.loader_handle = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*********************************************************************/
|
||||
/* Here we can put whatever Vulkan extensions we want to be enabled */
|
||||
/* at instance creation, which is done in the programs, not in SDL. */
|
||||
/* So: programs call SDL_Vulkan_GetInstanceExtensions() and here */
|
||||
/* we put the extensions specific to this backend so the programs */
|
||||
/* get a list with the extension we want, so they can include that */
|
||||
/* list in the ppEnabledExtensionNames and EnabledExtensionCount */
|
||||
/* members of the VkInstanceCreateInfo struct passed to */
|
||||
/* vkCreateInstance(). */
|
||||
/*********************************************************************/
|
||||
SDL_bool KMSDRM_LEGACY_Vulkan_GetInstanceExtensions(_THIS,
|
||||
SDL_Window *window,
|
||||
unsigned *count,
|
||||
const char **names)
|
||||
{
|
||||
static const char *const extensionsForKMSDRM[] = {
|
||||
VK_KHR_SURFACE_EXTENSION_NAME, VK_KHR_DISPLAY_EXTENSION_NAME
|
||||
};
|
||||
if(!_this->vulkan_config.loader_handle)
|
||||
{
|
||||
SDL_SetError("Vulkan is not loaded");
|
||||
return SDL_FALSE;
|
||||
}
|
||||
return SDL_Vulkan_GetInstanceExtensions_Helper(
|
||||
count, names, SDL_arraysize(extensionsForKMSDRM),
|
||||
extensionsForKMSDRM);
|
||||
}
|
||||
|
||||
void KMSDRM_LEGACY_Vulkan_GetDrawableSize(_THIS, SDL_Window *window, int *w, int *h)
|
||||
{
|
||||
if (w) {
|
||||
*w = window->w;
|
||||
}
|
||||
|
||||
if (h) {
|
||||
*h = window->h;
|
||||
}
|
||||
}
|
||||
|
||||
/***********************************************************************/
|
||||
/* First thing to know is that we don't call vkCreateInstance() here. */
|
||||
/* Instead, programs using SDL and Vulkan create their Vulkan instance */
|
||||
/* and we get it here, ready to use. */
|
||||
/* Extensions specific for this platform are activated in */
|
||||
/* KMSDRM_LEGACY_Vulkan_GetInstanceExtensions(), like we do with */
|
||||
/* VK_KHR_DISPLAY_EXTENSION_NAME, which is what we need for x-less VK. */
|
||||
/***********************************************************************/
|
||||
SDL_bool KMSDRM_LEGACY_Vulkan_CreateSurface(_THIS,
|
||||
SDL_Window *window,
|
||||
VkInstance instance,
|
||||
VkSurfaceKHR *surface)
|
||||
{
|
||||
VkPhysicalDevice gpu;
|
||||
uint32_t gpu_count;
|
||||
uint32_t display_count;
|
||||
uint32_t mode_count;
|
||||
uint32_t plane_count;
|
||||
|
||||
VkPhysicalDevice *physical_devices = NULL;
|
||||
VkDisplayPropertiesKHR *displays_props = NULL;
|
||||
VkDisplayModePropertiesKHR *modes_props = NULL;
|
||||
VkDisplayPlanePropertiesKHR *planes_props = NULL;
|
||||
|
||||
VkDisplayModeCreateInfoKHR display_mode_create_info;
|
||||
VkDisplaySurfaceCreateInfoKHR display_plane_surface_create_info;
|
||||
|
||||
VkExtent2D image_size;
|
||||
VkDisplayModeKHR *display_mode = NULL;
|
||||
VkDisplayModePropertiesKHR display_mode_props = {0};
|
||||
VkDisplayModeParametersKHR new_mode_parameters = { {0, 0}, 0};
|
||||
|
||||
VkResult result;
|
||||
SDL_bool ret = SDL_FALSE;
|
||||
SDL_bool mode_found = SDL_FALSE;
|
||||
|
||||
/* We don't receive a display index in KMSDRM_LEGACY_CreateDevice(), only
|
||||
a device index, which determines the GPU to use, but not the output.
|
||||
So we simply use the first connected output (ie, the first connected
|
||||
video output) for now.
|
||||
In other words, change this index to select a different output. Easy! */
|
||||
int display_index = 0;
|
||||
|
||||
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;
|
||||
|
||||
PFN_vkCreateDisplayPlaneSurfaceKHR vkCreateDisplayPlaneSurfaceKHR =
|
||||
(PFN_vkCreateDisplayPlaneSurfaceKHR)vkGetInstanceProcAddr(
|
||||
instance, "vkCreateDisplayPlaneSurfaceKHR");
|
||||
|
||||
PFN_vkEnumeratePhysicalDevices vkEnumeratePhysicalDevices =
|
||||
(PFN_vkEnumeratePhysicalDevices)vkGetInstanceProcAddr(
|
||||
instance, "vkEnumeratePhysicalDevices");
|
||||
|
||||
PFN_vkGetPhysicalDeviceDisplayPropertiesKHR vkGetPhysicalDeviceDisplayPropertiesKHR =
|
||||
(PFN_vkGetPhysicalDeviceDisplayPropertiesKHR)vkGetInstanceProcAddr(
|
||||
instance, "vkGetPhysicalDeviceDisplayPropertiesKHR");
|
||||
|
||||
PFN_vkGetDisplayModePropertiesKHR vkGetDisplayModePropertiesKHR =
|
||||
(PFN_vkGetDisplayModePropertiesKHR)vkGetInstanceProcAddr(
|
||||
instance, "vkGetDisplayModePropertiesKHR");
|
||||
|
||||
PFN_vkGetPhysicalDeviceDisplayPlanePropertiesKHR vkGetPhysicalDeviceDisplayPlanePropertiesKHR =
|
||||
(PFN_vkGetPhysicalDeviceDisplayPlanePropertiesKHR)vkGetInstanceProcAddr(
|
||||
instance, "vkGetPhysicalDeviceDisplayPlanePropertiesKHR");
|
||||
|
||||
/*PFN_vkGetDisplayPlaneSupportedDisplaysKHR vkGetDisplayPlaneSupportedDisplaysKHR =
|
||||
(PFN_vkGetDisplayPlaneSupportedDisplaysKHR)vkGetInstanceProcAddr(
|
||||
instance, "vkGetDisplayPlaneSupportedDisplaysKHR");
|
||||
|
||||
PFN_vkGetDisplayPlaneCapabilitiesKHR vkGetDisplayPlaneCapabilitiesKHR =
|
||||
(PFN_vkGetDisplayPlaneCapabilitiesKHR)vkGetInstanceProcAddr(
|
||||
instance, "vkGetDisplayPlaneCapabilitiesKHR");
|
||||
*/
|
||||
|
||||
PFN_vkCreateDisplayModeKHR vkCreateDisplayModeKHR =
|
||||
(PFN_vkCreateDisplayModeKHR)vkGetInstanceProcAddr(
|
||||
instance, "vkCreateDisplayModeKHR");
|
||||
|
||||
if(!_this->vulkan_config.loader_handle)
|
||||
{
|
||||
SDL_SetError("Vulkan is not loaded");
|
||||
goto clean;
|
||||
}
|
||||
|
||||
/*************************************/
|
||||
/* Block for vulkan surface creation */
|
||||
/*************************************/
|
||||
|
||||
/****************************************************************/
|
||||
/* If we got vkCreateDisplayPlaneSurfaceKHR() pointer, it means */
|
||||
/* that the VK_KHR_Display extension is active on the instance. */
|
||||
/* That's the central extension we need for x-less VK! */
|
||||
/****************************************************************/
|
||||
if(!vkCreateDisplayPlaneSurfaceKHR)
|
||||
{
|
||||
SDL_SetError(VK_KHR_DISPLAY_EXTENSION_NAME
|
||||
" extension is not enabled in the Vulkan instance.");
|
||||
goto clean;
|
||||
}
|
||||
|
||||
/* Get the physical device count. */
|
||||
vkEnumeratePhysicalDevices(instance, &gpu_count, NULL);
|
||||
|
||||
if (gpu_count == 0) {
|
||||
SDL_SetError("Vulkan can't find physical devices (gpus).");
|
||||
goto clean;
|
||||
}
|
||||
|
||||
/* Get the physical devices. */
|
||||
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
|
||||
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];
|
||||
|
||||
/* A display is a video output. 1 GPU can have N displays.
|
||||
Vulkan only counts the connected displays.
|
||||
Get the display count of the GPU. */
|
||||
vkGetPhysicalDeviceDisplayPropertiesKHR(gpu, &display_count, NULL);
|
||||
if (display_count == 0) {
|
||||
SDL_SetError("Vulkan can't find any displays.");
|
||||
goto clean;
|
||||
}
|
||||
|
||||
/* Get the props of the displays of the physical device. */
|
||||
displays_props = (VkDisplayPropertiesKHR *) SDL_malloc(display_count * sizeof(*displays_props));
|
||||
vkGetPhysicalDeviceDisplayPropertiesKHR(gpu,
|
||||
&display_count,
|
||||
displays_props);
|
||||
|
||||
/* Get the videomode count for the first display. */
|
||||
vkGetDisplayModePropertiesKHR(gpu,
|
||||
displays_props[display_index].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);
|
||||
goto clean;
|
||||
}
|
||||
|
||||
/* Get the props of the videomodes for the first display. */
|
||||
modes_props = (VkDisplayModePropertiesKHR *) SDL_malloc(mode_count * sizeof(*modes_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);
|
||||
|
||||
/* Get a video mode equal or smaller than the window size. REMEMBER:
|
||||
We have to get a small enough videomode for the window size,
|
||||
because videomode determines how big the scanout region is and we can't
|
||||
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)
|
||||
{
|
||||
display_mode_props = modes_props[i];
|
||||
mode_found = SDL_TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/* 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;
|
||||
/* For now, simply use the first plane. */
|
||||
display_plane_surface_create_info.planeIndex = 0;
|
||||
display_plane_surface_create_info.imageExtent = image_size;
|
||||
result = vkCreateDisplayPlaneSurfaceKHR(instance,
|
||||
&display_plane_surface_create_info,
|
||||
NULL,
|
||||
surface);
|
||||
if(result != VK_SUCCESS)
|
||||
{
|
||||
SDL_SetError("vkCreateDisplayPlaneSurfaceKHR failed: %s",
|
||||
SDL_Vulkan_GetResultString(result));
|
||||
goto clean;
|
||||
}
|
||||
|
||||
ret = SDL_TRUE;
|
||||
|
||||
clean:
|
||||
if (physical_devices)
|
||||
SDL_free (physical_devices);
|
||||
if (displays_props)
|
||||
SDL_free (displays_props);
|
||||
if (planes_props)
|
||||
SDL_free (planes_props);
|
||||
if (modes_props)
|
||||
SDL_free (modes_props);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* vim: set ts=4 sw=4 expandtab: */
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2021 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @author Manuel Alfayate Corchere <redwindwanderer@gmail.com>.
|
||||
* Based on Jacob Lifshay's SDL_x11vulkan.c.
|
||||
*/
|
||||
|
||||
#include "../../SDL_internal.h"
|
||||
|
||||
#ifndef SDL_kmsdrm_legacy_vulkan_h_
|
||||
#define SDL_kmsdrm_legacy_vulkan_h_
|
||||
|
||||
#include "../SDL_vulkan_internal.h"
|
||||
#include "../SDL_sysvideo.h"
|
||||
|
||||
#if SDL_VIDEO_VULKAN && SDL_VIDEO_DRIVER_KMSDRM
|
||||
|
||||
int KMSDRM_LEGACY_Vulkan_LoadLibrary(_THIS, const char *path);
|
||||
void KMSDRM_LEGACY_Vulkan_UnloadLibrary(_THIS);
|
||||
SDL_bool KMSDRM_LEGACY_Vulkan_GetInstanceExtensions(_THIS,
|
||||
SDL_Window *window,
|
||||
unsigned *count,
|
||||
const char **names);
|
||||
void KMSDRM_LEGACY_Vulkan_GetDrawableSize(_THIS, SDL_Window *window, int *w, int *h);
|
||||
SDL_bool KMSDRM_LEGACY_Vulkan_CreateSurface(_THIS,
|
||||
SDL_Window *window,
|
||||
VkInstance instance,
|
||||
VkSurfaceKHR *surface);
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* SDL_kmsdrm_legacy_vulkan_h_ */
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
Loading…
Reference in New Issue