1use wgpu::{Adapter, Backends, Device, Features, Instance, Limits, Queue};
2
3use crate::{report::AdapterReport, TestParameters};
4
5pub fn init_logger() {
7 #[cfg(not(target_arch = "wasm32"))]
9 let _ = env_logger::try_init();
10 #[cfg(target_arch = "wasm32")]
11 let _ = console_log::init_with_level(log::Level::Info);
12}
13
14pub fn initialize_instance(backends: wgpu::Backends, params: &TestParameters) -> Instance {
16 let backends = if cfg!(feature = "webgl") {
27 backends - wgpu::Backends::BROWSER_WEBGPU
28 } else {
29 backends
30 };
31 let dx12_shader_compiler = if params.force_fxc {
34 wgpu::Dx12Compiler::Fxc
35 } else {
36 wgpu::Dx12Compiler::from_env().unwrap_or(wgpu::Dx12Compiler::StaticDxc)
37 };
38 let flags = wgpu::InstanceFlags::debugging()
40 .with_env()
41 .union(params.required_instance_flags);
42
43 Instance::new(&wgpu::InstanceDescriptor {
44 backends,
45 flags,
46 memory_budget_thresholds: wgpu::MemoryBudgetThresholds {
47 for_resource_creation: Some(99),
48 for_device_loss: None,
49 },
50 backend_options: wgpu::BackendOptions {
51 dx12: wgpu::Dx12BackendOptions {
52 shader_compiler: dx12_shader_compiler,
53 ..Default::default()
54 },
55 gl: wgpu::GlBackendOptions {
56 fence_behavior: if cfg!(target_family = "wasm") {
57 wgpu::GlFenceBehavior::AutoFinish
63 } else {
64 wgpu::GlFenceBehavior::Normal
65 },
66 ..Default::default()
67 }
68 .with_env(),
69 noop: wgpu::NoopBackendOptions {
76 enable: !cfg!(target_arch = "wasm32"),
77 },
78 },
79 })
80}
81
82pub async fn initialize_adapter(
84 adapter_report: Option<&AdapterReport>,
85 params: &TestParameters,
86) -> (Instance, Adapter, Option<SurfaceGuard>) {
87 let backends = adapter_report
88 .map(|report| Backends::from(report.info.backend))
89 .unwrap_or_default();
90
91 let instance = initialize_instance(backends, params);
92 #[allow(unused_variables)]
93 let surface: Option<wgpu::Surface>;
94 let surface_guard: Option<SurfaceGuard>;
95
96 #[allow(unused_assignments)]
97 #[cfg(not(all(
99 target_arch = "wasm32",
100 any(target_os = "emscripten", feature = "webgl")
101 )))]
102 {
103 surface = None;
104 surface_guard = None;
105 }
106 #[cfg(all(
107 target_arch = "wasm32",
108 any(target_os = "emscripten", feature = "webgl")
109 ))]
110 {
111 let canvas = initialize_html_canvas();
113
114 surface = Some(
115 instance
116 .create_surface(wgpu::SurfaceTarget::Canvas(canvas.clone()))
117 .expect("could not create surface from canvas"),
118 );
119
120 surface_guard = Some(SurfaceGuard { canvas });
121 }
122
123 cfg_if::cfg_if! {
124 if #[cfg(not(target_arch = "wasm32"))] {
125 let adapter_iter = instance.enumerate_adapters(backends);
126 let adapter = adapter_iter.into_iter()
127 .find(|adapter| if let Some(adapter_report) = adapter_report {
131 adapter.get_info() == adapter_report.info
132 } else {
133 true
134 });
135 let Some(adapter) = adapter else {
136 panic!(
137 "Could not find adapter with info {:#?} in {:#?}",
138 adapter_report.map(|r| &r.info),
139 instance.enumerate_adapters(backends).into_iter().map(|a| a.get_info()).collect::<Vec<_>>(),
140 );
141 };
142 } else {
143 let adapter = instance.request_adapter(&wgpu::RequestAdapterOptions {
144 compatible_surface: surface.as_ref(),
145 ..Default::default()
146 }).await.unwrap();
147 }
148 }
149
150 log::info!("Testing using adapter: {:#?}", adapter.get_info());
151
152 (instance, adapter, surface_guard)
153}
154
155pub async fn initialize_device(
157 adapter: &Adapter,
158 features: Features,
159 limits: Limits,
160) -> (Device, Queue) {
161 let bundle = adapter
162 .request_device(&wgpu::DeviceDescriptor {
163 label: None,
164 required_features: features,
165 required_limits: limits,
166 experimental_features: unsafe { wgpu::ExperimentalFeatures::enabled() },
167 memory_hints: wgpu::MemoryHints::MemoryUsage,
168 trace: wgpu::Trace::Off,
169 })
170 .await;
171
172 match bundle {
173 Ok(b) => b,
174 Err(e) => panic!("Failed to initialize device: {e}"),
175 }
176}
177
178#[cfg(target_arch = "wasm32")]
180pub fn initialize_html_canvas() -> web_sys::HtmlCanvasElement {
181 use wasm_bindgen::JsCast;
182
183 web_sys::window()
184 .and_then(|win| win.document())
185 .and_then(|doc| {
186 let canvas = doc.create_element("Canvas").unwrap();
187 canvas.dyn_into::<web_sys::HtmlCanvasElement>().ok()
188 })
189 .expect("couldn't create canvas")
190}
191
192pub struct SurfaceGuard {
193 #[cfg(target_arch = "wasm32")]
194 #[allow(unused)]
195 canvas: web_sys::HtmlCanvasElement,
196}
197
198impl SurfaceGuard {
199 #[cfg(all(
200 target_arch = "wasm32",
201 any(target_os = "emscripten", feature = "webgl")
202 ))]
203 pub(crate) fn check_for_unreported_errors(&self) -> bool {
204 use wasm_bindgen::JsCast;
205
206 self.canvas
207 .get_context("webgl2")
208 .unwrap()
209 .unwrap()
210 .dyn_into::<web_sys::WebGl2RenderingContext>()
211 .unwrap()
212 .get_error()
213 != web_sys::WebGl2RenderingContext::NO_ERROR
214 }
215}