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 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 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 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 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 }
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 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 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};