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"]
|
||||
path = third_party/msdfgen
|
||||
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_VCPKG OFF CACHE BOOL "Use VCPKG 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/detect_os.cmake)
|
||||
|
||||
@@ -8,15 +8,10 @@
|
||||
#include "window/renderer_window.h"
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
aorii::init(renderer_api::vulkan);
|
||||
|
||||
renderer_window::desc_type desc{};
|
||||
desc.resolution = { 1280, 1280 };
|
||||
auto window = aorii::create_renderer_window(desc);
|
||||
|
||||
while (!aorii::should_exit()) {
|
||||
aorii::update();
|
||||
}
|
||||
|
||||
aorii::destroy();
|
||||
window_desc desc{};
|
||||
desc.title = "Aorii";
|
||||
desc.resolution.width = 1280;
|
||||
desc.resolution.height = 720;
|
||||
desc.resizable = true;
|
||||
return aorii::run(desc);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
project(aorii_core)
|
||||
set(CMAKE_CXX_STANDARD 26)
|
||||
|
||||
find_package(harfbuzz REQUIRED)
|
||||
find_package(Eigen3 REQUIRED)
|
||||
@@ -6,6 +7,7 @@ find_package(spdlog REQUIRED)
|
||||
find_package(Boost REQUIRED)
|
||||
find_package(Freetype REQUIRED)
|
||||
find_package(Vulkan REQUIRED)
|
||||
find_package(glfw3 REQUIRED)
|
||||
|
||||
if (APPLE)
|
||||
find_library(COCOA_LIBRARY Cocoa)
|
||||
@@ -15,10 +17,11 @@ set(RENDERER_SOURCES "")
|
||||
retrieve_files(${CMAKE_CURRENT_SOURCE_DIR} 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_compile_definitions(${PROJECT_NAME} PRIVATE NOMINMAX)
|
||||
add_os_definitions(${PROJECT_NAME})
|
||||
configure_glfw_native(${PROJECT_NAME})
|
||||
if (APPLE)
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC ${COCOA_LIBRARY})
|
||||
endif ()
|
||||
|
||||
@@ -60,8 +60,8 @@ public:
|
||||
return res;
|
||||
}
|
||||
|
||||
template<typename f, typename callback, typename ...args>
|
||||
auto submit_with_callback(f&& in_func, callback&& in_callback, args&&... in_args) {
|
||||
template<typename f, typename callback_f, typename ...args>
|
||||
auto submit_with_callback(f&& in_func, callback_f&& in_callback, args&&... in_args) {
|
||||
using return_type = std::invoke_result_t<f, args...>;
|
||||
|
||||
if (stop) { throw std::runtime_error("submit on stopped ThreadPool"); }
|
||||
@@ -92,7 +92,7 @@ public:
|
||||
/**
|
||||
* @brief 提交一个任务到线程池,并在主线程中执行回调函数
|
||||
* @tparam f 任务函数类型
|
||||
* @tparam callback 回调函数类型
|
||||
* @tparam callback_f 回调函数类型
|
||||
* @tparam args 任务函数参数类型
|
||||
* @param in_func 任务函数
|
||||
* @param in_callback 回调函数
|
||||
@@ -104,8 +104,8 @@ public:
|
||||
* auto res = thread_pool.submit_with_main_thread_callback(func, callback, 1, 2);
|
||||
* @endcode
|
||||
*/
|
||||
template<typename f, typename callback, typename ...args>
|
||||
auto submit_with_main_thread_callback(f&& in_func, callback&& in_callback, args&&... in_args) {
|
||||
template<typename f, typename callback_f, typename ...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...>;
|
||||
|
||||
if (stop) { throw std::runtime_error("submit on stopped ThreadPool"); }
|
||||
@@ -117,7 +117,7 @@ public:
|
||||
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;
|
||||
try {
|
||||
(*task)();
|
||||
|
||||
@@ -7,15 +7,10 @@ glyph_cache::~glyph_cache() {
|
||||
clear();
|
||||
}
|
||||
|
||||
void glyph_cache::initialize(LLGL::RenderSystem& in_render_system) {
|
||||
render_system = &in_render_system;
|
||||
void glyph_cache::initialize() {
|
||||
}
|
||||
|
||||
void glyph_cache::clear() {
|
||||
if (!render_system)
|
||||
return;
|
||||
for (auto& page : active_atlases)
|
||||
render_system->Release(*page.texture);
|
||||
active_atlases.clear();
|
||||
}
|
||||
|
||||
@@ -27,33 +22,33 @@ glyph_metadata glyph_cache::get_glyph(const glyph_key& in_key) {
|
||||
return glyph;
|
||||
}
|
||||
|
||||
bool glyph_cache::atlas_page::put_glyph(const LLGL::TextureRegion& in_size, const LLGL::ImageView& in_data,
|
||||
Eigen::AlignedBox2f& out_uv_rect) {
|
||||
if (current_x + in_size.offset.x > texture->GetDesc().extent.width) {
|
||||
current_x = 0;
|
||||
current_y += row_height;
|
||||
row_height = 0;
|
||||
}
|
||||
if (current_y + in_size.offset.y > texture->GetDesc().extent.height)
|
||||
return false;
|
||||
|
||||
render_system->WriteTexture(*texture, in_size, in_data);
|
||||
bool glyph_cache::atlas_page::put_glyph(Eigen::AlignedBox2f& out_uv_rect) {
|
||||
// if (current_x + in_size.offset.x > texture->GetDesc().extent.width) {
|
||||
// current_x = 0;
|
||||
// current_y += row_height;
|
||||
// row_height = 0;
|
||||
// }
|
||||
// if (current_y + in_size.offset.y > texture->GetDesc().extent.height)
|
||||
// return false;
|
||||
//
|
||||
// render_system->WriteTexture(*texture, in_size, in_data);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
glyph_cache::atlas_page glyph_cache::allocate_space(uint32_t in_width, uint32_t in_height) {
|
||||
LLGL::TextureDescriptor descriptor{};
|
||||
descriptor.type = LLGL::TextureType::Texture2D;
|
||||
descriptor.cpuAccessFlags = LLGL::CPUAccessFlags::Write;
|
||||
descriptor.extent.width = in_width;
|
||||
descriptor.extent.height = in_height;
|
||||
|
||||
atlas_page page{};
|
||||
page.texture = render_system->CreateTexture(descriptor);
|
||||
|
||||
active_atlases.push_back(page);
|
||||
return page;
|
||||
// LLGL::TextureDescriptor descriptor{};
|
||||
// descriptor.type = LLGL::TextureType::Texture2D;
|
||||
// descriptor.cpuAccessFlags = LLGL::CPUAccessFlags::Write;
|
||||
// descriptor.extent.width = in_width;
|
||||
// descriptor.extent.height = in_height;
|
||||
//
|
||||
// atlas_page page{};
|
||||
// page.texture = render_system->CreateTexture(descriptor);
|
||||
//
|
||||
// active_atlases.push_back(page);
|
||||
// return page;
|
||||
return {};
|
||||
}
|
||||
|
||||
glyph_metadata glyph_cache::make_glyph(const glyph_key& in_key) {
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
#pragma once
|
||||
#include <cstdint>
|
||||
#include <Eigen/Eigen>
|
||||
#include <LLGL/Texture.h>
|
||||
|
||||
#include "font_type.h"
|
||||
#include "containers/lrucache.hpp"
|
||||
#include "LLGL/RenderSystem.h"
|
||||
|
||||
struct glyph_key {
|
||||
font_family family{};
|
||||
@@ -40,7 +38,7 @@ private:
|
||||
};
|
||||
|
||||
struct glyph_metadata {
|
||||
LLGL::Texture* atlas_texture;
|
||||
// LLGL::Texture* atlas_texture;
|
||||
Eigen::AlignedBox2f uv_rect;
|
||||
Eigen::Vector2f size;
|
||||
Eigen::Vector2f bearing;
|
||||
@@ -50,24 +48,24 @@ class glyph_cache {
|
||||
public:
|
||||
~glyph_cache();
|
||||
|
||||
void initialize(LLGL::RenderSystem& in_render_system);
|
||||
void initialize();
|
||||
void clear();
|
||||
glyph_metadata get_glyph(const glyph_key& in_key);
|
||||
private:
|
||||
struct atlas_page {
|
||||
LLGL::Texture* texture = nullptr;
|
||||
LLGL::RenderSystem* render_system = nullptr;
|
||||
// LLGL::Texture* texture = nullptr;
|
||||
// LLGL::RenderSystem* render_system = nullptr;
|
||||
uint32_t current_x = 0;
|
||||
uint32_t current_y = 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};
|
||||
std::vector<atlas_page> active_atlases;
|
||||
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);
|
||||
glyph_metadata make_glyph(const glyph_key& in_key);
|
||||
|
||||
@@ -179,7 +179,7 @@ struct pixel {
|
||||
}
|
||||
|
||||
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);
|
||||
memset(data, 0, sizeof(data));
|
||||
for (int i = 0; i < Num; ++i) {
|
||||
@@ -189,7 +189,7 @@ struct pixel {
|
||||
}
|
||||
|
||||
template<typename U, int N2>
|
||||
operator pixel() {
|
||||
explicit operator pixel<U, N2>() {
|
||||
pixel<U, N2> result = *this;
|
||||
return result;
|
||||
}
|
||||
@@ -217,7 +217,7 @@ struct image_accessor {
|
||||
void copy_from(const image_accessor<T>& rhs) {
|
||||
const int temp_width = std::min(width, rhs.width);
|
||||
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);
|
||||
for (int y = 0; y < temp_height; ++y) {
|
||||
auto src_row = rhs.get_row(y);
|
||||
@@ -304,7 +304,7 @@ struct image_accessor {
|
||||
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);
|
||||
row_pitch = in_row_pitch;
|
||||
}
|
||||
@@ -326,9 +326,9 @@ struct image_accessor {
|
||||
void* const data;
|
||||
const int width;
|
||||
const int height;
|
||||
int row_pitch; // 行跨度,支持对齐
|
||||
uint64_t row_pitch; // 行跨度,支持对齐
|
||||
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;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -15,13 +15,13 @@ void pipeline::destroy() {
|
||||
|
||||
void pipeline::set_triangle(const std::span<const aorii_vertex>& in_vertexes,
|
||||
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())); }
|
||||
const auto v_buffer = static_cast<aorii_vertex*>(vertex_buffer->lock());
|
||||
std::ranges::copy(in_vertexes, v_buffer);
|
||||
vertex_buffer->unlock();
|
||||
|
||||
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());
|
||||
std::ranges::copy(in_triangles, i_buffer);
|
||||
index_buffer->unlock();
|
||||
// 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());
|
||||
// std::ranges::copy(in_vertexes, v_buffer);
|
||||
// vertex_buffer->unlock();
|
||||
//
|
||||
// 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());
|
||||
// std::ranges::copy(in_triangles, i_buffer);
|
||||
// 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 "misc/stb_image.h"
|
||||
|
||||
#if DX_BACKEND
|
||||
#include "backend/dx/dx_renderer.h"
|
||||
#endif
|
||||
|
||||
using time_type = decltype(std::chrono::high_resolution_clock::now());
|
||||
std::chrono::duration<double> delta_time = {};
|
||||
time_type begin_time = {};
|
||||
@@ -73,15 +69,42 @@ aorii_renderer* s_renderer{};
|
||||
// return texture;
|
||||
// }
|
||||
|
||||
bool aorii::init() {
|
||||
create_renderer();
|
||||
create_window_manager();
|
||||
namespace aorii {
|
||||
bool init(const window_desc& in_main_window_desc) {
|
||||
if (!create_window_manager())
|
||||
return false;
|
||||
const auto main_window = get_window_manager()->create_window(in_main_window_desc);
|
||||
if (!create_renderer())
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void aorii::destroy() {
|
||||
destroy_window_manager();
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
int aorii::run(const window_desc& in_main_window_desc) {
|
||||
if (!init(in_main_window_desc))
|
||||
return -1;
|
||||
while (!should_exit()) {
|
||||
update();
|
||||
}
|
||||
destroy();
|
||||
return 0;
|
||||
}
|
||||
|
||||
aorii_renderer* aorii::get_renderer() {
|
||||
@@ -95,6 +118,12 @@ bool aorii::create_renderer() {
|
||||
if (s_renderer) return true;
|
||||
|
||||
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();
|
||||
return s_renderer != nullptr;
|
||||
}
|
||||
@@ -102,22 +131,11 @@ bool aorii::create_renderer() {
|
||||
void aorii::destroy_renderer() {
|
||||
if (!s_renderer) return;
|
||||
|
||||
s_renderer->destroy();
|
||||
delete s_renderer;
|
||||
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() {
|
||||
return delta_time;
|
||||
}
|
||||
@@ -125,3 +143,81 @@ const std::chrono::duration<double>& aorii::get_delta_time() {
|
||||
std::chrono::duration<double> aorii::get_total_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 <filesystem>
|
||||
#include <vulkan/vulkan.hpp>
|
||||
#include <GLFW/glfw3.h>
|
||||
|
||||
#include "device_selector.h"
|
||||
#include "renderer_types.h"
|
||||
|
||||
struct window_desc;
|
||||
|
||||
class aorii_renderer {
|
||||
public:
|
||||
bool init();
|
||||
void destroy();
|
||||
|
||||
vk::SurfaceKHR create_surface(GLFWwindow* in_window);
|
||||
vk::SwapchainKHR create_swap_chain(const vk::SwapchainCreateInfoKHR& in_create_info);
|
||||
private:
|
||||
|
||||
vk::Instance instance;
|
||||
device_selector selector;
|
||||
device_set main_device;
|
||||
};
|
||||
|
||||
namespace aorii {
|
||||
bool init();
|
||||
void destroy();
|
||||
int run(const window_desc& in_main_window_desc);
|
||||
|
||||
aorii_renderer* get_renderer();
|
||||
|
||||
bool create_renderer();
|
||||
void destroy_renderer();
|
||||
void update();
|
||||
|
||||
const std::chrono::duration<double>& get_delta_time();
|
||||
std::chrono::duration<double> get_total_time();
|
||||
|
||||
@@ -1,20 +1,85 @@
|
||||
#include "renderer_buffer.h"
|
||||
|
||||
void renderer_buffer::resize(const uint64_t new_size) {
|
||||
if (new_size == get_size())
|
||||
return;
|
||||
if (new_size < 1) {
|
||||
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);
|
||||
#include "renderer_buffer_memory_strategy.h"
|
||||
|
||||
aorii::get_command_buffer()->CopyBuffer(*new_buffer, 0, *buffer, 0, std::min(get_size(), new_size));
|
||||
aorii::get_renderer()->Release(*buffer);
|
||||
buffer = new_buffer;
|
||||
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;
|
||||
|
||||
// 如果允许原地扩展并且可以原地扩展
|
||||
if (in_allow_in_place && try_resize_in_place(in_new_size)) {
|
||||
desc.size = in_new_size;
|
||||
return;
|
||||
}
|
||||
|
||||
// 计算新的大小
|
||||
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;
|
||||
memory = new_memory;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,45 +2,81 @@
|
||||
#include <span>
|
||||
#include <spdlog/spdlog.h>
|
||||
|
||||
#include "LLGL/Buffer.h"
|
||||
#include "LLGL/RenderSystem.h"
|
||||
#include "renderer.h"
|
||||
#include "misc/scope_exit.h"
|
||||
#include "renderer_types.h"
|
||||
|
||||
class buffer_memory_strategy;
|
||||
|
||||
class renderer_buffer {
|
||||
public:
|
||||
explicit renderer_buffer(const LLGL::BufferDescriptor& in_desc) {
|
||||
buffer = aorii::get_renderer()->CreateBuffer(in_desc);
|
||||
}
|
||||
explicit renderer_buffer(const device_set& in_device, const renderer_buffer_desc& in_desc);
|
||||
|
||||
virtual ~renderer_buffer() {
|
||||
aorii::get_renderer()->Release(*buffer);
|
||||
}
|
||||
virtual ~renderer_buffer();
|
||||
|
||||
virtual void* lock(const LLGL::CPUAccess access = LLGL::CPUAccess::WriteDiscard) {
|
||||
return aorii::get_renderer()->MapBuffer(*buffer, access);
|
||||
[[nodiscard]] const auto& get_memory() const {
|
||||
return memory;
|
||||
}
|
||||
virtual void unlock() {
|
||||
return aorii::get_renderer()->UnmapBuffer(*buffer);
|
||||
}
|
||||
|
||||
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]] const auto& get_desc() const {
|
||||
return desc;
|
||||
}
|
||||
[[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:
|
||||
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"
|
||||
|
||||
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 {
|
||||
friend class window_manager;
|
||||
public:
|
||||
explicit renderer_window();
|
||||
|
||||
explicit renderer_window(const window_desc& in_desc);
|
||||
virtual ~renderer_window();
|
||||
|
||||
void set_title(const std::wstring& in_title) 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; }
|
||||
|
||||
bool create_swap_chain(vk::SwapchainCreateInfoKHR in_create_info);
|
||||
[[nodiscard]] auto get_swap_chain() const { return swap_chain; }
|
||||
[[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;
|
||||
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 <GLFW/glfw3.h>
|
||||
#include <spdlog/spdlog.h>
|
||||
|
||||
#include "renderer_window.h"
|
||||
#include "renderer/renderer.h"
|
||||
|
||||
class manager_window_event_listener : public LLGL::Window::EventListener {
|
||||
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* s_window_manager;
|
||||
|
||||
window_manager::~window_manager() {
|
||||
windows.clear();
|
||||
windows_to_remove.clear();
|
||||
}
|
||||
|
||||
std::weak_ptr<renderer_window> window_manager::create_window(const LLGL::SwapChainDescriptor& in_desc) {
|
||||
auto window = std::make_shared<renderer_window>(in_desc);
|
||||
#if !IS_MOBILE
|
||||
const auto& manager_listener = std::make_shared<manager_window_event_listener>(this);
|
||||
window->get_surface()->AddEventListener(manager_listener);
|
||||
#endif
|
||||
windows.push_back(window);
|
||||
return window;
|
||||
bool window_manager::init() {
|
||||
if (glfwInit() != GLFW_TRUE) {
|
||||
spdlog::error("初始化GLFW失败");
|
||||
return false;
|
||||
}
|
||||
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
|
||||
return true;
|
||||
}
|
||||
|
||||
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() {
|
||||
windows_to_remove.clear();
|
||||
glfwPollEvents();
|
||||
}
|
||||
|
||||
void window_manager::on_window_close(LLGL::Window& in_sender) {
|
||||
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()) {
|
||||
windows_to_remove.push_back(*has_removed.begin());
|
||||
windows.erase(has_removed.begin(), has_removed.end());
|
||||
spdlog::info("Window begin close");
|
||||
} else {
|
||||
spdlog::error("Failed to close window!");
|
||||
void window_manager::on_window_close() {
|
||||
}
|
||||
|
||||
window_manager* aorii::get_window_manager() {
|
||||
return s_window_manager;
|
||||
}
|
||||
|
||||
bool aorii::create_window_manager() {
|
||||
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() {
|
||||
|
||||
@@ -8,30 +8,30 @@ class window_manager {
|
||||
public:
|
||||
~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; }
|
||||
void update();
|
||||
|
||||
[[nodiscard]] bool should_exit() const {
|
||||
return windows.empty() && windows_to_remove.empty();
|
||||
return windows.empty() || windows[0]->should_close();
|
||||
}
|
||||
|
||||
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_to_remove;
|
||||
};
|
||||
|
||||
namespace aorii {
|
||||
inline window_manager* s_window_manager;
|
||||
inline void create_window_manager() { s_window_manager = new window_manager(); }
|
||||
inline void destroy_window_manager() { delete s_window_manager; }
|
||||
window_manager* get_window_manager();
|
||||
bool create_window_manager();
|
||||
void destroy_window_manager();
|
||||
|
||||
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