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 
     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