summaryrefslogtreecommitdiffstats
path: root/libs
diff options
context:
space:
mode:
authorMathias Agopian <mathias@google.com>2013-07-23 17:28:53 -0700
committerMathias Agopian <mathias@google.com>2013-07-26 18:45:02 -0700
commitad678e18b66f495efa78dc3b9ab99b579945c9e2 (patch)
treeb1158419e04a0417533618592ef58d5fa23490b5 /libs
parentbf5b849ec7b2050e1fe05aebb3914823da6a0d07 (diff)
downloadframeworks_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.cpp28
-rw-r--r--libs/gui/GLConsumer.cpp95
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 [?]