1use bytemuck::{Pod, Zeroable};
2use wgpu::util::DeviceExt;
3
4#[repr(C)]
22#[derive(Copy, Clone, Debug, Pod, Zeroable)]
23pub struct RectInstance {
24 pub pos: [f32; 2],
25 pub size: [f32; 2],
26 pub color: [f32; 4],
27 pub radius: [f32; 4],
28 pub border_width: f32, pub border_color: [f32; 4], pub shadow_color: [f32; 4], pub shadow_offset: [f32; 2], pub shadow_blur: f32, pub clip_rect: [f32; 4], pub grayscale: f32, pub brightness: f32,
36 pub opacity: f32,
37 pub border_alignment: f32,
38}
39
40impl Default for RectInstance {
41 fn default() -> Self {
42 Self {
43 pos: [0.0; 2],
44 size: [100.0, 100.0],
45 color: [1.0, 1.0, 1.0, 1.0],
46 radius: [0.0; 4],
47 border_width: 0.0,
48 border_color: [0.0; 4],
49 shadow_color: [0.0; 4],
50 shadow_offset: [0.0; 2],
51 shadow_blur: 0.0,
52 clip_rect: [0.0, 0.0, 9999.0, 9999.0],
53 grayscale: 0.0,
54 brightness: 1.0,
55 opacity: 1.0,
56 border_alignment: 0.0, }
58 }
59}
60
61impl RectInstance {
62 pub const fn desc() -> wgpu::VertexBufferLayout<'static> {
63 wgpu::VertexBufferLayout {
64 array_stride: std::mem::size_of::<RectInstance>() as wgpu::BufferAddress,
65 step_mode: wgpu::VertexStepMode::Instance,
66 attributes: &[
67 wgpu::VertexAttribute {
68 offset: 0,
69 shader_location: 0,
70 format: wgpu::VertexFormat::Float32x2,
71 },
72 wgpu::VertexAttribute {
73 offset: 8,
74 shader_location: 1,
75 format: wgpu::VertexFormat::Float32x2,
76 },
77 wgpu::VertexAttribute {
78 offset: 16,
79 shader_location: 2,
80 format: wgpu::VertexFormat::Float32x4,
81 },
82 wgpu::VertexAttribute {
83 offset: 32,
84 shader_location: 3,
85 format: wgpu::VertexFormat::Float32x4,
86 },
87 wgpu::VertexAttribute {
88 offset: 48,
89 shader_location: 4,
90 format: wgpu::VertexFormat::Float32,
91 },
92 wgpu::VertexAttribute {
93 offset: 52,
94 shader_location: 5,
95 format: wgpu::VertexFormat::Float32x4,
96 },
97 wgpu::VertexAttribute {
98 offset: 68,
99 shader_location: 6,
100 format: wgpu::VertexFormat::Float32x4,
101 },
102 wgpu::VertexAttribute {
103 offset: 84,
104 shader_location: 7,
105 format: wgpu::VertexFormat::Float32x2,
106 },
107 wgpu::VertexAttribute {
108 offset: 92,
109 shader_location: 8,
110 format: wgpu::VertexFormat::Float32,
111 },
112 wgpu::VertexAttribute {
113 offset: 96,
114 shader_location: 9,
115 format: wgpu::VertexFormat::Float32x4,
116 },
117 wgpu::VertexAttribute {
118 offset: 112,
119 shader_location: 10,
120 format: wgpu::VertexFormat::Float32,
121 },
122 wgpu::VertexAttribute {
123 offset: 116,
124 shader_location: 11,
125 format: wgpu::VertexFormat::Float32,
126 },
127 wgpu::VertexAttribute {
128 offset: 120,
129 shader_location: 12,
130 format: wgpu::VertexFormat::Float32,
131 },
132 wgpu::VertexAttribute {
133 offset: 124,
134 shader_location: 13,
135 format: wgpu::VertexFormat::Float32,
136 },
137 ],
138 }
139 }
140}
141
142#[repr(C)]
143#[derive(Copy, Clone, Pod, Zeroable)]
144struct ScreenUniforms {
145 screen_size: [f32; 2],
146 _padding: [f32; 2],
147}
148
149pub struct RectPipeline {
150 pub pipeline: wgpu::RenderPipeline,
151 pub uniform_buffer: wgpu::Buffer,
152 pub uniform_bg: wgpu::BindGroup,
153 pub instance_buffer: Option<wgpu::Buffer>,
154 pub instance_count: u32,
155}
156
157impl RectPipeline {
158 pub fn new(device: &wgpu::Device, format: wgpu::TextureFormat) -> Self {
159 let shader = device.create_shader_module(wgpu::include_wgsl!("shaders/rect.wgsl"));
160
161 let uniform_buffer = device.create_buffer(&wgpu::BufferDescriptor {
162 label: Some("Rect Uniform Buffer"),
163 size: std::mem::size_of::<ScreenUniforms>() as u64,
164 usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
165 mapped_at_creation: false,
166 });
167
168 let bgl = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
169 label: Some("Rect BGL"),
170 entries: &[wgpu::BindGroupLayoutEntry {
171 binding: 0,
172 visibility: wgpu::ShaderStages::VERTEX,
173 ty: wgpu::BindingType::Buffer {
174 ty: wgpu::BufferBindingType::Uniform,
175 has_dynamic_offset: false,
176 min_binding_size: None,
177 },
178 count: None,
179 }],
180 });
181
182 let uniform_bg = device.create_bind_group(&wgpu::BindGroupDescriptor {
183 label: Some("Rect Uniform BG"),
184 layout: &bgl,
185 entries: &[wgpu::BindGroupEntry {
186 binding: 0,
187 resource: uniform_buffer.as_entire_binding(),
188 }],
189 });
190
191 let layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
192 label: Some("Rect Pipeline Layout"),
193 bind_group_layouts: &[Some(&bgl)],
194 immediate_size: 0,
195 });
196
197 let pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
198 label: Some("Rect Pipeline"),
199 layout: Some(&layout),
200 vertex: wgpu::VertexState {
201 module: &shader,
202 entry_point: Some("vs_main"),
203 buffers: &[RectInstance::desc()],
204 compilation_options: Default::default(),
205 },
206 fragment: Some(wgpu::FragmentState {
207 module: &shader,
208 entry_point: Some("fs_main"),
209 targets: &[Some(wgpu::ColorTargetState {
210 format,
211 blend: Some(wgpu::BlendState::PREMULTIPLIED_ALPHA_BLENDING),
212 write_mask: wgpu::ColorWrites::ALL,
213 })],
214 compilation_options: Default::default(),
215 }),
216 primitive: wgpu::PrimitiveState::default(),
217 depth_stencil: None,
218 multisample: wgpu::MultisampleState::default(),
219 multiview_mask: None,
220 cache: None,
221 });
222
223 Self {
224 pipeline,
225 uniform_buffer,
226 uniform_bg,
227 instance_buffer: None,
228 instance_count: 0,
229 }
230 }
231
232 pub fn prepare(
233 &mut self,
234 device: &wgpu::Device,
235 queue: &wgpu::Queue,
236 width: u32,
237 height: u32,
238 rects: &[RectInstance],
239 ) {
240 queue.write_buffer(
241 &self.uniform_buffer,
242 0,
243 bytemuck::bytes_of(&ScreenUniforms {
244 screen_size: [width as f32, height as f32],
245 _padding: [0.0; 2],
246 }),
247 );
248
249 if rects.is_empty() {
250 self.instance_count = 0;
251 return;
252 }
253
254 self.instance_buffer = Some(
255 device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
256 label: Some("Rect Instance Buffer"),
257 contents: bytemuck::cast_slice(rects),
258 usage: wgpu::BufferUsages::VERTEX,
259 }),
260 );
261 self.instance_count = rects.len() as u32;
262 }
263
264 pub fn draw<'a>(&'a self, pass: &mut wgpu::RenderPass<'a>) {
265 if self.instance_count == 0 {
266 return;
267 }
268 if let Some(buf) = &self.instance_buffer {
269 pass.set_pipeline(&self.pipeline);
270 pass.set_bind_group(0, &self.uniform_bg, &[]);
271 pass.set_vertex_buffer(0, buf.slice(..));
272 pass.draw(0..6, 0..self.instance_count);
273 }
274 }
275}