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 18 namespace gfx { 19 20 // The GL Api being used. This could be g_real_gl or gl_trace_gl 21 static GLApi* g_gl; 22 // A GL Api that calls directly into the driver. 23 static RealGLApi* g_real_gl; 24 // A GL Api that calls TRACE and then calls another GL api. 25 static TraceGLApi* g_trace_gl; 26 27 namespace { 28 29 static inline GLenum GetInternalFormat(GLenum internal_format) { 30 if (gfx::GetGLImplementation() != gfx::kGLImplementationEGLGLES2) { 31 if (internal_format == GL_BGRA_EXT || internal_format == GL_BGRA8_EXT) 32 return GL_RGBA8; 33 } 34 return internal_format; 35 } 36 37 // TODO(epenner): Could the above function be merged into this and removed? 38 static inline GLenum GetTexInternalFormat(GLenum internal_format, 39 GLenum format, 40 GLenum type) { 41 GLenum gl_internal_format = GetInternalFormat(internal_format); 42 43 if (gfx::GetGLImplementation() == gfx::kGLImplementationEGLGLES2) 44 return gl_internal_format; 45 46 if (type == GL_FLOAT) { 47 switch (format) { 48 case GL_RGBA: 49 gl_internal_format = GL_RGBA32F_ARB; 50 break; 51 case GL_RGB: 52 gl_internal_format = GL_RGB32F_ARB; 53 break; 54 case GL_LUMINANCE_ALPHA: 55 gl_internal_format = GL_LUMINANCE_ALPHA32F_ARB; 56 break; 57 case GL_LUMINANCE: 58 gl_internal_format = GL_LUMINANCE32F_ARB; 59 break; 60 case GL_ALPHA: 61 gl_internal_format = GL_ALPHA32F_ARB; 62 break; 63 default: 64 NOTREACHED(); 65 break; 66 } 67 } else if (type == GL_HALF_FLOAT_OES) { 68 switch (format) { 69 case GL_RGBA: 70 gl_internal_format = GL_RGBA16F_ARB; 71 break; 72 case GL_RGB: 73 gl_internal_format = GL_RGB16F_ARB; 74 break; 75 case GL_LUMINANCE_ALPHA: 76 gl_internal_format = GL_LUMINANCE_ALPHA16F_ARB; 77 break; 78 case GL_LUMINANCE: 79 gl_internal_format = GL_LUMINANCE16F_ARB; 80 break; 81 case GL_ALPHA: 82 gl_internal_format = GL_ALPHA16F_ARB; 83 break; 84 default: 85 NOTREACHED(); 86 break; 87 } 88 } 89 return gl_internal_format; 90 } 91 92 static inline GLenum GetTexType(GLenum type) { 93 if (gfx::GetGLImplementation() != gfx::kGLImplementationEGLGLES2) { 94 if (type == GL_HALF_FLOAT_OES) 95 return GL_HALF_FLOAT_ARB; 96 } 97 return type; 98 } 99 100 static void GL_BINDING_CALL CustomTexImage2D( 101 GLenum target, GLint level, GLint internalformat, 102 GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, 103 const void* pixels) { 104 GLenum gl_internal_format = GetTexInternalFormat( 105 internalformat, format, type); 106 GLenum gl_type = GetTexType(type); 107 return g_driver_gl.orig_fn.glTexImage2DFn( 108 target, level, gl_internal_format, width, height, border, format, gl_type, 109 pixels); 110 } 111 112 static void GL_BINDING_CALL CustomTexSubImage2D( 113 GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, 114 GLsizei height, GLenum format, GLenum type, const void* pixels) { 115 GLenum gl_type = GetTexType(type); 116 return g_driver_gl.orig_fn.glTexSubImage2DFn( 117 target, level, xoffset, yoffset, width, height, format, gl_type, pixels); 118 } 119 120 static void GL_BINDING_CALL CustomTexStorage2DEXT( 121 GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, 122 GLsizei height) { 123 GLenum gl_internal_format = GetInternalFormat(internalformat); 124 return g_driver_gl.orig_fn.glTexStorage2DEXTFn( 125 target, levels, gl_internal_format, width, height); 126 } 127 128 static void GL_BINDING_CALL CustomRenderbufferStorageEXT( 129 GLenum target, GLenum internalformat, GLsizei width, GLsizei height) { 130 GLenum gl_internal_format = GetInternalFormat(internalformat); 131 return g_driver_gl.orig_fn.glRenderbufferStorageEXTFn( 132 target, gl_internal_format, width, height); 133 } 134 135 // The ANGLE and IMG variants of glRenderbufferStorageMultisample currently do 136 // not support BGRA render buffers so only the EXT one is customized. If 137 // GL_CHROMIUM_renderbuffer_format_BGRA8888 support is added to ANGLE then the 138 // ANGLE version should also be customized. 139 static void GL_BINDING_CALL CustomRenderbufferStorageMultisampleEXT( 140 GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, 141 GLsizei height) { 142 GLenum gl_internal_format = GetInternalFormat(internalformat); 143 return g_driver_gl.orig_fn.glRenderbufferStorageMultisampleEXTFn( 144 target, samples, gl_internal_format, width, height); 145 } 146 147 } // anonymous namespace 148 149 void DriverGL::Initialize() { 150 InitializeBindings(); 151 } 152 153 void DriverGL::InitializeExtensions(GLContext* context) { 154 InitializeExtensionBindings(context); 155 orig_fn = fn; 156 fn.glTexImage2DFn = 157 reinterpret_cast<glTexImage2DProc>(CustomTexImage2D); 158 fn.glTexSubImage2DFn = 159 reinterpret_cast<glTexSubImage2DProc>(CustomTexSubImage2D); 160 fn.glTexStorage2DEXTFn = 161 reinterpret_cast<glTexStorage2DEXTProc>(CustomTexStorage2DEXT); 162 fn.glRenderbufferStorageEXTFn = 163 reinterpret_cast<glRenderbufferStorageEXTProc>( 164 CustomRenderbufferStorageEXT); 165 fn.glRenderbufferStorageMultisampleEXTFn = 166 reinterpret_cast<glRenderbufferStorageMultisampleEXTProc>( 167 CustomRenderbufferStorageMultisampleEXT); 168 } 169 170 void InitializeGLBindingsGL() { 171 g_current_gl_context_tls = new base::ThreadLocalPointer<GLApi>; 172 g_driver_gl.Initialize(); 173 if (!g_real_gl) { 174 g_real_gl = new RealGLApi(); 175 g_trace_gl = new TraceGLApi(g_real_gl); 176 } 177 g_real_gl->Initialize(&g_driver_gl); 178 g_gl = g_real_gl; 179 if (CommandLine::ForCurrentProcess()->HasSwitch( 180 switches::kEnableGPUServiceTracing)) { 181 g_gl = g_trace_gl; 182 } 183 SetGLToRealGLApi(); 184 } 185 186 GLApi* GetCurrentGLApi() { 187 return g_current_gl_context_tls->Get(); 188 } 189 190 void SetGLApi(GLApi* api) { 191 g_current_gl_context_tls->Set(api); 192 } 193 194 void SetGLToRealGLApi() { 195 SetGLApi(g_gl); 196 } 197 198 void InitializeGLExtensionBindingsGL(GLContext* context) { 199 g_driver_gl.InitializeExtensions(context); 200 } 201 202 void InitializeDebugGLBindingsGL() { 203 g_driver_gl.InitializeDebugBindings(); 204 } 205 206 void ClearGLBindingsGL() { 207 if (g_real_gl) { 208 delete g_real_gl; 209 g_real_gl = NULL; 210 } 211 if (g_trace_gl) { 212 delete g_trace_gl; 213 g_trace_gl = NULL; 214 } 215 g_gl = NULL; 216 g_driver_gl.ClearBindings(); 217 if (g_current_gl_context_tls) { 218 delete g_current_gl_context_tls; 219 g_current_gl_context_tls = NULL; 220 } 221 } 222 223 GLApi::GLApi() { 224 } 225 226 GLApi::~GLApi() { 227 if (GetCurrentGLApi() == this) 228 SetGLApi(NULL); 229 } 230 231 GLApiBase::GLApiBase() 232 : driver_(NULL) { 233 } 234 235 GLApiBase::~GLApiBase() { 236 } 237 238 void GLApiBase::InitializeBase(DriverGL* driver) { 239 driver_ = driver; 240 } 241 242 RealGLApi::RealGLApi() { 243 } 244 245 RealGLApi::~RealGLApi() { 246 } 247 248 void RealGLApi::Initialize(DriverGL* driver) { 249 InitializeBase(driver); 250 } 251 252 TraceGLApi::~TraceGLApi() { 253 } 254 255 VirtualGLApi::VirtualGLApi() 256 : real_context_(NULL), 257 current_context_(NULL) { 258 } 259 260 VirtualGLApi::~VirtualGLApi() { 261 } 262 263 void VirtualGLApi::Initialize(DriverGL* driver, GLContext* real_context) { 264 InitializeBase(driver); 265 real_context_ = real_context; 266 267 DCHECK(real_context->IsCurrent(NULL)); 268 std::string ext_string( 269 reinterpret_cast<const char*>(driver_->fn.glGetStringFn(GL_EXTENSIONS))); 270 std::vector<std::string> ext; 271 Tokenize(ext_string, " ", &ext); 272 273 std::vector<std::string>::iterator it; 274 // We can't support GL_EXT_occlusion_query_boolean which is 275 // based on GL_ARB_occlusion_query without a lot of work virtualizing 276 // queries. 277 it = std::find(ext.begin(), ext.end(), "GL_EXT_occlusion_query_boolean"); 278 if (it != ext.end()) 279 ext.erase(it); 280 281 extensions_ = JoinString(ext, " "); 282 } 283 284 bool VirtualGLApi::MakeCurrent(GLContext* virtual_context, GLSurface* surface) { 285 bool switched_contexts = g_current_gl_context_tls->Get() != this; 286 GLSurface* current_surface = GLSurface::GetCurrent(); 287 if (switched_contexts || surface != current_surface) { 288 // MakeCurrent 'lite' path that avoids potentially expensive MakeCurrent() 289 // calls if the GLSurface uses the same underlying surface or renders to 290 // an FBO. 291 if (switched_contexts || !current_surface || 292 !virtual_context->IsCurrent(surface)) { 293 if (!real_context_->MakeCurrent(surface)) { 294 return false; 295 } 296 } 297 } 298 299 DCHECK_EQ(real_context_, GLContext::GetRealCurrent()); 300 DCHECK(real_context_->IsCurrent(NULL)); 301 DCHECK(virtual_context->IsCurrent(surface)); 302 303 if (switched_contexts || virtual_context != current_context_) { 304 // There should be no errors from the previous context leaking into the 305 // new context. 306 DCHECK_EQ(glGetErrorFn(), static_cast<GLenum>(GL_NO_ERROR)); 307 308 current_context_ = virtual_context; 309 // Set all state that is different from the real state 310 // NOTE: !!! This is a temporary implementation that just restores all 311 // state to let us test that it works. 312 // TODO: ASAP, change this to something that only restores the state 313 // needed for individual GL calls. 314 GLApi* temp = GetCurrentGLApi(); 315 SetGLToRealGLApi(); 316 if (virtual_context->GetGLStateRestorer()->IsInitialized()) 317 virtual_context->GetGLStateRestorer()->RestoreState(); 318 SetGLApi(temp); 319 } 320 SetGLApi(this); 321 322 virtual_context->SetCurrent(surface); 323 if (!surface->OnMakeCurrent(virtual_context)) { 324 LOG(ERROR) << "Could not make GLSurface current."; 325 return false; 326 } 327 return true; 328 } 329 330 void VirtualGLApi::OnReleaseVirtuallyCurrent(GLContext* virtual_context) { 331 if (current_context_ == virtual_context) 332 current_context_ = NULL; 333 } 334 335 const GLubyte* VirtualGLApi::glGetStringFn(GLenum name) { 336 switch (name) { 337 case GL_EXTENSIONS: 338 return reinterpret_cast<const GLubyte*>(extensions_.c_str()); 339 default: 340 return driver_->fn.glGetStringFn(name); 341 } 342 } 343 344 } // namespace gfx 345