chromium/ui/ozone/platform/drm/gpu/drm_thread_proxy.cc

// 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.

#include "ui/ozone/platform/drm/gpu/drm_thread_proxy.h"

#include <memory>
#include <utility>

#include "base/functional/bind.h"
#include "base/task/single_thread_task_runner.h"
#include "base/threading/thread_restrictions.h"
#include "base/trace_event/trace_event.h"
#include "ui/gfx/linux/gbm_wrapper.h"
#include "ui/ozone/platform/drm/gpu/drm_device.h"
#include "ui/ozone/platform/drm/gpu/drm_device_generator.h"
#include "ui/ozone/platform/drm/gpu/drm_thread.h"
#include "ui/ozone/platform/drm/gpu/drm_window_proxy.h"
#include "ui/ozone/platform/drm/gpu/gbm_pixmap.h"
#include "ui/ozone/platform/drm/gpu/proxy_helpers.h"

namespace ui {

namespace {

void OnBufferCreatedOnDrmThread(
    scoped_refptr<base::SingleThreadTaskRunner> task_runner,
    DrmThreadProxy::CreateBufferAsyncCallback callback,
    std::unique_ptr<GbmBuffer> buffer,
    scoped_refptr<DrmFramebuffer> framebuffer) {
  task_runner->PostTask(FROM_HERE,
                        base::BindOnce(std::move(callback), std::move(buffer),
                                       std::move(framebuffer)));
}

class GbmDeviceGenerator : public DrmDeviceGenerator {
 public:
  GbmDeviceGenerator() = default;

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

  ~GbmDeviceGenerator() override = default;

  // DrmDeviceGenerator:
  scoped_refptr<DrmDevice> CreateDevice(const base::FilePath& path,
                                        base::ScopedFD fd,
                                        bool is_primary_device) override {
    auto gbm = CreateGbmDevice(fd.get());
    if (!gbm) {
      PLOG(ERROR) << "Unable to initialize GBM for " << path.value();
      return nullptr;
    }

    auto drm = base::MakeRefCounted<DrmDevice>(
        path, std::move(fd), is_primary_device, std::move(gbm));
    if (!drm->Initialize())
      return nullptr;
    return drm;
  }
};

}  // namespace

DrmThreadProxy::DrmThreadProxy() = default;

DrmThreadProxy::~DrmThreadProxy() = default;

void DrmThreadProxy::StartDrmThread(base::OnceClosure receiver_drainer) {
  drm_thread_.Start(std::move(receiver_drainer),
                    std::make_unique<GbmDeviceGenerator>());
}

std::unique_ptr<DrmWindowProxy> DrmThreadProxy::CreateDrmWindowProxy(
    gfx::AcceleratedWidget widget) {
  return std::make_unique<DrmWindowProxy>(widget, &drm_thread_);
}

void DrmThreadProxy::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) {
  TRACE_EVENT0("drm", "DrmThreadProxy::CreateBuffer");
  DCHECK(drm_thread_.task_runner())
      << "no task runner! in DrmThreadProxy::CreateBuffer";
  base::ScopedAllowBaseSyncPrimitivesOutsideBlockingScope allow_wait;
  base::OnceClosure task = base::BindOnce(
      &DrmThread::CreateBuffer, base::Unretained(&drm_thread_), widget, size,
      framebuffer_size, format, usage, flags, buffer, framebuffer);
  PostSyncTask(drm_thread_.task_runner(),
               base::BindOnce(&DrmThread::RunTaskAfterDeviceReady,
                              base::Unretained(&drm_thread_), std::move(task)));
}

void DrmThreadProxy::CreateBufferAsync(gfx::AcceleratedWidget widget,
                                       const gfx::Size& size,
                                       gfx::BufferFormat format,
                                       gfx::BufferUsage usage,
                                       uint32_t flags,
                                       CreateBufferAsyncCallback callback) {
  DCHECK(drm_thread_.task_runner())
      << "no task runner! in DrmThreadProxy::CreateBufferAsync";
  base::OnceClosure task = base::BindOnce(
      &DrmThread::CreateBufferAsync, base::Unretained(&drm_thread_), widget,
      size, format, usage, flags,
      base::BindOnce(OnBufferCreatedOnDrmThread,
                     base::SingleThreadTaskRunner::GetCurrentDefault(),
                     std::move(callback)));
  drm_thread_.task_runner()->PostTask(
      FROM_HERE,
      base::BindOnce(&DrmThread::RunTaskAfterDeviceReady,
                     base::Unretained(&drm_thread_), std::move(task), nullptr));
}

