• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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