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.
5 #include "ui/ozone/platform/drm/gpu/drm_window.h"
7 #include "base/trace_event/trace_event.h"
8 #include "third_party/skia/include/core/SkBitmap.h"
9 #include "third_party/skia/include/core/SkDevice.h"
10 #include "third_party/skia/include/core/SkSurface.h"
11 #include "ui/ozone/common/gpu/ozone_gpu_message_params.h"
12 #include "ui/ozone/platform/drm/gpu/drm_buffer.h"
13 #include "ui/ozone/platform/drm/gpu/drm_device.h"
14 #include "ui/ozone/platform/drm/gpu/drm_device_manager.h"
15 #include "ui/ozone/platform/drm/gpu/scanout_buffer.h"
16 #include "ui/ozone/platform/drm/gpu/screen_manager.h"
22 #ifndef DRM_CAP_CURSOR_WIDTH
23 #define DRM_CAP_CURSOR_WIDTH 0x8
26 #ifndef DRM_CAP_CURSOR_HEIGHT
27 #define DRM_CAP_CURSOR_HEIGHT 0x9
30 void EmptyFlipCallback(gfx::SwapResult
) {
33 void UpdateCursorImage(DrmBuffer
* cursor
, const SkBitmap
& image
) {
35 image
.getBounds(&damage
);
37 // Clear to transparent in case |image| is smaller than the canvas.
38 SkCanvas
* canvas
= cursor
->GetCanvas();
39 canvas
->clear(SK_ColorTRANSPARENT
);
42 clip
.set(0, 0, canvas
->getDeviceSize().width(),
43 canvas
->getDeviceSize().height());
44 canvas
->clipRect(clip
, SkRegion::kReplace_Op
);
45 canvas
->drawBitmapRect(image
, damage
);
50 DrmWindow::DrmWindow(gfx::AcceleratedWidget widget
,
51 DrmDeviceManager
* device_manager
,
52 ScreenManager
* screen_manager
)
54 device_manager_(device_manager
),
55 screen_manager_(screen_manager
) {
58 DrmWindow::~DrmWindow() {
61 void DrmWindow::Initialize() {
62 TRACE_EVENT1("drm", "DrmWindow::Initialize", "widget", widget_
);
64 device_manager_
->UpdateDrmDevice(widget_
, nullptr);
67 void DrmWindow::Shutdown() {
68 TRACE_EVENT1("drm", "DrmWindow::Shutdown", "widget", widget_
);
69 device_manager_
->RemoveDrmDevice(widget_
);
72 gfx::AcceleratedWidget
DrmWindow::GetAcceleratedWidget() {
76 HardwareDisplayController
* DrmWindow::GetController() {
80 void DrmWindow::OnBoundsChanged(const gfx::Rect
& bounds
) {
81 TRACE_EVENT2("drm", "DrmWindow::OnBoundsChanged", "widget", widget_
, "bounds",
84 if (bounds_
.size() != bounds
.size())
85 last_submitted_planes_
.clear();
87 screen_manager_
->UpdateControllerToWindowMapping();
90 void DrmWindow::SetCursor(const std::vector
<SkBitmap
>& bitmaps
,
91 const gfx::Point
& location
,
93 cursor_bitmaps_
= bitmaps
;
94 cursor_location_
= location
;
96 cursor_frame_delay_ms_
= frame_delay_ms
;
99 if (cursor_frame_delay_ms_
)
101 FROM_HERE
, base::TimeDelta::FromMilliseconds(cursor_frame_delay_ms_
),
102 this, &DrmWindow::OnCursorAnimationTimeout
);
107 void DrmWindow::SetCursorWithoutAnimations(const std::vector
<SkBitmap
>& bitmaps
,
108 const gfx::Point
& location
) {
109 cursor_bitmaps_
= bitmaps
;
110 cursor_location_
= location
;
112 cursor_frame_delay_ms_
= 0;
116 void DrmWindow::MoveCursor(const gfx::Point
& location
) {
117 cursor_location_
= location
;
120 controller_
->MoveCursor(location
);
123 void DrmWindow::QueueOverlayPlane(const OverlayPlane
& plane
) {
124 pending_planes_
.push_back(plane
);
127 bool DrmWindow::SchedulePageFlip(bool is_sync
,
128 const SwapCompletionCallback
& callback
) {
129 last_submitted_planes_
.clear();
130 last_submitted_planes_
.swap(pending_planes_
);
131 last_swap_sync_
= is_sync
;
134 return controller_
->SchedulePageFlip(last_submitted_planes_
, is_sync
, false,
138 callback
.Run(gfx::SwapResult::SWAP_ACK
);
142 bool DrmWindow::TestPageFlip(const std::vector
<OverlayCheck_Params
>& overlays
,
143 ScanoutBufferGenerator
* buffer_generator
) {
146 for (const auto& overlay
: overlays
) {
147 // It is possible that the cc rect we get actually falls off the edge of
148 // the screen. Usually this is prevented via things like status bars
149 // blocking overlaying or cc clipping it, but in case it wasn't properly
150 // clipped (since GL will render this situation fine) just ignore it here.
151 // This should be an extremely rare occurrance.
152 if (overlay
.plane_z_order
!= 0 && !bounds().Contains(overlay
.display_rect
))
156 scoped_refptr
<DrmDevice
> drm
= controller_
->GetAllocationDrmDevice();
157 OverlayPlaneList planes
;
158 for (const auto& overlay
: overlays
) {
160 (overlay
.plane_z_order
== 0) ? bounds().size() : overlay
.buffer_size
;
161 scoped_refptr
<ScanoutBuffer
> buffer
= buffer_generator
->Create(drm
, size
);
164 planes
.push_back(OverlayPlane(buffer
, overlay
.plane_z_order
,
165 overlay
.transform
, overlay
.display_rect
,
166 gfx::RectF(gfx::Size(1, 1))));
168 return controller_
->SchedulePageFlip(planes
, true, true,
169 base::Bind(&EmptyFlipCallback
));
172 const OverlayPlane
* DrmWindow::GetLastModesetBuffer() {
173 return OverlayPlane::GetPrimaryPlane(last_submitted_planes_
);
176 void DrmWindow::ResetCursor(bool bitmap_only
) {
180 if (cursor_bitmaps_
.size()) {
181 // Draw new cursor into backbuffer.
182 UpdateCursorImage(cursor_buffers_
[cursor_frontbuffer_
^ 1].get(),
183 cursor_bitmaps_
[cursor_frame_
]);
185 // Reset location & buffer.
187 controller_
->MoveCursor(cursor_location_
);
188 controller_
->SetCursor(cursor_buffers_
[cursor_frontbuffer_
^ 1]);
189 cursor_frontbuffer_
^= 1;
192 controller_
->UnsetCursor();
196 void DrmWindow::OnCursorAnimationTimeout() {
198 cursor_frame_
%= cursor_bitmaps_
.size();
203 void DrmWindow::SetController(HardwareDisplayController
* controller
) {
204 if (controller_
== controller
)
207 controller_
= controller
;
208 device_manager_
->UpdateDrmDevice(
209 widget_
, controller
? controller
->GetAllocationDrmDevice() : nullptr);
211 UpdateCursorBuffers();
212 // We changed displays, so we want to update the cursor as well.
213 ResetCursor(false /* bitmap_only */);
216 void DrmWindow::UpdateCursorBuffers() {
218 for (size_t i
= 0; i
< arraysize(cursor_buffers_
); ++i
) {
219 cursor_buffers_
[i
] = nullptr;
222 scoped_refptr
<DrmDevice
> drm
= controller_
->GetAllocationDrmDevice();
224 uint64_t cursor_width
= 64;
225 uint64_t cursor_height
= 64;
226 drm
->GetCapability(DRM_CAP_CURSOR_WIDTH
, &cursor_width
);
227 drm
->GetCapability(DRM_CAP_CURSOR_HEIGHT
, &cursor_height
);
229 SkImageInfo info
= SkImageInfo::MakeN32Premul(cursor_width
, cursor_height
);
230 for (size_t i
= 0; i
< arraysize(cursor_buffers_
); ++i
) {
231 cursor_buffers_
[i
] = new DrmBuffer(drm
);
232 // Don't register a framebuffer for cursors since they are special (they
233 // aren't modesetting buffers and drivers may fail to register them due to
234 // their small sizes).
235 if (!cursor_buffers_
[i
]->Initialize(
236 info
, false /* should_register_framebuffer */)) {
237 LOG(FATAL
) << "Failed to initialize cursor buffer";