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 <string>
6
7#include "base/command_line.h"
8#include "base/lazy_instance.h"
9#include "base/logging.h"
10#include "base/threading/thread_local.h"
11#include "ui/gl/gl_bindings.h"
12#include "ui/gl/gl_context.h"
13#include "ui/gl/gl_gl_api_implementation.h"
14#include "ui/gl/gl_implementation.h"
15#include "ui/gl/gl_surface.h"
16#include "ui/gl/gl_switches.h"
17#include "ui/gl/gl_version_info.h"
18
19namespace gfx {
20
21namespace {
22base::LazyInstance<base::ThreadLocalPointer<GLContext> >::Leaky
23    current_context_ = LAZY_INSTANCE_INITIALIZER;
24
25base::LazyInstance<base::ThreadLocalPointer<GLContext> >::Leaky
26    current_real_context_ = LAZY_INSTANCE_INITIALIZER;
27}  // namespace
28
29GLContext::ScopedReleaseCurrent::ScopedReleaseCurrent() : canceled_(false) {}
30
31GLContext::ScopedReleaseCurrent::~ScopedReleaseCurrent() {
32  if (!canceled_ && GetCurrent()) {
33    GetCurrent()->ReleaseCurrent(NULL);
34  }
35}
36
37void GLContext::ScopedReleaseCurrent::Cancel() {
38  canceled_ = true;
39}
40
41GLContext::FlushEvent::FlushEvent() {
42}
43
44GLContext::FlushEvent::~FlushEvent() {
45}
46
47void GLContext::FlushEvent::Signal() {
48  flag_.Set();
49}
50
51bool GLContext::FlushEvent::IsSignaled() {
52  return flag_.IsSet();
53}
54
55GLContext::GLContext(GLShareGroup* share_group) : share_group_(share_group) {
56  if (!share_group_.get())
57    share_group_ = new GLShareGroup;
58
59  share_group_->AddContext(this);
60}
61
62GLContext::~GLContext() {
63  share_group_->RemoveContext(this);
64  if (GetCurrent() == this) {
65    SetCurrent(NULL);
66  }
67}
68
69scoped_refptr<GLContext::FlushEvent> GLContext::SignalFlush() {
70  DCHECK(IsCurrent(NULL));
71  scoped_refptr<FlushEvent> flush_event = new FlushEvent();
72  flush_events_.push_back(flush_event);
73  return flush_event;
74}
75
76bool GLContext::GetTotalGpuMemory(size_t* bytes) {
77  DCHECK(bytes);
78  *bytes = 0;
79  return false;
80}
81
82void GLContext::SetSafeToForceGpuSwitch() {
83}
84
85void GLContext::SetUnbindFboOnMakeCurrent() {
86  NOTIMPLEMENTED();
87}
88
89std::string GLContext::GetExtensions() {
90  DCHECK(IsCurrent(NULL));
91  const char* ext = reinterpret_cast<const char*>(glGetString(GL_EXTENSIONS));
92  return std::string(ext ? ext : "");
93}
94
95std::string GLContext::GetGLVersion() {
96  DCHECK(IsCurrent(NULL));
97  const char *version =
98      reinterpret_cast<const char*>(glGetString(GL_VERSION));
99  return std::string(version ? version : "");
100}
101
102std::string GLContext::GetGLRenderer() {
103  DCHECK(IsCurrent(NULL));
104  const char *renderer =
105      reinterpret_cast<const char*>(glGetString(GL_RENDERER));
106  return std::string(renderer ? renderer : "");
107}
108
109bool GLContext::HasExtension(const char* name) {
110  std::string extensions = GetExtensions();
111  extensions += " ";
112
113  std::string delimited_name(name);
114  delimited_name += " ";
115
116  return extensions.find(delimited_name) != std::string::npos;
117}
118
119const GLVersionInfo* GLContext::GetVersionInfo() {
120  if(!version_info_) {
121    std::string version = GetGLVersion();
122    std::string renderer = GetGLRenderer();
123    version_info_ = scoped_ptr<GLVersionInfo>(
124        new GLVersionInfo(version.c_str(), renderer.c_str()));
125  }
126  return version_info_.get();
127}
128
129GLShareGroup* GLContext::share_group() {
130  return share_group_.get();
131}
132
133bool GLContext::LosesAllContextsOnContextLost() {
134  switch (GetGLImplementation()) {
135    case kGLImplementationDesktopGL:
136      return false;
137    case kGLImplementationEGLGLES2:
138      return true;
139    case kGLImplementationOSMesaGL:
140    case kGLImplementationAppleGL:
141      return false;
142    case kGLImplementationMockGL:
143      return false;
144    default:
145      NOTREACHED();
146      return true;
147  }
148}
149
150GLContext* GLContext::GetCurrent() {
151  return current_context_.Pointer()->Get();
152}
153
154GLContext* GLContext::GetRealCurrent() {
155  return current_real_context_.Pointer()->Get();
156}
157
158void GLContext::SetCurrent(GLSurface* surface) {
159  current_context_.Pointer()->Set(surface ? this : NULL);
160  GLSurface::SetCurrent(surface);
161  // Leave the real GL api current so that unit tests work correctly.
162  // TODO(sievers): Remove this, but needs all gpu_unittest classes
163  // to create and make current a context.
164  if (!surface && GetGLImplementation() != kGLImplementationMockGL) {
165    SetGLApiToNoContext();
166  }
167}
168
169GLStateRestorer* GLContext::GetGLStateRestorer() {
170  return state_restorer_.get();
171}
172
173void GLContext::SetGLStateRestorer(GLStateRestorer* state_restorer) {
174  state_restorer_ = make_scoped_ptr(state_restorer);
175}
176
177bool GLContext::WasAllocatedUsingRobustnessExtension() {
178  return false;
179}
180
181bool GLContext::InitializeDynamicBindings() {
182  DCHECK(IsCurrent(NULL));
183  static bool initialized = false;
184  if (initialized)
185    return initialized;
186  initialized = InitializeDynamicGLBindings(GetGLImplementation(), this);
187  if (!initialized)
188    LOG(ERROR) << "Could not initialize dynamic bindings.";
189  return initialized;
190}
191
192void GLContext::SetupForVirtualization() {
193  if (!virtual_gl_api_) {
194    virtual_gl_api_.reset(new VirtualGLApi());
195    virtual_gl_api_->Initialize(&g_driver_gl, this);
196  }
197}
198
199bool GLContext::MakeVirtuallyCurrent(
200    GLContext* virtual_context, GLSurface* surface) {
201  DCHECK(virtual_gl_api_);
202  return virtual_gl_api_->MakeCurrent(virtual_context, surface);
203}
204
205void GLContext::OnReleaseVirtuallyCurrent(GLContext* virtual_context) {
206  if (virtual_gl_api_)
207    virtual_gl_api_->OnReleaseVirtuallyCurrent(virtual_context);
208}
209
210void GLContext::SetRealGLApi() {
211  SetGLToRealGLApi();
212}
213
214void GLContext::OnFlush() {
215  for (size_t n = 0; n < flush_events_.size(); n++)
216    flush_events_[n]->Signal();
217  flush_events_.clear();
218}
219
220GLContextReal::GLContextReal(GLShareGroup* share_group)
221    : GLContext(share_group) {}
222
223GLContextReal::~GLContextReal() {}
224
225void GLContextReal::SetCurrent(GLSurface* surface) {
226  GLContext::SetCurrent(surface);
227  current_real_context_.Pointer()->Set(surface ? this : NULL);
228}
229
230}  // namespace gfx
231