| // 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 <string> | 
 |  | 
 | #include "base/command_line.h" | 
 | #include "base/lazy_instance.h" | 
 | #include "base/logging.h" | 
 | #include "base/threading/thread_local.h" | 
 | #include "ui/gl/gl_bindings.h" | 
 | #include "ui/gl/gl_context.h" | 
 | #include "ui/gl/gl_gl_api_implementation.h" | 
 | #include "ui/gl/gl_implementation.h" | 
 | #include "ui/gl/gl_surface.h" | 
 | #include "ui/gl/gl_switches.h" | 
 | #include "ui/gl/gl_version_info.h" | 
 |  | 
 | namespace gfx { | 
 |  | 
 | namespace { | 
 | base::LazyInstance<base::ThreadLocalPointer<GLContext> >::Leaky | 
 |     current_context_ = LAZY_INSTANCE_INITIALIZER; | 
 |  | 
 | base::LazyInstance<base::ThreadLocalPointer<GLContext> >::Leaky | 
 |     current_real_context_ = LAZY_INSTANCE_INITIALIZER; | 
 | }  // namespace | 
 |  | 
 | GLContext::ScopedReleaseCurrent::ScopedReleaseCurrent() : canceled_(false) {} | 
 |  | 
 | GLContext::ScopedReleaseCurrent::~ScopedReleaseCurrent() { | 
 |   if (!canceled_ && GetCurrent()) { | 
 |     GetCurrent()->ReleaseCurrent(NULL); | 
 |   } | 
 | } | 
 |  | 
 | void GLContext::ScopedReleaseCurrent::Cancel() { | 
 |   canceled_ = true; | 
 | } | 
 |  | 
 | GLContext::FlushEvent::FlushEvent() { | 
 | } | 
 |  | 
 | GLContext::FlushEvent::~FlushEvent() { | 
 | } | 
 |  | 
 | void GLContext::FlushEvent::Signal() { | 
 |   flag_.Set(); | 
 | } | 
 |  | 
 | bool GLContext::FlushEvent::IsSignaled() { | 
 |   return flag_.IsSet(); | 
 | } | 
 |  | 
 | GLContext::GLContext(GLShareGroup* share_group) : | 
 |     share_group_(share_group), | 
 |     swap_interval_(1), | 
 |     force_swap_interval_zero_(false) { | 
 |   if (!share_group_.get()) | 
 |     share_group_ = new GLShareGroup; | 
 |  | 
 |   share_group_->AddContext(this); | 
 | } | 
 |  | 
 | GLContext::~GLContext() { | 
 |   share_group_->RemoveContext(this); | 
 |   if (GetCurrent() == this) { | 
 |     SetCurrent(NULL); | 
 |   } | 
 | } | 
 |  | 
 | scoped_refptr<GLContext::FlushEvent> GLContext::SignalFlush() { | 
 |   DCHECK(IsCurrent(NULL)); | 
 |   scoped_refptr<FlushEvent> flush_event = new FlushEvent(); | 
 |   flush_events_.push_back(flush_event); | 
 |   return flush_event; | 
 | } | 
 |  | 
 | bool GLContext::GetTotalGpuMemory(size_t* bytes) { | 
 |   DCHECK(bytes); | 
 |   *bytes = 0; | 
 |   return false; | 
 | } | 
 |  | 
 | void GLContext::SetSafeToForceGpuSwitch() { | 
 | } | 
 |  | 
 | bool GLContext::ForceGpuSwitchIfNeeded() { | 
 |   return true; | 
 | } | 
 |  | 
 | void GLContext::SetUnbindFboOnMakeCurrent() { | 
 |   NOTIMPLEMENTED(); | 
 | } | 
 |  | 
 | std::string GLContext::GetExtensions() { | 
 |   DCHECK(IsCurrent(NULL)); | 
 |   const char* ext = reinterpret_cast<const char*>(glGetString(GL_EXTENSIONS)); | 
 |   return std::string(ext ? ext : ""); | 
 | } | 
 |  | 
 | std::string GLContext::GetGLVersion() { | 
 |   DCHECK(IsCurrent(NULL)); | 
 |   const char *version = | 
 |       reinterpret_cast<const char*>(glGetString(GL_VERSION)); | 
 |   return std::string(version ? version : ""); | 
 | } | 
 |  | 
 | std::string GLContext::GetGLRenderer() { | 
 |   DCHECK(IsCurrent(NULL)); | 
 |   const char *renderer = | 
 |       reinterpret_cast<const char*>(glGetString(GL_RENDERER)); | 
 |   return std::string(renderer ? renderer : ""); | 
 | } | 
 |  | 
 | bool GLContext::HasExtension(const char* name) { | 
 |   std::string extensions = GetExtensions(); | 
 |   extensions += " "; | 
 |  | 
 |   std::string delimited_name(name); | 
 |   delimited_name += " "; | 
 |  | 
 |   return extensions.find(delimited_name) != std::string::npos; | 
 | } | 
 |  | 
 | const GLVersionInfo* GLContext::GetVersionInfo() { | 
 |   if(!version_info_) { | 
 |     std::string version = GetGLVersion(); | 
 |     std::string renderer = GetGLRenderer(); | 
 |     version_info_ = scoped_ptr<GLVersionInfo>( | 
 |         new GLVersionInfo(version.c_str(), renderer.c_str())); | 
 |   } | 
 |   return version_info_.get(); | 
 | } | 
 |  | 
 | GLShareGroup* GLContext::share_group() { | 
 |   return share_group_.get(); | 
 | } | 
 |  | 
 | bool GLContext::LosesAllContextsOnContextLost() { | 
 |   switch (GetGLImplementation()) { | 
 |     case kGLImplementationDesktopGL: | 
 |       return false; | 
 |     case kGLImplementationEGLGLES2: | 
 |       return true; | 
 |     case kGLImplementationOSMesaGL: | 
 |     case kGLImplementationAppleGL: | 
 |       return false; | 
 |     case kGLImplementationMockGL: | 
 |       return false; | 
 |     default: | 
 |       NOTREACHED(); | 
 |       return true; | 
 |   } | 
 | } | 
 |  | 
 | GLContext* GLContext::GetCurrent() { | 
 |   return current_context_.Pointer()->Get(); | 
 | } | 
 |  | 
 | GLContext* GLContext::GetRealCurrent() { | 
 |   return current_real_context_.Pointer()->Get(); | 
 | } | 
 |  | 
 | void GLContext::SetCurrent(GLSurface* surface) { | 
 |   current_context_.Pointer()->Set(surface ? this : NULL); | 
 |   GLSurface::SetCurrent(surface); | 
 |   // Leave the real GL api current so that unit tests work correctly. | 
 |   // TODO(sievers): Remove this, but needs all gpu_unittest classes | 
 |   // to create and make current a context. | 
 |   if (!surface && GetGLImplementation() != kGLImplementationMockGL) { | 
 |     SetGLApiToNoContext(); | 
 |   } | 
 | } | 
 |  | 
 | GLStateRestorer* GLContext::GetGLStateRestorer() { | 
 |   return state_restorer_.get(); | 
 | } | 
 |  | 
 | void GLContext::SetGLStateRestorer(GLStateRestorer* state_restorer) { | 
 |   state_restorer_ = make_scoped_ptr(state_restorer); | 
 | } | 
 |  | 
 | void GLContext::SetSwapInterval(int interval) { | 
 |   swap_interval_ = interval; | 
 |   OnSetSwapInterval(force_swap_interval_zero_ ? 0 : swap_interval_); | 
 | } | 
 |  | 
 | void GLContext::ForceSwapIntervalZero(bool force) { | 
 |   force_swap_interval_zero_ = force; | 
 |   OnSetSwapInterval(force_swap_interval_zero_ ? 0 : swap_interval_); | 
 | } | 
 |  | 
 | bool GLContext::WasAllocatedUsingRobustnessExtension() { | 
 |   return false; | 
 | } | 
 |  | 
 | bool GLContext::InitializeDynamicBindings() { | 
 |   DCHECK(IsCurrent(NULL)); | 
 |   static bool initialized = false; | 
 |   if (initialized) | 
 |     return initialized; | 
 |   initialized = InitializeDynamicGLBindings(GetGLImplementation(), this); | 
 |   if (!initialized) | 
 |     LOG(ERROR) << "Could not initialize dynamic bindings."; | 
 |   return initialized; | 
 | } | 
 |  | 
 | void GLContext::SetupForVirtualization() { | 
 |   if (!virtual_gl_api_) { | 
 |     virtual_gl_api_.reset(new VirtualGLApi()); | 
 |     virtual_gl_api_->Initialize(&g_driver_gl, this); | 
 |   } | 
 | } | 
 |  | 
 | bool GLContext::MakeVirtuallyCurrent( | 
 |     GLContext* virtual_context, GLSurface* surface) { | 
 |   DCHECK(virtual_gl_api_); | 
 |   if (!ForceGpuSwitchIfNeeded()) | 
 |     return false; | 
 |   return virtual_gl_api_->MakeCurrent(virtual_context, surface); | 
 | } | 
 |  | 
 | void GLContext::OnReleaseVirtuallyCurrent(GLContext* virtual_context) { | 
 |   if (virtual_gl_api_) | 
 |     virtual_gl_api_->OnReleaseVirtuallyCurrent(virtual_context); | 
 | } | 
 |  | 
 | void GLContext::SetRealGLApi() { | 
 |   SetGLToRealGLApi(); | 
 | } | 
 |  | 
 | void GLContext::OnFlush() { | 
 |   for (size_t n = 0; n < flush_events_.size(); n++) | 
 |     flush_events_[n]->Signal(); | 
 |   flush_events_.clear(); | 
 | } | 
 |  | 
 | GLContextReal::GLContextReal(GLShareGroup* share_group) | 
 |     : GLContext(share_group) {} | 
 |  | 
 | GLContextReal::~GLContextReal() {} | 
 |  | 
 | void GLContextReal::SetCurrent(GLSurface* surface) { | 
 |   GLContext::SetCurrent(surface); | 
 |   current_real_context_.Pointer()->Set(surface ? this : NULL); | 
 | } | 
 |  | 
 | }  // namespace gfx |