| OLD | NEW |
| (Empty) |
| 1 /* | |
| 2 * Copyright (C) 2012 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 | |
| 6 * are met: | |
| 7 * 1. Redistributions of source code must retain the above copyright | |
| 8 * notice, this list of conditions and the following disclaimer. | |
| 9 * 2. Redistributions in binary form must reproduce the above copyright | |
| 10 * notice, this list of conditions and the following disclaimer in the | |
| 11 * documentation and/or other materials provided with the distribution. | |
| 12 * | |
| 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND AN
Y | |
| 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | |
| 15 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |
| 16 * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR AN
Y | |
| 17 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |
| 18 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |
| 19 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND O
N | |
| 20 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
| 21 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |
| 22 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
| 23 */ | |
| 24 | |
| 25 #include "config.h" | |
| 26 | |
| 27 #include "platform/graphics/Canvas2DLayerManager.h" | |
| 28 | |
| 29 #include "SkDevice.h" | |
| 30 #include "SkSurface.h" | |
| 31 #include "public/platform/Platform.h" | |
| 32 #include "public/platform/WebGraphicsContext3DProvider.h" | |
| 33 #include "public/platform/WebThread.h" | |
| 34 #include "web/tests/MockWebGraphicsContext3D.h" | |
| 35 | |
| 36 #include <gmock/gmock.h> | |
| 37 #include <gtest/gtest.h> | |
| 38 | |
| 39 using namespace WebCore; | |
| 40 using testing::InSequence; | |
| 41 using testing::Return; | |
| 42 using testing::Test; | |
| 43 | |
| 44 namespace { | |
| 45 | |
| 46 class MockWebGraphicsContext3DProvider : public blink::WebGraphicsContext3DProvi
der { | |
| 47 public: | |
| 48 MockWebGraphicsContext3DProvider(blink::WebGraphicsContext3D* context3d) | |
| 49 : m_context3d(context3d) { } | |
| 50 | |
| 51 blink::WebGraphicsContext3D* context3d() | |
| 52 { | |
| 53 return m_context3d; | |
| 54 } | |
| 55 | |
| 56 GrContext* grContext() | |
| 57 { | |
| 58 return 0; | |
| 59 } | |
| 60 | |
| 61 private: | |
| 62 blink::WebGraphicsContext3D* m_context3d; | |
| 63 }; | |
| 64 | |
| 65 class FakeCanvas2DLayerBridge : public Canvas2DLayerBridge { | |
| 66 public: | |
| 67 FakeCanvas2DLayerBridge(blink::WebGraphicsContext3D* context, PassOwnPtr<SkD
eferredCanvas> canvas) | |
| 68 : Canvas2DLayerBridge(adoptPtr(new MockWebGraphicsContext3DProvider(cont
ext)), canvas, 0, NonOpaque) | |
| 69 , m_freeableBytes(0) | |
| 70 , m_freeMemoryIfPossibleCount(0) | |
| 71 , m_flushCount(0) | |
| 72 { | |
| 73 } | |
| 74 | |
| 75 virtual size_t storageAllocatedForRecording() OVERRIDE | |
| 76 { | |
| 77 // Because the fake layer has no canvas to query, just | |
| 78 // return status quo. Allocation changes that would normally be | |
| 79 // initiated by the canvas can be faked by invoking | |
| 80 // storageAllocatedForRecordingChanged directly from the test code. | |
| 81 return m_bytesAllocated; | |
| 82 } | |
| 83 | |
| 84 void fakeFreeableBytes(size_t size) | |
| 85 { | |
| 86 m_freeableBytes = size; | |
| 87 } | |
| 88 | |
| 89 virtual size_t freeMemoryIfPossible(size_t size) OVERRIDE | |
| 90 { | |
| 91 m_freeMemoryIfPossibleCount++; | |
| 92 size_t bytesFreed = size < m_freeableBytes ? size : m_freeableBytes; | |
| 93 m_freeableBytes -= bytesFreed; | |
| 94 if (bytesFreed) | |
| 95 storageAllocatedForRecordingChanged(m_bytesAllocated - bytesFreed); | |
| 96 return bytesFreed; | |
| 97 } | |
| 98 | |
| 99 virtual void flush() OVERRIDE | |
| 100 { | |
| 101 flushedDrawCommands(); | |
| 102 m_freeableBytes = bytesAllocated(); | |
| 103 m_flushCount++; | |
| 104 } | |
| 105 | |
| 106 public: | |
| 107 size_t m_freeableBytes; | |
| 108 int m_freeMemoryIfPossibleCount; | |
| 109 int m_flushCount; | |
| 110 }; | |
| 111 | |
| 112 class FakeCanvas2DLayerBridgePtr { | |
| 113 public: | |
| 114 FakeCanvas2DLayerBridgePtr(PassRefPtr<FakeCanvas2DLayerBridge> layerBridge) | |
| 115 : m_layerBridge(layerBridge) { } | |
| 116 | |
| 117 ~FakeCanvas2DLayerBridgePtr() | |
| 118 { | |
| 119 m_layerBridge->beginDestruction(); | |
| 120 } | |
| 121 | |
| 122 FakeCanvas2DLayerBridge* operator->() { return m_layerBridge.get(); } | |
| 123 FakeCanvas2DLayerBridge* get() { return m_layerBridge.get(); } | |
| 124 | |
| 125 private: | |
| 126 RefPtr<FakeCanvas2DLayerBridge> m_layerBridge; | |
| 127 }; | |
| 128 | |
| 129 static PassOwnPtr<SkDeferredCanvas> createCanvas() | |
| 130 { | |
| 131 RefPtr<SkSurface> surface = adoptRef(SkSurface::NewRasterPMColor(1, 1)); | |
| 132 return adoptPtr(SkDeferredCanvas::Create(surface.get())); | |
| 133 } | |
| 134 | |
| 135 } // unnamed namespace | |
| 136 | |
| 137 class Canvas2DLayerManagerTest : public Test { | |
| 138 protected: | |
| 139 void storageAllocationTrackingTest() | |
| 140 { | |
| 141 Canvas2DLayerManager& manager = Canvas2DLayerManager::get(); | |
| 142 manager.init(10, 10); | |
| 143 { | |
| 144 OwnPtr<blink::MockWebGraphicsContext3D> webContext = adoptPtr(new bl
ink::MockWebGraphicsContext3D); | |
| 145 OwnPtr<SkDeferredCanvas> canvas1 = createCanvas(); | |
| 146 FakeCanvas2DLayerBridgePtr layer1(adoptRef(new FakeCanvas2DLayerBrid
ge(webContext.get(), canvas1.release()))); | |
| 147 EXPECT_EQ((size_t)0, manager.m_bytesAllocated); | |
| 148 layer1->storageAllocatedForRecordingChanged(1); | |
| 149 EXPECT_EQ((size_t)1, manager.m_bytesAllocated); | |
| 150 // Test allocation increase | |
| 151 layer1->storageAllocatedForRecordingChanged(2); | |
| 152 EXPECT_EQ((size_t)2, manager.m_bytesAllocated); | |
| 153 // Test allocation decrease | |
| 154 layer1->storageAllocatedForRecordingChanged(1); | |
| 155 EXPECT_EQ((size_t)1, manager.m_bytesAllocated); | |
| 156 { | |
| 157 OwnPtr<SkDeferredCanvas> canvas2 = createCanvas(); | |
| 158 FakeCanvas2DLayerBridgePtr layer2(adoptRef(new FakeCanvas2DLayer
Bridge(webContext.get(), canvas2.release()))); | |
| 159 EXPECT_EQ((size_t)1, manager.m_bytesAllocated); | |
| 160 // verify multi-layer allocation tracking | |
| 161 layer2->storageAllocatedForRecordingChanged(2); | |
| 162 EXPECT_EQ((size_t)3, manager.m_bytesAllocated); | |
| 163 } | |
| 164 // Verify tracking after destruction | |
| 165 EXPECT_EQ((size_t)1, manager.m_bytesAllocated); | |
| 166 } | |
| 167 } | |
| 168 | |
| 169 void evictionTest() | |
| 170 { | |
| 171 OwnPtr<blink::MockWebGraphicsContext3D> webContext = adoptPtr(new blink:
:MockWebGraphicsContext3D); | |
| 172 Canvas2DLayerManager& manager = Canvas2DLayerManager::get(); | |
| 173 manager.init(10, 5); | |
| 174 OwnPtr<SkDeferredCanvas> canvas = createCanvas(); | |
| 175 FakeCanvas2DLayerBridgePtr layer(adoptRef(new FakeCanvas2DLayerBridge(we
bContext.get(), canvas.release()))); | |
| 176 layer->fakeFreeableBytes(10); | |
| 177 layer->storageAllocatedForRecordingChanged(8); // under the max | |
| 178 EXPECT_EQ(0, layer->m_freeMemoryIfPossibleCount); | |
| 179 layer->storageAllocatedForRecordingChanged(12); // over the max | |
| 180 EXPECT_EQ(1, layer->m_freeMemoryIfPossibleCount); | |
| 181 EXPECT_EQ((size_t)3, layer->m_freeableBytes); | |
| 182 EXPECT_EQ(0, layer->m_flushCount); // eviction succeeded without trigger
ing a flush | |
| 183 EXPECT_EQ((size_t)5, layer->bytesAllocated()); | |
| 184 } | |
| 185 | |
| 186 void hiddenCanvasTest() | |
| 187 { | |
| 188 OwnPtr<blink::MockWebGraphicsContext3D> webContext = adoptPtr(new blink:
:MockWebGraphicsContext3D); | |
| 189 Canvas2DLayerManager& manager = Canvas2DLayerManager::get(); | |
| 190 manager.init(20, 5); | |
| 191 OwnPtr<SkDeferredCanvas> canvas = createCanvas(); | |
| 192 FakeCanvas2DLayerBridgePtr layer(adoptRef(new FakeCanvas2DLayerBridge(we
bContext.get(), canvas.release()))); | |
| 193 layer->fakeFreeableBytes(5); | |
| 194 layer->storageAllocatedForRecordingChanged(10); | |
| 195 EXPECT_EQ(0, layer->m_freeMemoryIfPossibleCount); | |
| 196 EXPECT_EQ(0, layer->m_flushCount); | |
| 197 EXPECT_EQ((size_t)10, layer->bytesAllocated()); | |
| 198 layer->setIsHidden(true); | |
| 199 EXPECT_EQ(1, layer->m_freeMemoryIfPossibleCount); | |
| 200 EXPECT_EQ((size_t)0, layer->m_freeableBytes); | |
| 201 EXPECT_EQ((size_t)0, layer->bytesAllocated()); | |
| 202 EXPECT_EQ(1, layer->m_flushCount); | |
| 203 } | |
| 204 | |
| 205 void addRemoveLayerTest() | |
| 206 { | |
| 207 OwnPtr<blink::MockWebGraphicsContext3D> webContext = adoptPtr(new blink:
:MockWebGraphicsContext3D); | |
| 208 Canvas2DLayerManager& manager = Canvas2DLayerManager::get(); | |
| 209 manager.init(10, 5); | |
| 210 OwnPtr<SkDeferredCanvas> canvas = createCanvas(); | |
| 211 FakeCanvas2DLayerBridgePtr layer(adoptRef(new FakeCanvas2DLayerBridge(we
bContext.get(), canvas.release()))); | |
| 212 EXPECT_FALSE(manager.isInList(layer.get())); | |
| 213 layer->storageAllocatedForRecordingChanged(5); | |
| 214 EXPECT_TRUE(manager.isInList(layer.get())); | |
| 215 layer->storageAllocatedForRecordingChanged(0); | |
| 216 EXPECT_FALSE(manager.isInList(layer.get())); | |
| 217 } | |
| 218 | |
| 219 void flushEvictionTest() | |
| 220 { | |
| 221 OwnPtr<blink::MockWebGraphicsContext3D> webContext = adoptPtr(new blink:
:MockWebGraphicsContext3D); | |
| 222 Canvas2DLayerManager& manager = Canvas2DLayerManager::get(); | |
| 223 manager.init(10, 5); | |
| 224 OwnPtr<SkDeferredCanvas> canvas = createCanvas(); | |
| 225 FakeCanvas2DLayerBridgePtr layer(adoptRef(new FakeCanvas2DLayerBridge(we
bContext.get(), canvas.release()))); | |
| 226 layer->fakeFreeableBytes(1); // Not enough freeable bytes, will cause ag
gressive eviction by flushing | |
| 227 layer->storageAllocatedForRecordingChanged(8); // under the max | |
| 228 EXPECT_EQ(0, layer->m_freeMemoryIfPossibleCount); | |
| 229 layer->storageAllocatedForRecordingChanged(12); // over the max | |
| 230 EXPECT_EQ(2, layer->m_freeMemoryIfPossibleCount); // Two tries, one befo
re flush, one after flush | |
| 231 EXPECT_EQ((size_t)5, layer->m_freeableBytes); | |
| 232 EXPECT_EQ(1, layer->m_flushCount); // flush was attempted | |
| 233 EXPECT_EQ((size_t)5, layer->bytesAllocated()); | |
| 234 EXPECT_TRUE(manager.isInList(layer.get())); | |
| 235 } | |
| 236 | |
| 237 void doDeferredFrameTestTask(FakeCanvas2DLayerBridge* layer, bool skipComman
ds) | |
| 238 { | |
| 239 EXPECT_FALSE(Canvas2DLayerManager::get().m_taskObserverActive); | |
| 240 layer->willUse(); | |
| 241 layer->storageAllocatedForRecordingChanged(1); | |
| 242 EXPECT_TRUE(Canvas2DLayerManager::get().m_taskObserverActive); | |
| 243 if (skipCommands) { | |
| 244 layer->willUse(); | |
| 245 layer->skippedPendingDrawCommands(); | |
| 246 } | |
| 247 blink::Platform::current()->currentThread()->exitRunLoop(); | |
| 248 } | |
| 249 | |
| 250 class DeferredFrameTestTask : public blink::WebThread::Task { | |
| 251 public: | |
| 252 DeferredFrameTestTask(Canvas2DLayerManagerTest* test, FakeCanvas2DLayerB
ridge* layer, bool skipCommands) | |
| 253 { | |
| 254 m_test = test; | |
| 255 m_layer = layer; | |
| 256 m_skipCommands = skipCommands; | |
| 257 } | |
| 258 | |
| 259 virtual void run() OVERRIDE | |
| 260 { | |
| 261 m_test->doDeferredFrameTestTask(m_layer, m_skipCommands); | |
| 262 } | |
| 263 private: | |
| 264 Canvas2DLayerManagerTest* m_test; | |
| 265 FakeCanvas2DLayerBridge* m_layer; | |
| 266 bool m_skipCommands; | |
| 267 }; | |
| 268 | |
| 269 void deferredFrameTest() | |
| 270 { | |
| 271 OwnPtr<blink::MockWebGraphicsContext3D> webContext = adoptPtr(new blink:
:MockWebGraphicsContext3D); | |
| 272 Canvas2DLayerManager::get().init(10, 10); | |
| 273 OwnPtr<SkDeferredCanvas> canvas = createCanvas(); | |
| 274 FakeCanvas2DLayerBridgePtr layer(adoptRef(new FakeCanvas2DLayerBridge(we
bContext.get(), canvas.release()))); | |
| 275 blink::Platform::current()->currentThread()->postTask(new DeferredFrameT
estTask(this, layer.get(), true)); | |
| 276 blink::Platform::current()->currentThread()->enterRunLoop(); | |
| 277 // Verify that didProcessTask was called upon completion | |
| 278 EXPECT_FALSE(Canvas2DLayerManager::get().m_taskObserverActive); | |
| 279 // Verify that no flush was performed because frame is fresh | |
| 280 EXPECT_EQ(0, layer->m_flushCount); | |
| 281 | |
| 282 // Verify that no flushes are triggered as long as frame are fresh | |
| 283 blink::Platform::current()->currentThread()->postTask(new DeferredFrameT
estTask(this, layer.get(), true)); | |
| 284 blink::Platform::current()->currentThread()->enterRunLoop(); | |
| 285 EXPECT_FALSE(Canvas2DLayerManager::get().m_taskObserverActive); | |
| 286 EXPECT_EQ(0, layer->m_flushCount); | |
| 287 | |
| 288 blink::Platform::current()->currentThread()->postTask(new DeferredFrameT
estTask(this, layer.get(), true)); | |
| 289 blink::Platform::current()->currentThread()->enterRunLoop(); | |
| 290 EXPECT_FALSE(Canvas2DLayerManager::get().m_taskObserverActive); | |
| 291 EXPECT_EQ(0, layer->m_flushCount); | |
| 292 | |
| 293 // Verify that a flush is triggered when queue is accumulating a multi-f
rame backlog. | |
| 294 blink::Platform::current()->currentThread()->postTask(new DeferredFrameT
estTask(this, layer.get(), false)); | |
| 295 blink::Platform::current()->currentThread()->enterRunLoop(); | |
| 296 EXPECT_FALSE(Canvas2DLayerManager::get().m_taskObserverActive); | |
| 297 EXPECT_EQ(1, layer->m_flushCount); | |
| 298 | |
| 299 blink::Platform::current()->currentThread()->postTask(new DeferredFrameT
estTask(this, layer.get(), false)); | |
| 300 blink::Platform::current()->currentThread()->enterRunLoop(); | |
| 301 EXPECT_FALSE(Canvas2DLayerManager::get().m_taskObserverActive); | |
| 302 EXPECT_EQ(2, layer->m_flushCount); | |
| 303 } | |
| 304 }; | |
| 305 | |
| 306 namespace { | |
| 307 | |
| 308 TEST_F(Canvas2DLayerManagerTest, testStorageAllocationTracking) | |
| 309 { | |
| 310 storageAllocationTrackingTest(); | |
| 311 } | |
| 312 | |
| 313 TEST_F(Canvas2DLayerManagerTest, testEviction) | |
| 314 { | |
| 315 evictionTest(); | |
| 316 } | |
| 317 | |
| 318 TEST_F(Canvas2DLayerManagerTest, testFlushEviction) | |
| 319 { | |
| 320 flushEvictionTest(); | |
| 321 } | |
| 322 | |
| 323 TEST_F(Canvas2DLayerManagerTest, testDeferredFrame) | |
| 324 { | |
| 325 deferredFrameTest(); | |
| 326 } | |
| 327 | |
| 328 TEST_F(Canvas2DLayerManagerTest, testHiddenCanvas) | |
| 329 { | |
| 330 hiddenCanvasTest(); | |
| 331 } | |
| 332 | |
| 333 TEST_F(Canvas2DLayerManagerTest, testAddRemoveLayer) | |
| 334 { | |
| 335 addRemoveLayerTest(); | |
| 336 } | |
| 337 | |
| 338 } // unnamed namespace | |
| 339 | |
| OLD | NEW |