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/output/software_renderer.h"
7 #include "cc/layers/quad_sink.h"
8 #include "cc/output/compositor_frame_metadata.h"
9 #include "cc/output/software_output_device.h"
10 #include "cc/quads/render_pass.h"
11 #include "cc/quads/render_pass_draw_quad.h"
12 #include "cc/quads/solid_color_draw_quad.h"
13 #include "cc/quads/tile_draw_quad.h"
14 #include "cc/test/animation_test_common.h"
15 #include "cc/test/fake_output_surface.h"
16 #include "cc/test/geometry_test_utils.h"
17 #include "cc/test/render_pass_test_common.h"
18 #include "cc/test/render_pass_test_utils.h"
19 #include "testing/gmock/include/gmock/gmock.h"
20 #include "testing/gtest/include/gtest/gtest.h"
21 #include "third_party/skia/include/core/SkCanvas.h"
22 #include "third_party/skia/include/core/SkDevice.h"
27 class SoftwareRendererTest
: public testing::Test
, public RendererClient
{
29 SoftwareRendererTest() : should_clear_root_render_pass_(true) {}
31 void InitializeRenderer(
32 scoped_ptr
<SoftwareOutputDevice
> software_output_device
) {
33 output_surface_
= FakeOutputSurface::CreateSoftware(
34 software_output_device
.Pass());
35 resource_provider_
= ResourceProvider::Create(output_surface_
.get(), 0);
36 renderer_
= SoftwareRenderer::Create(
37 this, output_surface_
.get(), resource_provider());
40 ResourceProvider
* resource_provider() const {
41 return resource_provider_
.get();
44 SoftwareRenderer
* renderer() const { return renderer_
.get(); }
46 void set_viewport(gfx::Rect viewport
) {
50 void set_should_clear_root_render_pass(bool clear_root_render_pass
) {
51 should_clear_root_render_pass_
= clear_root_render_pass
;
54 // RendererClient implementation.
55 virtual gfx::Rect
DeviceViewport() const OVERRIDE
{
58 virtual float DeviceScaleFactor() const OVERRIDE
{
61 virtual const LayerTreeSettings
& Settings() const OVERRIDE
{
64 virtual void SetFullRootLayerDamage() OVERRIDE
{}
65 virtual bool HasImplThread() const OVERRIDE
{ return false; }
66 virtual bool ShouldClearRootRenderPass() const OVERRIDE
{
67 return should_clear_root_render_pass_
;
69 virtual CompositorFrameMetadata
MakeCompositorFrameMetadata() const OVERRIDE
{
70 return CompositorFrameMetadata();
72 virtual bool AllowPartialSwap() const OVERRIDE
{
75 virtual bool ExternalStencilTestEnabled() const OVERRIDE
{ return false; }
78 scoped_ptr
<FakeOutputSurface
> output_surface_
;
79 scoped_ptr
<ResourceProvider
> resource_provider_
;
80 scoped_ptr
<SoftwareRenderer
> renderer_
;
82 LayerTreeSettings settings_
;
83 bool should_clear_root_render_pass_
;
86 TEST_F(SoftwareRendererTest
, SolidColorQuad
) {
87 gfx::Size
outer_size(100, 100);
88 gfx::Size
inner_size(98, 98);
89 gfx::Rect
outer_rect(outer_size
);
90 gfx::Rect
inner_rect(gfx::Point(1, 1), inner_size
);
91 set_viewport(gfx::Rect(outer_size
));
93 InitializeRenderer(make_scoped_ptr(new SoftwareOutputDevice
));
95 scoped_ptr
<SharedQuadState
> shared_quad_state
= SharedQuadState::Create();
96 shared_quad_state
->SetAll(
97 gfx::Transform(), outer_size
, outer_rect
, outer_rect
, false, 1.0);
98 RenderPass::Id root_render_pass_id
= RenderPass::Id(1, 1);
99 scoped_ptr
<TestRenderPass
> root_render_pass
= TestRenderPass::Create();
100 root_render_pass
->SetNew(
101 root_render_pass_id
, outer_rect
, outer_rect
, gfx::Transform());
102 scoped_ptr
<SolidColorDrawQuad
> outer_quad
= SolidColorDrawQuad::Create();
104 shared_quad_state
.get(), outer_rect
, SK_ColorYELLOW
, false);
105 scoped_ptr
<SolidColorDrawQuad
> inner_quad
= SolidColorDrawQuad::Create();
106 inner_quad
->SetNew(shared_quad_state
.get(), inner_rect
, SK_ColorCYAN
, false);
107 root_render_pass
->AppendQuad(inner_quad
.PassAs
<DrawQuad
>());
108 root_render_pass
->AppendQuad(outer_quad
.PassAs
<DrawQuad
>());
111 list
.push_back(root_render_pass
.PassAs
<RenderPass
>());
112 renderer()->DrawFrame(&list
);
115 output
.setConfig(SkBitmap::kARGB_8888_Config
,
116 DeviceViewport().width(),
117 DeviceViewport().height());
118 output
.allocPixels();
119 renderer()->GetFramebufferPixels(output
.getPixels(), outer_rect
);
121 EXPECT_EQ(SK_ColorYELLOW
, output
.getColor(0, 0));
122 EXPECT_EQ(SK_ColorYELLOW
,
123 output
.getColor(outer_size
.width() - 1, outer_size
.height() - 1));
124 EXPECT_EQ(SK_ColorCYAN
, output
.getColor(1, 1));
125 EXPECT_EQ(SK_ColorCYAN
,
126 output
.getColor(inner_size
.width() - 1, inner_size
.height() - 1));
129 TEST_F(SoftwareRendererTest
, TileQuad
) {
130 gfx::Size
outer_size(100, 100);
131 gfx::Size
inner_size(98, 98);
132 gfx::Rect
outer_rect(outer_size
);
133 gfx::Rect
inner_rect(gfx::Point(1, 1), inner_size
);
134 set_viewport(gfx::Rect(outer_size
));
135 InitializeRenderer(make_scoped_ptr(new SoftwareOutputDevice
));
137 ResourceProvider::ResourceId resource_yellow
=
138 resource_provider()->CreateResource(
139 outer_size
, GL_RGBA
, ResourceProvider::TextureUsageAny
);
140 ResourceProvider::ResourceId resource_cyan
=
141 resource_provider()->CreateResource(
142 inner_size
, GL_RGBA
, ResourceProvider::TextureUsageAny
);
144 SkBitmap yellow_tile
;
145 yellow_tile
.setConfig(
146 SkBitmap::kARGB_8888_Config
, outer_size
.width(), outer_size
.height());
147 yellow_tile
.allocPixels();
148 yellow_tile
.eraseColor(SK_ColorYELLOW
);
152 SkBitmap::kARGB_8888_Config
, inner_size
.width(), inner_size
.height());
153 cyan_tile
.allocPixels();
154 cyan_tile
.eraseColor(SK_ColorCYAN
);
156 resource_provider()->SetPixels(
158 static_cast<uint8_t*>(yellow_tile
.getPixels()),
159 gfx::Rect(outer_size
),
160 gfx::Rect(outer_size
),
162 resource_provider()->SetPixels(resource_cyan
,
163 static_cast<uint8_t*>(cyan_tile
.getPixels()),
164 gfx::Rect(inner_size
),
165 gfx::Rect(inner_size
),
168 gfx::Rect root_rect
= DeviceViewport();
170 scoped_ptr
<SharedQuadState
> shared_quad_state
= SharedQuadState::Create();
171 shared_quad_state
->SetAll(
172 gfx::Transform(), outer_size
, outer_rect
, outer_rect
, false, 1.0);
173 RenderPass::Id root_render_pass_id
= RenderPass::Id(1, 1);
174 scoped_ptr
<TestRenderPass
> root_render_pass
= TestRenderPass::Create();
175 root_render_pass
->SetNew(
176 root_render_pass_id
, root_rect
, root_rect
, gfx::Transform());
177 scoped_ptr
<TileDrawQuad
> outer_quad
= TileDrawQuad::Create();
178 outer_quad
->SetNew(shared_quad_state
.get(),
182 gfx::RectF(outer_size
),
185 scoped_ptr
<TileDrawQuad
> inner_quad
= TileDrawQuad::Create();
186 inner_quad
->SetNew(shared_quad_state
.get(),
190 gfx::RectF(inner_size
),
193 root_render_pass
->AppendQuad(inner_quad
.PassAs
<DrawQuad
>());
194 root_render_pass
->AppendQuad(outer_quad
.PassAs
<DrawQuad
>());
197 list
.push_back(root_render_pass
.PassAs
<RenderPass
>());
198 renderer()->DrawFrame(&list
);
201 output
.setConfig(SkBitmap::kARGB_8888_Config
,
202 DeviceViewport().width(),
203 DeviceViewport().height());
204 output
.allocPixels();
205 renderer()->GetFramebufferPixels(output
.getPixels(), outer_rect
);
207 EXPECT_EQ(SK_ColorYELLOW
, output
.getColor(0, 0));
208 EXPECT_EQ(SK_ColorYELLOW
,
209 output
.getColor(outer_size
.width() - 1, outer_size
.height() - 1));
210 EXPECT_EQ(SK_ColorCYAN
, output
.getColor(1, 1));
211 EXPECT_EQ(SK_ColorCYAN
,
212 output
.getColor(inner_size
.width() - 1, inner_size
.height() - 1));
215 TEST_F(SoftwareRendererTest
, ShouldClearRootRenderPass
) {
216 gfx::Rect
viewport_rect(0, 0, 100, 100);
217 set_viewport(viewport_rect
);
218 set_should_clear_root_render_pass(false);
219 InitializeRenderer(make_scoped_ptr(new SoftwareOutputDevice
));
224 output
.setConfig(SkBitmap::kARGB_8888_Config
,
225 viewport_rect
.width(),
226 viewport_rect
.height());
227 output
.allocPixels();
229 // Draw a fullscreen green quad in a first frame.
230 RenderPass::Id
root_clear_pass_id(1, 0);
231 TestRenderPass
* root_clear_pass
= AddRenderPass(
232 &list
, root_clear_pass_id
, viewport_rect
, gfx::Transform());
233 AddQuad(root_clear_pass
, viewport_rect
, SK_ColorGREEN
);
235 renderer()->DecideRenderPassAllocationsForFrame(list
);
236 renderer()->DrawFrame(&list
);
237 renderer()->GetFramebufferPixels(output
.getPixels(), viewport_rect
);
239 EXPECT_EQ(SK_ColorGREEN
, output
.getColor(0, 0));
240 EXPECT_EQ(SK_ColorGREEN
,
241 output
.getColor(viewport_rect
.width() - 1, viewport_rect
.height() - 1));
245 // Draw a smaller magenta rect without filling the viewport in a separate
247 gfx::Rect
smaller_rect(20, 20, 60, 60);
249 RenderPass::Id
root_smaller_pass_id(2, 0);
250 TestRenderPass
* root_smaller_pass
= AddRenderPass(
251 &list
, root_smaller_pass_id
, viewport_rect
, gfx::Transform());
252 AddQuad(root_smaller_pass
, smaller_rect
, SK_ColorMAGENTA
);
254 renderer()->DecideRenderPassAllocationsForFrame(list
);
255 renderer()->DrawFrame(&list
);
256 renderer()->GetFramebufferPixels(output
.getPixels(), viewport_rect
);
258 // If we didn't clear, the borders should still be green.
259 EXPECT_EQ(SK_ColorGREEN
, output
.getColor(0, 0));
260 EXPECT_EQ(SK_ColorGREEN
,
261 output
.getColor(viewport_rect
.width() - 1, viewport_rect
.height() - 1));
263 EXPECT_EQ(SK_ColorMAGENTA
,
264 output
.getColor(smaller_rect
.x(), smaller_rect
.y()));
265 EXPECT_EQ(SK_ColorMAGENTA
,
266 output
.getColor(smaller_rect
.right() - 1, smaller_rect
.bottom() - 1));