Index: cc/surfaces/compositor_frame_sink_support_unittest.cc |
diff --git a/cc/surfaces/compositor_frame_sink_support_unittest.cc b/cc/surfaces/compositor_frame_sink_support_unittest.cc |
index 7451f8cb5d7c68e4c5dbdf52f8848ab3f38738ad..bdaa1ecc494619b251fb0f391e42214dbb814714 100644 |
--- a/cc/surfaces/compositor_frame_sink_support_unittest.cc |
+++ b/cc/surfaces/compositor_frame_sink_support_unittest.cc |
@@ -6,13 +6,18 @@ |
#include "base/macros.h" |
#include "cc/output/compositor_frame.h" |
+#include "cc/output/copy_output_request.h" |
+#include "cc/output/copy_output_result.h" |
+#include "cc/resources/resource_provider.h" |
#include "cc/surfaces/compositor_frame_sink_support_client.h" |
#include "cc/surfaces/frame_sink_id.h" |
#include "cc/surfaces/surface_id.h" |
+#include "cc/surfaces/surface_info.h" |
#include "cc/surfaces/surface_manager.h" |
#include "cc/test/begin_frame_args_test.h" |
#include "cc/test/compositor_frame_helpers.h" |
#include "cc/test/fake_external_begin_frame_source.h" |
+#include "cc/test/mock_compositor_frame_sink_support_client.h" |
#include "testing/gmock/include/gmock/gmock.h" |
#include "testing/gtest/include/gtest/gtest.h" |
@@ -24,1409 +29,761 @@ using testing::_; |
using testing::Eq; |
namespace cc { |
+namespace test { |
namespace { |
-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); |
+constexpr bool kIsRoot = true; |
+constexpr bool kIsChildRoot = false; |
+constexpr bool kHandlesFrameSinkIdInvalidation = true; |
+constexpr bool kNeedsSyncPoints = true; |
+ |
+constexpr FrameSinkId kArbitraryFrameSinkId(1, 1); |
+constexpr FrameSinkId kAnotherArbitraryFrameSinkId(2, 2); |
+constexpr FrameSinkId kYetAnotherArbitraryFrameSinkId(3, 3); |
+ |
+const base::UnguessableToken kArbitraryToken = base::UnguessableToken::Create(); |
+const base::UnguessableToken kArbitrarySourceId1 = |
+ base::UnguessableToken::Deserialize(0xdead, 0xbeef); |
+const base::UnguessableToken kArbitrarySourceId2 = |
+ base::UnguessableToken::Deserialize(0xdead, 0xbee0); |
+ |
+gpu::SyncToken GenTestSyncToken(int id) { |
+ gpu::SyncToken token; |
+ token.Set(gpu::CommandBufferNamespace::GPU_IO, 0, |
+ gpu::CommandBufferId::FromUnsafeValue(id), 1); |
+ return token; |
+} |
-class MockCompositorFrameSinkSupportClient |
+class FakeCompositorFrameSinkSupportClient |
: public CompositorFrameSinkSupportClient { |
public: |
- MockCompositorFrameSinkSupportClient() { |
- ON_CALL(*this, ReclaimResources(_)) |
- .WillByDefault(Invoke( |
- this, |
- &MockCompositorFrameSinkSupportClient::ReclaimResourcesInternal)); |
- ON_CALL(*this, DidReceiveCompositorFrameAck(_)) |
- .WillByDefault(Invoke( |
- this, |
- &MockCompositorFrameSinkSupportClient::ReclaimResourcesInternal)); |
- } |
+ FakeCompositorFrameSinkSupportClient() = default; |
+ ~FakeCompositorFrameSinkSupportClient() override = default; |
- ReturnedResourceArray& last_returned_resources() { |
- return last_returned_resources_; |
+ void DidReceiveCompositorFrameAck( |
+ const ReturnedResourceArray& resources) override { |
+ InsertResources(resources); |
} |
- // CompositorFrameSinkSupportClient implementation. |
- MOCK_METHOD1(DidReceiveCompositorFrameAck, |
- void(const ReturnedResourceArray&)); |
- MOCK_METHOD1(OnBeginFrame, void(const BeginFrameArgs&)); |
- MOCK_METHOD1(ReclaimResources, void(const ReturnedResourceArray&)); |
- MOCK_METHOD2(WillDrawSurface, void(const LocalSurfaceId&, const gfx::Rect&)); |
+ void OnBeginFrame(const BeginFrameArgs& args) override {} |
- private: |
- void ReclaimResourcesInternal(const ReturnedResourceArray& resources) { |
- last_returned_resources_ = resources; |
+ void ReclaimResources(const ReturnedResourceArray& resources) override { |
+ InsertResources(resources); |
} |
- ReturnedResourceArray last_returned_resources_; |
-}; |
- |
-std::vector<SurfaceId> empty_surface_ids() { |
- return std::vector<SurfaceId>(); |
-} |
- |
-SurfaceId MakeSurfaceId(const FrameSinkId& frame_sink_id, uint32_t local_id) { |
- return SurfaceId( |
- frame_sink_id, |
- LocalSurfaceId(local_id, base::UnguessableToken::Deserialize(0, 1u))); |
-} |
- |
-CompositorFrame MakeCompositorFrame( |
- std::vector<SurfaceId> activation_dependencies, |
- std::vector<SurfaceId> referenced_surfaces, |
- TransferableResourceArray resource_list) { |
- CompositorFrame compositor_frame = test::MakeCompositorFrame(); |
- compositor_frame.metadata.begin_frame_ack = BeginFrameAck(0, 1, 1, true); |
- compositor_frame.metadata.activation_dependencies = |
- std::move(activation_dependencies); |
- compositor_frame.metadata.referenced_surfaces = |
- std::move(referenced_surfaces); |
- compositor_frame.resource_list = std::move(resource_list); |
- return compositor_frame; |
-} |
- |
-CompositorFrame MakeCompositorFrame() { |
- return MakeCompositorFrame(empty_surface_ids(), empty_surface_ids(), |
- TransferableResourceArray()); |
-} |
+ void WillDrawSurface(const LocalSurfaceId& local_surface_id, |
+ const gfx::Rect& damage_rect) override {} |
-CompositorFrame MakeCompositorFrame( |
- std::vector<SurfaceId> activation_dependencies) { |
- return MakeCompositorFrame(activation_dependencies, activation_dependencies, |
- TransferableResourceArray()); |
-} |
- |
-CompositorFrame MakeCompositorFrame( |
- std::vector<SurfaceId> activation_dependencies, |
- std::vector<SurfaceId> referenced_surfaces) { |
- return MakeCompositorFrame(std::move(activation_dependencies), |
- std::move(referenced_surfaces), |
- TransferableResourceArray()); |
-} |
+ void clear_returned_resources() { returned_resources_.clear(); } |
+ const ReturnedResourceArray& returned_resources() { |
+ return returned_resources_; |
+ } |
-CompositorFrame MakeCompositorFrameWithResources( |
- std::vector<SurfaceId> activation_dependencies, |
- TransferableResourceArray resource_list) { |
- return MakeCompositorFrame(activation_dependencies, empty_surface_ids(), |
- std::move(resource_list)); |
-} |
+ private: |
+ void InsertResources(const ReturnedResourceArray& resources) { |
+ returned_resources_.insert(returned_resources_.end(), resources.begin(), |
+ resources.end()); |
+ } |
-TransferableResource MakeResource(ResourceId id, |
- ResourceFormat format, |
- uint32_t filter, |
- const gfx::Size& size) { |
- TransferableResource resource; |
- resource.id = id; |
- resource.format = format; |
- resource.filter = filter; |
- resource.size = size; |
- return resource; |
-} |
+ ReturnedResourceArray returned_resources_; |
-} // namespace |
+ DISALLOW_COPY_AND_ASSIGN(FakeCompositorFrameSinkSupportClient); |
+}; |
class CompositorFrameSinkSupportTest : public testing::Test, |
public SurfaceObserver { |
public: |
CompositorFrameSinkSupportTest() |
- : surface_manager_(SurfaceManager::LifetimeType::REFERENCES) {} |
- ~CompositorFrameSinkSupportTest() override {} |
- |
- CompositorFrameSinkSupport& display_support() { return *supports_[0]; } |
- Surface* display_surface() { |
- return display_support().current_surface_for_testing(); |
- } |
- |
- CompositorFrameSinkSupport& parent_support() { return *supports_[1]; } |
- Surface* parent_surface() { |
- return parent_support().current_surface_for_testing(); |
+ : support_( |
+ CompositorFrameSinkSupport::Create(&fake_support_client_, |
+ &manager_, |
+ kArbitraryFrameSinkId, |
+ kIsRoot, |
+ kHandlesFrameSinkIdInvalidation, |
+ kNeedsSyncPoints)), |
+ local_surface_id_(3, kArbitraryToken), |
+ frame_sync_token_(GenTestSyncToken(4)), |
+ consumer_sync_token_(GenTestSyncToken(5)) { |
+ manager_.AddObserver(this); |
} |
- const ReferencedSurfaceTracker& parent_reference_tracker() { |
- return parent_support().ReferenceTrackerForTesting(); |
+ ~CompositorFrameSinkSupportTest() override { |
+ manager_.RemoveObserver(this); |
+ support_->EvictFrame(); |
} |
- CompositorFrameSinkSupport& child_support1() { return *supports_[2]; } |
- Surface* child_surface1() { |
- return child_support1().current_surface_for_testing(); |
+ const SurfaceId& last_created_surface_id() const { |
+ return last_created_surface_id_; |
} |
- CompositorFrameSinkSupport& child_support2() { return *supports_[3]; } |
- Surface* child_surface2() { |
- return child_support2().current_surface_for_testing(); |
+ // SurfaceObserver implementation. |
+ void OnSurfaceCreated(const SurfaceInfo& surface_info) override { |
+ last_created_surface_id_ = surface_info.id(); |
+ last_surface_info_ = surface_info; |
} |
- |
- CompositorFrameSinkSupport& support(int index) { return *supports_[index]; } |
- Surface* surface(int index) { |
- return support(index).current_surface_for_testing(); |
+ void OnSurfaceDamaged(const SurfaceId& id, bool* changed) override { |
+ *changed = true; |
} |
- SurfaceManager& surface_manager() { return surface_manager_; } |
- |
- // Returns all the references where |surface_id| is the parent. |
- const SurfaceManager::SurfaceIdSet& GetChildReferences( |
- const SurfaceId& surface_id) { |
- return surface_manager().parent_to_child_refs_[surface_id]; |
+ void SubmitCompositorFrameWithResources(ResourceId* resource_ids, |
+ size_t num_resource_ids) { |
+ CompositorFrame frame = MakeCompositorFrame(); |
+ for (size_t i = 0u; i < num_resource_ids; ++i) { |
+ TransferableResource resource; |
+ resource.id = resource_ids[i]; |
+ resource.mailbox_holder.texture_target = GL_TEXTURE_2D; |
+ resource.mailbox_holder.sync_token = frame_sync_token_; |
+ frame.resource_list.push_back(resource); |
+ } |
+ support_->SubmitCompositorFrame(local_surface_id_, std::move(frame)); |
+ EXPECT_EQ(last_created_surface_id_.local_surface_id(), local_surface_id_); |
} |
- // Returns true if there is a temporary reference for |surface_id|. |
- bool HasTemporaryReference(const SurfaceId& surface_id) { |
- return surface_manager().HasTemporaryReference(surface_id); |
+ void UnrefResources(ResourceId* ids_to_unref, |
+ int* counts_to_unref, |
+ size_t num_ids_to_unref) { |
+ ReturnedResourceArray unref_array; |
+ for (size_t i = 0; i < num_ids_to_unref; ++i) { |
+ ReturnedResource resource; |
+ resource.sync_token = consumer_sync_token_; |
+ resource.id = ids_to_unref[i]; |
+ resource.count = counts_to_unref[i]; |
+ unref_array.push_back(resource); |
+ } |
+ support_->UnrefResources(unref_array); |
} |
- SurfaceDependencyTracker& dependency_tracker() { |
- return *surface_manager_.dependency_tracker(); |
+ void CheckReturnedResourcesMatchExpected(ResourceId* expected_returned_ids, |
+ int* expected_returned_counts, |
+ size_t expected_resources, |
+ gpu::SyncToken expected_sync_token) { |
+ const ReturnedResourceArray& actual_resources = |
+ fake_support_client_.returned_resources(); |
+ ASSERT_EQ(expected_resources, actual_resources.size()); |
+ for (size_t i = 0; i < expected_resources; ++i) { |
+ ReturnedResource resource = actual_resources[i]; |
+ EXPECT_EQ(expected_sync_token, resource.sync_token); |
+ EXPECT_EQ(expected_returned_ids[i], resource.id); |
+ EXPECT_EQ(expected_returned_counts[i], resource.count); |
+ } |
+ fake_support_client_.clear_returned_resources(); |
} |
- FakeExternalBeginFrameSource* begin_frame_source() { |
- return begin_frame_source_.get(); |
+ void RefCurrentFrameResources() { |
+ Surface* surface = manager_.GetSurfaceForId( |
+ SurfaceId(support_->frame_sink_id(), local_surface_id_)); |
+ support_->RefResources(surface->GetActiveFrame().resource_list); |
} |
- // testing::Test: |
- void SetUp() override { |
- testing::Test::SetUp(); |
- constexpr bool is_root = true; |
- constexpr bool is_child_root = false; |
- constexpr bool handles_frame_sink_id_invalidation = true; |
- constexpr bool needs_sync_points = true; |
- begin_frame_source_ = |
- base::MakeUnique<FakeExternalBeginFrameSource>(0.f, false); |
- surface_manager_.SetDependencyTracker( |
- base::MakeUnique<SurfaceDependencyTracker>(&surface_manager_, |
- begin_frame_source_.get())); |
- surface_manager_.AddObserver(this); |
- supports_.push_back(CompositorFrameSinkSupport::Create( |
- &support_client_, &surface_manager_, kDisplayFrameSink, is_root, |
- handles_frame_sink_id_invalidation, needs_sync_points)); |
- supports_.push_back(CompositorFrameSinkSupport::Create( |
- &support_client_, &surface_manager_, kParentFrameSink, is_child_root, |
- handles_frame_sink_id_invalidation, needs_sync_points)); |
- supports_.push_back(CompositorFrameSinkSupport::Create( |
- &support_client_, &surface_manager_, kChildFrameSink1, is_child_root, |
- handles_frame_sink_id_invalidation, needs_sync_points)); |
- supports_.push_back(CompositorFrameSinkSupport::Create( |
- &support_client_, &surface_manager_, kChildFrameSink2, is_child_root, |
- handles_frame_sink_id_invalidation, needs_sync_points)); |
- |
- // Normally, the BeginFrameSource would be registered by the Display. We |
- // register it here so that BeginFrames are received by the display support, |
- // for use in the PassesOnBeginFrameAcks test. Other supports do not receive |
- // BeginFrames, since the frame sink hierarchy is not set up in this test. |
- surface_manager_.RegisterBeginFrameSource(begin_frame_source_.get(), |
- kDisplayFrameSink); |
- } |
+ protected: |
+ SurfaceManager manager_; |
+ FakeCompositorFrameSinkSupportClient fake_support_client_; |
+ std::unique_ptr<CompositorFrameSinkSupport> support_; |
+ LocalSurfaceId local_surface_id_; |
+ SurfaceId last_created_surface_id_; |
+ SurfaceInfo last_surface_info_; |
+ |
+ // This is the sync token submitted with the frame. It should never be |
+ // returned to the client. |
+ const gpu::SyncToken frame_sync_token_; |
+ |
+ // This is the sync token returned by the consumer. It should always be |
+ // returned to the client. |
+ const gpu::SyncToken consumer_sync_token_; |
+}; |
- void TearDown() override { |
- surface_manager_.RemoveObserver(this); |
- surface_manager_.SetDependencyTracker(nullptr); |
- surface_manager_.UnregisterBeginFrameSource(begin_frame_source_.get()); |
+// Tests submitting a frame with resources followed by one with no resources |
+// with no resource provider action in between. |
+TEST_F(CompositorFrameSinkSupportTest, ResourceLifetimeSimple) { |
+ ResourceId first_frame_ids[] = {1, 2, 3}; |
+ SubmitCompositorFrameWithResources(first_frame_ids, |
+ arraysize(first_frame_ids)); |
+ |
+ // All of the resources submitted in the first frame are still in use at this |
+ // time by virtue of being in the pending frame, so none can be returned to |
+ // the client yet. |
+ EXPECT_EQ(0u, fake_support_client_.returned_resources().size()); |
+ fake_support_client_.clear_returned_resources(); |
+ |
+ // The second frame references no resources of first frame and thus should |
+ // make all resources of first frame available to be returned. |
+ SubmitCompositorFrameWithResources(NULL, 0); |
+ |
+ ResourceId expected_returned_ids[] = {1, 2, 3}; |
+ int expected_returned_counts[] = {1, 1, 1}; |
+ // Resources were never consumed so no sync token should be set. |
+ CheckReturnedResourcesMatchExpected( |
+ expected_returned_ids, expected_returned_counts, |
+ arraysize(expected_returned_counts), gpu::SyncToken()); |
+ |
+ ResourceId third_frame_ids[] = {4, 5, 6}; |
+ SubmitCompositorFrameWithResources(third_frame_ids, |
+ arraysize(third_frame_ids)); |
+ |
+ // All of the resources submitted in the third frame are still in use at this |
+ // time by virtue of being in the pending frame, so none can be returned to |
+ // the client yet. |
+ EXPECT_EQ(0u, fake_support_client_.returned_resources().size()); |
+ fake_support_client_.clear_returned_resources(); |
+ |
+ // The forth frame references no resources of third frame and thus should |
+ // make all resources of third frame available to be returned. |
+ ResourceId forth_frame_ids[] = {7, 8, 9}; |
+ SubmitCompositorFrameWithResources(forth_frame_ids, |
+ arraysize(forth_frame_ids)); |
+ |
+ ResourceId forth_expected_returned_ids[] = {4, 5, 6}; |
+ int forth_expected_returned_counts[] = {1, 1, 1}; |
+ // Resources were never consumed so no sync token should be set. |
+ CheckReturnedResourcesMatchExpected( |
+ forth_expected_returned_ids, forth_expected_returned_counts, |
+ arraysize(forth_expected_returned_counts), gpu::SyncToken()); |
+} |
- // SurfaceDependencyTracker depends on this BeginFrameSource and so it must |
- // be destroyed AFTER the dependency tracker is destroyed. |
- begin_frame_source_.reset(); |
+// Tests submitting a frame with resources followed by one with no resources |
+// with the resource provider holding everything alive. |
+TEST_F(CompositorFrameSinkSupportTest, |
+ ResourceLifetimeSimpleWithProviderHoldingAlive) { |
+ ResourceId first_frame_ids[] = {1, 2, 3}; |
+ SubmitCompositorFrameWithResources(first_frame_ids, |
+ arraysize(first_frame_ids)); |
+ |
+ // All of the resources submitted in the first frame are still in use at this |
+ // time by virtue of being in the pending frame, so none can be returned to |
+ // the client yet. |
+ EXPECT_EQ(0u, fake_support_client_.returned_resources().size()); |
+ fake_support_client_.clear_returned_resources(); |
+ |
+ // Hold on to everything. |
+ RefCurrentFrameResources(); |
+ |
+ // The second frame references no resources and thus should make all resources |
+ // available to be returned as soon as the resource provider releases them. |
+ SubmitCompositorFrameWithResources(NULL, 0); |
+ |
+ EXPECT_EQ(0u, fake_support_client_.returned_resources().size()); |
+ fake_support_client_.clear_returned_resources(); |
+ |
+ int release_counts[] = {1, 1, 1}; |
+ UnrefResources(first_frame_ids, release_counts, arraysize(first_frame_ids)); |
+ |
+ // None is returned to the client since DidReceiveCompositorAck is not |
+ // invoked. |
+ EXPECT_EQ(0u, fake_support_client_.returned_resources().size()); |
+ |
+ // Submitting an empty frame causes previous resources referenced by the |
+ // previous frame to be returned to client. |
+ SubmitCompositorFrameWithResources(nullptr, 0); |
+ ResourceId expected_returned_ids[] = {1, 2, 3}; |
+ int expected_returned_counts[] = {1, 1, 1}; |
+ CheckReturnedResourcesMatchExpected( |
+ expected_returned_ids, expected_returned_counts, |
+ arraysize(expected_returned_counts), consumer_sync_token_); |
+} |
- supports_.clear(); |
+// Tests referencing a resource, unref'ing it to zero, then using it again |
+// before returning it to the client. |
+TEST_F(CompositorFrameSinkSupportTest, ResourceReusedBeforeReturn) { |
+ ResourceId first_frame_ids[] = {7}; |
+ SubmitCompositorFrameWithResources(first_frame_ids, |
+ arraysize(first_frame_ids)); |
+ |
+ // This removes all references to resource id 7. |
+ SubmitCompositorFrameWithResources(NULL, 0); |
+ |
+ // This references id 7 again. |
+ SubmitCompositorFrameWithResources(first_frame_ids, |
+ arraysize(first_frame_ids)); |
+ |
+ // This removes it again. |
+ SubmitCompositorFrameWithResources(NULL, 0); |
+ |
+ // Now it should be returned. |
+ // We don't care how many entries are in the returned array for 7, so long as |
+ // the total returned count matches the submitted count. |
+ const ReturnedResourceArray& returned = |
+ fake_support_client_.returned_resources(); |
+ size_t return_count = 0; |
+ for (size_t i = 0; i < returned.size(); ++i) { |
+ EXPECT_EQ(7u, returned[i].id); |
+ return_count += returned[i].count; |
+ } |
+ EXPECT_EQ(2u, return_count); |
+} |
- damaged_surfaces_.clear(); |
+// Tests having resources referenced multiple times, as if referenced by |
+// multiple providers. |
+TEST_F(CompositorFrameSinkSupportTest, ResourceRefMultipleTimes) { |
+ ResourceId first_frame_ids[] = {3, 4}; |
+ SubmitCompositorFrameWithResources(first_frame_ids, |
+ arraysize(first_frame_ids)); |
+ |
+ // Ref resources from the first frame twice. |
+ RefCurrentFrameResources(); |
+ RefCurrentFrameResources(); |
+ |
+ ResourceId second_frame_ids[] = {4, 5}; |
+ SubmitCompositorFrameWithResources(second_frame_ids, |
+ arraysize(second_frame_ids)); |
+ |
+ // Ref resources from the second frame 3 times. |
+ RefCurrentFrameResources(); |
+ RefCurrentFrameResources(); |
+ RefCurrentFrameResources(); |
+ |
+ // Submit a frame with no resources to remove all current frame refs from |
+ // submitted resources. |
+ SubmitCompositorFrameWithResources(NULL, 0); |
+ |
+ EXPECT_EQ(0u, fake_support_client_.returned_resources().size()); |
+ fake_support_client_.clear_returned_resources(); |
+ |
+ // Expected current refs: |
+ // 3 -> 2 |
+ // 4 -> 2 + 3 = 5 |
+ // 5 -> 3 |
+ { |
+ SCOPED_TRACE("unref all 3"); |
+ ResourceId ids_to_unref[] = {3, 4, 5}; |
+ int counts[] = {1, 1, 1}; |
+ UnrefResources(ids_to_unref, counts, arraysize(ids_to_unref)); |
+ |
+ EXPECT_EQ(0u, fake_support_client_.returned_resources().size()); |
+ fake_support_client_.clear_returned_resources(); |
+ |
+ UnrefResources(ids_to_unref, counts, arraysize(ids_to_unref)); |
+ SubmitCompositorFrameWithResources(nullptr, 0); |
+ ResourceId expected_returned_ids[] = {3}; |
+ int expected_returned_counts[] = {1}; |
+ CheckReturnedResourcesMatchExpected( |
+ expected_returned_ids, expected_returned_counts, |
+ arraysize(expected_returned_counts), consumer_sync_token_); |
} |
- bool IsSurfaceDamaged(const SurfaceId& surface_id) const { |
- return damaged_surfaces_.count(surface_id) > 0; |
+ // Expected refs remaining: |
+ // 4 -> 3 |
+ // 5 -> 1 |
+ { |
+ SCOPED_TRACE("unref 4 and 5"); |
+ ResourceId ids_to_unref[] = {4, 5}; |
+ int counts[] = {1, 1}; |
+ UnrefResources(ids_to_unref, counts, arraysize(ids_to_unref)); |
+ SubmitCompositorFrameWithResources(nullptr, 0); |
+ |
+ ResourceId expected_returned_ids[] = {5}; |
+ int expected_returned_counts[] = {1}; |
+ CheckReturnedResourcesMatchExpected( |
+ expected_returned_ids, expected_returned_counts, |
+ arraysize(expected_returned_counts), consumer_sync_token_); |
} |
- // SurfaceObserver implementation: |
- void OnSurfaceCreated(const SurfaceInfo& surface_info) override {} |
- void OnSurfaceDamaged(const SurfaceId& surface_id, bool* changed) override { |
- damaged_surfaces_.insert(surface_id); |
+ // Now, just 2 refs remaining on resource 4. Unref both at once and make sure |
+ // the returned count is correct. |
+ { |
+ SCOPED_TRACE("unref only 4"); |
+ ResourceId ids_to_unref[] = {4}; |
+ int counts[] = {2}; |
+ UnrefResources(ids_to_unref, counts, arraysize(ids_to_unref)); |
+ SubmitCompositorFrameWithResources(nullptr, 0); |
+ |
+ ResourceId expected_returned_ids[] = {4}; |
+ int expected_returned_counts[] = {2}; |
+ CheckReturnedResourcesMatchExpected( |
+ expected_returned_ids, expected_returned_counts, |
+ arraysize(expected_returned_counts), consumer_sync_token_); |
} |
+} |
- protected: |
- testing::NiceMock<MockCompositorFrameSinkSupportClient> support_client_; |
+TEST_F(CompositorFrameSinkSupportTest, ResourceLifetime) { |
+ ResourceId first_frame_ids[] = {1, 2, 3}; |
+ SubmitCompositorFrameWithResources(first_frame_ids, |
+ arraysize(first_frame_ids)); |
+ |
+ // All of the resources submitted in the first frame are still in use at this |
+ // time by virtue of being in the pending frame, so none can be returned to |
+ // the client yet. |
+ EXPECT_EQ(0u, fake_support_client_.returned_resources().size()); |
+ fake_support_client_.clear_returned_resources(); |
+ |
+ // The second frame references some of the same resources, but some different |
+ // ones. We expect to receive back resource 1 with a count of 1 since it was |
+ // only referenced by the first frame. |
+ ResourceId second_frame_ids[] = {2, 3, 4}; |
+ SubmitCompositorFrameWithResources(second_frame_ids, |
+ arraysize(second_frame_ids)); |
+ { |
+ SCOPED_TRACE("second frame"); |
+ ResourceId expected_returned_ids[] = {1}; |
+ int expected_returned_counts[] = {1}; |
+ CheckReturnedResourcesMatchExpected( |
+ expected_returned_ids, expected_returned_counts, |
+ arraysize(expected_returned_counts), gpu::SyncToken()); |
+ } |
- private: |
- base::flat_set<SurfaceId> damaged_surfaces_; |
- SurfaceManager surface_manager_; |
- std::unique_ptr<FakeExternalBeginFrameSource> begin_frame_source_; |
- std::vector<std::unique_ptr<CompositorFrameSinkSupport>> supports_; |
+ // The third frame references a disjoint set of resources, so we expect to |
+ // receive back all resources from the first and second frames. Resource IDs 2 |
+ // and 3 will have counts of 2, since they were used in both frames, and |
+ // resource ID 4 will have a count of 1. |
+ ResourceId third_frame_ids[] = {10, 11, 12, 13}; |
+ SubmitCompositorFrameWithResources(third_frame_ids, |
+ arraysize(third_frame_ids)); |
+ |
+ { |
+ SCOPED_TRACE("third frame"); |
+ ResourceId expected_returned_ids[] = {2, 3, 4}; |
+ int expected_returned_counts[] = {2, 2, 1}; |
+ CheckReturnedResourcesMatchExpected( |
+ expected_returned_ids, expected_returned_counts, |
+ arraysize(expected_returned_counts), gpu::SyncToken()); |
+ } |
- DISALLOW_COPY_AND_ASSIGN(CompositorFrameSinkSupportTest); |
-}; |
+ // Simulate a ResourceProvider taking a ref on all of the resources. |
+ RefCurrentFrameResources(); |
-// 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(CompositorFrameSinkSupportTest, RootSurfaceReceivesReferences) { |
- const SurfaceId display_id_first = MakeSurfaceId(kDisplayFrameSink, 1); |
- const SurfaceId display_id_second = MakeSurfaceId(kDisplayFrameSink, 2); |
- |
- // Submit a CompositorFrame for the first display root surface. |
- display_support().SubmitCompositorFrame(display_id_first.local_surface_id(), |
- MakeCompositorFrame()); |
- |
- // A surface reference from the top-level root is added and there shouldn't be |
- // a temporary reference. |
- EXPECT_FALSE(HasTemporaryReference(display_id_first)); |
- EXPECT_THAT(GetChildReferences(surface_manager().GetRootSurfaceId()), |
- UnorderedElementsAre(display_id_first)); |
- |
- // Submit a CompositorFrame for the second display root surface. |
- display_support().SubmitCompositorFrame(display_id_second.local_surface_id(), |
- MakeCompositorFrame()); |
- |
- // A surface reference from the top-level root to |display_id_second| should |
- // be added and the reference to |display_root_first| removed. |
- EXPECT_FALSE(HasTemporaryReference(display_id_second)); |
- EXPECT_THAT(GetChildReferences(surface_manager().GetRootSurfaceId()), |
- UnorderedElementsAre(display_id_second)); |
- |
- // Surface |display_id_first| is unreachable and should get deleted. |
- EXPECT_EQ(nullptr, surface_manager().GetSurfaceForId(display_id_first)); |
-} |
+ ResourceId fourth_frame_ids[] = {12, 13}; |
+ SubmitCompositorFrameWithResources(fourth_frame_ids, |
+ arraysize(fourth_frame_ids)); |
-// The parent Surface is blocked on |child_id1| and |child_id2|. |
-TEST_F(CompositorFrameSinkSupportTest, DisplayCompositorLockingBlockedOnTwo) { |
- const SurfaceId parent_id = MakeSurfaceId(kParentFrameSink, 1); |
- const SurfaceId child_id1 = MakeSurfaceId(kChildFrameSink1, 1); |
- const SurfaceId child_id2 = MakeSurfaceId(kChildFrameSink2, 1); |
- |
- parent_support().SubmitCompositorFrame( |
- parent_id.local_surface_id(), |
- MakeCompositorFrame({child_id1, child_id2}, empty_surface_ids())); |
- |
- // parent_support is blocked on |child_id1| and |child_id2|. |
- EXPECT_TRUE(dependency_tracker().has_deadline()); |
- EXPECT_FALSE(parent_surface()->HasActiveFrame()); |
- EXPECT_TRUE(parent_surface()->HasPendingFrame()); |
- EXPECT_THAT(parent_surface()->blocking_surfaces(), |
- UnorderedElementsAre(child_id1, child_id2)); |
- |
- // Submit a CompositorFrame without any dependencies to |child_id1|. |
- // parent_support should now only be blocked on |child_id2|. |
- child_support1().SubmitCompositorFrame(child_id1.local_surface_id(), |
- MakeCompositorFrame()); |
- |
- EXPECT_TRUE(dependency_tracker().has_deadline()); |
- EXPECT_FALSE(parent_surface()->HasActiveFrame()); |
- EXPECT_TRUE(parent_surface()->HasPendingFrame()); |
- EXPECT_THAT(parent_surface()->blocking_surfaces(), |
- UnorderedElementsAre(child_id2)); |
- |
- // Submit a CompositorFrame without any dependencies to |child_id2|. |
- // parent_support should be activated. |
- child_support2().SubmitCompositorFrame(child_id2.local_surface_id(), |
- MakeCompositorFrame()); |
- |
- EXPECT_FALSE(dependency_tracker().has_deadline()); |
- EXPECT_TRUE(parent_surface()->HasActiveFrame()); |
- EXPECT_FALSE(parent_surface()->HasPendingFrame()); |
- EXPECT_THAT(parent_surface()->blocking_surfaces(), IsEmpty()); |
-} |
+ EXPECT_EQ(0u, fake_support_client_.returned_resources().size()); |
-// The parent Surface is blocked on |child_id2| which is blocked on |child_id3|. |
-TEST_F(CompositorFrameSinkSupportTest, DisplayCompositorLockingBlockedChain) { |
- const SurfaceId parent_id = MakeSurfaceId(kParentFrameSink, 1); |
- const SurfaceId child_id1 = MakeSurfaceId(kChildFrameSink1, 1); |
- const SurfaceId child_id2 = MakeSurfaceId(kChildFrameSink2, 1); |
- |
- parent_support().SubmitCompositorFrame( |
- parent_id.local_surface_id(), |
- MakeCompositorFrame({child_id1}, empty_surface_ids())); |
- |
- // parent_support is blocked on |child_id1|. |
- EXPECT_TRUE(dependency_tracker().has_deadline()); |
- EXPECT_FALSE(parent_surface()->HasActiveFrame()); |
- EXPECT_TRUE(parent_surface()->HasPendingFrame()); |
- EXPECT_THAT(parent_surface()->blocking_surfaces(), |
- UnorderedElementsAre(child_id1)); |
- // The parent should not report damage until it activates. |
- EXPECT_FALSE(IsSurfaceDamaged(parent_id)); |
- |
- child_support1().SubmitCompositorFrame( |
- child_id1.local_surface_id(), |
- MakeCompositorFrame({child_id2}, empty_surface_ids())); |
- |
- // child_support1 should now be blocked on |child_id2|. |
- EXPECT_TRUE(dependency_tracker().has_deadline()); |
- EXPECT_FALSE(child_surface1()->HasActiveFrame()); |
- EXPECT_TRUE(child_surface1()->HasPendingFrame()); |
- EXPECT_THAT(child_surface1()->blocking_surfaces(), |
- UnorderedElementsAre(child_id2)); |
- // The parent and child should not report damage until they activate. |
- EXPECT_FALSE(IsSurfaceDamaged(parent_id)); |
- EXPECT_FALSE(IsSurfaceDamaged(child_id1)); |
- |
- // The parent should still be blocked on |child_id1| because it's pending. |
- EXPECT_THAT(parent_surface()->blocking_surfaces(), |
- UnorderedElementsAre(child_id1)); |
- |
- // Submit a CompositorFrame without any dependencies to |child_id2|. |
- // parent_support should be activated. |
- child_support2().SubmitCompositorFrame( |
- child_id2.local_surface_id(), MakeCompositorFrame(empty_surface_ids())); |
- |
- EXPECT_FALSE(dependency_tracker().has_deadline()); |
- |
- // child_surface1 should now be active. |
- EXPECT_TRUE(child_surface1()->HasActiveFrame()); |
- EXPECT_FALSE(child_surface1()->HasPendingFrame()); |
- EXPECT_THAT(child_surface1()->blocking_surfaces(), IsEmpty()); |
- |
- // parent_surface should now be active. |
- EXPECT_TRUE(parent_surface()->HasActiveFrame()); |
- EXPECT_FALSE(parent_surface()->HasPendingFrame()); |
- EXPECT_THAT(parent_surface()->blocking_surfaces(), IsEmpty()); |
- |
- // All three surfaces |parent_id|, |child_id1|, and |child_id2| should |
- // now report damage. This would trigger a new display frame. |
- EXPECT_TRUE(IsSurfaceDamaged(parent_id)); |
- EXPECT_TRUE(IsSurfaceDamaged(child_id1)); |
- EXPECT_TRUE(IsSurfaceDamaged(child_id2)); |
-} |
+ RefCurrentFrameResources(); |
-// parent_surface and child_surface1 are blocked on |child_id2|. |
-TEST_F(CompositorFrameSinkSupportTest, |
- DisplayCompositorLockingTwoBlockedOnOne) { |
- const SurfaceId parent_id = MakeSurfaceId(kParentFrameSink, 1); |
- const SurfaceId child_id1 = MakeSurfaceId(kChildFrameSink1, 1); |
- const SurfaceId child_id2 = MakeSurfaceId(kChildFrameSink2, 1); |
- |
- parent_support().SubmitCompositorFrame( |
- parent_id.local_surface_id(), |
- MakeCompositorFrame({child_id2}, empty_surface_ids())); |
- |
- // parent_support is blocked on |child_id2|. |
- EXPECT_TRUE(dependency_tracker().has_deadline()); |
- EXPECT_FALSE(parent_surface()->HasActiveFrame()); |
- EXPECT_TRUE(parent_surface()->HasPendingFrame()); |
- EXPECT_THAT(parent_surface()->blocking_surfaces(), |
- UnorderedElementsAre(child_id2)); |
- |
- // child_support1 should now be blocked on |child_id2|. |
- child_support1().SubmitCompositorFrame( |
- child_id1.local_surface_id(), |
- MakeCompositorFrame({child_id2}, empty_surface_ids())); |
- |
- EXPECT_TRUE(dependency_tracker().has_deadline()); |
- EXPECT_FALSE(child_surface1()->HasActiveFrame()); |
- EXPECT_TRUE(child_surface1()->HasPendingFrame()); |
- EXPECT_THAT(child_surface1()->blocking_surfaces(), |
- UnorderedElementsAre(child_id2)); |
- |
- // The parent should still be blocked on |child_id2|. |
- EXPECT_THAT(parent_surface()->blocking_surfaces(), |
- UnorderedElementsAre(child_id2)); |
- |
- // Submit a CompositorFrame without any dependencies to |child_id2|. |
- // parent_support should be activated. |
- child_support2().SubmitCompositorFrame(child_id2.local_surface_id(), |
- MakeCompositorFrame()); |
- |
- EXPECT_FALSE(dependency_tracker().has_deadline()); |
- |
- // child_surface1 should now be active. |
- EXPECT_TRUE(child_surface1()->HasActiveFrame()); |
- EXPECT_FALSE(child_surface1()->HasPendingFrame()); |
- EXPECT_THAT(child_surface1()->blocking_surfaces(), IsEmpty()); |
- |
- // parent_surface should now be active. |
- EXPECT_TRUE(parent_surface()->HasActiveFrame()); |
- EXPECT_FALSE(parent_surface()->HasPendingFrame()); |
- EXPECT_THAT(parent_surface()->blocking_surfaces(), IsEmpty()); |
-} |
+ // All resources are still being used by the external reference, so none can |
+ // be returned to the client. |
+ EXPECT_EQ(0u, fake_support_client_.returned_resources().size()); |
-// parent_surface is blocked on |child_id1|, and child_surface2 is blocked on |
-// |child_id2| until the deadline hits. |
-TEST_F(CompositorFrameSinkSupportTest, DisplayCompositorLockingDeadlineHits) { |
- const SurfaceId parent_id = MakeSurfaceId(kParentFrameSink, 1); |
- const SurfaceId child_id1 = MakeSurfaceId(kChildFrameSink1, 1); |
- const SurfaceId child_id2 = MakeSurfaceId(kChildFrameSink2, 1); |
- |
- parent_support().SubmitCompositorFrame( |
- parent_id.local_surface_id(), |
- MakeCompositorFrame({child_id1}, empty_surface_ids())); |
- |
- // parent_support is blocked on |child_id1|. |
- EXPECT_TRUE(dependency_tracker().has_deadline()); |
- EXPECT_FALSE(parent_surface()->HasActiveFrame()); |
- EXPECT_TRUE(parent_surface()->HasPendingFrame()); |
- EXPECT_THAT(parent_surface()->blocking_surfaces(), |
- UnorderedElementsAre(child_id1)); |
- |
- child_support1().SubmitCompositorFrame( |
- child_id1.local_surface_id(), |
- MakeCompositorFrame({child_id2}, empty_surface_ids())); |
- |
- // child_support1 should now be blocked on |child_id2|. |
- EXPECT_TRUE(dependency_tracker().has_deadline()); |
- EXPECT_FALSE(child_surface1()->HasActiveFrame()); |
- EXPECT_TRUE(child_surface1()->HasPendingFrame()); |
- EXPECT_THAT(child_surface1()->blocking_surfaces(), |
- UnorderedElementsAre(child_id2)); |
- |
- // The parent should still be blocked on |child_id1| because it's pending. |
- EXPECT_THAT(parent_surface()->blocking_surfaces(), |
- UnorderedElementsAre(child_id1)); |
- |
- BeginFrameArgs args = |
- CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 0, 1); |
- |
- for (int i = 0; i < 3; ++i) { |
- begin_frame_source()->TestOnBeginFrame(args); |
- // There is still a looming deadline! Eeek! |
- EXPECT_TRUE(dependency_tracker().has_deadline()); |
- |
- // parent_support is still blocked on |child_id1|. |
- EXPECT_FALSE(parent_surface()->HasActiveFrame()); |
- EXPECT_TRUE(parent_surface()->HasPendingFrame()); |
- EXPECT_THAT(parent_surface()->blocking_surfaces(), |
- UnorderedElementsAre(child_id1)); |
- |
- // child_support1 is still blocked on |child_id2|. |
- EXPECT_FALSE(child_surface1()->HasActiveFrame()); |
- EXPECT_TRUE(child_surface1()->HasPendingFrame()); |
- EXPECT_THAT(child_surface1()->blocking_surfaces(), |
- UnorderedElementsAre(child_id2)); |
+ // Release resources associated with the first RefCurrentFrameResources() call |
+ // first. |
+ { |
+ ResourceId ids_to_unref[] = {10, 11, 12, 13}; |
+ int counts[] = {1, 1, 1, 1}; |
+ UnrefResources(ids_to_unref, counts, arraysize(ids_to_unref)); |
} |
- begin_frame_source()->TestOnBeginFrame(args); |
- |
- // The deadline has passed. |
- EXPECT_FALSE(dependency_tracker().has_deadline()); |
- |
- // parent_surface has been activated. |
- EXPECT_TRUE(parent_surface()->HasActiveFrame()); |
- EXPECT_FALSE(parent_surface()->HasPendingFrame()); |
- EXPECT_THAT(parent_surface()->blocking_surfaces(), IsEmpty()); |
- |
- // child_surface1 has been activated. |
- EXPECT_TRUE(child_surface1()->HasActiveFrame()); |
- EXPECT_FALSE(child_surface1()->HasPendingFrame()); |
- EXPECT_THAT(child_surface1()->blocking_surfaces(), IsEmpty()); |
-} |
+ // Nothing is returned to the client yet since DidReceiveCompositorFrameAck |
+ // is not invoked. |
+ { |
+ SCOPED_TRACE("fourth frame, first unref"); |
+ CheckReturnedResourcesMatchExpected(nullptr, nullptr, 0, |
+ consumer_sync_token_); |
+ } |
-// Verifies that the deadline does not reset if we submit CompositorFrames |
-// to new Surfaces with unresolved dependencies. |
-TEST_F(CompositorFrameSinkSupportTest, |
- DisplayCompositorLockingFramesSubmittedAfterDeadlineSet) { |
- const SurfaceId arbitrary_id = MakeSurfaceId(kArbitraryFrameSink, 1); |
- BeginFrameArgs args = |
- CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 0, 1); |
- for (int i = 0; i < 3; ++i) { |
- LocalSurfaceId local_surface_id(1, base::UnguessableToken::Create()); |
- support(i).SubmitCompositorFrame( |
- local_surface_id, |
- MakeCompositorFrame({arbitrary_id}, empty_surface_ids())); |
- // The deadline has been set. |
- EXPECT_TRUE(dependency_tracker().has_deadline()); |
- |
- // support(i) should be blocked on arbitrary_id. |
- EXPECT_FALSE(surface(i)->HasActiveFrame()); |
- EXPECT_TRUE(surface(i)->HasPendingFrame()); |
- EXPECT_THAT(surface(i)->blocking_surfaces(), |
- UnorderedElementsAre(arbitrary_id)); |
- |
- // Issue a BeginFrame to get closer to the deadline. |
- begin_frame_source()->TestOnBeginFrame(args); |
+ { |
+ ResourceId ids_to_unref[] = {12, 13}; |
+ int counts[] = {1, 1}; |
+ UnrefResources(ids_to_unref, counts, arraysize(ids_to_unref)); |
} |
- // The deadline hits and all the Surfaces should activate. |
- begin_frame_source()->TestOnBeginFrame(args); |
- for (int i = 0; i < 3; ++i) { |
- EXPECT_TRUE(surface(i)->HasActiveFrame()); |
- EXPECT_FALSE(surface(i)->HasPendingFrame()); |
- EXPECT_THAT(surface(i)->blocking_surfaces(), IsEmpty()); |
+ // Resources 12 and 13 are still in use by the current frame, so they |
+ // shouldn't be available to be returned. |
+ EXPECT_EQ(0u, fake_support_client_.returned_resources().size()); |
+ |
+ // If we submit an empty frame, however, they should become available. |
+ // Resources that were previously unref'd also return at this point. |
+ SubmitCompositorFrameWithResources(NULL, 0u); |
+ |
+ { |
+ SCOPED_TRACE("fourth frame, second unref"); |
+ ResourceId expected_returned_ids[] = {10, 11, 12, 13}; |
+ int expected_returned_counts[] = {1, 1, 2, 2}; |
+ CheckReturnedResourcesMatchExpected( |
+ expected_returned_ids, expected_returned_counts, |
+ arraysize(expected_returned_counts), consumer_sync_token_); |
} |
} |
-// This test verifies at the Surface activates once a CompositorFrame is |
-// submitted that has no unresolved dependencies. |
-TEST_F(CompositorFrameSinkSupportTest, |
- DisplayCompositorLockingNewFrameOverridesOldDependencies) { |
- const SurfaceId parent_id = MakeSurfaceId(kParentFrameSink, 1); |
- const SurfaceId arbitrary_id = MakeSurfaceId(kArbitraryFrameSink, 1); |
- |
- // Submit a CompositorFrame that depends on |arbitrary_id|. |
- parent_support().SubmitCompositorFrame( |
- parent_id.local_surface_id(), |
- MakeCompositorFrame({arbitrary_id}, empty_surface_ids())); |
- |
- // Verify that the CompositorFrame is blocked on |arbitrary_id|. |
- EXPECT_FALSE(parent_surface()->HasActiveFrame()); |
- EXPECT_TRUE(parent_surface()->HasPendingFrame()); |
- EXPECT_THAT(parent_surface()->blocking_surfaces(), |
- UnorderedElementsAre(arbitrary_id)); |
- |
- // Submit a CompositorFrame that has no dependencies. |
- parent_support().SubmitCompositorFrame(parent_id.local_surface_id(), |
- MakeCompositorFrame()); |
- |
- // Verify that the CompositorFrame has been activated. |
- EXPECT_TRUE(parent_surface()->HasActiveFrame()); |
- EXPECT_FALSE(parent_surface()->HasPendingFrame()); |
- EXPECT_THAT(parent_surface()->blocking_surfaces(), IsEmpty()); |
+TEST_F(CompositorFrameSinkSupportTest, AddDuringEviction) { |
+ MockCompositorFrameSinkSupportClient mock_client; |
+ std::unique_ptr<CompositorFrameSinkSupport> support = |
+ CompositorFrameSinkSupport::Create( |
+ &mock_client, &manager_, kAnotherArbitraryFrameSinkId, kIsRoot, |
+ kHandlesFrameSinkIdInvalidation, kNeedsSyncPoints); |
+ LocalSurfaceId local_surface_id(6, kArbitraryToken); |
+ support->SubmitCompositorFrame(local_surface_id, MakeCompositorFrame()); |
+ |
+ EXPECT_CALL(mock_client, DidReceiveCompositorFrameAck(_)) |
+ .WillOnce(testing::InvokeWithoutArgs([&support, &mock_client]() { |
+ LocalSurfaceId new_id(7, base::UnguessableToken::Create()); |
+ support->SubmitCompositorFrame(new_id, MakeCompositorFrame()); |
+ })) |
+ .WillRepeatedly(testing::Return()); |
+ support->EvictFrame(); |
} |
-// 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_F(CompositorFrameSinkSupportTest, |
- OnlyActiveFramesAffectSurfaceReferences) { |
- const SurfaceId parent_id = MakeSurfaceId(kParentFrameSink, 1); |
- const SurfaceId child_id1 = MakeSurfaceId(kChildFrameSink1, 1); |
- const SurfaceId child_id2 = MakeSurfaceId(kChildFrameSink2, 1); |
- |
- // child_support1 submits a CompositorFrame without any dependencies. |
- // DidReceiveCompositorFrameAck should call on immediate activation. |
- EXPECT_CALL(support_client_, DidReceiveCompositorFrameAck(_)).Times(1); |
- child_support1().SubmitCompositorFrame(child_id1.local_surface_id(), |
- MakeCompositorFrame()); |
- testing::Mock::VerifyAndClearExpectations(&support_client_); |
- |
- // Verify that the child surface is not blocked. |
- EXPECT_TRUE(child_surface1()->HasActiveFrame()); |
- EXPECT_FALSE(child_surface1()->HasPendingFrame()); |
- EXPECT_THAT(child_surface1()->blocking_surfaces(), IsEmpty()); |
- |
- // Verify that there's a temporary reference for |child_id1|. |
- EXPECT_TRUE(HasTemporaryReference(child_id1)); |
- |
- // parent_support submits a CompositorFrame that depends on |child_id1| |
- // (which is already active) and |child_id2|. Thus, the parent should not |
- // activate immediately. DidReceiveCompositorFrameAck should not be called |
- // immediately because the parent CompositorFrame is also blocked on |
- // |child_id2|. |
- EXPECT_CALL(support_client_, DidReceiveCompositorFrameAck(_)).Times(0); |
- parent_support().SubmitCompositorFrame( |
- parent_id.local_surface_id(), |
- MakeCompositorFrame({child_id2}, {child_id1})); |
- EXPECT_FALSE(parent_surface()->HasActiveFrame()); |
- EXPECT_TRUE(parent_surface()->HasPendingFrame()); |
- EXPECT_THAT(parent_surface()->blocking_surfaces(), |
- UnorderedElementsAre(child_id2)); |
- EXPECT_THAT(GetChildReferences(parent_id), IsEmpty()); |
- testing::Mock::VerifyAndClearExpectations(&support_client_); |
- |
- // Verify that there's a temporary reference for |child_id1| that still |
- // exists. |
- EXPECT_TRUE(HasTemporaryReference(child_id1)); |
- |
- // child_support2 submits a CompositorFrame without any dependencies. |
- // Both the child and the parent should immediately ACK CompositorFrames |
- // on activation. |
- EXPECT_CALL(support_client_, DidReceiveCompositorFrameAck(_)).Times(2); |
- child_support2().SubmitCompositorFrame(child_id2.local_surface_id(), |
- MakeCompositorFrame()); |
- testing::Mock::VerifyAndClearExpectations(&support_client_); |
- |
- // Verify that the child surface is not blocked. |
- EXPECT_TRUE(child_surface1()->HasActiveFrame()); |
- EXPECT_FALSE(child_surface1()->HasPendingFrame()); |
- EXPECT_THAT(child_surface1()->blocking_surfaces(), IsEmpty()); |
- |
- // Verify that the parent surface's CompositorFrame has activated and that the |
- // temporary reference has been replaced by a permanent one. |
- EXPECT_TRUE(parent_surface()->HasActiveFrame()); |
- EXPECT_FALSE(parent_surface()->HasPendingFrame()); |
- EXPECT_THAT(parent_surface()->blocking_surfaces(), IsEmpty()); |
- EXPECT_FALSE(HasTemporaryReference(child_id1)); |
- EXPECT_THAT(GetChildReferences(parent_id), UnorderedElementsAre(child_id1)); |
-} |
+// Tests doing an EvictFrame before shutting down the factory. |
+TEST_F(CompositorFrameSinkSupportTest, EvictFrame) { |
+ MockCompositorFrameSinkSupportClient mock_client; |
+ std::unique_ptr<CompositorFrameSinkSupport> support = |
+ CompositorFrameSinkSupport::Create( |
+ &mock_client, &manager_, kAnotherArbitraryFrameSinkId, kIsRoot, |
+ kHandlesFrameSinkIdInvalidation, kNeedsSyncPoints); |
+ LocalSurfaceId local_surface_id(7, kArbitraryToken); |
+ SurfaceId id(kAnotherArbitraryFrameSinkId, local_surface_id); |
-// 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_F(CompositorFrameSinkSupportTest, |
- DisplayCompositorLockingResourcesOnlyReturnedOnce) { |
- const SurfaceId parent_id = MakeSurfaceId(kParentFrameSink, 1); |
- const SurfaceId child_id = MakeSurfaceId(kChildFrameSink1, 1); |
- |
- // The parent submits a CompositorFrame that depends on |child_id| before the |
- // child submits a CompositorFrame. The CompositorFrame also has resources in |
- // its resource list. |
- TransferableResource resource = |
- MakeResource(1337 /* id */, ALPHA_8 /* format */, 1234 /* filter */, |
- gfx::Size(1234, 5678)); |
- TransferableResourceArray resource_list = {resource}; |
- parent_support().SubmitCompositorFrame( |
- parent_id.local_surface_id(), |
- MakeCompositorFrameWithResources({child_id}, resource_list)); |
- |
- // Verify that the CompositorFrame is blocked on |child_id|. |
- EXPECT_FALSE(parent_surface()->HasActiveFrame()); |
- EXPECT_TRUE(parent_surface()->HasPendingFrame()); |
- EXPECT_THAT(parent_surface()->blocking_surfaces(), |
- UnorderedElementsAre(child_id)); |
- |
- child_support1().SubmitCompositorFrame( |
- child_id.local_surface_id(), MakeCompositorFrame(empty_surface_ids())); |
- |
- // Verify that the child CompositorFrame activates immediately. |
- EXPECT_TRUE(child_surface1()->HasActiveFrame()); |
- EXPECT_FALSE(child_surface1()->HasPendingFrame()); |
- EXPECT_THAT(child_surface1()->blocking_surfaces(), IsEmpty()); |
- |
- // Verify that the parent has activated. |
- EXPECT_TRUE(parent_surface()->HasActiveFrame()); |
- EXPECT_FALSE(parent_surface()->HasPendingFrame()); |
- EXPECT_THAT(parent_surface()->blocking_surfaces(), IsEmpty()); |
- |
- // The parent submits a CompositorFrame without any dependencies. That frame |
- // should activate immediately, replacing the earlier frame. The resource from |
- // the earlier frame should be returned to the client. |
- parent_support().SubmitCompositorFrame( |
- parent_id.local_surface_id(), MakeCompositorFrame({empty_surface_ids()})); |
- EXPECT_TRUE(parent_surface()->HasActiveFrame()); |
- EXPECT_FALSE(parent_surface()->HasPendingFrame()); |
- EXPECT_THAT(parent_surface()->blocking_surfaces(), IsEmpty()); |
- ReturnedResource returned_resource = resource.ToReturnedResource(); |
- EXPECT_THAT(support_client_.last_returned_resources(), |
- UnorderedElementsAre(returned_resource)); |
+ TransferableResource resource; |
+ resource.id = 1; |
+ resource.mailbox_holder.texture_target = GL_TEXTURE_2D; |
+ CompositorFrame frame = MakeCompositorFrame(); |
+ frame.resource_list.push_back(resource); |
+ support->SubmitCompositorFrame(local_surface_id, std::move(frame)); |
+ EXPECT_EQ(last_created_surface_id().local_surface_id(), local_surface_id); |
+ local_surface_id_ = LocalSurfaceId(); |
+ |
+ ReturnedResourceArray returned_resources = {resource.ToReturnedResource()}; |
+ EXPECT_TRUE(manager_.GetSurfaceForId(id)); |
+ EXPECT_CALL(mock_client, DidReceiveCompositorFrameAck(returned_resources)) |
+ .Times(1); |
+ support->EvictFrame(); |
+ EXPECT_FALSE(manager_.GetSurfaceForId(id)); |
} |
-// The parent Surface is blocked on |child_id2| which is blocked on |child_id3|. |
-// child_support1 evicts its blocked Surface. The parent surface should |
-// activate. |
-TEST_F(CompositorFrameSinkSupportTest, EvictSurfaceWithPendingFrame) { |
- const SurfaceId parent_id1 = MakeSurfaceId(kParentFrameSink, 1); |
- const SurfaceId child_id1 = MakeSurfaceId(kChildFrameSink1, 1); |
- const SurfaceId child_id2 = MakeSurfaceId(kChildFrameSink2, 1); |
- |
- // Submit a CompositorFrame that depends on |child_id1|. |
- parent_support().SubmitCompositorFrame( |
- parent_id1.local_surface_id(), |
- MakeCompositorFrame({child_id1}, empty_surface_ids())); |
- |
- // Verify that the CompositorFrame is blocked on |child_id1|. |
- EXPECT_FALSE(parent_surface()->HasActiveFrame()); |
- EXPECT_TRUE(parent_surface()->HasPendingFrame()); |
- EXPECT_THAT(parent_surface()->blocking_surfaces(), |
- UnorderedElementsAre(child_id1)); |
- |
- // Submit a CompositorFrame that depends on |child_id2|. |
- child_support1().SubmitCompositorFrame( |
- child_id1.local_surface_id(), |
- MakeCompositorFrame({child_id2}, empty_surface_ids())); |
- |
- // Verify that the CompositorFrame is blocked on |child_id2|. |
- EXPECT_FALSE(child_surface1()->HasActiveFrame()); |
- EXPECT_TRUE(child_surface1()->HasPendingFrame()); |
- EXPECT_THAT(child_surface1()->blocking_surfaces(), |
- UnorderedElementsAre(child_id2)); |
- |
- // Evict child_support1's current Surface. |
- // TODO(fsamuel): EvictFrame => EvictCurrentSurface. |
- child_support1().EvictFrame(); |
- |
- // The parent Surface should immediately activate. |
- EXPECT_TRUE(parent_surface()->HasActiveFrame()); |
- EXPECT_FALSE(parent_surface()->HasPendingFrame()); |
- EXPECT_THAT(parent_surface()->blocking_surfaces(), IsEmpty()); |
- EXPECT_FALSE(dependency_tracker().has_deadline()); |
-} |
+// Tests doing an EvictSurface which has unregistered dependency. |
+TEST_F(CompositorFrameSinkSupportTest, EvictSurfaceDependencyUnRegistered) { |
+ MockCompositorFrameSinkSupportClient mock_client; |
+ std::unique_ptr<CompositorFrameSinkSupport> support = |
+ CompositorFrameSinkSupport::Create( |
+ &mock_client, &manager_, kAnotherArbitraryFrameSinkId, kIsRoot, |
+ kHandlesFrameSinkIdInvalidation, kNeedsSyncPoints); |
+ LocalSurfaceId local_surface_id(7, kArbitraryToken); |
-// 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_F(CompositorFrameSinkSupportTest, DropStaleReferencesAfterActivation) { |
- const SurfaceId parent_id = MakeSurfaceId(kParentFrameSink, 1); |
- const SurfaceId child_id1 = MakeSurfaceId(kChildFrameSink1, 1); |
- const SurfaceId child_id2 = MakeSurfaceId(kChildFrameSink2, 1); |
- |
- // The parent submits a CompositorFrame that depends on |child_id1| before the |
- // child submits a CompositorFrame. |
- EXPECT_CALL(support_client_, DidReceiveCompositorFrameAck(_)).Times(0); |
- parent_support().SubmitCompositorFrame( |
- parent_id.local_surface_id(), |
- MakeCompositorFrame({child_id1}, empty_surface_ids())); |
- |
- // Verify that the CompositorFrame is blocked on |child_id|. |
- EXPECT_FALSE(parent_surface()->HasActiveFrame()); |
- EXPECT_TRUE(parent_surface()->HasPendingFrame()); |
- EXPECT_THAT(parent_surface()->blocking_surfaces(), |
- UnorderedElementsAre(child_id1)); |
- testing::Mock::VerifyAndClearExpectations(&support_client_); |
- |
- // Verify that no references are added while the CompositorFrame is pending. |
- EXPECT_THAT(GetChildReferences(parent_id), IsEmpty()); |
- |
- // DidReceiveCompositorFrameAck should get called twice: once for the child |
- // and once for the now active parent CompositorFrame. |
- EXPECT_CALL(support_client_, DidReceiveCompositorFrameAck(_)).Times(2); |
- child_support1().SubmitCompositorFrame(child_id1.local_surface_id(), |
- MakeCompositorFrame()); |
- testing::Mock::VerifyAndClearExpectations(&support_client_); |
- |
- // Verify that the child CompositorFrame activates immediately. |
- EXPECT_TRUE(child_surface1()->HasActiveFrame()); |
- EXPECT_FALSE(child_surface1()->HasPendingFrame()); |
- EXPECT_THAT(child_surface1()->blocking_surfaces(), IsEmpty()); |
- |
- // Verify that the parent Surface has activated. |
- EXPECT_TRUE(parent_surface()->HasActiveFrame()); |
- EXPECT_FALSE(parent_surface()->HasPendingFrame()); |
- EXPECT_THAT(parent_surface()->blocking_surfaces(), IsEmpty()); |
- |
- // Submit a new parent CompositorFrame to add a reference. |
- parent_support().SubmitCompositorFrame( |
- parent_id.local_surface_id(), |
- MakeCompositorFrame(empty_surface_ids(), {child_id1})); |
- |
- // Verify that the parent Surface has activated. |
- EXPECT_TRUE(parent_surface()->HasActiveFrame()); |
- EXPECT_FALSE(parent_surface()->HasPendingFrame()); |
- EXPECT_THAT(parent_surface()->blocking_surfaces(), IsEmpty()); |
- |
- // Verify that there is no temporary reference for the child and that |
- // the reference from the parent to the child still exists. |
- EXPECT_FALSE(HasTemporaryReference(child_id1)); |
- EXPECT_THAT(GetChildReferences(parent_id), UnorderedElementsAre(child_id1)); |
- |
- // The parent submits another CompositorFrame that depends on |child_id2|. |
- // Submitting a pending CompositorFrame will not trigger a CompositorFrameAck. |
- EXPECT_CALL(support_client_, DidReceiveCompositorFrameAck(_)).Times(0); |
- parent_support().SubmitCompositorFrame( |
- parent_id.local_surface_id(), |
- MakeCompositorFrame({child_id2}, empty_surface_ids())); |
- testing::Mock::VerifyAndClearExpectations(&support_client_); |
- |
- // The parent surface should now have both a pending and activate |
- // CompositorFrame. Verify that the set of child references from |
- // |parent_id| are only from the active CompositorFrame. |
- EXPECT_TRUE(parent_surface()->HasActiveFrame()); |
- EXPECT_TRUE(parent_surface()->HasPendingFrame()); |
- EXPECT_THAT(parent_surface()->blocking_surfaces(), |
- UnorderedElementsAre(child_id2)); |
- EXPECT_THAT(GetChildReferences(parent_id), UnorderedElementsAre(child_id1)); |
- |
- child_support2().SubmitCompositorFrame(child_id2.local_surface_id(), |
- MakeCompositorFrame()); |
- |
- // Verify that the parent Surface has activated and no longer has a pending |
- // CompositorFrame. Also verify that |child_id1| is no longer a child |
- // reference of |parent_id|. |
- EXPECT_TRUE(parent_surface()->HasActiveFrame()); |
- EXPECT_FALSE(parent_surface()->HasPendingFrame()); |
- EXPECT_THAT(parent_surface()->blocking_surfaces(), IsEmpty()); |
- // The parent will not immediately refer to the child until it submits a new |
- // CompositorFrame with the reference. |
- EXPECT_THAT(GetChildReferences(parent_id), IsEmpty()); |
+ TransferableResource resource; |
+ resource.id = 1; |
+ resource.mailbox_holder.texture_target = GL_TEXTURE_2D; |
+ CompositorFrame frame = MakeCompositorFrame(); |
+ frame.resource_list.push_back(resource); |
+ support->SubmitCompositorFrame(local_surface_id, std::move(frame)); |
+ EXPECT_EQ(last_created_surface_id().local_surface_id(), local_surface_id); |
+ local_surface_id_ = LocalSurfaceId(); |
+ |
+ SurfaceId surface_id(kAnotherArbitraryFrameSinkId, local_surface_id); |
+ Surface* surface = manager_.GetSurfaceForId(surface_id); |
+ surface->AddDestructionDependency( |
+ SurfaceSequence(kYetAnotherArbitraryFrameSinkId, 4)); |
+ |
+ ReturnedResourceArray returned_resource = {resource.ToReturnedResource()}; |
+ |
+ EXPECT_TRUE(manager_.GetSurfaceForId(surface_id)); |
+ EXPECT_CALL(mock_client, DidReceiveCompositorFrameAck(returned_resource)) |
+ .Times(1); |
+ support->EvictFrame(); |
+ EXPECT_FALSE(manager_.GetSurfaceForId(surface_id)); |
} |
-// Checks whether the latency info are moved to the new surface from the old |
-// one when LocalSurfaceId changes. No frame has unresolved dependencies. |
-TEST_F(CompositorFrameSinkSupportTest, |
- LatencyInfoCarriedOverOnResize_NoUnresolvedDependencies) { |
- const SurfaceId parent_id1 = MakeSurfaceId(kParentFrameSink, 1); |
- const SurfaceId parent_id2 = MakeSurfaceId(kParentFrameSink, 2); |
- const ui::LatencyComponentType latency_type1 = |
- ui::BROWSER_SNAPSHOT_FRAME_NUMBER_COMPONENT; |
- const int64_t latency_id1 = 234; |
- const int64_t latency_sequence_number1 = 5645432; |
- const ui::LatencyComponentType latency_type2 = ui::TAB_SHOW_COMPONENT; |
- const int64_t latency_id2 = 31434351; |
- const int64_t latency_sequence_number2 = 663788; |
- |
- // Submit a frame with latency info |
- ui::LatencyInfo info; |
- info.AddLatencyNumber(latency_type1, latency_id1, latency_sequence_number1); |
+// Tests doing an EvictSurface which has registered dependency. |
+TEST_F(CompositorFrameSinkSupportTest, EvictSurfaceDependencyRegistered) { |
+ MockCompositorFrameSinkSupportClient mock_client; |
+ std::unique_ptr<CompositorFrameSinkSupport> support = |
+ CompositorFrameSinkSupport::Create( |
+ &mock_client, &manager_, kAnotherArbitraryFrameSinkId, kIsRoot, |
+ kHandlesFrameSinkIdInvalidation, kNeedsSyncPoints); |
+ LocalSurfaceId local_surface_id(7, kArbitraryToken); |
+ TransferableResource resource; |
+ resource.id = 1; |
+ resource.mailbox_holder.texture_target = GL_TEXTURE_2D; |
CompositorFrame frame = MakeCompositorFrame(); |
- frame.metadata.latency_info.push_back(info); |
- |
- parent_support().SubmitCompositorFrame(parent_id1.local_surface_id(), |
- std::move(frame)); |
- |
- // Verify that the old surface has an active frame and no pending frame. |
- Surface* old_surface = surface_manager().GetSurfaceForId(parent_id1); |
- ASSERT_NE(nullptr, old_surface); |
- EXPECT_TRUE(old_surface->HasActiveFrame()); |
- EXPECT_FALSE(old_surface->HasPendingFrame()); |
- |
- // Submit another frame with some other latency info and a different |
- // LocalSurfaceId. |
- ui::LatencyInfo info2; |
- info2.AddLatencyNumber(latency_type2, latency_id2, latency_sequence_number2); |
- |
- CompositorFrame frame2 = MakeCompositorFrame(); |
- frame2.metadata.latency_info.push_back(info2); |
- |
- parent_support().SubmitCompositorFrame(parent_id2.local_surface_id(), |
- std::move(frame2)); |
- |
- // Verify that the new surface has an active frame and no pending frames. |
- Surface* surface = surface_manager().GetSurfaceForId(parent_id2); |
- ASSERT_NE(nullptr, surface); |
- EXPECT_TRUE(surface->HasActiveFrame()); |
- EXPECT_FALSE(surface->HasPendingFrame()); |
- |
- // Verify that the new surface has both latency info elements. |
- std::vector<ui::LatencyInfo> info_list; |
- surface->TakeLatencyInfo(&info_list); |
- EXPECT_EQ(2u, info_list.size()); |
- |
- ui::LatencyInfo aggregated_latency_info = info_list[0]; |
- aggregated_latency_info.AddNewLatencyFrom(info_list[1]); |
- |
- // Two components are the original ones, and the third one is |
- // DISPLAY_COMPOSITOR_RECEIVED_FRAME_COMPONENT, logged on compositor frame |
- // submit. |
- EXPECT_EQ(3u, aggregated_latency_info.latency_components().size()); |
- |
- ui::LatencyInfo::LatencyComponent comp1; |
- EXPECT_TRUE( |
- aggregated_latency_info.FindLatency(latency_type1, latency_id1, &comp1)); |
- EXPECT_EQ(latency_sequence_number1, comp1.sequence_number); |
- EXPECT_TRUE( |
- aggregated_latency_info.FindLatency(latency_type2, latency_id2, nullptr)); |
- EXPECT_TRUE(aggregated_latency_info.FindLatency( |
- ui::DISPLAY_COMPOSITOR_RECEIVED_FRAME_COMPONENT, nullptr)); |
-} |
+ frame.resource_list.push_back(resource); |
+ uint32_t execute_count = 0; |
+ support->SubmitCompositorFrame(local_surface_id, std::move(frame)); |
+ EXPECT_EQ(last_created_surface_id().local_surface_id(), local_surface_id); |
+ local_surface_id_ = LocalSurfaceId(); |
-// Checks whether the latency info are moved to the new surface from the old |
-// one when LocalSurfaceId changes. Old surface has unresolved dependencies. |
-TEST_F(CompositorFrameSinkSupportTest, |
- LatencyInfoCarriedOverOnResize_OldSurfaceHasPendingAndActiveFrame) { |
- const SurfaceId parent_id1 = MakeSurfaceId(kParentFrameSink, 1); |
- const SurfaceId parent_id2 = MakeSurfaceId(kParentFrameSink, 2); |
- const SurfaceId child_id = MakeSurfaceId(kChildFrameSink1, 1); |
- |
- const ui::LatencyComponentType latency_type1 = |
- ui::BROWSER_SNAPSHOT_FRAME_NUMBER_COMPONENT; |
- const int64_t latency_id1 = 234; |
- const int64_t latency_sequence_number1 = 5645432; |
- const ui::LatencyComponentType latency_type2 = ui::TAB_SHOW_COMPONENT; |
- const int64_t latency_id2 = 31434351; |
- const int64_t latency_sequence_number2 = 663788; |
- |
- // Submit a frame with no unresolved dependecy. |
- ui::LatencyInfo info; |
- info.AddLatencyNumber(latency_type1, latency_id1, latency_sequence_number1); |
+ manager_.RegisterFrameSinkId(kYetAnotherArbitraryFrameSinkId); |
- CompositorFrame frame = MakeCompositorFrame(); |
- frame.metadata.latency_info.push_back(info); |
- |
- parent_support().SubmitCompositorFrame(parent_id1.local_surface_id(), |
- std::move(frame)); |
- |
- // Submit a frame with unresolved dependencies. |
- ui::LatencyInfo info2; |
- info2.AddLatencyNumber(latency_type2, latency_id2, latency_sequence_number2); |
- |
- CompositorFrame frame2 = MakeCompositorFrame({child_id}, empty_surface_ids()); |
- frame2.metadata.latency_info.push_back(info2); |
- |
- parent_support().SubmitCompositorFrame(parent_id1.local_surface_id(), |
- std::move(frame2)); |
- |
- // Verify that the old surface has both an active and a pending frame. |
- Surface* old_surface = surface_manager().GetSurfaceForId(parent_id1); |
- ASSERT_NE(nullptr, old_surface); |
- EXPECT_TRUE(old_surface->HasActiveFrame()); |
- EXPECT_TRUE(old_surface->HasPendingFrame()); |
- |
- // Submit a frame with a new local surface id. |
- parent_support().SubmitCompositorFrame(parent_id2.local_surface_id(), |
- MakeCompositorFrame()); |
- |
- // Verify that the new surface has an active frame only. |
- Surface* surface = surface_manager().GetSurfaceForId(parent_id2); |
- ASSERT_NE(nullptr, surface); |
- EXPECT_TRUE(surface->HasActiveFrame()); |
- EXPECT_FALSE(surface->HasPendingFrame()); |
- |
- // Verify that the new surface has latency info from both active and pending |
- // frame of the old surface. |
- std::vector<ui::LatencyInfo> info_list; |
- surface->TakeLatencyInfo(&info_list); |
- EXPECT_EQ(2u, info_list.size()); |
- |
- ui::LatencyInfo aggregated_latency_info = info_list[0]; |
- aggregated_latency_info.AddNewLatencyFrom(info_list[1]); |
- |
- // Two components are the original ones, and the third one is |
- // DISPLAY_COMPOSITOR_RECEIVED_FRAME_COMPONENT, logged on compositor frame |
- // submit. |
- EXPECT_EQ(3u, aggregated_latency_info.latency_components().size()); |
- |
- ui::LatencyInfo::LatencyComponent comp1; |
- EXPECT_TRUE( |
- aggregated_latency_info.FindLatency(latency_type1, latency_id1, &comp1)); |
- EXPECT_EQ(latency_sequence_number1, comp1.sequence_number); |
- EXPECT_TRUE( |
- aggregated_latency_info.FindLatency(latency_type2, latency_id2, nullptr)); |
- EXPECT_TRUE(aggregated_latency_info.FindLatency( |
- ui::DISPLAY_COMPOSITOR_RECEIVED_FRAME_COMPONENT, nullptr)); |
-} |
+ SurfaceId surface_id(kAnotherArbitraryFrameSinkId, local_surface_id); |
+ Surface* surface = manager_.GetSurfaceForId(surface_id); |
+ surface->AddDestructionDependency( |
+ SurfaceSequence(kYetAnotherArbitraryFrameSinkId, 4)); |
-// Checks whether the latency info are moved to the new surface from the old |
-// one when LocalSurfaceId changes. The new surface has unresolved dependencies. |
-TEST_F(CompositorFrameSinkSupportTest, |
- LatencyInfoCarriedOverOnResize_NewSurfaceHasPendingFrame) { |
- const SurfaceId parent_id1 = MakeSurfaceId(kParentFrameSink, 1); |
- const SurfaceId parent_id2 = MakeSurfaceId(kParentFrameSink, 2); |
- const SurfaceId child_id = MakeSurfaceId(kChildFrameSink1, 1); |
- |
- const ui::LatencyComponentType latency_type1 = |
- ui::BROWSER_SNAPSHOT_FRAME_NUMBER_COMPONENT; |
- const int64_t latency_id1 = 234; |
- const int64_t latency_sequence_number1 = 5645432; |
- const ui::LatencyComponentType latency_type2 = ui::TAB_SHOW_COMPONENT; |
- const int64_t latency_id2 = 31434351; |
- const int64_t latency_sequence_number2 = 663788; |
- |
- // Submit a frame with no unresolved dependencies. |
- ui::LatencyInfo info; |
- info.AddLatencyNumber(latency_type1, latency_id1, latency_sequence_number1); |
+ ReturnedResourceArray returned_resources; |
+ EXPECT_TRUE(manager_.GetSurfaceForId(surface_id)); |
+ support->EvictFrame(); |
+ EXPECT_TRUE(manager_.GetSurfaceForId(surface_id)); |
+ EXPECT_EQ(0u, execute_count); |
+ |
+ returned_resources.push_back(resource.ToReturnedResource()); |
+ EXPECT_CALL(mock_client, DidReceiveCompositorFrameAck(returned_resources)) |
+ .Times(1); |
+ manager_.SatisfySequence(SurfaceSequence(kYetAnotherArbitraryFrameSinkId, 4)); |
+ EXPECT_FALSE(manager_.GetSurfaceForId(surface_id)); |
+} |
- CompositorFrame frame = MakeCompositorFrame(); |
- frame.metadata.latency_info.push_back(info); |
- |
- parent_support().SubmitCompositorFrame(parent_id1.local_surface_id(), |
- std::move(frame)); |
- |
- // Verify that the old surface has an active frame only. |
- Surface* old_surface = surface_manager().GetSurfaceForId(parent_id1); |
- ASSERT_NE(nullptr, old_surface); |
- EXPECT_TRUE(old_surface->HasActiveFrame()); |
- EXPECT_FALSE(old_surface->HasPendingFrame()); |
- |
- // Submit a frame with a new local surface id and with unresolved |
- // dependencies. |
- ui::LatencyInfo info2; |
- info2.AddLatencyNumber(latency_type2, latency_id2, latency_sequence_number2); |
- |
- CompositorFrame frame2 = MakeCompositorFrame({child_id}, empty_surface_ids()); |
- frame2.metadata.latency_info.push_back(info2); |
- |
- parent_support().SubmitCompositorFrame(parent_id2.local_surface_id(), |
- std::move(frame2)); |
- |
- // Verify that the new surface has a pending frame and no active frame. |
- Surface* surface = surface_manager().GetSurfaceForId(parent_id2); |
- ASSERT_NE(nullptr, surface); |
- EXPECT_TRUE(surface->HasPendingFrame()); |
- EXPECT_FALSE(surface->HasActiveFrame()); |
- |
- // Resolve the dependencies. The frame in parent's surface must become active. |
- child_support1().SubmitCompositorFrame(child_id.local_surface_id(), |
- MakeCompositorFrame()); |
- EXPECT_FALSE(surface->HasPendingFrame()); |
- EXPECT_TRUE(surface->HasActiveFrame()); |
- |
- // Both latency info elements must exist in the now-activated frame of the |
- // new surface. |
- std::vector<ui::LatencyInfo> info_list; |
- surface->TakeLatencyInfo(&info_list); |
- EXPECT_EQ(2u, info_list.size()); |
- |
- ui::LatencyInfo aggregated_latency_info = info_list[0]; |
- aggregated_latency_info.AddNewLatencyFrom(info_list[1]); |
- |
- // Two components are the original ones, and the third one is |
- // DISPLAY_COMPOSITOR_RECEIVED_FRAME_COMPONENT, logged on compositor frame |
- // submit. |
- EXPECT_EQ(3u, aggregated_latency_info.latency_components().size()); |
- |
- ui::LatencyInfo::LatencyComponent comp1; |
- EXPECT_TRUE( |
- aggregated_latency_info.FindLatency(latency_type1, latency_id1, &comp1)); |
- EXPECT_EQ(latency_sequence_number1, comp1.sequence_number); |
- EXPECT_TRUE( |
- aggregated_latency_info.FindLatency(latency_type2, latency_id2, nullptr)); |
- EXPECT_TRUE(aggregated_latency_info.FindLatency( |
- ui::DISPLAY_COMPOSITOR_RECEIVED_FRAME_COMPONENT, nullptr)); |
+TEST_F(CompositorFrameSinkSupportTest, DestroySequence) { |
+ LocalSurfaceId local_surface_id2(5, kArbitraryToken); |
+ std::unique_ptr<CompositorFrameSinkSupport> support2 = |
+ CompositorFrameSinkSupport::Create( |
+ &fake_support_client_, &manager_, kYetAnotherArbitraryFrameSinkId, |
+ kIsChildRoot, kHandlesFrameSinkIdInvalidation, kNeedsSyncPoints); |
+ SurfaceId id2(kYetAnotherArbitraryFrameSinkId, local_surface_id2); |
+ support2->SubmitCompositorFrame(local_surface_id2, MakeCompositorFrame()); |
+ |
+ // Check that waiting before the sequence is satisfied works. |
+ manager_.GetSurfaceForId(id2)->AddDestructionDependency( |
+ SurfaceSequence(kYetAnotherArbitraryFrameSinkId, 4)); |
+ support2->EvictFrame(); |
+ |
+ DCHECK(manager_.GetSurfaceForId(id2)); |
+ manager_.SatisfySequence(SurfaceSequence(kYetAnotherArbitraryFrameSinkId, 4)); |
+ manager_.SatisfySequence(SurfaceSequence(kYetAnotherArbitraryFrameSinkId, 6)); |
+ DCHECK(!manager_.GetSurfaceForId(id2)); |
+ |
+ // Check that waiting after the sequence is satisfied works. |
+ support2->SubmitCompositorFrame(local_surface_id2, MakeCompositorFrame()); |
+ DCHECK(manager_.GetSurfaceForId(id2)); |
+ manager_.GetSurfaceForId(id2)->AddDestructionDependency( |
+ SurfaceSequence(kAnotherArbitraryFrameSinkId, 6)); |
+ support2->EvictFrame(); |
+ DCHECK(!manager_.GetSurfaceForId(id2)); |
} |
-TEST_F(CompositorFrameSinkSupportTest, PassesOnBeginFrameAcks) { |
- const SurfaceId display_id = MakeSurfaceId(kDisplayFrameSink, 1); |
+// Tests that Surface ID namespace invalidation correctly allows |
+// Sequences to be ignored. |
+TEST_F(CompositorFrameSinkSupportTest, InvalidFrameSinkId) { |
+ FrameSinkId frame_sink_id(1234, 5678); |
- // Request BeginFrames. |
- display_support().SetNeedsBeginFrame(true); |
+ LocalSurfaceId local_surface_id(5, kArbitraryToken); |
+ SurfaceId id(support_->frame_sink_id(), local_surface_id); |
+ support_->SubmitCompositorFrame(local_surface_id, MakeCompositorFrame()); |
- // Issue a BeginFrame. |
- BeginFrameArgs args = |
- CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 0, 1); |
- begin_frame_source()->TestOnBeginFrame(args); |
+ manager_.RegisterFrameSinkId(frame_sink_id); |
+ manager_.GetSurfaceForId(id)->AddDestructionDependency( |
+ SurfaceSequence(frame_sink_id, 4)); |
- // Check that the support forwards a BeginFrameDidNotSwap ack to the |
- // BeginFrameSource. |
- BeginFrameAck ack(0, 1, 1, false); |
- display_support().BeginFrameDidNotSwap(ack); |
- EXPECT_EQ(ack, begin_frame_source()->LastAckForObserver(&display_support())); |
+ support_->EvictFrame(); |
- // Issue another BeginFrame. |
- args = CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 0, 2); |
- begin_frame_source()->TestOnBeginFrame(args); |
+ // Verify the dependency has prevented the surface from getting destroyed. |
+ EXPECT_TRUE(manager_.GetSurfaceForId(id)); |
- // Check that the support forwards the BeginFrameAck attached |
- // to a CompositorFrame to the BeginFrameSource. |
- BeginFrameAck ack2(0, 2, 2, true); |
- CompositorFrame frame = MakeCompositorFrame(); |
- frame.metadata.begin_frame_ack = ack2; |
- display_support().SubmitCompositorFrame(display_id.local_surface_id(), |
- std::move(frame)); |
- EXPECT_EQ(ack2, begin_frame_source()->LastAckForObserver(&display_support())); |
-} |
+ manager_.InvalidateFrameSinkId(frame_sink_id); |
-// Checks that resources and ack are sent together if possible. |
-TEST_F(CompositorFrameSinkSupportTest, ReturnResourcesWithAck) { |
- const SurfaceId parent_id = MakeSurfaceId(kParentFrameSink, 1); |
- TransferableResource resource; |
- resource.id = 1234; |
- parent_support().SubmitCompositorFrame( |
- parent_id.local_surface_id(), |
- MakeCompositorFrameWithResources(empty_surface_ids(), {resource})); |
- ReturnedResourceArray returned_resources; |
- TransferableResource::ReturnResources({resource}, &returned_resources); |
- EXPECT_CALL(support_client_, ReclaimResources(_)).Times(0); |
- EXPECT_CALL(support_client_, |
- DidReceiveCompositorFrameAck(Eq(returned_resources))); |
- parent_support().SubmitCompositorFrame(parent_id.local_surface_id(), |
- MakeCompositorFrame()); |
+ // Verify that the invalidated namespace caused the unsatisfied sequence |
+ // to be ignored. |
+ EXPECT_FALSE(manager_.GetSurfaceForId(id)); |
} |
-// Verifies that if a surface is marked destroyed and a new frame arrives for |
-// it, it will be recovered. |
-TEST_F(CompositorFrameSinkSupportTest, SurfaceResurrection) { |
- const SurfaceId parent_id = MakeSurfaceId(kParentFrameSink, 1); |
- const SurfaceId child_id = MakeSurfaceId(kChildFrameSink1, 3); |
- |
- // Create the child surface by submitting a frame to it. |
- EXPECT_EQ(nullptr, surface_manager().GetSurfaceForId(child_id)); |
- child_support1().SubmitCompositorFrame(child_id.local_surface_id(), |
- MakeCompositorFrame()); |
- |
- // Verify that the child surface is created. |
- Surface* surface = surface_manager().GetSurfaceForId(child_id); |
- EXPECT_NE(nullptr, surface); |
- |
- // Add a reference from the parent to the child. |
- parent_support().SubmitCompositorFrame(parent_id.local_surface_id(), |
- MakeCompositorFrame({child_id})); |
- |
- // Attempt to destroy the child surface. The surface must still exist since |
- // the parent needs it but it will be marked as destroyed. |
- child_support1().EvictFrame(); |
- surface = surface_manager().GetSurfaceForId(child_id); |
- EXPECT_NE(nullptr, surface); |
- EXPECT_TRUE(surface->destroyed()); |
- |
- // Child submits another frame to the same local surface id that is marked |
- // destroyed. |
- child_support1().SubmitCompositorFrame(child_id.local_surface_id(), |
- MakeCompositorFrame()); |
- |
- // Verify that the surface that was marked destroyed is recovered and is being |
- // used again. |
- Surface* surface2 = surface_manager().GetSurfaceForId(child_id); |
- EXPECT_EQ(surface, surface2); |
- EXPECT_FALSE(surface2->destroyed()); |
+TEST_F(CompositorFrameSinkSupportTest, DestroyCycle) { |
+ LocalSurfaceId local_surface_id2(5, kArbitraryToken); |
+ SurfaceId id2(kYetAnotherArbitraryFrameSinkId, local_surface_id2); |
+ std::unique_ptr<CompositorFrameSinkSupport> support2 = |
+ CompositorFrameSinkSupport::Create( |
+ &fake_support_client_, &manager_, kYetAnotherArbitraryFrameSinkId, |
+ kIsChildRoot, kHandlesFrameSinkIdInvalidation, kNeedsSyncPoints); |
+ manager_.RegisterFrameSinkId(kAnotherArbitraryFrameSinkId); |
+ // Give id2 a frame that references local_surface_id_. |
+ { |
+ std::unique_ptr<RenderPass> render_pass(RenderPass::Create()); |
+ CompositorFrame frame = MakeCompositorFrame(); |
+ frame.render_pass_list.push_back(std::move(render_pass)); |
+ frame.metadata.referenced_surfaces.push_back( |
+ SurfaceId(support_->frame_sink_id(), local_surface_id_)); |
+ support2->SubmitCompositorFrame(local_surface_id2, std::move(frame)); |
+ EXPECT_EQ(last_created_surface_id().local_surface_id(), local_surface_id2); |
+ } |
+ manager_.GetSurfaceForId(id2)->AddDestructionDependency( |
+ SurfaceSequence(kAnotherArbitraryFrameSinkId, 4)); |
+ support2->EvictFrame(); |
+ // Give local_surface_id_ a frame that references id2. |
+ { |
+ std::unique_ptr<RenderPass> render_pass(RenderPass::Create()); |
+ CompositorFrame frame = MakeCompositorFrame(); |
+ frame.render_pass_list.push_back(std::move(render_pass)); |
+ frame.metadata.referenced_surfaces.push_back(id2); |
+ support_->SubmitCompositorFrame(local_surface_id_, std::move(frame)); |
+ } |
+ support_->EvictFrame(); |
+ EXPECT_TRUE(manager_.GetSurfaceForId(id2)); |
+ // local_surface_id_ should be retained by reference from id2. |
+ EXPECT_TRUE(manager_.GetSurfaceForId( |
+ SurfaceId(support_->frame_sink_id(), local_surface_id_))); |
+ |
+ // Satisfy last destruction dependency for id2. |
+ manager_.SatisfySequence(SurfaceSequence(kAnotherArbitraryFrameSinkId, 4)); |
+ |
+ // id2 and local_surface_id_ are in a reference cycle that has no surface |
+ // sequences holding on to it, so they should be destroyed. |
+ EXPECT_TRUE(!manager_.GetSurfaceForId(id2)); |
+ EXPECT_TRUE(!manager_.GetSurfaceForId( |
+ SurfaceId(support_->frame_sink_id(), local_surface_id_))); |
+ |
+ local_surface_id_ = LocalSurfaceId(); |
} |
-// Verifies that if a LocalSurfaceId belonged to a surface that doesn't exist |
-// anymore, it can still be reused for new surfaces. |
-TEST_F(CompositorFrameSinkSupportTest, LocalSurfaceIdIsReusable) { |
- const SurfaceId parent_id = MakeSurfaceId(kParentFrameSink, 1); |
- const SurfaceId child_id = MakeSurfaceId(kChildFrameSink1, 3); |
- |
- // Submit the first frame. Creates the surface. |
- child_support1().SubmitCompositorFrame(child_id.local_surface_id(), |
- MakeCompositorFrame()); |
- EXPECT_NE(nullptr, surface_manager().GetSurfaceForId(child_id)); |
- |
- // Add a reference from parent. |
- parent_support().SubmitCompositorFrame(parent_id.local_surface_id(), |
- MakeCompositorFrame({child_id})); |
- |
- // Remove the reference from parant. This allows us to destroy the surface. |
- parent_support().SubmitCompositorFrame(parent_id.local_surface_id(), |
- MakeCompositorFrame()); |
- |
- // Destroy the surface. |
- child_support1().EvictFrame(); |
- EXPECT_EQ(nullptr, surface_manager().GetSurfaceForId(child_id)); |
- |
- // Submit another frame with the same local surface id. This should work fine |
- // and a new surface must be created. |
- child_support1().SubmitCompositorFrame(child_id.local_surface_id(), |
- MakeCompositorFrame()); |
- EXPECT_NE(nullptr, surface_manager().GetSurfaceForId(child_id)); |
+void CopyRequestTestCallback(bool* called, |
+ std::unique_ptr<CopyOutputResult> result) { |
+ *called = true; |
} |
-// 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(CompositorFrameSinkSupportTest, DependencyTrackingGarbageCollection) { |
- const SurfaceId display_id = MakeSurfaceId(kDisplayFrameSink, 1); |
- const SurfaceId parent_id1 = MakeSurfaceId(kParentFrameSink, 1); |
- const SurfaceId parent_id2 = MakeSurfaceId(kParentFrameSink, 2); |
- const SurfaceId child_id = MakeSurfaceId(kChildFrameSink1, 1); |
- |
- parent_support().SubmitCompositorFrame( |
- parent_id1.local_surface_id(), |
- MakeCompositorFrame({child_id}, empty_surface_ids())); |
- display_support().SubmitCompositorFrame( |
- display_id.local_surface_id(), |
- MakeCompositorFrame({parent_id1}, empty_surface_ids())); |
- |
- EXPECT_TRUE(dependency_tracker().has_deadline()); |
- |
- BeginFrameArgs args = |
- CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 0, 1); |
- |
- // Advance BeginFrames to trigger a deadline. |
- for (int i = 0; i < 3; ++i) { |
- begin_frame_source()->TestOnBeginFrame(args); |
- EXPECT_TRUE(dependency_tracker().has_deadline()); |
+TEST_F(CompositorFrameSinkSupportTest, DuplicateCopyRequest) { |
+ { |
+ std::unique_ptr<RenderPass> render_pass(RenderPass::Create()); |
+ CompositorFrame frame = MakeCompositorFrame(); |
+ frame.render_pass_list.push_back(std::move(render_pass)); |
+ frame.metadata.referenced_surfaces.push_back( |
+ SurfaceId(support_->frame_sink_id(), local_surface_id_)); |
+ support_->SubmitCompositorFrame(local_surface_id_, std::move(frame)); |
+ EXPECT_EQ(last_created_surface_id().local_surface_id(), local_surface_id_); |
} |
- begin_frame_source()->TestOnBeginFrame(args); |
- EXPECT_FALSE(dependency_tracker().has_deadline()); |
- |
- EXPECT_TRUE(display_surface()->HasActiveFrame()); |
- EXPECT_FALSE(display_surface()->HasPendingFrame()); |
- EXPECT_TRUE(parent_surface()->HasActiveFrame()); |
- EXPECT_FALSE(parent_surface()->HasPendingFrame()); |
- |
- parent_support().SubmitCompositorFrame( |
- parent_id2.local_surface_id(), |
- MakeCompositorFrame({child_id}, empty_surface_ids())); |
- display_support().SubmitCompositorFrame( |
- display_id.local_surface_id(), |
- MakeCompositorFrame({parent_id2}, empty_surface_ids())); |
- |
- // The display surface now has two CompositorFrames. One that is pending, |
- // indirectly blocked on child_id and one that is active, also indirectly |
- // referring to child_id, but activated due to the deadline above. |
- EXPECT_TRUE(display_surface()->HasActiveFrame()); |
- EXPECT_TRUE(display_surface()->HasPendingFrame()); |
- |
- // Submitting a CompositorFrame will trigger garbage collection of the |
- // |parent_id1| subtree. This should not crash. |
- child_support1().SubmitCompositorFrame(child_id.local_surface_id(), |
- MakeCompositorFrame()); |
-} |
-// 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(CompositorFrameSinkSupportTest, GarbageCollectionOnDeadline) { |
- const SurfaceId display_id = MakeSurfaceId(kDisplayFrameSink, 1); |
- const SurfaceId parent_id1 = MakeSurfaceId(kParentFrameSink, 1); |
- const SurfaceId parent_id2 = MakeSurfaceId(kParentFrameSink, 2); |
- const SurfaceId child_id = MakeSurfaceId(kChildFrameSink1, 1); |
- |
- // |parent_id1| is blocked on |child_id|. |
- parent_support().SubmitCompositorFrame( |
- parent_id1.local_surface_id(), |
- MakeCompositorFrame({child_id}, empty_surface_ids())); |
- |
- display_support().SubmitCompositorFrame(display_id.local_surface_id(), |
- MakeCompositorFrame({parent_id1})); |
- |
- EXPECT_TRUE(dependency_tracker().has_deadline()); |
- EXPECT_TRUE(display_surface()->HasPendingFrame()); |
- EXPECT_FALSE(display_surface()->HasActiveFrame()); |
- |
- // Advance BeginFrames to trigger a deadline. This activates the |
- // CompositorFrame submitted above. |
- BeginFrameArgs args = |
- CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 0, 1); |
- for (int i = 0; i < 3; ++i) { |
- begin_frame_source()->TestOnBeginFrame(args); |
- EXPECT_TRUE(dependency_tracker().has_deadline()); |
- } |
- begin_frame_source()->TestOnBeginFrame(args); |
- EXPECT_FALSE(dependency_tracker().has_deadline()); |
- EXPECT_FALSE(display_surface()->HasPendingFrame()); |
- EXPECT_TRUE(display_surface()->HasActiveFrame()); |
- |
- // By submitting a display CompositorFrame, and replacing the parent's |
- // CompositorFrame with another surface ID, parent_id1 becomes unreachable and |
- // a candidate for garbage collection. |
- display_support().SubmitCompositorFrame( |
- display_id.local_surface_id(), |
- MakeCompositorFrame({parent_id2}, empty_surface_ids())); |
- |
- // Now |parent_id1| is only kept alive by the active |display_id| frame. |
- parent_support().SubmitCompositorFrame( |
- parent_id2.local_surface_id(), |
- MakeCompositorFrame({child_id}, empty_surface_ids())); |
- |
- // SurfaceDependencyTracker should now be tracking |display_id|, |parent_id1| |
- // and |parent_id2|. By activating the pending |display_id| frame by deadline, |
- // |parent_id1| becomes unreachable and is garbage collected while |
- // SurfaceDependencyTracker is in the process of activating surfaces. This |
- // should not cause a crash or use-after-free. |
- for (int i = 0; i < 3; ++i) { |
- begin_frame_source()->TestOnBeginFrame(args); |
- EXPECT_TRUE(dependency_tracker().has_deadline()); |
- } |
- begin_frame_source()->TestOnBeginFrame(args); |
- EXPECT_FALSE(dependency_tracker().has_deadline()); |
+ bool called1 = false; |
+ std::unique_ptr<CopyOutputRequest> request; |
+ request = CopyOutputRequest::CreateRequest( |
+ base::Bind(&CopyRequestTestCallback, &called1)); |
+ request->set_source(kArbitrarySourceId1); |
+ |
+ support_->RequestCopyOfSurface(std::move(request)); |
+ EXPECT_FALSE(called1); |
+ |
+ bool called2 = false; |
+ request = CopyOutputRequest::CreateRequest( |
+ base::Bind(&CopyRequestTestCallback, &called2)); |
+ request->set_source(kArbitrarySourceId2); |
+ |
+ support_->RequestCopyOfSurface(std::move(request)); |
+ // Callbacks have different sources so neither should be called. |
+ EXPECT_FALSE(called1); |
+ EXPECT_FALSE(called2); |
+ |
+ bool called3 = false; |
+ request = CopyOutputRequest::CreateRequest( |
+ base::Bind(&CopyRequestTestCallback, &called3)); |
+ request->set_source(kArbitrarySourceId1); |
+ |
+ support_->RequestCopyOfSurface(std::move(request)); |
+ // Two callbacks are from source1, so the first should be called. |
+ EXPECT_TRUE(called1); |
+ EXPECT_FALSE(called2); |
+ EXPECT_FALSE(called3); |
+ |
+ support_->EvictFrame(); |
+ local_surface_id_ = LocalSurfaceId(); |
+ EXPECT_TRUE(called1); |
+ EXPECT_TRUE(called2); |
+ EXPECT_TRUE(called3); |
} |
-// This test verifies that a CompositorFrame will only blocked on embedded |
-// surfaces but not on other retained surface IDs in the CompositorFrame. |
-TEST_F(CompositorFrameSinkSupportTest, OnlyBlockOnEmbeddedSurfaces) { |
- const SurfaceId display_id = MakeSurfaceId(kDisplayFrameSink, 1); |
- const SurfaceId parent_id1 = MakeSurfaceId(kParentFrameSink, 1); |
- const SurfaceId parent_id2 = MakeSurfaceId(kParentFrameSink, 2); |
- |
- // Submitting a CompositorFrame with |parent_id2| so that the display |
- // CompositorFrame can hold a reference to it. |
- parent_support().SubmitCompositorFrame(parent_id2.local_surface_id(), |
- MakeCompositorFrame()); |
- |
- display_support().SubmitCompositorFrame( |
- display_id.local_surface_id(), |
- MakeCompositorFrame({parent_id1}, {parent_id2})); |
- |
- EXPECT_TRUE(display_surface()->HasPendingFrame()); |
- EXPECT_FALSE(display_surface()->HasActiveFrame()); |
- EXPECT_TRUE(dependency_tracker().has_deadline()); |
- |
- // Verify that the display CompositorFrame will only block on |parent_id1| but |
- // not |parent_id2|. |
- EXPECT_THAT(display_surface()->blocking_surfaces(), |
- UnorderedElementsAre(parent_id1)); |
- // Verify that the display surface holds no references while its |
- // CompositorFrame is pending. |
- EXPECT_THAT(GetChildReferences(display_id), IsEmpty()); |
- |
- // Submitting a CompositorFrame with |parent_id1| should unblock the display |
- // CompositorFrame. |
- parent_support().SubmitCompositorFrame(parent_id1.local_surface_id(), |
- MakeCompositorFrame()); |
- |
- EXPECT_FALSE(dependency_tracker().has_deadline()); |
- EXPECT_FALSE(display_surface()->HasPendingFrame()); |
- EXPECT_TRUE(display_surface()->HasActiveFrame()); |
- EXPECT_THAT(display_surface()->blocking_surfaces(), IsEmpty()); |
-} |
+// Check whether the SurfaceInfo object is created and populated correctly |
+// after the frame submission. |
+TEST_F(CompositorFrameSinkSupportTest, SurfaceInfo) { |
+ CompositorFrame frame = MakeCompositorFrame(); |
-// This test verifies that a late arriving CompositorFrame activates immediately |
-// and does not trigger a new deadline. |
-TEST_F(CompositorFrameSinkSupportTest, LateArrivingDependency) { |
- const SurfaceId display_id = MakeSurfaceId(kDisplayFrameSink, 1); |
- const SurfaceId parent_id1 = MakeSurfaceId(kParentFrameSink, 1); |
- const SurfaceId child_id1 = MakeSurfaceId(kChildFrameSink1, 1); |
- |
- display_support().SubmitCompositorFrame( |
- display_id.local_surface_id(), |
- MakeCompositorFrame({parent_id1}, empty_surface_ids())); |
- |
- EXPECT_TRUE(display_surface()->HasPendingFrame()); |
- EXPECT_FALSE(display_surface()->HasActiveFrame()); |
- EXPECT_TRUE(dependency_tracker().has_deadline()); |
- |
- // Advance BeginFrames to trigger a deadline. This activates the |
- // CompositorFrame submitted above. |
- BeginFrameArgs args = |
- CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 0, 1); |
- for (int i = 0; i < 3; ++i) { |
- begin_frame_source()->TestOnBeginFrame(args); |
- EXPECT_TRUE(dependency_tracker().has_deadline()); |
- } |
- begin_frame_source()->TestOnBeginFrame(args); |
- EXPECT_FALSE(dependency_tracker().has_deadline()); |
- EXPECT_FALSE(display_surface()->HasPendingFrame()); |
- EXPECT_TRUE(display_surface()->HasActiveFrame()); |
- |
- // A late arriving CompositorFrame should activate immediately without |
- // scheduling a deadline and without waiting for dependencies to resolve. |
- parent_support().SubmitCompositorFrame( |
- parent_id1.local_surface_id(), |
- MakeCompositorFrame({child_id1}, empty_surface_ids())); |
- EXPECT_FALSE(dependency_tracker().has_deadline()); |
- EXPECT_FALSE(parent_surface()->HasPendingFrame()); |
- EXPECT_TRUE(parent_surface()->HasActiveFrame()); |
-} |
+ auto render_pass = RenderPass::Create(); |
+ render_pass->SetNew(1, gfx::Rect(5, 6), gfx::Rect(), gfx::Transform()); |
+ frame.render_pass_list.push_back(std::move(render_pass)); |
-// This test verifies that CompositorFrames submitted to a surface referenced |
-// by a parent CompositorFrame as a fallback will be rejected and ACK'ed |
-// immediately. |
-TEST_F(CompositorFrameSinkSupportTest, FallbackSurfacesClosed) { |
- const SurfaceId parent_id1 = MakeSurfaceId(kParentFrameSink, 1); |
- // This is the fallback child surface that the parent holds a reference to. |
- const SurfaceId child_id1 = MakeSurfaceId(kChildFrameSink1, 1); |
- // This is the primary child surface that the parent wants to block on. |
- const SurfaceId child_id2 = MakeSurfaceId(kChildFrameSink1, 2); |
- |
- // child_support1 submits a CompositorFrame without any dependencies. |
- // DidReceiveCompositorFrameAck should call on immediate activation. |
- // However, resources will not be returned because this frame is a candidate |
- // for display. |
- TransferableResource resource = |
- MakeResource(1337 /* id */, ALPHA_8 /* format */, 1234 /* filter */, |
- gfx::Size(1234, 5678)); |
- ReturnedResourceArray returned_resources; |
- TransferableResource::ReturnResources({resource}, &returned_resources); |
- |
- EXPECT_CALL(support_client_, |
- DidReceiveCompositorFrameAck(Eq(ReturnedResourceArray()))); |
- child_support1().SubmitCompositorFrame( |
- child_id1.local_surface_id(), |
- MakeCompositorFrameWithResources(empty_surface_ids(), {resource})); |
- testing::Mock::VerifyAndClearExpectations(&support_client_); |
- |
- // The parent is blocked on |child_id2| and references |child_id1|. The |
- // surface corresponding to |child_id1| will not accept new CompositorFrames |
- // while the parent CompositorFrame is blocked. |
- parent_support().SubmitCompositorFrame( |
- parent_id1.local_surface_id(), |
- MakeCompositorFrame({child_id2}, {child_id1})); |
- EXPECT_TRUE(dependency_tracker().has_deadline()); |
- EXPECT_TRUE(parent_surface()->HasPendingFrame()); |
- EXPECT_FALSE(parent_surface()->HasActiveFrame()); |
- |
- // Resources will be returned immediately because |child_id1|'s surface is |
- // closed. |
- TransferableResource resource2 = |
- MakeResource(1246 /* id */, ALPHA_8 /* format */, 1357 /* filter */, |
- gfx::Size(8765, 4321)); |
- ReturnedResourceArray returned_resources2; |
- TransferableResource::ReturnResources({resource2}, &returned_resources2); |
- EXPECT_CALL(support_client_, |
- DidReceiveCompositorFrameAck(Eq(returned_resources2))); |
- child_support1().SubmitCompositorFrame( |
- child_id1.local_surface_id(), |
- MakeCompositorFrameWithResources(empty_surface_ids(), {resource2})); |
- testing::Mock::VerifyAndClearExpectations(&support_client_); |
- |
- // Advance BeginFrames to trigger a deadline. This activates the |
- // CompositorFrame submitted to the parent. |
- BeginFrameArgs args = |
- CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, 0, 1); |
- for (int i = 0; i < 3; ++i) { |
- begin_frame_source()->TestOnBeginFrame(args); |
- EXPECT_TRUE(dependency_tracker().has_deadline()); |
- } |
- begin_frame_source()->TestOnBeginFrame(args); |
- EXPECT_FALSE(dependency_tracker().has_deadline()); |
- EXPECT_FALSE(parent_surface()->HasPendingFrame()); |
- EXPECT_TRUE(parent_surface()->HasActiveFrame()); |
- |
- // Resources will be returned immediately because |child_id1|'s surface is |
- // closed forever. |
- EXPECT_CALL(support_client_, |
- DidReceiveCompositorFrameAck(Eq(returned_resources2))); |
- child_support1().SubmitCompositorFrame( |
- child_id1.local_surface_id(), |
- MakeCompositorFrameWithResources(empty_surface_ids(), {resource2})); |
- testing::Mock::VerifyAndClearExpectations(&support_client_); |
+ render_pass = RenderPass::Create(); |
+ render_pass->SetNew(2, gfx::Rect(7, 8), gfx::Rect(), gfx::Transform()); |
+ frame.render_pass_list.push_back(std::move(render_pass)); |
+ |
+ frame.metadata.device_scale_factor = 2.5f; |
+ |
+ support_->SubmitCompositorFrame(local_surface_id_, std::move(frame)); |
+ SurfaceId expected_surface_id(support_->frame_sink_id(), local_surface_id_); |
+ EXPECT_EQ(expected_surface_id, last_surface_info_.id()); |
+ EXPECT_EQ(2.5f, last_surface_info_.device_scale_factor()); |
+ EXPECT_EQ(gfx::Size(7, 8), last_surface_info_.size_in_pixels()); |
} |
+} // namespace |
+ |
+} // namespace test |
+ |
} // namespace cc |