Files
mirai/src/render/device_utils.h
2026-01-04 19:40:00 +08:00

401 lines
11 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#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();
}