| 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
|
|
|