diff options
author | gman@chromium.org <gman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-08-06 01:12:28 +0000 |
---|---|---|
committer | gman@chromium.org <gman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-08-06 01:12:28 +0000 |
commit | 3a2e7c7b5a3cfabaab0043020f2a35cde53fb0d7 (patch) | |
tree | 72416741e7d081122bf1f85954b689bd43eb84b9 /gpu | |
parent | c87bcf000fde1dd7194b5e40e8c9f1058700dd9d (diff) | |
download | chromium_src-3a2e7c7b5a3cfabaab0043020f2a35cde53fb0d7.zip chromium_src-3a2e7c7b5a3cfabaab0043020f2a35cde53fb0d7.tar.gz chromium_src-3a2e7c7b5a3cfabaab0043020f2a35cde53fb0d7.tar.bz2 |
Clear render buffers
TEST=unit tests
BUG=41300
Review URL: http://codereview.chromium.org/3058043
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@55169 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'gpu')
10 files changed, 629 insertions, 17 deletions
diff --git a/gpu/command_buffer/build_gles2_cmd_buffer.py b/gpu/command_buffer/build_gles2_cmd_buffer.py index ef65df7..f747f7a 100755 --- a/gpu/command_buffer/build_gles2_cmd_buffer.py +++ b/gpu/command_buffer/build_gles2_cmd_buffer.py @@ -1038,7 +1038,13 @@ _FUNCTION_INFO = { 'gl_test_func': 'glCheckFramebufferStatusEXT', 'result': ['GLenum'], }, - 'ClearDepthf': {'decoder_func': 'glClearDepth'}, + 'ClearColor': {'decoder_func': 'DoClearColor'}, + 'ClearDepthf': { + 'decoder_func': 'DoClearDepthf', + 'gl_test_func': 'glClearDepth', + }, + 'ColorMask': {'decoder_func': 'DoColorMask'}, + 'ClearStencil': {'decoder_func': 'DoClearStencil'}, 'CommandBufferEnable': { 'type': 'Custom', 'immediate': False, @@ -1091,7 +1097,11 @@ _FUNCTION_INFO = { }, 'DeleteTextures': {'type': 'DELn'}, 'DepthRangef': {'decoder_func': 'glDepthRange'}, + 'DepthMask': {'decoder_func': 'DoDepthMask'}, 'DetachShader': {'decoder_func': 'DoDetachShader'}, + 'Disable': { + 'decoder_func': 'DoDisable', + }, 'DisableVertexAttribArray': { 'decoder_func': 'DoDisableVertexAttribArray', 'impl_decl': False, @@ -1105,6 +1115,9 @@ _FUNCTION_INFO = { 'type': 'Manual', 'cmd_args': 'GLenum mode, GLsizei count, GLenum type, GLuint index_offset', }, + 'Enable': { + 'decoder_func': 'DoEnable', + }, 'EnableVertexAttribArray': { 'decoder_func': 'DoEnableVertexAttribArray', 'impl_decl': False, @@ -1376,6 +1389,8 @@ _FUNCTION_INFO = { 'cmd_args': 'GLuint shader, const char* data', }, + 'StencilMask': {'decoder_func': 'DoStencilMask'}, + 'StencilMaskSeparate': {'decoder_func': 'DoStencilMaskSeparate'}, 'SwapBuffers': { 'type': 'Custom', 'impl_func': False, diff --git a/gpu/command_buffer/service/framebuffer_manager.cc b/gpu/command_buffer/service/framebuffer_manager.cc index 8dd036b..9b74f7f 100644 --- a/gpu/command_buffer/service/framebuffer_manager.cc +++ b/gpu/command_buffer/service/framebuffer_manager.cc @@ -37,6 +37,25 @@ void FramebufferManager::CreateFramebufferInfo( DCHECK(result.second); } +bool FramebufferManager::FramebufferInfo::HasUnclearedAttachment( + GLenum attachment) const { + AttachmentToRenderbufferMap::const_iterator it = + renderbuffers_.find(attachment); + if (it != renderbuffers_.end()) { + RenderbufferManager::RenderbufferInfo* info = it->second; + return !info->cleared(); + } + return false; +} + +void FramebufferManager::FramebufferInfo::MarkAttachedRenderbuffersAsCleared() { + for (AttachmentToRenderbufferMap::iterator it = renderbuffers_.begin(); + it != renderbuffers_.end(); ++it) { + RenderbufferManager::RenderbufferInfo* info = it->second; + info->set_cleared(); + } +} + FramebufferManager::FramebufferInfo* FramebufferManager::GetFramebufferInfo( GLuint client_id) { FramebufferInfoMap::iterator it = framebuffer_infos_.find(client_id); @@ -55,7 +74,8 @@ void FramebufferManager::FramebufferInfo::AttachRenderbuffer( GLenum attachment, RenderbufferManager::RenderbufferInfo* renderbuffer) { DCHECK(attachment == GL_COLOR_ATTACHMENT0 || attachment == GL_DEPTH_ATTACHMENT || - attachment == GL_STENCIL_ATTACHMENT); + attachment == GL_STENCIL_ATTACHMENT || + attachment == GL_DEPTH_STENCIL_ATTACHMENT); if (renderbuffer) { renderbuffers_[attachment] = RenderbufferManager::RenderbufferInfo::Ref(renderbuffer); diff --git a/gpu/command_buffer/service/framebuffer_manager.h b/gpu/command_buffer/service/framebuffer_manager.h index f437e6a..8e0ce40 100644 --- a/gpu/command_buffer/service/framebuffer_manager.h +++ b/gpu/command_buffer/service/framebuffer_manager.h @@ -33,11 +33,15 @@ class FramebufferManager { return service_id_; } + bool HasUnclearedAttachment(GLenum attachment) const; + // Attaches a renderbuffer to a particlar attachment. // Pass null to detach. void AttachRenderbuffer( GLenum attachment, RenderbufferManager::RenderbufferInfo* renderbuffer); + void MarkAttachedRenderbuffersAsCleared(); + bool IsDeleted() { return service_id_ == 0; } diff --git a/gpu/command_buffer/service/framebuffer_manager_unittest.cc b/gpu/command_buffer/service/framebuffer_manager_unittest.cc index ed435c1..57fed7b 100644 --- a/gpu/command_buffer/service/framebuffer_manager_unittest.cc +++ b/gpu/command_buffer/service/framebuffer_manager_unittest.cc @@ -75,7 +75,109 @@ TEST_F(FramebufferManagerTest, Destroy) { ASSERT_TRUE(info1 == NULL); } -// TODO(gman): Write test for AttachRenderbuffer +class FramebufferInfoTest : public testing::Test { + public: + static const GLuint kClient1Id = 1; + static const GLuint kService1Id = 11; + + FramebufferInfoTest() + : manager_() { + } + ~FramebufferInfoTest() { + manager_.Destroy(false); + } + + protected: + virtual void SetUp() { + gl_.reset(new ::testing::StrictMock< ::gfx::MockGLInterface>()); + ::gfx::GLInterface::SetGLInterface(gl_.get()); + manager_.CreateFramebufferInfo(kClient1Id, kService1Id); + info_ = manager_.GetFramebufferInfo(kClient1Id); + ASSERT_TRUE(info_ != NULL); + } + + virtual void TearDown() { + ::gfx::GLInterface::SetGLInterface(NULL); + gl_.reset(); + } + + // Use StrictMock to make 100% sure we know how GL will be called. + scoped_ptr< ::testing::StrictMock< ::gfx::MockGLInterface> > gl_; + FramebufferManager manager_; + FramebufferManager::FramebufferInfo* info_; +}; + +// GCC requires these declarations, but MSVC requires they not be present +#ifndef COMPILER_MSVC +const GLuint FramebufferInfoTest::kClient1Id; +const GLuint FramebufferInfoTest::kService1Id; +#endif + +TEST_F(FramebufferInfoTest, Basic) { + EXPECT_EQ(kService1Id, info_->service_id()); + EXPECT_FALSE(info_->IsDeleted()); +} + +TEST_F(FramebufferInfoTest, AttachRenderbuffer) { + const GLuint kRenderbufferClient1Id = 33; + const GLuint kRenderbufferService1Id = 333; + const GLuint kRenderbufferClient2Id = 34; + const GLuint kRenderbufferService2Id = 334; + EXPECT_FALSE(info_->HasUnclearedAttachment(GL_COLOR_ATTACHMENT0)); + EXPECT_FALSE(info_->HasUnclearedAttachment(GL_DEPTH_ATTACHMENT)); + EXPECT_FALSE(info_->HasUnclearedAttachment(GL_STENCIL_ATTACHMENT)); + EXPECT_FALSE(info_->HasUnclearedAttachment(GL_DEPTH_STENCIL_ATTACHMENT)); + + RenderbufferManager rb_manager; + rb_manager.CreateRenderbufferInfo( + kRenderbufferClient1Id, kRenderbufferService1Id); + RenderbufferManager::RenderbufferInfo* rb_info1 = + rb_manager.GetRenderbufferInfo(kRenderbufferClient1Id); + ASSERT_TRUE(rb_info1 != NULL); + + // check adding one attachment + info_->AttachRenderbuffer(GL_COLOR_ATTACHMENT0, rb_info1); + EXPECT_TRUE(info_->HasUnclearedAttachment(GL_COLOR_ATTACHMENT0)); + EXPECT_FALSE(info_->HasUnclearedAttachment(GL_DEPTH_ATTACHMENT)); + + // check adding another + info_->AttachRenderbuffer(GL_DEPTH_ATTACHMENT, rb_info1); + EXPECT_TRUE(info_->HasUnclearedAttachment(GL_COLOR_ATTACHMENT0)); + EXPECT_TRUE(info_->HasUnclearedAttachment(GL_DEPTH_ATTACHMENT)); + + // check marking them as cleared. + info_->MarkAttachedRenderbuffersAsCleared(); + EXPECT_FALSE(info_->HasUnclearedAttachment(GL_COLOR_ATTACHMENT0)); + EXPECT_FALSE(info_->HasUnclearedAttachment(GL_DEPTH_ATTACHMENT)); + + // Check adding one that is already cleared. + info_->AttachRenderbuffer(GL_STENCIL_ATTACHMENT, rb_info1); + EXPECT_FALSE(info_->HasUnclearedAttachment(GL_STENCIL_ATTACHMENT)); + + // Check marking the renderbuffer as unclared. + rb_info1->set_internal_format(GL_RGBA); + EXPECT_TRUE(info_->HasUnclearedAttachment(GL_STENCIL_ATTACHMENT)); + + // Clear it. + info_->MarkAttachedRenderbuffersAsCleared(); + EXPECT_FALSE(info_->HasUnclearedAttachment(GL_STENCIL_ATTACHMENT)); + + // Check replacing an attachment + rb_manager.CreateRenderbufferInfo( + kRenderbufferClient2Id, kRenderbufferService2Id); + RenderbufferManager::RenderbufferInfo* rb_info2 = + rb_manager.GetRenderbufferInfo(kRenderbufferClient2Id); + ASSERT_TRUE(rb_info2 != NULL); + + info_->AttachRenderbuffer(GL_STENCIL_ATTACHMENT, rb_info2); + EXPECT_TRUE(info_->HasUnclearedAttachment(GL_STENCIL_ATTACHMENT)); + + // Check removing it. + info_->AttachRenderbuffer(GL_STENCIL_ATTACHMENT, NULL); + EXPECT_FALSE(info_->HasUnclearedAttachment(GL_STENCIL_ATTACHMENT)); + + rb_manager.Destroy(false); +} } // namespace gles2 } // namespace gpu diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc index bef335d..1a00ed7 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc @@ -831,6 +831,12 @@ class GLES2DecoderImpl : public base::SupportsWeakPtr<GLES2DecoderImpl>, error::Error ShaderSourceHelper( GLuint client_id, const char* data, uint32 data_size); + // Clears any uncleared render buffers attached to the given frame buffer. + void ClearUnclearedRenderbuffers(FramebufferManager::FramebufferInfo* info); + + // Remembers the state of some capabilities. + void SetCapabilityState(GLenum cap, bool enabled); + // Checks if the current program exists and is valid. If not generates the // appropriate GL error. Returns true if the current program is in a usable // state. @@ -886,6 +892,17 @@ class GLES2DecoderImpl : public base::SupportsWeakPtr<GLES2DecoderImpl>, // Wrapper for glCheckFramebufferStatus GLenum DoCheckFramebufferStatus(GLenum target); + // 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); + // Wrapper for glCompileShader. void DoCompileShader(GLuint shader); @@ -898,9 +915,15 @@ class GLES2DecoderImpl : public base::SupportsWeakPtr<GLES2DecoderImpl>, // Wrapper for glDrawArrays. void DoDrawArrays(GLenum mode, GLint first, GLsizei count); + // Wrapper for glDisable + void DoDisable(GLenum cap); + // Wrapper for glDisableVertexAttribArray. void DoDisableVertexAttribArray(GLuint index); + // Wrapper for glEnable + void DoEnable(GLenum cap); + // Wrapper for glEnableVertexAttribArray. void DoEnableVertexAttribArray(GLuint index); @@ -1160,6 +1183,23 @@ class GLES2DecoderImpl : public base::SupportsWeakPtr<GLES2DecoderImpl>, GLuint black_2d_texture_id_; GLuint black_cube_texture_id_; + // state saved for clearing so we can clear render buffers and then + // restore to these values. + GLclampf clear_red_; + GLclampf clear_green_; + GLclampf clear_blue_; + GLclampf clear_alpha_; + GLboolean mask_red_; + GLboolean mask_green_; + GLboolean mask_blue_; + GLboolean mask_alpha_; + GLint clear_stencil_; + GLuint mask_stencil_front_; + GLuint mask_stencil_back_; + GLclampf clear_depth_; + GLboolean mask_depth_; + bool enable_scissor_test_; + // The program in use by glUseProgram ProgramManager::ProgramInfo::Ref current_program_; @@ -1457,6 +1497,20 @@ GLES2DecoderImpl::GLES2DecoderImpl(ContextGroup* group) active_texture_unit_(0), black_2d_texture_id_(0), black_cube_texture_id_(0), + clear_red_(0), + clear_green_(0), + clear_blue_(0), + clear_alpha_(0), + mask_red_(true), + mask_green_(true), + mask_blue_(true), + mask_alpha_(true), + clear_stencil_(0), + mask_stencil_front_(-1), + mask_stencil_back_(-1), + clear_depth_(1.0f), + mask_depth_(true), + enable_scissor_test_(false), anti_aliased_(false), use_shader_translator_(true), vertex_compiler_(NULL), @@ -2741,9 +2795,9 @@ void GLES2DecoderImpl::DoFramebufferRenderbuffer( return; } GLuint service_id = 0; + RenderbufferManager::RenderbufferInfo* info = NULL; if (client_renderbuffer_id) { - RenderbufferManager::RenderbufferInfo* info = - GetRenderbufferInfo(client_renderbuffer_id); + info = GetRenderbufferInfo(client_renderbuffer_id); if (!info) { SetGLError(GL_INVALID_OPERATION, "glFramebufferRenderbuffer: unknown renderbuffer"); @@ -2753,6 +2807,125 @@ void GLES2DecoderImpl::DoFramebufferRenderbuffer( } glFramebufferRenderbufferEXT( target, attachment, renderbuffertarget, service_id); + if (service_id == 0 || + glCheckFramebufferStatusEXT(target) == GL_FRAMEBUFFER_COMPLETE) { + bound_framebuffer_->AttachRenderbuffer(attachment, info); + if (info) { + ClearUnclearedRenderbuffers(bound_framebuffer_); + } + } +} + +void GLES2DecoderImpl::SetCapabilityState(GLenum cap, bool enabled) { + switch (cap) { + case GL_SCISSOR_TEST: + enable_scissor_test_ = enabled; + break; + default: + break; + } +} + +void GLES2DecoderImpl::DoDisable(GLenum cap) { + SetCapabilityState(cap, false); + glDisable(cap); +} + +void GLES2DecoderImpl::DoEnable(GLenum cap) { + SetCapabilityState(cap, true); + glEnable(cap); +} + +void GLES2DecoderImpl::DoClearColor( + GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) { + clear_red_ = red; + clear_green_ = green; + clear_blue_ = blue; + clear_alpha_ = alpha; + glClearColor(red, green, blue, alpha); +} + +void GLES2DecoderImpl::DoClearDepthf(GLclampf depth) { + clear_depth_ = depth; + glClearDepth(depth); +} + +void GLES2DecoderImpl::DoClearStencil(GLint s) { + clear_stencil_ = s; + glClearStencil(s); +} + +void GLES2DecoderImpl::DoColorMask( + GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) { + mask_red_ = red; + mask_green_ = green; + mask_blue_ = blue; + mask_alpha_ = alpha; + glColorMask(red, green, blue, alpha); +} + +void GLES2DecoderImpl::DoDepthMask(GLboolean depth) { + mask_depth_ = depth; + glDepthMask(depth); +} + +void GLES2DecoderImpl::DoStencilMask(GLuint mask) { + mask_stencil_front_ = mask; + mask_stencil_back_ = mask; + glStencilMask(mask); +} + +void GLES2DecoderImpl::DoStencilMaskSeparate(GLenum face, GLuint mask) { + if (face == GL_FRONT) { + mask_stencil_front_ = mask; + } else { + mask_stencil_back_ = mask; + } + glStencilMaskSeparate(face, mask); +} + +// NOTE: There's an assumption here that Texture attachments +// are cleared because they are textures so we only need to clear +// the renderbuffers. +void GLES2DecoderImpl::ClearUnclearedRenderbuffers( + FramebufferManager::FramebufferInfo* info) { + GLbitfield clear_bits = 0; + if (info->HasUnclearedAttachment(GL_COLOR_ATTACHMENT0)) { + glClearColor(0, 0, 0, 0); + glColorMask(true, true, true, true); + clear_bits |= GL_COLOR_BUFFER_BIT; + } + + if (info->HasUnclearedAttachment(GL_STENCIL_ATTACHMENT) || + info->HasUnclearedAttachment(GL_DEPTH_STENCIL_ATTACHMENT)) { + glClearStencil(0); + glStencilMask(-1); + clear_bits |= GL_STENCIL_BUFFER_BIT; + } + + if (info->HasUnclearedAttachment(GL_DEPTH_ATTACHMENT) || + info->HasUnclearedAttachment(GL_DEPTH_STENCIL_ATTACHMENT)) { + glClearDepth(1.0f); + glDepthMask(true); + clear_bits |= GL_DEPTH_BUFFER_BIT; + } + + glDisable(GL_SCISSOR_TEST); + glClear(clear_bits); + + info->MarkAttachedRenderbuffersAsCleared(); + + // reset clear color + 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); + } } GLenum GLES2DecoderImpl::DoCheckFramebufferStatus(GLenum target) { @@ -2771,8 +2944,9 @@ void GLES2DecoderImpl::DoFramebufferTexture2D( return; } GLuint service_id = 0; + TextureManager::TextureInfo* info = NULL; if (client_texture_id) { - TextureManager::TextureInfo* info = GetTextureInfo(client_texture_id); + info = GetTextureInfo(client_texture_id); if (!info) { SetGLError(GL_INVALID_OPERATION, "glFramebufferTexture2D: unknown texture"); @@ -2781,6 +2955,10 @@ void GLES2DecoderImpl::DoFramebufferTexture2D( service_id = info->service_id(); } glFramebufferTexture2DEXT(target, attachment, textarget, service_id, level); + if (service_id != 0 && + glCheckFramebufferStatusEXT(target) == GL_FRAMEBUFFER_COMPLETE) { + ClearUnclearedRenderbuffers(bound_framebuffer_); + } } void GLES2DecoderImpl::DoGetFramebufferAttachmentParameteriv( diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h b/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h index 874bd8a..0ae6355 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h +++ b/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h @@ -231,21 +231,21 @@ 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); - glClearColor(red, green, blue, alpha); + DoClearColor(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); - glClearDepth(depth); + DoClearDepthf(depth); return error::kNoError; } error::Error GLES2DecoderImpl::HandleClearStencil( uint32 immediate_data_size, const gles2::ClearStencil& c) { GLint s = static_cast<GLint>(c.s); - glClearStencil(s); + DoClearStencil(s); return error::kNoError; } @@ -255,7 +255,7 @@ 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); - glColorMask(red, green, blue, alpha); + DoColorMask(red, green, blue, alpha); return error::kNoError; } @@ -613,7 +613,7 @@ error::Error GLES2DecoderImpl::HandleDepthFunc( error::Error GLES2DecoderImpl::HandleDepthMask( uint32 immediate_data_size, const gles2::DepthMask& c) { GLboolean flag = static_cast<GLboolean>(c.flag); - glDepthMask(flag); + DoDepthMask(flag); return error::kNoError; } @@ -640,7 +640,7 @@ error::Error GLES2DecoderImpl::HandleDisable( SetGLError(GL_INVALID_ENUM, "glDisable: cap GL_INVALID_ENUM"); return error::kNoError; } - glDisable(cap); + DoDisable(cap); return error::kNoError; } @@ -675,7 +675,7 @@ error::Error GLES2DecoderImpl::HandleEnable( SetGLError(GL_INVALID_ENUM, "glEnable: cap GL_INVALID_ENUM"); return error::kNoError; } - glEnable(cap); + DoEnable(cap); return error::kNoError; } @@ -1609,7 +1609,7 @@ error::Error GLES2DecoderImpl::HandleStencilFuncSeparate( error::Error GLES2DecoderImpl::HandleStencilMask( uint32 immediate_data_size, const gles2::StencilMask& c) { GLuint mask = static_cast<GLuint>(c.mask); - glStencilMask(mask); + DoStencilMask(mask); return error::kNoError; } @@ -1621,7 +1621,7 @@ error::Error GLES2DecoderImpl::HandleStencilMaskSeparate( SetGLError(GL_INVALID_ENUM, "glStencilMaskSeparate: face GL_INVALID_ENUM"); return error::kNoError; } - glStencilMaskSeparate(face, mask); + DoStencilMaskSeparate(face, mask); return error::kNoError; } diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc index 2bb4612..4a37678 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc @@ -2285,6 +2285,281 @@ TEST_F(GLES2DecoderTest, CopyTexSubImage2DBadArgs) { EXPECT_EQ(GL_INVALID_VALUE, GetGLError()); } +// Check that if a renderbuffer is attached and GL returns +// GL_FRAMEBUFFER_COMPLETE that the buffer is cleared and state is restored. +TEST_F(GLES2DecoderTest, FramebufferRenderbufferClearColor) { + DoBindFramebuffer(GL_FRAMEBUFFER, client_framebuffer_id_, + kServiceFramebufferId); + ClearColor color_cmd; + ColorMask color_mask_cmd; + Enable enable_cmd; + FramebufferRenderbuffer cmd; + color_cmd.Init(0.1f, 0.2f, 0.3f, 0.4f); + color_mask_cmd.Init(0, 1, 0, 1); + enable_cmd.Init(GL_SCISSOR_TEST); + cmd.Init( + GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, + client_renderbuffer_id_); + InSequence sequence; + 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_, Enable(GL_SCISSOR_TEST)) + .Times(1) + .RetiresOnSaturation(); + EXPECT_CALL(*gl_, FramebufferRenderbufferEXT( + GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, + kServiceRenderbufferId)) + .Times(1) + .RetiresOnSaturation(); + EXPECT_CALL(*gl_, CheckFramebufferStatusEXT(GL_FRAMEBUFFER)) + .WillOnce(Return(GL_FRAMEBUFFER_COMPLETE)) + .RetiresOnSaturation(); + EXPECT_CALL(*gl_, ClearColor(0, 0, 0, 0)) + .Times(1) + .RetiresOnSaturation(); + EXPECT_CALL(*gl_, ColorMask(1, 1, 1, 1)) + .Times(1) + .RetiresOnSaturation(); + EXPECT_CALL(*gl_, Disable(GL_SCISSOR_TEST)) + .Times(1) + .RetiresOnSaturation(); + EXPECT_CALL(*gl_, Clear(GL_COLOR_BUFFER_BIT)) + .Times(1) + .RetiresOnSaturation(); + 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_, ClearStencil(0)) + .Times(1) + .RetiresOnSaturation(); + EXPECT_CALL(*gl_, StencilMaskSeparate(GL_FRONT, static_cast<GLuint>(-1))) + .Times(1) + .RetiresOnSaturation(); + EXPECT_CALL(*gl_, StencilMaskSeparate(GL_BACK, static_cast<GLuint>(-1))) + .Times(1) + .RetiresOnSaturation(); + EXPECT_CALL(*gl_, ClearDepth(1.0f)) + .Times(1) + .RetiresOnSaturation(); + EXPECT_CALL(*gl_, DepthMask(1)) + .Times(1) + .RetiresOnSaturation(); + EXPECT_CALL(*gl_, Enable(GL_SCISSOR_TEST)) + .Times(1) + .RetiresOnSaturation(); + EXPECT_EQ(error::kNoError, ExecuteCmd(color_cmd)); + EXPECT_EQ(error::kNoError, ExecuteCmd(color_mask_cmd)); + EXPECT_EQ(error::kNoError, ExecuteCmd(enable_cmd)); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); +} + +TEST_F(GLES2DecoderTest, FramebufferRenderbufferClearDepth) { + DoBindFramebuffer(GL_FRAMEBUFFER, client_framebuffer_id_, + kServiceFramebufferId); + ClearDepthf depth_cmd; + DepthMask depth_mask_cmd; + FramebufferRenderbuffer cmd; + depth_cmd.Init(0.5f); + depth_mask_cmd.Init(false); + cmd.Init( + GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, + client_renderbuffer_id_); + InSequence sequence; + EXPECT_CALL(*gl_, ClearDepth(0.5f)) + .Times(1) + .RetiresOnSaturation(); + EXPECT_CALL(*gl_, DepthMask(0)) + .Times(1) + .RetiresOnSaturation(); + EXPECT_CALL(*gl_, FramebufferRenderbufferEXT( + GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, + kServiceRenderbufferId)) + .Times(1) + .RetiresOnSaturation(); + EXPECT_CALL(*gl_, CheckFramebufferStatusEXT(GL_FRAMEBUFFER)) + .WillOnce(Return(GL_FRAMEBUFFER_COMPLETE)) + .RetiresOnSaturation(); + EXPECT_CALL(*gl_, ClearDepth(1.0f)) + .Times(1) + .RetiresOnSaturation(); + EXPECT_CALL(*gl_, DepthMask(1)) + .Times(1) + .RetiresOnSaturation(); + EXPECT_CALL(*gl_, Disable(GL_SCISSOR_TEST)) + .Times(1) + .RetiresOnSaturation(); + EXPECT_CALL(*gl_, Clear(GL_DEPTH_BUFFER_BIT)) + .Times(1) + .RetiresOnSaturation(); + EXPECT_CALL(*gl_, ClearColor(0, 0, 0, 0)) + .Times(1) + .RetiresOnSaturation(); + EXPECT_CALL(*gl_, ColorMask(1, 1, 1, 1)) + .Times(1) + .RetiresOnSaturation(); + EXPECT_CALL(*gl_, ClearStencil(0)) + .Times(1) + .RetiresOnSaturation(); + EXPECT_CALL(*gl_, StencilMaskSeparate(GL_FRONT, static_cast<GLuint>(-1))) + .Times(1) + .RetiresOnSaturation(); + EXPECT_CALL(*gl_, StencilMaskSeparate(GL_BACK, static_cast<GLuint>(-1))) + .Times(1) + .RetiresOnSaturation(); + EXPECT_CALL(*gl_, ClearDepth(0.5f)) + .Times(1) + .RetiresOnSaturation(); + EXPECT_CALL(*gl_, DepthMask(0)) + .Times(1) + .RetiresOnSaturation(); + EXPECT_EQ(error::kNoError, ExecuteCmd(depth_cmd)); + EXPECT_EQ(error::kNoError, ExecuteCmd(depth_mask_cmd)); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); +} + +TEST_F(GLES2DecoderTest, FramebufferRenderbufferClearStencil) { + DoBindFramebuffer(GL_FRAMEBUFFER, client_framebuffer_id_, + kServiceFramebufferId); + ClearStencil stencil_cmd; + StencilMaskSeparate stencil_mask_separate_cmd; + FramebufferRenderbuffer cmd; + stencil_cmd.Init(123); + stencil_mask_separate_cmd.Init(GL_BACK, 0x1234u); + cmd.Init( + GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, + client_renderbuffer_id_); + InSequence sequence; + EXPECT_CALL(*gl_, ClearStencil(123)) + .Times(1) + .RetiresOnSaturation(); + EXPECT_CALL(*gl_, StencilMaskSeparate(GL_BACK, 0x1234u)) + .Times(1) + .RetiresOnSaturation(); + EXPECT_CALL(*gl_, FramebufferRenderbufferEXT( + GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, + kServiceRenderbufferId)) + .Times(1) + .RetiresOnSaturation(); + EXPECT_CALL(*gl_, CheckFramebufferStatusEXT(GL_FRAMEBUFFER)) + .WillOnce(Return(GL_FRAMEBUFFER_COMPLETE)) + .RetiresOnSaturation(); + EXPECT_CALL(*gl_, ClearStencil(0)) + .Times(1) + .RetiresOnSaturation(); + EXPECT_CALL(*gl_, StencilMask(static_cast<GLuint>(-1))) + .Times(1) + .RetiresOnSaturation(); + EXPECT_CALL(*gl_, Disable(GL_SCISSOR_TEST)) + .Times(1) + .RetiresOnSaturation(); + EXPECT_CALL(*gl_, Clear(GL_STENCIL_BUFFER_BIT)) + .Times(1) + .RetiresOnSaturation(); + EXPECT_CALL(*gl_, ClearColor(0, 0, 0, 0)) + .Times(1) + .RetiresOnSaturation(); + EXPECT_CALL(*gl_, ColorMask(1, 1, 1, 1)) + .Times(1) + .RetiresOnSaturation(); + EXPECT_CALL(*gl_, ClearStencil(123)) + .Times(1) + .RetiresOnSaturation(); + EXPECT_CALL(*gl_, StencilMaskSeparate(GL_FRONT, static_cast<GLuint>(-1))) + .Times(1) + .RetiresOnSaturation(); + EXPECT_CALL(*gl_, StencilMaskSeparate(GL_BACK, 0x1234u)) + .Times(1) + .RetiresOnSaturation(); + EXPECT_CALL(*gl_, ClearDepth(1.0f)) + .Times(1) + .RetiresOnSaturation(); + EXPECT_CALL(*gl_, DepthMask(1)) + .Times(1) + .RetiresOnSaturation(); + EXPECT_EQ(error::kNoError, ExecuteCmd(stencil_cmd)); + EXPECT_EQ(error::kNoError, ExecuteCmd(stencil_mask_separate_cmd)); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); +} + +#if 0 // Turn this test on once we allow GL_DEPTH_STENCIL_ATTACHMENT +TEST_F(GLES2DecoderTest, FramebufferRenderbufferClearDepthStencil) { + DoBindFramebuffer(GL_FRAMEBUFFER, client_framebuffer_id_, + kServiceFramebufferId); + ClearDepthf depth_cmd; + ClearStencil stencil_cmd; + FramebufferRenderbuffer cmd; + depth_cmd.Init(0.5f); + stencil_cmd.Init(123); + cmd.Init( + GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, + client_renderbuffer_id_); + InSequence sequence; + EXPECT_CALL(*gl_, ClearDepth(0.5f)) + .Times(1) + .RetiresOnSaturation(); + EXPECT_CALL(*gl_, ClearStencil(123)) + .Times(1) + .RetiresOnSaturation(); + EXPECT_CALL(*gl_, FramebufferRenderbufferEXT( + GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, + kServiceRenderbufferId)) + .Times(1) + .RetiresOnSaturation(); + EXPECT_CALL(*gl_, CheckFramebufferStatusEXT(GL_FRAMEBUFFER)) + .WillOnce(Return(GL_FRAMEBUFFER_COMPLETE)) + .RetiresOnSaturation(); + EXPECT_CALL(*gl_, ClearStencil(0)) + .Times(1) + .RetiresOnSaturation(); + EXPECT_CALL(*gl_, StencilMask(static_cast<GLuint>(-1))) + .Times(1) + .RetiresOnSaturation(); + EXPECT_CALL(*gl_, ClearDepth(1.0f)) + .Times(1) + .RetiresOnSaturation(); + EXPECT_CALL(*gl_, DepthMask(1)) + .Times(1) + .RetiresOnSaturation(); + EXPECT_CALL(*gl_, Disable(GL_SCISSOR_TEST)) + .Times(1) + .RetiresOnSaturation(); + EXPECT_CALL(*gl_, Clear(GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)) + .Times(1) + .RetiresOnSaturation(); + EXPECT_CALL(*gl_, ClearColor(0, 0, 0, 0)) + .Times(1) + .RetiresOnSaturation(); + EXPECT_CALL(*gl_, ColorMask(1, 1, 1, 1)) + .Times(1) + .RetiresOnSaturation(); + EXPECT_CALL(*gl_, ClearStencil(123)) + .Times(1) + .RetiresOnSaturation(); + EXPECT_CALL(*gl_, StencilMaskSeparate(GL_FRONT, static_cast<GLuint>(-1))) + .Times(1) + .RetiresOnSaturation(); + EXPECT_CALL(*gl_, StencilMaskSeparate(GL_BACK, static_cast<GLuint>(-1))) + .Times(1) + .RetiresOnSaturation(); + EXPECT_CALL(*gl_, ClearDepth(0.5f)) + .Times(1) + .RetiresOnSaturation(); + EXPECT_CALL(*gl_, DepthMask(1)) + .Times(1) + .RetiresOnSaturation(); + EXPECT_EQ(error::kNoError, ExecuteCmd(depth_cmd)); + EXPECT_EQ(error::kNoError, ExecuteCmd(stencil_cmd)); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); +} +#endif + // TODO(gman): BufferData // TODO(gman): BufferDataImmediate 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 45f47bb..9e8e5ae 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_1.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_1.cc @@ -72,16 +72,30 @@ void GLES2DecoderTestBase::SpecializedSetup<CopyTexSubImage2D, 0>( template <> void GLES2DecoderTestBase::SpecializedSetup<FramebufferRenderbuffer, 0>( - bool /* valid */) { + bool valid) { DoBindFramebuffer(GL_FRAMEBUFFER, client_framebuffer_id_, kServiceFramebufferId); + if (valid) { + // Return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT so the code + // doesn't try to clear the buffer. That is tested else where. + EXPECT_CALL(*gl_, CheckFramebufferStatusEXT(GL_FRAMEBUFFER)) + .WillOnce(Return(GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT)) + .RetiresOnSaturation(); + } }; template <> void GLES2DecoderTestBase::SpecializedSetup<FramebufferTexture2D, 0>( - bool /* valid */) { + bool valid) { DoBindFramebuffer(GL_FRAMEBUFFER, client_framebuffer_id_, kServiceFramebufferId); + if (valid) { + // Return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT so the code + // doesn't try to clear the buffer. That is tested else where. + EXPECT_CALL(*gl_, CheckFramebufferStatusEXT(GL_FRAMEBUFFER)) + .WillOnce(Return(GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT)) + .RetiresOnSaturation(); + } }; template <> diff --git a/gpu/command_buffer/service/renderbuffer_manager.h b/gpu/command_buffer/service/renderbuffer_manager.h index 50b64a9..1dc16c6 100644 --- a/gpu/command_buffer/service/renderbuffer_manager.h +++ b/gpu/command_buffer/service/renderbuffer_manager.h @@ -48,6 +48,7 @@ class RenderbufferManager { void set_internal_format(GLenum internalformat) { internal_format_ = internalformat; + cleared_ = false; } bool IsDeleted() { diff --git a/gpu/command_buffer/service/renderbuffer_manager_unittest.cc b/gpu/command_buffer/service/renderbuffer_manager_unittest.cc index 05c51ce..04781324 100644 --- a/gpu/command_buffer/service/renderbuffer_manager_unittest.cc +++ b/gpu/command_buffer/service/renderbuffer_manager_unittest.cc @@ -49,6 +49,9 @@ TEST_F(RenderbufferManagerTest, Basic) { EXPECT_FALSE(info1->cleared()); info1->set_cleared(); EXPECT_TRUE(info1->cleared()); + // Check if we set the format it gets marked as not cleared. + info1->set_internal_format(GL_RGBA); + EXPECT_FALSE(info1->cleared()); EXPECT_FALSE(info1->IsDeleted()); EXPECT_EQ(kService1Id, info1->service_id()); // Check we get nothing for a non-existent renderbuffer. |