// Copyright (c) 2012 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. #include #include #include "gpu/command_buffer/service/error_state_mock.h" #include "gpu/command_buffer/service/feature_info.h" #include "gpu/command_buffer/service/framebuffer_manager.h" #include "gpu/command_buffer/service/gles2_cmd_decoder_mock.h" #include "gpu/command_buffer/service/gpu_service_test.h" #include "gpu/command_buffer/service/renderbuffer_manager.h" #include "gpu/command_buffer/service/test_helper.h" #include "gpu/command_buffer/service/texture_manager.h" #include "testing/gtest/include/gtest/gtest.h" #include "ui/gl/gl_mock.h" using ::testing::_; using ::testing::Return; namespace gpu { namespace gles2 { namespace { const GLint kMaxTextureSize = 64; const GLint kMaxCubemapSize = 64; const GLint kMaxRectangleTextureSize = 64; const GLint kMax3DTextureSize = 256; const GLint kMaxRenderbufferSize = 64; const GLint kMaxSamples = 4; const uint32_t kMaxDrawBuffers = 16; const uint32_t kMaxColorAttachments = 16; const bool kUseDefaultTextures = false; } // namespace class FramebufferManagerTest : public GpuServiceTest { public: FramebufferManagerTest() : manager_(1, 1, CONTEXT_TYPE_OPENGLES2, NULL), feature_info_(new FeatureInfo()) { texture_manager_.reset(new TextureManager(NULL, feature_info_.get(), kMaxTextureSize, kMaxCubemapSize, kMaxRectangleTextureSize, kMax3DTextureSize, kUseDefaultTextures)); renderbuffer_manager_.reset(new RenderbufferManager(NULL, kMaxRenderbufferSize, kMaxSamples, feature_info_.get())); } ~FramebufferManagerTest() override { manager_.Destroy(false); texture_manager_->Destroy(false); renderbuffer_manager_->Destroy(false); } protected: FramebufferManager manager_; scoped_refptr feature_info_; scoped_ptr texture_manager_; scoped_ptr renderbuffer_manager_; }; TEST_F(FramebufferManagerTest, Basic) { const GLuint kClient1Id = 1; const GLuint kService1Id = 11; const GLuint kClient2Id = 2; // Check we can create framebuffer. manager_.CreateFramebuffer(kClient1Id, kService1Id); // Check framebuffer got created. Framebuffer* framebuffer1 = manager_.GetFramebuffer(kClient1Id); ASSERT_TRUE(framebuffer1 != NULL); EXPECT_FALSE(framebuffer1->IsDeleted()); EXPECT_EQ(kService1Id, framebuffer1->service_id()); GLuint client_id = 0; EXPECT_TRUE(manager_.GetClientId(framebuffer1->service_id(), &client_id)); EXPECT_EQ(kClient1Id, client_id); // Check we get nothing for a non-existent framebuffer. EXPECT_TRUE(manager_.GetFramebuffer(kClient2Id) == NULL); // Check trying to a remove non-existent framebuffers does not crash. manager_.RemoveFramebuffer(kClient2Id); // Check framebuffer gets deleted when last reference is released. EXPECT_CALL(*gl_, DeleteFramebuffersEXT(1, ::testing::Pointee(kService1Id))) .Times(1) .RetiresOnSaturation(); // Check we can't get the framebuffer after we remove it. manager_.RemoveFramebuffer(kClient1Id); EXPECT_TRUE(manager_.GetFramebuffer(kClient1Id) == NULL); } TEST_F(FramebufferManagerTest, Destroy) { const GLuint kClient1Id = 1; const GLuint kService1Id = 11; // Check we can create framebuffer. manager_.CreateFramebuffer(kClient1Id, kService1Id); // Check framebuffer got created. Framebuffer* framebuffer1 = manager_.GetFramebuffer(kClient1Id); ASSERT_TRUE(framebuffer1 != NULL); EXPECT_CALL(*gl_, DeleteFramebuffersEXT(1, ::testing::Pointee(kService1Id))) .Times(1) .RetiresOnSaturation(); manager_.Destroy(true); // Check the resources were released. framebuffer1 = manager_.GetFramebuffer(kClient1Id); ASSERT_TRUE(framebuffer1 == NULL); } class FramebufferInfoTestBase : public GpuServiceTest { public: static const GLuint kClient1Id = 1; static const GLuint kService1Id = 11; explicit FramebufferInfoTestBase(ContextType context_type) : manager_(kMaxDrawBuffers, kMaxColorAttachments, context_type, new FramebufferCompletenessCache), feature_info_(new FeatureInfo()) { texture_manager_.reset(new TextureManager(NULL, feature_info_.get(), kMaxTextureSize, kMaxCubemapSize, kMaxRectangleTextureSize, kMax3DTextureSize, kUseDefaultTextures)); renderbuffer_manager_.reset(new RenderbufferManager(NULL, kMaxRenderbufferSize, kMaxSamples, feature_info_.get())); } ~FramebufferInfoTestBase() override { manager_.Destroy(false); texture_manager_->Destroy(false); renderbuffer_manager_->Destroy(false); } protected: void SetUp() override { InitializeContext("2.0", "GL_EXT_framebuffer_object"); } void InitializeContext(const char* gl_version, const char* extensions) { GpuServiceTest::SetUpWithGLVersion(gl_version, extensions); TestHelper::SetupFeatureInfoInitExpectationsWithGLVersion(gl_.get(), extensions, "", gl_version); feature_info_->InitializeForTesting(); decoder_.reset(new MockGLES2Decoder()); manager_.CreateFramebuffer(kClient1Id, kService1Id); error_state_.reset(new ::testing::StrictMock()); framebuffer_ = manager_.GetFramebuffer(kClient1Id); ASSERT_TRUE(framebuffer_ != NULL); } FramebufferManager manager_; Framebuffer* framebuffer_; scoped_refptr feature_info_; scoped_ptr texture_manager_; scoped_ptr renderbuffer_manager_; scoped_ptr error_state_; scoped_ptr decoder_; }; class FramebufferInfoTest : public FramebufferInfoTestBase { public: FramebufferInfoTest() : FramebufferInfoTestBase(CONTEXT_TYPE_OPENGLES2) {} }; // GCC requires these declarations, but MSVC requires they not be present #ifndef COMPILER_MSVC const GLuint FramebufferInfoTestBase::kClient1Id; const GLuint FramebufferInfoTestBase::kService1Id; #endif TEST_F(FramebufferInfoTest, Basic) { EXPECT_EQ(kService1Id, framebuffer_->service_id()); EXPECT_FALSE(framebuffer_->IsDeleted()); EXPECT_TRUE(NULL == framebuffer_->GetAttachment(GL_COLOR_ATTACHMENT0)); EXPECT_TRUE(NULL == framebuffer_->GetAttachment(GL_DEPTH_ATTACHMENT)); EXPECT_TRUE(NULL == framebuffer_->GetAttachment(GL_STENCIL_ATTACHMENT)); EXPECT_TRUE( NULL == framebuffer_->GetAttachment(GL_DEPTH_STENCIL_ATTACHMENT)); EXPECT_FALSE(framebuffer_->HasDepthAttachment()); EXPECT_FALSE(framebuffer_->HasStencilAttachment()); EXPECT_EQ(static_cast(GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT), framebuffer_->IsPossiblyComplete(feature_info_.get())); EXPECT_TRUE(framebuffer_->IsCleared()); EXPECT_EQ(static_cast(0), framebuffer_->GetReadBufferInternalFormat()); EXPECT_FALSE(manager_.IsComplete(framebuffer_)); } TEST_F(FramebufferInfoTest, AttachRenderbuffer) { const GLuint kRenderbufferClient1Id = 33; const GLuint kRenderbufferService1Id = 333; const GLuint kRenderbufferClient2Id = 34; const GLuint kRenderbufferService2Id = 334; const GLuint kRenderbufferClient3Id = 35; const GLuint kRenderbufferService3Id = 335; const GLuint kRenderbufferClient4Id = 36; const GLuint kRenderbufferService4Id = 336; const GLsizei kWidth1 = 16; const GLsizei kHeight1 = 32; const GLenum kFormat1 = GL_RGBA4; const GLenum kBadFormat1 = GL_DEPTH_COMPONENT16; const GLsizei kSamples1 = 0; const GLsizei kWidth2 = 16; const GLsizei kHeight2 = 32; const GLenum kFormat2 = GL_DEPTH_COMPONENT16; const GLsizei kSamples2 = 0; const GLsizei kWidth3 = 16; const GLsizei kHeight3 = 32; const GLenum kFormat3 = GL_STENCIL_INDEX8; const GLsizei kSamples3 = 0; const GLsizei kWidth4 = 16; const GLsizei kHeight4 = 32; const GLenum kFormat4 = GL_STENCIL_INDEX8; const GLsizei kSamples4 = 0; EXPECT_FALSE(framebuffer_->HasUnclearedAttachment(GL_COLOR_ATTACHMENT0)); EXPECT_FALSE(framebuffer_->HasUnclearedAttachment(GL_DEPTH_ATTACHMENT)); EXPECT_FALSE(framebuffer_->HasUnclearedAttachment(GL_STENCIL_ATTACHMENT)); EXPECT_FALSE( framebuffer_->HasUnclearedAttachment(GL_DEPTH_STENCIL_ATTACHMENT)); renderbuffer_manager_->CreateRenderbuffer( kRenderbufferClient1Id, kRenderbufferService1Id); Renderbuffer* renderbuffer1 = renderbuffer_manager_->GetRenderbuffer(kRenderbufferClient1Id); ASSERT_TRUE(renderbuffer1 != NULL); // check adding one attachment framebuffer_->AttachRenderbuffer(GL_COLOR_ATTACHMENT0, renderbuffer1); EXPECT_FALSE(framebuffer_->HasUnclearedAttachment(GL_COLOR_ATTACHMENT0)); EXPECT_FALSE(framebuffer_->HasUnclearedAttachment(GL_DEPTH_ATTACHMENT)); EXPECT_EQ(static_cast(GL_RGBA4), framebuffer_->GetReadBufferInternalFormat()); EXPECT_FALSE(framebuffer_->HasDepthAttachment()); EXPECT_FALSE(framebuffer_->HasStencilAttachment()); EXPECT_EQ(static_cast(GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT), framebuffer_->IsPossiblyComplete(feature_info_.get())); EXPECT_TRUE(framebuffer_->IsCleared()); // Try a format that's not good for COLOR_ATTACHMENT0. renderbuffer_manager_->SetInfo( renderbuffer1, kSamples1, kBadFormat1, kWidth1, kHeight1); EXPECT_EQ(static_cast(GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT), framebuffer_->IsPossiblyComplete(feature_info_.get())); // Try a good format. renderbuffer_manager_->SetInfo( renderbuffer1, kSamples1, kFormat1, kWidth1, kHeight1); EXPECT_EQ(static_cast(kFormat1), framebuffer_->GetReadBufferInternalFormat()); EXPECT_FALSE(framebuffer_->HasDepthAttachment()); EXPECT_FALSE(framebuffer_->HasStencilAttachment()); EXPECT_EQ(static_cast(GL_FRAMEBUFFER_COMPLETE), framebuffer_->IsPossiblyComplete(feature_info_.get())); EXPECT_FALSE(framebuffer_->IsCleared()); // check adding another renderbuffer_manager_->CreateRenderbuffer( kRenderbufferClient2Id, kRenderbufferService2Id); Renderbuffer* renderbuffer2 = renderbuffer_manager_->GetRenderbuffer(kRenderbufferClient2Id); ASSERT_TRUE(renderbuffer2 != NULL); framebuffer_->AttachRenderbuffer(GL_DEPTH_ATTACHMENT, renderbuffer2); EXPECT_TRUE(framebuffer_->HasUnclearedAttachment(GL_COLOR_ATTACHMENT0)); EXPECT_FALSE(framebuffer_->HasUnclearedAttachment(GL_DEPTH_ATTACHMENT)); EXPECT_EQ(static_cast(kFormat1), framebuffer_->GetReadBufferInternalFormat()); EXPECT_TRUE(framebuffer_->HasDepthAttachment()); EXPECT_FALSE(framebuffer_->HasStencilAttachment()); // The attachment has a size of 0,0 so depending on the order of the map // of attachments it could either get INCOMPLETE_ATTACHMENT because it's 0,0 // or INCOMPLETE_DIMENSIONS because it's not the same size as the other // attachment. GLenum status = framebuffer_->IsPossiblyComplete(feature_info_.get()); EXPECT_TRUE( status == GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT || status == GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT); EXPECT_FALSE(framebuffer_->IsCleared()); renderbuffer_manager_->SetInfo( renderbuffer2, kSamples2, kFormat2, kWidth2, kHeight2); EXPECT_EQ(static_cast(GL_FRAMEBUFFER_COMPLETE), framebuffer_->IsPossiblyComplete(feature_info_.get())); EXPECT_FALSE(framebuffer_->IsCleared()); EXPECT_TRUE(framebuffer_->HasUnclearedAttachment(GL_DEPTH_ATTACHMENT)); // check marking them as cleared. manager_.MarkAttachmentsAsCleared( framebuffer_, renderbuffer_manager_.get(), texture_manager_.get()); EXPECT_FALSE(framebuffer_->HasUnclearedAttachment(GL_COLOR_ATTACHMENT0)); EXPECT_FALSE(framebuffer_->HasUnclearedAttachment(GL_DEPTH_ATTACHMENT)); EXPECT_EQ(static_cast(GL_FRAMEBUFFER_COMPLETE), framebuffer_->IsPossiblyComplete(feature_info_.get())); EXPECT_TRUE(framebuffer_->IsCleared()); // Check adding one that is already cleared. renderbuffer_manager_->CreateRenderbuffer( kRenderbufferClient3Id, kRenderbufferService3Id); Renderbuffer* renderbuffer3 = renderbuffer_manager_->GetRenderbuffer(kRenderbufferClient3Id); ASSERT_TRUE(renderbuffer3 != NULL); renderbuffer_manager_->SetInfo( renderbuffer3, kSamples3, kFormat3, kWidth3, kHeight3); renderbuffer_manager_->SetCleared(renderbuffer3, true); framebuffer_->AttachRenderbuffer(GL_STENCIL_ATTACHMENT, renderbuffer3); EXPECT_FALSE(framebuffer_->HasUnclearedAttachment(GL_STENCIL_ATTACHMENT)); EXPECT_EQ(static_cast(kFormat1), framebuffer_->GetReadBufferInternalFormat()); EXPECT_TRUE(framebuffer_->HasDepthAttachment()); EXPECT_TRUE(framebuffer_->HasStencilAttachment()); EXPECT_EQ(static_cast(GL_FRAMEBUFFER_COMPLETE), framebuffer_->IsPossiblyComplete(feature_info_.get())); EXPECT_TRUE(framebuffer_->IsCleared()); // Check marking the renderbuffer as unclared. renderbuffer_manager_->SetInfo( renderbuffer1, kSamples1, kFormat1, kWidth1, kHeight1); EXPECT_EQ(static_cast(kFormat1), framebuffer_->GetReadBufferInternalFormat()); EXPECT_TRUE(framebuffer_->HasDepthAttachment()); EXPECT_TRUE(framebuffer_->HasStencilAttachment()); EXPECT_EQ(static_cast(GL_FRAMEBUFFER_COMPLETE), framebuffer_->IsPossiblyComplete(feature_info_.get())); EXPECT_FALSE(framebuffer_->IsCleared()); const Framebuffer::Attachment* attachment = framebuffer_->GetAttachment(GL_COLOR_ATTACHMENT0); ASSERT_TRUE(attachment != NULL); EXPECT_EQ(kWidth1, attachment->width()); EXPECT_EQ(kHeight1, attachment->height()); EXPECT_EQ(kSamples1, attachment->samples()); EXPECT_EQ(kFormat1, attachment->internal_format()); EXPECT_FALSE(attachment->cleared()); EXPECT_TRUE(framebuffer_->HasUnclearedAttachment(GL_COLOR_ATTACHMENT0)); // Clear it. manager_.MarkAttachmentsAsCleared( framebuffer_, renderbuffer_manager_.get(), texture_manager_.get()); EXPECT_FALSE(framebuffer_->HasUnclearedAttachment(GL_COLOR_ATTACHMENT0)); EXPECT_TRUE(framebuffer_->IsCleared()); // Check replacing an attachment renderbuffer_manager_->CreateRenderbuffer( kRenderbufferClient4Id, kRenderbufferService4Id); Renderbuffer* renderbuffer4 = renderbuffer_manager_->GetRenderbuffer(kRenderbufferClient4Id); ASSERT_TRUE(renderbuffer4 != NULL); renderbuffer_manager_->SetInfo( renderbuffer4, kSamples4, kFormat4, kWidth4, kHeight4); framebuffer_->AttachRenderbuffer(GL_STENCIL_ATTACHMENT, renderbuffer4); EXPECT_TRUE(framebuffer_->HasUnclearedAttachment(GL_STENCIL_ATTACHMENT)); EXPECT_FALSE(framebuffer_->IsCleared()); attachment = framebuffer_->GetAttachment(GL_STENCIL_ATTACHMENT); ASSERT_TRUE(attachment != NULL); EXPECT_EQ(kWidth4, attachment->width()); EXPECT_EQ(kHeight4, attachment->height()); EXPECT_EQ(kSamples4, attachment->samples()); EXPECT_EQ(kFormat4, attachment->internal_format()); EXPECT_FALSE(attachment->cleared()); EXPECT_EQ(static_cast(GL_FRAMEBUFFER_COMPLETE), framebuffer_->IsPossiblyComplete(feature_info_.get())); // Check changing an attachment. renderbuffer_manager_->SetInfo( renderbuffer4, kSamples4, kFormat4, kWidth4 + 1, kHeight4); attachment = framebuffer_->GetAttachment(GL_STENCIL_ATTACHMENT); ASSERT_TRUE(attachment != NULL); EXPECT_EQ(kWidth4 + 1, attachment->width()); EXPECT_EQ(kHeight4, attachment->height()); EXPECT_EQ(kSamples4, attachment->samples()); EXPECT_EQ(kFormat4, attachment->internal_format()); EXPECT_FALSE(attachment->cleared()); EXPECT_FALSE(framebuffer_->IsCleared()); EXPECT_EQ(static_cast(GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT), framebuffer_->IsPossiblyComplete(feature_info_.get())); // Check removing it. framebuffer_->AttachRenderbuffer(GL_STENCIL_ATTACHMENT, NULL); EXPECT_FALSE(framebuffer_->HasUnclearedAttachment(GL_STENCIL_ATTACHMENT)); EXPECT_EQ(static_cast(kFormat1), framebuffer_->GetReadBufferInternalFormat()); EXPECT_TRUE(framebuffer_->HasDepthAttachment()); EXPECT_FALSE(framebuffer_->HasStencilAttachment()); EXPECT_TRUE(framebuffer_->IsCleared()); EXPECT_EQ(static_cast(GL_FRAMEBUFFER_COMPLETE), framebuffer_->IsPossiblyComplete(feature_info_.get())); // Remove depth, Set color to 0 size. framebuffer_->AttachRenderbuffer(GL_DEPTH_ATTACHMENT, NULL); renderbuffer_manager_->SetInfo(renderbuffer1, kSamples1, kFormat1, 0, 0); EXPECT_EQ(static_cast(GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT), framebuffer_->IsPossiblyComplete(feature_info_.get())); // Remove color. framebuffer_->AttachRenderbuffer(GL_COLOR_ATTACHMENT0, NULL); EXPECT_EQ(static_cast(GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT), framebuffer_->IsPossiblyComplete(feature_info_.get())); } TEST_F(FramebufferInfoTest, AttachTexture) { const GLuint kTextureClient1Id = 33; const GLuint kTextureService1Id = 333; const GLuint kTextureClient2Id = 34; const GLuint kTextureService2Id = 334; const GLint kDepth = 1; const GLint kBorder = 0; const GLenum kType = GL_UNSIGNED_BYTE; const GLsizei kWidth1 = 16; const GLsizei kHeight1 = 32; const GLint kLevel1 = 0; const GLenum kFormat1 = GL_RGBA; const GLenum kBadFormat1 = GL_DEPTH_COMPONENT16; const GLenum kTarget1 = GL_TEXTURE_2D; const GLsizei kSamples1 = 0; const GLsizei kWidth2 = 16; const GLsizei kHeight2 = 32; const GLint kLevel2 = 0; const GLenum kFormat2 = GL_RGB; const GLenum kTarget2 = GL_TEXTURE_2D; const GLsizei kSamples2 = 0; const GLsizei kWidth3 = 75; const GLsizei kHeight3 = 123; const GLint kLevel3 = 0; const GLenum kFormat3 = GL_RGB565; const GLsizei kSamples3 = 0; EXPECT_FALSE(framebuffer_->HasUnclearedAttachment(GL_COLOR_ATTACHMENT0)); EXPECT_FALSE(framebuffer_->HasUnclearedAttachment(GL_DEPTH_ATTACHMENT)); EXPECT_FALSE(framebuffer_->HasUnclearedAttachment(GL_STENCIL_ATTACHMENT)); EXPECT_FALSE( framebuffer_->HasUnclearedAttachment(GL_DEPTH_STENCIL_ATTACHMENT)); EXPECT_EQ(static_cast(GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT), framebuffer_->IsPossiblyComplete(feature_info_.get())); texture_manager_->CreateTexture(kTextureClient1Id, kTextureService1Id); scoped_refptr texture1( texture_manager_->GetTexture(kTextureClient1Id)); ASSERT_TRUE(texture1.get() != NULL); // check adding one attachment framebuffer_->AttachTexture( GL_COLOR_ATTACHMENT0, texture1.get(), kTarget1, kLevel1, kSamples1); EXPECT_FALSE(framebuffer_->HasUnclearedAttachment(GL_COLOR_ATTACHMENT0)); EXPECT_EQ(static_cast(GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT), framebuffer_->IsPossiblyComplete(feature_info_.get())); EXPECT_TRUE(framebuffer_->IsCleared()); EXPECT_EQ(static_cast(0), framebuffer_->GetReadBufferInternalFormat()); // Try format that doesn't work with COLOR_ATTACHMENT0 texture_manager_->SetTarget(texture1.get(), GL_TEXTURE_2D); texture_manager_->SetLevelInfo( texture1.get(), GL_TEXTURE_2D, kLevel1, kBadFormat1, kWidth1, kHeight1, kDepth, kBorder, kBadFormat1, kType, gfx::Rect(kWidth1, kHeight1)); EXPECT_EQ(static_cast(GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT), framebuffer_->IsPossiblyComplete(feature_info_.get())); // Try a good format. texture_manager_->SetLevelInfo(texture1.get(), GL_TEXTURE_2D, kLevel1, kFormat1, kWidth1, kHeight1, kDepth, kBorder, kFormat1, kType, gfx::Rect()); EXPECT_EQ(static_cast(GL_FRAMEBUFFER_COMPLETE), framebuffer_->IsPossiblyComplete(feature_info_.get())); EXPECT_FALSE(framebuffer_->IsCleared()); texture_manager_->SetLevelInfo(texture1.get(), GL_TEXTURE_2D, kLevel1, kFormat1, kWidth1, kHeight1, kDepth, kBorder, kFormat1, kType, gfx::Rect(kWidth1, kHeight1)); EXPECT_EQ(static_cast(GL_FRAMEBUFFER_COMPLETE), framebuffer_->IsPossiblyComplete(feature_info_.get())); EXPECT_TRUE(framebuffer_->IsCleared()); EXPECT_EQ(static_cast(kFormat1), framebuffer_->GetReadBufferInternalFormat()); const Framebuffer::Attachment* attachment = framebuffer_->GetAttachment(GL_COLOR_ATTACHMENT0); ASSERT_TRUE(attachment != NULL); EXPECT_EQ(kWidth1, attachment->width()); EXPECT_EQ(kHeight1, attachment->height()); EXPECT_EQ(kSamples1, attachment->samples()); EXPECT_EQ(kFormat1, attachment->internal_format()); EXPECT_TRUE(attachment->cleared()); // Check replacing an attachment texture_manager_->CreateTexture(kTextureClient2Id, kTextureService2Id); scoped_refptr texture2( texture_manager_->GetTexture(kTextureClient2Id)); ASSERT_TRUE(texture2.get() != NULL); texture_manager_->SetTarget(texture2.get(), GL_TEXTURE_2D); texture_manager_->SetLevelInfo(texture2.get(), GL_TEXTURE_2D, kLevel2, kFormat2, kWidth2, kHeight2, kDepth, kBorder, kFormat2, kType, gfx::Rect(kWidth2, kHeight2)); framebuffer_->AttachTexture( GL_COLOR_ATTACHMENT0, texture2.get(), kTarget2, kLevel2, kSamples2); EXPECT_EQ(static_cast(kFormat2), framebuffer_->GetReadBufferInternalFormat()); EXPECT_EQ(static_cast(GL_FRAMEBUFFER_COMPLETE), framebuffer_->IsPossiblyComplete(feature_info_.get())); EXPECT_TRUE(framebuffer_->IsCleared()); attachment = framebuffer_->GetAttachment(GL_COLOR_ATTACHMENT0); ASSERT_TRUE(attachment != NULL); EXPECT_EQ(kWidth2, attachment->width()); EXPECT_EQ(kHeight2, attachment->height()); EXPECT_EQ(kSamples2, attachment->samples()); EXPECT_EQ(kFormat2, attachment->internal_format()); EXPECT_TRUE(attachment->cleared()); // Check changing attachment texture_manager_->SetLevelInfo(texture2.get(), GL_TEXTURE_2D, kLevel3, kFormat3, kWidth3, kHeight3, kDepth, kBorder, kFormat3, kType, gfx::Rect()); attachment = framebuffer_->GetAttachment(GL_COLOR_ATTACHMENT0); ASSERT_TRUE(attachment != NULL); EXPECT_EQ(kWidth3, attachment->width()); EXPECT_EQ(kHeight3, attachment->height()); EXPECT_EQ(kSamples3, attachment->samples()); EXPECT_EQ(kFormat3, attachment->internal_format()); EXPECT_FALSE(attachment->cleared()); EXPECT_EQ(static_cast(kFormat3), framebuffer_->GetReadBufferInternalFormat()); EXPECT_EQ(static_cast(GL_FRAMEBUFFER_COMPLETE), framebuffer_->IsPossiblyComplete(feature_info_.get())); EXPECT_FALSE(framebuffer_->IsCleared()); // Set to size 0 texture_manager_->SetLevelInfo(texture2.get(), GL_TEXTURE_2D, kLevel3, kFormat3, 0, 0, kDepth, kBorder, kFormat3, kType, gfx::Rect()); EXPECT_EQ(static_cast(GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT), framebuffer_->IsPossiblyComplete(feature_info_.get())); // Check removing it. framebuffer_->AttachTexture(GL_COLOR_ATTACHMENT0, NULL, 0, 0, 0); EXPECT_TRUE(framebuffer_->GetAttachment(GL_COLOR_ATTACHMENT0) == NULL); EXPECT_EQ(static_cast(0), framebuffer_->GetReadBufferInternalFormat()); EXPECT_EQ(static_cast(GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT), framebuffer_->IsPossiblyComplete(feature_info_.get())); EXPECT_TRUE(framebuffer_->IsCleared()); } TEST_F(FramebufferInfoTest, ClearPartiallyClearedAttachments) { const GLuint kTextureClientId = 33; const GLuint kTextureServiceId = 333; texture_manager_->CreateTexture(kTextureClientId, kTextureServiceId); scoped_refptr texture( texture_manager_->GetTexture(kTextureClientId)); ASSERT_TRUE(texture.get() != NULL); texture_manager_->SetTarget(texture.get(), GL_TEXTURE_2D); framebuffer_->AttachTexture( GL_COLOR_ATTACHMENT0, texture.get(), GL_TEXTURE_2D, 0, 0); const Framebuffer::Attachment* attachment = framebuffer_->GetAttachment(GL_COLOR_ATTACHMENT0); ASSERT_TRUE(attachment != NULL); // Not cleared at all. texture_manager_->SetLevelInfo(texture.get(), GL_TEXTURE_2D, 0, GL_RGBA, 4, 4, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, gfx::Rect()); EXPECT_FALSE(attachment->cleared()); EXPECT_FALSE(attachment->IsPartiallyCleared()); EXPECT_FALSE(framebuffer_->IsCleared()); EXPECT_TRUE(framebuffer_->HasUnclearedAttachment(GL_COLOR_ATTACHMENT0)); EXPECT_TRUE(framebuffer_->HasUnclearedColorAttachments()); // Clear it but nothing happens. framebuffer_->ClearUnclearedIntOr3DTexturesOrPartiallyClearedTextures( decoder_.get(), texture_manager_.get()); EXPECT_FALSE(attachment->cleared()); EXPECT_FALSE(attachment->IsPartiallyCleared()); EXPECT_FALSE(framebuffer_->IsCleared()); EXPECT_TRUE(framebuffer_->HasUnclearedAttachment(GL_COLOR_ATTACHMENT0)); EXPECT_TRUE(framebuffer_->HasUnclearedColorAttachments()); // Fully cleared. texture_manager_->SetLevelInfo(texture.get(), GL_TEXTURE_2D, 0, GL_RGBA, 4, 4, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, gfx::Rect(0, 0, 4, 4)); EXPECT_TRUE(attachment->cleared()); EXPECT_FALSE(attachment->IsPartiallyCleared()); EXPECT_TRUE(framebuffer_->IsCleared()); EXPECT_FALSE(framebuffer_->HasUnclearedAttachment(GL_COLOR_ATTACHMENT0)); EXPECT_FALSE(framebuffer_->HasUnclearedColorAttachments()); // Clear it but nothing happens. framebuffer_->ClearUnclearedIntOr3DTexturesOrPartiallyClearedTextures( decoder_.get(), texture_manager_.get()); EXPECT_TRUE(attachment->cleared()); EXPECT_FALSE(attachment->IsPartiallyCleared()); EXPECT_TRUE(framebuffer_->IsCleared()); EXPECT_FALSE(framebuffer_->HasUnclearedAttachment(GL_COLOR_ATTACHMENT0)); EXPECT_FALSE(framebuffer_->HasUnclearedColorAttachments()); // Partially cleared. texture_manager_->SetLevelInfo(texture.get(), GL_TEXTURE_2D, 0, GL_RGBA, 4, 4, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, gfx::Rect(1, 1, 2, 2)); EXPECT_FALSE(attachment->cleared()); EXPECT_TRUE(attachment->IsPartiallyCleared()); EXPECT_FALSE(framebuffer_->IsCleared()); EXPECT_TRUE(framebuffer_->HasUnclearedAttachment(GL_COLOR_ATTACHMENT0)); EXPECT_TRUE(framebuffer_->HasUnclearedColorAttachments()); // Now clear it. EXPECT_CALL(*decoder_.get(), ClearLevel(texture->texture(), GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, _, _, _, _)) .WillOnce(Return(true)) .WillOnce(Return(true)) .WillOnce(Return(true)) .WillOnce(Return(true)) .WillOnce(Return(true)) .WillOnce(Return(true)) .WillOnce(Return(true)) .WillOnce(Return(true)) .RetiresOnSaturation(); framebuffer_->ClearUnclearedIntOr3DTexturesOrPartiallyClearedTextures( decoder_.get(), texture_manager_.get()); EXPECT_TRUE(attachment->cleared()); EXPECT_FALSE(attachment->IsPartiallyCleared()); EXPECT_TRUE(framebuffer_->IsCleared()); EXPECT_FALSE(framebuffer_->HasUnclearedAttachment(GL_COLOR_ATTACHMENT0)); EXPECT_FALSE(framebuffer_->HasUnclearedColorAttachments()); } TEST_F(FramebufferInfoTest, Clear3DTextureAttachments) { const GLuint kTextureClientId = 33; const GLuint kTextureServiceId = 333; texture_manager_->CreateTexture(kTextureClientId, kTextureServiceId); scoped_refptr texture( texture_manager_->GetTexture(kTextureClientId)); ASSERT_TRUE(texture.get() != NULL); texture_manager_->SetTarget(texture.get(), GL_TEXTURE_3D); framebuffer_->AttachTexture( GL_COLOR_ATTACHMENT0, texture.get(), GL_TEXTURE_3D, 0, 0); const Framebuffer::Attachment* attachment = framebuffer_->GetAttachment(GL_COLOR_ATTACHMENT0); ASSERT_TRUE(attachment != NULL); const int kWidth = 4; const int kHeight = 8; const int kDepth = 2; // Fully cleared. texture_manager_->SetLevelInfo(texture.get(), GL_TEXTURE_2D, 0, GL_RGBA8, kWidth, kHeight, kDepth, 0, GL_RGBA, GL_UNSIGNED_BYTE, gfx::Rect(0, 0, kWidth, kHeight)); EXPECT_TRUE(attachment->cleared()); EXPECT_FALSE(attachment->IsPartiallyCleared()); EXPECT_TRUE(framebuffer_->IsCleared()); EXPECT_FALSE(framebuffer_->HasUnclearedAttachment(GL_COLOR_ATTACHMENT0)); EXPECT_FALSE(framebuffer_->HasUnclearedColorAttachments()); // Clear it but nothing happens. framebuffer_->ClearUnclearedIntOr3DTexturesOrPartiallyClearedTextures( decoder_.get(), texture_manager_.get()); EXPECT_TRUE(attachment->cleared()); EXPECT_FALSE(attachment->IsPartiallyCleared()); EXPECT_TRUE(framebuffer_->IsCleared()); EXPECT_FALSE(framebuffer_->HasUnclearedAttachment(GL_COLOR_ATTACHMENT0)); EXPECT_FALSE(framebuffer_->HasUnclearedColorAttachments()); // Not cleared at all. texture_manager_->SetLevelInfo(texture.get(), GL_TEXTURE_3D, 0, GL_RGBA8, kWidth, kHeight, kDepth, 0, GL_RGBA, GL_UNSIGNED_BYTE, gfx::Rect()); EXPECT_FALSE(attachment->cleared()); EXPECT_FALSE(attachment->IsPartiallyCleared()); EXPECT_FALSE(framebuffer_->IsCleared()); EXPECT_TRUE(framebuffer_->HasUnclearedAttachment(GL_COLOR_ATTACHMENT0)); EXPECT_TRUE(framebuffer_->HasUnclearedColorAttachments()); // Now clear it. EXPECT_CALL(*decoder_.get(), ClearLevel3D(texture->texture(), GL_TEXTURE_3D, 0, GL_RGBA, GL_UNSIGNED_BYTE, kWidth, kHeight, kDepth)) .WillOnce(Return(true)) .RetiresOnSaturation(); framebuffer_->ClearUnclearedIntOr3DTexturesOrPartiallyClearedTextures( decoder_.get(), texture_manager_.get()); EXPECT_TRUE(attachment->cleared()); EXPECT_FALSE(attachment->IsPartiallyCleared()); EXPECT_TRUE(framebuffer_->IsCleared()); EXPECT_FALSE(framebuffer_->HasUnclearedAttachment(GL_COLOR_ATTACHMENT0)); EXPECT_FALSE(framebuffer_->HasUnclearedColorAttachments()); } TEST_F(FramebufferInfoTest, ClearIntegerTextureAttachments) { const GLuint kTextureClientId = 33; const GLuint kTextureServiceId = 333; texture_manager_->CreateTexture(kTextureClientId, kTextureServiceId); scoped_refptr texture( texture_manager_->GetTexture(kTextureClientId)); ASSERT_TRUE(texture.get() != NULL); texture_manager_->SetTarget(texture.get(), GL_TEXTURE_2D); framebuffer_->AttachTexture( GL_COLOR_ATTACHMENT0, texture.get(), GL_TEXTURE_2D, 0, 0); const Framebuffer::Attachment* attachment = framebuffer_->GetAttachment(GL_COLOR_ATTACHMENT0); ASSERT_TRUE(attachment != NULL); const int kWidth = 4; const int kHeight = 8; // Fully cleared. texture_manager_->SetLevelInfo(texture.get(), GL_TEXTURE_2D, 0, GL_RGBA8UI, kWidth, kHeight, 1, 0, GL_RGBA_INTEGER, GL_UNSIGNED_BYTE, gfx::Rect(0, 0, kWidth, kHeight)); EXPECT_TRUE(attachment->cleared()); EXPECT_FALSE(attachment->IsPartiallyCleared()); EXPECT_TRUE(framebuffer_->IsCleared()); EXPECT_FALSE(framebuffer_->HasUnclearedAttachment(GL_COLOR_ATTACHMENT0)); EXPECT_FALSE(framebuffer_->HasUnclearedColorAttachments()); // Clear it but nothing happens. framebuffer_->ClearUnclearedIntOr3DTexturesOrPartiallyClearedTextures( decoder_.get(), texture_manager_.get()); EXPECT_TRUE(attachment->cleared()); EXPECT_FALSE(attachment->IsPartiallyCleared()); EXPECT_TRUE(framebuffer_->IsCleared()); EXPECT_FALSE(framebuffer_->HasUnclearedAttachment(GL_COLOR_ATTACHMENT0)); EXPECT_FALSE(framebuffer_->HasUnclearedColorAttachments()); // Not cleared at all. texture_manager_->SetLevelInfo(texture.get(), GL_TEXTURE_2D, 0, GL_RGBA8UI, kWidth, kHeight, 1, 0, GL_RGBA_INTEGER, GL_UNSIGNED_BYTE, gfx::Rect()); EXPECT_FALSE(attachment->cleared()); EXPECT_FALSE(attachment->IsPartiallyCleared()); EXPECT_FALSE(framebuffer_->IsCleared()); EXPECT_TRUE(framebuffer_->HasUnclearedAttachment(GL_COLOR_ATTACHMENT0)); EXPECT_TRUE(framebuffer_->HasUnclearedColorAttachments()); // Now clear it. EXPECT_CALL(*decoder_.get(), ClearLevel(texture->texture(), GL_TEXTURE_2D, 0, GL_RGBA_INTEGER, GL_UNSIGNED_BYTE, 0, 0, kWidth, kHeight)) .WillOnce(Return(true)) .RetiresOnSaturation(); framebuffer_->ClearUnclearedIntOr3DTexturesOrPartiallyClearedTextures( decoder_.get(), texture_manager_.get()); EXPECT_TRUE(attachment->cleared()); EXPECT_FALSE(attachment->IsPartiallyCleared()); EXPECT_TRUE(framebuffer_->IsCleared()); EXPECT_FALSE(framebuffer_->HasUnclearedAttachment(GL_COLOR_ATTACHMENT0)); EXPECT_FALSE(framebuffer_->HasUnclearedColorAttachments()); } TEST_F(FramebufferInfoTest, DrawBuffers) { const GLuint kTextureClientId[] = { 33, 34 }; const GLuint kTextureServiceId[] = { 333, 334 }; for (GLenum i = GL_COLOR_ATTACHMENT0; i < GL_COLOR_ATTACHMENT0 + kMaxColorAttachments; ++i) { EXPECT_FALSE(framebuffer_->HasUnclearedAttachment(i)); } EXPECT_FALSE(framebuffer_->HasUnclearedColorAttachments()); EXPECT_EQ(static_cast(GL_COLOR_ATTACHMENT0), framebuffer_->GetDrawBuffer(GL_DRAW_BUFFER0_ARB)); for (GLenum i = GL_DRAW_BUFFER1_ARB; i < GL_DRAW_BUFFER0_ARB + kMaxDrawBuffers; ++i) { EXPECT_EQ(static_cast(GL_NONE), framebuffer_->GetDrawBuffer(i)); } for (size_t ii = 0; ii < arraysize(kTextureClientId); ++ii) { texture_manager_->CreateTexture( kTextureClientId[ii], kTextureServiceId[ii]); scoped_refptr texture( texture_manager_->GetTexture(kTextureClientId[ii])); ASSERT_TRUE(texture.get() != NULL); framebuffer_->AttachTexture( GL_COLOR_ATTACHMENT0 + ii, texture.get(), GL_TEXTURE_2D, 0, 0); EXPECT_FALSE( framebuffer_->HasUnclearedAttachment(GL_COLOR_ATTACHMENT0 + ii)); const Framebuffer::Attachment* attachment = framebuffer_->GetAttachment(GL_COLOR_ATTACHMENT0 + ii); ASSERT_TRUE(attachment != NULL); EXPECT_TRUE(attachment->cleared()); } EXPECT_TRUE(framebuffer_->IsCleared()); EXPECT_FALSE(framebuffer_->HasUnclearedColorAttachments()); // Set draw buffer 1 as uncleared. scoped_refptr texture1( texture_manager_->GetTexture(kTextureClientId[1])); texture_manager_->SetTarget(texture1.get(), GL_TEXTURE_2D); texture_manager_->SetLevelInfo(texture1.get(), GL_TEXTURE_2D, 0, GL_RGBA, 4, 4, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, gfx::Rect()); const Framebuffer::Attachment* attachment1 = framebuffer_->GetAttachment(GL_COLOR_ATTACHMENT1); ASSERT_TRUE(attachment1 != NULL); EXPECT_FALSE(attachment1->cleared()); EXPECT_FALSE(framebuffer_->IsCleared()); EXPECT_TRUE(framebuffer_->HasUnclearedAttachment(GL_COLOR_ATTACHMENT1)); EXPECT_TRUE(framebuffer_->HasUnclearedColorAttachments()); GLenum buffers[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 }; framebuffer_->SetDrawBuffers(2, buffers); EXPECT_EQ(static_cast(GL_COLOR_ATTACHMENT0), framebuffer_->GetDrawBuffer(GL_DRAW_BUFFER0_ARB)); EXPECT_EQ(static_cast(GL_COLOR_ATTACHMENT1), framebuffer_->GetDrawBuffer(GL_DRAW_BUFFER1_ARB)); for (GLenum i = GL_DRAW_BUFFER2_ARB; i < GL_DRAW_BUFFER0_ARB + kMaxDrawBuffers; ++i) { EXPECT_EQ(static_cast(GL_NONE), framebuffer_->GetDrawBuffer(i)); } // Only draw buffer 1 needs clearing, so we need to mask draw buffer 0. EXPECT_CALL(*gl_, DrawBuffersARB(kMaxDrawBuffers, _)) .Times(1) .RetiresOnSaturation(); EXPECT_TRUE(framebuffer_->PrepareDrawBuffersForClear()); // Now we disable draw buffer 1. buffers[1] = GL_NONE; framebuffer_->SetDrawBuffers(2, buffers); // We will enable the disabled draw buffer for clear(), and disable it // after the clear. EXPECT_CALL(*gl_, DrawBuffersARB(kMaxDrawBuffers, _)) .Times(1) .RetiresOnSaturation(); EXPECT_TRUE(framebuffer_->PrepareDrawBuffersForClear()); // Now we disable draw buffer 0, enable draw buffer 1. buffers[0] = GL_NONE; buffers[1] = GL_COLOR_ATTACHMENT1; framebuffer_->SetDrawBuffers(2, buffers); // This is the perfect setting for clear. No need to call DrawBuffers(). EXPECT_FALSE(framebuffer_->PrepareDrawBuffersForClear()); } class FramebufferInfoFloatTest : public FramebufferInfoTest { public: FramebufferInfoFloatTest() : FramebufferInfoTest() { } ~FramebufferInfoFloatTest() override {} protected: void SetUp() override { InitializeContext("OpenGL ES 3.0", "GL_OES_texture_float GL_EXT_color_buffer_float"); } }; TEST_F(FramebufferInfoFloatTest, AttachFloatTexture) { const GLuint kTextureClientId = 33; const GLuint kTextureServiceId = 333; const GLint kDepth = 1; const GLint kBorder = 0; const GLenum kType = GL_FLOAT; const GLsizei kWidth = 16; const GLsizei kHeight = 32; const GLint kLevel = 0; const GLenum kFormat = GL_RGBA; const GLenum kInternalFormat = GL_RGBA32F; const GLenum kTarget = GL_TEXTURE_2D; const GLsizei kSamples = 0; EXPECT_FALSE(framebuffer_->HasUnclearedAttachment(GL_COLOR_ATTACHMENT0)); EXPECT_FALSE(framebuffer_->HasUnclearedAttachment(GL_DEPTH_ATTACHMENT)); EXPECT_FALSE(framebuffer_->HasUnclearedAttachment(GL_STENCIL_ATTACHMENT)); texture_manager_->CreateTexture(kTextureClientId, kTextureServiceId); scoped_refptr texture( texture_manager_->GetTexture(kTextureClientId)); ASSERT_TRUE(texture.get() != NULL); framebuffer_->AttachTexture( GL_COLOR_ATTACHMENT0, texture.get(), kTarget, kLevel, kSamples); EXPECT_EQ(static_cast(0), framebuffer_->GetReadBufferInternalFormat()); texture_manager_->SetTarget(texture.get(), GL_TEXTURE_2D); texture_manager_->SetLevelInfo(texture.get(), GL_TEXTURE_2D, kLevel, kInternalFormat, kWidth, kHeight, kDepth, kBorder, kFormat, kType, gfx::Rect()); // Texture with a sized float internalformat is allowed as an attachment // since float color attachment extension is present. EXPECT_EQ(static_cast(GL_FRAMEBUFFER_COMPLETE), framebuffer_->IsPossiblyComplete(feature_info_.get())); } TEST_F(FramebufferInfoTest, UnbindRenderbuffer) { const GLuint kRenderbufferClient1Id = 33; const GLuint kRenderbufferService1Id = 333; const GLuint kRenderbufferClient2Id = 34; const GLuint kRenderbufferService2Id = 334; renderbuffer_manager_->CreateRenderbuffer( kRenderbufferClient1Id, kRenderbufferService1Id); Renderbuffer* renderbuffer1 = renderbuffer_manager_->GetRenderbuffer(kRenderbufferClient1Id); ASSERT_TRUE(renderbuffer1 != NULL); renderbuffer_manager_->CreateRenderbuffer( kRenderbufferClient2Id, kRenderbufferService2Id); Renderbuffer* renderbuffer2 = renderbuffer_manager_->GetRenderbuffer(kRenderbufferClient2Id); ASSERT_TRUE(renderbuffer2 != NULL); // Attach to 2 attachment points. framebuffer_->AttachRenderbuffer(GL_COLOR_ATTACHMENT0, renderbuffer1); framebuffer_->AttachRenderbuffer(GL_DEPTH_ATTACHMENT, renderbuffer1); // Check they were attached. EXPECT_TRUE(framebuffer_->GetAttachment(GL_COLOR_ATTACHMENT0) != NULL); EXPECT_TRUE(framebuffer_->GetAttachment(GL_DEPTH_ATTACHMENT) != NULL); // Unbind unattached renderbuffer. framebuffer_->UnbindRenderbuffer(GL_RENDERBUFFER, renderbuffer2); // Should be no-op. EXPECT_TRUE(framebuffer_->GetAttachment(GL_COLOR_ATTACHMENT0) != NULL); EXPECT_TRUE(framebuffer_->GetAttachment(GL_DEPTH_ATTACHMENT) != NULL); // Unbind renderbuffer. framebuffer_->UnbindRenderbuffer(GL_RENDERBUFFER, renderbuffer1); // Check they were detached EXPECT_TRUE(framebuffer_->GetAttachment(GL_COLOR_ATTACHMENT0) == NULL); EXPECT_TRUE(framebuffer_->GetAttachment(GL_DEPTH_ATTACHMENT) == NULL); } TEST_F(FramebufferInfoTest, UnbindTexture) { const GLuint kTextureClient1Id = 33; const GLuint kTextureService1Id = 333; const GLuint kTextureClient2Id = 34; const GLuint kTextureService2Id = 334; const GLenum kTarget1 = GL_TEXTURE_2D; const GLint kLevel1 = 0; const GLint kSamples1 = 0; texture_manager_->CreateTexture(kTextureClient1Id, kTextureService1Id); scoped_refptr texture1( texture_manager_->GetTexture(kTextureClient1Id)); ASSERT_TRUE(texture1.get() != NULL); texture_manager_->CreateTexture(kTextureClient2Id, kTextureService2Id); scoped_refptr texture2( texture_manager_->GetTexture(kTextureClient2Id)); ASSERT_TRUE(texture2.get() != NULL); // Attach to 2 attachment points. framebuffer_->AttachTexture( GL_COLOR_ATTACHMENT0, texture1.get(), kTarget1, kLevel1, kSamples1); framebuffer_->AttachTexture( GL_DEPTH_ATTACHMENT, texture1.get(), kTarget1, kLevel1, kSamples1); // Check they were attached. EXPECT_TRUE(framebuffer_->GetAttachment(GL_COLOR_ATTACHMENT0) != NULL); EXPECT_TRUE(framebuffer_->GetAttachment(GL_DEPTH_ATTACHMENT) != NULL); // Unbind unattached texture. framebuffer_->UnbindTexture(kTarget1, texture2.get()); // Should be no-op. EXPECT_TRUE(framebuffer_->GetAttachment(GL_COLOR_ATTACHMENT0) != NULL); EXPECT_TRUE(framebuffer_->GetAttachment(GL_DEPTH_ATTACHMENT) != NULL); // Unbind texture. framebuffer_->UnbindTexture(kTarget1, texture1.get()); // Check they were detached EXPECT_TRUE(framebuffer_->GetAttachment(GL_COLOR_ATTACHMENT0) == NULL); EXPECT_TRUE(framebuffer_->GetAttachment(GL_DEPTH_ATTACHMENT) == NULL); } TEST_F(FramebufferInfoTest, IsCompleteMarkAsComplete) { const GLuint kRenderbufferClient1Id = 33; const GLuint kRenderbufferService1Id = 333; const GLuint kTextureClient2Id = 34; const GLuint kTextureService2Id = 334; const GLenum kTarget1 = GL_TEXTURE_2D; const GLint kLevel1 = 0; const GLint kSamples1 = 0; renderbuffer_manager_->CreateRenderbuffer( kRenderbufferClient1Id, kRenderbufferService1Id); Renderbuffer* renderbuffer1 = renderbuffer_manager_->GetRenderbuffer(kRenderbufferClient1Id); ASSERT_TRUE(renderbuffer1 != NULL); texture_manager_->CreateTexture(kTextureClient2Id, kTextureService2Id); scoped_refptr texture2( texture_manager_->GetTexture(kTextureClient2Id)); ASSERT_TRUE(texture2.get() != NULL); // Check MarkAsComlete marks as complete. manager_.MarkAsComplete(framebuffer_); EXPECT_TRUE(manager_.IsComplete(framebuffer_)); // Check at attaching marks as not complete. framebuffer_->AttachTexture( GL_COLOR_ATTACHMENT0, texture2.get(), kTarget1, kLevel1, kSamples1); EXPECT_FALSE(manager_.IsComplete(framebuffer_)); manager_.MarkAsComplete(framebuffer_); EXPECT_TRUE(manager_.IsComplete(framebuffer_)); framebuffer_->AttachRenderbuffer(GL_DEPTH_ATTACHMENT, renderbuffer1); EXPECT_FALSE(manager_.IsComplete(framebuffer_)); // Check MarkAttachmentsAsCleared marks as complete. manager_.MarkAttachmentsAsCleared( framebuffer_, renderbuffer_manager_.get(), texture_manager_.get()); EXPECT_TRUE(manager_.IsComplete(framebuffer_)); // Check Unbind marks as not complete. framebuffer_->UnbindRenderbuffer(GL_RENDERBUFFER, renderbuffer1); EXPECT_FALSE(manager_.IsComplete(framebuffer_)); manager_.MarkAsComplete(framebuffer_); EXPECT_TRUE(manager_.IsComplete(framebuffer_)); framebuffer_->UnbindTexture(kTarget1, texture2.get()); EXPECT_FALSE(manager_.IsComplete(framebuffer_)); } TEST_F(FramebufferInfoTest, GetStatus) { const GLuint kRenderbufferClient1Id = 33; const GLuint kRenderbufferService1Id = 333; const GLuint kTextureClient2Id = 34; const GLuint kTextureService2Id = 334; const GLenum kTarget1 = GL_TEXTURE_2D; const GLint kLevel1 = 0; const GLint kSamples1 = 0; renderbuffer_manager_->CreateRenderbuffer( kRenderbufferClient1Id, kRenderbufferService1Id); Renderbuffer* renderbuffer1 = renderbuffer_manager_->GetRenderbuffer(kRenderbufferClient1Id); ASSERT_TRUE(renderbuffer1 != NULL); texture_manager_->CreateTexture(kTextureClient2Id, kTextureService2Id); scoped_refptr texture2( texture_manager_->GetTexture(kTextureClient2Id)); ASSERT_TRUE(texture2.get() != NULL); texture_manager_->SetTarget(texture2.get(), GL_TEXTURE_2D); EXPECT_CALL(*gl_, CheckFramebufferStatusEXT(GL_FRAMEBUFFER)) .WillOnce(Return(GL_FRAMEBUFFER_COMPLETE)) .RetiresOnSaturation(); framebuffer_->GetStatus(texture_manager_.get(), GL_FRAMEBUFFER); // Check a second call for the same type does not call anything framebuffer_->GetStatus(texture_manager_.get(), GL_FRAMEBUFFER); // Check changing the attachments calls CheckFramebufferStatus. framebuffer_->AttachTexture( GL_COLOR_ATTACHMENT0, texture2.get(), kTarget1, kLevel1, kSamples1); EXPECT_CALL(*gl_, CheckFramebufferStatusEXT(GL_FRAMEBUFFER)) .WillOnce(Return(GL_FRAMEBUFFER_COMPLETE)).RetiresOnSaturation(); framebuffer_->GetStatus(texture_manager_.get(), GL_FRAMEBUFFER); // Check a second call for the same type does not call anything. framebuffer_->GetStatus(texture_manager_.get(), GL_FRAMEBUFFER); // Check a second call with a different target calls CheckFramebufferStatus. EXPECT_CALL(*gl_, CheckFramebufferStatusEXT(GL_READ_FRAMEBUFFER)) .WillOnce(Return(GL_FRAMEBUFFER_COMPLETE)) .RetiresOnSaturation(); framebuffer_->GetStatus(texture_manager_.get(), GL_READ_FRAMEBUFFER); // Check a second call for the same type does not call anything. framebuffer_->GetStatus(texture_manager_.get(), GL_READ_FRAMEBUFFER); // Check adding another attachment calls CheckFramebufferStatus. framebuffer_->AttachRenderbuffer(GL_DEPTH_ATTACHMENT, renderbuffer1); EXPECT_CALL(*gl_, CheckFramebufferStatusEXT(GL_READ_FRAMEBUFFER)) .WillOnce(Return(GL_FRAMEBUFFER_COMPLETE)) .RetiresOnSaturation(); framebuffer_->GetStatus(texture_manager_.get(), GL_READ_FRAMEBUFFER); // Check a second call for the same type does not call anything. framebuffer_->GetStatus(texture_manager_.get(), GL_READ_FRAMEBUFFER); // Check changing the format calls CheckFramebuffferStatus. TestHelper::SetTexParameteriWithExpectations(gl_.get(), error_state_.get(), texture_manager_.get(), texture2.get(), GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE, GL_NO_ERROR); EXPECT_CALL(*gl_, CheckFramebufferStatusEXT(GL_READ_FRAMEBUFFER)) .WillOnce(Return(GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT)) .WillOnce(Return(GL_FRAMEBUFFER_COMPLETE)) .RetiresOnSaturation(); framebuffer_->GetStatus(texture_manager_.get(), GL_READ_FRAMEBUFFER); // Check since it did not return FRAMEBUFFER_COMPLETE that it calls // CheckFramebufferStatus framebuffer_->GetStatus(texture_manager_.get(), GL_READ_FRAMEBUFFER); // Check putting it back does not call CheckFramebufferStatus. TestHelper::SetTexParameteriWithExpectations(gl_.get(), error_state_.get(), texture_manager_.get(), texture2.get(), GL_TEXTURE_WRAP_S, GL_REPEAT, GL_NO_ERROR); framebuffer_->GetStatus(texture_manager_.get(), GL_READ_FRAMEBUFFER); // Check Unbinding does not call CheckFramebufferStatus framebuffer_->UnbindRenderbuffer(GL_RENDERBUFFER, renderbuffer1); framebuffer_->GetStatus(texture_manager_.get(), GL_READ_FRAMEBUFFER); } class FramebufferInfoES3Test : public FramebufferInfoTestBase { public: FramebufferInfoES3Test() : FramebufferInfoTestBase(CONTEXT_TYPE_WEBGL2) {} }; TEST_F(FramebufferInfoES3Test, DifferentDimensions) { const GLuint kRenderbufferClient1Id = 33; const GLuint kRenderbufferService1Id = 333; const GLuint kRenderbufferClient2Id = 34; const GLuint kRenderbufferService2Id = 334; const GLsizei kWidth1 = 16; const GLsizei kHeight1 = 32; const GLenum kFormat1 = GL_RGBA4; const GLsizei kSamples1 = 0; const GLsizei kWidth2 = 32; // Different from kWidth1 const GLsizei kHeight2 = 32; const GLenum kFormat2 = GL_DEPTH_COMPONENT16; const GLsizei kSamples2 = 0; EXPECT_FALSE(framebuffer_->HasUnclearedAttachment(GL_COLOR_ATTACHMENT0)); EXPECT_FALSE(framebuffer_->HasUnclearedAttachment(GL_DEPTH_ATTACHMENT)); EXPECT_FALSE(framebuffer_->HasUnclearedAttachment(GL_STENCIL_ATTACHMENT)); EXPECT_FALSE( framebuffer_->HasUnclearedAttachment(GL_DEPTH_STENCIL_ATTACHMENT)); renderbuffer_manager_->CreateRenderbuffer( kRenderbufferClient1Id, kRenderbufferService1Id); Renderbuffer* renderbuffer1 = renderbuffer_manager_->GetRenderbuffer(kRenderbufferClient1Id); ASSERT_TRUE(renderbuffer1 != NULL); renderbuffer_manager_->SetInfo( renderbuffer1, kSamples1, kFormat1, kWidth1, kHeight1); framebuffer_->AttachRenderbuffer(GL_COLOR_ATTACHMENT0, renderbuffer1); renderbuffer_manager_->CreateRenderbuffer( kRenderbufferClient2Id, kRenderbufferService2Id); Renderbuffer* renderbuffer2 = renderbuffer_manager_->GetRenderbuffer(kRenderbufferClient2Id); ASSERT_TRUE(renderbuffer2 != NULL); renderbuffer_manager_->SetInfo( renderbuffer2, kSamples2, kFormat2, kWidth2, kHeight2); framebuffer_->AttachRenderbuffer(GL_DEPTH_ATTACHMENT, renderbuffer2); EXPECT_EQ(static_cast(GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT), framebuffer_->IsPossiblyComplete(feature_info_.get())); } TEST_F(FramebufferInfoES3Test, ReadBuffer) { const GLuint kRenderbufferClientId = 33; const GLuint kRenderbufferServiceId = 333; EXPECT_EQ(static_cast(GL_COLOR_ATTACHMENT0), framebuffer_->read_buffer()); framebuffer_->set_read_buffer(GL_NONE); EXPECT_EQ(static_cast(GL_NONE), framebuffer_->read_buffer()); EXPECT_FALSE(framebuffer_->GetReadBufferAttachment()); framebuffer_->set_read_buffer(GL_COLOR_ATTACHMENT1); EXPECT_FALSE(framebuffer_->GetReadBufferAttachment()); renderbuffer_manager_->CreateRenderbuffer( kRenderbufferClientId, kRenderbufferServiceId); Renderbuffer* renderbuffer = renderbuffer_manager_->GetRenderbuffer(kRenderbufferClientId); ASSERT_TRUE(renderbuffer != NULL); framebuffer_->AttachRenderbuffer(GL_COLOR_ATTACHMENT1, renderbuffer); EXPECT_TRUE(framebuffer_->GetReadBufferAttachment()); } } // namespace gles2 } // namespace gpu