datafrost/
lib.rs

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
12//! #### Data format and acceleration structure management
13//!
14//! `datafrost` is a data-oriented resource management and scheduling library. It implements a graphics API-inspired interface that allows one to cleanly and efficiently:
15//!
16//! - Create primary data objects, and define "derived" datatypes whose contents are generated from the primary format.
17//! - Track how a primary object changes and automatically update the affected parts of the derived formats.
18//! - Schedule commands to asynchronously and concurrently read or modify data objects.
19//!   - `datafrost` guarantees optimal scheduling by building a directed acyclic graph to represent pending operations.
20//!   - Multiple commands which reference different data, or immutably reference the same data, will execute in parallel.
21//!   - Commands which mutably access the same data run in sequence, without the possibility of data races.
22//! - Map the contents of data objects and read their results on the main thread.
23//!
24//! ## Usage
25//!
26//! The following is an abridged example of how to use `datafrost`. The full code may be found in the
27//! [examples folder](/examples/derived.rs). To begin, we define the data formats that our code will use:
28//!
29//! ```ignore
30//! use datafrost::*;
31//! use std::ops::*;
32//!
33//! /// First, we define a general "kind" of data that our program will use.
34//! /// In this case, let's imagine that we want to efficiently deal with
35//! /// arrays of numbers.
36//! pub struct NumberArray;
37//!
38//! /// Defines the layout of an array of numbers.
39//! pub struct NumberArrayDescriptor {
40//!     /// The length of the array.
41//!     pub len: usize
42//! }
43//!
44//! impl Kind for NumberArray { .. }
45//!
46//! /// Next, we define the primary data format that we would like
47//! /// to use and modify - an array of specifically `u32`s.
48//! pub struct PrimaryArray(Vec<u32>);
49//!
50//! impl Format for PrimaryArray { .. }
51//!
52//! /// Now, let's imagine that we want to efficiently maintain an
53//! /// acceleration structure containing all of the numbers in
54//! /// the array, but doubled. So, we define the format.
55//! pub struct DoubledArray(Vec<u32>);
56//!
57//! impl Format for DoubledArray { .. }
58//!
59//! /// Our goal is for `datafrost` to automatically update the doubled
60//! /// array whenever the primary array changes. Thus, we implement
61//! /// a way for it do so.
62//! pub struct DoublePrimaryArray;
63//!
64//! impl DerivedDescriptor<PrimaryArray> for DoublePrimaryArray {
65//!     type Format = DoubledArray;
66//!
67//!     fn update(&self, data: &mut DoubledArray, parent: &PrimaryArray, usages: &[&Range<usize>]) {
68//!         // Loop over all ranges of the array that have changed, and
69//!         // for each value in the range, recompute the data.
70//!         for range in usages.iter().copied() {
71//!             for i in range.clone() {
72//!                 data.0[i] = 2 * parent.0[i];
73//!             }
74//!         }
75//!     }
76//! }
77//! ```
78//!
79//! Now that our data and its derived formats are defined, we can create instances of
80//! it and schedule commands to act upon the data:
81//!
82//! ```ignore
83//! // Create a new context.
84//! let ctx = DataFrostContext::new(ContextDescriptor {
85//!     label: Some("my context")
86//! });
87//!
88//! // Allocate a new primary array object, which has a doubled
89//! // array as a derived format.
90//! let data = ctx.allocate::<PrimaryArray>(AllocationDescriptor {
91//!     descriptor: NumberArrayDescriptor { len: 7 },
92//!     label: Some("my data"),
93//!     derived_formats: &[Derived::new(DoublePrimaryArray)]
94//! });
95//!
96//! // Create a command buffer to record operations to execute
97//! // on our data.
98//! let mut command_buffer = CommandBuffer::new(CommandBufferDescriptor { label: Some("my command buffer") });
99//!
100//! // Schedule a command to fill the primary number array with some data.
101//! let view = data.view::<PrimaryArray>();
102//! let view_clone = view.clone();
103//! command_buffer.schedule(CommandDescriptor {
104//!     label: Some("fill array"),
105//!     views: &[&view.as_mut(4..6)],
106//!     command: move |ctx| ctx.get_mut(&view_clone).0[4..6].fill(33)
107//! });
108//!
109//! // Schedule a command to map the contents of the derived acceleration structure
110//! // so that we may view them synchronously.
111//! let derived = command_buffer.map(&data.view::<DoubledArray>().as_const());
112//!
113//! // Submit the buffer for processing.
114//! ctx.submit(Some(command_buffer));
115//!
116//! // The doubled acceleration structure automatically contains the
117//! // correct, up-to-date data!
118//! assert_eq!(&[0, 0, 0, 0, 66, 66, 0], &ctx.get(&derived).0[..]);
119//! ```
120
121use 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
142/// Defines a dynamic vector type for efficient allocation of variable-sized, hetegenous objects.
143mod dyn_vec;
144
145/// Implements a directed acyclic graph structure for work scheduling.
146mod graph;
147
148/// Defines a way to create unique IDs.
149mod unique_id;
150
151/// Denotes a general class of formats, which all share similar data.
152/// Formats of the same kind may be derived from one another.
153pub trait Kind: 'static + Send + Sync {
154    /// A structure which holds properties common to all formats of this kind.
155    type FormatDescriptor: Send + Sync;
156
157    /// A structure which describes the parts of a format that have changed.
158    type UsageDescriptor: Send + Sync + Sized;
159}
160
161/// A certain format of data.
162pub trait Format: 'static + Send + Sync + Sized {
163    /// The kind of data that this format represents.
164    type Kind: Kind;
165
166    /// Allocates a new object of this format for the provided descriptor with
167    /// unspecified contents.
168    fn allocate(descriptor: &<Self::Kind as Kind>::FormatDescriptor) -> Self;
169}
170
171/// Allows a format to act as a maintained "copy" of a parent
172/// by synchronizing its contents with those of the parent.
173pub trait DerivedDescriptor<F: Format>: 'static + Send + Sync + Sized {
174    /// The format that should be created for this descriptor.
175    type Format: Format<Kind = F::Kind>;
176
177    /// Updates the given data based upon the portions of the parent that have changed.
178    fn update(
179        &self,
180        data: &mut Self::Format,
181        parent: &F,
182        usages: &[&<F::Kind as Kind>::UsageDescriptor],
183    );
184}
185
186/// A type-erased instance of [`View`] that is used to specify
187/// data usage in a [`CommandDescriptor`].
188pub trait ViewUsage: Send + Sync + ViewUsageInner {}
189
190/// Determines how a new data object will be allocated.
191pub struct AllocationDescriptor<'a, F: Format> {
192    /// The descriptor describing the layout of the data.
193    pub descriptor: <F::Kind as Kind>::FormatDescriptor,
194    /// An optional label to associate with the object.
195    pub label: Option<&'static str>,
196    /// Derived formats that should be set up to track the parent format.
197    pub derived_formats: &'a [Derived<F>],
198}
199
200/// Records a list of operations that should be executed on formatted data.
201pub struct CommandBuffer {
202    /// The internal dynamic vector that stores command information.
203    command_list: DynVec,
204    /// A handle to the first command in the list.
205    first_command_entry: Option<DynEntry<CommandEntry>>,
206    /// The label of this command buffer.
207    label: Option<&'static str>,
208    /// A handle to the last command in the list.
209    last_command_entry: Option<DynEntry<CommandEntry>>,
210}
211
212impl CommandBuffer {
213    /// Creates a new command buffer with the provided descriptor.
214    pub fn new(descriptor: CommandBufferDescriptor) -> Self {
215        /// The default amount of space to allocate for a new command buffer.
216        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    /// Requires that all referenced views are available and ready
227    /// at this point in the buffer.
228    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    /// Maps a format for synchronous viewing.
245    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    /// Schedules a command to execute on format data.
287    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    /// Creates a linked list of views in the command list.
309    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    /// Updates the first and last command entries after the provided command
341    /// has been added to the command list.
342    ///
343    /// # Safety
344    ///
345    /// The `self.last_command_entry` field, if `Some`, must refer to a valid command list value.
346    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/// Specifies the parameters of a new [`CommandBuffer`].
359#[derive(Copy, Clone, Debug, Default)]
360pub struct CommandBufferDescriptor {
361    /// An optional label to associate with the object.
362    pub label: Option<&'static str>,
363}
364
365/// Describes the present status of a submitted command buffer.
366#[derive(Copy, Clone, Debug, Default)]
367pub struct CommandBufferStatus {
368    /// The number of commands left to process in this command buffer.
369    pub incomplete_commands: u32,
370}
371
372impl CommandBufferStatus {
373    /// Whether all commands in this command buffer have been processed.
374    pub fn complete(&self) -> bool {
375        self.incomplete_commands == 0
376    }
377}
378
379/// Uniquely identifies a submitted command buffer,
380/// allowing one to query its completion status.
381#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
382pub struct CommandBufferSubmission {
383    /// The unique ID of the command buffer.
384    unique_id: u64,
385    /// The ID of the context that created this command buffer.
386    context_id: u64,
387    /// The ID of the command buffer within the `Slab`.
388    command_buffer_id: u16,
389}
390
391/// Allows for interacting with format data during command execution.
392/// When this object is dropped, a command is considered complete.
393
394pub struct CommandContext {
395    /// The inner context state.
396    inner: ManuallyDrop<CommandContextInner>,
397}
398
399impl CommandContext {
400    /// Immutably gets the data referenced by the view.
401    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    /// Mutably gets the data referenced by the view, and records the usage for updating derived formats.
409    /// This function will panic if `view` refers to a derived format.
410    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    /// Gets the proper reference to the view, or panics if the view was invalid.
418    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
462/// Describes a command to execute.
463pub struct CommandDescriptor<'a, C: 'static + Send + Sync + FnOnce(CommandContext)> {
464    /// The label associated with this command.
465    pub label: Option<&'static str>,
466    /// The command to execute asynchronously.
467    pub command: C,
468    /// A list of views that the command will access via the [`CommandContext`].
469    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/// Determines how a [`DataFrostContext`] should behave.
483#[derive(Copy, Clone, Debug, Default)]
484pub struct ContextDescriptor {
485    /// An optional label to associate with the object.
486    pub label: Option<&'static str>,
487}
488
489/// References an object of a specific [`Kind`]. The object is backed
490/// by a single primary format and some number of derived formats.
491pub struct Data<K: Kind> {
492    /// The inner representation of this object.
493    inner: Arc<DataInner<K>>,
494}
495
496impl<K: Kind> Data<K> {
497    /// Creates a view of this data of the given format and mutability.
498    /// The format must either be the primary format or one of the derived
499    /// formats specified during object creation. If this is a mutable view,
500    /// then the format must be the primary format. Using views with invalid
501    /// mutability or formats will lead to panics when [`DataFrostContext::submit`]
502    /// is called.
503    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            //assert!(TypeId::of::<M>() == TypeId::of::<Const>(), "Attempted to mutably access derived format {} of object{}", type_name::<F>(), FormattedLabel(" ", self.inner.label, ""));
514            (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/// Manages a collection of formatted data, coordinates the execution of commands
573/// against the data, and automatically updates derived formats using the results
574/// of those commands.
575#[derive(Clone)]
576pub struct DataFrostContext {
577    /// The shared data that composes this context.
578    holder: Arc<ContextHolder>,
579}
580
581impl DataFrostContext {
582    /// Allocates a new, empty context.
583    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    /// Creates a new object from the provided descriptor. Objects are also created for each derived format,
614    /// and will automatically update whenever this object is changed.
615    pub fn allocate<F: Format>(&self, descriptor: AllocationDescriptor<F>) -> Data<F::Kind> {
616        self.inner().allocate(descriptor)
617    }
618
619    /// Immutably gets the data referenced by the mapping. This function will block if the mapping is not yet available.
620    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    /// Mutably gets the data referenced by the mapping. This function will block if the mapping is not yet available.
633    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    /// Checks the current status of an executing command buffer.
643    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    /// Schedules the provided command buffer for execution.
659    pub fn submit(&self, buffer: CommandBuffer) -> CommandBufferSubmission {
660        self.inner().submit(buffer, &self.holder)
661    }
662
663    /// Gets the inner data of this context.
664    fn inner(&self) -> MutexGuard<ContextInner> {
665        self.holder
666            .inner
667            .lock()
668            .expect("Failed to obtain inner context.")
669    }
670
671    /// Waits for a mapping to become available.
672    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
756/// Marks a derived format that should be accessible and kept
757/// automatically up-to-date when the parent object changes.
758pub struct Derived<F: Format> {
759    /// The inner implementation used to allocate and update derived objects of this format.
760    inner: Arc<dyn DerivedFormatUpdater>,
761    /// A marker for generic bounds.
762    marker: PhantomData<fn() -> F>,
763}
764
765impl<F: Format> Derived<F> {
766    /// Specifies how a derived object should be created to track an object of type `F`.
767    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
793/// A handle created by calling [`CommandBuffer::map`] which allows
794/// for synchronously accessing the data of a [`View`].
795pub struct Mapped<M: Mutability, F: Format> {
796    /// The inner state used to track the mapping.
797    inner: Arc<MappedInner>,
798    /// The view associating with this mapping.
799    view: View<F>,
800    /// Marker data.
801    marker: PhantomData<fn() -> M>,
802}
803
804/// References a specified format underlying a [`Data`] instance.
805pub struct View<F: Format> {
806    /// The inner representation of this object.
807    inner: Data<F::Kind>,
808    /// The index to which this format refers.
809    id: u32,
810    /// Whether this is a derived format.
811    derived: bool,
812    /// A marker for generic bounds.
813    marker: PhantomData<fn() -> F>,
814}
815
816impl<F: Format> View<F> {
817    /// Marks this view as being used immutably from a command.
818    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    /// Marks this view as being used mutably from a command, with the given usage.
827    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    /// Gets the data to which this view refers.
836    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
880/// Declares how a command will use a view. Created by calling [`View::as_const`]
881/// or [`View::as_mut`].
882pub struct ViewDescriptor<'a, M: UsageMutability, F: Format> {
883    /// The underlying view.
884    view: &'a View<F>,
885    /// The usage for the view.
886    descriptor: SyncUnsafeCell<Option<M::Descriptor<F>>>,
887    /// Whether the usage has been moved into the command buffer yet.
888    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
909/// A guard which allows access to the data of a format.
910pub struct ViewRef<'a, M: Mutability, F: Format> {
911    /// The inner reference to the data.
912    reference: RwCellGuard<'a, M, *mut ()>,
913    /// Marker data.
914    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
937/// Implements the ability to create and update a derived resource.
938trait DerivedFormatUpdater: 'static + Send + Sync {
939    /// Allocates an instance of the derived format.
940    unsafe fn allocate(&self, descriptor: *const ()) -> Box<UnsafeCell<dyn Any + Send + Sync>>;
941
942    /// The type ID of the derived format.
943    fn format_type_id(&self) -> TypeId;
944
945    /// Updates the derived format for the given usages.
946    ///
947    /// # Safety
948    ///
949    /// This function must be called with a context that contains an immutable
950    /// view (the parent) and a mutable view (the derived) object.
951    /// The set of usages must match the usage descriptor type shared
952    /// by both the parent and child.
953    unsafe fn update(&self, context: CommandContext, usages: *const [*const ()]);
954}
955
956/// A user-specified command that may be executed.
957trait ExecutableCommand: 'static + Send + Sync {
958    /// Executes this command.
959    ///
960    /// # Safety
961    ///
962    /// This function must only be called once.
963    unsafe fn execute(&self, ctx: CommandContext);
964}
965
966/// Determines how a command will view an object.
967trait ViewHolder: 'static + Send + Sync {
968    /// The ID of the context associated with this view.
969    fn context_id(&self) -> u64;
970
971    /// The ID of the object refernced by this view.
972    fn id(&self) -> u32;
973
974    /// Whether this is a mutable view.
975    fn mutable(&self) -> bool;
976
977    /// Gets a pointer to the usage of this view, if any.
978    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
993/// Holds a command buffer which describes work to perform on objects.
994struct ActiveCommandBuffer {
995    /// A reference to the list of commands used by this buffer.
996    command_list: Arc<DynVec>,
997    /// An optional label for the command buffer.
998    label: Option<&'static str>,
999    /// The set of commands that are left before this command buffer may be discarded.
1000    remaining_commands: u32,
1001    /// A unique ID identifying this buffer instance.
1002    unique_id: u64,
1003}
1004
1005/// Holds the inner state for a command context.
1006struct CommandContextInner {
1007    /// The ID of the command that is currently executing.
1008    pub command_id: NodeId,
1009    /// A reference to the context.
1010    pub context: Arc<ContextHolder>,
1011    /// An optional label describing the command.
1012    pub label: Option<&'static str>,
1013    /// An optional label describing the command buffer.
1014    pub command_buffer_label: Option<&'static str>,
1015    /// The list of views that this context references.
1016    pub views: Vec<CommandContextView>,
1017}
1018
1019/// Stores information about a view accessible from a command context.
1020struct CommandContextView {
1021    /// The ID of the view.
1022    pub id: u32,
1023    /// Whether the view is mutable.
1024    pub mutable: bool,
1025    /// A cell containing a pointer to the view.
1026    pub value: RwCell<*mut ()>,
1027}
1028
1029/// Describes a single command within a command list.
1030struct CommandEntry {
1031    /// The computation to complete.
1032    pub computation: SyncUnsafeCell<Option<Computation>>,
1033    /// The first view entry in the views linked list.
1034    pub first_view_entry: Option<DynEntry<ViewEntry>>,
1035    /// The label of this command.
1036    pub label: Option<&'static str>,
1037    /// The next command entry in the command list.
1038    pub next_instance: Option<DynEntry<CommandEntry>>,
1039}
1040
1041/// Describes an operation which corresponds to a node
1042/// in the computation graph.
1043#[derive(Clone)]
1044enum Computation {
1045    /// A command must be executed against object data.
1046    Execute {
1047        /// The command to execute.
1048        command: DynEntry<dyn ExecutableCommand>,
1049    },
1050    /// An object should be mapped and made available synchronously.
1051    Map {
1052        /// The inner context to map.
1053        inner: Option<Arc<MappedInner>>,
1054    },
1055    /// A derived object's data must be updated.
1056    Update {
1057        /// The object to update.
1058        object: u32,
1059        /// The list of updates that this object should reference.
1060        updates: Vec<(Arc<DynVec>, DynEntry<dyn ViewHolder>)>,
1061    },
1062}
1063
1064/// Describes an operation within the computation graph.
1065struct ComputationNode {
1066    /// The computation to complete.
1067    pub computation: Computation,
1068    /// The command buffer containing the computation.
1069    pub command_buffer: u16,
1070    /// Information about the update which will take place, if
1071    /// this node is updating derived data.
1072    pub derived_update: Option<DerivedFormatUpdate>,
1073    /// A label describing this computation.
1074    pub label: Option<&'static str>,
1075    /// The set of views used by this computation.
1076    pub views: Vec<ComputationViewReference>,
1077}
1078
1079/// Describes a view used by a computation.
1080struct ComputationViewReference {
1081    /// The ID of the view object.
1082    pub id: u32,
1083    /// Whether this is a mutable view.
1084    pub mutable: bool,
1085    /// The holder used to access the view.
1086    pub view_holder: DynEntry<dyn ViewHolder>,
1087}
1088
1089/// Holds the inner data for a context.
1090struct ContextHolder {
1091    /// The notifier to use when new work is available from the context.
1092    change_notifier: ChangeNotifier,
1093    /// The listener to use when waiting for changes from the context.
1094    change_listener: Condvar,
1095    /// The ID of the context.
1096    context_id: u64,
1097    /// The inner mutable context data.
1098    inner: Mutex<ContextInner>,
1099}
1100
1101/// Manages a set of objects and efficiently schedules
1102/// computations on them.
1103struct ContextInner {
1104    /// The list of command buffers that are referenced by commands.
1105    active_command_buffers: Slab<ActiveCommandBuffer>,
1106    /// The compute graph containing operation nodes.
1107    compute_graph: DirectedAcyclicGraph<ComputationNode>,
1108    /// The ID of the context.
1109    context_id: u64,
1110    /// The set of nodes that must complete for mappings to be available.
1111    critical_nodes: DirectedAcyclicGraphFlags,
1112    /// The set of nodes that are both critical and immediately schedulable.
1113    critical_top_level_nodes: DirectedAcyclicGraphFlags,
1114    /// The set of objects within the context.
1115    objects: Slab<DataHolder>,
1116    /// A sender used to alert the context of object updates.
1117    object_update_sender: Sender<ObjectUpdate>,
1118    /// Receives updates about the objects within the context.
1119    object_updates: std::sync::mpsc::Receiver<ObjectUpdate>,
1120    /// Whether an update should be sent out on the notifier when new work is available.
1121    stalled: bool,
1122    /// A buffer used to temporarily store node IDs without reallocation.
1123    temporary_node_buffer: Vec<NodeId>,
1124    /// The set of nodes the are immediately schedulable.
1125    top_level_nodes: DirectedAcyclicGraphFlags,
1126}
1127
1128impl ContextInner {
1129    /// Creates a new object from the provided descriptor. Objects are also created for each derived format,
1130    /// and will automatically update whenever this object is changed.
1131    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    /// Schedules the provided command buffer for execution.
1206    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    /// Creates a command context to execute the provided computation.
1222    ///
1223    /// # Safety
1224    ///
1225    /// The command ID must refer to a vald node in the compute graph.
1226    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    /// Attempts to get the next command to execute. Returns `None` if no work is presently available,
1259    /// `Some(None)` if new mappings were made available, and `Some(Some(_))` if work must be done.
1260    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 command context must immediately be dropped,
1287                        // then drop it without reacquiring mutex.
1288                        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    /// Determines the next command to schedule, removes it from the graph,
1349    /// and returns it. Prioritizes critical nodes.
1350    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    /// Schedules all commands in the provided buffer for processing.
1377    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    /// Schedules a command to execute.
1423    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            // Iterate over all used views to find any conflicting computations
1440            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                // Determine which other commands are dependencies of this one
1461                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                // Add view to object
1503                if next_view.mutable() {
1504                    &mut object.mutable_references
1505                } else {
1506                    &mut object.immutable_references
1507                }
1508                .push(node);
1509            }
1510
1511            // Add the new computation to the graph
1512            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            // Update any derived views that this command affects
1524            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    /// Marks the provided node, and all of its parents, as critical.
1640    ///
1641    /// # Safety
1642    ///
1643    /// For this function call to be sound, node must refer to a valid
1644    /// node in the computation graph.
1645    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    /// Marks a command as complete and removes it from the node graph.
1657    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    /// Updates the objects of this context, discarding any which have been dropped.
1698    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    /// Notifies all waiting threads that new commands are available for processing.
1719    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
1731/// Holds an object within a context.
1732struct DataHolder {
1733    /// Information about the base or derived state of this object.
1734    pub derive_state: FormatDeriveState,
1735    /// An optional label describing this object.
1736    pub label: Option<&'static str>,
1737    /// A list of computations which use this object immutably.
1738    pub immutable_references: Vec<NodeId>,
1739    /// A list of computations which use this object mutably.
1740    pub mutable_references: Vec<NodeId>,
1741    /// A refernce to the inner object.
1742    pub value: Pin<Box<UnsafeCell<dyn Any + Send + Sync>>>,
1743}
1744
1745/// Holds the inner information for an allocated object.
1746struct DataInner<K: Kind> {
1747    /// The ID of the context associated with this data.
1748    pub context_id: u64,
1749    /// A list of any derived formats for this data.
1750    pub derived_formats: Vec<(TypeId, u32)>,
1751    /// The descriptor of this data.
1752    pub descriptor: K::FormatDescriptor,
1753    /// The ID of the format associated with this data.
1754    pub format_id: TypeId,
1755    /// The ID of this object.
1756    pub id: u32,
1757    /// An optional label describing this object.
1758    pub label: Option<&'static str>,
1759    /// The updater to notify when this data is dropped.
1760    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
1771/// Provides information about how a format update should take place.
1772struct DerivedFormatUpdate {
1773    /// The parent of this format.
1774    pub parent: u32,
1775    /// The index of this format within the parent's derived list.
1776    pub index: u32,
1777}
1778
1779/// Stores information about the state of a base's derived format.
1780struct DerivedFormatState {
1781    /// The type ID of this format.
1782    pub format_id: TypeId,
1783    /// The ID of this format.
1784    pub id: u32,
1785    /// The next update that is scheduled for this derived format.
1786    pub next_update: Option<NodeId>,
1787}
1788
1789/// Describes whether an object is a base object
1790/// or derived data.
1791enum FormatDeriveState {
1792    /// The object is a mutable base object.
1793    Base {
1794        /// The set of objects derived from this one.
1795        derived_formats: Vec<DerivedFormatState>,
1796    },
1797    /// The object derives its data from another.
1798    Derived {
1799        /// The ID of the parent object.
1800        parent: u32,
1801        /// The index of the object in the parent's derived array.
1802        index: u8,
1803        /// The object to use when updating this format.
1804        updater: Arc<dyn DerivedFormatUpdater>,
1805    },
1806}
1807
1808/// Prints a formatted object label with a prefix and suffix,
1809/// or prints nothing if the object did not exist.
1810struct 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
1822/// The state associated with mapped data.
1823struct MappedInner {
1824    /// The ID of the context associated with the mapping.
1825    pub context_id: u64,
1826    /// The command context associated with the mapping.
1827    pub command_context: UnsafeCell<MaybeUninit<CommandContext>>,
1828    /// The label of the object to be mapped.
1829    pub label: Option<&'static str>,
1830    /// Whether this object has been submitted or mapped yet.
1831    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
1845/// Provides the results of a query against a `MapObjectState`.
1846struct MapObjectStateQuery {
1847    /// Indicates that the mapping is ready to be accessed.
1848    pub complete: bool,
1849    /// The node ID associated with the mapping, assuming that it has been queued.
1850    pub node: NodeId,
1851    /// Indicates that the mapping has been submitted for processing.
1852    pub queued: bool,
1853}
1854
1855/// Tracks whether an object is presently mapped.
1856#[derive(Default)]
1857struct MapObjectState(AtomicU32);
1858
1859impl MapObjectState {
1860    /// A flag bit indicating that the mapping has been queued for execution.
1861    const MAPPING_QUEUED: u32 = 1 << 16;
1862    /// A flag bit indicating that the mapping is completed.
1863    const MAPPING_COMPLETE: u32 = 1 << 17;
1864
1865    /// Moves this mapping to the queued state, and sets the node ID.
1866    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    /// Marks this mapping as complete.
1874    pub fn set_complete(&self) {
1875        self.0.fetch_or(Self::MAPPING_COMPLETE, Ordering::Release);
1876    }
1877
1878    /// Gets the current state of this mapping.
1879    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
1893/// Notifies the context of an update that has occurred to an object.
1894enum ObjectUpdate {
1895    /// An object has been dropped.
1896    DropData {
1897        /// The ID of the object which has been dropped.
1898        id: u32,
1899    },
1900}
1901
1902/// A node in a linked list of views used by a command.
1903struct ViewEntry {
1904    /// The next view in the linked list, if any.
1905    pub next_instance: Option<DynEntry<ViewEntry>>,
1906    /// The view itself.
1907    pub view: DynEntry<dyn ViewHolder>,
1908}
1909
1910/// Implements the ability to update a derived format.
1911struct TypedDerivedFormatUpdater<F: Format, D: DerivedDescriptor<F>> {
1912    /// The descriptor determining how to update the format.
1913    pub descriptor: D,
1914    /// Marker data.
1915    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
1945/// Acts as a view holder for the provided view and descriptor.
1946struct TypedViewHolder<M: UsageMutability, F: Format> {
1947    /// The view that this holder references.
1948    view: View<F>,
1949    /// The descriptor determining how this view is being used.
1950    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
1971/// Hides implementation details from other crates.
1972mod private {
1973    use super::*;
1974
1975    /// Provides the ability to add a view to a command buffer.
1976    pub trait ViewUsageInner {
1977        /// Adds a view holder entry to the given command list.
1978        fn add_to_list(&self, command_list: &mut DynVec) -> DynEntry<dyn ViewHolder>;
1979    }
1980
1981    /// Mutability which optionally stores a descriptor about a view's usage.
1982    pub trait UsageMutability: Mutability {
1983        /// The descriptor that must be provided for this mutability.
1984        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            // Do some calculation to update the acceleration structure based upon the
2041            // how the primary format has been modified.
2042            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}