diff options
Diffstat (limited to 'gpu')
12 files changed, 839 insertions, 125 deletions
diff --git a/gpu/command_buffer/build_gles2_cmd_buffer.py b/gpu/command_buffer/build_gles2_cmd_buffer.py index 4d8d924..5e00aa0 100755 --- a/gpu/command_buffer/build_gles2_cmd_buffer.py +++ b/gpu/command_buffer/build_gles2_cmd_buffer.py @@ -1134,7 +1134,7 @@ _FUNCTION_INFO = { 'decoder_func': 'DoClearDepthf', 'gl_test_func': 'glClearDepth', }, - 'ColorMask': {'decoder_func': 'DoColorMask'}, + 'ColorMask': {'decoder_func': 'DoColorMask', 'expectation': False}, 'ClearStencil': {'decoder_func': 'DoClearStencil'}, 'CommandBufferEnableCHROMIUM': { 'type': 'Custom', @@ -1192,7 +1192,7 @@ _FUNCTION_INFO = { }, 'DeleteTextures': {'type': 'DELn'}, 'DepthRangef': {'decoder_func': 'glDepthRange'}, - 'DepthMask': {'decoder_func': 'DoDepthMask'}, + 'DepthMask': {'decoder_func': 'DoDepthMask', 'expectation': False}, 'DetachShader': {'decoder_func': 'DoDetachShader'}, 'Disable': { 'decoder_func': 'DoDisable', @@ -1507,8 +1507,11 @@ _FUNCTION_INFO = { 'cmd_args': 'GLuint shader, const char* data', }, - 'StencilMask': {'decoder_func': 'DoStencilMask'}, - 'StencilMaskSeparate': {'decoder_func': 'DoStencilMaskSeparate'}, + 'StencilMask': {'decoder_func': 'DoStencilMask', 'expectation': False}, + 'StencilMaskSeparate': { + 'decoder_func': 'DoStencilMaskSeparate', + 'expectation': False, + }, 'SwapBuffers': { 'type': 'Custom', 'impl_func': False, @@ -4271,6 +4274,22 @@ class Argument(object): """Gets the bucket version of this argument.""" return self + +class BoolArgument(Argument): + """class for GLboolean""" + + def __init__(self, name, type): + Argument.__init__(self, name, 'GLboolean') + + def GetValidArg(self, func, offset, index): + """Gets a valid value for this argument.""" + return 'true' + + def GetValidGLArg(self, func, offset, index): + """Gets a valid GL value for this argument.""" + return 'true' + + class DataSizeArgument(Argument): """class for data_size which Bucket commands do not need.""" @@ -4335,7 +4354,7 @@ class SizeNotNegativeArgument(SizeArgument): class EnumBaseArgument(Argument): - """Base class for EnumArgument, IntArgument and BoolArgument""" + """Base class for EnumArgument, IntArgument and ValidatedBoolArgument""" def __init__(self, name, gl_type, type, gl_error): Argument.__init__(self, name, gl_type) @@ -4405,7 +4424,7 @@ class IntArgument(EnumBaseArgument): EnumBaseArgument.__init__(self, name, "GLint", type, "GL_INVALID_VALUE") -class BoolArgument(EnumBaseArgument): +class ValidatedBoolArgument(EnumBaseArgument): """A class for a GLboolean argument that can only except specific values. For example glUniformMatrix takes a GLboolean for it's transpose but it @@ -5059,6 +5078,8 @@ def CreateArg(arg_string): elif arg_parts[0].startswith('GLenum') and len(arg_parts[0]) > 6: return EnumArgument(arg_parts[-1], " ".join(arg_parts[0:-1])) elif arg_parts[0].startswith('GLboolean') and len(arg_parts[0]) > 9: + return ValidatedBoolArgument(arg_parts[-1], " ".join(arg_parts[0:-1])) + elif arg_parts[0].startswith('GLboolean'): return BoolArgument(arg_parts[-1], " ".join(arg_parts[0:-1])) elif (arg_parts[0].startswith('GLint') and len(arg_parts[0]) > 5 and not arg_parts[0].startswith('GLintptr')): diff --git a/gpu/command_buffer/service/framebuffer_manager.cc b/gpu/command_buffer/service/framebuffer_manager.cc index 190a910..316bc32 100644 --- a/gpu/command_buffer/service/framebuffer_manager.cc +++ b/gpu/command_buffer/service/framebuffer_manager.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -43,6 +43,10 @@ class RenderbufferAttachment render_buffer_->set_cleared(); } + virtual bool IsTexture(TextureManager::TextureInfo* /* texture */) const { + return false; + } + RenderbufferManager::RenderbufferInfo* render_buffer() const { return render_buffer_.get(); } @@ -99,6 +103,10 @@ class TextureAttachment NOTREACHED(); } + virtual bool IsTexture(TextureManager::TextureInfo* texture) const { + return texture == texture_.get(); + } + TextureManager::TextureInfo* texture() const { return texture_.get(); } @@ -169,6 +177,25 @@ void FramebufferManager::FramebufferInfo::MarkAttachedRenderbuffersAsCleared() { } } +bool FramebufferManager::FramebufferInfo::HasDepthAttachment() const { + return attachments_.find(GL_DEPTH_STENCIL_ATTACHMENT) != attachments_.end() || + attachments_.find(GL_DEPTH_ATTACHMENT) != attachments_.end(); +} + +bool FramebufferManager::FramebufferInfo::HasStencilAttachment() const { + return attachments_.find(GL_DEPTH_STENCIL_ATTACHMENT) != attachments_.end() || + attachments_.find(GL_STENCIL_ATTACHMENT) != attachments_.end(); +} + +GLenum FramebufferManager::FramebufferInfo::GetColorAttachmentFormat() const { + AttachmentMap::const_iterator it = attachments_.find(GL_COLOR_ATTACHMENT0); + if (it == attachments_.end()) { + return 0; + } + const Attachment* attachment = it->second; + return attachment->internal_format(); +} + bool FramebufferManager::FramebufferInfo::IsNotComplete() const { for (AttachmentMap::const_iterator it = attachments_.begin(); it != attachments_.end(); ++it) { @@ -215,9 +242,14 @@ void FramebufferManager::FramebufferInfo::AttachTexture( attachment == GL_DEPTH_ATTACHMENT || attachment == GL_STENCIL_ATTACHMENT || attachment == GL_DEPTH_STENCIL_ATTACHMENT); + const Attachment* a = GetAttachment(attachment); + if (a && a->IsTexture(texture)) { + texture->DetachFromFramebuffer(); + } if (texture) { attachments_[attachment] = Attachment::Ref( new TextureAttachment(texture, target, level)); + texture->AttachToFramebuffer(); } else { attachments_.erase(attachment); } diff --git a/gpu/command_buffer/service/framebuffer_manager.h b/gpu/command_buffer/service/framebuffer_manager.h index 362e0b8..0641c35 100644 --- a/gpu/command_buffer/service/framebuffer_manager.h +++ b/gpu/command_buffer/service/framebuffer_manager.h @@ -36,6 +36,7 @@ class FramebufferManager { virtual GLsizei samples() const = 0; virtual bool cleared() const = 0; virtual void set_cleared() = 0; + virtual bool IsTexture(TextureManager::TextureInfo* texture) const = 0; }; explicit FramebufferInfo(GLuint service_id); @@ -72,8 +73,12 @@ class FramebufferManager { return has_been_bound_ && !IsDeleted(); } + bool HasDepthAttachment() const; + bool HasStencilAttachment() const; + GLenum GetColorAttachmentFormat() const; + // We can't know if the frame buffer is complete since that is - // implementation dependent and we'd have to check after every glTexImage + // implementation dependent and we'd have to check after every glTexImage // call but we can know in certain cases that it's NOT complete which we // need to enforce the OpenGL ES 2.0 spec on top of DesktopGL. bool IsNotComplete() const; diff --git a/gpu/command_buffer/service/framebuffer_manager_unittest.cc b/gpu/command_buffer/service/framebuffer_manager_unittest.cc index d3c3879..77c6622 100644 --- a/gpu/command_buffer/service/framebuffer_manager_unittest.cc +++ b/gpu/command_buffer/service/framebuffer_manager_unittest.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -122,6 +122,9 @@ TEST_F(FramebufferInfoTest, Basic) { EXPECT_TRUE(NULL == info_->GetAttachment(GL_DEPTH_ATTACHMENT)); EXPECT_TRUE(NULL == info_->GetAttachment(GL_STENCIL_ATTACHMENT)); EXPECT_TRUE(NULL == info_->GetAttachment(GL_DEPTH_STENCIL_ATTACHMENT)); + EXPECT_FALSE(info_->HasDepthAttachment()); + EXPECT_FALSE(info_->HasStencilAttachment()); + EXPECT_EQ(static_cast<GLenum>(0), info_->GetColorAttachmentFormat()); } TEST_F(FramebufferInfoTest, AttachRenderbuffer) { @@ -161,12 +164,23 @@ TEST_F(FramebufferInfoTest, AttachRenderbuffer) { EXPECT_TRUE(info_->HasUnclearedAttachment(GL_COLOR_ATTACHMENT0)); EXPECT_FALSE(info_->HasUnclearedAttachment(GL_DEPTH_ATTACHMENT)); EXPECT_TRUE(info_->IsNotComplete()); + EXPECT_EQ(static_cast<GLenum>(GL_RGBA4), info_->GetColorAttachmentFormat()); + EXPECT_FALSE(info_->HasDepthAttachment()); + EXPECT_FALSE(info_->HasStencilAttachment()); + + rb_info1->SetInfo(1, GL_RGB, 0, 0); + EXPECT_EQ(static_cast<GLenum>(GL_RGB), info_->GetColorAttachmentFormat()); + EXPECT_FALSE(info_->HasDepthAttachment()); + EXPECT_FALSE(info_->HasStencilAttachment()); // check adding another info_->AttachRenderbuffer(GL_DEPTH_ATTACHMENT, rb_info1); EXPECT_TRUE(info_->HasUnclearedAttachment(GL_COLOR_ATTACHMENT0)); EXPECT_TRUE(info_->HasUnclearedAttachment(GL_DEPTH_ATTACHMENT)); EXPECT_TRUE(info_->IsNotComplete()); + EXPECT_EQ(static_cast<GLenum>(GL_RGB), info_->GetColorAttachmentFormat()); + EXPECT_TRUE(info_->HasDepthAttachment()); + EXPECT_FALSE(info_->HasStencilAttachment()); // check marking them as cleared. info_->MarkAttachedRenderbuffersAsCleared(); @@ -177,10 +191,16 @@ TEST_F(FramebufferInfoTest, AttachRenderbuffer) { // Check adding one that is already cleared. info_->AttachRenderbuffer(GL_STENCIL_ATTACHMENT, rb_info1); EXPECT_FALSE(info_->HasUnclearedAttachment(GL_STENCIL_ATTACHMENT)); + EXPECT_EQ(static_cast<GLenum>(GL_RGB), info_->GetColorAttachmentFormat()); + EXPECT_TRUE(info_->HasDepthAttachment()); + EXPECT_TRUE(info_->HasStencilAttachment()); // Check marking the renderbuffer as unclared. rb_info1->SetInfo(kSamples1, kFormat1, kWidth1, kHeight1); EXPECT_FALSE(info_->IsNotComplete()); + EXPECT_EQ(static_cast<GLenum>(kFormat1), info_->GetColorAttachmentFormat()); + EXPECT_TRUE(info_->HasDepthAttachment()); + EXPECT_TRUE(info_->HasStencilAttachment()); const FramebufferManager::FramebufferInfo::Attachment* attachment = info_->GetAttachment(GL_COLOR_ATTACHMENT0); @@ -230,6 +250,9 @@ TEST_F(FramebufferInfoTest, AttachRenderbuffer) { // Check removing it. info_->AttachRenderbuffer(GL_STENCIL_ATTACHMENT, NULL); EXPECT_FALSE(info_->HasUnclearedAttachment(GL_STENCIL_ATTACHMENT)); + EXPECT_EQ(static_cast<GLenum>(kFormat1), info_->GetColorAttachmentFormat()); + EXPECT_TRUE(info_->HasDepthAttachment()); + EXPECT_FALSE(info_->HasStencilAttachment()); rb_manager.Destroy(false); } @@ -278,12 +301,14 @@ TEST_F(FramebufferInfoTest, AttachTexture) { info_->AttachTexture(GL_COLOR_ATTACHMENT0, tex_info1, kTarget1, kLevel1); EXPECT_FALSE(info_->HasUnclearedAttachment(GL_COLOR_ATTACHMENT0)); EXPECT_TRUE(info_->IsNotComplete()); + EXPECT_EQ(static_cast<GLenum>(0), info_->GetColorAttachmentFormat()); tex_manager.SetInfoTarget(tex_info1, GL_TEXTURE_2D); tex_manager.SetLevelInfo( &feature_info, tex_info1, GL_TEXTURE_2D, kLevel1, kFormat1, kWidth1, kHeight1, kDepth, kBorder, kFormat1, kType); EXPECT_FALSE(info_->IsNotComplete()); + EXPECT_EQ(static_cast<GLenum>(kFormat1), info_->GetColorAttachmentFormat()); const FramebufferManager::FramebufferInfo::Attachment* attachment = info_->GetAttachment(GL_COLOR_ATTACHMENT0); @@ -306,6 +331,7 @@ TEST_F(FramebufferInfoTest, AttachTexture) { kFormat2, kWidth2, kHeight2, kDepth, kBorder, kFormat2, kType); info_->AttachTexture(GL_COLOR_ATTACHMENT0, tex_info2, kTarget2, kLevel2); + EXPECT_EQ(static_cast<GLenum>(kFormat2), info_->GetColorAttachmentFormat()); attachment = info_->GetAttachment(GL_COLOR_ATTACHMENT0); ASSERT_TRUE(attachment != NULL); @@ -326,10 +352,12 @@ TEST_F(FramebufferInfoTest, AttachTexture) { EXPECT_EQ(kSamples3, attachment->samples()); EXPECT_EQ(kFormat3, attachment->internal_format()); EXPECT_TRUE(attachment->cleared()); + EXPECT_EQ(static_cast<GLenum>(kFormat3), info_->GetColorAttachmentFormat()); // Check removing it. info_->AttachTexture(GL_COLOR_ATTACHMENT0, NULL, 0, 0); EXPECT_TRUE(info_->GetAttachment(GL_COLOR_ATTACHMENT0) == NULL); + EXPECT_EQ(static_cast<GLenum>(0), info_->GetColorAttachmentFormat()); tex_manager.Destroy(false); } diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc index 3e0e02a..e23c05b 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc @@ -126,7 +126,7 @@ static bool IsAngle() { #endif } -void WrappedTexImage2D( +static void WrappedTexImage2D( GLenum target, GLint level, GLenum internal_format, @@ -735,6 +735,15 @@ class GLES2DecoderImpl : public base::SupportsWeakPtr<GLES2DecoderImpl>, void RestoreCurrentRenderbufferBindings(); void RestoreCurrentTexture2DBindings(); + // Sets DEPTH_TEST, STENCIL_TEST and color mask for the current framebuffer. + void ApplyDirtyState(); + + // These check the state of the currently bound framebuffer or the + // backbuffer if no framebuffer is bound. + bool BoundFramebufferHasColorAttachmentWithAlpha(); + bool BoundFramebufferHasDepthAttachment(); + bool BoundFramebufferHasStencilAttachment(); + private: friend class ScopedGLErrorSuppressor; friend class ScopedResolvedFrameBufferBinder; @@ -824,6 +833,7 @@ class GLES2DecoderImpl : public base::SupportsWeakPtr<GLES2DecoderImpl>, // Get the format of the currently bound frame buffer (either FBO or regular // back buffer) GLenum GetBoundReadFrameBufferInternalFormat(); + GLenum GetBoundDrawFrameBufferInternalFormat(); // Wrapper for CompressedTexImage2D commands. error::Error DoCompressedTexImage2D( @@ -1259,8 +1269,8 @@ class GLES2DecoderImpl : public base::SupportsWeakPtr<GLES2DecoderImpl>, // Wrapper for glValidateProgram. void DoValidateProgram(GLuint program_client_id); - void DoCopyTextureToParentTextureCHROMIUM(GLuint client_texture_id, - GLuint parent_client_texture_id); + void DoCopyTextureToParentTextureCHROMIUM( + GLuint client_texture_id, GLuint parent_client_texture_id); void DoResizeCHROMIUM(GLuint width, GLuint height); @@ -1462,6 +1472,7 @@ class GLES2DecoderImpl : public base::SupportsWeakPtr<GLES2DecoderImpl>, GLclampf clear_depth_; GLboolean mask_depth_; bool enable_scissor_test_; + bool state_dirty_; // The program in use by glUseProgram ProgramManager::ProgramInfo::Ref current_program_; @@ -1501,6 +1512,8 @@ class GLES2DecoderImpl : public base::SupportsWeakPtr<GLES2DecoderImpl>, // The format of the back buffer_ GLenum back_buffer_color_format_; + bool back_buffer_has_depth_; + bool back_buffer_has_stencil_; bool teximage2d_faster_than_texsubimage2d_; bool bufferdata_faster_than_buffersubdata_; @@ -1844,6 +1857,7 @@ GLES2DecoderImpl::GLES2DecoderImpl(SurfaceManager* surface_manager, clear_depth_(1.0f), mask_depth_(true), enable_scissor_test_(false), + state_dirty_(true), offscreen_target_color_format_(0), offscreen_target_depth_format_(0), offscreen_target_stencil_format_(0), @@ -1851,6 +1865,8 @@ GLES2DecoderImpl::GLES2DecoderImpl(SurfaceManager* surface_manager, copy_texture_to_parent_texture_fb_(0), offscreen_saved_color_format_(0), back_buffer_color_format_(0), + back_buffer_has_depth_(false), + back_buffer_has_stencil_(false), teximage2d_faster_than_texsubimage2d_(true), bufferdata_faster_than_buffersubdata_(true), current_decoder_error_(error::kNoError), @@ -1930,10 +1946,6 @@ bool GLES2DecoderImpl::Initialize( vertex_attrib_manager_.Initialize(group_->max_vertex_attribs()); - GLint v = 0; - glGetIntegerv(GL_ALPHA_BITS, &v); - back_buffer_color_format_ = v ? GL_RGBA : GL_RGB; - if (gfx::GetGLImplementation() != gfx::kGLImplementationEGLGLES2) { // We have to enable vertex array 0 on OpenGL or it won't render. Note that // OpenGL ES 2.0 does not have this issue. @@ -1961,11 +1973,30 @@ bool GLES2DecoderImpl::Initialize( glActiveTexture(GL_TEXTURE0); CHECK_GL_ERROR(); - if (surface_->IsOffscreen()) { - ContextCreationAttribParser attrib_parser; - if (!attrib_parser.Parse(attribs)) - return false; + ContextCreationAttribParser attrib_parser; + if (!attrib_parser.Parse(attribs)) + return false; + + // These are NOT if the back buffer has these proprorties. They are + // if we want the command buffer to enforce them regardless of what + // the real backbuffer is assuming the real back buffer gives us more than + // we ask for. In other words, if we ask for RGB and we get RGBA then we'll + // make it appear RGB. If on the other hand we ask for RGBA nd get RGB we + // can't do anything about that. + + GLint v = 0; + glGetIntegerv(GL_ALPHA_BITS, &v); + // This checks if the user requested RGBA and we have RGBA then RGBA. If the + // user requested RGB then RGB. If the user did not specify a preference than + // use whatever we were given. Same for DEPTH and STENCIL. + back_buffer_color_format_ = + (attrib_parser.alpha_size_ != 0 && v > 0) ? GL_RGBA : GL_RGB; + glGetIntegerv(GL_DEPTH_BITS, &v); + back_buffer_has_depth_ = attrib_parser.depth_size_ != 0 && v > 0; + glGetIntegerv(GL_STENCIL_BITS, &v); + back_buffer_has_stencil_ = attrib_parser.stencil_size_ != 0 && v > 0; + if (surface_->IsOffscreen()) { if (attrib_parser.samples_ > 0 && attrib_parser.sample_buffers_ > 0 && (context_->HasExtension("GL_EXT_framebuffer_multisample") || context_->HasExtension("GL_ANGLE_framebuffer_multisample"))) { @@ -2234,6 +2265,10 @@ void GLES2DecoderImpl::DeleteFramebuffersHelper( FramebufferManager::FramebufferInfo* info = GetFramebufferInfo(client_ids[ii]); if (info) { + if (info == bound_draw_framebuffer_) { + bound_draw_framebuffer_ = NULL; + state_dirty_ = true; + } GLuint service_id = info->service_id(); glDeleteFramebuffersEXT(1, &service_id); RemoveFramebufferInfo(client_ids[ii]); @@ -2247,6 +2282,7 @@ void GLES2DecoderImpl::DeleteRenderbuffersHelper( RenderbufferManager::RenderbufferInfo* info = GetRenderbufferInfo(client_ids[ii]); if (info) { + state_dirty_ = true; GLuint service_id = info->service_id(); glDeleteRenderbuffersEXT(1, &service_id); RemoveRenderbufferInfo(client_ids[ii]); @@ -2259,6 +2295,9 @@ void GLES2DecoderImpl::DeleteTexturesHelper( for (GLsizei ii = 0; ii < n; ++ii) { TextureManager::TextureInfo* info = GetTextureInfo(client_ids[ii]); if (info) { + if (info->IsAttachedToFramebuffer()) { + state_dirty_ = true; + } GLuint service_id = info->service_id(); glDeleteTextures(1, &service_id); RemoveTextureInfo(client_ids[ii]); @@ -2283,13 +2322,17 @@ static void RebindCurrentFramebuffer( FramebufferManager::FramebufferInfo* info, FrameBuffer* offscreen_frame_buffer) { GLuint framebuffer_id = info ? info->service_id() : 0; + if (framebuffer_id == 0 && offscreen_frame_buffer) { framebuffer_id = offscreen_frame_buffer->id(); } + glBindFramebufferEXT(target, framebuffer_id); } void GLES2DecoderImpl::RestoreCurrentFramebufferBindings() { + state_dirty_ = true; + if (!feature_info_->feature_flags().chromium_framebuffer_multisample) { RebindCurrentFramebuffer( GL_FRAMEBUFFER, @@ -2346,12 +2389,17 @@ gfx::Size GLES2DecoderImpl::GetBoundReadFrameBufferSize() { GLenum GLES2DecoderImpl::GetBoundReadFrameBufferInternalFormat() { if (bound_read_framebuffer_ != 0) { - const FramebufferManager::FramebufferInfo::Attachment* attachment = - bound_read_framebuffer_->GetAttachment(GL_COLOR_ATTACHMENT0); - if (attachment) { - return attachment->internal_format(); - } - return 0; + return bound_read_framebuffer_->GetColorAttachmentFormat(); + } else if (offscreen_target_frame_buffer_.get()) { + return offscreen_target_color_format_; + } else { + return back_buffer_color_format_; + } +} + +GLenum GLES2DecoderImpl::GetBoundDrawFrameBufferInternalFormat() { + if (bound_draw_framebuffer_ != 0) { + return bound_draw_framebuffer_->GetColorAttachmentFormat(); } else if (offscreen_target_frame_buffer_.get()) { return offscreen_target_color_format_; } else { @@ -2443,7 +2491,7 @@ bool GLES2DecoderImpl::UpdateOffscreenFrameBufferSize() { // Clear the target frame buffer. { ScopedFrameBufferBinder binder(this, offscreen_target_frame_buffer_->id()); - glClearColor(0, 0, 0, 0); + glClearColor(0, 0, 0, offscreen_target_color_format_ == GL_RGB); glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); glClearStencil(0); glStencilMaskSeparate(GL_FRONT, GL_TRUE); @@ -2824,6 +2872,47 @@ void GLES2DecoderImpl::DoBindBuffer(GLenum target, GLuint client_id) { glBindBuffer(target, service_id); } +bool GLES2DecoderImpl::BoundFramebufferHasColorAttachmentWithAlpha() { + return (GLES2Util::GetChannelsForFormat( + GetBoundDrawFrameBufferInternalFormat()) & 0x0008) != 0; +} + +bool GLES2DecoderImpl::BoundFramebufferHasDepthAttachment() { + if (bound_draw_framebuffer_) { + return bound_draw_framebuffer_->HasDepthAttachment(); + } + if (offscreen_target_frame_buffer_.get()) { + return offscreen_target_depth_format_ != 0; + } + return back_buffer_has_depth_; +} + +bool GLES2DecoderImpl::BoundFramebufferHasStencilAttachment() { + if (bound_draw_framebuffer_) { + return bound_draw_framebuffer_->HasStencilAttachment(); + } + if (offscreen_target_frame_buffer_.get()) { + return offscreen_target_stencil_format_ != 0; + } + return back_buffer_has_stencil_; +} + +void GLES2DecoderImpl::ApplyDirtyState() { + if (state_dirty_) { + glColorMask( + mask_red_, mask_green_, mask_blue_, + mask_alpha_ && BoundFramebufferHasColorAttachmentWithAlpha()); + glDepthMask(mask_depth_ && BoundFramebufferHasDepthAttachment()); + glStencilMaskSeparate( + GL_FRONT, + BoundFramebufferHasStencilAttachment() ? mask_stencil_front_ : 0); + glStencilMaskSeparate( + GL_BACK, + BoundFramebufferHasStencilAttachment() ? mask_stencil_back_ : 0); + state_dirty_ = false; + } +} + void GLES2DecoderImpl::DoBindFramebuffer(GLenum target, GLuint client_id) { FramebufferManager::FramebufferInfo* info = NULL; GLuint service_id = 0; @@ -2852,10 +2941,13 @@ void GLES2DecoderImpl::DoBindFramebuffer(GLenum target, GLuint client_id) { bound_read_framebuffer_ = info; } + state_dirty_ = true; + // When rendering to an offscreen frame buffer, instead of unbinding from // the current frame buffer, bind to the offscreen target frame buffer. - if (info == NULL && offscreen_target_frame_buffer_.get()) + if (info == NULL && offscreen_target_frame_buffer_.get()) { service_id = offscreen_target_frame_buffer_->id(); + } glBindFramebufferEXT(target, service_id); } @@ -3009,6 +3101,57 @@ bool GLES2DecoderImpl::GetHelper( } } switch (pname) { + case GL_COLOR_WRITEMASK: + *num_written = 4; + if (params) { + params[0] = mask_red_; + params[1] = mask_green_; + params[2] = mask_blue_; + params[3] = mask_alpha_; + } + return true; + case GL_DEPTH_WRITEMASK: + *num_written = 1; + if (params) { + params[0] = mask_depth_; + } + return true; + case GL_STENCIL_BACK_WRITEMASK: + *num_written = 1; + if (params) { + params[0] = mask_stencil_back_; + } + return true; + case GL_STENCIL_WRITEMASK: + *num_written = 1; + if (params) { + params[0] = mask_stencil_front_; + } + return true; + case GL_ALPHA_BITS: + *num_written = 1; + if (params) { + GLint v = 0; + glGetIntegerv(GL_ALPHA_BITS, &v); + params[0] = BoundFramebufferHasColorAttachmentWithAlpha() ? v : 0; + } + return true; + case GL_DEPTH_BITS: + *num_written = 1; + if (params) { + GLint v = 0; + glGetIntegerv(GL_DEPTH_BITS, &v); + params[0] = BoundFramebufferHasDepthAttachment() ? v : 0; + } + return true; + case GL_STENCIL_BITS: + *num_written = 1; + if (params) { + GLint v = 0; + glGetIntegerv(GL_STENCIL_BITS, &v); + params[0] = BoundFramebufferHasStencilAttachment() ? v : 0; + } + return true; case GL_COMPRESSED_TEXTURE_FORMATS: *num_written = 0; // We don't support compressed textures. @@ -3400,6 +3543,7 @@ error::Error GLES2DecoderImpl::HandleRegisterSharedIdsCHROMIUM( void GLES2DecoderImpl::DoClear(GLbitfield mask) { if (CheckFramebufferComplete("glClear")) { + ApplyDirtyState(); glClear(mask); } } @@ -3426,6 +3570,7 @@ void GLES2DecoderImpl::DoDrawArrays( bool simulated_fixed_attribs = false; if (SimulateFixedAttribs(max_vertex_accessed, &simulated_fixed_attribs)) { bool textures_set = SetBlackTextureForNonRenderableTextures(); + ApplyDirtyState(); glDrawArrays(mode, first, count); if (textures_set) { RestoreStateForNonRenderableTextures(); @@ -3474,6 +3619,9 @@ void GLES2DecoderImpl::DoFramebufferRenderbuffer( } } } + if (framebuffer_info == bound_draw_framebuffer_) { + state_dirty_ = true; + } } void GLES2DecoderImpl::SetCapabilityState(GLenum cap, bool enabled) { @@ -3521,27 +3669,28 @@ void GLES2DecoderImpl::DoColorMask( mask_green_ = green; mask_blue_ = blue; mask_alpha_ = alpha; - glColorMask(red, green, blue, alpha); + state_dirty_ = true; } void GLES2DecoderImpl::DoDepthMask(GLboolean depth) { mask_depth_ = depth; - glDepthMask(depth); + state_dirty_ = true; } void GLES2DecoderImpl::DoStencilMask(GLuint mask) { mask_stencil_front_ = mask; mask_stencil_back_ = mask; - glStencilMask(mask); + state_dirty_ = true; } void GLES2DecoderImpl::DoStencilMaskSeparate(GLenum face, GLuint mask) { - if (face == GL_FRONT) { + if (face == GL_FRONT || face == GL_FRONT_AND_BACK) { mask_stencil_front_ = mask; - } else { + } + if (face == GL_BACK || face == GL_FRONT_AND_BACK) { mask_stencil_back_ = mask; } - glStencilMaskSeparate(face, mask); + state_dirty_ = true; } // NOTE: There's an assumption here that Texture attachments @@ -3586,13 +3735,10 @@ void GLES2DecoderImpl::ClearUnclearedRenderbuffers( } void GLES2DecoderImpl::RestoreClearState() { + state_dirty_ = true; glClearColor(clear_red_, clear_green_, clear_blue_, clear_alpha_); - glColorMask(mask_red_, mask_green_, mask_blue_, mask_alpha_); glClearStencil(clear_stencil_); - glStencilMaskSeparate(GL_FRONT, mask_stencil_front_); - glStencilMaskSeparate(GL_BACK, mask_stencil_back_); glClearDepth(clear_depth_); - glDepthMask(mask_depth_); if (enable_scissor_test_) { glEnable(GL_SCISSOR_TEST); } @@ -3638,6 +3784,9 @@ void GLES2DecoderImpl::DoFramebufferTexture2D( ClearUnclearedRenderbuffers(target, framebuffer_info); } } + if (framebuffer_info == bound_draw_framebuffer_) { + state_dirty_ = true; + } } void GLES2DecoderImpl::DoGetFramebufferAttachmentParameteriv( @@ -4433,6 +4582,7 @@ error::Error GLES2DecoderImpl::HandleDrawElements( bool simulated_fixed_attribs = false; if (SimulateFixedAttribs(max_vertex_accessed, &simulated_fixed_attribs)) { bool textures_set = SetBlackTextureForNonRenderableTextures(); + ApplyDirtyState(); const GLvoid* indices = reinterpret_cast<const GLvoid*>(offset); glDrawElements(mode, count, type, indices); if (textures_set) { @@ -5648,6 +5798,10 @@ error::Error GLES2DecoderImpl::DoTexImage2D( pixels = zero.get(); } + if (info->IsAttachedToFramebuffer()) { + state_dirty_ = true; + } + if (!teximage2d_faster_than_texsubimage2d_) { GLsizei tex_width = 0; GLsizei tex_height = 0; @@ -5828,6 +5982,10 @@ void GLES2DecoderImpl::DoCopyTexImage2D( ScopedResolvedFrameBufferBinder binder(this, false); gfx::Size size = GetBoundReadFrameBufferSize(); + if (info->IsAttachedToFramebuffer()) { + state_dirty_ = true; + } + // Clip to size to source dimensions GLint copyX = 0; GLint copyY = 0; diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc index d50bb6d..05c4073 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc @@ -45,15 +45,6 @@ class GLES2DecoderTest : public GLES2DecoderTestBase { bool init); }; -class GLES2DecoderRGBBackbufferTest : public GLES2DecoderTest { - public: - GLES2DecoderRGBBackbufferTest() { } - - virtual void SetUp() { - InitDecoder("", false); - } -}; - class GLES2DecoderWithShaderTest : public GLES2DecoderWithShaderTestBase { public: GLES2DecoderWithShaderTest() @@ -89,9 +80,29 @@ class GLES2DecoderWithShaderTest : public GLES2DecoderWithShaderTestBase { } }; +class GLES2DecoderRGBBackbufferTest : public GLES2DecoderWithShaderTest { + public: + GLES2DecoderRGBBackbufferTest() { } + + virtual void SetUp() { + InitDecoder("", false, false, false, false, false, false); + SetupDefaultProgram(); + } +}; + +class GLES2DecoderManualInitTest : public GLES2DecoderWithShaderTest { + public: + GLES2DecoderManualInitTest() { } + + // Override default setup so nothing gets setup. + virtual void SetUp() { + } +}; + TEST_F(GLES2DecoderWithShaderTest, DrawArraysNoAttributesSucceeds) { SetupTexture(); AddExpectationsForSimulatedAttrib0(kNumVertices, 0); + SetupExpectationsForApplyingDefaultDirtyState(); EXPECT_CALL(*gl_, DrawArrays(GL_TRIANGLES, 0, kNumVertices)) .Times(1) @@ -131,6 +142,7 @@ TEST_F(GLES2DecoderWithShaderTest, DrawArraysBadTextureUsesBlack) { .Times(1) .RetiresOnSaturation(); } + SetupExpectationsForApplyingDefaultDirtyState(); DrawArrays cmd; cmd.Init(GL_TRIANGLES, 0, kNumVertices); EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); @@ -163,8 +175,10 @@ TEST_F(GLES2DecoderWithShaderTest, TEST_F(GLES2DecoderWithShaderTest, DrawArraysValidAttributesSucceeds) { SetupTexture(); SetupVertexBuffer(); + DoEnableVertexAttribArray(1); DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0); AddExpectationsForSimulatedAttrib0(kNumVertices, kServiceBufferId); + SetupExpectationsForApplyingDefaultDirtyState(); EXPECT_CALL(*gl_, DrawArrays(GL_TRIANGLES, 0, kNumVertices)) .Times(1) @@ -191,6 +205,7 @@ TEST_F(GLES2DecoderWithShaderTest, DrawArraysDeletedBufferFails) { TEST_F(GLES2DecoderWithShaderTest, DrawArraysDeletedProgramSucceeds) { SetupTexture(); AddExpectationsForSimulatedAttrib0(kNumVertices, 0); + SetupExpectationsForApplyingDefaultDirtyState(); DoDeleteProgram(client_program_id_, kServiceProgramId); EXPECT_CALL(*gl_, DrawArrays(_, _, _)) @@ -259,6 +274,7 @@ TEST_F(GLES2DecoderWithShaderTest, DrawElementsNoAttributesSucceeds) { SetupTexture(); SetupIndexBuffer(); AddExpectationsForSimulatedAttrib0(kMaxValidIndex + 1, 0); + SetupExpectationsForApplyingDefaultDirtyState(); EXPECT_CALL(*gl_, DrawElements(GL_TRIANGLES, kValidIndexRangeCount, GL_UNSIGNED_SHORT, BufferOffset(kValidIndexRangeStart * 2))) @@ -317,6 +333,7 @@ TEST_F(GLES2DecoderWithShaderTest, DrawElementsValidAttributesSucceeds) { SetupIndexBuffer(); DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0); AddExpectationsForSimulatedAttrib0(kMaxValidIndex + 1, kServiceBufferId); + SetupExpectationsForApplyingDefaultDirtyState(); EXPECT_CALL(*gl_, DrawElements(GL_TRIANGLES, kValidIndexRangeCount, GL_UNSIGNED_SHORT, @@ -349,6 +366,7 @@ TEST_F(GLES2DecoderWithShaderTest, DrawElementsDeletedProgramSucceeds) { SetupTexture(); SetupIndexBuffer(); AddExpectationsForSimulatedAttrib0(kMaxValidIndex + 1, 0); + SetupExpectationsForApplyingDefaultDirtyState(); DoDeleteProgram(client_program_id_, kServiceProgramId); EXPECT_CALL(*gl_, DrawElements(_, _, _, _)) @@ -1245,13 +1263,29 @@ TEST_F(GLES2DecoderTest, CheckFramebufferStatusWithNoBoundTarget) { EXPECT_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_COMPLETE), *result); } +TEST_F(GLES2DecoderWithShaderTest, BindAndDeleteFramebuffer) { + SetupTexture(); + AddExpectationsForSimulatedAttrib0(kNumVertices, 0); + SetupExpectationsForApplyingDefaultDirtyState(); + DoBindFramebuffer(GL_FRAMEBUFFER, client_framebuffer_id_, + kServiceFramebufferId); + DoDeleteFramebuffer(client_framebuffer_id_, kServiceFramebufferId); + EXPECT_CALL(*gl_, DrawArrays(GL_TRIANGLES, 0, kNumVertices)) + .Times(1) + .RetiresOnSaturation(); + DrawArrays cmd; + cmd.Init(GL_TRIANGLES, 0, kNumVertices); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); +} + TEST_F(GLES2DecoderTest, FramebufferRenderbufferWithNoBoundTarget) { EXPECT_CALL(*gl_, FramebufferRenderbufferEXT(_, _, _, _)) .Times(0); FramebufferRenderbuffer cmd; cmd.Init( - GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, - client_renderbuffer_id_); + GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, + client_renderbuffer_id_); EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); EXPECT_EQ(GL_INVALID_OPERATION, GetGLError()); } @@ -1300,12 +1334,8 @@ TEST_F(GLES2DecoderTest, GetFramebufferAttachmentParameterivWithRenderbuffer) { SetupExpectationsForFramebufferAttachment( GL_COLOR_BUFFER_BIT, // clear bits 0, 0, 0, 0, // color - 0x1111, // color bits 0, // stencil - -1, // stencil mask back, - -1, // stencil mask front, 1.0f, // depth - 1, // depth mask false); // scissor test EXPECT_CALL(*gl_, GetError()) .WillOnce(Return(GL_NO_ERROR)) @@ -1360,12 +1390,8 @@ TEST_F(GLES2DecoderTest, GetFramebufferAttachmentParameterivWithTexture) { SetupExpectationsForFramebufferAttachment( 0, // clear bits 0, 0, 0, 0, // color - 0x1111, // color bits 0, // stencil - -1, // stencil mask back, - -1, // stencil mask front, 1.0f, // depth - 1, // depth mask false); // scissor test EXPECT_CALL(*gl_, GetError()) .WillOnce(Return(GL_NO_ERROR)) @@ -1542,12 +1568,8 @@ void GLES2DecoderTest::CheckReadPixelsOutOfRange( SetupExpectationsForFramebufferAttachment( 0, // clear bits 0, 0, 0, 0, // color - 0x1111, // color bits 0, // stencil - -1, // stencil mask back, - -1, // stencil mask front, 1.0f, // depth - 1, // depth mask false); // scissor test FramebufferTexture2D fbtex_cmd; fbtex_cmd.Init( @@ -2529,9 +2551,9 @@ TEST_F(GLES2DecoderTest, FramebufferRenderbufferClearColor) { EXPECT_CALL(*gl_, ClearColor(0.1f, 0.2f, 0.3f, 0.4f)) .Times(1) .RetiresOnSaturation(); - EXPECT_CALL(*gl_, ColorMask(0, 1, 0, 1)) - .Times(1) - .RetiresOnSaturation(); +// EXPECT_CALL(*gl_, ColorMask(0, 1, 0, 1)) +// .Times(0) +// .RetiresOnSaturation(); EXPECT_CALL(*gl_, Enable(GL_SCISSOR_TEST)) .Times(1) .RetiresOnSaturation(); @@ -2549,12 +2571,8 @@ TEST_F(GLES2DecoderTest, FramebufferRenderbufferClearColor) { SetupExpectationsForFramebufferAttachment( GL_COLOR_BUFFER_BIT, // clear bits 0.1f, 0.2f, 0.3f, 0.4f, // color - 0x0101, // color bits 0, // stencil - -1, // stencil mask back - -1, // stencil mask front 1.0f, // depth - 1, // depth mask true); // scissor test EXPECT_EQ(error::kNoError, ExecuteCmd(color_cmd)); EXPECT_EQ(error::kNoError, ExecuteCmd(color_mask_cmd)); @@ -2577,9 +2595,9 @@ TEST_F(GLES2DecoderTest, FramebufferRenderbufferClearDepth) { EXPECT_CALL(*gl_, ClearDepth(0.5f)) .Times(1) .RetiresOnSaturation(); - EXPECT_CALL(*gl_, DepthMask(0)) - .Times(1) - .RetiresOnSaturation(); +// EXPECT_CALL(*gl_, DepthMask(0)) +// .Times(1) +// .RetiresOnSaturation(); EXPECT_CALL(*gl_, GetError()) .WillOnce(Return(GL_NO_ERROR)) .RetiresOnSaturation(); @@ -2594,12 +2612,8 @@ TEST_F(GLES2DecoderTest, FramebufferRenderbufferClearDepth) { SetupExpectationsForFramebufferAttachment( GL_DEPTH_BUFFER_BIT, // clear bits 0, 0, 0, 0, // color - 0x1111, // color bits 0, // stencil - -1, // stencil mask back, - -1, // stencil mask front, 0.5f, // depth - 0, // depth mask false); // scissor test EXPECT_EQ(error::kNoError, ExecuteCmd(depth_cmd)); EXPECT_EQ(error::kNoError, ExecuteCmd(depth_mask_cmd)); @@ -2621,9 +2635,9 @@ TEST_F(GLES2DecoderTest, FramebufferRenderbufferClearStencil) { EXPECT_CALL(*gl_, ClearStencil(123)) .Times(1) .RetiresOnSaturation(); - EXPECT_CALL(*gl_, StencilMaskSeparate(GL_BACK, 0x1234u)) - .Times(1) - .RetiresOnSaturation(); +// EXPECT_CALL(*gl_, StencilMaskSeparate(GL_BACK, 0x1234u)) +// .Times(1) +// .RetiresOnSaturation(); EXPECT_CALL(*gl_, GetError()) .WillOnce(Return(GL_NO_ERROR)) .RetiresOnSaturation(); @@ -2638,12 +2652,8 @@ TEST_F(GLES2DecoderTest, FramebufferRenderbufferClearStencil) { SetupExpectationsForFramebufferAttachment( GL_STENCIL_BUFFER_BIT, // clear bits 0, 0, 0, 0, // color - 0x1111, // color bits 123, // stencil - -1, // stencil mask back, - 0x1234u, // stencil mask front, 1.0f, // depth - 1, // depth mask false); // scissor test EXPECT_EQ(error::kNoError, ExecuteCmd(stencil_cmd)); EXPECT_EQ(error::kNoError, ExecuteCmd(stencil_mask_separate_cmd)); @@ -2725,12 +2735,8 @@ TEST_F(GLES2DecoderTest, FramebufferRenderbufferClearDepthStencil) { SetupExpectationsForFramebufferAttachment( GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, // clear bits 0, 0, 0, 0, // color - 0x1111, // color bits 123, // stencil - -1, // stencil mask back, - -1, // stencil mask front, 0.5f, // depth - 1, // depth mask false); // scissor test EXPECT_EQ(error::kNoError, ExecuteCmd(depth_cmd)); EXPECT_EQ(error::kNoError, ExecuteCmd(stencil_cmd)); @@ -2974,6 +2980,381 @@ TEST_F(GLES2DecoderTest, EXPECT_EQ(surface.get(), decoder_->GetGLSurface()); } +// Test that with an RGB backbuffer if we set the color mask to 1,1,1,1 it is +// set to 1,1,1,0 at Draw time but is 1,1,1,1 at query time. +TEST_F(GLES2DecoderRGBBackbufferTest, RGBBackbufferColorMask) { + ColorMask cmd; + cmd.Init(true, true, true, true); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); + + SetupTexture(); + AddExpectationsForSimulatedAttrib0(kNumVertices, 0); + SetupExpectationsForApplyingDirtyState( + true, // Framebuffer is RGB + false, // Framebuffer has depth + false, // Framebuffer has stencil + 0x1110, // color bits + false, // depth mask + 0, // front stencil mask + 0); // back stencil mask + + EXPECT_CALL(*gl_, DrawArrays(GL_TRIANGLES, 0, kNumVertices)) + .Times(1) + .RetiresOnSaturation(); + DrawArrays draw_cmd; + draw_cmd.Init(GL_TRIANGLES, 0, kNumVertices); + EXPECT_EQ(error::kNoError, ExecuteCmd(draw_cmd)); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); + + EXPECT_CALL(*gl_, GetError()) + .WillOnce(Return(GL_NO_ERROR)) + .WillOnce(Return(GL_NO_ERROR)) + .RetiresOnSaturation(); + typedef GetIntegerv::Result Result; + Result* result = static_cast<Result*>(shared_memory_address_); + EXPECT_CALL(*gl_, GetIntegerv(GL_COLOR_WRITEMASK, result->GetData())) + .Times(0); + result->size = 0; + GetIntegerv cmd2; + cmd2.Init(GL_COLOR_WRITEMASK, shared_memory_id_, shared_memory_offset_); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd2)); + EXPECT_EQ( + decoder_->GetGLES2Util()->GLGetNumValuesReturned(GL_COLOR_WRITEMASK), + result->GetNumResults()); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); + EXPECT_EQ(1, result->GetData()[0]); + EXPECT_EQ(1, result->GetData()[1]); + EXPECT_EQ(1, result->GetData()[2]); + EXPECT_EQ(1, result->GetData()[3]); +} + +// Test that with no depth if we set DepthMask true that it's set to false at +// draw time but querying it returns true. +TEST_F(GLES2DecoderRGBBackbufferTest, RGBBackbufferDepthMask) { + EXPECT_CALL(*gl_, DepthMask(true)) + .Times(0) + .RetiresOnSaturation(); + DepthMask cmd; + cmd.Init(true); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); + + SetupTexture(); + AddExpectationsForSimulatedAttrib0(kNumVertices, 0); + SetupExpectationsForApplyingDirtyState( + true, // Framebuffer is RGB + false, // Framebuffer has depth + false, // Framebuffer has stencil + 0x1110, // color bits + false, // depth mask + 0, // front stencil mask + 0); // back stencil mask + + EXPECT_CALL(*gl_, DrawArrays(GL_TRIANGLES, 0, kNumVertices)) + .Times(1) + .RetiresOnSaturation(); + DrawArrays draw_cmd; + draw_cmd.Init(GL_TRIANGLES, 0, kNumVertices); + EXPECT_EQ(error::kNoError, ExecuteCmd(draw_cmd)); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); + + EXPECT_CALL(*gl_, GetError()) + .WillOnce(Return(GL_NO_ERROR)) + .WillOnce(Return(GL_NO_ERROR)) + .RetiresOnSaturation(); + typedef GetIntegerv::Result Result; + Result* result = static_cast<Result*>(shared_memory_address_); + EXPECT_CALL(*gl_, GetIntegerv(GL_DEPTH_WRITEMASK, result->GetData())) + .Times(0); + result->size = 0; + GetIntegerv cmd2; + cmd2.Init(GL_DEPTH_WRITEMASK, shared_memory_id_, shared_memory_offset_); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd2)); + EXPECT_EQ( + decoder_->GetGLES2Util()->GLGetNumValuesReturned(GL_DEPTH_WRITEMASK), + result->GetNumResults()); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); + EXPECT_EQ(1, result->GetData()[0]); +} + +// Test that with no stencil if we set the stencil mask it's still set to 0 at +// draw time but gets our value if we query. +TEST_F(GLES2DecoderRGBBackbufferTest, RGBBackbufferStencilMask) { + const GLint kMask = 123; + EXPECT_CALL(*gl_, StencilMask(kMask)) + .Times(0) + .RetiresOnSaturation(); + StencilMask cmd; + cmd.Init(kMask); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); + + SetupTexture(); + AddExpectationsForSimulatedAttrib0(kNumVertices, 0); + SetupExpectationsForApplyingDirtyState( + true, // Framebuffer is RGB + false, // Framebuffer has depth + false, // Framebuffer has stencil + 0x1110, // color bits + false, // depth mask + 0, // front stencil mask + 0); // back stencil mask + EXPECT_CALL(*gl_, DrawArrays(GL_TRIANGLES, 0, kNumVertices)) + .Times(1) + .RetiresOnSaturation(); + DrawArrays draw_cmd; + draw_cmd.Init(GL_TRIANGLES, 0, kNumVertices); + EXPECT_EQ(error::kNoError, ExecuteCmd(draw_cmd)); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); + + EXPECT_CALL(*gl_, GetError()) + .WillOnce(Return(GL_NO_ERROR)) + .WillOnce(Return(GL_NO_ERROR)) + .RetiresOnSaturation(); + typedef GetIntegerv::Result Result; + Result* result = static_cast<Result*>(shared_memory_address_); + EXPECT_CALL(*gl_, GetIntegerv(GL_STENCIL_TEST, result->GetData())) + .Times(0); + result->size = 0; + GetIntegerv cmd2; + cmd2.Init(GL_STENCIL_WRITEMASK, shared_memory_id_, shared_memory_offset_); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd2)); + EXPECT_EQ( + decoder_->GetGLES2Util()->GLGetNumValuesReturned(GL_STENCIL_WRITEMASK), + result->GetNumResults()); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); + EXPECT_EQ(kMask, result->GetData()[0]); +} + +// Test that if an FBO is bound we get the correct masks. +TEST_F(GLES2DecoderRGBBackbufferTest, RGBBackbufferColorMaskFBO) { + ColorMask cmd; + cmd.Init(true, true, true, true); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); + + SetupTexture(); + SetupVertexBuffer(); + DoEnableVertexAttribArray(0); + DoVertexAttribPointer(0, 2, GL_FLOAT, 0, 0); + DoEnableVertexAttribArray(1); + DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0); + DoEnableVertexAttribArray(2); + DoVertexAttribPointer(2, 2, GL_FLOAT, 0, 0); + SetupExpectationsForApplyingDirtyState( + true, // Framebuffer is RGB + false, // Framebuffer has depth + false, // Framebuffer has stencil + 0x1110, // color bits + false, // depth mask + 0, // front stencil mask + 0); // back stencil mask + + EXPECT_CALL(*gl_, DrawArrays(GL_TRIANGLES, 0, kNumVertices)) + .Times(1) + .RetiresOnSaturation(); + DrawArrays draw_cmd; + draw_cmd.Init(GL_TRIANGLES, 0, kNumVertices); + EXPECT_EQ(error::kNoError, ExecuteCmd(draw_cmd)); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); + + // Check that no extra calls are made on the next draw. + EXPECT_CALL(*gl_, DrawArrays(GL_TRIANGLES, 0, kNumVertices)) + .Times(1) + .RetiresOnSaturation(); + EXPECT_EQ(error::kNoError, ExecuteCmd(draw_cmd)); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); + + // Setup Frame buffer. + DoBindFramebuffer(GL_FRAMEBUFFER, client_framebuffer_id_, + kServiceFramebufferId); + EXPECT_CALL(*gl_, FramebufferRenderbufferEXT(_, _, _, _)) + .Times(0); + FramebufferRenderbuffer fbrb_cmd; + fbrb_cmd.Init( + GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, + client_renderbuffer_id_); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); + + // This time state needs to be set. + SetupExpectationsForApplyingDirtyState( + false, // Framebuffer is RGB + false, // Framebuffer has depth + false, // Framebuffer has stencil + 0x1110, // color bits + false, // depth mask + 0, // front stencil mask + 0); // back stencil mask + EXPECT_CALL(*gl_, DrawArrays(GL_TRIANGLES, 0, kNumVertices)) + .Times(1) + .RetiresOnSaturation(); + EXPECT_EQ(error::kNoError, ExecuteCmd(draw_cmd)); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); + + // Check that no extra calls are made on the next draw. + EXPECT_CALL(*gl_, DrawArrays(GL_TRIANGLES, 0, kNumVertices)) + .Times(1) + .RetiresOnSaturation(); + EXPECT_EQ(error::kNoError, ExecuteCmd(draw_cmd)); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); + + // Unbind + DoBindFramebuffer(GL_FRAMEBUFFER, 0, 0); + + SetupExpectationsForApplyingDirtyState( + true, // Framebuffer is RGB + false, // Framebuffer has depth + false, // Framebuffer has stencil + 0x1110, // color bits + false, // depth mask + 0, // front stencil mask + 0); // back stencil mask + + EXPECT_CALL(*gl_, DrawArrays(GL_TRIANGLES, 0, kNumVertices)) + .Times(1) + .RetiresOnSaturation(); + EXPECT_EQ(error::kNoError, ExecuteCmd(draw_cmd)); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); +} + +TEST_F(GLES2DecoderManualInitTest, ActualAlphaMatchesRequestedAlpha) { + InitDecoder("", true, false, false, true, false, false); + + EXPECT_CALL(*gl_, GetError()) + .WillOnce(Return(GL_NO_ERROR)) + .WillOnce(Return(GL_NO_ERROR)) + .RetiresOnSaturation(); + typedef GetIntegerv::Result Result; + Result* result = static_cast<Result*>(shared_memory_address_); + EXPECT_CALL(*gl_, GetIntegerv(GL_ALPHA_BITS, _)) + .WillOnce(SetArgumentPointee<1>(8)) + .RetiresOnSaturation(); + result->size = 0; + GetIntegerv cmd2; + cmd2.Init(GL_ALPHA_BITS, shared_memory_id_, shared_memory_offset_); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd2)); + EXPECT_EQ( + decoder_->GetGLES2Util()->GLGetNumValuesReturned(GL_ALPHA_BITS), + result->GetNumResults()); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); + EXPECT_EQ(8, result->GetData()[0]); +} + +TEST_F(GLES2DecoderManualInitTest, ActualAlphaDoesNotMatchRequestedAlpha) { + InitDecoder("", true, false, false, false, false, false); + + EXPECT_CALL(*gl_, GetError()) + .WillOnce(Return(GL_NO_ERROR)) + .WillOnce(Return(GL_NO_ERROR)) + .RetiresOnSaturation(); + typedef GetIntegerv::Result Result; + Result* result = static_cast<Result*>(shared_memory_address_); + EXPECT_CALL(*gl_, GetIntegerv(GL_ALPHA_BITS, _)) + .WillOnce(SetArgumentPointee<1>(8)) + .RetiresOnSaturation(); + result->size = 0; + GetIntegerv cmd2; + cmd2.Init(GL_ALPHA_BITS, shared_memory_id_, shared_memory_offset_); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd2)); + EXPECT_EQ( + decoder_->GetGLES2Util()->GLGetNumValuesReturned(GL_ALPHA_BITS), + result->GetNumResults()); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); + EXPECT_EQ(0, result->GetData()[0]); +} + +TEST_F(GLES2DecoderManualInitTest, ActualDepthMatchesRequestedDepth) { + InitDecoder("", false, true, false, false, true, false); + + EXPECT_CALL(*gl_, GetError()) + .WillOnce(Return(GL_NO_ERROR)) + .WillOnce(Return(GL_NO_ERROR)) + .RetiresOnSaturation(); + typedef GetIntegerv::Result Result; + Result* result = static_cast<Result*>(shared_memory_address_); + EXPECT_CALL(*gl_, GetIntegerv(GL_DEPTH_BITS, _)) + .WillOnce(SetArgumentPointee<1>(24)) + .RetiresOnSaturation(); + result->size = 0; + GetIntegerv cmd2; + cmd2.Init(GL_DEPTH_BITS, shared_memory_id_, shared_memory_offset_); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd2)); + EXPECT_EQ( + decoder_->GetGLES2Util()->GLGetNumValuesReturned(GL_DEPTH_BITS), + result->GetNumResults()); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); + EXPECT_EQ(24, result->GetData()[0]); +} + +TEST_F(GLES2DecoderManualInitTest, ActualDepthDoesNotMatchRequestedDepth) { + InitDecoder("", false, true, false, false, false, false); + + EXPECT_CALL(*gl_, GetError()) + .WillOnce(Return(GL_NO_ERROR)) + .WillOnce(Return(GL_NO_ERROR)) + .RetiresOnSaturation(); + typedef GetIntegerv::Result Result; + Result* result = static_cast<Result*>(shared_memory_address_); + EXPECT_CALL(*gl_, GetIntegerv(GL_DEPTH_BITS, _)) + .WillOnce(SetArgumentPointee<1>(24)) + .RetiresOnSaturation(); + result->size = 0; + GetIntegerv cmd2; + cmd2.Init(GL_DEPTH_BITS, shared_memory_id_, shared_memory_offset_); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd2)); + EXPECT_EQ( + decoder_->GetGLES2Util()->GLGetNumValuesReturned(GL_DEPTH_BITS), + result->GetNumResults()); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); + EXPECT_EQ(0, result->GetData()[0]); +} + +TEST_F(GLES2DecoderManualInitTest, ActualStencilMatchesRequestedStencil) { + InitDecoder("", false, false, true, false, false, true); + + EXPECT_CALL(*gl_, GetError()) + .WillOnce(Return(GL_NO_ERROR)) + .WillOnce(Return(GL_NO_ERROR)) + .RetiresOnSaturation(); + typedef GetIntegerv::Result Result; + Result* result = static_cast<Result*>(shared_memory_address_); + EXPECT_CALL(*gl_, GetIntegerv(GL_STENCIL_BITS, _)) + .WillOnce(SetArgumentPointee<1>(8)) + .RetiresOnSaturation(); + result->size = 0; + GetIntegerv cmd2; + cmd2.Init(GL_STENCIL_BITS, shared_memory_id_, shared_memory_offset_); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd2)); + EXPECT_EQ( + decoder_->GetGLES2Util()->GLGetNumValuesReturned(GL_STENCIL_BITS), + result->GetNumResults()); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); + EXPECT_EQ(8, result->GetData()[0]); +} + +TEST_F(GLES2DecoderManualInitTest, ActualStencilDoesNotMatchRequestedStencil) { + InitDecoder("", false, false, true, false, false, false); + + EXPECT_CALL(*gl_, GetError()) + .WillOnce(Return(GL_NO_ERROR)) + .WillOnce(Return(GL_NO_ERROR)) + .RetiresOnSaturation(); + typedef GetIntegerv::Result Result; + Result* result = static_cast<Result*>(shared_memory_address_); + EXPECT_CALL(*gl_, GetIntegerv(GL_STENCIL_BITS, _)) + .WillOnce(SetArgumentPointee<1>(8)) + .RetiresOnSaturation(); + result->size = 0; + GetIntegerv cmd2; + cmd2.Init(GL_STENCIL_BITS, shared_memory_id_, shared_memory_offset_); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd2)); + EXPECT_EQ( + decoder_->GetGLES2Util()->GLGetNumValuesReturned(GL_STENCIL_BITS), + result->GetNumResults()); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); + EXPECT_EQ(0, result->GetData()[0]); +} // TODO(gman): BufferData diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_1.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_1.cc index 9497dbc..dc086f3 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_1.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_1.cc @@ -59,6 +59,22 @@ void GLES2DecoderTestBase::SpecializedSetup<CheckFramebufferStatus, 0>( }; template <> +void GLES2DecoderTestBase::SpecializedSetup<Clear, 0>(bool valid) { + if (valid) { + SetupExpectationsForApplyingDefaultDirtyState(); + } +}; + +template <> +void GLES2DecoderTestBase::SpecializedSetup<ColorMask, 0>( + bool /* valid */) { + // We bind a framebuffer color the colormask test since the framebuffer + // will be considered RGB. + DoBindFramebuffer(GL_FRAMEBUFFER, client_framebuffer_id_, + kServiceFramebufferId); +}; + +template <> void GLES2DecoderTestBase::SpecializedSetup<CopyTexImage2D, 0>( bool valid) { if (valid) { diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_1_autogen.h b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_1_autogen.h index 477c3bf..58f5a86 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_1_autogen.h +++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_1_autogen.h @@ -326,10 +326,9 @@ TEST_F(GLES2DecoderTest1, ClearStencilValidArgs) { } TEST_F(GLES2DecoderTest1, ColorMaskValidArgs) { - EXPECT_CALL(*gl_, ColorMask(1, 2, 3, 4)); SpecializedSetup<ColorMask, 0>(true); ColorMask cmd; - cmd.Init(1, 2, 3, 4); + cmd.Init(true, true, true, true); EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); EXPECT_EQ(GL_NO_ERROR, GetGLError()); } @@ -642,10 +641,9 @@ TEST_F(GLES2DecoderTest1, DepthFuncValidArgs) { } TEST_F(GLES2DecoderTest1, DepthMaskValidArgs) { - EXPECT_CALL(*gl_, DepthMask(1)); SpecializedSetup<DepthMask, 0>(true); DepthMask cmd; - cmd.Init(1); + cmd.Init(true); EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); EXPECT_EQ(GL_NO_ERROR, GetGLError()); } 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 5d7375b..8f93103 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 @@ -282,10 +282,10 @@ TEST_F(GLES2DecoderTest2, RenderbufferStorageInvalidArgs3_0) { } TEST_F(GLES2DecoderTest2, SampleCoverageValidArgs) { - EXPECT_CALL(*gl_, SampleCoverage(1, 2)); + EXPECT_CALL(*gl_, SampleCoverage(1, true)); SpecializedSetup<SampleCoverage, 0>(true); SampleCoverage cmd; - cmd.Init(1, 2); + cmd.Init(1, true); EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); EXPECT_EQ(GL_NO_ERROR, GetGLError()); } @@ -343,7 +343,6 @@ TEST_F(GLES2DecoderTest2, StencilFuncSeparateValidArgs) { } TEST_F(GLES2DecoderTest2, StencilMaskValidArgs) { - EXPECT_CALL(*gl_, StencilMask(1)); SpecializedSetup<StencilMask, 0>(true); StencilMask cmd; cmd.Init(1); @@ -352,7 +351,6 @@ TEST_F(GLES2DecoderTest2, StencilMaskValidArgs) { } TEST_F(GLES2DecoderTest2, StencilMaskSeparateValidArgs) { - EXPECT_CALL(*gl_, StencilMaskSeparate(GL_FRONT, 2)); SpecializedSetup<StencilMaskSeparate, 0>(true); StencilMaskSeparate cmd; cmd.Init(GL_FRONT, 2); 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 9470d08..1322d58c 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc @@ -48,11 +48,17 @@ GLES2DecoderTestBase::GLES2DecoderTestBase() GLES2DecoderTestBase::~GLES2DecoderTestBase() {} void GLES2DecoderTestBase::SetUp() { - InitDecoder("", true); + InitDecoder("", true, true, false, true, true, false); } void GLES2DecoderTestBase::InitDecoder( - const char* extensions, bool has_alpha_backbuffer) { + const char* extensions, + bool has_alpha, + bool has_depth, + bool has_stencil, + bool request_alpha, + bool request_depth, + bool request_stencil) { gl_.reset(new StrictMock<MockGLInterface>()); ::gfx::GLInterface::SetGLInterface(gl_.get()); surface_manager_.reset(new StrictMock<MockSurfaceManager>); @@ -65,9 +71,6 @@ void GLES2DecoderTestBase::InitDecoder( EXPECT_TRUE(group_->Initialize(DisallowedExtensions(), extensions)); - EXPECT_CALL(*gl_, GetIntegerv(GL_ALPHA_BITS, _)) - .WillOnce(SetArgumentPointee<1>(has_alpha_backbuffer ? 8 : 0)) - .RetiresOnSaturation(); EXPECT_CALL(*gl_, EnableVertexAttribArray(0)) .Times(1) .RetiresOnSaturation(); @@ -113,6 +116,16 @@ void GLES2DecoderTestBase::InitDecoder( .Times(1) .RetiresOnSaturation(); + EXPECT_CALL(*gl_, GetIntegerv(GL_ALPHA_BITS, _)) + .WillOnce(SetArgumentPointee<1>(has_alpha ? 8 : 0)) + .RetiresOnSaturation(); + EXPECT_CALL(*gl_, GetIntegerv(GL_DEPTH_BITS, _)) + .WillOnce(SetArgumentPointee<1>(has_depth ? 24 : 0)) + .RetiresOnSaturation(); + EXPECT_CALL(*gl_, GetIntegerv(GL_STENCIL_BITS, _)) + .WillOnce(SetArgumentPointee<1>(has_stencil ? 8 : 0)) + .RetiresOnSaturation(); + EXPECT_CALL(*gl_, Enable(GL_VERTEX_PROGRAM_POINT_SIZE)) .Times(1) .RetiresOnSaturation(); @@ -134,10 +147,22 @@ void GLES2DecoderTestBase::InitDecoder( context_ = new gfx::GLContextStub; + // From <EGL/egl.h>. + const int32 EGL_ALPHA_SIZE = 0x3021; + const int32 EGL_DEPTH_SIZE = 0x3025; + const int32 EGL_STENCIL_SIZE = 0x3026; + + int32 attributes[] = { + EGL_ALPHA_SIZE, request_alpha ? 8 : 0, + EGL_DEPTH_SIZE, request_depth ? 24 : 0, + EGL_STENCIL_SIZE, request_stencil ? 8 : 0, + }; + std::vector<int32> attribs(attributes, attributes + arraysize(attributes)); + decoder_.reset(GLES2Decoder::Create(surface_manager_.get(), group_.get())); decoder_->Initialize( surface_, context_, surface_->GetSize(), DisallowedExtensions(), - NULL, std::vector<int32>(), NULL, 0); + NULL, attribs, NULL, 0); decoder_->set_engine(engine_.get()); EXPECT_CALL(*gl_, GenBuffersARB(_, _)) @@ -263,12 +288,8 @@ void GLES2DecoderTestBase::SetupExpectationsForFramebufferAttachment( GLclampf restore_green, GLclampf restore_blue, GLclampf restore_alpha, - GLuint restore_color_mask, GLuint restore_stencil, - GLuint restore_stencil_front_mask, - GLuint restore_stencil_back_mask, GLclampf restore_depth, - GLboolean restore_depth_mask, bool restore_scissor_test) { InSequence sequence; EXPECT_CALL(*gl_, CheckFramebufferStatusEXT(GL_FRAMEBUFFER)) @@ -308,28 +329,12 @@ void GLES2DecoderTestBase::SetupExpectationsForFramebufferAttachment( restore_red, restore_green, restore_blue, restore_alpha)) .Times(1) .RetiresOnSaturation(); - EXPECT_CALL(*gl_, ColorMask( - ((restore_color_mask & 0x1000) != 0) ? 1 : 0, - ((restore_color_mask & 0x0100) != 0) ? 1 : 0, - ((restore_color_mask & 0x0010) != 0) ? 1 : 0, - ((restore_color_mask & 0x0001) != 0) ? 1 : 0)) - .Times(1) - .RetiresOnSaturation(); EXPECT_CALL(*gl_, ClearStencil(restore_stencil)) .Times(1) .RetiresOnSaturation(); - EXPECT_CALL(*gl_, StencilMaskSeparate(GL_FRONT, restore_stencil_front_mask)) - .Times(1) - .RetiresOnSaturation(); - EXPECT_CALL(*gl_, StencilMaskSeparate(GL_BACK, restore_stencil_back_mask)) - .Times(1) - .RetiresOnSaturation(); EXPECT_CALL(*gl_, ClearDepth(restore_depth)) .Times(1) .RetiresOnSaturation(); - EXPECT_CALL(*gl_, DepthMask(restore_depth_mask)) - .Times(1) - .RetiresOnSaturation(); if (restore_scissor_test) { EXPECT_CALL(*gl_, Enable(GL_SCISSOR_TEST)) .Times(1) @@ -386,6 +391,43 @@ void GLES2DecoderTestBase::DoDeleteBuffer( EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); } +void GLES2DecoderTestBase::SetupExpectationsForApplyingDirtyState( + bool framebuffer_is_rgb, + bool framebuffer_has_depth, + bool framebuffer_has_stencil, + GLuint color_bits, + bool depth_mask, + GLuint front_stencil_mask, + GLuint back_stencil_mask) { + EXPECT_CALL(*gl_, ColorMask( + (color_bits & 0x1000) != 0, + (color_bits & 0x0100) != 0, + (color_bits & 0x0010) != 0, + (color_bits & 0x0001) && !framebuffer_is_rgb)) + .Times(1) + .RetiresOnSaturation(); + EXPECT_CALL(*gl_, DepthMask(depth_mask)) + .Times(1) + .RetiresOnSaturation(); + EXPECT_CALL(*gl_, StencilMaskSeparate(GL_FRONT, front_stencil_mask)) + .Times(1) + .RetiresOnSaturation(); + EXPECT_CALL(*gl_, StencilMaskSeparate(GL_BACK, back_stencil_mask)) + .Times(1) + .RetiresOnSaturation(); +} + +void GLES2DecoderTestBase::SetupExpectationsForApplyingDefaultDirtyState() { + SetupExpectationsForApplyingDirtyState( + false, // Framebuffer is RGB + false, // Framebuffer has depth + false, // Framebuffer has stencil + 0x1111, // color bits + true, // depth mask + 0, // front stencil mask + 0); // back stencil mask +} + void GLES2DecoderTestBase::DoBindFramebuffer( GLenum target, GLuint client_id, GLuint service_id) { EXPECT_CALL(*gl_, BindFramebufferEXT(target, service_id)) @@ -535,7 +577,10 @@ const int GLES2DecoderTestBase::kBackBufferHeight; void GLES2DecoderWithShaderTestBase::SetUp() { GLES2DecoderTestBase::SetUp(); + SetupDefaultProgram(); +} +void GLES2DecoderWithShaderTestBase::SetupDefaultProgram() { { static AttribInfo attribs[] = { { kAttrib1Name, kAttrib1Size, kAttrib1Type, kAttrib1Location, }, diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h index d939e4f8..2676f9f 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h +++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h @@ -162,7 +162,14 @@ class GLES2DecoderTestBase : public testing::Test { void SetBucketAsCString(uint32 bucket_id, const char* str); - void InitDecoder(const char* extensions, bool has_alpha_backbuffer); + void InitDecoder( + const char* extensions, + bool has_alpha, + bool has_depth, + bool has_stencil, + bool request_alpha, + bool request_depth, + bool request_stencil); const ContextGroup& group() const { return *group_.get(); @@ -232,14 +239,21 @@ class GLES2DecoderTestBase : public testing::Test { GLclampf restore_green, GLclampf restore_blue, GLclampf restore_alpha, - GLuint restore_color_mask, GLuint restore_stencil, - GLuint restore_stencil_front_mask, - GLuint restore_stencil_back_mask, GLclampf restore_depth, - GLboolean restore_depth_mask, bool restore_scissor_test); + void SetupExpectationsForApplyingDirtyState( + bool framebuffer_is_rgb, + bool framebuffer_has_depth, + bool framebuffer_has_stencil, + GLuint color_bits, // NOTE! bits are 0x1000, 0x0100, 0x0010, and 0x0001 + bool depth_mask, + GLuint front_stencil_mask, + GLuint back_stencil_mask); + + void SetupExpectationsForApplyingDefaultDirtyState(); + GLvoid* BufferOffset(unsigned i) { return static_cast<int8 *>(NULL)+(i); } @@ -382,6 +396,7 @@ class GLES2DecoderWithShaderTestBase : public GLES2DecoderTestBase { virtual void SetUp(); virtual void TearDown(); + void SetupDefaultProgram(); void SetupTexture(); void DoEnableVertexAttribArray(GLint index); diff --git a/gpu/command_buffer/service/texture_manager.h b/gpu/command_buffer/service/texture_manager.h index 6b7ff12..2fc1cb9 100644 --- a/gpu/command_buffer/service/texture_manager.h +++ b/gpu/command_buffer/service/texture_manager.h @@ -42,6 +42,7 @@ class TextureManager { cube_complete_(false), npot_(false), has_been_bound_(false), + framebuffer_attachment_count_(0), owned_(true) { } @@ -131,6 +132,19 @@ class TextureManager { owned_ = false; } + bool IsAttachedToFramebuffer() const { + return framebuffer_attachment_count_ != 0; + } + + void AttachToFramebuffer() { + ++framebuffer_attachment_count_; + } + + void DetachFromFramebuffer() { + DCHECK(framebuffer_attachment_count_ > 0); + --framebuffer_attachment_count_; + } + private: friend class TextureManager; friend class base::RefCounted<TextureInfo>; @@ -240,6 +254,9 @@ class TextureManager { // Whether this texture has ever been bound. bool has_been_bound_; + // The number of framebuffers this texture is attached to. + int framebuffer_attachment_count_; + // Whether the associated context group owns this texture and should delete // it. bool owned_; |