[chromium] LayerRendererChromium is not getting visibility messages in single threade...
[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(1, 1); 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 releaseContentsTextures() OVERRIDE { }
93     virtual void setMemoryAllocationLimitBytes(size_t bytes) OVERRIDE { m_memoryAllocationLimitBytes = bytes; }
94
95     // Methods added for test.
96     int setFullRootLayerDamageCount() const { return m_setFullRootLayerDamageCount; }
97
98     CCRenderPass* rootRenderPass() { return m_rootRenderPass.get(); }
99
100     size_t memoryAllocationLimitBytes() const { return m_memoryAllocationLimitBytes; }
101
102 private:
103     int m_setFullRootLayerDamageCount;
104     DebugScopedSetImplThread m_implThread;
105     OwnPtr<CCLayerImpl> m_rootLayer;
106     OwnPtr<CCRenderPass> m_rootRenderPass;
107     size_t m_memoryAllocationLimitBytes;
108 };
109
110 class FakeLayerRendererChromium : public LayerRendererChromium {
111 public:
112     FakeLayerRendererChromium(CCRendererClient* client, PassRefPtr<GraphicsContext3D> context) : LayerRendererChromium(client, context, UnthrottledUploader) { }
113
114     // LayerRendererChromium methods.
115
116     // Changing visibility to public.
117     using LayerRendererChromium::initialize;
118     using LayerRendererChromium::isFramebufferDiscarded;
119 };
120
121 class LayerRendererChromiumTest : public testing::Test {
122 protected:
123     LayerRendererChromiumTest()
124         : m_suggestHaveBackbufferYes(1, true)
125         , m_suggestHaveBackbufferNo(1, false)
126         , m_context(GraphicsContext3DPrivate::createGraphicsContextFromWebContext(adoptPtr(new FrameCountingMemoryAllocationSettingContext()), GraphicsContext3D::RenderDirectlyToHostWindow))
127         , m_mockContext(*static_cast<FrameCountingMemoryAllocationSettingContext*>(GraphicsContext3DPrivate::extractWebGraphicsContext3D(m_context.get())))
128         , m_layerRendererChromium(&m_mockClient, m_context.release())
129     {
130     }
131
132     virtual void SetUp()
133     {
134         WebKit::WebCompositor::initialize(0);
135         m_layerRendererChromium.initialize();
136     }
137
138     virtual void TearDown()
139     {
140         WebKit::WebCompositor::shutdown();
141     }
142
143     void swapBuffers()
144     {
145         m_layerRendererChromium.swapBuffers(IntRect());
146     }
147
148     WebGraphicsMemoryAllocation m_suggestHaveBackbufferYes;
149     WebGraphicsMemoryAllocation m_suggestHaveBackbufferNo;
150
151     RefPtr<GraphicsContext3D> m_context;
152     FrameCountingMemoryAllocationSettingContext& m_mockContext;
153     FakeCCRendererClient m_mockClient;
154     FakeLayerRendererChromium m_layerRendererChromium;
155     CCScopedSettings m_scopedSettings;
156 };
157
158 // Test LayerRendererChromium discardFramebuffer functionality:
159 // Suggest recreating framebuffer when one already exists.
160 // Expected: it does nothing.
161 TEST_F(LayerRendererChromiumTest, SuggestBackbufferYesWhenItAlreadyExistsShouldDoNothing)
162 {
163     m_mockContext.setMemoryAllocation(m_suggestHaveBackbufferYes);
164     EXPECT_EQ(0, m_mockClient.setFullRootLayerDamageCount());
165     EXPECT_FALSE(m_layerRendererChromium.isFramebufferDiscarded());
166
167     swapBuffers();
168     EXPECT_EQ(1, m_mockContext.frameCount());
169 }
170
171 // Test LayerRendererChromium discardFramebuffer functionality:
172 // Suggest discarding framebuffer when one exists and the renderer is not visible.
173 // Expected: it is discarded and damage tracker is reset.
174 TEST_F(LayerRendererChromiumTest, SuggestBackbufferNoShouldDiscardBackbufferAndDamageRootLayerWhileNotVisible)
175 {
176     m_layerRendererChromium.setVisible(false);
177     m_mockContext.setMemoryAllocation(m_suggestHaveBackbufferNo);
178     EXPECT_EQ(1, m_mockClient.setFullRootLayerDamageCount());
179     EXPECT_TRUE(m_layerRendererChromium.isFramebufferDiscarded());
180 }
181
182 // Test LayerRendererChromium discardFramebuffer functionality:
183 // Suggest discarding framebuffer when one exists and the renderer is visible.
184 // Expected: the allocation is ignored.
185 TEST_F(LayerRendererChromiumTest, SuggestBackbufferNoDoNothingWhenVisible)
186 {
187     m_layerRendererChromium.setVisible(true);
188     m_mockContext.setMemoryAllocation(m_suggestHaveBackbufferNo);
189     EXPECT_EQ(0, m_mockClient.setFullRootLayerDamageCount());
190     EXPECT_FALSE(m_layerRendererChromium.isFramebufferDiscarded());
191 }
192
193
194 // Test LayerRendererChromium discardFramebuffer functionality:
195 // Suggest discarding framebuffer when one does not exist.
196 // Expected: it does nothing.
197 TEST_F(LayerRendererChromiumTest, SuggestBackbufferNoWhenItDoesntExistShouldDoNothing)
198 {
199     m_layerRendererChromium.setVisible(false);
200     m_mockContext.setMemoryAllocation(m_suggestHaveBackbufferNo);
201     EXPECT_EQ(1, m_mockClient.setFullRootLayerDamageCount());
202     EXPECT_TRUE(m_layerRendererChromium.isFramebufferDiscarded());
203
204     m_mockContext.setMemoryAllocation(m_suggestHaveBackbufferNo);
205     EXPECT_EQ(1, m_mockClient.setFullRootLayerDamageCount());
206     EXPECT_TRUE(m_layerRendererChromium.isFramebufferDiscarded());
207 }
208
209 // Test LayerRendererChromium discardFramebuffer functionality:
210 // Begin drawing a frame while a framebuffer is discarded.
211 // Expected: will recreate framebuffer.
212 TEST_F(LayerRendererChromiumTest, DiscardedBackbufferIsRecreatedForScopeDuration)
213 {
214     m_layerRendererChromium.setVisible(false);
215     m_mockContext.setMemoryAllocation(m_suggestHaveBackbufferNo);
216     EXPECT_TRUE(m_layerRendererChromium.isFramebufferDiscarded());
217     EXPECT_EQ(1, m_mockClient.setFullRootLayerDamageCount());
218
219     m_layerRendererChromium.setVisible(true);
220     m_layerRendererChromium.beginDrawingFrame(m_mockClient.rootRenderPass());
221     EXPECT_FALSE(m_layerRendererChromium.isFramebufferDiscarded());
222
223     swapBuffers();
224     EXPECT_EQ(1, m_mockContext.frameCount());
225 }
226
227 TEST_F(LayerRendererChromiumTest, FramebufferDiscardedAfterReadbackWhenNotVisible)
228 {
229     m_layerRendererChromium.setVisible(false);
230     m_mockContext.setMemoryAllocation(m_suggestHaveBackbufferNo);
231     EXPECT_TRUE(m_layerRendererChromium.isFramebufferDiscarded());
232     EXPECT_EQ(1, m_mockClient.setFullRootLayerDamageCount());
233
234     char pixels[4];
235     m_layerRendererChromium.beginDrawingFrame(m_mockClient.rootRenderPass());
236     EXPECT_FALSE(m_layerRendererChromium.isFramebufferDiscarded());
237
238     m_layerRendererChromium.getFramebufferPixels(pixels, IntRect(0, 0, 1, 1));
239     EXPECT_TRUE(m_layerRendererChromium.isFramebufferDiscarded());
240     EXPECT_EQ(2, m_mockClient.setFullRootLayerDamageCount());
241 }
242
243 class ForbidSynchronousCallContext : public FakeWebGraphicsContext3D {
244 public:
245     ForbidSynchronousCallContext() { }
246
247     virtual bool getActiveAttrib(WebGLId program, WGC3Duint index, ActiveInfo&) { ADD_FAILURE(); return false; }
248     virtual bool getActiveUniform(WebGLId program, WGC3Duint index, ActiveInfo&) { ADD_FAILURE(); return false; }
249     virtual void getAttachedShaders(WebGLId program, WGC3Dsizei maxCount, WGC3Dsizei* count, WebGLId* shaders) { ADD_FAILURE(); }
250     virtual WGC3Dint getAttribLocation(WebGLId program, const WGC3Dchar* name) { ADD_FAILURE(); return 0; }
251     virtual void getBooleanv(WGC3Denum pname, WGC3Dboolean* value) { ADD_FAILURE(); }
252     virtual void getBufferParameteriv(WGC3Denum target, WGC3Denum pname, WGC3Dint* value) { ADD_FAILURE(); }
253     virtual Attributes getContextAttributes() { ADD_FAILURE(); return m_attrs; }
254     virtual WGC3Denum getError() { ADD_FAILURE(); return 0; }
255     virtual void getFloatv(WGC3Denum pname, WGC3Dfloat* value) { ADD_FAILURE(); }
256     virtual void getFramebufferAttachmentParameteriv(WGC3Denum target, WGC3Denum attachment, WGC3Denum pname, WGC3Dint* value) { ADD_FAILURE(); }
257     virtual void getIntegerv(WGC3Denum pname, WGC3Dint* value)
258     {
259         if (pname == WebCore::GraphicsContext3D::MAX_TEXTURE_SIZE)
260             *value = 1024; // MAX_TEXTURE_SIZE is cached client side, so it's OK to query.
261         else
262             ADD_FAILURE();
263     }
264
265     // We allow querying the shader compilation and program link status in debug mode, but not release.
266     virtual void getProgramiv(WebGLId program, WGC3Denum pname, WGC3Dint* value)
267     {
268 #ifndef NDEBUG
269         *value = 1;
270 #else
271         ADD_FAILURE();
272 #endif
273     }
274
275     virtual void getShaderiv(WebGLId shader, WGC3Denum pname, WGC3Dint* value)
276     {
277 #ifndef NDEBUG
278         *value = 1;
279 #else
280         ADD_FAILURE();
281 #endif
282     }
283
284     virtual WebString getString(WGC3Denum name)
285     {
286         // We allow querying the extension string.
287         // FIXME: It'd be better to check that we only do this before starting any other expensive work (like starting a compilation)
288         if (name != WebCore::GraphicsContext3D::EXTENSIONS)
289             ADD_FAILURE();
290         return WebString();
291     }
292
293     virtual WebString getProgramInfoLog(WebGLId program) { ADD_FAILURE(); return WebString(); }
294     virtual void getRenderbufferParameteriv(WGC3Denum target, WGC3Denum pname, WGC3Dint* value) { ADD_FAILURE(); }
295
296     virtual WebString getShaderInfoLog(WebGLId shader) { ADD_FAILURE(); return WebString(); }
297     virtual void getShaderPrecisionFormat(WGC3Denum shadertype, WGC3Denum precisiontype, WGC3Dint* range, WGC3Dint* precision) { ADD_FAILURE(); }
298     virtual WebString getShaderSource(WebGLId shader) { ADD_FAILURE(); return WebString(); }
299     virtual void getTexParameterfv(WGC3Denum target, WGC3Denum pname, WGC3Dfloat* value) { ADD_FAILURE(); }
300     virtual void getTexParameteriv(WGC3Denum target, WGC3Denum pname, WGC3Dint* value) { ADD_FAILURE(); }
301     virtual void getUniformfv(WebGLId program, WGC3Dint location, WGC3Dfloat* value) { ADD_FAILURE(); }
302     virtual void getUniformiv(WebGLId program, WGC3Dint location, WGC3Dint* value) { ADD_FAILURE(); }
303     virtual WGC3Dint getUniformLocation(WebGLId program, const WGC3Dchar* name) { ADD_FAILURE(); return 0; }
304     virtual void getVertexAttribfv(WGC3Duint index, WGC3Denum pname, WGC3Dfloat* value) { ADD_FAILURE(); }
305     virtual void getVertexAttribiv(WGC3Duint index, WGC3Denum pname, WGC3Dint* value) { ADD_FAILURE(); }
306     virtual WGC3Dsizeiptr getVertexAttribOffset(WGC3Duint index, WGC3Denum pname) { ADD_FAILURE(); return 0; }
307 };
308
309 // 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.
310 TEST(LayerRendererChromiumTest2, initializationDoesNotMakeSynchronousCalls)
311 {
312     CCScopedSettings scopedSettings;
313     FakeCCRendererClient mockClient;
314     FakeLayerRendererChromium layerRendererChromium(&mockClient, GraphicsContext3DPrivate::createGraphicsContextFromWebContext(adoptPtr(new ForbidSynchronousCallContext), GraphicsContext3D::RenderDirectlyToHostWindow));
315
316     EXPECT_TRUE(layerRendererChromium.initialize());
317 }
318
319 class LoseContextOnFirstGetContext : public FakeWebGraphicsContext3D {
320 public:
321     LoseContextOnFirstGetContext()
322         : m_contextLost(false)
323     {
324     }
325
326     virtual bool makeContextCurrent() OVERRIDE
327     {
328         return !m_contextLost;
329     }
330
331     virtual void getProgramiv(WebGLId program, WGC3Denum pname, WGC3Dint* value) OVERRIDE
332     {
333         m_contextLost = true;
334         *value = 0;
335     }
336
337     virtual void getShaderiv(WebGLId shader, WGC3Denum pname, WGC3Dint* value) OVERRIDE
338     {
339         m_contextLost = true;
340         *value = 0;
341     }
342
343     virtual WGC3Denum getGraphicsResetStatusARB() OVERRIDE
344     {
345         return m_contextLost ? 1 : 0;
346     }
347
348 private:
349     bool m_contextLost;
350 };
351
352 TEST(LayerRendererChromiumTest2, initializationWithQuicklyLostContextDoesNotAssert)
353 {
354     CCScopedSettings scopedSettings;
355     FakeCCRendererClient mockClient;
356     FakeLayerRendererChromium layerRendererChromium(&mockClient, GraphicsContext3DPrivate::createGraphicsContextFromWebContext(adoptPtr(new LoseContextOnFirstGetContext), GraphicsContext3D::RenderDirectlyToHostWindow));
357
358     layerRendererChromium.initialize();
359 }
360
361 class ContextThatDoesNotSupportMemoryManagmentExtensions : public FakeWebGraphicsContext3D {
362 public:
363     ContextThatDoesNotSupportMemoryManagmentExtensions() { }
364
365     // WebGraphicsContext3D methods.
366
367     // This method would normally do a glSwapBuffers under the hood.
368     virtual void prepareTexture() { }
369     virtual void setMemoryAllocationChangedCallbackCHROMIUM(WebGraphicsMemoryAllocationChangedCallbackCHROMIUM* callback) { }
370     virtual WebString getString(WebKit::WGC3Denum name) { return WebString(); }
371 };
372
373 TEST(LayerRendererChromiumTest2, initializationWithoutGpuMemoryManagerExtensionSupportShouldDefaultToNonZeroAllocation)
374 {
375     FakeCCRendererClient mockClient;
376     FakeLayerRendererChromium layerRendererChromium(&mockClient, GraphicsContext3DPrivate::createGraphicsContextFromWebContext(adoptPtr(new ContextThatDoesNotSupportMemoryManagmentExtensions), GraphicsContext3D::RenderDirectlyToHostWindow));
377
378     layerRendererChromium.initialize();
379
380     EXPECT_GT(mockClient.memoryAllocationLimitBytes(), 0ul);
381 }
382
383 class ClearCountingContext : public FakeWebGraphicsContext3D {
384 public:
385     ClearCountingContext() : m_clear(0) { }
386
387     virtual void clear(WGC3Dbitfield)
388     {
389         m_clear++;
390     }
391
392     int clearCount() const { return m_clear; }
393
394 private:
395     int m_clear;
396 };
397
398 TEST(LayerRendererChromiumTest2, opaqueBackground)
399 {
400     FakeCCRendererClient mockClient;
401     RefPtr<GraphicsContext3D> context = GraphicsContext3DPrivate::createGraphicsContextFromWebContext(adoptPtr(new ClearCountingContext), GraphicsContext3D::RenderDirectlyToHostWindow);
402     FakeLayerRendererChromium layerRendererChromium(&mockClient, context);
403
404     mockClient.rootRenderPass()->setHasTransparentBackground(false);
405
406     EXPECT_TRUE(layerRendererChromium.initialize());
407
408     layerRendererChromium.beginDrawingFrame(mockClient.rootRenderPass());
409     layerRendererChromium.drawRenderPass(mockClient.rootRenderPass(), FloatRect());
410     layerRendererChromium.finishDrawingFrame();
411
412     // On DEBUG builds, render passes with opaque background clear to blue to
413     // easily see regions that were not drawn on the screen.
414 #if defined(NDEBUG)
415     EXPECT_EQ(0, static_cast<ClearCountingContext*>(GraphicsContext3DPrivate::extractWebGraphicsContext3D(context.get()))->clearCount());
416 #else
417     EXPECT_EQ(1, static_cast<ClearCountingContext*>(GraphicsContext3DPrivate::extractWebGraphicsContext3D(context.get()))->clearCount());
418 #endif
419 }
420
421 TEST(LayerRendererChromiumTest2, transparentBackground)
422 {
423     FakeCCRendererClient mockClient;
424     RefPtr<GraphicsContext3D> context = GraphicsContext3DPrivate::createGraphicsContextFromWebContext(adoptPtr(new ClearCountingContext), GraphicsContext3D::RenderDirectlyToHostWindow);
425     FakeLayerRendererChromium layerRendererChromium(&mockClient, context);
426
427     mockClient.rootRenderPass()->setHasTransparentBackground(true);
428
429     EXPECT_TRUE(layerRendererChromium.initialize());
430
431     layerRendererChromium.beginDrawingFrame(mockClient.rootRenderPass());
432     layerRendererChromium.drawRenderPass(mockClient.rootRenderPass(), FloatRect());
433     layerRendererChromium.finishDrawingFrame();
434
435     EXPECT_EQ(1, static_cast<ClearCountingContext*>(GraphicsContext3DPrivate::extractWebGraphicsContext3D(context.get()))->clearCount());
436 }