diff options
Diffstat (limited to 'libs/gui/SurfaceTexture.cpp')
-rw-r--r-- | libs/gui/SurfaceTexture.cpp | 501 |
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]) { |