2025-05-07 19:21:51 +02:00
|
|
|
/*
|
|
|
|
|
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
|
|
|
|
|
*/
|
|
|
|
|
|
2025-04-19 15:46:26 +02:00
|
|
|
module;
|
|
|
|
|
|
|
|
|
|
#include <vulkan/vulkan.h>
|
|
|
|
|
#include <vulkan/vulkan_wayland.h>
|
|
|
|
|
#include <vulkan/vk_enum_string_helper.h>
|
|
|
|
|
|
|
|
|
|
#define GET_EXTENSION_FUNCTION(_id) ((PFN_##_id)(vkGetInstanceProcAddr(instance, #_id)))
|
|
|
|
|
|
2025-11-16 15:32:11 +01:00
|
|
|
module Crafter.Graphics:VulkanDevice_impl;
|
|
|
|
|
import :VulkanDevice;
|
|
|
|
|
|
2025-04-19 15:46:26 +02:00
|
|
|
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",
|
2025-04-19 23:59:27 +02:00
|
|
|
"VK_KHR_shader_float_controls",
|
|
|
|
|
"VK_KHR_dynamic_rendering"
|
2025-04-19 15:46:26 +02:00
|
|
|
};
|
|
|
|
|
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<VkLayerProperties> 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<VkPhysicalDevice> 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<VkQueueFamilyProperties> 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;
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-04-19 23:59:27 +02:00
|
|
|
|
2025-04-19 15:46:26 +02:00
|
|
|
|
|
|
|
|
float priority = 1;
|
|
|
|
|
|
|
|
|
|
VkDeviceQueueCreateInfo queueCreateInfo = {};
|
|
|
|
|
queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
|
|
|
|
|
queueCreateInfo.queueFamilyIndex = queueFamilyIndex;
|
|
|
|
|
queueCreateInfo.queueCount = 1;
|
|
|
|
|
queueCreateInfo.pQueuePriorities = &priority;
|
|
|
|
|
|
2025-04-19 23:59:27 +02:00
|
|
|
VkPhysicalDeviceDynamicRenderingFeaturesKHR dynamicRenderingFeature = {VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_FEATURES_KHR};
|
|
|
|
|
dynamicRenderingFeature.dynamicRendering = VK_TRUE;
|
|
|
|
|
|
2025-04-19 15:46:26 +02:00
|
|
|
VkPhysicalDeviceMeshShaderFeaturesEXT ext_feature = {VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_FEATURES_EXT};
|
|
|
|
|
ext_feature.meshShader = VK_TRUE;
|
2025-04-19 23:59:27 +02:00
|
|
|
ext_feature.pNext = &dynamicRenderingFeature;
|
|
|
|
|
|
2025-04-19 15:46:26 +02:00
|
|
|
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<VkLayerProperties> 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));
|
2025-04-19 23:59:27 +02:00
|
|
|
|
|
|
|
|
vkGetPhysicalDeviceMemoryProperties(physDevice, &memoryProperties);
|
|
|
|
|
|
|
|
|
|
std::vector<VkFormat> formatList = {
|
|
|
|
|
VK_FORMAT_D32_SFLOAT,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
for (auto& format : formatList) {
|
|
|
|
|
VkFormatProperties formatProps;
|
|
|
|
|
vkGetPhysicalDeviceFormatProperties(physDevice, format, &formatProps);
|
|
|
|
|
if (formatProps.optimalTilingFeatures)
|
|
|
|
|
{
|
|
|
|
|
depthFormat = format;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
vkCmdDrawMeshTasksEXTProc = reinterpret_cast<PFN_vkCmdDrawMeshTasksEXT>(vkGetDeviceProcAddr(device, "vkCmdDrawMeshTasksEXT"));
|
|
|
|
|
vkCmdBeginRenderingKHRProc = reinterpret_cast<PFN_vkCmdBeginRenderingKHR>(vkGetInstanceProcAddr(instance, "vkCmdBeginRenderingKHR"));
|
|
|
|
|
vkCmdEndRenderingKHRProc = reinterpret_cast<PFN_vkCmdEndRenderingKHR>(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");
|
2025-04-19 15:46:26 +02:00
|
|
|
}
|