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

Commit 1ff67245 authored by Ady Abraham's avatar Ady Abraham Committed by Android (Google) Code Review
Browse files

Merge "DisplayModeDirector: separate the display refresh rate and the render frame rate"

parents 5dc88839 b878a206
Loading
Loading
Loading
Loading
+1 −68
Original line number Diff line number Diff line
@@ -24,11 +24,11 @@ import android.hardware.SensorManager;
import android.os.Handler;
import android.os.PowerManager;
import android.util.IntArray;
import android.util.Slog;
import android.util.SparseArray;
import android.view.Display;
import android.view.DisplayInfo;
import android.view.SurfaceControl;
import android.view.SurfaceControl.RefreshRateRange;
import android.view.SurfaceControl.Transaction;
import android.window.DisplayWindowPolicyController;
import android.window.ScreenCapture;
@@ -36,7 +36,6 @@ import android.window.ScreenCapture;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.List;
import java.util.Objects;
import java.util.Set;

/**
@@ -650,72 +649,6 @@ public abstract class DisplayManagerInternal {
        void onDisplayGroupChanged(int groupId);
    }

    /**
     * Information about the min and max refresh rate DM would like to set the display to.
     */
    public static final class RefreshRateRange {
        public static final String TAG = "RefreshRateRange";

        // The tolerance within which we consider something approximately equals.
        public static final float FLOAT_TOLERANCE = 0.01f;

        /**
         * The lowest desired refresh rate.
         */
        public float min;

        /**
         * The highest desired refresh rate.
         */
        public float max;

        public RefreshRateRange() {}

        public RefreshRateRange(float min, float max) {
            if (min < 0 || max < 0 || min > max + FLOAT_TOLERANCE) {
                Slog.e(TAG, "Wrong values for min and max when initializing RefreshRateRange : "
                        + min + " " + max);
                this.min = this.max = 0;
                return;
            }
            if (min > max) {
                // Min and max are within epsilon of each other, but in the wrong order.
                float t = min;
                min = max;
                max = t;
            }
            this.min = min;
            this.max = max;
        }

        /**
         * Checks whether the two objects have the same values.
         */
        @Override
        public boolean equals(Object other) {
            if (other == this) {
                return true;
            }

            if (!(other instanceof RefreshRateRange)) {
                return false;
            }

            RefreshRateRange refreshRateRange = (RefreshRateRange) other;
            return (min == refreshRateRange.min && max == refreshRateRange.max);
        }

        @Override
        public int hashCode() {
            return Objects.hash(min, max);
        }

        @Override
        public String toString() {
            return "(" + min + " " + max + ")";
        }
    }

    /**
     * Describes a limitation on a display's refresh rate. Includes the allowed refresh rate
     * range as well as information about when it applies, such as high-brightness-mode.
+179 −35
Original line number Diff line number Diff line
@@ -67,6 +67,7 @@ import android.os.RemoteException;
import android.os.ServiceManager;
import android.util.ArrayMap;
import android.util.Log;
import android.util.Slog;
import android.util.SparseIntArray;
import android.util.proto.ProtoOutputStream;
import android.view.Surface.OutOfResourcesException;
@@ -1673,6 +1674,146 @@ public final class SurfaceControl implements Parcelable {
        return nativeGetDisplayedContentSample(displayToken, maxFrames, timestamp);
    }

    /**
     * Information about the min and max refresh rate DM would like to set the display to.
     * @hide
     */
    public static final class RefreshRateRange {
        public static final String TAG = "RefreshRateRange";

        // The tolerance within which we consider something approximately equals.
        public static final float FLOAT_TOLERANCE = 0.01f;

        /**
         * The lowest desired refresh rate.
         */
        public float min;

        /**
         * The highest desired refresh rate.
         */
        public float max;

        public RefreshRateRange() {}

        public RefreshRateRange(float min, float max) {
            if (min < 0 || max < 0 || min > max + FLOAT_TOLERANCE) {
                Slog.e(TAG, "Wrong values for min and max when initializing RefreshRateRange : "
                        + min + " " + max);
                this.min = this.max = 0;
                return;
            }
            if (min > max) {
                // Min and max are within epsilon of each other, but in the wrong order.
                float t = min;
                min = max;
                max = t;
            }
            this.min = min;
            this.max = max;
        }

        /**
         * Checks whether the two objects have the same values.
         */
        @Override
        public boolean equals(Object other) {
            if (other == this) {
                return true;
            }

            if (!(other instanceof RefreshRateRange)) {
                return false;
            }

            RefreshRateRange refreshRateRange = (RefreshRateRange) other;
            return (min == refreshRateRange.min && max == refreshRateRange.max);
        }

        @Override
        public int hashCode() {
            return Objects.hash(min, max);
        }

        @Override
        public String toString() {
            return "(" + min + " " + max + ")";
        }

        /**
         * Copies the supplied object's values to this object.
         */
        public void copyFrom(RefreshRateRange other) {
            this.min = other.min;
            this.max = other.max;
        }
    }

    /**
     * Information about the ranges of refresh rates for the display physical refresh rates and the
     * render frame rate DM would like to set the policy to.
     * @hide
     */
    public static final class RefreshRateRanges {
        public static final String TAG = "RefreshRateRanges";

        /**
         *  The range of refresh rates that the display should run at.
         */
        public final RefreshRateRange physical;

        /**
         *  The range of refresh rates that apps should render at.
         */
        public final RefreshRateRange render;

        public RefreshRateRanges() {
            physical = new RefreshRateRange();
            render = new RefreshRateRange();
        }

        public RefreshRateRanges(RefreshRateRange physical, RefreshRateRange render) {
            this.physical = new RefreshRateRange(physical.min, physical.max);
            this.render = new RefreshRateRange(render.min, render.max);
        }

        /**
         * Checks whether the two objects have the same values.
         */
        @Override
        public boolean equals(Object other) {
            if (other == this) {
                return true;
            }

            if (!(other instanceof RefreshRateRanges)) {
                return false;
            }

            RefreshRateRanges rates = (RefreshRateRanges) other;
            return physical.equals(rates.physical) && render.equals(
                    rates.render);
        }

        @Override
        public int hashCode() {
            return Objects.hash(physical, render);
        }

        @Override
        public String toString() {
            return "physical: " + physical + " render:  " + render;
        }

        /**
         * Copies the supplied object's values to this object.
         */
        public void copyFrom(RefreshRateRanges other) {
            this.physical.copyFrom(other.physical);
            this.render.copyFrom(other.render);
        }
    }


    /**
     * Contains information about desired display configuration.
@@ -1682,44 +1823,49 @@ public final class SurfaceControl implements Parcelable {
    public static final class DesiredDisplayModeSpecs {
        public int defaultMode;
        /**
         * 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.
         * If true this will allow switching between modes in different display configuration
         * groups. This way the user may see visual interruptions when the display mode changes.
         */
        public float primaryRefreshRateMin;
        public float primaryRefreshRateMax;
        public boolean allowGroupSwitching;

        /**
         * 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.
         * The primary physical and render refresh rate ranges represent display manager's general
         * guidance on the display configs surface flinger will consider when switching refresh
         * rates and scheduling the frame rate. Unless surface flinger has a specific reason to do
         * otherwise, it will stay within this range.
         */
        public float appRequestRefreshRateMin;
        public float appRequestRefreshRateMax;
        public final RefreshRateRanges primaryRanges;

        /**
         * If true this will allow switching between modes in different display configuration
         * groups. This way the user may see visual interruptions when the display mode changes.
         * The app request physical and render refresh rate ranges allow 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 boolean allowGroupSwitching;
        public final RefreshRateRanges appRequestRanges;

        public DesiredDisplayModeSpecs() {}
        public DesiredDisplayModeSpecs() {
            this.primaryRanges = new RefreshRateRanges();
            this.appRequestRanges = new RefreshRateRanges();
        }

        public DesiredDisplayModeSpecs(DesiredDisplayModeSpecs other) {
            this.primaryRanges = new RefreshRateRanges();
            this.appRequestRanges = new RefreshRateRanges();
            copyFrom(other);
        }

        public DesiredDisplayModeSpecs(int defaultMode, boolean allowGroupSwitching,
                float primaryRefreshRateMin, float primaryRefreshRateMax,
                float appRequestRefreshRateMin, float appRequestRefreshRateMax) {
                RefreshRateRanges primaryRanges, RefreshRateRanges appRequestRanges) {
            this.defaultMode = defaultMode;
            this.allowGroupSwitching = allowGroupSwitching;
            this.primaryRefreshRateMin = primaryRefreshRateMin;
            this.primaryRefreshRateMax = primaryRefreshRateMax;
            this.appRequestRefreshRateMin = appRequestRefreshRateMin;
            this.appRequestRefreshRateMax = appRequestRefreshRateMax;
            this.primaryRanges =
                    new RefreshRateRanges(primaryRanges.physical, primaryRanges.render);
            this.appRequestRanges =
                    new RefreshRateRanges(appRequestRanges.physical, appRequestRanges.render);
        }

        @Override
@@ -1732,10 +1878,9 @@ public final class SurfaceControl implements Parcelable {
         */
        public boolean equals(DesiredDisplayModeSpecs other) {
            return other != null && defaultMode == other.defaultMode
                    && primaryRefreshRateMin == other.primaryRefreshRateMin
                    && primaryRefreshRateMax == other.primaryRefreshRateMax
                    && appRequestRefreshRateMin == other.appRequestRefreshRateMin
                    && appRequestRefreshRateMax == other.appRequestRefreshRateMax;
                    && allowGroupSwitching == other.allowGroupSwitching
                    && primaryRanges.equals(other.primaryRanges)
                    && appRequestRanges.equals(other.appRequestRanges);
        }

        @Override
