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 SoftwareRendererTest() : should_clear_root_render_pass_(true) {}
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 resource_provider_
= ResourceProvider::Create(output_surface_
.get(), 0);
39 renderer_
= SoftwareRenderer::Create(
40 this, output_surface_
.get(), resource_provider());
43 ResourceProvider
* resource_provider() const {
44 return resource_provider_
.get();
47 SoftwareRenderer
* renderer() const { return renderer_
.get(); }
49 void set_viewport(gfx::Rect viewport
) {
53 void set_should_clear_root_render_pass(bool clear_root_render_pass
) {
54 should_clear_root_render_pass_
= clear_root_render_pass
;
57 // RendererClient implementation.
58 virtual gfx::Rect
DeviceViewport() const OVERRIDE
{
61 virtual float DeviceScaleFactor() const OVERRIDE
{
64 virtual const LayerTreeSettings
& Settings() const OVERRIDE
{
67 virtual void SetFullRootLayerDamage() OVERRIDE
{}
68 virtual bool HasImplThread() const OVERRIDE
{ return false; }
69 virtual bool ShouldClearRootRenderPass() const OVERRIDE
{
70 return should_clear_root_render_pass_
;
72 virtual CompositorFrameMetadata
MakeCompositorFrameMetadata() const OVERRIDE
{
73 return CompositorFrameMetadata();
75 virtual bool AllowPartialSwap() const OVERRIDE
{
78 virtual bool ExternalStencilTestEnabled() const OVERRIDE
{ return false; }
81 FakeOutputSurfaceClient output_surface_client_
;
82 scoped_ptr
<FakeOutputSurface
> output_surface_
;
83 scoped_ptr
<ResourceProvider
> resource_provider_
;
84 scoped_ptr
<SoftwareRenderer
> renderer_
;
86 LayerTreeSettings settings_
;
87 bool should_clear_root_render_pass_
;
90 TEST_F(SoftwareRendererTest
, SolidColorQuad
) {
91 gfx::Size
outer_size(100, 100);
92 gfx::Size
inner_size(98, 98);
93 gfx::Rect
outer_rect(outer_size
);
94 gfx::Rect
inner_rect(gfx::Point(1, 1), inner_size
);
95 gfx::Rect
visible_rect(gfx::Point(1, 2), gfx::Size(98, 97));
96 set_viewport(gfx::Rect(outer_size
));
98 InitializeRenderer(make_scoped_ptr(new SoftwareOutputDevice
));
100 scoped_ptr
<SharedQuadState
> shared_quad_state
= SharedQuadState::Create();
101 shared_quad_state
->SetAll(
102 gfx::Transform(), outer_size
, outer_rect
, outer_rect
, false, 1.0);
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 scoped_ptr
<SolidColorDrawQuad
> outer_quad
= SolidColorDrawQuad::Create();
109 shared_quad_state
.get(), outer_rect
, SK_ColorYELLOW
, false);
110 scoped_ptr
<SolidColorDrawQuad
> inner_quad
= SolidColorDrawQuad::Create();
111 inner_quad
->SetNew(shared_quad_state
.get(), inner_rect
, SK_ColorCYAN
, false);
112 inner_quad
->visible_rect
= visible_rect
;
113 root_render_pass
->AppendQuad(inner_quad
.PassAs
<DrawQuad
>());
114 root_render_pass
->AppendQuad(outer_quad
.PassAs
<DrawQuad
>());
117 list
.push_back(root_render_pass
.PassAs
<RenderPass
>());
118 renderer()->DrawFrame(&list
, NULL
);
121 output
.setConfig(SkBitmap::kARGB_8888_Config
,
122 DeviceViewport().width(),
123 DeviceViewport().height());
124 output
.allocPixels();
125 renderer()->GetFramebufferPixels(output
.getPixels(), outer_rect
);
127 EXPECT_EQ(SK_ColorYELLOW
, output
.getColor(0, 0));
128 EXPECT_EQ(SK_ColorYELLOW
,
129 output
.getColor(outer_size
.width() - 1, outer_size
.height() - 1));
130 EXPECT_EQ(SK_ColorYELLOW
, output
.getColor(1, 1));
131 EXPECT_EQ(SK_ColorCYAN
, output
.getColor(1, 2));
132 EXPECT_EQ(SK_ColorCYAN
,
133 output
.getColor(inner_size
.width() - 1, inner_size
.height() - 1));
136 TEST_F(SoftwareRendererTest
, TileQuad
) {
137 gfx::Size
outer_size(100, 100);
138 gfx::Size
inner_size(98, 98);
139 gfx::Rect
outer_rect(outer_size
);
140 gfx::Rect
inner_rect(gfx::Point(1, 1), inner_size
);
141 set_viewport(gfx::Rect(outer_size
));
142 InitializeRenderer(make_scoped_ptr(new SoftwareOutputDevice
));
144 ResourceProvider::ResourceId resource_yellow
=
145 resource_provider()->CreateResource(
146 outer_size
, GL_RGBA
, ResourceProvider::TextureUsageAny
);
147 ResourceProvider::ResourceId resource_cyan
=
148 resource_provider()->CreateResource(
149 inner_size
, GL_RGBA
, ResourceProvider::TextureUsageAny
);
151 SkBitmap yellow_tile
;
152 yellow_tile
.setConfig(
153 SkBitmap::kARGB_8888_Config
, outer_size
.width(), outer_size
.height());
154 yellow_tile
.allocPixels();
155 yellow_tile
.eraseColor(SK_ColorYELLOW
);
159 SkBitmap::kARGB_8888_Config
, inner_size
.width(), inner_size
.height());
160 cyan_tile
.allocPixels();
161 cyan_tile
.eraseColor(SK_ColorCYAN
);
163 resource_provider()->SetPixels(
165 static_cast<uint8_t*>(yellow_tile
.getPixels()),
166 gfx::Rect(outer_size
),
167 gfx::Rect(outer_size
),
169 resource_provider()->SetPixels(resource_cyan
,
170 static_cast<uint8_t*>(cyan_tile
.getPixels()),
171 gfx::Rect(inner_size
),
172 gfx::Rect(inner_size
),
175 gfx::Rect root_rect
= DeviceViewport();
177 scoped_ptr
<SharedQuadState
> shared_quad_state
= SharedQuadState::Create();
178 shared_quad_state
->SetAll(
179 gfx::Transform(), outer_size
, outer_rect
, outer_rect
, false, 1.0);
180 RenderPass::Id root_render_pass_id
= RenderPass::Id(1, 1);
181 scoped_ptr
<TestRenderPass
> root_render_pass
= TestRenderPass::Create();
182 root_render_pass
->SetNew(
183 root_render_pass_id
, root_rect
, root_rect
, gfx::Transform());
184 scoped_ptr
<TileDrawQuad
> outer_quad
= TileDrawQuad::Create();
185 outer_quad
->SetNew(shared_quad_state
.get(),
189 gfx::RectF(outer_size
),
192 scoped_ptr
<TileDrawQuad
> inner_quad
= TileDrawQuad::Create();
193 inner_quad
->SetNew(shared_quad_state
.get(),
197 gfx::RectF(inner_size
),
200 root_render_pass
->AppendQuad(inner_quad
.PassAs
<DrawQuad
>());
201 root_render_pass
->AppendQuad(outer_quad
.PassAs
<DrawQuad
>());
204 list
.push_back(root_render_pass
.PassAs
<RenderPass
>());
205 renderer()->DrawFrame(&list
, NULL
);
208 output
.setConfig(SkBitmap::kARGB_8888_Config
,
209 DeviceViewport().width(),
210 DeviceViewport().height());
211 output
.allocPixels();
212 renderer()->GetFramebufferPixels(output
.getPixels(), outer_rect
);
214 EXPECT_EQ(SK_ColorYELLOW
, output
.getColor(0, 0));
215 EXPECT_EQ(SK_ColorYELLOW
,
216 output
.getColor(outer_size
.width() - 1, outer_size
.height() - 1));
217 EXPECT_EQ(SK_ColorCYAN
, output
.getColor(1, 1));
218 EXPECT_EQ(SK_ColorCYAN
,
219 output
.getColor(inner_size
.width() - 1, inner_size
.height() - 1));
222 TEST_F(SoftwareRendererTest
, TileQuadVisibleRect
) {
223 gfx::Size
tile_size(100, 100);
224 gfx::Rect
tile_rect(tile_size
);
225 gfx::Rect visible_rect
= tile_rect
;
226 visible_rect
.Inset(1, 2, 3, 4);
227 set_viewport(gfx::Rect(tile_size
));
228 InitializeRenderer(make_scoped_ptr(new SoftwareOutputDevice
));
230 ResourceProvider::ResourceId resource_cyan
=
231 resource_provider()->CreateResource(
232 tile_size
, GL_RGBA
, ResourceProvider::TextureUsageAny
);
234 SkBitmap cyan_tile
; // The lowest five rows are yellow.
236 SkBitmap::kARGB_8888_Config
, tile_size
.width(), tile_size
.height());
237 cyan_tile
.allocPixels();
238 cyan_tile
.eraseColor(SK_ColorCYAN
);
241 0, visible_rect
.bottom() - 1, tile_rect
.width(), tile_rect
.bottom()),
244 resource_provider()->SetPixels(resource_cyan
,
245 static_cast<uint8_t*>(cyan_tile
.getPixels()),
246 gfx::Rect(tile_size
),
247 gfx::Rect(tile_size
),
250 gfx::Rect root_rect
= DeviceViewport();
252 scoped_ptr
<SharedQuadState
> shared_quad_state
= SharedQuadState::Create();
253 shared_quad_state
->SetAll(
254 gfx::Transform(), tile_size
, tile_rect
, tile_rect
, false, 1.0);
255 RenderPass::Id root_render_pass_id
= RenderPass::Id(1, 1);
256 scoped_ptr
<TestRenderPass
> root_render_pass
= TestRenderPass::Create();
257 root_render_pass
->SetNew(
258 root_render_pass_id
, root_rect
, root_rect
, gfx::Transform());
259 scoped_ptr
<TileDrawQuad
> quad
= TileDrawQuad::Create();
260 quad
->SetNew(shared_quad_state
.get(),
264 gfx::RectF(tile_size
),
267 quad
->visible_rect
= visible_rect
;
268 root_render_pass
->AppendQuad(quad
.PassAs
<DrawQuad
>());
271 list
.push_back(root_render_pass
.PassAs
<RenderPass
>());
272 renderer()->DrawFrame(&list
, NULL
);
275 output
.setConfig(SkBitmap::kARGB_8888_Config
,
276 DeviceViewport().width(),
277 DeviceViewport().height());
278 output
.allocPixels();
279 renderer()->GetFramebufferPixels(output
.getPixels(), tile_rect
);
281 // Check portion of tile not in visible rect isn't drawn.
282 const unsigned int kTransparent
= SK_ColorTRANSPARENT
;
283 EXPECT_EQ(kTransparent
, output
.getColor(0, 0));
284 EXPECT_EQ(kTransparent
,
285 output
.getColor(tile_rect
.width() - 1, tile_rect
.height() - 1));
286 EXPECT_EQ(kTransparent
,
287 output
.getColor(visible_rect
.x() - 1, visible_rect
.y() - 1));
288 EXPECT_EQ(kTransparent
,
289 output
.getColor(visible_rect
.right(), visible_rect
.bottom()));
290 // Ensure visible part is drawn correctly.
291 EXPECT_EQ(SK_ColorCYAN
, output
.getColor(visible_rect
.x(), visible_rect
.y()));
294 output
.getColor(visible_rect
.right() - 2, visible_rect
.bottom() - 2));
295 // Ensure last visible line is correct.
298 output
.getColor(visible_rect
.right() - 1, visible_rect
.bottom() - 1));
301 TEST_F(SoftwareRendererTest
, ShouldClearRootRenderPass
) {
302 gfx::Rect
viewport_rect(0, 0, 100, 100);
303 set_viewport(viewport_rect
);
304 set_should_clear_root_render_pass(false);
305 InitializeRenderer(make_scoped_ptr(new SoftwareOutputDevice
));
310 output
.setConfig(SkBitmap::kARGB_8888_Config
,
311 viewport_rect
.width(),
312 viewport_rect
.height());
313 output
.allocPixels();
315 // Draw a fullscreen green quad in a first frame.
316 RenderPass::Id
root_clear_pass_id(1, 0);
317 TestRenderPass
* root_clear_pass
= AddRenderPass(
318 &list
, root_clear_pass_id
, viewport_rect
, gfx::Transform());
319 AddQuad(root_clear_pass
, viewport_rect
, SK_ColorGREEN
);
321 renderer()->DecideRenderPassAllocationsForFrame(list
);
322 renderer()->DrawFrame(&list
, NULL
);
323 renderer()->GetFramebufferPixels(output
.getPixels(), viewport_rect
);
325 EXPECT_EQ(SK_ColorGREEN
, output
.getColor(0, 0));
326 EXPECT_EQ(SK_ColorGREEN
,
327 output
.getColor(viewport_rect
.width() - 1, viewport_rect
.height() - 1));
331 // Draw a smaller magenta rect without filling the viewport in a separate
333 gfx::Rect
smaller_rect(20, 20, 60, 60);
335 RenderPass::Id
root_smaller_pass_id(2, 0);
336 TestRenderPass
* root_smaller_pass
= AddRenderPass(
337 &list
, root_smaller_pass_id
, viewport_rect
, gfx::Transform());
338 AddQuad(root_smaller_pass
, smaller_rect
, SK_ColorMAGENTA
);
340 renderer()->DecideRenderPassAllocationsForFrame(list
);
341 renderer()->DrawFrame(&list
, NULL
);
342 renderer()->GetFramebufferPixels(output
.getPixels(), viewport_rect
);
344 // If we didn't clear, the borders should still be green.
345 EXPECT_EQ(SK_ColorGREEN
, output
.getColor(0, 0));
346 EXPECT_EQ(SK_ColorGREEN
,
347 output
.getColor(viewport_rect
.width() - 1, viewport_rect
.height() - 1));
349 EXPECT_EQ(SK_ColorMAGENTA
,
350 output
.getColor(smaller_rect
.x(), smaller_rect
.y()));
351 EXPECT_EQ(SK_ColorMAGENTA
,
352 output
.getColor(smaller_rect
.right() - 1, smaller_rect
.bottom() - 1));
355 TEST_F(SoftwareRendererTest
, RenderPassVisibleRect
) {
356 gfx::Rect
viewport_rect(0, 0, 100, 100);
357 set_viewport(viewport_rect
);
358 InitializeRenderer(make_scoped_ptr(new SoftwareOutputDevice
));
363 output
.setConfig(SkBitmap::kARGB_8888_Config
,
364 viewport_rect
.width(),
365 viewport_rect
.height());
366 output
.allocPixels();
368 // Pass drawn as inner quad is magenta.
369 gfx::Rect
smaller_rect(20, 20, 60, 60);
370 RenderPass::Id
smaller_pass_id(2, 1);
371 TestRenderPass
* smaller_pass
=
372 AddRenderPass(&list
, smaller_pass_id
, smaller_rect
, gfx::Transform());
373 AddQuad(smaller_pass
, smaller_rect
, SK_ColorMAGENTA
);
375 // Root pass is green.
376 RenderPass::Id
root_clear_pass_id(1, 0);
377 TestRenderPass
* root_clear_pass
=
378 AddRenderPass(&list
, root_clear_pass_id
, viewport_rect
, gfx::Transform());
379 AddRenderPassQuad(root_clear_pass
, smaller_pass
);
380 AddQuad(root_clear_pass
, viewport_rect
, SK_ColorGREEN
);
382 // Interior pass quad has smaller visible rect.
383 gfx::Rect
interior_visible_rect(30, 30, 40, 40);
384 root_clear_pass
->quad_list
[0]->visible_rect
= interior_visible_rect
;
386 renderer()->DecideRenderPassAllocationsForFrame(list
);
387 renderer()->DrawFrame(&list
, NULL
);
388 renderer()->GetFramebufferPixels(output
.getPixels(), viewport_rect
);
390 EXPECT_EQ(SK_ColorGREEN
, output
.getColor(0, 0));
393 output
.getColor(viewport_rect
.width() - 1, viewport_rect
.height() - 1));
395 // Part outside visible rect should remain green.
396 EXPECT_EQ(SK_ColorGREEN
, output
.getColor(smaller_rect
.x(), smaller_rect
.y()));
399 output
.getColor(smaller_rect
.right() - 1, smaller_rect
.bottom() - 1));
403 output
.getColor(interior_visible_rect
.x(), interior_visible_rect
.y()));
404 EXPECT_EQ(SK_ColorMAGENTA
,
405 output
.getColor(interior_visible_rect
.right() - 1,
406 interior_visible_rect
.bottom() - 1));