Files
mirai/src/window/window.cpp

197 lines
6.2 KiB
C++

#include "window.h"
#include <SDL3/SDL_vulkan.h>
#include "render/sdl3webgpu.h"
#include <utility>
#include "core/logger.h"
#include "render/wgpu_context.h"
namespace mirai {
void_result_t window::make_window(window_config config) {
auto win_ptr = SDL_CreateWindow(config.title.c_str(), config.size.x(), config.size.y(), config.flags);
if (!win_ptr) {
return MAKE_ERROR_INFO(error_code::window_creation_failed,
"SDL_CreateWindow 失败: {}", SDL_GetError());
}
if (config.wgpu_window) {
wgpu_surface_ = SDL_GetWGPUSurface(wgpu_context::instance().get_instance(), win_ptr);
if (!wgpu_surface_) {
SDL_DestroyWindow(win_ptr);
return MAKE_ERROR_INFO(error_code::window_creation_failed,
"SDL_GetWGPUSurface 失败: {}", SDL_GetError());
}
}
if (!SDL_SetWindowTitle(win_ptr, config.title.c_str())) {
SDL_DestroyWindow(win_ptr);
return MAKE_ERROR_INFO(error_code::window_creation_failed,
"SDL_SetWindowTitle 失败: {}", SDL_GetError());
}
window_ = win_ptr;
return {};
}
void window::update(duration_ms delta_time) {
if (closing_) {
return;
}
if (need_rebuild_swapchain()) {
auto result = rebuild_swapchain();
if (!result) {
MIRAI_LOG_ERROR("窗口 {} 交换链重建失败: {}", get_window_title(), result.error().full_description());
return;
}
}
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();
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};
wgpu::RenderPassDescriptor render_pass_descriptor{};
render_pass_descriptor.setDefault();
render_pass_descriptor.colorAttachmentCount = 1;
render_pass_descriptor.colorAttachments = &color_attachment;
wgpu::raii::RenderPassEncoder render_pass = encoder->beginRenderPass(render_pass_descriptor);
render_pass->setPipeline(pipeline);
render_pass->draw(3, 1, 0, 0);
render_pass->end();
wgpu::raii::CommandBuffer command_buffer = encoder->finish();
queue->submit(*command_buffer);
wgpu_surface_.present();
wgpuTextureViewRelease(texture_view);
wgpuTextureRelease(texture.texture);
}
void window::show_window(bool show) {
if (show) {
SDL_ShowWindow(window_);
}
else {
SDL_HideWindow(window_);
}
}
void window::move_window(vec2i pos) {
SDL_SetWindowPosition(window_, pos.x(), pos.y());
}
std::string window::get_window_title() {
const char* title = SDL_GetWindowTitle(window_);
if (!title) {
MIRAI_LOG_ERROR("SDL_GetWindowTitle 失败: {}", SDL_GetError());
return "";
}
return std::string(title);
}
void window::resize(vec2i new_size) {
SDL_SetWindowSize(window_, new_size.x(), new_size.y());
need_swapchain_rebuild_ = true;
}
vec2i window::get_pos() const {
int x, y;
if (!SDL_GetWindowPosition(window_, &x, &y)) {
MIRAI_LOG_ERROR("SDL_GetWindowPosition 失败: {}", SDL_GetError());
x = 0;
y = 0;
}
return vec2i{x, y};
}
vec2i window::get_framebuffer_size() const {
int width, height;
if (!SDL_GetWindowSizeInPixels(window_, &width, &height)) {
MIRAI_LOG_ERROR("SDL_Vulkan_GetDrawableSize 失败: {}", SDL_GetError());
width = 0;
height = 0;
}
return vec2i{width, height};
}
vec2i window::get_window_size() const {
int width, height;
if (!SDL_GetWindowSize(window_, &width, &height)) {
MIRAI_LOG_ERROR("SDL_GetWindowSize 失败: {}", SDL_GetError());
width = 0;
height = 0;
}
return vec2i{width, height};
}
bool window::need_rebuild_swapchain() const {
if (!wgpu_surface_) {
return false;
}
return need_swapchain_rebuild_;
}
void_result_t window::rebuild_swapchain(bool hdr_enabled, vec2i new_extent) {
wgpu::SurfaceConfiguration wgpu_surface_config{};
wgpu_surface_config.setDefault();
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<uint32_t>(new_extent.x());
wgpu_surface_config.height = static_cast<uint32_t>(new_extent.y());
wgpu_surface_config.presentMode = wgpu::PresentMode::Mailbox;
wgpu_surface_config.alphaMode = wgpu::CompositeAlphaMode::Auto;
wgpu_surface_.configure(wgpu_surface_config);
need_swapchain_rebuild_ = false;
return {};
}
std::pair<wgpu::SurfaceTexture, wgpu::TextureView> 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<int>(swapchain_texture.status));
return {swapchain_texture, nullptr};
}
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.arrayLayerCount = 1;
view_desc.aspect = wgpu::TextureAspect::All;
auto texture_view = wgpuTextureCreateView(swapchain_texture.texture, &view_desc);
return {swapchain_texture, texture_view};
}
void window::on_created() {
object::on_created();
}
void window::on_destroying() {
object::on_destroying();
if (wgpu_surface_) {
wgpu_surface_.unconfigure();
wgpuSurfaceRelease(wgpu_surface_);
wgpu_surface_ = nullptr;
}
MIRAI_LOG_INFO("窗口 {} 销毁", get_window_title());
SDL_DestroyWindow(window_);
window_ = nullptr;
}
}