blob: cbfed845b1f2b7cac8fbe1e0154cd6ce5ff94a08 [file] [log] [blame]
// Copyright 2015 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/viz/service/display/display_damage_tracker.h"
#include <utility>
#include "base/test/null_task_runner.h"
#include "components/viz/common/quads/compositor_frame.h"
#include "components/viz/common/quads/compositor_render_pass.h"
#include "components/viz/common/surfaces/frame_sink_id.h"
#include "components/viz/common/surfaces/parent_local_surface_id_allocator.h"
#include "components/viz/service/display/display_resource_provider_software.h"
#include "components/viz/service/display/surface_aggregator.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/test/compositor_frame_helpers.h"
#include "components/viz/test/fake_external_begin_frame_source.h"
#include "components/viz/test/mock_compositor_frame_sink_client.h"
#include "gpu/command_buffer/service/scheduler.h"
#include "gpu/command_buffer/service/shared_image/shared_image_manager.h"
#include "gpu/command_buffer/service/sync_point_manager.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace viz {
namespace {
constexpr FrameSinkId kRootFrameSinkId(3, 3);
constexpr FrameSinkId kChildFrameSinkId(4, 4);
} // namespace
class DisplayDamageTrackerTest : public testing::Test {
public:
DisplayDamageTrackerTest()
: manager_(FrameSinkManagerImpl::InitParams()),
resource_provider_(&shared_image_manager_, &gpu_scheduler_),
aggregator_(manager_.surface_manager(), &resource_provider_, false),
root_client_(&manager_, kRootFrameSinkId),
task_runner_(base::MakeRefCounted<base::NullTaskRunner>()),
fake_begin_frame_source_(0.f, false),
damage_tracker_(
std::make_unique<DisplayDamageTracker>(manager_.surface_manager(),
&aggregator_)) {
manager_.RegisterFrameSinkId(kRootFrameSinkId, false);
manager_.RegisterBeginFrameSource(&fake_begin_frame_source_,
kRootFrameSinkId);
damage_tracker_->SetNewRootSurface(root_client_.surface_id());
}
~DisplayDamageTrackerTest() override {
manager_.UnregisterBeginFrameSource(&fake_begin_frame_source_);
}
protected:
class Client {
public:
Client(FrameSinkManagerImpl* manager, FrameSinkId frame_sink_id)
: frame_sink_id_(frame_sink_id),
support_(
std::make_unique<CompositorFrameSinkSupport>(&client_,
manager,
frame_sink_id,
/*is_root=*/true)) {
MakeNewSurfaceId();
support_->SetNeedsBeginFrame(true);
}
SurfaceId MakeNewSurfaceId() {
id_allocator_.GenerateId();
local_surface_id_ = id_allocator_.GetCurrentLocalSurfaceId();
return SurfaceId(frame_sink_id_, local_surface_id_);
}
SurfaceId surface_id() {
return SurfaceId(frame_sink_id_, local_surface_id_);
}
void SetUpAutoNeedsBeginFrame() {
support_->SetNeedsBeginFrame(false);
support_->SetAutoNeedsBeginFrame();
}
void SubmitCompositorFrame(const BeginFrameId& frame_id) {
CompositorRenderPassList pass_list;
auto pass = CompositorRenderPass::Create();
pass->output_rect = gfx::Rect(0, 0, 100, 100);
pass->damage_rect = gfx::Rect(10, 10, 1, 1);
pass->id = CompositorRenderPassId{1u};
pass_list.push_back(std::move(pass));
BeginFrameAck ack;
ack.frame_id = frame_id;
ack.has_damage = true;
CompositorFrame frame = CompositorFrameBuilder()
.SetRenderPassList(std::move(pass_list))
.SetBeginFrameAck(ack)
.Build();
support_->SubmitCompositorFrame(local_surface_id_, std::move(frame));
}
MockCompositorFrameSinkClient client_;
FrameSinkId frame_sink_id_;
LocalSurfaceId local_surface_id_;
std::unique_ptr<CompositorFrameSinkSupport> support_;
ParentLocalSurfaceIdAllocator id_allocator_;
};
void TickBeginFrame() {
// Ack previous surfaces
damage_tracker_->RunDrawCallbacks();
last_begin_frame_args_ =
fake_begin_frame_source_.CreateBeginFrameArgs(BEGINFRAME_FROM_HERE);
fake_begin_frame_source_.TestOnBeginFrame(last_begin_frame_args_);
}
gpu::SharedImageManager shared_image_manager_;
gpu::SyncPointManager sync_point_manager_;
gpu::Scheduler gpu_scheduler_{&sync_point_manager_};
FrameSinkManagerImpl manager_;
DisplayResourceProviderSoftware resource_provider_;
SurfaceAggregator aggregator_;
Client root_client_;
scoped_refptr<base::NullTaskRunner> task_runner_;
FakeExternalBeginFrameSource fake_begin_frame_source_;
std::unique_ptr<DisplayDamageTracker> damage_tracker_;
BeginFrameArgs last_begin_frame_args_;
};
TEST_F(DisplayDamageTrackerTest, Basic) {
TickBeginFrame();
// Check that we don't have root surface
EXPECT_TRUE(damage_tracker_->IsRootSurfaceValid());
EXPECT_TRUE(damage_tracker_->root_frame_missing());
EXPECT_FALSE(damage_tracker_->HasPendingSurfaces(last_begin_frame_args_));
// Submit root surface and check that we have root surface and no pending
// surfaces
root_client_.SubmitCompositorFrame(last_begin_frame_args_.frame_id);
EXPECT_FALSE(damage_tracker_->root_frame_missing());
EXPECT_FALSE(damage_tracker_->HasPendingSurfaces(last_begin_frame_args_));
// Begin next frame
TickBeginFrame();
EXPECT_TRUE(damage_tracker_->IsRootSurfaceValid());
EXPECT_FALSE(damage_tracker_->root_frame_missing());
EXPECT_TRUE(damage_tracker_->HasPendingSurfaces(last_begin_frame_args_));
// Submit CF and check that we have root surface and no pending surfaces
root_client_.SubmitCompositorFrame(last_begin_frame_args_.frame_id);
EXPECT_FALSE(damage_tracker_->root_frame_missing());
EXPECT_FALSE(damage_tracker_->HasPendingSurfaces(last_begin_frame_args_));
}
TEST_F(DisplayDamageTrackerTest, Resize) {
EXPECT_TRUE(damage_tracker_->root_frame_missing());
// Submit initial frame
TickBeginFrame();
root_client_.SubmitCompositorFrame(last_begin_frame_args_.frame_id);
// Expect no damage because of resize
EXPECT_FALSE(
damage_tracker_->expecting_root_surface_damage_because_of_resize());
// Resize display and expect there is root frame, but with expected damage
damage_tracker_->DisplayResized();
EXPECT_TRUE(
damage_tracker_->expecting_root_surface_damage_because_of_resize());
EXPECT_FALSE(damage_tracker_->root_frame_missing());
// Submit next frame
TickBeginFrame();
root_client_.SubmitCompositorFrame(last_begin_frame_args_.frame_id);
// Expecting no damage
EXPECT_FALSE(
damage_tracker_->expecting_root_surface_damage_because_of_resize());
EXPECT_FALSE(damage_tracker_->root_frame_missing());
}
TEST_F(DisplayDamageTrackerTest, NewRoot) {
EXPECT_TRUE(damage_tracker_->root_frame_missing());
// Submit initial frame
TickBeginFrame();
root_client_.SubmitCompositorFrame(last_begin_frame_args_.frame_id);
// Root shouldn't be missing and no pending surfaces
EXPECT_FALSE(damage_tracker_->root_frame_missing());
EXPECT_FALSE(damage_tracker_->HasPendingSurfaces(last_begin_frame_args_));
// Set new surface and expect root is missing
damage_tracker_->SetNewRootSurface(root_client_.MakeNewSurfaceId());
EXPECT_TRUE(damage_tracker_->root_frame_missing());
EXPECT_FALSE(damage_tracker_->HasPendingSurfaces(last_begin_frame_args_));
// Submit new root
TickBeginFrame();
root_client_.SubmitCompositorFrame(last_begin_frame_args_.frame_id);
// Check that root is in place and no surface pending.
EXPECT_FALSE(damage_tracker_->root_frame_missing());
EXPECT_FALSE(damage_tracker_->HasPendingSurfaces(last_begin_frame_args_));
}
TEST_F(DisplayDamageTrackerTest, TwoSurfaces) {
Client embedded_client(&manager_, kChildFrameSinkId);
manager_.RegisterFrameSinkHierarchy(kRootFrameSinkId, kChildFrameSinkId);
EXPECT_TRUE(damage_tracker_->root_frame_missing());
// Submit initial frame
TickBeginFrame();
root_client_.SubmitCompositorFrame(last_begin_frame_args_.frame_id);
embedded_client.SubmitCompositorFrame(last_begin_frame_args_.frame_id);
// Expect no pending surfaces
EXPECT_FALSE(damage_tracker_->root_frame_missing());
EXPECT_FALSE(damage_tracker_->HasPendingSurfaces(last_begin_frame_args_));
// Begin next frame and check submission in order embedded_client, root_client
TickBeginFrame();
EXPECT_TRUE(damage_tracker_->HasPendingSurfaces(last_begin_frame_args_));
embedded_client.SubmitCompositorFrame(last_begin_frame_args_.frame_id);
EXPECT_TRUE(damage_tracker_->HasPendingSurfaces(last_begin_frame_args_));
root_client_.SubmitCompositorFrame(last_begin_frame_args_.frame_id);
EXPECT_FALSE(damage_tracker_->HasPendingSurfaces(last_begin_frame_args_));
// Begin next frame and check submission in order root_client, embedded_client
TickBeginFrame();
EXPECT_TRUE(damage_tracker_->HasPendingSurfaces(last_begin_frame_args_));
root_client_.SubmitCompositorFrame(last_begin_frame_args_.frame_id);
EXPECT_TRUE(damage_tracker_->HasPendingSurfaces(last_begin_frame_args_));
embedded_client.SubmitCompositorFrame(last_begin_frame_args_.frame_id);
EXPECT_FALSE(damage_tracker_->HasPendingSurfaces(last_begin_frame_args_));
manager_.UnregisterFrameSinkHierarchy(kRootFrameSinkId, kChildFrameSinkId);
}
TEST_F(DisplayDamageTrackerTest, UnsolicitedFrameUnderAutoNeedsBeginFrame) {
root_client_.SetUpAutoNeedsBeginFrame();
// Ensure that when submitting the unsolicited frame below, a new
// BeginFrameArgs is used.
TickBeginFrame();
// Submit an unsolicited frame.
root_client_.SubmitCompositorFrame(
BeginFrameAck::CreateManualAckWithDamage().frame_id);
// Send ACK for the frame.
damage_tracker_->RunDrawCallbacks();
EXPECT_TRUE(damage_tracker_->IsRootSurfaceValid());
EXPECT_FALSE(damage_tracker_->root_frame_missing());
// Verify that the corresponding surface is not considered as pending.
EXPECT_FALSE(damage_tracker_->HasPendingSurfaces(last_begin_frame_args_));
}
} // namespace viz