1// Copyright 2013 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/test/pixel_test.h"
6
7#include "base/command_line.h"
8#include "base/message_loop/message_loop_proxy.h"
9#include "base/path_service.h"
10#include "base/run_loop.h"
11#include "cc/base/switches.h"
12#include "cc/output/compositor_frame_metadata.h"
13#include "cc/output/copy_output_request.h"
14#include "cc/output/copy_output_result.h"
15#include "cc/output/gl_renderer.h"
16#include "cc/output/output_surface_client.h"
17#include "cc/output/software_renderer.h"
18#include "cc/resources/raster_worker_pool.h"
19#include "cc/resources/resource_provider.h"
20#include "cc/resources/texture_mailbox_deleter.h"
21#include "cc/test/fake_output_surface_client.h"
22#include "cc/test/paths.h"
23#include "cc/test/pixel_test_output_surface.h"
24#include "cc/test/pixel_test_software_output_device.h"
25#include "cc/test/pixel_test_utils.h"
26#include "cc/test/test_in_process_context_provider.h"
27#include "cc/test/test_shared_bitmap_manager.h"
28#include "testing/gtest/include/gtest/gtest.h"
29
30namespace cc {
31
32PixelTest::PixelTest()
33    : device_viewport_size_(gfx::Size(200, 200)),
34      disable_picture_quad_image_filtering_(false),
35      output_surface_client_(new FakeOutputSurfaceClient) {}
36
37PixelTest::~PixelTest() {}
38
39bool PixelTest::RunPixelTest(RenderPassList* pass_list,
40                             const base::FilePath& ref_file,
41                             const PixelComparator& comparator) {
42  return RunPixelTestWithReadbackTarget(pass_list,
43                                        pass_list->back(),
44                                        ref_file,
45                                        comparator);
46}
47
48bool PixelTest::RunPixelTestWithReadbackTarget(
49    RenderPassList* pass_list,
50    RenderPass* target,
51    const base::FilePath& ref_file,
52    const PixelComparator& comparator) {
53  base::RunLoop run_loop;
54
55  target->copy_requests.push_back(CopyOutputRequest::CreateBitmapRequest(
56      base::Bind(&PixelTest::ReadbackResult,
57                 base::Unretained(this),
58                 run_loop.QuitClosure())));
59
60  float device_scale_factor = 1.f;
61  gfx::Rect device_viewport_rect =
62      gfx::Rect(device_viewport_size_) + external_device_viewport_offset_;
63  gfx::Rect device_clip_rect = external_device_clip_rect_.IsEmpty()
64                                   ? device_viewport_rect
65                                   : external_device_clip_rect_;
66  renderer_->DecideRenderPassAllocationsForFrame(*pass_list);
67  renderer_->DrawFrame(pass_list,
68                       device_scale_factor,
69                       device_viewport_rect,
70                       device_clip_rect,
71                       disable_picture_quad_image_filtering_);
72
73  // Wait for the readback to complete.
74  resource_provider_->Finish();
75  run_loop.Run();
76
77  return PixelsMatchReference(ref_file, comparator);
78}
79
80void PixelTest::ReadbackResult(base::Closure quit_run_loop,
81                               scoped_ptr<CopyOutputResult> result) {
82  ASSERT_TRUE(result->HasBitmap());
83  result_bitmap_ = result->TakeBitmap().Pass();
84  quit_run_loop.Run();
85}
86
87bool PixelTest::PixelsMatchReference(const base::FilePath& ref_file,
88                                     const PixelComparator& comparator) {
89  base::FilePath test_data_dir;
90  if (!PathService::Get(CCPaths::DIR_TEST_DATA, &test_data_dir))
91    return false;
92
93  // If this is false, we didn't set up a readback on a render pass.
94  if (!result_bitmap_)
95    return false;
96
97  CommandLine* cmd = CommandLine::ForCurrentProcess();
98  if (cmd->HasSwitch(switches::kCCRebaselinePixeltests))
99    return WritePNGFile(*result_bitmap_, test_data_dir.Append(ref_file), true);
100
101  return MatchesPNGFile(
102      *result_bitmap_, test_data_dir.Append(ref_file), comparator);
103}
104
105void PixelTest::SetUpGLRenderer(bool use_skia_gpu_backend) {
106  enable_pixel_output_.reset(new gfx::DisableNullDrawGLBindings);
107
108  output_surface_.reset(
109      new PixelTestOutputSurface(new TestInProcessContextProvider));
110  output_surface_->BindToClient(output_surface_client_.get());
111
112  shared_bitmap_manager_.reset(new TestSharedBitmapManager());
113  resource_provider_ = ResourceProvider::Create(
114      output_surface_.get(), shared_bitmap_manager_.get(), 0, false, 1, false);
115
116  texture_mailbox_deleter_ = make_scoped_ptr(
117      new TextureMailboxDeleter(base::MessageLoopProxy::current()));
118
119  renderer_ = GLRenderer::Create(this,
120                                 &settings_,
121                                 output_surface_.get(),
122                                 resource_provider_.get(),
123                                 texture_mailbox_deleter_.get(),
124                                 0).PassAs<DirectRenderer>();
125}
126
127void PixelTest::ForceExpandedViewport(const gfx::Size& surface_expansion) {
128  static_cast<PixelTestOutputSurface*>(output_surface_.get())
129      ->set_surface_expansion_size(surface_expansion);
130  SoftwareOutputDevice* device = output_surface_->software_device();
131  if (device) {
132    static_cast<PixelTestSoftwareOutputDevice*>(device)
133        ->set_surface_expansion_size(surface_expansion);
134  }
135}
136
137void PixelTest::ForceViewportOffset(const gfx::Vector2d& viewport_offset) {
138  external_device_viewport_offset_ = viewport_offset;
139}
140
141void PixelTest::ForceDeviceClip(const gfx::Rect& clip) {
142  external_device_clip_rect_ = clip;
143}
144
145void PixelTest::EnableExternalStencilTest() {
146  static_cast<PixelTestOutputSurface*>(output_surface_.get())
147      ->set_has_external_stencil_test(true);
148}
149
150void PixelTest::RunOnDemandRasterTask(Task* on_demand_raster_task) {
151  TaskGraphRunner task_graph_runner;
152  NamespaceToken on_demand_task_namespace =
153      task_graph_runner.GetNamespaceToken();
154
155  // Construct a task graph that contains this single raster task.
156  TaskGraph graph;
157  graph.nodes.push_back(
158      TaskGraph::Node(on_demand_raster_task,
159                      RasterWorkerPool::kOnDemandRasterTaskPriority,
160                      0u));
161
162  // Schedule task and wait for task graph runner to finish running it.
163  task_graph_runner.ScheduleTasks(on_demand_task_namespace, &graph);
164  task_graph_runner.RunUntilIdle();
165
166  // Collect task now that it has finished running.
167  Task::Vector completed_tasks;
168  task_graph_runner.CollectCompletedTasks(on_demand_task_namespace,
169                                          &completed_tasks);
170  DCHECK_EQ(1u, completed_tasks.size());
171  DCHECK_EQ(completed_tasks[0], on_demand_raster_task);
172}
173
174void PixelTest::SetUpSoftwareRenderer() {
175  scoped_ptr<SoftwareOutputDevice> device(new PixelTestSoftwareOutputDevice());
176  output_surface_.reset(new PixelTestOutputSurface(device.Pass()));
177  output_surface_->BindToClient(output_surface_client_.get());
178  shared_bitmap_manager_.reset(new TestSharedBitmapManager());
179  resource_provider_ = ResourceProvider::Create(
180      output_surface_.get(), shared_bitmap_manager_.get(), 0, false, 1, false);
181  renderer_ =
182      SoftwareRenderer::Create(
183          this, &settings_, output_surface_.get(), resource_provider_.get())
184          .PassAs<DirectRenderer>();
185}
186
187}  // namespace cc
188