-
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> --- V3: * Drop the TODO about printing a kernel error in BorrowedConnectorState I thought this was something we'd want early on in designing this, but since then I'm pretty sure we just want to return None - there are valid cases where we'd get None while doing connector iteration through an atomic state * Improve safety comments in BorrowedConnectorState::new() * Rename Borrowed*State to *StateMutator I think this makes things a lot clearer, as well - cleanup the documentation regarding this. * Drop plane state iterator for now. It's not that we don't need this, it's just that I haven't actually finished writing these up for all types so I'd rather focus on that later now that we've demonstrated it's a thing that is possible. And it at least shouldn't be needed for getting these bindings/rvkms upstream.
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> --- V3: * Drop the TODO about printing a kernel error in BorrowedConnectorState I thought this was something we'd want early on in designing this, but since then I'm pretty sure we just want to return None - there are valid cases where we'd get None while doing connector iteration through an atomic state * Improve safety comments in BorrowedConnectorState::new() * Rename Borrowed*State to *StateMutator I think this makes things a lot clearer, as well - cleanup the documentation regarding this. * Drop plane state iterator for now. It's not that we don't need this, it's just that I haven't actually finished writing these up for all types so I'd rather focus on that later now that we've demonstrated it's a thing that is possible. And it at least shouldn't be needed for getting these bindings/rvkms upstream.