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:
parent
3d9dda7dc3
commit
a5c75c0162
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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++;
|
||||
|
@ -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) {
|
||||
|
@ -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]));
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user