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

Commit 27cd07ca authored by Mathias Agopian's avatar Mathias Agopian
Browse files

changes to SurfaceTexture needed for unification with SF

- implement connect/disconnect
- implement missing query
- handle texture_2d in addition to texture_external_oes

Change-Id: I971a70821f00f22b01f5337de4a7d451177fec4d
parent 7797e647
Loading
Loading
Loading
Loading
+23 −2
Original line number Diff line number Diff line
@@ -127,11 +127,28 @@ public:
    // be called from the client.
    status_t setDefaultBufferSize(uint32_t w, uint32_t h);

private:
    // getCurrentBuffer returns the buffer associated with the current image.
    sp<GraphicBuffer> getCurrentBuffer() const;

    // getCurrentTextureTarget returns the texture target of the current
    // texture as returned by updateTexImage().
    GLenum getCurrentTextureTarget() const;

    // getCurrentCrop returns the cropping rectangle of the current buffer
    Rect getCurrentCrop() const;

    // getCurrentTransform returns the transform of the current buffer
    uint32_t getCurrentTransform() const;

protected:

    // freeAllBuffers frees the resources (both GraphicBuffer and EGLImage) for
    // all slots.
    void freeAllBuffers();
    static bool isExternalFormat(uint32_t format);
    static GLenum getTextureTarget(uint32_t format);

private:

    // createImage creates a new EGLImage from a GraphicBuffer.
    EGLImageKHR createImage(EGLDisplay dpy,
@@ -194,6 +211,10 @@ private:
    // reset mCurrentTexture to INVALID_BUFFER_SLOT.
    int mCurrentTexture;

    // mCurrentTextureTarget is the GLES texture target to be used with the
    // current texture.
    GLenum mCurrentTextureTarget;

    // mCurrentTextureBuf is the graphic buffer of the current texture. It's
    // possible that this buffer is not associated with any buffer slot, so we
    // must track it separately in order to properly use
@@ -262,7 +283,7 @@ private:
    // mMutex is the mutex used to prevent concurrent access to the member
    // variables of SurfaceTexture objects. It must be locked whenever the
    // member variables are accessed.
    Mutex mMutex;
    mutable Mutex mMutex;
};

// ----------------------------------------------------------------------------
+21 −1
Original line number Diff line number Diff line
@@ -27,6 +27,8 @@

namespace android {

class Surface;

class SurfaceTextureClient
    : public EGLNativeBase<ANativeWindow, SurfaceTextureClient, RefBase>
{
@@ -36,6 +38,7 @@ public:
    sp<ISurfaceTexture> getISurfaceTexture() const;

private:
    friend class Surface;

    // can't be copied
    SurfaceTextureClient& operator = (const SurfaceTextureClient& rhs);
@@ -78,6 +81,8 @@ private:

    void freeAllBuffers();

    int getConnectedApi() const;

    enum { MIN_UNDEQUEUED_BUFFERS = SurfaceTexture::MIN_UNDEQUEUED_BUFFERS };
    enum { MIN_BUFFER_SLOTS = SurfaceTexture::MIN_BUFFER_SLOTS };
    enum { NUM_BUFFER_SLOTS = SurfaceTexture::NUM_BUFFER_SLOTS };
@@ -121,10 +126,25 @@ private:
    // a timestamp is auto-generated when queueBuffer is called.
    int64_t mTimestamp;

    // mConnectedApi holds the currently connected API to this surface
    int mConnectedApi;

    // mQueryWidth is the width returned by query(). It is set to width
    // of the last dequeued buffer or to mReqWidth if no buffer was dequeued.
    uint32_t mQueryWidth;

    // mQueryHeight is the height returned by query(). It is set to height
    // of the last dequeued buffer or to mReqHeight if no buffer was dequeued.
    uint32_t mQueryHeight;

    // mQueryFormat is the format returned by query(). It is set to the last
    // dequeued format or to mReqFormat if no buffer was dequeued.
    uint32_t mQueryFormat;

    // mMutex is the mutex used to prevent concurrent access to the member
    // variables of SurfaceTexture objects. It must be locked whenever the
    // member variables are accessed.
    Mutex mMutex;
    mutable Mutex mMutex;
};

}; // namespace android
+68 −4
Original line number Diff line number Diff line
@@ -27,6 +27,8 @@

#include <gui/SurfaceTexture.h>

#include <hardware/hardware.h>

#include <surfaceflinger/ISurfaceComposer.h>
#include <surfaceflinger/SurfaceComposerClient.h>
#include <surfaceflinger/IGraphicBufferAlloc.h>
@@ -82,6 +84,7 @@ SurfaceTexture::SurfaceTexture(GLuint tex) :
    mUseDefaultSize(true),
    mBufferCount(MIN_BUFFER_SLOTS),
    mCurrentTexture(INVALID_BUFFER_SLOT),
    mCurrentTextureTarget(GL_TEXTURE_EXTERNAL_OES),
    mCurrentTransform(0),
    mCurrentTimestamp(0),
    mLastQueued(INVALID_BUFFER_SLOT),
