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

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

SurfaceTexture can now force the client to request a buffer

SurfaceTexture now has the concept of default size a new method,
setDefaultBufferSize() to set it. When the default size is
changed, dequeueBuffer() will return a value telling the
client that it must ask for a new buffer.

The above only applies if the client has not
overriden the buffer size with setGeometry.

Change-Id: I520dc40363054b7e37fdb67d6a2e7bce70326e81
parent 3d9dda7d
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -36,6 +36,8 @@ class ISurfaceTexture : public IInterface
public:
    DECLARE_META_INTERFACE(SurfaceTexture);

    enum { BUFFER_NEEDS_REALLOCATION = 1 };

    // requestBuffer requests a new buffer for the given index. The server (i.e.
    // the ISurfaceTexture implementation) assigns the newly created buffer to
    // the given slot index, and the client is expected to mirror the
@@ -56,6 +58,8 @@ public:
    // should call requestBuffer to assign a new buffer to that slot. The client
    // is expected to either call cancelBuffer on the dequeued slot or to fill
    // in the contents of its associated buffer contents and call queueBuffer.
    // If dequeueBuffer return BUFFER_NEEDS_REALLOCATION, the client is
    // expected to call requestBuffer immediately.
    virtual status_t dequeueBuffer(int *slot) = 0;

    // queueBuffer indicates that the client has finished filling in the
+23 −0
Original line number Diff line number Diff line
@@ -121,6 +121,12 @@ public:
    // buffers before the client is done with them.
    sp<IBinder> getAllocator();

    // setDefaultBufferSize is used to set the size of buffers returned by
    // requestBuffers when a with and height of zero is requested.
    // A call to setDefaultBufferSize() may trigger requestBuffers() to
    // be called from the client.
    status_t setDefaultBufferSize(uint32_t w, uint32_t h);

private:

    // freeAllBuffers frees the resources (both GraphicBuffer and EGLImage) for
@@ -158,6 +164,23 @@ private:
    // for a slot when requestBuffer is called with that slot's index.
    BufferSlot mSlots[NUM_BUFFER_SLOTS];

    // mDefaultWidth holds the default width of allocated buffers. It is used
    // in requestBuffers() if a width and height of zero is specified.
    uint32_t mDefaultWidth;

    // mDefaultHeight holds the default height of allocated buffers. It is used
    // in requestBuffers() if a width and height of zero is specified.
    uint32_t mDefaultHeight;

    // mPixelFormat holds the pixel format of allocated buffers. It is used
    // in requestBuffers() if a format of zero is specified.
    uint32_t mPixelFormat;

    // mUseDefaultSize indicates whether or not the default size should be used
    // that is, if the last requestBuffer has been called with both width
    // and height null.
    bool mUseDefaultSize;

    // mBufferCount is the number of buffer slots that the client and server
    // must maintain. It defaults to MIN_BUFFER_SLOTS and can be changed by
    // calling setBufferCount.
