// Copyright 2013 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 "gpu/command_buffer/service/feature_info.h" #include "gpu/command_buffer/service/gpu_service_test.h" #include "gpu/command_buffer/service/mailbox_manager_impl.h" #include "gpu/command_buffer/service/mailbox_manager_sync.h" #include "gpu/command_buffer/service/texture_manager.h" #include "testing/gtest/include/gtest/gtest.h" #include "ui/gl/gl_context_stub.h" #include "ui/gl/gl_mock.h" #include "ui/gl/gl_surface_stub.h" namespace gpu { namespace gles2 { using namespace ::testing; class MailboxManagerTest : public GpuServiceTest { public: MailboxManagerTest() {} ~MailboxManagerTest() override {} protected: void SetUp() override { GpuServiceTest::SetUp(); feature_info_ = new FeatureInfo; manager_ = new MailboxManagerImpl; DCHECK(!manager_->UsesSync()); } virtual void SetUpWithSynchronizer() { GpuServiceTest::SetUp(); feature_info_ = new FeatureInfo; manager_ = new MailboxManagerSync(); DCHECK(manager_->UsesSync()); } void TearDown() override { GpuServiceTest::TearDown(); } Texture* CreateTexture() { return new Texture(1); } void SetTarget(Texture* texture, GLenum target, GLuint max_level) { texture->SetTarget(NULL, target, max_level); } void SetLevelInfo(Texture* texture, GLenum target, GLint level, GLenum internal_format, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const gfx::Rect& cleared_rect) { texture->SetLevelInfo(NULL, target, level, internal_format, width, height, depth, border, format, type, cleared_rect); } void SetLevelCleared(Texture* texture, GLenum target, GLint level, bool cleared) { texture->SetLevelCleared(target, level, cleared); } GLenum SetParameter(Texture* texture, GLenum pname, GLint param) { return texture->SetParameteri(feature_info_.get(), pname, param); } void DestroyTexture(Texture* texture) { delete texture; } scoped_refptr manager_; private: scoped_refptr feature_info_; DISALLOW_COPY_AND_ASSIGN(MailboxManagerTest); }; // Tests basic produce/consume behavior. TEST_F(MailboxManagerTest, Basic) { Texture* texture = CreateTexture(); Mailbox name = Mailbox::Generate(); manager_->ProduceTexture(name, texture); EXPECT_EQ(texture, manager_->ConsumeTexture(name)); // We can consume multiple times. EXPECT_EQ(texture, manager_->ConsumeTexture(name)); // Destroy should cleanup the mailbox. DestroyTexture(texture); EXPECT_EQ(NULL, manager_->ConsumeTexture(name)); } // Tests behavior with multiple produce on the same texture. TEST_F(MailboxManagerTest, ProduceMultipleMailbox) { Texture* texture = CreateTexture(); Mailbox name1 = Mailbox::Generate(); manager_->ProduceTexture(name1, texture); EXPECT_EQ(texture, manager_->ConsumeTexture(name1)); // Can produce a second time with the same mailbox. manager_->ProduceTexture(name1, texture); EXPECT_EQ(texture, manager_->ConsumeTexture(name1)); // Can produce again, with a different mailbox. Mailbox name2 = Mailbox::Generate(); manager_->ProduceTexture(name2, texture); // Still available under all mailboxes. EXPECT_EQ(texture, manager_->ConsumeTexture(name1)); EXPECT_EQ(texture, manager_->ConsumeTexture(name2)); // Destroy should cleanup all mailboxes. DestroyTexture(texture); EXPECT_EQ(NULL, manager_->ConsumeTexture(name1)); EXPECT_EQ(NULL, manager_->ConsumeTexture(name2)); } // Tests behavior with multiple produce on the same mailbox with different // textures. TEST_F(MailboxManagerTest, ProduceMultipleTexture) { Texture* texture1 = CreateTexture(); Texture* texture2 = CreateTexture(); Mailbox name = Mailbox::Generate(); manager_->ProduceTexture(name, texture1); EXPECT_EQ(texture1, manager_->ConsumeTexture(name)); // Can produce a second time with the same mailbox, but different texture. manager_->ProduceTexture(name, texture2); EXPECT_EQ(texture2, manager_->ConsumeTexture(name)); // Destroying the texture that's under no mailbox shouldn't have an effect. DestroyTexture(texture1); EXPECT_EQ(texture2, manager_->ConsumeTexture(name)); // Destroying the texture that's bound should clean up. DestroyTexture(texture2); EXPECT_EQ(NULL, manager_->ConsumeTexture(name)); } TEST_F(MailboxManagerTest, ProduceMultipleTextureMailbox) { Texture* texture1 = CreateTexture(); Texture* texture2 = CreateTexture(); Mailbox name1 = Mailbox::Generate(); Mailbox name2 = Mailbox::Generate(); // Put texture1 on name1 and name2. manager_->ProduceTexture(name1, texture1); manager_->ProduceTexture(name2, texture1); EXPECT_EQ(texture1, manager_->ConsumeTexture(name1)); EXPECT_EQ(texture1, manager_->ConsumeTexture(name2)); // Put texture2 on name2. manager_->ProduceTexture(name2, texture2); EXPECT_EQ(texture1, manager_->ConsumeTexture(name1)); EXPECT_EQ(texture2, manager_->ConsumeTexture(name2)); // Destroy texture1, shouldn't affect name2. DestroyTexture(texture1); EXPECT_EQ(NULL, manager_->ConsumeTexture(name1)); EXPECT_EQ(texture2, manager_->ConsumeTexture(name2)); DestroyTexture(texture2); EXPECT_EQ(NULL, manager_->ConsumeTexture(name2)); } const GLsizei kMaxTextureWidth = 64; const GLsizei kMaxTextureHeight = 64; const GLsizei kMaxTextureDepth = 1; class MailboxManagerSyncTest : public MailboxManagerTest { public: MailboxManagerSyncTest() {} ~MailboxManagerSyncTest() override {} protected: void SetUp() override { MailboxManagerTest::SetUpWithSynchronizer(); manager2_ = new MailboxManagerSync(); context_ = new gfx::GLContextStub(); surface_ = new gfx::GLSurfaceStub(); context_->MakeCurrent(surface_.get()); } Texture* DefineTexture() { Texture* texture = CreateTexture(); const GLsizei levels_needed = TextureManager::ComputeMipMapCount( GL_TEXTURE_2D, kMaxTextureWidth, kMaxTextureHeight, kMaxTextureDepth); SetTarget(texture, GL_TEXTURE_2D, levels_needed); SetLevelInfo(texture, GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, gfx::Rect(1, 1)); SetParameter(texture, GL_TEXTURE_MIN_FILTER, GL_LINEAR); SetParameter(texture, GL_TEXTURE_MAG_FILTER, GL_LINEAR); return texture; } void SetupUpdateTexParamExpectations(GLuint texture_id, GLenum min, GLenum mag, GLenum wrap_s, GLenum wrap_t) { DCHECK(texture_id); const GLuint kCurrentTexture = 0; EXPECT_CALL(*gl_, GetIntegerv(GL_TEXTURE_BINDING_2D, _)) .WillOnce(SetArgPointee<1>(kCurrentTexture)) .RetiresOnSaturation(); EXPECT_CALL(*gl_, BindTexture(GL_TEXTURE_2D, texture_id)) .Times(1) .RetiresOnSaturation(); EXPECT_CALL(*gl_, TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, min)) .Times(1) .RetiresOnSaturation(); EXPECT_CALL(*gl_, TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag)) .Times(1) .RetiresOnSaturation(); EXPECT_CALL(*gl_, TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrap_s)) .Times(1) .RetiresOnSaturation(); EXPECT_CALL(*gl_, TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrap_t)) .Times(1) .RetiresOnSaturation(); EXPECT_CALL(*gl_, BindTexture(GL_TEXTURE_2D, kCurrentTexture)) .Times(1) .RetiresOnSaturation(); EXPECT_CALL(*gl_, Flush()) .Times(1) .RetiresOnSaturation(); } void TearDown() override { context_->ReleaseCurrent(NULL); MailboxManagerTest::TearDown(); } scoped_refptr manager2_; scoped_refptr context_; scoped_refptr surface_; private: DISALLOW_COPY_AND_ASSIGN(MailboxManagerSyncTest); }; TEST_F(MailboxManagerSyncTest, ProduceDestroy) { Texture* texture = DefineTexture(); Mailbox name = Mailbox::Generate(); InSequence sequence; manager_->ProduceTexture(name, texture); EXPECT_EQ(texture, manager_->ConsumeTexture(name)); DestroyTexture(texture); EXPECT_EQ(NULL, manager_->ConsumeTexture(name)); EXPECT_EQ(NULL, manager2_->ConsumeTexture(name)); } TEST_F(MailboxManagerSyncTest, ProduceSyncDestroy) { InSequence sequence; Texture* texture = DefineTexture(); Mailbox name = Mailbox::Generate(); manager_->ProduceTexture(name, texture); EXPECT_EQ(texture, manager_->ConsumeTexture(name)); // Synchronize manager_->PushTextureUpdates(0); manager2_->PullTextureUpdates(0); DestroyTexture(texture); EXPECT_EQ(NULL, manager_->ConsumeTexture(name)); EXPECT_EQ(NULL, manager2_->ConsumeTexture(name)); } TEST_F(MailboxManagerSyncTest, ProduceSyncClobberDestroy) { InSequence sequence; Texture* texture = DefineTexture(); Mailbox name = Mailbox::Generate(); manager_->ProduceTexture(name, texture); manager_->PushTextureUpdates(0); // Clobber Texture* old_texture = texture; texture = DefineTexture(); manager_->ProduceTexture(name, texture); DestroyTexture(old_texture); DestroyTexture(texture); EXPECT_EQ(NULL, manager_->ConsumeTexture(name)); EXPECT_EQ(NULL, manager2_->ConsumeTexture(name)); } // Duplicates a texture into a second manager instance, and then // makes sure a redefinition becomes visible there too. TEST_F(MailboxManagerSyncTest, ProduceConsumeResize) { const GLuint kNewTextureId = 1234; InSequence sequence; Texture* texture = DefineTexture(); Mailbox name = Mailbox::Generate(); manager_->ProduceTexture(name, texture); EXPECT_EQ(texture, manager_->ConsumeTexture(name)); // Synchronize manager_->PushTextureUpdates(0); manager2_->PullTextureUpdates(0); EXPECT_CALL(*gl_, GenTextures(1, _)) .WillOnce(SetArgPointee<1>(kNewTextureId)); SetupUpdateTexParamExpectations( kNewTextureId, GL_LINEAR, GL_LINEAR, GL_REPEAT, GL_REPEAT); Texture* new_texture = manager2_->ConsumeTexture(name); EXPECT_FALSE(new_texture == NULL); EXPECT_NE(texture, new_texture); EXPECT_EQ(kNewTextureId, new_texture->service_id()); // Resize original texture SetLevelInfo(texture, GL_TEXTURE_2D, 0, GL_RGBA, 16, 32, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, gfx::Rect(16, 32)); // Should have been orphaned EXPECT_TRUE(texture->GetLevelImage(GL_TEXTURE_2D, 0) == NULL); // Synchronize again manager_->PushTextureUpdates(0); SetupUpdateTexParamExpectations( kNewTextureId, GL_LINEAR, GL_LINEAR, GL_REPEAT, GL_REPEAT); manager2_->PullTextureUpdates(0); GLsizei width, height; new_texture->GetLevelSize(GL_TEXTURE_2D, 0, &width, &height, nullptr); EXPECT_EQ(16, width); EXPECT_EQ(32, height); // Should have gotten a new attachment EXPECT_TRUE(texture->GetLevelImage(GL_TEXTURE_2D, 0) != NULL); // Resize original texture again.... SetLevelInfo(texture, GL_TEXTURE_2D, 0, GL_RGBA, 64, 64, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, gfx::Rect(64, 64)); // ...and immediately delete the texture which should save the changes. SetupUpdateTexParamExpectations( kNewTextureId, GL_LINEAR, GL_LINEAR, GL_REPEAT, GL_REPEAT); DestroyTexture(texture); // Should be still around since there is a ref from manager2 EXPECT_EQ(new_texture, manager2_->ConsumeTexture(name)); // The last change to the texture should be visible without a sync point (i.e. // push). manager2_->PullTextureUpdates(0); new_texture->GetLevelSize(GL_TEXTURE_2D, 0, &width, &height, nullptr); EXPECT_EQ(64, width); EXPECT_EQ(64, height); DestroyTexture(new_texture); EXPECT_EQ(NULL, manager_->ConsumeTexture(name)); EXPECT_EQ(NULL, manager2_->ConsumeTexture(name)); } // Makes sure changes are correctly published even when updates are // pushed in both directions, i.e. makes sure we don't clobber a shared // texture definition with an older version. TEST_F(MailboxManagerSyncTest, ProduceConsumeBidirectional) { const GLuint kNewTextureId1 = 1234; const GLuint kNewTextureId2 = 4321; Texture* texture1 = DefineTexture(); Mailbox name1 = Mailbox::Generate(); Texture* texture2 = DefineTexture(); Mailbox name2 = Mailbox::Generate(); Texture* new_texture1 = NULL; Texture* new_texture2 = NULL; manager_->ProduceTexture(name1, texture1); manager2_->ProduceTexture(name2, texture2); // Make visible. manager_->PushTextureUpdates(0); manager2_->PushTextureUpdates(0); // Create textures in the other manager instances for texture1 and texture2, // respectively to create a real sharing scenario. Otherwise, there would // never be conflicting updates/pushes. { InSequence sequence; EXPECT_CALL(*gl_, GenTextures(1, _)) .WillOnce(SetArgPointee<1>(kNewTextureId1)); SetupUpdateTexParamExpectations( kNewTextureId1, GL_LINEAR, GL_LINEAR, GL_REPEAT, GL_REPEAT); new_texture1 = manager2_->ConsumeTexture(name1); EXPECT_CALL(*gl_, GenTextures(1, _)) .WillOnce(SetArgPointee<1>(kNewTextureId2)); SetupUpdateTexParamExpectations( kNewTextureId2, GL_LINEAR, GL_LINEAR, GL_REPEAT, GL_REPEAT); new_texture2 = manager_->ConsumeTexture(name2); } EXPECT_EQ(kNewTextureId1, new_texture1->service_id()); EXPECT_EQ(kNewTextureId2, new_texture2->service_id()); // Make a change to texture1 DCHECK_EQ(static_cast(GL_LINEAR), texture1->min_filter()); EXPECT_EQ(static_cast(GL_NO_ERROR), SetParameter(texture1, GL_TEXTURE_MIN_FILTER, GL_NEAREST)); // Make sure this does not clobber it with the previous version we pushed. manager_->PullTextureUpdates(0); // Make a change to texture2 DCHECK_EQ(static_cast(GL_LINEAR), texture2->mag_filter()); EXPECT_EQ(static_cast(GL_NO_ERROR), SetParameter(texture2, GL_TEXTURE_MAG_FILTER, GL_NEAREST)); Mock::VerifyAndClearExpectations(gl_.get()); // Synchronize in both directions manager_->PushTextureUpdates(0); manager2_->PushTextureUpdates(0); // manager1 should see the change to texture2 mag_filter being applied. SetupUpdateTexParamExpectations( new_texture2->service_id(), GL_LINEAR, GL_NEAREST, GL_REPEAT, GL_REPEAT); manager_->PullTextureUpdates(0); // manager2 should see the change to texture1 min_filter being applied. SetupUpdateTexParamExpectations( new_texture1->service_id(), GL_NEAREST, GL_LINEAR, GL_REPEAT, GL_REPEAT); manager2_->PullTextureUpdates(0); DestroyTexture(texture1); DestroyTexture(texture2); DestroyTexture(new_texture1); DestroyTexture(new_texture2); } // If a texture is shared with another manager instance, but the mailbox // is then clobbered with a different texture in the source context, this should // disconnect the earlier texture from updates. TEST_F(MailboxManagerSyncTest, ProduceAndClobber) { const GLuint kNewTextureId = 1234; InSequence sequence; Texture* texture = DefineTexture(); Mailbox name = Mailbox::Generate(); manager_->ProduceTexture(name, texture); EXPECT_EQ(texture, manager_->ConsumeTexture(name)); // Synchronize manager_->PushTextureUpdates(0); manager2_->PullTextureUpdates(0); EXPECT_CALL(*gl_, GenTextures(1, _)) .WillOnce(SetArgPointee<1>(kNewTextureId)); SetupUpdateTexParamExpectations( kNewTextureId, GL_LINEAR, GL_LINEAR, GL_REPEAT, GL_REPEAT); Texture* new_texture = manager2_->ConsumeTexture(name); EXPECT_FALSE(new_texture == NULL); EXPECT_NE(texture, new_texture); EXPECT_EQ(kNewTextureId, new_texture->service_id()); Texture* old_texture = texture; texture = DefineTexture(); manager_->ProduceTexture(name, texture); // Make a change to the new texture DCHECK_EQ(static_cast(GL_LINEAR), texture->min_filter()); EXPECT_EQ(static_cast(GL_NO_ERROR), SetParameter(texture, GL_TEXTURE_MIN_FILTER, GL_NEAREST)); // Synchronize in both directions - no changes, since it's not shared manager_->PushTextureUpdates(0); manager2_->PullTextureUpdates(0); EXPECT_EQ(static_cast(GL_LINEAR), new_texture->min_filter()); // Make a change to the previously shared texture DCHECK_EQ(static_cast(GL_LINEAR), old_texture->mag_filter()); EXPECT_EQ(static_cast(GL_NO_ERROR), SetParameter(old_texture, GL_TEXTURE_MAG_FILTER, GL_NEAREST)); // Synchronize and expect update manager_->PushTextureUpdates(0); SetupUpdateTexParamExpectations( new_texture->service_id(), GL_LINEAR, GL_NEAREST, GL_REPEAT, GL_REPEAT); manager2_->PullTextureUpdates(0); EXPECT_CALL(*gl_, GenTextures(1, _)) .WillOnce(SetArgPointee<1>(kNewTextureId)); SetupUpdateTexParamExpectations( kNewTextureId, GL_NEAREST, GL_LINEAR, GL_REPEAT, GL_REPEAT); Texture* tmp_texture = manager2_->ConsumeTexture(name); EXPECT_NE(new_texture, tmp_texture); DestroyTexture(tmp_texture); DestroyTexture(old_texture); DestroyTexture(texture); DestroyTexture(new_texture); EXPECT_EQ(NULL, manager_->ConsumeTexture(name)); EXPECT_EQ(NULL, manager2_->ConsumeTexture(name)); } TEST_F(MailboxManagerSyncTest, ClearedStateSynced) { const GLuint kNewTextureId = 1234; Texture* texture = DefineTexture(); EXPECT_TRUE(texture->SafeToRenderFrom()); Mailbox name = Mailbox::Generate(); manager_->ProduceTexture(name, texture); EXPECT_EQ(texture, manager_->ConsumeTexture(name)); // Synchronize manager_->PushTextureUpdates(0); manager2_->PullTextureUpdates(0); EXPECT_CALL(*gl_, GenTextures(1, _)) .WillOnce(SetArgPointee<1>(kNewTextureId)); SetupUpdateTexParamExpectations( kNewTextureId, GL_LINEAR, GL_LINEAR, GL_REPEAT, GL_REPEAT); Texture* new_texture = manager2_->ConsumeTexture(name); EXPECT_FALSE(new_texture == NULL); EXPECT_NE(texture, new_texture); EXPECT_EQ(kNewTextureId, new_texture->service_id()); EXPECT_TRUE(texture->SafeToRenderFrom()); // Change cleared to false. SetLevelCleared(texture, texture->target(), 0, false); EXPECT_FALSE(texture->SafeToRenderFrom()); // Synchronize manager_->PushTextureUpdates(0); SetupUpdateTexParamExpectations( kNewTextureId, GL_LINEAR, GL_LINEAR, GL_REPEAT, GL_REPEAT); manager2_->PullTextureUpdates(0); // Cleared state should be synced. EXPECT_FALSE(new_texture->SafeToRenderFrom()); DestroyTexture(texture); DestroyTexture(new_texture); EXPECT_EQ(NULL, manager_->ConsumeTexture(name)); EXPECT_EQ(NULL, manager2_->ConsumeTexture(name)); } TEST_F(MailboxManagerSyncTest, SyncIncompleteTexture) { const GLuint kNewTextureId = 1234; // Create but not define texture. Texture* texture = CreateTexture(); SetTarget(texture, GL_TEXTURE_2D, 1); EXPECT_FALSE(texture->IsDefined()); Mailbox name = Mailbox::Generate(); manager_->ProduceTexture(name, texture); EXPECT_EQ(texture, manager_->ConsumeTexture(name)); // Synchronize manager_->PushTextureUpdates(0); manager2_->PullTextureUpdates(0); // Should sync to new texture which is not defined. EXPECT_CALL(*gl_, GenTextures(1, _)) .WillOnce(SetArgPointee<1>(kNewTextureId)); SetupUpdateTexParamExpectations(kNewTextureId, texture->min_filter(), texture->mag_filter(), texture->wrap_s(), texture->wrap_t()); Texture* new_texture = manager2_->ConsumeTexture(name); ASSERT_TRUE(new_texture); EXPECT_NE(texture, new_texture); EXPECT_EQ(kNewTextureId, new_texture->service_id()); EXPECT_FALSE(new_texture->IsDefined()); // Change cleared to false. SetLevelInfo(texture, GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, gfx::Rect(1, 1)); SetParameter(texture, GL_TEXTURE_MIN_FILTER, GL_LINEAR); SetParameter(texture, GL_TEXTURE_MAG_FILTER, GL_LINEAR); EXPECT_TRUE(texture->IsDefined()); // Synchronize manager_->PushTextureUpdates(0); SetupUpdateTexParamExpectations( kNewTextureId, GL_LINEAR, GL_LINEAR, GL_REPEAT, GL_REPEAT); manager2_->PullTextureUpdates(0); // Cleared state should be synced. EXPECT_TRUE(new_texture->IsDefined()); DestroyTexture(texture); DestroyTexture(new_texture); EXPECT_EQ(NULL, manager_->ConsumeTexture(name)); EXPECT_EQ(NULL, manager2_->ConsumeTexture(name)); } // Putting the same texture into multiple mailboxes should result in sharing // only a single texture also within a synchronized manager instance. TEST_F(MailboxManagerSyncTest, SharedThroughMultipleMailboxes) { const GLuint kNewTextureId = 1234; InSequence sequence; Texture* texture = DefineTexture(); Mailbox name1 = Mailbox::Generate(); Mailbox name2 = Mailbox::Generate(); manager_->ProduceTexture(name1, texture); // Share manager_->PushTextureUpdates(0); EXPECT_CALL(*gl_, GenTextures(1, _)) .WillOnce(SetArgPointee<1>(kNewTextureId)); manager2_->PullTextureUpdates(0); SetupUpdateTexParamExpectations( kNewTextureId, GL_LINEAR, GL_LINEAR, GL_REPEAT, GL_REPEAT); Texture* new_texture = manager2_->ConsumeTexture(name1); EXPECT_EQ(kNewTextureId, new_texture->service_id()); manager_->ProduceTexture(name2, texture); // Synchronize manager_->PushTextureUpdates(0); manager2_->PullTextureUpdates(0); // name2 should return the same texture EXPECT_EQ(new_texture, manager2_->ConsumeTexture(name2)); // Even after destroying the source texture, the original mailbox should // still exist. DestroyTexture(texture); EXPECT_EQ(new_texture, manager2_->ConsumeTexture(name1)); DestroyTexture(new_texture); } // A: produce texture1 into M, B: consume into new_texture // B: produce texture2 into M, A: produce texture1 into M // B: consume M should return new_texture TEST_F(MailboxManagerSyncTest, ProduceBothWays) { const GLuint kNewTextureId = 1234; InSequence sequence; Texture* texture1 = DefineTexture(); Texture* texture2 = DefineTexture(); Mailbox name = Mailbox::Generate(); manager_->ProduceTexture(name, texture1); // Share manager_->PushTextureUpdates(0); EXPECT_CALL(*gl_, GenTextures(1, _)) .WillOnce(SetArgPointee<1>(kNewTextureId)); SetupUpdateTexParamExpectations( kNewTextureId, GL_LINEAR, GL_LINEAR, GL_REPEAT, GL_REPEAT); Texture* new_texture = manager2_->ConsumeTexture(name); EXPECT_EQ(kNewTextureId, new_texture->service_id()); // Clobber manager2_->ProduceTexture(name, texture2); manager_->ProduceTexture(name, texture1); // Synchronize manager -> manager2 manager_->PushTextureUpdates(0); manager2_->PullTextureUpdates(0); // name should return the original texture, and not texture2 or a new one. EXPECT_EQ(new_texture, manager2_->ConsumeTexture(name)); DestroyTexture(texture1); DestroyTexture(texture2); DestroyTexture(new_texture); } // TODO: Texture::level_infos_[][].size() // TODO: unsupported targets and formats } // namespace gles2 } // namespace gpu