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 "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"
26
27namespace cc {
28namespace {
29
30class SoftwareRendererTest : public testing::Test, public RendererClient {
31 public:
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_));
37
38    shared_bitmap_manager_.reset(new TestSharedBitmapManager());
39    resource_provider_ = ResourceProvider::Create(output_surface_.get(),
40                                                  shared_bitmap_manager_.get(),
41                                                  NULL,
42                                                  0,
43                                                  false,
44                                                  1,
45                                                  false);
46    renderer_ = SoftwareRenderer::Create(
47        this, &settings_, output_surface_.get(), resource_provider());
48  }
49
50  ResourceProvider* resource_provider() const {
51    return resource_provider_.get();
52  }
53
54  SoftwareRenderer* renderer() const { return renderer_.get(); }
55
56  // RendererClient implementation.
57  virtual void SetFullRootLayerDamage() OVERRIDE {}
58
59  scoped_ptr<SkBitmap> DrawAndCopyOutput(RenderPassList* list,
60                                         float device_scale_factor,
61                                         gfx::Rect device_viewport_rect) {
62    scoped_ptr<SkBitmap> bitmap_result;
63    base::RunLoop loop;
64
65    list->back()->copy_requests.push_back(
66        CopyOutputRequest::CreateBitmapRequest(
67            base::Bind(&SoftwareRendererTest::SaveBitmapResult,
68                       base::Unretained(&bitmap_result),
69                       loop.QuitClosure())));
70
71    renderer()->DrawFrame(list,
72                          device_scale_factor,
73                          device_viewport_rect,
74                          device_viewport_rect,
75                          false);
76    loop.Run();
77    return bitmap_result.Pass();
78  }
79
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();
85    quit_closure.Run();
86  }
87
88 protected:
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_;
95};
96
97TEST_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));
103
104  InitializeRenderer(make_scoped_ptr(new SoftwareOutputDevice));
105
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(),
113                            outer_size,
114                            outer_rect,
115                            outer_rect,
116                            false,
117                            1.0,
118                            SkXfermode::kSrcOver_Mode,
119                            0);
120  SolidColorDrawQuad* inner_quad =
121      root_render_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
122  inner_quad->SetNew(
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>();
127  outer_quad->SetNew(
128      shared_quad_state, outer_rect, outer_rect, SK_ColorYELLOW, false);
129
130  RenderPassList list;
131  list.push_back(root_render_pass.PassAs<RenderPass>());
132
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);
139
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));
147}
148
149TEST_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));
155
156  ResourceProvider::ResourceId resource_yellow =
157      resource_provider()->CreateResource(
158          outer_size,
159          GL_CLAMP_TO_EDGE,
160          ResourceProvider::TextureHintImmutable,
161          RGBA_8888);
162  ResourceProvider::ResourceId resource_cyan =
163      resource_provider()->CreateResource(
164          inner_size,
165          GL_CLAMP_TO_EDGE,
166          ResourceProvider::TextureHintImmutable,
167          RGBA_8888);
168
169  SkBitmap yellow_tile;
170  yellow_tile.allocN32Pixels(outer_size.width(), outer_size.height());
171  yellow_tile.eraseColor(SK_ColorYELLOW);
172
173  SkBitmap cyan_tile;
174  cyan_tile.allocN32Pixels(inner_size.width(), inner_size.height());
175  cyan_tile.eraseColor(SK_ColorCYAN);
176
177  resource_provider()->SetPixels(
178      resource_yellow,
179      static_cast<uint8_t*>(yellow_tile.getPixels()),
180      gfx::Rect(outer_size),
181      gfx::Rect(outer_size),
182      gfx::Vector2d());
183  resource_provider()->SetPixels(resource_cyan,
184                                 static_cast<uint8_t*>(cyan_tile.getPixels()),
185                                 gfx::Rect(inner_size),
186                                 gfx::Rect(inner_size),
187                                 gfx::Vector2d());
188
189  gfx::Rect root_rect = outer_rect;
190
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(),
198                            outer_size,
199                            outer_rect,
200                            outer_rect,
201                            false,
202                            1.0,
203                            SkXfermode::kSrcOver_Mode,
204                            0);
205  TileDrawQuad* inner_quad =
206      root_render_pass->CreateAndAppendDrawQuad<TileDrawQuad>();
207  inner_quad->SetNew(shared_quad_state,
208                     inner_rect,
209                     inner_rect,
210                     inner_rect,
211                     resource_cyan,
212                     gfx::RectF(inner_size),
213                     inner_size,
214                     false);
215  TileDrawQuad* outer_quad =
216      root_render_pass->CreateAndAppendDrawQuad<TileDrawQuad>();
217  outer_quad->SetNew(shared_quad_state,
218                     outer_rect,
219                     outer_rect,
220                     outer_rect,
221                     resource_yellow,
222                     gfx::RectF(outer_size),
223                     outer_size,
224                     false);
225
226  RenderPassList list;
227  list.push_back(root_render_pass.PassAs<RenderPass>());
228
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);
235
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));
242}
243
244TEST_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));
250
251  ResourceProvider::ResourceId resource_cyan =
252      resource_provider()->CreateResource(
253          tile_size,
254          GL_CLAMP_TO_EDGE,
255          ResourceProvider::TextureHintImmutable,
256          RGBA_8888);
257
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);
261  cyan_tile.eraseArea(
262      SkIRect::MakeLTRB(
263          0, visible_rect.bottom() - 1, tile_rect.width(), tile_rect.bottom()),
264      SK_ColorYELLOW);
265
266  resource_provider()->SetPixels(resource_cyan,
267                                 static_cast<uint8_t*>(cyan_tile.getPixels()),
268                                 gfx::Rect(tile_size),
269                                 gfx::Rect(tile_size),
270                                 gfx::Vector2d());
271
272  gfx::Rect root_rect(tile_size);
273
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(),
281                            tile_size,
282                            tile_rect,
283                            tile_rect,
284                            false,
285                            1.0,
286                            SkXfermode::kSrcOver_Mode,
287                            0);
288  TileDrawQuad* quad =
289      root_render_pass->CreateAndAppendDrawQuad<TileDrawQuad>();
290  quad->SetNew(shared_quad_state,
291               tile_rect,
292               tile_rect,
293               tile_rect,
294               resource_cyan,
295               gfx::RectF(tile_size),
296               tile_size,
297               false);
298  quad->visible_rect = visible_rect;
299
300  RenderPassList list;
301  list.push_back(root_render_pass.PassAs<RenderPass>());
302
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);
309
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()));
321  EXPECT_EQ(
322      SK_ColorCYAN,
323      output->getColor(visible_rect.right() - 2, visible_rect.bottom() - 2));
324  // Ensure last visible line is correct.
325  EXPECT_EQ(
326      SK_ColorYELLOW,
327      output->getColor(visible_rect.right() - 1, visible_rect.bottom() - 1));
328}
329
330TEST_F(SoftwareRendererTest, ShouldClearRootRenderPass) {
331  float device_scale_factor = 1.f;
332  gfx::Rect device_viewport_rect(0, 0, 100, 100);
333
334  settings_.should_clear_root_render_pass = false;
335  InitializeRenderer(make_scoped_ptr(new SoftwareOutputDevice));
336
337  RenderPassList list;
338
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);
344
345  renderer()->DecideRenderPassAllocationsForFrame(list);
346
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);
351
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));
356
357  list.clear();
358
359  // Draw a smaller magenta rect without filling the viewport in a separate
360  // frame.
361  gfx::Rect smaller_rect(20, 20, 60, 60);
362
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);
367
368  renderer()->DecideRenderPassAllocationsForFrame(list);
369
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);
373
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));
379
380  EXPECT_EQ(SK_ColorMAGENTA,
381            output->getColor(smaller_rect.x(), smaller_rect.y()));
382  EXPECT_EQ(
383      SK_ColorMAGENTA,
384      output->getColor(smaller_rect.right() - 1, smaller_rect.bottom() - 1));
385}
386
387TEST_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));
391
392  RenderPassList list;
393
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);
400
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);
407
408  // Interior pass quad has smaller visible rect.
409  gfx::Rect interior_visible_rect(30, 30, 40, 40);
410  root_clear_pass->quad_list.front()->visible_rect = interior_visible_rect;
411
412  renderer()->DecideRenderPassAllocationsForFrame(list);
413
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);
418
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));
423
424  // Part outside visible rect should remain green.
425  EXPECT_EQ(SK_ColorGREEN,
426            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