2
* Copyright (C) 2012 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
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.
13
* THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
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 ANY
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 ON
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.
27
#include "Canvas2DLayerManager.h"
29
#include "FakeWebGraphicsContext3D.h"
30
#include "GraphicsContext3DPrivate.h"
31
#include <gmock/gmock.h>
32
#include <gtest/gtest.h>
33
#include <public/Platform.h>
34
#include <public/WebThread.h>
36
using namespace WebCore;
37
using testing::InSequence;
38
using testing::Return;
42
class FakeCanvas2DLayerBridge : public Canvas2DLayerBridge {
44
FakeCanvas2DLayerBridge()
45
: Canvas2DLayerBridge(GraphicsContext3DPrivate::createGraphicsContextFromWebContext(adoptPtr(new WebKit::FakeWebGraphicsContext3D)), IntSize(1, 1), Deferred, 0)
47
, m_freeMemoryIfPossibleCount(0)
52
virtual size_t storageAllocatedForRecording() OVERRIDE
54
// Because the fake layer has no canvas to query, just
55
// return status quo. Allocation changes that would normally be
56
// initiated by the canvas can be faked by invoking
57
// storageAllocatedForRecordingChanged directly from the test code.
58
return m_bytesAllocated;
61
void fakeFreeableBytes(size_t size)
63
m_freeableBytes = size;
66
virtual size_t freeMemoryIfPossible(size_t size) OVERRIDE
68
m_freeMemoryIfPossibleCount++;
69
size_t bytesFreed = size < m_freeableBytes ? size : m_freeableBytes;
70
m_freeableBytes -= bytesFreed;
72
Canvas2DLayerManager::get().layerAllocatedStorageChanged(this, -((intptr_t)bytesFreed));
73
m_bytesAllocated -= bytesFreed;
77
virtual void flush() OVERRIDE
79
flushedDrawCommands();
84
size_t m_freeableBytes;
85
int m_freeMemoryIfPossibleCount;
89
class Canvas2DLayerManagerTest : public Test {
91
void storageAllocationTrackingTest()
93
Canvas2DLayerManager& manager = Canvas2DLayerManager::get();
96
FakeCanvas2DLayerBridge layer1;
97
EXPECT_EQ((size_t)0, manager.m_bytesAllocated);
98
layer1.storageAllocatedForRecordingChanged(1);
99
EXPECT_EQ((size_t)1, manager.m_bytesAllocated);
100
// Test allocation increase
101
layer1.storageAllocatedForRecordingChanged(2);
102
EXPECT_EQ((size_t)2, manager.m_bytesAllocated);
103
// Test allocation decrease
104
layer1.storageAllocatedForRecordingChanged(1);
105
EXPECT_EQ((size_t)1, manager.m_bytesAllocated);
107
FakeCanvas2DLayerBridge layer2;
108
EXPECT_EQ((size_t)1, manager.m_bytesAllocated);
109
// verify multi-layer allocation tracking
110
layer2.storageAllocatedForRecordingChanged(2);
111
EXPECT_EQ((size_t)3, manager.m_bytesAllocated);
113
// Verify tracking after destruction
114
EXPECT_EQ((size_t)1, manager.m_bytesAllocated);
120
Canvas2DLayerManager& manager = Canvas2DLayerManager::get();
122
FakeCanvas2DLayerBridge layer;
123
layer.fakeFreeableBytes(10);
124
layer.storageAllocatedForRecordingChanged(8); // under the max
125
EXPECT_EQ(0, layer.m_freeMemoryIfPossibleCount);
126
layer.storageAllocatedForRecordingChanged(12); // over the max
127
EXPECT_EQ(1, layer.m_freeMemoryIfPossibleCount);
128
EXPECT_EQ((size_t)3, layer.m_freeableBytes);
129
EXPECT_EQ(0, layer.m_flushCount); // eviction succeeded without triggering a flush
130
EXPECT_EQ((size_t)5, layer.bytesAllocated());
133
void flushEvictionTest()
135
Canvas2DLayerManager& manager = Canvas2DLayerManager::get();
137
FakeCanvas2DLayerBridge layer;
138
layer.fakeFreeableBytes(1); // Not enough freeable bytes, will cause aggressive eviction by flushing
139
layer.storageAllocatedForRecordingChanged(8); // under the max
140
EXPECT_EQ(0, layer.m_freeMemoryIfPossibleCount);
141
layer.storageAllocatedForRecordingChanged(12); // over the max
142
EXPECT_EQ(2, layer.m_freeMemoryIfPossibleCount); // Two tries, one before flush, one after flush
143
EXPECT_EQ((size_t)0, layer.m_freeableBytes);
144
EXPECT_EQ(1, layer.m_flushCount); // flush was attempted
145
EXPECT_EQ((size_t)11, layer.bytesAllocated()); // flush drops the layer from manager's tracking list
146
EXPECT_FALSE(manager.isInList(&layer));
149
void doDeferredFrameTestTask(FakeCanvas2DLayerBridge* layer, bool skipCommands)
151
EXPECT_FALSE(Canvas2DLayerManager::get().m_taskObserverActive);
152
layer->contextAcquired();
153
layer->storageAllocatedForRecordingChanged(1);
154
EXPECT_TRUE(Canvas2DLayerManager::get().m_taskObserverActive);
156
layer->contextAcquired();
157
layer->storageAllocatedForRecordingChanged(0);
158
layer->skippedPendingDrawCommands();
160
WebKit::Platform::current()->currentThread()->exitRunLoop();
163
class DeferredFrameTestTask : public WebKit::WebThread::Task {
165
DeferredFrameTestTask(Canvas2DLayerManagerTest* test, FakeCanvas2DLayerBridge* layer, bool skipCommands)
169
m_skipCommands = skipCommands;
172
virtual void run() OVERRIDE
174
m_test->doDeferredFrameTestTask(m_layer, m_skipCommands);
177
Canvas2DLayerManagerTest* m_test;
178
FakeCanvas2DLayerBridge* m_layer;
182
void deferredFrameTest()
184
Canvas2DLayerManager::get().init(10, 10);
185
FakeCanvas2DLayerBridge fakeLayer;
186
WebKit::Platform::current()->currentThread()->postTask(new DeferredFrameTestTask(this, &fakeLayer, true));
187
WebKit::Platform::current()->currentThread()->enterRunLoop();
188
// Verify that didProcessTask was called upon completion
189
EXPECT_FALSE(Canvas2DLayerManager::get().m_taskObserverActive);
190
// Verify that no flush was performed because frame is fresh
191
EXPECT_EQ(0, fakeLayer.m_flushCount);
193
// Verify that no flushes are triggered as long as frame are fresh
194
WebKit::Platform::current()->currentThread()->postTask(new DeferredFrameTestTask(this, &fakeLayer, true));
195
WebKit::Platform::current()->currentThread()->enterRunLoop();
196
EXPECT_FALSE(Canvas2DLayerManager::get().m_taskObserverActive);
197
EXPECT_EQ(0, fakeLayer.m_flushCount);
199
WebKit::Platform::current()->currentThread()->postTask(new DeferredFrameTestTask(this, &fakeLayer, true));
200
WebKit::Platform::current()->currentThread()->enterRunLoop();
201
EXPECT_FALSE(Canvas2DLayerManager::get().m_taskObserverActive);
202
EXPECT_EQ(0, fakeLayer.m_flushCount);
204
// Verify that a flush is triggered every two frames when they are stale.
205
WebKit::Platform::current()->currentThread()->postTask(new DeferredFrameTestTask(this, &fakeLayer, false));
206
WebKit::Platform::current()->currentThread()->enterRunLoop();
207
EXPECT_FALSE(Canvas2DLayerManager::get().m_taskObserverActive);
208
EXPECT_EQ(1, fakeLayer.m_flushCount);
210
WebKit::Platform::current()->currentThread()->postTask(new DeferredFrameTestTask(this, &fakeLayer, false));
211
WebKit::Platform::current()->currentThread()->enterRunLoop();
212
EXPECT_FALSE(Canvas2DLayerManager::get().m_taskObserverActive);
213
EXPECT_EQ(1, fakeLayer.m_flushCount);
215
WebKit::Platform::current()->currentThread()->postTask(new DeferredFrameTestTask(this, &fakeLayer, false));
216
WebKit::Platform::current()->currentThread()->enterRunLoop();
217
EXPECT_FALSE(Canvas2DLayerManager::get().m_taskObserverActive);
218
EXPECT_EQ(2, fakeLayer.m_flushCount);
220
WebKit::Platform::current()->currentThread()->postTask(new DeferredFrameTestTask(this, &fakeLayer, false));
221
WebKit::Platform::current()->currentThread()->enterRunLoop();
222
EXPECT_FALSE(Canvas2DLayerManager::get().m_taskObserverActive);
223
EXPECT_EQ(2, fakeLayer.m_flushCount);
229
TEST_F(Canvas2DLayerManagerTest, testStorageAllocationTracking)
231
storageAllocationTrackingTest();
234
TEST_F(Canvas2DLayerManagerTest, testEviction)
239
TEST_F(Canvas2DLayerManagerTest, testFlushEviction)
244
TEST_F(Canvas2DLayerManagerTest, testDeferredFrame)