1#![feature(alloc_layout_extra)]
2#![feature(coerce_unsized)]
3#![feature(downcast_unchecked)]
4#![feature(non_null_convenience)]
5#![feature(ptr_metadata)]
6#![feature(sync_unsafe_cell)]
7#![feature(unsize)]
8#![allow(private_interfaces)]
9#![deny(missing_docs)]
10#![deny(clippy::missing_docs_in_private_items)]
11
12use crate::dyn_vec::*;
122use crate::graph::*;
123use crate::unique_id::*;
124pub use mutability_marker::*;
125use private::*;
126use slab::*;
127use std::any::*;
128use std::cell::*;
129use std::hint::*;
130use std::marker::*;
131use std::mem::*;
132use std::ops::*;
133use std::pin::*;
134use std::sync::atomic::*;
135use std::sync::mpsc::*;
136use std::sync::*;
137use sync_rw_cell::*;
138use task_pool::*;
139#[allow(unused_imports)]
140use wasm_sync::{Condvar, Mutex};
141
142mod dyn_vec;
144
145mod graph;
147
148mod unique_id;
150
151pub trait Kind: 'static + Send + Sync {
154 type FormatDescriptor: Send + Sync;
156
157 type UsageDescriptor: Send + Sync + Sized;
159}
160
161pub trait Format: 'static + Send + Sync + Sized {
163 type Kind: Kind;
165
166 fn allocate(descriptor: &<Self::Kind as Kind>::FormatDescriptor) -> Self;
169}
170
171pub trait DerivedDescriptor<F: Format>: 'static + Send + Sync + Sized {
174 type Format: Format<Kind = F::Kind>;
176
177 fn update(
179 &self,
180 data: &mut Self::Format,
181 parent: &F,
182 usages: &[&<F::Kind as Kind>::UsageDescriptor],
183 );
184}
185
186pub trait ViewUsage: Send + Sync + ViewUsageInner {}
189
190pub struct AllocationDescriptor<'a, F: Format> {
192 pub descriptor: <F::Kind as Kind>::FormatDescriptor,
194 pub label: Option<&'static str>,
196 pub derived_formats: &'a [Derived<F>],
198}
199
200pub struct CommandBuffer {
202 command_list: DynVec,
204 first_command_entry: Option<DynEntry<CommandEntry>>,
206 label: Option<&'static str>,
208 last_command_entry: Option<DynEntry<CommandEntry>>,
210}
211
212impl CommandBuffer {
213 pub fn new(descriptor: CommandBufferDescriptor) -> Self {
215 const DEFAULT_ALLOCATION_SIZE: usize = 2048;
217
218 Self {
219 command_list: DynVec::with_capacity(DEFAULT_ALLOCATION_SIZE),
220 label: descriptor.label,
221 first_command_entry: None,
222 last_command_entry: None,
223 }
224 }
225
226 pub fn fence(&mut self, views: &[&dyn ViewUsage]) {
229 unsafe {
230 let computation = SyncUnsafeCell::new(Some(Computation::Execute {
231 command: self.command_list.push(()),
232 }));
233 let first_view_entry = self.push_views(views);
234 let next_command = self.command_list.push(CommandEntry {
235 computation,
236 first_view_entry,
237 label: Some("Fence"),
238 next_instance: None,
239 });
240 self.update_first_last_command_entries(next_command);
241 }
242 }
243
244 pub fn map<M: UsageMutability, F: Format>(
246 &mut self,
247 view: &ViewDescriptor<M, F>,
248 ) -> Mapped<M, F> {
249 unsafe {
250 assert!(
251 TypeId::of::<M>() == TypeId::of::<Const>() || !view.view.derived,
252 "Attempted to mutably map derived view of object{} in command buffer{}",
253 FormattedLabel(" ", view.view.inner.inner.label, ""),
254 FormattedLabel(" ", self.label, "")
255 );
256
257 let inner = Arc::new(MappedInner {
258 context_id: view.view.inner.inner.context_id,
259 command_context: UnsafeCell::new(MaybeUninit::uninit()),
260 label: view.view.inner.inner.label,
261 map_state: MapObjectState::default(),
262 });
263
264 let computation = SyncUnsafeCell::new(Some(Computation::Map {
265 inner: Some(inner.clone()),
266 }));
267
268 let first_view_entry = self.push_views(&[view]);
269 let next_command = self.command_list.push(CommandEntry {
270 computation,
271 first_view_entry,
272 label: Some("Map format"),
273 next_instance: None,
274 });
275
276 self.update_first_last_command_entries(next_command);
277
278 Mapped {
279 inner,
280 view: view.view.clone(),
281 marker: PhantomData,
282 }
283 }
284 }
285
286 pub fn schedule(
288 &mut self,
289 descriptor: CommandDescriptor<impl Send + Sync + FnOnce(CommandContext)>,
290 ) {
291 unsafe {
292 let computation = SyncUnsafeCell::new(Some(Computation::Execute {
293 command: self
294 .command_list
295 .push(SyncUnsafeCell::new(Some(descriptor.command))),
296 }));
297 let first_view_entry = self.push_views(descriptor.views);
298 let next_command = self.command_list.push(CommandEntry {
299 computation,
300 first_view_entry,
301 label: descriptor.label,
302 next_instance: None,
303 });
304 self.update_first_last_command_entries(next_command);
305 }
306 }
307
308 fn push_views(&mut self, list: &[&dyn ViewUsage]) -> Option<DynEntry<ViewEntry>> {
310 unsafe {
311 let mut view_iter = list.iter();
312 if let Some(first) = view_iter.next() {
313 let view = first.add_to_list(&mut self.command_list);
314 let first_entry = self.command_list.push(ViewEntry {
315 next_instance: None,
316 view,
317 });
318 let mut previous_entry = first_entry;
319
320 for to_add in view_iter {
321 let view = to_add.add_to_list(&mut self.command_list);
322 let next_entry = self.command_list.push(ViewEntry {
323 next_instance: None,
324 view,
325 });
326
327 self.command_list
328 .get_unchecked_mut(previous_entry)
329 .next_instance = Some(next_entry);
330 previous_entry = next_entry;
331 }
332
333 Some(first_entry)
334 } else {
335 None
336 }
337 }
338 }
339
340 unsafe fn update_first_last_command_entries(&mut self, next_command: DynEntry<CommandEntry>) {
347 unsafe {
348 if self.first_command_entry.is_none() {
349 self.first_command_entry = Some(next_command);
350 } else if let Some(entry) = self.last_command_entry {
351 self.command_list.get_unchecked_mut(entry).next_instance = Some(next_command);
352 }
353 self.last_command_entry = Some(next_command);
354 }
355 }
356}
357
358#[derive(Copy, Clone, Debug, Default)]
360pub struct CommandBufferDescriptor {
361 pub label: Option<&'static str>,
363}
364
365#[derive(Copy, Clone, Debug, Default)]
367pub struct CommandBufferStatus {
368 pub incomplete_commands: u32,
370}
371
372impl CommandBufferStatus {
373 pub fn complete(&self) -> bool {
375 self.incomplete_commands == 0
376 }
377}
378
379#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
382pub struct CommandBufferSubmission {
383 unique_id: u64,
385 context_id: u64,
387 command_buffer_id: u16,
389}
390
391pub struct CommandContext {
395 inner: ManuallyDrop<CommandContextInner>,
397}
398
399impl CommandContext {
400 pub fn get<F: Format>(&self, view: &View<F>) -> ViewRef<Const, F> {
402 ViewRef {
403 reference: self.find_view::<Const, _>(view).borrow(),
404 marker: PhantomData,
405 }
406 }
407
408 pub fn get_mut<F: Format>(&self, view: &View<F>) -> ViewRef<Mut, F> {
411 ViewRef {
412 reference: self.find_view::<Mut, _>(view).borrow_mut(),
413 marker: PhantomData,
414 }
415 }
416
417 fn find_view<M: Mutability, F: Format>(&self, view: &View<F>) -> &RwCell<*mut ()> {
419 let mutable = TypeId::of::<Mut>() == TypeId::of::<M>();
420 if let Some(command_view) = self
421 .inner
422 .views
423 .iter()
424 .find(|x| x.id == view.id && x.mutable == mutable)
425 {
426 &command_view.value
427 } else {
428 panic!(
429 "View{} was not referenced by command{}{}",
430 FormattedLabel(" ", view.inner.inner.label, ""),
431 FormattedLabel(" ", self.inner.label, ""),
432 FormattedLabel(
433 " (from command buffer ",
434 self.inner.command_buffer_label,
435 ")"
436 )
437 );
438 }
439 }
440}
441
442impl std::fmt::Debug for CommandContext {
443 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
444 f.debug_struct("CommandContext").finish()
445 }
446}
447
448impl Drop for CommandContext {
449 fn drop(&mut self) {
450 unsafe {
451 self.inner
452 .context
453 .inner
454 .lock()
455 .expect("Failed to lock context.")
456 .complete_command(self.inner.command_id, &self.inner.context);
457 ManuallyDrop::drop(&mut self.inner);
458 }
459 }
460}
461
462pub struct CommandDescriptor<'a, C: 'static + Send + Sync + FnOnce(CommandContext)> {
464 pub label: Option<&'static str>,
466 pub command: C,
468 pub views: &'a [&'a dyn ViewUsage],
470}
471
472impl<'a, C: 'static + Send + Sync + FnOnce(CommandContext)> std::fmt::Debug
473 for CommandDescriptor<'a, C>
474{
475 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
476 f.debug_tuple("CommandDescriptor")
477 .field(&self.label)
478 .finish()
479 }
480}
481
482#[derive(Copy, Clone, Debug, Default)]
484pub struct ContextDescriptor {
485 pub label: Option<&'static str>,
487}
488
489pub struct Data<K: Kind> {
492 inner: Arc<DataInner<K>>,
494}
495
496impl<K: Kind> Data<K> {
497 pub fn view<F: Format<Kind = K>>(&self) -> View<F> {
504 let (id, derived) = if TypeId::of::<F>() == self.inner.format_id {
505 (self.inner.id, false)
506 } else if let Some((_, id)) = self
507 .inner
508 .derived_formats
509 .iter()
510 .copied()
511 .find(|&(id, _)| id == TypeId::of::<F>())
512 {
513 (id, true)
515 } else {
516 panic!(
517 "Derived format {} of object{} did not exist",
518 type_name::<F>(),
519 FormattedLabel(" ", self.inner.label, "")
520 )
521 };
522
523 View {
524 inner: self.clone(),
525 id,
526 derived,
527 marker: PhantomData,
528 }
529 }
530}
531
532impl<K: Kind> Clone for Data<K> {
533 fn clone(&self) -> Self {
534 Self {
535 inner: self.inner.clone(),
536 }
537 }
538}
539
540impl<K: Kind> std::fmt::Debug for Data<K>
541where
542 K::FormatDescriptor: std::fmt::Debug,
543{
544 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
545 if let Some(label) = self.inner.label {
546 f.debug_tuple("Data")
547 .field(&label)
548 .field(&self.inner.descriptor)
549 .finish()
550 } else {
551 f.debug_tuple("Data").field(&self.inner.descriptor).finish()
552 }
553 }
554}
555
556impl<K: Kind> Deref for Data<K> {
557 type Target = K::FormatDescriptor;
558
559 fn deref(&self) -> &Self::Target {
560 &self.inner.descriptor
561 }
562}
563
564impl<K: Kind> PartialEq for Data<K> {
565 fn eq(&self, other: &Self) -> bool {
566 Arc::ptr_eq(&self.inner, &other.inner)
567 }
568}
569
570impl<K: Kind> Eq for Data<K> {}
571
572#[derive(Clone)]
576pub struct DataFrostContext {
577 holder: Arc<ContextHolder>,
579}
580
581impl DataFrostContext {
582 pub fn new(_: ContextDescriptor) -> Self {
584 let (object_update_sender, object_updates) = channel();
585
586 let change_notifier = ChangeNotifier::default();
587 let change_listener = Condvar::new();
588 let context_id = unique_id();
589 let inner = Mutex::new(ContextInner {
590 active_command_buffers: Slab::new(),
591 context_id,
592 compute_graph: DirectedAcyclicGraph::new(),
593 critical_nodes: DirectedAcyclicGraphFlags::new(),
594 critical_top_level_nodes: DirectedAcyclicGraphFlags::new(),
595 objects: Slab::new(),
596 object_update_sender,
597 object_updates,
598 stalled: true,
599 temporary_node_buffer: Vec::new(),
600 top_level_nodes: DirectedAcyclicGraphFlags::new(),
601 });
602
603 let holder = Arc::new(ContextHolder {
604 change_notifier,
605 change_listener,
606 context_id,
607 inner,
608 });
609
610 Self { holder }
611 }
612
613 pub fn allocate<F: Format>(&self, descriptor: AllocationDescriptor<F>) -> Data<F::Kind> {
616 self.inner().allocate(descriptor)
617 }
618
619 pub fn get<'a, M: Mutability, F: Format>(
621 &self,
622 mapping: &'a Mapped<M, F>,
623 ) -> ViewRef<'a, Const, F> {
624 unsafe {
625 self.wait_for_mapping(mapping);
626 return (*mapping.inner.command_context.get())
627 .assume_init_ref()
628 .get(&mapping.view);
629 }
630 }
631
632 pub fn get_mut<'a, F: Format>(&self, mapping: &'a mut Mapped<Mut, F>) -> ViewRef<'a, Mut, F> {
634 unsafe {
635 self.wait_for_mapping(mapping);
636 return (*mapping.inner.command_context.get())
637 .assume_init_mut()
638 .get_mut(&mapping.view);
639 }
640 }
641
642 pub fn query(&self, submission: &CommandBufferSubmission) -> CommandBufferStatus {
644 assert!(
645 submission.context_id == self.holder.context_id,
646 "Submission was not owned by this context."
647 );
648 self.inner()
649 .active_command_buffers
650 .get(submission.command_buffer_id as usize)
651 .filter(|x| x.unique_id == submission.unique_id)
652 .map(|x| CommandBufferStatus {
653 incomplete_commands: x.remaining_commands,
654 })
655 .unwrap_or_default()
656 }
657
658 pub fn submit(&self, buffer: CommandBuffer) -> CommandBufferSubmission {
660 self.inner().submit(buffer, &self.holder)
661 }
662
663 fn inner(&self) -> MutexGuard<ContextInner> {
665 self.holder
666 .inner
667 .lock()
668 .expect("Failed to obtain inner context.")
669 }
670
671 fn wait_for_mapping<M: Mutability, F: Format>(&self, mapping: &Mapped<M, F>) {
673 unsafe {
674 assert!(
675 mapping.inner.context_id == self.holder.context_id,
676 "Mapping was not from this context."
677 );
678
679 let query = mapping.inner.map_state.get();
680 if query.queued {
681 if !query.complete {
682 let mut inner = self.inner();
683 while !mapping.inner.map_state.get().complete {
684 if inner.top_level_nodes.get_unchecked(query.node) {
685 inner
686 .critical_top_level_nodes
687 .set_unchecked(query.node, false);
688 inner.top_level_nodes.set_unchecked(query.node, false);
689 inner
690 .compute_graph
691 .get_unchecked_mut(query.node)
692 .computation = Computation::Map { inner: None };
693 *mapping.inner.command_context.get() = MaybeUninit::new(
694 inner.create_command_context(&self.holder, query.node),
695 );
696 mapping.inner.map_state.set_complete();
697 return;
698 }
699
700 match inner.prepare_next_command::<true>(&self.holder) {
701 Some(Some(command)) => {
702 drop(inner);
703 command.execute();
704 inner = self.inner();
705 }
706 Some(None) => continue,
707 None => {
708 inner = self
709 .holder
710 .change_listener
711 .wait(inner)
712 .expect("Failed to lock mutex.")
713 }
714 }
715 }
716 }
717 } else {
718 panic!(
719 "Attempted to map object{} before submitting the associated command buffer.",
720 FormattedLabel(" ", mapping.inner.label, "")
721 )
722 }
723 }
724 }
725}
726
727impl std::fmt::Debug for DataFrostContext {
728 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
729 f.debug_tuple("DataFrostContext").finish()
730 }
731}
732
733impl Default for DataFrostContext {
734 fn default() -> Self {
735 Self::new(ContextDescriptor::default())
736 }
737}
738
739impl WorkProvider for DataFrostContext {
740 fn change_notifier(&self) -> &ChangeNotifier {
741 &self.holder.change_notifier
742 }
743
744 fn next_task(&self) -> Option<Box<dyn '_ + WorkUnit>> {
745 let mut inner = self.inner();
746 loop {
747 match inner.prepare_next_command::<false>(&self.holder) {
748 Some(Some(command)) => return Some(command),
749 Some(None) => continue,
750 None => return None,
751 }
752 }
753 }
754}
755
756pub struct Derived<F: Format> {
759 inner: Arc<dyn DerivedFormatUpdater>,
761 marker: PhantomData<fn() -> F>,
763}
764
765impl<F: Format> Derived<F> {
766 pub fn new<D: DerivedDescriptor<F>>(descriptor: D) -> Self {
768 Self {
769 inner: Arc::new(TypedDerivedFormatUpdater {
770 descriptor,
771 marker: PhantomData,
772 }),
773 marker: PhantomData,
774 }
775 }
776}
777
778impl<F: Format> Clone for Derived<F> {
779 fn clone(&self) -> Self {
780 Self {
781 inner: self.inner.clone(),
782 marker: PhantomData,
783 }
784 }
785}
786
787impl<F: Format> std::fmt::Debug for Derived<F> {
788 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
789 f.debug_tuple("Derived").field(&type_name::<F>()).finish()
790 }
791}
792
793pub struct Mapped<M: Mutability, F: Format> {
796 inner: Arc<MappedInner>,
798 view: View<F>,
800 marker: PhantomData<fn() -> M>,
802}
803
804pub struct View<F: Format> {
806 inner: Data<F::Kind>,
808 id: u32,
810 derived: bool,
812 marker: PhantomData<fn() -> F>,
814}
815
816impl<F: Format> View<F> {
817 pub fn as_const(&self) -> ViewDescriptor<Const, F> {
819 ViewDescriptor {
820 view: self,
821 descriptor: SyncUnsafeCell::new(Some(())),
822 taken: AtomicBool::new(false),
823 }
824 }
825
826 pub fn as_mut(&self, usage: <F::Kind as Kind>::UsageDescriptor) -> ViewDescriptor<Mut, F> {
828 ViewDescriptor {
829 view: self,
830 descriptor: SyncUnsafeCell::new(Some(usage)),
831 taken: AtomicBool::new(false),
832 }
833 }
834
835 pub fn data(&self) -> &Data<F::Kind> {
837 &self.inner
838 }
839}
840
841impl<F: Format> Clone for View<F> {
842 fn clone(&self) -> Self {
843 Self {
844 inner: self.inner.clone(),
845 id: self.id,
846 derived: self.derived,
847 marker: PhantomData,
848 }
849 }
850}
851
852impl<F: Format> std::fmt::Debug for View<F>
853where
854 <F::Kind as Kind>::FormatDescriptor: std::fmt::Debug,
855{
856 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
857 f.debug_tuple("View")
858 .field(&type_name::<F>())
859 .field(&self.inner)
860 .finish()
861 }
862}
863
864impl<F: Format> Deref for View<F> {
865 type Target = <F::Kind as Kind>::FormatDescriptor;
866
867 fn deref(&self) -> &Self::Target {
868 &self.inner.inner.descriptor
869 }
870}
871
872impl<F: Format> PartialEq for View<F> {
873 fn eq(&self, other: &Self) -> bool {
874 self.inner == other.inner
875 }
876}
877
878impl<F: Format> Eq for View<F> {}
879
880pub struct ViewDescriptor<'a, M: UsageMutability, F: Format> {
883 view: &'a View<F>,
885 descriptor: SyncUnsafeCell<Option<M::Descriptor<F>>>,
887 taken: AtomicBool,
889}
890
891impl<'a, M: UsageMutability, F: Format> ViewUsage for ViewDescriptor<'a, M, F> {}
892
893impl<'a, M: UsageMutability, F: Format> ViewUsageInner for ViewDescriptor<'a, M, F> {
894 fn add_to_list(&self, command_list: &mut DynVec) -> DynEntry<dyn ViewHolder> {
895 unsafe {
896 assert!(
897 !self.taken.swap(true, Ordering::Relaxed),
898 "Attempted to reuse view descriptor{}",
899 FormattedLabel(" ", self.view.inner.inner.label, "")
900 );
901 command_list.push(TypedViewHolder::<M, F> {
902 view: self.view.clone(),
903 descriptor: take(&mut *self.descriptor.get()).unwrap_unchecked(),
904 })
905 }
906 }
907}
908
909pub struct ViewRef<'a, M: Mutability, F: Format> {
911 reference: RwCellGuard<'a, M, *mut ()>,
913 marker: PhantomData<&'a F>,
915}
916
917impl<'a, M: Mutability, F: Format + std::fmt::Debug> std::fmt::Debug for ViewRef<'a, M, F> {
918 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
919 (**self).fmt(f)
920 }
921}
922
923impl<'a, M: Mutability, F: Format> Deref for ViewRef<'a, M, F> {
924 type Target = F;
925
926 fn deref(&self) -> &Self::Target {
927 unsafe { &*self.reference.cast_const().cast() }
928 }
929}
930
931impl<'a, F: Format> DerefMut for ViewRef<'a, Mut, F> {
932 fn deref_mut(&mut self) -> &mut Self::Target {
933 unsafe { &mut *self.reference.cast() }
934 }
935}
936
937trait DerivedFormatUpdater: 'static + Send + Sync {
939 unsafe fn allocate(&self, descriptor: *const ()) -> Box<UnsafeCell<dyn Any + Send + Sync>>;
941
942 fn format_type_id(&self) -> TypeId;
944
945 unsafe fn update(&self, context: CommandContext, usages: *const [*const ()]);
954}
955
956trait ExecutableCommand: 'static + Send + Sync {
958 unsafe fn execute(&self, ctx: CommandContext);
964}
965
966trait ViewHolder: 'static + Send + Sync {
968 fn context_id(&self) -> u64;
970
971 fn id(&self) -> u32;
973
974 fn mutable(&self) -> bool;
976
977 fn usage(&self) -> *const ();
979}
980
981impl ExecutableCommand for () {
982 unsafe fn execute(&self, _: CommandContext) {}
983}
984
985impl<F: 'static + Send + Sync + FnOnce(CommandContext)> ExecutableCommand
986 for SyncUnsafeCell<Option<F>>
987{
988 unsafe fn execute(&self, ctx: CommandContext) {
989 take(&mut *self.get()).unwrap_unchecked()(ctx);
990 }
991}
992
993struct ActiveCommandBuffer {
995 command_list: Arc<DynVec>,
997 label: Option<&'static str>,
999 remaining_commands: u32,
1001 unique_id: u64,
1003}
1004
1005struct CommandContextInner {
1007 pub command_id: NodeId,
1009 pub context: Arc<ContextHolder>,
1011 pub label: Option<&'static str>,
1013 pub command_buffer_label: Option<&'static str>,
1015 pub views: Vec<CommandContextView>,
1017}
1018
1019struct CommandContextView {
1021 pub id: u32,
1023 pub mutable: bool,
1025 pub value: RwCell<*mut ()>,
1027}
1028
1029struct CommandEntry {
1031 pub computation: SyncUnsafeCell<Option<Computation>>,
1033 pub first_view_entry: Option<DynEntry<ViewEntry>>,
1035 pub label: Option<&'static str>,
1037 pub next_instance: Option<DynEntry<CommandEntry>>,
1039}
1040
1041#[derive(Clone)]
1044enum Computation {
1045 Execute {
1047 command: DynEntry<dyn ExecutableCommand>,
1049 },
1050 Map {
1052 inner: Option<Arc<MappedInner>>,
1054 },
1055 Update {
1057 object: u32,
1059 updates: Vec<(Arc<DynVec>, DynEntry<dyn ViewHolder>)>,
1061 },
1062}
1063
1064struct ComputationNode {
1066 pub computation: Computation,
1068 pub command_buffer: u16,
1070 pub derived_update: Option<DerivedFormatUpdate>,
1073 pub label: Option<&'static str>,
1075 pub views: Vec<ComputationViewReference>,
1077}
1078
1079struct ComputationViewReference {
1081 pub id: u32,
1083 pub mutable: bool,
1085 pub view_holder: DynEntry<dyn ViewHolder>,
1087}
1088
1089struct ContextHolder {
1091 change_notifier: ChangeNotifier,
1093 change_listener: Condvar,
1095 context_id: u64,
1097 inner: Mutex<ContextInner>,
1099}
1100
1101struct ContextInner {
1104 active_command_buffers: Slab<ActiveCommandBuffer>,
1106 compute_graph: DirectedAcyclicGraph<ComputationNode>,
1108 context_id: u64,
1110 critical_nodes: DirectedAcyclicGraphFlags,
1112 critical_top_level_nodes: DirectedAcyclicGraphFlags,
1114 objects: Slab<DataHolder>,
1116 object_update_sender: Sender<ObjectUpdate>,
1118 object_updates: std::sync::mpsc::Receiver<ObjectUpdate>,
1120 stalled: bool,
1122 temporary_node_buffer: Vec<NodeId>,
1124 top_level_nodes: DirectedAcyclicGraphFlags,
1126}
1127
1128impl ContextInner {
1129 pub fn allocate<F: Format>(&mut self, descriptor: AllocationDescriptor<F>) -> Data<F::Kind> {
1132 unsafe {
1133 let mut derived_formats = Vec::with_capacity(descriptor.derived_formats.len());
1134 let mut derived_states: Vec<DerivedFormatState> =
1135 Vec::with_capacity(descriptor.derived_formats.len());
1136
1137 let object = F::allocate(&descriptor.descriptor);
1138 let id = self.objects.insert(DataHolder {
1139 immutable_references: Vec::new(),
1140 mutable_references: Vec::new(),
1141 label: descriptor.label,
1142 derive_state: FormatDeriveState::Base {
1143 derived_formats: Vec::with_capacity(descriptor.derived_formats.len()),
1144 },
1145 value: Box::pin(UnsafeCell::new(object)),
1146 }) as u32;
1147
1148 for (index, derived) in descriptor.derived_formats.iter().enumerate() {
1149 let derived_object = derived
1150 .inner
1151 .allocate(&descriptor.descriptor as *const _ as *const _);
1152 let id = self.objects.insert(DataHolder {
1153 immutable_references: Vec::new(),
1154 mutable_references: Vec::new(),
1155 label: descriptor.label,
1156 derive_state: FormatDeriveState::Derived {
1157 index: index as u8,
1158 parent: id,
1159 updater: derived.inner.clone(),
1160 },
1161 value: Box::into_pin(derived_object),
1162 }) as u32;
1163 assert!(
1164 derived.inner.format_type_id() != TypeId::of::<F>(),
1165 "Derived format cannot be the same type as parent."
1166 );
1167 assert!(
1168 derived_states
1169 .iter()
1170 .all(|x| x.format_id != derived.inner.format_type_id()),
1171 "Duplicate derived formats."
1172 );
1173
1174 let format_id = derived.inner.format_type_id();
1175 derived_formats.push((format_id, id));
1176 derived_states.push(DerivedFormatState {
1177 format_id,
1178 id,
1179 next_update: None,
1180 });
1181 }
1182
1183 if let FormatDeriveState::Base { derived_formats } =
1184 &mut self.objects.get_unchecked_mut(id as usize).derive_state
1185 {
1186 *derived_formats = derived_states;
1187 } else {
1188 unreachable_unchecked()
1189 }
1190
1191 let inner = Arc::new(DataInner {
1192 context_id: self.context_id,
1193 derived_formats,
1194 descriptor: descriptor.descriptor,
1195 format_id: TypeId::of::<F>(),
1196 id,
1197 label: descriptor.label,
1198 object_updater: self.object_update_sender.clone(),
1199 });
1200
1201 Data { inner }
1202 }
1203 }
1204
1205 pub fn submit(
1207 &mut self,
1208 buffer: CommandBuffer,
1209 context: &ContextHolder,
1210 ) -> CommandBufferSubmission {
1211 self.update_objects();
1212 let (submission, added_top_level_node) = self.submit_buffer(buffer);
1213 self.critical_top_level_nodes
1214 .and(&self.critical_nodes, &self.top_level_nodes);
1215 if added_top_level_node {
1216 self.notify_new_top_level_commands(context);
1217 }
1218 submission
1219 }
1220
1221 fn create_command_context(
1227 &self,
1228 context: &Arc<ContextHolder>,
1229 command_id: NodeId,
1230 ) -> CommandContext {
1231 unsafe {
1232 let computation = self.compute_graph.get_unchecked(command_id);
1233 CommandContext {
1234 inner: ManuallyDrop::new(CommandContextInner {
1235 command_id,
1236 command_buffer_label: self
1237 .active_command_buffers
1238 .get_unchecked(computation.command_buffer as usize)
1239 .label,
1240 context: context.clone(),
1241 label: computation.label,
1242 views: computation
1243 .views
1244 .iter()
1245 .map(|x| CommandContextView {
1246 id: x.id,
1247 mutable: x.mutable,
1248 value: RwCell::new(
1249 self.objects.get_unchecked(x.id as usize).value.get().cast(),
1250 ),
1251 })
1252 .collect(),
1253 }),
1254 }
1255 }
1256 }
1257
1258 fn prepare_next_command<const CRITICAL_ONLY: bool>(
1261 &mut self,
1262 context: &Arc<ContextHolder>,
1263 ) -> Option<Option<Box<dyn WorkUnit>>> {
1264 unsafe {
1265 if let Some(node) = self.pop_command::<CRITICAL_ONLY>() {
1266 let ctx = self.create_command_context(context, node);
1267 let computation = self.compute_graph.get_unchecked_mut(node);
1268
1269 match &mut computation.computation {
1270 Computation::Execute { command } => {
1271 let command = *command;
1272 let command_buffer = self
1273 .active_command_buffers
1274 .get_unchecked(computation.command_buffer as usize)
1275 .command_list
1276 .clone();
1277 Some(Some(Box::new(move || {
1278 command_buffer.get_unchecked(command).execute(ctx)
1279 })))
1280 }
1281 Computation::Map { inner } => {
1282 let value = take(inner).unwrap_unchecked();
1283 *value.command_context.get() = MaybeUninit::new(ctx);
1284 value.map_state.set_complete();
1285
1286 if let Some(mut value) = Arc::into_inner(value) {
1289 self.complete_command(node, context);
1290 let command_context = value.command_context.get_mut().assume_init_mut();
1291 ManuallyDrop::drop(&mut command_context.inner);
1292 forget(value);
1293 }
1294
1295 Some(None)
1296 }
1297 Computation::Update { object, updates } => {
1298 let derived = *object;
1299 let value = self.objects.get_unchecked(derived as usize);
1300 let FormatDeriveState::Derived {
1301 updater,
1302 parent,
1303 index,
1304 ..
1305 } = &value.derive_state
1306 else {
1307 unreachable_unchecked()
1308 };
1309
1310 let parent = *parent as usize;
1311 let index = *index as usize;
1312 let updater = updater.clone();
1313
1314 let format_state = if let FormatDeriveState::Base { derived_formats } =
1315 &mut self.objects.get_unchecked_mut(parent).derive_state
1316 {
1317 derived_formats.get_unchecked_mut(index)
1318 } else {
1319 unreachable_unchecked()
1320 };
1321
1322 if format_state.next_update == Some(node) {
1323 format_state.next_update = None;
1324 }
1325
1326 let updates = take(updates);
1327 Some(Some(Box::new(move || {
1328 let mut update_list = Vec::with_capacity(updates.len());
1329 update_list.extend(
1330 updates
1331 .iter()
1332 .map(|(buffer, entry)| buffer.get_unchecked(*entry).usage()),
1333 );
1334 updater.update(ctx, &update_list[..] as *const _);
1335 })))
1336 }
1337 }
1338 } else {
1339 if !self.compute_graph.is_empty() {
1340 self.stalled = true;
1341 }
1342
1343 None
1344 }
1345 }
1346 }
1347
1348 fn pop_command<const CRITICAL_ONLY: bool>(&mut self) -> Option<NodeId> {
1351 unsafe {
1352 if let Some(node) = self.critical_top_level_nodes.first_set_node() {
1353 debug_assert!(
1354 self.compute_graph.parents(node).next().is_none(),
1355 "Attempted to pop non-parent node."
1356 );
1357 self.critical_top_level_nodes.set_unchecked(node, false);
1358 self.top_level_nodes.set_unchecked(node, false);
1359 Some(node)
1360 } else if let Some(node) = (!CRITICAL_ONLY)
1361 .then(|| self.top_level_nodes.first_set_node())
1362 .flatten()
1363 {
1364 debug_assert!(
1365 self.compute_graph.parents(node).next().is_none(),
1366 "Attempted to pop non-parent node."
1367 );
1368 self.top_level_nodes.set_unchecked(node, false);
1369 Some(node)
1370 } else {
1371 None
1372 }
1373 }
1374 }
1375
1376 fn submit_buffer(&mut self, buffer: CommandBuffer) -> (CommandBufferSubmission, bool) {
1378 unsafe {
1379 let mut added_top_level_node = false;
1380 let unique_id = unique_id();
1381
1382 let command_buffer_id = if let Some(first_entry) = buffer.first_command_entry {
1383 let command_buffer_id = self.active_command_buffers.insert(ActiveCommandBuffer {
1384 command_list: Arc::new(buffer.command_list),
1385 label: buffer.label,
1386 remaining_commands: 0,
1387 unique_id,
1388 }) as u16;
1389
1390 let mut command_entry = Some(first_entry);
1391 while let Some(entry) = command_entry {
1392 let next = self
1393 .active_command_buffers
1394 .get_unchecked(command_buffer_id as usize)
1395 .command_list
1396 .get_unchecked(entry);
1397 command_entry = next.next_instance;
1398 added_top_level_node |= self.schedule_command(
1399 command_buffer_id,
1400 buffer.label,
1401 take(&mut *next.computation.get()).unwrap_unchecked(),
1402 next.label,
1403 next.first_view_entry,
1404 );
1405 }
1406
1407 command_buffer_id
1408 } else {
1409 0
1410 };
1411
1412 let submission = CommandBufferSubmission {
1413 command_buffer_id,
1414 context_id: self.context_id,
1415 unique_id,
1416 };
1417
1418 (submission, added_top_level_node)
1419 }
1420 }
1421
1422 fn schedule_command(
1424 &mut self,
1425 command_buffer_id: u16,
1426 command_buffer_label: Option<&'static str>,
1427 computation: Computation,
1428 label: Option<&'static str>,
1429 first_view_entry: Option<DynEntry<ViewEntry>>,
1430 ) -> bool {
1431 unsafe {
1432 let command_buffer = self
1433 .active_command_buffers
1434 .get_unchecked(command_buffer_id as usize)
1435 .command_list
1436 .clone();
1437 let node = self.compute_graph.vacant_node();
1438
1439 self.temporary_node_buffer.clear();
1441 let mut views = Vec::new();
1442 let mut view_entry = first_view_entry;
1443
1444 while let Some(entry) = view_entry {
1445 let next = command_buffer.get_unchecked(entry);
1446 let next_view = command_buffer.get_unchecked(next.view);
1447 assert!(
1448 next_view.context_id() == self.context_id,
1449 "View did not belong to this context."
1450 );
1451 views.push(ComputationViewReference {
1452 id: next_view.id(),
1453 view_holder: next.view,
1454 mutable: next_view.mutable(),
1455 });
1456
1457 view_entry = next.next_instance;
1458 let object = self.objects.get_unchecked_mut(next_view.id() as usize);
1459
1460 for computation in object.mutable_references.iter().copied() {
1462 assert!(!next_view.mutable() || computation != node,
1463 "Attempted to use two conflicting views of object{} with command{} in buffer{}",
1464 FormattedLabel(" ", object.label, ""),
1465 FormattedLabel(" ", label, ""),
1466 FormattedLabel(" ", command_buffer_label, ""));
1467 self.temporary_node_buffer.push(computation);
1468 }
1469
1470 if next_view.mutable() {
1471 for computation in object.immutable_references.iter().copied() {
1472 assert!(computation != node,
1473 "Attempted to use two conflicting views of object{} with command{} in buffer{}",
1474 FormattedLabel(" ", object.label, ""),
1475 FormattedLabel(" ", label, ""),
1476 FormattedLabel(" ", command_buffer_label, ""));
1477
1478 if let Some(derived) =
1479 &self.compute_graph.get_unchecked(computation).derived_update
1480 {
1481 if derived.parent == next_view.id() {
1482 let FormatDeriveState::Base { derived_formats } =
1483 &mut object.derive_state
1484 else {
1485 unreachable_unchecked()
1486 };
1487
1488 if derived_formats
1489 .get_unchecked(derived.index as usize)
1490 .next_update
1491 == Some(computation)
1492 {
1493 continue;
1494 }
1495 }
1496 }
1497
1498 self.temporary_node_buffer.push(computation);
1499 }
1500 }
1501
1502 if next_view.mutable() {
1504 &mut object.mutable_references
1505 } else {
1506 &mut object.immutable_references
1507 }
1508 .push(node);
1509 }
1510
1511 self.compute_graph.insert_unchecked(
1513 ComputationNode {
1514 computation: computation.clone(),
1515 command_buffer: command_buffer_id,
1516 derived_update: None,
1517 label,
1518 views,
1519 },
1520 &self.temporary_node_buffer,
1521 );
1522
1523 for i in 0..self.compute_graph.get_unchecked(node).views.len() {
1525 let view = &self
1526 .compute_graph
1527 .get_unchecked(node)
1528 .views
1529 .get_unchecked(i);
1530 let view_id = view.id;
1531 let view_holder = view.view_holder;
1532 let mutable = view.mutable;
1533 let object = self.objects.get_unchecked_mut(view.id as usize);
1534 let mut derived_nodes_to_add = Vec::new();
1535 match &mut object.derive_state {
1536 FormatDeriveState::Base { derived_formats } => {
1537 if mutable {
1538 for (index, format) in derived_formats.iter_mut().enumerate() {
1539 let derived = if let Some(derived) = format.next_update {
1540 self.compute_graph.add_parent_unchecked(node, derived);
1541 self.top_level_nodes.set_unchecked(derived, false);
1542 derived
1543 } else {
1544 let derived_computation = self.compute_graph.insert_unchecked(
1545 ComputationNode {
1546 computation: Computation::Update {
1547 object: format.id,
1548 updates: Vec::with_capacity(1),
1549 },
1550 command_buffer: command_buffer_id,
1551 derived_update: Some(DerivedFormatUpdate {
1552 parent: view_id,
1553 index: index as u32,
1554 }),
1555 label: None,
1556 views: vec![
1557 ComputationViewReference {
1558 id: view_id,
1559 view_holder,
1560 mutable: false,
1561 },
1562 ComputationViewReference {
1563 id: format.id,
1564 view_holder,
1565 mutable: true,
1566 },
1567 ],
1568 },
1569 &[node],
1570 );
1571 format.next_update = Some(derived_computation);
1572 object.immutable_references.push(derived_computation);
1573 derived_nodes_to_add.push((format.id, derived_computation));
1574 self.active_command_buffers
1575 .get_unchecked_mut(command_buffer_id as usize)
1576 .remaining_commands += 1;
1577 derived_computation
1578 };
1579
1580 let Computation::Update { updates, .. } =
1581 &mut self.compute_graph.get_unchecked_mut(derived).computation
1582 else {
1583 unreachable_unchecked()
1584 };
1585
1586 updates.push((command_buffer.clone(), view_holder));
1587 }
1588 }
1589 }
1590 &mut FormatDeriveState::Derived { parent, index, .. } => {
1591 if let FormatDeriveState::Base { derived_formats } =
1592 &mut self.objects.get_unchecked_mut(parent as usize).derive_state
1593 {
1594 derived_formats
1595 .get_unchecked_mut(index as usize)
1596 .next_update = None;
1597 } else {
1598 unreachable_unchecked()
1599 }
1600 }
1601 }
1602
1603 for (id, node) in derived_nodes_to_add {
1604 self.objects
1605 .get_unchecked_mut(id as usize)
1606 .mutable_references
1607 .push(node);
1608 }
1609 }
1610
1611 self.top_level_nodes.resize_for(&self.compute_graph);
1612 self.critical_nodes.resize_for(&self.compute_graph);
1613
1614 let top_level = if self.temporary_node_buffer.is_empty() {
1615 self.top_level_nodes.set_unchecked(node, true);
1616 true
1617 } else {
1618 false
1619 };
1620
1621 if let Computation::Map { inner } = computation {
1622 let inner_ref = inner.as_ref().unwrap_unchecked();
1623 assert!(
1624 inner_ref.context_id == self.context_id,
1625 "Attempted to map object in incorrect context."
1626 );
1627 inner_ref.map_state.set_queued(node);
1628 self.mark_critical(node);
1629 }
1630
1631 self.active_command_buffers
1632 .get_unchecked_mut(command_buffer_id as usize)
1633 .remaining_commands += 1;
1634
1635 top_level
1636 }
1637 }
1638
1639 unsafe fn mark_critical(&mut self, node: NodeId) {
1646 self.critical_nodes.set_unchecked(node, true);
1647 while let Some(parent) = self.temporary_node_buffer.pop() {
1648 if !self.critical_nodes.get_unchecked(parent) {
1649 self.temporary_node_buffer
1650 .extend(self.compute_graph.parents(parent));
1651 self.critical_nodes.set_unchecked(parent, true);
1652 }
1653 }
1654 }
1655
1656 unsafe fn complete_command(&mut self, id: NodeId, context: &ContextHolder) {
1658 self.temporary_node_buffer.clear();
1659 self.temporary_node_buffer
1660 .extend(self.compute_graph.children_unchecked(id));
1661 self.critical_nodes.set_unchecked(id, false);
1662 let computation = self.compute_graph.pop_unchecked(id);
1663
1664 for child in self.temporary_node_buffer.iter().copied() {
1665 if self.compute_graph.parents_unchecked(child).next().is_none() {
1666 self.top_level_nodes.set_unchecked(child, true);
1667 }
1668 }
1669
1670 for view in computation.views {
1671 let object = self.objects.get_unchecked_mut(view.id as usize);
1672 let view_vec = if view.mutable {
1673 &mut object.mutable_references
1674 } else {
1675 &mut object.immutable_references
1676 };
1677 view_vec.swap_remove(view_vec.iter().position(|x| *x == id).unwrap_unchecked());
1678 }
1679
1680 self.critical_top_level_nodes
1681 .and(&self.top_level_nodes, &self.critical_nodes);
1682
1683 let command_list = self
1684 .active_command_buffers
1685 .get_unchecked_mut(computation.command_buffer as usize);
1686 command_list.remaining_commands -= 1;
1687 if command_list.remaining_commands == 0 {
1688 self.active_command_buffers
1689 .remove(computation.command_buffer as usize);
1690 }
1691
1692 if !self.temporary_node_buffer.is_empty() {
1693 self.notify_new_top_level_commands(context);
1694 }
1695 }
1696
1697 fn update_objects(&mut self) {
1699 unsafe {
1700 while let Ok(update) = self.object_updates.try_recv() {
1701 match update {
1702 ObjectUpdate::DropData { id } => {
1703 let FormatDeriveState::Base { derived_formats } =
1704 self.objects.remove(id as usize).derive_state
1705 else {
1706 unreachable_unchecked()
1707 };
1708
1709 for format in derived_formats {
1710 self.objects.remove(format.id as usize);
1711 }
1712 }
1713 }
1714 }
1715 }
1716 }
1717
1718 fn notify_new_top_level_commands(&mut self, context: &ContextHolder) {
1720 if self.stalled {
1721 self.stalled = false;
1722 context.change_notifier.notify();
1723 }
1724
1725 if self.critical_top_level_nodes.first_set_node().is_some() {
1726 context.change_listener.notify_all();
1727 }
1728 }
1729}
1730
1731struct DataHolder {
1733 pub derive_state: FormatDeriveState,
1735 pub label: Option<&'static str>,
1737 pub immutable_references: Vec<NodeId>,
1739 pub mutable_references: Vec<NodeId>,
1741 pub value: Pin<Box<UnsafeCell<dyn Any + Send + Sync>>>,
1743}
1744
1745struct DataInner<K: Kind> {
1747 pub context_id: u64,
1749 pub derived_formats: Vec<(TypeId, u32)>,
1751 pub descriptor: K::FormatDescriptor,
1753 pub format_id: TypeId,
1755 pub id: u32,
1757 pub label: Option<&'static str>,
1759 pub object_updater: Sender<ObjectUpdate>,
1761}
1762
1763impl<K: Kind> Drop for DataInner<K> {
1764 fn drop(&mut self) {
1765 let _ = self
1766 .object_updater
1767 .send(ObjectUpdate::DropData { id: self.id });
1768 }
1769}
1770
1771struct DerivedFormatUpdate {
1773 pub parent: u32,
1775 pub index: u32,
1777}
1778
1779struct DerivedFormatState {
1781 pub format_id: TypeId,
1783 pub id: u32,
1785 pub next_update: Option<NodeId>,
1787}
1788
1789enum FormatDeriveState {
1792 Base {
1794 derived_formats: Vec<DerivedFormatState>,
1796 },
1797 Derived {
1799 parent: u32,
1801 index: u8,
1803 updater: Arc<dyn DerivedFormatUpdater>,
1805 },
1806}
1807
1808struct FormattedLabel(pub &'static str, pub Option<&'static str>, pub &'static str);
1811
1812impl std::fmt::Display for FormattedLabel {
1813 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1814 if let Some(label) = &self.1 {
1815 f.write_fmt(format_args!("{}'{}'{}", self.0, label, self.2))
1816 } else {
1817 Ok(())
1818 }
1819 }
1820}
1821
1822struct MappedInner {
1824 pub context_id: u64,
1826 pub command_context: UnsafeCell<MaybeUninit<CommandContext>>,
1828 pub label: Option<&'static str>,
1830 pub map_state: MapObjectState,
1832}
1833
1834impl Drop for MappedInner {
1835 fn drop(&mut self) {
1836 unsafe {
1837 self.command_context.get_mut().assume_init_drop();
1838 }
1839 }
1840}
1841
1842unsafe impl Send for MappedInner {}
1843unsafe impl Sync for MappedInner {}
1844
1845struct MapObjectStateQuery {
1847 pub complete: bool,
1849 pub node: NodeId,
1851 pub queued: bool,
1853}
1854
1855#[derive(Default)]
1857struct MapObjectState(AtomicU32);
1858
1859impl MapObjectState {
1860 const MAPPING_QUEUED: u32 = 1 << 16;
1862 const MAPPING_COMPLETE: u32 = 1 << 17;
1864
1865 pub fn set_queued(&self, node: NodeId) {
1867 self.0.store(
1868 Self::MAPPING_QUEUED | (u16::from(node) as u32),
1869 Ordering::Release,
1870 );
1871 }
1872
1873 pub fn set_complete(&self) {
1875 self.0.fetch_or(Self::MAPPING_COMPLETE, Ordering::Release);
1876 }
1877
1878 pub fn get(&self) -> MapObjectStateQuery {
1880 let value = self.0.load(Ordering::Acquire);
1881 let complete = (value & Self::MAPPING_COMPLETE) != 0;
1882 let queued = (value & Self::MAPPING_QUEUED) != 0;
1883 let node = (value as u16).into();
1884
1885 MapObjectStateQuery {
1886 complete,
1887 node,
1888 queued,
1889 }
1890 }
1891}
1892
1893enum ObjectUpdate {
1895 DropData {
1897 id: u32,
1899 },
1900}
1901
1902struct ViewEntry {
1904 pub next_instance: Option<DynEntry<ViewEntry>>,
1906 pub view: DynEntry<dyn ViewHolder>,
1908}
1909
1910struct TypedDerivedFormatUpdater<F: Format, D: DerivedDescriptor<F>> {
1912 pub descriptor: D,
1914 pub marker: PhantomData<fn() -> (F, D)>,
1916}
1917
1918impl<F: Format, D: DerivedDescriptor<F>> DerivedFormatUpdater for TypedDerivedFormatUpdater<F, D> {
1919 unsafe fn allocate(&self, descriptor: *const ()) -> Box<UnsafeCell<dyn Any + Send + Sync>> {
1920 Box::new(UnsafeCell::new(<D::Format as Format>::allocate(
1921 &*(descriptor as *const _),
1922 )))
1923 }
1924
1925 fn format_type_id(&self) -> TypeId {
1926 TypeId::of::<D::Format>()
1927 }
1928
1929 unsafe fn update(&self, context: CommandContext, usages: *const [*const ()]) {
1930 self.descriptor.update(
1931 &mut *context.inner.views.get_unchecked(1).value.borrow().cast(),
1932 &*context
1933 .inner
1934 .views
1935 .get_unchecked(0)
1936 .value
1937 .borrow()
1938 .cast_const()
1939 .cast(),
1940 &*transmute::<_, *const [_]>(usages),
1941 );
1942 }
1943}
1944
1945struct TypedViewHolder<M: UsageMutability, F: Format> {
1947 view: View<F>,
1949 descriptor: M::Descriptor<F>,
1951}
1952
1953impl<M: UsageMutability, F: Format> ViewHolder for TypedViewHolder<M, F> {
1954 fn context_id(&self) -> u64 {
1955 self.view.inner.inner.context_id
1956 }
1957
1958 fn id(&self) -> u32 {
1959 self.view.id
1960 }
1961
1962 fn mutable(&self) -> bool {
1963 TypeId::of::<M>() == TypeId::of::<Mut>()
1964 }
1965
1966 fn usage(&self) -> *const () {
1967 &self.descriptor as *const _ as *const _
1968 }
1969}
1970
1971mod private {
1973 use super::*;
1974
1975 pub trait ViewUsageInner {
1977 fn add_to_list(&self, command_list: &mut DynVec) -> DynEntry<dyn ViewHolder>;
1979 }
1980
1981 pub trait UsageMutability: Mutability {
1983 type Descriptor<F: Format>: Send + Sync;
1985 }
1986
1987 impl UsageMutability for Const {
1988 type Descriptor<F: Format> = ();
1989 }
1990
1991 impl UsageMutability for Mut {
1992 type Descriptor<F: Format> = <F::Kind as Kind>::UsageDescriptor;
1993 }
1994}
1995
1996#[cfg(test)]
1997mod tests {
1998 use super::*;
1999
2000 #[derive(Debug)]
2001 pub struct DataDescriptor {
2002 pub initial_value: u32,
2003 }
2004
2005 pub struct MyData;
2006
2007 impl Kind for MyData {
2008 type FormatDescriptor = DataDescriptor;
2009 type UsageDescriptor = u32;
2010 }
2011
2012 #[derive(Debug)]
2013 pub struct Primary(pub i32);
2014
2015 impl Format for Primary {
2016 type Kind = MyData;
2017
2018 fn allocate(descriptor: &<Self::Kind as Kind>::FormatDescriptor) -> Self {
2019 Self(descriptor.initial_value as i32)
2020 }
2021 }
2022
2023 #[derive(Debug)]
2024 pub struct DerivedAccelerationStructure(pub i32);
2025
2026 impl Format for DerivedAccelerationStructure {
2027 type Kind = MyData;
2028
2029 fn allocate(descriptor: &<Self::Kind as Kind>::FormatDescriptor) -> Self {
2030 Self(2 * descriptor.initial_value as i32)
2031 }
2032 }
2033
2034 pub struct UpdateAccelerationFromPrimary;
2035
2036 impl DerivedDescriptor<Primary> for UpdateAccelerationFromPrimary {
2037 type Format = DerivedAccelerationStructure;
2038
2039 fn update(&self, data: &mut Self::Format, parent: &Primary, _usage: &[&u32]) {
2040 data.0 = 2 * parent.0;
2043 }
2044 }
2045
2046 #[test]
2047 #[should_panic]
2048 fn test_panic_on_conflicting_usage() {
2049 let ctx = DataFrostContext::new(ContextDescriptor {
2050 label: Some("my context"),
2051 });
2052 let data = ctx.allocate::<Primary>(AllocationDescriptor {
2053 descriptor: DataDescriptor { initial_value: 23 },
2054 label: Some("my int"),
2055 derived_formats: &[],
2056 });
2057
2058 let mut command_buffer = CommandBuffer::new(CommandBufferDescriptor {
2059 label: Some("my command buffer"),
2060 });
2061 let view = data.view::<Primary>();
2062
2063 command_buffer.schedule(CommandDescriptor {
2064 label: Some("Test command"),
2065 views: &[&view.as_const(), &view.as_mut(25)],
2066 command: |_| {},
2067 });
2068
2069 ctx.submit(command_buffer);
2070 }
2071
2072 #[test]
2073 fn test_allow_multiple_const_usage() {
2074 let ctx = DataFrostContext::new(ContextDescriptor {
2075 label: Some("my context"),
2076 });
2077 let data = ctx.allocate::<Primary>(AllocationDescriptor {
2078 descriptor: DataDescriptor { initial_value: 23 },
2079 label: Some("my int"),
2080 derived_formats: &[],
2081 });
2082
2083 let mut command_buffer = CommandBuffer::new(CommandBufferDescriptor {
2084 label: Some("my command buffer"),
2085 });
2086 let view_a = data.view::<Primary>();
2087 let view_b = data.view::<Primary>();
2088
2089 command_buffer.schedule(CommandDescriptor {
2090 label: Some("Test command"),
2091 command: |_| {},
2092 views: &[&view_a.as_const(), &view_b.as_const()],
2093 });
2094
2095 ctx.submit(command_buffer);
2096 }
2097
2098 #[test]
2099 fn test_single_mappings() {
2100 let ctx = DataFrostContext::new(ContextDescriptor {
2101 label: Some("my context"),
2102 });
2103 let data = ctx.allocate::<Primary>(AllocationDescriptor {
2104 descriptor: DataDescriptor { initial_value: 23 },
2105 label: Some("my int"),
2106 derived_formats: &[Derived::new(UpdateAccelerationFromPrimary)],
2107 });
2108
2109 let mut command_buffer = CommandBuffer::new(CommandBufferDescriptor {
2110 label: Some("my command buffer"),
2111 });
2112 let view = data.view::<Primary>();
2113
2114 let view_clone = view.clone();
2115 command_buffer.schedule(CommandDescriptor {
2116 label: Some("Test command"),
2117 command: move |ctx| {
2118 let mut vc = ctx.get_mut(&view_clone);
2119 vc.0 += 4;
2120 },
2121 views: &[&view.as_mut(4)],
2122 });
2123
2124 let mapping1 = command_buffer.map(&data.view::<DerivedAccelerationStructure>().as_const());
2125
2126 let view_clone = view.clone();
2127 command_buffer.schedule(CommandDescriptor {
2128 label: Some("Test command"),
2129 command: move |ctx| {
2130 let mut vc = ctx.get_mut(&view_clone);
2131 vc.0 += 2;
2132 },
2133 views: &[&view.as_mut(2)],
2134 });
2135
2136 let mapping2 = command_buffer.map(&data.view::<DerivedAccelerationStructure>().as_const());
2137 ctx.submit(command_buffer);
2138
2139 let value = ctx.get(&mapping1);
2140 assert_eq!(value.0, 54);
2141 drop(value);
2142 drop(mapping1);
2143 let value = ctx.get(&mapping2);
2144 assert_eq!(value.0, 58);
2145 drop(value);
2146 drop(mapping2);
2147 }
2148
2149 #[test]
2150 fn test_skip_irrelevant_command() {
2151 let execution_count = Arc::new(AtomicU32::new(0));
2152 let ctx = DataFrostContext::new(ContextDescriptor {
2153 label: Some("my context"),
2154 });
2155 let data = ctx.allocate::<Primary>(AllocationDescriptor {
2156 descriptor: DataDescriptor { initial_value: 23 },
2157 label: Some("my int"),
2158 derived_formats: &[Derived::new(UpdateAccelerationFromPrimary)],
2159 });
2160
2161 let mut command_buffer = CommandBuffer::new(CommandBufferDescriptor {
2162 label: Some("my command buffer"),
2163 });
2164 let view = data.view::<Primary>();
2165
2166 let ex_clone = execution_count.clone();
2167 let view_clone = view.clone();
2168 command_buffer.schedule(CommandDescriptor {
2169 label: Some("Test command"),
2170 command: move |ctx| {
2171 let mut vc = ctx.get_mut(&view_clone);
2172 vc.0 += 4;
2173 ex_clone.fetch_add(1, Ordering::Relaxed);
2174 },
2175 views: &[&view.as_mut(4)],
2176 });
2177
2178 let ex_clone = execution_count.clone();
2179 command_buffer.schedule(CommandDescriptor {
2180 label: Some("Test command"),
2181 command: move |_| {
2182 ex_clone.fetch_add(1, Ordering::Relaxed);
2183 },
2184 views: &[&view.as_const()],
2185 });
2186
2187 let mapping = command_buffer.map(&data.view::<DerivedAccelerationStructure>().as_const());
2188 ctx.submit(command_buffer);
2189
2190 ctx.get(&mapping);
2191 assert_eq!(execution_count.load(Ordering::Relaxed), 1);
2192 }
2193}