• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
15 namespace android_webview {
16 
17 namespace {
18 
19 // "App" context is a bit of a stretch. Basically we use this context while
20 // saving and restoring the App GL state.
21 class AppContextSurface {
22  public:
AppContextSurface()23   AppContextSurface()
24       : surface(new gfx::GLSurfaceStub),
25         context(gfx::GLContext::CreateGLContext(NULL,
26                                                 surface.get(),
27                                                 gfx::PreferDiscreteGpu)) {}
MakeCurrent()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 
37 base::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.
MakeAppContextCurrent()43 void MakeAppContextCurrent() {
44   g_app_context_surface.Get().MakeCurrent();
45 }
46 
GLEnableDisable(GLenum cap,bool enable)47 void GLEnableDisable(GLenum cap, bool enable) {
48   if (enable)
49     glEnable(cap);
50   else
51     glDisable(cap);
52 }
53 
ClearGLErrors(bool warn,const char * msg)54 bool 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 
65 bool g_globals_initialized = false;
66 GLint g_gl_max_texture_units = 0;
67 bool g_supports_oes_vertex_array_object = false;
68 
69 }  // namespace
70 
71 namespace internal {
72 
73 class ScopedAppGLStateRestoreImpl {
74  public:
75   ScopedAppGLStateRestoreImpl(ScopedAppGLStateRestore::CallMode mode);
76   ~ScopedAppGLStateRestoreImpl();
77 
stencil_enabled() const78   bool stencil_enabled() const { return stencil_test_; }
framebuffer_binding_ext() const79   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 
ScopedAppGLStateRestoreImpl(ScopedAppGLStateRestore::CallMode mode)171 ScopedAppGLStateRestoreImpl::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, &current_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 
~ScopedAppGLStateRestoreImpl()303 ScopedAppGLStateRestoreImpl::~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 
ScopedAppGLStateRestore(CallMode mode)423 ScopedAppGLStateRestore::ScopedAppGLStateRestore(CallMode mode)
424     : impl_(new internal::ScopedAppGLStateRestoreImpl(mode)) {
425 }
426 
~ScopedAppGLStateRestore()427 ScopedAppGLStateRestore::~ScopedAppGLStateRestore() {}
428 
stencil_enabled() const429 bool ScopedAppGLStateRestore::stencil_enabled() const {
430   return impl_->stencil_enabled();
431 }
framebuffer_binding_ext() const432 int ScopedAppGLStateRestore::framebuffer_binding_ext() const {
433   return impl_->framebuffer_binding_ext();
434 }
435 
436 }  // namespace android_webview
437