From 29f34453164d90fe64ff1be1b4e88b39b3b39f4b Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Sun, 19 May 2019 10:36:44 -0700 Subject: [PATCH] video: Add Vulkan support for vivante fb Vivante drivers use the VK_KHR_display extension for rendering directly to the frame buffer. This patch adds support to the video driver for Vulkan rendering using that method. - Add an utility function SDL_Vulkan_Display_CreateSurface that creates a surface using this extension. The display to use (if there are multiple) can be overridden using the environment variable "SDL_VULKAN_DISPLAY". - Use this function in a new compilation unit SDL_vivantevideo.c, which implements the SDL_VIDEO_VULKAN methods of the driver structure. --- src/video/SDL_vulkan_internal.h | 7 + src/video/SDL_vulkan_utils.c | 341 ++++++++++++++++++++++++++ src/video/vivante/SDL_vivantevideo.c | 8 + src/video/vivante/SDL_vivantevulkan.c | 159 ++++++++++++ src/video/vivante/SDL_vivantevulkan.h | 53 ++++ 5 files changed, 568 insertions(+) create mode 100644 src/video/vivante/SDL_vivantevulkan.c create mode 100644 src/video/vivante/SDL_vivantevulkan.h diff --git a/src/video/SDL_vulkan_internal.h b/src/video/SDL_vulkan_internal.h index f095a01bde468..9577703e2ed3f 100644 --- a/src/video/SDL_vulkan_internal.h +++ b/src/video/SDL_vulkan_internal.h @@ -73,6 +73,13 @@ extern SDL_bool SDL_Vulkan_GetInstanceExtensions_Helper(unsigned *userCount, unsigned nameCount, const char *const *names); +/* Create a surface directly from a display connected to a physical device + * using the DisplayKHR extension. + * This needs to be passed an instance that was created with the VK_KHR_DISPLAY_EXTENSION_NAME + * exension. */ +extern SDL_bool SDL_Vulkan_Display_CreateSurface(void *vkGetInstanceProcAddr, + VkInstance instance, + VkSurfaceKHR *surface); #else /* No SDL Vulkan support, just include the header for typedefs */ diff --git a/src/video/SDL_vulkan_utils.c b/src/video/SDL_vulkan_utils.c index 4fc75ad32a6ef..b7750ffb525e7 100644 --- a/src/video/SDL_vulkan_utils.c +++ b/src/video/SDL_vulkan_utils.c @@ -22,6 +22,7 @@ #include "SDL_vulkan_internal.h" #include "SDL_error.h" +#include "SDL_log.h" #if SDL_VIDEO_VULKAN @@ -167,6 +168,346 @@ SDL_bool SDL_Vulkan_GetInstanceExtensions_Helper(unsigned *userCount, return SDL_TRUE; } +/* Alpha modes, in order of preference */ +static const VkDisplayPlaneAlphaFlagBitsKHR alphaModes[4] = { + VK_DISPLAY_PLANE_ALPHA_OPAQUE_BIT_KHR, + VK_DISPLAY_PLANE_ALPHA_GLOBAL_BIT_KHR, + VK_DISPLAY_PLANE_ALPHA_PER_PIXEL_BIT_KHR, + VK_DISPLAY_PLANE_ALPHA_PER_PIXEL_PREMULTIPLIED_BIT_KHR, +}; + +SDL_bool SDL_Vulkan_Display_CreateSurface(void *vkGetInstanceProcAddr_, + VkInstance instance, + VkSurfaceKHR *surface) +{ + PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = + (PFN_vkGetInstanceProcAddr)vkGetInstanceProcAddr_; +#define VULKAN_INSTANCE_FUNCTION(name) \ + PFN_##name name = (PFN_##name)vkGetInstanceProcAddr((VkInstance)instance, #name) + VULKAN_INSTANCE_FUNCTION(vkEnumeratePhysicalDevices); + VULKAN_INSTANCE_FUNCTION(vkGetPhysicalDeviceDisplayPropertiesKHR); + VULKAN_INSTANCE_FUNCTION(vkGetDisplayModePropertiesKHR); + VULKAN_INSTANCE_FUNCTION(vkGetPhysicalDeviceDisplayPlanePropertiesKHR); + VULKAN_INSTANCE_FUNCTION(vkGetDisplayPlaneCapabilitiesKHR); + VULKAN_INSTANCE_FUNCTION(vkGetDisplayPlaneSupportedDisplaysKHR); + VULKAN_INSTANCE_FUNCTION(vkCreateDisplayPlaneSurfaceKHR); +#undef VULKAN_INSTANCE_FUNCTION + VkDisplaySurfaceCreateInfoKHR createInfo = {}; + VkResult result; + uint32_t physicalDeviceCount = 0; + VkPhysicalDevice *physicalDevices = NULL; + uint32_t physicalDeviceIndex; + const char *chosenDisplayId; + int displayId = 0; /* Counting from physical device 0, display 0 */ + + if(!vkEnumeratePhysicalDevices || + !vkGetPhysicalDeviceDisplayPropertiesKHR || + !vkGetDisplayModePropertiesKHR || + !vkGetPhysicalDeviceDisplayPlanePropertiesKHR || + !vkGetDisplayPlaneCapabilitiesKHR || + !vkGetDisplayPlaneSupportedDisplaysKHR || + !vkCreateDisplayPlaneSurfaceKHR) + { + SDL_SetError(VK_KHR_DISPLAY_EXTENSION_NAME + " extension is not enabled in the Vulkan instance."); + goto error; + } + + if ((chosenDisplayId = SDL_getenv("SDL_VULKAN_DISPLAY")) != NULL) + { + displayId = SDL_atoi(chosenDisplayId); + } + + /* Enumerate physical devices */ + result = + vkEnumeratePhysicalDevices(instance, &physicalDeviceCount, NULL); + if(result != VK_SUCCESS) + { + SDL_SetError("Could not enumerate Vulkan physical devices"); + goto error; + } + if(physicalDeviceCount == 0) + { + SDL_SetError("No Vulkan physical devices"); + goto error; + } + physicalDevices = SDL_malloc(sizeof(VkPhysicalDevice) * physicalDeviceCount); + if(!physicalDevices) + { + SDL_OutOfMemory(); + goto error; + } + result = + vkEnumeratePhysicalDevices(instance, &physicalDeviceCount, physicalDevices); + if(result != VK_SUCCESS) + { + SDL_SetError("Error enumerating physical devices"); + goto error; + } + + for(physicalDeviceIndex = 0; physicalDeviceIndex < physicalDeviceCount; + physicalDeviceIndex++) + { + VkPhysicalDevice physicalDevice = physicalDevices[physicalDeviceIndex]; + uint32_t displayPropertiesCount = 0; + VkDisplayPropertiesKHR *displayProperties = NULL; + uint32_t displayModePropertiesCount = 0; + VkDisplayModePropertiesKHR *displayModeProperties = NULL; + int bestMatchIndex = -1; + uint32_t refreshRate = 0; + uint32_t i; + uint32_t displayPlanePropertiesCount = 0; + int planeIndex = -1; + VkDisplayKHR display; + VkDisplayPlanePropertiesKHR *displayPlaneProperties = NULL; + VkExtent2D extent; + VkDisplayPlaneCapabilitiesKHR planeCaps; + + /* Get information about the physical displays */ + result = + vkGetPhysicalDeviceDisplayPropertiesKHR(physicalDevice, &displayPropertiesCount, NULL); + if (result != VK_SUCCESS || displayPropertiesCount == 0) + { + /* This device has no physical device display properties, move on to next. */ + continue; + } + SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "vulkandisplay: Number of display properties for device %u: %u", + physicalDeviceIndex, displayPropertiesCount); + + if (displayId < 0 || displayId >= displayPropertiesCount) + { + /* Display id specified was higher than number of available displays, move to next physical device. */ + displayId -= displayPropertiesCount; + continue; + } + + displayProperties = SDL_malloc(sizeof(VkDisplayPropertiesKHR) * displayPropertiesCount); + if(!displayProperties) + { + SDL_OutOfMemory(); + goto error; + } + + result = + vkGetPhysicalDeviceDisplayPropertiesKHR(physicalDevice, &displayPropertiesCount, displayProperties); + if (result != VK_SUCCESS || displayPropertiesCount == 0) { + SDL_free(displayProperties); + SDL_SetError("Error enumerating physical device displays"); + goto error; + } + + display = displayProperties[displayId].display; + extent = displayProperties[displayId].physicalResolution; + SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "vulkandisplay: Display: %s Native resolution: %ux%u", + displayProperties[displayId].displayName, extent.width, extent.height); + + free(displayProperties); + displayProperties = NULL; + + /* Get display mode properties for the chosen display */ + result = + vkGetDisplayModePropertiesKHR(physicalDevice, display, &displayModePropertiesCount, NULL); + if (result != VK_SUCCESS || displayModePropertiesCount == 0) + { + SDL_SetError("Error enumerating display modes"); + goto error; + } + SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "vulkandisplay: Number of display modes: %u", displayModePropertiesCount); + + displayModeProperties = SDL_malloc(sizeof(VkDisplayModePropertiesKHR) * displayModePropertiesCount); + if(!displayModeProperties) + { + SDL_OutOfMemory(); + goto error; + } + + result = + vkGetDisplayModePropertiesKHR(physicalDevice, display, &displayModePropertiesCount, displayModeProperties); + if (result != VK_SUCCESS || displayModePropertiesCount == 0) { + SDL_SetError("Error enumerating display modes"); + SDL_free(displayModeProperties); + goto error; + } + + /* Try to find a display mode that matches the native resolution */ + for (i = 0; i < displayModePropertiesCount; ++i) + { + if (displayModeProperties[i].parameters.visibleRegion.width == extent.width && + displayModeProperties[i].parameters.visibleRegion.height == extent.height && + displayModeProperties[i].parameters.refreshRate > refreshRate) + { + bestMatchIndex = i; + refreshRate = displayModeProperties[i].parameters.refreshRate; + } + } + if (bestMatchIndex < 0) + { + SDL_SetError("Found no matching display mode"); + SDL_free(displayModeProperties); + goto error; + } + createInfo.displayMode = displayModeProperties[bestMatchIndex].displayMode; + SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "vulkandisplay: Matching mode %ux%u with refresh rate %u", + displayModeProperties[bestMatchIndex].parameters.visibleRegion.width, + displayModeProperties[bestMatchIndex].parameters.visibleRegion.height, + refreshRate); + + SDL_free(displayModeProperties); + displayModeProperties = NULL; + + /* Try to find a plane index that supports our display */ + result = + vkGetPhysicalDeviceDisplayPlanePropertiesKHR(physicalDevice, &displayPlanePropertiesCount, NULL); + if (result != VK_SUCCESS || displayPlanePropertiesCount == 0) + { + SDL_SetError("Error enumerating display planes"); + goto error; + } + SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "vulkandisplay: Number of display planes: %u", displayPlanePropertiesCount); + + displayPlaneProperties = SDL_malloc(sizeof(VkDisplayPlanePropertiesKHR) * displayPlanePropertiesCount); + if(!displayPlaneProperties) + { + SDL_OutOfMemory(); + goto error; + } + + result = + vkGetPhysicalDeviceDisplayPlanePropertiesKHR(physicalDevice, &displayPlanePropertiesCount, displayPlaneProperties); + if (result != VK_SUCCESS || displayPlanePropertiesCount == 0) + { + SDL_SetError("Error enumerating display plane properties"); + SDL_free(displayPlaneProperties); + goto error; + } + + for (i = 0; i < displayPlanePropertiesCount; ++i) + { + uint32_t planeSupportedDisplaysCount = 0; + VkDisplayKHR *planeSupportedDisplays = NULL; + uint32_t j; + + /* Check if plane is attached to a display, if not, continue. */ + if (displayPlaneProperties[i].currentDisplay == VK_NULL_HANDLE) + continue; + + /* Check supported displays for this plane. */ + result = + vkGetDisplayPlaneSupportedDisplaysKHR(physicalDevice, i, &planeSupportedDisplaysCount, NULL); + if (result != VK_SUCCESS || planeSupportedDisplaysCount == 0) + { + /* No supported displays, on to next plane. */ + SDL_free(displayPlaneProperties); + continue; + } + SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "vulkandisplay: Number of supported displays for plane %u: %u", i, planeSupportedDisplaysCount); + + planeSupportedDisplays = SDL_malloc(sizeof(VkDisplayKHR) * planeSupportedDisplaysCount); + if(!planeSupportedDisplays) + { + SDL_free(displayPlaneProperties); + SDL_OutOfMemory(); + goto error; + } + + result = + vkGetDisplayPlaneSupportedDisplaysKHR(physicalDevice, i, &planeSupportedDisplaysCount, planeSupportedDisplays); + if (result != VK_SUCCESS || planeSupportedDisplaysCount == 0) + { + SDL_SetError("Error enumerating supported displays, or no supported displays"); + SDL_free(planeSupportedDisplays); + SDL_free(displayPlaneProperties); + goto error; + } + + for (j = 0; j < planeSupportedDisplaysCount && planeSupportedDisplays[j] != display; ++j) + ; + + SDL_free(planeSupportedDisplays); + planeSupportedDisplays = NULL; + + if (j == planeSupportedDisplaysCount) + { + /* This display is not supported for this plane, move on. */ + continue; + } + + result = vkGetDisplayPlaneCapabilitiesKHR(physicalDevice, createInfo.displayMode, i, &planeCaps); + if (result != VK_SUCCESS) + { + SDL_SetError("Error getting display plane capabilities"); + SDL_free(displayPlaneProperties); + goto error; + } + + /* Check if plane fulfills extent requirements. */ + if (extent.width >= planeCaps.minDstExtent.width && extent.height >= planeCaps.minDstExtent.height && + extent.width <= planeCaps.maxDstExtent.width && extent.height <= planeCaps.maxDstExtent.height) + { + /* If it does, choose this plane. */ + SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "vulkandisplay: Choosing plane %d, minimum extent %dx%d maximum extent %dx%d", i, + planeCaps.minDstExtent.width, planeCaps.minDstExtent.height, + planeCaps.maxDstExtent.width, planeCaps.maxDstExtent.height); + planeIndex = i; + break; + } + } + + if (planeIndex < 0) + { + SDL_SetError("No plane supports the selected resolution"); + SDL_free(displayPlaneProperties); + goto error; + } + + createInfo.planeIndex = planeIndex; + createInfo.planeStackIndex = displayPlaneProperties[planeIndex].currentStackIndex; + SDL_free(displayPlaneProperties); + displayPlaneProperties = NULL; + + /* Find a supported alpha mode. Not all planes support OPAQUE */ + createInfo.alphaMode = VK_DISPLAY_PLANE_ALPHA_OPAQUE_BIT_KHR; + for (uint32_t i = 0; i < SDL_arraysize(alphaModes); i++) { + if (planeCaps.supportedAlpha & alphaModes[i]) { + createInfo.alphaMode = alphaModes[i]; + break; + } + } + SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "vulkandisplay: Chose alpha mode 0x%x", createInfo.alphaMode); + + /* Found a match, finally! Fill in extent, and break from loop */ + createInfo.imageExtent = extent; + break; + } + + SDL_free(physicalDevices); + physicalDevices = NULL; + + if (physicalDeviceIndex == physicalDeviceCount) + { + SDL_SetError("No usable displays found or requested display out of range"); + return SDL_FALSE; + } + + createInfo.sType = VK_STRUCTURE_TYPE_DISPLAY_SURFACE_CREATE_INFO_KHR; + createInfo.transform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; + createInfo.globalAlpha = 1.0f; + + result = vkCreateDisplayPlaneSurfaceKHR(instance, &createInfo, + NULL, surface); + if(result != VK_SUCCESS) + { + SDL_SetError("vkCreateDisplayPlaneSurfaceKHR failed: %s", + SDL_Vulkan_GetResultString(result)); + return SDL_FALSE; + } + SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "vulkandisplay: Created surface"); + return SDL_TRUE; +error: + SDL_free(physicalDevices); + return SDL_FALSE; +} + #endif /* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/vivante/SDL_vivantevideo.c b/src/video/vivante/SDL_vivantevideo.c index a1d8648f1e7a0..ddc1163927c64 100644 --- a/src/video/vivante/SDL_vivantevideo.c +++ b/src/video/vivante/SDL_vivantevideo.c @@ -37,6 +37,7 @@ #include "SDL_vivantevideo.h" #include "SDL_vivanteplatform.h" #include "SDL_vivanteopengles.h" +#include "SDL_vivantevulkan.h" static int @@ -109,6 +110,13 @@ VIVANTE_Create() device->GL_DeleteContext = VIVANTE_GLES_DeleteContext; #endif +#if SDL_VIDEO_VULKAN + device->Vulkan_LoadLibrary = VIVANTE_Vulkan_LoadLibrary; + device->Vulkan_UnloadLibrary = VIVANTE_Vulkan_UnloadLibrary; + device->Vulkan_GetInstanceExtensions = VIVANTE_Vulkan_GetInstanceExtensions; + device->Vulkan_CreateSurface = VIVANTE_Vulkan_CreateSurface; +#endif + device->PumpEvents = VIVANTE_PumpEvents; return device; diff --git a/src/video/vivante/SDL_vivantevulkan.c b/src/video/vivante/SDL_vivantevulkan.c new file mode 100644 index 0000000000000..907e6ac7ade54 --- /dev/null +++ b/src/video/vivante/SDL_vivantevulkan.c @@ -0,0 +1,159 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2017 Sam Lantinga + + 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 Wladimir J. van der Laan. Based on Jacob Lifshay's + * SDL_x11vulkan.c, Mark Callow's SDL_androidvulkan.c, and + * the FSL demo framework. + */ + +#include "../../SDL_internal.h" + +#if SDL_VIDEO_VULKAN && SDL_VIDEO_DRIVER_VIVANTE + +#include "SDL_vivantevideo.h" +#include "SDL_assert.h" + +#include "SDL_loadso.h" +#include "SDL_vivantevulkan.h" +#include "SDL_syswm.h" +#include "SDL_log.h" + +int VIVANTE_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 loader library */ + if(!path) + path = SDL_getenv("SDL_VULKAN_LIBRARY"); + if(!path) + { + /* If no path set, try Vivante fb vulkan driver explicitly */ + path = "libvulkan-fb.so"; + _this->vulkan_config.loader_handle = SDL_LoadObject(path); + if(!_this->vulkan_config.loader_handle) + { + /* If that couldn't be loaded, fall back to default name */ + path = "libvulkan.so"; + _this->vulkan_config.loader_handle = SDL_LoadObject(path); + } + } else { + _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)); + SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "vivante: Loaded vulkan driver %s", 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 VIVANTE_Vulkan_UnloadLibrary(_THIS) +{ + if(_this->vulkan_config.loader_handle) + { + SDL_UnloadObject(_this->vulkan_config.loader_handle); + _this->vulkan_config.loader_handle = NULL; + } +} + +SDL_bool VIVANTE_Vulkan_GetInstanceExtensions(_THIS, + SDL_Window *window, + unsigned *count, + const char **names) +{ + static const char *const extensionsForVivante[] = { + 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(extensionsForVivante), + extensionsForVivante); +} + +SDL_bool VIVANTE_Vulkan_CreateSurface(_THIS, + SDL_Window *window, + VkInstance instance, + VkSurfaceKHR *surface) +{ + if(!_this->vulkan_config.loader_handle) + { + SDL_SetError("Vulkan is not loaded"); + return SDL_FALSE; + } + return SDL_Vulkan_Display_CreateSurface(_this->vulkan_config.vkGetInstanceProcAddr, instance, surface); +} + +#endif + +/* vi: set ts=4 sw=4 expandtab: */ + diff --git a/src/video/vivante/SDL_vivantevulkan.h b/src/video/vivante/SDL_vivantevulkan.h new file mode 100644 index 0000000000000..b0dcc6f46bbfb --- /dev/null +++ b/src/video/vivante/SDL_vivantevulkan.h @@ -0,0 +1,53 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2017 Sam Lantinga + + 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 Wladimir J. van der Laan. Based on Jacob Lifshay's + * SDL_x11vulkan.h and Mark Callow's SDL_vivantevulkan.h + */ + +#include "../../SDL_internal.h" + +#ifndef SDL_vivantevulkan_h_ +#define SDL_vivantevulkan_h_ + +#include "../SDL_vulkan_internal.h" +#include "../SDL_sysvideo.h" + +#if SDL_VIDEO_VULKAN && SDL_VIDEO_DRIVER_VIVANTE + +int VIVANTE_Vulkan_LoadLibrary(_THIS, const char *path); +void VIVANTE_Vulkan_UnloadLibrary(_THIS); +SDL_bool VIVANTE_Vulkan_GetInstanceExtensions(_THIS, + SDL_Window *window, + unsigned *count, + const char **names); +SDL_bool VIVANTE_Vulkan_CreateSurface(_THIS, + SDL_Window *window, + VkInstance instance, + VkSurfaceKHR *surface); + +#endif + +#endif /* SDL_vivantevulkan_h_ */ + +/* vi: set ts=4 sw=4 expandtab: */ +