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/output/compositor_frame_metadata.h"
9 #include "cc/output/copy_output_request.h"
10 #include "cc/output/copy_output_result.h"
11 #include "cc/output/software_output_device.h"
12 #include "cc/quads/render_pass.h"
13 #include "cc/quads/render_pass_draw_quad.h"
14 #include "cc/quads/solid_color_draw_quad.h"
15 #include "cc/quads/tile_draw_quad.h"
16 #include "cc/test/animation_test_common.h"
17 #include "cc/test/fake_output_surface.h"
18 #include "cc/test/fake_output_surface_client.h"
19 #include "cc/test/fake_resource_provider.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_
= FakeResourceProvider::Create(
41 output_surface_
.get(), shared_bitmap_manager_
.get());
42 renderer_
= SoftwareRenderer::Create(
43 this, &settings_
, output_surface_
.get(), resource_provider());
46 ResourceProvider
* resource_provider() const {
47 return resource_provider_
.get();
50 SoftwareRenderer
* renderer() const { return renderer_
.get(); }
52 // RendererClient implementation.
53 void SetFullRootLayerDamage() override
{}
55 scoped_ptr
<SkBitmap
> DrawAndCopyOutput(RenderPassList
* list
,
56 float device_scale_factor
,
57 gfx::Rect device_viewport_rect
) {
58 scoped_ptr
<SkBitmap
> bitmap_result
;
61 list
->back()->copy_requests
.push_back(
62 CopyOutputRequest::CreateBitmapRequest(
63 base::Bind(&SoftwareRendererTest::SaveBitmapResult
,
64 base::Unretained(&bitmap_result
),
65 loop
.QuitClosure())));
67 renderer()->DrawFrame(list
,
73 return bitmap_result
.Pass();
76 static void SaveBitmapResult(scoped_ptr
<SkBitmap
>* bitmap_result
,
77 const base::Closure
& quit_closure
,
78 scoped_ptr
<CopyOutputResult
> result
) {
79 DCHECK(result
->HasBitmap());
80 *bitmap_result
= result
->TakeBitmap();
85 RendererSettings settings_
;
86 FakeOutputSurfaceClient output_surface_client_
;
87 scoped_ptr
<FakeOutputSurface
> output_surface_
;
88 scoped_ptr
<SharedBitmapManager
> shared_bitmap_manager_
;
89 scoped_ptr
<ResourceProvider
> resource_provider_
;
90 scoped_ptr
<SoftwareRenderer
> renderer_
;
93 TEST_F(SoftwareRendererTest
, SolidColorQuad
) {
94 gfx::Size
outer_size(100, 100);
95 gfx::Size
inner_size(98, 98);
96 gfx::Rect
outer_rect(outer_size
);
97 gfx::Rect
inner_rect(gfx::Point(1, 1), inner_size
);
98 gfx::Rect
visible_rect(gfx::Point(1, 2), gfx::Size(98, 97));
100 InitializeRenderer(make_scoped_ptr(new SoftwareOutputDevice
));
102 RenderPassId root_render_pass_id
= RenderPassId(1, 1);
103 scoped_ptr
<TestRenderPass
> root_render_pass
= TestRenderPass::Create();
104 root_render_pass
->SetNew(
105 root_render_pass_id
, outer_rect
, outer_rect
, gfx::Transform());
106 SharedQuadState
* shared_quad_state
=
107 root_render_pass
->CreateAndAppendSharedQuadState();
108 shared_quad_state
->SetAll(gfx::Transform(),
114 SkXfermode::kSrcOver_Mode
,
116 SolidColorDrawQuad
* inner_quad
=
117 root_render_pass
->CreateAndAppendDrawQuad
<SolidColorDrawQuad
>();
119 shared_quad_state
, inner_rect
, inner_rect
, SK_ColorCYAN
, false);
120 inner_quad
->visible_rect
= visible_rect
;
121 SolidColorDrawQuad
* outer_quad
=
122 root_render_pass
->CreateAndAppendDrawQuad
<SolidColorDrawQuad
>();
124 shared_quad_state
, outer_rect
, outer_rect
, SK_ColorYELLOW
, false);
127 list
.push_back(root_render_pass
.Pass());
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().width());
134 EXPECT_EQ(outer_rect
.height(), output
->info().height());
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 ResourceId resource_yellow
= resource_provider()->CreateResource(
153 outer_size
, GL_CLAMP_TO_EDGE
, ResourceProvider::TEXTURE_HINT_IMMUTABLE
,
155 ResourceId resource_cyan
= resource_provider()->CreateResource(
156 inner_size
, GL_CLAMP_TO_EDGE
, ResourceProvider::TEXTURE_HINT_IMMUTABLE
,
159 SkBitmap yellow_tile
;
160 yellow_tile
.allocN32Pixels(outer_size
.width(), outer_size
.height());
161 yellow_tile
.eraseColor(SK_ColorYELLOW
);
164 cyan_tile
.allocN32Pixels(inner_size
.width(), inner_size
.height());
165 cyan_tile
.eraseColor(SK_ColorCYAN
);
167 resource_provider()->CopyToResource(
168 resource_yellow
, static_cast<uint8_t*>(yellow_tile
.getPixels()),
170 resource_provider()->CopyToResource(
171 resource_cyan
, static_cast<uint8_t*>(cyan_tile
.getPixels()), inner_size
);
173 gfx::Rect root_rect
= outer_rect
;
175 RenderPassId root_render_pass_id
= RenderPassId(1, 1);
176 scoped_ptr
<TestRenderPass
> root_render_pass
= TestRenderPass::Create();
177 root_render_pass
->SetNew(
178 root_render_pass_id
, root_rect
, root_rect
, gfx::Transform());
179 SharedQuadState
* shared_quad_state
=
180 root_render_pass
->CreateAndAppendSharedQuadState();
181 shared_quad_state
->SetAll(gfx::Transform(),
187 SkXfermode::kSrcOver_Mode
,
189 TileDrawQuad
* inner_quad
=
190 root_render_pass
->CreateAndAppendDrawQuad
<TileDrawQuad
>();
191 inner_quad
->SetNew(shared_quad_state
,
196 gfx::RectF(inner_size
),
200 TileDrawQuad
* outer_quad
=
201 root_render_pass
->CreateAndAppendDrawQuad
<TileDrawQuad
>();
202 outer_quad
->SetNew(shared_quad_state
,
207 gfx::RectF(outer_size
),
213 list
.push_back(root_render_pass
.Pass());
215 float device_scale_factor
= 1.f
;
216 gfx::Rect
device_viewport_rect(outer_size
);
217 scoped_ptr
<SkBitmap
> output
=
218 DrawAndCopyOutput(&list
, device_scale_factor
, device_viewport_rect
);
219 EXPECT_EQ(outer_rect
.width(), output
->info().width());
220 EXPECT_EQ(outer_rect
.height(), output
->info().height());
222 EXPECT_EQ(SK_ColorYELLOW
, output
->getColor(0, 0));
223 EXPECT_EQ(SK_ColorYELLOW
,
224 output
->getColor(outer_size
.width() - 1, outer_size
.height() - 1));
225 EXPECT_EQ(SK_ColorCYAN
, output
->getColor(1, 1));
226 EXPECT_EQ(SK_ColorCYAN
,
227 output
->getColor(inner_size
.width() - 1, inner_size
.height() - 1));
230 TEST_F(SoftwareRendererTest
, TileQuadVisibleRect
) {
231 gfx::Size
tile_size(100, 100);
232 gfx::Rect
tile_rect(tile_size
);
233 gfx::Rect visible_rect
= tile_rect
;
234 visible_rect
.Inset(1, 2, 3, 4);
235 InitializeRenderer(make_scoped_ptr(new SoftwareOutputDevice
));
237 ResourceId resource_cyan
= resource_provider()->CreateResource(
238 tile_size
, GL_CLAMP_TO_EDGE
, ResourceProvider::TEXTURE_HINT_IMMUTABLE
,
241 SkBitmap cyan_tile
; // The lowest five rows are yellow.
242 cyan_tile
.allocN32Pixels(tile_size
.width(), tile_size
.height());
243 cyan_tile
.eraseColor(SK_ColorCYAN
);
246 0, visible_rect
.bottom() - 1, tile_rect
.width(), tile_rect
.bottom()),
249 resource_provider()->CopyToResource(
250 resource_cyan
, static_cast<uint8_t*>(cyan_tile
.getPixels()), tile_size
);
252 gfx::Rect
root_rect(tile_size
);
254 RenderPassId root_render_pass_id
= RenderPassId(1, 1);
255 scoped_ptr
<TestRenderPass
> root_render_pass
= TestRenderPass::Create();
256 root_render_pass
->SetNew(
257 root_render_pass_id
, root_rect
, root_rect
, gfx::Transform());
258 SharedQuadState
* shared_quad_state
=
259 root_render_pass
->CreateAndAppendSharedQuadState();
260 shared_quad_state
->SetAll(gfx::Transform(),
266 SkXfermode::kSrcOver_Mode
,
269 root_render_pass
->CreateAndAppendDrawQuad
<TileDrawQuad
>();
270 quad
->SetNew(shared_quad_state
,
275 gfx::RectF(tile_size
),
279 quad
->visible_rect
= visible_rect
;
282 list
.push_back(root_render_pass
.Pass());
284 float device_scale_factor
= 1.f
;
285 gfx::Rect
device_viewport_rect(tile_size
);
286 scoped_ptr
<SkBitmap
> output
=
287 DrawAndCopyOutput(&list
, device_scale_factor
, device_viewport_rect
);
288 EXPECT_EQ(tile_rect
.width(), output
->info().width());
289 EXPECT_EQ(tile_rect
.height(), output
->info().height());
291 // Check portion of tile not in visible rect isn't drawn.
292 const unsigned int kTransparent
= SK_ColorTRANSPARENT
;
293 EXPECT_EQ(kTransparent
, output
->getColor(0, 0));
294 EXPECT_EQ(kTransparent
,
295 output
->getColor(tile_rect
.width() - 1, tile_rect
.height() - 1));
296 EXPECT_EQ(kTransparent
,
297 output
->getColor(visible_rect
.x() - 1, visible_rect
.y() - 1));
298 EXPECT_EQ(kTransparent
,
299 output
->getColor(visible_rect
.right(), visible_rect
.bottom()));
300 // Ensure visible part is drawn correctly.
301 EXPECT_EQ(SK_ColorCYAN
, output
->getColor(visible_rect
.x(), visible_rect
.y()));
304 output
->getColor(visible_rect
.right() - 2, visible_rect
.bottom() - 2));
305 // Ensure last visible line is correct.
308 output
->getColor(visible_rect
.right() - 1, visible_rect
.bottom() - 1));
311 TEST_F(SoftwareRendererTest
, ShouldClearRootRenderPass
) {
312 float device_scale_factor
= 1.f
;
313 gfx::Rect
device_viewport_rect(0, 0, 100, 100);
315 settings_
.should_clear_root_render_pass
= false;
316 InitializeRenderer(make_scoped_ptr(new SoftwareOutputDevice
));
320 // Draw a fullscreen green quad in a first frame.
321 RenderPassId
root_clear_pass_id(1, 0);
322 TestRenderPass
* root_clear_pass
= AddRenderPass(
323 &list
, root_clear_pass_id
, device_viewport_rect
, gfx::Transform());
324 AddQuad(root_clear_pass
, device_viewport_rect
, SK_ColorGREEN
);
326 renderer()->DecideRenderPassAllocationsForFrame(list
);
328 scoped_ptr
<SkBitmap
> output
=
329 DrawAndCopyOutput(&list
, device_scale_factor
, device_viewport_rect
);
330 EXPECT_EQ(device_viewport_rect
.width(), output
->info().width());
331 EXPECT_EQ(device_viewport_rect
.height(), output
->info().height());
333 EXPECT_EQ(SK_ColorGREEN
, output
->getColor(0, 0));
334 EXPECT_EQ(SK_ColorGREEN
,
335 output
->getColor(device_viewport_rect
.width() - 1,
336 device_viewport_rect
.height() - 1));
340 // Draw a smaller magenta rect without filling the viewport in a separate
342 gfx::Rect
smaller_rect(20, 20, 60, 60);
344 RenderPassId
root_smaller_pass_id(2, 0);
345 TestRenderPass
* root_smaller_pass
= AddRenderPass(
346 &list
, root_smaller_pass_id
, device_viewport_rect
, gfx::Transform());
347 AddQuad(root_smaller_pass
, smaller_rect
, SK_ColorMAGENTA
);
349 renderer()->DecideRenderPassAllocationsForFrame(list
);
351 output
= DrawAndCopyOutput(&list
, device_scale_factor
, device_viewport_rect
);
352 EXPECT_EQ(device_viewport_rect
.width(), output
->info().width());
353 EXPECT_EQ(device_viewport_rect
.height(), output
->info().height());
355 // If we didn't clear, the borders should still be green.
356 EXPECT_EQ(SK_ColorGREEN
, output
->getColor(0, 0));
357 EXPECT_EQ(SK_ColorGREEN
,
358 output
->getColor(device_viewport_rect
.width() - 1,
359 device_viewport_rect
.height() - 1));
361 EXPECT_EQ(SK_ColorMAGENTA
,
362 output
->getColor(smaller_rect
.x(), smaller_rect
.y()));
365 output
->getColor(smaller_rect
.right() - 1, smaller_rect
.bottom() - 1));
368 TEST_F(SoftwareRendererTest
, RenderPassVisibleRect
) {
369 float device_scale_factor
= 1.f
;
370 gfx::Rect
device_viewport_rect(0, 0, 100, 100);
371 InitializeRenderer(make_scoped_ptr(new SoftwareOutputDevice
));
375 // Pass drawn as inner quad is magenta.
376 gfx::Rect
smaller_rect(20, 20, 60, 60);
377 RenderPassId
smaller_pass_id(2, 1);
378 TestRenderPass
* smaller_pass
=
379 AddRenderPass(&list
, smaller_pass_id
, smaller_rect
, gfx::Transform());
380 AddQuad(smaller_pass
, smaller_rect
, SK_ColorMAGENTA
);
382 // Root pass is green.
383 RenderPassId
root_clear_pass_id(1, 0);
384 TestRenderPass
* root_clear_pass
= AddRenderPass(
385 &list
, root_clear_pass_id
, device_viewport_rect
, gfx::Transform());
386 AddRenderPassQuad(root_clear_pass
, smaller_pass
);
387 AddQuad(root_clear_pass
, device_viewport_rect
, SK_ColorGREEN
);
389 // Interior pass quad has smaller visible rect.
390 gfx::Rect
interior_visible_rect(30, 30, 40, 40);
391 root_clear_pass
->quad_list
.front()->visible_rect
= interior_visible_rect
;
393 renderer()->DecideRenderPassAllocationsForFrame(list
);
395 scoped_ptr
<SkBitmap
> output
=
396 DrawAndCopyOutput(&list
, device_scale_factor
, device_viewport_rect
);
397 EXPECT_EQ(device_viewport_rect
.width(), output
->info().width());
398 EXPECT_EQ(device_viewport_rect
.height(), output
->info().height());
400 EXPECT_EQ(SK_ColorGREEN
, output
->getColor(0, 0));
401 EXPECT_EQ(SK_ColorGREEN
,
402 output
->getColor(device_viewport_rect
.width() - 1,
403 device_viewport_rect
.height() - 1));
405 // Part outside visible rect should remain green.
406 EXPECT_EQ(SK_ColorGREEN
,
407 output
->getColor(smaller_rect
.x(), smaller_rect
.y()));
410 output
->getColor(smaller_rect
.right() - 1, smaller_rect
.bottom() - 1));
414 output
->getColor(interior_visible_rect
.x(), interior_visible_rect
.y()));
415 EXPECT_EQ(SK_ColorMAGENTA
,
416 output
->getColor(interior_visible_rect
.right() - 1,
417 interior_visible_rect
.bottom() - 1));