1use crate::color::sRGB32;
5use crate::graphics::{Driver, Vec2f};
6use crate::render::atlas::PxBox;
7use crate::{PxDim, PxPoint, PxRect, PxVector, RelDim, SourceID};
8use derive_where::derive_where;
9use num_traits::Zero;
10use smallvec::SmallVec;
11use std::collections::HashMap;
12use std::num::NonZero;
13use std::sync::Arc;
14use wgpu::wgt::SamplerDescriptor;
15use wgpu::{
16 BindGroupEntry, BindGroupLayoutEntry, Buffer, BufferDescriptor, BufferUsages, TextureView,
17};
18
19use parking_lot::RwLock;
20
21use super::atlas::Atlas;
22
23#[derive(Debug)]
24pub struct Shared {
26 layout: wgpu::PipelineLayout,
27 shader: wgpu::ShaderModule,
28 sampler: wgpu::Sampler,
29 pipelines: RwLock<HashMap<wgpu::TextureFormat, wgpu::RenderPipeline>>,
30 layers: RwLock<HashMap<Arc<SourceID>, Layer>>,
31}
32
33pub const TARGET_BLEND: wgpu::ColorTargetState = wgpu::ColorTargetState {
34 format: crate::render::atlas::ATLAS_FORMAT,
35 blend: Some(wgpu::BlendState::REPLACE),
36 write_mask: wgpu::ColorWrites::ALL,
37};
38
39impl Shared {
40 pub fn new(device: &wgpu::Device) -> Self {
41 let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
42 label: Some("Compositor"),
43 source: wgpu::ShaderSource::Wgsl(include_str!("../shaders/compositor.wgsl").into()),
44 });
45
46 let bind_group_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
47 label: Some("Compositor Bind Group"),
48 entries: &[
49 BindGroupLayoutEntry {
50 binding: 0,
51 visibility: wgpu::ShaderStages::VERTEX,
52 ty: wgpu::BindingType::Buffer {
53 ty: wgpu::BufferBindingType::Uniform,
54 has_dynamic_offset: false,
55 min_binding_size: NonZero::new(size_of::<crate::Mat4x4>() as u64),
56 },
57 count: None,
58 },
59 BindGroupLayoutEntry {
60 binding: 1,
61 visibility: wgpu::ShaderStages::VERTEX | wgpu::ShaderStages::FRAGMENT,
62 ty: wgpu::BindingType::Buffer {
63 ty: wgpu::BufferBindingType::Storage { read_only: true },
64 has_dynamic_offset: true,
65 min_binding_size: None,
66 },
67 count: None,
68 },
69 BindGroupLayoutEntry {
70 binding: 2,
71 visibility: wgpu::ShaderStages::FRAGMENT,
72 ty: wgpu::BindingType::Buffer {
73 ty: wgpu::BufferBindingType::Storage { read_only: true },
74 has_dynamic_offset: false,
75 min_binding_size: None,
76 },
77 count: None,
78 },
79 BindGroupLayoutEntry {
80 binding: 3,
81 visibility: wgpu::ShaderStages::FRAGMENT,
82 ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering),
83 count: None,
84 },
85 BindGroupLayoutEntry {
86 binding: 4,
87 visibility: wgpu::ShaderStages::VERTEX | wgpu::ShaderStages::FRAGMENT,
88 ty: wgpu::BindingType::Texture {
89 multisampled: false,
90 view_dimension: wgpu::TextureViewDimension::D2Array,
91 sample_type: wgpu::TextureSampleType::Float { filterable: true },
92 },
93 count: None,
94 },
95 BindGroupLayoutEntry {
96 binding: 5,
97 visibility: wgpu::ShaderStages::VERTEX | wgpu::ShaderStages::FRAGMENT,
98 ty: wgpu::BindingType::Texture {
99 multisampled: false,
100 view_dimension: wgpu::TextureViewDimension::D2Array,
101 sample_type: wgpu::TextureSampleType::Float { filterable: true },
102 },
103 count: None,
104 },
105 ],
106 });
107
108 let layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
109 label: Some("Compositor Pipeline"),
110 bind_group_layouts: &[&bind_group_layout],
111 push_constant_ranges: &[],
112 });
113
114 let sampler = device.create_sampler(&SamplerDescriptor {
115 label: Some("Compositor Sampler"),
116 address_mode_u: wgpu::AddressMode::ClampToEdge,
117 address_mode_v: wgpu::AddressMode::ClampToEdge,
118 address_mode_w: wgpu::AddressMode::ClampToEdge,
119 mag_filter: wgpu::FilterMode::Linear,
120 min_filter: wgpu::FilterMode::Linear,
121 mipmap_filter: wgpu::FilterMode::Linear,
122 border_color: Some(wgpu::SamplerBorderColor::TransparentBlack),
123 ..Default::default()
124 });
125
126 Self {
127 layout,
128 shader,
129 sampler,
130 pipelines: HashMap::new().into(),
131 layers: HashMap::new().into(),
132 }
133 }
134
135 pub fn access_layers(
136 &self,
137 ) -> parking_lot::lock_api::RwLockReadGuard<
138 '_,
139 parking_lot::RawRwLock,
140 HashMap<Arc<SourceID>, Layer>,
141 > {
142 self.layers.read()
143 }
144
145 fn get_pipeline(
146 &self,
147 device: &wgpu::Device,
148 format: wgpu::TextureFormat,
149 ) -> wgpu::RenderPipeline {
150 self.pipelines
151 .write()
152 .entry(format)
153 .or_insert_with(|| {
154 device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
155 label: None,
156 layout: Some(&self.layout),
157 vertex: wgpu::VertexState {
158 module: &self.shader,
159 entry_point: Some("vs_main"),
160 buffers: &[],
161 compilation_options: Default::default(),
162 },
163 fragment: Some(wgpu::FragmentState {
164 module: &self.shader,
165 entry_point: Some("fs_main"),
166 compilation_options: Default::default(),
167 targets: &[Some(wgpu::ColorTargetState {
168 format,
169 blend: Some(wgpu::BlendState::PREMULTIPLIED_ALPHA_BLENDING),
170 write_mask: wgpu::ColorWrites::ALL,
171 })],
172 }),
173 primitive: wgpu::PrimitiveState {
174 front_face: wgpu::FrontFace::Cw,
175 topology: wgpu::PrimitiveTopology::TriangleList,
176 ..Default::default()
177 },
178 depth_stencil: None,
179 multisample: wgpu::MultisampleState::default(),
180 multiview: None,
181 cache: None,
182 })
183 })
184 .clone()
185 }
186
187 pub fn create_layer(
188 &self,
189 _device: &wgpu::Device,
190 id: Arc<SourceID>,
191 mut area: PxRect,
192 dest: Option<PxRect>,
193 color: sRGB32,
194 rotation: f32,
195 force: bool,
196 ) -> Option<Layer> {
197 let array = area.v.as_array_mut();
201 array[0] = array[0].floor();
202 array[1] = array[1].floor();
203 array[2] = array[2].ceil();
204 array[3] = array[3].ceil();
205
206 let dest = dest.unwrap_or(area);
207
208 let target = if color == sRGB32::white() && rotation.is_zero() && !force && dest == area {
210 None
211 } else {
212 Some(RwLock::new(LayerTarget {
213 dependents: Default::default(),
214 }))
215 };
216
217 let layer = Layer {
218 area,
219 dest,
220 color,
221 rotation,
222 target,
223 };
224
225 if let Some(prev) = self.layers.read().get(&id)
226 && *prev == layer
227 {
228 return None;
229 }
230
231 self.layers.write().insert(id, layer)
232 }
233}
234
235#[derive(Debug)]
238pub struct LayerTarget {
239 pub dependents: Vec<std::sync::Weak<SourceID>>, }
242
243#[derive(Debug)]
244pub struct Layer {
245 pub area: PxRect,
248 dest: PxRect,
251 color: sRGB32,
252 rotation: f32,
253 pub target: Option<RwLock<LayerTarget>>,
255}
256
257impl PartialEq for Layer {
258 fn eq(&self, other: &Self) -> bool {
259 self.area == other.area
260 && self.dest == other.dest
261 && self.color == other.color
262 && self.rotation == other.rotation
263 }
264}
265
266type DeferFn = dyn FnOnce(&Driver, &mut Data) + Send + Sync;
267type CustomDrawFn = dyn FnMut(&Driver, &mut wgpu::RenderPass<'_>, PxVector) + Send + Sync;
268
269#[derive(Debug)]
289pub struct Compositor {
290 pipeline: wgpu::RenderPipeline,
291 mvp: Buffer,
292 clip: Buffer,
293 clipdata: Vec<PxRect>, pub(crate) segments: SmallVec<[HashMap<u8, Segment>; 1]>,
295 view: std::sync::Weak<TextureView>,
296 layer_view: std::sync::Weak<TextureView>,
297 layer: bool, }
299
300#[derive_where(Debug)]
308pub struct Segment {
309 group: wgpu::BindGroup,
310 buffer: Buffer,
311 data: Vec<Data>,
312 regions: Vec<std::ops::Range<u32>>,
313 #[derive_where(skip)]
314 defer: HashMap<u32, (Box<DeferFn>, PxRect, PxVector)>,
315 #[derive_where(skip)]
316 custom: Vec<(u32, Box<CustomDrawFn>, PxVector)>,
317}
318
319impl Compositor {
320 fn reserve(&mut self, driver: &Driver, pass: u8, slice: u8) {
321 self.segments.resize_with(pass as usize + 1, HashMap::new);
322 self.segments[pass as usize]
323 .entry(slice)
324 .or_insert_with(|| {
325 let buffer = driver.device.create_buffer(&BufferDescriptor {
326 label: Some("Compositor Data"),
327 size: 32 * size_of::<Data>() as u64,
328 usage: BufferUsages::STORAGE | BufferUsages::COPY_DST,
329 mapped_at_creation: false,
330 });
331
332 let group = Self::gen_binding(
333 &self.mvp,
334 &buffer,
335 &self.clip,
336 &driver.shared,
337 &driver.device,
338 &driver.atlas.read().view,
339 &driver.layer_atlas[self.layer as usize].read().view,
340 &self.pipeline.get_bind_group_layout(0),
341 );
342
343 #[allow(clippy::single_range_in_vec_init)]
344 Segment {
345 group,
346 buffer,
347 data: Vec::new(),
348 regions: vec![0..0],
349 defer: HashMap::new(),
350 custom: Vec::new(),
351 }
352 });
353 }
354
355 fn gen_binding(
356 mvp: &Buffer,
357 buffer: &Buffer,
358 clip: &Buffer,
359 shared: &Shared,
360 device: &wgpu::Device,
361 atlasview: &TextureView,
362 layerview: &TextureView,
363 layout: &wgpu::BindGroupLayout,
364 ) -> wgpu::BindGroup {
365 let bindings = [
366 BindGroupEntry {
367 binding: 0,
368 resource: mvp.as_entire_binding(),
369 },
370 BindGroupEntry {
371 binding: 1,
372 resource: buffer.as_entire_binding(),
373 },
374 BindGroupEntry {
375 binding: 2,
376 resource: clip.as_entire_binding(),
377 },
378 BindGroupEntry {
379 binding: 3,
380 resource: wgpu::BindingResource::Sampler(&shared.sampler),
381 },
382 BindGroupEntry {
383 binding: 4,
384 resource: wgpu::BindingResource::TextureView(atlasview),
385 },
386 BindGroupEntry {
387 binding: 5,
388 resource: wgpu::BindingResource::TextureView(layerview),
389 },
390 ];
391
392 device.create_bind_group(&wgpu::BindGroupDescriptor {
393 layout,
394 entries: &bindings,
395 label: None,
396 })
397 }
398
399 pub fn new(
402 device: &wgpu::Device,
403 shared: &Shared,
404 atlasview: &Arc<TextureView>,
405 layerview: &Arc<TextureView>,
406 format: wgpu::TextureFormat,
407 layer: bool,
408 ) -> Self {
409 let pipeline = shared.get_pipeline(device, format);
410
411 let mvp = device.create_buffer(&BufferDescriptor {
412 label: Some("MVP"),
413 size: std::mem::size_of::<crate::Mat4x4>() as u64,
414 usage: BufferUsages::UNIFORM | BufferUsages::COPY_DST,
415 mapped_at_creation: false,
416 });
417
418 let clip = device.create_buffer(&BufferDescriptor {
419 label: Some("Compositor Clip Data"),
420 size: 4 * size_of::<PxRect>() as u64,
421 usage: BufferUsages::STORAGE | BufferUsages::COPY_DST,
422 mapped_at_creation: false,
423 });
424
425 let buffer = device.create_buffer(&BufferDescriptor {
426 label: Some("Compositor Data"),
427 size: 32 * size_of::<Data>() as u64,
428 usage: BufferUsages::STORAGE | BufferUsages::COPY_DST,
429 mapped_at_creation: false,
430 });
431
432 let group = Self::gen_binding(
433 &mvp,
434 &buffer,
435 &clip,
436 shared,
437 device,
438 atlasview,
439 layerview,
440 &pipeline.get_bind_group_layout(0),
441 );
442
443 #[allow(clippy::single_range_in_vec_init)]
444 let segment = Segment {
445 group,
446 buffer,
447 data: Vec::new(),
448 regions: vec![0..0],
449 defer: HashMap::new(),
450 custom: Vec::new(),
451 };
452
453 Self {
454 pipeline,
455 mvp,
456 clip,
457 clipdata: vec![PxRect::zero()],
458 segments: SmallVec::from_buf([HashMap::from_iter([(0, segment)])]),
459 view: Arc::downgrade(atlasview),
460 layer_view: Arc::downgrade(layerview),
461 layer,
462 }
463 }
464
465 fn rebind(&mut self, shared: &Shared, device: &wgpu::Device, atlas: &Atlas, layers: &Atlas) {
468 self.view = Arc::downgrade(&atlas.view);
469 self.layer_view = Arc::downgrade(&layers.view);
470
471 for slices in &mut self.segments {
472 for segment in slices.values_mut() {
473 segment.group = Self::gen_binding(
474 &self.mvp,
475 &segment.buffer,
476 &self.clip,
477 shared,
478 device,
479 &atlas.view,
480 &layers.view,
481 &self.pipeline.get_bind_group_layout(0),
482 );
483 }
484 }
485 }
486
487 fn check_data(
488 mvp: &Buffer,
489 clip: &Buffer,
490 layout: &wgpu::BindGroupLayout,
491 segment: &mut Segment,
492 shared: &Shared,
493 device: &wgpu::Device,
494 atlas: &Atlas,
495 layers: &Atlas,
496 ) {
497 let size = segment.data.len() * size_of::<Data>();
498 if (segment.buffer.size() as usize) < size {
499 segment.buffer.destroy();
500 segment.buffer = device.create_buffer(&BufferDescriptor {
501 label: Some("Compositor Data"),
502 size: size.next_power_of_two() as u64,
503 usage: BufferUsages::STORAGE | BufferUsages::COPY_DST,
504 mapped_at_creation: false,
505 });
506
507 segment.group = Self::gen_binding(
508 mvp,
509 &segment.buffer,
510 clip,
511 shared,
512 device,
513 &atlas.view,
514 &layers.view,
515 layout,
516 );
517 }
518 }
519
520 fn check_clip(
521 &mut self,
522 shared: &Shared,
523 device: &wgpu::Device,
524 atlas: &Atlas,
525 layers: &Atlas,
526 ) {
527 let size = self.clipdata.len() * size_of::<PxRect>();
528 if (self.clip.size() as usize) < size {
529 self.clip.destroy();
530 self.clip = device.create_buffer(&BufferDescriptor {
531 label: Some("Compositor Clip Data"),
532 size: size.next_power_of_two() as u64,
533 usage: BufferUsages::STORAGE | BufferUsages::COPY_DST,
534 mapped_at_creation: false,
535 });
536 self.rebind(shared, device, atlas, layers);
537 }
538 }
539
540 #[inline]
541 fn scissor_check(dim: &PxDim, clip: PxRect) -> Result<PxRect, PxRect> {
542 if PxRect::new(0.0, 0.0, dim.width, dim.height) == clip {
543 Err(clip)
544 } else {
545 Ok(clip)
546 }
547 }
548
549 #[inline]
550 fn clip_data(
551 clipdata: &mut Vec<PxRect>,
552 cliprect: Result<PxRect, PxRect>,
553 offset: PxVector,
554 mut data: Data,
555 ) -> Option<Data> {
556 match cliprect {
557 Ok(clip) => {
558 if data.rotation.is_zero() {
559 let (mut x, mut y, mut w, mut h) =
560 (data.pos.0[0], data.pos.0[1], data.dim.0[0], data.dim.0[1]);
561
562 if !clip.collides(&PxRect::new(x, y, x + w, y + h)) {
564 return None;
567 }
568
569 let (mut u, mut v, mut uw, mut vh) =
570 (data.uv.0[0], data.uv.0[1], data.uvdim.0[0], data.uvdim.0[1]);
571
572 let bounds = clip.v.as_array_ref();
575 let (min_x, min_y, max_x, max_y) = (bounds[0], bounds[1], bounds[2], bounds[3]);
576
577 let uv_ratio = RelDim::new(uw / w, vh / h);
579
580 if x < min_x {
582 let right_shift = min_x - x;
583
584 x += right_shift;
585 u += right_shift * uv_ratio.width;
586 w -= right_shift;
587 uw -= right_shift * uv_ratio.width;
588 }
589
590 if x + w > max_x {
592 let right_shift = max_x - (x + w);
593 w += right_shift;
594 uw += right_shift * uv_ratio.width;
595 }
596
597 if y < min_y {
599 let bottom_shift = min_y - y;
600
601 y += bottom_shift;
602 v += bottom_shift * uv_ratio.height;
603 h -= bottom_shift;
604 vh -= bottom_shift * uv_ratio.height;
605 }
606
607 if y + h > max_y {
609 let bottom_shift = max_y - (y + h);
610 h += bottom_shift;
611 vh += bottom_shift * uv_ratio.height;
612 }
613
614 Some(Data {
615 pos: [x + offset.x, y + offset.y].into(),
616 dim: [w, h].into(),
617 uv: [u, v].into(),
618 uvdim: [uw, vh].into(),
619 color: data.color,
620 rotation: data.rotation,
621 flags: data.flags,
622 _padding: data._padding,
623 })
624 } else {
625 let idx = if let Some((idx, _)) =
628 clipdata.iter().enumerate().find(|(_, r)| **r == clip)
629 {
630 idx
631 } else {
632 clipdata.push(clip);
633 clipdata.len() - 1
634 };
635
636 debug_assert!(idx < 0xFFFF);
637 data.flags = DataFlags::from_bits(data.flags)
638 .with_clip(idx as u16)
639 .into();
640 data.pos.0[0] += offset.x;
641 data.pos.0[1] += offset.y;
642 Some(data)
643 }
644 }
645 Err(clip) => {
646 if data.rotation.is_zero() {
650 let (x, y, w, h) = (data.pos.0[0], data.pos.0[1], data.dim.0[0], data.dim.0[1]);
651 if !clip.collides(&PxRect::new(x, y, x + w, y + h)) {
652 return None;
655 }
656 }
657 data.pos.0[0] += offset.x;
658 data.pos.0[1] += offset.y;
659 Some(data)
660 }
661 }
662 }
663
664 pub fn prepare(&mut self, driver: &Driver, _: &mut wgpu::CommandEncoder, surface_dim: PxDim) {
665 if self.view.strong_count() == 0 || self.layer_view.strong_count() == 0 {
667 self.rebind(
668 &driver.shared,
669 &driver.device,
670 &driver.atlas.read(),
671 &driver.layer_atlas[self.layer as usize].read(),
672 );
673 }
674
675 for slices in &mut self.segments {
677 for segment in slices.values_mut() {
678 for (idx, (f, clip, offset)) in segment.defer.drain() {
679 f(driver, &mut segment.data[idx as usize]);
680 segment.data[idx as usize].flags =
681 DataFlags::from_bits(segment.data[idx as usize].flags).into();
682 segment.data[idx as usize] = Self::clip_data(
683 &mut self.clipdata,
684 Self::scissor_check(&surface_dim, clip),
685 offset,
686 segment.data[idx as usize],
687 )
688 .unwrap_or_default();
689 }
690
691 if !segment.data.is_empty() {
692 Self::check_data(
693 &self.mvp,
694 &self.clip,
695 &self.pipeline.get_bind_group_layout(0),
696 segment,
697 &driver.shared,
698 &driver.device,
699 &driver.atlas.read(),
700 &driver.layer_atlas[self.layer as usize].read(),
701 );
702
703 let mut offset = 0;
705 for range in &segment.regions {
706 let len = range.end - range.start;
707 driver.queue.write_buffer(
708 &segment.buffer,
709 range.start as u64,
710 bytemuck::cast_slice(
711 &segment.data.as_slice()[offset as usize..(offset + len) as usize],
712 ),
713 );
714 offset += len;
715 }
716 }
717 }
718 }
719
720 driver.queue.write_buffer(
721 &self.mvp,
722 0,
723 bytemuck::cast_slice(
724 &crate::graphics::mat4_proj(
725 0.0,
726 surface_dim.height,
727 surface_dim.width,
728 -(surface_dim.height),
729 0.2,
730 10000.0,
731 )
732 .to_array(),
733 ),
734 );
735
736 if !self.clipdata.is_empty() {
739 self.check_clip(
740 &driver.shared,
741 &driver.device,
742 &driver.atlas.read(),
743 &driver.layer_atlas[self.layer as usize].read(),
744 );
745 driver.queue.write_buffer(
746 &self.clip,
747 0,
748 bytemuck::cast_slice(self.clipdata.as_slice()),
749 );
750 }
751 }
752
753 #[inline]
754 fn append_internal(
755 &mut self,
756 clipstack: &[PxRect],
757 surface_dim: PxDim,
758 layer_offset: PxVector,
759 pos: PxPoint,
760 dim: PxDim,
761 uv: PxPoint,
762 uvdim: PxDim,
763 color: u32,
764 rotation: f32,
765 tex: u8,
766 pass: u8,
767 slice: u8,
768 raw: bool,
769 layer: bool,
770 ) -> u32 {
771 let data = Data {
772 pos: pos.to_array().into(),
773 dim: dim.to_array().into(),
774 uv: uv.to_array().into(),
775 uvdim: uvdim.to_array().into(),
776 color,
777 rotation,
778 flags: DataFlags::new()
779 .with_tex(tex)
780 .with_raw(raw)
781 .with_layer(layer)
782 .into(),
783 ..Default::default()
784 };
785
786 if let Some(d) = Self::clip_data(
787 &mut self.clipdata,
788 clipstack.last().ok_or(surface_dim.into()).copied(),
789 layer_offset,
790 data,
791 ) {
792 self.preprocessed(d, pass, slice)
793 } else {
794 u32::MAX }
796 }
797
798 #[inline]
799 fn preprocessed(&mut self, data: Data, index: u8, slice: u8) -> u32 {
800 let segment = &mut self.segments[index as usize].get_mut(&slice).unwrap();
801 let region = segment.regions.last_mut().unwrap();
802 if region.end == u32::MAX {
803 panic!(
804 "Still processing a compute operation! Finish it by calling set_compute_buffer() first."
805 );
806 }
807
808 let idx = region.end;
809 segment.data.push(data);
810 region.end += 1;
811 idx
812 }
813
814 pub fn draw(&mut self, driver: &Driver, pass: &mut wgpu::RenderPass<'_>, index: u8, slice: u8) {
815 let segment = &mut self.segments[index as usize].get_mut(&slice).unwrap();
816
817 let mut last_index = 0;
818 for (i, f, draw_offset) in &mut segment.custom {
819 if last_index < *i {
820 pass.set_pipeline(&self.pipeline);
821 pass.set_bind_group(0, &segment.group, &[0]);
822 pass.draw(last_index..*i, 0..1);
823 }
824 last_index = *i;
825 f(driver, pass, *draw_offset);
826 }
827
828 pass.set_pipeline(&self.pipeline);
829 pass.set_bind_group(0, &segment.group, &[0]);
830 pass.draw(last_index..(segment.regions.last().unwrap().end * 6), 0..1);
831 }
832
833 pub fn cleanup(&mut self) {
834 for slices in &mut self.segments {
835 for segment in slices.values_mut() {
836 segment.data.clear();
837 segment.regions.clear();
838 segment.regions.push(0..0);
839 }
840 }
841
842 self.clipdata.clear();
843 self.clipdata.push(PxRect::zero());
844 }
845}
846
847pub struct CompositorView<'a> {
855 pub index: u8, pub window: &'a mut Compositor, pub layer0: &'a mut Compositor, pub layer1: &'a mut Compositor, pub clipstack: &'a mut Vec<PxRect>,
861 pub offset: PxVector,
862 pub surface_dim: PxDim, pub pass: u8,
864 pub slice: u8, }
866
867impl<'a> CompositorView<'a> {
868 #[inline]
869 pub fn with_clip<T>(
870 &mut self,
871 clip: PxRect,
872 f: impl FnOnce(&mut Self) -> Result<T, crate::Error>,
873 ) -> Result<T, crate::Error> {
874 if let Some(prev) = self.clipstack.last() {
875 self.clipstack.push(clip.intersect(*prev));
876 } else {
877 self.clipstack.push(clip);
878 }
879 let r = f(self);
880 self.clipstack
881 .pop()
882 .expect("Tried to pop a clipping rect but the stack was empty!");
883 r
884 }
885
886 #[inline]
887 pub fn current_clip(&self) -> PxRect {
888 *self.clipstack.last().unwrap_or(&self.surface_dim.into())
889 }
890
891 #[inline]
892 pub fn segment(&mut self) -> &mut Segment {
893 let pass = self.pass;
894 let slice = self.slice;
895 self.compositor().segments[pass as usize]
896 .get_mut(&slice)
897 .unwrap()
898 }
899
900 #[inline]
901 pub fn compositor(&mut self) -> &mut Compositor {
902 match self.index {
903 0 => self.window,
904 1 => self.layer0,
905 2 => self.layer1,
906 _ => panic!("Illegal compositor index!"),
907 }
908 }
909
910 #[inline]
911 pub fn append_data(
912 &mut self,
913 pos: PxPoint,
914 dim: PxDim,
915 uv: PxPoint,
916 uvdim: PxDim,
917 color: u32,
918 rotation: f32,
919 tex: u8,
920 raw: bool,
921 ) -> u32 {
922 let compositor = match self.index {
924 0 => &mut self.window,
925 1 => &mut self.layer0,
926 2 => &mut self.layer1,
927 _ => panic!("Illegal compositor index!"),
928 };
929 compositor.append_internal(
930 self.clipstack,
931 self.surface_dim,
932 self.offset,
933 pos,
934 dim,
935 uv,
936 uvdim,
937 color,
938 rotation,
939 tex,
940 self.pass,
941 self.slice,
942 raw,
943 false,
944 )
945 }
946
947 #[inline]
948 pub(crate) fn append_layer(&mut self, layer: &Layer, parent_pos: PxPoint, uv: PxBox) -> u32 {
949 let compositor = match self.index {
951 0 => &mut self.window,
952 1 => &mut self.layer0,
953 2 => &mut self.layer1,
954 _ => panic!("Illegal compositor index!"),
955 };
956 compositor.append_internal(
957 self.clipstack,
958 self.surface_dim,
959 self.offset,
960 layer.dest.topleft() + parent_pos.to_vector(),
961 layer.dest.dim(),
962 uv.min.to_f32().to_array().into(),
963 uv.size().to_f32().to_array().into(),
964 layer.color.rgba,
965 layer.rotation,
966 0,
967 self.pass,
968 self.slice,
969 false,
970 true,
971 )
972 }
973
974 #[inline]
975 pub fn preprocessed(&mut self, mut data: Data) -> u32 {
976 data.pos.0[0] += self.offset.x;
977 data.pos.0[1] += self.offset.y;
978 data.flags = DataFlags::from_bits(data.flags).into();
979 let pass = self.pass;
980 let slice = self.slice;
981 self.compositor().preprocessed(data, pass, slice)
982 }
983
984 #[inline]
985 pub fn defer(&mut self, f: impl FnOnce(&Driver, &mut Data) + Send + Sync + 'static) {
986 let clip = self.current_clip();
987 let offset = self.offset;
988 let segment = self.segment();
989 let region = segment.regions.last_mut().unwrap();
990 if region.end == u32::MAX {
991 panic!(
992 "Still processing a compute operation! Finish it by calling set_compute_buffer() first."
993 );
994 }
995
996 let idx = region.end;
997 segment.data.push(Default::default());
998 segment.defer.insert(idx, (Box::new(f), clip, offset));
999 region.end += 1;
1000 }
1001
1002 pub fn append_custom(
1003 &mut self,
1004 f: impl FnMut(&Driver, &mut wgpu::RenderPass<'_>, PxVector) + Send + Sync + 'static,
1005 ) {
1006 let index = self.segment().regions.last().unwrap().end;
1007 if index == u32::MAX {
1008 panic!(
1009 "Still processing a compute operation! Finish it by calling set_compute_buffer() first."
1010 );
1011 }
1012 let offset = self.offset;
1013 self.segment().custom.push((index, Box::new(f), offset));
1014 }
1015
1016 pub fn get_compute_buffer(&mut self) -> (&Buffer, u32) {
1022 let offset = self.segment().regions.last().unwrap().end;
1023 if offset == u32::MAX {
1024 panic!(
1025 "Still processing a compute operation! Finish it by calling set_compute_buffer() first."
1026 );
1027 }
1028 self.segment().regions.push(offset..u32::MAX);
1029 (&self.segment().buffer, offset)
1030 }
1031
1032 pub fn set_compute_buffer(&mut self, count: u32) {
1036 let region = self.segment().regions.last_mut().unwrap();
1037 region.start += count;
1038 region.end = region.start;
1039 }
1040
1041 pub fn reserve(&mut self, driver: &Driver) {
1042 let pass = self.pass;
1043 let slice = self.slice;
1044 self.compositor().reserve(driver, pass, slice);
1045 }
1046}
1047
1048#[bitfield_struct::bitfield(u32)]
1049pub struct DataFlags {
1050 #[bits(16)]
1051 pub clip: u16,
1052 #[bits(8)]
1053 pub tex: u8,
1054 #[bits(6)]
1055 pub __: u8,
1056 pub layer: bool,
1057 pub raw: bool,
1058}
1059
1060#[repr(C)]
1074#[derive(Debug, Clone, Copy, Default, PartialEq, bytemuck::NoUninit)]
1075pub struct Data {
1076 pub pos: Vec2f,
1077 pub dim: Vec2f,
1078 pub uv: Vec2f,
1079 pub uvdim: Vec2f,
1080 pub color: u32, pub rotation: f32,
1082 pub flags: u32,
1083 pub _padding: [u8; 4], }
1085
1086static_assertions::const_assert_eq!(std::mem::size_of::<Data>(), 48);
1087
1088