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 <string> 8 9#include "base/debug/trace_event.h" 10#include "base/lazy_instance.h" 11#include "ui/gl/gl_bindings.h" 12#include "ui/gl/gl_context.h" 13#include "ui/gl/gl_surface_stub.h" 14 15namespace android_webview { 16 17namespace { 18 19// "App" context is a bit of a stretch. Basically we use this context while 20// saving and restoring the App GL state. 21class AppContextSurface { 22 public: 23 AppContextSurface() 24 : surface(new gfx::GLSurfaceStub), 25 context(gfx::GLContext::CreateGLContext(NULL, 26 surface.get(), 27 gfx::PreferDiscreteGpu)) {} 28 void MakeCurrent() { context->MakeCurrent(surface.get()); } 29 30 private: 31 scoped_refptr<gfx::GLSurfaceStub> surface; 32 scoped_refptr<gfx::GLContext> context; 33 34 DISALLOW_COPY_AND_ASSIGN(AppContextSurface); 35}; 36 37base::LazyInstance<AppContextSurface> g_app_context_surface = 38 LAZY_INSTANCE_INITIALIZER; 39 40// Make the global g_app_context_surface current so that the gl_binding is not 41// NULL for making gl* calls. The binding can be null if another GlContext was 42// destroyed immediately before gl* calls here. 43void MakeAppContextCurrent() { 44 g_app_context_surface.Get().MakeCurrent(); 45} 46 47void GLEnableDisable(GLenum cap, bool enable) { 48 if (enable) 49 glEnable(cap); 50 else 51 glDisable(cap); 52} 53 54bool ClearGLErrors(bool warn, const char* msg) { 55 bool no_error = true; 56 GLenum error; 57 while ((error = glGetError()) != GL_NO_ERROR) { 58 DLOG_IF(WARNING, warn) << error << " " << msg; 59 no_error = false; 60 } 61 62 return no_error; 63} 64 65bool g_globals_initialized = false; 66GLint g_gl_max_texture_units = 0; 67bool g_supports_oes_vertex_array_object = false; 68 69} // namespace 70 71namespace internal { 72 73class ScopedAppGLStateRestoreImpl { 74 public: 75 ScopedAppGLStateRestoreImpl(ScopedAppGLStateRestore::CallMode mode); 76 ~ScopedAppGLStateRestoreImpl(); 77 78 bool stencil_enabled() const { return stencil_test_; } 79 GLint framebuffer_binding_ext() const { return framebuffer_binding_ext_; } 80 81 private: 82 const ScopedAppGLStateRestore::CallMode mode_; 83 84 GLint pack_alignment_; 85 GLint unpack_alignment_; 86 87 struct { 88 GLint enabled; 89 GLint size; 90 GLint type; 91 GLint normalized; 92 GLint stride; 93 GLvoid* pointer; 94 GLint vertex_attrib_array_buffer_binding; 95 GLfloat current_vertex_attrib[4]; 96 } vertex_attrib_[3]; 97 98 GLint vertex_array_buffer_binding_; 99 GLint index_array_buffer_binding_; 100 101 GLboolean depth_test_; 102 GLboolean cull_face_; 103 GLint cull_face_mode_; 104 GLboolean color_mask_[4]; 105 GLfloat color_clear_[4]; 106 GLfloat blend_color_[4]; 107 GLfloat depth_clear_; 108 GLint current_program_; 109 GLint depth_func_; 110 GLboolean depth_mask_; 111 GLfloat depth_rage_[2]; 112 GLint front_face_; 113 GLint hint_generate_mipmap_; 114 GLfloat line_width_; 115 GLfloat polygon_offset_factor_; 116 GLfloat polygon_offset_units_; 117 GLfloat sample_coverage_value_; 118 GLboolean sample_coverage_invert_; 119 GLint blend_equation_rgb_; 120 GLint blend_equation_alpha_; 121 122 GLboolean enable_dither_; 123 GLboolean enable_polygon_offset_fill_; 124 GLboolean enable_sample_alpha_to_coverage_; 125 GLboolean enable_sample_coverage_; 126 127 // Not saved/restored in MODE_DRAW. 128 GLboolean blend_enabled_; 129 GLint blend_src_rgb_; 130 GLint blend_src_alpha_; 131 GLint blend_dest_rgb_; 132 GLint blend_dest_alpha_; 133 GLint active_texture_; 134 GLint viewport_[4]; 135 GLboolean scissor_test_; 136 GLint scissor_box_[4]; 137 138 GLboolean stencil_test_; 139 GLint stencil_front_func_; 140 GLint stencil_front_ref_; 141 GLint stencil_front_mask_; 142 GLint stencil_back_func_; 143 GLint stencil_back_ref_; 144 GLint stencil_back_mask_; 145 GLint stencil_clear_; 146 GLint stencil_front_writemask_; 147 GLint stencil_back_writemask_; 148 GLint stencil_front_fail_op_; 149 GLint stencil_front_z_fail_op_; 150 GLint stencil_front_z_pass_op_; 151 GLint stencil_back_fail_op_; 152 GLint stencil_back_z_fail_op_; 153 GLint stencil_back_z_pass_op_; 154 155 GLint framebuffer_binding_ext_; 156 157 struct TextureBindings { 158 GLint texture_2d; 159 GLint texture_cube_map; 160 GLint texture_external_oes; 161 // TODO(boliu): TEXTURE_RECTANGLE_ARB 162 }; 163 164 std::vector<TextureBindings> texture_bindings_; 165 166 GLint vertex_array_bindings_oes_; 167 168 DISALLOW_COPY_AND_ASSIGN(ScopedAppGLStateRestoreImpl); 169}; 170 171ScopedAppGLStateRestoreImpl::ScopedAppGLStateRestoreImpl( 172 ScopedAppGLStateRestore::CallMode mode) 173 : mode_(mode) { 174 TRACE_EVENT0("android_webview", "AppGLStateSave"); 175 MakeAppContextCurrent(); 176 177 ClearGLErrors(true, "Incoming GLError"); 178 179 if (!g_globals_initialized) { 180 g_globals_initialized = true; 181 182 glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &g_gl_max_texture_units); 183 DCHECK_GT(g_gl_max_texture_units, 0); 184 185 std::string extensions( 186 reinterpret_cast<const char*>(glGetString(GL_EXTENSIONS))); 187 g_supports_oes_vertex_array_object = 188 extensions.find("GL_OES_vertex_array_object") != std::string::npos; 189 } 190 191 glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &vertex_array_buffer_binding_); 192 glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &index_array_buffer_binding_); 193 194 switch(mode_) { 195 case ScopedAppGLStateRestore::MODE_DRAW: 196 DCHECK_EQ(0, vertex_array_buffer_binding_); 197 DCHECK_EQ(0, index_array_buffer_binding_); 198 break; 199 case ScopedAppGLStateRestore::MODE_RESOURCE_MANAGEMENT: 200 glGetBooleanv(GL_BLEND, &blend_enabled_); 201 glGetIntegerv(GL_BLEND_SRC_RGB, &blend_src_rgb_); 202 glGetIntegerv(GL_BLEND_SRC_ALPHA, &blend_src_alpha_); 203 glGetIntegerv(GL_BLEND_DST_RGB, &blend_dest_rgb_); 204 glGetIntegerv(GL_BLEND_DST_ALPHA, &blend_dest_alpha_); 205 glGetIntegerv(GL_VIEWPORT, viewport_); 206 glGetBooleanv(GL_SCISSOR_TEST, &scissor_test_); 207 glGetIntegerv(GL_SCISSOR_BOX, scissor_box_); 208 break; 209 } 210 211 glGetIntegerv(GL_PACK_ALIGNMENT, &pack_alignment_); 212 glGetIntegerv(GL_UNPACK_ALIGNMENT, &unpack_alignment_); 213 214 glGetBooleanv(GL_DEPTH_TEST, &depth_test_); 215 glGetBooleanv(GL_CULL_FACE, &cull_face_); 216 glGetIntegerv(GL_CULL_FACE_MODE, &cull_face_mode_); 217 glGetBooleanv(GL_COLOR_WRITEMASK, color_mask_); 218 glGetIntegerv(GL_CURRENT_PROGRAM, ¤t_program_); 219 glGetFloatv(GL_COLOR_CLEAR_VALUE, color_clear_); 220 glGetFloatv(GL_DEPTH_CLEAR_VALUE, &depth_clear_); 221 glGetFloatv(GL_BLEND_COLOR, blend_color_); 222 glGetIntegerv(GL_DEPTH_FUNC, &depth_func_); 223 glGetBooleanv(GL_DEPTH_WRITEMASK, &depth_mask_); 224 glGetFloatv(GL_DEPTH_RANGE, depth_rage_); 225 glGetIntegerv(GL_FRONT_FACE, &front_face_); 226 glGetIntegerv(GL_GENERATE_MIPMAP_HINT, &hint_generate_mipmap_); 227 glGetFloatv(GL_LINE_WIDTH, &line_width_); 228 glGetFloatv(GL_POLYGON_OFFSET_FACTOR, &polygon_offset_factor_); 229 glGetFloatv(GL_POLYGON_OFFSET_UNITS, &polygon_offset_units_); 230 glGetFloatv(GL_SAMPLE_COVERAGE_VALUE, &sample_coverage_value_); 231 glGetBooleanv(GL_SAMPLE_COVERAGE_INVERT, &sample_coverage_invert_); 232 glGetIntegerv(GL_BLEND_EQUATION_RGB, &blend_equation_rgb_); 233 glGetIntegerv(GL_BLEND_EQUATION_ALPHA, &blend_equation_alpha_); 234 235 glGetBooleanv(GL_DITHER, &enable_dither_); 236 glGetBooleanv(GL_POLYGON_OFFSET_FILL, &enable_polygon_offset_fill_); 237 glGetBooleanv(GL_SAMPLE_ALPHA_TO_COVERAGE, &enable_sample_alpha_to_coverage_); 238 glGetBooleanv(GL_SAMPLE_COVERAGE, &enable_sample_coverage_); 239 240 glGetBooleanv(GL_STENCIL_TEST, &stencil_test_); 241 glGetIntegerv(GL_STENCIL_FUNC, &stencil_front_func_); 242 glGetIntegerv(GL_STENCIL_VALUE_MASK, &stencil_front_mask_); 243 glGetIntegerv(GL_STENCIL_REF, &stencil_front_ref_); 244 glGetIntegerv(GL_STENCIL_BACK_FUNC, &stencil_back_func_); 245 glGetIntegerv(GL_STENCIL_BACK_VALUE_MASK, &stencil_back_mask_); 246 glGetIntegerv(GL_STENCIL_BACK_REF, &stencil_back_ref_); 247 glGetIntegerv(GL_STENCIL_CLEAR_VALUE, &stencil_clear_); 248 glGetIntegerv(GL_STENCIL_WRITEMASK, &stencil_front_writemask_); 249 glGetIntegerv(GL_STENCIL_BACK_WRITEMASK, &stencil_back_writemask_); 250 glGetIntegerv(GL_STENCIL_FAIL, &stencil_front_fail_op_); 251 glGetIntegerv(GL_STENCIL_PASS_DEPTH_FAIL, &stencil_front_z_fail_op_); 252 glGetIntegerv(GL_STENCIL_PASS_DEPTH_PASS, &stencil_front_z_pass_op_); 253 glGetIntegerv(GL_STENCIL_BACK_FAIL, &stencil_back_fail_op_); 254 glGetIntegerv(GL_STENCIL_BACK_PASS_DEPTH_FAIL, &stencil_back_z_fail_op_); 255 glGetIntegerv(GL_STENCIL_BACK_PASS_DEPTH_PASS, &stencil_back_z_pass_op_); 256 257 glGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT, &framebuffer_binding_ext_); 258 259 glGetIntegerv(GL_ACTIVE_TEXTURE, &active_texture_); 260 261 texture_bindings_.resize(g_gl_max_texture_units); 262 for (int ii = 0; ii < g_gl_max_texture_units; ++ii) { 263 glActiveTexture(GL_TEXTURE0 + ii); 264 TextureBindings& bindings = texture_bindings_[ii]; 265 glGetIntegerv(GL_TEXTURE_BINDING_2D, &bindings.texture_2d); 266 glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP, &bindings.texture_cube_map); 267 glGetIntegerv(GL_TEXTURE_BINDING_EXTERNAL_OES, 268 &bindings.texture_external_oes); 269 } 270 271 if (g_supports_oes_vertex_array_object) { 272 glGetIntegerv(GL_VERTEX_ARRAY_BINDING_OES, &vertex_array_bindings_oes_); 273 glBindVertexArrayOES(0); 274 } 275 276 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(vertex_attrib_); ++i) { 277 glGetVertexAttribiv( 278 i, GL_VERTEX_ATTRIB_ARRAY_ENABLED, &vertex_attrib_[i].enabled); 279 glGetVertexAttribiv( 280 i, GL_VERTEX_ATTRIB_ARRAY_SIZE, &vertex_attrib_[i].size); 281 glGetVertexAttribiv( 282 i, GL_VERTEX_ATTRIB_ARRAY_TYPE, &vertex_attrib_[i].type); 283 glGetVertexAttribiv( 284 i, GL_VERTEX_ATTRIB_ARRAY_NORMALIZED, &vertex_attrib_[i].normalized); 285 glGetVertexAttribiv( 286 i, GL_VERTEX_ATTRIB_ARRAY_STRIDE, &vertex_attrib_[i].stride); 287 glGetVertexAttribPointerv( 288 i, GL_VERTEX_ATTRIB_ARRAY_POINTER, &vertex_attrib_[i].pointer); 289 glGetVertexAttribPointerv( 290 i, GL_VERTEX_ATTRIB_ARRAY_POINTER, &vertex_attrib_[i].pointer); 291 glGetVertexAttribiv(i, 292 GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, 293 &vertex_attrib_[i].vertex_attrib_array_buffer_binding); 294 glGetVertexAttribfv( 295 i, GL_CURRENT_VERTEX_ATTRIB, vertex_attrib_[i].current_vertex_attrib); 296 } 297 298 // Android 5.0.0 specific qualcomm workaround. See crbug.com/434570. 299 glBindRenderbufferEXT(GL_RENDERBUFFER, 0); 300 DCHECK(ClearGLErrors(false, NULL)); 301} 302 303ScopedAppGLStateRestoreImpl::~ScopedAppGLStateRestoreImpl() { 304 TRACE_EVENT0("android_webview", "AppGLStateRestore"); 305 MakeAppContextCurrent(); 306 307 DCHECK(ClearGLErrors(false, NULL)); 308 309 glBindFramebufferEXT(GL_FRAMEBUFFER, framebuffer_binding_ext_); 310 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_array_buffer_binding_); 311 312 if (g_supports_oes_vertex_array_object) 313 glBindVertexArrayOES(0); 314 315 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(vertex_attrib_); ++i) { 316 glBindBuffer(GL_ARRAY_BUFFER, 317 vertex_attrib_[i].vertex_attrib_array_buffer_binding); 318 glVertexAttribPointer(i, 319 vertex_attrib_[i].size, 320 vertex_attrib_[i].type, 321 vertex_attrib_[i].normalized, 322 vertex_attrib_[i].stride, 323 vertex_attrib_[i].pointer); 324 325 glVertexAttrib4fv(i, vertex_attrib_[i].current_vertex_attrib); 326 327 if (vertex_attrib_[i].enabled) { 328 glEnableVertexAttribArray(i); 329 } else { 330 glDisableVertexAttribArray(i); 331 } 332 } 333 334 if (g_supports_oes_vertex_array_object && vertex_array_bindings_oes_ != 0) 335 glBindVertexArrayOES(vertex_array_bindings_oes_); 336 337 glBindBuffer(GL_ARRAY_BUFFER, vertex_array_buffer_binding_); 338 339 for (int ii = 0; ii < g_gl_max_texture_units; ++ii) { 340 glActiveTexture(GL_TEXTURE0 + ii); 341 TextureBindings& bindings = texture_bindings_[ii]; 342 glBindTexture(GL_TEXTURE_2D, bindings.texture_2d); 343 glBindTexture(GL_TEXTURE_CUBE_MAP, bindings.texture_cube_map); 344 glBindTexture(GL_TEXTURE_EXTERNAL_OES, bindings.texture_external_oes); 345 } 346 glActiveTexture(active_texture_); 347 348 glPixelStorei(GL_PACK_ALIGNMENT, pack_alignment_); 349 glPixelStorei(GL_UNPACK_ALIGNMENT, unpack_alignment_); 350 351 GLEnableDisable(GL_DEPTH_TEST, depth_test_); 352 353 GLEnableDisable(GL_CULL_FACE, cull_face_); 354 glCullFace(cull_face_mode_); 355 356 glColorMask(color_mask_[0], color_mask_[1], color_mask_[2], color_mask_[3]); 357 358 glUseProgram(current_program_); 359 360 glClearColor( 361 color_clear_[0], color_clear_[1], color_clear_[2], color_clear_[3]); 362 glBlendColor( 363 blend_color_[0], blend_color_[1], blend_color_[2], blend_color_[3]); 364 glClearDepth(depth_clear_); 365 glDepthFunc(depth_func_); 366 glDepthMask(depth_mask_); 367 glDepthRange(depth_rage_[0], depth_rage_[1]); 368 glFrontFace(front_face_); 369 glHint(GL_GENERATE_MIPMAP_HINT, hint_generate_mipmap_); 370 // TODO(boliu): GL_FRAGMENT_SHADER_DERIVATIVE_HINT_OES ?? 371 glLineWidth(line_width_); 372 glPolygonOffset(polygon_offset_factor_, polygon_offset_units_); 373 glSampleCoverage(sample_coverage_value_, sample_coverage_invert_); 374 glBlendEquationSeparate(blend_equation_rgb_, blend_equation_alpha_); 375 376 GLEnableDisable(GL_DITHER, enable_dither_); 377 GLEnableDisable(GL_POLYGON_OFFSET_FILL, enable_polygon_offset_fill_); 378 GLEnableDisable(GL_SAMPLE_ALPHA_TO_COVERAGE, 379 enable_sample_alpha_to_coverage_); 380 GLEnableDisable(GL_SAMPLE_COVERAGE, enable_sample_coverage_); 381 382 switch(mode_) { 383 case ScopedAppGLStateRestore::MODE_DRAW: 384 // No-op. 385 break; 386 case ScopedAppGLStateRestore::MODE_RESOURCE_MANAGEMENT: 387 GLEnableDisable(GL_BLEND, blend_enabled_); 388 glBlendFuncSeparate( 389 blend_src_rgb_, blend_dest_rgb_, blend_src_alpha_, blend_dest_alpha_); 390 391 glViewport(viewport_[0], viewport_[1], viewport_[2], viewport_[3]); 392 393 GLEnableDisable(GL_SCISSOR_TEST, scissor_test_); 394 395 glScissor( 396 scissor_box_[0], scissor_box_[1], scissor_box_[2], scissor_box_[3]); 397 break; 398 } 399 400 GLEnableDisable(GL_STENCIL_TEST, stencil_test_); 401 glStencilFuncSeparate( 402 GL_FRONT, stencil_front_func_, stencil_front_mask_, stencil_front_ref_); 403 glStencilFuncSeparate( 404 GL_BACK, stencil_back_func_, stencil_back_mask_, stencil_back_ref_); 405 glClearStencil(stencil_clear_); 406 glStencilMaskSeparate(GL_FRONT, stencil_front_writemask_); 407 glStencilMaskSeparate(GL_BACK, stencil_back_writemask_); 408 glStencilOpSeparate(GL_FRONT, 409 stencil_front_fail_op_, 410 stencil_front_z_fail_op_, 411 stencil_front_z_pass_op_); 412 glStencilOpSeparate(GL_BACK, 413 stencil_back_fail_op_, 414 stencil_back_z_fail_op_, 415 stencil_back_z_pass_op_); 416 417 // Do not leak GLError out of chromium. 418 ClearGLErrors(true, "Chromium GLError"); 419} 420 421} // namespace internal 422 423ScopedAppGLStateRestore::ScopedAppGLStateRestore(CallMode mode) 424 : impl_(new internal::ScopedAppGLStateRestoreImpl(mode)) { 425} 426 427ScopedAppGLStateRestore::~ScopedAppGLStateRestore() {} 428 429bool ScopedAppGLStateRestore::stencil_enabled() const { 430 return impl_->stencil_enabled(); 431} 432int ScopedAppGLStateRestore::framebuffer_binding_ext() const { 433 return impl_->framebuffer_binding_ext(); 434} 435 436} // namespace android_webview 437