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