summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/gui/SurfaceTexture.h22
-rw-r--r--libs/gui/SurfaceTexture.cpp81
2 files changed, 74 insertions, 29 deletions
diff --git a/include/gui/SurfaceTexture.h b/include/gui/SurfaceTexture.h
index 71d818c..a6fb12e 100644
--- a/include/gui/SurfaceTexture.h
+++ b/include/gui/SurfaceTexture.h
@@ -208,13 +208,27 @@ public:
protected:
- // freeAllBuffers frees the resources (both GraphicBuffer and EGLImage) for
- // all slots.
+ // freeBufferLocked frees the resources (both GraphicBuffer and EGLImage)
+ // for the given slot.
+ void freeBufferLocked(int index);
+
+ // freeAllBuffersLocked frees the resources (both GraphicBuffer and
+ // EGLImage) for all slots.
void freeAllBuffersLocked();
+ // freeAllBuffersExceptHeadLocked frees the resources (both GraphicBuffer
+ // and EGLImage) for all slots except the head of mQueue
+ void freeAllBuffersExceptHeadLocked();
+
// drainQueueLocked drains the buffer queue if we're in synchronous mode
- // returns immediately otherwise.
- void drainQueueLocked();
+ // returns immediately otherwise. return NO_INIT if SurfaceTexture
+ // became abandoned or disconnected during this call.
+ status_t drainQueueLocked();
+
+ // drainQueueAndFreeBuffersLocked drains the buffer queue if we're in
+ // synchronous mode and free all buffers. In asynchronous mode, all buffers
+ // are freed except the current buffer.
+ status_t drainQueueAndFreeBuffersLocked();
static bool isExternalFormat(uint32_t format);
diff --git a/libs/gui/SurfaceTexture.cpp b/libs/gui/SurfaceTexture.cpp
index 631cc1c..4afca68 100644
--- a/libs/gui/SurfaceTexture.cpp
+++ b/libs/gui/SurfaceTexture.cpp
@@ -418,7 +418,9 @@ status_t SurfaceTexture::setSynchronousMode(bool enabled) {
if (!enabled) {
// going to asynchronous mode, drain the queue
- drainQueueLocked();
+ err = drainQueueLocked();
+ if (err != NO_ERROR)
+ return err;
}
if (mSynchronousMode != enabled) {
@@ -616,13 +618,9 @@ status_t SurfaceTexture::disconnect(int api) {
case NATIVE_WINDOW_API_MEDIA:
case NATIVE_WINDOW_API_CAMERA:
if (mConnectedApi == api) {
+ drainQueueAndFreeBuffersLocked();
mConnectedApi = NO_CONNECTED_API;
- if (mQueue.isEmpty()) {
- // if the queue is not empty, we need to wait for it
- // to drain before we can free all buffers. This is
- // done in updateTexImage().
- freeAllBuffersLocked();
- }
+ mDequeueCondition.signal();
} else {
LOGE("disconnect: connected to another api (cur=%d, req=%d)",
mConnectedApi, api);
@@ -658,7 +656,7 @@ status_t SurfaceTexture::updateTexImage() {
if (mAbandoned) {
LOGE("calling updateTexImage() on an abandoned SurfaceTexture");
- //return NO_INIT;
+ return NO_INIT;
}
// In asynchronous mode the list is guaranteed to be one buffer
@@ -667,21 +665,14 @@ status_t SurfaceTexture::updateTexImage() {
Fifo::iterator front(mQueue.begin());
int buf = *front;
- if (uint32_t(buf) >= NUM_BUFFER_SLOTS) {
- LOGE("buffer index out of range (index=%d)", buf);
- //return BAD_VALUE;
- }
-
// Update the GL texture object.
EGLImageKHR image = mSlots[buf].mEglImage;
if (image == EGL_NO_IMAGE_KHR) {
EGLDisplay dpy = eglGetCurrentDisplay();
-
if (mSlots[buf].mGraphicBuffer == 0) {
LOGE("buffer at slot %d is null", buf);
- //return BAD_VALUE;
+ return BAD_VALUE;
}
-
image = createImage(dpy, mSlots[buf].mGraphicBuffer);
mSlots[buf].mEglImage = image;
mSlots[buf].mEglDisplay = dpy;
@@ -871,24 +862,64 @@ void SurfaceTexture::setFrameAvailableListener(
mFrameAvailableListener = listener;
}
+void SurfaceTexture::freeBufferLocked(int i) {
+ mSlots[i].mGraphicBuffer = 0;
+ mSlots[i].mBufferState = BufferSlot::FREE;
+ if (mSlots[i].mEglImage != EGL_NO_IMAGE_KHR) {
+ eglDestroyImageKHR(mSlots[i].mEglDisplay, mSlots[i].mEglImage);
+ mSlots[i].mEglImage = EGL_NO_IMAGE_KHR;
+ mSlots[i].mEglDisplay = EGL_NO_DISPLAY;
+ }
+}
+
void SurfaceTexture::freeAllBuffersLocked() {
LOGW_IF(!mQueue.isEmpty(),
"freeAllBuffersLocked called but mQueue is not empty");
for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
- mSlots[i].mGraphicBuffer = 0;
- mSlots[i].mBufferState = BufferSlot::FREE;
- if (mSlots[i].mEglImage != EGL_NO_IMAGE_KHR) {
- eglDestroyImageKHR(mSlots[i].mEglDisplay, mSlots[i].mEglImage);
- mSlots[i].mEglImage = EGL_NO_IMAGE_KHR;
- mSlots[i].mEglDisplay = EGL_NO_DISPLAY;
+ freeBufferLocked(i);
+ }
+}
+
+void SurfaceTexture::freeAllBuffersExceptHeadLocked() {
+ LOGW_IF(!mQueue.isEmpty(),
+ "freeAllBuffersExceptCurrentLocked called but mQueue is not empty");
+ int head = -1;
+ if (!mQueue.empty()) {
+ Fifo::iterator front(mQueue.begin());
+ head = *front;
+ }
+ for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
+ if (i != head) {
+ freeBufferLocked(i);
}
}
}
-void SurfaceTexture::drainQueueLocked() {
+status_t SurfaceTexture::drainQueueLocked() {
while (mSynchronousMode && !mQueue.isEmpty()) {
mDequeueCondition.wait(mMutex);
+ if (mAbandoned) {
+ LOGE("drainQueueLocked: SurfaceTexture has been abandoned!");
+ return NO_INIT;
+ }
+ if (mConnectedApi == NO_CONNECTED_API) {
+ LOGE("drainQueueLocked: SurfaceTexture is not connected!");
+ return NO_INIT;
+ }
}
+ return NO_ERROR;
+}
+
+status_t SurfaceTexture::drainQueueAndFreeBuffersLocked() {
+ status_t err = drainQueueLocked();
+ if (err == NO_ERROR) {
+ if (mSynchronousMode) {
+ freeAllBuffersLocked();
+ } else {
+ freeAllBuffersExceptHeadLocked();
+ }
+ }
+ return err;
}
EGLImageKHR SurfaceTexture::createImage(EGLDisplay dpy,
@@ -960,10 +991,10 @@ int SurfaceTexture::query(int what, int* outValue)
void SurfaceTexture::abandon() {
Mutex::Autolock lock(mMutex);
- // clear the queue
- freeAllBuffersLocked();
+ mQueue.clear();
mAbandoned = true;
mCurrentTextureBuf.clear();
+ freeAllBuffersLocked();
mDequeueCondition.signal();
}