/* Crafter®.Graphics Copyright (C) 2025 Catcrafts® Catcrafts.net This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3.0 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ module; #include #include #include #include #include #include #include #include #include #include "VulkanInitializers.hpp" #include "VulkanBuffer.h" #define GET_EXTENSION_FUNCTION(_id) ((PFN_##_id)(vkGetInstanceProcAddr(instance, #_id))) module Crafter.Graphics; using namespace Crafter; const char* const instanceExtensionNames[] = { "VK_EXT_debug_utils", "VK_KHR_surface", "VK_KHR_wayland_surface" }; const char* const deviceExtensionNames[] = { "VK_KHR_swapchain", "VK_KHR_spirv_1_4", "VK_EXT_mesh_shader", "VK_KHR_shader_float_controls", "VK_KHR_dynamic_rendering" }; const char* const layerNames[] = { "VK_LAYER_KHRONOS_validation" }; void VulkanDevice::CHECK_VK_RESULT(VkResult result) { if (result != VK_SUCCESS) { throw std::runtime_error(string_VkResult(result)); } } VkBool32 onError(VkDebugUtilsMessageSeverityFlagBitsEXT severity, VkDebugUtilsMessageTypeFlagsEXT type, const VkDebugUtilsMessengerCallbackDataEXT* callbackData, void* userData) { printf("Vulkan "); switch (type) { case VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT : printf("general "); break; case VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT : printf("validation "); break; case VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT : printf("performance "); break; } switch (severity) { case VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT : printf("(verbose): "); break; default : case VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT : printf("(info): "); break; case VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT : printf("(warning): "); break; case VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT : printf("(error): "); break; } printf("%s\n", callbackData->pMessage); return 0; } void VulkanDevice::CreateDevice() { VkApplicationInfo app{VK_STRUCTURE_TYPE_APPLICATION_INFO}; app.pApplicationName = ""; app.pEngineName = "Crafter.Graphics"; app.apiVersion = VK_MAKE_VERSION(1, 4, 0); VkInstanceCreateInfo instanceCreateInfo = {}; instanceCreateInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; instanceCreateInfo.pApplicationInfo = &app; instanceCreateInfo.enabledExtensionCount = sizeof(instanceExtensionNames) / sizeof(const char*); instanceCreateInfo.ppEnabledExtensionNames = instanceExtensionNames; size_t foundInstanceLayers = 0; std::uint32_t instanceLayerCount; CHECK_VK_RESULT(vkEnumerateInstanceLayerProperties(&instanceLayerCount, NULL)); std::vector instanceLayerProperties(instanceLayerCount); CHECK_VK_RESULT(vkEnumerateInstanceLayerProperties(&instanceLayerCount, instanceLayerProperties.data())); for (uint32_t i = 0; i < instanceLayerCount; i++) { for (size_t j = 0; j < sizeof(layerNames) / sizeof(const char*); j++) { if (std::strcmp(instanceLayerProperties[i].layerName, layerNames[j]) == 0) { foundInstanceLayers++; } } } if (foundInstanceLayers >= sizeof(layerNames) / sizeof(const char*)) { instanceCreateInfo.enabledLayerCount = sizeof(layerNames) / sizeof(const char*); instanceCreateInfo.ppEnabledLayerNames = layerNames; } CHECK_VK_RESULT(vkCreateInstance(&instanceCreateInfo, NULL, &instance)); VkDebugUtilsMessengerCreateInfoEXT debugUtilsMessengerCreateInfo = {}; debugUtilsMessengerCreateInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT; debugUtilsMessengerCreateInfo.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT; debugUtilsMessengerCreateInfo.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; debugUtilsMessengerCreateInfo.pfnUserCallback = onError; CHECK_VK_RESULT(GET_EXTENSION_FUNCTION(vkCreateDebugUtilsMessengerEXT)(instance, &debugUtilsMessengerCreateInfo, NULL, &debugMessenger)); uint32_t physDeviceCount; vkEnumeratePhysicalDevices(instance, &physDeviceCount, NULL); std::vector physDevices(physDeviceCount); vkEnumeratePhysicalDevices(instance, &physDeviceCount, physDevices.data()); uint32_t bestScore = 0; for (uint32_t i = 0; i < physDeviceCount; i++) { VkPhysicalDevice device = physDevices[i]; VkPhysicalDeviceProperties properties; vkGetPhysicalDeviceProperties(device, &properties); uint32_t score; switch (properties.deviceType) { default : continue; case VK_PHYSICAL_DEVICE_TYPE_OTHER : score = 1; break; case VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU : score = 4; break; case VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU : score = 5; break; case VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU : score = 3; break; case VK_PHYSICAL_DEVICE_TYPE_CPU : score = 2; break; } if (score > bestScore) { physDevice = device; bestScore = score; } } uint32_t queueFamilyCount; vkGetPhysicalDeviceQueueFamilyProperties(physDevice, &queueFamilyCount, NULL); std::vector queueFamilies(queueFamilyCount); vkGetPhysicalDeviceQueueFamilyProperties(physDevice, &queueFamilyCount, queueFamilies.data()); for (uint32_t i = 0; i < queueFamilyCount; i++) { if (queueFamilies[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) { queueFamilyIndex = i; break; } } float priority = 1; VkDeviceQueueCreateInfo queueCreateInfo = {}; queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; queueCreateInfo.queueFamilyIndex = queueFamilyIndex; queueCreateInfo.queueCount = 1; queueCreateInfo.pQueuePriorities = &priority; VkPhysicalDeviceDynamicRenderingFeaturesKHR dynamicRenderingFeature = {VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_FEATURES_KHR}; dynamicRenderingFeature.dynamicRendering = VK_TRUE; VkPhysicalDeviceMeshShaderFeaturesEXT ext_feature = {VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_FEATURES_EXT}; ext_feature.meshShader = VK_TRUE; ext_feature.pNext = &dynamicRenderingFeature; VkPhysicalDeviceFeatures2 physical_features2 = {VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2}; physical_features2.pNext = &ext_feature; VkDeviceCreateInfo deviceCreateInfo = {}; deviceCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; deviceCreateInfo.queueCreateInfoCount = 1; deviceCreateInfo.pQueueCreateInfos = &queueCreateInfo; deviceCreateInfo.enabledExtensionCount = sizeof(deviceExtensionNames) / sizeof(const char*); deviceCreateInfo.ppEnabledExtensionNames = deviceExtensionNames; deviceCreateInfo.pNext = &physical_features2; uint32_t deviceLayerCount; CHECK_VK_RESULT(vkEnumerateDeviceLayerProperties(physDevice, &deviceLayerCount, NULL)); std::vector deviceLayerProperties(deviceLayerCount); CHECK_VK_RESULT(vkEnumerateDeviceLayerProperties(physDevice, &deviceLayerCount, deviceLayerProperties.data())); size_t foundDeviceLayers = 0; for (uint32_t i = 0; i < deviceLayerCount; i++) { for (size_t j = 0; j < sizeof(layerNames) / sizeof(const char*); j++) { if (strcmp(deviceLayerProperties[i].layerName, layerNames[j]) == 0) { foundDeviceLayers++; } } } if (foundDeviceLayers >= sizeof(layerNames) / sizeof(const char*)) { deviceCreateInfo.enabledLayerCount = sizeof(layerNames) / sizeof(const char*); deviceCreateInfo.ppEnabledLayerNames = layerNames; } CHECK_VK_RESULT(vkCreateDevice(physDevice, &deviceCreateInfo, NULL, &device)); vkGetDeviceQueue(device, queueFamilyIndex, 0, &queue); VkCommandPoolCreateInfo commandPoolcreateInfo = {}; commandPoolcreateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; commandPoolcreateInfo.queueFamilyIndex = queueFamilyIndex; commandPoolcreateInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; CHECK_VK_RESULT(vkCreateCommandPool(device, &commandPoolcreateInfo, NULL, &commandPool)); vkGetPhysicalDeviceMemoryProperties(physDevice, &memoryProperties); std::vector formatList = { VK_FORMAT_D32_SFLOAT, }; for (auto& format : formatList) { VkFormatProperties formatProps; vkGetPhysicalDeviceFormatProperties(physDevice, format, &formatProps); if (formatProps.optimalTilingFeatures) { depthFormat = format; break; } } vkCmdDrawMeshTasksEXTProc = reinterpret_cast(vkGetDeviceProcAddr(device, "vkCmdDrawMeshTasksEXT")); vkCmdBeginRenderingKHRProc = reinterpret_cast(vkGetInstanceProcAddr(instance, "vkCmdBeginRenderingKHR")); vkCmdEndRenderingKHRProc = reinterpret_cast(vkGetInstanceProcAddr(instance, "vkCmdEndRenderingKHR")); } std::uint32_t VulkanDevice::GetMemoryType(uint32_t typeBits, VkMemoryPropertyFlags properties) { for (uint32_t i = 0; i < memoryProperties.memoryTypeCount; i++) { if ((typeBits & 1) == 1) { if ((memoryProperties.memoryTypes[i].propertyFlags & properties) == properties) { return i; } } typeBits >>= 1; } throw std::runtime_error("Could not find a matching memory type"); }