adding backend management responsability to the user

This commit is contained in:
2024-10-09 18:56:41 +02:00
parent b075f8ea73
commit f189928c82
12 changed files with 321 additions and 139 deletions

View File

@@ -9,6 +9,7 @@
#include "Vulkan.h"
#include "VulkanLoader.h"
#include "VulkanInstance.h"
VulkanGlobal* VulkanGetGlobal()
{
@@ -16,37 +17,49 @@ VulkanGlobal* VulkanGetGlobal()
return &vulkan;
}
bool VulkanLoadBackend()
PulseBackendFlags VulkanCheckSupport(PulseBackendFlags candidates, PulseShaderFormatsFlags shader_formats_used)
{
if(candidates != PULSE_BACKEND_ANY && (candidates & PULSE_BACKEND_VULKAN) == 0)
return PULSE_BACKEND_INVALID;
if((shader_formats_used & PULSE_SHADER_FORMAT_SPIRV_BIT) == 0)
return PULSE_BACKEND_INVALID;
if(!VulkanInitLoader())
return PULSE_BACKEND_INVALID;
VulkanInstance instance;
if(!VulkanInitInstance(&instance, PULSE_NO_DEBUG)) // Instance creation will fail if Vulkan is not supported
{
PulseGetLastErrorType(); // Clearing out the errors set by the failed instance creation
return PULSE_BACKEND_INVALID;
}
VulkanDestroyInstance(&instance);
VulkanLoaderShutdown();
return PULSE_BACKEND_VULKAN;
}
bool VulkanLoadBackend(PulseDebugLevel debug_level)
{
if(!VulkanInitLoader())
return false;
VulkanDriverData* driver_data = (VulkanDriverData*)calloc(1, sizeof(VulkanDriverData));
PULSE_CHECK_ALLOCATION_RETVAL(driver_data, false);
if(!VulkanInitInstance(&driver_data->instance, debug_level))
return false;
VulkanDriver.driver_data = driver_data;
return true;
}
PulseDevice VulkanCreatePulseDevice(PulseDebugLevel debug_level)
void VulkanUnloadBackend(PulseBackend backend)
{
VulkanPulseDevice* vulkan_device = (VulkanPulseDevice*)calloc(1, sizeof(VulkanPulseDevice));
PULSE_CHECK_ALLOCATION_RETVAL(vulkan_device, PULSE_NULL_HANDLE);
if(!VulkanInitInstance(&vulkan_device->instance, debug_level))
return PULSE_NULL_HANDLE;
PulseDeviceHandler* pulse_device = (PulseDeviceHandler*)calloc(1, sizeof(PulseDeviceHandler));
PULSE_CHECK_ALLOCATION_RETVAL(pulse_device, PULSE_NULL_HANDLE);
pulse_device->debug_level = debug_level;
pulse_device->driver_data = vulkan_device;
return pulse_device;
VulkanDestroyInstance(&VULKAN_RETRIEVE_DRIVER_DATA(backend)->instance);
VulkanLoaderShutdown();
}
void VulkanDestroyPulseDevice(PulseDevice device)
{
}
PulseBackendLoader VulkanDriver = {
PulseBackendHandler VulkanDriver = {
.PFN_LoadBackend = VulkanLoadBackend,
.PFN_CreateDevice = VulkanCreatePulseDevice,
.PFN_DestroyDevice = VulkanDestroyPulseDevice,
.PFN_UnloadBackend = VulkanUnloadBackend,
.PFN_CreateDevice = VulkanCreateDevice,
.backend = PULSE_BACKEND_VULKAN,
.supported_shader_formats = PULSE_SHADER_FORMAT_SPIRV_BIT
.supported_shader_formats = PULSE_SHADER_FORMAT_SPIRV_BIT,
.driver_data = PULSE_NULLPTR
};

View File

@@ -12,6 +12,8 @@
#include "VulkanDevice.h"
#include "VulkanInstance.h"
#define VULKAN_RETRIEVE_DRIVER_DATA(device) ((VulkanDriverData*)device->driver_data)
typedef struct VulkanGlobal
{
#define PULSE_VULKAN_GLOBAL_FUNCTION(fn) PFN_##fn fn;
@@ -19,14 +21,16 @@ typedef struct VulkanGlobal
#undef PULSE_VULKAN_GLOBAL_FUNCTION
} VulkanGlobal;
typedef struct VulkanPulseDevice
typedef struct VulkanDriverData
{
VulkanInstance instance;
VulkanDevice device;
} VulkanPulseDevice;
} VulkanDriverData;
VulkanGlobal* VulkanGetGlobal();
PulseBackendFlags VulkanCheckSupport(PulseBackendFlags candidates, PulseShaderFormatsFlags shader_formats_used); // Return PULSE_BACKEND_VULKAN in case of success and PULSE_BACKEND_INVALID otherwise
#endif // PULSE_VULKAN_H_
#endif // PULSE_ENABLE_VULKAN_BACKEND

