chromium/ui/ozone/platform/drm/gpu/drm_thread.h

// Copyright 2015 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_GPU_DRM_THREAD_H_
#define UI_OZONE_PLATFORM_DRM_GPU_DRM_THREAD_H_

#include <stdint.h>

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

#include "base/files/file.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/threading/thread.h"
#include "mojo/public/cpp/bindings/associated_receiver_set.h"
#include "mojo/public/cpp/bindings/pending_associated_receiver.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/receiver_set.h"
#include "ui/gfx/native_pixmap_handle.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/ozone/platform/drm/common/display_types.h"
#include "ui/ozone/platform/drm/gpu/drm_device_generator.h"
#include "ui/ozone/platform/drm/mojom/device_cursor.mojom.h"
#include "ui/ozone/platform/drm/mojom/drm_device.mojom.h"
#include "ui/ozone/public/drm_modifiers_filter.h"
#include "ui/ozone/public/hardware_capabilities.h"
#include "ui/ozone/public/overlay_surface_candidate.h"
#include "ui/ozone/public/swap_completion_callback.h"

namespace base {
class FilePath;
}  // namespace base

namespace display {
struct ColorCalibration;
struct ColorTemperatureAdjustment;
struct DisplayConfigurationParams;
struct GammaAdjustment;
}  // namespace display

namespace gfx {
class Point;
class Rect;
}  // namespace gfx