@@ -198,6 +201,7 @@ status_t SurfaceTexture::dequeueBuffer(int *buf) {
    if (buffer == NULL) {
        return ISurfaceTexture::BUFFER_NEEDS_REALLOCATION;
    }

    if ((mUseDefaultSize) &&
        ((uint32_t(buffer->width) != mDefaultWidth) ||
         (uint32_t(buffer->height) != mDefaultHeight))) {
@@ -264,9 +268,6 @@ status_t SurfaceTexture::updateTexImage() {
    LOGV("SurfaceTexture::updateTexImage");
    Mutex::Autolock lock(mMutex);

    // We always bind the texture even if we don't update its contents.
    glBindTexture(GL_TEXTURE_EXTERNAL_OES, mTexName);

    // Initially both mCurrentTexture and mLastQueued are INVALID_BUFFER_SLOT,
    // so this check will fail until a buffer gets queued.
    if (mCurrentTexture != mLastQueued) {
@@ -284,7 +285,15 @@ status_t SurfaceTexture::updateTexImage() {
        while ((error = glGetError()) != GL_NO_ERROR) {
            LOGE("GL error cleared before updating SurfaceTexture: %#04x", error);
        }
        glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, (GLeglImageOES)image);

        GLenum target = getTextureTarget(
                mSlots[mLastQueued].mGraphicBuffer->format);
        if (target != mCurrentTextureTarget) {
            glDeleteTextures(1, &mTexName);
        }
        glBindTexture(target, mTexName);
        glEGLImageTargetTexture2DOES(target, (GLeglImageOES)image);

        bool failed = false;
        while ((error = glGetError()) != GL_NO_ERROR) {
            LOGE("error binding external texture image %p (slot %d): %#04x",
@@ -297,14 +306,53 @@ status_t SurfaceTexture::updateTexImage() {

        // Update the SurfaceTexture state.
        mCurrentTexture = mLastQueued;
        mCurrentTextureTarget = target;
        mCurrentTextureBuf = mSlots[mCurrentTexture].mGraphicBuffer;
        mCurrentCrop = mLastQueuedCrop;
        mCurrentTransform = mLastQueuedTransform;
        mCurrentTimestamp = mLastQueuedTimestamp;
    } else {
        // We always bind the texture even if we don't update its contents.
        glBindTexture(mCurrentTextureTarget, mTexName);
    }
    return OK;
}

bool SurfaceTexture::isExternalFormat(uint32_t format)
{
    switch (format) {
    // supported YUV formats
    case HAL_PIXEL_FORMAT_YV12:
    // Legacy/deprecated YUV formats
    case HAL_PIXEL_FORMAT_YCbCr_422_SP:
    case HAL_PIXEL_FORMAT_YCrCb_420_SP:
    case HAL_PIXEL_FORMAT_YCbCr_422_I:
        return true;
    }

    // Any OEM format needs to be considered
    if (format>=0x100 && format<=0x1FF)
        return true;

    return false;
}

GLenum SurfaceTexture::getTextureTarget(uint32_t format)
{
    GLenum target = GL_TEXTURE_2D;
#if defined(GL_OES_EGL_image_external)
    if (isExternalFormat(format)) {
        target = GL_TEXTURE_EXTERNAL_OES;
    }
#endif
    return target;
}

GLenum SurfaceTexture::getCurrentTextureTarget() const {
    Mutex::Autolock lock(mMutex);
    return mCurrentTextureTarget;
}

void SurfaceTexture::getTransformMatrix(float mtx[16]) {
    LOGV("SurfaceTexture::getTransformMatrix");
    Mutex::Autolock lock(mMutex);
@@ -459,6 +507,22 @@ EGLImageKHR SurfaceTexture::createImage(EGLDisplay dpy,
    return image;
}

sp<GraphicBuffer> SurfaceTexture::getCurrentBuffer() const {
    Mutex::Autolock lock(mMutex);
    return mCurrentTextureBuf;
}

Rect SurfaceTexture::getCurrentCrop() const {
    Mutex::Autolock lock(mMutex);
    return mCurrentCrop;
}

uint32_t SurfaceTexture::getCurrentTransform() const {
    Mutex::Autolock lock(mMutex);
    return mCurrentTransform;
}


static void mtxMul(float out[16], const float a[16], const float b[16]) {
    out[0] = a[0]*b[0] + a[4]*b[1] + a[8]*b[2] + a[12]*b[3];
    out[1] = a[1]*b[0] + a[5]*b[1] + a[9]*b[2] + a[13]*b[3];
+52 −13
Original line number Diff line number Diff line
@@ -26,8 +26,10 @@ namespace android {
SurfaceTextureClient::SurfaceTextureClient(
        const sp<ISurfaceTexture>& surfaceTexture):
        mSurfaceTexture(surfaceTexture), mAllocator(0), mReqWidth(0),
        mReqHeight(0), mReqFormat(DEFAULT_FORMAT), mReqUsage(0),
        mTimestamp(NATIVE_WINDOW_TIMESTAMP_AUTO), mMutex() {
        mReqHeight(0), mReqFormat(0), mReqUsage(0),
        mTimestamp(NATIVE_WINDOW_TIMESTAMP_AUTO), mConnectedApi(0),
        mQueryWidth(0), mQueryHeight(0), mQueryFormat(0),
        mMutex() {
    // Initialize the ANativeWindow function pointers.
    ANativeWindow::setSwapInterval  = setSwapInterval;
    ANativeWindow::dequeueBuffer    = dequeueBuffer;
@@ -101,9 +103,10 @@ int SurfaceTextureClient::dequeueBuffer(android_native_buffer_t** buffer) {
    }
    sp<GraphicBuffer>& gbuf(mSlots[buf]);
    if (err == ISurfaceTexture::BUFFER_NEEDS_REALLOCATION ||
        gbuf == 0 || gbuf->getWidth() != mReqWidth ||
        gbuf->getHeight() != mReqHeight ||
        uint32_t(gbuf->getPixelFormat()) != mReqFormat ||
        gbuf == 0 ||
        (mReqWidth && gbuf->getWidth() != mReqWidth) ||
        (mReqHeight && gbuf->getHeight() != mReqHeight) ||
        (mReqFormat && uint32_t(gbuf->getPixelFormat()) != mReqFormat) ||
        (gbuf->getUsage() & mReqUsage) != mReqUsage) {
        gbuf = mSurfaceTexture->requestBuffer(buf, mReqWidth, mReqHeight,
                mReqFormat, mReqUsage);
@@ -111,6 +114,9 @@ int SurfaceTextureClient::dequeueBuffer(android_native_buffer_t** buffer) {
            LOGE("dequeueBuffer: ISurfaceTexture::requestBuffer failed");
            return NO_MEMORY;
        }
        mQueryWidth  = gbuf->width;
        mQueryHeight = gbuf->height;
        mQueryFormat = gbuf->format;
    }
    *buffer = gbuf.get();
    return OK;
@@ -159,13 +165,13 @@ int SurfaceTextureClient::query(int what, int* value) {
    Mutex::Autolock lock(mMutex);
    switch (what) {
    case NATIVE_WINDOW_WIDTH:
        *value = mQueryWidth ? mQueryWidth : mReqWidth;
        return NO_ERROR;
    case NATIVE_WINDOW_HEIGHT:
        // XXX: How should SurfaceTexture behave if setBuffersGeometry didn't
        // override the size?
        *value = 0;
        *value = mQueryHeight ? mQueryHeight : mReqHeight;
        return NO_ERROR;
    case NATIVE_WINDOW_FORMAT:
        *value = DEFAULT_FORMAT;
        *value = mQueryFormat ? mQueryFormat : mReqFormat;
        return NO_ERROR;
    case NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS:
        *value = MIN_UNDEQUEUED_BUFFERS;
@@ -260,16 +266,49 @@ int SurfaceTextureClient::dispatchSetBuffersTimestamp(va_list args) {

int SurfaceTextureClient::connect(int api) {
    LOGV("SurfaceTextureClient::connect");
    // XXX: Implement this!
    return INVALID_OPERATION;
    Mutex::Autolock lock(mMutex);
    int err = NO_ERROR;
    switch (api) {
        case NATIVE_WINDOW_API_EGL:
            if (mConnectedApi) {
                err = -EINVAL;
            } else {
                mConnectedApi = api;
            }
            break;
        default:
            err = -EINVAL;
            break;
    }
    return err;
}

int SurfaceTextureClient::disconnect(int api) {
    LOGV("SurfaceTextureClient::disconnect");
    // XXX: Implement this!
    return INVALID_OPERATION;
    Mutex::Autolock lock(mMutex);
    int err = NO_ERROR;
    switch (api) {
        case NATIVE_WINDOW_API_EGL:
            if (mConnectedApi == api) {
                mConnectedApi = 0;
            } else {
                err = -EINVAL;
            }
            break;
        default:
            err = -EINVAL;
            break;
    }
    return err;
}

int SurfaceTextureClient::getConnectedApi() const
{
    Mutex::Autolock lock(mMutex);
    return mConnectedApi;
}


int SurfaceTextureClient::setUsage(uint32_t reqUsage)
{
    LOGV("SurfaceTextureClient::setUsage");