chromium/ui/ozone/platform/drm/common/drm_wrapper.h

// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef UI_OZONE_PLATFORM_DRM_COMMON_DRM_WRAPPER_H_
#define UI_OZONE_PLATFORM_DRM_COMMON_DRM_WRAPPER_H_

#include <stddef.h>
#include <stdint.h>

#include <memory>
#include <optional>
#include <vector>

#include "base/files/file_path.h"
#include "base/files/scoped_file.h"
#include "base/functional/callback.h"
#include "base/memory/raw_ptr.h"
#include "third_party/perfetto/include/perfetto/tracing/traced_value_forward.h"
#include "ui/display/types/display_constants.h"
#include "ui/display/types/gamma_ramp_rgb_entry.h"
#include "ui/gfx/geometry/point.h"
#include "ui/gfx/geometry/size.h"
#include "ui/ozone/platform/drm/common/scoped_drm_types.h"

typedef struct _drmModeModeInfo drmModeModeInfo;

struct SkImageInfo;

namespace display {
class GammaCurve;
}  // namespace display

namespace ui {

class DrmWrapper;

class DrmPropertyBlobMetadata {
 public:
  DrmPropertyBlobMetadata(DrmWrapper* drm, uint32_t id);

  DrmPropertyBlobMetadata(const DrmPropertyBlobMetadata&) = delete;
  DrmPropertyBlobMetadata& operator=(const DrmPropertyBlobMetadata&) = delete;

  ~DrmPropertyBlobMetadata();

  uint32_t id() const { return id_; }

 private:
  raw_ptr<DrmWrapper> drm_;  // Not owned;
  uint32_t id_;
};

using ScopedDrmPropertyBlob = std::unique_ptr<DrmPropertyBlobMetadata>;

// Wraps DRM calls into a tight interface. Used to provide different
// implementations of the DRM calls. For the actual implementation the DRM API
// would be called. In unit tests this interface would be stubbed.
class DrmWrapper {
 public:
  DrmWrapper(const base::FilePath& device_path,
             base::ScopedFD fd,
             bool is_primary_device);
  DrmWrapper(const DrmWrapper&) = delete;
  DrmWrapper& operator=(const DrmWrapper&) = delete;
  virtual ~DrmWrapper();

  struct Property {
    // Unique identifier for the property. 0 denotes an invalid ID.
    uint32_t id = 0;

    // Depending on the property, this may be an actual value describing the
    // property or an ID of another property.
    uint64_t value = 0;
  };

  // Open device.
  virtual bool Initialize();

  /*******
   * CRTCs
   *******/

  // Get the CRTC state. This is generally used to save state before using the
  // CRTC. When the user finishes using the CRTC, the user should restore the
  // CRTC to it's initial state. Use |SetCrtc| to restore the state.
  virtual ScopedDrmCrtcPtr GetCrtc(uint32_t crtc_id) const;

  // Used to configure CRTC with ID |crtc_id| to use the connector in
  // |connectors|. The CRTC will be configured with mode |mode| and will display
  // the framebuffer with ID |framebuffer|. Before being able to display the
  // framebuffer, it should be registered with the CRTC using |AddFramebuffer|.
  virtual bool SetCrtc(uint32_t crtc_id,
                       uint32_t framebuffer,
                       std::vector<uint32_t> connectors,
                       const drmModeModeInfo& mode);

  virtual bool DisableCrtc(uint32_t crtc_id);

  /**************
   * Capabilities
   **************/

  // Queries whether a |capability| is available and stores its value in
  // |value| if found.
  virtual bool GetCapability(uint64_t capability, uint64_t* value) const;

  // Can be used to query device/driver |capability|. Sets the value of
  // |capability| to |value|. Returns true in case of a successful query.
  virtual bool SetCapability(uint64_t capability, uint64_t value);

  /************
   * Connectors
   ************/

  // Returns the connector properties for |connector_id|.
  virtual ScopedDrmConnectorPtr GetConnector(uint32_t connector_id) const;

  /********
   * Cursor
   ********/

  // Move the cursor on CRTC |crtc_id| to (x, y);
  virtual bool MoveCursor(uint32_t crtc_id, const gfx::Point& point);

  // Set the cursor to be displayed in CRTC |crtc_id|. (width, height) is the
  // cursor size pointed by |handle|.
  virtual bool SetCursor(uint32_t crtc_id,
                         uint32_t handle,
                         const gfx::Size& size);

  /************
   * DRM Master
   ************/

  virtual bool SetMaster();
  virtual bool DropMaster();

  /**************
   * Dumb Buffers
   **************/

  virtual bool CreateDumbBuffer(const SkImageInfo& info,
                                uint32_t* handle,
                                uint32_t* stride);
  virtual bool DestroyDumbBuffer(uint32_t handle);
  virtual bool MapDumbBuffer(uint32_t handle, size_t size, void** pixels);
  virtual bool UnmapDumbBuffer(void* pixels, size_t size);

  virtual bool CloseBufferHandle(uint32_t handle);

  /**********
   * Encoders
   **********/

  // Returns the encoder properties for |encoder_id|.
  virtual ScopedDrmEncoderPtr GetEncoder(uint32_t encoder_id) const;

  /**************
   * Framebuffers
   **************/

  // Get the DRM details associated with |framebuffer|.
  virtual ScopedDrmFramebufferPtr GetFramebuffer(uint32_t framebuffer) const;

  // Deregister the given |framebuffer|.
  virtual bool RemoveFramebuffer(uint32_t framebuffer);

