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 "base/run_loop.h"
8 #include "cc/layers/quad_sink.h"
9 #include "cc/output/compositor_frame_metadata.h"
10 #include "cc/output/copy_output_request.h"
11 #include "cc/output/copy_output_result.h"
12 #include "cc/output/software_output_device.h"
13 #include "cc/quads/render_pass.h"
14 #include "cc/quads/render_pass_draw_quad.h"
15 #include "cc/quads/solid_color_draw_quad.h"
16 #include "cc/quads/tile_draw_quad.h"
17 #include "cc/test/animation_test_common.h"
18 #include "cc/test/fake_output_surface.h"
19 #include "cc/test/fake_output_surface_client.h"
20 #include "cc/test/geometry_test_utils.h"
21 #include "cc/test/render_pass_test_common.h"
22 #include "cc/test/render_pass_test_utils.h"
23 #include "cc/test/test_shared_bitmap_manager.h"
24 #include "testing/gmock/include/gmock/gmock.h"
25 #include "testing/gtest/include/gtest/gtest.h"
26 #include "third_party/skia/include/core/SkCanvas.h"
31 class SoftwareRendererTest
: public testing::Test
, public RendererClient
{
33 void InitializeRenderer(
34 scoped_ptr
<SoftwareOutputDevice
> software_output_device
) {
35 output_surface_
= FakeOutputSurface::CreateSoftware(
36 software_output_device
.Pass());
37 CHECK(output_surface_
->BindToClient(&output_surface_client_
));
39 shared_bitmap_manager_
.reset(new TestSharedBitmapManager());
40 resource_provider_
= ResourceProvider::Create(
41 output_surface_
.get(), shared_bitmap_manager_
.get(), 0, false, 1,
43 renderer_
= SoftwareRenderer::Create(
44 this, &settings_
, output_surface_
.get(), resource_provider());
47 ResourceProvider
* resource_provider() const {
48 return resource_provider_
.get();
51 SoftwareRenderer
* renderer() const { return renderer_
.get(); }
53 // RendererClient implementation.
54 virtual void SetFullRootLayerDamage() OVERRIDE
{}
56 scoped_ptr
<SkBitmap
> DrawAndCopyOutput(RenderPassList
* list
,
57 float device_scale_factor
,
58 gfx::Rect device_viewport_rect
) {
59 scoped_ptr
<SkBitmap
> bitmap_result
;
62 list
->back()->copy_requests
.push_back(
63 CopyOutputRequest::CreateBitmapRequest(
64 base::Bind(&SoftwareRendererTest::SaveBitmapResult
,
65 base::Unretained(&bitmap_result
),
66 loop
.QuitClosure())));
68 renderer()->DrawFrame(list
,
74 return bitmap_result
.Pass();
77 static void SaveBitmapResult(scoped_ptr
<SkBitmap
>* bitmap_result
,
78 const base::Closure
& quit_closure
,
79 scoped_ptr
<CopyOutputResult
> result
) {
80 DCHECK(result
->HasBitmap());
81 *bitmap_result
= result
->TakeBitmap();
86 LayerTreeSettings settings_
;
87 FakeOutputSurfaceClient output_surface_client_
;
88 scoped_ptr
<FakeOutputSurface
> output_surface_
;
89 scoped_ptr
<SharedBitmapManager
> shared_bitmap_manager_
;
90 scoped_ptr
<ResourceProvider
> resource_provider_
;
91 scoped_ptr
<SoftwareRenderer
> renderer_
;
94 TEST_F(SoftwareRendererTest
, SolidColorQuad
) {
95 gfx::Size
outer_size(100, 100);
96 gfx::Size
inner_size(98, 98);
97 gfx::Rect
outer_rect(outer_size
);
98 gfx::Rect
inner_rect(gfx::Point(1, 1), inner_size
);
99 gfx::Rect
visible_rect(gfx::Point(1, 2), gfx::Size(98, 97));
101 InitializeRenderer(make_scoped_ptr(new SoftwareOutputDevice
));
103 RenderPass::Id root_render_pass_id
= RenderPass::Id(1, 1);
104 scoped_ptr
<TestRenderPass
> root_render_pass
= TestRenderPass::Create();
105 root_render_pass
->SetNew(
106 root_render_pass_id
, outer_rect
, outer_rect
, gfx::Transform());
107 SharedQuadState
* shared_quad_state
=
108 root_render_pass
->CreateAndAppendSharedQuadState();
109 shared_quad_state
->SetAll(gfx::Transform(),
115 SkXfermode::kSrcOver_Mode
);
116 scoped_ptr
<SolidColorDrawQuad
> outer_quad
= SolidColorDrawQuad::Create();
118 shared_quad_state
, outer_rect
, outer_rect
, SK_ColorYELLOW
, false);
119 scoped_ptr
<SolidColorDrawQuad
> inner_quad
= SolidColorDrawQuad::Create();
121 shared_quad_state
, inner_rect
, inner_rect
, SK_ColorCYAN
, false);
122 inner_quad
->visible_rect
= visible_rect
;
123 root_render_pass
->AppendQuad(inner_quad
.PassAs
<DrawQuad
>());
124 root_render_pass
->AppendQuad(outer_quad
.PassAs
<DrawQuad
>());
127 list
.push_back(root_render_pass
.PassAs
<RenderPass
>());
129 float device_scale_factor
= 1.f
;
130 gfx::Rect
device_viewport_rect(outer_size
);
131 scoped_ptr
<SkBitmap
> output
=
132 DrawAndCopyOutput(&list
, device_scale_factor
, device_viewport_rect
);
133 EXPECT_EQ(outer_rect
.width(), output
->info().fWidth
);
134 EXPECT_EQ(outer_rect
.width(), output
->info().fHeight
);
136 EXPECT_EQ(SK_ColorYELLOW
, output
->getColor(0, 0));
137 EXPECT_EQ(SK_ColorYELLOW
,
138 output
->getColor(outer_size
.width() - 1, outer_size
.height() - 1));
139 EXPECT_EQ(SK_ColorYELLOW
, output
->getColor(1, 1));
140 EXPECT_EQ(SK_ColorCYAN
, output
->getColor(1, 2));
141 EXPECT_EQ(SK_ColorCYAN
,
142 output
->getColor(inner_size
.width() - 1, inner_size
.height() - 1));
145 TEST_F(SoftwareRendererTest
, TileQuad
) {
146 gfx::Size
outer_size(100, 100);
147 gfx::Size
inner_size(98, 98);
148 gfx::Rect
outer_rect(outer_size
);
149 gfx::Rect
inner_rect(gfx::Point(1, 1), inner_size
);
150 InitializeRenderer(make_scoped_ptr(new SoftwareOutputDevice
));
152 ResourceProvider::ResourceId resource_yellow
=
153 resource_provider()->CreateResource(outer_size
,
155 ResourceProvider::TextureUsageAny
,
157 ResourceProvider::ResourceId resource_cyan
=
158 resource_provider()->CreateResource(inner_size
,
160 ResourceProvider::TextureUsageAny
,
163 SkBitmap yellow_tile
;
164 yellow_tile
.setConfig(
165 SkBitmap::kARGB_8888_Config
, outer_size
.width(), outer_size
.height());
166 yellow_tile
.allocPixels();
167 yellow_tile
.eraseColor(SK_ColorYELLOW
);
171 SkBitmap::kARGB_8888_Config
, inner_size
.width(), inner_size
.height());
172 cyan_tile
.allocPixels();
173 cyan_tile
.eraseColor(SK_ColorCYAN
);
175 resource_provider()->SetPixels(
177 static_cast<uint8_t*>(yellow_tile
.getPixels()),
178 gfx::Rect(outer_size
),
179 gfx::Rect(outer_size
),
181 resource_provider()->SetPixels(resource_cyan
,
182 static_cast<uint8_t*>(cyan_tile
.getPixels()),
183 gfx::Rect(inner_size
),
184 gfx::Rect(inner_size
),
187 gfx::Rect root_rect
= outer_rect
;
189 RenderPass::Id root_render_pass_id
= RenderPass::Id(1, 1);
190 scoped_ptr
<TestRenderPass
> root_render_pass
= TestRenderPass::Create();
191 root_render_pass
->SetNew(
192 root_render_pass_id
, root_rect
, root_rect
, gfx::Transform());
193 SharedQuadState
* shared_quad_state
=
194 root_render_pass
->CreateAndAppendSharedQuadState();
195 shared_quad_state
->SetAll(gfx::Transform(),
201 SkXfermode::kSrcOver_Mode
);
202 scoped_ptr
<TileDrawQuad
> outer_quad
= TileDrawQuad::Create();
203 outer_quad
->SetNew(shared_quad_state
,
208 gfx::RectF(outer_size
),
211 scoped_ptr
<TileDrawQuad
> inner_quad
= TileDrawQuad::Create();
212 inner_quad
->SetNew(shared_quad_state
,
217 gfx::RectF(inner_size
),
220 root_render_pass
->AppendQuad(inner_quad
.PassAs
<DrawQuad
>());
221 root_render_pass
->AppendQuad(outer_quad
.PassAs
<DrawQuad
>());
224 list
.push_back(root_render_pass
.PassAs
<RenderPass
>());
226 float device_scale_factor
= 1.f
;
227 gfx::Rect
device_viewport_rect(outer_size
);
228 scoped_ptr
<SkBitmap
> output
=
229 DrawAndCopyOutput(&list
, device_scale_factor
, device_viewport_rect
);
230 EXPECT_EQ(outer_rect
.width(), output
->info().fWidth
);
231 EXPECT_EQ(outer_rect
.width(), output
->info().fHeight
);
233 EXPECT_EQ(SK_ColorYELLOW
, output
->getColor(0, 0));
234 EXPECT_EQ(SK_ColorYELLOW
,
235 output
->getColor(outer_size
.width() - 1, outer_size
.height() - 1));
236 EXPECT_EQ(SK_ColorCYAN
, output
->getColor(1, 1));
237 EXPECT_EQ(SK_ColorCYAN
,
238 output
->getColor(inner_size
.width() - 1, inner_size
.height() - 1));
241 TEST_F(SoftwareRendererTest
, TileQuadVisibleRect
) {
242 gfx::Size
tile_size(100, 100);
243 gfx::Rect
tile_rect(tile_size
);
244 gfx::Rect visible_rect
= tile_rect
;
245 visible_rect
.Inset(1, 2, 3, 4);
246 InitializeRenderer(make_scoped_ptr(new SoftwareOutputDevice
));
248 ResourceProvider::ResourceId resource_cyan
=
249 resource_provider()->CreateResource(tile_size
,
251 ResourceProvider::TextureUsageAny
,
254 SkBitmap cyan_tile
; // The lowest five rows are yellow.
256 SkBitmap::kARGB_8888_Config
, tile_size
.width(), tile_size
.height());
257 cyan_tile
.allocPixels();
258 cyan_tile
.eraseColor(SK_ColorCYAN
);
261 0, visible_rect
.bottom() - 1, tile_rect
.width(), tile_rect
.bottom()),
264 resource_provider()->SetPixels(resource_cyan
,
265 static_cast<uint8_t*>(cyan_tile
.getPixels()),
266 gfx::Rect(tile_size
),
267 gfx::Rect(tile_size
),
270 gfx::Rect
root_rect(tile_size
);
272 RenderPass::Id root_render_pass_id
= RenderPass::Id(1, 1);
273 scoped_ptr
<TestRenderPass
> root_render_pass
= TestRenderPass::Create();
274 root_render_pass
->SetNew(
275 root_render_pass_id
, root_rect
, root_rect
, gfx::Transform());
276 SharedQuadState
* shared_quad_state
=
277 root_render_pass
->CreateAndAppendSharedQuadState();
278 shared_quad_state
->SetAll(gfx::Transform(),
284 SkXfermode::kSrcOver_Mode
);
285 scoped_ptr
<TileDrawQuad
> quad
= TileDrawQuad::Create();
286 quad
->SetNew(shared_quad_state
,
291 gfx::RectF(tile_size
),
294 quad
->visible_rect
= visible_rect
;
295 root_render_pass
->AppendQuad(quad
.PassAs
<DrawQuad
>());
298 list
.push_back(root_render_pass
.PassAs
<RenderPass
>());
300 float device_scale_factor
= 1.f
;
301 gfx::Rect
device_viewport_rect(tile_size
);
302 scoped_ptr
<SkBitmap
> output
=
303 DrawAndCopyOutput(&list
, device_scale_factor
, device_viewport_rect
);
304 EXPECT_EQ(tile_rect
.width(), output
->info().fWidth
);
305 EXPECT_EQ(tile_rect
.width(), output
->info().fHeight
);
307 // Check portion of tile not in visible rect isn't drawn.
308 const unsigned int kTransparent
= SK_ColorTRANSPARENT
;
309 EXPECT_EQ(kTransparent
, output
->getColor(0, 0));
310 EXPECT_EQ(kTransparent
,
311 output
->getColor(tile_rect
.width() - 1, tile_rect
.height() - 1));
312 EXPECT_EQ(kTransparent
,
313 output
->getColor(visible_rect
.x() - 1, visible_rect
.y() - 1));
314 EXPECT_EQ(kTransparent
,
315 output
->getColor(visible_rect
.right(), visible_rect
.bottom()));
316 // Ensure visible part is drawn correctly.
317 EXPECT_EQ(SK_ColorCYAN
, output
->getColor(visible_rect
.x(), visible_rect
.y()));
320 output
->getColor(visible_rect
.right() - 2, visible_rect
.bottom() - 2));
321 // Ensure last visible line is correct.
324 output
->getColor(visible_rect
.right() - 1, visible_rect
.bottom() - 1));
327 TEST_F(SoftwareRendererTest
, ShouldClearRootRenderPass
) {
328 float device_scale_factor
= 1.f
;
329 gfx::Rect
device_viewport_rect(0, 0, 100, 100);
331 settings_
.should_clear_root_render_pass
= false;
332 InitializeRenderer(make_scoped_ptr(new SoftwareOutputDevice
));
336 // Draw a fullscreen green quad in a first frame.
337 RenderPass::Id
root_clear_pass_id(1, 0);
338 TestRenderPass
* root_clear_pass
= AddRenderPass(
339 &list
, root_clear_pass_id
, device_viewport_rect
, gfx::Transform());
340 AddQuad(root_clear_pass
, device_viewport_rect
, SK_ColorGREEN
);
342 renderer()->DecideRenderPassAllocationsForFrame(list
);
344 scoped_ptr
<SkBitmap
> output
=
345 DrawAndCopyOutput(&list
, device_scale_factor
, device_viewport_rect
);
346 EXPECT_EQ(device_viewport_rect
.width(), output
->info().fWidth
);
347 EXPECT_EQ(device_viewport_rect
.width(), output
->info().fHeight
);
349 EXPECT_EQ(SK_ColorGREEN
, output
->getColor(0, 0));
350 EXPECT_EQ(SK_ColorGREEN
,
351 output
->getColor(device_viewport_rect
.width() - 1,
352 device_viewport_rect
.height() - 1));
356 // Draw a smaller magenta rect without filling the viewport in a separate
358 gfx::Rect
smaller_rect(20, 20, 60, 60);
360 RenderPass::Id
root_smaller_pass_id(2, 0);
361 TestRenderPass
* root_smaller_pass
= AddRenderPass(
362 &list
, root_smaller_pass_id
, device_viewport_rect
, gfx::Transform());
363 AddQuad(root_smaller_pass
, smaller_rect
, SK_ColorMAGENTA
);
365 renderer()->DecideRenderPassAllocationsForFrame(list
);
367 output
= DrawAndCopyOutput(&list
, device_scale_factor
, device_viewport_rect
);
368 EXPECT_EQ(device_viewport_rect
.width(), output
->info().fWidth
);
369 EXPECT_EQ(device_viewport_rect
.width(), output
->info().fHeight
);
371 // If we didn't clear, the borders should still be green.
372 EXPECT_EQ(SK_ColorGREEN
, output
->getColor(0, 0));
373 EXPECT_EQ(SK_ColorGREEN
,
374 output
->getColor(device_viewport_rect
.width() - 1,
375 device_viewport_rect
.height() - 1));
377 EXPECT_EQ(SK_ColorMAGENTA
,
378 output
->getColor(smaller_rect
.x(), smaller_rect
.y()));
381 output
->getColor(smaller_rect
.right() - 1, smaller_rect
.bottom() - 1));
384 TEST_F(SoftwareRendererTest
, RenderPassVisibleRect
) {
385 float device_scale_factor
= 1.f
;
386 gfx::Rect
device_viewport_rect(0, 0, 100, 100);
387 InitializeRenderer(make_scoped_ptr(new SoftwareOutputDevice
));
391 // Pass drawn as inner quad is magenta.
392 gfx::Rect
smaller_rect(20, 20, 60, 60);
393 RenderPass::Id
smaller_pass_id(2, 1);
394 TestRenderPass
* smaller_pass
=
395 AddRenderPass(&list
, smaller_pass_id
, smaller_rect
, gfx::Transform());
396 AddQuad(smaller_pass
, smaller_rect
, SK_ColorMAGENTA
);
398 // Root pass is green.
399 RenderPass::Id
root_clear_pass_id(1, 0);
400 TestRenderPass
* root_clear_pass
= AddRenderPass(
401 &list
, root_clear_pass_id
, device_viewport_rect
, gfx::Transform());
402 AddRenderPassQuad(root_clear_pass
, smaller_pass
);
403 AddQuad(root_clear_pass
, device_viewport_rect
, SK_ColorGREEN
);
405 // Interior pass quad has smaller visible rect.
406 gfx::Rect
interior_visible_rect(30, 30, 40, 40);
407 root_clear_pass
->quad_list
[0]->visible_rect
= interior_visible_rect
;
409 renderer()->DecideRenderPassAllocationsForFrame(list
);
411 scoped_ptr
<SkBitmap
> output
=
412 DrawAndCopyOutput(&list
, device_scale_factor
, device_viewport_rect
);
413 EXPECT_EQ(device_viewport_rect
.width(), output
->info().fWidth
);
414 EXPECT_EQ(device_viewport_rect
.width(), output
->info().fHeight
);
416 EXPECT_EQ(SK_ColorGREEN
, output
->getColor(0, 0));
417 EXPECT_EQ(SK_ColorGREEN
,
418 output
->getColor(device_viewport_rect
.width() - 1,
419 device_viewport_rect
.height() - 1));
421 // Part outside visible rect should remain green.
422 EXPECT_EQ(SK_ColorGREEN
,
423 output
->getColor(smaller_rect
.x(), smaller_rect
.y()));
426 output
->getColor(smaller_rect
.right() - 1, smaller_rect
.bottom() - 1));
430 output
->getColor(interior_visible_rect
.x(), interior_visible_rect
.y()));
431 EXPECT_EQ(SK_ColorMAGENTA
,
432 output
->getColor(interior_visible_rect
.right() - 1,
433 interior_visible_rect
.bottom() - 1));