Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / ui / ozone / platform / dri / hardware_display_controller.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/hardware_display_controller.h"
6
7 #include <drm.h>
8 #include <errno.h>
9 #include <string.h>
10 #include <xf86drm.h>
11
12 #include "base/basictypes.h"
13 #include "base/debug/trace_event.h"
14 #include "base/logging.h"
15 #include "base/time/time.h"
16 #include "third_party/skia/include/core/SkCanvas.h"
17 #include "ui/gfx/geometry/point.h"
18 #include "ui/gfx/geometry/size.h"
19 #include "ui/ozone/platform/dri/crtc_state.h"
20 #include "ui/ozone/platform/dri/dri_buffer.h"
21 #include "ui/ozone/platform/dri/dri_wrapper.h"
22 #include "ui/ozone/public/native_pixmap.h"
23
24 namespace ui {
25
26 namespace {
27
28 // DRM callback on page flip events. This callback is triggered after the
29 // page flip has happened and the backbuffer is now the new frontbuffer
30 // The old frontbuffer is no longer used by the hardware and can be used for
31 // future draw operations.
32 //
33 // |device| will contain a reference to the |ScanoutSurface| object which
34 // the event belongs to.
35 //
36 // TODO(dnicoara) When we have a FD handler for the DRM calls in the message
37 // loop, we can move this function in the handler.
38 void HandlePageFlipEvent(int fd,
39                          unsigned int frame,
40                          unsigned int seconds,
41                          unsigned int useconds,
42                          void* controller) {
43   static_cast<HardwareDisplayController*>(controller)
44       ->OnPageFlipEvent(frame, seconds, useconds);
45 }
46
47 const OverlayPlane& GetPrimaryPlane(const OverlayPlaneList& overlays) {
48   for (size_t i = 0; i < overlays.size(); ++i) {
49     if (overlays[i].z_order == 0)
50       return overlays[i];
51   }
52
53   NOTREACHED();
54   return overlays[0];
55 }
56
57 }  // namespace
58
59 OverlayPlane::OverlayPlane(scoped_refptr<ScanoutBuffer> buffer)
60     : buffer(buffer),
61       z_order(0),
62       display_bounds(gfx::Point(), buffer->GetSize()),
63       crop_rect(0, 0, 1, 1),
64       overlay_plane(0) {}
65
66 OverlayPlane::OverlayPlane(scoped_refptr<ScanoutBuffer> buffer,
67                            int z_order,
68                            gfx::OverlayTransform plane_transform,
69                            const gfx::Rect& display_bounds,
70                            const gfx::RectF& crop_rect)
71     : buffer(buffer),
72       z_order(z_order),
73       plane_transform(plane_transform),
74       display_bounds(display_bounds),
75       crop_rect(crop_rect),
76       overlay_plane(0) {
77 }
78
79 OverlayPlane::~OverlayPlane() {}
80
81 HardwareDisplayController::HardwareDisplayController(
82     DriWrapper* drm,
83     scoped_ptr<CrtcState> state)
84     : drm_(drm),
85       is_disabled_(true),
86       time_of_last_flip_(0),
87       pending_page_flips_(0) {
88   crtc_states_.push_back(state.release());
89 }
90
91 HardwareDisplayController::~HardwareDisplayController() {
92   // Reset the cursor.
93   UnsetCursor();
94 }
95
96 bool HardwareDisplayController::Modeset(const OverlayPlane& primary,
97                                         drmModeModeInfo mode) {
98   TRACE_EVENT0("dri", "HDC::Modeset");
99   DCHECK(primary.buffer.get());
100   pending_page_flips_ = 0;
101   bool status = true;
102   for (size_t i = 0; i < crtc_states_.size(); ++i) {
103     status &= ModesetCrtc(primary.buffer, mode, crtc_states_[i]);
104     crtc_states_[i]->set_is_disabled(false);
105   }
106
107   // Since a subset of controllers may be actively using |primary|, just keep
108   // track of it.
109   current_planes_ = std::vector<OverlayPlane>(1, primary);
110   pending_planes_.clear();
111   is_disabled_ = false;
112   mode_ = mode;
113   return status;
114 }
115
116 bool HardwareDisplayController::Enable() {
117   TRACE_EVENT0("dri", "HDC::Enable");
118   DCHECK(!current_planes_.empty());
119   OverlayPlane primary = GetPrimaryPlane(current_planes_);
120   DCHECK(primary.buffer.get());
121   pending_page_flips_ = 0;
122   bool status = true;
123   for (size_t i = 0; i < crtc_states_.size(); ++i)
124     status &= ModesetCrtc(primary.buffer, mode_, crtc_states_[i]);
125
126   return status;
127 }
128
129 void HardwareDisplayController::Disable() {
130   TRACE_EVENT0("dri", "HDC::Disable");
131   pending_page_flips_ = 0;
132   for (size_t i = 0; i < crtc_states_.size(); ++i) {
133     drm_->DisableCrtc(crtc_states_[i]->crtc());
134     crtc_states_[i]->set_is_disabled(true);
135   }
136
137   is_disabled_ = true;
138 }
139
140 void HardwareDisplayController::QueueOverlayPlane(const OverlayPlane& plane) {
141   pending_planes_.push_back(plane);
142 }
143
144 bool HardwareDisplayController::SchedulePageFlip() {
145   DCHECK(!pending_planes_.empty());
146   DCHECK_EQ(0u, pending_page_flips_);
147
148   if (is_disabled_)
149     return true;
150
151   bool status = true;
152   for (size_t i = 0; i < crtc_states_.size(); ++i)
153     status &= SchedulePageFlipOnCrtc(pending_planes_, crtc_states_[i]);
154
155   return status;
156 }
157
158 void HardwareDisplayController::WaitForPageFlipEvent() {
159   TRACE_EVENT1("dri", "HDC::WaitForPageFlipEvent",
160                "pending_pageflips", pending_page_flips_);
161
162   bool has_pending_page_flips = pending_page_flips_ != 0;
163   drmEventContext drm_event;
164   drm_event.version = DRM_EVENT_CONTEXT_VERSION;
165   drm_event.page_flip_handler = HandlePageFlipEvent;
166   drm_event.vblank_handler = NULL;
167
168   // Wait for the page-flips to complete.
169   while (pending_page_flips_ > 0)
170     drm_->HandleEvent(drm_event);
171
172   // In case there are no pending pageflips do not replace the current planes
173   // since they are still being used.
174   if (has_pending_page_flips)
175     current_planes_.swap(pending_planes_);
176
177   pending_planes_.clear();
178 }
179
180 void HardwareDisplayController::OnPageFlipEvent(unsigned int frame,
181                                                 unsigned int seconds,
182                                                 unsigned int useconds) {
183   TRACE_EVENT0("dri", "HDC::OnPageFlipEvent");
184
185   --pending_page_flips_;
186   time_of_last_flip_ =
187       static_cast<uint64_t>(seconds) * base::Time::kMicrosecondsPerSecond +
188       useconds;
189 }
190
191 bool HardwareDisplayController::SetCursor(scoped_refptr<ScanoutBuffer> buffer) {
192   bool status = true;
193   cursor_buffer_ = buffer;
194
195   if (is_disabled_)
196     return true;
197
198   for (size_t i = 0; i < crtc_states_.size(); ++i) {
199     status &= drm_->SetCursor(
200         crtc_states_[i]->crtc(), buffer->GetHandle(), buffer->GetSize());
201   }
202
203   return status;
204 }
205
206 bool HardwareDisplayController::UnsetCursor() {
207   bool status = true;
208   cursor_buffer_ = NULL;
209   for (size_t i = 0; i < crtc_states_.size(); ++i)
210     status &= drm_->SetCursor(crtc_states_[i]->crtc(), 0, gfx::Size());
211
212   return status;
213 }
214
215 bool HardwareDisplayController::MoveCursor(const gfx::Point& location) {
216   if (is_disabled_)
217     return true;
218
219   bool status = true;
220   for (size_t i = 0; i < crtc_states_.size(); ++i)
221     status &= drm_->MoveCursor(crtc_states_[i]->crtc(), location);
222
223   return status;
224 }
225
226 void HardwareDisplayController::AddCrtc(
227     scoped_ptr<CrtcState> state) {
228   crtc_states_.push_back(state.release());
229 }
230
231 scoped_ptr<CrtcState> HardwareDisplayController::RemoveCrtc(uint32_t crtc) {
232   for (ScopedVector<CrtcState>::iterator it = crtc_states_.begin();
233        it != crtc_states_.end();
234        ++it) {
235     if ((*it)->crtc() == crtc) {
236       scoped_ptr<CrtcState> controller(*it);
237       crtc_states_.weak_erase(it);
238       return controller.Pass();
239     }
240   }
241
242   return scoped_ptr<CrtcState>();
243 }
244
245 bool HardwareDisplayController::HasCrtc(uint32_t crtc) const {
246   for (size_t i = 0; i < crtc_states_.size(); ++i)
247     if (crtc_states_[i]->crtc() == crtc)
248       return true;
249
250   return false;
251 }
252
253 bool HardwareDisplayController::IsMirrored() const {
254   return crtc_states_.size() > 1;
255 }
256
257 bool HardwareDisplayController::IsDisabled() const {
258   return is_disabled_;
259 }
260
261 gfx::Size HardwareDisplayController::GetModeSize() const {
262   return gfx::Size(mode_.hdisplay, mode_.vdisplay);
263 }
264
265 bool HardwareDisplayController::ModesetCrtc(
266     const scoped_refptr<ScanoutBuffer>& buffer,
267     drmModeModeInfo mode,
268     CrtcState* state) {
269   if (!drm_->SetCrtc(state->crtc(),
270                      buffer->GetFramebufferId(),
271                      std::vector<uint32_t>(1, state->connector()),
272                      &mode)) {
273     LOG(ERROR) << "Failed to modeset: error='" << strerror(errno)
274                << "' crtc=" << state->crtc()
275                << " connector=" << state->connector()
276                << " framebuffer_id=" << buffer->GetFramebufferId()
277                << " mode=" << mode.hdisplay << "x" << mode.vdisplay << "@"
278                << mode.vrefresh;
279     return false;
280   }
281
282   return true;
283 }
284
285 bool HardwareDisplayController::SchedulePageFlipOnCrtc(
286     const OverlayPlaneList& overlays,
287     CrtcState* state) {
288   const OverlayPlane& primary = GetPrimaryPlane(overlays);
289   DCHECK(primary.buffer.get());
290
291   if (primary.buffer->GetSize() != gfx::Size(mode_.hdisplay, mode_.vdisplay)) {
292     LOG(WARNING) << "Trying to pageflip a buffer with the wrong size. Expected "
293                  << mode_.hdisplay << "x" << mode_.vdisplay
294                  << " got " << primary.buffer->GetSize().ToString() << " for"
295                  << " crtc=" << state->crtc()
296                  << " connector=" << state->connector();
297     return true;
298   }
299
300   if (!drm_->PageFlip(state->crtc(),
301                       primary.buffer->GetFramebufferId(),
302                       this)) {
303     LOG(ERROR) << "Cannot page flip: error='" << strerror(errno) << "'"
304                << " crtc=" << state->crtc()
305                << " framebuffer=" << primary.buffer->GetFramebufferId()
306                << " size=" << primary.buffer->GetSize().ToString();
307     return false;
308   }
309
310   ++pending_page_flips_;
311
312   for (size_t i = 0; i < overlays.size(); i++) {
313     const OverlayPlane& plane = overlays[i];
314     if (!plane.overlay_plane)
315       continue;
316
317     const gfx::Size& size = plane.buffer->GetSize();
318     gfx::RectF crop_rect = plane.crop_rect;
319     crop_rect.Scale(size.width(), size.height());
320     if (!drm_->PageFlipOverlay(state->crtc(),
321                                plane.buffer->GetFramebufferId(),
322                                plane.display_bounds,
323                                crop_rect,
324                                plane.overlay_plane)) {
325       LOG(ERROR) << "Cannot display on overlay: " << strerror(errno);
326       return false;
327     }
328   }
329
330   return true;
331 }
332
333 }  // namespace ui