View File

@@ -2,6 +2,99 @@
// This file is part of "Pulse"
// For conditions of distribution and use, see copyright notice in LICENSE
#include "VulkanInstance.h"
#include "VulkanDevice.h"
#include "../../PulseInternal.h"
/*
static int32_t VulkanScorePhysicalDevice(VkPhysicalDevice device, const char** device_extensions, uint32_t device_extensions_count)
{
PULSE_DECLARE_STACK_FIXED_ALLOCATOR(allocator, sizeof(VkExtensionProperties) * 4096, sizeof(VkExtensionProperties));
// Check extensions support
uint32_t extension_count;
kbhGetVulkanPFNs()->vkEnumerateDeviceExtensionProperties(device, PULSE_NULLPTR, &extension_count, PULSE_NULLPTR);
VkExtensionProperties* props = (VkExtensionProperties*)kbhCallocInFixed(&allocator, extension_count, sizeof(VkExtensionProperties));
if(!props)
return -1;
kbhGetVulkanPFNs()->vkEnumerateDeviceExtensionProperties(device, PULSE_NULLPTR, &extension_count, props);
bool are_there_required_device_extensions = true;
for(int j = 0; j < device_extensions_count; j++)
{
bool is_there_extension = false;
for(int k = 0; k < extension_count; k++)
{
if(strcmp(device_extensions[j], props[k].extensionName) == 0)
{
is_there_extension = true;
break;
}
}
if(is_there_extension == false)
{
are_there_required_device_extensions = false;
break;
}
}
if(are_there_required_device_extensions == false)
return -1;
// Check Queue Families Support
int32_t queue;
if(kbhFindPhysicalDeviceQueueFamily(device, KBH_VULKAN_QUEUE_COMPUTE, &queue) != KBH_RHI_SUCCESS)
return -1;
VkPhysicalDeviceProperties device_props;
kbhGetVulkanPFNs()->vkGetPhysicalDeviceProperties(device, &device_props);
VkPhysicalDeviceFeatures device_features;
kbhGetVulkanPFNs()->vkGetPhysicalDeviceFeatures(device, &device_features);
int32_t score = -1;
if(device_props.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU)
score += 1001;
score += device_props.limits.maxComputeWorkGroupCount[0];
score += device_props.limits.maxComputeWorkGroupCount[1];
score += device_props.limits.maxComputeWorkGroupCount[2];
score += device_props.limits.maxComputeSharedMemorySize;
return score;
}
static VkPhysicalDevice VulkanPickPhysicalDevice(VulkanInstance* instance)
{
VkPhysicalDevice* devices = PULSE_NULLPTR;
VkPhysicalDevice chosen_one = VK_NULL_HANDLE;
uint32_t device_count;
int32_t best_device_score = -1;
instance->vkEnumeratePhysicalDevices(instance->instance, &device_count, PULSE_NULLPTR);
devices = (VkPhysicalDevice*)calloc(device_count, sizeof(VkPhysicalDevice));
PULSE_CHECK_ALLOCATION_RETVAL(devices, VK_NULL_HANDLE);
instance->vkEnumeratePhysicalDevices(instance->instance, &device_count, devices);
for(int i = 0; i < device_count; i++)
{
int32_t current_device_score = VulkanScorePhysicalDevice(devices[i], PULSE_NULLPTR, 0);
if(current_device_score > best_device_score)
{
best_device_score = current_device_score;
chosen_one = devices[i];
}
}
return chosen_one;
}
*/
void* VulkanCreateDevice(PulseBackend backend, PulseDevice* forbiden_devices, uint32_t forbiden_devices_count)
{
}
void VulkanDestroyDevice(VulkanDevice* device)
{
if(device == PULSE_NULLPTR || device->device == VK_NULL_HANDLE)
return;
vmaDestroyAllocator(device->allocator);
device->vkDestroyDevice(device->device, PULSE_NULLPTR);
device->device = VK_NULL_HANDLE;
}

