blob: ee68a898f3c0171cbf6daacfeda81d4a6899ed45 [file] [log] [blame]
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "cc/trees/presentation_time_callback_buffer.h"
#include "base/bind.h"
#include "base/callback.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace {
std::vector<cc::PresentationTimeCallbackBuffer::MainCallback>
GenerateMainCallbacks(int num_callbacks) {
std::vector<cc::PresentationTimeCallbackBuffer::MainCallback> result;
while (num_callbacks-- > 0) {
// `PresentationTimeCallbackBuffer` isn't supposed to invoke any callbacks.
// We can check for that by passing callbacks which cause test failure.
result.push_back(base::BindOnce([](const gfx::PresentationFeedback&) {
FAIL() << "Callbacks should not be directly invoked by "
"PresentationTimeCallbackBuffer";
}));
}
return result;
}
std::vector<cc::PresentationTimeCallbackBuffer::CompositorCallback>
GenerateCompositorCallbacks(int num_callbacks) {
std::vector<cc::PresentationTimeCallbackBuffer::CompositorCallback> result;
while (num_callbacks-- > 0) {
// `PresentationTimeCallbackBuffer` isn't supposed to invoke any callbacks.
// We can check for that by passing callbacks which cause test failure.
result.push_back(base::BindOnce([](base::TimeTicks presentation_timestamp) {
FAIL() << "Callbacks should not be directly invoked by "
"PresentationTimeCallbackBuffer";
}));
}
return result;
}
constexpr uint32_t kFrameToken1 = 234;
constexpr uint32_t kFrameToken2 = 345;
constexpr uint32_t kFrameToken3 = 456;
constexpr uint32_t kFrameToken4 = 567;
} // namespace
namespace cc {
TEST(PresentationTimeCallbackBufferTest, TestNoCallbacks) {
PresentationTimeCallbackBuffer buffer;
auto result = buffer.PopPendingCallbacks(kFrameToken1, false);
EXPECT_TRUE(result.main_thread_callbacks.empty());
EXPECT_TRUE(result.compositor_thread_callbacks.empty());
}
TEST(PresentationTimeCallbackBufferTest, TestOneMainThreadCallback) {
PresentationTimeCallbackBuffer buffer;
buffer.RegisterMainThreadPresentationCallbacks(kFrameToken2,
GenerateMainCallbacks(1));
// Make sure that popping early frame tokens doesn't return irrelevant
// entries.
{
auto result = buffer.PopPendingCallbacks(kFrameToken1, false);
EXPECT_TRUE(result.main_thread_callbacks.empty());
EXPECT_TRUE(result.compositor_thread_callbacks.empty());
}
{
auto result = buffer.PopPendingCallbacks(kFrameToken2, false);
EXPECT_EQ(result.main_thread_callbacks.size(), 1ull);
EXPECT_TRUE(result.compositor_thread_callbacks.empty());
}
// Make sure that the buffer has removed the registration since the "pop".
{
auto result = buffer.PopPendingCallbacks(kFrameToken2, false);
EXPECT_TRUE(result.main_thread_callbacks.empty());
EXPECT_TRUE(result.compositor_thread_callbacks.empty());
}
}
TEST(PresentationTimeCallbackBufferTest, TestOneCompositorThreadCallback) {
PresentationTimeCallbackBuffer buffer;
buffer.RegisterCompositorPresentationCallbacks(
kFrameToken2, GenerateCompositorCallbacks(1));
// Make sure that popping early frame tokens doesn't return irrelevant
// entries.
{
auto result = buffer.PopPendingCallbacks(kFrameToken1, false);
EXPECT_TRUE(result.main_thread_callbacks.empty());
EXPECT_TRUE(result.compositor_thread_callbacks.empty());
}
{
auto result = buffer.PopPendingCallbacks(kFrameToken2, false);
EXPECT_TRUE(result.main_thread_callbacks.empty());
EXPECT_EQ(result.compositor_thread_callbacks.size(), 1ull);
}
// Make sure that the buffer has removed the registration since the "pop".
{
auto result = buffer.PopPendingCallbacks(kFrameToken2, false);
EXPECT_TRUE(result.main_thread_callbacks.empty());
EXPECT_TRUE(result.compositor_thread_callbacks.empty());
}
}
TEST(PresentationTimeCallbackBufferTest, TestMixedCallbacks) {
PresentationTimeCallbackBuffer buffer;
buffer.RegisterMainThreadPresentationCallbacks(kFrameToken2,
GenerateMainCallbacks(1));
buffer.RegisterCompositorPresentationCallbacks(
kFrameToken2, GenerateCompositorCallbacks(1));
// Make sure that popping early frame tokens doesn't return irrelevant
// entries.
{
auto result = buffer.PopPendingCallbacks(kFrameToken1, false);
EXPECT_TRUE(result.main_thread_callbacks.empty());
EXPECT_TRUE(result.compositor_thread_callbacks.empty());
}
{
auto result = buffer.PopPendingCallbacks(kFrameToken2, false);
EXPECT_EQ(result.main_thread_callbacks.size(), 1ull);
EXPECT_EQ(result.compositor_thread_callbacks.size(), 1ull);
}
// Make sure that the buffer has removed the registrations since the "pop".
{
auto result = buffer.PopPendingCallbacks(kFrameToken2, false);
EXPECT_TRUE(result.main_thread_callbacks.empty());
EXPECT_TRUE(result.compositor_thread_callbacks.empty());
}
}
TEST(PresentationTimeCallbackBufferTest, TestCallbackBatching) {
PresentationTimeCallbackBuffer buffer;
// Register one callback for frame1, two for frame2 and two for frame4.
buffer.RegisterMainThreadPresentationCallbacks(kFrameToken1,
GenerateMainCallbacks(1));
buffer.RegisterMainThreadPresentationCallbacks(kFrameToken2,
GenerateMainCallbacks(2));
buffer.RegisterMainThreadPresentationCallbacks(kFrameToken4,
GenerateMainCallbacks(2));
// Pop callbacks up to and including frame3. Should be three in total; one
// from frame1 and two from frame2.
{
auto result = buffer.PopPendingCallbacks(kFrameToken3, false);
EXPECT_EQ(result.main_thread_callbacks.size(), 3ull);
EXPECT_TRUE(result.compositor_thread_callbacks.empty());
}
}
// Tests that popping callbacks for main thread only vs. for both main and
// compositor threads works properly.
TEST(PresentationTimeCallbackBufferTest, PopMainCallbacksOnly) {
PresentationTimeCallbackBuffer buffer;
// Register callbacks for main and compositor threads of 3 frames.
buffer.RegisterMainThreadPresentationCallbacks(kFrameToken1,
GenerateMainCallbacks(1));
buffer.RegisterCompositorPresentationCallbacks(
kFrameToken1, GenerateCompositorCallbacks(1));
buffer.RegisterMainThreadPresentationCallbacks(kFrameToken2,
GenerateMainCallbacks(1));
buffer.RegisterCompositorPresentationCallbacks(
kFrameToken2, GenerateCompositorCallbacks(1));
buffer.RegisterMainThreadPresentationCallbacks(kFrameToken3,
GenerateMainCallbacks(1));
buffer.RegisterCompositorPresentationCallbacks(
kFrameToken3, GenerateCompositorCallbacks(1));
// Pop only main thread callbacks up to and including frame1. The result
// should only contain 1 main thread callback of frame1 and no compositor
// thread callback.
{
auto result = buffer.PopPendingCallbacks(kFrameToken1, true);
EXPECT_EQ(result.main_thread_callbacks.size(), 1ull);
EXPECT_TRUE(result.compositor_thread_callbacks.empty());
}
// Pop only main thread callbacks up to and including frame2. The result
// should only contain 1 main thread callback of frame2 and no compositor
// thread callback.
{
auto result = buffer.PopPendingCallbacks(kFrameToken2, true);
EXPECT_EQ(result.main_thread_callbacks.size(), 1ull);
EXPECT_TRUE(result.compositor_thread_callbacks.empty());
}
// Pop both main and compositor thread callbacks up to and including frame3.
// The result should contain 1 main thread callback of frame3 and all 3
// compositor thread callbacks of the 3 frames.
{
auto result = buffer.PopPendingCallbacks(kFrameToken3, false);
EXPECT_EQ(result.main_thread_callbacks.size(), 1ull);
EXPECT_EQ(result.compositor_thread_callbacks.size(), 3ull);
}
}
} // namespace cc