From 581d90924f89a86d416ad37ecba0b3770078c542 Mon Sep 17 00:00:00 2001 From: nanako <469449812@qq.com> Date: Mon, 19 Jan 2026 20:32:59 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E9=94=99=E8=AF=AF=E4=BB=A3?= =?UTF-8?q?=E7=A0=81=E4=BB=A5=E6=94=AF=E6=8C=81WebGPU=EF=BC=8C=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0=E7=AA=97=E5=8F=A3=E6=9C=80=E5=B0=8F=E5=8C=96=E5=8A=9F?= =?UTF-8?q?=E8=83=BD=EF=BC=8C=E4=BC=98=E5=8C=96=E4=BA=A4=E6=8D=A2=E9=93=BE?= =?UTF-8?q?=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- example/main.cpp | 1 + src/render/test_shader_code.wgsl | 2 +- src/render/wgpu_context.cpp | 2 +- src/types/error.h | 10 ++-- src/window/window.cpp | 97 ++++++++++++++++++++++++-------- src/window/window.h | 4 +- src/window/window_manager.cpp | 2 +- 7 files changed, 85 insertions(+), 33 deletions(-) diff --git a/example/main.cpp b/example/main.cpp index 26ca74a..0a788df 100644 --- a/example/main.cpp +++ b/example/main.cpp @@ -7,6 +7,7 @@ using namespace mirai; int main(int argc, char* argv[]) { mirai_app_config config; config.window_mgr_config.main_window.size = vec2i{800, 600}; + config.window_mgr_config.main_window.flags = SDL_WINDOW_RESIZABLE; mirai::mirai_app app; app.setup(config); diff --git a/src/render/test_shader_code.wgsl b/src/render/test_shader_code.wgsl index 7b48094..68a8568 100644 --- a/src/render/test_shader_code.wgsl +++ b/src/render/test_shader_code.wgsl @@ -15,5 +15,5 @@ fn vs_main(@builtin(vertex_index) in_vertex_index: u32) -> @builtin(position) ve @fragment fn fs_main() -> @location(0) vec4 { // 输出红色 - return vec4(1.0, 0.0, 0.0, 1.0); + return vec4(0.2, 0.0, 0.2, 1.0); } diff --git a/src/render/wgpu_context.cpp b/src/render/wgpu_context.cpp index 29cafa8..9ad0494 100644 --- a/src/render/wgpu_context.cpp +++ b/src/render/wgpu_context.cpp @@ -13,7 +13,7 @@ namespace mirai { void wgpu_context::test_shader() { - std::filesystem::path shader_path = R"(F:\Projects\mirai\src\render\test_shader_code.wgsl)"; + std::filesystem::path shader_path = R"(D:\Projects\mirai\src\render\test_shader_code.wgsl)"; auto code = make_obj(shader_path); auto sm = make_obj(wgpu_device_, code); diff --git a/src/types/error.h b/src/types/error.h index b6c29f5..068cea1 100644 --- a/src/types/error.h +++ b/src/types/error.h @@ -68,8 +68,8 @@ enum class error_code : u32 { corrupted_file = 206, // ---- 图形/渲染错误 (300-399) ---- - /// Vulkan 初始化失败 - vulkan_init_failed = 300, + /// WebGPU 初始化失败 + wgpu_init_failed = 300, /// 设备不支持 device_not_supported = 301, /// 着色器编译失败 @@ -87,7 +87,9 @@ enum class error_code : u32 { /// 资源绑定错误 resource_binding_error = 308, /// 分配失败 - vulkan_allocation_failed = 309, + allocation_failed = 309, + /// 无效操作 + invalid_operation = 310, // ---- 窗口/输入错误 (400-499) ---- /// 窗口创建失败 @@ -183,7 +185,7 @@ enum class error_code : u32 { return "Invalid format"; case error_code::corrupted_file: return "Corrupted file"; - case error_code::vulkan_init_failed: + case error_code::wgpu_init_failed: return "Vulkan initialization failed"; case error_code::device_not_supported: return "Device not supported"; diff --git a/src/window/window.cpp b/src/window/window.cpp index a249b7f..66b6512 100644 --- a/src/window/window.cpp +++ b/src/window/window.cpp @@ -47,18 +47,44 @@ namespace mirai { return; } } + const auto& size = get_framebuffer_size(); + // size.all() 返回宽高都大于 0 + if (is_minimized() || !size.all()) { + // 窗口被最小化或尺寸无效, 跳过渲染 + return; + } + auto swapchain_result = acquire_next_swapchain_texture(); + if (!swapchain_result.has_value()) { + switch (swapchain_result.error()) { + case wgpu::SurfaceGetCurrentTextureStatus::Outdated: + need_swapchain_rebuild_ = true; + MIRAI_LOG_WARN("交换链过时, 需要重建"); + return; + case wgpu::SurfaceGetCurrentTextureStatus::Lost: + need_swapchain_rebuild_ = true; + MIRAI_LOG_WARN("交换链丢失, 需要重建"); + return; + case wgpu::SurfaceGetCurrentTextureStatus::Timeout: + MIRAI_LOG_ERROR("获取交换链纹理超时"); + break; + default: + MIRAI_LOG_ERROR("获取交换链纹理失败: 状态码 {}", static_cast(swapchain_result.error())); + } + return; + } + auto [texture, texture_view] = swapchain_result.value(); + wgpu::raii::CommandEncoder encoder = wgpu_context::instance().get_command_encoder(); wgpu::raii::Queue queue = wgpu_context::instance().get_queue(); - auto size = get_framebuffer_size(); - auto pipeline = wgpu_context::instance().get_test_pipeline(); - auto [texture, texture_view] = acquire_next_swapchain_texture(); + auto pipeline = wgpu_context::instance().get_test_pipeline(); + wgpu::RenderPassColorAttachment color_attachment{}; color_attachment.setDefault(); - color_attachment.view = texture_view; - color_attachment.loadOp = wgpu::LoadOp::Clear; - color_attachment.storeOp = wgpu::StoreOp::Store; - color_attachment.clearValue = {0.95f, 0.35f, 0.49f, 1.0f}; + color_attachment.view = texture_view; + color_attachment.loadOp = wgpu::LoadOp::Clear; + color_attachment.storeOp = wgpu::StoreOp::Store; + color_attachment.clearValue = {0.95f, 0.35f, 0.49f, 1.0f}; wgpu::RenderPassDescriptor render_pass_descriptor{}; render_pass_descriptor.setDefault(); @@ -106,6 +132,10 @@ namespace mirai { need_swapchain_rebuild_ = true; } + void window::minimize_window() { + SDL_MinimizeWindow(window_); + } + vec2i window::get_pos() const { int x, y; if (!SDL_GetWindowPosition(window_, &x, &y)) { @@ -120,7 +150,7 @@ namespace mirai { int width, height; if (!SDL_GetWindowSizeInPixels(window_, &width, &height)) { MIRAI_LOG_ERROR("SDL_Vulkan_GetDrawableSize 失败: {}", SDL_GetError()); - width = 0; + width = 0; height = 0; } return vec2i{width, height}; @@ -130,12 +160,17 @@ namespace mirai { int width, height; if (!SDL_GetWindowSize(window_, &width, &height)) { MIRAI_LOG_ERROR("SDL_GetWindowSize 失败: {}", SDL_GetError()); - width = 0; + width = 0; height = 0; } return vec2i{width, height}; } + bool window::is_minimized() const { + auto flags = SDL_GetWindowFlags(window_); + return (flags & SDL_WINDOW_MINIMIZED) != 0; + } + bool window::need_rebuild_swapchain() const { if (!wgpu_surface_) { return false; @@ -144,13 +179,26 @@ namespace mirai { } void_result_t window::rebuild_swapchain(bool hdr_enabled, vec2i new_extent) { + if (!wgpu_surface_) { + return MAKE_ERROR_INFO(error_code::invalid_operation, + "无法重建交换链: WGPU Surface 未创建"); + } + if (new_extent.x() <= 0 || new_extent.y() <= 0) { + return MAKE_ERROR_INFO(error_code::invalid_argument, + "无法重建交换链: 提供了无效的交换链尺寸 {}x{}", new_extent.x(), new_extent.y()); + } + if (!need_swapchain_rebuild_) { + return {}; + } + hdr_enabled_ = hdr_enabled; + wgpu::SurfaceConfiguration wgpu_surface_config{}; wgpu_surface_config.setDefault(); - wgpu_surface_config.usage = wgpu::TextureUsage::RenderAttachment; + wgpu_surface_config.usage = wgpu::TextureUsage::RenderAttachment; wgpu_surface_config.device = wgpu_context::instance().get_device(); - wgpu_surface_config.format = hdr_enabled ? wgpu::TextureFormat::RGB10A2Unorm : wgpu::TextureFormat::BGRA8Unorm; - wgpu_surface_config.width = static_cast(new_extent.x()); - wgpu_surface_config.height = static_cast(new_extent.y()); + wgpu_surface_config.format = hdr_enabled ? wgpu::TextureFormat::RGB10A2Unorm : wgpu::TextureFormat::BGRA8Unorm; + wgpu_surface_config.width = static_cast(new_extent.x()); + wgpu_surface_config.height = static_cast(new_extent.y()); wgpu_surface_config.presentMode = wgpu::PresentMode::Mailbox; wgpu_surface_config.alphaMode = wgpu::CompositeAlphaMode::Auto; wgpu_surface_.configure(wgpu_surface_config); @@ -158,25 +206,24 @@ namespace mirai { return {}; } - std::pair window::acquire_next_swapchain_texture() { + result_t, wgpu::SurfaceGetCurrentTextureStatus> window::acquire_next_swapchain_texture() { wgpu::SurfaceTexture swapchain_texture; wgpu_surface_.getCurrentTexture(&swapchain_texture); if (swapchain_texture.status != wgpu::SurfaceGetCurrentTextureStatus::Success) { - MIRAI_LOG_ERROR("获取交换链纹理失败,状态码: {}", static_cast(swapchain_texture.status)); - return {swapchain_texture, nullptr}; + return std::unexpected(swapchain_texture.status); } wgpu::TextureViewDescriptor view_desc{}; view_desc.setDefault(); - view_desc.label = "Surface Texture View"; - view_desc.format = wgpuTextureGetFormat(swapchain_texture.texture); - view_desc.dimension = wgpu::TextureViewDimension::_2D; - view_desc.baseMipLevel = 0; - view_desc.mipLevelCount = 1; - view_desc.baseArrayLayer = 0; + view_desc.label = "Surface Texture View"; + view_desc.format = wgpuTextureGetFormat(swapchain_texture.texture); + view_desc.dimension = wgpu::TextureViewDimension::_2D; + view_desc.baseMipLevel = 0; + view_desc.mipLevelCount = 1; + view_desc.baseArrayLayer = 0; view_desc.arrayLayerCount = 1; - view_desc.aspect = wgpu::TextureAspect::All; - auto texture_view = wgpuTextureCreateView(swapchain_texture.texture, &view_desc); - return {swapchain_texture, texture_view}; + view_desc.aspect = wgpu::TextureAspect::All; + auto texture_view = wgpuTextureCreateView(swapchain_texture.texture, &view_desc); + return std::make_pair(swapchain_texture, wgpu::TextureView{texture_view}); } void window::on_created() { diff --git a/src/window/window.h b/src/window/window.h index 66a4fdb..7bd5ca6 100644 --- a/src/window/window.h +++ b/src/window/window.h @@ -34,6 +34,7 @@ namespace mirai { std::string get_window_title(); void resize(vec2i new_size); + void minimize_window(); vec2i get_pos() const; vec2i get_framebuffer_size() const; @@ -42,6 +43,7 @@ namespace mirai { auto is_closing() const { return closing_; } + bool is_minimized() const; bool need_rebuild_swapchain() const; void_result_t rebuild_swapchain(bool hdr_enabled, vec2i new_extent); @@ -52,7 +54,7 @@ namespace mirai { return wgpu_surface_; } - std::pair acquire_next_swapchain_texture(); + result_t, wgpu::SurfaceGetCurrentTextureStatus> acquire_next_swapchain_texture(); protected: void on_created() override; void on_destroying() override; diff --git a/src/window/window_manager.cpp b/src/window/window_manager.cpp index 080cd9b..dadf819 100644 --- a/src/window/window_manager.cpp +++ b/src/window/window_manager.cpp @@ -55,7 +55,7 @@ namespace mirai { if (event.type == SDL_EVENT_QUIT) { g_quit_requested = true; } - if (event.type == SDL_EVENT_WINDOW_RESIZED) { + else if (event.type == SDL_EVENT_WINDOW_RESIZED) { auto win = get_window_by_id(event.window.windowID).lock(); if (win) { win->resize(vec2i{event.window.data1, event.window.data2});