Merge "Split refresh rate range into two ranges" into rvc-dev am: 5724666853
Change-Id: I3ab1225ff065704a3c560a487ff0a4e9781960d7
This commit is contained in:
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
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, minRefreshRate, maxRefreshRate);
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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)));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user