namespace ui {

class DrmDeviceManager;
class DrmFramebuffer;
class DrmGpuDisplayManager;
class GbmBuffer;
class ScreenManager;

struct DrmOverlayPlane;

// Holds all the DRM related state and performs all DRM related operations.
//
// The DRM thread is used to insulate DRM operations from potential blocking
// behaviour on the GPU main thread in order to reduce the potential for jank
// (for example jank in the cursor if the GPU main thread is performing heavy
// operations). The inverse is also true as blocking operations on the DRM
// thread (such as modesetting) no longer block the GPU main thread.
class DrmThread : public base::Thread,
                  public ozone::mojom::DeviceCursor,
                  public ozone::mojom::DrmDevice {
 public:
  using OverlayCapabilitiesCallback =
      base::OnceCallback<void(gfx::AcceleratedWidget,
                              const std::vector<OverlaySurfaceCandidate>&,
                              const std::vector<OverlayStatus>&)>;

  DrmThread();

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

  ~DrmThread() override;

  void Start(base::OnceClosure receiver_completer,
             std::unique_ptr<DrmDeviceGenerator> device_generator);

  // Runs |task| once a DrmDevice is registered. |done|
  // will be signaled if it's not null.
  void RunTaskAfterDeviceReady(base::OnceClosure task,
                               base::WaitableEvent* done);

  // Must be called on the DRM thread. All methods for use from the GPU thread.
  // DrmThreadProxy (on GPU)thread) is the client for these methods.
  void CreateBuffer(gfx::AcceleratedWidget widget,
                    const gfx::Size& size,
                    const gfx::Size& framebuffer_size,
                    gfx::BufferFormat format,
                    gfx::BufferUsage usage,
                    uint32_t flags,
                    std::unique_ptr<GbmBuffer>* buffer,
                    scoped_refptr<DrmFramebuffer>* framebuffer);
  using CreateBufferAsyncCallback =
      base::OnceCallback<void(std::unique_ptr<GbmBuffer>,
                              scoped_refptr<DrmFramebuffer>)>;
  void CreateBufferAsync(gfx::AcceleratedWidget widget,
                         const gfx::Size& size,
                         gfx::BufferFormat format,
                         gfx::BufferUsage usage,
                         uint32_t flags,
                         CreateBufferAsyncCallback callback);
  void CreateBufferFromHandle(gfx::AcceleratedWidget widget,
                              const gfx::Size& size,
                              gfx::BufferFormat format,
                              gfx::NativePixmapHandle handle,
                              std::unique_ptr<GbmBuffer>* buffer,
                              scoped_refptr<DrmFramebuffer>* framebuffer);
  void SetDisplaysConfiguredCallback(base::RepeatingClosure callback);
  void AddDrmDeviceReceiver(
      mojo::PendingReceiver<ozone::mojom::DrmDevice> receiver);

  // Verifies if the display controller can successfully scanout the given set
  // of OverlaySurfaceCandidates and return the status associated with each
  // candidate.
  void CheckOverlayCapabilities(
      gfx::AcceleratedWidget widget,
      const std::vector<OverlaySurfaceCandidate>& candidates,
      OverlayCapabilitiesCallback callback);

  // Similar to CheckOverlayCapabilities() but stores the result in |result|
  // instead of running a callback.
  void CheckOverlayCapabilitiesSync(
      gfx::AcceleratedWidget widget,
      const std::vector<OverlaySurfaceCandidate>& candidates,
      std::vector<OverlayStatus>* result);
  // Calls `receive_callback` with a `HardwareCapabilities` containing
  // information about overlay support on the current hardware.
  void GetHardwareCapabilities(gfx::AcceleratedWidget widget,
                               HardwareCapabilitiesCallback receive_callback);

  // DrmWindowProxy (on GPU thread) is the client for these methods.
  void SchedulePageFlip(gfx::AcceleratedWidget widget,
                        std::vector<DrmOverlayPlane> planes,
                        SwapCompletionOnceCallback submission_callback,
                        PresentationOnceCallback presentation_callback);

  void IsDeviceAtomic(gfx::AcceleratedWidget widget, bool* is_atomic);

  // Sets a filter that the DRM thread can invoke to filter out modifiers
  // incompatible with use in GPU main and Viz threads.
  void SetDrmModifiersFilter(std::unique_ptr<DrmModifiersFilter> filter);

  // ozone::mojom::DrmDevice
  void CreateWindow(gfx::AcceleratedWidget widget,
                    const gfx::Rect& initial_bounds) override;
  void DestroyWindow(gfx::AcceleratedWidget widget) override;
  void SetWindowBounds(gfx::AcceleratedWidget widget,
                       const gfx::Rect& bounds) override;
  void TakeDisplayControl(base::OnceCallback<void(bool)> callback) override;
  void RelinquishDisplayControl(
      base::OnceCallback<void(bool)> callback) override;
  void ShouldDisplayEventTriggerConfiguration(
      const EventPropertyMap& event_props,
      base::OnceCallback<void(bool)> callback) override;
  void RefreshNativeDisplays(
      base::OnceCallback<void(MovableDisplaySnapshots)> callback) override;
  void AddGraphicsDevice(const base::FilePath& path,
                         mojo::PlatformHandle fd_mojo_handle) override;
  void RemoveGraphicsDevice(const base::FilePath& path) override;
  void ConfigureNativeDisplays(
      const std::vector<display::DisplayConfigurationParams>& config_requests,
      display::ModesetFlags modeset_flags,
      ConfigureNativeDisplaysCallback callback) override;
  void SetHdcpKeyProp(int64_t display_id,
                      const std::string& key,
                      SetHdcpKeyPropCallback callback) override;
  void GetHDCPState(int64_t display_id,
                    base::OnceCallback<void(int64_t,
                                            bool,
                                            display::HDCPState,
                                            display::ContentProtectionMethod)>
                        callback) override;
  void SetHDCPState(int64_t display_id,
                    display::HDCPState state,
                    display::ContentProtectionMethod protection_method,
                    base::OnceCallback<void(int64_t, bool)> callback) override;
  void SetColorTemperatureAdjustment(
      int64_t display_id,
      const display::ColorTemperatureAdjustment& cta) override;
  void SetColorCalibration(
      int64_t display_id,
      const display::ColorCalibration& calibration) override;
  void SetGammaAdjustment(int64_t display_id,
                          const display::GammaAdjustment& adjustment) override;
  void SetPrivacyScreen(int64_t display_id,
                        bool enabled,
                        base::OnceCallback<void(bool)> callback) override;
  void GetSeamlessRefreshRates(
      int64_t display_id,
      GetSeamlessRefreshRatesCallback callback) override;

  void GetDeviceCursor(
      mojo::PendingAssociatedReceiver<ozone::mojom::DeviceCursor> receiver)
      override;

  // ozone::mojom::DeviceCursor
  void SetCursor(gfx::AcceleratedWidget widget,
                 const std::vector<SkBitmap>& bitmaps,
                 const std::optional<gfx::Point>& location,
                 base::TimeDelta frame_delay) override;
  void MoveCursor(gfx::AcceleratedWidget widget,
                  const gfx::Point& location) override;

  // base::Thread:
  void Init() override;
  void CleanUp() override;

 private:
  struct TaskInfo {
    base::OnceClosure task;
    raw_ptr<base::WaitableEvent> done;

    TaskInfo(base::OnceClosure task, base::WaitableEvent* done);
    TaskInfo(TaskInfo&& other);
    ~TaskInfo();
  };

  void OnPlanesReadyForPageFlip(gfx::AcceleratedWidget widget,
                                SwapCompletionOnceCallback submission_callback,
                                PresentationOnceCallback presentation_callback,
                                std::vector<DrmOverlayPlane> planes);

  // Called when a DrmDevice or DrmWindow is created. Runs tasks that are now
  // unblocked.
  void ProcessPendingTasks();

  std::unique_ptr<DrmDeviceManager> device_manager_;
  std::unique_ptr<ScreenManager> screen_manager_;
  std::unique_ptr<DrmGpuDisplayManager> display_manager_;

  base::OnceClosure complete_early_receiver_requests_;

  // The mojo implementation requires an AssociatedReceiverSet because the
  // DrmThread serves requests from two different client threads.
  mojo::AssociatedReceiverSet<ozone::mojom::DeviceCursor> cursor_receivers_;

  // This is a ReceiverSet because the regular Receiver causes the sequence
  // checker in InterfaceEndpointClient to fail during teardown.
  // TODO(samans): Figure out why.
  mojo::ReceiverSet<ozone::mojom::DrmDevice> drm_receivers_;

  // The AcceleratedWidget from the last call to CreateWindow.
  gfx::AcceleratedWidget last_created_window_ = gfx::kNullAcceleratedWidget;

  // The tasks that are blocked on a DrmDevice becoming available.
  std::vector<TaskInfo> pending_tasks_;

  // Holds the DrmDeviceGenerator that DrmDeviceManager will use. Will be passed
  // on to DrmDeviceManager after the thread starts.
  std::unique_ptr<DrmDeviceGenerator> device_generator_;

  base::WeakPtrFactory<DrmThread> weak_ptr_factory_{this};
};

}  // namespace ui

#endif  // UI_OZONE_PLATFORM_DRM_GPU_DRM_THREAD_H_