diff options
| -rw-r--r-- | include/gui/ISurfaceTexture.h | 7 | ||||
| -rw-r--r-- | include/gui/SurfaceTexture.h | 28 | ||||
| -rw-r--r-- | include/utils/threads.h | 7 | ||||
| -rw-r--r-- | libs/gui/ISurfaceTexture.cpp | 13 | ||||
| -rw-r--r-- | libs/gui/SurfaceTexture.cpp | 179 | ||||
| -rw-r--r-- | libs/gui/SurfaceTextureClient.cpp | 3 | ||||
| -rw-r--r-- | services/surfaceflinger/Layer.cpp | 2 | ||||
| -rw-r--r-- | services/surfaceflinger/SurfaceTextureLayer.cpp | 14 | ||||
| -rw-r--r-- | services/surfaceflinger/SurfaceTextureLayer.h | 3 |
9 files changed, 199 insertions, 57 deletions
diff --git a/include/gui/ISurfaceTexture.h b/include/gui/ISurfaceTexture.h index 1eda646695..50626a0967 100644 --- a/include/gui/ISurfaceTexture.h +++ b/include/gui/ISurfaceTexture.h @@ -111,7 +111,12 @@ protected: // // This method will fail if the connect was previously called on the // SurfaceTexture and no corresponding disconnect call was made. - virtual status_t connect(int api) = 0; + // + // outWidth, outHeight and outTransform are filled with the default width + // and height of the window and current transform applied to buffers, + // respectively. + virtual status_t connect(int api, + uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransform) = 0; // disconnect attempts to disconnect a client API from the SurfaceTexture. // Calling this method will cause any subsequent calls to other diff --git a/include/gui/SurfaceTexture.h b/include/gui/SurfaceTexture.h index 2a8e725560..a6fb12e296 100644 --- a/include/gui/SurfaceTexture.h +++ b/include/gui/SurfaceTexture.h @@ -106,7 +106,8 @@ public: // // This method will fail if the connect was previously called on the // SurfaceTexture and no corresponding disconnect call was made. - virtual status_t connect(int api); + virtual status_t connect(int api, + uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransform); // disconnect attempts to disconnect a client API from the SurfaceTexture. // Calling this method will cause any subsequent calls to other @@ -207,9 +208,28 @@ public: protected: - // freeAllBuffers frees the resources (both GraphicBuffer and EGLImage) for - // all slots. - void freeAllBuffers(); + // 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. 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); private: diff --git a/include/utils/threads.h b/include/utils/threads.h index c8e9c0413d..c84a9b448c 100644 --- a/include/utils/threads.h +++ b/include/utils/threads.h @@ -20,6 +20,7 @@ #include <stdint.h> #include <sys/types.h> #include <time.h> +#include <system/graphics.h> #if defined(HAVE_PTHREADS) # include <pthread.h> @@ -42,8 +43,8 @@ enum { * ** Keep in sync with android.os.Process.java ** * *********************************************** * - * This maps directly to the "nice" priorites we use in Android. - * A thread priority should be chosen inverse-proportinally to + * This maps directly to the "nice" priorities we use in Android. + * A thread priority should be chosen inverse-proportionally to * the amount of work the thread is expected to do. The more work * a thread will do, the less favorable priority it should get so that * it doesn't starve the system. Threads not behaving properly might @@ -66,7 +67,7 @@ enum { ANDROID_PRIORITY_DISPLAY = -4, /* ui service treads might want to run at a urgent display (uncommon) */ - ANDROID_PRIORITY_URGENT_DISPLAY = -8, + ANDROID_PRIORITY_URGENT_DISPLAY = HAL_PRIORITY_URGENT_DISPLAY, /* all normal audio threads */ ANDROID_PRIORITY_AUDIO = -16, diff --git a/libs/gui/ISurfaceTexture.cpp b/libs/gui/ISurfaceTexture.cpp index 55246dc902..babd2c07bc 100644 --- a/libs/gui/ISurfaceTexture.cpp +++ b/libs/gui/ISurfaceTexture.cpp @@ -162,11 +162,15 @@ public: return result; } - virtual status_t connect(int api) { + virtual status_t connect(int api, + uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransform) { Parcel data, reply; data.writeInterfaceToken(ISurfaceTexture::getInterfaceDescriptor()); data.writeInt32(api); remote()->transact(CONNECT, data, &reply); + *outWidth = reply.readInt32(); + *outHeight = reply.readInt32(); + *outTransform = reply.readInt32(); status_t result = reply.readInt32(); return result; } @@ -283,7 +287,12 @@ status_t BnSurfaceTexture::onTransact( case CONNECT: { CHECK_INTERFACE(ISurfaceTexture, data, reply); int api = data.readInt32(); - status_t res = connect(api); + uint32_t outWidth, outHeight, outTransform; + status_t res = connect(api, + &outWidth, &outHeight, &outTransform); + reply->writeInt32(outWidth); + reply->writeInt32(outHeight); + reply->writeInt32(outTransform); reply->writeInt32(res); return NO_ERROR; } break; diff --git a/libs/gui/SurfaceTexture.cpp b/libs/gui/SurfaceTexture.cpp index 1a036ee57c..4afca68849 100644 --- a/libs/gui/SurfaceTexture.cpp +++ b/libs/gui/SurfaceTexture.cpp @@ -104,7 +104,7 @@ SurfaceTexture::SurfaceTexture(GLuint tex, bool allowSynchronousMode) : SurfaceTexture::~SurfaceTexture() { LOGV("SurfaceTexture::~SurfaceTexture"); - freeAllBuffers(); + freeAllBuffersLocked(); } status_t SurfaceTexture::setBufferCountServerLocked(int bufferCount) { @@ -154,7 +154,10 @@ status_t SurfaceTexture::setBufferCount(int bufferCount) { LOGE("setBufferCount: SurfaceTexture has been abandoned!"); return NO_INIT; } - + if (mConnectedApi == NO_CONNECTED_API) { + LOGE("setBufferCount: SurfaceTexture is not connected!"); + return NO_INIT; + } if (bufferCount > NUM_BUFFER_SLOTS) { LOGE("setBufferCount: bufferCount larger than slots available"); return BAD_VALUE; @@ -185,7 +188,7 @@ status_t SurfaceTexture::setBufferCount(int bufferCount) { // here we're guaranteed that the client doesn't have dequeued buffers // and will release all of its buffer references. - freeAllBuffers(); + freeAllBuffersLocked(); mBufferCount = bufferCount; mClientBufferCount = bufferCount; mCurrentTexture = INVALID_BUFFER_SLOT; @@ -214,6 +217,10 @@ status_t SurfaceTexture::requestBuffer(int slot, sp<GraphicBuffer>* buf) { LOGE("requestBuffer: SurfaceTexture has been abandoned!"); return NO_INIT; } + if (mConnectedApi == NO_CONNECTED_API) { + LOGE("requestBuffer: SurfaceTexture is not connected!"); + return NO_INIT; + } if (slot < 0 || mBufferCount <= slot) { LOGE("requestBuffer: slot index out of range [0, %d]: %d", mBufferCount, slot); @@ -228,11 +235,6 @@ 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; @@ -246,10 +248,19 @@ status_t SurfaceTexture::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h, int dequeuedCount = 0; bool tryAgain = true; while (tryAgain) { + if (mAbandoned) { + LOGE("dequeueBuffer: SurfaceTexture has been abandoned!"); + return NO_INIT; + } + if (mConnectedApi == NO_CONNECTED_API) { + LOGE("dequeueBuffer: SurfaceTexture is not connected!"); + return NO_INIT; + } + // We need to wait for the FIFO to drain if the number of buffer // needs to change. // - // The condition "number of buffer needs to change" is true if + // The condition "number of buffers needs to change" is true if // - the client doesn't care about how many buffers there are // - AND the actual number of buffer is different from what was // set in the last setBufferCountServer() @@ -261,31 +272,24 @@ status_t SurfaceTexture::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h, // As long as this condition is true AND the FIFO is not empty, we // wait on mDequeueCondition. - int minBufferCountNeeded = mSynchronousMode ? + const int minBufferCountNeeded = mSynchronousMode ? MIN_SYNC_BUFFER_SLOTS : MIN_ASYNC_BUFFER_SLOTS; - if (!mClientBufferCount && + const bool numberOfBuffersNeedsToChange = !mClientBufferCount && ((mServerBufferCount != mBufferCount) || - (mServerBufferCount < minBufferCountNeeded))) { + (mServerBufferCount < minBufferCountNeeded)); + + if (!mQueue.isEmpty() && numberOfBuffersNeedsToChange) { // 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; + mDequeueCondition.wait(mMutex); + // NOTE: we continue here because we need to reevaluate our + // whole state (eg: we could be abandoned or disconnected) + continue; } - - if (!mClientBufferCount && - ((mServerBufferCount != mBufferCount) || - (mServerBufferCount < minBufferCountNeeded))) { + if (numberOfBuffersNeedsToChange) { // here we're guaranteed that mQueue is empty - freeAllBuffers(); + freeAllBuffersLocked(); mBufferCount = mServerBufferCount; if (mBufferCount < minBufferCountNeeded) mBufferCount = minBufferCountNeeded; @@ -414,9 +418,9 @@ status_t SurfaceTexture::setSynchronousMode(bool enabled) { if (!enabled) { // going to asynchronous mode, drain the queue - while (mSynchronousMode != enabled && !mQueue.isEmpty()) { - mDequeueCondition.wait(mMutex); - } + err = drainQueueLocked(); + if (err != NO_ERROR) + return err; } if (mSynchronousMode != enabled) { @@ -442,6 +446,10 @@ status_t SurfaceTexture::queueBuffer(int buf, int64_t timestamp, LOGE("queueBuffer: SurfaceTexture has been abandoned!"); return NO_INIT; } + if (mConnectedApi == NO_CONNECTED_API) { + LOGE("queueBuffer: SurfaceTexture is not connected!"); + return NO_INIT; + } if (buf < 0 || buf >= mBufferCount) { LOGE("queueBuffer: slot index out of range [0, %d]: %d", mBufferCount, buf); @@ -512,6 +520,10 @@ void SurfaceTexture::cancelBuffer(int buf) { LOGW("cancelBuffer: SurfaceTexture has been abandoned!"); return; } + if (mConnectedApi == NO_CONNECTED_API) { + LOGE("cancelBuffer: SurfaceTexture is not connected!"); + return; + } if (buf < 0 || buf >= mBufferCount) { LOGE("cancelBuffer: slot index out of range [0, %d]: %d", @@ -533,6 +545,10 @@ status_t SurfaceTexture::setCrop(const Rect& crop) { LOGE("setCrop: SurfaceTexture has been abandoned!"); return NO_INIT; } + if (mConnectedApi == NO_CONNECTED_API) { + LOGE("setCrop: SurfaceTexture is not connected!"); + return NO_INIT; + } mNextCrop = crop; return OK; } @@ -544,11 +560,16 @@ status_t SurfaceTexture::setTransform(uint32_t transform) { LOGE("setTransform: SurfaceTexture has been abandoned!"); return NO_INIT; } + if (mConnectedApi == NO_CONNECTED_API) { + LOGE("setTransform: SurfaceTexture is not connected!"); + return NO_INIT; + } mNextTransform = transform; return OK; } -status_t SurfaceTexture::connect(int api) { +status_t SurfaceTexture::connect(int api, + uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransform) { LOGV("SurfaceTexture::connect(this=%p, %d)", this, api); Mutex::Autolock lock(mMutex); @@ -569,6 +590,9 @@ status_t SurfaceTexture::connect(int api) { err = -EINVAL; } else { mConnectedApi = api; + *outWidth = mDefaultWidth; + *outHeight = mDefaultHeight; + *outTransform = 0; } break; default: @@ -594,7 +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; + mDequeueCondition.signal(); } else { LOGE("disconnect: connected to another api (cur=%d, req=%d)", mConnectedApi, api); @@ -628,6 +654,11 @@ status_t SurfaceTexture::updateTexImage() { LOGV("SurfaceTexture::updateTexImage"); Mutex::Autolock lock(mMutex); + if (mAbandoned) { + LOGE("calling updateTexImage() on an abandoned SurfaceTexture"); + return NO_INIT; + } + // In asynchronous mode the list is guaranteed to be one buffer // deep, while in synchronous mode we use the oldest buffer. if (!mQueue.empty()) { @@ -638,6 +669,10 @@ status_t SurfaceTexture::updateTexImage() { 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; + } image = createImage(dpy, mSlots[buf].mGraphicBuffer); mSlots[buf].mEglImage = image; mSlots[buf].mEglDisplay = dpy; @@ -827,18 +862,66 @@ void SurfaceTexture::setFrameAvailableListener( mFrameAvailableListener = listener; } -void SurfaceTexture::freeAllBuffers() { +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); } } } +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, const sp<GraphicBuffer>& graphicBuffer) { EGLClientBuffer cbuf = (EGLClientBuffer)graphicBuffer->getNativeBuffer(); @@ -908,9 +991,10 @@ int SurfaceTexture::query(int what, int* outValue) void SurfaceTexture::abandon() { Mutex::Autolock lock(mMutex); - freeAllBuffers(); + mQueue.clear(); mAbandoned = true; mCurrentTextureBuf.clear(); + freeAllBuffersLocked(); mDequeueCondition.signal(); } @@ -966,13 +1050,24 @@ void SurfaceTexture::dump(String8& result, const char* prefix, for (int i=0 ; i<mBufferCount ; i++) { const BufferSlot& slot(mSlots[i]); snprintf(buffer, SIZE, - "%s%s[%02d] state=%-8s, crop=[%d,%d,%d,%d], transform=0x%02x, " - "timestamp=%lld\n", - prefix, (i==mCurrentTexture)?">":" ", i, stateName(slot.mBufferState), + "%s%s[%02d] " + "state=%-8s, crop=[%d,%d,%d,%d], " + "transform=0x%02x, timestamp=%lld", + prefix, (i==mCurrentTexture)?">":" ", i, + stateName(slot.mBufferState), slot.mCrop.left, slot.mCrop.top, slot.mCrop.right, slot.mCrop.bottom, slot.mTransform, slot.mTimestamp ); result.append(buffer); + + const sp<GraphicBuffer>& buf(slot.mGraphicBuffer); + if (buf != NULL) { + snprintf(buffer, SIZE, + ", %p [%4ux%4u:%4u,%3X]", + buf->handle, buf->width, buf->height, buf->stride, buf->format); + result.append(buffer); + } + result.append("\n"); } } diff --git a/libs/gui/SurfaceTextureClient.cpp b/libs/gui/SurfaceTextureClient.cpp index d1037defc4..e91be84c48 100644 --- a/libs/gui/SurfaceTextureClient.cpp +++ b/libs/gui/SurfaceTextureClient.cpp @@ -385,7 +385,8 @@ int SurfaceTextureClient::dispatchUnlockAndPost(va_list args) { int SurfaceTextureClient::connect(int api) { LOGV("SurfaceTextureClient::connect"); Mutex::Autolock lock(mMutex); - int err = mSurfaceTexture->connect(api); + int err = mSurfaceTexture->connect(api, + &mDefaultWidth, &mDefaultHeight, &mTransformHint); if (!err && api == NATIVE_WINDOW_API_CPU) { mConnectedToCpu = true; } diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 383c0454ce..505c843a64 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -533,7 +533,7 @@ void Layer::dump(String8& result, char* buffer, size_t SIZE) const } snprintf(buffer, SIZE, " " - "format=%2d, activeBuffer=[%3ux%3u:%3u,%3u]," + "format=%2d, activeBuffer=[%4ux%4u:%4u,%3X]," " freezeLock=%p, queued-frames=%d\n", mFormat, w0, h0, s0,f0, getFreezeLock().get(), mQueuedFrames); diff --git a/services/surfaceflinger/SurfaceTextureLayer.cpp b/services/surfaceflinger/SurfaceTextureLayer.cpp index 5973e76118..79cd0c3140 100644 --- a/services/surfaceflinger/SurfaceTextureLayer.cpp +++ b/services/surfaceflinger/SurfaceTextureLayer.cpp @@ -86,9 +86,19 @@ status_t SurfaceTextureLayer::dequeueBuffer(int *buf, return res; } -status_t SurfaceTextureLayer::connect(int api) { - status_t err = SurfaceTexture::connect(api); +status_t SurfaceTextureLayer::connect(int api, + uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransform) { + status_t err = SurfaceTexture::connect(api, + outWidth, outHeight, outTransform); if (err == NO_ERROR) { + sp<Layer> layer(mLayer.promote()); + if (layer != NULL) { + uint32_t orientation = layer->getOrientation(); + if (orientation & Transform::ROT_INVALID) { + orientation = 0; + } + *outTransform = orientation; + } switch(api) { case NATIVE_WINDOW_API_MEDIA: case NATIVE_WINDOW_API_CAMERA: diff --git a/services/surfaceflinger/SurfaceTextureLayer.h b/services/surfaceflinger/SurfaceTextureLayer.h index 5d328b7c6a..9508524af8 100644 --- a/services/surfaceflinger/SurfaceTextureLayer.h +++ b/services/surfaceflinger/SurfaceTextureLayer.h @@ -51,7 +51,8 @@ protected: virtual status_t dequeueBuffer(int *buf, uint32_t w, uint32_t h, uint32_t format, uint32_t usage); - virtual status_t connect(int api); + virtual status_t connect(int api, + uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransform); }; // --------------------------------------------------------------------------- |