Loading core/java/android/view/Display.java +11 −0 Original line number Diff line number Diff line Loading @@ -2433,10 +2433,18 @@ public final class Display { * @hide */ public static final int FLAG_ARR_RENDER_RATE = 1 << 0; /** * @hide * * A synthetic display mode flag that indicates the mode is used to override the display's * logical width and height without changing the mode reported to SurfaceFlinger. */ public static final int FLAG_SIZE_OVERRIDE = 1 << 1; /** @hide */ @IntDef(flag = true, prefix = {"FLAG_"}, value = { FLAG_ARR_RENDER_RATE, FLAG_SIZE_OVERRIDE, }) @Retention(RetentionPolicy.SOURCE) public @interface ModeFlags {} Loading Loading @@ -2761,6 +2769,9 @@ public final class Display { if ((flags & FLAG_ARR_RENDER_RATE) != 0) { msg.append(", FLAG_ARR_RENDER_RATE"); } if ((flags & FLAG_SIZE_OVERRIDE) != 0) { msg.append(", FLAG_SIZE_OVERRIDE"); } return msg.toString(); } Loading services/core/java/com/android/server/display/DisplayModeFactory.java +5 −1 Original line number Diff line number Diff line Loading @@ -54,13 +54,17 @@ public class DisplayModeFactory { @SuppressLint("WrongConstant") static Display.Mode createMode(SurfaceControl.DisplayMode mode, float[] alternativeRefreshRates, boolean hasArrSupport, boolean syntheticModesV2Enabled) { boolean hasArrSupport, boolean syntheticModesV2Enabled, boolean sizeOverrideEnabled) { int flags = 0; if (syntheticModesV2Enabled && hasArrSupport && mode.peakRefreshRate <= SYNTHETIC_MODE_HIGH_BOUNDARY) { flags |= Display.Mode.FLAG_ARR_RENDER_RATE; } if (sizeOverrideEnabled) { flags |= Display.Mode.FLAG_SIZE_OVERRIDE; } return new Display.Mode(NEXT_DISPLAY_MODE_ID.getAndIncrement(), Display.Mode.INVALID_MODE_ID, flags, mode.width, mode.height, mode.peakRefreshRate, mode.vsyncRate, Loading services/core/java/com/android/server/display/LocalDisplayAdapter.java +7 −5 Original line number Diff line number Diff line Loading @@ -293,8 +293,8 @@ final class LocalDisplayAdapter extends DisplayAdapter { public boolean updateDisplayPropertiesLocked(SurfaceControl.StaticDisplayInfo staticInfo, SurfaceControl.DynamicDisplayInfo dynamicInfo, SurfaceControl.DesiredDisplayModeSpecs modeSpecs) { boolean changed = updateDisplayModesLocked(dynamicInfo, modeSpecs); boolean changed = updateDisplayModesLocked(dynamicInfo, modeSpecs, staticInfo.isInternal); changed |= updateStaticInfo(staticInfo); changed |= updateColorModesLocked(dynamicInfo.supportedColorModes, dynamicInfo.activeColorMode); Loading @@ -312,13 +312,15 @@ final class LocalDisplayAdapter extends DisplayAdapter { } private boolean updateDisplayModesLocked(SurfaceControl.DynamicDisplayInfo dynamicInfo, SurfaceControl.DesiredDisplayModeSpecs modeSpecs) { SurfaceControl.DesiredDisplayModeSpecs modeSpecs, boolean isInternal) { SurfaceControl.DisplayMode[] displayModes = dynamicInfo.supportedDisplayModes; int preferredSfDisplayModeId = dynamicInfo.preferredBootDisplayMode; int activeSfDisplayModeId = dynamicInfo.activeDisplayModeId; float renderFrameRate = dynamicInfo.renderFrameRate; boolean hasArrSupport = dynamicInfo.hasArrSupport; boolean syntheticModesV2Enabled = getFeatureFlags().isSyntheticModesV2Enabled(); boolean sizeOverrideEnabled = getFeatureFlags().isSizeOverrideForExternalDisplaysEnabled() && !isInternal; mSfDisplayModes = Arrays.copyOf(displayModes, displayModes.length); mActiveSfDisplayMode = getModeById(displayModes, activeSfDisplayModeId); Loading Loading @@ -369,8 +371,8 @@ final class LocalDisplayAdapter extends DisplayAdapter { for (int j = 0; j < alternativeRates.length; j++) { alternativeRates[j] = alternativeRefreshRates.get(j); } Display.Mode displayMode = DisplayModeFactory.createMode( mode, alternativeRates, hasArrSupport, syntheticModesV2Enabled); Display.Mode displayMode = DisplayModeFactory.createMode(mode, alternativeRates, hasArrSupport, syntheticModesV2Enabled, sizeOverrideEnabled); record = new DisplayModeRecord(displayMode); modesAdded = true; } Loading services/core/java/com/android/server/display/LogicalDisplay.java +61 −12 Original line number Diff line number Diff line Loading @@ -16,6 +16,8 @@ package com.android.server.display; import static android.view.Display.Mode.INVALID_MODE_ID; import static com.android.server.display.DisplayDeviceInfo.TOUCH_NONE; import static com.android.server.display.layout.Layout.Display.POSITION_REAR; import static com.android.server.wm.utils.DisplayInfoOverrides.WM_OVERRIDE_FIELDS; Loading Loading @@ -232,15 +234,17 @@ final class LogicalDisplay { private final boolean mSyncedResolutionSwitchEnabled; private final boolean mSyntheticModesV2Enabled; private final boolean mSizeOverrideEnabled; private boolean mCanHostTasks; LogicalDisplay(int displayId, int layerStack, DisplayDevice primaryDisplayDevice) { this(displayId, layerStack, primaryDisplayDevice, false, true); this(displayId, layerStack, primaryDisplayDevice, false, true, false); } LogicalDisplay(int displayId, int layerStack, DisplayDevice primaryDisplayDevice, boolean isSyncedResolutionSwitchEnabled, boolean syntheticModesV2Enabled) { boolean isSyncedResolutionSwitchEnabled, boolean syntheticModesV2Enabled, boolean sizeOverrideEnabled) { mDisplayId = displayId; mLayerStack = layerStack; mPrimaryDisplayDevice = primaryDisplayDevice; Loading @@ -253,6 +257,7 @@ final class LogicalDisplay { mBaseDisplayInfo.thermalBrightnessThrottlingDataId = mThermalBrightnessThrottlingDataId; mSyncedResolutionSwitchEnabled = isSyncedResolutionSwitchEnabled; mSyntheticModesV2Enabled = syntheticModesV2Enabled; mSizeOverrideEnabled = sizeOverrideEnabled; // No need to initialize mCanHostTasks here; it's handled in // DisplayManagerService#setupLogicalDisplay(). Loading Loading @@ -505,16 +510,30 @@ final class LogicalDisplay { && mDevicePosition != Layout.Display.POSITION_REAR) { mBaseDisplayInfo.flags |= Display.FLAG_ALLOWS_CONTENT_MODE_SWITCH; } int currentWidth = deviceInfo.width; int currentHeight = deviceInfo.height; float currentXDpi = deviceInfo.xDpi; float currentYDpi = deviceInfo.yDpi; Display.Mode sizeOverrideMode = getUserPreferredModeForSizeOverrideLocked(deviceInfo); if (sizeOverrideMode != null && mSizeOverrideEnabled) { currentWidth = sizeOverrideMode.getPhysicalWidth(); currentHeight = sizeOverrideMode.getPhysicalHeight(); currentXDpi = currentXDpi * (currentWidth / (float) deviceInfo.width); currentYDpi = currentYDpi * (currentHeight / (float) deviceInfo.height); } Rect maskingInsets = getMaskingInsets(deviceInfo); int maskedWidth = deviceInfo.width - maskingInsets.left - maskingInsets.right; int maskedHeight = deviceInfo.height - maskingInsets.top - maskingInsets.bottom; int maskedWidth = currentWidth - maskingInsets.left - maskingInsets.right; int maskedHeight = currentHeight - maskingInsets.top - maskingInsets.bottom; if (mIsAnisotropyCorrectionEnabled && deviceInfo.type == Display.TYPE_EXTERNAL && deviceInfo.xDpi > 0 && deviceInfo.yDpi > 0) { if (deviceInfo.xDpi > deviceInfo.yDpi * DisplayDevice.MAX_ANISOTROPY) { maskedHeight = (int) (maskedHeight * deviceInfo.xDpi / deviceInfo.yDpi + 0.5); } else if (deviceInfo.xDpi * DisplayDevice.MAX_ANISOTROPY < deviceInfo.yDpi) { maskedWidth = (int) (maskedWidth * deviceInfo.yDpi / deviceInfo.xDpi + 0.5); && currentXDpi > 0 && currentYDpi > 0) { if (currentXDpi > currentYDpi * DisplayDevice.MAX_ANISOTROPY) { maskedHeight = (int) (maskedHeight * currentXDpi / currentYDpi + 0.5); } else if (currentXDpi * DisplayDevice.MAX_ANISOTROPY < currentYDpi) { maskedWidth = (int) (maskedWidth * currentYDpi / currentXDpi + 0.5); } } Loading Loading @@ -553,10 +572,10 @@ final class LogicalDisplay { deviceInfo.allmSupported || deviceInfo.gameContentTypeSupported; mBaseDisplayInfo.logicalDensityDpi = deviceInfo.densityDpi > 0 ? deviceInfo.densityDpi : calculateBaseDensity(deviceInfo.xDpi, deviceInfo.yDpi, maskedWidth, : calculateBaseDensity(currentXDpi, currentYDpi, maskedWidth, maskedHeight); mBaseDisplayInfo.physicalXDpi = deviceInfo.xDpi; mBaseDisplayInfo.physicalYDpi = deviceInfo.yDpi; mBaseDisplayInfo.physicalXDpi = currentXDpi; mBaseDisplayInfo.physicalYDpi = currentYDpi; mBaseDisplayInfo.appVsyncOffsetNanos = deviceInfo.appVsyncOffsetNanos; mBaseDisplayInfo.presentationDeadlineNanos = deviceInfo.presentationDeadlineNanos; mBaseDisplayInfo.state = deviceInfo.state; Loading Loading @@ -623,6 +642,36 @@ final class LogicalDisplay { return Math.max((int) (dpi + 0.5), EXTERNAL_DISPLAY_MIN_DENSITY_DPI); } @Nullable private Display.Mode getUserPreferredModeForSizeOverrideLocked(DisplayDeviceInfo deviceInfo) { Display.Mode[] modes = deviceInfo.supportedModes; int selectedModeId = deviceInfo.modeId; int userPreferredModeId = deviceInfo.userPreferredModeId; if (userPreferredModeId == INVALID_MODE_ID) { return null; } // user preferred mode is normal mode if (userPreferredModeId == selectedModeId) { return null; } Display.Mode userPreferredMode = null; for (Display.Mode mode : modes) { if (userPreferredModeId == mode.getModeId()) { userPreferredMode = mode; break; } } if (userPreferredMode != null && (userPreferredMode.getFlags() & Display.Mode.FLAG_SIZE_OVERRIDE) != 0) { return userPreferredMode; } return null; } private void updateFrameRateOverrides(DisplayDeviceInfo deviceInfo) { mTempFrameRateOverride.clear(); if (mFrameRateOverrides != null) { Loading services/core/java/com/android/server/display/LogicalDisplayMapper.java +2 −1 Original line number Diff line number Diff line Loading @@ -1312,7 +1312,8 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener { private LogicalDisplay createNewLogicalDisplayLocked(DisplayDevice device, int displayId) { final int layerStack = assignLayerStackLocked(displayId); final LogicalDisplay display = new LogicalDisplay(displayId, layerStack, device, mFlags.isSyncedResolutionSwitchEnabled(), mFlags.isSyntheticModesV2Enabled()); mFlags.isSyncedResolutionSwitchEnabled(), mFlags.isSyntheticModesV2Enabled(), mFlags.isSizeOverrideForExternalDisplaysEnabled()); display.updateLocked(mDisplayDeviceRepo, mSyntheticModeManager); final DisplayInfo info = display.getDisplayInfoLocked(); Loading Loading
core/java/android/view/Display.java +11 −0 Original line number Diff line number Diff line Loading @@ -2433,10 +2433,18 @@ public final class Display { * @hide */ public static final int FLAG_ARR_RENDER_RATE = 1 << 0; /** * @hide * * A synthetic display mode flag that indicates the mode is used to override the display's * logical width and height without changing the mode reported to SurfaceFlinger. */ public static final int FLAG_SIZE_OVERRIDE = 1 << 1; /** @hide */ @IntDef(flag = true, prefix = {"FLAG_"}, value = { FLAG_ARR_RENDER_RATE, FLAG_SIZE_OVERRIDE, }) @Retention(RetentionPolicy.SOURCE) public @interface ModeFlags {} Loading Loading @@ -2761,6 +2769,9 @@ public final class Display { if ((flags & FLAG_ARR_RENDER_RATE) != 0) { msg.append(", FLAG_ARR_RENDER_RATE"); } if ((flags & FLAG_SIZE_OVERRIDE) != 0) { msg.append(", FLAG_SIZE_OVERRIDE"); } return msg.toString(); } Loading
services/core/java/com/android/server/display/DisplayModeFactory.java +5 −1 Original line number Diff line number Diff line Loading @@ -54,13 +54,17 @@ public class DisplayModeFactory { @SuppressLint("WrongConstant") static Display.Mode createMode(SurfaceControl.DisplayMode mode, float[] alternativeRefreshRates, boolean hasArrSupport, boolean syntheticModesV2Enabled) { boolean hasArrSupport, boolean syntheticModesV2Enabled, boolean sizeOverrideEnabled) { int flags = 0; if (syntheticModesV2Enabled && hasArrSupport && mode.peakRefreshRate <= SYNTHETIC_MODE_HIGH_BOUNDARY) { flags |= Display.Mode.FLAG_ARR_RENDER_RATE; } if (sizeOverrideEnabled) { flags |= Display.Mode.FLAG_SIZE_OVERRIDE; } return new Display.Mode(NEXT_DISPLAY_MODE_ID.getAndIncrement(), Display.Mode.INVALID_MODE_ID, flags, mode.width, mode.height, mode.peakRefreshRate, mode.vsyncRate, Loading
services/core/java/com/android/server/display/LocalDisplayAdapter.java +7 −5 Original line number Diff line number Diff line Loading @@ -293,8 +293,8 @@ final class LocalDisplayAdapter extends DisplayAdapter { public boolean updateDisplayPropertiesLocked(SurfaceControl.StaticDisplayInfo staticInfo, SurfaceControl.DynamicDisplayInfo dynamicInfo, SurfaceControl.DesiredDisplayModeSpecs modeSpecs) { boolean changed = updateDisplayModesLocked(dynamicInfo, modeSpecs); boolean changed = updateDisplayModesLocked(dynamicInfo, modeSpecs, staticInfo.isInternal); changed |= updateStaticInfo(staticInfo); changed |= updateColorModesLocked(dynamicInfo.supportedColorModes, dynamicInfo.activeColorMode); Loading @@ -312,13 +312,15 @@ final class LocalDisplayAdapter extends DisplayAdapter { } private boolean updateDisplayModesLocked(SurfaceControl.DynamicDisplayInfo dynamicInfo, SurfaceControl.DesiredDisplayModeSpecs modeSpecs) { SurfaceControl.DesiredDisplayModeSpecs modeSpecs, boolean isInternal) { SurfaceControl.DisplayMode[] displayModes = dynamicInfo.supportedDisplayModes; int preferredSfDisplayModeId = dynamicInfo.preferredBootDisplayMode; int activeSfDisplayModeId = dynamicInfo.activeDisplayModeId; float renderFrameRate = dynamicInfo.renderFrameRate; boolean hasArrSupport = dynamicInfo.hasArrSupport; boolean syntheticModesV2Enabled = getFeatureFlags().isSyntheticModesV2Enabled(); boolean sizeOverrideEnabled = getFeatureFlags().isSizeOverrideForExternalDisplaysEnabled() && !isInternal; mSfDisplayModes = Arrays.copyOf(displayModes, displayModes.length); mActiveSfDisplayMode = getModeById(displayModes, activeSfDisplayModeId); Loading Loading @@ -369,8 +371,8 @@ final class LocalDisplayAdapter extends DisplayAdapter { for (int j = 0; j < alternativeRates.length; j++) { alternativeRates[j] = alternativeRefreshRates.get(j); } Display.Mode displayMode = DisplayModeFactory.createMode( mode, alternativeRates, hasArrSupport, syntheticModesV2Enabled); Display.Mode displayMode = DisplayModeFactory.createMode(mode, alternativeRates, hasArrSupport, syntheticModesV2Enabled, sizeOverrideEnabled); record = new DisplayModeRecord(displayMode); modesAdded = true; } Loading
services/core/java/com/android/server/display/LogicalDisplay.java +61 −12 Original line number Diff line number Diff line Loading @@ -16,6 +16,8 @@ package com.android.server.display; import static android.view.Display.Mode.INVALID_MODE_ID; import static com.android.server.display.DisplayDeviceInfo.TOUCH_NONE; import static com.android.server.display.layout.Layout.Display.POSITION_REAR; import static com.android.server.wm.utils.DisplayInfoOverrides.WM_OVERRIDE_FIELDS; Loading Loading @@ -232,15 +234,17 @@ final class LogicalDisplay { private final boolean mSyncedResolutionSwitchEnabled; private final boolean mSyntheticModesV2Enabled; private final boolean mSizeOverrideEnabled; private boolean mCanHostTasks; LogicalDisplay(int displayId, int layerStack, DisplayDevice primaryDisplayDevice) { this(displayId, layerStack, primaryDisplayDevice, false, true); this(displayId, layerStack, primaryDisplayDevice, false, true, false); } LogicalDisplay(int displayId, int layerStack, DisplayDevice primaryDisplayDevice, boolean isSyncedResolutionSwitchEnabled, boolean syntheticModesV2Enabled) { boolean isSyncedResolutionSwitchEnabled, boolean syntheticModesV2Enabled, boolean sizeOverrideEnabled) { mDisplayId = displayId; mLayerStack = layerStack; mPrimaryDisplayDevice = primaryDisplayDevice; Loading @@ -253,6 +257,7 @@ final class LogicalDisplay { mBaseDisplayInfo.thermalBrightnessThrottlingDataId = mThermalBrightnessThrottlingDataId; mSyncedResolutionSwitchEnabled = isSyncedResolutionSwitchEnabled; mSyntheticModesV2Enabled = syntheticModesV2Enabled; mSizeOverrideEnabled = sizeOverrideEnabled; // No need to initialize mCanHostTasks here; it's handled in // DisplayManagerService#setupLogicalDisplay(). Loading Loading @@ -505,16 +510,30 @@ final class LogicalDisplay { && mDevicePosition != Layout.Display.POSITION_REAR) { mBaseDisplayInfo.flags |= Display.FLAG_ALLOWS_CONTENT_MODE_SWITCH; } int currentWidth = deviceInfo.width; int currentHeight = deviceInfo.height; float currentXDpi = deviceInfo.xDpi; float currentYDpi = deviceInfo.yDpi; Display.Mode sizeOverrideMode = getUserPreferredModeForSizeOverrideLocked(deviceInfo); if (sizeOverrideMode != null && mSizeOverrideEnabled) { currentWidth = sizeOverrideMode.getPhysicalWidth(); currentHeight = sizeOverrideMode.getPhysicalHeight(); currentXDpi = currentXDpi * (currentWidth / (float) deviceInfo.width); currentYDpi = currentYDpi * (currentHeight / (float) deviceInfo.height); } Rect maskingInsets = getMaskingInsets(deviceInfo); int maskedWidth = deviceInfo.width - maskingInsets.left - maskingInsets.right; int maskedHeight = deviceInfo.height - maskingInsets.top - maskingInsets.bottom; int maskedWidth = currentWidth - maskingInsets.left - maskingInsets.right; int maskedHeight = currentHeight - maskingInsets.top - maskingInsets.bottom; if (mIsAnisotropyCorrectionEnabled && deviceInfo.type == Display.TYPE_EXTERNAL && deviceInfo.xDpi > 0 && deviceInfo.yDpi > 0) { if (deviceInfo.xDpi > deviceInfo.yDpi * DisplayDevice.MAX_ANISOTROPY) { maskedHeight = (int) (maskedHeight * deviceInfo.xDpi / deviceInfo.yDpi + 0.5); } else if (deviceInfo.xDpi * DisplayDevice.MAX_ANISOTROPY < deviceInfo.yDpi) { maskedWidth = (int) (maskedWidth * deviceInfo.yDpi / deviceInfo.xDpi + 0.5); && currentXDpi > 0 && currentYDpi > 0) { if (currentXDpi > currentYDpi * DisplayDevice.MAX_ANISOTROPY) { maskedHeight = (int) (maskedHeight * currentXDpi / currentYDpi + 0.5); } else if (currentXDpi * DisplayDevice.MAX_ANISOTROPY < currentYDpi) { maskedWidth = (int) (maskedWidth * currentYDpi / currentXDpi + 0.5); } } Loading Loading @@ -553,10 +572,10 @@ final class LogicalDisplay { deviceInfo.allmSupported || deviceInfo.gameContentTypeSupported; mBaseDisplayInfo.logicalDensityDpi = deviceInfo.densityDpi > 0 ? deviceInfo.densityDpi : calculateBaseDensity(deviceInfo.xDpi, deviceInfo.yDpi, maskedWidth, : calculateBaseDensity(currentXDpi, currentYDpi, maskedWidth, maskedHeight); mBaseDisplayInfo.physicalXDpi = deviceInfo.xDpi; mBaseDisplayInfo.physicalYDpi = deviceInfo.yDpi; mBaseDisplayInfo.physicalXDpi = currentXDpi; mBaseDisplayInfo.physicalYDpi = currentYDpi; mBaseDisplayInfo.appVsyncOffsetNanos = deviceInfo.appVsyncOffsetNanos; mBaseDisplayInfo.presentationDeadlineNanos = deviceInfo.presentationDeadlineNanos; mBaseDisplayInfo.state = deviceInfo.state; Loading Loading @@ -623,6 +642,36 @@ final class LogicalDisplay { return Math.max((int) (dpi + 0.5), EXTERNAL_DISPLAY_MIN_DENSITY_DPI); } @Nullable private Display.Mode getUserPreferredModeForSizeOverrideLocked(DisplayDeviceInfo deviceInfo) { Display.Mode[] modes = deviceInfo.supportedModes; int selectedModeId = deviceInfo.modeId; int userPreferredModeId = deviceInfo.userPreferredModeId; if (userPreferredModeId == INVALID_MODE_ID) { return null; } // user preferred mode is normal mode if (userPreferredModeId == selectedModeId) { return null; } Display.Mode userPreferredMode = null; for (Display.Mode mode : modes) { if (userPreferredModeId == mode.getModeId()) { userPreferredMode = mode; break; } } if (userPreferredMode != null && (userPreferredMode.getFlags() & Display.Mode.FLAG_SIZE_OVERRIDE) != 0) { return userPreferredMode; } return null; } private void updateFrameRateOverrides(DisplayDeviceInfo deviceInfo) { mTempFrameRateOverride.clear(); if (mFrameRateOverrides != null) { Loading
services/core/java/com/android/server/display/LogicalDisplayMapper.java +2 −1 Original line number Diff line number Diff line Loading @@ -1312,7 +1312,8 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener { private LogicalDisplay createNewLogicalDisplayLocked(DisplayDevice device, int displayId) { final int layerStack = assignLayerStackLocked(displayId); final LogicalDisplay display = new LogicalDisplay(displayId, layerStack, device, mFlags.isSyncedResolutionSwitchEnabled(), mFlags.isSyntheticModesV2Enabled()); mFlags.isSyncedResolutionSwitchEnabled(), mFlags.isSyntheticModesV2Enabled(), mFlags.isSizeOverrideForExternalDisplaysEnabled()); display.updateLocked(mDisplayDeviceRepo, mSyntheticModeManager); final DisplayInfo info = display.getDisplayInfoLocked(); Loading