1use onedrop_codegen::{ShaderUniforms, USER_TEXTURE_FIRST_BINDING, USER_TEXTURE_SLOTS};
39use wgpu::util::DeviceExt;
40
41use crate::comp_pipeline::{
42 PREV_MAIN_BINDING, build_user_shader_bind_group_layout, make_fallback_user_texture_view,
43 make_md2_sampler,
44};
45use crate::error::Result;
46use crate::warp_pipeline::WarpVertex;
47
48pub struct WarpAuxViews<'a> {
55 pub prev_blur1: &'a wgpu::TextureView,
56 pub prev_blur2: &'a wgpu::TextureView,
57 pub prev_blur3: &'a wgpu::TextureView,
58 pub noise_lq: &'a wgpu::TextureView,
59 pub noise_mq: &'a wgpu::TextureView,
60 pub noise_hq: &'a wgpu::TextureView,
61 pub noisevol_lq: &'a wgpu::TextureView,
62 pub noisevol_hq: &'a wgpu::TextureView,
63}
64
65pub struct UserWarpPipeline {
70 pipeline: wgpu::RenderPipeline,
71 bind_group: wgpu::BindGroup,
72 bind_group_layout: wgpu::BindGroupLayout,
73 #[allow(dead_code)]
77 pipeline_layout: wgpu::PipelineLayout,
78 uniforms_buffer: wgpu::Buffer,
79 sampler: wgpu::Sampler,
81 sampler_fw: wgpu::Sampler,
85 sampler_fc: wgpu::Sampler,
86 sampler_pw: wgpu::Sampler,
87 sampler_pc: wgpu::Sampler,
88 #[allow(dead_code)]
93 fallback_user_view: wgpu::TextureView,
94 user_texture_views: [wgpu::TextureView; USER_TEXTURE_SLOTS],
97}
98
99impl UserWarpPipeline {
100 pub fn new(
110 device: &wgpu::Device,
111 queue: &wgpu::Queue,
112 target_format: wgpu::TextureFormat,
113 wrapped_wgsl: &str,
114 prev_view: &wgpu::TextureView,
115 aux: &WarpAuxViews,
116 user_views: [Option<wgpu::TextureView>; USER_TEXTURE_SLOTS],
117 ) -> Result<Self> {
118 let sampler = device.create_sampler(&wgpu::SamplerDescriptor {
119 label: Some("User Warp Sampler Main"),
120 address_mode_u: wgpu::AddressMode::ClampToEdge,
121 address_mode_v: wgpu::AddressMode::ClampToEdge,
122 address_mode_w: wgpu::AddressMode::ClampToEdge,
123 mag_filter: wgpu::FilterMode::Linear,
124 min_filter: wgpu::FilterMode::Linear,
125 mipmap_filter: wgpu::MipmapFilterMode::Linear,
126 ..Default::default()
127 });
128 let sampler_fw = make_md2_sampler(device, "User Warp Sampler FW", true, true);
129 let sampler_fc = make_md2_sampler(device, "User Warp Sampler FC", true, false);
130 let sampler_pw = make_md2_sampler(device, "User Warp Sampler PW", false, true);
131 let sampler_pc = make_md2_sampler(device, "User Warp Sampler PC", false, false);
132
133 let fallback_user_view = make_fallback_user_texture_view(device, queue);
134 let user_texture_views: [wgpu::TextureView; USER_TEXTURE_SLOTS] = {
135 let mut arr = std::array::from_fn(|_| fallback_user_view.clone());
136 for (slot, opt) in user_views.into_iter().enumerate() {
137 if let Some(v) = opt {
138 arr[slot] = v;
139 }
140 }
141 arr
142 };
143
144 let initial = ShaderUniforms::default();
145 let uniforms_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
146 label: Some("User Warp ShaderUniforms"),
147 contents: bytemuck::bytes_of(&initial),
148 usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
149 });
150
151 let bind_group_layout =
152 build_user_shader_bind_group_layout(device, "User Warp Bind Group Layout");
153 let user_view_refs: [&wgpu::TextureView; USER_TEXTURE_SLOTS] =
154 std::array::from_fn(|i| &user_texture_views[i]);
155 let bind_group = create_user_warp_bind_group(
156 device,
157 &bind_group_layout,
158 &uniforms_buffer,
159 prev_view,
160 &sampler,
161 aux,
162 &sampler_fw,
163 &sampler_fc,
164 &sampler_pw,
165 &sampler_pc,
166 &user_view_refs,
167 );
168
169 let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
170 label: Some("User Warp Pipeline Layout"),
171 bind_group_layouts: &[Some(&bind_group_layout)],
172 immediate_size: 0,
173 });
174
175 let pipeline =
176 build_warp_pipeline_from_wgsl(device, &pipeline_layout, target_format, wrapped_wgsl)?;
177
178 Ok(Self {
179 pipeline,
180 bind_group,
181 bind_group_layout,
182 pipeline_layout,
183 uniforms_buffer,
184 sampler,
185 sampler_fw,
186 sampler_fc,
187 sampler_pw,
188 sampler_pc,
189 fallback_user_view,
190 user_texture_views,
191 })
192 }
193
194 pub fn update_uniforms(&self, queue: &wgpu::Queue, uniforms: &ShaderUniforms) {
196 queue.write_buffer(&self.uniforms_buffer, 0, bytemuck::bytes_of(uniforms));
197 }
198
199 pub fn rebind_textures(
203 &mut self,
204 device: &wgpu::Device,
205 prev_view: &wgpu::TextureView,
206 aux: &WarpAuxViews,
207 ) {
208 let user_view_refs: [&wgpu::TextureView; USER_TEXTURE_SLOTS] =
209 std::array::from_fn(|i| &self.user_texture_views[i]);
210 self.bind_group = create_user_warp_bind_group(
211 device,
212 &self.bind_group_layout,
213 &self.uniforms_buffer,
214 prev_view,
215 &self.sampler,
216 aux,
217 &self.sampler_fw,
218 &self.sampler_fc,
219 &self.sampler_pw,
220 &self.sampler_pc,
221 &user_view_refs,
222 );
223 }
224
225 #[allow(clippy::too_many_arguments)]
229 pub fn render(
230 &self,
231 encoder: &mut wgpu::CommandEncoder,
232 output_view: &wgpu::TextureView,
233 vertex_buffer: &wgpu::Buffer,
234 index_buffer: &wgpu::Buffer,
235 index_count: u32,
236 ) {
237 let mut pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
238 label: Some("User Warp Render Pass"),
239 color_attachments: &[Some(wgpu::RenderPassColorAttachment {
240 view: output_view,
241 depth_slice: None,
242 resolve_target: None,
243 ops: wgpu::Operations {
244 load: wgpu::LoadOp::Clear(wgpu::Color::BLACK),
245 store: wgpu::StoreOp::Store,
246 },
247 })],
248 depth_stencil_attachment: None,
249 timestamp_writes: None,
250 occlusion_query_set: None,
251 multiview_mask: None,
252 });
253 pass.set_pipeline(&self.pipeline);
254 pass.set_bind_group(0, &self.bind_group, &[]);
255 pass.set_vertex_buffer(0, vertex_buffer.slice(..));
256 pass.set_index_buffer(index_buffer.slice(..), wgpu::IndexFormat::Uint32);
257 pass.draw_indexed(0..index_count, 0, 0..1);
258 }
259}
260
261#[allow(clippy::too_many_arguments)]
268fn create_user_warp_bind_group(
269 device: &wgpu::Device,
270 layout: &wgpu::BindGroupLayout,
271 uniforms_buffer: &wgpu::Buffer,
272 prev_view: &wgpu::TextureView,
273 sampler: &wgpu::Sampler,
274 aux: &WarpAuxViews,
275 sampler_fw: &wgpu::Sampler,
276 sampler_fc: &wgpu::Sampler,
277 sampler_pw: &wgpu::Sampler,
278 sampler_pc: &wgpu::Sampler,
279 user_textures: &[&wgpu::TextureView; USER_TEXTURE_SLOTS],
280) -> wgpu::BindGroup {
281 let mut entries: Vec<wgpu::BindGroupEntry> = vec![
282 wgpu::BindGroupEntry {
283 binding: 0,
284 resource: uniforms_buffer.as_entire_binding(),
285 },
286 wgpu::BindGroupEntry {
287 binding: 1,
288 resource: wgpu::BindingResource::TextureView(prev_view),
289 },
290 wgpu::BindGroupEntry {
291 binding: 2,
292 resource: wgpu::BindingResource::Sampler(sampler),
293 },
294 wgpu::BindGroupEntry {
296 binding: 3,
297 resource: wgpu::BindingResource::TextureView(aux.prev_blur1),
298 },
299 wgpu::BindGroupEntry {
300 binding: 4,
301 resource: wgpu::BindingResource::TextureView(aux.prev_blur2),
302 },
303 wgpu::BindGroupEntry {
304 binding: 5,
305 resource: wgpu::BindingResource::TextureView(aux.prev_blur3),
306 },
307 wgpu::BindGroupEntry {
309 binding: 6,
310 resource: wgpu::BindingResource::TextureView(aux.noise_lq),
311 },
312 wgpu::BindGroupEntry {
313 binding: 7,
314 resource: wgpu::BindingResource::TextureView(aux.noise_mq),
315 },
316 wgpu::BindGroupEntry {
317 binding: 8,
318 resource: wgpu::BindingResource::TextureView(aux.noise_hq),
319 },
320 wgpu::BindGroupEntry {
321 binding: 9,
322 resource: wgpu::BindingResource::TextureView(aux.noisevol_lq),
323 },
324 wgpu::BindGroupEntry {
325 binding: 10,
326 resource: wgpu::BindingResource::TextureView(aux.noisevol_hq),
327 },
328 wgpu::BindGroupEntry {
330 binding: 11,
331 resource: wgpu::BindingResource::Sampler(sampler_fw),
332 },
333 wgpu::BindGroupEntry {
334 binding: 12,
335 resource: wgpu::BindingResource::Sampler(sampler_fc),
336 },
337 wgpu::BindGroupEntry {
338 binding: 13,
339 resource: wgpu::BindingResource::Sampler(sampler_pw),
340 },
341 wgpu::BindGroupEntry {
342 binding: 14,
343 resource: wgpu::BindingResource::Sampler(sampler_pc),
344 },
345 ];
346 for (n, view) in user_textures.iter().enumerate() {
347 entries.push(wgpu::BindGroupEntry {
348 binding: USER_TEXTURE_FIRST_BINDING + n as u32,
349 resource: wgpu::BindingResource::TextureView(view),
350 });
351 }
352 entries.push(wgpu::BindGroupEntry {
353 binding: PREV_MAIN_BINDING,
354 resource: wgpu::BindingResource::TextureView(prev_view),
355 });
356 device.create_bind_group(&wgpu::BindGroupDescriptor {
357 label: Some("User Warp Bind Group"),
358 layout,
359 entries: &entries,
360 })
361}
362
363fn build_warp_pipeline_from_wgsl(
368 device: &wgpu::Device,
369 pipeline_layout: &wgpu::PipelineLayout,
370 target_format: wgpu::TextureFormat,
371 source: &str,
372) -> Result<wgpu::RenderPipeline> {
373 let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
374 label: Some("User Warp Shader"),
375 source: wgpu::ShaderSource::Wgsl(source.into()),
376 });
377 Ok(
378 device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
379 label: Some("User Warp Pipeline"),
380 layout: Some(pipeline_layout),
381 vertex: wgpu::VertexState {
382 module: &shader,
383 entry_point: Some("vs_main"),
384 buffers: &[wgpu::VertexBufferLayout {
385 array_stride: std::mem::size_of::<WarpVertex>() as wgpu::BufferAddress,
386 step_mode: wgpu::VertexStepMode::Vertex,
387 attributes: &[
388 wgpu::VertexAttribute {
389 offset: 0,
390 shader_location: 0,
391 format: wgpu::VertexFormat::Float32x2,
392 },
393 wgpu::VertexAttribute {
394 offset: std::mem::size_of::<[f32; 2]>() as wgpu::BufferAddress,
395 shader_location: 1,
396 format: wgpu::VertexFormat::Float32x2,
397 },
398 ],
399 }],
400 compilation_options: Default::default(),
401 },
402 fragment: Some(wgpu::FragmentState {
403 module: &shader,
404 entry_point: Some("fs_main"),
405 targets: &[Some(wgpu::ColorTargetState {
406 format: target_format,
407 blend: Some(wgpu::BlendState::REPLACE),
408 write_mask: wgpu::ColorWrites::ALL,
409 })],
410 compilation_options: Default::default(),
411 }),
412 primitive: wgpu::PrimitiveState {
413 topology: wgpu::PrimitiveTopology::TriangleList,
414 ..Default::default()
415 },
416 depth_stencil: None,
417 multisample: wgpu::MultisampleState::default(),
418 multiview_mask: None,
419 cache: None,
420 }),
421 )
422}