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