initial backend selection implementation
continuous-integration/drone/push Build is passing Details

pull/23/head
cosmonaut 2022-09-28 12:01:46 -07:00
parent 5176f790d8
commit c0e4e50863
4 changed files with 149 additions and 14 deletions

View File

@ -332,6 +332,14 @@ typedef enum Refresh_BorderColor
REFRESH_BORDERCOLOR_INT_OPAQUE_WHITE REFRESH_BORDERCOLOR_INT_OPAQUE_WHITE
} Refresh_BorderColor; } Refresh_BorderColor;
typedef enum Refresh_Backend
{
REFRESH_BACKEND_DONTCARE,
REFRESH_BACKEND_VULKAN,
REFRESH_BACKEND_PS5,
REFRESH_BACKEND_INVALID
} Refresh_Backend;
/* Structures */ /* Structures */
typedef struct Refresh_DepthStencilValue typedef struct Refresh_DepthStencilValue
@ -594,9 +602,24 @@ REFRESHAPI void Refresh_HookLogFunctions(
Refresh_LogFunc error Refresh_LogFunc error
); );
/* Backend selection */
/* Select the graphics API backend that Refresh should use.
*
* Note that Refresh is not required to select your preferred backend
* if it detects an incompatibility.
*
* Returns the backend that will actually be used.
*
* preferredBackend: The preferred backend that Refresh should select.
* flags: A pointer to a bitflag value that will be filled in with required SDL_WindowFlags masks.
*/
REFRESHAPI Refresh_Backend Refresh_SelectBackend(Refresh_Backend preferredBackend, uint32_t *flags);
/* Device */ /* Device */
/* Create a rendering context for use on the calling thread. /* Create a rendering context for use on the calling thread.
* You MUST have called Refresh_SelectDriver prior to calling this function.
* *
* presentationParameters: A window handle and presentation mode. * presentationParameters: A window handle and presentation mode.
* debugMode: Enable debug mode properties. * debugMode: Enable debug mode properties.

View File

@ -33,7 +33,8 @@
/* Drivers */ /* Drivers */
static const Refresh_Driver *drivers[] = { static const Refresh_Driver *backends[] = {
NULL,
#ifdef REFRESH_DRIVER_VULKAN #ifdef REFRESH_DRIVER_VULKAN
&VulkanDriver, &VulkanDriver,
#endif #endif
@ -129,18 +130,55 @@ uint32_t Refresh_LinkedVersion(void)
/* Driver Functions */ /* Driver Functions */
static int32_t selectedDriver = 0; static Refresh_Backend selectedBackend = REFRESH_BACKEND_INVALID;
Refresh_Backend Refresh_SelectBackend(Refresh_Backend preferredBackend, uint32_t *flags)
{
uint32_t backendIndex, i;
if (preferredBackend != REFRESH_BACKEND_DONTCARE)
{
/* Try to force it! */
backendIndex = preferredBackend;
if (backends[backendIndex]->PrepareDriver(flags))
{
selectedBackend = preferredBackend;
return selectedBackend;
}
}
/* Iterate until we find an appropriate backend. */
for (i = 1; backends[i] != NULL; i += 1)
{
if (backends[i]->PrepareDriver(flags))
{
selectedBackend = i;
return i;
}
}
if (backends[i] == NULL)
{
Refresh_LogError("No supported Refresh backend found!");
}
selectedBackend = REFRESH_BACKEND_INVALID;
return REFRESH_BACKEND_INVALID;
}
Refresh_Device* Refresh_CreateDevice( Refresh_Device* Refresh_CreateDevice(
Refresh_PresentationParameters *presentationParameters, Refresh_PresentationParameters *presentationParameters,
uint8_t debugMode uint8_t debugMode
) { ) {
if (selectedDriver < 0) if (selectedBackend == REFRESH_BACKEND_INVALID)
{ {
Refresh_LogError("Invalid backend selection. Did you call Refresh_SelectBackend?");
return NULL; return NULL;
} }
return drivers[selectedDriver]->CreateDevice( return backends[selectedBackend]->CreateDevice(
presentationParameters, presentationParameters,
debugMode debugMode
); );

View File

@ -542,6 +542,7 @@ struct Refresh_Device
typedef struct Refresh_Driver typedef struct Refresh_Driver
{ {
const char *Name; const char *Name;
uint8_t (*PrepareDriver)(uint32_t *flags);
Refresh_Device* (*CreateDevice)( Refresh_Device* (*CreateDevice)(
Refresh_PresentationParameters *presentationParameters, Refresh_PresentationParameters *presentationParameters,
uint8_t debugMode uint8_t debugMode

View File

@ -10285,9 +10285,7 @@ static void VULKAN_INTERNAL_GetPhysicalDeviceProperties(
static uint8_t VULKAN_INTERNAL_DeterminePhysicalDevice( static uint8_t VULKAN_INTERNAL_DeterminePhysicalDevice(
VulkanRenderer *renderer, VulkanRenderer *renderer,
VkSurfaceKHR surface, VkSurfaceKHR surface
const char **deviceExtensionNames,
uint32_t deviceExtensionCount
) { ) {
VkResult vulkanResult; VkResult vulkanResult;
VkPhysicalDevice *physicalDevices; VkPhysicalDevice *physicalDevices;
@ -10513,9 +10511,8 @@ static uint8_t VULKAN_INTERNAL_CreateLogicalDevice(
return 1; return 1;
} }
static void VULKAN_INTERNAL_LoadEntryPoints( static void VULKAN_INTERNAL_LoadEntryPoints()
VulkanRenderer *renderer {
) {
/* Load Vulkan entry points */ /* Load Vulkan entry points */
if (SDL_Vulkan_LoadLibrary(NULL) < 0) if (SDL_Vulkan_LoadLibrary(NULL) < 0)
{ {
@ -10546,6 +10543,83 @@ static void VULKAN_INTERNAL_LoadEntryPoints(
#include "Refresh_Driver_Vulkan_vkfuncs.h" #include "Refresh_Driver_Vulkan_vkfuncs.h"
} }
static uint8_t VULKAN_PrepareDriver(uint32_t *flags)
{
SDL_Window *dummyWindowHandle;
VulkanRenderer *renderer;
VkSurfaceKHR surface;
uint8_t result;
VULKAN_INTERNAL_LoadEntryPoints();
/* Test if we can create a Vulkan device */
dummyWindowHandle = SDL_CreateWindow(
"Refresh Vulkan",
0, 0,
128, 128,
SDL_WINDOW_VULKAN | SDL_WINDOW_HIDDEN
);
if (dummyWindowHandle == NULL)
{
Refresh_LogWarn("Vulkan: Could not create dummy window");
return 0;
}
/* partially set up VulkanRenderer so we can fall back in case of device non-compliance */
renderer = (VulkanRenderer*) SDL_malloc(sizeof(VulkanRenderer));
SDL_memset(renderer, '\0', sizeof(VulkanRenderer));
if (!VULKAN_INTERNAL_CreateInstance(renderer, dummyWindowHandle))
{
SDL_DestroyWindow(dummyWindowHandle);
SDL_free(renderer);
Refresh_LogWarn("Vulkan: Could not create Vulkan instance");
return 0;
}
if (!SDL_Vulkan_CreateSurface(
(SDL_Window*) dummyWindowHandle,
renderer->instance,
&surface
)) {
SDL_DestroyWindow(dummyWindowHandle);
SDL_free(renderer);
Refresh_LogWarn(
"SDL_Vulkan_CreateSurface failed: %s",
SDL_GetError()
);
return 0;
}
#define VULKAN_INSTANCE_FUNCTION(ext, ret, func, params) \
renderer->func = (vkfntype_##func) vkGetInstanceProcAddr(renderer->instance, #func);
#include "Refresh_Driver_Vulkan_vkfuncs.h"
result = VULKAN_INTERNAL_DeterminePhysicalDevice(renderer, surface);
renderer->vkDestroySurfaceKHR(
renderer->instance,
surface,
NULL
);
renderer->vkDestroyInstance(renderer->instance, NULL);
SDL_DestroyWindow(dummyWindowHandle);
SDL_free(renderer);
if (!result)
{
Refresh_LogWarn("Vulkan: Failed to determine a suitable physical device");
}
else
{
*flags = SDL_WINDOW_VULKAN;
}
return result;
}
static Refresh_Device* VULKAN_CreateDevice( static Refresh_Device* VULKAN_CreateDevice(
Refresh_PresentationParameters *presentationParameters, Refresh_PresentationParameters *presentationParameters,
uint8_t debugMode uint8_t debugMode
@ -10609,7 +10683,7 @@ static Refresh_Device* VULKAN_CreateDevice(
*/ */
#define VULKAN_INSTANCE_FUNCTION(ext, ret, func, params) \ #define VULKAN_INSTANCE_FUNCTION(ext, ret, func, params) \
renderer->func = (vkfntype_##func) vkGetInstanceProcAddr(renderer->instance, #func); renderer->func = (vkfntype_##func) vkGetInstanceProcAddr(renderer->instance, #func);
#include "Refresh_Driver_Vulkan_vkfuncs.h" #include "Refresh_Driver_Vulkan_vkfuncs.h"
/* /*
@ -10622,9 +10696,7 @@ static Refresh_Device* VULKAN_CreateDevice(
} }
if (!VULKAN_INTERNAL_DeterminePhysicalDevice( if (!VULKAN_INTERNAL_DeterminePhysicalDevice(
renderer, renderer,
surface, surface
deviceExtensionNames,
deviceExtensionCount
)) { )) {
Refresh_LogError("Failed to determine a suitable physical device"); Refresh_LogError("Failed to determine a suitable physical device");
return NULL; return NULL;
@ -11124,6 +11196,7 @@ static Refresh_Device* VULKAN_CreateDevice(
Refresh_Driver VulkanDriver = { Refresh_Driver VulkanDriver = {
"Vulkan", "Vulkan",
VULKAN_PrepareDriver,
VULKAN_CreateDevice VULKAN_CreateDevice
}; };