Home | History | Annotate | Download | only in service
      1 // Copyright 2013 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "gpu/command_buffer/service/mailbox_manager.h"
      6 
      7 #include "gpu/command_buffer/service/feature_info.h"
      8 #include "gpu/command_buffer/service/mailbox_synchronizer.h"
      9 #include "gpu/command_buffer/service/texture_manager.h"
     10 #include "testing/gtest/include/gtest/gtest.h"
     11 #include "ui/gl/gl_mock.h"
     12 
     13 namespace gpu {
     14 namespace gles2 {
     15 
     16 using namespace ::testing;
     17 
     18 class MailboxManagerTest : public testing::Test {
     19  public:
     20   MailboxManagerTest() {}
     21   virtual ~MailboxManagerTest() {}
     22 
     23  protected:
     24   virtual void SetUp() {
     25     testing::Test::SetUp();
     26     feature_info_ = new FeatureInfo;
     27     manager_ = new MailboxManager;
     28   }
     29 
     30   Texture* CreateTexture() {
     31     return new Texture(1);
     32   }
     33 
     34   void SetTarget(Texture* texture, GLenum target, GLuint max_level) {
     35     texture->SetTarget(NULL, target, max_level);
     36   }
     37 
     38   void SetLevelInfo(
     39       Texture* texture,
     40       GLenum target,
     41       GLint level,
     42       GLenum internal_format,
     43       GLsizei width,
     44       GLsizei height,
     45       GLsizei depth,
     46       GLint border,
     47       GLenum format,
     48       GLenum type,
     49       bool cleared) {
     50     texture->SetLevelInfo(NULL,
     51                           target,
     52                           level,
     53                           internal_format,
     54                           width,
     55                           height,
     56                           depth,
     57                           border,
     58                           format,
     59                           type,
     60                           cleared);
     61   }
     62 
     63   GLenum SetParameter(Texture* texture, GLenum pname, GLint param) {
     64     return texture->SetParameteri(feature_info_, pname, param);
     65   }
     66 
     67   void DestroyTexture(Texture* texture) {
     68     delete texture;
     69   }
     70 
     71   scoped_refptr<MailboxManager> manager_;
     72 
     73  private:
     74   scoped_refptr<FeatureInfo> feature_info_;
     75 
     76   DISALLOW_COPY_AND_ASSIGN(MailboxManagerTest);
     77 };
     78 
     79 // Tests basic produce/consume behavior.
     80 TEST_F(MailboxManagerTest, Basic) {
     81   Texture* texture = CreateTexture();
     82 
     83   Mailbox name;
     84   manager_->GenerateMailbox(&name);
     85   manager_->ProduceTexture(0, name, texture);
     86   EXPECT_EQ(texture, manager_->ConsumeTexture(0, name));
     87 
     88   // We can consume multiple times.
     89   EXPECT_EQ(texture, manager_->ConsumeTexture(0, name));
     90 
     91   // Wrong target should fail the consume.
     92   EXPECT_EQ(NULL, manager_->ConsumeTexture(1, name));
     93 
     94   // Destroy should cleanup the mailbox.
     95   DestroyTexture(texture);
     96   EXPECT_EQ(NULL, manager_->ConsumeTexture(0, name));
     97 }
     98 
     99 // Tests behavior with multiple produce on the same texture.
    100 TEST_F(MailboxManagerTest, ProduceMultipleMailbox) {
    101   Texture* texture = CreateTexture();
    102 
    103   Mailbox name1;
    104   manager_->GenerateMailbox(&name1);
    105 
    106   manager_->ProduceTexture(0, name1, texture);
    107   EXPECT_EQ(texture, manager_->ConsumeTexture(0, name1));
    108 
    109   // Can produce a second time with the same mailbox.
    110   manager_->ProduceTexture(0, name1, texture);
    111   EXPECT_EQ(texture, manager_->ConsumeTexture(0, name1));
    112 
    113   // Can produce again, with a different mailbox.
    114   Mailbox name2;
    115   manager_->GenerateMailbox(&name2);
    116   manager_->ProduceTexture(0, name2, texture);
    117 
    118   // Still available under all mailboxes.
    119   EXPECT_EQ(texture, manager_->ConsumeTexture(0, name1));
    120   EXPECT_EQ(texture, manager_->ConsumeTexture(0, name2));
    121 
    122   // Destroy should cleanup all mailboxes.
    123   DestroyTexture(texture);
    124   EXPECT_EQ(NULL, manager_->ConsumeTexture(0, name1));
    125   EXPECT_EQ(NULL, manager_->ConsumeTexture(0, name2));
    126 }
    127 
    128 // Tests behavior with multiple produce on the same mailbox with different
    129 // textures.
    130 TEST_F(MailboxManagerTest, ProduceMultipleTexture) {
    131   Texture* texture1 = CreateTexture();
    132   Texture* texture2 = CreateTexture();
    133 
    134   Mailbox name;
    135   manager_->GenerateMailbox(&name);
    136 
    137   manager_->ProduceTexture(0, name, texture1);
    138   EXPECT_EQ(texture1, manager_->ConsumeTexture(0, name));
    139 
    140   // Can produce a second time with the same mailbox, but different texture.
    141   manager_->ProduceTexture(0, name, texture2);
    142   EXPECT_EQ(texture2, manager_->ConsumeTexture(0, name));
    143 
    144   // Destroying the texture that's under no mailbox shouldn't have an effect.
    145   DestroyTexture(texture1);
    146   EXPECT_EQ(texture2, manager_->ConsumeTexture(0, name));
    147 
    148   // Destroying the texture that's bound should clean up.
    149   DestroyTexture(texture2);
    150   EXPECT_EQ(NULL, manager_->ConsumeTexture(0, name));
    151 }
    152 
    153 TEST_F(MailboxManagerTest, ProduceMultipleTextureMailbox) {
    154   Texture* texture1 = CreateTexture();
    155   Texture* texture2 = CreateTexture();
    156   Mailbox name1;
    157   manager_->GenerateMailbox(&name1);
    158   Mailbox name2;
    159   manager_->GenerateMailbox(&name2);
    160 
    161   // Put texture1 on name1 and name2.
    162   manager_->ProduceTexture(0, name1, texture1);
    163   manager_->ProduceTexture(0, name2, texture1);
    164   EXPECT_EQ(texture1, manager_->ConsumeTexture(0, name1));
    165   EXPECT_EQ(texture1, manager_->ConsumeTexture(0, name2));
    166 
    167   // Put texture2 on name2.
    168   manager_->ProduceTexture(0, name2, texture2);
    169   EXPECT_EQ(texture1, manager_->ConsumeTexture(0, name1));
    170   EXPECT_EQ(texture2, manager_->ConsumeTexture(0, name2));
    171 
    172   // Destroy texture1, shouldn't affect name2.
    173   DestroyTexture(texture1);
    174   EXPECT_EQ(NULL, manager_->ConsumeTexture(0, name1));
    175   EXPECT_EQ(texture2, manager_->ConsumeTexture(0, name2));
    176 
    177   DestroyTexture(texture2);
    178   EXPECT_EQ(NULL, manager_->ConsumeTexture(0, name2));
    179 }
    180 
    181 const GLsizei kMaxTextureWidth = 64;
    182 const GLsizei kMaxTextureHeight = 64;
    183 const GLsizei kMaxTextureDepth = 1;
    184 
    185 class MailboxManagerSyncTest : public MailboxManagerTest {
    186  public:
    187   MailboxManagerSyncTest() {}
    188   virtual ~MailboxManagerSyncTest() {}
    189 
    190  protected:
    191   virtual void SetUp() {
    192     MailboxSynchronizer::Initialize();
    193     MailboxManagerTest::SetUp();
    194     manager2_ = new MailboxManager;
    195     gl_.reset(new ::testing::StrictMock< ::gfx::MockGLInterface>());
    196     ::gfx::MockGLInterface::SetGLInterface(gl_.get());
    197   }
    198 
    199   Texture* DefineTexture() {
    200     Texture* texture = CreateTexture();
    201     const GLsizei levels_needed = TextureManager::ComputeMipMapCount(
    202         GL_TEXTURE_2D, kMaxTextureWidth, kMaxTextureHeight, kMaxTextureDepth);
    203     SetTarget(texture, GL_TEXTURE_2D, levels_needed);
    204     SetLevelInfo(texture,
    205                  GL_TEXTURE_2D,
    206                  0,
    207                  GL_RGBA,
    208                  1,
    209                  1,
    210                  1,
    211                  0,
    212                  GL_RGBA,
    213                  GL_UNSIGNED_BYTE,
    214                  true);
    215     SetParameter(texture, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    216     SetParameter(texture, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    217     return texture;
    218   }
    219 
    220   void SetupUpdateTexParamExpectations(GLuint texture_id,
    221                                        GLenum min,
    222                                        GLenum mag,
    223                                        GLenum wrap_s,
    224                                        GLenum wrap_t) {
    225     DCHECK(texture_id);
    226     const GLuint kCurrentTexture = 0;
    227     EXPECT_CALL(*gl_, GetIntegerv(GL_TEXTURE_BINDING_2D, _))
    228         .WillOnce(SetArgPointee<1>(kCurrentTexture))
    229         .RetiresOnSaturation();
    230     EXPECT_CALL(*gl_, BindTexture(GL_TEXTURE_2D, texture_id))
    231         .Times(1)
    232         .RetiresOnSaturation();
    233     EXPECT_CALL(*gl_,
    234                 TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, min))
    235         .Times(1)
    236         .RetiresOnSaturation();
    237     EXPECT_CALL(*gl_,
    238                 TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag))
    239         .Times(1)
    240         .RetiresOnSaturation();
    241     EXPECT_CALL(*gl_, TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrap_s))
    242         .Times(1)
    243         .RetiresOnSaturation();
    244     EXPECT_CALL(*gl_, TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrap_t))
    245         .Times(1)
    246         .RetiresOnSaturation();
    247     EXPECT_CALL(*gl_, Flush())
    248         .Times(1)
    249         .RetiresOnSaturation();
    250     EXPECT_CALL(*gl_, BindTexture(GL_TEXTURE_2D, kCurrentTexture))
    251         .Times(1)
    252         .RetiresOnSaturation();
    253   }
    254 
    255   virtual void TearDown() {
    256     MailboxManagerTest::TearDown();
    257     MailboxSynchronizer::Terminate();
    258     ::gfx::MockGLInterface::SetGLInterface(NULL);
    259     gl_.reset();
    260   }
    261 
    262   scoped_ptr< ::testing::StrictMock< ::gfx::MockGLInterface> > gl_;
    263   scoped_refptr<MailboxManager> manager2_;
    264 
    265  private:
    266   DISALLOW_COPY_AND_ASSIGN(MailboxManagerSyncTest);
    267 };
    268 
    269 TEST_F(MailboxManagerSyncTest, ProduceDestroy) {
    270   Texture* texture = DefineTexture();
    271   Mailbox name = Mailbox::Generate();
    272 
    273   InSequence sequence;
    274   manager_->ProduceTexture(GL_TEXTURE_2D, name, texture);
    275   EXPECT_EQ(texture, manager_->ConsumeTexture(GL_TEXTURE_2D, name));
    276 
    277   DestroyTexture(texture);
    278   EXPECT_EQ(NULL, manager_->ConsumeTexture(GL_TEXTURE_2D, name));
    279   EXPECT_EQ(NULL, manager2_->ConsumeTexture(GL_TEXTURE_2D, name));
    280 }
    281 
    282 TEST_F(MailboxManagerSyncTest, ProduceSyncDestroy) {
    283   InSequence sequence;
    284 
    285   Texture* texture = DefineTexture();
    286   Mailbox name = Mailbox::Generate();
    287 
    288   manager_->ProduceTexture(GL_TEXTURE_2D, name, texture);
    289   EXPECT_EQ(texture, manager_->ConsumeTexture(GL_TEXTURE_2D, name));
    290 
    291   // Synchronize
    292   EXPECT_CALL(*gl_, Flush()).Times(1);
    293   manager_->PushTextureUpdates();
    294   manager2_->PullTextureUpdates();
    295 
    296   DestroyTexture(texture);
    297   EXPECT_EQ(NULL, manager_->ConsumeTexture(GL_TEXTURE_2D, name));
    298   EXPECT_EQ(NULL, manager2_->ConsumeTexture(GL_TEXTURE_2D, name));
    299 }
    300 
    301 // Duplicates a texture into a second manager instance, and then
    302 // makes sure a redefinition becomes visible there too.
    303 TEST_F(MailboxManagerSyncTest, ProduceConsumeResize) {
    304   const GLuint kNewTextureId = 1234;
    305   InSequence sequence;
    306 
    307   Texture* texture = DefineTexture();
    308   Mailbox name = Mailbox::Generate();
    309 
    310   manager_->ProduceTexture(GL_TEXTURE_2D, name, texture);
    311   EXPECT_EQ(texture, manager_->ConsumeTexture(GL_TEXTURE_2D, name));
    312 
    313   // Synchronize
    314   EXPECT_CALL(*gl_, Flush()).Times(1);
    315   manager_->PushTextureUpdates();
    316   manager2_->PullTextureUpdates();
    317 
    318   EXPECT_CALL(*gl_, GenTextures(1, _))
    319       .WillOnce(SetArgPointee<1>(kNewTextureId));
    320   SetupUpdateTexParamExpectations(
    321       kNewTextureId, GL_LINEAR, GL_LINEAR, GL_REPEAT, GL_REPEAT);
    322   Texture* new_texture = manager2_->ConsumeTexture(GL_TEXTURE_2D, name);
    323   EXPECT_FALSE(new_texture == NULL);
    324   EXPECT_NE(texture, new_texture);
    325   EXPECT_EQ(kNewTextureId, new_texture->service_id());
    326 
    327   // Resize original texture
    328   SetLevelInfo(texture,
    329                GL_TEXTURE_2D,
    330                0,
    331                GL_RGBA,
    332                16,
    333                32,
    334                1,
    335                0,
    336                GL_RGBA,
    337                GL_UNSIGNED_BYTE,
    338                true);
    339   // Should have been orphaned
    340   EXPECT_TRUE(texture->GetLevelImage(GL_TEXTURE_2D, 0) == NULL);
    341 
    342   // Synchronize again
    343   EXPECT_CALL(*gl_, Flush()).Times(1);
    344   manager_->PushTextureUpdates();
    345   SetupUpdateTexParamExpectations(
    346       kNewTextureId, GL_LINEAR, GL_LINEAR, GL_REPEAT, GL_REPEAT);
    347   manager2_->PullTextureUpdates();
    348   GLsizei width, height;
    349   new_texture->GetLevelSize(GL_TEXTURE_2D, 0, &width, &height);
    350   EXPECT_EQ(16, width);
    351   EXPECT_EQ(32, height);
    352 
    353   // Should have gotten a new attachment
    354   EXPECT_TRUE(texture->GetLevelImage(GL_TEXTURE_2D, 0) != NULL);
    355   // Resize original texture again....
    356   SetLevelInfo(texture,
    357                GL_TEXTURE_2D,
    358                0,
    359                GL_RGBA,
    360                64,
    361                64,
    362                1,
    363                0,
    364                GL_RGBA,
    365                GL_UNSIGNED_BYTE,
    366                true);
    367   // ...and immediately delete the texture which should save the changes.
    368   SetupUpdateTexParamExpectations(
    369       kNewTextureId, GL_LINEAR, GL_LINEAR, GL_REPEAT, GL_REPEAT);
    370   DestroyTexture(texture);
    371 
    372   // Should be still around since there is a ref from manager2
    373   EXPECT_EQ(new_texture, manager2_->ConsumeTexture(GL_TEXTURE_2D, name));
    374 
    375   // The last change to the texture should be visible without a sync point (i.e.
    376   // push).
    377   manager2_->PullTextureUpdates();
    378   new_texture->GetLevelSize(GL_TEXTURE_2D, 0, &width, &height);
    379   EXPECT_EQ(64, width);
    380   EXPECT_EQ(64, height);
    381 
    382   DestroyTexture(new_texture);
    383   EXPECT_EQ(NULL, manager_->ConsumeTexture(GL_TEXTURE_2D, name));
    384   EXPECT_EQ(NULL, manager2_->ConsumeTexture(GL_TEXTURE_2D, name));
    385 }
    386 
    387 // Makes sure changes are correctly published even when updates are
    388 // pushed in both directions, i.e. makes sure we don't clobber a shared
    389 // texture definition with an older version.
    390 TEST_F(MailboxManagerSyncTest, ProduceConsumeBidirectional) {
    391   const GLuint kNewTextureId1 = 1234;
    392   const GLuint kNewTextureId2 = 4321;
    393 
    394   Texture* texture1 = DefineTexture();
    395   Mailbox name1 = Mailbox::Generate();
    396   Texture* texture2 = DefineTexture();
    397   Mailbox name2 = Mailbox::Generate();
    398   Texture* new_texture1 = NULL;
    399   Texture* new_texture2 = NULL;
    400 
    401   manager_->ProduceTexture(GL_TEXTURE_2D, name1, texture1);
    402   manager2_->ProduceTexture(GL_TEXTURE_2D, name2, texture2);
    403 
    404   // Make visible.
    405   EXPECT_CALL(*gl_, Flush()).Times(2);
    406   manager_->PushTextureUpdates();
    407   manager2_->PushTextureUpdates();
    408 
    409   // Create textures in the other manager instances for texture1 and texture2,
    410   // respectively to create a real sharing scenario. Otherwise, there would
    411   // never be conflicting updates/pushes.
    412   {
    413     InSequence sequence;
    414     EXPECT_CALL(*gl_, GenTextures(1, _))
    415         .WillOnce(SetArgPointee<1>(kNewTextureId1));
    416     SetupUpdateTexParamExpectations(
    417         kNewTextureId1, GL_LINEAR, GL_LINEAR, GL_REPEAT, GL_REPEAT);
    418     new_texture1 = manager2_->ConsumeTexture(GL_TEXTURE_2D, name1);
    419     EXPECT_CALL(*gl_, GenTextures(1, _))
    420         .WillOnce(SetArgPointee<1>(kNewTextureId2));
    421     SetupUpdateTexParamExpectations(
    422         kNewTextureId2, GL_LINEAR, GL_LINEAR, GL_REPEAT, GL_REPEAT);
    423     new_texture2 = manager_->ConsumeTexture(GL_TEXTURE_2D, name2);
    424   }
    425   EXPECT_EQ(kNewTextureId1, new_texture1->service_id());
    426   EXPECT_EQ(kNewTextureId2, new_texture2->service_id());
    427 
    428   // Make a change to texture1
    429   DCHECK_EQ(static_cast<GLuint>(GL_LINEAR), texture1->min_filter());
    430   EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR),
    431             SetParameter(texture1, GL_TEXTURE_MIN_FILTER, GL_NEAREST));
    432 
    433   // Make sure this does not clobber it with the previous version we pushed.
    434   manager_->PullTextureUpdates();
    435 
    436   // Make a change to texture2
    437   DCHECK_EQ(static_cast<GLuint>(GL_LINEAR), texture2->mag_filter());
    438   EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR),
    439             SetParameter(texture2, GL_TEXTURE_MAG_FILTER, GL_NEAREST));
    440 
    441   Mock::VerifyAndClearExpectations(gl_.get());
    442 
    443   // Synchronize in both directions
    444   EXPECT_CALL(*gl_, Flush()).Times(2);
    445   manager_->PushTextureUpdates();
    446   manager2_->PushTextureUpdates();
    447   // manager1 should see the change to texture2 mag_filter being applied.
    448   SetupUpdateTexParamExpectations(
    449       new_texture2->service_id(), GL_LINEAR, GL_NEAREST, GL_REPEAT, GL_REPEAT);
    450   manager_->PullTextureUpdates();
    451   // manager2 should see the change to texture1 min_filter being applied.
    452   SetupUpdateTexParamExpectations(
    453       new_texture1->service_id(), GL_NEAREST, GL_LINEAR, GL_REPEAT, GL_REPEAT);
    454   manager2_->PullTextureUpdates();
    455 
    456   DestroyTexture(texture1);
    457   DestroyTexture(texture2);
    458   DestroyTexture(new_texture1);
    459   DestroyTexture(new_texture2);
    460 }
    461 
    462 // TODO: different texture into same mailbox
    463 
    464 // TODO: same texture, multiple mailboxes
    465 
    466 // TODO: Produce incomplete texture
    467 
    468 // TODO: Texture::level_infos_[][].size()
    469 
    470 // TODO: unsupported targets and formats
    471 
    472 }  // namespace gles2
    473 }  // namespace gpu
    474