TODO 设备创建
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
project(mirai)
|
||||
|
||||
find_package(Vulkan REQUIRED)
|
||||
find_package(unofficial-vulkan-memory-allocator-hpp CONFIG REQUIRED)
|
||||
find_package(SDL3 CONFIG REQUIRED)
|
||||
find_package(harfbuzz CONFIG REQUIRED)
|
||||
find_package(Freetype CONFIG REQUIRED)
|
||||
@@ -26,6 +27,7 @@ target_link_libraries(${PROJECT_NAME} PUBLIC
|
||||
Eigen3::Eigen
|
||||
spdlog::spdlog
|
||||
fmt::fmt
|
||||
unofficial::VulkanMemoryAllocator-Hpp::VulkanMemoryAllocator-Hpp
|
||||
)
|
||||
target_link_directories(${PROJECT_NAME} PUBLIC ${Stb_INCLUDE_DIR})
|
||||
target_compile_definitions(${PROJECT_NAME} PUBLIC VULKAN_HPP_NO_EXCEPTIONS VULKAN_HPP_DISPATCH_LOADER_DYNAMIC=1)
|
||||
|
||||
@@ -1,25 +1,45 @@
|
||||
#pragma once
|
||||
#include "types/types.h"
|
||||
#include "resource_types.h"
|
||||
#include "core/object.h"
|
||||
#include "gpu_resource/resource_types.h"
|
||||
|
||||
#include <vulkan/vulkan.hpp>
|
||||
#include <vma/vk_mem_alloc.h>
|
||||
#include <vulkan-memory-allocator-hpp/vk_mem_alloc.hpp>
|
||||
|
||||
namespace mirai {
|
||||
/**
|
||||
* @brief GPU 分配信息
|
||||
*
|
||||
* 包含单个内存分配的详细信息
|
||||
*/
|
||||
struct allocation_info {
|
||||
// 分配的大小(字节)
|
||||
/// 分配的大小(字节)
|
||||
u64 size = 0;
|
||||
// 偏移量(字节)
|
||||
/// 分配的偏移量
|
||||
u64 offset = 0;
|
||||
// 设备内存句柄
|
||||
/// 设备内存句柄
|
||||
vk::DeviceMemory device_memory{};
|
||||
// 映射的内存指针
|
||||
void* mapped_ptr = nullptr;
|
||||
// 内存类型索引
|
||||
/// 映射的指针(如果已映射)
|
||||
void* mapped_data = nullptr;
|
||||
/// 内存类型索引
|
||||
u32 memory_type_index = 0;
|
||||
// 分配标志
|
||||
vk::MemoryPropertyFlags property_flags{};
|
||||
/// 是否为专用分配
|
||||
bool is_dedicated = false;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Buffer 创建信息
|
||||
*/
|
||||
struct buffer_create_info {
|
||||
/// Buffer 大小(字节)
|
||||
u64 size = 0;
|
||||
/// Buffer 用途
|
||||
buffer_usage usage = buffer_usage::vertex;
|
||||
/// 内存用途
|
||||
memory_usage mem_usage = memory_usage::gpu_only;
|
||||
/// 是否持久映射
|
||||
bool persistent_mapped = false;
|
||||
/// 调试名称
|
||||
std::string debug_name;
|
||||
};
|
||||
struct buffer_allocation_info {
|
||||
/// Buffer 大小(字节)
|
||||
@@ -41,12 +61,12 @@ namespace mirai {
|
||||
/// Vulkan Buffer 句柄
|
||||
vk::Buffer buffer{};
|
||||
/// VMA 分配句柄
|
||||
VmaAllocation allocation = VK_NULL_HANDLE;
|
||||
vma::Allocation allocation = VK_NULL_HANDLE;
|
||||
/// 分配信息
|
||||
allocation_info info;
|
||||
/// 是否有效
|
||||
[[nodiscard]] bool is_valid() const noexcept {
|
||||
return buffer && allocation != VK_NULL_HANDLE;
|
||||
return buffer && allocation;
|
||||
}
|
||||
};
|
||||
/**
|
||||
@@ -86,40 +106,13 @@ namespace mirai {
|
||||
/// Vulkan Image 句柄
|
||||
vk::Image image{};
|
||||
/// VMA 分配句柄
|
||||
VmaAllocation allocation = VK_NULL_HANDLE;
|
||||
vma::Allocation allocation = VK_NULL_HANDLE;
|
||||
/// 分配信息
|
||||
allocation_info info;
|
||||
/// 是否有效
|
||||
[[nodiscard]] bool is_valid() const noexcept {
|
||||
return image && allocation != VK_NULL_HANDLE;
|
||||
return image && allocation;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief GPU 分配器配置
|
||||
*/
|
||||
struct allocator_config {
|
||||
/// Vulkan 实例
|
||||
vk::Instance instance{};
|
||||
/// 物理设备
|
||||
vk::PhysicalDevice physical_device{};
|
||||
/// 逻辑设备
|
||||
vk::Device device{};
|
||||
/// Vulkan API 版本
|
||||
u32 vulkan_api_version = VK_API_VERSION_1_3;
|
||||
/// 是否启用 Buffer Device Address
|
||||
bool enable_buffer_device_address = true;
|
||||
/// 是否启用内存预算跟踪
|
||||
bool enable_memory_budget = true;
|
||||
/// 首选的大块分配大小(字节)
|
||||
u64 preferred_large_heap_block_size = 256 * 1024 * 1024; // 256 MB
|
||||
};
|
||||
|
||||
class vma_allocator : public object {
|
||||
MIRAI_OBJECT_TYPE_INFO(vma_allocator, object)
|
||||
|
||||
explicit vma_allocator(const allocator_config& config);
|
||||
~vma_allocator() override;
|
||||
|
||||
};
|
||||
}
|
||||
155
src/gpu_resource/allocator.cpp
Normal file
155
src/gpu_resource/allocator.cpp
Normal file
@@ -0,0 +1,155 @@
|
||||
#include "allocator.h"
|
||||
|
||||
#include "resource_types_vulkan.h"
|
||||
#include "core/logger.h"
|
||||
|
||||
#define VMA_IMPLEMENTATION
|
||||
#include <vma/vk_mem_alloc.h>
|
||||
#include <vulkan-memory-allocator-hpp/vk_mem_alloc.hpp>
|
||||
|
||||
namespace mirai {
|
||||
result_t<vma::Allocator> create_vma_allocator(const allocator_config& config) {
|
||||
// 假设你已经有了 instance, physicalDevice, device 和 dl (调度器)
|
||||
auto& d = config.disp;
|
||||
|
||||
// 1. 填充 VMA 需要的函数指针结构体
|
||||
vma::VulkanFunctions functions{};
|
||||
functions.vkGetInstanceProcAddr = d.vkGetInstanceProcAddr;
|
||||
functions.vkGetDeviceProcAddr = d.vkGetDeviceProcAddr;
|
||||
// 还可以填充其他具体函数,但在 Dynamic 模式下,主要给这两个入口,
|
||||
// VMA 会尝试自己获取,或者你需要把 d 里面的函数逐个填进去(视 VMA 版本而定)
|
||||
// 比较稳妥的做法是把 VMA 需要的核心函数都填上:
|
||||
functions.vkGetPhysicalDeviceProperties = d.vkGetPhysicalDeviceProperties;
|
||||
functions.vkGetPhysicalDeviceMemoryProperties = d.vkGetPhysicalDeviceMemoryProperties;
|
||||
functions.vkAllocateMemory = d.vkAllocateMemory;
|
||||
functions.vkFreeMemory = d.vkFreeMemory;
|
||||
functions.vkMapMemory = d.vkMapMemory;
|
||||
functions.vkUnmapMemory = d.vkUnmapMemory;
|
||||
functions.vkFlushMappedMemoryRanges = d.vkFlushMappedMemoryRanges;
|
||||
functions.vkInvalidateMappedMemoryRanges = d.vkInvalidateMappedMemoryRanges;
|
||||
functions.vkBindBufferMemory = d.vkBindBufferMemory;
|
||||
functions.vkBindImageMemory = d.vkBindImageMemory;
|
||||
functions.vkGetBufferMemoryRequirements = d.vkGetBufferMemoryRequirements;
|
||||
functions.vkGetImageMemoryRequirements = d.vkGetImageMemoryRequirements;
|
||||
functions.vkCreateBuffer = d.vkCreateBuffer;
|
||||
functions.vkDestroyBuffer = d.vkDestroyBuffer;
|
||||
functions.vkCreateImage = d.vkCreateImage;
|
||||
functions.vkDestroyImage = d.vkDestroyImage;
|
||||
functions.vkCmdCopyBuffer = d.vkCmdCopyBuffer;
|
||||
// 如果开启了 bufferDeviceAddress,还需要相关的函数...
|
||||
|
||||
// 2. 创建 Allocator
|
||||
vma::AllocatorCreateInfo allocator_info{};
|
||||
allocator_info.vulkanApiVersion = VK_API_VERSION_1_3;
|
||||
allocator_info.physicalDevice = config.physical_device;
|
||||
allocator_info.device = config.device;
|
||||
allocator_info.instance = config.instance;
|
||||
allocator_info.pVulkanFunctions = &functions; // <--- 关键:告诉 VMA 用动态加载的函数
|
||||
allocator_info.preferredLargeHeapBlockSize = config.preferred_large_heap_block_size;
|
||||
// allocatorInfo.flags = vma::AllocatorCreateFlagBits::eBufferDeviceAddress; // 如果你要用 BDA
|
||||
|
||||
// 启用功能标志
|
||||
vma::AllocatorCreateFlags flags;
|
||||
|
||||
if (config.enable_buffer_device_address) {
|
||||
flags |= vma::AllocatorCreateFlagBits::eBufferDeviceAddress;
|
||||
}
|
||||
|
||||
if (config.enable_memory_budget) {
|
||||
flags |= vma::AllocatorCreateFlagBits::eExtMemoryBudget;
|
||||
}
|
||||
allocator_info.flags = flags;
|
||||
|
||||
// 创建 RAII 风格的 Allocator
|
||||
auto [result, allocator] = vma::createAllocator(allocator_info);
|
||||
if (result != vk::Result::eSuccess) {
|
||||
return MAKE_ERROR_INFO(error_code::vulkan_init_failed, "Failed to create VMA Allocator: {}", to_string(result));
|
||||
}
|
||||
return allocator;
|
||||
}
|
||||
|
||||
void vma_allocator::setup(const allocator_config& config) {
|
||||
instance_ = config.instance;
|
||||
physical_device_ = config.physical_device;
|
||||
device_ = config.device;
|
||||
enable_buffer_device_address_ = config.enable_buffer_device_address;
|
||||
|
||||
auto result = create_vma_allocator(config);
|
||||
if (!result) {
|
||||
MIRAI_LOG_ERROR("VMA 分配器初始化失败: {}", result.error().full_description());
|
||||
throw std::runtime_error("VMA Allocator initialization failed");
|
||||
}
|
||||
vma_allocator_ = result.value();
|
||||
}
|
||||
|
||||
vma::MemoryUsage vma_allocator::to_vma_memory_usage(memory_usage usage) noexcept {
|
||||
switch (usage) {
|
||||
case memory_usage::gpu_only:
|
||||
return vma::MemoryUsage::eGpuOnly;
|
||||
case memory_usage::cpu_only:
|
||||
return vma::MemoryUsage::eCpuOnly;
|
||||
case memory_usage::cpu_to_gpu:
|
||||
return vma::MemoryUsage::eCpuToGpu;
|
||||
case memory_usage::gpu_to_cpu:
|
||||
return vma::MemoryUsage::eGpuToCpu;
|
||||
case memory_usage::auto_prefer_device:
|
||||
return vma::MemoryUsage::eAutoPreferDevice;
|
||||
case memory_usage::auto_prefer_host:
|
||||
return vma::MemoryUsage::eAutoPreferHost;
|
||||
default:
|
||||
return vma::MemoryUsage::eAuto;
|
||||
}
|
||||
}
|
||||
|
||||
vma::AllocationCreateFlags
|
||||
vma_allocator::to_vma_allocation_flags(memory_usage usage, bool persistent_mapped) noexcept {
|
||||
vma::AllocationCreateFlags flags;
|
||||
|
||||
// 持久映射
|
||||
if (persistent_mapped) {
|
||||
flags |= vma::AllocationCreateFlagBits::eMapped;
|
||||
}
|
||||
|
||||
// 根据内存用途设置访问模式
|
||||
switch (usage) {
|
||||
case memory_usage::cpu_only:
|
||||
case memory_usage::cpu_to_gpu:
|
||||
flags |= vma::AllocationCreateFlagBits::eHostAccessSequentialWrite;
|
||||
break;
|
||||
case memory_usage::gpu_to_cpu:
|
||||
flags |= vma::AllocationCreateFlagBits::eHostAccessRandom;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
result_t<buffer_allocation> vma_allocator::alloc_buffer(const buffer_create_info& info) {
|
||||
buffer_allocation alloc;
|
||||
|
||||
vk::BufferCreateInfo buffer_info{};
|
||||
buffer_info.size = info.size;
|
||||
buffer_info.usage = to_vulkan_buffer_usage(info.usage);
|
||||
buffer_info.sharingMode = vk::SharingMode::eExclusive;
|
||||
|
||||
if (enable_buffer_device_address_ && has_flag(info.usage, buffer_usage::shader_device_address)) {
|
||||
buffer_info.usage |= vk::BufferUsageFlagBits::eShaderDeviceAddress;
|
||||
}
|
||||
|
||||
vma::AllocationCreateInfo alloc_info{};
|
||||
alloc_info.usage = to_vma_memory_usage(info.mem_usage);
|
||||
alloc_info.flags = to_vma_allocation_flags(info.mem_usage, info.persistent_mapped);
|
||||
|
||||
vma::AllocationInfo vma_alloc_info{};
|
||||
vk::Result vk_result;
|
||||
vk::Buffer vk_buffer;
|
||||
|
||||
{
|
||||
std::lock_guard lock(mutex_);
|
||||
// vk_result = vma::UniqueBuffer(vma_allocator_, &buffer_info, &alloc_info, reinterpret_cast<VkBuffer*>(&vk_buffer),
|
||||
// reinterpret_cast<VmaAllocation*>(&alloc.allocation), &vma_alloc_info);
|
||||
}
|
||||
}
|
||||
}
|
||||
64
src/gpu_resource/allocator.h
Normal file
64
src/gpu_resource/allocator.h
Normal file
@@ -0,0 +1,64 @@
|
||||
#pragma once
|
||||
#include <mutex>
|
||||
|
||||
#include "types/types.h"
|
||||
#include "resource_types.h"
|
||||
#include "core/object.h"
|
||||
|
||||
#include <vulkan/vulkan.hpp>
|
||||
|
||||
#include "allocation_types.h"
|
||||
#include "render/vulkan_types.h"
|
||||
#include "types/error.h"
|
||||
|
||||
namespace mirai {
|
||||
/**
|
||||
* @brief GPU 分配器配置
|
||||
*/
|
||||
struct allocator_config {
|
||||
/// Vulkan 实例
|
||||
vk::Instance instance{};
|
||||
/// 物理设备
|
||||
vk::PhysicalDevice physical_device{};
|
||||
/// 逻辑设备
|
||||
vk::Device device{};
|
||||
/// Vulkan API 版本
|
||||
u32 vulkan_api_version = VK_API_VERSION_1_3;
|
||||
/// 是否启用 Buffer Device Address
|
||||
bool enable_buffer_device_address = true;
|
||||
/// 是否启用内存预算跟踪
|
||||
bool enable_memory_budget = true;
|
||||
/// 首选的大块分配大小(字节)
|
||||
u64 preferred_large_heap_block_size = 256 * 1024 * 1024; // 256 MB
|
||||
vk_dispatch_loader& disp;
|
||||
};
|
||||
|
||||
class vma_allocator : public object {
|
||||
MIRAI_OBJECT_TYPE_INFO(vma_allocator, object)
|
||||
|
||||
static auto& get() noexcept {
|
||||
static vma_allocator instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
explicit vma_allocator() = default;
|
||||
~vma_allocator() override;
|
||||
|
||||
void setup(const allocator_config& config);
|
||||
|
||||
vma::MemoryUsage to_vma_memory_usage(memory_usage usage) noexcept;
|
||||
vma::AllocationCreateFlags to_vma_allocation_flags(memory_usage usage, bool persistent_mapped) noexcept;
|
||||
|
||||
result_t<buffer_allocation> alloc_buffer(const buffer_create_info& info);
|
||||
private:
|
||||
vk::Instance instance_{};
|
||||
vk::PhysicalDevice physical_device_;
|
||||
vk::Device device_;
|
||||
vma::Allocator vma_allocator_;
|
||||
vma::DefragmentationContext defrag_context_;
|
||||
bool enable_buffer_device_address_ = true;
|
||||
std::atomic<u64> total_allocated_bytes_{0};
|
||||
std::atomic<u64> allocation_count_{0};
|
||||
mutable std::mutex mutex_;
|
||||
};
|
||||
}
|
||||
21
src/gpu_resource/gpu_buffer.cpp
Normal file
21
src/gpu_resource/gpu_buffer.cpp
Normal file
@@ -0,0 +1,21 @@
|
||||
#include "gpu_buffer.h"
|
||||
|
||||
#include "allocator.h"
|
||||
|
||||
namespace mirai {
|
||||
gpu_buffer::gpu_buffer(const buffer_create_info& info) {
|
||||
vma_allocator::get();
|
||||
}
|
||||
|
||||
bool gpu_buffer::is_host_visible() const noexcept {
|
||||
switch (mem_usage_) {
|
||||
case memory_usage::cpu_only:
|
||||
case memory_usage::cpu_to_gpu:
|
||||
case memory_usage::gpu_to_cpu:
|
||||
case memory_usage::auto_prefer_host:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
29
src/gpu_resource/gpu_buffer.h
Normal file
29
src/gpu_resource/gpu_buffer.h
Normal file
@@ -0,0 +1,29 @@
|
||||
#pragma once
|
||||
#include "resource_types.h"
|
||||
#include "core/object.h"
|
||||
#include "gpu_resource/allocation_types.h"
|
||||
|
||||
namespace mirai {
|
||||
class gpu_buffer : public object {
|
||||
MIRAI_OBJECT_TYPE_INFO(gpu_buffer, object)
|
||||
|
||||
gpu_buffer(const buffer_create_info& info);
|
||||
private:
|
||||
[[nodiscard]] bool is_host_visible() const noexcept;
|
||||
|
||||
buffer_allocation allocation_;
|
||||
|
||||
// buffer申请大小
|
||||
u64 size_ = 0;
|
||||
// buffer用途
|
||||
buffer_usage usage_ = buffer_usage::vertex;
|
||||
// 内存用途
|
||||
memory_usage mem_usage_ = memory_usage::gpu_only;
|
||||
// 是否持久映射
|
||||
bool persistent_mapped_ = false;
|
||||
// 映射的指针
|
||||
void* mapped_data_ = nullptr;
|
||||
// 调试名称
|
||||
std::string debug_name_;
|
||||
};
|
||||
}
|
||||
@@ -3,34 +3,34 @@
|
||||
|
||||
namespace mirai {
|
||||
[[nodiscard]] constexpr auto to_vulkan_buffer_usage(buffer_usage usage) noexcept {
|
||||
vk::BufferUsageFlags2 flags{};
|
||||
vk::BufferUsageFlags flags{};
|
||||
|
||||
if (has_flag(usage, buffer_usage::vertex)) {
|
||||
flags |= vk::BufferUsageFlagBits2::eVertexBuffer;
|
||||
flags |= vk::BufferUsageFlagBits::eVertexBuffer;
|
||||
}
|
||||
if (has_flag(usage, buffer_usage::index)) {
|
||||
flags |= vk::BufferUsageFlagBits2::eIndexBuffer;
|
||||
flags |= vk::BufferUsageFlagBits::eIndexBuffer;
|
||||
}
|
||||
if (has_flag(usage, buffer_usage::uniform)) {
|
||||
flags |= vk::BufferUsageFlagBits2::eUniformBuffer;
|
||||
flags |= vk::BufferUsageFlagBits::eUniformBuffer;
|
||||
}
|
||||
if (has_flag(usage, buffer_usage::storage)) {
|
||||
flags |= vk::BufferUsageFlagBits2::eStorageBuffer;
|
||||
flags |= vk::BufferUsageFlagBits::eStorageBuffer;
|
||||
}
|
||||
if (has_flag(usage, buffer_usage::staging)) {
|
||||
flags |= vk::BufferUsageFlagBits2::eTransferSrc | vk::BufferUsageFlagBits2::eTransferDst;
|
||||
flags |= vk::BufferUsageFlagBits::eTransferSrc | vk::BufferUsageFlagBits::eTransferDst;
|
||||
}
|
||||
if (has_flag(usage, buffer_usage::indirect)) {
|
||||
flags |= vk::BufferUsageFlagBits2::eIndirectBuffer;
|
||||
flags |= vk::BufferUsageFlagBits::eIndirectBuffer;
|
||||
}
|
||||
if (has_flag(usage, buffer_usage::transfer_src)) {
|
||||
flags |= vk::BufferUsageFlagBits2::eTransferSrc;
|
||||
flags |= vk::BufferUsageFlagBits::eTransferSrc;
|
||||
}
|
||||
if (has_flag(usage, buffer_usage::transfer_dst)) {
|
||||
flags |= vk::BufferUsageFlagBits2::eTransferDst;
|
||||
flags |= vk::BufferUsageFlagBits::eTransferDst;
|
||||
}
|
||||
if (has_flag(usage, buffer_usage::shader_device_address)) {
|
||||
flags |= vk::BufferUsageFlagBits2::eShaderDeviceAddress;
|
||||
flags |= vk::BufferUsageFlagBits::eShaderDeviceAddress;
|
||||
}
|
||||
return flags;
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
#include "allocator.h"
|
||||
151
src/render/device_utils.cpp
Normal file
151
src/render/device_utils.cpp
Normal file
@@ -0,0 +1,151 @@
|
||||
#include "device_utils.h"
|
||||
|
||||
#include "core/logger.h"
|
||||
|
||||
namespace mirai {
|
||||
swapchain_support_details query_swapchain_support(vk::PhysicalDevice physical_device, vk::SurfaceKHR surface) {
|
||||
swapchain_support_details details;
|
||||
|
||||
if (!surface) {
|
||||
return details;
|
||||
}
|
||||
|
||||
// 获取表面能力
|
||||
auto [result_caps, capabilities] = physical_device.getSurfaceCapabilitiesKHR(surface);
|
||||
if (result_caps == vk::Result::eSuccess) {
|
||||
details.capabilities = capabilities;
|
||||
}
|
||||
|
||||
// 获取表面格式
|
||||
auto [result_formats, formats] = physical_device.getSurfaceFormatsKHR(surface);
|
||||
if (result_formats == vk::Result::eSuccess) {
|
||||
details.formats = formats;
|
||||
}
|
||||
|
||||
// 获取呈现模式
|
||||
auto [result_modes, modes] = physical_device.getSurfacePresentModesKHR(surface);
|
||||
if (result_modes == vk::Result::eSuccess) {
|
||||
details.present_modes = modes;
|
||||
}
|
||||
|
||||
return details;
|
||||
}
|
||||
|
||||
queue_family_indices find_queue_families(vk::PhysicalDevice physical_device, vk::SurfaceKHR surface) {
|
||||
queue_family_indices indices;
|
||||
|
||||
std::vector<vk::QueueFamilyProperties> queue_families = physical_device.getQueueFamilyProperties();
|
||||
|
||||
for (u32 i = 0; i < queue_families.size(); ++i) {
|
||||
const auto& queue_family = queue_families[i];
|
||||
|
||||
// 检查图形支持
|
||||
if (queue_family.queueFlags & vk::QueueFlagBits::eGraphics) {
|
||||
indices.graphics_family = i;
|
||||
}
|
||||
|
||||
// 检查呈现支持
|
||||
if (surface) {
|
||||
auto [result, present_support] = physical_device.getSurfaceSupportKHR(i, surface);
|
||||
if (result == vk::Result::eSuccess && present_support) {
|
||||
indices.present_family = i;
|
||||
}
|
||||
}
|
||||
|
||||
// 检查独立计算队列
|
||||
if ((queue_family.queueFlags & vk::QueueFlagBits::eCompute) &&
|
||||
!(queue_family.queueFlags & vk::QueueFlagBits::eGraphics)) {
|
||||
indices.compute_family = i;
|
||||
}
|
||||
else if (queue_family.queueFlags & vk::QueueFlagBits::eCompute) {
|
||||
if (!indices.compute_family.has_value()) {
|
||||
indices.compute_family = i;
|
||||
}
|
||||
}
|
||||
|
||||
// 检查独立传输队列
|
||||
if ((queue_family.queueFlags & vk::QueueFlagBits::eTransfer) &&
|
||||
!(queue_family.queueFlags & vk::QueueFlagBits::eGraphics) &&
|
||||
!(queue_family.queueFlags & vk::QueueFlagBits::eCompute)) {
|
||||
indices.transfer_family = i;
|
||||
}
|
||||
else if (queue_family.queueFlags & vk::QueueFlagBits::eTransfer) {
|
||||
if (!indices.transfer_family.has_value()) {
|
||||
indices.transfer_family = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return indices;
|
||||
}
|
||||
|
||||
physical_device_info populate_physical_device(const vk::PhysicalDevice& physical_device, vk::SurfaceKHR surface) {
|
||||
physical_device_info info;
|
||||
info.physical_device = physical_device;
|
||||
|
||||
// 获取基本属性和特性
|
||||
info.properties = physical_device.getProperties();
|
||||
info.features = physical_device.getFeatures();
|
||||
info.memory_properties = physical_device.getMemoryProperties();
|
||||
|
||||
// 获取 Vulkan 1.1/1.2/1.3 特性
|
||||
vk::PhysicalDeviceFeatures2 features2{};
|
||||
|
||||
features2.setPNext(&info.features_11);
|
||||
info.features_11.setPNext(&info.features_12);
|
||||
info.features_12.setPNext(&info.features_13);
|
||||
|
||||
physical_device.getFeatures2(&features2);
|
||||
|
||||
// 获取队列族
|
||||
info.queue_families = find_queue_families(physical_device, surface);
|
||||
|
||||
// 获取交换链支持
|
||||
if (surface) {
|
||||
info.swapchain_support = query_swapchain_support(physical_device, surface);
|
||||
}
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
bool is_extension_supported(const char* extension_name) {
|
||||
const auto& extensions = get_available_extensions();
|
||||
return std::ranges::any_of(extensions, [extension_name](const vk::ExtensionProperties& ext) {
|
||||
return std::strcmp(ext.extensionName, extension_name) == 0;
|
||||
});
|
||||
}
|
||||
|
||||
bool is_layer_supported(const char* layer_name) {
|
||||
const auto& layers = get_available_layers();
|
||||
return std::ranges::any_of(layers, [layer_name](const vk::LayerProperties& layer) {
|
||||
return std::strcmp(layer.layerName, layer_name) == 0;
|
||||
});
|
||||
}
|
||||
|
||||
std::vector<vk::ExtensionProperties> get_available_extensions() {
|
||||
auto [result, extensions] = vk::enumerateInstanceExtensionProperties();
|
||||
if (result != vk::Result::eSuccess) {
|
||||
MIRAI_LOG_ERROR("Failed to enumerate Vulkan instance extensions: {}", vk::to_string(result));
|
||||
return {};
|
||||
}
|
||||
return extensions;
|
||||
}
|
||||
|
||||
std::vector<vk::LayerProperties> get_available_layers() {
|
||||
auto [result, layers] = vk::enumerateInstanceLayerProperties();
|
||||
if (result != vk::Result::eSuccess) {
|
||||
MIRAI_LOG_ERROR("Failed to enumerate Vulkan instance layers: {}", vk::to_string(result));
|
||||
return {};
|
||||
}
|
||||
return layers;
|
||||
}
|
||||
|
||||
u32 get_supported_api_version() {
|
||||
auto [result, version] = vk::enumerateInstanceVersion();
|
||||
if (result != vk::Result::eSuccess) {
|
||||
MIRAI_LOG_ERROR("Failed to get supported Vulkan API version: {}", vk::to_string(result));
|
||||
return VK_API_VERSION_1_0;
|
||||
}
|
||||
return version;
|
||||
}
|
||||
}
|
||||
400
src/render/device_utils.h
Normal file
400
src/render/device_utils.h
Normal file
@@ -0,0 +1,400 @@
|
||||
#pragma once
|
||||
#include "types/types.h"
|
||||
|
||||
#include <vulkan/vulkan.hpp>
|
||||
|
||||
namespace mirai {
|
||||
/**
|
||||
* @brief 交换链支持详情
|
||||
*
|
||||
* 存储物理设备的交换链支持信息
|
||||
*/
|
||||
struct swapchain_support_details {
|
||||
/// 表面能力
|
||||
vk::SurfaceCapabilitiesKHR capabilities{};
|
||||
|
||||
/// 支持的表面格式列表
|
||||
std::vector<vk::SurfaceFormatKHR> formats;
|
||||
|
||||
/// 支持的呈现模式列表
|
||||
std::vector<vk::PresentModeKHR> present_modes;
|
||||
|
||||
/**
|
||||
* @brief 检查交换链支持是否足够
|
||||
* @return 如果至少有一个格式和一个呈现模式返回 true
|
||||
*/
|
||||
[[nodiscard]] bool is_adequate() const noexcept {
|
||||
return !formats.empty() && !present_modes.empty();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 选择最佳的表面格式
|
||||
* @param preferred_format 首选格式
|
||||
* @param preferred_color_space 首选颜色空间
|
||||
* @return 选择的表面格式
|
||||
*/
|
||||
[[nodiscard]] vk::SurfaceFormatKHR choose_surface_format(
|
||||
vk::Format preferred_format = vk::Format::eB8G8R8A8Srgb,
|
||||
vk::ColorSpaceKHR preferred_color_space = vk::ColorSpaceKHR::eSrgbNonlinear
|
||||
) const {
|
||||
// 首先尝试找到首选格式
|
||||
for (const auto& format : formats) {
|
||||
if (format.format == preferred_format &&
|
||||
format.colorSpace == preferred_color_space) {
|
||||
return format;
|
||||
}
|
||||
}
|
||||
|
||||
// 如果找不到首选格式,返回第一个可用格式
|
||||
return formats.empty()
|
||||
? vk::SurfaceFormatKHR{
|
||||
vk::Format::eB8G8R8A8Unorm,
|
||||
vk::ColorSpaceKHR::eSrgbNonlinear
|
||||
}
|
||||
: formats[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 选择最佳的呈现模式
|
||||
* @param preferred_mode 首选模式
|
||||
* @return 选择的呈现模式
|
||||
*/
|
||||
[[nodiscard]] vk::PresentModeKHR choose_present_mode(
|
||||
vk::PresentModeKHR preferred_mode = vk::PresentModeKHR::eMailbox
|
||||
) const {
|
||||
// 首先尝试找到首选模式
|
||||
for (const auto& mode : present_modes) {
|
||||
if (mode == preferred_mode) {
|
||||
return mode;
|
||||
}
|
||||
}
|
||||
|
||||
// 如果找不到首选模式,返回 FIFO(总是可用)
|
||||
return vk::PresentModeKHR::eFifo;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 选择交换链范围
|
||||
* @param window_width 窗口宽度
|
||||
* @param window_height 窗口高度
|
||||
* @return 选择的范围
|
||||
*/
|
||||
[[nodiscard]] vk::Extent2D choose_extent(u32 window_width, u32 window_height) const {
|
||||
if (capabilities.currentExtent.width != std::numeric_limits<u32>::max()) {
|
||||
return capabilities.currentExtent;
|
||||
}
|
||||
|
||||
vk::Extent2D actual_extent = {window_width, window_height};
|
||||
|
||||
actual_extent.width = std::clamp(actual_extent.width,
|
||||
capabilities.minImageExtent.width,
|
||||
capabilities.maxImageExtent.width);
|
||||
actual_extent.height = std::clamp(actual_extent.height,
|
||||
capabilities.minImageExtent.height,
|
||||
capabilities.maxImageExtent.height);
|
||||
|
||||
return actual_extent;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 选择图像数量
|
||||
* @param preferred_count 首选数量
|
||||
* @return 选择的图像数量
|
||||
*/
|
||||
[[nodiscard]] u32 choose_image_count(u32 preferred_count = 3) const {
|
||||
u32 image_count = std::max(preferred_count, capabilities.minImageCount);
|
||||
|
||||
if (capabilities.maxImageCount > 0) {
|
||||
image_count = std::min(image_count, capabilities.maxImageCount);
|
||||
}
|
||||
|
||||
return image_count;
|
||||
}
|
||||
};
|
||||
|
||||
swapchain_support_details query_swapchain_support(vk::PhysicalDevice physical_device, vk::SurfaceKHR surface);
|
||||
|
||||
/// 无效的队列族索引
|
||||
constexpr u32 invalid_queue_family = std::numeric_limits<u32>::max();
|
||||
/**
|
||||
* @brief 队列族索引
|
||||
*
|
||||
* 存储 Vulkan 设备的各种队列族索引
|
||||
*/
|
||||
struct queue_family_indices {
|
||||
/// 图形队列族索引
|
||||
std::optional<u32> graphics_family;
|
||||
|
||||
/// 呈现队列族索引
|
||||
std::optional<u32> present_family;
|
||||
|
||||
/// 计算队列族索引
|
||||
std::optional<u32> compute_family;
|
||||
|
||||
/// 传输队列族索引
|
||||
std::optional<u32> transfer_family;
|
||||
|
||||
/**
|
||||
* @brief 检查是否所有必需的队列族都已找到
|
||||
* @return 如果图形和呈现队列族都存在返回 true
|
||||
*/
|
||||
[[nodiscard]] bool is_complete() const noexcept {
|
||||
return graphics_family.has_value() && present_family.has_value();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 检查是否有独立的计算队列族
|
||||
* @return 如果有独立的计算队列族返回 true
|
||||
*/
|
||||
[[nodiscard]] bool has_dedicated_compute() const noexcept {
|
||||
return compute_family.has_value() &&
|
||||
compute_family.value() != graphics_family.value();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 检查是否有独立的传输队列族
|
||||
* @return 如果有独立的传输队列族返回 true
|
||||
*/
|
||||
[[nodiscard]] bool has_dedicated_transfer() const noexcept {
|
||||
return transfer_family.has_value() &&
|
||||
transfer_family.value() != graphics_family.value() &&
|
||||
transfer_family.value() != compute_family.value_or(invalid_queue_family);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取唯一的队列族索引列表
|
||||
* @return 唯一队列族索引的向量
|
||||
*/
|
||||
[[nodiscard]] std::vector<u32> get_unique_families() const {
|
||||
std::vector<u32> unique_families;
|
||||
|
||||
if (graphics_family.has_value()) {
|
||||
unique_families.push_back(graphics_family.value());
|
||||
}
|
||||
|
||||
if (present_family.has_value() &&
|
||||
present_family.value() != graphics_family.value_or(invalid_queue_family)) {
|
||||
unique_families.push_back(present_family.value());
|
||||
}
|
||||
|
||||
if (compute_family.has_value() &&
|
||||
compute_family.value() != graphics_family.value_or(invalid_queue_family) &&
|
||||
compute_family.value() != present_family.value_or(invalid_queue_family)) {
|
||||
unique_families.push_back(compute_family.value());
|
||||
}
|
||||
|
||||
if (transfer_family.has_value() &&
|
||||
transfer_family.value() != graphics_family.value_or(invalid_queue_family) &&
|
||||
transfer_family.value() != present_family.value_or(invalid_queue_family) &&
|
||||
transfer_family.value() != compute_family.value_or(invalid_queue_family)) {
|
||||
unique_families.push_back(transfer_family.value());
|
||||
}
|
||||
|
||||
return unique_families;
|
||||
}
|
||||
};
|
||||
|
||||
queue_family_indices find_queue_families(vk::PhysicalDevice physical_device, vk::SurfaceKHR surface);
|
||||
|
||||
/**
|
||||
* @brief 物理设备信息
|
||||
*
|
||||
* 存储物理设备的详细信息
|
||||
*/
|
||||
struct physical_device_info {
|
||||
/// 物理设备句柄
|
||||
vk::PhysicalDevice physical_device;
|
||||
|
||||
/// 设备属性
|
||||
vk::PhysicalDeviceProperties properties{};
|
||||
|
||||
/// 设备特性
|
||||
vk::PhysicalDeviceFeatures features{};
|
||||
|
||||
/// Vulkan 1.1 特性
|
||||
vk::PhysicalDeviceVulkan11Features features_11;
|
||||
|
||||
/// Vulkan 1.2 特性
|
||||
vk::PhysicalDeviceVulkan12Features features_12;
|
||||
|
||||
/// Vulkan 1.3 特性
|
||||
vk::PhysicalDeviceVulkan13Features features_13;
|
||||
|
||||
/// 设备内存属性
|
||||
vk::PhysicalDeviceMemoryProperties memory_properties{};
|
||||
|
||||
/// 队列族索引
|
||||
queue_family_indices queue_families;
|
||||
|
||||
/// 交换链支持详情
|
||||
swapchain_support_details swapchain_support;
|
||||
|
||||
/// 设备评分(用于选择最佳设备)
|
||||
i32 score = 0;
|
||||
|
||||
/**
|
||||
* @brief 获取设备名称
|
||||
* @return 设备名称字符串
|
||||
*/
|
||||
[[nodiscard]] std::string get_device_name() const {
|
||||
return std::string(properties.deviceName.data());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 检查是否为独立 GPU
|
||||
* @return 如果是独立 GPU 返回 true
|
||||
*/
|
||||
[[nodiscard]] bool is_discrete_gpu() const noexcept {
|
||||
return properties.deviceType == vk::PhysicalDeviceType::eDiscreteGpu;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 检查是否为集成 GPU
|
||||
* @return 如果是集成 GPU 返回 true
|
||||
*/
|
||||
[[nodiscard]] bool is_integrated_gpu() const noexcept {
|
||||
return properties.deviceType == vk::PhysicalDeviceType::eIntegratedGpu;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 检查是否支持 Vulkan 1.3
|
||||
* @return 如果支持 Vulkan 1.3 返回 true
|
||||
*/
|
||||
[[nodiscard]] bool supports_vulkan_1_3() const noexcept {
|
||||
return properties.apiVersion >= VK_API_VERSION_1_3;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 检查是否支持 Dynamic Rendering
|
||||
* @return 如果支持 Dynamic Rendering 返回 true
|
||||
*/
|
||||
[[nodiscard]] bool supports_dynamic_rendering() const noexcept {
|
||||
return features_13.dynamicRendering == vk::True;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 检查是否支持 Synchronization2
|
||||
* @return 如果支持 Synchronization2 返回 true
|
||||
*/
|
||||
[[nodiscard]] bool supports_synchronization2() const noexcept {
|
||||
return features_13.synchronization2 == vk::True;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 检查是否支持描述符索引
|
||||
* @return 如果支持描述符索引返回 true
|
||||
*/
|
||||
[[nodiscard]] bool supports_descriptor_indexing() const noexcept {
|
||||
return features_12.descriptorIndexing == vk::True;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 检查是否支持 Timeline Semaphores
|
||||
* @return 如果支持 Timeline Semaphores 返回 true
|
||||
*/
|
||||
[[nodiscard]] bool supports_timeline_semaphores() const noexcept {
|
||||
return features_12.timelineSemaphore == vk::True;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 检查是否支持 Buffer Device Address
|
||||
* @return 如果支持 Buffer Device Address 返回 true
|
||||
*/
|
||||
[[nodiscard]] bool supports_buffer_device_address() const noexcept {
|
||||
return features_12.bufferDeviceAddress == vk::True;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 检查设备是否适合使用
|
||||
* @return 如果设备满足最低要求返回 true
|
||||
*/
|
||||
[[nodiscard]] bool is_suitable() const noexcept {
|
||||
return physical_device &&
|
||||
queue_families.is_complete() &&
|
||||
swapchain_support.is_adequate() &&
|
||||
supports_vulkan_1_3() &&
|
||||
supports_dynamic_rendering() &&
|
||||
supports_synchronization2();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 计算设备评分
|
||||
* @return 设备评分
|
||||
*/
|
||||
[[nodiscard]] i32 calculate_score() const {
|
||||
if (!is_suitable()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
i32 device_score = 0;
|
||||
|
||||
// 独立 GPU 加分
|
||||
if (is_discrete_gpu()) {
|
||||
device_score += 1000;
|
||||
}
|
||||
else if (is_integrated_gpu()) {
|
||||
device_score += 100;
|
||||
}
|
||||
|
||||
// 最大纹理尺寸加分
|
||||
device_score += static_cast<i32>(properties.limits.maxImageDimension2D / 1000);
|
||||
|
||||
// 支持可选特性加分
|
||||
if (supports_descriptor_indexing()) {
|
||||
device_score += 100;
|
||||
}
|
||||
if (supports_timeline_semaphores()) {
|
||||
device_score += 50;
|
||||
}
|
||||
if (supports_buffer_device_address()) {
|
||||
device_score += 50;
|
||||
}
|
||||
|
||||
// 有独立计算队列加分
|
||||
if (queue_families.has_dedicated_compute()) {
|
||||
device_score += 50;
|
||||
}
|
||||
|
||||
// 有独立传输队列加分
|
||||
if (queue_families.has_dedicated_transfer()) {
|
||||
device_score += 50;
|
||||
}
|
||||
|
||||
return device_score;
|
||||
}
|
||||
};
|
||||
|
||||
physical_device_info populate_physical_device(const vk::PhysicalDevice& physical_device, vk::SurfaceKHR surface);
|
||||
|
||||
/**
|
||||
* @brief 检查是否支持指定的实例扩展
|
||||
* @param extension_name 扩展名称
|
||||
* @return 如果支持返回 true
|
||||
*/
|
||||
[[nodiscard]] static bool is_extension_supported(const char* extension_name);
|
||||
|
||||
/**
|
||||
* @brief 检查是否支持指定的验证层
|
||||
* @param layer_name 层名称
|
||||
* @return 如果支持返回 true
|
||||
*/
|
||||
[[nodiscard]] static bool is_layer_supported(const char* layer_name);
|
||||
|
||||
/**
|
||||
* @brief 获取所有可用的实例扩展
|
||||
* @return 扩展属性列表
|
||||
*/
|
||||
[[nodiscard]] static std::vector<vk::ExtensionProperties> get_available_extensions();
|
||||
|
||||
/**
|
||||
* @brief 获取所有可用的验证层
|
||||
* @return 层属性列表
|
||||
*/
|
||||
[[nodiscard]] static std::vector<vk::LayerProperties> get_available_layers();
|
||||
|
||||
/**
|
||||
* @brief 获取实例支持的最高 API 版本
|
||||
* @return 支持的 API 版本
|
||||
*/
|
||||
[[nodiscard]] static u32 get_supported_api_version();
|
||||
}
|
||||
23
src/render/vulkan_context.cpp
Normal file
23
src/render/vulkan_context.cpp
Normal file
@@ -0,0 +1,23 @@
|
||||
#include "vulkan_context.h"
|
||||
|
||||
#include "core/logger.h"
|
||||
|
||||
namespace mirai {
|
||||
void vulkan_context::setup(const vulkan_context_config& config) {
|
||||
}
|
||||
|
||||
void vulkan_context::create_default_device(const vk::SurfaceKHR& surface) {
|
||||
auto infos = instance_->get_physical_devices_info(surface);
|
||||
for (const auto& info : infos) {
|
||||
if (info.is_suitable()) {
|
||||
MIRAI_LOG_INFO("Selected GPU: {} (score: {})", info.get_device_name(), info.score);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
vulkan_device_config config{
|
||||
|
||||
};
|
||||
auto device = make_obj<vulkan_device>(config);
|
||||
}
|
||||
}
|
||||
29
src/render/vulkan_context.h
Normal file
29
src/render/vulkan_context.h
Normal file
@@ -0,0 +1,29 @@
|
||||
#pragma once
|
||||
|
||||
#include "vulkan_device.h"
|
||||
#include "vulkan_instance.h"
|
||||
#include "core/object.h"
|
||||
|
||||
namespace mirai {
|
||||
|
||||
struct vulkan_context_config {
|
||||
/// Vulkan 实例配置
|
||||
vulkan_instance_config instance_config;
|
||||
};
|
||||
|
||||
class vulkan_context : public object {
|
||||
MIRAI_OBJECT_TYPE_INFO(vulkan_context, object)
|
||||
public:
|
||||
static auto& get() noexcept {
|
||||
static vulkan_context instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
void setup(const vulkan_context_config& config);
|
||||
void create_default_device(const vk::SurfaceKHR& surface);
|
||||
private:
|
||||
vk_dynamic_loader dl;
|
||||
std::shared_ptr<vulkan_instance> instance_;
|
||||
std::vector<std::shared_ptr<vulkan_device>> devices_;
|
||||
};
|
||||
}
|
||||
23
src/render/vulkan_device.cpp
Normal file
23
src/render/vulkan_device.cpp
Normal file
@@ -0,0 +1,23 @@
|
||||
#include "vulkan_device.h"
|
||||
|
||||
#include "gpu_resource/allocator.h"
|
||||
|
||||
mirai::vulkan_device::vulkan_device(const vulkan_device_config& config) {
|
||||
physical_device_ = config.physical_device;
|
||||
|
||||
auto proc_addr = config.dl.getProcAddress<PFN_vkGetInstanceProcAddr>("vkGetInstanceProcAddr");
|
||||
disp_.init(proc_addr);
|
||||
disp_.init(device_);
|
||||
|
||||
allocator_config alloc_config{
|
||||
config.instance,
|
||||
physical_device_,
|
||||
device_,
|
||||
config.vulkan_api_version,
|
||||
config.enable_buffer_device_address,
|
||||
config.enable_memory_budget,
|
||||
config.preferred_large_heap_block_size,
|
||||
disp_
|
||||
};
|
||||
vma_allocator::get().setup(alloc_config);
|
||||
}
|
||||
41
src/render/vulkan_device.h
Normal file
41
src/render/vulkan_device.h
Normal file
@@ -0,0 +1,41 @@
|
||||
#pragma once
|
||||
#include "vulkan_types.h"
|
||||
#include "core/object.h"
|
||||
|
||||
#include <vulkan/vulkan.hpp>
|
||||
|
||||
namespace mirai {
|
||||
class vma_allocator;
|
||||
}
|
||||
|
||||
namespace mirai {
|
||||
struct vulkan_device_config {
|
||||
vk::Instance instance;
|
||||
vk::PhysicalDevice physical_device;
|
||||
/// Vulkan API 版本
|
||||
u32 vulkan_api_version = VK_API_VERSION_1_3;
|
||||
/// 是否启用 Buffer Device Address
|
||||
bool enable_buffer_device_address = true;
|
||||
/// 是否启用内存预算跟踪
|
||||
bool enable_memory_budget = true;
|
||||
/// 首选的大块分配大小(字节)
|
||||
u64 preferred_large_heap_block_size = 256 * 1024 * 1024; // 256 MB
|
||||
/// Vulkan 动态加载器引用
|
||||
vk_dynamic_loader& dl;
|
||||
};
|
||||
|
||||
class vulkan_device : public object {
|
||||
MIRAI_OBJECT_TYPE_INFO(vulkan_device, object)
|
||||
public:
|
||||
vulkan_device(const vulkan_device_config& config);
|
||||
|
||||
private:
|
||||
// 逻辑设备
|
||||
vk::Device device_;
|
||||
vk_dispatch_loader disp_;
|
||||
// std::shared_ptr<vma_allocator> allocator_; // 先使用全局分配器,这里保存一个变量用于未来多GPU支持
|
||||
|
||||
// 保存物理设备映射
|
||||
vk::PhysicalDevice physical_device_;
|
||||
};
|
||||
}
|
||||
@@ -1,8 +1,5 @@
|
||||
#include "vulkan_instance.h"
|
||||
|
||||
#include "vulkan_types.h"
|
||||
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
|
||||
|
||||
#include <set>
|
||||
#include <SDL3/SDL.h>
|
||||
#include <SDL3/SDL_vulkan.h>
|
||||
@@ -36,54 +33,40 @@ namespace mirai {
|
||||
config_ = config;
|
||||
}
|
||||
|
||||
bool vulkan_instance::is_extension_supported(const char* extension_name) {
|
||||
const auto& extensions = get_available_extensions();
|
||||
return std::ranges::any_of(extensions, [extension_name](const vk::ExtensionProperties& ext) {
|
||||
return std::strcmp(ext.extensionName, extension_name) == 0;
|
||||
});
|
||||
}
|
||||
|
||||
bool vulkan_instance::is_layer_supported(const char* layer_name) {
|
||||
const auto& layers = get_available_layers();
|
||||
return std::ranges::any_of(layers, [layer_name](const vk::LayerProperties& layer) {
|
||||
return std::strcmp(layer.layerName, layer_name) == 0;
|
||||
});
|
||||
}
|
||||
|
||||
std::vector<vk::ExtensionProperties> vulkan_instance::get_available_extensions() {
|
||||
auto [result, extensions] = vk::enumerateInstanceExtensionProperties();
|
||||
if (result != vk::Result::eSuccess) {
|
||||
MIRAI_LOG_ERROR("Failed to enumerate Vulkan instance extensions: {}", vk::to_string(result));
|
||||
std::vector<vk::PhysicalDevice> vulkan_instance::enumerate_physical_devices() const {
|
||||
if (!instance_) {
|
||||
return {};
|
||||
}
|
||||
return extensions;
|
||||
}
|
||||
|
||||
std::vector<vk::LayerProperties> vulkan_instance::get_available_layers() {
|
||||
auto [result, layers] = vk::enumerateInstanceLayerProperties();
|
||||
auto [result, devices] = instance_.enumeratePhysicalDevices();
|
||||
if (result != vk::Result::eSuccess) {
|
||||
MIRAI_LOG_ERROR("Failed to enumerate Vulkan instance layers: {}", vk::to_string(result));
|
||||
return {};
|
||||
}
|
||||
return layers;
|
||||
|
||||
return devices;
|
||||
}
|
||||
|
||||
u32 vulkan_instance::get_supported_api_version() {
|
||||
auto [result, version] = vk::enumerateInstanceVersion();
|
||||
if (result != vk::Result::eSuccess) {
|
||||
MIRAI_LOG_ERROR("Failed to get supported Vulkan API version: {}", vk::to_string(result));
|
||||
return VK_API_VERSION_1_0;
|
||||
std::vector<physical_device_info> vulkan_instance::get_physical_devices_info(vk::SurfaceKHR surface) const {
|
||||
auto devices = enumerate_physical_devices();
|
||||
std::vector<physical_device_info> infos;
|
||||
infos.reserve(devices.size());
|
||||
|
||||
for (const auto& device : devices) {
|
||||
auto info = populate_physical_device(device, surface);
|
||||
info.score = info.calculate_score();
|
||||
infos.push_back(std::move(info));
|
||||
}
|
||||
return version;
|
||||
|
||||
auto pred = [](const physical_device_info& a, const physical_device_info& b) {
|
||||
return a.score > b.score;
|
||||
};
|
||||
// 按评分排序(降序)
|
||||
std::ranges::sort(infos, pred);
|
||||
return infos;
|
||||
}
|
||||
|
||||
void vulkan_instance::on_created() {
|
||||
void vulkan_instance::on_created() {
|
||||
object::on_created();
|
||||
{
|
||||
const vk_dynamic_loader dl;
|
||||
auto proc_addr = dl.getProcAddress<PFN_vkGetInstanceProcAddr>("vkGetInstanceProcAddr");
|
||||
VULKAN_HPP_DEFAULT_DISPATCHER.init(proc_addr);
|
||||
}
|
||||
|
||||
auto result = create_instance(config_);
|
||||
if (!result.has_value()) {
|
||||
@@ -196,13 +179,13 @@ namespace mirai {
|
||||
return MAKE_ERROR_INFO(error_code::vulkan_init_failed,
|
||||
"Failed to create Vulkan instance: {}", vk::to_string(result));
|
||||
}
|
||||
VULKAN_HPP_DEFAULT_DISPATCHER.init(instance);
|
||||
instance_ = instance;
|
||||
|
||||
MIRAI_LOG_INFO("Vulkan instance created with API version {}.{}.{}",
|
||||
VK_VERSION_MAJOR(api_version_),
|
||||
VK_VERSION_MINOR(api_version_),
|
||||
VK_VERSION_PATCH(api_version_));
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,9 @@
|
||||
#include <vulkan/vulkan.hpp>
|
||||
#include <functional>
|
||||
|
||||
#include "device_utils.h"
|
||||
#include "vulkan_types.h"
|
||||
|
||||
namespace mirai {
|
||||
/**
|
||||
* @brief 调试消息严重级别
|
||||
@@ -69,7 +72,6 @@ namespace mirai {
|
||||
|
||||
explicit vulkan_instance(const vulkan_instance_config& config = {});
|
||||
|
||||
|
||||
// ============================================================================================
|
||||
// 扩展和层查询
|
||||
// ============================================================================================
|
||||
@@ -78,57 +80,22 @@ namespace mirai {
|
||||
* @brief 获取已启用的实例扩展列表
|
||||
* @return 扩展名称列表
|
||||
*/
|
||||
[[nodiscard]] const std::vector<const char*>& get_enabled_extensions() const noexcept {
|
||||
return enabled_extensions_;
|
||||
}
|
||||
[[nodiscard]] const std::vector<const char*>& get_enabled_extensions() const noexcept { return enabled_extensions_; }
|
||||
|
||||
/**
|
||||
* @brief 获取已启用的验证层列表
|
||||
* @return 层名称列表
|
||||
*/
|
||||
[[nodiscard]] const std::vector<const char*>& get_enabled_layers() const noexcept {
|
||||
return enabled_layers_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 检查是否支持指定的实例扩展
|
||||
* @param extension_name 扩展名称
|
||||
* @return 如果支持返回 true
|
||||
*/
|
||||
[[nodiscard]] static bool is_extension_supported(const char* extension_name);
|
||||
|
||||
/**
|
||||
* @brief 检查是否支持指定的验证层
|
||||
* @param layer_name 层名称
|
||||
* @return 如果支持返回 true
|
||||
*/
|
||||
[[nodiscard]] static bool is_layer_supported(const char* layer_name);
|
||||
|
||||
/**
|
||||
* @brief 获取所有可用的实例扩展
|
||||
* @return 扩展属性列表
|
||||
*/
|
||||
[[nodiscard]] static std::vector<vk::ExtensionProperties> get_available_extensions();
|
||||
|
||||
/**
|
||||
* @brief 获取所有可用的验证层
|
||||
* @return 层属性列表
|
||||
*/
|
||||
[[nodiscard]] static std::vector<vk::LayerProperties> get_available_layers();
|
||||
[[nodiscard]] const std::vector<const char*>& get_enabled_layers() const noexcept { return enabled_layers_; }
|
||||
|
||||
/**
|
||||
* @brief 获取要求的 API 版本
|
||||
* @return API 版本
|
||||
*/
|
||||
[[nodiscard]] u32 get_api_version() const noexcept {
|
||||
return api_version_;
|
||||
}
|
||||
[[nodiscard]] u32 get_api_version() const noexcept { return api_version_; }
|
||||
|
||||
/**
|
||||
* @brief 获取实例支持的最高 API 版本
|
||||
* @return 支持的 API 版本
|
||||
*/
|
||||
[[nodiscard]] static u32 get_supported_api_version();
|
||||
[[nodiscard]] std::vector<vk::PhysicalDevice> enumerate_physical_devices() const;
|
||||
[[nodiscard]] std::vector<physical_device_info> get_physical_devices_info(vk::SurfaceKHR surface = {}) const;
|
||||
protected:
|
||||
void on_created() override;
|
||||
void on_destroying() override;
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
|
||||
#if VK_HEADER_VERSION >= 304
|
||||
using vk_dynamic_loader = vk::detail::DynamicLoader;
|
||||
using vk_dispatch_loader = vk::detail::DispatchLoaderDynamic;
|
||||
#else
|
||||
using vk_dynamic_loader = vk::DynamicLoader;
|
||||
using vk_dispatch_loader = vk::DispatchLoaderDynamic;
|
||||
#endif
|
||||
|
||||
@@ -35,6 +35,12 @@
|
||||
"version>=": "12.2.0",
|
||||
"features": ["freetype"]
|
||||
},
|
||||
{
|
||||
"name": "vulkan-hpp"
|
||||
},
|
||||
{
|
||||
"name": "vulkan-memory-allocator-hpp"
|
||||
},
|
||||
{
|
||||
"name": "yoga",
|
||||
"version>=": "3.2.1"
|
||||
|
||||
Reference in New Issue
Block a user