  // Register any format buffer with the CRTC. On successful registration, the
  // CRTC will assign a framebuffer ID to |framebuffer|.
  virtual bool AddFramebuffer2(uint32_t width,
                               uint32_t height,
                               uint32_t format,
                               uint32_t handles[4],
                               uint32_t strides[4],
                               uint32_t offsets[4],
                               uint64_t modifiers[4],
                               uint32_t* framebuffer,
                               uint32_t flags);

  /*******
   * Gamma
   *******/

  virtual bool SetGammaRamp(uint32_t crtc_id, const display::GammaCurve& lut);

  /********
   * Planes
   ********/

  // Returns the list of all planes available on this DRM device.
  virtual ScopedDrmPlaneResPtr GetPlaneResources() const;

  // Returns the properties associated with plane with id |plane_id|.
  virtual ScopedDrmPlanePtr GetPlane(uint32_t plane_id) const;

  /************
   * Properties
   ************/

  // Returns the properties associated with object with id |object_id| and type
  // |object_type|. |object_type| is one of DRM_MODE_OBJECT_*.
  virtual ScopedDrmObjectPropertyPtr GetObjectProperties(
      uint32_t object_id,
      uint32_t object_type) const;

  // Sets a property (defined by {|property_id|, |property_value|} on an object
  // with ID |object_id| and type |object_type|.
  // |object_id| and |property_id| are unique identifiers.
  // |object_type| is one of DRM_MODE_OBJECT_*.
  virtual bool SetObjectProperty(uint32_t object_id,
                                 uint32_t object_type,
                                 uint32_t property_id,
                                 uint32_t property_value);

  virtual ScopedDrmPropertyPtr GetProperty(uint32_t id) const;

  // Returns the property with name |name| associated with |connector|. Returns
  // NULL if property not found. If the returned value is valid, it must be
  // released using FreeProperty().
  virtual ScopedDrmPropertyPtr GetProperty(drmModeConnector* connector,
                                           const char* name) const;

  // Sets the value of property with ID |property_id| to |value|. The property
  // is applied to the connector with ID |connector_id|.
  virtual bool SetProperty(uint32_t connector_id,
                           uint32_t property_id,
                           uint64_t value);

  /****************
   * Property Blobs
   ****************/

  // Creates a property blob with data |blob| of size |size|.
  virtual ScopedDrmPropertyBlob CreatePropertyBlob(const void* blob,
                                                   size_t size);
  // Creates a property blob with |size| for data |blob| which user space
  // can't read back.
  virtual ScopedDrmPropertyBlob CreatePropertyBlobWithFlags(const void* blob,
                                                            size_t size,
                                                            uint32_t flags);
  virtual void DestroyPropertyBlob(uint32_t id);

  // Returns a binary blob associated with |property_id|. May be nullptr if the
  // property couldn't be found.
  virtual ScopedDrmPropertyBlobPtr GetPropertyBlob(uint32_t property_id) const;

  // Returns a binary blob associated with |connector|. The binary blob is
  // associated with the property with name |name|. Return NULL if the property
  // could not be found or if the property does not have a binary blob. If valid
  // the returned object must be freed using FreePropertyBlob().
  virtual ScopedDrmPropertyBlobPtr GetPropertyBlob(drmModeConnector* connector,
                                                   const char* name) const;

  /***********
   * Resources
   ***********/

  // Returns all the DRM resources for this device. This includes CRTC,
  // connectors, and encoders state.
  virtual ScopedDrmResourcesPtr GetResources() const;

  /*********
   * Utility
   *********/

  // Adds trace records to |context|.
  virtual void WriteIntoTrace(perfetto::TracedDictionary dict) const;

  virtual std::optional<std::string> GetDriverName() const;

  // TODO(gildekel): remove once DrmWrapper and DrmDevice are completely
  // decoupled.
  // Returns a list of supported drm formats and modifiers for |crtc_id|. Note:
  // implementation in wrapper is a stub. Full implementation is in
  // DrmDevice::GetFormatsAndModifiersForCrtc().
  virtual display::DrmFormatsAndModifiers GetFormatsAndModifiersForCrtc(
      uint32_t crtc_id) const;

  // Extracts the FD from the given |drm|. The |drm| object will be invalidated.
  static base::ScopedFD ToScopedFD(std::unique_ptr<DrmWrapper> drm);

  base::FilePath device_path() const { return device_path_; }
  bool is_atomic() const { return is_atomic_; }
  bool is_primary_device() const { return is_primary_device_; }

 protected:
  // TODO(gildekel): move CommitProperties() and PageFlip() to the public API
  // once DrmWrapper and DrmDevice are completely decoupled. Consider changing
  // the signature to `void* user_data` instead of |page_flip_id|, which is too
  // specific.
  bool CommitProperties(drmModeAtomicReq* properties,
                        uint32_t flags,
                        uint64_t page_flip_id);

  bool PageFlip(uint32_t crtc_id, uint32_t framebuffer, uint64_t page_flip_id);

  const int& GetFd() const { return drm_fd_.get(); }

 private:
  // Path to the DRM device (in sysfs).
  const base::FilePath device_path_;

  // DRM device FD.
  base::ScopedFD drm_fd_;

  // Whether or not DRM was successfully set to atomic during the initialization
  // of this DRM device.
  bool is_atomic_ = false;

  const bool is_primary_device_;
};

}  // namespace ui

#endif  // UI_OZONE_PLATFORM_DRM_COMMON_DRM_WRAPPER_H_