v/renderer/init.cpp

250 lines
8.4 KiB
C++

//
// Created by Vicente Ferrari Smith on 12.02.26.
//
#include "init.h"
#include <print>
#include <vector>
VKAPI_ATTR VkBool32 VKAPI_CALL debugCallback(
VkDebugUtilsMessageSeverityFlagBitsEXT severity,
VkDebugUtilsMessageTypeFlagsEXT type,
const VkDebugUtilsMessengerCallbackDataEXT* callbackData,
void* userData) {
const char* severityStr = "UNKNOWN";
if (severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT)
severityStr = "VERBOSE";
else if (severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT)
severityStr = "INFO";
else if (severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT)
severityStr = "WARNING";
else if (severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT)
severityStr = "ERROR";
const char* typeStr = "";
if (type & VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT)
typeStr = "GENERAL";
else if (type & VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT)
typeStr = "VALIDATION";
else if (type & VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT)
typeStr = "PERFORMANCE";
std::fprintf(stderr, "\n[VULKAN %s][%s]\n%s\n",
severityStr,
typeStr,
callbackData->pMessage);
// Print associated objects (very useful on MoltenVK)
for (uint32_t i = 0; i < callbackData->objectCount; i++) {
const VkDebugUtilsObjectNameInfoEXT& obj =
callbackData->pObjects[i];
std::fprintf(stderr,
" Object %u: type=%d handle=0x%llx name=%s\n",
i,
obj.objectType,
static_cast<unsigned long long>(obj.objectHandle),
obj.pObjectName ? obj.pObjectName : "null");
}
return VK_FALSE; // Do not abort Vulkan call
}
int createInstance(GLFWwindow *window) {
volkInitialize();
uint32_t extensions_count;
const char** extensions = glfwGetRequiredInstanceExtensions(&extensions_count);
std::vector<const char*> instance_exts;
instance_exts.reserve(extensions_count + 1);
// Copy GLFW-required extensions
for (uint32_t i = 0; i < extensions_count; i++) {
instance_exts.push_back(extensions[i]);
}
// Append portability enumeration (MANDATORY on macOS)
instance_exts.push_back(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME);
instance_exts.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
for (auto& ext : instance_exts) {
std::print("extension {}\n", ext);
}
constexpr VkApplicationInfo app{
.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
.apiVersion = VK_API_VERSION_1_4,
};
const char* layers[] = {
"VK_LAYER_KHRONOS_validation"
};
VkDebugUtilsMessengerCreateInfoEXT dbg{};
dbg.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT;
dbg.messageSeverity =
VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT |
VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;
dbg.messageType =
VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT |
VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT |
VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;
dbg.pfnUserCallback = debugCallback;
const VkInstanceCreateInfo ici{
.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
.pNext = &dbg,
.flags = VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR,
.pApplicationInfo = &app,
.enabledLayerCount = 1,
.ppEnabledLayerNames = layers,
.enabledExtensionCount = static_cast<uint32_t>(instance_exts.size()),
.ppEnabledExtensionNames = instance_exts.data(),
};
VkResult res = vkCreateInstance(&ici, nullptr, &instance);
if (res != VK_SUCCESS) {
printf("vkCreateInstance failed: %d\n", res);
return -1;
}
volkLoadInstance(instance);
VkDebugUtilsMessengerEXT messenger;
vkCreateDebugUtilsMessengerEXT(instance, &dbg, nullptr, &messenger);
uint32_t layerCount = 0;
vkEnumerateInstanceLayerProperties(&layerCount, nullptr);
return 0;
}
void createSurface(GLFWwindow *window) {
glfwCreateWindowSurface(instance, window, nullptr, &surface);
}
void createDevice() {
uint32_t deviceCount = 0;
uint32_t res = vkEnumeratePhysicalDevices(instance, &deviceCount, nullptr);
if (res != VK_SUCCESS || deviceCount == 0) {
printf("vkEnumeratePhysicalDevices failed or found no devices (%d)\n", res);
}
std::vector<VkPhysicalDevice> devices(deviceCount);
vkEnumeratePhysicalDevices(instance, &deviceCount, devices.data());
printf("Found %u physical device(s)\n", deviceCount);
for (uint32_t i = 0; i < deviceCount; i++) {
VkPhysicalDeviceProperties props{};
vkGetPhysicalDeviceProperties(devices[i], &props);
printf("Device %u:\n", i);
printf(" Name: %s\n", props.deviceName);
printf(" Type: %u\n", props.deviceType);
printf(" API version: %u.%u.%u\n",
VK_VERSION_MAJOR(props.apiVersion),
VK_VERSION_MINOR(props.apiVersion),
VK_VERSION_PATCH(props.apiVersion));
}
physicalDevice = devices[0];
queueFamily = 0;
uint32_t qCount = 0;
vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &qCount, nullptr);
std::vector<VkQueueFamilyProperties> qprops(qCount);
vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &qCount, qprops.data());
for (uint32_t i = 0; i < qCount; i++) {
VkBool32 present = VK_FALSE;
vkGetPhysicalDeviceSurfaceSupportKHR(physicalDevice, i, surface, &present);
if ((qprops[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) && present) {
queueFamily = i;
break;
}
}
std::println("{}", queueFamily);
const char* devExts[] = {
VK_KHR_SWAPCHAIN_EXTENSION_NAME,
VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME,
VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME,
VK_EXT_EXTENDED_DYNAMIC_STATE_2_EXTENSION_NAME,
VK_EXT_EXTENDED_DYNAMIC_STATE_3_EXTENSION_NAME,
VK_KHR_SYNCHRONIZATION_2_EXTENSION_NAME,
"VK_KHR_portability_subset"
};
float prio = 1.0f;
VkDeviceQueueCreateInfo qci{
.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
.queueFamilyIndex = queueFamily,
.queueCount = 1,
.pQueuePriorities = &prio
};
VkPhysicalDeviceDescriptorIndexingFeatures indexingFeatures{
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES,
.pNext = nullptr,
.shaderSampledImageArrayNonUniformIndexing = VK_TRUE,
.descriptorBindingSampledImageUpdateAfterBind = VK_TRUE,
.descriptorBindingPartiallyBound = VK_TRUE,
.runtimeDescriptorArray = VK_TRUE
};
VkPhysicalDeviceTimelineSemaphoreFeatures timeline{
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES,
.pNext = &indexingFeatures,
.timelineSemaphore = VK_TRUE
};
VkPhysicalDeviceSynchronization2Features sync2{
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SYNCHRONIZATION_2_FEATURES,
.pNext = &timeline,
.synchronization2 = VK_TRUE
};
VkPhysicalDeviceDynamicRenderingFeatures dyn{
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_FEATURES,
.pNext = &sync2,
.dynamicRendering = VK_TRUE
};
const VkDeviceCreateInfo dci{
.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
.pNext = &dyn,
.queueCreateInfoCount = 1,
.pQueueCreateInfos = &qci,
.enabledExtensionCount = 7,
.ppEnabledExtensionNames = devExts
};
vkCreateDevice(physicalDevice, &dci, nullptr, &device);
volkLoadDevice(device);
vkGetDeviceQueue(device, queueFamily, 0, &graphics_queue);
VmaAllocatorCreateInfo allocatorCreateInfo = {
.flags = 0,
.physicalDevice = physicalDevice,
.device = device,
.preferredLargeHeapBlockSize = 0,
.pAllocationCallbacks = nullptr,
.pDeviceMemoryCallbacks = nullptr,
.pHeapSizeLimit = nullptr,
.pVulkanFunctions = nullptr,
.instance = instance,
.vulkanApiVersion = VK_API_VERSION_1_4,
.pTypeExternalMemoryHandleTypes = nullptr,
};
VmaVulkanFunctions vulkan_functions = {};
res = vmaImportVulkanFunctionsFromVolk(&allocatorCreateInfo, &vulkan_functions);
allocatorCreateInfo.pVulkanFunctions = &vulkan_functions;
res = vmaCreateAllocator(&allocatorCreateInfo, &allocator);
}