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
This commit is contained in:
Mathias Agopian 2011-03-31 19:10:24 -07:00
parent 3d9dda7dc3
commit a5c75c0162
5 changed files with 227 additions and 5 deletions

View File

@ -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

View File

@ -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.

View File

@ -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++;

View File

@ -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) {

View File

@ -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]));
}
}