@@ -1748,18 +1893,17 @@ public final class SurfaceControl implements Parcelable {
         */
        public void copyFrom(DesiredDisplayModeSpecs other) {
            defaultMode = other.defaultMode;
            primaryRefreshRateMin = other.primaryRefreshRateMin;
            primaryRefreshRateMax = other.primaryRefreshRateMax;
            appRequestRefreshRateMin = other.appRequestRefreshRateMin;
            appRequestRefreshRateMax = other.appRequestRefreshRateMax;
            allowGroupSwitching = other.allowGroupSwitching;
            primaryRanges.copyFrom(other.primaryRanges);
            appRequestRanges.copyFrom(other.appRequestRanges);
        }

        @Override
        public String toString() {
            return String.format("defaultConfig=%d primaryRefreshRateRange=[%.0f %.0f]"
                            + " appRequestRefreshRateRange=[%.0f %.0f]",
                    defaultMode, primaryRefreshRateMin, primaryRefreshRateMax,
                    appRequestRefreshRateMin, appRequestRefreshRateMax);
            return "defaultMode=" + defaultMode
                    + " allowGroupSwitching=" + allowGroupSwitching
                    + " primaryRanges=" + primaryRanges
                    + " appRequestRanges=" + appRequestRanges;
        }
    }

+116 −42
Original line number Diff line number Diff line
@@ -187,15 +187,27 @@ static struct {
    jfieldID white;
} gDisplayPrimariesClassInfo;

