Merge "Update libgui to use android::base properties instead of cutils" into rvc-dev
diff --git a/cmds/servicemanager/ServiceManager.cpp b/cmds/servicemanager/ServiceManager.cpp
index cbbea12..1f9892a 100644
--- a/cmds/servicemanager/ServiceManager.cpp
+++ b/cmds/servicemanager/ServiceManager.cpp
@@ -49,14 +49,28 @@
const std::string iface = name.substr(lastDot+1, firstSlash-lastDot-1);
const std::string instance = name.substr(firstSlash+1);
- for (const auto& manifest : {
- vintf::VintfObject::GetDeviceHalManifest(),
- vintf::VintfObject::GetFrameworkHalManifest()
+ struct ManifestWithDescription {
+ std::shared_ptr<const vintf::HalManifest> manifest;
+ const char* description;
+ };
+ for (const ManifestWithDescription& mwd : {
+ ManifestWithDescription{ vintf::VintfObject::GetDeviceHalManifest(), "device" },
+ ManifestWithDescription{ vintf::VintfObject::GetFrameworkHalManifest(), "framework" },
}) {
- if (manifest != nullptr && manifest->hasAidlInstance(package, iface, instance)) {
+ if (mwd.manifest == nullptr) {
+ LOG(ERROR) << "NULL VINTF MANIFEST!: " << mwd.description;
+ // note, we explicitly do not retry here, so that we can detect VINTF
+ // or other bugs (b/151696835)
+ continue;
+ }
+ if (mwd.manifest->hasAidlInstance(package, iface, instance)) {
+ LOG(INFO) << "Found " << name << " in " << mwd.description << " VINTF manifest.";
return true;
}
}
+
+ // Although it is tested, explicitly rebuilding qualified name, in case it
+ // becomes something unexpected.
LOG(ERROR) << "Could not find " << package << "." << iface << "/" << instance
<< " in the VINTF manifest.";
return false;
@@ -72,13 +86,20 @@
#endif // !VENDORSERVICEMANAGER
ServiceManager::ServiceManager(std::unique_ptr<Access>&& access) : mAccess(std::move(access)) {
-#ifndef VENDORSERVICEMANAGER
- // can process these at any times, don't want to delay first VINTF client
- std::thread([] {
- vintf::VintfObject::GetDeviceHalManifest();
- vintf::VintfObject::GetFrameworkHalManifest();
- }).detach();
-#endif // !VENDORSERVICEMANAGER
+// TODO(b/151696835): reenable performance hack when we solve bug, since with
+// this hack and other fixes, it is unlikely we will see even an ephemeral
+// failure when the manifest parse fails. The goal is that the manifest will
+// be read incorrectly and cause the process trying to register a HAL to
+// fail. If this is in fact an early boot kernel contention issue, then we
+// will get no failure, and by its absence, be signalled to invest more
+// effort in re-adding this performance hack.
+// #ifndef VENDORSERVICEMANAGER
+// // can process these at any times, don't want to delay first VINTF client
+// std::thread([] {
+// vintf::VintfObject::GetDeviceHalManifest();
+// vintf::VintfObject::GetFrameworkHalManifest();
+// }).detach();
+// #endif // !VENDORSERVICEMANAGER
}
ServiceManager::~ServiceManager() {
// this should only happen in tests
@@ -547,4 +568,4 @@
return Status::ok();
}
-} // namespace android
\ No newline at end of file
+} // namespace android
diff --git a/include/ui/FatVector.h b/include/ui/FatVector.h
new file mode 120000
index 0000000..c2047c0
--- /dev/null
+++ b/include/ui/FatVector.h
@@ -0,0 +1 @@
+../../libs/ui/include/ui/FatVector.h
\ No newline at end of file
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index 6fd53cf..2a27a9a 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -931,8 +931,11 @@
}
virtual status_t setDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken,
- int32_t defaultConfig, float minRefreshRate,
- float maxRefreshRate) {
+ int32_t defaultConfig,
+ float primaryRefreshRateMin,
+ float primaryRefreshRateMax,
+ float appRequestRefreshRateMin,
+ float appRequestRefreshRateMax) {
Parcel data, reply;
status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
if (result != NO_ERROR) {
@@ -949,14 +952,26 @@
ALOGE("setDesiredDisplayConfigSpecs failed to write defaultConfig: %d", result);
return result;
}
- result = data.writeFloat(minRefreshRate);
+ result = data.writeFloat(primaryRefreshRateMin);
if (result != NO_ERROR) {
- ALOGE("setDesiredDisplayConfigSpecs failed to write minRefreshRate: %d", result);
+ ALOGE("setDesiredDisplayConfigSpecs failed to write primaryRefreshRateMin: %d", result);
return result;
}
- result = data.writeFloat(maxRefreshRate);
+ result = data.writeFloat(primaryRefreshRateMax);
if (result != NO_ERROR) {
- ALOGE("setDesiredDisplayConfigSpecs failed to write maxRefreshRate: %d", result);
+ ALOGE("setDesiredDisplayConfigSpecs failed to write primaryRefreshRateMax: %d", result);
+ return result;
+ }
+ result = data.writeFloat(appRequestRefreshRateMin);
+ if (result != NO_ERROR) {
+ ALOGE("setDesiredDisplayConfigSpecs failed to write appRequestRefreshRateMin: %d",
+ result);
+ return result;
+ }
+ result = data.writeFloat(appRequestRefreshRateMax);
+ if (result != NO_ERROR) {
+ ALOGE("setDesiredDisplayConfigSpecs failed to write appRequestRefreshRateMax: %d",
+ result);
return result;
}
@@ -971,9 +986,14 @@
virtual status_t getDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken,
int32_t* outDefaultConfig,
- float* outMinRefreshRate,
- float* outMaxRefreshRate) {
- if (!outDefaultConfig || !outMinRefreshRate || !outMaxRefreshRate) return BAD_VALUE;
+ float* outPrimaryRefreshRateMin,
+ float* outPrimaryRefreshRateMax,
+ float* outAppRequestRefreshRateMin,
+ float* outAppRequestRefreshRateMax) {
+ if (!outDefaultConfig || !outPrimaryRefreshRateMin || !outPrimaryRefreshRateMax ||
+ !outAppRequestRefreshRateMin || !outAppRequestRefreshRateMax) {
+ return BAD_VALUE;
+ }
Parcel data, reply;
status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
if (result != NO_ERROR) {
@@ -996,14 +1016,26 @@
ALOGE("getDesiredDisplayConfigSpecs failed to read defaultConfig: %d", result);
return result;
}
- result = reply.readFloat(outMinRefreshRate);
+ result = reply.readFloat(outPrimaryRefreshRateMin);
if (result != NO_ERROR) {
- ALOGE("getDesiredDisplayConfigSpecs failed to read minRefreshRate: %d", result);
+ ALOGE("getDesiredDisplayConfigSpecs failed to read primaryRefreshRateMin: %d", result);
return result;
}
- result = reply.readFloat(outMaxRefreshRate);
+ result = reply.readFloat(outPrimaryRefreshRateMax);
if (result != NO_ERROR) {
- ALOGE("getDesiredDisplayConfigSpecs failed to read maxRefreshRate: %d", result);
+ ALOGE("getDesiredDisplayConfigSpecs failed to read primaryRefreshRateMax: %d", result);
+ return result;
+ }
+ result = reply.readFloat(outAppRequestRefreshRateMin);
+ if (result != NO_ERROR) {
+ ALOGE("getDesiredDisplayConfigSpecs failed to read appRequestRefreshRateMin: %d",
+ result);
+ return result;
+ }
+ result = reply.readFloat(outAppRequestRefreshRateMax);
+ if (result != NO_ERROR) {
+ ALOGE("getDesiredDisplayConfigSpecs failed to read appRequestRefreshRateMax: %d",
+ result);
return result;
}
return reply.readInt32();
@@ -1835,20 +1867,38 @@
ALOGE("setDesiredDisplayConfigSpecs: failed to read defaultConfig: %d", result);
return result;
}
- float minRefreshRate;
- result = data.readFloat(&minRefreshRate);
+ float primaryRefreshRateMin;
+ result = data.readFloat(&primaryRefreshRateMin);
if (result != NO_ERROR) {
- ALOGE("setDesiredDisplayConfigSpecs: failed to read minRefreshRate: %d", result);
+ ALOGE("setDesiredDisplayConfigSpecs: failed to read primaryRefreshRateMin: %d",
+ result);
return result;
}
- float maxRefreshRate;
- result = data.readFloat(&maxRefreshRate);
+ float primaryRefreshRateMax;
+ result = data.readFloat(&primaryRefreshRateMax);
if (result != NO_ERROR) {
- ALOGE("setDesiredDisplayConfigSpecs: failed to read maxRefreshRate: %d", result);
+ ALOGE("setDesiredDisplayConfigSpecs: failed to read primaryRefreshRateMax: %d",
+ result);
return result;
}
- result = setDesiredDisplayConfigSpecs(displayToken, defaultConfig, minRefreshRate,
- maxRefreshRate);
+ float appRequestRefreshRateMin;
+ result = data.readFloat(&appRequestRefreshRateMin);
+ if (result != NO_ERROR) {
+ ALOGE("setDesiredDisplayConfigSpecs: failed to read appRequestRefreshRateMin: %d",
+ result);
+ return result;
+ }
+ float appRequestRefreshRateMax;
+ result = data.readFloat(&appRequestRefreshRateMax);
+ if (result != NO_ERROR) {
+ ALOGE("setDesiredDisplayConfigSpecs: failed to read appRequestRefreshRateMax: %d",
+ result);
+ return result;
+ }
+ result =
+ setDesiredDisplayConfigSpecs(displayToken, defaultConfig, primaryRefreshRateMin,
+ primaryRefreshRateMax, appRequestRefreshRateMin,
+ appRequestRefreshRateMax);
if (result != NO_ERROR) {
ALOGE("setDesiredDisplayConfigSpecs: failed to call setDesiredDisplayConfigSpecs: "
"%d",
@@ -1862,11 +1912,16 @@
CHECK_INTERFACE(ISurfaceComposer, data, reply);
sp<IBinder> displayToken = data.readStrongBinder();
int32_t defaultConfig;
- float minRefreshRate;
- float maxRefreshRate;
+ float primaryRefreshRateMin;
+ float primaryRefreshRateMax;
+ float appRequestRefreshRateMin;
+ float appRequestRefreshRateMax;
- status_t result = getDesiredDisplayConfigSpecs(displayToken, &defaultConfig,
- &minRefreshRate, &maxRefreshRate);
+ status_t result =
+ getDesiredDisplayConfigSpecs(displayToken, &defaultConfig,
+ &primaryRefreshRateMin, &primaryRefreshRateMax,
+ &appRequestRefreshRateMin,
+ &appRequestRefreshRateMax);
if (result != NO_ERROR) {
ALOGE("getDesiredDisplayConfigSpecs: failed to get getDesiredDisplayConfigSpecs: "
"%d",
@@ -1879,14 +1934,28 @@
ALOGE("getDesiredDisplayConfigSpecs: failed to write defaultConfig: %d", result);
return result;
}
- result = reply->writeFloat(minRefreshRate);
+ result = reply->writeFloat(primaryRefreshRateMin);
if (result != NO_ERROR) {
- ALOGE("getDesiredDisplayConfigSpecs: failed to write minRefreshRate: %d", result);
+ ALOGE("getDesiredDisplayConfigSpecs: failed to write primaryRefreshRateMin: %d",
+ result);
return result;
}
- result = reply->writeFloat(maxRefreshRate);
+ result = reply->writeFloat(primaryRefreshRateMax);
if (result != NO_ERROR) {
- ALOGE("getDesiredDisplayConfigSpecs: failed to write maxRefreshRate: %d", result);
+ ALOGE("getDesiredDisplayConfigSpecs: failed to write primaryRefreshRateMax: %d",
+ result);
+ return result;
+ }
+ result = reply->writeFloat(appRequestRefreshRateMin);
+ if (result != NO_ERROR) {
+ ALOGE("getDesiredDisplayConfigSpecs: failed to write appRequestRefreshRateMin: %d",
+ result);
+ return result;
+ }
+ result = reply->writeFloat(appRequestRefreshRateMax);
+ if (result != NO_ERROR) {
+ ALOGE("getDesiredDisplayConfigSpecs: failed to write appRequestRefreshRateMax: %d",
+ result);
return result;
}
reply->writeInt32(result);
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index d9cbeb7..a52f298 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -1698,22 +1698,26 @@
status_t SurfaceComposerClient::setDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken,
int32_t defaultConfig,
- float minRefreshRate,
- float maxRefreshRate) {
- return ComposerService::getComposerService()->setDesiredDisplayConfigSpecs(displayToken,
- defaultConfig,
- minRefreshRate,
- maxRefreshRate);
+ float primaryRefreshRateMin,
+ float primaryRefreshRateMax,
+ float appRequestRefreshRateMin,
+ float appRequestRefreshRateMax) {
+ return ComposerService::getComposerService()
+ ->setDesiredDisplayConfigSpecs(displayToken, defaultConfig, primaryRefreshRateMin,
+ primaryRefreshRateMax, appRequestRefreshRateMin,
+ appRequestRefreshRateMax);
}
status_t SurfaceComposerClient::getDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken,
int32_t* outDefaultConfig,
- float* outMinRefreshRate,
- float* outMaxRefreshRate) {
- return ComposerService::getComposerService()->getDesiredDisplayConfigSpecs(displayToken,
- outDefaultConfig,
- outMinRefreshRate,
- outMaxRefreshRate);
+ float* outPrimaryRefreshRateMin,
+ float* outPrimaryRefreshRateMax,
+ float* outAppRequestRefreshRateMin,
+ float* outAppRequestRefreshRateMax) {
+ return ComposerService::getComposerService()
+ ->getDesiredDisplayConfigSpecs(displayToken, outDefaultConfig, outPrimaryRefreshRateMin,
+ outPrimaryRefreshRateMax, outAppRequestRefreshRateMin,
+ outAppRequestRefreshRateMax);
}
status_t SurfaceComposerClient::getDisplayColorModes(const sp<IBinder>& display,
diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index b4a3fbe..0d33b3f 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -426,19 +426,36 @@
*/
virtual status_t removeRegionSamplingListener(const sp<IRegionSamplingListener>& listener) = 0;
- /*
- * Sets the refresh rate boundaries for display configuration.
- * For all other parameters, default configuration is used. The index for the default is
- * corresponding to the configs returned from getDisplayConfigs().
+ /* Sets the refresh rate boundaries for the display.
+ *
+ * The primary refresh rate range represents display manager's general guidance on the display
+ * configs we'll consider when switching refresh rates. Unless we get an explicit signal from an
+ * app, we should stay within this range.
+ *
+ * The app request refresh rate range allows us to consider more display configs when switching
+ * refresh rates. Although we should generally stay within the primary range, specific
+ * considerations, such as layer frame rate settings specified via the setFrameRate() api, may
+ * cause us to go outside the primary range. We never go outside the app request range. The app
+ * request range will be greater than or equal to the primary refresh rate range, never smaller.
+ *
+ * defaultConfig is used to narrow the list of display configs SurfaceFlinger will consider
+ * switching between. Only configs with a config group and resolution matching defaultConfig
+ * will be considered for switching. The defaultConfig index corresponds to the list of configs
+ * returned from getDisplayConfigs().
*/
virtual status_t setDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken,
- int32_t defaultConfig, float minRefreshRate,
- float maxRefreshRate) = 0;
+ int32_t defaultConfig,
+ float primaryRefreshRateMin,
+ float primaryRefreshRateMax,
+ float appRequestRefreshRateMin,
+ float appRequestRefreshRateMax) = 0;
virtual status_t getDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken,
int32_t* outDefaultConfig,
- float* outMinRefreshRate,
- float* outMaxRefreshRate) = 0;
+ float* outPrimaryRefreshRateMin,
+ float* outPrimaryRefreshRateMax,
+ float* outAppRequestRefreshRateMin,
+ float* outAppRequestRefreshRateMax) = 0;
/*
* Gets whether brightness operations are supported on a display.
*
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 2fb9538..531aed7 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -118,21 +118,19 @@
// Shorthand for getDisplayConfigs element at getActiveConfig index.
static status_t getActiveDisplayConfig(const sp<IBinder>& display, DisplayConfig*);
- // Sets the refresh rate boundaries for display configuration.
- // For all other parameters, default configuration is used. The index for the default is
- // corresponting to the configs returned from getDisplayConfigs().
+ // Sets the refresh rate boundaries for the display.
static status_t setDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken,
- int32_t defaultConfig, float minRefreshRate,
- float maxRefreshRate);
- // Gets the refresh rate boundaries for display configuration.
- // For all other parameters, default configuration is used. The index for the default is
- // corresponting to the configs returned from getDisplayConfigs().
- // The reason is passed in for telemetry tracking, and it corresponds to the list of all
- // the policy rules that were used.
+ int32_t defaultConfig, float primaryRefreshRateMin,
+ float primaryRefreshRateMax,
+ float appRequestRefreshRateMin,
+ float appRequestRefreshRateMax);
+ // Gets the refresh rate boundaries for the display.
static status_t getDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken,
int32_t* outDefaultConfig,
- float* outMinRefreshRate,
- float* outMaxRefreshRate);
+ float* outPrimaryRefreshRateMin,
+ float* outPrimaryRefreshRateMax,
+ float* outAppRequestRefreshRateMin,
+ float* outAppRequestRefreshRateMax);
// Gets the list of supported color modes for the given display
static status_t getDisplayColorModes(const sp<IBinder>& display,
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 1acbc9e..a1d12a5 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -834,14 +834,19 @@
return NO_ERROR;
}
status_t setDesiredDisplayConfigSpecs(const sp<IBinder>& /*displayToken*/,
- int32_t /*defaultConfig*/, float /*minRefreshRate*/,
- float /*maxRefreshRate*/) {
+ int32_t /*defaultConfig*/,
+ float /*primaryRefreshRateMin*/,
+ float /*primaryRefreshRateMax*/,
+ float /*appRequestRefreshRateMin*/,
+ float /*appRequestRefreshRateMax*/) {
return NO_ERROR;
}
status_t getDesiredDisplayConfigSpecs(const sp<IBinder>& /*displayToken*/,
int32_t* /*outDefaultConfig*/,
- float* /*outMinRefreshRate*/,
- float* /*outMaxRefreshRate*/) override {
+ float* /*outPrimaryRefreshRateMin*/,
+ float* /*outPrimaryRefreshRateMax*/,
+ float* /*outAppRequestRefreshRateMin*/,
+ float* /*outAppRequestRefreshRateMax*/) override {
return NO_ERROR;
};
status_t notifyPowerHint(int32_t /*hintId*/) override { return NO_ERROR; }
diff --git a/libs/ui/Region.cpp b/libs/ui/Region.cpp
index d929cc3..82ce757 100644
--- a/libs/ui/Region.cpp
+++ b/libs/ui/Region.cpp
@@ -67,19 +67,20 @@
// ----------------------------------------------------------------------------
Region::Region() {
- mStorage.add(Rect(0,0));
+ mStorage.push_back(Rect(0, 0));
}
Region::Region(const Region& rhs)
- : mStorage(rhs.mStorage)
{
+ mStorage.clear();
+ mStorage.insert(mStorage.begin(), rhs.mStorage.begin(), rhs.mStorage.end());
#if defined(VALIDATE_REGIONS)
validate(rhs, "rhs copy-ctor");
#endif
}
Region::Region(const Rect& rhs) {
- mStorage.add(rhs);
+ mStorage.push_back(rhs);
}
Region::~Region()
@@ -100,8 +101,8 @@
* final, correctly ordered region buffer. Each rectangle will be compared with the span directly
* above it, and subdivided to resolve any remaining T-junctions.
*/
-static void reverseRectsResolvingJunctions(const Rect* begin, const Rect* end,
- Vector<Rect>& dst, int spanDirection) {
+static void reverseRectsResolvingJunctions(const Rect* begin, const Rect* end, FatVector<Rect>& dst,
+ int spanDirection) {
dst.clear();
const Rect* current = end - 1;
@@ -109,7 +110,7 @@
// add first span immediately
do {
- dst.add(*current);
+ dst.push_back(*current);
current--;
} while (current->top == lastTop && current >= begin);
@@ -147,12 +148,12 @@
if (prev.right <= left) break;
if (prev.right > left && prev.right < right) {
- dst.add(Rect(prev.right, top, right, bottom));
+ dst.push_back(Rect(prev.right, top, right, bottom));
right = prev.right;
}
if (prev.left > left && prev.left < right) {
- dst.add(Rect(prev.left, top, right, bottom));
+ dst.push_back(Rect(prev.left, top, right, bottom));
right = prev.left;
}
@@ -166,12 +167,12 @@
if (prev.left >= right) break;
if (prev.left > left && prev.left < right) {
- dst.add(Rect(left, top, prev.left, bottom));
+ dst.push_back(Rect(left, top, prev.left, bottom));
left = prev.left;
}
if (prev.right > left && prev.right < right) {
- dst.add(Rect(left, top, prev.right, bottom));
+ dst.push_back(Rect(left, top, prev.right, bottom));
left = prev.right;
}
// if an entry in the previous span is too far left, nothing further right in the
@@ -183,7 +184,7 @@
}
if (left < right) {
- dst.add(Rect(left, top, right, bottom));
+ dst.push_back(Rect(left, top, right, bottom));
}
current--;
@@ -201,13 +202,14 @@
if (r.isEmpty()) return r;
if (r.isRect()) return r;
- Vector<Rect> reversed;
+ FatVector<Rect> reversed;
reverseRectsResolvingJunctions(r.begin(), r.end(), reversed, direction_RTL);
Region outputRegion;
- reverseRectsResolvingJunctions(reversed.begin(), reversed.end(),
- outputRegion.mStorage, direction_LTR);
- outputRegion.mStorage.add(r.getBounds()); // to make region valid, mStorage must end with bounds
+ reverseRectsResolvingJunctions(reversed.data(), reversed.data() + reversed.size(),
+ outputRegion.mStorage, direction_LTR);
+ outputRegion.mStorage.push_back(
+ r.getBounds()); // to make region valid, mStorage must end with bounds
#if defined(VALIDATE_REGIONS)
validate(outputRegion, "T-Junction free region");
@@ -222,7 +224,8 @@
validate(*this, "this->operator=");
validate(rhs, "rhs.operator=");
#endif
- mStorage = rhs.mStorage;
+ mStorage.clear();
+ mStorage.insert(mStorage.begin(), rhs.mStorage.begin(), rhs.mStorage.end());
return *this;
}
@@ -231,7 +234,7 @@
if (mStorage.size() >= 2) {
const Rect bounds(getBounds());
mStorage.clear();
- mStorage.add(bounds);
+ mStorage.push_back(bounds);
}
return *this;
}
@@ -255,25 +258,25 @@
void Region::clear()
{
mStorage.clear();
- mStorage.add(Rect(0,0));
+ mStorage.push_back(Rect(0, 0));
}
void Region::set(const Rect& r)
{
mStorage.clear();
- mStorage.add(r);
+ mStorage.push_back(r);
}
void Region::set(int32_t w, int32_t h)
{
mStorage.clear();
- mStorage.add(Rect(w, h));
+ mStorage.push_back(Rect(w, h));
}
void Region::set(uint32_t w, uint32_t h)
{
mStorage.clear();
- mStorage.add(Rect(w, h));
+ mStorage.push_back(Rect(w, h));
}
bool Region::isTriviallyEqual(const Region& region) const {
@@ -299,8 +302,7 @@
void Region::addRectUnchecked(int l, int t, int r, int b)
{
Rect rect(l,t,r,b);
- size_t where = mStorage.size() - 1;
- mStorage.insertAt(rect, where, 1);
+ mStorage.insert(mStorage.end() - 1, rect);
}
// ----------------------------------------------------------------------------
@@ -358,7 +360,7 @@
Region& Region::scaleSelf(float sx, float sy) {
size_t count = mStorage.size();
- Rect* rects = mStorage.editArray();
+ Rect* rects = mStorage.data();
while (count) {
rects->left = static_cast<int32_t>(static_cast<float>(rects->left) * sx + 0.5f);
rects->right = static_cast<int32_t>(static_cast<float>(rects->right) * sx + 0.5f);
@@ -463,10 +465,10 @@
class Region::rasterizer : public region_operator<Rect>::region_rasterizer
{
Rect bounds;
- Vector<Rect>& storage;
+ FatVector<Rect>& storage;
Rect* head;
Rect* tail;
- Vector<Rect> span;
+ FatVector<Rect> span;
Rect* cur;
public:
explicit rasterizer(Region& reg)
@@ -493,8 +495,8 @@
flushSpan();
}
if (storage.size()) {
- bounds.top = storage.itemAt(0).top;
- bounds.bottom = storage.top().bottom;
+ bounds.top = storage.front().top;
+ bounds.bottom = storage.back().bottom;
if (storage.size() == 1) {
storage.clear();
}
@@ -502,7 +504,7 @@
bounds.left = 0;
bounds.right = 0;
}
- storage.add(bounds);
+ storage.push_back(bounds);
}
void Region::rasterizer::operator()(const Rect& rect)
@@ -517,15 +519,15 @@
return;
}
}
- span.add(rect);
- cur = span.editArray() + (span.size() - 1);
+ span.push_back(rect);
+ cur = span.data() + (span.size() - 1);
}
void Region::rasterizer::flushSpan()
{
bool merge = false;
if (tail-head == ssize_t(span.size())) {
- Rect const* p = span.editArray();
+ Rect const* p = span.data();
Rect const* q = head;
if (p->top == q->bottom) {
merge = true;
@@ -540,17 +542,17 @@
}
}
if (merge) {
- const int bottom = span[0].bottom;
+ const int bottom = span.front().bottom;
Rect* r = head;
while (r != tail) {
r->bottom = bottom;
r++;
}
} else {
- bounds.left = min(span.itemAt(0).left, bounds.left);
- bounds.right = max(span.top().right, bounds.right);
- storage.appendVector(span);
- tail = storage.editArray() + storage.size();
+ bounds.left = min(span.front().left, bounds.left);
+ bounds.right = max(span.back().right, bounds.right);
+ storage.insert(storage.end(), span.begin(), span.end());
+ tail = storage.data() + storage.size();
head = tail - span.size();
}
span.clear();
@@ -558,7 +560,7 @@
bool Region::validate(const Region& reg, const char* name, bool silent)
{
- if (reg.mStorage.isEmpty()) {
+ if (reg.mStorage.empty()) {
ALOGE_IF(!silent, "%s: mStorage is empty, which is never valid", name);
// return immediately as the code below assumes mStorage is non-empty
return false;
@@ -697,9 +699,8 @@
}
sk_dst.op(sk_lhs, sk_rhs, sk_op);
- if (sk_dst.isEmpty() && dst.isEmpty())
- return;
-
+ if (sk_dst.empty() && dst.empty()) return;
+
bool same = true;
Region::const_iterator head = dst.begin();
Region::const_iterator const tail = dst.end();
@@ -794,7 +795,7 @@
validate(reg, "translate (before)");
#endif
size_t count = reg.mStorage.size();
- Rect* rects = reg.mStorage.editArray();
+ Rect* rects = reg.mStorage.data();
while (count) {
rects->offsetBy(dx, dy);
rects++;
@@ -874,24 +875,25 @@
ALOGE("Region::unflatten() failed, invalid region");
return BAD_VALUE;
}
- mStorage = result.mStorage;
+ mStorage.clear();
+ mStorage.insert(mStorage.begin(), result.mStorage.begin(), result.mStorage.end());
return NO_ERROR;
}
// ----------------------------------------------------------------------------
Region::const_iterator Region::begin() const {
- return mStorage.array();
+ return mStorage.data();
}
Region::const_iterator Region::end() const {
// Workaround for b/77643177
// mStorage should never be empty, but somehow it is and it's causing
// an abort in ubsan
- if (mStorage.isEmpty()) return mStorage.array();
+ if (mStorage.empty()) return mStorage.data();
size_t numRects = isRect() ? 1 : mStorage.size() - 1;
- return mStorage.array() + numRects;
+ return mStorage.data() + numRects;
}
Rect const* Region::getArray(size_t* count) const {
diff --git a/libs/ui/include/ui/FatVector.h b/libs/ui/include/ui/FatVector.h
new file mode 100644
index 0000000..25fe3a0
--- /dev/null
+++ b/libs/ui/include/ui/FatVector.h
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_REGION_FAT_VECTOR_H
+#define ANDROID_REGION_FAT_VECTOR_H
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <utils/Log.h>
+#include <type_traits>
+
+#include <vector>
+
+namespace android {
+
+template <typename T, size_t SIZE = 4>
+class InlineStdAllocator {
+public:
+ struct Allocation {
+ private:
+ Allocation(const Allocation&) = delete;
+ void operator=(const Allocation&) = delete;
+
+ public:
+ Allocation() {}
+ // char array instead of T array, so memory is uninitialized, with no destructors run
+ char array[sizeof(T) * SIZE];
+ bool inUse = false;
+ };
+
+ typedef T value_type; // needed to implement std::allocator
+ typedef T* pointer; // needed to implement std::allocator
+
+ explicit InlineStdAllocator(Allocation& allocation) : mAllocation(allocation) {}
+ InlineStdAllocator(const InlineStdAllocator& other) : mAllocation(other.mAllocation) {}
+ ~InlineStdAllocator() {}
+
+ T* allocate(size_t num, const void* = 0) {
+ if (!mAllocation.inUse && num <= SIZE) {
+ mAllocation.inUse = true;
+ return static_cast<T*>(static_cast<void*>(mAllocation.array));
+ } else {
+ return static_cast<T*>(static_cast<void*>(malloc(num * sizeof(T))));
+ }
+ }
+
+ void deallocate(pointer p, size_t) {
+ if (p == static_cast<T*>(static_cast<void*>(mAllocation.array))) {
+ mAllocation.inUse = false;
+ } else {
+ // 'free' instead of delete here - destruction handled separately
+ free(p);
+ }
+ }
+ Allocation& mAllocation;
+};
+
+/**
+ * std::vector with SIZE elements preallocated into an internal buffer.
+ *
+ * Useful for avoiding the cost of malloc in cases where only SIZE or
+ * fewer elements are needed in the common case.
+ */
+template <typename T, size_t SIZE = 4>
+class FatVector : public std::vector<T, InlineStdAllocator<T, SIZE>> {
+public:
+ FatVector()
+ : std::vector<T, InlineStdAllocator<T, SIZE>>(InlineStdAllocator<T, SIZE>(mAllocation)) {
+ this->reserve(SIZE);
+ }
+
+ explicit FatVector(size_t capacity) : FatVector() { this->resize(capacity); }
+
+private:
+ typename InlineStdAllocator<T, SIZE>::Allocation mAllocation;
+};
+
+} // namespace android
+
+#endif // ANDROID_REGION_FAT_VECTOR_H
diff --git a/libs/ui/include/ui/Region.h b/libs/ui/include/ui/Region.h
index 2db3b10..6bb7b8d 100644
--- a/libs/ui/include/ui/Region.h
+++ b/libs/ui/include/ui/Region.h
@@ -21,13 +21,13 @@
#include <sys/types.h>
#include <ostream>
-#include <utils/Vector.h>
-
#include <ui/Rect.h>
#include <utils/Flattenable.h>
#include <android-base/macros.h>
+#include "FatVector.h"
+
#include <string>
namespace android {
@@ -180,7 +180,7 @@
// with an extra Rect as the last element which is set to the
// bounds of the region. However, if the region is
// a simple Rect then mStorage contains only that rect.
- Vector<Rect> mStorage;
+ FatVector<Rect> mStorage;
};
@@ -235,4 +235,3 @@
}; // namespace android
#endif // ANDROID_UI_REGION_H
-
diff --git a/libs/ui/include_vndk/ui/FatVector.h b/libs/ui/include_vndk/ui/FatVector.h
new file mode 120000
index 0000000..bf30166
--- /dev/null
+++ b/libs/ui/include_vndk/ui/FatVector.h
@@ -0,0 +1 @@
+../../include/ui/FatVector.h
\ No newline at end of file
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
index 5634adb..43e67c2 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
@@ -58,7 +58,7 @@
ATRACE_INT("ContentFPS", contentFramerate);
// Find the appropriate refresh rate with minimal error
- auto iter = min_element(mAvailableRefreshRates.cbegin(), mAvailableRefreshRates.cend(),
+ auto iter = min_element(mPrimaryRefreshRates.cbegin(), mPrimaryRefreshRates.cend(),
[contentFramerate](const auto& lhs, const auto& rhs) -> bool {
return std::abs(lhs->fps - contentFramerate) <
std::abs(rhs->fps - contentFramerate);
@@ -71,7 +71,7 @@
constexpr float MARGIN = 0.05f;
float ratio = (*iter)->fps / contentFramerate;
if (std::abs(std::round(ratio) - ratio) > MARGIN) {
- while (iter != mAvailableRefreshRates.cend()) {
+ while (iter != mPrimaryRefreshRates.cend()) {
ratio = (*iter)->fps / contentFramerate;
if (std::abs(std::round(ratio) - ratio) <= MARGIN) {
@@ -110,7 +110,8 @@
// refresh rate.
if (layers.empty()) {
*touchConsidered = touchActive;
- return touchActive ? *mAvailableRefreshRates.back() : getCurrentRefreshRateByPolicyLocked();
+ return touchActive ? getMaxRefreshRateByPolicyLocked()
+ : getCurrentRefreshRateByPolicyLocked();
}
int noVoteLayers = 0;
@@ -135,25 +136,25 @@
}
}
- // Consider the touch event if there are no ExplicitDefault layers.
- // ExplicitDefault are mostly interactive (as opposed to ExplicitExactOrMultiple)
- // and therefore if those posted an explicit vote we should not change it
- // if get get a touch event.
- if (touchActive && explicitDefaultVoteLayers == 0) {
+ // Consider the touch event if there are no Explicit* layers. Otherwise wait until after we've
+ // selected a refresh rate to see if we should apply touch boost.
+ if (touchActive && explicitDefaultVoteLayers == 0 && explicitExactOrMultipleVoteLayers == 0) {
*touchConsidered = true;
- return *mAvailableRefreshRates.back();
+ return getMaxRefreshRateByPolicyLocked();
}
// Only if all layers want Min we should return Min
if (noVoteLayers + minVoteLayers == layers.size()) {
- return *mAvailableRefreshRates.front();
+ return getMinRefreshRateByPolicyLocked();
}
+ const Policy* policy = getCurrentPolicyLocked();
+
// Find the best refresh rate based on score
std::vector<std::pair<const RefreshRate*, float>> scores;
- scores.reserve(mAvailableRefreshRates.size());
+ scores.reserve(mAppRequestRefreshRates.size());
- for (const auto refreshRate : mAvailableRefreshRates) {
+ for (const auto refreshRate : mAppRequestRefreshRates) {
scores.emplace_back(refreshRate, 0.0f);
}
@@ -166,6 +167,15 @@
auto weight = layer.weight;
for (auto i = 0u; i < scores.size(); i++) {
+ bool inPrimaryRange =
+ scores[i].first->inPolicy(policy->primaryRange.min, policy->primaryRange.max);
+ if (!inPrimaryRange && layer.vote != LayerVoteType::ExplicitDefault &&
+ layer.vote != LayerVoteType::ExplicitExactOrMultiple) {
+ // Only layers with explicit frame rate settings are allowed to score refresh rates
+ // outside the primary range.
+ continue;
+ }
+
// If the layer wants Max, give higher score to the higher refresh rate
if (layer.vote == LayerVoteType::Max) {
const auto ratio = scores[i].first->fps / scores.back().first->fps;
@@ -249,6 +259,17 @@
? getBestRefreshRate(scores.rbegin(), scores.rend())
: getBestRefreshRate(scores.begin(), scores.end());
+ // Consider the touch event if there are no ExplicitDefault layers. ExplicitDefault are mostly
+ // interactive (as opposed to ExplicitExactOrMultiple) and therefore if those posted an explicit
+ // vote we should not change it if we get a touch event. Only apply touch boost if it will
+ // actually increase the refresh rate over the normal selection.
+ const RefreshRate& touchRefreshRate = getMaxRefreshRateByPolicyLocked();
+ if (touchActive && explicitDefaultVoteLayers == 0 &&
+ bestRefreshRate->fps < touchRefreshRate.fps) {
+ *touchConsidered = true;
+ return touchRefreshRate;
+ }
+
return *bestRefreshRate;
}
@@ -278,12 +299,20 @@
const RefreshRate& RefreshRateConfigs::getMinRefreshRateByPolicy() const {
std::lock_guard lock(mLock);
- return *mAvailableRefreshRates.front();
+ return getMinRefreshRateByPolicyLocked();
+}
+
+const RefreshRate& RefreshRateConfigs::getMinRefreshRateByPolicyLocked() const {
+ return *mPrimaryRefreshRates.front();
}
const RefreshRate& RefreshRateConfigs::getMaxRefreshRateByPolicy() const {
std::lock_guard lock(mLock);
- return *mAvailableRefreshRates.back();
+ return getMaxRefreshRateByPolicyLocked();
+}
+
+const RefreshRate& RefreshRateConfigs::getMaxRefreshRateByPolicyLocked() const {
+ return *mPrimaryRefreshRates.back();
}
const RefreshRate& RefreshRateConfigs::getCurrentRefreshRate() const {
@@ -297,8 +326,8 @@
}
const RefreshRate& RefreshRateConfigs::getCurrentRefreshRateByPolicyLocked() const {
- if (std::find(mAvailableRefreshRates.begin(), mAvailableRefreshRates.end(),
- mCurrentRefreshRate) != mAvailableRefreshRates.end()) {
+ if (std::find(mAppRequestRefreshRates.begin(), mAppRequestRefreshRates.end(),
+ mCurrentRefreshRate) != mAppRequestRefreshRates.end()) {
return *mCurrentRefreshRate;
}
return *mRefreshRates.at(getCurrentPolicyLocked()->defaultConfig);
@@ -320,7 +349,7 @@
const float fps = 1e9f / config->getVsyncPeriod();
mRefreshRates.emplace(configId,
std::make_unique<RefreshRate>(configId, config,
- base::StringPrintf("%2.ffps", fps), fps,
+ base::StringPrintf("%.0ffps", fps), fps,
RefreshRate::ConstructorTag(0)));
if (configId == currentConfigId) {
mCurrentRefreshRate = mRefreshRates.at(configId).get();
@@ -342,10 +371,11 @@
return false;
}
const RefreshRate& refreshRate = *iter->second;
- if (!refreshRate.inPolicy(policy.minRefreshRate, policy.maxRefreshRate)) {
+ if (!refreshRate.inPolicy(policy.primaryRange.min, policy.primaryRange.max)) {
return false;
}
- return true;
+ return policy.appRequestRange.min <= policy.primaryRange.min &&
+ policy.appRequestRange.max >= policy.primaryRange.max;
}
status_t RefreshRateConfigs::setDisplayManagerPolicy(const Policy& policy) {
@@ -392,7 +422,7 @@
bool RefreshRateConfigs::isConfigAllowed(HwcConfigIndexType config) const {
std::lock_guard lock(mLock);
- for (const RefreshRate* refreshRate : mAvailableRefreshRates) {
+ for (const RefreshRate* refreshRate : mAppRequestRefreshRates) {
if (refreshRate->configId == config) {
return true;
}
@@ -430,33 +460,44 @@
// Filter configs based on current policy and sort based on vsync period
const Policy* policy = getCurrentPolicyLocked();
const auto& defaultConfig = mRefreshRates.at(policy->defaultConfig)->hwcConfig;
- ALOGV("constructAvailableRefreshRates: default %d group %d min %.2f max %.2f",
- policy->defaultConfig.value(), defaultConfig->getConfigGroup(), policy->minRefreshRate,
- policy->maxRefreshRate);
- getSortedRefreshRateList(
- [&](const RefreshRate& refreshRate) REQUIRES(mLock) {
- const auto& hwcConfig = refreshRate.hwcConfig;
+ ALOGV("constructAvailableRefreshRates: default %d group %d primaryRange=[%.2f %.2f]"
+ " appRequestRange=[%.2f %.2f]",
+ policy->defaultConfig.value(), defaultConfig->getConfigGroup(), policy->primaryRange.min,
+ policy->primaryRange.max, policy->appRequestRange.min, policy->appRequestRange.max);
- return hwcConfig->getHeight() == defaultConfig->getHeight() &&
- hwcConfig->getWidth() == defaultConfig->getWidth() &&
- hwcConfig->getDpiX() == defaultConfig->getDpiX() &&
- hwcConfig->getDpiY() == defaultConfig->getDpiY() &&
- (policy->allowGroupSwitching ||
- hwcConfig->getConfigGroup() == defaultConfig->getConfigGroup()) &&
- refreshRate.inPolicy(policy->minRefreshRate, policy->maxRefreshRate);
- },
- &mAvailableRefreshRates);
+ auto filterRefreshRates = [&](float min, float max, const char* listName,
+ std::vector<const RefreshRate*>* outRefreshRates) {
+ getSortedRefreshRateList(
+ [&](const RefreshRate& refreshRate) REQUIRES(mLock) {
+ const auto& hwcConfig = refreshRate.hwcConfig;
- std::string availableRefreshRates;
- for (const auto& refreshRate : mAvailableRefreshRates) {
- base::StringAppendF(&availableRefreshRates, "%s ", refreshRate->name.c_str());
- }
+ return hwcConfig->getHeight() == defaultConfig->getHeight() &&
+ hwcConfig->getWidth() == defaultConfig->getWidth() &&
+ hwcConfig->getDpiX() == defaultConfig->getDpiX() &&
+ hwcConfig->getDpiY() == defaultConfig->getDpiY() &&
+ (policy->allowGroupSwitching ||
+ hwcConfig->getConfigGroup() == defaultConfig->getConfigGroup()) &&
+ refreshRate.inPolicy(min, max);
+ },
+ outRefreshRates);
- ALOGV("Available refresh rates: %s", availableRefreshRates.c_str());
- LOG_ALWAYS_FATAL_IF(mAvailableRefreshRates.empty(),
- "No compatible display configs for default=%d min=%.0f max=%.0f",
- policy->defaultConfig.value(), policy->minRefreshRate,
- policy->maxRefreshRate);
+ LOG_ALWAYS_FATAL_IF(outRefreshRates->empty(),
+ "No matching configs for %s range: min=%.0f max=%.0f", listName, min,
+ max);
+ auto stringifyRefreshRates = [&]() -> std::string {
+ std::string str;
+ for (auto refreshRate : *outRefreshRates) {
+ base::StringAppendF(&str, "%s ", refreshRate->name.c_str());
+ }
+ return str;
+ };
+ ALOGV("%s refresh rates: %s", listName, stringifyRefreshRates().c_str());
+ };
+
+ filterRefreshRates(policy->primaryRange.min, policy->primaryRange.max, "primary",
+ &mPrimaryRefreshRates);
+ filterRefreshRates(policy->appRequestRange.min, policy->appRequestRange.max, "app request",
+ &mAppRequestRefreshRates);
}
} // namespace android::scheduler
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
index dea7e90..e8a7bef 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
@@ -107,18 +107,46 @@
std::unordered_map<HwcConfigIndexType, std::unique_ptr<const RefreshRate>>;
struct Policy {
+ struct Range {
+ float min = 0;
+ float max = std::numeric_limits<float>::max();
+
+ bool operator==(const Range& other) const {
+ return min == other.min && max == other.max;
+ }
+
+ bool operator!=(const Range& other) const { return !(*this == other); }
+ };
+
// The default config, used to ensure we only initiate display config switches within the
// same config group as defaultConfigId's group.
HwcConfigIndexType defaultConfig;
- // The min and max FPS allowed by the policy.
- float minRefreshRate = 0;
- float maxRefreshRate = std::numeric_limits<float>::max();
+ // The primary refresh rate range represents display manager's general guidance on the
+ // display configs we'll consider when switching refresh rates. Unless we get an explicit
+ // signal from an app, we should stay within this range.
+ Range primaryRange;
+ // The app request refresh rate range allows us to consider more display configs when
+ // switching refresh rates. Although we should generally stay within the primary range,
+ // specific considerations, such as layer frame rate settings specified via the
+ // setFrameRate() api, may cause us to go outside the primary range. We never go outside the
+ // app request range. The app request range will be greater than or equal to the primary
+ // refresh rate range, never smaller.
+ Range appRequestRange;
// Whether or not we switch config groups to get the best frame rate. Only used by tests.
bool allowGroupSwitching = false;
+ Policy() = default;
+ Policy(HwcConfigIndexType defaultConfig, const Range& range)
+ : Policy(defaultConfig, range, range) {}
+ Policy(HwcConfigIndexType defaultConfig, const Range& primaryRange,
+ const Range& appRequestRange)
+ : defaultConfig(defaultConfig),
+ primaryRange(primaryRange),
+ appRequestRange(appRequestRange) {}
+
bool operator==(const Policy& other) const {
- return defaultConfig == other.defaultConfig && minRefreshRate == other.minRefreshRate &&
- maxRefreshRate == other.maxRefreshRate &&
+ return defaultConfig == other.defaultConfig && primaryRange == other.primaryRange &&
+ appRequestRange == other.appRequestRange &&
allowGroupSwitching == other.allowGroupSwitching;
}
@@ -198,13 +226,15 @@
// Returns the lowest refresh rate supported by the device. This won't change at runtime.
const RefreshRate& getMinRefreshRate() const { return *mMinSupportedRefreshRate; }
- // Returns the lowest refresh rate according to the current policy. May change in runtime.
+ // Returns the lowest refresh rate according to the current policy. May change at runtime. Only
+ // uses the primary range, not the app request range.
const RefreshRate& getMinRefreshRateByPolicy() const EXCLUDES(mLock);
// Returns the highest refresh rate supported by the device. This won't change at runtime.
const RefreshRate& getMaxRefreshRate() const { return *mMaxSupportedRefreshRate; }
- // Returns the highest refresh rate according to the current policy. May change in runtime.
+ // Returns the highest refresh rate according to the current policy. May change at runtime. Only
+ // uses the primary range, not the app request range.
const RefreshRate& getMaxRefreshRateByPolicy() const EXCLUDES(mLock);
// Returns the current refresh rate
@@ -243,6 +273,14 @@
// display refresh period.
std::pair<nsecs_t, nsecs_t> getDisplayFrames(nsecs_t layerPeriod, nsecs_t displayPeriod) const;
+ // Returns the lowest refresh rate according to the current policy. May change at runtime. Only
+ // uses the primary range, not the app request range.
+ const RefreshRate& getMinRefreshRateByPolicyLocked() const REQUIRES(mLock);
+
+ // Returns the highest refresh rate according to the current policy. May change at runtime. Only
+ // uses the primary range, not the app request range.
+ const RefreshRate& getMaxRefreshRateByPolicyLocked() const REQUIRES(mLock);
+
// Returns the current refresh rate, if allowed. Otherwise the default that is allowed by
// the policy.
const RefreshRate& getCurrentRefreshRateByPolicyLocked() const REQUIRES(mLock);
@@ -254,9 +292,13 @@
// object is initialized.
AllRefreshRatesMapType mRefreshRates;
- // The list of refresh rates which are available in the current policy, ordered by vsyncPeriod
- // (the first element is the lowest refresh rate)
- std::vector<const RefreshRate*> mAvailableRefreshRates GUARDED_BY(mLock);
+ // The list of refresh rates in the primary range of the current policy, ordered by vsyncPeriod
+ // (the first element is the lowest refresh rate).
+ std::vector<const RefreshRate*> mPrimaryRefreshRates GUARDED_BY(mLock);
+
+ // The list of refresh rates in the app request range of the current policy, ordered by
+ // vsyncPeriod (the first element is the lowest refresh rate).
+ std::vector<const RefreshRate*> mAppRequestRefreshRates GUARDED_BY(mLock);
// The current config. This will change at runtime. This is set by SurfaceFlinger on
// the main thread, and read by the Scheduler (and other objects) on other threads.
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 86bb6eb..217c777 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -574,10 +574,8 @@
HwcConfigIndexType Scheduler::calculateRefreshRateConfigIndexType() {
ATRACE_CALL();
- // NOTE: If we remove the kernel idle timer, and use our internal idle timer, this
- // code will have to be refactored. If Display Power is not in normal operation we want to be in
- // performance mode. When coming back to normal mode, a grace period is given with
- // DisplayPowerTimer.
+ // If Display Power is not in normal operation we want to be in performance mode. When coming
+ // back to normal mode, a grace period is given with DisplayPowerTimer.
if (mDisplayPowerTimer &&
(!mFeatures.isDisplayPowerStateNormal ||
mFeatures.displayPowerTimer == TimerState::Reset)) {
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 79ea97b..4ca2074 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -1003,7 +1003,7 @@
} else {
const HwcConfigIndexType config(mode);
const float fps = mRefreshRateConfigs->getRefreshRateFromConfigId(config).getFps();
- const scheduler::RefreshRateConfigs::Policy policy{config, fps, fps};
+ const scheduler::RefreshRateConfigs::Policy policy{config, {fps, fps}};
constexpr bool kOverridePolicy = false;
return setDesiredDisplayConfigSpecsInternal(display, policy, kOverridePolicy);
@@ -4383,17 +4383,19 @@
scheduler::RefreshRateConfigs::Policy policy = mRefreshRateConfigs->getDisplayManagerPolicy();
StringAppendF(&result,
"DesiredDisplayConfigSpecs (DisplayManager): default config ID: %d"
- ", min: %.2f Hz, max: %.2f Hz",
- policy.defaultConfig.value(), policy.minRefreshRate, policy.maxRefreshRate);
+ ", primary range: [%.2f %.2f], app request range: [%.2f %.2f]\n\n",
+ policy.defaultConfig.value(), policy.primaryRange.min, policy.primaryRange.max,
+ policy.appRequestRange.min, policy.appRequestRange.max);
StringAppendF(&result, "(config override by backdoor: %s)\n\n",
mDebugDisplayConfigSetByBackdoor ? "yes" : "no");
scheduler::RefreshRateConfigs::Policy currentPolicy = mRefreshRateConfigs->getCurrentPolicy();
if (currentPolicy != policy) {
StringAppendF(&result,
"DesiredDisplayConfigSpecs (Override): default config ID: %d"
- ", min: %.2f Hz, max: %.2f Hz\n\n",
- currentPolicy.defaultConfig.value(), currentPolicy.minRefreshRate,
- currentPolicy.maxRefreshRate);
+ ", primary range: [%.2f %.2f], app request range: [%.2f %.2f]\n\n",
+ currentPolicy.defaultConfig.value(), currentPolicy.primaryRange.min,
+ currentPolicy.primaryRange.max, currentPolicy.appRequestRange.min,
+ currentPolicy.appRequestRange.max);
}
mScheduler->dump(mAppConnectionHandle, result);
@@ -5928,9 +5930,11 @@
}
scheduler::RefreshRateConfigs::Policy currentPolicy = mRefreshRateConfigs->getCurrentPolicy();
- ALOGV("Setting desired display config specs: defaultConfig: %d min: %.f max: %.f",
- currentPolicy.defaultConfig.value(), currentPolicy.minRefreshRate,
- currentPolicy.maxRefreshRate);
+ ALOGV("Setting desired display config specs: defaultConfig: %d primaryRange: [%.0f %.0f]"
+ " expandedRange: [%.0f %.0f]",
+ currentPolicy.defaultConfig.value(), currentPolicy.primaryRange.min,
+ currentPolicy.primaryRange.max, currentPolicy.appRequestRange.min,
+ currentPolicy.appRequestRange.max);
// TODO(b/140204874): This hack triggers a notification that something has changed, so
// that listeners that care about a change in allowed configs can get the notification.
@@ -5963,8 +5967,11 @@
}
status_t SurfaceFlinger::setDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken,
- int32_t defaultConfig, float minRefreshRate,
- float maxRefreshRate) {
+ int32_t defaultConfig,
+ float primaryRefreshRateMin,
+ float primaryRefreshRateMax,
+ float appRequestRefreshRateMin,
+ float appRequestRefreshRateMax) {
ATRACE_CALL();
if (!displayToken) {
@@ -5982,7 +5989,9 @@
return INVALID_OPERATION;
} else {
using Policy = scheduler::RefreshRateConfigs::Policy;
- const Policy policy{HwcConfigIndexType(defaultConfig), minRefreshRate, maxRefreshRate};
+ const Policy policy{HwcConfigIndexType(defaultConfig),
+ {primaryRefreshRateMin, primaryRefreshRateMax},
+ {appRequestRefreshRateMin, appRequestRefreshRateMax}};
constexpr bool kOverridePolicy = false;
return setDesiredDisplayConfigSpecsInternal(display, policy, kOverridePolicy);
@@ -5994,11 +6003,14 @@
status_t SurfaceFlinger::getDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken,
int32_t* outDefaultConfig,
- float* outMinRefreshRate,
- float* outMaxRefreshRate) {
+ float* outPrimaryRefreshRateMin,
+ float* outPrimaryRefreshRateMax,
+ float* outAppRequestRefreshRateMin,
+ float* outAppRequestRefreshRateMax) {
ATRACE_CALL();
- if (!displayToken || !outDefaultConfig || !outMinRefreshRate || !outMaxRefreshRate) {
+ if (!displayToken || !outDefaultConfig || !outPrimaryRefreshRateMin ||
+ !outPrimaryRefreshRateMax || !outAppRequestRefreshRateMin || !outAppRequestRefreshRateMax) {
return BAD_VALUE;
}
@@ -6012,8 +6024,10 @@
scheduler::RefreshRateConfigs::Policy policy =
mRefreshRateConfigs->getDisplayManagerPolicy();
*outDefaultConfig = policy.defaultConfig.value();
- *outMinRefreshRate = policy.minRefreshRate;
- *outMaxRefreshRate = policy.maxRefreshRate;
+ *outPrimaryRefreshRateMin = policy.primaryRange.min;
+ *outPrimaryRefreshRateMax = policy.primaryRange.max;
+ *outAppRequestRefreshRateMin = policy.appRequestRange.min;
+ *outAppRequestRefreshRateMax = policy.appRequestRange.max;
return NO_ERROR;
} else if (display->isVirtual()) {
return INVALID_OPERATION;
@@ -6023,8 +6037,10 @@
*outDefaultConfig = getHwComposer().getActiveConfigIndex(*displayId);
auto vsyncPeriod = getHwComposer().getActiveConfig(*displayId)->getVsyncPeriod();
- *outMinRefreshRate = 1e9f / vsyncPeriod;
- *outMaxRefreshRate = 1e9f / vsyncPeriod;
+ *outPrimaryRefreshRateMin = 1e9f / vsyncPeriod;
+ *outPrimaryRefreshRateMax = 1e9f / vsyncPeriod;
+ *outAppRequestRefreshRateMin = 1e9f / vsyncPeriod;
+ *outAppRequestRefreshRateMax = 1e9f / vsyncPeriod;
return NO_ERROR;
}
}
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 294a52f..f3984ed 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -493,10 +493,15 @@
const sp<IRegionSamplingListener>& listener) override;
status_t removeRegionSamplingListener(const sp<IRegionSamplingListener>& listener) override;
status_t setDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken, int32_t displayModeId,
- float minRefreshRate, float maxRefreshRate) override;
+ float primaryRefreshRateMin, float primaryRefreshRateMax,
+ float appRequestRefreshRateMin,
+ float appRequestRefreshRateMax) override;
status_t getDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken,
- int32_t* outDefaultConfig, float* outMinRefreshRate,
- float* outMaxRefreshRate) override;
+ int32_t* outDefaultConfig,
+ float* outPrimaryRefreshRateMin,
+ float* outPrimaryRefreshRateMax,
+ float* outAppRequestRefreshRateMin,
+ float* outAppRequestRefreshRateMax) override;
status_t getDisplayBrightnessSupport(const sp<IBinder>& displayToken,
bool* outSupport) const override;
status_t setDisplayBrightness(const sp<IBinder>& displayToken, float brightness) override;
diff --git a/services/surfaceflinger/surfaceflinger.rc b/services/surfaceflinger/surfaceflinger.rc
index d3942e8..575e70d 100644
--- a/services/surfaceflinger/surfaceflinger.rc
+++ b/services/surfaceflinger/surfaceflinger.rc
@@ -4,7 +4,7 @@
group graphics drmrpc readproc
capabilities SYS_NICE
onrestart restart zygote
- writepid /dev/stune/foreground/tasks
+ task_profiles HighPerformance
socket pdx/system/vr/display/client stream 0666 system graphics u:object_r:pdx_display_client_endpoint_socket:s0
socket pdx/system/vr/display/manager stream 0666 system graphics u:object_r:pdx_display_manager_endpoint_socket:s0
socket pdx/system/vr/display/vsync stream 0666 system graphics u:object_r:pdx_display_vsync_endpoint_socket:s0
diff --git a/services/surfaceflinger/tests/Credentials_test.cpp b/services/surfaceflinger/tests/Credentials_test.cpp
index 507d28b..c136708 100644
--- a/services/surfaceflinger/tests/Credentials_test.cpp
+++ b/services/surfaceflinger/tests/Credentials_test.cpp
@@ -215,14 +215,21 @@
TEST_F(CredentialsTest, SetDesiredDisplayConfigsTest) {
const auto display = SurfaceComposerClient::getInternalDisplayToken();
int32_t defaultConfig;
- float minFps;
- float maxFps;
- status_t res = SurfaceComposerClient::getDesiredDisplayConfigSpecs(display, &defaultConfig,
- &minFps, &maxFps);
+ float primaryFpsMin;
+ float primaryFpsMax;
+ float appRequestFpsMin;
+ float appRequestFpsMax;
+ status_t res =
+ SurfaceComposerClient::getDesiredDisplayConfigSpecs(display, &defaultConfig,
+ &primaryFpsMin, &primaryFpsMax,
+ &appRequestFpsMin,
+ &appRequestFpsMax);
ASSERT_EQ(res, NO_ERROR);
std::function<status_t()> condition = [=]() {
- return SurfaceComposerClient::setDesiredDisplayConfigSpecs(display, defaultConfig, minFps,
- maxFps);
+ return SurfaceComposerClient::setDesiredDisplayConfigSpecs(display, defaultConfig,
+ primaryFpsMin, primaryFpsMax,
+ appRequestFpsMin,
+ appRequestFpsMax);
};
ASSERT_NO_FATAL_FAILURE(checkWithPrivileges<status_t>(condition, NO_ERROR, PERMISSION_DENIED));
}
diff --git a/services/surfaceflinger/tests/DisplayConfigs_test.cpp b/services/surfaceflinger/tests/DisplayConfigs_test.cpp
index 0ed2ffb..debfe83 100644
--- a/services/surfaceflinger/tests/DisplayConfigs_test.cpp
+++ b/services/surfaceflinger/tests/DisplayConfigs_test.cpp
@@ -39,11 +39,16 @@
TEST_F(RefreshRateRangeTest, setAllConfigs) {
int32_t initialDefaultConfig;
- float initialMin;
- float initialMax;
+ float initialPrimaryMin;
+ float initialPrimaryMax;
+ float initialAppRequestMin;
+ float initialAppRequestMax;
status_t res = SurfaceComposerClient::getDesiredDisplayConfigSpecs(mDisplayToken,
&initialDefaultConfig,
- &initialMin, &initialMax);
+ &initialPrimaryMin,
+ &initialPrimaryMax,
+ &initialAppRequestMin,
+ &initialAppRequestMax);
ASSERT_EQ(res, NO_ERROR);
Vector<DisplayConfig> configs;
@@ -53,22 +58,33 @@
for (size_t i = 0; i < configs.size(); i++) {
res = SurfaceComposerClient::setDesiredDisplayConfigSpecs(mDisplayToken, i,
configs[i].refreshRate,
+ configs[i].refreshRate,
+ configs[i].refreshRate,
configs[i].refreshRate);
ASSERT_EQ(res, NO_ERROR);
int defaultConfig;
- float minRefreshRate;
- float maxRefreshRate;
+ float primaryRefreshRateMin;
+ float primaryRefreshRateMax;
+ float appRequestRefreshRateMin;
+ float appRequestRefreshRateMax;
res = SurfaceComposerClient::getDesiredDisplayConfigSpecs(mDisplayToken, &defaultConfig,
- &minRefreshRate, &maxRefreshRate);
+ &primaryRefreshRateMin,
+ &primaryRefreshRateMax,
+ &appRequestRefreshRateMin,
+ &appRequestRefreshRateMax);
ASSERT_EQ(res, NO_ERROR);
ASSERT_EQ(defaultConfig, i);
- ASSERT_EQ(minRefreshRate, configs[i].refreshRate);
- ASSERT_EQ(maxRefreshRate, configs[i].refreshRate);
+ ASSERT_EQ(primaryRefreshRateMin, configs[i].refreshRate);
+ ASSERT_EQ(primaryRefreshRateMax, configs[i].refreshRate);
+ ASSERT_EQ(appRequestRefreshRateMin, configs[i].refreshRate);
+ ASSERT_EQ(appRequestRefreshRateMax, configs[i].refreshRate);
}
res = SurfaceComposerClient::setDesiredDisplayConfigSpecs(mDisplayToken, initialDefaultConfig,
- initialMin, initialMax);
+ initialPrimaryMin, initialPrimaryMax,
+ initialAppRequestMin,
+ initialAppRequestMax);
ASSERT_EQ(res, NO_ERROR);
}
diff --git a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
index 32c58ad..a03fd89 100644
--- a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
+++ b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
@@ -443,6 +443,8 @@
EXPECT_EQ(NO_ERROR,
SurfaceComposerClient::setDesiredDisplayConfigSpecs(display, i,
config.refreshRate,
+ config.refreshRate,
+ config.refreshRate,
config.refreshRate));
waitForDisplayTransaction();
EXPECT_TRUE(waitForConfigChangedEvent(EXTERNAL_DISPLAY, i));
@@ -547,6 +549,8 @@
EXPECT_EQ(NO_ERROR,
SurfaceComposerClient::setDesiredDisplayConfigSpecs(display, i,
config.refreshRate,
+ config.refreshRate,
+ config.refreshRate,
config.refreshRate));
waitForDisplayTransaction();
EXPECT_TRUE(waitForConfigChangedEvent(EXTERNAL_DISPLAY, i));
@@ -659,9 +663,11 @@
const auto& config = configs[i];
if (config.resolution.getWidth() == 800 && config.refreshRate == 1e9f / 11'111'111) {
EXPECT_EQ(NO_ERROR,
- SurfaceComposerClient::setDesiredDisplayConfigSpecs(display, i,
- configs[i].refreshRate,
- configs[i].refreshRate));
+ SurfaceComposerClient::
+ setDesiredDisplayConfigSpecs(display, i, configs[i].refreshRate,
+ configs[i].refreshRate,
+ configs[i].refreshRate,
+ configs[i].refreshRate));
waitForDisplayTransaction();
EXPECT_TRUE(waitForConfigChangedEvent(EXTERNAL_DISPLAY, i));
break;
@@ -706,6 +712,8 @@
EXPECT_EQ(NO_ERROR,
SurfaceComposerClient::setDesiredDisplayConfigSpecs(display, i,
config.refreshRate,
+ config.refreshRate,
+ config.refreshRate,
config.refreshRate));
waitForDisplayTransaction();
EXPECT_TRUE(waitForConfigChangedEvent(EXTERNAL_DISPLAY, i));
@@ -751,6 +759,8 @@
EXPECT_EQ(NO_ERROR,
SurfaceComposerClient::setDesiredDisplayConfigSpecs(display, i,
config.refreshRate,
+ config.refreshRate,
+ config.refreshRate,
config.refreshRate));
waitForDisplayTransaction();
EXPECT_TRUE(waitForConfigChangedEvent(EXTERNAL_DISPLAY, i));
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
index 2ceb89c..47addc8 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
@@ -166,8 +166,8 @@
auto refreshRateConfigs =
std::make_unique<RefreshRateConfigs>(m60OnlyConfigDevice,
/*currentConfigId=*/HWC_CONFIG_ID_60);
- ASSERT_LT(refreshRateConfigs->setDisplayManagerPolicy({HwcConfigIndexType(10), 60, 60}), 0);
- ASSERT_LT(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, 20, 40}), 0);
+ ASSERT_LT(refreshRateConfigs->setDisplayManagerPolicy({HwcConfigIndexType(10), {60, 60}}), 0);
+ ASSERT_LT(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {20, 40}}), 0);
}
TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_storesFullRefreshRateMap) {
@@ -201,7 +201,7 @@
ASSERT_EQ(mExpected60Config, minRate60);
ASSERT_EQ(mExpected60Config, performanceRate60);
- ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_90, 60, 90}), 0);
+ ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_90, {60, 90}}), 0);
refreshRateConfigs->setCurrentConfigId(HWC_CONFIG_ID_90);
const auto& minRate90 = refreshRateConfigs->getMinRefreshRateByPolicy();
@@ -226,7 +226,7 @@
ASSERT_EQ(mExpected60Config, minRate60);
ASSERT_EQ(mExpected60Config, performanceRate60);
- ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_90, 60, 90}), 0);
+ ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_90, {60, 90}}), 0);
refreshRateConfigs->setCurrentConfigId(HWC_CONFIG_ID_90);
const auto& minRate90 = refreshRateConfigs->getMinRefreshRateByPolicy();
@@ -248,7 +248,7 @@
ASSERT_EQ(mExpected60Config, minRate);
ASSERT_EQ(mExpected90Config, performanceRate);
- ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, 60, 60}), 0);
+ ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {60, 60}}), 0);
auto& minRate60 = refreshRateConfigs->getMinRefreshRateByPolicy();
auto& performanceRate60 = refreshRateConfigs->getMaxRefreshRateByPolicy();
@@ -271,7 +271,7 @@
EXPECT_EQ(current.getConfigId(), HWC_CONFIG_ID_90);
}
- ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_90, 90, 90}), 0);
+ ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_90, {90, 90}}), 0);
{
auto& current = refreshRateConfigs->getCurrentRefreshRate();
EXPECT_EQ(current.getConfigId(), HWC_CONFIG_ID_90);
@@ -298,7 +298,7 @@
EXPECT_EQ(mExpected60Config,
refreshRateConfigs->getRefreshRateForContent(makeLayerRequirements(24.0f)));
- ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, 60, 60}), 0);
+ ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {60, 60}}), 0);
EXPECT_EQ(mExpected60Config,
refreshRateConfigs->getRefreshRateForContent(makeLayerRequirements(90.0f)));
EXPECT_EQ(mExpected60Config,
@@ -310,7 +310,7 @@
EXPECT_EQ(mExpected60Config,
refreshRateConfigs->getRefreshRateForContent(makeLayerRequirements(24.0f)));
- ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_90, 90, 90}), 0);
+ ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_90, {90, 90}}), 0);
EXPECT_EQ(mExpected90Config,
refreshRateConfigs->getRefreshRateForContent(makeLayerRequirements(90.0f)));
EXPECT_EQ(mExpected90Config,
@@ -321,7 +321,7 @@
refreshRateConfigs->getRefreshRateForContent(makeLayerRequirements(30.0f)));
EXPECT_EQ(mExpected90Config,
refreshRateConfigs->getRefreshRateForContent(makeLayerRequirements(24.0f)));
- ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, 0, 120}), 0);
+ ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {0, 120}}), 0);
EXPECT_EQ(mExpected90Config,
refreshRateConfigs->getRefreshRateForContent(makeLayerRequirements(90.0f)));
EXPECT_EQ(mExpected60Config,
@@ -407,7 +407,7 @@
&ignored));
lr.name = "";
- ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, 60, 60}), 0);
+ ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {60, 60}}), 0);
lr.vote = LayerVoteType::Min;
EXPECT_EQ(mExpected60Config,
@@ -445,7 +445,7 @@
refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
&ignored));
- ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_90, 90, 90}), 0);
+ ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_90, {90, 90}}), 0);
lr.vote = LayerVoteType::Min;
EXPECT_EQ(mExpected90Config,
@@ -483,7 +483,7 @@
refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
&ignored));
- ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, 0, 120}), 0);
+ ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {0, 120}}), 0);
lr.vote = LayerVoteType::Min;
EXPECT_EQ(mExpected60Config,
refreshRateConfigs->getRefreshRateForContentV2(layers, /*touchActive*/ false,
@@ -1130,7 +1130,8 @@
lr1.desiredRefreshRate = 60.0f;
lr1.name = "60Hz ExplicitExactOrMultiple";
lr2.vote = LayerVoteType::Heuristic;
- lr2.name = "NoVote";
+ lr2.desiredRefreshRate = 60.0f;
+ lr2.name = "60Hz Heuristic";
refreshRateConfigs->getRefreshRateForContentV2(layers, true, &touchConsidered);
EXPECT_EQ(true, touchConsidered);
@@ -1138,7 +1139,8 @@
lr1.desiredRefreshRate = 60.0f;
lr1.name = "60Hz ExplicitExactOrMultiple";
lr2.vote = LayerVoteType::Heuristic;
- lr2.name = "NoVote";
+ lr2.desiredRefreshRate = 60.0f;
+ lr2.name = "60Hz Heuristic";
refreshRateConfigs->getRefreshRateForContentV2(layers, true, &touchConsidered);
EXPECT_EQ(false, touchConsidered);
@@ -1146,15 +1148,17 @@
lr1.desiredRefreshRate = 60.0f;
lr1.name = "60Hz ExplicitExactOrMultiple";
lr2.vote = LayerVoteType::Heuristic;
- lr2.name = "NoVote";
+ lr2.desiredRefreshRate = 60.0f;
+ lr2.name = "60Hz Heuristic";
refreshRateConfigs->getRefreshRateForContentV2(layers, true, &touchConsidered);
EXPECT_EQ(true, touchConsidered);
lr1.vote = LayerVoteType::ExplicitDefault;
lr1.desiredRefreshRate = 60.0f;
- lr1.name = "60Hz ExplicitExactrMultiple";
+ lr1.name = "60Hz ExplicitExactOrMultiple";
lr2.vote = LayerVoteType::Heuristic;
- lr2.name = "NoVote";
+ lr2.desiredRefreshRate = 60.0f;
+ lr2.name = "60Hz Heuristic";
refreshRateConfigs->getRefreshRateForContentV2(layers, true, &touchConsidered);
EXPECT_EQ(false, touchConsidered);
}
@@ -1227,6 +1231,59 @@
.getConfigId());
}
+TEST_F(RefreshRateConfigsTest, primaryVsAppRequestPolicy) {
+ auto refreshRateConfigs =
+ std::make_unique<RefreshRateConfigs>(m60_90Device,
+ /*currentConfigId=*/HWC_CONFIG_ID_60);
+
+ auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+ layers[0].name = "Test layer";
+
+ // Return the config ID from calling getRefreshRateForContentV2() for a single layer with the
+ // given voteType and fps.
+ auto getFrameRate = [&](LayerVoteType voteType, float fps,
+ bool touchActive = false) -> HwcConfigIndexType {
+ layers[0].vote = voteType;
+ layers[0].desiredRefreshRate = fps;
+ bool touchConsidered;
+ return refreshRateConfigs->getRefreshRateForContentV2(layers, touchActive, &touchConsidered)
+ .getConfigId();
+ };
+
+ ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy(
+ {HWC_CONFIG_ID_60, {60.f, 60.f}, {60.f, 90.f}}),
+ 0);
+ bool touchConsidered;
+ EXPECT_EQ(HWC_CONFIG_ID_60,
+ refreshRateConfigs
+ ->getRefreshRateForContentV2({}, /*touchActive=*/false, &touchConsidered)
+ .getConfigId());
+ EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::NoVote, 90.f));
+ EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::Min, 90.f));
+ EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::Max, 90.f));
+ EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::Heuristic, 90.f));
+ EXPECT_EQ(HWC_CONFIG_ID_90, getFrameRate(LayerVoteType::ExplicitDefault, 90.f));
+ EXPECT_EQ(HWC_CONFIG_ID_90, getFrameRate(LayerVoteType::ExplicitExactOrMultiple, 90.f));
+
+ // Touch boost should be restricted to the primary range.
+ EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::Max, 90.f, /*touch=*/true));
+ // When we're higher than the primary range max due to a layer frame rate setting, touch boost
+ // shouldn't drag us back down to the primary range max.
+ EXPECT_EQ(HWC_CONFIG_ID_90, getFrameRate(LayerVoteType::ExplicitDefault, 90.f, /*touch=*/true));
+ EXPECT_EQ(HWC_CONFIG_ID_90,
+ getFrameRate(LayerVoteType::ExplicitExactOrMultiple, 90.f, /*touch=*/true));
+
+ ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy(
+ {HWC_CONFIG_ID_60, {60.f, 60.f}, {60.f, 60.f}}),
+ 0);
+ EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::NoVote, 90.f));
+ EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::Min, 90.f));
+ EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::Max, 90.f));
+ EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::Heuristic, 90.f));
+ EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::ExplicitDefault, 90.f));
+ EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::ExplicitExactOrMultiple, 90.f));
+}
+
} // namespace
} // namespace scheduler
} // namespace android
diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp
index a44b9e7..d3ed88d 100644
--- a/vulkan/libvulkan/swapchain.cpp
+++ b/vulkan/libvulkan/swapchain.cpp
@@ -1478,7 +1478,7 @@
ANativeWindowBuffer* buffer;
int fence_fd;
err = window->dequeueBuffer(window, &buffer, &fence_fd);
- if (err == android::TIMED_OUT) {
+ if (err == android::TIMED_OUT || err == android::INVALID_OPERATION) {
ALOGW("dequeueBuffer timed out: %s (%d)", strerror(-err), err);
return timeout ? VK_TIMEOUT : VK_NOT_READY;
} else if (err != android::OK) {