refactor setup

This commit is contained in:
2026-02-18 08:28:00 -08:00
parent 89386f12a0
commit a43f4720a1
2 changed files with 79 additions and 97 deletions

View File

@@ -7,12 +7,15 @@ mod setup;
#[wasm_bindgen]
pub struct Setup{
setup:setup::SetupContext<'static>,
device:wgpu::Device,
queue:wgpu::Queue,
surface:wgpu::Surface<'static>,
config:wgpu::SurfaceConfiguration,
}
#[wasm_bindgen]
pub async fn setup(canvas:web_sys::HtmlCanvasElement)->Setup{
let setup=setup::setup_and_start(canvas).await;
Setup{setup}
let (device,queue,surface,config)=setup::setup_and_start(canvas).await;
Setup{device,queue,surface,config}
}
#[wasm_bindgen]
pub struct Graphics{
@@ -27,8 +30,8 @@ impl Graphics{
data:&[u8],
)->Result<Self,JsValue>{
Ok(Self{
graphics:graphics::Graphics::new(data,setup.setup.device,setup.setup.queue,setup.setup.config).map_err(|e|JsValue::from_str(&e.to_string()))?,
surface:setup.setup.surface,
graphics:graphics::Graphics::new(data,setup.device,setup.queue,setup.config).map_err(|e|JsValue::from_str(&e.to_string()))?,
surface:setup.surface,
})
}
#[wasm_bindgen]

View File

@@ -13,97 +13,69 @@ fn required_downlevel_capabilities()->wgpu::DownlevelCapabilities{
}
}
struct SetupContextPartial1{
backends:wgpu::Backends,
instance:wgpu::Instance,
}
fn create_instance()->SetupContextPartial1{
let backends=wgpu::Backends::from_env().unwrap_or_default();
SetupContextPartial1{
backends,
instance:Default::default(),
mod step1{
pub fn create_instance()->wgpu::Instance{
Default::default()
}
}
impl SetupContextPartial1{
fn create_surface<'a>(self,canvas:web_sys::HtmlCanvasElement)->Result<SetupContextPartial2<'a>,wgpu::CreateSurfaceError>{
Ok(SetupContextPartial2{
backends:self.backends,
surface:self.instance.create_surface(wgpu::SurfaceTarget::Canvas(canvas))?,
instance:self.instance,
})
mod step2{
pub fn create_surface<'window>(instance:&wgpu::Instance,target:impl Into<wgpu::SurfaceTarget<'window>>)->Result<wgpu::Surface<'window>,wgpu::CreateSurfaceError>{
instance.create_surface(target)
}
}
struct SetupContextPartial2<'a>{
backends:wgpu::Backends,
instance:wgpu::Instance,
surface:wgpu::Surface<'a>,
}
impl<'a> SetupContextPartial2<'a>{
async fn pick_adapter(self)->SetupContextPartial3<'a>{
mod step3{
pub async fn pick_adapter(instance:&wgpu::Instance,surface:&wgpu::Surface<'_>)->Option<wgpu::Adapter>{
let backends=wgpu::Backends::from_env().unwrap_or_default();
//TODO: prefer adapter that implements optional features
//let optional_features=optional_features();
let required_features=required_features();
let required_features=super::required_features();
let required_downlevel_capabilities=super::required_downlevel_capabilities();
//no helper function smh gotta write it myself
let adapters=self.instance.enumerate_adapters(self.backends).await;
let adapters=instance.enumerate_adapters(backends).await;
let chosen_adapter=adapters.into_iter()
let adapter=adapters.into_iter()
// reverse because we want to select adapters that appear first in ties,
// and max_by_key selects the last equal element in the iterator.
.rev()
.filter(|adapter|
adapter.is_surface_supported(&self.surface)
adapter.is_surface_supported(surface)
&&adapter.features().contains(required_features)
&&{
let downlevel_capabilities=adapter.get_downlevel_capabilities();
downlevel_capabilities.shader_model>=required_downlevel_capabilities.shader_model
&&downlevel_capabilities.flags.contains(required_downlevel_capabilities.flags)
}
)
.max_by_key(|adapter|match adapter.get_info().device_type{
wgpu::DeviceType::IntegratedGpu=>3,
wgpu::DeviceType::DiscreteGpu=>4,
wgpu::DeviceType::VirtualGpu=>2,
wgpu::DeviceType::Other|wgpu::DeviceType::Cpu=>1,
});
let adapter=chosen_adapter.expect("No suitable GPU adapters found on the system!");
})?;
let adapter_info=adapter.get_info();
println!("Using {} ({:?})", adapter_info.name, adapter_info.backend);
let required_downlevel_capabilities=required_downlevel_capabilities();
let downlevel_capabilities=adapter.get_downlevel_capabilities();
assert!(
downlevel_capabilities.shader_model >= required_downlevel_capabilities.shader_model,
"Adapter does not support the minimum shader model required to run this example: {:?}",
required_downlevel_capabilities.shader_model
);
assert!(
downlevel_capabilities
.flags
.contains(required_downlevel_capabilities.flags),
"Adapter does not support the downlevel capabilities required to run this example: {:?}",
required_downlevel_capabilities.flags - downlevel_capabilities.flags
);
SetupContextPartial3{
surface:self.surface,
adapter,
}
Some(adapter)
}
}
struct SetupContextPartial3<'a>{
surface:wgpu::Surface<'a>,
adapter:wgpu::Adapter,
}
impl<'a> SetupContextPartial3<'a>{
async fn request_device(self)->SetupContextPartial4<'a>{
let optional_features=optional_features();
let required_features=required_features();
mod step4{
pub async fn request_device(adapter:&wgpu::Adapter)->(wgpu::Device,wgpu::Queue){
let optional_features=super::optional_features();
let required_features=super::required_features();
// Make sure we use the texture resolution limits from the adapter, so we can support images the size of the surface.
let needed_limits=strafesnet_graphics::graphics::required_limits().using_resolution(self.adapter.limits());
let needed_limits=strafesnet_graphics::graphics::required_limits().using_resolution(adapter.limits());
let (device, queue)=self.adapter
let (device, queue)=adapter
.request_device(
&wgpu::DeviceDescriptor{
label:None,
required_features:(optional_features&self.adapter.features())|required_features,
required_features:(optional_features&adapter.features())|required_features,
required_limits:needed_limits,
memory_hints:wgpu::MemoryHints::Performance,
trace:wgpu::Trace::Off,
@@ -112,59 +84,66 @@ impl<'a> SetupContextPartial3<'a>{
).await
.expect("Unable to find a suitable GPU adapter!");
SetupContextPartial4{
surface:self.surface,
adapter:self.adapter,
(
device,
queue,
}
)
}
}
struct SetupContextPartial4<'a>{
surface:wgpu::Surface<'a>,
adapter:wgpu::Adapter,
device:wgpu::Device,
queue:wgpu::Queue,
}
impl<'a> SetupContextPartial4<'a>{
fn configure_surface(self,(width,height):(u32,u32))->SetupContext<'a>{
let mut config=self.surface
.get_default_config(&self.adapter, width, height)
mod step5{
pub fn configure_surface(
adapter:&wgpu::Adapter,
device:&wgpu::Device,
surface:&wgpu::Surface<'_>,
(width,height):(u32,u32),
)->wgpu::SurfaceConfiguration{
let mut config=surface
.get_default_config(adapter, width, height)
.expect("Surface isn't supported by the adapter.");
let surface_view_format=config.format.add_srgb_suffix();
config.view_formats.push(surface_view_format);
config.present_mode=wgpu::PresentMode::AutoNoVsync;
self.surface.configure(&self.device, &config);
surface.configure(device, &config);
SetupContext{
surface:self.surface,
device:self.device,
queue:self.queue,
config,
}
config
}
}
pub struct SetupContext<'a>{
pub surface:wgpu::Surface<'a>,
pub device:wgpu::Device,
pub queue:wgpu::Queue,
pub config:wgpu::SurfaceConfiguration,
struct ToSurfaceTarget{
canvas:web_sys::HtmlCanvasElement,
}
impl From<ToSurfaceTarget> for wgpu::SurfaceTarget<'static>{
fn from(ToSurfaceTarget{canvas}:ToSurfaceTarget)->Self{
#[cfg(target_arch = "wasm32")]
let target=wgpu::SurfaceTarget::Canvas(canvas);
#[expect(unused)]
#[cfg(not(target_arch = "wasm32"))]
let target=panic!("{canvas:?}");
#[allow(unused)]
target
}
}
pub async fn setup_and_start(canvas:web_sys::HtmlCanvasElement)->SetupContext<'static>{
pub async fn setup_and_start(canvas:web_sys::HtmlCanvasElement)->(wgpu::Device,wgpu::Queue,wgpu::Surface<'static>,wgpu::SurfaceConfiguration){
let size=(canvas.width(),canvas.height());
println!("Initializing the surface...");
let partial_1=create_instance();
let instance=step1::create_instance();
let partial_2=partial_1.create_surface(canvas).unwrap();
let surface=step2::create_surface(&instance,ToSurfaceTarget{canvas}).unwrap();
let partial_3=partial_2.pick_adapter().await;
let adapter=step3::pick_adapter(&instance,&surface).await.expect("No suitable GPU adapters found on the system!");
let partial_4=partial_3.request_device().await;
let (device,queue)=step4::request_device(&adapter).await;
let setup_context=partial_4.configure_surface(size);
let config=step5::configure_surface(&adapter,&device,&surface,size);
setup_context
(
device,
queue,
surface,
config,
)
}