1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "ui/ozone/platform/drm/gpu/drm_window.h"
6
7 #include <stddef.h>
8 #include <stdint.h>
9 #include <utility>
10
11 #include "base/macros.h"
12 #include "base/time/time.h"
13 #include "base/trace_event/trace_event.h"
14 #include "third_party/skia/include/core/SkBitmap.h"
15 #include "third_party/skia/include/core/SkCanvas.h"
16 #include "third_party/skia/include/core/SkSurface.h"
17 #include "ui/gfx/gpu_fence.h"
18 #include "ui/gfx/presentation_feedback.h"
19 #include "ui/ozone/platform/drm/common/drm_util.h"
20 #include "ui/ozone/platform/drm/gpu/crtc_controller.h"
21 #include "ui/ozone/platform/drm/gpu/drm_device.h"
22 #include "ui/ozone/platform/drm/gpu/drm_device_manager.h"
23 #include "ui/ozone/platform/drm/gpu/drm_dumb_buffer.h"
24 #include "ui/ozone/platform/drm/gpu/drm_overlay_validator.h"
25 #include "ui/ozone/platform/drm/gpu/screen_manager.h"
26
27 namespace ui {
28
DrmWindow(gfx::AcceleratedWidget widget,DrmDeviceManager * device_manager,ScreenManager * screen_manager)29 DrmWindow::DrmWindow(gfx::AcceleratedWidget widget,
30 DrmDeviceManager* device_manager,
31 ScreenManager* screen_manager)
32 : widget_(widget),
33 device_manager_(device_manager),
34 screen_manager_(screen_manager) {
35 }
36
~DrmWindow()37 DrmWindow::~DrmWindow() {
38 }
39
Initialize()40 void DrmWindow::Initialize() {
41 TRACE_EVENT1("drm", "DrmWindow::Initialize", "widget", widget_);
42
43 device_manager_->UpdateDrmDevice(widget_, nullptr);
44 overlay_validator_ = std::make_unique<DrmOverlayValidator>(this);
45 }
46
Shutdown()47 void DrmWindow::Shutdown() {
48 TRACE_EVENT1("drm", "DrmWindow::Shutdown", "widget", widget_);
49 device_manager_->RemoveDrmDevice(widget_);
50 }
51
GetAcceleratedWidget() const52 gfx::AcceleratedWidget DrmWindow::GetAcceleratedWidget() const {
53 return widget_;
54 }
55
GetController() const56 HardwareDisplayController* DrmWindow::GetController() const {
57 return controller_;
58 }
59
SetBounds(const gfx::Rect & bounds)60 void DrmWindow::SetBounds(const gfx::Rect& bounds) {
61 TRACE_EVENT2("drm", "DrmWindow::SetBounds", "widget", widget_, "bounds",
62 bounds.ToString());
63 if (bounds_.size() != bounds.size())
64 last_submitted_planes_.clear();
65
66 bounds_ = bounds;
67 screen_manager_->UpdateControllerToWindowMapping();
68 }
69
SetCursor(const std::vector<SkBitmap> & bitmaps,const gfx::Point & location,int frame_delay_ms)70 void DrmWindow::SetCursor(const std::vector<SkBitmap>& bitmaps,
71 const gfx::Point& location,
72 int frame_delay_ms) {
73 cursor_bitmaps_ = bitmaps;
74 cursor_location_ = location;
75 cursor_frame_ = 0;
76 cursor_frame_delay_ms_ = frame_delay_ms;
77 cursor_timer_.Stop();
78
79 if (cursor_frame_delay_ms_) {
80 cursor_timer_.Start(
81 FROM_HERE, base::TimeDelta::FromMilliseconds(cursor_frame_delay_ms_),
82 this, &DrmWindow::OnCursorAnimationTimeout);
83 }
84
85 ResetCursor();
86 }
87
MoveCursor(const gfx::Point & location)88 void DrmWindow::MoveCursor(const gfx::Point& location) {
89 cursor_location_ = location;
90 UpdateCursorLocation();
91 }
92
SchedulePageFlip(std::vector<DrmOverlayPlane> planes,SwapCompletionOnceCallback submission_callback,PresentationOnceCallback presentation_callback)93 void DrmWindow::SchedulePageFlip(
94 std::vector<DrmOverlayPlane> planes,
95 SwapCompletionOnceCallback submission_callback,
96 PresentationOnceCallback presentation_callback) {
97 if (controller_) {
98 const DrmDevice* drm = controller_->GetDrmDevice().get();
99 for (const auto& plane : planes) {
100 if (plane.buffer && plane.buffer->drm_device() != drm) {
101 // Although |force_buffer_reallocation_| is set to true during window
102 // bounds update, this may still be needed because of in-flight buffers.
103 force_buffer_reallocation_ = true;
104 break;
105 }
106 }
107 }
108
109 if (force_buffer_reallocation_) {
110 force_buffer_reallocation_ = false;
111 std::move(submission_callback)
112 .Run(gfx::SwapResult::SWAP_NAK_RECREATE_BUFFERS, nullptr);
113 std::move(presentation_callback).Run(gfx::PresentationFeedback::Failure());
114 return;
115 }
116
117 last_submitted_planes_ = DrmOverlayPlane::Clone(planes);
118
119 if (!controller_) {
120 std::move(submission_callback).Run(gfx::SwapResult::SWAP_ACK, nullptr);
121 std::move(presentation_callback).Run(gfx::PresentationFeedback::Failure());
122 return;
123 }
124
125 controller_->SchedulePageFlip(std::move(planes),
126 std::move(submission_callback),
127 std::move(presentation_callback));
128 }
129
TestPageFlip(const OverlaySurfaceCandidateList & overlay_params)130 OverlayStatusList DrmWindow::TestPageFlip(
131 const OverlaySurfaceCandidateList& overlay_params) {
132 return overlay_validator_->TestPageFlip(overlay_params,
133 last_submitted_planes_);
134 }
135
GetLastModesetBuffer() const136 const DrmOverlayPlane* DrmWindow::GetLastModesetBuffer() const {
137 return DrmOverlayPlane::GetPrimaryPlane(last_submitted_planes_);
138 }
139
UpdateCursorImage()140 void DrmWindow::UpdateCursorImage() {
141 if (!controller_)
142 return;
143 if (cursor_bitmaps_.size()) {
144 controller_->SetCursor(cursor_bitmaps_[cursor_frame_]);
145 } else {
146 // No cursor set.
147 controller_->SetCursor(SkBitmap());
148 }
149 }
150
UpdateCursorLocation()151 void DrmWindow::UpdateCursorLocation() {
152 if (!controller_)
153 return;
154 controller_->MoveCursor(cursor_location_);
155 }
156
ResetCursor()157 void DrmWindow::ResetCursor() {
158 UpdateCursorLocation();
159 UpdateCursorImage();
160 }
161
OnCursorAnimationTimeout()162 void DrmWindow::OnCursorAnimationTimeout() {
163 cursor_frame_++;
164 cursor_frame_ %= cursor_bitmaps_.size();
165
166 UpdateCursorImage();
167 }
168
SetController(HardwareDisplayController * controller)169 void DrmWindow::SetController(HardwareDisplayController* controller) {
170 if (controller_ == controller)
171 return;
172
173 // Force buffer reallocation since the window moved to a different controller.
174 // This is required otherwise the GPU will eventually try to render into the
175 // buffer currently showing on the old controller (there is no guarantee that
176 // the old controller has been updated in the meantime).
177 force_buffer_reallocation_ = true;
178
179 controller_ = controller;
180 device_manager_->UpdateDrmDevice(
181 widget_, controller ? controller->GetDrmDevice() : nullptr);
182
183 // We changed displays, so we want to update the cursor as well.
184 ResetCursor();
185 }
186
187 } // namespace ui
188