6330387168ec28ab01f649b5d077495e7093f296
[platform/framework/web/crosswalk.git] / src / ui / ozone / platform / dri / screen_manager.cc
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
17 namespace ui {
18
19 ScreenManager::ScreenManager(DriWrapper* dri,
20                              ScanoutBufferGenerator* buffer_generator)
21     : dri_(dri), buffer_generator_(buffer_generator) {
22 }
23
24 ScreenManager::~ScreenManager() {
25 }
26
27 void 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
42 void 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
52 bool 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
90 bool 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
107 base::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
123 ScreenManager::HardwareDisplayControllers::iterator
124 ScreenManager::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
135 ScreenManager::HardwareDisplayControllers::iterator
136 ScreenManager::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
150 void 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
172 bool 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
194 bool 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