static struct {
    jclass clazz;
    jmethodID ctor;
    jfieldID min;
    jfieldID max;
} gRefreshRateRangeClassInfo;

static struct {
    jclass clazz;
    jmethodID ctor;
    jfieldID physical;
    jfieldID render;
} gRefreshRateRangesClassInfo;

static struct {
    jclass clazz;
    jmethodID ctor;
    jfieldID defaultMode;
    jfieldID allowGroupSwitching;
    jfieldID primaryRefreshRateMin;
    jfieldID primaryRefreshRateMax;
    jfieldID appRequestRefreshRateMin;
    jfieldID appRequestRefreshRateMax;
    jfieldID primaryRanges;
    jfieldID appRequestRanges;
} gDesiredDisplayModeSpecsClassInfo;

static struct {
@@ -1190,6 +1202,39 @@ static jobject nativeGetDynamicDisplayInfo(JNIEnv* env, jclass clazz, jobject to
    return object;
}

struct RefreshRateRange {
    const float min;
    const float max;

    RefreshRateRange(float min, float max) : min(min), max(max) {}

    RefreshRateRange(JNIEnv* env, jobject obj)
          : min(env->GetFloatField(obj, gRefreshRateRangeClassInfo.min)),
            max(env->GetFloatField(obj, gRefreshRateRangeClassInfo.max)) {}

