Fix search results being clipped in app list.
[chromium-blink-merge.git] / ui / gl / gl_gl_api_implementation.cc
blob6752a25ee5a83644a00495804ffb027d81a54859
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_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"
19 namespace gfx {
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
26 // current.
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;
33 namespace {
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)
38 return GL_RGBA8;
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,
45 GLenum format,
46 GLenum type) {
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) {
53 switch (type) {
54 case GL_UNSIGNED_BYTE:
55 gl_internal_format = GL_R8_EXT;
56 break;
57 case GL_HALF_FLOAT_OES:
58 gl_internal_format = GL_R16F_EXT;
59 break;
60 case GL_FLOAT:
61 gl_internal_format = GL_R32F_EXT;
62 break;
63 default:
64 NOTREACHED();
65 break;
67 return gl_internal_format;
68 } else if (format == GL_RG_EXT) {
69 switch (type) {
70 case GL_UNSIGNED_BYTE:
71 gl_internal_format = GL_RG8_EXT;
72 break;
73 case GL_HALF_FLOAT_OES:
74 gl_internal_format = GL_RG16F_EXT;
75 break;
76 case GL_FLOAT:
77 gl_internal_format = GL_RG32F_EXT;
78 break;
79 default:
80 NOTREACHED();
81 break;
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
92 // support.
93 // http://code.google.com/p/angleproject/issues/detail?id=556
94 switch (format) {
95 case GL_RGBA:
96 gl_internal_format = GL_RGBA;
97 break;
98 case GL_RGB:
99 gl_internal_format = GL_RGB;
100 break;
101 default:
102 break;
106 if (gfx::g_version_info->is_es)
107 return gl_internal_format;
109 if (type == GL_FLOAT) {
110 switch (format) {
111 case GL_RGBA:
112 gl_internal_format = GL_RGBA32F_ARB;
113 break;
114 case GL_RGB:
115 gl_internal_format = GL_RGB32F_ARB;
116 break;
117 case GL_LUMINANCE_ALPHA:
118 gl_internal_format = GL_LUMINANCE_ALPHA32F_ARB;
119 break;
120 case GL_LUMINANCE:
121 gl_internal_format = GL_LUMINANCE32F_ARB;
122 break;
123 case GL_ALPHA:
124 gl_internal_format = GL_ALPHA32F_ARB;
125 break;
126 default:
127 NOTREACHED();
128 break;
130 } else if (type == GL_HALF_FLOAT_OES) {
131 switch (format) {
132 case GL_RGBA:
133 gl_internal_format = GL_RGBA16F_ARB;
134 break;
135 case GL_RGB:
136 gl_internal_format = GL_RGB16F_ARB;
137 break;
138 case GL_LUMINANCE_ALPHA:
139 gl_internal_format = GL_LUMINANCE_ALPHA16F_ARB;
140 break;
141 case GL_LUMINANCE:
142 gl_internal_format = GL_LUMINANCE16F_ARB;
143 break;
144 case GL_ALPHA:
145 gl_internal_format = GL_ALPHA16F_ARB;
146 break;
147 default:
148 NOTREACHED();
149 break;
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;
160 return type;
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,
172 pixels);
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,
185 GLsizei height) {
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,
204 GLsizei height) {
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;
217 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,
256 GLsizei count,
257 GLenum type,
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;
291 return before;
294 void InitializeStaticGLBindingsGL() {
295 g_current_gl_context_tls = new base::ThreadLocalPointer<GLApi>;
296 g_driver_gl.InitializeStaticBindings();
297 if (!g_real_gl) {
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);
303 g_gl = g_real_gl;
304 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
305 switches::kEnableGPUServiceTracing)) {
306 g_gl = g_trace_gl;
308 SetGLToRealGLApi();
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() {
320 SetGLApi(g_gl);
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() {
357 if (g_real_gl) {
358 delete g_real_gl;
359 g_real_gl = NULL;
361 if (g_trace_gl) {
362 delete g_trace_gl;
363 g_trace_gl = NULL;
365 if (g_no_context_gl) {
366 delete g_no_context_gl;
367 g_no_context_gl = NULL;
369 g_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;
381 GLApi::GLApi() {
384 GLApi::~GLApi() {
385 if (GetCurrentGLApi() == this)
386 SetGLApi(NULL);
389 GLApiBase::GLApiBase()
390 : driver_(NULL) {
393 GLApiBase::~GLApiBase() {
396 void GLApiBase::InitializeBase(DriverGL* driver) {
397 driver_ = 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
447 // queries.
448 it = std::find(ext.begin(), ext.end(), "GL_EXT_occlusion_query_boolean");
449 if (it != ext.end())
450 ext.erase(it);
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
461 // an FBO.
462 if (switched_contexts || !current_surface ||
463 !virtual_context->IsCurrent(surface)) {
464 if (!real_context_->MakeCurrent(surface)) {
465 return false;
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_) {
479 #if DCHECK_IS_ON()
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
484 // the new context.
485 DCHECK(error == GL_NO_ERROR || error == GL_CONTEXT_LOST_KHR);
486 #endif
488 // Set all state that is different from the real state
489 GLApi* temp = GetCurrentGLApi();
490 SetGLToRealGLApi();
491 if (virtual_context->GetGLStateRestorer()->IsInitialized()) {
492 virtual_context->GetGLStateRestorer()->RestoreState(
493 (current_context_ && !state_dirtied_externally && !switched_contexts)
494 ? current_context_->GetGLStateRestorer()
495 : NULL);
497 SetGLApi(temp);
498 current_context_ = virtual_context;
500 SetGLApi(this);
502 virtual_context->SetCurrent(surface);
503 if (!surface->OnMakeCurrent(virtual_context)) {
504 LOG(ERROR) << "Could not make GLSurface current.";
505 return false;
507 return true;
510 void VirtualGLApi::OnReleaseVirtuallyCurrent(GLContext* virtual_context) {
511 if (current_context_ == virtual_context)
512 current_context_ = NULL;
515 const GLubyte* VirtualGLApi::glGetStringFn(GLenum name) {
516 switch (name) {
517 case GL_EXTENSIONS:
518 return reinterpret_cast<const GLubyte*>(extensions_.c_str());
519 default:
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()) {
534 SetGLToRealGLApi();
537 ScopedSetGLToRealGLApi::~ScopedSetGLToRealGLApi() {
538 SetGLApi(old_gl_api_);
541 } // namespace gfx