External Interop (#14)

pull/1/head
thatcosmonaut 2021-01-13 17:37:54 -08:00 committed by GitHub
parent 4783d2efc2
commit b12b785dbe
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 373 additions and 139 deletions

View File

@ -46,6 +46,12 @@
#endif /* __GNUC__ */
#endif /* REFRESHNAMELESS */
#define VK_DEFINE_HANDLE(object) typedef struct object##_T* object;
VK_DEFINE_HANDLE(VkInstance)
VK_DEFINE_HANDLE(VkDevice)
VK_DEFINE_HANDLE(VkPhysicalDevice)
#include <stdint.h>
#ifdef __cplusplus
@ -608,6 +614,56 @@ typedef struct Refresh_FramebufferCreateInfo
uint32_t height;
} Refresh_FramebufferCreateInfo;
/* Interop Structs */
typedef enum Refresh_SysRendererType
{
REFRESH_RENDERER_TYPE_VULKAN
} Refresh_SysRendererType;
typedef struct Refresh_SysRenderer
{
Refresh_SysRendererType rendererType;
union
{
#if REFRESH_DRIVER_VULKAN
struct
{
VkInstance instance;
VkPhysicalDevice physicalDevice;
VkDevice logicalDevice;
uint32_t queueFamilyIndex;
} vulkan;
#endif /* REFRESH_DRIVER_VULKAN */
uint8_t filler[64];
} renderer;
} Refresh_SysRenderer;
typedef struct Refresh_TextureHandles
{
Refresh_SysRendererType rendererType;
union
{
#if REFRESH_DRIVER_VULKAN
#if defined(__LP64__) || defined(_WIN64) || defined(__x86_64__) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__)
#define REFRESH_VULKAN_HANDLE_TYPE void*
#else
#define REFRESH_VULKAN_HANDLE_TYPE uint64_t
#endif
struct
{
REFRESH_VULKAN_HANDLE_TYPE image; /* VkImage */
REFRESH_VULKAN_HANDLE_TYPE view; /* VkImageView */
} vulkan;
#endif /* REFRESH_DRIVER_VULKAN */
uint8_t filler[64];
} texture;
} Refresh_TextureHandles;
/* Version API */
#define REFRESH_ABI_VERSION 0
@ -655,6 +711,18 @@ REFRESHAPI Refresh_Device* Refresh_CreateDevice(
uint8_t debugMode
);
/* Create a rendering context by taking an externally-initialized VkDevice.
* Only valid with Vulkan backend.
* Useful for piggybacking on a separate graphics library like FNA3D.
*
* sysRenderer: Externally-initialized device info.
* debugMode: Enable debug mode properties.
*/
REFRESHAPI Refresh_Device* Refresh_CreateDeviceUsingExternal(
Refresh_SysRenderer *sysRenderer,
uint8_t debugMode
);
/* Destroys a rendering context previously returned by Refresh_CreateDevice. */
REFRESHAPI void Refresh_DestroyDevice(Refresh_Device *device);
@ -1357,6 +1425,13 @@ REFRESHAPI void Refresh_Wait(
Refresh_Device *device
);
/* Export handles to be consumed by another API */
REFRESHAPI void Refresh_GetTextureHandles(
Refresh_Device* device,
Refresh_Texture* texture,
Refresh_TextureHandles* handles
);
#ifdef __cplusplus
}
#endif /* __cplusplus */

View File

@ -141,6 +141,26 @@ Refresh_Device* Refresh_CreateDevice(
);
}
Refresh_Device* Refresh_CreateDeviceUsingExternal(
Refresh_SysRenderer *sysRenderer,
uint8_t debugMode
) {
if (selectedDriver < 0)
{
return NULL;
}
if (sysRenderer == NULL)
{
return NULL;
}
return drivers[selectedDriver]->CreateDeviceUsingExternal(
sysRenderer,
debugMode
);
}
void Refresh_DestroyDevice(Refresh_Device *device)
{
NULL_RETURN(device);
@ -895,4 +915,17 @@ void Refresh_Wait(
);
}
void Refresh_GetTextureHandles(
Refresh_Device* device,
Refresh_Texture* texture,
Refresh_TextureHandles *handles
) {
NULL_RETURN(device);
return device->GetTextureHandles(
device->driverData,
texture,
handles
);
}
/* vim: set noexpandtab shiftwidth=8 tabstop=8: */

