wgpu_examples/multiview/
mod.rs

1//! Renders different content to different layers of an array texture using multiview,
2//! a feature commonly used for VR rendering.
3
4use std::{num::NonZero, time::Instant};
5
6use wgpu::util::TextureBlitter;
7
8const TEXTURE_SIZE: u32 = 512;
9
10// Change this to demonstrate non-contiguous multiview functionality
11const LAYER_MASK: u32 = 0b11;
12
13const NUM_LAYERS: u32 = 32 - LAYER_MASK.leading_zeros();
14
15pub struct Example {
16    pipeline: wgpu::RenderPipeline,
17    entire_texture_view: wgpu::TextureView,
18    views: Vec<wgpu::TextureView>,
19    start_time: Instant,
20    blitter: TextureBlitter,
21}
22
23impl crate::framework::Example for Example {
24    fn init(
25        config: &wgpu::SurfaceConfiguration,
26        _adapter: &wgpu::Adapter,
27        device: &wgpu::Device,
28        _queue: &wgpu::Queue,
29    ) -> Self {
30        let shader_src = include_str!("shader.wgsl");
31
32        let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
33            label: None,
34            source: wgpu::ShaderSource::Wgsl(shader_src.into()),
35        });
36
37        let pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
38            label: None,
39            vertex: wgpu::VertexState {
40                buffers: &[],
41                module: &shader,
42                entry_point: Some("vs_main"),
43                compilation_options: Default::default(),
44            },
45            primitive: wgpu::PrimitiveState::default(),
46            fragment: Some(wgpu::FragmentState {
47                module: &shader,
48                entry_point: Some("fs_main"),
49                compilation_options: Default::default(),
50                targets: &[Some(wgpu::ColorTargetState {
51                    format: wgpu::TextureFormat::Rgba8Unorm,
52                    blend: None,
53                    write_mask: wgpu::ColorWrites::ALL,
54                })],
55            }),
56            multiview_mask: NonZero::new(LAYER_MASK),
57            multisample: Default::default(),
58            layout: None,
59            depth_stencil: None,
60            cache: None,
61        });
62        let texture = device.create_texture(&wgpu::TextureDescriptor {
63            label: None,
64            size: wgpu::Extent3d {
65                width: TEXTURE_SIZE,
66                height: TEXTURE_SIZE,
67                depth_or_array_layers: NUM_LAYERS,
68            },
69            mip_level_count: 1,
70            sample_count: 1,
71            dimension: wgpu::TextureDimension::D2,
72            format: wgpu::TextureFormat::Rgba8Unorm,
73            usage: wgpu::TextureUsages::RENDER_ATTACHMENT
74                | wgpu::TextureUsages::COPY_SRC
75                | wgpu::TextureUsages::TEXTURE_BINDING,
76            view_formats: &[],
77        });
78        let entire_texture_view = texture.create_view(&wgpu::TextureViewDescriptor {
79            label: None,
80            format: Some(wgpu::TextureFormat::Rgba8Unorm),
81            dimension: Some(wgpu::TextureViewDimension::D2Array),
82            usage: Some(wgpu::TextureUsages::RENDER_ATTACHMENT),
83            aspect: wgpu::TextureAspect::All,
84            base_mip_level: 0,
85            mip_level_count: None,
86            base_array_layer: 0,
87            array_layer_count: Some(NUM_LAYERS),
88        });
89        let mut views = Vec::new();
90        for i in 0..NUM_LAYERS {
91            views.push(texture.create_view(&wgpu::TextureViewDescriptor {
92                label: None,
93                format: Some(wgpu::TextureFormat::Rgba8Unorm),
94                dimension: Some(wgpu::TextureViewDimension::D2),
95                usage: Some(wgpu::TextureUsages::TEXTURE_BINDING),
96                aspect: wgpu::TextureAspect::All,
97                base_mip_level: 0,
98                mip_level_count: None,
99                base_array_layer: i,
100                array_layer_count: Some(1),
101            }));
102        }
103        let blitter = wgpu::util::TextureBlitter::new(device, config.format);
104        Self {
105            pipeline,
106            entire_texture_view,
107            views,
108            blitter,
109            start_time: Instant::now(),
110        }
111    }
112
113    fn render(&mut self, view: &wgpu::TextureView, device: &wgpu::Device, queue: &wgpu::Queue) {
114        let mut encoder = device.create_command_encoder(&wgpu::CommandEncoderDescriptor::default());
115        {
116            let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
117                label: None,
118                color_attachments: &[Some(wgpu::RenderPassColorAttachment {
119                    view: &self.entire_texture_view,
120                    depth_slice: None,
121                    resolve_target: None,
122                    ops: wgpu::Operations {
123                        load: wgpu::LoadOp::Clear(wgpu::Color {
124                            r: 0.02,
125                            g: 0.02,
126                            b: 0.02,
127                            a: 1.0,
128                        }),
129                        store: wgpu::StoreOp::Store,
130                    },
131                })],
132                depth_stencil_attachment: None,
133                timestamp_writes: None,
134                occlusion_query_set: None,
135                multiview_mask: NonZero::new(LAYER_MASK),
136            });
137            rpass.set_pipeline(&self.pipeline);
138            rpass.draw(0..6, 0..1);
139        }
140
141        let layer = (Instant::now() - self.start_time).as_secs() % NUM_LAYERS as u64;
142        self.blitter
143            .copy(device, &mut encoder, &self.views[layer as usize], view);
144        queue.submit(Some(encoder.finish()));
145    }
146
147    fn required_downlevel_capabilities() -> wgpu::DownlevelCapabilities {
148        Default::default()
149    }
150
151    fn required_features() -> wgpu::Features {
152        wgpu::Features::MULTIVIEW
153            | if !(LAYER_MASK + 1).is_power_of_two() {
154                wgpu::Features::SELECTIVE_MULTIVIEW
155            } else {
156                wgpu::Features::empty()
157            }
158    }
159
160    fn required_limits() -> wgpu::Limits {
161        wgpu::Limits {
162            max_multiview_view_count: NUM_LAYERS,
163            ..Default::default()
164        }
165    }
166
167    fn resize(
168        &mut self,
169        _config: &wgpu::SurfaceConfiguration,
170        _device: &wgpu::Device,
171        _queue: &wgpu::Queue,
172    ) {
173        // empty
174    }
175    fn update(&mut self, _event: winit::event::WindowEvent) {
176        // empty
177    }
178}
179
180pub fn main() {
181    crate::framework::run::<Example>("multiview");
182}