拓冰建站拓冰建站
首页 / 资讯中心 / 正文

wgpu 多窗口渲染实战:hello_windows 示例如何同时管理 16 个窗口与 Surface

wgpu 多窗口渲染实战hello_windows 示例如何同时管理 16 个窗口与 Surface【免费下载链接】wgpuA cross-platform, safe, pure-Rust graphics API.项目地址: https://gitcode.com/GitHub_Trending/wg/wgpu本篇指南围绕 wgpu 仓库中examples/features下的hello_windows示例展开讲解如何在一个进程内创建并同时渲染 16 个独立窗口每个窗口使用不同的背景色。通过阅读本文你将掌握 wgpu 多窗口架构下的Surface生命周期创建、配置、获取帧、present、多窗口事件分发与窗口关闭回收逻辑以及如何在winit事件循环中为每个窗口维护独立的交换链配置。示例概览与运行方式hello_windows是 wgpu 官方示例集中用于演示多窗口multi-window渲染的示例。它在一个应用中渲染 4×4 共 16 个窗口每个窗口的背景色各不相同整体呈现从绿色到蓝绿色、再到黄色的渐变网格。它不依赖examples/features/src/framework.rs中的公共框架而是直接在示例内自行管理窗口、实例、设备与 Surface非常适合作为研究 wgpu 多窗口架构的独立入口。运行该示例在仓库根目录下cargo run --bin wgpu-examples hello_windows命令解析--bin wgpu-examples指定二进制目标。在 examples/features/Cargo.toml 中定义了[[bin]] name wgpu-examples入口为src/main.rshello_windows作为第一个命令行参数传入。入口程序 src/main.rs 通过std::env::args().nth(1)读取示例名并在EXAMPLES常量表中查找匹配项后调用对应的main函数示例注册于 src/main.rs 的EXAMPLES列表中且在 src/lib.rs 中声明为模块pub mod hello_windows。需要注意的是该示例是Native-only在 src/main.rs 中hello_windows的webgl与webgpu标记均为false且在 mod.rs 的 wasm32 分支中直接panic!(wasm32 is not supported)。因此它只面向桌面/移动原生平台运行。运行效果16 个窗口的网格布局运行后16 个窗口按 4 行 4 列平铺背景色从左上到右下渐变第一行由深绿过渡到蓝绿、亮蓝第二行由黄绿过渡到灰蓝第三、四行逐渐过渡到金黄、橙与粉色。每个窗口标题栏显示其行列坐标例如x0y0、x3y3便于区分窗口身份。窗口的几何布局由 mod.rs 中的常量决定const WINDOW_SIZE: u32 128; // 窗口客户区边长 const WINDOW_PADDING: u32 16; // 窗口间距 const WINDOW_TITLEBAR: u32 32; // 标题栏高度用于纵向偏移计算 const WINDOW_OFFSET: u32 WINDOW_SIZE WINDOW_PADDING; // 相邻窗口水平间距 const ROWS: u32 4; const COLUMNS: u32 4;窗口创建循环mod.rs使用event_loop.create_window()依次创建 16 个窗口标题为format!(x{column}y{row})初始尺寸PhysicalSize::new(WINDOW_SIZE, WINDOW_SIZE)通过window.set_outer_position()计算网格位置横坐标WINDOW_PADDING column * WINDOW_OFFSET纵坐标WINDOW_PADDING row * (WINDOW_OFFSET WINDOW_TITLEBAR)其中加标题栏高度是为了补偿窗口标题栏占用的额外空间使网格在视觉上对齐。每个窗口的背景色由行列坐标推导mod.rsfn frac(index: u32, max: u32) - f64 { index as f64 / max as f64 } wgpu::Color { r: frac(row, ROWS), g: 0.5 - frac(row * column, ROWS * COLUMNS) * 0.5, b: frac(column, COLUMNS), a: 1.0, }即红色分量随行号递增、蓝色分量随列号递增、绿色分量在行列组合间递减从而生成平滑渐变。核心数据结构Viewport 与 App 状态机示例将“窗口 其 Surface 交换链配置”封装为两个结构体mod.rsstruct ViewportDesc { window: ArcWindow, background: wgpu::Color, surface: wgpu::Surfacestatic, } struct Viewport { desc: ViewportDesc, config: wgpu::SurfaceConfiguration, }ViewportDesc持有窗口句柄、背景色与对应的Surface在new()中调用instance.create_surface(window.clone())为窗口创建 SurfaceViewport在build()中通过surface.get_default_config(adapter, width, height)获取默认交换链配置并调用surface.configure(device, config)从而把 Surface 与设备、交换链配置绑定Viewport::resize()在窗口尺寸变化时更新config.width/height并重新configureViewport::get_current_texture()封装了surface.get_current_texture()。应用整体则是一个App结构体其状态用枚举建模enum AppState { Uninitialized, Running { instance: wgpu::Instance, device: wgpu::Device, queue: wgpu::Queue, viewports: HashMapWindowId, Viewport, }, }关键点在于用HashMapWindowId, Viewport以窗口 ID 为键维护所有视口。由于window_event回调携带window_id参数事件处理可以精确定位到对应的Viewport这正是多窗口应用的标准组织方式。初始化流程从窗口到设备初始化全部在ApplicationHandler::resumed()回调中完成mod.rs分为三步创建全部窗口如上文所述循环创建 16 个窗口并生成各自的背景色创建 wgpu Instancelet instance wgpu::Instance::new( wgpu::InstanceDescriptor::new_with_display_handle_from_env( Box::new(event_loop.owned_display_handle()), ), );new_with_display_handle_from_env会从环境读取显示句柄使多窗口的 Surface 创建在不同平台Vulkan、Metal、DX12、GLES 等上都能拿到正确的显示信息 3.请求适配器与设备使用pollster::block_on同步等待异步初始化完成。request_adapter时通过compatible_surface: viewport_descs.first().map(|desc| desc.surface)传入第一个窗口的 Surface作为兼容性约束确保选出的适配器能够驱动所有窗口的交换链随后request_device使用wgpu::Limits::downlevel_defaults()与空required_features保证在尽可能广泛的硬件上可用。初始化完成后为每个ViewportDesc调用build()生成Viewport并以desc.window.id()为键放入HashMap状态机进入Running。Surface 生命周期创建、配置与取帧hello_windows是理解 wgpu Surface 生命周期最直接的示例。它在同一Instance下为每个窗口分别走完以下流程创建 Surfaceinstance.create_surface(window)。在 wgpu/src/api/instance.rs 中create_surface接受任何可转换为SurfaceTarget的目标最常用的是窗口句柄内部会为当前实例启用的所有后端创建 Surface 并返回ResultSurface, CreateSurfaceError获取默认配置surface.get_default_config(adapter, width, height)。在 wgpu/src/api/surface.rs 中该方法结合适配器能力返回一份可直接使用的SurfaceConfiguration含格式、呈现模式、alpha 模式等若该 Surface 不被适配器支持则返回None示例中直接unwrap()配置交换链surface.configure(device, config)。在 wgpu/src/api/surface.rs 中configure将配置下发给后端并缓存副本注意文档指出width或height为 0 时配置会失败因此resize()前必须保证尺寸非零取帧surface.get_current_texture()。在 wgpu/src/api/surface.rs 返回CurrentSurfaceTexture枚举调用方必须对每种情况做出处理。get_current_texture的返回值处理是示例中信息量最大的部分mod.rs返回变体含义示例的处理方式Success(frame)成功取得帧直接进入渲染Timeout/Occluded超时或窗口被遮挡跳过本帧request_redraw()后返回Suboptimal(texture)帧仍可用但交换链已不优丢弃帧、重新configure后请求重绘Outdated交换链已过时如窗口尺寸变化重新configure后请求重绘Validation校验错误示例未注册 error scope直接unreachable!LostSurface 丢失如移动端后台切换用instance.create_surface()重建 Surface 并重新configure这组模式与 examples/features/src/framework.rs 中SurfaceWrapper::acquire()的处理逻辑一致可作为所有 wgpu 应用取帧循环的参考模板。渲染循环每个窗口一次 Clear每个窗口的绘制逻辑位于WindowEvent::RedrawRequested分支mod.rs。取到帧后let view frame.texture.create_view(wgpu::TextureViewDescriptor::default()); let mut encoder device.create_command_encoder(wgpu::CommandEncoderDescriptor { label: None }); { let _rpass encoder.begin_render_pass(wgpu::RenderPassDescriptor { color_attachments: [Some(wgpu::RenderPassColorAttachment { view: view, depth_slice: None, resolve_target: None, ops: wgpu::Operations { load: wgpu::LoadOp::Clear(viewport.desc.background), store: wgpu::StoreOp::Store, }, })], depth_stencil_attachment: None, timestamp_writes: None, occlusion_query_set: None, multiview_mask: None, }); } queue.submit(Some(encoder.finish())); viewport.desc.window.pre_present_notify(); queue.present(frame);要点每个窗口各创建独立的CommandEncoder用LoadOp::Clear(background)将该窗口清成自己的背景色渲染结束后调用window.pre_present_notify()告知窗口系统即将呈现然后queue.present(frame)提交帧若想看到每个窗口各画一帧的负载均衡语义注意示例为每个窗口的 RedrawRequested 事件独立取帧并独立 present这模拟了多视图编辑器、多显示器输出等真实多窗口场景的渲染组织方式。多窗口事件处理与关闭回收多窗口应用与单窗口的关键差异在于事件中的window_id。window_event回调签名携带window_id: WindowIdmod.rs示例据此在HashMap中定位目标视口Resizedviewport.resize(device, new_size)更新该窗口的交换链配置macOS 上还需request_redraw()手动触发重绘mod.rsOccluded记录遮挡状态取消遮挡后请求重绘mod.rsCloseRequested从viewports中移除对应窗口当最后一个窗口关闭、viewports为空时调用event_loop.exit()退出应用mod.rs。这种逐窗口回收、空则退出的语义是多窗口应用的标准生命周期管理方式。总结与延伸hello_windows用不到 300 行代码展示了 wgpu 多窗口渲染的完整骨架窗口即资源每个窗口对应一个独立的Surface与SurfaceConfiguration用HashMapWindowId, Viewport组织Surface 状态机create_surface → get_default_config → configure → get_current_texture是每个窗口必须走完的流程且取帧时必须穷举处理CurrentSurfaceTexture的 7 种结果事件驱动渲染依托winit的ApplicationHandler在resumed中初始化、在window_event中按window_id分发渲染与回收。进一步阅读建议完整实现examples/features/src/hello_windows/mod.rs示例注册与 Native-only 标记examples/features/src/main.rs公共框架对照单窗口 SurfaceWrapper 的取帧策略examples/features/src/framework.rsSurface API 文档级注释wgpu/src/api/surface.rs官方示例总览与更多示例说明examples/README.md【免费下载链接】wgpuA cross-platform, safe, pure-Rust graphics API.项目地址: https://gitcode.com/GitHub_Trending/wg/wgpu创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门