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

Commit ffe1f19c authored by Jesse Hall's avatar Jesse Hall
Browse files

Fix virtual displays for HWC<=1.1

If we're using a HWC that doesn't support virtual displays, or we have
more virtual displays than HWC supports concurrently, the
VirtualDisplaySurface should simply be a passthrough from source
(GLES) to sink.

This change also tries to distinguish between display types and HWC
display IDs a little better, though there's more to do here. Probably
needs a higher-level rethink; it's too error-prone now.

Bug: 8446838
Change-Id: I708d2cf262ec30177042304f174ca5b8da701df1
parent 48bc05b5
Loading
Loading
Loading
Loading
+31 −38
Original line number Diff line number Diff line
@@ -70,12 +70,13 @@ void checkGLErrors()
DisplayDevice::DisplayDevice(
        const sp<SurfaceFlinger>& flinger,
        DisplayType type,
        int32_t hwcId,
        bool isSecure,
        const wp<IBinder>& displayToken,
        const sp<DisplaySurface>& displaySurface,
        EGLConfig config)
    : mFlinger(flinger),
      mType(type), mHwcDisplayId(-1),
      mType(type), mHwcDisplayId(hwcId),
      mDisplayToken(displayToken),
      mDisplaySurface(displaySurface),
      mDisplay(EGL_NO_DISPLAY),
