Index: ui/ozone/platform/drm/gpu/drm_window.cc |
diff --git a/ui/ozone/platform/drm/gpu/drm_window.cc b/ui/ozone/platform/drm/gpu/drm_window.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..3dda06cd307395763a54f9b96b38705affbeab7a |
--- /dev/null |
+++ b/ui/ozone/platform/drm/gpu/drm_window.cc |
@@ -0,0 +1,244 @@ |
+// 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/gpu/drm_window.h" |
+ |
+#include "base/trace_event/trace_event.h" |
+#include "third_party/skia/include/core/SkBitmap.h" |
+#include "third_party/skia/include/core/SkDevice.h" |
+#include "third_party/skia/include/core/SkSurface.h" |
+#include "ui/ozone/common/gpu/ozone_gpu_message_params.h" |
+#include "ui/ozone/platform/drm/gpu/drm_buffer.h" |
+#include "ui/ozone/platform/drm/gpu/drm_device.h" |
+#include "ui/ozone/platform/drm/gpu/drm_device_manager.h" |
+#include "ui/ozone/platform/drm/gpu/scanout_buffer.h" |
+#include "ui/ozone/platform/drm/gpu/screen_manager.h" |
+ |
+namespace ui { |
+ |
+namespace { |
+ |
+#ifndef DRM_CAP_CURSOR_WIDTH |
+#define DRM_CAP_CURSOR_WIDTH 0x8 |
+#endif |
+ |
+#ifndef DRM_CAP_CURSOR_HEIGHT |
+#define DRM_CAP_CURSOR_HEIGHT 0x9 |
+#endif |
+ |
+void EmptyFlipCallback(gfx::SwapResult) { |
+} |
+ |
+void UpdateCursorImage(DrmBuffer* cursor, const SkBitmap& image) { |
+ SkRect damage; |
+ image.getBounds(&damage); |
+ |
+ // Clear to transparent in case |image| is smaller than the canvas. |
+ SkCanvas* canvas = cursor->GetCanvas(); |
+ canvas->clear(SK_ColorTRANSPARENT); |
+ |
+ SkRect clip; |
+ clip.set(0, 0, canvas->getDeviceSize().width(), |
+ canvas->getDeviceSize().height()); |
+ canvas->clipRect(clip, SkRegion::kReplace_Op); |
+ canvas->drawBitmapRectToRect(image, &damage, damage); |
+} |
+ |
+} // namespace |
+ |
+DrmWindow::DrmWindow(gfx::AcceleratedWidget widget, |
+ DrmDeviceManager* device_manager, |
+ ScreenManager* screen_manager) |
+ : widget_(widget), |
+ device_manager_(device_manager), |
+ screen_manager_(screen_manager) { |
+} |
+ |
+DrmWindow::~DrmWindow() { |
+} |
+ |
+void DrmWindow::Initialize() { |
+ TRACE_EVENT1("drm", "DrmWindow::Initialize", "widget", widget_); |
+ |
+ device_manager_->UpdateDrmDevice(widget_, nullptr); |
+} |
+ |
+void DrmWindow::Shutdown() { |
+ TRACE_EVENT1("drm", "DrmWindow::Shutdown", "widget", widget_); |
+ device_manager_->RemoveDrmDevice(widget_); |
+} |
+ |
+gfx::AcceleratedWidget DrmWindow::GetAcceleratedWidget() { |
+ return widget_; |
+} |
+ |
+HardwareDisplayController* DrmWindow::GetController() { |
+ return controller_; |
+} |
+ |
+void DrmWindow::OnBoundsChanged(const gfx::Rect& bounds) { |
+ TRACE_EVENT2("drm", "DrmWindow::OnBoundsChanged", "widget", widget_, "bounds", |
+ bounds.ToString()); |
+ bounds_ = bounds; |
+ if (bounds_.size() != bounds.size()) |
+ last_submitted_planes_.clear(); |
+ |
+ screen_manager_->UpdateControllerToWindowMapping(); |
+} |
+ |
+void DrmWindow::SetCursor(const std::vector<SkBitmap>& bitmaps, |
+ const gfx::Point& location, |
+ int frame_delay_ms) { |
+ cursor_bitmaps_ = bitmaps; |
+ cursor_location_ = location; |
+ cursor_frame_ = 0; |
+ cursor_frame_delay_ms_ = frame_delay_ms; |
+ cursor_timer_.Stop(); |
+ |
+ if (cursor_frame_delay_ms_) |
+ cursor_timer_.Start( |
+ FROM_HERE, base::TimeDelta::FromMilliseconds(cursor_frame_delay_ms_), |
+ this, &DrmWindow::OnCursorAnimationTimeout); |
+ |
+ ResetCursor(false); |
+} |
+ |
+void DrmWindow::SetCursorWithoutAnimations(const std::vector<SkBitmap>& bitmaps, |
+ const gfx::Point& location) { |
+ cursor_bitmaps_ = bitmaps; |
+ cursor_location_ = location; |
+ cursor_frame_ = 0; |
+ cursor_frame_delay_ms_ = 0; |
+ ResetCursor(false); |
+} |
+ |
+void DrmWindow::MoveCursor(const gfx::Point& location) { |
+ cursor_location_ = location; |
+ |
+ if (controller_) |
+ controller_->MoveCursor(location); |
+} |
+ |
+void DrmWindow::QueueOverlayPlane(const OverlayPlane& plane) { |
+ pending_planes_.push_back(plane); |
+} |
+ |
+bool DrmWindow::SchedulePageFlip(bool is_sync, |
+ const SwapCompletionCallback& callback) { |
+ last_submitted_planes_.clear(); |
+ last_submitted_planes_.swap(pending_planes_); |
+ last_swap_sync_ = is_sync; |
+ |
+ if (controller_) { |
+ return controller_->SchedulePageFlip(last_submitted_planes_, is_sync, false, |
+ callback); |
+ } |
+ |
+ callback.Run(gfx::SwapResult::SWAP_ACK); |
+ return true; |
+} |
+ |
+bool DrmWindow::TestPageFlip(const std::vector<OverlayCheck_Params>& overlays, |
+ ScanoutBufferGenerator* buffer_generator) { |
+ if (!controller_) |
+ return true; |
+ for (const auto& overlay : overlays) { |
+ // It is possible that the cc rect we get actually falls off the edge of |
+ // the screen. Usually this is prevented via things like status bars |
+ // blocking overlaying or cc clipping it, but in case it wasn't properly |
+ // clipped (since GL will render this situation fine) just ignore it here. |
+ // This should be an extremely rare occurrance. |
+ if (overlay.plane_z_order != 0 && !bounds().Contains(overlay.display_rect)) |
+ return false; |
+ } |
+ |
+ scoped_refptr<DrmDevice> drm = controller_->GetAllocationDrmDevice(); |
+ OverlayPlaneList planes; |
+ for (const auto& overlay : overlays) { |
+ gfx::Size size = |
+ (overlay.plane_z_order == 0) ? bounds().size() : overlay.buffer_size; |
+ scoped_refptr<ScanoutBuffer> buffer = buffer_generator->Create(drm, size); |
+ if (!buffer) |
+ return false; |
+ planes.push_back(OverlayPlane(buffer, overlay.plane_z_order, |
+ overlay.transform, overlay.display_rect, |
+ gfx::RectF(gfx::Size(1, 1)))); |
+ } |
+ return controller_->SchedulePageFlip(planes, true, true, |
+ base::Bind(&EmptyFlipCallback)); |
+} |
+ |
+const OverlayPlane* DrmWindow::GetLastModesetBuffer() { |
+ return OverlayPlane::GetPrimaryPlane(last_submitted_planes_); |
+} |
+ |
+void DrmWindow::ResetCursor(bool bitmap_only) { |
+ if (!controller_) |
+ return; |
+ |
+ if (cursor_bitmaps_.size()) { |
+ // Draw new cursor into backbuffer. |
+ UpdateCursorImage(cursor_buffers_[cursor_frontbuffer_ ^ 1].get(), |
+ cursor_bitmaps_[cursor_frame_]); |
+ |
+ // Reset location & buffer. |
+ if (!bitmap_only) |
+ controller_->MoveCursor(cursor_location_); |
+ controller_->SetCursor(cursor_buffers_[cursor_frontbuffer_ ^ 1]); |
+ cursor_frontbuffer_ ^= 1; |
+ } else { |
+ // No cursor set. |
+ controller_->UnsetCursor(); |
+ } |
+} |
+ |
+void DrmWindow::OnCursorAnimationTimeout() { |
+ cursor_frame_++; |
+ cursor_frame_ %= cursor_bitmaps_.size(); |
+ |
+ ResetCursor(true); |
+} |
+ |
+void DrmWindow::SetController(HardwareDisplayController* controller) { |
+ if (controller_ == controller) |
+ return; |
+ |
+ controller_ = controller; |
+ device_manager_->UpdateDrmDevice( |
+ widget_, controller ? controller->GetAllocationDrmDevice() : nullptr); |
+ |
+ UpdateCursorBuffers(); |
+ // We changed displays, so we want to update the cursor as well. |
+ ResetCursor(false /* bitmap_only */); |
+} |
+ |
+void DrmWindow::UpdateCursorBuffers() { |
+ if (!controller_) { |
+ for (size_t i = 0; i < arraysize(cursor_buffers_); ++i) { |
+ cursor_buffers_[i] = nullptr; |
+ } |
+ } else { |
+ scoped_refptr<DrmDevice> drm = controller_->GetAllocationDrmDevice(); |
+ |
+ uint64_t cursor_width = 64; |
+ uint64_t cursor_height = 64; |
+ drm->GetCapability(DRM_CAP_CURSOR_WIDTH, &cursor_width); |
+ drm->GetCapability(DRM_CAP_CURSOR_HEIGHT, &cursor_height); |
+ |
+ SkImageInfo info = SkImageInfo::MakeN32Premul(cursor_width, cursor_height); |
+ for (size_t i = 0; i < arraysize(cursor_buffers_); ++i) { |
+ cursor_buffers_[i] = new DrmBuffer(drm); |
+ // Don't register a framebuffer for cursors since they are special (they |
+ // aren't modesetting buffers and drivers may fail to register them due to |
+ // their small sizes). |
+ if (!cursor_buffers_[i]->Initialize( |
+ info, false /* should_register_framebuffer */)) { |
+ LOG(FATAL) << "Failed to initialize cursor buffer"; |
+ return; |
+ } |
+ } |
+ } |
+} |
+ |
+} // namespace ui |