This commit is contained in:
Nanako 2025-02-06 14:10:02 +08:00
parent aa9398bad9
commit 7e90e0f302
16 changed files with 563 additions and 210 deletions

View File

@ -11,6 +11,7 @@ time_type last_time = {};
namespace aorii {
bool init(const window_desc& in_main_window_desc) {
spdlog::info("初始化 Aorii");
begin_time = std::chrono::high_resolution_clock::now();
if (!create_font_manager())
return false;
@ -27,15 +28,18 @@ namespace aorii {
destroy_window_manager();
destroy_renderer();
destroy_font_manager();
spdlog::info("Aorii 销毁");
}
void update() {
thread_pool::global().process_main_thread_callbacks();
// 更新时间
const auto& current_time = std::chrono::high_resolution_clock::now();
delta_time = current_time - last_time;
last_time = current_time;
// 更新窗口
get_window_manager()->update();
std::this_thread::yield();

View File

@ -0,0 +1,192 @@
#include "device_selector.h"
void device_selector::classify_and_sort_devices(const vk::Instance instance, const vk::SurfaceKHR surface) {
const auto& physical_devices = instance.enumeratePhysicalDevices();
// 获取设备的评分列表
auto device_scores = get_device_scores(physical_devices, surface);
// 按评分排序设备(从高到低)
auto sort_pred = [](const auto& a, const auto& b) { return a.second > b.second; };
std::ranges::sort(device_scores, sort_pred);
// 根据排序结果将设备分组
group_devices(device_scores, surface);
}
vk::PhysicalDevice device_selector::get_main_device() const {
// 优先使用同时支持显示和计算的设备
if (!combined_group.empty()) {
return combined_group[0];
}
// 如果没有同时支持显示和计算的设备,则使用显示设备
if (!display_group.empty()) {
return display_group[0];
}
// 如果没有显示设备,则使用计算设备
if (!compute_group.empty()) {
spdlog::warn("没有找到同时支持显示和计算的设备,将使用计算设备");
return compute_group[0];
}
return nullptr;
}
vk::PhysicalDevice device_selector::get_main_compute_device() const {
// 优先使用同时支持显示和计算的设备
if (!combined_group.empty()) {
return combined_group[0];
}
// 如果没有同时支持显示和计算的设备,则使用计算设备
if (!compute_group.empty()) {
return compute_group[0];
}
// 如果没有计算设备,则使用显示设备
if (!display_group.empty()) {
spdlog::warn("没有找到计算设备,将使用显示设备");
return display_group[0];
}
return nullptr;
}
std::vector<uint32_t> device_selector::get_queue_families(vk::PhysicalDevice in_physical_device,
const vk::QueueFlags& in_flags) {
std::vector<uint32_t> result;
const auto queue_families = in_physical_device.getQueueFamilyProperties();
for (uint32_t i = 0; i < queue_families.size(); ++i) {
if (queue_families[i].queueFlags & in_flags) {
result.push_back(i);
}
}
return result;
}
std::vector<device_selector::device_score> device_selector::get_device_scores(
const std::vector<vk::PhysicalDevice>& devices, const vk::SurfaceKHR surface) {
std::vector<device_score> deviceScores;
for (const auto& dev: devices) {
int score = score_device(dev, surface);
deviceScores.emplace_back(dev, score);
}
return deviceScores;
}
int device_selector::score_device(const vk::PhysicalDevice& dev, const vk::SurfaceKHR surface) {
int score = 0;
// 获取设备属性和特性
const auto& properties = dev.getProperties();
const auto& features = dev.getFeatures();
// 首选独立显卡
if (properties.deviceType == vk::PhysicalDeviceType::eDiscreteGpu) {
score += 1000;
} else if (properties.deviceType == vk::PhysicalDeviceType::eIntegratedGpu) {
score += 500;
}
// 查询队列族属性
const auto& queue_props = dev.getQueueFamilyProperties();
bool has_graphics = false;
bool has_compute = false;
bool can_present = false;
for (uint32_t i = 0; i < queue_props.size(); ++i) {
const auto& prop = queue_props[i];
if (prop.queueFlags & vk::QueueFlagBits::eGraphics) {
has_graphics = true;
score += 100;
}
if (prop.queueFlags & vk::QueueFlagBits::eCompute) {
has_compute = true;
score += 100;
}
// 检查呈现能力
const VkBool32 present_support = dev.getSurfaceSupportKHR(i, surface);
if (present_support == VK_TRUE) {
can_present = true;
score += 100;
}
}
// 如果同时支持图形、计算和呈现,则加额外分
if (has_graphics && has_compute && can_present) {
score += 500; // 额外奖励
}
// 考虑内存大小
const auto& memory_properties = dev.getMemoryProperties();
uint64_t total_memory = 0;
for (const auto& heap : memory_properties.memoryHeaps) {
if (heap.flags & vk::MemoryHeapFlagBits::eDeviceLocal) {
total_memory += heap.size;
}
}
score += static_cast<int>(total_memory / (1024 * 1024 * 1024)); // 每GB加1分
std::string device_name = properties.deviceName;
spdlog::info("{}: {}分", device_name, score);
return score;
}
void device_selector::group_devices(const std::vector<device_score>& deviceScores, const vk::SurfaceKHR surface) {
for (const auto& [dev, score] : deviceScores) {
const device_type& type = classify_device(dev, surface);
switch (type) {
case device_type::combined:
combined_group.push_back(dev);
display_group.push_back(dev);
compute_group.push_back(dev);
break;
case device_type::display:
display_group.push_back(dev);
break;
case device_type::compute:
compute_group.push_back(dev);
break;
default:
// 忽略不符合条件的设备
break;
}
}
}
device_selector::device_type device_selector::classify_device(const vk::PhysicalDevice& dev,
const vk::SurfaceKHR surface) {
bool has_graphics = false;
bool has_compute = false;
bool can_present = false;
const auto& queue_props = dev.getQueueFamilyProperties();
for (uint32_t i = 0; i < queue_props.size(); ++i) {
const auto& prop = queue_props[i];
if (prop.queueFlags & vk::QueueFlagBits::eGraphics) {
has_graphics = true;
}
if (prop.queueFlags & vk::QueueFlagBits::eCompute) {
has_compute = true;
}
// 检查呈现能力
const VkBool32 present_support = dev.getSurfaceSupportKHR(i, surface);
if (present_support == VK_TRUE) {
can_present = true;
}
}
if (has_graphics && has_compute && can_present) {
return device_type::combined;
}
if (has_graphics && can_present) {
return device_type::display;
}
if (has_compute) {
return device_type::compute;
}
return device_type::unknown;
}

View File

@ -8,36 +8,13 @@ class device_selector {
public:
using device_group = std::vector<vk::PhysicalDevice>;
void classify_and_sort_devices(const vk::Instance instance, const vk::SurfaceKHR surface) {
const auto& physical_devices = instance.enumeratePhysicalDevices();
void classify_and_sort_devices(vk::Instance instance, vk::SurfaceKHR surface);
// 获取设备的评分列表
auto device_scores = get_device_scores(physical_devices, surface);
vk::PhysicalDevice get_main_device() const;
// 按评分排序设备(从高到低)
auto sort_pred = [](const auto& a, const auto& b) { return a.second > b.second; };
std::ranges::sort(device_scores, sort_pred);
vk::PhysicalDevice get_main_compute_device() const;
// 根据排序结果将设备分组
group_devices(device_scores, surface);
}
vk::PhysicalDevice get_main_device() const {
// 优先使用同时支持显示和计算的设备
if (!combined_group.empty()) {
return combined_group[0];
}
// 如果没有同时支持显示和计算的设备,则使用显示设备
if (!display_group.empty()) {
return display_group[0];
}
// 如果没有显示设备,则使用计算设备
if (!compute_group.empty()) {
spdlog::warn("没有找到同时支持显示和计算的设备,将使用计算设备");
return compute_group[0];
}
return nullptr;
}
[[nodiscard]] static std::vector<uint32_t> get_queue_families(vk::PhysicalDevice in_physical_device, const vk::QueueFlags& in_flags);
device_group combined_group; // 同时支持显示和计算的设备组
device_group display_group; // 显示设备组
@ -45,134 +22,11 @@ public:
private:
using device_score = std::pair<vk::PhysicalDevice, int>;
static std::vector<device_score> get_device_scores(const std::vector<vk::PhysicalDevice>& devices,
const vk::SurfaceKHR surface) {
std::vector<device_score> deviceScores;
static std::vector<device_score> get_device_scores(const std::vector<vk::PhysicalDevice>& devices, vk::SurfaceKHR surface);
for (const auto& dev: devices) {
int score = score_device(dev, surface);
deviceScores.emplace_back(dev, score);
}
return deviceScores;
}
static int score_device(const vk::PhysicalDevice& dev, vk::SurfaceKHR surface);
static int score_device(const vk::PhysicalDevice& dev, const vk::SurfaceKHR surface) {
int score = 0;
void group_devices(const std::vector<device_score>& deviceScores, vk::SurfaceKHR surface);
// 获取设备属性和特性
const auto& properties = dev.getProperties();
const auto& features = dev.getFeatures();
// 首选独立显卡
if (properties.deviceType == vk::PhysicalDeviceType::eDiscreteGpu) {
score += 1000;
} else if (properties.deviceType == vk::PhysicalDeviceType::eIntegratedGpu) {
score += 500;
}
// 查询队列族属性
const auto& queue_props = dev.getQueueFamilyProperties();
bool has_graphics = false;
bool has_compute = false;
bool can_present = false;
for (uint32_t i = 0; i < queue_props.size(); ++i) {
const auto& prop = queue_props[i];
if (prop.queueFlags & vk::QueueFlagBits::eGraphics) {
has_graphics = true;
score += 100;
}
if (prop.queueFlags & vk::QueueFlagBits::eCompute) {
has_compute = true;
score += 100;
}
// 检查呈现能力
const VkBool32 present_support = dev.getSurfaceSupportKHR(i, surface);
if (present_support == VK_TRUE) {
can_present = true;
score += 100;
}
}
// 如果同时支持图形、计算和呈现,则加额外分
if (has_graphics && has_compute && can_present) {
score += 500; // 额外奖励
}
// 考虑内存大小
const auto& memory_properties = dev.getMemoryProperties();
uint64_t total_memory = 0;
for (const auto& heap : memory_properties.memoryHeaps) {
if (heap.flags & vk::MemoryHeapFlagBits::eDeviceLocal) {
total_memory += heap.size;
}
}
score += static_cast<int>(total_memory / (1024 * 1024 * 1024)); // 每GB加1分
std::string device_name = properties.deviceName;
spdlog::info("{}: {}分", device_name, score);
return score;
}
void group_devices(const std::vector<device_score>& deviceScores,
const vk::SurfaceKHR surface) {
for (const auto& [dev, score] : deviceScores) {
const device_type& type = classify_device(dev, surface);
switch (type) {
case device_type::combined:
combined_group.push_back(dev);
display_group.push_back(dev);
compute_group.push_back(dev);
break;
case device_type::display:
display_group.push_back(dev);
break;
case device_type::compute:
compute_group.push_back(dev);
break;
default:
// 忽略不符合条件的设备
break;
}
}
}
static device_type classify_device(const vk::PhysicalDevice& dev, const vk::SurfaceKHR surface) {
bool has_graphics = false;
bool has_compute = false;
bool can_present = false;
const auto& queue_props = dev.getQueueFamilyProperties();
for (uint32_t i = 0; i < queue_props.size(); ++i) {
const auto& prop = queue_props[i];
if (prop.queueFlags & vk::QueueFlagBits::eGraphics) {
has_graphics = true;
}
if (prop.queueFlags & vk::QueueFlagBits::eCompute) {
has_compute = true;
}
// 检查呈现能力
const VkBool32 present_support = dev.getSurfaceSupportKHR(i, surface);
if (present_support == VK_TRUE) {
can_present = true;
}
}
if (has_graphics && has_compute && can_present) {
return device_type::combined;
}
if (has_graphics && can_present) {
return device_type::display;
}
if (has_compute) {
return device_type::compute;
}
return device_type::unknown;
}
static device_type classify_device(const vk::PhysicalDevice& dev, vk::SurfaceKHR surface);
};

View File

@ -112,9 +112,11 @@ bool aorii_renderer::init() {
std::vector<const char*> extensions;
{
// #if DEBUG
// extensions.push_back(VK_EXT_DEBUG_REPORT_EXTENSION_NAME);
// #endif
#if DEBUG
extensions.push_back(VK_EXT_DEBUG_REPORT_EXTENSION_NAME);
extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
#endif
// 交换链
uint32_t glfw_extension_count = 0;
auto glfw_extensions = glfwGetRequiredInstanceExtensions(&glfw_extension_count);
for (int i = 0; i < glfw_extension_count; ++i) {
@ -126,6 +128,16 @@ bool aorii_renderer::init() {
create_info.setPEnabledExtensionNames(extensions);
}
std::vector<const char*> layers;
{
#if DEBUG
layers.push_back("VK_LAYER_KHRONOS_validation");
create_info.setPEnabledLayerNames(layers);
for (auto layer: layers) {
spdlog::info("启用层: {}", layer);
}
#endif
}
instance = createInstance(create_info);
if (!instance) {
@ -140,30 +152,37 @@ bool aorii_renderer::init() {
std::vector<const char*> device_extensions;
device_extensions.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
std::vector<vk::DeviceQueueCreateInfo> queue_create_infos;
const auto family_indexes = device_selector::get_queue_families(selector.get_main_device(), vk::QueueFlagBits::eGraphics);
for (const auto i : family_indexes) {
constexpr float queue_priority = 1.0f;
vk::DeviceQueueCreateInfo queue_create_info{};
queue_create_info.setQueueFamilyIndex(i);
queue_create_info.setQueueCount(1);
queue_create_info.setPQueuePriorities(&queue_priority);
queue_create_infos.push_back(queue_create_info);
}
vk::DeviceCreateInfo device_create_info{};
device_create_info.setPEnabledExtensionNames(device_extensions);
main_device.create_device(selector.get_main_device(), device_create_info);
spdlog::info("Vulkan 主设备: {}", main_device.get_physical_device_name());
device_create_info.setQueueCreateInfos(queue_create_infos);
vk::SwapchainCreateInfoKHR swap_chain_create_info{};
swap_chain_create_info.setMinImageCount(2);
swap_chain_create_info.setImageFormat(vk::Format::eB8G8R8A8Unorm);
swap_chain_create_info.setImageColorSpace(vk::ColorSpaceKHR::eSrgbNonlinear);
swap_chain_create_info.setImageExtent(main_window->get_framebuffer_size());
swap_chain_create_info.setImageArrayLayers(1);
swap_chain_create_info.setImageUsage(vk::ImageUsageFlagBits::eColorAttachment);
swap_chain_create_info.setImageSharingMode(vk::SharingMode::eExclusive);
swap_chain_create_info.setPreTransform(vk::SurfaceTransformFlagBitsKHR::eIdentity);
swap_chain_create_info.setCompositeAlpha(vk::CompositeAlphaFlagBitsKHR::eOpaque);
swap_chain_create_info.setPresentMode(vk::PresentModeKHR::eFifo);
swap_chain_create_info.setClipped(true);
swap_chain_create_info.setOldSwapchain(nullptr);
// main_window->create_swap_chain(swap_chain_create_info);
main_device.create_device(selector.get_main_device(), device_create_info);
spdlog::info("Vulkan 主设备使用: {}", main_device.get_physical_device_name());
for (auto extension: device_extensions) {
spdlog::info("启用设备扩展: {}", extension);
}
renderer_swapchain::create_info swapchain_info{};
if (!main_window->create_swap_chain(swapchain_info))
return false;
return true;
}
void aorii_renderer::destroy() {
main_device->destroy();
instance.destroy();
}
@ -176,6 +195,36 @@ vk::SurfaceKHR aorii_renderer::create_surface(GLFWwindow* in_window) const {
return { surface };
}
vk::SwapchainKHR aorii_renderer::create_swap_chain(const vk::SwapchainCreateInfoKHR& in_create_info) {
return main_device->createSwapchainKHR(in_create_info);
void aorii_renderer::destroy_surface(const vk::SurfaceKHR& in_surface) const {
instance.destroySurfaceKHR(in_surface);
}
const std::vector<device_handle>& aorii_renderer::get_compute_device() const {
if (!compute_device.empty()) return compute_device;
for (const auto& device: selector.compute_group) {
const float queue_priority = 1.0f;
std::vector<vk::DeviceQueueCreateInfo> queue_create_infos;
const auto queue_families = device.getQueueFamilyProperties();
for (uint32_t i = 0; i < queue_families.size(); ++i) {
const bool queue_compute_support = static_cast<bool>(
queue_families[i].queueFlags & vk::QueueFlagBits::eCompute);
if (queue_compute_support) {
vk::DeviceQueueCreateInfo queue_create_info{};
queue_create_info.setQueueFamilyIndex(i);
queue_create_info.setQueueCount(1);
queue_create_info.setPQueuePriorities(&queue_priority);
queue_create_infos.push_back(queue_create_info);
}
}
device_handle handle;
vk::DeviceCreateInfo device_create_info{};
device_create_info.setQueueCreateInfos(queue_create_infos);
handle.create_device(device, device_create_info);
spdlog::info("创建 Vulkan 计算设备: {}", handle.get_physical_device_name());
compute_device.push_back(handle);
}
return compute_device;
}

View File

@ -5,6 +5,7 @@
#include <GLFW/glfw3.h>
#include "device_selector.h"
#include "renderer_swapchain.h"
#include "renderer_types.h"
struct window_desc;
@ -15,11 +16,14 @@ public:
void destroy();
vk::SurfaceKHR create_surface(GLFWwindow* in_window) const;
vk::SwapchainKHR create_swap_chain(const vk::SwapchainCreateInfoKHR& in_create_info);
void destroy_surface(const vk::SurfaceKHR& in_surface) const;
device_handle get_main_device() const { return main_device; }
const std::vector<device_handle>& get_compute_device() const;
private:
vk::Instance instance;
device_selector selector;
device_set main_device;
device_handle main_device;
mutable std::vector<device_handle> compute_device;
};
namespace aorii {

View File

@ -2,12 +2,12 @@
#include "renderer_buffer_memory_strategy.h"
uint32_t device_set::get_physical_device_id() const {
uint32_t device_handle::get_physical_device_id() const {
const auto& props = physical_device.getProperties();
return props.deviceID;
}
std::string device_set::get_physical_device_name() const {
std::string device_handle::get_physical_device_name() const {
const auto& props = physical_device.getProperties();
return props.deviceName;
}
@ -22,7 +22,7 @@ renderer_buffer_desc::operator vk::BufferCreateInfo() const {
return buffer_info;
}
renderer_buffer::renderer_buffer(const device_set& in_device, const renderer_buffer_desc& in_desc) {
renderer_buffer::renderer_buffer(const device_handle& in_device, const renderer_buffer_desc& in_desc) {
device = in_device;
desc = in_desc;
memory_strategy = buffer_memory_strategy::create(in_desc.memory_props);

View File

@ -8,7 +8,7 @@ class buffer_memory_strategy;
class renderer_buffer {
public:
explicit renderer_buffer(const device_set& in_device, const renderer_buffer_desc& in_desc);
explicit renderer_buffer(const device_handle& in_device, const renderer_buffer_desc& in_desc);
virtual ~renderer_buffer();
@ -45,7 +45,7 @@ public:
*/
void resize(vk::DeviceSize in_new_size, vk::CommandBuffer in_command_buffer, bool in_preserve_data = true, bool in_allow_in_place = true, float in_growth_factor = 1.5f);
protected:
device_set device;
device_handle device;
renderer_buffer_desc desc;
vk::Buffer buffer;
vk::DeviceMemory memory;

View File

@ -12,7 +12,7 @@ std::unique_ptr<buffer_memory_strategy> buffer_memory_strategy::create(vk::Memor
throw std::runtime_error("Unsupported memory property flags");
}
void host_visible_strategy::copy_from(const device_set& in_device, vk::Buffer in_buffer, const vk::DeviceMemory in_device_memory,
void host_visible_strategy::copy_from(const device_handle& in_device, vk::Buffer in_buffer, const vk::DeviceMemory in_device_memory,
const void* in_data, const vk::DeviceSize in_size, vk::CommandBuffer in_command_buffer) {
void* mapped = in_device->mapMemory(in_device_memory, 0, in_size);
std::memcpy(mapped, in_data, in_size);
@ -26,7 +26,7 @@ void host_visible_strategy::copy_from(const device_set& in_device, vk::Buffer in
in_device->unmapMemory(in_device_memory);
}
void device_local_strategy::copy_from(const device_set& in_device, vk::Buffer in_buffer, vk::DeviceMemory in_device_memory,
void device_local_strategy::copy_from(const device_handle& in_device, vk::Buffer in_buffer, vk::DeviceMemory in_device_memory,
const void* in_data, const vk::DeviceSize in_size, vk::CommandBuffer in_command_buffer) {
// 创建暂存缓冲区

View File

@ -8,7 +8,7 @@ class buffer_memory_strategy {
public:
virtual ~buffer_memory_strategy() = default;
virtual void copy_from(const device_set& in_device, vk::Buffer in_buffer, vk::DeviceMemory in_device_memory,
virtual void copy_from(const device_handle& in_device, vk::Buffer in_buffer, vk::DeviceMemory in_device_memory,
const void* in_data, vk::DeviceSize in_size,
vk::CommandBuffer in_command_buffer) = 0;
@ -17,10 +17,10 @@ public:
class host_visible_strategy : public buffer_memory_strategy {
public:
virtual void copy_from(const device_set& in_device, vk::Buffer in_buffer, vk::DeviceMemory in_device_memory, const void* in_data, vk::DeviceSize in_size, vk::CommandBuffer in_command_buffer) override;
virtual void copy_from(const device_handle& in_device, vk::Buffer in_buffer, vk::DeviceMemory in_device_memory, const void* in_data, vk::DeviceSize in_size, vk::CommandBuffer in_command_buffer) override;
};
class device_local_strategy : public buffer_memory_strategy {
public:
virtual void copy_from(const device_set& in_device, vk::Buffer in_buffer, vk::DeviceMemory in_device_memory, const void* in_data, vk::DeviceSize in_size, vk::CommandBuffer in_command_buffer) override;
virtual void copy_from(const device_handle& in_device, vk::Buffer in_buffer, vk::DeviceMemory in_device_memory, const void* in_data, vk::DeviceSize in_size, vk::CommandBuffer in_command_buffer) override;
};

View File

@ -0,0 +1,175 @@
#include "renderer_swapchain.h"
// std::string to_string(const vk::Extent2D& in) {
// return fmt::format("Extent2D: {}x{}", in.width, in.height);
// }
// std::string to_string(const vk::SwapchainCreateInfoKHR& in) {
// // 格式化字符串
// std::string result = fmt::format("SwapchainCreateInfoKHR:\n"
// " surface: {}\n"
// " minImageCount: {}\n"
// " imageFormat: {}\n"
// " imageColorSpace: {}\n"
// " imageExtent: {}\n"
// " imageArrayLayers: {}\n"
// " imageUsage: {}\n"
// " presentMode: {}\n"
// " preTransform: {}\n"
// " compositeAlpha: {}\n"
// " clipped: {}\n",
// in.surface,
// in.minImageCount,
// vk::to_string(in.imageFormat),
// vk::to_string(in.imageColorSpace),
// to_string(in.imageExtent),
// in.imageArrayLayers,
// vk::to_string(in.imageUsage),
// vk::to_string(in.presentMode),
// vk::to_string(in.preTransform),
// vk::to_string(in.compositeAlpha),
// in.clipped);
// return result;
// }
bool renderer_swapchain::init_swapchain(const device_handle& in_device, const vk::SurfaceKHR& in_surface, const create_info& in_info) {
device = in_device;
surface = in_surface;
info = in_info;
// 获取交换链支持的信息
const auto& surface_capabilities = device.physical_device.getSurfaceCapabilitiesKHR(in_surface);
// 验证并调整图像数量
uint32_t image_count = std::max(in_info.min_image_count,
surface_capabilities.minImageCount);
if (surface_capabilities.maxImageCount > 0) {
image_count = std::clamp(image_count,
surface_capabilities.minImageCount,
surface_capabilities.maxImageCount);
}
// 验证并调整图像格式
auto surface_formats = device.physical_device.getSurfaceFormatsKHR(in_surface);
if (surface_formats.empty()) {
spdlog::error("获取表面格式失败");
return false;
}
if (surface_formats.size() == 1 && surface_formats[0].format == vk::Format::eUndefined) {
info.format = vk::Format::eB8G8R8A8Srgb;
info.color_space = vk::ColorSpaceKHR::eSrgbNonlinear;
spdlog::warn("表面格式未指定,使用默认格式 {} {}", vk::to_string(info.format), vk::to_string(info.color_space));
} else {
bool found = false;
for (const auto& format : surface_formats) {
if (format.format == info.format && format.colorSpace == info.color_space) {
found = true;
break;
}
}
if (!found) {
info.format = surface_formats[0].format;
info.color_space = surface_formats[0].colorSpace;
spdlog::warn("请求的表面格式不支持,使用默认格式 {} {}", vk::to_string(info.format), vk::to_string(info.color_space));
}
}
// 验证并调整呈现模式
auto present_modes = device.physical_device.getSurfacePresentModesKHR(in_surface);
if (present_modes.empty()) {
spdlog::error("获取呈现模式失败");
return false;
}
if (std::ranges::find(present_modes, info.present_mode) == present_modes.end()) {
info.present_mode = vk::PresentModeKHR::eFifo;
spdlog::warn("请求的呈现模式不支持,使用默认呈现模式 Fifo");
}
// 验证并调整交换链尺寸
info.extent = std::clamp(info.extent,
surface_capabilities.minImageExtent,
surface_capabilities.maxImageExtent);
// 验证并调整图像用途
if ((surface_capabilities.supportedUsageFlags & info.image_usage) != info.image_usage) {
info.image_usage = vk::ImageUsageFlagBits::eColorAttachment;
spdlog::warn("请求的图像用途不支持,使用默认图像用途 ColorAttachment");
}
// 验证并调整合成 alpha
if (!(surface_capabilities.supportedCompositeAlpha & vk::CompositeAlphaFlagBitsKHR::eOpaque)) {
spdlog::warn("不支持不透明合成 alpha");
return false;
}
// 创建交换链信息
vk::SwapchainCreateInfoKHR create_info{};
create_info.surface = surface;
create_info.minImageCount = image_count;
create_info.imageFormat = info.format;
create_info.imageColorSpace = info.color_space;
create_info.imageExtent = info.extent;
create_info.imageArrayLayers = 1;
create_info.imageUsage = info.image_usage;
create_info.imageSharingMode = vk::SharingMode::eExclusive;
create_info.presentMode = info.present_mode;
create_info.preTransform = surface_capabilities.currentTransform;
create_info.compositeAlpha = vk::CompositeAlphaFlagBitsKHR::eOpaque;
create_info.clipped = VK_TRUE;
create_info.imageExtent = info.extent;
// 创建交换链
swapchain = device->createSwapchainKHR(create_info);
if (!swapchain) {
spdlog::error("创建交换链失败");
return false;
}
images = device->getSwapchainImagesKHR(swapchain);
if (images.empty()) {
spdlog::error("获取交换链图像失败");
return false;
}
// 创建图像视图
return create_image_views(device.device, in_info.format);
}
bool renderer_swapchain::create_image_views(const vk::Device& device, vk::Format format) {
image_views.resize(images.size());
for (size_t i = 0; i < images.size(); i++) {
vk::ImageViewCreateInfo view_info{};
view_info.image = images[i];
view_info.viewType = vk::ImageViewType::e2D;
view_info.format = format;
view_info.components.r = vk::ComponentSwizzle::eIdentity;
view_info.components.g = vk::ComponentSwizzle::eIdentity;
view_info.components.b = vk::ComponentSwizzle::eIdentity;
view_info.components.a = vk::ComponentSwizzle::eIdentity;
view_info.subresourceRange.aspectMask = vk::ImageAspectFlagBits::eColor;
view_info.subresourceRange.baseMipLevel = 0;
view_info.subresourceRange.levelCount = 1;
view_info.subresourceRange.baseArrayLayer = 0;
view_info.subresourceRange.layerCount = 1;
auto new_view = device.createImageView(view_info);
if (new_view)
image_views[i] = new_view;
else
goto ERROR;
}
return true;
ERROR:
spdlog::error("创建图像视图失败");
for (const auto view: image_views) { device.destroyImageView(view); }
return false;
}
void renderer_swapchain::cleanup() {
if (device) {
for (const auto& view : image_views) {
device->destroyImageView(view);
}
device->destroySwapchainKHR(swapchain);
}
}

View File

@ -0,0 +1,52 @@
#pragma once
#include <spdlog/spdlog.h>
#include <vulkan/vulkan.hpp>
#include "renderer_types.h"
class renderer_swapchain {
public:
struct create_info {
vk::PresentModeKHR present_mode = vk::PresentModeKHR::eMailbox; // 呈现模式
vk::Format format = vk::Format::eB8G8R8A8Srgb; // 请求的图像格式
vk::ColorSpaceKHR color_space = vk::ColorSpaceKHR::eSrgbNonlinear; // 色彩空间
vk::ImageUsageFlags image_usage = vk::ImageUsageFlagBits::eColorAttachment; // 图像用途
vk::Extent2D extent = vk::Extent2D(800, 600); // 交换链图像大小
uint32_t min_image_count = 2; // 最小缓冲区数量
};
renderer_swapchain() {
}
~renderer_swapchain() {
cleanup();
}
bool resize(const vk::Extent2D& in_size) {
cleanup();
info.extent = in_size;
return init_swapchain(device, surface, info);
}
[[nodiscard]] const auto& get_swapchain() const { return swapchain; }
[[nodiscard]] const auto& get_images() const { return images; }
[[nodiscard]] const auto& get_image_views() const { return image_views; }
[[nodiscard]] const auto& get_create_info() const { return info; }
[[nodiscard]] const auto& get_surface() const { return surface; }
[[nodiscard]] const auto& get_device() const { return device; }
bool init_swapchain(const device_handle& in_device, const vk::SurfaceKHR& in_surface, const create_info& in_info);
private:
bool create_image_views(const vk::Device& device, vk::Format format);
void cleanup();
private:
device_handle device;
create_info info;
vk::SurfaceKHR surface;
vk::SwapchainKHR swapchain;
std::vector<vk::Image> images;
std::vector<vk::ImageView> image_views;
};

View File

@ -1,7 +1,7 @@
#pragma once
#include <vulkan/vulkan.hpp>
struct device_set {
struct device_handle {
vk::PhysicalDevice physical_device;
vk::Device device;
@ -18,6 +18,13 @@ struct device_set {
physical_device = in_physical_device;
device = physical_device.createDevice(in_create_info);
}
void destroy_device() {
if (device) {
device.destroy();
device = nullptr;
}
}
// 获取物理设备GUID
[[nodiscard]] uint32_t get_physical_device_id() const;
// 获取物理设备名称

View File

@ -1,12 +0,0 @@
#include "window/renderer_window.h"
#include "LLGL/Platform/MacOS/MacOSNativeHandle.h"
void* renderer_window::get_native_handle() const {
if (auto surface = get_surface()) {
LLGL::NativeHandle native_handle;
surface->GetNativeHandle(&native_handle, sizeof(LLGL::NativeHandle));
return native_handle.responder;
}
return nullptr;
}

View File

@ -3,6 +3,7 @@
#include <spdlog/spdlog.h>
#include "window_manager.h"
#include <GLFW/glfw3native.h>
renderer_window::renderer_window(const window_desc& in_desc) {
glfwWindowHint(GLFW_RESIZABLE, in_desc.resizable);
@ -37,6 +38,13 @@ renderer_window::renderer_window(const window_desc& in_desc) {
}
renderer_window::~renderer_window() {
delete swapchain;
if (surface) {
const auto renderer = aorii::get_renderer();
if (renderer) {
renderer->destroy_surface(surface);
}
}
}
void renderer_window::set_title(const std::wstring& in_title) const {
@ -58,7 +66,7 @@ bool renderer_window::create_surface() {
return true;
}
bool renderer_window::create_swap_chain(vk::SwapchainCreateInfoKHR in_create_info) {
bool renderer_window::create_swap_chain(const renderer_swapchain::create_info& in_create_info) {
const auto renderer = aorii::get_renderer();
if (!renderer)
return false;
@ -66,23 +74,42 @@ bool renderer_window::create_swap_chain(vk::SwapchainCreateInfoKHR in_create_inf
spdlog::error("窗口表面未创建");
return false;
}
in_create_info.setSurface(surface);
swap_chain = renderer->create_swap_chain(in_create_info);
if (!swap_chain) {
const auto& main_device = renderer->get_main_device();
auto temp_swapchain_info = in_create_info;
temp_swapchain_info.extent = get_size();
swapchain = new renderer_swapchain();
if (!swapchain->init_swapchain(main_device, surface, temp_swapchain_info)) {
spdlog::error("创建交换链失败");
return false;
}
return true;
}
#if !AORII_MACOS
void* renderer_window::get_native_handle() const {
#if defined(GLFW_EXPOSE_NATIVE_WIN32)
return glfwGetWin32Window(window);
#elif defined(GLFW_EXPOSE_NATIVE_COCOA)
return glfwGetCocoaWindow(window);
#elif defined(GLFW_EXPOSE_NATIVE_X11)
return reinterpret_cast<void*>(
static_cast<uintptr_t>(glfwGetX11Window(window)));
#elif defined(GLFW_EXPOSE_NATIVE_WAYLAND)
return glfwGetWaylandWindow(window);
#elif defined(GLFW_EXPOSE_NATIVE_EGL)
return static_cast<void*>(glfwGetEGLDisplay(window));
#else
static_assert(false, "No native platform window implementation available");
return nullptr;
}
#endif
}
void renderer_window::on_resize(int in_width, int in_height) {
spdlog::info("窗口大小变更:{}x{}", in_width, in_height);
if (swapchain) {
swapchain->resize({static_cast<uint32_t>(in_width), static_cast<uint32_t>(in_height)});
}
}
void renderer_window::on_glfw_close() {

View File

@ -1,5 +1,6 @@
#pragma once
#include "renderer/renderer.h"
#include "renderer/renderer_swapchain.h"
#include "vulkan/vulkan.hpp"
@ -47,14 +48,14 @@ public:
bool create_surface();
[[nodiscard]] auto get_surface() const { return surface; }
bool create_swap_chain(vk::SwapchainCreateInfoKHR in_create_info);
[[nodiscard]] auto get_swap_chain() const { return swap_chain; }
bool create_swap_chain(const renderer_swapchain::create_info& in_create_info);
[[nodiscard]] auto get_swap_chain() const { return swapchain; }
[[nodiscard]] void* get_native_handle() const;
protected:
virtual void on_resize(int in_width, int in_height);
virtual void on_glfw_close();
private:
GLFWwindow* window;
vk::SwapchainKHR swap_chain;
renderer_swapchain* swapchain;
vk::SurfaceKHR surface;
};

View File

@ -42,7 +42,7 @@ std::weak_ptr<renderer_window> window_manager::create_window(const window_desc&
}
void window_manager::destroy_window(renderer_window* in_window) {
auto it = std::ranges::find_if(windows, [in_window](const auto& window) {
const auto it = std::ranges::find_if(windows, [in_window](const auto& window) {
return window.get() == in_window;
});
if (it != windows.end()) {