summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/gui/ISurfaceTexture.h4
-rw-r--r--include/gui/SurfaceTexture.h23
-rw-r--r--libs/gui/SurfaceTexture.cpp51
-rw-r--r--libs/gui/SurfaceTextureClient.cpp7
-rw-r--r--libs/gui/tests/SurfaceTextureClient_test.cpp147
5 files changed, 227 insertions, 5 deletions
diff --git a/include/gui/ISurfaceTexture.h b/include/gui/ISurfaceTexture.h
index 6ed3c6f..d2d3bb8 100644
--- a/include/gui/ISurfaceTexture.h
+++ b/include/gui/ISurfaceTexture.h
@@ -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
diff --git a/include/gui/SurfaceTexture.h b/include/gui/SurfaceTexture.h
index afa64d3..585d288 100644
--- a/include/gui/SurfaceTexture.h
+++ b/include/gui/SurfaceTexture.h
@@ -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.
diff --git a/libs/gui/SurfaceTexture.cpp b/libs/gui/SurfaceTexture.cpp
index cdaca47..f4e2a67 100644
--- a/libs/gui/SurfaceTexture.cpp
+++ b/libs/gui/SurfaceTexture.cpp
@@ -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++;
diff --git a/libs/gui/SurfaceTextureClient.cpp b/libs/gui/SurfaceTextureClient.cpp
index a4812d0..29fc4d3 100644
--- a/libs/gui/SurfaceTextureClient.cpp
+++ b/libs/gui/SurfaceTextureClient.cpp
@@ -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) {
diff --git a/libs/gui/tests/SurfaceTextureClient_test.cpp b/libs/gui/tests/SurfaceTextureClient_test.cpp
index 94b05bc..348171d 100644
--- a/libs/gui/tests/SurfaceTextureClient_test.cpp
+++ b/libs/gui/tests/SurfaceTextureClient_test.cpp
@@ -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]));
+}
+
}