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.
5 #include "android_webview/browser/scoped_app_gl_state_restore.h"
9 #include "base/lazy_instance.h"
10 #include "base/trace_event/trace_event.h"
11 #include "ui/gl/gl_bindings.h"
12 #include "ui/gl/gl_context.h"
13 #include "ui/gl/gl_surface_stub.h"
15 namespace android_webview
{
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
{
24 : surface(new gfx::GLSurfaceStub
),
25 context(gfx::GLContext::CreateGLContext(NULL
,
27 gfx::PreferDiscreteGpu
)) {}
28 void MakeCurrent() { context
->MakeCurrent(surface
.get()); }
31 scoped_refptr
<gfx::GLSurfaceStub
> surface
;
32 scoped_refptr
<gfx::GLContext
> context
;
34 DISALLOW_COPY_AND_ASSIGN(AppContextSurface
);
37 base::LazyInstance
<AppContextSurface
> g_app_context_surface
=
38 LAZY_INSTANCE_INITIALIZER
;
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.
43 void MakeAppContextCurrent() {
44 g_app_context_surface
.Get().MakeCurrent();
47 void GLEnableDisable(GLenum cap
, bool enable
) {
54 bool ClearGLErrors(bool warn
, const char* msg
) {
57 while ((error
= glGetError()) != GL_NO_ERROR
) {
58 DLOG_IF(WARNING
, warn
) << error
<< " " << msg
;
65 bool g_globals_initialized
= false;
66 GLint g_gl_max_texture_units
= 0;
67 bool g_supports_oes_vertex_array_object
= false;
73 class ScopedAppGLStateRestoreImpl
{
75 ScopedAppGLStateRestoreImpl(ScopedAppGLStateRestore::CallMode mode
);
76 ~ScopedAppGLStateRestoreImpl();
78 bool stencil_enabled() const { return stencil_test_
; }
79 GLint
framebuffer_binding_ext() const { return framebuffer_binding_ext_
; }
82 const ScopedAppGLStateRestore::CallMode mode_
;
84 GLint pack_alignment_
;
85 GLint unpack_alignment_
;
94 GLint vertex_attrib_array_buffer_binding
;
95 GLfloat current_vertex_attrib
[4];
98 GLint vertex_array_buffer_binding_
;
99 GLint index_array_buffer_binding_
;
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_
;
110 GLboolean depth_mask_
;
111 GLfloat depth_rage_
[2];
113 GLint hint_generate_mipmap_
;
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_
;
122 GLboolean enable_dither_
;
123 GLboolean enable_polygon_offset_fill_
;
124 GLboolean enable_sample_alpha_to_coverage_
;
125 GLboolean enable_sample_coverage_
;
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_
;
135 GLboolean scissor_test_
;
136 GLint scissor_box_
[4];
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_
;
155 GLint framebuffer_binding_ext_
;
157 struct TextureBindings
{
159 GLint texture_cube_map
;
160 GLint texture_external_oes
;
161 // TODO(boliu): TEXTURE_RECTANGLE_ARB
164 std::vector
<TextureBindings
> texture_bindings_
;
166 GLint vertex_array_bindings_oes_
;
168 DISALLOW_COPY_AND_ASSIGN(ScopedAppGLStateRestoreImpl
);
171 ScopedAppGLStateRestoreImpl::ScopedAppGLStateRestoreImpl(
172 ScopedAppGLStateRestore::CallMode mode
)
174 TRACE_EVENT0("android_webview", "AppGLStateSave");
175 MakeAppContextCurrent();
177 ClearGLErrors(true, "Incoming GLError");
179 if (!g_globals_initialized
) {
180 g_globals_initialized
= true;
182 glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS
, &g_gl_max_texture_units
);
184 std::string extensions
;
185 const char* extensions_c_str
=
186 reinterpret_cast<const char*>(glGetString(GL_EXTENSIONS
));
187 if (extensions_c_str
)
188 extensions
= extensions_c_str
;
189 g_supports_oes_vertex_array_object
=
190 extensions
.find("GL_OES_vertex_array_object") != std::string::npos
;
193 glGetIntegerv(GL_ARRAY_BUFFER_BINDING
, &vertex_array_buffer_binding_
);
194 glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING
, &index_array_buffer_binding_
);
197 case ScopedAppGLStateRestore::MODE_DRAW
:
198 DCHECK_EQ(0, vertex_array_buffer_binding_
);
199 DCHECK_EQ(0, index_array_buffer_binding_
);
201 case ScopedAppGLStateRestore::MODE_RESOURCE_MANAGEMENT
:
202 glGetBooleanv(GL_BLEND
, &blend_enabled_
);
203 glGetIntegerv(GL_BLEND_SRC_RGB
, &blend_src_rgb_
);
204 glGetIntegerv(GL_BLEND_SRC_ALPHA
, &blend_src_alpha_
);
205 glGetIntegerv(GL_BLEND_DST_RGB
, &blend_dest_rgb_
);
206 glGetIntegerv(GL_BLEND_DST_ALPHA
, &blend_dest_alpha_
);
207 glGetIntegerv(GL_VIEWPORT
, viewport_
);
208 glGetBooleanv(GL_SCISSOR_TEST
, &scissor_test_
);
209 glGetIntegerv(GL_SCISSOR_BOX
, scissor_box_
);
213 glGetIntegerv(GL_PACK_ALIGNMENT
, &pack_alignment_
);
214 glGetIntegerv(GL_UNPACK_ALIGNMENT
, &unpack_alignment_
);
216 glGetBooleanv(GL_DEPTH_TEST
, &depth_test_
);
217 glGetBooleanv(GL_CULL_FACE
, &cull_face_
);
218 glGetIntegerv(GL_CULL_FACE_MODE
, &cull_face_mode_
);
219 glGetBooleanv(GL_COLOR_WRITEMASK
, color_mask_
);
220 glGetIntegerv(GL_CURRENT_PROGRAM
, ¤t_program_
);
221 glGetFloatv(GL_COLOR_CLEAR_VALUE
, color_clear_
);
222 glGetFloatv(GL_DEPTH_CLEAR_VALUE
, &depth_clear_
);
223 glGetFloatv(GL_BLEND_COLOR
, blend_color_
);
224 glGetIntegerv(GL_DEPTH_FUNC
, &depth_func_
);
225 glGetBooleanv(GL_DEPTH_WRITEMASK
, &depth_mask_
);
226 glGetFloatv(GL_DEPTH_RANGE
, depth_rage_
);
227 glGetIntegerv(GL_FRONT_FACE
, &front_face_
);
228 glGetIntegerv(GL_GENERATE_MIPMAP_HINT
, &hint_generate_mipmap_
);
229 glGetFloatv(GL_LINE_WIDTH
, &line_width_
);
230 glGetFloatv(GL_POLYGON_OFFSET_FACTOR
, &polygon_offset_factor_
);
231 glGetFloatv(GL_POLYGON_OFFSET_UNITS
, &polygon_offset_units_
);
232 glGetFloatv(GL_SAMPLE_COVERAGE_VALUE
, &sample_coverage_value_
);
233 glGetBooleanv(GL_SAMPLE_COVERAGE_INVERT
, &sample_coverage_invert_
);
234 glGetIntegerv(GL_BLEND_EQUATION_RGB
, &blend_equation_rgb_
);
235 glGetIntegerv(GL_BLEND_EQUATION_ALPHA
, &blend_equation_alpha_
);
237 glGetBooleanv(GL_DITHER
, &enable_dither_
);
238 glGetBooleanv(GL_POLYGON_OFFSET_FILL
, &enable_polygon_offset_fill_
);
239 glGetBooleanv(GL_SAMPLE_ALPHA_TO_COVERAGE
, &enable_sample_alpha_to_coverage_
);
240 glGetBooleanv(GL_SAMPLE_COVERAGE
, &enable_sample_coverage_
);
242 glGetBooleanv(GL_STENCIL_TEST
, &stencil_test_
);
243 glGetIntegerv(GL_STENCIL_FUNC
, &stencil_front_func_
);
244 glGetIntegerv(GL_STENCIL_VALUE_MASK
, &stencil_front_mask_
);
245 glGetIntegerv(GL_STENCIL_REF
, &stencil_front_ref_
);
246 glGetIntegerv(GL_STENCIL_BACK_FUNC
, &stencil_back_func_
);
247 glGetIntegerv(GL_STENCIL_BACK_VALUE_MASK
, &stencil_back_mask_
);
248 glGetIntegerv(GL_STENCIL_BACK_REF
, &stencil_back_ref_
);
249 glGetIntegerv(GL_STENCIL_CLEAR_VALUE
, &stencil_clear_
);
250 glGetIntegerv(GL_STENCIL_WRITEMASK
, &stencil_front_writemask_
);
251 glGetIntegerv(GL_STENCIL_BACK_WRITEMASK
, &stencil_back_writemask_
);
252 glGetIntegerv(GL_STENCIL_FAIL
, &stencil_front_fail_op_
);
253 glGetIntegerv(GL_STENCIL_PASS_DEPTH_FAIL
, &stencil_front_z_fail_op_
);
254 glGetIntegerv(GL_STENCIL_PASS_DEPTH_PASS
, &stencil_front_z_pass_op_
);
255 glGetIntegerv(GL_STENCIL_BACK_FAIL
, &stencil_back_fail_op_
);
256 glGetIntegerv(GL_STENCIL_BACK_PASS_DEPTH_FAIL
, &stencil_back_z_fail_op_
);
257 glGetIntegerv(GL_STENCIL_BACK_PASS_DEPTH_PASS
, &stencil_back_z_pass_op_
);
259 glGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT
, &framebuffer_binding_ext_
);
261 glGetIntegerv(GL_ACTIVE_TEXTURE
, &active_texture_
);
263 texture_bindings_
.resize(g_gl_max_texture_units
);
264 for (int ii
= 0; ii
< g_gl_max_texture_units
; ++ii
) {
265 glActiveTexture(GL_TEXTURE0
+ ii
);
266 TextureBindings
& bindings
= texture_bindings_
[ii
];
267 glGetIntegerv(GL_TEXTURE_BINDING_2D
, &bindings
.texture_2d
);
268 glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP
, &bindings
.texture_cube_map
);
269 glGetIntegerv(GL_TEXTURE_BINDING_EXTERNAL_OES
,
270 &bindings
.texture_external_oes
);
273 if (g_supports_oes_vertex_array_object
) {
274 glGetIntegerv(GL_VERTEX_ARRAY_BINDING_OES
, &vertex_array_bindings_oes_
);
275 glBindVertexArrayOES(0);
278 for (size_t i
= 0; i
< arraysize(vertex_attrib_
); ++i
) {
280 i
, GL_VERTEX_ATTRIB_ARRAY_ENABLED
, &vertex_attrib_
[i
].enabled
);
282 i
, GL_VERTEX_ATTRIB_ARRAY_SIZE
, &vertex_attrib_
[i
].size
);
284 i
, GL_VERTEX_ATTRIB_ARRAY_TYPE
, &vertex_attrib_
[i
].type
);
286 i
, GL_VERTEX_ATTRIB_ARRAY_NORMALIZED
, &vertex_attrib_
[i
].normalized
);
288 i
, GL_VERTEX_ATTRIB_ARRAY_STRIDE
, &vertex_attrib_
[i
].stride
);
289 glGetVertexAttribPointerv(
290 i
, GL_VERTEX_ATTRIB_ARRAY_POINTER
, &vertex_attrib_
[i
].pointer
);
291 glGetVertexAttribPointerv(
292 i
, GL_VERTEX_ATTRIB_ARRAY_POINTER
, &vertex_attrib_
[i
].pointer
);
293 glGetVertexAttribiv(i
,
294 GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING
,
295 &vertex_attrib_
[i
].vertex_attrib_array_buffer_binding
);
297 i
, GL_CURRENT_VERTEX_ATTRIB
, vertex_attrib_
[i
].current_vertex_attrib
);
300 // Android 5.0.0 specific qualcomm workaround. See crbug.com/434570.
301 glBindRenderbufferEXT(GL_RENDERBUFFER
, 0);
302 DCHECK(ClearGLErrors(false, NULL
));
305 ScopedAppGLStateRestoreImpl::~ScopedAppGLStateRestoreImpl() {
306 TRACE_EVENT0("android_webview", "AppGLStateRestore");
307 MakeAppContextCurrent();
309 DCHECK(ClearGLErrors(false, NULL
));
311 glBindFramebufferEXT(GL_FRAMEBUFFER
, framebuffer_binding_ext_
);
312 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER
, index_array_buffer_binding_
);
314 if (g_supports_oes_vertex_array_object
)
315 glBindVertexArrayOES(0);
317 for (size_t i
= 0; i
< arraysize(vertex_attrib_
); ++i
) {
318 glBindBuffer(GL_ARRAY_BUFFER
,
319 vertex_attrib_
[i
].vertex_attrib_array_buffer_binding
);
320 glVertexAttribPointer(i
,
321 vertex_attrib_
[i
].size
,
322 vertex_attrib_
[i
].type
,
323 vertex_attrib_
[i
].normalized
,
324 vertex_attrib_
[i
].stride
,
325 vertex_attrib_
[i
].pointer
);
327 glVertexAttrib4fv(i
, vertex_attrib_
[i
].current_vertex_attrib
);
329 if (vertex_attrib_
[i
].enabled
) {
330 glEnableVertexAttribArray(i
);
332 glDisableVertexAttribArray(i
);
336 if (g_supports_oes_vertex_array_object
&& vertex_array_bindings_oes_
!= 0)
337 glBindVertexArrayOES(vertex_array_bindings_oes_
);
339 glBindBuffer(GL_ARRAY_BUFFER
, vertex_array_buffer_binding_
);
341 for (int ii
= 0; ii
< g_gl_max_texture_units
; ++ii
) {
342 glActiveTexture(GL_TEXTURE0
+ ii
);
343 TextureBindings
& bindings
= texture_bindings_
[ii
];
344 glBindTexture(GL_TEXTURE_2D
, bindings
.texture_2d
);
345 glBindTexture(GL_TEXTURE_CUBE_MAP
, bindings
.texture_cube_map
);
346 glBindTexture(GL_TEXTURE_EXTERNAL_OES
, bindings
.texture_external_oes
);
348 glActiveTexture(active_texture_
);
350 glPixelStorei(GL_PACK_ALIGNMENT
, pack_alignment_
);
351 glPixelStorei(GL_UNPACK_ALIGNMENT
, unpack_alignment_
);
353 GLEnableDisable(GL_DEPTH_TEST
, depth_test_
);
355 GLEnableDisable(GL_CULL_FACE
, cull_face_
);
356 glCullFace(cull_face_mode_
);
358 glColorMask(color_mask_
[0], color_mask_
[1], color_mask_
[2], color_mask_
[3]);
360 glUseProgram(current_program_
);
363 color_clear_
[0], color_clear_
[1], color_clear_
[2], color_clear_
[3]);
365 blend_color_
[0], blend_color_
[1], blend_color_
[2], blend_color_
[3]);
366 glClearDepth(depth_clear_
);
367 glDepthFunc(depth_func_
);
368 glDepthMask(depth_mask_
);
369 glDepthRange(depth_rage_
[0], depth_rage_
[1]);
370 glFrontFace(front_face_
);
371 glHint(GL_GENERATE_MIPMAP_HINT
, hint_generate_mipmap_
);
372 // TODO(boliu): GL_FRAGMENT_SHADER_DERIVATIVE_HINT_OES ??
373 glLineWidth(line_width_
);
374 glPolygonOffset(polygon_offset_factor_
, polygon_offset_units_
);
375 glSampleCoverage(sample_coverage_value_
, sample_coverage_invert_
);
376 glBlendEquationSeparate(blend_equation_rgb_
, blend_equation_alpha_
);
378 GLEnableDisable(GL_DITHER
, enable_dither_
);
379 GLEnableDisable(GL_POLYGON_OFFSET_FILL
, enable_polygon_offset_fill_
);
380 GLEnableDisable(GL_SAMPLE_ALPHA_TO_COVERAGE
,
381 enable_sample_alpha_to_coverage_
);
382 GLEnableDisable(GL_SAMPLE_COVERAGE
, enable_sample_coverage_
);
385 case ScopedAppGLStateRestore::MODE_DRAW
:
388 case ScopedAppGLStateRestore::MODE_RESOURCE_MANAGEMENT
:
389 GLEnableDisable(GL_BLEND
, blend_enabled_
);
391 blend_src_rgb_
, blend_dest_rgb_
, blend_src_alpha_
, blend_dest_alpha_
);
393 glViewport(viewport_
[0], viewport_
[1], viewport_
[2], viewport_
[3]);
395 GLEnableDisable(GL_SCISSOR_TEST
, scissor_test_
);
398 scissor_box_
[0], scissor_box_
[1], scissor_box_
[2], scissor_box_
[3]);
402 GLEnableDisable(GL_STENCIL_TEST
, stencil_test_
);
403 glStencilFuncSeparate(
404 GL_FRONT
, stencil_front_func_
, stencil_front_mask_
, stencil_front_ref_
);
405 glStencilFuncSeparate(
406 GL_BACK
, stencil_back_func_
, stencil_back_mask_
, stencil_back_ref_
);
407 glClearStencil(stencil_clear_
);
408 glStencilMaskSeparate(GL_FRONT
, stencil_front_writemask_
);
409 glStencilMaskSeparate(GL_BACK
, stencil_back_writemask_
);
410 glStencilOpSeparate(GL_FRONT
,
411 stencil_front_fail_op_
,
412 stencil_front_z_fail_op_
,
413 stencil_front_z_pass_op_
);
414 glStencilOpSeparate(GL_BACK
,
415 stencil_back_fail_op_
,
416 stencil_back_z_fail_op_
,
417 stencil_back_z_pass_op_
);
419 // Do not leak GLError out of chromium.
420 ClearGLErrors(true, "Chromium GLError");
423 } // namespace internal
425 ScopedAppGLStateRestore::ScopedAppGLStateRestore(CallMode mode
)
426 : impl_(new internal::ScopedAppGLStateRestoreImpl(mode
)) {
429 ScopedAppGLStateRestore::~ScopedAppGLStateRestore() {}
431 bool ScopedAppGLStateRestore::stencil_enabled() const {
432 return impl_
->stencil_enabled();
434 int ScopedAppGLStateRestore::framebuffer_binding_ext() const {
435 return impl_
->framebuffer_binding_ext();
438 } // namespace android_webview