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

Commit 3094df35 authored by Mathias Agopian's avatar Mathias Agopian
Browse files

First prototype atttempting to support an external display

both API and implementation will change, this is just a prototype
intended to show feasability.

SurfaceFlinger is passed an ISurfaceTexture through a new
callback, it is in turn used to create an EGLSurface which
surfaceflinger will draw into in addition to the main screen.

Change-Id: Id0bbb0b854bb7bae44d57246a90b65d4567f9a21
parent 852db07d
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -145,6 +145,9 @@ public:

    /* triggers screen on and waits for it to complete */
    virtual void unblank() = 0;

    /* connects to an external display */
    virtual void connectDisplay(const sp<ISurfaceTexture> display) = 0;
};

// ----------------------------------------------------------------------------
@@ -168,6 +171,7 @@ public:
        CREATE_DISPLAY_EVENT_CONNECTION,
        BLANK,
        UNBLANK,
        CONNECT_DISPLAY,
    };

    virtual status_t    onTransact( uint32_t code,
+13 −0
Original line number Diff line number Diff line
@@ -207,6 +207,13 @@ public:
        data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
        remote()->transact(BnSurfaceComposer::UNBLANK, data, &reply);
    }

    virtual void connectDisplay(const sp<ISurfaceTexture> display) {
        Parcel data, reply;
        data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
        data.writeStrongBinder(display->asBinder());
        remote()->transact(BnSurfaceComposer::CONNECT_DISPLAY, data, &reply);
    }
};

IMPLEMENT_META_INTERFACE(SurfaceComposer, "android.ui.ISurfaceComposer");
@@ -301,6 +308,12 @@ status_t BnSurfaceComposer::onTransact(
            CHECK_INTERFACE(ISurfaceComposer, data, reply);
            unblank();
        } break;
        case CONNECT_DISPLAY: {
            CHECK_INTERFACE(ISurfaceComposer, data, reply);
            sp<ISurfaceTexture> surfaceTexture =
                    interface_cast<ISurfaceTexture>(data.readStrongBinder());
            connectDisplay(surfaceTexture);
        } break;
        default:
            return BBinder::onTransact(code, data, reply, flags);
    }
+9 −12
Original line number Diff line number Diff line
@@ -225,20 +225,10 @@ void DisplayHardware::init(uint32_t dpy)
    // initialize EGL
    EGLint attribs[] = {
            EGL_SURFACE_TYPE,           EGL_WINDOW_BIT,
            EGL_NONE,               0,
            EGL_RECORDABLE_ANDROID,     EGL_TRUE,
            EGL_NONE
    };

    // debug: disable h/w rendering
    char property[PROPERTY_VALUE_MAX];
    if (property_get("debug.sf.hw", property, NULL) > 0) {
        if (atoi(property) == 0) {
            ALOGW("H/W composition disabled");
            attribs[2] = EGL_CONFIG_CAVEAT;
            attribs[3] = EGL_SLOW_CONFIG;
        }
    }

    // TODO: all the extensions below should be queried through
    // eglGetProcAddress().

@@ -248,6 +238,13 @@ void DisplayHardware::init(uint32_t dpy)

    EGLConfig config = NULL;
    err = selectConfigForPixelFormat(display, attribs, format, &config);
    if (err) {
        // maybe we failed because of EGL_RECORDABLE_ANDROID
        ALOGW("couldn't find an EGLConfig with EGL_RECORDABLE_ANDROID");
        attribs[2] = EGL_NONE;
        err = selectConfigForPixelFormat(display, attribs, format, &config);
    }

    ALOGE_IF(err, "couldn't find an EGLConfig matching the screen format");
    
    EGLint r,g,b,a;
+1 −0
Original line number Diff line number Diff line
@@ -96,6 +96,7 @@ public:

    uint32_t getPageFlipCount() const;
    EGLDisplay getEGLDisplay() const { return mDisplay; }
    EGLConfig getEGLConfig() const { return mConfig; }

    void dump(String8& res) const;

