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/fake_output_surface_client.h"
17 #include "cc/test/geometry_test_utils.h"
18 #include "cc/test/render_pass_test_common.h"
19 #include "cc/test/render_pass_test_utils.h"
20 #include "testing/gmock/include/gmock/gmock.h"
21 #include "testing/gtest/include/gtest/gtest.h"
22 #include "third_party/skia/include/core/SkCanvas.h"
23 #include "third_party/skia/include/core/SkDevice.h"
28 class SoftwareRendererTest
: public testing::Test
, public RendererClient
{
30 void InitializeRenderer(
31 scoped_ptr
<SoftwareOutputDevice
> software_output_device
) {
32 output_surface_
= FakeOutputSurface::CreateSoftware(
33 software_output_device
.Pass());
34 CHECK(output_surface_
->BindToClient(&output_surface_client_
));
37 ResourceProvider::Create(output_surface_
.get(), 0, false);
38 renderer_
= SoftwareRenderer::Create(
39 this, &settings_
, output_surface_
.get(), resource_provider());
42 ResourceProvider
* resource_provider() const {
43 return resource_provider_
.get();
46 SoftwareRenderer
* renderer() const { return renderer_
.get(); }
48 void set_viewport(gfx::Rect viewport
) {
52 // RendererClient implementation.
53 virtual gfx::Rect
DeviceViewport() const OVERRIDE
{
56 virtual gfx::Rect
DeviceClip() const OVERRIDE
{ return DeviceViewport(); }
57 virtual void SetFullRootLayerDamage() OVERRIDE
{}
58 virtual CompositorFrameMetadata
MakeCompositorFrameMetadata() const OVERRIDE
{
59 return CompositorFrameMetadata();
63 LayerTreeSettings settings_
;
64 FakeOutputSurfaceClient output_surface_client_
;
65 scoped_ptr
<FakeOutputSurface
> output_surface_
;
66 scoped_ptr
<ResourceProvider
> resource_provider_
;
67 scoped_ptr
<SoftwareRenderer
> renderer_
;
71 TEST_F(SoftwareRendererTest
, SolidColorQuad
) {
72 gfx::Size
outer_size(100, 100);
73 gfx::Size
inner_size(98, 98);
74 gfx::Rect
outer_rect(outer_size
);
75 gfx::Rect
inner_rect(gfx::Point(1, 1), inner_size
);
76 gfx::Rect
visible_rect(gfx::Point(1, 2), gfx::Size(98, 97));
77 set_viewport(gfx::Rect(outer_size
));
79 InitializeRenderer(make_scoped_ptr(new SoftwareOutputDevice
));
81 scoped_ptr
<SharedQuadState
> shared_quad_state
= SharedQuadState::Create();
82 shared_quad_state
->SetAll(
83 gfx::Transform(), outer_size
, outer_rect
, outer_rect
, false, 1.0);
84 RenderPass::Id root_render_pass_id
= RenderPass::Id(1, 1);
85 scoped_ptr
<TestRenderPass
> root_render_pass
= TestRenderPass::Create();
86 root_render_pass
->SetNew(
87 root_render_pass_id
, outer_rect
, outer_rect
, gfx::Transform());
88 scoped_ptr
<SolidColorDrawQuad
> outer_quad
= SolidColorDrawQuad::Create();
90 shared_quad_state
.get(), outer_rect
, SK_ColorYELLOW
, false);
91 scoped_ptr
<SolidColorDrawQuad
> inner_quad
= SolidColorDrawQuad::Create();
92 inner_quad
->SetNew(shared_quad_state
.get(), inner_rect
, SK_ColorCYAN
, false);
93 inner_quad
->visible_rect
= visible_rect
;
94 root_render_pass
->AppendQuad(inner_quad
.PassAs
<DrawQuad
>());
95 root_render_pass
->AppendQuad(outer_quad
.PassAs
<DrawQuad
>());
98 list
.push_back(root_render_pass
.PassAs
<RenderPass
>());
100 float device_scale_factor
= 1.f
;
101 renderer()->DrawFrame(&list
, NULL
, device_scale_factor
, true);
104 output
.setConfig(SkBitmap::kARGB_8888_Config
,
105 DeviceViewport().width(),
106 DeviceViewport().height());
107 output
.allocPixels();
108 renderer()->GetFramebufferPixels(output
.getPixels(), outer_rect
);
110 EXPECT_EQ(SK_ColorYELLOW
, output
.getColor(0, 0));
111 EXPECT_EQ(SK_ColorYELLOW
,
112 output
.getColor(outer_size
.width() - 1, outer_size
.height() - 1));
113 EXPECT_EQ(SK_ColorYELLOW
, output
.getColor(1, 1));
114 EXPECT_EQ(SK_ColorCYAN
, output
.getColor(1, 2));
115 EXPECT_EQ(SK_ColorCYAN
,
116 output
.getColor(inner_size
.width() - 1, inner_size
.height() - 1));
119 TEST_F(SoftwareRendererTest
, TileQuad
) {
120 gfx::Size
outer_size(100, 100);
121 gfx::Size
inner_size(98, 98);
122 gfx::Rect
outer_rect(outer_size
);
123 gfx::Rect
inner_rect(gfx::Point(1, 1), inner_size
);
124 set_viewport(gfx::Rect(outer_size
));
125 InitializeRenderer(make_scoped_ptr(new SoftwareOutputDevice
));
127 ResourceProvider::ResourceId resource_yellow
=
128 resource_provider()->CreateResource(outer_size
,
130 ResourceProvider::TextureUsageAny
,
132 ResourceProvider::ResourceId resource_cyan
=
133 resource_provider()->CreateResource(inner_size
,
135 ResourceProvider::TextureUsageAny
,
138 SkBitmap yellow_tile
;
139 yellow_tile
.setConfig(
140 SkBitmap::kARGB_8888_Config
, outer_size
.width(), outer_size
.height());
141 yellow_tile
.allocPixels();
142 yellow_tile
.eraseColor(SK_ColorYELLOW
);
146 SkBitmap::kARGB_8888_Config
, inner_size
.width(), inner_size
.height());
147 cyan_tile
.allocPixels();
148 cyan_tile
.eraseColor(SK_ColorCYAN
);
150 resource_provider()->SetPixels(
152 static_cast<uint8_t*>(yellow_tile
.getPixels()),
153 gfx::Rect(outer_size
),
154 gfx::Rect(outer_size
),
156 resource_provider()->SetPixels(resource_cyan
,
157 static_cast<uint8_t*>(cyan_tile
.getPixels()),
158 gfx::Rect(inner_size
),
159 gfx::Rect(inner_size
),
162 gfx::Rect root_rect
= DeviceViewport();
164 scoped_ptr
<SharedQuadState
> shared_quad_state
= SharedQuadState::Create();
165 shared_quad_state
->SetAll(
166 gfx::Transform(), outer_size
, outer_rect
, outer_rect
, false, 1.0);
167 RenderPass::Id root_render_pass_id
= RenderPass::Id(1, 1);
168 scoped_ptr
<TestRenderPass
> root_render_pass
= TestRenderPass::Create();
169 root_render_pass
->SetNew(
170 root_render_pass_id
, root_rect
, root_rect
, gfx::Transform());
171 scoped_ptr
<TileDrawQuad
> outer_quad
= TileDrawQuad::Create();
172 outer_quad
->SetNew(shared_quad_state
.get(),
176 gfx::RectF(outer_size
),
179 scoped_ptr
<TileDrawQuad
> inner_quad
= TileDrawQuad::Create();
180 inner_quad
->SetNew(shared_quad_state
.get(),
184 gfx::RectF(inner_size
),
187 root_render_pass
->AppendQuad(inner_quad
.PassAs
<DrawQuad
>());
188 root_render_pass
->AppendQuad(outer_quad
.PassAs
<DrawQuad
>());
191 list
.push_back(root_render_pass
.PassAs
<RenderPass
>());
193 float device_scale_factor
= 1.f
;
194 renderer()->DrawFrame(&list
, NULL
, device_scale_factor
, true);
197 output
.setConfig(SkBitmap::kARGB_8888_Config
,
198 DeviceViewport().width(),
199 DeviceViewport().height());
200 output
.allocPixels();
201 renderer()->GetFramebufferPixels(output
.getPixels(), outer_rect
);
203 EXPECT_EQ(SK_ColorYELLOW
, output
.getColor(0, 0));
204 EXPECT_EQ(SK_ColorYELLOW
,
205 output
.getColor(outer_size
.width() - 1, outer_size
.height() - 1));
206 EXPECT_EQ(SK_ColorCYAN
, output
.getColor(1, 1));
207 EXPECT_EQ(SK_ColorCYAN
,
208 output
.getColor(inner_size
.width() - 1, inner_size
.height() - 1));
211 TEST_F(SoftwareRendererTest
, TileQuadVisibleRect
) {
212 gfx::Size
tile_size(100, 100);
213 gfx::Rect
tile_rect(tile_size
);
214 gfx::Rect visible_rect
= tile_rect
;
215 visible_rect
.Inset(1, 2, 3, 4);
216 set_viewport(gfx::Rect(tile_size
));
217 InitializeRenderer(make_scoped_ptr(new SoftwareOutputDevice
));
219 ResourceProvider::ResourceId resource_cyan
=
220 resource_provider()->CreateResource(tile_size
,
222 ResourceProvider::TextureUsageAny
,
225 SkBitmap cyan_tile
; // The lowest five rows are yellow.
227 SkBitmap::kARGB_8888_Config
, tile_size
.width(), tile_size
.height());
228 cyan_tile
.allocPixels();
229 cyan_tile
.eraseColor(SK_ColorCYAN
);
232 0, visible_rect
.bottom() - 1, tile_rect
.width(), tile_rect
.bottom()),
235 resource_provider()->SetPixels(resource_cyan
,
236 static_cast<uint8_t*>(cyan_tile
.getPixels()),
237 gfx::Rect(tile_size
),
238 gfx::Rect(tile_size
),
241 gfx::Rect root_rect
= DeviceViewport();
243 scoped_ptr
<SharedQuadState
> shared_quad_state
= SharedQuadState::Create();
244 shared_quad_state
->SetAll(
245 gfx::Transform(), tile_size
, tile_rect
, tile_rect
, false, 1.0);
246 RenderPass::Id root_render_pass_id
= RenderPass::Id(1, 1);
247 scoped_ptr
<TestRenderPass
> root_render_pass
= TestRenderPass::Create();
248 root_render_pass
->SetNew(
249 root_render_pass_id
, root_rect
, root_rect
, gfx::Transform());
250 scoped_ptr
<TileDrawQuad
> quad
= TileDrawQuad::Create();
251 quad
->SetNew(shared_quad_state
.get(),
255 gfx::RectF(tile_size
),
258 quad
->visible_rect
= visible_rect
;
259 root_render_pass
->AppendQuad(quad
.PassAs
<DrawQuad
>());
262 list
.push_back(root_render_pass
.PassAs
<RenderPass
>());
264 float device_scale_factor
= 1.f
;
265 renderer()->DrawFrame(&list
, NULL
, device_scale_factor
, true);
268 output
.setConfig(SkBitmap::kARGB_8888_Config
,
269 DeviceViewport().width(),
270 DeviceViewport().height());
271 output
.allocPixels();
272 renderer()->GetFramebufferPixels(output
.getPixels(), tile_rect
);
274 // Check portion of tile not in visible rect isn't drawn.
275 const unsigned int kTransparent
= SK_ColorTRANSPARENT
;
276 EXPECT_EQ(kTransparent
, output
.getColor(0, 0));
277 EXPECT_EQ(kTransparent
,
278 output
.getColor(tile_rect
.width() - 1, tile_rect
.height() - 1));
279 EXPECT_EQ(kTransparent
,
280 output
.getColor(visible_rect
.x() - 1, visible_rect
.y() - 1));
281 EXPECT_EQ(kTransparent
,
282 output
.getColor(visible_rect
.right(), visible_rect
.bottom()));
283 // Ensure visible part is drawn correctly.
284 EXPECT_EQ(SK_ColorCYAN
, output
.getColor(visible_rect
.x(), visible_rect
.y()));
287 output
.getColor(visible_rect
.right() - 2, visible_rect
.bottom() - 2));
288 // Ensure last visible line is correct.
291 output
.getColor(visible_rect
.right() - 1, visible_rect
.bottom() - 1));
294 TEST_F(SoftwareRendererTest
, ShouldClearRootRenderPass
) {
295 float device_scale_factor
= 1.f
;
296 gfx::Rect
viewport_rect(0, 0, 100, 100);
297 set_viewport(viewport_rect
);
299 settings_
.should_clear_root_render_pass
= false;
300 InitializeRenderer(make_scoped_ptr(new SoftwareOutputDevice
));
305 output
.setConfig(SkBitmap::kARGB_8888_Config
,
306 viewport_rect
.width(),
307 viewport_rect
.height());
308 output
.allocPixels();
310 // Draw a fullscreen green quad in a first frame.
311 RenderPass::Id
root_clear_pass_id(1, 0);
312 TestRenderPass
* root_clear_pass
= AddRenderPass(
313 &list
, root_clear_pass_id
, viewport_rect
, gfx::Transform());
314 AddQuad(root_clear_pass
, viewport_rect
, SK_ColorGREEN
);
316 renderer()->DecideRenderPassAllocationsForFrame(list
);
317 renderer()->DrawFrame(&list
, NULL
, device_scale_factor
, true);
318 renderer()->GetFramebufferPixels(output
.getPixels(), viewport_rect
);
320 EXPECT_EQ(SK_ColorGREEN
, output
.getColor(0, 0));
321 EXPECT_EQ(SK_ColorGREEN
,
322 output
.getColor(viewport_rect
.width() - 1, viewport_rect
.height() - 1));
326 // Draw a smaller magenta rect without filling the viewport in a separate
328 gfx::Rect
smaller_rect(20, 20, 60, 60);
330 RenderPass::Id
root_smaller_pass_id(2, 0);
331 TestRenderPass
* root_smaller_pass
= AddRenderPass(
332 &list
, root_smaller_pass_id
, viewport_rect
, gfx::Transform());
333 AddQuad(root_smaller_pass
, smaller_rect
, SK_ColorMAGENTA
);
335 renderer()->DecideRenderPassAllocationsForFrame(list
);
336 renderer()->DrawFrame(&list
, NULL
, device_scale_factor
, true);
337 renderer()->GetFramebufferPixels(output
.getPixels(), viewport_rect
);
339 // If we didn't clear, the borders should still be green.
340 EXPECT_EQ(SK_ColorGREEN
, output
.getColor(0, 0));
341 EXPECT_EQ(SK_ColorGREEN
,
342 output
.getColor(viewport_rect
.width() - 1, viewport_rect
.height() - 1));
344 EXPECT_EQ(SK_ColorMAGENTA
,
345 output
.getColor(smaller_rect
.x(), smaller_rect
.y()));
346 EXPECT_EQ(SK_ColorMAGENTA
,
347 output
.getColor(smaller_rect
.right() - 1, smaller_rect
.bottom() - 1));
350 TEST_F(SoftwareRendererTest
, RenderPassVisibleRect
) {
351 float device_scale_factor
= 1.f
;
352 gfx::Rect
viewport_rect(0, 0, 100, 100);
353 set_viewport(viewport_rect
);
354 InitializeRenderer(make_scoped_ptr(new SoftwareOutputDevice
));
359 output
.setConfig(SkBitmap::kARGB_8888_Config
,
360 viewport_rect
.width(),
361 viewport_rect
.height());
362 output
.allocPixels();
364 // Pass drawn as inner quad is magenta.
365 gfx::Rect
smaller_rect(20, 20, 60, 60);
366 RenderPass::Id
smaller_pass_id(2, 1);
367 TestRenderPass
* smaller_pass
=
368 AddRenderPass(&list
, smaller_pass_id
, smaller_rect
, gfx::Transform());
369 AddQuad(smaller_pass
, smaller_rect
, SK_ColorMAGENTA
);
371 // Root pass is green.
372 RenderPass::Id
root_clear_pass_id(1, 0);
373 TestRenderPass
* root_clear_pass
=
374 AddRenderPass(&list
, root_clear_pass_id
, viewport_rect
, gfx::Transform());
375 AddRenderPassQuad(root_clear_pass
, smaller_pass
);
376 AddQuad(root_clear_pass
, viewport_rect
, SK_ColorGREEN
);
378 // Interior pass quad has smaller visible rect.
379 gfx::Rect
interior_visible_rect(30, 30, 40, 40);
380 root_clear_pass
->quad_list
[0]->visible_rect
= interior_visible_rect
;
382 renderer()->DecideRenderPassAllocationsForFrame(list
);
383 renderer()->DrawFrame(&list
, NULL
, device_scale_factor
, true);
384 renderer()->GetFramebufferPixels(output
.getPixels(), viewport_rect
);
386 EXPECT_EQ(SK_ColorGREEN
, output
.getColor(0, 0));
389 output
.getColor(viewport_rect
.width() - 1, viewport_rect
.height() - 1));
391 // Part outside visible rect should remain green.
392 EXPECT_EQ(SK_ColorGREEN
, output
.getColor(smaller_rect
.x(), smaller_rect
.y()));
395 output
.getColor(smaller_rect
.right() - 1, smaller_rect
.bottom() - 1));
399 output
.getColor(interior_visible_rect
.x(), interior_visible_rect
.y()));
400 EXPECT_EQ(SK_ColorMAGENTA
,
401 output
.getColor(interior_visible_rect
.right() - 1,
402 interior_visible_rect
.bottom() - 1));