Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / ui / gl / gl_gl_api_implementation.cc
blobf706c848dbd776f1785bfa0139ed1eef670713ac
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"
7 #include <algorithm>
8 #include <vector>
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"
20 namespace gfx {
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
27 // current.
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;
34 namespace {
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)
39 return GL_RGBA8;
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,
46 GLenum format,
47 GLenum type) {
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.
55 switch (type) {
56 case GL_UNSIGNED_BYTE:
57 gl_internal_format = GL_R8_EXT;
58 break;
59 case GL_HALF_FLOAT_OES:
60 gl_internal_format = GL_R16F_EXT;
61 break;
62 case GL_FLOAT:
63 gl_internal_format = GL_R32F_EXT;
64 break;
65 default:
66 NOTREACHED();
67 break;
69 return gl_internal_format;
70 } else if (internal_format == GL_RG_EXT) {
71 // GL_EXT_texture_rg case in ES2.
72 switch (type) {
73 case GL_UNSIGNED_BYTE:
74 gl_internal_format = GL_RG8_EXT;
75 break;
76 case GL_HALF_FLOAT_OES:
77 gl_internal_format = GL_RG16F_EXT;
78 break;
79 case GL_FLOAT:
80 gl_internal_format = GL_RG32F_EXT;
81 break;
82 default:
83 NOTREACHED();
84 break;
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
95 // support.
96 // http://code.google.com/p/angleproject/issues/detail?id=556
97 switch (format) {
98 case GL_RGBA:
99 gl_internal_format = GL_RGBA;
100 break;
101 case GL_RGB:
102 gl_internal_format = GL_RGB;
103 break;
104 default:
105 break;
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.
115 case GL_RGBA:
116 gl_internal_format = GL_RGBA32F_ARB;
117 break;
118 case GL_RGB:
119 gl_internal_format = GL_RGB32F_ARB;
120 break;
121 case GL_LUMINANCE_ALPHA:
122 gl_internal_format = GL_LUMINANCE_ALPHA32F_ARB;
123 break;
124 case GL_LUMINANCE:
125 gl_internal_format = GL_LUMINANCE32F_ARB;
126 break;
127 case GL_ALPHA:
128 gl_internal_format = GL_ALPHA32F_ARB;
129 break;
130 default:
131 // We can't assert here because if the client context is ES3,
132 // all sized internal_format will reach here.
133 break;
135 } else if (type == GL_HALF_FLOAT_OES) {
136 switch (internal_format) {
137 case GL_RGBA:
138 gl_internal_format = GL_RGBA16F_ARB;
139 break;
140 case GL_RGB:
141 gl_internal_format = GL_RGB16F_ARB;
142 break;
143 case GL_LUMINANCE_ALPHA:
144 gl_internal_format = GL_LUMINANCE_ALPHA16F_ARB;
145 break;
146 case GL_LUMINANCE:
147 gl_internal_format = GL_LUMINANCE16F_ARB;
148 break;
149 case GL_ALPHA:
150 gl_internal_format = GL_ALPHA16F_ARB;
151 break;
152 default:
153 NOTREACHED();
154 break;
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;
165 return type;
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,
177 pixels);
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,
190 GLsizei height) {
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,
209 GLsizei height) {
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;
222 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,
261 GLsizei count,
262 GLenum type,
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;
296 return before;
299 void InitializeStaticGLBindingsGL() {
300 g_current_gl_context_tls = new base::ThreadLocalPointer<GLApi>;
301 g_driver_gl.InitializeStaticBindings();
302 if (!g_real_gl) {
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);
308 g_gl = g_real_gl;
309 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
310 switches::kEnableGPUServiceTracing)) {
311 g_gl = g_trace_gl;
313 SetGLToRealGLApi();
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() {
325 SetGLApi(g_gl);
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() {
363 if (g_real_gl) {
364 delete g_real_gl;
365 g_real_gl = NULL;
367 if (g_trace_gl) {
368 delete g_trace_gl;
369 g_trace_gl = NULL;
371 if (g_no_context_gl) {
372 delete g_no_context_gl;
373 g_no_context_gl = NULL;
375 g_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;
387 GLApi::GLApi() {
390 GLApi::~GLApi() {
391 if (GetCurrentGLApi() == this)
392 SetGLApi(NULL);
395 GLApiBase::GLApiBase()
396 : driver_(NULL) {
399 GLApiBase::~GLApiBase() {
402 void GLApiBase::InitializeBase(DriverGL* driver) {
403 driver_ = driver;
406 RealGLApi::RealGLApi() {
407 #if DCHECK_IS_ON()
408 filtered_exts_initialized_ = false;
409 #endif
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()) {
435 #if DCHECK_IS_ON()
436 DCHECK(filtered_exts_initialized_);
437 #endif
438 *params = static_cast<GLint>(filtered_exts_.size());
439 } else {
440 GLApiBase::glGetIntegervFn(pname, params);
444 const GLubyte* RealGLApi::glGetStringFn(GLenum name) {
445 if (name == GL_EXTENSIONS && disabled_exts_.size()) {
446 #if DCHECK_IS_ON()
447 DCHECK(filtered_exts_initialized_);
448 #endif
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()) {
456 #if DCHECK_IS_ON()
457 DCHECK(filtered_exts_initialized_);
458 #endif
459 if (index >= filtered_exts_.size()) {
460 return NULL;
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) {
480 filtered_exts_str_ =
481 FilterGLExtensionList(reinterpret_cast<const char*>(
482 GLApiBase::glGetStringFn(GL_EXTENSIONS)),
483 disabled_exts_);
484 base::SplitString(filtered_exts_str_, ' ', &filtered_exts_);
485 } else {
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_, " ");
499 #if DCHECK_IS_ON()
500 filtered_exts_initialized_ = true;
501 #endif
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
536 // an FBO.
537 if (switched_contexts || !current_surface ||
538 !virtual_context->IsCurrent(surface)) {
539 if (!real_context_->MakeCurrent(surface)) {
540 return false;
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_) {
554 #if DCHECK_IS_ON()
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
559 // the new context.
560 DCHECK(error == GL_NO_ERROR || error == GL_CONTEXT_LOST_KHR);
561 #endif
563 // Set all state that is different from the real state
564 GLApi* temp = GetCurrentGLApi();
565 SetGLToRealGLApi();
566 if (virtual_context->GetGLStateRestorer()->IsInitialized()) {
567 GLStateRestorer* virtual_state = virtual_context->GetGLStateRestorer();
568 GLStateRestorer* current_state = current_context_ ?
569 current_context_->GetGLStateRestorer() :
570 nullptr;
571 if (switched_contexts || virtual_context != current_context_) {
572 if (current_state)
573 current_state->PauseQueries();
574 virtual_state->ResumeQueries();
577 virtual_state->RestoreState(
578 (current_state && !state_dirtied_externally && !switched_contexts)
579 ? current_state
580 : NULL);
582 SetGLApi(temp);
583 current_context_ = virtual_context;
585 SetGLApi(this);
587 virtual_context->SetCurrent(surface);
588 if (!surface->OnMakeCurrent(virtual_context)) {
589 LOG(ERROR) << "Could not make GLSurface current.";
590 return false;
592 return true;
595 void VirtualGLApi::OnReleaseVirtuallyCurrent(GLContext* virtual_context) {
596 if (current_context_ == virtual_context)
597 current_context_ = NULL;
600 const GLubyte* VirtualGLApi::glGetStringFn(GLenum name) {
601 switch (name) {
602 case GL_EXTENSIONS:
603 return reinterpret_cast<const GLubyte*>(extensions_.c_str());
604 default:
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()) {
619 SetGLToRealGLApi();
622 ScopedSetGLToRealGLApi::~ScopedSetGLToRealGLApi() {
623 SetGLApi(old_gl_api_);
626 } // namespace gfx