diff options
author | gman@chromium.org <gman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-10-27 13:00:42 +0000 |
---|---|---|
committer | gman@chromium.org <gman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-10-27 13:00:42 +0000 |
commit | 88a61bf4abf1483f6d8ade487559a0c10f17cc1b (patch) | |
tree | 9d3787992897deb3575cdeed1770010303571a26 /gpu | |
parent | 688178bffe550d6d8f36dcb61fd98350316dea8e (diff) | |
download | chromium_src-88a61bf4abf1483f6d8ade487559a0c10f17cc1b.zip chromium_src-88a61bf4abf1483f6d8ade487559a0c10f17cc1b.tar.gz chromium_src-88a61bf4abf1483f6d8ade487559a0c10f17cc1b.tar.bz2 |
Cache more GL state
BUG=155557
Review URL: https://chromiumcodereview.appspot.com/11315011
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@164540 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'gpu')
-rwxr-xr-x | gpu/command_buffer/build_gles2_cmd_buffer.py | 123 | ||||
-rw-r--r-- | gpu/command_buffer/service/context_state.cc | 51 | ||||
-rw-r--r-- | gpu/command_buffer/service/context_state.h | 72 | ||||
-rw-r--r-- | gpu/command_buffer/service/gles2_cmd_decoder.cc | 280 | ||||
-rw-r--r-- | gpu/command_buffer/service/gles2_cmd_decoder_autogen.h | 55 | ||||
-rw-r--r-- | gpu/command_buffer/service/gles2_cmd_decoder_unittest_2_autogen.h | 2 | ||||
-rw-r--r-- | gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc | 24 |
7 files changed, 459 insertions, 148 deletions
diff --git a/gpu/command_buffer/build_gles2_cmd_buffer.py b/gpu/command_buffer/build_gles2_cmd_buffer.py index ac0f58bd..302e0ab 100755 --- a/gpu/command_buffer/build_gles2_cmd_buffer.py +++ b/gpu/command_buffer/build_gles2_cmd_buffer.py @@ -812,6 +812,10 @@ _PEPPER_INTERFACES = [ # expectation: If False the unit test will have no expected calls. # gen_func: Name of function that generates GL resource for corresponding # bind function. +# states: array of states that get set by this function corresponding to +# the given arguments +# state_flag: name of flag that is set to true when function is called. +# no_gl: no GL function is called. # valid_args: A dictionary of argument indices to args to use in unit tests # when they can not be automatically determined. # pepper_interface: The pepper interface that is used for this extension @@ -875,12 +879,35 @@ _FUNCTION_INFO = { 'type': 'Manual', 'cmd_args': 'GLbitfield mask' }, - 'ClearColor': {'decoder_func': 'DoClearColor'}, + 'ClearColor': { + 'type': 'StateSet', + 'states': [ + {'name': 'color_clear_red'}, + {'name': 'color_clear_green'}, + {'name': 'color_clear_blue'}, + {'name': 'color_clear_alpha'}, + ], + }, 'ClearDepthf': { - 'decoder_func': 'DoClearDepthf', + 'type': 'StateSet', + 'states': [ + {'name': 'depth_clear'}, + ], + 'decoder_func': 'glClearDepth', 'gl_test_func': 'glClearDepth', }, - 'ColorMask': {'decoder_func': 'DoColorMask', 'expectation': False}, + 'ColorMask': { + 'type': 'StateSet', + 'states': [ + {'name': 'color_mask_red'}, + {'name': 'color_mask_green'}, + {'name': 'color_mask_blue'}, + {'name': 'color_mask_alpha'}, + ], + 'state_flag': 'clear_state_dirty_', + 'no_gl': True, + 'expectation': False, + }, 'ConsumeTextureCHROMIUM': { 'decoder_func': 'DoConsumeTextureCHROMIUM', 'type': 'PUT', @@ -890,7 +917,12 @@ _FUNCTION_INFO = { 'extension': True, 'chromium': True, }, - 'ClearStencil': {'decoder_func': 'DoClearStencil'}, + 'ClearStencil': { + 'type': 'StateSet', + 'states': [ + {'name': 'stencil_clear'}, + ], + }, 'EnableFeatureCHROMIUM': { 'type': 'Custom', 'immediate': False, @@ -928,6 +960,50 @@ _FUNCTION_INFO = { 'type': 'Create', 'client_test': False, }, + 'BlendColor': { + 'type': 'StateSet', + 'states': [ + {'name': 'blend_color_red'}, + {'name': 'blend_color_green'}, + {'name': 'blend_color_blue'}, + {'name': 'blend_color_alpha'}, + ], + }, + 'BlendEquation': {'decoder_func': 'DoBlendEquation'}, + 'BlendEquationSeparate': { + 'type': 'StateSet', + 'states': [ + {'name': 'blend_equation_rgb'}, + {'name': 'blend_equation_alpha'}, + ], + }, + 'BlendFunc': {'decoder_func': 'DoBlendFunc'}, + 'BlendFuncSeparate': { + 'type': 'StateSet', + 'states': [ + {'name': 'blend_source_rgb'}, + {'name': 'blend_dest_rgb'}, + {'name': 'blend_source_alpha'}, + {'name': 'blend_dest_alpha'}, + ], + }, + 'SampleCoverage': {'decoder_func': 'DoSampleCoverage'}, + 'StencilFunc': {'decoder_func': 'DoStencilFunc'}, + 'StencilFuncSeparate': {'decoder_func': 'DoStencilFuncSeparate'}, + 'StencilOp': {'decoder_func': 'DoStencilOp'}, + 'StencilOpSeparate': {'decoder_func': 'DoStencilOpSeparate'}, + 'Hint': {'decoder_func': 'DoHint'}, + 'CullFace': {'type': 'StateSet', 'states': [{'name': 'cull_mode'}]}, + 'FrontFace': {'type': 'StateSet', 'states': [{'name': 'front_face'}]}, + 'DepthFunc': {'type': 'StateSet', 'states': [{'name': 'depth_func'}]}, + 'LineWidth': {'type': 'StateSet', 'states': [{'name': 'line_width'}]}, + 'PolygonOffset': { + 'type': 'StateSet', + 'states': [ + {'name': 'polygon_offset_factor'}, + {'name': 'polygon_offset_units'}, + ], + }, 'DeleteBuffers': { 'type': 'DELn', 'gl_test_func': 'glDeleteBuffersARB', @@ -962,8 +1038,19 @@ _FUNCTION_INFO = { 'resource_type': 'Texture', 'resource_types': 'Textures', }, - 'DepthRangef': {'decoder_func': 'glDepthRange'}, - 'DepthMask': {'decoder_func': 'DoDepthMask', 'expectation': False}, + 'DepthRangef': { + 'decoder_func': 'DoDepthRangef', + 'gl_test_func': 'glDepthRange', + }, + 'DepthMask': { + 'type': 'StateSet', + 'states': [ + {'name': 'depth_mask'}, + ], + 'state_flag': 'clear_state_dirty_', + 'no_gl': True, + 'expectation': False, + }, 'DetachShader': {'decoder_func': 'DoDetachShader'}, 'Disable': { 'decoder_func': 'DoDisable', @@ -1275,6 +1362,7 @@ _FUNCTION_INFO = { 'type': 'Is', 'decoder_func': 'DoIsEnabled', 'impl_func': False, + 'expectation': False, }, 'IsFramebuffer': { 'type': 'Is', @@ -2443,6 +2531,28 @@ TEST_F(GLES2ImplementationTest, %(name)s) { }) +class StateSetHandler(TypeHandler): + """Handler for commands that simply set state.""" + + def __init__(self): + TypeHandler.__init__(self) + + def WriteHandlerImplementation(self, func, file): + """Overrriden from TypeHandler.""" + states = func.GetInfo('states') + args = func.GetOriginalArgs() + ndx = 0 + for state in states: + file.Write(" state_.%s = %s;\n" % (state['name'], args[ndx].name)) + ndx += 1 + state_flag = func.GetInfo('state_flag') + if state_flag: + file.Write(" %s = true;\n" % state_flag) + if not func.GetInfo("no_gl"): + file.Write(" %s(%s);\n" % + (func.GetGLFunctionName(), func.MakeOriginalArgString(""))) + + class CustomHandler(TypeHandler): """Handler for commands that are auto-generated but require minor tweaks.""" @@ -5830,6 +5940,7 @@ class GLGenerator(object): 'PUT': PUTHandler(), 'PUTn': PUTnHandler(), 'PUTXn': PUTXnHandler(), + 'StateSet': StateSetHandler(), 'STRn': STRnHandler(), 'Todo': TodoHandler(), } diff --git a/gpu/command_buffer/service/context_state.cc b/gpu/command_buffer/service/context_state.cc index 4b6eeaa..866abf4 100644 --- a/gpu/command_buffer/service/context_state.cc +++ b/gpu/command_buffer/service/context_state.cc @@ -26,22 +26,65 @@ ContextState::ContextState() color_mask_green(true), color_mask_blue(true), color_mask_alpha(true), - stencil_clear(0), - stencil_mask_front(-1), - stencil_mask_back(-1), depth_clear(1.0f), depth_mask(true), + depth_func(GL_LESS), + z_near(0.0f), + z_far(1.0f), enable_blend(false), enable_cull_face(false), enable_scissor_test(false), enable_depth_test(false), enable_stencil_test(false), + enable_polygon_offset_fill(false), + enable_dither(true), + enable_sample_alpha_to_coverage(false), + enable_sample_coverage(false), viewport_x(0), viewport_y(0), viewport_width(0), viewport_height(0), viewport_max_width(0), - viewport_max_height(0) { + viewport_max_height(0), + scissor_x(0), + scissor_y(0), + scissor_width(0), + scissor_height(0), + cull_mode(GL_BACK), + front_face(GL_CCW), + blend_source_rgb(GL_ONE), + blend_dest_rgb(GL_ZERO), + blend_source_alpha(GL_ONE), + blend_dest_alpha(GL_ZERO), + blend_equation_rgb(GL_FUNC_ADD), + blend_equation_alpha(GL_FUNC_ADD), + blend_color_red(0), + blend_color_green(0), + blend_color_blue(0), + blend_color_alpha(0), + stencil_clear(0), + stencil_front_writemask(0xFFFFFFFFU), + stencil_front_func(GL_ALWAYS), + stencil_front_ref(0), + stencil_front_mask(0xFFFFFFFFU), + stencil_front_fail_op(GL_KEEP), + stencil_front_z_fail_op(GL_KEEP), + stencil_front_z_pass_op(GL_KEEP), + stencil_back_writemask(0xFFFFFFFFU), + stencil_back_func(GL_ALWAYS), + stencil_back_ref(0), + stencil_back_mask(0xFFFFFFFFU), + stencil_back_fail_op(GL_KEEP), + stencil_back_z_fail_op(GL_KEEP), + stencil_back_z_pass_op(GL_KEEP), + polygon_offset_factor(0.0f), + polygon_offset_units(0.0f), + sample_coverage_value(1.0f), + sample_coverage_invert(false), + line_width(1.0), + hint_generate_mipmap(GL_DONT_CARE), + hint_fragment_shader_derivative(GL_DONT_CARE), + pack_reverse_row_order(false) { } ContextState::~ContextState() { diff --git a/gpu/command_buffer/service/context_state.h b/gpu/command_buffer/service/context_state.h index 7b37387..7cabc0a 100644 --- a/gpu/command_buffer/service/context_state.h +++ b/gpu/command_buffer/service/context_state.h @@ -17,12 +17,13 @@ #include "gpu/command_buffer/service/texture_manager.h" #include "gpu/command_buffer/service/vertex_attrib_manager.h" #include "gpu/command_buffer/service/vertex_array_manager.h" +#include "gpu/gpu_export.h" namespace gpu { namespace gles2 { // State associated with each texture unit. -struct TextureUnit { +struct GPU_EXPORT TextureUnit { TextureUnit(); ~TextureUnit(); @@ -76,7 +77,7 @@ struct TextureUnit { }; -struct ContextState { +struct GPU_EXPORT ContextState { ContextState(); ~ContextState(); @@ -100,17 +101,21 @@ struct ContextState { GLboolean color_mask_blue; GLboolean color_mask_alpha; - GLint stencil_clear; - GLuint stencil_mask_front; - GLuint stencil_mask_back; GLclampf depth_clear; GLboolean depth_mask; + GLenum depth_func; + float z_near; + float z_far; bool enable_blend; bool enable_cull_face; bool enable_scissor_test; bool enable_depth_test; bool enable_stencil_test; + bool enable_polygon_offset_fill; + bool enable_dither; + bool enable_sample_alpha_to_coverage; + bool enable_sample_coverage; // Cached values of the currently assigned viewport dimensions. GLint viewport_x; @@ -120,6 +125,11 @@ struct ContextState { GLsizei viewport_max_width; GLsizei viewport_max_height; + GLint scissor_x; + GLint scissor_y; + GLsizei scissor_width; + GLsizei scissor_height; + // The currently bound array buffer. If this is 0 it is illegal to call // glVertexAttribPointer. BufferManager::BufferInfo::Ref bound_array_buffer; @@ -144,50 +154,44 @@ struct ContextState { GLenum cull_mode; GLenum front_face; - GLenum depth_func; - GLenum source_blend_rgb; - GLenum dest_blend_rgb; - GLenum source_blend_alpha; - GLenum dest_blend_alpha; + + GLenum blend_source_rgb; + GLenum blend_dest_rgb; + GLenum blend_source_alpha; + GLenum blend_dest_alpha; GLenum blend_equation_rgb; GLenum blend_equation_alpha; GLfloat blend_color_red; GLfloat blend_color_green; GLfloat blend_color_blue; GLfloat blend_color_alpha; - GLenum stencil_func; - GLint stencil_ref; - GLenum stencil_fail; - GLenum stencil_pass_depth_fail; - GLenum stencil_pass_depth_pass; - GLuint stencil_writemask; + + GLint stencil_clear; + GLuint stencil_front_writemask; + GLenum stencil_front_func; + GLint stencil_front_ref; + GLuint stencil_front_mask; + GLenum stencil_front_fail_op; + GLenum stencil_front_z_fail_op; + GLenum stencil_front_z_pass_op; + GLuint stencil_back_writemask; GLenum stencil_back_func; GLint stencil_back_ref; - GLenum stencil_back_fail; - GLenum stencil_back_pass_depth_fail; - GLenum stencil_back_pass_depth_pass; - GLuint stencil_back_writemask; - bool polygon_offset_fill; + GLuint stencil_back_mask; + GLenum stencil_back_fail_op; + GLenum stencil_back_z_fail_op; + GLenum stencil_back_z_pass_op; + GLfloat polygon_offset_factor; GLfloat polygon_offset_units; - bool sample_alpha_to_coverage; - bool sample_coverage; + GLclampf sample_coverage_value; bool sample_coverage_invert; - bool dither; GLfloat line_width; - GLenum generate_mipmap_hint; - GLenum fragment_shader_derivative_hint; - - float z_near; - float z_far; - - GLint scissor_x; - GLint scissor_y; - GLsizei scissor_width; - GLsizei scissor_height; + GLenum hint_generate_mipmap; + GLenum hint_fragment_shader_derivative; bool pack_reverse_row_order; }; diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc index 63bf1cc..6b38210 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc @@ -1021,15 +1021,20 @@ class GLES2DecoderImpl : public base::SupportsWeakPtr<GLES2DecoderImpl>, error::Error DoClear(GLbitfield mask); // Wrappers for clear and mask settings functions. - void DoClearColor( - GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha); - void DoClearDepthf(GLclampf depth); - void DoClearStencil(GLint s); - void DoColorMask( - GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha); - void DoDepthMask(GLboolean depth); void DoStencilMask(GLuint mask); void DoStencilMaskSeparate(GLenum face, GLuint mask); + void DoStencilFunc(GLenum func, GLint ref, GLuint mask); + void DoStencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint mask); + void DoStencilOp(GLenum fail, GLenum zfail, GLenum zpass); + void DoStencilOpSeparate( + GLenum face, GLenum fail, GLenum zfail, GLenum zpass); + + // Wrappers for various state. + void DoBlendEquation(GLenum mode); + void DoBlendFunc(GLenum sfactor, GLenum dfactor); + void DoDepthRangef(GLclampf znear, GLclampf zfar); + void DoHint(GLenum target, GLenum mode); + void DoSampleCoverage (GLclampf value, GLboolean invert); // Wrapper for glCompileShader. void DoCompileShader(GLuint shader); @@ -1466,7 +1471,7 @@ class GLES2DecoderImpl : public base::SupportsWeakPtr<GLES2DecoderImpl>, // state saved for clearing so we can clear render buffers and then // restore to these values. - bool state_dirty_; + bool clear_state_dirty_; // The offscreen frame buffer that the client renders to. With EGL, the // depth and stencil buffers are separate. With regular GL there is a single @@ -1921,7 +1926,7 @@ GLES2DecoderImpl::GLES2DecoderImpl(ContextGroup* group) attrib_0_size_(0), fixed_attrib_buffer_id_(0), fixed_attrib_buffer_size_(0), - state_dirty_(true), + clear_state_dirty_(true), offscreen_target_color_format_(0), offscreen_target_depth_format_(0), offscreen_target_stencil_format_(0), @@ -2244,14 +2249,29 @@ bool GLES2DecoderImpl::Initialize( state_.viewport_max_width = viewport_params[0]; state_.viewport_max_height = viewport_params[1]; + state_.scissor_width = state_.viewport_width; + state_.scissor_height = state_.viewport_height; + // Set all the default state because some GL drivers get it wrong. glActiveTexture(GL_TEXTURE0 + state_.active_texture_unit); - glLineWidth(1.0); EnableDisable(GL_BLEND, state_.enable_blend); - glBlendColor(0.0f, 0.0, 0.0f, 0.0f); - glBlendFunc(GL_ONE, GL_ZERO); - glBlendEquation(GL_FUNC_ADD); - glBlendFuncSeparate(GL_ONE, GL_ZERO, GL_ONE, GL_ZERO); + glBlendColor( + state_.blend_color_red, + state_.blend_color_green, + state_.blend_color_blue, + state_.blend_color_alpha); + glBlendFunc( + state_.blend_source_rgb, + state_.blend_dest_rgb); + glBlendFuncSeparate( + state_.blend_source_rgb, + state_.blend_dest_rgb, + state_.blend_source_alpha, + state_.blend_dest_alpha); + glBlendEquation( + state_.blend_equation_rgb); + glBlendEquationSeparate( + state_.blend_equation_rgb, state_.blend_equation_alpha); glClearColor( state_.color_clear_red, state_.color_clear_green, state_.color_clear_blue, state_.color_clear_alpha); @@ -2259,29 +2279,50 @@ bool GLES2DecoderImpl::Initialize( state_.color_mask_red, state_.color_mask_green, state_.color_mask_blue, state_.color_mask_alpha); EnableDisable(GL_CULL_FACE, state_.enable_cull_face); - glCullFace(GL_BACK); + glCullFace(state_.cull_mode); glClearDepth(state_.depth_clear); - glDepthFunc(GL_LESS); - glDepthRange(0.0f, 1.0f); + glDepthFunc(state_.depth_func); + glDepthRange(state_.z_near, state_.z_far); EnableDisable(GL_DEPTH_TEST, state_.enable_depth_test); - glEnable(GL_DITHER); - glFrontFace(GL_CCW); - glHint(GL_GENERATE_MIPMAP_HINT, GL_DONT_CARE); - glLineWidth(1.0f); + EnableDisable(GL_DITHER, state_.enable_dither); + glFrontFace(state_.front_face); + glHint(GL_GENERATE_MIPMAP_HINT, state_.hint_generate_mipmap); + glLineWidth(state_.line_width); glPixelStorei(GL_PACK_ALIGNMENT, state_.pack_alignment); - glPolygonOffset(0.0f, 0.0f); - glDisable(GL_POLYGON_OFFSET_FILL); - glSampleCoverage(1.0, false); + glPolygonOffset(state_.polygon_offset_factor, state_.polygon_offset_units); + EnableDisable(GL_POLYGON_OFFSET_FILL, state_.enable_polygon_offset_fill); + EnableDisable( + GL_SAMPLE_ALPHA_TO_COVERAGE, state_.enable_sample_alpha_to_coverage); + EnableDisable(GL_SAMPLE_COVERAGE, state_.enable_sample_coverage); + glSampleCoverage(state_.sample_coverage_value, state_.sample_coverage_invert); glScissor( - state_.viewport_x, state_.viewport_y, - state_.viewport_width, state_.viewport_height); + state_.scissor_x, state_.scissor_y, + state_.scissor_width, state_.scissor_height); EnableDisable(GL_SCISSOR_TEST, state_.enable_scissor_test); EnableDisable(GL_STENCIL_TEST, state_.enable_stencil_test); glClearStencil(state_.stencil_clear); - glStencilFunc(GL_ALWAYS, 0, 0xFFFFFFFFU); - glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); - glStencilMaskSeparate(GL_FRONT, state_.stencil_mask_front); - glStencilMaskSeparate(GL_BACK, state_.stencil_mask_back); + glStencilFuncSeparate( + GL_FRONT, + state_.stencil_front_func, + state_.stencil_front_ref, + state_.stencil_front_mask); + glStencilFuncSeparate( + GL_BACK, + state_.stencil_back_func, + state_.stencil_back_ref, + state_.stencil_back_mask); + glStencilOpSeparate( + GL_FRONT, + state_.stencil_front_fail_op, + state_.stencil_front_z_fail_op, + state_.stencil_front_z_pass_op); + glStencilOpSeparate( + GL_BACK, + state_.stencil_back_fail_op, + state_.stencil_back_z_fail_op, + state_.stencil_back_z_pass_op); + glStencilMaskSeparate(GL_FRONT, state_.stencil_front_writemask); + glStencilMaskSeparate(GL_BACK, state_.stencil_back_writemask); glPixelStorei(GL_UNPACK_ALIGNMENT, state_.unpack_alignment); DoBindBuffer(GL_ARRAY_BUFFER, 0); @@ -2457,7 +2498,7 @@ void GLES2DecoderImpl::DeleteFramebuffersHelper( if (framebuffer && !framebuffer->IsDeleted()) { if (framebuffer == state_.bound_draw_framebuffer) { state_.bound_draw_framebuffer = NULL; - state_dirty_ = true; + clear_state_dirty_ = true; GLenum target = supports_separate_framebuffer_binds ? GL_DRAW_FRAMEBUFFER_EXT : GL_FRAMEBUFFER; glBindFramebufferEXT(target, GetBackbufferServiceId()); @@ -2500,7 +2541,7 @@ void GLES2DecoderImpl::DeleteRenderbuffersHelper( GL_FRAMEBUFFER, renderbuffer); } } - state_dirty_ = true; + clear_state_dirty_ = true; RemoveRenderbufferInfo(client_ids[ii]); } } @@ -2514,7 +2555,7 @@ void GLES2DecoderImpl::DeleteTexturesHelper( TextureManager::TextureInfo* texture = GetTextureInfo(client_ids[ii]); if (texture && !texture->IsDeleted()) { if (texture->IsAttachedToFramebuffer()) { - state_dirty_ = true; + clear_state_dirty_ = true; } // Unbind texture from texture units. for (size_t jj = 0; jj < group_->max_texture_units(); ++jj) { @@ -2589,7 +2630,7 @@ static void RebindCurrentFramebuffer( } void GLES2DecoderImpl::RestoreCurrentFramebufferBindings() { - state_dirty_ = true; + clear_state_dirty_ = true; if (!features().chromium_framebuffer_multisample) { RebindCurrentFramebuffer( @@ -3352,7 +3393,7 @@ bool GLES2DecoderImpl::BoundFramebufferHasStencilAttachment() { } void GLES2DecoderImpl::ApplyDirtyState() { - if (state_dirty_) { + if (clear_state_dirty_) { glColorMask( state_.color_mask_red, state_.color_mask_green, state_.color_mask_blue, state_.color_mask_alpha && @@ -3362,14 +3403,14 @@ void GLES2DecoderImpl::ApplyDirtyState() { EnableDisable(GL_DEPTH_TEST, state_.enable_depth_test && have_depth); bool have_stencil = BoundFramebufferHasStencilAttachment(); glStencilMaskSeparate( - GL_FRONT, have_stencil ? state_.stencil_mask_front : 0); + GL_FRONT, have_stencil ? state_.stencil_front_writemask : 0); glStencilMaskSeparate( - GL_BACK, have_stencil ? state_.stencil_mask_back : 0); + GL_BACK, have_stencil ? state_.stencil_back_writemask : 0); EnableDisable(GL_STENCIL_TEST, state_.enable_stencil_test && have_stencil); EnableDisable(GL_CULL_FACE, state_.enable_cull_face); EnableDisable(GL_SCISSOR_TEST, state_.enable_scissor_test); EnableDisable(GL_BLEND, state_.enable_blend); - state_dirty_ = false; + clear_state_dirty_ = false; } } @@ -3421,7 +3462,7 @@ void GLES2DecoderImpl::DoBindFramebuffer(GLenum target, GLuint client_id) { state_.bound_read_framebuffer = info; } - state_dirty_ = true; + clear_state_dirty_ = true; // If we are rendering to the backbuffer get the FBO id for any simulated // backbuffer. @@ -3675,13 +3716,13 @@ bool GLES2DecoderImpl::GetHelper( case GL_STENCIL_BACK_WRITEMASK: *num_written = 1; if (params) { - params[0] = state_.stencil_mask_back; + params[0] = state_.stencil_back_writemask; } return true; case GL_STENCIL_WRITEMASK: *num_written = 1; if (params) { - params[0] = state_.stencil_mask_front; + params[0] = state_.stencil_front_writemask; } return true; case GL_DEPTH_TEST: @@ -4303,7 +4344,7 @@ void GLES2DecoderImpl::DoFramebufferRenderbuffer( framebuffer_info->AttachRenderbuffer(attachment, info); } if (framebuffer_info == state_.bound_draw_framebuffer) { - state_dirty_ = true; + clear_state_dirty_ = true; } } @@ -4321,16 +4362,24 @@ bool GLES2DecoderImpl::SetCapabilityState(GLenum cap, bool enabled) { case GL_DEPTH_TEST: { if (state_.enable_depth_test != enabled) { state_.enable_depth_test = enabled; - state_dirty_ = true; + clear_state_dirty_ = true; } return false; } case GL_STENCIL_TEST: if (state_.enable_stencil_test != enabled) { state_.enable_stencil_test = enabled; - state_dirty_ = true; + clear_state_dirty_ = true; } return false; + case GL_POLYGON_OFFSET_FILL: + state_.enable_polygon_offset_fill = enabled; + case GL_DITHER: + state_.enable_dither = enabled; + case GL_SAMPLE_ALPHA_TO_COVERAGE: + state_.enable_sample_alpha_to_coverage = enabled; + case GL_SAMPLE_COVERAGE: + state_.enable_sample_coverage = enabled; default: return true; } @@ -4360,58 +4409,124 @@ bool GLES2DecoderImpl::DoIsEnabled(GLenum cap) { return state_.enable_depth_test; case GL_STENCIL_TEST: return state_.enable_stencil_test; + case GL_POLYGON_OFFSET_FILL: + return state_.enable_polygon_offset_fill; + case GL_DITHER: + return state_.enable_dither; + case GL_SAMPLE_ALPHA_TO_COVERAGE: + return state_.enable_sample_alpha_to_coverage; + case GL_SAMPLE_COVERAGE: + return state_.enable_sample_coverage; default: return glIsEnabled(cap) != 0; } } -void GLES2DecoderImpl::DoClearColor( - GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) { - state_.color_clear_red = red; - state_.color_clear_green = green; - state_.color_clear_blue = blue; - state_.color_clear_alpha = alpha; - glClearColor(red, green, blue, alpha); +void GLES2DecoderImpl::DoDepthRangef(GLclampf znear, GLclampf zfar) { + state_.z_near = std::min(1.0f, std::max(0.0f, znear)); + state_.z_far = std::min(1.0f, std::max(0.0f, zfar)); + glDepthRange(znear, zfar); } -void GLES2DecoderImpl::DoClearDepthf(GLclampf depth) { - state_.depth_clear = depth; - glClearDepth(depth); +void GLES2DecoderImpl::DoStencilMask(GLuint mask) { + state_.stencil_front_writemask = mask; + state_.stencil_back_writemask = mask; + clear_state_dirty_ = true; } -void GLES2DecoderImpl::DoClearStencil(GLint s) { - state_.stencil_clear = s; - glClearStencil(s); +void GLES2DecoderImpl::DoStencilMaskSeparate(GLenum face, GLuint mask) { + if (face == GL_FRONT || face == GL_FRONT_AND_BACK) { + state_.stencil_front_writemask = mask; + } + if (face == GL_BACK || face == GL_FRONT_AND_BACK) { + state_.stencil_back_writemask = mask; + } + clear_state_dirty_ = true; } -void GLES2DecoderImpl::DoColorMask( - GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) { - state_.color_mask_red = red; - state_.color_mask_green = green; - state_.color_mask_blue = blue; - state_.color_mask_alpha = alpha; - state_dirty_ = true; +void GLES2DecoderImpl::DoStencilFunc(GLenum func, GLint ref, GLuint mask) { + state_.stencil_front_func = func; + state_.stencil_front_ref = ref; + state_.stencil_front_mask = mask; + state_.stencil_back_func = func; + state_.stencil_back_ref = ref; + state_.stencil_back_mask = mask; + glStencilFunc(func, ref, mask); } -void GLES2DecoderImpl::DoDepthMask(GLboolean depth) { - state_.depth_mask = depth; - state_dirty_ = true; +void GLES2DecoderImpl::DoStencilFuncSeparate( + GLenum face, GLenum func, GLint ref, GLuint mask) { + if (face == GL_FRONT || face == GL_FRONT_AND_BACK) { + state_.stencil_front_func = func; + state_.stencil_front_ref = ref; + state_.stencil_front_mask = mask; + } + if (face == GL_BACK || face == GL_FRONT_AND_BACK) { + state_.stencil_back_func = func; + state_.stencil_back_ref = ref; + state_.stencil_back_mask = mask; + } + glStencilFuncSeparate(face, func, ref, mask); } -void GLES2DecoderImpl::DoStencilMask(GLuint mask) { - state_.stencil_mask_front = mask; - state_.stencil_mask_back = mask; - state_dirty_ = true; +void GLES2DecoderImpl::DoStencilOp( + GLenum fail, GLenum zfail, GLenum zpass) { + state_.stencil_front_fail_op = fail; + state_.stencil_front_z_fail_op = zfail; + state_.stencil_front_z_pass_op = zpass; + state_.stencil_back_fail_op = fail; + state_.stencil_back_z_fail_op = zfail; + state_.stencil_back_z_pass_op = zpass; + glStencilOp(fail, zfail, zpass); } -void GLES2DecoderImpl::DoStencilMaskSeparate(GLenum face, GLuint mask) { +void GLES2DecoderImpl::DoStencilOpSeparate( + GLenum face, GLenum fail, GLenum zfail, GLenum zpass) { if (face == GL_FRONT || face == GL_FRONT_AND_BACK) { - state_.stencil_mask_front = mask; + state_.stencil_front_fail_op = fail; + state_.stencil_front_z_fail_op = zfail; + state_.stencil_front_z_pass_op = zpass; } if (face == GL_BACK || face == GL_FRONT_AND_BACK) { - state_.stencil_mask_back = mask; + state_.stencil_back_fail_op = fail; + state_.stencil_back_z_fail_op = zfail; + state_.stencil_back_z_pass_op = zpass; } - state_dirty_ = true; + glStencilOpSeparate(face, fail, zfail, zpass); +} + +void GLES2DecoderImpl::DoBlendEquation(GLenum mode) { + state_.blend_equation_rgb = mode; + state_.blend_equation_alpha = mode; + glBlendEquation(mode); +} + +void GLES2DecoderImpl::DoBlendFunc(GLenum sfactor, GLenum dfactor) { + state_.blend_source_rgb = sfactor; + state_.blend_dest_rgb = dfactor; + state_.blend_source_alpha = sfactor; + state_.blend_dest_alpha = dfactor; + glBlendFunc(sfactor, dfactor); +} + +void GLES2DecoderImpl::DoHint(GLenum target, GLenum mode) { + switch (target) { + case GL_GENERATE_MIPMAP_HINT: + state_.hint_generate_mipmap = mode; + break; + case GL_FRAGMENT_SHADER_DERIVATIVE_HINT_OES: + state_.hint_fragment_shader_derivative = mode; + break; + default: + NOTREACHED(); + } + glHint(target, mode); +} + +void GLES2DecoderImpl::DoSampleCoverage (GLclampf value, GLboolean invert) { + state_.sample_coverage_value = std::min(1.0f, std::max(0.0f, value)); + state_.sample_coverage_invert = (invert != 0); + glSampleCoverage(state_.sample_coverage_value, invert); } // Assumes framebuffer is complete. @@ -4468,7 +4583,7 @@ void GLES2DecoderImpl::ClearUnclearedAttachments( } void GLES2DecoderImpl::RestoreClearState() { - state_dirty_ = true; + clear_state_dirty_ = true; glClearColor( state_.color_clear_red, state_.color_clear_green, state_.color_clear_blue, state_.color_clear_alpha); @@ -4527,7 +4642,7 @@ void GLES2DecoderImpl::DoFramebufferTexture2D( framebuffer_info->AttachTexture(attachment, info, textarget, level); } if (framebuffer_info == state_.bound_draw_framebuffer) { - state_dirty_ = true; + clear_state_dirty_ = true; } } @@ -6566,6 +6681,7 @@ error::Error GLES2DecoderImpl::HandlePixelStorei( state_.pack_alignment = param; break; case GL_PACK_REVERSE_ROW_ORDER_ANGLE: + state_.pack_reverse_row_order = (param != 0); break; case GL_UNPACK_ALIGNMENT: state_.unpack_alignment = param; @@ -7161,7 +7277,7 @@ error::Error GLES2DecoderImpl::DoCompressedTexImage2D( } if (info->IsAttachedToFramebuffer()) { - state_dirty_ = true; + clear_state_dirty_ = true; // TODO(gman): If textures tracked which framebuffers they were attached to // we could just mark those framebuffers as not complete. framebuffer_manager()->IncFramebufferStateChangeCount(); @@ -7398,7 +7514,7 @@ error::Error GLES2DecoderImpl::DoTexImage2D( } if (info->IsAttachedToFramebuffer()) { - state_dirty_ = true; + clear_state_dirty_ = true; // TODO(gman): If textures tracked which framebuffers they were attached to // we could just mark those framebuffers as not complete. framebuffer_manager()->IncFramebufferStateChangeCount(); @@ -7612,7 +7728,7 @@ void GLES2DecoderImpl::DoCopyTexImage2D( gfx::Size size = GetBoundReadFrameBufferSize(); if (info->IsAttachedToFramebuffer()) { - state_dirty_ = true; + clear_state_dirty_ = true; // TODO(gman): If textures tracked which framebuffers they were attached to // we could just mark those framebuffers as not complete. framebuffer_manager()->IncFramebufferStateChangeCount(); @@ -9126,7 +9242,7 @@ void GLES2DecoderImpl::DoCopyTextureCHROMIUM( texture_manager()->SetLevelCleared(dest_info, GL_TEXTURE_2D, level); } - state_dirty_ = true; + clear_state_dirty_ = true; glViewport(0, 0, source_width, source_height); copy_texture_CHROMIUM_->DoCopyTexture(target, source_info->service_id(), dest_info->service_id(), level, @@ -9218,7 +9334,7 @@ void GLES2DecoderImpl::DoTexStorage2DEXT( return; } if (info->IsAttachedToFramebuffer()) { - state_dirty_ = true; + clear_state_dirty_ = true; } if (info->IsImmutable()) { SetGLError(GL_INVALID_OPERATION, diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h b/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h index fe5806f..6a1251a 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h +++ b/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h @@ -79,6 +79,10 @@ error::Error GLES2DecoderImpl::HandleBlendColor( GLclampf green = static_cast<GLclampf>(c.green); GLclampf blue = static_cast<GLclampf>(c.blue); GLclampf alpha = static_cast<GLclampf>(c.alpha); + state_.blend_color_red = red; + state_.blend_color_green = green; + state_.blend_color_blue = blue; + state_.blend_color_alpha = alpha; glBlendColor(red, green, blue, alpha); return error::kNoError; } @@ -90,7 +94,7 @@ error::Error GLES2DecoderImpl::HandleBlendEquation( SetGLErrorInvalidEnum("glBlendEquation", mode, "mode"); return error::kNoError; } - glBlendEquation(mode); + DoBlendEquation(mode); return error::kNoError; } @@ -106,6 +110,8 @@ error::Error GLES2DecoderImpl::HandleBlendEquationSeparate( SetGLErrorInvalidEnum("glBlendEquationSeparate", modeAlpha, "modeAlpha"); return error::kNoError; } + state_.blend_equation_rgb = modeRGB; + state_.blend_equation_alpha = modeAlpha; glBlendEquationSeparate(modeRGB, modeAlpha); return error::kNoError; } @@ -122,7 +128,7 @@ error::Error GLES2DecoderImpl::HandleBlendFunc( SetGLErrorInvalidEnum("glBlendFunc", dfactor, "dfactor"); return error::kNoError; } - glBlendFunc(sfactor, dfactor); + DoBlendFunc(sfactor, dfactor); return error::kNoError; } @@ -148,6 +154,10 @@ error::Error GLES2DecoderImpl::HandleBlendFuncSeparate( SetGLErrorInvalidEnum("glBlendFuncSeparate", dstAlpha, "dstAlpha"); return error::kNoError; } + state_.blend_source_rgb = srcRGB; + state_.blend_dest_rgb = dstRGB; + state_.blend_source_alpha = srcAlpha; + state_.blend_dest_alpha = dstAlpha; glBlendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha); return error::kNoError; } @@ -221,21 +231,27 @@ error::Error GLES2DecoderImpl::HandleClearColor( GLclampf green = static_cast<GLclampf>(c.green); GLclampf blue = static_cast<GLclampf>(c.blue); GLclampf alpha = static_cast<GLclampf>(c.alpha); - DoClearColor(red, green, blue, alpha); + state_.color_clear_red = red; + state_.color_clear_green = green; + state_.color_clear_blue = blue; + state_.color_clear_alpha = alpha; + glClearColor(red, green, blue, alpha); return error::kNoError; } error::Error GLES2DecoderImpl::HandleClearDepthf( uint32 immediate_data_size, const gles2::ClearDepthf& c) { GLclampf depth = static_cast<GLclampf>(c.depth); - DoClearDepthf(depth); + state_.depth_clear = depth; + glClearDepth(depth); return error::kNoError; } error::Error GLES2DecoderImpl::HandleClearStencil( uint32 immediate_data_size, const gles2::ClearStencil& c) { GLint s = static_cast<GLint>(c.s); - DoClearStencil(s); + state_.stencil_clear = s; + glClearStencil(s); return error::kNoError; } @@ -245,7 +261,11 @@ error::Error GLES2DecoderImpl::HandleColorMask( GLboolean green = static_cast<GLboolean>(c.green); GLboolean blue = static_cast<GLboolean>(c.blue); GLboolean alpha = static_cast<GLboolean>(c.alpha); - DoColorMask(red, green, blue, alpha); + state_.color_mask_red = red; + state_.color_mask_green = green; + state_.color_mask_blue = blue; + state_.color_mask_alpha = alpha; + clear_state_dirty_ = true; return error::kNoError; } @@ -431,6 +451,7 @@ error::Error GLES2DecoderImpl::HandleCullFace( SetGLErrorInvalidEnum("glCullFace", mode, "mode"); return error::kNoError; } + state_.cull_mode = mode; glCullFace(mode); return error::kNoError; } @@ -570,6 +591,7 @@ error::Error GLES2DecoderImpl::HandleDepthFunc( SetGLErrorInvalidEnum("glDepthFunc", func, "func"); return error::kNoError; } + state_.depth_func = func; glDepthFunc(func); return error::kNoError; } @@ -577,7 +599,8 @@ error::Error GLES2DecoderImpl::HandleDepthFunc( error::Error GLES2DecoderImpl::HandleDepthMask( uint32 immediate_data_size, const gles2::DepthMask& c) { GLboolean flag = static_cast<GLboolean>(c.flag); - DoDepthMask(flag); + state_.depth_mask = flag; + clear_state_dirty_ = true; return error::kNoError; } @@ -585,7 +608,7 @@ error::Error GLES2DecoderImpl::HandleDepthRangef( uint32 immediate_data_size, const gles2::DepthRangef& c) { GLclampf zNear = static_cast<GLclampf>(c.zNear); GLclampf zFar = static_cast<GLclampf>(c.zFar); - glDepthRange(zNear, zFar); + DoDepthRangef(zNear, zFar); return error::kNoError; } @@ -705,6 +728,7 @@ error::Error GLES2DecoderImpl::HandleFrontFace( SetGLErrorInvalidEnum("glFrontFace", mode, "mode"); return error::kNoError; } + state_.front_face = mode; glFrontFace(mode); return error::kNoError; } @@ -1298,7 +1322,7 @@ error::Error GLES2DecoderImpl::HandleHint( SetGLErrorInvalidEnum("glHint", mode, "mode"); return error::kNoError; } - glHint(target, mode); + DoHint(target, mode); return error::kNoError; } @@ -1400,6 +1424,7 @@ error::Error GLES2DecoderImpl::HandleIsTexture( error::Error GLES2DecoderImpl::HandleLineWidth( uint32 immediate_data_size, const gles2::LineWidth& c) { GLfloat width = static_cast<GLfloat>(c.width); + state_.line_width = width; glLineWidth(width); return error::kNoError; } @@ -1415,6 +1440,8 @@ error::Error GLES2DecoderImpl::HandlePolygonOffset( uint32 immediate_data_size, const gles2::PolygonOffset& c) { GLfloat factor = static_cast<GLfloat>(c.factor); GLfloat units = static_cast<GLfloat>(c.units); + state_.polygon_offset_factor = factor; + state_.polygon_offset_units = units; glPolygonOffset(factor, units); return error::kNoError; } @@ -1456,7 +1483,7 @@ error::Error GLES2DecoderImpl::HandleSampleCoverage( uint32 immediate_data_size, const gles2::SampleCoverage& c) { GLclampf value = static_cast<GLclampf>(c.value); GLboolean invert = static_cast<GLboolean>(c.invert); - glSampleCoverage(value, invert); + DoSampleCoverage(value, invert); return error::kNoError; } @@ -1487,7 +1514,7 @@ error::Error GLES2DecoderImpl::HandleStencilFunc( SetGLErrorInvalidEnum("glStencilFunc", func, "func"); return error::kNoError; } - glStencilFunc(func, ref, mask); + DoStencilFunc(func, ref, mask); return error::kNoError; } @@ -1505,7 +1532,7 @@ error::Error GLES2DecoderImpl::HandleStencilFuncSeparate( SetGLErrorInvalidEnum("glStencilFuncSeparate", func, "func"); return error::kNoError; } - glStencilFuncSeparate(face, func, ref, mask); + DoStencilFuncSeparate(face, func, ref, mask); return error::kNoError; } @@ -1545,7 +1572,7 @@ error::Error GLES2DecoderImpl::HandleStencilOp( SetGLErrorInvalidEnum("glStencilOp", zpass, "zpass"); return error::kNoError; } - glStencilOp(fail, zfail, zpass); + DoStencilOp(fail, zfail, zpass); return error::kNoError; } @@ -1571,7 +1598,7 @@ error::Error GLES2DecoderImpl::HandleStencilOpSeparate( SetGLErrorInvalidEnum("glStencilOpSeparate", zpass, "zpass"); return error::kNoError; } - glStencilOpSeparate(face, fail, zfail, zpass); + DoStencilOpSeparate(face, fail, zfail, zpass); return error::kNoError; } diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_2_autogen.h b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_2_autogen.h index a62e17c..939ef93 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_2_autogen.h +++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_2_autogen.h @@ -91,7 +91,6 @@ TEST_F(GLES2DecoderTest2, IsBufferInvalidArgsBadSharedMemoryId) { } TEST_F(GLES2DecoderTest2, IsEnabledValidArgs) { - EXPECT_CALL(*gl_, IsEnabled(GL_DITHER)); SpecializedSetup<IsEnabled, 0>(true); IsEnabled cmd; cmd.Init(GL_DITHER, shared_memory_id_, shared_memory_offset_); @@ -118,7 +117,6 @@ TEST_F(GLES2DecoderTest2, IsEnabledInvalidArgs0_1) { } TEST_F(GLES2DecoderTest2, IsEnabledInvalidArgsBadSharedMemoryId) { - EXPECT_CALL(*gl_, IsEnabled(GL_DITHER)).Times(0); SpecializedSetup<IsEnabled, 0>(false); IsEnabled cmd; cmd.Init(GL_DITHER, kInvalidSharedMemoryId, shared_memory_offset_); diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc index 34e8eb6..108d2ae 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc @@ -201,9 +201,6 @@ void GLES2DecoderTestBase::InitDecoder( EXPECT_CALL(*gl_, ActiveTexture(GL_TEXTURE0)) .Times(1) .RetiresOnSaturation(); - EXPECT_CALL(*gl_, LineWidth(1.0)) - .Times(1) - .RetiresOnSaturation(); EXPECT_CALL(*gl_, Disable(GL_BLEND)) .Times(1) .RetiresOnSaturation(); @@ -213,10 +210,13 @@ void GLES2DecoderTestBase::InitDecoder( EXPECT_CALL(*gl_, BlendFunc(GL_ONE, GL_ZERO)) .Times(1) .RetiresOnSaturation(); + EXPECT_CALL(*gl_, BlendFuncSeparate(GL_ONE, GL_ZERO, GL_ONE, GL_ZERO)) + .Times(1) + .RetiresOnSaturation(); EXPECT_CALL(*gl_, BlendEquation(GL_FUNC_ADD)) .Times(1) .RetiresOnSaturation(); - EXPECT_CALL(*gl_, BlendFuncSeparate(GL_ONE, GL_ZERO, GL_ONE, GL_ZERO)) + EXPECT_CALL(*gl_, BlendEquationSeparate(GL_FUNC_ADD, GL_FUNC_ADD)) .Times(1) .RetiresOnSaturation(); EXPECT_CALL(*gl_, ClearColor(0.0f, 0.0, 0.0f, 0.0f)) @@ -264,6 +264,12 @@ void GLES2DecoderTestBase::InitDecoder( EXPECT_CALL(*gl_, Disable(GL_POLYGON_OFFSET_FILL)) .Times(1) .RetiresOnSaturation(); + EXPECT_CALL(*gl_, Disable(GL_SAMPLE_ALPHA_TO_COVERAGE)) + .Times(1) + .RetiresOnSaturation(); + EXPECT_CALL(*gl_, Disable(GL_SAMPLE_COVERAGE)) + .Times(1) + .RetiresOnSaturation(); EXPECT_CALL(*gl_, SampleCoverage(1.0, false)) .Times(1) .RetiresOnSaturation(); @@ -280,10 +286,16 @@ void GLES2DecoderTestBase::InitDecoder( EXPECT_CALL(*gl_, ClearStencil(0)) .Times(1) .RetiresOnSaturation(); - EXPECT_CALL(*gl_, StencilFunc(GL_ALWAYS, 0, 0xFFFFFFFFU)) + EXPECT_CALL(*gl_, StencilFuncSeparate(GL_FRONT, GL_ALWAYS, 0, 0xFFFFFFFFU)) + .Times(1) + .RetiresOnSaturation(); + EXPECT_CALL(*gl_, StencilFuncSeparate(GL_BACK, GL_ALWAYS, 0, 0xFFFFFFFFU)) + .Times(1) + .RetiresOnSaturation(); + EXPECT_CALL(*gl_, StencilOpSeparate(GL_FRONT, GL_KEEP, GL_KEEP, GL_KEEP)) .Times(1) .RetiresOnSaturation(); - EXPECT_CALL(*gl_, StencilOp(GL_KEEP, GL_KEEP, GL_KEEP)) + EXPECT_CALL(*gl_, StencilOpSeparate(GL_BACK, GL_KEEP, GL_KEEP, GL_KEEP)) .Times(1) .RetiresOnSaturation(); EXPECT_CALL(*gl_, StencilMaskSeparate(GL_FRONT, 0xFFFFFFFFU)) |