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

Commit b267579b authored by Daniel Lam's avatar Daniel Lam
Browse files

SurfaceTexture: Fully refactored from BufferQueue

SurfaceTexture and BufferQueue are separate objects.

Change-Id: I230bc0ae6f78d0f9b2b5df902f40ab443ed5a055
parent fddc28d8
Loading
Loading
Loading
Loading
+22 −0
Original line number Diff line number Diff line
@@ -203,6 +203,16 @@ public:
    // when a new frame becomes available.
    void setFrameAvailableListener(const sp<FrameAvailableListener>& listener);

    // setDefaultBufferFormat allows the BufferQueue to create
    // GraphicBuffers of a defaultFormat if no format is specified
    // in dequeueBuffer
    status_t setDefaultBufferFormat(uint32_t defaultFormat);

    // setConsumerUsageBits will turn on additional usage bits for dequeueBuffer
    status_t setConsumerUsageBits(uint32_t usage);

    // setTransformHint bakes in rotation to buffers so overlays can be used
    status_t setTransformHint(uint32_t hint);

private:
    // freeBufferLocked frees the resources (both GraphicBuffer and EGLImage)
@@ -417,7 +427,19 @@ private:
    // with the surface Texture.
    uint64_t mFrameCounter;

    // mBufferHasBeenQueued is true once a buffer has been queued.  It is reset
    // by changing the buffer count.
    bool mBufferHasBeenQueued;

    // mDefaultBufferFormat can be set so it will override
    // the buffer format when it isn't specified in dequeueBuffer
    uint32_t mDefaultBufferFormat;

    // mConsumerUsageBits contains flags the consumer wants for GraphicBuffers
    uint32_t mConsumerUsageBits;

    // mTransformHint is used to optimize for screen rotations
    uint32_t mTransformHint;
};

// ----------------------------------------------------------------------------
+27 −6
Original line number Diff line number Diff line
@@ -39,8 +39,12 @@ namespace android {

class String8;

class SurfaceTexture : public BufferQueue {
class SurfaceTexture : public virtual RefBase {
public:
    // This typedef allows external code to continue referencing
    // SurfaceTexture::FrameAvailableListener during refactoring
    typedef  BufferQueue::FrameAvailableListener FrameAvailableListener;


    // SurfaceTexture constructs a new SurfaceTexture object. tex indicates the
    // name of the OpenGL ES texture to which images are to be streamed. This
@@ -49,14 +53,15 @@ public:
    // enabled. texTarget specifies the OpenGL ES texture target to which the
    // texture will be bound in updateTexImage. useFenceSync specifies whether
    // fences should be used to synchronize access to buffers if that behavior
    // is enabled at compile-time.
    // is enabled at compile-time. A custom bufferQueue can be specified
    // if behavior for queue/dequeue/connect etc needs to be customized.
    // Otherwise a default BufferQueue will be created and used.
    SurfaceTexture(GLuint tex, bool allowSynchronousMode = true,
            GLenum texTarget = GL_TEXTURE_EXTERNAL_OES, bool useFenceSync = true);
            GLenum texTarget = GL_TEXTURE_EXTERNAL_OES, bool useFenceSync = true,
            const sp<BufferQueue> &bufferQueue = 0);

    virtual ~SurfaceTexture();



    // updateTexImage sets the image contents of the target texture to that of
    // the most recently queued buffer.
    //
@@ -152,6 +157,18 @@ public:
    // log messages.
    void setName(const String8& name);

    // These functions call the corresponding BufferQueue implementation
    // so the refactoring can proceed smoothly
    status_t setDefaultBufferFormat(uint32_t defaultFormat);
    status_t setConsumerUsageBits(uint32_t usage);
    status_t setTransformHint(uint32_t hint);
    virtual status_t setSynchronousMode(bool enabled);
    virtual status_t setBufferCount(int bufferCount);
    virtual status_t connect(int api,
                uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransform);

    sp<BufferQueue> getBufferQueue() const;

    // dump our state in a String
    virtual void dump(String8& result) const;
    virtual void dump(String8& result, const char* prefix, char* buffer, size_t SIZE) const;
@@ -241,7 +258,7 @@ private:
        EGLSyncKHR mFence;
    };

    EGLSlot mEGLSlots[NUM_BUFFER_SLOTS];
    EGLSlot mEGLSlots[BufferQueue::NUM_BUFFER_SLOTS];

    // mAbandoned indicates that the BufferQueue will no longer be used to
    // consume images buffers pushed to it using the ISurfaceTexture interface.
@@ -267,6 +284,10 @@ private:
    // reset mCurrentTexture to INVALID_BUFFER_SLOT.
    int mCurrentTexture;

    // The SurfaceTexture has-a BufferQueue and is responsible for creating this object
    // if none is supplied
    sp<BufferQueue> mBufferQueue;

};

