Remove chromeos==0 blacklist for test_isolation_mode.
[chromium-blink-merge.git] / ui / gl / gl_gl_api_implementation.cc
bloba8d4dbe0c0de5ecda49b59c5f38fc26a214ec453
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 (format == GL_RED_EXT) {
54 switch (type) {
55 case GL_UNSIGNED_BYTE:
56 gl_internal_format = GL_R8_EXT;
57 break;
58 case GL_HALF_FLOAT_OES:
59 gl_internal_format = GL_R16F_EXT;
60 break;
61 case GL_FLOAT:
62 gl_internal_format = GL_R32F_EXT;
63 break;
64 default:
65 NOTREACHED();
66 break;
68 return gl_internal_format;
69 } else if (format == GL_RG_EXT) {
70 switch (type) {
71 case GL_UNSIGNED_BYTE:
72 gl_internal_format = GL_RG8_EXT;
73 break;
74 case GL_HALF_FLOAT_OES:
75 gl_internal_format = GL_RG16F_EXT;
76 break;
77 case GL_FLOAT:
78 gl_internal_format = GL_RG32F_EXT;
79 break;
80 default:
81 NOTREACHED();
82 break;
84 return gl_internal_format;
88 if (type == GL_FLOAT && gfx::g_version_info->is_angle &&
89 gfx::g_version_info->is_es && gfx::g_version_info->major_version == 2) {
90 // It's possible that the texture is using a sized internal format, and
91 // ANGLE exposing GLES2 API doesn't support those.
92 // TODO(oetuaho@nvidia.com): Remove these conversions once ANGLE has the
93 // support.
94 // http://code.google.com/p/angleproject/issues/detail?id=556
95 switch (format) {
96 case GL_RGBA:
97 gl_internal_format = GL_RGBA;
98 break;
99 case GL_RGB:
100 gl_internal_format = GL_RGB;
101 break;
102 default:
103 break;
107 if (gfx::g_version_info->is_es)
108 return gl_internal_format;
110 if (type == GL_FLOAT) {
111 switch (format) {
112 case GL_RGBA:
113 gl_internal_format = GL_RGBA32F_ARB;
114 break;
115 case GL_RGB:
116 gl_internal_format = GL_RGB32F_ARB;
117 break;
118 case GL_LUMINANCE_ALPHA:
119 gl_internal_format = GL_LUMINANCE_ALPHA32F_ARB;
120 break;
121 case GL_LUMINANCE:
122 gl_internal_format = GL_LUMINANCE32F_ARB;
123 break;
124 case GL_ALPHA:
125 gl_internal_format = GL_ALPHA32F_ARB;
126 break;
127 default:
128 NOTREACHED();
129 break;
131 } else if (type == GL_HALF_FLOAT_OES) {
132 switch (format) {
133 case GL_RGBA:
134 gl_internal_format = GL_RGBA16F_ARB;
135 break;
136 case GL_RGB:
137 gl_internal_format = GL_RGB16F_ARB;
138 break;
139 case GL_LUMINANCE_ALPHA:
140 gl_internal_format = GL_LUMINANCE_ALPHA16F_ARB;
141 break;
142 case GL_LUMINANCE:
143 gl_internal_format = GL_LUMINANCE16F_ARB;
144 break;
145 case GL_ALPHA:
146 gl_internal_format = GL_ALPHA16F_ARB;
147 break;
148 default:
149 NOTREACHED();
150 break;
153 return gl_internal_format;
156 static inline GLenum GetTexType(GLenum type) {
157 if (gfx::GetGLImplementation() != gfx::kGLImplementationEGLGLES2) {
158 if (type == GL_HALF_FLOAT_OES)
159 return GL_HALF_FLOAT_ARB;
161 return type;
164 static void GL_BINDING_CALL CustomTexImage2D(
165 GLenum target, GLint level, GLint internalformat,
166 GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type,
167 const void* pixels) {
168 GLenum gl_internal_format = GetTexInternalFormat(
169 internalformat, format, type);
170 GLenum gl_type = GetTexType(type);
171 g_driver_gl.orig_fn.glTexImage2DFn(
172 target, level, gl_internal_format, width, height, border, format, gl_type,
173 pixels);
176 static void GL_BINDING_CALL CustomTexSubImage2D(
177 GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
178 GLsizei height, GLenum format, GLenum type, const void* pixels) {
179 GLenum gl_type = GetTexType(type);
180 g_driver_gl.orig_fn.glTexSubImage2DFn(
181 target, level, xoffset, yoffset, width, height, format, gl_type, pixels);
184 static void GL_BINDING_CALL CustomTexStorage2DEXT(
185 GLenum target, GLsizei levels, GLenum internalformat, GLsizei width,
186 GLsizei height) {
187 GLenum gl_internal_format = GetInternalFormat(internalformat);
188 g_driver_gl.orig_fn.glTexStorage2DEXTFn(
189 target, levels, gl_internal_format, width, height);
192 static void GL_BINDING_CALL CustomRenderbufferStorageEXT(
193 GLenum target, GLenum internalformat, GLsizei width, GLsizei height) {
194 GLenum gl_internal_format = GetInternalFormat(internalformat);
195 g_driver_gl.orig_fn.glRenderbufferStorageEXTFn(
196 target, gl_internal_format, width, height);
199 // The ANGLE and IMG variants of glRenderbufferStorageMultisample currently do
200 // not support BGRA render buffers so only the EXT one is customized. If
201 // GL_CHROMIUM_renderbuffer_format_BGRA8888 support is added to ANGLE then the
202 // ANGLE version should also be customized.
203 static void GL_BINDING_CALL CustomRenderbufferStorageMultisampleEXT(
204 GLenum target, GLsizei samples, GLenum internalformat, GLsizei width,
205 GLsizei height) {
206 GLenum gl_internal_format = GetInternalFormat(internalformat);
207 g_driver_gl.orig_fn.glRenderbufferStorageMultisampleEXTFn(
208 target, samples, gl_internal_format, width, height);
211 } // anonymous namespace
213 void DriverGL::InitializeCustomDynamicBindings(GLContext* context) {
214 InitializeDynamicBindings(context);
216 DCHECK(orig_fn.glTexImage2DFn == NULL);
217 orig_fn.glTexImage2DFn = fn.glTexImage2DFn;
218 fn.glTexImage2DFn =
219 reinterpret_cast<glTexImage2DProc>(CustomTexImage2D);
221 DCHECK(orig_fn.glTexSubImage2DFn == NULL);
222 orig_fn.glTexSubImage2DFn = fn.glTexSubImage2DFn;
223 fn.glTexSubImage2DFn =
224 reinterpret_cast<glTexSubImage2DProc>(CustomTexSubImage2D);
226 DCHECK(orig_fn.glTexStorage2DEXTFn == NULL);
227 orig_fn.glTexStorage2DEXTFn = fn.glTexStorage2DEXTFn;
228 fn.glTexStorage2DEXTFn =
229 reinterpret_cast<glTexStorage2DEXTProc>(CustomTexStorage2DEXT);
231 DCHECK(orig_fn.glRenderbufferStorageEXTFn == NULL);
232 orig_fn.glRenderbufferStorageEXTFn = fn.glRenderbufferStorageEXTFn;
233 fn.glRenderbufferStorageEXTFn =
234 reinterpret_cast<glRenderbufferStorageEXTProc>(
235 CustomRenderbufferStorageEXT);
237 DCHECK(orig_fn.glRenderbufferStorageMultisampleEXTFn == NULL);
238 orig_fn.glRenderbufferStorageMultisampleEXTFn =
239 fn.glRenderbufferStorageMultisampleEXTFn;
240 fn.glRenderbufferStorageMultisampleEXTFn =
241 reinterpret_cast<glRenderbufferStorageMultisampleEXTProc>(
242 CustomRenderbufferStorageMultisampleEXT);
245 static void GL_BINDING_CALL NullDrawClearFn(GLbitfield mask) {
246 if (!g_driver_gl.null_draw_bindings_enabled)
247 g_driver_gl.orig_fn.glClearFn(mask);
250 static void GL_BINDING_CALL
251 NullDrawDrawArraysFn(GLenum mode, GLint first, GLsizei count) {
252 if (!g_driver_gl.null_draw_bindings_enabled)
253 g_driver_gl.orig_fn.glDrawArraysFn(mode, first, count);
256 static void GL_BINDING_CALL NullDrawDrawElementsFn(GLenum mode,
257 GLsizei count,
258 GLenum type,
259 const void* indices) {
260 if (!g_driver_gl.null_draw_bindings_enabled)
261 g_driver_gl.orig_fn.glDrawElementsFn(mode, count, type, indices);
264 void DriverGL::InitializeNullDrawBindings() {
265 DCHECK(orig_fn.glClearFn == NULL);
266 orig_fn.glClearFn = fn.glClearFn;
267 fn.glClearFn = NullDrawClearFn;
269 DCHECK(orig_fn.glDrawArraysFn == NULL);
270 orig_fn.glDrawArraysFn = fn.glDrawArraysFn;
271 fn.glDrawArraysFn = NullDrawDrawArraysFn;
273 DCHECK(orig_fn.glDrawElementsFn == NULL);
274 orig_fn.glDrawElementsFn = fn.glDrawElementsFn;
275 fn.glDrawElementsFn = NullDrawDrawElementsFn;
277 null_draw_bindings_enabled = true;
280 bool DriverGL::HasInitializedNullDrawBindings() {
281 return orig_fn.glClearFn != NULL && orig_fn.glDrawArraysFn != NULL &&
282 orig_fn.glDrawElementsFn != NULL;
285 bool DriverGL::SetNullDrawBindingsEnabled(bool enabled) {
286 DCHECK(orig_fn.glClearFn != NULL);
287 DCHECK(orig_fn.glDrawArraysFn != NULL);
288 DCHECK(orig_fn.glDrawElementsFn != NULL);
290 bool before = null_draw_bindings_enabled;
291 null_draw_bindings_enabled = enabled;
292 return before;
295 void InitializeStaticGLBindingsGL() {
296 g_current_gl_context_tls = new base::ThreadLocalPointer<GLApi>;
297 g_driver_gl.InitializeStaticBindings();
298 if (!g_real_gl) {
299 g_real_gl = new RealGLApi();
300 g_trace_gl = new TraceGLApi(g_real_gl);
301 g_no_context_gl = new NoContextGLApi();
303 g_real_gl->Initialize(&g_driver_gl);
304 g_gl = g_real_gl;
305 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
306 switches::kEnableGPUServiceTracing)) {
307 g_gl = g_trace_gl;
309 SetGLToRealGLApi();
312 GLApi* GetCurrentGLApi() {
313 return g_current_gl_context_tls ? g_current_gl_context_tls->Get() : nullptr;
316 void SetGLApi(GLApi* api) {
317 g_current_gl_context_tls->Set(api);
320 void SetGLToRealGLApi() {
321 SetGLApi(g_gl);
324 void SetGLApiToNoContext() {
325 SetGLApi(g_no_context_gl);
328 const GLVersionInfo* GetGLVersionInfo() {
329 return g_version_info;
332 void InitializeDynamicGLBindingsGL(GLContext* context) {
333 g_driver_gl.InitializeCustomDynamicBindings(context);
334 DCHECK(context && context->IsCurrent(NULL) && !g_version_info);
335 g_real_gl->InitializeWithContext();
336 g_version_info = new GLVersionInfo(
337 context->GetGLVersion().c_str(),
338 context->GetGLRenderer().c_str(),
339 context->GetExtensions().c_str());
342 void InitializeDebugGLBindingsGL() {
343 g_driver_gl.InitializeDebugBindings();
346 void InitializeNullDrawGLBindingsGL() {
347 g_driver_gl.InitializeNullDrawBindings();
350 bool HasInitializedNullDrawGLBindingsGL() {
351 return g_driver_gl.HasInitializedNullDrawBindings();
354 bool SetNullDrawGLBindingsEnabledGL(bool enabled) {
355 return g_driver_gl.SetNullDrawBindingsEnabled(enabled);
358 void ClearGLBindingsGL() {
359 if (g_real_gl) {
360 delete g_real_gl;
361 g_real_gl = NULL;
363 if (g_trace_gl) {
364 delete g_trace_gl;
365 g_trace_gl = NULL;
367 if (g_no_context_gl) {
368 delete g_no_context_gl;
369 g_no_context_gl = NULL;
371 g_gl = NULL;
372 g_driver_gl.ClearBindings();
373 if (g_current_gl_context_tls) {
374 delete g_current_gl_context_tls;
375 g_current_gl_context_tls = NULL;
377 if (g_version_info) {
378 delete g_version_info;
379 g_version_info = NULL;
383 GLApi::GLApi() {
386 GLApi::~GLApi() {
387 if (GetCurrentGLApi() == this)
388 SetGLApi(NULL);
391 GLApiBase::GLApiBase()
392 : driver_(NULL) {
395 GLApiBase::~GLApiBase() {
398 void GLApiBase::InitializeBase(DriverGL* driver) {
399 driver_ = driver;
402 RealGLApi::RealGLApi() {
405 RealGLApi::~RealGLApi() {
408 void RealGLApi::Initialize(DriverGL* driver) {
409 InitializeWithCommandLine(driver, base::CommandLine::ForCurrentProcess());
412 void RealGLApi::InitializeWithCommandLine(DriverGL* driver,
413 base::CommandLine* command_line) {
414 DCHECK(command_line);
415 InitializeBase(driver);
417 const std::string disabled_extensions = command_line->GetSwitchValueASCII(
418 switches::kDisableGLExtensions);
419 if (!disabled_extensions.empty()) {
420 Tokenize(disabled_extensions, ", ;", &disabled_exts_);
424 void RealGLApi::InitializeWithContext() {
425 InitializeFilteredExtensions();
428 void RealGLApi::glGetIntegervFn(GLenum pname, GLint* params) {
429 if (!filtered_exts_.empty() && pname == GL_NUM_EXTENSIONS) {
430 *params = static_cast<GLint>(filtered_exts_.size());
431 } else {
432 GLApiBase::glGetIntegervFn(pname, params);
436 const GLubyte* RealGLApi::glGetStringFn(GLenum name) {
437 if (!filtered_exts_.empty() && name == GL_EXTENSIONS) {
438 return reinterpret_cast<const GLubyte*>(filtered_exts_str_.c_str());
440 return GLApiBase::glGetStringFn(name);
443 const GLubyte* RealGLApi::glGetStringiFn(GLenum name, GLuint index) {
444 if (!filtered_exts_str_.empty() && name == GL_EXTENSIONS) {
445 if (index >= filtered_exts_.size()) {
446 return NULL;
448 return reinterpret_cast<const GLubyte*>(filtered_exts_[index].c_str());
450 return GLApiBase::glGetStringiFn(name, index);
453 void RealGLApi::glFlushFn() {
454 GLApiBase::glFlushFn();
457 void RealGLApi::glFinishFn() {
458 GLApiBase::glFinishFn();
461 void RealGLApi::InitializeFilteredExtensions() {
462 if (!disabled_exts_.empty() && filtered_exts_.empty()) {
463 DCHECK(filtered_exts_.empty() && filtered_exts_str_.empty());
464 // Fill in filtered_exts_ vector first.
465 if (gfx::GetGLImplementation() !=
466 gfx::kGLImplementationDesktopGLCoreProfile) {
467 const char* gl_extensions = reinterpret_cast<const char*>(
468 GLApiBase::glGetStringFn(GL_EXTENSIONS));
469 if (gl_extensions)
470 base::SplitString(gl_extensions, ' ', &filtered_exts_);
471 } else {
472 GLint num_extensions = 0;
473 GLApiBase::glGetIntegervFn(GL_NUM_EXTENSIONS, &num_extensions);
474 for (GLint i = 0; i < num_extensions; ++i) {
475 const char* gl_extension = reinterpret_cast<const char*>(
476 GLApiBase::glGetStringiFn(GL_EXTENSIONS, i));
477 DCHECK(gl_extension != NULL);
478 filtered_exts_.push_back(gl_extension);
482 // Filter out extensions from the command line.
483 for (const std::string& disabled_ext : disabled_exts_) {
484 filtered_exts_.erase(std::remove(filtered_exts_.begin(),
485 filtered_exts_.end(),
486 disabled_ext),
487 filtered_exts_.end());
490 // Construct filtered extensions string for GL_EXTENSIONS string lookups.
491 filtered_exts_str_ = JoinString(filtered_exts_, " ");
495 TraceGLApi::~TraceGLApi() {
498 NoContextGLApi::NoContextGLApi() {
501 NoContextGLApi::~NoContextGLApi() {
504 VirtualGLApi::VirtualGLApi()
505 : real_context_(NULL),
506 current_context_(NULL) {
509 VirtualGLApi::~VirtualGLApi() {
512 void VirtualGLApi::Initialize(DriverGL* driver, GLContext* real_context) {
513 InitializeBase(driver);
514 real_context_ = real_context;
516 DCHECK(real_context->IsCurrent(NULL));
517 std::string ext_string = real_context->GetExtensions();
518 std::vector<std::string> ext;
519 Tokenize(ext_string, " ", &ext);
521 std::vector<std::string>::iterator it;
522 // We can't support GL_EXT_occlusion_query_boolean which is
523 // based on GL_ARB_occlusion_query without a lot of work virtualizing
524 // queries.
525 it = std::find(ext.begin(), ext.end(), "GL_EXT_occlusion_query_boolean");
526 if (it != ext.end())
527 ext.erase(it);
529 extensions_ = JoinString(ext, " ");
532 bool VirtualGLApi::MakeCurrent(GLContext* virtual_context, GLSurface* surface) {
533 bool switched_contexts = g_current_gl_context_tls->Get() != this;
534 GLSurface* current_surface = GLSurface::GetCurrent();
535 if (switched_contexts || surface != current_surface) {
536 // MakeCurrent 'lite' path that avoids potentially expensive MakeCurrent()
537 // calls if the GLSurface uses the same underlying surface or renders to
538 // an FBO.
539 if (switched_contexts || !current_surface ||
540 !virtual_context->IsCurrent(surface)) {
541 if (!real_context_->MakeCurrent(surface)) {
542 return false;
547 bool state_dirtied_externally = real_context_->GetStateWasDirtiedExternally();
548 real_context_->SetStateWasDirtiedExternally(false);
550 DCHECK_EQ(real_context_, GLContext::GetRealCurrent());
551 DCHECK(real_context_->IsCurrent(NULL));
552 DCHECK(virtual_context->IsCurrent(surface));
554 if (state_dirtied_externally || switched_contexts ||
555 virtual_context != current_context_) {
556 #if DCHECK_IS_ON()
557 GLenum error = glGetErrorFn();
558 // Accepting a context loss error here enables using debug mode to work on
559 // context loss handling in virtual context mode.
560 // There should be no other errors from the previous context leaking into
561 // the new context.
562 DCHECK(error == GL_NO_ERROR || error == GL_CONTEXT_LOST_KHR);
563 #endif
565 // Set all state that is different from the real state
566 GLApi* temp = GetCurrentGLApi();
567 SetGLToRealGLApi();
568 if (virtual_context->GetGLStateRestorer()->IsInitialized()) {
569 virtual_context->GetGLStateRestorer()->RestoreState(
570 (current_context_ && !state_dirtied_externally && !switched_contexts)
571 ? current_context_->GetGLStateRestorer()
572 : NULL);
574 SetGLApi(temp);
575 current_context_ = virtual_context;
577 SetGLApi(this);
579 virtual_context->SetCurrent(surface);
580 if (!surface->OnMakeCurrent(virtual_context)) {
581 LOG(ERROR) << "Could not make GLSurface current.";
582 return false;
584 return true;
587 void VirtualGLApi::OnReleaseVirtuallyCurrent(GLContext* virtual_context) {
588 if (current_context_ == virtual_context)
589 current_context_ = NULL;
592 const GLubyte* VirtualGLApi::glGetStringFn(GLenum name) {
593 switch (name) {
594 case GL_EXTENSIONS:
595 return reinterpret_cast<const GLubyte*>(extensions_.c_str());
596 default:
597 return driver_->fn.glGetStringFn(name);
601 void VirtualGLApi::glFlushFn() {
602 GLApiBase::glFlushFn();
605 void VirtualGLApi::glFinishFn() {
606 GLApiBase::glFinishFn();
609 ScopedSetGLToRealGLApi::ScopedSetGLToRealGLApi()
610 : old_gl_api_(GetCurrentGLApi()) {
611 SetGLToRealGLApi();
614 ScopedSetGLToRealGLApi::~ScopedSetGLToRealGLApi() {
615 SetGLApi(old_gl_api_);
618 } // namespace gfx