64d9d71a37c99255e1ec0ad71fd87a52f12a0140
[WebKit-https.git] / Source / WebKit / chromium / tests / LayerRendererChromiumTest.cpp
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 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.
23  */
24
25 #include "config.h"
26 #include "LayerRendererChromium.h"
27
28 #include "CCTestCommon.h"
29 #include "FakeWebGraphicsContext3D.h"
30 #include "GraphicsContext3D.h"
31 #include "GraphicsContext3DPrivate.h"
32 #include "WebCompositor.h"
33 #include "cc/CCDrawQuad.h"
34 #include "cc/CCSettings.h"
35 #include "cc/CCSingleThreadProxy.h"
36
37 #include <gmock/gmock.h>
38 #include <gtest/gtest.h>
39
40 using namespace WebCore;
41 using namespace WebKit;
42 using namespace WebKitTests;
43
44 class FrameCountingMemoryAllocationSettingContext : public FakeWebGraphicsContext3D {
45 public:
46     FrameCountingMemoryAllocationSettingContext() : m_frame(0) { }
47
48     // WebGraphicsContext3D methods.
49
50     // This method would normally do a glSwapBuffers under the hood.
51     virtual void prepareTexture() { m_frame++; }
52     virtual void setMemoryAllocationChangedCallbackCHROMIUM(WebGraphicsMemoryAllocationChangedCallbackCHROMIUM* callback) { m_memoryAllocationChangedCallback = callback; }
53     virtual WebString getString(WebKit::WGC3Denum name)
54     {
55         if (name == GraphicsContext3D::EXTENSIONS)
56             return WebString("GL_CHROMIUM_set_visibility GL_CHROMIUM_gpu_memory_manager GL_CHROMIUM_discard_framebuffer");
57         return WebString();
58     }
59
60     // Methods added for test.
61     int frameCount() { return m_frame; }
62     void setMemoryAllocation(WebGraphicsMemoryAllocation allocation)
63     {
64         ASSERT(CCProxy::isImplThread());
65         // In single threaded mode we expect this callback on main thread.
66         DebugScopedSetMainThread main;
67         m_memoryAllocationChangedCallback->onMemoryAllocationChanged(allocation);
68     }
69
70 private:
71     int m_frame;
72     WebGraphicsMemoryAllocationChangedCallbackCHROMIUM* m_memoryAllocationChangedCallback;
73 };
74
75 class FakeCCRendererClient : public CCRendererClient {
76 public:
77     FakeCCRendererClient()
78         : m_setFullRootLayerDamageCount(0)
79         , m_rootLayer(CCLayerImpl::create(1))
80         , m_memoryAllocationLimitBytes(0)
81     {
82         m_rootLayer->createRenderSurface();
83         m_rootRenderPass = CCRenderPass::create(m_rootLayer->renderSurface());
84     }
85
86     // CCRendererClient methods.
87     virtual const IntSize& deviceViewportSize() const OVERRIDE { static IntSize fakeSize; return fakeSize; }
88     virtual const CCLayerTreeSettings& settings() const OVERRIDE { static CCLayerTreeSettings fakeSettings; return fakeSettings; }
89     virtual void didLoseContext() OVERRIDE { }
90     virtual void onSwapBuffersComplete() OVERRIDE { }
91     virtual void setFullRootLayerDamage() OVERRIDE { m_setFullRootLayerDamageCount++; }
92     virtual void setContentsMemoryAllocationLimitBytes(size_t bytes) OVERRIDE { m_memoryAllocationLimitBytes = bytes; }
93
94     // Methods added for test.
95     int setFullRootLayerDamageCount() const { return m_setFullRootLayerDamageCount; }
96
97     CCRenderPass* rootRenderPass() { return m_rootRenderPass.get(); }
98
99     size_t memoryAllocationLimitBytes() const { return m_memoryAllocationLimitBytes; }
100
101 private:
102     int m_setFullRootLayerDamageCount;
103     DebugScopedSetImplThread m_implThread;
104     OwnPtr<CCLayerImpl> m_rootLayer;
105     OwnPtr<CCRenderPass> m_rootRenderPass;
106     size_t m_memoryAllocationLimitBytes;
107 };
108
109 class FakeLayerRendererChromium : public LayerRendererChromium {
110 public:
111     FakeLayerRendererChromium(CCRendererClient* client, PassRefPtr<GraphicsContext3D> context) : LayerRendererChromium(client, context, UnthrottledUploader) { }
112
113     // LayerRendererChromium methods.
114
115     // Changing visibility to public.
116     using LayerRendererChromium::initialize;
117     using LayerRendererChromium::isFramebufferDiscarded;
118 };
119
120 class LayerRendererChromiumTest : public testing::Test {
121 protected:
122     LayerRendererChromiumTest()
123         : m_suggestHaveBackbufferYes(1, true)
124         , m_suggestHaveBackbufferNo(1, false)
125         , m_context(GraphicsContext3DPrivate::createGraphicsContextFromWebContext(adoptPtr(new FrameCountingMemoryAllocationSettingContext()), GraphicsContext3D::RenderDirectlyToHostWindow))
126         , m_mockContext(*static_cast<FrameCountingMemoryAllocationSettingContext*>(GraphicsContext3DPrivate::extractWebGraphicsContext3D(m_context.get())))
127         , m_layerRendererChromium(&m_mockClient, m_context.release())
128     {
129     }
130
131     virtual void SetUp()
132     {
133         WebKit::WebCompositor::initialize(0);
134         m_layerRendererChromium.initialize();
135     }
136
137     virtual void TearDown()
138     {
139         WebKit::WebCompositor::shutdown();
140     }
141
142     void swapBuffers()
143     {
144         m_layerRendererChromium.swapBuffers(IntRect());
145     }
146
147     WebGraphicsMemoryAllocation m_suggestHaveBackbufferYes;
148     WebGraphicsMemoryAllocation m_suggestHaveBackbufferNo;
149
150     RefPtr<GraphicsContext3D> m_context;
151     FrameCountingMemoryAllocationSettingContext& m_mockContext;
152     FakeCCRendererClient m_mockClient;
153     FakeLayerRendererChromium m_layerRendererChromium;
154     CCScopedSettings m_scopedSettings;
155 };
156
157 // Test LayerRendererChromium discardFramebuffer functionality:
158 // Suggest recreating framebuffer when one already exists.
159 // Expected: it does nothing.
160 TEST_F(LayerRendererChromiumTest, SuggestBackbufferYesWhenItAlreadyExistsShouldDoNothing)
161 {
162     m_mockContext.setMemoryAllocation(m_suggestHaveBackbufferYes);
163     EXPECT_EQ(0, m_mockClient.setFullRootLayerDamageCount());
164     EXPECT_FALSE(m_layerRendererChromium.isFramebufferDiscarded());
165
166     swapBuffers();
167     EXPECT_EQ(1, m_mockContext.frameCount());
168 }
169
170 // Test LayerRendererChromium discardFramebuffer functionality:
171 // Suggest discarding framebuffer when one exists.
172 // Expected: it is discarded and damage tracker is reset.
173 TEST_F(LayerRendererChromiumTest, SuggestBackbufferNoShouldDiscardBackbufferAndDamageRootLayer)
174 {
175     m_mockContext.setMemoryAllocation(m_suggestHaveBackbufferNo);
176     EXPECT_EQ(1, m_mockClient.setFullRootLayerDamageCount());
177     EXPECT_TRUE(m_layerRendererChromium.isFramebufferDiscarded());
178 }
179
180 // Test LayerRendererChromium discardFramebuffer functionality:
181 // Suggest discarding framebuffer when one does not exist.
182 // Expected: it does nothing.
183 TEST_F(LayerRendererChromiumTest, SuggestBackbufferNoWhenItDoesntExistShouldDoNothing)
184 {
185     m_mockContext.setMemoryAllocation(m_suggestHaveBackbufferNo);
186     EXPECT_EQ(1, m_mockClient.setFullRootLayerDamageCount());
187     EXPECT_TRUE(m_layerRendererChromium.isFramebufferDiscarded());
188
189     m_mockContext.setMemoryAllocation(m_suggestHaveBackbufferNo);
190     EXPECT_EQ(1, m_mockClient.setFullRootLayerDamageCount());
191     EXPECT_TRUE(m_layerRendererChromium.isFramebufferDiscarded());
192 }
193
194 // Test LayerRendererChromium discardFramebuffer functionality:
195 // Suggest discarding framebuffer, then try to swapBuffers.
196 // Expected: framebuffer is discarded, swaps are ignored, and damage is reset after discard and after each swap.
197 TEST_F(LayerRendererChromiumTest, SwapBuffersWhileBackbufferDiscardedShouldIgnoreSwapAndDamageRootLayer)
198 {
199     m_mockContext.setMemoryAllocation(m_suggestHaveBackbufferNo);
200     EXPECT_TRUE(m_layerRendererChromium.isFramebufferDiscarded());
201     EXPECT_EQ(1, m_mockClient.setFullRootLayerDamageCount());
202
203     swapBuffers();
204     EXPECT_EQ(0, m_mockContext.frameCount());
205     EXPECT_EQ(2, m_mockClient.setFullRootLayerDamageCount());
206
207     swapBuffers();
208     EXPECT_EQ(0, m_mockContext.frameCount());
209     EXPECT_EQ(3, m_mockClient.setFullRootLayerDamageCount());
210 }
211
212 // Test LayerRendererChromium discardFramebuffer functionality:
213 // Begin drawing a frame while a framebuffer is discarded.
214 // Expected: will recreate framebuffer.
215 TEST_F(LayerRendererChromiumTest, DiscardedBackbufferIsRecreatredForScopeDuration)
216 {
217     m_mockContext.setMemoryAllocation(m_suggestHaveBackbufferNo);
218     EXPECT_TRUE(m_layerRendererChromium.isFramebufferDiscarded());
219     EXPECT_EQ(1, m_mockClient.setFullRootLayerDamageCount());
220
221     m_layerRendererChromium.beginDrawingFrame(m_mockClient.rootRenderPass());
222     EXPECT_FALSE(m_layerRendererChromium.isFramebufferDiscarded());
223
224     swapBuffers();
225     EXPECT_EQ(1, m_mockContext.frameCount());
226 }
227
228 class ForbidSynchronousCallContext : public FakeWebGraphicsContext3D {
229 public:
230     ForbidSynchronousCallContext() { }
231
232     virtual bool getActiveAttrib(WebGLId program, WGC3Duint index, ActiveInfo&) { ADD_FAILURE(); return false; }
233     virtual bool getActiveUniform(WebGLId program, WGC3Duint index, ActiveInfo&) { ADD_FAILURE(); return false; }
234     virtual void getAttachedShaders(WebGLId program, WGC3Dsizei maxCount, WGC3Dsizei* count, WebGLId* shaders) { ADD_FAILURE(); }
235     virtual WGC3Dint getAttribLocation(WebGLId program, const WGC3Dchar* name) { ADD_FAILURE(); return 0; }
236     virtual void getBooleanv(WGC3Denum pname, WGC3Dboolean* value) { ADD_FAILURE(); }
237     virtual void getBufferParameteriv(WGC3Denum target, WGC3Denum pname, WGC3Dint* value) { ADD_FAILURE(); }
238     virtual Attributes getContextAttributes() { ADD_FAILURE(); return m_attrs; }
239     virtual WGC3Denum getError() { ADD_FAILURE(); return 0; }
240     virtual void getFloatv(WGC3Denum pname, WGC3Dfloat* value) { ADD_FAILURE(); }
241     virtual void getFramebufferAttachmentParameteriv(WGC3Denum target, WGC3Denum attachment, WGC3Denum pname, WGC3Dint* value) { ADD_FAILURE(); }
242     virtual void getIntegerv(WGC3Denum pname, WGC3Dint* value)
243     {
244         if (pname == WebCore::GraphicsContext3D::MAX_TEXTURE_SIZE)
245             *value = 1024; // MAX_TEXTURE_SIZE is cached client side, so it's OK to query.
246         else
247             ADD_FAILURE();
248     }
249
250     // We allow querying the shader compilation and program link status in debug mode, but not release.
251     virtual void getProgramiv(WebGLId program, WGC3Denum pname, WGC3Dint* value)
252     {
253 #ifndef NDEBUG
254         *value = 1;
255 #else
256         ADD_FAILURE();
257 #endif
258     }
259
260     virtual void getShaderiv(WebGLId shader, WGC3Denum pname, WGC3Dint* value)
261     {
262 #ifndef NDEBUG
263         *value = 1;
264 #else
265         ADD_FAILURE();
266 #endif
267     }
268
269     virtual WebString getString(WGC3Denum name)
270     {
271         // We allow querying the extension string.
272         // FIXME: It'd be better to check that we only do this before starting any other expensive work (like starting a compilation)
273         if (name != WebCore::GraphicsContext3D::EXTENSIONS)
274             ADD_FAILURE();
275         return WebString();
276     }
277
278     virtual WebString getProgramInfoLog(WebGLId program) { ADD_FAILURE(); return WebString(); }
279     virtual void getRenderbufferParameteriv(WGC3Denum target, WGC3Denum pname, WGC3Dint* value) { ADD_FAILURE(); }
280
281     virtual WebString getShaderInfoLog(WebGLId shader) { ADD_FAILURE(); return WebString(); }
282     virtual void getShaderPrecisionFormat(WGC3Denum shadertype, WGC3Denum precisiontype, WGC3Dint* range, WGC3Dint* precision) { ADD_FAILURE(); }
283     virtual WebString getShaderSource(WebGLId shader) { ADD_FAILURE(); return WebString(); }
284     virtual void getTexParameterfv(WGC3Denum target, WGC3Denum pname, WGC3Dfloat* value) { ADD_FAILURE(); }
285     virtual void getTexParameteriv(WGC3Denum target, WGC3Denum pname, WGC3Dint* value) { ADD_FAILURE(); }
286     virtual void getUniformfv(WebGLId program, WGC3Dint location, WGC3Dfloat* value) { ADD_FAILURE(); }
287     virtual void getUniformiv(WebGLId program, WGC3Dint location, WGC3Dint* value) { ADD_FAILURE(); }
288     virtual WGC3Dint getUniformLocation(WebGLId program, const WGC3Dchar* name) { ADD_FAILURE(); return 0; }
289     virtual void getVertexAttribfv(WGC3Duint index, WGC3Denum pname, WGC3Dfloat* value) { ADD_FAILURE(); }
290     virtual void getVertexAttribiv(WGC3Duint index, WGC3Denum pname, WGC3Dint* value) { ADD_FAILURE(); }
291     virtual WGC3Dsizeiptr getVertexAttribOffset(WGC3Duint index, WGC3Denum pname) { ADD_FAILURE(); return 0; }
292 };
293
294 // This test isn't using the same fixture as LayerRendererChromiumTest, and you can't mix TEST() and TEST_F() with the same name, hence LRC2.
295 TEST(LayerRendererChromiumTest2, initializationDoesNotMakeSynchronousCalls)
296 {
297     CCScopedSettings scopedSettings;
298     FakeCCRendererClient mockClient;
299     FakeLayerRendererChromium layerRendererChromium(&mockClient, GraphicsContext3DPrivate::createGraphicsContextFromWebContext(adoptPtr(new ForbidSynchronousCallContext), GraphicsContext3D::RenderDirectlyToHostWindow));
300
301     EXPECT_TRUE(layerRendererChromium.initialize());
302 }
303
304 class LoseContextOnFirstGetContext : public FakeWebGraphicsContext3D {
305 public:
306     LoseContextOnFirstGetContext()
307         : m_contextLost(false)
308     {
309     }
310
311     virtual bool makeContextCurrent() OVERRIDE
312     {
313         return !m_contextLost;
314     }
315
316     virtual void getProgramiv(WebGLId program, WGC3Denum pname, WGC3Dint* value) OVERRIDE
317     {
318         m_contextLost = true;
319         *value = 0;
320     }
321
322     virtual void getShaderiv(WebGLId shader, WGC3Denum pname, WGC3Dint* value) OVERRIDE
323     {
324         m_contextLost = true;
325         *value = 0;
326     }
327
328     virtual WGC3Denum getGraphicsResetStatusARB() OVERRIDE
329     {
330         return m_contextLost ? 1 : 0;
331     }
332
333 private:
334     bool m_contextLost;
335 };
336
337 TEST(LayerRendererChromiumTest2, initializationWithQuicklyLostContextDoesNotAssert)
338 {
339     CCScopedSettings scopedSettings;
340     FakeCCRendererClient mockClient;
341     FakeLayerRendererChromium layerRendererChromium(&mockClient, GraphicsContext3DPrivate::createGraphicsContextFromWebContext(adoptPtr(new LoseContextOnFirstGetContext), GraphicsContext3D::RenderDirectlyToHostWindow));
342
343     layerRendererChromium.initialize();
344 }
345
346 class ContextThatDoesNotSupportMemoryManagmentExtensions : public FakeWebGraphicsContext3D {
347 public:
348     ContextThatDoesNotSupportMemoryManagmentExtensions() { }
349
350     // WebGraphicsContext3D methods.
351
352     // This method would normally do a glSwapBuffers under the hood.
353     virtual void prepareTexture() { }
354     virtual void setMemoryAllocationChangedCallbackCHROMIUM(WebGraphicsMemoryAllocationChangedCallbackCHROMIUM* callback) { }
355     virtual WebString getString(WebKit::WGC3Denum name) { return WebString(); }
356 };
357
358 TEST(LayerRendererChromiumTest2, initializationWithoutGpuMemoryManagerExtensionSupportShouldDefaultToNonZeroAllocation)
359 {
360     FakeCCRendererClient mockClient;
361     FakeLayerRendererChromium layerRendererChromium(&mockClient, GraphicsContext3DPrivate::createGraphicsContextFromWebContext(adoptPtr(new ContextThatDoesNotSupportMemoryManagmentExtensions), GraphicsContext3D::RenderDirectlyToHostWindow));
362
363     layerRendererChromium.initialize();
364
365     EXPECT_GT(mockClient.memoryAllocationLimitBytes(), 0ul);
366 }
367
368 class ClearCountingContext : public FakeWebGraphicsContext3D {
369 public:
370     ClearCountingContext() : m_clear(0) { }
371
372     virtual void clear(WGC3Dbitfield)
373     {
374         m_clear++;
375     }
376
377     int clearCount() const { return m_clear; }
378
379 private:
380     int m_clear;
381 };
382
383 TEST(LayerRendererChromiumTest2, opaqueBackground)
384 {
385     FakeCCRendererClient mockClient;
386     RefPtr<GraphicsContext3D> context = GraphicsContext3DPrivate::createGraphicsContextFromWebContext(adoptPtr(new ClearCountingContext), GraphicsContext3D::RenderDirectlyToHostWindow);
387     FakeLayerRendererChromium layerRendererChromium(&mockClient, context);
388
389     mockClient.rootRenderPass()->setHasTransparentBackground(false);
390
391     EXPECT_TRUE(layerRendererChromium.initialize());
392
393     layerRendererChromium.beginDrawingFrame(mockClient.rootRenderPass());
394     layerRendererChromium.drawRenderPass(mockClient.rootRenderPass(), FloatRect());
395     layerRendererChromium.finishDrawingFrame();
396
397     // On DEBUG builds, render passes with opaque background clear to blue to
398     // easily see regions that were not drawn on the screen.
399 #if defined(NDEBUG)
400     EXPECT_EQ(0, static_cast<ClearCountingContext*>(GraphicsContext3DPrivate::extractWebGraphicsContext3D(context.get()))->clearCount());
401 #else
402     EXPECT_EQ(1, static_cast<ClearCountingContext*>(GraphicsContext3DPrivate::extractWebGraphicsContext3D(context.get()))->clearCount());
403 #endif
404 }
405
406 TEST(LayerRendererChromiumTest2, transparentBackground)
407 {
408     FakeCCRendererClient mockClient;
409     RefPtr<GraphicsContext3D> context = GraphicsContext3DPrivate::createGraphicsContextFromWebContext(adoptPtr(new ClearCountingContext), GraphicsContext3D::RenderDirectlyToHostWindow);
410     FakeLayerRendererChromium layerRendererChromium(&mockClient, context);
411
412     mockClient.rootRenderPass()->setHasTransparentBackground(true);
413
414     EXPECT_TRUE(layerRendererChromium.initialize());
415
416     layerRendererChromium.beginDrawingFrame(mockClient.rootRenderPass());
417     layerRendererChromium.drawRenderPass(mockClient.rootRenderPass(), FloatRect());
418     layerRendererChromium.finishDrawingFrame();
419
420     EXPECT_EQ(1, static_cast<ClearCountingContext*>(GraphicsContext3DPrivate::extractWebGraphicsContext3D(context.get()))->clearCount());
421 }