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/mailbox_manager.h"
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_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 testing::Test {
22 MailboxManagerTest() {}
23 virtual ~MailboxManagerTest() {}
26 virtual void SetUp() {
27 testing::Test::SetUp();
28 feature_info_ = new FeatureInfo;
29 manager_ = new MailboxManager;
32 Texture* CreateTexture() {
33 return new Texture(1);
36 void SetTarget(Texture* texture, GLenum target, GLuint max_level) {
37 texture->SetTarget(NULL, target, max_level);
44 GLenum internal_format,
52 texture->SetLevelInfo(NULL,
65 GLenum SetParameter(Texture* texture, GLenum pname, GLint param) {
66 return texture->SetParameteri(feature_info_, pname, param);
69 void DestroyTexture(Texture* texture) {
73 scoped_refptr<MailboxManager> manager_;
76 scoped_refptr<FeatureInfo> feature_info_;
78 DISALLOW_COPY_AND_ASSIGN(MailboxManagerTest);
81 // Tests basic produce/consume behavior.
82 TEST_F(MailboxManagerTest, Basic) {
83 Texture* texture = CreateTexture();
85 Mailbox name = Mailbox::Generate();
86 manager_->ProduceTexture(0, name, texture);
87 EXPECT_EQ(texture, manager_->ConsumeTexture(0, name));
89 // We can consume multiple times.
90 EXPECT_EQ(texture, manager_->ConsumeTexture(0, name));
92 // Wrong target should fail the consume.
93 EXPECT_EQ(NULL, manager_->ConsumeTexture(1, name));
95 // Destroy should cleanup the mailbox.
96 DestroyTexture(texture);
97 EXPECT_EQ(NULL, manager_->ConsumeTexture(0, name));
100 // Tests behavior with multiple produce on the same texture.
101 TEST_F(MailboxManagerTest, ProduceMultipleMailbox) {
102 Texture* texture = CreateTexture();
104 Mailbox name1 = Mailbox::Generate();
106 manager_->ProduceTexture(0, name1, texture);
107 EXPECT_EQ(texture, manager_->ConsumeTexture(0, name1));
109 // Can produce a second time with the same mailbox.
110 manager_->ProduceTexture(0, name1, texture);
111 EXPECT_EQ(texture, manager_->ConsumeTexture(0, name1));
113 // Can produce again, with a different mailbox.
114 Mailbox name2 = Mailbox::Generate();
115 manager_->ProduceTexture(0, name2, texture);
117 // Still available under all mailboxes.
118 EXPECT_EQ(texture, manager_->ConsumeTexture(0, name1));
119 EXPECT_EQ(texture, manager_->ConsumeTexture(0, name2));
121 // Destroy should cleanup all mailboxes.
122 DestroyTexture(texture);
123 EXPECT_EQ(NULL, manager_->ConsumeTexture(0, name1));
124 EXPECT_EQ(NULL, manager_->ConsumeTexture(0, name2));
127 // Tests behavior with multiple produce on the same mailbox with different
129 TEST_F(MailboxManagerTest, ProduceMultipleTexture) {
130 Texture* texture1 = CreateTexture();
131 Texture* texture2 = CreateTexture();
133 Mailbox name = Mailbox::Generate();
135 manager_->ProduceTexture(0, name, texture1);
136 EXPECT_EQ(texture1, manager_->ConsumeTexture(0, name));
138 // Can produce a second time with the same mailbox, but different texture.
139 manager_->ProduceTexture(0, name, texture2);
140 EXPECT_EQ(texture2, manager_->ConsumeTexture(0, name));
142 // Destroying the texture that's under no mailbox shouldn't have an effect.
143 DestroyTexture(texture1);
144 EXPECT_EQ(texture2, manager_->ConsumeTexture(0, name));
146 // Destroying the texture that's bound should clean up.
147 DestroyTexture(texture2);
148 EXPECT_EQ(NULL, manager_->ConsumeTexture(0, name));
151 TEST_F(MailboxManagerTest, ProduceMultipleTextureMailbox) {
152 Texture* texture1 = CreateTexture();
153 Texture* texture2 = CreateTexture();
154 Mailbox name1 = Mailbox::Generate();
155 Mailbox name2 = Mailbox::Generate();
157 // Put texture1 on name1 and name2.
158 manager_->ProduceTexture(0, name1, texture1);
159 manager_->ProduceTexture(0, name2, texture1);
160 EXPECT_EQ(texture1, manager_->ConsumeTexture(0, name1));
161 EXPECT_EQ(texture1, manager_->ConsumeTexture(0, name2));
163 // Put texture2 on name2.
164 manager_->ProduceTexture(0, name2, texture2);
165 EXPECT_EQ(texture1, manager_->ConsumeTexture(0, name1));
166 EXPECT_EQ(texture2, manager_->ConsumeTexture(0, name2));
168 // Destroy texture1, shouldn't affect name2.
169 DestroyTexture(texture1);
170 EXPECT_EQ(NULL, manager_->ConsumeTexture(0, name1));
171 EXPECT_EQ(texture2, manager_->ConsumeTexture(0, name2));
173 DestroyTexture(texture2);
174 EXPECT_EQ(NULL, manager_->ConsumeTexture(0, name2));
177 const GLsizei kMaxTextureWidth = 64;
178 const GLsizei kMaxTextureHeight = 64;
179 const GLsizei kMaxTextureDepth = 1;
181 class MailboxManagerSyncTest : public MailboxManagerTest {
183 MailboxManagerSyncTest() {}
184 virtual ~MailboxManagerSyncTest() {}
187 virtual void SetUp() {
188 MailboxSynchronizer::Initialize();
189 MailboxManagerTest::SetUp();
190 manager2_ = new MailboxManager;
191 gl_.reset(new ::testing::StrictMock< ::gfx::MockGLInterface>());
192 ::gfx::MockGLInterface::SetGLInterface(gl_.get());
193 context_ = new gfx::GLContextStub();
194 surface_ = new gfx::GLSurfaceStub();
195 context_->MakeCurrent(surface_);
198 Texture* DefineTexture() {
199 Texture* texture = CreateTexture();
200 const GLsizei levels_needed = TextureManager::ComputeMipMapCount(
201 GL_TEXTURE_2D, kMaxTextureWidth, kMaxTextureHeight, kMaxTextureDepth);
202 SetTarget(texture, GL_TEXTURE_2D, levels_needed);
203 SetLevelInfo(texture,
214 SetParameter(texture, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
215 SetParameter(texture, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
219 void SetupUpdateTexParamExpectations(GLuint texture_id,
225 const GLuint kCurrentTexture = 0;
226 EXPECT_CALL(*gl_, GetIntegerv(GL_TEXTURE_BINDING_2D, _))
227 .WillOnce(SetArgPointee<1>(kCurrentTexture))
228 .RetiresOnSaturation();
229 EXPECT_CALL(*gl_, BindTexture(GL_TEXTURE_2D, texture_id))
231 .RetiresOnSaturation();
233 TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, min))
235 .RetiresOnSaturation();
237 TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag))
239 .RetiresOnSaturation();
240 EXPECT_CALL(*gl_, TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrap_s))
242 .RetiresOnSaturation();
243 EXPECT_CALL(*gl_, TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrap_t))
245 .RetiresOnSaturation();
246 EXPECT_CALL(*gl_, Flush())
248 .RetiresOnSaturation();
249 EXPECT_CALL(*gl_, BindTexture(GL_TEXTURE_2D, kCurrentTexture))
251 .RetiresOnSaturation();
254 virtual void TearDown() {
255 MailboxManagerTest::TearDown();
256 MailboxSynchronizer::Terminate();
257 context_->ReleaseCurrent(NULL);
258 ::gfx::MockGLInterface::SetGLInterface(NULL);
262 scoped_ptr< ::testing::StrictMock< ::gfx::MockGLInterface> > gl_;
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(GL_TEXTURE_2D, name, texture);
277 EXPECT_EQ(texture, manager_->ConsumeTexture(GL_TEXTURE_2D, name));
279 DestroyTexture(texture);
280 EXPECT_EQ(NULL, manager_->ConsumeTexture(GL_TEXTURE_2D, name));
281 EXPECT_EQ(NULL, manager2_->ConsumeTexture(GL_TEXTURE_2D, name));
284 TEST_F(MailboxManagerSyncTest, ProduceSyncDestroy) {
287 Texture* texture = DefineTexture();
288 Mailbox name = Mailbox::Generate();
290 manager_->ProduceTexture(GL_TEXTURE_2D, name, texture);
291 EXPECT_EQ(texture, manager_->ConsumeTexture(GL_TEXTURE_2D, name));
294 manager_->PushTextureUpdates();
295 manager2_->PullTextureUpdates();
297 DestroyTexture(texture);
298 EXPECT_EQ(NULL, manager_->ConsumeTexture(GL_TEXTURE_2D, name));
299 EXPECT_EQ(NULL, manager2_->ConsumeTexture(GL_TEXTURE_2D, name));
302 // Duplicates a texture into a second manager instance, and then
303 // makes sure a redefinition becomes visible there too.
304 TEST_F(MailboxManagerSyncTest, ProduceConsumeResize) {
305 const GLuint kNewTextureId = 1234;
308 Texture* texture = DefineTexture();
309 Mailbox name = Mailbox::Generate();
311 manager_->ProduceTexture(GL_TEXTURE_2D, name, texture);
312 EXPECT_EQ(texture, manager_->ConsumeTexture(GL_TEXTURE_2D, name));
315 manager_->PushTextureUpdates();
316 manager2_->PullTextureUpdates();
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());
327 // Resize original texture
328 SetLevelInfo(texture,
339 // Should have been orphaned
340 EXPECT_TRUE(texture->GetLevelImage(GL_TEXTURE_2D, 0) == NULL);
343 manager_->PushTextureUpdates();
344 SetupUpdateTexParamExpectations(
345 kNewTextureId, GL_LINEAR, GL_LINEAR, GL_REPEAT, GL_REPEAT);
346 manager2_->PullTextureUpdates();
347 GLsizei width, height;
348 new_texture->GetLevelSize(GL_TEXTURE_2D, 0, &width, &height);
349 EXPECT_EQ(16, width);
350 EXPECT_EQ(32, height);
352 // Should have gotten a new attachment
353 EXPECT_TRUE(texture->GetLevelImage(GL_TEXTURE_2D, 0) != NULL);
354 // Resize original texture again....
355 SetLevelInfo(texture,
366 // ...and immediately delete the texture which should save the changes.
367 SetupUpdateTexParamExpectations(
368 kNewTextureId, GL_LINEAR, GL_LINEAR, GL_REPEAT, GL_REPEAT);
369 DestroyTexture(texture);
371 // Should be still around since there is a ref from manager2
372 EXPECT_EQ(new_texture, manager2_->ConsumeTexture(GL_TEXTURE_2D, name));
374 // The last change to the texture should be visible without a sync point (i.e.
376 manager2_->PullTextureUpdates();
377 new_texture->GetLevelSize(GL_TEXTURE_2D, 0, &width, &height);
378 EXPECT_EQ(64, width);
379 EXPECT_EQ(64, height);
381 DestroyTexture(new_texture);
382 EXPECT_EQ(NULL, manager_->ConsumeTexture(GL_TEXTURE_2D, name));
383 EXPECT_EQ(NULL, manager2_->ConsumeTexture(GL_TEXTURE_2D, name));
386 // Makes sure changes are correctly published even when updates are
387 // pushed in both directions, i.e. makes sure we don't clobber a shared
388 // texture definition with an older version.
389 TEST_F(MailboxManagerSyncTest, ProduceConsumeBidirectional) {
390 const GLuint kNewTextureId1 = 1234;
391 const GLuint kNewTextureId2 = 4321;
393 Texture* texture1 = DefineTexture();
394 Mailbox name1 = Mailbox::Generate();
395 Texture* texture2 = DefineTexture();
396 Mailbox name2 = Mailbox::Generate();
397 Texture* new_texture1 = NULL;
398 Texture* new_texture2 = NULL;
400 manager_->ProduceTexture(GL_TEXTURE_2D, name1, texture1);
401 manager2_->ProduceTexture(GL_TEXTURE_2D, name2, texture2);
404 manager_->PushTextureUpdates();
405 manager2_->PushTextureUpdates();
407 // Create textures in the other manager instances for texture1 and texture2,
408 // respectively to create a real sharing scenario. Otherwise, there would
409 // never be conflicting updates/pushes.
412 EXPECT_CALL(*gl_, GenTextures(1, _))
413 .WillOnce(SetArgPointee<1>(kNewTextureId1));
414 SetupUpdateTexParamExpectations(
415 kNewTextureId1, GL_LINEAR, GL_LINEAR, GL_REPEAT, GL_REPEAT);
416 new_texture1 = manager2_->ConsumeTexture(GL_TEXTURE_2D, name1);
417 EXPECT_CALL(*gl_, GenTextures(1, _))
418 .WillOnce(SetArgPointee<1>(kNewTextureId2));
419 SetupUpdateTexParamExpectations(
420 kNewTextureId2, GL_LINEAR, GL_LINEAR, GL_REPEAT, GL_REPEAT);
421 new_texture2 = manager_->ConsumeTexture(GL_TEXTURE_2D, name2);
423 EXPECT_EQ(kNewTextureId1, new_texture1->service_id());
424 EXPECT_EQ(kNewTextureId2, new_texture2->service_id());
426 // Make a change to texture1
427 DCHECK_EQ(static_cast<GLuint>(GL_LINEAR), texture1->min_filter());
428 EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR),
429 SetParameter(texture1, GL_TEXTURE_MIN_FILTER, GL_NEAREST));
431 // Make sure this does not clobber it with the previous version we pushed.
432 manager_->PullTextureUpdates();
434 // Make a change to texture2
435 DCHECK_EQ(static_cast<GLuint>(GL_LINEAR), texture2->mag_filter());
436 EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR),
437 SetParameter(texture2, GL_TEXTURE_MAG_FILTER, GL_NEAREST));
439 Mock::VerifyAndClearExpectations(gl_.get());
441 // Synchronize in both directions
442 manager_->PushTextureUpdates();
443 manager2_->PushTextureUpdates();
444 // manager1 should see the change to texture2 mag_filter being applied.
445 SetupUpdateTexParamExpectations(
446 new_texture2->service_id(), GL_LINEAR, GL_NEAREST, GL_REPEAT, GL_REPEAT);
447 manager_->PullTextureUpdates();
448 // manager2 should see the change to texture1 min_filter being applied.
449 SetupUpdateTexParamExpectations(
450 new_texture1->service_id(), GL_NEAREST, GL_LINEAR, GL_REPEAT, GL_REPEAT);
451 manager2_->PullTextureUpdates();
453 DestroyTexture(texture1);
454 DestroyTexture(texture2);
455 DestroyTexture(new_texture1);
456 DestroyTexture(new_texture2);
459 // TODO: different texture into same mailbox
461 // TODO: same texture, multiple mailboxes
463 // TODO: Produce incomplete texture
465 // TODO: Texture::level_infos_[][].size()
467 // TODO: unsupported targets and formats