-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdevice.rs
More file actions
117 lines (104 loc) · 3.88 KB
/
device.rs
File metadata and controls
117 lines (104 loc) · 3.88 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
//! wgpu Device / Surface 初始化,与浏览器 canvas 绑定。
//!
//! 实际只在 wasm32 + WebGPU 后端运行(项目仅浏览器部署);
//! desktop target 保留一个返回 Err 的存根,让 lib 单元测试能在桌面跑通编译。
use std::sync::Arc;
use wgpu::{SurfaceCapabilities, TextureFormat, TextureUsages};
/// 初始化 wgpu 所需的上下文:从一块 HTML canvas 获取 GPU 设备和 Surface。
pub struct DeviceContext {
pub surface: wgpu::Surface<'static>,
pub device: Arc<wgpu::Device>,
pub queue: Arc<wgpu::Queue>,
pub surface_format: TextureFormat,
}
/// 创建 wgpu Instance、Adapter、Device 和 Surface(wasm32 实现)。
#[cfg(target_arch = "wasm32")]
pub async fn init_device(canvas: &web_sys::HtmlCanvasElement) -> Result<DeviceContext, String> {
use wgpu::{
DeviceDescriptor, Instance, InstanceDescriptor, MemoryHints, PowerPreference,
RequestAdapterOptions,
};
let instance_desc = InstanceDescriptor {
backends: wgpu::Backends::BROWSER_WEBGPU,
flags: wgpu::InstanceFlags::default(),
backend_options: wgpu::BackendOptions::default(),
display: None,
memory_budget_thresholds: wgpu::MemoryBudgetThresholds::default(),
};
let instance = Instance::new(instance_desc);
let surface = instance
.create_surface(wgpu::SurfaceTarget::Canvas(canvas.clone()))
.map_err(|e| format!("创建 Surface 失败: {e}"))?;
let adapter_options = RequestAdapterOptions {
power_preference: PowerPreference::HighPerformance,
force_fallback_adapter: false,
compatible_surface: Some(&surface),
};
let adapter = instance
.request_adapter(&adapter_options)
.await
.map_err(|e| format!("无法获取 GPU 适配器:{e}"))?;
let caps = surface.get_capabilities(&adapter);
let surface_format = select_format(&caps);
let device_desc = DeviceDescriptor {
label: None,
required_features: wgpu::Features::empty(),
required_limits: wgpu::Limits::downlevel_defaults(),
memory_hints: MemoryHints::Performance,
experimental_features: wgpu::ExperimentalFeatures::disabled(),
trace: Default::default(),
};
let (device, queue) = adapter
.request_device(&device_desc)
.await
.map_err(|e| format!("创建设备失败: {e}"))?;
let device = Arc::new(device);
let queue = Arc::new(queue);
Ok(DeviceContext {
surface,
device,
queue,
surface_format,
})
}
/// Desktop 存根:直接返回错误。本项目只在浏览器跑,desktop 仅为单元测试编译目标。
#[cfg(not(target_arch = "wasm32"))]
pub async fn init_device(_canvas: &web_sys::HtmlCanvasElement) -> Result<DeviceContext, String> {
Err("init_device 只在 wasm32 浏览器目标下可用".to_string())
}
/// 从 SurfaceCapabilities 中选择首选纹理格式。
#[allow(dead_code)] // desktop target 下 init_device 走存根分支,不调用本函数
fn select_format(caps: &SurfaceCapabilities) -> TextureFormat {
let preferred = &caps.formats;
for fmt in [
wgpu::TextureFormat::Bgra8UnormSrgb,
wgpu::TextureFormat::Bgra8Unorm,
] {
if preferred.contains(&fmt) {
return fmt;
}
}
preferred[0]
}
/// 配置 Surface(尺寸、格式、呈现模式)。
pub fn configure_surface(
surface: &wgpu::Surface<'static>,
device: &wgpu::Device,
format: TextureFormat,
width: u32,
height: u32,
) {
surface.configure(
device,
&wgpu::SurfaceConfiguration {
usage: TextureUsages::RENDER_ATTACHMENT,
format,
width,
height,
present_mode: wgpu::PresentMode::Fifo,
alpha_mode: wgpu::CompositeAlphaMode::Opaque,
view_formats: vec![],
desired_maximum_frame_latency: 2,
},
);
}