    jobject toJava(JNIEnv* env) const {
        return env->NewObject(gRefreshRateRangeClassInfo.clazz, gRefreshRateRangeClassInfo.ctor,
                              min, max);
    }
};

struct RefreshRateRanges {
    const RefreshRateRange physical;
    const RefreshRateRange render;

    RefreshRateRanges(RefreshRateRange physical, RefreshRateRange render)
          : physical(physical), render(render) {}

    RefreshRateRanges(JNIEnv* env, jobject obj)
          : physical(env, env->GetObjectField(obj, gRefreshRateRangesClassInfo.physical)),
            render(env, env->GetObjectField(obj, gRefreshRateRangesClassInfo.render)) {}

    jobject toJava(JNIEnv* env) const {
        return env->NewObject(gRefreshRateRangesClassInfo.clazz, gRefreshRateRangesClassInfo.ctor,
                              physical.toJava(env), render.toJava(env));
    }
};

static jboolean nativeSetDesiredDisplayModeSpecs(JNIEnv* env, jclass clazz, jobject tokenObj,
                                                 jobject DesiredDisplayModeSpecs) {
    sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
@@ -1200,25 +1245,23 @@ static jboolean nativeSetDesiredDisplayModeSpecs(JNIEnv* env, jclass clazz, jobj
    jboolean allowGroupSwitching =
            env->GetBooleanField(DesiredDisplayModeSpecs,
                                 gDesiredDisplayModeSpecsClassInfo.allowGroupSwitching);
    jfloat primaryRefreshRateMin =
            env->GetFloatField(DesiredDisplayModeSpecs,
                               gDesiredDisplayModeSpecsClassInfo.primaryRefreshRateMin);
    jfloat primaryRefreshRateMax =
            env->GetFloatField(DesiredDisplayModeSpecs,
                               gDesiredDisplayModeSpecsClassInfo.primaryRefreshRateMax);
    jfloat appRequestRefreshRateMin =
            env->GetFloatField(DesiredDisplayModeSpecs,
                               gDesiredDisplayModeSpecsClassInfo.appRequestRefreshRateMin);
    jfloat appRequestRefreshRateMax =
            env->GetFloatField(DesiredDisplayModeSpecs,
                               gDesiredDisplayModeSpecsClassInfo.appRequestRefreshRateMax);

    size_t result = SurfaceComposerClient::setDesiredDisplayModeSpecs(token, defaultMode,

    const jobject primaryRangesObject =
            env->GetObjectField(DesiredDisplayModeSpecs,
                                gDesiredDisplayModeSpecsClassInfo.primaryRanges);
    const jobject appRequestRangesObject =
            env->GetObjectField(DesiredDisplayModeSpecs,
                                gDesiredDisplayModeSpecsClassInfo.appRequestRanges);
    const RefreshRateRanges primaryRanges(env, primaryRangesObject);
    const RefreshRateRanges appRequestRanges(env, appRequestRangesObject);

    size_t result =
            SurfaceComposerClient::setDesiredDisplayModeSpecs(token, defaultMode,
                                                              allowGroupSwitching,
                                                                      primaryRefreshRateMin,
                                                                      primaryRefreshRateMax,
                                                                      appRequestRefreshRateMin,
                                                                      appRequestRefreshRateMax);
                                                              primaryRanges.physical.min,
                                                              primaryRanges.physical.max,
                                                              appRequestRanges.physical.min,
                                                              appRequestRanges.physical.max);
    return result == NO_ERROR ? JNI_TRUE : JNI_FALSE;
}

@@ -1228,22 +1271,31 @@ static jobject nativeGetDesiredDisplayModeSpecs(JNIEnv* env, jclass clazz, jobje

    ui::DisplayModeId defaultMode;
    bool allowGroupSwitching;
    float primaryRefreshRateMin;
    float primaryRefreshRateMax;
    float appRequestRefreshRateMin;
    float appRequestRefreshRateMax;
    float primaryPhysicalRefreshRateMin;
    float primaryPhysicalRefreshRateMax;
    float appRequestPhysicalRefreshRateMin;
    float appRequestPhysicalRefreshRateMax;
    if (SurfaceComposerClient::getDesiredDisplayModeSpecs(token, &defaultMode, &allowGroupSwitching,
                                                          &primaryRefreshRateMin,
                                                          &primaryRefreshRateMax,
                                                          &appRequestRefreshRateMin,
                                                          &appRequestRefreshRateMax) != NO_ERROR) {
                                                          &primaryPhysicalRefreshRateMin,
                                                          &primaryPhysicalRefreshRateMax,
                                                          &appRequestPhysicalRefreshRateMin,
                                                          &appRequestPhysicalRefreshRateMax) !=
        NO_ERROR) {
        return nullptr;
    }

    const RefreshRateRange primaryPhysicalRange(primaryPhysicalRefreshRateMin,
                                                primaryPhysicalRefreshRateMax);
    const RefreshRateRange appRequestPhysicalRange(appRequestPhysicalRefreshRateMin,
                                                   appRequestPhysicalRefreshRateMax);

    // TODO(b/241460058): populate the render ranges
    const RefreshRateRanges primaryRanges(primaryPhysicalRange, primaryPhysicalRange);
    const RefreshRateRanges appRequestRanges(appRequestPhysicalRange, appRequestPhysicalRange);

    return env->NewObject(gDesiredDisplayModeSpecsClassInfo.clazz,
                          gDesiredDisplayModeSpecsClassInfo.ctor, defaultMode, allowGroupSwitching,
                          primaryRefreshRateMin, primaryRefreshRateMax, appRequestRefreshRateMin,
                          appRequestRefreshRateMax);
                          primaryRanges.toJava(env), appRequestRanges.toJava(env));
}

