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.
5 #include "gpu/command_buffer/service/feature_info.h"
6 #include "gpu/command_buffer/service/gpu_service_test.h"
7 #include "gpu/command_buffer/service/mailbox_manager_impl.h"
8 #include "gpu/command_buffer/service/mailbox_manager_sync.h"
9 #include "gpu/command_buffer/service/texture_manager.h"
10 #include "testing/gtest/include/gtest/gtest.h"
11 #include "ui/gl/gl_context_stub.h"
12 #include "ui/gl/gl_mock.h"
13 #include "ui/gl/gl_surface_stub.h"
18 using namespace ::testing;
20 class MailboxManagerTest : public GpuServiceTest {
22 MailboxManagerTest() {}
23 ~MailboxManagerTest() override {}
26 void SetUp() override {
27 GpuServiceTest::SetUp();
28 feature_info_ = new FeatureInfo;
29 manager_ = new MailboxManagerImpl;
30 DCHECK(!manager_->UsesSync());
33 virtual void SetUpWithSynchronizer() {
34 GpuServiceTest::SetUp();
35 feature_info_ = new FeatureInfo;
36 manager_ = new MailboxManagerSync();
37 DCHECK(manager_->UsesSync());
40 void TearDown() override { GpuServiceTest::TearDown(); }
42 Texture* CreateTexture() {
43 return new Texture(1);
46 void SetTarget(Texture* texture, GLenum target, GLuint max_level) {
47 texture->SetTarget(NULL, target, max_level);
54 GLenum internal_format,
62 texture->SetLevelInfo(NULL,
75 GLenum SetParameter(Texture* texture, GLenum pname, GLint param) {
76 return texture->SetParameteri(feature_info_.get(), pname, param);
79 void DestroyTexture(Texture* texture) {
83 scoped_refptr<MailboxManager> manager_;
86 scoped_refptr<FeatureInfo> feature_info_;
88 DISALLOW_COPY_AND_ASSIGN(MailboxManagerTest);
91 // Tests basic produce/consume behavior.
92 TEST_F(MailboxManagerTest, Basic) {
93 Texture* texture = CreateTexture();
95 Mailbox name = Mailbox::Generate();
96 manager_->ProduceTexture(name, texture);
97 EXPECT_EQ(texture, manager_->ConsumeTexture(name));
99 // We can consume multiple times.
100 EXPECT_EQ(texture, manager_->ConsumeTexture(name));
102 // Destroy should cleanup the mailbox.
103 DestroyTexture(texture);
104 EXPECT_EQ(NULL, manager_->ConsumeTexture(name));
107 // Tests behavior with multiple produce on the same texture.
108 TEST_F(MailboxManagerTest, ProduceMultipleMailbox) {
109 Texture* texture = CreateTexture();
111 Mailbox name1 = Mailbox::Generate();
113 manager_->ProduceTexture(name1, texture);
114 EXPECT_EQ(texture, manager_->ConsumeTexture(name1));
116 // Can produce a second time with the same mailbox.
117 manager_->ProduceTexture(name1, texture);
118 EXPECT_EQ(texture, manager_->ConsumeTexture(name1));
120 // Can produce again, with a different mailbox.
121 Mailbox name2 = Mailbox::Generate();
122 manager_->ProduceTexture(name2, texture);
124 // Still available under all mailboxes.
125 EXPECT_EQ(texture, manager_->ConsumeTexture(name1));
126 EXPECT_EQ(texture, manager_->ConsumeTexture(name2));
128 // Destroy should cleanup all mailboxes.
129 DestroyTexture(texture);
130 EXPECT_EQ(NULL, manager_->ConsumeTexture(name1));
131 EXPECT_EQ(NULL, manager_->ConsumeTexture(name2));
134 // Tests behavior with multiple produce on the same mailbox with different
136 TEST_F(MailboxManagerTest, ProduceMultipleTexture) {
137 Texture* texture1 = CreateTexture();
138 Texture* texture2 = CreateTexture();
140 Mailbox name = Mailbox::Generate();
142 manager_->ProduceTexture(name, texture1);
143 EXPECT_EQ(texture1, manager_->ConsumeTexture(name));
145 // Can produce a second time with the same mailbox, but different texture.
146 manager_->ProduceTexture(name, texture2);
147 EXPECT_EQ(texture2, manager_->ConsumeTexture(name));
149 // Destroying the texture that's under no mailbox shouldn't have an effect.
150 DestroyTexture(texture1);
151 EXPECT_EQ(texture2, manager_->ConsumeTexture(name));
153 // Destroying the texture that's bound should clean up.
154 DestroyTexture(texture2);
155 EXPECT_EQ(NULL, manager_->ConsumeTexture(name));
158 TEST_F(MailboxManagerTest, ProduceMultipleTextureMailbox) {
159 Texture* texture1 = CreateTexture();
160 Texture* texture2 = CreateTexture();
161 Mailbox name1 = Mailbox::Generate();
162 Mailbox name2 = Mailbox::Generate();
164 // Put texture1 on name1 and name2.
165 manager_->ProduceTexture(name1, texture1);
166 manager_->ProduceTexture(name2, texture1);
167 EXPECT_EQ(texture1, manager_->ConsumeTexture(name1));
168 EXPECT_EQ(texture1, manager_->ConsumeTexture(name2));
170 // Put texture2 on name2.
171 manager_->ProduceTexture(name2, texture2);
172 EXPECT_EQ(texture1, manager_->ConsumeTexture(name1));
173 EXPECT_EQ(texture2, manager_->ConsumeTexture(name2));
175 // Destroy texture1, shouldn't affect name2.
176 DestroyTexture(texture1);
177 EXPECT_EQ(NULL, manager_->ConsumeTexture(name1));
178 EXPECT_EQ(texture2, manager_->ConsumeTexture(name2));
180 DestroyTexture(texture2);
181 EXPECT_EQ(NULL, manager_->ConsumeTexture(name2));
184 const GLsizei kMaxTextureWidth = 64;
185 const GLsizei kMaxTextureHeight = 64;
186 const GLsizei kMaxTextureDepth = 1;
188 class MailboxManagerSyncTest : public MailboxManagerTest {
190 MailboxManagerSyncTest() {}
191 ~MailboxManagerSyncTest() override {}
194 void SetUp() override {
195 MailboxManagerTest::SetUpWithSynchronizer();
196 manager2_ = new MailboxManagerSync();
197 context_ = new gfx::GLContextStub();
198 surface_ = new gfx::GLSurfaceStub();
199 context_->MakeCurrent(surface_.get());
202 Texture* DefineTexture() {
203 Texture* texture = CreateTexture();
204 const GLsizei levels_needed = TextureManager::ComputeMipMapCount(
205 GL_TEXTURE_2D, kMaxTextureWidth, kMaxTextureHeight, kMaxTextureDepth);
206 SetTarget(texture, GL_TEXTURE_2D, levels_needed);
207 SetLevelInfo(texture,
218 SetParameter(texture, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
219 SetParameter(texture, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
223 void SetupUpdateTexParamExpectations(GLuint texture_id,
229 const GLuint kCurrentTexture = 0;
230 EXPECT_CALL(*gl_, GetIntegerv(GL_TEXTURE_BINDING_2D, _))
231 .WillOnce(SetArgPointee<1>(kCurrentTexture))
232 .RetiresOnSaturation();
233 EXPECT_CALL(*gl_, BindTexture(GL_TEXTURE_2D, texture_id))
235 .RetiresOnSaturation();
237 TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, min))
239 .RetiresOnSaturation();
241 TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag))
243 .RetiresOnSaturation();
244 EXPECT_CALL(*gl_, TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrap_s))
246 .RetiresOnSaturation();
247 EXPECT_CALL(*gl_, TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrap_t))
249 .RetiresOnSaturation();
250 EXPECT_CALL(*gl_, Flush())
252 .RetiresOnSaturation();
253 EXPECT_CALL(*gl_, BindTexture(GL_TEXTURE_2D, kCurrentTexture))
255 .RetiresOnSaturation();
258 void TearDown() override {
259 context_->ReleaseCurrent(NULL);
260 MailboxManagerTest::TearDown();
263 scoped_refptr<MailboxManager> manager2_;
264 scoped_refptr<gfx::GLContext> context_;
265 scoped_refptr<gfx::GLSurface> surface_;
268 DISALLOW_COPY_AND_ASSIGN(MailboxManagerSyncTest);
271 TEST_F(MailboxManagerSyncTest, ProduceDestroy) {
272 Texture* texture = DefineTexture();
273 Mailbox name = Mailbox::Generate();
276 manager_->ProduceTexture(name, texture);
277 EXPECT_EQ(texture, manager_->ConsumeTexture(name));
279 DestroyTexture(texture);
280 EXPECT_EQ(NULL, manager_->ConsumeTexture(name));
281 EXPECT_EQ(NULL, manager2_->ConsumeTexture(name));
284 TEST_F(MailboxManagerSyncTest, ProduceSyncDestroy) {
287 Texture* texture = DefineTexture();
288 Mailbox name = Mailbox::Generate();
290 manager_->ProduceTexture(name, texture);
291 EXPECT_EQ(texture, manager_->ConsumeTexture(name));
294 manager_->PushTextureUpdates(0);
295 manager2_->PullTextureUpdates(0);
297 DestroyTexture(texture);
298 EXPECT_EQ(NULL, manager_->ConsumeTexture(name));
299 EXPECT_EQ(NULL, manager2_->ConsumeTexture(name));
302 TEST_F(MailboxManagerSyncTest, ProduceSyncClobberDestroy) {
305 Texture* texture = DefineTexture();
306 Mailbox name = Mailbox::Generate();
308 manager_->ProduceTexture(name, texture);
309 manager_->PushTextureUpdates(0);
312 Texture* old_texture = texture;
313 texture = DefineTexture();
314 manager_->ProduceTexture(name, texture);
316 DestroyTexture(old_texture);
317 DestroyTexture(texture);
318 EXPECT_EQ(NULL, manager_->ConsumeTexture(name));
319 EXPECT_EQ(NULL, manager2_->ConsumeTexture(name));
322 // Duplicates a texture into a second manager instance, and then
323 // makes sure a redefinition becomes visible there too.
324 TEST_F(MailboxManagerSyncTest, ProduceConsumeResize) {
325 const GLuint kNewTextureId = 1234;
328 Texture* texture = DefineTexture();
329 Mailbox name = Mailbox::Generate();
331 manager_->ProduceTexture(name, texture);
332 EXPECT_EQ(texture, manager_->ConsumeTexture(name));
335 manager_->PushTextureUpdates(0);
336 manager2_->PullTextureUpdates(0);
338 EXPECT_CALL(*gl_, GenTextures(1, _))
339 .WillOnce(SetArgPointee<1>(kNewTextureId));
340 SetupUpdateTexParamExpectations(
341 kNewTextureId, GL_LINEAR, GL_LINEAR, GL_REPEAT, GL_REPEAT);
342 Texture* new_texture = manager2_->ConsumeTexture(name);
343 EXPECT_FALSE(new_texture == NULL);
344 EXPECT_NE(texture, new_texture);
345 EXPECT_EQ(kNewTextureId, new_texture->service_id());
347 // Resize original texture
348 SetLevelInfo(texture,
359 // Should have been orphaned
360 EXPECT_TRUE(texture->GetLevelImage(GL_TEXTURE_2D, 0) == NULL);
363 manager_->PushTextureUpdates(0);
364 SetupUpdateTexParamExpectations(
365 kNewTextureId, GL_LINEAR, GL_LINEAR, GL_REPEAT, GL_REPEAT);
366 manager2_->PullTextureUpdates(0);
367 GLsizei width, height;
368 new_texture->GetLevelSize(GL_TEXTURE_2D, 0, &width, &height);
369 EXPECT_EQ(16, width);
370 EXPECT_EQ(32, height);
372 // Should have gotten a new attachment
373 EXPECT_TRUE(texture->GetLevelImage(GL_TEXTURE_2D, 0) != NULL);
374 // Resize original texture again....
375 SetLevelInfo(texture,
386 // ...and immediately delete the texture which should save the changes.
387 SetupUpdateTexParamExpectations(
388 kNewTextureId, GL_LINEAR, GL_LINEAR, GL_REPEAT, GL_REPEAT);
389 DestroyTexture(texture);
391 // Should be still around since there is a ref from manager2
392 EXPECT_EQ(new_texture, manager2_->ConsumeTexture(name));
394 // The last change to the texture should be visible without a sync point (i.e.
396 manager2_->PullTextureUpdates(0);
397 new_texture->GetLevelSize(GL_TEXTURE_2D, 0, &width, &height);
398 EXPECT_EQ(64, width);
399 EXPECT_EQ(64, height);
401 DestroyTexture(new_texture);
402 EXPECT_EQ(NULL, manager_->ConsumeTexture(name));
403 EXPECT_EQ(NULL, manager2_->ConsumeTexture(name));
406 // Makes sure changes are correctly published even when updates are
407 // pushed in both directions, i.e. makes sure we don't clobber a shared
408 // texture definition with an older version.
409 TEST_F(MailboxManagerSyncTest, ProduceConsumeBidirectional) {
410 const GLuint kNewTextureId1 = 1234;
411 const GLuint kNewTextureId2 = 4321;
413 Texture* texture1 = DefineTexture();
414 Mailbox name1 = Mailbox::Generate();
415 Texture* texture2 = DefineTexture();
416 Mailbox name2 = Mailbox::Generate();
417 Texture* new_texture1 = NULL;
418 Texture* new_texture2 = NULL;
420 manager_->ProduceTexture(name1, texture1);
421 manager2_->ProduceTexture(name2, texture2);
424 manager_->PushTextureUpdates(0);
425 manager2_->PushTextureUpdates(0);
427 // Create textures in the other manager instances for texture1 and texture2,
428 // respectively to create a real sharing scenario. Otherwise, there would
429 // never be conflicting updates/pushes.
432 EXPECT_CALL(*gl_, GenTextures(1, _))
433 .WillOnce(SetArgPointee<1>(kNewTextureId1));
434 SetupUpdateTexParamExpectations(
435 kNewTextureId1, GL_LINEAR, GL_LINEAR, GL_REPEAT, GL_REPEAT);
436 new_texture1 = manager2_->ConsumeTexture(name1);
437 EXPECT_CALL(*gl_, GenTextures(1, _))
438 .WillOnce(SetArgPointee<1>(kNewTextureId2));
439 SetupUpdateTexParamExpectations(
440 kNewTextureId2, GL_LINEAR, GL_LINEAR, GL_REPEAT, GL_REPEAT);
441 new_texture2 = manager_->ConsumeTexture(name2);
443 EXPECT_EQ(kNewTextureId1, new_texture1->service_id());
444 EXPECT_EQ(kNewTextureId2, new_texture2->service_id());
446 // Make a change to texture1
447 DCHECK_EQ(static_cast<GLuint>(GL_LINEAR), texture1->min_filter());
448 EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR),
449 SetParameter(texture1, GL_TEXTURE_MIN_FILTER, GL_NEAREST));
451 // Make sure this does not clobber it with the previous version we pushed.
452 manager_->PullTextureUpdates(0);
454 // Make a change to texture2
455 DCHECK_EQ(static_cast<GLuint>(GL_LINEAR), texture2->mag_filter());
456 EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR),
457 SetParameter(texture2, GL_TEXTURE_MAG_FILTER, GL_NEAREST));
459 Mock::VerifyAndClearExpectations(gl_.get());
461 // Synchronize in both directions
462 manager_->PushTextureUpdates(0);
463 manager2_->PushTextureUpdates(0);
464 // manager1 should see the change to texture2 mag_filter being applied.
465 SetupUpdateTexParamExpectations(
466 new_texture2->service_id(), GL_LINEAR, GL_NEAREST, GL_REPEAT, GL_REPEAT);
467 manager_->PullTextureUpdates(0);
468 // manager2 should see the change to texture1 min_filter being applied.
469 SetupUpdateTexParamExpectations(
470 new_texture1->service_id(), GL_NEAREST, GL_LINEAR, GL_REPEAT, GL_REPEAT);
471 manager2_->PullTextureUpdates(0);
473 DestroyTexture(texture1);
474 DestroyTexture(texture2);
475 DestroyTexture(new_texture1);
476 DestroyTexture(new_texture2);
479 // If a texture is shared with another manager instance, but the mailbox
480 // is then clobbered with a different texture in the source context, this should
481 // disconnect the earlier texture from updates.
482 TEST_F(MailboxManagerSyncTest, ProduceAndClobber) {
483 const GLuint kNewTextureId = 1234;
486 Texture* texture = DefineTexture();
487 Mailbox name = Mailbox::Generate();
489 manager_->ProduceTexture(name, texture);
490 EXPECT_EQ(texture, manager_->ConsumeTexture(name));
493 manager_->PushTextureUpdates(0);
494 manager2_->PullTextureUpdates(0);
496 EXPECT_CALL(*gl_, GenTextures(1, _))
497 .WillOnce(SetArgPointee<1>(kNewTextureId));
498 SetupUpdateTexParamExpectations(
499 kNewTextureId, GL_LINEAR, GL_LINEAR, GL_REPEAT, GL_REPEAT);
500 Texture* new_texture = manager2_->ConsumeTexture(name);
501 EXPECT_FALSE(new_texture == NULL);
502 EXPECT_NE(texture, new_texture);
503 EXPECT_EQ(kNewTextureId, new_texture->service_id());
505 Texture* old_texture = texture;
506 texture = DefineTexture();
507 manager_->ProduceTexture(name, texture);
509 // Make a change to the new texture
510 DCHECK_EQ(static_cast<GLuint>(GL_LINEAR), texture->min_filter());
511 EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR),
512 SetParameter(texture, GL_TEXTURE_MIN_FILTER, GL_NEAREST));
514 // Synchronize in both directions - no changes, since it's not shared
515 manager_->PushTextureUpdates(0);
516 manager2_->PullTextureUpdates(0);
517 EXPECT_EQ(static_cast<GLuint>(GL_LINEAR), new_texture->min_filter());
519 // Make a change to the previously shared texture
520 DCHECK_EQ(static_cast<GLuint>(GL_LINEAR), old_texture->mag_filter());
521 EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR),
522 SetParameter(old_texture, GL_TEXTURE_MAG_FILTER, GL_NEAREST));
524 // Synchronize and expect update
525 manager_->PushTextureUpdates(0);
526 SetupUpdateTexParamExpectations(
527 new_texture->service_id(), GL_LINEAR, GL_NEAREST, GL_REPEAT, GL_REPEAT);
528 manager2_->PullTextureUpdates(0);
530 EXPECT_CALL(*gl_, GenTextures(1, _))
531 .WillOnce(SetArgPointee<1>(kNewTextureId));
532 SetupUpdateTexParamExpectations(
533 kNewTextureId, GL_NEAREST, GL_LINEAR, GL_REPEAT, GL_REPEAT);
534 Texture* tmp_texture = manager2_->ConsumeTexture(name);
535 EXPECT_NE(new_texture, tmp_texture);
536 DestroyTexture(tmp_texture);
538 DestroyTexture(old_texture);
539 DestroyTexture(texture);
540 DestroyTexture(new_texture);
542 EXPECT_EQ(NULL, manager_->ConsumeTexture(name));
543 EXPECT_EQ(NULL, manager2_->ConsumeTexture(name));
546 // Putting the same texture into multiple mailboxes should result in sharing
547 // only a single texture also within a synchronized manager instance.
548 TEST_F(MailboxManagerSyncTest, SharedThroughMultipleMailboxes) {
549 const GLuint kNewTextureId = 1234;
552 Texture* texture = DefineTexture();
553 Mailbox name1 = Mailbox::Generate();
554 Mailbox name2 = Mailbox::Generate();
556 manager_->ProduceTexture(name1, texture);
559 manager_->PushTextureUpdates(0);
560 EXPECT_CALL(*gl_, GenTextures(1, _))
561 .WillOnce(SetArgPointee<1>(kNewTextureId));
562 manager2_->PullTextureUpdates(0);
563 SetupUpdateTexParamExpectations(
564 kNewTextureId, GL_LINEAR, GL_LINEAR, GL_REPEAT, GL_REPEAT);
565 Texture* new_texture = manager2_->ConsumeTexture(name1);
566 EXPECT_EQ(kNewTextureId, new_texture->service_id());
568 manager_->ProduceTexture(name2, texture);
571 manager_->PushTextureUpdates(0);
572 manager2_->PullTextureUpdates(0);
574 // name2 should return the same texture
575 EXPECT_EQ(new_texture, manager2_->ConsumeTexture(name2));
577 // Even after destroying the source texture, the original mailbox should
579 DestroyTexture(texture);
580 EXPECT_EQ(new_texture, manager2_->ConsumeTexture(name1));
581 DestroyTexture(new_texture);
584 // A: produce texture1 into M, B: consume into new_texture
585 // B: produce texture2 into M, A: produce texture1 into M
586 // B: consume M should return new_texture
587 TEST_F(MailboxManagerSyncTest, ProduceBothWays) {
588 const GLuint kNewTextureId = 1234;
591 Texture* texture1 = DefineTexture();
592 Texture* texture2 = DefineTexture();
593 Mailbox name = Mailbox::Generate();
595 manager_->ProduceTexture(name, texture1);
598 manager_->PushTextureUpdates(0);
599 EXPECT_CALL(*gl_, GenTextures(1, _))
600 .WillOnce(SetArgPointee<1>(kNewTextureId));
601 SetupUpdateTexParamExpectations(
602 kNewTextureId, GL_LINEAR, GL_LINEAR, GL_REPEAT, GL_REPEAT);
603 Texture* new_texture = manager2_->ConsumeTexture(name);
604 EXPECT_EQ(kNewTextureId, new_texture->service_id());
607 manager2_->ProduceTexture(name, texture2);
608 manager_->ProduceTexture(name, texture1);
610 // Synchronize manager -> manager2
611 manager_->PushTextureUpdates(0);
612 manager2_->PullTextureUpdates(0);
614 // name should return the original texture, and not texture2 or a new one.
615 EXPECT_EQ(new_texture, manager2_->ConsumeTexture(name));
617 DestroyTexture(texture1);
618 DestroyTexture(texture2);
619 DestroyTexture(new_texture);
622 // TODO: Produce incomplete texture
624 // TODO: Texture::level_infos_[][].size()
626 // TODO: unsupported targets and formats