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/gbm_surface_factory.h"
6
7#include <gbm.h>
8
9#include "base/command_line.h"
10#include "base/files/file_path.h"
11#include "third_party/khronos/EGL/egl.h"
12#include "ui/ozone/platform/dri/dri_window_delegate_impl.h"
13#include "ui/ozone/platform/dri/dri_window_delegate_manager.h"
14#include "ui/ozone/platform/dri/gbm_buffer.h"
15#include "ui/ozone/platform/dri/gbm_surface.h"
16#include "ui/ozone/platform/dri/gbm_surfaceless.h"
17#include "ui/ozone/platform/dri/screen_manager.h"
18#include "ui/ozone/public/native_pixmap.h"
19#include "ui/ozone/public/overlay_candidates_ozone.h"
20#include "ui/ozone/public/ozone_switches.h"
21#include "ui/ozone/public/surface_ozone_egl.h"
22
23namespace ui {
24namespace {
25
26class SingleOverlay : public OverlayCandidatesOzone {
27 public:
28  SingleOverlay() {}
29  virtual ~SingleOverlay() {}
30
31  virtual void CheckOverlaySupport(
32      OverlaySurfaceCandidateList* candidates) OVERRIDE {
33    if (candidates->size() == 2) {
34      OverlayCandidatesOzone::OverlaySurfaceCandidate* first =
35          &(*candidates)[0];
36      OverlayCandidatesOzone::OverlaySurfaceCandidate* second =
37          &(*candidates)[1];
38      OverlayCandidatesOzone::OverlaySurfaceCandidate* overlay;
39      if (first->plane_z_order == 0) {
40        overlay = second;
41      } else if (second->plane_z_order == 0) {
42        overlay = first;
43      } else {
44        NOTREACHED();
45        return;
46      }
47      if (overlay->plane_z_order > 0 &&
48          IsTransformSupported(overlay->transform)) {
49        overlay->overlay_handled = true;
50      }
51    }
52  }
53
54 private:
55  bool IsTransformSupported(gfx::OverlayTransform transform) {
56    switch (transform) {
57      case gfx::OVERLAY_TRANSFORM_NONE:
58        return true;
59      default:
60        return false;
61    }
62  }
63
64  DISALLOW_COPY_AND_ASSIGN(SingleOverlay);
65};
66
67}  // namespace
68
69GbmSurfaceFactory::GbmSurfaceFactory(bool allow_surfaceless)
70    : DriSurfaceFactory(NULL, NULL, NULL),
71      device_(NULL),
72      allow_surfaceless_(allow_surfaceless) {
73}
74
75GbmSurfaceFactory::~GbmSurfaceFactory() {}
76
77void GbmSurfaceFactory::InitializeGpu(
78    DriWrapper* dri,
79    gbm_device* device,
80    ScreenManager* screen_manager,
81    DriWindowDelegateManager* window_manager) {
82  drm_ = dri;
83  device_ = device;
84  screen_manager_ = screen_manager;
85  window_manager_ = window_manager;
86}
87
88intptr_t GbmSurfaceFactory::GetNativeDisplay() {
89  DCHECK(state_ == INITIALIZED);
90  return reinterpret_cast<intptr_t>(device_);
91}
92
93const int32* GbmSurfaceFactory::GetEGLSurfaceProperties(
94    const int32* desired_list) {
95  static const int32 kConfigAttribs[] = {
96    EGL_BUFFER_SIZE, 32,
97    EGL_ALPHA_SIZE, 8,
98    EGL_BLUE_SIZE, 8,
99    EGL_GREEN_SIZE, 8,
100    EGL_RED_SIZE, 8,
101    EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
102    EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
103    EGL_NONE
104  };
105
106  return kConfigAttribs;
107}
108
109bool GbmSurfaceFactory::LoadEGLGLES2Bindings(
110      AddGLLibraryCallback add_gl_library,
111      SetGLGetProcAddressProcCallback set_gl_get_proc_address) {
112  base::NativeLibraryLoadError error;
113  base::NativeLibrary gles_library = base::LoadNativeLibrary(
114      base::FilePath("libGLESv2.so.2"),
115      &error);
116  if (!gles_library) {
117    LOG(WARNING) << "Failed to load GLES library: " << error.ToString();
118    return false;
119  }
120
121  base::NativeLibrary egl_library = base::LoadNativeLibrary(
122      base::FilePath("libEGL.so.1"),
123      &error);
124  if (!egl_library) {
125    LOG(WARNING) << "Failed to load EGL library: " << error.ToString();
126    base::UnloadNativeLibrary(gles_library);
127    return false;
128  }
129
130  GLGetProcAddressProc get_proc_address =
131      reinterpret_cast<GLGetProcAddressProc>(
132          base::GetFunctionPointerFromNativeLibrary(
133              egl_library, "eglGetProcAddress"));
134  if (!get_proc_address) {
135    LOG(ERROR) << "eglGetProcAddress not found.";
136    base::UnloadNativeLibrary(egl_library);
137    base::UnloadNativeLibrary(gles_library);
138    return false;
139  }
140
141  set_gl_get_proc_address.Run(get_proc_address);
142  add_gl_library.Run(egl_library);
143  add_gl_library.Run(gles_library);
144
145  return true;
146}
147
148scoped_ptr<SurfaceOzoneEGL> GbmSurfaceFactory::CreateEGLSurfaceForWidget(
149    gfx::AcceleratedWidget widget) {
150  DCHECK(state_ == INITIALIZED);
151
152  DriWindowDelegate* delegate = GetOrCreateWindowDelegate(widget);
153
154  scoped_ptr<GbmSurface> surface(new GbmSurface(delegate, device_, drm_));
155  if (!surface->Initialize())
156    return scoped_ptr<SurfaceOzoneEGL>();
157
158  return surface.PassAs<SurfaceOzoneEGL>();
159}
160
161scoped_ptr<SurfaceOzoneEGL>
162GbmSurfaceFactory::CreateSurfacelessEGLSurfaceForWidget(
163    gfx::AcceleratedWidget widget) {
164  if (!allow_surfaceless_)
165    return scoped_ptr<SurfaceOzoneEGL>();
166
167  DriWindowDelegate* delegate = GetOrCreateWindowDelegate(widget);
168  return scoped_ptr<SurfaceOzoneEGL>(new GbmSurfaceless(delegate));
169}
170
171scoped_refptr<ui::NativePixmap> GbmSurfaceFactory::CreateNativePixmap(
172    gfx::Size size,
173    BufferFormat format) {
174  scoped_refptr<GbmBuffer> buffer = GbmBuffer::CreateBuffer(
175      drm_, device_, format, size, true);
176  if (!buffer.get())
177    return NULL;
178
179  return scoped_refptr<GbmPixmap>(new GbmPixmap(buffer));
180}
181
182OverlayCandidatesOzone* GbmSurfaceFactory::GetOverlayCandidates(
183    gfx::AcceleratedWidget w) {
184  if (CommandLine::ForCurrentProcess()->HasSwitch(
185          switches::kOzoneTestSingleOverlaySupport))
186    return new SingleOverlay();
187  return NULL;
188}
189
190bool GbmSurfaceFactory::ScheduleOverlayPlane(
191    gfx::AcceleratedWidget widget,
192    int plane_z_order,
193    gfx::OverlayTransform plane_transform,
194    scoped_refptr<NativePixmap> buffer,
195    const gfx::Rect& display_bounds,
196    const gfx::RectF& crop_rect) {
197  scoped_refptr<GbmPixmap> pixmap = static_cast<GbmPixmap*>(buffer.get());
198  if (!pixmap.get()) {
199    LOG(ERROR) << "ScheduleOverlayPlane passed NULL buffer.";
200    return false;
201  }
202  HardwareDisplayController* hdc =
203      window_manager_->GetWindowDelegate(widget)->GetController();
204  if (!hdc)
205    return true;
206
207  hdc->QueueOverlayPlane(OverlayPlane(pixmap->buffer(),
208                                      plane_z_order,
209                                      plane_transform,
210                                      display_bounds,
211                                      crop_rect));
212  return true;
213}
214
215bool GbmSurfaceFactory::CanShowPrimaryPlaneAsOverlay() {
216  return allow_surfaceless_;
217}
218
219DriWindowDelegate* GbmSurfaceFactory::GetOrCreateWindowDelegate(
220    gfx::AcceleratedWidget widget) {
221  if (!window_manager_->HasWindowDelegate(widget)) {
222    scoped_ptr<DriWindowDelegate> delegate(
223        new DriWindowDelegateImpl(widget, screen_manager_));
224    delegate->Initialize();
225    window_manager_->AddWindowDelegate(widget, delegate.Pass());
226  }
227
228  return window_manager_->GetWindowDelegate(widget);
229}
230
231}  // namespace ui
232