wgpu_examples/srgb_blend/
mod.rs

1use bytemuck::{Pod, Zeroable};
2use wgpu::util::DeviceExt;
3
4#[repr(C)]
5#[derive(Clone, Copy, Pod, Zeroable)]
6struct Vertex {
7    _pos: [f32; 4],
8    _color: [f32; 4],
9}
10
11fn vertex(pos: [i8; 2], _color: [f32; 4], offset: f32) -> Vertex {
12    let scale = 0.5;
13    Vertex {
14        _pos: [
15            (pos[0] as f32 + offset) * scale,
16            (pos[1] as f32 + offset) * scale,
17            0.0,
18            1.0,
19        ],
20        _color,
21    }
22}
23
24fn quad(vertices: &mut Vec<Vertex>, indices: &mut Vec<u16>, color: [f32; 4], offset: f32) {
25    let base = vertices.len() as u16;
26
27    vertices.extend_from_slice(&[
28        vertex([-1, -1], color, offset),
29        vertex([1, -1], color, offset),
30        vertex([1, 1], color, offset),
31        vertex([-1, 1], color, offset),
32    ]);
33
34    indices.extend([0, 1, 2, 2, 3, 0].iter().map(|i| base + *i));
35}
36
37fn create_vertices() -> (Vec<Vertex>, Vec<u16>) {
38    let mut vertices = Vec::new();
39    let mut indices = Vec::new();
40
41    let red = [1.0, 0.0, 0.0, 0.5];
42    let blue = [0.0, 0.0, 1.0, 0.5];
43
44    quad(&mut vertices, &mut indices, red, 0.5);
45    quad(&mut vertices, &mut indices, blue, -0.5);
46
47    (vertices, indices)
48}
49
50struct Example<const SRGB: bool> {
51    vertex_buf: wgpu::Buffer,
52    index_buf: wgpu::Buffer,
53    index_count: usize,
54    bind_group: wgpu::BindGroup,
55    pipeline: wgpu::RenderPipeline,
56}
57
58impl<const SRGB: bool> crate::framework::Example for Example<SRGB> {
59    const SRGB: bool = SRGB;
60
61    fn optional_features() -> wgpu::Features {
62        wgpu::Features::POLYGON_MODE_LINE
63    }
64
65    fn init(
66        config: &wgpu::SurfaceConfiguration,
67        _adapter: &wgpu::Adapter,
68        device: &wgpu::Device,
69        _queue: &wgpu::Queue,
70    ) -> Self {
71        // Create the vertex and index buffers
72        let vertex_size = size_of::<Vertex>();
73        let (vertex_data, index_data) = create_vertices();
74
75        let vertex_buf = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
76            label: Some("Vertex Buffer"),
77            contents: bytemuck::cast_slice(&vertex_data),
78            usage: wgpu::BufferUsages::VERTEX,
79        });
80
81        let index_buf = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
82            label: Some("Index Buffer"),
83            contents: bytemuck::cast_slice(&index_data),
84            usage: wgpu::BufferUsages::INDEX,
85        });
86
87        // Create pipeline layout
88        let bind_group_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
89            label: None,
90            entries: &[],
91        });
92        let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
93            label: None,
94            bind_group_layouts: &[&bind_group_layout],
95            push_constant_ranges: &[],
96        });
97
98        // Create bind group
99        let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
100            layout: &bind_group_layout,
101            entries: &[],
102            label: None,
103        });
104
105        let shader = device.create_shader_module(wgpu::include_wgsl!("shader.wgsl"));
106
107        let vertex_buffers = [wgpu::VertexBufferLayout {
108            array_stride: vertex_size as wgpu::BufferAddress,
109            step_mode: wgpu::VertexStepMode::Vertex,
110            attributes: &[
111                wgpu::VertexAttribute {
112                    format: wgpu::VertexFormat::Float32x4,
113                    offset: 0,
114                    shader_location: 0,
115                },
116                wgpu::VertexAttribute {
117                    format: wgpu::VertexFormat::Float32x4,
118                    offset: 4 * 4,
119                    shader_location: 1,
120                },
121            ],
122        }];
123
124        let pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
125            label: None,
126            layout: Some(&pipeline_layout),
127            vertex: wgpu::VertexState {
128                module: &shader,
129                entry_point: Some("vs_main"),
130                compilation_options: Default::default(),
131                buffers: &vertex_buffers,
132            },
133            fragment: Some(wgpu::FragmentState {
134                module: &shader,
135                entry_point: Some("fs_main"),
136                compilation_options: Default::default(),
137                targets: &[Some(wgpu::ColorTargetState {
138                    format: config.view_formats[0],
139                    blend: Some(wgpu::BlendState::ALPHA_BLENDING),
140                    write_mask: wgpu::ColorWrites::ALL,
141                })],
142            }),
143            primitive: wgpu::PrimitiveState {
144                cull_mode: Some(wgpu::Face::Back),
145                ..Default::default()
146            },
147            depth_stencil: None,
148            multisample: wgpu::MultisampleState::default(),
149            multiview: None,
150            cache: None,
151        });
152
153        // Done
154        Example {
155            vertex_buf,
156            index_buf,
157            index_count: index_data.len(),
158            bind_group,
159            pipeline,
160        }
161    }
162
163    fn update(&mut self, _event: winit::event::WindowEvent) {
164        //empty
165    }
166
167    fn resize(
168        &mut self,
169        _config: &wgpu::SurfaceConfiguration,
170        _device: &wgpu::Device,
171        _queue: &wgpu::Queue,
172    ) {
173    }
174
175    fn render(&mut self, view: &wgpu::TextureView, device: &wgpu::Device, queue: &wgpu::Queue) {
176        device.push_error_scope(wgpu::ErrorFilter::Validation);
177        let mut encoder =
178            device.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None });
179        {
180            let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
181                label: None,
182                color_attachments: &[Some(wgpu::RenderPassColorAttachment {
183                    view,
184                    depth_slice: None,
185                    resolve_target: None,
186                    ops: wgpu::Operations {
187                        load: wgpu::LoadOp::Clear(wgpu::Color {
188                            r: 0.0,
189                            g: 0.0,
190                            b: 0.0,
191                            a: 1.0,
192                        }),
193                        store: wgpu::StoreOp::Store,
194                    },
195                })],
196                depth_stencil_attachment: None,
197                timestamp_writes: None,
198                occlusion_query_set: None,
199            });
200            rpass.push_debug_group("Prepare data for draw.");
201            rpass.set_pipeline(&self.pipeline);
202            rpass.set_bind_group(0, &self.bind_group, &[]);
203            rpass.set_index_buffer(self.index_buf.slice(..), wgpu::IndexFormat::Uint16);
204            rpass.set_vertex_buffer(0, self.vertex_buf.slice(..));
205            rpass.pop_debug_group();
206            rpass.insert_debug_marker("Draw!");
207            rpass.draw_indexed(0..self.index_count as u32, 0, 0..1);
208        }
209
210        queue.submit(Some(encoder.finish()));
211    }
212}
213
214pub fn main() {
215    let mut args = std::env::args();
216    args.next();
217    if Some("linear") == args.nth(1).as_deref() {
218        crate::framework::run::<Example<false>>("srgb-blend-linear");
219    } else {
220        crate::framework::run::<Example<true>>("srgb-blend-srg");
221    }
222}
223
224#[cfg(test)]
225#[wgpu_test::gpu_test]
226pub static TEST_SRGB: crate::framework::ExampleTestParams = crate::framework::ExampleTestParams {
227    name: "srgb-blend-srg",
228    // Generated on WARP/Windows
229    image_path: "/examples/features/src/srgb_blend/screenshot-srgb.png",
230    width: 192,
231    height: 192,
232    optional_features: wgpu::Features::default(),
233    base_test_parameters: wgpu_test::TestParameters::default(),
234    comparisons: &[wgpu_test::ComparisonType::Mean(0.04)],
235    _phantom: std::marker::PhantomData::<Example<true>>,
236};
237
238#[cfg(test)]
239#[wgpu_test::gpu_test]
240pub static TEST_LINEAR: crate::framework::ExampleTestParams = crate::framework::ExampleTestParams {
241    name: "srgb-blend-linear",
242    // Generated on WARP/Windows
243    image_path: "/examples/features/src/srgb_blend/screenshot-linear.png",
244    width: 192,
245    height: 192,
246    optional_features: wgpu::Features::default(),
247    base_test_parameters: wgpu_test::TestParameters::default(),
248    comparisons: &[wgpu_test::ComparisonType::Mean(0.04)],
249    _phantom: std::marker::PhantomData::<Example<false>>,
250};