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