v
This commit is contained in:
parent
aa9398bad9
commit
7e90e0f302
@ -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();
|
||||
|
192
src/core/renderer/device_selector.cpp
Normal file
192
src/core/renderer/device_selector.cpp
Normal 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;
|
||||
}
|
@ -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);
|
||||
};
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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) {
|
||||
|
||||
// 创建暂存缓冲区
|
||||
|
@ -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;
|
||||
};
|
||||
|
175
src/core/renderer/renderer_swapchain.cpp
Normal file
175
src/core/renderer/renderer_swapchain.cpp
Normal 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);
|
||||
}
|
||||
}
|
52
src/core/renderer/renderer_swapchain.h
Normal file
52
src/core/renderer/renderer_swapchain.h
Normal 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;
|
||||
};
|
@ -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;
|
||||
// 获取物理设备名称
|
||||
|
@ -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;
|
||||
}
|
@ -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() {
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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()) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user