Add ICU message format support
[chromium-blink-merge.git] / ui / gl / gl_gl_api_implementation.cc
blob2de5c978ff536181eeb226eafd814e18da3b8256
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::WillUseGLGetStringForExtensions()) {
479 filtered_exts_str_ =
480 FilterGLExtensionList(reinterpret_cast<const char*>(
481 GLApiBase::glGetStringFn(GL_EXTENSIONS)),
482 disabled_exts_);
483 base::SplitString(filtered_exts_str_, ' ', &filtered_exts_);
484 } else {
485 GLint num_extensions = 0;
486 GLApiBase::glGetIntegervFn(GL_NUM_EXTENSIONS, &num_extensions);
487 for (GLint i = 0; i < num_extensions; ++i) {
488 const char* gl_extension = reinterpret_cast<const char*>(
489 GLApiBase::glGetStringiFn(GL_EXTENSIONS, i));
490 DCHECK(gl_extension != NULL);
491 if (std::find(disabled_exts_.begin(), disabled_exts_.end(),
492 gl_extension) == disabled_exts_.end()) {
493 filtered_exts_.push_back(gl_extension);
496 filtered_exts_str_ = base::JoinString(filtered_exts_, " ");
498 #if DCHECK_IS_ON()
499 filtered_exts_initialized_ = true;
500 #endif
504 TraceGLApi::~TraceGLApi() {
507 NoContextGLApi::NoContextGLApi() {
510 NoContextGLApi::~NoContextGLApi() {
513 VirtualGLApi::VirtualGLApi()
514 : real_context_(NULL),
515 current_context_(NULL) {
518 VirtualGLApi::~VirtualGLApi() {
521 void VirtualGLApi::Initialize(DriverGL* driver, GLContext* real_context) {
522 InitializeBase(driver);
523 real_context_ = real_context;
525 DCHECK(real_context->IsCurrent(NULL));
526 extensions_ = real_context->GetExtensions();
529 bool VirtualGLApi::MakeCurrent(GLContext* virtual_context, GLSurface* surface) {
530 bool switched_contexts = g_current_gl_context_tls->Get() != this;
531 GLSurface* current_surface = GLSurface::GetCurrent();
532 if (switched_contexts || surface != current_surface) {
533 // MakeCurrent 'lite' path that avoids potentially expensive MakeCurrent()
534 // calls if the GLSurface uses the same underlying surface or renders to
535 // an FBO.
536 if (switched_contexts || !current_surface ||
537 !virtual_context->IsCurrent(surface)) {
538 if (!real_context_->MakeCurrent(surface)) {
539 return false;
544 bool state_dirtied_externally = real_context_->GetStateWasDirtiedExternally();
545 real_context_->SetStateWasDirtiedExternally(false);
547 DCHECK_EQ(real_context_, GLContext::GetRealCurrent());
548 DCHECK(real_context_->IsCurrent(NULL));
549 DCHECK(virtual_context->IsCurrent(surface));
551 if (state_dirtied_externally || switched_contexts ||
552 virtual_context != current_context_) {
553 #if DCHECK_IS_ON()
554 GLenum error = glGetErrorFn();
555 // Accepting a context loss error here enables using debug mode to work on
556 // context loss handling in virtual context mode.
557 // There should be no other errors from the previous context leaking into
558 // the new context.
559 DCHECK(error == GL_NO_ERROR || error == GL_CONTEXT_LOST_KHR);
560 #endif
562 // Set all state that is different from the real state
563 GLApi* temp = GetCurrentGLApi();
564 SetGLToRealGLApi();
565 if (virtual_context->GetGLStateRestorer()->IsInitialized()) {
566 GLStateRestorer* virtual_state = virtual_context->GetGLStateRestorer();
567 GLStateRestorer* current_state = current_context_ ?
568 current_context_->GetGLStateRestorer() :
569 nullptr;
570 if (switched_contexts || virtual_context != current_context_) {
571 if (current_state)
572 current_state->PauseQueries();
573 virtual_state->ResumeQueries();
576 virtual_state->RestoreState(
577 (current_state && !state_dirtied_externally && !switched_contexts)
578 ? current_state
579 : NULL);
581 SetGLApi(temp);
582 current_context_ = virtual_context;
584 SetGLApi(this);
586 virtual_context->SetCurrent(surface);
587 if (!surface->OnMakeCurrent(virtual_context)) {
588 LOG(ERROR) << "Could not make GLSurface current.";
589 return false;
591 return true;
594 void VirtualGLApi::OnReleaseVirtuallyCurrent(GLContext* virtual_context) {
595 if (current_context_ == virtual_context)
596 current_context_ = NULL;
599 const GLubyte* VirtualGLApi::glGetStringFn(GLenum name) {
600 switch (name) {
601 case GL_EXTENSIONS:
602 return reinterpret_cast<const GLubyte*>(extensions_.c_str());
603 default:
604 return driver_->fn.glGetStringFn(name);
608 void VirtualGLApi::glFlushFn() {
609 GLApiBase::glFlushFn();
612 void VirtualGLApi::glFinishFn() {
613 GLApiBase::glFinishFn();
616 ScopedSetGLToRealGLApi::ScopedSetGLToRealGLApi()
617 : old_gl_api_(GetCurrentGLApi()) {
618 SetGLToRealGLApi();
621 ScopedSetGLToRealGLApi::~ScopedSetGLToRealGLApi() {
622 SetGLApi(old_gl_api_);
625 } // namespace gfx