// ----------------------------------------------------------------------------
+10 −2
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@

#include <gui/ISurfaceTexture.h>
#include <gui/SurfaceTexture.h>
#include <gui/BufferQueue.h>

#include <ui/ANativeObjectBase.h>
#include <ui/Region.h>
@@ -34,8 +35,15 @@ class SurfaceTextureClient
    : public ANativeObjectBase<ANativeWindow, SurfaceTextureClient, RefBase>
{
public:

    SurfaceTextureClient(const sp<ISurfaceTexture>& surfaceTexture);

    // SurfaceTextureClient is overloaded to assist in refactoring ST and BQ.
    // SurfaceTexture is no longer an ISurfaceTexture, so client code
    // calling the original constructor will fail. Thus this convenience method
    // passes in the surfaceTexture's bufferQueue to the init method.
    SurfaceTextureClient(const sp<SurfaceTexture>& surfaceTexture);

    sp<ISurfaceTexture> getISurfaceTexture() const;

protected:
@@ -94,8 +102,8 @@ protected:
    virtual int lock(ANativeWindow_Buffer* outBuffer, ARect* inOutDirtyBounds);
    virtual int unlockAndPost();

    enum { MIN_UNDEQUEUED_BUFFERS = SurfaceTexture::MIN_UNDEQUEUED_BUFFERS };
    enum { NUM_BUFFER_SLOTS = SurfaceTexture::NUM_BUFFER_SLOTS };
    enum { MIN_UNDEQUEUED_BUFFERS = BufferQueue::MIN_UNDEQUEUED_BUFFERS };
    enum { NUM_BUFFER_SLOTS = BufferQueue::NUM_BUFFER_SLOTS };
    enum { DEFAULT_FORMAT = PIXEL_FORMAT_RGBA_8888 };

private:
+35 −5
Original line number Diff line number Diff line
@@ -83,7 +83,10 @@ BufferQueue::BufferQueue( bool allowSynchronousMode ) :
    mConnectedApi(NO_CONNECTED_API),
    mAbandoned(false),
    mFrameCounter(0),
    mBufferHasBeenQueued(false)
    mBufferHasBeenQueued(false),
    mDefaultBufferFormat(0),
    mConsumerUsageBits(0),
    mTransformHint(0)
{
    // Choose a name using the PID and a process-unique ID.
    mConsumerName = String8::format("unnamed-%d-%d", getpid(), createProcessUniqueId());
@@ -128,6 +131,7 @@ status_t BufferQueue::setBufferCountServerLocked(int bufferCount) {
        // dequeueBuffer.

        mServerBufferCount = bufferCount;
        mDequeueCondition.broadcast();
    }
    return OK;
}
@@ -149,6 +153,24 @@ void BufferQueue::setFrameAvailableListener(
    mFrameAvailableListener = listener;
}

status_t BufferQueue::setDefaultBufferFormat(uint32_t defaultFormat) {
    Mutex::Autolock lock(mMutex);
    mDefaultBufferFormat = defaultFormat;
    return OK;
}

status_t BufferQueue::setConsumerUsageBits(uint32_t usage) {
    Mutex::Autolock lock(mMutex);
    mConsumerUsageBits = usage;
    return OK;
}

status_t BufferQueue::setTransformHint(uint32_t hint) {
    Mutex::Autolock lock(mMutex);
    mTransformHint = hint;
    return OK;
}

status_t BufferQueue::setBufferCount(int bufferCount) {
    ST_LOGV("setBufferCount: count=%d", bufferCount);
    Mutex::Autolock lock(mMutex);
@@ -263,6 +285,12 @@ status_t BufferQueue::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h,
    { // Scope for the lock
        Mutex::Autolock lock(mMutex);

        if (format == 0) {
            format = mDefaultBufferFormat;
        }
        // turn on usage bits the consumer requested
        usage |= mConsumerUsageBits;

        int found = -1;
        int foundSync = -1;
        int dequeuedCount = 0;
@@ -563,7 +591,7 @@ status_t BufferQueue::queueBuffer(int buf, int64_t timestamp,

        *outWidth = mDefaultWidth;
        *outHeight = mDefaultHeight;
        *outTransform = 0;
        *outTransform = mTransformHint;

        ATRACE_INT(mConsumerName.string(), mQueue.size());
    } // scope for the lock
@@ -846,7 +874,8 @@ status_t BufferQueue::acquire(BufferItem *buffer) {
        ATRACE_INT(mConsumerName.string(), mQueue.size());
    }
    else {
        return -EINVAL; //should be a better return code
        // should be a better return code?
        return -EINVAL;
    }

    return OK;
@@ -880,9 +909,10 @@ status_t BufferQueue::releaseBuffer(int buf, EGLDisplay display,

status_t BufferQueue::consumerDisconnect() {
    Mutex::Autolock lock(mMutex);
    // Once the SurfaceTexture disconnects, the BufferQueue
    // is considered abandoned

    mAbandoned = true;

    mQueue.clear();
    freeAllBuffersLocked();
    mDequeueCondition.broadcast();
    return OK;
+68 −18
Original line number Diff line number Diff line
@@ -105,8 +105,7 @@ static int32_t createProcessUniqueId() {
}

SurfaceTexture::SurfaceTexture(GLuint tex, bool allowSynchronousMode,
        GLenum texTarget, bool useFenceSync) :
    BufferQueue(allowSynchronousMode),
        GLenum texTarget, bool useFenceSync, const sp<BufferQueue> &bufferQueue) :
    mCurrentTransform(0),
    mCurrentTimestamp(0),
    mTexName(tex),
@@ -121,27 +120,37 @@ SurfaceTexture::SurfaceTexture(GLuint tex, bool allowSynchronousMode,
{
    // Choose a name using the PID and a process-unique ID.
    mName = String8::format("unnamed-%d-%d", getpid(), createProcessUniqueId());
    BufferQueue::setConsumerName(mName);

    ST_LOGV("SurfaceTexture");
    if (bufferQueue == 0) {

        ST_LOGV("Creating a new BufferQueue");
        mBufferQueue = new BufferQueue(allowSynchronousMode);
    }
    else {
        mBufferQueue = bufferQueue;
    }
    mBufferQueue->setConsumerName(mName);

    memcpy(mCurrentTransformMatrix, mtxIdentity,
            sizeof(mCurrentTransformMatrix));
}

SurfaceTexture::~SurfaceTexture() {
    ST_LOGV("~SurfaceTexture");

    abandon();
}

status_t SurfaceTexture::setBufferCountServer(int bufferCount) {
    Mutex::Autolock lock(mMutex);
    return BufferQueue::setBufferCountServer(bufferCount);
    return mBufferQueue->setBufferCountServer(bufferCount);
}


status_t SurfaceTexture::setDefaultBufferSize(uint32_t w, uint32_t h)
{
    return BufferQueue::setDefaultBufferSize(w, h);
    Mutex::Autolock lock(mMutex);
    return mBufferQueue->setDefaultBufferSize(w, h);
}

status_t SurfaceTexture::updateTexImage() {
@@ -154,11 +163,11 @@ status_t SurfaceTexture::updateTexImage() {
        return NO_INIT;
    }

    BufferItem item;
    BufferQueue::BufferItem item;

    // In asynchronous mode the list is guaranteed to be one buffer
    // deep, while in synchronous mode we use the oldest buffer.
    if (acquire(&item) == NO_ERROR) {
    if (mBufferQueue->acquire(&item) == NO_ERROR) {
        int buf = item.mBuf;
        // This buffer was newly allocated, so we need to clean up on our side
        if (item.mGraphicBuffer != NULL) {
@@ -205,19 +214,19 @@ status_t SurfaceTexture::updateTexImage() {
            failed = true;
        }
        if (failed) {
            releaseBuffer(buf, mEGLSlots[buf].mEglDisplay,
            mBufferQueue->releaseBuffer(buf, mEGLSlots[buf].mEglDisplay,
                    mEGLSlots[buf].mFence);
            return -EINVAL;
        }

        if (mCurrentTexture != INVALID_BUFFER_SLOT) {
        if (mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) {
            if (mUseFenceSync) {
                EGLSyncKHR fence = eglCreateSyncKHR(dpy, EGL_SYNC_FENCE_KHR,
                        NULL);
                if (fence == EGL_NO_SYNC_KHR) {
                    ALOGE("updateTexImage: error creating fence: %#x",
                            eglGetError());
                    releaseBuffer(buf, mEGLSlots[buf].mEglDisplay,
                    mBufferQueue->releaseBuffer(buf, mEGLSlots[buf].mEglDisplay,
                            mEGLSlots[buf].mFence);
                    return -EINVAL;
                }
@@ -232,7 +241,7 @@ status_t SurfaceTexture::updateTexImage() {
                buf, item.mGraphicBuffer != NULL ? item.mGraphicBuffer->handle : 0);

        // release old buffer
        releaseBuffer(mCurrentTexture,
        mBufferQueue->releaseBuffer(mCurrentTexture,
                mEGLSlots[mCurrentTexture].mEglDisplay,
                mEGLSlots[mCurrentTexture].mFence);

@@ -385,7 +394,7 @@ void SurfaceTexture::setFrameAvailableListener(
        const sp<FrameAvailableListener>& listener) {
    ST_LOGV("setFrameAvailableListener");
    Mutex::Autolock lock(mMutex);
    BufferQueue::setFrameAvailableListener(listener);
    mBufferQueue->setFrameAvailableListener(listener);
}

EGLImageKHR SurfaceTexture::createImage(EGLDisplay dpy,
@@ -426,7 +435,7 @@ uint32_t SurfaceTexture::getCurrentScalingMode() const {

bool SurfaceTexture::isSynchronousMode() const {
    Mutex::Autolock lock(mMutex);
    return BufferQueue::isSynchronousMode();
    return mBufferQueue->isSynchronousMode();
}

void SurfaceTexture::abandon() {
@@ -435,7 +444,7 @@ void SurfaceTexture::abandon() {
    mCurrentTextureBuf.clear();

    // destroy all egl buffers
    for (int i =0; i < NUM_BUFFER_SLOTS; i++) {
    for (int i =0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
        mEGLSlots[i].mGraphicBuffer = 0;
        if (mEGLSlots[i].mEglImage != EGL_NO_IMAGE_KHR) {
            eglDestroyImageKHR(mEGLSlots[i].mEglDisplay,
@@ -446,13 +455,54 @@ void SurfaceTexture::abandon() {
    }

    // disconnect from the BufferQueue
    BufferQueue::consumerDisconnect();
    mBufferQueue->consumerDisconnect();
}

void SurfaceTexture::setName(const String8& name) {
    Mutex::Autolock _l(mMutex);
    mName = name;
    BufferQueue::setConsumerName(name);
    mBufferQueue->setConsumerName(name);
}

status_t SurfaceTexture::setDefaultBufferFormat(uint32_t defaultFormat) {
    Mutex::Autolock lock(mMutex);
    return mBufferQueue->setDefaultBufferFormat(defaultFormat);
}

status_t SurfaceTexture::setConsumerUsageBits(uint32_t usage) {
    Mutex::Autolock lock(mMutex);
    return mBufferQueue->setConsumerUsageBits(usage);
}

status_t SurfaceTexture::setTransformHint(uint32_t hint) {
    Mutex::Autolock lock(mMutex);
    return mBufferQueue->setTransformHint(hint);
}

// Used for refactoring BufferQueue from SurfaceTexture
// Should not be in final interface once users of SurfaceTexture are clean up.
status_t SurfaceTexture::setSynchronousMode(bool enabled) {
    Mutex::Autolock lock(mMutex);
    return mBufferQueue->setSynchronousMode(enabled);
}

// Used for refactoring, should not be in final interface
sp<BufferQueue> SurfaceTexture::getBufferQueue() const {
    Mutex::Autolock lock(mMutex);
    return mBufferQueue;
}

// Used for refactoring, should not be in final interface
status_t SurfaceTexture::setBufferCount(int bufferCount) {
    Mutex::Autolock lock(mMutex);
    return mBufferQueue->setBufferCount(bufferCount);
}

// Used for refactoring, should not be in final interface
status_t SurfaceTexture::connect(int api,
                uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransform) {
    Mutex::Autolock lock(mMutex);
    return mBufferQueue->connect(api, outWidth, outHeight, outTransform);
}

void SurfaceTexture::dump(String8& result) const
@@ -477,7 +527,7 @@ void SurfaceTexture::dump(String8& result, const char* prefix,
    result.append(buffer);


    BufferQueue::dump(result, prefix, buffer, SIZE);
    mBufferQueue->dump(result, prefix, buffer, SIZE);
}

static void mtxMul(float out[16], const float a[16], const float b[16]) {
Loading