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.
4
5#include "cc/output/software_renderer.h"
6
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"
24
25namespace cc {
26namespace {
27
28class SoftwareRendererTest : public testing::Test, public RendererClient {
29 public:
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_));
35
36    resource_provider_ =
37        ResourceProvider::Create(output_surface_.get(), NULL, 0, false, 1);
38    renderer_ = SoftwareRenderer::Create(
39        this, &settings_, output_surface_.get(), resource_provider());
40  }
41
42  ResourceProvider* resource_provider() const {
43    return resource_provider_.get();
44  }
45
46  SoftwareRenderer* renderer() const { return renderer_.get(); }
47
48  // RendererClient implementation.
49  virtual void SetFullRootLayerDamage() OVERRIDE {}
50
51 protected:
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_;
57};
58
59TEST_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));
65
66  InitializeRenderer(make_scoped_ptr(new SoftwareOutputDevice));
67
68  scoped_ptr<SharedQuadState> shared_quad_state = SharedQuadState::Create();
69  shared_quad_state->SetAll(gfx::Transform(),
70                            outer_size,
71                            outer_rect,
72                            outer_rect,
73                            false,
74                            1.0,
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();
81  outer_quad->SetNew(
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>());
88
89  RenderPassList list;
90  list.push_back(root_render_pass.PassAs<RenderPass>());
91
92  float device_scale_factor = 1.f;
93  gfx::Rect device_viewport_rect(outer_size);
94  renderer()->DrawFrame(&list,
95                        NULL,
96                        device_scale_factor,
97                        device_viewport_rect,
98                        device_viewport_rect,
99                        true,
100                        false);
101
102  SkBitmap output;
103  output.setConfig(
104      SkBitmap::kARGB_8888_Config, outer_rect.width(), outer_rect.height());
105  output.allocPixels();
106  renderer()->GetFramebufferPixels(output.getPixels(), outer_rect);
107
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));
115}
116
117TEST_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));
123
124  ResourceProvider::ResourceId resource_yellow =
125      resource_provider()->CreateResource(outer_size,
126                                          GL_CLAMP_TO_EDGE,
127                                          ResourceProvider::TextureUsageAny,
128                                          RGBA_8888);
129  ResourceProvider::ResourceId resource_cyan =
130      resource_provider()->CreateResource(inner_size,
131                                          GL_CLAMP_TO_EDGE,
132                                          ResourceProvider::TextureUsageAny,
133                                          RGBA_8888);
134
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);
140
141  SkBitmap cyan_tile;
142  cyan_tile.setConfig(
143      SkBitmap::kARGB_8888_Config, inner_size.width(), inner_size.height());
144  cyan_tile.allocPixels();
145  cyan_tile.eraseColor(SK_ColorCYAN);
146
147  resource_provider()->SetPixels(
148      resource_yellow,
149      static_cast<uint8_t*>(yellow_tile.getPixels()),
150      gfx::Rect(outer_size),
151      gfx::Rect(outer_size),
152      gfx::Vector2d());
153  resource_provider()->SetPixels(resource_cyan,
154                                 static_cast<uint8_t*>(cyan_tile.getPixels()),
155                                 gfx::Rect(inner_size),
156                                 gfx::Rect(inner_size),
157                                 gfx::Vector2d());
158
159  gfx::Rect root_rect = outer_rect;
160
161  scoped_ptr<SharedQuadState> shared_quad_state = SharedQuadState::Create();
162  shared_quad_state->SetAll(gfx::Transform(),
163                            outer_size,
164                            outer_rect,
165                            outer_rect,
166                            false,
167                            1.0,
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(),
175                     outer_rect,
176                     outer_rect,
177                     resource_yellow,
178                     gfx::RectF(outer_size),
179                     outer_size,
180                     false);
181  scoped_ptr<TileDrawQuad> inner_quad = TileDrawQuad::Create();
182  inner_quad->SetNew(shared_quad_state.get(),
183                     inner_rect,
184                     inner_rect,
185                     resource_cyan,
186                     gfx::RectF(inner_size),
187                     inner_size,
188                     false);
189  root_render_pass->AppendQuad(inner_quad.PassAs<DrawQuad>());
190  root_render_pass->AppendQuad(outer_quad.PassAs<DrawQuad>());
191
192  RenderPassList list;
193  list.push_back(root_render_pass.PassAs<RenderPass>());
194
195  float device_scale_factor = 1.f;
196  gfx::Rect device_viewport_rect(outer_size);
197  renderer()->DrawFrame(&list,
198                        NULL,
199                        device_scale_factor,
200                        device_viewport_rect,
201                        device_viewport_rect,
202                        true,
203                        false);
204
205  SkBitmap output;
206  output.setConfig(
207      SkBitmap::kARGB_8888_Config, outer_size.width(), outer_size.height());
208  output.allocPixels();
209  renderer()->GetFramebufferPixels(output.getPixels(), outer_rect);
210
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));
217}
218
219TEST_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));
225
226  ResourceProvider::ResourceId resource_cyan =
227      resource_provider()->CreateResource(tile_size,
228                                          GL_CLAMP_TO_EDGE,
229                                          ResourceProvider::TextureUsageAny,
230                                          RGBA_8888);
231
232  SkBitmap cyan_tile;  // The lowest five rows are yellow.
233  cyan_tile.setConfig(
234      SkBitmap::kARGB_8888_Config, tile_size.width(), tile_size.height());
235  cyan_tile.allocPixels();
236  cyan_tile.eraseColor(SK_ColorCYAN);
237  cyan_tile.eraseArea(
238      SkIRect::MakeLTRB(
239          0, visible_rect.bottom() - 1, tile_rect.width(), tile_rect.bottom()),
240      SK_ColorYELLOW);
241
242  resource_provider()->SetPixels(resource_cyan,
243                                 static_cast<uint8_t*>(cyan_tile.getPixels()),
244                                 gfx::Rect(tile_size),
245                                 gfx::Rect(tile_size),
246                                 gfx::Vector2d());
247
248  gfx::Rect root_rect(tile_size);
249
250  scoped_ptr<SharedQuadState> shared_quad_state = SharedQuadState::Create();
251  shared_quad_state->SetAll(gfx::Transform(),
252                            tile_size,
253                            tile_rect,
254                            tile_rect,
255                            false,
256                            1.0,
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(),
264               tile_rect,
265               tile_rect,
266               resource_cyan,
267               gfx::RectF(tile_size),
268               tile_size,
269               false);
270  quad->visible_rect = visible_rect;
271  root_render_pass->AppendQuad(quad.PassAs<DrawQuad>());
272
273  RenderPassList list;
274  list.push_back(root_render_pass.PassAs<RenderPass>());
275
276  float device_scale_factor = 1.f;
277  gfx::Rect device_viewport_rect(tile_size);
278  renderer()->DrawFrame(&list,
279                        NULL,
280                        device_scale_factor,
281                        device_viewport_rect,
282                        device_viewport_rect,
283                        true,
284                        false);
285
286  SkBitmap output;
287  output.setConfig(
288      SkBitmap::kARGB_8888_Config, tile_size.width(), tile_size.height());
289  output.allocPixels();
290  renderer()->GetFramebufferPixels(output.getPixels(), tile_rect);
291
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()));
303  EXPECT_EQ(
304      SK_ColorCYAN,
305      output.getColor(visible_rect.right() - 2, visible_rect.bottom() - 2));
306  // Ensure last visible line is correct.
307  EXPECT_EQ(
308      SK_ColorYELLOW,
309      output.getColor(visible_rect.right() - 1, visible_rect.bottom() - 1));
310}
311
312TEST_F(SoftwareRendererTest, ShouldClearRootRenderPass) {
313  float device_scale_factor = 1.f;
314  gfx::Rect viewport_rect(0, 0, 100, 100);
315
316  settings_.should_clear_root_render_pass = false;
317  InitializeRenderer(make_scoped_ptr(new SoftwareOutputDevice));
318
319  RenderPassList list;
320
321  SkBitmap output;
322  output.setConfig(SkBitmap::kARGB_8888_Config,
323                   viewport_rect.width(),
324                   viewport_rect.height());
325  output.allocPixels();
326
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);
332
333  renderer()->DecideRenderPassAllocationsForFrame(list);
334  renderer()->DrawFrame(&list,
335                        NULL,
336                        device_scale_factor,
337                        viewport_rect,
338                        viewport_rect,
339                        true,
340                        false);
341  renderer()->GetFramebufferPixels(output.getPixels(), viewport_rect);
342
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));
346
347  list.clear();
348
349  // Draw a smaller magenta rect without filling the viewport in a separate
350  // frame.
351  gfx::Rect smaller_rect(20, 20, 60, 60);
352
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);
357
358  renderer()->DecideRenderPassAllocationsForFrame(list);
359  renderer()->DrawFrame(&list,
360                        NULL,
361                        device_scale_factor,
362                        viewport_rect,
363                        viewport_rect,
364                        true,
365                        false);
366  renderer()->GetFramebufferPixels(output.getPixels(), viewport_rect);
367
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));
372
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));
377}
378
379TEST_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));
383
384  RenderPassList list;
385
386  SkBitmap output;
387  output.setConfig(SkBitmap::kARGB_8888_Config,
388                   viewport_rect.width(),
389                   viewport_rect.height());
390  output.allocPixels();
391
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);
398
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);
405
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;
409
410  renderer()->DecideRenderPassAllocationsForFrame(list);
411  renderer()->DrawFrame(&list,
412                        NULL,
413                        device_scale_factor,
414                        viewport_rect,
415                        viewport_rect,
416                        true,
417                        false);
418  renderer()->GetFramebufferPixels(output.getPixels(), viewport_rect);
419
420  EXPECT_EQ(SK_ColorGREEN, output.getColor(0, 0));
421  EXPECT_EQ(
422      SK_ColorGREEN,
423      output.getColor(viewport_rect.width() - 1, viewport_rect.height() - 1));
424
425  // Part outside visible rect should remain green.
426  EXPECT_EQ(SK_ColorGREEN, output.getColor(smaller_rect.x(), smaller_rect.y()));
427  EXPECT_EQ(
428      SK_ColorGREEN,
429      output.getColor(smaller_rect.right() - 1, smaller_rect.bottom() - 1));
430
431  EXPECT_EQ(
432      SK_ColorMAGENTA,
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));
437}
438
439}  // namespace
440}  // namespace cc
441