异步线程绘制
This commit is contained in:
parent
09304715ed
commit
192bb51f1d
@ -6,5 +6,6 @@ int main(int argc, char* argv[]) {
|
||||
init.size = {800, 600};
|
||||
init.resizable = true;
|
||||
init.centered = true;
|
||||
// init.api = mirage::renderer_api::opengl;
|
||||
return run(init);
|
||||
}
|
||||
|
@ -245,13 +245,17 @@ def generate_pipeline_header_preamble() -> List[str]:
|
||||
" throw std::runtime_error(\"Failed to read shader file: \" + std::string(e.what()));",
|
||||
" }",
|
||||
"",
|
||||
" bool is_string_source = rendererID == LLGL::RendererID::OpenGL;",
|
||||
" if (is_string_source) {",
|
||||
" shaderData.push_back('\\0');",
|
||||
" }",
|
||||
" // 创建着色器",
|
||||
" LLGL::ShaderDescriptor desc = shaderDesc;",
|
||||
" desc.source = shaderData.data();",
|
||||
" desc.sourceSize = shaderData.size();",
|
||||
" desc.entryPoint = entryPoint;",
|
||||
" desc.type = type;",
|
||||
" desc.sourceType = rendererID == LLGL::RendererID::OpenGL ? LLGL::ShaderSourceType::CodeString : LLGL::ShaderSourceType::BinaryBuffer;",
|
||||
" desc.sourceType = is_string_source ? LLGL::ShaderSourceType::CodeString : LLGL::ShaderSourceType::BinaryBuffer;",
|
||||
"",
|
||||
" auto shader = renderer->CreateShader(desc);",
|
||||
" if (auto report = shader->GetReport()) {",
|
||||
|
@ -1,14 +1,16 @@
|
||||
#include "mirage.h"
|
||||
|
||||
#include "async/thread_pool.h"
|
||||
#include "misc/lazy_singleton.h"
|
||||
#include "renderer/dpi_sensibility.h"
|
||||
#include "window/window_manager.h"
|
||||
|
||||
mirage::duration_type delta_time = {};
|
||||
mirage::time_type begin_time = {};
|
||||
mirage::time_type last_time = {};
|
||||
LLGL::RenderSystemPtr renderer = nullptr;
|
||||
uint64_t frame_index = 0;
|
||||
std::filesystem::path shader_path = "resource/shaders";
|
||||
mirage::duration_type delta_time = {};
|
||||
mirage::time_type begin_time = {};
|
||||
mirage::time_type last_time = {};
|
||||
LLGL::RenderSystemPtr renderer = nullptr;
|
||||
uint64_t frame_index = 0;
|
||||
std::filesystem::path shader_path = "resource/shaders";
|
||||
|
||||
namespace mirage {
|
||||
void on_llgl_log(LLGL::Log::ReportType type, const char* text, void* user_data) {
|
||||
@ -21,6 +23,7 @@ namespace mirage {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
std::string to_string(renderer_api api) {
|
||||
switch (api) {
|
||||
case renderer_api::dx11:
|
||||
@ -36,7 +39,9 @@ namespace mirage {
|
||||
}
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
bool init_renderer(const init_info& in_info) {
|
||||
dpi_sensibility::init_dpi_sensibility();
|
||||
RegisterCallback(on_llgl_log);
|
||||
LLGL::RenderSystemDescriptor desc{};
|
||||
desc.moduleName = to_string(in_info.api);
|
||||
@ -57,23 +62,17 @@ namespace mirage {
|
||||
return true;
|
||||
}
|
||||
bool init_window(const init_info& in_info) {
|
||||
auto main_window = lazy_singleton<window_manager>::get().create_window(in_info);
|
||||
auto window_ptr = main_window.lock();
|
||||
if (!window_ptr) {
|
||||
if (!lazy_singleton<window_manager>::get().init(in_info)) {
|
||||
spdlog::error("窗口管理器初始化失败");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!window_ptr->create_context(in_info)) {
|
||||
return false;
|
||||
}
|
||||
spdlog::info("主窗口创建成功");
|
||||
spdlog::info("窗口管理器创建成功");
|
||||
return true;
|
||||
}
|
||||
void destroy_renderer() {
|
||||
LLGL::RenderSystem::Unload(std::move(renderer));
|
||||
}
|
||||
|
||||
|
||||
bool init(const init_info& in_info) {
|
||||
spdlog::info("初始化 mirage");
|
||||
if (!init_renderer(in_info)) {
|
||||
@ -104,6 +103,7 @@ namespace mirage {
|
||||
last_time = current_time;
|
||||
|
||||
lazy_singleton<window_manager>::get().update(delta_time);
|
||||
frame_index++;
|
||||
|
||||
std::this_thread::yield();
|
||||
}
|
||||
@ -130,7 +130,6 @@ namespace mirage {
|
||||
}
|
||||
while (!should_exit()) {
|
||||
update();
|
||||
frame_index++;
|
||||
}
|
||||
destroy();
|
||||
} catch (const std::exception& e) {
|
||||
|
@ -95,7 +95,7 @@ namespace mirage {
|
||||
};
|
||||
|
||||
struct triangle_index_t {
|
||||
int32_t vertex_index[3];
|
||||
uint32_t vertex_index[3];
|
||||
};
|
||||
|
||||
struct pipeline_info {
|
||||
|
30
src/core/renderer/dpi_sensibility.h
Normal file
30
src/core/renderer/dpi_sensibility.h
Normal file
@ -0,0 +1,30 @@
|
||||
#pragma once
|
||||
#if MIRAGE_PLATFORM_WINDOWS
|
||||
#include <Windows.h>
|
||||
#include <ShellScalingApi.h>
|
||||
#pragma comment(lib, "Shcore.lib")
|
||||
#endif
|
||||
|
||||
#include <spdlog/spdlog.h>
|
||||
|
||||
namespace mirage {
|
||||
class dpi_sensibility {
|
||||
public:
|
||||
|
||||
static void init_dpi_sensibility() {
|
||||
dpi_sensibility_impl();
|
||||
}
|
||||
private:
|
||||
#if MIRAGE_PLATFORM_WINDOWS
|
||||
static void dpi_sensibility_impl() {
|
||||
if (SetProcessDpiAwareness(PROCESS_PER_MONITOR_DPI_AWARE)) {
|
||||
spdlog::info("设置DPI感知上下文成功");
|
||||
}
|
||||
}
|
||||
#else
|
||||
static void dpi_sensibility_impl() {
|
||||
spdlog::warn("当前平台不支持DPI感知");
|
||||
}
|
||||
#endif
|
||||
};
|
||||
}
|
@ -15,15 +15,20 @@ namespace mirage {
|
||||
if (command_buffer) {
|
||||
get_renderer()->Release(*command_buffer);
|
||||
}
|
||||
if (swap_chain) {
|
||||
get_renderer()->Release(*swap_chain);
|
||||
}
|
||||
}
|
||||
|
||||
bool render_context::init(const swap_chain_descriptor& in_desc, const std::shared_ptr<LLGL::Surface>& in_surface) {
|
||||
LLGL::SwapChainDescriptor temp = in_desc;
|
||||
temp.resolution = in_surface->GetContentSize();
|
||||
swap_chain = get_renderer()->CreateSwapChain(temp, in_surface);
|
||||
temp.resolution = in_surface->GetContentSize();
|
||||
swap_chain = get_renderer()->CreateSwapChain(temp, in_surface);
|
||||
if (swap_chain == nullptr) {
|
||||
spdlog::error("无法创建交换链");
|
||||
return false;
|
||||
}
|
||||
|
||||
command_buffer = get_renderer()->CreateCommandBuffer(LLGL::CommandBufferFlags::ImmediateSubmit);
|
||||
if (command_buffer == nullptr) {
|
||||
spdlog::error("无法创建命令缓冲区");
|
||||
@ -47,32 +52,10 @@ namespace mirage {
|
||||
);
|
||||
pipeline = generated_pipelines::create_aorii_rect_pipeline(get_renderer(), swap_chain->GetRenderPass(), pipeline_layout_desc);
|
||||
|
||||
vertex va{};
|
||||
va.position = {0.0f, 0.0f};
|
||||
va.uv = {0.0f, 0.0f};
|
||||
va.color = {1.0f, 1.0f, 0.0f, 1.0f};
|
||||
vertex vb{};
|
||||
vb.position = {100.0f, 0.0f};
|
||||
vb.uv = {1.0f, 0.0f};
|
||||
vb.color = {1.0f, 0.0f, 1.0f, 1.0f};
|
||||
vertex vc{};
|
||||
vc.position = {100.0f, 100.0f};
|
||||
vc.uv = {1.0f, 1.0f};
|
||||
vc.color = {0.0f, 1.0f, 1.0f, 1.0f};
|
||||
vertex vd{};
|
||||
vd.position = {0.0f, 100.0f};
|
||||
vd.uv = {0.0f, 1.0f};
|
||||
vd.color = {0.0f, 1.0f, 0.0f, 1.0f};
|
||||
|
||||
std::vector quad_vertices = {va, vb, vc, vd};
|
||||
vertex_buffer->push(quad_vertices);
|
||||
|
||||
triangle_index_t ta{0, 1, 2};
|
||||
triangle_index_t tb{0, 2, 3};
|
||||
std::vector quad_indices = {ta, tb};
|
||||
index_buffer->push(quad_indices);
|
||||
push_rectangle({0, 0}, {100, 100}, linear_color::white);
|
||||
return true;
|
||||
}
|
||||
|
||||
render_context::update_status render_context::update(const duration_type& in_delta_time) {
|
||||
if (!command_buffer || !swap_chain) {
|
||||
return update_status::fail;
|
||||
@ -80,15 +63,22 @@ namespace mirage {
|
||||
if (!swap_chain->IsPresentable()) {
|
||||
return update_status::wait_for_present;
|
||||
}
|
||||
command_buffer->Begin();
|
||||
{
|
||||
|
||||
if (auto size = new_size.exchange({})) {
|
||||
swap_chain->ResizeBuffers(size.value());
|
||||
pipeline_param param;
|
||||
param.mvp = get_projection_matrix();
|
||||
param_buffer->set(param);
|
||||
}
|
||||
|
||||
command_buffer->Begin(); {
|
||||
command_buffer->SetViewport(swap_chain->GetResolution());
|
||||
command_buffer->SetVertexBuffer(vertex_buffer->get_raw());
|
||||
command_buffer->SetIndexBuffer(index_buffer->get_raw());
|
||||
|
||||
command_buffer->BeginRenderPass(*swap_chain);
|
||||
{
|
||||
command_buffer->BeginRenderPass(*swap_chain); {
|
||||
command_buffer->Clear(LLGL::ClearFlags::Color, {0.1f, 0.1f, 0.2f, 1.0f});
|
||||
command_buffer->Clear(LLGL::ClearFlags::Depth);
|
||||
|
||||
command_buffer->SetPipelineState(*pipeline.pipeline_state);
|
||||
command_buffer->SetResource(0, param_buffer->get_raw());
|
||||
@ -98,49 +88,87 @@ namespace mirage {
|
||||
command_buffer->EndRenderPass();
|
||||
}
|
||||
command_buffer->End();
|
||||
get_renderer()->GetCommandQueue()->Submit(*command_buffer);
|
||||
swap_chain->Present();
|
||||
return update_status::success;
|
||||
}
|
||||
void render_context::resize_swap_chain(const LLGL::Extent2D& in_size, long in_flag) {
|
||||
if (swap_chain) {
|
||||
swap_chain->ResizeBuffers(in_size, in_flag);
|
||||
|
||||
pipeline_param param;
|
||||
param.mvp = get_projection_matrix();
|
||||
param_buffer->set(param);
|
||||
}
|
||||
void render_context::resize_swap_chain(const LLGL::Extent2D& in_size, long in_flag) {
|
||||
if (!swap_chain)
|
||||
return;
|
||||
new_size = in_size;
|
||||
}
|
||||
|
||||
void render_context::set_vsync(bool in_vsync) {
|
||||
if (swap_chain) {
|
||||
swap_chain->SetVsyncInterval(in_vsync ? 1 : 0);
|
||||
vsync = in_vsync;
|
||||
spdlog::info("垂直同步: {}", vsync);
|
||||
}
|
||||
if (!swap_chain)
|
||||
return;
|
||||
swap_chain->SetVsyncInterval(in_vsync ? 1 : 0);
|
||||
vsync = in_vsync;
|
||||
spdlog::info("垂直同步: {}", vsync);
|
||||
}
|
||||
|
||||
void render_context::push_rectangle(const Eigen::Vector2f& in_pos, const Eigen::Vector2f& in_size, const linear_color_type& in_color) {
|
||||
vertex va{};
|
||||
vertex vb{};
|
||||
vertex vc{};
|
||||
vertex vd{};
|
||||
va.color = in_color;
|
||||
vb.color = in_color;
|
||||
vc.color = in_color;
|
||||
vd.color = in_color;
|
||||
|
||||
va.position = in_pos;
|
||||
vb.position = {in_pos.x() + in_size.x(), in_pos.y()};
|
||||
vc.position = in_pos + in_size;
|
||||
vd.position = {in_pos.x(), in_pos.y() + in_size.y()};
|
||||
|
||||
va.uv = {0.0f, 0.0f};
|
||||
vb.uv = {1.0f, 0.0f};
|
||||
vc.uv = {1.0f, 1.0f};
|
||||
vd.uv = {0.0f, 1.0f};
|
||||
|
||||
const auto index_offset = static_cast<uint32_t>(vertex_buffer->get_size() / sizeof(vertex));
|
||||
|
||||
// 根据index_offset计算索引
|
||||
const triangle_index_t ta = {0 + index_offset, 1 + index_offset, 2 + index_offset};
|
||||
const triangle_index_t tb = {0 + index_offset, 2 + index_offset, 3 + index_offset};
|
||||
|
||||
std::vector quad_indices = {ta, tb};
|
||||
std::vector quad_vertices = {va, vb, vc, vd};
|
||||
vertex_buffer->push(quad_vertices);
|
||||
index_buffer->push(quad_indices);
|
||||
}
|
||||
|
||||
Eigen::Matrix4f render_context::get_projection_matrix() const {
|
||||
const bool is_clip_range_unit_cube = get_renderer()->GetRenderingCaps().clippingRange == LLGL::ClippingRange::MinusOneToOne;
|
||||
const auto& size = swap_chain->GetResolution();
|
||||
// 创建一个单位矩阵
|
||||
|
||||
Eigen::Matrix4f matrix = Eigen::Matrix4f::Identity();
|
||||
// 透视投影矩阵
|
||||
|
||||
if (is_clip_range_unit_cube) {
|
||||
matrix(0, 0) = 2.0f / size.width;
|
||||
matrix(1, 1) = 2.0f / size.height;
|
||||
matrix(2, 2) = 1.0f;
|
||||
matrix(3, 3) = 1.0f;
|
||||
matrix(3, 0) = -1.0f;
|
||||
matrix(3, 1) = -1.0f;
|
||||
} else {
|
||||
// 对于 [-1, 1] 的裁剪范围
|
||||
matrix(0, 0) = 2.0f / size.width;
|
||||
matrix(1, 1) = -2.0f / size.height;
|
||||
matrix(2, 2) = 1.0f;
|
||||
matrix(3, 3) = 1.0f;
|
||||
matrix(3, 0) = -1.0f;
|
||||
matrix(3, 1) = 1.0f;
|
||||
|
||||
// 调整Z轴范围从[-1,1]
|
||||
matrix(2, 2) = 2.0f;
|
||||
matrix(3, 2) = -1.0f;
|
||||
} else {
|
||||
// 对于 [0, 1] 的裁剪范围
|
||||
matrix(0, 0) = 2.0f / size.width;
|
||||
matrix(1, 1) = -2.0f / size.height;
|
||||
matrix(2, 2) = 1.0f;
|
||||
matrix(3, 3) = 1.0f;
|
||||
matrix(3, 0) = -1.0f;
|
||||
matrix(3, 1) = 1.0f;
|
||||
// 调整Z轴范围从[0,1]
|
||||
matrix(2, 2) = 1.0f;
|
||||
matrix(3, 2) = 0.0f;
|
||||
}
|
||||
return matrix;
|
||||
}
|
||||
|
||||
} // namespace mirage
|
||||
|
@ -29,6 +29,12 @@ namespace mirage {
|
||||
}
|
||||
|
||||
[[nodiscard]] Eigen::Matrix4f get_projection_matrix() const;
|
||||
|
||||
void push_rectangle(const Eigen::Vector2f& in_pos, const Eigen::Vector2f& in_size, const linear_color_type& in_color);
|
||||
void reset_vertices() {
|
||||
vertex_buffer->clear();
|
||||
index_buffer->clear();
|
||||
}
|
||||
private:
|
||||
std::shared_ptr<render_buffer> vertex_buffer;
|
||||
std::shared_ptr<render_buffer> index_buffer;
|
||||
@ -37,5 +43,6 @@ namespace mirage {
|
||||
LLGL::SwapChain* swap_chain = nullptr;
|
||||
bool vsync = true;
|
||||
pipeline_info pipeline;
|
||||
std::atomic<std::optional<LLGL::Extent2D>> new_size;
|
||||
};
|
||||
} // namespace mirage
|
||||
|
@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
#include "LLGL/LLGL.h"
|
||||
#include "misc/color.h"
|
||||
#include "misc/enum_class_flags.h"
|
||||
#include <Eigen/Eigen>
|
||||
#include <cstdint>
|
||||
@ -7,7 +8,7 @@
|
||||
namespace mirage {
|
||||
using transform_type = Eigen::Affine2d;
|
||||
using color_type = LLGL::ColorRGBAub;
|
||||
using linear_color_type = LLGL::ColorRGBAf;
|
||||
using linear_color_type = linear_color;
|
||||
using point_type = Eigen::Vector2f;
|
||||
|
||||
struct vertex_shader_param {
|
||||
|
@ -15,7 +15,7 @@ struct PSInput {
|
||||
PSInput vertex_main(VSInput input)
|
||||
{
|
||||
PSInput output;
|
||||
output.position = mul(float4(input.position, 0.0, 1.0), param_buffer.transform);
|
||||
output.position = mul(float4(input.position, 0, 1.0), param_buffer.transform);
|
||||
output.color = input.color;
|
||||
return output;
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
#include "misc/lazy_singleton.h"
|
||||
#include "window/window.h"
|
||||
#include "window/window_manager.h"
|
||||
#include <spdlog/spdlog.h>
|
||||
@ -164,6 +165,12 @@ namespace mirage {
|
||||
return {};
|
||||
}
|
||||
|
||||
void window::on_resize(const LLGL::Extent2D& in_client_area_size) {
|
||||
if (context) {
|
||||
context->resize_swap_chain(in_client_area_size, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void window::init_event_listener() {
|
||||
if (auto window_ptr = static_cast<LLGL::Window*>(surface.get())) {
|
||||
window_ptr->SetUserData(this);
|
||||
|
@ -43,7 +43,7 @@ namespace mirage {
|
||||
}
|
||||
#endif
|
||||
|
||||
void window::update(const duration_type& in_delta_time) {
|
||||
void window::render_update(const duration_type& in_delta_time) {
|
||||
if (context) {
|
||||
context->update(in_delta_time);
|
||||
}
|
||||
|
@ -17,7 +17,7 @@ namespace mirage {
|
||||
}
|
||||
[[nodiscard]] void* get_native_handle() const;
|
||||
|
||||
void update(const duration_type& in_delta_time);
|
||||
void render_update(const duration_type& in_delta_time);
|
||||
void set_title(const std::u8string& in_title);
|
||||
[[nodiscard]] std::u8string get_title() const;
|
||||
void set_fullscreen(bool in_fullscreen);
|
||||
@ -43,7 +43,7 @@ namespace mirage {
|
||||
virtual void on_wheel_motion(int in_motion) {}
|
||||
virtual void on_local_motion(const LLGL::Offset2D& in_position) {}
|
||||
virtual void on_global_motion(const LLGL::Offset2D& in_motion) {}
|
||||
virtual void on_resize(const LLGL::Extent2D& in_client_area_size) {}
|
||||
virtual void on_resize(const LLGL::Extent2D& in_client_area_size);
|
||||
virtual void on_update() {}
|
||||
virtual void on_get_focus() {}
|
||||
virtual void on_lost_focus() {}
|
||||
|
@ -1,32 +1,56 @@
|
||||
#include "window_manager.h"
|
||||
|
||||
#include <spdlog/spdlog.h>
|
||||
#include <Windows.h>
|
||||
|
||||
namespace mirage {
|
||||
void window_manager::update(const duration_type& in_delta_time) {
|
||||
if (!LLGL::Surface::ProcessEvents()) {
|
||||
return;
|
||||
}
|
||||
LLGL::Surface::ProcessEvents();
|
||||
to_destroy.clear();
|
||||
for (const auto& w : windows) {
|
||||
w->update(in_delta_time);
|
||||
}
|
||||
|
||||
std::shared_lock lock(mutex);
|
||||
should_exit_flag = windows.empty() && to_destroy.empty();
|
||||
}
|
||||
|
||||
bool window_manager::init(const init_info& in_info) {
|
||||
auto main_window = create_window(in_info);
|
||||
auto window_ptr = main_window.lock();
|
||||
if (!window_ptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!window_ptr->create_context(in_info)) {
|
||||
return false;
|
||||
}
|
||||
last_time = std::chrono::high_resolution_clock::now();
|
||||
render_thread = std::thread(&window_manager::render_thread_func, this);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool window_manager::destroy() {
|
||||
should_exit_flag = true;
|
||||
render_thread.join();
|
||||
windows.clear();
|
||||
to_destroy.clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
std::weak_ptr<window> window_manager::create_window(const LLGL::WindowDescriptor& desc) {
|
||||
auto window_ptr = std::make_shared<window>(desc);
|
||||
windows.push_back(window_ptr);
|
||||
|
||||
{
|
||||
std::unique_lock lock(mutex);
|
||||
windows.push_back(window_ptr);
|
||||
}
|
||||
if (!window_ptr) {
|
||||
spdlog::error("无法创建窗口");
|
||||
return {};
|
||||
}
|
||||
return window_ptr;
|
||||
}
|
||||
|
||||
void window_manager::destroy_window(const window& in_window) {
|
||||
std::unique_lock lock(mutex);
|
||||
for (auto it = windows.begin(); it != windows.end(); ++it) {
|
||||
if (it->get() == &in_window) {
|
||||
to_destroy.push_back(*it);
|
||||
@ -35,10 +59,27 @@ namespace mirage {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::weak_ptr<window> window_manager::get_main_window() {
|
||||
std::shared_lock lock(mutex);
|
||||
if (windows.empty()) {
|
||||
return {};
|
||||
}
|
||||
return windows.front();
|
||||
}
|
||||
|
||||
void window_manager::render_thread_func() {
|
||||
while (!should_exit_flag) {
|
||||
const auto& current_time = std::chrono::high_resolution_clock::now();
|
||||
const auto in_delta_time = current_time - last_time;
|
||||
last_time = current_time;
|
||||
|
||||
std::shared_lock lock(mutex);
|
||||
for (const auto& w : windows) {
|
||||
w->render_update(in_delta_time);
|
||||
}
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(16));
|
||||
}
|
||||
}
|
||||
} // namespace mirage
|
||||
|
@ -1,17 +1,19 @@
|
||||
#pragma once
|
||||
#include "misc/lazy_singleton.h"
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include "window.h"
|
||||
#include <shared_mutex>
|
||||
|
||||
namespace mirage {
|
||||
class window_manager {
|
||||
public:
|
||||
void update(const duration_type& in_delta_time);
|
||||
|
||||
bool init(const init_info& in_info);
|
||||
bool destroy();
|
||||
|
||||
[[nodiscard]] bool should_exit() const {
|
||||
return windows.empty() && to_destroy.empty();
|
||||
return should_exit_flag;
|
||||
}
|
||||
|
||||
std::weak_ptr<window> create_window(const LLGL::WindowDescriptor& desc);
|
||||
@ -24,9 +26,14 @@ namespace mirage {
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<std::shared_ptr<window>> windows;
|
||||
std::vector<std::shared_ptr<window>> to_destroy;
|
||||
|
||||
void render_thread_func();
|
||||
std::thread render_thread;
|
||||
time_type last_time = {};
|
||||
std::atomic_bool should_exit_flag = false;
|
||||
std::shared_mutex mutex;
|
||||
};
|
||||
} // namespace mirage
|
||||
|
Loading…
x
Reference in New Issue
Block a user