250 lines
8.4 KiB
C++
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);
|
|
}
|