diff options
Diffstat (limited to 'libs/gui')
24 files changed, 2298 insertions, 1869 deletions
diff --git a/libs/gui/Android.mk b/libs/gui/Android.mk index d970a33..c080f47 100644 --- a/libs/gui/Android.mk +++ b/libs/gui/Android.mk @@ -3,29 +3,30 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES:= \ BitTube.cpp \ + BufferItemConsumer.cpp \ BufferQueue.cpp \ ConsumerBase.cpp \ + CpuConsumer.cpp \ DisplayEventReceiver.cpp \ + DummyConsumer.cpp \ + GLConsumer.cpp \ + GraphicBufferAlloc.cpp \ + GuiConfig.cpp \ IDisplayEventConnection.cpp \ + IGraphicBufferAlloc.cpp \ + IGraphicBufferProducer.cpp \ ISensorEventConnection.cpp \ ISensorServer.cpp \ - ISurfaceTexture.cpp \ - Sensor.cpp \ - SensorEventQueue.cpp \ - SensorManager.cpp \ - SurfaceTexture.cpp \ - SurfaceTextureClient.cpp \ ISurfaceComposer.cpp \ - ISurface.cpp \ ISurfaceComposerClient.cpp \ - IGraphicBufferAlloc.cpp \ LayerState.cpp \ + Sensor.cpp \ + SensorEventQueue.cpp \ + SensorManager.cpp \ Surface.cpp \ + SurfaceControl.cpp \ SurfaceComposerClient.cpp \ - DummyConsumer.cpp \ - CpuConsumer.cpp \ - BufferItemConsumer.cpp \ - GuiConfig.cpp + SyncFeatures.cpp \ LOCAL_SHARED_LIBRARIES := \ libbinder \ @@ -35,27 +36,16 @@ LOCAL_SHARED_LIBRARIES := \ libsync \ libui \ libutils \ + liblog LOCAL_MODULE:= libgui -ifeq ($(TARGET_BOARD_PLATFORM), omap4) - LOCAL_CFLAGS += -DUSE_FENCE_SYNC +ifeq ($(TARGET_BOARD_PLATFORM), tegra) + LOCAL_CFLAGS += -DDONT_USE_FENCE_SYNC endif -ifeq ($(TARGET_BOARD_PLATFORM), s5pc110) - LOCAL_CFLAGS += -DUSE_FENCE_SYNC -endif -ifeq ($(TARGET_BOARD_PLATFORM), exynos5) - LOCAL_CFLAGS += -DUSE_NATIVE_FENCE_SYNC - LOCAL_CFLAGS += -DUSE_WAIT_SYNC -endif -ifneq ($(filter generic%,$(TARGET_DEVICE)),) - # Emulator build - LOCAL_CFLAGS += -DUSE_FENCE_SYNC -endif - -ifeq ($(TARGET_BOARD_PLATFORM), msm8960) - LOCAL_CFLAGS += -DUSE_NATIVE_FENCE_SYNC +ifeq ($(TARGET_BOARD_PLATFORM), tegra3) + LOCAL_CFLAGS += -DDONT_USE_FENCE_SYNC endif include $(BUILD_SHARED_LIBRARY) diff --git a/libs/gui/BufferItemConsumer.cpp b/libs/gui/BufferItemConsumer.cpp index 5079883..7db1b84 100644 --- a/libs/gui/BufferItemConsumer.cpp +++ b/libs/gui/BufferItemConsumer.cpp @@ -62,8 +62,8 @@ status_t BufferItemConsumer::acquireBuffer(BufferItem *item, bool waitForFence) return err; } - if (waitForFence && item->mFence.get()) { - err = item->mFence->waitForever(1000, "BufferItemConsumer::acquireBuffer"); + if (waitForFence) { + err = item->mFence->waitForever("BufferItemConsumer::acquireBuffer"); if (err != OK) { BI_LOGE("Failed to wait for fence of acquired buffer: %s (%d)", strerror(-err), err); @@ -93,4 +93,14 @@ status_t BufferItemConsumer::releaseBuffer(const BufferItem &item, return err; } +status_t BufferItemConsumer::setDefaultBufferSize(uint32_t w, uint32_t h) { + Mutex::Autolock _l(mMutex); + return mBufferQueue->setDefaultBufferSize(w, h); +} + +status_t BufferItemConsumer::setDefaultBufferFormat(uint32_t defaultFormat) { + Mutex::Autolock _l(mMutex); + return mBufferQueue->setDefaultBufferFormat(defaultFormat); +} + } // namespace android diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp index 086e298..b4c7231 100644 --- a/libs/gui/BufferQueue.cpp +++ b/libs/gui/BufferQueue.cpp @@ -29,7 +29,6 @@ #include <private/gui/ComposerService.h> #include <utils/Log.h> -#include <gui/SurfaceTexture.h> #include <utils/Trace.h> // Macros for including the BufferQueue name in log messages @@ -107,7 +106,7 @@ status_t BufferQueue::setDefaultMaxBufferCountLocked(int count) { mDefaultMaxBufferCount = count; mDequeueCondition.broadcast(); - return OK; + return NO_ERROR; } bool BufferQueue::isSynchronousMode() const { @@ -123,20 +122,20 @@ void BufferQueue::setConsumerName(const String8& name) { status_t BufferQueue::setDefaultBufferFormat(uint32_t defaultFormat) { Mutex::Autolock lock(mMutex); mDefaultBufferFormat = defaultFormat; - return OK; + return NO_ERROR; } status_t BufferQueue::setConsumerUsageBits(uint32_t usage) { Mutex::Autolock lock(mMutex); mConsumerUsageBits = usage; - return OK; + return NO_ERROR; } status_t BufferQueue::setTransformHint(uint32_t hint) { ST_LOGV("setTransformHint: %02x", hint); Mutex::Autolock lock(mMutex); mTransformHint = hint; - return OK; + return NO_ERROR; } status_t BufferQueue::setBufferCount(int bufferCount) { @@ -147,11 +146,12 @@ status_t BufferQueue::setBufferCount(int bufferCount) { Mutex::Autolock lock(mMutex); if (mAbandoned) { - ST_LOGE("setBufferCount: SurfaceTexture has been abandoned!"); + ST_LOGE("setBufferCount: BufferQueue has been abandoned!"); return NO_INIT; } if (bufferCount > NUM_BUFFER_SLOTS) { - ST_LOGE("setBufferCount: bufferCount larger than slots available"); + ST_LOGE("setBufferCount: bufferCount too large (max %d)", + NUM_BUFFER_SLOTS); return BAD_VALUE; } @@ -168,7 +168,7 @@ status_t BufferQueue::setBufferCount(int bufferCount) { if (bufferCount == 0) { mOverrideMaxBufferCount = 0; mDequeueCondition.broadcast(); - return OK; + return NO_ERROR; } if (bufferCount < minBufferSlots) { @@ -192,7 +192,7 @@ status_t BufferQueue::setBufferCount(int bufferCount) { listener->onBuffersReleased(); } - return OK; + return NO_ERROR; } int BufferQueue::query(int what, int* outValue) @@ -201,7 +201,7 @@ int BufferQueue::query(int what, int* outValue) Mutex::Autolock lock(mMutex); if (mAbandoned) { - ST_LOGE("query: SurfaceTexture has been abandoned!"); + ST_LOGE("query: BufferQueue has been abandoned!"); return NO_INIT; } @@ -234,7 +234,7 @@ status_t BufferQueue::requestBuffer(int slot, sp<GraphicBuffer>* buf) { ST_LOGV("requestBuffer: slot=%d", slot); Mutex::Autolock lock(mMutex); if (mAbandoned) { - ST_LOGE("requestBuffer: SurfaceTexture has been abandoned!"); + ST_LOGE("requestBuffer: BufferQueue has been abandoned!"); return NO_INIT; } int maxBufferCount = getMaxBufferCountLocked(); @@ -255,7 +255,7 @@ status_t BufferQueue::requestBuffer(int slot, sp<GraphicBuffer>* buf) { return NO_ERROR; } -status_t BufferQueue::dequeueBuffer(int *outBuf, sp<Fence>& outFence, +status_t BufferQueue::dequeueBuffer(int *outBuf, sp<Fence>* outFence, uint32_t w, uint32_t h, uint32_t format, uint32_t usage) { ATRACE_CALL(); ST_LOGV("dequeueBuffer: w=%d h=%d fmt=%#x usage=%#x", w, h, format, usage); @@ -283,7 +283,7 @@ status_t BufferQueue::dequeueBuffer(int *outBuf, sp<Fence>& outFence, bool tryAgain = true; while (tryAgain) { if (mAbandoned) { - ST_LOGE("dequeueBuffer: SurfaceTexture has been abandoned!"); + ST_LOGE("dequeueBuffer: BufferQueue has been abandoned!"); return NO_INIT; } @@ -295,7 +295,7 @@ status_t BufferQueue::dequeueBuffer(int *outBuf, sp<Fence>& outFence, assert(mSlots[i].mBufferState == BufferSlot::FREE); if (mSlots[i].mGraphicBuffer != NULL) { freeBufferLocked(i); - returnFlags |= ISurfaceTexture::RELEASE_ALL_BUFFERS; + returnFlags |= IGraphicBufferProducer::RELEASE_ALL_BUFFERS; } } @@ -373,8 +373,6 @@ status_t BufferQueue::dequeueBuffer(int *outBuf, sp<Fence>& outFence, h = mDefaultHeight; } - // buffer is now in DEQUEUED (but can also be current at the same time, - // if we're in synchronous mode) mSlots[buf].mBufferState = BufferSlot::DEQUEUED; const sp<GraphicBuffer>& buffer(mSlots[buf].mGraphicBuffer); @@ -388,20 +386,20 @@ status_t BufferQueue::dequeueBuffer(int *outBuf, sp<Fence>& outFence, mSlots[buf].mGraphicBuffer = NULL; mSlots[buf].mRequestBufferCalled = false; mSlots[buf].mEglFence = EGL_NO_SYNC_KHR; - mSlots[buf].mFence.clear(); + mSlots[buf].mFence = Fence::NO_FENCE; mSlots[buf].mEglDisplay = EGL_NO_DISPLAY; - returnFlags |= ISurfaceTexture::BUFFER_NEEDS_REALLOCATION; + returnFlags |= IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION; } dpy = mSlots[buf].mEglDisplay; eglFence = mSlots[buf].mEglFence; - outFence = mSlots[buf].mFence; + *outFence = mSlots[buf].mFence; mSlots[buf].mEglFence = EGL_NO_SYNC_KHR; - mSlots[buf].mFence.clear(); + mSlots[buf].mFence = Fence::NO_FENCE; } // end lock scope - if (returnFlags & ISurfaceTexture::BUFFER_NEEDS_REALLOCATION) { + if (returnFlags & IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION) { status_t error; sp<GraphicBuffer> graphicBuffer( mGraphicBufferAlloc->createGraphicBuffer( @@ -416,7 +414,7 @@ status_t BufferQueue::dequeueBuffer(int *outBuf, sp<Fence>& outFence, Mutex::Autolock lock(mMutex); if (mAbandoned) { - ST_LOGE("dequeueBuffer: SurfaceTexture has been abandoned!"); + ST_LOGE("dequeueBuffer: BufferQueue has been abandoned!"); return NO_INIT; } @@ -424,7 +422,6 @@ status_t BufferQueue::dequeueBuffer(int *outBuf, sp<Fence>& outFence, } } - if (eglFence != EGL_NO_SYNC_KHR) { EGLint result = eglClientWaitSyncKHR(dpy, eglFence, 0, 1000000000); // If something goes wrong, log the error, but return the buffer without @@ -450,7 +447,7 @@ status_t BufferQueue::setSynchronousMode(bool enabled) { Mutex::Autolock lock(mMutex); if (mAbandoned) { - ST_LOGE("setSynchronousMode: SurfaceTexture has been abandoned!"); + ST_LOGE("setSynchronousMode: BufferQueue has been abandoned!"); return NO_INIT; } @@ -489,6 +486,11 @@ status_t BufferQueue::queueBuffer(int buf, input.deflate(×tamp, &crop, &scalingMode, &transform, &fence); + if (fence == NULL) { + ST_LOGE("queueBuffer: fence is NULL"); + return BAD_VALUE; + } + ST_LOGV("queueBuffer: slot=%d time=%#llx crop=[%d,%d,%d,%d] tr=%#x " "scale=%s", buf, timestamp, crop.left, crop.top, crop.right, crop.bottom, @@ -499,7 +501,7 @@ status_t BufferQueue::queueBuffer(int buf, { // scope for the lock Mutex::Autolock lock(mMutex); if (mAbandoned) { - ST_LOGE("queueBuffer: SurfaceTexture has been abandoned!"); + ST_LOGE("queueBuffer: BufferQueue has been abandoned!"); return NO_INIT; } int maxBufferCount = getMaxBufferCountLocked(); @@ -586,10 +588,10 @@ status_t BufferQueue::queueBuffer(int buf, if (listener != 0) { listener->onFrameAvailable(); } - return OK; + return NO_ERROR; } -void BufferQueue::cancelBuffer(int buf, sp<Fence> fence) { +void BufferQueue::cancelBuffer(int buf, const sp<Fence>& fence) { ATRACE_CALL(); ST_LOGV("cancelBuffer: slot=%d", buf); Mutex::Autolock lock(mMutex); @@ -608,6 +610,9 @@ void BufferQueue::cancelBuffer(int buf, sp<Fence> fence) { ST_LOGE("cancelBuffer: slot %d is not owned by the client (state=%d)", buf, mSlots[buf].mBufferState); return; + } else if (fence == NULL) { + ST_LOGE("cancelBuffer: fence is NULL"); + return; } mSlots[buf].mBufferState = BufferSlot::FREE; mSlots[buf].mFrameNumber = 0; @@ -786,7 +791,7 @@ void BufferQueue::freeBufferLocked(int slot) { eglDestroySyncKHR(mSlots[slot].mEglDisplay, mSlots[slot].mEglFence); mSlots[slot].mEglFence = EGL_NO_SYNC_KHR; } - mSlots[slot].mFence.clear(); + mSlots[slot].mFence = Fence::NO_FENCE; } void BufferQueue::freeAllBuffersLocked() { @@ -844,7 +849,7 @@ status_t BufferQueue::acquireBuffer(BufferItem *buffer) { mSlots[buf].mAcquireCalled = true; mSlots[buf].mNeedsCleanupOnRelease = false; mSlots[buf].mBufferState = BufferSlot::ACQUIRED; - mSlots[buf].mFence.clear(); + mSlots[buf].mFence = Fence::NO_FENCE; mQueue.erase(front); mDequeueCondition.broadcast(); @@ -854,7 +859,7 @@ status_t BufferQueue::acquireBuffer(BufferItem *buffer) { return NO_BUFFER_AVAILABLE; } - return OK; + return NO_ERROR; } status_t BufferQueue::releaseBuffer(int buf, EGLDisplay display, @@ -864,8 +869,8 @@ status_t BufferQueue::releaseBuffer(int buf, EGLDisplay display, Mutex::Autolock _l(mMutex); - if (buf == INVALID_BUFFER_SLOT) { - return -EINVAL; + if (buf == INVALID_BUFFER_SLOT || fence == NULL) { + return BAD_VALUE; } mSlots[buf].mEglDisplay = display; @@ -885,7 +890,7 @@ status_t BufferQueue::releaseBuffer(int buf, EGLDisplay display, } mDequeueCondition.broadcast(); - return OK; + return NO_ERROR; } status_t BufferQueue::consumerConnect(const sp<ConsumerListener>& consumerListener) { @@ -896,10 +901,14 @@ status_t BufferQueue::consumerConnect(const sp<ConsumerListener>& consumerListen ST_LOGE("consumerConnect: BufferQueue has been abandoned!"); return NO_INIT; } + if (consumerListener == NULL) { + ST_LOGE("consumerConnect: consumerListener may not be NULL"); + return BAD_VALUE; + } mConsumerListener = consumerListener; - return OK; + return NO_ERROR; } status_t BufferQueue::consumerDisconnect() { @@ -916,7 +925,7 @@ status_t BufferQueue::consumerDisconnect() { mQueue.clear(); freeAllBuffersLocked(); mDequeueCondition.broadcast(); - return OK; + return NO_ERROR; } status_t BufferQueue::getReleasedBuffers(uint32_t* slotMask) { @@ -952,7 +961,7 @@ status_t BufferQueue::setDefaultBufferSize(uint32_t w, uint32_t h) Mutex::Autolock lock(mMutex); mDefaultWidth = w; mDefaultHeight = h; - return OK; + return NO_ERROR; } status_t BufferQueue::setDefaultMaxBufferCount(int bufferCount) { @@ -973,7 +982,7 @@ status_t BufferQueue::setMaxAcquiredBufferCount(int maxAcquiredBuffers) { return INVALID_OPERATION; } mMaxAcquiredBufferCount = maxAcquiredBuffers; - return OK; + return NO_ERROR; } void BufferQueue::freeAllBuffersExceptHeadLocked() { @@ -991,7 +1000,7 @@ void BufferQueue::freeAllBuffersExceptHeadLocked() { } status_t BufferQueue::drainQueueLocked() { - while (mSynchronousMode && !mQueue.isEmpty()) { + while (mSynchronousMode && mQueue.size() > 1) { mDequeueCondition.wait(mMutex); if (mAbandoned) { ST_LOGE("drainQueueLocked: BufferQueue has been abandoned!"); @@ -1008,7 +1017,7 @@ status_t BufferQueue::drainQueueLocked() { status_t BufferQueue::drainQueueAndFreeBuffersLocked() { status_t err = drainQueueLocked(); if (err == NO_ERROR) { - if (mSynchronousMode) { + if (mQueue.empty()) { freeAllBuffersLocked(); } else { freeAllBuffersExceptHeadLocked(); diff --git a/libs/gui/ConsumerBase.cpp b/libs/gui/ConsumerBase.cpp index 624d7e0..4937b17 100644 --- a/libs/gui/ConsumerBase.cpp +++ b/libs/gui/ConsumerBase.cpp @@ -18,7 +18,6 @@ #define ATRACE_TAG ATRACE_TAG_GRAPHICS //#define LOG_NDEBUG 0 -#define GL_GLEXT_PROTOTYPES #define EGL_EGLEXT_PROTOTYPES #include <EGL/egl.h> @@ -69,7 +68,7 @@ ConsumerBase::ConsumerBase(const sp<BufferQueue>& bufferQueue) : status_t err = mBufferQueue->consumerConnect(proxy); if (err != NO_ERROR) { - CB_LOGE("SurfaceTexture: error connecting to BufferQueue: %s (%d)", + CB_LOGE("ConsumerBase: error connecting to BufferQueue: %s (%d)", strerror(-err), err); } else { mBufferQueue->setConsumerName(mName); @@ -77,14 +76,25 @@ ConsumerBase::ConsumerBase(const sp<BufferQueue>& bufferQueue) : } ConsumerBase::~ConsumerBase() { - CB_LOGV("~ConsumerBase"); + CB_LOGV("~ConsumerBase"); + Mutex::Autolock lock(mMutex); + + // Verify that abandon() has been called before we get here. This should + // be done by ConsumerBase::onLastStrongRef(), but it's possible for a + // derived class to override that method and not call + // ConsumerBase::onLastStrongRef(). + LOG_ALWAYS_FATAL_IF(!mAbandoned, "[%s] ~ConsumerBase was called, but the " + "consumer is not abandoned!", mName.string()); +} + +void ConsumerBase::onLastStrongRef(const void* id) { abandon(); } void ConsumerBase::freeBufferLocked(int slotIndex) { CB_LOGV("freeBufferLocked: slotIndex=%d", slotIndex); mSlots[slotIndex].mGraphicBuffer = 0; - mSlots[slotIndex].mFence = 0; + mSlots[slotIndex].mFence = Fence::NO_FENCE; } // Used for refactoring, should not be in final interface @@ -99,7 +109,7 @@ void ConsumerBase::onFrameAvailable() { sp<FrameAvailableListener> listener; { // scope for the lock Mutex::Autolock lock(mMutex); - listener = mFrameAvailableListener; + listener = mFrameAvailableListener.promote(); } if (listener != NULL) { @@ -148,7 +158,7 @@ void ConsumerBase::abandonLocked() { } void ConsumerBase::setFrameAvailableListener( - const sp<FrameAvailableListener>& listener) { + const wp<FrameAvailableListener>& listener) { CB_LOGV("setFrameAvailableListener"); Mutex::Autolock lock(mMutex); mFrameAvailableListener = listener; @@ -228,9 +238,9 @@ status_t ConsumerBase::releaseBufferLocked(int slot, EGLDisplay display, freeBufferLocked(slot); } - mSlots[slot].mFence.clear(); + mSlots[slot].mFence = Fence::NO_FENCE; return err; } -} // namespace android
\ No newline at end of file +} // namespace android diff --git a/libs/gui/CpuConsumer.cpp b/libs/gui/CpuConsumer.cpp index 710e1af..0543649 100644 --- a/libs/gui/CpuConsumer.cpp +++ b/libs/gui/CpuConsumer.cpp @@ -17,8 +17,9 @@ //#define LOG_NDEBUG 0 #define LOG_TAG "CpuConsumer" #define ATRACE_TAG ATRACE_TAG_GRAPHICS -#include <utils/Log.h> +#include <cutils/compiler.h> +#include <utils/Log.h> #include <gui/CpuConsumer.h> #define CC_LOGV(x, ...) ALOGV("[%s] "x, mName.string(), ##__VA_ARGS__) @@ -29,24 +30,25 @@ namespace android { -CpuConsumer::CpuConsumer(uint32_t maxLockedBuffers) : +CpuConsumer::CpuConsumer(uint32_t maxLockedBuffers, bool synchronousMode) : ConsumerBase(new BufferQueue(true) ), mMaxLockedBuffers(maxLockedBuffers), mCurrentLockedBuffers(0) { + // Create tracking entries for locked buffers + mAcquiredBuffers.insertAt(0, maxLockedBuffers); - for (int i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) { - mBufferPointers[i] = NULL; - } - - mBufferQueue->setSynchronousMode(true); + mBufferQueue->setSynchronousMode(synchronousMode); mBufferQueue->setConsumerUsageBits(GRALLOC_USAGE_SW_READ_OFTEN); mBufferQueue->setMaxAcquiredBufferCount(maxLockedBuffers); } CpuConsumer::~CpuConsumer() { + // ConsumerBase destructor does all the work. } + + void CpuConsumer::setName(const String8& name) { Mutex::Autolock _l(mMutex); mName = name; @@ -78,7 +80,7 @@ status_t CpuConsumer::lockNextBuffer(LockedBuffer *nativeBuffer) { int buf = b.mBuf; if (b.mFence.get()) { - err = b.mFence->waitForever(1000, "CpuConsumer::lockNextBuffer"); + err = b.mFence->waitForever("CpuConsumer::lockNextBuffer"); if (err != OK) { CC_LOGE("Failed to wait for fence of acquired buffer: %s (%d)", strerror(-err), err); @@ -86,22 +88,57 @@ status_t CpuConsumer::lockNextBuffer(LockedBuffer *nativeBuffer) { } } - err = mSlots[buf].mGraphicBuffer->lock( - GraphicBuffer::USAGE_SW_READ_OFTEN, - b.mCrop, - &mBufferPointers[buf]); + void *bufferPointer = NULL; + android_ycbcr ycbcr = android_ycbcr(); - if (mBufferPointers[buf] != NULL && err != OK) { - CC_LOGE("Unable to lock buffer for CPU reading: %s (%d)", strerror(-err), - err); - return err; + if (mSlots[buf].mGraphicBuffer->getPixelFormat() == + HAL_PIXEL_FORMAT_YCbCr_420_888) { + err = mSlots[buf].mGraphicBuffer->lockYCbCr( + GraphicBuffer::USAGE_SW_READ_OFTEN, + b.mCrop, + &ycbcr); + + if (err != OK) { + CC_LOGE("Unable to lock YCbCr buffer for CPU reading: %s (%d)", + strerror(-err), err); + return err; + } + bufferPointer = ycbcr.y; + } else { + err = mSlots[buf].mGraphicBuffer->lock( + GraphicBuffer::USAGE_SW_READ_OFTEN, + b.mCrop, + &bufferPointer); + + if (err != OK) { + CC_LOGE("Unable to lock buffer for CPU reading: %s (%d)", + strerror(-err), err); + return err; + } + } + + size_t lockedIdx = 0; + for (; lockedIdx < mMaxLockedBuffers; lockedIdx++) { + if (mAcquiredBuffers[lockedIdx].mSlot == + BufferQueue::INVALID_BUFFER_SLOT) { + break; + } } + assert(lockedIdx < mMaxLockedBuffers); - nativeBuffer->data = reinterpret_cast<uint8_t*>(mBufferPointers[buf]); + AcquiredBuffer &ab = mAcquiredBuffers.editItemAt(lockedIdx); + ab.mSlot = buf; + ab.mBufferPointer = bufferPointer; + ab.mGraphicBuffer = mSlots[buf].mGraphicBuffer; + + nativeBuffer->data = + reinterpret_cast<uint8_t*>(bufferPointer); nativeBuffer->width = mSlots[buf].mGraphicBuffer->getWidth(); nativeBuffer->height = mSlots[buf].mGraphicBuffer->getHeight(); nativeBuffer->format = mSlots[buf].mGraphicBuffer->getPixelFormat(); - nativeBuffer->stride = mSlots[buf].mGraphicBuffer->getStride(); + nativeBuffer->stride = (ycbcr.y != NULL) ? + ycbcr.ystride : + mSlots[buf].mGraphicBuffer->getStride(); nativeBuffer->crop = b.mCrop; nativeBuffer->transform = b.mTransform; @@ -109,6 +146,11 @@ status_t CpuConsumer::lockNextBuffer(LockedBuffer *nativeBuffer) { nativeBuffer->timestamp = b.mTimestamp; nativeBuffer->frameNumber = b.mFrameNumber; + nativeBuffer->dataCb = reinterpret_cast<uint8_t*>(ycbcr.cb); + nativeBuffer->dataCr = reinterpret_cast<uint8_t*>(ycbcr.cr); + nativeBuffer->chromaStride = ycbcr.cstride; + nativeBuffer->chromaStep = ycbcr.chroma_step; + mCurrentLockedBuffers++; return OK; @@ -116,43 +158,50 @@ status_t CpuConsumer::lockNextBuffer(LockedBuffer *nativeBuffer) { status_t CpuConsumer::unlockBuffer(const LockedBuffer &nativeBuffer) { Mutex::Autolock _l(mMutex); - int slotIndex = 0; + size_t lockedIdx = 0; status_t err; void *bufPtr = reinterpret_cast<void *>(nativeBuffer.data); - for (; slotIndex < BufferQueue::NUM_BUFFER_SLOTS; slotIndex++) { - if (bufPtr == mBufferPointers[slotIndex]) break; + for (; lockedIdx < mMaxLockedBuffers; lockedIdx++) { + if (bufPtr == mAcquiredBuffers[lockedIdx].mBufferPointer) break; } - if (slotIndex == BufferQueue::NUM_BUFFER_SLOTS) { + if (lockedIdx == mMaxLockedBuffers) { CC_LOGE("%s: Can't find buffer to free", __FUNCTION__); return BAD_VALUE; } - mBufferPointers[slotIndex] = NULL; - err = mSlots[slotIndex].mGraphicBuffer->unlock(); + return releaseAcquiredBufferLocked(lockedIdx); +} + +status_t CpuConsumer::releaseAcquiredBufferLocked(int lockedIdx) { + status_t err; + + err = mAcquiredBuffers[lockedIdx].mGraphicBuffer->unlock(); if (err != OK) { - CC_LOGE("%s: Unable to unlock graphic buffer %d", __FUNCTION__, slotIndex); + CC_LOGE("%s: Unable to unlock graphic buffer %d", __FUNCTION__, + lockedIdx); return err; } - releaseBufferLocked(slotIndex, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR); + int buf = mAcquiredBuffers[lockedIdx].mSlot; + + // release the buffer if it hasn't already been freed by the BufferQueue. + // This can happen, for example, when the producer of this buffer + // disconnected after this buffer was acquired. + if (CC_LIKELY(mAcquiredBuffers[lockedIdx].mGraphicBuffer == + mSlots[buf].mGraphicBuffer)) { + releaseBufferLocked(buf, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR); + } - mCurrentLockedBuffers--; + AcquiredBuffer &ab = mAcquiredBuffers.editItemAt(lockedIdx); + ab.mSlot = BufferQueue::INVALID_BUFFER_SLOT; + ab.mBufferPointer = NULL; + ab.mGraphicBuffer.clear(); + mCurrentLockedBuffers--; return OK; } void CpuConsumer::freeBufferLocked(int slotIndex) { - if (mBufferPointers[slotIndex] != NULL) { - status_t err; - CC_LOGW("Buffer %d freed while locked by consumer", slotIndex); - mBufferPointers[slotIndex] = NULL; - err = mSlots[slotIndex].mGraphicBuffer->unlock(); - if (err != OK) { - CC_LOGE("%s: Unable to unlock graphic buffer %d", __FUNCTION__, - slotIndex); - } - mCurrentLockedBuffers--; - } ConsumerBase::freeBufferLocked(slotIndex); } diff --git a/libs/gui/SurfaceTexture.cpp b/libs/gui/GLConsumer.cpp index b4dfb5e..dc46a51 100644 --- a/libs/gui/SurfaceTexture.cpp +++ b/libs/gui/GLConsumer.cpp @@ -14,7 +14,7 @@ * limitations under the License. */ -#define LOG_TAG "SurfaceTexture" +#define LOG_TAG "GLConsumer" #define ATRACE_TAG ATRACE_TAG_GRAPHICS //#define LOG_NDEBUG 0 @@ -28,50 +28,27 @@ #include <hardware/hardware.h> +#include <gui/GLConsumer.h> #include <gui/IGraphicBufferAlloc.h> #include <gui/ISurfaceComposer.h> #include <gui/SurfaceComposerClient.h> -#include <gui/SurfaceTexture.h> #include <private/gui/ComposerService.h> +#include <private/gui/SyncFeatures.h> #include <utils/Log.h> #include <utils/String8.h> #include <utils/Trace.h> -// 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 -#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 +namespace android { + +// Macros for including the GLConsumer name in log messages #define ST_LOGV(x, ...) ALOGV("[%s] "x, mName.string(), ##__VA_ARGS__) #define ST_LOGD(x, ...) ALOGD("[%s] "x, mName.string(), ##__VA_ARGS__) #define ST_LOGI(x, ...) ALOGI("[%s] "x, mName.string(), ##__VA_ARGS__) #define ST_LOGW(x, ...) ALOGW("[%s] "x, mName.string(), ##__VA_ARGS__) #define ST_LOGE(x, ...) ALOGE("[%s] "x, mName.string(), ##__VA_ARGS__) -namespace android { - // Transform matrices static float mtxIdentity[16] = { 1, 0, 0, 0, @@ -97,41 +74,36 @@ static float mtxRot90[16] = { 0, 0, 1, 0, 1, 0, 0, 1, }; -static float mtxRot180[16] = { - -1, 0, 0, 0, - 0, -1, 0, 0, - 0, 0, 1, 0, - 1, 1, 0, 1, -}; -static float mtxRot270[16] = { - 0, -1, 0, 0, - 1, 0, 0, 0, - 0, 0, 1, 0, - 0, 1, 0, 1, -}; static void mtxMul(float out[16], const float a[16], const float b[16]); -SurfaceTexture::SurfaceTexture(GLuint tex, bool allowSynchronousMode, +GLConsumer::GLConsumer(const sp<BufferQueue>& bq, GLuint tex, + GLenum texTarget, bool useFenceSync) : + ConsumerBase(bq), + mUseFenceSync(useFenceSync), + mTexTarget(texTarget) {} + + +GLConsumer::GLConsumer(GLuint tex, bool allowSynchronousMode, GLenum texTarget, bool useFenceSync, const sp<BufferQueue> &bufferQueue) : ConsumerBase(bufferQueue == 0 ? new BufferQueue(allowSynchronousMode) : bufferQueue), mCurrentTransform(0), + mCurrentScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE), + mCurrentFence(Fence::NO_FENCE), mCurrentTimestamp(0), + mDefaultWidth(1), + mDefaultHeight(1), mFilteringEnabled(true), mTexName(tex), -#ifdef USE_FENCE_SYNC mUseFenceSync(useFenceSync), -#else - mUseFenceSync(false), -#endif mTexTarget(texTarget), mEglDisplay(EGL_NO_DISPLAY), mEglContext(EGL_NO_CONTEXT), mCurrentTexture(BufferQueue::INVALID_BUFFER_SLOT), mAttached(true) { - ST_LOGV("SurfaceTexture"); + ST_LOGV("GLConsumer"); memcpy(mCurrentTransformMatrix, mtxIdentity, sizeof(mCurrentTransformMatrix)); @@ -139,13 +111,13 @@ SurfaceTexture::SurfaceTexture(GLuint tex, bool allowSynchronousMode, mBufferQueue->setConsumerUsageBits(DEFAULT_USAGE_FLAGS); } -status_t SurfaceTexture::setDefaultMaxBufferCount(int bufferCount) { +status_t GLConsumer::setDefaultMaxBufferCount(int bufferCount) { Mutex::Autolock lock(mMutex); return mBufferQueue->setDefaultMaxBufferCount(bufferCount); } -status_t SurfaceTexture::setDefaultBufferSize(uint32_t w, uint32_t h) +status_t GLConsumer::setDefaultBufferSize(uint32_t w, uint32_t h) { Mutex::Autolock lock(mMutex); mDefaultWidth = w; @@ -153,11 +125,54 @@ status_t SurfaceTexture::setDefaultBufferSize(uint32_t w, uint32_t h) return mBufferQueue->setDefaultBufferSize(w, h); } -status_t SurfaceTexture::updateTexImage() { - return SurfaceTexture::updateTexImage(NULL, false); +status_t GLConsumer::updateTexImage() { + ATRACE_CALL(); + ST_LOGV("updateTexImage"); + Mutex::Autolock lock(mMutex); + + if (mAbandoned) { + ST_LOGE("updateTexImage: 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; + } + + BufferQueue::BufferItem item; + + // Acquire the next buffer. + // In asynchronous mode the list is guaranteed to be one buffer + // deep, while in synchronous mode we use the oldest buffer. + err = acquireBufferLocked(&item); + if (err != NO_ERROR) { + if (err == BufferQueue::NO_BUFFER_AVAILABLE) { + // We always bind the texture even if we don't update its contents. + ST_LOGV("updateTexImage: no buffers were available"); + glBindTexture(mTexTarget, mTexName); + err = NO_ERROR; + } else { + ST_LOGE("updateTexImage: acquire failed: %s (%d)", + strerror(-err), err); + } + return err; + } + + // Release the previous buffer. + err = releaseAndUpdateLocked(item); + if (err != NO_ERROR) { + // We always bind the texture. + glBindTexture(mTexTarget, mTexName); + return err; + } + + // Bind the new buffer to the GL texture, and wait until it's ready. + return bindTextureImageLocked(); } -status_t SurfaceTexture::acquireBufferLocked(BufferQueue::BufferItem *item) { +status_t GLConsumer::acquireBufferLocked(BufferQueue::BufferItem *item) { status_t err = ConsumerBase::acquireBufferLocked(item); if (err != NO_ERROR) { return err; @@ -165,186 +180,187 @@ status_t SurfaceTexture::acquireBufferLocked(BufferQueue::BufferItem *item) { int slot = item->mBuf; if (item->mGraphicBuffer != NULL) { + // This buffer has not been acquired before, so we must assume + // that any EGLImage in mEglSlots is stale. if (mEglSlots[slot].mEglImage != EGL_NO_IMAGE_KHR) { - eglDestroyImageKHR(mEglDisplay, mEglSlots[slot].mEglImage); + if (!eglDestroyImageKHR(mEglDisplay, mEglSlots[slot].mEglImage)) { + ST_LOGW("acquireBufferLocked: eglDestroyImageKHR failed for slot=%d", + slot); + // keep going + } 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::releaseBufferLocked(int buf, EGLDisplay display, +status_t GLConsumer::releaseBufferLocked(int buf, EGLDisplay display, EGLSyncKHR eglFence) { - status_t err = ConsumerBase::releaseBufferLocked(buf, mEglDisplay, - eglFence); + status_t err = ConsumerBase::releaseBufferLocked(buf, display, 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); - +status_t GLConsumer::releaseAndUpdateLocked(const BufferQueue::BufferItem& item) +{ status_t err = NO_ERROR; - if (mAbandoned) { - ST_LOGE("updateTexImage: SurfaceTexture is abandoned!"); - return NO_INIT; - } - if (!mAttached) { - ST_LOGE("updateTexImage: SurfaceTexture is not attached to an OpenGL " + ST_LOGE("releaseAndUpdate: GLConsumer is not attached to an OpenGL " "ES context"); return INVALID_OPERATION; } - EGLDisplay dpy = eglGetCurrentDisplay(); - EGLContext ctx = eglGetCurrentContext(); + // Confirm state. + err = checkAndUpdateEglStateLocked(); + if (err != NO_ERROR) { + return err; + } - if ((mEglDisplay != dpy && mEglDisplay != EGL_NO_DISPLAY) || - dpy == EGL_NO_DISPLAY) { - ST_LOGE("updateTexImage: invalid current EGLDisplay"); - return INVALID_OPERATION; + int buf = item.mBuf; + + // If the mEglSlot entry is empty, create an EGLImage for the gralloc + // buffer currently in the slot in ConsumerBase. + // + // We may have to do this even when item.mGraphicBuffer == NULL (which + // means the buffer was previously acquired), if we destroyed the + // EGLImage when detaching from a context but the buffer has not been + // re-allocated. + 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", + mEglDisplay, buf); + return UNKNOWN_ERROR; + } + mEglSlots[buf].mEglImage = image; } - if ((mEglContext != ctx && mEglContext != EGL_NO_CONTEXT) || - ctx == EGL_NO_CONTEXT) { - ST_LOGE("updateTexImage: invalid current EGLContext"); - return INVALID_OPERATION; + // Do whatever sync ops we need to do before releasing the old slot. + err = syncForReleaseLocked(mEglDisplay); + 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. + releaseBufferLocked(buf, mEglDisplay, EGL_NO_SYNC_KHR); + return err; } - mEglDisplay = dpy; - mEglContext = ctx; + ST_LOGV("releaseAndUpdate: (slot=%d buf=%p) -> (slot=%d buf=%p)", + mCurrentTexture, + mCurrentTextureBuf != NULL ? mCurrentTextureBuf->handle : 0, + buf, mSlots[buf].mGraphicBuffer->handle); - BufferQueue::BufferItem item; - - // In asynchronous mode the list is guaranteed to be one buffer - // deep, while in synchronous mode we use the oldest buffer. - err = acquireBufferLocked(&item); - if (err == NO_ERROR) { - int buf = item.mBuf; - - // 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(mSlots[buf].mGraphicBuffer, item)) { - releaseBufferLocked(buf, dpy, EGL_NO_SYNC_KHR); - glBindTexture(mTexTarget, mTexName); - return NO_ERROR; + // release old buffer + if (mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) { + status_t status = releaseBufferLocked(mCurrentTexture, mEglDisplay, + mEglSlots[mCurrentTexture].mEglFence); + if (status != NO_ERROR && status != BufferQueue::STALE_BUFFER_SLOT) { + ST_LOGE("releaseAndUpdate: failed to release buffer: %s (%d)", + strerror(-status), status); + err = status; + // keep going, with error raised [?] } + } - GLint error; - while ((error = glGetError()) != GL_NO_ERROR) { - ST_LOGW("updateTexImage: clearing GL error: %#04x", error); - } + // Update the GLConsumer state. + mCurrentTexture = buf; + mCurrentTextureBuf = mSlots[buf].mGraphicBuffer; + mCurrentCrop = item.mCrop; + mCurrentTransform = item.mTransform; + mCurrentScalingMode = item.mScalingMode; + mCurrentTimestamp = item.mTimestamp; + mCurrentFence = item.mFence; - EGLImageKHR image = mEglSlots[buf].mEglImage; - glBindTexture(mTexTarget, mTexName); - glEGLImageTargetTexture2DOES(mTexTarget, (GLeglImageOES)image); + computeCurrentTransformMatrixLocked(); - while ((error = glGetError()) != GL_NO_ERROR) { - ST_LOGE("updateTexImage: error binding external texture image %p " - "(slot %d): %#04x", image, buf, error); - err = UNKNOWN_ERROR; - } + return err; +} - if (err == NO_ERROR) { - err = syncForReleaseLocked(dpy); - } +status_t GLConsumer::bindTextureImageLocked() { + if (mEglDisplay == EGL_NO_DISPLAY) { + ALOGE("bindTextureImage: invalid display"); + return INVALID_OPERATION; + } + GLint error; + while ((error = glGetError()) != GL_NO_ERROR) { + ST_LOGW("bindTextureImage: clearing GL error: %#04x", error); + } + + glBindTexture(mTexTarget, mTexName); + if (mCurrentTexture == BufferQueue::INVALID_BUFFER_SLOT) { + if (mCurrentTextureBuf == NULL) { + ST_LOGE("bindTextureImage: no currently-bound texture"); + return NO_INIT; + } + status_t err = bindUnslottedBufferLocked(mEglDisplay); 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. - releaseBufferLocked(buf, dpy, EGL_NO_SYNC_KHR); return err; } + } else { + EGLImageKHR image = mEglSlots[mCurrentTexture].mEglImage; - ST_LOGV("updateTexImage: (slot=%d buf=%p) -> (slot=%d buf=%p)", - mCurrentTexture, - mCurrentTextureBuf != NULL ? mCurrentTextureBuf->handle : 0, - buf, mSlots[buf].mGraphicBuffer->handle); - - // release old buffer - if (mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) { - 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; - } - } + glEGLImageTargetTexture2DOES(mTexTarget, (GLeglImageOES)image); - // Update the SurfaceTexture state. - mCurrentTexture = buf; - mCurrentTextureBuf = mSlots[buf].mGraphicBuffer; - mCurrentCrop = item.mCrop; - mCurrentTransform = item.mTransform; - mCurrentScalingMode = item.mScalingMode; - mCurrentTimestamp = item.mTimestamp; - 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) { - ST_LOGE("updateTexImage: acquire failed: %s (%d)", - strerror(-err), err); - return err; + while ((error = glGetError()) != GL_NO_ERROR) { + ST_LOGE("bindTextureImage: error binding external texture image %p" + ": %#04x", image, error); + return UNKNOWN_ERROR; } - // We always bind the texture even if we don't update its contents. - glBindTexture(mTexTarget, mTexName); - return OK; } - return err; + // Wait for the new buffer to be ready. + return doGLFenceWaitLocked(); + } -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 GLConsumer::checkAndUpdateEglStateLocked() { + EGLDisplay dpy = eglGetCurrentDisplay(); + EGLContext ctx = eglGetCurrentContext(); + + if ((mEglDisplay != dpy && mEglDisplay != EGL_NO_DISPLAY) || + dpy == EGL_NO_DISPLAY) { + ST_LOGE("checkAndUpdateEglState: invalid current EGLDisplay"); + return INVALID_OPERATION; + } + + if ((mEglContext != ctx && mEglContext != EGL_NO_CONTEXT) || + ctx == EGL_NO_CONTEXT) { + ST_LOGE("checkAndUpdateEglState: invalid current EGLContext"); + return INVALID_OPERATION; + } + + mEglDisplay = dpy; + mEglContext = ctx; + return NO_ERROR; +} + +void GLConsumer::setReleaseFence(const sp<Fence>& fence) { + if (fence->isValid() && + mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) { + 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() { +status_t GLConsumer::detachFromContext() { ATRACE_CALL(); ST_LOGV("detachFromContext"); Mutex::Autolock lock(mMutex); if (mAbandoned) { - ST_LOGE("detachFromContext: abandoned SurfaceTexture"); + ST_LOGE("detachFromContext: abandoned GLConsumer"); return NO_INIT; } if (!mAttached) { - ST_LOGE("detachFromContext: SurfaceTexture is not attached to a " + ST_LOGE("detachFromContext: GLConsumer is not attached to a " "context"); return INVALID_OPERATION; } @@ -373,7 +389,7 @@ status_t SurfaceTexture::detachFromContext() { // Because we're giving up the EGLDisplay we need to free all the EGLImages // that are associated with it. They'll be recreated when the - // SurfaceTexture gets attached to a new OpenGL ES context (and thus gets a + // GLConsumer 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; @@ -390,18 +406,18 @@ status_t SurfaceTexture::detachFromContext() { return OK; } -status_t SurfaceTexture::attachToContext(GLuint tex) { +status_t GLConsumer::attachToContext(GLuint tex) { ATRACE_CALL(); ST_LOGV("attachToContext"); Mutex::Autolock lock(mMutex); if (mAbandoned) { - ST_LOGE("attachToContext: abandoned SurfaceTexture"); + ST_LOGE("attachToContext: abandoned GLConsumer"); return NO_INIT; } if (mAttached) { - ST_LOGE("attachToContext: SurfaceTexture is already attached to a " + ST_LOGE("attachToContext: GLConsumer is already attached to a " "context"); return INVALID_OPERATION; } @@ -425,32 +441,10 @@ status_t SurfaceTexture::attachToContext(GLuint tex) { if (mCurrentTextureBuf != NULL) { // The EGLImageKHR that was associated with the slot was destroyed when - // the SurfaceTexture was detached from the old context, so we need to + // the GLConsumer was detached from the old context, so we need to // recreate it here. - EGLImageKHR image = createImage(dpy, mCurrentTextureBuf); - if (image == EGL_NO_IMAGE_KHR) { - return UNKNOWN_ERROR; - } - - // Attach the current buffer to the GL texture. - glEGLImageTargetTexture2DOES(mTexTarget, (GLeglImageOES)image); - - GLint error; - status_t err = OK; - while ((error = glGetError()) != GL_NO_ERROR) { - ST_LOGE("attachToContext: error binding external texture image %p " - "(slot %d): %#04x", image, mCurrentTexture, error); - err = UNKNOWN_ERROR; - } - - // We destroy the EGLImageKHR here because the current buffer may no - // longer be associated with one of the buffer slots, so we have - // nowhere to to store it. If the buffer is still associated with a - // slot then another EGLImageKHR will be created next time that buffer - // gets acquired in updateTexImage. - eglDestroyImageKHR(dpy, image); - - if (err != OK) { + status_t err = bindUnslottedBufferLocked(dpy); + if (err != NO_ERROR) { return err; } } @@ -463,11 +457,43 @@ status_t SurfaceTexture::attachToContext(GLuint tex) { return OK; } -status_t SurfaceTexture::syncForReleaseLocked(EGLDisplay dpy) { +status_t GLConsumer::bindUnslottedBufferLocked(EGLDisplay dpy) { + ST_LOGV("bindUnslottedBuffer ct=%d ctb=%p", + mCurrentTexture, mCurrentTextureBuf.get()); + + // Create a temporary EGLImageKHR. + EGLImageKHR image = createImage(dpy, mCurrentTextureBuf); + if (image == EGL_NO_IMAGE_KHR) { + return UNKNOWN_ERROR; + } + + // Attach the current buffer to the GL texture. + glEGLImageTargetTexture2DOES(mTexTarget, (GLeglImageOES)image); + + GLint error; + status_t err = OK; + while ((error = glGetError()) != GL_NO_ERROR) { + ST_LOGE("bindUnslottedBuffer: error binding external texture image %p " + "(slot %d): %#04x", image, mCurrentTexture, error); + err = UNKNOWN_ERROR; + } + + // We destroy the EGLImageKHR here because the current buffer may no + // longer be associated with one of the buffer slots, so we have + // nowhere to to store it. If the buffer is still associated with a + // slot then another EGLImageKHR will be created next time that buffer + // gets acquired in updateTexImage. + eglDestroyImageKHR(dpy, image); + + return err; +} + + +status_t GLConsumer::syncForReleaseLocked(EGLDisplay dpy) { ST_LOGV("syncForReleaseLocked"); if (mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) { - if (useNativeFenceSync) { + if (SyncFeatures::getInstance().useNativeFenceSync()) { EGLSyncKHR sync = eglCreateSyncKHR(dpy, EGL_SYNC_NATIVE_FENCE_ANDROID, NULL); if (sync == EGL_NO_SYNC_KHR) { @@ -490,7 +516,7 @@ status_t SurfaceTexture::syncForReleaseLocked(EGLDisplay dpy) { "%s (%d)", strerror(-err), err); return err; } - } else if (mUseFenceSync) { + } else if (mUseFenceSync && SyncFeatures::getInstance().useFenceSync()) { EGLSyncKHR fence = mEglSlots[mCurrentTexture].mEglFence; if (fence != EGL_NO_SYNC_KHR) { // There is already a fence for the current slot. We need to @@ -526,7 +552,7 @@ status_t SurfaceTexture::syncForReleaseLocked(EGLDisplay dpy) { return OK; } -bool SurfaceTexture::isExternalFormat(uint32_t format) +bool GLConsumer::isExternalFormat(uint32_t format) { switch (format) { // supported YUV formats @@ -545,19 +571,19 @@ bool SurfaceTexture::isExternalFormat(uint32_t format) return false; } -GLenum SurfaceTexture::getCurrentTextureTarget() const { +GLenum GLConsumer::getCurrentTextureTarget() const { return mTexTarget; } -void SurfaceTexture::getTransformMatrix(float mtx[16]) { +void GLConsumer::getTransformMatrix(float mtx[16]) { Mutex::Autolock lock(mMutex); memcpy(mtx, mCurrentTransformMatrix, sizeof(mCurrentTransformMatrix)); } -void SurfaceTexture::setFilteringEnabled(bool enabled) { +void GLConsumer::setFilteringEnabled(bool enabled) { Mutex::Autolock lock(mMutex); if (mAbandoned) { - ST_LOGE("setFilteringEnabled: SurfaceTexture is abandoned!"); + ST_LOGE("setFilteringEnabled: GLConsumer is abandoned!"); return; } bool needsRecompute = mFilteringEnabled != enabled; @@ -572,7 +598,7 @@ void SurfaceTexture::setFilteringEnabled(bool enabled) { } } -void SurfaceTexture::computeCurrentTransformMatrixLocked() { +void GLConsumer::computeCurrentTransformMatrixLocked() { ST_LOGV("computeCurrentTransformMatrixLocked"); float xform[16]; @@ -665,19 +691,19 @@ void SurfaceTexture::computeCurrentTransformMatrixLocked() { mtxMul(mtxBeforeFlipV, crop, xform); // SurfaceFlinger expects the top of its window textures to be at a Y - // coordinate of 0, so SurfaceTexture must behave the same way. We don't + // coordinate of 0, so GLConsumer must behave the same way. We don't // want to expose this to applications, however, so we must add an // additional vertical flip to the transform after all the other transforms. mtxMul(mCurrentTransformMatrix, mtxFlipV, mtxBeforeFlipV); } -nsecs_t SurfaceTexture::getTimestamp() { +nsecs_t GLConsumer::getTimestamp() { ST_LOGV("getTimestamp"); Mutex::Autolock lock(mMutex); return mCurrentTimestamp; } -EGLImageKHR SurfaceTexture::createImage(EGLDisplay dpy, +EGLImageKHR GLConsumer::createImage(EGLDisplay dpy, const sp<GraphicBuffer>& graphicBuffer) { EGLClientBuffer cbuf = (EGLClientBuffer)graphicBuffer->getNativeBuffer(); EGLint attrs[] = { @@ -693,12 +719,12 @@ EGLImageKHR SurfaceTexture::createImage(EGLDisplay dpy, return image; } -sp<GraphicBuffer> SurfaceTexture::getCurrentBuffer() const { +sp<GraphicBuffer> GLConsumer::getCurrentBuffer() const { Mutex::Autolock lock(mMutex); return mCurrentTextureBuf; } -Rect SurfaceTexture::getCurrentCrop() const { +Rect GLConsumer::getCurrentCrop() const { Mutex::Autolock lock(mMutex); Rect outCrop = mCurrentCrop; @@ -734,27 +760,27 @@ Rect SurfaceTexture::getCurrentCrop() const { return outCrop; } -uint32_t SurfaceTexture::getCurrentTransform() const { +uint32_t GLConsumer::getCurrentTransform() const { Mutex::Autolock lock(mMutex); return mCurrentTransform; } -uint32_t SurfaceTexture::getCurrentScalingMode() const { +uint32_t GLConsumer::getCurrentScalingMode() const { Mutex::Autolock lock(mMutex); return mCurrentScalingMode; } -sp<Fence> SurfaceTexture::getCurrentFence() const { +sp<Fence> GLConsumer::getCurrentFence() const { Mutex::Autolock lock(mMutex); return mCurrentFence; } -status_t SurfaceTexture::doGLFenceWait() const { +status_t GLConsumer::doGLFenceWait() const { Mutex::Autolock lock(mMutex); return doGLFenceWaitLocked(); } -status_t SurfaceTexture::doGLFenceWaitLocked() const { +status_t GLConsumer::doGLFenceWaitLocked() const { EGLDisplay dpy = eglGetCurrentDisplay(); EGLContext ctx = eglGetCurrentContext(); @@ -769,8 +795,8 @@ status_t SurfaceTexture::doGLFenceWaitLocked() const { return INVALID_OPERATION; } - if (mCurrentFence != NULL) { - if (useWaitSync) { + if (mCurrentFence->isValid()) { + if (SyncFeatures::getInstance().useWaitSync()) { // Create an EGLSyncKHR from the current fence. int fenceFd = mCurrentFence->dup(); if (fenceFd == -1) { @@ -793,7 +819,7 @@ status_t SurfaceTexture::doGLFenceWaitLocked() const { // 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); + eglWaitSyncKHR(dpy, sync, 0); EGLint eglErr = eglGetError(); eglDestroySyncKHR(dpy, sync); if (eglErr != EGL_SUCCESS) { @@ -802,8 +828,8 @@ status_t SurfaceTexture::doGLFenceWaitLocked() const { return UNKNOWN_ERROR; } } else { - status_t err = mCurrentFence->waitForever(1000, - "SurfaceTexture::doGLFenceWaitLocked"); + status_t err = mCurrentFence->waitForever( + "GLConsumer::doGLFenceWaitLocked"); if (err != NO_ERROR) { ST_LOGE("doGLFenceWait: error waiting for fence: %d", err); return err; @@ -814,12 +840,12 @@ status_t SurfaceTexture::doGLFenceWaitLocked() const { return NO_ERROR; } -bool SurfaceTexture::isSynchronousMode() const { +bool GLConsumer::isSynchronousMode() const { Mutex::Autolock lock(mMutex); return mBufferQueue->isSynchronousMode(); } -void SurfaceTexture::freeBufferLocked(int slotIndex) { +void GLConsumer::freeBufferLocked(int slotIndex) { ST_LOGV("freeBufferLocked: slotIndex=%d", slotIndex); if (slotIndex == mCurrentTexture) { mCurrentTexture = BufferQueue::INVALID_BUFFER_SLOT; @@ -833,42 +859,42 @@ void SurfaceTexture::freeBufferLocked(int slotIndex) { ConsumerBase::freeBufferLocked(slotIndex); } -void SurfaceTexture::abandonLocked() { +void GLConsumer::abandonLocked() { ST_LOGV("abandonLocked"); mCurrentTextureBuf.clear(); ConsumerBase::abandonLocked(); } -void SurfaceTexture::setName(const String8& name) { +void GLConsumer::setName(const String8& name) { Mutex::Autolock _l(mMutex); mName = name; mBufferQueue->setConsumerName(name); } -status_t SurfaceTexture::setDefaultBufferFormat(uint32_t defaultFormat) { +status_t GLConsumer::setDefaultBufferFormat(uint32_t defaultFormat) { Mutex::Autolock lock(mMutex); return mBufferQueue->setDefaultBufferFormat(defaultFormat); } -status_t SurfaceTexture::setConsumerUsageBits(uint32_t usage) { +status_t GLConsumer::setConsumerUsageBits(uint32_t usage) { Mutex::Autolock lock(mMutex); usage |= DEFAULT_USAGE_FLAGS; return mBufferQueue->setConsumerUsageBits(usage); } -status_t SurfaceTexture::setTransformHint(uint32_t hint) { +status_t GLConsumer::setTransformHint(uint32_t hint) { Mutex::Autolock lock(mMutex); return mBufferQueue->setTransformHint(hint); } -// Used for refactoring BufferQueue from SurfaceTexture -// Should not be in final interface once users of SurfaceTexture are clean up. -status_t SurfaceTexture::setSynchronousMode(bool enabled) { +// Used for refactoring BufferQueue from GLConsumer +// Should not be in final interface once users of GLConsumer are clean up. +status_t GLConsumer::setSynchronousMode(bool enabled) { Mutex::Autolock lock(mMutex); return mBufferQueue->setSynchronousMode(enabled); } -void SurfaceTexture::dumpLocked(String8& result, const char* prefix, +void GLConsumer::dumpLocked(String8& result, const char* prefix, char* buffer, size_t size) const { snprintf(buffer, size, diff --git a/libs/gui/GraphicBufferAlloc.cpp b/libs/gui/GraphicBufferAlloc.cpp new file mode 100644 index 0000000..b360e81 --- /dev/null +++ b/libs/gui/GraphicBufferAlloc.cpp @@ -0,0 +1,53 @@ +/* + ** + ** Copyright 2012 The Android Open Source Project + ** + ** Licensed under the Apache License Version 2.0(the "License"); + ** you may not use this file except in compliance with the License. + ** You may obtain a copy of the License at + ** + ** http://www.apache.org/licenses/LICENSE-2.0 + ** + ** Unless required by applicable law or agreed to in writing software + ** distributed under the License is distributed on an "AS IS" BASIS + ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND either express or implied. + ** See the License for the specific language governing permissions and + ** limitations under the License. + */ + +#include <cutils/log.h> + +#include <ui/GraphicBuffer.h> + +#include <gui/GraphicBufferAlloc.h> + +// ---------------------------------------------------------------------------- +namespace android { +// ---------------------------------------------------------------------------- + +GraphicBufferAlloc::GraphicBufferAlloc() { +} + +GraphicBufferAlloc::~GraphicBufferAlloc() { +} + +sp<GraphicBuffer> GraphicBufferAlloc::createGraphicBuffer(uint32_t w, uint32_t h, + PixelFormat format, uint32_t usage, status_t* error) { + sp<GraphicBuffer> graphicBuffer(new GraphicBuffer(w, h, format, usage)); + status_t err = graphicBuffer->initCheck(); + *error = err; + if (err != 0 || graphicBuffer->handle == 0) { + if (err == NO_MEMORY) { + GraphicBuffer::dumpAllocationsToSystemLog(); + } + ALOGE("GraphicBufferAlloc::createGraphicBuffer(w=%d, h=%d) " + "failed (%s), handle=%p", + w, h, strerror(-err), graphicBuffer->handle); + return 0; + } + return graphicBuffer; +} + +// ---------------------------------------------------------------------------- +}; // namespace android +// ---------------------------------------------------------------------------- diff --git a/libs/gui/GuiConfig.cpp b/libs/gui/GuiConfig.cpp index bafd21a..bc0c83c 100644 --- a/libs/gui/GuiConfig.cpp +++ b/libs/gui/GuiConfig.cpp @@ -22,14 +22,8 @@ void appendGuiConfigString(String8& configStr) { static const char* config = " [libgui" -#ifdef USE_FENCE_SYNC - " USE_FENCE_SYNC" -#endif -#ifdef USE_NATIVE_FENCE_SYNC - " USE_NATIVE_FENCE_SYNC" -#endif -#ifdef USE_WAIT_SYNC - " USE_WAIT_SYNC" +#ifdef DONT_USE_FENCE_SYNC + " DONT_USE_FENCE_SYNC" #endif "]"; configStr.append(config); diff --git a/libs/gui/ISurfaceTexture.cpp b/libs/gui/IGraphicBufferProducer.cpp index a0b1e74..63d7628 100644 --- a/libs/gui/ISurfaceTexture.cpp +++ b/libs/gui/IGraphicBufferProducer.cpp @@ -25,7 +25,7 @@ #include <binder/Parcel.h> #include <binder/IInterface.h> -#include <gui/ISurfaceTexture.h> +#include <gui/IGraphicBufferProducer.h> namespace android { // ---------------------------------------------------------------------------- @@ -43,17 +43,17 @@ enum { }; -class BpSurfaceTexture : public BpInterface<ISurfaceTexture> +class BpGraphicBufferProducer : public BpInterface<IGraphicBufferProducer> { public: - BpSurfaceTexture(const sp<IBinder>& impl) - : BpInterface<ISurfaceTexture>(impl) + BpGraphicBufferProducer(const sp<IBinder>& impl) + : BpInterface<IGraphicBufferProducer>(impl) { } virtual status_t requestBuffer(int bufferIdx, sp<GraphicBuffer>* buf) { Parcel data, reply; - data.writeInterfaceToken(ISurfaceTexture::getInterfaceDescriptor()); + data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor()); data.writeInt32(bufferIdx); status_t result =remote()->transact(REQUEST_BUFFER, data, &reply); if (result != NO_ERROR) { @@ -71,7 +71,7 @@ public: virtual status_t setBufferCount(int bufferCount) { Parcel data, reply; - data.writeInterfaceToken(ISurfaceTexture::getInterfaceDescriptor()); + data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor()); data.writeInt32(bufferCount); status_t result =remote()->transact(SET_BUFFER_COUNT, data, &reply); if (result != NO_ERROR) { @@ -81,10 +81,10 @@ public: return result; } - virtual status_t dequeueBuffer(int *buf, sp<Fence>& fence, + virtual status_t dequeueBuffer(int *buf, sp<Fence>* fence, uint32_t w, uint32_t h, uint32_t format, uint32_t usage) { Parcel data, reply; - data.writeInterfaceToken(ISurfaceTexture::getInterfaceDescriptor()); + data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor()); data.writeInt32(w); data.writeInt32(h); data.writeInt32(format); @@ -94,11 +94,13 @@ public: return result; } *buf = reply.readInt32(); - fence.clear(); - bool hasFence = reply.readInt32(); - if (hasFence) { - fence = new Fence(); - reply.read(*fence.get()); + bool fenceWasWritten = reply.readInt32(); + if (fenceWasWritten) { + // If the fence was written by the callee, then overwrite the + // caller's fence here. If it wasn't written then don't touch the + // caller's fence. + *fence = new Fence(); + reply.read(*(fence->get())); } result = reply.readInt32(); return result; @@ -107,7 +109,7 @@ public: virtual status_t queueBuffer(int buf, const QueueBufferInput& input, QueueBufferOutput* output) { Parcel data, reply; - data.writeInterfaceToken(ISurfaceTexture::getInterfaceDescriptor()); + data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor()); data.writeInt32(buf); data.write(input); status_t result = remote()->transact(QUEUE_BUFFER, data, &reply); @@ -119,21 +121,17 @@ public: return result; } - virtual void cancelBuffer(int buf, sp<Fence> fence) { + virtual void cancelBuffer(int buf, const sp<Fence>& fence) { Parcel data, reply; - bool hasFence = fence.get() && fence->isValid(); - data.writeInterfaceToken(ISurfaceTexture::getInterfaceDescriptor()); + data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor()); data.writeInt32(buf); - data.writeInt32(hasFence); - if (hasFence) { - data.write(*fence.get()); - } + data.write(*fence.get()); remote()->transact(CANCEL_BUFFER, data, &reply); } virtual int query(int what, int* value) { Parcel data, reply; - data.writeInterfaceToken(ISurfaceTexture::getInterfaceDescriptor()); + data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor()); data.writeInt32(what); status_t result = remote()->transact(QUERY, data, &reply); if (result != NO_ERROR) { @@ -146,7 +144,7 @@ public: virtual status_t setSynchronousMode(bool enabled) { Parcel data, reply; - data.writeInterfaceToken(ISurfaceTexture::getInterfaceDescriptor()); + data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor()); data.writeInt32(enabled); status_t result = remote()->transact(SET_SYNCHRONOUS_MODE, data, &reply); if (result != NO_ERROR) { @@ -158,7 +156,7 @@ public: virtual status_t connect(int api, QueueBufferOutput* output) { Parcel data, reply; - data.writeInterfaceToken(ISurfaceTexture::getInterfaceDescriptor()); + data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor()); data.writeInt32(api); status_t result = remote()->transact(CONNECT, data, &reply); if (result != NO_ERROR) { @@ -171,7 +169,7 @@ public: virtual status_t disconnect(int api) { Parcel data, reply; - data.writeInterfaceToken(ISurfaceTexture::getInterfaceDescriptor()); + data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor()); data.writeInt32(api); status_t result =remote()->transact(DISCONNECT, data, &reply); if (result != NO_ERROR) { @@ -182,16 +180,16 @@ public: } }; -IMPLEMENT_META_INTERFACE(SurfaceTexture, "android.gui.SurfaceTexture"); +IMPLEMENT_META_INTERFACE(GraphicBufferProducer, "android.gui.IGraphicBufferProducer"); // ---------------------------------------------------------------------- -status_t BnSurfaceTexture::onTransact( +status_t BnGraphicBufferProducer::onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { switch(code) { case REQUEST_BUFFER: { - CHECK_INTERFACE(ISurfaceTexture, data, reply); + CHECK_INTERFACE(IGraphicBufferProducer, data, reply); int bufferIdx = data.readInt32(); sp<GraphicBuffer> buffer; int result = requestBuffer(bufferIdx, &buffer); @@ -203,32 +201,31 @@ status_t BnSurfaceTexture::onTransact( return NO_ERROR; } break; case SET_BUFFER_COUNT: { - CHECK_INTERFACE(ISurfaceTexture, data, reply); + CHECK_INTERFACE(IGraphicBufferProducer, data, reply); int bufferCount = data.readInt32(); int result = setBufferCount(bufferCount); reply->writeInt32(result); return NO_ERROR; } break; case DEQUEUE_BUFFER: { - CHECK_INTERFACE(ISurfaceTexture, data, reply); + CHECK_INTERFACE(IGraphicBufferProducer, data, reply); uint32_t w = data.readInt32(); uint32_t h = data.readInt32(); uint32_t format = data.readInt32(); uint32_t usage = data.readInt32(); int buf; sp<Fence> fence; - int result = dequeueBuffer(&buf, fence, w, h, format, usage); - bool hasFence = fence.get() && fence->isValid(); + int result = dequeueBuffer(&buf, &fence, w, h, format, usage); reply->writeInt32(buf); - reply->writeInt32(hasFence); - if (hasFence) { + reply->writeInt32(fence != NULL); + if (fence != NULL) { reply->write(*fence.get()); } reply->writeInt32(result); return NO_ERROR; } break; case QUEUE_BUFFER: { - CHECK_INTERFACE(ISurfaceTexture, data, reply); + CHECK_INTERFACE(IGraphicBufferProducer, data, reply); int buf = data.readInt32(); QueueBufferInput input(data); QueueBufferOutput* const output = @@ -239,19 +236,15 @@ status_t BnSurfaceTexture::onTransact( return NO_ERROR; } break; case CANCEL_BUFFER: { - CHECK_INTERFACE(ISurfaceTexture, data, reply); + CHECK_INTERFACE(IGraphicBufferProducer, data, reply); int buf = data.readInt32(); - sp<Fence> fence; - bool hasFence = data.readInt32(); - if (hasFence) { - fence = new Fence(); - data.read(*fence.get()); - } + sp<Fence> fence = new Fence(); + data.read(*fence.get()); cancelBuffer(buf, fence); return NO_ERROR; } break; case QUERY: { - CHECK_INTERFACE(ISurfaceTexture, data, reply); + CHECK_INTERFACE(IGraphicBufferProducer, data, reply); int value; int what = data.readInt32(); int res = query(what, &value); @@ -260,14 +253,14 @@ status_t BnSurfaceTexture::onTransact( return NO_ERROR; } break; case SET_SYNCHRONOUS_MODE: { - CHECK_INTERFACE(ISurfaceTexture, data, reply); + CHECK_INTERFACE(IGraphicBufferProducer, data, reply); bool enabled = data.readInt32(); status_t res = setSynchronousMode(enabled); reply->writeInt32(res); return NO_ERROR; } break; case CONNECT: { - CHECK_INTERFACE(ISurfaceTexture, data, reply); + CHECK_INTERFACE(IGraphicBufferProducer, data, reply); int api = data.readInt32(); QueueBufferOutput* const output = reinterpret_cast<QueueBufferOutput *>( @@ -277,7 +270,7 @@ status_t BnSurfaceTexture::onTransact( return NO_ERROR; } break; case DISCONNECT: { - CHECK_INTERFACE(ISurfaceTexture, data, reply); + CHECK_INTERFACE(IGraphicBufferProducer, data, reply); int api = data.readInt32(); status_t res = disconnect(api); reply->writeInt32(res); @@ -289,61 +282,48 @@ status_t BnSurfaceTexture::onTransact( // ---------------------------------------------------------------------------- -static bool isValid(const sp<Fence>& fence) { - return fence.get() && fence->isValid(); -} - -ISurfaceTexture::QueueBufferInput::QueueBufferInput(const Parcel& parcel) { +IGraphicBufferProducer::QueueBufferInput::QueueBufferInput(const Parcel& parcel) { parcel.read(*this); } -size_t ISurfaceTexture::QueueBufferInput::getFlattenedSize() const +size_t IGraphicBufferProducer::QueueBufferInput::getFlattenedSize() const { return sizeof(timestamp) + sizeof(crop) + sizeof(scalingMode) + sizeof(transform) - + sizeof(bool) - + (isValid(fence) ? fence->getFlattenedSize() : 0); + + fence->getFlattenedSize(); } -size_t ISurfaceTexture::QueueBufferInput::getFdCount() const +size_t IGraphicBufferProducer::QueueBufferInput::getFdCount() const { - return isValid(fence) ? fence->getFdCount() : 0; + return fence->getFdCount(); } -status_t ISurfaceTexture::QueueBufferInput::flatten(void* buffer, size_t size, +status_t IGraphicBufferProducer::QueueBufferInput::flatten(void* buffer, size_t size, int fds[], size_t count) const { status_t err = NO_ERROR; - bool haveFence = isValid(fence); char* p = (char*)buffer; memcpy(p, ×tamp, sizeof(timestamp)); p += sizeof(timestamp); memcpy(p, &crop, sizeof(crop)); p += sizeof(crop); memcpy(p, &scalingMode, sizeof(scalingMode)); p += sizeof(scalingMode); memcpy(p, &transform, sizeof(transform)); p += sizeof(transform); - memcpy(p, &haveFence, sizeof(haveFence)); p += sizeof(haveFence); - if (haveFence) { - err = fence->flatten(p, size - (p - (char*)buffer), fds, count); - } + err = fence->flatten(p, size - (p - (char*)buffer), fds, count); return err; } -status_t ISurfaceTexture::QueueBufferInput::unflatten(void const* buffer, +status_t IGraphicBufferProducer::QueueBufferInput::unflatten(void const* buffer, size_t size, int fds[], size_t count) { status_t err = NO_ERROR; - bool haveFence; const char* p = (const char*)buffer; memcpy(×tamp, p, sizeof(timestamp)); p += sizeof(timestamp); memcpy(&crop, p, sizeof(crop)); p += sizeof(crop); memcpy(&scalingMode, p, sizeof(scalingMode)); p += sizeof(scalingMode); memcpy(&transform, p, sizeof(transform)); p += sizeof(transform); - memcpy(&haveFence, p, sizeof(haveFence)); p += sizeof(haveFence); - if (haveFence) { - fence = new Fence(); - err = fence->unflatten(p, size - (p - (const char*)buffer), fds, count); - } + fence = new Fence(); + err = fence->unflatten(p, size - (p - (const char*)buffer), fds, count); return err; } diff --git a/libs/gui/ISurface.cpp b/libs/gui/ISurface.cpp deleted file mode 100644 index c2ea183..0000000 --- a/libs/gui/ISurface.cpp +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define LOG_TAG "ISurface" - -#include <stdio.h> -#include <stdint.h> -#include <sys/types.h> - -#include <binder/Parcel.h> - -#include <gui/ISurface.h> -#include <gui/ISurfaceTexture.h> - -namespace android { - -// ---------------------------------------------------------------------- - -class BpSurface : public BpInterface<ISurface> -{ -public: - BpSurface(const sp<IBinder>& impl) - : BpInterface<ISurface>(impl) - { - } - - virtual sp<ISurfaceTexture> getSurfaceTexture() const { - Parcel data, reply; - data.writeInterfaceToken(ISurface::getInterfaceDescriptor()); - remote()->transact(GET_SURFACE_TEXTURE, data, &reply); - return interface_cast<ISurfaceTexture>(reply.readStrongBinder()); - } -}; - -IMPLEMENT_META_INTERFACE(Surface, "android.ui.ISurface"); - -// ---------------------------------------------------------------------- - -status_t BnSurface::onTransact( - uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) -{ - switch(code) { - case GET_SURFACE_TEXTURE: { - CHECK_INTERFACE(ISurface, data, reply); - reply->writeStrongBinder( getSurfaceTexture()->asBinder() ); - return NO_ERROR; - } - default: - return BBinder::onTransact(code, data, reply, flags); - } -} - -}; // namespace android diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp index 85a9488..6442a86 100644 --- a/libs/gui/ISurfaceComposer.cpp +++ b/libs/gui/ISurfaceComposer.cpp @@ -28,7 +28,7 @@ #include <gui/BitTube.h> #include <gui/IDisplayEventConnection.h> #include <gui/ISurfaceComposer.h> -#include <gui/ISurfaceTexture.h> +#include <gui/IGraphicBufferProducer.h> #include <private/gui/LayerState.h> @@ -102,29 +102,27 @@ public: remote()->transact(BnSurfaceComposer::BOOT_FINISHED, data, &reply); } - virtual status_t captureScreen( - const sp<IBinder>& display, sp<IMemoryHeap>* heap, - uint32_t* width, uint32_t* height, PixelFormat* format, + virtual status_t captureScreen(const sp<IBinder>& display, + const sp<IGraphicBufferProducer>& producer, uint32_t reqWidth, uint32_t reqHeight, - uint32_t minLayerZ, uint32_t maxLayerZ) + uint32_t minLayerZ, uint32_t maxLayerZ, + bool isCpuConsumer) { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); data.writeStrongBinder(display); + data.writeStrongBinder(producer->asBinder()); data.writeInt32(reqWidth); data.writeInt32(reqHeight); data.writeInt32(minLayerZ); data.writeInt32(maxLayerZ); + data.writeInt32(isCpuConsumer); remote()->transact(BnSurfaceComposer::CAPTURE_SCREEN, data, &reply); - *heap = interface_cast<IMemoryHeap>(reply.readStrongBinder()); - *width = reply.readInt32(); - *height = reply.readInt32(); - *format = reply.readInt32(); return reply.readInt32(); } virtual bool authenticateSurfaceTexture( - const sp<ISurfaceTexture>& surfaceTexture) const + const sp<IGraphicBufferProducer>& bufferProducer) const { Parcel data, reply; int err = NO_ERROR; @@ -135,7 +133,7 @@ public: "interface descriptor: %s (%d)", strerror(-err), -err); return false; } - err = data.writeStrongBinder(surfaceTexture->asBinder()); + err = data.writeStrongBinder(bufferProducer->asBinder()); if (err != NO_ERROR) { ALOGE("ISurfaceComposer::authenticateSurfaceTexture: error writing " "strong binder to parcel: %s (%d)", strerror(-err), -err); @@ -271,26 +269,23 @@ status_t BnSurfaceComposer::onTransact( case CAPTURE_SCREEN: { CHECK_INTERFACE(ISurfaceComposer, data, reply); sp<IBinder> display = data.readStrongBinder(); + sp<IGraphicBufferProducer> producer = + interface_cast<IGraphicBufferProducer>(data.readStrongBinder()); uint32_t reqWidth = data.readInt32(); uint32_t reqHeight = data.readInt32(); uint32_t minLayerZ = data.readInt32(); uint32_t maxLayerZ = data.readInt32(); - sp<IMemoryHeap> heap; - uint32_t w, h; - PixelFormat f; - status_t res = captureScreen(display, &heap, &w, &h, &f, - reqWidth, reqHeight, minLayerZ, maxLayerZ); - reply->writeStrongBinder(heap->asBinder()); - reply->writeInt32(w); - reply->writeInt32(h); - reply->writeInt32(f); + bool isCpuConsumer = data.readInt32(); + status_t res = captureScreen(display, producer, + reqWidth, reqHeight, minLayerZ, maxLayerZ, + isCpuConsumer); reply->writeInt32(res); } break; case AUTHENTICATE_SURFACE: { CHECK_INTERFACE(ISurfaceComposer, data, reply); - sp<ISurfaceTexture> surfaceTexture = - interface_cast<ISurfaceTexture>(data.readStrongBinder()); - int32_t result = authenticateSurfaceTexture(surfaceTexture) ? 1 : 0; + sp<IGraphicBufferProducer> bufferProducer = + interface_cast<IGraphicBufferProducer>(data.readStrongBinder()); + int32_t result = authenticateSurfaceTexture(bufferProducer) ? 1 : 0; reply->writeInt32(result); } break; case CREATE_DISPLAY_EVENT_CONNECTION: { diff --git a/libs/gui/ISurfaceComposerClient.cpp b/libs/gui/ISurfaceComposerClient.cpp index 8f7bc05..1adc134 100644 --- a/libs/gui/ISurfaceComposerClient.cpp +++ b/libs/gui/ISurfaceComposerClient.cpp @@ -29,7 +29,7 @@ #include <ui/Point.h> #include <ui/Rect.h> -#include <gui/ISurface.h> +#include <gui/IGraphicBufferProducer.h> #include <gui/ISurfaceComposerClient.h> #include <private/gui/LayerState.h> @@ -46,17 +46,13 @@ class BpSurfaceComposerClient : public BpInterface<ISurfaceComposerClient> { public: BpSurfaceComposerClient(const sp<IBinder>& impl) - : BpInterface<ISurfaceComposerClient>(impl) - { + : BpInterface<ISurfaceComposerClient>(impl) { } - virtual sp<ISurface> createSurface( surface_data_t* params, - const String8& name, - uint32_t w, - uint32_t h, - PixelFormat format, - uint32_t flags) - { + virtual status_t createSurface(const String8& name, uint32_t w, + uint32_t h, PixelFormat format, uint32_t flags, + sp<IBinder>* handle, + sp<IGraphicBufferProducer>* gbp) { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposerClient::getInterfaceDescriptor()); data.writeString8(name); @@ -65,15 +61,15 @@ public: data.writeInt32(format); data.writeInt32(flags); remote()->transact(CREATE_SURFACE, data, &reply); - params->readFromParcel(reply); - return interface_cast<ISurface>(reply.readStrongBinder()); + *handle = reply.readStrongBinder(); + *gbp = interface_cast<IGraphicBufferProducer>(reply.readStrongBinder()); + return reply.readInt32(); } - virtual status_t destroySurface(SurfaceID sid) - { + virtual status_t destroySurface(const sp<IBinder>& handle) { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposerClient::getInterfaceDescriptor()); - data.writeInt32(sid); + data.writeStrongBinder(handle); remote()->transact(DESTROY_SURFACE, data, &reply); return reply.readInt32(); } @@ -89,21 +85,23 @@ status_t BnSurfaceComposerClient::onTransact( switch(code) { case CREATE_SURFACE: { CHECK_INTERFACE(ISurfaceComposerClient, data, reply); - surface_data_t params; String8 name = data.readString8(); uint32_t w = data.readInt32(); uint32_t h = data.readInt32(); PixelFormat format = data.readInt32(); uint32_t flags = data.readInt32(); - sp<ISurface> s = createSurface(¶ms, name, w, h, - format, flags); - params.writeToParcel(reply); - reply->writeStrongBinder(s->asBinder()); + sp<IBinder> handle; + sp<IGraphicBufferProducer> gbp; + status_t result = createSurface(name, w, h, format, flags, + &handle, &gbp); + reply->writeStrongBinder(handle); + reply->writeStrongBinder(gbp->asBinder()); + reply->writeInt32(result); return NO_ERROR; } break; case DESTROY_SURFACE: { CHECK_INTERFACE(ISurfaceComposerClient, data, reply); - reply->writeInt32( destroySurface( data.readInt32() ) ); + reply->writeInt32( destroySurface( data.readStrongBinder() ) ); return NO_ERROR; } break; default: @@ -111,20 +109,4 @@ status_t BnSurfaceComposerClient::onTransact( } } -// ---------------------------------------------------------------------- - -status_t ISurfaceComposerClient::surface_data_t::readFromParcel(const Parcel& parcel) -{ - token = parcel.readInt32(); - identity = parcel.readInt32(); - return NO_ERROR; -} - -status_t ISurfaceComposerClient::surface_data_t::writeToParcel(Parcel* parcel) const -{ - parcel->writeInt32(token); - parcel->writeInt32(identity); - return NO_ERROR; -} - }; // namespace android diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index e2604f8..acdbd77 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -17,36 +17,48 @@ #include <utils/Errors.h> #include <binder/Parcel.h> #include <gui/ISurfaceComposerClient.h> -#include <gui/ISurfaceTexture.h> +#include <gui/IGraphicBufferProducer.h> #include <private/gui/LayerState.h> namespace android { status_t layer_state_t::write(Parcel& output) const { - status_t err; - - err = output.write(transparentRegion); - if (err < NO_ERROR) return err; - - // NOTE: regions are at the end of the structure - size_t size = sizeof(layer_state_t); - size -= sizeof(transparentRegion); - err = output.write(this, size); - return err; + output.writeStrongBinder(surface); + output.writeInt32(what); + output.writeFloat(x); + output.writeFloat(y); + output.writeInt32(z); + output.writeInt32(w); + output.writeInt32(h); + output.writeInt32(layerStack); + output.writeFloat(alpha); + output.writeInt32(flags); + output.writeInt32(mask); + *reinterpret_cast<layer_state_t::matrix22_t *>( + output.writeInplace(sizeof(layer_state_t::matrix22_t))) = matrix; + output.write(crop); + output.write(transparentRegion); + return NO_ERROR; } status_t layer_state_t::read(const Parcel& input) { - status_t err; - - err = input.read(transparentRegion); - if (err < NO_ERROR) return err; - - // NOTE: regions are at the end of the structure - size_t size = sizeof(layer_state_t); - size -= sizeof(transparentRegion); - input.read(this, size); + surface = input.readStrongBinder(); + what = input.readInt32(); + x = input.readFloat(); + y = input.readFloat(); + z = input.readInt32(); + w = input.readInt32(); + h = input.readInt32(); + layerStack = input.readInt32(); + alpha = input.readFloat(); + flags = input.readInt32(); + mask = input.readInt32(); + matrix = *reinterpret_cast<layer_state_t::matrix22_t const *>( + input.readInplace(sizeof(layer_state_t::matrix22_t))); + input.read(crop); + input.read(transparentRegion); return NO_ERROR; } @@ -74,7 +86,7 @@ status_t DisplayState::write(Parcel& output) const { status_t DisplayState::read(const Parcel& input) { token = input.readStrongBinder(); - surface = interface_cast<ISurfaceTexture>(input.readStrongBinder()); + surface = interface_cast<IGraphicBufferProducer>(input.readStrongBinder()); what = input.readInt32(); layerStack = input.readInt32(); orientation = input.readInt32(); diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp index 1745061..a616c1e 100644 --- a/libs/gui/Surface.cpp +++ b/libs/gui/Surface.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007 The Android Open Source Project + * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,371 +15,820 @@ */ #define LOG_TAG "Surface" - -#include <stdint.h> -#include <errno.h> -#include <sys/types.h> -#include <sys/stat.h> +#define ATRACE_TAG ATRACE_TAG_GRAPHICS +//#define LOG_NDEBUG 0 #include <android/native_window.h> -#include <utils/CallStack.h> -#include <utils/Errors.h> -#include <utils/Log.h> -#include <utils/threads.h> +#include <binder/Parcel.h> -#include <binder/IPCThreadState.h> +#include <utils/Log.h> +#include <utils/Trace.h> -#include <ui/DisplayInfo.h> -#include <ui/GraphicBuffer.h> -#include <ui/Rect.h> +#include <ui/Fence.h> -#include <gui/ISurface.h> #include <gui/ISurfaceComposer.h> -#include <gui/Surface.h> #include <gui/SurfaceComposerClient.h> -#include <gui/SurfaceTextureClient.h> +#include <gui/GLConsumer.h> +#include <gui/Surface.h> -namespace android { +#include <private/gui/ComposerService.h> -// ============================================================================ -// SurfaceControl -// ============================================================================ +namespace android { -SurfaceControl::SurfaceControl( - const sp<SurfaceComposerClient>& client, - const sp<ISurface>& surface, - const ISurfaceComposerClient::surface_data_t& data) - : mClient(client), mSurface(surface), - mToken(data.token), mIdentity(data.identity) +Surface::Surface( + const sp<IGraphicBufferProducer>& bufferProducer) + : mGraphicBufferProducer(bufferProducer) { + // Initialize the ANativeWindow function pointers. + ANativeWindow::setSwapInterval = hook_setSwapInterval; + ANativeWindow::dequeueBuffer = hook_dequeueBuffer; + ANativeWindow::cancelBuffer = hook_cancelBuffer; + ANativeWindow::queueBuffer = hook_queueBuffer; + ANativeWindow::query = hook_query; + ANativeWindow::perform = hook_perform; + + ANativeWindow::dequeueBuffer_DEPRECATED = hook_dequeueBuffer_DEPRECATED; + ANativeWindow::cancelBuffer_DEPRECATED = hook_cancelBuffer_DEPRECATED; + ANativeWindow::lockBuffer_DEPRECATED = hook_lockBuffer_DEPRECATED; + ANativeWindow::queueBuffer_DEPRECATED = hook_queueBuffer_DEPRECATED; + + const_cast<int&>(ANativeWindow::minSwapInterval) = 0; + const_cast<int&>(ANativeWindow::maxSwapInterval) = 1; + + mReqWidth = 0; + mReqHeight = 0; + mReqFormat = 0; + mReqUsage = 0; + mTimestamp = NATIVE_WINDOW_TIMESTAMP_AUTO; + mCrop.clear(); + mScalingMode = NATIVE_WINDOW_SCALING_MODE_FREEZE; + mTransform = 0; + mDefaultWidth = 0; + mDefaultHeight = 0; + mUserWidth = 0; + mUserHeight = 0; + mTransformHint = 0; + mConsumerRunningBehind = false; + mConnectedToCpu = false; +} + +Surface::~Surface() { + if (mConnectedToCpu) { + Surface::disconnect(NATIVE_WINDOW_API_CPU); + } } - -SurfaceControl::~SurfaceControl() -{ - destroy(); + +sp<IGraphicBufferProducer> Surface::getIGraphicBufferProducer() const { + return mGraphicBufferProducer; } -void SurfaceControl::destroy() -{ - if (isValid()) { - mClient->destroySurface(mToken); - } +int Surface::hook_setSwapInterval(ANativeWindow* window, int interval) { + Surface* c = getSelf(window); + return c->setSwapInterval(interval); +} - // clear all references and trigger an IPC now, to make sure things - // happen without delay, since these resources are quite heavy. - mClient.clear(); - mSurface.clear(); - IPCThreadState::self()->flushCommands(); +int Surface::hook_dequeueBuffer(ANativeWindow* window, + ANativeWindowBuffer** buffer, int* fenceFd) { + Surface* c = getSelf(window); + return c->dequeueBuffer(buffer, fenceFd); } -void SurfaceControl::clear() -{ - // here, the window manager tells us explicitly that we should destroy - // the surface's resource. Soon after this call, it will also release - // its last reference (which will call the dtor); however, it is possible - // that a client living in the same process still holds references which - // would delay the call to the dtor -- that is why we need this explicit - // "clear()" call. - destroy(); +int Surface::hook_cancelBuffer(ANativeWindow* window, + ANativeWindowBuffer* buffer, int fenceFd) { + Surface* c = getSelf(window); + return c->cancelBuffer(buffer, fenceFd); } -bool SurfaceControl::isSameSurface( - const sp<SurfaceControl>& lhs, const sp<SurfaceControl>& rhs) -{ - if (lhs == 0 || rhs == 0) - return false; - return lhs->mSurface->asBinder() == rhs->mSurface->asBinder(); -} - -status_t SurfaceControl::setLayerStack(int32_t layerStack) { - status_t err = validate(); - if (err < 0) return err; - const sp<SurfaceComposerClient>& client(mClient); - return client->setLayerStack(mToken, layerStack); -} -status_t SurfaceControl::setLayer(int32_t layer) { - status_t err = validate(); - if (err < 0) return err; - const sp<SurfaceComposerClient>& client(mClient); - return client->setLayer(mToken, layer); -} -status_t SurfaceControl::setPosition(int32_t x, int32_t y) { - status_t err = validate(); - if (err < 0) return err; - const sp<SurfaceComposerClient>& client(mClient); - return client->setPosition(mToken, x, y); -} -status_t SurfaceControl::setSize(uint32_t w, uint32_t h) { - status_t err = validate(); - if (err < 0) return err; - const sp<SurfaceComposerClient>& client(mClient); - return client->setSize(mToken, w, h); -} -status_t SurfaceControl::hide() { - status_t err = validate(); - if (err < 0) return err; - const sp<SurfaceComposerClient>& client(mClient); - return client->hide(mToken); -} -status_t SurfaceControl::show() { - status_t err = validate(); - if (err < 0) return err; - const sp<SurfaceComposerClient>& client(mClient); - return client->show(mToken); -} -status_t SurfaceControl::setFlags(uint32_t flags, uint32_t mask) { - status_t err = validate(); - if (err < 0) return err; - const sp<SurfaceComposerClient>& client(mClient); - return client->setFlags(mToken, flags, mask); -} -status_t SurfaceControl::setTransparentRegionHint(const Region& transparent) { - status_t err = validate(); - if (err < 0) return err; - const sp<SurfaceComposerClient>& client(mClient); - return client->setTransparentRegionHint(mToken, transparent); -} -status_t SurfaceControl::setAlpha(float alpha) { - status_t err = validate(); - if (err < 0) return err; - const sp<SurfaceComposerClient>& client(mClient); - return client->setAlpha(mToken, alpha); -} -status_t SurfaceControl::setMatrix(float dsdx, float dtdx, float dsdy, float dtdy) { - status_t err = validate(); - if (err < 0) return err; - const sp<SurfaceComposerClient>& client(mClient); - return client->setMatrix(mToken, dsdx, dtdx, dsdy, dtdy); -} -status_t SurfaceControl::setCrop(const Rect& crop) { - status_t err = validate(); - if (err < 0) return err; - const sp<SurfaceComposerClient>& client(mClient); - return client->setCrop(mToken, crop); -} - -status_t SurfaceControl::validate() const -{ - if (mToken<0 || mClient==0) { - ALOGE("invalid token (%d, identity=%u) or client (%p)", - mToken, mIdentity, mClient.get()); - return NO_INIT; +int Surface::hook_queueBuffer(ANativeWindow* window, + ANativeWindowBuffer* buffer, int fenceFd) { + Surface* c = getSelf(window); + return c->queueBuffer(buffer, fenceFd); +} + +int Surface::hook_dequeueBuffer_DEPRECATED(ANativeWindow* window, + ANativeWindowBuffer** buffer) { + Surface* c = getSelf(window); + ANativeWindowBuffer* buf; + int fenceFd = -1; + int result = c->dequeueBuffer(&buf, &fenceFd); + sp<Fence> fence(new Fence(fenceFd)); + int waitResult = fence->waitForever("dequeueBuffer_DEPRECATED"); + if (waitResult != OK) { + ALOGE("dequeueBuffer_DEPRECATED: Fence::wait returned an error: %d", + waitResult); + c->cancelBuffer(buf, -1); + return waitResult; } - return NO_ERROR; + *buffer = buf; + return result; } -status_t SurfaceControl::writeSurfaceToParcel( - const sp<SurfaceControl>& control, Parcel* parcel) -{ - sp<ISurface> sur; - uint32_t identity = 0; - if (SurfaceControl::isValid(control)) { - sur = control->mSurface; - identity = control->mIdentity; +int Surface::hook_cancelBuffer_DEPRECATED(ANativeWindow* window, + ANativeWindowBuffer* buffer) { + Surface* c = getSelf(window); + return c->cancelBuffer(buffer, -1); +} + +int Surface::hook_lockBuffer_DEPRECATED(ANativeWindow* window, + ANativeWindowBuffer* buffer) { + Surface* c = getSelf(window); + return c->lockBuffer_DEPRECATED(buffer); +} + +int Surface::hook_queueBuffer_DEPRECATED(ANativeWindow* window, + ANativeWindowBuffer* buffer) { + Surface* c = getSelf(window); + return c->queueBuffer(buffer, -1); +} + +int Surface::hook_query(const ANativeWindow* window, + int what, int* value) { + const Surface* c = getSelf(window); + return c->query(what, value); +} + +int Surface::hook_perform(ANativeWindow* window, int operation, ...) { + va_list args; + va_start(args, operation); + Surface* c = getSelf(window); + return c->perform(operation, args); +} + +int Surface::setSwapInterval(int interval) { + ATRACE_CALL(); + // EGL specification states: + // interval is silently clamped to minimum and maximum implementation + // dependent values before being stored. + // Although we don't have to, we apply the same logic here. + + if (interval < minSwapInterval) + interval = minSwapInterval; + + if (interval > maxSwapInterval) + interval = maxSwapInterval; + + status_t res = mGraphicBufferProducer->setSynchronousMode(interval ? true : false); + + return res; +} + +int Surface::dequeueBuffer(android_native_buffer_t** buffer, + int* fenceFd) { + ATRACE_CALL(); + ALOGV("Surface::dequeueBuffer"); + Mutex::Autolock lock(mMutex); + int buf = -1; + int reqW = mReqWidth ? mReqWidth : mUserWidth; + int reqH = mReqHeight ? mReqHeight : mUserHeight; + sp<Fence> fence; + status_t result = mGraphicBufferProducer->dequeueBuffer(&buf, &fence, + reqW, reqH, mReqFormat, mReqUsage); + if (result < 0) { + ALOGV("dequeueBuffer: IGraphicBufferProducer::dequeueBuffer(%d, %d, %d, %d)" + "failed: %d", mReqWidth, mReqHeight, mReqFormat, mReqUsage, + result); + return result; } - parcel->writeStrongBinder(sur!=0 ? sur->asBinder() : NULL); - parcel->writeStrongBinder(NULL); // NULL ISurfaceTexture in this case. - parcel->writeInt32(identity); - return NO_ERROR; + sp<GraphicBuffer>& gbuf(mSlots[buf].buffer); + if (result & IGraphicBufferProducer::RELEASE_ALL_BUFFERS) { + freeAllBuffers(); + } + + if ((result & IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION) || gbuf == 0) { + result = mGraphicBufferProducer->requestBuffer(buf, &gbuf); + if (result != NO_ERROR) { + ALOGE("dequeueBuffer: IGraphicBufferProducer::requestBuffer failed: %d", + result); + return result; + } + } + + if (fence->isValid()) { + *fenceFd = fence->dup(); + if (*fenceFd == -1) { + ALOGE("dequeueBuffer: error duping fence: %d", errno); + // dup() should never fail; something is badly wrong. Soldier on + // and hope for the best; the worst that should happen is some + // visible corruption that lasts until the next frame. + } + } else { + *fenceFd = -1; + } + + *buffer = gbuf.get(); + return OK; } -sp<Surface> SurfaceControl::getSurface() const -{ - Mutex::Autolock _l(mLock); - if (mSurfaceData == 0) { - sp<SurfaceControl> surface_control(const_cast<SurfaceControl*>(this)); - mSurfaceData = new Surface(surface_control); +int Surface::cancelBuffer(android_native_buffer_t* buffer, + int fenceFd) { + ATRACE_CALL(); + ALOGV("Surface::cancelBuffer"); + Mutex::Autolock lock(mMutex); + int i = getSlotFromBufferLocked(buffer); + if (i < 0) { + return i; + } + sp<Fence> fence(fenceFd >= 0 ? new Fence(fenceFd) : Fence::NO_FENCE); + mGraphicBufferProducer->cancelBuffer(i, fence); + return OK; +} + +int Surface::getSlotFromBufferLocked( + android_native_buffer_t* buffer) const { + bool dumpedState = false; + for (int i = 0; i < NUM_BUFFER_SLOTS; i++) { + if (mSlots[i].buffer != NULL && + mSlots[i].buffer->handle == buffer->handle) { + return i; + } } - return mSurfaceData; + ALOGE("getSlotFromBufferLocked: unknown buffer: %p", buffer->handle); + return BAD_VALUE; } -// ============================================================================ -// Surface -// ============================================================================ +int Surface::lockBuffer_DEPRECATED(android_native_buffer_t* buffer) { + ALOGV("Surface::lockBuffer"); + Mutex::Autolock lock(mMutex); + return OK; +} -// --------------------------------------------------------------------------- +int Surface::queueBuffer(android_native_buffer_t* buffer, int fenceFd) { + ATRACE_CALL(); + ALOGV("Surface::queueBuffer"); + Mutex::Autolock lock(mMutex); + int64_t timestamp; + if (mTimestamp == NATIVE_WINDOW_TIMESTAMP_AUTO) { + timestamp = systemTime(SYSTEM_TIME_MONOTONIC); + ALOGV("Surface::queueBuffer making up timestamp: %.2f ms", + timestamp / 1000000.f); + } else { + timestamp = mTimestamp; + } + int i = getSlotFromBufferLocked(buffer); + if (i < 0) { + return i; + } -Surface::Surface(const sp<SurfaceControl>& surface) - : SurfaceTextureClient(), - mSurface(surface->mSurface), - mIdentity(surface->mIdentity) -{ - sp<ISurfaceTexture> st; - if (mSurface != NULL) { - st = mSurface->getSurfaceTexture(); + + // Make sure the crop rectangle is entirely inside the buffer. + Rect crop; + mCrop.intersect(Rect(buffer->width, buffer->height), &crop); + + sp<Fence> fence(fenceFd >= 0 ? new Fence(fenceFd) : Fence::NO_FENCE); + IGraphicBufferProducer::QueueBufferOutput output; + IGraphicBufferProducer::QueueBufferInput input(timestamp, crop, mScalingMode, + mTransform, fence); + status_t err = mGraphicBufferProducer->queueBuffer(i, input, &output); + if (err != OK) { + ALOGE("queueBuffer: error queuing buffer to SurfaceTexture, %d", err); + } + uint32_t numPendingBuffers = 0; + output.deflate(&mDefaultWidth, &mDefaultHeight, &mTransformHint, + &numPendingBuffers); + + mConsumerRunningBehind = (numPendingBuffers >= 2); + + return err; +} + +int Surface::query(int what, int* value) const { + ATRACE_CALL(); + ALOGV("Surface::query"); + { // scope for the lock + Mutex::Autolock lock(mMutex); + switch (what) { + case NATIVE_WINDOW_FORMAT: + if (mReqFormat) { + *value = mReqFormat; + return NO_ERROR; + } + break; + case NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER: { + sp<ISurfaceComposer> composer( + ComposerService::getComposerService()); + if (composer->authenticateSurfaceTexture(mGraphicBufferProducer)) { + *value = 1; + } else { + *value = 0; + } + return NO_ERROR; + } + case NATIVE_WINDOW_CONCRETE_TYPE: + *value = NATIVE_WINDOW_SURFACE; + return NO_ERROR; + case NATIVE_WINDOW_DEFAULT_WIDTH: + *value = mUserWidth ? mUserWidth : mDefaultWidth; + return NO_ERROR; + case NATIVE_WINDOW_DEFAULT_HEIGHT: + *value = mUserHeight ? mUserHeight : mDefaultHeight; + return NO_ERROR; + case NATIVE_WINDOW_TRANSFORM_HINT: + *value = mTransformHint; + return NO_ERROR; + case NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND: { + status_t err = NO_ERROR; + if (!mConsumerRunningBehind) { + *value = 0; + } else { + err = mGraphicBufferProducer->query(what, value); + if (err == NO_ERROR) { + mConsumerRunningBehind = *value; + } + } + return err; + } + } } - init(st); + return mGraphicBufferProducer->query(what, value); } -Surface::Surface(const Parcel& parcel, const sp<IBinder>& ref) - : SurfaceTextureClient() +int Surface::perform(int operation, va_list args) { - mSurface = interface_cast<ISurface>(ref); - sp<IBinder> st_binder(parcel.readStrongBinder()); - sp<ISurfaceTexture> st; - if (st_binder != NULL) { - st = interface_cast<ISurfaceTexture>(st_binder); - } else if (mSurface != NULL) { - st = mSurface->getSurfaceTexture(); + int res = NO_ERROR; + switch (operation) { + case NATIVE_WINDOW_CONNECT: + // deprecated. must return NO_ERROR. + break; + case NATIVE_WINDOW_DISCONNECT: + // deprecated. must return NO_ERROR. + break; + case NATIVE_WINDOW_SET_USAGE: + res = dispatchSetUsage(args); + break; + case NATIVE_WINDOW_SET_CROP: + res = dispatchSetCrop(args); + break; + case NATIVE_WINDOW_SET_BUFFER_COUNT: + res = dispatchSetBufferCount(args); + break; + case NATIVE_WINDOW_SET_BUFFERS_GEOMETRY: + res = dispatchSetBuffersGeometry(args); + break; + case NATIVE_WINDOW_SET_BUFFERS_TRANSFORM: + res = dispatchSetBuffersTransform(args); + break; + case NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP: + res = dispatchSetBuffersTimestamp(args); + break; + case NATIVE_WINDOW_SET_BUFFERS_DIMENSIONS: + res = dispatchSetBuffersDimensions(args); + break; + case NATIVE_WINDOW_SET_BUFFERS_USER_DIMENSIONS: + res = dispatchSetBuffersUserDimensions(args); + break; + case NATIVE_WINDOW_SET_BUFFERS_FORMAT: + res = dispatchSetBuffersFormat(args); + break; + case NATIVE_WINDOW_LOCK: + res = dispatchLock(args); + break; + case NATIVE_WINDOW_UNLOCK_AND_POST: + res = dispatchUnlockAndPost(args); + break; + case NATIVE_WINDOW_SET_SCALING_MODE: + res = dispatchSetScalingMode(args); + break; + case NATIVE_WINDOW_API_CONNECT: + res = dispatchConnect(args); + break; + case NATIVE_WINDOW_API_DISCONNECT: + res = dispatchDisconnect(args); + break; + default: + res = NAME_NOT_FOUND; + break; } + return res; +} - mIdentity = parcel.readInt32(); - init(st); +int Surface::dispatchConnect(va_list args) { + int api = va_arg(args, int); + return connect(api); } -Surface::Surface(const sp<ISurfaceTexture>& st) - : SurfaceTextureClient(), - mSurface(NULL), - mIdentity(0) -{ - init(st); +int Surface::dispatchDisconnect(va_list args) { + int api = va_arg(args, int); + return disconnect(api); } -status_t Surface::writeToParcel( - const sp<Surface>& surface, Parcel* parcel) -{ - sp<ISurface> sur; - sp<ISurfaceTexture> st; - uint32_t identity = 0; - if (Surface::isValid(surface)) { - sur = surface->mSurface; - st = surface->getISurfaceTexture(); - identity = surface->mIdentity; - } else if (surface != 0 && - (surface->mSurface != NULL || - surface->getISurfaceTexture() != NULL)) { - ALOGE("Parceling invalid surface with non-NULL ISurface/ISurfaceTexture as NULL: " - "mSurface = %p, surfaceTexture = %p, mIdentity = %d, ", - surface->mSurface.get(), surface->getISurfaceTexture().get(), - surface->mIdentity); +int Surface::dispatchSetUsage(va_list args) { + int usage = va_arg(args, int); + return setUsage(usage); +} + +int Surface::dispatchSetCrop(va_list args) { + android_native_rect_t const* rect = va_arg(args, android_native_rect_t*); + return setCrop(reinterpret_cast<Rect const*>(rect)); +} + +int Surface::dispatchSetBufferCount(va_list args) { + size_t bufferCount = va_arg(args, size_t); + return setBufferCount(bufferCount); +} + +int Surface::dispatchSetBuffersGeometry(va_list args) { + int w = va_arg(args, int); + int h = va_arg(args, int); + int f = va_arg(args, int); + int err = setBuffersDimensions(w, h); + if (err != 0) { + return err; } + return setBuffersFormat(f); +} - parcel->writeStrongBinder(sur != NULL ? sur->asBinder() : NULL); - parcel->writeStrongBinder(st != NULL ? st->asBinder() : NULL); - parcel->writeInt32(identity); - return NO_ERROR; +int Surface::dispatchSetBuffersDimensions(va_list args) { + int w = va_arg(args, int); + int h = va_arg(args, int); + return setBuffersDimensions(w, h); +} +int Surface::dispatchSetBuffersUserDimensions(va_list args) { + int w = va_arg(args, int); + int h = va_arg(args, int); + return setBuffersUserDimensions(w, h); } -Mutex Surface::sCachedSurfacesLock; -DefaultKeyedVector<wp<IBinder>, wp<Surface> > Surface::sCachedSurfaces; +int Surface::dispatchSetBuffersFormat(va_list args) { + int f = va_arg(args, int); + return setBuffersFormat(f); +} -sp<Surface> Surface::readFromParcel(const Parcel& data) { - Mutex::Autolock _l(sCachedSurfacesLock); - sp<IBinder> binder(data.readStrongBinder()); - sp<Surface> surface = sCachedSurfaces.valueFor(binder).promote(); - if (surface == 0) { - surface = new Surface(data, binder); - sCachedSurfaces.add(binder, surface); - } else { - // The Surface was found in the cache, but we still should clear any - // remaining data from the parcel. - data.readStrongBinder(); // ISurfaceTexture - data.readInt32(); // identity +int Surface::dispatchSetScalingMode(va_list args) { + int m = va_arg(args, int); + return setScalingMode(m); +} + +int Surface::dispatchSetBuffersTransform(va_list args) { + int transform = va_arg(args, int); + return setBuffersTransform(transform); +} + +int Surface::dispatchSetBuffersTimestamp(va_list args) { + int64_t timestamp = va_arg(args, int64_t); + return setBuffersTimestamp(timestamp); +} + +int Surface::dispatchLock(va_list args) { + ANativeWindow_Buffer* outBuffer = va_arg(args, ANativeWindow_Buffer*); + ARect* inOutDirtyBounds = va_arg(args, ARect*); + return lock(outBuffer, inOutDirtyBounds); +} + +int Surface::dispatchUnlockAndPost(va_list args) { + return unlockAndPost(); +} + + +int Surface::connect(int api) { + ATRACE_CALL(); + ALOGV("Surface::connect"); + Mutex::Autolock lock(mMutex); + IGraphicBufferProducer::QueueBufferOutput output; + int err = mGraphicBufferProducer->connect(api, &output); + if (err == NO_ERROR) { + uint32_t numPendingBuffers = 0; + output.deflate(&mDefaultWidth, &mDefaultHeight, &mTransformHint, + &numPendingBuffers); + mConsumerRunningBehind = (numPendingBuffers >= 2); } - if (surface->mSurface == NULL && surface->getISurfaceTexture() == NULL) { - surface = 0; + if (!err && api == NATIVE_WINDOW_API_CPU) { + mConnectedToCpu = true; } - cleanCachedSurfacesLocked(); - return surface; + return err; } -// Remove the stale entries from the surface cache. This should only be called -// with sCachedSurfacesLock held. -void Surface::cleanCachedSurfacesLocked() { - for (int i = sCachedSurfaces.size()-1; i >= 0; --i) { - wp<Surface> s(sCachedSurfaces.valueAt(i)); - if (s == 0 || s.promote() == 0) { - sCachedSurfaces.removeItemsAt(i); +int Surface::disconnect(int api) { + ATRACE_CALL(); + ALOGV("Surface::disconnect"); + Mutex::Autolock lock(mMutex); + freeAllBuffers(); + int err = mGraphicBufferProducer->disconnect(api); + if (!err) { + mReqFormat = 0; + mReqWidth = 0; + mReqHeight = 0; + mReqUsage = 0; + mCrop.clear(); + mScalingMode = NATIVE_WINDOW_SCALING_MODE_FREEZE; + mTransform = 0; + if (api == NATIVE_WINDOW_API_CPU) { + mConnectedToCpu = false; } } + return err; } -void Surface::init(const sp<ISurfaceTexture>& surfaceTexture) +int Surface::setUsage(uint32_t reqUsage) { - if (mSurface != NULL || surfaceTexture != NULL) { - ALOGE_IF(surfaceTexture==0, "got a NULL ISurfaceTexture from ISurface"); - if (surfaceTexture != NULL) { - setISurfaceTexture(surfaceTexture); - setUsage(GraphicBuffer::USAGE_HW_RENDER); - } + ALOGV("Surface::setUsage"); + Mutex::Autolock lock(mMutex); + mReqUsage = reqUsage; + return OK; +} + +int Surface::setCrop(Rect const* rect) +{ + ATRACE_CALL(); - // TODO: the display metrics should come from the display manager - DisplayInfo dinfo; - sp<IBinder> display = SurfaceComposerClient::getBuiltInDisplay( - ISurfaceComposer::eDisplayIdMain); - SurfaceComposerClient::getDisplayInfo(display, &dinfo); - const_cast<float&>(ANativeWindow::xdpi) = dinfo.xdpi; - const_cast<float&>(ANativeWindow::ydpi) = dinfo.ydpi; - const_cast<uint32_t&>(ANativeWindow::flags) = 0; + Rect realRect; + if (rect == NULL || rect->isEmpty()) { + realRect.clear(); + } else { + realRect = *rect; } + + ALOGV("Surface::setCrop rect=[%d %d %d %d]", + realRect.left, realRect.top, realRect.right, realRect.bottom); + + Mutex::Autolock lock(mMutex); + mCrop = realRect; + return NO_ERROR; } -Surface::~Surface() +int Surface::setBufferCount(int bufferCount) { - // clear all references and trigger an IPC now, to make sure things - // happen without delay, since these resources are quite heavy. - mSurface.clear(); - IPCThreadState::self()->flushCommands(); -} + ATRACE_CALL(); + ALOGV("Surface::setBufferCount"); + Mutex::Autolock lock(mMutex); + + status_t err = mGraphicBufferProducer->setBufferCount(bufferCount); + ALOGE_IF(err, "IGraphicBufferProducer::setBufferCount(%d) returned %s", + bufferCount, strerror(-err)); -bool Surface::isValid() { - return getISurfaceTexture() != NULL; + if (err == NO_ERROR) { + freeAllBuffers(); + } + + return err; } -sp<ISurfaceTexture> Surface::getSurfaceTexture() { - return getISurfaceTexture(); +int Surface::setBuffersDimensions(int w, int h) +{ + ATRACE_CALL(); + ALOGV("Surface::setBuffersDimensions"); + + if (w<0 || h<0) + return BAD_VALUE; + + if ((w && !h) || (!w && h)) + return BAD_VALUE; + + Mutex::Autolock lock(mMutex); + mReqWidth = w; + mReqHeight = h; + return NO_ERROR; } -sp<IBinder> Surface::asBinder() const { - return mSurface!=0 ? mSurface->asBinder() : 0; +int Surface::setBuffersUserDimensions(int w, int h) +{ + ATRACE_CALL(); + ALOGV("Surface::setBuffersUserDimensions"); + + if (w<0 || h<0) + return BAD_VALUE; + + if ((w && !h) || (!w && h)) + return BAD_VALUE; + + Mutex::Autolock lock(mMutex); + mUserWidth = w; + mUserHeight = h; + return NO_ERROR; } -// ---------------------------------------------------------------------------- +int Surface::setBuffersFormat(int format) +{ + ALOGV("Surface::setBuffersFormat"); -int Surface::query(int what, int* value) const { - switch (what) { - case NATIVE_WINDOW_CONCRETE_TYPE: - *value = NATIVE_WINDOW_SURFACE; - return NO_ERROR; + if (format<0) + return BAD_VALUE; + + Mutex::Autolock lock(mMutex); + mReqFormat = format; + return NO_ERROR; +} + +int Surface::setScalingMode(int mode) +{ + ATRACE_CALL(); + ALOGV("Surface::setScalingMode(%d)", mode); + + switch (mode) { + case NATIVE_WINDOW_SCALING_MODE_FREEZE: + case NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW: + case NATIVE_WINDOW_SCALING_MODE_SCALE_CROP: + break; + default: + ALOGE("unknown scaling mode: %d", mode); + return BAD_VALUE; } - return SurfaceTextureClient::query(what, value); + + Mutex::Autolock lock(mMutex); + mScalingMode = mode; + return NO_ERROR; } -// ---------------------------------------------------------------------------- +int Surface::setBuffersTransform(int transform) +{ + ATRACE_CALL(); + ALOGV("Surface::setBuffersTransform"); + Mutex::Autolock lock(mMutex); + mTransform = transform; + return NO_ERROR; +} -status_t Surface::lock(SurfaceInfo* other, Region* inOutDirtyRegion) { - ANativeWindow_Buffer outBuffer; +int Surface::setBuffersTimestamp(int64_t timestamp) +{ + ALOGV("Surface::setBuffersTimestamp"); + Mutex::Autolock lock(mMutex); + mTimestamp = timestamp; + return NO_ERROR; +} - ARect temp; - ARect* inOutDirtyBounds = NULL; - if (inOutDirtyRegion) { - temp = inOutDirtyRegion->getBounds(); - inOutDirtyBounds = &temp; +void Surface::freeAllBuffers() { + for (int i = 0; i < NUM_BUFFER_SLOTS; i++) { + mSlots[i].buffer = 0; } +} - status_t err = SurfaceTextureClient::lock(&outBuffer, inOutDirtyBounds); +// ---------------------------------------------------------------------- +// the lock/unlock APIs must be used from the same thread - if (err == NO_ERROR) { - other->w = uint32_t(outBuffer.width); - other->h = uint32_t(outBuffer.height); - other->s = uint32_t(outBuffer.stride); - other->usage = GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN; - other->format = uint32_t(outBuffer.format); - other->bits = outBuffer.bits; +static status_t copyBlt( + const sp<GraphicBuffer>& dst, + const sp<GraphicBuffer>& src, + const Region& reg) +{ + // src and dst with, height and format must be identical. no verification + // is done here. + status_t err; + uint8_t const * src_bits = NULL; + err = src->lock(GRALLOC_USAGE_SW_READ_OFTEN, reg.bounds(), (void**)&src_bits); + ALOGE_IF(err, "error locking src buffer %s", strerror(-err)); + + uint8_t* dst_bits = NULL; + err = dst->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, reg.bounds(), (void**)&dst_bits); + ALOGE_IF(err, "error locking dst buffer %s", strerror(-err)); + + Region::const_iterator head(reg.begin()); + Region::const_iterator tail(reg.end()); + if (head != tail && src_bits && dst_bits) { + const size_t bpp = bytesPerPixel(src->format); + const size_t dbpr = dst->stride * bpp; + const size_t sbpr = src->stride * bpp; + + while (head != tail) { + const Rect& r(*head++); + ssize_t h = r.height(); + if (h <= 0) continue; + size_t size = r.width() * bpp; + uint8_t const * s = src_bits + (r.left + src->stride * r.top) * bpp; + uint8_t * d = dst_bits + (r.left + dst->stride * r.top) * bpp; + if (dbpr==sbpr && size==sbpr) { + size *= h; + h = 1; + } + do { + memcpy(d, s, size); + d += dbpr; + s += sbpr; + } while (--h > 0); + } } - if (inOutDirtyRegion) { - inOutDirtyRegion->set( static_cast<Rect const&>(temp) ); + if (src_bits) + src->unlock(); + + if (dst_bits) + dst->unlock(); + + return err; +} + +// ---------------------------------------------------------------------------- + +status_t Surface::lock( + ANativeWindow_Buffer* outBuffer, ARect* inOutDirtyBounds) +{ + if (mLockedBuffer != 0) { + ALOGE("Surface::lock failed, already locked"); + return INVALID_OPERATION; } + if (!mConnectedToCpu) { + int err = Surface::connect(NATIVE_WINDOW_API_CPU); + if (err) { + return err; + } + // we're intending to do software rendering from this point + setUsage(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN); + } + + ANativeWindowBuffer* out; + int fenceFd = -1; + status_t err = dequeueBuffer(&out, &fenceFd); + ALOGE_IF(err, "dequeueBuffer failed (%s)", strerror(-err)); + if (err == NO_ERROR) { + sp<GraphicBuffer> backBuffer(GraphicBuffer::getSelf(out)); + sp<Fence> fence(new Fence(fenceFd)); + + err = fence->waitForever("Surface::lock"); + if (err != OK) { + ALOGE("Fence::wait failed (%s)", strerror(-err)); + cancelBuffer(out, fenceFd); + return err; + } + + const Rect bounds(backBuffer->width, backBuffer->height); + + Region newDirtyRegion; + if (inOutDirtyBounds) { + newDirtyRegion.set(static_cast<Rect const&>(*inOutDirtyBounds)); + newDirtyRegion.andSelf(bounds); + } else { + newDirtyRegion.set(bounds); + } + + // figure out if we can copy the frontbuffer back + const sp<GraphicBuffer>& frontBuffer(mPostedBuffer); + const bool canCopyBack = (frontBuffer != 0 && + backBuffer->width == frontBuffer->width && + backBuffer->height == frontBuffer->height && + backBuffer->format == frontBuffer->format); + + if (canCopyBack) { + // copy the area that is invalid and not repainted this round + const Region copyback(mDirtyRegion.subtract(newDirtyRegion)); + if (!copyback.isEmpty()) + copyBlt(backBuffer, frontBuffer, copyback); + } else { + // if we can't copy-back anything, modify the user's dirty + // region to make sure they redraw the whole buffer + newDirtyRegion.set(bounds); + mDirtyRegion.clear(); + Mutex::Autolock lock(mMutex); + for (size_t i=0 ; i<NUM_BUFFER_SLOTS ; i++) { + mSlots[i].dirtyRegion.clear(); + } + } + + + { // scope for the lock + Mutex::Autolock lock(mMutex); + int backBufferSlot(getSlotFromBufferLocked(backBuffer.get())); + if (backBufferSlot >= 0) { + Region& dirtyRegion(mSlots[backBufferSlot].dirtyRegion); + mDirtyRegion.subtract(dirtyRegion); + dirtyRegion = newDirtyRegion; + } + } + + mDirtyRegion.orSelf(newDirtyRegion); + if (inOutDirtyBounds) { + *inOutDirtyBounds = newDirtyRegion.getBounds(); + } + + void* vaddr; + status_t res = backBuffer->lock( + GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN, + newDirtyRegion.bounds(), &vaddr); + + ALOGW_IF(res, "failed locking buffer (handle = %p)", + backBuffer->handle); + + if (res != 0) { + err = INVALID_OPERATION; + } else { + mLockedBuffer = backBuffer; + outBuffer->width = backBuffer->width; + outBuffer->height = backBuffer->height; + outBuffer->stride = backBuffer->stride; + outBuffer->format = backBuffer->format; + outBuffer->bits = vaddr; + } + } return err; } -status_t Surface::unlockAndPost() { - return SurfaceTextureClient::unlockAndPost(); +status_t Surface::unlockAndPost() +{ + if (mLockedBuffer == 0) { + ALOGE("Surface::unlockAndPost failed, no locked buffer"); + return INVALID_OPERATION; + } + + status_t err = mLockedBuffer->unlock(); + ALOGE_IF(err, "failed unlocking buffer (%p)", mLockedBuffer->handle); + + err = queueBuffer(mLockedBuffer.get(), -1); + ALOGE_IF(err, "queueBuffer (handle=%p) failed (%s)", + mLockedBuffer->handle, strerror(-err)); + + mPostedBuffer = mLockedBuffer; + mLockedBuffer = 0; + return err; } -// ---------------------------------------------------------------------------- }; // namespace android diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 80dd6ee..f345df8 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -31,7 +31,8 @@ #include <ui/DisplayInfo.h> -#include <gui/ISurface.h> +#include <gui/CpuConsumer.h> +#include <gui/IGraphicBufferProducer.h> #include <gui/ISurfaceComposer.h> #include <gui/ISurfaceComposerClient.h> #include <gui/SurfaceComposerClient.h> @@ -115,18 +116,20 @@ class Composer : public Singleton<Composer> SortedVector<ComposerState> mComposerStates; SortedVector<DisplayState > mDisplayStates; uint32_t mForceSynchronous; + uint32_t mTransactionNestCount; bool mAnimation; Composer() : Singleton<Composer>(), - mForceSynchronous(0), + mForceSynchronous(0), mTransactionNestCount(0), mAnimation(false) { } + void openGlobalTransactionImpl(); void closeGlobalTransactionImpl(bool synchronous); void setAnimationTransactionImpl(); layer_state_t* getLayerStateLocked( - const sp<SurfaceComposerClient>& client, SurfaceID id); + const sp<SurfaceComposerClient>& client, const sp<IBinder>& id); DisplayState& getDisplayStateLocked(const sp<IBinder>& token); @@ -134,28 +137,29 @@ public: sp<IBinder> createDisplay(const String8& displayName, bool secure); sp<IBinder> getBuiltInDisplay(int32_t id); - status_t setPosition(const sp<SurfaceComposerClient>& client, SurfaceID id, + status_t setPosition(const sp<SurfaceComposerClient>& client, const sp<IBinder>& id, float x, float y); - status_t setSize(const sp<SurfaceComposerClient>& client, SurfaceID id, + status_t setSize(const sp<SurfaceComposerClient>& client, const sp<IBinder>& id, uint32_t w, uint32_t h); - status_t setLayer(const sp<SurfaceComposerClient>& client, SurfaceID id, + status_t setLayer(const sp<SurfaceComposerClient>& client, const sp<IBinder>& id, int32_t z); - status_t setFlags(const sp<SurfaceComposerClient>& client, SurfaceID id, + status_t setFlags(const sp<SurfaceComposerClient>& client, const sp<IBinder>& id, uint32_t flags, uint32_t mask); status_t setTransparentRegionHint( - const sp<SurfaceComposerClient>& client, SurfaceID id, + const sp<SurfaceComposerClient>& client, const sp<IBinder>& id, const Region& transparentRegion); - status_t setAlpha(const sp<SurfaceComposerClient>& client, SurfaceID id, + status_t setAlpha(const sp<SurfaceComposerClient>& client, const sp<IBinder>& id, float alpha); - status_t setMatrix(const sp<SurfaceComposerClient>& client, SurfaceID id, + status_t setMatrix(const sp<SurfaceComposerClient>& client, const sp<IBinder>& id, float dsdx, float dtdx, float dsdy, float dtdy); status_t setOrientation(int orientation); - status_t setCrop(const sp<SurfaceComposerClient>& client, SurfaceID id, + status_t setCrop(const sp<SurfaceComposerClient>& client, const sp<IBinder>& id, const Rect& crop); status_t setLayerStack(const sp<SurfaceComposerClient>& client, - SurfaceID id, uint32_t layerStack); + const sp<IBinder>& id, uint32_t layerStack); - void setDisplaySurface(const sp<IBinder>& token, const sp<ISurfaceTexture>& surface); + void setDisplaySurface(const sp<IBinder>& token, + const sp<IGraphicBufferProducer>& bufferProducer); void setDisplayLayerStack(const sp<IBinder>& token, uint32_t layerStack); void setDisplayProjection(const sp<IBinder>& token, uint32_t orientation, @@ -166,6 +170,10 @@ public: Composer::getInstance().setAnimationTransactionImpl(); } + static void openGlobalTransaction() { + Composer::getInstance().openGlobalTransactionImpl(); + } + static void closeGlobalTransaction(bool synchronous) { Composer::getInstance().closeGlobalTransactionImpl(synchronous); } @@ -184,6 +192,13 @@ sp<IBinder> Composer::getBuiltInDisplay(int32_t id) { return ComposerService::getComposerService()->getBuiltInDisplay(id); } +void Composer::openGlobalTransactionImpl() { + { // scope for the lock + Mutex::Autolock _l(mLock); + mTransactionNestCount += 1; + } +} + void Composer::closeGlobalTransactionImpl(bool synchronous) { sp<ISurfaceComposer> sm(ComposerService::getComposerService()); @@ -193,13 +208,21 @@ void Composer::closeGlobalTransactionImpl(bool synchronous) { { // scope for the lock Mutex::Autolock _l(mLock); + mForceSynchronous |= synchronous; + if (!mTransactionNestCount) { + ALOGW("At least one call to closeGlobalTransaction() was not matched by a prior " + "call to openGlobalTransaction()."); + } else if (--mTransactionNestCount) { + return; + } + transaction = mComposerStates; mComposerStates.clear(); displayTransaction = mDisplayStates; mDisplayStates.clear(); - if (synchronous || mForceSynchronous) { + if (mForceSynchronous) { flags |= ISurfaceComposer::eSynchronous; } if (mAnimation) { @@ -219,7 +242,7 @@ void Composer::setAnimationTransactionImpl() { } layer_state_t* Composer::getLayerStateLocked( - const sp<SurfaceComposerClient>& client, SurfaceID id) { + const sp<SurfaceComposerClient>& client, const sp<IBinder>& id) { ComposerState s; s.client = client->mClient; @@ -236,7 +259,7 @@ layer_state_t* Composer::getLayerStateLocked( } status_t Composer::setPosition(const sp<SurfaceComposerClient>& client, - SurfaceID id, float x, float y) { + const sp<IBinder>& id, float x, float y) { Mutex::Autolock _l(mLock); layer_state_t* s = getLayerStateLocked(client, id); if (!s) @@ -248,7 +271,7 @@ status_t Composer::setPosition(const sp<SurfaceComposerClient>& client, } status_t Composer::setSize(const sp<SurfaceComposerClient>& client, - SurfaceID id, uint32_t w, uint32_t h) { + const sp<IBinder>& id, uint32_t w, uint32_t h) { Mutex::Autolock _l(mLock); layer_state_t* s = getLayerStateLocked(client, id); if (!s) @@ -264,7 +287,7 @@ status_t Composer::setSize(const sp<SurfaceComposerClient>& client, } status_t Composer::setLayer(const sp<SurfaceComposerClient>& client, - SurfaceID id, int32_t z) { + const sp<IBinder>& id, int32_t z) { Mutex::Autolock _l(mLock); layer_state_t* s = getLayerStateLocked(client, id); if (!s) @@ -275,7 +298,7 @@ status_t Composer::setLayer(const sp<SurfaceComposerClient>& client, } status_t Composer::setFlags(const sp<SurfaceComposerClient>& client, - SurfaceID id, uint32_t flags, + const sp<IBinder>& id, uint32_t flags, uint32_t mask) { Mutex::Autolock _l(mLock); layer_state_t* s = getLayerStateLocked(client, id); @@ -289,7 +312,7 @@ status_t Composer::setFlags(const sp<SurfaceComposerClient>& client, } status_t Composer::setTransparentRegionHint( - const sp<SurfaceComposerClient>& client, SurfaceID id, + const sp<SurfaceComposerClient>& client, const sp<IBinder>& id, const Region& transparentRegion) { Mutex::Autolock _l(mLock); layer_state_t* s = getLayerStateLocked(client, id); @@ -301,7 +324,7 @@ status_t Composer::setTransparentRegionHint( } status_t Composer::setAlpha(const sp<SurfaceComposerClient>& client, - SurfaceID id, float alpha) { + const sp<IBinder>& id, float alpha) { Mutex::Autolock _l(mLock); layer_state_t* s = getLayerStateLocked(client, id); if (!s) @@ -312,7 +335,7 @@ status_t Composer::setAlpha(const sp<SurfaceComposerClient>& client, } status_t Composer::setLayerStack(const sp<SurfaceComposerClient>& client, - SurfaceID id, uint32_t layerStack) { + const sp<IBinder>& id, uint32_t layerStack) { Mutex::Autolock _l(mLock); layer_state_t* s = getLayerStateLocked(client, id); if (!s) @@ -323,7 +346,7 @@ status_t Composer::setLayerStack(const sp<SurfaceComposerClient>& client, } status_t Composer::setMatrix(const sp<SurfaceComposerClient>& client, - SurfaceID id, float dsdx, float dtdx, + const sp<IBinder>& id, float dsdx, float dtdx, float dsdy, float dtdy) { Mutex::Autolock _l(mLock); layer_state_t* s = getLayerStateLocked(client, id); @@ -340,7 +363,7 @@ status_t Composer::setMatrix(const sp<SurfaceComposerClient>& client, } status_t Composer::setCrop(const sp<SurfaceComposerClient>& client, - SurfaceID id, const Rect& crop) { + const sp<IBinder>& id, const Rect& crop) { Mutex::Autolock _l(mLock); layer_state_t* s = getLayerStateLocked(client, id); if (!s) @@ -365,10 +388,10 @@ DisplayState& Composer::getDisplayStateLocked(const sp<IBinder>& token) { } void Composer::setDisplaySurface(const sp<IBinder>& token, - const sp<ISurfaceTexture>& surface) { + const sp<IGraphicBufferProducer>& bufferProducer) { Mutex::Autolock _l(mLock); DisplayState& s(getDisplayStateLocked(token)); - s.surface = surface; + s.surface = bufferProducer; s.what |= DisplayState::eSurfaceChanged; } @@ -448,16 +471,18 @@ sp<SurfaceControl> SurfaceComposerClient::createSurface( PixelFormat format, uint32_t flags) { - sp<SurfaceControl> result; + sp<SurfaceControl> sur; if (mStatus == NO_ERROR) { - ISurfaceComposerClient::surface_data_t data; - sp<ISurface> surface = mClient->createSurface(&data, name, - w, h, format, flags); - if (surface != 0) { - result = new SurfaceControl(this, surface, data); + sp<IBinder> handle; + sp<IGraphicBufferProducer> gbp; + status_t err = mClient->createSurface(name, w, h, format, flags, + &handle, &gbp); + ALOGE_IF(err, "SurfaceComposerClient::createSurface error %s", strerror(-err)); + if (err == NO_ERROR) { + sur = new SurfaceControl(this, handle, gbp); } } - return result; + return sur; } sp<IBinder> SurfaceComposerClient::createDisplay(const String8& displayName, @@ -469,7 +494,7 @@ sp<IBinder> SurfaceComposerClient::getBuiltInDisplay(int32_t id) { return Composer::getInstance().getBuiltInDisplay(id); } -status_t SurfaceComposerClient::destroySurface(SurfaceID sid) { +status_t SurfaceComposerClient::destroySurface(const sp<IBinder>& sid) { if (mStatus != NO_ERROR) return mStatus; status_t err = mClient->destroySurface(sid); @@ -483,7 +508,7 @@ inline Composer& SurfaceComposerClient::getComposer() { // ---------------------------------------------------------------------------- void SurfaceComposerClient::openGlobalTransaction() { - // Currently a no-op + Composer::openGlobalTransaction(); } void SurfaceComposerClient::closeGlobalTransaction(bool synchronous) { @@ -496,53 +521,53 @@ void SurfaceComposerClient::setAnimationTransaction() { // ---------------------------------------------------------------------------- -status_t SurfaceComposerClient::setCrop(SurfaceID id, const Rect& crop) { +status_t SurfaceComposerClient::setCrop(const sp<IBinder>& id, const Rect& crop) { return getComposer().setCrop(this, id, crop); } -status_t SurfaceComposerClient::setPosition(SurfaceID id, float x, float y) { +status_t SurfaceComposerClient::setPosition(const sp<IBinder>& id, float x, float y) { return getComposer().setPosition(this, id, x, y); } -status_t SurfaceComposerClient::setSize(SurfaceID id, uint32_t w, uint32_t h) { +status_t SurfaceComposerClient::setSize(const sp<IBinder>& id, uint32_t w, uint32_t h) { return getComposer().setSize(this, id, w, h); } -status_t SurfaceComposerClient::setLayer(SurfaceID id, int32_t z) { +status_t SurfaceComposerClient::setLayer(const sp<IBinder>& id, int32_t z) { return getComposer().setLayer(this, id, z); } -status_t SurfaceComposerClient::hide(SurfaceID id) { +status_t SurfaceComposerClient::hide(const sp<IBinder>& id) { return getComposer().setFlags(this, id, layer_state_t::eLayerHidden, layer_state_t::eLayerHidden); } -status_t SurfaceComposerClient::show(SurfaceID id) { +status_t SurfaceComposerClient::show(const sp<IBinder>& id) { return getComposer().setFlags(this, id, 0, layer_state_t::eLayerHidden); } -status_t SurfaceComposerClient::setFlags(SurfaceID id, uint32_t flags, +status_t SurfaceComposerClient::setFlags(const sp<IBinder>& id, uint32_t flags, uint32_t mask) { return getComposer().setFlags(this, id, flags, mask); } -status_t SurfaceComposerClient::setTransparentRegionHint(SurfaceID id, +status_t SurfaceComposerClient::setTransparentRegionHint(const sp<IBinder>& id, const Region& transparentRegion) { return getComposer().setTransparentRegionHint(this, id, transparentRegion); } -status_t SurfaceComposerClient::setAlpha(SurfaceID id, float alpha) { +status_t SurfaceComposerClient::setAlpha(const sp<IBinder>& id, float alpha) { return getComposer().setAlpha(this, id, alpha); } -status_t SurfaceComposerClient::setLayerStack(SurfaceID id, uint32_t layerStack) { +status_t SurfaceComposerClient::setLayerStack(const sp<IBinder>& id, uint32_t layerStack) { return getComposer().setLayerStack(this, id, layerStack); } -status_t SurfaceComposerClient::setMatrix(SurfaceID id, float dsdx, float dtdx, +status_t SurfaceComposerClient::setMatrix(const sp<IBinder>& id, float dsdx, float dtdx, float dsdy, float dtdy) { return getComposer().setMatrix(this, id, dsdx, dtdx, dsdy, dtdy); } @@ -550,8 +575,8 @@ status_t SurfaceComposerClient::setMatrix(SurfaceID id, float dsdx, float dtdx, // ---------------------------------------------------------------------------- void SurfaceComposerClient::setDisplaySurface(const sp<IBinder>& token, - const sp<ISurfaceTexture>& surface) { - Composer::getInstance().setDisplaySurface(token, surface); + const sp<IGraphicBufferProducer>& bufferProducer) { + Composer::getInstance().setDisplaySurface(token, bufferProducer); } void SurfaceComposerClient::setDisplayLayerStack(const sp<IBinder>& token, @@ -585,27 +610,33 @@ void SurfaceComposerClient::unblankDisplay(const sp<IBinder>& token) { // ---------------------------------------------------------------------------- +status_t ScreenshotClient::capture( + const sp<IBinder>& display, + const sp<IGraphicBufferProducer>& producer, + uint32_t reqWidth, uint32_t reqHeight, + uint32_t minLayerZ, uint32_t maxLayerZ) { + sp<ISurfaceComposer> s(ComposerService::getComposerService()); + if (s == NULL) return NO_INIT; + return s->captureScreen(display, producer, + reqWidth, reqHeight, minLayerZ, maxLayerZ, + false); +} + ScreenshotClient::ScreenshotClient() - : mWidth(0), mHeight(0), mFormat(PIXEL_FORMAT_NONE) { + : mHaveBuffer(false) { + memset(&mBuffer, 0, sizeof(mBuffer)); } -status_t ScreenshotClient::update(const sp<IBinder>& display) { - sp<ISurfaceComposer> s(ComposerService::getComposerService()); - if (s == NULL) return NO_INIT; - mHeap = 0; - return s->captureScreen(display, &mHeap, - &mWidth, &mHeight, &mFormat, 0, 0, - 0, -1UL); +ScreenshotClient::~ScreenshotClient() { + ScreenshotClient::release(); } -status_t ScreenshotClient::update(const sp<IBinder>& display, - uint32_t reqWidth, uint32_t reqHeight) { - sp<ISurfaceComposer> s(ComposerService::getComposerService()); - if (s == NULL) return NO_INIT; - mHeap = 0; - return s->captureScreen(display, &mHeap, - &mWidth, &mHeight, &mFormat, reqWidth, reqHeight, - 0, -1UL); +sp<CpuConsumer> ScreenshotClient::getCpuConsumer() const { + if (mCpuConsumer == NULL) { + mCpuConsumer = new CpuConsumer(1); + mCpuConsumer->setName(String8("ScreenshotClient")); + } + return mCpuConsumer; } status_t ScreenshotClient::update(const sp<IBinder>& display, @@ -613,38 +644,66 @@ status_t ScreenshotClient::update(const sp<IBinder>& display, uint32_t minLayerZ, uint32_t maxLayerZ) { sp<ISurfaceComposer> s(ComposerService::getComposerService()); if (s == NULL) return NO_INIT; - mHeap = 0; - return s->captureScreen(display, &mHeap, - &mWidth, &mHeight, &mFormat, reqWidth, reqHeight, - minLayerZ, maxLayerZ); + sp<CpuConsumer> cpuConsumer = getCpuConsumer(); + + if (mHaveBuffer) { + mCpuConsumer->unlockBuffer(mBuffer); + memset(&mBuffer, 0, sizeof(mBuffer)); + mHaveBuffer = false; + } + + status_t err = s->captureScreen(display,cpuConsumer->getBufferQueue(), + reqWidth, reqHeight, minLayerZ, maxLayerZ, true); + + if (err == NO_ERROR) { + err = mCpuConsumer->lockNextBuffer(&mBuffer); + if (err == NO_ERROR) { + mHaveBuffer = true; + } + } + return err; +} + +status_t ScreenshotClient::update(const sp<IBinder>& display) { + return ScreenshotClient::update(display, 0, 0, 0, -1UL); +} + +status_t ScreenshotClient::update(const sp<IBinder>& display, + uint32_t reqWidth, uint32_t reqHeight) { + return ScreenshotClient::update(display, reqWidth, reqHeight, 0, -1UL); } void ScreenshotClient::release() { - mHeap = 0; + if (mHaveBuffer) { + mCpuConsumer->unlockBuffer(mBuffer); + memset(&mBuffer, 0, sizeof(mBuffer)); + mHaveBuffer = false; + } + mCpuConsumer.clear(); } void const* ScreenshotClient::getPixels() const { - return mHeap->getBase(); + return mBuffer.data; } uint32_t ScreenshotClient::getWidth() const { - return mWidth; + return mBuffer.width; } uint32_t ScreenshotClient::getHeight() const { - return mHeight; + return mBuffer.height; } PixelFormat ScreenshotClient::getFormat() const { - return mFormat; + return mBuffer.format; } uint32_t ScreenshotClient::getStride() const { - return mWidth; + return mBuffer.stride; } size_t ScreenshotClient::getSize() const { - return mHeap->getSize(); + return mBuffer.stride * mBuffer.height * bytesPerPixel(mBuffer.format); } // ---------------------------------------------------------------------------- diff --git a/libs/gui/SurfaceControl.cpp b/libs/gui/SurfaceControl.cpp new file mode 100644 index 0000000..f4e88f5 --- /dev/null +++ b/libs/gui/SurfaceControl.cpp @@ -0,0 +1,190 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "SurfaceControl" + +#include <stdint.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/stat.h> + +#include <android/native_window.h> + +#include <utils/CallStack.h> +#include <utils/Errors.h> +#include <utils/Log.h> +#include <utils/threads.h> + +#include <binder/IPCThreadState.h> + +#include <ui/DisplayInfo.h> +#include <ui/GraphicBuffer.h> +#include <ui/Rect.h> + +#include <gui/ISurfaceComposer.h> +#include <gui/Surface.h> +#include <gui/SurfaceComposerClient.h> +#include <gui/SurfaceControl.h> + +namespace android { + +// ============================================================================ +// SurfaceControl +// ============================================================================ + +SurfaceControl::SurfaceControl( + const sp<SurfaceComposerClient>& client, + const sp<IBinder>& handle, + const sp<IGraphicBufferProducer>& gbp) + : mClient(client), mHandle(handle), mGraphicBufferProducer(gbp) +{ +} + +SurfaceControl::~SurfaceControl() +{ + destroy(); +} + +void SurfaceControl::destroy() +{ + if (isValid()) { + mClient->destroySurface(mHandle); + } + // clear all references and trigger an IPC now, to make sure things + // happen without delay, since these resources are quite heavy. + mClient.clear(); + mHandle.clear(); + mGraphicBufferProducer.clear(); + IPCThreadState::self()->flushCommands(); +} + +void SurfaceControl::clear() +{ + // here, the window manager tells us explicitly that we should destroy + // the surface's resource. Soon after this call, it will also release + // its last reference (which will call the dtor); however, it is possible + // that a client living in the same process still holds references which + // would delay the call to the dtor -- that is why we need this explicit + // "clear()" call. + destroy(); +} + +bool SurfaceControl::isSameSurface( + const sp<SurfaceControl>& lhs, const sp<SurfaceControl>& rhs) +{ + if (lhs == 0 || rhs == 0) + return false; + return lhs->mHandle == rhs->mHandle; +} + +status_t SurfaceControl::setLayerStack(int32_t layerStack) { + status_t err = validate(); + if (err < 0) return err; + const sp<SurfaceComposerClient>& client(mClient); + return client->setLayerStack(mHandle, layerStack); +} +status_t SurfaceControl::setLayer(int32_t layer) { + status_t err = validate(); + if (err < 0) return err; + const sp<SurfaceComposerClient>& client(mClient); + return client->setLayer(mHandle, layer); +} +status_t SurfaceControl::setPosition(float x, float y) { + status_t err = validate(); + if (err < 0) return err; + const sp<SurfaceComposerClient>& client(mClient); + return client->setPosition(mHandle, x, y); +} +status_t SurfaceControl::setSize(uint32_t w, uint32_t h) { + status_t err = validate(); + if (err < 0) return err; + const sp<SurfaceComposerClient>& client(mClient); + return client->setSize(mHandle, w, h); +} +status_t SurfaceControl::hide() { + status_t err = validate(); + if (err < 0) return err; + const sp<SurfaceComposerClient>& client(mClient); + return client->hide(mHandle); +} +status_t SurfaceControl::show() { + status_t err = validate(); + if (err < 0) return err; + const sp<SurfaceComposerClient>& client(mClient); + return client->show(mHandle); +} +status_t SurfaceControl::setFlags(uint32_t flags, uint32_t mask) { + status_t err = validate(); + if (err < 0) return err; + const sp<SurfaceComposerClient>& client(mClient); + return client->setFlags(mHandle, flags, mask); +} +status_t SurfaceControl::setTransparentRegionHint(const Region& transparent) { + status_t err = validate(); + if (err < 0) return err; + const sp<SurfaceComposerClient>& client(mClient); + return client->setTransparentRegionHint(mHandle, transparent); +} +status_t SurfaceControl::setAlpha(float alpha) { + status_t err = validate(); + if (err < 0) return err; + const sp<SurfaceComposerClient>& client(mClient); + return client->setAlpha(mHandle, alpha); +} +status_t SurfaceControl::setMatrix(float dsdx, float dtdx, float dsdy, float dtdy) { + status_t err = validate(); + if (err < 0) return err; + const sp<SurfaceComposerClient>& client(mClient); + return client->setMatrix(mHandle, dsdx, dtdx, dsdy, dtdy); +} +status_t SurfaceControl::setCrop(const Rect& crop) { + status_t err = validate(); + if (err < 0) return err; + const sp<SurfaceComposerClient>& client(mClient); + return client->setCrop(mHandle, crop); +} + +status_t SurfaceControl::validate() const +{ + if (mHandle==0 || mClient==0) { + ALOGE("invalid handle (%p) or client (%p)", + mHandle.get(), mClient.get()); + return NO_INIT; + } + return NO_ERROR; +} + +status_t SurfaceControl::writeSurfaceToParcel( + const sp<SurfaceControl>& control, Parcel* parcel) +{ + sp<IGraphicBufferProducer> bp; + if (control != NULL) { + bp = control->mGraphicBufferProducer; + } + return parcel->writeStrongBinder(bp->asBinder()); +} + +sp<Surface> SurfaceControl::getSurface() const +{ + Mutex::Autolock _l(mLock); + if (mSurfaceData == 0) { + mSurfaceData = new Surface(mGraphicBufferProducer); + } + return mSurfaceData; +} + +// ---------------------------------------------------------------------------- +}; // namespace android diff --git a/libs/gui/SurfaceTextureClient.cpp b/libs/gui/SurfaceTextureClient.cpp deleted file mode 100644 index afdbf04..0000000 --- a/libs/gui/SurfaceTextureClient.cpp +++ /dev/null @@ -1,854 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define LOG_TAG "SurfaceTextureClient" -#define ATRACE_TAG ATRACE_TAG_GRAPHICS -//#define LOG_NDEBUG 0 - -#include <android/native_window.h> - -#include <utils/Log.h> -#include <utils/Trace.h> - -#include <ui/Fence.h> - -#include <gui/ISurfaceComposer.h> -#include <gui/SurfaceComposerClient.h> -#include <gui/SurfaceTexture.h> -#include <gui/SurfaceTextureClient.h> - -#include <private/gui/ComposerService.h> - -namespace android { - -SurfaceTextureClient::SurfaceTextureClient( - const sp<ISurfaceTexture>& surfaceTexture) -{ - SurfaceTextureClient::init(); - SurfaceTextureClient::setISurfaceTexture(surfaceTexture); -} - -// see SurfaceTextureClient.h -SurfaceTextureClient::SurfaceTextureClient(const - sp<SurfaceTexture>& surfaceTexture) -{ - SurfaceTextureClient::init(); - SurfaceTextureClient::setISurfaceTexture(surfaceTexture->getBufferQueue()); -} - -SurfaceTextureClient::SurfaceTextureClient() { - SurfaceTextureClient::init(); -} - -SurfaceTextureClient::~SurfaceTextureClient() { - if (mConnectedToCpu) { - SurfaceTextureClient::disconnect(NATIVE_WINDOW_API_CPU); - } -} - -void SurfaceTextureClient::init() { - // Initialize the ANativeWindow function pointers. - ANativeWindow::setSwapInterval = hook_setSwapInterval; - ANativeWindow::dequeueBuffer = hook_dequeueBuffer; - ANativeWindow::cancelBuffer = hook_cancelBuffer; - ANativeWindow::queueBuffer = hook_queueBuffer; - ANativeWindow::query = hook_query; - ANativeWindow::perform = hook_perform; - - ANativeWindow::dequeueBuffer_DEPRECATED = hook_dequeueBuffer_DEPRECATED; - ANativeWindow::cancelBuffer_DEPRECATED = hook_cancelBuffer_DEPRECATED; - ANativeWindow::lockBuffer_DEPRECATED = hook_lockBuffer_DEPRECATED; - ANativeWindow::queueBuffer_DEPRECATED = hook_queueBuffer_DEPRECATED; - - const_cast<int&>(ANativeWindow::minSwapInterval) = 0; - const_cast<int&>(ANativeWindow::maxSwapInterval) = 1; - - mReqWidth = 0; - mReqHeight = 0; - mReqFormat = 0; - mReqUsage = 0; - mTimestamp = NATIVE_WINDOW_TIMESTAMP_AUTO; - mCrop.clear(); - mScalingMode = NATIVE_WINDOW_SCALING_MODE_FREEZE; - mTransform = 0; - mDefaultWidth = 0; - mDefaultHeight = 0; - mUserWidth = 0; - mUserHeight = 0; - mTransformHint = 0; - mConsumerRunningBehind = false; - mConnectedToCpu = false; -} - -void SurfaceTextureClient::setISurfaceTexture( - const sp<ISurfaceTexture>& surfaceTexture) -{ - mSurfaceTexture = surfaceTexture; -} - -sp<ISurfaceTexture> SurfaceTextureClient::getISurfaceTexture() const { - return mSurfaceTexture; -} - -int SurfaceTextureClient::hook_setSwapInterval(ANativeWindow* window, int interval) { - SurfaceTextureClient* c = getSelf(window); - return c->setSwapInterval(interval); -} - -int SurfaceTextureClient::hook_dequeueBuffer(ANativeWindow* window, - ANativeWindowBuffer** buffer, int* fenceFd) { - SurfaceTextureClient* c = getSelf(window); - return c->dequeueBuffer(buffer, fenceFd); -} - -int SurfaceTextureClient::hook_cancelBuffer(ANativeWindow* window, - ANativeWindowBuffer* buffer, int fenceFd) { - SurfaceTextureClient* c = getSelf(window); - return c->cancelBuffer(buffer, fenceFd); -} - -int SurfaceTextureClient::hook_queueBuffer(ANativeWindow* window, - ANativeWindowBuffer* buffer, int fenceFd) { - SurfaceTextureClient* c = getSelf(window); - return c->queueBuffer(buffer, fenceFd); -} - -int SurfaceTextureClient::hook_dequeueBuffer_DEPRECATED(ANativeWindow* window, - ANativeWindowBuffer** buffer) { - SurfaceTextureClient* c = getSelf(window); - ANativeWindowBuffer* buf; - int fenceFd = -1; - int result = c->dequeueBuffer(&buf, &fenceFd); - sp<Fence> fence(new Fence(fenceFd)); - int waitResult = fence->waitForever(1000, "dequeueBuffer_DEPRECATED"); - if (waitResult != OK) { - ALOGE("dequeueBuffer_DEPRECATED: Fence::wait returned an error: %d", - waitResult); - c->cancelBuffer(buf, -1); - return waitResult; - } - *buffer = buf; - return result; -} - -int SurfaceTextureClient::hook_cancelBuffer_DEPRECATED(ANativeWindow* window, - ANativeWindowBuffer* buffer) { - SurfaceTextureClient* c = getSelf(window); - return c->cancelBuffer(buffer, -1); -} - -int SurfaceTextureClient::hook_lockBuffer_DEPRECATED(ANativeWindow* window, - ANativeWindowBuffer* buffer) { - SurfaceTextureClient* c = getSelf(window); - return c->lockBuffer_DEPRECATED(buffer); -} - -int SurfaceTextureClient::hook_queueBuffer_DEPRECATED(ANativeWindow* window, - ANativeWindowBuffer* buffer) { - SurfaceTextureClient* c = getSelf(window); - return c->queueBuffer(buffer, -1); -} - -int SurfaceTextureClient::hook_query(const ANativeWindow* window, - int what, int* value) { - const SurfaceTextureClient* c = getSelf(window); - return c->query(what, value); -} - -int SurfaceTextureClient::hook_perform(ANativeWindow* window, int operation, ...) { - va_list args; - va_start(args, operation); - SurfaceTextureClient* c = getSelf(window); - return c->perform(operation, args); -} - -int SurfaceTextureClient::setSwapInterval(int interval) { - ATRACE_CALL(); - // EGL specification states: - // interval is silently clamped to minimum and maximum implementation - // dependent values before being stored. - // Although we don't have to, we apply the same logic here. - - if (interval < minSwapInterval) - interval = minSwapInterval; - - if (interval > maxSwapInterval) - interval = maxSwapInterval; - - status_t res = mSurfaceTexture->setSynchronousMode(interval ? true : false); - - return res; -} - -int SurfaceTextureClient::dequeueBuffer(android_native_buffer_t** buffer, - int* fenceFd) { - ATRACE_CALL(); - ALOGV("SurfaceTextureClient::dequeueBuffer"); - Mutex::Autolock lock(mMutex); - int buf = -1; - int reqW = mReqWidth ? mReqWidth : mUserWidth; - int reqH = mReqHeight ? mReqHeight : mUserHeight; - sp<Fence> fence; - status_t result = mSurfaceTexture->dequeueBuffer(&buf, fence, reqW, reqH, - mReqFormat, mReqUsage); - if (result < 0) { - ALOGV("dequeueBuffer: ISurfaceTexture::dequeueBuffer(%d, %d, %d, %d)" - "failed: %d", mReqWidth, mReqHeight, mReqFormat, mReqUsage, - result); - return result; - } - sp<GraphicBuffer>& gbuf(mSlots[buf].buffer); - if (result & ISurfaceTexture::RELEASE_ALL_BUFFERS) { - freeAllBuffers(); - } - - if ((result & ISurfaceTexture::BUFFER_NEEDS_REALLOCATION) || gbuf == 0) { - result = mSurfaceTexture->requestBuffer(buf, &gbuf); - if (result != NO_ERROR) { - ALOGE("dequeueBuffer: ISurfaceTexture::requestBuffer failed: %d", - result); - return result; - } - } - - if (fence.get()) { - *fenceFd = fence->dup(); - if (*fenceFd == -1) { - ALOGE("dequeueBuffer: error duping fence: %d", errno); - // dup() should never fail; something is badly wrong. Soldier on - // and hope for the best; the worst that should happen is some - // visible corruption that lasts until the next frame. - } - } else { - *fenceFd = -1; - } - - *buffer = gbuf.get(); - return OK; -} - -int SurfaceTextureClient::cancelBuffer(android_native_buffer_t* buffer, - int fenceFd) { - ATRACE_CALL(); - ALOGV("SurfaceTextureClient::cancelBuffer"); - Mutex::Autolock lock(mMutex); - int i = getSlotFromBufferLocked(buffer); - if (i < 0) { - return i; - } - sp<Fence> fence(fenceFd >= 0 ? new Fence(fenceFd) : NULL); - mSurfaceTexture->cancelBuffer(i, fence); - return OK; -} - -int SurfaceTextureClient::getSlotFromBufferLocked( - android_native_buffer_t* buffer) const { - bool dumpedState = false; - for (int i = 0; i < NUM_BUFFER_SLOTS; i++) { - if (mSlots[i].buffer != NULL && - mSlots[i].buffer->handle == buffer->handle) { - return i; - } - } - ALOGE("getSlotFromBufferLocked: unknown buffer: %p", buffer->handle); - return BAD_VALUE; -} - -int SurfaceTextureClient::lockBuffer_DEPRECATED(android_native_buffer_t* buffer) { - ALOGV("SurfaceTextureClient::lockBuffer"); - Mutex::Autolock lock(mMutex); - return OK; -} - -int SurfaceTextureClient::queueBuffer(android_native_buffer_t* buffer, int fenceFd) { - ATRACE_CALL(); - ALOGV("SurfaceTextureClient::queueBuffer"); - Mutex::Autolock lock(mMutex); - int64_t timestamp; - if (mTimestamp == NATIVE_WINDOW_TIMESTAMP_AUTO) { - timestamp = systemTime(SYSTEM_TIME_MONOTONIC); - ALOGV("SurfaceTextureClient::queueBuffer making up timestamp: %.2f ms", - timestamp / 1000000.f); - } else { - timestamp = mTimestamp; - } - int i = getSlotFromBufferLocked(buffer); - if (i < 0) { - return i; - } - - - // Make sure the crop rectangle is entirely inside the buffer. - Rect crop; - mCrop.intersect(Rect(buffer->width, buffer->height), &crop); - - sp<Fence> fence(fenceFd >= 0 ? new Fence(fenceFd) : NULL); - ISurfaceTexture::QueueBufferOutput output; - ISurfaceTexture::QueueBufferInput input(timestamp, crop, mScalingMode, - mTransform, fence); - status_t err = mSurfaceTexture->queueBuffer(i, input, &output); - if (err != OK) { - ALOGE("queueBuffer: error queuing buffer to SurfaceTexture, %d", err); - } - uint32_t numPendingBuffers = 0; - output.deflate(&mDefaultWidth, &mDefaultHeight, &mTransformHint, - &numPendingBuffers); - - mConsumerRunningBehind = (numPendingBuffers >= 2); - - return err; -} - -int SurfaceTextureClient::query(int what, int* value) const { - ATRACE_CALL(); - ALOGV("SurfaceTextureClient::query"); - { // scope for the lock - Mutex::Autolock lock(mMutex); - switch (what) { - case NATIVE_WINDOW_FORMAT: - if (mReqFormat) { - *value = mReqFormat; - return NO_ERROR; - } - break; - case NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER: { - sp<ISurfaceComposer> composer( - ComposerService::getComposerService()); - if (composer->authenticateSurfaceTexture(mSurfaceTexture)) { - *value = 1; - } else { - *value = 0; - } - return NO_ERROR; - } - case NATIVE_WINDOW_CONCRETE_TYPE: - *value = NATIVE_WINDOW_SURFACE_TEXTURE_CLIENT; - return NO_ERROR; - case NATIVE_WINDOW_DEFAULT_WIDTH: - *value = mUserWidth ? mUserWidth : mDefaultWidth; - return NO_ERROR; - case NATIVE_WINDOW_DEFAULT_HEIGHT: - *value = mUserHeight ? mUserHeight : mDefaultHeight; - return NO_ERROR; - case NATIVE_WINDOW_TRANSFORM_HINT: - *value = mTransformHint; - return NO_ERROR; - case NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND: { - status_t err = NO_ERROR; - if (!mConsumerRunningBehind) { - *value = 0; - } else { - err = mSurfaceTexture->query(what, value); - if (err == NO_ERROR) { - mConsumerRunningBehind = *value; - } - } - return err; - } - } - } - return mSurfaceTexture->query(what, value); -} - -int SurfaceTextureClient::perform(int operation, va_list args) -{ - int res = NO_ERROR; - switch (operation) { - case NATIVE_WINDOW_CONNECT: - // deprecated. must return NO_ERROR. - break; - case NATIVE_WINDOW_DISCONNECT: - // deprecated. must return NO_ERROR. - break; - case NATIVE_WINDOW_SET_USAGE: - res = dispatchSetUsage(args); - break; - case NATIVE_WINDOW_SET_CROP: - res = dispatchSetCrop(args); - break; - case NATIVE_WINDOW_SET_BUFFER_COUNT: - res = dispatchSetBufferCount(args); - break; - case NATIVE_WINDOW_SET_BUFFERS_GEOMETRY: - res = dispatchSetBuffersGeometry(args); - break; - case NATIVE_WINDOW_SET_BUFFERS_TRANSFORM: - res = dispatchSetBuffersTransform(args); - break; - case NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP: - res = dispatchSetBuffersTimestamp(args); - break; - case NATIVE_WINDOW_SET_BUFFERS_DIMENSIONS: - res = dispatchSetBuffersDimensions(args); - break; - case NATIVE_WINDOW_SET_BUFFERS_USER_DIMENSIONS: - res = dispatchSetBuffersUserDimensions(args); - break; - case NATIVE_WINDOW_SET_BUFFERS_FORMAT: - res = dispatchSetBuffersFormat(args); - break; - case NATIVE_WINDOW_LOCK: - res = dispatchLock(args); - break; - case NATIVE_WINDOW_UNLOCK_AND_POST: - res = dispatchUnlockAndPost(args); - break; - case NATIVE_WINDOW_SET_SCALING_MODE: - res = dispatchSetScalingMode(args); - break; - case NATIVE_WINDOW_API_CONNECT: - res = dispatchConnect(args); - break; - case NATIVE_WINDOW_API_DISCONNECT: - res = dispatchDisconnect(args); - break; - default: - res = NAME_NOT_FOUND; - break; - } - return res; -} - -int SurfaceTextureClient::dispatchConnect(va_list args) { - int api = va_arg(args, int); - return connect(api); -} - -int SurfaceTextureClient::dispatchDisconnect(va_list args) { - int api = va_arg(args, int); - return disconnect(api); -} - -int SurfaceTextureClient::dispatchSetUsage(va_list args) { - int usage = va_arg(args, int); - return setUsage(usage); -} - -int SurfaceTextureClient::dispatchSetCrop(va_list args) { - android_native_rect_t const* rect = va_arg(args, android_native_rect_t*); - return setCrop(reinterpret_cast<Rect const*>(rect)); -} - -int SurfaceTextureClient::dispatchSetBufferCount(va_list args) { - size_t bufferCount = va_arg(args, size_t); - return setBufferCount(bufferCount); -} - -int SurfaceTextureClient::dispatchSetBuffersGeometry(va_list args) { - int w = va_arg(args, int); - int h = va_arg(args, int); - int f = va_arg(args, int); - int err = setBuffersDimensions(w, h); - if (err != 0) { - return err; - } - return setBuffersFormat(f); -} - -int SurfaceTextureClient::dispatchSetBuffersDimensions(va_list args) { - int w = va_arg(args, int); - int h = va_arg(args, int); - return setBuffersDimensions(w, h); -} - -int SurfaceTextureClient::dispatchSetBuffersUserDimensions(va_list args) { - int w = va_arg(args, int); - int h = va_arg(args, int); - return setBuffersUserDimensions(w, h); -} - -int SurfaceTextureClient::dispatchSetBuffersFormat(va_list args) { - int f = va_arg(args, int); - return setBuffersFormat(f); -} - -int SurfaceTextureClient::dispatchSetScalingMode(va_list args) { - int m = va_arg(args, int); - return setScalingMode(m); -} - -int SurfaceTextureClient::dispatchSetBuffersTransform(va_list args) { - int transform = va_arg(args, int); - return setBuffersTransform(transform); -} - -int SurfaceTextureClient::dispatchSetBuffersTimestamp(va_list args) { - int64_t timestamp = va_arg(args, int64_t); - return setBuffersTimestamp(timestamp); -} - -int SurfaceTextureClient::dispatchLock(va_list args) { - ANativeWindow_Buffer* outBuffer = va_arg(args, ANativeWindow_Buffer*); - ARect* inOutDirtyBounds = va_arg(args, ARect*); - return lock(outBuffer, inOutDirtyBounds); -} - -int SurfaceTextureClient::dispatchUnlockAndPost(va_list args) { - return unlockAndPost(); -} - - -int SurfaceTextureClient::connect(int api) { - ATRACE_CALL(); - ALOGV("SurfaceTextureClient::connect"); - Mutex::Autolock lock(mMutex); - ISurfaceTexture::QueueBufferOutput output; - int err = mSurfaceTexture->connect(api, &output); - if (err == NO_ERROR) { - uint32_t numPendingBuffers = 0; - output.deflate(&mDefaultWidth, &mDefaultHeight, &mTransformHint, - &numPendingBuffers); - mConsumerRunningBehind = (numPendingBuffers >= 2); - } - if (!err && api == NATIVE_WINDOW_API_CPU) { - mConnectedToCpu = true; - } - return err; -} - -int SurfaceTextureClient::disconnect(int api) { - ATRACE_CALL(); - ALOGV("SurfaceTextureClient::disconnect"); - Mutex::Autolock lock(mMutex); - freeAllBuffers(); - int err = mSurfaceTexture->disconnect(api); - if (!err) { - mReqFormat = 0; - mReqWidth = 0; - mReqHeight = 0; - mReqUsage = 0; - mCrop.clear(); - mScalingMode = NATIVE_WINDOW_SCALING_MODE_FREEZE; - mTransform = 0; - if (api == NATIVE_WINDOW_API_CPU) { - mConnectedToCpu = false; - } - } - return err; -} - -int SurfaceTextureClient::setUsage(uint32_t reqUsage) -{ - ALOGV("SurfaceTextureClient::setUsage"); - Mutex::Autolock lock(mMutex); - mReqUsage = reqUsage; - return OK; -} - -int SurfaceTextureClient::setCrop(Rect const* rect) -{ - ATRACE_CALL(); - - Rect realRect; - if (rect == NULL || rect->isEmpty()) { - realRect.clear(); - } else { - realRect = *rect; - } - - ALOGV("SurfaceTextureClient::setCrop rect=[%d %d %d %d]", - realRect.left, realRect.top, realRect.right, realRect.bottom); - - Mutex::Autolock lock(mMutex); - mCrop = realRect; - return NO_ERROR; -} - -int SurfaceTextureClient::setBufferCount(int bufferCount) -{ - ATRACE_CALL(); - ALOGV("SurfaceTextureClient::setBufferCount"); - Mutex::Autolock lock(mMutex); - - status_t err = mSurfaceTexture->setBufferCount(bufferCount); - ALOGE_IF(err, "ISurfaceTexture::setBufferCount(%d) returned %s", - bufferCount, strerror(-err)); - - if (err == NO_ERROR) { - freeAllBuffers(); - } - - return err; -} - -int SurfaceTextureClient::setBuffersDimensions(int w, int h) -{ - ATRACE_CALL(); - ALOGV("SurfaceTextureClient::setBuffersDimensions"); - - if (w<0 || h<0) - return BAD_VALUE; - - if ((w && !h) || (!w && h)) - return BAD_VALUE; - - Mutex::Autolock lock(mMutex); - mReqWidth = w; - mReqHeight = h; - return NO_ERROR; -} - -int SurfaceTextureClient::setBuffersUserDimensions(int w, int h) -{ - ATRACE_CALL(); - ALOGV("SurfaceTextureClient::setBuffersUserDimensions"); - - if (w<0 || h<0) - return BAD_VALUE; - - if ((w && !h) || (!w && h)) - return BAD_VALUE; - - Mutex::Autolock lock(mMutex); - mUserWidth = w; - mUserHeight = h; - return NO_ERROR; -} - -int SurfaceTextureClient::setBuffersFormat(int format) -{ - ALOGV("SurfaceTextureClient::setBuffersFormat"); - - if (format<0) - return BAD_VALUE; - - Mutex::Autolock lock(mMutex); - mReqFormat = format; - return NO_ERROR; -} - -int SurfaceTextureClient::setScalingMode(int mode) -{ - ATRACE_CALL(); - ALOGV("SurfaceTextureClient::setScalingMode(%d)", mode); - - switch (mode) { - case NATIVE_WINDOW_SCALING_MODE_FREEZE: - case NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW: - case NATIVE_WINDOW_SCALING_MODE_SCALE_CROP: - break; - default: - ALOGE("unknown scaling mode: %d", mode); - return BAD_VALUE; - } - - Mutex::Autolock lock(mMutex); - mScalingMode = mode; - return NO_ERROR; -} - -int SurfaceTextureClient::setBuffersTransform(int transform) -{ - ATRACE_CALL(); - ALOGV("SurfaceTextureClient::setBuffersTransform"); - Mutex::Autolock lock(mMutex); - mTransform = transform; - return NO_ERROR; -} - -int SurfaceTextureClient::setBuffersTimestamp(int64_t timestamp) -{ - ALOGV("SurfaceTextureClient::setBuffersTimestamp"); - Mutex::Autolock lock(mMutex); - mTimestamp = timestamp; - return NO_ERROR; -} - -void SurfaceTextureClient::freeAllBuffers() { - for (int i = 0; i < NUM_BUFFER_SLOTS; i++) { - mSlots[i].buffer = 0; - } -} - -// ---------------------------------------------------------------------- -// the lock/unlock APIs must be used from the same thread - -static status_t copyBlt( - const sp<GraphicBuffer>& dst, - const sp<GraphicBuffer>& src, - const Region& reg) -{ - // src and dst with, height and format must be identical. no verification - // is done here. - status_t err; - uint8_t const * src_bits = NULL; - err = src->lock(GRALLOC_USAGE_SW_READ_OFTEN, reg.bounds(), (void**)&src_bits); - ALOGE_IF(err, "error locking src buffer %s", strerror(-err)); - - uint8_t* dst_bits = NULL; - err = dst->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, reg.bounds(), (void**)&dst_bits); - ALOGE_IF(err, "error locking dst buffer %s", strerror(-err)); - - Region::const_iterator head(reg.begin()); - Region::const_iterator tail(reg.end()); - if (head != tail && src_bits && dst_bits) { - const size_t bpp = bytesPerPixel(src->format); - const size_t dbpr = dst->stride * bpp; - const size_t sbpr = src->stride * bpp; - - while (head != tail) { - const Rect& r(*head++); - ssize_t h = r.height(); - if (h <= 0) continue; - size_t size = r.width() * bpp; - uint8_t const * s = src_bits + (r.left + src->stride * r.top) * bpp; - uint8_t * d = dst_bits + (r.left + dst->stride * r.top) * bpp; - if (dbpr==sbpr && size==sbpr) { - size *= h; - h = 1; - } - do { - memcpy(d, s, size); - d += dbpr; - s += sbpr; - } while (--h > 0); - } - } - - if (src_bits) - src->unlock(); - - if (dst_bits) - dst->unlock(); - - return err; -} - -// ---------------------------------------------------------------------------- - -status_t SurfaceTextureClient::lock( - ANativeWindow_Buffer* outBuffer, ARect* inOutDirtyBounds) -{ - if (mLockedBuffer != 0) { - ALOGE("Surface::lock failed, already locked"); - return INVALID_OPERATION; - } - - if (!mConnectedToCpu) { - int err = SurfaceTextureClient::connect(NATIVE_WINDOW_API_CPU); - if (err) { - return err; - } - // we're intending to do software rendering from this point - setUsage(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN); - } - - ANativeWindowBuffer* out; - int fenceFd = -1; - status_t err = dequeueBuffer(&out, &fenceFd); - ALOGE_IF(err, "dequeueBuffer failed (%s)", strerror(-err)); - if (err == NO_ERROR) { - sp<GraphicBuffer> backBuffer(GraphicBuffer::getSelf(out)); - sp<Fence> fence(new Fence(fenceFd)); - - err = fence->waitForever(1000, "SurfaceTextureClient::lock"); - if (err != OK) { - ALOGE("Fence::wait failed (%s)", strerror(-err)); - cancelBuffer(out, fenceFd); - return err; - } - - const Rect bounds(backBuffer->width, backBuffer->height); - - Region newDirtyRegion; - if (inOutDirtyBounds) { - newDirtyRegion.set(static_cast<Rect const&>(*inOutDirtyBounds)); - newDirtyRegion.andSelf(bounds); - } else { - newDirtyRegion.set(bounds); - } - - // figure out if we can copy the frontbuffer back - const sp<GraphicBuffer>& frontBuffer(mPostedBuffer); - const bool canCopyBack = (frontBuffer != 0 && - backBuffer->width == frontBuffer->width && - backBuffer->height == frontBuffer->height && - backBuffer->format == frontBuffer->format); - - if (canCopyBack) { - // copy the area that is invalid and not repainted this round - const Region copyback(mDirtyRegion.subtract(newDirtyRegion)); - if (!copyback.isEmpty()) - copyBlt(backBuffer, frontBuffer, copyback); - } else { - // if we can't copy-back anything, modify the user's dirty - // region to make sure they redraw the whole buffer - newDirtyRegion.set(bounds); - mDirtyRegion.clear(); - Mutex::Autolock lock(mMutex); - for (size_t i=0 ; i<NUM_BUFFER_SLOTS ; i++) { - mSlots[i].dirtyRegion.clear(); - } - } - - - { // scope for the lock - Mutex::Autolock lock(mMutex); - int backBufferSlot(getSlotFromBufferLocked(backBuffer.get())); - if (backBufferSlot >= 0) { - Region& dirtyRegion(mSlots[backBufferSlot].dirtyRegion); - mDirtyRegion.subtract(dirtyRegion); - dirtyRegion = newDirtyRegion; - } - } - - mDirtyRegion.orSelf(newDirtyRegion); - if (inOutDirtyBounds) { - *inOutDirtyBounds = newDirtyRegion.getBounds(); - } - - void* vaddr; - status_t res = backBuffer->lock( - GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN, - newDirtyRegion.bounds(), &vaddr); - - ALOGW_IF(res, "failed locking buffer (handle = %p)", - backBuffer->handle); - - if (res != 0) { - err = INVALID_OPERATION; - } else { - mLockedBuffer = backBuffer; - outBuffer->width = backBuffer->width; - outBuffer->height = backBuffer->height; - outBuffer->stride = backBuffer->stride; - outBuffer->format = backBuffer->format; - outBuffer->bits = vaddr; - } - } - return err; -} - -status_t SurfaceTextureClient::unlockAndPost() -{ - if (mLockedBuffer == 0) { - ALOGE("Surface::unlockAndPost failed, no locked buffer"); - return INVALID_OPERATION; - } - - status_t err = mLockedBuffer->unlock(); - ALOGE_IF(err, "failed unlocking buffer (%p)", mLockedBuffer->handle); - - err = queueBuffer(mLockedBuffer.get(), -1); - ALOGE_IF(err, "queueBuffer (handle=%p) failed (%s)", - mLockedBuffer->handle, strerror(-err)); - - mPostedBuffer = mLockedBuffer; - mLockedBuffer = 0; - return err; -} - -}; // namespace android diff --git a/libs/gui/SyncFeatures.cpp b/libs/gui/SyncFeatures.cpp new file mode 100644 index 0000000..e5804a7 --- /dev/null +++ b/libs/gui/SyncFeatures.cpp @@ -0,0 +1,94 @@ +/* + ** Copyright 2013, The Android Open Source Project + ** + ** Licensed under the Apache License, Version 2.0 (the "License"); + ** you may not use this file except in compliance with the License. + ** You may obtain a copy of the License at + ** + ** http://www.apache.org/licenses/LICENSE-2.0 + ** + ** Unless required by applicable law or agreed to in writing, software + ** distributed under the License is distributed on an "AS IS" BASIS, + ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ** See the License for the specific language governing permissions and + ** limitations under the License. + */ + +#define LOG_TAG "GLConsumer" + +#define GL_GLEXT_PROTOTYPES +#define EGL_EGLEXT_PROTOTYPES + +#include <EGL/egl.h> +#include <EGL/eglext.h> + +#include <utils/Log.h> +#include <utils/Singleton.h> +#include <utils/String8.h> + +#include <private/gui/SyncFeatures.h> + +EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name); + +namespace android { + +ANDROID_SINGLETON_STATIC_INSTANCE(SyncFeatures); + +SyncFeatures::SyncFeatures() : Singleton<SyncFeatures>(), + mHasNativeFenceSync(false), + mHasFenceSync(false), + mHasWaitSync(false) { + EGLDisplay dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY); + // This can only be called after EGL has been initialized; otherwise the + // check below will abort. + const char* exts = eglQueryStringImplementationANDROID(dpy, EGL_EXTENSIONS); + LOG_ALWAYS_FATAL_IF(exts == NULL, "eglQueryStringImplementationANDROID failed"); + if (strstr(exts, "EGL_ANDROID_native_fence_sync")) { + // This makes GLConsumer 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. + mHasNativeFenceSync = true; + } + if (strstr(exts, "EGL_KHR_fence_sync")) { + mHasFenceSync = true; + } + if (strstr(exts, "EGL_KHR_wait_sync")) { + mHasWaitSync = true; + } + mString.append("[using:"); + if (useNativeFenceSync()) { + mString.append(" EGL_ANDROID_native_fence_sync"); + } + if (useFenceSync()) { + mString.append(" EGL_KHR_fence_sync"); + } + if (useWaitSync()) { + mString.append(" EGL_KHR_wait_sync"); + } + mString.append("]"); +} + +bool SyncFeatures::useNativeFenceSync() const { + // EGL_ANDROID_native_fence_sync is not compatible with using the + // EGL_KHR_fence_sync extension for the same purpose. + return mHasNativeFenceSync; +} +bool SyncFeatures::useFenceSync() const { +#ifdef DONT_USE_FENCE_SYNC + // on some devices it's better to not use EGL_KHR_fence_sync + // even if they have it + return false; +#endif + // currently we shall only attempt to use EGL_KHR_fence_sync if + // USE_FENCE_SYNC is set in our makefile + return !mHasNativeFenceSync && mHasFenceSync; +} +bool SyncFeatures::useWaitSync() const { + return (useNativeFenceSync() || useFenceSync()) && mHasWaitSync; +} + +String8 SyncFeatures::toString() const { + return mString; +} + +} // namespace android diff --git a/libs/gui/tests/Android.mk b/libs/gui/tests/Android.mk index 4a6f74f..21bd875 100644 --- a/libs/gui/tests/Android.mk +++ b/libs/gui/tests/Android.mk @@ -15,6 +15,7 @@ LOCAL_SRC_FILES := \ LOCAL_SHARED_LIBRARIES := \ libEGL \ + libGLESv1_CM \ libGLESv2 \ libbinder \ libcutils \ diff --git a/libs/gui/tests/BufferQueue_test.cpp b/libs/gui/tests/BufferQueue_test.cpp index 817abb4..62d215b 100644 --- a/libs/gui/tests/BufferQueue_test.cpp +++ b/libs/gui/tests/BufferQueue_test.cpp @@ -63,28 +63,28 @@ struct DummyConsumer : public BufferQueue::ConsumerListener { TEST_F(BufferQueueTest, AcquireBuffer_ExceedsMaxAcquireCount_Fails) { sp<DummyConsumer> dc(new DummyConsumer); mBQ->consumerConnect(dc); - ISurfaceTexture::QueueBufferOutput qbo; + IGraphicBufferProducer::QueueBufferOutput qbo; mBQ->connect(NATIVE_WINDOW_API_CPU, &qbo); mBQ->setBufferCount(4); int slot; sp<Fence> fence; sp<GraphicBuffer> buf; - ISurfaceTexture::QueueBufferInput qbi(0, Rect(0, 0, 1, 1), - NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, fence); + IGraphicBufferProducer::QueueBufferInput qbi(0, Rect(0, 0, 1, 1), + NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, Fence::NO_FENCE); BufferQueue::BufferItem item; for (int i = 0; i < 2; i++) { - ASSERT_EQ(ISurfaceTexture::BUFFER_NEEDS_REALLOCATION, - mBQ->dequeueBuffer(&slot, fence, 1, 1, 0, + ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, + mBQ->dequeueBuffer(&slot, &fence, 1, 1, 0, GRALLOC_USAGE_SW_READ_OFTEN)); ASSERT_EQ(OK, mBQ->requestBuffer(slot, &buf)); ASSERT_EQ(OK, mBQ->queueBuffer(slot, qbi, &qbo)); ASSERT_EQ(OK, mBQ->acquireBuffer(&item)); } - ASSERT_EQ(ISurfaceTexture::BUFFER_NEEDS_REALLOCATION, - mBQ->dequeueBuffer(&slot, fence, 1, 1, 0, + ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, + mBQ->dequeueBuffer(&slot, &fence, 1, 1, 0, GRALLOC_USAGE_SW_READ_OFTEN)); ASSERT_EQ(OK, mBQ->requestBuffer(slot, &buf)); ASSERT_EQ(OK, mBQ->queueBuffer(slot, qbi, &qbo)); diff --git a/libs/gui/tests/CpuConsumer_test.cpp b/libs/gui/tests/CpuConsumer_test.cpp index 72a36bf..73fdd04 100644 --- a/libs/gui/tests/CpuConsumer_test.cpp +++ b/libs/gui/tests/CpuConsumer_test.cpp @@ -26,7 +26,7 @@ #include <gtest/gtest.h> #include <gui/CpuConsumer.h> -#include <gui/SurfaceTextureClient.h> +#include <gui/Surface.h> #include <ui/GraphicBuffer.h> #include <utils/String8.h> #include <utils/Thread.h> @@ -35,6 +35,11 @@ #include <ui/FramebufferNativeWindow.h> +#define CPU_CONSUMER_TEST_FORMAT_RAW 0 +#define CPU_CONSUMER_TEST_FORMAT_Y8 0 +#define CPU_CONSUMER_TEST_FORMAT_Y16 0 +#define CPU_CONSUMER_TEST_FORMAT_RGBA_8888 1 + namespace android { struct CpuConsumerTestParams { @@ -64,7 +69,7 @@ protected: mCC = new CpuConsumer(params.maxLockedBuffers); String8 name("CpuConsumer_Under_Test"); mCC->setName(name); - mSTC = new SurfaceTextureClient(mCC->getProducerInterface()); + mSTC = new Surface(mCC->getProducerInterface()); mANW = mSTC; } @@ -149,7 +154,7 @@ protected: }; sp<CpuConsumer> mCC; - sp<SurfaceTextureClient> mSTC; + sp<Surface> mSTC; sp<ANativeWindow> mANW; }; @@ -157,7 +162,7 @@ protected: ASSERT_EQ(NO_ERROR, err) << msg << strerror(-err) void checkPixel(const CpuConsumer::LockedBuffer &buf, - uint32_t x, uint32_t y, uint32_t r, uint32_t g, uint32_t b) { + uint32_t x, uint32_t y, uint32_t r, uint32_t g=0, uint32_t b=0) { // Ignores components that don't exist for given pixel switch(buf.format) { case HAL_PIXEL_FORMAT_RAW_SENSOR: { @@ -179,6 +184,31 @@ void checkPixel(const CpuConsumer::LockedBuffer &buf, } break; } + // ignores g,b + case HAL_PIXEL_FORMAT_Y8: { + uint8_t *bPtr = (uint8_t*)buf.data; + bPtr += y * buf.stride + x; + EXPECT_EQ(r, *bPtr) << "at x = " << x << " y = " << y; + break; + } + // ignores g,b + case HAL_PIXEL_FORMAT_Y16: { + // stride is in pixels, not in bytes + uint16_t *bPtr = ((uint16_t*)buf.data) + y * buf.stride + x; + + EXPECT_EQ(r, *bPtr) << "at x = " << x << " y = " << y; + break; + } + case HAL_PIXEL_FORMAT_RGBA_8888: { + const int bytesPerPixel = 4; + uint8_t *bPtr = (uint8_t*)buf.data; + bPtr += (y * buf.stride + x) * bytesPerPixel; + + EXPECT_EQ(r, bPtr[0]) << "at x = " << x << " y = " << y; + EXPECT_EQ(g, bPtr[1]) << "at x = " << x << " y = " << y; + EXPECT_EQ(b, bPtr[2]) << "at x = " << x << " y = " << y; + break; + } default: { ADD_FAILURE() << "Unknown format for check:" << buf.format; break; @@ -189,6 +219,61 @@ void checkPixel(const CpuConsumer::LockedBuffer &buf, // Fill a YV12 buffer with a multi-colored checkerboard pattern void fillYV12Buffer(uint8_t* buf, int w, int h, int stride); +// Fill a Y8/Y16 buffer with a multi-colored checkerboard pattern +template <typename T> // T == uint8_t or uint16_t +void fillGreyscaleBuffer(T* buf, int w, int h, int stride, int bpp) { + const int blockWidth = w > 16 ? w / 16 : 1; + const int blockHeight = h > 16 ? h / 16 : 1; + const int yuvTexOffsetY = 0; + + ASSERT_TRUE(bpp == 8 || bpp == 16); + ASSERT_TRUE(sizeof(T)*8 == bpp); + + // stride is in pixels, not in bytes + int yuvTexStrideY = stride; + for (int x = 0; x < w; x++) { + for (int y = 0; y < h; y++) { + int parityX = (x / blockWidth) & 1; + int parityY = (y / blockHeight) & 1; + T intensity = (parityX ^ parityY) ? 63 : 191; + buf[yuvTexOffsetY + (y * yuvTexStrideY) + x] = intensity; + } + } +} + +inline uint8_t chooseColorRgba8888(int blockX, int blockY, uint8_t channel) { + const int colorVariations = 3; + uint8_t color = ((blockX % colorVariations) + (blockY % colorVariations)) + % (colorVariations) == channel ? 191: 63; + + return color; +} + +// Fill a RGBA8888 buffer with a multi-colored checkerboard pattern +void fillRgba8888Buffer(uint8_t* buf, int w, int h, int stride) +{ + const int blockWidth = w > 16 ? w / 16 : 1; + const int blockHeight = h > 16 ? h / 16 : 1; + const int bytesPerPixel = 4; + + // stride is in pixels, not in bytes + for (int x = 0; x < w; ++x) { + for (int y = 0; y < h; ++y) { + int blockX = (x / blockWidth); + int blockY = (y / blockHeight); + + uint8_t r = chooseColorRgba8888(blockX, blockY, 0); + uint8_t g = chooseColorRgba8888(blockX, blockY, 1); + uint8_t b = chooseColorRgba8888(blockX, blockY, 2); + + buf[(y*stride + x)*bytesPerPixel + 0] = r; + buf[(y*stride + x)*bytesPerPixel + 1] = g; + buf[(y*stride + x)*bytesPerPixel + 2] = b; + buf[(y*stride + x)*bytesPerPixel + 3] = 255; + } + } +} + // Fill a RAW sensor buffer with a multi-colored checkerboard pattern. // Assumes GRBG mosaic ordering. Result should be a grid in a 2x2 pattern // of [ R, B; G, W] @@ -217,6 +302,89 @@ void fillBayerRawBuffer(uint8_t* buf, int w, int h, int stride) { } +template<typename T> // uint8_t or uint16_t +void checkGreyscaleBuffer(const CpuConsumer::LockedBuffer &buf) { + uint32_t w = buf.width; + uint32_t h = buf.height; + const int blockWidth = w > 16 ? w / 16 : 1; + const int blockHeight = h > 16 ? h / 16 : 1; + const int blockRows = h / blockHeight; + const int blockCols = w / blockWidth; + + // Top-left square is bright + checkPixel(buf, 0, 0, 191); + checkPixel(buf, 1, 0, 191); + checkPixel(buf, 0, 1, 191); + checkPixel(buf, 1, 1, 191); + + // One-right square is dark + checkPixel(buf, blockWidth, 0, 63); + checkPixel(buf, blockWidth + 1, 0, 63); + checkPixel(buf, blockWidth, 1, 63); + checkPixel(buf, blockWidth + 1, 1, 63); + + // One-down square is dark + checkPixel(buf, 0, blockHeight, 63); + checkPixel(buf, 1, blockHeight, 63); + checkPixel(buf, 0, blockHeight + 1, 63); + checkPixel(buf, 1, blockHeight + 1, 63); + + // One-diag square is bright + checkPixel(buf, blockWidth, blockHeight, 191); + checkPixel(buf, blockWidth + 1, blockHeight, 191); + checkPixel(buf, blockWidth, blockHeight + 1, 191); + checkPixel(buf, blockWidth + 1, blockHeight + 1, 191); + + // Test bottom-right pixel + const int maxBlockX = ((w-1 + (blockWidth-1)) / blockWidth) & 0x1; + const int maxBlockY = ((h-1 + (blockHeight-1)) / blockHeight) & 0x1; + uint32_t pixelValue = ((maxBlockX % 2) == (maxBlockY % 2)) ? 191 : 63; + checkPixel(buf, w-1, h-1, pixelValue); +} + +void checkRgba8888Buffer(const CpuConsumer::LockedBuffer &buf) { + uint32_t w = buf.width; + uint32_t h = buf.height; + const int blockWidth = w > 16 ? w / 16 : 1; + const int blockHeight = h > 16 ? h / 16 : 1; + const int blockRows = h / blockHeight; + const int blockCols = w / blockWidth; + + // Top-left square is bright red + checkPixel(buf, 0, 0, 191, 63, 63); + checkPixel(buf, 1, 0, 191, 63, 63); + checkPixel(buf, 0, 1, 191, 63, 63); + checkPixel(buf, 1, 1, 191, 63, 63); + + // One-right square is bright green + checkPixel(buf, blockWidth, 0, 63, 191, 63); + checkPixel(buf, blockWidth + 1, 0, 63, 191, 63); + checkPixel(buf, blockWidth, 1, 63, 191, 63); + checkPixel(buf, blockWidth + 1, 1, 63, 191, 63); + + // One-down square is bright green + checkPixel(buf, 0, blockHeight, 63, 191, 63); + checkPixel(buf, 1, blockHeight, 63, 191, 63); + checkPixel(buf, 0, blockHeight + 1, 63, 191, 63); + checkPixel(buf, 1, blockHeight + 1, 63, 191, 63); + + // One-diag square is bright blue + checkPixel(buf, blockWidth, blockHeight, 63, 63, 191); + checkPixel(buf, blockWidth + 1, blockHeight, 63, 63, 191); + checkPixel(buf, blockWidth, blockHeight + 1, 63, 63, 191); + checkPixel(buf, blockWidth + 1, blockHeight + 1, 63, 63, 191); + + // Test bottom-right pixel + { + const int maxBlockX = ((w-1) / blockWidth); + const int maxBlockY = ((h-1) / blockHeight); + uint8_t r = chooseColorRgba8888(maxBlockX, maxBlockY, 0); + uint8_t g = chooseColorRgba8888(maxBlockX, maxBlockY, 1); + uint8_t b = chooseColorRgba8888(maxBlockX, maxBlockY, 2); + checkPixel(buf, w-1, h-1, r, g, b); + } +} + void checkBayerRawBuffer(const CpuConsumer::LockedBuffer &buf) { uint32_t w = buf.width; uint32_t h = buf.height; @@ -258,6 +426,23 @@ void checkBayerRawBuffer(const CpuConsumer::LockedBuffer &buf) { checkPixel(buf, w-1, h-1, maxR, maxG, maxB); } +void checkAnyBuffer(const CpuConsumer::LockedBuffer &buf, int format) { + switch (format) { + case HAL_PIXEL_FORMAT_RAW_SENSOR: + checkBayerRawBuffer(buf); + break; + case HAL_PIXEL_FORMAT_Y8: + checkGreyscaleBuffer<uint8_t>(buf); + break; + case HAL_PIXEL_FORMAT_Y16: + checkGreyscaleBuffer<uint16_t>(buf); + break; + case HAL_PIXEL_FORMAT_RGBA_8888: + checkRgba8888Buffer(buf); + break; + } +} + void fillYV12BufferRect(uint8_t* buf, int w, int h, int stride, const android_native_rect_t& rect); @@ -322,6 +507,18 @@ void produceOneFrame(const sp<ANativeWindow>& anw, case HAL_PIXEL_FORMAT_RAW_SENSOR: fillBayerRawBuffer(img, params.width, params.height, buf->getStride()); break; + case HAL_PIXEL_FORMAT_Y8: + fillGreyscaleBuffer<uint8_t>(img, params.width, params.height, + buf->getStride(), /*bpp*/8); + break; + case HAL_PIXEL_FORMAT_Y16: + fillGreyscaleBuffer<uint16_t>((uint16_t*)img, params.width, + params.height, buf->getStride(), + /*bpp*/16); + break; + case HAL_PIXEL_FORMAT_RGBA_8888: + fillRgba8888Buffer(img, params.width, params.height, buf->getStride()); + break; default: FAIL() << "Unknown pixel format under test!"; break; @@ -341,7 +538,7 @@ void produceOneFrame(const sp<ANativeWindow>& anw, // This test is disabled because the HAL_PIXEL_FORMAT_RAW_SENSOR format is not // supported on all devices. -TEST_P(CpuConsumerTest, DISABLED_FromCpuSingle) { +TEST_P(CpuConsumerTest, FromCpuSingle) { status_t err; CpuConsumerTestParams params = GetParam(); @@ -369,13 +566,13 @@ TEST_P(CpuConsumerTest, DISABLED_FromCpuSingle) { EXPECT_EQ(stride, b.stride); EXPECT_EQ(time, b.timestamp); - checkBayerRawBuffer(b); + checkAnyBuffer(b, GetParam().format); mCC->unlockBuffer(b); } // This test is disabled because the HAL_PIXEL_FORMAT_RAW_SENSOR format is not // supported on all devices. -TEST_P(CpuConsumerTest, DISABLED_FromCpuManyInQueue) { +TEST_P(CpuConsumerTest, FromCpuManyInQueue) { status_t err; CpuConsumerTestParams params = GetParam(); @@ -410,7 +607,7 @@ TEST_P(CpuConsumerTest, DISABLED_FromCpuManyInQueue) { EXPECT_EQ(stride[i], b.stride); EXPECT_EQ(time[i], b.timestamp); - checkBayerRawBuffer(b); + checkAnyBuffer(b, GetParam().format); mCC->unlockBuffer(b); } @@ -418,7 +615,7 @@ TEST_P(CpuConsumerTest, DISABLED_FromCpuManyInQueue) { // This test is disabled because the HAL_PIXEL_FORMAT_RAW_SENSOR format is not // supported on all devices. -TEST_P(CpuConsumerTest, DISABLED_FromCpuLockMax) { +TEST_P(CpuConsumerTest, FromCpuLockMax) { status_t err; CpuConsumerTestParams params = GetParam(); @@ -452,7 +649,7 @@ TEST_P(CpuConsumerTest, DISABLED_FromCpuLockMax) { EXPECT_EQ(stride, b[i].stride); EXPECT_EQ(time, b[i].timestamp); - checkBayerRawBuffer(b[i]); + checkAnyBuffer(b[i], GetParam().format); } ALOGV("Locking frame %d (too many)", params.maxLockedBuffers); @@ -475,7 +672,7 @@ TEST_P(CpuConsumerTest, DISABLED_FromCpuLockMax) { EXPECT_EQ(stride, bTooMuch.stride); EXPECT_EQ(time, bTooMuch.timestamp); - checkBayerRawBuffer(bTooMuch); + checkAnyBuffer(bTooMuch, GetParam().format); ALOGV("Unlocking extra buffer"); err = mCC->unlockBuffer(bTooMuch); @@ -493,17 +690,66 @@ TEST_P(CpuConsumerTest, DISABLED_FromCpuLockMax) { } +CpuConsumerTestParams y8TestSets[] = { + { 512, 512, 1, HAL_PIXEL_FORMAT_Y8}, + { 512, 512, 3, HAL_PIXEL_FORMAT_Y8}, + { 2608, 1960, 1, HAL_PIXEL_FORMAT_Y8}, + { 2608, 1960, 3, HAL_PIXEL_FORMAT_Y8}, + { 100, 100, 1, HAL_PIXEL_FORMAT_Y8}, + { 100, 100, 3, HAL_PIXEL_FORMAT_Y8}, +}; + +CpuConsumerTestParams y16TestSets[] = { + { 512, 512, 1, HAL_PIXEL_FORMAT_Y16}, + { 512, 512, 3, HAL_PIXEL_FORMAT_Y16}, + { 2608, 1960, 1, HAL_PIXEL_FORMAT_Y16}, + { 2608, 1960, 3, HAL_PIXEL_FORMAT_Y16}, + { 100, 100, 1, HAL_PIXEL_FORMAT_Y16}, + { 100, 100, 3, HAL_PIXEL_FORMAT_Y16}, +}; + CpuConsumerTestParams rawTestSets[] = { { 512, 512, 1, HAL_PIXEL_FORMAT_RAW_SENSOR}, { 512, 512, 3, HAL_PIXEL_FORMAT_RAW_SENSOR}, { 2608, 1960, 1, HAL_PIXEL_FORMAT_RAW_SENSOR}, { 2608, 1960, 3, HAL_PIXEL_FORMAT_RAW_SENSOR}, { 100, 100, 1, HAL_PIXEL_FORMAT_RAW_SENSOR}, - { 100, 100, 3, HAL_PIXEL_FORMAT_RAW_SENSOR} + { 100, 100, 3, HAL_PIXEL_FORMAT_RAW_SENSOR}, +}; + +CpuConsumerTestParams rgba8888TestSets[] = { + { 512, 512, 1, HAL_PIXEL_FORMAT_RGBA_8888}, + { 512, 512, 3, HAL_PIXEL_FORMAT_RGBA_8888}, + { 2608, 1960, 1, HAL_PIXEL_FORMAT_RGBA_8888}, + { 2608, 1960, 3, HAL_PIXEL_FORMAT_RGBA_8888}, + { 100, 100, 1, HAL_PIXEL_FORMAT_RGBA_8888}, + { 100, 100, 3, HAL_PIXEL_FORMAT_RGBA_8888}, }; +#if CPU_CONSUMER_TEST_FORMAT_Y8 +INSTANTIATE_TEST_CASE_P(Y8Tests, + CpuConsumerTest, + ::testing::ValuesIn(y8TestSets)); +#endif + +#if CPU_CONSUMER_TEST_FORMAT_Y16 +INSTANTIATE_TEST_CASE_P(Y16Tests, + CpuConsumerTest, + ::testing::ValuesIn(y16TestSets)); +#endif + +#if CPU_CONSUMER_TEST_FORMAT_RAW INSTANTIATE_TEST_CASE_P(RawTests, CpuConsumerTest, ::testing::ValuesIn(rawTestSets)); +#endif + +#if CPU_CONSUMER_TEST_FORMAT_RGBA_8888 +INSTANTIATE_TEST_CASE_P(Rgba8888Tests, + CpuConsumerTest, + ::testing::ValuesIn(rgba8888TestSets)); +#endif + + } // namespace android diff --git a/libs/gui/tests/SurfaceTextureClient_test.cpp b/libs/gui/tests/SurfaceTextureClient_test.cpp index ec14a0d..7376b4c 100644 --- a/libs/gui/tests/SurfaceTextureClient_test.cpp +++ b/libs/gui/tests/SurfaceTextureClient_test.cpp @@ -19,7 +19,7 @@ #include <EGL/egl.h> #include <gtest/gtest.h> -#include <gui/SurfaceTextureClient.h> +#include <gui/Surface.h> #include <system/graphics.h> #include <utils/Log.h> #include <utils/Thread.h> @@ -40,8 +40,8 @@ protected: ALOGV("Begin test: %s.%s", testInfo->test_case_name(), testInfo->name()); - mST = new SurfaceTexture(123); - mSTC = new SurfaceTextureClient(mST); + mST = new GLConsumer(123); + mSTC = new Surface(mST->getBufferQueue()); mANW = mSTC; // We need a valid GL context so we can test updateTexImage() @@ -61,6 +61,7 @@ protected: &myConfig, 1, &numConfigs)); ASSERT_EQ(EGL_SUCCESS, eglGetError()); + mEglConfig = myConfig; EGLint pbufferAttribs[] = { EGL_WIDTH, 16, EGL_HEIGHT, 16, @@ -95,24 +96,25 @@ protected: virtual EGLint const* getConfigAttribs() { static EGLint sDefaultConfigAttribs[] = { - EGL_SURFACE_TYPE, EGL_PBUFFER_BIT, + EGL_SURFACE_TYPE, EGL_PBUFFER_BIT | EGL_WINDOW_BIT, EGL_NONE }; return sDefaultConfigAttribs; } - sp<SurfaceTexture> mST; - sp<SurfaceTextureClient> mSTC; + sp<GLConsumer> mST; + sp<Surface> mSTC; sp<ANativeWindow> mANW; EGLDisplay mEglDisplay; EGLSurface mEglSurface; EGLContext mEglContext; + EGLConfig mEglConfig; }; TEST_F(SurfaceTextureClientTest, GetISurfaceTextureIsNotNull) { - sp<ISurfaceTexture> ist(mSTC->getISurfaceTexture()); + sp<IGraphicBufferProducer> ist(mSTC->getIGraphicBufferProducer()); ASSERT_TRUE(ist != NULL); } @@ -128,7 +130,7 @@ TEST_F(SurfaceTextureClientTest, ConcreteTypeIsSurfaceTextureClient) { int result = -123; int err = mANW->query(mANW.get(), NATIVE_WINDOW_CONCRETE_TYPE, &result); EXPECT_EQ(NO_ERROR, err); - EXPECT_EQ(NATIVE_WINDOW_SURFACE_TEXTURE_CLIENT, result); + EXPECT_EQ(NATIVE_WINDOW_SURFACE, result); } TEST_F(SurfaceTextureClientTest, EglCreateWindowSurfaceSucceeds) { @@ -169,6 +171,34 @@ TEST_F(SurfaceTextureClientTest, EglCreateWindowSurfaceSucceeds) { eglTerminate(dpy); } +TEST_F(SurfaceTextureClientTest, EglSwapBuffersAbandonErrorIsEglBadSurface) { + + EGLSurface eglSurface = eglCreateWindowSurface(mEglDisplay, mEglConfig, mANW.get(), NULL); + EXPECT_NE(EGL_NO_SURFACE, eglSurface); + EXPECT_EQ(EGL_SUCCESS, eglGetError()); + + EGLBoolean success = eglMakeCurrent(mEglDisplay, eglSurface, eglSurface, mEglContext); + EXPECT_TRUE(success); + + glClear(GL_COLOR_BUFFER_BIT); + success = eglSwapBuffers(mEglDisplay, eglSurface); + EXPECT_TRUE(success); + + mST->abandon(); + + glClear(GL_COLOR_BUFFER_BIT); + success = eglSwapBuffers(mEglDisplay, eglSurface); + EXPECT_FALSE(success); + EXPECT_EQ(EGL_BAD_SURFACE, eglGetError()); + + success = eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext); + ASSERT_TRUE(success); + + if (eglSurface != EGL_NO_SURFACE) { + eglDestroySurface(mEglDisplay, eglSurface); + } +} + TEST_F(SurfaceTextureClientTest, BufferGeometryInvalidSizesFail) { EXPECT_GT(OK, native_window_set_buffers_geometry(mANW.get(), -1, 0, 0)); EXPECT_GT(OK, native_window_set_buffers_geometry(mANW.get(), 0, -1, 0)); @@ -250,7 +280,7 @@ TEST_F(SurfaceTextureClientTest, BufferGeometrySizeCanBeChangedWithoutFormat) { } TEST_F(SurfaceTextureClientTest, SurfaceTextureSetDefaultSize) { - sp<SurfaceTexture> st(mST); + sp<GLConsumer> st(mST); ANativeWindowBuffer* buf; EXPECT_EQ(OK, st->setDefaultBufferSize(16, 8)); ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf)); @@ -464,7 +494,7 @@ TEST_F(SurfaceTextureClientTest, SetCropCropsCrop) { // from the SurfaceTexture class. TEST_F(SurfaceTextureClientTest, DISABLED_SurfaceTextureSyncModeWaitRetire) { class MyThread : public Thread { - sp<SurfaceTexture> mST; + sp<GLConsumer> mST; EGLContext ctx; EGLSurface sur; EGLDisplay dpy; @@ -480,7 +510,7 @@ TEST_F(SurfaceTextureClientTest, DISABLED_SurfaceTextureSyncModeWaitRetire) { return false; } public: - MyThread(const sp<SurfaceTexture>& mST) + MyThread(const sp<GLConsumer>& mST) : mST(mST), mBufferRetired(false) { ctx = eglGetCurrentContext(); sur = eglGetCurrentSurface(EGL_DRAW); @@ -685,8 +715,8 @@ protected: ASSERT_NE(EGL_NO_CONTEXT, mEglContext); for (int i = 0; i < NUM_SURFACE_TEXTURES; i++) { - sp<SurfaceTexture> st(new SurfaceTexture(i)); - sp<SurfaceTextureClient> stc(new SurfaceTextureClient(st)); + sp<GLConsumer> st(new GLConsumer(i)); + sp<Surface> stc(new Surface(st->getBufferQueue())); mEglSurfaces[i] = eglCreateWindowSurface(mEglDisplay, myConfig, static_cast<ANativeWindow*>(stc.get()), NULL); ASSERT_EQ(EGL_SUCCESS, eglGetError()); diff --git a/libs/gui/tests/SurfaceTexture_test.cpp b/libs/gui/tests/SurfaceTexture_test.cpp index d9b40cf..dd6c435 100644 --- a/libs/gui/tests/SurfaceTexture_test.cpp +++ b/libs/gui/tests/SurfaceTexture_test.cpp @@ -18,8 +18,7 @@ //#define LOG_NDEBUG 0 #include <gtest/gtest.h> -#include <gui/SurfaceTexture.h> -#include <gui/SurfaceTextureClient.h> +#include <gui/GLConsumer.h> #include <ui/GraphicBuffer.h> #include <utils/String8.h> #include <utils/threads.h> @@ -30,10 +29,14 @@ #include <EGL/egl.h> #include <EGL/eglext.h> +#include <GLES/gl.h> +#include <GLES/glext.h> #include <GLES2/gl2.h> #include <GLES2/gl2ext.h> #include <ui/FramebufferNativeWindow.h> +#include <utils/UniquePtr.h> +#include <android/native_window.h> namespace android { @@ -202,7 +205,6 @@ protected: while ((err = glGetError()) != GL_NO_ERROR) { msg += String8::format(", %#x", err); } - fprintf(stderr, "pixel check failure: %s\n", msg.string()); return ::testing::AssertionFailure( ::testing::Message(msg.string())); } @@ -228,7 +230,6 @@ protected: msg += String8::format("a(%d isn't %d)", pixel[3], a); } if (!msg.isEmpty()) { - fprintf(stderr, "pixel check failure: %s\n", msg.string()); return ::testing::AssertionFailure( ::testing::Message(msg.string())); } else { @@ -378,14 +379,108 @@ static int abs(int value) { // XXX: Code above this point should live elsewhere +class MultiTextureConsumerTest : public GLTest { +protected: + enum { TEX_ID = 123 }; + + virtual void SetUp() { + GLTest::SetUp(); + mGlConsumer = new GLConsumer(TEX_ID); + mSurface = new Surface(mGlConsumer->getBufferQueue()); + mANW = mSurface.get(); + + } + virtual void TearDown() { + GLTest::TearDown(); + } + virtual EGLint const* getContextAttribs() { + return NULL; + } + virtual EGLint const* getConfigAttribs() { + static EGLint sDefaultConfigAttribs[] = { + EGL_SURFACE_TYPE, EGL_PBUFFER_BIT, + EGL_RED_SIZE, 8, + EGL_GREEN_SIZE, 8, + EGL_BLUE_SIZE, 8, + EGL_ALPHA_SIZE, 8, + EGL_NONE }; + + return sDefaultConfigAttribs; + } + sp<GLConsumer> mGlConsumer; + sp<Surface> mSurface; + ANativeWindow* mANW; +}; + + +TEST_F(MultiTextureConsumerTest, EGLImageTargetWorks) { + ANativeWindow_Buffer buffer; + + ASSERT_EQ(native_window_set_usage(mANW, GRALLOC_USAGE_SW_WRITE_OFTEN), NO_ERROR); + ASSERT_EQ(native_window_set_buffers_format(mANW, HAL_PIXEL_FORMAT_RGBA_8888), NO_ERROR); + + glShadeModel(GL_FLAT); + glDisable(GL_DITHER); + glDisable(GL_CULL_FACE); + glViewport(0, 0, getSurfaceWidth(), getSurfaceHeight()); + glOrthof(0, getSurfaceWidth(), 0, getSurfaceHeight(), 0, 1); + glEnableClientState(GL_VERTEX_ARRAY); + glColor4f(1, 1, 1, 1); + + glBindTexture(GL_TEXTURE_EXTERNAL_OES, TEX_ID); + glTexParameterx(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameterx(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameterx(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameterx(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + + uint32_t texel = 0x80808080; + glBindTexture(GL_TEXTURE_2D, TEX_ID+1); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, &texel); + glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, TEX_ID+1); + glEnable(GL_TEXTURE_2D); + glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_EXTERNAL_OES, TEX_ID); + glEnable(GL_TEXTURE_EXTERNAL_OES); + glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + + glClear(GL_COLOR_BUFFER_BIT); + for (int i=0 ; i<8 ; i++) { + mSurface->lock(&buffer, NULL); + memset(buffer.bits, (i&7) * 0x20, buffer.stride * buffer.height * 4); + mSurface->unlockAndPost(); + + mGlConsumer->updateTexImage(); + + GLfloat vertices[][2] = { {i*16.0f, 0}, {(i+1)*16.0f, 0}, {(i+1)*16.0f, 16.0f}, {i*16.0f, 16.0f} }; + glVertexPointer(2, GL_FLOAT, 0, vertices); + glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + + ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError()); + } + + for (int i=0 ; i<8 ; i++) { + EXPECT_TRUE(checkPixel(i*16 + 8, 8, i*16, i*16, i*16, i*16, 0)); + } +} + + + class SurfaceTextureGLTest : public GLTest { protected: enum { TEX_ID = 123 }; virtual void SetUp() { GLTest::SetUp(); - mST = new SurfaceTexture(TEX_ID); - mSTC = new SurfaceTextureClient(mST); + mST = new GLConsumer(TEX_ID); + mSTC = new Surface(mST->getBufferQueue()); mANW = mSTC; mTextureRenderer = new TextureRenderer(TEX_ID, mST); ASSERT_NO_FATAL_FAILURE(mTextureRenderer->SetUp()); @@ -406,7 +501,7 @@ protected: class TextureRenderer: public RefBase { public: - TextureRenderer(GLuint texName, const sp<SurfaceTexture>& st): + TextureRenderer(GLuint texName, const sp<GLConsumer>& st): mTexName(texName), mST(st) { } @@ -447,7 +542,7 @@ protected: ASSERT_NE(-1, mTexMatrixHandle); } - // drawTexture draws the SurfaceTexture over the entire GL viewport. + // drawTexture draws the GLConsumer over the entire GL viewport. void drawTexture() { static const GLfloat triangleVertices[] = { -1.0f, 1.0f, @@ -494,14 +589,14 @@ protected: } GLuint mTexName; - sp<SurfaceTexture> mST; + sp<GLConsumer> mST; GLuint mPgm; GLint mPositionHandle; GLint mTexSamplerHandle; GLint mTexMatrixHandle; }; - class FrameWaiter : public SurfaceTexture::FrameAvailableListener { + class FrameWaiter : public GLConsumer::FrameAvailableListener { public: FrameWaiter(): mPendingFrames(0) { @@ -526,7 +621,7 @@ protected: Condition mCondition; }; - // Note that SurfaceTexture will lose the notifications + // Note that GLConsumer will lose the notifications // onBuffersReleased and onFrameAvailable as there is currently // no way to forward the events. This DisconnectWaiter will not let the // disconnect finish until finishDisconnect() is called. It will @@ -575,8 +670,8 @@ protected: Condition mFrameCondition; }; - sp<SurfaceTexture> mST; - sp<SurfaceTextureClient> mSTC; + sp<GLConsumer> mST; + sp<Surface> mSTC; sp<ANativeWindow> mANW; sp<TextureRenderer> mTextureRenderer; sp<FrameWaiter> mFW; @@ -719,18 +814,18 @@ TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledYV12BufferNpot) { glViewport(0, 0, texWidth, texHeight); drawTexture(); - EXPECT_TRUE(checkPixel( 0, 0, 255, 127, 255, 255)); - EXPECT_TRUE(checkPixel(63, 0, 0, 133, 0, 255)); - EXPECT_TRUE(checkPixel(63, 65, 0, 133, 0, 255)); - EXPECT_TRUE(checkPixel( 0, 65, 255, 127, 255, 255)); - - EXPECT_TRUE(checkPixel(22, 44, 255, 127, 255, 255)); - EXPECT_TRUE(checkPixel(45, 52, 255, 127, 255, 255)); - EXPECT_TRUE(checkPixel(52, 51, 98, 255, 73, 255)); - EXPECT_TRUE(checkPixel( 7, 31, 155, 0, 118, 255)); - EXPECT_TRUE(checkPixel(31, 9, 107, 24, 87, 255)); - EXPECT_TRUE(checkPixel(29, 35, 255, 127, 255, 255)); - EXPECT_TRUE(checkPixel(36, 22, 155, 29, 0, 255)); + EXPECT_TRUE(checkPixel( 0, 0, 255, 127, 255, 255, 3)); + EXPECT_TRUE(checkPixel(63, 0, 0, 133, 0, 255, 3)); + EXPECT_TRUE(checkPixel(63, 65, 0, 133, 0, 255, 3)); + EXPECT_TRUE(checkPixel( 0, 65, 255, 127, 255, 255, 3)); + + EXPECT_TRUE(checkPixel(22, 44, 255, 127, 255, 255, 3)); + EXPECT_TRUE(checkPixel(45, 52, 255, 127, 255, 255, 3)); + EXPECT_TRUE(checkPixel(52, 51, 98, 255, 73, 255, 3)); + EXPECT_TRUE(checkPixel( 7, 31, 155, 0, 118, 255, 3)); + EXPECT_TRUE(checkPixel(31, 9, 107, 24, 87, 255, 3)); + EXPECT_TRUE(checkPixel(29, 35, 255, 127, 255, 255, 3)); + EXPECT_TRUE(checkPixel(36, 22, 155, 29, 0, 255, 3)); } TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledYV12BufferPow2) { @@ -1070,7 +1165,7 @@ TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledRGBABufferPow2) { EXPECT_TRUE(checkPixel( 3, 52, 35, 231, 35, 35)); } -// Tests if SurfaceTexture and BufferQueue are robust enough +// Tests if GLConsumer and BufferQueue are robust enough // to handle a special case where updateTexImage is called // in the middle of disconnect. This ordering is enforced // by blocking in the disconnect callback. @@ -1123,12 +1218,12 @@ TEST_F(SurfaceTextureGLTest, DisconnectStressTest) { sp<Thread> pt(new ProducerThread(mANW)); pt->run(); - // eat a frame so SurfaceTexture will own an at least one slot + // eat a frame so GLConsumer will own an at least one slot dw->waitForFrame(); EXPECT_EQ(OK,mST->updateTexImage()); dw->waitForFrame(); - // Could fail here as SurfaceTexture thinks it still owns the slot + // Could fail here as GLConsumer thinks it still owns the slot // but bufferQueue has released all slots EXPECT_EQ(OK,mST->updateTexImage()); @@ -1136,7 +1231,7 @@ TEST_F(SurfaceTextureGLTest, DisconnectStressTest) { } -// This test ensures that the SurfaceTexture clears the mCurrentTexture +// This test ensures that the GLConsumer clears the mCurrentTexture // when it is disconnected and reconnected. Otherwise it will // attempt to release a buffer that it does not owned TEST_F(SurfaceTextureGLTest, DisconnectClearsCurrentTexture) { @@ -1581,7 +1676,7 @@ TEST_F(SurfaceTextureGLToGLTest, EglDestroySurfaceUnrefsBuffers) { // This test should have the only reference to buffer 0. EXPECT_EQ(1, buffers[0]->getStrongCount()); - // The SurfaceTexture should hold a single reference to buffer 1 in its + // The GLConsumer should hold a single reference to buffer 1 in its // mCurrentBuffer member. All of the references in the slots should have // been released. EXPECT_EQ(2, buffers[1]->getStrongCount()); @@ -1615,7 +1710,7 @@ TEST_F(SurfaceTextureGLToGLTest, EglDestroySurfaceAfterAbandonUnrefsBuffers) { buffers[i] = mST->getCurrentBuffer(); } - // Abandon the SurfaceTexture, releasing the ref that the SurfaceTexture has + // Abandon the GLConsumer, releasing the ref that the GLConsumer has // on buffers[2]. mST->abandon(); @@ -1639,6 +1734,81 @@ TEST_F(SurfaceTextureGLToGLTest, EglDestroySurfaceAfterAbandonUnrefsBuffers) { } } +TEST_F(SurfaceTextureGLToGLTest, EglMakeCurrentBeforeConsumerDeathUnrefsBuffers) { + sp<GraphicBuffer> buffer; + + EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mProducerEglSurface, + mProducerEglSurface, mProducerEglContext)); + + // Produce a frame + glClear(GL_COLOR_BUFFER_BIT); + EXPECT_TRUE(eglSwapBuffers(mEglDisplay, mProducerEglSurface)); + ASSERT_EQ(EGL_SUCCESS, eglGetError()); + + // Destroy the EGLSurface. + EXPECT_TRUE(eglDestroySurface(mEglDisplay, mProducerEglSurface)); + ASSERT_EQ(EGL_SUCCESS, eglGetError()); + mProducerEglSurface = EGL_NO_SURFACE; + mSTC.clear(); + mANW.clear(); + mTextureRenderer.clear(); + + // Consume a frame + ASSERT_EQ(NO_ERROR, mST->updateTexImage()); + buffer = mST->getCurrentBuffer(); + + // Destroy the GL texture object to release its ref + GLuint texID = TEX_ID; + glDeleteTextures(1, &texID); + + // make un-current, all references to buffer should be gone + EXPECT_TRUE(eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, + EGL_NO_SURFACE, EGL_NO_CONTEXT)); + + // Destroy consumer + mST.clear(); + + EXPECT_EQ(1, buffer->getStrongCount()); +} + +TEST_F(SurfaceTextureGLToGLTest, EglMakeCurrentAfterConsumerDeathUnrefsBuffers) { + sp<GraphicBuffer> buffer; + + EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mProducerEglSurface, + mProducerEglSurface, mProducerEglContext)); + + // Produce a frame + glClear(GL_COLOR_BUFFER_BIT); + EXPECT_TRUE(eglSwapBuffers(mEglDisplay, mProducerEglSurface)); + ASSERT_EQ(EGL_SUCCESS, eglGetError()); + + // Destroy the EGLSurface. + EXPECT_TRUE(eglDestroySurface(mEglDisplay, mProducerEglSurface)); + ASSERT_EQ(EGL_SUCCESS, eglGetError()); + mProducerEglSurface = EGL_NO_SURFACE; + mSTC.clear(); + mANW.clear(); + mTextureRenderer.clear(); + + // Consume a frame + ASSERT_EQ(NO_ERROR, mST->updateTexImage()); + buffer = mST->getCurrentBuffer(); + + // Destroy the GL texture object to release its ref + GLuint texID = TEX_ID; + glDeleteTextures(1, &texID); + + // Destroy consumer + mST.clear(); + + // make un-current, all references to buffer should be gone + EXPECT_TRUE(eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, + EGL_NO_SURFACE, EGL_NO_CONTEXT)); + + EXPECT_EQ(1, buffer->getStrongCount()); +} + + TEST_F(SurfaceTextureGLToGLTest, EglSurfaceDefaultsToSynchronousMode) { // This test requires 3 buffers to run on a single thread. mST->setDefaultMaxBufferCount(3); @@ -1847,7 +2017,7 @@ TEST_F(SurfaceTextureGLToGLTest, TexturingFromPreRotatedGLFilledBuffer) { * This test fixture is for testing GL -> GL texture streaming from one thread * to another. It contains functionality to create a producer thread that will * perform GL rendering to an ANativeWindow that feeds frames to a - * SurfaceTexture. Additionally it supports interlocking the producer and + * GLConsumer. Additionally it supports interlocking the producer and * consumer threads so that a specific sequence of calls can be * deterministically created by the test. * @@ -1914,13 +2084,13 @@ protected: // FrameCondition is a utility class for interlocking between the producer // and consumer threads. The FrameCondition object should be created and // destroyed in the consumer thread only. The consumer thread should set - // the FrameCondition as the FrameAvailableListener of the SurfaceTexture, + // the FrameCondition as the FrameAvailableListener of the GLConsumer, // and should call both waitForFrame and finishFrame once for each expected // frame. // // This interlocking relies on the fact that onFrameAvailable gets called - // synchronously from SurfaceTexture::queueBuffer. - class FrameCondition : public SurfaceTexture::FrameAvailableListener { + // synchronously from GLConsumer::queueBuffer. + class FrameCondition : public GLConsumer::FrameAvailableListener { public: FrameCondition(): mFrameAvailable(false), @@ -1951,7 +2121,7 @@ protected: ALOGV("-finishFrame"); } - // This should be called by SurfaceTexture on the producer thread. + // This should be called by GLConsumer on the producer thread. virtual void onFrameAvailable() { Mutex::Autolock lock(mMutex); ALOGV("+onFrameAvailable"); diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index 545b547..429becf 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -23,11 +23,17 @@ #include <utils/String8.h> #include <private/gui/ComposerService.h> +#include <binder/ProcessState.h> namespace android { class SurfaceTest : public ::testing::Test { protected: + + SurfaceTest() { + ProcessState::self()->startThreadPool(); + } + virtual void SetUp() { mComposerClient = new SurfaceComposerClient; ASSERT_EQ(NO_ERROR, mComposerClient->initCheck()); @@ -81,14 +87,11 @@ TEST_F(SurfaceTest, ScreenshotsOfProtectedBuffersSucceed) { sp<ANativeWindow> anw(mSurface); // Verify the screenshot works with no protected buffers. - sp<IMemoryHeap> heap; - uint32_t w=0, h=0; - PixelFormat fmt=0; + sp<CpuConsumer> consumer = new CpuConsumer(1); sp<ISurfaceComposer> sf(ComposerService::getComposerService()); sp<IBinder> display(sf->getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain)); - ASSERT_EQ(NO_ERROR, sf->captureScreen(display, &heap, &w, &h, &fmt, 64, 64, 0, - 0x7fffffff)); - ASSERT_TRUE(heap != NULL); + ASSERT_EQ(NO_ERROR, sf->captureScreen(display, consumer->getBufferQueue(), + 64, 64, 0, 0x7fffffff, true)); // Set the PROTECTED usage bit and verify that the screenshot fails. Note // that we need to dequeue a buffer in order for it to actually get @@ -116,11 +119,8 @@ TEST_F(SurfaceTest, ScreenshotsOfProtectedBuffersSucceed) { &buf)); ASSERT_EQ(NO_ERROR, anw->queueBuffer(anw.get(), buf, -1)); } - heap = 0; - w = h = fmt = 0; - ASSERT_EQ(NO_ERROR, sf->captureScreen(display, &heap, &w, &h, &fmt, - 64, 64, 0, 0x7fffffff)); - ASSERT_TRUE(heap != NULL); + ASSERT_EQ(NO_ERROR, sf->captureScreen(display, consumer->getBufferQueue(), + 64, 64, 0, 0x7fffffff, true)); } TEST_F(SurfaceTest, ConcreteTypeIsSurface) { |