+49 −2
Original line number Diff line number Diff line
@@ -76,6 +76,10 @@ static float mtxRot270[16] = {
static void mtxMul(float out[16], const float a[16], const float b[16]);

SurfaceTexture::SurfaceTexture(GLuint tex) :
    mDefaultWidth(1),
    mDefaultHeight(1),
    mPixelFormat(PIXEL_FORMAT_RGBA_8888),
    mUseDefaultSize(true),
    mBufferCount(MIN_BUFFER_SLOTS),
    mCurrentTexture(INVALID_BUFFER_SLOT),
    mCurrentTransform(0),
@@ -115,6 +119,16 @@ status_t SurfaceTexture::setBufferCount(int bufferCount) {
    return OK;
}

status_t SurfaceTexture::setDefaultBufferSize(uint32_t w, uint32_t h)
{
    Mutex::Autolock lock(mMutex);
    if ((w != mDefaultWidth) || (h != mDefaultHeight)) {
        mDefaultWidth = w;
        mDefaultHeight = h;
    }
    return OK;
}

sp<GraphicBuffer> SurfaceTexture::requestBuffer(int buf,
        uint32_t w, uint32_t h, uint32_t format, uint32_t usage) {
    LOGV("SurfaceTexture::requestBuffer");
@@ -124,12 +138,34 @@ sp<GraphicBuffer> SurfaceTexture::requestBuffer(int buf,
                mBufferCount, buf);
        return 0;
    }
    if ((w && !h) || (!w & h)) {
        LOGE("requestBuffer: invalid size: w=%u, h=%u: %d", w, h, buf);
        return 0;
    }

    const bool useDefaultSize = !w && !h;
    if (useDefaultSize) {
        // use the default size
        w = mDefaultWidth;
        h = mDefaultHeight;
    }

    const bool updateFormat = (format != 0);
    if (!updateFormat) {
        // keep the current (or default) format
        format = mPixelFormat;
    }

    usage |= GraphicBuffer::USAGE_HW_TEXTURE;
    sp<GraphicBuffer> graphicBuffer(
            mGraphicBufferAlloc->createGraphicBuffer(w, h, format, usage));
    if (graphicBuffer == 0) {
        LOGE("requestBuffer: SurfaceComposer::createGraphicBuffer failed");
    } else {
        mUseDefaultSize = useDefaultSize;
        if (updateFormat) {
            mPixelFormat = format;
        }
        mSlots[buf].mGraphicBuffer = graphicBuffer;
        if (mSlots[buf].mEglImage != EGL_NO_IMAGE_KHR) {
            eglDestroyImageKHR(mSlots[buf].mEglDisplay, mSlots[buf].mEglImage);
@@ -155,7 +191,18 @@ status_t SurfaceTexture::dequeueBuffer(int *buf) {
    if (found == INVALID_BUFFER_SLOT) {
        return -EBUSY;
    }

    *buf = found;

    const sp<GraphicBuffer>& buffer(mSlots[found].mGraphicBuffer);
    if (buffer == NULL) {
        return ISurfaceTexture::BUFFER_NEEDS_REALLOCATION;
    }
    if ((mUseDefaultSize) &&
        ((uint32_t(buffer->width) != mDefaultWidth) ||
         (uint32_t(buffer->height) != mDefaultHeight))) {
        return ISurfaceTexture::BUFFER_NEEDS_REALLOCATION;
    }
    return OK;
}

@@ -312,10 +359,10 @@ void SurfaceTexture::getTransformMatrix(float mtx[16]) {
        } else {
            tx = 0.0f;
        }
        if (mCurrentCrop.right < buf->getWidth()) {
        if (mCurrentCrop.right < int32_t(buf->getWidth())) {
            xshrink++;
        }
        if (mCurrentCrop.bottom < buf->getHeight()) {
        if (mCurrentCrop.bottom < int32_t(buf->getHeight())) {
            ty = (float(buf->getHeight() - mCurrentCrop.bottom) + 1.0f) /
                    float(buf->getHeight());
            yshrink++;
+4 −3
Original line number Diff line number Diff line
@@ -25,8 +25,8 @@ namespace android {

SurfaceTextureClient::SurfaceTextureClient(
        const sp<ISurfaceTexture>& surfaceTexture):
        mSurfaceTexture(surfaceTexture), mAllocator(0), mReqWidth(1),
        mReqHeight(1), mReqFormat(DEFAULT_FORMAT), mReqUsage(0),
        mSurfaceTexture(surfaceTexture), mAllocator(0), mReqWidth(0),
        mReqHeight(0), mReqFormat(DEFAULT_FORMAT), mReqUsage(0),
        mTimestamp(NATIVE_WINDOW_TIMESTAMP_AUTO), mMutex() {
    // Initialize the ANativeWindow function pointers.
    ANativeWindow::setSwapInterval  = setSwapInterval;
@@ -100,7 +100,8 @@ int SurfaceTextureClient::dequeueBuffer(android_native_buffer_t** buffer) {
        return err;
    }
    sp<GraphicBuffer>& gbuf(mSlots[buf]);
    if (gbuf == 0 || gbuf->getWidth() != mReqWidth ||
    if (err == ISurfaceTexture::BUFFER_NEEDS_REALLOCATION ||
        gbuf == 0 || gbuf->getWidth() != mReqWidth ||
        gbuf->getHeight() != mReqHeight ||
        uint32_t(gbuf->getPixelFormat()) != mReqFormat ||
        (gbuf->getUsage() & mReqUsage) != mReqUsage) {
+147 −0
Original line number Diff line number Diff line
@@ -100,4 +100,151 @@ TEST_F(SurfaceTextureClientTest, EglCreateWindowSurfaceFails) {
    eglTerminate(dpy);
}

TEST_F(SurfaceTextureClientTest, BufferGeometryInvalidSizesFail) {
    sp<ANativeWindow> anw(mSTC);

    EXPECT_GT(OK, native_window_set_buffers_geometry(anw.get(), -1,  0,  0));
    EXPECT_GT(OK, native_window_set_buffers_geometry(anw.get(),  0, -1,  0));
    EXPECT_GT(OK, native_window_set_buffers_geometry(anw.get(),  0,  0, -1));
    EXPECT_GT(OK, native_window_set_buffers_geometry(anw.get(), -1, -1,  0));
    EXPECT_GT(OK, native_window_set_buffers_geometry(anw.get(),  0,  8,  0));
    EXPECT_GT(OK, native_window_set_buffers_geometry(anw.get(),  8,  0,  0));
}

TEST_F(SurfaceTextureClientTest, DefaultGeometryValues) {
    sp<ANativeWindow> anw(mSTC);
    android_native_buffer_t* buf;
    ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf));
    EXPECT_EQ(1, buf->width);
    EXPECT_EQ(1, buf->height);
    EXPECT_EQ(PIXEL_FORMAT_RGBA_8888, buf->format);
    ASSERT_EQ(OK, anw->cancelBuffer(anw.get(), buf));
}

TEST_F(SurfaceTextureClientTest, BufferGeometryCanBeSet) {
    sp<ANativeWindow> anw(mSTC);
    android_native_buffer_t* buf;
    EXPECT_EQ(OK, native_window_set_buffers_geometry(anw.get(), 16, 8, PIXEL_FORMAT_RGB_565));
    ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf));
    EXPECT_EQ(16, buf->width);
    EXPECT_EQ(8, buf->height);
    EXPECT_EQ(PIXEL_FORMAT_RGB_565, buf->format);
    ASSERT_EQ(OK, anw->cancelBuffer(anw.get(), buf));
}

TEST_F(SurfaceTextureClientTest, BufferGeometryDefaultSizeSetFormat) {
    sp<ANativeWindow> anw(mSTC);
    android_native_buffer_t* buf;
    EXPECT_EQ(OK, native_window_set_buffers_geometry(anw.get(), 0, 0, PIXEL_FORMAT_RGB_565));
    ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf));
    EXPECT_EQ(1, buf->width);
    EXPECT_EQ(1, buf->height);
    EXPECT_EQ(PIXEL_FORMAT_RGB_565, buf->format);
    ASSERT_EQ(OK, anw->cancelBuffer(anw.get(), buf));
}

TEST_F(SurfaceTextureClientTest, BufferGeometrySetSizeDefaultFormat) {
    sp<ANativeWindow> anw(mSTC);
    android_native_buffer_t* buf;
    EXPECT_EQ(OK, native_window_set_buffers_geometry(anw.get(), 16, 8, 0));
    ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf));
    EXPECT_EQ(16, buf->width);
    EXPECT_EQ(8, buf->height);
    EXPECT_EQ(PIXEL_FORMAT_RGBA_8888, buf->format);
    ASSERT_EQ(OK, anw->cancelBuffer(anw.get(), buf));
}

TEST_F(SurfaceTextureClientTest, BufferGeometrySizeCanBeUnset) {
    sp<ANativeWindow> anw(mSTC);
    android_native_buffer_t* buf;
    EXPECT_EQ(OK, native_window_set_buffers_geometry(anw.get(), 16, 8, 0));
    ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf));
    EXPECT_EQ(16, buf->width);
    EXPECT_EQ(8, buf->height);
    EXPECT_EQ(PIXEL_FORMAT_RGBA_8888, buf->format);
    ASSERT_EQ(OK, anw->cancelBuffer(anw.get(), buf));
    EXPECT_EQ(OK, native_window_set_buffers_geometry(anw.get(), 0, 0, 0));
    ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf));
    EXPECT_EQ(1, buf->width);
    EXPECT_EQ(1, buf->height);
    EXPECT_EQ(PIXEL_FORMAT_RGBA_8888, buf->format);
    ASSERT_EQ(OK, anw->cancelBuffer(anw.get(), buf));
}

