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(), NULL
, 0, false, 1);
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 // RendererClient implementation.
49 virtual void SetFullRootLayerDamage() OVERRIDE
{}
52 LayerTreeSettings settings_
;
53 FakeOutputSurfaceClient output_surface_client_
;
54 scoped_ptr
<FakeOutputSurface
> output_surface_
;
55 scoped_ptr
<ResourceProvider
> resource_provider_
;
56 scoped_ptr
<SoftwareRenderer
> renderer_
;
59 TEST_F(SoftwareRendererTest
, SolidColorQuad
) {
60 gfx::Size
outer_size(100, 100);
61 gfx::Size
inner_size(98, 98);
62 gfx::Rect
outer_rect(outer_size
);
63 gfx::Rect
inner_rect(gfx::Point(1, 1), inner_size
);
64 gfx::Rect
visible_rect(gfx::Point(1, 2), gfx::Size(98, 97));
66 InitializeRenderer(make_scoped_ptr(new SoftwareOutputDevice
));
68 scoped_ptr
<SharedQuadState
> shared_quad_state
= SharedQuadState::Create();
69 shared_quad_state
->SetAll(gfx::Transform(),
75 SkXfermode::kSrcOver_Mode
);
76 RenderPass::Id root_render_pass_id
= RenderPass::Id(1, 1);
77 scoped_ptr
<TestRenderPass
> root_render_pass
= TestRenderPass::Create();
78 root_render_pass
->SetNew(
79 root_render_pass_id
, outer_rect
, outer_rect
, gfx::Transform());
80 scoped_ptr
<SolidColorDrawQuad
> outer_quad
= SolidColorDrawQuad::Create();
82 shared_quad_state
.get(), outer_rect
, SK_ColorYELLOW
, false);
83 scoped_ptr
<SolidColorDrawQuad
> inner_quad
= SolidColorDrawQuad::Create();
84 inner_quad
->SetNew(shared_quad_state
.get(), inner_rect
, SK_ColorCYAN
, false);
85 inner_quad
->visible_rect
= visible_rect
;
86 root_render_pass
->AppendQuad(inner_quad
.PassAs
<DrawQuad
>());
87 root_render_pass
->AppendQuad(outer_quad
.PassAs
<DrawQuad
>());
90 list
.push_back(root_render_pass
.PassAs
<RenderPass
>());
92 float device_scale_factor
= 1.f
;
93 gfx::Rect
device_viewport_rect(outer_size
);
94 renderer()->DrawFrame(&list
,
104 SkBitmap::kARGB_8888_Config
, outer_rect
.width(), outer_rect
.height());
105 output
.allocPixels();
106 renderer()->GetFramebufferPixels(output
.getPixels(), outer_rect
);
108 EXPECT_EQ(SK_ColorYELLOW
, output
.getColor(0, 0));
109 EXPECT_EQ(SK_ColorYELLOW
,
110 output
.getColor(outer_size
.width() - 1, outer_size
.height() - 1));
111 EXPECT_EQ(SK_ColorYELLOW
, output
.getColor(1, 1));
112 EXPECT_EQ(SK_ColorCYAN
, output
.getColor(1, 2));
113 EXPECT_EQ(SK_ColorCYAN
,
114 output
.getColor(inner_size
.width() - 1, inner_size
.height() - 1));
117 TEST_F(SoftwareRendererTest
, TileQuad
) {
118 gfx::Size
outer_size(100, 100);
119 gfx::Size
inner_size(98, 98);
120 gfx::Rect
outer_rect(outer_size
);
121 gfx::Rect
inner_rect(gfx::Point(1, 1), inner_size
);
122 InitializeRenderer(make_scoped_ptr(new SoftwareOutputDevice
));
124 ResourceProvider::ResourceId resource_yellow
=
125 resource_provider()->CreateResource(outer_size
,
127 ResourceProvider::TextureUsageAny
,
129 ResourceProvider::ResourceId resource_cyan
=
130 resource_provider()->CreateResource(inner_size
,
132 ResourceProvider::TextureUsageAny
,
135 SkBitmap yellow_tile
;
136 yellow_tile
.setConfig(
137 SkBitmap::kARGB_8888_Config
, outer_size
.width(), outer_size
.height());
138 yellow_tile
.allocPixels();
139 yellow_tile
.eraseColor(SK_ColorYELLOW
);
143 SkBitmap::kARGB_8888_Config
, inner_size
.width(), inner_size
.height());
144 cyan_tile
.allocPixels();
145 cyan_tile
.eraseColor(SK_ColorCYAN
);
147 resource_provider()->SetPixels(
149 static_cast<uint8_t*>(yellow_tile
.getPixels()),
150 gfx::Rect(outer_size
),
151 gfx::Rect(outer_size
),
153 resource_provider()->SetPixels(resource_cyan
,
154 static_cast<uint8_t*>(cyan_tile
.getPixels()),
155 gfx::Rect(inner_size
),
156 gfx::Rect(inner_size
),
159 gfx::Rect root_rect
= outer_rect
;
161 scoped_ptr
<SharedQuadState
> shared_quad_state
= SharedQuadState::Create();
162 shared_quad_state
->SetAll(gfx::Transform(),
168 SkXfermode::kSrcOver_Mode
);
169 RenderPass::Id root_render_pass_id
= RenderPass::Id(1, 1);
170 scoped_ptr
<TestRenderPass
> root_render_pass
= TestRenderPass::Create();
171 root_render_pass
->SetNew(
172 root_render_pass_id
, root_rect
, root_rect
, gfx::Transform());
173 scoped_ptr
<TileDrawQuad
> outer_quad
= TileDrawQuad::Create();
174 outer_quad
->SetNew(shared_quad_state
.get(),
178 gfx::RectF(outer_size
),
181 scoped_ptr
<TileDrawQuad
> inner_quad
= TileDrawQuad::Create();
182 inner_quad
->SetNew(shared_quad_state
.get(),
186 gfx::RectF(inner_size
),
189 root_render_pass
->AppendQuad(inner_quad
.PassAs
<DrawQuad
>());
190 root_render_pass
->AppendQuad(outer_quad
.PassAs
<DrawQuad
>());
193 list
.push_back(root_render_pass
.PassAs
<RenderPass
>());
195 float device_scale_factor
= 1.f
;
196 gfx::Rect
device_viewport_rect(outer_size
);
197 renderer()->DrawFrame(&list
,
200 device_viewport_rect
,
201 device_viewport_rect
,
207 SkBitmap::kARGB_8888_Config
, outer_size
.width(), outer_size
.height());
208 output
.allocPixels();
209 renderer()->GetFramebufferPixels(output
.getPixels(), outer_rect
);
211 EXPECT_EQ(SK_ColorYELLOW
, output
.getColor(0, 0));
212 EXPECT_EQ(SK_ColorYELLOW
,
213 output
.getColor(outer_size
.width() - 1, outer_size
.height() - 1));
214 EXPECT_EQ(SK_ColorCYAN
, output
.getColor(1, 1));
215 EXPECT_EQ(SK_ColorCYAN
,
216 output
.getColor(inner_size
.width() - 1, inner_size
.height() - 1));
219 TEST_F(SoftwareRendererTest
, TileQuadVisibleRect
) {
220 gfx::Size
tile_size(100, 100);
221 gfx::Rect
tile_rect(tile_size
);
222 gfx::Rect visible_rect
= tile_rect
;
223 visible_rect
.Inset(1, 2, 3, 4);
224 InitializeRenderer(make_scoped_ptr(new SoftwareOutputDevice
));
226 ResourceProvider::ResourceId resource_cyan
=
227 resource_provider()->CreateResource(tile_size
,
229 ResourceProvider::TextureUsageAny
,
232 SkBitmap cyan_tile
; // The lowest five rows are yellow.
234 SkBitmap::kARGB_8888_Config
, tile_size
.width(), tile_size
.height());
235 cyan_tile
.allocPixels();
236 cyan_tile
.eraseColor(SK_ColorCYAN
);
239 0, visible_rect
.bottom() - 1, tile_rect
.width(), tile_rect
.bottom()),
242 resource_provider()->SetPixels(resource_cyan
,
243 static_cast<uint8_t*>(cyan_tile
.getPixels()),
244 gfx::Rect(tile_size
),
245 gfx::Rect(tile_size
),
248 gfx::Rect
root_rect(tile_size
);
250 scoped_ptr
<SharedQuadState
> shared_quad_state
= SharedQuadState::Create();
251 shared_quad_state
->SetAll(gfx::Transform(),
257 SkXfermode::kSrcOver_Mode
);
258 RenderPass::Id root_render_pass_id
= RenderPass::Id(1, 1);
259 scoped_ptr
<TestRenderPass
> root_render_pass
= TestRenderPass::Create();
260 root_render_pass
->SetNew(
261 root_render_pass_id
, root_rect
, root_rect
, gfx::Transform());
262 scoped_ptr
<TileDrawQuad
> quad
= TileDrawQuad::Create();
263 quad
->SetNew(shared_quad_state
.get(),
267 gfx::RectF(tile_size
),
270 quad
->visible_rect
= visible_rect
;
271 root_render_pass
->AppendQuad(quad
.PassAs
<DrawQuad
>());
274 list
.push_back(root_render_pass
.PassAs
<RenderPass
>());
276 float device_scale_factor
= 1.f
;
277 gfx::Rect
device_viewport_rect(tile_size
);
278 renderer()->DrawFrame(&list
,
281 device_viewport_rect
,
282 device_viewport_rect
,
288 SkBitmap::kARGB_8888_Config
, tile_size
.width(), tile_size
.height());
289 output
.allocPixels();
290 renderer()->GetFramebufferPixels(output
.getPixels(), tile_rect
);
292 // Check portion of tile not in visible rect isn't drawn.
293 const unsigned int kTransparent
= SK_ColorTRANSPARENT
;
294 EXPECT_EQ(kTransparent
, output
.getColor(0, 0));
295 EXPECT_EQ(kTransparent
,
296 output
.getColor(tile_rect
.width() - 1, tile_rect
.height() - 1));
297 EXPECT_EQ(kTransparent
,
298 output
.getColor(visible_rect
.x() - 1, visible_rect
.y() - 1));
299 EXPECT_EQ(kTransparent
,
300 output
.getColor(visible_rect
.right(), visible_rect
.bottom()));
301 // Ensure visible part is drawn correctly.
302 EXPECT_EQ(SK_ColorCYAN
, output
.getColor(visible_rect
.x(), visible_rect
.y()));
305 output
.getColor(visible_rect
.right() - 2, visible_rect
.bottom() - 2));
306 // Ensure last visible line is correct.
309 output
.getColor(visible_rect
.right() - 1, visible_rect
.bottom() - 1));
312 TEST_F(SoftwareRendererTest
, ShouldClearRootRenderPass
) {
313 float device_scale_factor
= 1.f
;
314 gfx::Rect
viewport_rect(0, 0, 100, 100);
316 settings_
.should_clear_root_render_pass
= false;
317 InitializeRenderer(make_scoped_ptr(new SoftwareOutputDevice
));
322 output
.setConfig(SkBitmap::kARGB_8888_Config
,
323 viewport_rect
.width(),
324 viewport_rect
.height());
325 output
.allocPixels();
327 // Draw a fullscreen green quad in a first frame.
328 RenderPass::Id
root_clear_pass_id(1, 0);
329 TestRenderPass
* root_clear_pass
= AddRenderPass(
330 &list
, root_clear_pass_id
, viewport_rect
, gfx::Transform());
331 AddQuad(root_clear_pass
, viewport_rect
, SK_ColorGREEN
);
333 renderer()->DecideRenderPassAllocationsForFrame(list
);
334 renderer()->DrawFrame(&list
,
341 renderer()->GetFramebufferPixels(output
.getPixels(), viewport_rect
);
343 EXPECT_EQ(SK_ColorGREEN
, output
.getColor(0, 0));
344 EXPECT_EQ(SK_ColorGREEN
,
345 output
.getColor(viewport_rect
.width() - 1, viewport_rect
.height() - 1));
349 // Draw a smaller magenta rect without filling the viewport in a separate
351 gfx::Rect
smaller_rect(20, 20, 60, 60);
353 RenderPass::Id
root_smaller_pass_id(2, 0);
354 TestRenderPass
* root_smaller_pass
= AddRenderPass(
355 &list
, root_smaller_pass_id
, viewport_rect
, gfx::Transform());
356 AddQuad(root_smaller_pass
, smaller_rect
, SK_ColorMAGENTA
);
358 renderer()->DecideRenderPassAllocationsForFrame(list
);
359 renderer()->DrawFrame(&list
,
366 renderer()->GetFramebufferPixels(output
.getPixels(), viewport_rect
);
368 // If we didn't clear, the borders should still be green.
369 EXPECT_EQ(SK_ColorGREEN
, output
.getColor(0, 0));
370 EXPECT_EQ(SK_ColorGREEN
,
371 output
.getColor(viewport_rect
.width() - 1, viewport_rect
.height() - 1));
373 EXPECT_EQ(SK_ColorMAGENTA
,
374 output
.getColor(smaller_rect
.x(), smaller_rect
.y()));
375 EXPECT_EQ(SK_ColorMAGENTA
,
376 output
.getColor(smaller_rect
.right() - 1, smaller_rect
.bottom() - 1));
379 TEST_F(SoftwareRendererTest
, RenderPassVisibleRect
) {
380 float device_scale_factor
= 1.f
;
381 gfx::Rect
viewport_rect(0, 0, 100, 100);
382 InitializeRenderer(make_scoped_ptr(new SoftwareOutputDevice
));
387 output
.setConfig(SkBitmap::kARGB_8888_Config
,
388 viewport_rect
.width(),
389 viewport_rect
.height());
390 output
.allocPixels();
392 // Pass drawn as inner quad is magenta.
393 gfx::Rect
smaller_rect(20, 20, 60, 60);
394 RenderPass::Id
smaller_pass_id(2, 1);
395 TestRenderPass
* smaller_pass
=
396 AddRenderPass(&list
, smaller_pass_id
, smaller_rect
, gfx::Transform());
397 AddQuad(smaller_pass
, smaller_rect
, SK_ColorMAGENTA
);
399 // Root pass is green.
400 RenderPass::Id
root_clear_pass_id(1, 0);
401 TestRenderPass
* root_clear_pass
=
402 AddRenderPass(&list
, root_clear_pass_id
, viewport_rect
, gfx::Transform());
403 AddRenderPassQuad(root_clear_pass
, smaller_pass
);
404 AddQuad(root_clear_pass
, viewport_rect
, SK_ColorGREEN
);
406 // Interior pass quad has smaller visible rect.
407 gfx::Rect
interior_visible_rect(30, 30, 40, 40);
408 root_clear_pass
->quad_list
[0]->visible_rect
= interior_visible_rect
;
410 renderer()->DecideRenderPassAllocationsForFrame(list
);
411 renderer()->DrawFrame(&list
,
418 renderer()->GetFramebufferPixels(output
.getPixels(), viewport_rect
);
420 EXPECT_EQ(SK_ColorGREEN
, output
.getColor(0, 0));
423 output
.getColor(viewport_rect
.width() - 1, viewport_rect
.height() - 1));
425 // Part outside visible rect should remain green.
426 EXPECT_EQ(SK_ColorGREEN
, output
.getColor(smaller_rect
.x(), smaller_rect
.y()));
429 output
.getColor(smaller_rect
.right() - 1, smaller_rect
.bottom() - 1));
433 output
.getColor(interior_visible_rect
.x(), interior_visible_rect
.y()));
434 EXPECT_EQ(SK_ColorMAGENTA
,
435 output
.getColor(interior_visible_rect
.right() - 1,
436 interior_visible_rect
.bottom() - 1));