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. 4 5#include "ui/gl/gl_gl_api_implementation.h" 6 7#include <algorithm> 8#include <vector> 9 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" 18 19namespace gfx { 20 21// The GL Api being used. This could be g_real_gl or gl_trace_gl 22static GLApi* g_gl = NULL; 23// A GL Api that calls directly into the driver. 24static RealGLApi* g_real_gl = NULL; 25// A GL Api that does nothing but warn about illegal GL calls without a context 26// current. 27static NoContextGLApi* g_no_context_gl = NULL; 28// A GL Api that calls TRACE and then calls another GL api. 29static TraceGLApi* g_trace_gl = NULL; 30// GL version used when initializing dynamic bindings. 31static GLVersionInfo* g_version_info = NULL; 32 33namespace { 34 35static 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; 39 } 40 return internal_format; 41} 42 43// TODO(epenner): Could the above function be merged into this and removed? 44static inline GLenum GetTexInternalFormat(GLenum internal_format, 45 GLenum format, 46 GLenum type) { 47 GLenum gl_internal_format = GetInternalFormat(internal_format); 48 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; 67 } 68 } 69 70 if (gfx::g_version_info->is_es) 71 return gl_internal_format; 72 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; 93 } 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; 114 } 115 } 116 return gl_internal_format; 117} 118 119static inline GLenum GetTexType(GLenum type) { 120 if (gfx::GetGLImplementation() != gfx::kGLImplementationEGLGLES2) { 121 if (type == GL_HALF_FLOAT_OES) 122 return GL_HALF_FLOAT_ARB; 123 } 124 return type; 125} 126 127static 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); 137} 138 139static 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); 145} 146 147static 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); 153} 154 155static 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); 160} 161 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. 166static 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); 172} 173 174} // anonymous namespace 175 176void DriverGL::InitializeCustomDynamicBindings(GLContext* context) { 177 InitializeDynamicBindings(context); 178 179 DCHECK(orig_fn.glTexImage2DFn == NULL); 180 orig_fn.glTexImage2DFn = fn.glTexImage2DFn; 181 fn.glTexImage2DFn = 182 reinterpret_cast<glTexImage2DProc>(CustomTexImage2D); 183 184 DCHECK(orig_fn.glTexSubImage2DFn == NULL); 185 orig_fn.glTexSubImage2DFn = fn.glTexSubImage2DFn; 186 fn.glTexSubImage2DFn = 187 reinterpret_cast<glTexSubImage2DProc>(CustomTexSubImage2D); 188 189 DCHECK(orig_fn.glTexStorage2DEXTFn == NULL); 190 orig_fn.glTexStorage2DEXTFn = fn.glTexStorage2DEXTFn; 191 fn.glTexStorage2DEXTFn = 192 reinterpret_cast<glTexStorage2DEXTProc>(CustomTexStorage2DEXT); 193 194 DCHECK(orig_fn.glRenderbufferStorageEXTFn == NULL); 195 orig_fn.glRenderbufferStorageEXTFn = fn.glRenderbufferStorageEXTFn; 196 fn.glRenderbufferStorageEXTFn = 197 reinterpret_cast<glRenderbufferStorageEXTProc>( 198 CustomRenderbufferStorageEXT); 199 200 DCHECK(orig_fn.glRenderbufferStorageMultisampleEXTFn == NULL); 201 orig_fn.glRenderbufferStorageMultisampleEXTFn = 202 fn.glRenderbufferStorageMultisampleEXTFn; 203 fn.glRenderbufferStorageMultisampleEXTFn = 204 reinterpret_cast<glRenderbufferStorageMultisampleEXTProc>( 205 CustomRenderbufferStorageMultisampleEXT); 206} 207 208static void GL_BINDING_CALL NullDrawClearFn(GLbitfield mask) { 209 if (!g_driver_gl.null_draw_bindings_enabled) 210 g_driver_gl.orig_fn.glClearFn(mask); 211} 212 213static void GL_BINDING_CALL 214NullDrawDrawArraysFn(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); 217} 218 219static 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); 225} 226 227void DriverGL::InitializeNullDrawBindings() { 228 DCHECK(orig_fn.glClearFn == NULL); 229 orig_fn.glClearFn = fn.glClearFn; 230 fn.glClearFn = NullDrawClearFn; 231 232 DCHECK(orig_fn.glDrawArraysFn == NULL); 233 orig_fn.glDrawArraysFn = fn.glDrawArraysFn; 234 fn.glDrawArraysFn = NullDrawDrawArraysFn; 235 236 DCHECK(orig_fn.glDrawElementsFn == NULL); 237 orig_fn.glDrawElementsFn = fn.glDrawElementsFn; 238 fn.glDrawElementsFn = NullDrawDrawElementsFn; 239 240 null_draw_bindings_enabled = true; 241} 242 243bool DriverGL::HasInitializedNullDrawBindings() { 244 return orig_fn.glClearFn != NULL && orig_fn.glDrawArraysFn != NULL && 245 orig_fn.glDrawElementsFn != NULL; 246} 247 248bool DriverGL::SetNullDrawBindingsEnabled(bool enabled) { 249 DCHECK(orig_fn.glClearFn != NULL); 250 DCHECK(orig_fn.glDrawArraysFn != NULL); 251 DCHECK(orig_fn.glDrawElementsFn != NULL); 252 253 bool before = null_draw_bindings_enabled; 254 null_draw_bindings_enabled = enabled; 255 return before; 256} 257 258void 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(); 265 } 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; 271 } 272 SetGLToRealGLApi(); 273} 274 275GLApi* GetCurrentGLApi() { 276 return g_current_gl_context_tls->Get(); 277} 278 279void SetGLApi(GLApi* api) { 280 g_current_gl_context_tls->Set(api); 281} 282 283void SetGLToRealGLApi() { 284 SetGLApi(g_gl); 285} 286 287void SetGLApiToNoContext() { 288 SetGLApi(g_no_context_gl); 289} 290 291const GLVersionInfo* GetGLVersionInfo() { 292 return g_version_info; 293} 294 295void 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()); 300} 301 302void InitializeDebugGLBindingsGL() { 303 g_driver_gl.InitializeDebugBindings(); 304} 305 306void InitializeNullDrawGLBindingsGL() { 307 g_driver_gl.InitializeNullDrawBindings(); 308} 309 310bool HasInitializedNullDrawGLBindingsGL() { 311 return g_driver_gl.HasInitializedNullDrawBindings(); 312} 313 314bool SetNullDrawGLBindingsEnabledGL(bool enabled) { 315 return g_driver_gl.SetNullDrawBindingsEnabled(enabled); 316} 317 318void ClearGLBindingsGL() { 319 if (g_real_gl) { 320 delete g_real_gl; 321 g_real_gl = NULL; 322 } 323 if (g_trace_gl) { 324 delete g_trace_gl; 325 g_trace_gl = NULL; 326 } 327 if (g_no_context_gl) { 328 delete g_no_context_gl; 329 g_no_context_gl = NULL; 330 } 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; 336 } 337 if (g_version_info) { 338 delete g_version_info; 339 g_version_info = NULL; 340 } 341} 342 343GLApi::GLApi() { 344} 345 346GLApi::~GLApi() { 347 if (GetCurrentGLApi() == this) 348 SetGLApi(NULL); 349} 350 351GLApiBase::GLApiBase() 352 : driver_(NULL) { 353} 354 355GLApiBase::~GLApiBase() { 356} 357 358void GLApiBase::InitializeBase(DriverGL* driver) { 359 driver_ = driver; 360} 361 362void GLApiBase::SignalFlush() { 363 DCHECK(GLContext::GetCurrent()); 364 GLContext::GetCurrent()->OnFlush(); 365} 366 367RealGLApi::RealGLApi() { 368} 369 370RealGLApi::~RealGLApi() { 371} 372 373void RealGLApi::Initialize(DriverGL* driver) { 374 InitializeBase(driver); 375} 376 377void RealGLApi::glFlushFn() { 378 GLApiBase::glFlushFn(); 379 GLApiBase::SignalFlush(); 380} 381 382void RealGLApi::glFinishFn() { 383 GLApiBase::glFinishFn(); 384 GLApiBase::SignalFlush(); 385} 386 387TraceGLApi::~TraceGLApi() { 388} 389 390NoContextGLApi::NoContextGLApi() { 391} 392 393NoContextGLApi::~NoContextGLApi() { 394} 395 396VirtualGLApi::VirtualGLApi() 397 : real_context_(NULL), 398 current_context_(NULL) { 399} 400 401VirtualGLApi::~VirtualGLApi() { 402} 403 404void VirtualGLApi::Initialize(DriverGL* driver, GLContext* real_context) { 405 InitializeBase(driver); 406 real_context_ = real_context; 407 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); 413 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); 421 422 extensions_ = JoinString(ext, " "); 423} 424 425bool 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; 436 } 437 } 438 } 439 440 DCHECK_EQ(real_context_, GLContext::GetRealCurrent()); 441 DCHECK(real_context_->IsCurrent(NULL)); 442 DCHECK(virtual_context->IsCurrent(surface)); 443 444 if (switched_contexts || virtual_context != current_context_) { 445 // There should be no errors from the previous context leaking into the 446 // new context. 447 DCHECK_EQ(glGetErrorFn(), static_cast<GLenum>(GL_NO_ERROR)); 448 449 // Set all state that is different from the real state 450 GLApi* temp = GetCurrentGLApi(); 451 SetGLToRealGLApi(); 452 if (virtual_context->GetGLStateRestorer()->IsInitialized()) { 453 virtual_context->GetGLStateRestorer()->RestoreState( 454 (current_context_ && !switched_contexts) 455 ? current_context_->GetGLStateRestorer() 456 : NULL); 457 } 458 SetGLApi(temp); 459 current_context_ = virtual_context; 460 } 461 SetGLApi(this); 462 463 virtual_context->SetCurrent(surface); 464 if (!surface->OnMakeCurrent(virtual_context)) { 465 LOG(ERROR) << "Could not make GLSurface current."; 466 return false; 467 } 468 return true; 469} 470 471void VirtualGLApi::OnReleaseVirtuallyCurrent(GLContext* virtual_context) { 472 if (current_context_ == virtual_context) 473 current_context_ = NULL; 474} 475 476const GLubyte* VirtualGLApi::glGetStringFn(GLenum name) { 477 switch (name) { 478 case GL_EXTENSIONS: 479 return reinterpret_cast<const GLubyte*>(extensions_.c_str()); 480 default: 481 return driver_->fn.glGetStringFn(name); 482 } 483} 484 485void VirtualGLApi::glFlushFn() { 486 GLApiBase::glFlushFn(); 487 GLApiBase::SignalFlush(); 488} 489 490void VirtualGLApi::glFinishFn() { 491 GLApiBase::glFinishFn(); 492 GLApiBase::SignalFlush(); 493} 494 495ScopedSetGLToRealGLApi::ScopedSetGLToRealGLApi() 496 : old_gl_api_(GetCurrentGLApi()) { 497 SetGLToRealGLApi(); 498} 499 500ScopedSetGLToRealGLApi::~ScopedSetGLToRealGLApi() { 501 SetGLApi(old_gl_api_); 502} 503 504} // namespace gfx 505