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_split.h"
12 #include "base/strings/string_util.h"
13 #include "ui/gl/gl_context.h"
14 #include "ui/gl/gl_implementation.h"
15 #include "ui/gl/gl_state_restorer.h"
16 #include "ui/gl/gl_surface.h"
17 #include "ui/gl/gl_switches.h"
18 #include "ui/gl/gl_version_info.h"
22 // The GL Api being used. This could be g_real_gl or gl_trace_gl
23 static GLApi
* g_gl
= NULL
;
24 // A GL Api that calls directly into the driver.
25 static RealGLApi
* g_real_gl
= NULL
;
26 // A GL Api that does nothing but warn about illegal GL calls without a context
28 static NoContextGLApi
* g_no_context_gl
= NULL
;
29 // A GL Api that calls TRACE and then calls another GL api.
30 static TraceGLApi
* g_trace_gl
= NULL
;
31 // GL version used when initializing dynamic bindings.
32 static GLVersionInfo
* g_version_info
= NULL
;
36 static inline GLenum
GetInternalFormat(GLenum internal_format
) {
37 if (gfx::GetGLImplementation() != gfx::kGLImplementationEGLGLES2
) {
38 if (internal_format
== GL_BGRA_EXT
|| internal_format
== GL_BGRA8_EXT
)
41 return internal_format
;
44 // TODO(epenner): Could the above function be merged into this and removed?
45 static inline GLenum
GetTexInternalFormat(GLenum internal_format
,
48 GLenum gl_internal_format
= GetInternalFormat(internal_format
);
50 // g_version_info must be initialized when this function is bound.
51 DCHECK(gfx::g_version_info
);
52 if (gfx::g_version_info
->is_es3
) {
53 if (internal_format
== GL_RED_EXT
) {
54 // GL_EXT_texture_rg case in ES2.
56 case GL_UNSIGNED_BYTE
:
57 gl_internal_format
= GL_R8_EXT
;
59 case GL_HALF_FLOAT_OES
:
60 gl_internal_format
= GL_R16F_EXT
;
63 gl_internal_format
= GL_R32F_EXT
;
69 return gl_internal_format
;
70 } else if (internal_format
== GL_RG_EXT
) {
71 // GL_EXT_texture_rg case in ES2.
73 case GL_UNSIGNED_BYTE
:
74 gl_internal_format
= GL_RG8_EXT
;
76 case GL_HALF_FLOAT_OES
:
77 gl_internal_format
= GL_RG16F_EXT
;
80 gl_internal_format
= GL_RG32F_EXT
;
86 return gl_internal_format
;
90 if (type
== GL_FLOAT
&& gfx::g_version_info
->is_angle
&&
91 gfx::g_version_info
->is_es
&& gfx::g_version_info
->major_version
== 2) {
92 // It's possible that the texture is using a sized internal format, and
93 // ANGLE exposing GLES2 API doesn't support those.
94 // TODO(oetuaho@nvidia.com): Remove these conversions once ANGLE has the
96 // http://code.google.com/p/angleproject/issues/detail?id=556
99 gl_internal_format
= GL_RGBA
;
102 gl_internal_format
= GL_RGB
;
109 if (gfx::g_version_info
->is_es
)
110 return gl_internal_format
;
112 if (type
== GL_FLOAT
) {
113 switch (internal_format
) {
114 // We need to map all the unsized internal formats from ES2 clients.
116 gl_internal_format
= GL_RGBA32F_ARB
;
119 gl_internal_format
= GL_RGB32F_ARB
;
121 case GL_LUMINANCE_ALPHA
:
122 gl_internal_format
= GL_LUMINANCE_ALPHA32F_ARB
;
125 gl_internal_format
= GL_LUMINANCE32F_ARB
;
128 gl_internal_format
= GL_ALPHA32F_ARB
;
131 // We can't assert here because if the client context is ES3,
132 // all sized internal_format will reach here.
135 } else if (type
== GL_HALF_FLOAT_OES
) {
136 switch (internal_format
) {
138 gl_internal_format
= GL_RGBA16F_ARB
;
141 gl_internal_format
= GL_RGB16F_ARB
;
143 case GL_LUMINANCE_ALPHA
:
144 gl_internal_format
= GL_LUMINANCE_ALPHA16F_ARB
;
147 gl_internal_format
= GL_LUMINANCE16F_ARB
;
150 gl_internal_format
= GL_ALPHA16F_ARB
;
157 return gl_internal_format
;
160 static inline GLenum
GetTexType(GLenum type
) {
161 if (gfx::GetGLImplementation() != gfx::kGLImplementationEGLGLES2
) {
162 if (type
== GL_HALF_FLOAT_OES
)
163 return GL_HALF_FLOAT_ARB
;
168 static void GL_BINDING_CALL
CustomTexImage2D(
169 GLenum target
, GLint level
, GLint internalformat
,
170 GLsizei width
, GLsizei height
, GLint border
, GLenum format
, GLenum type
,
171 const void* pixels
) {
172 GLenum gl_internal_format
= GetTexInternalFormat(
173 internalformat
, format
, type
);
174 GLenum gl_type
= GetTexType(type
);
175 g_driver_gl
.orig_fn
.glTexImage2DFn(
176 target
, level
, gl_internal_format
, width
, height
, border
, format
, gl_type
,
180 static void GL_BINDING_CALL
CustomTexSubImage2D(
181 GLenum target
, GLint level
, GLint xoffset
, GLint yoffset
, GLsizei width
,
182 GLsizei height
, GLenum format
, GLenum type
, const void* pixels
) {
183 GLenum gl_type
= GetTexType(type
);
184 g_driver_gl
.orig_fn
.glTexSubImage2DFn(
185 target
, level
, xoffset
, yoffset
, width
, height
, format
, gl_type
, pixels
);
188 static void GL_BINDING_CALL
CustomTexStorage2DEXT(
189 GLenum target
, GLsizei levels
, GLenum internalformat
, GLsizei width
,
191 GLenum gl_internal_format
= GetInternalFormat(internalformat
);
192 g_driver_gl
.orig_fn
.glTexStorage2DEXTFn(
193 target
, levels
, gl_internal_format
, width
, height
);
196 static void GL_BINDING_CALL
CustomRenderbufferStorageEXT(
197 GLenum target
, GLenum internalformat
, GLsizei width
, GLsizei height
) {
198 GLenum gl_internal_format
= GetInternalFormat(internalformat
);
199 g_driver_gl
.orig_fn
.glRenderbufferStorageEXTFn(
200 target
, gl_internal_format
, width
, height
);
203 // The ANGLE and IMG variants of glRenderbufferStorageMultisample currently do
204 // not support BGRA render buffers so only the EXT one is customized. If
205 // GL_CHROMIUM_renderbuffer_format_BGRA8888 support is added to ANGLE then the
206 // ANGLE version should also be customized.
207 static void GL_BINDING_CALL
CustomRenderbufferStorageMultisampleEXT(
208 GLenum target
, GLsizei samples
, GLenum internalformat
, GLsizei width
,
210 GLenum gl_internal_format
= GetInternalFormat(internalformat
);
211 g_driver_gl
.orig_fn
.glRenderbufferStorageMultisampleEXTFn(
212 target
, samples
, gl_internal_format
, width
, height
);
215 } // anonymous namespace
217 void DriverGL::InitializeCustomDynamicBindings(GLContext
* context
) {
218 InitializeDynamicBindings(context
);
220 DCHECK(orig_fn
.glTexImage2DFn
== NULL
);
221 orig_fn
.glTexImage2DFn
= fn
.glTexImage2DFn
;
223 reinterpret_cast<glTexImage2DProc
>(CustomTexImage2D
);
225 DCHECK(orig_fn
.glTexSubImage2DFn
== NULL
);
226 orig_fn
.glTexSubImage2DFn
= fn
.glTexSubImage2DFn
;
227 fn
.glTexSubImage2DFn
=
228 reinterpret_cast<glTexSubImage2DProc
>(CustomTexSubImage2D
);
230 DCHECK(orig_fn
.glTexStorage2DEXTFn
== NULL
);
231 orig_fn
.glTexStorage2DEXTFn
= fn
.glTexStorage2DEXTFn
;
232 fn
.glTexStorage2DEXTFn
=
233 reinterpret_cast<glTexStorage2DEXTProc
>(CustomTexStorage2DEXT
);
235 DCHECK(orig_fn
.glRenderbufferStorageEXTFn
== NULL
);
236 orig_fn
.glRenderbufferStorageEXTFn
= fn
.glRenderbufferStorageEXTFn
;
237 fn
.glRenderbufferStorageEXTFn
=
238 reinterpret_cast<glRenderbufferStorageEXTProc
>(
239 CustomRenderbufferStorageEXT
);
241 DCHECK(orig_fn
.glRenderbufferStorageMultisampleEXTFn
== NULL
);
242 orig_fn
.glRenderbufferStorageMultisampleEXTFn
=
243 fn
.glRenderbufferStorageMultisampleEXTFn
;
244 fn
.glRenderbufferStorageMultisampleEXTFn
=
245 reinterpret_cast<glRenderbufferStorageMultisampleEXTProc
>(
246 CustomRenderbufferStorageMultisampleEXT
);
249 static void GL_BINDING_CALL
NullDrawClearFn(GLbitfield mask
) {
250 if (!g_driver_gl
.null_draw_bindings_enabled
)
251 g_driver_gl
.orig_fn
.glClearFn(mask
);
254 static void GL_BINDING_CALL
255 NullDrawDrawArraysFn(GLenum mode
, GLint first
, GLsizei count
) {
256 if (!g_driver_gl
.null_draw_bindings_enabled
)
257 g_driver_gl
.orig_fn
.glDrawArraysFn(mode
, first
, count
);
260 static void GL_BINDING_CALL
NullDrawDrawElementsFn(GLenum mode
,
263 const void* indices
) {
264 if (!g_driver_gl
.null_draw_bindings_enabled
)
265 g_driver_gl
.orig_fn
.glDrawElementsFn(mode
, count
, type
, indices
);
268 void DriverGL::InitializeNullDrawBindings() {
269 DCHECK(orig_fn
.glClearFn
== NULL
);
270 orig_fn
.glClearFn
= fn
.glClearFn
;
271 fn
.glClearFn
= NullDrawClearFn
;
273 DCHECK(orig_fn
.glDrawArraysFn
== NULL
);
274 orig_fn
.glDrawArraysFn
= fn
.glDrawArraysFn
;
275 fn
.glDrawArraysFn
= NullDrawDrawArraysFn
;
277 DCHECK(orig_fn
.glDrawElementsFn
== NULL
);
278 orig_fn
.glDrawElementsFn
= fn
.glDrawElementsFn
;
279 fn
.glDrawElementsFn
= NullDrawDrawElementsFn
;
281 null_draw_bindings_enabled
= true;
284 bool DriverGL::HasInitializedNullDrawBindings() {
285 return orig_fn
.glClearFn
!= NULL
&& orig_fn
.glDrawArraysFn
!= NULL
&&
286 orig_fn
.glDrawElementsFn
!= NULL
;
289 bool DriverGL::SetNullDrawBindingsEnabled(bool enabled
) {
290 DCHECK(orig_fn
.glClearFn
!= NULL
);
291 DCHECK(orig_fn
.glDrawArraysFn
!= NULL
);
292 DCHECK(orig_fn
.glDrawElementsFn
!= NULL
);
294 bool before
= null_draw_bindings_enabled
;
295 null_draw_bindings_enabled
= enabled
;
299 void InitializeStaticGLBindingsGL() {
300 g_current_gl_context_tls
= new base::ThreadLocalPointer
<GLApi
>;
301 g_driver_gl
.InitializeStaticBindings();
303 g_real_gl
= new RealGLApi();
304 g_trace_gl
= new TraceGLApi(g_real_gl
);
305 g_no_context_gl
= new NoContextGLApi();
307 g_real_gl
->Initialize(&g_driver_gl
);
309 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
310 switches::kEnableGPUServiceTracing
)) {
316 GLApi
* GetCurrentGLApi() {
317 return g_current_gl_context_tls
? g_current_gl_context_tls
->Get() : nullptr;
320 void SetGLApi(GLApi
* api
) {
321 g_current_gl_context_tls
->Set(api
);
324 void SetGLToRealGLApi() {
328 void SetGLApiToNoContext() {
329 SetGLApi(g_no_context_gl
);
332 const GLVersionInfo
* GetGLVersionInfo() {
333 return g_version_info
;
336 void InitializeDynamicGLBindingsGL(GLContext
* context
) {
337 g_real_gl
->InitializeFilteredExtensions();
338 g_driver_gl
.InitializeCustomDynamicBindings(context
);
339 DCHECK(context
&& context
->IsCurrent(NULL
) && !g_version_info
);
340 g_version_info
= new GLVersionInfo(
341 context
->GetGLVersion().c_str(),
342 context
->GetGLRenderer().c_str(),
343 context
->GetExtensions().c_str());
346 void InitializeDebugGLBindingsGL() {
347 g_driver_gl
.InitializeDebugBindings();
350 void InitializeNullDrawGLBindingsGL() {
351 g_driver_gl
.InitializeNullDrawBindings();
354 bool HasInitializedNullDrawGLBindingsGL() {
355 return g_driver_gl
.HasInitializedNullDrawBindings();
358 bool SetNullDrawGLBindingsEnabledGL(bool enabled
) {
359 return g_driver_gl
.SetNullDrawBindingsEnabled(enabled
);
362 void ClearGLBindingsGL() {
371 if (g_no_context_gl
) {
372 delete g_no_context_gl
;
373 g_no_context_gl
= NULL
;
376 g_driver_gl
.ClearBindings();
377 if (g_current_gl_context_tls
) {
378 delete g_current_gl_context_tls
;
379 g_current_gl_context_tls
= NULL
;
381 if (g_version_info
) {
382 delete g_version_info
;
383 g_version_info
= NULL
;
391 if (GetCurrentGLApi() == this)
395 GLApiBase::GLApiBase()
399 GLApiBase::~GLApiBase() {
402 void GLApiBase::InitializeBase(DriverGL
* driver
) {
406 RealGLApi::RealGLApi() {
408 filtered_exts_initialized_
= false;
412 RealGLApi::~RealGLApi() {
415 void RealGLApi::Initialize(DriverGL
* driver
) {
416 InitializeWithCommandLine(driver
, base::CommandLine::ForCurrentProcess());
419 void RealGLApi::InitializeWithCommandLine(DriverGL
* driver
,
420 base::CommandLine
* command_line
) {
421 DCHECK(command_line
);
422 InitializeBase(driver
);
424 const std::string disabled_extensions
= command_line
->GetSwitchValueASCII(
425 switches::kDisableGLExtensions
);
426 if (!disabled_extensions
.empty()) {
427 disabled_exts_
= base::SplitString(
428 disabled_extensions
, ", ;",
429 base::KEEP_WHITESPACE
, base::SPLIT_WANT_NONEMPTY
);
433 void RealGLApi::glGetIntegervFn(GLenum pname
, GLint
* params
) {
434 if (pname
== GL_NUM_EXTENSIONS
&& disabled_exts_
.size()) {
436 DCHECK(filtered_exts_initialized_
);
438 *params
= static_cast<GLint
>(filtered_exts_
.size());
440 GLApiBase::glGetIntegervFn(pname
, params
);
444 const GLubyte
* RealGLApi::glGetStringFn(GLenum name
) {
445 if (name
== GL_EXTENSIONS
&& disabled_exts_
.size()) {
447 DCHECK(filtered_exts_initialized_
);
449 return reinterpret_cast<const GLubyte
*>(filtered_exts_str_
.c_str());
451 return GLApiBase::glGetStringFn(name
);
454 const GLubyte
* RealGLApi::glGetStringiFn(GLenum name
, GLuint index
) {
455 if (name
== GL_EXTENSIONS
&& disabled_exts_
.size()) {
457 DCHECK(filtered_exts_initialized_
);
459 if (index
>= filtered_exts_
.size()) {
462 return reinterpret_cast<const GLubyte
*>(filtered_exts_
[index
].c_str());
464 return GLApiBase::glGetStringiFn(name
, index
);
467 void RealGLApi::glFlushFn() {
468 GLApiBase::glFlushFn();
471 void RealGLApi::glFinishFn() {
472 GLApiBase::glFinishFn();
475 void RealGLApi::InitializeFilteredExtensions() {
476 if (disabled_exts_
.size()) {
477 filtered_exts_
.clear();
478 if (gfx::GetGLImplementation() !=
479 gfx::kGLImplementationDesktopGLCoreProfile
) {
481 FilterGLExtensionList(reinterpret_cast<const char*>(
482 GLApiBase::glGetStringFn(GL_EXTENSIONS
)),
484 base::SplitString(filtered_exts_str_
, ' ', &filtered_exts_
);
486 GLint num_extensions
= 0;
487 GLApiBase::glGetIntegervFn(GL_NUM_EXTENSIONS
, &num_extensions
);
488 for (GLint i
= 0; i
< num_extensions
; ++i
) {
489 const char* gl_extension
= reinterpret_cast<const char*>(
490 GLApiBase::glGetStringiFn(GL_EXTENSIONS
, i
));
491 DCHECK(gl_extension
!= NULL
);
492 if (std::find(disabled_exts_
.begin(), disabled_exts_
.end(),
493 gl_extension
) == disabled_exts_
.end()) {
494 filtered_exts_
.push_back(gl_extension
);
497 filtered_exts_str_
= base::JoinString(filtered_exts_
, " ");
500 filtered_exts_initialized_
= true;
505 TraceGLApi::~TraceGLApi() {
508 NoContextGLApi::NoContextGLApi() {
511 NoContextGLApi::~NoContextGLApi() {
514 VirtualGLApi::VirtualGLApi()
515 : real_context_(NULL
),
516 current_context_(NULL
) {
519 VirtualGLApi::~VirtualGLApi() {
522 void VirtualGLApi::Initialize(DriverGL
* driver
, GLContext
* real_context
) {
523 InitializeBase(driver
);
524 real_context_
= real_context
;
526 DCHECK(real_context
->IsCurrent(NULL
));
527 extensions_
= real_context
->GetExtensions();
530 bool VirtualGLApi::MakeCurrent(GLContext
* virtual_context
, GLSurface
* surface
) {
531 bool switched_contexts
= g_current_gl_context_tls
->Get() != this;
532 GLSurface
* current_surface
= GLSurface::GetCurrent();
533 if (switched_contexts
|| surface
!= current_surface
) {
534 // MakeCurrent 'lite' path that avoids potentially expensive MakeCurrent()
535 // calls if the GLSurface uses the same underlying surface or renders to
537 if (switched_contexts
|| !current_surface
||
538 !virtual_context
->IsCurrent(surface
)) {
539 if (!real_context_
->MakeCurrent(surface
)) {
545 bool state_dirtied_externally
= real_context_
->GetStateWasDirtiedExternally();
546 real_context_
->SetStateWasDirtiedExternally(false);
548 DCHECK_EQ(real_context_
, GLContext::GetRealCurrent());
549 DCHECK(real_context_
->IsCurrent(NULL
));
550 DCHECK(virtual_context
->IsCurrent(surface
));
552 if (state_dirtied_externally
|| switched_contexts
||
553 virtual_context
!= current_context_
) {
555 GLenum error
= glGetErrorFn();
556 // Accepting a context loss error here enables using debug mode to work on
557 // context loss handling in virtual context mode.
558 // There should be no other errors from the previous context leaking into
560 DCHECK(error
== GL_NO_ERROR
|| error
== GL_CONTEXT_LOST_KHR
);
563 // Set all state that is different from the real state
564 GLApi
* temp
= GetCurrentGLApi();
566 if (virtual_context
->GetGLStateRestorer()->IsInitialized()) {
567 GLStateRestorer
* virtual_state
= virtual_context
->GetGLStateRestorer();
568 GLStateRestorer
* current_state
= current_context_
?
569 current_context_
->GetGLStateRestorer() :
571 if (switched_contexts
|| virtual_context
!= current_context_
) {
573 current_state
->PauseQueries();
574 virtual_state
->ResumeQueries();
577 virtual_state
->RestoreState(
578 (current_state
&& !state_dirtied_externally
&& !switched_contexts
)
583 current_context_
= virtual_context
;
587 virtual_context
->SetCurrent(surface
);
588 if (!surface
->OnMakeCurrent(virtual_context
)) {
589 LOG(ERROR
) << "Could not make GLSurface current.";
595 void VirtualGLApi::OnReleaseVirtuallyCurrent(GLContext
* virtual_context
) {
596 if (current_context_
== virtual_context
)
597 current_context_
= NULL
;
600 const GLubyte
* VirtualGLApi::glGetStringFn(GLenum name
) {
603 return reinterpret_cast<const GLubyte
*>(extensions_
.c_str());
605 return driver_
->fn
.glGetStringFn(name
);
609 void VirtualGLApi::glFlushFn() {
610 GLApiBase::glFlushFn();
613 void VirtualGLApi::glFinishFn() {
614 GLApiBase::glFinishFn();
617 ScopedSetGLToRealGLApi::ScopedSetGLToRealGLApi()
618 : old_gl_api_(GetCurrentGLApi()) {
622 ScopedSetGLToRealGLApi::~ScopedSetGLToRealGLApi() {
623 SetGLApi(old_gl_api_
);