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