Merge "SurfaceFlinger: record layer history for TX with eAnimation" into rvc-dev
This commit is contained in:
commit
d9f4f88929
13 changed files with 166 additions and 64 deletions
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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};
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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++;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue