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/dri/screen_manager.h" 6 7#include <xf86drmMode.h> 8 9#include "ui/gfx/geometry/point.h" 10#include "ui/gfx/geometry/rect.h" 11#include "ui/gfx/geometry/size.h" 12#include "ui/ozone/platform/dri/crtc_state.h" 13#include "ui/ozone/platform/dri/dri_util.h" 14#include "ui/ozone/platform/dri/hardware_display_controller.h" 15#include "ui/ozone/platform/dri/scanout_buffer.h" 16 17namespace ui { 18 19ScreenManager::ScreenManager(DriWrapper* dri, 20 ScanoutBufferGenerator* buffer_generator) 21 : dri_(dri), buffer_generator_(buffer_generator) { 22} 23 24ScreenManager::~ScreenManager() { 25} 26 27void ScreenManager::AddDisplayController(uint32_t crtc, uint32_t connector) { 28 HardwareDisplayControllers::iterator it = FindDisplayController(crtc); 29 // TODO(dnicoara): Turn this into a DCHECK when async display configuration is 30 // properly supported. (When there can't be a race between forcing initial 31 // display configuration in ScreenManager and NativeDisplayDelegate creating 32 // the display controllers.) 33 if (it != controllers_.end()) { 34 LOG(WARNING) << "Display controller (crtc=" << crtc << ") already present."; 35 return; 36 } 37 38 controllers_.push_back(new HardwareDisplayController( 39 dri_, scoped_ptr<CrtcState>(new CrtcState(dri_, crtc, connector)))); 40} 41 42void ScreenManager::RemoveDisplayController(uint32_t crtc) { 43 HardwareDisplayControllers::iterator it = FindDisplayController(crtc); 44 if (it != controllers_.end()) { 45 bool is_mirrored = (*it)->IsMirrored(); 46 (*it)->RemoveCrtc(crtc); 47 if (!is_mirrored) 48 controllers_.erase(it); 49 } 50} 51 52bool ScreenManager::ConfigureDisplayController(uint32_t crtc, 53 uint32_t connector, 54 const gfx::Point& origin, 55 const drmModeModeInfo& mode) { 56 gfx::Rect modeset_bounds( 57 origin.x(), origin.y(), mode.hdisplay, mode.vdisplay); 58 HardwareDisplayControllers::iterator it = FindDisplayController(crtc); 59 DCHECK(controllers_.end() != it) << "Display controller (crtc=" << crtc 60 << ") doesn't exist."; 61 62 HardwareDisplayController* controller = *it; 63 controller = *it; 64 // If nothing changed just enable the controller. Note, we perform an exact 65 // comparison on the mode since the refresh rate may have changed. 66 if (SameMode(mode, controller->get_mode()) && 67 origin == controller->origin() && !controller->IsDisabled()) 68 return controller->Enable(); 69 70 // Either the mode or the location of the display changed, so exit mirror 71 // mode and configure the display independently. If the caller still wants 72 // mirror mode, subsequent calls configuring the other controllers will 73 // restore mirror mode. 74 if (controller->IsMirrored()) { 75 controller = 76 new HardwareDisplayController(dri_, controller->RemoveCrtc(crtc)); 77 controllers_.push_back(controller); 78 it = controllers_.end() - 1; 79 } 80 81 HardwareDisplayControllers::iterator mirror = 82 FindActiveDisplayControllerByLocation(modeset_bounds); 83 // Handle mirror mode. 84 if (mirror != controllers_.end() && it != mirror) 85 return HandleMirrorMode(it, mirror, crtc, connector); 86 87 return ModesetDisplayController(controller, origin, mode); 88} 89 90bool ScreenManager::DisableDisplayController(uint32_t crtc) { 91 HardwareDisplayControllers::iterator it = FindDisplayController(crtc); 92 if (it != controllers_.end()) { 93 if ((*it)->IsMirrored()) { 94 HardwareDisplayController* controller = 95 new HardwareDisplayController(dri_, (*it)->RemoveCrtc(crtc)); 96 controllers_.push_back(controller); 97 } 98 99 (*it)->Disable(); 100 return true; 101 } 102 103 LOG(ERROR) << "Failed to find display controller crtc=" << crtc; 104 return false; 105} 106 107base::WeakPtr<HardwareDisplayController> ScreenManager::GetDisplayController( 108 const gfx::Rect& bounds) { 109 // TODO(dnicoara): Remove hack once TestScreen uses a simple Ozone display 110 // configuration reader and ScreenManager is called from there to create the 111 // one display needed by the content_shell target. 112 if (controllers_.empty()) 113 ForceInitializationOfPrimaryDisplay(); 114 115 HardwareDisplayControllers::iterator it = 116 FindActiveDisplayControllerByLocation(bounds); 117 if (it != controllers_.end()) 118 return (*it)->AsWeakPtr(); 119 120 return base::WeakPtr<HardwareDisplayController>(); 121} 122 123ScreenManager::HardwareDisplayControllers::iterator 124ScreenManager::FindDisplayController(uint32_t crtc) { 125 for (HardwareDisplayControllers::iterator it = controllers_.begin(); 126 it != controllers_.end(); 127 ++it) { 128 if ((*it)->HasCrtc(crtc)) 129 return it; 130 } 131 132 return controllers_.end(); 133} 134 135ScreenManager::HardwareDisplayControllers::iterator 136ScreenManager::FindActiveDisplayControllerByLocation(const gfx::Rect& bounds) { 137 for (HardwareDisplayControllers::iterator it = controllers_.begin(); 138 it != controllers_.end(); 139 ++it) { 140 gfx::Rect controller_bounds((*it)->origin(), (*it)->GetModeSize()); 141 // We don't perform a strict check since content_shell will have windows 142 // smaller than the display size. 143 if (controller_bounds.Contains(bounds) && !(*it)->IsDisabled()) 144 return it; 145 } 146 147 return controllers_.end(); 148} 149 150void ScreenManager::ForceInitializationOfPrimaryDisplay() { 151 LOG(WARNING) << "Forcing initialization of primary display."; 152 ScopedVector<HardwareDisplayControllerInfo> displays = 153 GetAvailableDisplayControllerInfos(dri_->get_fd()); 154 155 DCHECK_NE(0u, displays.size()); 156 157 ScopedDrmPropertyPtr dpms( 158 dri_->GetProperty(displays[0]->connector(), "DPMS")); 159 if (dpms) 160 dri_->SetProperty(displays[0]->connector()->connector_id, 161 dpms->prop_id, 162 DRM_MODE_DPMS_ON); 163 164 AddDisplayController(displays[0]->crtc()->crtc_id, 165 displays[0]->connector()->connector_id); 166 ConfigureDisplayController(displays[0]->crtc()->crtc_id, 167 displays[0]->connector()->connector_id, 168 gfx::Point(), 169 displays[0]->connector()->modes[0]); 170} 171 172bool ScreenManager::ModesetDisplayController( 173 HardwareDisplayController* controller, 174 const gfx::Point& origin, 175 const drmModeModeInfo& mode) { 176 controller->set_origin(origin); 177 // Create a surface suitable for the current controller. 178 scoped_refptr<ScanoutBuffer> buffer = 179 buffer_generator_->Create(gfx::Size(mode.hdisplay, mode.vdisplay)); 180 181 if (!buffer.get()) { 182 LOG(ERROR) << "Failed to create scanout buffer"; 183 return false; 184 } 185 186 if (!controller->Modeset(OverlayPlane(buffer), mode)) { 187 LOG(ERROR) << "Failed to modeset controller"; 188 return false; 189 } 190 191 return true; 192} 193 194bool ScreenManager::HandleMirrorMode( 195 HardwareDisplayControllers::iterator original, 196 HardwareDisplayControllers::iterator mirror, 197 uint32_t crtc, 198 uint32_t connector) { 199 (*mirror)->AddCrtc((*original)->RemoveCrtc(crtc)); 200 if ((*mirror)->Enable()) { 201 controllers_.erase(original); 202 return true; 203 } 204 205 LOG(ERROR) << "Failed to switch to mirror mode"; 206 207 // When things go wrong revert back to the previous configuration since 208 // it is expected that the configuration would not have changed if 209 // things fail. 210 (*original)->AddCrtc((*mirror)->RemoveCrtc(crtc)); 211 (*original)->Enable(); 212 return false; 213} 214 215} // namespace ui 216