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

Commit 3316a0a0 authored by Dominik Laskowski's avatar Dominik Laskowski
Browse files

Generalize physical display management

This CL enables the framework to manage an arbitrary number of physical
displays. It also surfaces physical display IDs, which are stable across
reboots and encode (model, port) information that will be propagated
further up in a follow-up CL.

Bug: 116025192
Test: Boot with more than two displays
Test: Hotplug works with any number of displays
Test: Verify stable display IDs with "dumpsys display"
Change-Id: Idb2eaff66b2e0873be6ad27d337ff18b730d1331
parent 1ba86936
Loading
Loading
Loading
Loading
+6 −7
Original line number Diff line number Diff line
@@ -252,10 +252,12 @@ status_t BootAnimation::initTexture(FileMap* map, int* width, int* height)
status_t BootAnimation::readyToRun() {
    mAssets.addDefaultAssets();

    sp<IBinder> dtoken(SurfaceComposerClient::getBuiltInDisplay(
            ISurfaceComposer::eDisplayIdMain));
    mDisplayToken = SurfaceComposerClient::getInternalDisplayToken();
    if (mDisplayToken == nullptr)
        return -1;

    DisplayInfo dinfo;
    status_t status = SurfaceComposerClient::getDisplayInfo(dtoken, &dinfo);
    status_t status = SurfaceComposerClient::getDisplayInfo(mDisplayToken, &dinfo);
    if (status)
        return -1;

@@ -1014,16 +1016,13 @@ void BootAnimation::handleViewport(nsecs_t timestep) {
        // At the end of the animation, we switch to the viewport that DisplayManager will apply
        // later. This changes the coordinate system, and means we must move the surface up by
        // the inset amount.
        sp<IBinder> dtoken(SurfaceComposerClient::getBuiltInDisplay(
                ISurfaceComposer::eDisplayIdMain));

        Rect layerStackRect(0, 0, mWidth, mHeight - mTargetInset);
        Rect displayRect(0, mTargetInset, mWidth, mHeight);

        SurfaceComposerClient::Transaction t;
        t.setPosition(mFlingerSurfaceControl, 0, -mTargetInset)
                .setCrop(mFlingerSurfaceControl, Rect(0, mTargetInset, mWidth, mHeight));
        t.setDisplayProjection(dtoken, 0 /* orientation */, layerStackRect, displayRect);
        t.setDisplayProjection(mDisplayToken, 0 /* orientation */, layerStackRect, displayRect);
        t.apply();

        mTargetInset = mCurrentInset = 0;
+1 −0
Original line number Diff line number Diff line
@@ -171,6 +171,7 @@ private:
    EGLDisplay  mDisplay;
    EGLDisplay  mContext;
    EGLDisplay  mSurface;
    sp<IBinder> mDisplayToken;
    sp<SurfaceControl> mFlingerSurfaceControl;
    sp<Surface> mFlingerSurface;
    bool        mClockEnabled;
+18 −13
Original line number Diff line number Diff line
@@ -46,23 +46,22 @@

using namespace android;

static uint32_t DEFAULT_DISPLAY_ID = ISurfaceComposer::eDisplayIdMain;

#define COLORSPACE_UNKNOWN    0
#define COLORSPACE_SRGB       1
#define COLORSPACE_DISPLAY_P3 2

static void usage(const char* pname)
static void usage(const char* pname, PhysicalDisplayId displayId)
{
    fprintf(stderr,
            "usage: %s [-hp] [-d display-id] [FILENAME]\n"
            "   -h: this message\n"
            "   -p: save the file as a png.\n"
            "   -d: specify the display id to capture, default %d.\n"
            "   -d: specify the physical display ID to capture (default: %"
                    ANDROID_PHYSICAL_DISPLAY_ID_FORMAT ")\n"
            "       see \"dumpsys SurfaceFlinger --display-id\" for valid display IDs.\n"
            "If FILENAME ends with .png it will be saved as a png.\n"
            "If FILENAME is not given, the results will be printed to stdout.\n",
            pname, DEFAULT_DISPLAY_ID
    );
            pname, displayId);
}

static SkColorType flinger2skia(PixelFormat f)
@@ -127,9 +126,14 @@ static status_t notifyMediaScanner(const char* fileName) {

int main(int argc, char** argv)
{
    std::optional<PhysicalDisplayId> displayId = SurfaceComposerClient::getInternalDisplayId();
    if (!displayId) {
        fprintf(stderr, "Failed to get token for internal display\n");
        return 1;
    }

    const char* pname = argv[0];
    bool png = false;
    int32_t displayId = DEFAULT_DISPLAY_ID;
    int c;
    while ((c = getopt(argc, argv, "phd:")) != -1) {
        switch (c) {
@@ -137,11 +141,11 @@ int main(int argc, char** argv)
                png = true;
                break;
            case 'd':
                displayId = atoi(optarg);
                displayId = atoll(optarg);
                break;
            case '?':
            case 'h':
                usage(pname);
                usage(pname, *displayId);
                return 1;
        }
    }
@@ -166,7 +170,7 @@ int main(int argc, char** argv)
    }

    if (fd == -1) {
        usage(pname);
        usage(pname, *displayId);
        return 1;
    }

@@ -192,9 +196,10 @@ int main(int argc, char** argv)
    ProcessState::self()->setThreadPoolMaxThreadCount(0);
    ProcessState::self()->startThreadPool();

    sp<IBinder> display = SurfaceComposerClient::getBuiltInDisplay(displayId);
    if (display == NULL) {
        fprintf(stderr, "Unable to get handle for display %d\n", displayId);
    const sp<IBinder> display = SurfaceComposerClient::getPhysicalDisplayToken(*displayId);
    if (display == nullptr) {
        fprintf(stderr, "Failed to get token for invalid display %"
                ANDROID_PHYSICAL_DISPLAY_ID_FORMAT "\n", *displayId);
        return 1;
    }

+0 −1
Original line number Diff line number Diff line
@@ -33456,7 +33456,6 @@ HSPLandroid/view/SurfaceControl;->destroy()V
HSPLandroid/view/SurfaceControl;->finalize()V
HSPLandroid/view/SurfaceControl;->getActiveColorMode(Landroid/os/IBinder;)I
HSPLandroid/view/SurfaceControl;->getActiveConfig(Landroid/os/IBinder;)I
HSPLandroid/view/SurfaceControl;->getBuiltInDisplay(I)Landroid/os/IBinder;
HSPLandroid/view/SurfaceControl;->getDisplayColorModes(Landroid/os/IBinder;)[I
HSPLandroid/view/SurfaceControl;->getDisplayConfigs(Landroid/os/IBinder;)[Landroid/view/SurfaceControl$PhysicalDisplayInfo;
HSPLandroid/view/SurfaceControl;->getHandle()Landroid/os/IBinder;
+4 −19
Original line number Diff line number Diff line
@@ -22,7 +22,6 @@ import static android.view.DisplayEventReceiver.VSYNC_SOURCE_SURFACE_FLINGER;
import android.annotation.TestApi;
import android.annotation.UnsupportedAppUsage;
import android.graphics.FrameInfo;
import android.graphics.Insets;
import android.hardware.display.DisplayManagerGlobal;
import android.os.Build;
import android.os.Handler;
@@ -914,25 +913,11 @@ public final class Choreographer {
            super(looper, vsyncSource);
        }

        // TODO(b/116025192): physicalDisplayId is ignored because SF only emits VSYNC events for
        // the internal display and DisplayEventReceiver#scheduleVsync only allows requesting VSYNC
        // for the internal display implicitly.
        @Override
        public void onVsync(long timestampNanos, int builtInDisplayId, int frame) {
            // Ignore vsync from secondary display.
            // This can be problematic because the call to scheduleVsync() is a one-shot.
            // We need to ensure that we will still receive the vsync from the primary
            // display which is the one we really care about.  Ideally we should schedule
            // vsync for a particular display.
            // At this time Surface Flinger won't send us vsyncs for secondary displays
            // but that could change in the future so let's log a message to help us remember
            // that we need to fix this.
            if (builtInDisplayId != SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN) {
                Log.d(TAG, "Received vsync from secondary display, but we don't support "
                        + "this case yet.  Choreographer needs a way to explicitly request "
                        + "vsync for a specific display to ensure it doesn't lose track "
                        + "of its scheduled vsync.");
                scheduleVsync();
                return;
            }

        public void onVsync(long timestampNanos, long physicalDisplayId, int frame) {
            // Post the vsync event to the Handler.
            // The idea is to prevent incoming vsync events from completely starving
            // the message queue.  If there are no messages in the queue with timestamps
Loading