/
redgpu
/
ezEngine
Обзор
Документация
Войти
/
redgpu
/
ezEngine
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
Безопасность
dev
Code/ThirdParty/Jolt/Compute/VK/ComputeSystemVKImpl.cpp
398 строк
15 KB
Jan Krassnigg
Updated Jolt (#1965)
16 июн 2026, 10:48
Не верифицирован
16 июн 2026, 10:48
2c0d62b
Код
Авторство
О чём код?
// Jolt Physics Library (https://github.com/jrouwe/JoltPhysics) // SPDX-FileCopyrightText: 2025 Jorrit Rouwe // SPDX-License-Identifier: MIT #include <Jolt/Jolt.h> #ifdef JPH_USE_VK #include <Jolt/Compute/VK/ComputeSystemVKImpl.h> #include <Jolt/Core/QuickSort.h> #include <Jolt/Core/IncludeWindows.h> #if defined(JPH_PLATFORM_LINUX) || defined(JPH_PLATFORM_ANDROID) ||defined(JPH_PLATFORM_MACOS) #include <dlfcn.h> #endif JPH_NAMESPACE_BEGIN JPH_IMPLEMENT_RTTI_VIRTUAL(ComputeSystemVKImpl) { JPH_ADD_BASE_CLASS(ComputeSystemVKImpl, ComputeSystemVKWithAllocator) } #ifdef JPH_DEBUG static VKAPI_ATTR VkBool32 VKAPI_CALL sVulkanDebugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT inSeverity, [[maybe_unused]] VkDebugUtilsMessageTypeFlagsEXT inType, const VkDebugUtilsMessengerCallbackDataEXT *inCallbackData, [[maybe_unused]] void *inUserData) { if (inSeverity & (VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT)) Trace("VK: %s", inCallbackData->pMessage); JPH_ASSERT((inSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) == 0); return VK_FALSE; } #endif // JPH_DEBUG ComputeSystemVKImpl::~ComputeSystemVKImpl() { ComputeSystemVK::Shutdown(); if (mDevice != VK_NULL_HANDLE && mVkDestroyDevice != nullptr) mVkDestroyDevice(mDevice, nullptr); #ifdef JPH_DEBUG if (mInstance != VK_NULL_HANDLE && mDebugMessenger != VK_NULL_HANDLE && mVkDestroyDebugUtilsMessengerEXT != nullptr) mVkDestroyDebugUtilsMessengerEXT(mInstance, mDebugMessenger, nullptr); #endif if (mInstance != VK_NULL_HANDLE && mVkDestroyInstance != nullptr) mVkDestroyInstance(mInstance, nullptr); } bool ComputeSystemVKImpl::Initialize(ComputeSystemResult &outResult) { #ifdef JPH_PLATFORM_WINDOWS HMODULE module = LoadLibraryA("vulkan-1.dll"); if (!module) { outResult.SetError("Failed to load vulkan-1.dll"); return false; } mVkGetInstanceProcAddr = reinterpret_cast<PFN_vkGetInstanceProcAddr>(reinterpret_cast<void *>(GetProcAddress(module, "vkGetInstanceProcAddr"))); #elif defined(JPH_PLATFORM_LINUX) || defined(JPH_PLATFORM_ANDROID) void *library = dlopen("libvulkan.so.1", RTLD_NOW | RTLD_LOCAL); if (!library) library = dlopen("libvulkan.so", RTLD_NOW | RTLD_LOCAL); if (!library) { outResult.SetError("Failed to load libvulkan.so.1 or libvulkan.so"); return false; } mVkGetInstanceProcAddr = reinterpret_cast<PFN_vkGetInstanceProcAddr>(dlsym(library, "vkGetInstanceProcAddr")); #elif defined(JPH_PLATFORM_MACOS) void *library = dlopen("libvulkan.1.dylib", RTLD_NOW | RTLD_LOCAL); if (!library) library = dlopen("libvulkan.dylib", RTLD_NOW | RTLD_LOCAL); if (!library) { outResult.SetError("Failed to load libvulkan.1.dylib or libvulkan.dylib"); return false; } mVkGetInstanceProcAddr = reinterpret_cast<PFN_vkGetInstanceProcAddr>(dlsym(library, "vkGetInstanceProcAddr")); #else #error "Unsupported platform" #endif // Check vkGetInstanceProcAddr if (mVkGetInstanceProcAddr == nullptr) { outResult.SetError("Failed to get vkGetInstanceProcAddr"); return false; } // Required instance extensions Array<const char *> required_instance_extensions; required_instance_extensions.push_back(VK_KHR_SURFACE_EXTENSION_NAME); required_instance_extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); #ifdef JPH_PLATFORM_MACOS required_instance_extensions.push_back("VK_KHR_portability_enumeration"); required_instance_extensions.push_back("VK_KHR_get_physical_device_properties2"); #endif GetInstanceExtensions(required_instance_extensions); // Required device extensions Array<const char *> required_device_extensions; required_device_extensions.push_back(VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME); #ifdef JPH_PLATFORM_MACOS required_device_extensions.push_back("VK_KHR_portability_subset"); // VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME #endif GetDeviceExtensions(required_device_extensions); // Load pre-instance Vulkan functions #define JPH_LOAD_VK_PRE_INST(name) mVk##name = reinterpret_cast<PFN_vk##name>(reinterpret_cast<void *>(mVkGetInstanceProcAddr(nullptr, "vk" #name))); JPH_ASSERT(mVk##name != nullptr) JPH_LOAD_VK_PRE_INST(CreateInstance); JPH_LOAD_VK_PRE_INST(EnumerateInstanceExtensionProperties); JPH_LOAD_VK_PRE_INST(EnumerateInstanceLayerProperties); #undef JPH_LOAD_VK_PRE_INST // Query supported instance extensions uint32 instance_extension_count = 0; if (VKFailed(mVkEnumerateInstanceExtensionProperties(nullptr, &instance_extension_count, nullptr), outResult)) return false; Array<VkExtensionProperties> instance_extensions; instance_extensions.resize(instance_extension_count); if (VKFailed(mVkEnumerateInstanceExtensionProperties(nullptr, &instance_extension_count, instance_extensions.data()), outResult)) return false; // Query supported validation layers uint32 validation_layer_count; mVkEnumerateInstanceLayerProperties(&validation_layer_count, nullptr); Array<VkLayerProperties> validation_layers(validation_layer_count); mVkEnumerateInstanceLayerProperties(&validation_layer_count, validation_layers.data()); VkApplicationInfo app_info = {}; app_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; app_info.apiVersion = VK_API_VERSION_1_1; // Create Vulkan instance VkInstanceCreateInfo instance_create_info = {}; instance_create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; #ifdef JPH_PLATFORM_MACOS instance_create_info.flags = VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR; #endif instance_create_info.pApplicationInfo = &app_info; #ifdef JPH_DEBUG // Enable validation layer if supported const char *desired_validation_layers[] = { "VK_LAYER_KHRONOS_validation" }; for (const VkLayerProperties &p : validation_layers) if (strcmp(desired_validation_layers[0], p.layerName) == 0) { instance_create_info.enabledLayerCount = 1; instance_create_info.ppEnabledLayerNames = desired_validation_layers; break; } // Setup debug messenger callback if the extension is supported VkDebugUtilsMessengerCreateInfoEXT messenger_create_info = {}; for (const VkExtensionProperties &ext : instance_extensions) if (strcmp(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, ext.extensionName) == 0) { messenger_create_info.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT; messenger_create_info.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT; messenger_create_info.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; messenger_create_info.pfnUserCallback = sVulkanDebugCallback; instance_create_info.pNext = &messenger_create_info; required_instance_extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); break; } #endif instance_create_info.enabledExtensionCount = (uint32)required_instance_extensions.size(); instance_create_info.ppEnabledExtensionNames = required_instance_extensions.data(); if (VKFailed(mVkCreateInstance(&instance_create_info, nullptr, &mInstance), outResult)) return false; // Load instance-level Vulkan functions #define JPH_LOAD_VK_INST(name) mVk##name = reinterpret_cast<PFN_vk##name>(reinterpret_cast<void *>(mVkGetInstanceProcAddr(mInstance, "vk" #name))); JPH_ASSERT(mVk##name != nullptr) JPH_LOAD_VK_INST(CreateDevice); JPH_LOAD_VK_INST(DestroyInstance); JPH_LOAD_VK_INST(EnumerateDeviceExtensionProperties); JPH_LOAD_VK_INST(EnumeratePhysicalDevices); JPH_LOAD_VK_INST(GetPhysicalDeviceProperties); JPH_LOAD_VK_INST(GetPhysicalDeviceQueueFamilyProperties); #undef JPH_LOAD_VK_INST // Get vkGetDeviceProcAddr mVkGetDeviceProcAddr = reinterpret_cast<PFN_vkGetDeviceProcAddr>(reinterpret_cast<void *>(mVkGetInstanceProcAddr(mInstance, "vkGetDeviceProcAddr"))); if (mVkGetDeviceProcAddr == nullptr) { outResult.SetError("Failed to get vkGetDeviceProcAddr"); return false; } #ifdef JPH_DEBUG // Finalize debug messenger callback PFN_vkCreateDebugUtilsMessengerEXT vkCreateDebugUtilsMessengerEXT = (PFN_vkCreateDebugUtilsMessengerEXT)(std::uintptr_t)mVkGetInstanceProcAddr(mInstance, "vkCreateDebugUtilsMessengerEXT"); mVkDestroyDebugUtilsMessengerEXT = reinterpret_cast<PFN_vkDestroyDebugUtilsMessengerEXT>(reinterpret_cast<void *>(mVkGetInstanceProcAddr(mInstance, "vkDestroyDebugUtilsMessengerEXT"))); if (vkCreateDebugUtilsMessengerEXT != nullptr && VKFailed(vkCreateDebugUtilsMessengerEXT(mInstance, &messenger_create_info, nullptr, &mDebugMessenger), outResult)) return false; #endif // Notify that instance has been created OnInstanceCreated(); // Select device uint32 device_count = 0; if (VKFailed(mVkEnumeratePhysicalDevices(mInstance, &device_count, nullptr), outResult)) return false; Array<VkPhysicalDevice> devices; devices.resize(device_count); if (VKFailed(mVkEnumeratePhysicalDevices(mInstance, &device_count, devices.data()), outResult)) return false; struct Device { VkPhysicalDevice mPhysicalDevice; String mName; VkSurfaceFormatKHR mFormat; uint32 mGraphicsQueueIndex; uint32 mPresentQueueIndex; uint32 mComputeQueueIndex; int mScore; }; Array<Device> available_devices; for (VkPhysicalDevice device : devices) { // Get device properties VkPhysicalDeviceProperties properties; mVkGetPhysicalDeviceProperties(device, &properties); // Test if it is an appropriate type int score = 0; switch (properties.deviceType) { case VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU: score = 30; break; case VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU: score = 20; break; case VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU: score = 10; break; case VK_PHYSICAL_DEVICE_TYPE_CPU: score = 5; break; case VK_PHYSICAL_DEVICE_TYPE_OTHER: case VK_PHYSICAL_DEVICE_TYPE_MAX_ENUM: continue; } // Check if the device supports all our required extensions uint32 device_extension_count; mVkEnumerateDeviceExtensionProperties(device, nullptr, &device_extension_count, nullptr); Array<VkExtensionProperties> available_extensions; available_extensions.resize(device_extension_count); mVkEnumerateDeviceExtensionProperties(device, nullptr, &device_extension_count, available_extensions.data()); int found_extensions = 0; for (const char *required_device_extension : required_device_extensions) for (const VkExtensionProperties &ext : available_extensions) if (strcmp(required_device_extension, ext.extensionName) == 0) { found_extensions++; break; } if (found_extensions != int(required_device_extensions.size())) continue; // Find the right queues uint32 queue_family_count = 0; mVkGetPhysicalDeviceQueueFamilyProperties(device, &queue_family_count, nullptr); Array<VkQueueFamilyProperties> queue_families; queue_families.resize(queue_family_count); mVkGetPhysicalDeviceQueueFamilyProperties(device, &queue_family_count, queue_families.data()); uint32 graphics_queue = ~uint32(0); uint32 present_queue = ~uint32(0); uint32 compute_queue = ~uint32(0); for (uint32 i = 0; i < uint32(queue_families.size()); ++i) { if (queue_families[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) { graphics_queue = i; if (queue_families[i].queueFlags & VK_QUEUE_COMPUTE_BIT) compute_queue = i; } if (HasPresentSupport(device, i)) present_queue = i; if (graphics_queue != ~uint32(0) && present_queue != ~uint32(0) && compute_queue != ~uint32(0)) break; } if (graphics_queue == ~uint32(0) || present_queue == ~uint32(0) || compute_queue == ~uint32(0)) continue; // Select surface format VkSurfaceFormatKHR selected_format = SelectFormat(device); if (selected_format.format == VK_FORMAT_UNDEFINED) continue; // Add the device available_devices.push_back({ device, properties.deviceName, selected_format, graphics_queue, present_queue, compute_queue, score }); } if (available_devices.empty()) { outResult.SetError("No suitable Vulkan device found"); return false; } // Sort the devices by score QuickSort(available_devices.begin(), available_devices.end(), [](const Device &inLHS, const Device &inRHS) { return inLHS.mScore > inRHS.mScore; }); const Device &selected_device = available_devices[0]; // Create device float queue_priority = 1.0f; VkDeviceQueueCreateInfo queue_create_info[3] = {}; for (VkDeviceQueueCreateInfo &q : queue_create_info) { q.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; q.queueCount = 1; q.pQueuePriorities = &queue_priority; } uint32 num_queues = 0; queue_create_info[num_queues++].queueFamilyIndex = selected_device.mGraphicsQueueIndex; bool found = false; for (uint32 i = 0; i < num_queues; ++i) if (queue_create_info[i].queueFamilyIndex == selected_device.mPresentQueueIndex) { found = true; break; } if (!found) queue_create_info[num_queues++].queueFamilyIndex = selected_device.mPresentQueueIndex; found = false; for (uint32 i = 0; i < num_queues; ++i) if (queue_create_info[i].queueFamilyIndex == selected_device.mComputeQueueIndex) { found = true; break; } if (!found) queue_create_info[num_queues++].queueFamilyIndex = selected_device.mComputeQueueIndex; VkPhysicalDeviceScalarBlockLayoutFeatures enable_scalar_block = {}; enable_scalar_block.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SCALAR_BLOCK_LAYOUT_FEATURES; enable_scalar_block.scalarBlockLayout = VK_TRUE; VkPhysicalDeviceFeatures2 enabled_features2 = {}; enabled_features2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; GetEnabledFeatures(enabled_features2); enable_scalar_block.pNext = enabled_features2.pNext; enabled_features2.pNext = &enable_scalar_block; VkDeviceCreateInfo device_create_info = {}; device_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; device_create_info.queueCreateInfoCount = num_queues; device_create_info.pQueueCreateInfos = queue_create_info; device_create_info.enabledExtensionCount = uint32(required_device_extensions.size()); device_create_info.ppEnabledExtensionNames = required_device_extensions.data(); device_create_info.pNext = &enabled_features2; device_create_info.pEnabledFeatures = nullptr; VkDevice device = VK_NULL_HANDLE; if (VKFailed(mVkCreateDevice(selected_device.mPhysicalDevice, &device_create_info, nullptr, &device), outResult)) return false; // Store selected format mSelectedFormat = selected_device.mFormat; // Initialize the compute system (loads device-level functions) if (!ComputeSystemVKWithAllocator::Initialize(mInstance, selected_device.mPhysicalDevice, mVkGetInstanceProcAddr, mVkGetDeviceProcAddr, device, selected_device.mComputeQueueIndex, outResult)) return false; // Get the queues mGraphicsQueueIndex = selected_device.mGraphicsQueueIndex; mPresentQueueIndex = selected_device.mPresentQueueIndex; mVkGetDeviceQueue(mDevice, mGraphicsQueueIndex, 0, &mGraphicsQueue); mVkGetDeviceQueue(mDevice, mPresentQueueIndex, 0, &mPresentQueue); return true; } ComputeSystemResult CreateComputeSystemVK() { ComputeSystemResult result; Ref<ComputeSystemVKImpl> compute = new ComputeSystemVKImpl; if (!compute->Initialize(result)) return result; result.Set(compute.GetPtr()); return result; } JPH_NAMESPACE_END #endif // JPH_USE_VK