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