wgpu_examples/hello_triangle/
mod.rs
1use std::borrow::Cow;
2use winit::{
3 event::{Event, WindowEvent},
4 event_loop::EventLoop,
5 window::Window,
6};
7
8async fn run(event_loop: EventLoop<()>, window: Window) {
9 let mut size = window.inner_size();
10 size.width = size.width.max(1);
11 size.height = size.height.max(1);
12
13 let instance = wgpu::Instance::new(&wgpu::InstanceDescriptor::from_env_or_default());
14
15 let surface = instance.create_surface(&window).unwrap();
16 let adapter = instance
17 .request_adapter(&wgpu::RequestAdapterOptions {
18 power_preference: wgpu::PowerPreference::default(),
19 force_fallback_adapter: false,
20 compatible_surface: Some(&surface),
22 })
23 .await
24 .expect("Failed to find an appropriate adapter");
25
26 let (device, queue) = adapter
28 .request_device(&wgpu::DeviceDescriptor {
29 label: None,
30 required_features: wgpu::Features::empty(),
31 required_limits: wgpu::Limits::downlevel_webgl2_defaults()
33 .using_resolution(adapter.limits()),
34 memory_hints: wgpu::MemoryHints::MemoryUsage,
35 trace: wgpu::Trace::Off,
36 })
37 .await
38 .expect("Failed to create device");
39
40 let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
42 label: None,
43 source: wgpu::ShaderSource::Wgsl(Cow::Borrowed(include_str!("shader.wgsl"))),
44 });
45
46 let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
47 label: None,
48 bind_group_layouts: &[],
49 push_constant_ranges: &[],
50 });
51
52 let swapchain_capabilities = surface.get_capabilities(&adapter);
53 let swapchain_format = swapchain_capabilities.formats[0];
54
55 let render_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
56 label: None,
57 layout: Some(&pipeline_layout),
58 vertex: wgpu::VertexState {
59 module: &shader,
60 entry_point: Some("vs_main"),
61 buffers: &[],
62 compilation_options: Default::default(),
63 },
64 fragment: Some(wgpu::FragmentState {
65 module: &shader,
66 entry_point: Some("fs_main"),
67 compilation_options: Default::default(),
68 targets: &[Some(swapchain_format.into())],
69 }),
70 primitive: wgpu::PrimitiveState::default(),
71 depth_stencil: None,
72 multisample: wgpu::MultisampleState::default(),
73 multiview: None,
74 cache: None,
75 });
76
77 let mut config = surface
78 .get_default_config(&adapter, size.width, size.height)
79 .unwrap();
80 surface.configure(&device, &config);
81
82 let window = &window;
83 event_loop
84 .run(move |event, target| {
85 let _ = (&instance, &adapter, &shader, &pipeline_layout);
89
90 if let Event::WindowEvent {
91 window_id: _,
92 event,
93 } = event
94 {
95 match event {
96 WindowEvent::Resized(new_size) => {
97 config.width = new_size.width.max(1);
99 config.height = new_size.height.max(1);
100 surface.configure(&device, &config);
101 window.request_redraw();
103 }
104 WindowEvent::RedrawRequested => {
105 let frame = surface
106 .get_current_texture()
107 .expect("Failed to acquire next swap chain texture");
108 let view = frame
109 .texture
110 .create_view(&wgpu::TextureViewDescriptor::default());
111 let mut encoder =
112 device.create_command_encoder(&wgpu::CommandEncoderDescriptor {
113 label: None,
114 });
115 {
116 let mut rpass =
117 encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
118 label: None,
119 color_attachments: &[Some(wgpu::RenderPassColorAttachment {
120 view: &view,
121 depth_slice: None,
122 resolve_target: None,
123 ops: wgpu::Operations {
124 load: wgpu::LoadOp::Clear(wgpu::Color::GREEN),
125 store: wgpu::StoreOp::Store,
126 },
127 })],
128 depth_stencil_attachment: None,
129 timestamp_writes: None,
130 occlusion_query_set: None,
131 });
132 rpass.set_pipeline(&render_pipeline);
133 rpass.draw(0..3, 0..1);
134 }
135
136 queue.submit(Some(encoder.finish()));
137 window.pre_present_notify();
138 frame.present();
139 }
140 WindowEvent::CloseRequested => target.exit(),
141 _ => {}
142 };
143 }
144 })
145 .unwrap();
146}
147
148pub fn main() {
149 let event_loop = EventLoop::new().unwrap();
150 #[cfg_attr(
151 not(target_arch = "wasm32"),
152 expect(unused_mut, reason = "`wasm32` re-assigns to specify canvas")
153 )]
154 let mut builder = winit::window::WindowBuilder::new();
155 #[cfg(target_arch = "wasm32")]
156 {
157 use wasm_bindgen::JsCast;
158 use winit::platform::web::WindowBuilderExtWebSys;
159 let canvas = web_sys::window()
160 .unwrap()
161 .document()
162 .unwrap()
163 .get_element_by_id("canvas")
164 .unwrap()
165 .dyn_into::<web_sys::HtmlCanvasElement>()
166 .unwrap();
167 builder = builder.with_canvas(Some(canvas));
168 }
169 let window = builder.build(&event_loop).unwrap();
170
171 #[cfg(not(target_arch = "wasm32"))]
172 {
173 env_logger::init();
174 pollster::block_on(run(event_loop, window));
175 }
176 #[cfg(target_arch = "wasm32")]
177 {
178 std::panic::set_hook(Box::new(console_error_panic_hook::hook));
179 console_log::init().expect("could not initialize logger");
180 wasm_bindgen_futures::spawn_local(run(event_loop, window));
181 }
182}