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, ¤t_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