Home | History | Annotate | Download | only in browser
      1 // Copyright 2013 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 "android_webview/browser/scoped_app_gl_state_restore.h"
      6 
      7 #include "base/debug/trace_event.h"
      8 #include "base/lazy_instance.h"
      9 #include "ui/gl/gl_context.h"
     10 #include "ui/gl/gl_surface_stub.h"
     11 
     12 namespace android_webview {
     13 
     14 namespace {
     15 
     16 // "App" context is a bit of a stretch. Basically we use this context while
     17 // saving and restoring the App GL state.
     18 class AppContextSurface {
     19  public:
     20   AppContextSurface()
     21       : surface(new gfx::GLSurfaceStub),
     22         context(gfx::GLContext::CreateGLContext(NULL,
     23                                                 surface.get(),
     24                                                 gfx::PreferDiscreteGpu)) {}
     25   void MakeCurrent() { context->MakeCurrent(surface.get()); }
     26 
     27  private:
     28   scoped_refptr<gfx::GLSurfaceStub> surface;
     29   scoped_refptr<gfx::GLContext> context;
     30 
     31   DISALLOW_COPY_AND_ASSIGN(AppContextSurface);
     32 };
     33 
     34 base::LazyInstance<AppContextSurface> g_app_context_surface =
     35     LAZY_INSTANCE_INITIALIZER;
     36 
     37 // Make the global g_app_context_surface current so that the gl_binding is not
     38 // NULL for making gl* calls. The binding can be null if another GlContext was
     39 // destroyed immediately before gl* calls here.
     40 void MakeAppContextCurrent() {
     41   g_app_context_surface.Get().MakeCurrent();
     42 }
     43 
     44 void GLEnableDisable(GLenum cap, bool enable) {
     45   if (enable)
     46     glEnable(cap);
     47   else
     48     glDisable(cap);
     49 }
     50 
     51 GLint g_gl_max_texture_units = 0;
     52 
     53 }  // namespace
     54 
     55 ScopedAppGLStateRestore::ScopedAppGLStateRestore(CallMode mode) : mode_(mode) {
     56   TRACE_EVENT0("android_webview", "AppGLStateSave");
     57   MakeAppContextCurrent();
     58 
     59   glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &vertex_array_buffer_binding_);
     60   glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &index_array_buffer_binding_);
     61 
     62   switch(mode_) {
     63     case MODE_DRAW:
     64       // TODO(boliu): These should always be 0 in draw case. When we have
     65       // guarantee that we are no longer making GL calls outside of draw, DCHECK
     66       // these are 0 here.
     67       LOG_IF(ERROR, vertex_array_buffer_binding_)
     68           << "GL_ARRAY_BUFFER_BINDING not zero in draw: "
     69           << vertex_array_buffer_binding_;
     70       LOG_IF(ERROR, index_array_buffer_binding_)
     71           << "GL_ELEMENT_ARRAY_BUFFER_BINDING not zero in draw: "
     72           << index_array_buffer_binding_;
     73 
     74       vertex_array_buffer_binding_ = 0;
     75       index_array_buffer_binding_ = 0;
     76       break;
     77     case MODE_RESOURCE_MANAGEMENT:
     78       glGetBooleanv(GL_BLEND, &blend_enabled_);
     79       glGetIntegerv(GL_BLEND_SRC_RGB, &blend_src_rgb_);
     80       glGetIntegerv(GL_BLEND_SRC_ALPHA, &blend_src_alpha_);
     81       glGetIntegerv(GL_BLEND_DST_RGB, &blend_dest_rgb_);
     82       glGetIntegerv(GL_BLEND_DST_ALPHA, &blend_dest_alpha_);
     83       glGetIntegerv(GL_VIEWPORT, viewport_);
     84       glGetBooleanv(GL_SCISSOR_TEST, &scissor_test_);
     85       glGetIntegerv(GL_SCISSOR_BOX, scissor_box_);
     86       break;
     87   }
     88 
     89   glGetIntegerv(GL_PACK_ALIGNMENT, &pack_alignment_);
     90   glGetIntegerv(GL_UNPACK_ALIGNMENT, &unpack_alignment_);
     91 
     92   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(vertex_attrib_); ++i) {
     93     glGetVertexAttribiv(
     94         i, GL_VERTEX_ATTRIB_ARRAY_ENABLED, &vertex_attrib_[i].enabled);
     95     glGetVertexAttribiv(
     96         i, GL_VERTEX_ATTRIB_ARRAY_SIZE, &vertex_attrib_[i].size);
     97     glGetVertexAttribiv(
     98         i, GL_VERTEX_ATTRIB_ARRAY_TYPE, &vertex_attrib_[i].type);
     99     glGetVertexAttribiv(
    100         i, GL_VERTEX_ATTRIB_ARRAY_NORMALIZED, &vertex_attrib_[i].normalized);
    101     glGetVertexAttribiv(
    102         i, GL_VERTEX_ATTRIB_ARRAY_STRIDE, &vertex_attrib_[i].stride);
    103     glGetVertexAttribPointerv(
    104         i, GL_VERTEX_ATTRIB_ARRAY_POINTER, &vertex_attrib_[i].pointer);
    105   }
    106 
    107   glGetBooleanv(GL_DEPTH_TEST, &depth_test_);
    108   glGetBooleanv(GL_CULL_FACE, &cull_face_);
    109   glGetIntegerv(GL_CULL_FACE_MODE, &cull_face_mode_);
    110   glGetBooleanv(GL_COLOR_WRITEMASK, color_mask_);
    111   glGetIntegerv(GL_CURRENT_PROGRAM, &current_program_);
    112   glGetFloatv(GL_COLOR_CLEAR_VALUE, color_clear_);
    113   glGetFloatv(GL_DEPTH_CLEAR_VALUE, &depth_clear_);
    114   glGetIntegerv(GL_DEPTH_FUNC, &depth_func_);
    115   glGetBooleanv(GL_DEPTH_WRITEMASK, &depth_mask_);
    116   glGetFloatv(GL_DEPTH_RANGE, depth_rage_);
    117   glGetIntegerv(GL_FRONT_FACE, &front_face_);
    118   glGetIntegerv(GL_GENERATE_MIPMAP_HINT, &hint_generate_mipmap_);
    119   glGetFloatv(GL_LINE_WIDTH, &line_width_);
    120   glGetFloatv(GL_POLYGON_OFFSET_FACTOR, &polygon_offset_factor_);
    121   glGetFloatv(GL_POLYGON_OFFSET_UNITS, &polygon_offset_units_);
    122   glGetFloatv(GL_SAMPLE_COVERAGE_VALUE, &sample_coverage_value_);
    123   glGetBooleanv(GL_SAMPLE_COVERAGE_INVERT, &sample_coverage_invert_);
    124 
    125   glGetBooleanv(GL_DITHER, &enable_dither_);
    126   glGetBooleanv(GL_POLYGON_OFFSET_FILL, &enable_polygon_offset_fill_);
    127   glGetBooleanv(GL_SAMPLE_ALPHA_TO_COVERAGE, &enable_sample_alpha_to_coverage_);
    128   glGetBooleanv(GL_SAMPLE_COVERAGE, &enable_sample_coverage_);
    129 
    130   glGetBooleanv(GL_STENCIL_TEST, &stencil_test_);
    131   glGetIntegerv(GL_STENCIL_FUNC, &stencil_func_);
    132   glGetIntegerv(GL_STENCIL_VALUE_MASK, &stencil_mask_);
    133   glGetIntegerv(GL_STENCIL_REF, &stencil_ref_);
    134 
    135   glGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT, &framebuffer_binding_ext_);
    136 
    137   if (!g_gl_max_texture_units) {
    138     glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &g_gl_max_texture_units);
    139     DCHECK_GT(g_gl_max_texture_units, 0);
    140   }
    141 
    142   glGetIntegerv(GL_ACTIVE_TEXTURE, &active_texture_);
    143 
    144   texture_bindings_.resize(g_gl_max_texture_units);
    145   for (int ii = 0; ii < g_gl_max_texture_units; ++ii) {
    146     glActiveTexture(GL_TEXTURE0 + ii);
    147     TextureBindings& bindings = texture_bindings_[ii];
    148     glGetIntegerv(GL_TEXTURE_BINDING_2D, &bindings.texture_2d);
    149     glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP, &bindings.texture_cube_map);
    150     glGetIntegerv(GL_TEXTURE_BINDING_EXTERNAL_OES,
    151                   &bindings.texture_external_oes);
    152   }
    153 }
    154 
    155 ScopedAppGLStateRestore::~ScopedAppGLStateRestore() {
    156   TRACE_EVENT0("android_webview", "AppGLStateRestore");
    157   MakeAppContextCurrent();
    158 
    159   glBindFramebufferEXT(GL_FRAMEBUFFER, framebuffer_binding_ext_);
    160   glBindBuffer(GL_ARRAY_BUFFER, vertex_array_buffer_binding_);
    161   glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_array_buffer_binding_);
    162 
    163   for (int ii = 0; ii < g_gl_max_texture_units; ++ii) {
    164     glActiveTexture(GL_TEXTURE0 + ii);
    165     TextureBindings& bindings = texture_bindings_[ii];
    166     glBindTexture(GL_TEXTURE_2D, bindings.texture_2d);
    167     glBindTexture(GL_TEXTURE_CUBE_MAP, bindings.texture_cube_map);
    168     glBindTexture(GL_TEXTURE_EXTERNAL_OES, bindings.texture_external_oes);
    169   }
    170   glActiveTexture(active_texture_);
    171 
    172   glPixelStorei(GL_PACK_ALIGNMENT, pack_alignment_);
    173   glPixelStorei(GL_UNPACK_ALIGNMENT, unpack_alignment_);
    174 
    175   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(vertex_attrib_); ++i) {
    176     glVertexAttribPointer(i,
    177                           vertex_attrib_[i].size,
    178                           vertex_attrib_[i].type,
    179                           vertex_attrib_[i].normalized,
    180                           vertex_attrib_[i].stride,
    181                           vertex_attrib_[i].pointer);
    182 
    183     if (vertex_attrib_[i].enabled) {
    184       glEnableVertexAttribArray(i);
    185     } else {
    186       glDisableVertexAttribArray(i);
    187     }
    188   }
    189 
    190   GLEnableDisable(GL_DEPTH_TEST, depth_test_);
    191 
    192   GLEnableDisable(GL_CULL_FACE, cull_face_);
    193   glCullFace(cull_face_mode_);
    194 
    195   glColorMask(color_mask_[0], color_mask_[1], color_mask_[2], color_mask_[3]);
    196 
    197   glUseProgram(current_program_);
    198 
    199   glClearColor(
    200       color_clear_[0], color_clear_[1], color_clear_[2], color_clear_[3]);
    201   glClearDepth(depth_clear_);
    202   glDepthFunc(depth_func_);
    203   glDepthMask(depth_mask_);
    204   glDepthRange(depth_rage_[0], depth_rage_[1]);
    205   glFrontFace(front_face_);
    206   glHint(GL_GENERATE_MIPMAP_HINT, hint_generate_mipmap_);
    207   // TODO(boliu): GL_FRAGMENT_SHADER_DERIVATIVE_HINT_OES ??
    208   glLineWidth(line_width_);
    209   glPolygonOffset(polygon_offset_factor_, polygon_offset_units_);
    210   glSampleCoverage(sample_coverage_value_, sample_coverage_invert_);
    211 
    212   GLEnableDisable(GL_DITHER, enable_dither_);
    213   GLEnableDisable(GL_POLYGON_OFFSET_FILL, enable_polygon_offset_fill_);
    214   GLEnableDisable(GL_SAMPLE_ALPHA_TO_COVERAGE,
    215                   enable_sample_alpha_to_coverage_);
    216   GLEnableDisable(GL_SAMPLE_COVERAGE, enable_sample_coverage_);
    217 
    218   switch(mode_) {
    219     case MODE_DRAW:
    220       // No-op.
    221       break;
    222     case MODE_RESOURCE_MANAGEMENT:
    223       GLEnableDisable(GL_BLEND, blend_enabled_);
    224       glBlendFuncSeparate(
    225           blend_src_rgb_, blend_dest_rgb_, blend_src_alpha_, blend_dest_alpha_);
    226 
    227       glViewport(viewport_[0], viewport_[1], viewport_[2], viewport_[3]);
    228 
    229       GLEnableDisable(GL_SCISSOR_TEST, scissor_test_);
    230 
    231       glScissor(
    232           scissor_box_[0], scissor_box_[1], scissor_box_[2], scissor_box_[3]);
    233       break;
    234   }
    235 
    236   GLEnableDisable(GL_STENCIL_TEST, stencil_test_);
    237   glStencilFunc(stencil_func_, stencil_mask_, stencil_ref_);
    238 }
    239 
    240 }  // namespace android_webview
    241