| // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 
 | // Use of this source code is governed by a BSD-style license that can be | 
 | // found in the LICENSE file. | 
 |  | 
 | #include "ui/gl/gl_surface.h" | 
 |  | 
 | #include <algorithm> | 
 | #include <vector> | 
 |  | 
 | #include "base/command_line.h" | 
 | #include "base/debug/trace_event.h" | 
 | #include "base/lazy_instance.h" | 
 | #include "base/logging.h" | 
 | #include "base/threading/thread_local.h" | 
 | #include "ui/gl/gl_context.h" | 
 | #include "ui/gl/gl_implementation.h" | 
 | #include "ui/gl/gl_switches.h" | 
 |  | 
 | #if defined(USE_X11) | 
 | #include <X11/Xlib.h> | 
 | #endif | 
 |  | 
 | namespace gfx { | 
 |  | 
 | namespace { | 
 | base::LazyInstance<base::ThreadLocalPointer<GLSurface> >::Leaky | 
 |     current_surface_ = LAZY_INSTANCE_INITIALIZER; | 
 | }  // namespace | 
 |  | 
 | // static | 
 | bool GLSurface::InitializeOneOff(GLImplementation impl) { | 
 |   DCHECK_EQ(kGLImplementationNone, GetGLImplementation()); | 
 |  | 
 |   TRACE_EVENT0("gpu", "GLSurface::InitializeOneOff"); | 
 |  | 
 |   std::vector<GLImplementation> allowed_impls; | 
 |   GetAllowedGLImplementations(&allowed_impls); | 
 |   DCHECK(!allowed_impls.empty()); | 
 |  | 
 |   CommandLine* cmd = CommandLine::ForCurrentProcess(); | 
 |  | 
 |   // The default implementation is always the first one in list. | 
 |   if (impl == kGLImplementationNone) | 
 |     impl = allowed_impls[0]; | 
 |   bool fallback_to_osmesa = false; | 
 |   if (cmd->HasSwitch(switches::kOverrideUseGLWithOSMesaForTests)) { | 
 |     impl = kGLImplementationOSMesaGL; | 
 |   } else if (cmd->HasSwitch(switches::kUseGL)) { | 
 |     std::string requested_implementation_name = | 
 |         cmd->GetSwitchValueASCII(switches::kUseGL); | 
 |     if (requested_implementation_name == "any") { | 
 |       fallback_to_osmesa = true; | 
 |     } else if (requested_implementation_name == "swiftshader") { | 
 |       impl = kGLImplementationEGLGLES2; | 
 |     } else { | 
 |       impl = GetNamedGLImplementation(requested_implementation_name); | 
 |       if (std::find(allowed_impls.begin(), | 
 |                     allowed_impls.end(), | 
 |                     impl) == allowed_impls.end()) { | 
 |         LOG(ERROR) << "Requested GL implementation is not available."; | 
 |         return false; | 
 |       } | 
 |     } | 
 |   } | 
 |  | 
 |   bool gpu_service_logging = cmd->HasSwitch(switches::kEnableGPUServiceLogging); | 
 |   bool disable_gl_drawing = cmd->HasSwitch(switches::kDisableGLDrawingForTests); | 
 |  | 
 |   return InitializeOneOffImplementation( | 
 |       impl, fallback_to_osmesa, gpu_service_logging, disable_gl_drawing); | 
 | } | 
 |  | 
 | // static | 
 | bool GLSurface::InitializeOneOffImplementation(GLImplementation impl, | 
 |                                                bool fallback_to_osmesa, | 
 |                                                bool gpu_service_logging, | 
 |                                                bool disable_gl_drawing) { | 
 |   bool initialized = | 
 |       InitializeStaticGLBindings(impl) && InitializeOneOffInternal(); | 
 |   if (!initialized && fallback_to_osmesa) { | 
 |     ClearGLBindings(); | 
 |     initialized = InitializeStaticGLBindings(kGLImplementationOSMesaGL) && | 
 |                   InitializeOneOffInternal(); | 
 |   } | 
 |   if (!initialized) | 
 |     ClearGLBindings(); | 
 |  | 
 |   if (initialized) { | 
 |     DVLOG(1) << "Using " | 
 |              << GetGLImplementationName(GetGLImplementation()) | 
 |              << " GL implementation."; | 
 |     if (gpu_service_logging) | 
 |       InitializeDebugGLBindings(); | 
 |     if (disable_gl_drawing) | 
 |       InitializeNullDrawGLBindings(); | 
 |   } | 
 |   return initialized; | 
 | } | 
 |  | 
 | // static | 
 | void GLSurface::InitializeOneOffForTests() { | 
 |   DCHECK_EQ(kGLImplementationNone, GetGLImplementation()); | 
 |  | 
 | #if defined(USE_X11) | 
 |   XInitThreads(); | 
 | #endif | 
 |  | 
 |   bool use_osmesa = true; | 
 |  | 
 |   // We usually use OSMesa as this works on all bots. The command line can | 
 |   // override this behaviour to use hardware GL. | 
 |   if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kUseGpuInTests)) | 
 |     use_osmesa = false; | 
 |  | 
 | #if defined(OS_ANDROID) | 
 |   // On Android we always use hardware GL. | 
 |   use_osmesa = false; | 
 | #endif | 
 |  | 
 |   std::vector<GLImplementation> allowed_impls; | 
 |   GetAllowedGLImplementations(&allowed_impls); | 
 |   DCHECK(!allowed_impls.empty()); | 
 |  | 
 |   GLImplementation impl = allowed_impls[0]; | 
 |   if (use_osmesa) | 
 |     impl = kGLImplementationOSMesaGL; | 
 |  | 
 |   DCHECK(!CommandLine::ForCurrentProcess()->HasSwitch(switches::kUseGL)) | 
 |       << "kUseGL has not effect in tests"; | 
 |  | 
 |   bool fallback_to_osmesa = false; | 
 |   bool gpu_service_logging = false; | 
 |   bool disable_gl_drawing = true; | 
 |  | 
 |   CHECK(InitializeOneOffImplementation( | 
 |       impl, fallback_to_osmesa, gpu_service_logging, disable_gl_drawing)); | 
 | } | 
 |  | 
 | // static | 
 | void GLSurface::InitializeOneOffWithMockBindingsForTests() { | 
 |   DCHECK(!CommandLine::ForCurrentProcess()->HasSwitch(switches::kUseGL)) | 
 |       << "kUseGL has not effect in tests"; | 
 |  | 
 |   // This method may be called multiple times in the same process to set up | 
 |   // mock bindings in different ways. | 
 |   ClearGLBindings(); | 
 |  | 
 |   bool fallback_to_osmesa = false; | 
 |   bool gpu_service_logging = false; | 
 |   bool disable_gl_drawing = false; | 
 |  | 
 |   CHECK(InitializeOneOffImplementation(kGLImplementationMockGL, | 
 |                                        fallback_to_osmesa, | 
 |                                        gpu_service_logging, | 
 |                                        disable_gl_drawing)); | 
 | } | 
 |  | 
 | // static | 
 | void GLSurface::InitializeDynamicMockBindingsForTests(GLContext* context) { | 
 |   CHECK(InitializeDynamicGLBindings(kGLImplementationMockGL, context)); | 
 | } | 
 |  | 
 | GLSurface::GLSurface() {} | 
 |  | 
 | bool GLSurface::Initialize() { | 
 |   return true; | 
 | } | 
 |  | 
 | bool GLSurface::Resize(const gfx::Size& size) { | 
 |   NOTIMPLEMENTED(); | 
 |   return false; | 
 | } | 
 |  | 
 | bool GLSurface::Recreate() { | 
 |   NOTIMPLEMENTED(); | 
 |   return false; | 
 | } | 
 |  | 
 | bool GLSurface::DeferDraws() { | 
 |   return false; | 
 | } | 
 |  | 
 | bool GLSurface::SupportsPostSubBuffer() { | 
 |   return false; | 
 | } | 
 |  | 
 | unsigned int GLSurface::GetBackingFrameBufferObject() { | 
 |   return 0; | 
 | } | 
 |  | 
 | bool GLSurface::PostSubBuffer(int x, int y, int width, int height) { | 
 |   return false; | 
 | } | 
 |  | 
 | bool GLSurface::OnMakeCurrent(GLContext* context) { | 
 |   return true; | 
 | } | 
 |  | 
 | bool GLSurface::SetBackbufferAllocation(bool allocated) { | 
 |   return true; | 
 | } | 
 |  | 
 | void GLSurface::SetFrontbufferAllocation(bool allocated) { | 
 | } | 
 |  | 
 | void* GLSurface::GetShareHandle() { | 
 |   NOTIMPLEMENTED(); | 
 |   return NULL; | 
 | } | 
 |  | 
 | void* GLSurface::GetDisplay() { | 
 |   NOTIMPLEMENTED(); | 
 |   return NULL; | 
 | } | 
 |  | 
 | void* GLSurface::GetConfig() { | 
 |   NOTIMPLEMENTED(); | 
 |   return NULL; | 
 | } | 
 |  | 
 | unsigned GLSurface::GetFormat() { | 
 |   NOTIMPLEMENTED(); | 
 |   return 0; | 
 | } | 
 |  | 
 | VSyncProvider* GLSurface::GetVSyncProvider() { | 
 |   return NULL; | 
 | } | 
 |  | 
 | bool GLSurface::ScheduleOverlayPlane(int z_order, | 
 |                                      OverlayTransform transform, | 
 |                                      GLImage* image, | 
 |                                      const Rect& bounds_rect, | 
 |                                      const RectF& crop_rect) { | 
 |   NOTIMPLEMENTED(); | 
 |   return false; | 
 | } | 
 |  | 
 | bool GLSurface::IsSurfaceless() const { | 
 |   return false; | 
 | } | 
 |  | 
 | GLSurface* GLSurface::GetCurrent() { | 
 |   return current_surface_.Pointer()->Get(); | 
 | } | 
 |  | 
 | GLSurface::~GLSurface() { | 
 |   if (GetCurrent() == this) | 
 |     SetCurrent(NULL); | 
 | } | 
 |  | 
 | void GLSurface::SetCurrent(GLSurface* surface) { | 
 |   current_surface_.Pointer()->Set(surface); | 
 | } | 
 |  | 
 | bool GLSurface::ExtensionsContain(const char* c_extensions, const char* name) { | 
 |   DCHECK(name); | 
 |   if (!c_extensions) | 
 |     return false; | 
 |   std::string extensions(c_extensions); | 
 |   extensions += " "; | 
 |  | 
 |   std::string delimited_name(name); | 
 |   delimited_name += " "; | 
 |  | 
 |   return extensions.find(delimited_name) != std::string::npos; | 
 | } | 
 |  | 
 | GLSurfaceAdapter::GLSurfaceAdapter(GLSurface* surface) : surface_(surface) {} | 
 |  | 
 | bool GLSurfaceAdapter::Initialize() { | 
 |   return surface_->Initialize(); | 
 | } | 
 |  | 
 | void GLSurfaceAdapter::Destroy() { | 
 |   surface_->Destroy(); | 
 | } | 
 |  | 
 | bool GLSurfaceAdapter::Resize(const gfx::Size& size) { | 
 |   return surface_->Resize(size); | 
 | } | 
 |  | 
 | bool GLSurfaceAdapter::Recreate() { | 
 |   return surface_->Recreate(); | 
 | } | 
 |  | 
 | bool GLSurfaceAdapter::DeferDraws() { | 
 |   return surface_->DeferDraws(); | 
 | } | 
 |  | 
 | bool GLSurfaceAdapter::IsOffscreen() { | 
 |   return surface_->IsOffscreen(); | 
 | } | 
 |  | 
 | bool GLSurfaceAdapter::SwapBuffers() { | 
 |   return surface_->SwapBuffers(); | 
 | } | 
 |  | 
 | bool GLSurfaceAdapter::PostSubBuffer(int x, int y, int width, int height) { | 
 |   return surface_->PostSubBuffer(x, y, width, height); | 
 | } | 
 |  | 
 | bool GLSurfaceAdapter::SupportsPostSubBuffer() { | 
 |   return surface_->SupportsPostSubBuffer(); | 
 | } | 
 |  | 
 | gfx::Size GLSurfaceAdapter::GetSize() { | 
 |   return surface_->GetSize(); | 
 | } | 
 |  | 
 | void* GLSurfaceAdapter::GetHandle() { | 
 |   return surface_->GetHandle(); | 
 | } | 
 |  | 
 | unsigned int GLSurfaceAdapter::GetBackingFrameBufferObject() { | 
 |   return surface_->GetBackingFrameBufferObject(); | 
 | } | 
 |  | 
 | bool GLSurfaceAdapter::OnMakeCurrent(GLContext* context) { | 
 |   return surface_->OnMakeCurrent(context); | 
 | } | 
 |  | 
 | bool GLSurfaceAdapter::SetBackbufferAllocation(bool allocated) { | 
 |   return surface_->SetBackbufferAllocation(allocated); | 
 | } | 
 |  | 
 | void GLSurfaceAdapter::SetFrontbufferAllocation(bool allocated) { | 
 |   surface_->SetFrontbufferAllocation(allocated); | 
 | } | 
 |  | 
 | void* GLSurfaceAdapter::GetShareHandle() { | 
 |   return surface_->GetShareHandle(); | 
 | } | 
 |  | 
 | void* GLSurfaceAdapter::GetDisplay() { | 
 |   return surface_->GetDisplay(); | 
 | } | 
 |  | 
 | void* GLSurfaceAdapter::GetConfig() { | 
 |   return surface_->GetConfig(); | 
 | } | 
 |  | 
 | unsigned GLSurfaceAdapter::GetFormat() { | 
 |   return surface_->GetFormat(); | 
 | } | 
 |  | 
 | VSyncProvider* GLSurfaceAdapter::GetVSyncProvider() { | 
 |   return surface_->GetVSyncProvider(); | 
 | } | 
 |  | 
 | bool GLSurfaceAdapter::ScheduleOverlayPlane(int z_order, | 
 |                                             OverlayTransform transform, | 
 |                                             GLImage* image, | 
 |                                             const Rect& bounds_rect, | 
 |                                             const RectF& crop_rect) { | 
 |   return surface_->ScheduleOverlayPlane( | 
 |       z_order, transform, image, bounds_rect, crop_rect); | 
 | } | 
 |  | 
 | bool GLSurfaceAdapter::IsSurfaceless() const { | 
 |   return surface_->IsSurfaceless(); | 
 | } | 
 |  | 
 | GLSurfaceAdapter::~GLSurfaceAdapter() {} | 
 |  | 
 | }  // namespace gfx |