2 * Copyright (C) 2013 Google Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
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
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.
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.
33 #include "platform/graphics/gpu/DrawingBuffer.h"
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"
44 #include <gmock/gmock.h>
45 #include <gtest/gtest.h>
47 using namespace blink;
53 class FakeContextEvictionManager : public ContextEvictionManager {
55 void forciblyLoseOldestContext(const String& reason) { }
56 IntSize oldestContextSize() { return IntSize(); }
59 class WebGraphicsContext3DForTests : public MockWebGraphicsContext3D {
61 WebGraphicsContext3DForTests()
62 : MockWebGraphicsContext3D()
64 , m_currentMailboxByte(0)
65 , m_mostRecentlyWaitedSyncPoint(0)
66 , m_currentImageId(1) { }
68 virtual void bindTexture(WGC3Denum target, WebGLId texture)
70 if (target == GL_TEXTURE_2D) {
71 m_boundTexture = texture;
75 virtual void texImage2D(WGC3Denum target, WGC3Dint level, WGC3Denum internalformat, WGC3Dsizei width, WGC3Dsizei height, WGC3Dint border, WGC3Denum format, WGC3Denum type, const void* pixels)
77 if (target == GL_TEXTURE_2D && !level) {
78 m_textureSizes.set(m_boundTexture, IntSize(width, height));
82 virtual void genMailboxCHROMIUM(WGC3Dbyte* mailbox)
84 ++m_currentMailboxByte;
85 WebExternalTextureMailbox temp;
86 memset(mailbox, m_currentMailboxByte, sizeof(temp.name));
89 virtual void produceTextureDirectCHROMIUM(WebGLId texture, WGC3Denum target, const WGC3Dbyte* mailbox)
91 ASSERT_EQ(target, static_cast<WGC3Denum>(GL_TEXTURE_2D));
92 ASSERT_TRUE(m_textureSizes.contains(texture));
93 m_mostRecentlyProducedSize = m_textureSizes.get(texture);
96 IntSize mostRecentlyProducedSize()
98 return m_mostRecentlyProducedSize;
101 virtual unsigned insertSyncPoint()
103 static unsigned syncPointGenerator = 0;
104 return ++syncPointGenerator;
107 virtual void waitSyncPoint(unsigned syncPoint)
109 m_mostRecentlyWaitedSyncPoint = syncPoint;
112 virtual WGC3Duint createImageCHROMIUM(WGC3Dsizei width, WGC3Dsizei height, WGC3Denum internalformat, WGC3Denum usage)
114 m_imageSizes.set(m_currentImageId, IntSize(width, height));
115 return m_currentImageId++;
118 MOCK_METHOD1(destroyImageMock, void(WGC3Duint imageId));
119 void destroyImageCHROMIUM(WGC3Duint imageId)
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);
128 MOCK_METHOD1(bindTexImage2DMock, void(WGC3Dint imageId));
129 void bindTexImage2DCHROMIUM(WGC3Denum target, WGC3Dint imageId)
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);
138 MOCK_METHOD1(releaseTexImage2DMock, void(WGC3Dint imageId));
139 void releaseTexImage2DCHROMIUM(WGC3Denum target, WGC3Dint imageId)
141 if (target == GL_TEXTURE_2D) {
142 m_imageSizes.set(m_currentImageId, IntSize());
143 m_imageToTextureMap.remove(imageId);
144 releaseTexImage2DMock(imageId);
148 unsigned mostRecentlyWaitedSyncPoint()
150 return m_mostRecentlyWaitedSyncPoint;
153 WGC3Duint nextImageIdToBeCreated()
155 return m_currentImageId;
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;
169 static const int initialWidth = 100;
170 static const int initialHeight = 100;
171 static const int alternateHeight = 50;
173 class DrawingBufferForTests : public DrawingBuffer {
175 static PassRefPtr<DrawingBufferForTests> create(PassOwnPtr<WebGraphicsContext3D> context,
176 const IntSize& size, PreserveDrawingBuffer preserve, PassRefPtr<ContextEvictionManager> contextEvictionManager)
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>();
185 return drawingBuffer.release();
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)
197 virtual ~DrawingBufferForTests()
206 class DrawingBufferTest : public Test {
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());
217 WebGraphicsContext3DForTests* webContext()
222 WebGraphicsContext3DForTests* m_context;
223 RefPtr<DrawingBufferForTests> m_drawingBuffer;
226 TEST_F(DrawingBufferTest, testPaintRenderingResultsToCanvas)
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();
241 TEST_F(DrawingBufferTest, verifyResizingProperlyAffectsMailboxes)
243 WebExternalTextureMailbox mailbox;
245 IntSize initialSize(initialWidth, initialHeight);
246 IntSize alternateSize(initialWidth, alternateHeight);
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());
254 m_drawingBuffer->reset(IntSize(initialWidth, alternateHeight));
255 m_drawingBuffer->mailboxReleased(mailbox, false);
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());
262 // Reset to initial size.
263 m_drawingBuffer->reset(IntSize(initialWidth, initialHeight));
264 m_drawingBuffer->mailboxReleased(mailbox, false);
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());
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();
279 TEST_F(DrawingBufferTest, verifyDestructionCompleteAfterAllMailboxesReleased)
282 m_drawingBuffer->m_live = &live;
284 WebExternalTextureMailbox mailbox1;
285 WebExternalTextureMailbox mailbox2;
286 WebExternalTextureMailbox mailbox3;
288 IntSize initialSize(initialWidth, initialHeight);
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));
298 m_drawingBuffer->markContentsChanged();
299 m_drawingBuffer->mailboxReleased(mailbox1, false);
301 m_drawingBuffer->beginDestruction();
302 EXPECT_EQ(live, true);
304 DrawingBufferForTests* weakPointer = m_drawingBuffer.get();
305 m_drawingBuffer.clear();
306 EXPECT_EQ(live, true);
308 weakPointer->markContentsChanged();
309 weakPointer->mailboxReleased(mailbox2, false);
310 EXPECT_EQ(live, true);
312 weakPointer->markContentsChanged();
313 weakPointer->mailboxReleased(mailbox3, false);
314 EXPECT_EQ(live, false);
317 TEST_F(DrawingBufferTest, verifyDrawingBufferStaysAliveIfResourcesAreLost)
320 m_drawingBuffer->m_live = &live;
321 WebExternalTextureMailbox mailbox1;
322 WebExternalTextureMailbox mailbox2;
323 WebExternalTextureMailbox mailbox3;
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));
332 m_drawingBuffer->markContentsChanged();
333 m_drawingBuffer->mailboxReleased(mailbox1, true);
334 EXPECT_EQ(live, true);
336 m_drawingBuffer->beginDestruction();
337 EXPECT_EQ(live, true);
339 m_drawingBuffer->markContentsChanged();
340 m_drawingBuffer->mailboxReleased(mailbox2, false);
341 EXPECT_EQ(live, true);
343 DrawingBufferForTests* weakPtr = m_drawingBuffer.get();
344 m_drawingBuffer.clear();
345 EXPECT_EQ(live, true);
347 weakPtr->markContentsChanged();
348 weakPtr->mailboxReleased(mailbox3, true);
349 EXPECT_EQ(live, false);
352 class TextureMailboxWrapper {
354 explicit TextureMailboxWrapper(const WebExternalTextureMailbox& mailbox)
358 bool operator==(const TextureMailboxWrapper& other) const
360 return !memcmp(m_mailbox.name, other.m_mailbox.name, sizeof(m_mailbox.name));
363 bool operator!=(const TextureMailboxWrapper& other) const
365 return !(*this == other);
369 WebExternalTextureMailbox m_mailbox;
372 TEST_F(DrawingBufferTest, verifyOnlyOneRecycledMailboxMustBeKept)
374 WebExternalTextureMailbox mailbox1;
375 WebExternalTextureMailbox mailbox2;
376 WebExternalTextureMailbox mailbox3;
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));
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);
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));
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));
409 m_drawingBuffer->mailboxReleased(recycledMailbox1, false);
410 m_drawingBuffer->mailboxReleased(recycledMailbox2, false);
411 m_drawingBuffer->beginDestruction();
414 TEST_F(DrawingBufferTest, verifyInsertAndWaitSyncPointCorrectly)
416 WebExternalTextureMailbox mailbox;
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());
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());
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());
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());
444 class DrawingBufferImageChromiumTest : public DrawingBufferTest {
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());
459 virtual void TearDown()
461 RuntimeEnabledFeatures::setWebGLImageChromiumEnabled(false);
463 WGC3Duint m_imageId0;
466 TEST_F(DrawingBufferImageChromiumTest, verifyResizingReallocatesImages)
468 WebExternalTextureMailbox mailbox;
470 IntSize initialSize(initialWidth, initialHeight);
471 IntSize alternateSize(initialWidth, alternateHeight);
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());
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);
487 m_drawingBuffer->reset(IntSize(initialWidth, alternateHeight));
488 m_drawingBuffer->mailboxReleased(mailbox, false);
489 testing::Mock::VerifyAndClearExpectations(webContext());
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());
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());
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());
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);
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());
538 class DepthStencilTrackingContext : public MockWebGraphicsContext3D {
540 DepthStencilTrackingContext()
541 : m_nextRenderBufferId(1)
542 , m_stencilAttachment(0)
543 , m_depthAttachment(0) { }
544 virtual ~DepthStencilTrackingContext() { }
546 int numAllocatedRenderBuffer() const { return m_nextRenderBufferId - 1; }
547 WebGLId stencilAttachment() const { return m_stencilAttachment; }
548 WebGLId depthAttachment() const { return m_depthAttachment; }
550 virtual WebString getString(WGC3Denum type) OVERRIDE
552 if (type == GL_EXTENSIONS) {
553 return WebString::fromUTF8("GL_OES_packed_depth_stencil");
558 virtual WebGLId createRenderbuffer() OVERRIDE
560 return ++m_nextRenderBufferId;
563 virtual void framebufferRenderbuffer(WGC3Denum target, WGC3Denum attachment, WGC3Denum renderbuffertarget, WebGLId renderbuffer) OVERRIDE
565 if (attachment == GL_STENCIL_ATTACHMENT) {
566 m_stencilAttachment = renderbuffer;
568 m_depthAttachment = renderbuffer;
572 virtual void getIntegerv(WGC3Denum ptype, WGC3Dint* value) OVERRIDE
576 *value = m_depthAttachment ? 24 : 0;
578 case GL_STENCIL_BITS:
579 *value = m_stencilAttachment ? 8 : 0;
582 MockWebGraphicsContext3D::getIntegerv(ptype, value);
586 WebGLId m_nextRenderBufferId;
587 WebGLId m_stencilAttachment;
588 WebGLId m_depthAttachment;
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) { }
601 bool expectDepthStencil;
602 int expectedRenderBuffers;
603 const char* const testCaseName;
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
611 TEST(DrawingBufferDepthStencilTest, packedDepthStencilSupported)
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"),
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);
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);
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());
640 EXPECT_EQ(0u, trackingContext->stencilAttachment());
641 EXPECT_EQ(0u, trackingContext->depthAttachment());
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());
653 EXPECT_EQ(0u, trackingContext->stencilAttachment());
654 EXPECT_EQ(0u, trackingContext->depthAttachment());
657 drawingBuffer->beginDestruction();
661 TEST_F(DrawingBufferTest, verifySetIsHiddenProperlyAffectsMailboxes)
663 blink::WebExternalTextureMailbox mailbox;
665 // Produce mailboxes.
666 m_drawingBuffer->markContentsChanged();
667 EXPECT_TRUE(m_drawingBuffer->prepareMailbox(&mailbox, 0));
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());
676 m_drawingBuffer->beginDestruction();