diff options
author | Mathias Agopian <mathias@google.com> | 2013-07-23 17:28:53 -0700 |
---|---|---|
committer | Mathias Agopian <mathias@google.com> | 2013-07-26 18:45:02 -0700 |
commit | ad678e18b66f495efa78dc3b9ab99b579945c9e2 (patch) | |
tree | b1158419e04a0417533618592ef58d5fa23490b5 /libs | |
parent | bf5b849ec7b2050e1fe05aebb3914823da6a0d07 (diff) | |
download | frameworks_native-ad678e18b66f495efa78dc3b9ab99b579945c9e2.zip frameworks_native-ad678e18b66f495efa78dc3b9ab99b579945c9e2.tar.gz frameworks_native-ad678e18b66f495efa78dc3b9ab99b579945c9e2.tar.bz2 |
single buffer mode for BufferQueue
Bug: 9891035
Change-Id: Id1ab5f911a6dc4c1d8235e65775b3d3635231ad4
Diffstat (limited to 'libs')
-rw-r--r-- | libs/gui/BufferQueue.cpp | 28 | ||||
-rw-r--r-- | libs/gui/GLConsumer.cpp | 95 |
2 files changed, 113 insertions, 10 deletions
diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp index 95ba095..45488ff 100644 --- a/libs/gui/BufferQueue.cpp +++ b/libs/gui/BufferQueue.cpp @@ -72,6 +72,7 @@ BufferQueue::BufferQueue(const sp<IGraphicBufferAlloc>& allocator) : mOverrideMaxBufferCount(0), mConsumerControlledByApp(false), mDequeueBufferCannotBlock(false), + mUseAsyncBuffer(true), mConnectedApi(NO_CONNECTED_API), mAbandoned(false), mFrameCounter(0), @@ -100,7 +101,8 @@ BufferQueue::~BufferQueue() { } status_t BufferQueue::setDefaultMaxBufferCountLocked(int count) { - if (count < 2 || count > NUM_BUFFER_SLOTS) + const int minBufferCount = mUseAsyncBuffer ? 2 : 1; + if (count < minBufferCount || count > NUM_BUFFER_SLOTS) return BAD_VALUE; mDefaultMaxBufferCount = count; @@ -1033,6 +1035,17 @@ status_t BufferQueue::setDefaultMaxBufferCount(int bufferCount) { return setDefaultMaxBufferCountLocked(bufferCount); } +status_t BufferQueue::disableAsyncBuffer() { + ATRACE_CALL(); + Mutex::Autolock lock(mMutex); + if (mConsumerListener != NULL) { + ST_LOGE("disableAsyncBuffer: consumer already connected!"); + return INVALID_OPERATION; + } + mUseAsyncBuffer = false; + return NO_ERROR; +} + status_t BufferQueue::setMaxAcquiredBufferCount(int maxAcquiredBuffers) { ATRACE_CALL(); Mutex::Autolock lock(mMutex); @@ -1049,8 +1062,17 @@ status_t BufferQueue::setMaxAcquiredBufferCount(int maxAcquiredBuffers) { } int BufferQueue::getMinUndequeuedBufferCount(bool async) const { - return (mDequeueBufferCannotBlock || async) ? - mMaxAcquiredBufferCount+1 : mMaxAcquiredBufferCount; + // if dequeueBuffer is allowed to error out, we don't have to + // add an extra buffer. + if (!mUseAsyncBuffer) + return mMaxAcquiredBufferCount; + + // we're in async mode, or we want to prevent the app to + // deadlock itself, we throw-in an extra buffer to guarantee it. + if (mDequeueBufferCannotBlock || async) + return mMaxAcquiredBufferCount+1; + + return mMaxAcquiredBufferCount; } int BufferQueue::getMinMaxBufferCountLocked(bool async) const { diff --git a/libs/gui/GLConsumer.cpp b/libs/gui/GLConsumer.cpp index bd1671d..b8a3d28 100644 --- a/libs/gui/GLConsumer.cpp +++ b/libs/gui/GLConsumer.cpp @@ -25,6 +25,7 @@ #include <EGL/eglext.h> #include <GLES2/gl2.h> #include <GLES2/gl2ext.h> +#include <cutils/compiler.h> #include <hardware/hardware.h> @@ -49,6 +50,12 @@ namespace android { #define ST_LOGW(x, ...) ALOGW("[%s] "x, mName.string(), ##__VA_ARGS__) #define ST_LOGE(x, ...) ALOGE("[%s] "x, mName.string(), ##__VA_ARGS__) +static const struct { + size_t width, height; + char const* bits; +} kDebugData = { 11, 8, + "__X_____X_____X___X_____XXXXXXX___XX_XXX_XX_XXXXXXXXXXXX_XXXXXXX_XX_X_____X_X___XX_XX___" }; + // Transform matrices static float mtxIdentity[16] = { 1, 0, 0, 0, @@ -154,7 +161,7 @@ status_t GLConsumer::updateTexImage() { } // Release the previous buffer. - err = releaseAndUpdateLocked(item); + err = updateAndReleaseLocked(item); if (err != NO_ERROR) { // We always bind the texture. glBindTexture(mTexTarget, mTexName); @@ -165,6 +172,80 @@ status_t GLConsumer::updateTexImage() { return bindTextureImageLocked(); } + +status_t GLConsumer::releaseTexImage() { + ATRACE_CALL(); + ST_LOGV("releaseTexImage"); + Mutex::Autolock lock(mMutex); + + if (mAbandoned) { + ST_LOGE("releaseTexImage: GLConsumer is abandoned!"); + return NO_INIT; + } + + // Make sure the EGL state is the same as in previous calls. + status_t err = checkAndUpdateEglStateLocked(); + if (err != NO_ERROR) { + return err; + } + + // Update the GLConsumer state. + int buf = mCurrentTexture; + if (buf != BufferQueue::INVALID_BUFFER_SLOT) { + + ST_LOGV("releaseTexImage:(slot=%d", buf); + + // Do whatever sync ops we need to do before releasing the slot. + err = syncForReleaseLocked(mEglDisplay); + if (err != NO_ERROR) { + ST_LOGE("syncForReleaseLocked failed (slot=%d), err=%d", buf, err); + return err; + } + + err = releaseBufferLocked(buf, mSlots[buf].mGraphicBuffer, + mEglDisplay, EGL_NO_SYNC_KHR); + if (err < NO_ERROR) { + ST_LOGE("releaseTexImage: failed to release buffer: %s (%d)", + strerror(-err), err); + return err; + } + + if (CC_UNLIKELY(mReleasedTexImageBuffer == NULL)) { + // The first time, create the debug texture in case the application + // continues to use it. + sp<GraphicBuffer> buffer = new GraphicBuffer(11, 8, PIXEL_FORMAT_RGBA_8888, + GraphicBuffer::USAGE_SW_WRITE_RARELY); + uint32_t* bits; + buffer->lock(GraphicBuffer::USAGE_SW_WRITE_RARELY, reinterpret_cast<void**>(&bits)); + size_t w = buffer->getStride(); + size_t h = buffer->getHeight(); + memset(bits, 0, w*h*4); + for (size_t y=0 ; y<kDebugData.height ; y++) { + for (size_t x=0 ; x<kDebugData.width ; x++) { + bits[x] = (kDebugData.bits[y*11+x] == 'X') ? 0xFF000000 : 0xFFFFFFFF; + } + bits += w; + } + buffer->unlock(); + mReleasedTexImageBuffer = buffer; + } + + mCurrentTexture = BufferQueue::INVALID_BUFFER_SLOT; + mCurrentTextureBuf = mReleasedTexImageBuffer; + mCurrentCrop.makeInvalid(); + mCurrentTransform = 0; + mCurrentScalingMode = NATIVE_WINDOW_SCALING_MODE_FREEZE; + mCurrentTimestamp = 0; + mCurrentFence = Fence::NO_FENCE; + + // bind a dummy texture + glBindTexture(mTexTarget, mTexName); + bindUnslottedBufferLocked(mEglDisplay); + } + + return NO_ERROR; +} + status_t GLConsumer::acquireBufferLocked(BufferQueue::BufferItem *item, nsecs_t presentWhen) { status_t err = ConsumerBase::acquireBufferLocked(item, presentWhen); @@ -202,12 +283,12 @@ status_t GLConsumer::releaseBufferLocked(int buf, return err; } -status_t GLConsumer::releaseAndUpdateLocked(const BufferQueue::BufferItem& item) +status_t GLConsumer::updateAndReleaseLocked(const BufferQueue::BufferItem& item) { status_t err = NO_ERROR; if (!mAttached) { - ST_LOGE("releaseAndUpdate: GLConsumer is not attached to an OpenGL " + ST_LOGE("updateAndRelease: GLConsumer is not attached to an OpenGL " "ES context"); return INVALID_OPERATION; } @@ -230,7 +311,7 @@ status_t GLConsumer::releaseAndUpdateLocked(const BufferQueue::BufferItem& item) if (mEglSlots[buf].mEglImage == EGL_NO_IMAGE_KHR) { EGLImageKHR image = createImage(mEglDisplay, mSlots[buf].mGraphicBuffer); if (image == EGL_NO_IMAGE_KHR) { - ST_LOGW("releaseAndUpdate: unable to createImage on display=%p slot=%d", + ST_LOGW("updateAndRelease: unable to createImage on display=%p slot=%d", mEglDisplay, buf); return UNKNOWN_ERROR; } @@ -249,7 +330,7 @@ status_t GLConsumer::releaseAndUpdateLocked(const BufferQueue::BufferItem& item) return err; } - ST_LOGV("releaseAndUpdate: (slot=%d buf=%p) -> (slot=%d buf=%p)", + ST_LOGV("updateAndRelease: (slot=%d buf=%p) -> (slot=%d buf=%p)", mCurrentTexture, mCurrentTextureBuf != NULL ? mCurrentTextureBuf->handle : 0, buf, mSlots[buf].mGraphicBuffer->handle); @@ -259,8 +340,8 @@ status_t GLConsumer::releaseAndUpdateLocked(const BufferQueue::BufferItem& item) status_t status = releaseBufferLocked( mCurrentTexture, mCurrentTextureBuf, mEglDisplay, mEglSlots[mCurrentTexture].mEglFence); - if (status != NO_ERROR && status != BufferQueue::STALE_BUFFER_SLOT) { - ST_LOGE("releaseAndUpdate: failed to release buffer: %s (%d)", + if (status < NO_ERROR) { + ST_LOGE("updateAndRelease: failed to release buffer: %s (%d)", strerror(-status), status); err = status; // keep going, with error raised [?] |