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/geometry_test_utils.h"
20 #include "cc/test/render_pass_test_common.h"
21 #include "cc/test/render_pass_test_utils.h"
22 #include "cc/test/test_shared_bitmap_manager.h"
23 #include "testing/gmock/include/gmock/gmock.h"
24 #include "testing/gtest/include/gtest/gtest.h"
25 #include "third_party/skia/include/core/SkCanvas.h"
30 class SoftwareRendererTest
: public testing::Test
, public RendererClient
{
32 void InitializeRenderer(
33 scoped_ptr
<SoftwareOutputDevice
> software_output_device
) {
34 output_surface_
= FakeOutputSurface::CreateSoftware(
35 software_output_device
.Pass());
36 CHECK(output_surface_
->BindToClient(&output_surface_client_
));
38 shared_bitmap_manager_
.reset(new TestSharedBitmapManager());
39 resource_provider_
= ResourceProvider::Create(output_surface_
.get(),
40 shared_bitmap_manager_
.get(),
46 renderer_
= SoftwareRenderer::Create(
47 this, &settings_
, output_surface_
.get(), resource_provider());
50 ResourceProvider
* resource_provider() const {
51 return resource_provider_
.get();
54 SoftwareRenderer
* renderer() const { return renderer_
.get(); }
56 // RendererClient implementation.
57 virtual void SetFullRootLayerDamage() OVERRIDE
{}
59 scoped_ptr
<SkBitmap
> DrawAndCopyOutput(RenderPassList
* list
,
60 float device_scale_factor
,
61 gfx::Rect device_viewport_rect
) {
62 scoped_ptr
<SkBitmap
> bitmap_result
;
65 list
->back()->copy_requests
.push_back(
66 CopyOutputRequest::CreateBitmapRequest(
67 base::Bind(&SoftwareRendererTest::SaveBitmapResult
,
68 base::Unretained(&bitmap_result
),
69 loop
.QuitClosure())));
71 renderer()->DrawFrame(list
,
77 return bitmap_result
.Pass();
80 static void SaveBitmapResult(scoped_ptr
<SkBitmap
>* bitmap_result
,
81 const base::Closure
& quit_closure
,
82 scoped_ptr
<CopyOutputResult
> result
) {
83 DCHECK(result
->HasBitmap());
84 *bitmap_result
= result
->TakeBitmap();
89 LayerTreeSettings settings_
;
90 FakeOutputSurfaceClient output_surface_client_
;
91 scoped_ptr
<FakeOutputSurface
> output_surface_
;
92 scoped_ptr
<SharedBitmapManager
> shared_bitmap_manager_
;
93 scoped_ptr
<ResourceProvider
> resource_provider_
;
94 scoped_ptr
<SoftwareRenderer
> renderer_
;
97 TEST_F(SoftwareRendererTest
, SolidColorQuad
) {
98 gfx::Size
outer_size(100, 100);
99 gfx::Size
inner_size(98, 98);
100 gfx::Rect
outer_rect(outer_size
);
101 gfx::Rect
inner_rect(gfx::Point(1, 1), inner_size
);
102 gfx::Rect
visible_rect(gfx::Point(1, 2), gfx::Size(98, 97));
104 InitializeRenderer(make_scoped_ptr(new SoftwareOutputDevice
));
106 RenderPassId root_render_pass_id
= RenderPassId(1, 1);
107 scoped_ptr
<TestRenderPass
> root_render_pass
= TestRenderPass::Create();
108 root_render_pass
->SetNew(
109 root_render_pass_id
, outer_rect
, outer_rect
, gfx::Transform());
110 SharedQuadState
* shared_quad_state
=
111 root_render_pass
->CreateAndAppendSharedQuadState();
112 shared_quad_state
->SetAll(gfx::Transform(),
118 SkXfermode::kSrcOver_Mode
,
120 SolidColorDrawQuad
* inner_quad
=
121 root_render_pass
->CreateAndAppendDrawQuad
<SolidColorDrawQuad
>();
123 shared_quad_state
, inner_rect
, inner_rect
, SK_ColorCYAN
, false);
124 inner_quad
->visible_rect
= visible_rect
;
125 SolidColorDrawQuad
* outer_quad
=
126 root_render_pass
->CreateAndAppendDrawQuad
<SolidColorDrawQuad
>();
128 shared_quad_state
, outer_rect
, outer_rect
, SK_ColorYELLOW
, false);
131 list
.push_back(root_render_pass
.PassAs
<RenderPass
>());
133 float device_scale_factor
= 1.f
;
134 gfx::Rect
device_viewport_rect(outer_size
);
135 scoped_ptr
<SkBitmap
> output
=
136 DrawAndCopyOutput(&list
, device_scale_factor
, device_viewport_rect
);
137 EXPECT_EQ(outer_rect
.width(), output
->info().fWidth
);
138 EXPECT_EQ(outer_rect
.width(), output
->info().fHeight
);
140 EXPECT_EQ(SK_ColorYELLOW
, output
->getColor(0, 0));
141 EXPECT_EQ(SK_ColorYELLOW
,
142 output
->getColor(outer_size
.width() - 1, outer_size
.height() - 1));
143 EXPECT_EQ(SK_ColorYELLOW
, output
->getColor(1, 1));
144 EXPECT_EQ(SK_ColorCYAN
, output
->getColor(1, 2));
145 EXPECT_EQ(SK_ColorCYAN
,
146 output
->getColor(inner_size
.width() - 1, inner_size
.height() - 1));
149 TEST_F(SoftwareRendererTest
, TileQuad
) {
150 gfx::Size
outer_size(100, 100);
151 gfx::Size
inner_size(98, 98);
152 gfx::Rect
outer_rect(outer_size
);
153 gfx::Rect
inner_rect(gfx::Point(1, 1), inner_size
);
154 InitializeRenderer(make_scoped_ptr(new SoftwareOutputDevice
));
156 ResourceProvider::ResourceId resource_yellow
=
157 resource_provider()->CreateResource(
160 ResourceProvider::TextureHintImmutable
,
162 ResourceProvider::ResourceId resource_cyan
=
163 resource_provider()->CreateResource(
166 ResourceProvider::TextureHintImmutable
,
169 SkBitmap yellow_tile
;
170 yellow_tile
.allocN32Pixels(outer_size
.width(), outer_size
.height());
171 yellow_tile
.eraseColor(SK_ColorYELLOW
);
174 cyan_tile
.allocN32Pixels(inner_size
.width(), inner_size
.height());
175 cyan_tile
.eraseColor(SK_ColorCYAN
);
177 resource_provider()->SetPixels(
179 static_cast<uint8_t*>(yellow_tile
.getPixels()),
180 gfx::Rect(outer_size
),
181 gfx::Rect(outer_size
),
183 resource_provider()->SetPixels(resource_cyan
,
184 static_cast<uint8_t*>(cyan_tile
.getPixels()),
185 gfx::Rect(inner_size
),
186 gfx::Rect(inner_size
),
189 gfx::Rect root_rect
= outer_rect
;
191 RenderPassId root_render_pass_id
= RenderPassId(1, 1);
192 scoped_ptr
<TestRenderPass
> root_render_pass
= TestRenderPass::Create();
193 root_render_pass
->SetNew(
194 root_render_pass_id
, root_rect
, root_rect
, gfx::Transform());
195 SharedQuadState
* shared_quad_state
=
196 root_render_pass
->CreateAndAppendSharedQuadState();
197 shared_quad_state
->SetAll(gfx::Transform(),
203 SkXfermode::kSrcOver_Mode
,
205 TileDrawQuad
* inner_quad
=
206 root_render_pass
->CreateAndAppendDrawQuad
<TileDrawQuad
>();
207 inner_quad
->SetNew(shared_quad_state
,
212 gfx::RectF(inner_size
),
215 TileDrawQuad
* outer_quad
=
216 root_render_pass
->CreateAndAppendDrawQuad
<TileDrawQuad
>();
217 outer_quad
->SetNew(shared_quad_state
,
222 gfx::RectF(outer_size
),
227 list
.push_back(root_render_pass
.PassAs
<RenderPass
>());
229 float device_scale_factor
= 1.f
;
230 gfx::Rect
device_viewport_rect(outer_size
);
231 scoped_ptr
<SkBitmap
> output
=
232 DrawAndCopyOutput(&list
, device_scale_factor
, device_viewport_rect
);
233 EXPECT_EQ(outer_rect
.width(), output
->info().fWidth
);
234 EXPECT_EQ(outer_rect
.width(), output
->info().fHeight
);
236 EXPECT_EQ(SK_ColorYELLOW
, output
->getColor(0, 0));
237 EXPECT_EQ(SK_ColorYELLOW
,
238 output
->getColor(outer_size
.width() - 1, outer_size
.height() - 1));
239 EXPECT_EQ(SK_ColorCYAN
, output
->getColor(1, 1));
240 EXPECT_EQ(SK_ColorCYAN
,
241 output
->getColor(inner_size
.width() - 1, inner_size
.height() - 1));
244 TEST_F(SoftwareRendererTest
, TileQuadVisibleRect
) {
245 gfx::Size
tile_size(100, 100);
246 gfx::Rect
tile_rect(tile_size
);
247 gfx::Rect visible_rect
= tile_rect
;
248 visible_rect
.Inset(1, 2, 3, 4);
249 InitializeRenderer(make_scoped_ptr(new SoftwareOutputDevice
));
251 ResourceProvider::ResourceId resource_cyan
=
252 resource_provider()->CreateResource(
255 ResourceProvider::TextureHintImmutable
,
258 SkBitmap cyan_tile
; // The lowest five rows are yellow.
259 cyan_tile
.allocN32Pixels(tile_size
.width(), tile_size
.height());
260 cyan_tile
.eraseColor(SK_ColorCYAN
);
263 0, visible_rect
.bottom() - 1, tile_rect
.width(), tile_rect
.bottom()),
266 resource_provider()->SetPixels(resource_cyan
,
267 static_cast<uint8_t*>(cyan_tile
.getPixels()),
268 gfx::Rect(tile_size
),
269 gfx::Rect(tile_size
),
272 gfx::Rect
root_rect(tile_size
);
274 RenderPassId root_render_pass_id
= RenderPassId(1, 1);
275 scoped_ptr
<TestRenderPass
> root_render_pass
= TestRenderPass::Create();
276 root_render_pass
->SetNew(
277 root_render_pass_id
, root_rect
, root_rect
, gfx::Transform());
278 SharedQuadState
* shared_quad_state
=
279 root_render_pass
->CreateAndAppendSharedQuadState();
280 shared_quad_state
->SetAll(gfx::Transform(),
286 SkXfermode::kSrcOver_Mode
,
289 root_render_pass
->CreateAndAppendDrawQuad
<TileDrawQuad
>();
290 quad
->SetNew(shared_quad_state
,
295 gfx::RectF(tile_size
),
298 quad
->visible_rect
= visible_rect
;
301 list
.push_back(root_render_pass
.PassAs
<RenderPass
>());
303 float device_scale_factor
= 1.f
;
304 gfx::Rect
device_viewport_rect(tile_size
);
305 scoped_ptr
<SkBitmap
> output
=
306 DrawAndCopyOutput(&list
, device_scale_factor
, device_viewport_rect
);
307 EXPECT_EQ(tile_rect
.width(), output
->info().fWidth
);
308 EXPECT_EQ(tile_rect
.width(), output
->info().fHeight
);
310 // Check portion of tile not in visible rect isn't drawn.
311 const unsigned int kTransparent
= SK_ColorTRANSPARENT
;
312 EXPECT_EQ(kTransparent
, output
->getColor(0, 0));
313 EXPECT_EQ(kTransparent
,
314 output
->getColor(tile_rect
.width() - 1, tile_rect
.height() - 1));
315 EXPECT_EQ(kTransparent
,
316 output
->getColor(visible_rect
.x() - 1, visible_rect
.y() - 1));
317 EXPECT_EQ(kTransparent
,
318 output
->getColor(visible_rect
.right(), visible_rect
.bottom()));
319 // Ensure visible part is drawn correctly.
320 EXPECT_EQ(SK_ColorCYAN
, output
->getColor(visible_rect
.x(), visible_rect
.y()));
323 output
->getColor(visible_rect
.right() - 2, visible_rect
.bottom() - 2));
324 // Ensure last visible line is correct.
327 output
->getColor(visible_rect
.right() - 1, visible_rect
.bottom() - 1));
330 TEST_F(SoftwareRendererTest
, ShouldClearRootRenderPass
) {
331 float device_scale_factor
= 1.f
;
332 gfx::Rect
device_viewport_rect(0, 0, 100, 100);
334 settings_
.should_clear_root_render_pass
= false;
335 InitializeRenderer(make_scoped_ptr(new SoftwareOutputDevice
));
339 // Draw a fullscreen green quad in a first frame.
340 RenderPassId
root_clear_pass_id(1, 0);
341 TestRenderPass
* root_clear_pass
= AddRenderPass(
342 &list
, root_clear_pass_id
, device_viewport_rect
, gfx::Transform());
343 AddQuad(root_clear_pass
, device_viewport_rect
, SK_ColorGREEN
);
345 renderer()->DecideRenderPassAllocationsForFrame(list
);
347 scoped_ptr
<SkBitmap
> output
=
348 DrawAndCopyOutput(&list
, device_scale_factor
, device_viewport_rect
);
349 EXPECT_EQ(device_viewport_rect
.width(), output
->info().fWidth
);
350 EXPECT_EQ(device_viewport_rect
.width(), output
->info().fHeight
);
352 EXPECT_EQ(SK_ColorGREEN
, output
->getColor(0, 0));
353 EXPECT_EQ(SK_ColorGREEN
,
354 output
->getColor(device_viewport_rect
.width() - 1,
355 device_viewport_rect
.height() - 1));
359 // Draw a smaller magenta rect without filling the viewport in a separate
361 gfx::Rect
smaller_rect(20, 20, 60, 60);
363 RenderPassId
root_smaller_pass_id(2, 0);
364 TestRenderPass
* root_smaller_pass
= AddRenderPass(
365 &list
, root_smaller_pass_id
, device_viewport_rect
, gfx::Transform());
366 AddQuad(root_smaller_pass
, smaller_rect
, SK_ColorMAGENTA
);
368 renderer()->DecideRenderPassAllocationsForFrame(list
);
370 output
= DrawAndCopyOutput(&list
, device_scale_factor
, device_viewport_rect
);
371 EXPECT_EQ(device_viewport_rect
.width(), output
->info().fWidth
);
372 EXPECT_EQ(device_viewport_rect
.width(), output
->info().fHeight
);
374 // If we didn't clear, the borders should still be green.
375 EXPECT_EQ(SK_ColorGREEN
, output
->getColor(0, 0));
376 EXPECT_EQ(SK_ColorGREEN
,
377 output
->getColor(device_viewport_rect
.width() - 1,
378 device_viewport_rect
.height() - 1));
380 EXPECT_EQ(SK_ColorMAGENTA
,
381 output
->getColor(smaller_rect
.x(), smaller_rect
.y()));
384 output
->getColor(smaller_rect
.right() - 1, smaller_rect
.bottom() - 1));
387 TEST_F(SoftwareRendererTest
, RenderPassVisibleRect
) {
388 float device_scale_factor
= 1.f
;
389 gfx::Rect
device_viewport_rect(0, 0, 100, 100);
390 InitializeRenderer(make_scoped_ptr(new SoftwareOutputDevice
));
394 // Pass drawn as inner quad is magenta.
395 gfx::Rect
smaller_rect(20, 20, 60, 60);
396 RenderPassId
smaller_pass_id(2, 1);
397 TestRenderPass
* smaller_pass
=
398 AddRenderPass(&list
, smaller_pass_id
, smaller_rect
, gfx::Transform());
399 AddQuad(smaller_pass
, smaller_rect
, SK_ColorMAGENTA
);
401 // Root pass is green.
402 RenderPassId
root_clear_pass_id(1, 0);
403 TestRenderPass
* root_clear_pass
= AddRenderPass(
404 &list
, root_clear_pass_id
, device_viewport_rect
, gfx::Transform());
405 AddRenderPassQuad(root_clear_pass
, smaller_pass
);
406 AddQuad(root_clear_pass
, device_viewport_rect
, SK_ColorGREEN
);
408 // Interior pass quad has smaller visible rect.
409 gfx::Rect
interior_visible_rect(30, 30, 40, 40);
410 root_clear_pass
->quad_list
[0]->visible_rect
= interior_visible_rect
;
412 renderer()->DecideRenderPassAllocationsForFrame(list
);
414 scoped_ptr
<SkBitmap
> output
=
415 DrawAndCopyOutput(&list
, device_scale_factor
, device_viewport_rect
);
416 EXPECT_EQ(device_viewport_rect
.width(), output
->info().fWidth
);
417 EXPECT_EQ(device_viewport_rect
.width(), output
->info().fHeight
);
419 EXPECT_EQ(SK_ColorGREEN
, output
->getColor(0, 0));
420 EXPECT_EQ(SK_ColorGREEN
,
421 output
->getColor(device_viewport_rect
.width() - 1,
422 device_viewport_rect
.height() - 1));
424 // Part outside visible rect should remain green.
425 EXPECT_EQ(SK_ColorGREEN
,
426 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));