vulkan
This commit is contained in:
3
.gitmodules
vendored
3
.gitmodules
vendored
@@ -1,6 +1,3 @@
|
|||||||
[submodule "third_party/LLGL"]
|
|
||||||
path = third_party/LLGL
|
|
||||||
url = https://github.com/LukasBanana/LLGL.git
|
|
||||||
[submodule "third_party/msdfgen"]
|
[submodule "third_party/msdfgen"]
|
||||||
path = third_party/msdfgen
|
path = third_party/msdfgen
|
||||||
url = https://github.com/Chlumsky/msdfgen.git
|
url = https://github.com/Chlumsky/msdfgen.git
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ endif ()
|
|||||||
set(MSDFGEN_USE_SKIA OFF CACHE BOOL "Use Skia for MSDFGen" FORCE)
|
set(MSDFGEN_USE_SKIA OFF CACHE BOOL "Use Skia for MSDFGen" FORCE)
|
||||||
set(MSDFGEN_USE_VCPKG OFF CACHE BOOL "Use VCPKG for MSDFGen" FORCE)
|
set(MSDFGEN_USE_VCPKG OFF CACHE BOOL "Use VCPKG for MSDFGen" FORCE)
|
||||||
set(MSDFGEN_USE_OPENMP ON CACHE BOOL "Use OpenMP for MSDFGen" FORCE)
|
set(MSDFGEN_USE_OPENMP ON CACHE BOOL "Use OpenMP for MSDFGen" FORCE)
|
||||||
set(LLGL_BUILD_STATIC_LIB ON CACHE BOOL "Build LLGL as static library" FORCE)
|
|
||||||
|
|
||||||
include(cmake/retrieve_files.cmake)
|
include(cmake/retrieve_files.cmake)
|
||||||
include(cmake/detect_os.cmake)
|
include(cmake/detect_os.cmake)
|
||||||
|
|||||||
@@ -8,15 +8,10 @@
|
|||||||
#include "window/renderer_window.h"
|
#include "window/renderer_window.h"
|
||||||
|
|
||||||
int main(int argc, char* argv[]) {
|
int main(int argc, char* argv[]) {
|
||||||
aorii::init(renderer_api::vulkan);
|
window_desc desc{};
|
||||||
|
desc.title = "Aorii";
|
||||||
renderer_window::desc_type desc{};
|
desc.resolution.width = 1280;
|
||||||
desc.resolution = { 1280, 1280 };
|
desc.resolution.height = 720;
|
||||||
auto window = aorii::create_renderer_window(desc);
|
desc.resizable = true;
|
||||||
|
return aorii::run(desc);
|
||||||
while (!aorii::should_exit()) {
|
|
||||||
aorii::update();
|
|
||||||
}
|
|
||||||
|
|
||||||
aorii::destroy();
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
project(aorii_core)
|
project(aorii_core)
|
||||||
|
set(CMAKE_CXX_STANDARD 26)
|
||||||
|
|
||||||
find_package(harfbuzz REQUIRED)
|
find_package(harfbuzz REQUIRED)
|
||||||
find_package(Eigen3 REQUIRED)
|
find_package(Eigen3 REQUIRED)
|
||||||
@@ -6,6 +7,7 @@ find_package(spdlog REQUIRED)
|
|||||||
find_package(Boost REQUIRED)
|
find_package(Boost REQUIRED)
|
||||||
find_package(Freetype REQUIRED)
|
find_package(Freetype REQUIRED)
|
||||||
find_package(Vulkan REQUIRED)
|
find_package(Vulkan REQUIRED)
|
||||||
|
find_package(glfw3 REQUIRED)
|
||||||
|
|
||||||
if (APPLE)
|
if (APPLE)
|
||||||
find_library(COCOA_LIBRARY Cocoa)
|
find_library(COCOA_LIBRARY Cocoa)
|
||||||
@@ -15,10 +17,11 @@ set(RENDERER_SOURCES "")
|
|||||||
retrieve_files(${CMAKE_CURRENT_SOURCE_DIR} RENDERER_SOURCES)
|
retrieve_files(${CMAKE_CURRENT_SOURCE_DIR} RENDERER_SOURCES)
|
||||||
|
|
||||||
add_library(${PROJECT_NAME} STATIC ${RENDERER_SOURCES})
|
add_library(${PROJECT_NAME} STATIC ${RENDERER_SOURCES})
|
||||||
target_link_libraries(${PROJECT_NAME} PUBLIC Freetype::Freetype harfbuzz::harfbuzz Eigen3::Eigen spdlog::spdlog msdfgen-full Boost::boost Vulkan::Vulkan)
|
target_link_libraries(${PROJECT_NAME} PUBLIC Freetype::Freetype glfw harfbuzz Eigen3::Eigen spdlog::spdlog msdfgen-full Boost::boost Vulkan::Vulkan)
|
||||||
target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
|
target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
target_compile_definitions(${PROJECT_NAME} PRIVATE NOMINMAX)
|
target_compile_definitions(${PROJECT_NAME} PRIVATE NOMINMAX)
|
||||||
add_os_definitions(${PROJECT_NAME})
|
add_os_definitions(${PROJECT_NAME})
|
||||||
|
configure_glfw_native(${PROJECT_NAME})
|
||||||
if (APPLE)
|
if (APPLE)
|
||||||
target_link_libraries(${PROJECT_NAME} PUBLIC ${COCOA_LIBRARY})
|
target_link_libraries(${PROJECT_NAME} PUBLIC ${COCOA_LIBRARY})
|
||||||
endif ()
|
endif ()
|
||||||
|
|||||||
@@ -60,8 +60,8 @@ public:
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename f, typename callback, typename ...args>
|
template<typename f, typename callback_f, typename ...args>
|
||||||
auto submit_with_callback(f&& in_func, callback&& in_callback, args&&... in_args) {
|
auto submit_with_callback(f&& in_func, callback_f&& in_callback, args&&... in_args) {
|
||||||
using return_type = std::invoke_result_t<f, args...>;
|
using return_type = std::invoke_result_t<f, args...>;
|
||||||
|
|
||||||
if (stop) { throw std::runtime_error("submit on stopped ThreadPool"); }
|
if (stop) { throw std::runtime_error("submit on stopped ThreadPool"); }
|
||||||
@@ -92,7 +92,7 @@ public:
|
|||||||
/**
|
/**
|
||||||
* @brief 提交一个任务到线程池,并在主线程中执行回调函数
|
* @brief 提交一个任务到线程池,并在主线程中执行回调函数
|
||||||
* @tparam f 任务函数类型
|
* @tparam f 任务函数类型
|
||||||
* @tparam callback 回调函数类型
|
* @tparam callback_f 回调函数类型
|
||||||
* @tparam args 任务函数参数类型
|
* @tparam args 任务函数参数类型
|
||||||
* @param in_func 任务函数
|
* @param in_func 任务函数
|
||||||
* @param in_callback 回调函数
|
* @param in_callback 回调函数
|
||||||
@@ -104,8 +104,8 @@ public:
|
|||||||
* auto res = thread_pool.submit_with_main_thread_callback(func, callback, 1, 2);
|
* auto res = thread_pool.submit_with_main_thread_callback(func, callback, 1, 2);
|
||||||
* @endcode
|
* @endcode
|
||||||
*/
|
*/
|
||||||
template<typename f, typename callback, typename ...args>
|
template<typename f, typename callback_f, typename ...args>
|
||||||
auto submit_with_main_thread_callback(f&& in_func, callback&& in_callback, args&&... in_args) {
|
auto submit_with_main_thread_callback(f&& in_func, callback_f&& in_callback, args&&... in_args) {
|
||||||
using return_type = std::invoke_result_t<f, args...>;
|
using return_type = std::invoke_result_t<f, args...>;
|
||||||
|
|
||||||
if (stop) { throw std::runtime_error("submit on stopped ThreadPool"); }
|
if (stop) { throw std::runtime_error("submit on stopped ThreadPool"); }
|
||||||
@@ -117,7 +117,7 @@ public:
|
|||||||
auto res = task->get_future();
|
auto res = task->get_future();
|
||||||
|
|
||||||
{
|
{
|
||||||
auto task_with_callback = [this, task, callback = std::forward<callback>(in_callback), shared_res = res.share()] {
|
auto task_with_callback = [this, task, callback = std::forward<callback_f>(in_callback), shared_res = res.share()] {
|
||||||
std::optional<return_type> callback_value;
|
std::optional<return_type> callback_value;
|
||||||
try {
|
try {
|
||||||
(*task)();
|
(*task)();
|
||||||
|
|||||||
@@ -7,15 +7,10 @@ glyph_cache::~glyph_cache() {
|
|||||||
clear();
|
clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void glyph_cache::initialize(LLGL::RenderSystem& in_render_system) {
|
void glyph_cache::initialize() {
|
||||||
render_system = &in_render_system;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void glyph_cache::clear() {
|
void glyph_cache::clear() {
|
||||||
if (!render_system)
|
|
||||||
return;
|
|
||||||
for (auto& page : active_atlases)
|
|
||||||
render_system->Release(*page.texture);
|
|
||||||
active_atlases.clear();
|
active_atlases.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -27,33 +22,33 @@ glyph_metadata glyph_cache::get_glyph(const glyph_key& in_key) {
|
|||||||
return glyph;
|
return glyph;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool glyph_cache::atlas_page::put_glyph(const LLGL::TextureRegion& in_size, const LLGL::ImageView& in_data,
|
bool glyph_cache::atlas_page::put_glyph(Eigen::AlignedBox2f& out_uv_rect) {
|
||||||
Eigen::AlignedBox2f& out_uv_rect) {
|
// if (current_x + in_size.offset.x > texture->GetDesc().extent.width) {
|
||||||
if (current_x + in_size.offset.x > texture->GetDesc().extent.width) {
|
// current_x = 0;
|
||||||
current_x = 0;
|
// current_y += row_height;
|
||||||
current_y += row_height;
|
// row_height = 0;
|
||||||
row_height = 0;
|
// }
|
||||||
}
|
// if (current_y + in_size.offset.y > texture->GetDesc().extent.height)
|
||||||
if (current_y + in_size.offset.y > texture->GetDesc().extent.height)
|
// return false;
|
||||||
return false;
|
//
|
||||||
|
// render_system->WriteTexture(*texture, in_size, in_data);
|
||||||
render_system->WriteTexture(*texture, in_size, in_data);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
glyph_cache::atlas_page glyph_cache::allocate_space(uint32_t in_width, uint32_t in_height) {
|
glyph_cache::atlas_page glyph_cache::allocate_space(uint32_t in_width, uint32_t in_height) {
|
||||||
LLGL::TextureDescriptor descriptor{};
|
// LLGL::TextureDescriptor descriptor{};
|
||||||
descriptor.type = LLGL::TextureType::Texture2D;
|
// descriptor.type = LLGL::TextureType::Texture2D;
|
||||||
descriptor.cpuAccessFlags = LLGL::CPUAccessFlags::Write;
|
// descriptor.cpuAccessFlags = LLGL::CPUAccessFlags::Write;
|
||||||
descriptor.extent.width = in_width;
|
// descriptor.extent.width = in_width;
|
||||||
descriptor.extent.height = in_height;
|
// descriptor.extent.height = in_height;
|
||||||
|
//
|
||||||
atlas_page page{};
|
// atlas_page page{};
|
||||||
page.texture = render_system->CreateTexture(descriptor);
|
// page.texture = render_system->CreateTexture(descriptor);
|
||||||
|
//
|
||||||
active_atlases.push_back(page);
|
// active_atlases.push_back(page);
|
||||||
return page;
|
// return page;
|
||||||
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
glyph_metadata glyph_cache::make_glyph(const glyph_key& in_key) {
|
glyph_metadata glyph_cache::make_glyph(const glyph_key& in_key) {
|
||||||
|
|||||||
@@ -1,11 +1,9 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <Eigen/Eigen>
|
#include <Eigen/Eigen>
|
||||||
#include <LLGL/Texture.h>
|
|
||||||
|
|
||||||
#include "font_type.h"
|
#include "font_type.h"
|
||||||
#include "containers/lrucache.hpp"
|
#include "containers/lrucache.hpp"
|
||||||
#include "LLGL/RenderSystem.h"
|
|
||||||
|
|
||||||
struct glyph_key {
|
struct glyph_key {
|
||||||
font_family family{};
|
font_family family{};
|
||||||
@@ -40,7 +38,7 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct glyph_metadata {
|
struct glyph_metadata {
|
||||||
LLGL::Texture* atlas_texture;
|
// LLGL::Texture* atlas_texture;
|
||||||
Eigen::AlignedBox2f uv_rect;
|
Eigen::AlignedBox2f uv_rect;
|
||||||
Eigen::Vector2f size;
|
Eigen::Vector2f size;
|
||||||
Eigen::Vector2f bearing;
|
Eigen::Vector2f bearing;
|
||||||
@@ -50,24 +48,24 @@ class glyph_cache {
|
|||||||
public:
|
public:
|
||||||
~glyph_cache();
|
~glyph_cache();
|
||||||
|
|
||||||
void initialize(LLGL::RenderSystem& in_render_system);
|
void initialize();
|
||||||
void clear();
|
void clear();
|
||||||
glyph_metadata get_glyph(const glyph_key& in_key);
|
glyph_metadata get_glyph(const glyph_key& in_key);
|
||||||
private:
|
private:
|
||||||
struct atlas_page {
|
struct atlas_page {
|
||||||
LLGL::Texture* texture = nullptr;
|
// LLGL::Texture* texture = nullptr;
|
||||||
LLGL::RenderSystem* render_system = nullptr;
|
// LLGL::RenderSystem* render_system = nullptr;
|
||||||
uint32_t current_x = 0;
|
uint32_t current_x = 0;
|
||||||
uint32_t current_y = 0;
|
uint32_t current_y = 0;
|
||||||
uint32_t row_height = 0;
|
uint32_t row_height = 0;
|
||||||
|
|
||||||
bool put_glyph(const LLGL::TextureRegion& in_size, const LLGL::ImageView& in_data, Eigen::AlignedBox2f& out_uv_rect);
|
bool put_glyph(Eigen::AlignedBox2f& out_uv_rect);
|
||||||
};
|
};
|
||||||
|
|
||||||
cache::lru_cache<glyph_key, glyph_metadata> metadata_cache{500};
|
cache::lru_cache<glyph_key, glyph_metadata> metadata_cache{500};
|
||||||
std::vector<atlas_page> active_atlases;
|
std::vector<atlas_page> active_atlases;
|
||||||
std::mutex atlas_mutex;
|
std::mutex atlas_mutex;
|
||||||
LLGL::RenderSystem* render_system = nullptr;
|
// LLGL::RenderSystem* render_system = nullptr;
|
||||||
|
|
||||||
atlas_page allocate_space(uint32_t in_width, uint32_t in_height);
|
atlas_page allocate_space(uint32_t in_width, uint32_t in_height);
|
||||||
glyph_metadata make_glyph(const glyph_key& in_key);
|
glyph_metadata make_glyph(const glyph_key& in_key);
|
||||||
|
|||||||
@@ -179,7 +179,7 @@ struct pixel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename U, int N2>
|
template<typename U, int N2>
|
||||||
auto operator=(const pixel<U, N2>& rhs) {
|
auto& operator=(const pixel<U, N2>& rhs) {
|
||||||
constexpr int Num = std::min(N, N2);
|
constexpr int Num = std::min(N, N2);
|
||||||
memset(data, 0, sizeof(data));
|
memset(data, 0, sizeof(data));
|
||||||
for (int i = 0; i < Num; ++i) {
|
for (int i = 0; i < Num; ++i) {
|
||||||
@@ -189,7 +189,7 @@ struct pixel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename U, int N2>
|
template<typename U, int N2>
|
||||||
operator pixel() {
|
explicit operator pixel<U, N2>() {
|
||||||
pixel<U, N2> result = *this;
|
pixel<U, N2> result = *this;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -217,7 +217,7 @@ struct image_accessor {
|
|||||||
void copy_from(const image_accessor<T>& rhs) {
|
void copy_from(const image_accessor<T>& rhs) {
|
||||||
const int temp_width = std::min(width, rhs.width);
|
const int temp_width = std::min(width, rhs.width);
|
||||||
const int temp_height = std::min(height, rhs.height);
|
const int temp_height = std::min(height, rhs.height);
|
||||||
if constexpr (std::is_same<T, float>::value) {
|
if constexpr (std::is_same_v<T, float>) {
|
||||||
auto row_size = std::min(temp_width * sizeof(T), row_pitch);
|
auto row_size = std::min(temp_width * sizeof(T), row_pitch);
|
||||||
for (int y = 0; y < temp_height; ++y) {
|
for (int y = 0; y < temp_height; ++y) {
|
||||||
auto src_row = rhs.get_row(y);
|
auto src_row = rhs.get_row(y);
|
||||||
@@ -304,7 +304,7 @@ struct image_accessor {
|
|||||||
return get_pixel(pos.x(), pos.y());
|
return get_pixel(pos.x(), pos.y());
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_row_pitch(const int in_row_pitch) {
|
void set_row_pitch(const uint64_t in_row_pitch) {
|
||||||
assert(in_row_pitch >= width);
|
assert(in_row_pitch >= width);
|
||||||
row_pitch = in_row_pitch;
|
row_pitch = in_row_pitch;
|
||||||
}
|
}
|
||||||
@@ -326,9 +326,9 @@ struct image_accessor {
|
|||||||
void* const data;
|
void* const data;
|
||||||
const int width;
|
const int width;
|
||||||
const int height;
|
const int height;
|
||||||
int row_pitch; // 行跨度,支持对齐
|
uint64_t row_pitch; // 行跨度,支持对齐
|
||||||
private:
|
private:
|
||||||
uint8_t* get_row(const int y) const {
|
[[nodiscard]] uint8_t* get_row(const int y) const {
|
||||||
return (uint8_t*)data + y * row_pitch;
|
return (uint8_t*)data + y * row_pitch;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -15,13 +15,13 @@ void pipeline::destroy() {
|
|||||||
|
|
||||||
void pipeline::set_triangle(const std::span<const aorii_vertex>& in_vertexes,
|
void pipeline::set_triangle(const std::span<const aorii_vertex>& in_vertexes,
|
||||||
const std::span<const aorii_triangle>& in_triangles) {
|
const std::span<const aorii_triangle>& in_triangles) {
|
||||||
if (vertex_buffer->get_size() < in_vertexes.size()) { vertex_buffer->resize(static_cast<int>(in_vertexes.size())); }
|
// if (vertex_buffer->get_size() < in_vertexes.size()) { vertex_buffer->resize(static_cast<int>(in_vertexes.size())); }
|
||||||
const auto v_buffer = static_cast<aorii_vertex*>(vertex_buffer->lock());
|
// const auto v_buffer = static_cast<aorii_vertex*>(vertex_buffer->lock());
|
||||||
std::ranges::copy(in_vertexes, v_buffer);
|
// std::ranges::copy(in_vertexes, v_buffer);
|
||||||
vertex_buffer->unlock();
|
// vertex_buffer->unlock();
|
||||||
|
//
|
||||||
if (index_buffer->get_size() < in_triangles.size()) { index_buffer->resize(static_cast<int>(in_triangles.size())); }
|
// if (index_buffer->get_size() < in_triangles.size()) { index_buffer->resize(static_cast<int>(in_triangles.size())); }
|
||||||
const auto i_buffer = static_cast<aorii_triangle*>(index_buffer->lock());
|
// const auto i_buffer = static_cast<aorii_triangle*>(index_buffer->lock());
|
||||||
std::ranges::copy(in_triangles, i_buffer);
|
// std::ranges::copy(in_triangles, i_buffer);
|
||||||
index_buffer->unlock();
|
// index_buffer->unlock();
|
||||||
}
|
}
|
||||||
|
|||||||
176
src/core/renderer/device_selector.h
Normal file
176
src/core/renderer/device_selector.h
Normal file
@@ -0,0 +1,176 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <vector>
|
||||||
|
#include <vulkan/vulkan.hpp>
|
||||||
|
#include <spdlog/spdlog.h>
|
||||||
|
|
||||||
|
class device_selector {
|
||||||
|
enum class device_type { combined, display, compute, unknown };
|
||||||
|
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();
|
||||||
|
|
||||||
|
// 获取设备的评分列表
|
||||||
|
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 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
device_group combined_group; // 同时支持显示和计算的设备组
|
||||||
|
device_group display_group; // 显示设备组
|
||||||
|
device_group compute_group; // 计算设备组
|
||||||
|
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;
|
||||||
|
|
||||||
|
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, 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分
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -10,10 +10,6 @@
|
|||||||
#include "window/window_manager.h"
|
#include "window/window_manager.h"
|
||||||
#include "misc/stb_image.h"
|
#include "misc/stb_image.h"
|
||||||
|
|
||||||
#if DX_BACKEND
|
|
||||||
#include "backend/dx/dx_renderer.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
using time_type = decltype(std::chrono::high_resolution_clock::now());
|
using time_type = decltype(std::chrono::high_resolution_clock::now());
|
||||||
std::chrono::duration<double> delta_time = {};
|
std::chrono::duration<double> delta_time = {};
|
||||||
time_type begin_time = {};
|
time_type begin_time = {};
|
||||||
@@ -73,15 +69,42 @@ aorii_renderer* s_renderer{};
|
|||||||
// return texture;
|
// return texture;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
bool aorii::init() {
|
namespace aorii {
|
||||||
create_renderer();
|
bool init(const window_desc& in_main_window_desc) {
|
||||||
create_window_manager();
|
if (!create_window_manager())
|
||||||
return true;
|
return false;
|
||||||
|
const auto main_window = get_window_manager()->create_window(in_main_window_desc);
|
||||||
|
if (!create_renderer())
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void destroy() {
|
||||||
|
destroy_renderer();
|
||||||
|
destroy_window_manager();
|
||||||
|
}
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void aorii::destroy() {
|
int aorii::run(const window_desc& in_main_window_desc) {
|
||||||
destroy_window_manager();
|
if (!init(in_main_window_desc))
|
||||||
destroy_renderer();
|
return -1;
|
||||||
|
while (!should_exit()) {
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
destroy();
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
aorii_renderer* aorii::get_renderer() {
|
aorii_renderer* aorii::get_renderer() {
|
||||||
@@ -95,6 +118,12 @@ bool aorii::create_renderer() {
|
|||||||
if (s_renderer) return true;
|
if (s_renderer) return true;
|
||||||
|
|
||||||
s_renderer = new aorii_renderer();
|
s_renderer = new aorii_renderer();
|
||||||
|
if (!s_renderer->init()) {
|
||||||
|
delete s_renderer;
|
||||||
|
s_renderer = nullptr;
|
||||||
|
spdlog::error("创建渲染器失败");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
last_time = std::chrono::high_resolution_clock::now();
|
last_time = std::chrono::high_resolution_clock::now();
|
||||||
return s_renderer != nullptr;
|
return s_renderer != nullptr;
|
||||||
}
|
}
|
||||||
@@ -102,22 +131,11 @@ bool aorii::create_renderer() {
|
|||||||
void aorii::destroy_renderer() {
|
void aorii::destroy_renderer() {
|
||||||
if (!s_renderer) return;
|
if (!s_renderer) return;
|
||||||
|
|
||||||
|
s_renderer->destroy();
|
||||||
delete s_renderer;
|
delete s_renderer;
|
||||||
aorii_text::destroy_freetype();
|
aorii_text::destroy_freetype();
|
||||||
}
|
}
|
||||||
|
|
||||||
void aorii::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;
|
|
||||||
|
|
||||||
s_window_manager->update();
|
|
||||||
|
|
||||||
std::this_thread::yield();
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::chrono::duration<double>& aorii::get_delta_time() {
|
const std::chrono::duration<double>& aorii::get_delta_time() {
|
||||||
return delta_time;
|
return delta_time;
|
||||||
}
|
}
|
||||||
@@ -125,3 +143,81 @@ const std::chrono::duration<double>& aorii::get_delta_time() {
|
|||||||
std::chrono::duration<double> aorii::get_total_time() {
|
std::chrono::duration<double> aorii::get_total_time() {
|
||||||
return std::chrono::high_resolution_clock::now() - begin_time;
|
return std::chrono::high_resolution_clock::now() - begin_time;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool aorii_renderer::init() {
|
||||||
|
spdlog::info("初始化渲染器");
|
||||||
|
vk::ApplicationInfo app_info{};
|
||||||
|
app_info.setPEngineName("Aorii");
|
||||||
|
app_info.setEngineVersion(VK_MAKE_VERSION(1, 0, 0));
|
||||||
|
app_info.setApiVersion(VK_API_VERSION_1_0);
|
||||||
|
app_info.setPApplicationName("AoriiHelloWorld");
|
||||||
|
app_info.setApplicationVersion(VK_MAKE_VERSION(1, 0, 0));
|
||||||
|
|
||||||
|
vk::InstanceCreateInfo create_info{};
|
||||||
|
create_info.setPApplicationInfo(&app_info);
|
||||||
|
|
||||||
|
std::vector<const char*> extensions;
|
||||||
|
// #if DEBUG
|
||||||
|
// extensions.push_back(VK_EXT_DEBUG_REPORT_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) {
|
||||||
|
extensions.push_back(glfw_extensions[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
create_info.setPEnabledExtensionNames(extensions);
|
||||||
|
|
||||||
|
instance = createInstance(create_info);
|
||||||
|
if (!instance) {
|
||||||
|
spdlog::critical("创建 Vulkan 实例失败");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto& main_window = aorii::get_window_manager()->get_main_window().lock();
|
||||||
|
if (!main_window->create_surface())
|
||||||
|
return false;
|
||||||
|
selector.classify_and_sort_devices(instance, main_window->get_surface());
|
||||||
|
|
||||||
|
std::vector<const char*> device_extensions;
|
||||||
|
device_extensions.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
|
||||||
|
vk::DeviceCreateInfo device_create_info{};
|
||||||
|
device_create_info.setPEnabledExtensionNames(device_extensions);
|
||||||
|
main_device.create_device(selector.get_main_device(), device_create_info);
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void aorii_renderer::destroy() {
|
||||||
|
instance.destroy();
|
||||||
|
glfwTerminate();
|
||||||
|
}
|
||||||
|
|
||||||
|
vk::SurfaceKHR aorii_renderer::create_surface(GLFWwindow* in_window) {
|
||||||
|
VkSurfaceKHR surface;
|
||||||
|
if (instance && glfwCreateWindowSurface(instance, in_window, nullptr, &surface) != VK_SUCCESS) {
|
||||||
|
spdlog::critical("创建窗口表面失败");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return vk::SurfaceKHR(surface);
|
||||||
|
}
|
||||||
|
|
||||||
|
vk::SwapchainKHR aorii_renderer::create_swap_chain(const vk::SwapchainCreateInfoKHR& in_create_info) {
|
||||||
|
return main_device->createSwapchainKHR(in_create_info);
|
||||||
|
}
|
||||||
|
|||||||
@@ -2,23 +2,33 @@
|
|||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <vulkan/vulkan.hpp>
|
#include <vulkan/vulkan.hpp>
|
||||||
|
#include <GLFW/glfw3.h>
|
||||||
|
|
||||||
|
#include "device_selector.h"
|
||||||
|
#include "renderer_types.h"
|
||||||
|
|
||||||
|
struct window_desc;
|
||||||
|
|
||||||
class aorii_renderer {
|
class aorii_renderer {
|
||||||
public:
|
public:
|
||||||
|
bool init();
|
||||||
|
void destroy();
|
||||||
|
|
||||||
|
vk::SurfaceKHR create_surface(GLFWwindow* in_window);
|
||||||
|
vk::SwapchainKHR create_swap_chain(const vk::SwapchainCreateInfoKHR& in_create_info);
|
||||||
private:
|
private:
|
||||||
|
vk::Instance instance;
|
||||||
|
device_selector selector;
|
||||||
|
device_set main_device;
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace aorii {
|
namespace aorii {
|
||||||
bool init();
|
int run(const window_desc& in_main_window_desc);
|
||||||
void destroy();
|
|
||||||
|
|
||||||
aorii_renderer* get_renderer();
|
aorii_renderer* get_renderer();
|
||||||
|
|
||||||
bool create_renderer();
|
bool create_renderer();
|
||||||
void destroy_renderer();
|
void destroy_renderer();
|
||||||
void update();
|
|
||||||
|
|
||||||
const std::chrono::duration<double>& get_delta_time();
|
const std::chrono::duration<double>& get_delta_time();
|
||||||
std::chrono::duration<double> get_total_time();
|
std::chrono::duration<double> get_total_time();
|
||||||
|
|||||||
@@ -1,20 +1,85 @@
|
|||||||
#include "renderer_buffer.h"
|
#include "renderer_buffer.h"
|
||||||
|
|
||||||
void renderer_buffer::resize(const uint64_t new_size) {
|
#include "renderer_buffer_memory_strategy.h"
|
||||||
if (new_size == get_size())
|
|
||||||
|
uint32_t device_set::get_physical_device_id() const {
|
||||||
|
const auto& props = physical_device.getProperties();
|
||||||
|
return props.deviceID;
|
||||||
|
}
|
||||||
|
|
||||||
|
renderer_buffer_desc::operator vk::BufferCreateInfo() const {
|
||||||
|
vk::BufferCreateInfo buffer_info;
|
||||||
|
buffer_info.size = size;
|
||||||
|
buffer_info.usage = usage_flags;
|
||||||
|
buffer_info.sharingMode = concurrent ? vk::SharingMode::eConcurrent : vk::SharingMode::eExclusive;
|
||||||
|
buffer_info.queueFamilyIndexCount = static_cast<uint32_t>(queue_families.size());
|
||||||
|
buffer_info.pQueueFamilyIndices = queue_families.data();
|
||||||
|
return buffer_info;
|
||||||
|
}
|
||||||
|
|
||||||
|
renderer_buffer::renderer_buffer(const device_set& in_device, const renderer_buffer_desc& in_desc) {
|
||||||
|
device = in_device;
|
||||||
|
desc = in_desc;
|
||||||
|
memory_strategy = buffer_memory_strategy::create(in_desc.memory_props);
|
||||||
|
|
||||||
|
buffer = in_device->createBuffer(in_desc);
|
||||||
|
|
||||||
|
const auto& mem_reqs = in_device->getBufferMemoryRequirements(buffer);
|
||||||
|
memory = allocate_memory(mem_reqs, in_desc.memory_props);
|
||||||
|
|
||||||
|
device->bindBufferMemory(buffer, memory, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderer_buffer::~renderer_buffer() {
|
||||||
|
device->destroyBuffer(buffer);
|
||||||
|
device->freeMemory(memory);
|
||||||
|
}
|
||||||
|
|
||||||
|
void renderer_buffer::copy_from(const void* in_data, vk::DeviceSize in_size, vk::CommandBuffer in_command_buffer) {
|
||||||
|
memory_strategy->copy_from(device, buffer, memory, in_data, in_size, in_command_buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void renderer_buffer::resize(const vk::DeviceSize in_new_size, const vk::CommandBuffer in_command_buffer, const bool in_preserve_data, const bool in_allow_in_place,
|
||||||
|
const float in_growth_factor) {
|
||||||
|
const vk::DeviceSize old_size = get_size();
|
||||||
|
if (in_new_size == old_size)
|
||||||
return;
|
return;
|
||||||
if (new_size < 1) {
|
|
||||||
|
// 如果允许原地扩展并且可以原地扩展
|
||||||
|
if (in_allow_in_place && try_resize_in_place(in_new_size)) {
|
||||||
|
desc.size = in_new_size;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
void* temp_buffer = malloc(new_size);
|
|
||||||
ON_SCOPE_EXIT {
|
|
||||||
free(temp_buffer);
|
|
||||||
};
|
|
||||||
auto new_desc = get_desc();
|
|
||||||
new_desc.size = new_size;
|
|
||||||
const auto new_buffer = aorii::get_renderer()->CreateBuffer(new_desc, temp_buffer);
|
|
||||||
|
|
||||||
aorii::get_command_buffer()->CopyBuffer(*new_buffer, 0, *buffer, 0, std::min(get_size(), new_size));
|
// 计算新的大小
|
||||||
aorii::get_renderer()->Release(*buffer);
|
desc.size = calculate_new_size(in_new_size, in_growth_factor);
|
||||||
|
|
||||||
|
// 创建新的缓冲区
|
||||||
|
const auto& mem_reqs = device->getBufferMemoryRequirements(buffer);
|
||||||
|
const auto new_memory = allocate_memory(mem_reqs, desc.memory_props);
|
||||||
|
const auto new_buffer = device->createBuffer(desc);
|
||||||
|
device->bindBufferMemory(new_buffer, new_memory, 0);
|
||||||
|
|
||||||
|
// 如果需要保留数据
|
||||||
|
if (in_preserve_data) {
|
||||||
|
if (desc.is_host_visible()) {
|
||||||
|
void* src_data = device->mapMemory(memory, 0, old_size);
|
||||||
|
void* dst_data = device->mapMemory(new_memory, 0, desc.size);
|
||||||
|
memcpy(dst_data, src_data, std::min(old_size, desc.size));
|
||||||
|
device->unmapMemory(memory);
|
||||||
|
device->unmapMemory(new_memory);
|
||||||
|
} else {
|
||||||
|
vk::BufferCopy copy_region {};
|
||||||
|
copy_region.size = std::min(old_size, desc.size);
|
||||||
|
in_command_buffer.copyBuffer(buffer, new_buffer, copy_region);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 释放原有资源
|
||||||
|
device->destroyBuffer(buffer);
|
||||||
|
device->freeMemory(memory);
|
||||||
|
// 更新资源
|
||||||
buffer = new_buffer;
|
buffer = new_buffer;
|
||||||
|
memory = new_memory;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,45 +2,81 @@
|
|||||||
#include <span>
|
#include <span>
|
||||||
#include <spdlog/spdlog.h>
|
#include <spdlog/spdlog.h>
|
||||||
|
|
||||||
#include "LLGL/Buffer.h"
|
#include "renderer_types.h"
|
||||||
#include "LLGL/RenderSystem.h"
|
|
||||||
#include "renderer.h"
|
class buffer_memory_strategy;
|
||||||
#include "misc/scope_exit.h"
|
|
||||||
|
|
||||||
class renderer_buffer {
|
class renderer_buffer {
|
||||||
public:
|
public:
|
||||||
explicit renderer_buffer(const LLGL::BufferDescriptor& in_desc) {
|
explicit renderer_buffer(const device_set& in_device, const renderer_buffer_desc& in_desc);
|
||||||
buffer = aorii::get_renderer()->CreateBuffer(in_desc);
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual ~renderer_buffer() {
|
virtual ~renderer_buffer();
|
||||||
aorii::get_renderer()->Release(*buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void* lock(const LLGL::CPUAccess access = LLGL::CPUAccess::WriteDiscard) {
|
[[nodiscard]] const auto& get_memory() const {
|
||||||
return aorii::get_renderer()->MapBuffer(*buffer, access);
|
return memory;
|
||||||
}
|
}
|
||||||
virtual void unlock() {
|
[[nodiscard]] const auto& get_desc() const {
|
||||||
return aorii::get_renderer()->UnmapBuffer(*buffer);
|
return desc;
|
||||||
}
|
|
||||||
|
|
||||||
template<class T>
|
|
||||||
void set_data(const T& in_data) {
|
|
||||||
aorii::get_command_buffer()->UpdateBuffer(*buffer, 0, &in_data, sizeof(T));
|
|
||||||
}
|
|
||||||
template<class T>
|
|
||||||
void set_data(const std::span<const T>& in_data) {
|
|
||||||
aorii::get_command_buffer()->UpdateBuffer(*buffer, 0, in_data.data(), sizeof(T) * in_data.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
void resize(uint64_t new_size);
|
|
||||||
|
|
||||||
[[nodiscard]] auto get_desc() const {
|
|
||||||
return buffer->GetDesc();
|
|
||||||
}
|
}
|
||||||
[[nodiscard]] auto get_size() const {
|
[[nodiscard]] auto get_size() const {
|
||||||
return get_desc().size;
|
return desc.size;
|
||||||
}
|
}
|
||||||
|
[[nodiscard]] auto get_buffer() const {
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
void set_data(const T& in_data, vk::CommandBuffer in_command_buffer = nullptr) {
|
||||||
|
copy_from(&in_data, sizeof(T), in_command_buffer);
|
||||||
|
}
|
||||||
|
template<class T>
|
||||||
|
void set_data(const std::span<const T>& in_data, vk::CommandBuffer in_command_buffer = nullptr) {
|
||||||
|
copy_from(in_data.data(), in_data.size_bytes(), in_command_buffer);
|
||||||
|
}
|
||||||
|
void copy_from(const void* in_data, vk::DeviceSize in_size, vk::CommandBuffer in_command_buffer = nullptr);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 重新分配缓冲区大小
|
||||||
|
* @param in_new_size 新的大小
|
||||||
|
* @param in_command_buffer 命令缓冲区
|
||||||
|
* @param in_preserve_data 是否保留原有数据
|
||||||
|
* @param in_allow_in_place 是否允许原地扩展
|
||||||
|
* @param in_growth_factor 扩展因子
|
||||||
|
*/
|
||||||
|
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:
|
protected:
|
||||||
LLGL::Buffer* buffer;
|
device_set device;
|
||||||
|
renderer_buffer_desc desc;
|
||||||
|
vk::Buffer buffer;
|
||||||
|
vk::DeviceMemory memory;
|
||||||
|
std::unique_ptr<buffer_memory_strategy> memory_strategy;
|
||||||
|
private:
|
||||||
|
[[nodiscard]] auto find_memory_type(const uint32_t type_filter, const vk::MemoryPropertyFlags properties) const {
|
||||||
|
const auto& mem_properties = device.physical_device.getMemoryProperties();
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < mem_properties.memoryTypeCount; i++) {
|
||||||
|
if ((type_filter & (1 << i)) && (mem_properties.memoryTypes[i].propertyFlags & properties) == properties) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw std::runtime_error("failed to find suitable memory type!");
|
||||||
|
}
|
||||||
|
|
||||||
|
vk::DeviceMemory allocate_memory(const vk::MemoryRequirements& in_requirements, vk::MemoryPropertyFlags props) {
|
||||||
|
vk::MemoryAllocateInfo alloc_info;
|
||||||
|
alloc_info.allocationSize = in_requirements.size;
|
||||||
|
alloc_info.memoryTypeIndex = find_memory_type(in_requirements.memoryTypeBits, props);
|
||||||
|
|
||||||
|
return device->allocateMemory(alloc_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool try_resize_in_place(vk::DeviceSize in_size) {
|
||||||
|
const auto& mem_props = device->getBufferMemoryRequirements(buffer);
|
||||||
|
return in_size <= mem_props.size;
|
||||||
|
}
|
||||||
|
[[nodiscard]] vk::DeviceSize calculate_new_size(const vk::DeviceSize in_new_size, const float in_growth_factor) const {
|
||||||
|
const vk::DeviceSize growth_size = get_size() * in_growth_factor;
|
||||||
|
return std::max(in_new_size, growth_size);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
44
src/core/renderer/renderer_buffer_memory_strategy.cpp
Normal file
44
src/core/renderer/renderer_buffer_memory_strategy.cpp
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
#include "renderer_buffer_memory_strategy.h"
|
||||||
|
|
||||||
|
#include "renderer_buffer.h"
|
||||||
|
|
||||||
|
std::unique_ptr<buffer_memory_strategy> buffer_memory_strategy::create(vk::MemoryPropertyFlags in_memory_props) {
|
||||||
|
if (in_memory_props & vk::MemoryPropertyFlagBits::eHostVisible) {
|
||||||
|
return std::make_unique<host_visible_strategy>();
|
||||||
|
}
|
||||||
|
if (in_memory_props & vk::MemoryPropertyFlagBits::eDeviceLocal) {
|
||||||
|
return std::make_unique<device_local_strategy>();
|
||||||
|
}
|
||||||
|
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,
|
||||||
|
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);
|
||||||
|
|
||||||
|
vk::MappedMemoryRange range;
|
||||||
|
range.memory = in_device_memory;
|
||||||
|
range.offset = 0;
|
||||||
|
range.size = in_size;
|
||||||
|
in_device->flushMappedMemoryRanges(range);
|
||||||
|
|
||||||
|
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,
|
||||||
|
const void* in_data, const vk::DeviceSize in_size, vk::CommandBuffer in_command_buffer) {
|
||||||
|
|
||||||
|
// 创建暂存缓冲区
|
||||||
|
const renderer_buffer staging_buffer(in_device, renderer_buffer_desc::staging_buffer(in_size));
|
||||||
|
|
||||||
|
// 复制数据到暂存缓冲区
|
||||||
|
void* mapped = in_device->mapMemory(staging_buffer.get_memory(), 0, in_size);
|
||||||
|
std::memcpy(mapped, in_data, in_size);
|
||||||
|
in_device->unmapMemory(staging_buffer.get_memory());
|
||||||
|
|
||||||
|
// 记录复制命令
|
||||||
|
vk::BufferCopy copy_region{};
|
||||||
|
copy_region.size = in_size;
|
||||||
|
in_command_buffer.copyBuffer(staging_buffer.get_buffer(), in_buffer, copy_region);
|
||||||
|
}
|
||||||
26
src/core/renderer/renderer_buffer_memory_strategy.h
Normal file
26
src/core/renderer/renderer_buffer_memory_strategy.h
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <vulkan/vulkan.hpp>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include "renderer_types.h"
|
||||||
|
|
||||||
|
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,
|
||||||
|
const void* in_data, vk::DeviceSize in_size,
|
||||||
|
vk::CommandBuffer in_command_buffer) = 0;
|
||||||
|
|
||||||
|
static std::unique_ptr<buffer_memory_strategy> create(vk::MemoryPropertyFlags in_memory_props);
|
||||||
|
};
|
||||||
|
|
||||||
|
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;
|
||||||
|
};
|
||||||
|
|
||||||
|
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;
|
||||||
|
};
|
||||||
84
src/core/renderer/renderer_types.h
Normal file
84
src/core/renderer/renderer_types.h
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <vulkan/vulkan.hpp>
|
||||||
|
|
||||||
|
struct device_set {
|
||||||
|
vk::PhysicalDevice physical_device;
|
||||||
|
vk::Device device;
|
||||||
|
|
||||||
|
// 重载->运算符,使得device_set可以直接调用vk::Device的成员函数
|
||||||
|
vk::Device* operator->() { return &device; }
|
||||||
|
const vk::Device* operator->() const { return &device; }
|
||||||
|
|
||||||
|
explicit operator vk::PhysicalDevice() const { return physical_device; }
|
||||||
|
explicit operator vk::Device() const { return device; }
|
||||||
|
operator bool() const { return static_cast<bool>(device); }
|
||||||
|
bool operator!() const { return !device; }
|
||||||
|
|
||||||
|
void create_device(const vk::PhysicalDevice in_physical_device, const vk::DeviceCreateInfo& in_create_info) {
|
||||||
|
physical_device = in_physical_device;
|
||||||
|
device = physical_device.createDevice(in_create_info);
|
||||||
|
}
|
||||||
|
// 获取物理设备GUID
|
||||||
|
[[nodiscard]] uint32_t get_physical_device_id() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct renderer_buffer_desc {
|
||||||
|
// 大小
|
||||||
|
vk::DeviceSize size;
|
||||||
|
// 缓冲使用标志
|
||||||
|
vk::BufferUsageFlags usage_flags;
|
||||||
|
// 内存属性
|
||||||
|
vk::MemoryPropertyFlags memory_props;
|
||||||
|
// 内存共享标志
|
||||||
|
bool concurrent = false;
|
||||||
|
// 队列族
|
||||||
|
std::vector<uint32_t> queue_families;
|
||||||
|
|
||||||
|
[[nodiscard]] bool is_host_visible() const {
|
||||||
|
return (memory_props & vk::MemoryPropertyFlagBits::eHostVisible)
|
||||||
|
== vk::MemoryPropertyFlagBits::eHostVisible;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] bool is_device_local() const {
|
||||||
|
return (memory_props & vk::MemoryPropertyFlagBits::eDeviceLocal)
|
||||||
|
== vk::MemoryPropertyFlagBits::eDeviceLocal;
|
||||||
|
}
|
||||||
|
|
||||||
|
operator vk::BufferCreateInfo() const;
|
||||||
|
operator vk::BufferCreateInfo() {
|
||||||
|
return static_cast<const renderer_buffer_desc&>(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
static renderer_buffer_desc staging_buffer(const vk::DeviceSize in_size) {
|
||||||
|
return {
|
||||||
|
.size = in_size,
|
||||||
|
.usage_flags = vk::BufferUsageFlagBits::eTransferSrc,
|
||||||
|
.memory_props = vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static renderer_buffer_desc uniform_buffer(const vk::DeviceSize in_size) {
|
||||||
|
return {
|
||||||
|
.size = in_size,
|
||||||
|
.usage_flags = vk::BufferUsageFlagBits::eUniformBuffer,
|
||||||
|
.memory_props = vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static renderer_buffer_desc index_buffer(const vk::DeviceSize in_size) {
|
||||||
|
return {
|
||||||
|
.size = in_size,
|
||||||
|
.usage_flags = vk::BufferUsageFlagBits::eIndexBuffer | vk::BufferUsageFlagBits::eTransferDst,
|
||||||
|
.memory_props = vk::MemoryPropertyFlagBits::eDeviceLocal
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static renderer_buffer_desc vertex_buffer(const vk::DeviceSize in_size) {
|
||||||
|
return {
|
||||||
|
.size = in_size,
|
||||||
|
.usage_flags = vk::BufferUsageFlagBits::eVertexBuffer | vk::BufferUsageFlagBits::eTransferDst,
|
||||||
|
.memory_props = vk::MemoryPropertyFlagBits::eDeviceLocal
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
91
src/core/window/renderer_window.cpp
Normal file
91
src/core/window/renderer_window.cpp
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
#include "renderer_window.h"
|
||||||
|
|
||||||
|
#include <spdlog/spdlog.h>
|
||||||
|
|
||||||
|
#include "window_manager.h"
|
||||||
|
|
||||||
|
renderer_window::renderer_window(const window_desc& in_desc) {
|
||||||
|
glfwWindowHint(GLFW_RESIZABLE, in_desc.resizable);
|
||||||
|
glfwWindowHint(GLFW_DECORATED, in_desc.decorated);
|
||||||
|
glfwWindowHint(GLFW_VISIBLE, in_desc.visible);
|
||||||
|
glfwWindowHint(GLFW_FOCUSED, in_desc.focused);
|
||||||
|
glfwWindowHint(GLFW_FOCUS_ON_SHOW, in_desc.focus_on_show);
|
||||||
|
glfwWindowHint(GLFW_MAXIMIZED, in_desc.maximized);
|
||||||
|
glfwWindowHint(GLFW_FLOATING, in_desc.floating);
|
||||||
|
glfwWindowHint(GLFW_CENTER_CURSOR, in_desc.center_cursor);
|
||||||
|
glfwWindowHint(GLFW_TRANSPARENT_FRAMEBUFFER, in_desc.transparent);
|
||||||
|
|
||||||
|
window = glfwCreateWindow(in_desc.resolution.width, in_desc.resolution.height, in_desc.title.c_str(), in_desc.monitor, nullptr);
|
||||||
|
glfwSetWindowUserPointer(window, this);
|
||||||
|
if (!window) {
|
||||||
|
spdlog::error("Failed to create window");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
glfwSetWindowSizeCallback(window, [](GLFWwindow* in_window, int in_width, int in_height) {
|
||||||
|
const auto my_window = static_cast<renderer_window*>(glfwGetWindowUserPointer(in_window));
|
||||||
|
my_window->on_resize(in_width, in_height);
|
||||||
|
});
|
||||||
|
glfwSetWindowCloseCallback(window, [](GLFWwindow* in_window) {
|
||||||
|
const auto my_window = static_cast<renderer_window*>(glfwGetWindowUserPointer(in_window));
|
||||||
|
my_window->on_glfw_close();
|
||||||
|
});
|
||||||
|
|
||||||
|
if (in_desc.create_surface) {
|
||||||
|
create_surface();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
renderer_window::~renderer_window() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void renderer_window::set_title(const std::wstring& in_title) const {
|
||||||
|
}
|
||||||
|
|
||||||
|
void renderer_window::close() const {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool renderer_window::create_surface() {
|
||||||
|
const auto renderer = aorii::get_renderer();
|
||||||
|
if (!renderer)
|
||||||
|
return false;
|
||||||
|
surface = renderer->create_surface(window);
|
||||||
|
if (!surface) {
|
||||||
|
spdlog::error("创建窗口表面失败");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool renderer_window::create_swap_chain(vk::SwapchainCreateInfoKHR in_create_info) {
|
||||||
|
const auto renderer = aorii::get_renderer();
|
||||||
|
if (!renderer)
|
||||||
|
return false;
|
||||||
|
if (!surface) {
|
||||||
|
spdlog::error("窗口表面未创建");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
in_create_info.setSurface(surface);
|
||||||
|
swap_chain = renderer->create_swap_chain(in_create_info);
|
||||||
|
if (!swap_chain) {
|
||||||
|
spdlog::error("创建交换链失败");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if !AORII_MACOS
|
||||||
|
void* renderer_window::get_native_handle() const {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void renderer_window::on_resize(int in_width, int in_height) {
|
||||||
|
spdlog::info("窗口大小变更:{}x{}", in_width, in_height);
|
||||||
|
}
|
||||||
|
|
||||||
|
void renderer_window::on_glfw_close() {
|
||||||
|
spdlog::info("窗口关闭");
|
||||||
|
aorii::get_window_manager()->destroy_window(this);
|
||||||
|
}
|
||||||
@@ -3,55 +3,58 @@
|
|||||||
|
|
||||||
#include "vulkan/vulkan.hpp"
|
#include "vulkan/vulkan.hpp"
|
||||||
|
|
||||||
|
struct window_desc {
|
||||||
|
std::string title;
|
||||||
|
vk::Extent2D resolution;
|
||||||
|
GLFWmonitor* monitor = nullptr;
|
||||||
|
bool fullscreen = false;
|
||||||
|
bool resizable = true;
|
||||||
|
bool borderless = false;
|
||||||
|
bool vsync = true;
|
||||||
|
bool always_on_top = false;
|
||||||
|
bool transparent = false;
|
||||||
|
bool decorated = true;
|
||||||
|
bool focused = true;
|
||||||
|
bool focus_on_show = true;
|
||||||
|
bool maximized = false;
|
||||||
|
bool visible = true;
|
||||||
|
bool floating = false;
|
||||||
|
bool center_cursor = false;
|
||||||
|
bool create_surface = true;
|
||||||
|
};
|
||||||
|
|
||||||
class renderer_window {
|
class renderer_window {
|
||||||
friend class window_manager;
|
friend class window_manager;
|
||||||
public:
|
public:
|
||||||
explicit renderer_window();
|
explicit renderer_window(const window_desc& in_desc);
|
||||||
|
|
||||||
virtual ~renderer_window();
|
virtual ~renderer_window();
|
||||||
|
|
||||||
void set_title(const std::wstring& in_title) const;
|
void set_title(const std::wstring& in_title) const;
|
||||||
|
|
||||||
void close() const;
|
void close() const;
|
||||||
|
bool should_close() const { return glfwWindowShouldClose(window); }
|
||||||
|
|
||||||
|
vk::Extent2D get_size() const {
|
||||||
|
int width, height;
|
||||||
|
glfwGetWindowSize(window, &width, &height);
|
||||||
|
return vk::Extent2D(width, height);
|
||||||
|
}
|
||||||
|
vk::Extent2D get_framebuffer_size() const {
|
||||||
|
int width, height;
|
||||||
|
glfwGetFramebufferSize(window, &width, &height);
|
||||||
|
return vk::Extent2D(width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool create_surface();
|
||||||
[[nodiscard]] auto get_surface() const { return 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; }
|
||||||
[[nodiscard]] void* get_native_handle() const;
|
[[nodiscard]] void* get_native_handle() const;
|
||||||
|
protected:
|
||||||
|
virtual void on_resize(int in_width, int in_height);
|
||||||
|
virtual void on_glfw_close();
|
||||||
private:
|
private:
|
||||||
|
GLFWwindow* window;
|
||||||
vk::SwapchainKHR swap_chain;
|
vk::SwapchainKHR swap_chain;
|
||||||
vk::SurfaceKHR surface;
|
vk::SurfaceKHR surface;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline renderer_window::renderer_window(const desc_type& in_desc) {
|
|
||||||
swap_chain = aorii::get_renderer()->CreateSwapChain(in_desc);
|
|
||||||
surface = static_cast<surface_type*>(&swap_chain->GetSurface());
|
|
||||||
}
|
|
||||||
|
|
||||||
inline renderer_window::~renderer_window() { if (swap_chain) { aorii::get_renderer()->Release(*swap_chain); } }
|
|
||||||
|
|
||||||
inline void renderer_window::set_title(const std::wstring& in_title) const {
|
|
||||||
if (const auto window = get_surface()) { window->SetTitle(in_title.c_str()); }
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void renderer_window::close() const {
|
|
||||||
#if !AORII_IS_MOBILE
|
|
||||||
if (const auto window = get_surface()) { window->Show(false); }
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
#if !AORII_MACOS
|
|
||||||
inline void* renderer_window::get_native_handle() const {
|
|
||||||
#if !AORII_IS_MOBILE
|
|
||||||
if (auto surface = get_surface()) {
|
|
||||||
LLGL::NativeHandle native_handle;
|
|
||||||
surface->GetNativeHandle(&native_handle, sizeof(LLGL::NativeHandle));
|
|
||||||
#if AORII_WINDOWS
|
|
||||||
return native_handle.window;
|
|
||||||
#elif AORII_LINUX
|
|
||||||
return native_handle.window;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|||||||
@@ -1,55 +1,70 @@
|
|||||||
#include "window_manager.h"
|
#include "window_manager.h"
|
||||||
|
|
||||||
|
#include <GLFW/glfw3.h>
|
||||||
#include <spdlog/spdlog.h>
|
#include <spdlog/spdlog.h>
|
||||||
|
|
||||||
#include "renderer_window.h"
|
#include "renderer_window.h"
|
||||||
#include "renderer/renderer.h"
|
#include "renderer/renderer.h"
|
||||||
|
|
||||||
class manager_window_event_listener : public LLGL::Window::EventListener {
|
window_manager* s_window_manager;
|
||||||
public:
|
|
||||||
explicit manager_window_event_listener(window_manager* in_manager) :
|
|
||||||
manager(in_manager) {
|
|
||||||
}
|
|
||||||
protected:
|
|
||||||
virtual void OnQuit(LLGL::Window& sender, bool& veto) override {
|
|
||||||
EventListener::OnQuit(sender, veto);
|
|
||||||
manager->on_window_close(sender);
|
|
||||||
}
|
|
||||||
|
|
||||||
window_manager* manager;
|
|
||||||
};
|
|
||||||
|
|
||||||
window_manager::~window_manager() {
|
window_manager::~window_manager() {
|
||||||
windows.clear();
|
windows.clear();
|
||||||
windows_to_remove.clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::weak_ptr<renderer_window> window_manager::create_window(const LLGL::SwapChainDescriptor& in_desc) {
|
bool window_manager::init() {
|
||||||
auto window = std::make_shared<renderer_window>(in_desc);
|
if (glfwInit() != GLFW_TRUE) {
|
||||||
#if !IS_MOBILE
|
spdlog::error("初始化GLFW失败");
|
||||||
const auto& manager_listener = std::make_shared<manager_window_event_listener>(this);
|
return false;
|
||||||
window->get_surface()->AddEventListener(manager_listener);
|
}
|
||||||
#endif
|
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
|
||||||
windows.push_back(window);
|
return true;
|
||||||
return window;
|
}
|
||||||
|
|
||||||
|
void window_manager::destroy() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
std::weak_ptr<renderer_window> window_manager::create_window(const window_desc& in_desc) {
|
||||||
|
auto window_ptr = std::make_shared<renderer_window>(in_desc);
|
||||||
|
windows.push_back(window_ptr);
|
||||||
|
return window_ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void window_manager::destroy_window(renderer_window* in_window) {
|
||||||
|
auto it = std::ranges::find_if(windows, [in_window](const auto& window) {
|
||||||
|
return window.get() == in_window;
|
||||||
|
});
|
||||||
|
if (it != windows.end()) {
|
||||||
|
windows.erase(it);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void window_manager::update() {
|
void window_manager::update() {
|
||||||
windows_to_remove.clear();
|
glfwPollEvents();
|
||||||
}
|
}
|
||||||
|
|
||||||
void window_manager::on_window_close(LLGL::Window& in_sender) {
|
void window_manager::on_window_close() {
|
||||||
auto has_removed = std::ranges::remove_if(windows, [&in_sender](const std::shared_ptr<renderer_window>& w) {
|
}
|
||||||
return w->get_surface() == &in_sender;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (has_removed.begin() != has_removed.end()) {
|
window_manager* aorii::get_window_manager() {
|
||||||
windows_to_remove.push_back(*has_removed.begin());
|
return s_window_manager;
|
||||||
windows.erase(has_removed.begin(), has_removed.end());
|
}
|
||||||
spdlog::info("Window begin close");
|
|
||||||
} else {
|
bool aorii::create_window_manager() {
|
||||||
spdlog::error("Failed to close window!");
|
s_window_manager = new window_manager();
|
||||||
|
if (!s_window_manager->init()) {
|
||||||
|
delete s_window_manager;
|
||||||
|
s_window_manager = nullptr;
|
||||||
|
spdlog::error("创建窗口管理器失败");
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void aorii::destroy_window_manager() {
|
||||||
|
s_window_manager->destroy();
|
||||||
|
delete s_window_manager;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool aorii::should_exit() {
|
bool aorii::should_exit() {
|
||||||
|
|||||||
@@ -8,30 +8,30 @@ class window_manager {
|
|||||||
public:
|
public:
|
||||||
~window_manager();
|
~window_manager();
|
||||||
|
|
||||||
std::weak_ptr<renderer_window> create_window(const LLGL::SwapChainDescriptor& in_desc);
|
bool init();
|
||||||
|
void destroy();
|
||||||
|
|
||||||
|
std::weak_ptr<renderer_window> create_window(const window_desc& in_desc);
|
||||||
|
void destroy_window(renderer_window* in_window);
|
||||||
|
|
||||||
|
std::weak_ptr<renderer_window> get_main_window() {
|
||||||
|
return windows.empty() ? std::weak_ptr<renderer_window>() : windows.front();
|
||||||
|
}
|
||||||
const auto& get_windows() const { return windows; }
|
const auto& get_windows() const { return windows; }
|
||||||
void update();
|
void update();
|
||||||
|
|
||||||
[[nodiscard]] bool should_exit() const {
|
[[nodiscard]] bool should_exit() const {
|
||||||
return windows.empty() && windows_to_remove.empty();
|
return windows.empty() || windows[0]->should_close();
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void on_window_close(LLGL::Window& in_sender);
|
void on_window_close();
|
||||||
std::vector<std::shared_ptr<renderer_window>> windows;
|
std::vector<std::shared_ptr<renderer_window>> windows;
|
||||||
std::vector<std::shared_ptr<renderer_window>> windows_to_remove;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace aorii {
|
namespace aorii {
|
||||||
inline window_manager* s_window_manager;
|
window_manager* get_window_manager();
|
||||||
inline void create_window_manager() { s_window_manager = new window_manager(); }
|
bool create_window_manager();
|
||||||
inline void destroy_window_manager() { delete s_window_manager; }
|
void destroy_window_manager();
|
||||||
|
|
||||||
bool should_exit();
|
bool should_exit();
|
||||||
|
|
||||||
inline auto create_renderer_window(const LLGL::SwapChainDescriptor& in_desc) {
|
|
||||||
return s_window_manager->create_window(in_desc);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline const auto& get_all_window() { return s_window_manager->get_windows(); }
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user