@@ -91,38 +92,6 @@ DisplayDevice::DisplayDevice(
      mOrientation()
{
    mNativeWindow = new Surface(mDisplaySurface->getIGraphicBufferProducer());
    init(config);
}

DisplayDevice::~DisplayDevice() {
    if (mSurface != EGL_NO_SURFACE) {
        eglDestroySurface(mDisplay, mSurface);
        mSurface = EGL_NO_SURFACE;
    }
}

bool DisplayDevice::isValid() const {
    return mFlinger != NULL;
}

int DisplayDevice::getWidth() const {
    return mDisplayWidth;
}

int DisplayDevice::getHeight() const {
    return mDisplayHeight;
}

PixelFormat DisplayDevice::getFormat() const {
    return mFormat;
}

EGLSurface DisplayDevice::getEGLSurface() const {
    return mSurface;
}

void DisplayDevice::init(EGLConfig config)
{
    ANativeWindow* const window = mNativeWindow.get();

    int format;
@@ -146,11 +115,8 @@ void DisplayDevice::init(EGLConfig config)
    mViewport.makeInvalid();
    mFrame.makeInvalid();

    // external displays are always considered enabled
    mScreenAcquired = (mType >= DisplayDevice::NUM_DISPLAY_TYPES);

    // get an h/w composer ID
    mHwcDisplayId = mFlinger->allocateHwcDisplayId(mType);
    // virtual displays are always considered enabled
    mScreenAcquired = (mType >= DisplayDevice::DISPLAY_VIRTUAL);

    // Name the display.  The name will be replaced shortly if the display
    // was created with createDisplay().
@@ -170,6 +136,33 @@ void DisplayDevice::init(EGLConfig config)
    setProjection(DisplayState::eOrientationDefault, mViewport, mFrame);
}

DisplayDevice::~DisplayDevice() {
    if (mSurface != EGL_NO_SURFACE) {
        eglDestroySurface(mDisplay, mSurface);
        mSurface = EGL_NO_SURFACE;
    }
}

bool DisplayDevice::isValid() const {
    return mFlinger != NULL;
}

int DisplayDevice::getWidth() const {
    return mDisplayWidth;
}

int DisplayDevice::getHeight() const {
    return mDisplayHeight;
}

PixelFormat DisplayDevice::getFormat() const {
    return mFormat;
}

EGLSurface DisplayDevice::getEGLSurface() const {
    return mSurface;
}

void DisplayDevice::setDisplayName(const String8& displayName) {
    if (!displayName.isEmpty()) {
        // never override the name with an empty name
+1 −2
Original line number Diff line number Diff line
@@ -72,6 +72,7 @@ public:
    DisplayDevice(
            const sp<SurfaceFlinger>& flinger,
            DisplayType type,
            int32_t hwcId,  // negative for non-HWC-composited displays
            bool isSecure,
            const wp<IBinder>& displayToken,
            const sp<DisplaySurface>& displaySurface,
@@ -152,8 +153,6 @@ public:
    void dump(String8& result, char* buffer, size_t SIZE) const;

private:
    void init(EGLConfig config);

    /*
     *  Constants, set during initialization
     */
+22 −10
Original line number Diff line number Diff line
@@ -21,24 +21,30 @@
namespace android {
// ---------------------------------------------------------------------------

VirtualDisplaySurface::VirtualDisplaySurface(HWComposer& hwc, int disp,
VirtualDisplaySurface::VirtualDisplaySurface(HWComposer& hwc, int32_t dispId,
        const sp<IGraphicBufferProducer>& sink, const String8& name)
:   mHwc(hwc),
    mDisplayId(disp),
    mSource(new BufferQueueInterposer(sink, name)),
    mDisplayId(dispId),
    mName(name)
{}
{
    if (mDisplayId >= 0) {
        mInterposer = new BufferQueueInterposer(sink, name);
        mSourceProducer = mInterposer;
    } else {
        mSourceProducer = sink;
    }
}

VirtualDisplaySurface::~VirtualDisplaySurface() {
    if (mAcquiredBuffer != NULL) {
        status_t result = mSource->releaseBuffer(Fence::NO_FENCE);
        status_t result = mInterposer->releaseBuffer(Fence::NO_FENCE);
        ALOGE_IF(result != NO_ERROR, "VirtualDisplaySurface \"%s\": "
                "failed to release buffer: %d", mName.string(), result);
    }
}

sp<IGraphicBufferProducer> VirtualDisplaySurface::getIGraphicBufferProducer() const {
    return mSource;
    return mSourceProducer;
}

status_t VirtualDisplaySurface::compositionComplete() {
@@ -46,6 +52,9 @@ status_t VirtualDisplaySurface::compositionComplete() {
}

status_t VirtualDisplaySurface::advanceFrame() {
    if (mInterposer == NULL)
        return NO_ERROR;

    Mutex::Autolock lock(mMutex);
    status_t result = NO_ERROR;

@@ -57,12 +66,12 @@ status_t VirtualDisplaySurface::advanceFrame() {
    }

    sp<Fence> fence;
    result = mSource->acquireBuffer(&mAcquiredBuffer, &fence);
    result = mInterposer->acquireBuffer(&mAcquiredBuffer, &fence);
    if (result == BufferQueueInterposer::NO_BUFFER_AVAILABLE) {
        result = mSource->pullEmptyBuffer();
        result = mInterposer->pullEmptyBuffer();
        if (result != NO_ERROR)
            return result;
        result = mSource->acquireBuffer(&mAcquiredBuffer, &fence);
        result = mInterposer->acquireBuffer(&mAcquiredBuffer, &fence);
    }
    if (result != NO_ERROR)
        return result;
@@ -71,6 +80,9 @@ status_t VirtualDisplaySurface::advanceFrame() {
}

void VirtualDisplaySurface::onFrameCommitted() {
    if (mInterposer == NULL)
        return;

    Mutex::Autolock lock(mMutex);
    if (mAcquiredBuffer != NULL) {
        // fbFence signals when reads from the framebuffer are finished
@@ -85,7 +97,7 @@ void VirtualDisplaySurface::onFrameCommitted() {
                String8::format("HWC done: %.21s", mName.string()),
                fbFence, outFence);

        status_t result = mSource->releaseBuffer(fence);
        status_t result = mInterposer->releaseBuffer(fence);
        ALOGE_IF(result != NO_ERROR, "VirtualDisplaySurface \"%s\": "
                "failed to release buffer: %d", mName.string(), result);
        mAcquiredBuffer.clear();
+13 −3
Original line number Diff line number Diff line
@@ -45,12 +45,18 @@ class HWComposer;
 * eglSwapBuffers doesn't immediately dequeue a buffer for the next frame,
 * since we can't rely on being able to dequeue more than one buffer at a time.
 *
 * This class also has a passthrough mode, where it doesn't use a
 * BufferQueueInterposer and never sends buffers to HWC. Instead, OpenGL ES
 * output buffers are queued directly to the virtual display sink; this class
 * is inactive after construction. This mode is used when the HWC doesn't
 * support compositing for virtual displays.
 *
 * TODO(jessehall): Add a libgui test that ensures that EGL/GLES do lazy
 * dequeBuffers; we've wanted to require that for other reasons anyway.
 */
class VirtualDisplaySurface : public DisplaySurface {
public:
    VirtualDisplaySurface(HWComposer& hwc, int disp,
    VirtualDisplaySurface(HWComposer& hwc, int32_t dispId,
            const sp<IGraphicBufferProducer>& sink,
            const String8& name);

@@ -66,10 +72,14 @@ private:

    // immutable after construction
    HWComposer& mHwc;
    int mDisplayId;
    sp<BufferQueueInterposer> mSource;
    int32_t mDisplayId;
    String8 mName;

    // with HWC support, both of these point to the same object.
    // otherwise, mInterposer is NULL and mSourceProducer is the sink.
    sp<BufferQueueInterposer> mInterposer;
    sp<IGraphicBufferProducer> mSourceProducer;

    // mutable, must be synchronized with mMutex
    Mutex mMutex;
    sp<GraphicBuffer> mAcquiredBuffer;
+6 −4
Original line number Diff line number Diff line
@@ -510,7 +510,8 @@ status_t SurfaceFlinger::readyToRun()
            wp<IBinder> token = mBuiltinDisplays[i];

            sp<DisplayDevice> hw = new DisplayDevice(this,
                    type, isSecure, token, new FramebufferSurface(*mHwc, i),
                    type, allocateHwcDisplayId(type), isSecure, token,
                    new FramebufferSurface(*mHwc, i),
                    mEGLConfig);
            if (i > DisplayDevice::DISPLAY_PRIMARY) {
                // FIXME: currently we don't get blank/unblank requests
@@ -1149,10 +1150,11 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags)
                    const DisplayDeviceState& state(curr[i]);

                    sp<DisplaySurface> dispSurface;
                    int32_t hwcDisplayId = allocateHwcDisplayId(state.type);
                    if (state.isVirtualDisplay()) {
                        if (state.surface != NULL) {
                            dispSurface = new VirtualDisplaySurface(
                                    *mHwc, state.type, state.surface,
                                    *mHwc, hwcDisplayId, state.surface,
                                    state.displayName);
                        }
                    } else {
@@ -1169,8 +1171,8 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags)
                    const wp<IBinder>& display(curr.keyAt(i));
                    if (dispSurface != NULL) {
                        sp<DisplayDevice> hw = new DisplayDevice(this,
                                state.type, state.isSecure, display,
                                dispSurface, mEGLConfig);
                                state.type, hwcDisplayId, state.isSecure,
                                display, dispSurface, mEGLConfig);
                        hw->setLayerStack(state.layerStack);
                        hw->setProjection(state.orientation,
                                state.viewport, state.frame);