1use crate::Buffer;
2use crate::graphics::gradient;
3use crate::quad::{self, Quad};
4
5use bytemuck::{Pod, Zeroable};
6use std::ops::Range;
7
8#[derive(Clone, Copy, Debug)]
10#[repr(C)]
11pub struct Gradient {
12 pub gradient: gradient::Packed,
14
15 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 0 => Uint32x4,
139 1 => Uint32x4,
141 2 => Uint32x4,
143 3 => Uint32x4,
145 4 => Uint32x4,
147 5 => Float32x4,
149 6 => Float32x4,
151 7 => Float32x4,
153 8 => Float32x4,
155 9 => Float32,
157 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}