use wgpu::{Adapter, Device, Instance, Queue};
use wgt::{Backends, Features, Limits};
pub fn init_logger() {
#[cfg(not(target_arch = "wasm32"))]
let _ = env_logger::try_init();
#[cfg(target_arch = "wasm32")]
let _ = console_log::init_with_level(log::Level::Info);
}
pub fn initialize_instance(force_fxc: bool) -> Instance {
let backends = if cfg!(feature = "webgl") {
Backends::all() - Backends::BROWSER_WEBGPU
} else {
Backends::all()
};
let dx12_shader_compiler = if force_fxc {
wgpu::Dx12Compiler::Fxc
} else {
wgpu::util::dx12_shader_compiler_from_env().unwrap_or_default()
};
let gles_minor_version = wgpu::util::gles_minor_version_from_env().unwrap_or_default();
Instance::new(wgpu::InstanceDescriptor {
backends,
flags: wgpu::InstanceFlags::debugging().with_env(),
dx12_shader_compiler,
gles_minor_version,
})
}
pub async fn initialize_adapter(
adapter_index: usize,
force_fxc: bool,
) -> (Instance, Adapter, Option<SurfaceGuard>) {
let instance = initialize_instance(force_fxc);
#[allow(unused_variables)]
let surface: Option<wgpu::Surface>;
let surface_guard: Option<SurfaceGuard>;
#[allow(unused_assignments)]
#[cfg(not(all(
target_arch = "wasm32",
any(target_os = "emscripten", feature = "webgl")
)))]
{
surface = None;
surface_guard = None;
}
#[cfg(all(
target_arch = "wasm32",
any(target_os = "emscripten", feature = "webgl")
))]
{
let canvas = initialize_html_canvas();
surface = Some(
instance
.create_surface(wgpu::SurfaceTarget::Canvas(canvas.clone()))
.expect("could not create surface from canvas"),
);
surface_guard = Some(SurfaceGuard { canvas });
}
cfg_if::cfg_if! {
if #[cfg(not(target_arch = "wasm32"))] {
let adapter_iter = instance.enumerate_adapters(wgpu::Backends::all());
let adapter_count = adapter_iter.len();
let adapter = adapter_iter.into_iter()
.nth(adapter_index)
.unwrap_or_else(|| panic!("Tried to get index {adapter_index} adapter, but adapter list was only {adapter_count} long. Is .gpuconfig out of date?"));
} else {
assert_eq!(adapter_index, 0);
let adapter = instance.request_adapter(&wgpu::RequestAdapterOptions {
compatible_surface: surface.as_ref(),
..Default::default()
}).await.unwrap();
}
}
log::info!("Testing using adapter: {:#?}", adapter.get_info());
(instance, adapter, surface_guard)
}
pub async fn initialize_device(
adapter: &Adapter,
features: Features,
limits: Limits,
) -> (Device, Queue) {
let bundle = adapter
.request_device(
&wgpu::DeviceDescriptor {
label: None,
required_features: features,
required_limits: limits,
memory_hints: wgpu::MemoryHints::MemoryUsage,
},
None,
)
.await;
match bundle {
Ok(b) => b,
Err(e) => panic!("Failed to initialize device: {e}"),
}
}
#[cfg(target_arch = "wasm32")]
pub fn initialize_html_canvas() -> web_sys::HtmlCanvasElement {
use wasm_bindgen::JsCast;
web_sys::window()
.and_then(|win| win.document())
.and_then(|doc| {
let canvas = doc.create_element("Canvas").unwrap();
canvas.dyn_into::<web_sys::HtmlCanvasElement>().ok()
})
.expect("couldn't create canvas")
}
pub struct SurfaceGuard {
#[cfg(target_arch = "wasm32")]
#[allow(unused)]
canvas: web_sys::HtmlCanvasElement,
}
impl SurfaceGuard {
#[cfg(all(
target_arch = "wasm32",
any(target_os = "emscripten", feature = "webgl")
))]
pub(crate) fn check_for_unreported_errors(&self) -> bool {
use wasm_bindgen::JsCast;
self.canvas
.get_context("webgl2")
.unwrap()
.unwrap()
.dyn_into::<web_sys::WebGl2RenderingContext>()
.unwrap()
.get_error()
!= web_sys::WebGl2RenderingContext::NO_ERROR
}
}