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.
8 #include "base/cancelable_callback.h"
9 #include "base/command_line.h"
10 #include "base/lazy_instance.h"
11 #include "base/logging.h"
12 #include "base/strings/string_util.h"
13 #include "base/threading/thread_local.h"
14 #include "ui/gl/gl_bindings.h"
15 #include "ui/gl/gl_context.h"
16 #include "ui/gl/gl_gl_api_implementation.h"
17 #include "ui/gl/gl_implementation.h"
18 #include "ui/gl/gl_surface.h"
19 #include "ui/gl/gl_switches.h"
20 #include "ui/gl/gl_version_info.h"
21 #include "ui/gl/gpu_timing.h"
26 base::LazyInstance
<base::ThreadLocalPointer
<GLContext
> >::Leaky
27 current_context_
= LAZY_INSTANCE_INITIALIZER
;
29 base::LazyInstance
<base::ThreadLocalPointer
<GLContext
> >::Leaky
30 current_real_context_
= LAZY_INSTANCE_INITIALIZER
;
33 GLContext::ScopedReleaseCurrent::ScopedReleaseCurrent() : canceled_(false) {}
35 GLContext::ScopedReleaseCurrent::~ScopedReleaseCurrent() {
36 if (!canceled_
&& GetCurrent()) {
37 GetCurrent()->ReleaseCurrent(nullptr);
41 void GLContext::ScopedReleaseCurrent::Cancel() {
45 GLContext::GLContext(GLShareGroup
* share_group
) :
46 share_group_(share_group
),
47 state_dirtied_externally_(false),
49 force_swap_interval_zero_(false),
50 state_dirtied_callback_(
51 base::Bind(&GLContext::SetStateWasDirtiedExternally
,
52 // Note that if this is not unretained, it will create a cycle (and
53 // will never be freed.
54 base::Unretained(this),
56 if (!share_group_
.get())
57 share_group_
= new GLShareGroup
;
59 share_group_
->AddContext(this);
62 GLContext::~GLContext() {
63 share_group_
->RemoveContext(this);
64 if (GetCurrent() == this) {
69 bool GLContext::GetTotalGpuMemory(size_t* bytes
) {
75 void GLContext::SetSafeToForceGpuSwitch() {
78 bool GLContext::ForceGpuSwitchIfNeeded() {
82 void GLContext::SetUnbindFboOnMakeCurrent() {
86 std::string
GLContext::GetExtensions() {
87 DCHECK(IsCurrent(nullptr));
88 if (gfx::GetGLImplementation() !=
89 gfx::kGLImplementationDesktopGLCoreProfile
) {
90 const char* ext
= reinterpret_cast<const char*>(glGetString(GL_EXTENSIONS
));
91 return std::string(ext
? ext
: "");
94 std::vector
<std::string
> exts
;
95 GLint num_extensions
= 0;
96 glGetIntegerv(GL_NUM_EXTENSIONS
, &num_extensions
);
97 for (GLint i
= 0; i
< num_extensions
; ++i
) {
98 const char* extension
= reinterpret_cast<const char*>(
99 glGetStringi(GL_EXTENSIONS
, i
));
100 DCHECK(extension
!= nullptr);
101 exts
.push_back(extension
);
103 return base::JoinString(exts
, " ");
106 std::string
GLContext::GetGLVersion() {
107 DCHECK(IsCurrent(nullptr));
108 const char *version
=
109 reinterpret_cast<const char*>(glGetString(GL_VERSION
));
110 return std::string(version
? version
: "");
113 std::string
GLContext::GetGLRenderer() {
114 DCHECK(IsCurrent(nullptr));
115 const char *renderer
=
116 reinterpret_cast<const char*>(glGetString(GL_RENDERER
));
117 return std::string(renderer
? renderer
: "");
120 base::Closure
GLContext::GetStateWasDirtiedExternallyCallback() {
121 return state_dirtied_callback_
.callback();
124 void GLContext::RestoreStateIfDirtiedExternally() {
128 bool GLContext::GetStateWasDirtiedExternally() const {
129 DCHECK(virtual_gl_api_
);
130 return state_dirtied_externally_
;
133 void GLContext::SetStateWasDirtiedExternally(bool dirtied_externally
) {
134 DCHECK(virtual_gl_api_
);
135 state_dirtied_externally_
= dirtied_externally
;
138 bool GLContext::HasExtension(const char* name
) {
139 std::string extensions
= GetExtensions();
142 std::string
delimited_name(name
);
143 delimited_name
+= " ";
145 return extensions
.find(delimited_name
) != std::string::npos
;
148 const GLVersionInfo
* GLContext::GetVersionInfo() {
150 std::string version
= GetGLVersion();
151 std::string renderer
= GetGLRenderer();
153 make_scoped_ptr(new GLVersionInfo(
154 version
.c_str(), renderer
.c_str(),
155 GetExtensions().c_str()));
157 return version_info_
.get();
160 GLShareGroup
* GLContext::share_group() {
161 return share_group_
.get();
164 bool GLContext::LosesAllContextsOnContextLost() {
165 switch (GetGLImplementation()) {
166 case kGLImplementationDesktopGL
:
168 case kGLImplementationEGLGLES2
:
170 case kGLImplementationOSMesaGL
:
171 case kGLImplementationAppleGL
:
173 case kGLImplementationMockGL
:
181 GLContext
* GLContext::GetCurrent() {
182 return current_context_
.Pointer()->Get();
185 GLContext
* GLContext::GetRealCurrent() {
186 return current_real_context_
.Pointer()->Get();
189 void GLContext::SetCurrent(GLSurface
* surface
) {
190 current_context_
.Pointer()->Set(surface
? this : nullptr);
191 GLSurface::SetCurrent(surface
);
192 // Leave the real GL api current so that unit tests work correctly.
193 // TODO(sievers): Remove this, but needs all gpu_unittest classes
194 // to create and make current a context.
195 if (!surface
&& GetGLImplementation() != kGLImplementationMockGL
) {
196 SetGLApiToNoContext();
200 GLStateRestorer
* GLContext::GetGLStateRestorer() {
201 return state_restorer_
.get();
204 void GLContext::SetGLStateRestorer(GLStateRestorer
* state_restorer
) {
205 state_restorer_
= make_scoped_ptr(state_restorer
);
208 void GLContext::SetSwapInterval(int interval
) {
209 swap_interval_
= interval
;
210 OnSetSwapInterval(force_swap_interval_zero_
? 0 : swap_interval_
);
213 void GLContext::ForceSwapIntervalZero(bool force
) {
214 force_swap_interval_zero_
= force
;
215 OnSetSwapInterval(force_swap_interval_zero_
? 0 : swap_interval_
);
218 bool GLContext::WasAllocatedUsingRobustnessExtension() {
222 bool GLContext::InitializeDynamicBindings() {
223 DCHECK(IsCurrent(nullptr));
224 static bool initialized
= false;
227 initialized
= InitializeDynamicGLBindings(GetGLImplementation(), this);
229 LOG(ERROR
) << "Could not initialize dynamic bindings.";
233 void GLContext::SetupForVirtualization() {
234 if (!virtual_gl_api_
) {
235 virtual_gl_api_
.reset(new VirtualGLApi());
236 virtual_gl_api_
->Initialize(&g_driver_gl
, this);
240 bool GLContext::MakeVirtuallyCurrent(
241 GLContext
* virtual_context
, GLSurface
* surface
) {
242 DCHECK(virtual_gl_api_
);
243 if (!ForceGpuSwitchIfNeeded())
245 return virtual_gl_api_
->MakeCurrent(virtual_context
, surface
);
248 void GLContext::OnReleaseVirtuallyCurrent(GLContext
* virtual_context
) {
250 virtual_gl_api_
->OnReleaseVirtuallyCurrent(virtual_context
);
253 void GLContext::SetRealGLApi() {
257 GLContextReal::GLContextReal(GLShareGroup
* share_group
)
258 : GLContext(share_group
) {}
260 scoped_refptr
<gfx::GPUTimingClient
> GLContextReal::CreateGPUTimingClient() {
262 gpu_timing_
.reset(GPUTiming::CreateGPUTiming(this));
264 return gpu_timing_
->CreateGPUTimingClient();
267 GLContextReal::~GLContextReal() {}
269 void GLContextReal::SetCurrent(GLSurface
* surface
) {
270 GLContext::SetCurrent(surface
);
271 current_real_context_
.Pointer()->Set(surface
? this : nullptr);