diff --git a/src/core/aorii.cpp b/src/core/aorii.cpp index a47e2ae..fb57f5b 100644 --- a/src/core/aorii.cpp +++ b/src/core/aorii.cpp @@ -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(); diff --git a/src/core/renderer/device_selector.cpp b/src/core/renderer/device_selector.cpp new file mode 100644 index 0000000..5f2534d --- /dev/null +++ b/src/core/renderer/device_selector.cpp @@ -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 device_selector::get_queue_families(vk::PhysicalDevice in_physical_device, + const vk::QueueFlags& in_flags) { + std::vector 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::get_device_scores( + const std::vector& devices, const vk::SurfaceKHR surface) { + std::vector 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(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& 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; +} diff --git a/src/core/renderer/device_selector.h b/src/core/renderer/device_selector.h index dae9e8e..ff07090 100644 --- a/src/core/renderer/device_selector.h +++ b/src/core/renderer/device_selector.h @@ -8,36 +8,13 @@ class device_selector { public: using device_group = std::vector; - 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 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; - static std::vector get_device_scores(const std::vector& devices, - const vk::SurfaceKHR surface) { - std::vector deviceScores; + static std::vector get_device_scores(const std::vector& 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& 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(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& 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); }; diff --git a/src/core/renderer/renderer.cpp b/src/core/renderer/renderer.cpp index 026fc84..011886a 100644 --- a/src/core/renderer/renderer.cpp +++ b/src/core/renderer/renderer.cpp @@ -112,9 +112,11 @@ bool aorii_renderer::init() { std::vector 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 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 device_extensions; device_extensions.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME); + + std::vector 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& 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 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( + 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; +} + diff --git a/src/core/renderer/renderer.h b/src/core/renderer/renderer.h index 31a270f..9a670ce 100644 --- a/src/core/renderer/renderer.h +++ b/src/core/renderer/renderer.h @@ -5,6 +5,7 @@ #include #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& get_compute_device() const; private: vk::Instance instance; device_selector selector; - device_set main_device; + device_handle main_device; + mutable std::vector compute_device; }; namespace aorii { diff --git a/src/core/renderer/renderer_buffer.cpp b/src/core/renderer/renderer_buffer.cpp index c456e51..e8956a5 100644 --- a/src/core/renderer/renderer_buffer.cpp +++ b/src/core/renderer/renderer_buffer.cpp @@ -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); diff --git a/src/core/renderer/renderer_buffer.h b/src/core/renderer/renderer_buffer.h index 48f57bc..48f6185 100644 --- a/src/core/renderer/renderer_buffer.h +++ b/src/core/renderer/renderer_buffer.h @@ -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; diff --git a/src/core/renderer/renderer_buffer_memory_strategy.cpp b/src/core/renderer/renderer_buffer_memory_strategy.cpp index aa1879e..0892a3f 100644 --- a/src/core/renderer/renderer_buffer_memory_strategy.cpp +++ b/src/core/renderer/renderer_buffer_memory_strategy.cpp @@ -12,7 +12,7 @@ std::unique_ptr 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) { // 创建暂存缓冲区 diff --git a/src/core/renderer/renderer_buffer_memory_strategy.h b/src/core/renderer/renderer_buffer_memory_strategy.h index cedd30c..5206638 100644 --- a/src/core/renderer/renderer_buffer_memory_strategy.h +++ b/src/core/renderer/renderer_buffer_memory_strategy.h @@ -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; }; diff --git a/src/core/renderer/renderer_swapchain.cpp b/src/core/renderer/renderer_swapchain.cpp new file mode 100644 index 0000000..e7e94ff --- /dev/null +++ b/src/core/renderer/renderer_swapchain.cpp @@ -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); + } +} diff --git a/src/core/renderer/renderer_swapchain.h b/src/core/renderer/renderer_swapchain.h new file mode 100644 index 0000000..a57f0f2 --- /dev/null +++ b/src/core/renderer/renderer_swapchain.h @@ -0,0 +1,52 @@ +#pragma once +#include +#include + +#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 images; + std::vector image_views; +}; diff --git a/src/core/renderer/renderer_types.h b/src/core/renderer/renderer_types.h index 317475a..d227004 100644 --- a/src/core/renderer/renderer_types.h +++ b/src/core/renderer/renderer_types.h @@ -1,7 +1,7 @@ #pragma once #include -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; // 获取物理设备名称 diff --git a/src/core/window/mac/renderer_window_mac.mm b/src/core/window/mac/renderer_window_mac.mm deleted file mode 100644 index 758168d..0000000 --- a/src/core/window/mac/renderer_window_mac.mm +++ /dev/null @@ -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; -} diff --git a/src/core/window/renderer_window.cpp b/src/core/window/renderer_window.cpp index ff78203..fd1197d 100644 --- a/src/core/window/renderer_window.cpp +++ b/src/core/window/renderer_window.cpp @@ -3,6 +3,7 @@ #include #include "window_manager.h" +#include 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( + static_cast(glfwGetX11Window(window))); +#elif defined(GLFW_EXPOSE_NATIVE_WAYLAND) + return glfwGetWaylandWindow(window); +#elif defined(GLFW_EXPOSE_NATIVE_EGL) + return static_cast(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(in_width), static_cast(in_height)}); + } } void renderer_window::on_glfw_close() { diff --git a/src/core/window/renderer_window.h b/src/core/window/renderer_window.h index 0bdcf30..be59125 100644 --- a/src/core/window/renderer_window.h +++ b/src/core/window/renderer_window.h @@ -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; }; diff --git a/src/core/window/window_manager.cpp b/src/core/window/window_manager.cpp index 33619cf..4dbc666 100644 --- a/src/core/window/window_manager.cpp +++ b/src/core/window/window_manager.cpp @@ -42,7 +42,7 @@ std::weak_ptr 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()) {