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