1// Copyright (c) 2012 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/gl/gl_surface.h"
6
7#include <algorithm>
8#include <vector>
9
10#include "base/command_line.h"
11#include "base/debug/trace_event.h"
12#include "base/lazy_instance.h"
13#include "base/logging.h"
14#include "base/threading/thread_local.h"
15#include "ui/gl/gl_context.h"
16#include "ui/gl/gl_implementation.h"
17#include "ui/gl/gl_switches.h"
18
19#if defined(USE_X11)
20#include <X11/Xlib.h>
21#endif
22
23namespace gfx {
24
25namespace {
26base::LazyInstance<base::ThreadLocalPointer<GLSurface> >::Leaky
27    current_surface_ = LAZY_INSTANCE_INITIALIZER;
28}  // namespace
29
30// static
31bool GLSurface::InitializeOneOff() {
32  DCHECK_EQ(kGLImplementationNone, GetGLImplementation());
33
34  TRACE_EVENT0("gpu", "GLSurface::InitializeOneOff");
35
36  std::vector<GLImplementation> allowed_impls;
37  GetAllowedGLImplementations(&allowed_impls);
38  DCHECK(!allowed_impls.empty());
39
40  CommandLine* cmd = CommandLine::ForCurrentProcess();
41
42  // The default implementation is always the first one in list.
43  GLImplementation impl = allowed_impls[0];
44  bool fallback_to_osmesa = false;
45  if (cmd->HasSwitch(switches::kOverrideUseGLWithOSMesaForTests)) {
46    impl = kGLImplementationOSMesaGL;
47  } else if (cmd->HasSwitch(switches::kUseGL)) {
48    std::string requested_implementation_name =
49        cmd->GetSwitchValueASCII(switches::kUseGL);
50    if (requested_implementation_name == "any") {
51      fallback_to_osmesa = true;
52    } else if (requested_implementation_name == "swiftshader") {
53      impl = kGLImplementationEGLGLES2;
54    } else {
55      impl = GetNamedGLImplementation(requested_implementation_name);
56      if (std::find(allowed_impls.begin(),
57                    allowed_impls.end(),
58                    impl) == allowed_impls.end()) {
59        LOG(ERROR) << "Requested GL implementation is not available.";
60        return false;
61      }
62    }
63  }
64
65  bool gpu_service_logging = cmd->HasSwitch(switches::kEnableGPUServiceLogging);
66  bool disable_gl_drawing = cmd->HasSwitch(switches::kDisableGLDrawingForTests);
67
68  return InitializeOneOffImplementation(
69      impl, fallback_to_osmesa, gpu_service_logging, disable_gl_drawing);
70}
71
72// static
73bool GLSurface::InitializeOneOffImplementation(GLImplementation impl,
74                                               bool fallback_to_osmesa,
75                                               bool gpu_service_logging,
76                                               bool disable_gl_drawing) {
77  bool initialized =
78      InitializeStaticGLBindings(impl) && InitializeOneOffInternal();
79  if (!initialized && fallback_to_osmesa) {
80    ClearGLBindings();
81    initialized = InitializeStaticGLBindings(kGLImplementationOSMesaGL) &&
82                  InitializeOneOffInternal();
83  }
84  if (!initialized)
85    ClearGLBindings();
86
87  if (initialized) {
88    DVLOG(1) << "Using "
89             << GetGLImplementationName(GetGLImplementation())
90             << " GL implementation.";
91    if (gpu_service_logging)
92      InitializeDebugGLBindings();
93    if (disable_gl_drawing)
94      InitializeNullDrawGLBindings();
95  }
96  return initialized;
97}
98
99// static
100void GLSurface::InitializeOneOffForTests() {
101  DCHECK_EQ(kGLImplementationNone, GetGLImplementation());
102
103#if defined(USE_X11)
104  XInitThreads();
105#endif
106
107  bool use_osmesa = true;
108
109  // We usually use OSMesa as this works on all bots. The command line can
110  // override this behaviour to use hardware GL.
111  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kUseGpuInTests))
112    use_osmesa = false;
113
114#if defined(OS_ANDROID)
115  // On Android we always use hardware GL.
116  use_osmesa = false;
117#endif
118
119  std::vector<GLImplementation> allowed_impls;
120  GetAllowedGLImplementations(&allowed_impls);
121  DCHECK(!allowed_impls.empty());
122
123  GLImplementation impl = allowed_impls[0];
124  if (use_osmesa)
125    impl = kGLImplementationOSMesaGL;
126
127  DCHECK(!CommandLine::ForCurrentProcess()->HasSwitch(switches::kUseGL))
128      << "kUseGL has not effect in tests";
129
130  bool fallback_to_osmesa = false;
131  bool gpu_service_logging = false;
132  bool disable_gl_drawing = true;
133
134  CHECK(InitializeOneOffImplementation(
135      impl, fallback_to_osmesa, gpu_service_logging, disable_gl_drawing));
136}
137
138// static
139void GLSurface::InitializeOneOffWithMockBindingsForTests() {
140  DCHECK(!CommandLine::ForCurrentProcess()->HasSwitch(switches::kUseGL))
141      << "kUseGL has not effect in tests";
142
143  // This method may be called multiple times in the same process to set up
144  // mock bindings in different ways.
145  ClearGLBindings();
146
147  bool fallback_to_osmesa = false;
148  bool gpu_service_logging = false;
149  bool disable_gl_drawing = false;
150
151  CHECK(InitializeOneOffImplementation(kGLImplementationMockGL,
152                                       fallback_to_osmesa,
153                                       gpu_service_logging,
154                                       disable_gl_drawing));
155}
156
157// static
158void GLSurface::InitializeDynamicMockBindingsForTests(GLContext* context) {
159  CHECK(InitializeDynamicGLBindings(kGLImplementationMockGL, context));
160}
161
162GLSurface::GLSurface() {}
163
164bool GLSurface::Initialize() {
165  return true;
166}
167
168bool GLSurface::Resize(const gfx::Size& size) {
169  NOTIMPLEMENTED();
170  return false;
171}
172
173bool GLSurface::Recreate() {
174  NOTIMPLEMENTED();
175  return false;
176}
177
178bool GLSurface::DeferDraws() {
179  return false;
180}
181
182bool GLSurface::SupportsPostSubBuffer() {
183  return false;
184}
185
186unsigned int GLSurface::GetBackingFrameBufferObject() {
187  return 0;
188}
189
190bool GLSurface::PostSubBuffer(int x, int y, int width, int height) {
191  return false;
192}
193
194bool GLSurface::OnMakeCurrent(GLContext* context) {
195  return true;
196}
197
198bool GLSurface::SetBackbufferAllocation(bool allocated) {
199  return true;
200}
201
202void GLSurface::SetFrontbufferAllocation(bool allocated) {
203}
204
205void* GLSurface::GetShareHandle() {
206  NOTIMPLEMENTED();
207  return NULL;
208}
209
210void* GLSurface::GetDisplay() {
211  NOTIMPLEMENTED();
212  return NULL;
213}
214
215void* GLSurface::GetConfig() {
216  NOTIMPLEMENTED();
217  return NULL;
218}
219
220unsigned GLSurface::GetFormat() {
221  NOTIMPLEMENTED();
222  return 0;
223}
224
225VSyncProvider* GLSurface::GetVSyncProvider() {
226  return NULL;
227}
228
229bool GLSurface::ScheduleOverlayPlane(int z_order,
230                                     OverlayTransform transform,
231                                     GLImage* image,
232                                     const Rect& bounds_rect,
233                                     const RectF& crop_rect) {
234  NOTIMPLEMENTED();
235  return false;
236}
237
238bool GLSurface::IsSurfaceless() const {
239  return false;
240}
241
242GLSurface* GLSurface::GetCurrent() {
243  return current_surface_.Pointer()->Get();
244}
245
246GLSurface::~GLSurface() {
247  if (GetCurrent() == this)
248    SetCurrent(NULL);
249}
250
251void GLSurface::SetCurrent(GLSurface* surface) {
252  current_surface_.Pointer()->Set(surface);
253}
254
255bool GLSurface::ExtensionsContain(const char* c_extensions, const char* name) {
256  DCHECK(name);
257  if (!c_extensions)
258    return false;
259  std::string extensions(c_extensions);
260  extensions += " ";
261
262  std::string delimited_name(name);
263  delimited_name += " ";
264
265  return extensions.find(delimited_name) != std::string::npos;
266}
267
268GLSurfaceAdapter::GLSurfaceAdapter(GLSurface* surface) : surface_(surface) {}
269
270bool GLSurfaceAdapter::Initialize() {
271  return surface_->Initialize();
272}
273
274void GLSurfaceAdapter::Destroy() {
275  surface_->Destroy();
276}
277
278bool GLSurfaceAdapter::Resize(const gfx::Size& size) {
279  return surface_->Resize(size);
280}
281
282bool GLSurfaceAdapter::Recreate() {
283  return surface_->Recreate();
284}
285
286bool GLSurfaceAdapter::DeferDraws() {
287  return surface_->DeferDraws();
288}
289
290bool GLSurfaceAdapter::IsOffscreen() {
291  return surface_->IsOffscreen();
292}
293
294bool GLSurfaceAdapter::SwapBuffers() {
295  return surface_->SwapBuffers();
296}
297
298bool GLSurfaceAdapter::PostSubBuffer(int x, int y, int width, int height) {
299  return surface_->PostSubBuffer(x, y, width, height);
300}
301
302bool GLSurfaceAdapter::SupportsPostSubBuffer() {
303  return surface_->SupportsPostSubBuffer();
304}
305
306gfx::Size GLSurfaceAdapter::GetSize() {
307  return surface_->GetSize();
308}
309
310void* GLSurfaceAdapter::GetHandle() {
311  return surface_->GetHandle();
312}
313
314unsigned int GLSurfaceAdapter::GetBackingFrameBufferObject() {
315  return surface_->GetBackingFrameBufferObject();
316}
317
318bool GLSurfaceAdapter::OnMakeCurrent(GLContext* context) {
319  return surface_->OnMakeCurrent(context);
320}
321
322bool GLSurfaceAdapter::SetBackbufferAllocation(bool allocated) {
323  return surface_->SetBackbufferAllocation(allocated);
324}
325
326void GLSurfaceAdapter::SetFrontbufferAllocation(bool allocated) {
327  surface_->SetFrontbufferAllocation(allocated);
328}
329
330void* GLSurfaceAdapter::GetShareHandle() {
331  return surface_->GetShareHandle();
332}
333
334void* GLSurfaceAdapter::GetDisplay() {
335  return surface_->GetDisplay();
336}
337
338void* GLSurfaceAdapter::GetConfig() {
339  return surface_->GetConfig();
340}
341
342unsigned GLSurfaceAdapter::GetFormat() {
343  return surface_->GetFormat();
344}
345
346VSyncProvider* GLSurfaceAdapter::GetVSyncProvider() {
347  return surface_->GetVSyncProvider();
348}
349
350bool GLSurfaceAdapter::ScheduleOverlayPlane(int z_order,
351                                            OverlayTransform transform,
352                                            GLImage* image,
353                                            const Rect& bounds_rect,
354                                            const RectF& crop_rect) {
355  return surface_->ScheduleOverlayPlane(
356      z_order, transform, image, bounds_rect, crop_rect);
357}
358
359bool GLSurfaceAdapter::IsSurfaceless() const {
360  return surface_->IsSurfaceless();
361}
362
363GLSurfaceAdapter::~GLSurfaceAdapter() {}
364
365}  // namespace gfx
366