Merge "SurfaceFlinger: record layer history for TX with eAnimation" into rvc-dev

This commit is contained in:
TreeHugger Robot 2020-06-02 03:20:45 +00:00 committed by Android (Google) Code Review
commit d9f4f88929
13 changed files with 166 additions and 64 deletions

View file

@ -31,6 +31,7 @@
#include "SurfaceInterceptor.h"
#include "FrameTracer/FrameTracer.h"
#include "Scheduler/LayerHistory.h"
#include "TimeStats/TimeStats.h"
namespace android {
@ -399,7 +400,8 @@ void BufferQueueLayer::onFrameAvailable(const BufferItem& item) {
// Add this buffer from our internal queue tracker
{ // Autolock scope
const nsecs_t presentTime = item.mIsAutoTimestamp ? 0 : item.mTimestamp;
mFlinger->mScheduler->recordLayerHistory(this, presentTime);
mFlinger->mScheduler->recordLayerHistory(this, presentTime,
LayerHistory::LayerUpdateType::Buffer);
Mutex::Autolock lock(mQueueItemLock);
// Reset the frame number tracker when we receive the first buffer after

View file

@ -283,7 +283,8 @@ bool BufferStateLayer::setBuffer(const sp<GraphicBuffer>& buffer, const sp<Fence
desiredPresentTime = desiredPresentTime <= 0 ? 0 : desiredPresentTime;
mCurrentState.desiredPresentTime = desiredPresentTime;
mFlinger->mScheduler->recordLayerHistory(this, desiredPresentTime);
mFlinger->mScheduler->recordLayerHistory(this, desiredPresentTime,
LayerHistory::LayerUpdateType::Buffer);
addFrameEvent(acquireFence, postTime, desiredPresentTime);
return true;

View file

@ -1399,7 +1399,8 @@ bool Layer::setFrameRate(FrameRate frameRate) {
}
// Activate the layer in Scheduler's LayerHistory
mFlinger->mScheduler->recordLayerHistory(this, systemTime());
mFlinger->mScheduler->recordLayerHistory(this, systemTime(),
LayerHistory::LayerUpdateType::SetFrameRate);
mCurrentState.sequence++;
mCurrentState.frameRate = frameRate;

View file

@ -79,7 +79,8 @@ void LayerHistory::registerLayer(Layer* layer, float lowRefreshRate, float highR
mLayerInfos.emplace_back(layer, std::move(info));
}
void LayerHistory::record(Layer* layer, nsecs_t presentTime, nsecs_t now) {
void LayerHistory::record(Layer* layer, nsecs_t presentTime, nsecs_t now,
LayerUpdateType /*updateType*/) {
std::lock_guard lock(mLock);
const auto it = std::find_if(mLayerInfos.begin(), mLayerInfos.end(),

View file

@ -52,10 +52,18 @@ public:
// Sets the display size. Client is responsible for synchronization.
virtual void setDisplayArea(uint32_t displayArea) = 0;
// Sets whether a config change is pending to be applied
virtual void setConfigChangePending(bool pending) = 0;
// Represents which layer activity is recorded
enum class LayerUpdateType {
Buffer, // a new buffer queued
AnimationTX, // a new transaction with eAnimation flag set
SetFrameRate, // setFrameRate API was called
};
// Marks the layer as active, and records the given state to its history.
virtual void record(Layer*, nsecs_t presentTime, nsecs_t now) = 0;
virtual void record(Layer*, nsecs_t presentTime, nsecs_t now, LayerUpdateType updateType) = 0;
using Summary = std::vector<RefreshRateConfigs::LayerRequirement>;
@ -83,7 +91,7 @@ public:
void setConfigChangePending(bool /*pending*/) override {}
// Marks the layer as active, and records the given state to its history.
void record(Layer*, nsecs_t presentTime, nsecs_t now) override;
void record(Layer*, nsecs_t presentTime, nsecs_t now, LayerUpdateType updateType) override;
// Rebuilds sets of active/inactive layers, and accumulates stats for active layers.
android::scheduler::LayerHistory::Summary summarize(nsecs_t now) override;
@ -141,7 +149,7 @@ public:
void setConfigChangePending(bool pending) override { mConfigChangePending = pending; }
// Marks the layer as active, and records the given state to its history.
void record(Layer*, nsecs_t presentTime, nsecs_t now) override;
void record(Layer*, nsecs_t presentTime, nsecs_t now, LayerUpdateType updateType) override;
// Rebuilds sets of active/inactive layers, and accumulates stats for active layers.
android::scheduler::LayerHistory::Summary summarize(nsecs_t /*now*/) override;

View file

@ -99,7 +99,8 @@ void LayerHistoryV2::registerLayer(Layer* layer, float /*lowRefreshRate*/, float
mLayerInfos.emplace_back(layer, std::move(info));
}
void LayerHistoryV2::record(Layer* layer, nsecs_t presentTime, nsecs_t now) {
void LayerHistoryV2::record(Layer* layer, nsecs_t presentTime, nsecs_t now,
LayerUpdateType updateType) {
std::lock_guard lock(mLock);
const auto it = std::find_if(mLayerInfos.begin(), mLayerInfos.end(),
@ -107,7 +108,7 @@ void LayerHistoryV2::record(Layer* layer, nsecs_t presentTime, nsecs_t now) {
LOG_FATAL_IF(it == mLayerInfos.end(), "%s: unknown layer %p", __FUNCTION__, layer);
const auto& info = it->second;
info->setLastPresentTime(presentTime, now, mConfigChangePending);
info->setLastPresentTime(presentTime, now, updateType, mConfigChangePending);
// Activate layer if inactive.
if (const auto end = activeLayers().end(); it >= end) {

View file

@ -35,18 +35,24 @@ LayerInfoV2::LayerInfoV2(const std::string& name, nsecs_t highRefreshRatePeriod,
mLayerVote({defaultVote, 0.0f}) {}
void LayerInfoV2::setLastPresentTime(nsecs_t lastPresentTime, nsecs_t now,
bool pendingConfigChange) {
LayerUpdateType updateType, bool pendingConfigChange) {
lastPresentTime = std::max(lastPresentTime, static_cast<nsecs_t>(0));
mLastUpdatedTime = std::max(lastPresentTime, now);
FrameTimeData frameTime = {.presetTime = lastPresentTime,
.queueTime = mLastUpdatedTime,
.pendingConfigChange = pendingConfigChange};
mFrameTimes.push_back(frameTime);
if (mFrameTimes.size() > HISTORY_SIZE) {
mFrameTimes.pop_front();
switch (updateType) {
case LayerUpdateType::AnimationTX:
mLastAnimationTime = std::max(lastPresentTime, now);
break;
case LayerUpdateType::SetFrameRate:
case LayerUpdateType::Buffer:
FrameTimeData frameTime = {.presetTime = lastPresentTime,
.queueTime = mLastUpdatedTime,
.pendingConfigChange = pendingConfigChange};
mFrameTimes.push_back(frameTime);
if (mFrameTimes.size() > HISTORY_SIZE) {
mFrameTimes.pop_front();
}
break;
}
}
@ -81,6 +87,10 @@ bool LayerInfoV2::isFrequent(nsecs_t now) const {
return (1e9f * (numFrames - 1)) / totalTime >= MIN_FPS_FOR_FREQUENT_LAYER;
}
bool LayerInfoV2::isAnimating(nsecs_t now) const {
return mLastAnimationTime >= getActiveLayerThreshold(now);
}
bool LayerInfoV2::hasEnoughDataForHeuristic() const {
// The layer had to publish at least HISTORY_SIZE or HISTORY_TIME of updates
if (mFrameTimes.size() < 2) {
@ -190,6 +200,11 @@ std::pair<LayerHistory::LayerVoteType, float> LayerInfoV2::getRefreshRate(nsecs_
return {mLayerVote.type, mLayerVote.fps};
}
if (isAnimating(now)) {
ALOGV("%s is animating", mName.c_str());
return {LayerHistory::LayerVoteType::Max, 0};
}
if (!isFrequent(now)) {
ALOGV("%s is infrequent", mName.c_str());
return {LayerHistory::LayerVoteType::Min, 0};

View file

@ -43,6 +43,8 @@ constexpr nsecs_t getActiveLayerThreshold(nsecs_t now) {
// Stores history of present times and refresh rates for a layer.
class LayerInfoV2 {
using LayerUpdateType = LayerHistory::LayerUpdateType;
// Layer is considered frequent if the earliest value in the window of most recent present times
// is within a threshold. If a layer is infrequent, its average refresh rate is disregarded in
// favor of a low refresh rate.
@ -63,7 +65,8 @@ public:
// Records the last requested present time. It also stores information about when
// the layer was last updated. If the present time is farther in the future than the
// updated time, the updated time is the present time.
void setLastPresentTime(nsecs_t lastPresentTime, nsecs_t now, bool pendingConfigChange);
void setLastPresentTime(nsecs_t lastPresentTime, nsecs_t now, LayerUpdateType updateType,
bool pendingConfigChange);
// Sets an explicit layer vote. This usually comes directly from the application via
// ANativeWindow_setFrameRate API
@ -107,6 +110,7 @@ private:
};
bool isFrequent(nsecs_t now) const;
bool isAnimating(nsecs_t now) const;
bool hasEnoughDataForHeuristic() const;
std::optional<float> calculateRefreshRateIfPossible();
std::pair<nsecs_t, bool> calculateAverageFrameTime() const;
@ -121,6 +125,8 @@ private:
nsecs_t mLastUpdatedTime = 0;
nsecs_t mLastAnimationTime = 0;
float mLastReportedRefreshRate = 0.0f;
// Holds information about the layer vote

View file

@ -417,9 +417,10 @@ void Scheduler::registerLayer(Layer* layer) {
}
}
void Scheduler::recordLayerHistory(Layer* layer, nsecs_t presentTime) {
void Scheduler::recordLayerHistory(Layer* layer, nsecs_t presentTime,
LayerHistory::LayerUpdateType updateType) {
if (mLayerHistory) {
mLayerHistory->record(layer, presentTime, systemTime());
mLayerHistory->record(layer, presentTime, systemTime(), updateType);
}
}

View file

@ -39,6 +39,7 @@
namespace android {
using namespace std::chrono_literals;
using scheduler::LayerHistory;
class DispSync;
class FenceTime;
@ -118,7 +119,7 @@ public:
// Layers are registered on creation, and unregistered when the weak reference expires.
void registerLayer(Layer*);
void recordLayerHistory(Layer*, nsecs_t presentTime);
void recordLayerHistory(Layer*, nsecs_t presentTime, LayerHistory::LayerUpdateType updateType);
void setConfigChangePending(bool pending);
// Detects content using layer history, and selects a matching refresh rate.
@ -211,7 +212,7 @@ private:
std::unique_ptr<EventControlThread> mEventControlThread;
// Used to choose refresh rate if content detection is enabled.
std::unique_ptr<scheduler::LayerHistory> mLayerHistory;
std::unique_ptr<LayerHistory> mLayerHistory;
// Whether to use idle timer callbacks that support the kernel timer.
const bool mSupportKernelTimer;
@ -236,7 +237,7 @@ private:
TimerState displayPowerTimer = TimerState::Expired;
std::optional<HwcConfigIndexType> configId;
scheduler::LayerHistory::Summary contentRequirements;
LayerHistory::Summary contentRequirements;
bool isDisplayPowerStateNormal = true;
} mFeatures GUARDED_BY(mFeatureStateLock);

View file

@ -115,6 +115,7 @@
#include "Scheduler/DispSyncSource.h"
#include "Scheduler/EventControlThread.h"
#include "Scheduler/EventThread.h"
#include "Scheduler/LayerHistory.h"
#include "Scheduler/MessageQueue.h"
#include "Scheduler/PhaseOffsets.h"
#include "Scheduler/Scheduler.h"
@ -3401,6 +3402,12 @@ void SurfaceFlinger::applyTransactionState(
for (const ComposerState& state : states) {
clientStateFlags |= setClientStateLocked(state, desiredPresentTime, postTime, privileged,
listenerCallbacksWithSurfaces);
if ((flags & eAnimation) && state.state.surface) {
if (const auto layer = fromHandleLocked(state.state.surface).promote(); layer) {
mScheduler->recordLayerHistory(layer.get(), desiredPresentTime,
LayerHistory::LayerUpdateType::AnimationTX);
}
}
}
for (const auto& listenerCallback : listenerCallbacksWithSurfaces) {

View file

@ -96,14 +96,14 @@ TEST_F(LayerHistoryTest, oneLayer) {
// no layers are returned if active layers have insufficient history.
for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE - 1; i++) {
history().record(layer.get(), 0, mTime);
history().record(layer.get(), 0, mTime, LayerHistory::LayerUpdateType::Buffer);
ASSERT_TRUE(history().summarize(mTime).empty());
EXPECT_EQ(1, activeLayerCount());
}
// High FPS is returned once enough history has been recorded.
for (int i = 0; i < 10; i++) {
history().record(layer.get(), 0, mTime);
history().record(layer.get(), 0, mTime, LayerHistory::LayerUpdateType::Buffer);
ASSERT_EQ(1, history().summarize(mTime).size());
EXPECT_FLOAT_EQ(HI_FPS, history().summarize(mTime)[0].desiredRefreshRate);
EXPECT_EQ(1, activeLayerCount());
@ -121,7 +121,7 @@ TEST_F(LayerHistoryTest, explicitTimestamp) {
nsecs_t time = mTime;
for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
history().record(layer.get(), time, time);
history().record(layer.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
time += LO_FPS_PERIOD;
}
@ -155,7 +155,7 @@ TEST_F(LayerHistoryTest, multipleLayers) {
// layer1 is active but infrequent.
for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
history().record(layer1.get(), time, time);
history().record(layer1.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
time += MAX_FREQUENT_LAYER_PERIOD_NS.count();
}
@ -166,12 +166,12 @@ TEST_F(LayerHistoryTest, multipleLayers) {
// layer2 is frequent and has high refresh rate.
for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
history().record(layer2.get(), time, time);
history().record(layer2.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
time += HI_FPS_PERIOD;
}
// layer1 is still active but infrequent.
history().record(layer1.get(), time, time);
history().record(layer1.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
ASSERT_EQ(2, history().summarize(time).size());
EXPECT_FLOAT_EQ(LO_FPS, history().summarize(time)[0].desiredRefreshRate);
@ -182,7 +182,7 @@ TEST_F(LayerHistoryTest, multipleLayers) {
// layer1 is no longer active.
// layer2 is frequent and has low refresh rate.
for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
history().record(layer2.get(), time, time);
history().record(layer2.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
time += LO_FPS_PERIOD;
}
@ -196,10 +196,10 @@ TEST_F(LayerHistoryTest, multipleLayers) {
constexpr int RATIO = LO_FPS_PERIOD / HI_FPS_PERIOD;
for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE - 1; i++) {
if (i % RATIO == 0) {
history().record(layer2.get(), time, time);
history().record(layer2.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
}
history().record(layer3.get(), time, time);
history().record(layer3.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
time += HI_FPS_PERIOD;
}
@ -209,7 +209,7 @@ TEST_F(LayerHistoryTest, multipleLayers) {
EXPECT_EQ(2, frequentLayerCount(time));
// layer3 becomes recently active.
history().record(layer3.get(), time, time);
history().record(layer3.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
ASSERT_EQ(2, history().summarize(time).size());
EXPECT_FLOAT_EQ(LO_FPS, history().summarize(time)[0].desiredRefreshRate);
EXPECT_FLOAT_EQ(HI_FPS, history().summarize(time)[1].desiredRefreshRate);
@ -228,7 +228,7 @@ TEST_F(LayerHistoryTest, multipleLayers) {
// layer2 still has low refresh rate.
// layer3 becomes inactive.
for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
history().record(layer2.get(), time, time);
history().record(layer2.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
time += LO_FPS_PERIOD;
}
@ -246,7 +246,7 @@ TEST_F(LayerHistoryTest, multipleLayers) {
// layer3 becomes active and has high refresh rate.
for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
history().record(layer3.get(), time, time);
history().record(layer3.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
time += HI_FPS_PERIOD;
}

View file

@ -17,6 +17,7 @@
#undef LOG_TAG
#define LOG_TAG "LayerHistoryTestV2"
#include <Layer.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <log/log.h>
@ -60,6 +61,13 @@ protected:
[now](const auto& pair) { return pair.second->isFrequent(now); });
}
auto animatingLayerCount(nsecs_t now) const NO_THREAD_SAFETY_ANALYSIS {
const auto& infos = history().mLayerInfos;
return std::count_if(infos.begin(),
infos.begin() + static_cast<long>(history().mActiveLayersEnd),
[now](const auto& pair) { return pair.second->isAnimating(now); });
}
void setLayerInfoVote(Layer* layer,
LayerHistory::LayerVoteType vote) NO_THREAD_SAFETY_ANALYSIS {
for (auto& [weak, info] : history().mLayerInfos) {
@ -109,7 +117,7 @@ TEST_F(LayerHistoryTestV2, oneLayer) {
// Max returned if active layers have insufficient history.
for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE - 1; i++) {
history().record(layer.get(), 0, time);
history().record(layer.get(), 0, time, LayerHistory::LayerUpdateType::Buffer);
ASSERT_EQ(1, history().summarize(time).size());
EXPECT_EQ(LayerHistory::LayerVoteType::Max, history().summarize(time)[0].vote);
EXPECT_EQ(1, activeLayerCount());
@ -117,7 +125,7 @@ TEST_F(LayerHistoryTestV2, oneLayer) {
// Max is returned since we have enough history but there is no timestamp votes.
for (int i = 0; i < 10; i++) {
history().record(layer.get(), 0, time);
history().record(layer.get(), 0, time, LayerHistory::LayerUpdateType::Buffer);
ASSERT_EQ(1, history().summarize(time).size());
EXPECT_EQ(LayerHistory::LayerVoteType::Max, history().summarize(time)[0].vote);
EXPECT_EQ(1, activeLayerCount());
@ -134,7 +142,7 @@ TEST_F(LayerHistoryTestV2, oneInvisibleLayer) {
nsecs_t time = systemTime();
history().record(layer.get(), 0, time);
history().record(layer.get(), 0, time, LayerHistory::LayerUpdateType::Buffer);
auto summary = history().summarize(time);
ASSERT_EQ(1, history().summarize(time).size());
// Layer is still considered inactive so we expect to get Min
@ -158,7 +166,7 @@ TEST_F(LayerHistoryTestV2, explicitTimestamp) {
nsecs_t time = systemTime();
for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
history().record(layer.get(), time, time);
history().record(layer.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
time += LO_FPS_PERIOD;
}
@ -181,7 +189,7 @@ TEST_F(LayerHistoryTestV2, oneLayerNoVote) {
nsecs_t time = systemTime();
for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
history().record(layer.get(), time, time);
history().record(layer.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
time += HI_FPS_PERIOD;
}
@ -208,7 +216,7 @@ TEST_F(LayerHistoryTestV2, oneLayerMinVote) {
nsecs_t time = systemTime();
for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
history().record(layer.get(), time, time);
history().record(layer.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
time += HI_FPS_PERIOD;
}
@ -236,7 +244,7 @@ TEST_F(LayerHistoryTestV2, oneLayerMaxVote) {
nsecs_t time = systemTime();
for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
history().record(layer.get(), time, time);
history().record(layer.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
time += LO_FPS_PERIOD;
}
@ -264,7 +272,7 @@ TEST_F(LayerHistoryTestV2, oneLayerExplicitVote) {
nsecs_t time = systemTime();
for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
history().record(layer.get(), time, time);
history().record(layer.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
time += HI_FPS_PERIOD;
}
@ -296,7 +304,7 @@ TEST_F(LayerHistoryTestV2, oneLayerExplicitExactVote) {
nsecs_t time = systemTime();
for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
history().record(layer.get(), time, time);
history().record(layer.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
time += HI_FPS_PERIOD;
}
@ -340,7 +348,7 @@ TEST_F(LayerHistoryTestV2, multipleLayers) {
// layer1 is active but infrequent.
for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
history().record(layer1.get(), time, time);
history().record(layer1.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
time += MAX_FREQUENT_LAYER_PERIOD_NS.count();
}
@ -351,12 +359,12 @@ TEST_F(LayerHistoryTestV2, multipleLayers) {
// layer2 is frequent and has high refresh rate.
for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
history().record(layer2.get(), time, time);
history().record(layer2.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
time += HI_FPS_PERIOD;
}
// layer1 is still active but infrequent.
history().record(layer1.get(), time, time);
history().record(layer1.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
ASSERT_EQ(2, history().summarize(time).size());
EXPECT_EQ(LayerHistory::LayerVoteType::Min, history().summarize(time)[0].vote);
@ -368,7 +376,7 @@ TEST_F(LayerHistoryTestV2, multipleLayers) {
// layer1 is no longer active.
// layer2 is frequent and has low refresh rate.
for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
history().record(layer2.get(), time, time);
history().record(layer2.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
time += LO_FPS_PERIOD;
}
@ -383,10 +391,10 @@ TEST_F(LayerHistoryTestV2, multipleLayers) {
constexpr int RATIO = LO_FPS_PERIOD / HI_FPS_PERIOD;
for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE - 1; i++) {
if (i % RATIO == 0) {
history().record(layer2.get(), time, time);
history().record(layer2.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
}
history().record(layer3.get(), time, time);
history().record(layer3.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
time += HI_FPS_PERIOD;
}
@ -398,7 +406,7 @@ TEST_F(LayerHistoryTestV2, multipleLayers) {
EXPECT_EQ(2, frequentLayerCount(time));
// layer3 becomes recently active.
history().record(layer3.get(), time, time);
history().record(layer3.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
ASSERT_EQ(2, history().summarize(time).size());
EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, history().summarize(time)[0].vote);
EXPECT_FLOAT_EQ(LO_FPS, history().summarize(time)[0].desiredRefreshRate);
@ -422,7 +430,7 @@ TEST_F(LayerHistoryTestV2, multipleLayers) {
// layer2 still has low refresh rate.
// layer3 becomes inactive.
for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
history().record(layer2.get(), time, time);
history().record(layer2.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
time += LO_FPS_PERIOD;
}
@ -441,7 +449,7 @@ TEST_F(LayerHistoryTestV2, multipleLayers) {
// layer3 becomes active and has high refresh rate.
for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
history().record(layer3.get(), time, time);
history().record(layer3.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
time += HI_FPS_PERIOD;
}
@ -470,7 +478,7 @@ TEST_F(LayerHistoryTestV2, inactiveLayers) {
// the very first updates makes the layer frequent
for (int i = 0; i < FREQUENT_LAYER_WINDOW_SIZE - 1; i++) {
history().record(layer.get(), time, time);
history().record(layer.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
time += MAX_FREQUENT_LAYER_PERIOD_NS.count();
EXPECT_EQ(1, layerCount());
@ -481,7 +489,7 @@ TEST_F(LayerHistoryTestV2, inactiveLayers) {
}
// the next update with the MAX_FREQUENT_LAYER_PERIOD_NS will get us to infrequent
history().record(layer.get(), time, time);
history().record(layer.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
time += MAX_FREQUENT_LAYER_PERIOD_NS.count();
EXPECT_EQ(1, layerCount());
@ -495,7 +503,7 @@ TEST_F(LayerHistoryTestV2, inactiveLayers) {
// Now event if we post a quick few frame we should stay infrequent
for (int i = 0; i < FREQUENT_LAYER_WINDOW_SIZE - 1; i++) {
history().record(layer.get(), time, time);
history().record(layer.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
time += HI_FPS_PERIOD;
EXPECT_EQ(1, layerCount());
@ -506,7 +514,7 @@ TEST_F(LayerHistoryTestV2, inactiveLayers) {
}
// More quick frames will get us to frequent again
history().record(layer.get(), time, time);
history().record(layer.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
time += HI_FPS_PERIOD;
EXPECT_EQ(1, layerCount());
@ -533,8 +541,9 @@ TEST_F(LayerHistoryTestV2, invisibleExplicitLayer) {
nsecs_t time = systemTime();
// Post a buffer to the layers to make them active
history().record(explicitVisiblelayer.get(), time, time);
history().record(explicitInvisiblelayer.get(), time, time);
history().record(explicitVisiblelayer.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
history().record(explicitInvisiblelayer.get(), time, time,
LayerHistory::LayerUpdateType::Buffer);
EXPECT_EQ(2, layerCount());
ASSERT_EQ(1, history().summarize(time).size());
@ -545,6 +554,52 @@ TEST_F(LayerHistoryTestV2, invisibleExplicitLayer) {
EXPECT_EQ(2, frequentLayerCount(time));
}
TEST_F(LayerHistoryTestV2, infrequentAnimatingLayer) {
auto layer = createLayer();
EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
EXPECT_CALL(*layer, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate()));
nsecs_t time = systemTime();
EXPECT_EQ(1, layerCount());
EXPECT_EQ(0, activeLayerCount());
EXPECT_EQ(0, frequentLayerCount(time));
EXPECT_EQ(0, animatingLayerCount(time));
// layer is active but infrequent.
for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
history().record(layer.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
time += MAX_FREQUENT_LAYER_PERIOD_NS.count();
}
ASSERT_EQ(1, history().summarize(time).size());
EXPECT_EQ(LayerHistory::LayerVoteType::Min, history().summarize(time)[0].vote);
EXPECT_EQ(1, activeLayerCount());
EXPECT_EQ(0, frequentLayerCount(time));
EXPECT_EQ(0, animatingLayerCount(time));
// another update with the same cadence keep in infrequent
history().record(layer.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
time += MAX_FREQUENT_LAYER_PERIOD_NS.count();
ASSERT_EQ(1, history().summarize(time).size());
EXPECT_EQ(LayerHistory::LayerVoteType::Min, history().summarize(time)[0].vote);
EXPECT_EQ(1, activeLayerCount());
EXPECT_EQ(0, frequentLayerCount(time));
EXPECT_EQ(0, animatingLayerCount(time));
// an update as animation will immediately vote for Max
history().record(layer.get(), time, time, LayerHistory::LayerUpdateType::AnimationTX);
time += MAX_FREQUENT_LAYER_PERIOD_NS.count();
ASSERT_EQ(1, history().summarize(time).size());
EXPECT_EQ(LayerHistory::LayerVoteType::Max, history().summarize(time)[0].vote);
EXPECT_EQ(1, activeLayerCount());
EXPECT_EQ(0, frequentLayerCount(time));
EXPECT_EQ(1, animatingLayerCount(time));
}
class LayerHistoryTestV2Parameterized
: public LayerHistoryTestV2,
public testing::WithParamInterface<std::chrono::nanoseconds> {};
@ -565,8 +620,10 @@ TEST_P(LayerHistoryTestV2Parameterized, HeuristicLayerWithInfrequentLayer) {
const nsecs_t startTime = systemTime();
const std::chrono::nanoseconds heuristicUpdateDelta = 41'666'667ns;
history().record(heuristicLayer.get(), startTime, startTime);
history().record(infrequentLayer.get(), startTime, startTime);
history().record(heuristicLayer.get(), startTime, startTime,
LayerHistory::LayerUpdateType::Buffer);
history().record(infrequentLayer.get(), startTime, startTime,
LayerHistory::LayerUpdateType::Buffer);
nsecs_t time = startTime;
nsecs_t lastInfrequentUpdate = startTime;
@ -574,13 +631,14 @@ TEST_P(LayerHistoryTestV2Parameterized, HeuristicLayerWithInfrequentLayer) {
int infrequentLayerUpdates = 0;
while (infrequentLayerUpdates <= totalInfrequentLayerUpdates) {
time += heuristicUpdateDelta.count();
history().record(heuristicLayer.get(), time, time);
history().record(heuristicLayer.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
if (time - lastInfrequentUpdate >= infrequentUpdateDelta.count()) {
ALOGI("submitting infrequent frame [%d/%d]", infrequentLayerUpdates,
totalInfrequentLayerUpdates);
lastInfrequentUpdate = time;
history().record(infrequentLayer.get(), time, time);
history().record(infrequentLayer.get(), time, time,
LayerHistory::LayerUpdateType::Buffer);
infrequentLayerUpdates++;
}