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.
5 #include "ui/gl/gl_gl_api_implementation.h"
10 #include "base/command_line.h"
11 #include "base/strings/string_util.h"
12 #include "ui/gl/gl_context.h"
13 #include "ui/gl/gl_implementation.h"
14 #include "ui/gl/gl_state_restorer.h"
15 #include "ui/gl/gl_surface.h"
16 #include "ui/gl/gl_switches.h"
17 #include "ui/gl/gl_version_info.h"
21 // The GL Api being used. This could be g_real_gl or gl_trace_gl
22 static GLApi
* g_gl
= NULL
;
23 // A GL Api that calls directly into the driver.
24 static RealGLApi
* g_real_gl
= NULL
;
25 // A GL Api that does nothing but warn about illegal GL calls without a context
27 static NoContextGLApi
* g_no_context_gl
= NULL
;
28 // A GL Api that calls TRACE and then calls another GL api.
29 static TraceGLApi
* g_trace_gl
= NULL
;
30 // GL version used when initializing dynamic bindings.
31 static GLVersionInfo
* g_version_info
= NULL
;
35 static inline GLenum
GetInternalFormat(GLenum internal_format
) {
36 if (gfx::GetGLImplementation() != gfx::kGLImplementationEGLGLES2
) {
37 if (internal_format
== GL_BGRA_EXT
|| internal_format
== GL_BGRA8_EXT
)
40 return internal_format
;
43 // TODO(epenner): Could the above function be merged into this and removed?
44 static inline GLenum
GetTexInternalFormat(GLenum internal_format
,
47 GLenum gl_internal_format
= GetInternalFormat(internal_format
);
49 // g_version_info must be initialized when this function is bound.
50 DCHECK(gfx::g_version_info
);
51 if (gfx::g_version_info
->is_es3
) {
52 if (format
== GL_RED_EXT
) {
54 case GL_UNSIGNED_BYTE
:
55 gl_internal_format
= GL_R8_EXT
;
57 case GL_HALF_FLOAT_OES
:
58 gl_internal_format
= GL_R16F_EXT
;
61 gl_internal_format
= GL_R32F_EXT
;
67 return gl_internal_format
;
68 } else if (format
== GL_RG_EXT
) {
70 case GL_UNSIGNED_BYTE
:
71 gl_internal_format
= GL_RG8_EXT
;
73 case GL_HALF_FLOAT_OES
:
74 gl_internal_format
= GL_RG16F_EXT
;
77 gl_internal_format
= GL_RG32F_EXT
;
83 return gl_internal_format
;
87 if (type
== GL_FLOAT
&& gfx::g_version_info
->is_angle
&&
88 gfx::g_version_info
->is_es
&& gfx::g_version_info
->major_version
== 2) {
89 // It's possible that the texture is using a sized internal format, and
90 // ANGLE exposing GLES2 API doesn't support those.
91 // TODO(oetuaho@nvidia.com): Remove these conversions once ANGLE has the
93 // http://code.google.com/p/angleproject/issues/detail?id=556
96 gl_internal_format
= GL_RGBA
;
99 gl_internal_format
= GL_RGB
;
106 if (gfx::g_version_info
->is_es
)
107 return gl_internal_format
;
109 if (type
== GL_FLOAT
) {
112 gl_internal_format
= GL_RGBA32F_ARB
;
115 gl_internal_format
= GL_RGB32F_ARB
;
117 case GL_LUMINANCE_ALPHA
:
118 gl_internal_format
= GL_LUMINANCE_ALPHA32F_ARB
;
121 gl_internal_format
= GL_LUMINANCE32F_ARB
;
124 gl_internal_format
= GL_ALPHA32F_ARB
;
130 } else if (type
== GL_HALF_FLOAT_OES
) {
133 gl_internal_format
= GL_RGBA16F_ARB
;
136 gl_internal_format
= GL_RGB16F_ARB
;
138 case GL_LUMINANCE_ALPHA
:
139 gl_internal_format
= GL_LUMINANCE_ALPHA16F_ARB
;
142 gl_internal_format
= GL_LUMINANCE16F_ARB
;
145 gl_internal_format
= GL_ALPHA16F_ARB
;
152 return gl_internal_format
;
155 static inline GLenum
GetTexType(GLenum type
) {
156 if (gfx::GetGLImplementation() != gfx::kGLImplementationEGLGLES2
) {
157 if (type
== GL_HALF_FLOAT_OES
)
158 return GL_HALF_FLOAT_ARB
;
163 static void GL_BINDING_CALL
CustomTexImage2D(
164 GLenum target
, GLint level
, GLint internalformat
,
165 GLsizei width
, GLsizei height
, GLint border
, GLenum format
, GLenum type
,
166 const void* pixels
) {
167 GLenum gl_internal_format
= GetTexInternalFormat(
168 internalformat
, format
, type
);
169 GLenum gl_type
= GetTexType(type
);
170 g_driver_gl
.orig_fn
.glTexImage2DFn(
171 target
, level
, gl_internal_format
, width
, height
, border
, format
, gl_type
,
175 static void GL_BINDING_CALL
CustomTexSubImage2D(
176 GLenum target
, GLint level
, GLint xoffset
, GLint yoffset
, GLsizei width
,
177 GLsizei height
, GLenum format
, GLenum type
, const void* pixels
) {
178 GLenum gl_type
= GetTexType(type
);
179 g_driver_gl
.orig_fn
.glTexSubImage2DFn(
180 target
, level
, xoffset
, yoffset
, width
, height
, format
, gl_type
, pixels
);
183 static void GL_BINDING_CALL
CustomTexStorage2DEXT(
184 GLenum target
, GLsizei levels
, GLenum internalformat
, GLsizei width
,
186 GLenum gl_internal_format
= GetInternalFormat(internalformat
);
187 g_driver_gl
.orig_fn
.glTexStorage2DEXTFn(
188 target
, levels
, gl_internal_format
, width
, height
);
191 static void GL_BINDING_CALL
CustomRenderbufferStorageEXT(
192 GLenum target
, GLenum internalformat
, GLsizei width
, GLsizei height
) {
193 GLenum gl_internal_format
= GetInternalFormat(internalformat
);
194 g_driver_gl
.orig_fn
.glRenderbufferStorageEXTFn(
195 target
, gl_internal_format
, width
, height
);
198 // The ANGLE and IMG variants of glRenderbufferStorageMultisample currently do
199 // not support BGRA render buffers so only the EXT one is customized. If
200 // GL_CHROMIUM_renderbuffer_format_BGRA8888 support is added to ANGLE then the
201 // ANGLE version should also be customized.
202 static void GL_BINDING_CALL
CustomRenderbufferStorageMultisampleEXT(
203 GLenum target
, GLsizei samples
, GLenum internalformat
, GLsizei width
,
205 GLenum gl_internal_format
= GetInternalFormat(internalformat
);
206 g_driver_gl
.orig_fn
.glRenderbufferStorageMultisampleEXTFn(
207 target
, samples
, gl_internal_format
, width
, height
);
210 } // anonymous namespace
212 void DriverGL::InitializeCustomDynamicBindings(GLContext
* context
) {
213 InitializeDynamicBindings(context
);
215 DCHECK(orig_fn
.glTexImage2DFn
== NULL
);
216 orig_fn
.glTexImage2DFn
= fn
.glTexImage2DFn
;
218 reinterpret_cast<glTexImage2DProc
>(CustomTexImage2D
);
220 DCHECK(orig_fn
.glTexSubImage2DFn
== NULL
);
221 orig_fn
.glTexSubImage2DFn
= fn
.glTexSubImage2DFn
;
222 fn
.glTexSubImage2DFn
=
223 reinterpret_cast<glTexSubImage2DProc
>(CustomTexSubImage2D
);
225 DCHECK(orig_fn
.glTexStorage2DEXTFn
== NULL
);
226 orig_fn
.glTexStorage2DEXTFn
= fn
.glTexStorage2DEXTFn
;
227 fn
.glTexStorage2DEXTFn
=
228 reinterpret_cast<glTexStorage2DEXTProc
>(CustomTexStorage2DEXT
);
230 DCHECK(orig_fn
.glRenderbufferStorageEXTFn
== NULL
);
231 orig_fn
.glRenderbufferStorageEXTFn
= fn
.glRenderbufferStorageEXTFn
;
232 fn
.glRenderbufferStorageEXTFn
=
233 reinterpret_cast<glRenderbufferStorageEXTProc
>(
234 CustomRenderbufferStorageEXT
);
236 DCHECK(orig_fn
.glRenderbufferStorageMultisampleEXTFn
== NULL
);
237 orig_fn
.glRenderbufferStorageMultisampleEXTFn
=
238 fn
.glRenderbufferStorageMultisampleEXTFn
;
239 fn
.glRenderbufferStorageMultisampleEXTFn
=
240 reinterpret_cast<glRenderbufferStorageMultisampleEXTProc
>(
241 CustomRenderbufferStorageMultisampleEXT
);
244 static void GL_BINDING_CALL
NullDrawClearFn(GLbitfield mask
) {
245 if (!g_driver_gl
.null_draw_bindings_enabled
)
246 g_driver_gl
.orig_fn
.glClearFn(mask
);
249 static void GL_BINDING_CALL
250 NullDrawDrawArraysFn(GLenum mode
, GLint first
, GLsizei count
) {
251 if (!g_driver_gl
.null_draw_bindings_enabled
)
252 g_driver_gl
.orig_fn
.glDrawArraysFn(mode
, first
, count
);
255 static void GL_BINDING_CALL
NullDrawDrawElementsFn(GLenum mode
,
258 const void* indices
) {
259 if (!g_driver_gl
.null_draw_bindings_enabled
)
260 g_driver_gl
.orig_fn
.glDrawElementsFn(mode
, count
, type
, indices
);
263 void DriverGL::InitializeNullDrawBindings() {
264 DCHECK(orig_fn
.glClearFn
== NULL
);
265 orig_fn
.glClearFn
= fn
.glClearFn
;
266 fn
.glClearFn
= NullDrawClearFn
;
268 DCHECK(orig_fn
.glDrawArraysFn
== NULL
);
269 orig_fn
.glDrawArraysFn
= fn
.glDrawArraysFn
;
270 fn
.glDrawArraysFn
= NullDrawDrawArraysFn
;
272 DCHECK(orig_fn
.glDrawElementsFn
== NULL
);
273 orig_fn
.glDrawElementsFn
= fn
.glDrawElementsFn
;
274 fn
.glDrawElementsFn
= NullDrawDrawElementsFn
;
276 null_draw_bindings_enabled
= true;
279 bool DriverGL::HasInitializedNullDrawBindings() {
280 return orig_fn
.glClearFn
!= NULL
&& orig_fn
.glDrawArraysFn
!= NULL
&&
281 orig_fn
.glDrawElementsFn
!= NULL
;
284 bool DriverGL::SetNullDrawBindingsEnabled(bool enabled
) {
285 DCHECK(orig_fn
.glClearFn
!= NULL
);
286 DCHECK(orig_fn
.glDrawArraysFn
!= NULL
);
287 DCHECK(orig_fn
.glDrawElementsFn
!= NULL
);
289 bool before
= null_draw_bindings_enabled
;
290 null_draw_bindings_enabled
= enabled
;
294 void InitializeStaticGLBindingsGL() {
295 g_current_gl_context_tls
= new base::ThreadLocalPointer
<GLApi
>;
296 g_driver_gl
.InitializeStaticBindings();
298 g_real_gl
= new RealGLApi();
299 g_trace_gl
= new TraceGLApi(g_real_gl
);
300 g_no_context_gl
= new NoContextGLApi();
302 g_real_gl
->Initialize(&g_driver_gl
);
304 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
305 switches::kEnableGPUServiceTracing
)) {
311 GLApi
* GetCurrentGLApi() {
312 return g_current_gl_context_tls
->Get();
315 void SetGLApi(GLApi
* api
) {
316 g_current_gl_context_tls
->Set(api
);
319 void SetGLToRealGLApi() {
323 void SetGLApiToNoContext() {
324 SetGLApi(g_no_context_gl
);
327 const GLVersionInfo
* GetGLVersionInfo() {
328 return g_version_info
;
331 void InitializeDynamicGLBindingsGL(GLContext
* context
) {
332 g_driver_gl
.InitializeCustomDynamicBindings(context
);
333 DCHECK(context
&& context
->IsCurrent(NULL
) && !g_version_info
);
334 g_version_info
= new GLVersionInfo(
335 context
->GetGLVersion().c_str(),
336 context
->GetGLRenderer().c_str(),
337 context
->GetExtensions().c_str());
340 void InitializeDebugGLBindingsGL() {
341 g_driver_gl
.InitializeDebugBindings();
344 void InitializeNullDrawGLBindingsGL() {
345 g_driver_gl
.InitializeNullDrawBindings();
348 bool HasInitializedNullDrawGLBindingsGL() {
349 return g_driver_gl
.HasInitializedNullDrawBindings();
352 bool SetNullDrawGLBindingsEnabledGL(bool enabled
) {
353 return g_driver_gl
.SetNullDrawBindingsEnabled(enabled
);
356 void ClearGLBindingsGL() {
365 if (g_no_context_gl
) {
366 delete g_no_context_gl
;
367 g_no_context_gl
= NULL
;
370 g_driver_gl
.ClearBindings();
371 if (g_current_gl_context_tls
) {
372 delete g_current_gl_context_tls
;
373 g_current_gl_context_tls
= NULL
;
375 if (g_version_info
) {
376 delete g_version_info
;
377 g_version_info
= NULL
;
385 if (GetCurrentGLApi() == this)
389 GLApiBase::GLApiBase()
393 GLApiBase::~GLApiBase() {
396 void GLApiBase::InitializeBase(DriverGL
* driver
) {
400 RealGLApi::RealGLApi() {
403 RealGLApi::~RealGLApi() {
406 void RealGLApi::Initialize(DriverGL
* driver
) {
407 InitializeBase(driver
);
410 void RealGLApi::glFlushFn() {
411 GLApiBase::glFlushFn();
414 void RealGLApi::glFinishFn() {
415 GLApiBase::glFinishFn();
418 TraceGLApi::~TraceGLApi() {
421 NoContextGLApi::NoContextGLApi() {
424 NoContextGLApi::~NoContextGLApi() {
427 VirtualGLApi::VirtualGLApi()
428 : real_context_(NULL
),
429 current_context_(NULL
) {
432 VirtualGLApi::~VirtualGLApi() {
435 void VirtualGLApi::Initialize(DriverGL
* driver
, GLContext
* real_context
) {
436 InitializeBase(driver
);
437 real_context_
= real_context
;
439 DCHECK(real_context
->IsCurrent(NULL
));
440 std::string ext_string
= real_context
->GetExtensions();
441 std::vector
<std::string
> ext
;
442 Tokenize(ext_string
, " ", &ext
);
444 std::vector
<std::string
>::iterator it
;
445 // We can't support GL_EXT_occlusion_query_boolean which is
446 // based on GL_ARB_occlusion_query without a lot of work virtualizing
448 it
= std::find(ext
.begin(), ext
.end(), "GL_EXT_occlusion_query_boolean");
452 extensions_
= JoinString(ext
, " ");
455 bool VirtualGLApi::MakeCurrent(GLContext
* virtual_context
, GLSurface
* surface
) {
456 bool switched_contexts
= g_current_gl_context_tls
->Get() != this;
457 GLSurface
* current_surface
= GLSurface::GetCurrent();
458 if (switched_contexts
|| surface
!= current_surface
) {
459 // MakeCurrent 'lite' path that avoids potentially expensive MakeCurrent()
460 // calls if the GLSurface uses the same underlying surface or renders to
462 if (switched_contexts
|| !current_surface
||
463 !virtual_context
->IsCurrent(surface
)) {
464 if (!real_context_
->MakeCurrent(surface
)) {
470 bool state_dirtied_externally
= real_context_
->GetStateWasDirtiedExternally();
471 real_context_
->SetStateWasDirtiedExternally(false);
473 DCHECK_EQ(real_context_
, GLContext::GetRealCurrent());
474 DCHECK(real_context_
->IsCurrent(NULL
));
475 DCHECK(virtual_context
->IsCurrent(surface
));
477 if (state_dirtied_externally
|| switched_contexts
||
478 virtual_context
!= current_context_
) {
480 GLenum error
= glGetErrorFn();
481 // Accepting a context loss error here enables using debug mode to work on
482 // context loss handling in virtual context mode.
483 // There should be no other errors from the previous context leaking into
485 DCHECK(error
== GL_NO_ERROR
|| error
== GL_CONTEXT_LOST_KHR
);
488 // Set all state that is different from the real state
489 GLApi
* temp
= GetCurrentGLApi();
491 if (virtual_context
->GetGLStateRestorer()->IsInitialized()) {
492 virtual_context
->GetGLStateRestorer()->RestoreState(
493 (current_context_
&& !state_dirtied_externally
&& !switched_contexts
)
494 ? current_context_
->GetGLStateRestorer()
498 current_context_
= virtual_context
;
502 virtual_context
->SetCurrent(surface
);
503 if (!surface
->OnMakeCurrent(virtual_context
)) {
504 LOG(ERROR
) << "Could not make GLSurface current.";
510 void VirtualGLApi::OnReleaseVirtuallyCurrent(GLContext
* virtual_context
) {
511 if (current_context_
== virtual_context
)
512 current_context_
= NULL
;
515 const GLubyte
* VirtualGLApi::glGetStringFn(GLenum name
) {
518 return reinterpret_cast<const GLubyte
*>(extensions_
.c_str());
520 return driver_
->fn
.glGetStringFn(name
);
524 void VirtualGLApi::glFlushFn() {
525 GLApiBase::glFlushFn();
528 void VirtualGLApi::glFinishFn() {
529 GLApiBase::glFinishFn();
532 ScopedSetGLToRealGLApi::ScopedSetGLToRealGLApi()
533 : old_gl_api_(GetCurrentGLApi()) {
537 ScopedSetGLToRealGLApi::~ScopedSetGLToRealGLApi() {
538 SetGLApi(old_gl_api_
);