summaryrefslogtreecommitdiffstats
path: root/libs/gui/SurfaceTexture.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'libs/gui/SurfaceTexture.cpp')
-rw-r--r--libs/gui/SurfaceTexture.cpp70
1 files changed, 38 insertions, 32 deletions
diff --git a/libs/gui/SurfaceTexture.cpp b/libs/gui/SurfaceTexture.cpp
index 3cecdb4..886a3fb 100644
--- a/libs/gui/SurfaceTexture.cpp
+++ b/libs/gui/SurfaceTexture.cpp
@@ -78,7 +78,7 @@ static float mtxRot270[16] = {
static void mtxMul(float out[16], const float a[16], const float b[16]);
-SurfaceTexture::SurfaceTexture(GLuint tex) :
+SurfaceTexture::SurfaceTexture(GLuint tex, bool allowSynchronousMode) :
mDefaultWidth(1),
mDefaultHeight(1),
mPixelFormat(PIXEL_FORMAT_RGBA_8888),
@@ -91,7 +91,8 @@ SurfaceTexture::SurfaceTexture(GLuint tex) :
mCurrentTimestamp(0),
mNextTransform(0),
mTexName(tex),
- mSynchronousMode(false) {
+ mSynchronousMode(false),
+ mAllowSynchronousMode(allowSynchronousMode) {
LOGV("SurfaceTexture::SurfaceTexture");
sp<ISurfaceComposer> composer(ComposerService::getComposerService());
mGraphicBufferAlloc = composer->createGraphicBufferAlloc();
@@ -147,6 +148,11 @@ status_t SurfaceTexture::setBufferCount(int bufferCount) {
LOGV("SurfaceTexture::setBufferCount");
Mutex::Autolock lock(mMutex);
+ if (bufferCount > NUM_BUFFER_SLOTS) {
+ LOGE("setBufferCount: bufferCount larger than slots available");
+ return BAD_VALUE;
+ }
+
// Error out if the user has dequeued buffers
for (int i=0 ; i<mBufferCount ; i++) {
if (mSlots[i].mBufferState == BufferSlot::DEQUEUED) {
@@ -207,7 +213,7 @@ status_t SurfaceTexture::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h,
uint32_t format, uint32_t usage) {
LOGV("SurfaceTexture::dequeueBuffer");
- if ((w && !h) || (!w & h)) {
+ if ((w && !h) || (!w && h)) {
LOGE("dequeueBuffer: invalid size: w=%u, h=%u", w, h);
return BAD_VALUE;
}
@@ -346,11 +352,13 @@ status_t SurfaceTexture::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h,
((uint32_t(buffer->usage) & usage) != usage))
{
usage |= GraphicBuffer::USAGE_HW_TEXTURE;
+ status_t error;
sp<GraphicBuffer> graphicBuffer(
- mGraphicBufferAlloc->createGraphicBuffer(w, h, format, usage));
+ mGraphicBufferAlloc->createGraphicBuffer(
+ w, h, format, usage, &error));
if (graphicBuffer == 0) {
LOGE("dequeueBuffer: SurfaceComposer::createGraphicBuffer failed");
- return NO_MEMORY;
+ return error;
}
if (updateFormat) {
mPixelFormat = format;
@@ -371,6 +379,9 @@ status_t SurfaceTexture::setSynchronousMode(bool enabled) {
Mutex::Autolock lock(mMutex);
status_t err = OK;
+ if (!mAllowSynchronousMode && enabled)
+ return err;
+
if (!enabled) {
// going to asynchronous mode, drain the queue
while (mSynchronousMode != enabled && !mQueue.isEmpty()) {
@@ -413,17 +424,22 @@ status_t SurfaceTexture::queueBuffer(int buf, int64_t timestamp) {
return -EINVAL;
}
- if (mQueue.empty()) {
- listener = mFrameAvailableListener;
- }
-
if (mSynchronousMode) {
- // in synchronous mode we queue all buffers in a FIFO
+ // In synchronous mode we queue all buffers in a FIFO.
mQueue.push_back(buf);
+
+ // Synchronous mode always signals that an additional frame should
+ // be consumed.
+ listener = mFrameAvailableListener;
} else {
- // in asynchronous mode we only keep the most recent buffer
+ // In asynchronous mode we only keep the most recent buffer.
if (mQueue.empty()) {
mQueue.push_back(buf);
+
+ // Asynchronous mode only signals that a frame should be
+ // consumed if no previous frame was pending. If a frame were
+ // pending then the consumer would have already been notified.
+ listener = mFrameAvailableListener;
} else {
Fifo::iterator front(mQueue.begin());
// buffer currently queued is freed
@@ -479,24 +495,14 @@ status_t SurfaceTexture::setTransform(uint32_t transform) {
status_t SurfaceTexture::updateTexImage() {
LOGV("SurfaceTexture::updateTexImage");
-
Mutex::Autolock lock(mMutex);
- int buf = mCurrentTexture;
+ // In asynchronous mode the list is guaranteed to be one buffer
+ // deep, while in synchronous mode we use the oldest buffer.
if (!mQueue.empty()) {
- // in asynchronous mode the list is guaranteed to be one buffer deep,
- // while in synchronous mode we use the oldest buffer
Fifo::iterator front(mQueue.begin());
- buf = *front;
- mQueue.erase(front);
- if (mQueue.isEmpty()) {
- mDequeueCondition.signal();
- }
- }
+ int buf = *front;
- // Initially both mCurrentTexture and buf are INVALID_BUFFER_SLOT,
- // so this check will fail until a buffer gets queued.
- if (mCurrentTexture != buf) {
// Update the GL texture object.
EGLImageKHR image = mSlots[buf].mEglImage;
if (image == EGL_NO_IMAGE_KHR) {
@@ -534,7 +540,7 @@ status_t SurfaceTexture::updateTexImage() {
}
if (mCurrentTexture != INVALID_BUFFER_SLOT) {
- // the current buffer becomes FREE if it was still in the queued
+ // The current buffer becomes FREE if it was still in the queued
// state. If it has already been given to the client
// (synchronous mode), then it stays in DEQUEUED state.
if (mSlots[mCurrentTexture].mBufferState == BufferSlot::QUEUED)
@@ -549,17 +555,17 @@ status_t SurfaceTexture::updateTexImage() {
mCurrentTransform = mSlots[buf].mTransform;
mCurrentTimestamp = mSlots[buf].mTimestamp;
computeCurrentTransformMatrix();
+
+ // Now that we've passed the point at which failures can happen,
+ // it's safe to remove the buffer from the front of the queue.
+ mQueue.erase(front);
mDequeueCondition.signal();
} else {
// We always bind the texture even if we don't update its contents.
glBindTexture(mCurrentTextureTarget, mTexName);
}
- return OK;
-}
-size_t SurfaceTexture::getQueuedCount() const {
- Mutex::Autolock lock(mMutex);
- return mQueue.size();
+ return OK;
}
bool SurfaceTexture::isExternalFormat(uint32_t format)
@@ -700,10 +706,10 @@ nsecs_t SurfaceTexture::getTimestamp() {
}
void SurfaceTexture::setFrameAvailableListener(
- const sp<FrameAvailableListener>& l) {
+ const sp<FrameAvailableListener>& listener) {
LOGV("SurfaceTexture::setFrameAvailableListener");
Mutex::Autolock lock(mMutex);
- mFrameAvailableListener = l;
+ mFrameAvailableListener = listener;
}
sp<IBinder> SurfaceTexture::getAllocator() {