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