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/layer_tree_pixel_test.h"
6 
7 #include <stddef.h>
8 #include <stdint.h>
9 
10 #include "base/bind.h"
11 #include "base/command_line.h"
12 #include "base/path_service.h"
13 #include "base/test/test_switches.h"
14 #include "cc/layers/solid_color_layer.h"
15 #include "cc/layers/texture_layer.h"
16 #include "cc/test/pixel_comparator.h"
17 #include "cc/test/pixel_test_output_surface.h"
18 #include "cc/test/pixel_test_utils.h"
19 #include "cc/test/test_layer_tree_frame_sink.h"
20 #include "cc/trees/effect_node.h"
21 #include "cc/trees/layer_tree_impl.h"
22 #include "components/viz/common/display/renderer_settings.h"
23 #include "components/viz/common/features.h"
24 #include "components/viz/common/frame_sinks/copy_output_request.h"
25 #include "components/viz/common/frame_sinks/copy_output_result.h"
26 #include "components/viz/service/display/software_output_device.h"
27 #include "components/viz/service/display_embedder/skia_output_surface_dependency_impl.h"
28 #include "components/viz/service/display_embedder/skia_output_surface_impl.h"
29 #include "components/viz/test/paths.h"
30 #include "components/viz/test/test_gpu_service_holder.h"
31 #include "components/viz/test/test_in_process_context_provider.h"
32 #include "gpu/command_buffer/client/gles2_implementation.h"
33 #include "gpu/ipc/gl_in_process_context.h"
34 
35 using gpu::gles2::GLES2Interface;
36 
37 namespace cc {
38 
39 namespace {
40 
GetDefaultRasterType(viz::RendererType renderer_type)41 TestRasterType GetDefaultRasterType(viz::RendererType renderer_type) {
42   switch (renderer_type) {
43     case viz::RendererType::kSoftware:
44       return TestRasterType::kBitmap;
45     case viz::RendererType::kSkiaVk:
46     case viz::RendererType::kSkiaDawn:
47       return TestRasterType::kOop;
48     default:
49       return TestRasterType::kOneCopy;
50   }
51 }
52 
53 }  // namespace
54 
LayerTreePixelTest(viz::RendererType renderer_type)55 LayerTreePixelTest::LayerTreePixelTest(viz::RendererType renderer_type)
56     : LayerTreeTest(renderer_type),
57       raster_type_(GetDefaultRasterType(renderer_type)),
58       pixel_comparator_(new ExactPixelComparator(true)),
59       pending_texture_mailbox_callbacks_(0) {}
60 
61 LayerTreePixelTest::~LayerTreePixelTest() = default;
62 
63 std::unique_ptr<TestLayerTreeFrameSink>
CreateLayerTreeFrameSink(const viz::RendererSettings & renderer_settings,double refresh_rate,scoped_refptr<viz::ContextProvider>,scoped_refptr<viz::RasterContextProvider>)64 LayerTreePixelTest::CreateLayerTreeFrameSink(
65     const viz::RendererSettings& renderer_settings,
66     double refresh_rate,
67     scoped_refptr<viz::ContextProvider>,
68     scoped_refptr<viz::RasterContextProvider>) {
69   scoped_refptr<viz::TestInProcessContextProvider> compositor_context_provider;
70   scoped_refptr<viz::TestInProcessContextProvider> worker_context_provider;
71   if (!use_software_renderer()) {
72     compositor_context_provider =
73         base::MakeRefCounted<viz::TestInProcessContextProvider>(
74             /*enable_gpu_rasterization=*/use_accelerated_raster(),
75             /*enable_oop_rasterization=*/false, /*support_locking=*/false);
76     worker_context_provider =
77         base::MakeRefCounted<viz::TestInProcessContextProvider>(
78             /*enable_gpu_rasterization=*/use_accelerated_raster(),
79             /*enable_oop_rasterization=*/raster_type() == TestRasterType::kOop,
80             /*support_locking=*/true);
81     // Bind worker context to main thread like it is in production. This is
82     // needed to fully initialize the context. Compositor context is bound to
83     // the impl thread in LayerTreeFrameSink::BindToCurrentThread().
84     gpu::ContextResult result = worker_context_provider->BindToCurrentThread();
85     DCHECK_EQ(result, gpu::ContextResult::kSuccess);
86   }
87   static constexpr bool disable_display_vsync = false;
88   bool synchronous_composite =
89       !HasImplThread() &&
90       !layer_tree_host()->GetSettings().single_thread_proxy_scheduler;
91   viz::RendererSettings test_settings = renderer_settings;
92   // Keep texture sizes exactly matching the bounds of the RenderPass to avoid
93   // floating point badness in texcoords.
94   test_settings.dont_round_texture_sizes_for_pixel_tests = true;
95   auto delegating_output_surface = std::make_unique<TestLayerTreeFrameSink>(
96       compositor_context_provider, worker_context_provider,
97       gpu_memory_buffer_manager(), test_settings, &debug_settings_,
98       ImplThreadTaskRunner(), synchronous_composite, disable_display_vsync,
99       refresh_rate);
100   delegating_output_surface->SetEnlargePassTextureAmount(
101       enlarge_texture_amount_);
102   return delegating_output_surface;
103 }
104 
DrawLayersOnThread(LayerTreeHostImpl * host_impl)105 void LayerTreePixelTest::DrawLayersOnThread(LayerTreeHostImpl* host_impl) {
106   // Verify that we're using Gpu rasterization or not as requested.
107   if (!use_software_renderer()) {
108     viz::ContextProvider* context_provider =
109         host_impl->layer_tree_frame_sink()->context_provider();
110     viz::RasterContextProvider* worker_context_provider =
111         host_impl->layer_tree_frame_sink()->worker_context_provider();
112     EXPECT_EQ(use_accelerated_raster(),
113               context_provider->ContextCapabilities().gpu_rasterization);
114     EXPECT_EQ(use_accelerated_raster(),
115               worker_context_provider->ContextCapabilities().gpu_rasterization);
116     EXPECT_EQ(
117         raster_type() == TestRasterType::kOop,
118         worker_context_provider->ContextCapabilities().supports_oop_raster);
119   } else {
120     EXPECT_EQ(TestRasterType::kBitmap, raster_type());
121   }
122   LayerTreeTest::DrawLayersOnThread(host_impl);
123 }
124 
InitializeSettings(LayerTreeSettings * settings)125 void LayerTreePixelTest::InitializeSettings(LayerTreeSettings* settings) {
126   LayerTreeTest::InitializeSettings(settings);
127   settings->gpu_rasterization_disabled = !use_accelerated_raster();
128   settings->use_zero_copy = raster_type() == TestRasterType::kZeroCopy;
129 }
130 
131 std::unique_ptr<viz::DisplayCompositorMemoryAndTaskController>
CreateDisplayControllerOnThread()132 LayerTreePixelTest::CreateDisplayControllerOnThread() {
133   auto skia_deps = std::make_unique<viz::SkiaOutputSurfaceDependencyImpl>(
134       viz::TestGpuServiceHolder::GetInstance()->gpu_service(),
135       gpu::kNullSurfaceHandle);
136   return std::make_unique<viz::DisplayCompositorMemoryAndTaskController>(
137       std::move(skia_deps));
138 }
139 
140 std::unique_ptr<viz::SkiaOutputSurface>
CreateDisplaySkiaOutputSurfaceOnThread(viz::DisplayCompositorMemoryAndTaskController * display_controller)141 LayerTreePixelTest::CreateDisplaySkiaOutputSurfaceOnThread(
142     viz::DisplayCompositorMemoryAndTaskController* display_controller) {
143   // Set up the SkiaOutputSurfaceImpl.
144   auto output_surface = viz::SkiaOutputSurfaceImpl::Create(
145       display_controller, viz::RendererSettings(), &debug_settings_);
146   return output_surface;
147 }
148 
149 std::unique_ptr<viz::OutputSurface>
CreateDisplayOutputSurfaceOnThread(scoped_refptr<viz::ContextProvider> compositor_context_provider)150 LayerTreePixelTest::CreateDisplayOutputSurfaceOnThread(
151     scoped_refptr<viz::ContextProvider> compositor_context_provider) {
152   std::unique_ptr<PixelTestOutputSurface> display_output_surface;
153   if (renderer_type_ == viz::RendererType::kGL) {
154     // Pixel tests use a separate context for the Display to more closely
155     // mimic texture transport from the renderer process to the Display
156     // compositor.
157     auto display_context_provider =
158         base::MakeRefCounted<viz::TestInProcessContextProvider>(
159             /*enable_gpu_rasterization=*/false,
160             /*enable_oop_rasterization=*/false, /*support_locking=*/false);
161     gpu::ContextResult result = display_context_provider->BindToCurrentThread();
162     DCHECK_EQ(result, gpu::ContextResult::kSuccess);
163 
164     gfx::SurfaceOrigin surface_origin = gfx::SurfaceOrigin::kBottomLeft;
165     display_output_surface = std::make_unique<PixelTestOutputSurface>(
166         std::move(display_context_provider), surface_origin);
167   } else {
168     EXPECT_EQ(viz::RendererType::kSoftware, renderer_type_);
169     display_output_surface = std::make_unique<PixelTestOutputSurface>(
170         std::make_unique<viz::SoftwareOutputDevice>());
171   }
172   return std::move(display_output_surface);
173 }
174 
175 std::unique_ptr<viz::CopyOutputRequest>
CreateCopyOutputRequest()176 LayerTreePixelTest::CreateCopyOutputRequest() {
177   return std::make_unique<viz::CopyOutputRequest>(
178       viz::CopyOutputRequest::ResultFormat::RGBA_BITMAP,
179       base::BindOnce(&LayerTreePixelTest::ReadbackResult,
180                      base::Unretained(this)));
181 }
182 
ReadbackResult(std::unique_ptr<viz::CopyOutputResult> result)183 void LayerTreePixelTest::ReadbackResult(
184     std::unique_ptr<viz::CopyOutputResult> result) {
185   ASSERT_FALSE(result->IsEmpty());
186   EXPECT_EQ(result->format(), viz::CopyOutputResult::Format::RGBA_BITMAP);
187   result_bitmap_ = std::make_unique<SkBitmap>(result->AsSkBitmap());
188   EXPECT_TRUE(result_bitmap_->readyToDraw());
189   EndTest();
190 }
191 
BeginTest()192 void LayerTreePixelTest::BeginTest() {
193   Layer* target =
194       readback_target_ ? readback_target_ : layer_tree_host()->root_layer();
195   if (!layer_tree_host()->IsUsingLayerLists()) {
196     target->RequestCopyOfOutput(CreateCopyOutputRequest());
197   } else {
198     layer_tree_host()->property_trees()->effect_tree.AddCopyRequest(
199         target->effect_tree_index(), CreateCopyOutputRequest());
200     layer_tree_host()
201         ->property_trees()
202         ->effect_tree.Node(target->effect_tree_index())
203         ->has_copy_request = true;
204   }
205   PostSetNeedsCommitToMainThread();
206 }
207 
AfterTest()208 void LayerTreePixelTest::AfterTest() {
209   // Bitmap comparison.
210   if (ref_file_.empty()) {
211     EXPECT_TRUE(
212         MatchesBitmap(*result_bitmap_, expected_bitmap_, *pixel_comparator_));
213     return;
214   }
215 
216   // File comparison.
217   base::FilePath test_data_dir;
218   EXPECT_TRUE(
219       base::PathService::Get(viz::Paths::DIR_TEST_DATA, &test_data_dir));
220   base::FilePath ref_file_path = test_data_dir.Append(ref_file_);
221 
222   base::CommandLine* cmd = base::CommandLine::ForCurrentProcess();
223   if (cmd->HasSwitch(switches::kRebaselinePixelTests))
224     EXPECT_TRUE(WritePNGFile(*result_bitmap_, ref_file_path, true));
225   EXPECT_TRUE(MatchesPNGFile(*result_bitmap_,
226                              ref_file_path,
227                              *pixel_comparator_));
228 }
229 
CreateSolidColorLayer(const gfx::Rect & rect,SkColor color)230 scoped_refptr<SolidColorLayer> LayerTreePixelTest::CreateSolidColorLayer(
231     const gfx::Rect& rect, SkColor color) {
232   scoped_refptr<SolidColorLayer> layer = SolidColorLayer::Create();
233   layer->SetIsDrawable(true);
234   layer->SetHitTestable(true);
235   layer->SetBounds(rect.size());
236   layer->SetPosition(gfx::PointF(rect.origin()));
237   layer->SetOffsetToTransformParent(
238       gfx::Vector2dF(rect.origin().x(), rect.origin().y()));
239   layer->SetBackgroundColor(color);
240   return layer;
241 }
242 
EndTest()243 void LayerTreePixelTest::EndTest() {
244   // Drop textures on the main thread so that they can be cleaned up and
245   // the pending callbacks will fire.
246   for (size_t i = 0; i < texture_layers_.size(); ++i) {
247     texture_layers_[i]->ClearTexture();
248   }
249 
250   TryEndTest();
251 }
252 
TryEndTest()253 void LayerTreePixelTest::TryEndTest() {
254   if (!result_bitmap_)
255     return;
256   if (pending_texture_mailbox_callbacks_)
257     return;
258   LayerTreeTest::EndTest();
259 }
260 
261 scoped_refptr<SolidColorLayer> LayerTreePixelTest::
CreateSolidColorLayerWithBorder(const gfx::Rect & rect,SkColor color,int border_width,SkColor border_color)262     CreateSolidColorLayerWithBorder(
263         const gfx::Rect& rect, SkColor color,
264         int border_width, SkColor border_color) {
265   std::vector<scoped_refptr<SolidColorLayer>> layers;
266   CreateSolidColorLayerPlusBorders(rect, color, border_width, border_color,
267                                    layers);
268   layers[0]->AddChild(layers[1]);
269   layers[0]->AddChild(layers[2]);
270   layers[0]->AddChild(layers[3]);
271   layers[0]->AddChild(layers[4]);
272   return layers[0];
273 }
274 
CreateSolidColorLayerPlusBorders(const gfx::Rect & rect,SkColor color,int border_width,SkColor border_color,std::vector<scoped_refptr<SolidColorLayer>> & layers)275 void LayerTreePixelTest::CreateSolidColorLayerPlusBorders(
276     const gfx::Rect& rect,
277     SkColor color,
278     int border_width,
279     SkColor border_color,
280     std::vector<scoped_refptr<SolidColorLayer>>& layers) {
281   scoped_refptr<SolidColorLayer> layer = CreateSolidColorLayer(rect, color);
282   scoped_refptr<SolidColorLayer> border_top = CreateSolidColorLayer(
283       gfx::Rect(0, 0, rect.width(), border_width), border_color);
284   scoped_refptr<SolidColorLayer> border_left = CreateSolidColorLayer(
285       gfx::Rect(0,
286                 border_width,
287                 border_width,
288                 rect.height() - border_width * 2),
289       border_color);
290   scoped_refptr<SolidColorLayer> border_right =
291       CreateSolidColorLayer(gfx::Rect(rect.width() - border_width,
292                                       border_width,
293                                       border_width,
294                                       rect.height() - border_width * 2),
295                             border_color);
296   scoped_refptr<SolidColorLayer> border_bottom = CreateSolidColorLayer(
297       gfx::Rect(0, rect.height() - border_width, rect.width(), border_width),
298       border_color);
299   layers.push_back(layer);
300   layers.push_back(border_top);
301   layers.push_back(border_left);
302   layers.push_back(border_right);
303   layers.push_back(border_bottom);
304 }
305 
RunPixelTest(scoped_refptr<Layer> content_root,base::FilePath file_name)306 void LayerTreePixelTest::RunPixelTest(scoped_refptr<Layer> content_root,
307                                       base::FilePath file_name) {
308   content_root_ = content_root;
309   readback_target_ = nullptr;
310   ref_file_ = file_name;
311   RunTest(CompositorMode::THREADED);
312 }
313 
RunPixelTest(scoped_refptr<Layer> content_root,const SkBitmap & expected_bitmap)314 void LayerTreePixelTest::RunPixelTest(scoped_refptr<Layer> content_root,
315                                       const SkBitmap& expected_bitmap) {
316   content_root_ = content_root;
317   readback_target_ = nullptr;
318   ref_file_ = base::FilePath();
319   expected_bitmap_ = expected_bitmap;
320   RunTest(CompositorMode::THREADED);
321 }
322 
RunPixelTestWithLayerList(base::FilePath file_name)323 void LayerTreePixelTest::RunPixelTestWithLayerList(base::FilePath file_name) {
324   readback_target_ = nullptr;
325   ref_file_ = file_name;
326   RunTest(CompositorMode::THREADED);
327 }
328 
RunSingleThreadedPixelTest(scoped_refptr<Layer> content_root,base::FilePath file_name)329 void LayerTreePixelTest::RunSingleThreadedPixelTest(
330     scoped_refptr<Layer> content_root,
331     base::FilePath file_name) {
332   content_root_ = content_root;
333   readback_target_ = nullptr;
334   ref_file_ = file_name;
335   RunTest(CompositorMode::SINGLE_THREADED);
336 }
337 
RunPixelTestWithReadbackTarget(scoped_refptr<Layer> content_root,Layer * target,base::FilePath file_name)338 void LayerTreePixelTest::RunPixelTestWithReadbackTarget(
339     scoped_refptr<Layer> content_root,
340     Layer* target,
341     base::FilePath file_name) {
342   content_root_ = content_root;
343   readback_target_ = target;
344   ref_file_ = file_name;
345   RunTest(CompositorMode::THREADED);
346 }
347 
SetupTree()348 void LayerTreePixelTest::SetupTree() {
349   if (layer_tree_host()->IsUsingLayerLists()) {
350     // In layer list mode, content_root_ is not used. The subclass should call
351     // SetInitialRootBounds() if needed.
352     LayerTreeTest::SetupTree();
353     return;
354   }
355 
356   SetInitialRootBounds(content_root_->bounds());
357   LayerTreeTest::SetupTree();
358   layer_tree_host()->root_layer()->AddChild(content_root_);
359 }
360 
CopyMailboxToBitmap(const gfx::Size & size,const gpu::Mailbox & mailbox,const gpu::SyncToken & sync_token,const gfx::ColorSpace & color_space)361 SkBitmap LayerTreePixelTest::CopyMailboxToBitmap(
362     const gfx::Size& size,
363     const gpu::Mailbox& mailbox,
364     const gpu::SyncToken& sync_token,
365     const gfx::ColorSpace& color_space) {
366   SkBitmap bitmap;
367   std::unique_ptr<gpu::GLInProcessContext> context =
368       viz::CreateTestInProcessContext();
369   GLES2Interface* gl = context->GetImplementation();
370 
371   if (sync_token.HasData())
372     gl->WaitSyncTokenCHROMIUM(sync_token.GetConstData());
373 
374   GLuint texture_id = gl->CreateAndConsumeTextureCHROMIUM(mailbox.name);
375 
376   GLuint fbo = 0;
377   gl->GenFramebuffers(1, &fbo);
378   gl->BindFramebuffer(GL_FRAMEBUFFER, fbo);
379   gl->FramebufferTexture2D(
380       GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture_id, 0);
381   EXPECT_EQ(static_cast<unsigned>(GL_FRAMEBUFFER_COMPLETE),
382             gl->CheckFramebufferStatus(GL_FRAMEBUFFER));
383 
384   std::unique_ptr<uint8_t[]> pixels(new uint8_t[size.GetArea() * 4]);
385   gl->ReadPixels(0,
386                  0,
387                  size.width(),
388                  size.height(),
389                  GL_RGBA,
390                  GL_UNSIGNED_BYTE,
391                  pixels.get());
392 
393   gl->DeleteFramebuffers(1, &fbo);
394   gl->DeleteTextures(1, &texture_id);
395 
396   EXPECT_TRUE(color_space.IsValid());
397   bitmap.allocPixels(SkImageInfo::MakeN32Premul(size.width(), size.height(),
398                                                 color_space.ToSkColorSpace()));
399 
400   uint8_t* out_pixels = static_cast<uint8_t*>(bitmap.getPixels());
401 
402   size_t row_bytes = size.width() * 4;
403   size_t total_bytes = size.height() * row_bytes;
404   for (size_t dest_y = 0; dest_y < total_bytes; dest_y += row_bytes) {
405     // Flip Y axis.
406     size_t src_y = total_bytes - dest_y - row_bytes;
407     // Swizzle OpenGL -> Skia byte order.
408     for (size_t x = 0; x < row_bytes; x += 4) {
409       out_pixels[dest_y + x + SK_R32_SHIFT/8] = pixels.get()[src_y + x + 0];
410       out_pixels[dest_y + x + SK_G32_SHIFT/8] = pixels.get()[src_y + x + 1];
411       out_pixels[dest_y + x + SK_B32_SHIFT/8] = pixels.get()[src_y + x + 2];
412       out_pixels[dest_y + x + SK_A32_SHIFT/8] = pixels.get()[src_y + x + 3];
413     }
414   }
415 
416   return bitmap;
417 }
418 
Finish()419 void LayerTreePixelTest::Finish() {
420   std::unique_ptr<gpu::GLInProcessContext> context =
421       viz::CreateTestInProcessContext();
422   GLES2Interface* gl = context->GetImplementation();
423   gl->Finish();
424 }
425 
426 }  // namespace cc
427