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

Commit 27fd410b authored by Mathias Agopian's avatar Mathias Agopian Committed by Android (Google) Code Review
Browse files

Merge "SurfaceTexture can now force the client to request a buffer"

parents bf59b168 a5c75c01
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]));
}

}