static jobject nativeGetDisplayNativePrimaries(JNIEnv* env, jclass, jobject tokenObj) {
@@ -2235,23 +2287,45 @@ int register_android_view_SurfaceControl(JNIEnv* env)
    gDisplayPrimariesClassInfo.white = GetFieldIDOrDie(env, displayPrimariesClazz, "white",
            "Landroid/view/SurfaceControl$CieXyz;");

    jclass RefreshRateRangeClazz =
            FindClassOrDie(env, "android/view/SurfaceControl$RefreshRateRange");
    gRefreshRateRangeClassInfo.clazz = MakeGlobalRefOrDie(env, RefreshRateRangeClazz);
    gRefreshRateRangeClassInfo.ctor =
            GetMethodIDOrDie(env, gRefreshRateRangeClassInfo.clazz, "<init>", "(FF)V");
    gRefreshRateRangeClassInfo.min = GetFieldIDOrDie(env, RefreshRateRangeClazz, "min", "F");
    gRefreshRateRangeClassInfo.max = GetFieldIDOrDie(env, RefreshRateRangeClazz, "max", "F");

    jclass RefreshRateRangesClazz =
            FindClassOrDie(env, "android/view/SurfaceControl$RefreshRateRanges");
    gRefreshRateRangesClassInfo.clazz = MakeGlobalRefOrDie(env, RefreshRateRangesClazz);
    gRefreshRateRangesClassInfo.ctor =
            GetMethodIDOrDie(env, gRefreshRateRangesClassInfo.clazz, "<init>",
                             "(Landroid/view/SurfaceControl$RefreshRateRange;Landroid/view/"
                             "SurfaceControl$RefreshRateRange;)V");
    gRefreshRateRangesClassInfo.physical =
            GetFieldIDOrDie(env, RefreshRateRangesClazz, "physical",
                            "Landroid/view/SurfaceControl$RefreshRateRange;");
    gRefreshRateRangesClassInfo.render =
            GetFieldIDOrDie(env, RefreshRateRangesClazz, "render",
                            "Landroid/view/SurfaceControl$RefreshRateRange;");

    jclass DesiredDisplayModeSpecsClazz =
            FindClassOrDie(env, "android/view/SurfaceControl$DesiredDisplayModeSpecs");
    gDesiredDisplayModeSpecsClassInfo.clazz = MakeGlobalRefOrDie(env, DesiredDisplayModeSpecsClazz);
    gDesiredDisplayModeSpecsClassInfo.ctor =
            GetMethodIDOrDie(env, gDesiredDisplayModeSpecsClassInfo.clazz, "<init>", "(IZFFFF)V");
            GetMethodIDOrDie(env, gDesiredDisplayModeSpecsClassInfo.clazz, "<init>",
                             "(IZLandroid/view/SurfaceControl$RefreshRateRanges;Landroid/view/"
                             "SurfaceControl$RefreshRateRanges;)V");
    gDesiredDisplayModeSpecsClassInfo.defaultMode =
            GetFieldIDOrDie(env, DesiredDisplayModeSpecsClazz, "defaultMode", "I");
    gDesiredDisplayModeSpecsClassInfo.allowGroupSwitching =
            GetFieldIDOrDie(env, DesiredDisplayModeSpecsClazz, "allowGroupSwitching", "Z");
    gDesiredDisplayModeSpecsClassInfo.primaryRefreshRateMin =
            GetFieldIDOrDie(env, DesiredDisplayModeSpecsClazz, "primaryRefreshRateMin", "F");
    gDesiredDisplayModeSpecsClassInfo.primaryRefreshRateMax =
            GetFieldIDOrDie(env, DesiredDisplayModeSpecsClazz, "primaryRefreshRateMax", "F");
    gDesiredDisplayModeSpecsClassInfo.appRequestRefreshRateMin =
            GetFieldIDOrDie(env, DesiredDisplayModeSpecsClazz, "appRequestRefreshRateMin", "F");
    gDesiredDisplayModeSpecsClassInfo.appRequestRefreshRateMax =
            GetFieldIDOrDie(env, DesiredDisplayModeSpecsClazz, "appRequestRefreshRateMax", "F");
    gDesiredDisplayModeSpecsClassInfo.primaryRanges =
            GetFieldIDOrDie(env, DesiredDisplayModeSpecsClazz, "primaryRanges",
                            "Landroid/view/SurfaceControl$RefreshRateRanges;");
    gDesiredDisplayModeSpecsClassInfo.appRequestRanges =
            GetFieldIDOrDie(env, DesiredDisplayModeSpecsClazz, "appRequestRanges",
                            "Landroid/view/SurfaceControl$RefreshRateRanges;");

    jclass jankDataClazz =
                FindClassOrDie(env, "android/view/SurfaceControl$JankData");
+1 −0
Original line number Diff line number Diff line
@@ -119,6 +119,7 @@ import android.view.DisplayEventReceiver;
import android.view.DisplayInfo;
import android.view.Surface;
import android.view.SurfaceControl;
import android.view.SurfaceControl.RefreshRateRange;
import android.window.DisplayWindowPolicyController;
import android.window.ScreenCapture;

+286 −114

File changed.

Preview size limit exceeded, changes collapsed.

Loading