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

Commit 670ec4a1 authored by Oleg Blinnikov's avatar Oleg Blinnikov Committed by Android (Google) Code Review
Browse files

Merge "Handle non-square pixels on External display" into main

parents 5e564dbb d0b0bf69
Loading
Loading
Loading
Loading
+29 −3
Original line number Diff line number Diff line
@@ -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();

@@ -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;
    }

    /**
@@ -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);
    }

    /**
+2 −1
Original line number Diff line number Diff line
@@ -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);
+61 −7
Original line number Diff line number Diff line
@@ -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;
@@ -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;
@@ -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) {
@@ -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;
@@ -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
@@ -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;
+2 −1
Original line number Diff line number Diff line
@@ -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();
+10 −0
Original line number Diff line number Diff line
@@ -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
@@ -259,6 +264,10 @@ public class DisplayManagerFlags {
        return mRefreshRateVotingTelemetry.isEnabled();
    }

    public boolean isPixelAnisotropyCorrectionInLogicalDisplayEnabled() {
        return mPixelAnisotropyCorrectionEnabled.isEnabled();
    }

    public boolean isSensorBasedBrightnessThrottlingEnabled() {
        return mSensorBasedBrightnessThrottling.isEnabled();
    }
@@ -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