chromium/components/viz/service/frame_sinks/surface_synchronization_unittest.cc

// Copyright 2017 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/containers/flat_set.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/simple_test_tick_clock.h"
#include "components/viz/common/features.h"
#include "components/viz/common/surfaces/surface_id.h"
#include "components/viz/service/display_embedder/server_shared_bitmap_manager.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/frame_index_constants.h"
#include "components/viz/service/surfaces/surface.h"
#include "components/viz/service/surfaces/surface_allocation_group.h"
#include "components/viz/test/begin_frame_args_test.h"
#include "components/viz/test/compositor_frame_helpers.h"
#include "components/viz/test/fake_external_begin_frame_source.h"
#include "components/viz/test/fake_surface_observer.h"
#include "components/viz/test/mock_compositor_frame_sink_client.h"
#include "components/viz/test/surface_id_allocator_set.h"
#include "components/viz/test/test_surface_id_allocator.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"

_;
Eq;
IsEmpty;
UnorderedElementsAre;

namespace viz {
namespace {

constexpr bool kIsRoot =;
constexpr bool kIsChildRoot =;
constexpr FrameSinkId kDisplayFrameSink(2, 0);
constexpr FrameSinkId kParentFrameSink(3, 0);
constexpr FrameSinkId kChildFrameSink1(65563, 0);
constexpr FrameSinkId kChildFrameSink2(65564, 0);
constexpr FrameSinkId kArbitraryFrameSink(1337, 7331);

const uint64_t kBeginFrameSourceId =;

std::vector<SurfaceId> empty_surface_ids() {}
std::vector<SurfaceRange> empty_surface_ranges() {}

CompositorFrame MakeCompositorFrame(
    std::vector<SurfaceId> activation_dependencies,
    std::vector<SurfaceRange> referenced_surfaces,
    std::vector<TransferableResource> resource_list,
    const FrameDeadline& deadline = FrameDeadline()) {}

}  // namespace

class SurfaceSynchronizationTest : public testing::Test {};

// The display root surface should have a surface reference from the top-level
// root added/removed when a CompositorFrame is submitted with a new
// SurfaceId.
TEST_F(SurfaceSynchronizationTest, RootSurfaceReceivesReferences) {}

// The parent Surface is blocked on |child_id1| and |child_id2|.
TEST_F(SurfaceSynchronizationTest, BlockedOnTwo) {}

// The parent Surface is blocked on |child_id2| which is blocked on
// |child_id3|.
TEST_F(SurfaceSynchronizationTest, BlockedChain) {}

// parent_surface and child_surface1 are blocked on |child_id2|.
TEST_F(SurfaceSynchronizationTest, TwoBlockedOnOne) {}

// parent_surface is blocked on |child_id1|, and child_surface2 is blocked on
// |child_id2| until the deadline hits.
TEST_F(SurfaceSynchronizationTest, DeadlineHits) {}

// This test verifies that unlimited deadline mode works and that surfaces will
// not activate until dependencies are resolved.
TEST_F(SurfaceSynchronizationTest, UnlimitedDeadline) {}

// parent_surface is blocked on |child_id1| until a late BeginFrame arrives and
// triggers a deadline.
TEST_F(SurfaceSynchronizationTest, LateBeginFrameTriggersDeadline) {}

// This test verifies at the Surface activates once a CompositorFrame is
// submitted that has no unresolved dependencies.
TEST_F(SurfaceSynchronizationTest, NewFrameOverridesOldDependencies) {}

// Supports testing features::OnBeginFrameAcks, which changes the expectations
// of what IPCs are sent to the CompositorFrameSinkClient. When enabled
// OnBeginFrame also handles ReturnResources as well as
// DidReceiveCompositorFrameAck.
class OnBeginFrameAcksSurfaceSynchronizationTest
    : public SurfaceSynchronizationTest,
      public testing::WithParamInterface<std::tuple<bool, bool>> {};

OnBeginFrameAcksSurfaceSynchronizationTest::
    OnBeginFrameAcksSurfaceSynchronizationTest() {}

void OnBeginFrameAcksSurfaceSynchronizationTest::SetUp() {}

// This test verifies that a pending CompositorFrame does not affect surface
// references. A new surface from a child will continue to exist as a temporary
// reference until the parent's frame activates.
TEST_P(OnBeginFrameAcksSurfaceSynchronizationTest,
       OnlyActiveFramesAffectSurfaceReferences) {}

// This test verifies that we do not double count returned resources when a
// CompositorFrame starts out as pending, then becomes active, and then is
// replaced with another active CompositorFrame.
TEST_P(OnBeginFrameAcksSurfaceSynchronizationTest, ResourcesOnlyReturnedOnce) {}

// This test verifies that if a surface has both a pending and active
// CompositorFrame and the pending CompositorFrame activates, replacing
// the existing active CompositorFrame, then the surface reference hierarchy
// will be updated allowing garbage collection of surfaces that are no longer
// referenced.
TEST_P(OnBeginFrameAcksSurfaceSynchronizationTest,
       DropStaleReferencesAfterActivation) {}

// Verifies that LatencyInfo does not get too large after multiple frame
// submissions.
TEST_F(SurfaceSynchronizationTest, LimitLatencyInfo) {}

// Checks whether SurfaceAllocationGroup properly aggregates LatencyInfo of
// multiple surfaces. In this variation of the test, there are no pending
// frames.
TEST_F(SurfaceSynchronizationTest,
       LatencyInfoAggregation_NoUnresolvedDependencies) {}

// Checks whether SurfaceAllocationGroup properly aggregates LatencyInfo of
// multiple surfaces. In this variation of the test, the older surface has both
// pending and active frames and we verify that the LatencyInfo of both pending
// and active frame are present in the aggregated LatencyInfo.
TEST_F(SurfaceSynchronizationTest,
       LatencyInfoAggregation_OldSurfaceHasPendingAndActiveFrame) {}

// Checks whether SurfaceAllocationGroup properly aggregates LatencyInfo of
// multiple surfaces. In this variation of the test, the newer surface has a
// pending frame that becomes active after the dependency is resolved and we
// make sure the LatencyInfo of the activated frame is included in the
// aggregated LatencyInfo.
TEST_F(SurfaceSynchronizationTest,
       LatencyInfoAggregation_NewSurfaceHasPendingFrame) {}

// Checks whether SurfaceAllocationGroup properly aggregates LatencyInfo of
// multiple surfaces. In this variation of the test, multiple older surfaces
// with pending frames exist during aggregation of an activated frame on a newer
// surface.
TEST_F(SurfaceSynchronizationTest,
       LatencyInfoAggregation_MultipleOldSurfacesWithPendingFrames) {}

// This test verifies that when a new surface is created, the LatencyInfo of the
// previous surface does not get carried over into the new surface.
TEST_F(SurfaceSynchronizationTest, LatencyInfoNotCarriedOver) {}

// Checks that resources and ack are sent together if possible.
TEST_P(OnBeginFrameAcksSurfaceSynchronizationTest, ReturnResourcesWithAck) {}

// Verifies that arrival of a new CompositorFrame doesn't change the fact that a
// surface is marked for destruction.
TEST_P(OnBeginFrameAcksSurfaceSynchronizationTest, SubmitToDestroyedSurface) {}

// Verifies that if a LocalSurfaceId belonged to a surface that doesn't
// exist anymore, it can not be recreated.
TEST_F(SurfaceSynchronizationTest, LocalSurfaceIdIsNotReusable) {}

// This test verifies that a crash does not occur if garbage collection is
// triggered during surface dependency resolution. This test triggers garbage
// collection during surface resolution, by causing an activation to remove
// a surface subtree from the root. Both the old subtree and the new
// activated subtree refer to the same dependency. The old subtree was activated
// by deadline, and the new subtree was activated by a dependency finally
// resolving.
TEST_F(SurfaceSynchronizationTest, DependencyTrackingGarbageCollection) {}

// This test verifies that a crash does not occur if garbage collection is
// triggered when a deadline forces frame activation. This test triggers garbage
// collection during deadline activation by causing the activation of a display
// frame to replace a previously activated display frame that was referring to
// a now-unreachable surface subtree. That subtree gets garbage collected during
// deadline activation. SurfaceDependencyTracker is also tracking a surface
// from that subtree due to an unresolved dependency. This test verifies that
// this dependency resolution does not crash.
TEST_F(SurfaceSynchronizationTest, GarbageCollectionOnDeadline) {}

// This test verifies that a CompositorFrame will only blocked on embedded
// surfaces but not on other retained surface IDs in the CompositorFrame.
TEST_F(SurfaceSynchronizationTest, OnlyBlockOnEmbeddedSurfaces) {}

// This test verifies that a late arriving CompositorFrame activates
// immediately and does not trigger a new deadline.
TEST_F(SurfaceSynchronizationTest, LateArrivingDependency) {}

// This test verifies that a late arriving CompositorFrame activates
// immediately along with its subtree and does not trigger a new deadline.
TEST_F(SurfaceSynchronizationTest, MultiLevelLateArrivingDependency) {}

// This test verifies that CompositorFrames submitted to a surface referenced
// by a parent CompositorFrame as a fallback will be ACK'ed immediately.
TEST_P(OnBeginFrameAcksSurfaceSynchronizationTest, FallbackSurfacesClosed) {}

// This test verifies that two surface subtrees have independent deadlines.
TEST_F(SurfaceSynchronizationTest, IndependentDeadlines) {}

// This test verifies that a child inherits its deadline from its dependent
// parent (embedder) if the deadline is shorter than child's deadline.
TEST_F(SurfaceSynchronizationTest, InheritShorterDeadline) {}

// This test verifies that in case of A embedding B embedding C, if the deadline
// of A is longer than the deadline of B, B's deadline is not extended.
TEST_F(SurfaceSynchronizationTest, ChildDeadlineNotExtendedByInheritance) {}

// This test verifies that all surfaces within a dependency chain will
// ultimately inherit the parent's shorter deadline even if the grandchild is
// available before the child.
TEST_F(SurfaceSynchronizationTest, MultiLevelDeadlineInheritance) {}

// This test verifies that no crash occurs if a CompositorFrame activates AFTER
// its FrameSink has been destroyed.
TEST_F(SurfaceSynchronizationTest, FrameActivationAfterFrameSinkDestruction) {}

TEST_F(SurfaceSynchronizationTest, PreviousFrameSurfaceId) {}

TEST_F(SurfaceSynchronizationTest, FrameIndexWithPendingFrames) {}

// This test verifies that a new surface with a pending CompositorFrame gets
// a temporary reference immediately, as opposed to when the surface activates.
TEST_F(SurfaceSynchronizationTest, PendingSurfaceKeptAlive) {}

// Tests getting the correct active frame index.
TEST_F(SurfaceSynchronizationTest, ActiveFrameIndex) {}

// This test verifies that SurfaceManager::GetLatestInFlightSurface returns
// the latest child surface not yet set as a fallback by the parent.
// Alternatively, it returns the fallback surface specified, if no tempoary
// references to child surfaces are available. This mechanism is used by surface
// synchronization to present the freshest surfaces available at aggregation
// time.
TEST_F(SurfaceSynchronizationTest, LatestInFlightSurface) {}

// This test verifies that GetLatestInFlightSurface will return nullptr when the
// start of the range is newer than its end, even if a surface matching the end
// exists.
TEST_F(SurfaceSynchronizationTest,
       LatestInFlightSurfaceWithInvalidSurfaceRange) {}

// This test verifies that GetLatestInFlightSurface will return the primary or
// nullptr if fallback is not specified.
// TODO(akaba): this would change after https://crbug.com/861769
TEST_F(SurfaceSynchronizationTest, LatestInFlightSurfaceWithoutFallback) {}

// This test verifies that GetLatestInFlightSurface will not return null if the
// fallback is garbage collected, but instead returns the latest surface older
// than primary if that exists.
TEST_F(SurfaceSynchronizationTest, LatestInFlightSurfaceWithGarbageFallback) {}

// This test verifies that in the case of different frame sinks
// GetLatestInFlightSurface will return the latest surface in the primary's
// FrameSinkId or the latest in the fallback's FrameSinkId if no surface exists
// in the primary's.
TEST_F(SurfaceSynchronizationTest, LatestInFlightSurfaceDifferentFrameSinkIds) {}

// This test verifies that GetLatestInFlightSurface will return the
// primary surface ID if it is in the temporary reference queue.
TEST_F(SurfaceSynchronizationTest, LatestInFlightSurfaceReturnPrimary) {}

// This test verifies that GetLatestInFlightSurface can use persistent
// references to compute the latest surface.
TEST_F(SurfaceSynchronizationTest,
       LatestInFlightSurfaceUsesPersistentReferences) {}

// This test verifies that GetLatestInFlightSurface will skip a surface if
// its nonce is different.
TEST_F(SurfaceSynchronizationTest, LatestInFlightSurfaceSkipDifferentNonce) {}

// This test verifies that if a child submits a LocalSurfaceId newer that the
// parent's dependency, then the parent will drop its dependency and activate
// if possible. In this version of the test, parent sequence number of the
// activated surface is larger than that in the dependency, while the child
// sequence number is smaller.
TEST_F(SurfaceSynchronizationTest, DropDependenciesThatWillNeverArrive1) {}

// This test verifies that if a child submits a LocalSurfaceId newer that the
// parent's dependency, then the parent will drop its dependency and activate
// if possible. In this version of the test, parent sequence number of the
// activated surface is smaller than that in the dependency, while the child
// sequence number is larger.
TEST_F(SurfaceSynchronizationTest, DropDependenciesThatWillNeverArrive2) {}

// This test verifies that a surface will continue to observe a child surface
// until its dependency arrives.
TEST_F(SurfaceSynchronizationTest, ObserveDependenciesUntilArrival) {}

// This test verifies that we don't mark the previous active surface for
// destruction until the new surface activates.
TEST_F(SurfaceSynchronizationTest,
       MarkPreviousSurfaceForDestructionAfterActivation) {}

// This test verifies that CompositorFrameSinkSupport does not refer to
// a valid but non-existant |last_activated_surface_id_|.
TEST_F(SurfaceSynchronizationTest, SetPreviousFrameSurfaceDoesntCrash) {}

// This test verifies that when a surface activates that has the same
// FrameSinkId of the primary but its embed token doesn't match, we don't
// update the references of the parent.
TEST_F(SurfaceSynchronizationTest,
       SurfaceReferenceTracking_PrimaryEmbedTokenDoesntMatch) {}

// This test verifies that a parent referencing a SurfaceRange get updated
// whenever a child surface activates inside this range. This should also update
// the SurfaceReferences tree.
TEST_F(SurfaceSynchronizationTest,
       SurfaceReferenceTracking_NewerSurfaceUpdatesReferences) {}

// This test verifies that once a frame sink become invalidated, it should
// immediately unblock all pending frames depending on that sink.
TEST_F(SurfaceSynchronizationTest,
       InvalidatedFrameSinkShouldNotBlockActivation) {}

TEST_F(SurfaceSynchronizationTest, EvictSurface) {}

// Tests that in cases where a pending-deletion surface (surface A) is
// activated during anothother surface (surface B)'s deletion, we don't attempt
// to delete surface A twice.
TEST_F(SurfaceSynchronizationTest, SurfaceActivationDuringDeletion) {}

// This test verifies that if a surface is created with new embed token, a new
// allocation group is created, and once that surface is destroyed, the
// allocation group is destroyed as well.
TEST_F(SurfaceSynchronizationTest,
       AllocationGroupCreationInitiatedBySubmitter) {}

// This test verifies that if a surface references another surface that has an
// embed token that was never seen before, an allocation group will be created
// for the embedded surface.
TEST_F(SurfaceSynchronizationTest, AllocationGroupCreationInitiatedByEmbedder) {}

// This test verifies that if the parent embeds a SurfaceRange that has
// different embed tokens at start and end, then initially both allocation
// groups are created, but once the primary becomes available, the allocation
// group for the fallback gets destroyed.
TEST_F(SurfaceSynchronizationTest,
       FallbackAllocationGroupDestroyedAfterPrimaryAvailable) {}

// This test verifies that if the parent embeds a SurfaceRange that has
// different embed tokens for primary and fallback and a surface already exists
// in the primary's allocation group, we don't create an allocation group for
// the fallback at all.
TEST_F(SurfaceSynchronizationTest,
       FallbackAllocationGroupNotCreatedIfPrimaryAvailable) {}

// Verifies that the value of last active surface is correct after embed token
// changes. https://crbug.com/967012
TEST_F(SurfaceSynchronizationTest,
       CheckLastActiveSurfaceAfterEmbedTokenChange) {}

// Regression test for https://crbug.com/1000868. Verify that the output of
// GetLatestInFlightSurface is correct when there is a conflict between the last
// surface in the group and the queried SurfaceRange.
TEST_F(SurfaceSynchronizationTest, LatestInFlightSurfaceConflict) {}

// Check that if two different SurfaceIds with the same embed token are
// embedded, viz doesn't crash. https://crbug.com/1001143
TEST_F(SurfaceSynchronizationTest,
       DuplicateAllocationGroupInActivationDependencies) {}

class SurfaceSynchronizationTestMayAlwaysAckOnActivation
    : public SurfaceSynchronizationTest,
      public testing::WithParamInterface<bool> {};

SurfaceSynchronizationTestMayAlwaysAckOnActivation::
    SurfaceSynchronizationTestMayAlwaysAckOnActivation() {}

// Tests that when a new CompositorFrame for an Embedded Surface arrives, and is
// not immediately ACKed, that when a CompositorFrame from its Embedder arrives
// with new ActivationDependencies, that the UnACKed frame receives and ACK so
// that that client can begin frame production to satistfy the new dependencies.
// (https://crbug.com/1203804)
TEST_P(SurfaceSynchronizationTestMayAlwaysAckOnActivation,
       UnAckedSurfaceArrivesBeforeNewActivationDependencies) {}

INSTANTIATE_TEST_SUITE_P();

class SurfaceSynchronizationTestDrawImmediatelyWithActivationAck
    : public SurfaceSynchronizationTest {};

// Tests that a frame activation causes acks when submitted for a frame prior to
// an interactive frame or within the cooldown frames, post-interaction.
TEST_F(SurfaceSynchronizationTestDrawImmediatelyWithActivationAck,
       AckOnSurfaceActivationDuringInteractionCooldown) {}

// Tests that when a CompositorFrame for an Embedded Surface arrives after its
// Embedder has submitted new ActivationDependencies, that it is immediately
// ACKed, even if normally it would not be due to damage. This way we don't have
// an Embedder blocked on an unACKed frame. (https://crbug.com/1203804)
TEST_P(OnBeginFrameAcksSurfaceSynchronizationTest,
       UnAckedOldActivationDependencyArrivesAfterNewDependencies) {}

// The first boolean parameter is whether BeginFrameAcks is enabled;
// the second is whether AutoNeedsBeginFrame is enabled.
INSTANTIATE_TEST_SUITE_P();

}  // namespace viz