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            let layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
76                label: Some("iced_wgpu.quad.gradient.pipeline"),
77                push_constant_ranges: &[],
78                bind_group_layouts: &[constants_layout],
79            });
80
81            let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
82                label: Some("iced_wgpu.quad.gradient.shader"),
83                source: wgpu::ShaderSource::Wgsl(std::borrow::Cow::Borrowed(concat!(
84                    include_str!("../shader/quad.wgsl"),
85                    "\n",
86                    include_str!("../shader/vertex.wgsl"),
87                    "\n",
88                    include_str!("../shader/quad/gradient.wgsl"),
89                    "\n",
90                    include_str!("../shader/color.wgsl"),
91                    "\n",
92                    include_str!("../shader/color/linear_rgb.wgsl")
93                ))),
94            });
95
96            let pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
97                label: Some("iced_wgpu.quad.gradient.pipeline"),
98                layout: Some(&layout),
99                vertex: wgpu::VertexState {
100                    module: &shader,
101                    entry_point: Some("gradient_vs_main"),
102                    buffers: &[wgpu::VertexBufferLayout {
103                        array_stride: std::mem::size_of::<Gradient>() as u64,
104                        step_mode: wgpu::VertexStepMode::Instance,
105                        attributes: &wgpu::vertex_attr_array!(
106                            // Colors 1-2
107                            0 => Uint32x4,
108                            // Colors 3-4
109                            1 => Uint32x4,
110                            // Colors 5-6
111                            2 => Uint32x4,
112                            // Colors 7-8
113                            3 => Uint32x4,
114                            // Offsets 1-8
115                            4 => Uint32x4,
116                            // Direction
117                            5 => Float32x4,
118                            // Position & Scale
119                            6 => Float32x4,
120                            // Border color
121                            7 => Float32x4,
122                            // Border radius
123                            8 => Float32x4,
124                            // Border width
125                            9 => Float32,
126                            // Snap
127                            10 => Uint32,
128                        ),
129                    }],
130                    compilation_options: wgpu::PipelineCompilationOptions::default(),
131                },
132                fragment: Some(wgpu::FragmentState {
133                    module: &shader,
134                    entry_point: Some("gradient_fs_main"),
135                    targets: &quad::color_target_state(format),
136                    compilation_options: wgpu::PipelineCompilationOptions::default(),
137                }),
138                primitive: wgpu::PrimitiveState {
139                    topology: wgpu::PrimitiveTopology::TriangleList,
140                    front_face: wgpu::FrontFace::Cw,
141                    ..Default::default()
142                },
143                depth_stencil: None,
144                multisample: wgpu::MultisampleState {
145                    count: 1,
146                    mask: !0,
147                    alpha_to_coverage_enabled: false,
148                },
149                multiview: None,
150                cache: None,
151            });
152
153            Self { pipeline }
154        }
155
156        #[cfg(target_arch = "wasm32")]
157        Self {}
158    }
159
160    #[allow(unused_variables)]
161    pub fn render<'a>(
162        &'a self,
163        render_pass: &mut wgpu::RenderPass<'a>,
164        constants: &'a wgpu::BindGroup,
165        layer: &'a Layer,
166        range: Range<usize>,
167    ) {
168        #[cfg(not(target_arch = "wasm32"))]
169        {
170            render_pass.set_pipeline(&self.pipeline);
171            render_pass.set_bind_group(0, constants, &[]);
172            render_pass.set_vertex_buffer(0, layer.instances.slice(..));
173
174            render_pass.draw(0..6, range.start as u32..range.end as u32);
175        }
176    }
177}