Skip to content
Snippets Groups Projects
  • Lyude Paul's avatar
    ea59337a
    WIP: rust: drm/kms: Add drm_atomic_state bindings · ea59337a
    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's avatarLyude 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
    ea59337a
    History
    WIP: rust: drm/kms: Add drm_atomic_state bindings
    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's avatarLyude 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