summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/view/SurfaceControl.java48
-rw-r--r--core/jni/android_view_SurfaceControl.cpp64
-rw-r--r--services/core/java/com/android/server/display/DisplayModeDirector.java183
-rw-r--r--services/core/java/com/android/server/display/LocalDisplayAdapter.java17
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java2
-rw-r--r--services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java92
6 files changed, 284 insertions, 122 deletions
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 76ed37c51bfe..22fb6ace1547 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -1464,8 +1464,23 @@ public final class SurfaceControl implements Parcelable {
*/
public static final class DesiredDisplayConfigSpecs {
public int defaultConfig;
- public float minRefreshRate;
- public float maxRefreshRate;
+ /**
+ * The primary refresh rate range represents display manager's general guidance on the
+ * display configs surface flinger will consider when switching refresh rates. Unless
+ * surface flinger has a specific reason to do otherwise, it will stay within this range.
+ */
+ public float primaryRefreshRateMin;
+ public float primaryRefreshRateMax;
+ /**
+ * The app request refresh rate range allows surface flinger to consider more display
+ * configs when switching refresh rates. Although surface flinger will generally stay within
+ * the primary range, specific considerations, such as layer frame rate settings specified
+ * via the setFrameRate() api, may cause surface flinger to go outside the primary
+ * range. Surface flinger never goes outside the app request range. The app request range
+ * will be greater than or equal to the primary refresh rate range, never smaller.
+ */
+ public float appRequestRefreshRateMin;
+ public float appRequestRefreshRateMax;
public DesiredDisplayConfigSpecs() {}
@@ -1473,11 +1488,14 @@ public final class SurfaceControl implements Parcelable {
copyFrom(other);
}
- public DesiredDisplayConfigSpecs(
- int defaultConfig, float minRefreshRate, float maxRefreshRate) {
+ public DesiredDisplayConfigSpecs(int defaultConfig, float primaryRefreshRateMin,
+ float primaryRefreshRateMax, float appRequestRefreshRateMin,
+ float appRequestRefreshRateMax) {
this.defaultConfig = defaultConfig;
- this.minRefreshRate = minRefreshRate;
- this.maxRefreshRate = maxRefreshRate;
+ this.primaryRefreshRateMin = primaryRefreshRateMin;
+ this.primaryRefreshRateMax = primaryRefreshRateMax;
+ this.appRequestRefreshRateMin = appRequestRefreshRateMin;
+ this.appRequestRefreshRateMax = appRequestRefreshRateMax;
}
@Override
@@ -1490,8 +1508,10 @@ public final class SurfaceControl implements Parcelable {
*/
public boolean equals(DesiredDisplayConfigSpecs other) {
return other != null && defaultConfig == other.defaultConfig
- && minRefreshRate == other.minRefreshRate
- && maxRefreshRate == other.maxRefreshRate;
+ && primaryRefreshRateMin == other.primaryRefreshRateMin
+ && primaryRefreshRateMax == other.primaryRefreshRateMax
+ && appRequestRefreshRateMin == other.appRequestRefreshRateMin
+ && appRequestRefreshRateMax == other.appRequestRefreshRateMax;
}
@Override
@@ -1504,14 +1524,18 @@ public final class SurfaceControl implements Parcelable {
*/
public void copyFrom(DesiredDisplayConfigSpecs other) {
defaultConfig = other.defaultConfig;
- minRefreshRate = other.minRefreshRate;
- maxRefreshRate = other.maxRefreshRate;
+ primaryRefreshRateMin = other.primaryRefreshRateMin;
+ primaryRefreshRateMax = other.primaryRefreshRateMax;
+ appRequestRefreshRateMin = other.appRequestRefreshRateMin;
+ appRequestRefreshRateMax = other.appRequestRefreshRateMax;
}
@Override
public String toString() {
- return String.format("defaultConfig=%d min=%.0f max=%.0f", defaultConfig,
- minRefreshRate, maxRefreshRate);
+ return String.format("defaultConfig=%d primaryRefreshRateRange=[%.0f %.0f]"
+ + " appRequestRefreshRateRange=[%.0f %.0f]",
+ defaultConfig, primaryRefreshRateMin, primaryRefreshRateMax,
+ appRequestRefreshRateMin, appRequestRefreshRateMax);
}
}
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index 58697875b2c3..36b4b6aad4b4 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -174,8 +174,10 @@ static struct {
jclass clazz;
jmethodID ctor;
jfieldID defaultConfig;
- jfieldID minRefreshRate;
- jfieldID maxRefreshRate;
+ jfieldID primaryRefreshRateMin;
+ jfieldID primaryRefreshRateMax;
+ jfieldID appRequestRefreshRateMin;
+ jfieldID appRequestRefreshRateMax;
} gDesiredDisplayConfigSpecsClassInfo;
class JNamedColorSpace {
@@ -919,13 +921,24 @@ static jboolean nativeSetDesiredDisplayConfigSpecs(JNIEnv* env, jclass clazz, jo
jint defaultConfig = env->GetIntField(desiredDisplayConfigSpecs,
gDesiredDisplayConfigSpecsClassInfo.defaultConfig);
- jfloat minRefreshRate = env->GetFloatField(desiredDisplayConfigSpecs,
- gDesiredDisplayConfigSpecsClassInfo.minRefreshRate);
- jfloat maxRefreshRate = env->GetFloatField(desiredDisplayConfigSpecs,
- gDesiredDisplayConfigSpecsClassInfo.maxRefreshRate);
-
- size_t result = SurfaceComposerClient::setDesiredDisplayConfigSpecs(
- token, defaultConfig, minRefreshRate, maxRefreshRate);
+ jfloat primaryRefreshRateMin =
+ env->GetFloatField(desiredDisplayConfigSpecs,
+ gDesiredDisplayConfigSpecsClassInfo.primaryRefreshRateMin);
+ jfloat primaryRefreshRateMax =
+ env->GetFloatField(desiredDisplayConfigSpecs,
+ gDesiredDisplayConfigSpecsClassInfo.primaryRefreshRateMax);
+ jfloat appRequestRefreshRateMin =
+ env->GetFloatField(desiredDisplayConfigSpecs,
+ gDesiredDisplayConfigSpecsClassInfo.appRequestRefreshRateMin);
+ jfloat appRequestRefreshRateMax =
+ env->GetFloatField(desiredDisplayConfigSpecs,
+ gDesiredDisplayConfigSpecsClassInfo.appRequestRefreshRateMax);
+
+ size_t result = SurfaceComposerClient::setDesiredDisplayConfigSpecs(token, defaultConfig,
+ primaryRefreshRateMin,
+ primaryRefreshRateMax,
+ appRequestRefreshRateMin,
+ appRequestRefreshRateMax);
return result == NO_ERROR ? JNI_TRUE : JNI_FALSE;
}
@@ -934,16 +947,23 @@ static jobject nativeGetDesiredDisplayConfigSpecs(JNIEnv* env, jclass clazz, job
if (token == nullptr) return nullptr;
int32_t defaultConfig;
- float minRefreshRate;
- float maxRefreshRate;
- if (SurfaceComposerClient::getDesiredDisplayConfigSpecs(token, &defaultConfig, &minRefreshRate,
- &maxRefreshRate) != NO_ERROR) {
+ float primaryRefreshRateMin;
+ float primaryRefreshRateMax;
+ float appRequestRefreshRateMin;
+ float appRequestRefreshRateMax;
+ if (SurfaceComposerClient::getDesiredDisplayConfigSpecs(token, &defaultConfig,
+ &primaryRefreshRateMin,
+ &primaryRefreshRateMax,
+ &appRequestRefreshRateMin,
+ &appRequestRefreshRateMax) !=
+ NO_ERROR) {
return nullptr;
}
return env->NewObject(gDesiredDisplayConfigSpecsClassInfo.clazz,
- gDesiredDisplayConfigSpecsClassInfo.ctor, defaultConfig, minRefreshRate,
- maxRefreshRate);
+ gDesiredDisplayConfigSpecsClassInfo.ctor, defaultConfig,
+ primaryRefreshRateMin, primaryRefreshRateMax, appRequestRefreshRateMin,
+ appRequestRefreshRateMax);
}
static jint nativeGetActiveConfig(JNIEnv* env, jclass clazz, jobject tokenObj) {
@@ -1757,13 +1777,17 @@ int register_android_view_SurfaceControl(JNIEnv* env)
gDesiredDisplayConfigSpecsClassInfo.clazz =
MakeGlobalRefOrDie(env, desiredDisplayConfigSpecsClazz);
gDesiredDisplayConfigSpecsClassInfo.ctor =
- GetMethodIDOrDie(env, gDesiredDisplayConfigSpecsClassInfo.clazz, "<init>", "(IFF)V");
+ GetMethodIDOrDie(env, gDesiredDisplayConfigSpecsClassInfo.clazz, "<init>", "(IFFFF)V");
gDesiredDisplayConfigSpecsClassInfo.defaultConfig =
GetFieldIDOrDie(env, desiredDisplayConfigSpecsClazz, "defaultConfig", "I");
- gDesiredDisplayConfigSpecsClassInfo.minRefreshRate =
- GetFieldIDOrDie(env, desiredDisplayConfigSpecsClazz, "minRefreshRate", "F");
- gDesiredDisplayConfigSpecsClassInfo.maxRefreshRate =
- GetFieldIDOrDie(env, desiredDisplayConfigSpecsClazz, "maxRefreshRate", "F");
+ gDesiredDisplayConfigSpecsClassInfo.primaryRefreshRateMin =
+ GetFieldIDOrDie(env, desiredDisplayConfigSpecsClazz, "primaryRefreshRateMin", "F");
+ gDesiredDisplayConfigSpecsClassInfo.primaryRefreshRateMax =
+ GetFieldIDOrDie(env, desiredDisplayConfigSpecsClazz, "primaryRefreshRateMax", "F");
+ gDesiredDisplayConfigSpecsClassInfo.appRequestRefreshRateMin =
+ GetFieldIDOrDie(env, desiredDisplayConfigSpecsClazz, "appRequestRefreshRateMin", "F");
+ gDesiredDisplayConfigSpecsClassInfo.appRequestRefreshRateMax =
+ GetFieldIDOrDie(env, desiredDisplayConfigSpecsClazz, "appRequestRefreshRateMax", "F");
return err;
}
diff --git a/services/core/java/com/android/server/display/DisplayModeDirector.java b/services/core/java/com/android/server/display/DisplayModeDirector.java
index 612fd39634ea..c54ebf87e558 100644
--- a/services/core/java/com/android/server/display/DisplayModeDirector.java
+++ b/services/core/java/com/android/server/display/DisplayModeDirector.java
@@ -152,6 +152,47 @@ public class DisplayModeDirector {
return votes;
}
+ private static final class VoteSummary {
+ public float minRefreshRate;
+ public float maxRefreshRate;
+ public int width;
+ public int height;
+
+ VoteSummary() {
+ reset();
+ }
+
+ public void reset() {
+ minRefreshRate = 0f;
+ maxRefreshRate = Float.POSITIVE_INFINITY;
+ width = Vote.INVALID_SIZE;
+ height = Vote.INVALID_SIZE;
+ }
+ }
+
+ // VoteSummary is returned as an output param to cut down a bit on the number of temporary
+ // objects.
+ private void summarizeVotes(
+ SparseArray<Vote> votes, int lowestConsideredPriority, /*out*/ VoteSummary summary) {
+ summary.reset();
+ for (int priority = Vote.MAX_PRIORITY; priority >= lowestConsideredPriority; priority--) {
+ Vote vote = votes.get(priority);
+ if (vote == null) {
+ continue;
+ }
+ // For refresh rates, just use the tightest bounds of all the votes
+ summary.minRefreshRate = Math.max(summary.minRefreshRate, vote.refreshRateRange.min);
+ summary.maxRefreshRate = Math.min(summary.maxRefreshRate, vote.refreshRateRange.max);
+ // For display size, use only the first vote we come across (i.e. the highest
+ // priority vote that includes the width / height).
+ if (summary.height == Vote.INVALID_SIZE && summary.width == Vote.INVALID_SIZE
+ && vote.height > 0 && vote.width > 0) {
+ summary.width = vote.width;
+ summary.height = vote.height;
+ }
+ }
+ }
+
/**
* Calculates the refresh rate ranges and display modes that the system is allowed to freely
* switch between based on global and display-specific constraints.
@@ -174,52 +215,31 @@ public class DisplayModeDirector {
}
int[] availableModes = new int[]{defaultMode.getModeId()};
- float minRefreshRate = 0f;
- float maxRefreshRate = Float.POSITIVE_INFINITY;
+ VoteSummary primarySummary = new VoteSummary();
int lowestConsideredPriority = Vote.MIN_PRIORITY;
while (lowestConsideredPriority <= Vote.MAX_PRIORITY) {
- minRefreshRate = 0f;
- maxRefreshRate = Float.POSITIVE_INFINITY;
- int height = Vote.INVALID_SIZE;
- int width = Vote.INVALID_SIZE;
-
- for (int priority = Vote.MAX_PRIORITY;
- priority >= lowestConsideredPriority; priority--) {
- Vote vote = votes.get(priority);
- if (vote == null) {
- continue;
- }
- // For refresh rates, just use the tightest bounds of all the votes
- minRefreshRate = Math.max(minRefreshRate, vote.refreshRateRange.min);
- maxRefreshRate = Math.min(maxRefreshRate, vote.refreshRateRange.max);
- // For display size, use only the first vote we come across (i.e. the highest
- // priority vote that includes the width / height).
- if (height == Vote.INVALID_SIZE && width == Vote.INVALID_SIZE
- && vote.height > 0 && vote.width > 0) {
- width = vote.width;
- height = vote.height;
- }
- }
+ summarizeVotes(votes, lowestConsideredPriority, primarySummary);
// If we don't have anything specifying the width / height of the display, just use
// the default width and height. We don't want these switching out from underneath
// us since it's a pretty disruptive behavior.
- if (height == Vote.INVALID_SIZE || width == Vote.INVALID_SIZE) {
- width = defaultMode.getPhysicalWidth();
- height = defaultMode.getPhysicalHeight();
+ if (primarySummary.height == Vote.INVALID_SIZE
+ || primarySummary.width == Vote.INVALID_SIZE) {
+ primarySummary.width = defaultMode.getPhysicalWidth();
+ primarySummary.height = defaultMode.getPhysicalHeight();
}
- availableModes = filterModes(modes, width, height, minRefreshRate, maxRefreshRate);
+ availableModes = filterModes(modes, primarySummary);
if (availableModes.length > 0) {
if (DEBUG) {
Slog.w(TAG, "Found available modes=" + Arrays.toString(availableModes)
+ " with lowest priority considered "
+ Vote.priorityToString(lowestConsideredPriority)
+ " and constraints: "
- + "width=" + width
- + ", height=" + height
- + ", minRefreshRate=" + minRefreshRate
- + ", maxRefreshRate=" + maxRefreshRate);
+ + "width=" + primarySummary.width
+ + ", height=" + primarySummary.height
+ + ", minRefreshRate=" + primarySummary.minRefreshRate
+ + ", maxRefreshRate=" + primarySummary.maxRefreshRate);
}
break;
}
@@ -228,10 +248,10 @@ public class DisplayModeDirector {
Slog.w(TAG, "Couldn't find available modes with lowest priority set to "
+ Vote.priorityToString(lowestConsideredPriority)
+ " and with the following constraints: "
- + "width=" + width
- + ", height=" + height
- + ", minRefreshRate=" + minRefreshRate
- + ", maxRefreshRate=" + maxRefreshRate);
+ + "width=" + primarySummary.width
+ + ", height=" + primarySummary.height
+ + ", minRefreshRate=" + primarySummary.minRefreshRate
+ + ", maxRefreshRate=" + primarySummary.maxRefreshRate);
}
// If we haven't found anything with the current set of votes, drop the
@@ -239,6 +259,20 @@ public class DisplayModeDirector {
lowestConsideredPriority++;
}
+ VoteSummary appRequestSummary = new VoteSummary();
+ summarizeVotes(
+ votes, Vote.APP_REQUEST_REFRESH_RATE_RANGE_PRIORITY_CUTOFF, appRequestSummary);
+ appRequestSummary.minRefreshRate =
+ Math.min(appRequestSummary.minRefreshRate, primarySummary.minRefreshRate);
+ appRequestSummary.maxRefreshRate =
+ Math.max(appRequestSummary.maxRefreshRate, primarySummary.maxRefreshRate);
+ if (DEBUG) {
+ Slog.i(TAG,
+ String.format("App request range: [%.0f %.0f]",
+ appRequestSummary.minRefreshRate,
+ appRequestSummary.maxRefreshRate));
+ }
+
int baseModeId = defaultMode.getModeId();
if (availableModes.length > 0) {
baseModeId = availableModes[0];
@@ -246,20 +280,23 @@ public class DisplayModeDirector {
// filterModes function is going to filter the modes based on the voting system. If
// the application requests a given mode with preferredModeId function, it will be
// stored as baseModeId.
- return new DesiredDisplayModeSpecs(
- baseModeId, new RefreshRateRange(minRefreshRate, maxRefreshRate));
+ return new DesiredDisplayModeSpecs(baseModeId,
+ new RefreshRateRange(
+ primarySummary.minRefreshRate, primarySummary.maxRefreshRate),
+ new RefreshRateRange(
+ appRequestSummary.minRefreshRate, appRequestSummary.maxRefreshRate));
}
}
- private int[] filterModes(Display.Mode[] supportedModes,
- int width, int height, float minRefreshRate, float maxRefreshRate) {
+ private int[] filterModes(Display.Mode[] supportedModes, VoteSummary summary) {
ArrayList<Display.Mode> availableModes = new ArrayList<>();
for (Display.Mode mode : supportedModes) {
- if (mode.getPhysicalWidth() != width || mode.getPhysicalHeight() != height) {
+ if (mode.getPhysicalWidth() != summary.width
+ || mode.getPhysicalHeight() != summary.height) {
if (DEBUG) {
Slog.w(TAG, "Discarding mode " + mode.getModeId() + ", wrong size"
- + ": desiredWidth=" + width
- + ": desiredHeight=" + height
+ + ": desiredWidth=" + summary.width
+ + ": desiredHeight=" + summary.height
+ ": actualWidth=" + mode.getPhysicalWidth()
+ ": actualHeight=" + mode.getPhysicalHeight());
}
@@ -269,13 +306,13 @@ public class DisplayModeDirector {
// Some refresh rates are calculated based on frame timings, so they aren't *exactly*
// equal to expected refresh rate. Given that, we apply a bit of tolerance to this
// comparison.
- if (refreshRate < (minRefreshRate - FLOAT_TOLERANCE)
- || refreshRate > (maxRefreshRate + FLOAT_TOLERANCE)) {
+ if (refreshRate < (summary.minRefreshRate - FLOAT_TOLERANCE)
+ || refreshRate > (summary.maxRefreshRate + FLOAT_TOLERANCE)) {
if (DEBUG) {
Slog.w(TAG, "Discarding mode " + mode.getModeId()
+ ", outside refresh rate bounds"
- + ": minRefreshRate=" + minRefreshRate
- + ", maxRefreshRate=" + maxRefreshRate
+ + ": minRefreshRate=" + summary.minRefreshRate
+ + ", maxRefreshRate=" + summary.maxRefreshRate
+ ", modeRefreshRate=" + refreshRate);
}
continue;
@@ -535,7 +572,7 @@ public class DisplayModeDirector {
/**
* Information about the desired display mode to be set by the system. Includes the base
- * mode ID and refresh rate range.
+ * mode ID and the primary and app request refresh rate ranges.
*
* We have this class in addition to SurfaceControl.DesiredDisplayConfigSpecs to make clear the
* distinction between the config ID / physical index that
@@ -548,17 +585,28 @@ public class DisplayModeDirector {
*/
public int baseModeId;
/**
- * The refresh rate range.
+ * The primary refresh rate range.
*/
- public final RefreshRateRange refreshRateRange;
+ public final RefreshRateRange primaryRefreshRateRange;
+ /**
+ * The app request refresh rate range. Lower priority considerations won't be included in
+ * this range, allowing surface flinger to consider additional refresh rates for apps that
+ * call setFrameRate(). This range will be greater than or equal to the primary refresh rate
+ * range, never smaller.
+ */
+ public final RefreshRateRange appRequestRefreshRateRange;
public DesiredDisplayModeSpecs() {
- refreshRateRange = new RefreshRateRange();
+ primaryRefreshRateRange = new RefreshRateRange();
+ appRequestRefreshRateRange = new RefreshRateRange();
}
- public DesiredDisplayModeSpecs(int baseModeId, @NonNull RefreshRateRange refreshRateRange) {
+ public DesiredDisplayModeSpecs(int baseModeId,
+ @NonNull RefreshRateRange primaryRefreshRateRange,
+ @NonNull RefreshRateRange appRequestRefreshRateRange) {
this.baseModeId = baseModeId;
- this.refreshRateRange = refreshRateRange;
+ this.primaryRefreshRateRange = primaryRefreshRateRange;
+ this.appRequestRefreshRateRange = appRequestRefreshRateRange;
}
/**
@@ -566,8 +614,10 @@ public class DisplayModeDirector {
*/
@Override
public String toString() {
- return String.format("baseModeId=%d min=%.0f max=%.0f", baseModeId,
- refreshRateRange.min, refreshRateRange.max);
+ return String.format("baseModeId=%d primaryRefreshRateRange=[%.0f %.0f]"
+ + " appRequestRefreshRateRange=[%.0f %.0f]",
+ baseModeId, primaryRefreshRateRange.min, primaryRefreshRateRange.max,
+ appRequestRefreshRateRange.min, appRequestRefreshRateRange.max);
}
/**
* Checks whether the two objects have the same values.
@@ -587,7 +637,11 @@ public class DisplayModeDirector {
if (baseModeId != desiredDisplayModeSpecs.baseModeId) {
return false;
}
- if (!refreshRateRange.equals(desiredDisplayModeSpecs.refreshRateRange)) {
+ if (!primaryRefreshRateRange.equals(desiredDisplayModeSpecs.primaryRefreshRateRange)) {
+ return false;
+ }
+ if (!appRequestRefreshRateRange.equals(
+ desiredDisplayModeSpecs.appRequestRefreshRateRange)) {
return false;
}
return true;
@@ -595,7 +649,7 @@ public class DisplayModeDirector {
@Override
public int hashCode() {
- return Objects.hash(baseModeId, refreshRateRange);
+ return Objects.hash(baseModeId, primaryRefreshRateRange, appRequestRefreshRateRange);
}
/**
@@ -603,8 +657,10 @@ public class DisplayModeDirector {
*/
public void copyFrom(DesiredDisplayModeSpecs other) {
baseModeId = other.baseModeId;
- refreshRateRange.min = other.refreshRateRange.min;
- refreshRateRange.max = other.refreshRateRange.max;
+ primaryRefreshRateRange.min = other.primaryRefreshRateRange.min;
+ primaryRefreshRateRange.max = other.primaryRefreshRateRange.max;
+ appRequestRefreshRateRange.min = other.appRequestRefreshRateRange.min;
+ appRequestRefreshRateRange.max = other.appRequestRefreshRateRange.max;
}
}
@@ -637,12 +693,17 @@ public class DisplayModeDirector {
// LOW_POWER_MODE force display to [0, 60HZ] if Settings.Global.LOW_POWER_MODE is on.
public static final int PRIORITY_LOW_POWER_MODE = 5;
- // Whenever a new priority is added, remember to update MIN_PRIORITY and/or MAX_PRIORITY as
- // appropriate, as well as priorityToString.
+ // Whenever a new priority is added, remember to update MIN_PRIORITY, MAX_PRIORITY, and
+ // APP_REQUEST_REFRESH_RATE_RANGE_PRIORITY_CUTOFF, as well as priorityToString.
public static final int MIN_PRIORITY = PRIORITY_LOW_BRIGHTNESS;
public static final int MAX_PRIORITY = PRIORITY_LOW_POWER_MODE;
+ // The cutoff for the app request refresh rate range. Votes with priorities lower than this
+ // value will not be considered when constructing the app request refresh rate range.
+ public static final int APP_REQUEST_REFRESH_RATE_RANGE_PRIORITY_CUTOFF =
+ PRIORITY_APP_REQUEST_REFRESH_RATE;
+
/**
* A value signifying an invalid width or height in a vote.
*/
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index 6132467103a9..4f5a02ad22fa 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -310,9 +310,14 @@ final class LocalDisplayAdapter extends DisplayAdapter {
// list of available modes will take care of updating display config specs.
if (activeBaseMode != NO_DISPLAY_MODE_ID) {
if (mDisplayModeSpecs.baseModeId != activeBaseMode
- || mDisplayModeSpecs.refreshRateRange.min != configSpecs.minRefreshRate
- || mDisplayModeSpecs.refreshRateRange.max
- != configSpecs.maxRefreshRate) {
+ || mDisplayModeSpecs.primaryRefreshRateRange.min
+ != configSpecs.primaryRefreshRateMin
+ || mDisplayModeSpecs.primaryRefreshRateRange.max
+ != configSpecs.primaryRefreshRateMax
+ || mDisplayModeSpecs.appRequestRefreshRateRange.min
+ != configSpecs.appRequestRefreshRateMin
+ || mDisplayModeSpecs.appRequestRefreshRateRange.max
+ != configSpecs.appRequestRefreshRateMax) {
mDisplayModeSpecsInvalid = true;
sendTraversalRequestLocked();
}
@@ -799,8 +804,10 @@ final class LocalDisplayAdapter extends DisplayAdapter {
LocalDisplayDevice::setDesiredDisplayModeSpecsAsync, this,
getDisplayTokenLocked(),
new SurfaceControl.DesiredDisplayConfigSpecs(baseConfigId,
- mDisplayModeSpecs.refreshRateRange.min,
- mDisplayModeSpecs.refreshRateRange.max)));
+ mDisplayModeSpecs.primaryRefreshRateRange.min,
+ mDisplayModeSpecs.primaryRefreshRateRange.max,
+ mDisplayModeSpecs.appRequestRefreshRateRange.min,
+ mDisplayModeSpecs.appRequestRefreshRateRange.max)));
}
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java b/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java
index 6d1530219372..8abddc82a90b 100644
--- a/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java
@@ -308,7 +308,7 @@ public class LocalDisplayAdapterTest {
doReturn(0).when(() -> SurfaceControl.getActiveColorMode(display.token));
doReturn(new int[] { 0 }).when(
() -> SurfaceControl.getDisplayColorModes(display.token));
- doReturn(new SurfaceControl.DesiredDisplayConfigSpecs(0, 60.f, 60.f))
+ doReturn(new SurfaceControl.DesiredDisplayConfigSpecs(0, 60.f, 60.f, 60.f, 60.f))
.when(() -> SurfaceControl.getDesiredDisplayConfigSpecs(display.token));
}
diff --git a/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java b/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java
index 08bd1ee3c389..8137c36ea350 100644
--- a/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java
@@ -16,7 +16,6 @@
package com.android.server.display;
-import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import android.content.Context;
@@ -30,7 +29,6 @@ import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
import com.android.server.display.DisplayModeDirector.DesiredDisplayModeSpecs;
-import com.android.server.display.DisplayModeDirector.RefreshRateRange;
import com.android.server.display.DisplayModeDirector.Vote;
import com.google.common.truth.Truth;
@@ -79,10 +77,12 @@ public class DisplayModeDirectorTest {
int displayId = 0;
// With no votes present, DisplayModeDirector should allow any refresh rate.
- assertEquals(new DesiredDisplayModeSpecs(/*baseModeId=*/60,
- new RefreshRateRange(0f, Float.POSITIVE_INFINITY)),
+ DesiredDisplayModeSpecs modeSpecs =
createDisplayModeDirectorWithDisplayFpsRange(60, 90).getDesiredDisplayModeSpecs(
- displayId));
+ displayId);
+ Truth.assertThat(modeSpecs.baseModeId).isEqualTo(60);
+ Truth.assertThat(modeSpecs.primaryRefreshRateRange.min).isEqualTo(0f);
+ Truth.assertThat(modeSpecs.primaryRefreshRateRange.max).isEqualTo(Float.POSITIVE_INFINITY);
int numPriorities =
DisplayModeDirector.Vote.MAX_PRIORITY - DisplayModeDirector.Vote.MIN_PRIORITY + 1;
@@ -101,10 +101,12 @@ public class DisplayModeDirectorTest {
int priority = Vote.MIN_PRIORITY + i;
votes.put(priority, Vote.forRefreshRates(minFps + i, maxFps - i));
director.injectVotesByDisplay(votesByDisplay);
- assertEquals(new DesiredDisplayModeSpecs(
- /*baseModeId=*/minFps + i,
- new RefreshRateRange(minFps + i, maxFps - i)),
- director.getDesiredDisplayModeSpecs(displayId));
+ modeSpecs = director.getDesiredDisplayModeSpecs(displayId);
+ Truth.assertThat(modeSpecs.baseModeId).isEqualTo(minFps + i);
+ Truth.assertThat(modeSpecs.primaryRefreshRateRange.min)
+ .isEqualTo((float) (minFps + i));
+ Truth.assertThat(modeSpecs.primaryRefreshRateRange.max)
+ .isEqualTo((float) (maxFps - i));
}
}
@@ -119,9 +121,10 @@ public class DisplayModeDirectorTest {
votes.put(Vote.MAX_PRIORITY, Vote.forRefreshRates(65, 85));
votes.put(Vote.MIN_PRIORITY, Vote.forRefreshRates(70, 80));
director.injectVotesByDisplay(votesByDisplay);
- assertEquals(new DesiredDisplayModeSpecs(/*baseModeId=*/70,
- new RefreshRateRange(70, 80)),
- director.getDesiredDisplayModeSpecs(displayId));
+ modeSpecs = director.getDesiredDisplayModeSpecs(displayId);
+ Truth.assertThat(modeSpecs.baseModeId).isEqualTo(70);
+ Truth.assertThat(modeSpecs.primaryRefreshRateRange.min).isEqualTo(70f);
+ Truth.assertThat(modeSpecs.primaryRefreshRateRange.max).isEqualTo(80f);
}
}
@@ -140,8 +143,8 @@ public class DisplayModeDirectorTest {
director.injectVotesByDisplay(votesByDisplay);
DesiredDisplayModeSpecs desiredSpecs = director.getDesiredDisplayModeSpecs(displayId);
- Truth.assertThat(desiredSpecs.refreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(60);
- Truth.assertThat(desiredSpecs.refreshRateRange.max).isWithin(FLOAT_TOLERANCE).of(60);
+ Truth.assertThat(desiredSpecs.primaryRefreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(60);
+ Truth.assertThat(desiredSpecs.primaryRefreshRateRange.max).isWithin(FLOAT_TOLERANCE).of(60);
Truth.assertThat(desiredSpecs.baseModeId).isEqualTo(60);
}
@@ -159,34 +162,77 @@ public class DisplayModeDirectorTest {
votes.put(Vote.PRIORITY_LOW_BRIGHTNESS, Vote.forRefreshRates(60, 60));
director.injectVotesByDisplay(votesByDisplay);
DesiredDisplayModeSpecs desiredSpecs = director.getDesiredDisplayModeSpecs(displayId);
- Truth.assertThat(desiredSpecs.refreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(60);
- Truth.assertThat(desiredSpecs.refreshRateRange.max).isWithin(FLOAT_TOLERANCE).of(60);
+ Truth.assertThat(desiredSpecs.primaryRefreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(60);
+ Truth.assertThat(desiredSpecs.primaryRefreshRateRange.max).isWithin(FLOAT_TOLERANCE).of(60);
votes.clear();
votes.put(Vote.PRIORITY_APP_REQUEST_REFRESH_RATE, Vote.forRefreshRates(60, 90));
votes.put(Vote.PRIORITY_LOW_BRIGHTNESS, Vote.forRefreshRates(90, 90));
director.injectVotesByDisplay(votesByDisplay);
desiredSpecs = director.getDesiredDisplayModeSpecs(displayId);
- Truth.assertThat(desiredSpecs.refreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(90);
- Truth.assertThat(desiredSpecs.refreshRateRange.max).isWithin(FLOAT_TOLERANCE).of(90);
-
+ Truth.assertThat(desiredSpecs.primaryRefreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(90);
+ Truth.assertThat(desiredSpecs.primaryRefreshRateRange.max).isWithin(FLOAT_TOLERANCE).of(90);
votes.clear();
votes.put(Vote.PRIORITY_APP_REQUEST_REFRESH_RATE, Vote.forRefreshRates(90, 90));
votes.put(Vote.PRIORITY_LOW_BRIGHTNESS, Vote.forRefreshRates(60, 60));
director.injectVotesByDisplay(votesByDisplay);
desiredSpecs = director.getDesiredDisplayModeSpecs(displayId);
- Truth.assertThat(desiredSpecs.refreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(90);
- Truth.assertThat(desiredSpecs.refreshRateRange.max).isWithin(FLOAT_TOLERANCE).of(90);
+ Truth.assertThat(desiredSpecs.primaryRefreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(90);
+ Truth.assertThat(desiredSpecs.primaryRefreshRateRange.max).isWithin(FLOAT_TOLERANCE).of(90);
votes.clear();
votes.put(Vote.PRIORITY_APP_REQUEST_REFRESH_RATE, Vote.forRefreshRates(60, 60));
votes.put(Vote.PRIORITY_LOW_BRIGHTNESS, Vote.forRefreshRates(90, 90));
director.injectVotesByDisplay(votesByDisplay);
desiredSpecs = director.getDesiredDisplayModeSpecs(displayId);
- Truth.assertThat(desiredSpecs.refreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(60);
- Truth.assertThat(desiredSpecs.refreshRateRange.max).isWithin(FLOAT_TOLERANCE).of(60);
+ Truth.assertThat(desiredSpecs.primaryRefreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(60);
+ Truth.assertThat(desiredSpecs.primaryRefreshRateRange.max).isWithin(FLOAT_TOLERANCE).of(60);
+ }
+ @Test
+ public void testAppRequestRefreshRateRange() {
+ // Confirm that the app request range doesn't include low brightness or min refresh rate
+ // settings, but does include everything else.
+ assertTrue(
+ Vote.PRIORITY_LOW_BRIGHTNESS < Vote.APP_REQUEST_REFRESH_RATE_RANGE_PRIORITY_CUTOFF);
+ assertTrue(Vote.PRIORITY_USER_SETTING_MIN_REFRESH_RATE
+ < Vote.APP_REQUEST_REFRESH_RATE_RANGE_PRIORITY_CUTOFF);
+ assertTrue(Vote.PRIORITY_APP_REQUEST_REFRESH_RATE
+ >= Vote.APP_REQUEST_REFRESH_RATE_RANGE_PRIORITY_CUTOFF);
+ int displayId = 0;
+ DisplayModeDirector director = createDisplayModeDirectorWithDisplayFpsRange(60, 90);
+ SparseArray<Vote> votes = new SparseArray<>();
+ SparseArray<SparseArray<Vote>> votesByDisplay = new SparseArray<>();
+ votesByDisplay.put(displayId, votes);
+ votes.put(Vote.PRIORITY_LOW_BRIGHTNESS, Vote.forRefreshRates(60, 60));
+ director.injectVotesByDisplay(votesByDisplay);
+ DesiredDisplayModeSpecs desiredSpecs = director.getDesiredDisplayModeSpecs(displayId);
+ Truth.assertThat(desiredSpecs.primaryRefreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(60);
+ Truth.assertThat(desiredSpecs.primaryRefreshRateRange.max).isWithin(FLOAT_TOLERANCE).of(60);
+ Truth.assertThat(desiredSpecs.appRequestRefreshRateRange.min).isAtMost(60f);
+ Truth.assertThat(desiredSpecs.appRequestRefreshRateRange.max).isAtLeast(90f);
+
+ votes.put(Vote.PRIORITY_USER_SETTING_MIN_REFRESH_RATE,
+ Vote.forRefreshRates(90, Float.POSITIVE_INFINITY));
+ director.injectVotesByDisplay(votesByDisplay);
+ desiredSpecs = director.getDesiredDisplayModeSpecs(displayId);
+ Truth.assertThat(desiredSpecs.primaryRefreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(90);
+ Truth.assertThat(desiredSpecs.primaryRefreshRateRange.max).isAtLeast(90f);
+ Truth.assertThat(desiredSpecs.appRequestRefreshRateRange.min).isAtMost(60f);
+ Truth.assertThat(desiredSpecs.appRequestRefreshRateRange.max).isAtLeast(90f);
+
+ votes.put(Vote.PRIORITY_APP_REQUEST_REFRESH_RATE, Vote.forRefreshRates(75, 75));
+ director.injectVotesByDisplay(votesByDisplay);
+ desiredSpecs = director.getDesiredDisplayModeSpecs(displayId);
+ Truth.assertThat(desiredSpecs.primaryRefreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(75);
+ Truth.assertThat(desiredSpecs.primaryRefreshRateRange.max).isWithin(FLOAT_TOLERANCE).of(75);
+ Truth.assertThat(desiredSpecs.appRequestRefreshRateRange.min)
+ .isWithin(FLOAT_TOLERANCE)
+ .of(75);
+ Truth.assertThat(desiredSpecs.appRequestRefreshRateRange.max)
+ .isWithin(FLOAT_TOLERANCE)
+ .of(75);
}
}