Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / platform / graphics / gpu / DrawingBufferTest.cpp
1 /*
2  * Copyright (C) 2013 Google Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
8  *     * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  *     * Redistributions in binary form must reproduce the above
11  * copyright notice, this list of conditions and the following disclaimer
12  * in the documentation and/or other materials provided with the
13  * distribution.
14  *     * Neither the name of Google Inc. nor the names of its
15  * contributors may be used to endorse or promote products derived from
16  * this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30
31 #include "config.h"
32
33 #include "platform/graphics/gpu/DrawingBuffer.h"
34
35 #include "platform/RuntimeEnabledFeatures.h"
36 #include "platform/graphics/ImageBuffer.h"
37 #include "platform/graphics/UnacceleratedImageBufferSurface.h"
38 #include "platform/graphics/gpu/Extensions3DUtil.h"
39 #include "platform/graphics/test/MockWebGraphicsContext3D.h"
40 #include "public/platform/Platform.h"
41 #include "public/platform/WebExternalTextureMailbox.h"
42 #include "wtf/RefPtr.h"
43
44 #include <gmock/gmock.h>
45 #include <gtest/gtest.h>
46
47 using namespace blink;
48 using testing::Test;
49 using testing::_;
50
51 namespace {
52
53 class FakeContextEvictionManager : public ContextEvictionManager {
54 public:
55     void forciblyLoseOldestContext(const String& reason) { }
56     IntSize oldestContextSize() { return IntSize(); }
57 };
58
59 class WebGraphicsContext3DForTests : public MockWebGraphicsContext3D {
60 public:
61     WebGraphicsContext3DForTests()
62         : MockWebGraphicsContext3D()
63         , m_boundTexture(0)
64         , m_currentMailboxByte(0)
65         , m_mostRecentlyWaitedSyncPoint(0)
66         , m_currentImageId(1) { }
67
68     virtual void bindTexture(WGC3Denum target, WebGLId texture)
69     {
70         if (target == GL_TEXTURE_2D) {
71             m_boundTexture = texture;
72         }
73     }
74
75     virtual void texImage2D(WGC3Denum target, WGC3Dint level, WGC3Denum internalformat, WGC3Dsizei width, WGC3Dsizei height, WGC3Dint border, WGC3Denum format, WGC3Denum type, const void* pixels)
76     {
77         if (target == GL_TEXTURE_2D && !level) {
78             m_textureSizes.set(m_boundTexture, IntSize(width, height));
79         }
80     }
81
82     virtual void genMailboxCHROMIUM(WGC3Dbyte* mailbox)
83     {
84         ++m_currentMailboxByte;
85         WebExternalTextureMailbox temp;
86         memset(mailbox, m_currentMailboxByte, sizeof(temp.name));
87     }
88
89     virtual void produceTextureDirectCHROMIUM(WebGLId texture, WGC3Denum target, const WGC3Dbyte* mailbox)
90     {
91         ASSERT_EQ(target, static_cast<WGC3Denum>(GL_TEXTURE_2D));
92         ASSERT_TRUE(m_textureSizes.contains(texture));
93         m_mostRecentlyProducedSize = m_textureSizes.get(texture);
94     }
95
96     IntSize mostRecentlyProducedSize()
97     {
98         return m_mostRecentlyProducedSize;
99     }
100
101     virtual unsigned insertSyncPoint()
102     {
103         static unsigned syncPointGenerator = 0;
104         return ++syncPointGenerator;
105     }
106
107     virtual void waitSyncPoint(unsigned syncPoint)
108     {
109         m_mostRecentlyWaitedSyncPoint = syncPoint;
110     }
111
112     virtual WGC3Duint createImageCHROMIUM(WGC3Dsizei width, WGC3Dsizei height, WGC3Denum internalformat, WGC3Denum usage)
113     {
114         m_imageSizes.set(m_currentImageId, IntSize(width, height));
115         return m_currentImageId++;
116     }
117
118     MOCK_METHOD1(destroyImageMock, void(WGC3Duint imageId));
119     void destroyImageCHROMIUM(WGC3Duint imageId)
120     {
121         m_imageSizes.remove(imageId);
122         // No textures should be bound to this.
123         ASSERT(m_imageToTextureMap.find(imageId) == m_imageToTextureMap.end());
124         m_imageSizes.remove(imageId);
125         destroyImageMock(imageId);
126     }
127
128     MOCK_METHOD1(bindTexImage2DMock, void(WGC3Dint imageId));
129     void bindTexImage2DCHROMIUM(WGC3Denum target, WGC3Dint imageId)
130     {
131         if (target == GL_TEXTURE_2D) {
132             m_textureSizes.set(m_boundTexture, m_imageSizes.find(imageId)->value);
133             m_imageToTextureMap.set(imageId, m_boundTexture);
134             bindTexImage2DMock(imageId);
135         }
136     }
137
138     MOCK_METHOD1(releaseTexImage2DMock, void(WGC3Dint imageId));
139     void releaseTexImage2DCHROMIUM(WGC3Denum target, WGC3Dint imageId)
140     {
141         if (target == GL_TEXTURE_2D) {
142             m_imageSizes.set(m_currentImageId, IntSize());
143             m_imageToTextureMap.remove(imageId);
144             releaseTexImage2DMock(imageId);
145         }
146     }
147
148     unsigned mostRecentlyWaitedSyncPoint()
149     {
150         return m_mostRecentlyWaitedSyncPoint;
151     }
152
153     WGC3Duint nextImageIdToBeCreated()
154     {
155         return m_currentImageId;
156     }
157
158 private:
159     WebGLId m_boundTexture;
160     HashMap<WebGLId, IntSize> m_textureSizes;
161     WGC3Dbyte m_currentMailboxByte;
162     IntSize m_mostRecentlyProducedSize;
163     unsigned m_mostRecentlyWaitedSyncPoint;
164     WGC3Duint m_currentImageId;
165     HashMap<WGC3Duint, IntSize> m_imageSizes;
166     HashMap<WGC3Duint, WebGLId> m_imageToTextureMap;
167 };
168
169 static const int initialWidth = 100;
170 static const int initialHeight = 100;
171 static const int alternateHeight = 50;
172
173 class DrawingBufferForTests : public DrawingBuffer {
174 public:
175     static PassRefPtr<DrawingBufferForTests> create(PassOwnPtr<WebGraphicsContext3D> context,
176         const IntSize& size, PreserveDrawingBuffer preserve, PassRefPtr<ContextEvictionManager> contextEvictionManager)
177     {
178         OwnPtr<Extensions3DUtil> extensionsUtil = Extensions3DUtil::create(context.get());
179         RefPtr<DrawingBufferForTests> drawingBuffer =
180             adoptRef(new DrawingBufferForTests(context, extensionsUtil.release(), preserve, contextEvictionManager));
181         if (!drawingBuffer->initialize(size)) {
182             drawingBuffer->beginDestruction();
183             return PassRefPtr<DrawingBufferForTests>();
184         }
185         return drawingBuffer.release();
186     }
187
188     DrawingBufferForTests(PassOwnPtr<WebGraphicsContext3D> context,
189         PassOwnPtr<Extensions3DUtil> extensionsUtil,
190         PreserveDrawingBuffer preserve,
191         PassRefPtr<ContextEvictionManager> contextEvictionManager)
192         : DrawingBuffer(context, extensionsUtil, false /* multisampleExtensionSupported */,
193             false /* packedDepthStencilExtensionSupported */, preserve, WebGraphicsContext3D::Attributes(), contextEvictionManager)
194         , m_live(0)
195     { }
196
197     virtual ~DrawingBufferForTests()
198     {
199         if (m_live)
200             *m_live = false;
201     }
202
203     bool* m_live;
204 };
205
206 class DrawingBufferTest : public Test {
207 protected:
208     virtual void SetUp()
209     {
210         RefPtr<FakeContextEvictionManager> contextEvictionManager = adoptRef(new FakeContextEvictionManager());
211         OwnPtr<WebGraphicsContext3DForTests> context = adoptPtr(new WebGraphicsContext3DForTests);
212         m_context = context.get();
213         m_drawingBuffer = DrawingBufferForTests::create(context.release(),
214             IntSize(initialWidth, initialHeight), DrawingBuffer::Preserve, contextEvictionManager.release());
215     }
216
217     WebGraphicsContext3DForTests* webContext()
218     {
219         return m_context;
220     }
221
222     WebGraphicsContext3DForTests* m_context;
223     RefPtr<DrawingBufferForTests> m_drawingBuffer;
224 };
225
226 TEST_F(DrawingBufferTest, testPaintRenderingResultsToCanvas)
227 {
228     OwnPtr<ImageBufferSurface> imageBufferSurface = adoptPtr(new UnacceleratedImageBufferSurface(IntSize(initialWidth, initialHeight)));
229     EXPECT_FALSE(!imageBufferSurface);
230     EXPECT_TRUE(imageBufferSurface->isValid());
231     OwnPtr<ImageBuffer> imageBuffer = ImageBuffer::create(imageBufferSurface.release());
232     EXPECT_FALSE(!imageBuffer);
233     EXPECT_FALSE(imageBuffer->isAccelerated());
234     EXPECT_FALSE(imageBuffer->bitmap().isNull());
235     m_drawingBuffer->paintRenderingResultsToCanvas(imageBuffer.get());
236     EXPECT_FALSE(imageBuffer->isAccelerated());
237     EXPECT_FALSE(imageBuffer->bitmap().isNull());
238     m_drawingBuffer->beginDestruction();
239 }
240
241 TEST_F(DrawingBufferTest, verifyResizingProperlyAffectsMailboxes)
242 {
243     WebExternalTextureMailbox mailbox;
244
245     IntSize initialSize(initialWidth, initialHeight);
246     IntSize alternateSize(initialWidth, alternateHeight);
247
248     // Produce one mailbox at size 100x100.
249     m_drawingBuffer->markContentsChanged();
250     EXPECT_TRUE(m_drawingBuffer->prepareMailbox(&mailbox, 0));
251     EXPECT_EQ(initialSize, webContext()->mostRecentlyProducedSize());
252
253     // Resize to 100x50.
254     m_drawingBuffer->reset(IntSize(initialWidth, alternateHeight));
255     m_drawingBuffer->mailboxReleased(mailbox, false);
256
257     // Produce a mailbox at this size.
258     m_drawingBuffer->markContentsChanged();
259     EXPECT_TRUE(m_drawingBuffer->prepareMailbox(&mailbox, 0));
260     EXPECT_EQ(alternateSize, webContext()->mostRecentlyProducedSize());
261
262     // Reset to initial size.
263     m_drawingBuffer->reset(IntSize(initialWidth, initialHeight));
264     m_drawingBuffer->mailboxReleased(mailbox, false);
265
266     // Prepare another mailbox and verify that it's the correct size.
267     m_drawingBuffer->markContentsChanged();
268     EXPECT_TRUE(m_drawingBuffer->prepareMailbox(&mailbox, 0));
269     EXPECT_EQ(initialSize, webContext()->mostRecentlyProducedSize());
270
271     // Prepare one final mailbox and verify that it's the correct size.
272     m_drawingBuffer->mailboxReleased(mailbox, false);
273     m_drawingBuffer->markContentsChanged();
274     EXPECT_TRUE(m_drawingBuffer->prepareMailbox(&mailbox, 0));
275     EXPECT_EQ(initialSize, webContext()->mostRecentlyProducedSize());
276     m_drawingBuffer->beginDestruction();
277 }
278
279 TEST_F(DrawingBufferTest, verifyDestructionCompleteAfterAllMailboxesReleased)
280 {
281     bool live = true;
282     m_drawingBuffer->m_live = &live;
283
284     WebExternalTextureMailbox mailbox1;
285     WebExternalTextureMailbox mailbox2;
286     WebExternalTextureMailbox mailbox3;
287
288     IntSize initialSize(initialWidth, initialHeight);
289
290     // Produce mailboxes.
291     m_drawingBuffer->markContentsChanged();
292     EXPECT_TRUE(m_drawingBuffer->prepareMailbox(&mailbox1, 0));
293     m_drawingBuffer->markContentsChanged();
294     EXPECT_TRUE(m_drawingBuffer->prepareMailbox(&mailbox2, 0));
295     m_drawingBuffer->markContentsChanged();
296     EXPECT_TRUE(m_drawingBuffer->prepareMailbox(&mailbox3, 0));
297
298     m_drawingBuffer->markContentsChanged();
299     m_drawingBuffer->mailboxReleased(mailbox1, false);
300
301     m_drawingBuffer->beginDestruction();
302     EXPECT_EQ(live, true);
303
304     DrawingBufferForTests* weakPointer = m_drawingBuffer.get();
305     m_drawingBuffer.clear();
306     EXPECT_EQ(live, true);
307
308     weakPointer->markContentsChanged();
309     weakPointer->mailboxReleased(mailbox2, false);
310     EXPECT_EQ(live, true);
311
312     weakPointer->markContentsChanged();
313     weakPointer->mailboxReleased(mailbox3, false);
314     EXPECT_EQ(live, false);
315 }
316
317 TEST_F(DrawingBufferTest, verifyDrawingBufferStaysAliveIfResourcesAreLost)
318 {
319     bool live = true;
320     m_drawingBuffer->m_live = &live;
321     WebExternalTextureMailbox mailbox1;
322     WebExternalTextureMailbox mailbox2;
323     WebExternalTextureMailbox mailbox3;
324
325     m_drawingBuffer->markContentsChanged();
326     EXPECT_TRUE(m_drawingBuffer->prepareMailbox(&mailbox1, 0));
327     m_drawingBuffer->markContentsChanged();
328     EXPECT_TRUE(m_drawingBuffer->prepareMailbox(&mailbox2, 0));
329     m_drawingBuffer->markContentsChanged();
330     EXPECT_TRUE(m_drawingBuffer->prepareMailbox(&mailbox3, 0));
331
332     m_drawingBuffer->markContentsChanged();
333     m_drawingBuffer->mailboxReleased(mailbox1, true);
334     EXPECT_EQ(live, true);
335
336     m_drawingBuffer->beginDestruction();
337     EXPECT_EQ(live, true);
338
339     m_drawingBuffer->markContentsChanged();
340     m_drawingBuffer->mailboxReleased(mailbox2, false);
341     EXPECT_EQ(live, true);
342
343     DrawingBufferForTests* weakPtr = m_drawingBuffer.get();
344     m_drawingBuffer.clear();
345     EXPECT_EQ(live, true);
346
347     weakPtr->markContentsChanged();
348     weakPtr->mailboxReleased(mailbox3, true);
349     EXPECT_EQ(live, false);
350 }
351
352 class TextureMailboxWrapper {
353 public:
354     explicit TextureMailboxWrapper(const WebExternalTextureMailbox& mailbox)
355         : m_mailbox(mailbox)
356     { }
357
358     bool operator==(const TextureMailboxWrapper& other) const
359     {
360         return !memcmp(m_mailbox.name, other.m_mailbox.name, sizeof(m_mailbox.name));
361     }
362
363     bool operator!=(const TextureMailboxWrapper& other) const
364     {
365         return !(*this == other);
366     }
367
368 private:
369     WebExternalTextureMailbox m_mailbox;
370 };
371
372 TEST_F(DrawingBufferTest, verifyOnlyOneRecycledMailboxMustBeKept)
373 {
374     WebExternalTextureMailbox mailbox1;
375     WebExternalTextureMailbox mailbox2;
376     WebExternalTextureMailbox mailbox3;
377
378     // Produce mailboxes.
379     m_drawingBuffer->markContentsChanged();
380     EXPECT_TRUE(m_drawingBuffer->prepareMailbox(&mailbox1, 0));
381     m_drawingBuffer->markContentsChanged();
382     EXPECT_TRUE(m_drawingBuffer->prepareMailbox(&mailbox2, 0));
383     m_drawingBuffer->markContentsChanged();
384     EXPECT_TRUE(m_drawingBuffer->prepareMailbox(&mailbox3, 0));
385
386     // Release mailboxes by specific order; 1, 3, 2.
387     m_drawingBuffer->markContentsChanged();
388     m_drawingBuffer->mailboxReleased(mailbox1, false);
389     m_drawingBuffer->markContentsChanged();
390     m_drawingBuffer->mailboxReleased(mailbox3, false);
391     m_drawingBuffer->markContentsChanged();
392     m_drawingBuffer->mailboxReleased(mailbox2, false);
393
394     // The first recycled mailbox must be 2. 1 and 3 were deleted by FIFO order because
395     // DrawingBuffer never keeps more than one mailbox.
396     WebExternalTextureMailbox recycledMailbox1;
397     m_drawingBuffer->markContentsChanged();
398     EXPECT_TRUE(m_drawingBuffer->prepareMailbox(&recycledMailbox1, 0));
399     EXPECT_EQ(TextureMailboxWrapper(mailbox2), TextureMailboxWrapper(recycledMailbox1));
400
401     // The second recycled mailbox must be a new mailbox.
402     WebExternalTextureMailbox recycledMailbox2;
403     m_drawingBuffer->markContentsChanged();
404     EXPECT_TRUE(m_drawingBuffer->prepareMailbox(&recycledMailbox2, 0));
405     EXPECT_NE(TextureMailboxWrapper(mailbox1), TextureMailboxWrapper(recycledMailbox2));
406     EXPECT_NE(TextureMailboxWrapper(mailbox2), TextureMailboxWrapper(recycledMailbox2));
407     EXPECT_NE(TextureMailboxWrapper(mailbox3), TextureMailboxWrapper(recycledMailbox2));
408
409     m_drawingBuffer->mailboxReleased(recycledMailbox1, false);
410     m_drawingBuffer->mailboxReleased(recycledMailbox2, false);
411     m_drawingBuffer->beginDestruction();
412 }
413
414 TEST_F(DrawingBufferTest, verifyInsertAndWaitSyncPointCorrectly)
415 {
416     WebExternalTextureMailbox mailbox;
417
418     // Produce mailboxes.
419     m_drawingBuffer->markContentsChanged();
420     EXPECT_EQ(0u, webContext()->mostRecentlyWaitedSyncPoint());
421     EXPECT_TRUE(m_drawingBuffer->prepareMailbox(&mailbox, 0));
422     // prepareMailbox() does not wait for any sync point.
423     EXPECT_EQ(0u, webContext()->mostRecentlyWaitedSyncPoint());
424
425     unsigned waitSyncPoint = webContext()->insertSyncPoint();
426     mailbox.syncPoint = waitSyncPoint;
427     m_drawingBuffer->mailboxReleased(mailbox, false);
428     // m_drawingBuffer will wait for the sync point when recycling.
429     EXPECT_EQ(0u, webContext()->mostRecentlyWaitedSyncPoint());
430
431     m_drawingBuffer->markContentsChanged();
432     EXPECT_TRUE(m_drawingBuffer->prepareMailbox(&mailbox, 0));
433     // m_drawingBuffer waits for the sync point when recycling in prepareMailbox().
434     EXPECT_EQ(waitSyncPoint, webContext()->mostRecentlyWaitedSyncPoint());
435
436     m_drawingBuffer->beginDestruction();
437     waitSyncPoint = webContext()->insertSyncPoint();
438     mailbox.syncPoint = waitSyncPoint;
439     m_drawingBuffer->mailboxReleased(mailbox, false);
440     // m_drawingBuffer waits for the sync point because the destruction is in progress.
441     EXPECT_EQ(waitSyncPoint, webContext()->mostRecentlyWaitedSyncPoint());
442 }
443
444 class DrawingBufferImageChromiumTest : public DrawingBufferTest {
445 protected:
446     virtual void SetUp()
447     {
448         RefPtr<FakeContextEvictionManager> contextEvictionManager = adoptRef(new FakeContextEvictionManager());
449         OwnPtr<WebGraphicsContext3DForTests> context = adoptPtr(new WebGraphicsContext3DForTests);
450         m_context = context.get();
451         RuntimeEnabledFeatures::setWebGLImageChromiumEnabled(true);
452         m_imageId0 = webContext()->nextImageIdToBeCreated();
453         EXPECT_CALL(*webContext(), bindTexImage2DMock(m_imageId0)).Times(1);
454         m_drawingBuffer = DrawingBufferForTests::create(context.release(),
455             IntSize(initialWidth, initialHeight), DrawingBuffer::Preserve, contextEvictionManager.release());
456         testing::Mock::VerifyAndClearExpectations(webContext());
457     }
458
459     virtual void TearDown()
460     {
461         RuntimeEnabledFeatures::setWebGLImageChromiumEnabled(false);
462     }
463     WGC3Duint m_imageId0;
464 };
465
466 TEST_F(DrawingBufferImageChromiumTest, verifyResizingReallocatesImages)
467 {
468     WebExternalTextureMailbox mailbox;
469
470     IntSize initialSize(initialWidth, initialHeight);
471     IntSize alternateSize(initialWidth, alternateHeight);
472
473     WGC3Duint m_imageId1 = webContext()->nextImageIdToBeCreated();
474     EXPECT_CALL(*webContext(), bindTexImage2DMock(m_imageId1)).Times(1);
475     // Produce one mailbox at size 100x100.
476     m_drawingBuffer->markContentsChanged();
477     EXPECT_TRUE(m_drawingBuffer->prepareMailbox(&mailbox, 0));
478     EXPECT_EQ(initialSize, webContext()->mostRecentlyProducedSize());
479     EXPECT_TRUE(mailbox.allowOverlay);
480     testing::Mock::VerifyAndClearExpectations(webContext());
481
482     WGC3Duint m_imageId2 = webContext()->nextImageIdToBeCreated();
483     EXPECT_CALL(*webContext(), bindTexImage2DMock(m_imageId2)).Times(1);
484     EXPECT_CALL(*webContext(), destroyImageMock(m_imageId0)).Times(1);
485     EXPECT_CALL(*webContext(), releaseTexImage2DMock(m_imageId0)).Times(1);
486     // Resize to 100x50.
487     m_drawingBuffer->reset(IntSize(initialWidth, alternateHeight));
488     m_drawingBuffer->mailboxReleased(mailbox, false);
489     testing::Mock::VerifyAndClearExpectations(webContext());
490
491     WGC3Duint m_imageId3 = webContext()->nextImageIdToBeCreated();
492     EXPECT_CALL(*webContext(), bindTexImage2DMock(m_imageId3)).Times(1);
493     EXPECT_CALL(*webContext(), destroyImageMock(m_imageId1)).Times(1);
494     EXPECT_CALL(*webContext(), releaseTexImage2DMock(m_imageId1)).Times(1);
495     // Produce a mailbox at this size.
496     m_drawingBuffer->markContentsChanged();
497     EXPECT_TRUE(m_drawingBuffer->prepareMailbox(&mailbox, 0));
498     EXPECT_EQ(alternateSize, webContext()->mostRecentlyProducedSize());
499     EXPECT_TRUE(mailbox.allowOverlay);
500     testing::Mock::VerifyAndClearExpectations(webContext());
501
502     WGC3Duint m_imageId4 = webContext()->nextImageIdToBeCreated();
503     EXPECT_CALL(*webContext(), bindTexImage2DMock(m_imageId4)).Times(1);
504     EXPECT_CALL(*webContext(), destroyImageMock(m_imageId2)).Times(1);
505     EXPECT_CALL(*webContext(), releaseTexImage2DMock(m_imageId2)).Times(1);
506     // Reset to initial size.
507     m_drawingBuffer->reset(IntSize(initialWidth, initialHeight));
508     m_drawingBuffer->mailboxReleased(mailbox, false);
509     testing::Mock::VerifyAndClearExpectations(webContext());
510
511     WGC3Duint m_imageId5 = webContext()->nextImageIdToBeCreated();
512     EXPECT_CALL(*webContext(), bindTexImage2DMock(m_imageId5)).Times(1);
513     EXPECT_CALL(*webContext(), destroyImageMock(m_imageId3)).Times(1);
514     EXPECT_CALL(*webContext(), releaseTexImage2DMock(m_imageId3)).Times(1);
515     // Prepare another mailbox and verify that it's the correct size.
516     m_drawingBuffer->markContentsChanged();
517     EXPECT_TRUE(m_drawingBuffer->prepareMailbox(&mailbox, 0));
518     EXPECT_EQ(initialSize, webContext()->mostRecentlyProducedSize());
519     EXPECT_TRUE(mailbox.allowOverlay);
520     testing::Mock::VerifyAndClearExpectations(webContext());
521
522     // Prepare one final mailbox and verify that it's the correct size.
523     m_drawingBuffer->mailboxReleased(mailbox, false);
524     m_drawingBuffer->markContentsChanged();
525     EXPECT_TRUE(m_drawingBuffer->prepareMailbox(&mailbox, 0));
526     EXPECT_EQ(initialSize, webContext()->mostRecentlyProducedSize());
527     EXPECT_TRUE(mailbox.allowOverlay);
528     m_drawingBuffer->mailboxReleased(mailbox, false);
529
530     EXPECT_CALL(*webContext(), destroyImageMock(m_imageId5)).Times(1);
531     EXPECT_CALL(*webContext(), releaseTexImage2DMock(m_imageId5)).Times(1);
532     EXPECT_CALL(*webContext(), destroyImageMock(m_imageId4)).Times(1);
533     EXPECT_CALL(*webContext(), releaseTexImage2DMock(m_imageId4)).Times(1);
534     m_drawingBuffer->beginDestruction();
535     testing::Mock::VerifyAndClearExpectations(webContext());
536 }
537
538 class DepthStencilTrackingContext : public MockWebGraphicsContext3D {
539 public:
540     DepthStencilTrackingContext()
541         : m_nextRenderBufferId(1)
542         , m_stencilAttachment(0)
543         , m_depthAttachment(0) { }
544     virtual ~DepthStencilTrackingContext() { }
545
546     int numAllocatedRenderBuffer() const { return m_nextRenderBufferId - 1; }
547     WebGLId stencilAttachment() const { return m_stencilAttachment; }
548     WebGLId depthAttachment() const { return m_depthAttachment; }
549
550     virtual WebString getString(WGC3Denum type) OVERRIDE
551     {
552         if (type == GL_EXTENSIONS) {
553             return WebString::fromUTF8("GL_OES_packed_depth_stencil");
554         }
555         return WebString();
556     }
557
558     virtual WebGLId createRenderbuffer() OVERRIDE
559     {
560         return ++m_nextRenderBufferId;
561     }
562
563     virtual void framebufferRenderbuffer(WGC3Denum target, WGC3Denum attachment, WGC3Denum renderbuffertarget, WebGLId renderbuffer) OVERRIDE
564     {
565         if (attachment == GL_STENCIL_ATTACHMENT) {
566             m_stencilAttachment = renderbuffer;
567         } else {
568             m_depthAttachment = renderbuffer;
569         }
570     }
571
572     virtual void getIntegerv(WGC3Denum ptype, WGC3Dint* value) OVERRIDE
573     {
574         switch (ptype) {
575         case GL_DEPTH_BITS:
576             *value = m_depthAttachment ? 24 : 0;
577             return;
578         case GL_STENCIL_BITS:
579             *value = m_stencilAttachment ? 8 : 0;
580             return;
581         }
582         MockWebGraphicsContext3D::getIntegerv(ptype, value);
583     }
584
585 private:
586     WebGLId m_nextRenderBufferId;
587     WebGLId m_stencilAttachment;
588     WebGLId m_depthAttachment;
589 };
590
591 struct DepthStencilTestCase {
592     DepthStencilTestCase(bool requestStencil, bool requestDepth, int expectedRenderBuffers, bool expectDepthStencil, const char* const testCaseName)
593         : requestStencil(requestStencil)
594         , requestDepth(requestDepth)
595         , expectDepthStencil(expectDepthStencil)
596         , expectedRenderBuffers(expectedRenderBuffers)
597         , testCaseName(testCaseName) { }
598
599     bool requestStencil;
600     bool requestDepth;
601     bool expectDepthStencil;
602     int expectedRenderBuffers;
603     const char* const testCaseName;
604 };
605
606 // This tests that when the packed depth+stencil extension is supported DrawingBuffer always allocates
607 // a single packed renderbuffer if either is requested and properly computes the actual context attributes
608 // as defined by WebGL. We always allocate a packed buffer in this case since many desktop OpenGL drivers
609 // that support this extension do not consider a framebuffer with only a depth or a stencil buffer attached
610 // to be complete.
611 TEST(DrawingBufferDepthStencilTest, packedDepthStencilSupported)
612 {
613     DepthStencilTestCase cases[] = {
614         DepthStencilTestCase(false, false, false, 0, "neither"),
615         DepthStencilTestCase(true, false, true, 1, "stencil only"),
616         DepthStencilTestCase(false, true, true, 1, "depth only"),
617         DepthStencilTestCase(true, true, true, 1, "both"),
618     };
619
620     for (size_t i = 0; i < arraysize(cases); i++) {
621         SCOPED_TRACE(cases[i].testCaseName);
622         OwnPtr<DepthStencilTrackingContext> context = adoptPtr(new DepthStencilTrackingContext);
623         DepthStencilTrackingContext* trackingContext = context.get();
624         DrawingBuffer::PreserveDrawingBuffer preserve = DrawingBuffer::Preserve;
625         RefPtr<ContextEvictionManager> contextEvictionManager = adoptRef(new FakeContextEvictionManager);
626
627         WebGraphicsContext3D::Attributes requestedAttributes;
628         requestedAttributes.stencil = cases[i].requestStencil;
629         requestedAttributes.depth = cases[i].requestDepth;
630         RefPtr<DrawingBuffer> drawingBuffer = DrawingBuffer::create(context.release(), IntSize(10, 10), preserve, requestedAttributes, contextEvictionManager);
631
632         EXPECT_EQ(cases[i].requestDepth, drawingBuffer->getActualAttributes().depth);
633         EXPECT_EQ(cases[i].requestStencil, drawingBuffer->getActualAttributes().stencil);
634         EXPECT_EQ(cases[i].expectedRenderBuffers, trackingContext->numAllocatedRenderBuffer());
635         if (cases[i].expectDepthStencil) {
636             EXPECT_EQ(trackingContext->stencilAttachment(), trackingContext->depthAttachment());
637         } else if (cases[i].requestStencil || cases[i].requestDepth) {
638             EXPECT_NE(trackingContext->stencilAttachment(), trackingContext->depthAttachment());
639         } else {
640             EXPECT_EQ(0u, trackingContext->stencilAttachment());
641             EXPECT_EQ(0u, trackingContext->depthAttachment());
642         }
643
644         drawingBuffer->reset(IntSize(10, 20));
645         EXPECT_EQ(cases[i].requestDepth, drawingBuffer->getActualAttributes().depth);
646         EXPECT_EQ(cases[i].requestStencil, drawingBuffer->getActualAttributes().stencil);
647         EXPECT_EQ(cases[i].expectedRenderBuffers, trackingContext->numAllocatedRenderBuffer());
648         if (cases[i].expectDepthStencil) {
649             EXPECT_EQ(trackingContext->stencilAttachment(), trackingContext->depthAttachment());
650         } else if (cases[i].requestStencil || cases[i].requestDepth) {
651             EXPECT_NE(trackingContext->stencilAttachment(), trackingContext->depthAttachment());
652         } else {
653             EXPECT_EQ(0u, trackingContext->stencilAttachment());
654             EXPECT_EQ(0u, trackingContext->depthAttachment());
655         }
656
657         drawingBuffer->beginDestruction();
658     }
659 }
660
661 TEST_F(DrawingBufferTest, verifySetIsHiddenProperlyAffectsMailboxes)
662 {
663     blink::WebExternalTextureMailbox mailbox;
664
665     // Produce mailboxes.
666     m_drawingBuffer->markContentsChanged();
667     EXPECT_TRUE(m_drawingBuffer->prepareMailbox(&mailbox, 0));
668
669     unsigned waitSyncPoint = webContext()->insertSyncPoint();
670     mailbox.syncPoint = waitSyncPoint;
671     m_drawingBuffer->setIsHidden(true);
672     m_drawingBuffer->mailboxReleased(mailbox);
673     // m_drawingBuffer deletes mailbox immediately when hidden.
674     EXPECT_EQ(waitSyncPoint, webContext()->mostRecentlyWaitedSyncPoint());
675
676     m_drawingBuffer->beginDestruction();
677 }
678
679 } // namespace