View File

@@ -32,7 +32,7 @@ typedef struct VulkanDevice
#undef PULSE_VULKAN_DEVICE_FUNCTION
} VulkanDevice;
VulkanDevice* VulkanCreateDevice(PulseDebugLevel debug_level);
void* VulkanCreateDevice(PulseBackend backend, PulseDevice* forbiden_devices, uint32_t forbiden_devices_count);
void VulkanDestroyDevice(VulkanDevice* device);
#endif // PULSE_VULKAN_DEVICE_H_

View File

@@ -24,7 +24,10 @@ static VkInstance VulkanCreateInstance(const char** extensions_enabled, uint32_t
create_info.pApplicationInfo = &app_info;
create_info.enabledExtensionCount = extensions_count;
create_info.ppEnabledExtensionNames = extensions_enabled;
create_info.enabledLayerCount = sizeof(layer_names) / sizeof(layer_names[0]);
if(debug_level == PULSE_NO_DEBUG)
create_info.enabledLayerCount = 0;
else
create_info.enabledLayerCount = sizeof(layer_names) / sizeof(layer_names[0]);
create_info.ppEnabledLayerNames = layer_names;
create_info.pNext = PULSE_NULLPTR;
#ifdef PULSE_PLAT_MACOS
@@ -39,17 +42,29 @@ static VkInstance VulkanCreateInstance(const char** extensions_enabled, uint32_t
bool VulkanInitInstance(VulkanInstance* instance, PulseDebugLevel debug_level)
{
instance->instance = VulkanCreateInstance(NULL, 0, debug_level);
#ifdef PULSE_PLAT_MACOS
const char* extensions[] = {
VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME,
};
#else
const char* extensions[] = {
};
#endif
instance->instance = VulkanCreateInstance(extensions, sizeof(extensions) / sizeof(char*), debug_level);
if(instance->instance == VK_NULL_HANDLE)
{
PulseSetInternalError(PULSE_ERROR_INITIALIZATION_FAILED);
return false;
}
if(VulkanLoadInstance(instance))
if(!VulkanLoadInstance(instance))
return false;
return true;
}
void VulkanDestroyInstance(VulkanInstance* instance)
{
if(instance == PULSE_NULLPTR || instance->instance == VK_NULL_HANDLE)
return;
instance->vkDestroyInstance(instance->instance, PULSE_NULLPTR);
instance->instance = VK_NULL_HANDLE;
}

View File

@@ -40,6 +40,8 @@
static LibModule vulkan_lib_module = PULSE_NULLPTR;
static uint32_t loader_references_count = 0;
static bool VulkanLoadGlobalFunctions(void* context, PFN_vkVoidFunction (*load)(void*, const char*));
static bool VulkanLoadInstanceFunctions(VulkanInstance* instance, PFN_vkVoidFunction (*load)(void*, const char*));
static bool VulkanLoadDeviceFunctions(VulkanInstance* instance, VulkanDevice* device, PFN_vkVoidFunction (*load)(VulkanInstance*, void*, const char*));
@@ -109,6 +111,9 @@ bool VulkanInitLoader()
};
#endif
if(loader_references_count != 0)
return true;
for(size_t i = 0; i < sizeof(libnames) / sizeof(const char*); i++)
{
vulkan_lib_module = LoadLibrary(libnames[i]);
@@ -127,6 +132,7 @@ bool VulkanInitLoader()
PulseSetInternalError(PULSE_ERROR_INITIALIZATION_FAILED);
return false;
}
loader_references_count++;
return VulkanLoadGlobalFunctions(PULSE_NULLPTR, vkGetInstanceProcAddrStub);
}
@@ -142,6 +148,9 @@ bool VulkanLoadDevice(VulkanInstance* instance, VulkanDevice* device)
void VulkanLoaderShutdown()
{
loader_references_count--;
if(loader_references_count != 0)
return;
UnloadLibrary(vulkan_lib_module);
vulkan_lib_module = PULSE_NULLPTR;
}