封装render_context
This commit is contained in:
parent
6a7ebf73a9
commit
45231d9953
30
src/core/a.puml
Normal file
30
src/core/a.puml
Normal file
@ -0,0 +1,30 @@
|
||||
@startuml
|
||||
start
|
||||
:主线程启动;
|
||||
|
||||
fork
|
||||
:创建窗口;
|
||||
:初始化命令缓冲池;
|
||||
fork again
|
||||
:启动工作线程;
|
||||
repeat
|
||||
:锁定次级CB队列;
|
||||
if (有可用CB?) then (是)
|
||||
:取出次级CB;
|
||||
else (否)
|
||||
:创建新次级CB;
|
||||
endif
|
||||
:录制绘制命令;
|
||||
:返回就绪队列;
|
||||
repeat while(有更多任务?)
|
||||
end fork
|
||||
|
||||
:开始主CB录制;
|
||||
while (遍历所有窗口?)
|
||||
:合并次级CB;
|
||||
:提交到GPU;
|
||||
:呈现窗口;
|
||||
endwhile
|
||||
|
||||
stop
|
||||
@enduml
|
57
src/core/b.puml
Normal file
57
src/core/b.puml
Normal file
@ -0,0 +1,57 @@
|
||||
@startuml
|
||||
skinparam classFontSize 13
|
||||
skinparam classAttributeIconSize 0
|
||||
|
||||
class GUIFramework {
|
||||
+ WindowScheduler windowMgr
|
||||
+ CommandBufferPool cmdPool
|
||||
+ WidgetCacheSystem cacheSys
|
||||
+ MainLoop()
|
||||
+ SubmitFrame()
|
||||
}
|
||||
|
||||
class WindowScheduler {
|
||||
+ vector<WindowContext> windows
|
||||
+ CreateWindow()
|
||||
+ CloseWindow()
|
||||
}
|
||||
|
||||
class WindowContext {
|
||||
- LLGL::Window* window
|
||||
- LLGL::CommandBuffer* primaryCB
|
||||
+ vector<CommandBuffer*> secondaryCBs
|
||||
+ CachedTextureManager textureCache
|
||||
}
|
||||
|
||||
class CommandBufferPool {
|
||||
- queue<LLGL::CommandBuffer*> freeBuffers
|
||||
- queue<LLGL::CommandBuffer*> readyBuffers
|
||||
+ AsyncRecord(function)
|
||||
+ SyncThreads()
|
||||
}
|
||||
|
||||
class ElementDrawer {
|
||||
- LLGL::CommandBuffer* currentCB
|
||||
+ DrawRect()
|
||||
+ DrawText()
|
||||
+ DrawRoundedRect()
|
||||
+ SetTransform()
|
||||
+ PushState()
|
||||
+ PopState()
|
||||
}
|
||||
|
||||
class WidgetCacheSystem {
|
||||
- map<Widget*, CachedTexture> cacheMap
|
||||
+ GetCachedTexture()
|
||||
+ InvalidateCache()
|
||||
+ UpdateCache()
|
||||
}
|
||||
|
||||
GUIFramework "1" *-- "1" WindowScheduler
|
||||
GUIFramework "1" *-- "1" CommandBufferPool
|
||||
GUIFramework "1" *-- "1" WidgetCacheSystem
|
||||
WindowScheduler "1" *-- "many" WindowContext
|
||||
CommandBufferPool "1" *-- "many" LLGL::CommandBuffer
|
||||
ElementDrawer "1" --* WidgetCacheSystem
|
||||
ElementDrawer "1" --* LLGL::CommandBuffer
|
||||
@enduml
|
26
src/core/c.puml
Normal file
26
src/core/c.puml
Normal file
@ -0,0 +1,26 @@
|
||||
@startuml
|
||||
actor MainThread
|
||||
participant WorkerThread
|
||||
participant GPU
|
||||
|
||||
MainThread -> WorkerThread : 分发录制任务
|
||||
activate WorkerThread
|
||||
|
||||
WorkerThread -> WorkerThread : 获取次级CB
|
||||
WorkerThread -> ElementDrawer : 录制绘制命令
|
||||
WorkerThread -> CommandBufferPool : 提交就绪CB
|
||||
deactivate WorkerThread
|
||||
|
||||
MainThread -> MainThread : 同步所有工作线程
|
||||
MainThread -> WindowContext : 开始主CB录制
|
||||
|
||||
loop 每个窗口
|
||||
WindowContext -> CommandBufferPool : 获取就绪CB列表
|
||||
CommandBufferPool -> WindowContext : 返回次级CB集合
|
||||
WindowContext -> LLGL::CommandBuffer : 执行次级CB
|
||||
end
|
||||
|
||||
MainThread -> GPU : 提交主CB
|
||||
GPU -> GPU : 执行绘制命令
|
||||
GPU -> Window : 呈现画面
|
||||
@enduml
|
16
src/core/d.puml
Normal file
16
src/core/d.puml
Normal file
@ -0,0 +1,16 @@
|
||||
@startuml
|
||||
state CommandBufferState {
|
||||
[*] --> Idle
|
||||
Idle --> Recording : Begin()
|
||||
Recording --> Executable : End()
|
||||
Executable --> Pending : Submit()
|
||||
Pending --> Idle : Reset()
|
||||
}
|
||||
|
||||
state CacheState {
|
||||
[*] --> Valid
|
||||
Valid --> Invalid : Widget Changed
|
||||
Invalid --> Rendering : Start Update
|
||||
Rendering --> Valid : Complete
|
||||
}
|
||||
@enduml
|
28
src/core/e.puml
Normal file
28
src/core/e.puml
Normal file
@ -0,0 +1,28 @@
|
||||
@startuml
|
||||
skinparam componentStyle rectangle
|
||||
skinparam nodesep 20
|
||||
skinparam ranksep 30
|
||||
|
||||
package "GUI Framework" {
|
||||
[Window Manager] as WM
|
||||
[Command Buffer Pool] as CBP
|
||||
[Cache System] as CS
|
||||
[Element Drawer] as ED
|
||||
}
|
||||
|
||||
package "LLGL Backend" {
|
||||
[Command Buffer] as CB
|
||||
[Texture] as Tex
|
||||
[Render Context] as RC
|
||||
}
|
||||
|
||||
WM --> CBP : manages
|
||||
CBP --> CB : creates
|
||||
ED --> CS : queries
|
||||
ED --> CB : records
|
||||
CS --> Tex : caches
|
||||
[GUI Framework] ..> [LLGL Backend] : depends on
|
||||
|
||||
note right of CB: 管理图形API原生命令缓冲区
|
||||
note bottom of Tex: 存储缓存的UI元素渲染结果
|
||||
@enduml
|
@ -3,10 +3,10 @@
|
||||
#include "async/thread_pool.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;
|
||||
mirage::duration_type delta_time = {};
|
||||
mirage::time_type begin_time = {};
|
||||
mirage::time_type last_time = {};
|
||||
LLGL::RenderSystemPtr renderer = nullptr;
|
||||
|
||||
namespace mirage {
|
||||
void on_llgl_log(LLGL::Log::ReportType type, const char* text, void* user_data) {
|
||||
@ -51,6 +51,7 @@ namespace mirage {
|
||||
spdlog::info("供应商: {}", renderer_info.vendorName.c_str());
|
||||
spdlog::info("着色器语言: {}", renderer_info.shadingLanguageName.c_str());
|
||||
spdlog::info("渲染器加载成功");
|
||||
|
||||
return true;
|
||||
}
|
||||
bool init_window(const init_info& in_info) {
|
||||
@ -66,6 +67,10 @@ namespace mirage {
|
||||
spdlog::info("主窗口创建成功");
|
||||
return true;
|
||||
}
|
||||
void destroy_renderer() {
|
||||
LLGL::RenderSystem::Unload(std::move(renderer));
|
||||
}
|
||||
|
||||
|
||||
bool init(const init_info& in_info) {
|
||||
spdlog::info("初始化 mirage");
|
||||
@ -84,7 +89,7 @@ namespace mirage {
|
||||
if (!lazy_singleton<window_manager>::get().destroy()) {
|
||||
spdlog::warn("窗口管理器销毋失败");
|
||||
}
|
||||
LLGL::RenderSystem::Unload(std::move(renderer));
|
||||
destroy_renderer();
|
||||
spdlog::info("mirage 销毁");
|
||||
}
|
||||
|
||||
@ -114,6 +119,7 @@ namespace mirage {
|
||||
return renderer_api::vulkan;
|
||||
#endif
|
||||
}
|
||||
|
||||
int run(const init_info& in_init_info) {
|
||||
try {
|
||||
if (!init(in_init_info)) {
|
||||
@ -144,4 +150,7 @@ namespace mirage {
|
||||
LLGL::RenderSystem* get_renderer() {
|
||||
return renderer.get();
|
||||
}
|
||||
LLGL::CommandQueue* get_main_command_queue() {
|
||||
return renderer->GetCommandQueue();
|
||||
}
|
||||
} // namespace mirage
|
||||
|
@ -20,4 +20,5 @@ namespace mirage {
|
||||
duration_type get_total_time();
|
||||
|
||||
LLGL::RenderSystem* get_renderer();
|
||||
LLGL::CommandQueue* get_main_command_queue();
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
#include <chrono>
|
||||
#include "LLGL/LLGL.h"
|
||||
#include <Eigen/Eigen>
|
||||
|
||||
namespace mirage {
|
||||
using time_type = decltype(std::chrono::high_resolution_clock::now());
|
||||
@ -76,4 +77,49 @@ namespace mirage {
|
||||
return desc;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
struct vertex_param_pack {
|
||||
union {
|
||||
float x;
|
||||
float r;
|
||||
};
|
||||
union {
|
||||
float y;
|
||||
float g;
|
||||
};
|
||||
union {
|
||||
float z;
|
||||
float b;
|
||||
};
|
||||
union {
|
||||
float w;
|
||||
float a;
|
||||
};
|
||||
vertex_param_pack(float in_x, float in_y, float in_z, float in_w) : x(in_x), y(in_y), z(in_z), w(in_w) {}
|
||||
vertex_param_pack(const LLGL::ColorRGBAf& in) : r(in.r), g(in.g), b(in.b), a(in.a) {}
|
||||
vertex_param_pack(const LLGL::Offset2D& in) : x(in.x), y(in.y), z(0), w(0) {}
|
||||
vertex_param_pack(const LLGL::Extent2D& in) : x(in.width), y(in.height), z(0), w(0) {}
|
||||
vertex_param_pack(const LLGL::Offset3D& in) : x(in.x), y(in.y), z(in.z), w(0) {}
|
||||
vertex_param_pack(const LLGL::Extent3D& in) : x(in.width), y(in.height), z(in.depth), w(0) {}
|
||||
vertex_param_pack(const Eigen::Vector2f& in) : x(in.x()), y(in.y()), z(0), w(0) {}
|
||||
vertex_param_pack(const Eigen::Vector3f& in) : x(in.x()), y(in.y()), z(in.z()), w(0) {}
|
||||
vertex_param_pack(const Eigen::Vector4f& in) : x(in.x()), y(in.y()), z(in.z()), w(in.w()) {}
|
||||
};
|
||||
|
||||
struct vertex_t {
|
||||
Eigen::Vector3d position;
|
||||
Eigen::Vector2d uv;
|
||||
LLGL::ColorRGBAf color;
|
||||
vertex_param_pack param_a;
|
||||
vertex_param_pack param_b;
|
||||
vertex_param_pack param_c;
|
||||
};
|
||||
|
||||
struct triangle_index_t {
|
||||
int32_t vertex_index[3];
|
||||
};
|
||||
|
||||
struct triangle_t {
|
||||
vertex_t vertex[3];
|
||||
};
|
||||
}
|
||||
|
135
src/core/renderer/render_buffer.cpp
Normal file
135
src/core/renderer/render_buffer.cpp
Normal file
@ -0,0 +1,135 @@
|
||||
#include "render_buffer.h"
|
||||
|
||||
namespace mirage {
|
||||
render_buffer::~render_buffer() {
|
||||
if (buffer) {
|
||||
get_renderer()->Release(*buffer);
|
||||
}
|
||||
}
|
||||
void render_buffer::init(const LLGL::BufferDescriptor& in_desc) {
|
||||
if (buffer) {
|
||||
throw std::runtime_error("Buffer already initialized");
|
||||
}
|
||||
|
||||
LLGL::BufferDescriptor desc = in_desc;
|
||||
desc.size = std::max(desc.size, DEFAULT_INITIAL_SIZE);
|
||||
|
||||
buffer = get_renderer()->CreateBuffer(desc);
|
||||
if (!buffer) {
|
||||
throw std::runtime_error("Failed to create buffer");
|
||||
}
|
||||
|
||||
capacity = desc.size;
|
||||
access_flags = desc.cpuAccessFlags;
|
||||
}
|
||||
void render_buffer::reserve(size_t new_capacity) {
|
||||
if (new_capacity > capacity) {
|
||||
resize(new_capacity, true);
|
||||
}
|
||||
}
|
||||
void render_buffer::shrink_to_fit() {
|
||||
if (capacity > size) {
|
||||
resize(size, true);
|
||||
}
|
||||
}
|
||||
void render_buffer::resize(size_t in_capacity_size, bool in_keep_data) {
|
||||
if (in_capacity_size <= capacity) {
|
||||
return;
|
||||
}
|
||||
LLGL::BufferDescriptor desc = buffer->GetDesc();
|
||||
desc.size = in_capacity_size;
|
||||
auto new_buffer = get_renderer()->CreateBuffer(desc);
|
||||
if (!new_buffer) {
|
||||
spdlog::error("无法创建缓冲区");
|
||||
return;
|
||||
}
|
||||
|
||||
if (in_keep_data) {
|
||||
const auto old_data = read();
|
||||
get_renderer()->WriteBuffer(*new_buffer, 0, old_data->get_data(), old_data->get_size_bytes());
|
||||
} else {
|
||||
size = 0;
|
||||
}
|
||||
|
||||
if (buffer) {
|
||||
get_renderer()->Release(*buffer);
|
||||
}
|
||||
buffer = new_buffer;
|
||||
capacity = in_capacity_size;
|
||||
}
|
||||
void render_buffer::clear() {
|
||||
size = 0;
|
||||
}
|
||||
heap_ptr render_buffer::read(size_t in_offset, size_t in_size) const {
|
||||
if (in_offset + in_size > size) {
|
||||
spdlog::error("读取缓冲区越界");
|
||||
return {};
|
||||
}
|
||||
auto out_heap = std::make_shared<heap>(in_size);
|
||||
get_renderer()->ReadBuffer(*buffer, in_offset, *out_heap, in_size);
|
||||
return out_heap;
|
||||
}
|
||||
heap_ptr render_buffer::read() const {
|
||||
return read(0, size);
|
||||
}
|
||||
void render_buffer::push(const void* data, size_t in_data_size) {
|
||||
if (size + in_data_size > capacity) {
|
||||
// 使用更智能的增长策略
|
||||
const size_t new_capacity = std::max(static_cast<size_t>(capacity * GROWTH_FACTOR), size + in_data_size);
|
||||
resize(new_capacity);
|
||||
}
|
||||
|
||||
// 批量写入优化
|
||||
if (access_flags & LLGL::CPUAccessFlags::Write) {
|
||||
// 如果支持直接写入,使用映射方式
|
||||
if (auto mapped_data = get_renderer()->MapBuffer(*buffer, LLGL::CPUAccess::WriteOnly)) {
|
||||
std::memcpy(static_cast<uint8_t*>(mapped_data) + size, data, in_data_size);
|
||||
get_renderer()->UnmapBuffer(*buffer);
|
||||
}
|
||||
} else {
|
||||
// 否则使用WriteBuffer
|
||||
get_renderer()->WriteBuffer(*buffer, size, data, in_data_size);
|
||||
}
|
||||
size += in_data_size;
|
||||
}
|
||||
void render_buffer::update_async(const void* data, size_t offset, size_t size) {
|
||||
if (offset + size > capacity) {
|
||||
throw std::out_of_range("Buffer update out of bounds");
|
||||
}
|
||||
|
||||
if (offset + size > capacity) {
|
||||
throw std::out_of_range("Buffer update out of bounds");
|
||||
}
|
||||
|
||||
// 使用 RAII 方式获取命令缓冲区
|
||||
const scoped_command cmd;
|
||||
if (!cmd.is_valid()) {
|
||||
throw std::runtime_error("Failed to acquire command buffer");
|
||||
}
|
||||
|
||||
// 复制数据到临时缓冲区(如果需要)
|
||||
std::vector temp_data(static_cast<const uint8_t*>(data), static_cast<const uint8_t*>(data) + size);
|
||||
|
||||
// 更新缓冲区
|
||||
cmd->UpdateBuffer(*buffer, offset, temp_data.data(), size);
|
||||
|
||||
// 提交到命令队列(scoped_command 析构时会自动 End)
|
||||
get_main_command_queue()->Submit(*cmd);
|
||||
}
|
||||
void render_buffer::batch_update_async(const std::vector<update_info>& updates) {
|
||||
scoped_command cmd;
|
||||
if (!cmd.is_valid()) {
|
||||
throw std::runtime_error("Failed to acquire command buffer");
|
||||
}
|
||||
|
||||
for (const auto& update : updates) {
|
||||
if (update.offset + update.size > capacity) {
|
||||
spdlog::warn("跳过越界更新");
|
||||
continue;
|
||||
}
|
||||
cmd->UpdateBuffer(*buffer, update.offset, update.data, update.size);
|
||||
}
|
||||
|
||||
get_main_command_queue()->Submit(*cmd);
|
||||
}
|
||||
} // namespace mirage
|
110
src/core/renderer/render_buffer.h
Normal file
110
src/core/renderer/render_buffer.h
Normal file
@ -0,0 +1,110 @@
|
||||
#pragma once
|
||||
#include "LLGL/LLGL.h"
|
||||
#include "mirage.h"
|
||||
#include "render_command_pool.h"
|
||||
#include <span>
|
||||
|
||||
namespace mirage {
|
||||
struct heap {
|
||||
explicit heap(size_t in_size) : size(in_size) {
|
||||
data = std::make_unique<uint8_t[]>(in_size);
|
||||
}
|
||||
auto get_size() const {
|
||||
return size;
|
||||
}
|
||||
auto get_size_bytes() const {
|
||||
return size;
|
||||
}
|
||||
auto get_data() const {
|
||||
return data.get();
|
||||
}
|
||||
|
||||
operator std::span<uint8_t>() const {
|
||||
return {data.get(), size};
|
||||
}
|
||||
operator std::span<const uint8_t>() const {
|
||||
return {data.get(), size};
|
||||
}
|
||||
operator uint8_t*() const {
|
||||
return data.get();
|
||||
}
|
||||
operator void*() const {
|
||||
return data.get();
|
||||
}
|
||||
|
||||
private:
|
||||
std::unique_ptr<uint8_t[]> data;
|
||||
size_t size;
|
||||
};
|
||||
|
||||
using heap_ptr = std::shared_ptr<heap>;
|
||||
|
||||
class render_buffer {
|
||||
public:
|
||||
// 添加预分配大小的常量
|
||||
static constexpr size_t DEFAULT_INITIAL_SIZE = 1024;
|
||||
static constexpr float GROWTH_FACTOR = 2.0f;
|
||||
|
||||
render_buffer() : buffer(nullptr), size(0), capacity(0), access_flags(0) {}
|
||||
// 禁用拷贝操作
|
||||
render_buffer(const render_buffer&) = delete;
|
||||
render_buffer& operator=(const render_buffer&) = delete;
|
||||
|
||||
~render_buffer();
|
||||
|
||||
void init(const LLGL::BufferDescriptor& in_desc);
|
||||
|
||||
// 预留空间
|
||||
void reserve(size_t new_capacity);
|
||||
|
||||
// 收缩到适合大小
|
||||
void shrink_to_fit();
|
||||
void resize(size_t in_capacity_size, bool in_keep_data = true);
|
||||
void clear();
|
||||
|
||||
[[nodiscard]] heap_ptr read(size_t in_offset, size_t in_size) const;
|
||||
[[nodiscard]] heap_ptr read() const;
|
||||
|
||||
void push(const void* data, size_t in_data_size);
|
||||
template <typename T>
|
||||
void push(std::span<const T> data) {
|
||||
push(data.data(), data.size_bytes());
|
||||
}
|
||||
template <class T>
|
||||
void push(const T& data) {
|
||||
push(&data, sizeof(T));
|
||||
}
|
||||
|
||||
// 异步更新缓冲区
|
||||
struct update_info {
|
||||
const void* data;
|
||||
size_t offset;
|
||||
size_t size;
|
||||
};
|
||||
void update_async(const void* data, size_t offset, size_t size);
|
||||
void batch_update_async(const std::vector<update_info>& updates);
|
||||
|
||||
[[nodiscard]] size_t get_size() const {
|
||||
return size;
|
||||
}
|
||||
[[nodiscard]] size_t get_capacity() const {
|
||||
return capacity;
|
||||
}
|
||||
[[nodiscard]] bool is_empty() const {
|
||||
return size == 0;
|
||||
}
|
||||
|
||||
operator LLGL::Buffer*() const {
|
||||
return buffer;
|
||||
}
|
||||
operator bool() const {
|
||||
return buffer;
|
||||
}
|
||||
|
||||
private:
|
||||
LLGL::Buffer* buffer;
|
||||
size_t size;
|
||||
size_t capacity;
|
||||
long access_flags;
|
||||
};
|
||||
} // namespace mirage
|
60
src/core/renderer/render_command_pool.cpp
Normal file
60
src/core/renderer/render_command_pool.cpp
Normal file
@ -0,0 +1,60 @@
|
||||
#include "render_command_pool.h"
|
||||
|
||||
#include "mirage.h"
|
||||
#include <spdlog/spdlog.h>
|
||||
|
||||
namespace mirage {
|
||||
|
||||
LLGL::CommandBuffer* render_command_pool::acquire() {
|
||||
std::lock_guard lock(mutex);
|
||||
|
||||
// 检查是否有可用的命令缓冲区
|
||||
for (auto& buffer : buffers) {
|
||||
if (!buffer.in_use) {
|
||||
buffer.in_use = true;
|
||||
return buffer.cmd_buffer;
|
||||
}
|
||||
}
|
||||
|
||||
// 如果没有可用的,创建新的
|
||||
return create_new_buffer();
|
||||
}
|
||||
void render_command_pool::release(const LLGL::CommandBuffer* in_cmd_buffer) {
|
||||
std::lock_guard lock(mutex);
|
||||
|
||||
for (auto& buffer : buffers) {
|
||||
if (buffer.cmd_buffer == in_cmd_buffer) {
|
||||
buffer.in_use = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
void render_command_pool::cleanup() {
|
||||
std::lock_guard lock(mutex);
|
||||
|
||||
for (auto& buffer : buffers) {
|
||||
if (buffer.cmd_buffer) {
|
||||
get_renderer()->Release(*buffer.cmd_buffer);
|
||||
}
|
||||
}
|
||||
buffers.clear();
|
||||
}
|
||||
LLGL::CommandBuffer* render_command_pool::create_new_buffer() {
|
||||
if (buffers.size() >= MAX_POOL_SIZE) {
|
||||
spdlog::warn("Command pool reached maximum size");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
LLGL::CommandBufferDescriptor desc;
|
||||
desc.flags = LLGL::CommandBufferFlags::ImmediateSubmit;
|
||||
|
||||
auto* cmd_buffer = get_renderer()->CreateCommandBuffer(desc);
|
||||
if (!cmd_buffer) {
|
||||
spdlog::error("Failed to create command buffer");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
buffers.push_back({cmd_buffer, true});
|
||||
return cmd_buffer;
|
||||
}
|
||||
} // namespace mirage
|
67
src/core/renderer/render_command_pool.h
Normal file
67
src/core/renderer/render_command_pool.h
Normal file
@ -0,0 +1,67 @@
|
||||
#pragma once
|
||||
#include "LLGL/LLGL.h"
|
||||
#include "misc/lazy_singleton.h"
|
||||
#include <mutex>
|
||||
|
||||
namespace mirage {
|
||||
class render_command_pool {
|
||||
friend class lazy_singleton_func;
|
||||
public:
|
||||
// 获取一个可用的命令缓冲区
|
||||
LLGL::CommandBuffer* acquire();
|
||||
|
||||
// 释放命令缓冲区回池
|
||||
void release(const LLGL::CommandBuffer* in_cmd_buffer);
|
||||
|
||||
// 清理所有资源
|
||||
void cleanup();
|
||||
private:
|
||||
struct buffer_entry {
|
||||
LLGL::CommandBuffer* cmd_buffer = nullptr;
|
||||
bool in_use = false;
|
||||
};
|
||||
|
||||
std::vector<buffer_entry> buffers;
|
||||
std::mutex mutex;
|
||||
|
||||
static constexpr size_t INITIAL_POOL_SIZE = 4;
|
||||
static constexpr size_t MAX_POOL_SIZE = 16;
|
||||
|
||||
render_command_pool() {
|
||||
// 预创建一些命令缓冲区
|
||||
for (size_t i = 0; i < INITIAL_POOL_SIZE; ++i) {
|
||||
create_new_buffer();
|
||||
}
|
||||
}
|
||||
|
||||
~render_command_pool() {
|
||||
cleanup();
|
||||
}
|
||||
|
||||
LLGL::CommandBuffer* create_new_buffer();
|
||||
};
|
||||
|
||||
// RAII 包装器用于自动管理命令缓冲区的获取和释放
|
||||
class scoped_command {
|
||||
public:
|
||||
scoped_command() : cmd_buffer(lazy_singleton<render_command_pool>::get().acquire()) {
|
||||
if (cmd_buffer) {
|
||||
cmd_buffer->Begin();
|
||||
}
|
||||
}
|
||||
|
||||
~scoped_command() {
|
||||
if (cmd_buffer) {
|
||||
cmd_buffer->End();
|
||||
lazy_singleton<render_command_pool>::get().release(cmd_buffer);
|
||||
}
|
||||
}
|
||||
|
||||
operator LLGL::CommandBuffer*() const { return cmd_buffer; }
|
||||
LLGL::CommandBuffer* operator->() const { return cmd_buffer; }
|
||||
|
||||
[[nodiscard]] bool is_valid() const { return cmd_buffer != nullptr; }
|
||||
private:
|
||||
LLGL::CommandBuffer* cmd_buffer;
|
||||
};
|
||||
} // namespace mirage
|
@ -1,17 +1,12 @@
|
||||
#include "render_context.h"
|
||||
|
||||
#include "LLGL/Utils/VertexFormat.h"
|
||||
#include "mirage.h"
|
||||
|
||||
namespace mirage {
|
||||
render_context::~render_context() {
|
||||
if (main_command_buffer) {
|
||||
get_renderer()->Release(*main_command_buffer);
|
||||
}
|
||||
if (vertex_buffer) {
|
||||
get_renderer()->Release(*vertex_buffer);
|
||||
}
|
||||
if (swap_chain) {
|
||||
get_renderer()->Release(*swap_chain);
|
||||
if (command_buffer) {
|
||||
get_renderer()->Release(*command_buffer);
|
||||
}
|
||||
}
|
||||
bool render_context::init(const swap_chain_descriptor& in_desc, const std::shared_ptr<LLGL::Surface>& in_surface) {
|
||||
@ -22,30 +17,30 @@ namespace mirage {
|
||||
spdlog::error("无法创建交换链");
|
||||
return false;
|
||||
}
|
||||
main_command_buffer = get_renderer()->CreateCommandBuffer(LLGL::CommandBufferFlags::ImmediateSubmit);
|
||||
if (main_command_buffer == nullptr) {
|
||||
command_buffer = get_renderer()->CreateCommandBuffer(LLGL::CommandBufferFlags::ImmediateSubmit);
|
||||
if (command_buffer == nullptr) {
|
||||
spdlog::error("无法创建命令缓冲区");
|
||||
return false;
|
||||
}
|
||||
set_vsync(in_desc.vsync);
|
||||
// LLGL::BufferDescriptor vertex_buffer_descriptor{};
|
||||
// vertex_buffer = get_renderer()->CreateBuffer(vertex_buffer_descriptor);
|
||||
create_vertex_buffer();
|
||||
create_index_buffer();
|
||||
return true;
|
||||
}
|
||||
render_context::update_status render_context::update(const duration_type& in_delta_time) {
|
||||
if (!main_command_buffer || !swap_chain) {
|
||||
if (!command_buffer || !swap_chain) {
|
||||
return update_status::fail;
|
||||
}
|
||||
if (!swap_chain->IsPresentable()) {
|
||||
return update_status::wait_for_present;
|
||||
}
|
||||
main_command_buffer->Begin();
|
||||
command_buffer->Begin();
|
||||
{
|
||||
main_command_buffer->BeginRenderPass(*swap_chain);
|
||||
main_command_buffer->Clear(LLGL::ClearFlags::Color, {0.1f, 0.1f, 0.2f, 1.0f});
|
||||
main_command_buffer->EndRenderPass();
|
||||
command_buffer->BeginRenderPass(*swap_chain);
|
||||
command_buffer->Clear(LLGL::ClearFlags::Color, {0.1f, 0.1f, 0.2f, 1.0f});
|
||||
command_buffer->EndRenderPass();
|
||||
}
|
||||
main_command_buffer->End();
|
||||
command_buffer->End();
|
||||
swap_chain->Present();
|
||||
return update_status::success;
|
||||
}
|
||||
@ -62,4 +57,29 @@ namespace mirage {
|
||||
spdlog::info("垂直同步: {}", vsync);
|
||||
}
|
||||
}
|
||||
|
||||
void render_context::create_vertex_buffer() {
|
||||
// 创建顶点格式布局
|
||||
LLGL::VertexFormat vertexFormat;
|
||||
|
||||
// 添加顶点属性
|
||||
vertexFormat.AppendAttribute({"position", LLGL::Format::RGB32Float}); // float3 position
|
||||
vertexFormat.AppendAttribute({"texCoord0", LLGL::Format::RG32Float}); // float2 uv
|
||||
vertexFormat.AppendAttribute({"color", LLGL::Format::RGBA32Float}); // float4 color
|
||||
vertexFormat.AppendAttribute({"texCoord1", LLGL::Format::RGBA32Float}); // float4 param_a
|
||||
vertexFormat.AppendAttribute({"texCoord2", LLGL::Format::RGBA32Float}); // float4 param_b
|
||||
vertexFormat.AppendAttribute({"texCoord3", LLGL::Format::RGBA32Float}); // float4 param_c
|
||||
|
||||
LLGL::BufferDescriptor vertex_buffer_descriptor{};
|
||||
vertex_buffer_descriptor.size = sizeof(vertex_t) * 512;
|
||||
vertex_buffer_descriptor.bindFlags = LLGL::BindFlags::VertexBuffer;
|
||||
vertex_buffer_descriptor.vertexAttribs = vertexFormat.attributes;
|
||||
vertex_buffer.init(vertex_buffer_descriptor);
|
||||
}
|
||||
void render_context::create_index_buffer() {
|
||||
LLGL::BufferDescriptor index_buffer_descriptor{};
|
||||
index_buffer_descriptor.size = sizeof(triangle_index_t) * 512;
|
||||
index_buffer_descriptor.bindFlags = LLGL::BindFlags::IndexBuffer;
|
||||
index_buffer.init(index_buffer_descriptor);
|
||||
}
|
||||
} // namespace mirage
|
||||
|
@ -1,15 +1,13 @@
|
||||
#pragma once
|
||||
#include "LLGL/LLGL.h"
|
||||
#include "misc/mirage_type.h"
|
||||
#include "render_buffer.h"
|
||||
#include <span>
|
||||
|
||||
namespace mirage {
|
||||
class render_context {
|
||||
public:
|
||||
enum class update_status {
|
||||
success,
|
||||
wait_for_present,
|
||||
fail
|
||||
};
|
||||
enum class update_status { success, wait_for_present, fail };
|
||||
|
||||
~render_context();
|
||||
|
||||
@ -24,10 +22,21 @@ namespace mirage {
|
||||
[[nodiscard]] auto get_swap_chain() const {
|
||||
return swap_chain;
|
||||
}
|
||||
|
||||
[[nodiscard]] size_t get_vertex_count() const {
|
||||
return vertex_buffer.get_size() / sizeof(vertex_t);
|
||||
}
|
||||
[[nodiscard]] size_t get_index_count() const {
|
||||
return index_buffer.get_size() / sizeof(triangle_index_t);
|
||||
}
|
||||
private:
|
||||
LLGL::SwapChain* swap_chain = nullptr;
|
||||
LLGL::Buffer* vertex_buffer = nullptr;
|
||||
LLGL::CommandBuffer* main_command_buffer = nullptr;
|
||||
bool vsync = true;
|
||||
void create_vertex_buffer();
|
||||
void create_index_buffer();
|
||||
|
||||
render_buffer vertex_buffer;
|
||||
render_buffer index_buffer;
|
||||
LLGL::CommandBuffer* command_buffer = nullptr;
|
||||
LLGL::SwapChain* swap_chain = nullptr;
|
||||
bool vsync = true;
|
||||
};
|
||||
} // namespace mirage
|
||||
|
1
src/core/renderer/render_draw_command.cpp
Normal file
1
src/core/renderer/render_draw_command.cpp
Normal file
@ -0,0 +1 @@
|
||||
#include "render_draw_command.h"
|
7
src/core/renderer/render_draw_command.h
Normal file
7
src/core/renderer/render_draw_command.h
Normal file
@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
namespace mirage {
|
||||
class render_draw_command {
|
||||
|
||||
};
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
struct VSInput {
|
||||
float2 position : POSITION;
|
||||
float3 position : POSITION;
|
||||
float2 uv : TEXCOORD0;
|
||||
float4 color : COLOR0;
|
||||
float4 param_a : TEXCOORD1;
|
||||
|
Loading…
x
Reference in New Issue
Block a user