1use std::sync::Arc;
2use wgpu::util::DeviceExt;
3
4use crate::upload::GpuScene;
5
6pub struct BasicSolidRenderer {
7 pipeline: wgpu::RenderPipeline,
8 bgl: wgpu::BindGroupLayout,
9 z_bgl: wgpu::BindGroupLayout,
10}
11
12impl BasicSolidRenderer {
13 pub fn new(
14 device: Arc<wgpu::Device>,
15 target_format: wgpu::TextureFormat,
16 sample_count: u32,
17 ) -> Self {
18 Self::new_with_depth_state(
19 device,
20 target_format,
21 sample_count,
22 true,
23 wgpu::CompareFunction::LessEqual,
24 )
25 }
26
27 pub fn new_with_depth_write(
28 device: Arc<wgpu::Device>,
29 target_format: wgpu::TextureFormat,
30 sample_count: u32,
31 depth_write_enabled: bool,
32 ) -> Self {
33 Self::new_with_depth_state(
34 device,
35 target_format,
36 sample_count,
37 depth_write_enabled,
38 wgpu::CompareFunction::LessEqual,
39 )
40 }
41
42 pub fn new_with_depth_state(
43 device: Arc<wgpu::Device>,
44 target_format: wgpu::TextureFormat,
45 sample_count: u32,
46 depth_write_enabled: bool,
47 depth_compare: wgpu::CompareFunction,
48 ) -> Self {
49 let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
50 label: Some("solid-shader"),
51 source: wgpu::ShaderSource::Wgsl(jag_shaders::SOLID_WGSL.into()),
52 });
53
54 let bgl = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
55 label: Some("solid-vp-bgl"),
56 entries: &[wgpu::BindGroupLayoutEntry {
57 binding: 0,
58 visibility: wgpu::ShaderStages::VERTEX,
59 ty: wgpu::BindingType::Buffer {
60 ty: wgpu::BufferBindingType::Uniform,
61 has_dynamic_offset: false,
62 min_binding_size: std::num::NonZeroU64::new(32),
63 },
64 count: None,
65 }],
66 });
67
68 let z_bgl = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
69 label: Some("solid-z-bgl"),
70 entries: &[wgpu::BindGroupLayoutEntry {
71 binding: 0,
72 visibility: wgpu::ShaderStages::VERTEX,
73 ty: wgpu::BindingType::Buffer {
74 ty: wgpu::BufferBindingType::Uniform,
75 has_dynamic_offset: false,
76 min_binding_size: std::num::NonZeroU64::new(4),
77 },
78 count: None,
79 }],
80 });
81
82 let layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
83 label: Some("solid-pipeline-layout"),
84 bind_group_layouts: &[&bgl],
85 push_constant_ranges: &[],
86 });
87
88 let pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
89 label: Some("solid-pipeline"),
90 layout: Some(&layout),
91 vertex: wgpu::VertexState {
92 module: &shader,
93 entry_point: "vs_main",
94 buffers: &[wgpu::VertexBufferLayout {
95 array_stride: std::mem::size_of::<crate::upload::Vertex>() as u64,
96 step_mode: wgpu::VertexStepMode::Vertex,
97 attributes: &[
98 wgpu::VertexAttribute {
99 offset: 0,
100 shader_location: 0,
101 format: wgpu::VertexFormat::Float32x2,
102 },
103 wgpu::VertexAttribute {
104 offset: 8,
105 shader_location: 1,
106 format: wgpu::VertexFormat::Float32x4,
107 },
108 wgpu::VertexAttribute {
109 offset: 24,
110 shader_location: 2,
111 format: wgpu::VertexFormat::Float32,
112 },
113 ],
114 }],
115 },
116 fragment: Some(wgpu::FragmentState {
117 module: &shader,
118 entry_point: "fs_main",
119 targets: &[Some(wgpu::ColorTargetState {
120 format: target_format,
121 blend: Some(wgpu::BlendState::PREMULTIPLIED_ALPHA_BLENDING),
122 write_mask: wgpu::ColorWrites::ALL,
123 })],
124 }),
125 primitive: wgpu::PrimitiveState::default(),
126 depth_stencil: Some(wgpu::DepthStencilState {
127 format: wgpu::TextureFormat::Depth32Float,
128 depth_write_enabled,
129 depth_compare,
130 stencil: wgpu::StencilState::default(),
131 bias: wgpu::DepthBiasState::default(),
132 }),
133 multisample: wgpu::MultisampleState {
134 count: sample_count,
135 ..Default::default()
136 },
137 multiview: None,
138 });
139
140 Self {
141 pipeline,
142 bgl,
143 z_bgl,
144 }
145 }
146
147 pub fn record<'a>(
148 &'a self,
149 pass: &mut wgpu::RenderPass<'a>,
150 vp_bg: &'a wgpu::BindGroup,
151 scene: &'a GpuScene,
152 ) {
153 pass.set_pipeline(&self.pipeline);
154 pass.set_bind_group(0, vp_bg, &[]);
155 pass.set_vertex_buffer(0, scene.vertex.buffer.slice(..));
156 pass.set_index_buffer(scene.index.buffer.slice(..), wgpu::IndexFormat::Uint16);
157 pass.draw_indexed(0..scene.indices, 0, 0..1);
158 }
159
160 pub fn record_index_range<'a>(
161 &'a self,
162 pass: &mut wgpu::RenderPass<'a>,
163 vp_bg: &'a wgpu::BindGroup,
164 scene: &'a GpuScene,
165 index_start: u32,
166 index_count: u32,
167 ) {
168 if index_count == 0 {
169 return;
170 }
171 pass.set_pipeline(&self.pipeline);
172 pass.set_bind_group(0, vp_bg, &[]);
173 pass.set_vertex_buffer(0, scene.vertex.buffer.slice(..));
174 pass.set_index_buffer(scene.index.buffer.slice(..), wgpu::IndexFormat::Uint16);
175 pass.draw_indexed(index_start..(index_start + index_count), 0, 0..1);
176 }
177
178 pub fn viewport_bgl(&self) -> &wgpu::BindGroupLayout {
179 &self.bgl
180 }
181
182 pub fn z_index_bgl(&self) -> &wgpu::BindGroupLayout {
183 &self.z_bgl
184 }
185}
186
187pub struct OverlaySolidRenderer {
191 pipeline: wgpu::RenderPipeline,
192 bgl: wgpu::BindGroupLayout,
193}
194
195impl OverlaySolidRenderer {
196 pub fn new(device: Arc<wgpu::Device>, target_format: wgpu::TextureFormat) -> Self {
197 let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
198 label: Some("overlay-solid-shader"),
199 source: wgpu::ShaderSource::Wgsl(jag_shaders::SOLID_WGSL.into()),
200 });
201
202 let bgl = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
203 label: Some("overlay-solid-vp-bgl"),
204 entries: &[wgpu::BindGroupLayoutEntry {
205 binding: 0,
206 visibility: wgpu::ShaderStages::VERTEX,
207 ty: wgpu::BindingType::Buffer {
208 ty: wgpu::BufferBindingType::Uniform,
209 has_dynamic_offset: false,
210 min_binding_size: std::num::NonZeroU64::new(32),
211 },
212 count: None,
213 }],
214 });
215
216 let layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
217 label: Some("overlay-solid-pipeline-layout"),
218 bind_group_layouts: &[&bgl],
219 push_constant_ranges: &[],
220 });
221
222 let pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
223 label: Some("overlay-solid-pipeline"),
224 layout: Some(&layout),
225 vertex: wgpu::VertexState {
226 module: &shader,
227 entry_point: "vs_main",
228 buffers: &[wgpu::VertexBufferLayout {
229 array_stride: std::mem::size_of::<crate::upload::Vertex>() as u64,
230 step_mode: wgpu::VertexStepMode::Vertex,
231 attributes: &[
232 wgpu::VertexAttribute {
233 offset: 0,
234 shader_location: 0,
235 format: wgpu::VertexFormat::Float32x2,
236 },
237 wgpu::VertexAttribute {
238 offset: 8,
239 shader_location: 1,
240 format: wgpu::VertexFormat::Float32x4,
241 },
242 wgpu::VertexAttribute {
243 offset: 24,
244 shader_location: 2,
245 format: wgpu::VertexFormat::Float32,
246 },
247 ],
248 }],
249 },
250 fragment: Some(wgpu::FragmentState {
251 module: &shader,
252 entry_point: "fs_main",
253 targets: &[Some(wgpu::ColorTargetState {
254 format: target_format,
255 blend: Some(wgpu::BlendState::PREMULTIPLIED_ALPHA_BLENDING),
256 write_mask: wgpu::ColorWrites::ALL,
257 })],
258 }),
259 primitive: wgpu::PrimitiveState::default(),
260 depth_stencil: None,
261 multisample: wgpu::MultisampleState::default(),
262 multiview: None,
263 });
264
265 Self { pipeline, bgl }
266 }
267
268 pub fn viewport_bgl(&self) -> &wgpu::BindGroupLayout {
269 &self.bgl
270 }
271
272 pub fn record<'a>(
273 &'a self,
274 pass: &mut wgpu::RenderPass<'a>,
275 vp_bg: &'a wgpu::BindGroup,
276 vbuf: &'a wgpu::Buffer,
277 ibuf: &'a wgpu::Buffer,
278 icount: u32,
279 ) {
280 pass.set_pipeline(&self.pipeline);
281 pass.set_bind_group(0, vp_bg, &[]);
282 pass.set_vertex_buffer(0, vbuf.slice(..));
283 pass.set_index_buffer(ibuf.slice(..), wgpu::IndexFormat::Uint16);
284 pass.draw_indexed(0..icount, 0, 0..1);
285 }
286}
287
288pub struct ScrimSolidRenderer {
295 pipeline: wgpu::RenderPipeline,
296 bgl: wgpu::BindGroupLayout,
297}
298
299impl ScrimSolidRenderer {
300 pub fn new(device: Arc<wgpu::Device>, target_format: wgpu::TextureFormat) -> Self {
301 let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
302 label: Some("scrim-solid-shader"),
303 source: wgpu::ShaderSource::Wgsl(jag_shaders::SOLID_WGSL.into()),
304 });
305
306 let bgl = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
307 label: Some("scrim-solid-vp-bgl"),
308 entries: &[wgpu::BindGroupLayoutEntry {
309 binding: 0,
310 visibility: wgpu::ShaderStages::VERTEX,
311 ty: wgpu::BindingType::Buffer {
312 ty: wgpu::BufferBindingType::Uniform,
313 has_dynamic_offset: false,
314 min_binding_size: std::num::NonZeroU64::new(32),
315 },
316 count: None,
317 }],
318 });
319
320 let layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
321 label: Some("scrim-solid-pipeline-layout"),
322 bind_group_layouts: &[&bgl],
323 push_constant_ranges: &[],
324 });
325
326 let pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
327 label: Some("scrim-solid-pipeline"),
328 layout: Some(&layout),
329 vertex: wgpu::VertexState {
330 module: &shader,
331 entry_point: "vs_main",
332 buffers: &[wgpu::VertexBufferLayout {
333 array_stride: std::mem::size_of::<crate::upload::Vertex>() as u64,
334 step_mode: wgpu::VertexStepMode::Vertex,
335 attributes: &[
336 wgpu::VertexAttribute {
337 offset: 0,
338 shader_location: 0,
339 format: wgpu::VertexFormat::Float32x2,
340 },
341 wgpu::VertexAttribute {
342 offset: 8,
343 shader_location: 1,
344 format: wgpu::VertexFormat::Float32x4,
345 },
346 wgpu::VertexAttribute {
347 offset: 24,
348 shader_location: 2,
349 format: wgpu::VertexFormat::Float32,
350 },
351 ],
352 }],
353 },
354 fragment: Some(wgpu::FragmentState {
355 module: &shader,
356 entry_point: "fs_main",
357 targets: &[Some(wgpu::ColorTargetState {
358 format: target_format,
359 blend: Some(wgpu::BlendState::PREMULTIPLIED_ALPHA_BLENDING),
360 write_mask: wgpu::ColorWrites::ALL,
361 })],
362 }),
363 primitive: wgpu::PrimitiveState::default(),
364 depth_stencil: None,
366 multisample: wgpu::MultisampleState::default(),
368 multiview: None,
369 });
370
371 Self { pipeline, bgl }
372 }
373
374 pub fn viewport_bgl(&self) -> &wgpu::BindGroupLayout {
375 &self.bgl
376 }
377
378 pub fn record<'a>(
379 &'a self,
380 pass: &mut wgpu::RenderPass<'a>,
381 vp_bg: &'a wgpu::BindGroup,
382 vbuf: &'a wgpu::Buffer,
383 ibuf: &'a wgpu::Buffer,
384 icount: u32,
385 ) {
386 pass.set_pipeline(&self.pipeline);
387 pass.set_bind_group(0, vp_bg, &[]);
388 pass.set_vertex_buffer(0, vbuf.slice(..));
389 pass.set_index_buffer(ibuf.slice(..), wgpu::IndexFormat::Uint16);
390 pass.draw_indexed(0..icount, 0, 0..1);
391 }
392}
393
394pub struct ScrimStencilMaskRenderer {
396 pipeline: wgpu::RenderPipeline,
397 bgl: wgpu::BindGroupLayout,
398}
399
400impl ScrimStencilMaskRenderer {
401 pub fn new(device: Arc<wgpu::Device>, target_format: wgpu::TextureFormat) -> Self {
402 let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
403 label: Some("scrim-stencil-mask-shader"),
404 source: wgpu::ShaderSource::Wgsl(jag_shaders::SOLID_WGSL.into()),
405 });
406
407 let bgl = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
408 label: Some("scrim-stencil-mask-vp-bgl"),
409 entries: &[wgpu::BindGroupLayoutEntry {
410 binding: 0,
411 visibility: wgpu::ShaderStages::VERTEX,
412 ty: wgpu::BindingType::Buffer {
413 ty: wgpu::BufferBindingType::Uniform,
414 has_dynamic_offset: false,
415 min_binding_size: std::num::NonZeroU64::new(32),
416 },
417 count: None,
418 }],
419 });
420
421 let layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
422 label: Some("scrim-stencil-mask-pipeline-layout"),
423 bind_group_layouts: &[&bgl],
424 push_constant_ranges: &[],
425 });
426
427 let pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
428 label: Some("scrim-stencil-mask-pipeline"),
429 layout: Some(&layout),
430 vertex: wgpu::VertexState {
431 module: &shader,
432 entry_point: "vs_main",
433 buffers: &[wgpu::VertexBufferLayout {
434 array_stride: std::mem::size_of::<crate::upload::Vertex>() as u64,
435 step_mode: wgpu::VertexStepMode::Vertex,
436 attributes: &[
437 wgpu::VertexAttribute {
438 offset: 0,
439 shader_location: 0,
440 format: wgpu::VertexFormat::Float32x2,
441 },
442 wgpu::VertexAttribute {
443 offset: 8,
444 shader_location: 1,
445 format: wgpu::VertexFormat::Float32x4,
446 },
447 wgpu::VertexAttribute {
448 offset: 24,
449 shader_location: 2,
450 format: wgpu::VertexFormat::Float32,
451 },
452 ],
453 }],
454 },
455 fragment: Some(wgpu::FragmentState {
456 module: &shader,
457 entry_point: "fs_main",
458 targets: &[Some(wgpu::ColorTargetState {
459 format: target_format,
460 blend: Some(wgpu::BlendState::REPLACE),
461 write_mask: wgpu::ColorWrites::empty(), })],
463 }),
464 primitive: wgpu::PrimitiveState::default(),
465 depth_stencil: Some(wgpu::DepthStencilState {
466 format: wgpu::TextureFormat::Depth24PlusStencil8,
467 depth_write_enabled: false,
468 depth_compare: wgpu::CompareFunction::Always,
469 stencil: wgpu::StencilState {
470 front: wgpu::StencilFaceState {
471 compare: wgpu::CompareFunction::Always,
472 fail_op: wgpu::StencilOperation::Replace,
473 depth_fail_op: wgpu::StencilOperation::Replace,
474 pass_op: wgpu::StencilOperation::Replace,
475 },
476 back: wgpu::StencilFaceState {
477 compare: wgpu::CompareFunction::Always,
478 fail_op: wgpu::StencilOperation::Replace,
479 depth_fail_op: wgpu::StencilOperation::Replace,
480 pass_op: wgpu::StencilOperation::Replace,
481 },
482 read_mask: 0xFF,
483 write_mask: 0xFF,
484 },
485 bias: wgpu::DepthBiasState::default(),
486 }),
487 multisample: wgpu::MultisampleState::default(),
488 multiview: None,
489 });
490
491 Self { pipeline, bgl }
492 }
493
494 pub fn viewport_bgl(&self) -> &wgpu::BindGroupLayout {
495 &self.bgl
496 }
497
498 pub fn record<'a>(
499 &'a self,
500 pass: &mut wgpu::RenderPass<'a>,
501 vp_bg: &'a wgpu::BindGroup,
502 vbuf: &'a wgpu::Buffer,
503 ibuf: &'a wgpu::Buffer,
504 icount: u32,
505 ) {
506 pass.set_pipeline(&self.pipeline);
507 pass.set_bind_group(0, vp_bg, &[]);
508 pass.set_vertex_buffer(0, vbuf.slice(..));
509 pass.set_index_buffer(ibuf.slice(..), wgpu::IndexFormat::Uint16);
510 pass.draw_indexed(0..icount, 0, 0..1);
511 }
512}
513
514pub struct ScrimStencilRenderer {
516 pipeline: wgpu::RenderPipeline,
517 bgl: wgpu::BindGroupLayout,
518}
519
520impl ScrimStencilRenderer {
521 pub fn new(device: Arc<wgpu::Device>, target_format: wgpu::TextureFormat) -> Self {
522 let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
523 label: Some("scrim-stencil-shader"),
524 source: wgpu::ShaderSource::Wgsl(jag_shaders::SOLID_WGSL.into()),
525 });
526
527 let bgl = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
528 label: Some("scrim-stencil-vp-bgl"),
529 entries: &[wgpu::BindGroupLayoutEntry {
530 binding: 0,
531 visibility: wgpu::ShaderStages::VERTEX,
532 ty: wgpu::BindingType::Buffer {
533 ty: wgpu::BufferBindingType::Uniform,
534 has_dynamic_offset: false,
535 min_binding_size: std::num::NonZeroU64::new(32),
536 },
537 count: None,
538 }],
539 });
540
541 let layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
542 label: Some("scrim-stencil-pipeline-layout"),
543 bind_group_layouts: &[&bgl],
544 push_constant_ranges: &[],
545 });
546
547 let pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
548 label: Some("scrim-stencil-pipeline"),
549 layout: Some(&layout),
550 vertex: wgpu::VertexState {
551 module: &shader,
552 entry_point: "vs_main",
553 buffers: &[wgpu::VertexBufferLayout {
554 array_stride: std::mem::size_of::<crate::upload::Vertex>() as u64,
555 step_mode: wgpu::VertexStepMode::Vertex,
556 attributes: &[
557 wgpu::VertexAttribute {
558 offset: 0,
559 shader_location: 0,
560 format: wgpu::VertexFormat::Float32x2,
561 },
562 wgpu::VertexAttribute {
563 offset: 8,
564 shader_location: 1,
565 format: wgpu::VertexFormat::Float32x4,
566 },
567 wgpu::VertexAttribute {
568 offset: 24,
569 shader_location: 2,
570 format: wgpu::VertexFormat::Float32,
571 },
572 ],
573 }],
574 },
575 fragment: Some(wgpu::FragmentState {
576 module: &shader,
577 entry_point: "fs_main",
578 targets: &[Some(wgpu::ColorTargetState {
579 format: target_format,
580 blend: Some(wgpu::BlendState::PREMULTIPLIED_ALPHA_BLENDING),
581 write_mask: wgpu::ColorWrites::ALL,
582 })],
583 }),
584 primitive: wgpu::PrimitiveState::default(),
585 depth_stencil: Some(wgpu::DepthStencilState {
586 format: wgpu::TextureFormat::Depth24PlusStencil8,
587 depth_write_enabled: false,
588 depth_compare: wgpu::CompareFunction::Always,
589 stencil: wgpu::StencilState {
590 front: wgpu::StencilFaceState {
591 compare: wgpu::CompareFunction::Equal,
592 fail_op: wgpu::StencilOperation::Keep,
593 depth_fail_op: wgpu::StencilOperation::Keep,
594 pass_op: wgpu::StencilOperation::Keep,
595 },
596 back: wgpu::StencilFaceState {
597 compare: wgpu::CompareFunction::Equal,
598 fail_op: wgpu::StencilOperation::Keep,
599 depth_fail_op: wgpu::StencilOperation::Keep,
600 pass_op: wgpu::StencilOperation::Keep,
601 },
602 read_mask: 0xFF,
603 write_mask: 0x00,
604 },
605 bias: wgpu::DepthBiasState::default(),
606 }),
607 multisample: wgpu::MultisampleState::default(),
608 multiview: None,
609 });
610
611 Self { pipeline, bgl }
612 }
613
614 pub fn viewport_bgl(&self) -> &wgpu::BindGroupLayout {
615 &self.bgl
616 }
617
618 pub fn record<'a>(
619 &'a self,
620 pass: &mut wgpu::RenderPass<'a>,
621 vp_bg: &'a wgpu::BindGroup,
622 vbuf: &'a wgpu::Buffer,
623 ibuf: &'a wgpu::Buffer,
624 icount: u32,
625 ) {
626 pass.set_pipeline(&self.pipeline);
627 pass.set_bind_group(0, vp_bg, &[]);
628 pass.set_vertex_buffer(0, vbuf.slice(..));
629 pass.set_index_buffer(ibuf.slice(..), wgpu::IndexFormat::Uint16);
630 pass.set_stencil_reference(0);
631 pass.draw_indexed(0..icount, 0, 0..1);
632 }
633}
634
635pub struct Compositor {
636 pipeline: wgpu::RenderPipeline,
637 bgl: wgpu::BindGroupLayout,
638 sampler: wgpu::Sampler,
639}
640
641impl Compositor {
642 pub fn new(device: Arc<wgpu::Device>, target_format: wgpu::TextureFormat) -> Self {
643 let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
644 label: Some("compositor-shader"),
645 source: wgpu::ShaderSource::Wgsl(jag_shaders::COMPOSITOR_WGSL.into()),
646 });
647
648 let bgl = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
649 label: Some("compositor-bgl"),
650 entries: &[
651 wgpu::BindGroupLayoutEntry {
652 binding: 0,
653 visibility: wgpu::ShaderStages::FRAGMENT,
654 ty: wgpu::BindingType::Texture {
655 sample_type: wgpu::TextureSampleType::Float { filterable: true },
656 view_dimension: wgpu::TextureViewDimension::D2,
657 multisampled: false,
658 },
659 count: None,
660 },
661 wgpu::BindGroupLayoutEntry {
662 binding: 1,
663 visibility: wgpu::ShaderStages::FRAGMENT,
664 ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering),
665 count: None,
666 },
667 ],
668 });
669
670 let layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
671 label: Some("compositor-pipeline-layout"),
672 bind_group_layouts: &[&bgl],
673 push_constant_ranges: &[],
674 });
675
676 let pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
677 label: Some("compositor-pipeline"),
678 layout: Some(&layout),
679 vertex: wgpu::VertexState {
680 module: &shader,
681 entry_point: "vs_main",
682 buffers: &[],
683 },
684 fragment: Some(wgpu::FragmentState {
685 module: &shader,
686 entry_point: "fs_main",
687 targets: &[Some(wgpu::ColorTargetState {
688 format: target_format,
689 blend: Some(wgpu::BlendState::REPLACE),
690 write_mask: wgpu::ColorWrites::ALL,
691 })],
692 }),
693 primitive: wgpu::PrimitiveState::default(),
694 depth_stencil: None,
695 multisample: wgpu::MultisampleState::default(),
696 multiview: None,
697 });
698
699 let sampler = device.create_sampler(&wgpu::SamplerDescriptor {
700 label: Some("compositor-sampler"),
701 mag_filter: wgpu::FilterMode::Linear,
702 min_filter: wgpu::FilterMode::Linear,
703 mipmap_filter: wgpu::FilterMode::Nearest,
704 address_mode_u: wgpu::AddressMode::ClampToEdge,
705 address_mode_v: wgpu::AddressMode::ClampToEdge,
706 address_mode_w: wgpu::AddressMode::ClampToEdge,
707 ..Default::default()
708 });
709
710 Self {
711 pipeline,
712 bgl,
713 sampler,
714 }
715 }
716
717 pub fn bind_group(
718 &self,
719 device: &wgpu::Device,
720 tex_view: &wgpu::TextureView,
721 ) -> wgpu::BindGroup {
722 device.create_bind_group(&wgpu::BindGroupDescriptor {
723 label: Some("compositor-bg"),
724 layout: &self.bgl,
725 entries: &[
726 wgpu::BindGroupEntry {
727 binding: 0,
728 resource: wgpu::BindingResource::TextureView(tex_view),
729 },
730 wgpu::BindGroupEntry {
731 binding: 1,
732 resource: wgpu::BindingResource::Sampler(&self.sampler),
733 },
734 ],
735 })
736 }
737
738 pub fn record<'a>(&'a self, pass: &mut wgpu::RenderPass<'a>, bg: &'a wgpu::BindGroup) {
739 pass.set_pipeline(&self.pipeline);
740 pass.set_bind_group(0, bg, &[]);
741 pass.draw(0..3, 0..1);
742 }
743}
744
745pub struct Blitter {
746 pipeline: wgpu::RenderPipeline,
747 bgl: wgpu::BindGroupLayout,
748 sampler: wgpu::Sampler,
749}
750
751impl Blitter {
752 pub fn new(device: Arc<wgpu::Device>, target_format: wgpu::TextureFormat) -> Self {
753 let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
754 label: Some("blit-shader"),
755 source: wgpu::ShaderSource::Wgsl(jag_shaders::BLIT_WGSL.into()),
756 });
757
758 let bgl = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
759 label: Some("blit-bgl"),
760 entries: &[
761 wgpu::BindGroupLayoutEntry {
762 binding: 0,
763 visibility: wgpu::ShaderStages::FRAGMENT,
764 ty: wgpu::BindingType::Texture {
765 sample_type: wgpu::TextureSampleType::Float { filterable: true },
766 view_dimension: wgpu::TextureViewDimension::D2,
767 multisampled: false,
768 },
769 count: None,
770 },
771 wgpu::BindGroupLayoutEntry {
772 binding: 1,
773 visibility: wgpu::ShaderStages::FRAGMENT,
774 ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering),
775 count: None,
776 },
777 ],
778 });
779
780 let layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
781 label: Some("blit-pipeline-layout"),
782 bind_group_layouts: &[&bgl],
783 push_constant_ranges: &[],
784 });
785
786 let pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
787 label: Some("blit-pipeline"),
788 layout: Some(&layout),
789 vertex: wgpu::VertexState {
790 module: &shader,
791 entry_point: "vs_main",
792 buffers: &[],
793 },
794 fragment: Some(wgpu::FragmentState {
795 module: &shader,
796 entry_point: "fs_main",
797 targets: &[Some(wgpu::ColorTargetState {
798 format: target_format,
799 blend: Some(wgpu::BlendState::REPLACE),
800 write_mask: wgpu::ColorWrites::ALL,
801 })],
802 }),
803 primitive: wgpu::PrimitiveState::default(),
804 depth_stencil: None,
805 multisample: wgpu::MultisampleState::default(),
806 multiview: None,
807 });
808
809 let sampler = device.create_sampler(&wgpu::SamplerDescriptor {
811 label: Some("blit-sampler"),
812 mag_filter: wgpu::FilterMode::Nearest,
813 min_filter: wgpu::FilterMode::Nearest,
814 mipmap_filter: wgpu::FilterMode::Nearest,
815 address_mode_u: wgpu::AddressMode::ClampToEdge,
816 address_mode_v: wgpu::AddressMode::ClampToEdge,
817 address_mode_w: wgpu::AddressMode::ClampToEdge,
818 ..Default::default()
819 });
820
821 Self {
822 pipeline,
823 bgl,
824 sampler,
825 }
826 }
827
828 pub fn bind_group(
829 &self,
830 device: &wgpu::Device,
831 tex_view: &wgpu::TextureView,
832 ) -> wgpu::BindGroup {
833 device.create_bind_group(&wgpu::BindGroupDescriptor {
834 label: Some("blit-bg"),
835 layout: &self.bgl,
836 entries: &[
837 wgpu::BindGroupEntry {
838 binding: 0,
839 resource: wgpu::BindingResource::TextureView(tex_view),
840 },
841 wgpu::BindGroupEntry {
842 binding: 1,
843 resource: wgpu::BindingResource::Sampler(&self.sampler),
844 },
845 ],
846 })
847 }
848
849 pub fn record<'a>(&'a self, pass: &mut wgpu::RenderPass<'a>, bg: &'a wgpu::BindGroup) {
850 pass.set_pipeline(&self.pipeline);
851 pass.set_bind_group(0, bg, &[]);
852 pass.draw(0..3, 0..1);
853 }
854}
855
856pub struct SmaaRenderer {
857 edge_bgl: wgpu::BindGroupLayout,
858 blend_bgl: wgpu::BindGroupLayout,
859 resolve_bgl: wgpu::BindGroupLayout,
860 edge_pipeline: wgpu::RenderPipeline,
861 blend_pipeline: wgpu::RenderPipeline,
862 resolve_pipeline: wgpu::RenderPipeline,
863 pub sampler_linear: wgpu::Sampler,
864 pub sampler_nearest: wgpu::Sampler,
865}
866
867impl SmaaRenderer {
868 pub fn new(device: Arc<wgpu::Device>, output_format: wgpu::TextureFormat) -> Self {
869 let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
870 label: Some("smaa-shader"),
871 source: wgpu::ShaderSource::Wgsl(jag_shaders::SMAA_WGSL.into()),
872 });
873
874 let edge_bgl = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
875 label: Some("smaa-edge-bgl"),
876 entries: &[
877 wgpu::BindGroupLayoutEntry {
878 binding: 0,
879 visibility: wgpu::ShaderStages::FRAGMENT,
880 ty: wgpu::BindingType::Texture {
881 sample_type: wgpu::TextureSampleType::Float { filterable: true },
882 view_dimension: wgpu::TextureViewDimension::D2,
883 multisampled: false,
884 },
885 count: None,
886 },
887 wgpu::BindGroupLayoutEntry {
888 binding: 1,
889 visibility: wgpu::ShaderStages::FRAGMENT,
890 ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering),
891 count: None,
892 },
893 wgpu::BindGroupLayoutEntry {
894 binding: 2,
895 visibility: wgpu::ShaderStages::FRAGMENT,
896 ty: wgpu::BindingType::Buffer {
897 ty: wgpu::BufferBindingType::Uniform,
898 has_dynamic_offset: false,
899 min_binding_size: std::num::NonZeroU64::new(16),
900 },
901 count: None,
902 },
903 ],
904 });
905
906 let blend_bgl = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
907 label: Some("smaa-blend-bgl"),
908 entries: &[
909 wgpu::BindGroupLayoutEntry {
910 binding: 0,
911 visibility: wgpu::ShaderStages::FRAGMENT,
912 ty: wgpu::BindingType::Texture {
913 sample_type: wgpu::TextureSampleType::Float { filterable: true },
914 view_dimension: wgpu::TextureViewDimension::D2,
915 multisampled: false,
916 },
917 count: None,
918 },
919 wgpu::BindGroupLayoutEntry {
920 binding: 1,
921 visibility: wgpu::ShaderStages::FRAGMENT,
922 ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering),
923 count: None,
924 },
925 wgpu::BindGroupLayoutEntry {
926 binding: 2,
927 visibility: wgpu::ShaderStages::FRAGMENT,
928 ty: wgpu::BindingType::Buffer {
929 ty: wgpu::BufferBindingType::Uniform,
930 has_dynamic_offset: false,
931 min_binding_size: std::num::NonZeroU64::new(16),
932 },
933 count: None,
934 },
935 ],
936 });
937
938 let resolve_bgl = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
939 label: Some("smaa-resolve-bgl"),
940 entries: &[
941 wgpu::BindGroupLayoutEntry {
942 binding: 0,
943 visibility: wgpu::ShaderStages::FRAGMENT,
944 ty: wgpu::BindingType::Texture {
945 sample_type: wgpu::TextureSampleType::Float { filterable: true },
946 view_dimension: wgpu::TextureViewDimension::D2,
947 multisampled: false,
948 },
949 count: None,
950 },
951 wgpu::BindGroupLayoutEntry {
952 binding: 1,
953 visibility: wgpu::ShaderStages::FRAGMENT,
954 ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering),
955 count: None,
956 },
957 wgpu::BindGroupLayoutEntry {
958 binding: 2,
959 visibility: wgpu::ShaderStages::FRAGMENT,
960 ty: wgpu::BindingType::Texture {
961 sample_type: wgpu::TextureSampleType::Float { filterable: true },
962 view_dimension: wgpu::TextureViewDimension::D2,
963 multisampled: false,
964 },
965 count: None,
966 },
967 wgpu::BindGroupLayoutEntry {
968 binding: 3,
969 visibility: wgpu::ShaderStages::FRAGMENT,
970 ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering),
971 count: None,
972 },
973 wgpu::BindGroupLayoutEntry {
974 binding: 4,
975 visibility: wgpu::ShaderStages::FRAGMENT,
976 ty: wgpu::BindingType::Buffer {
977 ty: wgpu::BufferBindingType::Uniform,
978 has_dynamic_offset: false,
979 min_binding_size: std::num::NonZeroU64::new(16),
980 },
981 count: None,
982 },
983 ],
984 });
985
986 let edge_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
987 label: Some("smaa-edge-layout"),
988 bind_group_layouts: &[&edge_bgl],
989 push_constant_ranges: &[],
990 });
991 let blend_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
992 label: Some("smaa-blend-layout"),
993 bind_group_layouts: &[&blend_bgl],
994 push_constant_ranges: &[],
995 });
996 let resolve_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
997 label: Some("smaa-resolve-layout"),
998 bind_group_layouts: &[&resolve_bgl],
999 push_constant_ranges: &[],
1000 });
1001
1002 let edge_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
1003 label: Some("smaa-edge-pipeline"),
1004 layout: Some(&edge_layout),
1005 vertex: wgpu::VertexState {
1006 module: &shader,
1007 entry_point: "vs_full",
1008 buffers: &[],
1009 },
1010 fragment: Some(wgpu::FragmentState {
1011 module: &shader,
1012 entry_point: "fs_edges",
1013 targets: &[Some(wgpu::ColorTargetState {
1014 format: wgpu::TextureFormat::Rgba8Unorm,
1015 blend: Some(wgpu::BlendState::REPLACE),
1016 write_mask: wgpu::ColorWrites::ALL,
1017 })],
1018 }),
1019 primitive: wgpu::PrimitiveState::default(),
1020 depth_stencil: None,
1021 multisample: wgpu::MultisampleState::default(),
1022 multiview: None,
1023 });
1024
1025 let blend_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
1026 label: Some("smaa-blend-pipeline"),
1027 layout: Some(&blend_layout),
1028 vertex: wgpu::VertexState {
1029 module: &shader,
1030 entry_point: "vs_full",
1031 buffers: &[],
1032 },
1033 fragment: Some(wgpu::FragmentState {
1034 module: &shader,
1035 entry_point: "fs_weights",
1036 targets: &[Some(wgpu::ColorTargetState {
1037 format: wgpu::TextureFormat::Rgba8Unorm,
1038 blend: Some(wgpu::BlendState::REPLACE),
1039 write_mask: wgpu::ColorWrites::ALL,
1040 })],
1041 }),
1042 primitive: wgpu::PrimitiveState::default(),
1043 depth_stencil: None,
1044 multisample: wgpu::MultisampleState::default(),
1045 multiview: None,
1046 });
1047
1048 let resolve_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
1049 label: Some("smaa-resolve-pipeline"),
1050 layout: Some(&resolve_layout),
1051 vertex: wgpu::VertexState {
1052 module: &shader,
1053 entry_point: "vs_full",
1054 buffers: &[],
1055 },
1056 fragment: Some(wgpu::FragmentState {
1057 module: &shader,
1058 entry_point: "fs_resolve",
1059 targets: &[Some(wgpu::ColorTargetState {
1060 format: output_format,
1061 blend: Some(wgpu::BlendState::REPLACE),
1062 write_mask: wgpu::ColorWrites::ALL,
1063 })],
1064 }),
1065 primitive: wgpu::PrimitiveState::default(),
1066 depth_stencil: None,
1067 multisample: wgpu::MultisampleState::default(),
1068 multiview: None,
1069 });
1070
1071 let sampler_linear = device.create_sampler(&wgpu::SamplerDescriptor {
1072 label: Some("smaa-linear-sampler"),
1073 mag_filter: wgpu::FilterMode::Linear,
1074 min_filter: wgpu::FilterMode::Linear,
1075 mipmap_filter: wgpu::FilterMode::Linear,
1076 address_mode_u: wgpu::AddressMode::ClampToEdge,
1077 address_mode_v: wgpu::AddressMode::ClampToEdge,
1078 address_mode_w: wgpu::AddressMode::ClampToEdge,
1079 ..Default::default()
1080 });
1081 let sampler_nearest = device.create_sampler(&wgpu::SamplerDescriptor {
1082 label: Some("smaa-nearest-sampler"),
1083 mag_filter: wgpu::FilterMode::Nearest,
1084 min_filter: wgpu::FilterMode::Nearest,
1085 mipmap_filter: wgpu::FilterMode::Nearest,
1086 address_mode_u: wgpu::AddressMode::ClampToEdge,
1087 address_mode_v: wgpu::AddressMode::ClampToEdge,
1088 address_mode_w: wgpu::AddressMode::ClampToEdge,
1089 ..Default::default()
1090 });
1091
1092 Self {
1093 edge_bgl,
1094 blend_bgl,
1095 resolve_bgl,
1096 edge_pipeline,
1097 blend_pipeline,
1098 resolve_pipeline,
1099 sampler_linear,
1100 sampler_nearest,
1101 }
1102 }
1103
1104 pub fn edge_bind_group(
1105 &self,
1106 device: &wgpu::Device,
1107 color_view: &wgpu::TextureView,
1108 params: &wgpu::Buffer,
1109 ) -> wgpu::BindGroup {
1110 device.create_bind_group(&wgpu::BindGroupDescriptor {
1111 label: Some("smaa-edge-bg"),
1112 layout: &self.edge_bgl,
1113 entries: &[
1114 wgpu::BindGroupEntry {
1115 binding: 0,
1116 resource: wgpu::BindingResource::TextureView(color_view),
1117 },
1118 wgpu::BindGroupEntry {
1119 binding: 1,
1120 resource: wgpu::BindingResource::Sampler(&self.sampler_nearest),
1121 },
1122 wgpu::BindGroupEntry {
1123 binding: 2,
1124 resource: params.as_entire_binding(),
1125 },
1126 ],
1127 })
1128 }
1129
1130 pub fn blend_bind_group(
1131 &self,
1132 device: &wgpu::Device,
1133 edge_view: &wgpu::TextureView,
1134 params: &wgpu::Buffer,
1135 ) -> wgpu::BindGroup {
1136 device.create_bind_group(&wgpu::BindGroupDescriptor {
1137 label: Some("smaa-blend-bg"),
1138 layout: &self.blend_bgl,
1139 entries: &[
1140 wgpu::BindGroupEntry {
1141 binding: 0,
1142 resource: wgpu::BindingResource::TextureView(edge_view),
1143 },
1144 wgpu::BindGroupEntry {
1145 binding: 1,
1146 resource: wgpu::BindingResource::Sampler(&self.sampler_nearest),
1147 },
1148 wgpu::BindGroupEntry {
1149 binding: 2,
1150 resource: params.as_entire_binding(),
1151 },
1152 ],
1153 })
1154 }
1155
1156 pub fn resolve_bind_group(
1157 &self,
1158 device: &wgpu::Device,
1159 color_view: &wgpu::TextureView,
1160 weight_view: &wgpu::TextureView,
1161 params: &wgpu::Buffer,
1162 ) -> wgpu::BindGroup {
1163 device.create_bind_group(&wgpu::BindGroupDescriptor {
1164 label: Some("smaa-resolve-bg"),
1165 layout: &self.resolve_bgl,
1166 entries: &[
1167 wgpu::BindGroupEntry {
1168 binding: 0,
1169 resource: wgpu::BindingResource::TextureView(color_view),
1170 },
1171 wgpu::BindGroupEntry {
1172 binding: 1,
1173 resource: wgpu::BindingResource::Sampler(&self.sampler_linear),
1174 },
1175 wgpu::BindGroupEntry {
1176 binding: 2,
1177 resource: wgpu::BindingResource::TextureView(weight_view),
1178 },
1179 wgpu::BindGroupEntry {
1180 binding: 3,
1181 resource: wgpu::BindingResource::Sampler(&self.sampler_linear),
1182 },
1183 wgpu::BindGroupEntry {
1184 binding: 4,
1185 resource: params.as_entire_binding(),
1186 },
1187 ],
1188 })
1189 }
1190
1191 pub fn record_edges<'a>(&'a self, pass: &mut wgpu::RenderPass<'a>, bg: &'a wgpu::BindGroup) {
1192 pass.set_pipeline(&self.edge_pipeline);
1193 pass.set_bind_group(0, bg, &[]);
1194 pass.draw(0..3, 0..1);
1195 }
1196
1197 pub fn record_blend<'a>(&'a self, pass: &mut wgpu::RenderPass<'a>, bg: &'a wgpu::BindGroup) {
1198 pass.set_pipeline(&self.blend_pipeline);
1199 pass.set_bind_group(0, bg, &[]);
1200 pass.draw(0..3, 0..1);
1201 }
1202
1203 pub fn record_resolve<'a>(&'a self, pass: &mut wgpu::RenderPass<'a>, bg: &'a wgpu::BindGroup) {
1204 pass.set_pipeline(&self.resolve_pipeline);
1205 pass.set_bind_group(0, bg, &[]);
1206 pass.draw(0..3, 0..1);
1207 }
1208}
1209
1210pub struct BackgroundRenderer {
1211 pipeline: wgpu::RenderPipeline,
1212 bgl: wgpu::BindGroupLayout,
1213}
1214
1215impl BackgroundRenderer {
1216 pub fn new(device: Arc<wgpu::Device>, target_format: wgpu::TextureFormat) -> Self {
1217 let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
1218 label: Some("background-shader"),
1219 source: wgpu::ShaderSource::Wgsl(jag_shaders::BACKGROUND_WGSL.into()),
1220 });
1221 let bgl = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
1222 label: Some("bg-bgl"),
1223 entries: &[
1224 wgpu::BindGroupLayoutEntry {
1225 binding: 0,
1226 visibility: wgpu::ShaderStages::FRAGMENT,
1227 ty: wgpu::BindingType::Buffer {
1228 ty: wgpu::BufferBindingType::Uniform,
1229 has_dynamic_offset: false,
1230 min_binding_size: std::num::NonZeroU64::new(64),
1231 },
1232 count: None,
1233 },
1234 wgpu::BindGroupLayoutEntry {
1235 binding: 1,
1236 visibility: wgpu::ShaderStages::FRAGMENT,
1237 ty: wgpu::BindingType::Buffer {
1238 ty: wgpu::BufferBindingType::Uniform,
1239 has_dynamic_offset: false,
1240 min_binding_size: std::num::NonZeroU64::new(256),
1241 },
1242 count: None,
1243 },
1244 ],
1245 });
1246 let layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
1247 label: Some("bg-pipeline-layout"),
1248 bind_group_layouts: &[&bgl],
1249 push_constant_ranges: &[],
1250 });
1251 let pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
1252 label: Some("bg-pipeline"),
1253 layout: Some(&layout),
1254 vertex: wgpu::VertexState {
1255 module: &shader,
1256 entry_point: "vs_main",
1257 buffers: &[],
1258 },
1259 fragment: Some(wgpu::FragmentState {
1260 module: &shader,
1261 entry_point: "fs_main",
1262 targets: &[Some(wgpu::ColorTargetState {
1263 format: target_format,
1264 blend: Some(wgpu::BlendState::PREMULTIPLIED_ALPHA_BLENDING),
1265 write_mask: wgpu::ColorWrites::ALL,
1266 })],
1267 }),
1268 primitive: wgpu::PrimitiveState::default(),
1269 depth_stencil: Some(wgpu::DepthStencilState {
1270 format: wgpu::TextureFormat::Depth32Float,
1271 depth_write_enabled: true,
1272 depth_compare: wgpu::CompareFunction::LessEqual,
1273 stencil: wgpu::StencilState::default(),
1274 bias: wgpu::DepthBiasState::default(),
1275 }),
1276 multisample: wgpu::MultisampleState::default(),
1277 multiview: None,
1278 });
1279 Self { pipeline, bgl }
1280 }
1281
1282 pub fn record<'a>(&'a self, pass: &mut wgpu::RenderPass<'a>, bg: &'a wgpu::BindGroup) {
1283 pass.set_pipeline(&self.pipeline);
1284 pass.set_bind_group(0, bg, &[]);
1285 pass.draw(0..3, 0..1);
1286 }
1287
1288 pub fn bgl(&self) -> &wgpu::BindGroupLayout {
1289 &self.bgl
1290 }
1291}
1292
1293pub struct BlurRenderer {
1294 pipeline: wgpu::RenderPipeline,
1295 bgl: wgpu::BindGroupLayout,
1296 sampler: wgpu::Sampler,
1297 pub param_buffer: wgpu::Buffer,
1298}
1299
1300impl BlurRenderer {
1301 pub fn new(device: Arc<wgpu::Device>, target_format: wgpu::TextureFormat) -> Self {
1302 let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
1303 label: Some("shadow-blur-shader"),
1304 source: wgpu::ShaderSource::Wgsl(jag_shaders::SHADOW_BLUR_WGSL.into()),
1305 });
1306 let bgl = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
1307 label: Some("shadow-blur-bgl"),
1308 entries: &[
1309 wgpu::BindGroupLayoutEntry {
1310 binding: 0,
1311 visibility: wgpu::ShaderStages::FRAGMENT,
1312 ty: wgpu::BindingType::Texture {
1313 sample_type: wgpu::TextureSampleType::Float { filterable: true },
1314 view_dimension: wgpu::TextureViewDimension::D2,
1315 multisampled: false,
1316 },
1317 count: None,
1318 },
1319 wgpu::BindGroupLayoutEntry {
1320 binding: 1,
1321 visibility: wgpu::ShaderStages::FRAGMENT,
1322 ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering),
1323 count: None,
1324 },
1325 wgpu::BindGroupLayoutEntry {
1326 binding: 2,
1327 visibility: wgpu::ShaderStages::FRAGMENT,
1328 ty: wgpu::BindingType::Buffer {
1329 ty: wgpu::BufferBindingType::Uniform,
1330 has_dynamic_offset: false,
1331 min_binding_size: std::num::NonZeroU64::new(32),
1332 },
1333 count: None,
1334 },
1335 ],
1336 });
1337 let layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
1338 label: Some("shadow-blur-pipeline-layout"),
1339 bind_group_layouts: &[&bgl],
1340 push_constant_ranges: &[],
1341 });
1342 let pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
1343 label: Some("shadow-blur-pipeline"),
1344 layout: Some(&layout),
1345 vertex: wgpu::VertexState {
1346 module: &shader,
1347 entry_point: "vs_main",
1348 buffers: &[],
1349 },
1350 fragment: Some(wgpu::FragmentState {
1351 module: &shader,
1352 entry_point: "fs_main",
1353 targets: &[Some(wgpu::ColorTargetState {
1354 format: target_format,
1355 blend: Some(wgpu::BlendState::REPLACE),
1356 write_mask: wgpu::ColorWrites::ALL,
1357 })],
1358 }),
1359 primitive: wgpu::PrimitiveState::default(),
1360 depth_stencil: None,
1361 multisample: wgpu::MultisampleState::default(),
1362 multiview: None,
1363 });
1364 let sampler = device.create_sampler(&wgpu::SamplerDescriptor {
1365 label: Some("shadow-blur-sampler"),
1366 mag_filter: wgpu::FilterMode::Linear,
1367 min_filter: wgpu::FilterMode::Linear,
1368 mipmap_filter: wgpu::FilterMode::Nearest,
1369 address_mode_u: wgpu::AddressMode::ClampToEdge,
1370 address_mode_v: wgpu::AddressMode::ClampToEdge,
1371 address_mode_w: wgpu::AddressMode::ClampToEdge,
1372 ..Default::default()
1373 });
1374 let param_buffer = device.create_buffer(&wgpu::BufferDescriptor {
1375 label: Some("shadow-blur-params"),
1376 size: 32, usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
1378 mapped_at_creation: false,
1379 });
1380 Self {
1381 pipeline,
1382 bgl,
1383 sampler,
1384 param_buffer,
1385 }
1386 }
1387
1388 pub fn bind_group(
1389 &self,
1390 device: &wgpu::Device,
1391 tex_view: &wgpu::TextureView,
1392 ) -> wgpu::BindGroup {
1393 device.create_bind_group(&wgpu::BindGroupDescriptor {
1394 label: Some("shadow-blur-bg"),
1395 layout: &self.bgl,
1396 entries: &[
1397 wgpu::BindGroupEntry {
1398 binding: 0,
1399 resource: wgpu::BindingResource::TextureView(tex_view),
1400 },
1401 wgpu::BindGroupEntry {
1402 binding: 1,
1403 resource: wgpu::BindingResource::Sampler(&self.sampler),
1404 },
1405 wgpu::BindGroupEntry {
1406 binding: 2,
1407 resource: self.param_buffer.as_entire_binding(),
1408 },
1409 ],
1410 })
1411 }
1412
1413 pub fn record<'a>(&'a self, pass: &mut wgpu::RenderPass<'a>, bg: &'a wgpu::BindGroup) {
1414 pass.set_pipeline(&self.pipeline);
1415 pass.set_bind_group(0, bg, &[]);
1416 pass.draw(0..3, 0..1);
1417 }
1418}
1419
1420pub struct ShadowCompositeRenderer {
1421 pipeline: wgpu::RenderPipeline,
1422 bgl: wgpu::BindGroupLayout,
1423 sampler: wgpu::Sampler,
1424 pub color_buffer: wgpu::Buffer,
1425}
1426
1427impl ShadowCompositeRenderer {
1428 pub fn new(device: Arc<wgpu::Device>, target_format: wgpu::TextureFormat) -> Self {
1429 let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
1430 label: Some("shadow-composite-shader"),
1431 source: wgpu::ShaderSource::Wgsl(jag_shaders::SHADOW_COMPOSITE_WGSL.into()),
1432 });
1433 let bgl = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
1434 label: Some("shadow-composite-bgl"),
1435 entries: &[
1436 wgpu::BindGroupLayoutEntry {
1437 binding: 0,
1438 visibility: wgpu::ShaderStages::FRAGMENT,
1439 ty: wgpu::BindingType::Texture {
1440 sample_type: wgpu::TextureSampleType::Float { filterable: true },
1441 view_dimension: wgpu::TextureViewDimension::D2,
1442 multisampled: false,
1443 },
1444 count: None,
1445 },
1446 wgpu::BindGroupLayoutEntry {
1447 binding: 1,
1448 visibility: wgpu::ShaderStages::FRAGMENT,
1449 ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering),
1450 count: None,
1451 },
1452 wgpu::BindGroupLayoutEntry {
1453 binding: 2,
1454 visibility: wgpu::ShaderStages::FRAGMENT,
1455 ty: wgpu::BindingType::Buffer {
1456 ty: wgpu::BufferBindingType::Uniform,
1457 has_dynamic_offset: false,
1458 min_binding_size: std::num::NonZeroU64::new(16),
1459 },
1460 count: None,
1461 },
1462 ],
1463 });
1464 let layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
1465 label: Some("shadow-composite-pipeline-layout"),
1466 bind_group_layouts: &[&bgl],
1467 push_constant_ranges: &[],
1468 });
1469 let pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
1470 label: Some("shadow-composite-pipeline"),
1471 layout: Some(&layout),
1472 vertex: wgpu::VertexState {
1473 module: &shader,
1474 entry_point: "vs_main",
1475 buffers: &[],
1476 },
1477 fragment: Some(wgpu::FragmentState {
1478 module: &shader,
1479 entry_point: "fs_main",
1480 targets: &[Some(wgpu::ColorTargetState {
1481 format: target_format,
1482 blend: Some(wgpu::BlendState::PREMULTIPLIED_ALPHA_BLENDING),
1483 write_mask: wgpu::ColorWrites::ALL,
1484 })],
1485 }),
1486 primitive: wgpu::PrimitiveState::default(),
1487 depth_stencil: None,
1488 multisample: wgpu::MultisampleState::default(),
1489 multiview: None,
1490 });
1491 let sampler = device.create_sampler(&wgpu::SamplerDescriptor {
1492 label: Some("shadow-composite-sampler"),
1493 mag_filter: wgpu::FilterMode::Linear,
1494 min_filter: wgpu::FilterMode::Linear,
1495 mipmap_filter: wgpu::FilterMode::Nearest,
1496 address_mode_u: wgpu::AddressMode::ClampToEdge,
1497 address_mode_v: wgpu::AddressMode::ClampToEdge,
1498 address_mode_w: wgpu::AddressMode::ClampToEdge,
1499 ..Default::default()
1500 });
1501 let color_buffer = device.create_buffer(&wgpu::BufferDescriptor {
1502 label: Some("shadow-color"),
1503 size: 16,
1504 usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
1505 mapped_at_creation: false,
1506 });
1507 Self {
1508 pipeline,
1509 bgl,
1510 sampler,
1511 color_buffer,
1512 }
1513 }
1514
1515 pub fn bind_group(
1516 &self,
1517 device: &wgpu::Device,
1518 tex_view: &wgpu::TextureView,
1519 ) -> wgpu::BindGroup {
1520 device.create_bind_group(&wgpu::BindGroupDescriptor {
1521 label: Some("shadow-composite-bg"),
1522 layout: &self.bgl,
1523 entries: &[
1524 wgpu::BindGroupEntry {
1525 binding: 0,
1526 resource: wgpu::BindingResource::TextureView(tex_view),
1527 },
1528 wgpu::BindGroupEntry {
1529 binding: 1,
1530 resource: wgpu::BindingResource::Sampler(&self.sampler),
1531 },
1532 wgpu::BindGroupEntry {
1533 binding: 2,
1534 resource: self.color_buffer.as_entire_binding(),
1535 },
1536 ],
1537 })
1538 }
1539
1540 pub fn record<'a>(&'a self, pass: &mut wgpu::RenderPass<'a>, bg: &'a wgpu::BindGroup) {
1541 pass.set_pipeline(&self.pipeline);
1542 pass.set_bind_group(0, bg, &[]);
1543 pass.draw(0..3, 0..1);
1544 }
1545}
1546
1547pub struct TextRenderer {
1548 pub pipeline: wgpu::RenderPipeline,
1549 vp_bgl: wgpu::BindGroupLayout,
1550 _z_bgl: wgpu::BindGroupLayout,
1551 pub tex_bgl: wgpu::BindGroupLayout,
1552 pub sampler: wgpu::Sampler,
1553 pub color_buffer: wgpu::Buffer,
1554}
1555
1556impl TextRenderer {
1557 pub fn new(device: Arc<wgpu::Device>, target_format: wgpu::TextureFormat) -> Self {
1558 let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
1559 label: Some("text-shader"),
1560 source: wgpu::ShaderSource::Wgsl(jag_shaders::TEXT_WGSL.into()),
1561 });
1562
1563 let vp_bgl = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
1565 label: Some("text-vp-bgl"),
1566 entries: &[wgpu::BindGroupLayoutEntry {
1567 binding: 0,
1568 visibility: wgpu::ShaderStages::VERTEX,
1569 ty: wgpu::BindingType::Buffer {
1570 ty: wgpu::BufferBindingType::Uniform,
1571 has_dynamic_offset: false,
1572 min_binding_size: std::num::NonZeroU64::new(32),
1573 },
1574 count: None,
1575 }],
1576 });
1577
1578 let z_bgl = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
1580 label: Some("text-z-bgl"),
1581 entries: &[wgpu::BindGroupLayoutEntry {
1582 binding: 0,
1583 visibility: wgpu::ShaderStages::VERTEX,
1584 ty: wgpu::BindingType::Buffer {
1585 ty: wgpu::BufferBindingType::Uniform,
1586 has_dynamic_offset: false,
1587 min_binding_size: std::num::NonZeroU64::new(4),
1588 },
1589 count: None,
1590 }],
1591 });
1592
1593 let tex_bgl = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
1595 label: Some("text-tex-bgl"),
1596 entries: &[
1597 wgpu::BindGroupLayoutEntry {
1598 binding: 0,
1599 visibility: wgpu::ShaderStages::FRAGMENT,
1600 ty: wgpu::BindingType::Texture {
1601 sample_type: wgpu::TextureSampleType::Float { filterable: true },
1602 view_dimension: wgpu::TextureViewDimension::D2,
1603 multisampled: false,
1604 },
1605 count: None,
1606 },
1607 wgpu::BindGroupLayoutEntry {
1608 binding: 1,
1609 visibility: wgpu::ShaderStages::FRAGMENT,
1610 ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering),
1611 count: None,
1612 },
1613 ],
1614 });
1615
1616 let layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
1617 label: Some("text-pipeline-layout"),
1618 bind_group_layouts: &[&vp_bgl, &z_bgl, &tex_bgl],
1619 push_constant_ranges: &[],
1620 });
1621
1622 let pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
1623 label: Some("text-pipeline"),
1624 layout: Some(&layout),
1625 vertex: wgpu::VertexState {
1626 module: &shader,
1627 entry_point: "vs_main",
1628 buffers: &[wgpu::VertexBufferLayout {
1629 array_stride: (std::mem::size_of::<f32>() * 8) as u64, step_mode: wgpu::VertexStepMode::Vertex,
1631 attributes: &[
1632 wgpu::VertexAttribute {
1633 offset: 0,
1634 shader_location: 0,
1635 format: wgpu::VertexFormat::Float32x2,
1636 },
1637 wgpu::VertexAttribute {
1638 offset: 8,
1639 shader_location: 1,
1640 format: wgpu::VertexFormat::Float32x2,
1641 },
1642 wgpu::VertexAttribute {
1643 offset: 16,
1644 shader_location: 2,
1645 format: wgpu::VertexFormat::Float32x4,
1646 },
1647 ],
1648 }],
1649 },
1650 fragment: Some(wgpu::FragmentState {
1651 module: &shader,
1652 entry_point: "fs_main",
1653 targets: &[Some(wgpu::ColorTargetState {
1654 format: target_format,
1655 blend: Some(wgpu::BlendState::PREMULTIPLIED_ALPHA_BLENDING),
1656 write_mask: wgpu::ColorWrites::ALL,
1657 })],
1658 }),
1659 primitive: wgpu::PrimitiveState::default(),
1660 depth_stencil: Some(wgpu::DepthStencilState {
1661 format: wgpu::TextureFormat::Depth32Float,
1662 depth_write_enabled: true,
1663 depth_compare: wgpu::CompareFunction::LessEqual,
1664 stencil: wgpu::StencilState::default(),
1665 bias: wgpu::DepthBiasState::default(),
1666 }),
1667 multisample: wgpu::MultisampleState::default(),
1668 multiview: None,
1669 });
1670
1671 let sampler = device.create_sampler(&wgpu::SamplerDescriptor {
1672 label: Some("text-sampler"),
1673 mag_filter: wgpu::FilterMode::Nearest,
1674 min_filter: wgpu::FilterMode::Nearest,
1675 mipmap_filter: wgpu::FilterMode::Nearest,
1676 address_mode_u: wgpu::AddressMode::ClampToEdge,
1677 address_mode_v: wgpu::AddressMode::ClampToEdge,
1678 address_mode_w: wgpu::AddressMode::ClampToEdge,
1679 ..Default::default()
1680 });
1681
1682 let color_buffer = device.create_buffer(&wgpu::BufferDescriptor {
1683 label: Some("text-color"),
1684 size: 16,
1685 usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
1686 mapped_at_creation: false,
1687 });
1688
1689 Self {
1690 pipeline,
1691 vp_bgl,
1692 _z_bgl: z_bgl,
1693 tex_bgl,
1694 sampler,
1695 color_buffer,
1696 }
1697 }
1698
1699 pub fn vp_bind_group(
1700 &self,
1701 device: &wgpu::Device,
1702 vp_buffer: &wgpu::Buffer,
1703 ) -> wgpu::BindGroup {
1704 device.create_bind_group(&wgpu::BindGroupDescriptor {
1705 label: Some("text-vp-bg"),
1706 layout: &self.vp_bgl,
1707 entries: &[wgpu::BindGroupEntry {
1708 binding: 0,
1709 resource: vp_buffer.as_entire_binding(),
1710 }],
1711 })
1712 }
1713
1714 pub fn tex_bind_group(
1715 &self,
1716 device: &wgpu::Device,
1717 tex_view: &wgpu::TextureView,
1718 ) -> wgpu::BindGroup {
1719 device.create_bind_group(&wgpu::BindGroupDescriptor {
1720 label: Some("text-tex-bg"),
1721 layout: &self.tex_bgl,
1722 entries: &[
1723 wgpu::BindGroupEntry {
1724 binding: 0,
1725 resource: wgpu::BindingResource::TextureView(tex_view),
1726 },
1727 wgpu::BindGroupEntry {
1728 binding: 1,
1729 resource: wgpu::BindingResource::Sampler(&self.sampler),
1730 },
1731 ],
1732 })
1733 }
1734
1735 pub fn record<'a>(
1736 &'a self,
1737 pass: &mut wgpu::RenderPass<'a>,
1738 vp_bg: &'a wgpu::BindGroup,
1739 z_bg: &'a wgpu::BindGroup,
1740 tex_bg: &'a wgpu::BindGroup,
1741 vbuf: &'a wgpu::Buffer,
1742 ibuf: &'a wgpu::Buffer,
1743 icount: u32,
1744 ) {
1745 pass.set_pipeline(&self.pipeline);
1746 pass.set_bind_group(0, vp_bg, &[]);
1747 pass.set_bind_group(1, z_bg, &[]);
1748 pass.set_bind_group(2, tex_bg, &[]);
1749 pass.set_vertex_buffer(0, vbuf.slice(..));
1750 pass.set_index_buffer(ibuf.slice(..), wgpu::IndexFormat::Uint16);
1751 pass.draw_indexed(0..icount, 0, 0..1);
1752 }
1753}
1754
1755pub struct ImageRenderer {
1756 pipeline: wgpu::RenderPipeline,
1757 vp_bgl: wgpu::BindGroupLayout,
1758 _z_bgl: wgpu::BindGroupLayout,
1759 tex_bgl: wgpu::BindGroupLayout,
1760 params_bgl: wgpu::BindGroupLayout,
1761 sampler: wgpu::Sampler,
1762}
1763
1764impl ImageRenderer {
1765 pub fn new(device: Arc<wgpu::Device>, target_format: wgpu::TextureFormat) -> Self {
1766 let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
1767 label: Some("image-shader"),
1768 source: wgpu::ShaderSource::Wgsl(jag_shaders::IMAGE_WGSL.into()),
1769 });
1770
1771 let disable_depth = std::env::var("JAG_IMAGE_NO_DEPTH")
1775 .ok()
1776 .map(|v| v == "1" || v.eq_ignore_ascii_case("true"))
1777 .unwrap_or(false);
1778
1779 let vp_bgl = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
1781 label: Some("image-vp-bgl"),
1782 entries: &[wgpu::BindGroupLayoutEntry {
1783 binding: 0,
1784 visibility: wgpu::ShaderStages::VERTEX,
1785 ty: wgpu::BindingType::Buffer {
1786 ty: wgpu::BufferBindingType::Uniform,
1787 has_dynamic_offset: false,
1788 min_binding_size: std::num::NonZeroU64::new(32),
1789 },
1790 count: None,
1791 }],
1792 });
1793
1794 let z_bgl = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
1796 label: Some("image-z-bgl"),
1797 entries: &[wgpu::BindGroupLayoutEntry {
1798 binding: 0,
1799 visibility: wgpu::ShaderStages::VERTEX,
1800 ty: wgpu::BindingType::Buffer {
1801 ty: wgpu::BufferBindingType::Uniform,
1802 has_dynamic_offset: false,
1803 min_binding_size: std::num::NonZeroU64::new(4),
1804 },
1805 count: None,
1806 }],
1807 });
1808
1809 let tex_bgl = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
1811 label: Some("image-tex-bgl"),
1812 entries: &[
1813 wgpu::BindGroupLayoutEntry {
1814 binding: 0,
1815 visibility: wgpu::ShaderStages::FRAGMENT,
1816 ty: wgpu::BindingType::Texture {
1817 sample_type: wgpu::TextureSampleType::Float { filterable: true },
1818 view_dimension: wgpu::TextureViewDimension::D2,
1819 multisampled: false,
1820 },
1821 count: None,
1822 },
1823 wgpu::BindGroupLayoutEntry {
1824 binding: 1,
1825 visibility: wgpu::ShaderStages::FRAGMENT,
1826 ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering),
1827 count: None,
1828 },
1829 ],
1830 });
1831
1832 let params_bgl = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
1835 label: Some("image-params-bgl"),
1836 entries: &[wgpu::BindGroupLayoutEntry {
1837 binding: 0,
1838 visibility: wgpu::ShaderStages::FRAGMENT,
1839 ty: wgpu::BindingType::Buffer {
1840 ty: wgpu::BufferBindingType::Uniform,
1841 has_dynamic_offset: false,
1842 min_binding_size: std::num::NonZeroU64::new(16),
1843 },
1844 count: None,
1845 }],
1846 });
1847
1848 let layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
1849 label: Some("image-pipeline-layout"),
1850 bind_group_layouts: &[&vp_bgl, &z_bgl, &tex_bgl, ¶ms_bgl],
1851 push_constant_ranges: &[],
1852 });
1853
1854 let depth_stencil = if disable_depth {
1855 None
1856 } else {
1857 Some(wgpu::DepthStencilState {
1858 format: wgpu::TextureFormat::Depth32Float,
1859 depth_write_enabled: true,
1860 depth_compare: wgpu::CompareFunction::LessEqual,
1861 stencil: wgpu::StencilState::default(),
1862 bias: wgpu::DepthBiasState::default(),
1863 })
1864 };
1865
1866 let pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
1867 label: Some("image-pipeline"),
1868 layout: Some(&layout),
1869 vertex: wgpu::VertexState {
1870 module: &shader,
1871 entry_point: "vs_main",
1872 buffers: &[wgpu::VertexBufferLayout {
1873 array_stride: (std::mem::size_of::<f32>() * 4) as u64,
1874 step_mode: wgpu::VertexStepMode::Vertex,
1875 attributes: &[
1876 wgpu::VertexAttribute {
1877 offset: 0,
1878 shader_location: 0,
1879 format: wgpu::VertexFormat::Float32x2,
1880 },
1881 wgpu::VertexAttribute {
1882 offset: 8,
1883 shader_location: 1,
1884 format: wgpu::VertexFormat::Float32x2,
1885 },
1886 ],
1887 }],
1888 },
1889 fragment: Some(wgpu::FragmentState {
1890 module: &shader,
1891 entry_point: "fs_main",
1892 targets: &[Some(wgpu::ColorTargetState {
1893 format: target_format,
1894 blend: Some(wgpu::BlendState::PREMULTIPLIED_ALPHA_BLENDING),
1895 write_mask: wgpu::ColorWrites::ALL,
1896 })],
1897 }),
1898 primitive: wgpu::PrimitiveState::default(),
1899 depth_stencil,
1900 multisample: wgpu::MultisampleState::default(),
1901 multiview: None,
1902 });
1903
1904 let sampler = device.create_sampler(&wgpu::SamplerDescriptor {
1905 label: Some("image-sampler"),
1906 mag_filter: wgpu::FilterMode::Linear,
1907 min_filter: wgpu::FilterMode::Linear,
1908 mipmap_filter: wgpu::FilterMode::Nearest,
1909 address_mode_u: wgpu::AddressMode::ClampToEdge,
1910 address_mode_v: wgpu::AddressMode::ClampToEdge,
1911 address_mode_w: wgpu::AddressMode::ClampToEdge,
1912 ..Default::default()
1913 });
1914
1915 Self {
1916 pipeline,
1917 vp_bgl,
1918 _z_bgl: z_bgl,
1919 tex_bgl,
1920 params_bgl,
1921 sampler,
1922 }
1923 }
1924
1925 pub fn vp_bind_group(
1926 &self,
1927 device: &wgpu::Device,
1928 vp_buffer: &wgpu::Buffer,
1929 ) -> wgpu::BindGroup {
1930 device.create_bind_group(&wgpu::BindGroupDescriptor {
1931 label: Some("image-vp-bg"),
1932 layout: &self.vp_bgl,
1933 entries: &[wgpu::BindGroupEntry {
1934 binding: 0,
1935 resource: vp_buffer.as_entire_binding(),
1936 }],
1937 })
1938 }
1939
1940 pub fn tex_bind_group(
1941 &self,
1942 device: &wgpu::Device,
1943 tex_view: &wgpu::TextureView,
1944 ) -> wgpu::BindGroup {
1945 device.create_bind_group(&wgpu::BindGroupDescriptor {
1946 label: Some("image-tex-bg"),
1947 layout: &self.tex_bgl,
1948 entries: &[
1949 wgpu::BindGroupEntry {
1950 binding: 0,
1951 resource: wgpu::BindingResource::TextureView(tex_view),
1952 },
1953 wgpu::BindGroupEntry {
1954 binding: 1,
1955 resource: wgpu::BindingResource::Sampler(&self.sampler),
1956 },
1957 ],
1958 })
1959 }
1960
1961 pub fn params_bind_group(
1962 &self,
1963 device: &wgpu::Device,
1964 opacity: f32,
1965 premultiplied_input: bool,
1966 ) -> (wgpu::BindGroup, wgpu::Buffer) {
1967 let params: [f32; 4] = [
1968 opacity.clamp(0.0, 1.0),
1969 if premultiplied_input { 1.0 } else { 0.0 },
1970 0.0,
1971 0.0,
1972 ];
1973 let buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
1974 label: Some("image-params-buffer"),
1975 contents: bytemuck::cast_slice(¶ms),
1976 usage: wgpu::BufferUsages::UNIFORM,
1977 });
1978 let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
1979 label: Some("image-params-bg"),
1980 layout: &self.params_bgl,
1981 entries: &[wgpu::BindGroupEntry {
1982 binding: 0,
1983 resource: buffer.as_entire_binding(),
1984 }],
1985 });
1986 (bind_group, buffer)
1987 }
1988
1989 pub fn record<'a>(
1990 &'a self,
1991 pass: &mut wgpu::RenderPass<'a>,
1992 vp_bg: &'a wgpu::BindGroup,
1993 z_bg: &'a wgpu::BindGroup,
1994 tex_bg: &'a wgpu::BindGroup,
1995 params_bg: &'a wgpu::BindGroup,
1996 vbuf: &'a wgpu::Buffer,
1997 ibuf: &'a wgpu::Buffer,
1998 icount: u32,
1999 ) {
2000 pass.set_pipeline(&self.pipeline);
2001 pass.set_bind_group(0, vp_bg, &[]);
2002 pass.set_bind_group(1, z_bg, &[]);
2003 pass.set_bind_group(2, tex_bg, &[]);
2004 pass.set_bind_group(3, params_bg, &[]);
2005 pass.set_vertex_buffer(0, vbuf.slice(..));
2006 pass.set_index_buffer(ibuf.slice(..), wgpu::IndexFormat::Uint16);
2007 pass.draw_indexed(0..icount, 0, 0..1);
2008 }
2009}