Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 305a57c5 authored by Steven Thomas's avatar Steven Thomas
Browse files

Split refresh rate range into two ranges

To prevent low-priority refresh rate considerations from overriding the
app frame rate as specified via the new setFrameRate() api, split the
display refresh rate range into "primary" and "app request" ranges. The
primary range includes the low priority considerations, while the app
request range removes two lower priority considerations.

In general, surface flinger will keep the display refresh rate within
the primary range, but layers with frame rate settings via the
setFrameRate() api may cause surface flinger to pick a refresh rate
outside the primary range. Surface flinger will never choose a refresh
rate outside the app request range specified by display manager.

Bug: 148978562

Test: - Added a new unit test to DisplayModeDirectorTest to verify that
        display manager strips lower priority considerations when
        deciding the app request range.

- Added a new unit test to RefreshRateConfigsTest to verify
  RefreshRateConfigs handles the primary vs app request range
  correctly.

- Manual test: Confirmed that with the "force 90Hz refresh rate" option
  turned on, we don't switch to 60Hz when playing a 60Hz video.

- Manual test: Confirmed that with the "force 90Hz refresh rate" option
  turned on, when an app calls setFrameRate(60), we stay at 60Hz.

- Manual test: Modified a Pixel 4 XL to prefer 60Hz in low brightness,
  entered low brightness, and confirmed we don't touch boost to 90Hz.

- Manual test: Confirmed that Maps stays at 60Hz on Pixel 4.

- Manual test: Turned on verbose logs in RefreshRateConfigs.cpp,
  confirmed they look good.

- Manual test: Inspected dumpsys output, confirmed the primary and
  app request refresh rate ranges are printed correctly.

