Files
mirage/example/new_pipeline/new_pipeline_example.cpp
nanako 74efe4e201 Refactor layout system: Replace slot and property_slot with layout modifiers
- Removed the slot and property_slot classes, consolidating their functionality into a new modifier system.
- Introduced align_modifier, padding_modifier, and stretch_modifier to handle layout properties.
- Updated overlay and stack classes to utilize the new modifier system for layout management.
- Simplified event handling by integrating layout modifiers directly into the event target retrieval process.
- Removed unused includes and cleaned up code for better readability and maintainability.
2025-11-30 15:53:24 +08:00

603 lines
17 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include "window_manager.h"
#include "desktop/glfw_window.h"
#include "vulkan/context.h"
#include "vulkan/device_manager.h"
#include "vulkan/logical_device.h"
#include "vulkan/swapchain.h"
#include "vulkan/resource_manager.h"
#include "pipeline/render_pipeline.h"
#include "render_command.h"
#include <iostream>
#include <memory>
#include <chrono>
#include <cmath>
#include "button.h"
#include "layout/fixed_box.h"
#include "imager.h"
#include "layout/overlay.h"
#include "post_effect.h"
#include "layout/stack.h"
#include "fill_box.h"
#include "layout/modifiers/modifiers.h" // 新的布局修饰器
#include "image/texture_manager.h"
using namespace mirage;
/// @brief 新渲染管线示例应用
///
/// 展示新的渲染管线系统的使用方式,包括:
/// 1. 基本几何渲染(多个矩形)
/// 2. z_order 排序验证
/// 3. 后效应用(模糊效果)
/// 4. 窗口 resize 处理
class NewPipelineExample {
public:
NewPipelineExample() = default;
void run() {
std::cout << "=== Mirage 新渲染管线示例 ===\n\n";
if (!init_window())
return;
if (!init_vulkan())
return;
if (!init_pipeline())
return;
if (!load_texture())
return;
main_loop();
cleanup();
}
private:
// ========================================================================
// 窗口和 Vulkan 资源
// ========================================================================
window_manager wm_;
window_interface* window_ = nullptr;
glfw_window* glfw_win_ = nullptr;
std::optional<render_context> context_;
vk::SurfaceKHR surface_;
vk::PhysicalDevice physical_device_;
std::optional<logical_device> logical_;
std::optional<resource_manager> res_mgr_;
std::optional<swapchain> swap_;
std::optional<texture_manager> texture_manager_;
// 新的渲染管线
std::unique_ptr<render_pipeline> pipeline_;
// 窗口尺寸
uint32_t window_width_ = 1280;
uint32_t window_height_ = 720;
// 动画时间
float time_ = 0.0f;
std::chrono::steady_clock::time_point start_time_;
texture_id_t texture_id_;
vec2i_t texture_size_;
// ========================================================================
// 初始化方法
// ========================================================================
/// 初始化窗口
bool init_window() {
std::cout << "1. 创建窗口...\n";
window_create_info window_info{
.title = "Mirage - 新渲染管线示例",
.width = static_cast<int>(window_width_),
.height = static_cast<int>(window_height_),
.mode = window_mode::WINDOWED,
.flags = window_flag::RESIZABLE | window_flag::VISIBLE |
window_flag::DECORATED | window_flag::FOCUSED
};
auto window_id_result = wm_.create_window(window_info);
if (!window_id_result) {
std::cerr << " ✗ 创建窗口失败: " << window_id_result.error() << "\n";
return false;
}
window_ = wm_.get_window(window_id_result.value());
if (!window_) {
std::cerr << " ✗ 获取窗口失败\n";
return false;
}
glfw_win_ = dynamic_cast<glfw_window*>(window_);
if (!glfw_win_) {
std::cerr << " ✗ 窗口类型错误\n";
return false;
}
std::cout << " ✓ 窗口创建成功\n\n";
return true;
}
/// 初始化 Vulkan
bool init_vulkan() {
std::cout << "2. 初始化 Vulkan...\n";
// 创建 Vulkan 上下文
auto required_extensions = glfw_window::get_required_instance_extensions();
render_context::create_info ctx_info{
.app_name = "Mirage 新管线示例",
.app_version = VK_MAKE_VERSION(1, 0, 0),
.engine_name = "Mirage Engine",
.engine_version = VK_MAKE_VERSION(1, 0, 0),
.enable_validation = true,
.required_extensions = required_extensions
};
auto context_result = render_context::create(ctx_info);
if (!context_result) {
std::cerr << " ✗ 创建 Vulkan 上下文失败: "
<< vk::to_string(context_result.error()) << "\n";
return false;
}
context_ = std::move(context_result.value());
std::cout << " ✓ Vulkan 上下文创建成功\n";
// 创建 Surface
std::cout << "3. 创建 Vulkan Surface...\n";
surface_ = glfw_win_->create_vulkan_surface(context_->get_instance());
if (!surface_) {
std::cerr << " ✗ 创建 Surface 失败\n";
return false;
}
std::cout << " ✓ Surface 创建成功\n";
// 选择物理设备
std::cout << "4. 选择物理设备...\n";
device_manager dev_mgr(context_->get_instance());
auto physical_device_result = dev_mgr.select_primary_device(surface_);
if (!physical_device_result) {
std::cerr << " ✗ 选择物理设备失败: "
<< vk::to_string(physical_device_result.error()) << "\n";
return false;
}
physical_device_ = physical_device_result.value();
auto device_props = physical_device_.getProperties();
std::cout << " ✓ 已选择: " << device_props.deviceName << "\n";
// 创建逻辑设备
std::cout << "5. 创建逻辑设备...\n";
auto logical_device_result = logical_device::create(physical_device_, surface_);
if (!logical_device_result) {
std::cerr << " ✗ 创建逻辑设备失败: "
<< vk::to_string(logical_device_result.error()) << "\n";
return false;
}
logical_ = std::move(logical_device_result.value());
std::cout << " ✓ 逻辑设备创建成功\n";
// 创建资源管理器
res_mgr_.emplace(*logical_, physical_device_, context_->get_instance());
// 创建纹理管理器
texture_manager_.emplace(*res_mgr_, *logical_);
// 创建 Swapchain
std::cout << "6. 创建 Swapchain...\n";
auto size = window_->get_framebuffer_size();
window_width_ = static_cast<uint32_t>(size.x());
window_height_ = static_cast<uint32_t>(size.y());
auto swapchain_result = swapchain::create(
*logical_, physical_device_, surface_,
window_width_, window_height_,
true, // 启用 VSync
*res_mgr_);
if (!swapchain_result) {
std::cerr << " ✗ 创建 Swapchain 失败: "
<< vk::to_string(swapchain_result.error()) << "\n";
return false;
}
swap_ = std::move(swapchain_result.value());
std::cout << " ✓ Swapchain 创建成功 (图像数: "
<< swap_->get_image_count() << ")\n\n";
return true;
}
/// 初始化渲染管线
bool init_pipeline() {
std::cout << "7. 创建新渲染管线...\n";
try {
// 配置管线选项
render_pipeline::config cfg{
.frames_in_flight = 2 // 双缓冲
};
// 创建管线实例
pipeline_ = std::make_unique<render_pipeline>(
*logical_,
*swap_,
*res_mgr_,
*texture_manager_,
cfg);
// 初始化管线(创建所有子组件)
pipeline_->initialize();
std::cout << " ✓ 新渲染管线创建成功\n";
std::cout << " - 离屏渲染目标: 已创建\n";
std::cout << " - 命令处理器: 已创建\n";
std::cout << " - 几何渲染器: 已创建\n";
std::cout << " - 后效应用器: 已创建\n";
std::cout << " - 帧调度器: 已创建\n\n";
return true;
}
catch (const std::exception& e) {
std::cerr << " ✗ 创建渲染管线失败: " << e.what() << "\n";
return false;
}
}
bool load_texture() {
texture_id_ = texture_manager_->load_texture("D:\\G2uY1fJa8AAOucs.jpg").value();
texture_size_ = texture_manager_->get_texture(texture_id_)->size();
return true;
}
// ========================================================================
// 渲染命令生成
// ========================================================================
/// 创建测试渲染命令
/// 包含多个测试场景基本几何、z_order排序、后效应用
auto create_test_commands() -> std::vector<render_command> {
std::vector<render_command> commands;
// ====================================================================
// 场景 1: 基本几何渲染 - 多个矩形
// ====================================================================
// 背景矩形(大的深蓝色)
{
auto cmd = rectangle_command(
vec2f_t(50.0f, 50.0f),
vec2f_t(300.0f, 200.0f),
color::from_rgba(30, 60, 120, 255),
10.0f // 圆角
);
cmd.order.z_order = 0; // 最底层
commands.emplace_back(cmd);
}
// 前景矩形(较小的浅蓝色,应该在背景上面)
{
auto cmd = rectangle_command(
vec2f_t(100.0f, 100.0f),
vec2f_t(200.0f, 150.0f),
color::from_rgba(100, 150, 200, 255),
5.0f);
cmd.order.z_order = 1; // 在背景上面
commands.emplace_back(cmd);
}
// ====================================================================
// 场景 2: z_order 排序测试
// ====================================================================
// 红色矩形 (z_order = 2)
{
auto cmd = rectangle_command(
vec2f_t(400.0f, 50.0f),
vec2f_t(150.0f, 150.0f),
color::from_rgba(200, 50, 50, 255),
8.0f);
cmd.order.z_order = 2;
commands.emplace_back(cmd);
}
// 绿色矩形 (z_order = 3应该在红色上面)
{
auto cmd = rectangle_command(
vec2f_t(450.0f, 100.0f),
vec2f_t(150.0f, 150.0f),
color::from_rgba(50, 200, 50, 255),
8.0f);
cmd.order.z_order = 3;
commands.emplace_back(cmd);
}
// 黄色矩形 (z_order = 1应该在红色和绿色下面)
{
auto cmd = rectangle_command(
vec2f_t(425.0f, 75.0f),
vec2f_t(150.0f, 150.0f),
color::from_rgba(200, 200, 50, 255),
8.0f);
cmd.order.z_order = 1;
commands.emplace_back(cmd);
}
// ====================================================================
// 场景 3: 后效测试 - 模糊效果
// ====================================================================
// 紫色背景矩形
{
auto cmd = rectangle_command(
vec2f_t(700.0f, 50.0f),
vec2f_t(250.0f, 200.0f),
color::from_rgba(150, 50, 150, 255),
10.0f);
cmd.order.z_order = 0;
commands.emplace_back(cmd);
}
// 应用模糊效果到紫色区域
{
auto blur = blur_effect(
vec2f_t(700.0f, 50.0f),
vec2f_t(250.0f, 200.0f),
8.0f, // 模糊半径
1.0f // 强度
);
blur.order.z_order = 10; // 后效通常在几何之后
commands.emplace_back(post_effect_command{blur});
}
// ====================================================================
// 场景 4: 动画矩形(测试持续渲染)
// ====================================================================
// 使用时间创建动画效果
float offset_x = 50.0f + std::sin(time_) * 30.0f;
float offset_y = 300.0f + std::cos(time_) * 30.0f;
{
auto cmd = rectangle_command(
vec2f_t(offset_x, offset_y),
vec2f_t(100.0f, 100.0f),
color::from_rgba(255, 180, 50, 255),
15.0f);
cmd.order.z_order = 5;
commands.emplace_back(cmd);
}
// ====================================================================
// 场景 5: 暗角效果测试
// ====================================================================
// 橙色矩形
{
auto cmd = rectangle_command(
vec2f_t(400.0f, 300.0f),
vec2f_t(200.0f, 180.0f),
color::from_rgba(200, 150, 50, 255),
5.0f);
cmd.order.z_order = 0;
commands.emplace_back(cmd);
}
// 应用暗角效果
{
auto vignette = vignette_effect(
vec2f_t(400.0f, 300.0f),
vec2f_t(200.0f, 180.0f),
0.5f, // 半径
0.5f, // 柔和度
0.8f // 强度
);
vignette.order.z_order = 10;
commands.emplace_back(post_effect_command{vignette});
}
return commands;
}
/// 创建widget测试渲染命令
auto create_widget_test_commands(render_command_builder& builder) -> std::vector<render_command> {
static uint32_t widget_build_count = 0;
widget_build_count++;
auto on_click = []() {
std::cout << "clicked" << std::endl;
};
// ===================================================================
// 布局修饰器管道语法示例
// ===================================================================
//
// ===== 旧写法(已弃用)=====
// slot{
// imager{}.texture_id(id_)
// }.align(alignment::CENTER).padding(10.f)
//
// slot{
// overlay{...}
// } | stretch()
//
// ===== 新写法(推荐)=====
// imager{}.texture_id(id_)
// | align(alignment::CENTER)
// | padding(10.f)
//
// overlay{...} | stretch()
//
// ===================================================================
// 使用新的布局修饰器管道语法
v_stack v{
// 普通方式:直接放置控件
button{
"Hello",
on_click
},
// 新的管道语法:通过修饰器添加布局属性
// 不再需要 slot{} 包装,直接使用 | 管道操作符
overlay{
// 使用管道语法设置图片居中对齐和边距
imager{}
.texture_id(texture_id_)
.fit(image_fit::contain)
.set_texture_size(texture_size_)
| align(alignment::CENTER)
| padding(10.f),
// 普通后效控件
post_effect_widget{
fill_box{},
blur_effect{20.f}
},
} | stretch() // 直接对 overlay 应用 stretch无需 slot 包装
};
layout_state state;
state.set_root(transform2d_t::Identity(), window_->get_framebuffer_size().cast<float>());
v.arrange(state);
v.build_render_commands(builder);
auto commands = builder.get_sorted_commands();
return commands;
}
// ========================================================================
// 主循环
// ========================================================================
void main_loop() {
std::cout << "=== 进入主循环 ===\n";
std::cout << "按 ESC 或关闭窗口退出\n";
std::cout << "调整窗口大小测试 resize 处理\n\n";
start_time_ = std::chrono::steady_clock::now();
uint32_t frame_count = 0;
// 添加调试计数器
static uint32_t build_commands_call_count = 0;
// 设置窗口事件回调(处理 resize
window_->set_event_callback([this](const event& e) {
if (e.type == event_type::WINDOW_RESIZE) {
pipeline_->on_resize(e.window.width, e.window.height);
window_width_ = e.window.width;
window_height_ = e.window.height;
}
});
// 主渲染循环
while (!wm_.all_windows_closed()) {
// 处理窗口事件
wm_.poll_all_events();
// 更新动画时间
auto now = std::chrono::steady_clock::now();
auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(
now - start_time_)
.count();
time_ = elapsed / 1000.0f;
// 生成渲染命令
render_command_builder builder;
// 调试:记录 build_render_commands 调用
build_commands_call_count++;
// auto commands = create_test_commands();
auto commands = create_widget_test_commands(builder);
// 调试:打印每帧的命令数量
if (frame_count % 60 == 0) {
std::cout << "[DEBUG] 帧 " << frame_count
<< ": build_render_commands 调用次数=" << build_commands_call_count
<< ", 生成命令数=" << commands.size() << std::endl;
}
// 使用新管线渲染帧
if (!pipeline_->render_frame(commands)) {
// 渲染失败,通常是 swapchain 过期
// on_resize 已经在事件回调中处理
std::cerr << "渲染帧失败,跳过..." << std::endl;
continue;
}
frame_count++;
// 每 60 帧输出一次信息
if (frame_count % 60 == 0) {
std::cout << "帧数: " << frame_count
<< ", 时间: " << time_ << "s" << std::endl;
}
}
std::cout << "\n=== 清理资源 ===\n";
pipeline_->wait_idle();
std::cout << "总帧数: " << frame_count << "\n";
std::cout << "总 build_render_commands 调用次数: " << build_commands_call_count << "\n";
}
// ========================================================================
// 清理
// ========================================================================
void cleanup() {
// 1. 清理管线(必须在 device 之前)
if (pipeline_) {
pipeline_->cleanup();
pipeline_.reset();
}
// 2. 等待设备空闲
if (logical_) {
auto result = logical_->get_handle().waitIdle();
if (result != vk::Result::eSuccess) {
std::cerr << "警告: waitIdle 失败: " << vk::to_string(result) << "\n";
}
}
// 3. 清理 Swapchain必须在 logical device 销毁前)
swap_.reset();
// 4. 清理纹理管理器(必须在 resource_manager 之前!)
texture_manager_.reset();
// 5. 清理资源管理器
res_mgr_.reset();
// 6. 清理逻辑设备
logical_.reset();
// 7. 销毁 Surface必须在 Instance 销毁前)
if (context_ && surface_) {
context_->get_instance().destroySurfaceKHR(surface_);
surface_ = nullptr;
}
// 8. 清理 Context最后销毁包含 Instance
context_.reset();
std::cout << "\n=== 程序成功完成 ===\n";
}
};
// ============================================================================
// 主函数
// ============================================================================
int main() {
try {
NewPipelineExample app;
app.run();
return 0;
}
catch (const std::exception& e) {
std::cerr << "异常: " << e.what() << "\n";
return 1;
}
}