-
Lyude Paul authored
Next up is introducing bindings that we can use to represent the global DRM atomic state, along with all of the various object states contained within. We do this by introducing a few new concepts: borrowed states, atomic state mutators, and atomic state composers. To understand these, we need to quickly touch upon the general life of an atomic commit. Assuming a driver does its own internal atomic commit, the procedure looks something like this: * Allocate a new atomic state * Duplicate the atomic state of each mode object we want to mutate, and add the duplicated state to the new atomic state * Check (possibly more then once) the atomic state, possibly modifying it along the way * Commit the atomic state to software (we'll call this commit time). At this point no new objects can be added to the state * Finish committing the atomic state to hardware asynchronously With this in mind, we introduce AtomicStateMutator and AtomicStateComposer (along with leaky variants intended for uses in FFI calls). An AtomicStateMutator allows mutating an atomic state but does not allow for adding new objects to the state. Subsequently, an AtomicStateComposer allows for both mutating an atomic state and adding new mode objects. We control when we expose each of these types in order to implement the limitations required by the aforementioned example. Note as well that AtomicStateComposer is intended to eventually be usable directly by drivers. In this scenario, a driver will be able to create an AtomicStateComposer (the equivalent of allocating an atomic state in C) and then commit it by passing it to our DRM bindings by-value, insuring that once the commit process begins it is impossible to keep using the AtomicStateComposer. The next part of this is allowing users to modify the atomic states of all of the objects contained within an atomic state. Since it's an extremely common usecase for objects to mutate the atomic state of multiple objects at once in an unpredictable order, we need a mechanism that will allow us to hand out &mut references to each state while ensuring at runtime that we do not break rust's data aliasing rules (which disallow us from ever having more then one &mut reference to the same piece of data). We do this by introducing the concept of a "borrowed" state. This is a very similar concept to RefCell, where it is ensured during runtime that when a &mut reference is taken out another one cannot be created until the corresponding Ref object has been dropped. Our equivalent Ref types are BorrowedConnectorState, BorrowedCrtcState, and BorrowedPlaneState. Each one of these types can be used in the same manner as a Ref - no additional borrows for an atomic state may be taken until the existing one has been dropped. Subsequently, all of these types implement their respective AsRaw* and FromRaw* counter-parts - and allow dereferencing to each driver-private data structure for fully qualified borrows (like BorrowedCrtcState<'a, CrtcState<T>>. This allows a pretty clean way of mutating multiple states at once without ever breaking rust's mutability rules. We'll use all of these types over the next few commits to begin introducing various atomic modeset callbacks to each mode object type. Signed-off-by:
Lyude Paul <lyude@redhat.com> --- TODO: * Finish adding state iterators We only have one iterator for planes right now, but the plan is to have iterators for all types and have two different kind of iterators: * State object iterators Basically, these just iterate through all of the mode objects of a specific type present in an atomic state. Currently this is what our plane iterator does. * State mutator iterators With the existence of AtomicStateMutator and friends, it makes sense to have a type of iterator that: * Only iterates through unborrowed atomic states, removing the need to deal with the Option<> that get_new_*_state() functions return * Returns each (object, old_state, new_state) triplet as a dedicated type (PlaneUpdate, CrtcUpdate, ConnectorUpdate) that can be upcasted from an Opaque type using a single call. This is desirable, as it would make iterating through objects with a specific Driver* implementation as easy as just adding a .filter_map() call to the iterator. * Upcast functions for the Borrowed* types
Lyude Paul authoredNext up is introducing bindings that we can use to represent the global DRM atomic state, along with all of the various object states contained within. We do this by introducing a few new concepts: borrowed states, atomic state mutators, and atomic state composers. To understand these, we need to quickly touch upon the general life of an atomic commit. Assuming a driver does its own internal atomic commit, the procedure looks something like this: * Allocate a new atomic state * Duplicate the atomic state of each mode object we want to mutate, and add the duplicated state to the new atomic state * Check (possibly more then once) the atomic state, possibly modifying it along the way * Commit the atomic state to software (we'll call this commit time). At this point no new objects can be added to the state * Finish committing the atomic state to hardware asynchronously With this in mind, we introduce AtomicStateMutator and AtomicStateComposer (along with leaky variants intended for uses in FFI calls). An AtomicStateMutator allows mutating an atomic state but does not allow for adding new objects to the state. Subsequently, an AtomicStateComposer allows for both mutating an atomic state and adding new mode objects. We control when we expose each of these types in order to implement the limitations required by the aforementioned example. Note as well that AtomicStateComposer is intended to eventually be usable directly by drivers. In this scenario, a driver will be able to create an AtomicStateComposer (the equivalent of allocating an atomic state in C) and then commit it by passing it to our DRM bindings by-value, insuring that once the commit process begins it is impossible to keep using the AtomicStateComposer. The next part of this is allowing users to modify the atomic states of all of the objects contained within an atomic state. Since it's an extremely common usecase for objects to mutate the atomic state of multiple objects at once in an unpredictable order, we need a mechanism that will allow us to hand out &mut references to each state while ensuring at runtime that we do not break rust's data aliasing rules (which disallow us from ever having more then one &mut reference to the same piece of data). We do this by introducing the concept of a "borrowed" state. This is a very similar concept to RefCell, where it is ensured during runtime that when a &mut reference is taken out another one cannot be created until the corresponding Ref object has been dropped. Our equivalent Ref types are BorrowedConnectorState, BorrowedCrtcState, and BorrowedPlaneState. Each one of these types can be used in the same manner as a Ref - no additional borrows for an atomic state may be taken until the existing one has been dropped. Subsequently, all of these types implement their respective AsRaw* and FromRaw* counter-parts - and allow dereferencing to each driver-private data structure for fully qualified borrows (like BorrowedCrtcState<'a, CrtcState<T>>. This allows a pretty clean way of mutating multiple states at once without ever breaking rust's mutability rules. We'll use all of these types over the next few commits to begin introducing various atomic modeset callbacks to each mode object type. Signed-off-by:
Lyude Paul <lyude@redhat.com> --- TODO: * Finish adding state iterators We only have one iterator for planes right now, but the plan is to have iterators for all types and have two different kind of iterators: * State object iterators Basically, these just iterate through all of the mode objects of a specific type present in an atomic state. Currently this is what our plane iterator does. * State mutator iterators With the existence of AtomicStateMutator and friends, it makes sense to have a type of iterator that: * Only iterates through unborrowed atomic states, removing the need to deal with the Option<> that get_new_*_state() functions return * Returns each (object, old_state, new_state) triplet as a dedicated type (PlaneUpdate, CrtcUpdate, ConnectorUpdate) that can be upcasted from an Opaque type using a single call. This is desirable, as it would make iterating through objects with a specific Driver* implementation as easy as just adding a .filter_map() call to the iterator. * Upcast functions for the Borrowed* types