Change-Id: I2a7f5ded0831c90b9b1ac09d941963a63b824098
parent 4502a6b1
Loading
Loading
Loading
Loading
+36 −12
Original line number Original line Diff line number Diff line
@@ -1464,8 +1464,23 @@ public final class SurfaceControl implements Parcelable {
     */
     */
    public static final class DesiredDisplayConfigSpecs {
    public static final class DesiredDisplayConfigSpecs {
        public int defaultConfig;
        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() {}
        public DesiredDisplayConfigSpecs() {}


@@ -1473,11 +1488,14 @@ public final class SurfaceControl implements Parcelable {
            copyFrom(other);
            copyFrom(other);
        }
        }


        public DesiredDisplayConfigSpecs(
        public DesiredDisplayConfigSpecs(int defaultConfig, float primaryRefreshRateMin,
                int defaultConfig, float minRefreshRate, float maxRefreshRate) {
                float primaryRefreshRateMax, float appRequestRefreshRateMin,
                float appRequestRefreshRateMax) {
            this.defaultConfig = defaultConfig;
            this.defaultConfig = defaultConfig;
            this.minRefreshRate = minRefreshRate;
            this.primaryRefreshRateMin = primaryRefreshRateMin;
            this.maxRefreshRate = maxRefreshRate;
            this.primaryRefreshRateMax = primaryRefreshRateMax;
            this.appRequestRefreshRateMin = appRequestRefreshRateMin;
            this.appRequestRefreshRateMax = appRequestRefreshRateMax;
        }
        }


        @Override
        @Override
@@ -1490,8 +1508,10 @@ public final class SurfaceControl implements Parcelable {
         */
         */
        public boolean equals(DesiredDisplayConfigSpecs other) {
        public boolean equals(DesiredDisplayConfigSpecs other) {
            return other != null && defaultConfig == other.defaultConfig
            return other != null && defaultConfig == other.defaultConfig
                    && minRefreshRate == other.minRefreshRate
                    && primaryRefreshRateMin == other.primaryRefreshRateMin
                    && maxRefreshRate == other.maxRefreshRate;
                    && primaryRefreshRateMax == other.primaryRefreshRateMax
                    && appRequestRefreshRateMin == other.appRequestRefreshRateMin
                    && appRequestRefreshRateMax == other.appRequestRefreshRateMax;
        }
        }


        @Override
        @Override
@@ -1504,14 +1524,18 @@ public final class SurfaceControl implements Parcelable {
         */
         */
        public void copyFrom(DesiredDisplayConfigSpecs other) {
        public void copyFrom(DesiredDisplayConfigSpecs other) {
            defaultConfig = other.defaultConfig;
            defaultConfig = other.defaultConfig;
            minRefreshRate = other.minRefreshRate;
            primaryRefreshRateMin = other.primaryRefreshRateMin;
            maxRefreshRate = other.maxRefreshRate;
            primaryRefreshRateMax = other.primaryRefreshRateMax;
            appRequestRefreshRateMin = other.appRequestRefreshRateMin;
            appRequestRefreshRateMax = other.appRequestRefreshRateMax;
        }
        }


        @Override
        @Override
        public String toString() {
        public String toString() {
            return String.format("defaultConfig=%d min=%.0f max=%.0f", defaultConfig,
            return String.format("defaultConfig=%d primaryRefreshRateRange=[%.0f %.0f]"
                    minRefreshRate, maxRefreshRate);
                            + " appRequestRefreshRateRange=[%.0f %.0f]",
                    defaultConfig, primaryRefreshRateMin, primaryRefreshRateMax,
                    appRequestRefreshRateMin, appRequestRefreshRateMax);
        }
        }
    }
    }


+44 −20
Original line number Original line Diff line number Diff line
@@ -174,8 +174,10 @@ static struct {
    jclass clazz;
    jclass clazz;
    jmethodID ctor;
    jmethodID ctor;
    jfieldID defaultConfig;
    jfieldID defaultConfig;
    jfieldID minRefreshRate;
    jfieldID primaryRefreshRateMin;
    jfieldID maxRefreshRate;
    jfieldID primaryRefreshRateMax;
    jfieldID appRequestRefreshRateMin;
    jfieldID appRequestRefreshRateMax;
} gDesiredDisplayConfigSpecsClassInfo;
} gDesiredDisplayConfigSpecsClassInfo;


class JNamedColorSpace {
class JNamedColorSpace {
@@ -919,13 +921,24 @@ static jboolean nativeSetDesiredDisplayConfigSpecs(JNIEnv* env, jclass clazz, jo


    jint defaultConfig = env->GetIntField(desiredDisplayConfigSpecs,
    jint defaultConfig = env->GetIntField(desiredDisplayConfigSpecs,
                                          gDesiredDisplayConfigSpecsClassInfo.defaultConfig);
                                          gDesiredDisplayConfigSpecsClassInfo.defaultConfig);
    jfloat minRefreshRate = env->GetFloatField(desiredDisplayConfigSpecs,
    jfloat primaryRefreshRateMin =
                                               gDesiredDisplayConfigSpecsClassInfo.minRefreshRate);
            env->GetFloatField(desiredDisplayConfigSpecs,
    jfloat maxRefreshRate = env->GetFloatField(desiredDisplayConfigSpecs,
                               gDesiredDisplayConfigSpecsClassInfo.primaryRefreshRateMin);
                                               gDesiredDisplayConfigSpecsClassInfo.maxRefreshRate);
    jfloat primaryRefreshRateMax =

            env->GetFloatField(desiredDisplayConfigSpecs,
    size_t result = SurfaceComposerClient::setDesiredDisplayConfigSpecs(
                               gDesiredDisplayConfigSpecsClassInfo.primaryRefreshRateMax);
            token, defaultConfig, minRefreshRate, maxRefreshRate);
    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;
    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;
    if (token == nullptr) return nullptr;


    int32_t defaultConfig;
    int32_t defaultConfig;
    float minRefreshRate;
    float primaryRefreshRateMin;
    float maxRefreshRate;
    float primaryRefreshRateMax;
    if (SurfaceComposerClient::getDesiredDisplayConfigSpecs(token, &defaultConfig, &minRefreshRate,
    float appRequestRefreshRateMin;
                                                            &maxRefreshRate) != NO_ERROR) {
    float appRequestRefreshRateMax;
    if (SurfaceComposerClient::getDesiredDisplayConfigSpecs(token, &defaultConfig,
                                                            &primaryRefreshRateMin,
                                                            &primaryRefreshRateMax,
                                                            &appRequestRefreshRateMin,
                                                            &appRequestRefreshRateMax) !=
        NO_ERROR) {
        return nullptr;
        return nullptr;
    }
    }


    return env->NewObject(gDesiredDisplayConfigSpecsClassInfo.clazz,
    return env->NewObject(gDesiredDisplayConfigSpecsClassInfo.clazz,
                          gDesiredDisplayConfigSpecsClassInfo.ctor, defaultConfig, minRefreshRate,
                          gDesiredDisplayConfigSpecsClassInfo.ctor, defaultConfig,
                          maxRefreshRate);
                          primaryRefreshRateMin, primaryRefreshRateMax, appRequestRefreshRateMin,
                          appRequestRefreshRateMax);
}
}


static jint nativeGetActiveConfig(JNIEnv* env, jclass clazz, jobject tokenObj) {
static jint nativeGetActiveConfig(JNIEnv* env, jclass clazz, jobject tokenObj) {
@@ -1757,13 +1777,17 @@ int register_android_view_SurfaceControl(JNIEnv* env)
    gDesiredDisplayConfigSpecsClassInfo.clazz =
    gDesiredDisplayConfigSpecsClassInfo.clazz =
            MakeGlobalRefOrDie(env, desiredDisplayConfigSpecsClazz);
            MakeGlobalRefOrDie(env, desiredDisplayConfigSpecsClazz);
    gDesiredDisplayConfigSpecsClassInfo.ctor =
    gDesiredDisplayConfigSpecsClassInfo.ctor =
            GetMethodIDOrDie(env, gDesiredDisplayConfigSpecsClassInfo.clazz, "<init>", "(IFF)V");
            GetMethodIDOrDie(env, gDesiredDisplayConfigSpecsClassInfo.clazz, "<init>", "(IFFFF)V");
    gDesiredDisplayConfigSpecsClassInfo.defaultConfig =
    gDesiredDisplayConfigSpecsClassInfo.defaultConfig =
            GetFieldIDOrDie(env, desiredDisplayConfigSpecsClazz, "defaultConfig", "I");
            GetFieldIDOrDie(env, desiredDisplayConfigSpecsClazz, "defaultConfig", "I");
    gDesiredDisplayConfigSpecsClassInfo.minRefreshRate =
    gDesiredDisplayConfigSpecsClassInfo.primaryRefreshRateMin =
            GetFieldIDOrDie(env, desiredDisplayConfigSpecsClazz, "minRefreshRate", "F");
            GetFieldIDOrDie(env, desiredDisplayConfigSpecsClazz, "primaryRefreshRateMin", "F");
    gDesiredDisplayConfigSpecsClassInfo.maxRefreshRate =
    gDesiredDisplayConfigSpecsClassInfo.primaryRefreshRateMax =
            GetFieldIDOrDie(env, desiredDisplayConfigSpecsClazz, "maxRefreshRate", "F");
            GetFieldIDOrDie(env, desiredDisplayConfigSpecsClazz, "primaryRefreshRateMax", "F");
    gDesiredDisplayConfigSpecsClassInfo.appRequestRefreshRateMin =
            GetFieldIDOrDie(env, desiredDisplayConfigSpecsClazz, "appRequestRefreshRateMin", "F");
    gDesiredDisplayConfigSpecsClassInfo.appRequestRefreshRateMax =
            GetFieldIDOrDie(env, desiredDisplayConfigSpecsClazz, "appRequestRefreshRateMax", "F");


    return err;
    return err;
}
}
+122 −61
Original line number Original line Diff line number Diff line
@@ -152,6 +152,47 @@ public class DisplayModeDirector {
        return votes;
        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
     * Calculates the refresh rate ranges and display modes that the system is allowed to freely
     * switch between based on global and display-specific constraints.
     * switch between based on global and display-specific constraints.
@@ -174,52 +215,31 @@ public class DisplayModeDirector {
            }
            }


            int[] availableModes = new int[]{defaultMode.getModeId()};
            int[] availableModes = new int[]{defaultMode.getModeId()};
            float minRefreshRate = 0f;
            VoteSummary primarySummary = new VoteSummary();
            float maxRefreshRate = Float.POSITIVE_INFINITY;
            int lowestConsideredPriority = Vote.MIN_PRIORITY;
            int lowestConsideredPriority = Vote.MIN_PRIORITY;
            while (lowestConsideredPriority <= Vote.MAX_PRIORITY) {
            while (lowestConsideredPriority <= Vote.MAX_PRIORITY) {
                minRefreshRate = 0f;
                summarizeVotes(votes, lowestConsideredPriority, primarySummary);
                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;
                    }
                }


                // If we don't have anything specifying the width / height of the display, just use
                // 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
                // the default width and height. We don't want these switching out from underneath
                // us since it's a pretty disruptive behavior.
                // us since it's a pretty disruptive behavior.
                if (height == Vote.INVALID_SIZE || width == Vote.INVALID_SIZE) {
                if (primarySummary.height == Vote.INVALID_SIZE
                    width = defaultMode.getPhysicalWidth();
                        || primarySummary.width == Vote.INVALID_SIZE) {
                    height = defaultMode.getPhysicalHeight();
                    primarySummary.width = defaultMode.getPhysicalWidth();
                    primarySummary.height = defaultMode.getPhysicalHeight();
                }
                }


                availableModes = filterModes(modes, width, height, minRefreshRate, maxRefreshRate);
                availableModes = filterModes(modes, primarySummary);
                if (availableModes.length > 0) {
                if (availableModes.length > 0) {
                    if (DEBUG) {
                    if (DEBUG) {
                        Slog.w(TAG, "Found available modes=" + Arrays.toString(availableModes)
                        Slog.w(TAG, "Found available modes=" + Arrays.toString(availableModes)
                                + " with lowest priority considered "
                                + " with lowest priority considered "
                                + Vote.priorityToString(lowestConsideredPriority)
                                + Vote.priorityToString(lowestConsideredPriority)
                                + " and constraints: "
                                + " and constraints: "
                                + "width=" + width
                                + "width=" + primarySummary.width
                                + ", height=" + height
                                + ", height=" + primarySummary.height
                                + ", minRefreshRate=" + minRefreshRate
                                + ", minRefreshRate=" + primarySummary.minRefreshRate
                                + ", maxRefreshRate=" + maxRefreshRate);
                                + ", maxRefreshRate=" + primarySummary.maxRefreshRate);
                    }
                    }
                    break;
                    break;
                }
                }
@@ -228,10 +248,10 @@ public class DisplayModeDirector {
                    Slog.w(TAG, "Couldn't find available modes with lowest priority set to "
                    Slog.w(TAG, "Couldn't find available modes with lowest priority set to "
                            + Vote.priorityToString(lowestConsideredPriority)
                            + Vote.priorityToString(lowestConsideredPriority)
                            + " and with the following constraints: "
                            + " and with the following constraints: "
                            + "width=" + width
                            + "width=" + primarySummary.width
                            + ", height=" + height
                            + ", height=" + primarySummary.height
                            + ", minRefreshRate=" + minRefreshRate
                            + ", minRefreshRate=" + primarySummary.minRefreshRate
                            + ", maxRefreshRate=" + maxRefreshRate);
                            + ", maxRefreshRate=" + primarySummary.maxRefreshRate);
                }
                }


                // If we haven't found anything with the current set of votes, drop the
                // If we haven't found anything with the current set of votes, drop the
@@ -239,6 +259,20 @@ public class DisplayModeDirector {
                lowestConsideredPriority++;
                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();
            int baseModeId = defaultMode.getModeId();
            if (availableModes.length > 0) {
            if (availableModes.length > 0) {
                baseModeId = availableModes[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
            // 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
            // the application requests a given mode with preferredModeId function, it will be
            // stored as baseModeId.
            // stored as baseModeId.
            return new DesiredDisplayModeSpecs(
            return new DesiredDisplayModeSpecs(baseModeId,
                    baseModeId, new RefreshRateRange(minRefreshRate, maxRefreshRate));
                    new RefreshRateRange(
                            primarySummary.minRefreshRate, primarySummary.maxRefreshRate),
                    new RefreshRateRange(
                            appRequestSummary.minRefreshRate, appRequestSummary.maxRefreshRate));
        }
        }
    }
    }


    private int[] filterModes(Display.Mode[] supportedModes,
    private int[] filterModes(Display.Mode[] supportedModes, VoteSummary summary) {
            int width, int height, float minRefreshRate, float maxRefreshRate) {
        ArrayList<Display.Mode> availableModes = new ArrayList<>();
        ArrayList<Display.Mode> availableModes = new ArrayList<>();
        for (Display.Mode mode : supportedModes) {
        for (Display.Mode mode : supportedModes) {
            if (mode.getPhysicalWidth() != width || mode.getPhysicalHeight() != height) {
            if (mode.getPhysicalWidth() != summary.width
                    || mode.getPhysicalHeight() != summary.height) {
                if (DEBUG) {
                if (DEBUG) {
                    Slog.w(TAG, "Discarding mode " + mode.getModeId() + ", wrong size"
                    Slog.w(TAG, "Discarding mode " + mode.getModeId() + ", wrong size"
                            + ": desiredWidth=" + width
                            + ": desiredWidth=" + summary.width
                            + ": desiredHeight=" + height
                            + ": desiredHeight=" + summary.height
                            + ": actualWidth=" + mode.getPhysicalWidth()
                            + ": actualWidth=" + mode.getPhysicalWidth()
                            + ": actualHeight=" + mode.getPhysicalHeight());
                            + ": actualHeight=" + mode.getPhysicalHeight());
                }
                }
@@ -269,13 +306,13 @@ public class DisplayModeDirector {
            // Some refresh rates are calculated based on frame timings, so they aren't *exactly*
            // 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
            // equal to expected refresh rate. Given that, we apply a bit of tolerance to this
            // comparison.
            // comparison.
            if (refreshRate < (minRefreshRate - FLOAT_TOLERANCE)
            if (refreshRate < (summary.minRefreshRate - FLOAT_TOLERANCE)
                    || refreshRate > (maxRefreshRate + FLOAT_TOLERANCE)) {
                    || refreshRate > (summary.maxRefreshRate + FLOAT_TOLERANCE)) {
                if (DEBUG) {
                if (DEBUG) {
                    Slog.w(TAG, "Discarding mode " + mode.getModeId()
                    Slog.w(TAG, "Discarding mode " + mode.getModeId()
                            + ", outside refresh rate bounds"
                            + ", outside refresh rate bounds"
                            + ": minRefreshRate=" + minRefreshRate
                            + ": minRefreshRate=" + summary.minRefreshRate
                            + ", maxRefreshRate=" + maxRefreshRate
                            + ", maxRefreshRate=" + summary.maxRefreshRate
                            + ", modeRefreshRate=" + refreshRate);
                            + ", modeRefreshRate=" + refreshRate);
                }
                }
                continue;
                continue;
@@ -535,7 +572,7 @@ public class DisplayModeDirector {


    /**
    /**
     * Information about the desired display mode to be set by the system. Includes the base
     * 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
     * We have this class in addition to SurfaceControl.DesiredDisplayConfigSpecs to make clear the
     * distinction between the config ID / physical index that
     * distinction between the config ID / physical index that
@@ -548,17 +585,28 @@ public class DisplayModeDirector {
         */
         */
        public int baseModeId;
        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() {
        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.baseModeId = baseModeId;
            this.refreshRateRange = refreshRateRange;
            this.primaryRefreshRateRange = primaryRefreshRateRange;
            this.appRequestRefreshRateRange = appRequestRefreshRateRange;
        }
        }


        /**
        /**
@@ -566,8 +614,10 @@ public class DisplayModeDirector {
         */
         */
        @Override
        @Override
        public String toString() {
        public String toString() {
            return String.format("baseModeId=%d min=%.0f max=%.0f", baseModeId,
            return String.format("baseModeId=%d primaryRefreshRateRange=[%.0f %.0f]"
                    refreshRateRange.min, refreshRateRange.max);
                            + " appRequestRefreshRateRange=[%.0f %.0f]",
                    baseModeId, primaryRefreshRateRange.min, primaryRefreshRateRange.max,
                    appRequestRefreshRateRange.min, appRequestRefreshRateRange.max);
        }
        }
        /**
        /**
         * Checks whether the two objects have the same values.
         * Checks whether the two objects have the same values.
@@ -587,7 +637,11 @@ public class DisplayModeDirector {
            if (baseModeId != desiredDisplayModeSpecs.baseModeId) {
            if (baseModeId != desiredDisplayModeSpecs.baseModeId) {
                return false;
                return false;
            }
            }
            if (!refreshRateRange.equals(desiredDisplayModeSpecs.refreshRateRange)) {
            if (!primaryRefreshRateRange.equals(desiredDisplayModeSpecs.primaryRefreshRateRange)) {
                return false;
            }
            if (!appRequestRefreshRateRange.equals(
                        desiredDisplayModeSpecs.appRequestRefreshRateRange)) {
                return false;
                return false;
            }
            }
            return true;
            return true;
@@ -595,7 +649,7 @@ public class DisplayModeDirector {


        @Override
        @Override
        public int hashCode() {
        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) {
        public void copyFrom(DesiredDisplayModeSpecs other) {
            baseModeId = other.baseModeId;
            baseModeId = other.baseModeId;
            refreshRateRange.min = other.refreshRateRange.min;
            primaryRefreshRateRange.min = other.primaryRefreshRateRange.min;
            refreshRateRange.max = other.refreshRateRange.max;
            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.
        // 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;
        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
        // Whenever a new priority is added, remember to update MIN_PRIORITY, MAX_PRIORITY, and
        // appropriate, as well as priorityToString.
        // APP_REQUEST_REFRESH_RATE_RANGE_PRIORITY_CUTOFF, as well as priorityToString.


        public static final int MIN_PRIORITY = PRIORITY_LOW_BRIGHTNESS;
        public static final int MIN_PRIORITY = PRIORITY_LOW_BRIGHTNESS;
        public static final int MAX_PRIORITY = PRIORITY_LOW_POWER_MODE;
        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.
         * A value signifying an invalid width or height in a vote.
         */
         */
+12 −5

File changed.

Preview size limit exceeded, changes collapsed.

+1 −1
Original line number Original line Diff line number Diff line
@@ -308,7 +308,7 @@ public class LocalDisplayAdapterTest {
        doReturn(0).when(() -> SurfaceControl.getActiveColorMode(display.token));
        doReturn(0).when(() -> SurfaceControl.getActiveColorMode(display.token));
        doReturn(new int[] { 0 }).when(
        doReturn(new int[] { 0 }).when(
                () -> SurfaceControl.getDisplayColorModes(display.token));
                () -> 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));
                .when(() -> SurfaceControl.getDesiredDisplayConfigSpecs(display.token));
    }
    }


Loading