Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(463)

Unified Diff: ui/ozone/platform/drm/gpu/screen_manager.cc

Issue 1285183008: Ozone integration. (Closed) Base URL: https://github.com/domokit/mojo.git@master
Patch Set: add missing license header Created 5 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « ui/ozone/platform/drm/gpu/screen_manager.h ('k') | ui/ozone/platform/drm/gpu/screen_manager_unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: ui/ozone/platform/drm/gpu/screen_manager.cc
diff --git a/ui/ozone/platform/drm/gpu/screen_manager.cc b/ui/ozone/platform/drm/gpu/screen_manager.cc
new file mode 100644
index 0000000000000000000000000000000000000000..4b4d3f13d75a1e813425e82198ceaa5b333a542a
--- /dev/null
+++ b/ui/ozone/platform/drm/gpu/screen_manager.cc
@@ -0,0 +1,348 @@
+// 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/screen_manager.h"
+
+#include <xf86drmMode.h>
+
+#include "third_party/skia/include/core/SkCanvas.h"
+#include "ui/gfx/geometry/point.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/geometry/size.h"
+#include "ui/ozone/platform/drm/common/drm_util.h"
+#include "ui/ozone/platform/drm/gpu/crtc_controller.h"
+#include "ui/ozone/platform/drm/gpu/drm_console_buffer.h"
+#include "ui/ozone/platform/drm/gpu/drm_device.h"
+#include "ui/ozone/platform/drm/gpu/drm_window.h"
+#include "ui/ozone/platform/drm/gpu/hardware_display_controller.h"
+#include "ui/ozone/platform/drm/gpu/scanout_buffer.h"
+
+namespace ui {
+
+namespace {
+
+// Copies the contents of the saved framebuffer from the CRTCs in |controller|
+// to the new modeset buffer |buffer|.
+void FillModesetBuffer(const scoped_refptr<DrmDevice>& drm,
+ HardwareDisplayController* controller,
+ ScanoutBuffer* buffer) {
+ DrmConsoleBuffer modeset_buffer(drm, buffer->GetFramebufferId());
+ if (!modeset_buffer.Initialize()) {
+ VLOG(2) << "Failed to grab framebuffer " << buffer->GetFramebufferId();
+ return;
+ }
+
+ auto crtcs = controller->crtc_controllers();
+ DCHECK(!crtcs.empty());
+
+ ScopedDrmCrtcPtr saved_crtc(drm->GetCrtc(crtcs[0]->crtc()));
+ if (!saved_crtc || !saved_crtc->buffer_id) {
+ VLOG(2) << "Crtc has no saved state or wasn't modeset";
+ return;
+ }
+
+ // If the display controller is in mirror mode, the CRTCs should be sharing
+ // the same framebuffer.
+ DrmConsoleBuffer saved_buffer(drm, saved_crtc->buffer_id);
+ if (!saved_buffer.Initialize()) {
+ VLOG(2) << "Failed to grab saved framebuffer " << saved_crtc->buffer_id;
+ return;
+ }
+
+ // Don't copy anything if the sizes mismatch. This can happen when the user
+ // changes modes.
+ if (saved_buffer.canvas()->getBaseLayerSize() !=
+ modeset_buffer.canvas()->getBaseLayerSize()) {
+ VLOG(2) << "Previous buffer has a different size than modeset buffer";
+ return;
+ }
+
+ skia::RefPtr<SkImage> image = saved_buffer.image();
+ SkPaint paint;
+ // Copy the source buffer. Do not perform any blending.
+ paint.setXfermodeMode(SkXfermode::kSrc_Mode);
+ modeset_buffer.canvas()->drawImage(image.get(), 0, 0, &paint);
+}
+
+} // namespace
+
+ScreenManager::ScreenManager(ScanoutBufferGenerator* buffer_generator)
+ : buffer_generator_(buffer_generator) {
+}
+
+ScreenManager::~ScreenManager() {
+ DCHECK(window_map_.empty());
+}
+
+void ScreenManager::AddDisplayController(const scoped_refptr<DrmDevice>& drm,
+ uint32_t crtc,
+ uint32_t connector) {
+ HardwareDisplayControllers::iterator it = FindDisplayController(drm, crtc);
+ // TODO(dnicoara): Turn this into a DCHECK when async display configuration is
+ // properly supported. (When there can't be a race between forcing initial
+ // display configuration in ScreenManager and NativeDisplayDelegate creating
+ // the display controllers.)
+ if (it != controllers_.end()) {
+ LOG(WARNING) << "Display controller (crtc=" << crtc << ") already present.";
+ return;
+ }
+
+ controllers_.push_back(new HardwareDisplayController(
+ scoped_ptr<CrtcController>(new CrtcController(drm, crtc, connector)),
+ gfx::Point()));
+}
+
+void ScreenManager::RemoveDisplayController(const scoped_refptr<DrmDevice>& drm,
+ uint32_t crtc) {
+ HardwareDisplayControllers::iterator it = FindDisplayController(drm, crtc);
+ if (it != controllers_.end()) {
+ bool is_mirrored = (*it)->IsMirrored();
+ (*it)->RemoveCrtc(drm, crtc);
+ if (!is_mirrored) {
+ controllers_.erase(it);
+ UpdateControllerToWindowMapping();
+ }
+ }
+}
+
+bool ScreenManager::ConfigureDisplayController(
+ const scoped_refptr<DrmDevice>& drm,
+ uint32_t crtc,
+ uint32_t connector,
+ const gfx::Point& origin,
+ const drmModeModeInfo& mode) {
+ bool status =
+ ActualConfigureDisplayController(drm, crtc, connector, origin, mode);
+ if (status)
+ UpdateControllerToWindowMapping();
+
+ return status;
+}
+
+bool ScreenManager::ActualConfigureDisplayController(
+ const scoped_refptr<DrmDevice>& drm,
+ uint32_t crtc,
+ uint32_t connector,
+ const gfx::Point& origin,
+ const drmModeModeInfo& mode) {
+ gfx::Rect modeset_bounds(origin.x(), origin.y(), mode.hdisplay,
+ mode.vdisplay);
+ HardwareDisplayControllers::iterator it = FindDisplayController(drm, crtc);
+ DCHECK(controllers_.end() != it) << "Display controller (crtc=" << crtc
+ << ") doesn't exist.";
+
+ HardwareDisplayController* controller = *it;
+ // If nothing changed just enable the controller. Note, we perform an exact
+ // comparison on the mode since the refresh rate may have changed.
+ if (SameMode(mode, controller->get_mode()) &&
+ origin == controller->origin()) {
+ if (controller->IsDisabled()) {
+ HardwareDisplayControllers::iterator mirror =
+ FindActiveDisplayControllerByLocation(modeset_bounds);
+ // If there is an active controller at the same location then start mirror
+ // mode.
+ if (mirror != controllers_.end())
+ return HandleMirrorMode(it, mirror, drm, crtc, connector);
+ }
+
+ // Just re-enable the controller to re-use the current state.
+ return EnableController(controller, controller->origin(),
+ controller->get_mode());
+ }
+
+ // Either the mode or the location of the display changed, so exit mirror
+ // mode and configure the display independently. If the caller still wants
+ // mirror mode, subsequent calls configuring the other controllers will
+ // restore mirror mode.
+ if (controller->IsMirrored()) {
+ controller = new HardwareDisplayController(
+ controller->RemoveCrtc(drm, crtc), controller->origin());
+ controllers_.push_back(controller);
+ it = controllers_.end() - 1;
+ }
+
+ HardwareDisplayControllers::iterator mirror =
+ FindActiveDisplayControllerByLocation(modeset_bounds);
+ // Handle mirror mode.
+ if (mirror != controllers_.end() && it != mirror)
+ return HandleMirrorMode(it, mirror, drm, crtc, connector);
+
+ return EnableController(controller, origin, mode);
+}
+
+bool ScreenManager::DisableDisplayController(
+ const scoped_refptr<DrmDevice>& drm,
+ uint32_t crtc) {
+ HardwareDisplayControllers::iterator it = FindDisplayController(drm, crtc);
+ if (it != controllers_.end()) {
+ HardwareDisplayController* controller = *it;
+ if (controller->IsMirrored()) {
+ controller = new HardwareDisplayController(
+ controller->RemoveCrtc(drm, crtc), controller->origin());
+ controllers_.push_back(controller);
+ }
+
+ controller->Disable();
+ UpdateControllerToWindowMapping();
+ return true;
+ }
+
+ LOG(ERROR) << "Failed to find display controller crtc=" << crtc;
+ return false;
+}
+
+HardwareDisplayController* ScreenManager::GetDisplayController(
+ const gfx::Rect& bounds) {
+ HardwareDisplayControllers::iterator it =
+ FindActiveDisplayControllerByLocation(bounds);
+ if (it != controllers_.end())
+ return *it;
+
+ return nullptr;
+}
+
+void ScreenManager::AddWindow(gfx::AcceleratedWidget widget,
+ scoped_ptr<DrmWindow> window) {
+ std::pair<WidgetToWindowMap::iterator, bool> result =
+ window_map_.add(widget, window.Pass());
+ DCHECK(result.second) << "Window already added.";
+ UpdateControllerToWindowMapping();
+}
+
+scoped_ptr<DrmWindow> ScreenManager::RemoveWindow(
+ gfx::AcceleratedWidget widget) {
+ scoped_ptr<DrmWindow> window = window_map_.take_and_erase(widget);
+ DCHECK(window) << "Attempting to remove non-existing window for " << widget;
+ UpdateControllerToWindowMapping();
+ return window.Pass();
+}
+
+DrmWindow* ScreenManager::GetWindow(gfx::AcceleratedWidget widget) {
+ WidgetToWindowMap::iterator it = window_map_.find(widget);
+ if (it != window_map_.end())
+ return it->second;
+
+ NOTREACHED() << "Attempting to get non-existing window for " << widget;
+ return nullptr;
+}
+
+ScreenManager::HardwareDisplayControllers::iterator
+ScreenManager::FindDisplayController(const scoped_refptr<DrmDevice>& drm,
+ uint32_t crtc) {
+ for (HardwareDisplayControllers::iterator it = controllers_.begin();
+ it != controllers_.end(); ++it) {
+ if ((*it)->HasCrtc(drm, crtc))
+ return it;
+ }
+
+ return controllers_.end();
+}
+
+ScreenManager::HardwareDisplayControllers::iterator
+ScreenManager::FindActiveDisplayControllerByLocation(const gfx::Rect& bounds) {
+ for (HardwareDisplayControllers::iterator it = controllers_.begin();
+ it != controllers_.end(); ++it) {
+ gfx::Rect controller_bounds((*it)->origin(), (*it)->GetModeSize());
+ if (controller_bounds == bounds && !(*it)->IsDisabled())
+ return it;
+ }
+
+ return controllers_.end();
+}
+
+bool ScreenManager::HandleMirrorMode(
+ HardwareDisplayControllers::iterator original,
+ HardwareDisplayControllers::iterator mirror,
+ const scoped_refptr<DrmDevice>& drm,
+ uint32_t crtc,
+ uint32_t connector) {
+ (*mirror)->AddCrtc((*original)->RemoveCrtc(drm, crtc));
+ if (EnableController(*mirror, (*mirror)->origin(), (*mirror)->get_mode())) {
+ controllers_.erase(original);
+ return true;
+ }
+
+ LOG(ERROR) << "Failed to switch to mirror mode";
+
+ // When things go wrong revert back to the previous configuration since
+ // it is expected that the configuration would not have changed if
+ // things fail.
+ (*original)->AddCrtc((*mirror)->RemoveCrtc(drm, crtc));
+ EnableController(*original, (*original)->origin(), (*original)->get_mode());
+ return false;
+}
+
+void ScreenManager::UpdateControllerToWindowMapping() {
+ std::map<DrmWindow*, HardwareDisplayController*> window_to_controller_map;
+ // First create a unique mapping between a window and a controller. Note, a
+ // controller may be associated with at most 1 window.
+ for (HardwareDisplayController* controller : controllers_) {
+ if (controller->IsDisabled())
+ continue;
+
+ DrmWindow* window = FindWindowAt(
+ gfx::Rect(controller->origin(), controller->GetModeSize()));
+ if (!window)
+ continue;
+
+ window_to_controller_map[window] = controller;
+ }
+
+ // Apply the new mapping to all windows.
+ for (auto pair : window_map_) {
+ auto it = window_to_controller_map.find(pair.second);
+ if (it != window_to_controller_map.end())
+ pair.second->SetController(it->second);
+ else
+ pair.second->SetController(nullptr);
+ }
+}
+
+bool ScreenManager::EnableController(HardwareDisplayController* controller,
+ const gfx::Point& origin,
+ const drmModeModeInfo& mode) {
+ DCHECK(!controller->crtc_controllers().empty());
+ gfx::Rect rect(origin, gfx::Size(mode.hdisplay, mode.vdisplay));
+ controller->set_origin(origin);
+
+ DrmWindow* window = FindWindowAt(rect);
+ if (window) {
+ const OverlayPlane* primary = window->GetLastModesetBuffer();
+ if (primary) {
+ if (!controller->Modeset(*primary, mode)) {
+ LOG(ERROR) << "Failed to modeset controller";
+ return false;
+ }
+
+ return true;
+ }
+ }
+
+ scoped_refptr<DrmDevice> drm = controller->GetAllocationDrmDevice();
+ scoped_refptr<ScanoutBuffer> buffer =
+ buffer_generator_->Create(drm, rect.size());
+ if (!buffer) {
+ LOG(ERROR) << "Failed to create scanout buffer";
+ return false;
+ }
+
+ FillModesetBuffer(drm, controller, buffer.get());
+ if (!controller->Modeset(OverlayPlane(buffer), mode)) {
+ LOG(ERROR) << "Failed to modeset controller";
+ return false;
+ }
+
+ return true;
+}
+
+DrmWindow* ScreenManager::FindWindowAt(const gfx::Rect& bounds) const {
+ for (auto pair : window_map_) {
+ if (pair.second->bounds() == bounds)
+ return pair.second;
+ }
+
+ return nullptr;
+}
+
+} // namespace ui
« no previous file with comments | « ui/ozone/platform/drm/gpu/screen_manager.h ('k') | ui/ozone/platform/drm/gpu/screen_manager_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698