1 // Copyright 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "cc/software_renderer.h"
7 #include "cc/compositor_frame_metadata.h"
8 #include "cc/quad_sink.h"
9 #include "cc/render_pass.h"
10 #include "cc/render_pass_draw_quad.h"
11 #include "cc/solid_color_draw_quad.h"
12 #include "cc/test/animation_test_common.h"
13 #include "cc/test/fake_output_surface.h"
14 #include "cc/test/fake_software_output_device.h"
15 #include "cc/test/geometry_test_utils.h"
16 #include "cc/test/render_pass_test_common.h"
17 #include "cc/test/render_pass_test_utils.h"
18 #include "cc/tile_draw_quad.h"
19 #include "testing/gmock/include/gmock/gmock.h"
20 #include "testing/gtest/include/gtest/gtest.h"
22 using namespace WebKit
;
27 class SoftwareRendererTest
: public testing::Test
, public RendererClient
{
29 SoftwareRendererTest()
30 : m_shouldClearRootRenderPass(true)
34 void initializeRenderer() {
35 m_outputSurface
= FakeOutputSurface::CreateSoftware(scoped_ptr
<SoftwareOutputDevice
>(new FakeSoftwareOutputDevice
));
36 m_resourceProvider
= ResourceProvider::create(m_outputSurface
.get());
37 m_renderer
= SoftwareRenderer::create(this, resourceProvider(), softwareDevice());
40 SoftwareOutputDevice
* softwareDevice() const { return m_outputSurface
->SoftwareDevice(); }
41 FakeOutputSurface
* outputSurface() const { return m_outputSurface
.get(); }
42 ResourceProvider
* resourceProvider() const { return m_resourceProvider
.get(); }
43 SoftwareRenderer
* renderer() const { return m_renderer
.get(); }
44 void setViewportSize(const gfx::Size
& viewportSize
) { m_viewportSize
= viewportSize
; }
45 void setShouldClearRootRenderPass(bool clearRootRenderPass
) { m_shouldClearRootRenderPass
= clearRootRenderPass
; }
47 // RendererClient implementation.
48 virtual const gfx::Size
& deviceViewportSize() const OVERRIDE
{ return m_viewportSize
; }
49 virtual const LayerTreeSettings
& settings() const OVERRIDE
{ return m_settings
; }
50 virtual void didLoseOutputSurface() OVERRIDE
{ }
51 virtual void onSwapBuffersComplete() OVERRIDE
{ }
52 virtual void setFullRootLayerDamage() OVERRIDE
{ }
53 virtual void setManagedMemoryPolicy(const ManagedMemoryPolicy
& policy
) OVERRIDE
{ };
54 virtual void enforceManagedMemoryPolicy(const ManagedMemoryPolicy
& policy
) OVERRIDE
{ };
55 virtual bool hasImplThread() const OVERRIDE
{ return false; }
56 virtual bool shouldClearRootRenderPass() const OVERRIDE
{ return m_shouldClearRootRenderPass
; }
57 virtual CompositorFrameMetadata
makeCompositorFrameMetadata() const
58 OVERRIDE
{ return CompositorFrameMetadata(); }
61 scoped_ptr
<FakeOutputSurface
> m_outputSurface
;
62 scoped_ptr
<ResourceProvider
> m_resourceProvider
;
63 scoped_ptr
<SoftwareRenderer
> m_renderer
;
64 gfx::Size m_viewportSize
;
65 LayerTreeSettings m_settings
;
66 bool m_shouldClearRootRenderPass
;
69 TEST_F(SoftwareRendererTest
, solidColorQuad
)
71 gfx::Size
outerSize(100, 100);
72 int outerPixels
= outerSize
.width() * outerSize
.height();
73 gfx::Size
innerSize(98, 98);
74 gfx::Rect
outerRect(gfx::Point(), outerSize
);
75 gfx::Rect
innerRect(gfx::Point(1, 1), innerSize
);
76 setViewportSize(outerSize
);
80 scoped_ptr
<SharedQuadState
> sharedQuadState
= SharedQuadState::Create();
81 sharedQuadState
->SetAll(gfx::Transform(), outerRect
, outerRect
, outerRect
, false, 1.0);
82 RenderPass::Id rootRenderPassId
= RenderPass::Id(1, 1);
83 scoped_ptr
<TestRenderPass
> rootRenderPass
= TestRenderPass::Create();
84 rootRenderPass
->SetNew(rootRenderPassId
, outerRect
, gfx::Rect(), gfx::Transform());
85 scoped_ptr
<SolidColorDrawQuad
> outerQuad
= SolidColorDrawQuad::Create();
86 outerQuad
->SetNew(sharedQuadState
.get(), outerRect
, SK_ColorYELLOW
);
87 scoped_ptr
<SolidColorDrawQuad
> innerQuad
= SolidColorDrawQuad::Create();
88 innerQuad
->SetNew(sharedQuadState
.get(), innerRect
, SK_ColorCYAN
);
89 rootRenderPass
->AppendQuad(innerQuad
.PassAs
<DrawQuad
>());
90 rootRenderPass
->AppendQuad(outerQuad
.PassAs
<DrawQuad
>());
93 list
.append(rootRenderPass
.PassAs
<RenderPass
>());
94 renderer()->drawFrame(list
);
96 scoped_array
<SkColor
> pixels(new SkColor
[deviceViewportSize().width() * deviceViewportSize().height()]);
97 renderer()->getFramebufferPixels(pixels
.get(), outerRect
);
99 // FIXME: This fails on Android. Endianness maybe?
100 // Yellow: expects 0xFFFFFF00, was 0xFF00FFFF on android.
101 // Cyan: expects 0xFF00FFFF, was 0xFFFFFF00 on android.
102 // http://crbug.com/154528
104 EXPECT_EQ(SK_ColorYELLOW
, pixels
[0]);
105 EXPECT_EQ(SK_ColorYELLOW
, pixels
[outerPixels
- 1]);
106 EXPECT_EQ(SK_ColorCYAN
, pixels
[outerSize
.width() + 1]);
107 EXPECT_EQ(SK_ColorCYAN
, pixels
[outerPixels
- outerSize
.width() - 2]);
111 TEST_F(SoftwareRendererTest
, tileQuad
)
113 gfx::Size
outerSize(100, 100);
114 int outerPixels
= outerSize
.width() * outerSize
.height();
115 gfx::Size
innerSize(98, 98);
116 int innerPixels
= innerSize
.width() * innerSize
.height();
117 gfx::Rect
outerRect(gfx::Point(), outerSize
);
118 gfx::Rect
innerRect(gfx::Point(1, 1), innerSize
);
119 setViewportSize(outerSize
);
120 initializeRenderer();
122 ResourceProvider::ResourceId resourceYellow
= resourceProvider()->createResource(outerSize
, GL_RGBA
, ResourceProvider::TextureUsageAny
);
123 ResourceProvider::ResourceId resourceCyan
= resourceProvider()->createResource(innerSize
, GL_RGBA
, ResourceProvider::TextureUsageAny
);
125 SkColor yellow
= SK_ColorYELLOW
;
126 SkColor cyan
= SK_ColorCYAN
;
127 scoped_array
<SkColor
> yellowPixels(new SkColor
[outerPixels
]);
128 scoped_array
<SkColor
> cyanPixels(new SkColor
[innerPixels
]);
129 for (int i
= 0; i
< outerPixels
; i
++)
130 yellowPixels
[i
] = yellow
;
131 for (int i
= 0; i
< innerPixels
; i
++)
132 cyanPixels
[i
] = cyan
;
134 resourceProvider()->setPixels(resourceYellow
, reinterpret_cast<uint8_t*>(yellowPixels
.get()), gfx::Rect(gfx::Point(), outerSize
), gfx::Rect(gfx::Point(), outerSize
), gfx::Vector2d());
135 resourceProvider()->setPixels(resourceCyan
, reinterpret_cast<uint8_t*>(cyanPixels
.get()), gfx::Rect(gfx::Point(), innerSize
), gfx::Rect(gfx::Point(), innerSize
), gfx::Vector2d());
137 gfx::Rect rect
= gfx::Rect(gfx::Point(), deviceViewportSize());
139 scoped_ptr
<SharedQuadState
> sharedQuadState
= SharedQuadState::Create();
140 sharedQuadState
->SetAll(gfx::Transform(), outerRect
, outerRect
, outerRect
, false, 1.0);
141 RenderPass::Id rootRenderPassId
= RenderPass::Id(1, 1);
142 scoped_ptr
<TestRenderPass
> rootRenderPass
= TestRenderPass::Create();
143 rootRenderPass
->SetNew(rootRenderPassId
, gfx::Rect(gfx::Point(), deviceViewportSize()), gfx::Rect(), gfx::Transform());
144 scoped_ptr
<TileDrawQuad
> outerQuad
= TileDrawQuad::Create();
145 outerQuad
->SetNew(sharedQuadState
.get(), outerRect
, outerRect
, resourceYellow
, gfx::RectF(gfx::PointF(), outerSize
), outerSize
, false, false, false, false, false);
146 scoped_ptr
<TileDrawQuad
> innerQuad
= TileDrawQuad::Create();
147 innerQuad
->SetNew(sharedQuadState
.get(), innerRect
, innerRect
, resourceCyan
, gfx::RectF(gfx::PointF(), innerSize
), innerSize
, false, false, false, false, false);
148 rootRenderPass
->AppendQuad(innerQuad
.PassAs
<DrawQuad
>());
149 rootRenderPass
->AppendQuad(outerQuad
.PassAs
<DrawQuad
>());
152 list
.append(rootRenderPass
.PassAs
<RenderPass
>());
153 renderer()->drawFrame(list
);
155 scoped_array
<SkColor
> pixels(new SkColor
[deviceViewportSize().width() * deviceViewportSize().height()]);
156 renderer()->getFramebufferPixels(pixels
.get(), outerRect
);
158 EXPECT_EQ(SK_ColorYELLOW
, pixels
[0]);
159 EXPECT_EQ(SK_ColorYELLOW
, pixels
[outerPixels
- 1]);
160 EXPECT_EQ(SK_ColorCYAN
, pixels
[outerSize
.width() + 1]);
161 EXPECT_EQ(SK_ColorCYAN
, pixels
[outerPixels
- outerSize
.width() - 2]);
164 TEST_F(SoftwareRendererTest
, shouldClearRootRenderPass
)
166 gfx::Rect
viewportRect(gfx::Size(100, 100));
167 size_t viewportPixels
= viewportRect
.width() * viewportRect
.height();
168 setViewportSize(viewportRect
.size());
169 setShouldClearRootRenderPass(false);
170 initializeRenderer();
173 scoped_array
<SkColor
> pixels(new SkColor
[viewportPixels
]);
175 // Draw a fullscreen green quad in a first frame.
176 RenderPass::Id
rootClearPassId(1, 0);
177 TestRenderPass
* rootClearPass
= addRenderPass(list
, rootClearPassId
, viewportRect
, gfx::Transform());
178 addQuad(rootClearPass
, viewportRect
, SK_ColorGREEN
);
180 renderer()->decideRenderPassAllocationsForFrame(list
);
181 renderer()->drawFrame(list
);
182 renderer()->getFramebufferPixels(pixels
.get(), viewportRect
);
184 EXPECT_EQ(SK_ColorGREEN
, pixels
[0]);
185 EXPECT_EQ(SK_ColorGREEN
, pixels
[viewportPixels
- 1]);
189 // Draw a smaller magenta rect without filling the viewport in a separate frame.
190 gfx::Rect
smallerRect(20, 20, 60, 60);
192 RenderPass::Id
rootSmallerPassId(2, 0);
193 TestRenderPass
* rootSmallerPass
= addRenderPass(list
, rootSmallerPassId
, viewportRect
, gfx::Transform());
194 addQuad(rootSmallerPass
, smallerRect
, SK_ColorMAGENTA
);
196 renderer()->decideRenderPassAllocationsForFrame(list
);
197 renderer()->drawFrame(list
);
198 renderer()->getFramebufferPixels(pixels
.get(), viewportRect
);
200 // If we didn't clear, the borders should still be green.
201 EXPECT_EQ(SK_ColorGREEN
, pixels
[0]);
202 EXPECT_EQ(SK_ColorGREEN
, pixels
[viewportPixels
- 1]);
204 EXPECT_EQ(SK_ColorMAGENTA
, pixels
[smallerRect
.y() * viewportRect
.width() + smallerRect
.x()]);
205 EXPECT_EQ(SK_ColorMAGENTA
, pixels
[(smallerRect
.bottom() - 1) * viewportRect
.width() + smallerRect
.right() - 1]);