blob: 44d276df980846df8e19cea04202fae365b4303d [file] [log] [blame]
// Copyright 2014 The Chromium Authors. All rights reserved.
// 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/host/drm_gpu_platform_support_host.h"
#include <stddef.h>
#include "base/command_line.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/trace_event/trace_event.h"
#include "ui/base/ui_base_features.h"
#include "ui/base/ui_base_switches.h"
#include "ui/ozone/common/gpu/ozone_gpu_message_params.h"
#include "ui/ozone/common/gpu/ozone_gpu_messages.h"
#include "ui/ozone/platform/drm/common/drm_util.h"
#include "ui/ozone/platform/drm/host/drm_cursor.h"
#include "ui/ozone/platform/drm/host/drm_display_host_manager.h"
#include "ui/ozone/platform/drm/host/drm_overlay_candidates_host.h"
#include "ui/ozone/platform/drm/host/drm_overlay_manager.h"
#include "ui/ozone/platform/drm/host/gpu_thread_observer.h"
namespace ui {
namespace {
// Helper class that provides DrmCursor with a mechanism to send messages
// to the GPU process.
class CursorIPC : public DrmCursorProxy {
public:
CursorIPC(scoped_refptr<base::SingleThreadTaskRunner> send_runner,
const base::Callback<void(IPC::Message*)>& send_callback);
~CursorIPC() override;
// DrmCursorProxy implementation.
void CursorSet(gfx::AcceleratedWidget window,
const std::vector<SkBitmap>& bitmaps,
const gfx::Point& point,
int frame_delay_ms) override;
void Move(gfx::AcceleratedWidget window, const gfx::Point& point) override;
void InitializeOnEvdevIfNecessary() override;
private:
bool IsConnected();
void Send(IPC::Message* message);
scoped_refptr<base::SingleThreadTaskRunner> send_runner_;
base::Callback<void(IPC::Message*)> send_callback_;
DISALLOW_COPY_AND_ASSIGN(CursorIPC);
};
CursorIPC::CursorIPC(scoped_refptr<base::SingleThreadTaskRunner> send_runner,
const base::Callback<void(IPC::Message*)>& send_callback)
: send_runner_(send_runner), send_callback_(send_callback) {}
CursorIPC::~CursorIPC() {}
bool CursorIPC::IsConnected() {
return !send_callback_.is_null();
}
void CursorIPC::CursorSet(gfx::AcceleratedWidget window,
const std::vector<SkBitmap>& bitmaps,
const gfx::Point& point,
int frame_delay_ms) {
Send(new OzoneGpuMsg_CursorSet(window, bitmaps, point, frame_delay_ms));
}
void CursorIPC::Move(gfx::AcceleratedWidget window, const gfx::Point& point) {
Send(new OzoneGpuMsg_CursorMove(window, point));
}
void CursorIPC::InitializeOnEvdevIfNecessary() {}
void CursorIPC::Send(IPC::Message* message) {
if (IsConnected() && send_runner_->PostTask(
FROM_HERE, base::BindOnce(send_callback_, message)))
return;
// Drop disconnected updates. DrmWindowHost will call
// CommitBoundsChange() when we connect to initialize the cursor
// location.
delete message;
}
} // namespace
DrmGpuPlatformSupportHost::DrmGpuPlatformSupportHost(DrmCursor* cursor)
: ui_runner_(base::ThreadTaskRunnerHandle::IsSet()
? base::ThreadTaskRunnerHandle::Get()
: nullptr),
cursor_(cursor),
weak_ptr_factory_(this) {
if (ui_runner_) {
weak_ptr_ = weak_ptr_factory_.GetWeakPtr();
} else {
DCHECK(!features::IsMusEnabled());
}
}
DrmGpuPlatformSupportHost::~DrmGpuPlatformSupportHost() {}
void DrmGpuPlatformSupportHost::AddGpuThreadObserver(
GpuThreadObserver* observer) {
gpu_thread_observers_.AddObserver(observer);
if (IsConnected())
observer->OnGpuThreadReady();
}
void DrmGpuPlatformSupportHost::RemoveGpuThreadObserver(
GpuThreadObserver* observer) {
gpu_thread_observers_.RemoveObserver(observer);
}
bool DrmGpuPlatformSupportHost::IsConnected() {
return host_id_ >= 0 && channel_established_;
}
void DrmGpuPlatformSupportHost::OnGpuServiceLaunched(
scoped_refptr<base::SingleThreadTaskRunner> ui_runner,
scoped_refptr<base::SingleThreadTaskRunner> io_runner,
GpuHostBindInterfaceCallback binder) {
NOTREACHED() << "DrmGpuPlatformSupportHost::OnGpuServiceLaunched shouldn't "
"be used with pre-mojo IPC";
}
void DrmGpuPlatformSupportHost::OnGpuProcessLaunched(
int host_id,
scoped_refptr<base::SingleThreadTaskRunner> ui_runner,
scoped_refptr<base::SingleThreadTaskRunner> send_runner,
const base::Callback<void(IPC::Message*)>& send_callback) {
// If there was a task runner set during construction, prefer using that.
if (!ui_runner_) {
ui_runner_ = std::move(ui_runner);
weak_ptr_ = weak_ptr_factory_.GetWeakPtr();
}
DCHECK(!ui_runner_->BelongsToCurrentThread());
TRACE_EVENT1("drm", "DrmGpuPlatformSupportHost::OnGpuProcessLaunched",
"host_id", host_id);
host_id_ = host_id;
send_runner_ = std::move(send_runner);
send_callback_ = send_callback;
for (GpuThreadObserver& observer : gpu_thread_observers_)
observer.OnGpuProcessLaunched();
ui_runner_->PostTask(
FROM_HERE,
base::BindOnce(&DrmGpuPlatformSupportHost::OnChannelEstablished,
weak_ptr_));
}
void DrmGpuPlatformSupportHost::OnChannelDestroyed(int host_id) {
TRACE_EVENT1("drm", "DrmGpuPlatformSupportHost::OnChannelDestroyed",
"host_id", host_id);
if (host_id_ == host_id) {
cursor_->ResetDrmCursorProxy();
host_id_ = -1;
channel_established_ = false;
send_runner_ = nullptr;
send_callback_.Reset();
for (GpuThreadObserver& observer : gpu_thread_observers_)
observer.OnGpuThreadRetired();
}
}
void DrmGpuPlatformSupportHost::OnMessageReceived(const IPC::Message& message) {
DCHECK(ui_runner_);
if (ui_runner_->BelongsToCurrentThread()) {
if (OnMessageReceivedForDrmDisplayHostManager(message))
return;
OnMessageReceivedForDrmOverlayManager(message);
} else {
ui_runner_->PostTask(
FROM_HERE, base::BindOnce(&DrmGpuPlatformSupportHost::OnMessageReceived,
weak_ptr_, message));
}
}
bool DrmGpuPlatformSupportHost::Send(IPC::Message* message) {
if (IsConnected() && send_runner_->PostTask(
FROM_HERE, base::BindOnce(send_callback_, message)))
return true;
delete message;
return false;
}
// DisplayHost
void DrmGpuPlatformSupportHost::RegisterHandlerForDrmDisplayHostManager(
DrmDisplayHostManager* handler) {
display_manager_ = handler;
}
void DrmGpuPlatformSupportHost::UnRegisterHandlerForDrmDisplayHostManager() {
display_manager_ = nullptr;
}
void DrmGpuPlatformSupportHost::OnChannelEstablished() {
TRACE_EVENT0("drm", "DrmGpuPlatformSupportHost::OnChannelEstablished");
channel_established_ = true;
for (GpuThreadObserver& observer : gpu_thread_observers_)
observer.OnGpuThreadReady();
// The cursor is special since it will process input events on the IO thread
// and can by-pass the UI thread. This means that we need to special case it
// and notify it after all other observers/handlers are notified such that the
// (windowing) state on the GPU can be initialized before the cursor is
// allowed to IPC messages (which are targeted to a specific window).
cursor_->SetDrmCursorProxy(
std::make_unique<CursorIPC>(send_runner_, send_callback_));
}
bool DrmGpuPlatformSupportHost::OnMessageReceivedForDrmDisplayHostManager(
const IPC::Message& message) {
bool handled = true;
IPC_BEGIN_MESSAGE_MAP(DrmGpuPlatformSupportHost, message)
IPC_MESSAGE_HANDLER(OzoneHostMsg_UpdateNativeDisplays,
OnUpdateNativeDisplays)
IPC_MESSAGE_HANDLER(OzoneHostMsg_DisplayConfigured, OnDisplayConfigured)
IPC_MESSAGE_HANDLER(OzoneHostMsg_HDCPStateReceived, OnHDCPStateReceived)
IPC_MESSAGE_HANDLER(OzoneHostMsg_HDCPStateUpdated, OnHDCPStateUpdated)
IPC_MESSAGE_HANDLER(OzoneHostMsg_DisplayControlTaken, OnTakeDisplayControl)
IPC_MESSAGE_HANDLER(OzoneHostMsg_DisplayControlRelinquished,
OnRelinquishDisplayControl)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
return handled;
}
void DrmGpuPlatformSupportHost::OnUpdateNativeDisplays(
const std::vector<DisplaySnapshot_Params>& params) {
display_manager_->GpuHasUpdatedNativeDisplays(params);
}
void DrmGpuPlatformSupportHost::OnDisplayConfigured(int64_t display_id,
bool status) {
display_manager_->GpuConfiguredDisplay(display_id, status);
}
void DrmGpuPlatformSupportHost::OnHDCPStateReceived(int64_t display_id,
bool status,
display::HDCPState state) {
display_manager_->GpuReceivedHDCPState(display_id, status, state);
}
void DrmGpuPlatformSupportHost::OnHDCPStateUpdated(int64_t display_id,
bool status) {
display_manager_->GpuUpdatedHDCPState(display_id, status);
}
void DrmGpuPlatformSupportHost::OnTakeDisplayControl(bool status) {
display_manager_->GpuTookDisplayControl(status);
}
void DrmGpuPlatformSupportHost::OnRelinquishDisplayControl(bool status) {
display_manager_->GpuRelinquishedDisplayControl(status);
}
bool DrmGpuPlatformSupportHost::GpuRefreshNativeDisplays() {
return Send(new OzoneGpuMsg_RefreshNativeDisplays());
}
bool DrmGpuPlatformSupportHost::GpuTakeDisplayControl() {
return Send(new OzoneGpuMsg_TakeDisplayControl());
}
bool DrmGpuPlatformSupportHost::GpuRelinquishDisplayControl() {
return Send(new OzoneGpuMsg_RelinquishDisplayControl());
}
bool DrmGpuPlatformSupportHost::GpuAddGraphicsDevice(const base::FilePath& path,
base::ScopedFD fd) {
IPC::Message* message = new OzoneGpuMsg_AddGraphicsDevice(
path, base::FileDescriptor(std::move(fd)));
// This function may be called from two places:
// - DrmDisplayHostManager::OnGpuProcessLaunched() invoked synchronously
// by GpuProcessHost::Init() on IO thread, which is the same thread as
// |send_runner_|. In this case we can synchronously send the IPC;
// - DrmDisplayHostManager::OnAddGraphicsDevice() on UI thread. In this
// case we need to post the send task to IO thread.
if (send_runner_ && send_runner_->BelongsToCurrentThread()) {
DCHECK(!send_callback_.is_null());
send_callback_.Run(message);
return true;
}
return Send(message);
}
bool DrmGpuPlatformSupportHost::GpuRemoveGraphicsDevice(
const base::FilePath& path) {
return Send(new OzoneGpuMsg_RemoveGraphicsDevice(path));
}
// Overlays
void DrmGpuPlatformSupportHost::RegisterHandlerForDrmOverlayManager(
DrmOverlayManager* handler) {
overlay_manager_ = handler;
}
void DrmGpuPlatformSupportHost::UnRegisterHandlerForDrmOverlayManager() {
overlay_manager_ = nullptr;
}
bool DrmGpuPlatformSupportHost::OnMessageReceivedForDrmOverlayManager(
const IPC::Message& message) {
bool handled = true;
IPC_BEGIN_MESSAGE_MAP(DrmGpuPlatformSupportHost, message)
IPC_MESSAGE_HANDLER(OzoneHostMsg_OverlayCapabilitiesReceived,
OnOverlayResult)
// TODO(rjk): insert the extra
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
return handled;
}
void DrmGpuPlatformSupportHost::OnOverlayResult(
gfx::AcceleratedWidget widget,
const std::vector<OverlayCheck_Params>& params,
const std::vector<OverlayCheckReturn_Params>& param_returns) {
auto candidates = CreateOverlaySurfaceCandidateListFrom(params);
auto returns = CreateOverlayStatusListFrom(param_returns);
overlay_manager_->GpuSentOverlayResult(widget, candidates, returns);
}
bool DrmGpuPlatformSupportHost::GpuCheckOverlayCapabilities(
gfx::AcceleratedWidget widget,
const OverlaySurfaceCandidateList& candidates) {
auto params = CreateParamsFromOverlaySurfaceCandidate(candidates);
return Send(new OzoneGpuMsg_CheckOverlayCapabilities(widget, params));
}
// DrmDisplayHost
bool DrmGpuPlatformSupportHost::GpuConfigureNativeDisplay(
int64_t display_id,
const ui::DisplayMode_Params& display_mode,
const gfx::Point& point) {
return Send(
new OzoneGpuMsg_ConfigureNativeDisplay(display_id, display_mode, point));
}
bool DrmGpuPlatformSupportHost::GpuDisableNativeDisplay(int64_t display_id) {
return Send(new OzoneGpuMsg_DisableNativeDisplay(display_id));
}
bool DrmGpuPlatformSupportHost::GpuGetHDCPState(int64_t display_id) {
return Send(new OzoneGpuMsg_GetHDCPState(display_id));
}
bool DrmGpuPlatformSupportHost::GpuSetHDCPState(int64_t display_id,
display::HDCPState state) {
return Send(new OzoneGpuMsg_SetHDCPState(display_id, state));
}
bool DrmGpuPlatformSupportHost::GpuSetColorCorrection(
int64_t display_id,
const std::vector<display::GammaRampRGBEntry>& degamma_lut,
const std::vector<display::GammaRampRGBEntry>& gamma_lut,
const std::vector<float>& correction_matrix) {
return Send(new OzoneGpuMsg_SetColorCorrection(display_id, degamma_lut,
gamma_lut, correction_matrix));
}
bool DrmGpuPlatformSupportHost::GpuDestroyWindow(
gfx::AcceleratedWidget widget) {
return Send(new OzoneGpuMsg_DestroyWindow(widget));
}
bool DrmGpuPlatformSupportHost::GpuCreateWindow(gfx::AcceleratedWidget widget) {
return Send(new OzoneGpuMsg_CreateWindow(widget));
}
bool DrmGpuPlatformSupportHost::GpuWindowBoundsChanged(
gfx::AcceleratedWidget widget,
const gfx::Rect& bounds) {
return Send(new OzoneGpuMsg_WindowBoundsChanged(widget, bounds));
}
} // namespace ui