diff options
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); } } |