blob: 7f968de4292dc90d0a2b5bbd2f1160b874584ff1 [file] [log] [blame]
// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/time/time.h"
#include "build/build_config.h"
#include "cc/test/pixel_comparator.h"
#include "components/viz/common/frame_sinks/begin_frame_args.h"
#include "components/viz/common/quads/compositor_frame.h"
#include "components/viz/common/quads/compositor_render_pass.h"
#include "components/viz/common/quads/solid_color_draw_quad.h"
#include "components/viz/common/quads/surface_draw_quad.h"
#include "components/viz/common/surfaces/parent_local_surface_id_allocator.h"
#include "components/viz/service/display/aggregated_frame.h"
#include "components/viz/service/display/delegated_ink_point_pixel_test_helper.h"
#include "components/viz/service/display/surface_aggregator.h"
#include "components/viz/service/display/viz_pixel_test.h"
#include "components/viz/service/frame_sinks/compositor_frame_sink_support.h"
#include "components/viz/service/frame_sinks/frame_sink_manager_impl.h"
#include "components/viz/service/surfaces/surface.h"
#include "components/viz/service/surfaces/surface_manager.h"
#include "components/viz/test/compositor_frame_helpers.h"
#include "testing/gtest/include/gtest/gtest.h"
#if !BUILDFLAG(IS_ANDROID)
namespace viz {
namespace {
constexpr FrameSinkId kArbitraryRootFrameSinkId(1, 1);
constexpr FrameSinkId kArbitraryChildFrameSinkId(2, 2);
constexpr FrameSinkId kArbitraryLeftFrameSinkId(3, 3);
constexpr FrameSinkId kArbitraryRightFrameSinkId(4, 4);
constexpr bool kIsRoot = true;
constexpr bool kIsChildRoot = false;
class SurfaceAggregatorPixelTest : public VizPixelTestWithParam {
public:
SurfaceAggregatorPixelTest()
: manager_(FrameSinkManagerImpl::InitParams()),
support_(std::make_unique<CompositorFrameSinkSupport>(
nullptr,
&manager_,
kArbitraryRootFrameSinkId,
kIsRoot)) {}
~SurfaceAggregatorPixelTest() override = default;
base::TimeTicks GetNextDisplayTime() {
base::TimeTicks display_time = next_display_time_;
next_display_time_ += BeginFrameArgs::DefaultInterval();
return display_time;
}
protected:
FrameSinkManagerImpl manager_;
ParentLocalSurfaceIdAllocator root_allocator_;
std::unique_ptr<CompositorFrameSinkSupport> support_;
base::TimeTicks next_display_time_ = base::TimeTicks() + base::Seconds(1);
};
INSTANTIATE_TEST_SUITE_P(,
SurfaceAggregatorPixelTest,
testing::ValuesIn(GetGpuRendererTypes()),
testing::PrintToStringParamName());
// GetGpuRendererTypes() can return an empty list, e.g. on Fuchsia ARM64.
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(SurfaceAggregatorPixelTest);
SharedQuadState* CreateAndAppendTestSharedQuadState(
CompositorRenderPass* render_pass,
const gfx::Transform& transform,
const gfx::Size& size) {
const gfx::Rect layer_rect = gfx::Rect(size);
const gfx::Rect visible_layer_rect = gfx::Rect(size);
const gfx::MaskFilterInfo mask_filter_info;
bool are_contents_opaque = false;
float opacity = 1.f;
const SkBlendMode blend_mode = SkBlendMode::kSrcOver;
auto* shared_state = render_pass->CreateAndAppendSharedQuadState();
shared_state->SetAll(transform, layer_rect, visible_layer_rect,
mask_filter_info, /*clip=*/std::nullopt,
are_contents_opaque, opacity, blend_mode,
/*sorting_context=*/0,
/*layer_id=*/0u, /*fast_rounded_corner=*/false);
return shared_state;
}
// Draws a very simple frame with no surface references.
TEST_P(SurfaceAggregatorPixelTest, DrawSimpleFrame) {
gfx::Rect rect(this->device_viewport_size_);
CompositorRenderPassId id{1};
auto pass = CompositorRenderPass::Create();
pass->SetNew(id, rect, rect, gfx::Transform());
CreateAndAppendTestSharedQuadState(pass.get(), gfx::Transform(),
this->device_viewport_size_);
auto* color_quad = pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
bool force_anti_aliasing_off = false;
color_quad->SetNew(pass->shared_quad_state_list.back(), rect, rect,
SkColors::kGreen, force_anti_aliasing_off);
auto root_frame =
CompositorFrameBuilder().AddRenderPass(std::move(pass)).Build();
this->root_allocator_.GenerateId();
SurfaceId root_surface_id(this->support_->frame_sink_id(),
this->root_allocator_.GetCurrentLocalSurfaceId());
this->support_->SubmitCompositorFrame(
this->root_allocator_.GetCurrentLocalSurfaceId(), std::move(root_frame));
SurfaceAggregator aggregator(this->manager_.surface_manager(),
this->resource_provider_.get(), false);
auto aggregated_frame = aggregator.Aggregate(
root_surface_id, this->GetNextDisplayTime(), gfx::OVERLAY_TRANSFORM_NONE);
cc::ExactPixelComparator pixel_comparator;
auto* pass_list = &aggregated_frame.render_pass_list;
EXPECT_TRUE(this->RunPixelTest(pass_list,
base::FilePath(FILE_PATH_LITERAL("green.png")),
pixel_comparator));
}
// Draws a frame with simple surface embedding.
TEST_P(SurfaceAggregatorPixelTest, DrawSimpleAggregatedFrame) {
gfx::Size child_size(200, 100);
auto child_support = std::make_unique<CompositorFrameSinkSupport>(
nullptr, &this->manager_, kArbitraryChildFrameSinkId, kIsChildRoot);
ParentLocalSurfaceIdAllocator child_allocator;
child_allocator.GenerateId();
LocalSurfaceId child_local_surface_id =
child_allocator.GetCurrentLocalSurfaceId();
SurfaceId child_surface_id(child_support->frame_sink_id(),
child_local_surface_id);
this->root_allocator_.GenerateId();
LocalSurfaceId root_local_surface_id =
this->root_allocator_.GetCurrentLocalSurfaceId();
SurfaceId root_surface_id(this->support_->frame_sink_id(),
root_local_surface_id);
{
gfx::Rect rect(this->device_viewport_size_);
CompositorRenderPassId id{1};
auto pass = CompositorRenderPass::Create();
pass->SetNew(id, rect, rect, gfx::Transform());
CreateAndAppendTestSharedQuadState(pass.get(), gfx::Transform(),
this->device_viewport_size_);
auto* surface_quad = pass->CreateAndAppendDrawQuad<SurfaceDrawQuad>();
surface_quad->SetNew(
pass->shared_quad_state_list.back(), gfx::Rect(child_size),
gfx::Rect(child_size), SurfaceRange(std::nullopt, child_surface_id),
SkColors::kWhite, /*stretch_content_to_fill_bounds=*/false);
auto* color_quad = pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
bool force_anti_aliasing_off = false;
color_quad->SetNew(pass->shared_quad_state_list.back(), rect, rect,
SkColors::kYellow, force_anti_aliasing_off);
auto root_frame =
CompositorFrameBuilder().AddRenderPass(std::move(pass)).Build();
this->support_->SubmitCompositorFrame(root_local_surface_id,
std::move(root_frame));
}
{
gfx::Rect rect(child_size);
CompositorRenderPassId id{1};
auto pass = CompositorRenderPass::Create();
pass->SetNew(id, rect, rect, gfx::Transform());
CreateAndAppendTestSharedQuadState(pass.get(), gfx::Transform(),
child_size);
auto* color_quad = pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
bool force_anti_aliasing_off = false;
color_quad->SetNew(pass->shared_quad_state_list.back(), rect, rect,
SkColors::kBlue, force_anti_aliasing_off);
auto child_frame =
CompositorFrameBuilder().AddRenderPass(std::move(pass)).Build();
child_support->SubmitCompositorFrame(child_local_surface_id,
std::move(child_frame));
}
SurfaceAggregator aggregator(this->manager_.surface_manager(),
this->resource_provider_.get(), false);
auto aggregated_frame = aggregator.Aggregate(
root_surface_id, this->GetNextDisplayTime(), gfx::OVERLAY_TRANSFORM_NONE);
cc::ExactPixelComparator pixel_comparator;
auto* pass_list = &aggregated_frame.render_pass_list;
EXPECT_TRUE(this->RunPixelTest(
pass_list, base::FilePath(FILE_PATH_LITERAL("blue_yellow.png")),
pixel_comparator));
}
// Tests a surface quad that has a non-identity transform into its pass.
TEST_P(SurfaceAggregatorPixelTest, DrawAggregatedFrameWithSurfaceTransforms) {
gfx::Size child_size(100, 200);
gfx::Size quad_size(100, 100);
// Structure:
// root (200x200) -> left_child (100x200 @ 0x0,
// right_child (100x200 @ 0x100)
// left_child -> top_green_quad (100x100 @ 0x0),
// bottom_blue_quad (100x100 @ 0x100)
// right_child -> top_blue_quad (100x100 @ 0x0),
// bottom_green_quad (100x100 @ 0x100)
auto left_support = std::make_unique<CompositorFrameSinkSupport>(
nullptr, &this->manager_, kArbitraryLeftFrameSinkId, kIsChildRoot);
auto right_support = std::make_unique<CompositorFrameSinkSupport>(
nullptr, &this->manager_, kArbitraryRightFrameSinkId, kIsChildRoot);
ParentLocalSurfaceIdAllocator left_child_allocator;
left_child_allocator.GenerateId();
LocalSurfaceId left_child_local_id =
left_child_allocator.GetCurrentLocalSurfaceId();
SurfaceId left_child_id(left_support->frame_sink_id(), left_child_local_id);
ParentLocalSurfaceIdAllocator right_child_allocator;
right_child_allocator.GenerateId();
LocalSurfaceId right_child_local_id =
right_child_allocator.GetCurrentLocalSurfaceId();
SurfaceId right_child_id(right_support->frame_sink_id(),
right_child_local_id);
this->root_allocator_.GenerateId();
LocalSurfaceId root_local_surface_id =
this->root_allocator_.GetCurrentLocalSurfaceId();
SurfaceId root_surface_id(this->support_->frame_sink_id(),
root_local_surface_id);
{
gfx::Rect rect(this->device_viewport_size_);
CompositorRenderPassId id{1};
auto pass = CompositorRenderPass::Create();
pass->SetNew(id, rect, rect, gfx::Transform());
gfx::Transform surface_transform;
CreateAndAppendTestSharedQuadState(pass.get(), surface_transform,
this->device_viewport_size_);
auto* left_surface_quad = pass->CreateAndAppendDrawQuad<SurfaceDrawQuad>();
left_surface_quad->SetNew(
pass->shared_quad_state_list.back(), gfx::Rect(child_size),
gfx::Rect(child_size), SurfaceRange(std::nullopt, left_child_id),
SkColors::kWhite, /*stretch_content_to_fill_bounds=*/false);
surface_transform.Translate(100, 0);
CreateAndAppendTestSharedQuadState(pass.get(), surface_transform,
this->device_viewport_size_);
auto* right_surface_quad = pass->CreateAndAppendDrawQuad<SurfaceDrawQuad>();
right_surface_quad->SetNew(
pass->shared_quad_state_list.back(), gfx::Rect(child_size),
gfx::Rect(child_size), SurfaceRange(std::nullopt, right_child_id),
SkColors::kWhite, /*stretch_content_to_fill_bounds=*/false);
auto root_frame =
CompositorFrameBuilder().AddRenderPass(std::move(pass)).Build();
this->support_->SubmitCompositorFrame(root_local_surface_id,
std::move(root_frame));
}
{
gfx::Rect rect(child_size);
CompositorRenderPassId id{1};
auto pass = CompositorRenderPass::Create();
pass->SetNew(id, rect, rect, gfx::Transform());
CreateAndAppendTestSharedQuadState(pass.get(), gfx::Transform(),
child_size);
auto* top_color_quad = pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
bool force_anti_aliasing_off = false;
top_color_quad->SetNew(pass->shared_quad_state_list.back(),
gfx::Rect(quad_size), gfx::Rect(quad_size),
SkColors::kGreen, force_anti_aliasing_off);
auto* bottom_color_quad =
pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
bottom_color_quad->SetNew(
pass->shared_quad_state_list.back(), gfx::Rect(0, 100, 100, 100),
gfx::Rect(0, 100, 100, 100), SkColors::kBlue, force_anti_aliasing_off);
auto child_frame =
CompositorFrameBuilder().AddRenderPass(std::move(pass)).Build();
left_support->SubmitCompositorFrame(left_child_local_id,
std::move(child_frame));
}
{
gfx::Rect rect(child_size);
CompositorRenderPassId id{1};
auto pass = CompositorRenderPass::Create();
pass->SetNew(id, rect, rect, gfx::Transform());
CreateAndAppendTestSharedQuadState(pass.get(), gfx::Transform(),
child_size);
auto* top_color_quad = pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
bool force_anti_aliasing_off = false;
top_color_quad->SetNew(pass->shared_quad_state_list.back(),
gfx::Rect(quad_size), gfx::Rect(quad_size),
SkColors::kBlue, force_anti_aliasing_off);
auto* bottom_color_quad =
pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
bottom_color_quad->SetNew(
pass->shared_quad_state_list.back(), gfx::Rect(0, 100, 100, 100),
gfx::Rect(0, 100, 100, 100), SkColors::kGreen, force_anti_aliasing_off);
auto child_frame =
CompositorFrameBuilder().AddRenderPass(std::move(pass)).Build();
right_support->SubmitCompositorFrame(right_child_local_id,
std::move(child_frame));
}
SurfaceAggregator aggregator(this->manager_.surface_manager(),
this->resource_provider_.get(), false);
auto aggregated_frame = aggregator.Aggregate(
root_surface_id, this->GetNextDisplayTime(), gfx::OVERLAY_TRANSFORM_NONE);
cc::ExactPixelComparator pixel_comparator;
auto* pass_list = &aggregated_frame.render_pass_list;
EXPECT_TRUE(this->RunPixelTest(
pass_list,
base::FilePath(FILE_PATH_LITERAL("four_blue_green_checkers.png")),
pixel_comparator));
}
// Draw a simple frame with a delegated ink trail on top of it, then confirm
// that it is erased by the next aggregation.
TEST_P(SurfaceAggregatorPixelTest, DrawAndEraseDelegatedInkTrail) {
DelegatedInkPointPixelTestHelper delegated_ink_helper(renderer_.get());
// Create and send metadata and points to the renderer that will be drawn.
// Points and timestamps are chosen arbitrarily.
const gfx::PointF kFirstPoint(10, 10);
const base::TimeTicks kFirstTimestamp = base::TimeTicks::Now();
delegated_ink_helper.CreateAndSendPoint(kFirstPoint, kFirstTimestamp);
delegated_ink_helper.CreateAndSendPointFromLastPoint(gfx::PointF(26, 37));
delegated_ink_helper.CreateAndSendPointFromLastPoint(gfx::PointF(45, 87));
delegated_ink_helper.CreateAndSendMetadata(kFirstPoint, 7.7f,
SkColors::kWhite, kFirstTimestamp,
gfx::RectF(0, 0, 200, 200),
/*render_pass_id=*/1);
gfx::Rect rect(this->device_viewport_size_);
CompositorRenderPassId id{1};
auto pass = CompositorRenderPass::Create();
pass->SetNew(id, rect, rect, gfx::Transform());
CreateAndAppendTestSharedQuadState(pass.get(), gfx::Transform(),
this->device_viewport_size_);
auto* color_quad = pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
bool force_anti_aliasing_off = false;
color_quad->SetNew(pass->shared_quad_state_list.back(), rect, rect,
SkColors::kGreen, force_anti_aliasing_off);
auto root_frame =
CompositorFrameBuilder().AddRenderPass(std::move(pass)).Build();
this->root_allocator_.GenerateId();
SurfaceId root_surface_id(this->support_->frame_sink_id(),
this->root_allocator_.GetCurrentLocalSurfaceId());
this->support_->SubmitCompositorFrame(
this->root_allocator_.GetCurrentLocalSurfaceId(), std::move(root_frame));
SurfaceAggregator aggregator(this->manager_.surface_manager(),
this->resource_provider_.get(), false);
auto aggregated_frame = aggregator.Aggregate(
root_surface_id, this->GetNextDisplayTime(), gfx::OVERLAY_TRANSFORM_NONE);
cc::FuzzyPixelOffByOneComparator pixel_comparator;
auto* pass_list = &aggregated_frame.render_pass_list;
base::FilePath expected_result =
base::FilePath(FILE_PATH_LITERAL("delegated_ink_trail.png"));
if (is_skia_graphite()) {
expected_result = expected_result.InsertBeforeExtensionASCII("_graphite");
}
EXPECT_TRUE(this->RunPixelTest(pass_list, expected_result, pixel_comparator));
// Providing the damage rect as the target damage ensures that aggregation
// occurs and DrawFrame() has something new to draw. If this doesn't cause
// anything to be aggregated, a black square is drawn. If it does, the result
// should just erase the previously drawn trail completely.
aggregated_frame = aggregator.Aggregate(
root_surface_id, this->GetNextDisplayTime(), gfx::OVERLAY_TRANSFORM_NONE,
delegated_ink_helper.GetDelegatedInkDamageRect());
pass_list = &aggregated_frame.render_pass_list;
EXPECT_TRUE(this->RunPixelTest(pass_list,
base::FilePath(FILE_PATH_LITERAL("green.png")),
pixel_comparator));
}
} // namespace
} // namespace viz
#endif // !BUILDFLAG(IS_ANDROID)