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

Commit e60b0687 authored by Mathias Agopian's avatar Mathias Agopian
Browse files

HWComposer now has its own concept of display IDs

HWComposer can now create IDs representing a display
it can deal with. IDs MAIN and HDMI are reserved.
SurfaceFlinger associate HWComposer IDs with a
DisplayDevice and uses that when it talks to HWComposer.

A DisplayDevice doesn't have to have a HWComposer ID,
in that case it just can't use h/w composer composition.

Change-Id: Iec3d7ac92e0c22bf975052ae2847402f58bade71
parent 7c9e8263
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -68,12 +68,12 @@ void checkGLErrors()

DisplayDevice::DisplayDevice(
        const sp<SurfaceFlinger>& flinger,
        int display,
        int32_t display, int32_t hwcDisplayId,
        const sp<ANativeWindow>& nativeWindow,
        const sp<FramebufferSurface>& framebufferSurface,
        EGLConfig config)
    : mFlinger(flinger),
      mId(display),
      mId(display), mHwcDisplayId(hwcDisplayId),
      mNativeWindow(nativeWindow),
      mFramebufferSurface(framebufferSurface),
      mDisplay(EGL_NO_DISPLAY),
+3 −1
Original line number Diff line number Diff line
@@ -62,7 +62,7 @@ public:

    DisplayDevice(
            const sp<SurfaceFlinger>& flinger,
            int dpy,
            int32_t dpy, int32_t hwcDisplayId,
            const sp<ANativeWindow>& nativeWindow,
            const sp<FramebufferSurface>& framebufferSurface,
            EGLConfig config);
@@ -96,6 +96,7 @@ public:
    const Transform&        getTransform() const { return mGlobalTransform; }
    uint32_t                getLayerStack() const { return mLayerStack; }
    int32_t                 getDisplayId() const { return mId; }
    int32_t                 getHwcDisplayId() const { return mHwcDisplayId; }

    status_t compositionComplete() const;
    
@@ -132,6 +133,7 @@ private:
     */
    sp<SurfaceFlinger> mFlinger;
    int32_t mId;
    int32_t mHwcDisplayId;

    // ANativeWindow this display is rendering into
    sp<ANativeWindow> mNativeWindow;
