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 <stddef.h>
6 #include <stdint.h>
7 #include <algorithm>
8 #include <memory>
9 #include <tuple>
10
11 #include "base/bind.h"
12 #include "base/callback_helpers.h"
13 #include "base/memory/aligned_memory.h"
14 #include "base/memory/read_only_shared_memory_region.h"
15 #include "base/memory/shared_memory_mapping.h"
16 #include "base/numerics/ranges.h"
17 #include "build/build_config.h"
18 #include "cc/base/math_util.h"
19 #include "cc/paint/paint_flags.h"
20 #include "cc/paint/skia_paint_canvas.h"
21 #include "cc/test/fake_raster_source.h"
22 #include "cc/test/fake_recording_source.h"
23 #include "cc/test/pixel_test.h"
24 #include "cc/test/render_pass_test_utils.h"
25 #include "cc/test/resource_provider_test_utils.h"
26 #include "cc/test/test_types.h"
27 #include "components/viz/client/client_resource_provider.h"
28 #include "components/viz/common/quads/picture_draw_quad.h"
29 #include "components/viz/common/quads/texture_draw_quad.h"
30 #include "components/viz/common/resources/bitmap_allocation.h"
31 #include "components/viz/common/resources/resource_format_utils.h"
32 #include "components/viz/service/display/delegated_ink_point_pixel_test_helper.h"
33 #include "components/viz/service/display/gl_renderer.h"
34 #include "components/viz/service/display/software_renderer.h"
35 #include "components/viz/service/display/viz_pixel_test.h"
36 #include "components/viz/test/buildflags.h"
37 #include "components/viz/test/test_in_process_context_provider.h"
38 #include "components/viz/test/test_shared_bitmap_manager.h"
39 #include "components/viz/test/test_types.h"
40 #include "gpu/command_buffer/client/gles2_interface.h"
41 #include "gpu/command_buffer/client/shared_image_interface.h"
42 #include "gpu/command_buffer/common/shared_image_usage.h"
43 #include "media/base/video_frame.h"
44 #include "media/renderers/video_resource_updater.h"
45 #include "media/video/half_float_maker.h"
46 #include "third_party/skia/include/core/SkColorPriv.h"
47 #include "third_party/skia/include/core/SkMatrix.h"
48 #include "third_party/skia/include/core/SkRefCnt.h"
49 #include "third_party/skia/include/core/SkSurface.h"
50 #include "third_party/skia/include/effects/SkColorMatrixFilter.h"
51 #include "ui/gfx/color_transform.h"
52 #include "ui/gfx/geometry/rect_conversions.h"
53 #include "ui/gfx/test/icc_profiles.h"
54
55 using gpu::gles2::GLES2Interface;
56
57 namespace viz {
58 namespace {
59
60 const gfx::DisplayColorSpaces kRec601DisplayColorSpaces(
61 gfx::ColorSpace(gfx::ColorSpace::PrimaryID::SMPTE170M,
62 gfx::ColorSpace::TransferID::SMPTE170M));
63
64 #if !defined(OS_ANDROID)
65 template <typename T>
MakePixelSpan(const std::vector<T> & vec)66 base::span<const uint8_t> MakePixelSpan(const std::vector<T>& vec) {
67 return base::make_span(reinterpret_cast<const uint8_t*>(vec.data()),
68 vec.size() * sizeof(T));
69 }
70
MakePixelSpan(const SkBitmap & bitmap)71 base::span<const uint8_t> MakePixelSpan(const SkBitmap& bitmap) {
72 return base::make_span(static_cast<const uint8_t*>(bitmap.getPixels()),
73 bitmap.computeByteSize());
74 }
75
AllocateAndRegisterSharedBitmapMemory(const SharedBitmapId & id,const gfx::Size & size,SharedBitmapManager * shared_bitmap_manager)76 base::WritableSharedMemoryMapping AllocateAndRegisterSharedBitmapMemory(
77 const SharedBitmapId& id,
78 const gfx::Size& size,
79 SharedBitmapManager* shared_bitmap_manager) {
80 base::MappedReadOnlyRegion shm =
81 bitmap_allocation::AllocateSharedBitmap(size, RGBA_8888);
82 shared_bitmap_manager->ChildAllocatedSharedBitmap(shm.region.Map(), id);
83 return std::move(shm.mapping);
84 }
85
DeleteSharedImage(scoped_refptr<ContextProvider> context_provider,gpu::Mailbox mailbox,const gpu::SyncToken & sync_token,bool is_lost)86 void DeleteSharedImage(scoped_refptr<ContextProvider> context_provider,
87 gpu::Mailbox mailbox,
88 const gpu::SyncToken& sync_token,
89 bool is_lost) {
90 DCHECK(context_provider);
91 gpu::SharedImageInterface* sii = context_provider->SharedImageInterface();
92 DCHECK(sii);
93 sii->DestroySharedImage(sync_token, mailbox);
94 }
95
CreateGpuResource(scoped_refptr<ContextProvider> context_provider,ClientResourceProvider * resource_provider,const gfx::Size & size,ResourceFormat format,gfx::ColorSpace color_space,base::span<const uint8_t> pixels)96 ResourceId CreateGpuResource(scoped_refptr<ContextProvider> context_provider,
97 ClientResourceProvider* resource_provider,
98 const gfx::Size& size,
99 ResourceFormat format,
100 gfx::ColorSpace color_space,
101 base::span<const uint8_t> pixels) {
102 DCHECK(context_provider);
103 gpu::SharedImageInterface* sii = context_provider->SharedImageInterface();
104 DCHECK(sii);
105 gpu::Mailbox mailbox = sii->CreateSharedImage(
106 format, size, color_space, kTopLeft_GrSurfaceOrigin, kPremul_SkAlphaType,
107 gpu::SHARED_IMAGE_USAGE_DISPLAY, pixels);
108 gpu::SyncToken sync_token = sii->GenUnverifiedSyncToken();
109
110 TransferableResource gl_resource = TransferableResource::MakeGL(
111 mailbox, GL_LINEAR, GL_TEXTURE_2D, sync_token, size,
112 false /* is_overlay_candidate */);
113 gl_resource.format = format;
114 gl_resource.color_space = std::move(color_space);
115 auto release_callback = SingleReleaseCallback::Create(
116 base::BindOnce(&DeleteSharedImage, std::move(context_provider), mailbox));
117 return resource_provider->ImportResource(gl_resource,
118 std::move(release_callback));
119 }
120
CreateTestRootRenderPass(AggregatedRenderPassId id,const gfx::Rect & rect)121 std::unique_ptr<AggregatedRenderPass> CreateTestRootRenderPass(
122 AggregatedRenderPassId id,
123 const gfx::Rect& rect) {
124 auto pass = std::make_unique<AggregatedRenderPass>();
125 const gfx::Rect output_rect = rect;
126 const gfx::Rect damage_rect = rect;
127 const gfx::Transform transform_to_root_target;
128 pass->SetNew(id, output_rect, damage_rect, transform_to_root_target);
129 return pass;
130 }
131
CreateTestRenderPass(AggregatedRenderPassId id,const gfx::Rect & rect,const gfx::Transform & transform_to_root_target)132 std::unique_ptr<AggregatedRenderPass> CreateTestRenderPass(
133 AggregatedRenderPassId id,
134 const gfx::Rect& rect,
135 const gfx::Transform& transform_to_root_target) {
136 auto pass = std::make_unique<AggregatedRenderPass>();
137 const gfx::Rect output_rect = rect;
138 const gfx::Rect damage_rect = rect;
139 pass->SetNew(id, output_rect, damage_rect, transform_to_root_target);
140 return pass;
141 }
142
CreateTestSharedQuadState(gfx::Transform quad_to_target_transform,const gfx::Rect & rect,AggregatedRenderPass * render_pass,const gfx::RRectF & rrect)143 SharedQuadState* CreateTestSharedQuadState(
144 gfx::Transform quad_to_target_transform,
145 const gfx::Rect& rect,
146 AggregatedRenderPass* render_pass,
147 const gfx::RRectF& rrect) {
148 const gfx::Rect layer_rect = rect;
149 const gfx::Rect visible_layer_rect = rect;
150 const gfx::Rect clip_rect = rect;
151 const bool is_clipped = false;
152 const bool are_contents_opaque = false;
153 const float opacity = 1.0f;
154 const gfx::MaskFilterInfo mask_filter_info(rrect);
155 const SkBlendMode blend_mode = SkBlendMode::kSrcOver;
156 int sorting_context_id = 0;
157 SharedQuadState* shared_state = render_pass->CreateAndAppendSharedQuadState();
158 shared_state->SetAll(quad_to_target_transform, layer_rect, visible_layer_rect,
159 mask_filter_info, clip_rect, is_clipped,
160 are_contents_opaque, opacity, blend_mode,
161 sorting_context_id);
162 return shared_state;
163 }
164
CreateTestSharedQuadStateClipped(gfx::Transform quad_to_target_transform,const gfx::Rect & rect,const gfx::Rect & clip_rect,AggregatedRenderPass * render_pass)165 SharedQuadState* CreateTestSharedQuadStateClipped(
166 gfx::Transform quad_to_target_transform,
167 const gfx::Rect& rect,
168 const gfx::Rect& clip_rect,
169 AggregatedRenderPass* render_pass) {
170 const gfx::Rect layer_rect = rect;
171 const gfx::Rect visible_layer_rect = clip_rect;
172 const bool is_clipped = true;
173 const bool are_contents_opaque = false;
174 const float opacity = 1.0f;
175 const SkBlendMode blend_mode = SkBlendMode::kSrcOver;
176 int sorting_context_id = 0;
177 SharedQuadState* shared_state = render_pass->CreateAndAppendSharedQuadState();
178 shared_state->SetAll(quad_to_target_transform, layer_rect, visible_layer_rect,
179 /*mask_filter_info=*/gfx::MaskFilterInfo(), clip_rect,
180 is_clipped, are_contents_opaque, opacity, blend_mode,
181 sorting_context_id);
182 return shared_state;
183 }
184
CreateTestRenderPassDrawQuad(const SharedQuadState * shared_state,const gfx::Rect & rect,AggregatedRenderPassId pass_id,AggregatedRenderPass * render_pass)185 void CreateTestRenderPassDrawQuad(const SharedQuadState* shared_state,
186 const gfx::Rect& rect,
187 AggregatedRenderPassId pass_id,
188 AggregatedRenderPass* render_pass) {
189 auto* quad =
190 render_pass->CreateAndAppendDrawQuad<AggregatedRenderPassDrawQuad>();
191 quad->SetNew(shared_state, rect, rect, pass_id,
192 0, // mask_resource_id
193 gfx::RectF(), // mask_uv_rect
194 gfx::Size(), // mask_texture_size
195 gfx::Vector2dF(), // filters scale
196 gfx::PointF(), // filter origin
197 gfx::RectF(rect), // tex_coord_rect
198 false, // force_anti_aliasing_off
199 1.0f); // backdrop_filter_quality
200 }
201
202 // Create a TextureDrawDrawQuad with two given colors.
203 // flipped_texture_quad: The TextureDrawDrawQuad is y flipped.
204 // half_and_half: if true, the upper half part of the texture is filled with
205 // texel_color_one, other part of the texture is filled with texel_color_two.
206 // if false, a 1/2 width and height rectangle in the middle of the quad will
207 // be filled with texel_color_two, other part of the texture is filled with
208 // texel_color_one,
CreateTestTwoColoredTextureDrawQuad(bool gpu_resource,const gfx::Rect & rect,SkColor texel_color_one,SkColor texel_color_two,SkColor background_color,bool premultiplied_alpha,bool flipped_texture_quad,bool half_and_half,const SharedQuadState * shared_state,DisplayResourceProvider * resource_provider,ClientResourceProvider * child_resource_provider,SharedBitmapManager * shared_bitmap_manager,scoped_refptr<ContextProvider> child_context_provider,AggregatedRenderPass * render_pass)209 void CreateTestTwoColoredTextureDrawQuad(
210 bool gpu_resource,
211 const gfx::Rect& rect,
212 SkColor texel_color_one,
213 SkColor texel_color_two,
214 SkColor background_color,
215 bool premultiplied_alpha,
216 bool flipped_texture_quad,
217 bool half_and_half,
218 const SharedQuadState* shared_state,
219 DisplayResourceProvider* resource_provider,
220 ClientResourceProvider* child_resource_provider,
221 SharedBitmapManager* shared_bitmap_manager,
222 scoped_refptr<ContextProvider> child_context_provider,
223 AggregatedRenderPass* render_pass) {
224 SkPMColor pixel_color_one =
225 premultiplied_alpha
226 ? SkPreMultiplyColor(texel_color_one)
227 : SkPackARGB32NoCheck(
228 SkColorGetA(texel_color_one), SkColorGetR(texel_color_one),
229 SkColorGetG(texel_color_one), SkColorGetB(texel_color_one));
230 SkPMColor pixel_color_two =
231 premultiplied_alpha
232 ? SkPreMultiplyColor(texel_color_two)
233 : SkPackARGB32NoCheck(
234 SkColorGetA(texel_color_two), SkColorGetR(texel_color_two),
235 SkColorGetG(texel_color_two), SkColorGetB(texel_color_two));
236 // The default color is texel_color_one
237 std::vector<uint32_t> pixels(rect.size().GetArea(), pixel_color_one);
238 if (half_and_half) {
239 // Fill the bottom half part of the texture with texel_color_two.
240 for (int i = rect.height() / 2; i < rect.height(); ++i) {
241 for (int k = 0; k < rect.width(); ++k) {
242 pixels[i * rect.width() + k] = pixel_color_two;
243 }
244 }
245 } else {
246 // Fill a 1/2 width and height rectangle with pixel_color_two.
247 for (int i = rect.height() / 4; i < (rect.height() * 3 / 4); ++i) {
248 for (int k = rect.width() / 4; k < (rect.width() * 3 / 4); ++k) {
249 pixels[i * rect.width() + k] = pixel_color_two;
250 }
251 }
252 }
253
254 ResourceId resource;
255 if (gpu_resource) {
256 resource = CreateGpuResource(
257 child_context_provider, child_resource_provider, rect.size(), BGRA_8888,
258 gfx::ColorSpace(), MakePixelSpan(pixels));
259 } else {
260 SharedBitmapId shared_bitmap_id = SharedBitmap::GenerateId();
261 base::WritableSharedMemoryMapping mapping =
262 AllocateAndRegisterSharedBitmapMemory(shared_bitmap_id, rect.size(),
263 shared_bitmap_manager);
264 resource = child_resource_provider->ImportResource(
265 TransferableResource::MakeSoftware(shared_bitmap_id, rect.size(),
266 RGBA_8888),
267 SingleReleaseCallback::Create(base::DoNothing()));
268
269 auto span = mapping.GetMemoryAsSpan<uint32_t>(pixels.size());
270 std::copy(pixels.begin(), pixels.end(), span.begin());
271 }
272
273 // Return the mapped resource id.
274 std::unordered_map<ResourceId, ResourceId> resource_map =
275 cc::SendResourceAndGetChildToParentMap({resource}, resource_provider,
276 child_resource_provider,
277 child_context_provider.get());
278 ResourceId mapped_resource = resource_map[resource];
279
280 bool needs_blending = true;
281 float vertex_opacity[4] = {1.0f, 1.0f, 1.0f, 1.0f};
282 const gfx::PointF uv_top_left(0.0f, 0.0f);
283 const gfx::PointF uv_bottom_right(1.0f, 1.0f);
284 const bool nearest_neighbor = false;
285 auto* quad = render_pass->CreateAndAppendDrawQuad<TextureDrawQuad>();
286 quad->SetNew(shared_state, rect, rect, needs_blending, mapped_resource,
287 premultiplied_alpha, uv_top_left, uv_bottom_right,
288 background_color, vertex_opacity, flipped_texture_quad,
289 nearest_neighbor, /*secure_output_only=*/false,
290 gfx::ProtectedVideoType::kClear);
291 }
292
CreateTestTextureDrawQuad(bool gpu_resource,const gfx::Rect & rect,SkColor texel_color,float vertex_opacity[4],SkColor background_color,bool premultiplied_alpha,const SharedQuadState * shared_state,DisplayResourceProvider * resource_provider,ClientResourceProvider * child_resource_provider,SharedBitmapManager * shared_bitmap_manager,scoped_refptr<ContextProvider> child_context_provider,AggregatedRenderPass * render_pass)293 void CreateTestTextureDrawQuad(
294 bool gpu_resource,
295 const gfx::Rect& rect,
296 SkColor texel_color,
297 float vertex_opacity[4],
298 SkColor background_color,
299 bool premultiplied_alpha,
300 const SharedQuadState* shared_state,
301 DisplayResourceProvider* resource_provider,
302 ClientResourceProvider* child_resource_provider,
303 SharedBitmapManager* shared_bitmap_manager,
304 scoped_refptr<ContextProvider> child_context_provider,
305 AggregatedRenderPass* render_pass) {
306 SkPMColor pixel_color = premultiplied_alpha
307 ? SkPreMultiplyColor(texel_color)
308 : SkPackARGB32NoCheck(SkColorGetA(texel_color),
309 SkColorGetR(texel_color),
310 SkColorGetG(texel_color),
311 SkColorGetB(texel_color));
312 size_t num_pixels = static_cast<size_t>(rect.width()) * rect.height();
313 std::vector<uint32_t> pixels(num_pixels, pixel_color);
314
315 ResourceId resource;
316 if (gpu_resource) {
317 resource = CreateGpuResource(
318 child_context_provider, child_resource_provider, rect.size(), RGBA_8888,
319 gfx::ColorSpace(), MakePixelSpan(pixels));
320 } else {
321 SharedBitmapId shared_bitmap_id = SharedBitmap::GenerateId();
322 base::WritableSharedMemoryMapping mapping =
323 AllocateAndRegisterSharedBitmapMemory(shared_bitmap_id, rect.size(),
324 shared_bitmap_manager);
325 resource = child_resource_provider->ImportResource(
326 TransferableResource::MakeSoftware(shared_bitmap_id, rect.size(),
327 RGBA_8888),
328 SingleReleaseCallback::Create(base::DoNothing()));
329
330 auto span = mapping.GetMemoryAsSpan<uint32_t>(pixels.size());
331 std::copy(pixels.begin(), pixels.end(), span.begin());
332 }
333
334 // Return the mapped resource id.
335 std::unordered_map<ResourceId, ResourceId> resource_map =
336 cc::SendResourceAndGetChildToParentMap({resource}, resource_provider,
337 child_resource_provider,
338 child_context_provider.get());
339 ResourceId mapped_resource = resource_map[resource];
340
341 bool needs_blending = true;
342 const gfx::PointF uv_top_left(0.0f, 0.0f);
343 const gfx::PointF uv_bottom_right(1.0f, 1.0f);
344 const bool flipped = false;
345 const bool nearest_neighbor = false;
346 auto* quad = render_pass->CreateAndAppendDrawQuad<TextureDrawQuad>();
347 quad->SetNew(shared_state, rect, rect, needs_blending, mapped_resource,
348 premultiplied_alpha, uv_top_left, uv_bottom_right,
349 background_color, vertex_opacity, flipped, nearest_neighbor,
350 /*secure_output_only=*/false, gfx::ProtectedVideoType::kClear);
351 }
352
CreateTestTextureDrawQuad(bool gpu_resource,const gfx::Rect & rect,SkColor texel_color,SkColor background_color,bool premultiplied_alpha,const SharedQuadState * shared_state,DisplayResourceProvider * resource_provider,ClientResourceProvider * child_resource_provider,SharedBitmapManager * shared_bitmap_manager,scoped_refptr<ContextProvider> child_context_provider,AggregatedRenderPass * render_pass)353 void CreateTestTextureDrawQuad(
354 bool gpu_resource,
355 const gfx::Rect& rect,
356 SkColor texel_color,
357 SkColor background_color,
358 bool premultiplied_alpha,
359 const SharedQuadState* shared_state,
360 DisplayResourceProvider* resource_provider,
361 ClientResourceProvider* child_resource_provider,
362 SharedBitmapManager* shared_bitmap_manager,
363 scoped_refptr<ContextProvider> child_context_provider,
364 AggregatedRenderPass* render_pass) {
365 float vertex_opacity[4] = {1.0f, 1.0f, 1.0f, 1.0f};
366 CreateTestTextureDrawQuad(gpu_resource, rect, texel_color, vertex_opacity,
367 background_color, premultiplied_alpha, shared_state,
368 resource_provider, child_resource_provider,
369 shared_bitmap_manager,
370 std::move(child_context_provider), render_pass);
371 }
372
CreateTestYUVVideoDrawQuad_FromVideoFrame(const SharedQuadState * shared_state,scoped_refptr<media::VideoFrame> video_frame,uint8_t alpha_value,const gfx::RectF & tex_coord_rect,AggregatedRenderPass * render_pass,media::VideoResourceUpdater * video_resource_updater,const gfx::Rect & rect,const gfx::Rect & visible_rect,DisplayResourceProvider * resource_provider,ClientResourceProvider * child_resource_provider,ContextProvider * child_context_provider)373 void CreateTestYUVVideoDrawQuad_FromVideoFrame(
374 const SharedQuadState* shared_state,
375 scoped_refptr<media::VideoFrame> video_frame,
376 uint8_t alpha_value,
377 const gfx::RectF& tex_coord_rect,
378 AggregatedRenderPass* render_pass,
379 media::VideoResourceUpdater* video_resource_updater,
380 const gfx::Rect& rect,
381 const gfx::Rect& visible_rect,
382 DisplayResourceProvider* resource_provider,
383 ClientResourceProvider* child_resource_provider,
384 ContextProvider* child_context_provider) {
385 const bool with_alpha = (video_frame->format() == media::PIXEL_FORMAT_I420A);
386
387 gfx::ColorSpace video_color_space = video_frame->ColorSpace();
388 DCHECK(video_color_space.IsValid());
389
390 bool needs_blending = true;
391
392 if (with_alpha) {
393 memset(video_frame->data(media::VideoFrame::kAPlane), alpha_value,
394 video_frame->stride(media::VideoFrame::kAPlane) *
395 video_frame->rows(media::VideoFrame::kAPlane));
396 }
397
398 media::VideoFrameExternalResources resources =
399 video_resource_updater->CreateExternalResourcesFromVideoFrame(
400 video_frame);
401
402 EXPECT_EQ(media::VideoFrameResourceType::YUV, resources.type);
403 EXPECT_EQ(media::VideoFrame::NumPlanes(video_frame->format()),
404 resources.resources.size());
405 EXPECT_EQ(media::VideoFrame::NumPlanes(video_frame->format()),
406 resources.release_callbacks.size());
407
408 ResourceId resource_y = child_resource_provider->ImportResource(
409 resources.resources[media::VideoFrame::kYPlane],
410 SingleReleaseCallback::Create(
411 std::move(resources.release_callbacks[media::VideoFrame::kYPlane])));
412 ResourceId resource_u = child_resource_provider->ImportResource(
413 resources.resources[media::VideoFrame::kUPlane],
414 SingleReleaseCallback::Create(
415 std::move(resources.release_callbacks[media::VideoFrame::kUPlane])));
416 ResourceId resource_v = child_resource_provider->ImportResource(
417 resources.resources[media::VideoFrame::kVPlane],
418 SingleReleaseCallback::Create(
419 std::move(resources.release_callbacks[media::VideoFrame::kVPlane])));
420 ResourceId resource_a = 0;
421 if (with_alpha) {
422 resource_a = child_resource_provider->ImportResource(
423 resources.resources[media::VideoFrame::kAPlane],
424 SingleReleaseCallback::Create(std::move(
425 resources.release_callbacks[media::VideoFrame::kAPlane])));
426 }
427
428 std::vector<ResourceId> resource_ids_to_transfer;
429 resource_ids_to_transfer.push_back(resource_y);
430 resource_ids_to_transfer.push_back(resource_u);
431 resource_ids_to_transfer.push_back(resource_v);
432 if (with_alpha)
433 resource_ids_to_transfer.push_back(resource_a);
434 // Transfer resources to the parent, and get the resource map.
435 std::unordered_map<ResourceId, ResourceId> resource_map =
436 cc::SendResourceAndGetChildToParentMap(
437 resource_ids_to_transfer, resource_provider, child_resource_provider,
438 child_context_provider);
439
440 ResourceId mapped_resource_y = resource_map[resource_y];
441 ResourceId mapped_resource_u = resource_map[resource_u];
442 ResourceId mapped_resource_v = resource_map[resource_v];
443 ResourceId mapped_resource_a = 0;
444 if (with_alpha)
445 mapped_resource_a = resource_map[resource_a];
446 const gfx::Size ya_tex_size = video_frame->coded_size();
447 const gfx::Size uv_tex_size = media::VideoFrame::PlaneSize(
448 video_frame->format(), media::VideoFrame::kUPlane,
449 video_frame->coded_size());
450 DCHECK(uv_tex_size == media::VideoFrame::PlaneSize(
451 video_frame->format(), media::VideoFrame::kVPlane,
452 video_frame->coded_size()));
453 if (with_alpha) {
454 DCHECK(ya_tex_size == media::VideoFrame::PlaneSize(
455 video_frame->format(), media::VideoFrame::kAPlane,
456 video_frame->coded_size()));
457 }
458
459 gfx::RectF ya_tex_coord_rect(tex_coord_rect.x() * ya_tex_size.width(),
460 tex_coord_rect.y() * ya_tex_size.height(),
461 tex_coord_rect.width() * ya_tex_size.width(),
462 tex_coord_rect.height() * ya_tex_size.height());
463 gfx::RectF uv_tex_coord_rect(tex_coord_rect.x() * uv_tex_size.width(),
464 tex_coord_rect.y() * uv_tex_size.height(),
465 tex_coord_rect.width() * uv_tex_size.width(),
466 tex_coord_rect.height() * uv_tex_size.height());
467
468 auto* yuv_quad = render_pass->CreateAndAppendDrawQuad<YUVVideoDrawQuad>();
469 uint32_t bits_per_channel = 8;
470 if (video_frame->format() == media::PIXEL_FORMAT_YUV420P10 ||
471 video_frame->format() == media::PIXEL_FORMAT_YUV422P10 ||
472 video_frame->format() == media::PIXEL_FORMAT_YUV444P10) {
473 bits_per_channel = 10;
474 }
475
476 ResourceFormat yuv_highbit_resource_format =
477 video_resource_updater->YuvResourceFormat(bits_per_channel);
478
479 float offset = 0.0f;
480 float multiplier = 1.0f;
481
482 if (yuv_highbit_resource_format == R16_EXT) {
483 multiplier = 65535.0f / ((1 << bits_per_channel) - 1);
484 } else if (yuv_highbit_resource_format == LUMINANCE_F16) {
485 std::unique_ptr<media::HalfFloatMaker> half_float_maker =
486 media::HalfFloatMaker::NewHalfFloatMaker(bits_per_channel);
487 offset = half_float_maker->Offset();
488 multiplier = half_float_maker->Multiplier();
489 } else {
490 bits_per_channel = 8;
491 }
492
493 yuv_quad->SetNew(shared_state, rect, visible_rect, needs_blending,
494 ya_tex_coord_rect, uv_tex_coord_rect, ya_tex_size,
495 uv_tex_size, mapped_resource_y, mapped_resource_u,
496 mapped_resource_v, mapped_resource_a, video_color_space,
497 offset, multiplier, bits_per_channel);
498 }
499
CreateTestY16TextureDrawQuad_FromVideoFrame(const SharedQuadState * shared_state,scoped_refptr<media::VideoFrame> video_frame,const gfx::RectF & tex_coord_rect,AggregatedRenderPass * render_pass,media::VideoResourceUpdater * video_resource_updater,const gfx::Rect & rect,const gfx::Rect & visible_rect,DisplayResourceProvider * resource_provider,ClientResourceProvider * child_resource_provider,ContextProvider * child_context_provider)500 void CreateTestY16TextureDrawQuad_FromVideoFrame(
501 const SharedQuadState* shared_state,
502 scoped_refptr<media::VideoFrame> video_frame,
503 const gfx::RectF& tex_coord_rect,
504 AggregatedRenderPass* render_pass,
505 media::VideoResourceUpdater* video_resource_updater,
506 const gfx::Rect& rect,
507 const gfx::Rect& visible_rect,
508 DisplayResourceProvider* resource_provider,
509 ClientResourceProvider* child_resource_provider,
510 ContextProvider* child_context_provider) {
511 media::VideoFrameExternalResources resources =
512 video_resource_updater->CreateExternalResourcesFromVideoFrame(
513 video_frame);
514
515 EXPECT_EQ(media::VideoFrameResourceType::RGBA, resources.type);
516 EXPECT_EQ(1u, resources.resources.size());
517 EXPECT_EQ(1u, resources.release_callbacks.size());
518
519 ResourceId resource_y = child_resource_provider->ImportResource(
520 resources.resources[0],
521 SingleReleaseCallback::Create(std::move(resources.release_callbacks[0])));
522
523 // Transfer resources to the parent, and get the resource map.
524 std::unordered_map<ResourceId, ResourceId> resource_map =
525 cc::SendResourceAndGetChildToParentMap({resource_y}, resource_provider,
526 child_resource_provider,
527 child_context_provider);
528 ResourceId mapped_resource_y = resource_map[resource_y];
529
530 auto* quad = render_pass->CreateAndAppendDrawQuad<TextureDrawQuad>();
531 bool needs_blending = true;
532 float vertex_opacity[4] = {1.0f, 1.0f, 1.0f, 1.0f};
533 quad->SetNew(shared_state, rect, rect, needs_blending, mapped_resource_y,
534 false, tex_coord_rect.origin(), tex_coord_rect.bottom_right(),
535 SK_ColorBLACK, vertex_opacity, false, false,
536 /*secure_output_only=*/false, gfx::ProtectedVideoType::kClear);
537 }
538
539 // Upshift video frame to 10 bit.
CreateHighbitVideoFrame(media::VideoFrame * video_frame)540 scoped_refptr<media::VideoFrame> CreateHighbitVideoFrame(
541 media::VideoFrame* video_frame) {
542 media::VideoPixelFormat format;
543 switch (video_frame->format()) {
544 case media::PIXEL_FORMAT_I420:
545 format = media::PIXEL_FORMAT_YUV420P10;
546 break;
547 case media::PIXEL_FORMAT_I422:
548 format = media::PIXEL_FORMAT_YUV422P10;
549 break;
550 case media::PIXEL_FORMAT_I444:
551 format = media::PIXEL_FORMAT_YUV444P10;
552 break;
553
554 default:
555 NOTREACHED();
556 return nullptr;
557 }
558 scoped_refptr<media::VideoFrame> ret = media::VideoFrame::CreateFrame(
559 format, video_frame->coded_size(), video_frame->visible_rect(),
560 video_frame->natural_size(), video_frame->timestamp());
561
562 // Copy all metadata.
563 ret->metadata()->MergeMetadataFrom(video_frame->metadata());
564
565 for (int plane = media::VideoFrame::kYPlane;
566 plane <= media::VideoFrame::kVPlane; ++plane) {
567 int width = video_frame->row_bytes(plane);
568 const uint8_t* src = video_frame->data(plane);
569 uint16_t* dst = reinterpret_cast<uint16_t*>(ret->data(plane));
570 for (int row = 0; row < video_frame->rows(plane); row++) {
571 for (int x = 0; x < width; x++) {
572 // Replicate the top bits into the lower bits, this way
573 // 0xFF becomes 0x3FF.
574 dst[x] = (src[x] << 2) | (src[x] >> 6);
575 }
576 src += video_frame->stride(plane);
577 dst += ret->stride(plane) / 2;
578 }
579 }
580 return ret;
581 }
582
CreateTestYUVVideoDrawQuad_Striped(const SharedQuadState * shared_state,media::VideoPixelFormat format,gfx::ColorSpace color_space,bool is_transparent,bool highbit,const gfx::RectF & tex_coord_rect,AggregatedRenderPass * render_pass,media::VideoResourceUpdater * video_resource_updater,const gfx::Rect & rect,const gfx::Rect & visible_rect,DisplayResourceProvider * resource_provider,ClientResourceProvider * child_resource_provider,ContextProvider * child_context_provider)583 void CreateTestYUVVideoDrawQuad_Striped(
584 const SharedQuadState* shared_state,
585 media::VideoPixelFormat format,
586 gfx::ColorSpace color_space,
587 bool is_transparent,
588 bool highbit,
589 const gfx::RectF& tex_coord_rect,
590 AggregatedRenderPass* render_pass,
591 media::VideoResourceUpdater* video_resource_updater,
592 const gfx::Rect& rect,
593 const gfx::Rect& visible_rect,
594 DisplayResourceProvider* resource_provider,
595 ClientResourceProvider* child_resource_provider,
596 ContextProvider* child_context_provider) {
597 scoped_refptr<media::VideoFrame> video_frame = media::VideoFrame::CreateFrame(
598 format, rect.size(), rect, rect.size(), base::TimeDelta());
599
600 // YUV values representing a striped pattern, for validating texture
601 // coordinates for sampling.
602 uint8_t y_value = 0;
603 uint8_t u_value = 0;
604 uint8_t v_value = 0;
605 for (int i = 0; i < video_frame->rows(media::VideoFrame::kYPlane); ++i) {
606 uint8_t* y_row = video_frame->data(media::VideoFrame::kYPlane) +
607 video_frame->stride(media::VideoFrame::kYPlane) * i;
608 for (int j = 0; j < video_frame->row_bytes(media::VideoFrame::kYPlane);
609 ++j) {
610 y_row[j] = (y_value += 1);
611 }
612 }
613 for (int i = 0; i < video_frame->rows(media::VideoFrame::kUPlane); ++i) {
614 uint8_t* u_row = video_frame->data(media::VideoFrame::kUPlane) +
615 video_frame->stride(media::VideoFrame::kUPlane) * i;
616 uint8_t* v_row = video_frame->data(media::VideoFrame::kVPlane) +
617 video_frame->stride(media::VideoFrame::kVPlane) * i;
618 for (int j = 0; j < video_frame->row_bytes(media::VideoFrame::kUPlane);
619 ++j) {
620 u_row[j] = (u_value += 3);
621 v_row[j] = (v_value += 5);
622 }
623 }
624 uint8_t alpha_value = is_transparent ? 0 : 128;
625
626 if (highbit)
627 video_frame = CreateHighbitVideoFrame(video_frame.get());
628 video_frame->set_color_space(color_space);
629
630 CreateTestYUVVideoDrawQuad_FromVideoFrame(
631 shared_state, video_frame, alpha_value, tex_coord_rect, render_pass,
632 video_resource_updater, rect, visible_rect, resource_provider,
633 child_resource_provider, child_context_provider);
634 }
635
636 // Creates a video frame of size background_size filled with yuv_background,
637 // and then draws a foreground rectangle in a different color on top of
638 // that. The foreground rectangle must have coordinates that are divisible
639 // by 2 because YUV is a block format.
CreateTestYUVVideoDrawQuad_TwoColor(const SharedQuadState * shared_state,media::VideoPixelFormat format,gfx::ColorSpace color_space,bool is_transparent,const gfx::RectF & tex_coord_rect,const gfx::Size & background_size,const gfx::Rect & visible_rect,uint8_t y_background,uint8_t u_background,uint8_t v_background,const gfx::Rect & foreground_rect,uint8_t y_foreground,uint8_t u_foreground,uint8_t v_foreground,AggregatedRenderPass * render_pass,media::VideoResourceUpdater * video_resource_updater,DisplayResourceProvider * resource_provider,ClientResourceProvider * child_resource_provider,ContextProvider * child_context_provider)640 void CreateTestYUVVideoDrawQuad_TwoColor(
641 const SharedQuadState* shared_state,
642 media::VideoPixelFormat format,
643 gfx::ColorSpace color_space,
644 bool is_transparent,
645 const gfx::RectF& tex_coord_rect,
646 const gfx::Size& background_size,
647 const gfx::Rect& visible_rect,
648 uint8_t y_background,
649 uint8_t u_background,
650 uint8_t v_background,
651 const gfx::Rect& foreground_rect,
652 uint8_t y_foreground,
653 uint8_t u_foreground,
654 uint8_t v_foreground,
655 AggregatedRenderPass* render_pass,
656 media::VideoResourceUpdater* video_resource_updater,
657 DisplayResourceProvider* resource_provider,
658 ClientResourceProvider* child_resource_provider,
659 ContextProvider* child_context_provider) {
660 const gfx::Rect rect(background_size);
661
662 scoped_refptr<media::VideoFrame> video_frame =
663 media::VideoFrame::CreateFrame(format, background_size, foreground_rect,
664 foreground_rect.size(), base::TimeDelta());
665 video_frame->set_color_space(color_space);
666
667 int planes[] = {media::VideoFrame::kYPlane, media::VideoFrame::kUPlane,
668 media::VideoFrame::kVPlane};
669 uint8_t yuv_background[] = {y_background, u_background, v_background};
670 uint8_t yuv_foreground[] = {y_foreground, u_foreground, v_foreground};
671 int sample_size[] = {1, 2, 2};
672
673 for (int i = 0; i < 3; ++i) {
674 memset(video_frame->data(planes[i]), yuv_background[i],
675 video_frame->stride(planes[i]) * video_frame->rows(planes[i]));
676 }
677
678 for (int i = 0; i < 3; ++i) {
679 // Since yuv encoding uses block encoding, widths have to be divisible
680 // by the sample size in order for this function to behave properly.
681 DCHECK_EQ(foreground_rect.x() % sample_size[i], 0);
682 DCHECK_EQ(foreground_rect.y() % sample_size[i], 0);
683 DCHECK_EQ(foreground_rect.width() % sample_size[i], 0);
684 DCHECK_EQ(foreground_rect.height() % sample_size[i], 0);
685
686 gfx::Rect sample_rect(foreground_rect.x() / sample_size[i],
687 foreground_rect.y() / sample_size[i],
688 foreground_rect.width() / sample_size[i],
689 foreground_rect.height() / sample_size[i]);
690 for (int y = sample_rect.y(); y < sample_rect.bottom(); ++y) {
691 for (int x = sample_rect.x(); x < sample_rect.right(); ++x) {
692 size_t offset = y * video_frame->stride(planes[i]) + x;
693 video_frame->data(planes[i])[offset] = yuv_foreground[i];
694 }
695 }
696 }
697
698 uint8_t alpha_value = 255;
699 CreateTestYUVVideoDrawQuad_FromVideoFrame(
700 shared_state, video_frame, alpha_value, tex_coord_rect, render_pass,
701 video_resource_updater, rect, visible_rect, resource_provider,
702 child_resource_provider, child_context_provider);
703 }
704
CreateTestYUVVideoDrawQuad_Solid(const SharedQuadState * shared_state,media::VideoPixelFormat format,const gfx::ColorSpace & color_space,bool is_transparent,const gfx::RectF & tex_coord_rect,uint8_t y,uint8_t u,uint8_t v,AggregatedRenderPass * render_pass,media::VideoResourceUpdater * video_resource_updater,const gfx::Rect & rect,const gfx::Rect & visible_rect,DisplayResourceProvider * resource_provider,ClientResourceProvider * child_resource_provider,ContextProvider * child_context_provider)705 void CreateTestYUVVideoDrawQuad_Solid(
706 const SharedQuadState* shared_state,
707 media::VideoPixelFormat format,
708 const gfx::ColorSpace& color_space,
709 bool is_transparent,
710 const gfx::RectF& tex_coord_rect,
711 uint8_t y,
712 uint8_t u,
713 uint8_t v,
714 AggregatedRenderPass* render_pass,
715 media::VideoResourceUpdater* video_resource_updater,
716 const gfx::Rect& rect,
717 const gfx::Rect& visible_rect,
718 DisplayResourceProvider* resource_provider,
719 ClientResourceProvider* child_resource_provider,
720 ContextProvider* child_context_provider) {
721 scoped_refptr<media::VideoFrame> video_frame = media::VideoFrame::CreateFrame(
722 format, rect.size(), rect, rect.size(), base::TimeDelta());
723 video_frame->set_color_space(color_space);
724
725 // YUV values of a solid, constant, color. Useful for testing that color
726 // space/color range are being handled properly.
727 memset(video_frame->data(media::VideoFrame::kYPlane), y,
728 video_frame->stride(media::VideoFrame::kYPlane) *
729 video_frame->rows(media::VideoFrame::kYPlane));
730 memset(video_frame->data(media::VideoFrame::kUPlane), u,
731 video_frame->stride(media::VideoFrame::kUPlane) *
732 video_frame->rows(media::VideoFrame::kUPlane));
733 memset(video_frame->data(media::VideoFrame::kVPlane), v,
734 video_frame->stride(media::VideoFrame::kVPlane) *
735 video_frame->rows(media::VideoFrame::kVPlane));
736
737 uint8_t alpha_value = is_transparent ? 0 : 128;
738 CreateTestYUVVideoDrawQuad_FromVideoFrame(
739 shared_state, video_frame, alpha_value, tex_coord_rect, render_pass,
740 video_resource_updater, rect, visible_rect, resource_provider,
741 child_resource_provider, child_context_provider);
742 }
743
CreateTestYUVVideoDrawQuad_NV12(const SharedQuadState * shared_state,const gfx::ColorSpace & color_space,const gfx::RectF & tex_coord_rect,uint8_t y,uint8_t u,uint8_t v,AggregatedRenderPass * render_pass,media::VideoResourceUpdater * video_resource_updater,const gfx::Rect & rect,const gfx::Rect & visible_rect,DisplayResourceProvider * resource_provider,ClientResourceProvider * child_resource_provider,scoped_refptr<ContextProvider> child_context_provider)744 void CreateTestYUVVideoDrawQuad_NV12(
745 const SharedQuadState* shared_state,
746 const gfx::ColorSpace& color_space,
747 const gfx::RectF& tex_coord_rect,
748 uint8_t y,
749 uint8_t u,
750 uint8_t v,
751 AggregatedRenderPass* render_pass,
752 media::VideoResourceUpdater* video_resource_updater,
753 const gfx::Rect& rect,
754 const gfx::Rect& visible_rect,
755 DisplayResourceProvider* resource_provider,
756 ClientResourceProvider* child_resource_provider,
757 scoped_refptr<ContextProvider> child_context_provider) {
758 bool needs_blending = true;
759 const gfx::Size ya_tex_size = rect.size();
760 const gfx::Size uv_tex_size = media::VideoFrame::PlaneSize(
761 media::PIXEL_FORMAT_NV12, media::VideoFrame::kUVPlane, rect.size());
762
763 std::vector<uint8_t> y_pixels(ya_tex_size.GetArea(), y);
764 ResourceId resource_y = CreateGpuResource(
765 child_context_provider, child_resource_provider, ya_tex_size,
766 video_resource_updater->YuvResourceFormat(8), color_space, y_pixels);
767
768 // U goes in the R component and V goes in the G component.
769 uint32_t rgba_pixel = (u << 24) | (v << 16);
770 std::vector<uint32_t> uv_pixels(uv_tex_size.GetArea(), rgba_pixel);
771 ResourceId resource_u = CreateGpuResource(
772 child_context_provider, child_resource_provider, uv_tex_size, RGBA_8888,
773 color_space, MakePixelSpan(uv_pixels));
774 ResourceId resource_v = resource_u;
775 ResourceId resource_a = 0;
776
777 // Transfer resources to the parent, and get the resource map.
778 std::unordered_map<ResourceId, ResourceId> resource_map =
779 cc::SendResourceAndGetChildToParentMap(
780 {resource_y, resource_u, resource_v}, resource_provider,
781 child_resource_provider, child_context_provider.get());
782
783 ResourceId mapped_resource_y = resource_map[resource_y];
784 ResourceId mapped_resource_u = resource_map[resource_u];
785 ResourceId mapped_resource_v = resource_map[resource_v];
786
787 gfx::RectF ya_tex_coord_rect(tex_coord_rect.x() * ya_tex_size.width(),
788 tex_coord_rect.y() * ya_tex_size.height(),
789 tex_coord_rect.width() * ya_tex_size.width(),
790 tex_coord_rect.height() * ya_tex_size.height());
791 gfx::RectF uv_tex_coord_rect(tex_coord_rect.x() * uv_tex_size.width(),
792 tex_coord_rect.y() * uv_tex_size.height(),
793 tex_coord_rect.width() * uv_tex_size.width(),
794 tex_coord_rect.height() * uv_tex_size.height());
795
796 auto* yuv_quad = render_pass->CreateAndAppendDrawQuad<YUVVideoDrawQuad>();
797 yuv_quad->SetNew(shared_state, rect, visible_rect, needs_blending,
798 ya_tex_coord_rect, uv_tex_coord_rect, ya_tex_size,
799 uv_tex_size, mapped_resource_y, mapped_resource_u,
800 mapped_resource_v, resource_a, color_space, 0.0f, 1.0f, 8);
801 }
802
CreateTestY16TextureDrawQuad_TwoColor(const SharedQuadState * shared_state,const gfx::RectF & tex_coord_rect,uint8_t g_foreground,uint8_t g_background,AggregatedRenderPass * render_pass,media::VideoResourceUpdater * video_resource_updater,const gfx::Rect & rect,const gfx::Rect & visible_rect,const gfx::Rect & foreground_rect,DisplayResourceProvider * resource_provider,ClientResourceProvider * child_resource_provider,ContextProvider * child_context_provider)803 void CreateTestY16TextureDrawQuad_TwoColor(
804 const SharedQuadState* shared_state,
805 const gfx::RectF& tex_coord_rect,
806 uint8_t g_foreground,
807 uint8_t g_background,
808 AggregatedRenderPass* render_pass,
809 media::VideoResourceUpdater* video_resource_updater,
810 const gfx::Rect& rect,
811 const gfx::Rect& visible_rect,
812 const gfx::Rect& foreground_rect,
813 DisplayResourceProvider* resource_provider,
814 ClientResourceProvider* child_resource_provider,
815 ContextProvider* child_context_provider) {
816 std::unique_ptr<unsigned char, base::AlignedFreeDeleter> memory(
817 static_cast<unsigned char*>(
818 base::AlignedAlloc(rect.size().GetArea() * 2,
819 media::VideoFrame::kFrameAddressAlignment)));
820 scoped_refptr<media::VideoFrame> video_frame =
821 media::VideoFrame::WrapExternalData(
822 media::PIXEL_FORMAT_Y16, rect.size(), visible_rect,
823 visible_rect.size(), memory.get(), rect.size().GetArea() * 2,
824 base::TimeDelta());
825 DCHECK_EQ(video_frame->rows(0) % 2, 0);
826 DCHECK_EQ(video_frame->stride(0) % 2, 0);
827
828 for (int j = 0; j < video_frame->rows(0); ++j) {
829 uint8_t* row = video_frame->data(0) + j * video_frame->stride(0);
830 if (j < foreground_rect.y() || j >= foreground_rect.bottom()) {
831 for (int i = 0; i < video_frame->stride(0) / 2; ++i) {
832 *row++ = i & 0xFF; // Fill R with anything. It is not rendered.
833 *row++ = g_background;
834 }
835 } else {
836 for (int i = 0;
837 i < std::min(video_frame->stride(0) / 2, foreground_rect.x()); ++i) {
838 *row++ = i & 0xFF;
839 *row++ = g_background;
840 }
841 for (int i = foreground_rect.x();
842 i < std::min(video_frame->stride(0) / 2, foreground_rect.right());
843 ++i) {
844 *row++ = i & 0xFF;
845 *row++ = g_foreground;
846 }
847 for (int i = foreground_rect.right(); i < video_frame->stride(0) / 2;
848 ++i) {
849 *row++ = i & 0xFF;
850 *row++ = g_background;
851 }
852 }
853 }
854
855 CreateTestY16TextureDrawQuad_FromVideoFrame(
856 shared_state, video_frame, tex_coord_rect, render_pass,
857 video_resource_updater, rect, visible_rect, resource_provider,
858 child_resource_provider, child_context_provider);
859 }
860
861 // Create two quads of specified colors on half-pixel boundaries.
CreateTestAxisAlignedQuads(const gfx::Rect & rect,SkColor front_color,SkColor back_color,bool needs_blending,bool force_aa_off,AggregatedRenderPass * pass)862 void CreateTestAxisAlignedQuads(const gfx::Rect& rect,
863 SkColor front_color,
864 SkColor back_color,
865 bool needs_blending,
866 bool force_aa_off,
867 AggregatedRenderPass* pass) {
868 gfx::Transform front_quad_to_target_transform;
869 front_quad_to_target_transform.Translate(50, 50);
870 front_quad_to_target_transform.Scale(0.5f + 1.0f / (rect.width() * 2.0f),
871 0.5f + 1.0f / (rect.height() * 2.0f));
872 SharedQuadState* front_shared_state = CreateTestSharedQuadState(
873 front_quad_to_target_transform, rect, pass, gfx::RRectF());
874
875 auto* front = pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
876 front->SetAll(front_shared_state, rect, rect, needs_blending, front_color,
877 force_aa_off);
878
879 gfx::Transform back_quad_to_target_transform;
880 back_quad_to_target_transform.Translate(25.5f, 25.5f);
881 back_quad_to_target_transform.Scale(0.5f, 0.5f);
882 SharedQuadState* back_shared_state = CreateTestSharedQuadState(
883 back_quad_to_target_transform, rect, pass, gfx::RRectF());
884
885 auto* back = pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
886 back->SetAll(back_shared_state, rect, rect, needs_blending, back_color,
887 force_aa_off);
888 }
889
890 using RendererPixelTest = VizPixelTestWithParam;
891 INSTANTIATE_TEST_SUITE_P(,
892 RendererPixelTest,
893 testing::ValuesIn(GetRendererTypes()),
894 testing::PrintToStringParamName());
895
896 // Test GLRenderer as well as SkiaRenderer.
897 using GPURendererPixelTest = VizPixelTestWithParam;
898 INSTANTIATE_TEST_SUITE_P(,
899 GPURendererPixelTest,
900 // TODO(crbug.com/1021566): Enable these tests for
901 // SkiaRenderer Dawn once video is supported.
902 testing::ValuesIn(GetGpuRendererTypesNoDawn()),
903 testing::PrintToStringParamName());
904
905 // Provides an exact comparator for GLRenderer and fuzzy comparator for Skia
906 // based (eg. SoftwareRenderer and SkiaRenderer).
907 class FuzzyForSkiaOnlyPixelComparator : public cc::PixelComparator {
908 public:
FuzzyForSkiaOnlyPixelComparator(RendererType type)909 explicit FuzzyForSkiaOnlyPixelComparator(RendererType type) {
910 if (type == RendererType::kGL) {
911 comparator_ = std::make_unique<cc::ExactPixelComparator>(false);
912 } else {
913 comparator_ = std::make_unique<cc::FuzzyPixelOffByOneComparator>(false);
914 }
915 }
916
Compare(const SkBitmap & actual_bmp,const SkBitmap & expected_bmp) const917 bool Compare(const SkBitmap& actual_bmp,
918 const SkBitmap& expected_bmp) const override {
919 return comparator_->Compare(actual_bmp, expected_bmp);
920 }
921
922 private:
923 std::unique_ptr<cc::PixelComparator> comparator_;
924 };
925
TEST_P(RendererPixelTest,SimpleGreenRect)926 TEST_P(RendererPixelTest, SimpleGreenRect) {
927 gfx::Rect rect(this->device_viewport_size_);
928
929 AggregatedRenderPassId id{1};
930 auto pass = CreateTestRootRenderPass(id, rect);
931
932 SharedQuadState* shared_state = CreateTestSharedQuadState(
933 gfx::Transform(), rect, pass.get(), gfx::RRectF());
934
935 auto* color_quad = pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
936 color_quad->SetNew(shared_state, rect, rect, SK_ColorGREEN, false);
937
938 AggregatedRenderPassList pass_list;
939 pass_list.push_back(std::move(pass));
940
941 EXPECT_TRUE(this->RunPixelTest(&pass_list,
942 base::FilePath(FILE_PATH_LITERAL("green.png")),
943 cc::ExactPixelComparator(true)));
944 }
945
TEST_P(RendererPixelTest,SimpleGreenRectNonRootRenderPass)946 TEST_P(RendererPixelTest, SimpleGreenRectNonRootRenderPass) {
947 gfx::Rect rect(this->device_viewport_size_);
948 gfx::Rect small_rect(100, 100);
949
950 AggregatedRenderPassId child_id{2};
951 auto child_pass =
952 CreateTestRenderPass(child_id, small_rect, gfx::Transform());
953
954 SharedQuadState* child_shared_state = CreateTestSharedQuadState(
955 gfx::Transform(), small_rect, child_pass.get(), gfx::RRectF());
956
957 auto* color_quad = child_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
958 color_quad->SetNew(child_shared_state, rect, rect, SK_ColorGREEN, false);
959
960 AggregatedRenderPassId root_id{1};
961 auto root_pass = CreateTestRenderPass(root_id, rect, gfx::Transform());
962
963 SharedQuadState* root_shared_state = CreateTestSharedQuadState(
964 gfx::Transform(), rect, root_pass.get(), gfx::RRectF());
965
966 CreateTestRenderPassDrawQuad(root_shared_state, small_rect, child_id,
967 root_pass.get());
968
969 auto* child_pass_ptr = child_pass.get();
970
971 AggregatedRenderPassList pass_list;
972 pass_list.push_back(std::move(child_pass));
973 pass_list.push_back(std::move(root_pass));
974
975 EXPECT_TRUE(this->RunPixelTestWithReadbackTarget(
976 &pass_list, child_pass_ptr,
977 base::FilePath(FILE_PATH_LITERAL("green_small.png")),
978 cc::ExactPixelComparator(true)));
979 }
980
TEST_P(RendererPixelTest,PremultipliedTextureWithoutBackground)981 TEST_P(RendererPixelTest, PremultipliedTextureWithoutBackground) {
982 gfx::Rect rect(this->device_viewport_size_);
983
984 AggregatedRenderPassId id{1};
985 auto pass = CreateTestRootRenderPass(id, rect);
986
987 SharedQuadState* shared_state = CreateTestSharedQuadState(
988 gfx::Transform(), rect, pass.get(), gfx::RRectF());
989
990 CreateTestTextureDrawQuad(
991 !is_software_renderer(), gfx::Rect(this->device_viewport_size_),
992 SkColorSetARGB(128, 0, 255, 0), // Texel color.
993 SK_ColorTRANSPARENT, // Background color.
994 true, // Premultiplied alpha.
995 shared_state, this->resource_provider_.get(),
996 this->child_resource_provider_.get(), this->shared_bitmap_manager_.get(),
997 this->child_context_provider_, pass.get());
998
999 auto* color_quad = pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
1000 color_quad->SetNew(shared_state, rect, rect, SK_ColorWHITE, false);
1001
1002 AggregatedRenderPassList pass_list;
1003 pass_list.push_back(std::move(pass));
1004
1005 EXPECT_TRUE(this->RunPixelTest(
1006 &pass_list, base::FilePath(FILE_PATH_LITERAL("green_alpha.png")),
1007 cc::FuzzyPixelOffByOneComparator(true)));
1008 }
1009
TEST_P(RendererPixelTest,PremultipliedTextureWithBackground)1010 TEST_P(RendererPixelTest, PremultipliedTextureWithBackground) {
1011 gfx::Rect rect(this->device_viewport_size_);
1012
1013 AggregatedRenderPassId id{1};
1014 auto pass = CreateTestRootRenderPass(id, rect);
1015
1016 SharedQuadState* texture_quad_state = CreateTestSharedQuadState(
1017 gfx::Transform(), rect, pass.get(), gfx::RRectF());
1018 texture_quad_state->opacity = 0.8f;
1019
1020 CreateTestTextureDrawQuad(
1021 !is_software_renderer(), gfx::Rect(this->device_viewport_size_),
1022 SkColorSetARGB(204, 120, 255, 120), // Texel color.
1023 SK_ColorGREEN, // Background color.
1024 true, // Premultiplied alpha.
1025 texture_quad_state, this->resource_provider_.get(),
1026 this->child_resource_provider_.get(), this->shared_bitmap_manager_.get(),
1027 this->child_context_provider_, pass.get());
1028
1029 SharedQuadState* color_quad_state = CreateTestSharedQuadState(
1030 gfx::Transform(), rect, pass.get(), gfx::RRectF());
1031 auto* color_quad = pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
1032 color_quad->SetNew(color_quad_state, rect, rect, SK_ColorWHITE, false);
1033
1034 AggregatedRenderPassList pass_list;
1035 pass_list.push_back(std::move(pass));
1036
1037 EXPECT_TRUE(this->RunPixelTest(
1038 &pass_list, base::FilePath(FILE_PATH_LITERAL("green_alpha.png")),
1039 cc::FuzzyPixelOffByOneComparator(true)));
1040 }
1041
TEST_P(RendererPixelTest,TextureDrawQuadVisibleRectInsetTopLeft)1042 TEST_P(RendererPixelTest, TextureDrawQuadVisibleRectInsetTopLeft) {
1043 gfx::Rect rect(this->device_viewport_size_);
1044
1045 AggregatedRenderPassId id{1};
1046 auto pass = CreateTestRootRenderPass(id, rect);
1047
1048 SharedQuadState* texture_quad_state = CreateTestSharedQuadState(
1049 gfx::Transform(), rect, pass.get(), gfx::RRectF());
1050
1051 CreateTestTwoColoredTextureDrawQuad(
1052 !is_software_renderer(), gfx::Rect(this->device_viewport_size_),
1053 SkColorSetARGB(0, 120, 255, 255), // Texel color 1.
1054 SkColorSetARGB(204, 120, 0, 255), // Texel color 2.
1055 SK_ColorGREEN, // Background color.
1056 true, // Premultiplied alpha.
1057 false, // flipped_texture_quad.
1058 false, // Half and half.
1059 texture_quad_state, this->resource_provider_.get(),
1060 this->child_resource_provider_.get(), this->shared_bitmap_manager_.get(),
1061 this->child_context_provider_, pass.get());
1062 pass->quad_list.front()->visible_rect.Inset(30, 50, 0, 0);
1063 SharedQuadState* color_quad_state = CreateTestSharedQuadState(
1064 gfx::Transform(), rect, pass.get(), gfx::RRectF());
1065 auto* color_quad = pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
1066 color_quad->SetNew(color_quad_state, rect, rect, SK_ColorWHITE, false);
1067
1068 AggregatedRenderPassList pass_list;
1069 pass_list.push_back(std::move(pass));
1070
1071 EXPECT_TRUE(this->RunPixelTest(
1072 &pass_list, base::FilePath(FILE_PATH_LITERAL("inset_top_left.png")),
1073 cc::FuzzyPixelOffByOneComparator(true)));
1074 }
1075
1076 // This tests drawing a TextureDrawQuad with a visible_rect strictly included in
1077 // rect, custom UVs, and rect.origin() that is not in the origin.
TEST_P(RendererPixelTest,TextureDrawQuadTranslatedAndVisibleRectInsetTopLeftAndCustomUV)1078 TEST_P(RendererPixelTest,
1079 TextureDrawQuadTranslatedAndVisibleRectInsetTopLeftAndCustomUV) {
1080 gfx::Rect rect(this->device_viewport_size_);
1081
1082 AggregatedRenderPassId id{1};
1083 auto pass = CreateTestRootRenderPass(id, rect);
1084
1085 SharedQuadState* texture_quad_state = CreateTestSharedQuadState(
1086 gfx::Transform(), rect, pass.get(), gfx::RRectF());
1087
1088 CreateTestTwoColoredTextureDrawQuad(
1089 !is_software_renderer(), gfx::Rect(this->device_viewport_size_),
1090 SkColorSetARGB(0, 120, 255, 255), // Texel color 1.
1091 SkColorSetARGB(204, 120, 0, 255), // Texel color 2.
1092 SK_ColorGREEN, // Background color.
1093 true, // Premultiplied alpha.
1094 false, // flipped_texture_quad.
1095 false, // Half and half.
1096 texture_quad_state, this->resource_provider_.get(),
1097 this->child_resource_provider_.get(), this->shared_bitmap_manager_.get(),
1098 this->child_context_provider_, pass.get());
1099 auto* quad = static_cast<TextureDrawQuad*>(pass->quad_list.front());
1100 quad->rect.Offset(10, 10);
1101 quad->visible_rect.Offset(10, 10);
1102 quad->visible_rect.Inset(30, 50, 12, 12);
1103 quad->uv_top_left.SetPoint(.2, .3);
1104 quad->uv_bottom_right.SetPoint(.4, .7);
1105 quad->nearest_neighbor = true; // To avoid bilinear filter differences.
1106 SharedQuadState* color_quad_state = CreateTestSharedQuadState(
1107 gfx::Transform(), rect, pass.get(), gfx::RRectF());
1108 auto* color_quad = pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
1109 color_quad->SetNew(color_quad_state, rect, rect, SK_ColorWHITE, false);
1110
1111 AggregatedRenderPassList pass_list;
1112 pass_list.push_back(std::move(pass));
1113
1114 EXPECT_TRUE(this->RunPixelTest(
1115 &pass_list,
1116 base::FilePath(FILE_PATH_LITERAL("offset_inset_top_left.png")),
1117 cc::FuzzyPixelOffByOneComparator(true)));
1118 }
1119
TEST_P(RendererPixelTest,TextureDrawQuadVisibleRectInsetBottomRight)1120 TEST_P(RendererPixelTest, TextureDrawQuadVisibleRectInsetBottomRight) {
1121 gfx::Rect rect(this->device_viewport_size_);
1122
1123 AggregatedRenderPassId id{1};
1124 auto pass = CreateTestRootRenderPass(id, rect);
1125
1126 SharedQuadState* texture_quad_state = CreateTestSharedQuadState(
1127 gfx::Transform(), rect, pass.get(), gfx::RRectF());
1128
1129 CreateTestTwoColoredTextureDrawQuad(
1130 !is_software_renderer(), gfx::Rect(this->device_viewport_size_),
1131 SkColorSetARGB(0, 120, 255, 255), // Texel color 1.
1132 SkColorSetARGB(204, 120, 0, 255), // Texel color 2.
1133 SK_ColorGREEN, // Background color.
1134 true, // Premultiplied alpha.
1135 false, // flipped_texture_quad.
1136 false, // Half and half.
1137 texture_quad_state, this->resource_provider_.get(),
1138 this->child_resource_provider_.get(), this->shared_bitmap_manager_.get(),
1139 this->child_context_provider_, pass.get());
1140 pass->quad_list.front()->visible_rect.Inset(0, 0, 40, 60);
1141 SharedQuadState* color_quad_state = CreateTestSharedQuadState(
1142 gfx::Transform(), rect, pass.get(), gfx::RRectF());
1143 auto* color_quad = pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
1144 color_quad->SetNew(color_quad_state, rect, rect, SK_ColorWHITE, false);
1145
1146 AggregatedRenderPassList pass_list;
1147 pass_list.push_back(std::move(pass));
1148
1149 EXPECT_TRUE(this->RunPixelTest(
1150 &pass_list, base::FilePath(FILE_PATH_LITERAL("inset_bottom_right.png")),
1151 cc::FuzzyPixelOffByOneComparator(true)));
1152 }
1153
TEST_P(GPURendererPixelTest,SolidColorBlend)1154 TEST_P(GPURendererPixelTest, SolidColorBlend) {
1155 gfx::Rect rect(this->device_viewport_size_);
1156
1157 AggregatedRenderPassId id{1};
1158 auto pass = CreateTestRootRenderPass(id, rect);
1159 pass->has_transparent_background = false;
1160
1161 SharedQuadState* shared_state = CreateTestSharedQuadState(
1162 gfx::Transform(), rect, pass.get(), gfx::RRectF());
1163 shared_state->opacity = 1 - 16.0f / 255;
1164 shared_state->blend_mode = SkBlendMode::kDstOut;
1165
1166 auto* color_quad = pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
1167 color_quad->SetNew(shared_state, rect, rect, SK_ColorRED, false);
1168
1169 SharedQuadState* shared_state_background = CreateTestSharedQuadState(
1170 gfx::Transform(), rect, pass.get(), gfx::RRectF());
1171
1172 SkColor background_color = SkColorSetRGB(0xff, 0xff * 14 / 16, 0xff);
1173 auto* color_quad_background =
1174 pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
1175 color_quad_background->SetNew(shared_state_background, rect, rect,
1176 background_color, false);
1177 // Result should be r=16, g=14, b=16.
1178
1179 AggregatedRenderPassList pass_list;
1180 pass_list.push_back(std::move(pass));
1181
1182 EXPECT_TRUE(this->RunPixelTest(
1183 &pass_list, base::FilePath(FILE_PATH_LITERAL("dark_grey.png")),
1184 cc::FuzzyPixelOffByOneComparator(/*discard_alpha=*/true)));
1185 }
1186
TEST_P(GPURendererPixelTest,SolidColorWithTemperature)1187 TEST_P(GPURendererPixelTest, SolidColorWithTemperature) {
1188 gfx::Rect rect(this->device_viewport_size_);
1189
1190 AggregatedRenderPassId id{1};
1191 auto pass = CreateTestRootRenderPass(id, rect);
1192
1193 SharedQuadState* shared_state = CreateTestSharedQuadState(
1194 gfx::Transform(), rect, pass.get(), gfx::RRectF());
1195
1196 auto* color_quad = pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
1197 color_quad->SetNew(shared_state, rect, rect, SK_ColorYELLOW, false);
1198
1199 AggregatedRenderPassList pass_list;
1200 pass_list.push_back(std::move(pass));
1201
1202 SkMatrix44 color_matrix(SkMatrix44::kIdentity_Constructor);
1203 color_matrix.set(0, 0, 0.7f);
1204 color_matrix.set(1, 1, 0.4f);
1205 color_matrix.set(2, 2, 0.5f);
1206 this->output_surface_->set_color_matrix(color_matrix);
1207
1208 EXPECT_TRUE(this->RunPixelTest(
1209 &pass_list, base::FilePath(FILE_PATH_LITERAL("temperature_brown.png")),
1210 cc::FuzzyPixelOffByOneComparator(true)));
1211 }
1212
TEST_P(GPURendererPixelTest,SolidColorWithTemperatureNonRootRenderPass)1213 TEST_P(GPURendererPixelTest, SolidColorWithTemperatureNonRootRenderPass) {
1214 // Create a root and a child passes with two different solid color quads.
1215 AggregatedRenderPassList render_passes_in_draw_order;
1216 gfx::Rect viewport_rect(this->device_viewport_size_);
1217 gfx::Rect root_rect(0, 0, viewport_rect.width(), viewport_rect.height() / 2);
1218 gfx::Rect child_rect(0, root_rect.bottom(), viewport_rect.width(),
1219 root_rect.height());
1220
1221 // Child pass.
1222 AggregatedRenderPassId child_pass_id{2};
1223 AggregatedRenderPass* child_pass = cc::AddRenderPass(
1224 &render_passes_in_draw_order, child_pass_id, viewport_rect,
1225 gfx::Transform(), cc::FilterOperations());
1226 cc::AddQuad(child_pass, child_rect, SK_ColorGREEN);
1227
1228 // Root pass.
1229 AggregatedRenderPassId root_pass_id{1};
1230 AggregatedRenderPass* root_pass = cc::AddRenderPass(
1231 &render_passes_in_draw_order, root_pass_id, viewport_rect,
1232 gfx::Transform(), cc::FilterOperations());
1233 cc::AddQuad(root_pass, root_rect, SK_ColorYELLOW);
1234
1235 SharedQuadState* pass_shared_state = CreateTestSharedQuadState(
1236 gfx::Transform(), viewport_rect, root_pass, gfx::RRectF());
1237 CreateTestRenderPassDrawQuad(pass_shared_state, viewport_rect, child_pass_id,
1238 root_pass);
1239
1240 // Set a non-identity output color matrix on the output surface, and expect
1241 // that the colors will be transformed.
1242 SkMatrix44 color_matrix(SkMatrix44::kIdentity_Constructor);
1243 color_matrix.set(0, 0, 0.7f);
1244 color_matrix.set(1, 1, 0.4f);
1245 color_matrix.set(2, 2, 0.5f);
1246 this->output_surface_->set_color_matrix(color_matrix);
1247
1248 EXPECT_TRUE(this->RunPixelTest(
1249 &render_passes_in_draw_order,
1250 base::FilePath(FILE_PATH_LITERAL("temperature_brown_non_root.png")),
1251 cc::FuzzyPixelOffByOneComparator(true)));
1252 }
1253
TEST_P(GPURendererPixelTest,PremultipliedTextureWithBackgroundAndVertexOpacity)1254 TEST_P(GPURendererPixelTest,
1255 PremultipliedTextureWithBackgroundAndVertexOpacity) {
1256 gfx::Rect rect(this->device_viewport_size_);
1257
1258 AggregatedRenderPassId id{1};
1259 auto pass = CreateTestRootRenderPass(id, rect);
1260
1261 SharedQuadState* texture_quad_state = CreateTestSharedQuadState(
1262 gfx::Transform(), rect, pass.get(), gfx::RRectF());
1263 texture_quad_state->opacity = 0.8f;
1264
1265 float vertex_opacity[4] = {1.f, 1.f, 0.f, 0.f};
1266 CreateTestTextureDrawQuad(
1267 !is_software_renderer(), gfx::Rect(this->device_viewport_size_),
1268 SkColorSetARGB(204, 120, 255, 120), // Texel color.
1269 vertex_opacity,
1270 SK_ColorGREEN, // Background color.
1271 true, // Premultiplied alpha.
1272 texture_quad_state, this->resource_provider_.get(),
1273 this->child_resource_provider_.get(), this->shared_bitmap_manager_.get(),
1274 this->child_context_provider_, pass.get());
1275
1276 SharedQuadState* color_quad_state = CreateTestSharedQuadState(
1277 gfx::Transform(), rect, pass.get(), gfx::RRectF());
1278 auto* color_quad = pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
1279 color_quad->SetNew(color_quad_state, rect, rect, SK_ColorWHITE, false);
1280
1281 AggregatedRenderPassList pass_list;
1282 pass_list.push_back(std::move(pass));
1283
1284 EXPECT_TRUE(this->RunPixelTest(
1285 &pass_list,
1286 base::FilePath(FILE_PATH_LITERAL("green_alpha_vertex_opacity.png")),
1287 cc::FuzzyPixelOffByOneComparator(true)));
1288 }
1289
1290 class IntersectingQuadPixelTest : public VizPixelTestWithParam {
1291 protected:
SetupQuadStateAndRenderPass()1292 void SetupQuadStateAndRenderPass() {
1293 // This sets up a pair of draw quads. They are both rotated
1294 // relative to the root plane, they are also rotated relative to each other.
1295 // The intersect in the middle at a non-perpendicular angle so that any
1296 // errors are hopefully magnified.
1297 // The quads should intersect correctly, as in the front quad should only
1298 // be partially in front of the back quad, and partially behind.
1299
1300 viewport_rect_ = gfx::Rect(this->device_viewport_size_);
1301 quad_rect_ = gfx::Rect(0, 0, this->device_viewport_size_.width(),
1302 this->device_viewport_size_.height() / 2.0);
1303
1304 AggregatedRenderPassId id{1};
1305 render_pass_ = CreateTestRootRenderPass(id, viewport_rect_);
1306
1307 // Create the front quad rotated on the Z and Y axis.
1308 gfx::Transform trans;
1309 trans.Translate3d(0, 0, 0.707 * this->device_viewport_size_.width() / 2.0);
1310 trans.RotateAboutZAxis(45.0);
1311 trans.RotateAboutYAxis(45.0);
1312 front_quad_state_ = CreateTestSharedQuadState(
1313 trans, viewport_rect_, render_pass_.get(), gfx::RRectF());
1314 front_quad_state_->clip_rect = quad_rect_;
1315 // Make sure they end up in a 3d sorting context.
1316 front_quad_state_->sorting_context_id = 1;
1317
1318 // Create the back quad, and rotate on just the y axis. This will intersect
1319 // the first quad partially.
1320 trans = gfx::Transform();
1321 trans.Translate3d(0, 0, -0.707 * this->device_viewport_size_.width() / 2.0);
1322 trans.RotateAboutYAxis(-45.0);
1323 back_quad_state_ = CreateTestSharedQuadState(
1324 trans, viewport_rect_, render_pass_.get(), gfx::RRectF());
1325 back_quad_state_->sorting_context_id = 1;
1326 back_quad_state_->clip_rect = quad_rect_;
1327 }
AppendBackgroundAndRunTest(const cc::PixelComparator & comparator,const base::FilePath::CharType * ref_file)1328 void AppendBackgroundAndRunTest(const cc::PixelComparator& comparator,
1329 const base::FilePath::CharType* ref_file) {
1330 SharedQuadState* background_quad_state = CreateTestSharedQuadState(
1331 gfx::Transform(), viewport_rect_, render_pass_.get(), gfx::RRectF());
1332 auto* background_quad =
1333 render_pass_->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
1334 background_quad->SetNew(background_quad_state, viewport_rect_,
1335 viewport_rect_, SK_ColorWHITE, false);
1336 pass_list_.push_back(std::move(render_pass_));
1337 EXPECT_TRUE(
1338 this->RunPixelTest(&pass_list_, base::FilePath(ref_file), comparator));
1339 }
1340 template <typename T>
CreateAndAppendDrawQuad()1341 T* CreateAndAppendDrawQuad() {
1342 return render_pass_->CreateAndAppendDrawQuad<T>();
1343 }
1344
1345 std::unique_ptr<AggregatedRenderPass> render_pass_;
1346 gfx::Rect viewport_rect_;
1347 SharedQuadState* front_quad_state_;
1348 SharedQuadState* back_quad_state_;
1349 gfx::Rect quad_rect_;
1350 AggregatedRenderPassList pass_list_;
1351 };
1352
1353 INSTANTIATE_TEST_SUITE_P(,
1354 IntersectingQuadPixelTest,
1355 testing::ValuesIn(GetRendererTypes()),
1356 testing::PrintToStringParamName());
1357
1358 class IntersectingVideoQuadPixelTest : public IntersectingQuadPixelTest {
1359 public:
SetUp()1360 void SetUp() override {
1361 IntersectingQuadPixelTest::SetUp();
1362 constexpr bool kUseStreamVideoDrawQuad = false;
1363 constexpr bool kUseGpuMemoryBufferResources = false;
1364 constexpr bool kUseR16Texture = false;
1365 constexpr int kMaxResourceSize = 10000;
1366
1367 video_resource_updater_ = std::make_unique<media::VideoResourceUpdater>(
1368 this->child_context_provider_.get(),
1369 /*raster_context_provider=*/nullptr, nullptr,
1370 this->child_resource_provider_.get(), kUseStreamVideoDrawQuad,
1371 kUseGpuMemoryBufferResources, kUseR16Texture, kMaxResourceSize);
1372 video_resource_updater2_ = std::make_unique<media::VideoResourceUpdater>(
1373 this->child_context_provider_.get(),
1374 /*raster_context_provider=*/nullptr, nullptr,
1375 this->child_resource_provider_.get(), kUseStreamVideoDrawQuad,
1376 kUseGpuMemoryBufferResources, kUseR16Texture, kMaxResourceSize);
1377 }
1378
1379 protected:
1380 std::unique_ptr<media::VideoResourceUpdater> video_resource_updater_;
1381 std::unique_ptr<media::VideoResourceUpdater> video_resource_updater2_;
1382 };
1383
1384 INSTANTIATE_TEST_SUITE_P(,
1385 IntersectingVideoQuadPixelTest,
1386 // TODO(crbug.com/1021566): Enable these tests for
1387 // SkiaRenderer Dawn once video is supported.
1388 testing::ValuesIn(GetGpuRendererTypesNoDawn()),
1389 testing::PrintToStringParamName());
1390
1391 class IntersectingQuadSoftwareTest : public IntersectingQuadPixelTest {};
1392
1393 INSTANTIATE_TEST_SUITE_P(,
1394 IntersectingQuadSoftwareTest,
1395 testing::Values(RendererType::kSoftware),
1396 testing::PrintToStringParamName());
1397
TEST_P(IntersectingQuadPixelTest,SolidColorQuads)1398 TEST_P(IntersectingQuadPixelTest, SolidColorQuads) {
1399 // TODO(crbug.com/1021566): Enable this test for SkiaRenderer Dawn.
1400 if (renderer_type() == RendererType::kSkiaDawn)
1401 return;
1402
1403 this->SetupQuadStateAndRenderPass();
1404
1405 auto* quad = this->template CreateAndAppendDrawQuad<SolidColorDrawQuad>();
1406 auto* quad2 = this->template CreateAndAppendDrawQuad<SolidColorDrawQuad>();
1407
1408 quad->SetNew(this->front_quad_state_, this->quad_rect_, this->quad_rect_,
1409 SK_ColorBLUE, false);
1410 quad2->SetNew(this->back_quad_state_, this->quad_rect_, this->quad_rect_,
1411 SK_ColorGREEN, false);
1412 this->AppendBackgroundAndRunTest(
1413 cc::FuzzyPixelComparator(false, 2.f, 0.f, 256.f, 256, 0.f),
1414 FILE_PATH_LITERAL("intersecting_blue_green.png"));
1415 }
1416
TEST_P(IntersectingQuadPixelTest,TexturedQuads)1417 TEST_P(IntersectingQuadPixelTest, TexturedQuads) {
1418 this->SetupQuadStateAndRenderPass();
1419 CreateTestTwoColoredTextureDrawQuad(
1420 !is_software_renderer(), this->quad_rect_, SkColorSetARGB(255, 0, 0, 0),
1421 SkColorSetARGB(255, 0, 0, 255), SK_ColorTRANSPARENT,
1422 true /* premultiplied_alpha */, false /* flipped_texture_quad */,
1423 false /* half_and_half */, this->front_quad_state_,
1424 this->resource_provider_.get(), this->child_resource_provider_.get(),
1425 this->shared_bitmap_manager_.get(), this->child_context_provider_,
1426 this->render_pass_.get());
1427 CreateTestTwoColoredTextureDrawQuad(
1428 !is_software_renderer(), this->quad_rect_, SkColorSetARGB(255, 0, 255, 0),
1429 SkColorSetARGB(255, 0, 0, 0), SK_ColorTRANSPARENT,
1430 true /* premultiplied_alpha */, false /* flipped_texture_quad */,
1431 false /* half_and_half */, this->back_quad_state_,
1432 this->resource_provider_.get(), this->child_resource_provider_.get(),
1433 this->shared_bitmap_manager_.get(), this->child_context_provider_,
1434 this->render_pass_.get());
1435
1436 this->AppendBackgroundAndRunTest(
1437 cc::FuzzyPixelComparator(false, 2.f, 0.f, 256.f, 256, 0.f),
1438 FILE_PATH_LITERAL("intersecting_blue_green_squares.png"));
1439 }
1440
TEST_P(IntersectingQuadPixelTest,NonFlippedTexturedQuads)1441 TEST_P(IntersectingQuadPixelTest, NonFlippedTexturedQuads) {
1442 this->SetupQuadStateAndRenderPass();
1443 CreateTestTwoColoredTextureDrawQuad(
1444 !is_software_renderer(), this->quad_rect_, SkColorSetARGB(255, 0, 0, 0),
1445 SkColorSetARGB(255, 0, 0, 255), SK_ColorTRANSPARENT,
1446 true /* premultiplied_alpha */, false /* flipped_texture_quad */,
1447 true /* half_and_half */, this->front_quad_state_,
1448 this->resource_provider_.get(), this->child_resource_provider_.get(),
1449 this->shared_bitmap_manager_.get(), this->child_context_provider_,
1450 this->render_pass_.get());
1451 CreateTestTwoColoredTextureDrawQuad(
1452 !is_software_renderer(), this->quad_rect_, SkColorSetARGB(255, 0, 255, 0),
1453 SkColorSetARGB(255, 0, 0, 0), SK_ColorTRANSPARENT,
1454 true /* premultiplied_alpha */, false /* flipped_texture_quad */,
1455 true /* half_and_half */, this->back_quad_state_,
1456 this->resource_provider_.get(), this->child_resource_provider_.get(),
1457 this->shared_bitmap_manager_.get(), this->child_context_provider_,
1458 this->render_pass_.get());
1459
1460 this->AppendBackgroundAndRunTest(
1461 cc::FuzzyPixelComparator(false, 2.f, 0.f, 256.f, 256, 0.f),
1462 FILE_PATH_LITERAL(
1463 "intersecting_non_flipped_blue_green_half_size_rectangles.png"));
1464 }
1465
TEST_P(IntersectingQuadPixelTest,FlippedTexturedQuads)1466 TEST_P(IntersectingQuadPixelTest, FlippedTexturedQuads) {
1467 this->SetupQuadStateAndRenderPass();
1468 CreateTestTwoColoredTextureDrawQuad(
1469 !is_software_renderer(), this->quad_rect_, SkColorSetARGB(255, 0, 0, 0),
1470 SkColorSetARGB(255, 0, 0, 255), SK_ColorTRANSPARENT,
1471 true /* premultiplied_alpha */, true /* flipped_texture_quad */,
1472 true /* half_and_half */, this->front_quad_state_,
1473 this->resource_provider_.get(), this->child_resource_provider_.get(),
1474 this->shared_bitmap_manager_.get(), this->child_context_provider_,
1475 this->render_pass_.get());
1476 CreateTestTwoColoredTextureDrawQuad(
1477 !is_software_renderer(), this->quad_rect_, SkColorSetARGB(255, 0, 255, 0),
1478 SkColorSetARGB(255, 0, 0, 0), SK_ColorTRANSPARENT,
1479 true /* premultiplied_alpha */, true /* flipped_texture_quad */,
1480 true /* half_and_half */, this->back_quad_state_,
1481 this->resource_provider_.get(), this->child_resource_provider_.get(),
1482 this->shared_bitmap_manager_.get(), this->child_context_provider_,
1483 this->render_pass_.get());
1484
1485 this->AppendBackgroundAndRunTest(
1486 cc::FuzzyPixelComparator(false, 2.f, 0.f, 256.f, 256, 0.f),
1487 FILE_PATH_LITERAL(
1488 "intersecting_flipped_blue_green_half_size_rectangles.png"));
1489 }
1490
TEST_P(IntersectingQuadSoftwareTest,PictureQuads)1491 TEST_P(IntersectingQuadSoftwareTest, PictureQuads) {
1492 bool needs_blending = true;
1493 this->SetupQuadStateAndRenderPass();
1494 gfx::Rect outer_rect(this->quad_rect_);
1495 gfx::Rect inner_rect(this->quad_rect_.x() + (this->quad_rect_.width() / 4),
1496 this->quad_rect_.y() + (this->quad_rect_.height() / 4),
1497 this->quad_rect_.width() / 2,
1498 this->quad_rect_.height() / 2);
1499
1500 cc::PaintFlags black_flags;
1501 black_flags.setColor(SK_ColorBLACK);
1502 cc::PaintFlags blue_flags;
1503 blue_flags.setColor(SK_ColorBLUE);
1504 cc::PaintFlags green_flags;
1505 green_flags.setColor(SK_ColorGREEN);
1506
1507 std::unique_ptr<cc::FakeRecordingSource> blue_recording =
1508 cc::FakeRecordingSource::CreateFilledRecordingSource(
1509 this->quad_rect_.size());
1510 blue_recording->add_draw_rect_with_flags(outer_rect, black_flags);
1511 blue_recording->add_draw_rect_with_flags(inner_rect, blue_flags);
1512 blue_recording->Rerecord();
1513 scoped_refptr<cc::RasterSource> blue_raster_source =
1514 blue_recording->CreateRasterSource();
1515
1516 auto* blue_quad =
1517 this->render_pass_->template CreateAndAppendDrawQuad<PictureDrawQuad>();
1518
1519 blue_quad->SetNew(this->front_quad_state_, this->quad_rect_, this->quad_rect_,
1520 needs_blending, gfx::RectF(this->quad_rect_),
1521 this->quad_rect_.size(), false, RGBA_8888, this->quad_rect_,
1522 1.f, {}, blue_raster_source->GetDisplayItemList());
1523
1524 std::unique_ptr<cc::FakeRecordingSource> green_recording =
1525 cc::FakeRecordingSource::CreateFilledRecordingSource(
1526 this->quad_rect_.size());
1527 green_recording->add_draw_rect_with_flags(outer_rect, green_flags);
1528 green_recording->add_draw_rect_with_flags(inner_rect, black_flags);
1529 green_recording->Rerecord();
1530 scoped_refptr<cc::RasterSource> green_raster_source =
1531 green_recording->CreateRasterSource();
1532
1533 auto* green_quad =
1534 this->render_pass_->template CreateAndAppendDrawQuad<PictureDrawQuad>();
1535 green_quad->SetNew(this->back_quad_state_, this->quad_rect_, this->quad_rect_,
1536 needs_blending, gfx::RectF(this->quad_rect_),
1537 this->quad_rect_.size(), false, RGBA_8888,
1538 this->quad_rect_, 1.f, {},
1539 green_raster_source->GetDisplayItemList());
1540 this->AppendBackgroundAndRunTest(
1541 cc::FuzzyPixelComparator(false, 2.f, 0.f, 256.f, 256, 0.f),
1542 FILE_PATH_LITERAL("intersecting_blue_green_squares.png"));
1543 }
1544
TEST_P(IntersectingQuadPixelTest,RenderPassQuads)1545 TEST_P(IntersectingQuadPixelTest, RenderPassQuads) {
1546 this->SetupQuadStateAndRenderPass();
1547 AggregatedRenderPassId child_pass_id1{2};
1548 AggregatedRenderPassId child_pass_id2{3};
1549 auto child_pass1 =
1550 CreateTestRenderPass(child_pass_id1, this->quad_rect_, gfx::Transform());
1551 SharedQuadState* child1_quad_state = CreateTestSharedQuadState(
1552 gfx::Transform(), this->quad_rect_, child_pass1.get(), gfx::RRectF());
1553 auto child_pass2 =
1554 CreateTestRenderPass(child_pass_id2, this->quad_rect_, gfx::Transform());
1555 SharedQuadState* child2_quad_state = CreateTestSharedQuadState(
1556 gfx::Transform(), this->quad_rect_, child_pass2.get(), gfx::RRectF());
1557 CreateTestTwoColoredTextureDrawQuad(
1558 !is_software_renderer(), this->quad_rect_, SkColorSetARGB(255, 0, 0, 0),
1559 SkColorSetARGB(255, 0, 0, 255), SK_ColorTRANSPARENT,
1560 true /* premultiplied_alpha */, false /* flipped_texture_quad */,
1561 false /* half_and_half */, child1_quad_state,
1562 this->resource_provider_.get(), this->child_resource_provider_.get(),
1563 this->shared_bitmap_manager_.get(), this->child_context_provider_,
1564 child_pass1.get());
1565 CreateTestTwoColoredTextureDrawQuad(
1566 !is_software_renderer(), this->quad_rect_, SkColorSetARGB(255, 0, 255, 0),
1567 SkColorSetARGB(255, 0, 0, 0), SK_ColorTRANSPARENT,
1568 true /* premultiplied_alpha */, false /* flipped_texture_quad */,
1569 false /* half_and_half */, child2_quad_state,
1570 this->resource_provider_.get(), this->child_resource_provider_.get(),
1571 this->shared_bitmap_manager_.get(), this->child_context_provider_,
1572 child_pass2.get());
1573
1574 CreateTestRenderPassDrawQuad(this->front_quad_state_, this->quad_rect_,
1575 child_pass_id1, this->render_pass_.get());
1576 CreateTestRenderPassDrawQuad(this->back_quad_state_, this->quad_rect_,
1577 child_pass_id2, this->render_pass_.get());
1578
1579 this->pass_list_.push_back(std::move(child_pass1));
1580 this->pass_list_.push_back(std::move(child_pass2));
1581 this->AppendBackgroundAndRunTest(
1582 cc::FuzzyPixelComparator(false, 2.f, 0.f, 256.f, 256, 0.f),
1583 FILE_PATH_LITERAL("intersecting_blue_green_squares.png"));
1584 }
1585
TEST_P(IntersectingVideoQuadPixelTest,YUVVideoQuads)1586 TEST_P(IntersectingVideoQuadPixelTest, YUVVideoQuads) {
1587 this->SetupQuadStateAndRenderPass();
1588 gfx::Rect inner_rect(
1589 ((this->quad_rect_.x() + (this->quad_rect_.width() / 4)) & ~0xF),
1590 ((this->quad_rect_.y() + (this->quad_rect_.height() / 4)) & ~0xF),
1591 (this->quad_rect_.width() / 2) & ~0xF,
1592 (this->quad_rect_.height() / 2) & ~0xF);
1593
1594 CreateTestYUVVideoDrawQuad_TwoColor(
1595 this->front_quad_state_, media::PIXEL_FORMAT_I420,
1596 gfx::ColorSpace::CreateJpeg(), false, gfx::RectF(0.0f, 0.0f, 1.0f, 1.0f),
1597 this->quad_rect_.size(), this->quad_rect_, 0, 128, 128, inner_rect, 29,
1598 255, 107, this->render_pass_.get(), this->video_resource_updater_.get(),
1599 this->resource_provider_.get(), this->child_resource_provider_.get(),
1600 this->child_context_provider_.get());
1601
1602 CreateTestYUVVideoDrawQuad_TwoColor(
1603 this->back_quad_state_, media::PIXEL_FORMAT_I420,
1604 gfx::ColorSpace::CreateJpeg(), false, gfx::RectF(0.0f, 0.0f, 1.0f, 1.0f),
1605 this->quad_rect_.size(), this->quad_rect_, 149, 43, 21, inner_rect, 0,
1606 128, 128, this->render_pass_.get(), this->video_resource_updater2_.get(),
1607 this->resource_provider_.get(), this->child_resource_provider_.get(),
1608 this->child_context_provider_.get());
1609
1610 this->AppendBackgroundAndRunTest(
1611 cc::FuzzyPixelComparator(true, 0.50f, 0.f, 1.2f, 2, 0),
1612 FILE_PATH_LITERAL("intersecting_blue_green_squares_video.png"));
1613 }
1614
TEST_P(IntersectingVideoQuadPixelTest,Y16VideoQuads)1615 TEST_P(IntersectingVideoQuadPixelTest, Y16VideoQuads) {
1616 this->SetupQuadStateAndRenderPass();
1617 gfx::Rect inner_rect(
1618 ((this->quad_rect_.x() + (this->quad_rect_.width() / 4)) & ~0xF),
1619 ((this->quad_rect_.y() + (this->quad_rect_.height() / 4)) & ~0xF),
1620 (this->quad_rect_.width() / 2) & ~0xF,
1621 (this->quad_rect_.height() / 2) & ~0xF);
1622
1623 CreateTestY16TextureDrawQuad_TwoColor(
1624 this->front_quad_state_, gfx::RectF(0.0f, 0.0f, 1.0f, 1.0f), 18, 0,
1625 this->render_pass_.get(), this->video_resource_updater_.get(),
1626 this->quad_rect_, this->quad_rect_, inner_rect,
1627 this->resource_provider_.get(), this->child_resource_provider_.get(),
1628 this->child_context_provider_.get());
1629
1630 CreateTestY16TextureDrawQuad_TwoColor(
1631 this->back_quad_state_, gfx::RectF(0.0f, 0.0f, 1.0f, 1.0f), 0, 182,
1632 this->render_pass_.get(), this->video_resource_updater2_.get(),
1633 this->quad_rect_, this->quad_rect_, inner_rect,
1634 this->resource_provider_.get(), this->child_resource_provider_.get(),
1635 this->child_context_provider_.get());
1636
1637 this->AppendBackgroundAndRunTest(
1638 cc::FuzzyPixelOffByOneComparator(false),
1639 FILE_PATH_LITERAL("intersecting_light_dark_squares_video.png"));
1640 }
1641
1642 // TODO(skaslev): The software renderer does not support non-premultplied alpha.
TEST_P(GPURendererPixelTest,NonPremultipliedTextureWithoutBackground)1643 TEST_P(GPURendererPixelTest, NonPremultipliedTextureWithoutBackground) {
1644 gfx::Rect rect(this->device_viewport_size_);
1645
1646 AggregatedRenderPassId id{1};
1647 auto pass = CreateTestRootRenderPass(id, rect);
1648
1649 SharedQuadState* shared_state = CreateTestSharedQuadState(
1650 gfx::Transform(), rect, pass.get(), gfx::RRectF());
1651
1652 CreateTestTextureDrawQuad(
1653 !is_software_renderer(), gfx::Rect(this->device_viewport_size_),
1654 SkColorSetARGB(128, 0, 255, 0), // Texel color.
1655 SK_ColorTRANSPARENT, // Background color.
1656 false, // Premultiplied alpha.
1657 shared_state, this->resource_provider_.get(),
1658 this->child_resource_provider_.get(), this->shared_bitmap_manager_.get(),
1659 this->child_context_provider_, pass.get());
1660
1661 auto* color_quad = pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
1662 color_quad->SetNew(shared_state, rect, rect, SK_ColorWHITE, false);
1663
1664 AggregatedRenderPassList pass_list;
1665 pass_list.push_back(std::move(pass));
1666
1667 EXPECT_TRUE(this->RunPixelTest(
1668 &pass_list, base::FilePath(FILE_PATH_LITERAL("green_alpha.png")),
1669 cc::FuzzyPixelOffByOneComparator(true)));
1670 }
1671
1672 // TODO(skaslev): The software renderer does not support non-premultplied alpha.
TEST_P(GPURendererPixelTest,NonPremultipliedTextureWithBackground)1673 TEST_P(GPURendererPixelTest, NonPremultipliedTextureWithBackground) {
1674 gfx::Rect rect(this->device_viewport_size_);
1675
1676 AggregatedRenderPassId id{1};
1677 auto pass = CreateTestRootRenderPass(id, rect);
1678
1679 SharedQuadState* texture_quad_state = CreateTestSharedQuadState(
1680 gfx::Transform(), rect, pass.get(), gfx::RRectF());
1681 texture_quad_state->opacity = 0.8f;
1682
1683 CreateTestTextureDrawQuad(
1684 !is_software_renderer(), gfx::Rect(this->device_viewport_size_),
1685 SkColorSetARGB(204, 120, 255, 120), // Texel color.
1686 SK_ColorGREEN, // Background color.
1687 false, // Premultiplied alpha.
1688 texture_quad_state, this->resource_provider_.get(),
1689 this->child_resource_provider_.get(), this->shared_bitmap_manager_.get(),
1690 this->child_context_provider_, pass.get());
1691
1692 SharedQuadState* color_quad_state = CreateTestSharedQuadState(
1693 gfx::Transform(), rect, pass.get(), gfx::RRectF());
1694 auto* color_quad = pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
1695 color_quad->SetNew(color_quad_state, rect, rect, SK_ColorWHITE, false);
1696
1697 AggregatedRenderPassList pass_list;
1698 pass_list.push_back(std::move(pass));
1699
1700 EXPECT_TRUE(this->RunPixelTest(
1701 &pass_list, base::FilePath(FILE_PATH_LITERAL("green_alpha.png")),
1702 cc::FuzzyPixelOffByOneComparator(true)));
1703 }
1704
1705 class VideoRendererPixelTestBase : public VizPixelTest {
1706 public:
VideoRendererPixelTestBase(RendererType type)1707 explicit VideoRendererPixelTestBase(RendererType type) : VizPixelTest(type) {}
1708
1709 protected:
1710 // Include the protected member variables from the parent class.
1711 using cc::PixelTest::child_context_provider_;
1712 using cc::PixelTest::child_resource_provider_;
1713 using cc::PixelTest::resource_provider_;
1714
CreateEdgeBleedPass(media::VideoPixelFormat format,const gfx::ColorSpace & color_space,AggregatedRenderPassList * pass_list)1715 void CreateEdgeBleedPass(media::VideoPixelFormat format,
1716 const gfx::ColorSpace& color_space,
1717 AggregatedRenderPassList* pass_list) {
1718 gfx::Rect rect(200, 200);
1719
1720 AggregatedRenderPassId id{1};
1721 auto pass = CreateTestRootRenderPass(id, rect);
1722
1723 // Scale the video up so that bilinear filtering kicks in to sample more
1724 // than just nearest neighbor would.
1725 gfx::Transform scale_by_2;
1726 scale_by_2.Scale(2.f, 2.f);
1727 gfx::Rect half_rect(100, 100);
1728 SharedQuadState* shared_state = CreateTestSharedQuadState(
1729 scale_by_2, half_rect, pass.get(), gfx::RRectF());
1730
1731 gfx::Size background_size(200, 200);
1732 gfx::Rect green_rect(16, 20, 100, 100);
1733 gfx::RectF tex_coord_rect(
1734 static_cast<float>(green_rect.x()) / background_size.width(),
1735 static_cast<float>(green_rect.y()) / background_size.height(),
1736 static_cast<float>(green_rect.width()) / background_size.width(),
1737 static_cast<float>(green_rect.height()) / background_size.height());
1738
1739 // YUV of (149,43,21) should be green (0,255,0) in RGB.
1740 // Create a video frame that has a non-green background rect, with a
1741 // green sub-rectangle that should be the only thing displayed in
1742 // the final image. Bleeding will appear on all four sides of the video
1743 // if the tex coords are not clamped.
1744 CreateTestYUVVideoDrawQuad_TwoColor(
1745 shared_state, format, color_space, false, tex_coord_rect,
1746 background_size, gfx::Rect(background_size), 128, 128, 128, green_rect,
1747 149, 43, 21, pass.get(), video_resource_updater_.get(),
1748 resource_provider_.get(), child_resource_provider_.get(),
1749 child_context_provider_.get());
1750 pass_list->push_back(std::move(pass));
1751 }
1752
SetUp()1753 void SetUp() override {
1754 VizPixelTest::SetUp();
1755 constexpr bool kUseStreamVideoDrawQuad = false;
1756 constexpr bool kUseGpuMemoryBufferResources = false;
1757 constexpr bool kUseR16Texture = false;
1758 constexpr int kMaxResourceSize = 10000;
1759 video_resource_updater_ = std::make_unique<media::VideoResourceUpdater>(
1760 child_context_provider_.get(), nullptr, nullptr,
1761 child_resource_provider_.get(), kUseStreamVideoDrawQuad,
1762 kUseGpuMemoryBufferResources, kUseR16Texture, kMaxResourceSize);
1763 }
1764
TearDown()1765 void TearDown() override {
1766 video_resource_updater_ = nullptr;
1767 VizPixelTest::TearDown();
1768 }
1769
1770 std::unique_ptr<media::VideoResourceUpdater> video_resource_updater_;
1771 };
1772
1773 #if BUILDFLAG(ENABLE_GL_BACKEND_TESTS)
1774 class VideoRendererPixelHiLoTest
1775 : public VideoRendererPixelTestBase,
1776 public testing::WithParamInterface<std::tuple<RendererType, bool>> {
1777 public:
VideoRendererPixelHiLoTest()1778 VideoRendererPixelHiLoTest()
1779 : VideoRendererPixelTestBase(std::get<0>(GetParam())) {}
1780
IsHighbit() const1781 bool IsHighbit() const { return std::get<1>(GetParam()); }
1782 };
1783
1784 INSTANTIATE_TEST_SUITE_P(
1785 ,
1786 VideoRendererPixelHiLoTest,
1787 testing::Combine(testing::Values(RendererType::kGL, RendererType::kSkiaGL),
1788 testing::Bool()),
1789 cc::PrintTupleToStringParamName());
1790
TEST_P(VideoRendererPixelHiLoTest,SimpleYUVRect)1791 TEST_P(VideoRendererPixelHiLoTest, SimpleYUVRect) {
1792 gfx::Rect rect(this->device_viewport_size_);
1793
1794 AggregatedRenderPassId id{1};
1795 auto pass = CreateTestRootRenderPass(id, rect);
1796 // Set the output color space to match the input primaries and transfer.
1797 this->display_color_spaces_ = kRec601DisplayColorSpaces;
1798
1799 SharedQuadState* shared_state = CreateTestSharedQuadState(
1800 gfx::Transform(), rect, pass.get(), gfx::RRectF());
1801
1802 CreateTestYUVVideoDrawQuad_Striped(
1803 shared_state, media::PIXEL_FORMAT_I420, gfx::ColorSpace::CreateREC601(),
1804 false, IsHighbit(), gfx::RectF(0.0f, 0.0f, 1.0f, 1.0f), pass.get(),
1805 this->video_resource_updater_.get(), rect, rect,
1806 this->resource_provider_.get(), this->child_resource_provider_.get(),
1807 this->child_context_provider_.get());
1808
1809 AggregatedRenderPassList pass_list;
1810 pass_list.push_back(std::move(pass));
1811
1812 EXPECT_TRUE(this->RunPixelTest(
1813 &pass_list, base::FilePath(FILE_PATH_LITERAL("yuv_stripes.png")),
1814 cc::FuzzyPixelOffByOneComparator(true)));
1815 }
1816
TEST_P(VideoRendererPixelHiLoTest,ClippedYUVRect)1817 TEST_P(VideoRendererPixelHiLoTest, ClippedYUVRect) {
1818 gfx::Rect viewport(this->device_viewport_size_);
1819 gfx::Rect draw_rect(this->device_viewport_size_.width() * 1.5,
1820 this->device_viewport_size_.height() * 1.5);
1821
1822 AggregatedRenderPassId id{1};
1823 auto pass = CreateTestRootRenderPass(id, viewport);
1824 // Set the output color space to match the input primaries and transfer.
1825 this->display_color_spaces_ = kRec601DisplayColorSpaces;
1826
1827 SharedQuadState* shared_state = CreateTestSharedQuadState(
1828 gfx::Transform(), viewport, pass.get(), gfx::RRectF());
1829
1830 CreateTestYUVVideoDrawQuad_Striped(
1831 shared_state, media::PIXEL_FORMAT_I420, gfx::ColorSpace::CreateREC601(),
1832 false, IsHighbit(), gfx::RectF(0.0f, 0.0f, 1.0f, 1.0f), pass.get(),
1833 this->video_resource_updater_.get(), draw_rect, viewport,
1834 this->resource_provider_.get(), this->child_resource_provider_.get(),
1835 this->child_context_provider_.get());
1836 AggregatedRenderPassList pass_list;
1837 pass_list.push_back(std::move(pass));
1838
1839 EXPECT_TRUE(this->RunPixelTest(
1840 &pass_list, base::FilePath(FILE_PATH_LITERAL("yuv_stripes_clipped.png")),
1841 cc::FuzzyPixelOffByOneComparator(true)));
1842 }
1843 #endif // #if BUILDFLAG(ENABLE_GL_BACKEND_TESTS)
1844
1845 class VideoRendererPixelTest
1846 : public VideoRendererPixelTestBase,
1847 public testing::WithParamInterface<RendererType> {
1848 public:
VideoRendererPixelTest()1849 VideoRendererPixelTest() : VideoRendererPixelTestBase(GetParam()) {}
1850 };
1851
1852 INSTANTIATE_TEST_SUITE_P(,
1853 VideoRendererPixelTest,
1854 // TODO(crbug.com/1021566): Enable these tests for
1855 // SkiaRenderer Dawn once video is supported.
1856 testing::ValuesIn(GetGpuRendererTypesNoDawn()),
1857 testing::PrintToStringParamName());
1858
TEST_P(VideoRendererPixelTest,OffsetYUVRect)1859 TEST_P(VideoRendererPixelTest, OffsetYUVRect) {
1860 gfx::Rect rect(this->device_viewport_size_);
1861
1862 AggregatedRenderPassId id{1};
1863 auto pass = CreateTestRootRenderPass(id, rect);
1864 // Set the output color space to match the input primaries and transfer.
1865 this->display_color_spaces_ = kRec601DisplayColorSpaces;
1866
1867 SharedQuadState* shared_state = CreateTestSharedQuadState(
1868 gfx::Transform(), rect, pass.get(), gfx::RRectF());
1869
1870 // Intentionally sets frame format to I420 for testing coverage.
1871 CreateTestYUVVideoDrawQuad_Striped(
1872 shared_state, media::PIXEL_FORMAT_I420, gfx::ColorSpace::CreateREC601(),
1873 false, false, gfx::RectF(0.125f, 0.25f, 0.75f, 0.5f), pass.get(),
1874 this->video_resource_updater_.get(), rect, rect,
1875 this->resource_provider_.get(), this->child_resource_provider_.get(),
1876 this->child_context_provider_.get());
1877
1878 AggregatedRenderPassList pass_list;
1879 pass_list.push_back(std::move(pass));
1880
1881 EXPECT_TRUE(this->RunPixelTest(
1882 &pass_list, base::FilePath(FILE_PATH_LITERAL("yuv_stripes_offset.png")),
1883 cc::FuzzyPixelComparator(true, 100.0f, 1.0f, 1.0f, 1, 0)));
1884 }
1885
TEST_P(VideoRendererPixelTest,SimpleYUVRectBlack)1886 TEST_P(VideoRendererPixelTest, SimpleYUVRectBlack) {
1887 gfx::Rect rect(this->device_viewport_size_);
1888
1889 AggregatedRenderPassId id{1};
1890 auto pass = CreateTestRootRenderPass(id, rect);
1891 // Set the output color space to match the input primaries and transfer.
1892 this->display_color_spaces_ = kRec601DisplayColorSpaces;
1893
1894 SharedQuadState* shared_state = CreateTestSharedQuadState(
1895 gfx::Transform(), rect, pass.get(), gfx::RRectF());
1896
1897 // In MPEG color range YUV values of (15,128,128) should produce black.
1898 CreateTestYUVVideoDrawQuad_Solid(
1899 shared_state, media::PIXEL_FORMAT_I420, gfx::ColorSpace::CreateREC601(),
1900 false, gfx::RectF(0.0f, 0.0f, 1.0f, 1.0f), 15, 128, 128, pass.get(),
1901 this->video_resource_updater_.get(), rect, rect,
1902 this->resource_provider_.get(), this->child_resource_provider_.get(),
1903 this->child_context_provider_.get());
1904
1905 AggregatedRenderPassList pass_list;
1906 pass_list.push_back(std::move(pass));
1907
1908 // If we didn't get black out of the YUV values above, then we probably have a
1909 // color range issue.
1910 EXPECT_TRUE(this->RunPixelTest(&pass_list,
1911 base::FilePath(FILE_PATH_LITERAL("black.png")),
1912 cc::FuzzyPixelOffByOneComparator(true)));
1913 }
1914
TEST_P(VideoRendererPixelTest,SimpleYUVJRect)1915 TEST_P(VideoRendererPixelTest, SimpleYUVJRect) {
1916 gfx::Rect rect(this->device_viewport_size_);
1917
1918 AggregatedRenderPassId id{1};
1919 auto pass = CreateTestRootRenderPass(id, rect);
1920
1921 SharedQuadState* shared_state = CreateTestSharedQuadState(
1922 gfx::Transform(), rect, pass.get(), gfx::RRectF());
1923
1924 // YUV of (149,43,21) should be green (0,255,0) in RGB.
1925 CreateTestYUVVideoDrawQuad_Solid(
1926 shared_state, media::PIXEL_FORMAT_I420, gfx::ColorSpace::CreateJpeg(),
1927 false, gfx::RectF(0.0f, 0.0f, 1.0f, 1.0f), 149, 43, 21, pass.get(),
1928 this->video_resource_updater_.get(), rect, rect,
1929 this->resource_provider_.get(), this->child_resource_provider_.get(),
1930 this->child_context_provider_.get());
1931
1932 AggregatedRenderPassList pass_list;
1933 pass_list.push_back(std::move(pass));
1934
1935 EXPECT_TRUE(this->RunPixelTest(&pass_list,
1936 base::FilePath(FILE_PATH_LITERAL("green.png")),
1937 cc::FuzzyPixelOffByOneComparator(true)));
1938 }
1939
TEST_P(VideoRendererPixelTest,SimpleNV12JRect)1940 TEST_P(VideoRendererPixelTest, SimpleNV12JRect) {
1941 gfx::Rect rect(this->device_viewport_size_);
1942
1943 AggregatedRenderPassId id{1};
1944 auto pass = CreateTestRootRenderPass(id, rect);
1945
1946 SharedQuadState* shared_state = CreateTestSharedQuadState(
1947 gfx::Transform(), rect, pass.get(), gfx::RRectF());
1948
1949 // YUV of (149,43,21) should be green (0,255,0) in RGB.
1950 CreateTestYUVVideoDrawQuad_NV12(
1951 shared_state, gfx::ColorSpace::CreateJpeg(),
1952 gfx::RectF(0.0f, 0.0f, 1.0f, 1.0f), 149, 43, 21, pass.get(),
1953 this->video_resource_updater_.get(), rect, rect,
1954 this->resource_provider_.get(), this->child_resource_provider_.get(),
1955 this->child_context_provider_);
1956
1957 AggregatedRenderPassList pass_list;
1958 pass_list.push_back(std::move(pass));
1959
1960 EXPECT_TRUE(this->RunPixelTest(&pass_list,
1961 base::FilePath(FILE_PATH_LITERAL("green.png")),
1962 cc::FuzzyPixelOffByOneComparator(true)));
1963 }
1964
1965 // Test that a YUV video doesn't bleed outside of its tex coords when the
1966 // tex coord rect is only a partial subrectangle of the coded contents.
TEST_P(VideoRendererPixelTest,YUVEdgeBleed)1967 TEST_P(VideoRendererPixelTest, YUVEdgeBleed) {
1968 AggregatedRenderPassList pass_list;
1969 this->CreateEdgeBleedPass(media::PIXEL_FORMAT_I420,
1970 gfx::ColorSpace::CreateJpeg(), &pass_list);
1971 EXPECT_TRUE(this->RunPixelTest(&pass_list,
1972 base::FilePath(FILE_PATH_LITERAL("green.png")),
1973 cc::FuzzyPixelOffByOneComparator(true)));
1974 }
1975
TEST_P(VideoRendererPixelTest,YUVAEdgeBleed)1976 TEST_P(VideoRendererPixelTest, YUVAEdgeBleed) {
1977 AggregatedRenderPassList pass_list;
1978 this->CreateEdgeBleedPass(media::PIXEL_FORMAT_I420A,
1979 gfx::ColorSpace::CreateREC601(), &pass_list);
1980 // Set the output color space to match the input primaries and transfer.
1981 this->display_color_spaces_ = kRec601DisplayColorSpaces;
1982 EXPECT_TRUE(this->RunPixelTest(&pass_list,
1983 base::FilePath(FILE_PATH_LITERAL("green.png")),
1984 cc::FuzzyPixelOffByOneComparator(true)));
1985 }
1986
TEST_P(VideoRendererPixelTest,SimpleYUVJRectGrey)1987 TEST_P(VideoRendererPixelTest, SimpleYUVJRectGrey) {
1988 gfx::Rect rect(this->device_viewport_size_);
1989
1990 AggregatedRenderPassId id{1};
1991 auto pass = CreateTestRootRenderPass(id, rect);
1992
1993 SharedQuadState* shared_state = CreateTestSharedQuadState(
1994 gfx::Transform(), rect, pass.get(), gfx::RRectF());
1995
1996 // Dark grey in JPEG color range (in MPEG, this is black).
1997 CreateTestYUVVideoDrawQuad_Solid(
1998 shared_state, media::PIXEL_FORMAT_I420, gfx::ColorSpace::CreateJpeg(),
1999 false, gfx::RectF(0.0f, 0.0f, 1.0f, 1.0f), 15, 128, 128, pass.get(),
2000 this->video_resource_updater_.get(), rect, rect,
2001 this->resource_provider_.get(), this->child_resource_provider_.get(),
2002 this->child_context_provider_.get());
2003
2004 AggregatedRenderPassList pass_list;
2005 pass_list.push_back(std::move(pass));
2006
2007 EXPECT_TRUE(this->RunPixelTest(
2008 &pass_list, base::FilePath(FILE_PATH_LITERAL("dark_grey.png")),
2009 cc::FuzzyPixelOffByOneComparator(true)));
2010 }
2011
TEST_P(VideoRendererPixelTest,SimpleYUVARect)2012 TEST_P(VideoRendererPixelTest, SimpleYUVARect) {
2013 gfx::Rect rect(this->device_viewport_size_);
2014
2015 AggregatedRenderPassId id{1};
2016 auto pass = CreateTestRootRenderPass(id, rect);
2017 // Set the output color space to match the input primaries and transfer.
2018 this->display_color_spaces_ = kRec601DisplayColorSpaces;
2019
2020 SharedQuadState* shared_state = CreateTestSharedQuadState(
2021 gfx::Transform(), rect, pass.get(), gfx::RRectF());
2022
2023 CreateTestYUVVideoDrawQuad_Striped(
2024 shared_state, media::PIXEL_FORMAT_I420A, gfx::ColorSpace::CreateREC601(),
2025 false, false, gfx::RectF(0.0f, 0.0f, 1.0f, 1.0f), pass.get(),
2026 this->video_resource_updater_.get(), rect, rect,
2027 this->resource_provider_.get(), this->child_resource_provider_.get(),
2028 this->child_context_provider_.get());
2029
2030 auto* color_quad = pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
2031 color_quad->SetNew(shared_state, rect, rect, SK_ColorWHITE, false);
2032
2033 AggregatedRenderPassList pass_list;
2034 pass_list.push_back(std::move(pass));
2035
2036 EXPECT_TRUE(this->RunPixelTest(
2037 &pass_list, base::FilePath(FILE_PATH_LITERAL("yuv_stripes_alpha.png")),
2038 cc::FuzzyPixelOffByOneComparator(true)));
2039 }
2040
TEST_P(VideoRendererPixelTest,FullyTransparentYUVARect)2041 TEST_P(VideoRendererPixelTest, FullyTransparentYUVARect) {
2042 gfx::Rect rect(this->device_viewport_size_);
2043
2044 AggregatedRenderPassId id{1};
2045 auto pass = CreateTestRootRenderPass(id, rect);
2046 // Set the output color space to match the input primaries and transfer.
2047 this->display_color_spaces_ = kRec601DisplayColorSpaces;
2048
2049 SharedQuadState* shared_state = CreateTestSharedQuadState(
2050 gfx::Transform(), rect, pass.get(), gfx::RRectF());
2051
2052 CreateTestYUVVideoDrawQuad_Striped(
2053 shared_state, media::PIXEL_FORMAT_I420A, gfx::ColorSpace::CreateREC601(),
2054 true, false, gfx::RectF(0.0f, 0.0f, 1.0f, 1.0f), pass.get(),
2055 this->video_resource_updater_.get(), rect, rect,
2056 this->resource_provider_.get(), this->child_resource_provider_.get(),
2057 this->child_context_provider_.get());
2058
2059 auto* color_quad = pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
2060 color_quad->SetNew(shared_state, rect, rect, SK_ColorBLACK, false);
2061
2062 AggregatedRenderPassList pass_list;
2063 pass_list.push_back(std::move(pass));
2064
2065 EXPECT_TRUE(this->RunPixelTest(&pass_list,
2066 base::FilePath(FILE_PATH_LITERAL("black.png")),
2067 cc::ExactPixelComparator(true)));
2068 }
2069
TEST_P(VideoRendererPixelTest,TwoColorY16Rect)2070 TEST_P(VideoRendererPixelTest, TwoColorY16Rect) {
2071 gfx::Rect rect(this->device_viewport_size_);
2072
2073 AggregatedRenderPassId id{1};
2074 auto pass = CreateTestRootRenderPass(id, rect);
2075
2076 SharedQuadState* shared_state = CreateTestSharedQuadState(
2077 gfx::Transform(), rect, pass.get(), gfx::RRectF());
2078
2079 gfx::Rect upper_rect(rect.x(), rect.y(), rect.width(), rect.height() / 2);
2080 CreateTestY16TextureDrawQuad_TwoColor(
2081 shared_state, gfx::RectF(0.0f, 0.0f, 1.0f, 1.0f), 68, 123, pass.get(),
2082 this->video_resource_updater_.get(), rect, rect, upper_rect,
2083 this->resource_provider_.get(), this->child_resource_provider_.get(),
2084 this->child_context_provider_.get());
2085
2086 AggregatedRenderPassList pass_list;
2087 pass_list.push_back(std::move(pass));
2088
2089 EXPECT_TRUE(this->RunPixelTest(
2090 &pass_list,
2091 base::FilePath(FILE_PATH_LITERAL("blue_yellow_filter_chain.png")),
2092 cc::FuzzyPixelOffByOneComparator(true)));
2093 }
2094
2095 // TODO(https://crbug.com/1044841): Flaky, especially on Linux/TSAN and Fuchsia.
TEST_P(RendererPixelTest,DISABLED_FastPassColorFilterAlpha)2096 TEST_P(RendererPixelTest, DISABLED_FastPassColorFilterAlpha) {
2097 gfx::Rect viewport_rect(this->device_viewport_size_);
2098
2099 AggregatedRenderPassId root_pass_id{1};
2100 auto root_pass = CreateTestRootRenderPass(root_pass_id, viewport_rect);
2101
2102 AggregatedRenderPassId child_pass_id{2};
2103 gfx::Rect pass_rect(this->device_viewport_size_);
2104 gfx::Transform transform_to_root;
2105 float matrix[20];
2106 float amount = 0.5f;
2107 matrix[0] = 0.213f + 0.787f * amount;
2108 matrix[1] = 0.715f - 0.715f * amount;
2109 matrix[2] = 1.f - (matrix[0] + matrix[1]);
2110 matrix[3] = matrix[4] = 0;
2111 matrix[5] = 0.213f - 0.213f * amount;
2112 matrix[6] = 0.715f + 0.285f * amount;
2113 matrix[7] = 1.f - (matrix[5] + matrix[6]);
2114 matrix[8] = matrix[9] = 0;
2115 matrix[10] = 0.213f - 0.213f * amount;
2116 matrix[11] = 0.715f - 0.715f * amount;
2117 matrix[12] = 1.f - (matrix[10] + matrix[11]);
2118 matrix[13] = matrix[14] = 0;
2119 matrix[15] = matrix[16] = matrix[17] = matrix[19] = 0;
2120 matrix[18] = 1;
2121 cc::FilterOperations filters;
2122 filters.Append(cc::FilterOperation::CreateReferenceFilter(
2123 sk_make_sp<cc::ColorFilterPaintFilter>(SkColorFilters::Matrix(matrix),
2124 nullptr)));
2125
2126 auto child_pass =
2127 CreateTestRenderPass(child_pass_id, pass_rect, transform_to_root);
2128 child_pass->filters = filters;
2129
2130 gfx::Transform quad_to_target_transform;
2131 SharedQuadState* shared_state = CreateTestSharedQuadState(
2132 quad_to_target_transform, viewport_rect, child_pass.get(), gfx::RRectF());
2133 shared_state->opacity = 0.5f;
2134
2135 gfx::Rect blue_rect(0, 0, this->device_viewport_size_.width(),
2136 this->device_viewport_size_.height() / 2);
2137 auto* blue = child_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
2138 blue->SetNew(shared_state, blue_rect, blue_rect, SK_ColorBLUE, false);
2139 gfx::Rect yellow_rect(0, this->device_viewport_size_.height() / 2,
2140 this->device_viewport_size_.width(),
2141 this->device_viewport_size_.height() / 2);
2142 auto* yellow = child_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
2143 yellow->SetNew(shared_state, yellow_rect, yellow_rect, SK_ColorYELLOW, false);
2144
2145 SharedQuadState* blank_state = CreateTestSharedQuadState(
2146 quad_to_target_transform, viewport_rect, child_pass.get(), gfx::RRectF());
2147
2148 auto* white = child_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
2149 white->SetNew(blank_state, viewport_rect, viewport_rect, SK_ColorWHITE,
2150 false);
2151
2152 SharedQuadState* pass_shared_state = CreateTestSharedQuadState(
2153 gfx::Transform(), pass_rect, root_pass.get(), gfx::RRectF());
2154
2155 auto* render_pass_quad =
2156 root_pass->CreateAndAppendDrawQuad<AggregatedRenderPassDrawQuad>();
2157 render_pass_quad->SetNew(pass_shared_state, pass_rect, pass_rect,
2158 child_pass_id, 0, gfx::RectF(), gfx::Size(),
2159 gfx::Vector2dF(), gfx::PointF(),
2160 gfx::RectF(pass_rect), false, 1.0f);
2161
2162 AggregatedRenderPassList pass_list;
2163 pass_list.push_back(std::move(child_pass));
2164 pass_list.push_back(std::move(root_pass));
2165
2166 // This test has alpha=254 for the software renderer vs. alpha=255 for the gl
2167 // renderer so use a fuzzy comparator.
2168 EXPECT_TRUE(this->RunPixelTest(
2169 &pass_list, base::FilePath(FILE_PATH_LITERAL("blue_yellow_alpha.png")),
2170 FuzzyForSkiaOnlyPixelComparator(renderer_type())));
2171 }
2172
2173 // TODO(https://crbug.com/1044841): Flaky, especially on Linux/TSAN and Fuchsia.
TEST_P(RendererPixelTest,DISABLED_FastPassSaturateFilter)2174 TEST_P(RendererPixelTest, DISABLED_FastPassSaturateFilter) {
2175 gfx::Rect viewport_rect(this->device_viewport_size_);
2176
2177 AggregatedRenderPassId root_pass_id{1};
2178 auto root_pass = CreateTestRootRenderPass(root_pass_id, viewport_rect);
2179
2180 AggregatedRenderPassId child_pass_id{2};
2181 gfx::Rect pass_rect(this->device_viewport_size_);
2182 gfx::Transform transform_to_root;
2183 cc::FilterOperations filters;
2184 filters.Append(cc::FilterOperation::CreateSaturateFilter(0.5f));
2185
2186 auto child_pass =
2187 CreateTestRenderPass(child_pass_id, pass_rect, transform_to_root);
2188 child_pass->filters = filters;
2189
2190 gfx::Transform quad_to_target_transform;
2191 SharedQuadState* shared_state = CreateTestSharedQuadState(
2192 quad_to_target_transform, viewport_rect, child_pass.get(), gfx::RRectF());
2193 shared_state->opacity = 0.5f;
2194
2195 gfx::Rect blue_rect(0, 0, this->device_viewport_size_.width(),
2196 this->device_viewport_size_.height() / 2);
2197 auto* blue = child_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
2198 blue->SetNew(shared_state, blue_rect, blue_rect, SK_ColorBLUE, false);
2199 gfx::Rect yellow_rect(0, this->device_viewport_size_.height() / 2,
2200 this->device_viewport_size_.width(),
2201 this->device_viewport_size_.height() / 2);
2202 auto* yellow = child_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
2203 yellow->SetNew(shared_state, yellow_rect, yellow_rect, SK_ColorYELLOW, false);
2204
2205 SharedQuadState* blank_state = CreateTestSharedQuadState(
2206 quad_to_target_transform, viewport_rect, child_pass.get(), gfx::RRectF());
2207
2208 auto* white = child_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
2209 white->SetNew(blank_state, viewport_rect, viewport_rect, SK_ColorWHITE,
2210 false);
2211
2212 SharedQuadState* pass_shared_state = CreateTestSharedQuadState(
2213 gfx::Transform(), pass_rect, root_pass.get(), gfx::RRectF());
2214
2215 auto* render_pass_quad =
2216 root_pass->CreateAndAppendDrawQuad<AggregatedRenderPassDrawQuad>();
2217 render_pass_quad->SetNew(pass_shared_state, pass_rect, pass_rect,
2218 child_pass_id, 0, gfx::RectF(), gfx::Size(),
2219 gfx::Vector2dF(), gfx::PointF(),
2220 gfx::RectF(pass_rect), false, 1.0f);
2221
2222 AggregatedRenderPassList pass_list;
2223 pass_list.push_back(std::move(child_pass));
2224 pass_list.push_back(std::move(root_pass));
2225
2226 // This test blends slightly differently with the software renderer vs. the gl
2227 // renderer so use a fuzzy comparator.
2228 EXPECT_TRUE(this->RunPixelTest(
2229 &pass_list, base::FilePath(FILE_PATH_LITERAL("blue_yellow_alpha.png")),
2230 FuzzyForSkiaOnlyPixelComparator(renderer_type())));
2231 }
2232
TEST_P(RendererPixelTest,FastPassFilterChain)2233 TEST_P(RendererPixelTest, FastPassFilterChain) {
2234 gfx::Rect viewport_rect(this->device_viewport_size_);
2235
2236 AggregatedRenderPassId root_pass_id{1};
2237 auto root_pass = CreateTestRootRenderPass(root_pass_id, viewport_rect);
2238
2239 AggregatedRenderPassId child_pass_id{2};
2240 gfx::Rect pass_rect(this->device_viewport_size_);
2241 gfx::Transform transform_to_root;
2242 cc::FilterOperations filters;
2243 filters.Append(cc::FilterOperation::CreateGrayscaleFilter(1.f));
2244 filters.Append(cc::FilterOperation::CreateBrightnessFilter(0.5f));
2245
2246 auto child_pass =
2247 CreateTestRenderPass(child_pass_id, pass_rect, transform_to_root);
2248 child_pass->filters = filters;
2249
2250 gfx::Transform quad_to_target_transform;
2251 SharedQuadState* shared_state = CreateTestSharedQuadState(
2252 quad_to_target_transform, viewport_rect, child_pass.get(), gfx::RRectF());
2253 shared_state->opacity = 0.5f;
2254
2255 gfx::Rect blue_rect(0, 0, this->device_viewport_size_.width(),
2256 this->device_viewport_size_.height() / 2);
2257 auto* blue = child_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
2258 blue->SetNew(shared_state, blue_rect, blue_rect, SK_ColorBLUE, false);
2259 gfx::Rect yellow_rect(0, this->device_viewport_size_.height() / 2,
2260 this->device_viewport_size_.width(),
2261 this->device_viewport_size_.height() / 2);
2262 auto* yellow = child_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
2263 yellow->SetNew(shared_state, yellow_rect, yellow_rect, SK_ColorYELLOW, false);
2264
2265 SharedQuadState* blank_state = CreateTestSharedQuadState(
2266 quad_to_target_transform, viewport_rect, child_pass.get(), gfx::RRectF());
2267
2268 auto* white = child_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
2269 white->SetNew(blank_state, viewport_rect, viewport_rect, SK_ColorWHITE,
2270 false);
2271
2272 SharedQuadState* pass_shared_state = CreateTestSharedQuadState(
2273 gfx::Transform(), pass_rect, root_pass.get(), gfx::RRectF());
2274
2275 auto* render_pass_quad =
2276 root_pass->CreateAndAppendDrawQuad<AggregatedRenderPassDrawQuad>();
2277 render_pass_quad->SetNew(pass_shared_state, pass_rect, pass_rect,
2278 child_pass_id, 0, gfx::RectF(), gfx::Size(),
2279 gfx::Vector2dF(), gfx::PointF(),
2280 gfx::RectF(pass_rect), false, 1.0f);
2281
2282 AggregatedRenderPassList pass_list;
2283 pass_list.push_back(std::move(child_pass));
2284 pass_list.push_back(std::move(root_pass));
2285
2286 // This test blends slightly differently with the software renderer vs. the gl
2287 // renderer so use a fuzzy comparator.
2288 EXPECT_TRUE(this->RunPixelTest(
2289 &pass_list,
2290 base::FilePath(FILE_PATH_LITERAL("blue_yellow_filter_chain.png")),
2291 FuzzyForSkiaOnlyPixelComparator(renderer_type())));
2292 }
2293
2294 // TODO(https://crbug.com/1044841): Flaky, especially on Linux/TSAN and Fuchsia.
TEST_P(RendererPixelTest,DISABLED_FastPassColorFilterAlphaTranslation)2295 TEST_P(RendererPixelTest, DISABLED_FastPassColorFilterAlphaTranslation) {
2296 gfx::Rect viewport_rect(this->device_viewport_size_);
2297
2298 AggregatedRenderPassId root_pass_id{1};
2299 auto root_pass = CreateTestRootRenderPass(root_pass_id, viewport_rect);
2300
2301 AggregatedRenderPassId child_pass_id{2};
2302 gfx::Rect pass_rect(this->device_viewport_size_);
2303 gfx::Transform transform_to_root;
2304 float matrix[20];
2305 float amount = 0.5f;
2306 matrix[0] = 0.213f + 0.787f * amount;
2307 matrix[1] = 0.715f - 0.715f * amount;
2308 matrix[2] = 1.f - (matrix[0] + matrix[1]);
2309 matrix[3] = 0;
2310 matrix[4] = 20.f / 255;
2311 matrix[5] = 0.213f - 0.213f * amount;
2312 matrix[6] = 0.715f + 0.285f * amount;
2313 matrix[7] = 1.f - (matrix[5] + matrix[6]);
2314 matrix[8] = 0;
2315 matrix[9] = 200.f / 255;
2316 matrix[10] = 0.213f - 0.213f * amount;
2317 matrix[11] = 0.715f - 0.715f * amount;
2318 matrix[12] = 1.f - (matrix[10] + matrix[11]);
2319 matrix[13] = 0;
2320 matrix[14] = 1.5f / 255;
2321 matrix[15] = matrix[16] = matrix[17] = matrix[19] = 0;
2322 matrix[18] = 1;
2323 cc::FilterOperations filters;
2324 filters.Append(cc::FilterOperation::CreateReferenceFilter(
2325 sk_make_sp<cc::ColorFilterPaintFilter>(SkColorFilters::Matrix(matrix),
2326 nullptr)));
2327
2328 auto child_pass =
2329 CreateTestRenderPass(child_pass_id, pass_rect, transform_to_root);
2330 child_pass->filters = filters;
2331
2332 gfx::Transform quad_to_target_transform;
2333 SharedQuadState* shared_state = CreateTestSharedQuadState(
2334 quad_to_target_transform, viewport_rect, child_pass.get(), gfx::RRectF());
2335 shared_state->opacity = 0.5f;
2336
2337 gfx::Rect blue_rect(0, 0, this->device_viewport_size_.width(),
2338 this->device_viewport_size_.height() / 2);
2339 auto* blue = child_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
2340 blue->SetNew(shared_state, blue_rect, blue_rect, SK_ColorBLUE, false);
2341 gfx::Rect yellow_rect(0, this->device_viewport_size_.height() / 2,
2342 this->device_viewport_size_.width(),
2343 this->device_viewport_size_.height() / 2);
2344 auto* yellow = child_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
2345 yellow->SetNew(shared_state, yellow_rect, yellow_rect, SK_ColorYELLOW, false);
2346
2347 SharedQuadState* blank_state = CreateTestSharedQuadState(
2348 quad_to_target_transform, viewport_rect, child_pass.get(), gfx::RRectF());
2349
2350 auto* white = child_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
2351 white->SetNew(blank_state, viewport_rect, viewport_rect, SK_ColorWHITE,
2352 false);
2353
2354 SharedQuadState* pass_shared_state = CreateTestSharedQuadState(
2355 gfx::Transform(), pass_rect, root_pass.get(), gfx::RRectF());
2356
2357 auto* render_pass_quad =
2358 root_pass->CreateAndAppendDrawQuad<AggregatedRenderPassDrawQuad>();
2359 render_pass_quad->SetNew(pass_shared_state, pass_rect, pass_rect,
2360 child_pass_id, 0, gfx::RectF(), gfx::Size(),
2361 gfx::Vector2dF(), gfx::PointF(),
2362 gfx::RectF(pass_rect), false, 1.0f);
2363
2364 AggregatedRenderPassList pass_list;
2365
2366 pass_list.push_back(std::move(child_pass));
2367 pass_list.push_back(std::move(root_pass));
2368
2369 // This test has alpha=254 for the software renderer vs. alpha=255 for the gl
2370 // renderer so use a fuzzy comparator.
2371 EXPECT_TRUE(this->RunPixelTest(
2372 &pass_list,
2373 base::FilePath(FILE_PATH_LITERAL("blue_yellow_alpha_translate.png")),
2374 FuzzyForSkiaOnlyPixelComparator(renderer_type())));
2375 }
2376
TEST_P(RendererPixelTest,EnlargedRenderPassTexture)2377 TEST_P(RendererPixelTest, EnlargedRenderPassTexture) {
2378 gfx::Rect viewport_rect(this->device_viewport_size_);
2379
2380 AggregatedRenderPassId root_pass_id{1};
2381 auto root_pass = CreateTestRootRenderPass(root_pass_id, viewport_rect);
2382
2383 AggregatedRenderPassId child_pass_id{2};
2384 gfx::Rect pass_rect(this->device_viewport_size_);
2385 gfx::Transform transform_to_root;
2386 auto child_pass =
2387 CreateTestRenderPass(child_pass_id, pass_rect, transform_to_root);
2388
2389 gfx::Transform quad_to_target_transform;
2390 SharedQuadState* shared_state = CreateTestSharedQuadState(
2391 quad_to_target_transform, viewport_rect, child_pass.get(), gfx::RRectF());
2392
2393 gfx::Rect blue_rect(0, 0, this->device_viewport_size_.width(),
2394 this->device_viewport_size_.height() / 2);
2395 auto* blue = child_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
2396 blue->SetNew(shared_state, blue_rect, blue_rect, SK_ColorBLUE, false);
2397 gfx::Rect yellow_rect(0, this->device_viewport_size_.height() / 2,
2398 this->device_viewport_size_.width(),
2399 this->device_viewport_size_.height() / 2);
2400 auto* yellow = child_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
2401 yellow->SetNew(shared_state, yellow_rect, yellow_rect, SK_ColorYELLOW, false);
2402
2403 SharedQuadState* pass_shared_state = CreateTestSharedQuadState(
2404 gfx::Transform(), pass_rect, root_pass.get(), gfx::RRectF());
2405 CreateTestRenderPassDrawQuad(pass_shared_state, pass_rect, child_pass_id,
2406 root_pass.get());
2407
2408 AggregatedRenderPassList pass_list;
2409 pass_list.push_back(std::move(child_pass));
2410 pass_list.push_back(std::move(root_pass));
2411
2412 this->renderer_->SetEnlargePassTextureAmountForTesting(gfx::Size(50, 75));
2413
2414 EXPECT_TRUE(this->RunPixelTest(
2415 &pass_list, base::FilePath(FILE_PATH_LITERAL("blue_yellow.png")),
2416 cc::FuzzyPixelOffByOneComparator(true)));
2417 }
2418
TEST_P(RendererPixelTest,EnlargedRenderPassTextureWithAntiAliasing)2419 TEST_P(RendererPixelTest, EnlargedRenderPassTextureWithAntiAliasing) {
2420 gfx::Rect viewport_rect(this->device_viewport_size_);
2421
2422 AggregatedRenderPassId root_pass_id{1};
2423 auto root_pass = CreateTestRootRenderPass(root_pass_id, viewport_rect);
2424
2425 AggregatedRenderPassId child_pass_id{2};
2426 gfx::Rect pass_rect(this->device_viewport_size_);
2427 gfx::Transform transform_to_root;
2428 auto child_pass =
2429 CreateTestRenderPass(child_pass_id, pass_rect, transform_to_root);
2430
2431 gfx::Transform quad_to_target_transform;
2432 SharedQuadState* shared_state = CreateTestSharedQuadState(
2433 quad_to_target_transform, viewport_rect, child_pass.get(), gfx::RRectF());
2434
2435 gfx::Rect blue_rect(0, 0, this->device_viewport_size_.width(),
2436 this->device_viewport_size_.height() / 2);
2437 auto* blue = child_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
2438 blue->SetNew(shared_state, blue_rect, blue_rect, SK_ColorBLUE, false);
2439 gfx::Rect yellow_rect(0, this->device_viewport_size_.height() / 2,
2440 this->device_viewport_size_.width(),
2441 this->device_viewport_size_.height() / 2);
2442 auto* yellow = child_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
2443 yellow->SetNew(shared_state, yellow_rect, yellow_rect, SK_ColorYELLOW, false);
2444
2445 gfx::Transform aa_transform;
2446 aa_transform.Translate(0.5, 0.0);
2447
2448 SharedQuadState* pass_shared_state = CreateTestSharedQuadState(
2449 aa_transform, pass_rect, root_pass.get(), gfx::RRectF());
2450 CreateTestRenderPassDrawQuad(pass_shared_state, pass_rect, child_pass_id,
2451 root_pass.get());
2452
2453 SharedQuadState* root_shared_state = CreateTestSharedQuadState(
2454 gfx::Transform(), viewport_rect, root_pass.get(), gfx::RRectF());
2455 auto* background = root_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
2456 background->SetNew(root_shared_state, gfx::Rect(this->device_viewport_size_),
2457 gfx::Rect(this->device_viewport_size_), SK_ColorWHITE,
2458 false);
2459
2460 AggregatedRenderPassList pass_list;
2461 pass_list.push_back(std::move(child_pass));
2462 pass_list.push_back(std::move(root_pass));
2463
2464 this->renderer_->SetEnlargePassTextureAmountForTesting(gfx::Size(50, 75));
2465
2466 EXPECT_TRUE(this->RunPixelTest(
2467 &pass_list,
2468 base::FilePath(FILE_PATH_LITERAL("blue_yellow_anti_aliasing.png")),
2469 cc::FuzzyPixelComparator(true, 100.f, 0.f, 5.f, 7, 0)));
2470 }
2471
2472 // This tests the case where we have a RenderPass with a mask, but the quad
2473 // for the masked surface does not include the full surface texture.
TEST_P(RendererPixelTest,RenderPassAndMaskWithPartialQuad)2474 TEST_P(RendererPixelTest, RenderPassAndMaskWithPartialQuad) {
2475 gfx::Rect viewport_rect(this->device_viewport_size_);
2476
2477 AggregatedRenderPassId root_pass_id{1};
2478 auto root_pass = CreateTestRootRenderPass(root_pass_id, viewport_rect);
2479 SharedQuadState* root_pass_shared_state = CreateTestSharedQuadState(
2480 gfx::Transform(), viewport_rect, root_pass.get(), gfx::RRectF());
2481
2482 AggregatedRenderPassId child_pass_id{2};
2483 gfx::Transform transform_to_root;
2484 auto child_pass =
2485 CreateTestRenderPass(child_pass_id, viewport_rect, transform_to_root);
2486 SharedQuadState* child_pass_shared_state = CreateTestSharedQuadState(
2487 gfx::Transform(), viewport_rect, child_pass.get(), gfx::RRectF());
2488
2489 // The child render pass is just a green box.
2490 static const SkColor kCSSGreen = 0xff008000;
2491 auto* green = child_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
2492 green->SetNew(child_pass_shared_state, viewport_rect, viewport_rect,
2493 kCSSGreen, false);
2494
2495 // Make a mask.
2496 gfx::Rect mask_rect = viewport_rect;
2497 SkBitmap bitmap;
2498 bitmap.allocPixels(
2499 SkImageInfo::MakeN32Premul(mask_rect.width(), mask_rect.height()));
2500 cc::SkiaPaintCanvas canvas(bitmap);
2501 cc::PaintFlags flags;
2502 flags.setStyle(cc::PaintFlags::kStroke_Style);
2503 flags.setStrokeWidth(SkIntToScalar(4));
2504 flags.setColor(SK_ColorWHITE);
2505 canvas.clear(SK_ColorTRANSPARENT);
2506 gfx::Rect rect = mask_rect;
2507 while (!rect.IsEmpty()) {
2508 rect.Inset(6, 6, 4, 4);
2509 canvas.drawRect(
2510 SkRect::MakeXYWH(rect.x(), rect.y(), rect.width(), rect.height()),
2511 flags);
2512 rect.Inset(6, 6, 4, 4);
2513 }
2514
2515 ResourceId mask_resource_id;
2516 if (!is_software_renderer()) {
2517 mask_resource_id = CreateGpuResource(
2518 this->child_context_provider_, this->child_resource_provider_.get(),
2519 mask_rect.size(), RGBA_8888, gfx::ColorSpace(), MakePixelSpan(bitmap));
2520 } else {
2521 mask_resource_id =
2522 this->AllocateAndFillSoftwareResource(mask_rect.size(), bitmap);
2523 }
2524
2525 // Return the mapped resource id.
2526 std::unordered_map<ResourceId, ResourceId> resource_map =
2527 cc::SendResourceAndGetChildToParentMap(
2528 {mask_resource_id}, this->resource_provider_.get(),
2529 this->child_resource_provider_.get(),
2530 this->child_context_provider_.get());
2531 ResourceId mapped_mask_resource_id = resource_map[mask_resource_id];
2532
2533 // This AggregatedRenderPassDrawQuad does not include the full |viewport_rect|
2534 // which is the size of the child render pass.
2535 gfx::Rect sub_rect = gfx::Rect(50, 50, 200, 100);
2536 EXPECT_NE(sub_rect.x(), child_pass->output_rect.x());
2537 EXPECT_NE(sub_rect.y(), child_pass->output_rect.y());
2538 EXPECT_NE(sub_rect.right(), child_pass->output_rect.right());
2539 EXPECT_NE(sub_rect.bottom(), child_pass->output_rect.bottom());
2540
2541 // Set up a mask on the AggregatedRenderPassDrawQuad.
2542 auto* mask_quad =
2543 root_pass->CreateAndAppendDrawQuad<AggregatedRenderPassDrawQuad>();
2544 mask_quad->SetNew(
2545 root_pass_shared_state, sub_rect, sub_rect, child_pass_id,
2546 mapped_mask_resource_id,
2547 gfx::ScaleRect(gfx::RectF(sub_rect), 2.f / mask_rect.width(),
2548 2.f / mask_rect.height()), // mask_uv_rect
2549 gfx::Size(mask_rect.size()), // mask_texture_size
2550 gfx::Vector2dF(), // filters scale
2551 gfx::PointF(), // filter origin
2552 gfx::RectF(sub_rect), // tex_coord_rect
2553 false, // force_anti_aliasing_off
2554 1.0f); // backdrop_filter_quality
2555 // White background behind the masked render pass.
2556 auto* white = root_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
2557 white->SetNew(root_pass_shared_state, viewport_rect, viewport_rect,
2558 SK_ColorWHITE, false);
2559
2560 AggregatedRenderPassList pass_list;
2561 pass_list.push_back(std::move(child_pass));
2562 pass_list.push_back(std::move(root_pass));
2563
2564 EXPECT_TRUE(this->RunPixelTest(
2565 &pass_list, base::FilePath(FILE_PATH_LITERAL("mask_bottom_right.png")),
2566 cc::ExactPixelComparator(true)));
2567 }
2568
2569 // This tests the case where we have a RenderPass with a mask, but the quad
2570 // for the masked surface does not include the full surface texture.
TEST_P(RendererPixelTest,RenderPassAndMaskWithPartialQuad2)2571 TEST_P(RendererPixelTest, RenderPassAndMaskWithPartialQuad2) {
2572 gfx::Rect viewport_rect(this->device_viewport_size_);
2573
2574 AggregatedRenderPassId root_pass_id{1};
2575 auto root_pass = CreateTestRootRenderPass(root_pass_id, viewport_rect);
2576 SharedQuadState* root_pass_shared_state = CreateTestSharedQuadState(
2577 gfx::Transform(), viewport_rect, root_pass.get(), gfx::RRectF());
2578
2579 AggregatedRenderPassId child_pass_id{2};
2580 gfx::Transform transform_to_root;
2581 auto child_pass =
2582 CreateTestRenderPass(child_pass_id, viewport_rect, transform_to_root);
2583 SharedQuadState* child_pass_shared_state = CreateTestSharedQuadState(
2584 gfx::Transform(), viewport_rect, child_pass.get(), gfx::RRectF());
2585
2586 // The child render pass is just a green box.
2587 static const SkColor kCSSGreen = 0xff008000;
2588 auto* green = child_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
2589 green->SetNew(child_pass_shared_state, viewport_rect, viewport_rect,
2590 kCSSGreen, false);
2591
2592 // Make a mask.
2593 gfx::Rect mask_rect = viewport_rect;
2594 SkBitmap bitmap;
2595 bitmap.allocPixels(
2596 SkImageInfo::MakeN32Premul(mask_rect.width(), mask_rect.height()));
2597 cc::SkiaPaintCanvas canvas(bitmap);
2598 cc::PaintFlags flags;
2599 flags.setStyle(cc::PaintFlags::kStroke_Style);
2600 flags.setStrokeWidth(SkIntToScalar(4));
2601 flags.setColor(SK_ColorWHITE);
2602 canvas.clear(SK_ColorTRANSPARENT);
2603 gfx::Rect rect = mask_rect;
2604 while (!rect.IsEmpty()) {
2605 rect.Inset(6, 6, 4, 4);
2606 canvas.drawRect(
2607 SkRect::MakeXYWH(rect.x(), rect.y(), rect.width(), rect.height()),
2608 flags);
2609 rect.Inset(6, 6, 4, 4);
2610 }
2611
2612 ResourceId mask_resource_id;
2613 if (!is_software_renderer()) {
2614 mask_resource_id = CreateGpuResource(
2615 this->child_context_provider_, this->child_resource_provider_.get(),
2616 mask_rect.size(), RGBA_8888, gfx::ColorSpace(), MakePixelSpan(bitmap));
2617 } else {
2618 mask_resource_id =
2619 this->AllocateAndFillSoftwareResource(mask_rect.size(), bitmap);
2620 }
2621
2622 // Return the mapped resource id.
2623 std::unordered_map<ResourceId, ResourceId> resource_map =
2624 cc::SendResourceAndGetChildToParentMap(
2625 {mask_resource_id}, this->resource_provider_.get(),
2626 this->child_resource_provider_.get(),
2627 this->child_context_provider_.get());
2628 ResourceId mapped_mask_resource_id = resource_map[mask_resource_id];
2629
2630 // This AggregatedRenderPassDrawQuad does not include the full |viewport_rect|
2631 // which is the size of the child render pass.
2632 gfx::Rect sub_rect = gfx::Rect(50, 20, 200, 60);
2633 EXPECT_NE(sub_rect.x(), child_pass->output_rect.x());
2634 EXPECT_NE(sub_rect.y(), child_pass->output_rect.y());
2635 EXPECT_NE(sub_rect.right(), child_pass->output_rect.right());
2636 EXPECT_NE(sub_rect.bottom(), child_pass->output_rect.bottom());
2637
2638 // Set up a mask on the AggregatedRenderPassDrawQuad.
2639 auto* mask_quad =
2640 root_pass->CreateAndAppendDrawQuad<AggregatedRenderPassDrawQuad>();
2641 mask_quad->SetNew(
2642 root_pass_shared_state, sub_rect, sub_rect, child_pass_id,
2643 mapped_mask_resource_id,
2644 gfx::ScaleRect(gfx::RectF(sub_rect), 2.f / mask_rect.width(),
2645 2.f / mask_rect.height()), // mask_uv_rect
2646 gfx::Size(mask_rect.size()), // mask_texture_size
2647 gfx::Vector2dF(), // filters scale
2648 gfx::PointF(), // filter origin
2649 gfx::RectF(sub_rect), // tex_coord_rect
2650 false, // force_anti_aliasing_off
2651 1.0f); // backdrop_filter_quality
2652 // White background behind the masked render pass.
2653 auto* white = root_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
2654 white->SetNew(root_pass_shared_state, viewport_rect, viewport_rect,
2655 SK_ColorWHITE, false);
2656
2657 AggregatedRenderPassList pass_list;
2658 pass_list.push_back(std::move(child_pass));
2659 pass_list.push_back(std::move(root_pass));
2660
2661 EXPECT_TRUE(this->RunPixelTest(
2662 &pass_list, base::FilePath(FILE_PATH_LITERAL("mask_middle.png")),
2663 cc::ExactPixelComparator(true)));
2664 }
2665
TEST_P(RendererPixelTest,RenderPassAndMaskForRoundedCorner)2666 TEST_P(RendererPixelTest, RenderPassAndMaskForRoundedCorner) {
2667 gfx::Rect viewport_rect(this->device_viewport_size_);
2668 constexpr int kInset = 20;
2669 constexpr int kCornerRadius = 20;
2670
2671 AggregatedRenderPassId root_pass_id{1};
2672 auto root_pass = CreateTestRootRenderPass(root_pass_id, viewport_rect);
2673 SharedQuadState* root_pass_shared_state = CreateTestSharedQuadState(
2674 gfx::Transform(), viewport_rect, root_pass.get(), gfx::RRectF());
2675
2676 AggregatedRenderPassId child_pass_id{2};
2677 gfx::Transform transform_to_root;
2678 auto child_pass =
2679 CreateTestRenderPass(child_pass_id, viewport_rect, transform_to_root);
2680 SharedQuadState* child_pass_shared_state = CreateTestSharedQuadState(
2681 gfx::Transform(), viewport_rect, child_pass.get(), gfx::RRectF());
2682
2683 // The child render pass is just a blue box.
2684 auto* blue = child_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
2685 blue->SetNew(child_pass_shared_state, viewport_rect, viewport_rect,
2686 SK_ColorBLUE, false);
2687
2688 // Make a mask.
2689 gfx::Rect mask_rect = viewport_rect;
2690 SkBitmap bitmap;
2691 bitmap.allocPixels(
2692 SkImageInfo::MakeN32Premul(mask_rect.width(), mask_rect.height()));
2693 cc::SkiaPaintCanvas canvas(bitmap);
2694 cc::PaintFlags flags;
2695 flags.setStyle(cc::PaintFlags::kFill_Style);
2696 flags.setColor(SK_ColorWHITE);
2697 flags.setAntiAlias(true);
2698 canvas.clear(SK_ColorTRANSPARENT);
2699 gfx::Rect rounded_corner_rect = mask_rect;
2700 rounded_corner_rect.Inset(kInset, kInset);
2701 SkRRect rounded_corner = SkRRect::MakeRectXY(
2702 gfx::RectToSkRect(rounded_corner_rect), kCornerRadius, kCornerRadius);
2703 canvas.drawRRect(rounded_corner, flags);
2704
2705 ResourceId mask_resource_id;
2706 if (!is_software_renderer()) {
2707 mask_resource_id = CreateGpuResource(
2708 this->child_context_provider_, this->child_resource_provider_.get(),
2709 mask_rect.size(), RGBA_8888, gfx::ColorSpace(), MakePixelSpan(bitmap));
2710 } else {
2711 mask_resource_id =
2712 this->AllocateAndFillSoftwareResource(mask_rect.size(), bitmap);
2713 }
2714
2715 // Return the mapped resource id.
2716 std::unordered_map<ResourceId, ResourceId> resource_map =
2717 cc::SendResourceAndGetChildToParentMap(
2718 {mask_resource_id}, this->resource_provider_.get(),
2719 this->child_resource_provider_.get(),
2720 this->child_context_provider_.get());
2721 ResourceId mapped_mask_resource_id = resource_map[mask_resource_id];
2722
2723 // Set up a mask on the AggregatedRenderPassDrawQuad.
2724 auto* mask_quad =
2725 root_pass->CreateAndAppendDrawQuad<AggregatedRenderPassDrawQuad>();
2726 mask_quad->SetNew(
2727 root_pass_shared_state, viewport_rect, viewport_rect, child_pass_id,
2728 mapped_mask_resource_id,
2729 gfx::ScaleRect(gfx::RectF(viewport_rect), 1.f / mask_rect.width(),
2730 1.f / mask_rect.height()), // mask_uv_rect
2731 gfx::Size(mask_rect.size()), // mask_texture_size
2732 gfx::Vector2dF(), // filters scale
2733 gfx::PointF(), // filter origin
2734 gfx::RectF(viewport_rect), // tex_coord_rect
2735 false, // force_anti_aliasing_off
2736 1.0f); // backdrop_filter_quality
2737 // White background behind the masked render pass.
2738 auto* white = root_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
2739 white->SetNew(root_pass_shared_state, viewport_rect, viewport_rect,
2740 SK_ColorWHITE, false);
2741
2742 AggregatedRenderPassList pass_list;
2743 pass_list.push_back(std::move(child_pass));
2744 pass_list.push_back(std::move(root_pass));
2745
2746 // The rounded corners generated by masks should be very close to the rounded
2747 // corners generated by the fragment shader approach. The percentage of pixel
2748 // mismatch is around 0.52%.
2749 EXPECT_TRUE(this->RunPixelTest(
2750 &pass_list,
2751 base::FilePath(FILE_PATH_LITERAL("rounded_corner_simple.png")),
2752 cc::FuzzyPixelComparator(true, 0.6f, 0.f, 255.f, 255, 0)));
2753 }
2754
TEST_P(RendererPixelTest,RenderPassAndMaskForRoundedCornerMultiRadii)2755 TEST_P(RendererPixelTest, RenderPassAndMaskForRoundedCornerMultiRadii) {
2756 gfx::Rect viewport_rect(this->device_viewport_size_);
2757 constexpr int kInset = 20;
2758 const SkVector kCornerRadii[4] = {
2759 SkVector::Make(5.0, 5.0),
2760 SkVector::Make(15.0, 15.0),
2761 SkVector::Make(25.0, 25.0),
2762 SkVector::Make(35.0, 35.0),
2763 };
2764
2765 AggregatedRenderPassId root_pass_id{1};
2766 auto root_pass = CreateTestRootRenderPass(root_pass_id, viewport_rect);
2767 SharedQuadState* root_pass_shared_state = CreateTestSharedQuadState(
2768 gfx::Transform(), viewport_rect, root_pass.get(), gfx::RRectF());
2769
2770 AggregatedRenderPassId child_pass_id{2};
2771 gfx::Transform transform_to_root;
2772 auto child_pass =
2773 CreateTestRenderPass(child_pass_id, viewport_rect, transform_to_root);
2774 SharedQuadState* child_pass_shared_state = CreateTestSharedQuadState(
2775 gfx::Transform(), viewport_rect, child_pass.get(), gfx::RRectF());
2776
2777 // The child render pass is half a blue box and other half yellow box.
2778 gfx::Rect blue_rect(0, 0, this->device_viewport_size_.width(),
2779 this->device_viewport_size_.height() / 2);
2780 auto* blue = child_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
2781 blue->SetNew(child_pass_shared_state, blue_rect, blue_rect, SK_ColorBLUE,
2782 false);
2783
2784 gfx::Rect yellow_rect(0, this->device_viewport_size_.height() / 2,
2785 this->device_viewport_size_.width(),
2786 this->device_viewport_size_.height() / 2);
2787 auto* yellow = child_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
2788 yellow->SetNew(child_pass_shared_state, yellow_rect, yellow_rect,
2789 SK_ColorYELLOW, false);
2790
2791 // Make a mask.
2792 gfx::Rect mask_rect = viewport_rect;
2793 SkBitmap bitmap;
2794 bitmap.allocPixels(
2795 SkImageInfo::MakeN32Premul(mask_rect.width(), mask_rect.height()));
2796 cc::SkiaPaintCanvas canvas(bitmap);
2797 cc::PaintFlags flags;
2798 flags.setStyle(cc::PaintFlags::kFill_Style);
2799 flags.setColor(SK_ColorWHITE);
2800 flags.setAntiAlias(true);
2801 canvas.clear(SK_ColorTRANSPARENT);
2802 gfx::Rect rounded_corner_rect = mask_rect;
2803 rounded_corner_rect.Inset(kInset, kInset);
2804 SkRRect rounded_corner =
2805 SkRRect::MakeRect(gfx::RectToSkRect(rounded_corner_rect));
2806 rounded_corner.setRectRadii(rounded_corner.rect(), kCornerRadii);
2807 canvas.drawRRect(rounded_corner, flags);
2808
2809 ResourceId mask_resource_id;
2810 if (!is_software_renderer()) {
2811 mask_resource_id = CreateGpuResource(
2812 this->child_context_provider_, this->child_resource_provider_.get(),
2813 mask_rect.size(), RGBA_8888, gfx::ColorSpace(), MakePixelSpan(bitmap));
2814 } else {
2815 mask_resource_id =
2816 this->AllocateAndFillSoftwareResource(mask_rect.size(), bitmap);
2817 }
2818
2819 // Return the mapped resource id.
2820 std::unordered_map<ResourceId, ResourceId> resource_map =
2821 cc::SendResourceAndGetChildToParentMap(
2822 {mask_resource_id}, this->resource_provider_.get(),
2823 this->child_resource_provider_.get(),
2824 this->child_context_provider_.get());
2825 ResourceId mapped_mask_resource_id = resource_map[mask_resource_id];
2826
2827 // Set up a mask on the AggregatedRenderPassDrawQuad.
2828 auto* mask_quad =
2829 root_pass->CreateAndAppendDrawQuad<AggregatedRenderPassDrawQuad>();
2830 mask_quad->SetNew(
2831 root_pass_shared_state, viewport_rect, viewport_rect, child_pass_id,
2832 mapped_mask_resource_id,
2833 gfx::ScaleRect(gfx::RectF(viewport_rect), 1.f / mask_rect.width(),
2834 1.f / mask_rect.height()), // mask_uv_rect
2835 gfx::Size(mask_rect.size()), // mask_texture_size
2836 gfx::Vector2dF(), // filters scale
2837 gfx::PointF(), // filter origin
2838 gfx::RectF(viewport_rect), // tex_coord_rect
2839 false, // force_anti_aliasing_off
2840 1.0f); // backdrop_filter_quality
2841 // White background behind the masked render pass.
2842 auto* white = root_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
2843 white->SetNew(root_pass_shared_state, viewport_rect, viewport_rect,
2844 SK_ColorWHITE, false);
2845
2846 AggregatedRenderPassList pass_list;
2847 pass_list.push_back(std::move(child_pass));
2848 pass_list.push_back(std::move(root_pass));
2849
2850 EXPECT_TRUE(this->RunPixelTest(
2851 &pass_list,
2852 base::FilePath(FILE_PATH_LITERAL("rounded_corner_multi_radii.png")),
2853 cc::FuzzyPixelComparator(true, 0.6f, 0.f, 255.f, 255, 0)));
2854 }
2855
2856 class RendererPixelTestWithBackdropFilter : public VizPixelTestWithParam {
2857 protected:
SetUpRenderPassList()2858 void SetUpRenderPassList() {
2859 gfx::Rect device_viewport_rect(this->device_viewport_size_);
2860
2861 AggregatedRenderPassId root_id{1};
2862 auto root_pass = CreateTestRootRenderPass(root_id, device_viewport_rect);
2863 root_pass->has_transparent_background = false;
2864
2865 gfx::Transform identity_quad_to_target_transform;
2866
2867 AggregatedRenderPassId filter_pass_id{2};
2868 gfx::Transform transform_to_root;
2869 auto filter_pass = CreateTestRenderPass(
2870 filter_pass_id, filter_pass_layer_rect_, transform_to_root);
2871 filter_pass->backdrop_filters = this->backdrop_filters_;
2872 filter_pass->backdrop_filter_bounds = this->backdrop_filter_bounds_;
2873
2874 // A non-visible quad in the filtering render pass.
2875 {
2876 SharedQuadState* shared_state = CreateTestSharedQuadState(
2877 identity_quad_to_target_transform, filter_pass_layer_rect_,
2878 filter_pass.get(), gfx::RRectF());
2879 auto* color_quad =
2880 filter_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
2881 color_quad->SetNew(shared_state, filter_pass_layer_rect_,
2882 filter_pass_layer_rect_, SK_ColorTRANSPARENT, false);
2883 }
2884
2885 ResourceId mapped_mask_resource_id = 0;
2886 gfx::RectF mask_uv_rect;
2887 gfx::Size mask_texture_size;
2888 if (include_backdrop_mask_) {
2889 // Make a mask.
2890 gfx::Rect viewport_rect(this->device_viewport_size_);
2891 constexpr int kInset = 20;
2892 const SkVector kCornerRadii[4] = {
2893 SkVector::Make(5.0, 5.0),
2894 SkVector::Make(15.0, 15.0),
2895 SkVector::Make(25.0, 25.0),
2896 SkVector::Make(35.0, 35.0),
2897 };
2898 gfx::Rect mask_rect = viewport_rect;
2899 SkBitmap bitmap;
2900 bitmap.allocPixels(
2901 SkImageInfo::MakeN32Premul(mask_rect.width(), mask_rect.height()));
2902 cc::SkiaPaintCanvas canvas(bitmap);
2903 cc::PaintFlags flags;
2904 flags.setStyle(cc::PaintFlags::kFill_Style);
2905 flags.setColor(SK_ColorWHITE);
2906 flags.setAntiAlias(true);
2907 canvas.clear(SK_ColorTRANSPARENT);
2908 gfx::Rect rounded_corner_rect = mask_rect;
2909 rounded_corner_rect.Inset(kInset, kInset);
2910 SkRRect rounded_corner =
2911 SkRRect::MakeRect(gfx::RectToSkRect(rounded_corner_rect));
2912 rounded_corner.setRectRadii(rounded_corner.rect(), kCornerRadii);
2913 canvas.drawRRect(rounded_corner, flags);
2914
2915 ResourceId mask_resource_id;
2916 if (!is_software_renderer()) {
2917 mask_resource_id = CreateGpuResource(
2918 this->child_context_provider_, this->child_resource_provider_.get(),
2919 mask_rect.size(), RGBA_8888, gfx::ColorSpace(),
2920 MakePixelSpan(bitmap));
2921 } else {
2922 mask_resource_id =
2923 this->AllocateAndFillSoftwareResource(mask_rect.size(), bitmap);
2924 }
2925
2926 // Return the mapped resource id.
2927 std::unordered_map<ResourceId, ResourceId> resource_map =
2928 cc::SendResourceAndGetChildToParentMap(
2929 {mask_resource_id}, this->resource_provider_.get(),
2930 this->child_resource_provider_.get(),
2931 this->child_context_provider_.get());
2932 mapped_mask_resource_id = resource_map[mask_resource_id];
2933
2934 mask_uv_rect =
2935 gfx::ScaleRect(gfx::RectF(viewport_rect), 1.f / mask_rect.width(),
2936 1.f / mask_rect.height()), // mask_uv_rect
2937 mask_texture_size = gfx::Size(mask_rect.size());
2938 }
2939
2940 {
2941 SharedQuadState* shared_state = CreateTestSharedQuadState(
2942 filter_pass_to_target_transform_, filter_pass_layer_rect_,
2943 filter_pass.get(), gfx::RRectF());
2944 auto* filter_pass_quad =
2945 root_pass->CreateAndAppendDrawQuad<AggregatedRenderPassDrawQuad>();
2946 filter_pass_quad->SetNew(shared_state, filter_pass_layer_rect_,
2947 filter_pass_layer_rect_, filter_pass_id,
2948 mapped_mask_resource_id, mask_uv_rect,
2949 mask_texture_size,
2950 gfx::Vector2dF(1.0f, 1.0f), // filters_scale
2951 gfx::PointF(), // filters_origin
2952 gfx::RectF(), // tex_coord_rect
2953 false, // force_anti_aliasing_off
2954 1.0f); // backdrop_filter_quality
2955 }
2956
2957 const int kColumnWidth = device_viewport_rect.width() / 3;
2958
2959 gfx::Rect left_rect = gfx::Rect(0, 0, kColumnWidth, 20);
2960 for (int i = 0; left_rect.y() < device_viewport_rect.height(); ++i) {
2961 SharedQuadState* shared_state =
2962 CreateTestSharedQuadState(identity_quad_to_target_transform,
2963 left_rect, root_pass.get(), gfx::RRectF());
2964 auto* color_quad =
2965 root_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
2966 color_quad->SetNew(shared_state, left_rect, left_rect, SK_ColorGREEN,
2967 false);
2968 left_rect += gfx::Vector2d(0, left_rect.height() + 1);
2969 }
2970
2971 gfx::Rect middle_rect = gfx::Rect(kColumnWidth + 1, 0, kColumnWidth, 20);
2972 for (int i = 0; middle_rect.y() < device_viewport_rect.height(); ++i) {
2973 SharedQuadState* shared_state = CreateTestSharedQuadState(
2974 identity_quad_to_target_transform, middle_rect, root_pass.get(),
2975 gfx::RRectF());
2976 auto* color_quad =
2977 root_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
2978 color_quad->SetNew(shared_state, middle_rect, middle_rect, SK_ColorRED,
2979 false);
2980 middle_rect += gfx::Vector2d(0, middle_rect.height() + 1);
2981 }
2982
2983 gfx::Rect right_rect =
2984 gfx::Rect((kColumnWidth + 1) * 2, 0, kColumnWidth, 20);
2985 for (int i = 0; right_rect.y() < device_viewport_rect.height(); ++i) {
2986 SharedQuadState* shared_state =
2987 CreateTestSharedQuadState(identity_quad_to_target_transform,
2988 right_rect, root_pass.get(), gfx::RRectF());
2989 auto* color_quad =
2990 root_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
2991 color_quad->SetNew(shared_state, right_rect, right_rect, SK_ColorBLUE,
2992 false);
2993 right_rect += gfx::Vector2d(0, right_rect.height() + 1);
2994 }
2995
2996 SharedQuadState* shared_state = CreateTestSharedQuadState(
2997 identity_quad_to_target_transform, device_viewport_rect,
2998 root_pass.get(), gfx::RRectF());
2999 auto* background_quad =
3000 root_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
3001 background_quad->SetNew(shared_state, device_viewport_rect,
3002 device_viewport_rect, SK_ColorWHITE, false);
3003
3004 pass_list_.push_back(std::move(filter_pass));
3005 pass_list_.push_back(std::move(root_pass));
3006 }
3007
3008 AggregatedRenderPassList pass_list_;
3009 cc::FilterOperations backdrop_filters_;
3010 base::Optional<gfx::RRectF> backdrop_filter_bounds_;
3011 bool include_backdrop_mask_ = false;
3012 gfx::Transform filter_pass_to_target_transform_;
3013 gfx::Rect filter_pass_layer_rect_;
3014 };
3015
3016 INSTANTIATE_TEST_SUITE_P(,
3017 RendererPixelTestWithBackdropFilter,
3018 testing::ValuesIn(GetRendererTypes()),
3019 testing::PrintToStringParamName());
3020
TEST_P(RendererPixelTestWithBackdropFilter,InvertFilter)3021 TEST_P(RendererPixelTestWithBackdropFilter, InvertFilter) {
3022 this->backdrop_filters_.Append(cc::FilterOperation::CreateInvertFilter(1.f));
3023 this->filter_pass_layer_rect_ = gfx::Rect(this->device_viewport_size_);
3024 this->filter_pass_layer_rect_.Inset(12, 14, 16, 18);
3025 this->backdrop_filter_bounds_ =
3026 gfx::RRectF(gfx::RectF(this->filter_pass_layer_rect_));
3027 this->SetUpRenderPassList();
3028 EXPECT_TRUE(this->RunPixelTest(
3029 &this->pass_list_,
3030 base::FilePath(FILE_PATH_LITERAL("backdrop_filter.png")),
3031 cc::ExactPixelComparator(true)));
3032 }
3033
TEST_P(RendererPixelTestWithBackdropFilter,InvertFilterWithMask)3034 TEST_P(RendererPixelTestWithBackdropFilter, InvertFilterWithMask) {
3035 // TODO(989312): The mask on gl_renderer and software_renderer appears to be
3036 // offset from the correct location.
3037 if (is_gl_renderer() || is_software_renderer())
3038 return;
3039 this->backdrop_filters_.Append(cc::FilterOperation::CreateInvertFilter(1.f));
3040 this->filter_pass_layer_rect_ = gfx::Rect(this->device_viewport_size_);
3041 this->filter_pass_layer_rect_.Inset(12, 14, 16, 18);
3042 this->backdrop_filter_bounds_ =
3043 gfx::RRectF(gfx::RectF(this->filter_pass_layer_rect_));
3044 this->include_backdrop_mask_ = true;
3045 this->SetUpRenderPassList();
3046 EXPECT_TRUE(this->RunPixelTest(
3047 &this->pass_list_,
3048 base::FilePath(FILE_PATH_LITERAL("backdrop_filter_masked.png")),
3049 cc::FuzzyPixelOffByOneComparator(false)));
3050 }
3051
3052 class GLRendererPixelTestWithBackdropFilter : public VizPixelTest {
3053 public:
GLRendererPixelTestWithBackdropFilter()3054 GLRendererPixelTestWithBackdropFilter() : VizPixelTest(RendererType::kGL) {}
3055
3056 protected:
SetUpRenderPassList()3057 void SetUpRenderPassList() {
3058 pass_list_.clear();
3059 gfx::Rect device_viewport_rect(this->device_viewport_size_);
3060
3061 AggregatedRenderPassId root_id{1};
3062 auto root_pass = CreateTestRootRenderPass(root_id, device_viewport_rect);
3063 root_pass->has_transparent_background = false;
3064
3065 gfx::Transform identity_quad_to_target_transform;
3066
3067 AggregatedRenderPassId filter_pass_id{2};
3068 gfx::Transform transform_to_root;
3069 auto filter_pass = CreateTestRenderPass(
3070 filter_pass_id, filter_pass_layer_rect_, transform_to_root);
3071 filter_pass->backdrop_filters = this->backdrop_filters_;
3072 filter_pass->backdrop_filter_bounds = this->backdrop_filter_bounds_;
3073
3074 // A non-visible quad in the filtering render pass.
3075 {
3076 SharedQuadState* shared_state = CreateTestSharedQuadState(
3077 identity_quad_to_target_transform, filter_pass_layer_rect_,
3078 filter_pass.get(), gfx::RRectF());
3079 auto* color_quad =
3080 filter_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
3081 color_quad->SetNew(shared_state, filter_pass_layer_rect_,
3082 filter_pass_layer_rect_, SK_ColorTRANSPARENT, false);
3083 }
3084
3085 {
3086 SharedQuadState* shared_state = CreateTestSharedQuadState(
3087 filter_pass_to_target_transform_, filter_pass_layer_rect_,
3088 filter_pass.get(), gfx::RRectF());
3089 auto* filter_pass_quad =
3090 root_pass->CreateAndAppendDrawQuad<AggregatedRenderPassDrawQuad>();
3091 filter_pass_quad->SetAll(
3092 shared_state, filter_pass_layer_rect_, filter_pass_layer_rect_,
3093 /*needs_blending=*/true, filter_pass_id, 0, gfx::RectF(), gfx::Size(),
3094 gfx::Vector2dF(1.0f, 1.0f), // filters_scale
3095 gfx::PointF(), // filters_origin
3096 gfx::RectF(), // tex_coord_rect
3097 false, // force_anti_aliasing_off
3098 backdrop_filter_quality_, // backdrop_filter_quality
3099 can_use_backdrop_filter_cache_);
3100 }
3101
3102 const int kGridWidth = device_viewport_rect.width() / 3;
3103 const int kGridHeight = device_viewport_rect.height() / 3;
3104 gfx::Rect left_rect =
3105 gfx::Rect(kGridWidth / 2, kGridHeight, kGridWidth, kGridHeight);
3106
3107 SharedQuadState* shared_state =
3108 CreateTestSharedQuadState(identity_quad_to_target_transform, left_rect,
3109 root_pass.get(), gfx::RRectF());
3110 auto* color_quad = root_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
3111 color_quad->SetNew(shared_state, left_rect, left_rect, SK_ColorGREEN,
3112 false);
3113
3114 gfx::Rect right_rect =
3115 gfx::Rect(kGridWidth * 3 / 2, kGridHeight, kGridWidth, kGridHeight);
3116 shared_state =
3117 CreateTestSharedQuadState(identity_quad_to_target_transform, right_rect,
3118 root_pass.get(), gfx::RRectF());
3119 color_quad = root_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
3120 color_quad->SetNew(shared_state, right_rect, right_rect, SK_ColorRED,
3121 false);
3122
3123 shared_state = CreateTestSharedQuadState(identity_quad_to_target_transform,
3124 device_viewport_rect,
3125 root_pass.get(), gfx::RRectF());
3126 auto* background_quad =
3127 root_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
3128 background_quad->SetNew(shared_state, device_viewport_rect,
3129 device_viewport_rect, SK_ColorWHITE, false);
3130
3131 pass_list_.push_back(std::move(filter_pass));
3132 pass_list_.push_back(std::move(root_pass));
3133 }
3134
3135 AggregatedRenderPassList pass_list_;
3136 cc::FilterOperations backdrop_filters_;
3137 base::Optional<gfx::RRectF> backdrop_filter_bounds_;
3138 float backdrop_filter_quality_ = 1.0f;
3139 bool can_use_backdrop_filter_cache_ = false;
3140 gfx::Transform filter_pass_to_target_transform_;
3141 gfx::Rect filter_pass_layer_rect_;
3142 };
3143
TEST_F(GLRendererPixelTestWithBackdropFilter,FilterQuality)3144 TEST_F(GLRendererPixelTestWithBackdropFilter, FilterQuality) {
3145 this->backdrop_filters_.Append(cc::FilterOperation::CreateBlurFilter(2.0f));
3146 this->filter_pass_layer_rect_ = gfx::Rect(this->device_viewport_size_);
3147 this->backdrop_filter_bounds_ =
3148 gfx::RRectF(gfx::RectF(this->filter_pass_layer_rect_));
3149 this->backdrop_filter_quality_ = 1.0f;
3150 this->SetUpRenderPassList();
3151 EXPECT_TRUE(this->RunPixelTest(
3152 &this->pass_list_,
3153 base::FilePath(FILE_PATH_LITERAL("gl_backdrop_filter_1.png")),
3154 cc::FuzzyPixelOffByOneComparator(true)));
3155 this->backdrop_filter_quality_ = 0.33f;
3156 this->SetUpRenderPassList();
3157 EXPECT_TRUE(this->RunPixelTest(
3158 &this->pass_list_,
3159 base::FilePath(FILE_PATH_LITERAL("gl_backdrop_filter_2.png")),
3160 cc::FuzzyPixelOffByOneComparator(true)));
3161 }
3162
TEST_F(GLRendererPixelTestWithBackdropFilter,CachedResultOfBackdropFilter)3163 TEST_F(GLRendererPixelTestWithBackdropFilter, CachedResultOfBackdropFilter) {
3164 this->backdrop_filters_.Append(cc::FilterOperation::CreateBlurFilter(2.0f));
3165 this->filter_pass_layer_rect_ = gfx::Rect(this->device_viewport_size_);
3166 this->backdrop_filter_bounds_ =
3167 gfx::RRectF(gfx::RectF(this->filter_pass_layer_rect_));
3168 // Set the flag to use cached backdrop filtered texture. This makes the
3169 // GLRenderer cache backdrop filtered result.
3170 this->can_use_backdrop_filter_cache_ = true;
3171 this->SetUpRenderPassList();
3172
3173 EXPECT_TRUE(this->RunPixelTest(
3174 &this->pass_list_,
3175 base::FilePath(FILE_PATH_LITERAL("gl_backdrop_filter_1.png")),
3176 cc::FuzzyPixelOffByOneComparator(true)));
3177
3178 // Same render pass list makes the GLRenderer to skip backdrop filter
3179 // calculation and use cached texture. This should correctly produce the
3180 // same output image.
3181 this->SetUpRenderPassList();
3182 EXPECT_TRUE(this->RunPixelTest(
3183 &this->pass_list_,
3184 base::FilePath(FILE_PATH_LITERAL("gl_backdrop_filter_1.png")),
3185 cc::FuzzyPixelOffByOneComparator(true)));
3186
3187 // To prove the cached texture is used, change a quad on the root pass which
3188 // is beneath the backdrop filter. The output image should still be the same
3189 // as before.
3190 this->SetUpRenderPassList();
3191 DrawQuad* background_quad = *pass_list_.back()->quad_list.rbegin();
3192 static_cast<SolidColorDrawQuad*>(background_quad)->color = SK_ColorYELLOW;
3193 EXPECT_TRUE(this->RunPixelTest(
3194 &this->pass_list_,
3195 base::FilePath(FILE_PATH_LITERAL("gl_backdrop_filter_1.png")),
3196 cc::FuzzyPixelOffByOneComparator(true)));
3197
3198 // Set|can_use_backdrop_filter_cache_| to false to make GLRenderer re-run the
3199 // backdrop filter calculation
3200 this->can_use_backdrop_filter_cache_ = false;
3201 this->SetUpRenderPassList();
3202 background_quad = *pass_list_.back()->quad_list.rbegin();
3203 static_cast<SolidColorDrawQuad*>(background_quad)->color = SK_ColorYELLOW;
3204 EXPECT_TRUE(this->RunPixelTest(
3205 &this->pass_list_,
3206 base::FilePath(FILE_PATH_LITERAL("gl_backdrop_filter_3.png")),
3207 cc::FuzzyPixelOffByOneComparator(true)));
3208 }
3209
3210 class ExternalStencilPixelTest : public VizPixelTestWithParam {
3211 protected:
ClearBackgroundToGreen()3212 void ClearBackgroundToGreen() {
3213 GLES2Interface* gl = this->output_surface_->context_provider()->ContextGL();
3214 this->output_surface_->EnsureBackbuffer();
3215 this->output_surface_->Reshape(this->device_viewport_size_, 1,
3216 gfx::ColorSpace(),
3217 gfx::BufferFormat::RGBA_8888, false);
3218 gl->ClearColor(0.f, 1.f, 0.f, 1.f);
3219 gl->Clear(GL_COLOR_BUFFER_BIT);
3220 }
3221
PopulateStencilBuffer()3222 void PopulateStencilBuffer() {
3223 // Set two quadrants of the stencil buffer to 1.
3224 GLES2Interface* gl = this->output_surface_->context_provider()->ContextGL();
3225 this->output_surface_->EnsureBackbuffer();
3226 this->output_surface_->Reshape(this->device_viewport_size_, 1,
3227 gfx::ColorSpace(),
3228 gfx::BufferFormat::RGBA_8888, false);
3229 gl->ClearStencil(0);
3230 gl->Clear(GL_STENCIL_BUFFER_BIT);
3231 gl->Enable(GL_SCISSOR_TEST);
3232 gl->ClearStencil(1);
3233 gl->Scissor(0, 0, this->device_viewport_size_.width() / 2,
3234 this->device_viewport_size_.height() / 2);
3235 gl->Clear(GL_STENCIL_BUFFER_BIT);
3236 gl->Scissor(this->device_viewport_size_.width() / 2,
3237 this->device_viewport_size_.height() / 2,
3238 this->device_viewport_size_.width(),
3239 this->device_viewport_size_.height());
3240 gl->Clear(GL_STENCIL_BUFFER_BIT);
3241 gl->StencilFunc(GL_EQUAL, 1, 1);
3242 }
3243 };
3244
3245 // TODO(crbug.com/939442): Enable these tests for SkiaRenderer.
3246 INSTANTIATE_TEST_SUITE_P(,
3247 ExternalStencilPixelTest,
3248 testing::Values(RendererType::kGL),
3249 testing::PrintToStringParamName());
3250
TEST_P(ExternalStencilPixelTest,StencilTestEnabled)3251 TEST_P(ExternalStencilPixelTest, StencilTestEnabled) {
3252 this->ClearBackgroundToGreen();
3253 this->PopulateStencilBuffer();
3254 this->EnableExternalStencilTest();
3255
3256 // Draw a blue quad that covers the entire device viewport. It should be
3257 // clipped to the bottom left and top right corners by the external stencil.
3258 gfx::Rect rect(this->device_viewport_size_);
3259 AggregatedRenderPassId id{1};
3260 auto pass = CreateTestRootRenderPass(id, rect);
3261 SharedQuadState* blue_shared_state = CreateTestSharedQuadState(
3262 gfx::Transform(), rect, pass.get(), gfx::RRectF());
3263 auto* blue = pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
3264 blue->SetNew(blue_shared_state, rect, rect, SK_ColorBLUE, false);
3265 pass->has_transparent_background = false;
3266 AggregatedRenderPassList pass_list;
3267 pass_list.push_back(std::move(pass));
3268
3269 EXPECT_TRUE(this->RunPixelTest(
3270 &pass_list,
3271 base::FilePath(FILE_PATH_LITERAL("four_blue_green_checkers.png")),
3272 cc::ExactPixelComparator(true)));
3273 }
3274
TEST_P(ExternalStencilPixelTest,StencilTestDisabled)3275 TEST_P(ExternalStencilPixelTest, StencilTestDisabled) {
3276 this->PopulateStencilBuffer();
3277
3278 // Draw a green quad that covers the entire device viewport. The stencil
3279 // buffer should be ignored.
3280 gfx::Rect rect(this->device_viewport_size_);
3281 AggregatedRenderPassId id{1};
3282 auto pass = CreateTestRootRenderPass(id, rect);
3283 SharedQuadState* green_shared_state = CreateTestSharedQuadState(
3284 gfx::Transform(), rect, pass.get(), gfx::RRectF());
3285 auto* green = pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
3286 green->SetNew(green_shared_state, rect, rect, SK_ColorGREEN, false);
3287 AggregatedRenderPassList pass_list;
3288 pass_list.push_back(std::move(pass));
3289
3290 EXPECT_TRUE(this->RunPixelTest(&pass_list,
3291 base::FilePath(FILE_PATH_LITERAL("green.png")),
3292 cc::ExactPixelComparator(true)));
3293 }
3294
TEST_P(ExternalStencilPixelTest,RenderSurfacesIgnoreStencil)3295 TEST_P(ExternalStencilPixelTest, RenderSurfacesIgnoreStencil) {
3296 // The stencil test should apply only to the final render pass.
3297 this->ClearBackgroundToGreen();
3298 this->PopulateStencilBuffer();
3299 this->EnableExternalStencilTest();
3300
3301 gfx::Rect viewport_rect(this->device_viewport_size_);
3302
3303 AggregatedRenderPassId root_pass_id{1};
3304 auto root_pass = CreateTestRootRenderPass(root_pass_id, viewport_rect);
3305 root_pass->has_transparent_background = false;
3306
3307 AggregatedRenderPassId child_pass_id{2};
3308 gfx::Rect pass_rect(this->device_viewport_size_);
3309 gfx::Transform transform_to_root;
3310 auto child_pass =
3311 CreateTestRenderPass(child_pass_id, pass_rect, transform_to_root);
3312
3313 gfx::Transform quad_to_target_transform;
3314 SharedQuadState* shared_state = CreateTestSharedQuadState(
3315 quad_to_target_transform, viewport_rect, child_pass.get(), gfx::RRectF());
3316
3317 gfx::Rect blue_rect(0, 0, this->device_viewport_size_.width(),
3318 this->device_viewport_size_.height());
3319 auto* blue = child_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
3320 blue->SetNew(shared_state, blue_rect, blue_rect, SK_ColorBLUE, false);
3321
3322 SharedQuadState* pass_shared_state = CreateTestSharedQuadState(
3323 gfx::Transform(), pass_rect, root_pass.get(), gfx::RRectF());
3324 CreateTestRenderPassDrawQuad(pass_shared_state, pass_rect, child_pass_id,
3325 root_pass.get());
3326 AggregatedRenderPassList pass_list;
3327 pass_list.push_back(std::move(child_pass));
3328 pass_list.push_back(std::move(root_pass));
3329
3330 EXPECT_TRUE(this->RunPixelTest(
3331 &pass_list,
3332 base::FilePath(FILE_PATH_LITERAL("four_blue_green_checkers.png")),
3333 cc::ExactPixelComparator(true)));
3334 }
3335
3336 // Software renderer does not support anti-aliased edges.
TEST_P(GPURendererPixelTest,AntiAliasing)3337 TEST_P(GPURendererPixelTest, AntiAliasing) {
3338 gfx::Rect rect(this->device_viewport_size_);
3339
3340 AggregatedRenderPassId id{1};
3341 auto pass = CreateTestRootRenderPass(id, rect);
3342
3343 gfx::Transform red_quad_to_target_transform;
3344 red_quad_to_target_transform.Rotate(10);
3345 SharedQuadState* red_shared_state = CreateTestSharedQuadState(
3346 red_quad_to_target_transform, rect, pass.get(), gfx::RRectF());
3347
3348 auto* red = pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
3349 red->SetNew(red_shared_state, rect, rect, SK_ColorRED, false);
3350
3351 gfx::Transform yellow_quad_to_target_transform;
3352 yellow_quad_to_target_transform.Rotate(5);
3353 SharedQuadState* yellow_shared_state = CreateTestSharedQuadState(
3354 yellow_quad_to_target_transform, rect, pass.get(), gfx::RRectF());
3355
3356 auto* yellow = pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
3357 yellow->SetNew(yellow_shared_state, rect, rect, SK_ColorYELLOW, false);
3358
3359 gfx::Transform blue_quad_to_target_transform;
3360 SharedQuadState* blue_shared_state = CreateTestSharedQuadState(
3361 blue_quad_to_target_transform, rect, pass.get(), gfx::RRectF());
3362
3363 auto* blue = pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
3364 blue->SetNew(blue_shared_state, rect, rect, SK_ColorBLUE, false);
3365
3366 AggregatedRenderPassList pass_list;
3367 pass_list.push_back(std::move(pass));
3368
3369 EXPECT_TRUE(
3370 this->RunPixelTest(&pass_list,
3371 base::FilePath(FILE_PATH_LITERAL("anti_aliasing_.png"))
3372 .InsertBeforeExtensionASCII(this->renderer_str()),
3373 cc::FuzzyPixelOffByOneComparator(true)));
3374 }
3375
3376 // Software renderer does not support anti-aliased edges.
TEST_P(GPURendererPixelTest,AntiAliasingPerspective)3377 TEST_P(GPURendererPixelTest, AntiAliasingPerspective) {
3378 gfx::Rect rect(this->device_viewport_size_);
3379
3380 auto pass = CreateTestRootRenderPass(AggregatedRenderPassId{1}, rect);
3381
3382 gfx::Rect red_rect(0, 0, 180, 500);
3383 gfx::Transform red_quad_to_target_transform(
3384 1.0f, 2.4520f, 10.6206f, 19.0f, 0.0f, 0.3528f, 5.9737f, 9.5f, 0.0f,
3385 -0.2250f, -0.9744f, 0.0f, 0.0f, 0.0225f, 0.0974f, 1.0f);
3386 SharedQuadState* red_shared_state = CreateTestSharedQuadState(
3387 red_quad_to_target_transform, red_rect, pass.get(), gfx::RRectF());
3388 auto* red = pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
3389 red->SetNew(red_shared_state, red_rect, red_rect, SK_ColorRED, false);
3390
3391 gfx::Rect green_rect(19, 7, 180, 10);
3392 SharedQuadState* green_shared_state = CreateTestSharedQuadState(
3393 gfx::Transform(), green_rect, pass.get(), gfx::RRectF());
3394 auto* green = pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
3395 green->SetNew(green_shared_state, green_rect, green_rect, SK_ColorGREEN,
3396 false);
3397
3398 SharedQuadState* blue_shared_state = CreateTestSharedQuadState(
3399 gfx::Transform(), rect, pass.get(), gfx::RRectF());
3400 auto* blue = pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
3401 blue->SetNew(blue_shared_state, rect, rect, SK_ColorBLUE, false);
3402
3403 AggregatedRenderPassList pass_list;
3404 pass_list.push_back(std::move(pass));
3405
3406 EXPECT_TRUE(this->RunPixelTest(
3407 &pass_list,
3408 base::FilePath(FILE_PATH_LITERAL("anti_aliasing_perspective_.png"))
3409 .InsertBeforeExtensionASCII(this->renderer_str()),
3410 cc::FuzzyPixelOffByOneComparator(true)));
3411 }
3412
3413 // This test tests that anti-aliasing works for axis aligned quads.
3414 // Anti-aliasing is only supported in the gl and skia renderers.
TEST_P(GPURendererPixelTest,AxisAligned)3415 TEST_P(GPURendererPixelTest, AxisAligned) {
3416 gfx::Rect rect(this->device_viewport_size_);
3417
3418 AggregatedRenderPassId id{1};
3419 gfx::Transform transform_to_root;
3420 auto pass = CreateTestRenderPass(id, rect, transform_to_root);
3421
3422 CreateTestAxisAlignedQuads(rect, SK_ColorRED, SK_ColorYELLOW, false, false,
3423 pass.get());
3424
3425 gfx::Transform blue_quad_to_target_transform;
3426 SharedQuadState* blue_shared_state = CreateTestSharedQuadState(
3427 blue_quad_to_target_transform, rect, pass.get(), gfx::RRectF());
3428
3429 auto* blue = pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
3430 blue->SetNew(blue_shared_state, rect, rect, SK_ColorBLUE, false);
3431
3432 AggregatedRenderPassList pass_list;
3433 pass_list.push_back(std::move(pass));
3434
3435 EXPECT_TRUE(this->RunPixelTest(
3436 &pass_list, base::FilePath(FILE_PATH_LITERAL("axis_aligned.png")),
3437 cc::FuzzyPixelOffByOneComparator(true)));
3438 }
3439
3440 // This test tests that forcing anti-aliasing off works as expected for
3441 // solid color draw quads.
3442 // Anti-aliasing is only supported in the gl and skia renderers.
TEST_P(GPURendererPixelTest,SolidColorDrawQuadForceAntiAliasingOff)3443 TEST_P(GPURendererPixelTest, SolidColorDrawQuadForceAntiAliasingOff) {
3444 gfx::Rect rect(this->device_viewport_size_);
3445
3446 AggregatedRenderPassId id{1};
3447 gfx::Transform transform_to_root;
3448 auto pass = CreateTestRenderPass(id, rect, transform_to_root);
3449 pass->has_transparent_background = false;
3450
3451 gfx::Transform hole_quad_to_target_transform;
3452 hole_quad_to_target_transform.Translate(50, 50);
3453 hole_quad_to_target_transform.Scale(0.5f + 1.0f / (rect.width() * 2.0f),
3454 0.5f + 1.0f / (rect.height() * 2.0f));
3455 SharedQuadState* hole_shared_state = CreateTestSharedQuadState(
3456 hole_quad_to_target_transform, rect, pass.get(), gfx::RRectF());
3457
3458 auto* hole = pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
3459 hole->SetAll(hole_shared_state, rect, rect, false, SK_ColorTRANSPARENT, true);
3460
3461 gfx::Transform green_quad_to_target_transform;
3462 SharedQuadState* green_shared_state = CreateTestSharedQuadState(
3463 green_quad_to_target_transform, rect, pass.get(), gfx::RRectF());
3464
3465 auto* green = pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
3466 green->SetNew(green_shared_state, rect, rect, SK_ColorGREEN, false);
3467
3468 AggregatedRenderPassList pass_list;
3469 pass_list.push_back(std::move(pass));
3470
3471 EXPECT_TRUE(this->RunPixelTest(
3472 &pass_list,
3473 base::FilePath(FILE_PATH_LITERAL("force_anti_aliasing_off.png")),
3474 cc::ExactPixelComparator(/*discard_alpha=*/true)));
3475 }
3476
3477 // This test tests that forcing anti-aliasing off works as expected for
3478 // render pass draw quads.
3479 // Anti-aliasing is only supported in the gl and skia renderers.
TEST_P(GPURendererPixelTest,RenderPassDrawQuadForceAntiAliasingOff)3480 TEST_P(GPURendererPixelTest, RenderPassDrawQuadForceAntiAliasingOff) {
3481 gfx::Rect rect(this->device_viewport_size_);
3482
3483 AggregatedRenderPassId root_pass_id{1};
3484 gfx::Transform transform_to_root;
3485 auto root_pass = CreateTestRenderPass(root_pass_id, rect, transform_to_root);
3486
3487 AggregatedRenderPassId child_pass_id{2};
3488 gfx::Transform child_pass_transform;
3489 auto child_pass =
3490 CreateTestRenderPass(child_pass_id, rect, child_pass_transform);
3491
3492 gfx::Transform quad_to_target_transform;
3493 SharedQuadState* hole_shared_state = CreateTestSharedQuadState(
3494 quad_to_target_transform, rect, child_pass.get(), gfx::RRectF());
3495 SolidColorDrawQuad* hole =
3496 child_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
3497 hole->SetAll(hole_shared_state, rect, rect, false, SK_ColorTRANSPARENT,
3498 false);
3499
3500 bool needs_blending = false;
3501 bool force_anti_aliasing_off = true;
3502 float backdrop_filter_quality = 1.0f;
3503 bool can_use_backdrop_filter_cache = false;
3504 gfx::Transform hole_pass_to_target_transform;
3505 hole_pass_to_target_transform.Translate(50, 50);
3506 hole_pass_to_target_transform.Scale(0.5f + 1.0f / (rect.width() * 2.0f),
3507 0.5f + 1.0f / (rect.height() * 2.0f));
3508 SharedQuadState* pass_shared_state = CreateTestSharedQuadState(
3509 hole_pass_to_target_transform, rect, root_pass.get(), gfx::RRectF());
3510 AggregatedRenderPassDrawQuad* pass_quad =
3511 root_pass->CreateAndAppendDrawQuad<AggregatedRenderPassDrawQuad>();
3512 pass_quad->SetAll(pass_shared_state, rect, rect, needs_blending,
3513 child_pass_id, 0, gfx::RectF(), gfx::Size(),
3514 gfx::Vector2dF(), gfx::PointF(), gfx::RectF(rect),
3515 force_anti_aliasing_off, backdrop_filter_quality,
3516 can_use_backdrop_filter_cache);
3517
3518 gfx::Transform green_quad_to_target_transform;
3519 SharedQuadState* green_shared_state = CreateTestSharedQuadState(
3520 green_quad_to_target_transform, rect, root_pass.get(), gfx::RRectF());
3521
3522 SolidColorDrawQuad* green =
3523 root_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
3524 green->SetNew(green_shared_state, rect, rect, SK_ColorGREEN, false);
3525
3526 AggregatedRenderPassList pass_list;
3527 pass_list.push_back(std::move(child_pass));
3528 pass_list.push_back(std::move(root_pass));
3529
3530 EXPECT_TRUE(this->RunPixelTest(
3531 &pass_list,
3532 base::FilePath(FILE_PATH_LITERAL("force_anti_aliasing_off.png")),
3533 cc::ExactPixelComparator(/*discard_alpha=*/true)));
3534 }
3535
3536 // This test tests that forcing anti-aliasing off works as expected for
3537 // tile draw quads.
3538 // Anti-aliasing is only supported in the gl and skia renderers.
TEST_P(GPURendererPixelTest,TileDrawQuadForceAntiAliasingOff)3539 TEST_P(GPURendererPixelTest, TileDrawQuadForceAntiAliasingOff) {
3540 gfx::Rect rect(this->device_viewport_size_);
3541
3542 SkBitmap bitmap;
3543 bitmap.allocN32Pixels(32, 32);
3544 SkCanvas canvas(bitmap, SkSurfaceProps{});
3545 canvas.clear(SK_ColorTRANSPARENT);
3546
3547 gfx::Size tile_size(32, 32);
3548 ResourceId resource;
3549 if (!is_software_renderer()) {
3550 resource = CreateGpuResource(
3551 this->child_context_provider_, this->child_resource_provider_.get(),
3552 tile_size, RGBA_8888, gfx::ColorSpace(), MakePixelSpan(bitmap));
3553 } else {
3554 resource = this->AllocateAndFillSoftwareResource(tile_size, bitmap);
3555 }
3556
3557 // Return the mapped resource id.
3558 std::unordered_map<ResourceId, ResourceId> resource_map =
3559 cc::SendResourceAndGetChildToParentMap(
3560 {resource}, this->resource_provider_.get(),
3561 this->child_resource_provider_.get(),
3562 this->child_context_provider_.get());
3563 ResourceId mapped_resource = resource_map[resource];
3564
3565 AggregatedRenderPassId id{1};
3566 gfx::Transform transform_to_root;
3567 auto pass = CreateTestRenderPass(id, rect, transform_to_root);
3568 pass->has_transparent_background = false;
3569
3570 bool contents_premultiplied = true;
3571 bool needs_blending = false;
3572 bool nearest_neighbor = true;
3573 bool force_anti_aliasing_off = true;
3574 gfx::Transform hole_quad_to_target_transform;
3575 hole_quad_to_target_transform.Translate(50, 50);
3576 hole_quad_to_target_transform.Scale(0.5f + 1.0f / (rect.width() * 2.0f),
3577 0.5f + 1.0f / (rect.height() * 2.0f));
3578 SharedQuadState* hole_shared_state = CreateTestSharedQuadState(
3579 hole_quad_to_target_transform, rect, pass.get(), gfx::RRectF());
3580 TileDrawQuad* hole = pass->CreateAndAppendDrawQuad<TileDrawQuad>();
3581 hole->SetNew(hole_shared_state, rect, rect, needs_blending, mapped_resource,
3582 gfx::RectF(gfx::Rect(tile_size)), tile_size,
3583 contents_premultiplied, nearest_neighbor,
3584 force_anti_aliasing_off);
3585
3586 gfx::Transform green_quad_to_target_transform;
3587 SharedQuadState* green_shared_state = CreateTestSharedQuadState(
3588 green_quad_to_target_transform, rect, pass.get(), gfx::RRectF());
3589
3590 SolidColorDrawQuad* green =
3591 pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
3592 green->SetNew(green_shared_state, rect, rect, SK_ColorGREEN, false);
3593
3594 AggregatedRenderPassList pass_list;
3595 pass_list.push_back(std::move(pass));
3596
3597 EXPECT_TRUE(this->RunPixelTest(
3598 &pass_list,
3599 base::FilePath(FILE_PATH_LITERAL("force_anti_aliasing_off.png")),
3600 cc::ExactPixelComparator(/*discard_alpha=*/true)));
3601 }
3602
3603 // This test tests that forcing anti-aliasing off works as expected while
3604 // blending is still enabled.
3605 // Anti-aliasing is only supported in the gl and skia renderers.
TEST_P(GPURendererPixelTest,BlendingWithoutAntiAliasing)3606 TEST_P(GPURendererPixelTest, BlendingWithoutAntiAliasing) {
3607 gfx::Rect rect(this->device_viewport_size_);
3608
3609 AggregatedRenderPassId id{1};
3610 gfx::Transform transform_to_root;
3611 auto pass = CreateTestRenderPass(id, rect, transform_to_root);
3612 pass->has_transparent_background = false;
3613
3614 CreateTestAxisAlignedQuads(rect, 0x800000FF, 0x8000FF00, true, true,
3615 pass.get());
3616
3617 SharedQuadState* background_quad_state = CreateTestSharedQuadState(
3618 gfx::Transform(), rect, pass.get(), gfx::RRectF());
3619 auto* background_quad = pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
3620 background_quad->SetNew(background_quad_state, rect, rect, SK_ColorBLACK,
3621 false);
3622
3623 AggregatedRenderPassList pass_list;
3624 pass_list.push_back(std::move(pass));
3625
3626 EXPECT_TRUE(this->RunPixelTest(
3627 &pass_list,
3628 base::FilePath(FILE_PATH_LITERAL("translucent_quads_no_aa.png")),
3629 cc::ExactPixelComparator(/*discard_alpha=*/true)));
3630 }
3631
3632 // Trilinear filtering is only supported in the gl renderer.
3633 // TODO(https://crbug.com/1044841): Flaky, especially on Linux/TSAN and Fuchsia.
TEST_P(GPURendererPixelTest,TrilinearFiltering)3634 TEST_P(GPURendererPixelTest, TrilinearFiltering) {
3635 gfx::Rect viewport_rect(this->device_viewport_size_);
3636
3637 AggregatedRenderPassId root_pass_id{1};
3638 auto root_pass = CreateTestRootRenderPass(root_pass_id, viewport_rect);
3639 root_pass->has_transparent_background = false;
3640
3641 AggregatedRenderPassId child_pass_id{2};
3642 gfx::Transform transform_to_root;
3643 gfx::Rect child_pass_rect(
3644 ScaleToCeiledSize(this->device_viewport_size_, 4.0f));
3645 bool generate_mipmap = true;
3646 auto child_pass = std::make_unique<AggregatedRenderPass>();
3647 child_pass->SetAll(
3648 child_pass_id, child_pass_rect, child_pass_rect, transform_to_root,
3649 cc::FilterOperations(), cc::FilterOperations(), gfx::RRectF(),
3650 gfx::ContentColorUsage::kSRGB, false, false, false, generate_mipmap);
3651
3652 gfx::Rect red_rect(child_pass_rect);
3653 // Small enough red rect that linear filtering will miss it but large enough
3654 // that it makes a meaningful contribution when using trilinear filtering.
3655 red_rect.ClampToCenteredSize(gfx::Size(2, child_pass_rect.height()));
3656 SharedQuadState* red_shared_state = CreateTestSharedQuadState(
3657 gfx::Transform(), red_rect, child_pass.get(), gfx::RRectF());
3658 auto* red = child_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
3659 red->SetNew(red_shared_state, red_rect, red_rect, SK_ColorRED, false);
3660
3661 SharedQuadState* blue_shared_state = CreateTestSharedQuadState(
3662 gfx::Transform(), child_pass_rect, child_pass.get(), gfx::RRectF());
3663 auto* blue = child_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
3664 blue->SetNew(blue_shared_state, child_pass_rect, child_pass_rect,
3665 SK_ColorBLUE, false);
3666
3667 gfx::Transform child_to_root_transform(SkMatrix::MakeRectToRect(
3668 RectToSkRect(child_pass_rect), RectToSkRect(viewport_rect),
3669 SkMatrix::kFill_ScaleToFit));
3670 SharedQuadState* child_pass_shared_state = CreateTestSharedQuadState(
3671 child_to_root_transform, child_pass_rect, root_pass.get(), gfx::RRectF());
3672 auto* child_pass_quad =
3673 root_pass->CreateAndAppendDrawQuad<AggregatedRenderPassDrawQuad>();
3674 child_pass_quad->SetNew(child_pass_shared_state, child_pass_rect,
3675 child_pass_rect, child_pass_id, 0, gfx::RectF(),
3676 gfx::Size(), gfx::Vector2dF(), gfx::PointF(),
3677 gfx::RectF(child_pass_rect), false, 1.0f);
3678
3679 AggregatedRenderPassList pass_list;
3680 pass_list.push_back(std::move(child_pass));
3681 pass_list.push_back(std::move(root_pass));
3682
3683 EXPECT_TRUE(this->RunPixelTest(
3684 &pass_list, base::FilePath(FILE_PATH_LITERAL("trilinear_filtering.png")),
3685 cc::ExactPixelComparator(true)));
3686 }
3687
3688 class SoftwareRendererPixelTest : public VizPixelTest {
3689 public:
SoftwareRendererPixelTest()3690 SoftwareRendererPixelTest() : VizPixelTest(RendererType::kSoftware) {}
3691 };
3692
TEST_F(SoftwareRendererPixelTest,PictureDrawQuadIdentityScale)3693 TEST_F(SoftwareRendererPixelTest, PictureDrawQuadIdentityScale) {
3694 gfx::Rect viewport(this->device_viewport_size_);
3695 // TODO(enne): the renderer should figure this out on its own.
3696 ResourceFormat texture_format = RGBA_8888;
3697 bool nearest_neighbor = false;
3698
3699 AggregatedRenderPassId id{1};
3700 gfx::Transform transform_to_root;
3701 auto pass = CreateTestRenderPass(id, viewport, transform_to_root);
3702
3703 // One clipped blue quad in the lower right corner. Outside the clip
3704 // is red, which should not appear.
3705 gfx::Rect blue_rect(gfx::Size(100, 100));
3706 gfx::Rect blue_clip_rect(gfx::Point(50, 50), gfx::Size(50, 50));
3707
3708 std::unique_ptr<cc::FakeRecordingSource> blue_recording =
3709 cc::FakeRecordingSource::CreateFilledRecordingSource(blue_rect.size());
3710 cc::PaintFlags red_flags;
3711 red_flags.setColor(SK_ColorRED);
3712 blue_recording->add_draw_rect_with_flags(blue_rect, red_flags);
3713 cc::PaintFlags blue_flags;
3714 blue_flags.setColor(SK_ColorBLUE);
3715 blue_recording->add_draw_rect_with_flags(blue_clip_rect, blue_flags);
3716 blue_recording->Rerecord();
3717
3718 scoped_refptr<cc::RasterSource> blue_raster_source =
3719 blue_recording->CreateRasterSource();
3720
3721 gfx::Vector2d offset(viewport.bottom_right() - blue_rect.bottom_right());
3722 bool needs_blending = true;
3723 gfx::Transform blue_quad_to_target_transform;
3724 blue_quad_to_target_transform.Translate(offset.x(), offset.y());
3725 gfx::Rect blue_target_clip_rect = cc::MathUtil::MapEnclosingClippedRect(
3726 blue_quad_to_target_transform, blue_clip_rect);
3727 SharedQuadState* blue_shared_state =
3728 CreateTestSharedQuadStateClipped(blue_quad_to_target_transform, blue_rect,
3729 blue_target_clip_rect, pass.get());
3730
3731 auto* blue_quad = pass->CreateAndAppendDrawQuad<PictureDrawQuad>();
3732
3733 blue_quad->SetNew(blue_shared_state,
3734 viewport, // Intentionally bigger than clip.
3735 viewport, needs_blending, gfx::RectF(viewport),
3736 viewport.size(), nearest_neighbor, texture_format, viewport,
3737 1.f, {}, blue_raster_source->GetDisplayItemList());
3738
3739 // One viewport-filling green quad.
3740 std::unique_ptr<cc::FakeRecordingSource> green_recording =
3741 cc::FakeRecordingSource::CreateFilledRecordingSource(viewport.size());
3742 cc::PaintFlags green_flags;
3743 green_flags.setColor(SK_ColorGREEN);
3744 green_recording->add_draw_rect_with_flags(viewport, green_flags);
3745 green_recording->Rerecord();
3746 scoped_refptr<cc::RasterSource> green_raster_source =
3747 green_recording->CreateRasterSource();
3748
3749 gfx::Transform green_quad_to_target_transform;
3750 SharedQuadState* green_shared_state = CreateTestSharedQuadState(
3751 green_quad_to_target_transform, viewport, pass.get(), gfx::RRectF());
3752
3753 auto* green_quad = pass->CreateAndAppendDrawQuad<PictureDrawQuad>();
3754 green_quad->SetNew(green_shared_state, viewport, viewport, needs_blending,
3755 gfx::RectF(0.f, 0.f, 1.f, 1.f), viewport.size(),
3756 nearest_neighbor, texture_format, viewport, 1.f, {},
3757 green_raster_source->GetDisplayItemList());
3758
3759 AggregatedRenderPassList pass_list;
3760 pass_list.push_back(std::move(pass));
3761
3762 EXPECT_TRUE(this->RunPixelTest(
3763 &pass_list,
3764 base::FilePath(FILE_PATH_LITERAL("green_with_blue_corner.png")),
3765 cc::ExactPixelComparator(true)));
3766 }
3767
3768 // Not WithSkiaGPUBackend since that path currently requires tiles for opacity.
TEST_F(SoftwareRendererPixelTest,PictureDrawQuadOpacity)3769 TEST_F(SoftwareRendererPixelTest, PictureDrawQuadOpacity) {
3770 gfx::Rect viewport(this->device_viewport_size_);
3771 bool needs_blending = true;
3772 ResourceFormat texture_format = RGBA_8888;
3773 bool nearest_neighbor = false;
3774
3775 AggregatedRenderPassId id{1};
3776 gfx::Transform transform_to_root;
3777 auto pass = CreateTestRenderPass(id, viewport, transform_to_root);
3778
3779 // One viewport-filling 0.5-opacity green quad.
3780 std::unique_ptr<cc::FakeRecordingSource> green_recording =
3781 cc::FakeRecordingSource::CreateFilledRecordingSource(viewport.size());
3782 cc::PaintFlags green_flags;
3783 green_flags.setColor(SK_ColorGREEN);
3784 green_recording->add_draw_rect_with_flags(viewport, green_flags);
3785 green_recording->Rerecord();
3786 scoped_refptr<cc::RasterSource> green_raster_source =
3787 green_recording->CreateRasterSource();
3788
3789 gfx::Transform green_quad_to_target_transform;
3790 SharedQuadState* green_shared_state = CreateTestSharedQuadState(
3791 green_quad_to_target_transform, viewport, pass.get(), gfx::RRectF());
3792 green_shared_state->opacity = 0.5f;
3793
3794 auto* green_quad = pass->CreateAndAppendDrawQuad<PictureDrawQuad>();
3795 green_quad->SetNew(green_shared_state, viewport, viewport, needs_blending,
3796 gfx::RectF(0, 0, 1, 1), viewport.size(), nearest_neighbor,
3797 texture_format, viewport, 1.f, {},
3798 green_raster_source->GetDisplayItemList());
3799
3800 // One viewport-filling white quad.
3801 std::unique_ptr<cc::FakeRecordingSource> white_recording =
3802 cc::FakeRecordingSource::CreateFilledRecordingSource(viewport.size());
3803 cc::PaintFlags white_flags;
3804 white_flags.setColor(SK_ColorWHITE);
3805 white_recording->add_draw_rect_with_flags(viewport, white_flags);
3806 white_recording->Rerecord();
3807 scoped_refptr<cc::RasterSource> white_raster_source =
3808 white_recording->CreateRasterSource();
3809
3810 gfx::Transform white_quad_to_target_transform;
3811 SharedQuadState* white_shared_state = CreateTestSharedQuadState(
3812 white_quad_to_target_transform, viewport, pass.get(), gfx::RRectF());
3813
3814 auto* white_quad = pass->CreateAndAppendDrawQuad<PictureDrawQuad>();
3815 white_quad->SetNew(white_shared_state, viewport, viewport, needs_blending,
3816 gfx::RectF(0, 0, 1, 1), viewport.size(), nearest_neighbor,
3817 texture_format, viewport, 1.f, {},
3818 white_raster_source->GetDisplayItemList());
3819
3820 AggregatedRenderPassList pass_list;
3821 pass_list.push_back(std::move(pass));
3822
3823 EXPECT_TRUE(this->RunPixelTest(
3824 &pass_list, base::FilePath(FILE_PATH_LITERAL("green_alpha.png")),
3825 cc::FuzzyPixelOffByOneComparator(true)));
3826 }
3827
TEST_F(SoftwareRendererPixelTest,PictureDrawQuadOpacityWithAlpha)3828 TEST_F(SoftwareRendererPixelTest, PictureDrawQuadOpacityWithAlpha) {
3829 gfx::Rect viewport(this->device_viewport_size_);
3830 bool needs_blending = true;
3831 ResourceFormat texture_format = RGBA_8888;
3832 bool nearest_neighbor = false;
3833
3834 AggregatedRenderPassId id{1};
3835 gfx::Transform transform_to_root;
3836 auto pass = CreateTestRenderPass(id, viewport, transform_to_root);
3837
3838 // One viewport-filling 0.5-opacity transparent quad.
3839 std::unique_ptr<cc::FakeRecordingSource> transparent_recording =
3840 cc::FakeRecordingSource::CreateFilledRecordingSource(viewport.size());
3841 cc::PaintFlags transparent_flags;
3842 transparent_flags.setColor(SK_ColorTRANSPARENT);
3843 transparent_recording->add_draw_rect_with_flags(viewport, transparent_flags);
3844 transparent_recording->Rerecord();
3845 scoped_refptr<cc::RasterSource> transparent_raster_source =
3846 transparent_recording->CreateRasterSource();
3847
3848 gfx::Transform transparent_quad_to_target_transform;
3849 SharedQuadState* transparent_shared_state =
3850 CreateTestSharedQuadState(transparent_quad_to_target_transform, viewport,
3851 pass.get(), gfx::RRectF());
3852 transparent_shared_state->opacity = 0.5f;
3853
3854 auto* transparent_quad = pass->CreateAndAppendDrawQuad<PictureDrawQuad>();
3855 transparent_quad->SetNew(
3856 transparent_shared_state, viewport, viewport, needs_blending,
3857 gfx::RectF(0, 0, 1, 1), viewport.size(), nearest_neighbor, texture_format,
3858 viewport, 1.f, {}, transparent_raster_source->GetDisplayItemList());
3859
3860 // One viewport-filling white quad.
3861 std::unique_ptr<cc::FakeRecordingSource> white_recording =
3862 cc::FakeRecordingSource::CreateFilledRecordingSource(viewport.size());
3863 cc::PaintFlags white_flags;
3864 white_flags.setColor(SK_ColorWHITE);
3865 white_recording->add_draw_rect_with_flags(viewport, white_flags);
3866 white_recording->Rerecord();
3867 scoped_refptr<cc::RasterSource> white_raster_source =
3868 white_recording->CreateRasterSource();
3869
3870 gfx::Transform white_quad_to_target_transform;
3871 SharedQuadState* white_shared_state = CreateTestSharedQuadState(
3872 white_quad_to_target_transform, viewport, pass.get(), gfx::RRectF());
3873
3874 auto* white_quad = pass->CreateAndAppendDrawQuad<PictureDrawQuad>();
3875 white_quad->SetNew(white_shared_state, viewport, viewport, needs_blending,
3876 gfx::RectF(0, 0, 1, 1), viewport.size(), nearest_neighbor,
3877 texture_format, viewport, 1.f, {},
3878 white_raster_source->GetDisplayItemList());
3879
3880 AggregatedRenderPassList pass_list;
3881 pass_list.push_back(std::move(pass));
3882
3883 EXPECT_TRUE(this->RunPixelTest(&pass_list,
3884 base::FilePath(FILE_PATH_LITERAL("white.png")),
3885 cc::FuzzyPixelOffByOneComparator(true)));
3886 }
3887
draw_point_color(SkCanvas * canvas,SkScalar x,SkScalar y,SkColor color)3888 void draw_point_color(SkCanvas* canvas, SkScalar x, SkScalar y, SkColor color) {
3889 SkPaint paint;
3890 paint.setColor(color);
3891 canvas->drawPoint(x, y, paint);
3892 }
3893
3894 // If we disable image filtering, then a 2x2 bitmap should appear as four
3895 // huge sharp squares.
TEST_F(SoftwareRendererPixelTest,PictureDrawQuadDisableImageFiltering)3896 TEST_F(SoftwareRendererPixelTest, PictureDrawQuadDisableImageFiltering) {
3897 gfx::Rect viewport(this->device_viewport_size_);
3898 ResourceFormat texture_format = RGBA_8888;
3899 bool needs_blending = true;
3900 bool nearest_neighbor = false;
3901
3902 AggregatedRenderPassId id{1};
3903 gfx::Transform transform_to_root;
3904 auto pass = CreateTestRenderPass(id, viewport, transform_to_root);
3905
3906 sk_sp<SkSurface> surface = SkSurface::MakeRasterN32Premul(2, 2);
3907 ASSERT_NE(surface, nullptr);
3908 SkCanvas* canvas = surface->getCanvas();
3909 draw_point_color(canvas, 0, 0, SK_ColorGREEN);
3910 draw_point_color(canvas, 0, 1, SK_ColorBLUE);
3911 draw_point_color(canvas, 1, 0, SK_ColorBLUE);
3912 draw_point_color(canvas, 1, 1, SK_ColorGREEN);
3913
3914 std::unique_ptr<cc::FakeRecordingSource> recording =
3915 cc::FakeRecordingSource::CreateFilledRecordingSource(viewport.size());
3916 cc::PaintFlags flags;
3917 flags.setFilterQuality(kLow_SkFilterQuality);
3918 recording->add_draw_image_with_flags(surface->makeImageSnapshot(),
3919 gfx::Point(), flags);
3920 recording->Rerecord();
3921 scoped_refptr<cc::RasterSource> raster_source =
3922 recording->CreateRasterSource();
3923
3924 gfx::Transform quad_to_target_transform;
3925 SharedQuadState* shared_state = CreateTestSharedQuadState(
3926 quad_to_target_transform, viewport, pass.get(), gfx::RRectF());
3927
3928 auto* quad = pass->CreateAndAppendDrawQuad<PictureDrawQuad>();
3929 quad->SetNew(shared_state, viewport, viewport, needs_blending,
3930 gfx::RectF(0, 0, 2, 2), viewport.size(), nearest_neighbor,
3931 texture_format, viewport, 1.f, {},
3932 raster_source->GetDisplayItemList());
3933
3934 AggregatedRenderPassList pass_list;
3935 pass_list.push_back(std::move(pass));
3936
3937 this->disable_picture_quad_image_filtering_ = true;
3938
3939 EXPECT_TRUE(this->RunPixelTest(
3940 &pass_list,
3941 base::FilePath(FILE_PATH_LITERAL("four_blue_green_checkers.png")),
3942 cc::ExactPixelComparator(true)));
3943 }
3944
3945 // This disables filtering by setting |nearest_neighbor| on the
3946 // PictureDrawQuad.
TEST_F(SoftwareRendererPixelTest,PictureDrawQuadNearestNeighbor)3947 TEST_F(SoftwareRendererPixelTest, PictureDrawQuadNearestNeighbor) {
3948 gfx::Rect viewport(this->device_viewport_size_);
3949 ResourceFormat texture_format = RGBA_8888;
3950 bool needs_blending = true;
3951 bool nearest_neighbor = true;
3952
3953 AggregatedRenderPassId id{1};
3954 gfx::Transform transform_to_root;
3955 auto pass = CreateTestRenderPass(id, viewport, transform_to_root);
3956
3957 sk_sp<SkSurface> surface = SkSurface::MakeRasterN32Premul(2, 2);
3958 ASSERT_NE(surface, nullptr);
3959 SkCanvas* canvas = surface->getCanvas();
3960 draw_point_color(canvas, 0, 0, SK_ColorGREEN);
3961 draw_point_color(canvas, 0, 1, SK_ColorBLUE);
3962 draw_point_color(canvas, 1, 0, SK_ColorBLUE);
3963 draw_point_color(canvas, 1, 1, SK_ColorGREEN);
3964
3965 std::unique_ptr<cc::FakeRecordingSource> recording =
3966 cc::FakeRecordingSource::CreateFilledRecordingSource(viewport.size());
3967 cc::PaintFlags flags;
3968 flags.setFilterQuality(kLow_SkFilterQuality);
3969 recording->add_draw_image_with_flags(surface->makeImageSnapshot(),
3970 gfx::Point(), flags);
3971 recording->Rerecord();
3972 scoped_refptr<cc::RasterSource> raster_source =
3973 recording->CreateRasterSource();
3974
3975 gfx::Transform quad_to_target_transform;
3976 SharedQuadState* shared_state = CreateTestSharedQuadState(
3977 quad_to_target_transform, viewport, pass.get(), gfx::RRectF());
3978
3979 auto* quad = pass->CreateAndAppendDrawQuad<PictureDrawQuad>();
3980 quad->SetNew(shared_state, viewport, viewport, needs_blending,
3981 gfx::RectF(0, 0, 2, 2), viewport.size(), nearest_neighbor,
3982 texture_format, viewport, 1.f, {},
3983 raster_source->GetDisplayItemList());
3984
3985 AggregatedRenderPassList pass_list;
3986 pass_list.push_back(std::move(pass));
3987
3988 EXPECT_TRUE(this->RunPixelTest(
3989 &pass_list,
3990 base::FilePath(FILE_PATH_LITERAL("four_blue_green_checkers.png")),
3991 cc::ExactPixelComparator(true)));
3992 }
3993
3994 // This disables filtering by setting |nearest_neighbor| on the
3995 // TileDrawQuad.
TEST_P(RendererPixelTest,TileDrawQuadNearestNeighbor)3996 TEST_P(RendererPixelTest, TileDrawQuadNearestNeighbor) {
3997 constexpr bool contents_premultiplied = true;
3998 constexpr bool needs_blending = true;
3999 constexpr bool nearest_neighbor = true;
4000 constexpr bool force_anti_aliasing_off = false;
4001 constexpr ResourceFormat resource_format = RGBA_8888;
4002 gfx::Rect viewport(this->device_viewport_size_);
4003
4004 SkColorType ct = ResourceFormatToClosestSkColorType(!is_software_renderer(),
4005 resource_format);
4006 SkImageInfo info = SkImageInfo::Make(2, 2, ct, kPremul_SkAlphaType);
4007 SkBitmap bitmap;
4008 bitmap.allocPixels(info);
4009 SkCanvas canvas(bitmap, SkSurfaceProps{});
4010 draw_point_color(&canvas, 0, 0, SK_ColorGREEN);
4011 draw_point_color(&canvas, 0, 1, SK_ColorBLUE);
4012 draw_point_color(&canvas, 1, 0, SK_ColorBLUE);
4013 draw_point_color(&canvas, 1, 1, SK_ColorGREEN);
4014
4015 gfx::Size tile_size(2, 2);
4016 ResourceId resource;
4017 if (!is_software_renderer()) {
4018 resource = CreateGpuResource(
4019 this->child_context_provider_, this->child_resource_provider_.get(),
4020 tile_size, RGBA_8888, gfx::ColorSpace(), MakePixelSpan(bitmap));
4021 } else {
4022 resource = this->AllocateAndFillSoftwareResource(tile_size, bitmap);
4023 }
4024 // Return the mapped resource id.
4025 std::unordered_map<ResourceId, ResourceId> resource_map =
4026 cc::SendResourceAndGetChildToParentMap(
4027 {resource}, this->resource_provider_.get(),
4028 this->child_resource_provider_.get(),
4029 this->child_context_provider_.get());
4030 ResourceId mapped_resource = resource_map[resource];
4031
4032 AggregatedRenderPassId id{1};
4033 gfx::Transform transform_to_root;
4034 auto pass = CreateTestRenderPass(id, viewport, transform_to_root);
4035
4036 gfx::Transform quad_to_target_transform;
4037 SharedQuadState* shared_state = CreateTestSharedQuadState(
4038 quad_to_target_transform, viewport, pass.get(), gfx::RRectF());
4039
4040 auto* quad = pass->CreateAndAppendDrawQuad<TileDrawQuad>();
4041 quad->SetNew(shared_state, viewport, viewport, needs_blending,
4042 mapped_resource, gfx::RectF(gfx::Rect(tile_size)), tile_size,
4043 contents_premultiplied, nearest_neighbor,
4044 force_anti_aliasing_off);
4045
4046 AggregatedRenderPassList pass_list;
4047 pass_list.push_back(std::move(pass));
4048
4049 EXPECT_TRUE(this->RunPixelTest(
4050 &pass_list,
4051 base::FilePath(FILE_PATH_LITERAL("four_blue_green_checkers.png")),
4052 cc::ExactPixelComparator(true)));
4053 }
4054
4055 // This disables filtering by setting |nearest_neighbor| to true on the
4056 // TextureDrawQuad.
TEST_F(SoftwareRendererPixelTest,TextureDrawQuadNearestNeighbor)4057 TEST_F(SoftwareRendererPixelTest, TextureDrawQuadNearestNeighbor) {
4058 gfx::Rect viewport(this->device_viewport_size_);
4059 bool needs_blending = true;
4060 bool nearest_neighbor = true;
4061
4062 SkBitmap bitmap;
4063 bitmap.allocN32Pixels(2, 2);
4064 SkCanvas canvas(bitmap, SkSurfaceProps{});
4065 draw_point_color(&canvas, 0, 0, SK_ColorGREEN);
4066 draw_point_color(&canvas, 0, 1, SK_ColorBLUE);
4067 draw_point_color(&canvas, 1, 0, SK_ColorBLUE);
4068 draw_point_color(&canvas, 1, 1, SK_ColorGREEN);
4069
4070 gfx::Size tile_size(2, 2);
4071 ResourceId resource =
4072 this->AllocateAndFillSoftwareResource(tile_size, bitmap);
4073
4074 // Return the mapped resource id.
4075 std::unordered_map<ResourceId, ResourceId> resource_map =
4076 cc::SendResourceAndGetChildToParentMap(
4077 {resource}, this->resource_provider_.get(),
4078 this->child_resource_provider_.get(),
4079 this->child_context_provider_.get());
4080 ResourceId mapped_resource = resource_map[resource];
4081
4082 AggregatedRenderPassId id{1};
4083 gfx::Transform transform_to_root;
4084 auto pass = CreateTestRenderPass(id, viewport, transform_to_root);
4085
4086 gfx::Transform quad_to_target_transform;
4087 SharedQuadState* shared_state = CreateTestSharedQuadState(
4088 quad_to_target_transform, viewport, pass.get(), gfx::RRectF());
4089
4090 float vertex_opacity[4] = {1.0f, 1.0f, 1.0f, 1.0f};
4091 auto* quad = pass->CreateAndAppendDrawQuad<TextureDrawQuad>();
4092 quad->SetNew(shared_state, viewport, viewport, needs_blending,
4093 mapped_resource, false, gfx::PointF(0, 0), gfx::PointF(1, 1),
4094 SK_ColorBLACK, vertex_opacity, false, nearest_neighbor,
4095 /*secure_output_only=*/false, gfx::ProtectedVideoType::kClear);
4096
4097 AggregatedRenderPassList pass_list;
4098 pass_list.push_back(std::move(pass));
4099
4100 EXPECT_TRUE(this->RunPixelTest(
4101 &pass_list,
4102 base::FilePath(FILE_PATH_LITERAL("four_blue_green_checkers.png")),
4103 cc::FuzzyPixelComparator(false, 2.f, 0.f, 256.f, 256, 0.f)));
4104 }
4105
4106 // This ensures filtering is enabled by setting |nearest_neighbor| to false on
4107 // the TextureDrawQuad.
TEST_F(SoftwareRendererPixelTest,TextureDrawQuadLinear)4108 TEST_F(SoftwareRendererPixelTest, TextureDrawQuadLinear) {
4109 gfx::Rect viewport(this->device_viewport_size_);
4110 bool needs_blending = true;
4111 bool nearest_neighbor = false;
4112
4113 SkBitmap bitmap;
4114 bitmap.allocN32Pixels(2, 2);
4115 {
4116 SkCanvas canvas(bitmap, SkSurfaceProps{});
4117 draw_point_color(&canvas, 0, 0, SK_ColorGREEN);
4118 draw_point_color(&canvas, 0, 1, SK_ColorBLUE);
4119 draw_point_color(&canvas, 1, 0, SK_ColorBLUE);
4120 draw_point_color(&canvas, 1, 1, SK_ColorGREEN);
4121 }
4122
4123 gfx::Size tile_size(2, 2);
4124 ResourceId resource =
4125 this->AllocateAndFillSoftwareResource(tile_size, bitmap);
4126
4127 // Return the mapped resource id.
4128 std::unordered_map<ResourceId, ResourceId> resource_map =
4129 cc::SendResourceAndGetChildToParentMap(
4130 {resource}, this->resource_provider_.get(),
4131 this->child_resource_provider_.get(),
4132 this->child_context_provider_.get());
4133 ResourceId mapped_resource = resource_map[resource];
4134
4135 AggregatedRenderPassId id{1};
4136 gfx::Transform transform_to_root;
4137 auto pass = CreateTestRenderPass(id, viewport, transform_to_root);
4138
4139 gfx::Transform quad_to_target_transform;
4140 SharedQuadState* shared_state = CreateTestSharedQuadState(
4141 quad_to_target_transform, viewport, pass.get(), gfx::RRectF());
4142
4143 float vertex_opacity[4] = {1.0f, 1.0f, 1.0f, 1.0f};
4144 auto* quad = pass->CreateAndAppendDrawQuad<TextureDrawQuad>();
4145 quad->SetNew(shared_state, viewport, viewport, needs_blending,
4146 mapped_resource, false, gfx::PointF(0, 0), gfx::PointF(1, 1),
4147 SK_ColorBLACK, vertex_opacity, false, nearest_neighbor,
4148 /*secure_output_only=*/false, gfx::ProtectedVideoType::kClear);
4149
4150 AggregatedRenderPassList pass_list;
4151 pass_list.push_back(std::move(pass));
4152
4153 // Allow for a small amount of error as the blending alogrithm used by Skia is
4154 // affected by the offset in the expanded rect.
4155 EXPECT_TRUE(this->RunPixelTest(
4156 &pass_list,
4157 base::FilePath(FILE_PATH_LITERAL("four_blue_green_checkers_linear.png")),
4158 cc::FuzzyPixelComparator(false, 100.f, 0.f, 16.f, 16.f, 0.f)));
4159 }
4160
TEST_F(SoftwareRendererPixelTest,PictureDrawQuadNonIdentityScale)4161 TEST_F(SoftwareRendererPixelTest, PictureDrawQuadNonIdentityScale) {
4162 gfx::Rect viewport(this->device_viewport_size_);
4163 // TODO(enne): the renderer should figure this out on its own.
4164 ResourceFormat texture_format = RGBA_8888;
4165 bool needs_blending = true;
4166 bool nearest_neighbor = false;
4167
4168 AggregatedRenderPassId id{1};
4169 gfx::Transform transform_to_root;
4170 auto pass = CreateTestRenderPass(id, viewport, transform_to_root);
4171
4172 // As scaling up the blue checkerboards will cause sampling on the GPU,
4173 // a few extra "cleanup rects" need to be added to clobber the blending
4174 // to make the output image more clean. This will also test subrects
4175 // of the layer.
4176 gfx::Transform green_quad_to_target_transform;
4177 gfx::Rect green_rect1(gfx::Point(80, 0), gfx::Size(20, 100));
4178 gfx::Rect green_rect2(gfx::Point(0, 80), gfx::Size(100, 20));
4179
4180 std::unique_ptr<cc::FakeRecordingSource> green_recording =
4181 cc::FakeRecordingSource::CreateFilledRecordingSource(viewport.size());
4182
4183 cc::PaintFlags red_flags;
4184 red_flags.setColor(SK_ColorRED);
4185 green_recording->add_draw_rect_with_flags(viewport, red_flags);
4186 cc::PaintFlags green_flags;
4187 green_flags.setColor(SK_ColorGREEN);
4188 green_recording->add_draw_rect_with_flags(green_rect1, green_flags);
4189 green_recording->add_draw_rect_with_flags(green_rect2, green_flags);
4190 green_recording->Rerecord();
4191 scoped_refptr<cc::RasterSource> green_raster_source =
4192 green_recording->CreateRasterSource();
4193
4194 SharedQuadState* top_right_green_shared_quad_state =
4195 CreateTestSharedQuadState(green_quad_to_target_transform, viewport,
4196 pass.get(), gfx::RRectF());
4197
4198 auto* green_quad1 = pass->CreateAndAppendDrawQuad<PictureDrawQuad>();
4199 green_quad1->SetNew(
4200 top_right_green_shared_quad_state, green_rect1, green_rect1,
4201 needs_blending, gfx::RectF(gfx::SizeF(green_rect1.size())),
4202 green_rect1.size(), nearest_neighbor, texture_format, green_rect1, 1.f,
4203 {}, green_raster_source->GetDisplayItemList());
4204
4205 auto* green_quad2 = pass->CreateAndAppendDrawQuad<PictureDrawQuad>();
4206 green_quad2->SetNew(
4207 top_right_green_shared_quad_state, green_rect2, green_rect2,
4208 needs_blending, gfx::RectF(gfx::SizeF(green_rect2.size())),
4209 green_rect2.size(), nearest_neighbor, texture_format, green_rect2, 1.f,
4210 {}, green_raster_source->GetDisplayItemList());
4211
4212 // Add a green clipped checkerboard in the bottom right to help test
4213 // interleaving picture quad content and solid color content.
4214 gfx::Rect bottom_right_rect(
4215 gfx::Point(viewport.width() / 2, viewport.height() / 2),
4216 gfx::Size(viewport.width() / 2, viewport.height() / 2));
4217 SharedQuadState* bottom_right_green_shared_state =
4218 CreateTestSharedQuadStateClipped(green_quad_to_target_transform, viewport,
4219 bottom_right_rect, pass.get());
4220 auto* bottom_right_color_quad =
4221 pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
4222 bottom_right_color_quad->SetNew(bottom_right_green_shared_state, viewport,
4223 viewport, SK_ColorGREEN, false);
4224
4225 // Add two blue checkerboards taking up the bottom left and top right,
4226 // but use content scales as content rects to make this happen.
4227 // The content is at a 4x content scale.
4228 gfx::Rect layer_rect(gfx::Size(20, 30));
4229 float contents_scale = 4.f;
4230 // Two rects that touch at their corners, arbitrarily placed in the layer.
4231 gfx::RectF blue_layer_rect1(gfx::PointF(5.5f, 9.0f), gfx::SizeF(2.5f, 2.5f));
4232 gfx::RectF blue_layer_rect2(gfx::PointF(8.0f, 6.5f), gfx::SizeF(2.5f, 2.5f));
4233 gfx::RectF union_layer_rect = blue_layer_rect1;
4234 union_layer_rect.Union(blue_layer_rect2);
4235
4236 // Because scaling up will cause sampling outside the rects, add one extra
4237 // pixel of buffer at the final content scale.
4238 float inset = -1.f / contents_scale;
4239 blue_layer_rect1.Inset(inset, inset, inset, inset);
4240 blue_layer_rect2.Inset(inset, inset, inset, inset);
4241
4242 std::unique_ptr<cc::FakeRecordingSource> recording =
4243 cc::FakeRecordingSource::CreateFilledRecordingSource(layer_rect.size());
4244
4245 cc::Region outside(layer_rect);
4246 outside.Subtract(gfx::ToEnclosingRect(union_layer_rect));
4247 for (gfx::Rect rect : outside) {
4248 recording->add_draw_rect_with_flags(rect, red_flags);
4249 }
4250
4251 cc::PaintFlags blue_flags;
4252 blue_flags.setColor(SK_ColorBLUE);
4253 recording->add_draw_rectf_with_flags(blue_layer_rect1, blue_flags);
4254 recording->add_draw_rectf_with_flags(blue_layer_rect2, blue_flags);
4255 recording->Rerecord();
4256 scoped_refptr<cc::RasterSource> raster_source =
4257 recording->CreateRasterSource();
4258
4259 gfx::Rect content_union_rect(
4260 gfx::ToEnclosingRect(gfx::ScaleRect(union_layer_rect, contents_scale)));
4261
4262 // At a scale of 4x the rectangles with a width of 2.5 will take up 10 pixels,
4263 // so scale an additional 10x to make them 100x100.
4264 gfx::Transform quad_to_target_transform;
4265 quad_to_target_transform.Scale(10.0, 10.0);
4266 gfx::Rect quad_content_rect(gfx::Size(20, 20));
4267 SharedQuadState* blue_shared_state = CreateTestSharedQuadState(
4268 quad_to_target_transform, quad_content_rect, pass.get(), gfx::RRectF());
4269
4270 auto* blue_quad = pass->CreateAndAppendDrawQuad<PictureDrawQuad>();
4271 blue_quad->SetNew(blue_shared_state, quad_content_rect, quad_content_rect,
4272 needs_blending, gfx::RectF(quad_content_rect),
4273 content_union_rect.size(), nearest_neighbor, texture_format,
4274 content_union_rect, contents_scale, {},
4275 raster_source->GetDisplayItemList());
4276
4277 // Fill left half of viewport with green.
4278 gfx::Transform half_green_quad_to_target_transform;
4279 gfx::Rect half_green_rect(gfx::Size(viewport.width() / 2, viewport.height()));
4280 SharedQuadState* half_green_shared_state =
4281 CreateTestSharedQuadState(half_green_quad_to_target_transform,
4282 half_green_rect, pass.get(), gfx::RRectF());
4283 auto* half_color_quad = pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
4284 half_color_quad->SetNew(half_green_shared_state, half_green_rect,
4285 half_green_rect, SK_ColorGREEN, false);
4286
4287 AggregatedRenderPassList pass_list;
4288 pass_list.push_back(std::move(pass));
4289
4290 EXPECT_TRUE(this->RunPixelTest(
4291 &pass_list,
4292 base::FilePath(FILE_PATH_LITERAL("four_blue_green_checkers.png")),
4293 cc::ExactPixelComparator(true)));
4294 }
4295
4296 class RendererPixelTestWithFlippedOutputSurface : public VizPixelTestWithParam {
4297 protected:
GetSurfaceOrigin() const4298 gfx::SurfaceOrigin GetSurfaceOrigin() const override {
4299 return gfx::SurfaceOrigin::kTopLeft;
4300 }
4301 };
4302
4303 INSTANTIATE_TEST_SUITE_P(,
4304 RendererPixelTestWithFlippedOutputSurface,
4305 testing::ValuesIn(GetGpuRendererTypes()),
4306 testing::PrintToStringParamName());
4307
TEST_P(RendererPixelTestWithFlippedOutputSurface,ExplicitFlipTest)4308 TEST_P(RendererPixelTestWithFlippedOutputSurface, ExplicitFlipTest) {
4309 // This draws a blue rect above a yellow rect with an inverted output surface.
4310 gfx::Rect viewport_rect(this->device_viewport_size_);
4311
4312 AggregatedRenderPassId root_pass_id{1};
4313 auto root_pass = CreateTestRootRenderPass(root_pass_id, viewport_rect);
4314
4315 AggregatedRenderPassId child_pass_id{2};
4316 gfx::Rect pass_rect(this->device_viewport_size_);
4317 gfx::Transform transform_to_root;
4318 auto child_pass =
4319 CreateTestRenderPass(child_pass_id, pass_rect, transform_to_root);
4320
4321 gfx::Transform quad_to_target_transform;
4322 SharedQuadState* shared_state = CreateTestSharedQuadState(
4323 quad_to_target_transform, viewport_rect, child_pass.get(), gfx::RRectF());
4324
4325 gfx::Rect blue_rect(0, 0, this->device_viewport_size_.width(),
4326 this->device_viewport_size_.height() / 2);
4327 auto* blue = child_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
4328 blue->SetNew(shared_state, blue_rect, blue_rect, SK_ColorBLUE, false);
4329 gfx::Rect yellow_rect(0, this->device_viewport_size_.height() / 2,
4330 this->device_viewport_size_.width(),
4331 this->device_viewport_size_.height() / 2);
4332 auto* yellow = child_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
4333 yellow->SetNew(shared_state, yellow_rect, yellow_rect, SK_ColorYELLOW, false);
4334
4335 SharedQuadState* pass_shared_state = CreateTestSharedQuadState(
4336 gfx::Transform(), pass_rect, root_pass.get(), gfx::RRectF());
4337 CreateTestRenderPassDrawQuad(pass_shared_state, pass_rect, child_pass_id,
4338 root_pass.get());
4339
4340 AggregatedRenderPassList pass_list;
4341 pass_list.push_back(std::move(child_pass));
4342 pass_list.push_back(std::move(root_pass));
4343
4344 // Note: RunPixelTest() will issue a CopyOutputRequest on the root pass. The
4345 // implementation should realize the output surface is flipped, and return a
4346 // right-side up result regardless (i.e., NOT blue_yellow_flipped.png).
4347 EXPECT_TRUE(this->RunPixelTest(
4348 &pass_list, base::FilePath(FILE_PATH_LITERAL("blue_yellow.png")),
4349 cc::FuzzyPixelOffByOneComparator(true)));
4350 }
4351
TEST_P(RendererPixelTestWithFlippedOutputSurface,CheckChildPassUnflipped)4352 TEST_P(RendererPixelTestWithFlippedOutputSurface, CheckChildPassUnflipped) {
4353 // This draws a blue rect above a yellow rect with an inverted output surface.
4354 gfx::Rect viewport_rect(this->device_viewport_size_);
4355
4356 AggregatedRenderPassId root_pass_id{1};
4357 auto root_pass = CreateTestRootRenderPass(root_pass_id, viewport_rect);
4358
4359 AggregatedRenderPassId child_pass_id{2};
4360 gfx::Rect pass_rect(this->device_viewport_size_);
4361 gfx::Transform transform_to_root;
4362 auto child_pass =
4363 CreateTestRenderPass(child_pass_id, pass_rect, transform_to_root);
4364
4365 gfx::Transform quad_to_target_transform;
4366 SharedQuadState* shared_state = CreateTestSharedQuadState(
4367 quad_to_target_transform, viewport_rect, child_pass.get(), gfx::RRectF());
4368
4369 gfx::Rect blue_rect(0, 0, this->device_viewport_size_.width(),
4370 this->device_viewport_size_.height() / 2);
4371 auto* blue = child_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
4372 blue->SetNew(shared_state, blue_rect, blue_rect, SK_ColorBLUE, false);
4373 gfx::Rect yellow_rect(0, this->device_viewport_size_.height() / 2,
4374 this->device_viewport_size_.width(),
4375 this->device_viewport_size_.height() / 2);
4376 auto* yellow = child_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
4377 yellow->SetNew(shared_state, yellow_rect, yellow_rect, SK_ColorYELLOW, false);
4378
4379 SharedQuadState* pass_shared_state = CreateTestSharedQuadState(
4380 gfx::Transform(), pass_rect, root_pass.get(), gfx::RRectF());
4381 CreateTestRenderPassDrawQuad(pass_shared_state, pass_rect, child_pass_id,
4382 root_pass.get());
4383
4384 AggregatedRenderPassList pass_list;
4385 pass_list.push_back(std::move(child_pass));
4386 pass_list.push_back(std::move(root_pass));
4387
4388 // Check that the child pass remains unflipped.
4389 EXPECT_TRUE(this->RunPixelTestWithReadbackTarget(
4390 &pass_list, pass_list.front().get(),
4391 base::FilePath(FILE_PATH_LITERAL("blue_yellow.png")),
4392 cc::ExactPixelComparator(true)));
4393 }
4394
TEST_P(GPURendererPixelTest,CheckReadbackSubset)4395 TEST_P(GPURendererPixelTest, CheckReadbackSubset) {
4396 gfx::Rect viewport_rect(this->device_viewport_size_);
4397
4398 AggregatedRenderPassId root_pass_id{1};
4399 auto root_pass = CreateTestRootRenderPass(root_pass_id, viewport_rect);
4400
4401 AggregatedRenderPassId child_pass_id{2};
4402 gfx::Rect pass_rect(this->device_viewport_size_);
4403 gfx::Transform transform_to_root;
4404 auto child_pass =
4405 CreateTestRenderPass(child_pass_id, pass_rect, transform_to_root);
4406
4407 gfx::Transform quad_to_target_transform;
4408 SharedQuadState* shared_state = CreateTestSharedQuadState(
4409 quad_to_target_transform, viewport_rect, child_pass.get(), gfx::RRectF());
4410
4411 // Draw a green quad full-size with a blue quad in the lower-right corner.
4412 gfx::Rect blue_rect(this->device_viewport_size_.width() * 3 / 4,
4413 this->device_viewport_size_.height() * 3 / 4,
4414 this->device_viewport_size_.width() * 3 / 4,
4415 this->device_viewport_size_.height() * 3 / 4);
4416 auto* blue = child_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
4417 blue->SetNew(shared_state, blue_rect, blue_rect, SK_ColorBLUE, false);
4418 gfx::Rect green_rect(0, 0, this->device_viewport_size_.width(),
4419 this->device_viewport_size_.height());
4420 auto* green = child_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
4421 green->SetNew(shared_state, green_rect, green_rect, SK_ColorGREEN, false);
4422
4423 SharedQuadState* pass_shared_state = CreateTestSharedQuadState(
4424 gfx::Transform(), pass_rect, root_pass.get(), gfx::RRectF());
4425 CreateTestRenderPassDrawQuad(pass_shared_state, pass_rect, child_pass_id,
4426 root_pass.get());
4427
4428 AggregatedRenderPassList pass_list;
4429 pass_list.push_back(std::move(child_pass));
4430 pass_list.push_back(std::move(root_pass));
4431
4432 // Check that the child pass remains unflipped.
4433 gfx::Rect capture_rect(this->device_viewport_size_.width() / 2,
4434 this->device_viewport_size_.height() / 2,
4435 this->device_viewport_size_.width() / 2,
4436 this->device_viewport_size_.height() / 2);
4437 EXPECT_TRUE(this->RunPixelTestWithReadbackTargetAndArea(
4438 &pass_list, pass_list.front().get(),
4439 base::FilePath(FILE_PATH_LITERAL("green_small_with_blue_corner.png")),
4440 cc::ExactPixelComparator(true), &capture_rect));
4441 }
4442
TEST_P(GPURendererPixelTest,TextureQuadBatching)4443 TEST_P(GPURendererPixelTest, TextureQuadBatching) {
4444 // This test verifies that multiple texture quads using the same resource
4445 // get drawn correctly. It implicitly is trying to test that the
4446 // GLRenderer does the right thing with its draw quad cache.
4447
4448 gfx::Rect rect(this->device_viewport_size_);
4449 bool needs_blending = false;
4450
4451 AggregatedRenderPassId id{1};
4452 auto pass = CreateTestRootRenderPass(id, rect);
4453
4454 SharedQuadState* shared_state = CreateTestSharedQuadState(
4455 gfx::Transform(), rect, pass.get(), gfx::RRectF());
4456
4457 // Make a mask.
4458 gfx::Rect mask_rect = rect;
4459 SkBitmap bitmap;
4460 bitmap.allocPixels(
4461 SkImageInfo::MakeN32Premul(mask_rect.width(), mask_rect.height()));
4462 SkCanvas canvas(bitmap, SkSurfaceProps{});
4463 SkPaint paint;
4464 paint.setStyle(SkPaint::kStroke_Style);
4465 paint.setStrokeWidth(SkIntToScalar(4));
4466 paint.setColor(SK_ColorGREEN);
4467 canvas.clear(SK_ColorWHITE);
4468 gfx::Rect inset_rect = rect;
4469 while (!inset_rect.IsEmpty()) {
4470 inset_rect.Inset(6, 6, 4, 4);
4471 canvas.drawRect(SkRect::MakeXYWH(inset_rect.x(), inset_rect.y(),
4472 inset_rect.width(), inset_rect.height()),
4473 paint);
4474 inset_rect.Inset(6, 6, 4, 4);
4475 }
4476
4477 ResourceId resource = CreateGpuResource(
4478 this->child_context_provider_, this->child_resource_provider_.get(),
4479 mask_rect.size(), RGBA_8888, gfx::ColorSpace(), MakePixelSpan(bitmap));
4480
4481 // Return the mapped resource id.
4482 std::unordered_map<ResourceId, ResourceId> resource_map =
4483 cc::SendResourceAndGetChildToParentMap(
4484 {resource}, this->resource_provider_.get(),
4485 this->child_resource_provider_.get(),
4486 this->child_context_provider_.get());
4487 ResourceId mapped_resource = resource_map[resource];
4488
4489 // Arbitrary dividing lengths to divide up the resource into 16 quads.
4490 int widths[] = {
4491 0, 60, 50, 40,
4492 };
4493 int heights[] = {
4494 0, 10, 80, 50,
4495 };
4496 size_t num_quads = 4;
4497 for (size_t i = 0; i < num_quads; ++i) {
4498 int x_start = widths[i];
4499 int x_end = i == num_quads - 1 ? rect.width() : widths[i + 1];
4500 DCHECK_LE(x_end, rect.width());
4501 for (size_t j = 0; j < num_quads; ++j) {
4502 int y_start = heights[j];
4503 int y_end = j == num_quads - 1 ? rect.height() : heights[j + 1];
4504 DCHECK_LE(y_end, rect.height());
4505
4506 float vertex_opacity[4] = {1.0f, 1.0f, 1.0f, 1.0f};
4507 gfx::Rect layer_rect(x_start, y_start, x_end - x_start, y_end - y_start);
4508 gfx::RectF uv_rect = gfx::ScaleRect(
4509 gfx::RectF(layer_rect), 1.f / rect.width(), 1.f / rect.height());
4510
4511 auto* texture_quad = pass->CreateAndAppendDrawQuad<TextureDrawQuad>();
4512 texture_quad->SetNew(
4513 shared_state, layer_rect, layer_rect, needs_blending, mapped_resource,
4514 true, uv_rect.origin(), uv_rect.bottom_right(), SK_ColorWHITE,
4515 vertex_opacity, false, false, /*secure_output_only=*/false,
4516 gfx::ProtectedVideoType::kClear);
4517 }
4518 }
4519
4520 AggregatedRenderPassList pass_list;
4521 pass_list.push_back(std::move(pass));
4522
4523 EXPECT_TRUE(this->RunPixelTest(
4524 &pass_list, base::FilePath(FILE_PATH_LITERAL("spiral.png")),
4525 cc::FuzzyPixelOffByOneComparator(true)));
4526 }
4527
TEST_P(GPURendererPixelTest,TileQuadClamping)4528 TEST_P(GPURendererPixelTest, TileQuadClamping) {
4529 gfx::Rect viewport(this->device_viewport_size_);
4530 bool contents_premultiplied = true;
4531 bool needs_blending = true;
4532 bool nearest_neighbor = false;
4533 bool use_aa = false;
4534
4535 gfx::Size layer_size(4, 4);
4536 gfx::Size tile_size(20, 20);
4537 gfx::Rect quad_rect(layer_size);
4538 gfx::RectF tex_coord_rect(quad_rect);
4539
4540 // tile sized bitmap, with valid contents green and contents outside the
4541 // layer rect red.
4542 SkBitmap bitmap;
4543 bitmap.allocN32Pixels(tile_size.width(), tile_size.height());
4544 SkCanvas canvas(bitmap, SkSurfaceProps{});
4545 SkPaint red;
4546 red.setColor(SK_ColorRED);
4547 canvas.drawRect(SkRect::MakeWH(tile_size.width(), tile_size.height()), red);
4548 SkPaint green;
4549 green.setColor(SK_ColorGREEN);
4550 canvas.drawRect(SkRect::MakeWH(layer_size.width(), layer_size.height()),
4551 green);
4552
4553 ResourceId resource;
4554 if (!is_software_renderer()) {
4555 resource = CreateGpuResource(
4556 this->child_context_provider_, this->child_resource_provider_.get(),
4557 tile_size, RGBA_8888, gfx::ColorSpace(), MakePixelSpan(bitmap));
4558 } else {
4559 resource = this->AllocateAndFillSoftwareResource(tile_size, bitmap);
4560 }
4561 // Return the mapped resource id.
4562 std::unordered_map<ResourceId, ResourceId> resource_map =
4563 cc::SendResourceAndGetChildToParentMap(
4564 {resource}, this->resource_provider_.get(),
4565 this->child_resource_provider_.get(),
4566 this->child_context_provider_.get());
4567 ResourceId mapped_resource = resource_map[resource];
4568
4569 AggregatedRenderPassId id{1};
4570 gfx::Transform transform_to_root;
4571 auto pass = CreateTestRenderPass(id, viewport, transform_to_root);
4572
4573 // Green quad that should not show any red pixels from outside the
4574 // tex coord rect.
4575 gfx::Transform transform;
4576 transform.Scale(40, 40);
4577 SharedQuadState* quad_shared = CreateTestSharedQuadState(
4578 transform, gfx::Rect(layer_size), pass.get(), gfx::RRectF());
4579 auto* quad = pass->CreateAndAppendDrawQuad<TileDrawQuad>();
4580 quad->SetNew(quad_shared, gfx::Rect(layer_size), gfx::Rect(layer_size),
4581 needs_blending, mapped_resource, tex_coord_rect, tile_size,
4582 contents_premultiplied, nearest_neighbor, use_aa);
4583
4584 // Green background.
4585 SharedQuadState* background_shared = CreateTestSharedQuadState(
4586 gfx::Transform(), viewport, pass.get(), gfx::RRectF());
4587 auto* color_quad = pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
4588 color_quad->SetNew(background_shared, viewport, viewport, SK_ColorGREEN,
4589 false);
4590
4591 AggregatedRenderPassList pass_list;
4592 pass_list.push_back(std::move(pass));
4593
4594 EXPECT_TRUE(this->RunPixelTest(&pass_list,
4595 base::FilePath(FILE_PATH_LITERAL("green.png")),
4596 cc::ExactPixelComparator(true)));
4597 }
4598
TEST_P(RendererPixelTest,RoundedCornerSimpleSolidDrawQuad)4599 TEST_P(RendererPixelTest, RoundedCornerSimpleSolidDrawQuad) {
4600 gfx::Rect viewport_rect(this->device_viewport_size_);
4601 constexpr int kInset = 20;
4602 constexpr int kCornerRadius = 20;
4603
4604 AggregatedRenderPassId root_pass_id{1};
4605 auto root_pass = CreateTestRootRenderPass(root_pass_id, viewport_rect);
4606
4607 gfx::Transform quad_to_target_transform;
4608 gfx::Rect blue_rect(0, 0, this->device_viewport_size_.width(),
4609 this->device_viewport_size_.height());
4610 gfx::Rect red_rect = blue_rect;
4611 blue_rect.Inset(kInset, kInset);
4612
4613 gfx::RRectF rounded_corner_rrect(gfx::RectF(blue_rect), kCornerRadius);
4614 SharedQuadState* shared_state_rounded =
4615 CreateTestSharedQuadState(quad_to_target_transform, viewport_rect,
4616 root_pass.get(), rounded_corner_rrect);
4617
4618 auto* blue = root_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
4619 blue->SetNew(shared_state_rounded, blue_rect, blue_rect, SK_ColorBLUE, false);
4620
4621 SharedQuadState* shared_state_normal = CreateTestSharedQuadState(
4622 quad_to_target_transform, viewport_rect, root_pass.get(), gfx::RRectF());
4623
4624 auto* white = root_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
4625 white->SetNew(shared_state_normal, red_rect, red_rect, SK_ColorWHITE, false);
4626
4627 AggregatedRenderPassList pass_list;
4628 pass_list.push_back(std::move(root_pass));
4629
4630 if (is_gl_renderer()) {
4631 // GL Renderer should have an exact match as that is the reference point.
4632 EXPECT_TRUE(this->RunPixelTest(
4633 &pass_list,
4634 base::FilePath(FILE_PATH_LITERAL("rounded_corner_simple.png")),
4635 cc::ExactPixelComparator(true)));
4636 } else {
4637 // Software/skia renderer uses skia rrect to create rounded corner clip.
4638 // This results in a different corner path due to a different anti aliasing
4639 // approach than the fragment shader in gl renderer.
4640 EXPECT_TRUE(this->RunPixelTest(
4641 &pass_list,
4642 base::FilePath(FILE_PATH_LITERAL("rounded_corner_simple.png")),
4643 cc::FuzzyPixelComparator(true, 0.55f, 0.f, 255.f, 255, 0)));
4644 }
4645 }
4646
TEST_P(GPURendererPixelTest,RoundedCornerSimpleTextureDrawQuad)4647 TEST_P(GPURendererPixelTest, RoundedCornerSimpleTextureDrawQuad) {
4648 gfx::Rect viewport_rect(this->device_viewport_size_);
4649 constexpr int kInset = 20;
4650 constexpr int kCornerRadius = 20;
4651
4652 AggregatedRenderPassId root_pass_id{1};
4653 auto root_pass = CreateTestRootRenderPass(root_pass_id, viewport_rect);
4654
4655 gfx::Transform quad_to_target_transform;
4656 gfx::Rect blue_rect(0, 0, this->device_viewport_size_.width(),
4657 this->device_viewport_size_.height());
4658 gfx::Rect red_rect = blue_rect;
4659 blue_rect.Inset(kInset, kInset);
4660
4661 gfx::RRectF rounded_corner_rrect(gfx::RectF(blue_rect), kCornerRadius);
4662 SharedQuadState* shared_state_rounded =
4663 CreateTestSharedQuadState(quad_to_target_transform, viewport_rect,
4664 root_pass.get(), rounded_corner_rrect);
4665
4666 const uint8_t colors[] = {0, 0, 255, 255, 0, 0, 255, 255,
4667 0, 0, 255, 255, 0, 0, 255, 255};
4668 ResourceId resource = CreateGpuResource(
4669 this->child_context_provider_, this->child_resource_provider_.get(),
4670 gfx::Size(2, 2), RGBA_8888, gfx::ColorSpace(), colors);
4671
4672 std::unordered_map<ResourceId, ResourceId> resource_map =
4673 cc::SendResourceAndGetChildToParentMap(
4674 {resource}, this->resource_provider_.get(),
4675 this->child_resource_provider_.get(),
4676 this->child_context_provider_.get());
4677 ResourceId mapped_resource = resource_map[resource];
4678 bool needs_blending = true;
4679 const gfx::PointF uv_top_left(0.0f, 0.0f);
4680 const gfx::PointF uv_bottom_right(1.0f, 1.0f);
4681 const bool flipped = false;
4682 const bool nearest_neighbor = false;
4683 auto* blue = root_pass->CreateAndAppendDrawQuad<TextureDrawQuad>();
4684 float vertex_opacity[4] = {1.0f, 1.0f, 1.0f, 1.0f};
4685 blue->SetNew(shared_state_rounded, blue_rect, blue_rect, needs_blending,
4686 mapped_resource, true, uv_top_left, uv_bottom_right,
4687 SK_ColorBLACK, vertex_opacity, flipped, nearest_neighbor,
4688 /*secure_output_only=*/false, gfx::ProtectedVideoType::kClear);
4689
4690 SharedQuadState* shared_state_normal = CreateTestSharedQuadState(
4691 quad_to_target_transform, viewport_rect, root_pass.get(), gfx::RRectF());
4692
4693 auto* white = root_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
4694 white->SetNew(shared_state_normal, red_rect, red_rect, SK_ColorWHITE, false);
4695
4696 AggregatedRenderPassList pass_list;
4697 pass_list.push_back(std::move(root_pass));
4698
4699 if (is_gl_renderer()) {
4700 // GL Renderer should have an exact match as that is the reference point.
4701 EXPECT_TRUE(this->RunPixelTest(
4702 &pass_list,
4703 base::FilePath(FILE_PATH_LITERAL("rounded_corner_simple.png")),
4704 cc::ExactPixelComparator(true)));
4705 } else {
4706 // SkiaRenderer uses skia rrect to create rounded corner clip. This results
4707 // in a different corner path due to a different anti aliasing approach than
4708 // the fragment shader in gl renderer.
4709 EXPECT_TRUE(this->RunPixelTest(
4710 &pass_list,
4711 base::FilePath(FILE_PATH_LITERAL("rounded_corner_simple.png")),
4712 cc::FuzzyPixelComparator(true, 0.6f, 0.f, 255.f, 255, 0)));
4713 }
4714 }
4715
4716 // TODO(https://crbug.com/1044841): Flaky, especially on Linux/TSAN and Fuchsia.
TEST_P(RendererPixelTest,DISABLED_RoundedCornerOnRenderPass)4717 TEST_P(RendererPixelTest, DISABLED_RoundedCornerOnRenderPass) {
4718 gfx::Rect viewport_rect(this->device_viewport_size_);
4719 constexpr int kInset = 20;
4720 constexpr int kCornerRadius = 20;
4721 constexpr int kBlueCornerRadius = 10;
4722
4723 AggregatedRenderPassId root_pass_id{1};
4724 auto root_pass = CreateTestRootRenderPass(root_pass_id, viewport_rect);
4725
4726 AggregatedRenderPassId child_pass_id{2};
4727 gfx::Rect pass_rect(this->device_viewport_size_);
4728 pass_rect.Inset(kInset, kInset);
4729 gfx::Rect child_pass_local_rect = gfx::Rect(pass_rect.size());
4730 gfx::Transform transform_to_root;
4731 transform_to_root.Translate(pass_rect.OffsetFromOrigin());
4732 auto child_pass = CreateTestRenderPass(child_pass_id, child_pass_local_rect,
4733 transform_to_root);
4734
4735 gfx::Rect blue_rect = child_pass_local_rect;
4736 gfx::Vector2dF blue_offset_from_target(-30, 40);
4737 gfx::RRectF blue_rrect(gfx::RectF(blue_rect), kBlueCornerRadius);
4738 blue_rrect.Offset(blue_offset_from_target);
4739 gfx::Transform quad_to_target_transform;
4740 quad_to_target_transform.Translate(blue_offset_from_target);
4741 SharedQuadState* shared_state_with_rrect =
4742 CreateTestSharedQuadState(quad_to_target_transform, child_pass_local_rect,
4743 child_pass.get(), blue_rrect);
4744 auto* blue = child_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
4745 blue->SetNew(shared_state_with_rrect, blue_rect, blue_rect, SK_ColorBLUE,
4746 false);
4747
4748 SharedQuadState* shared_state_without_rrect = CreateTestSharedQuadState(
4749 gfx::Transform(), child_pass_local_rect, child_pass.get(), gfx::RRectF());
4750 gfx::Rect yellow_rect = child_pass_local_rect;
4751 yellow_rect.Offset(30, -60);
4752 auto* yellow = child_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
4753 yellow->SetNew(shared_state_without_rrect, yellow_rect, yellow_rect,
4754 SK_ColorYELLOW, false);
4755
4756 gfx::Rect white_rect = child_pass_local_rect;
4757 auto* white = child_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
4758 white->SetNew(shared_state_without_rrect, white_rect, white_rect,
4759 SK_ColorWHITE, false);
4760
4761 gfx::RRectF rounded_corner_bounds(gfx::RectF(pass_rect), kCornerRadius);
4762 SharedQuadState* pass_shared_state = CreateTestSharedQuadState(
4763 gfx::Transform(), pass_rect, root_pass.get(), rounded_corner_bounds);
4764 CreateTestRenderPassDrawQuad(pass_shared_state, pass_rect, child_pass_id,
4765 root_pass.get());
4766
4767 AggregatedRenderPassList pass_list;
4768 pass_list.push_back(std::move(child_pass));
4769 pass_list.push_back(std::move(root_pass));
4770
4771 base::FilePath path(FILE_PATH_LITERAL("rounded_corner_render_pass_.png"));
4772 path = path.InsertBeforeExtensionASCII(this->renderer_str());
4773 EXPECT_TRUE(this->RunPixelTest(&pass_list, path,
4774 cc::FuzzyPixelOffByOneComparator(true)));
4775 }
4776
4777 // TODO(https://crbug.com/1044841): Flaky, especially on Linux/TSAN and Fuchsia.
TEST_P(RendererPixelTest,DISABLED_RoundedCornerMultiRadii)4778 TEST_P(RendererPixelTest, DISABLED_RoundedCornerMultiRadii) {
4779 gfx::Rect viewport_rect(this->device_viewport_size_);
4780 constexpr gfx::RoundedCornersF kCornerRadii(5, 15, 25, 35);
4781 constexpr int kInset = 20;
4782
4783 AggregatedRenderPassId root_pass_id{1};
4784 auto root_pass = CreateTestRootRenderPass(root_pass_id, viewport_rect);
4785
4786 gfx::Rect pass_rect(this->device_viewport_size_);
4787 pass_rect.Inset(kInset, kInset);
4788 gfx::RRectF rounded_corner_bounds(gfx::RectF(pass_rect), kCornerRadii);
4789 gfx::Rect blue_rect = pass_rect;
4790 blue_rect.set_height(blue_rect.height() / 2);
4791
4792 gfx::Transform quad_to_target_transform;
4793 SharedQuadState* shared_state_normal =
4794 CreateTestSharedQuadState(quad_to_target_transform, pass_rect,
4795 root_pass.get(), rounded_corner_bounds);
4796 auto* blue = root_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
4797 blue->SetNew(shared_state_normal, blue_rect, blue_rect, SK_ColorBLUE, false);
4798
4799 gfx::Rect yellow_rect = blue_rect;
4800 yellow_rect.Offset(0, blue_rect.height());
4801
4802 auto* yellow = root_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
4803 yellow->SetNew(shared_state_normal, yellow_rect, yellow_rect, SK_ColorYELLOW,
4804 false);
4805
4806 SharedQuadState* sqs_white = CreateTestSharedQuadState(
4807 quad_to_target_transform, viewport_rect, root_pass.get(), gfx::RRectF());
4808 gfx::Rect white_rect = gfx::Rect(this->device_viewport_size_);
4809 auto* white = root_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
4810 white->SetNew(sqs_white, white_rect, white_rect, SK_ColorWHITE, false);
4811
4812 AggregatedRenderPassList pass_list;
4813 pass_list.push_back(std::move(root_pass));
4814
4815 if (is_gl_renderer()) {
4816 // GL Renderer should have an exact match as that is the reference point.
4817 EXPECT_TRUE(this->RunPixelTest(
4818 &pass_list,
4819 base::FilePath(FILE_PATH_LITERAL("rounded_corner_multi_radii.png")),
4820 cc::ExactPixelComparator(true)));
4821 } else {
4822 // Software/skia renderer uses skia rrect to create rounded corner clip.
4823 // This results in a different corner path due to a different anti aliasing
4824 // approach than the fragment shader in gl renderer.
4825 EXPECT_TRUE(this->RunPixelTest(
4826 &pass_list,
4827 base::FilePath(FILE_PATH_LITERAL("rounded_corner_multi_radii.png")),
4828 cc::FuzzyPixelComparator(true, 0.55f, 0.f, 255.f, 255, 0)));
4829 }
4830 }
4831
4832 // TODO(https://crbug.com/1044841): Flaky, especially on Linux/TSAN and Fuchsia.
TEST_P(RendererPixelTest,DISABLED_RoundedCornerMultipleQads)4833 TEST_P(RendererPixelTest, DISABLED_RoundedCornerMultipleQads) {
4834 const gfx::Rect viewport_rect(this->device_viewport_size_);
4835 constexpr gfx::RoundedCornersF kCornerRadiiUL(5, 0, 0, 0);
4836 constexpr gfx::RoundedCornersF kCornerRadiiUR(0, 15, 0, 0);
4837 constexpr gfx::RoundedCornersF kCornerRadiiLR(0, 0, 25, 0);
4838 constexpr gfx::RoundedCornersF kCornerRadiiLL(0, 0, 0, 35);
4839 constexpr int kInset = 20;
4840
4841 AggregatedRenderPassId root_pass_id{1};
4842 auto root_pass = CreateTestRootRenderPass(root_pass_id, viewport_rect);
4843
4844 gfx::Rect pass_rect(this->device_viewport_size_);
4845 pass_rect.Inset(kInset, kInset);
4846 gfx::RRectF rounded_corner_bounds_ul(gfx::RectF(pass_rect), kCornerRadiiUL);
4847 gfx::RRectF rounded_corner_bounds_ur(gfx::RectF(pass_rect), kCornerRadiiUR);
4848 gfx::RRectF rounded_corner_bounds_lr(gfx::RectF(pass_rect), kCornerRadiiLR);
4849 gfx::RRectF rounded_corner_bounds_ll(gfx::RectF(pass_rect), kCornerRadiiLL);
4850
4851 gfx::Rect ul_rect = pass_rect;
4852 ul_rect.set_height(ul_rect.height() / 2);
4853 ul_rect.set_width(ul_rect.width() / 2);
4854
4855 gfx::Rect ur_rect = pass_rect;
4856 ur_rect.set_x(ul_rect.right());
4857 ur_rect.set_width(pass_rect.right() - ur_rect.x());
4858 ur_rect.set_height(ul_rect.height());
4859
4860 gfx::Rect lr_rect = pass_rect;
4861 lr_rect.set_y(ur_rect.bottom());
4862 lr_rect.set_x(ur_rect.x());
4863 lr_rect.set_width(ur_rect.width());
4864 lr_rect.set_height(pass_rect.bottom() - lr_rect.y());
4865
4866 gfx::Rect ll_rect = pass_rect;
4867 ll_rect.set_y(lr_rect.y());
4868 ll_rect.set_width(ul_rect.width());
4869 ll_rect.set_height(lr_rect.height());
4870
4871 SharedQuadState* shared_state_normal_ul = CreateTestSharedQuadState(
4872 gfx::Transform(), pass_rect, root_pass.get(), rounded_corner_bounds_ul);
4873
4874 SharedQuadState* shared_state_normal_ur = CreateTestSharedQuadState(
4875 gfx::Transform(), pass_rect, root_pass.get(), rounded_corner_bounds_ur);
4876
4877 SharedQuadState* shared_state_normal_lr = CreateTestSharedQuadState(
4878 gfx::Transform(), pass_rect, root_pass.get(), rounded_corner_bounds_lr);
4879
4880 SharedQuadState* shared_state_normal_ll = CreateTestSharedQuadState(
4881 gfx::Transform(), pass_rect, root_pass.get(), rounded_corner_bounds_ll);
4882
4883 auto* ul = root_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
4884 auto* ur = root_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
4885 auto* lr = root_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
4886 auto* ll = root_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
4887
4888 ul->SetNew(shared_state_normal_ul, ul_rect, ul_rect, SK_ColorRED, false);
4889 ur->SetNew(shared_state_normal_ur, ur_rect, ur_rect, SK_ColorGREEN, false);
4890 lr->SetNew(shared_state_normal_lr, lr_rect, lr_rect, SK_ColorBLUE, false);
4891 ll->SetNew(shared_state_normal_ll, ll_rect, ll_rect, SK_ColorYELLOW, false);
4892
4893 SharedQuadState* sqs_white = CreateTestSharedQuadState(
4894 gfx::Transform(), viewport_rect, root_pass.get(), gfx::RRectF());
4895 gfx::Rect white_rect = gfx::Rect(this->device_viewport_size_);
4896 auto* white = root_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
4897 white->SetNew(sqs_white, white_rect, white_rect, SK_ColorWHITE, false);
4898
4899 AggregatedRenderPassList pass_list;
4900 pass_list.push_back(std::move(root_pass));
4901
4902 // GL Renderer should have an exact match as that is the reference point.
4903 // Software/skia renderer use skia rrect to create rounded corner clip.
4904 // This results in a different corner path due to a different anti aliasing
4905 // approach than the fragment shader in gl renderer.
4906 std::unique_ptr<cc::PixelComparator> comparator;
4907 comparator.reset(
4908 is_gl_renderer()
4909 ? static_cast<cc::PixelComparator*>(
4910 new cc::ExactPixelComparator(true))
4911 : static_cast<cc::PixelComparator*>(
4912 new cc::FuzzyPixelComparator(true, 0.55f, 0.f, 255.f, 255, 0)));
4913 EXPECT_TRUE(this->RunPixelTest(
4914 &pass_list,
4915 base::FilePath(FILE_PATH_LITERAL("rounded_corner_multi_quad.png")),
4916 *comparator));
4917 }
4918
4919 class RendererPixelTestWithOverdrawFeedback : public VizPixelTestWithParam {
4920 protected:
SetUp()4921 void SetUp() override {
4922 this->debug_settings_.show_overdraw_feedback = true;
4923 VizPixelTestWithParam::SetUp();
4924 }
4925 };
4926
TEST_P(RendererPixelTestWithOverdrawFeedback,TranslucentRectangles)4927 TEST_P(RendererPixelTestWithOverdrawFeedback, TranslucentRectangles) {
4928 gfx::Rect rect(this->device_viewport_size_);
4929
4930 AggregatedRenderPassId id{1};
4931 gfx::Transform transform_to_root;
4932 auto pass = CreateTestRenderPass(id, rect, transform_to_root);
4933
4934 CreateTestAxisAlignedQuads(rect, 0x10444444, 0x10CCCCCC, true, false,
4935 pass.get());
4936
4937 gfx::Transform bg_quad_to_target_transform;
4938 SharedQuadState* bg_shared_state = CreateTestSharedQuadState(
4939 bg_quad_to_target_transform, rect, pass.get(), gfx::RRectF());
4940
4941 auto* bg = pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
4942 bg->SetNew(bg_shared_state, rect, rect, SK_ColorBLACK, false);
4943
4944 AggregatedRenderPassList pass_list;
4945 pass_list.push_back(std::move(pass));
4946
4947 if (is_gl_renderer()) {
4948 EXPECT_TRUE(this->RunPixelTest(
4949 &pass_list,
4950 base::FilePath(FILE_PATH_LITERAL("translucent_rectangles.png")),
4951 cc::ExactPixelComparator(true)));
4952 } else {
4953 // TODO(xing.xu): investigate why overdraw feedback has small difference
4954 // (http://crbug.com/909971)
4955 EXPECT_TRUE(this->RunPixelTest(
4956 &pass_list,
4957 base::FilePath(FILE_PATH_LITERAL("skia_translucent_rectangles.png")),
4958 cc::FuzzyPixelComparator(false, 2.f, 0.f, 256.f, 256, 0.f)));
4959 }
4960 }
4961
4962 INSTANTIATE_TEST_SUITE_P(,
4963 RendererPixelTestWithOverdrawFeedback,
4964 testing::ValuesIn(GetGpuRendererTypes()),
4965 testing::PrintToStringParamName());
4966
4967 using PrimaryID = gfx::ColorSpace::PrimaryID;
4968 using TransferID = gfx::ColorSpace::TransferID;
4969
4970 class ColorTransformPixelTest
4971 : public VizPixelTest,
4972 public testing::WithParamInterface<
4973 std::tuple<RendererType, gfx::ColorSpace, gfx::ColorSpace, bool>> {
4974 public:
ColorTransformPixelTest()4975 ColorTransformPixelTest() : VizPixelTest(std::get<0>(GetParam())) {
4976 // Note that this size of 17 is not random -- it is chosen to match the
4977 // size of LUTs that are created. If we did not match the LUT size exactly,
4978 // then the error for LUT based transforms is much larger.
4979 this->device_viewport_size_ = gfx::Size(17, 5);
4980 this->src_color_space_ = std::get<1>(GetParam());
4981 this->dst_color_space_ = std::get<2>(GetParam());
4982 if (!this->src_color_space_.IsValid()) {
4983 this->src_color_space_ =
4984 gfx::ICCProfileForTestingNoAnalyticTrFn().GetColorSpace();
4985 }
4986 if (!this->dst_color_space_.IsValid()) {
4987 this->dst_color_space_ =
4988 gfx::ICCProfileForTestingNoAnalyticTrFn().GetColorSpace();
4989 }
4990 this->display_color_spaces_ =
4991 gfx::DisplayColorSpaces(this->dst_color_space_);
4992 this->premultiplied_alpha_ = std::get<3>(GetParam());
4993 }
4994
Basic()4995 void Basic() {
4996 // Skip piecewise transfer functions because SkColorSpace (needed for
4997 // CopyOutputResult::AsSkBitmap) doesn't support them..
4998 if ((src_color_space_.GetTransferID() == TransferID::PIECEWISE_HDR ||
4999 dst_color_space_.GetTransferID() == TransferID::PIECEWISE_HDR)) {
5000 LOG(ERROR) << "Skipping piecewise HDR function";
5001 return;
5002 }
5003
5004 gfx::Rect rect(this->device_viewport_size_);
5005 std::vector<uint8_t> input_colors(4 * rect.width() * rect.height(), 0);
5006 std::vector<SkColor> expected_output_colors(rect.width() * rect.height());
5007
5008 // Set the input data to be:
5009 // Row 0: Gradient of red from 0 to 255
5010 // Row 1: Gradient of green from 0 to 255
5011 // Row 2: Gradient of blue from 0 to 255
5012 // Row 3: Gradient of grey from 0 to 255
5013 // Row 4: Gradient of alpha from 0 to 255 with mixed colors.
5014 for (int x = 0; x < rect.width(); ++x) {
5015 int gradient_value = (x * 255) / (rect.width() - 1);
5016 for (int y = 0; y < rect.height(); ++y) {
5017 uint8_t* pixel = &input_colors[4 * (x + rect.width() * y)];
5018 pixel[3] = 255;
5019 if (y < 3) {
5020 pixel[y] = gradient_value;
5021 } else if (y == 3) {
5022 pixel[0] = pixel[1] = pixel[2] = gradient_value;
5023 } else {
5024 if (this->premultiplied_alpha_) {
5025 pixel[x % 3] = gradient_value;
5026 pixel[3] = gradient_value;
5027 } else {
5028 pixel[x % 3] = 0xFF;
5029 pixel[3] = gradient_value;
5030 }
5031 }
5032 }
5033 }
5034
5035 std::unique_ptr<gfx::ColorTransform> transform =
5036 gfx::ColorTransform::NewColorTransform(
5037 this->src_color_space_, this->dst_color_space_,
5038 gfx::ColorTransform::Intent::INTENT_PERCEPTUAL);
5039
5040 for (size_t i = 0; i < expected_output_colors.size(); ++i) {
5041 gfx::ColorTransform::TriStim color;
5042 color.set_x(input_colors[4 * i + 0] / 255.f);
5043 color.set_y(input_colors[4 * i + 1] / 255.f);
5044 color.set_z(input_colors[4 * i + 2] / 255.f);
5045 float alpha = input_colors[4 * i + 3] / 255.f;
5046 if (this->premultiplied_alpha_ && alpha > 0.0) {
5047 color.Scale(1.0f / alpha);
5048 }
5049 transform->Transform(&color, 1);
5050 color.Scale(alpha);
5051 color.set_x(base::ClampToRange(color.x(), 0.0f, 1.0f));
5052 color.set_y(base::ClampToRange(color.y(), 0.0f, 1.0f));
5053 color.set_z(base::ClampToRange(color.z(), 0.0f, 1.0f));
5054 expected_output_colors[i] =
5055 SkColorSetARGB(255, static_cast<size_t>(255.f * color.x() + 0.5f),
5056 static_cast<size_t>(255.f * color.y() + 0.5f),
5057 static_cast<size_t>(255.f * color.z() + 0.5f));
5058 }
5059
5060 AggregatedRenderPassId id{1};
5061 auto pass = CreateTestRootRenderPass(id, rect);
5062
5063 // Append a quad to execute the transform.
5064 {
5065 SharedQuadState* shared_state = CreateTestSharedQuadState(
5066 gfx::Transform(), rect, pass.get(), gfx::RRectF());
5067
5068 ResourceId resource = CreateGpuResource(
5069 this->child_context_provider_, this->child_resource_provider_.get(),
5070 rect.size(), RGBA_8888, this->src_color_space_, input_colors);
5071
5072 // Return the mapped resource id.
5073 std::unordered_map<ResourceId, ResourceId> resource_map =
5074 cc::SendResourceAndGetChildToParentMap(
5075 {resource}, this->resource_provider_.get(),
5076 this->child_resource_provider_.get(),
5077 this->child_context_provider_.get());
5078 ResourceId mapped_resource = resource_map[resource];
5079
5080 bool needs_blending = true;
5081 const gfx::PointF uv_top_left(0.0f, 0.0f);
5082 const gfx::PointF uv_bottom_right(1.0f, 1.0f);
5083 const bool flipped = false;
5084 const bool nearest_neighbor = false;
5085 auto* quad = pass->CreateAndAppendDrawQuad<TextureDrawQuad>();
5086
5087 float vertex_opacity[4] = {1.0f, 1.0f, 1.0f, 1.0f};
5088 quad->SetNew(shared_state, rect, rect, needs_blending, mapped_resource,
5089 this->premultiplied_alpha_, uv_top_left, uv_bottom_right,
5090 SK_ColorBLACK, vertex_opacity, flipped, nearest_neighbor,
5091 /*secure_output_only=*/false,
5092 gfx::ProtectedVideoType::kClear);
5093
5094 auto* color_quad = pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
5095 color_quad->SetNew(shared_state, rect, rect, SK_ColorBLACK, false);
5096 }
5097
5098 AggregatedRenderPassList pass_list;
5099 pass_list.push_back(std::move(pass));
5100
5101 // Allow a difference of 2 bytes in comparison for shader-based transforms,
5102 // and 4 bytes for LUT-based transforms (determined empirically).
5103 cc::FuzzyPixelComparator comparator(false, 100.f, 0.f, 2.f, 2, 0);
5104 EXPECT_TRUE(
5105 this->RunPixelTest(&pass_list, &expected_output_colors, comparator))
5106 << " src:" << src_color_space_ << ", dst:" << dst_color_space_;
5107 }
5108
5109 gfx::ColorSpace src_color_space_;
5110 gfx::ColorSpace dst_color_space_;
5111 bool premultiplied_alpha_ = false;
5112 };
5113
TEST_P(ColorTransformPixelTest,Basic)5114 TEST_P(ColorTransformPixelTest, Basic) {
5115 Basic();
5116 }
5117
5118 gfx::ColorSpace src_color_spaces[] = {
5119 // This will be replaced by an ICC-based space (which can't be initialized
5120 // here).
5121 gfx::ColorSpace(),
5122 gfx::ColorSpace(PrimaryID::BT709, TransferID::BT709),
5123 gfx::ColorSpace(PrimaryID::BT709, TransferID::GAMMA28),
5124 gfx::ColorSpace(PrimaryID::BT709, TransferID::SMPTE240M),
5125 gfx::ColorSpace(PrimaryID::BT709, TransferID::LINEAR),
5126 gfx::ColorSpace(PrimaryID::BT709, TransferID::IEC61966_2_1),
5127 gfx::ColorSpace(PrimaryID::BT709, TransferID::SMPTEST428_1),
5128 gfx::ColorSpace(PrimaryID::BT709, TransferID::IEC61966_2_1_HDR),
5129 gfx::ColorSpace(PrimaryID::BT709, TransferID::LINEAR_HDR),
5130 // Piecewise HDR transfer functions skipped with SkiaRenderer.
5131 gfx::ColorSpace::CreatePiecewiseHDR(PrimaryID::BT709, 0.5, 1.5),
5132 gfx::ColorSpace::CreateHDR10(50.f),
5133 gfx::ColorSpace::CreateHDR10(250.f),
5134 };
5135
5136 gfx::ColorSpace dst_color_spaces[] = {
5137 // This will be replaced by an ICC-based space (which can't be initialized
5138 // here).
5139 gfx::ColorSpace(),
5140 gfx::ColorSpace(PrimaryID::BT709, TransferID::BT709),
5141 gfx::ColorSpace(PrimaryID::BT709, TransferID::GAMMA28),
5142 gfx::ColorSpace(PrimaryID::BT709, TransferID::SMPTE240M),
5143 gfx::ColorSpace(PrimaryID::BT709, TransferID::LINEAR),
5144 gfx::ColorSpace(PrimaryID::BT709, TransferID::IEC61966_2_1),
5145 gfx::ColorSpace(PrimaryID::BT709, TransferID::IEC61966_2_1_HDR),
5146 gfx::ColorSpace(PrimaryID::BT709, TransferID::LINEAR_HDR),
5147 // Piecewise HDR transfer functions are skipped with SkiaRenderer.
5148 gfx::ColorSpace::CreatePiecewiseHDR(PrimaryID::BT709, 0.25, 2.5),
5149 };
5150
5151 gfx::ColorSpace intermediate_color_spaces[] = {
5152 gfx::ColorSpace(PrimaryID::XYZ_D50, TransferID::LINEAR),
5153 gfx::ColorSpace(PrimaryID::XYZ_D50, TransferID::IEC61966_2_1_HDR),
5154 };
5155
5156 INSTANTIATE_TEST_SUITE_P(
5157 FromColorSpace,
5158 ColorTransformPixelTest,
5159 testing::Combine(testing::ValuesIn(GetGpuRendererTypesNoDawn()),
5160 testing::ValuesIn(src_color_spaces),
5161 testing::ValuesIn(intermediate_color_spaces),
5162 testing::Bool()));
5163
5164 INSTANTIATE_TEST_SUITE_P(
5165 ToColorSpace,
5166 ColorTransformPixelTest,
5167 testing::Combine(testing::ValuesIn(GetGpuRendererTypesNoDawn()),
5168 testing::ValuesIn(intermediate_color_spaces),
5169 testing::ValuesIn(dst_color_spaces),
5170 testing::Bool()));
5171
5172 class DelegatedInkTest : public VizPixelTestWithParam,
5173 public DelegatedInkPointPixelTestHelper {
5174 public:
SetUp()5175 void SetUp() override {
5176 // Partial swap must be enabled or else the test will pass even if the
5177 // delegated ink trail damage rect is wrong, because the whole frame is
5178 // always redrawn otherwise.
5179 renderer_settings_.partial_swap_enabled = true;
5180 VizPixelTestWithParam::SetUp();
5181 EXPECT_TRUE(VizPixelTestWithParam::renderer_->use_partial_swap());
5182
5183 SetRendererAndCreateInkRenderer(VizPixelTestWithParam::renderer_.get());
5184 }
5185
CreateTestRootRenderPass(AggregatedRenderPassId id,const gfx::Rect & output_rect,const gfx::Rect & damage_rect)5186 std::unique_ptr<AggregatedRenderPass> CreateTestRootRenderPass(
5187 AggregatedRenderPassId id,
5188 const gfx::Rect& output_rect,
5189 const gfx::Rect& damage_rect) {
5190 auto pass = std::make_unique<AggregatedRenderPass>();
5191 const gfx::Transform transform_to_root_target;
5192 pass->SetNew(id, output_rect, damage_rect, transform_to_root_target);
5193 return pass;
5194 }
5195
DrawAndTestTrail(base::FilePath::StringPieceType file)5196 bool DrawAndTestTrail(base::FilePath::StringPieceType file) {
5197 gfx::Rect rect(this->device_viewport_size_);
5198
5199 // Minimize the root render pass damage rect so that it has to be expanded
5200 // by the delegated ink trail damage rect to confirm that it is the right
5201 // size to remove old trails and add new ones.
5202 gfx::Rect damage_rect(0, 0, 1, 1);
5203 AggregatedRenderPassId id{1};
5204 std::unique_ptr<AggregatedRenderPass> pass =
5205 CreateTestRootRenderPass(id, rect, damage_rect);
5206
5207 SharedQuadState* shared_state = CreateTestSharedQuadState(
5208 gfx::Transform(), rect, pass.get(), gfx::RRectF());
5209
5210 SolidColorDrawQuad* color_quad =
5211 pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
5212 color_quad->SetNew(shared_state, rect, rect, SK_ColorWHITE, false);
5213
5214 AggregatedRenderPassList pass_list;
5215 pass_list.push_back(std::move(pass));
5216
5217 return this->RunPixelTest(&pass_list, base::FilePath(file),
5218 cc::FuzzyPixelOffByOneComparator(true));
5219 }
5220 };
5221
5222 INSTANTIATE_TEST_SUITE_P(,
5223 DelegatedInkTest,
5224 testing::ValuesIn(GetRendererTypesSkiaOnly()),
5225 testing::PrintToStringParamName());
5226
5227 // Draw a single trail and erase it, making sure that no bits of trail are left
5228 // behind.
TEST_P(DelegatedInkTest,DrawOneTrailAndErase)5229 TEST_P(DelegatedInkTest, DrawOneTrailAndErase) {
5230 // First provide the metadata required to draw the trail, numbers arbitrary.
5231 CreateAndSendMetadata(gfx::PointF(10, 10), 3.5f, SK_ColorBLACK,
5232 gfx::RectF(0, 0, 175, 172));
5233
5234 // Then provide some points for the trail to draw. Numbers chosen arbitrarily
5235 // after the first point, which must match the metadata. This will predict no
5236 // points, so a trail made of 3 points will be drawn.
5237 CreateAndSendPointFromMetadata();
5238 CreateAndSendPointFromLastPoint(gfx::PointF(75, 62));
5239 CreateAndSendPointFromLastPoint(gfx::PointF(124, 45));
5240
5241 // Confirm that the trail was drawn.
5242 EXPECT_TRUE(
5243 DrawAndTestTrail(FILE_PATH_LITERAL("delegated_ink_one_trail.png")));
5244
5245 // The metadata should have been cleared after drawing, so confirm that there
5246 // is no trail after another draw.
5247 EXPECT_TRUE(DrawAndTestTrail(FILE_PATH_LITERAL("white.png")));
5248 }
5249
5250 // Confirm that drawing a second trail completely removes the first trail.
TEST_P(DelegatedInkTest,DrawTwoTrailsAndErase)5251 TEST_P(DelegatedInkTest, DrawTwoTrailsAndErase) {
5252 // TODO(crbug.com/1021566): Enable this test for SkiaRenderer Dawn.
5253 if (renderer_type() == RendererType::kSkiaDawn)
5254 return;
5255
5256 // First provide the metadata required to draw the trail, numbers arbitrary.
5257 CreateAndSendMetadata(gfx::PointF(140, 48), 8.2f, SK_ColorMAGENTA,
5258 gfx::RectF(0, 0, 200, 200));
5259
5260 // Then provide some points for the trail to draw. Numbers chosen arbitrarily
5261 // after the first point, which must match the metadata. No points will be
5262 // predicted, so a trail made of 2 points will be drawn.
5263 CreateAndSendPointFromMetadata();
5264 CreateAndSendPointFromLastPoint(gfx::PointF(115, 85));
5265
5266 // Confirm that the trail was drawn correctly.
5267 EXPECT_TRUE(DrawAndTestTrail(
5268 FILE_PATH_LITERAL("delegated_ink_two_trails_first.png")));
5269
5270 // Now provide new metadata and points to draw a new trail. Just use the last
5271 // point draw above as the starting point for the new trail. One point will
5272 // be predicted, so a trail consisting of 4 points will be drawn.
5273 CreateAndSendMetadataFromLastPoint();
5274 CreateAndSendPointFromLastPoint(gfx::PointF(134, 100));
5275 CreateAndSendPointFromLastPoint(gfx::PointF(150, 81.44f));
5276
5277 // Confirm the first trail is gone and only the second remains.
5278 EXPECT_TRUE(DrawAndTestTrail(
5279 FILE_PATH_LITERAL("delegated_ink_two_trails_second.png")));
5280
5281 // Confirm all trails are gone.
5282 EXPECT_TRUE(DrawAndTestTrail(FILE_PATH_LITERAL("white.png")));
5283 }
5284
5285 // Confirm that the trail can't be drawn beyond the presentation area.
TEST_P(DelegatedInkTest,TrailExtendsBeyondPresentationArea)5286 TEST_P(DelegatedInkTest, TrailExtendsBeyondPresentationArea) {
5287 // TODO(crbug.com/1021566): Enable this test for SkiaRenderer Dawn.
5288 if (renderer_type() == RendererType::kSkiaDawn)
5289 return;
5290
5291 const gfx::RectF kPresentationArea(30, 30, 100, 100);
5292 CreateAndSendMetadata(gfx::PointF(50.2f, 89.999f), 15.22f, SK_ColorCYAN,
5293 kPresentationArea);
5294
5295 // Send points such that some extend beyond the presentation area to confirm
5296 // that the trail is clipped correctly. One point will be predicted, so the
5297 // trail will be made of 9 points.
5298 CreateAndSendPointFromMetadata();
5299 CreateAndSendPointFromLastPoint(gfx::PointF(80.7f, 149.6f));
5300 CreateAndSendPointFromLastPoint(gfx::PointF(128.999f, 110.01f));
5301 CreateAndSendPointFromLastPoint(gfx::PointF(50, 50));
5302 CreateAndSendPointFromLastPoint(gfx::PointF(10.1f, 30.3f));
5303 CreateAndSendPointFromLastPoint(gfx::PointF(29.98f, 66));
5304 CreateAndSendPointFromLastPoint(gfx::PointF(52.3456f, 2.31f));
5305 CreateAndSendPointFromLastPoint(gfx::PointF(97, 36.9f));
5306 EXPECT_TRUE(DrawAndTestTrail(FILE_PATH_LITERAL(
5307 "delegated_ink_trail_clipped_by_presentation_area.png")));
5308 }
5309
5310 // Confirm that the trail appears on top of everything, including batched quads
5311 // that are drawn as part of the call to FinishDrawingQuadList.
TEST_P(DelegatedInkTest,DelegatedInkTrailAfterBatchedQuads)5312 TEST_P(DelegatedInkTest, DelegatedInkTrailAfterBatchedQuads) {
5313 gfx::Rect rect(this->device_viewport_size_);
5314
5315 AggregatedRenderPassId id{1};
5316 auto pass = CreateTestRootRenderPass(id, rect, rect);
5317
5318 SharedQuadState* shared_state = CreateTestSharedQuadState(
5319 gfx::Transform(), rect, pass.get(), gfx::RRectF());
5320
5321 CreateTestTextureDrawQuad(
5322 !is_software_renderer(), gfx::Rect(this->device_viewport_size_),
5323 SkColorSetARGB(128, 0, 255, 0), // Texel color.
5324 SK_ColorTRANSPARENT, // Background color.
5325 true, // Premultiplied alpha.
5326 shared_state, this->resource_provider_.get(),
5327 this->child_resource_provider_.get(), this->shared_bitmap_manager_.get(),
5328 this->child_context_provider_, pass.get());
5329
5330 auto* color_quad = pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
5331 color_quad->SetNew(shared_state, rect, rect, SK_ColorWHITE, false);
5332
5333 AggregatedRenderPassList pass_list;
5334 pass_list.push_back(std::move(pass));
5335
5336 const gfx::RectF kPresentationArea(0, 0, 200, 200);
5337 CreateAndSendMetadata(gfx::PointF(34.f, 72.f), 7.77f, SK_ColorDKGRAY,
5338 kPresentationArea);
5339 CreateAndSendPointFromMetadata();
5340 CreateAndSendPointFromLastPoint(gfx::PointF(79, 101));
5341 CreateAndSendPointFromLastPoint(gfx::PointF(134, 114));
5342
5343 EXPECT_TRUE(this->RunPixelTest(
5344 &pass_list,
5345 base::FilePath(
5346 FILE_PATH_LITERAL("delegated_ink_trail_on_batched_quads.png")),
5347 cc::FuzzyPixelOffByOneComparator(true)));
5348 }
5349
5350 // Confirm that delegated ink trails are not drawn on non-root render passes.
TEST_P(DelegatedInkTest,SimpleTrailNonRootRenderPass)5351 TEST_P(DelegatedInkTest, SimpleTrailNonRootRenderPass) {
5352 gfx::Rect rect(this->device_viewport_size_);
5353
5354 AggregatedRenderPassId child_id{2};
5355 auto child_pass = CreateTestRenderPass(child_id, rect, gfx::Transform());
5356
5357 SharedQuadState* child_shared_state = CreateTestSharedQuadState(
5358 gfx::Transform(), rect, child_pass.get(), gfx::RRectF());
5359
5360 auto* color_quad = child_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
5361 color_quad->SetNew(child_shared_state, rect, rect, SK_ColorGREEN, false);
5362
5363 AggregatedRenderPassId root_id{1};
5364 auto root_pass = CreateTestRootRenderPass(root_id, rect, rect);
5365
5366 SharedQuadState* root_shared_state = CreateTestSharedQuadState(
5367 gfx::Transform(), rect, root_pass.get(), gfx::RRectF());
5368
5369 CreateTestRenderPassDrawQuad(root_shared_state, rect, child_id,
5370 root_pass.get());
5371
5372 auto* child_pass_ptr = child_pass.get();
5373
5374 AggregatedRenderPassList pass_list;
5375 pass_list.push_back(std::move(child_pass));
5376 pass_list.push_back(std::move(root_pass));
5377
5378 // Values for a simple delegated ink trail, numbers chosen arbitrarily.
5379 const gfx::RectF kPresentationArea(0, 0, 200, 200);
5380 CreateAndSendMetadata(gfx::PointF(156.f, 111.f), 19.177f, SK_ColorRED,
5381 kPresentationArea);
5382 CreateAndSendPointFromMetadata();
5383 CreateAndSendPointFromLastPoint(gfx::PointF(119, 87.23f));
5384 CreateAndSendPointFromLastPoint(gfx::PointF(74.222f, 95.4f));
5385
5386 // This will only check what was drawn in the child pass, which should never
5387 // contain a delegated ink trail, so it should be solid green.
5388 EXPECT_TRUE(this->RunPixelTestWithReadbackTarget(
5389 &pass_list, child_pass_ptr,
5390 base::FilePath(FILE_PATH_LITERAL("green.png")),
5391 cc::ExactPixelComparator(true)));
5392 }
5393 #endif // !defined(OS_ANDROID)
5394
5395 } // namespace
5396 } // namespace viz
5397