iced_wgpu/quad/
gradient.rs

1use crate::Buffer;
2use crate::graphics::gradient;
3use crate::quad::{self, Quad};
4
5use bytemuck::{Pod, Zeroable};
6use std::ops::Range;
7
8/// A quad filled with interpolated colors.
9#[derive(Clone, Copy, Debug)]
10#[repr(C)]
11pub struct Gradient {
12    /// The background gradient data of the quad.
13    pub gradient: gradient::Packed,
14
15    /// The [`Quad`] data of the [`Gradient`].
16    pub quad: Quad,
17}
18
19#[allow(unsafe_code)]
20unsafe impl Pod for Gradient {}
21
22#[allow(unsafe_code)]
23unsafe impl Zeroable for Gradient {}
24
25#[derive(Debug)]
26pub struct Layer {
27    instances: Buffer<Gradient>,
28    instance_count: usize,
29}
30
31impl Layer {
32    pub fn new(device: &wgpu::Device) -> Self {
33        let instances = Buffer::new(
34            device,
35            "iced_wgpu.quad.gradient.buffer",
36            quad::INITIAL_INSTANCES,
37            wgpu::BufferUsages::VERTEX | wgpu::BufferUsages::COPY_DST,
38        );
39
40        Self {
41            instances,
42            instance_count: 0,
43        }
44    }
45
46    pub fn prepare(
47        &mut self,
48        device: &wgpu::Device,
49        encoder: &mut wgpu::CommandEncoder,
50        belt: &mut wgpu::util::StagingBelt,
51        instances: &[Gradient],
52    ) {
53        let _ = self.instances.resize(device, instances.len());
54        let _ = self.instances.write(device, encoder, belt, 0, instances);
55
56        self.instance_count = instances.len();
57    }
58}
59
60#[derive(Debug, Clone)]
61pub struct Pipeline {
62    #[cfg(not(target_arch = "wasm32"))]
63    pipeline: wgpu::RenderPipeline,
64}
65
66impl Pipeline {
67    #[allow(unused_variables)]
68    pub fn new(
69        device: &wgpu::Device,
70        format: wgpu::TextureFormat,
71        constants_layout: &wgpu::BindGroupLayout,
72    ) -> Self {
73        #[cfg(not(target_arch = "wasm32"))]
74        {
75            use crate::graphics::color;
76
77            let layout = device.create_pipeline_layout(
78                &wgpu::PipelineLayoutDescriptor {
79                    label: Some("iced_wgpu.quad.gradient.pipeline"),
80                    push_constant_ranges: &[],
81                    bind_group_layouts: &[constants_layout],
82                },
83            );
84
85            let shader =
86                device.create_shader_module(wgpu::ShaderModuleDescriptor {
87                    label: Some("iced_wgpu.quad.gradient.shader"),
88                    source: wgpu::ShaderSource::Wgsl(
89                        std::borrow::Cow::Borrowed(
90                            if color::GAMMA_CORRECTION {
91                                concat!(
92                                    include_str!("../shader/quad.wgsl"),
93                                    "\n",
94                                    include_str!("../shader/vertex.wgsl"),
95                                    "\n",
96                                    include_str!(
97                                        "../shader/quad/gradient.wgsl"
98                                    ),
99                                    "\n",
100                                    include_str!("../shader/color.wgsl"),
101                                    "\n",
102                                    include_str!("../shader/color/oklab.wgsl")
103                                )
104                            } else {
105                                concat!(
106                                    include_str!("../shader/quad.wgsl"),
107                                    "\n",
108                                    include_str!("../shader/vertex.wgsl"),
109                                    "\n",
110                                    include_str!(
111                                        "../shader/quad/gradient.wgsl"
112                                    ),
113                                    "\n",
114                                    include_str!("../shader/color.wgsl"),
115                                    "\n",
116                                    include_str!(
117                                        "../shader/color/linear_rgb.wgsl"
118                                    )
119                                )
120                            },
121                        ),
122                    ),
123                });
124
125            let pipeline = device.create_render_pipeline(
126                &wgpu::RenderPipelineDescriptor {
127                    label: Some("iced_wgpu.quad.gradient.pipeline"),
128                    layout: Some(&layout),
129                    vertex: wgpu::VertexState {
130                        module: &shader,
131                        entry_point: Some("gradient_vs_main"),
132                        buffers: &[wgpu::VertexBufferLayout {
133                            array_stride: std::mem::size_of::<Gradient>()
134                                as u64,
135                            step_mode: wgpu::VertexStepMode::Instance,
136                            attributes: &wgpu::vertex_attr_array!(
137                                // Colors 1-2
138                                0 => Uint32x4,
139                                // Colors 3-4
140                                1 => Uint32x4,
141                                // Colors 5-6
142                                2 => Uint32x4,
143                                // Colors 7-8
144                                3 => Uint32x4,
145                                // Offsets 1-8
146                                4 => Uint32x4,
147                                // Direction
148                                5 => Float32x4,
149                                // Position & Scale
150                                6 => Float32x4,
151                                // Border color
152                                7 => Float32x4,
153                                // Border radius
154                                8 => Float32x4,
155                                // Border width
156                                9 => Float32,
157                                // Snap
158                                10 => Uint32,
159                            ),
160                        }],
161                        compilation_options:
162                            wgpu::PipelineCompilationOptions::default(),
163                    },
164                    fragment: Some(wgpu::FragmentState {
165                        module: &shader,
166                        entry_point: Some("gradient_fs_main"),
167                        targets: &quad::color_target_state(format),
168                        compilation_options:
169                            wgpu::PipelineCompilationOptions::default(),
170                    }),
171                    primitive: wgpu::PrimitiveState {
172                        topology: wgpu::PrimitiveTopology::TriangleList,
173                        front_face: wgpu::FrontFace::Cw,
174                        ..Default::default()
175                    },
176                    depth_stencil: None,
177                    multisample: wgpu::MultisampleState {
178                        count: 1,
179                        mask: !0,
180                        alpha_to_coverage_enabled: false,
181                    },
182                    multiview: None,
183                    cache: None,
184                },
185            );
186
187            Self { pipeline }
188        }
189
190        #[cfg(target_arch = "wasm32")]
191        Self {}
192    }
193
194    #[allow(unused_variables)]
195    pub fn render<'a>(
196        &'a self,
197        render_pass: &mut wgpu::RenderPass<'a>,
198        constants: &'a wgpu::BindGroup,
199        layer: &'a Layer,
200        range: Range<usize>,
201    ) {
202        #[cfg(not(target_arch = "wasm32"))]
203        {
204            render_pass.set_pipeline(&self.pipeline);
205            render_pass.set_bind_group(0, constants, &[]);
206            render_pass.set_vertex_buffer(0, layer.instances.slice(..));
207
208            render_pass.draw(0..6, range.start as u32..range.end as u32);
209        }
210    }
211}