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/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"
19 using namespace ::testing
;
21 class MailboxManagerTest
: public GpuServiceTest
{
23 MailboxManagerTest() : initialized_synchronizer_(false) {}
24 virtual ~MailboxManagerTest() {}
27 virtual void SetUp() {
28 GpuServiceTest::SetUp();
29 feature_info_
= new FeatureInfo
;
30 manager_
= new MailboxManager
;
33 virtual void SetUpWithSynchronizer() {
34 GpuServiceTest::SetUp();
35 MailboxSynchronizer::Initialize();
36 initialized_synchronizer_
= true;
37 feature_info_
= new FeatureInfo
;
38 manager_
= new MailboxManager
;
41 virtual void TearDown() {
42 if (initialized_synchronizer_
)
43 MailboxSynchronizer::Terminate();
44 GpuServiceTest::TearDown();
47 Texture
* CreateTexture() {
48 return new Texture(1);
51 void SetTarget(Texture
* texture
, GLenum target
, GLuint max_level
) {
52 texture
->SetTarget(NULL
, target
, max_level
);
59 GLenum internal_format
,
67 texture
->SetLevelInfo(NULL
,
80 GLenum
SetParameter(Texture
* texture
, GLenum pname
, GLint param
) {
81 return texture
->SetParameteri(feature_info_
.get(), pname
, param
);
84 void DestroyTexture(Texture
* texture
) {
88 scoped_refptr
<MailboxManager
> manager_
;
91 bool initialized_synchronizer_
;
92 scoped_refptr
<FeatureInfo
> feature_info_
;
94 DISALLOW_COPY_AND_ASSIGN(MailboxManagerTest
);
97 // Tests basic produce/consume behavior.
98 TEST_F(MailboxManagerTest
, Basic
) {
99 Texture
* texture
= CreateTexture();
101 Mailbox name
= Mailbox::Generate();
102 manager_
->ProduceTexture(0, name
, texture
);
103 EXPECT_EQ(texture
, manager_
->ConsumeTexture(0, name
));
105 // We can consume multiple times.
106 EXPECT_EQ(texture
, manager_
->ConsumeTexture(0, name
));
108 // Wrong target should fail the consume.
109 EXPECT_EQ(NULL
, manager_
->ConsumeTexture(1, name
));
111 // Destroy should cleanup the mailbox.
112 DestroyTexture(texture
);
113 EXPECT_EQ(NULL
, manager_
->ConsumeTexture(0, name
));
116 // Tests behavior with multiple produce on the same texture.
117 TEST_F(MailboxManagerTest
, ProduceMultipleMailbox
) {
118 Texture
* texture
= CreateTexture();
120 Mailbox name1
= Mailbox::Generate();
122 manager_
->ProduceTexture(0, name1
, texture
);
123 EXPECT_EQ(texture
, manager_
->ConsumeTexture(0, name1
));
125 // Can produce a second time with the same mailbox.
126 manager_
->ProduceTexture(0, name1
, texture
);
127 EXPECT_EQ(texture
, manager_
->ConsumeTexture(0, name1
));
129 // Can produce again, with a different mailbox.
130 Mailbox name2
= Mailbox::Generate();
131 manager_
->ProduceTexture(0, name2
, texture
);
133 // Still available under all mailboxes.
134 EXPECT_EQ(texture
, manager_
->ConsumeTexture(0, name1
));
135 EXPECT_EQ(texture
, manager_
->ConsumeTexture(0, name2
));
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
));
143 // Tests behavior with multiple produce on the same mailbox with different
145 TEST_F(MailboxManagerTest
, ProduceMultipleTexture
) {
146 Texture
* texture1
= CreateTexture();
147 Texture
* texture2
= CreateTexture();
149 Mailbox name
= Mailbox::Generate();
151 manager_
->ProduceTexture(0, name
, texture1
);
152 EXPECT_EQ(texture1
, manager_
->ConsumeTexture(0, name
));
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
));
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
));
162 // Destroying the texture that's bound should clean up.
163 DestroyTexture(texture2
);
164 EXPECT_EQ(NULL
, manager_
->ConsumeTexture(0, name
));
167 TEST_F(MailboxManagerTest
, ProduceMultipleTextureMailbox
) {
168 Texture
* texture1
= CreateTexture();
169 Texture
* texture2
= CreateTexture();
170 Mailbox name1
= Mailbox::Generate();
171 Mailbox name2
= Mailbox::Generate();
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
));
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
));
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
));
189 DestroyTexture(texture2
);
190 EXPECT_EQ(NULL
, manager_
->ConsumeTexture(0, name2
));
193 const GLsizei kMaxTextureWidth
= 64;
194 const GLsizei kMaxTextureHeight
= 64;
195 const GLsizei kMaxTextureDepth
= 1;
197 class MailboxManagerSyncTest
: public MailboxManagerTest
{
199 MailboxManagerSyncTest() {}
200 virtual ~MailboxManagerSyncTest() {}
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());
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
,
227 SetParameter(texture
, GL_TEXTURE_MIN_FILTER
, GL_LINEAR
);
228 SetParameter(texture
, GL_TEXTURE_MAG_FILTER
, GL_LINEAR
);
232 void SetupUpdateTexParamExpectations(GLuint 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
))
244 .RetiresOnSaturation();
246 TexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
, min
))
248 .RetiresOnSaturation();
250 TexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MAG_FILTER
, mag
))
252 .RetiresOnSaturation();
253 EXPECT_CALL(*gl_
, TexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_WRAP_S
, wrap_s
))
255 .RetiresOnSaturation();
256 EXPECT_CALL(*gl_
, TexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_WRAP_T
, wrap_t
))
258 .RetiresOnSaturation();
259 EXPECT_CALL(*gl_
, Flush())
261 .RetiresOnSaturation();
262 EXPECT_CALL(*gl_
, BindTexture(GL_TEXTURE_2D
, kCurrentTexture
))
264 .RetiresOnSaturation();
267 virtual void TearDown() {
268 context_
->ReleaseCurrent(NULL
);
269 MailboxManagerTest::TearDown();
272 scoped_refptr
<MailboxManager
> manager2_
;
273 scoped_refptr
<gfx::GLContext
> context_
;
274 scoped_refptr
<gfx::GLSurface
> surface_
;
277 DISALLOW_COPY_AND_ASSIGN(MailboxManagerSyncTest
);
280 TEST_F(MailboxManagerSyncTest
, ProduceDestroy
) {
281 Texture
* texture
= DefineTexture();
282 Mailbox name
= Mailbox::Generate();
285 manager_
->ProduceTexture(GL_TEXTURE_2D
, name
, texture
);
286 EXPECT_EQ(texture
, manager_
->ConsumeTexture(GL_TEXTURE_2D
, name
));
288 DestroyTexture(texture
);
289 EXPECT_EQ(NULL
, manager_
->ConsumeTexture(GL_TEXTURE_2D
, name
));
290 EXPECT_EQ(NULL
, manager2_
->ConsumeTexture(GL_TEXTURE_2D
, name
));
293 TEST_F(MailboxManagerSyncTest
, ProduceSyncDestroy
) {
296 Texture
* texture
= DefineTexture();
297 Mailbox name
= Mailbox::Generate();
299 manager_
->ProduceTexture(GL_TEXTURE_2D
, name
, texture
);
300 EXPECT_EQ(texture
, manager_
->ConsumeTexture(GL_TEXTURE_2D
, name
));
303 manager_
->PushTextureUpdates();
304 manager2_
->PullTextureUpdates();
306 DestroyTexture(texture
);
307 EXPECT_EQ(NULL
, manager_
->ConsumeTexture(GL_TEXTURE_2D
, name
));
308 EXPECT_EQ(NULL
, manager2_
->ConsumeTexture(GL_TEXTURE_2D
, name
));
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;
317 Texture
* texture
= DefineTexture();
318 Mailbox name
= Mailbox::Generate();
320 manager_
->ProduceTexture(GL_TEXTURE_2D
, name
, texture
);
321 EXPECT_EQ(texture
, manager_
->ConsumeTexture(GL_TEXTURE_2D
, name
));
324 manager_
->PushTextureUpdates();
325 manager2_
->PullTextureUpdates();
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());
336 // Resize original texture
337 SetLevelInfo(texture
,
348 // Should have been orphaned
349 EXPECT_TRUE(texture
->GetLevelImage(GL_TEXTURE_2D
, 0) == NULL
);
352 manager_
->PushTextureUpdates();
353 SetupUpdateTexParamExpectations(
354 kNewTextureId
, GL_LINEAR
, GL_LINEAR
, GL_REPEAT
, GL_REPEAT
);
355 manager2_
->PullTextureUpdates();
356 GLsizei width
, height
;
357 new_texture
->GetLevelSize(GL_TEXTURE_2D
, 0, &width
, &height
);
358 EXPECT_EQ(16, width
);
359 EXPECT_EQ(32, height
);
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
,
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
);
380 // Should be still around since there is a ref from manager2
381 EXPECT_EQ(new_texture
, manager2_
->ConsumeTexture(GL_TEXTURE_2D
, name
));
383 // The last change to the texture should be visible without a sync point (i.e.
385 manager2_
->PullTextureUpdates();
386 new_texture
->GetLevelSize(GL_TEXTURE_2D
, 0, &width
, &height
);
387 EXPECT_EQ(64, width
);
388 EXPECT_EQ(64, height
);
390 DestroyTexture(new_texture
);
391 EXPECT_EQ(NULL
, manager_
->ConsumeTexture(GL_TEXTURE_2D
, name
));
392 EXPECT_EQ(NULL
, manager2_
->ConsumeTexture(GL_TEXTURE_2D
, name
));
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;
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
;
409 manager_
->ProduceTexture(GL_TEXTURE_2D
, name1
, texture1
);
410 manager2_
->ProduceTexture(GL_TEXTURE_2D
, name2
, texture2
);
413 manager_
->PushTextureUpdates();
414 manager2_
->PushTextureUpdates();
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.
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
);
432 EXPECT_EQ(kNewTextureId1
, new_texture1
->service_id());
433 EXPECT_EQ(kNewTextureId2
, new_texture2
->service_id());
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
));
440 // Make sure this does not clobber it with the previous version we pushed.
441 manager_
->PullTextureUpdates();
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
));
448 Mock::VerifyAndClearExpectations(gl_
.get());
450 // Synchronize in both directions
451 manager_
->PushTextureUpdates();
452 manager2_
->PushTextureUpdates();
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();
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();
462 DestroyTexture(texture1
);
463 DestroyTexture(texture2
);
464 DestroyTexture(new_texture1
);
465 DestroyTexture(new_texture2
);
468 // TODO: different texture into same mailbox
470 // TODO: same texture, multiple mailboxes
472 // TODO: Produce incomplete texture
474 // TODO: Texture::level_infos_[][].size()
476 // TODO: unsupported targets and formats