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 GetTexInternalFormat(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 = GetTexInternalFormat(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 = GetTexInternalFormat(internalformat); 124 return g_driver_gl.orig_fn.glTexStorage2DEXTFn( 125 target, levels, gl_internal_format, width, height); 126 } 127 128 } // anonymous namespace 129 130 void DriverGL::Initialize() { 131 InitializeBindings(); 132 } 133 134 void DriverGL::InitializeExtensions(GLContext* context) { 135 InitializeExtensionBindings(context); 136 orig_fn = fn; 137 fn.glTexImage2DFn = 138 reinterpret_cast<glTexImage2DProc>(CustomTexImage2D); 139 fn.glTexSubImage2DFn = 140 reinterpret_cast<glTexSubImage2DProc>(CustomTexSubImage2D); 141 fn.glTexStorage2DEXTFn = 142 reinterpret_cast<glTexStorage2DEXTProc>(CustomTexStorage2DEXT); 143 } 144 145 void InitializeGLBindingsGL() { 146 g_current_gl_context_tls = new base::ThreadLocalPointer<GLApi>; 147 g_driver_gl.Initialize(); 148 if (!g_real_gl) { 149 g_real_gl = new RealGLApi(); 150 g_trace_gl = new TraceGLApi(g_real_gl); 151 } 152 g_real_gl->Initialize(&g_driver_gl); 153 g_gl = g_real_gl; 154 if (CommandLine::ForCurrentProcess()->HasSwitch( 155 switches::kEnableGPUServiceTracing)) { 156 g_gl = g_trace_gl; 157 } 158 SetGLToRealGLApi(); 159 } 160 161 GLApi* GetCurrentGLApi() { 162 return g_current_gl_context_tls->Get(); 163 } 164 165 void SetGLApi(GLApi* api) { 166 g_current_gl_context_tls->Set(api); 167 } 168 169 void SetGLToRealGLApi() { 170 SetGLApi(g_gl); 171 } 172 173 void InitializeGLExtensionBindingsGL(GLContext* context) { 174 g_driver_gl.InitializeExtensions(context); 175 } 176 177 void InitializeDebugGLBindingsGL() { 178 g_driver_gl.InitializeDebugBindings(); 179 } 180 181 void ClearGLBindingsGL() { 182 if (g_real_gl) { 183 delete g_real_gl; 184 g_real_gl = NULL; 185 } 186 if (g_trace_gl) { 187 delete g_trace_gl; 188 g_trace_gl = NULL; 189 } 190 g_gl = NULL; 191 g_driver_gl.ClearBindings(); 192 if (g_current_gl_context_tls) { 193 delete g_current_gl_context_tls; 194 g_current_gl_context_tls = NULL; 195 } 196 } 197 198 GLApi::GLApi() { 199 } 200 201 GLApi::~GLApi() { 202 if (GetCurrentGLApi() == this) 203 SetGLApi(NULL); 204 } 205 206 GLApiBase::GLApiBase() 207 : driver_(NULL) { 208 } 209 210 GLApiBase::~GLApiBase() { 211 } 212 213 void GLApiBase::InitializeBase(DriverGL* driver) { 214 driver_ = driver; 215 } 216 217 RealGLApi::RealGLApi() { 218 } 219 220 RealGLApi::~RealGLApi() { 221 } 222 223 void RealGLApi::Initialize(DriverGL* driver) { 224 InitializeBase(driver); 225 } 226 227 TraceGLApi::~TraceGLApi() { 228 } 229 230 VirtualGLApi::VirtualGLApi() 231 : real_context_(NULL), 232 current_context_(NULL) { 233 } 234 235 VirtualGLApi::~VirtualGLApi() { 236 } 237 238 void VirtualGLApi::Initialize(DriverGL* driver, GLContext* real_context) { 239 InitializeBase(driver); 240 real_context_ = real_context; 241 242 DCHECK(real_context->IsCurrent(NULL)); 243 std::string ext_string( 244 reinterpret_cast<const char*>(driver_->fn.glGetStringFn(GL_EXTENSIONS))); 245 std::vector<std::string> ext; 246 Tokenize(ext_string, " ", &ext); 247 248 std::vector<std::string>::iterator it; 249 // We can't support GL_EXT_occlusion_query_boolean which is 250 // based on GL_ARB_occlusion_query without a lot of work virtualizing 251 // queries. 252 it = std::find(ext.begin(), ext.end(), "GL_EXT_occlusion_query_boolean"); 253 if (it != ext.end()) 254 ext.erase(it); 255 256 extensions_ = JoinString(ext, " "); 257 } 258 259 bool VirtualGLApi::MakeCurrent(GLContext* virtual_context, GLSurface* surface) { 260 bool switched_contexts = g_current_gl_context_tls->Get() != this; 261 GLSurface* current_surface = GLSurface::GetCurrent(); 262 if (switched_contexts || surface != current_surface) { 263 // MakeCurrent 'lite' path that avoids potentially expensive MakeCurrent() 264 // calls if the GLSurface uses the same underlying surface or renders to 265 // an FBO. 266 if (switched_contexts || !current_surface || 267 !virtual_context->IsCurrent(surface)) { 268 if (!real_context_->MakeCurrent(surface)) { 269 return false; 270 } 271 } 272 } 273 274 DCHECK_EQ(real_context_, GLContext::GetRealCurrent()); 275 DCHECK(real_context_->IsCurrent(NULL)); 276 DCHECK(virtual_context->IsCurrent(surface)); 277 278 if (switched_contexts || virtual_context != current_context_) { 279 // There should be no errors from the previous context leaking into the 280 // new context. 281 DCHECK_EQ(glGetErrorFn(), static_cast<GLenum>(GL_NO_ERROR)); 282 283 current_context_ = virtual_context; 284 // Set all state that is different from the real state 285 // NOTE: !!! This is a temporary implementation that just restores all 286 // state to let us test that it works. 287 // TODO: ASAP, change this to something that only restores the state 288 // needed for individual GL calls. 289 GLApi* temp = GetCurrentGLApi(); 290 SetGLToRealGLApi(); 291 if (virtual_context->GetGLStateRestorer()->IsInitialized()) 292 virtual_context->GetGLStateRestorer()->RestoreState(); 293 SetGLApi(temp); 294 } 295 SetGLApi(this); 296 297 virtual_context->SetCurrent(surface); 298 if (!surface->OnMakeCurrent(virtual_context)) { 299 LOG(ERROR) << "Could not make GLSurface current."; 300 return false; 301 } 302 return true; 303 } 304 305 void VirtualGLApi::OnReleaseVirtuallyCurrent(GLContext* virtual_context) { 306 if (current_context_ == virtual_context) 307 current_context_ = NULL; 308 } 309 310 const GLubyte* VirtualGLApi::glGetStringFn(GLenum name) { 311 switch (name) { 312 case GL_EXTENSIONS: 313 return reinterpret_cast<const GLubyte*>(extensions_.c_str()); 314 default: 315 return driver_->fn.glGetStringFn(name); 316 } 317 } 318 319 } // namespace gfx 320