TEST_F(SurfaceTextureClientTest, BufferGeometrySizeCanBeChangedWithoutFormat) {
    sp<ANativeWindow> anw(mSTC);
    android_native_buffer_t* buf;
    EXPECT_EQ(OK, native_window_set_buffers_geometry(anw.get(), 0, 0, PIXEL_FORMAT_RGB_565));
    ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf));
    EXPECT_EQ(1, buf->width);
    EXPECT_EQ(1, buf->height);
    EXPECT_EQ(PIXEL_FORMAT_RGB_565, buf->format);
    ASSERT_EQ(OK, anw->cancelBuffer(anw.get(), buf));
    EXPECT_EQ(OK, native_window_set_buffers_geometry(anw.get(), 16, 8, 0));
    ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf));
    EXPECT_EQ(16, buf->width);
    EXPECT_EQ(8, buf->height);
    EXPECT_EQ(PIXEL_FORMAT_RGB_565, buf->format);
    ASSERT_EQ(OK, anw->cancelBuffer(anw.get(), buf));
}

TEST_F(SurfaceTextureClientTest, SurfaceTextureSetDefaultSize) {
    sp<ANativeWindow> anw(mSTC);
    sp<SurfaceTexture> st(mST);
    android_native_buffer_t* buf;
    EXPECT_EQ(OK, st->setDefaultBufferSize(16, 8));
    ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf));
    EXPECT_EQ(16, buf->width);
    EXPECT_EQ(8, buf->height);
    EXPECT_EQ(PIXEL_FORMAT_RGBA_8888, buf->format);
    ASSERT_EQ(OK, anw->cancelBuffer(anw.get(), buf));
}

