cc: Remove noisy UpdateTiles traces.
[chromium-blink-merge.git] / ui / gl / gl_gl_api_implementation.cc
blob017e123eb1ff5f566031b9018a6cc2dff715090d
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 (type == GL_FLOAT && gfx::g_version_info->is_angle &&
52 gfx::g_version_info->is_es2) {
53 // It's possible that the texture is using a sized internal format, and
54 // ANGLE exposing GLES2 API doesn't support those.
55 // TODO(oetuaho@nvidia.com): Remove these conversions once ANGLE has the
56 // support.
57 // http://code.google.com/p/angleproject/issues/detail?id=556
58 switch (format) {
59 case GL_RGBA:
60 gl_internal_format = GL_RGBA;
61 break;
62 case GL_RGB:
63 gl_internal_format = GL_RGB;
64 break;
65 default:
66 break;
70 if (gfx::g_version_info->is_es)
71 return gl_internal_format;
73 if (type == GL_FLOAT) {
74 switch (format) {
75 case GL_RGBA:
76 gl_internal_format = GL_RGBA32F_ARB;
77 break;
78 case GL_RGB:
79 gl_internal_format = GL_RGB32F_ARB;
80 break;
81 case GL_LUMINANCE_ALPHA:
82 gl_internal_format = GL_LUMINANCE_ALPHA32F_ARB;
83 break;
84 case GL_LUMINANCE:
85 gl_internal_format = GL_LUMINANCE32F_ARB;
86 break;
87 case GL_ALPHA:
88 gl_internal_format = GL_ALPHA32F_ARB;
89 break;
90 default:
91 NOTREACHED();
92 break;
94 } else if (type == GL_HALF_FLOAT_OES) {
95 switch (format) {
96 case GL_RGBA:
97 gl_internal_format = GL_RGBA16F_ARB;
98 break;
99 case GL_RGB:
100 gl_internal_format = GL_RGB16F_ARB;
101 break;
102 case GL_LUMINANCE_ALPHA:
103 gl_internal_format = GL_LUMINANCE_ALPHA16F_ARB;
104 break;
105 case GL_LUMINANCE:
106 gl_internal_format = GL_LUMINANCE16F_ARB;
107 break;
108 case GL_ALPHA:
109 gl_internal_format = GL_ALPHA16F_ARB;
110 break;
111 default:
112 NOTREACHED();
113 break;
116 return gl_internal_format;
119 static inline GLenum GetTexType(GLenum type) {
120 if (gfx::GetGLImplementation() != gfx::kGLImplementationEGLGLES2) {
121 if (type == GL_HALF_FLOAT_OES)
122 return GL_HALF_FLOAT_ARB;
124 return type;
127 static void GL_BINDING_CALL CustomTexImage2D(
128 GLenum target, GLint level, GLint internalformat,
129 GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type,
130 const void* pixels) {
131 GLenum gl_internal_format = GetTexInternalFormat(
132 internalformat, format, type);
133 GLenum gl_type = GetTexType(type);
134 g_driver_gl.orig_fn.glTexImage2DFn(
135 target, level, gl_internal_format, width, height, border, format, gl_type,
136 pixels);
139 static void GL_BINDING_CALL CustomTexSubImage2D(
140 GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
141 GLsizei height, GLenum format, GLenum type, const void* pixels) {
142 GLenum gl_type = GetTexType(type);
143 g_driver_gl.orig_fn.glTexSubImage2DFn(
144 target, level, xoffset, yoffset, width, height, format, gl_type, pixels);
147 static void GL_BINDING_CALL CustomTexStorage2DEXT(
148 GLenum target, GLsizei levels, GLenum internalformat, GLsizei width,
149 GLsizei height) {
150 GLenum gl_internal_format = GetInternalFormat(internalformat);
151 g_driver_gl.orig_fn.glTexStorage2DEXTFn(
152 target, levels, gl_internal_format, width, height);
155 static void GL_BINDING_CALL CustomRenderbufferStorageEXT(
156 GLenum target, GLenum internalformat, GLsizei width, GLsizei height) {
157 GLenum gl_internal_format = GetInternalFormat(internalformat);
158 g_driver_gl.orig_fn.glRenderbufferStorageEXTFn(
159 target, gl_internal_format, width, height);
162 // The ANGLE and IMG variants of glRenderbufferStorageMultisample currently do
163 // not support BGRA render buffers so only the EXT one is customized. If
164 // GL_CHROMIUM_renderbuffer_format_BGRA8888 support is added to ANGLE then the
165 // ANGLE version should also be customized.
166 static void GL_BINDING_CALL CustomRenderbufferStorageMultisampleEXT(
167 GLenum target, GLsizei samples, GLenum internalformat, GLsizei width,
168 GLsizei height) {
169 GLenum gl_internal_format = GetInternalFormat(internalformat);
170 g_driver_gl.orig_fn.glRenderbufferStorageMultisampleEXTFn(
171 target, samples, gl_internal_format, width, height);
174 } // anonymous namespace
176 void DriverGL::InitializeCustomDynamicBindings(GLContext* context) {
177 InitializeDynamicBindings(context);
179 DCHECK(orig_fn.glTexImage2DFn == NULL);
180 orig_fn.glTexImage2DFn = fn.glTexImage2DFn;
181 fn.glTexImage2DFn =
182 reinterpret_cast<glTexImage2DProc>(CustomTexImage2D);
184 DCHECK(orig_fn.glTexSubImage2DFn == NULL);
185 orig_fn.glTexSubImage2DFn = fn.glTexSubImage2DFn;
186 fn.glTexSubImage2DFn =
187 reinterpret_cast<glTexSubImage2DProc>(CustomTexSubImage2D);
189 DCHECK(orig_fn.glTexStorage2DEXTFn == NULL);
190 orig_fn.glTexStorage2DEXTFn = fn.glTexStorage2DEXTFn;
191 fn.glTexStorage2DEXTFn =
192 reinterpret_cast<glTexStorage2DEXTProc>(CustomTexStorage2DEXT);
194 DCHECK(orig_fn.glRenderbufferStorageEXTFn == NULL);
195 orig_fn.glRenderbufferStorageEXTFn = fn.glRenderbufferStorageEXTFn;
196 fn.glRenderbufferStorageEXTFn =
197 reinterpret_cast<glRenderbufferStorageEXTProc>(
198 CustomRenderbufferStorageEXT);
200 DCHECK(orig_fn.glRenderbufferStorageMultisampleEXTFn == NULL);
201 orig_fn.glRenderbufferStorageMultisampleEXTFn =
202 fn.glRenderbufferStorageMultisampleEXTFn;
203 fn.glRenderbufferStorageMultisampleEXTFn =
204 reinterpret_cast<glRenderbufferStorageMultisampleEXTProc>(
205 CustomRenderbufferStorageMultisampleEXT);
208 static void GL_BINDING_CALL NullDrawClearFn(GLbitfield mask) {
209 if (!g_driver_gl.null_draw_bindings_enabled)
210 g_driver_gl.orig_fn.glClearFn(mask);
213 static void GL_BINDING_CALL
214 NullDrawDrawArraysFn(GLenum mode, GLint first, GLsizei count) {
215 if (!g_driver_gl.null_draw_bindings_enabled)
216 g_driver_gl.orig_fn.glDrawArraysFn(mode, first, count);
219 static void GL_BINDING_CALL NullDrawDrawElementsFn(GLenum mode,
220 GLsizei count,
221 GLenum type,
222 const void* indices) {
223 if (!g_driver_gl.null_draw_bindings_enabled)
224 g_driver_gl.orig_fn.glDrawElementsFn(mode, count, type, indices);
227 void DriverGL::InitializeNullDrawBindings() {
228 DCHECK(orig_fn.glClearFn == NULL);
229 orig_fn.glClearFn = fn.glClearFn;
230 fn.glClearFn = NullDrawClearFn;
232 DCHECK(orig_fn.glDrawArraysFn == NULL);
233 orig_fn.glDrawArraysFn = fn.glDrawArraysFn;
234 fn.glDrawArraysFn = NullDrawDrawArraysFn;
236 DCHECK(orig_fn.glDrawElementsFn == NULL);
237 orig_fn.glDrawElementsFn = fn.glDrawElementsFn;
238 fn.glDrawElementsFn = NullDrawDrawElementsFn;
240 null_draw_bindings_enabled = true;
243 bool DriverGL::HasInitializedNullDrawBindings() {
244 return orig_fn.glClearFn != NULL && orig_fn.glDrawArraysFn != NULL &&
245 orig_fn.glDrawElementsFn != NULL;
248 bool DriverGL::SetNullDrawBindingsEnabled(bool enabled) {
249 DCHECK(orig_fn.glClearFn != NULL);
250 DCHECK(orig_fn.glDrawArraysFn != NULL);
251 DCHECK(orig_fn.glDrawElementsFn != NULL);
253 bool before = null_draw_bindings_enabled;
254 null_draw_bindings_enabled = enabled;
255 return before;
258 void InitializeStaticGLBindingsGL() {
259 g_current_gl_context_tls = new base::ThreadLocalPointer<GLApi>;
260 g_driver_gl.InitializeStaticBindings();
261 if (!g_real_gl) {
262 g_real_gl = new RealGLApi();
263 g_trace_gl = new TraceGLApi(g_real_gl);
264 g_no_context_gl = new NoContextGLApi();
266 g_real_gl->Initialize(&g_driver_gl);
267 g_gl = g_real_gl;
268 if (CommandLine::ForCurrentProcess()->HasSwitch(
269 switches::kEnableGPUServiceTracing)) {
270 g_gl = g_trace_gl;
272 SetGLToRealGLApi();
275 GLApi* GetCurrentGLApi() {
276 return g_current_gl_context_tls->Get();
279 void SetGLApi(GLApi* api) {
280 g_current_gl_context_tls->Set(api);
283 void SetGLToRealGLApi() {
284 SetGLApi(g_gl);
287 void SetGLApiToNoContext() {
288 SetGLApi(g_no_context_gl);
291 const GLVersionInfo* GetGLVersionInfo() {
292 return g_version_info;
295 void InitializeDynamicGLBindingsGL(GLContext* context) {
296 g_driver_gl.InitializeCustomDynamicBindings(context);
297 DCHECK(context && context->IsCurrent(NULL) && !g_version_info);
298 g_version_info = new GLVersionInfo(context->GetGLVersion().c_str(),
299 context->GetGLRenderer().c_str());
302 void InitializeDebugGLBindingsGL() {
303 g_driver_gl.InitializeDebugBindings();
306 void InitializeNullDrawGLBindingsGL() {
307 g_driver_gl.InitializeNullDrawBindings();
310 bool HasInitializedNullDrawGLBindingsGL() {
311 return g_driver_gl.HasInitializedNullDrawBindings();
314 bool SetNullDrawGLBindingsEnabledGL(bool enabled) {
315 return g_driver_gl.SetNullDrawBindingsEnabled(enabled);
318 void ClearGLBindingsGL() {
319 if (g_real_gl) {
320 delete g_real_gl;
321 g_real_gl = NULL;
323 if (g_trace_gl) {
324 delete g_trace_gl;
325 g_trace_gl = NULL;
327 if (g_no_context_gl) {
328 delete g_no_context_gl;
329 g_no_context_gl = NULL;
331 g_gl = NULL;
332 g_driver_gl.ClearBindings();
333 if (g_current_gl_context_tls) {
334 delete g_current_gl_context_tls;
335 g_current_gl_context_tls = NULL;
337 if (g_version_info) {
338 delete g_version_info;
339 g_version_info = NULL;
343 GLApi::GLApi() {
346 GLApi::~GLApi() {
347 if (GetCurrentGLApi() == this)
348 SetGLApi(NULL);
351 GLApiBase::GLApiBase()
352 : driver_(NULL) {
355 GLApiBase::~GLApiBase() {
358 void GLApiBase::InitializeBase(DriverGL* driver) {
359 driver_ = driver;
362 void GLApiBase::SignalFlush() {
363 DCHECK(GLContext::GetCurrent());
364 GLContext::GetCurrent()->OnFlush();
367 RealGLApi::RealGLApi() {
370 RealGLApi::~RealGLApi() {
373 void RealGLApi::Initialize(DriverGL* driver) {
374 InitializeBase(driver);
377 void RealGLApi::glFlushFn() {
378 GLApiBase::glFlushFn();
379 GLApiBase::SignalFlush();
382 void RealGLApi::glFinishFn() {
383 GLApiBase::glFinishFn();
384 GLApiBase::SignalFlush();
387 TraceGLApi::~TraceGLApi() {
390 NoContextGLApi::NoContextGLApi() {
393 NoContextGLApi::~NoContextGLApi() {
396 VirtualGLApi::VirtualGLApi()
397 : real_context_(NULL),
398 current_context_(NULL) {
401 VirtualGLApi::~VirtualGLApi() {
404 void VirtualGLApi::Initialize(DriverGL* driver, GLContext* real_context) {
405 InitializeBase(driver);
406 real_context_ = real_context;
408 DCHECK(real_context->IsCurrent(NULL));
409 std::string ext_string(
410 reinterpret_cast<const char*>(driver_->fn.glGetStringFn(GL_EXTENSIONS)));
411 std::vector<std::string> ext;
412 Tokenize(ext_string, " ", &ext);
414 std::vector<std::string>::iterator it;
415 // We can't support GL_EXT_occlusion_query_boolean which is
416 // based on GL_ARB_occlusion_query without a lot of work virtualizing
417 // queries.
418 it = std::find(ext.begin(), ext.end(), "GL_EXT_occlusion_query_boolean");
419 if (it != ext.end())
420 ext.erase(it);
422 extensions_ = JoinString(ext, " ");
425 bool VirtualGLApi::MakeCurrent(GLContext* virtual_context, GLSurface* surface) {
426 bool switched_contexts = g_current_gl_context_tls->Get() != this;
427 GLSurface* current_surface = GLSurface::GetCurrent();
428 if (switched_contexts || surface != current_surface) {
429 // MakeCurrent 'lite' path that avoids potentially expensive MakeCurrent()
430 // calls if the GLSurface uses the same underlying surface or renders to
431 // an FBO.
432 if (switched_contexts || !current_surface ||
433 !virtual_context->IsCurrent(surface)) {
434 if (!real_context_->MakeCurrent(surface)) {
435 return false;
440 DCHECK_EQ(real_context_, GLContext::GetRealCurrent());
441 DCHECK(real_context_->IsCurrent(NULL));
442 DCHECK(virtual_context->IsCurrent(surface));
444 if (switched_contexts || virtual_context != current_context_) {
445 #if DCHECK_IS_ON
446 GLenum error = glGetErrorFn();
447 // Accepting a context loss error here enables using debug mode to work on
448 // context loss handling in virtual context mode.
449 // There should be no other errors from the previous context leaking into
450 // the new context.
451 DCHECK(error == GL_NO_ERROR || error == GL_CONTEXT_LOST_KHR);
452 #endif
454 // Set all state that is different from the real state
455 GLApi* temp = GetCurrentGLApi();
456 SetGLToRealGLApi();
457 if (virtual_context->GetGLStateRestorer()->IsInitialized()) {
458 virtual_context->GetGLStateRestorer()->RestoreState(
459 (current_context_ && !switched_contexts)
460 ? current_context_->GetGLStateRestorer()
461 : NULL);
463 SetGLApi(temp);
464 current_context_ = virtual_context;
466 SetGLApi(this);
468 virtual_context->SetCurrent(surface);
469 if (!surface->OnMakeCurrent(virtual_context)) {
470 LOG(ERROR) << "Could not make GLSurface current.";
471 return false;
473 return true;
476 void VirtualGLApi::OnReleaseVirtuallyCurrent(GLContext* virtual_context) {
477 if (current_context_ == virtual_context)
478 current_context_ = NULL;
481 const GLubyte* VirtualGLApi::glGetStringFn(GLenum name) {
482 switch (name) {
483 case GL_EXTENSIONS:
484 return reinterpret_cast<const GLubyte*>(extensions_.c_str());
485 default:
486 return driver_->fn.glGetStringFn(name);
490 void VirtualGLApi::glFlushFn() {
491 GLApiBase::glFlushFn();
492 GLApiBase::SignalFlush();
495 void VirtualGLApi::glFinishFn() {
496 GLApiBase::glFinishFn();
497 GLApiBase::SignalFlush();
500 ScopedSetGLToRealGLApi::ScopedSetGLToRealGLApi()
501 : old_gl_api_(GetCurrentGLApi()) {
502 SetGLToRealGLApi();
505 ScopedSetGLToRealGLApi::~ScopedSetGLToRealGLApi() {
506 SetGLApi(old_gl_api_);
509 } // namespace gfx