Loading services/core/java/com/android/server/display/DisplayDevice.java +29 −3 Original line number Diff line number Diff line Loading @@ -44,6 +44,15 @@ import java.io.PrintWriter; * </p> */ abstract class DisplayDevice { /** * Maximum acceptable anisotropy for the output image. * * Necessary to avoid unnecessary scaling when pixels are almost square, as they are non ideal * anyway. For external displays, we expect an anisotropy of about 2% even if the pixels * are, in fact, square due to the imprecision of the display's actual size (parsed from edid * and rounded to the nearest cm). */ static final float MAX_ANISOTROPY = 1.025f; private static final String TAG = "DisplayDevice"; private static final Display.Mode EMPTY_DISPLAY_MODE = new Display.Mode.Builder().build(); Loading @@ -69,13 +78,21 @@ abstract class DisplayDevice { // Do not use for any other purpose. DisplayDeviceInfo mDebugLastLoggedDeviceInfo; public DisplayDevice(DisplayAdapter displayAdapter, IBinder displayToken, String uniqueId, private final boolean mIsAnisotropyCorrectionEnabled; DisplayDevice(DisplayAdapter displayAdapter, IBinder displayToken, String uniqueId, Context context) { this(displayAdapter, displayToken, uniqueId, context, false); } DisplayDevice(DisplayAdapter displayAdapter, IBinder displayToken, String uniqueId, Context context, boolean isAnisotropyCorrectionEnabled) { mDisplayAdapter = displayAdapter; mDisplayToken = displayToken; mUniqueId = uniqueId; mDisplayDeviceConfig = null; mContext = context; mIsAnisotropyCorrectionEnabled = isAnisotropyCorrectionEnabled; } /** Loading Loading @@ -143,8 +160,17 @@ abstract class DisplayDevice { DisplayDeviceInfo displayDeviceInfo = getDisplayDeviceInfoLocked(); final boolean isRotated = mCurrentOrientation == ROTATION_90 || mCurrentOrientation == ROTATION_270; return isRotated ? new Point(displayDeviceInfo.height, displayDeviceInfo.width) : new Point(displayDeviceInfo.width, displayDeviceInfo.height); var width = displayDeviceInfo.width; var height = displayDeviceInfo.height; if (mIsAnisotropyCorrectionEnabled && displayDeviceInfo.yDpi > 0 && displayDeviceInfo.xDpi > 0) { if (displayDeviceInfo.xDpi > displayDeviceInfo.yDpi * MAX_ANISOTROPY) { height = (int) (height * displayDeviceInfo.xDpi / displayDeviceInfo.yDpi + 0.5); } else if (displayDeviceInfo.xDpi * MAX_ANISOTROPY < displayDeviceInfo.yDpi) { width = (int) (width * displayDeviceInfo.yDpi / displayDeviceInfo.xDpi + 0.5); } } return isRotated ? new Point(height, width) : new Point(width, height); } /** Loading services/core/java/com/android/server/display/LocalDisplayAdapter.java +2 −1 Original line number Diff line number Diff line Loading @@ -257,7 +257,8 @@ final class LocalDisplayAdapter extends DisplayAdapter { SurfaceControl.DynamicDisplayInfo dynamicInfo, SurfaceControl.DesiredDisplayModeSpecs modeSpecs, boolean isFirstDisplay) { super(LocalDisplayAdapter.this, displayToken, UNIQUE_ID_PREFIX + physicalDisplayId, getContext()); getContext(), getFeatureFlags().isPixelAnisotropyCorrectionInLogicalDisplayEnabled()); mPhysicalDisplayId = physicalDisplayId; mIsFirstDisplay = isFirstDisplay; updateDisplayPropertiesLocked(staticDisplayInfo, dynamicInfo, modeSpecs); Loading services/core/java/com/android/server/display/LogicalDisplay.java +61 −7 Original line number Diff line number Diff line Loading @@ -35,7 +35,6 @@ import android.view.SurfaceControl; import com.android.server.display.layout.Layout; import com.android.server.display.mode.DisplayModeDirector; import com.android.server.wm.utils.DisplayInfoOverrides; import com.android.server.wm.utils.InsetUtils; import java.io.PrintWriter; Loading Loading @@ -204,7 +203,28 @@ final class LogicalDisplay { private SparseArray<SurfaceControl.RefreshRateRange> mThermalRefreshRateThrottling = new SparseArray<>(); /** * If the aspect ratio of the resolution of the display does not match the physical aspect * ratio of the display, then without this feature enabled, picture would appear stretched to * the user. This is because applications assume that they are rendered on square pixels * (meaning density of pixels in x and y directions are equal). This would result into circles * appearing as ellipses to the user. * To compensate for non-square (anisotropic) pixels, if this feature is enabled: * 1. LogicalDisplay will add more pixels for the applications to render on, as if the pixels * were square and occupied the full display. * 2. SurfaceFlinger will squeeze this taller/wider surface into the available number of * physical pixels in the current display resolution. * 3. If a setting on the display itself is set to "fill the entire display panel" then the * display will stretch the pixels to fill the display fully. */ private final boolean mIsAnisotropyCorrectionEnabled; LogicalDisplay(int displayId, int layerStack, DisplayDevice primaryDisplayDevice) { this(displayId, layerStack, primaryDisplayDevice, false); } LogicalDisplay(int displayId, int layerStack, DisplayDevice primaryDisplayDevice, boolean isAnisotropyCorrectionEnabled) { mDisplayId = displayId; mLayerStack = layerStack; mPrimaryDisplayDevice = primaryDisplayDevice; Loading @@ -215,6 +235,7 @@ final class LogicalDisplay { mThermalBrightnessThrottlingDataId = DisplayDeviceConfig.DEFAULT_ID; mPowerThrottlingDataId = DisplayDeviceConfig.DEFAULT_ID; mBaseDisplayInfo.thermalBrightnessThrottlingDataId = mThermalBrightnessThrottlingDataId; mIsAnisotropyCorrectionEnabled = isAnisotropyCorrectionEnabled; } public void setDevicePositionLocked(int position) { Loading Loading @@ -453,6 +474,14 @@ final class LogicalDisplay { int maskedWidth = deviceInfo.width - maskingInsets.left - maskingInsets.right; int maskedHeight = deviceInfo.height - maskingInsets.top - maskingInsets.bottom; if (mIsAnisotropyCorrectionEnabled && 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); } } mBaseDisplayInfo.type = deviceInfo.type; mBaseDisplayInfo.address = deviceInfo.address; mBaseDisplayInfo.deviceProductInfo = deviceInfo.deviceProductInfo; Loading Loading @@ -666,6 +695,31 @@ final class LogicalDisplay { physWidth -= maskingInsets.left + maskingInsets.right; physHeight -= maskingInsets.top + maskingInsets.bottom; var displayLogicalWidth = displayInfo.logicalWidth; var displayLogicalHeight = displayInfo.logicalHeight; if (mIsAnisotropyCorrectionEnabled && displayDeviceInfo.xDpi > 0 && displayDeviceInfo.yDpi > 0) { if (displayDeviceInfo.xDpi > displayDeviceInfo.yDpi * DisplayDevice.MAX_ANISOTROPY) { var scalingFactor = displayDeviceInfo.yDpi / displayDeviceInfo.xDpi; if (rotated) { displayLogicalWidth = (int) ((float) displayLogicalWidth * scalingFactor + 0.5); } else { displayLogicalHeight = (int) ((float) displayLogicalHeight * scalingFactor + 0.5); } } else if (displayDeviceInfo.xDpi * DisplayDevice.MAX_ANISOTROPY < displayDeviceInfo.yDpi) { var scalingFactor = displayDeviceInfo.xDpi / displayDeviceInfo.yDpi; if (rotated) { displayLogicalHeight = (int) ((float) displayLogicalHeight * scalingFactor + 0.5); } else { displayLogicalWidth = (int) ((float) displayLogicalWidth * scalingFactor + 0.5); } } } // Determine whether the width or height is more constrained to be scaled. // physWidth / displayInfo.logicalWidth => letter box // or physHeight / displayInfo.logicalHeight => pillar box Loading @@ -675,16 +729,16 @@ final class LogicalDisplay { // comparing them. int displayRectWidth, displayRectHeight; if ((displayInfo.flags & Display.FLAG_SCALING_DISABLED) != 0 || mDisplayScalingDisabled) { displayRectWidth = displayInfo.logicalWidth; displayRectHeight = displayInfo.logicalHeight; } else if (physWidth * displayInfo.logicalHeight < physHeight * displayInfo.logicalWidth) { displayRectWidth = displayLogicalWidth; displayRectHeight = displayLogicalHeight; } else if (physWidth * displayLogicalHeight < physHeight * displayLogicalWidth) { // Letter box. displayRectWidth = physWidth; displayRectHeight = displayInfo.logicalHeight * physWidth / displayInfo.logicalWidth; displayRectHeight = displayLogicalHeight * physWidth / displayLogicalWidth; } else { // Pillar box. displayRectWidth = displayInfo.logicalWidth * physHeight / displayInfo.logicalHeight; displayRectWidth = displayLogicalWidth * physHeight / displayLogicalHeight; displayRectHeight = physHeight; } int displayRectTop = (physHeight - displayRectHeight) / 2; Loading services/core/java/com/android/server/display/LogicalDisplayMapper.java +2 −1 Original line number Diff line number Diff line Loading @@ -1151,7 +1151,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); final LogicalDisplay display = new LogicalDisplay(displayId, layerStack, device, mFlags.isPixelAnisotropyCorrectionInLogicalDisplayEnabled()); display.updateLocked(mDisplayDeviceRepo); final DisplayInfo info = display.getDisplayInfoLocked(); Loading services/core/java/com/android/server/display/feature/DisplayManagerFlags.java +10 −0 Original line number Diff line number Diff line Loading @@ -121,6 +121,11 @@ public class DisplayManagerFlags { Flags::refreshRateVotingTelemetry ); private final FlagState mPixelAnisotropyCorrectionEnabled = new FlagState( Flags.FLAG_ENABLE_PIXEL_ANISOTROPY_CORRECTION, Flags::enablePixelAnisotropyCorrection ); private final FlagState mSensorBasedBrightnessThrottling = new FlagState( Flags.FLAG_SENSOR_BASED_BRIGHTNESS_THROTTLING, Flags::sensorBasedBrightnessThrottling Loading Loading @@ -259,6 +264,10 @@ public class DisplayManagerFlags { return mRefreshRateVotingTelemetry.isEnabled(); } public boolean isPixelAnisotropyCorrectionInLogicalDisplayEnabled() { return mPixelAnisotropyCorrectionEnabled.isEnabled(); } public boolean isSensorBasedBrightnessThrottlingEnabled() { return mSensorBasedBrightnessThrottling.isEnabled(); } Loading Loading @@ -290,6 +299,7 @@ public class DisplayManagerFlags { pw.println(" " + mAutoBrightnessModesFlagState); pw.println(" " + mFastHdrTransitions); pw.println(" " + mRefreshRateVotingTelemetry); pw.println(" " + mPixelAnisotropyCorrectionEnabled); pw.println(" " + mSensorBasedBrightnessThrottling); pw.println(" " + mRefactorDisplayPowerController); } Loading Loading
services/core/java/com/android/server/display/DisplayDevice.java +29 −3 Original line number Diff line number Diff line Loading @@ -44,6 +44,15 @@ import java.io.PrintWriter; * </p> */ abstract class DisplayDevice { /** * Maximum acceptable anisotropy for the output image. * * Necessary to avoid unnecessary scaling when pixels are almost square, as they are non ideal * anyway. For external displays, we expect an anisotropy of about 2% even if the pixels * are, in fact, square due to the imprecision of the display's actual size (parsed from edid * and rounded to the nearest cm). */ static final float MAX_ANISOTROPY = 1.025f; private static final String TAG = "DisplayDevice"; private static final Display.Mode EMPTY_DISPLAY_MODE = new Display.Mode.Builder().build(); Loading @@ -69,13 +78,21 @@ abstract class DisplayDevice { // Do not use for any other purpose. DisplayDeviceInfo mDebugLastLoggedDeviceInfo; public DisplayDevice(DisplayAdapter displayAdapter, IBinder displayToken, String uniqueId, private final boolean mIsAnisotropyCorrectionEnabled; DisplayDevice(DisplayAdapter displayAdapter, IBinder displayToken, String uniqueId, Context context) { this(displayAdapter, displayToken, uniqueId, context, false); } DisplayDevice(DisplayAdapter displayAdapter, IBinder displayToken, String uniqueId, Context context, boolean isAnisotropyCorrectionEnabled) { mDisplayAdapter = displayAdapter; mDisplayToken = displayToken; mUniqueId = uniqueId; mDisplayDeviceConfig = null; mContext = context; mIsAnisotropyCorrectionEnabled = isAnisotropyCorrectionEnabled; } /** Loading Loading @@ -143,8 +160,17 @@ abstract class DisplayDevice { DisplayDeviceInfo displayDeviceInfo = getDisplayDeviceInfoLocked(); final boolean isRotated = mCurrentOrientation == ROTATION_90 || mCurrentOrientation == ROTATION_270; return isRotated ? new Point(displayDeviceInfo.height, displayDeviceInfo.width) : new Point(displayDeviceInfo.width, displayDeviceInfo.height); var width = displayDeviceInfo.width; var height = displayDeviceInfo.height; if (mIsAnisotropyCorrectionEnabled && displayDeviceInfo.yDpi > 0 && displayDeviceInfo.xDpi > 0) { if (displayDeviceInfo.xDpi > displayDeviceInfo.yDpi * MAX_ANISOTROPY) { height = (int) (height * displayDeviceInfo.xDpi / displayDeviceInfo.yDpi + 0.5); } else if (displayDeviceInfo.xDpi * MAX_ANISOTROPY < displayDeviceInfo.yDpi) { width = (int) (width * displayDeviceInfo.yDpi / displayDeviceInfo.xDpi + 0.5); } } return isRotated ? new Point(height, width) : new Point(width, height); } /** Loading
services/core/java/com/android/server/display/LocalDisplayAdapter.java +2 −1 Original line number Diff line number Diff line Loading @@ -257,7 +257,8 @@ final class LocalDisplayAdapter extends DisplayAdapter { SurfaceControl.DynamicDisplayInfo dynamicInfo, SurfaceControl.DesiredDisplayModeSpecs modeSpecs, boolean isFirstDisplay) { super(LocalDisplayAdapter.this, displayToken, UNIQUE_ID_PREFIX + physicalDisplayId, getContext()); getContext(), getFeatureFlags().isPixelAnisotropyCorrectionInLogicalDisplayEnabled()); mPhysicalDisplayId = physicalDisplayId; mIsFirstDisplay = isFirstDisplay; updateDisplayPropertiesLocked(staticDisplayInfo, dynamicInfo, modeSpecs); Loading
services/core/java/com/android/server/display/LogicalDisplay.java +61 −7 Original line number Diff line number Diff line Loading @@ -35,7 +35,6 @@ import android.view.SurfaceControl; import com.android.server.display.layout.Layout; import com.android.server.display.mode.DisplayModeDirector; import com.android.server.wm.utils.DisplayInfoOverrides; import com.android.server.wm.utils.InsetUtils; import java.io.PrintWriter; Loading Loading @@ -204,7 +203,28 @@ final class LogicalDisplay { private SparseArray<SurfaceControl.RefreshRateRange> mThermalRefreshRateThrottling = new SparseArray<>(); /** * If the aspect ratio of the resolution of the display does not match the physical aspect * ratio of the display, then without this feature enabled, picture would appear stretched to * the user. This is because applications assume that they are rendered on square pixels * (meaning density of pixels in x and y directions are equal). This would result into circles * appearing as ellipses to the user. * To compensate for non-square (anisotropic) pixels, if this feature is enabled: * 1. LogicalDisplay will add more pixels for the applications to render on, as if the pixels * were square and occupied the full display. * 2. SurfaceFlinger will squeeze this taller/wider surface into the available number of * physical pixels in the current display resolution. * 3. If a setting on the display itself is set to "fill the entire display panel" then the * display will stretch the pixels to fill the display fully. */ private final boolean mIsAnisotropyCorrectionEnabled; LogicalDisplay(int displayId, int layerStack, DisplayDevice primaryDisplayDevice) { this(displayId, layerStack, primaryDisplayDevice, false); } LogicalDisplay(int displayId, int layerStack, DisplayDevice primaryDisplayDevice, boolean isAnisotropyCorrectionEnabled) { mDisplayId = displayId; mLayerStack = layerStack; mPrimaryDisplayDevice = primaryDisplayDevice; Loading @@ -215,6 +235,7 @@ final class LogicalDisplay { mThermalBrightnessThrottlingDataId = DisplayDeviceConfig.DEFAULT_ID; mPowerThrottlingDataId = DisplayDeviceConfig.DEFAULT_ID; mBaseDisplayInfo.thermalBrightnessThrottlingDataId = mThermalBrightnessThrottlingDataId; mIsAnisotropyCorrectionEnabled = isAnisotropyCorrectionEnabled; } public void setDevicePositionLocked(int position) { Loading Loading @@ -453,6 +474,14 @@ final class LogicalDisplay { int maskedWidth = deviceInfo.width - maskingInsets.left - maskingInsets.right; int maskedHeight = deviceInfo.height - maskingInsets.top - maskingInsets.bottom; if (mIsAnisotropyCorrectionEnabled && 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); } } mBaseDisplayInfo.type = deviceInfo.type; mBaseDisplayInfo.address = deviceInfo.address; mBaseDisplayInfo.deviceProductInfo = deviceInfo.deviceProductInfo; Loading Loading @@ -666,6 +695,31 @@ final class LogicalDisplay { physWidth -= maskingInsets.left + maskingInsets.right; physHeight -= maskingInsets.top + maskingInsets.bottom; var displayLogicalWidth = displayInfo.logicalWidth; var displayLogicalHeight = displayInfo.logicalHeight; if (mIsAnisotropyCorrectionEnabled && displayDeviceInfo.xDpi > 0 && displayDeviceInfo.yDpi > 0) { if (displayDeviceInfo.xDpi > displayDeviceInfo.yDpi * DisplayDevice.MAX_ANISOTROPY) { var scalingFactor = displayDeviceInfo.yDpi / displayDeviceInfo.xDpi; if (rotated) { displayLogicalWidth = (int) ((float) displayLogicalWidth * scalingFactor + 0.5); } else { displayLogicalHeight = (int) ((float) displayLogicalHeight * scalingFactor + 0.5); } } else if (displayDeviceInfo.xDpi * DisplayDevice.MAX_ANISOTROPY < displayDeviceInfo.yDpi) { var scalingFactor = displayDeviceInfo.xDpi / displayDeviceInfo.yDpi; if (rotated) { displayLogicalHeight = (int) ((float) displayLogicalHeight * scalingFactor + 0.5); } else { displayLogicalWidth = (int) ((float) displayLogicalWidth * scalingFactor + 0.5); } } } // Determine whether the width or height is more constrained to be scaled. // physWidth / displayInfo.logicalWidth => letter box // or physHeight / displayInfo.logicalHeight => pillar box Loading @@ -675,16 +729,16 @@ final class LogicalDisplay { // comparing them. int displayRectWidth, displayRectHeight; if ((displayInfo.flags & Display.FLAG_SCALING_DISABLED) != 0 || mDisplayScalingDisabled) { displayRectWidth = displayInfo.logicalWidth; displayRectHeight = displayInfo.logicalHeight; } else if (physWidth * displayInfo.logicalHeight < physHeight * displayInfo.logicalWidth) { displayRectWidth = displayLogicalWidth; displayRectHeight = displayLogicalHeight; } else if (physWidth * displayLogicalHeight < physHeight * displayLogicalWidth) { // Letter box. displayRectWidth = physWidth; displayRectHeight = displayInfo.logicalHeight * physWidth / displayInfo.logicalWidth; displayRectHeight = displayLogicalHeight * physWidth / displayLogicalWidth; } else { // Pillar box. displayRectWidth = displayInfo.logicalWidth * physHeight / displayInfo.logicalHeight; displayRectWidth = displayLogicalWidth * physHeight / displayLogicalHeight; displayRectHeight = physHeight; } int displayRectTop = (physHeight - displayRectHeight) / 2; Loading
services/core/java/com/android/server/display/LogicalDisplayMapper.java +2 −1 Original line number Diff line number Diff line Loading @@ -1151,7 +1151,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); final LogicalDisplay display = new LogicalDisplay(displayId, layerStack, device, mFlags.isPixelAnisotropyCorrectionInLogicalDisplayEnabled()); display.updateLocked(mDisplayDeviceRepo); final DisplayInfo info = display.getDisplayInfoLocked(); Loading
services/core/java/com/android/server/display/feature/DisplayManagerFlags.java +10 −0 Original line number Diff line number Diff line Loading @@ -121,6 +121,11 @@ public class DisplayManagerFlags { Flags::refreshRateVotingTelemetry ); private final FlagState mPixelAnisotropyCorrectionEnabled = new FlagState( Flags.FLAG_ENABLE_PIXEL_ANISOTROPY_CORRECTION, Flags::enablePixelAnisotropyCorrection ); private final FlagState mSensorBasedBrightnessThrottling = new FlagState( Flags.FLAG_SENSOR_BASED_BRIGHTNESS_THROTTLING, Flags::sensorBasedBrightnessThrottling Loading Loading @@ -259,6 +264,10 @@ public class DisplayManagerFlags { return mRefreshRateVotingTelemetry.isEnabled(); } public boolean isPixelAnisotropyCorrectionInLogicalDisplayEnabled() { return mPixelAnisotropyCorrectionEnabled.isEnabled(); } public boolean isSensorBasedBrightnessThrottlingEnabled() { return mSensorBasedBrightnessThrottling.isEnabled(); } Loading Loading @@ -290,6 +299,7 @@ public class DisplayManagerFlags { pw.println(" " + mAutoBrightnessModesFlagState); pw.println(" " + mFastHdrTransitions); pw.println(" " + mRefreshRateVotingTelemetry); pw.println(" " + mPixelAnisotropyCorrectionEnabled); pw.println(" " + mSensorBasedBrightnessThrottling); pw.println(" " + mRefactorDisplayPowerController); } Loading