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/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"
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
);
183 DCHECK_GT(g_gl_max_texture_units
, 0);
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
;
191 glGetIntegerv(GL_ARRAY_BUFFER_BINDING
, &vertex_array_buffer_binding_
);
192 glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING
, &index_array_buffer_binding_
);
195 case ScopedAppGLStateRestore::MODE_DRAW
:
196 DCHECK_EQ(0, vertex_array_buffer_binding_
);
197 DCHECK_EQ(0, index_array_buffer_binding_
);
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_
);
211 glGetIntegerv(GL_PACK_ALIGNMENT
, &pack_alignment_
);
212 glGetIntegerv(GL_UNPACK_ALIGNMENT
, &unpack_alignment_
);
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_
);
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_
);
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_
);
257 glGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT
, &framebuffer_binding_ext_
);
259 glGetIntegerv(GL_ACTIVE_TEXTURE
, &active_texture_
);
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
);
271 if (g_supports_oes_vertex_array_object
) {
272 glGetIntegerv(GL_VERTEX_ARRAY_BINDING_OES
, &vertex_array_bindings_oes_
);
273 glBindVertexArrayOES(0);
276 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(vertex_attrib_
); ++i
) {
278 i
, GL_VERTEX_ATTRIB_ARRAY_ENABLED
, &vertex_attrib_
[i
].enabled
);
280 i
, GL_VERTEX_ATTRIB_ARRAY_SIZE
, &vertex_attrib_
[i
].size
);
282 i
, GL_VERTEX_ATTRIB_ARRAY_TYPE
, &vertex_attrib_
[i
].type
);
284 i
, GL_VERTEX_ATTRIB_ARRAY_NORMALIZED
, &vertex_attrib_
[i
].normalized
);
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
);
295 i
, GL_CURRENT_VERTEX_ATTRIB
, vertex_attrib_
[i
].current_vertex_attrib
);
297 DCHECK(ClearGLErrors(false, NULL
));
300 ScopedAppGLStateRestoreImpl::~ScopedAppGLStateRestoreImpl() {
301 TRACE_EVENT0("android_webview", "AppGLStateRestore");
302 MakeAppContextCurrent();
304 DCHECK(ClearGLErrors(false, NULL
));
306 glBindFramebufferEXT(GL_FRAMEBUFFER
, framebuffer_binding_ext_
);
307 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER
, index_array_buffer_binding_
);
309 if (g_supports_oes_vertex_array_object
)
310 glBindVertexArrayOES(0);
312 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(vertex_attrib_
); ++i
) {
313 glBindBuffer(GL_ARRAY_BUFFER
,
314 vertex_attrib_
[i
].vertex_attrib_array_buffer_binding
);
315 glVertexAttribPointer(i
,
316 vertex_attrib_
[i
].size
,
317 vertex_attrib_
[i
].type
,
318 vertex_attrib_
[i
].normalized
,
319 vertex_attrib_
[i
].stride
,
320 vertex_attrib_
[i
].pointer
);
322 glVertexAttrib4fv(i
, vertex_attrib_
[i
].current_vertex_attrib
);
324 if (vertex_attrib_
[i
].enabled
) {
325 glEnableVertexAttribArray(i
);
327 glDisableVertexAttribArray(i
);
331 if (g_supports_oes_vertex_array_object
&& vertex_array_bindings_oes_
!= 0)
332 glBindVertexArrayOES(vertex_array_bindings_oes_
);
334 glBindBuffer(GL_ARRAY_BUFFER
, vertex_array_buffer_binding_
);
336 for (int ii
= 0; ii
< g_gl_max_texture_units
; ++ii
) {
337 glActiveTexture(GL_TEXTURE0
+ ii
);
338 TextureBindings
& bindings
= texture_bindings_
[ii
];
339 glBindTexture(GL_TEXTURE_2D
, bindings
.texture_2d
);
340 glBindTexture(GL_TEXTURE_CUBE_MAP
, bindings
.texture_cube_map
);
341 glBindTexture(GL_TEXTURE_EXTERNAL_OES
, bindings
.texture_external_oes
);
343 glActiveTexture(active_texture_
);
345 glPixelStorei(GL_PACK_ALIGNMENT
, pack_alignment_
);
346 glPixelStorei(GL_UNPACK_ALIGNMENT
, unpack_alignment_
);
348 GLEnableDisable(GL_DEPTH_TEST
, depth_test_
);
350 GLEnableDisable(GL_CULL_FACE
, cull_face_
);
351 glCullFace(cull_face_mode_
);
353 glColorMask(color_mask_
[0], color_mask_
[1], color_mask_
[2], color_mask_
[3]);
355 glUseProgram(current_program_
);
358 color_clear_
[0], color_clear_
[1], color_clear_
[2], color_clear_
[3]);
360 blend_color_
[0], blend_color_
[1], blend_color_
[2], blend_color_
[3]);
361 glClearDepth(depth_clear_
);
362 glDepthFunc(depth_func_
);
363 glDepthMask(depth_mask_
);
364 glDepthRange(depth_rage_
[0], depth_rage_
[1]);
365 glFrontFace(front_face_
);
366 glHint(GL_GENERATE_MIPMAP_HINT
, hint_generate_mipmap_
);
367 // TODO(boliu): GL_FRAGMENT_SHADER_DERIVATIVE_HINT_OES ??
368 glLineWidth(line_width_
);
369 glPolygonOffset(polygon_offset_factor_
, polygon_offset_units_
);
370 glSampleCoverage(sample_coverage_value_
, sample_coverage_invert_
);
371 glBlendEquationSeparate(blend_equation_rgb_
, blend_equation_alpha_
);
373 GLEnableDisable(GL_DITHER
, enable_dither_
);
374 GLEnableDisable(GL_POLYGON_OFFSET_FILL
, enable_polygon_offset_fill_
);
375 GLEnableDisable(GL_SAMPLE_ALPHA_TO_COVERAGE
,
376 enable_sample_alpha_to_coverage_
);
377 GLEnableDisable(GL_SAMPLE_COVERAGE
, enable_sample_coverage_
);
380 case ScopedAppGLStateRestore::MODE_DRAW
:
383 case ScopedAppGLStateRestore::MODE_RESOURCE_MANAGEMENT
:
384 GLEnableDisable(GL_BLEND
, blend_enabled_
);
386 blend_src_rgb_
, blend_dest_rgb_
, blend_src_alpha_
, blend_dest_alpha_
);
388 glViewport(viewport_
[0], viewport_
[1], viewport_
[2], viewport_
[3]);
390 GLEnableDisable(GL_SCISSOR_TEST
, scissor_test_
);
393 scissor_box_
[0], scissor_box_
[1], scissor_box_
[2], scissor_box_
[3]);
397 GLEnableDisable(GL_STENCIL_TEST
, stencil_test_
);
398 glStencilFuncSeparate(
399 GL_FRONT
, stencil_front_func_
, stencil_front_mask_
, stencil_front_ref_
);
400 glStencilFuncSeparate(
401 GL_BACK
, stencil_back_func_
, stencil_back_mask_
, stencil_back_ref_
);
402 glClearStencil(stencil_clear_
);
403 glStencilMaskSeparate(GL_FRONT
, stencil_front_writemask_
);
404 glStencilMaskSeparate(GL_BACK
, stencil_back_writemask_
);
405 glStencilOpSeparate(GL_FRONT
,
406 stencil_front_fail_op_
,
407 stencil_front_z_fail_op_
,
408 stencil_front_z_pass_op_
);
409 glStencilOpSeparate(GL_BACK
,
410 stencil_back_fail_op_
,
411 stencil_back_z_fail_op_
,
412 stencil_back_z_pass_op_
);
414 // Do not leak GLError out of chromium.
415 ClearGLErrors(true, "Chromium GLError");
418 } // namespace internal
420 ScopedAppGLStateRestore::ScopedAppGLStateRestore(CallMode mode
)
421 : impl_(new internal::ScopedAppGLStateRestoreImpl(mode
)) {
424 ScopedAppGLStateRestore::~ScopedAppGLStateRestore() {}
426 bool ScopedAppGLStateRestore::stencil_enabled() const {
427 return impl_
->stencil_enabled();
429 int ScopedAppGLStateRestore::framebuffer_binding_ext() const {
430 return impl_
->framebuffer_binding_ext();
433 } // namespace android_webview