From fd62137041ea5971663fe3b1b0f3fea18a86b762 Mon Sep 17 00:00:00 2001 From: nanako <469449812@qq.com> Date: Mon, 5 Jan 2026 17:47:08 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E4=BA=A4=E6=8D=A2=E9=93=BE?= =?UTF-8?q?=E5=88=9B=E5=BB=BA=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/gpu_resource/allocator.cpp | 4 +- src/gpu_resource/swapchain.cpp | 80 ++++++++++++++++++++++++++++++++++ src/gpu_resource/swapchain.h | 23 ++++++++++ src/render/device_utils.cpp | 6 +-- src/render/device_utils.h | 4 ++ src/render/vulkan_context.cpp | 3 -- src/render/vulkan_context.h | 9 +++- src/render/vulkan_device.cpp | 2 +- src/render/vulkan_instance.cpp | 24 +++++----- src/window/window.cpp | 55 +++++++++++++++++++++-- src/window/window.h | 22 +++++++--- 11 files changed, 201 insertions(+), 31 deletions(-) create mode 100644 src/gpu_resource/swapchain.cpp create mode 100644 src/gpu_resource/swapchain.h diff --git a/src/gpu_resource/allocator.cpp b/src/gpu_resource/allocator.cpp index 9283d3d..1905691 100644 --- a/src/gpu_resource/allocator.cpp +++ b/src/gpu_resource/allocator.cpp @@ -63,7 +63,7 @@ namespace mirai { // 创建 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 MAKE_ERROR_INFO(error_code::vulkan_init_failed, "VMA分配器创建失败: {}", to_string(result)); } return allocator; } @@ -77,7 +77,7 @@ namespace mirai { auto result = create_vma_allocator(config); if (!result) { MIRAI_LOG_ERROR("VMA 分配器初始化失败: {}", result.error().full_description()); - throw std::runtime_error("VMA Allocator initialization failed"); + throw std::runtime_error("VMA 分配器初始化失败"); } vma_allocator_ = result.value(); } diff --git a/src/gpu_resource/swapchain.cpp b/src/gpu_resource/swapchain.cpp new file mode 100644 index 0000000..e380708 --- /dev/null +++ b/src/gpu_resource/swapchain.cpp @@ -0,0 +1,80 @@ +#include "swapchain.h" + +#include "core/logger.h" +#include "render/device_utils.h" +#include "render/vulkan_context.h" + +namespace mirai { + swapchain::swapchain(const swapchain_create_info& info) { + auto default_device = vulkan_context::get().get_default_device(); + if (!default_device) { + MIRAI_LOG_ERROR("无有效Vulkan设备,无法创建交换链。"); + return; + } + auto physical_device = default_device->get_physical_device(); + if (!physical_device) { + MIRAI_LOG_ERROR("无有效物理设备,无法创建交换链。"); + return; + } + auto queue_families = find_queue_families(physical_device, info.surface); + if (!queue_families.graphics_family) { + MIRAI_LOG_ERROR("未能找到用于交换链创建的图形队列族。"); + return; + } + if (!queue_families.present_family) { + MIRAI_LOG_ERROR("未能找到用于交换链创建的呈现队列族。"); + return; + } + const auto& query = query_swapchain_support(physical_device, info.surface); + + auto format_target = info.hdr_enabled ? vk::Format::eA2B10G10R10UnormPack32 : vk::Format::eB8G8R8A8Srgb; + + const auto& extent = query.choose_extent(info.initial_extent.x(), info.initial_extent.y()); + const auto image_count = query.choose_image_count(); + const auto present_mode = query.choose_present_mode(); + const auto image_format = query.choose_surface_format(format_target); + + vk::SwapchainCreateInfoKHR create_info{}; + create_info.setSurface(info.surface); + create_info.setMinImageCount(image_count); + create_info.setImageFormat(image_format.format); + create_info.setImageColorSpace(image_format.colorSpace); + create_info.setImageExtent(extent); + create_info.setImageArrayLayers(1); + create_info.setImageUsage(vk::ImageUsageFlagBits::eColorAttachment); + create_info.setPreTransform(query.get_transform()); + create_info.setCompositeAlpha(vk::CompositeAlphaFlagBitsKHR::eOpaque); + create_info.setPresentMode(present_mode); + create_info.setClipped(true); + + const auto graphics_queue_family_index = queue_families.graphics_family.value(); + const auto present_queue_family_index = queue_families.present_family.value(); + // 处理多个队列族(如果 Graphics 和 Present 不是同一个) + if (graphics_queue_family_index != present_queue_family_index) { + uint32_t queueFamilyIndices[] = { graphics_queue_family_index, present_queue_family_index }; + + create_info.setQueueFamilyIndices(queueFamilyIndices); + create_info.setImageSharingMode(vk::SharingMode::eConcurrent); + } else { + create_info.setImageSharingMode(vk::SharingMode::eExclusive); + } + + auto [result, swapchain] = default_device->get_device().createSwapchainKHR(create_info); + if (result != vk::Result::eSuccess) { + MIRAI_LOG_ERROR("交换链创建失败:{}", vk::to_string(result)); + return; + } + + swapchain_ = swapchain; + } + + void swapchain::on_destroying() { + object::on_destroying(); + if (swapchain_) { + MIRAI_LOG_INFO("销毁交换链。"); + auto default_device = vulkan_context::get().get_default_device(); + default_device->get_device().destroySwapchainKHR(swapchain_); + swapchain_ = nullptr; + } + } +} diff --git a/src/gpu_resource/swapchain.h b/src/gpu_resource/swapchain.h new file mode 100644 index 0000000..1d7b3fc --- /dev/null +++ b/src/gpu_resource/swapchain.h @@ -0,0 +1,23 @@ +#pragma once +#include "core/object.h" + +#include + +namespace mirai { + struct swapchain_create_info { + vk::SurfaceKHR surface{}; + vec2i initial_extent{800, 600}; + bool hdr_enabled{false}; + }; + class swapchain : public object { + MIRAI_OBJECT_TYPE_INFO(swapchain, object) + + swapchain(const swapchain_create_info& info); + + auto get_swapchain() const noexcept { return swapchain_; } + protected: + void on_destroying() override; + private: + vk::SwapchainKHR swapchain_; + }; +} diff --git a/src/render/device_utils.cpp b/src/render/device_utils.cpp index 72c7e37..562e227 100644 --- a/src/render/device_utils.cpp +++ b/src/render/device_utils.cpp @@ -125,7 +125,7 @@ namespace mirai { std::vector 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)); + MIRAI_LOG_ERROR("无法枚举 Vulkan 实例扩展: {}", vk::to_string(result)); return {}; } return extensions; @@ -134,7 +134,7 @@ namespace mirai { std::vector 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)); + MIRAI_LOG_ERROR("无法枚举 Vulkan 实例层: {}", vk::to_string(result)); return {}; } return layers; @@ -143,7 +143,7 @@ namespace mirai { 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)); + MIRAI_LOG_ERROR("获取支持的Vulkan API版本失败: {}", vk::to_string(result)); return VK_API_VERSION_1_0; } return version; diff --git a/src/render/device_utils.h b/src/render/device_utils.h index 3b51662..9468724 100644 --- a/src/render/device_utils.h +++ b/src/render/device_utils.h @@ -110,6 +110,10 @@ namespace mirai { return image_count; } + + [[nodiscard]] auto get_transform() const noexcept { + return capabilities.currentTransform; + } }; swapchain_support_details query_swapchain_support(vk::PhysicalDevice physical_device, vk::SurfaceKHR surface); diff --git a/src/render/vulkan_context.cpp b/src/render/vulkan_context.cpp index be4e597..1689510 100644 --- a/src/render/vulkan_context.cpp +++ b/src/render/vulkan_context.cpp @@ -4,9 +4,6 @@ #include "core/logger.h" -// 定义Vulkan-Hpp的全局动态加载器(当使用VULKAN_HPP_DISPATCH_LOADER_DYNAMIC时需要) -// VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE - namespace mirai { void vulkan_context::init(const vulkan_context_init_config& config) { instance_ = make_obj(config.instance_config); diff --git a/src/render/vulkan_context.h b/src/render/vulkan_context.h index 799c4c5..6c963dc 100644 --- a/src/render/vulkan_context.h +++ b/src/render/vulkan_context.h @@ -28,8 +28,13 @@ namespace mirai { std::shared_ptr create_device(const vulkan_device_config& info); - auto get_vk_instance() const { - return instance_->get_instance(); + [[nodiscard]] auto get_vk_instance() const noexcept { return instance_->get_instance(); } + // 获取默认设备(第一个创建设备, 一定带有呈现队列) + [[nodiscard]] auto get_default_device() const noexcept -> std::shared_ptr { + if (devices_.empty()) { + return nullptr; + } + return devices_.front(); } protected: void create_default_device(const vk::SurfaceKHR& surface); diff --git a/src/render/vulkan_device.cpp b/src/render/vulkan_device.cpp index 5fec5ac..deacc81 100644 --- a/src/render/vulkan_device.cpp +++ b/src/render/vulkan_device.cpp @@ -84,7 +84,7 @@ mirai::vulkan_device::vulkan_device(const vulkan_device_config& config) { // 创建逻辑设备 auto [result, device] = physical_device_.createDevice(device_create_info); if (result != vk::Result::eSuccess) { - MIRAI_LOG_ERROR("Failed to create logical device: {}", vk::to_string(result)); + MIRAI_LOG_ERROR("创建逻辑设备失败: {}", vk::to_string(result)); return; } device_ = device; diff --git a/src/render/vulkan_instance.cpp b/src/render/vulkan_instance.cpp index cc6e85c..93fd301 100644 --- a/src/render/vulkan_instance.cpp +++ b/src/render/vulkan_instance.cpp @@ -70,7 +70,7 @@ namespace mirai { auto result = create_instance(config_); if (!result.has_value()) { - MIRAI_LOG_ERROR("Failed to create Vulkan instance: {}", result.error().full_description()); + MIRAI_LOG_ERROR("无法创建Vulkan实例: {}", result.error().full_description()); return; } @@ -78,16 +78,16 @@ namespace mirai { if (validation_enabled_) { result = setup_debug_messenger(); if (!result.has_value()) { - MIRAI_LOG_WARN("Failed to setup debug messenger: {}", result.error().full_description()); + MIRAI_LOG_WARN("调试信使设置失败: {}", result.error().full_description()); } } #endif - MIRAI_LOG_INFO("Vulkan instance 对象创建"); + MIRAI_LOG_INFO("Vulkan 实例对象创建"); } void vulkan_instance::on_destroying() { object::on_destroying(); - MIRAI_LOG_INFO("Vulkan instance 对象销毁"); + MIRAI_LOG_INFO("Vulkan 实例对象销毁"); #if MIRAI_DEBUG if (debug_messenger_) { destroy_debug_messenger(); @@ -103,7 +103,7 @@ namespace mirai { #if MIRAI_DEBUG validation_enabled_ = config.enable_validation; if (validation_enabled_ && !is_layer_supported(validation_layer_name)) { - MIRAI_LOG_WARN("Vulkan validation layer not supported, disabling validation"); + MIRAI_LOG_WARN("Vulkan验证层不被支持,已禁用验证"); validation_enabled_ = false; } #endif @@ -112,7 +112,7 @@ namespace mirai { u32 supported_version = get_supported_api_version(); if (supported_version < api_version_) { return MAKE_ERROR_INFO(error_code::vulkan_init_failed, - "Requested Vulkan API version not supported"); + "请求的Vulkan API版本不受支持"); } // 应用信息 @@ -130,7 +130,7 @@ namespace mirai { for (const char* ext : enabled_extensions_) { if (!is_extension_supported(ext)) { return MAKE_ERROR_INFO(error_code::vulkan_init_failed, - "Required extension not supported: {}", ext); + "所需的扩展不受支持: {}", ext); } } @@ -176,11 +176,11 @@ namespace mirai { auto [result, instance] = vk::createInstance(create_info); if (result != vk::Result::eSuccess) { return MAKE_ERROR_INFO(error_code::vulkan_init_failed, - "Failed to create Vulkan instance: {}", vk::to_string(result)); + "无法创建Vulkan实例: {}", vk::to_string(result)); } instance_ = instance; - MIRAI_LOG_INFO("Vulkan instance created with API version {}.{}.{}", + MIRAI_LOG_INFO("已使用Vulkan API版本创建设备实例 {}.{}.{}", VK_VERSION_MAJOR(api_version_), VK_VERSION_MINOR(api_version_), VK_VERSION_PATCH(api_version_)); @@ -297,7 +297,7 @@ namespace mirai { vkGetInstanceProcAddr(instance_, "vkCreateDebugUtilsMessengerEXT")); if (!func) { - return MAKE_ERROR_INFO(error_code::vulkan_init_failed, "Could not load vkCreateDebugUtilsMessengerEXT"); + return MAKE_ERROR_INFO(error_code::vulkan_init_failed, "无法加载 vkCreateDebugUtilsMessengerEXT"); } VkDebugUtilsMessengerCreateInfoEXT create_info{}; @@ -316,11 +316,11 @@ namespace mirai { auto result = static_cast(func(static_cast(instance_), &create_info, nullptr, &messenger)); if (result != vk::Result::eSuccess) { - return MAKE_ERROR_INFO(error_code::vulkan_init_failed, "Failed to create debug messenger: {}", vk::to_string(result)); + return MAKE_ERROR_INFO(error_code::vulkan_init_failed, "未能创建Vulkan调试消息传递器: {}", vk::to_string(result)); } debug_messenger_ = messenger; - MIRAI_LOG_DEBUG("Vulkan debug messenger created"); + MIRAI_LOG_DEBUG("Vulkan调试信使已创建完成"); return {}; } diff --git a/src/window/window.cpp b/src/window/window.cpp index a350c9d..5cb9d84 100644 --- a/src/window/window.cpp +++ b/src/window/window.cpp @@ -2,7 +2,10 @@ #include +#include + #include "core/logger.h" +#include "gpu_resource/swapchain.h" #include "render/vulkan_context.h" namespace mirai { @@ -42,7 +45,15 @@ namespace mirai { } void window::update(duration_ms delta_time) { - + if (closing_) { + return; + } + if (need_rebuild_swapchain()) { + auto result = rebuild_swapchain(); + if (!result) { + MIRAI_LOG_ERROR("窗口 {} 交换链重建失败: {}", get_window_title(), result.error().full_description()); + } + } } void window::show_window(bool show) { @@ -70,20 +81,58 @@ namespace mirai { vec2i window::get_pos() const { int x, y; if (!SDL_GetWindowPosition(window_, &x, &y)) { - MIRAI_LOG_ERROR("SDL_GetWindowPosition failed: %s", SDL_GetError()); + MIRAI_LOG_ERROR("SDL_GetWindowPosition 失败: {}", SDL_GetError()); x = 0; y = 0; } return vec2i{x, y}; } + vec2i window::get_framebuffer_size() const { + int width, height; + if (!SDL_GetWindowSizeInPixels(window_, &width, &height)) { + MIRAI_LOG_ERROR("SDL_Vulkan_GetDrawableSize 失败: {}", SDL_GetError()); + width = 0; + height = 0; + } + return vec2i{width, height}; + } + + vec2i window::get_window_size() const { + int width, height; + if (!SDL_GetWindowSize(window_, &width, &height)) { + MIRAI_LOG_ERROR("SDL_GetWindowSize 失败: {}", SDL_GetError()); + width = 0; + height = 0; + } + return vec2i{width, height}; + } + + bool window::need_rebuild_swapchain() const { + if (!swapchain_) + return true; + return false; + } + + void_result_t window::rebuild_swapchain(bool hdr_enabled, vec2i new_extent) { + swapchain_create_info info{}; + info.surface = surface_; + info.hdr_enabled = hdr_enabled; + info.initial_extent = std::move(new_extent); + swapchain_ = make_obj(info); + if (!swapchain_) { + return MAKE_ERROR_INFO(error_code::swapchain_creation_failed, "交换链创建失败"); + } + return {}; + } + void window::on_created() { object::on_created(); - } void window::on_destroying() { object::on_destroying(); + swapchain_.reset(); MIRAI_LOG_INFO("窗口 {} 销毁", get_window_title()); SDL_Vulkan_DestroySurface(vulkan_context::get().get_vk_instance(), surface_, nullptr); SDL_DestroyWindow(window_); diff --git a/src/window/window.h b/src/window/window.h index 2086888..7552712 100644 --- a/src/window/window.h +++ b/src/window/window.h @@ -5,6 +5,10 @@ #include #include +namespace mirai { + class swapchain; +} + namespace mirai { struct window_config { vec2i size; @@ -33,19 +37,27 @@ namespace mirai { std::string get_window_title(); vec2i get_pos() const; + vec2i get_framebuffer_size() const; + vec2i get_window_size() const; auto is_closing() const { return closing_; } auto get_vk_surface() const { return surface_; } + + bool need_rebuild_swapchain() const; + void_result_t rebuild_swapchain(bool hdr_enabled, vec2i new_extent); + void_result_t rebuild_swapchain() { + return rebuild_swapchain(hdr_enabled_, get_framebuffer_size()); + } protected: void on_created() override; void on_destroying() override; - private: - SDL_Window* window_{}; - vk::SurfaceKHR surface_{}; - vk::Instance vk_instance_{}; - bool closing_{false}; + SDL_Window* window_{}; + vk::SurfaceKHR surface_{}; + std::shared_ptr swapchain_{}; + bool closing_{false}; + bool hdr_enabled_{false}; }; }