View File

@ -526,6 +526,12 @@ struct Refresh_Device
Refresh_Renderer *driverData
);
void(*GetTextureHandles)(
Refresh_Renderer *driverData,
Refresh_Texture *texture,
Refresh_TextureHandles *handles
);
/* Opaque pointer for the Driver */
Refresh_Renderer *driverData;
};
@ -583,7 +589,8 @@ struct Refresh_Device
ASSIGN_DRIVER_FUNC(AcquireCommandBuffer, name) \
ASSIGN_DRIVER_FUNC(QueuePresent, name) \
ASSIGN_DRIVER_FUNC(Submit, name) \
ASSIGN_DRIVER_FUNC(Wait, name)
ASSIGN_DRIVER_FUNC(Wait, name) \
ASSIGN_DRIVER_FUNC(GetTextureHandles, name)
typedef struct Refresh_Driver
{
@ -592,6 +599,10 @@ typedef struct Refresh_Driver
Refresh_PresentationParameters *presentationParameters,
uint8_t debugMode
);
Refresh_Device* (*CreateDeviceUsingExternal)(
Refresh_SysRenderer *sysRenderer,
uint8_t debugMode
);
} Refresh_Driver;
extern Refresh_Driver VulkanDriver;

View File

@ -1446,6 +1446,10 @@ typedef struct VulkanRenderer
uint32_t submittedRenderPassesToDestroyCount;
uint32_t submittedRenderPassesToDestroyCapacity;
/* External Interop */
uint8_t usesExternalDevice;
#define VULKAN_INSTANCE_FUNCTION(ext, ret, func, params) \
vkfntype_##func func;
#define VULKAN_DEVICE_FUNCTION(ext, ret, func, params) \
@ -3650,8 +3654,11 @@ static void VULKAN_DestroyDevice(
SDL_free(renderer->buffersInUse);
if (!renderer->usesExternalDevice)
{
renderer->vkDestroyDevice(renderer->logicalDevice, NULL);
renderer->vkDestroyInstance(renderer->instance, NULL);
}
SDL_free(renderer);
SDL_free(device);
@ -8226,7 +8233,7 @@ static void VULKAN_Submit(
}
else
{
submitInfo.pWaitDstStageMask = NULL;
submitInfo.pWaitDstStageMask = waitStages;
submitInfo.signalSemaphoreCount = 0;
submitInfo.pSignalSemaphores = NULL;
}
@ -8380,6 +8387,21 @@ static void VULKAN_Wait(
);
}
/* External interop */
static void VULKAN_GetTextureHandles(
Refresh_Renderer* driverData,
Refresh_Texture* texture,
Refresh_TextureHandles *handles
) {
VulkanRenderer *renderer = (VulkanRenderer*) driverData;
VulkanTexture *vulkanTexture = (VulkanTexture*) texture;
handles->rendererType = REFRESH_RENDERER_TYPE_VULKAN;
handles->texture.vulkan.image = vulkanTexture->image;
handles->texture.vulkan.view = vulkanTexture->view;
}
/* Device instantiation */
static inline uint8_t VULKAN_INTERNAL_SupportsExtension(
@ -8768,6 +8790,24 @@ static uint8_t VULKAN_INTERNAL_IsDeviceSuitable(
return 0;
}
static VULKAN_INTERNAL_GetPhysicalDeviceProperties(
VulkanRenderer *renderer
) {
renderer->physicalDeviceDriverProperties.sType =
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES_KHR;
renderer->physicalDeviceDriverProperties.pNext = NULL;
renderer->physicalDeviceProperties.sType =
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
renderer->physicalDeviceProperties.pNext =
&renderer->physicalDeviceDriverProperties;
renderer->vkGetPhysicalDeviceProperties2KHR(
renderer->physicalDevice,
&renderer->physicalDeviceProperties
);
}
static uint8_t VULKAN_INTERNAL_DeterminePhysicalDevice(
VulkanRenderer *renderer,
const char **deviceExtensionNames,
@ -8855,19 +8895,7 @@ static uint8_t VULKAN_INTERNAL_DeterminePhysicalDevice(
renderer->physicalDevice = physicalDevice;
renderer->queueFamilyIndices = queueFamilyIndices;
renderer->physicalDeviceDriverProperties.sType =
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES_KHR;
renderer->physicalDeviceDriverProperties.pNext = NULL;
renderer->physicalDeviceProperties.sType =
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
renderer->physicalDeviceProperties.pNext =
&renderer->physicalDeviceDriverProperties;
renderer->vkGetPhysicalDeviceProperties2KHR(
renderer->physicalDevice,
&renderer->physicalDeviceProperties
);
VULKAN_INTERNAL_GetPhysicalDeviceProperties(renderer);
SDL_stack_free(physicalDevices);
return 1;
@ -8991,12 +9019,44 @@ static uint8_t VULKAN_INTERNAL_CreateLogicalDevice(
return 1;
}
static Refresh_Device* VULKAN_CreateDevice(
Refresh_PresentationParameters *presentationParameters,
uint8_t debugMode
static void VULKAN_INTERNAL_LoadEntryPoints(
VulkanRenderer *renderer
) {
/* Load Vulkan entry points */
if (SDL_Vulkan_LoadLibrary(NULL) < 0)
{
Refresh_LogWarn("Vulkan: SDL_Vulkan_LoadLibrary failed!");
return 0;
}
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wpedantic"
vkGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)SDL_Vulkan_GetVkGetInstanceProcAddr();
#pragma GCC diagnostic pop
if (vkGetInstanceProcAddr == NULL)
{
Refresh_LogWarn(
"SDL_Vulkan_GetVkGetInstanceProcAddr(): %s",
SDL_GetError()
);
return 0;
}
#define VULKAN_GLOBAL_FUNCTION(name) \
name = (PFN_##name) vkGetInstanceProcAddr(VK_NULL_HANDLE, #name); \
if (name == NULL) \
{ \
Refresh_LogWarn("vkGetInstanceProcAddr(VK_NULL_HANDLE, \"" #name "\") failed"); \
return 0; \
}
#include "Refresh_Driver_Vulkan_vkfuncs.h"
}
/* Expects a partially initialized VulkanRenderer */
static Refresh_Device* VULKAN_INTERNAL_CreateDevice(
VulkanRenderer *renderer
) {
Refresh_Device *result;
VulkanRenderer *renderer;
VkResult vulkanResult;
uint32_t i;
@ -9028,124 +9088,7 @@ static Refresh_Device* VULKAN_CreateDevice(
result = (Refresh_Device*) SDL_malloc(sizeof(Refresh_Device));
ASSIGN_DRIVER(VULKAN)
renderer = (VulkanRenderer*) SDL_malloc(sizeof(VulkanRenderer));
/* Load Vulkan entry points */
if (SDL_Vulkan_LoadLibrary(NULL) < 0)
{
Refresh_LogWarn("Vulkan: SDL_Vulkan_LoadLibrary failed!");
return 0;
}
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wpedantic"
vkGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr) SDL_Vulkan_GetVkGetInstanceProcAddr();
#pragma GCC diagnostic pop
if (vkGetInstanceProcAddr == NULL)
{
Refresh_LogWarn(
"SDL_Vulkan_GetVkGetInstanceProcAddr(): %s",
SDL_GetError()
);
return 0;
}
#define VULKAN_GLOBAL_FUNCTION(name) \
name = (PFN_##name) vkGetInstanceProcAddr(VK_NULL_HANDLE, #name); \
if (name == NULL) \
{ \
Refresh_LogWarn("vkGetInstanceProcAddr(VK_NULL_HANDLE, \"" #name "\") failed"); \
return 0; \
}
#include "Refresh_Driver_Vulkan_vkfuncs.h"
result->driverData = (Refresh_Renderer*) renderer;
renderer->debugMode = debugMode;
renderer->headless = presentationParameters->deviceWindowHandle == NULL;
/* Create the VkInstance */
if (!VULKAN_INTERNAL_CreateInstance(renderer, presentationParameters->deviceWindowHandle))
{
Refresh_LogError("Error creating vulkan instance");
return NULL;
}
renderer->deviceWindowHandle = presentationParameters->deviceWindowHandle;
renderer->presentMode = presentationParameters->presentMode;
/*
* Create the WSI vkSurface
*/
if (!SDL_Vulkan_CreateSurface(
(SDL_Window*) renderer->deviceWindowHandle,
renderer->instance,
&renderer->surface
)) {
Refresh_LogError(
"SDL_Vulkan_CreateSurface failed: %s",
SDL_GetError()
);
return NULL;
}
/*
* Get vkInstance entry points
*/
#define VULKAN_INSTANCE_FUNCTION(ext, ret, func, params) \
renderer->func = (vkfntype_##func) vkGetInstanceProcAddr(renderer->instance, #func);
#include "Refresh_Driver_Vulkan_vkfuncs.h"
/*
* Choose/Create vkDevice
*/
if (SDL_strcmp(SDL_GetPlatform(), "Stadia") != 0)
{
deviceExtensionCount -= 1;
}
if (!VULKAN_INTERNAL_DeterminePhysicalDevice(
renderer,
deviceExtensionNames,
deviceExtensionCount
)) {
Refresh_LogError("Failed to determine a suitable physical device");
return NULL;
}
Refresh_LogInfo("Refresh Driver: Vulkan");
Refresh_LogInfo(
"Vulkan Device: %s",
renderer->physicalDeviceProperties.properties.deviceName
);
Refresh_LogInfo(
"Vulkan Driver: %s %s",
renderer->physicalDeviceDriverProperties.driverName,
renderer->physicalDeviceDriverProperties.driverInfo
);
Refresh_LogInfo(
"Vulkan Conformance: %u.%u.%u",
renderer->physicalDeviceDriverProperties.conformanceVersion.major,
renderer->physicalDeviceDriverProperties.conformanceVersion.minor,
renderer->physicalDeviceDriverProperties.conformanceVersion.patch
);
Refresh_LogWarn(
"\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"
"! Refresh Vulkan is still in development! !\n"
"! The API is unstable and subject to change! !\n"
"! You have been warned! !\n"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
);
if (!VULKAN_INTERNAL_CreateLogicalDevice(
renderer,
deviceExtensionNames,
deviceExtensionCount
)) {
Refresh_LogError("Failed to create logical device");
return NULL;
}
/*
* Create initial swapchain
@ -9818,9 +9761,181 @@ static Refresh_Device* VULKAN_CreateDevice(
return result;
}
static Refresh_Device* VULKAN_CreateDevice(
Refresh_PresentationParameters *presentationParameters,
uint8_t debugMode
) {
VulkanRenderer *renderer = (VulkanRenderer*) SDL_malloc(sizeof(VulkanRenderer));
VULKAN_INTERNAL_LoadEntryPoints(renderer);
/* Create the VkInstance */
if (!VULKAN_INTERNAL_CreateInstance(renderer, presentationParameters->deviceWindowHandle))
{
Refresh_LogError("Error creating vulkan instance");
return NULL;
}
renderer->deviceWindowHandle = presentationParameters->deviceWindowHandle;
renderer->presentMode = presentationParameters->presentMode;
renderer->debugMode = debugMode;
renderer->headless = presentationParameters->deviceWindowHandle == NULL;
renderer->usesExternalDevice = 0;
/*
* Create the WSI vkSurface
*/
if (!SDL_Vulkan_CreateSurface(
(SDL_Window*)renderer->deviceWindowHandle,
renderer->instance,
&renderer->surface
)) {
Refresh_LogError(
"SDL_Vulkan_CreateSurface failed: %s",
SDL_GetError()
);
return NULL;
}
/*
* Get vkInstance entry points
*/
#define VULKAN_INSTANCE_FUNCTION(ext, ret, func, params) \
renderer->func = (vkfntype_##func) vkGetInstanceProcAddr(renderer->instance, #func);
#include "Refresh_Driver_Vulkan_vkfuncs.h"
/*
* Choose/Create vkDevice
*/
if (SDL_strcmp(SDL_GetPlatform(), "Stadia") != 0)
{
deviceExtensionCount -= 1;
}
if (!VULKAN_INTERNAL_DeterminePhysicalDevice(
renderer,
deviceExtensionNames,
deviceExtensionCount
)) {
Refresh_LogError("Failed to determine a suitable physical device");
return NULL;
}
Refresh_LogInfo("Refresh Driver: Vulkan");
Refresh_LogInfo(
"Vulkan Device: %s",
renderer->physicalDeviceProperties.properties.deviceName
);
Refresh_LogInfo(
"Vulkan Driver: %s %s",
renderer->physicalDeviceDriverProperties.driverName,
renderer->physicalDeviceDriverProperties.driverInfo
);
Refresh_LogInfo(
"Vulkan Conformance: %u.%u.%u",
renderer->physicalDeviceDriverProperties.conformanceVersion.major,
renderer->physicalDeviceDriverProperties.conformanceVersion.minor,
renderer->physicalDeviceDriverProperties.conformanceVersion.patch
);
Refresh_LogWarn(
"\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"
"! Refresh Vulkan is still in development! !\n"
"! The API is unstable and subject to change! !\n"
"! You have been warned! !\n"
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
);
if (!VULKAN_INTERNAL_CreateLogicalDevice(
renderer,
deviceExtensionNames,
deviceExtensionCount
)) {
Refresh_LogError("Failed to create logical device");
return NULL;
}
return VULKAN_INTERNAL_CreateDevice(renderer);
}
static Refresh_Device* VULKAN_CreateDeviceUsingExternal(
Refresh_SysRenderer *sysRenderer,
uint8_t debugMode
) {
VulkanRenderer* renderer = (VulkanRenderer*)SDL_malloc(sizeof(VulkanRenderer));
renderer->instance = sysRenderer->renderer.vulkan.instance;
renderer->physicalDevice = sysRenderer->renderer.vulkan.physicalDevice;
renderer->logicalDevice = sysRenderer->renderer.vulkan.logicalDevice;
renderer->queueFamilyIndices.computeFamily = sysRenderer->renderer.vulkan.queueFamilyIndex;
renderer->queueFamilyIndices.graphicsFamily = sysRenderer->renderer.vulkan.queueFamilyIndex;
renderer->queueFamilyIndices.presentFamily = sysRenderer->renderer.vulkan.queueFamilyIndex;
renderer->queueFamilyIndices.transferFamily = sysRenderer->renderer.vulkan.queueFamilyIndex;
renderer->deviceWindowHandle = NULL;
renderer->presentMode = 0;
renderer->debugMode = debugMode;
renderer->headless = 1;
renderer->usesExternalDevice = 1;
VULKAN_INTERNAL_LoadEntryPoints(renderer);
/*
* Get vkInstance entry points
*/
#define VULKAN_INSTANCE_FUNCTION(ext, ret, func, params) \
renderer->func = (vkfntype_##func) vkGetInstanceProcAddr(renderer->instance, #func);
#include "Refresh_Driver_Vulkan_vkfuncs.h"
/* Load vkDevice entry points */
#define VULKAN_DEVICE_FUNCTION(ext, ret, func, params) \
renderer->func = (vkfntype_##func) \
renderer->vkGetDeviceProcAddr( \
renderer->logicalDevice, \
#func \
);
#include "Refresh_Driver_Vulkan_vkfuncs.h"
renderer->vkGetDeviceQueue(
renderer->logicalDevice,
renderer->queueFamilyIndices.graphicsFamily,
0,
&renderer->graphicsQueue
);
renderer->vkGetDeviceQueue(
renderer->logicalDevice,
renderer->queueFamilyIndices.presentFamily,
0,
&renderer->presentQueue
);
renderer->vkGetDeviceQueue(
renderer->logicalDevice,
renderer->queueFamilyIndices.computeFamily,
0,
&renderer->computeQueue
);
renderer->vkGetDeviceQueue(
renderer->logicalDevice,
renderer->queueFamilyIndices.transferFamily,
0,
&renderer->transferQueue
);
VULKAN_INTERNAL_GetPhysicalDeviceProperties(renderer);
return VULKAN_INTERNAL_CreateDevice(renderer);
}
Refresh_Driver VulkanDriver = {
"Vulkan",
VULKAN_CreateDevice
VULKAN_CreateDevice,
VULKAN_CreateDeviceUsingExternal
};
#endif //REFRESH_DRIVER_VULKAN