+75 −1
Original line number Diff line number Diff line
@@ -64,6 +64,7 @@
#include <private/android_filesystem_config.h>
#include <private/gui/SharedBufferStack.h>
#include <gui/BitTube.h>
#include <gui/SurfaceTextureClient.h>

#define EGL_VERSION_HW_ANDROID  0x3143

@@ -97,7 +98,8 @@ SurfaceFlinger::SurfaceFlinger()
        mDebugInTransaction(0),
        mLastTransactionTime(0),
        mBootFinished(false),
        mSecureFrameBuffer(0)
        mSecureFrameBuffer(0),
        mExternalDisplaySurface(EGL_NO_SURFACE)
{
    init();
}
@@ -370,6 +372,41 @@ sp<IDisplayEventConnection> SurfaceFlinger::createDisplayEventConnection() {
    return mEventThread->createEventConnection();
}

void SurfaceFlinger::connectDisplay(const sp<ISurfaceTexture> display) {
    const DisplayHardware& hw(graphicPlane(0).displayHardware());
    EGLSurface result = EGL_NO_SURFACE;
    EGLSurface old_surface = EGL_NO_SURFACE;
    sp<SurfaceTextureClient> stc;

    if (display != NULL) {
        stc = new SurfaceTextureClient(display);
        result = eglCreateWindowSurface(hw.getEGLDisplay(),
                hw.getEGLConfig(), (EGLNativeWindowType)stc.get(), NULL);
        ALOGE_IF(result == EGL_NO_SURFACE,
                "eglCreateWindowSurface failed (ISurfaceTexture=%p)",
                display.get());
    }

    { // scope for the lock
        Mutex::Autolock _l(mStateLock);
        old_surface = mExternalDisplaySurface;
        mExternalDisplayNativeWindow = stc;
        mExternalDisplaySurface = result;
        ALOGD("mExternalDisplaySurface = %p", result);
    }

    if (old_surface != EGL_NO_SURFACE) {
        // Note: EGL allows to destroy an object while its current
        // it will fail to become current next time though.
        eglDestroySurface(hw.getEGLDisplay(), old_surface);
    }
}

EGLSurface SurfaceFlinger::getExternalDisplaySurface() const {
    Mutex::Autolock _l(mStateLock);
    return mExternalDisplaySurface;
}

// ----------------------------------------------------------------------------

void SurfaceFlinger::waitForEvent() {
@@ -454,6 +491,43 @@ void SurfaceFlinger::onMessageReceived(int32_t what)
                hw.compositionComplete();
            }

            // render to the external display if we have one
            EGLSurface externalDisplaySurface = getExternalDisplaySurface();
            if (externalDisplaySurface != EGL_NO_SURFACE) {
                EGLSurface cur = eglGetCurrentSurface(EGL_DRAW);
                EGLBoolean success = eglMakeCurrent(eglGetCurrentDisplay(),
                        externalDisplaySurface, externalDisplaySurface,
                        eglGetCurrentContext());

                ALOGE_IF(!success, "eglMakeCurrent -> external failed");

                if (success) {
                    // redraw the screen entirely...
                    glDisable(GL_TEXTURE_EXTERNAL_OES);
                    glDisable(GL_TEXTURE_2D);
                    glClearColor(0,0,0,1);
                    glClear(GL_COLOR_BUFFER_BIT);
                    glMatrixMode(GL_MODELVIEW);
                    glLoadIdentity();
                    const Vector< sp<LayerBase> >& layers(mVisibleLayersSortedByZ);
                    const size_t count = layers.size();
                    for (size_t i=0 ; i<count ; ++i) {
                        const sp<LayerBase>& layer(layers[i]);
                        layer->drawForSreenShot();
                    }

                    success = eglSwapBuffers(eglGetCurrentDisplay(), externalDisplaySurface);
                    ALOGE_IF(!success, "external display eglSwapBuffers failed");

                    hw.compositionComplete();
                }

                success = eglMakeCurrent(eglGetCurrentDisplay(),
                        cur, cur, eglGetCurrentContext());

                ALOGE_IF(!success, "eglMakeCurrent -> internal failed");
            }

        } break;
    }
}
Loading