TEST_F(SurfaceTextureClientTest, SurfaceTextureSetDefaultSizeAfterDequeue) {
    sp<ANativeWindow> anw(mSTC);
    sp<SurfaceTexture> st(mST);
    android_native_buffer_t* buf[2];
    ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf[0]));
    ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf[1]));
    EXPECT_NE(buf[0], buf[1]);
    ASSERT_EQ(OK, anw->cancelBuffer(anw.get(), buf[0]));
    ASSERT_EQ(OK, anw->cancelBuffer(anw.get(), buf[1]));
    EXPECT_EQ(OK, st->setDefaultBufferSize(16, 8));
    ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf[0]));
    ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf[1]));
    EXPECT_NE(buf[0], buf[1]);
    EXPECT_EQ(16, buf[0]->width);
    EXPECT_EQ(16, buf[1]->width);
    EXPECT_EQ(8, buf[0]->height);
    EXPECT_EQ(8, buf[1]->height);
    ASSERT_EQ(OK, anw->cancelBuffer(anw.get(), buf[0]));
    ASSERT_EQ(OK, anw->cancelBuffer(anw.get(), buf[1]));
}

TEST_F(SurfaceTextureClientTest, SurfaceTextureSetDefaultSizeVsGeometry) {
    sp<ANativeWindow> anw(mSTC);
    sp<SurfaceTexture> st(mST);
    android_native_buffer_t* buf[2];
    EXPECT_EQ(OK, st->setDefaultBufferSize(16, 8));
    ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf[0]));
    ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf[1]));
    EXPECT_NE(buf[0], buf[1]);
    EXPECT_EQ(16, buf[0]->width);
    EXPECT_EQ(16, buf[1]->width);
    EXPECT_EQ(8, buf[0]->height);
    EXPECT_EQ(8, buf[1]->height);
    ASSERT_EQ(OK, anw->cancelBuffer(anw.get(), buf[0]));
    ASSERT_EQ(OK, anw->cancelBuffer(anw.get(), buf[1]));
    EXPECT_EQ(OK, native_window_set_buffers_geometry(anw.get(), 12, 24, 0));
    ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf[0]));
    ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf[1]));
    EXPECT_NE(buf[0], buf[1]);
    EXPECT_EQ(12, buf[0]->width);
    EXPECT_EQ(12, buf[1]->width);
    EXPECT_EQ(24, buf[0]->height);
    EXPECT_EQ(24, buf[1]->height);
    ASSERT_EQ(OK, anw->cancelBuffer(anw.get(), buf[0]));
    ASSERT_EQ(OK, anw->cancelBuffer(anw.get(), buf[1]));
}

}