Upstream version 7.36.149.0
[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/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"
14
15 namespace gpu {
16 namespace gles2 {
17
18 using namespace ::testing;
19
20 class MailboxManagerTest : public testing::Test {
21  public:
22   MailboxManagerTest() {}
23   virtual ~MailboxManagerTest() {}
24
25  protected:
26   virtual void SetUp() {
27     testing::Test::SetUp();
28     feature_info_ = new FeatureInfo;
29     manager_ = new MailboxManager;
30   }
31
32   Texture* CreateTexture() {
33     return new Texture(1);
34   }
35
36   void SetTarget(Texture* texture, GLenum target, GLuint max_level) {
37     texture->SetTarget(NULL, target, max_level);
38   }
39
40   void SetLevelInfo(
41       Texture* texture,
42       GLenum target,
43       GLint level,
44       GLenum internal_format,
45       GLsizei width,
46       GLsizei height,
47       GLsizei depth,
48       GLint border,
49       GLenum format,
50       GLenum type,
51       bool cleared) {
52     texture->SetLevelInfo(NULL,
53                           target,
54                           level,
55                           internal_format,
56                           width,
57                           height,
58                           depth,
59                           border,
60                           format,
61                           type,
62                           cleared);
63   }
64
65   GLenum SetParameter(Texture* texture, GLenum pname, GLint param) {
66     return texture->SetParameteri(feature_info_, pname, param);
67   }
68
69   void DestroyTexture(Texture* texture) {
70     delete texture;
71   }
72
73   scoped_refptr<MailboxManager> manager_;
74
75  private:
76   scoped_refptr<FeatureInfo> feature_info_;
77
78   DISALLOW_COPY_AND_ASSIGN(MailboxManagerTest);
79 };
80
81 // Tests basic produce/consume behavior.
82 TEST_F(MailboxManagerTest, Basic) {
83   Texture* texture = CreateTexture();
84
85   Mailbox name = Mailbox::Generate();
86   manager_->ProduceTexture(0, name, texture);
87   EXPECT_EQ(texture, manager_->ConsumeTexture(0, name));
88
89   // We can consume multiple times.
90   EXPECT_EQ(texture, manager_->ConsumeTexture(0, name));
91
92   // Wrong target should fail the consume.
93   EXPECT_EQ(NULL, manager_->ConsumeTexture(1, name));
94
95   // Destroy should cleanup the mailbox.
96   DestroyTexture(texture);
97   EXPECT_EQ(NULL, manager_->ConsumeTexture(0, name));
98 }
99
100 // Tests behavior with multiple produce on the same texture.
101 TEST_F(MailboxManagerTest, ProduceMultipleMailbox) {
102   Texture* texture = CreateTexture();
103
104   Mailbox name1 = Mailbox::Generate();
105
106   manager_->ProduceTexture(0, name1, texture);
107   EXPECT_EQ(texture, manager_->ConsumeTexture(0, name1));
108
109   // Can produce a second time with the same mailbox.
110   manager_->ProduceTexture(0, name1, texture);
111   EXPECT_EQ(texture, manager_->ConsumeTexture(0, name1));
112
113   // Can produce again, with a different mailbox.
114   Mailbox name2 = Mailbox::Generate();
115   manager_->ProduceTexture(0, name2, texture);
116
117   // Still available under all mailboxes.
118   EXPECT_EQ(texture, manager_->ConsumeTexture(0, name1));
119   EXPECT_EQ(texture, manager_->ConsumeTexture(0, name2));
120
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));
125 }
126
127 // Tests behavior with multiple produce on the same mailbox with different
128 // textures.
129 TEST_F(MailboxManagerTest, ProduceMultipleTexture) {
130   Texture* texture1 = CreateTexture();
131   Texture* texture2 = CreateTexture();
132
133   Mailbox name = Mailbox::Generate();
134
135   manager_->ProduceTexture(0, name, texture1);
136   EXPECT_EQ(texture1, manager_->ConsumeTexture(0, name));
137
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));
141
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));
145
146   // Destroying the texture that's bound should clean up.
147   DestroyTexture(texture2);
148   EXPECT_EQ(NULL, manager_->ConsumeTexture(0, name));
149 }
150
151 TEST_F(MailboxManagerTest, ProduceMultipleTextureMailbox) {
152   Texture* texture1 = CreateTexture();
153   Texture* texture2 = CreateTexture();
154   Mailbox name1 = Mailbox::Generate();
155   Mailbox name2 = Mailbox::Generate();
156
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));
162
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));
167
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));
172
173   DestroyTexture(texture2);
174   EXPECT_EQ(NULL, manager_->ConsumeTexture(0, name2));
175 }
176
177 const GLsizei kMaxTextureWidth = 64;
178 const GLsizei kMaxTextureHeight = 64;
179 const GLsizei kMaxTextureDepth = 1;
180
181 class MailboxManagerSyncTest : public MailboxManagerTest {
182  public:
183   MailboxManagerSyncTest() {}
184   virtual ~MailboxManagerSyncTest() {}
185
186  protected:
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_);
196   }
197
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,
204                  GL_TEXTURE_2D,
205                  0,
206                  GL_RGBA,
207                  1,
208                  1,
209                  1,
210                  0,
211                  GL_RGBA,
212                  GL_UNSIGNED_BYTE,
213                  true);
214     SetParameter(texture, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
215     SetParameter(texture, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
216     return texture;
217   }
218
219   void SetupUpdateTexParamExpectations(GLuint texture_id,
220                                        GLenum min,
221                                        GLenum mag,
222                                        GLenum wrap_s,
223                                        GLenum wrap_t) {
224     DCHECK(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))
230         .Times(1)
231         .RetiresOnSaturation();
232     EXPECT_CALL(*gl_,
233                 TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, min))
234         .Times(1)
235         .RetiresOnSaturation();
236     EXPECT_CALL(*gl_,
237                 TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag))
238         .Times(1)
239         .RetiresOnSaturation();
240     EXPECT_CALL(*gl_, TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrap_s))
241         .Times(1)
242         .RetiresOnSaturation();
243     EXPECT_CALL(*gl_, TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrap_t))
244         .Times(1)
245         .RetiresOnSaturation();
246     EXPECT_CALL(*gl_, Flush())
247         .Times(1)
248         .RetiresOnSaturation();
249     EXPECT_CALL(*gl_, BindTexture(GL_TEXTURE_2D, kCurrentTexture))
250         .Times(1)
251         .RetiresOnSaturation();
252   }
253
254   virtual void TearDown() {
255     MailboxManagerTest::TearDown();
256     MailboxSynchronizer::Terminate();
257     context_->ReleaseCurrent(NULL);
258     ::gfx::MockGLInterface::SetGLInterface(NULL);
259     gl_.reset();
260   }
261
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_;
266
267  private:
268   DISALLOW_COPY_AND_ASSIGN(MailboxManagerSyncTest);
269 };
270
271 TEST_F(MailboxManagerSyncTest, ProduceDestroy) {
272   Texture* texture = DefineTexture();
273   Mailbox name = Mailbox::Generate();
274
275   InSequence sequence;
276   manager_->ProduceTexture(GL_TEXTURE_2D, name, texture);
277   EXPECT_EQ(texture, manager_->ConsumeTexture(GL_TEXTURE_2D, name));
278
279   DestroyTexture(texture);
280   EXPECT_EQ(NULL, manager_->ConsumeTexture(GL_TEXTURE_2D, name));
281   EXPECT_EQ(NULL, manager2_->ConsumeTexture(GL_TEXTURE_2D, name));
282 }
283
284 TEST_F(MailboxManagerSyncTest, ProduceSyncDestroy) {
285   InSequence sequence;
286
287   Texture* texture = DefineTexture();
288   Mailbox name = Mailbox::Generate();
289
290   manager_->ProduceTexture(GL_TEXTURE_2D, name, texture);
291   EXPECT_EQ(texture, manager_->ConsumeTexture(GL_TEXTURE_2D, name));
292
293   // Synchronize
294   manager_->PushTextureUpdates();
295   manager2_->PullTextureUpdates();
296
297   DestroyTexture(texture);
298   EXPECT_EQ(NULL, manager_->ConsumeTexture(GL_TEXTURE_2D, name));
299   EXPECT_EQ(NULL, manager2_->ConsumeTexture(GL_TEXTURE_2D, name));
300 }
301
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;
306   InSequence sequence;
307
308   Texture* texture = DefineTexture();
309   Mailbox name = Mailbox::Generate();
310
311   manager_->ProduceTexture(GL_TEXTURE_2D, name, texture);
312   EXPECT_EQ(texture, manager_->ConsumeTexture(GL_TEXTURE_2D, name));
313
314   // Synchronize
315   manager_->PushTextureUpdates();
316   manager2_->PullTextureUpdates();
317
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());
326
327   // Resize original texture
328   SetLevelInfo(texture,
329                GL_TEXTURE_2D,
330                0,
331                GL_RGBA,
332                16,
333                32,
334                1,
335                0,
336                GL_RGBA,
337                GL_UNSIGNED_BYTE,
338                true);
339   // Should have been orphaned
340   EXPECT_TRUE(texture->GetLevelImage(GL_TEXTURE_2D, 0) == NULL);
341
342   // Synchronize again
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);
351
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,
356                GL_TEXTURE_2D,
357                0,
358                GL_RGBA,
359                64,
360                64,
361                1,
362                0,
363                GL_RGBA,
364                GL_UNSIGNED_BYTE,
365                true);
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);
370
371   // Should be still around since there is a ref from manager2
372   EXPECT_EQ(new_texture, manager2_->ConsumeTexture(GL_TEXTURE_2D, name));
373
374   // The last change to the texture should be visible without a sync point (i.e.
375   // push).
376   manager2_->PullTextureUpdates();
377   new_texture->GetLevelSize(GL_TEXTURE_2D, 0, &width, &height);
378   EXPECT_EQ(64, width);
379   EXPECT_EQ(64, height);
380
381   DestroyTexture(new_texture);
382   EXPECT_EQ(NULL, manager_->ConsumeTexture(GL_TEXTURE_2D, name));
383   EXPECT_EQ(NULL, manager2_->ConsumeTexture(GL_TEXTURE_2D, name));
384 }
385
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;
392
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;
399
400   manager_->ProduceTexture(GL_TEXTURE_2D, name1, texture1);
401   manager2_->ProduceTexture(GL_TEXTURE_2D, name2, texture2);
402
403   // Make visible.
404   manager_->PushTextureUpdates();
405   manager2_->PushTextureUpdates();
406
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.
410   {
411     InSequence sequence;
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);
422   }
423   EXPECT_EQ(kNewTextureId1, new_texture1->service_id());
424   EXPECT_EQ(kNewTextureId2, new_texture2->service_id());
425
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));
430
431   // Make sure this does not clobber it with the previous version we pushed.
432   manager_->PullTextureUpdates();
433
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));
438
439   Mock::VerifyAndClearExpectations(gl_.get());
440
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();
452
453   DestroyTexture(texture1);
454   DestroyTexture(texture2);
455   DestroyTexture(new_texture1);
456   DestroyTexture(new_texture2);
457 }
458
459 // TODO: different texture into same mailbox
460
461 // TODO: same texture, multiple mailboxes
462
463 // TODO: Produce incomplete texture
464
465 // TODO: Texture::level_infos_[][].size()
466
467 // TODO: unsupported targets and formats
468
469 }  // namespace gles2
470 }  // namespace gpu