diff options
14 files changed, 255 insertions, 33 deletions
diff --git a/core/java/android/view/DisplayEventReceiver.java b/core/java/android/view/DisplayEventReceiver.java index 169c8c51bb53..ce7606a0cf70 100644 --- a/core/java/android/view/DisplayEventReceiver.java +++ b/core/java/android/view/DisplayEventReceiver.java @@ -227,8 +227,10 @@ public abstract class DisplayEventReceiver { * timebase. * @param physicalDisplayId Stable display ID that uniquely describes a (display, port) pair. * @param modeId The new mode Id + * @param renderPeriod The render frame period, which is a multiple of the mode's vsync period */ - public void onModeChanged(long timestampNanos, long physicalDisplayId, int modeId) { + public void onModeChanged(long timestampNanos, long physicalDisplayId, int modeId, + long renderPeriod) { } /** @@ -303,8 +305,9 @@ public abstract class DisplayEventReceiver { // Called from native code. @SuppressWarnings("unused") - private void dispatchModeChanged(long timestampNanos, long physicalDisplayId, int modeId) { - onModeChanged(timestampNanos, physicalDisplayId, modeId); + private void dispatchModeChanged(long timestampNanos, long physicalDisplayId, int modeId, + long renderPeriod) { + onModeChanged(timestampNanos, physicalDisplayId, modeId, renderPeriod); } // Called from native code. diff --git a/core/java/android/view/DisplayInfo.java b/core/java/android/view/DisplayInfo.java index 138017c5f0ec..85cb517f6369 100644 --- a/core/java/android/view/DisplayInfo.java +++ b/core/java/android/view/DisplayInfo.java @@ -180,6 +180,16 @@ public final class DisplayInfo implements Parcelable { public int modeId; /** + * The render frame rate this display is scheduled at, which is a divisor of the active mode + * refresh rate. This is the rate SurfaceFlinger would consume frames and would be observable + * by applications via the cadence of {@link android.view.Choreographer} callbacks and + * by backpressure when submitting buffers as fast as possible. + * Apps can call {@link android.view.Display#getRefreshRate} to query this value. + * + */ + public float renderFrameRate; + + /** * The default display mode. */ public int defaultModeId; @@ -376,6 +386,7 @@ public final class DisplayInfo implements Parcelable { && Objects.equals(displayCutout, other.displayCutout) && rotation == other.rotation && modeId == other.modeId + && renderFrameRate == other.renderFrameRate && defaultModeId == other.defaultModeId && Arrays.equals(supportedModes, other.supportedModes) && colorMode == other.colorMode @@ -428,6 +439,7 @@ public final class DisplayInfo implements Parcelable { displayCutout = other.displayCutout; rotation = other.rotation; modeId = other.modeId; + renderFrameRate = other.renderFrameRate; defaultModeId = other.defaultModeId; supportedModes = Arrays.copyOf(other.supportedModes, other.supportedModes.length); colorMode = other.colorMode; @@ -475,6 +487,7 @@ public final class DisplayInfo implements Parcelable { displayCutout = DisplayCutout.ParcelableWrapper.readCutoutFromParcel(source); rotation = source.readInt(); modeId = source.readInt(); + renderFrameRate = source.readFloat(); defaultModeId = source.readInt(); int nModes = source.readInt(); supportedModes = new Display.Mode[nModes]; @@ -535,6 +548,7 @@ public final class DisplayInfo implements Parcelable { DisplayCutout.ParcelableWrapper.writeCutoutToParcel(displayCutout, dest, flags); dest.writeInt(rotation); dest.writeInt(modeId); + dest.writeFloat(renderFrameRate); dest.writeInt(defaultModeId); dest.writeInt(supportedModes.length); for (int i = 0; i < supportedModes.length; i++) { @@ -764,6 +778,7 @@ public final class DisplayInfo implements Parcelable { sb.append(presentationDeadlineNanos); sb.append(", mode "); sb.append(modeId); + sb.append(renderFrameRate); sb.append(", defaultMode "); sb.append(defaultModeId); sb.append(", modes "); diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java index 30e7a7ac5a45..89a0c05e0e3f 100644 --- a/core/java/android/view/SurfaceControl.java +++ b/core/java/android/view/SurfaceControl.java @@ -1504,6 +1504,7 @@ public final class SurfaceControl implements Parcelable { public static final class DynamicDisplayInfo { public DisplayMode[] supportedDisplayModes; public int activeDisplayModeId; + public float renderFrameRate; public int[] supportedColorModes; public int activeColorMode; @@ -1520,6 +1521,7 @@ public final class SurfaceControl implements Parcelable { return "DynamicDisplayInfo{" + "supportedDisplayModes=" + Arrays.toString(supportedDisplayModes) + ", activeDisplayModeId=" + activeDisplayModeId + + ", renderFrameRate=" + renderFrameRate + ", supportedColorModes=" + Arrays.toString(supportedColorModes) + ", activeColorMode=" + activeColorMode + ", hdrCapabilities=" + hdrCapabilities @@ -1535,6 +1537,7 @@ public final class SurfaceControl implements Parcelable { DynamicDisplayInfo that = (DynamicDisplayInfo) o; return Arrays.equals(supportedDisplayModes, that.supportedDisplayModes) && activeDisplayModeId == that.activeDisplayModeId + && renderFrameRate == that.renderFrameRate && Arrays.equals(supportedColorModes, that.supportedColorModes) && activeColorMode == that.activeColorMode && Objects.equals(hdrCapabilities, that.hdrCapabilities) @@ -1544,7 +1547,7 @@ public final class SurfaceControl implements Parcelable { @Override public int hashCode() { return Objects.hash(Arrays.hashCode(supportedDisplayModes), activeDisplayModeId, - activeColorMode, hdrCapabilities); + renderFrameRate, activeColorMode, hdrCapabilities); } } diff --git a/core/jni/android_view_DisplayEventReceiver.cpp b/core/jni/android_view_DisplayEventReceiver.cpp index 019e3bd32be9..a8d8a431666a 100644 --- a/core/jni/android_view_DisplayEventReceiver.cpp +++ b/core/jni/android_view_DisplayEventReceiver.cpp @@ -80,7 +80,7 @@ private: VsyncEventData vsyncEventData) override; void dispatchHotplug(nsecs_t timestamp, PhysicalDisplayId displayId, bool connected) override; void dispatchModeChanged(nsecs_t timestamp, PhysicalDisplayId displayId, int32_t modeId, - nsecs_t vsyncPeriod) override; + nsecs_t renderPeriod) override; void dispatchFrameRateOverrides(nsecs_t timestamp, PhysicalDisplayId displayId, std::vector<FrameRateOverride> overrides) override; void dispatchNullEvent(nsecs_t timestamp, PhysicalDisplayId displayId) override {} @@ -168,14 +168,14 @@ void NativeDisplayEventReceiver::dispatchHotplug(nsecs_t timestamp, PhysicalDisp } void NativeDisplayEventReceiver::dispatchModeChanged(nsecs_t timestamp, PhysicalDisplayId displayId, - int32_t modeId, nsecs_t) { + int32_t modeId, nsecs_t renderPeriod) { JNIEnv* env = AndroidRuntime::getJNIEnv(); ScopedLocalRef<jobject> receiverObj(env, GetReferent(env, mReceiverWeakGlobal)); if (receiverObj.get()) { ALOGV("receiver %p ~ Invoking mode changed handler.", this); env->CallVoidMethod(receiverObj.get(), gDisplayEventReceiverClassInfo.dispatchModeChanged, - timestamp, displayId.value, modeId); + timestamp, displayId.value, modeId, renderPeriod); ALOGV("receiver %p ~ Returned from mode changed handler.", this); } @@ -290,7 +290,7 @@ int register_android_view_DisplayEventReceiver(JNIEnv* env) { gDisplayEventReceiverClassInfo.clazz, "dispatchHotplug", "(JJZ)V"); gDisplayEventReceiverClassInfo.dispatchModeChanged = GetMethodIDOrDie(env, gDisplayEventReceiverClassInfo.clazz, "dispatchModeChanged", - "(JJI)V"); + "(JJIJ)V"); gDisplayEventReceiverClassInfo.dispatchFrameRateOverrides = GetMethodIDOrDie(env, gDisplayEventReceiverClassInfo.clazz, "dispatchFrameRateOverrides", diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp index 2c5386d6da69..1ed355577a3f 100644 --- a/core/jni/android_view_SurfaceControl.cpp +++ b/core/jni/android_view_SurfaceControl.cpp @@ -109,6 +109,7 @@ static struct { jmethodID ctor; jfieldID supportedDisplayModes; jfieldID activeDisplayModeId; + jfieldID renderFrameRate; jfieldID supportedColorModes; jfieldID activeColorMode; jfieldID hdrCapabilities; @@ -1184,6 +1185,7 @@ static jobject nativeGetDynamicDisplayInfo(JNIEnv* env, jclass clazz, jobject to env->SetObjectField(object, gDynamicDisplayInfoClassInfo.supportedDisplayModes, modesArray); env->SetIntField(object, gDynamicDisplayInfoClassInfo.activeDisplayModeId, info.activeDisplayModeId); + env->SetFloatField(object, gDynamicDisplayInfoClassInfo.renderFrameRate, info.renderFrameRate); jintArray colorModesArray = env->NewIntArray(info.supportedColorModes.size()); if (colorModesArray == NULL) { @@ -2174,6 +2176,8 @@ int register_android_view_SurfaceControl(JNIEnv* env) "[Landroid/view/SurfaceControl$DisplayMode;"); gDynamicDisplayInfoClassInfo.activeDisplayModeId = GetFieldIDOrDie(env, dynamicInfoClazz, "activeDisplayModeId", "I"); + gDynamicDisplayInfoClassInfo.renderFrameRate = + GetFieldIDOrDie(env, dynamicInfoClazz, "renderFrameRate", "F"); gDynamicDisplayInfoClassInfo.supportedColorModes = GetFieldIDOrDie(env, dynamicInfoClazz, "supportedColorModes", "[I"); gDynamicDisplayInfoClassInfo.activeColorMode = diff --git a/services/core/java/com/android/server/display/DisplayDeviceInfo.java b/services/core/java/com/android/server/display/DisplayDeviceInfo.java index 881199964d45..2ac951c3a127 100644 --- a/services/core/java/com/android/server/display/DisplayDeviceInfo.java +++ b/services/core/java/com/android/server/display/DisplayDeviceInfo.java @@ -237,6 +237,12 @@ final class DisplayDeviceInfo { public int modeId; /** + * The render frame rate this display is scheduled at. + * @see android.view.DisplayInfo#renderFrameRate for more details. + */ + public float renderFrameRate; + + /** * The default mode of the display. */ public int defaultModeId; @@ -431,6 +437,7 @@ final class DisplayDeviceInfo { || width != other.width || height != other.height || modeId != other.modeId + || renderFrameRate != other.renderFrameRate || defaultModeId != other.defaultModeId || !Arrays.equals(supportedModes, other.supportedModes) || !Arrays.equals(supportedColorModes, other.supportedColorModes) @@ -475,6 +482,7 @@ final class DisplayDeviceInfo { width = other.width; height = other.height; modeId = other.modeId; + renderFrameRate = other.renderFrameRate; defaultModeId = other.defaultModeId; supportedModes = other.supportedModes; colorMode = other.colorMode; @@ -515,6 +523,7 @@ final class DisplayDeviceInfo { sb.append(name).append("\": uniqueId=\"").append(uniqueId).append("\", "); sb.append(width).append(" x ").append(height); sb.append(", modeId ").append(modeId); + sb.append(", renderFrameRate ").append(renderFrameRate); sb.append(", defaultModeId ").append(defaultModeId); sb.append(", supportedModes ").append(Arrays.toString(supportedModes)); sb.append(", colorMode ").append(colorMode); diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java index a7e6b7fdb862..cee699b2a5bf 100644 --- a/services/core/java/com/android/server/display/DisplayManagerService.java +++ b/services/core/java/com/android/server/display/DisplayManagerService.java @@ -35,6 +35,7 @@ import static android.hardware.display.DisplayManagerGlobal.DisplayEvent; import static android.hardware.display.DisplayViewport.VIEWPORT_EXTERNAL; import static android.hardware.display.DisplayViewport.VIEWPORT_INTERNAL; import static android.hardware.display.DisplayViewport.VIEWPORT_VIRTUAL; +import static android.os.Process.FIRST_APPLICATION_UID; import static android.os.Process.ROOT_UID; import android.Manifest; @@ -881,20 +882,27 @@ public final class DisplayManagerService extends SystemService { private DisplayInfo getDisplayInfoForFrameRateOverride(DisplayEventReceiver.FrameRateOverride[] frameRateOverrides, DisplayInfo info, int callingUid) { - float frameRateHz = 0; + float frameRateHz = info.renderFrameRate; for (DisplayEventReceiver.FrameRateOverride frameRateOverride : frameRateOverrides) { if (frameRateOverride.uid == callingUid) { frameRateHz = frameRateOverride.frameRateHz; break; } } + if (frameRateHz == 0) { return info; } + // For non-apps users we always return the physical refresh rate from display mode + boolean displayModeReturnsPhysicalRefreshRate = + callingUid < FIRST_APPLICATION_UID + || CompatChanges.isChangeEnabled( + DISPLAY_MODE_RETURNS_PHYSICAL_REFRESH_RATE, callingUid); + // Override the refresh rate only if it is a divisor of the current // refresh rate. This calculation needs to be in sync with the native code - // in RefreshRateConfigs::getFrameRateDivisor + // in RefreshRateSelector::getFrameRateDivisor Display.Mode currentMode = info.getMode(); float numPeriods = currentMode.getRefreshRate() / frameRateHz; float numPeriodsRound = Math.round(numPeriods); @@ -918,8 +926,7 @@ public final class DisplayManagerService extends SystemService { } overriddenInfo.refreshRateOverride = mode.getRefreshRate(); - if (!CompatChanges.isChangeEnabled(DISPLAY_MODE_RETURNS_PHYSICAL_REFRESH_RATE, - callingUid)) { + if (!displayModeReturnsPhysicalRefreshRate) { overriddenInfo.modeId = mode.getModeId(); } return overriddenInfo; @@ -927,8 +934,7 @@ public final class DisplayManagerService extends SystemService { } overriddenInfo.refreshRateOverride = frameRateHz; - if (!CompatChanges.isChangeEnabled(DISPLAY_MODE_RETURNS_PHYSICAL_REFRESH_RATE, - callingUid)) { + if (!displayModeReturnsPhysicalRefreshRate) { overriddenInfo.supportedModes = Arrays.copyOf(info.supportedModes, info.supportedModes.length + 1); overriddenInfo.supportedModes[overriddenInfo.supportedModes.length - 1] = diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java index dc5c80f20d78..ee53b6087143 100644 --- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java +++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java @@ -226,6 +226,8 @@ final class LocalDisplayAdapter extends DisplayAdapter { private SurfaceControl.DisplayMode[] mSfDisplayModes; // The active display mode in SurfaceFlinger private SurfaceControl.DisplayMode mActiveSfDisplayMode; + // The active display vsync period in SurfaceFlinger + private float mActiveRenderFrameRate; private DisplayEventReceiver.FrameRateOverride[] mFrameRateOverrides = new DisplayEventReceiver.FrameRateOverride[0]; @@ -267,7 +269,7 @@ final class LocalDisplayAdapter extends DisplayAdapter { SurfaceControl.DesiredDisplayModeSpecs modeSpecs) { boolean changed = updateDisplayModesLocked( dynamicInfo.supportedDisplayModes, dynamicInfo.preferredBootDisplayMode, - dynamicInfo.activeDisplayModeId, modeSpecs); + dynamicInfo.activeDisplayModeId, dynamicInfo.renderFrameRate, modeSpecs); changed |= updateStaticInfo(staticInfo); changed |= updateColorModesLocked(dynamicInfo.supportedColorModes, dynamicInfo.activeColorMode); @@ -283,7 +285,8 @@ final class LocalDisplayAdapter extends DisplayAdapter { public boolean updateDisplayModesLocked( SurfaceControl.DisplayMode[] displayModes, int preferredSfDisplayModeId, - int activeSfDisplayModeId, SurfaceControl.DesiredDisplayModeSpecs modeSpecs) { + int activeSfDisplayModeId, float renderFrameRate, + SurfaceControl.DesiredDisplayModeSpecs modeSpecs) { mSfDisplayModes = Arrays.copyOf(displayModes, displayModes.length); mActiveSfDisplayMode = getModeById(displayModes, activeSfDisplayModeId); SurfaceControl.DisplayMode preferredSfDisplayMode = @@ -379,6 +382,16 @@ final class LocalDisplayAdapter extends DisplayAdapter { sendTraversalRequestLocked(); } + boolean renderFrameRateChanged = false; + + if (mActiveRenderFrameRate > 0 && mActiveRenderFrameRate != renderFrameRate) { + Slog.d(TAG, "The render frame rate was changed from SurfaceFlinger or the display" + + " device to " + renderFrameRate); + mActiveRenderFrameRate = renderFrameRate; + renderFrameRateChanged = true; + sendTraversalRequestLocked(); + } + // Check whether surface flinger spontaneously changed display config specs out from // under us. If so, schedule a traversal to reapply our display config specs. if (mDisplayModeSpecs.baseModeId != INVALID_MODE_ID) { @@ -398,7 +411,7 @@ final class LocalDisplayAdapter extends DisplayAdapter { boolean recordsChanged = records.size() != mSupportedModes.size() || modesAdded; // If the records haven't changed then we're done here. if (!recordsChanged) { - return activeModeChanged || preferredModeChanged; + return activeModeChanged || preferredModeChanged || renderFrameRateChanged; } mSupportedModes.clear(); @@ -410,16 +423,19 @@ final class LocalDisplayAdapter extends DisplayAdapter { if (mDefaultModeId == INVALID_MODE_ID) { mDefaultModeId = activeRecord.mMode.getModeId(); mDefaultModeGroup = mActiveSfDisplayMode.group; + mActiveRenderFrameRate = renderFrameRate; } else if (modesAdded && activeModeChanged) { Slog.d(TAG, "New display modes are added and the active mode has changed, " + "use active mode as default mode."); mDefaultModeId = activeRecord.mMode.getModeId(); mDefaultModeGroup = mActiveSfDisplayMode.group; + mActiveRenderFrameRate = renderFrameRate; } else if (findSfDisplayModeIdLocked(mDefaultModeId, mDefaultModeGroup) < 0) { Slog.w(TAG, "Default display mode no longer available, using currently" + " active mode as default."); mDefaultModeId = activeRecord.mMode.getModeId(); mDefaultModeGroup = mActiveSfDisplayMode.group; + mActiveRenderFrameRate = renderFrameRate; } // Determine whether the display mode specs' base mode is still there. @@ -620,6 +636,7 @@ final class LocalDisplayAdapter extends DisplayAdapter { mInfo.width = mActiveSfDisplayMode.width; mInfo.height = mActiveSfDisplayMode.height; mInfo.modeId = mActiveModeId; + mInfo.renderFrameRate = mActiveRenderFrameRate; mInfo.defaultModeId = getPreferredModeId(); mInfo.supportedModes = getDisplayModes(mSupportedModes); mInfo.colorMode = mActiveColorMode; @@ -995,8 +1012,8 @@ final class LocalDisplayAdapter extends DisplayAdapter { updateDeviceInfoLocked(); } - public void onActiveDisplayModeChangedLocked(int sfModeId) { - if (updateActiveModeLocked(sfModeId)) { + public void onActiveDisplayModeChangedLocked(int sfModeId, float renderFrameRate) { + if (updateActiveModeLocked(sfModeId, renderFrameRate)) { updateDeviceInfoLocked(); } } @@ -1008,8 +1025,9 @@ final class LocalDisplayAdapter extends DisplayAdapter { } } - public boolean updateActiveModeLocked(int activeSfModeId) { - if (mActiveSfDisplayMode.id == activeSfModeId) { + public boolean updateActiveModeLocked(int activeSfModeId, float renderFrameRate) { + if (mActiveSfDisplayMode.id == activeSfModeId + && mActiveRenderFrameRate == renderFrameRate) { return false; } mActiveSfDisplayMode = getModeById(mSfDisplayModes, activeSfModeId); @@ -1018,6 +1036,7 @@ final class LocalDisplayAdapter extends DisplayAdapter { Slog.w(TAG, "In unknown mode after setting allowed modes" + ", activeModeId=" + activeSfModeId); } + mActiveRenderFrameRate = renderFrameRate; return true; } @@ -1114,6 +1133,7 @@ final class LocalDisplayAdapter extends DisplayAdapter { pw.println(" " + sfDisplayMode); } pw.println("mActiveSfDisplayMode=" + mActiveSfDisplayMode); + pw.println("mActiveRenderFrameRate=" + mActiveRenderFrameRate); pw.println("mSupportedModes="); for (int i = 0; i < mSupportedModes.size(); i++) { pw.println(" " + mSupportedModes.valueAt(i)); @@ -1288,7 +1308,8 @@ final class LocalDisplayAdapter extends DisplayAdapter { public interface DisplayEventListener { void onHotplug(long timestampNanos, long physicalDisplayId, boolean connected); - void onModeChanged(long timestampNanos, long physicalDisplayId, int modeId); + void onModeChanged(long timestampNanos, long physicalDisplayId, int modeId, + long renderPeriod); void onFrameRateOverridesChanged(long timestampNanos, long physicalDisplayId, DisplayEventReceiver.FrameRateOverride[] overrides); @@ -1309,8 +1330,9 @@ final class LocalDisplayAdapter extends DisplayAdapter { } @Override - public void onModeChanged(long timestampNanos, long physicalDisplayId, int modeId) { - mListener.onModeChanged(timestampNanos, physicalDisplayId, modeId); + public void onModeChanged(long timestampNanos, long physicalDisplayId, int modeId, + long renderPeriod) { + mListener.onModeChanged(timestampNanos, physicalDisplayId, modeId, renderPeriod); } @Override @@ -1333,12 +1355,14 @@ final class LocalDisplayAdapter extends DisplayAdapter { } @Override - public void onModeChanged(long timestampNanos, long physicalDisplayId, int modeId) { + public void onModeChanged(long timestampNanos, long physicalDisplayId, int modeId, + long renderPeriod) { if (DEBUG) { Slog.d(TAG, "onModeChanged(" + "timestampNanos=" + timestampNanos + ", physicalDisplayId=" + physicalDisplayId - + ", modeId=" + modeId + ")"); + + ", modeId=" + modeId + + ", renderPeriod=" + renderPeriod + ")"); } synchronized (getSyncRoot()) { LocalDisplayDevice device = mDevices.get(physicalDisplayId); @@ -1349,7 +1373,8 @@ final class LocalDisplayAdapter extends DisplayAdapter { } return; } - device.onActiveDisplayModeChangedLocked(modeId); + float renderFrameRate = 1e9f / renderPeriod; + device.onActiveDisplayModeChangedLocked(modeId, renderFrameRate); } } diff --git a/services/core/java/com/android/server/display/LogicalDisplay.java b/services/core/java/com/android/server/display/LogicalDisplay.java index 8dd169bf4bf6..c7b27deb420d 100644 --- a/services/core/java/com/android/server/display/LogicalDisplay.java +++ b/services/core/java/com/android/server/display/LogicalDisplay.java @@ -377,6 +377,7 @@ final class LogicalDisplay { mBaseDisplayInfo.logicalHeight = maskedHeight; mBaseDisplayInfo.rotation = Surface.ROTATION_0; mBaseDisplayInfo.modeId = deviceInfo.modeId; + mBaseDisplayInfo.renderFrameRate = deviceInfo.renderFrameRate; mBaseDisplayInfo.defaultModeId = deviceInfo.defaultModeId; mBaseDisplayInfo.supportedModes = Arrays.copyOf( deviceInfo.supportedModes, deviceInfo.supportedModes.length); diff --git a/services/core/java/com/android/server/display/OverlayDisplayAdapter.java b/services/core/java/com/android/server/display/OverlayDisplayAdapter.java index 0e11b53e0257..3e67f0a466d7 100644 --- a/services/core/java/com/android/server/display/OverlayDisplayAdapter.java +++ b/services/core/java/com/android/server/display/OverlayDisplayAdapter.java @@ -340,6 +340,7 @@ final class OverlayDisplayAdapter extends DisplayAdapter { mInfo.width = mode.getPhysicalWidth(); mInfo.height = mode.getPhysicalHeight(); mInfo.modeId = mode.getModeId(); + mInfo.renderFrameRate = mode.getRefreshRate(); mInfo.defaultModeId = mModes[0].getModeId(); mInfo.supportedModes = mModes; mInfo.densityDpi = rawMode.mDensityDpi; diff --git a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java index d0e518b876dd..ad8d71514832 100644 --- a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java +++ b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java @@ -446,6 +446,7 @@ public class VirtualDisplayAdapter extends DisplayAdapter { mInfo.width = mWidth; mInfo.height = mHeight; mInfo.modeId = mMode.getModeId(); + mInfo.renderFrameRate = mMode.getRefreshRate(); mInfo.defaultModeId = mMode.getModeId(); mInfo.supportedModes = new Display.Mode[] { mMode }; mInfo.densityDpi = mDensityDpi; diff --git a/services/core/java/com/android/server/display/WifiDisplayAdapter.java b/services/core/java/com/android/server/display/WifiDisplayAdapter.java index c759d98561f9..e8327018e144 100644 --- a/services/core/java/com/android/server/display/WifiDisplayAdapter.java +++ b/services/core/java/com/android/server/display/WifiDisplayAdapter.java @@ -646,6 +646,7 @@ final class WifiDisplayAdapter extends DisplayAdapter { mInfo.width = mWidth; mInfo.height = mHeight; mInfo.modeId = mMode.getModeId(); + mInfo.renderFrameRate = mMode.getRefreshRate(); mInfo.defaultModeId = mMode.getModeId(); mInfo.supportedModes = new Display.Mode[] { mMode }; mInfo.presentationDeadlineNanos = 1000000000L / (int) mRefreshRate; // 1 frame 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 be32b79a9d13..f10597114a5e 100644 --- a/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java @@ -212,7 +212,7 @@ public class LocalDisplayAdapterTest { SurfaceControl.DisplayMode displayMode = createFakeDisplayMode(0, 1920, 1080, 0); displayMode.supportedHdrTypes = new int[0]; FakeDisplay display = new FakeDisplay(PORT_A, new SurfaceControl.DisplayMode[]{displayMode}, - 0); + 0, 0); setUpDisplay(display); updateAvailableDisplays(); mAdapter.registerLocked(); @@ -393,7 +393,7 @@ public class LocalDisplayAdapterTest { SurfaceControl.DisplayMode displayMode = createFakeDisplayMode(0, 1920, 1080, 60f); SurfaceControl.DisplayMode[] modes = new SurfaceControl.DisplayMode[]{displayMode}; - FakeDisplay display = new FakeDisplay(PORT_A, modes, 0); + FakeDisplay display = new FakeDisplay(PORT_A, modes, 0, displayMode.refreshRate); setUpDisplay(display); updateAvailableDisplays(); mAdapter.registerLocked(); @@ -449,7 +449,7 @@ public class LocalDisplayAdapterTest { SurfaceControl.DisplayMode displayMode = createFakeDisplayMode(0, 1920, 1080, 60f); SurfaceControl.DisplayMode[] modes = new SurfaceControl.DisplayMode[]{displayMode}; - FakeDisplay display = new FakeDisplay(PORT_A, modes, 0); + FakeDisplay display = new FakeDisplay(PORT_A, modes, 0, displayMode.refreshRate); setUpDisplay(display); updateAvailableDisplays(); mAdapter.registerLocked(); @@ -504,7 +504,7 @@ public class LocalDisplayAdapterTest { createFakeDisplayMode(0, 1920, 1080, 60f), createFakeDisplayMode(1, 1920, 1080, 50f) }; - FakeDisplay display = new FakeDisplay(PORT_A, modes, /* activeMode */ 0); + FakeDisplay display = new FakeDisplay(PORT_A, modes, /* activeMode */ 0, 60f); setUpDisplay(display); updateAvailableDisplays(); mAdapter.registerLocked(); @@ -538,6 +538,49 @@ public class LocalDisplayAdapterTest { } @Test + public void testAfterDisplayChange_RenderFrameRateIsUpdated() throws Exception { + SurfaceControl.DisplayMode[] modes = new SurfaceControl.DisplayMode[]{ + createFakeDisplayMode(0, 1920, 1080, 60f), + }; + FakeDisplay display = new FakeDisplay(PORT_A, modes, /* activeMode */ 0, + /* renderFrameRate */30f); + setUpDisplay(display); + updateAvailableDisplays(); + mAdapter.registerLocked(); + waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS); + + assertThat(mListener.addedDisplays.size()).isEqualTo(1); + assertThat(mListener.changedDisplays).isEmpty(); + + DisplayDeviceInfo displayDeviceInfo = mListener.addedDisplays.get(0) + .getDisplayDeviceInfoLocked(); + + Display.Mode activeMode = getModeById(displayDeviceInfo, displayDeviceInfo.modeId); + assertThat(activeMode.matches(1920, 1080, 60f)).isTrue(); + assertEquals(Float.floatToIntBits(30f), + Float.floatToIntBits(displayDeviceInfo.renderFrameRate)); + + // Change the render frame rate + display.dynamicInfo.renderFrameRate = 60f; + setUpDisplay(display); + mInjector.getTransmitter().sendHotplug(display, /* connected */ true); + waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS); + + assertTrue(mListener.traversalRequested); + assertThat(mListener.addedDisplays.size()).isEqualTo(1); + assertThat(mListener.changedDisplays.size()).isEqualTo(1); + + DisplayDevice displayDevice = mListener.changedDisplays.get(0); + displayDevice.applyPendingDisplayDeviceInfoChangesLocked(); + displayDeviceInfo = displayDevice.getDisplayDeviceInfoLocked(); + + activeMode = getModeById(displayDeviceInfo, displayDeviceInfo.modeId); + assertThat(activeMode.matches(1920, 1080, 60f)).isTrue(); + assertEquals(Float.floatToIntBits(60f), + Float.floatToIntBits(displayDeviceInfo.renderFrameRate)); + } + + @Test public void testAfterDisplayChange_HdrCapabilitiesAreUpdated() throws Exception { FakeDisplay display = new FakeDisplay(PORT_A); Display.HdrCapabilities initialHdrCapabilities = new Display.HdrCapabilities(new int[0], @@ -722,7 +765,7 @@ public class LocalDisplayAdapterTest { createFakeDisplayMode(1, 1920, 1080, 50f) }; final int activeMode = 0; - FakeDisplay display = new FakeDisplay(PORT_A, modes, activeMode); + FakeDisplay display = new FakeDisplay(PORT_A, modes, activeMode, 60f); display.desiredDisplayModeSpecs.defaultMode = 1; setUpDisplay(display); @@ -979,11 +1022,13 @@ public class LocalDisplayAdapterTest { dynamicInfo.activeDisplayModeId = 0; } - private FakeDisplay(int port, SurfaceControl.DisplayMode[] modes, int activeMode) { + private FakeDisplay(int port, SurfaceControl.DisplayMode[] modes, int activeMode, + float renderFrameRate) { address = createDisplayAddress(port); info = createFakeDisplayInfo(); dynamicInfo.supportedDisplayModes = modes; dynamicInfo.activeDisplayModeId = activeMode; + dynamicInfo.renderFrameRate = renderFrameRate; } private FakeDisplay(int port, SurfaceControl.DisplayMode[] modes, int activeMode, diff --git a/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java index 5af05584c07a..069feedbe6b6 100644 --- a/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java @@ -1164,6 +1164,76 @@ public class DisplayManagerServiceTest { } /** + * Tests that there is a display change notification if the render frame rate is updated + */ + @Test + public void testShouldNotifyChangeWhenDisplayInfoRenderFrameRateChanged() throws Exception { + DisplayManagerService displayManager = + new DisplayManagerService(mContext, mShortMockedInjector); + DisplayManagerService.BinderService displayManagerBinderService = + displayManager.new BinderService(); + registerDefaultDisplays(displayManager); + displayManager.onBootPhase(SystemService.PHASE_WAIT_FOR_DEFAULT_DISPLAY); + + FakeDisplayDevice displayDevice = createFakeDisplayDevice(displayManager, new float[]{60f}); + FakeDisplayManagerCallback callback = registerDisplayListenerCallback(displayManager, + displayManagerBinderService, displayDevice); + + updateRenderFrameRate(displayManager, displayDevice, 30f); + assertTrue(callback.mDisplayChangedCalled); + callback.clear(); + + updateRenderFrameRate(displayManager, displayDevice, 30f); + assertFalse(callback.mDisplayChangedCalled); + + updateRenderFrameRate(displayManager, displayDevice, 20f); + assertTrue(callback.mDisplayChangedCalled); + callback.clear(); + } + + /** + * Tests that the DisplayInfo is updated correctly with a render frame rate + */ + @Test + public void testDisplayInfoRenderFrameRate() throws Exception { + DisplayManagerService displayManager = + new DisplayManagerService(mContext, mShortMockedInjector); + DisplayManagerService.BinderService displayManagerBinderService = + displayManager.new BinderService(); + registerDefaultDisplays(displayManager); + displayManager.onBootPhase(SystemService.PHASE_WAIT_FOR_DEFAULT_DISPLAY); + + FakeDisplayDevice displayDevice = createFakeDisplayDevice(displayManager, + new float[]{60f, 30f, 20f}); + int displayId = getDisplayIdForDisplayDevice(displayManager, displayManagerBinderService, + displayDevice); + DisplayInfo displayInfo = displayManagerBinderService.getDisplayInfo(displayId); + assertEquals(60f, displayInfo.getRefreshRate(), 0.01f); + + updateRenderFrameRate(displayManager, displayDevice, 20f); + displayInfo = displayManagerBinderService.getDisplayInfo(displayId); + assertEquals(20f, displayInfo.getRefreshRate(), 0.01f); + } + + /** + * Tests that the mode reflects the render frame rate is in compat mode + */ + @Test + @DisableCompatChanges({DisplayManagerService.DISPLAY_MODE_RETURNS_PHYSICAL_REFRESH_RATE}) + public void testDisplayInfoRenderFrameRateModeCompat() throws Exception { + testDisplayInfoRenderFrameRateModeCompat(/*compatChangeEnabled*/ false); + } + + /** + * Tests that the mode reflects the physical display refresh rate when not in compat mode. + */ + @Test + @EnableCompatChanges({DisplayManagerService.DISPLAY_MODE_RETURNS_PHYSICAL_REFRESH_RATE}) + public void testDisplayInfoRenderFrameRateMode() throws Exception { + testDisplayInfoRenderFrameRateModeCompat(/*compatChangeEnabled*/ true); + } + + /** * Tests that EVENT_DISPLAY_ADDED is sent when a display is added. */ @Test @@ -1383,6 +1453,34 @@ public class DisplayManagerServiceTest { assertEquals(expectedMode, displayInfo.getMode()); } + private void testDisplayInfoRenderFrameRateModeCompat(boolean compatChangeEnabled) + throws Exception { + DisplayManagerService displayManager = + new DisplayManagerService(mContext, mShortMockedInjector); + DisplayManagerService.BinderService displayManagerBinderService = + displayManager.new BinderService(); + registerDefaultDisplays(displayManager); + displayManager.onBootPhase(SystemService.PHASE_WAIT_FOR_DEFAULT_DISPLAY); + + FakeDisplayDevice displayDevice = createFakeDisplayDevice(displayManager, + new float[]{60f, 30f, 20f}); + int displayId = getDisplayIdForDisplayDevice(displayManager, displayManagerBinderService, + displayDevice); + DisplayInfo displayInfo = displayManagerBinderService.getDisplayInfo(displayId); + assertEquals(60f, displayInfo.getRefreshRate(), 0.01f); + + updateRenderFrameRate(displayManager, displayDevice, 20f); + displayInfo = displayManagerBinderService.getDisplayInfo(displayId); + assertEquals(20f, displayInfo.getRefreshRate(), 0.01f); + Display.Mode expectedMode; + if (compatChangeEnabled) { + expectedMode = new Display.Mode(1, 100, 200, 60f); + } else { + expectedMode = new Display.Mode(3, 100, 200, 20f); + } + assertEquals(expectedMode, displayInfo.getMode()); + } + private void testDisplayInfoNonNativeFrameRateOverrideMode(boolean compatChangeEnabled) { DisplayManagerService displayManager = new DisplayManagerService(mContext, mBasicInjector); @@ -1452,6 +1550,15 @@ public class DisplayManagerServiceTest { updateDisplayDeviceInfo(displayManager, displayDevice, displayDeviceInfo); } + private void updateRenderFrameRate(DisplayManagerService displayManager, + FakeDisplayDevice displayDevice, + float renderFrameRate) { + DisplayDeviceInfo displayDeviceInfo = new DisplayDeviceInfo(); + displayDeviceInfo.copyFrom(displayDevice.getDisplayDeviceInfoLocked()); + displayDeviceInfo.renderFrameRate = renderFrameRate; + updateDisplayDeviceInfo(displayManager, displayDevice, displayDeviceInfo); + } + private void updateModeId(DisplayManagerService displayManager, FakeDisplayDevice displayDevice, int modeId) { @@ -1491,6 +1598,7 @@ public class DisplayManagerServiceTest { new Display.Mode(i + 1, width, height, refreshRates[i]); } displayDeviceInfo.modeId = 1; + displayDeviceInfo.renderFrameRate = displayDeviceInfo.supportedModes[0].getRefreshRate(); displayDeviceInfo.width = width; displayDeviceInfo.height = height; final Rect zeroRect = new Rect(); |