1use bytemuck::{Pod, Zeroable};
2
3#[repr(C)]
4#[derive(Copy, Clone, Debug, Pod, Zeroable)]
5pub struct ImageInstance {
6 pub pos: [f32; 2],
7 pub size: [f32; 2],
8 pub radius: [f32; 4],
9 pub border_width: f32,
10 pub border_color: [f32; 4],
11 pub shadow_color: [f32; 4],
12 pub shadow_offset: [f32; 2],
13 pub shadow_blur: f32,
14 pub clip_rect: [f32; 4],
15 pub grayscale: f32,
16 pub brightness: f32,
17 pub opacity: f32,
18 pub uv_rect: [f32; 4],
19 pub bg_color: [f32; 4],
20 pub rotation: [f32; 3], pub flip: [f32; 2], }
23
24impl Default for ImageInstance {
25 fn default() -> Self {
26 Self {
27 pos: [0.0; 2],
28 size: [100.0, 100.0],
29 radius: [0.0; 4],
30 border_width: 0.0,
31 border_color: [0.0; 4],
32 shadow_color: [0.0; 4],
33 shadow_offset: [0.0; 2],
34 shadow_blur: 0.0,
35 clip_rect: [0.0, 0.0, 9999.0, 9999.0],
36 grayscale: 0.0,
37 brightness: 1.0,
38 opacity: 1.0,
39 uv_rect: [0.0, 0.0, 1.0, 1.0],
40 bg_color: [0.0; 4],
41 rotation: [0.0; 3],
42 flip: [1.0, 1.0],
43 }
44 }
45}
46
47impl ImageInstance {
48 pub const fn desc() -> wgpu::VertexBufferLayout<'static> {
49 wgpu::VertexBufferLayout {
50 array_stride: std::mem::size_of::<ImageInstance>() as wgpu::BufferAddress,
51 step_mode: wgpu::VertexStepMode::Instance,
52 attributes: &[
53 wgpu::VertexAttribute { offset: 0, shader_location: 0, format: wgpu::VertexFormat::Float32x2 },
54 wgpu::VertexAttribute { offset: 8, shader_location: 1, format: wgpu::VertexFormat::Float32x2 },
55 wgpu::VertexAttribute { offset: 16, shader_location: 2, format: wgpu::VertexFormat::Float32x4 },
56 wgpu::VertexAttribute { offset: 32, shader_location: 3, format: wgpu::VertexFormat::Float32 },
57 wgpu::VertexAttribute { offset: 36, shader_location: 4, format: wgpu::VertexFormat::Float32x4 },
58 wgpu::VertexAttribute { offset: 52, shader_location: 5, format: wgpu::VertexFormat::Float32x4 },
59 wgpu::VertexAttribute { offset: 68, shader_location: 6, format: wgpu::VertexFormat::Float32x2 },
60 wgpu::VertexAttribute { offset: 76, shader_location: 7, format: wgpu::VertexFormat::Float32 },
61 wgpu::VertexAttribute { offset: 80, shader_location: 8, format: wgpu::VertexFormat::Float32x4 },
62 wgpu::VertexAttribute { offset: 96, shader_location: 9, format: wgpu::VertexFormat::Float32 },
63 wgpu::VertexAttribute { offset: 100, shader_location: 10, format: wgpu::VertexFormat::Float32 },
64 wgpu::VertexAttribute { offset: 104, shader_location: 11, format: wgpu::VertexFormat::Float32 },
65 wgpu::VertexAttribute { offset: 108, shader_location: 12, format: wgpu::VertexFormat::Float32x4 },
66 wgpu::VertexAttribute { offset: 124, shader_location: 13, format: wgpu::VertexFormat::Float32x4 },
67 wgpu::VertexAttribute { offset: 140, shader_location: 14, format: wgpu::VertexFormat::Float32x3 },
68 wgpu::VertexAttribute { offset: 152, shader_location: 15, format: wgpu::VertexFormat::Float32x2 },
69 ],
70 }
71 }
72}
73
74#[repr(C)]
75#[derive(Copy, Clone, Pod, Zeroable)]
76struct ScreenUniforms {
77 screen_size: [f32; 2],
78 _padding: [f32; 2],
79}
80
81pub struct ImagePipeline {
82 pipeline: wgpu::RenderPipeline,
83 uniform_buffer: wgpu::Buffer,
84 uniform_bg: wgpu::BindGroup,
85 pub texture_bgl: wgpu::BindGroupLayout,
86}
87
88impl ImagePipeline {
89 pub fn new(device: &wgpu::Device, format: wgpu::TextureFormat) -> Self {
90 let shader = device.create_shader_module(wgpu::include_wgsl!("shaders/image.wgsl"));
91
92 let uniform_buffer = device.create_buffer(&wgpu::BufferDescriptor {
93 label: Some("Image Uniform Buffer"),
94 size: std::mem::size_of::<ScreenUniforms>() as u64,
95 usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
96 mapped_at_creation: false,
97 });
98
99 let uniform_bgl = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
100 label: Some("Image Uniform BGL"),
101 entries: &[wgpu::BindGroupLayoutEntry {
102 binding: 0,
103 visibility: wgpu::ShaderStages::VERTEX,
104 ty: wgpu::BindingType::Buffer {
105 ty: wgpu::BufferBindingType::Uniform,
106 has_dynamic_offset: false,
107 min_binding_size: None,
108 },
109 count: None,
110 }],
111 });
112
113 let uniform_bg = device.create_bind_group(&wgpu::BindGroupDescriptor {
114 label: Some("Image Uniform BG"),
115 layout: &uniform_bgl,
116 entries: &[wgpu::BindGroupEntry {
117 binding: 0,
118 resource: uniform_buffer.as_entire_binding(),
119 }],
120 });
121
122 let texture_bgl = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
123 label: Some("Image Texture BGL"),
124 entries: &[
125 wgpu::BindGroupLayoutEntry {
126 binding: 0,
127 visibility: wgpu::ShaderStages::FRAGMENT,
128 ty: wgpu::BindingType::Texture {
129 sample_type: wgpu::TextureSampleType::Float { filterable: true },
130 view_dimension: wgpu::TextureViewDimension::D2,
131 multisampled: false,
132 },
133 count: None,
134 },
135 wgpu::BindGroupLayoutEntry {
136 binding: 1,
137 visibility: wgpu::ShaderStages::FRAGMENT,
138 ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering),
139 count: None,
140 },
141 ],
142 });
143
144 let layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
145 label: Some("Image Pipeline Layout"),
146 bind_group_layouts: &[Some(&uniform_bgl), Some(&texture_bgl)],
147 immediate_size: 0,
148 });
149
150 let pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
151 label: Some("Image Pipeline"),
152 layout: Some(&layout),
153 vertex: wgpu::VertexState {
154 module: &shader,
155 entry_point: Some("vs_main"),
156 buffers: &[ImageInstance::desc()],
157 compilation_options: Default::default(),
158 },
159 fragment: Some(wgpu::FragmentState {
160 module: &shader,
161 entry_point: Some("fs_main"),
162 targets: &[Some(wgpu::ColorTargetState {
163 format,
164 blend: Some(wgpu::BlendState::PREMULTIPLIED_ALPHA_BLENDING),
165 write_mask: wgpu::ColorWrites::ALL,
166 })],
167 compilation_options: Default::default(),
168 }),
169 primitive: wgpu::PrimitiveState::default(),
170 depth_stencil: None,
171 multisample: wgpu::MultisampleState::default(),
172 multiview_mask: None,
173 cache: None,
174 });
175
176 Self {
177 pipeline,
178 uniform_buffer,
179 uniform_bg,
180 texture_bgl,
181 }
182 }
183
184 pub fn prepare(
185 &self,
186 queue: &wgpu::Queue,
187 width: u32,
188 height: u32,
189 ) {
190 queue.write_buffer(
191 &self.uniform_buffer,
192 0,
193 bytemuck::bytes_of(&ScreenUniforms {
194 screen_size: [width as f32, height as f32],
195 _padding: [0.0; 2],
196 }),
197 );
198 }
199
200 pub fn draw<'a>(
201 &'a self,
202 pass: &mut wgpu::RenderPass<'a>,
203 texture_bind_group: &'a wgpu::BindGroup,
204 instance_buffer: &'a wgpu::Buffer,
205 instance_count: u32,
206 ) {
207 if instance_count == 0 {
208 return;
209 }
210 pass.set_pipeline(&self.pipeline);
211 pass.set_bind_group(0, &self.uniform_bg, &[]);
212 pass.set_bind_group(1, texture_bind_group, &[]);
213 pass.set_vertex_buffer(0, instance_buffer.slice(..));
214 pass.draw(0..6, 0..instance_count);
215 }
216}