OLD | NEW |
(Empty) | |
| 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 "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" |
| 17 |
| 18 namespace ui { |
| 19 |
| 20 namespace { |
| 21 |
| 22 #ifndef DRM_CAP_CURSOR_WIDTH |
| 23 #define DRM_CAP_CURSOR_WIDTH 0x8 |
| 24 #endif |
| 25 |
| 26 #ifndef DRM_CAP_CURSOR_HEIGHT |
| 27 #define DRM_CAP_CURSOR_HEIGHT 0x9 |
| 28 #endif |
| 29 |
| 30 void EmptyFlipCallback(gfx::SwapResult) { |
| 31 } |
| 32 |
| 33 void UpdateCursorImage(DrmBuffer* cursor, const SkBitmap& image) { |
| 34 SkRect damage; |
| 35 image.getBounds(&damage); |
| 36 |
| 37 // Clear to transparent in case |image| is smaller than the canvas. |
| 38 SkCanvas* canvas = cursor->GetCanvas(); |
| 39 canvas->clear(SK_ColorTRANSPARENT); |
| 40 |
| 41 SkRect clip; |
| 42 clip.set(0, 0, canvas->getDeviceSize().width(), |
| 43 canvas->getDeviceSize().height()); |
| 44 canvas->clipRect(clip, SkRegion::kReplace_Op); |
| 45 canvas->drawBitmapRectToRect(image, &damage, damage); |
| 46 } |
| 47 |
| 48 } // namespace |
| 49 |
| 50 DrmWindow::DrmWindow(gfx::AcceleratedWidget widget, |
| 51 DrmDeviceManager* device_manager, |
| 52 ScreenManager* screen_manager) |
| 53 : widget_(widget), |
| 54 device_manager_(device_manager), |
| 55 screen_manager_(screen_manager) { |
| 56 } |
| 57 |
| 58 DrmWindow::~DrmWindow() { |
| 59 } |
| 60 |
| 61 void DrmWindow::Initialize() { |
| 62 TRACE_EVENT1("drm", "DrmWindow::Initialize", "widget", widget_); |
| 63 |
| 64 device_manager_->UpdateDrmDevice(widget_, nullptr); |
| 65 } |
| 66 |
| 67 void DrmWindow::Shutdown() { |
| 68 TRACE_EVENT1("drm", "DrmWindow::Shutdown", "widget", widget_); |
| 69 device_manager_->RemoveDrmDevice(widget_); |
| 70 } |
| 71 |
| 72 gfx::AcceleratedWidget DrmWindow::GetAcceleratedWidget() { |
| 73 return widget_; |
| 74 } |
| 75 |
| 76 HardwareDisplayController* DrmWindow::GetController() { |
| 77 return controller_; |
| 78 } |
| 79 |
| 80 void DrmWindow::OnBoundsChanged(const gfx::Rect& bounds) { |
| 81 TRACE_EVENT2("drm", "DrmWindow::OnBoundsChanged", "widget", widget_, "bounds", |
| 82 bounds.ToString()); |
| 83 bounds_ = bounds; |
| 84 if (bounds_.size() != bounds.size()) |
| 85 last_submitted_planes_.clear(); |
| 86 |
| 87 screen_manager_->UpdateControllerToWindowMapping(); |
| 88 } |
| 89 |
| 90 void DrmWindow::SetCursor(const std::vector<SkBitmap>& bitmaps, |
| 91 const gfx::Point& location, |
| 92 int frame_delay_ms) { |
| 93 cursor_bitmaps_ = bitmaps; |
| 94 cursor_location_ = location; |
| 95 cursor_frame_ = 0; |
| 96 cursor_frame_delay_ms_ = frame_delay_ms; |
| 97 cursor_timer_.Stop(); |
| 98 |
| 99 if (cursor_frame_delay_ms_) |
| 100 cursor_timer_.Start( |
| 101 FROM_HERE, base::TimeDelta::FromMilliseconds(cursor_frame_delay_ms_), |
| 102 this, &DrmWindow::OnCursorAnimationTimeout); |
| 103 |
| 104 ResetCursor(false); |
| 105 } |
| 106 |
| 107 void DrmWindow::SetCursorWithoutAnimations(const std::vector<SkBitmap>& bitmaps, |
| 108 const gfx::Point& location) { |
| 109 cursor_bitmaps_ = bitmaps; |
| 110 cursor_location_ = location; |
| 111 cursor_frame_ = 0; |
| 112 cursor_frame_delay_ms_ = 0; |
| 113 ResetCursor(false); |
| 114 } |
| 115 |
| 116 void DrmWindow::MoveCursor(const gfx::Point& location) { |
| 117 cursor_location_ = location; |
| 118 |
| 119 if (controller_) |
| 120 controller_->MoveCursor(location); |
| 121 } |
| 122 |
| 123 void DrmWindow::QueueOverlayPlane(const OverlayPlane& plane) { |
| 124 pending_planes_.push_back(plane); |
| 125 } |
| 126 |
| 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; |
| 132 |
| 133 if (controller_) { |
| 134 return controller_->SchedulePageFlip(last_submitted_planes_, is_sync, false, |
| 135 callback); |
| 136 } |
| 137 |
| 138 callback.Run(gfx::SwapResult::SWAP_ACK); |
| 139 return true; |
| 140 } |
| 141 |
| 142 bool DrmWindow::TestPageFlip(const std::vector<OverlayCheck_Params>& overlays, |
| 143 ScanoutBufferGenerator* buffer_generator) { |
| 144 if (!controller_) |
| 145 return true; |
| 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)) |
| 153 return false; |
| 154 } |
| 155 |
| 156 scoped_refptr<DrmDevice> drm = controller_->GetAllocationDrmDevice(); |
| 157 OverlayPlaneList planes; |
| 158 for (const auto& overlay : overlays) { |
| 159 gfx::Size size = |
| 160 (overlay.plane_z_order == 0) ? bounds().size() : overlay.buffer_size; |
| 161 scoped_refptr<ScanoutBuffer> buffer = buffer_generator->Create(drm, size); |
| 162 if (!buffer) |
| 163 return false; |
| 164 planes.push_back(OverlayPlane(buffer, overlay.plane_z_order, |
| 165 overlay.transform, overlay.display_rect, |
| 166 gfx::RectF(gfx::Size(1, 1)))); |
| 167 } |
| 168 return controller_->SchedulePageFlip(planes, true, true, |
| 169 base::Bind(&EmptyFlipCallback)); |
| 170 } |
| 171 |
| 172 const OverlayPlane* DrmWindow::GetLastModesetBuffer() { |
| 173 return OverlayPlane::GetPrimaryPlane(last_submitted_planes_); |
| 174 } |
| 175 |
| 176 void DrmWindow::ResetCursor(bool bitmap_only) { |
| 177 if (!controller_) |
| 178 return; |
| 179 |
| 180 if (cursor_bitmaps_.size()) { |
| 181 // Draw new cursor into backbuffer. |
| 182 UpdateCursorImage(cursor_buffers_[cursor_frontbuffer_ ^ 1].get(), |
| 183 cursor_bitmaps_[cursor_frame_]); |
| 184 |
| 185 // Reset location & buffer. |
| 186 if (!bitmap_only) |
| 187 controller_->MoveCursor(cursor_location_); |
| 188 controller_->SetCursor(cursor_buffers_[cursor_frontbuffer_ ^ 1]); |
| 189 cursor_frontbuffer_ ^= 1; |
| 190 } else { |
| 191 // No cursor set. |
| 192 controller_->UnsetCursor(); |
| 193 } |
| 194 } |
| 195 |
| 196 void DrmWindow::OnCursorAnimationTimeout() { |
| 197 cursor_frame_++; |
| 198 cursor_frame_ %= cursor_bitmaps_.size(); |
| 199 |
| 200 ResetCursor(true); |
| 201 } |
| 202 |
| 203 void DrmWindow::SetController(HardwareDisplayController* controller) { |
| 204 if (controller_ == controller) |
| 205 return; |
| 206 |
| 207 controller_ = controller; |
| 208 device_manager_->UpdateDrmDevice( |
| 209 widget_, controller ? controller->GetAllocationDrmDevice() : nullptr); |
| 210 |
| 211 UpdateCursorBuffers(); |
| 212 // We changed displays, so we want to update the cursor as well. |
| 213 ResetCursor(false /* bitmap_only */); |
| 214 } |
| 215 |
| 216 void DrmWindow::UpdateCursorBuffers() { |
| 217 if (!controller_) { |
| 218 for (size_t i = 0; i < arraysize(cursor_buffers_); ++i) { |
| 219 cursor_buffers_[i] = nullptr; |
| 220 } |
| 221 } else { |
| 222 scoped_refptr<DrmDevice> drm = controller_->GetAllocationDrmDevice(); |
| 223 |
| 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); |
| 228 |
| 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"; |
| 238 return; |
| 239 } |
| 240 } |
| 241 } |
| 242 } |
| 243 |
| 244 } // namespace ui |
OLD | NEW |