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