177 lines
6.9 KiB
C
177 lines
6.9 KiB
C
#include "evkDevice.h"
|
|
#include "evkTypes.h"
|
|
#include "evkAllocator.h"
|
|
|
|
evstring VkDynamicRenderingExtName = evstr("VK_KHR_dynamic_rendering");
|
|
evstring VkSync2ExtName = evstr("VK_KHR_synchronization2");
|
|
|
|
VkPhysicalDeviceDynamicRenderingFeaturesKHR dynamicRenderingFeature = (VkPhysicalDeviceDynamicRenderingFeaturesKHR) {
|
|
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_FEATURES_KHR,
|
|
.dynamicRendering = VK_TRUE,
|
|
};
|
|
|
|
VkPhysicalDeviceSynchronization2Features sync2Features = (VkPhysicalDeviceSynchronization2Features) {
|
|
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SYNCHRONIZATION_2_FEATURES,
|
|
.synchronization2 = VK_TRUE,
|
|
};
|
|
|
|
VkPhysicalDevice evkDetectPhysicalDevice(evkInstance instance, VkPhysicalDeviceType deviceType)
|
|
{
|
|
VkPhysicalDevice chosenDevice = EV_INVALID(VkPhysicalDevice);
|
|
u32 deviceCount = 0;
|
|
|
|
vec(VkPhysicalDevice) physicalDevices = vec_init(VkPhysicalDevice);
|
|
vkEnumeratePhysicalDevices(instance.vk, &deviceCount, NULL);
|
|
vec_setlen(&physicalDevices, deviceCount);
|
|
vkEnumeratePhysicalDevices(instance.vk, &deviceCount, physicalDevices);
|
|
|
|
// TODO Add a more robust/flexible way to pick a GPU
|
|
for(u32 i = 0; i < deviceCount; i++)
|
|
{
|
|
VkPhysicalDeviceProperties deviceProperties;
|
|
vkGetPhysicalDeviceProperties(physicalDevices[i], &deviceProperties);
|
|
if(deviceProperties.deviceType == deviceType)
|
|
{
|
|
chosenDevice = physicalDevices[i];
|
|
break;
|
|
}
|
|
}
|
|
|
|
vec_fini(&physicalDevices);
|
|
|
|
return chosenDevice;
|
|
}
|
|
|
|
evkDevice evkCreateDevice(evkDeviceCreateInfo createInfo)
|
|
{
|
|
evkDevice device;
|
|
device._physicalDevice = evkDetectPhysicalDevice(createInfo.instance, createInfo.physicalDeviceType);
|
|
device._instance = createInfo.instance;
|
|
|
|
VkPhysicalDeviceProperties physicalDeviceProperties;
|
|
vkGetPhysicalDeviceProperties(device._physicalDevice, &physicalDeviceProperties);
|
|
device.limits = physicalDeviceProperties.limits;
|
|
|
|
for (u32 i = 0; i < MAX_QUEUE_FAMILIES; i++) {
|
|
device.queueFamilies[i] = (evkDeviceQueueFamily){
|
|
.familyIndex = -1,
|
|
.allocatedQueueCount = 0
|
|
};
|
|
}
|
|
|
|
VkDeviceCreateInfo vkDeviceCreateInfo = __EV_VEC_EMPTY_ARRAY;
|
|
vkDeviceCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
|
|
void** pNext = &vkDeviceCreateInfo.pNext;
|
|
|
|
if(ev_vec_find(&createInfo.deviceExtensions, &VkDynamicRenderingExtName) != -1)
|
|
{
|
|
*pNext = &dynamicRenderingFeature;
|
|
pNext = &dynamicRenderingFeature.pNext;
|
|
}
|
|
|
|
if(ev_vec_find(&createInfo.deviceExtensions, &VkSync2ExtName) != -1)
|
|
{
|
|
*pNext = &sync2Features;
|
|
pNext = &sync2Features.pNext;
|
|
}
|
|
|
|
vkDeviceCreateInfo.enabledExtensionCount = vec_len(&createInfo.deviceExtensions);
|
|
vkDeviceCreateInfo.ppEnabledExtensionNames = createInfo.deviceExtensions;
|
|
|
|
// Getting the total number of queues requested from the device
|
|
u32 totalQueueCount = 0;
|
|
for (u32 i = 0; i < vec_len(&createInfo.queueRequirements); i++) {
|
|
totalQueueCount += createInfo.queueRequirements[i].count;
|
|
}
|
|
|
|
const f32 DEFAULT_PRIORITY = 1.0f;
|
|
// A priorities list that can be passed with any VkQueueCreteInfo (doable since we have no custom priorities)
|
|
vec(f32) priorities = vec_init(f32);
|
|
vec_setlen(&priorities, totalQueueCount);
|
|
for (u32 i = 0; i < totalQueueCount; i++) {
|
|
priorities[i] = DEFAULT_PRIORITY;
|
|
}
|
|
|
|
vec(VkDeviceQueueCreateInfo) queueCreateInfoList = vec_init(VkDeviceQueueCreateInfo);
|
|
if (createInfo.queueRequirements) {
|
|
// Retrieving the queue family properties into a vector
|
|
u32 queueFamilyCount = 0;
|
|
vkGetPhysicalDeviceQueueFamilyProperties(device._physicalDevice, &queueFamilyCount, NULL);
|
|
vec(VkQueueFamilyProperties) queueFamilyProperties = vec_init(VkQueueFamilyProperties);
|
|
vec_setlen(&queueFamilyProperties, queueFamilyCount);
|
|
vkGetPhysicalDeviceQueueFamilyProperties(device._physicalDevice, &queueFamilyCount, queueFamilyProperties);
|
|
|
|
// Creating VkDeviceQueueCreateInfos from requirements and family properties
|
|
// NOTICE: Currently, there can be no queues of a specific type in 2 different
|
|
// families. While that can be considered a limitation, the application targeted
|
|
// by this abstraction aren't expected to be complex enough to need it.
|
|
for (u32 familyIndex = 0; familyIndex < queueFamilyCount; familyIndex++) {
|
|
VkQueueFamilyProperties currentFamilyProperties = queueFamilyProperties[familyIndex];
|
|
u32 availableQueuesInFamily = currentFamilyProperties.queueCount;
|
|
|
|
for (u32 reqIndex = 0; reqIndex < vec_len(&createInfo.queueRequirements); reqIndex++) {
|
|
evkDeviceQueueRequirement currentRequirement = createInfo.queueRequirements[reqIndex];
|
|
|
|
// Testing compatibility of queue family and requirement
|
|
if (currentRequirement.flags & currentFamilyProperties.queueFlags) {
|
|
|
|
u32 requiredCount = currentRequirement.count;
|
|
while (availableQueuesInFamily > 0 && requiredCount > 0) {
|
|
// If the queue family is not already in the vector, push it.
|
|
if (vec_len(&queueCreateInfoList) <= familyIndex) {
|
|
VkDeviceQueueCreateInfo newQueueCreateInfo = { 0 };
|
|
newQueueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
|
|
newQueueCreateInfo.queueFamilyIndex = familyIndex;
|
|
newQueueCreateInfo.pQueuePriorities = priorities;
|
|
vec_push(&queueCreateInfoList, &newQueueCreateInfo);
|
|
}
|
|
|
|
u32 allocationCount = (availableQueuesInFamily>requiredCount)?requiredCount:availableQueuesInFamily;
|
|
queueCreateInfoList[familyIndex].queueCount += allocationCount;
|
|
device.queueFamilies[currentRequirement.flags].familyIndex = familyIndex;
|
|
device.queueFamilies[currentRequirement.flags].allocatedQueueCount += allocationCount;
|
|
|
|
// Allowing retrieval of families according to their actual flags
|
|
device.queueFamilies[currentFamilyProperties.queueFlags].familyIndex = familyIndex;
|
|
device.queueFamilies[currentFamilyProperties.queueFlags].allocatedQueueCount += allocationCount;
|
|
|
|
// Updating the loop condition variables
|
|
availableQueuesInFamily -= allocationCount;
|
|
requiredCount -= allocationCount;
|
|
}
|
|
// Updating the requirement's count after allocation
|
|
createInfo.queueRequirements[reqIndex].count = requiredCount;
|
|
}
|
|
}
|
|
}
|
|
|
|
vkDeviceCreateInfo.pQueueCreateInfos = queueCreateInfoList;
|
|
vkDeviceCreateInfo.queueCreateInfoCount = (u32)vec_len(&queueCreateInfoList);
|
|
|
|
vec_fini(&queueFamilyProperties);
|
|
}
|
|
|
|
// Allowing the retrieval of non-requested, but allocated, queues is possible.
|
|
// Example: Allocating COMPUTE | GRAPHICS then requesting GRAPHICS should
|
|
// return the already allocated queue
|
|
for (i32 i = MAX_QUEUE_FAMILIES - 1; i >= 0; i--) {
|
|
for (i32 j = i - 1; j >= 0; j--) {
|
|
if (device.queueFamilies[j].familyIndex == -1 && (i & j) == j) {
|
|
device.queueFamilies[j] = device.queueFamilies[i];
|
|
}
|
|
}
|
|
}
|
|
|
|
vkCreateDevice(device._physicalDevice, &vkDeviceCreateInfo, evkGetAllocationCallbacks(), &device.vk);
|
|
|
|
vec_fini(&queueCreateInfoList);
|
|
vec_fini(&priorities);
|
|
|
|
return device;
|
|
}
|
|
|
|
void evkDestroyDevice(evkDevice device)
|
|
{
|
|
vkDestroyDevice(device.vk, evkGetAllocationCallbacks());
|
|
}
|