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:
MailboxManagerTest()23 MailboxManagerTest() : initialized_synchronizer_(false) {}
~MailboxManagerTest()24 virtual ~MailboxManagerTest() {}
25
26 protected:
SetUp()27 virtual void SetUp() {
28 GpuServiceTest::SetUp();
29 feature_info_ = new FeatureInfo;
30 manager_ = new MailboxManager;
31 }
32
SetUpWithSynchronizer()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
TearDown()41 virtual void TearDown() {
42 if (initialized_synchronizer_)
43 MailboxSynchronizer::Terminate();
44 GpuServiceTest::TearDown();
45 }
46
CreateTexture()47 Texture* CreateTexture() {
48 return new Texture(1);
49 }
50
SetTarget(Texture * texture,GLenum target,GLuint max_level)51 void SetTarget(Texture* texture, GLenum target, GLuint max_level) {
52 texture->SetTarget(NULL, target, max_level);
53 }
54
SetLevelInfo(Texture * texture,GLenum target,GLint level,GLenum internal_format,GLsizei width,GLsizei height,GLsizei depth,GLint border,GLenum format,GLenum type,bool cleared)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
SetParameter(Texture * texture,GLenum pname,GLint param)80 GLenum SetParameter(Texture* texture, GLenum pname, GLint param) {
81 return texture->SetParameteri(feature_info_.get(), pname, param);
82 }
83
DestroyTexture(Texture * texture)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.
TEST_F(MailboxManagerTest,Basic)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.
TEST_F(MailboxManagerTest,ProduceMultipleMailbox)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.
TEST_F(MailboxManagerTest,ProduceMultipleTexture)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
TEST_F(MailboxManagerTest,ProduceMultipleTextureMailbox)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:
MailboxManagerSyncTest()199 MailboxManagerSyncTest() {}
~MailboxManagerSyncTest()200 virtual ~MailboxManagerSyncTest() {}
201
202 protected:
SetUp()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
DefineTexture()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
SetupUpdateTexParamExpectations(GLuint texture_id,GLenum min,GLenum mag,GLenum wrap_s,GLenum wrap_t)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
TearDown()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
TEST_F(MailboxManagerSyncTest,ProduceDestroy)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
TEST_F(MailboxManagerSyncTest,ProduceSyncDestroy)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.
TEST_F(MailboxManagerSyncTest,ProduceConsumeResize)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.
TEST_F(MailboxManagerSyncTest,ProduceConsumeBidirectional)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