+90 −66
Original line number Diff line number Diff line
@@ -194,13 +194,13 @@ HWComposer::HWComposer(
        framebuffer_device_t const* fbDev)
    : mFlinger(flinger),
      mModule(0), mHwc(0), mNumDisplays(1), mCapacity(0),
      mNumOVLayers(0), mNumFBLayers(0),
      mCBContext(new cb_context),
      mEventHandler(handler), mRefreshPeriod(0),
      mEventHandler(handler),
      mVSyncCount(0), mDebugForceFakeVSync(false)
{
    for (size_t i = 0; i < MAX_DISPLAYS; i++)
        mLists[i] = NULL;
    for (size_t i =0 ; i<MAX_DISPLAYS ; i++) {
        mLists[i] = 0;
    }

    char value[PROPERTY_VALUE_MAX];
    property_get("debug.sf.no_hw_vsync", value, "0");
@@ -232,6 +232,10 @@ HWComposer::HWComposer(
                mHwc->registerProcs(mHwc, &mCBContext->procs);
            }

            // these IDs are always reserved
            mTokens.markBit(HWC_DISPLAY_PRIMARY);
            mTokens.markBit(HWC_DISPLAY_EXTERNAL);

            // always turn vsync off when we start
            needVSyncThread = false;
            if (hwcHasVsyncEvent(mHwc)) {
@@ -239,7 +243,7 @@ HWComposer::HWComposer(

                int period;
                if (mHwc->query(mHwc, HWC_VSYNC_PERIOD, &period) == NO_ERROR) {
                    mRefreshPeriod = nsecs_t(period);
                    mDisplayData[0].refresh = nsecs_t(period);
                }
            } else {
                needVSyncThread = true;
@@ -255,17 +259,17 @@ HWComposer::HWComposer(


    if (fbDev) {
        if (mRefreshPeriod == 0) {
            mRefreshPeriod = nsecs_t(1e9 / fbDev->fps);
            ALOGW("getting VSYNC period from fb HAL: %lld", mRefreshPeriod);
        if (mDisplayData[HWC_DISPLAY_PRIMARY].refresh == 0) {
            mDisplayData[HWC_DISPLAY_PRIMARY].refresh = nsecs_t(1e9 / fbDev->fps);
            ALOGW("getting VSYNC period from fb HAL: %lld", mDisplayData[0].refresh);
        }
        mDpiX = fbDev->xdpi;
        mDpiY = fbDev->ydpi;
        mDisplayData[HWC_DISPLAY_PRIMARY].xdpi = fbDev->xdpi;
        mDisplayData[HWC_DISPLAY_PRIMARY].ydpi = fbDev->ydpi;
    }

    if (mRefreshPeriod == 0) {
        mRefreshPeriod = nsecs_t(1e9 / 60.0);
        ALOGW("getting VSYNC period thin air: %lld", mRefreshPeriod);
    if (mDisplayData[HWC_DISPLAY_PRIMARY].refresh == 0) {
        mDisplayData[HWC_DISPLAY_PRIMARY].refresh = nsecs_t(1e9 / 60.0);
        ALOGW("getting VSYNC period thin air: %lld", mDisplayData[0].refresh);
    }

    if (needVSyncThread) {
@@ -276,8 +280,9 @@ HWComposer::HWComposer(

HWComposer::~HWComposer() {
    hwcEventControl(mHwc, 0, EVENT_VSYNC, 0);
    for (size_t i = 0; i < MAX_DISPLAYS; i++)
    for (size_t i = 0; i < MAX_DISPLAYS; i++) {
        free(mLists[i]);
    }
    if (mVSyncThread != NULL) {
        mVSyncThread->requestExitAndWait();
    }
@@ -315,8 +320,32 @@ void HWComposer::vsync(int dpy, int64_t timestamp) {
    mLastHwVSync = timestamp;
}

int32_t HWComposer::allocateDisplayId() {
    if (mTokens.isFull()) {
        return NO_MEMORY;
    }

    // FIXME: for now we don't support h/w composition wifi displays
    return -1;

    int32_t id = mTokens.firstUnmarkedBit();
    mTokens.markBit(id);
    return id;
}

status_t HWComposer::freeDisplayId(int32_t id) {
    if (id < MAX_DISPLAYS) {
        return BAD_VALUE;
    }
    if (!mTokens.hasBit(id)) {
        return BAD_INDEX;
    }
    mTokens.clearBit(id);
    return NO_ERROR;
}

nsecs_t HWComposer::getRefreshPeriod() const {
    return mRefreshPeriod;
    return mDisplayData[0].refresh;
}

nsecs_t HWComposer::getRefreshTimestamp() const {
@@ -325,15 +354,15 @@ nsecs_t HWComposer::getRefreshTimestamp() const {
    // the refresh period and whatever closest timestamp we have.
    Mutex::Autolock _l(mLock);
    nsecs_t now = systemTime(CLOCK_MONOTONIC);
    return now - ((now - mLastHwVSync) %  mRefreshPeriod);
    return now - ((now - mLastHwVSync) %  mDisplayData[0].refresh);
}

float HWComposer::getDpiX() const {
    return mDpiX;
    return mDisplayData[HWC_DISPLAY_PRIMARY].xdpi;
}

float HWComposer::getDpiY() const {
    return mDpiY;
    return mDisplayData[HWC_DISPLAY_PRIMARY].ydpi;
}

void HWComposer::eventControl(int event, int enabled) {
@@ -354,10 +383,11 @@ void HWComposer::eventControl(int event, int enabled) {
}

status_t HWComposer::createWorkList(int32_t id, size_t numLayers) {
    // FIXME: handle multiple displays
    if (uint32_t(id) >= MAX_DISPLAYS)
    if (!mTokens.hasBit(id)) {
        return BAD_INDEX;
    }

    // FIXME: handle multiple displays
    if (mHwc) {
        // TODO: must handle multiple displays here
        // mLists[0] is NULL only when this is called from the constructor
@@ -376,9 +406,10 @@ status_t HWComposer::createWorkList(int32_t id, size_t numLayers) {
    return NO_ERROR;
}

status_t HWComposer::prepare() const {
status_t HWComposer::prepare() {
    int err = hwcPrepare(mHwc, mNumDisplays,
            const_cast<hwc_display_contents_1_t**>(mLists));

    if (err == NO_ERROR) {

        // here we're just making sure that "skip" layers are set
@@ -388,65 +419,58 @@ status_t HWComposer::prepare() const {
        // think is almost possible.

        // TODO: must handle multiple displays here

        size_t numOVLayers = 0;
        size_t numFBLayers = 0;
        if (hwcHasVersion(mHwc, HWC_DEVICE_API_VERSION_1_0)) {
            size_t count = getNumLayers(0);

            struct hwc_display_contents_1* disp = mLists[0];
            mDisplayData[0].hasFbComp = false;
            mDisplayData[0].hasOvComp = false;
            for (size_t i=0 ; i<count ; i++) {
            int compositionType;
            if (hwcHasVersion(mHwc, HWC_DEVICE_API_VERSION_1_0)) {
                hwc_layer_1_t* l = &mLists[0]->hwLayers[i];
                hwc_layer_1_t* l = &disp->hwLayers[i];
                if (l->flags & HWC_SKIP_LAYER) {
                    l->compositionType = HWC_FRAMEBUFFER;
                }
                compositionType = l->compositionType;
                if (l->compositionType == HWC_FRAMEBUFFER)
                    mDisplayData[HWC_DISPLAY_PRIMARY].hasFbComp = true;
                if (l->compositionType == HWC_OVERLAY)
                    mDisplayData[HWC_DISPLAY_PRIMARY].hasOvComp = true;
            }
        } else {
                // mList really has hwc_layer_list_t memory layout
                hwc_layer_list_t* list0 = reinterpret_cast<hwc_layer_list_t*>(mLists[0]);
                hwc_layer_t* l = &list0->hwLayers[i];
            size_t count = getNumLayers(0);
            hwc_layer_list_t* disp = reinterpret_cast<hwc_layer_list_t*>(mLists[0]);
            mDisplayData[0].hasFbComp = false;
            mDisplayData[0].hasOvComp = false;
            for (size_t i=0 ; i<count ; i++) {
                hwc_layer_t* l = &disp->hwLayers[i];
                if (l->flags & HWC_SKIP_LAYER) {
                    l->compositionType = HWC_FRAMEBUFFER;
                }
                compositionType = l->compositionType;
            }

            switch (compositionType) {
                case HWC_OVERLAY:
                    numOVLayers++;
                    break;
                case HWC_FRAMEBUFFER:
                    numFBLayers++;
                    break;
                if (l->compositionType == HWC_FRAMEBUFFER)
                    mDisplayData[HWC_DISPLAY_PRIMARY].hasFbComp = true;
                if (l->compositionType == HWC_OVERLAY)
                    mDisplayData[HWC_DISPLAY_PRIMARY].hasOvComp = true;
            }
        }
        mNumOVLayers = numOVLayers;
        mNumFBLayers = numFBLayers;
    }
    return (status_t)err;
}

size_t HWComposer::getLayerCount(int32_t id, int type) const {
    // FIXME: handle multiple displays
    if (uint32_t(id) >= MAX_DISPLAYS) {
        // FIXME: in practice this is only use to know
        // if we have at least one layer of type.
        return (type == HWC_FRAMEBUFFER) ? 1 : 0;
bool HWComposer::hasHwcComposition(int32_t id) const {
    if (!mTokens.hasBit(id))
        return false;
    return mDisplayData[id].hasOvComp;
}


    switch (type) {
        case HWC_OVERLAY:
            return mNumOVLayers;
        case HWC_FRAMEBUFFER:
            return mNumFBLayers;
    }
    return 0;
bool HWComposer::hasGlesComposition(int32_t id) const {
    if (!mTokens.hasBit(id))
        return false;
    return mDisplayData[id].hasFbComp;
}

status_t HWComposer::commit(void* fbDisplay, void* fbSurface) const {
status_t HWComposer::commit() const {
    int err = NO_ERROR;
    if (mHwc) {
        void* fbDisplay = eglGetCurrentDisplay();
        void* fbSurface = eglGetCurrentSurface(EGL_DRAW);
        err = hwcSet(mHwc, fbDisplay, fbSurface, mNumDisplays,
                const_cast<hwc_display_contents_1_t**>(mLists));
        if (hwcHasVersion(mHwc, HWC_DEVICE_API_VERSION_1_0)) {
@@ -661,10 +685,10 @@ public:
 * returns an iterator initialized at a given index in the layer list
 */
HWComposer::LayerListIterator HWComposer::getLayerIterator(int32_t id, size_t index) {
    // FIXME: handle multiple displays
    if (uint32_t(id) >= MAX_DISPLAYS)
    if (!mTokens.hasBit(id))
        return LayerListIterator();

    // FIXME: handle multiple displays
    if (!mHwc || index > hwcNumHwLayers(mHwc, mLists[0]))
        return LayerListIterator();
    if (hwcHasVersion(mHwc, HWC_DEVICE_API_VERSION_1_0)) {
@@ -741,7 +765,7 @@ void HWComposer::dump(String8& result, char* buffer, size_t SIZE,
HWComposer::VSyncThread::VSyncThread(HWComposer& hwc)
    : mHwc(hwc), mEnabled(false),
      mNextFakeVSync(0),
      mRefreshPeriod(hwc.mRefreshPeriod)
      mRefreshPeriod(hwc.getRefreshPeriod())
{
}

+33 −12
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@
#include <utils/Thread.h>
#include <utils/Timers.h>
#include <utils/Vector.h>
#include <utils/BitSet.h>

extern "C" int clock_nanosleep(clockid_t clock_id, int flags,
                           const struct timespec *request,
@@ -70,14 +71,26 @@ public:

    status_t initCheck() const;

    // returns a display ID starting at MAX_DISPLAYS, this ID
    // is to be used with createWorkList (and all other
    // methods requiring an ID below).
    // IDs below MAX_DISPLAY are pre-defined and therefore are always valid.
    // returns a negative error code if an ID cannot be allocated
    int32_t allocateDisplayId();

    // recycles the given ID and frees the associated worklist.
    // IDs below MAX_DISPLAYS are not recycled
    status_t freeDisplayId(int32_t id);


    // Asks the HAL what it can do
    status_t prepare() const;
    status_t prepare();

    // disable hwc until next createWorkList
    status_t disable();

    // commits the list
    status_t commit(void* fbDisplay, void* fbSurface) const;
    status_t commit() const;

    // release hardware resources and blank screen
    status_t release() const;
@@ -88,9 +101,11 @@ public:
    // create a work list for numLayers layer. sets HWC_GEOMETRY_CHANGED.
    status_t createWorkList(int32_t id, size_t numLayers);

    // get number of layers of the given type as updated in prepare().
    // type is HWC_OVERLAY or HWC_FRAMEBUFFER
    size_t getLayerCount(int32_t id, int type) const;
    // does this display have layers handled by HWC
    bool hasHwcComposition(int32_t id) const;

    // does this display have layers handled by GLES
    bool hasGlesComposition(int32_t id) const;

    // needed forward declarations
    class LayerListIterator;
@@ -237,26 +252,32 @@ private:
    inline void vsync(int dpy, int64_t timestamp);


    struct DisplayData {
        DisplayData() : xdpi(0), ydpi(0), refresh(0),
            hasFbComp(false), hasOvComp(false) { }
        float xdpi;
        float ydpi;
        nsecs_t refresh;
        bool hasFbComp;
        bool hasOvComp;
    };

    sp<SurfaceFlinger>              mFlinger;
    hw_module_t const*              mModule;
    struct hwc_composer_device_1*   mHwc;
    // invariant: mLists[0] != NULL iff mHwc != NULL
    // TODO: decide whether mLists[i>0] should be non-NULL when display i is
    //       not attached/enabled.
    // mLists[i>0] can be NULL. that display is to be ignored
    struct hwc_display_contents_1*  mLists[MAX_DISPLAYS];
    DisplayData                     mDisplayData[MAX_DISPLAYS];
    size_t                          mNumDisplays;

    size_t                          mCapacity;
    mutable size_t                  mNumOVLayers;
    mutable size_t                  mNumFBLayers;
    cb_context*                     mCBContext;
    EventHandler&                   mEventHandler;
    nsecs_t                         mRefreshPeriod;
    float                           mDpiX;
    float                           mDpiY;
    size_t                          mVSyncCount;
    sp<VSyncThread>                 mVSyncThread;
    bool                            mDebugForceFakeVSync;
    BitSet32                        mTokens;

    // protected by mLock
    mutable Mutex mLock;
+41 −32
Original line number Diff line number Diff line
@@ -409,7 +409,8 @@ status_t SurfaceFlinger::readyToRun()
        mCurrentState.displays.add(mDefaultDisplays[i], DisplayDeviceState(i));
    }
    sp<DisplayDevice> hw = new DisplayDevice(this,
            DisplayDevice::DISPLAY_ID_MAIN, anw, fbs, mEGLConfig);
            DisplayDevice::DISPLAY_ID_MAIN, HWC_DISPLAY_PRIMARY,
            anw, fbs, mEGLConfig);
    mDisplays.add(hw->getDisplayId(), hw);

    //  initialize OpenGL ES
@@ -779,11 +780,11 @@ void SurfaceFlinger::setUpHWComposer() {
        mHwWorkListDirty = false;
        for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
            sp<const DisplayDevice> hw(mDisplays[dpy]);
            const int32_t id = hw->getHwcDisplayId();
            if (id >= 0) {
                const Vector< sp<LayerBase> >& currentLayers(
                    hw->getVisibleLayersSortedByZ());
                const size_t count = currentLayers.size();

            const int32_t id = hw->getDisplayId();
                if (hwc.createWorkList(id, count) >= 0) {
                    HWComposer::LayerListIterator cur = hwc.begin(id);
                    const HWComposer::LayerListIterator end = hwc.end(id);
@@ -805,6 +806,7 @@ void SurfaceFlinger::setUpHWComposer() {
                    }
                }
            }
        }
        status_t err = hwc.prepare();
        ALOGE_IF(err, "HWComposer::prepare failed (%s)", strerror(-err));
    }
@@ -841,21 +843,20 @@ void SurfaceFlinger::postFramebuffer()

    HWComposer& hwc(getHwComposer());
    if (hwc.initCheck() == NO_ERROR) {
        // FIXME: eventually commit() won't take arguments
        // FIXME: EGL spec says:
        //   "surface must be bound to the calling thread's current context,
        //    for the current rendering API."
        DisplayDevice::makeCurrent(
                getDisplayDevice(DisplayDevice::DISPLAY_ID_MAIN), mEGLContext);
        hwc.commit(mEGLDisplay, getDefaultDisplayDevice()->getEGLSurface());
        hwc.commit();
    }

    for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
        sp<const DisplayDevice> hw(mDisplays[dpy]);
        const Vector< sp<LayerBase> >& currentLayers(hw->getVisibleLayersSortedByZ());
        const size_t count = currentLayers.size();
        if (hwc.initCheck() == NO_ERROR) {
            int32_t id = hw->getDisplayId();
        int32_t id = hw->getHwcDisplayId();
        if (id >=0 && hwc.initCheck() == NO_ERROR) {
            HWComposer::LayerListIterator cur = hwc.begin(id);
            const HWComposer::LayerListIterator end = hwc.end(id);
            for (size_t i = 0; cur != end && i < count; ++i, ++cur) {
@@ -951,12 +952,15 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags)
                    if (state.surface->asBinder() != draw[i].surface->asBinder()) {
                        // changing the surface is like destroying and
                        // recreating the DisplayDevice
                        const int32_t hwcDisplayId =
                            (uint32_t(state.id) < DisplayDevice::DISPLAY_ID_COUNT) ?
                                state.id : getHwComposer().allocateDisplayId();

                        sp<SurfaceTextureClient> stc(
                                new SurfaceTextureClient(state.surface));

                        sp<DisplayDevice> disp = new DisplayDevice(this,
                                state.id, stc, 0, mEGLConfig);
                            state.id, hwcDisplayId, stc, 0, mEGLConfig);

                        disp->setLayerStack(state.layerStack);
                        disp->setOrientation(state.orientation);
@@ -982,10 +986,14 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags)
            for (size_t i=0 ; i<cc ; i++) {
                if (draw.indexOfKey(curr.keyAt(i)) < 0) {
                    const DisplayDeviceState& state(curr[i]);
                    const int32_t hwcDisplayId =
                        (uint32_t(state.id) < DisplayDevice::DISPLAY_ID_COUNT) ?
                            state.id : getHwComposer().allocateDisplayId();

                    sp<SurfaceTextureClient> stc(
                            new SurfaceTextureClient(state.surface));
                    sp<DisplayDevice> disp = new DisplayDevice(this, state.id,
                            stc, 0, mEGLConfig);
                    sp<DisplayDevice> disp = new DisplayDevice(this,
                        state.id, hwcDisplayId, stc, 0, mEGLConfig);
                    mDisplays.add(state.id, disp);
                }
            }
@@ -1251,12 +1259,13 @@ void SurfaceFlinger::doDisplayComposition(const sp<const DisplayDevice>& hw,
void SurfaceFlinger::doComposeSurfaces(const sp<const DisplayDevice>& hw, const Region& dirty)
{
    HWComposer& hwc(getHwComposer());
    int32_t id = hw->getDisplayId();
    int32_t id = hw->getHwcDisplayId();
    HWComposer::LayerListIterator cur = hwc.begin(id);
    const HWComposer::LayerListIterator end = hwc.end(id);

    const size_t fbLayerCount = hwc.getLayerCount(id, HWC_FRAMEBUFFER);
    if (cur==end || fbLayerCount) {
    const bool hasGlesComposition = hwc.hasGlesComposition(id);
    const bool hasHwcComposition = hwc.hasHwcComposition(id);
    if (cur==end || hasGlesComposition) {

        DisplayDevice::makeCurrent(hw, mEGLContext);

@@ -1265,7 +1274,7 @@ void SurfaceFlinger::doComposeSurfaces(const sp<const DisplayDevice>& hw, const
        glLoadIdentity();

        // Never touch the framebuffer if we don't have any framebuffer layers
        if (hwc.getLayerCount(id, HWC_OVERLAY)) {
        if (hasHwcComposition) {
            // when using overlays, we assume a fully transparent framebuffer
            // NOTE: we could reduce how much we need to clear, for instance
            // remove where there are opaque FB layers. however, on some