Merge "Add filename and line number in the debug messages."
diff --git a/include/gui/ISurfaceTexture.h b/include/gui/ISurfaceTexture.h
index bc630ae..1eda646 100644
--- a/include/gui/ISurfaceTexture.h
+++ b/include/gui/ISurfaceTexture.h
@@ -51,7 +51,7 @@
// the given slot index, and the client is expected to mirror the
// slot->buffer mapping so that it's not necessary to transfer a
// GraphicBuffer for every dequeue operation.
- virtual sp<GraphicBuffer> requestBuffer(int slot) = 0;
+ virtual status_t requestBuffer(int slot, sp<GraphicBuffer>* buf) = 0;
// setBufferCount sets the number of buffer slots available. Calling this
// will also cause all buffer slots to be emptied. The caller should empty
@@ -94,12 +94,6 @@
virtual status_t setTransform(uint32_t transform) = 0;
virtual status_t setScalingMode(int mode) = 0;
- // getAllocator retrieves the binder object that must be referenced as long
- // as the GraphicBuffers dequeued from this ISurfaceTexture are referenced.
- // Holding this binder reference prevents SurfaceFlinger from freeing the
- // buffers before the client is done with them.
- virtual sp<IBinder> getAllocator() = 0;
-
// query retrieves some information for this surface
// 'what' tokens allowed are that of android_natives.h
virtual int query(int what, int* value) = 0;
diff --git a/include/gui/SurfaceTexture.h b/include/gui/SurfaceTexture.h
index 945f4bc..2a8e725 100644
--- a/include/gui/SurfaceTexture.h
+++ b/include/gui/SurfaceTexture.h
@@ -69,7 +69,7 @@
// SurfaceTexture object (i.e. they are not owned by the client).
virtual status_t setBufferCount(int bufferCount);
- virtual sp<GraphicBuffer> requestBuffer(int buf);
+ virtual status_t requestBuffer(int slot, sp<GraphicBuffer>* buf);
// dequeueBuffer gets the next buffer slot index for the client to use. If a
// buffer slot is available then that slot index is written to the location
@@ -190,6 +190,17 @@
// getCurrentScalingMode returns the scaling mode of the current buffer
uint32_t getCurrentScalingMode() const;
+ // abandon frees all the buffers and puts the SurfaceTexture into the
+ // 'abandoned' state. Once put in this state the SurfaceTexture can never
+ // leave it. When in the 'abandoned' state, all methods of the
+ // ISurfaceTexture interface will fail with the NO_INIT error.
+ //
+ // Note that while calling this method causes all the buffers to be freed
+ // from the perspective of the the SurfaceTexture, if there are additional
+ // references on the buffers (e.g. if a buffer is referenced by a client or
+ // by OpenGL ES as a texture) then those buffer will remain allocated.
+ void abandon();
+
// dump our state in a String
void dump(String8& result) const;
void dump(String8& result, const char* prefix, char* buffer, size_t SIZE) const;
@@ -200,7 +211,6 @@
// all slots.
void freeAllBuffers();
static bool isExternalFormat(uint32_t format);
- static GLenum getTextureTarget(uint32_t format);
private:
@@ -337,14 +347,9 @@
// reset mCurrentTexture to INVALID_BUFFER_SLOT.
int mCurrentTexture;
- // mCurrentTextureTarget is the GLES texture target to be used with the
- // current texture.
- GLenum mCurrentTextureTarget;
-
// mCurrentTextureBuf is the graphic buffer of the current texture. It's
// possible that this buffer is not associated with any buffer slot, so we
- // must track it separately in order to properly use
- // IGraphicBufferAlloc::freeAllGraphicBuffersExcept.
+ // must track it separately in order to support the getCurrentBuffer method.
sp<GraphicBuffer> mCurrentTextureBuf;
// mCurrentCrop is the crop rectangle that applies to the current texture.
@@ -412,6 +417,13 @@
typedef Vector<int> Fifo;
Fifo mQueue;
+ // mAbandoned indicates that the SurfaceTexture will no longer be used to
+ // consume images buffers pushed to it using the ISurfaceTexture interface.
+ // It is initialized to false, and set to true in the abandon method. A
+ // SurfaceTexture that has been abandoned will return the NO_INIT error from
+ // all ISurfaceTexture methods capable of returning an error.
+ bool mAbandoned;
+
// mMutex is the mutex used to prevent concurrent access to the member
// variables of SurfaceTexture objects. It must be locked whenever the
// member variables are accessed.
diff --git a/include/gui/SurfaceTextureClient.h b/include/gui/SurfaceTextureClient.h
index 829d8ab..56f029f 100644
--- a/include/gui/SurfaceTextureClient.h
+++ b/include/gui/SurfaceTextureClient.h
@@ -106,10 +106,6 @@
// interactions with the server using this interface.
sp<ISurfaceTexture> mSurfaceTexture;
- // mAllocator is the binder object that is referenced to prevent the
- // dequeued buffers from being freed prematurely.
- sp<IBinder> mAllocator;
-
// mSlots stores the buffers that have been allocated for each buffer slot.
// It is initialized to null pointers, and gets filled in with the result of
// ISurfaceTexture::requestBuffer when the client dequeues a buffer from a
diff --git a/include/surfaceflinger/Surface.h b/include/surfaceflinger/Surface.h
index 9c352ad..0460bbd 100644
--- a/include/surfaceflinger/Surface.h
+++ b/include/surfaceflinger/Surface.h
@@ -122,7 +122,10 @@
uint32_t reserved[2];
};
+ explicit Surface(const sp<ISurfaceTexture>& st);
+
static status_t writeToParcel(const sp<Surface>& control, Parcel* parcel);
+
static sp<Surface> readFromParcel(const Parcel& data);
static bool isValid(const sp<Surface>& surface) {
return (surface != 0) && surface->isValid();
@@ -147,14 +150,14 @@
Surface& operator = (Surface& rhs);
Surface(const Surface& rhs);
- Surface(const sp<SurfaceControl>& control);
+ explicit Surface(const sp<SurfaceControl>& control);
Surface(const Parcel& data, const sp<IBinder>& ref);
~Surface();
/*
* private stuff...
*/
- void init();
+ void init(const sp<ISurfaceTexture>& surfaceTexture);
static void cleanCachedSurfacesLocked();
diff --git a/include/ui/PixelFormat.h b/include/ui/PixelFormat.h
index f46f25c..848c5a1 100644
--- a/include/ui/PixelFormat.h
+++ b/include/ui/PixelFormat.h
@@ -55,7 +55,7 @@
PIXEL_FORMAT_OPAQUE = -1,
// System chooses an opaque format (no alpha bits required)
-
+
// real pixel formats supported for rendering -----------------------------
PIXEL_FORMAT_RGBA_8888 = HAL_PIXEL_FORMAT_RGBA_8888, // 4x8-bit RGBA
@@ -84,7 +84,7 @@
INDEX_GREEN = 2,
INDEX_BLUE = 3
};
-
+
enum { // components
ALPHA = 1,
RGB = 2,
@@ -98,10 +98,10 @@
uint8_t h;
uint8_t l;
};
-
+
inline PixelFormatInfo() : version(sizeof(PixelFormatInfo)) { }
size_t getScanlineSize(unsigned int width) const;
- size_t getSize(size_t ci) const {
+ size_t getSize(size_t ci) const {
return (ci <= 3) ? (cinfo[ci].h - cinfo[ci].l) : 0;
}
size_t version;
@@ -112,7 +112,7 @@
szinfo cinfo[4];
struct {
uint8_t h_alpha;
- uint8_t l_alpha;
+ uint8_t l_alpha;
uint8_t h_red;
uint8_t l_red;
uint8_t h_green;
diff --git a/libs/gui/ISurfaceTexture.cpp b/libs/gui/ISurfaceTexture.cpp
index be90e2e..55246dc 100644
--- a/libs/gui/ISurfaceTexture.cpp
+++ b/libs/gui/ISurfaceTexture.cpp
@@ -38,7 +38,6 @@
CANCEL_BUFFER,
SET_CROP,
SET_TRANSFORM,
- GET_ALLOCATOR,
QUERY,
SET_SYNCHRONOUS_MODE,
CONNECT,
@@ -55,18 +54,18 @@
{
}
- virtual sp<GraphicBuffer> requestBuffer(int bufferIdx) {
+ virtual status_t requestBuffer(int bufferIdx, sp<GraphicBuffer>* buf) {
Parcel data, reply;
data.writeInterfaceToken(ISurfaceTexture::getInterfaceDescriptor());
data.writeInt32(bufferIdx);
remote()->transact(REQUEST_BUFFER, data, &reply);
- sp<GraphicBuffer> buffer;
bool nonNull = reply.readInt32();
if (nonNull) {
- buffer = new GraphicBuffer();
- reply.read(*buffer);
+ *buf = new GraphicBuffer();
+ reply.read(**buf);
}
- return buffer;
+ status_t result = reply.readInt32();
+ return result;
}
virtual status_t setBufferCount(int bufferCount)
@@ -144,13 +143,6 @@
return result;
}
- virtual sp<IBinder> getAllocator() {
- Parcel data, reply;
- data.writeInterfaceToken(ISurfaceTexture::getInterfaceDescriptor());
- remote()->transact(GET_ALLOCATOR, data, &reply);
- return reply.readStrongBinder();
- }
-
virtual int query(int what, int* value) {
Parcel data, reply;
data.writeInterfaceToken(ISurfaceTexture::getInterfaceDescriptor());
@@ -200,11 +192,13 @@
case REQUEST_BUFFER: {
CHECK_INTERFACE(ISurfaceTexture, data, reply);
int bufferIdx = data.readInt32();
- sp<GraphicBuffer> buffer(requestBuffer(bufferIdx));
+ sp<GraphicBuffer> buffer;
+ int result = requestBuffer(bufferIdx, &buffer);
reply->writeInt32(buffer != 0);
if (buffer != 0) {
reply->write(*buffer);
}
+ reply->writeInt32(result);
return NO_ERROR;
} break;
case SET_BUFFER_COUNT: {
@@ -270,12 +264,6 @@
reply->writeInt32(result);
return NO_ERROR;
} break;
- case GET_ALLOCATOR: {
- CHECK_INTERFACE(ISurfaceTexture, data, reply);
- sp<IBinder> result = getAllocator();
- reply->writeStrongBinder(result);
- return NO_ERROR;
- } break;
case QUERY: {
CHECK_INTERFACE(ISurfaceTexture, data, reply);
int value;
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index c4f9e53..ccf98e5 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -184,6 +184,7 @@
identity = control->mIdentity;
}
parcel->writeStrongBinder(sur!=0 ? sur->asBinder() : NULL);
+ parcel->writeStrongBinder(NULL); // NULL ISurfaceTexture in this case.
parcel->writeInt32(identity);
return NO_ERROR;
}
@@ -192,7 +193,8 @@
{
Mutex::Autolock _l(mLock);
if (mSurfaceData == 0) {
- mSurfaceData = new Surface(const_cast<SurfaceControl*>(this));
+ sp<SurfaceControl> surface_control(const_cast<SurfaceControl*>(this));
+ mSurfaceData = new Surface(surface_control);
}
return mSurfaceData;
}
@@ -208,31 +210,58 @@
mSurface(surface->mSurface),
mIdentity(surface->mIdentity)
{
- init();
+ sp<ISurfaceTexture> st;
+ if (mSurface != NULL) {
+ st = mSurface->getSurfaceTexture();
+ }
+ init(st);
}
Surface::Surface(const Parcel& parcel, const sp<IBinder>& ref)
: SurfaceTextureClient()
{
- mSurface = interface_cast<ISurface>(ref);
+ mSurface = interface_cast<ISurface>(ref);
+ sp<IBinder> st_binder(parcel.readStrongBinder());
+ sp<ISurfaceTexture> st;
+ if (st_binder != NULL) {
+ st = interface_cast<ISurfaceTexture>(st_binder);
+ } else if (mSurface != NULL) {
+ st = mSurface->getSurfaceTexture();
+ }
+
mIdentity = parcel.readInt32();
- init();
+ init(st);
+}
+
+Surface::Surface(const sp<ISurfaceTexture>& st)
+ : SurfaceTextureClient(),
+ mSurface(NULL),
+ mIdentity(0)
+{
+ init(st);
}
status_t Surface::writeToParcel(
const sp<Surface>& surface, Parcel* parcel)
{
sp<ISurface> sur;
+ sp<ISurfaceTexture> st;
uint32_t identity = 0;
if (Surface::isValid(surface)) {
sur = surface->mSurface;
+ st = surface->getISurfaceTexture();
identity = surface->mIdentity;
- } else if (surface != 0 && surface->mSurface != 0) {
- LOGW("Parceling invalid surface with non-NULL ISurface as NULL: "
- "mSurface = %p, mIdentity = %d",
- surface->mSurface.get(), surface->mIdentity);
+ } else if (surface != 0 &&
+ (surface->mSurface != NULL ||
+ surface->getISurfaceTexture() != NULL)) {
+ LOGE("Parceling invalid surface with non-NULL ISurface/ISurfaceTexture as NULL: "
+ "mSurface = %p, surfaceTexture = %p, mIdentity = %d, ",
+ surface->mSurface.get(), surface->getISurfaceTexture().get(),
+ surface->mIdentity);
}
- parcel->writeStrongBinder(sur!=0 ? sur->asBinder() : NULL);
+
+ parcel->writeStrongBinder(sur != NULL ? sur->asBinder() : NULL);
+ parcel->writeStrongBinder(st != NULL ? st->asBinder() : NULL);
parcel->writeInt32(identity);
return NO_ERROR;
@@ -249,8 +278,8 @@
surface = new Surface(data, binder);
sCachedSurfaces.add(binder, surface);
}
- if (surface->mSurface == 0) {
- surface = 0;
+ if (surface->mSurface == NULL && surface->getISurfaceTexture() == NULL) {
+ surface = 0;
}
cleanCachedSurfacesLocked();
return surface;
@@ -267,10 +296,9 @@
}
}
-void Surface::init()
+void Surface::init(const sp<ISurfaceTexture>& surfaceTexture)
{
- if (mSurface != NULL) {
- sp<ISurfaceTexture> surfaceTexture(mSurface->getSurfaceTexture());
+ if (mSurface != NULL || surfaceTexture != NULL) {
LOGE_IF(surfaceTexture==0, "got a NULL ISurfaceTexture from ISurface");
if (surfaceTexture != NULL) {
setISurfaceTexture(surfaceTexture);
diff --git a/libs/gui/SurfaceTexture.cpp b/libs/gui/SurfaceTexture.cpp
index 0f08570..8d19957 100644
--- a/libs/gui/SurfaceTexture.cpp
+++ b/libs/gui/SurfaceTexture.cpp
@@ -86,7 +86,6 @@
mClientBufferCount(0),
mServerBufferCount(MIN_ASYNC_BUFFER_SLOTS),
mCurrentTexture(INVALID_BUFFER_SLOT),
- mCurrentTextureTarget(GL_TEXTURE_EXTERNAL_OES),
mCurrentTransform(0),
mCurrentTimestamp(0),
mNextTransform(0),
@@ -94,7 +93,8 @@
mTexName(tex),
mSynchronousMode(false),
mAllowSynchronousMode(allowSynchronousMode),
- mConnectedApi(NO_CONNECTED_API) {
+ mConnectedApi(NO_CONNECTED_API),
+ mAbandoned(false) {
LOGV("SurfaceTexture::SurfaceTexture");
sp<ISurfaceComposer> composer(ComposerService::getComposerService());
mGraphicBufferAlloc = composer->createGraphicBufferAlloc();
@@ -150,6 +150,11 @@
LOGV("SurfaceTexture::setBufferCount");
Mutex::Autolock lock(mMutex);
+ if (mAbandoned) {
+ LOGE("setBufferCount: SurfaceTexture has been abandoned!");
+ return NO_INIT;
+ }
+
if (bufferCount > NUM_BUFFER_SLOTS) {
LOGE("setBufferCount: bufferCount larger than slots available");
return BAD_VALUE;
@@ -199,22 +204,32 @@
return OK;
}
-sp<GraphicBuffer> SurfaceTexture::requestBuffer(int buf) {
+status_t SurfaceTexture::requestBuffer(int slot, sp<GraphicBuffer>* buf) {
LOGV("SurfaceTexture::requestBuffer");
Mutex::Autolock lock(mMutex);
- if (buf < 0 || mBufferCount <= buf) {
- LOGE("requestBuffer: slot index out of range [0, %d]: %d",
- mBufferCount, buf);
- return 0;
+ if (mAbandoned) {
+ LOGE("requestBuffer: SurfaceTexture has been abandoned!");
+ return NO_INIT;
}
- mSlots[buf].mRequestBufferCalled = true;
- return mSlots[buf].mGraphicBuffer;
+ if (slot < 0 || mBufferCount <= slot) {
+ LOGE("requestBuffer: slot index out of range [0, %d]: %d",
+ mBufferCount, slot);
+ return BAD_VALUE;
+ }
+ mSlots[slot].mRequestBufferCalled = true;
+ *buf = mSlots[slot].mGraphicBuffer;
+ return NO_ERROR;
}
status_t SurfaceTexture::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h,
uint32_t format, uint32_t usage) {
LOGV("SurfaceTexture::dequeueBuffer");
+ if (mAbandoned) {
+ LOGE("dequeueBuffer: SurfaceTexture has been abandoned!");
+ return NO_INIT;
+ }
+
if ((w && !h) || (!w && h)) {
LOGE("dequeueBuffer: invalid size: w=%u, h=%u", w, h);
return BAD_VALUE;
@@ -252,6 +267,11 @@
// wait for the FIFO to drain
while (!mQueue.isEmpty()) {
mDequeueCondition.wait(mMutex);
+ if (mAbandoned) {
+ LOGE("dequeueBuffer: SurfaceTexture was abandoned while "
+ "blocked!");
+ return NO_INIT;
+ }
}
minBufferCountNeeded = mSynchronousMode ?
MIN_SYNC_BUFFER_SLOTS : MIN_ASYNC_BUFFER_SLOTS;
@@ -380,6 +400,11 @@
status_t SurfaceTexture::setSynchronousMode(bool enabled) {
Mutex::Autolock lock(mMutex);
+ if (mAbandoned) {
+ LOGE("setSynchronousMode: SurfaceTexture has been abandoned!");
+ return NO_INIT;
+ }
+
status_t err = OK;
if (!mAllowSynchronousMode && enabled)
return err;
@@ -410,6 +435,10 @@
{ // scope for the lock
Mutex::Autolock lock(mMutex);
+ if (mAbandoned) {
+ LOGE("queueBuffer: SurfaceTexture has been abandoned!");
+ return NO_INIT;
+ }
if (buf < 0 || buf >= mBufferCount) {
LOGE("queueBuffer: slot index out of range [0, %d]: %d",
mBufferCount, buf);
@@ -475,6 +504,12 @@
void SurfaceTexture::cancelBuffer(int buf) {
LOGV("SurfaceTexture::cancelBuffer");
Mutex::Autolock lock(mMutex);
+
+ if (mAbandoned) {
+ LOGW("cancelBuffer: SurfaceTexture has been abandoned!");
+ return;
+ }
+
if (buf < 0 || buf >= mBufferCount) {
LOGE("cancelBuffer: slot index out of range [0, %d]: %d",
mBufferCount, buf);
@@ -491,6 +526,10 @@
status_t SurfaceTexture::setCrop(const Rect& crop) {
LOGV("SurfaceTexture::setCrop");
Mutex::Autolock lock(mMutex);
+ if (mAbandoned) {
+ LOGE("setCrop: SurfaceTexture has been abandoned!");
+ return NO_INIT;
+ }
mNextCrop = crop;
return OK;
}
@@ -498,6 +537,10 @@
status_t SurfaceTexture::setTransform(uint32_t transform) {
LOGV("SurfaceTexture::setTransform");
Mutex::Autolock lock(mMutex);
+ if (mAbandoned) {
+ LOGE("setTransform: SurfaceTexture has been abandoned!");
+ return NO_INIT;
+ }
mNextTransform = transform;
return OK;
}
@@ -505,6 +548,12 @@
status_t SurfaceTexture::connect(int api) {
LOGV("SurfaceTexture::connect(this=%p, %d)", this, api);
Mutex::Autolock lock(mMutex);
+
+ if (mAbandoned) {
+ LOGE("connect: SurfaceTexture has been abandoned!");
+ return NO_INIT;
+ }
+
int err = NO_ERROR;
switch (api) {
case NATIVE_WINDOW_API_EGL:
@@ -529,6 +578,12 @@
status_t SurfaceTexture::disconnect(int api) {
LOGV("SurfaceTexture::disconnect(this=%p, %d)", this, api);
Mutex::Autolock lock(mMutex);
+
+ if (mAbandoned) {
+ LOGE("connect: SurfaceTexture has been abandoned!");
+ return NO_INIT;
+ }
+
int err = NO_ERROR;
switch (api) {
case NATIVE_WINDOW_API_EGL:
@@ -595,12 +650,8 @@
LOGW("updateTexImage: clearing GL error: %#04x", error);
}
- GLenum target = getTextureTarget(mSlots[buf].mGraphicBuffer->format);
- if (target != mCurrentTextureTarget) {
- glDeleteTextures(1, &mTexName);
- }
- glBindTexture(target, mTexName);
- glEGLImageTargetTexture2DOES(target, (GLeglImageOES)image);
+ glBindTexture(GL_TEXTURE_EXTERNAL_OES, mTexName);
+ glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, (GLeglImageOES)image);
bool failed = false;
while ((error = glGetError()) != GL_NO_ERROR) {
@@ -622,7 +673,6 @@
// Update the SurfaceTexture state.
mCurrentTexture = buf;
- mCurrentTextureTarget = target;
mCurrentTextureBuf = mSlots[buf].mGraphicBuffer;
mCurrentCrop = mSlots[buf].mCrop;
mCurrentTransform = mSlots[buf].mTransform;
@@ -636,7 +686,7 @@
mDequeueCondition.signal();
} else {
// We always bind the texture even if we don't update its contents.
- glBindTexture(mCurrentTextureTarget, mTexName);
+ glBindTexture(GL_TEXTURE_EXTERNAL_OES, mTexName);
}
return OK;
@@ -661,20 +711,8 @@
return false;
}
-GLenum SurfaceTexture::getTextureTarget(uint32_t format)
-{
- GLenum target = GL_TEXTURE_2D;
-#if defined(GL_OES_EGL_image_external)
- if (isExternalFormat(format)) {
- target = GL_TEXTURE_EXTERNAL_OES;
- }
-#endif
- return target;
-}
-
GLenum SurfaceTexture::getCurrentTextureTarget() const {
- Mutex::Autolock lock(mMutex);
- return mCurrentTextureTarget;
+ return GL_TEXTURE_EXTERNAL_OES;
}
void SurfaceTexture::getTransformMatrix(float mtx[16]) {
@@ -786,11 +824,6 @@
mFrameAvailableListener = listener;
}
-sp<IBinder> SurfaceTexture::getAllocator() {
- LOGV("SurfaceTexture::getAllocator");
- return mGraphicBufferAlloc->asBinder();
-}
-
void SurfaceTexture::freeAllBuffers() {
for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
mSlots[i].mGraphicBuffer = 0;
@@ -842,6 +875,12 @@
int SurfaceTexture::query(int what, int* outValue)
{
Mutex::Autolock lock(mMutex);
+
+ if (mAbandoned) {
+ LOGE("query: SurfaceTexture has been abandoned!");
+ return NO_INIT;
+ }
+
int value;
switch (what) {
case NATIVE_WINDOW_WIDTH:
@@ -868,6 +907,13 @@
return NO_ERROR;
}
+void SurfaceTexture::abandon() {
+ Mutex::Autolock lock(mMutex);
+ freeAllBuffers();
+ mAbandoned = true;
+ mDequeueCondition.signal();
+}
+
void SurfaceTexture::dump(String8& result) const
{
char buffer[1024];
@@ -895,12 +941,12 @@
}
snprintf(buffer, SIZE,
- "%scurrent: {crop=[%d,%d,%d,%d], transform=0x%02x, current=%d, target=0x%04x}\n"
+ "%scurrent: {crop=[%d,%d,%d,%d], transform=0x%02x, current=%d}\n"
"%snext : {crop=[%d,%d,%d,%d], transform=0x%02x, FIFO(%d)={%s}}\n"
,
prefix, mCurrentCrop.left,
mCurrentCrop.top, mCurrentCrop.right, mCurrentCrop.bottom,
- mCurrentTransform, mCurrentTexture, mCurrentTextureTarget,
+ mCurrentTransform, mCurrentTexture,
prefix, mNextCrop.left, mNextCrop.top, mNextCrop.right, mNextCrop.bottom,
mCurrentTransform, fifoSize, fifo.string()
);
diff --git a/libs/gui/SurfaceTextureClient.cpp b/libs/gui/SurfaceTextureClient.cpp
index 1dc6cd2..df0ad5a 100644
--- a/libs/gui/SurfaceTextureClient.cpp
+++ b/libs/gui/SurfaceTextureClient.cpp
@@ -55,6 +55,9 @@
mQueryWidth = 0;
mQueryHeight = 0;
mQueryFormat = 0;
+ mDefaultWidth = 0;
+ mDefaultHeight = 0;
+ mTransformHint = 0;
mConnectedToCpu = false;
}
@@ -62,9 +65,6 @@
const sp<ISurfaceTexture>& surfaceTexture)
{
mSurfaceTexture = surfaceTexture;
-
- // Get a reference to the allocator.
- mAllocator = mSurfaceTexture->getAllocator();
}
sp<ISurfaceTexture> SurfaceTextureClient::getISurfaceTexture() const {
@@ -148,10 +148,11 @@
}
if ((result & ISurfaceTexture::BUFFER_NEEDS_REALLOCATION) || gbuf == 0) {
- gbuf = mSurfaceTexture->requestBuffer(buf);
- if (gbuf == 0) {
- LOGE("dequeueBuffer: ISurfaceTexture::requestBuffer failed");
- return NO_MEMORY;
+ result = mSurfaceTexture->requestBuffer(buf, &gbuf);
+ if (result != NO_ERROR) {
+ LOGE("dequeueBuffer: ISurfaceTexture::requestBuffer failed: %d",
+ result);
+ return result;
}
mQueryWidth = gbuf->width;
mQueryHeight = gbuf->height;
diff --git a/libs/gui/tests/SurfaceTexture_test.cpp b/libs/gui/tests/SurfaceTexture_test.cpp
index 9abe89d..44babcf 100644
--- a/libs/gui/tests/SurfaceTexture_test.cpp
+++ b/libs/gui/tests/SurfaceTexture_test.cpp
@@ -832,9 +832,7 @@
pt->requestExitAndWait();
}
-// XXX: This test is disabled because there are currently no drivers that can
-// handle RGBA textures with the GL_TEXTURE_EXTERNAL_OES target.
-TEST_F(SurfaceTextureGLTest, DISABLED_TexturingFromCpuFilledRGBABufferNpot) {
+TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledRGBABufferNpot) {
const int texWidth = 64;
const int texHeight = 66;
@@ -871,26 +869,24 @@
EXPECT_TRUE(checkPixel( 0, 65, 35, 35, 35, 35));
EXPECT_TRUE(checkPixel(15, 10, 35, 231, 231, 231));
- EXPECT_TRUE(checkPixel(24, 63, 38, 228, 231, 35));
+ EXPECT_TRUE(checkPixel(23, 65, 231, 35, 231, 35));
EXPECT_TRUE(checkPixel(19, 40, 35, 231, 35, 35));
EXPECT_TRUE(checkPixel(38, 30, 231, 35, 35, 35));
EXPECT_TRUE(checkPixel(42, 54, 35, 35, 35, 231));
- EXPECT_TRUE(checkPixel(37, 33, 228, 38, 38, 38));
+ EXPECT_TRUE(checkPixel(37, 34, 35, 231, 231, 231));
EXPECT_TRUE(checkPixel(31, 8, 231, 35, 35, 231));
- EXPECT_TRUE(checkPixel(36, 47, 228, 35, 231, 231));
- EXPECT_TRUE(checkPixel(24, 63, 38, 228, 231, 35));
- EXPECT_TRUE(checkPixel(48, 3, 228, 228, 38, 35));
+ EXPECT_TRUE(checkPixel(37, 47, 231, 35, 231, 231));
+ EXPECT_TRUE(checkPixel(25, 38, 35, 35, 35, 35));
+ EXPECT_TRUE(checkPixel(49, 6, 35, 231, 35, 35));
EXPECT_TRUE(checkPixel(54, 50, 35, 231, 231, 231));
- EXPECT_TRUE(checkPixel(24, 25, 41, 41, 231, 231));
- EXPECT_TRUE(checkPixel(10, 9, 38, 38, 231, 231));
+ EXPECT_TRUE(checkPixel(27, 26, 231, 231, 231, 231));
+ EXPECT_TRUE(checkPixel(10, 6, 35, 35, 231, 231));
EXPECT_TRUE(checkPixel(29, 4, 35, 35, 35, 231));
- EXPECT_TRUE(checkPixel(56, 31, 38, 228, 231, 35));
+ EXPECT_TRUE(checkPixel(55, 28, 35, 35, 231, 35));
EXPECT_TRUE(checkPixel(58, 55, 35, 35, 231, 231));
}
-// XXX: This test is disabled because there are currently no drivers that can
-// handle RGBA textures with the GL_TEXTURE_EXTERNAL_OES target.
-TEST_F(SurfaceTextureGLTest, DISABLED_TexturingFromCpuFilledRGBABufferPow2) {
+TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledRGBABufferPow2) {
const int texWidth = 64;
const int texHeight = 64;
@@ -944,9 +940,7 @@
EXPECT_TRUE(checkPixel( 3, 52, 35, 231, 35, 35));
}
-// XXX: This test is disabled because there are currently no drivers that can
-// handle RGBA textures with the GL_TEXTURE_EXTERNAL_OES target.
-TEST_F(SurfaceTextureGLTest, DISABLED_TexturingFromGLFilledRGBABufferPow2) {
+TEST_F(SurfaceTextureGLTest, TexturingFromGLFilledRGBABufferPow2) {
const int texWidth = 64;
const int texHeight = 64;
@@ -956,7 +950,7 @@
EGLSurface stcEglSurface = eglCreateWindowSurface(mEglDisplay, mGlConfig,
mANW.get(), NULL);
ASSERT_EQ(EGL_SUCCESS, eglGetError());
- ASSERT_NE(EGL_NO_SURFACE, mEglSurface);
+ ASSERT_NE(EGL_NO_SURFACE, stcEglSurface);
EXPECT_TRUE(eglMakeCurrent(mEglDisplay, stcEglSurface, stcEglSurface,
mEglContext));
@@ -980,6 +974,8 @@
eglSwapBuffers(mEglDisplay, stcEglSurface);
+ eglDestroySurface(mEglDisplay, stcEglSurface);
+
// Do the consumer side of things
EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface,
mEglContext));
@@ -1018,6 +1014,83 @@
EXPECT_TRUE(checkPixel( 3, 52, 153, 153, 153, 153));
}
+TEST_F(SurfaceTextureGLTest, AbandonUnblocksDequeueBuffer) {
+ class ProducerThread : public Thread {
+ public:
+ ProducerThread(const sp<ANativeWindow>& anw):
+ mANW(anw),
+ mDequeueError(NO_ERROR) {
+ }
+
+ virtual ~ProducerThread() {
+ }
+
+ virtual bool threadLoop() {
+ Mutex::Autolock lock(mMutex);
+ ANativeWindowBuffer* anb;
+
+ // Frame 1
+ if (mANW->dequeueBuffer(mANW.get(), &anb) != NO_ERROR) {
+ return false;
+ }
+ if (anb == NULL) {
+ return false;
+ }
+ if (mANW->queueBuffer(mANW.get(), anb)
+ != NO_ERROR) {
+ return false;
+ }
+
+ // Frame 2
+ if (mANW->dequeueBuffer(mANW.get(), &anb) != NO_ERROR) {
+ return false;
+ }
+ if (anb == NULL) {
+ return false;
+ }
+ if (mANW->queueBuffer(mANW.get(), anb)
+ != NO_ERROR) {
+ return false;
+ }
+
+ // Frame 3 - error expected
+ mDequeueError = mANW->dequeueBuffer(mANW.get(), &anb);
+ return false;
+ }
+
+ status_t getDequeueError() {
+ Mutex::Autolock lock(mMutex);
+ return mDequeueError;
+ }
+
+ private:
+ sp<ANativeWindow> mANW;
+ status_t mDequeueError;
+ Mutex mMutex;
+ };
+
+ sp<FrameWaiter> fw(new FrameWaiter);
+ mST->setFrameAvailableListener(fw);
+ ASSERT_EQ(OK, mST->setSynchronousMode(true));
+ ASSERT_EQ(OK, mST->setBufferCountServer(2));
+
+ sp<Thread> pt(new ProducerThread(mANW));
+ pt->run();
+
+ fw->waitForFrame();
+ fw->waitForFrame();
+
+ // Sleep for 100ms to allow the producer thread's dequeueBuffer call to
+ // block waiting for a buffer to become available.
+ usleep(100000);
+
+ mST->abandon();
+
+ pt->requestExitAndWait();
+ ASSERT_EQ(NO_INIT,
+ reinterpret_cast<ProducerThread*>(pt.get())->getDequeueError());
+}
+
/*
* This test is for testing GL -> GL texture streaming via SurfaceTexture. It
* contains functionality to create a producer thread that will perform GL
@@ -1205,7 +1278,7 @@
sp<FrameCondition> mFC;
};
-TEST_F(SurfaceTextureGLToGLTest, UpdateTexImageBeforeFrameFinishedWorks) {
+TEST_F(SurfaceTextureGLToGLTest, UpdateTexImageBeforeFrameFinishedCompletes) {
class PT : public ProducerThread {
virtual void render() {
glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
@@ -1223,7 +1296,7 @@
// TODO: Add frame verification once RGB TEX_EXTERNAL_OES is supported!
}
-TEST_F(SurfaceTextureGLToGLTest, UpdateTexImageAfterFrameFinishedWorks) {
+TEST_F(SurfaceTextureGLToGLTest, UpdateTexImageAfterFrameFinishedCompletes) {
class PT : public ProducerThread {
virtual void render() {
glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
@@ -1241,7 +1314,7 @@
// TODO: Add frame verification once RGB TEX_EXTERNAL_OES is supported!
}
-TEST_F(SurfaceTextureGLToGLTest, RepeatedUpdateTexImageBeforeFrameFinishedWorks) {
+TEST_F(SurfaceTextureGLToGLTest, RepeatedUpdateTexImageBeforeFrameFinishedCompletes) {
enum { NUM_ITERATIONS = 1024 };
class PT : public ProducerThread {
@@ -1269,7 +1342,7 @@
}
}
-TEST_F(SurfaceTextureGLToGLTest, RepeatedUpdateTexImageAfterFrameFinishedWorks) {
+TEST_F(SurfaceTextureGLToGLTest, RepeatedUpdateTexImageAfterFrameFinishedCompletes) {
enum { NUM_ITERATIONS = 1024 };
class PT : public ProducerThread {
@@ -1297,4 +1370,70 @@
}
}
+// XXX: This test is disabled because it is currently hanging on some devices.
+TEST_F(SurfaceTextureGLToGLTest, DISABLED_RepeatedSwapBuffersWhileDequeueStalledCompletes) {
+ enum { NUM_ITERATIONS = 64 };
+
+ class PT : public ProducerThread {
+ virtual void render() {
+ for (int i = 0; i < NUM_ITERATIONS; i++) {
+ glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
+ glClear(GL_COLOR_BUFFER_BIT);
+ LOGV("+swapBuffers");
+ swapBuffers();
+ LOGV("-swapBuffers");
+ }
+ }
+ };
+
+ ASSERT_EQ(OK, mST->setSynchronousMode(true));
+ ASSERT_EQ(OK, mST->setBufferCountServer(2));
+
+ runProducerThread(new PT());
+
+ // Allow three frames to be rendered and queued before starting the
+ // rendering in this thread. For the latter two frames we don't call
+ // updateTexImage so the next dequeue from the producer thread will block
+ // waiting for a frame to become available.
+ mFC->waitForFrame();
+ mFC->finishFrame();
+
+ // We must call updateTexImage to consume the first frame so that the
+ // SurfaceTexture is able to reduce the buffer count to 2. This is because
+ // the GL driver may dequeue a buffer when the EGLSurface is created, and
+ // that happens before we call setBufferCountServer. It's possible that the
+ // driver does not dequeue a buffer at EGLSurface creation time, so we
+ // cannot rely on this to cause the second dequeueBuffer call to block.
+ mST->updateTexImage();
+
+ mFC->waitForFrame();
+ mFC->finishFrame();
+ mFC->waitForFrame();
+ mFC->finishFrame();
+
+ // Sleep for 100ms to allow the producer thread's dequeueBuffer call to
+ // block waiting for a buffer to become available.
+ usleep(100000);
+
+ // Render and present a number of images. This thread should not be blocked
+ // by the fact that the producer thread is blocking in dequeue.
+ for (int i = 0; i < NUM_ITERATIONS; i++) {
+ glClear(GL_COLOR_BUFFER_BIT);
+ eglSwapBuffers(mEglDisplay, mEglSurface);
+ }
+
+ // Consume the two pending buffers to unblock the producer thread.
+ mST->updateTexImage();
+ mST->updateTexImage();
+
+ // Consume the remaining buffers from the producer thread.
+ for (int i = 0; i < NUM_ITERATIONS-3; i++) {
+ mFC->waitForFrame();
+ mFC->finishFrame();
+ LOGV("+updateTexImage");
+ mST->updateTexImage();
+ LOGV("-updateTexImage");
+ }
+}
+
} // namespace android
diff --git a/libs/ui/FramebufferNativeWindow.cpp b/libs/ui/FramebufferNativeWindow.cpp
index 412552e..0e8ae61 100644
--- a/libs/ui/FramebufferNativeWindow.cpp
+++ b/libs/ui/FramebufferNativeWindow.cpp
@@ -310,35 +310,21 @@
int operation, ...)
{
switch (operation) {
- case NATIVE_WINDOW_SET_USAGE:
- // TODO: we should implement this
- return NO_ERROR;
case NATIVE_WINDOW_CONNECT:
- // TODO: we should implement this
- return NO_ERROR;
case NATIVE_WINDOW_DISCONNECT:
- // TODO: we should implement this
- return NO_ERROR;
- case NATIVE_WINDOW_LOCK:
- return INVALID_OPERATION;
- case NATIVE_WINDOW_UNLOCK_AND_POST:
- return INVALID_OPERATION;
- case NATIVE_WINDOW_SET_CROP:
- return INVALID_OPERATION;
- case NATIVE_WINDOW_SET_BUFFER_COUNT:
- // TODO: we should implement this
- return INVALID_OPERATION;
+ case NATIVE_WINDOW_SET_USAGE:
case NATIVE_WINDOW_SET_BUFFERS_GEOMETRY:
- return INVALID_OPERATION;
- case NATIVE_WINDOW_SET_BUFFERS_TRANSFORM:
- return INVALID_OPERATION;
- case NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP:
- return INVALID_OPERATION;
case NATIVE_WINDOW_SET_BUFFERS_DIMENSIONS:
- return INVALID_OPERATION;
case NATIVE_WINDOW_SET_BUFFERS_FORMAT:
- // TODO: we should implement this
+ case NATIVE_WINDOW_SET_BUFFERS_TRANSFORM:
+ // TODO: we should implement these
return NO_ERROR;
+
+ case NATIVE_WINDOW_LOCK:
+ case NATIVE_WINDOW_UNLOCK_AND_POST:
+ case NATIVE_WINDOW_SET_CROP:
+ case NATIVE_WINDOW_SET_BUFFER_COUNT:
+ case NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP:
case NATIVE_WINDOW_SET_SCALING_MODE:
return INVALID_OPERATION;
}
diff --git a/libs/utils/ResourceTypes.cpp b/libs/utils/ResourceTypes.cpp
index cb6c246..6cf01c8 100644
--- a/libs/utils/ResourceTypes.cpp
+++ b/libs/utils/ResourceTypes.cpp
@@ -4346,7 +4346,8 @@
| (0x0000ffff & (entryIndex));
resource_name resName;
if (!this->getResourceName(resID, &resName)) {
- return UNKNOWN_ERROR;
+ LOGW("idmap: resource 0x%08x has spec but lacks values, skipping\n", resID);
+ continue;
}
const String16 overlayType(resName.type, resName.typeLen);
diff --git a/services/surfaceflinger/SurfaceTextureLayer.cpp b/services/surfaceflinger/SurfaceTextureLayer.cpp
index 11f61cc..91e010f 100644
--- a/services/surfaceflinger/SurfaceTextureLayer.cpp
+++ b/services/surfaceflinger/SurfaceTextureLayer.cpp
@@ -60,7 +60,11 @@
sp<Layer> layer(mLayer.promote());
if (layer != NULL) {
- *outTransform = layer->getOrientation();
+ uint32_t orientation = layer->getOrientation();
+ if (orientation & Transform::ROT_INVALID) {
+ orientation = 0;
+ }
+ *outTransform = orientation;
}
return res;