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 19 namespace gfx { 20 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; 32 33 namespace { 34 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; 39 } 40 return internal_format; 41 } 42 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); 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 (at) 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 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; 123 } 124 return type; 125 } 126 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); 137 } 138 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); 145 } 146 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); 153 } 154 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); 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. 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); 172 } 173 174 } // anonymous namespace 175 176 void 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 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); 211 } 212 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); 217 } 218 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); 225 } 226 227 void 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 243 bool DriverGL::HasInitializedNullDrawBindings() { 244 return orig_fn.glClearFn != NULL && orig_fn.glDrawArraysFn != NULL && 245 orig_fn.glDrawElementsFn != NULL; 246 } 247 248 bool 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 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(); 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 275 GLApi* GetCurrentGLApi() { 276 return g_current_gl_context_tls->Get(); 277 } 278 279 void SetGLApi(GLApi* api) { 280 g_current_gl_context_tls->Set(api); 281 } 282 283 void SetGLToRealGLApi() { 284 SetGLApi(g_gl); 285 } 286 287 void SetGLApiToNoContext() { 288 SetGLApi(g_no_context_gl); 289 } 290 291 const GLVersionInfo* GetGLVersionInfo() { 292 return g_version_info; 293 } 294 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()); 300 } 301 302 void InitializeDebugGLBindingsGL() { 303 g_driver_gl.InitializeDebugBindings(); 304 } 305 306 void InitializeNullDrawGLBindingsGL() { 307 g_driver_gl.InitializeNullDrawBindings(); 308 } 309 310 bool HasInitializedNullDrawGLBindingsGL() { 311 return g_driver_gl.HasInitializedNullDrawBindings(); 312 } 313 314 bool SetNullDrawGLBindingsEnabledGL(bool enabled) { 315 return g_driver_gl.SetNullDrawBindingsEnabled(enabled); 316 } 317 318 void 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 343 GLApi::GLApi() { 344 } 345 346 GLApi::~GLApi() { 347 if (GetCurrentGLApi() == this) 348 SetGLApi(NULL); 349 } 350 351 GLApiBase::GLApiBase() 352 : driver_(NULL) { 353 } 354 355 GLApiBase::~GLApiBase() { 356 } 357 358 void GLApiBase::InitializeBase(DriverGL* driver) { 359 driver_ = driver; 360 } 361 362 void GLApiBase::SignalFlush() { 363 DCHECK(GLContext::GetCurrent()); 364 GLContext::GetCurrent()->OnFlush(); 365 } 366 367 RealGLApi::RealGLApi() { 368 } 369 370 RealGLApi::~RealGLApi() { 371 } 372 373 void RealGLApi::Initialize(DriverGL* driver) { 374 InitializeBase(driver); 375 } 376 377 void RealGLApi::glFlushFn() { 378 GLApiBase::glFlushFn(); 379 GLApiBase::SignalFlush(); 380 } 381 382 void RealGLApi::glFinishFn() { 383 GLApiBase::glFinishFn(); 384 GLApiBase::SignalFlush(); 385 } 386 387 TraceGLApi::~TraceGLApi() { 388 } 389 390 NoContextGLApi::NoContextGLApi() { 391 } 392 393 NoContextGLApi::~NoContextGLApi() { 394 } 395 396 VirtualGLApi::VirtualGLApi() 397 : real_context_(NULL), 398 current_context_(NULL) { 399 } 400 401 VirtualGLApi::~VirtualGLApi() { 402 } 403 404 void 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 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; 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 471 void VirtualGLApi::OnReleaseVirtuallyCurrent(GLContext* virtual_context) { 472 if (current_context_ == virtual_context) 473 current_context_ = NULL; 474 } 475 476 const 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 485 void VirtualGLApi::glFlushFn() { 486 GLApiBase::glFlushFn(); 487 GLApiBase::SignalFlush(); 488 } 489 490 void VirtualGLApi::glFinishFn() { 491 GLApiBase::glFinishFn(); 492 GLApiBase::SignalFlush(); 493 } 494 495 } // namespace gfx 496