#define IMPORT_CORE #include "core/VulkanWrapper.h" #define GLFW_INCLUDE_VULKAN #include #include #include #include #include #include typedef struct { VkInstance instance; VkPhysicalDevice physicalDevice; VkDevice device; } VulkanData; static VulkanData vk = {0}; #define VK_ERROR_CASE(error) \ case error: return #error static const char* getVulkanErrorString(VkResult r) { switch(r) { VK_ERROR_CASE(VK_ERROR_OUT_OF_HOST_MEMORY); VK_ERROR_CASE(VK_ERROR_OUT_OF_DEVICE_MEMORY); VK_ERROR_CASE(VK_ERROR_INITIALIZATION_FAILED); VK_ERROR_CASE(VK_ERROR_LAYER_NOT_PRESENT); VK_ERROR_CASE(VK_ERROR_EXTENSION_NOT_PRESENT); VK_ERROR_CASE(VK_ERROR_INCOMPATIBLE_DRIVER); default: return "unknown"; } } #define VK_ASSERT(a) \ do { \ VkResult vkResult = (a); \ if(vkResult != VK_SUCCESS) { \ printf("Vulkan error at [%s:%d]: %s\n", \ getShortFileName(__FILE__), __LINE__, \ getVulkanErrorString(vkResult)); \ return true; \ } \ } while(false) static bool initInstance() { VkApplicationInfo i = {.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO, .pApplicationName = "Vulkan", .applicationVersion = VK_MAKE_VERSION(1, 0, 0), .pEngineName = "Kajetan", .engineVersion = VK_MAKE_VERSION(0, 0, 1), .apiVersion = VK_API_VERSION_1_1}; VkInstanceCreateInfo ci = { .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, .pApplicationInfo = &i, .enabledLayerCount = 1, .ppEnabledLayerNames = (const char*[]){"VK_LAYER_KHRONOS_validation"}, .enabledExtensionCount = 4, .ppEnabledExtensionNames = (const char*[]){"VK_KHR_surface", "VK_KHR_xcb_surface", VK_EXT_DEBUG_UTILS_EXTENSION_NAME, VK_EXT_DEBUG_REPORT_EXTENSION_NAME}}; VK_ASSERT(vkCreateInstance(&ci, nullptr, &vk.instance)); return false; } static bool choosePhysicalDevice(VkPhysicalDevice* devices, u32 amount) { VK_ASSERT(vkEnumeratePhysicalDevices(vk.instance, &amount, devices)); int bestPoints = 0; LOG_INFO("Found %u devices", amount); for(u32 i = 0; i < amount; i++) { int points = 0; VkPhysicalDeviceProperties p; vkGetPhysicalDeviceProperties(devices[i], &p); if(p.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU) { points += 100; } else if(p.deviceType == VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU) { points += 50; } else if(p.deviceType == VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU) { points += 20; } if(points > bestPoints) { bestPoints = points; vk.physicalDevice = devices[i]; LOG_INFO("Best Device: %s", p.deviceName); } } return bestPoints == 0; } static bool initPhysicalDevice() { u32 deviceCount = 0; VK_ASSERT(vkEnumeratePhysicalDevices(vk.instance, &deviceCount, nullptr)); if(deviceCount == 0) { LOG_ERROR("No physical device was found"); return true; } VkPhysicalDevice* devices = cAllocate(sizeof(VkPhysicalDevice) * deviceCount); bool r = choosePhysicalDevice(devices, deviceCount); cFree(devices); return r; } static u32 findQueueFamilies(VkPhysicalDevice pd, VkQueueFlags flags) { u32 count = 0; vkGetPhysicalDeviceQueueFamilyProperties(pd, &count, nullptr); VkQueueFamilyProperties* properties = cAllocate(sizeof(VkQueueFamilyProperties) * count); vkGetPhysicalDeviceQueueFamilyProperties(pd, &count, properties); for(u32 i = 0; i < count; i++) { if(properties[i].queueCount != 0 && (properties[i].queueFlags & flags) == flags) { cFree(properties); return i; } } cFree(properties); return (u32)-1; } static bool initDevice() { VkPhysicalDeviceFeatures deviceFeatures = {0}; vkGetPhysicalDeviceFeatures(vk.physicalDevice, &deviceFeatures); u32 graphicsFamily = findQueueFamilies(vk.physicalDevice, VK_QUEUE_GRAPHICS_BIT); if(graphicsFamily == (u32)-1) { LOG_ERROR("Cannot find queue family"); return true; } VkDeviceQueueCreateInfo dqInfo = { .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, .queueFamilyIndex = graphicsFamily, .queueCount = 1, .pQueuePriorities = (float[]){1.0f}}; VkDeviceCreateInfo deviceCreateInfo = { .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, .queueCreateInfoCount = 1, .pQueueCreateInfos = &dqInfo, .enabledExtensionCount = 1, .ppEnabledExtensionNames = (const char*[]){VK_KHR_SWAPCHAIN_EXTENSION_NAME}, .pEnabledFeatures = &deviceFeatures}; VK_ASSERT(vkCreateDevice(vk.physicalDevice, &deviceCreateInfo, nullptr, &vk.device)); return false; } bool coreInitVulkan() { return initInstance() || initPhysicalDevice() || initDevice(); } void coreDestroyVulkan(void) { vkDestroyDevice(vk.device, nullptr); vkDestroyInstance(vk.instance, nullptr); }