df1cd4eced635fa56d8509f84a16dbd0fc5bed75
[platform/framework/web/crosswalk.git] / src / gpu / command_buffer / service / mailbox_manager_unittest.cc
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:
23   MailboxManagerTest() : initialized_synchronizer_(false) {}
24   virtual ~MailboxManagerTest() {}
25
26  protected:
27   virtual void SetUp() {
28     GpuServiceTest::SetUp();
29     feature_info_ = new FeatureInfo;
30     manager_ = new MailboxManager;
31   }
32
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
41   virtual void TearDown() {
42     if (initialized_synchronizer_)
43       MailboxSynchronizer::Terminate();
44     GpuServiceTest::TearDown();
45   }
46
47   Texture* CreateTexture() {
48     return new Texture(1);
49   }
50
51   void SetTarget(Texture* texture, GLenum target, GLuint max_level) {
52     texture->SetTarget(NULL, target, max_level);
53   }
54
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
80   GLenum SetParameter(Texture* texture, GLenum pname, GLint param) {
81     return texture->SetParameteri(feature_info_.get(), pname, param);
82   }
83
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.
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.
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.
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
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:
199   MailboxManagerSyncTest() {}
200   virtual ~MailboxManagerSyncTest() {}
201
202  protected:
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
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
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
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
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
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();
304   manager2_->PullTextureUpdates();
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.
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();
325   manager2_->PullTextureUpdates();
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();
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);
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();
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.
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();
414   manager2_->PushTextureUpdates();
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();
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();
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();
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