Home | History | Annotate | Download | only in gl
      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 ScopedSetGLToRealGLApi::ScopedSetGLToRealGLApi()
    496     : old_gl_api_(GetCurrentGLApi()) {
    497   SetGLToRealGLApi();
    498 }
    499 
    500 ScopedSetGLToRealGLApi::~ScopedSetGLToRealGLApi() {
    501   SetGLApi(old_gl_api_);
    502 }
    503 
    504 }  // namespace gfx
    505