void DrmThreadProxy::CreateBufferFromHandle(
    gfx::AcceleratedWidget widget,
    const gfx::Size& size,
    gfx::BufferFormat format,
    gfx::NativePixmapHandle handle,
    std::unique_ptr<GbmBuffer>* buffer,
    scoped_refptr<DrmFramebuffer>* framebuffer) {
  TRACE_EVENT0("drm", "DrmThreadProxy::CreateBufferFromHandle");
  base::ScopedAllowBaseSyncPrimitivesOutsideBlockingScope allow_wait;
  base::OnceClosure task = base::BindOnce(
      &DrmThread::CreateBufferFromHandle, base::Unretained(&drm_thread_),
      widget, size, format, std::move(handle), buffer, framebuffer);
  PostSyncTask(drm_thread_.task_runner(),
               base::BindOnce(&DrmThread::RunTaskAfterDeviceReady,
                              base::Unretained(&drm_thread_), std::move(task)));
}

void DrmThreadProxy::SetDisplaysConfiguredCallback(
    base::RepeatingClosure callback) {
  DCHECK(drm_thread_.task_runner());

  drm_thread_.task_runner()->PostTask(
      FROM_HERE,
      base::BindOnce(&DrmThread::SetDisplaysConfiguredCallback,
                     base::Unretained(&drm_thread_),
                     CreateSafeRepeatingCallback(std::move(callback))));
}

void DrmThreadProxy::CheckOverlayCapabilities(
    gfx::AcceleratedWidget widget,
    const std::vector<OverlaySurfaceCandidate>& candidates,
    DrmThread::OverlayCapabilitiesCallback callback) {
  DCHECK(drm_thread_.task_runner());
  base::OnceClosure task = base::BindOnce(
      &DrmThread::CheckOverlayCapabilities, base::Unretained(&drm_thread_),
      widget, candidates, CreateSafeOnceCallback(std::move(callback)));

  drm_thread_.task_runner()->PostTask(
      FROM_HERE,
      base::BindOnce(&DrmThread::RunTaskAfterDeviceReady,
                     base::Unretained(&drm_thread_), std::move(task), nullptr));
}

std::vector<OverlayStatus> DrmThreadProxy::CheckOverlayCapabilitiesSync(
    gfx::AcceleratedWidget widget,
    const std::vector<OverlaySurfaceCandidate>& candidates) {
  TRACE_EVENT0("drm", "DrmThreadProxy::CheckOverlayCapabilitiesSync");
  DCHECK(drm_thread_.task_runner());
  base::ScopedAllowBaseSyncPrimitivesOutsideBlockingScope allow_wait;
  std::vector<OverlayStatus> result;
  base::OnceClosure task = base::BindOnce(
      &DrmThread::CheckOverlayCapabilitiesSync, base::Unretained(&drm_thread_),
      widget, candidates, &result);
  PostSyncTask(drm_thread_.task_runner(),
               base::BindOnce(&DrmThread::RunTaskAfterDeviceReady,
                              base::Unretained(&drm_thread_), std::move(task)));
  return result;
}

void DrmThreadProxy::GetHardwareCapabilities(
    gfx::AcceleratedWidget widget,
    const HardwareCapabilitiesCallback& receive_callback) {
  TRACE_EVENT0("drm", "DrmThreadProxy::GetHardwareCapabilities");
  DCHECK(drm_thread_.task_runner());
  base::RepeatingClosure task = base::BindRepeating(
      &DrmThread::GetHardwareCapabilities, base::Unretained(&drm_thread_),
      widget, CreateSafeRepeatingCallback(receive_callback));
  drm_thread_.task_runner()->PostTask(
      FROM_HERE,
      base::BindOnce(&DrmThread::RunTaskAfterDeviceReady,
                     base::Unretained(&drm_thread_), std::move(task), nullptr));
}

void DrmThreadProxy::AddDrmDeviceReceiver(
    mojo::PendingReceiver<ozone::mojom::DrmDevice> receiver) {
  DCHECK(drm_thread_.task_runner()) << "DrmThreadProxy::AddDrmDeviceReceiver "
                                       "drm_thread_ task runner missing";

  if (drm_thread_.task_runner()->BelongsToCurrentThread()) {
    drm_thread_.AddDrmDeviceReceiver(std::move(receiver));
  } else {
    drm_thread_.task_runner()->PostTask(
        FROM_HERE,
        base::BindOnce(&DrmThread::AddDrmDeviceReceiver,
                       base::Unretained(&drm_thread_), std::move(receiver)));
  }
}

scoped_refptr<base::SingleThreadTaskRunner>
DrmThreadProxy::GetDrmThreadTaskRunner() {
  return drm_thread_.task_runner();
}

bool DrmThreadProxy::WaitUntilDrmThreadStarted() {
  return drm_thread_.WaitUntilThreadStarted();
}

void DrmThreadProxy::SetDrmModifiersFilter(
    std::unique_ptr<DrmModifiersFilter> filter) {
  DCHECK(drm_thread_.task_runner());
  base::OnceClosure task =
      base::BindOnce(&DrmThread::SetDrmModifiersFilter,
                     base::Unretained(&drm_thread_), std::move(filter));
  drm_thread_.task_runner()->PostTask(FROM_HERE, std::move(task));
}

}  // namespace ui