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.cpp501
1 files changed, 272 insertions, 229 deletions
diff --git a/libs/gui/SurfaceTexture.cpp b/libs/gui/SurfaceTexture.cpp
index 55be4bc..b4dfb5e 100644
--- a/libs/gui/SurfaceTexture.cpp
+++ b/libs/gui/SurfaceTexture.cpp
@@ -39,14 +39,28 @@
#include <utils/String8.h>
#include <utils/Trace.h>
-// This compile option makes SurfaceTexture use the EGL_KHR_fence_sync extension
-// to synchronize access to the buffers. It will cause dequeueBuffer to stall,
-// waiting for the GL reads for the buffer being dequeued to complete before
-// allowing the buffer to be dequeued.
+// This compile option makes SurfaceTexture use the
+// EGL_ANDROID_native_fence_sync extension to create Android native fences to
+// signal when all GLES reads for a given buffer have completed. It is not
+// compatible with using the EGL_KHR_fence_sync extension for the same
+// purpose.
+#ifdef USE_NATIVE_FENCE_SYNC
#ifdef USE_FENCE_SYNC
-#ifdef ALLOW_DEQUEUE_CURRENT_BUFFER
-#error "USE_FENCE_SYNC and ALLOW_DEQUEUE_CURRENT_BUFFER are incompatible"
+#error "USE_NATIVE_FENCE_SYNC and USE_FENCE_SYNC are incompatible"
#endif
+static const bool useNativeFenceSync = true;
+#else
+static const bool useNativeFenceSync = false;
+#endif
+
+// This compile option makes SurfaceTexture use the EGL_ANDROID_sync_wait
+// extension to insert server-side waits into the GLES command stream. This
+// feature requires the EGL_ANDROID_native_fence_sync and
+// EGL_ANDROID_wait_sync extensions.
+#ifdef USE_WAIT_SYNC
+static const bool useWaitSync = true;
+#else
+static const bool useWaitSync = false;
#endif
// Macros for including the SurfaceTexture name in log messages
@@ -98,14 +112,10 @@ static float mtxRot270[16] = {
static void mtxMul(float out[16], const float a[16], const float b[16]);
-// Get an ID that's unique within this process.
-static int32_t createProcessUniqueId() {
- static volatile int32_t globalCounter = 0;
- return android_atomic_inc(&globalCounter);
-}
SurfaceTexture::SurfaceTexture(GLuint tex, bool allowSynchronousMode,
GLenum texTarget, bool useFenceSync, const sp<BufferQueue> &bufferQueue) :
+ ConsumerBase(bufferQueue == 0 ? new BufferQueue(allowSynchronousMode) : bufferQueue),
mCurrentTransform(0),
mCurrentTimestamp(0),
mFilteringEnabled(true),
@@ -118,52 +128,20 @@ SurfaceTexture::SurfaceTexture(GLuint tex, bool allowSynchronousMode,
mTexTarget(texTarget),
mEglDisplay(EGL_NO_DISPLAY),
mEglContext(EGL_NO_CONTEXT),
- mAbandoned(false),
mCurrentTexture(BufferQueue::INVALID_BUFFER_SLOT),
mAttached(true)
{
- // Choose a name using the PID and a process-unique ID.
- mName = String8::format("unnamed-%d-%d", getpid(), createProcessUniqueId());
ST_LOGV("SurfaceTexture");
- if (bufferQueue == 0) {
- ST_LOGV("Creating a new BufferQueue");
- mBufferQueue = new BufferQueue(allowSynchronousMode);
- }
- else {
- mBufferQueue = bufferQueue;
- }
memcpy(mCurrentTransformMatrix, mtxIdentity,
sizeof(mCurrentTransformMatrix));
- // Note that we can't create an sp<...>(this) in a ctor that will not keep a
- // reference once the ctor ends, as that would cause the refcount of 'this'
- // dropping to 0 at the end of the ctor. Since all we need is a wp<...>
- // that's what we create.
- wp<BufferQueue::ConsumerListener> listener;
- sp<BufferQueue::ConsumerListener> proxy;
- listener = static_cast<BufferQueue::ConsumerListener*>(this);
- proxy = new BufferQueue::ProxyConsumerListener(listener);
-
- status_t err = mBufferQueue->consumerConnect(proxy);
- if (err != NO_ERROR) {
- ST_LOGE("SurfaceTexture: error connecting to BufferQueue: %s (%d)",
- strerror(-err), err);
- } else {
- mBufferQueue->setConsumerName(mName);
- mBufferQueue->setConsumerUsageBits(DEFAULT_USAGE_FLAGS);
- }
-}
-
-SurfaceTexture::~SurfaceTexture() {
- ST_LOGV("~SurfaceTexture");
-
- abandon();
+ mBufferQueue->setConsumerUsageBits(DEFAULT_USAGE_FLAGS);
}
-status_t SurfaceTexture::setBufferCountServer(int bufferCount) {
+status_t SurfaceTexture::setDefaultMaxBufferCount(int bufferCount) {
Mutex::Autolock lock(mMutex);
- return mBufferQueue->setBufferCountServer(bufferCount);
+ return mBufferQueue->setDefaultMaxBufferCount(bufferCount);
}
@@ -176,10 +154,48 @@ status_t SurfaceTexture::setDefaultBufferSize(uint32_t w, uint32_t h)
}
status_t SurfaceTexture::updateTexImage() {
- return SurfaceTexture::updateTexImage(NULL);
+ return SurfaceTexture::updateTexImage(NULL, false);
+}
+
+status_t SurfaceTexture::acquireBufferLocked(BufferQueue::BufferItem *item) {
+ status_t err = ConsumerBase::acquireBufferLocked(item);
+ if (err != NO_ERROR) {
+ return err;
+ }
+
+ int slot = item->mBuf;
+ if (item->mGraphicBuffer != NULL) {
+ if (mEglSlots[slot].mEglImage != EGL_NO_IMAGE_KHR) {
+ eglDestroyImageKHR(mEglDisplay, mEglSlots[slot].mEglImage);
+ mEglSlots[slot].mEglImage = EGL_NO_IMAGE_KHR;
+ }
+ }
+
+ // Update the GL texture object. We may have to do this even when
+ // item.mGraphicBuffer == NULL, if we destroyed the EGLImage when
+ // detaching from a context but the buffer has not been re-allocated.
+ if (mEglSlots[slot].mEglImage == EGL_NO_IMAGE_KHR) {
+ EGLImageKHR image = createImage(mEglDisplay, mSlots[slot].mGraphicBuffer);
+ if (image == EGL_NO_IMAGE_KHR) {
+ return UNKNOWN_ERROR;
+ }
+ mEglSlots[slot].mEglImage = image;
+ }
+
+ return NO_ERROR;
}
-status_t SurfaceTexture::updateTexImage(BufferRejecter* rejecter) {
+status_t SurfaceTexture::releaseBufferLocked(int buf, EGLDisplay display,
+ EGLSyncKHR eglFence) {
+ status_t err = ConsumerBase::releaseBufferLocked(buf, mEglDisplay,
+ eglFence);
+
+ mEglSlots[buf].mEglFence = EGL_NO_SYNC_KHR;
+
+ return err;
+}
+
+status_t SurfaceTexture::updateTexImage(BufferRejecter* rejecter, bool skipSync) {
ATRACE_CALL();
ST_LOGV("updateTexImage");
Mutex::Autolock lock(mMutex);
@@ -219,106 +235,84 @@ status_t SurfaceTexture::updateTexImage(BufferRejecter* rejecter) {
// In asynchronous mode the list is guaranteed to be one buffer
// deep, while in synchronous mode we use the oldest buffer.
- err = mBufferQueue->acquireBuffer(&item);
+ err = acquireBufferLocked(&item);
if (err == NO_ERROR) {
int buf = item.mBuf;
- // This buffer was newly allocated, so we need to clean up on our side
- if (item.mGraphicBuffer != NULL) {
- mEGLSlots[buf].mGraphicBuffer = 0;
- if (mEGLSlots[buf].mEglImage != EGL_NO_IMAGE_KHR) {
- eglDestroyImageKHR(dpy, mEGLSlots[buf].mEglImage);
- mEGLSlots[buf].mEglImage = EGL_NO_IMAGE_KHR;
- }
- mEGLSlots[buf].mGraphicBuffer = item.mGraphicBuffer;
- }
// we call the rejecter here, in case the caller has a reason to
// not accept this buffer. this is used by SurfaceFlinger to
// reject buffers which have the wrong size
- if (rejecter && rejecter->reject(mEGLSlots[buf].mGraphicBuffer, item)) {
- mBufferQueue->releaseBuffer(buf, dpy, mEGLSlots[buf].mFence);
- mEGLSlots[buf].mFence = EGL_NO_SYNC_KHR;
+ if (rejecter && rejecter->reject(mSlots[buf].mGraphicBuffer, item)) {
+ releaseBufferLocked(buf, dpy, EGL_NO_SYNC_KHR);
glBindTexture(mTexTarget, mTexName);
return NO_ERROR;
}
- // Update the GL texture object. We may have to do this even when
- // item.mGraphicBuffer == NULL, if we destroyed the EGLImage when
- // detaching from a context but the buffer has not been re-allocated.
- EGLImageKHR image = mEGLSlots[buf].mEglImage;
- if (image == EGL_NO_IMAGE_KHR) {
- if (mEGLSlots[buf].mGraphicBuffer == NULL) {
- ST_LOGE("updateTexImage: buffer at slot %d is null", buf);
- err = BAD_VALUE;
- } else {
- image = createImage(dpy, mEGLSlots[buf].mGraphicBuffer);
- mEGLSlots[buf].mEglImage = image;
- if (image == EGL_NO_IMAGE_KHR) {
- // NOTE: if dpy was invalid, createImage() is guaranteed to
- // fail. so we'd end up here.
- err = UNKNOWN_ERROR;
- }
- }
+ GLint error;
+ while ((error = glGetError()) != GL_NO_ERROR) {
+ ST_LOGW("updateTexImage: clearing GL error: %#04x", error);
}
- if (err == NO_ERROR) {
- GLint error;
- while ((error = glGetError()) != GL_NO_ERROR) {
- ST_LOGW("updateTexImage: clearing GL error: %#04x", error);
- }
-
- glBindTexture(mTexTarget, mTexName);
- glEGLImageTargetTexture2DOES(mTexTarget, (GLeglImageOES)image);
+ EGLImageKHR image = mEglSlots[buf].mEglImage;
+ glBindTexture(mTexTarget, mTexName);
+ glEGLImageTargetTexture2DOES(mTexTarget, (GLeglImageOES)image);
- while ((error = glGetError()) != GL_NO_ERROR) {
- ST_LOGE("updateTexImage: error binding external texture image %p "
- "(slot %d): %#04x", image, buf, error);
- err = UNKNOWN_ERROR;
- }
+ while ((error = glGetError()) != GL_NO_ERROR) {
+ ST_LOGE("updateTexImage: error binding external texture image %p "
+ "(slot %d): %#04x", image, buf, error);
+ err = UNKNOWN_ERROR;
+ }
- if (err == NO_ERROR) {
- err = syncForReleaseLocked(dpy);
- }
+ if (err == NO_ERROR) {
+ err = syncForReleaseLocked(dpy);
}
if (err != NO_ERROR) {
// Release the buffer we just acquired. It's not safe to
// release the old buffer, so instead we just drop the new frame.
- mBufferQueue->releaseBuffer(buf, dpy, mEGLSlots[buf].mFence);
- mEGLSlots[buf].mFence = EGL_NO_SYNC_KHR;
+ releaseBufferLocked(buf, dpy, EGL_NO_SYNC_KHR);
return err;
}
ST_LOGV("updateTexImage: (slot=%d buf=%p) -> (slot=%d buf=%p)",
mCurrentTexture,
mCurrentTextureBuf != NULL ? mCurrentTextureBuf->handle : 0,
- buf, item.mGraphicBuffer != NULL ? item.mGraphicBuffer->handle : 0);
+ buf, mSlots[buf].mGraphicBuffer->handle);
// release old buffer
if (mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) {
- status_t status = mBufferQueue->releaseBuffer(mCurrentTexture, dpy,
- mEGLSlots[mCurrentTexture].mFence);
-
- mEGLSlots[mCurrentTexture].mFence = EGL_NO_SYNC_KHR;
- if (status == BufferQueue::STALE_BUFFER_SLOT) {
- freeBufferLocked(mCurrentTexture);
- } else if (status != NO_ERROR) {
- ST_LOGE("updateTexImage: released invalid buffer");
+ status_t status = releaseBufferLocked(mCurrentTexture, dpy,
+ mEglSlots[mCurrentTexture].mEglFence);
+ if (status != NO_ERROR && status != BufferQueue::STALE_BUFFER_SLOT) {
+ ST_LOGE("updateTexImage: failed to release buffer: %s (%d)",
+ strerror(-status), status);
err = status;
}
}
// Update the SurfaceTexture state.
mCurrentTexture = buf;
- mCurrentTextureBuf = mEGLSlots[buf].mGraphicBuffer;
+ mCurrentTextureBuf = mSlots[buf].mGraphicBuffer;
mCurrentCrop = item.mCrop;
mCurrentTransform = item.mTransform;
mCurrentScalingMode = item.mScalingMode;
mCurrentTimestamp = item.mTimestamp;
- computeCurrentTransformMatrix();
+ mCurrentFence = item.mFence;
+ if (!skipSync) {
+ // SurfaceFlinger needs to lazily perform GLES synchronization
+ // only when it's actually going to use GLES for compositing.
+ // Eventually SurfaceFlinger should have its own consumer class,
+ // but for now we'll just hack it in to SurfaceTexture.
+ // SurfaceFlinger is responsible for calling doGLFenceWait before
+ // texturing from this SurfaceTexture.
+ doGLFenceWaitLocked();
+ }
+ computeCurrentTransformMatrixLocked();
} else {
if (err < 0) {
- ALOGE("updateTexImage failed on acquire %d", err);
+ ST_LOGE("updateTexImage: acquire failed: %s (%d)",
+ strerror(-err), err);
+ return err;
}
// We always bind the texture even if we don't update its contents.
glBindTexture(mTexTarget, mTexName);
@@ -328,6 +322,17 @@ status_t SurfaceTexture::updateTexImage(BufferRejecter* rejecter) {
return err;
}
+void SurfaceTexture::setReleaseFence(int fenceFd) {
+ sp<Fence> fence(new Fence(fenceFd));
+ if (fenceFd == -1 || mCurrentTexture == BufferQueue::INVALID_BUFFER_SLOT)
+ return;
+ status_t err = addReleaseFence(mCurrentTexture, fence);
+ if (err != OK) {
+ ST_LOGE("setReleaseFence: failed to add the fence: %s (%d)",
+ strerror(-err), err);
+ }
+}
+
status_t SurfaceTexture::detachFromContext() {
ATRACE_CALL();
ST_LOGV("detachFromContext");
@@ -371,10 +376,10 @@ status_t SurfaceTexture::detachFromContext() {
// SurfaceTexture gets attached to a new OpenGL ES context (and thus gets a
// new EGLDisplay).
for (int i =0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
- EGLImageKHR img = mEGLSlots[i].mEglImage;
+ EGLImageKHR img = mEglSlots[i].mEglImage;
if (img != EGL_NO_IMAGE_KHR) {
eglDestroyImageKHR(mEglDisplay, img);
- mEGLSlots[i].mEglImage = EGL_NO_IMAGE_KHR;
+ mEglSlots[i].mEglImage = EGL_NO_IMAGE_KHR;
}
}
@@ -461,36 +466,61 @@ status_t SurfaceTexture::attachToContext(GLuint tex) {
status_t SurfaceTexture::syncForReleaseLocked(EGLDisplay dpy) {
ST_LOGV("syncForReleaseLocked");
- if (mUseFenceSync && mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) {
- EGLSyncKHR fence = mEGLSlots[mCurrentTexture].mFence;
- if (fence != EGL_NO_SYNC_KHR) {
- // There is already a fence for the current slot. We need to wait
- // on that before replacing it with another fence to ensure that all
- // outstanding buffer accesses have completed before the producer
- // accesses it.
- EGLint result = eglClientWaitSyncKHR(dpy, fence, 0, 1000000000);
- if (result == EGL_FALSE) {
- ST_LOGE("syncForReleaseLocked: error waiting for previous "
- "fence: %#x", eglGetError());
+ if (mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) {
+ if (useNativeFenceSync) {
+ EGLSyncKHR sync = eglCreateSyncKHR(dpy,
+ EGL_SYNC_NATIVE_FENCE_ANDROID, NULL);
+ if (sync == EGL_NO_SYNC_KHR) {
+ ST_LOGE("syncForReleaseLocked: error creating EGL fence: %#x",
+ eglGetError());
return UNKNOWN_ERROR;
- } else if (result == EGL_TIMEOUT_EXPIRED_KHR) {
- ST_LOGE("syncForReleaseLocked: timeout waiting for previous "
- "fence");
- return TIMED_OUT;
}
- eglDestroySyncKHR(dpy, fence);
- }
+ glFlush();
+ int fenceFd = eglDupNativeFenceFDANDROID(dpy, sync);
+ eglDestroySyncKHR(dpy, sync);
+ if (fenceFd == EGL_NO_NATIVE_FENCE_FD_ANDROID) {
+ ST_LOGE("syncForReleaseLocked: error dup'ing native fence "
+ "fd: %#x", eglGetError());
+ return UNKNOWN_ERROR;
+ }
+ sp<Fence> fence(new Fence(fenceFd));
+ status_t err = addReleaseFenceLocked(mCurrentTexture, fence);
+ if (err != OK) {
+ ST_LOGE("syncForReleaseLocked: error adding release fence: "
+ "%s (%d)", strerror(-err), err);
+ return err;
+ }
+ } else if (mUseFenceSync) {
+ EGLSyncKHR fence = mEglSlots[mCurrentTexture].mEglFence;
+ if (fence != EGL_NO_SYNC_KHR) {
+ // There is already a fence for the current slot. We need to
+ // wait on that before replacing it with another fence to
+ // ensure that all outstanding buffer accesses have completed
+ // before the producer accesses it.
+ EGLint result = eglClientWaitSyncKHR(dpy, fence, 0, 1000000000);
+ if (result == EGL_FALSE) {
+ ST_LOGE("syncForReleaseLocked: error waiting for previous "
+ "fence: %#x", eglGetError());
+ return UNKNOWN_ERROR;
+ } else if (result == EGL_TIMEOUT_EXPIRED_KHR) {
+ ST_LOGE("syncForReleaseLocked: timeout waiting for previous "
+ "fence");
+ return TIMED_OUT;
+ }
+ eglDestroySyncKHR(dpy, fence);
+ }
- // Create a fence for the outstanding accesses in the current OpenGL ES
- // context.
- fence = eglCreateSyncKHR(dpy, EGL_SYNC_FENCE_KHR, NULL);
- if (fence == EGL_NO_SYNC_KHR) {
- ST_LOGE("syncForReleaseLocked: error creating fence: %#x",
- eglGetError());
- return UNKNOWN_ERROR;
+ // Create a fence for the outstanding accesses in the current
+ // OpenGL ES context.
+ fence = eglCreateSyncKHR(dpy, EGL_SYNC_FENCE_KHR, NULL);
+ if (fence == EGL_NO_SYNC_KHR) {
+ ST_LOGE("syncForReleaseLocked: error creating fence: %#x",
+ eglGetError());
+ return UNKNOWN_ERROR;
+ }
+ glFlush();
+ mEglSlots[mCurrentTexture].mEglFence = fence;
}
- glFlush();
- mEGLSlots[mCurrentTexture].mFence = fence;
}
return OK;
@@ -526,15 +556,24 @@ void SurfaceTexture::getTransformMatrix(float mtx[16]) {
void SurfaceTexture::setFilteringEnabled(bool enabled) {
Mutex::Autolock lock(mMutex);
+ if (mAbandoned) {
+ ST_LOGE("setFilteringEnabled: SurfaceTexture is abandoned!");
+ return;
+ }
bool needsRecompute = mFilteringEnabled != enabled;
mFilteringEnabled = enabled;
- if (needsRecompute) {
- computeCurrentTransformMatrix();
+
+ if (needsRecompute && mCurrentTextureBuf==NULL) {
+ ST_LOGD("setFilteringEnabled called with mCurrentTextureBuf == NULL");
+ }
+
+ if (needsRecompute && mCurrentTextureBuf != NULL) {
+ computeCurrentTransformMatrixLocked();
}
}
-void SurfaceTexture::computeCurrentTransformMatrix() {
- ST_LOGV("computeCurrentTransformMatrix");
+void SurfaceTexture::computeCurrentTransformMatrixLocked() {
+ ST_LOGV("computeCurrentTransformMatrixLocked");
float xform[16];
for (int i = 0; i < 16; i++) {
@@ -563,6 +602,11 @@ void SurfaceTexture::computeCurrentTransformMatrix() {
}
sp<GraphicBuffer>& buf(mCurrentTextureBuf);
+
+ if (buf == NULL) {
+ ST_LOGD("computeCurrentTransformMatrixLocked: mCurrentTextureBuf is NULL");
+ }
+
Rect cropRect = mCurrentCrop;
float tx = 0.0f, ty = 0.0f, sx = 1.0f, sy = 1.0f;
float bufferWidth = buf->getWidth();
@@ -587,11 +631,13 @@ void SurfaceTexture::computeCurrentTransformMatrix() {
// We know there's no subsampling of any channels, so we
// only need to shrink by a half a pixel.
shrinkAmount = 0.5;
+ break;
default:
// If we don't recognize the format, we must assume the
// worst case (that we care about), which is YUV420.
shrinkAmount = 1.0;
+ break;
}
}
@@ -631,13 +677,6 @@ nsecs_t SurfaceTexture::getTimestamp() {
return mCurrentTimestamp;
}
-void SurfaceTexture::setFrameAvailableListener(
- const sp<FrameAvailableListener>& listener) {
- ST_LOGV("setFrameAvailableListener");
- Mutex::Autolock lock(mMutex);
- mFrameAvailableListener = listener;
-}
-
EGLImageKHR SurfaceTexture::createImage(EGLDisplay dpy,
const sp<GraphicBuffer>& graphicBuffer) {
EGLClientBuffer cbuf = (EGLClientBuffer)graphicBuffer->getNativeBuffer();
@@ -705,6 +744,76 @@ uint32_t SurfaceTexture::getCurrentScalingMode() const {
return mCurrentScalingMode;
}
+sp<Fence> SurfaceTexture::getCurrentFence() const {
+ Mutex::Autolock lock(mMutex);
+ return mCurrentFence;
+}
+
+status_t SurfaceTexture::doGLFenceWait() const {
+ Mutex::Autolock lock(mMutex);
+ return doGLFenceWaitLocked();
+}
+
+status_t SurfaceTexture::doGLFenceWaitLocked() const {
+
+ EGLDisplay dpy = eglGetCurrentDisplay();
+ EGLContext ctx = eglGetCurrentContext();
+
+ if (mEglDisplay != dpy || mEglDisplay == EGL_NO_DISPLAY) {
+ ST_LOGE("doGLFenceWait: invalid current EGLDisplay");
+ return INVALID_OPERATION;
+ }
+
+ if (mEglContext != ctx || mEglContext == EGL_NO_CONTEXT) {
+ ST_LOGE("doGLFenceWait: invalid current EGLContext");
+ return INVALID_OPERATION;
+ }
+
+ if (mCurrentFence != NULL) {
+ if (useWaitSync) {
+ // Create an EGLSyncKHR from the current fence.
+ int fenceFd = mCurrentFence->dup();
+ if (fenceFd == -1) {
+ ST_LOGE("doGLFenceWait: error dup'ing fence fd: %d", errno);
+ return -errno;
+ }
+ EGLint attribs[] = {
+ EGL_SYNC_NATIVE_FENCE_FD_ANDROID, fenceFd,
+ EGL_NONE
+ };
+ EGLSyncKHR sync = eglCreateSyncKHR(dpy,
+ EGL_SYNC_NATIVE_FENCE_ANDROID, attribs);
+ if (sync == EGL_NO_SYNC_KHR) {
+ close(fenceFd);
+ ST_LOGE("doGLFenceWait: error creating EGL fence: %#x",
+ eglGetError());
+ return UNKNOWN_ERROR;
+ }
+
+ // XXX: The spec draft is inconsistent as to whether this should
+ // return an EGLint or void. Ignore the return value for now, as
+ // it's not strictly needed.
+ eglWaitSyncANDROID(dpy, sync, 0);
+ EGLint eglErr = eglGetError();
+ eglDestroySyncKHR(dpy, sync);
+ if (eglErr != EGL_SUCCESS) {
+ ST_LOGE("doGLFenceWait: error waiting for EGL fence: %#x",
+ eglErr);
+ return UNKNOWN_ERROR;
+ }
+ } else {
+ status_t err = mCurrentFence->waitForever(1000,
+ "SurfaceTexture::doGLFenceWaitLocked");
+ if (err != NO_ERROR) {
+ ST_LOGE("doGLFenceWait: error waiting for fence: %d", err);
+ return err;
+ }
+ }
+ }
+
+ return NO_ERROR;
+}
+
bool SurfaceTexture::isSynchronousMode() const {
Mutex::Autolock lock(mMutex);
return mBufferQueue->isSynchronousMode();
@@ -712,35 +821,22 @@ bool SurfaceTexture::isSynchronousMode() const {
void SurfaceTexture::freeBufferLocked(int slotIndex) {
ST_LOGV("freeBufferLocked: slotIndex=%d", slotIndex);
- mEGLSlots[slotIndex].mGraphicBuffer = 0;
if (slotIndex == mCurrentTexture) {
mCurrentTexture = BufferQueue::INVALID_BUFFER_SLOT;
}
- EGLImageKHR img = mEGLSlots[slotIndex].mEglImage;
+ EGLImageKHR img = mEglSlots[slotIndex].mEglImage;
if (img != EGL_NO_IMAGE_KHR) {
ST_LOGV("destroying EGLImage dpy=%p img=%p", mEglDisplay, img);
eglDestroyImageKHR(mEglDisplay, img);
}
- mEGLSlots[slotIndex].mEglImage = EGL_NO_IMAGE_KHR;
+ mEglSlots[slotIndex].mEglImage = EGL_NO_IMAGE_KHR;
+ ConsumerBase::freeBufferLocked(slotIndex);
}
-void SurfaceTexture::abandon() {
- ST_LOGV("abandon");
- Mutex::Autolock lock(mMutex);
-
- if (!mAbandoned) {
- mAbandoned = true;
- mCurrentTextureBuf.clear();
-
- // destroy all egl buffers
- for (int i =0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
- freeBufferLocked(i);
- }
-
- // disconnect from the BufferQueue
- mBufferQueue->consumerDisconnect();
- mBufferQueue.clear();
- }
+void SurfaceTexture::abandonLocked() {
+ ST_LOGV("abandonLocked");
+ mCurrentTextureBuf.clear();
+ ConsumerBase::abandonLocked();
}
void SurfaceTexture::setName(const String8& name) {
@@ -772,71 +868,18 @@ status_t SurfaceTexture::setSynchronousMode(bool enabled) {
return mBufferQueue->setSynchronousMode(enabled);
}
-// Used for refactoring, should not be in final interface
-sp<BufferQueue> SurfaceTexture::getBufferQueue() const {
- Mutex::Autolock lock(mMutex);
- return mBufferQueue;
-}
-
-void SurfaceTexture::onFrameAvailable() {
- ST_LOGV("onFrameAvailable");
-
- sp<FrameAvailableListener> listener;
- { // scope for the lock
- Mutex::Autolock lock(mMutex);
- listener = mFrameAvailableListener;
- }
-
- if (listener != NULL) {
- ST_LOGV("actually calling onFrameAvailable");
- listener->onFrameAvailable();
- }
-}
-
-void SurfaceTexture::onBuffersReleased() {
- ST_LOGV("onBuffersReleased");
-
- Mutex::Autolock lock(mMutex);
-
- if (mAbandoned) {
- // Nothing to do if we're already abandoned.
- return;
- }
-
- uint32_t mask = 0;
- mBufferQueue->getReleasedBuffers(&mask);
- for (int i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
- if (mask & (1 << i)) {
- freeBufferLocked(i);
- }
- }
-}
-
-void SurfaceTexture::dump(String8& result) const
-{
- char buffer[1024];
- dump(result, "", buffer, 1024);
-}
-
-void SurfaceTexture::dump(String8& result, const char* prefix,
- char* buffer, size_t SIZE) const
+void SurfaceTexture::dumpLocked(String8& result, const char* prefix,
+ char* buffer, size_t size) const
{
- Mutex::Autolock _l(mMutex);
- snprintf(buffer, SIZE, "%smTexName=%d, mAbandoned=%d\n", prefix, mTexName,
- int(mAbandoned));
- result.append(buffer);
-
- snprintf(buffer, SIZE,
- "%snext : {crop=[%d,%d,%d,%d], transform=0x%02x, current=%d}\n",
- prefix, mCurrentCrop.left,
- mCurrentCrop.top, mCurrentCrop.right, mCurrentCrop.bottom,
- mCurrentTransform, mCurrentTexture
- );
+ snprintf(buffer, size,
+ "%smTexName=%d mCurrentTexture=%d\n"
+ "%smCurrentCrop=[%d,%d,%d,%d] mCurrentTransform=%#x\n",
+ prefix, mTexName, mCurrentTexture, prefix, mCurrentCrop.left,
+ mCurrentCrop.top, mCurrentCrop.right, mCurrentCrop.bottom,
+ mCurrentTransform);
result.append(buffer);
- if (!mAbandoned) {
- mBufferQueue->dump(result, prefix, buffer, SIZE);
- }
+ ConsumerBase::dumpLocked(result, prefix, buffer, size);
}
static void mtxMul(float out[16], const float a[16], const float b[16]) {