From 74d211ae26a0257c6075a823812e40b55aa1e653 Mon Sep 17 00:00:00 2001 From: Mathias Agopian Date: Mon, 22 Apr 2013 16:55:35 +0200 Subject: clean-up/simplify all dump() APIs remove the scratch buffer parameter and use String8::appendFormat() instead. Change-Id: Ib96c91617c8e7292de87433d15cf6232b7d591b0 --- libs/gui/BufferQueue.cpp | 25 ++++++++----------------- 1 file changed, 8 insertions(+), 17 deletions(-) (limited to 'libs/gui/BufferQueue.cpp') diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp index b4c72315af..942151f808 100644 --- a/libs/gui/BufferQueue.cpp +++ b/libs/gui/BufferQueue.cpp @@ -707,36 +707,29 @@ status_t BufferQueue::disconnect(int api) { return err; } -void BufferQueue::dump(String8& result) const -{ - char buffer[1024]; - BufferQueue::dump(result, "", buffer, 1024); +void BufferQueue::dump(String8& result) const { + BufferQueue::dump(result, ""); } -void BufferQueue::dump(String8& result, const char* prefix, - char* buffer, size_t SIZE) const -{ +void BufferQueue::dump(String8& result, const char* prefix) const { Mutex::Autolock _l(mMutex); String8 fifo; int fifoSize = 0; Fifo::const_iterator i(mQueue.begin()); while (i != mQueue.end()) { - snprintf(buffer, SIZE, "%02d ", *i++); - fifoSize++; - fifo.append(buffer); + fifo.appendFormat("%02d ", *i++); + fifoSize++; } int maxBufferCount = getMaxBufferCountLocked(); - snprintf(buffer, SIZE, + result.appendFormat( "%s-BufferQueue maxBufferCount=%d, mSynchronousMode=%d, default-size=[%dx%d], " "default-format=%d, transform-hint=%02x, FIFO(%d)={%s}\n", prefix, maxBufferCount, mSynchronousMode, mDefaultWidth, mDefaultHeight, mDefaultBufferFormat, mTransformHint, fifoSize, fifo.string()); - result.append(buffer); - struct { const char * operator()(int state) const { @@ -752,7 +745,7 @@ void BufferQueue::dump(String8& result, const char* prefix, for (int i=0 ; i& buf(slot.mGraphicBuffer); if (buf != NULL) { - snprintf(buffer, SIZE, + result.appendFormat( ", %p [%4ux%4u:%4u,%3X]", buf->handle, buf->width, buf->height, buf->stride, buf->format); - result.append(buffer); } result.append("\n"); } -- cgit v1.2.3-59-g8ed1b From c5d7b7d323bba8772a9005f7d300ad983a04733a Mon Sep 17 00:00:00 2001 From: Lajos Molnar Date: Fri, 3 May 2013 14:50:50 -0700 Subject: BufferQueue: track buffer-queue by instance vs. by reference Instead of representing the buffer-queue as a vector of buffer indices, represent them as a vector of BufferItems (copies). This allows modifying the buffer slots independent of the queued buffers. As part of this change, BufferSlot properties that are only been relevant in the buffer-queue have been removed. Also, invalid scalingMode in queueBuffer now returns an error. ConsumerBase has also changed to allow reuse of the same buffer slots by different buffers. Change-Id: If2a698fa142b67c69ad41b8eaca6e127eb3ef75b Signed-off-by: Lajos Molnar Related-to-bug: 7093648 --- include/gui/BufferQueue.h | 38 ++-- include/gui/ConsumerBase.h | 19 +- include/gui/GLConsumer.h | 10 +- libs/gui/BufferItemConsumer.cpp | 4 +- libs/gui/BufferQueue.cpp | 198 ++++++++++++++------- libs/gui/ConsumerBase.cpp | 47 ++++- libs/gui/CpuConsumer.cpp | 4 +- libs/gui/GLConsumer.cpp | 28 ++- .../DisplayHardware/FramebufferSurface.cpp | 7 +- services/surfaceflinger/SurfaceFlingerConsumer.cpp | 2 +- 10 files changed, 232 insertions(+), 125 deletions(-) (limited to 'libs/gui/BufferQueue.cpp') diff --git a/include/gui/BufferQueue.h b/include/gui/BufferQueue.h index 34264bf268..8475a71433 100644 --- a/include/gui/BufferQueue.h +++ b/include/gui/BufferQueue.h @@ -240,7 +240,8 @@ public: mScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE), mTimestamp(0), mFrameNumber(0), - mBuf(INVALID_BUFFER_SLOT) { + mBuf(INVALID_BUFFER_SLOT), + mAcquireCalled(false) { mCrop.makeInvalid(); } // mGraphicBuffer points to the buffer allocated for this slot, or is NULL @@ -269,6 +270,9 @@ public: // mFence is a fence that will signal when the buffer is idle. sp mFence; + + // Indicates whether this buffer has been seen by a consumer yet + bool mAcquireCalled; }; // The following public functions are the consumer-facing interface @@ -285,7 +289,7 @@ public: // releaseBuffer releases a buffer slot from the consumer back to the // BufferQueue. This may be done while the buffer's contents are still // being accessed. The fence will signal when the buffer is no longer - // in use. + // in use. frameNumber is used to indentify the exact buffer returned. // // If releaseBuffer returns STALE_BUFFER_SLOT, then the consumer must free // any references to the just-released buffer that it might have, as if it @@ -294,7 +298,8 @@ public: // // Note that the dependencies on EGL will be removed once we switch to using // the Android HW Sync HAL. - status_t releaseBuffer(int buf, EGLDisplay display, EGLSyncKHR fence, + status_t releaseBuffer(int buf, uint64_t frameNumber, + EGLDisplay display, EGLSyncKHR fence, const sp& releaseFence); // consumerConnect connects a consumer to the BufferQueue. Only one @@ -410,20 +415,20 @@ private: // connected, mDequeueCondition must be broadcast. int getMaxBufferCountLocked() const; + // stillTracking returns true iff the buffer item is still being tracked + // in one of the slots. + bool stillTracking(const BufferItem *item) const; + struct BufferSlot { BufferSlot() : mEglDisplay(EGL_NO_DISPLAY), mBufferState(BufferSlot::FREE), mRequestBufferCalled(false), - mTransform(0), - mScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE), - mTimestamp(0), mFrameNumber(0), mEglFence(EGL_NO_SYNC_KHR), mAcquireCalled(false), mNeedsCleanupOnRelease(false) { - mCrop.makeInvalid(); } // mGraphicBuffer points to the buffer allocated for this slot or is NULL @@ -482,21 +487,6 @@ private: // needed but useful for debugging and catching producer bugs. bool mRequestBufferCalled; - // mCrop is the current crop rectangle for this buffer slot. - Rect mCrop; - - // mTransform is the current transform flags for this buffer slot. - // (example: NATIVE_WINDOW_TRANSFORM_ROT_90) - uint32_t mTransform; - - // mScalingMode is the current scaling mode for this buffer slot. - // (example: NATIVE_WINDOW_SCALING_MODE_FREEZE) - uint32_t mScalingMode; - - // mTimestamp is the current timestamp for this buffer slot. This gets - // to set by queueBuffer each time this slot is queued. - int64_t mTimestamp; - // mFrameNumber is the number of the queued frame for this slot. This // is used to dequeue buffers in LRU order (useful because buffers // may be released before their release fence is signaled). @@ -592,7 +582,7 @@ private: mutable Condition mDequeueCondition; // mQueue is a FIFO of queued buffers used in synchronous mode - typedef Vector Fifo; + typedef Vector Fifo; Fifo mQueue; // mAbandoned indicates that the BufferQueue will no longer be used to @@ -613,7 +603,7 @@ private: mutable Mutex mMutex; // mFrameCounter is the free running counter, incremented on every - // successful queueBuffer call. + // successful queueBuffer call, and buffer allocation. uint64_t mFrameCounter; // mBufferHasBeenQueued is true once a buffer has been queued. It is diff --git a/include/gui/ConsumerBase.h b/include/gui/ConsumerBase.h index 6250d8f08a..1d51bc9cf6 100644 --- a/include/gui/ConsumerBase.h +++ b/include/gui/ConsumerBase.h @@ -160,17 +160,23 @@ protected: // Derived classes should override this method to perform any cleanup that // must take place when a buffer is released back to the BufferQueue. If // it is overridden the derived class's implementation must call - // ConsumerBase::releaseBufferLocked. - virtual status_t releaseBufferLocked(int buf, EGLDisplay display, - EGLSyncKHR eglFence); + // ConsumerBase::releaseBufferLocked.e + virtual status_t releaseBufferLocked(int slot, + const sp graphicBuffer, + EGLDisplay display, EGLSyncKHR eglFence); + + // returns true iff the slot still has the graphicBuffer in it. + bool stillTracking(int slot, const sp graphicBuffer); // addReleaseFence* adds the sync points associated with a fence to the set // of sync points that must be reached before the buffer in the given slot // may be used after the slot has been released. This should be called by // derived classes each time some asynchronous work is kicked off that // references the buffer. - status_t addReleaseFence(int slot, const sp& fence); - status_t addReleaseFenceLocked(int slot, const sp& fence); + status_t addReleaseFence(int slot, + const sp graphicBuffer, const sp& fence); + status_t addReleaseFenceLocked(int slot, + const sp graphicBuffer, const sp& fence); // Slot contains the information and object references that // ConsumerBase maintains about a BufferQueue buffer slot. @@ -184,6 +190,9 @@ protected: // overwritten. The buffer can be dequeued before the fence signals; // the producer is responsible for delaying writes until it signals. sp mFence; + + // the frame number of the last acquired frame for this slot + uint64_t mFrameNumber; }; // mSlots stores the buffers that have been allocated by the BufferQueue diff --git a/include/gui/GLConsumer.h b/include/gui/GLConsumer.h index 1e889278c0..031684e5c2 100644 --- a/include/gui/GLConsumer.h +++ b/include/gui/GLConsumer.h @@ -241,11 +241,13 @@ protected: // releaseBufferLocked overrides the ConsumerBase method to update the // mEglSlots array in addition to the ConsumerBase. - virtual status_t releaseBufferLocked(int buf, EGLDisplay display, - EGLSyncKHR eglFence); + virtual status_t releaseBufferLocked(int slot, + const sp graphicBuffer, + EGLDisplay display, EGLSyncKHR eglFence); - status_t releaseBufferLocked(int buf, EGLSyncKHR eglFence) { - return releaseBufferLocked(buf, mEglDisplay, eglFence); + status_t releaseBufferLocked(int slot, + const sp graphicBuffer, EGLSyncKHR eglFence) { + return releaseBufferLocked(slot, graphicBuffer, mEglDisplay, eglFence); } static bool isExternalFormat(uint32_t format); diff --git a/libs/gui/BufferItemConsumer.cpp b/libs/gui/BufferItemConsumer.cpp index 7db1b8465a..ba04bdfda9 100644 --- a/libs/gui/BufferItemConsumer.cpp +++ b/libs/gui/BufferItemConsumer.cpp @@ -82,9 +82,9 @@ status_t BufferItemConsumer::releaseBuffer(const BufferItem &item, Mutex::Autolock _l(mMutex); - err = addReleaseFenceLocked(item.mBuf, releaseFence); + err = addReleaseFenceLocked(item.mBuf, item.mGraphicBuffer, releaseFence); - err = releaseBufferLocked(item.mBuf, EGL_NO_DISPLAY, + err = releaseBufferLocked(item.mBuf, item.mGraphicBuffer, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR); if (err != OK) { BI_LOGE("Failed to release buffer: %s (%d)", diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp index 942151f808..34dbd71330 100644 --- a/libs/gui/BufferQueue.cpp +++ b/libs/gui/BufferQueue.cpp @@ -418,6 +418,7 @@ status_t BufferQueue::dequeueBuffer(int *outBuf, sp* outFence, return NO_INIT; } + mSlots[*outBuf].mFrameNumber = ~0; mSlots[*outBuf].mGraphicBuffer = graphicBuffer; } } @@ -435,7 +436,8 @@ status_t BufferQueue::dequeueBuffer(int *outBuf, sp* outFence, eglDestroySyncKHR(dpy, eglFence); } - ST_LOGV("dequeueBuffer: returning slot=%d buf=%p flags=%#x", *outBuf, + ST_LOGV("dequeueBuffer: returning slot=%d/%llu buf=%p flags=%#x", *outBuf, + mSlots[*outBuf].mFrameNumber, mSlots[*outBuf].mGraphicBuffer->handle, returnFlags); return returnFlags; @@ -491,15 +493,22 @@ status_t BufferQueue::queueBuffer(int buf, 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, - transform, scalingModeName(scalingMode)); + switch (scalingMode) { + case NATIVE_WINDOW_SCALING_MODE_FREEZE: + case NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW: + case NATIVE_WINDOW_SCALING_MODE_SCALE_CROP: + case NATIVE_WINDOW_SCALING_MODE_NO_SCALE_CROP: + break; + default: + ST_LOGE("unknown scaling mode: %d", scalingMode); + return -EINVAL; + } sp listener; { // scope for the lock Mutex::Autolock lock(mMutex); + if (mAbandoned) { ST_LOGE("queueBuffer: BufferQueue has been abandoned!"); return NO_INIT; @@ -519,6 +528,12 @@ status_t BufferQueue::queueBuffer(int buf, return -EINVAL; } + ST_LOGV("queueBuffer: slot=%d/%llu time=%#llx crop=[%d,%d,%d,%d] " + "tr=%#x scale=%s", + buf, mFrameCounter + 1, timestamp, + crop.left, crop.top, crop.right, crop.bottom, + transform, scalingModeName(scalingMode)); + const sp& graphicBuffer(mSlots[buf].mGraphicBuffer); Rect bufferRect(graphicBuffer->getWidth(), graphicBuffer->getHeight()); Rect croppedCrop; @@ -529,9 +544,25 @@ status_t BufferQueue::queueBuffer(int buf, return -EINVAL; } + mSlots[buf].mFence = fence; + mSlots[buf].mBufferState = BufferSlot::QUEUED; + mFrameCounter++; + mSlots[buf].mFrameNumber = mFrameCounter; + + BufferItem item; + item.mAcquireCalled = mSlots[buf].mAcquireCalled; + item.mGraphicBuffer = mSlots[buf].mGraphicBuffer; + item.mCrop = crop; + item.mTransform = transform; + item.mScalingMode = scalingMode; + item.mTimestamp = timestamp; + item.mFrameNumber = mFrameCounter; + item.mBuf = buf; + item.mFence = fence; + if (mSynchronousMode) { // In synchronous mode we queue all buffers in a FIFO. - mQueue.push_back(buf); + mQueue.push_back(item); // Synchronous mode always signals that an additional frame should // be consumed. @@ -539,7 +570,7 @@ status_t BufferQueue::queueBuffer(int buf, } else { // In asynchronous mode we only keep the most recent buffer. if (mQueue.empty()) { - mQueue.push_back(buf); + mQueue.push_back(item); // Asynchronous mode only signals that a frame should be // consumed if no previous frame was pending. If a frame were @@ -547,34 +578,15 @@ status_t BufferQueue::queueBuffer(int buf, listener = mConsumerListener; } else { Fifo::iterator front(mQueue.begin()); - // buffer currently queued is freed - mSlots[*front].mBufferState = BufferSlot::FREE; + // buffer slot currently queued is marked free if still tracked + if (stillTracking(front)) { + mSlots[front->mBuf].mBufferState = BufferSlot::FREE; + } // and we record the new buffer index in the queued list - *front = buf; + *front = item; } } - mSlots[buf].mTimestamp = timestamp; - mSlots[buf].mCrop = crop; - mSlots[buf].mTransform = transform; - mSlots[buf].mFence = fence; - - switch (scalingMode) { - case NATIVE_WINDOW_SCALING_MODE_FREEZE: - case NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW: - case NATIVE_WINDOW_SCALING_MODE_SCALE_CROP: - break; - default: - ST_LOGE("unknown scaling mode: %d (ignoring)", scalingMode); - scalingMode = mSlots[buf].mScalingMode; - break; - } - - mSlots[buf].mBufferState = BufferSlot::QUEUED; - mSlots[buf].mScalingMode = scalingMode; - mFrameCounter++; - mSlots[buf].mFrameNumber = mFrameCounter; - mBufferHasBeenQueued = true; mDequeueCondition.broadcast(); @@ -718,7 +730,14 @@ void BufferQueue::dump(String8& result, const char* prefix) const { int fifoSize = 0; Fifo::const_iterator i(mQueue.begin()); while (i != mQueue.end()) { - fifo.appendFormat("%02d ", *i++); + fifo.appendFormat("%02d:%p crop=[%d,%d,%d,%d], " + "xform=0x%02x, time=%#llx, scale=%s\n", + i->mBuf, i->mGraphicBuffer.get(), + i->mCrop.left, i->mCrop.top, i->mCrop.right, + i->mCrop.bottom, i->mTransform, i->mTimestamp, + scalingModeName(i->mScalingMode) + ); + i++; fifoSize++; } @@ -746,14 +765,10 @@ void BufferQueue::dump(String8& result, const char* prefix) const { for (int i=0 ; i":" ", i, - stateName(slot.mBufferState), - slot.mCrop.left, slot.mCrop.top, slot.mCrop.right, - slot.mCrop.bottom, slot.mTransform, slot.mTimestamp, - scalingModeName(slot.mScalingMode) + slot.mGraphicBuffer.get(), + stateName(slot.mBufferState) ); const sp& buf(slot.mGraphicBuffer); @@ -820,27 +835,27 @@ status_t BufferQueue::acquireBuffer(BufferItem *buffer) { // deep, while in synchronous mode we use the oldest buffer. if (!mQueue.empty()) { Fifo::iterator front(mQueue.begin()); - int buf = *front; - + int buf = front->mBuf; + *buffer = *front; ATRACE_BUFFER_INDEX(buf); - if (mSlots[buf].mAcquireCalled) { + ST_LOGV("acquireBuffer: acquiring { slot=%d/%llu, buffer=%p }", + front->mBuf, front->mFrameNumber, + front->mGraphicBuffer->handle); + // if front buffer still being tracked update slot state + if (stillTracking(front)) { + mSlots[buf].mAcquireCalled = true; + mSlots[buf].mNeedsCleanupOnRelease = false; + mSlots[buf].mBufferState = BufferSlot::ACQUIRED; + mSlots[buf].mFence = Fence::NO_FENCE; + } + + // If the buffer has previously been acquired by the consumer, set + // mGraphicBuffer to NULL to avoid unnecessarily remapping this + // buffer on the consumer side. + if (buffer->mAcquireCalled) { buffer->mGraphicBuffer = NULL; - } else { - buffer->mGraphicBuffer = mSlots[buf].mGraphicBuffer; } - buffer->mCrop = mSlots[buf].mCrop; - buffer->mTransform = mSlots[buf].mTransform; - buffer->mScalingMode = mSlots[buf].mScalingMode; - buffer->mFrameNumber = mSlots[buf].mFrameNumber; - buffer->mTimestamp = mSlots[buf].mTimestamp; - buffer->mBuf = buf; - buffer->mFence = mSlots[buf].mFence; - - mSlots[buf].mAcquireCalled = true; - mSlots[buf].mNeedsCleanupOnRelease = false; - mSlots[buf].mBufferState = BufferSlot::ACQUIRED; - mSlots[buf].mFence = Fence::NO_FENCE; mQueue.erase(front); mDequeueCondition.broadcast(); @@ -853,7 +868,8 @@ status_t BufferQueue::acquireBuffer(BufferItem *buffer) { return NO_ERROR; } -status_t BufferQueue::releaseBuffer(int buf, EGLDisplay display, +status_t BufferQueue::releaseBuffer( + int buf, uint64_t frameNumber, EGLDisplay display, EGLSyncKHR eglFence, const sp& fence) { ATRACE_CALL(); ATRACE_BUFFER_INDEX(buf); @@ -864,12 +880,35 @@ status_t BufferQueue::releaseBuffer(int buf, EGLDisplay display, return BAD_VALUE; } - mSlots[buf].mEglDisplay = display; - mSlots[buf].mEglFence = eglFence; - mSlots[buf].mFence = fence; + // Check if this buffer slot is on the queue + bool slotQueued = false; + Fifo::iterator front(mQueue.begin()); + while (front != mQueue.end() && !slotQueued) { + if (front->mBuf == buf) + slotQueued = true; + front++; + } + + // If the frame number has changed because buffer has been reallocated, + // we can ignore this releaseBuffer for the old buffer. + if (frameNumber != mSlots[buf].mFrameNumber) { + // This should only occur if new buffer is still in the queue + ALOGE_IF(!slotQueued, + "received old buffer(#%lld) after new buffer(#%lld) on same " + "slot #%d already acquired", frameNumber, + mSlots[buf].mFrameNumber, buf); + return STALE_BUFFER_SLOT; + } + // this should never happen + ALOGE_IF(slotQueued, + "received new buffer(#%lld) on slot #%d that has not yet been " + "acquired", frameNumber, buf); // The buffer can now only be released if its in the acquired state if (mSlots[buf].mBufferState == BufferSlot::ACQUIRED) { + mSlots[buf].mEglDisplay = display; + mSlots[buf].mEglFence = eglFence; + mSlots[buf].mFence = fence; mSlots[buf].mBufferState = BufferSlot::FREE; } else if (mSlots[buf].mNeedsCleanupOnRelease) { ST_LOGV("releasing a stale buf %d its state was %d", buf, mSlots[buf].mBufferState); @@ -934,6 +973,17 @@ status_t BufferQueue::getReleasedBuffers(uint32_t* slotMask) { mask |= 1 << i; } } + + // Remove buffers in flight (on the queue) from the mask where acquire has + // been called, as the consumer will not receive the buffer address, so + // it should not free these slots. + Fifo::iterator front(mQueue.begin()); + while (front != mQueue.end()) { + if (front->mAcquireCalled) + mask &= ~(1 << front->mBuf); + front++; + } + *slotMask = mask; ST_LOGV("getReleasedBuffers: returning mask %#x", mask); @@ -977,16 +1027,14 @@ status_t BufferQueue::setMaxAcquiredBufferCount(int maxAcquiredBuffers) { } void BufferQueue::freeAllBuffersExceptHeadLocked() { - int head = -1; - if (!mQueue.empty()) { - Fifo::iterator front(mQueue.begin()); - head = *front; - } + // only called if mQueue is not empty + Fifo::iterator front(mQueue.begin()); mBufferHasBeenQueued = false; for (int i = 0; i < NUM_BUFFER_SLOTS; i++) { - if (i != head) { + const BufferSlot &slot = mSlots[i]; + if (slot.mGraphicBuffer == NULL || + slot.mGraphicBuffer->handle != front->mGraphicBuffer->handle) freeBufferLocked(i); - } } } @@ -1052,6 +1100,22 @@ int BufferQueue::getMaxBufferCountLocked() const { return maxBufferCount; } +bool BufferQueue::stillTracking(const BufferItem *item) const { + const BufferSlot &slot = mSlots[item->mBuf]; + + ST_LOGV("stillTracking?: item: { slot=%d/%llu, buffer=%p }, " + "slot: { slot=%d/%llu, buffer=%p }", + item->mBuf, item->mFrameNumber, + (item->mGraphicBuffer.get() ? item->mGraphicBuffer->handle : 0), + item->mBuf, slot.mFrameNumber, + (slot.mGraphicBuffer.get() ? slot.mGraphicBuffer->handle : 0)); + + // Compare item with its original buffer slot. We can check the slot + // as the buffer would not be moved to a different slot by the producer. + return (slot.mGraphicBuffer != NULL && + item->mGraphicBuffer->handle == slot.mGraphicBuffer->handle); +} + BufferQueue::ProxyConsumerListener::ProxyConsumerListener( const wp& consumerListener): mConsumerListener(consumerListener) {} diff --git a/libs/gui/ConsumerBase.cpp b/libs/gui/ConsumerBase.cpp index 8d911c9eaf..fd9d15365b 100644 --- a/libs/gui/ConsumerBase.cpp +++ b/libs/gui/ConsumerBase.cpp @@ -95,6 +95,7 @@ void ConsumerBase::freeBufferLocked(int slotIndex) { CB_LOGV("freeBufferLocked: slotIndex=%d", slotIndex); mSlots[slotIndex].mGraphicBuffer = 0; mSlots[slotIndex].mFence = Fence::NO_FENCE; + mSlots[slotIndex].mFrameNumber = 0; } // Used for refactoring, should not be in final interface @@ -191,21 +192,31 @@ status_t ConsumerBase::acquireBufferLocked(BufferQueue::BufferItem *item) { mSlots[item->mBuf].mGraphicBuffer = item->mGraphicBuffer; } + mSlots[item->mBuf].mFrameNumber = item->mFrameNumber; mSlots[item->mBuf].mFence = item->mFence; - CB_LOGV("acquireBufferLocked: -> slot=%d", item->mBuf); + CB_LOGV("acquireBufferLocked: -> slot=%d/%llu", + item->mBuf, item->mFrameNumber); return OK; } -status_t ConsumerBase::addReleaseFence(int slot, const sp& fence) { +status_t ConsumerBase::addReleaseFence(int slot, + const sp graphicBuffer, const sp& fence) { Mutex::Autolock lock(mMutex); - return addReleaseFenceLocked(slot, fence); + return addReleaseFenceLocked(slot, graphicBuffer, fence); } -status_t ConsumerBase::addReleaseFenceLocked(int slot, const sp& fence) { +status_t ConsumerBase::addReleaseFenceLocked(int slot, + const sp graphicBuffer, const sp& fence) { CB_LOGV("addReleaseFenceLocked: slot=%d", slot); + // If consumer no longer tracks this graphicBuffer, we can safely + // drop this fence, as it will never be received by the producer. + if (!stillTracking(slot, graphicBuffer)) { + return OK; + } + if (!mSlots[slot].mFence.get()) { mSlots[slot].mFence = fence; } else { @@ -225,11 +236,20 @@ status_t ConsumerBase::addReleaseFenceLocked(int slot, const sp& fence) { return OK; } -status_t ConsumerBase::releaseBufferLocked(int slot, EGLDisplay display, - EGLSyncKHR eglFence) { - CB_LOGV("releaseBufferLocked: slot=%d", slot); - status_t err = mBufferQueue->releaseBuffer(slot, display, eglFence, - mSlots[slot].mFence); +status_t ConsumerBase::releaseBufferLocked( + int slot, const sp graphicBuffer, + EGLDisplay display, EGLSyncKHR eglFence) { + // If consumer no longer tracks this graphicBuffer (we received a new + // buffer on the same slot), the buffer producer is definitely no longer + // tracking it. + if (!stillTracking(slot, graphicBuffer)) { + return OK; + } + + CB_LOGV("releaseBufferLocked: slot=%d/%llu", + slot, mSlots[slot].mFrameNumber); + status_t err = mBufferQueue->releaseBuffer(slot, mSlots[slot].mFrameNumber, + display, eglFence, mSlots[slot].mFence); if (err == BufferQueue::STALE_BUFFER_SLOT) { freeBufferLocked(slot); } @@ -239,4 +259,13 @@ status_t ConsumerBase::releaseBufferLocked(int slot, EGLDisplay display, return err; } +bool ConsumerBase::stillTracking(int slot, + const sp graphicBuffer) { + if (slot < 0 || slot >= BufferQueue::NUM_BUFFER_SLOTS) { + return false; + } + return (mSlots[slot].mGraphicBuffer != NULL && + mSlots[slot].mGraphicBuffer->handle == graphicBuffer->handle); +} + } // namespace android diff --git a/libs/gui/CpuConsumer.cpp b/libs/gui/CpuConsumer.cpp index 054364997e..08343610cd 100644 --- a/libs/gui/CpuConsumer.cpp +++ b/libs/gui/CpuConsumer.cpp @@ -189,7 +189,9 @@ status_t CpuConsumer::releaseAcquiredBufferLocked(int lockedIdx) { // disconnected after this buffer was acquired. if (CC_LIKELY(mAcquiredBuffers[lockedIdx].mGraphicBuffer == mSlots[buf].mGraphicBuffer)) { - releaseBufferLocked(buf, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR); + releaseBufferLocked( + buf, mAcquiredBuffers[lockedIdx].mGraphicBuffer, + EGL_NO_DISPLAY, EGL_NO_SYNC_KHR); } AcquiredBuffer &ab = mAcquiredBuffers.editItemAt(lockedIdx); diff --git a/libs/gui/GLConsumer.cpp b/libs/gui/GLConsumer.cpp index 344a93a326..6d29edc0c4 100644 --- a/libs/gui/GLConsumer.cpp +++ b/libs/gui/GLConsumer.cpp @@ -188,12 +188,16 @@ status_t GLConsumer::acquireBufferLocked(BufferQueue::BufferItem *item) { return NO_ERROR; } -status_t GLConsumer::releaseBufferLocked(int buf, EGLDisplay display, - EGLSyncKHR eglFence) { - status_t err = ConsumerBase::releaseBufferLocked(buf, display, eglFence); - +status_t GLConsumer::releaseBufferLocked(int buf, + sp graphicBuffer, + EGLDisplay display, EGLSyncKHR eglFence) { + // release the buffer if it hasn't already been discarded by the + // BufferQueue. This can happen, for example, when the producer of this + // buffer has reallocated the original buffer slot after this buffer + // was acquired. + status_t err = ConsumerBase::releaseBufferLocked( + buf, graphicBuffer, display, eglFence); mEglSlots[buf].mEglFence = EGL_NO_SYNC_KHR; - return err; } @@ -237,7 +241,10 @@ status_t GLConsumer::releaseAndUpdateLocked(const BufferQueue::BufferItem& item) 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); + // As we are still under lock since acquireBuffer, it is safe to + // release by slot. + releaseBufferLocked(buf, mSlots[buf].mGraphicBuffer, + mEglDisplay, EGL_NO_SYNC_KHR); return err; } @@ -248,7 +255,8 @@ status_t GLConsumer::releaseAndUpdateLocked(const BufferQueue::BufferItem& item) // release old buffer if (mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) { - status_t status = releaseBufferLocked(mCurrentTexture, mEglDisplay, + status_t status = releaseBufferLocked( + mCurrentTexture, mCurrentTextureBuf, mEglDisplay, mEglSlots[mCurrentTexture].mEglFence); if (status != NO_ERROR && status != BufferQueue::STALE_BUFFER_SLOT) { ST_LOGE("releaseAndUpdate: failed to release buffer: %s (%d)", @@ -334,7 +342,8 @@ status_t GLConsumer::checkAndUpdateEglStateLocked() { void GLConsumer::setReleaseFence(const sp& fence) { if (fence->isValid() && mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) { - status_t err = addReleaseFence(mCurrentTexture, fence); + status_t err = addReleaseFence(mCurrentTexture, + mCurrentTextureBuf, fence); if (err != OK) { ST_LOGE("setReleaseFence: failed to add the fence: %s (%d)", strerror(-err), err); @@ -503,7 +512,8 @@ status_t GLConsumer::syncForReleaseLocked(EGLDisplay dpy) { return UNKNOWN_ERROR; } sp fence(new Fence(fenceFd)); - status_t err = addReleaseFenceLocked(mCurrentTexture, fence); + status_t err = addReleaseFenceLocked(mCurrentTexture, + mCurrentTextureBuf, fence); if (err != OK) { ST_LOGE("syncForReleaseLocked: error adding release fence: " "%s (%d)", strerror(-err), err); diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp index 8b454ce74f..10bca383c8 100644 --- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp +++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp @@ -103,8 +103,8 @@ status_t FramebufferSurface::nextBuffer(sp& outBuffer, sp& if (mCurrentBufferSlot != BufferQueue::INVALID_BUFFER_SLOT && item.mBuf != mCurrentBufferSlot) { // Release the previous buffer. - err = releaseBufferLocked(mCurrentBufferSlot, EGL_NO_DISPLAY, - EGL_NO_SYNC_KHR); + err = releaseBufferLocked(mCurrentBufferSlot, mCurrentBuffer, + EGL_NO_DISPLAY, EGL_NO_SYNC_KHR); if (err != NO_ERROR && err != BufferQueue::STALE_BUFFER_SLOT) { ALOGE("error releasing buffer: %s (%d)", strerror(-err), err); return err; @@ -144,7 +144,8 @@ void FramebufferSurface::onFrameCommitted() { sp fence = mHwc.getAndResetReleaseFence(mDisplayType); if (fence->isValid() && mCurrentBufferSlot != BufferQueue::INVALID_BUFFER_SLOT) { - status_t err = addReleaseFence(mCurrentBufferSlot, fence); + status_t err = addReleaseFence(mCurrentBufferSlot, + mCurrentBuffer, fence); ALOGE_IF(err, "setReleaseFenceFd: failed to add the fence: %s (%d)", strerror(-err), err); } diff --git a/services/surfaceflinger/SurfaceFlingerConsumer.cpp b/services/surfaceflinger/SurfaceFlingerConsumer.cpp index 2869250502..6912dc060d 100644 --- a/services/surfaceflinger/SurfaceFlingerConsumer.cpp +++ b/services/surfaceflinger/SurfaceFlingerConsumer.cpp @@ -69,7 +69,7 @@ status_t SurfaceFlingerConsumer::updateTexImage(BufferRejecter* rejecter) // reject buffers which have the wrong size int buf = item.mBuf; if (rejecter && rejecter->reject(mSlots[buf].mGraphicBuffer, item)) { - releaseBufferLocked(buf, EGL_NO_SYNC_KHR); + releaseBufferLocked(buf, item.mGraphicBuffer, EGL_NO_SYNC_KHR); return NO_ERROR; } -- cgit v1.2.3-59-g8ed1b From 9e3cb55b8f6f007906872decfe3b8a2541e94dd2 Mon Sep 17 00:00:00 2001 From: Lajos Molnar Date: Mon, 6 May 2013 16:23:07 -0700 Subject: BufferQueue: remove freeAllBuffersExceptHeadLocked() Now that we are having separate buffer-instances for the buffer- queue, we can free all buffers; we don't have to keep the head alive. Change-Id: I023e9161a2501d99333f8868ce438afa914ec50f Signed-off-by: Lajos Molnar Related-to-bug: 7093648 --- include/gui/BufferQueue.h | 4 ---- libs/gui/BufferQueue.cpp | 29 +++++------------------------ 2 files changed, 5 insertions(+), 28 deletions(-) (limited to 'libs/gui/BufferQueue.cpp') diff --git a/include/gui/BufferQueue.h b/include/gui/BufferQueue.h index 8475a71433..766fa0f8db 100644 --- a/include/gui/BufferQueue.h +++ b/include/gui/BufferQueue.h @@ -373,10 +373,6 @@ private: // all slots. void freeAllBuffersLocked(); - // freeAllBuffersExceptHeadLocked frees the GraphicBuffer and sync - // resources for all slots except the head of mQueue. - void freeAllBuffersExceptHeadLocked(); - // drainQueueLocked waits for the buffer queue to empty if we're in // synchronous mode, or returns immediately otherwise. It returns NO_INIT // if the BufferQueue is abandoned (consumer disconnected) or disconnected diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp index 34dbd71330..0dab86427d 100644 --- a/libs/gui/BufferQueue.cpp +++ b/libs/gui/BufferQueue.cpp @@ -178,12 +178,10 @@ status_t BufferQueue::setBufferCount(int bufferCount) { } // here we're guaranteed that the client doesn't have dequeued buffers - // and will release all of its buffer references. - // - // XXX: Should this use drainQueueAndFreeBuffersLocked instead? + // and will release all of its buffer references. We don't clear the + // queue, however, so currently queued buffers still get displayed. freeAllBuffersLocked(); mOverrideMaxBufferCount = bufferCount; - mBufferHasBeenQueued = false; mDequeueCondition.broadcast(); listener = mConsumerListener; } // scope for lock @@ -801,9 +799,8 @@ void BufferQueue::freeBufferLocked(int slot) { } void BufferQueue::freeAllBuffersLocked() { - ALOGW_IF(!mQueue.isEmpty(), - "freeAllBuffersLocked called but mQueue is not empty"); - mQueue.clear(); + ALOGD_IF(!mQueue.isEmpty(), + "freeAllBuffersLocked called with non-empty mQueue"); mBufferHasBeenQueued = false; for (int i = 0; i < NUM_BUFFER_SLOTS; i++) { freeBufferLocked(i); @@ -1026,18 +1023,6 @@ status_t BufferQueue::setMaxAcquiredBufferCount(int maxAcquiredBuffers) { return NO_ERROR; } -void BufferQueue::freeAllBuffersExceptHeadLocked() { - // only called if mQueue is not empty - Fifo::iterator front(mQueue.begin()); - mBufferHasBeenQueued = false; - for (int i = 0; i < NUM_BUFFER_SLOTS; i++) { - const BufferSlot &slot = mSlots[i]; - if (slot.mGraphicBuffer == NULL || - slot.mGraphicBuffer->handle != front->mGraphicBuffer->handle) - freeBufferLocked(i); - } -} - status_t BufferQueue::drainQueueLocked() { while (mSynchronousMode && mQueue.size() > 1) { mDequeueCondition.wait(mMutex); @@ -1056,11 +1041,7 @@ status_t BufferQueue::drainQueueLocked() { status_t BufferQueue::drainQueueAndFreeBuffersLocked() { status_t err = drainQueueLocked(); if (err == NO_ERROR) { - if (mQueue.empty()) { - freeAllBuffersLocked(); - } else { - freeAllBuffersExceptHeadLocked(); - } + freeAllBuffersLocked(); } return err; } -- cgit v1.2.3-59-g8ed1b From 1585c4d9fbbba3ba70ae625923b85cd02cb8a0fd Mon Sep 17 00:00:00 2001 From: Andy McFadden Date: Fri, 28 Jun 2013 13:52:40 -0700 Subject: Pay attention to buffer timestamps When acquiring a buffer, SurfaceFlinger now computes the expected presentation time and passes it to the BufferQueue acquireBuffer() method. If it's not yet time to display the buffer, acquireBuffer() returns PRESENT_LATER instead of a buffer. The current implementation of the expected-present-time computation uses approximations and guesswork. Bug 7900302 Change-Id: If9345611c5983a11a811935aaf27d6388a5036f1 --- include/gui/BufferItemConsumer.h | 3 +- include/gui/BufferQueue.h | 10 ++- include/gui/ConsumerBase.h | 3 +- include/gui/GLConsumer.h | 3 +- libs/gui/BufferItemConsumer.cpp | 5 +- libs/gui/BufferQueue.cpp | 84 +++++++++++++++------- libs/gui/ConsumerBase.cpp | 5 +- libs/gui/CpuConsumer.cpp | 2 +- libs/gui/GLConsumer.cpp | 7 +- libs/gui/tests/BufferQueue_test.cpp | 4 +- .../DisplayHardware/FramebufferSurface.cpp | 2 +- services/surfaceflinger/Layer.cpp | 21 ++++-- services/surfaceflinger/SurfaceFlingerConsumer.cpp | 46 +++++++++++- services/surfaceflinger/SurfaceFlingerConsumer.h | 3 + 14 files changed, 148 insertions(+), 50 deletions(-) (limited to 'libs/gui/BufferQueue.cpp') diff --git a/include/gui/BufferItemConsumer.h b/include/gui/BufferItemConsumer.h index 98b450c734..5bf9acbe11 100644 --- a/include/gui/BufferItemConsumer.h +++ b/include/gui/BufferItemConsumer.h @@ -71,7 +71,8 @@ class BufferItemConsumer: public ConsumerBase // // If waitForFence is true, and the acquired BufferItem has a valid fence object, // acquireBuffer will wait on the fence with no timeout before returning. - status_t acquireBuffer(BufferItem *item, bool waitForFence = true); + status_t acquireBuffer(BufferItem *item, nsecs_t presentWhen, + bool waitForFence = true); // Returns an acquired buffer to the queue, allowing it to be reused. Since // only a fixed number of buffers may be acquired at a time, old buffers diff --git a/include/gui/BufferQueue.h b/include/gui/BufferQueue.h index 766fa0f8db..0143be3fd3 100644 --- a/include/gui/BufferQueue.h +++ b/include/gui/BufferQueue.h @@ -39,7 +39,7 @@ public: enum { NUM_BUFFER_SLOTS = 32 }; enum { NO_CONNECTED_API = 0 }; enum { INVALID_BUFFER_SLOT = -1 }; - enum { STALE_BUFFER_SLOT = 1, NO_BUFFER_AVAILABLE }; + enum { STALE_BUFFER_SLOT = 1, NO_BUFFER_AVAILABLE, PRESENT_LATER }; // When in async mode we reserve two slots in order to guarantee that the // producer and consumer can run asynchronously. @@ -284,7 +284,13 @@ public: // acquired then the BufferItem::mGraphicBuffer field of buffer is set to // NULL and it is assumed that the consumer still holds a reference to the // buffer. - status_t acquireBuffer(BufferItem *buffer); + // + // If presentWhen is nonzero, it indicates the time when the buffer will + // be displayed on screen. If the buffer's timestamp is farther in the + // future, the buffer won't be acquired, and PRESENT_LATER will be + // returned. The presentation time is in nanoseconds, and the time base + // is CLOCK_MONOTONIC. + status_t acquireBuffer(BufferItem *buffer, nsecs_t presentWhen); // releaseBuffer releases a buffer slot from the consumer back to the // BufferQueue. This may be done while the buffer's contents are still diff --git a/include/gui/ConsumerBase.h b/include/gui/ConsumerBase.h index 1d51bc9cf6..42b84cc7ce 100644 --- a/include/gui/ConsumerBase.h +++ b/include/gui/ConsumerBase.h @@ -152,7 +152,8 @@ protected: // initialization that must take place the first time a buffer is assigned // to a slot. If it is overridden the derived class's implementation must // call ConsumerBase::acquireBufferLocked. - virtual status_t acquireBufferLocked(BufferQueue::BufferItem *item); + virtual status_t acquireBufferLocked(BufferQueue::BufferItem *item, + nsecs_t presentWhen); // releaseBufferLocked relinquishes control over a buffer, returning that // control to the BufferQueue. diff --git a/include/gui/GLConsumer.h b/include/gui/GLConsumer.h index 031684e5c2..fbc8840715 100644 --- a/include/gui/GLConsumer.h +++ b/include/gui/GLConsumer.h @@ -237,7 +237,8 @@ protected: // acquireBufferLocked overrides the ConsumerBase method to update the // mEglSlots array in addition to the ConsumerBase behavior. - virtual status_t acquireBufferLocked(BufferQueue::BufferItem *item); + virtual status_t acquireBufferLocked(BufferQueue::BufferItem *item, + nsecs_t presentWhen); // releaseBufferLocked overrides the ConsumerBase method to update the // mEglSlots array in addition to the ConsumerBase. diff --git a/libs/gui/BufferItemConsumer.cpp b/libs/gui/BufferItemConsumer.cpp index ba04bdfda9..8d86c5906f 100644 --- a/libs/gui/BufferItemConsumer.cpp +++ b/libs/gui/BufferItemConsumer.cpp @@ -47,14 +47,15 @@ void BufferItemConsumer::setName(const String8& name) { mBufferQueue->setConsumerName(name); } -status_t BufferItemConsumer::acquireBuffer(BufferItem *item, bool waitForFence) { +status_t BufferItemConsumer::acquireBuffer(BufferItem *item, + nsecs_t presentWhen, bool waitForFence) { status_t err; if (!item) return BAD_VALUE; Mutex::Autolock _l(mMutex); - err = acquireBufferLocked(item); + err = acquireBufferLocked(item, presentWhen); if (err != OK) { if (err != NO_BUFFER_AVAILABLE) { BI_LOGE("Error acquiring buffer: %s (%d)", strerror(err), err); diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp index 0dab86427d..8d4b174450 100644 --- a/libs/gui/BufferQueue.cpp +++ b/libs/gui/BufferQueue.cpp @@ -807,7 +807,7 @@ void BufferQueue::freeAllBuffersLocked() { } } -status_t BufferQueue::acquireBuffer(BufferItem *buffer) { +status_t BufferQueue::acquireBuffer(BufferItem *buffer, nsecs_t presentWhen) { ATRACE_CALL(); Mutex::Autolock _l(mMutex); @@ -830,38 +830,68 @@ status_t BufferQueue::acquireBuffer(BufferItem *buffer) { // check if queue is empty // In asynchronous mode the list is guaranteed to be one buffer // deep, while in synchronous mode we use the oldest buffer. - if (!mQueue.empty()) { - Fifo::iterator front(mQueue.begin()); - int buf = front->mBuf; - *buffer = *front; - ATRACE_BUFFER_INDEX(buf); + if (mQueue.empty()) { + return NO_BUFFER_AVAILABLE; + } - ST_LOGV("acquireBuffer: acquiring { slot=%d/%llu, buffer=%p }", - front->mBuf, front->mFrameNumber, - front->mGraphicBuffer->handle); - // if front buffer still being tracked update slot state - if (stillTracking(front)) { - mSlots[buf].mAcquireCalled = true; - mSlots[buf].mNeedsCleanupOnRelease = false; - mSlots[buf].mBufferState = BufferSlot::ACQUIRED; - mSlots[buf].mFence = Fence::NO_FENCE; - } + Fifo::iterator front(mQueue.begin()); + int buf = front->mBuf; + + // Compare the buffer's desired presentation time to the predicted + // actual display time. + // + // The "presentWhen" argument indicates when the buffer is expected + // to be presented on-screen. If the buffer's desired-present time + // is earlier (less) than presentWhen, meaning it'll be displayed + // on time or possibly late, we acquire and return it. If we don't want + // to display it until after the presentWhen time, we return PRESENT_LATER + // without acquiring it. + // + // To be safe, we don't refuse to acquire the buffer if presentWhen is + // more than one second in the future beyond the desired present time + // (i.e. we'd be holding the buffer for a really long time). + const int MAX_FUTURE_NSEC = 1000000000ULL; + nsecs_t desiredPresent = front->mTimestamp; + if (presentWhen != 0 && desiredPresent > presentWhen && + desiredPresent - presentWhen < MAX_FUTURE_NSEC) + { + ALOGV("pts defer: des=%lld when=%lld (%lld) now=%lld", + desiredPresent, presentWhen, desiredPresent - presentWhen, + systemTime(CLOCK_MONOTONIC)); + return PRESENT_LATER; + } + if (presentWhen != 0) { + ALOGV("pts accept: %p[%d] sig=%lld des=%lld when=%lld (%lld)", + mSlots, buf, mSlots[buf].mFence->getSignalTime(), + desiredPresent, presentWhen, desiredPresent - presentWhen); + } - // If the buffer has previously been acquired by the consumer, set - // mGraphicBuffer to NULL to avoid unnecessarily remapping this - // buffer on the consumer side. - if (buffer->mAcquireCalled) { - buffer->mGraphicBuffer = NULL; - } + *buffer = *front; + ATRACE_BUFFER_INDEX(buf); - mQueue.erase(front); - mDequeueCondition.broadcast(); + ST_LOGV("acquireBuffer: acquiring { slot=%d/%llu, buffer=%p }", + front->mBuf, front->mFrameNumber, + front->mGraphicBuffer->handle); + // if front buffer still being tracked update slot state + if (stillTracking(front)) { + mSlots[buf].mAcquireCalled = true; + mSlots[buf].mNeedsCleanupOnRelease = false; + mSlots[buf].mBufferState = BufferSlot::ACQUIRED; + mSlots[buf].mFence = Fence::NO_FENCE; + } - ATRACE_INT(mConsumerName.string(), mQueue.size()); - } else { - return NO_BUFFER_AVAILABLE; + // If the buffer has previously been acquired by the consumer, set + // mGraphicBuffer to NULL to avoid unnecessarily remapping this + // buffer on the consumer side. + if (buffer->mAcquireCalled) { + buffer->mGraphicBuffer = NULL; } + mQueue.erase(front); + mDequeueCondition.broadcast(); + + ATRACE_INT(mConsumerName.string(), mQueue.size()); + return NO_ERROR; } diff --git a/libs/gui/ConsumerBase.cpp b/libs/gui/ConsumerBase.cpp index fd9d15365b..deb2646693 100644 --- a/libs/gui/ConsumerBase.cpp +++ b/libs/gui/ConsumerBase.cpp @@ -182,8 +182,9 @@ void ConsumerBase::dumpLocked(String8& result, const char* prefix) const { } } -status_t ConsumerBase::acquireBufferLocked(BufferQueue::BufferItem *item) { - status_t err = mBufferQueue->acquireBuffer(item); +status_t ConsumerBase::acquireBufferLocked(BufferQueue::BufferItem *item, + nsecs_t presentWhen) { + status_t err = mBufferQueue->acquireBuffer(item, presentWhen); if (err != NO_ERROR) { return err; } diff --git a/libs/gui/CpuConsumer.cpp b/libs/gui/CpuConsumer.cpp index 123b47056c..56bc7c66ea 100644 --- a/libs/gui/CpuConsumer.cpp +++ b/libs/gui/CpuConsumer.cpp @@ -79,7 +79,7 @@ status_t CpuConsumer::lockNextBuffer(LockedBuffer *nativeBuffer) { Mutex::Autolock _l(mMutex); - err = acquireBufferLocked(&b); + err = acquireBufferLocked(&b, 0); if (err != OK) { if (err == BufferQueue::NO_BUFFER_AVAILABLE) { return BAD_VALUE; diff --git a/libs/gui/GLConsumer.cpp b/libs/gui/GLConsumer.cpp index 6d29edc0c4..d12083fcb2 100644 --- a/libs/gui/GLConsumer.cpp +++ b/libs/gui/GLConsumer.cpp @@ -139,7 +139,7 @@ status_t GLConsumer::updateTexImage() { // 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); + err = acquireBufferLocked(&item, 0); if (err != NO_ERROR) { if (err == BufferQueue::NO_BUFFER_AVAILABLE) { // We always bind the texture even if we don't update its contents. @@ -165,8 +165,9 @@ status_t GLConsumer::updateTexImage() { return bindTextureImageLocked(); } -status_t GLConsumer::acquireBufferLocked(BufferQueue::BufferItem *item) { - status_t err = ConsumerBase::acquireBufferLocked(item); +status_t GLConsumer::acquireBufferLocked(BufferQueue::BufferItem *item, + nsecs_t presentWhen) { + status_t err = ConsumerBase::acquireBufferLocked(item, presentWhen); if (err != NO_ERROR) { return err; } diff --git a/libs/gui/tests/BufferQueue_test.cpp b/libs/gui/tests/BufferQueue_test.cpp index 62d215ba8f..96829879a1 100644 --- a/libs/gui/tests/BufferQueue_test.cpp +++ b/libs/gui/tests/BufferQueue_test.cpp @@ -80,7 +80,7 @@ TEST_F(BufferQueueTest, AcquireBuffer_ExceedsMaxAcquireCount_Fails) { 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(OK, mBQ->acquireBuffer(&item, 0)); } ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, @@ -90,7 +90,7 @@ TEST_F(BufferQueueTest, AcquireBuffer_ExceedsMaxAcquireCount_Fails) { ASSERT_EQ(OK, mBQ->queueBuffer(slot, qbi, &qbo)); // Acquire the third buffer, which should fail. - ASSERT_EQ(INVALID_OPERATION, mBQ->acquireBuffer(&item)); + ASSERT_EQ(INVALID_OPERATION, mBQ->acquireBuffer(&item, 0)); } TEST_F(BufferQueueTest, SetMaxAcquiredBufferCountWithIllegalValues_ReturnsError) { diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp index 10bca383c8..938459e1ec 100644 --- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp +++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp @@ -83,7 +83,7 @@ status_t FramebufferSurface::nextBuffer(sp& outBuffer, sp& Mutex::Autolock lock(mMutex); BufferQueue::BufferItem item; - status_t err = acquireBufferLocked(&item); + status_t err = acquireBufferLocked(&item, 0); if (err == BufferQueue::NO_BUFFER_AVAILABLE) { outBuffer = mCurrentBuffer; return NO_ERROR; diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index b08b8d104a..31a11ce4df 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -1051,11 +1051,6 @@ Region Layer::latchBuffer(bool& recomputeVisibleRegions) const bool oldOpacity = isOpaque(); sp oldActiveBuffer = mActiveBuffer; - // signal another event if we have more frames pending - if (android_atomic_dec(&mQueuedFrames) > 1) { - mFlinger->signalLayerUpdate(); - } - struct Reject : public SurfaceFlingerConsumer::BufferRejecter { Layer::State& front; Layer::State& current; @@ -1161,7 +1156,21 @@ Region Layer::latchBuffer(bool& recomputeVisibleRegions) Reject r(mDrawingState, getCurrentState(), recomputeVisibleRegions); - if (mSurfaceFlingerConsumer->updateTexImage(&r) != NO_ERROR) { + status_t updateResult = mSurfaceFlingerConsumer->updateTexImage(&r); + if (updateResult == BufferQueue::PRESENT_LATER) { + // Producer doesn't want buffer to be displayed yet. Signal a + // layer update so we check again at the next opportunity. + mFlinger->signalLayerUpdate(); + return outDirtyRegion; + } + + // Decrement the queued-frames count. Signal another event if we + // have more frames pending. + if (android_atomic_dec(&mQueuedFrames) > 1) { + mFlinger->signalLayerUpdate(); + } + + if (updateResult != NO_ERROR) { // something happened! recomputeVisibleRegions = true; return outDirtyRegion; diff --git a/services/surfaceflinger/SurfaceFlingerConsumer.cpp b/services/surfaceflinger/SurfaceFlingerConsumer.cpp index 7ac5c60621..b181b60724 100644 --- a/services/surfaceflinger/SurfaceFlingerConsumer.cpp +++ b/services/surfaceflinger/SurfaceFlingerConsumer.cpp @@ -50,12 +50,14 @@ status_t SurfaceFlingerConsumer::updateTexImage(BufferRejecter* rejecter) // 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); + err = acquireBufferLocked(&item, computeExpectedPresent()); if (err != NO_ERROR) { if (err == BufferQueue::NO_BUFFER_AVAILABLE) { // This variant of updateTexImage does not guarantee that the // texture is bound, so no need to call glBindTexture. err = NO_ERROR; + } else if (err == BufferQueue::PRESENT_LATER) { + // return the error, without logging } else { ALOGE("updateTexImage: acquire failed: %s (%d)", strerror(-err), err); @@ -99,6 +101,48 @@ status_t SurfaceFlingerConsumer::bindTextureImage() return bindTextureImageLocked(); } +// We need to determine the time when a buffer acquired now will be +// displayed. This can be calculated: +// time when previous buffer's actual-present fence was signaled +// + current display refresh rate * HWC latency +// + a little extra padding +// +// Buffer producers are expected to set their desired presentation time +// based on choreographer time stamps, which (coming from vsync events) +// will be slightly later then the actual-present timing. If we get a +// desired-present time that is unintentionally a hair after the next +// vsync, we'll hold the frame when we really want to display it. We +// want to use an expected-presentation time that is slightly late to +// avoid this sort of edge case. +nsecs_t SurfaceFlingerConsumer::computeExpectedPresent() +{ + // Don't yet have an easy way to get actual buffer flip time for + // the specific display, so use the current time. This is typically + // 1.3ms past the vsync event time. + const nsecs_t prevVsync = systemTime(CLOCK_MONOTONIC); + + // Given a SurfaceFlinger reference, and information about what display + // we're destined for, we could query the HWC for the refresh rate. This + // could change over time, e.g. we could switch to 24fps for a movie. + // For now, assume 60fps. + //const nsecs_t vsyncPeriod = + // getHwComposer().getRefreshPeriod(HWC_DISPLAY_PRIMARY); + const nsecs_t vsyncPeriod = 16700000; + + // The HWC doesn't currently have a way to report additional latency. + // Assume that whatever we submit now will appear on the next flip, + // i.e. 1 frame of latency w.r.t. the previous flip. + const uint32_t hwcLatency = 1; + + // A little extra padding to compensate for slack between actual vsync + // time and vsync event receipt. Currently not needed since we're + // using "now" instead of a vsync time. + const nsecs_t extraPadding = 0; + + // Total it up. + return prevVsync + hwcLatency * vsyncPeriod + extraPadding; +} + // --------------------------------------------------------------------------- }; // namespace android diff --git a/services/surfaceflinger/SurfaceFlingerConsumer.h b/services/surfaceflinger/SurfaceFlingerConsumer.h index 22eec81f74..d774c339d6 100644 --- a/services/surfaceflinger/SurfaceFlingerConsumer.h +++ b/services/surfaceflinger/SurfaceFlingerConsumer.h @@ -51,6 +51,9 @@ public: // See GLConsumer::bindTextureImageLocked(). status_t bindTextureImage(); + +private: + nsecs_t computeExpectedPresent(); }; // ---------------------------------------------------------------------------- -- cgit v1.2.3-59-g8ed1b From 595264f1af12e25dce57d7c5b1d52ed86ac0d0c9 Mon Sep 17 00:00:00 2001 From: Mathias Agopian Date: Tue, 16 Jul 2013 22:56:09 -0700 Subject: BufferQueue improvements and APIs changes this is the first step of a series of improvements to BufferQueue. A few things happen in this change: - setSynchronousMode() goes away as well as the SynchronousModeAllowed flag - BufferQueue now defaults to (what used to be) synchronous mode - a new "controlled by app" flag is passed when creating consumers and producers those flags are used to put the BufferQueue in a mode where it will never block if both flags are set. This is achieved by: - returning an error from dequeueBuffer() if it would block - making sure a buffer is always available by replacing the previous buffer with the new one in queueBuffer() (note: this is similar to what asynchrnous mode used to be) Note: in this change EGL's swap-interval 0 is broken; this will be fixed in another change. Change-Id: I691f9507d6e2e158287e3039f2a79a4d4434211d --- cmds/flatland/GLHelper.cpp | 2 +- include/gui/BufferItemConsumer.h | 4 +- include/gui/BufferQueue.h | 40 ++++++--------- include/gui/ConsumerBase.h | 4 +- include/gui/CpuConsumer.h | 2 +- include/gui/DummyConsumer.h | 46 ----------------- include/gui/GLConsumer.h | 7 +-- include/gui/IGraphicBufferProducer.h | 9 +--- include/gui/Surface.h | 9 +++- libs/gui/Android.mk | 1 - libs/gui/BufferItemConsumer.cpp | 5 +- libs/gui/BufferQueue.cpp | 57 ++++++---------------- libs/gui/ConsumerBase.cpp | 4 +- libs/gui/CpuConsumer.cpp | 5 +- libs/gui/DummyConsumer.cpp | 43 ---------------- libs/gui/GLConsumer.cpp | 16 +----- libs/gui/IGraphicBufferProducer.cpp | 26 ++-------- libs/gui/Surface.cpp | 10 ++-- libs/gui/tests/BufferQueue_test.cpp | 8 +-- libs/gui/tests/SurfaceTextureClient_test.cpp | 16 +++--- libs/gui/tests/SurfaceTexture_test.cpp | 42 +--------------- libs/gui/tests/Surface_test.cpp | 4 +- opengl/tests/EGLTest/EGL_test.cpp | 8 ++- services/surfaceflinger/Android.mk | 1 - .../DisplayHardware/FramebufferSurface.cpp | 3 +- .../DisplayHardware/VirtualDisplaySurface.cpp | 11 ++--- .../DisplayHardware/VirtualDisplaySurface.h | 3 +- services/surfaceflinger/Layer.cpp | 1 - services/surfaceflinger/SurfaceTextureLayer.cpp | 29 +---------- services/surfaceflinger/SurfaceTextureLayer.h | 4 -- 30 files changed, 96 insertions(+), 324 deletions(-) delete mode 100644 include/gui/DummyConsumer.h delete mode 100644 libs/gui/DummyConsumer.cpp (limited to 'libs/gui/BufferQueue.cpp') diff --git a/cmds/flatland/GLHelper.cpp b/cmds/flatland/GLHelper.cpp index 89eb95fd92..3928039505 100644 --- a/cmds/flatland/GLHelper.cpp +++ b/cmds/flatland/GLHelper.cpp @@ -198,7 +198,7 @@ bool GLHelper::getShaderProgram(const char* name, GLuint* outPgm) { bool GLHelper::createNamedSurfaceTexture(GLuint name, uint32_t w, uint32_t h, sp* glConsumer, EGLSurface* surface) { - sp bq = new BufferQueue(true, mGraphicBufferAlloc); + sp bq = new BufferQueue(mGraphicBufferAlloc); sp glc = new GLConsumer(bq, name, GL_TEXTURE_EXTERNAL_OES, false); glc->setDefaultBufferSize(w, h); diff --git a/include/gui/BufferItemConsumer.h b/include/gui/BufferItemConsumer.h index 0af6f8ea80..9370e81e38 100644 --- a/include/gui/BufferItemConsumer.h +++ b/include/gui/BufferItemConsumer.h @@ -51,9 +51,11 @@ class BufferItemConsumer: public ConsumerBase // the consumer usage flags passed to the graphics allocator. The // bufferCount parameter specifies how many buffers can be locked for user // access at the same time. + // controlledByApp tells whether this consumer is controlled by the + // application. BufferItemConsumer(const sp& bq, uint32_t consumerUsage, int bufferCount = BufferQueue::MIN_UNDEQUEUED_BUFFERS, - bool synchronousMode = false); + bool controlledByApp = false); virtual ~BufferItemConsumer(); diff --git a/include/gui/BufferQueue.h b/include/gui/BufferQueue.h index 0143be3fd3..f02e25f254 100644 --- a/include/gui/BufferQueue.h +++ b/include/gui/BufferQueue.h @@ -97,11 +97,9 @@ public: // BufferQueue manages a pool of gralloc memory slots to be used by - // producers and consumers. allowSynchronousMode specifies whether or not - // synchronous mode can be enabled by the producer. allocator is used to - // allocate all the needed gralloc buffers. - BufferQueue(bool allowSynchronousMode = true, - const sp& allocator = NULL); + // producers and consumers. allocator is used to allocate all the + // needed gralloc buffers. + BufferQueue(const sp& allocator = NULL); virtual ~BufferQueue(); // Query native window attributes. The "what" values are enumerated in @@ -197,15 +195,6 @@ public: // will usually be the one obtained from dequeueBuffer. virtual void cancelBuffer(int buf, const sp& fence); - // setSynchronousMode sets whether dequeueBuffer is synchronous or - // asynchronous. In synchronous mode, dequeueBuffer blocks until - // a buffer is available, the currently bound buffer can be dequeued and - // queued buffers will be acquired in order. In asynchronous mode, - // a queued buffer may be replaced by a subsequently queued buffer. - // - // The default mode is asynchronous. - virtual status_t setSynchronousMode(bool enabled); - // connect attempts to connect a producer API to the BufferQueue. This // must be called before any other IGraphicBufferProducer methods are // called except for getAllocator. A consumer must already be connected. @@ -215,7 +204,7 @@ public: // it's still connected to a producer). // // APIs are enumerated in window.h (e.g. NATIVE_WINDOW_API_CPU). - virtual status_t connect(int api, QueueBufferOutput* output); + virtual status_t connect(int api, bool producerControlledByApp, QueueBufferOutput* output); // disconnect attempts to disconnect a producer API from the BufferQueue. // Calling this method will cause any subsequent calls to other @@ -312,9 +301,11 @@ public: // consumer may be connected, and when that consumer disconnects the // BufferQueue is placed into the "abandoned" state, causing most // interactions with the BufferQueue by the producer to fail. + // controlledByApp indicates whether the consumer is controlled by + // the application. // // consumer may not be NULL. - status_t consumerConnect(const sp& consumer); + status_t consumerConnect(const sp& consumer, bool controlledByApp); // consumerDisconnect disconnects a consumer from the BufferQueue. All // buffers will be freed and the BufferQueue is placed in the "abandoned" @@ -347,10 +338,6 @@ public: // fail if a producer is connected to the BufferQueue. status_t setMaxAcquiredBufferCount(int maxAcquiredBuffers); - // isSynchronousMode returns whether the BufferQueue is currently in - // synchronous mode. - bool isSynchronousMode() const; - // setConsumerName sets the name used in logging void setConsumerName(const String8& name); @@ -568,13 +555,18 @@ private: // to NULL and is written by consumerConnect and consumerDisconnect. sp mConsumerListener; + // mConsumerControlledByApp whether the connected consumer is controlled by the + // application. + bool mConsumerControlledByApp; + + // mDequeueBufferCannotBlock whether dequeueBuffer() isn't allowed to block. + // this flag is set durring connect() when both consumer and producer are controlled + // by the application. + bool mDequeueBufferCannotBlock; + // mSynchronousMode whether we're in synchronous mode or not bool mSynchronousMode; - // mAllowSynchronousMode whether we allow synchronous mode or not. Set - // when the BufferQueue is created (by the consumer). - const bool mAllowSynchronousMode; - // mConnectedApi indicates the producer API that is currently connected // to this BufferQueue. It defaults to NO_CONNECTED_API (= 0), and gets // updated by the connect and disconnect methods. diff --git a/include/gui/ConsumerBase.h b/include/gui/ConsumerBase.h index 42b84cc7ce..7b58bc5bb1 100644 --- a/include/gui/ConsumerBase.h +++ b/include/gui/ConsumerBase.h @@ -87,7 +87,9 @@ protected: // ConsumerBase constructs a new ConsumerBase object to consume image // buffers from the given BufferQueue. - ConsumerBase(const sp &bufferQueue); + // The controlledByApp flag indicates that this consumer is under the application's + // control. + ConsumerBase(const sp &bufferQueue, bool controlledByApp = false); // onLastStrongRef gets called by RefBase just before the dtor of the most // derived class. It is used to clean up the buffers so that ConsumerBase diff --git a/include/gui/CpuConsumer.h b/include/gui/CpuConsumer.h index 5f1e36993f..28903508b3 100644 --- a/include/gui/CpuConsumer.h +++ b/include/gui/CpuConsumer.h @@ -67,7 +67,7 @@ class CpuConsumer : public ConsumerBase // Create a new CPU consumer. The maxLockedBuffers parameter specifies // how many buffers can be locked for user access at the same time. CpuConsumer(const sp& bq, - uint32_t maxLockedBuffers, bool synchronousMode = true); + uint32_t maxLockedBuffers, bool controlledByApp = false); virtual ~CpuConsumer(); diff --git a/include/gui/DummyConsumer.h b/include/gui/DummyConsumer.h deleted file mode 100644 index 08e8ec8072..0000000000 --- a/include/gui/DummyConsumer.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (C) 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. - */ - -#ifndef ANDROID_GUI_DUMMYCONSUMER_H -#define ANDROID_GUI_DUMMYCONSUMER_H - -#include - -namespace android { -// ---------------------------------------------------------------------------- - - -// The DummyConsumer does not keep a reference to BufferQueue -// unlike GLConsumer. This prevents a circular reference from -// forming without having to use a ProxyConsumerListener -class DummyConsumer : public BufferQueue::ConsumerListener { -public: - DummyConsumer(); - virtual ~DummyConsumer(); -protected: - - // Implementation of the BufferQueue::ConsumerListener interface. These - // calls are used to notify the GLConsumer of asynchronous events in the - // BufferQueue. - virtual void onFrameAvailable(); - virtual void onBuffersReleased(); - -}; - -// ---------------------------------------------------------------------------- -}; // namespace android - -#endif // ANDROID_GUI_DUMMYCONSUMER_H diff --git a/include/gui/GLConsumer.h b/include/gui/GLConsumer.h index 65544bd1df..1df5b42a00 100644 --- a/include/gui/GLConsumer.h +++ b/include/gui/GLConsumer.h @@ -87,7 +87,7 @@ public: // requirement that either of these methods be called. GLConsumer(const sp& bq, GLuint tex, GLenum texTarget = GL_TEXTURE_EXTERNAL_OES, - bool useFenceSync = true); + bool useFenceSync = true, bool isControlledByApp = false); // updateTexImage acquires the most recently queued buffer, and sets the // image contents of the target texture to it. @@ -177,10 +177,6 @@ public: // current texture buffer. status_t doGLFenceWait() const; - // isSynchronousMode returns whether the GLConsumer is currently in - // synchronous mode. - bool isSynchronousMode() const; - // set the name of the GLConsumer that will be used to identify it in // log messages. void setName(const String8& name); @@ -190,7 +186,6 @@ public: status_t setDefaultBufferFormat(uint32_t defaultFormat); status_t setConsumerUsageBits(uint32_t usage); status_t setTransformHint(uint32_t hint); - virtual status_t setSynchronousMode(bool enabled); // getBufferQueue returns the BufferQueue object to which this // GLConsumer is connected. diff --git a/include/gui/IGraphicBufferProducer.h b/include/gui/IGraphicBufferProducer.h index 29c7ff371b..af5fcfc79b 100644 --- a/include/gui/IGraphicBufferProducer.h +++ b/include/gui/IGraphicBufferProducer.h @@ -171,13 +171,6 @@ public: // 'what' tokens allowed are that of android_natives.h virtual int query(int what, int* value) = 0; - // setSynchronousMode set whether dequeueBuffer is synchronous or - // asynchronous. In synchronous mode, dequeueBuffer blocks until - // a buffer is available, the currently bound buffer can be dequeued and - // queued buffers will be retired in order. - // The default mode is asynchronous. - virtual status_t setSynchronousMode(bool enabled) = 0; - // connect attempts to connect a client API to the IGraphicBufferProducer. // This must be called before any other IGraphicBufferProducer methods are // called except for getAllocator. @@ -188,7 +181,7 @@ public: // outWidth, outHeight and outTransform are filled with the default width // and height of the window and current transform applied to buffers, // respectively. - virtual status_t connect(int api, QueueBufferOutput* output) = 0; + virtual status_t connect(int api, bool producerControlledByApp, QueueBufferOutput* output) = 0; // disconnect attempts to disconnect a client API from the // IGraphicBufferProducer. Calling this method will cause any subsequent diff --git a/include/gui/Surface.h b/include/gui/Surface.h index c25847ce6e..6f12e77113 100644 --- a/include/gui/Surface.h +++ b/include/gui/Surface.h @@ -61,8 +61,11 @@ public: * However, once a Surface is connected, it'll prevent other Surfaces * referring to the same IGraphicBufferProducer to become connected and * therefore prevent them to be used as actual producers of buffers. + * + * the controlledByApp flag indicates that this Surface (producer) is + * controlled by the application. This flag is used at connect time. */ - Surface(const sp& bufferProducer); + Surface(const sp& bufferProducer, bool controlledByApp = false); /* getIGraphicBufferProducer() returns the IGraphicBufferProducer this * Surface was created with. Usually it's an error to use the @@ -228,6 +231,10 @@ private: // window. this is only a hint, actual transform may differ. uint32_t mTransformHint; + // mProducerControlledByApp whether this buffer producer is controlled + // by the application + bool mProducerControlledByApp; + // mConsumerRunningBehind whether the consumer is running more than // one buffer behind the producer. mutable bool mConsumerRunningBehind; diff --git a/libs/gui/Android.mk b/libs/gui/Android.mk index c080f47c87..f627e5d2b8 100644 --- a/libs/gui/Android.mk +++ b/libs/gui/Android.mk @@ -8,7 +8,6 @@ LOCAL_SRC_FILES:= \ ConsumerBase.cpp \ CpuConsumer.cpp \ DisplayEventReceiver.cpp \ - DummyConsumer.cpp \ GLConsumer.cpp \ GraphicBufferAlloc.cpp \ GuiConfig.cpp \ diff --git a/libs/gui/BufferItemConsumer.cpp b/libs/gui/BufferItemConsumer.cpp index f5b2c7eb38..0f818b76ff 100644 --- a/libs/gui/BufferItemConsumer.cpp +++ b/libs/gui/BufferItemConsumer.cpp @@ -30,11 +30,10 @@ namespace android { BufferItemConsumer::BufferItemConsumer(const sp& bq, - uint32_t consumerUsage, int bufferCount, bool synchronousMode) : - ConsumerBase(bq) + uint32_t consumerUsage, int bufferCount, bool controlledByApp) : + ConsumerBase(bq, controlledByApp) { mBufferQueue->setConsumerUsageBits(consumerUsage); - mBufferQueue->setSynchronousMode(synchronousMode); mBufferQueue->setMaxAcquiredBufferCount(bufferCount); } diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp index 8d4b174450..1e86a4f3df 100644 --- a/libs/gui/BufferQueue.cpp +++ b/libs/gui/BufferQueue.cpp @@ -63,15 +63,15 @@ static const char* scalingModeName(int scalingMode) { } } -BufferQueue::BufferQueue(bool allowSynchronousMode, - const sp& allocator) : +BufferQueue::BufferQueue(const sp& allocator) : mDefaultWidth(1), mDefaultHeight(1), mMaxAcquiredBufferCount(1), mDefaultMaxBufferCount(2), mOverrideMaxBufferCount(0), - mSynchronousMode(false), - mAllowSynchronousMode(allowSynchronousMode), + mConsumerControlledByApp(false), + mDequeueBufferCannotBlock(false), + mSynchronousMode(true), mConnectedApi(NO_CONNECTED_API), mAbandoned(false), mFrameCounter(0), @@ -109,11 +109,6 @@ status_t BufferQueue::setDefaultMaxBufferCountLocked(int count) { return NO_ERROR; } -bool BufferQueue::isSynchronousMode() const { - Mutex::Autolock lock(mMutex); - return mSynchronousMode; -} - void BufferQueue::setConsumerName(const String8& name) { Mutex::Autolock lock(mMutex); mConsumerName = name; @@ -348,6 +343,10 @@ status_t BufferQueue::dequeueBuffer(int *outBuf, sp* outFence, // the max buffer count to change. tryAgain = found == INVALID_BUFFER_SLOT; if (tryAgain) { + if (mDequeueBufferCannotBlock) { + ST_LOGE("dequeueBuffer: would block! returning an error instead."); + return WOULD_BLOCK; + } mDequeueCondition.wait(mMutex); } } @@ -441,38 +440,6 @@ status_t BufferQueue::dequeueBuffer(int *outBuf, sp* outFence, return returnFlags; } -status_t BufferQueue::setSynchronousMode(bool enabled) { - ATRACE_CALL(); - ST_LOGV("setSynchronousMode: enabled=%d", enabled); - Mutex::Autolock lock(mMutex); - - if (mAbandoned) { - ST_LOGE("setSynchronousMode: BufferQueue has been abandoned!"); - return NO_INIT; - } - - status_t err = OK; - if (!mAllowSynchronousMode && enabled) - return err; - - if (!enabled) { - // going to asynchronous mode, drain the queue - err = drainQueueLocked(); - if (err != NO_ERROR) - return err; - } - - if (mSynchronousMode != enabled) { - // - if we're going to asynchronous mode, the queue is guaranteed to be - // empty here - // - if the client set the number of buffers, we're guaranteed that - // we have at least 3 (because we don't allow less) - mSynchronousMode = enabled; - mDequeueCondition.broadcast(); - } - return err; -} - status_t BufferQueue::queueBuffer(int buf, const QueueBufferInput& input, QueueBufferOutput* output) { ATRACE_CALL(); @@ -630,7 +597,7 @@ void BufferQueue::cancelBuffer(int buf, const sp& fence) { mDequeueCondition.broadcast(); } -status_t BufferQueue::connect(int api, QueueBufferOutput* output) { +status_t BufferQueue::connect(int api, bool producerControlledByApp, QueueBufferOutput* output) { ATRACE_CALL(); ST_LOGV("connect: api=%d", api); Mutex::Autolock lock(mMutex); @@ -667,6 +634,8 @@ status_t BufferQueue::connect(int api, QueueBufferOutput* output) { } mBufferHasBeenQueued = false; + mDequeueBufferCannotBlock = mConsumerControlledByApp && producerControlledByApp; + mSynchronousMode = !mDequeueBufferCannotBlock; return err; } @@ -950,7 +919,8 @@ status_t BufferQueue::releaseBuffer( return NO_ERROR; } -status_t BufferQueue::consumerConnect(const sp& consumerListener) { +status_t BufferQueue::consumerConnect(const sp& consumerListener, + bool controlledByApp) { ST_LOGV("consumerConnect"); Mutex::Autolock lock(mMutex); @@ -964,6 +934,7 @@ status_t BufferQueue::consumerConnect(const sp& consumerListen } mConsumerListener = consumerListener; + mConsumerControlledByApp = controlledByApp; return NO_ERROR; } diff --git a/libs/gui/ConsumerBase.cpp b/libs/gui/ConsumerBase.cpp index deb2646693..cd94ce19aa 100644 --- a/libs/gui/ConsumerBase.cpp +++ b/libs/gui/ConsumerBase.cpp @@ -51,7 +51,7 @@ static int32_t createProcessUniqueId() { return android_atomic_inc(&globalCounter); } -ConsumerBase::ConsumerBase(const sp& bufferQueue) : +ConsumerBase::ConsumerBase(const sp& bufferQueue, bool controlledByApp) : mAbandoned(false), mBufferQueue(bufferQueue) { // Choose a name using the PID and a process-unique ID. @@ -66,7 +66,7 @@ ConsumerBase::ConsumerBase(const sp& bufferQueue) : listener = static_cast(this); proxy = new BufferQueue::ProxyConsumerListener(listener); - status_t err = mBufferQueue->consumerConnect(proxy); + status_t err = mBufferQueue->consumerConnect(proxy, controlledByApp); if (err != NO_ERROR) { CB_LOGE("ConsumerBase: error connecting to BufferQueue: %s (%d)", strerror(-err), err); diff --git a/libs/gui/CpuConsumer.cpp b/libs/gui/CpuConsumer.cpp index adddfc2c6c..b8c00af0a7 100644 --- a/libs/gui/CpuConsumer.cpp +++ b/libs/gui/CpuConsumer.cpp @@ -31,15 +31,14 @@ namespace android { CpuConsumer::CpuConsumer(const sp& bq, - uint32_t maxLockedBuffers, bool synchronousMode) : - ConsumerBase(bq), + uint32_t maxLockedBuffers, bool controlledByApp) : + ConsumerBase(bq, controlledByApp), mMaxLockedBuffers(maxLockedBuffers), mCurrentLockedBuffers(0) { // Create tracking entries for locked buffers mAcquiredBuffers.insertAt(0, maxLockedBuffers); - mBufferQueue->setSynchronousMode(synchronousMode); mBufferQueue->setConsumerUsageBits(GRALLOC_USAGE_SW_READ_OFTEN); mBufferQueue->setMaxAcquiredBufferCount(maxLockedBuffers); } diff --git a/libs/gui/DummyConsumer.cpp b/libs/gui/DummyConsumer.cpp deleted file mode 100644 index be47e0edf3..0000000000 --- a/libs/gui/DummyConsumer.cpp +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (C) 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. - */ - -#define LOG_TAG "DummyConsumer" -// #define LOG_NDEBUG 0 - -#include - -#include -#include - -namespace android { - -DummyConsumer::DummyConsumer() { - ALOGV("DummyConsumer"); -} - -DummyConsumer::~DummyConsumer() { - ALOGV("~DummyConsumer"); -} - -void DummyConsumer::onFrameAvailable() { - ALOGV("onFrameAvailable"); -} - -void DummyConsumer::onBuffersReleased() { - ALOGV("onBuffersReleased"); -} - -}; // namespace android diff --git a/libs/gui/GLConsumer.cpp b/libs/gui/GLConsumer.cpp index 07f27c3aa3..92f07eb57c 100644 --- a/libs/gui/GLConsumer.cpp +++ b/libs/gui/GLConsumer.cpp @@ -79,8 +79,8 @@ static void mtxMul(float out[16], const float a[16], const float b[16]); GLConsumer::GLConsumer(const sp& bq, GLuint tex, - GLenum texTarget, bool useFenceSync) : - ConsumerBase(bq), + GLenum texTarget, bool useFenceSync, bool isControlledByApp) : + ConsumerBase(bq, isControlledByApp), mCurrentTransform(0), mCurrentScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE), mCurrentFence(Fence::NO_FENCE), @@ -844,11 +844,6 @@ status_t GLConsumer::doGLFenceWaitLocked() const { return NO_ERROR; } -bool GLConsumer::isSynchronousMode() const { - Mutex::Autolock lock(mMutex); - return mBufferQueue->isSynchronousMode(); -} - void GLConsumer::freeBufferLocked(int slotIndex) { ST_LOGV("freeBufferLocked: slotIndex=%d", slotIndex); if (slotIndex == mCurrentTexture) { @@ -891,13 +886,6 @@ status_t GLConsumer::setTransformHint(uint32_t hint) { return mBufferQueue->setTransformHint(hint); } -// 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 GLConsumer::dumpLocked(String8& result, const char* prefix) const { result.appendFormat( diff --git a/libs/gui/IGraphicBufferProducer.cpp b/libs/gui/IGraphicBufferProducer.cpp index 63d7628a55..9f65fc3f2b 100644 --- a/libs/gui/IGraphicBufferProducer.cpp +++ b/libs/gui/IGraphicBufferProducer.cpp @@ -37,7 +37,6 @@ enum { QUEUE_BUFFER, CANCEL_BUFFER, QUERY, - SET_SYNCHRONOUS_MODE, CONNECT, DISCONNECT, }; @@ -142,22 +141,11 @@ public: return result; } - virtual status_t setSynchronousMode(bool enabled) { - Parcel data, reply; - data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor()); - data.writeInt32(enabled); - status_t result = remote()->transact(SET_SYNCHRONOUS_MODE, data, &reply); - if (result != NO_ERROR) { - return result; - } - result = reply.readInt32(); - return result; - } - - virtual status_t connect(int api, QueueBufferOutput* output) { + virtual status_t connect(int api, bool producerControlledByApp, QueueBufferOutput* output) { Parcel data, reply; data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor()); data.writeInt32(api); + data.writeInt32(producerControlledByApp); status_t result = remote()->transact(CONNECT, data, &reply); if (result != NO_ERROR) { return result; @@ -252,20 +240,14 @@ status_t BnGraphicBufferProducer::onTransact( reply->writeInt32(res); return NO_ERROR; } break; - case SET_SYNCHRONOUS_MODE: { - 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(IGraphicBufferProducer, data, reply); int api = data.readInt32(); + bool producerControlledByApp = data.readInt32(); QueueBufferOutput* const output = reinterpret_cast( reply->writeInplace(sizeof(QueueBufferOutput))); - status_t res = connect(api, output); + status_t res = connect(api, producerControlledByApp, output); reply->writeInt32(res); return NO_ERROR; } break; diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp index a616c1e417..0d4449af65 100644 --- a/libs/gui/Surface.cpp +++ b/libs/gui/Surface.cpp @@ -37,7 +37,8 @@ namespace android { Surface::Surface( - const sp& bufferProducer) + const sp& bufferProducer, + bool controlledByApp) : mGraphicBufferProducer(bufferProducer) { // Initialize the ANativeWindow function pointers. @@ -71,6 +72,7 @@ Surface::Surface( mTransformHint = 0; mConsumerRunningBehind = false; mConnectedToCpu = false; + mProducerControlledByApp = true; } Surface::~Surface() { @@ -168,7 +170,9 @@ int Surface::setSwapInterval(int interval) { if (interval > maxSwapInterval) interval = maxSwapInterval; - status_t res = mGraphicBufferProducer->setSynchronousMode(interval ? true : false); + // FIXME: re-implement swap-interval + //status_t res = mGraphicBufferProducer->setSynchronousMode(interval ? true : false); + status_t res = NO_ERROR; return res; } @@ -486,7 +490,7 @@ int Surface::connect(int api) { ALOGV("Surface::connect"); Mutex::Autolock lock(mMutex); IGraphicBufferProducer::QueueBufferOutput output; - int err = mGraphicBufferProducer->connect(api, &output); + int err = mGraphicBufferProducer->connect(api, mProducerControlledByApp, &output); if (err == NO_ERROR) { uint32_t numPendingBuffers = 0; output.deflate(&mDefaultWidth, &mDefaultHeight, &mTransformHint, diff --git a/libs/gui/tests/BufferQueue_test.cpp b/libs/gui/tests/BufferQueue_test.cpp index 96829879a1..1f8e7fa0db 100644 --- a/libs/gui/tests/BufferQueue_test.cpp +++ b/libs/gui/tests/BufferQueue_test.cpp @@ -62,9 +62,9 @@ struct DummyConsumer : public BufferQueue::ConsumerListener { TEST_F(BufferQueueTest, AcquireBuffer_ExceedsMaxAcquireCount_Fails) { sp dc(new DummyConsumer); - mBQ->consumerConnect(dc); + mBQ->consumerConnect(dc, false); IGraphicBufferProducer::QueueBufferOutput qbo; - mBQ->connect(NATIVE_WINDOW_API_CPU, &qbo); + mBQ->connect(NATIVE_WINDOW_API_CPU, false, &qbo); mBQ->setBufferCount(4); int slot; @@ -95,7 +95,7 @@ TEST_F(BufferQueueTest, AcquireBuffer_ExceedsMaxAcquireCount_Fails) { TEST_F(BufferQueueTest, SetMaxAcquiredBufferCountWithIllegalValues_ReturnsError) { sp dc(new DummyConsumer); - mBQ->consumerConnect(dc); + mBQ->consumerConnect(dc, false); ASSERT_EQ(BAD_VALUE, mBQ->setMaxAcquiredBufferCount(0)); ASSERT_EQ(BAD_VALUE, mBQ->setMaxAcquiredBufferCount(-3)); @@ -106,7 +106,7 @@ TEST_F(BufferQueueTest, SetMaxAcquiredBufferCountWithIllegalValues_ReturnsError) TEST_F(BufferQueueTest, SetMaxAcquiredBufferCountWithLegalValues_Succeeds) { sp dc(new DummyConsumer); - mBQ->consumerConnect(dc); + mBQ->consumerConnect(dc, false); ASSERT_EQ(OK, mBQ->setMaxAcquiredBufferCount(1)); ASSERT_EQ(OK, mBQ->setMaxAcquiredBufferCount(2)); diff --git a/libs/gui/tests/SurfaceTextureClient_test.cpp b/libs/gui/tests/SurfaceTextureClient_test.cpp index 46bcb22637..9908cc9db5 100644 --- a/libs/gui/tests/SurfaceTextureClient_test.cpp +++ b/libs/gui/tests/SurfaceTextureClient_test.cpp @@ -338,7 +338,7 @@ TEST_F(SurfaceTextureClientTest, SurfaceTextureSetDefaultSizeVsGeometry) { TEST_F(SurfaceTextureClientTest, SurfaceTextureTooManyUpdateTexImage) { android_native_buffer_t* buf[3]; - ASSERT_EQ(OK, mST->setSynchronousMode(false)); + ASSERT_EQ(OK, mANW->setSwapInterval(mANW.get(), 0)); ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 4)); ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[0])); @@ -346,7 +346,7 @@ TEST_F(SurfaceTextureClientTest, SurfaceTextureTooManyUpdateTexImage) { EXPECT_EQ(OK, mST->updateTexImage()); EXPECT_EQ(OK, mST->updateTexImage()); - ASSERT_EQ(OK, mST->setSynchronousMode(true)); + ASSERT_EQ(OK, mANW->setSwapInterval(mANW.get(), 1)); ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 3)); ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[0])); @@ -361,7 +361,7 @@ TEST_F(SurfaceTextureClientTest, SurfaceTextureTooManyUpdateTexImage) { TEST_F(SurfaceTextureClientTest, SurfaceTextureSyncModeSlowRetire) { android_native_buffer_t* buf[3]; - ASSERT_EQ(OK, mST->setSynchronousMode(true)); + ASSERT_EQ(OK, mANW->setSwapInterval(mANW.get(), 1)); ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 4)); ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[0])); ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[1])); @@ -382,7 +382,7 @@ TEST_F(SurfaceTextureClientTest, SurfaceTextureSyncModeSlowRetire) { TEST_F(SurfaceTextureClientTest, SurfaceTextureSyncModeFastRetire) { android_native_buffer_t* buf[3]; - ASSERT_EQ(OK, mST->setSynchronousMode(true)); + ASSERT_EQ(OK, mANW->setSwapInterval(mANW.get(), 1)); ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 4)); ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[0])); ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[1])); @@ -403,7 +403,7 @@ TEST_F(SurfaceTextureClientTest, SurfaceTextureSyncModeFastRetire) { TEST_F(SurfaceTextureClientTest, SurfaceTextureSyncModeDQQR) { android_native_buffer_t* buf[3]; - ASSERT_EQ(OK, mST->setSynchronousMode(true)); + ASSERT_EQ(OK, mANW->setSwapInterval(mANW.get(), 1)); ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 3)); ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[0])); @@ -429,7 +429,7 @@ TEST_F(SurfaceTextureClientTest, SurfaceTextureSyncModeDQQR) { TEST_F(SurfaceTextureClientTest, DISABLED_SurfaceTextureSyncModeDequeueCurrent) { android_native_buffer_t* buf[3]; android_native_buffer_t* firstBuf; - ASSERT_EQ(OK, mST->setSynchronousMode(true)); + ASSERT_EQ(OK, mANW->setSwapInterval(mANW.get(), 1)); ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 3)); ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &firstBuf)); ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), firstBuf, -1)); @@ -449,7 +449,7 @@ TEST_F(SurfaceTextureClientTest, DISABLED_SurfaceTextureSyncModeDequeueCurrent) TEST_F(SurfaceTextureClientTest, SurfaceTextureSyncModeMinUndequeued) { android_native_buffer_t* buf[3]; - ASSERT_EQ(OK, mST->setSynchronousMode(true)); + ASSERT_EQ(OK, mANW->setSwapInterval(mANW.get(), 1)); ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 3)); // We should be able to dequeue all the buffers before we've queued mANWy. @@ -528,7 +528,7 @@ TEST_F(SurfaceTextureClientTest, DISABLED_SurfaceTextureSyncModeWaitRetire) { }; android_native_buffer_t* buf[3]; - ASSERT_EQ(OK, mST->setSynchronousMode(true)); + ASSERT_EQ(OK, mANW->setSwapInterval(mANW.get(), 1)); ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 3)); // dequeue/queue/update so we have a current buffer ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[0])); diff --git a/libs/gui/tests/SurfaceTexture_test.cpp b/libs/gui/tests/SurfaceTexture_test.cpp index d97521aea5..e6d87db252 100644 --- a/libs/gui/tests/SurfaceTexture_test.cpp +++ b/libs/gui/tests/SurfaceTexture_test.cpp @@ -944,7 +944,6 @@ TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledYV12BuffersRepeatedly) { enum { texHeight = 16 }; enum { numFrames = 1024 }; - ASSERT_EQ(NO_ERROR, mST->setSynchronousMode(true)); ASSERT_EQ(NO_ERROR, mST->setDefaultMaxBufferCount(2)); ASSERT_EQ(NO_ERROR, native_window_set_buffers_geometry(mANW.get(), texWidth, texHeight, HAL_PIXEL_FORMAT_YV12)); @@ -1211,10 +1210,8 @@ TEST_F(SurfaceTextureGLTest, DisconnectStressTest) { sp mANW; }; - ASSERT_EQ(OK, mST->setSynchronousMode(true)); - sp dw(new DisconnectWaiter()); - mST->getBufferQueue()->consumerConnect(dw); + mST->getBufferQueue()->consumerConnect(dw, false); sp pt(new ProducerThread(mANW)); @@ -1237,8 +1234,6 @@ TEST_F(SurfaceTextureGLTest, DisconnectStressTest) { // when it is disconnected and reconnected. Otherwise it will // attempt to release a buffer that it does not owned TEST_F(SurfaceTextureGLTest, DisconnectClearsCurrentTexture) { - ASSERT_EQ(OK, mST->setSynchronousMode(true)); - ASSERT_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_EGL)); @@ -1258,8 +1253,6 @@ TEST_F(SurfaceTextureGLTest, DisconnectClearsCurrentTexture) { ASSERT_EQ(OK, native_window_api_connect(mANW.get(), NATIVE_WINDOW_API_EGL)); - ASSERT_EQ(OK, mST->setSynchronousMode(true)); - EXPECT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &anb)); EXPECT_EQ(OK, mANW->queueBuffer(mANW.get(), anb, -1)); @@ -1272,8 +1265,6 @@ TEST_F(SurfaceTextureGLTest, DisconnectClearsCurrentTexture) { } TEST_F(SurfaceTextureGLTest, ScaleToWindowMode) { - ASSERT_EQ(OK, mST->setSynchronousMode(true)); - ASSERT_EQ(OK, native_window_set_scaling_mode(mANW.get(), NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW)); @@ -1306,8 +1297,6 @@ TEST_F(SurfaceTextureGLTest, ScaleToWindowMode) { // the image such that it has the same aspect ratio as the // default buffer size TEST_F(SurfaceTextureGLTest, CroppedScalingMode) { - ASSERT_EQ(OK, mST->setSynchronousMode(true)); - ASSERT_EQ(OK, native_window_set_scaling_mode(mANW.get(), NATIVE_WINDOW_SCALING_MODE_SCALE_CROP)); @@ -1417,7 +1406,6 @@ TEST_F(SurfaceTextureGLTest, AbandonUnblocksDequeueBuffer) { Mutex mMutex; }; - ASSERT_EQ(OK, mST->setSynchronousMode(true)); ASSERT_EQ(OK, mST->setDefaultMaxBufferCount(2)); sp pt(new ProducerThread(mANW)); @@ -1810,32 +1798,6 @@ TEST_F(SurfaceTextureGLToGLTest, EglMakeCurrentAfterConsumerDeathUnrefsBuffers) EXPECT_EQ(1, buffer->getStrongCount()); } - -TEST_F(SurfaceTextureGLToGLTest, EglSurfaceDefaultsToSynchronousMode) { - // This test requires 3 buffers to run on a single thread. - mST->setDefaultMaxBufferCount(3); - - ASSERT_TRUE(mST->isSynchronousMode()); - - for (int i = 0; i < 10; i++) { - // Produce a frame - EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mProducerEglSurface, - mProducerEglSurface, mProducerEglContext)); - ASSERT_EQ(EGL_SUCCESS, eglGetError()); - glClear(GL_COLOR_BUFFER_BIT); - EXPECT_TRUE(eglSwapBuffers(mEglDisplay, mProducerEglSurface)); - ASSERT_EQ(EGL_SUCCESS, eglGetError()); - - // Consume a frame - EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, - mEglContext)); - ASSERT_EQ(EGL_SUCCESS, eglGetError()); - ASSERT_EQ(NO_ERROR, mST->updateTexImage()); - } - - ASSERT_TRUE(mST->isSynchronousMode()); -} - TEST_F(SurfaceTextureGLToGLTest, TexturingFromUserSizedGLFilledBuffer) { enum { texWidth = 64 }; enum { texHeight = 64 }; @@ -2285,7 +2247,6 @@ TEST_F(SurfaceTextureGLThreadToGLTest, } }; - ASSERT_EQ(OK, mST->setSynchronousMode(true)); ASSERT_EQ(OK, mST->setDefaultMaxBufferCount(2)); runProducerThread(new PT()); @@ -2826,7 +2787,6 @@ TEST_F(SurfaceTextureMultiContextGLTest, TEST_F(SurfaceTextureMultiContextGLTest, UpdateTexImageSucceedsForBufferConsumedBeforeDetach) { - ASSERT_EQ(NO_ERROR, mST->setSynchronousMode(true)); ASSERT_EQ(NO_ERROR, mST->setDefaultMaxBufferCount(2)); // produce two frames and consume them both on the primary context diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index 953f6f91dc..c55b02aa21 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -83,7 +83,9 @@ TEST_F(SurfaceTest, QueuesToWindowComposerIsTrueWhenPurgatorized) { } // This test probably doesn't belong here. -TEST_F(SurfaceTest, ScreenshotsOfProtectedBuffersSucceed) { +// DISABLED because it hangs when disconnecting because of draining the queue. +// will be fixed in a subsequent BQ change +TEST_F(SurfaceTest, DISABLED_ScreenshotsOfProtectedBuffersSucceed) { sp anw(mSurface); // Verify the screenshot works with no protected buffers. diff --git a/opengl/tests/EGLTest/EGL_test.cpp b/opengl/tests/EGLTest/EGL_test.cpp index c0daba2e6d..86bbb84896 100644 --- a/opengl/tests/EGLTest/EGL_test.cpp +++ b/opengl/tests/EGLTest/EGL_test.cpp @@ -20,7 +20,6 @@ #include #include -#include namespace android { @@ -101,9 +100,14 @@ TEST_F(EGLTest, EGLTerminateSucceedsWithRemainingObjects) { }; EXPECT_TRUE(eglChooseConfig(mEglDisplay, attrs, &config, 1, &numConfigs)); + struct DummyConsumer : public BufferQueue::ConsumerListener { + virtual void onFrameAvailable() {} + virtual void onBuffersReleased() {} + }; + // Create a EGLSurface sp bq = new BufferQueue(); - bq->consumerConnect(new DummyConsumer()); + bq->consumerConnect(new DummyConsumer, false); sp mSTC = new Surface(static_cast >( bq)); sp mANW = mSTC; diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk index 2ec575ecbf..bb0a2f92a6 100644 --- a/services/surfaceflinger/Android.mk +++ b/services/surfaceflinger/Android.mk @@ -36,7 +36,6 @@ ifeq ($(TARGET_BOARD_PLATFORM),omap4) endif ifeq ($(TARGET_BOARD_PLATFORM),s5pc110) LOCAL_CFLAGS += -DHAS_CONTEXT_PRIORITY - LOCAL_CFLAGS += -DNEVER_DEFAULT_TO_ASYNC_MODE endif ifeq ($(TARGET_DISABLE_TRIPLE_BUFFERING),true) diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp index 7987da312b..bd2f5f36e7 100644 --- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp +++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp @@ -51,7 +51,7 @@ namespace android { */ FramebufferSurface::FramebufferSurface(HWComposer& hwc, int disp) : - ConsumerBase(new BufferQueue(true, new GraphicBufferAlloc())), + ConsumerBase(new BufferQueue(new GraphicBufferAlloc())), mDisplayType(disp), mCurrentBufferSlot(-1), mCurrentBuffer(0), @@ -64,7 +64,6 @@ FramebufferSurface::FramebufferSurface(HWComposer& hwc, int disp) : GRALLOC_USAGE_HW_COMPOSER); mBufferQueue->setDefaultBufferFormat(mHwc.getFormat(disp)); mBufferQueue->setDefaultBufferSize(mHwc.getWidth(disp), mHwc.getHeight(disp)); - mBufferQueue->setSynchronousMode(true); mBufferQueue->setDefaultMaxBufferCount(NUM_FRAMEBUFFER_SURFACE_BUFFERS); } diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp index a324e945e9..c92b66654e 100644 --- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp +++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp @@ -41,7 +41,7 @@ static const char* dbgCompositionTypeStr(DisplaySurface::CompositionType type) { VirtualDisplaySurface::VirtualDisplaySurface(HWComposer& hwc, int32_t dispId, const sp& sink, const String8& name) -: ConsumerBase(new BufferQueue(true)), +: ConsumerBase(new BufferQueue()), mHwc(hwc), mDisplayId(dispId), mDisplayName(name), @@ -345,13 +345,10 @@ int VirtualDisplaySurface::query(int what, int* value) { return mSource[SOURCE_SINK]->query(what, value); } -status_t VirtualDisplaySurface::setSynchronousMode(bool enabled) { - return mSource[SOURCE_SINK]->setSynchronousMode(enabled); -} - -status_t VirtualDisplaySurface::connect(int api, QueueBufferOutput* output) { +status_t VirtualDisplaySurface::connect(int api, bool producerControlledByApp, + QueueBufferOutput* output) { QueueBufferOutput qbo; - status_t result = mSource[SOURCE_SINK]->connect(api, &qbo); + status_t result = mSource[SOURCE_SINK]->connect(api, producerControlledByApp, &qbo); if (result == NO_ERROR) { updateQueueBufferOutput(qbo); *output = mQueueBufferOutput; diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h index 2b4cf8f8f7..94b24d2e1f 100644 --- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h +++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h @@ -101,8 +101,7 @@ private: const QueueBufferInput& input, QueueBufferOutput* output); virtual void cancelBuffer(int pslot, const sp& fence); virtual int query(int what, int* value); - virtual status_t setSynchronousMode(bool enabled); - virtual status_t connect(int api, QueueBufferOutput* output); + virtual status_t connect(int api, bool producerControlledByApp, QueueBufferOutput* output); virtual status_t disconnect(int api); // diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 2962115bdb..52211c22d9 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -115,7 +115,6 @@ void Layer::onFirstRef() mSurfaceFlingerConsumer->setConsumerUsageBits(getEffectiveUsage(0)); mSurfaceFlingerConsumer->setFrameAvailableListener(this); - mSurfaceFlingerConsumer->setSynchronousMode(true); mSurfaceFlingerConsumer->setName(mName); #ifdef TARGET_DISABLE_TRIPLE_BUFFERING diff --git a/services/surfaceflinger/SurfaceTextureLayer.cpp b/services/surfaceflinger/SurfaceTextureLayer.cpp index d0f0daec99..b76dc0c502 100644 --- a/services/surfaceflinger/SurfaceTextureLayer.cpp +++ b/services/surfaceflinger/SurfaceTextureLayer.cpp @@ -28,7 +28,7 @@ namespace android { SurfaceTextureLayer::SurfaceTextureLayer(const sp& flinger) - : BufferQueue(true), flinger(flinger) { + : BufferQueue(), flinger(flinger) { } SurfaceTextureLayer::~SurfaceTextureLayer() { @@ -51,32 +51,5 @@ SurfaceTextureLayer::~SurfaceTextureLayer() { flinger->postMessageAsync( new MessageCleanUpList(flinger, this) ); } -status_t SurfaceTextureLayer::connect(int api, QueueBufferOutput* output) { - status_t err = BufferQueue::connect(api, output); - if (err == NO_ERROR) { - switch(api) { - case NATIVE_WINDOW_API_MEDIA: - case NATIVE_WINDOW_API_CAMERA: - // Camera preview and videos are rate-limited on the producer - // side. If enabled for this build, we use async mode to always - // show the most recent frame at the cost of requiring an - // additional buffer. -#ifndef NEVER_DEFAULT_TO_ASYNC_MODE - err = setSynchronousMode(false); - break; -#endif - // fall through to set synchronous mode when not defaulting to - // async mode. - default: - err = setSynchronousMode(true); - break; - } - if (err != NO_ERROR) { - disconnect(api); - } - } - return err; -} - // --------------------------------------------------------------------------- }; // namespace android diff --git a/services/surfaceflinger/SurfaceTextureLayer.h b/services/surfaceflinger/SurfaceTextureLayer.h index 13cff2fff8..5f5e4ef5dd 100644 --- a/services/surfaceflinger/SurfaceTextureLayer.h +++ b/services/surfaceflinger/SurfaceTextureLayer.h @@ -38,10 +38,6 @@ class SurfaceTextureLayer : public BufferQueue { public: SurfaceTextureLayer(const sp& flinger); virtual ~SurfaceTextureLayer(); - - // After calling the superclass connect(), set or clear synchronous - // mode appropriately for the specified API. - virtual status_t connect(int api, QueueBufferOutput* output); }; // --------------------------------------------------------------------------- -- cgit v1.2.3-59-g8ed1b From a3fbda3cef04d51a35a3eb64b2f744a989800856 Mon Sep 17 00:00:00 2001 From: Mathias Agopian Date: Thu, 18 Jul 2013 15:55:03 -0700 Subject: BuffferQueue disconnect is now always asynchrnous we tag queued buffers with the "bufferqueue cannot block" flag and use that bit to discard a buffer in the queue by new ones comming in. this allows us to remove the buffer queue drain in disconnect while maintaining the right behaviour if it gets connected again (since each buffer remembers how it was enqueued). Change-Id: I1e703d363a687b70b19ba49cef32213116e8bd3f --- include/gui/BufferQueue.h | 36 +++++++++----------- libs/gui/BufferQueue.cpp | 74 +++++++++++------------------------------ libs/gui/tests/Surface_test.cpp | 4 +-- 3 files changed, 36 insertions(+), 78 deletions(-) (limited to 'libs/gui/BufferQueue.cpp') diff --git a/include/gui/BufferQueue.h b/include/gui/BufferQueue.h index f02e25f254..b968287cac 100644 --- a/include/gui/BufferQueue.h +++ b/include/gui/BufferQueue.h @@ -223,13 +223,13 @@ public: // public facing structure for BufferSlot struct BufferItem { - BufferItem() - : + BufferItem() : mTransform(0), mScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE), mTimestamp(0), mFrameNumber(0), mBuf(INVALID_BUFFER_SLOT), + mDequeueBufferCannotBlock(false), mAcquireCalled(false) { mCrop.makeInvalid(); } @@ -260,6 +260,13 @@ public: // mFence is a fence that will signal when the buffer is idle. sp mFence; + // mDequeueBufferCannotBlock whether this buffer was queued with the + // property that it can be replaced by a new buffer for the purpose of + // making sure dequeueBuffer() won't block. + // i.e.: was the BufferQueue in "mDequeueBufferCannotBlock" when this buffer + // was queued. + bool mDequeueBufferCannotBlock; + // Indicates whether this buffer has been seen by a consumer yet bool mAcquireCalled; }; @@ -366,17 +373,6 @@ private: // all slots. void freeAllBuffersLocked(); - // drainQueueLocked waits for the buffer queue to empty if we're in - // synchronous mode, or returns immediately otherwise. It returns NO_INIT - // if the BufferQueue is abandoned (consumer disconnected) or disconnected - // (producer disconnected) during the call. - status_t drainQueueLocked(); - - // drainQueueAndFreeBuffersLocked drains the buffer queue if we're in - // synchronous mode and free all buffers. In asynchronous mode, all buffers - // are freed except the currently queued buffer (if it exists). - status_t drainQueueAndFreeBuffersLocked(); - // setDefaultMaxBufferCountLocked sets the maximum number of buffer slots // that will be used if the producer does not override the buffer slot // count. The count must be between 2 and NUM_BUFFER_SLOTS, inclusive. @@ -387,15 +383,11 @@ private: // given the current BufferQueue state. int getMinMaxBufferCountLocked() const; - // getMinUndequeuedBufferCountLocked returns the minimum number of buffers - // that must remain in a state other than DEQUEUED. - int getMinUndequeuedBufferCountLocked() const; - // getMaxBufferCountLocked returns the maximum number of buffers that can // be allocated at once. This value depends upon the following member // variables: // - // mSynchronousMode + // mDequeueBufferCannotBlock // mMaxAcquiredBufferCount // mDefaultMaxBufferCount // mOverrideMaxBufferCount @@ -524,6 +516,11 @@ private: // in dequeueBuffer() if a width and height of zero is specified. uint32_t mDefaultHeight; + // mMinUndequeuedBufferCount holds the minimum number of buffers + // that must remain in a state other than DEQUEUED. + // This value cannot change while connected. + int mMinUndequeuedBufferCount; + // mMaxAcquiredBufferCount is the number of buffers that the consumer may // acquire at one time. It defaults to 1 and can be changed by the // consumer via the setMaxAcquiredBufferCount method, but this may only be @@ -564,9 +561,6 @@ private: // by the application. bool mDequeueBufferCannotBlock; - // mSynchronousMode whether we're in synchronous mode or not - bool mSynchronousMode; - // mConnectedApi indicates the producer API that is currently connected // to this BufferQueue. It defaults to NO_CONNECTED_API (= 0), and gets // updated by the connect and disconnect methods. diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp index 1e86a4f3df..f99bd29bd5 100644 --- a/libs/gui/BufferQueue.cpp +++ b/libs/gui/BufferQueue.cpp @@ -71,7 +71,6 @@ BufferQueue::BufferQueue(const sp& allocator) : mOverrideMaxBufferCount(0), mConsumerControlledByApp(false), mDequeueBufferCannotBlock(false), - mSynchronousMode(true), mConnectedApi(NO_CONNECTED_API), mAbandoned(false), mFrameCounter(0), @@ -210,7 +209,7 @@ int BufferQueue::query(int what, int* outValue) value = mDefaultBufferFormat; break; case NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS: - value = getMinUndequeuedBufferCountLocked(); + value = mMinUndequeuedBufferCount; break; case NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND: value = (mQueue.size() >= 2); @@ -329,7 +328,7 @@ status_t BufferQueue::dequeueBuffer(int *outBuf, sp* outFence, // make sure the client is not trying to dequeue more buffers // than allowed. const int newUndequeuedCount = maxBufferCount - (dequeuedCount+1); - const int minUndequeuedCount = getMinUndequeuedBufferCountLocked(); + const int minUndequeuedCount = mMinUndequeuedBufferCount; if (newUndequeuedCount < minUndequeuedCount) { ST_LOGE("dequeueBuffer: min undequeued buffer count (%d) " "exceeded (dequeued=%d undequeudCount=%d)", @@ -524,31 +523,27 @@ status_t BufferQueue::queueBuffer(int buf, item.mFrameNumber = mFrameCounter; item.mBuf = buf; item.mFence = fence; + item.mDequeueBufferCannotBlock = mDequeueBufferCannotBlock; - if (mSynchronousMode) { - // In synchronous mode we queue all buffers in a FIFO. + if (mQueue.empty()) { + // when the queue is empty, we can ignore "mDequeueBufferCannotBlock", and + // simply queue this buffer. mQueue.push_back(item); - - // Synchronous mode always signals that an additional frame should - // be consumed. listener = mConsumerListener; } else { - // In asynchronous mode we only keep the most recent buffer. - if (mQueue.empty()) { - mQueue.push_back(item); - - // Asynchronous mode only signals that a frame should be - // consumed if no previous frame was pending. If a frame were - // pending then the consumer would have already been notified. - listener = mConsumerListener; - } else { - Fifo::iterator front(mQueue.begin()); + // when the queue is not empty, we need to look at the front buffer + // state and see if we need to replace it. + Fifo::iterator front(mQueue.begin()); + if (front->mDequeueBufferCannotBlock) { // buffer slot currently queued is marked free if still tracked if (stillTracking(front)) { mSlots[front->mBuf].mBufferState = BufferSlot::FREE; } - // and we record the new buffer index in the queued list + // and we record the new buffer in the queued list *front = item; + } else { + mQueue.push_back(item); + listener = mConsumerListener; } } @@ -635,7 +630,8 @@ status_t BufferQueue::connect(int api, bool producerControlledByApp, QueueBuffer mBufferHasBeenQueued = false; mDequeueBufferCannotBlock = mConsumerControlledByApp && producerControlledByApp; - mSynchronousMode = !mDequeueBufferCannotBlock; + mMinUndequeuedBufferCount = mDequeueBufferCannotBlock ? + mMaxAcquiredBufferCount+1 : mMaxAcquiredBufferCount; return err; } @@ -662,7 +658,7 @@ status_t BufferQueue::disconnect(int api) { case NATIVE_WINDOW_API_MEDIA: case NATIVE_WINDOW_API_CAMERA: if (mConnectedApi == api) { - drainQueueAndFreeBuffersLocked(); + freeAllBuffersLocked(); mConnectedApi = NO_CONNECTED_API; mDequeueCondition.broadcast(); listener = mConsumerListener; @@ -711,9 +707,9 @@ void BufferQueue::dump(String8& result, const char* prefix) const { int maxBufferCount = getMaxBufferCountLocked(); result.appendFormat( - "%s-BufferQueue maxBufferCount=%d, mSynchronousMode=%d, default-size=[%dx%d], " + "%s-BufferQueue maxBufferCount=%d, mDequeueBufferCannotBlock=%d, default-size=[%dx%d], " "default-format=%d, transform-hint=%02x, FIFO(%d)={%s}\n", - prefix, maxBufferCount, mSynchronousMode, mDefaultWidth, + prefix, maxBufferCount, mDequeueBufferCannotBlock, mDefaultWidth, mDefaultHeight, mDefaultBufferFormat, mTransformHint, fifoSize, fifo.string()); @@ -768,8 +764,6 @@ void BufferQueue::freeBufferLocked(int slot) { } void BufferQueue::freeAllBuffersLocked() { - ALOGD_IF(!mQueue.isEmpty(), - "freeAllBuffersLocked called with non-empty mQueue"); mBufferHasBeenQueued = false; for (int i = 0; i < NUM_BUFFER_SLOTS; i++) { freeBufferLocked(i); @@ -1024,36 +1018,8 @@ status_t BufferQueue::setMaxAcquiredBufferCount(int maxAcquiredBuffers) { return NO_ERROR; } -status_t BufferQueue::drainQueueLocked() { - while (mSynchronousMode && mQueue.size() > 1) { - mDequeueCondition.wait(mMutex); - if (mAbandoned) { - ST_LOGE("drainQueueLocked: BufferQueue has been abandoned!"); - return NO_INIT; - } - if (mConnectedApi == NO_CONNECTED_API) { - ST_LOGE("drainQueueLocked: BufferQueue is not connected!"); - return NO_INIT; - } - } - return NO_ERROR; -} - -status_t BufferQueue::drainQueueAndFreeBuffersLocked() { - status_t err = drainQueueLocked(); - if (err == NO_ERROR) { - freeAllBuffersLocked(); - } - return err; -} - int BufferQueue::getMinMaxBufferCountLocked() const { - return getMinUndequeuedBufferCountLocked() + 1; -} - -int BufferQueue::getMinUndequeuedBufferCountLocked() const { - return mSynchronousMode ? mMaxAcquiredBufferCount : - mMaxAcquiredBufferCount + 1; + return mMinUndequeuedBufferCount + 1; } int BufferQueue::getMaxBufferCountLocked() const { diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index c55b02aa21..953f6f91dc 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -83,9 +83,7 @@ TEST_F(SurfaceTest, QueuesToWindowComposerIsTrueWhenPurgatorized) { } // This test probably doesn't belong here. -// DISABLED because it hangs when disconnecting because of draining the queue. -// will be fixed in a subsequent BQ change -TEST_F(SurfaceTest, DISABLED_ScreenshotsOfProtectedBuffersSucceed) { +TEST_F(SurfaceTest, ScreenshotsOfProtectedBuffersSucceed) { sp anw(mSurface); // Verify the screenshot works with no protected buffers. -- cgit v1.2.3-59-g8ed1b From 7cdd786fa80cf03551291ae8feca7b77583be1c5 Mon Sep 17 00:00:00 2001 From: Mathias Agopian Date: Thu, 18 Jul 2013 22:10:56 -0700 Subject: Make ANW.setSwapInterval(0) work again we can now queue/dequeue a buffer in asynchrnous mode by using the async parameter to these calls. async mode is only specified with those calls (it is not modal anymore). as a consequence it can only be specified when the buffer count is not overidden, as error is returned otherwise. Change-Id: Ic63f4f96f671cb9d65c4cecbcc192615e09a8b6b --- include/gui/BufferQueue.h | 24 +++--- include/gui/IGraphicBufferProducer.h | 17 ++-- include/gui/Surface.h | 4 + libs/gui/BufferQueue.cpp | 91 ++++++++++++++-------- libs/gui/IGraphicBufferProducer.cpp | 9 ++- libs/gui/Surface.cpp | 12 ++- libs/gui/tests/BufferQueue_test.cpp | 6 +- libs/gui/tests/SurfaceTextureClient_test.cpp | 6 -- .../DisplayHardware/VirtualDisplaySurface.cpp | 15 ++-- .../DisplayHardware/VirtualDisplaySurface.h | 4 +- 10 files changed, 113 insertions(+), 75 deletions(-) (limited to 'libs/gui/BufferQueue.cpp') diff --git a/include/gui/BufferQueue.h b/include/gui/BufferQueue.h index b968287cac..628678f604 100644 --- a/include/gui/BufferQueue.h +++ b/include/gui/BufferQueue.h @@ -167,7 +167,7 @@ public: // // In both cases, the producer will need to call requestBuffer to get a // GraphicBuffer handle for the returned slot. - virtual status_t dequeueBuffer(int *buf, sp* fence, + virtual status_t dequeueBuffer(int *buf, sp* fence, bool async, uint32_t width, uint32_t height, uint32_t format, uint32_t usage); // queueBuffer returns a filled buffer to the BufferQueue. @@ -229,7 +229,7 @@ public: mTimestamp(0), mFrameNumber(0), mBuf(INVALID_BUFFER_SLOT), - mDequeueBufferCannotBlock(false), + mIsDroppable(false), mAcquireCalled(false) { mCrop.makeInvalid(); } @@ -260,12 +260,12 @@ public: // mFence is a fence that will signal when the buffer is idle. sp mFence; - // mDequeueBufferCannotBlock whether this buffer was queued with the + // mIsDroppable whether this buffer was queued with the // property that it can be replaced by a new buffer for the purpose of // making sure dequeueBuffer() won't block. // i.e.: was the BufferQueue in "mDequeueBufferCannotBlock" when this buffer // was queued. - bool mDequeueBufferCannotBlock; + bool mIsDroppable; // Indicates whether this buffer has been seen by a consumer yet bool mAcquireCalled; @@ -379,9 +379,15 @@ private: // The initial default is 2. status_t setDefaultMaxBufferCountLocked(int count); + // getMinUndequeuedBufferCount returns the minimum number of buffers + // that must remain in a state other than DEQUEUED. + // The async parameter tells whether we're in asynchronous mode. + int getMinUndequeuedBufferCount(bool async) const; + // getMinBufferCountLocked returns the minimum number of buffers allowed // given the current BufferQueue state. - int getMinMaxBufferCountLocked() const; + // The async parameter tells whether we're in asynchronous mode. + int getMinMaxBufferCountLocked(bool async) const; // getMaxBufferCountLocked returns the maximum number of buffers that can // be allocated at once. This value depends upon the following member @@ -391,10 +397,11 @@ private: // mMaxAcquiredBufferCount // mDefaultMaxBufferCount // mOverrideMaxBufferCount + // async parameter // // Any time one of these member variables is changed while a producer is // connected, mDequeueCondition must be broadcast. - int getMaxBufferCountLocked() const; + int getMaxBufferCountLocked(bool async) const; // stillTracking returns true iff the buffer item is still being tracked // in one of the slots. @@ -516,11 +523,6 @@ private: // in dequeueBuffer() if a width and height of zero is specified. uint32_t mDefaultHeight; - // mMinUndequeuedBufferCount holds the minimum number of buffers - // that must remain in a state other than DEQUEUED. - // This value cannot change while connected. - int mMinUndequeuedBufferCount; - // mMaxAcquiredBufferCount is the number of buffers that the consumer may // acquire at one time. It defaults to 1 and can be changed by the // consumer via the setMaxAcquiredBufferCount method, but this may only be diff --git a/include/gui/IGraphicBufferProducer.h b/include/gui/IGraphicBufferProducer.h index af5fcfc79b..9677962a59 100644 --- a/include/gui/IGraphicBufferProducer.h +++ b/include/gui/IGraphicBufferProducer.h @@ -84,7 +84,10 @@ public: // the buffer. The contents of the buffer must not be overwritten until the // fence signals. If the fence is NULL, the buffer may be written // immediately. - virtual status_t dequeueBuffer(int *slot, sp* fence, + // + // The async parameter sets whether we're in asynchrnous mode for this + // deququeBuffer() call. + virtual status_t dequeueBuffer(int *slot, sp* fence, bool async, uint32_t w, uint32_t h, uint32_t format, uint32_t usage) = 0; // queueBuffer indicates that the client has finished filling in the @@ -96,6 +99,8 @@ public: // must be monotonically increasing. Its other properties (zero point, etc) // are client-dependent, and should be documented by the client. // + // The async parameter sets whether we're queuing a buffer in asynchronous mode. + // // outWidth, outHeight and outTransform are filled with the default width // and height of the window and current transform applied to buffers, // respectively. @@ -103,17 +108,18 @@ public: struct QueueBufferInput : public Flattenable { inline QueueBufferInput(const Parcel& parcel); inline QueueBufferInput(int64_t timestamp, - const Rect& crop, int scalingMode, uint32_t transform, - sp fence) + const Rect& crop, int scalingMode, uint32_t transform, bool async, + const sp& fence) : timestamp(timestamp), crop(crop), scalingMode(scalingMode), - transform(transform), fence(fence) { } + transform(transform), async(async), fence(fence) { } inline void deflate(int64_t* outTimestamp, Rect* outCrop, - int* outScalingMode, uint32_t* outTransform, + int* outScalingMode, uint32_t* outTransform, bool* outAsync, sp* outFence) const { *outTimestamp = timestamp; *outCrop = crop; *outScalingMode = scalingMode; *outTransform = transform; + *outAsync = bool(async); *outFence = fence; } @@ -130,6 +136,7 @@ public: Rect crop; int scalingMode; uint32_t transform; + int async; sp fence; }; diff --git a/include/gui/Surface.h b/include/gui/Surface.h index 6f12e77113..2f7406e2bf 100644 --- a/include/gui/Surface.h +++ b/include/gui/Surface.h @@ -235,6 +235,10 @@ private: // by the application bool mProducerControlledByApp; + // mSwapIntervalZero set if we should drop buffers at queue() time to + // achieve an asynchronous swap interval + bool mSwapIntervalZero; + // mConsumerRunningBehind whether the consumer is running more than // one buffer behind the producer. mutable bool mConsumerRunningBehind; diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp index f99bd29bd5..cf8143135e 100644 --- a/libs/gui/BufferQueue.cpp +++ b/libs/gui/BufferQueue.cpp @@ -30,6 +30,7 @@ #include #include +#include // Macros for including the BufferQueue name in log messages #define ST_LOGV(x, ...) ALOGV("[%s] "x, mConsumerName.string(), ##__VA_ARGS__) @@ -150,21 +151,21 @@ status_t BufferQueue::setBufferCount(int bufferCount) { } // Error out if the user has dequeued buffers - int maxBufferCount = getMaxBufferCountLocked(); - for (int i=0 ; i= 2); @@ -229,15 +230,11 @@ status_t BufferQueue::requestBuffer(int slot, sp* buf) { ST_LOGE("requestBuffer: BufferQueue has been abandoned!"); return NO_INIT; } - int maxBufferCount = getMaxBufferCountLocked(); - if (slot < 0 || maxBufferCount <= slot) { + if (slot < 0 || slot >= NUM_BUFFER_SLOTS) { ST_LOGE("requestBuffer: slot index out of range [0, %d]: %d", - maxBufferCount, slot); + NUM_BUFFER_SLOTS, slot); return BAD_VALUE; } else if (mSlots[slot].mBufferState != BufferSlot::DEQUEUED) { - // XXX: I vaguely recall there was some reason this can be valid, but - // for the life of me I can't recall under what circumstances that's - // the case. ST_LOGE("requestBuffer: slot %d is not owned by the client (state=%d)", slot, mSlots[slot].mBufferState); return BAD_VALUE; @@ -247,7 +244,7 @@ status_t BufferQueue::requestBuffer(int slot, sp* buf) { return NO_ERROR; } -status_t BufferQueue::dequeueBuffer(int *outBuf, sp* outFence, +status_t BufferQueue::dequeueBuffer(int *outBuf, sp* outFence, bool async, 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); @@ -279,7 +276,16 @@ status_t BufferQueue::dequeueBuffer(int *outBuf, sp* outFence, return NO_INIT; } - const int maxBufferCount = getMaxBufferCountLocked(); + const int maxBufferCount = getMaxBufferCountLocked(async); + if (async && mOverrideMaxBufferCount) { + // FIXME: some drivers are manually setting the buffer-count (which they + // shouldn't), so we do this extra test here to handle that case. + // This is TEMPORARY, until we get this fixed. + if (mOverrideMaxBufferCount < maxBufferCount) { + ST_LOGE("dequeueBuffer: async mode is invalid with buffercount override"); + return BAD_VALUE; + } + } // Free up any buffers that are in slots beyond the max buffer // count. @@ -328,7 +334,7 @@ status_t BufferQueue::dequeueBuffer(int *outBuf, sp* outFence, // make sure the client is not trying to dequeue more buffers // than allowed. const int newUndequeuedCount = maxBufferCount - (dequeuedCount+1); - const int minUndequeuedCount = mMinUndequeuedBufferCount; + const int minUndequeuedCount = getMinUndequeuedBufferCount(async); if (newUndequeuedCount < minUndequeuedCount) { ST_LOGE("dequeueBuffer: min undequeued buffer count (%d) " "exceeded (dequeued=%d undequeudCount=%d)", @@ -448,9 +454,10 @@ status_t BufferQueue::queueBuffer(int buf, uint32_t transform; int scalingMode; int64_t timestamp; + bool async; sp fence; - input.deflate(×tamp, &crop, &scalingMode, &transform, &fence); + input.deflate(×tamp, &crop, &scalingMode, &transform, &async, &fence); if (fence == NULL) { ST_LOGE("queueBuffer: fence is NULL"); @@ -477,7 +484,17 @@ status_t BufferQueue::queueBuffer(int buf, ST_LOGE("queueBuffer: BufferQueue has been abandoned!"); return NO_INIT; } - int maxBufferCount = getMaxBufferCountLocked(); + + const int maxBufferCount = getMaxBufferCountLocked(async); + if (async && mOverrideMaxBufferCount) { + // FIXME: some drivers are manually setting the buffer-count (which they + // shouldn't), so we do this extra test here to handle that case. + // This is TEMPORARY, until we get this fixed. + if (mOverrideMaxBufferCount < maxBufferCount) { + ST_LOGE("queueBuffer: async mode is invalid with buffercount override"); + return BAD_VALUE; + } + } if (buf < 0 || buf >= maxBufferCount) { ST_LOGE("queueBuffer: slot index out of range [0, %d]: %d", maxBufferCount, buf); @@ -523,7 +540,7 @@ status_t BufferQueue::queueBuffer(int buf, item.mFrameNumber = mFrameCounter; item.mBuf = buf; item.mFence = fence; - item.mDequeueBufferCannotBlock = mDequeueBufferCannotBlock; + item.mIsDroppable = mDequeueBufferCannotBlock || async; if (mQueue.empty()) { // when the queue is empty, we can ignore "mDequeueBufferCannotBlock", and @@ -534,7 +551,7 @@ status_t BufferQueue::queueBuffer(int buf, // when the queue is not empty, we need to look at the front buffer // state and see if we need to replace it. Fifo::iterator front(mQueue.begin()); - if (front->mDequeueBufferCannotBlock) { + if (front->mIsDroppable) { // buffer slot currently queued is marked free if still tracked if (stillTracking(front)) { mSlots[front->mBuf].mBufferState = BufferSlot::FREE; @@ -573,10 +590,9 @@ void BufferQueue::cancelBuffer(int buf, const sp& fence) { return; } - int maxBufferCount = getMaxBufferCountLocked(); - if (buf < 0 || buf >= maxBufferCount) { + if (buf < 0 || buf >= NUM_BUFFER_SLOTS) { ST_LOGE("cancelBuffer: slot index out of range [0, %d]: %d", - maxBufferCount, buf); + NUM_BUFFER_SLOTS, buf); return; } else if (mSlots[buf].mBufferState != BufferSlot::DEQUEUED) { ST_LOGE("cancelBuffer: slot %d is not owned by the client (state=%d)", @@ -630,8 +646,6 @@ status_t BufferQueue::connect(int api, bool producerControlledByApp, QueueBuffer mBufferHasBeenQueued = false; mDequeueBufferCannotBlock = mConsumerControlledByApp && producerControlledByApp; - mMinUndequeuedBufferCount = mDequeueBufferCannotBlock ? - mMaxAcquiredBufferCount+1 : mMaxAcquiredBufferCount; return err; } @@ -704,12 +718,11 @@ void BufferQueue::dump(String8& result, const char* prefix) const { fifoSize++; } - int maxBufferCount = getMaxBufferCountLocked(); result.appendFormat( - "%s-BufferQueue maxBufferCount=%d, mDequeueBufferCannotBlock=%d, default-size=[%dx%d], " + "%s-BufferQueue mMaxAcquiredBufferCount=%d, mDequeueBufferCannotBlock=%d, default-size=[%dx%d], " "default-format=%d, transform-hint=%02x, FIFO(%d)={%s}\n", - prefix, maxBufferCount, mDequeueBufferCannotBlock, mDefaultWidth, + prefix, mMaxAcquiredBufferCount, mDequeueBufferCannotBlock, mDefaultWidth, mDefaultHeight, mDefaultBufferFormat, mTransformHint, fifoSize, fifo.string()); @@ -725,16 +738,25 @@ void BufferQueue::dump(String8& result, const char* prefix) const { } } stateName; + // just trim the free buffers to not spam the dump + int maxBufferCount = 0; + for (int i=NUM_BUFFER_SLOTS-1 ; i>=0 ; i--) { + const BufferSlot& slot(mSlots[i]); + if ((slot.mBufferState != BufferSlot::FREE) || (slot.mGraphicBuffer != NULL)) { + maxBufferCount = i+1; + break; + } + } + for (int i=0 ; i& buf(slot.mGraphicBuffer); result.appendFormat( "%s%s[%02d:%p] state=%-8s", - prefix, (slot.mBufferState == BufferSlot::ACQUIRED)?">":" ", i, - slot.mGraphicBuffer.get(), + prefix, (slot.mBufferState == BufferSlot::ACQUIRED)?">":" ", i, buf.get(), stateName(slot.mBufferState) ); - const sp& buf(slot.mGraphicBuffer); if (buf != NULL) { result.appendFormat( ", %p [%4ux%4u:%4u,%3X]", @@ -1018,12 +1040,17 @@ status_t BufferQueue::setMaxAcquiredBufferCount(int maxAcquiredBuffers) { return NO_ERROR; } -int BufferQueue::getMinMaxBufferCountLocked() const { - return mMinUndequeuedBufferCount + 1; +int BufferQueue::getMinUndequeuedBufferCount(bool async) const { + return (mDequeueBufferCannotBlock || async) ? + mMaxAcquiredBufferCount+1 : mMaxAcquiredBufferCount; +} + +int BufferQueue::getMinMaxBufferCountLocked(bool async) const { + return getMinUndequeuedBufferCount(async) + 1; } -int BufferQueue::getMaxBufferCountLocked() const { - int minMaxBufferCount = getMinMaxBufferCountLocked(); +int BufferQueue::getMaxBufferCountLocked(bool async) const { + int minMaxBufferCount = getMinMaxBufferCountLocked(async); int maxBufferCount = mDefaultMaxBufferCount; if (maxBufferCount < minMaxBufferCount) { diff --git a/libs/gui/IGraphicBufferProducer.cpp b/libs/gui/IGraphicBufferProducer.cpp index 9f65fc3f2b..2e561dfc29 100644 --- a/libs/gui/IGraphicBufferProducer.cpp +++ b/libs/gui/IGraphicBufferProducer.cpp @@ -80,10 +80,11 @@ public: return result; } - virtual status_t dequeueBuffer(int *buf, sp* fence, + virtual status_t dequeueBuffer(int *buf, sp* fence, bool async, uint32_t w, uint32_t h, uint32_t format, uint32_t usage) { Parcel data, reply; data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor()); + data.writeInt32(async); data.writeInt32(w); data.writeInt32(h); data.writeInt32(format); @@ -197,13 +198,14 @@ status_t BnGraphicBufferProducer::onTransact( } break; case DEQUEUE_BUFFER: { CHECK_INTERFACE(IGraphicBufferProducer, data, reply); + bool async = data.readInt32(); uint32_t w = data.readInt32(); uint32_t h = data.readInt32(); uint32_t format = data.readInt32(); uint32_t usage = data.readInt32(); int buf; sp fence; - int result = dequeueBuffer(&buf, &fence, w, h, format, usage); + int result = dequeueBuffer(&buf, &fence, async, w, h, format, usage); reply->writeInt32(buf); reply->writeInt32(fence != NULL); if (fence != NULL) { @@ -274,6 +276,7 @@ size_t IGraphicBufferProducer::QueueBufferInput::getFlattenedSize() const + sizeof(crop) + sizeof(scalingMode) + sizeof(transform) + + sizeof(async) + fence->getFlattenedSize(); } @@ -291,6 +294,7 @@ status_t IGraphicBufferProducer::QueueBufferInput::flatten(void* buffer, size_t 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, &async, sizeof(async)); p += sizeof(async); err = fence->flatten(p, size - (p - (char*)buffer), fds, count); return err; } @@ -304,6 +308,7 @@ status_t IGraphicBufferProducer::QueueBufferInput::unflatten(void const* buffer, 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(&async, p, sizeof(async)); p += sizeof(async); fence = new Fence(); err = fence->unflatten(p, size - (p - (const char*)buffer), fds, count); return err; diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp index 0d4449af65..998ea8ac8c 100644 --- a/libs/gui/Surface.cpp +++ b/libs/gui/Surface.cpp @@ -73,6 +73,7 @@ Surface::Surface( mConsumerRunningBehind = false; mConnectedToCpu = false; mProducerControlledByApp = true; + mSwapIntervalZero = false; } Surface::~Surface() { @@ -162,7 +163,6 @@ int Surface::setSwapInterval(int interval) { // 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; @@ -170,11 +170,9 @@ int Surface::setSwapInterval(int interval) { if (interval > maxSwapInterval) interval = maxSwapInterval; - // FIXME: re-implement swap-interval - //status_t res = mGraphicBufferProducer->setSynchronousMode(interval ? true : false); - status_t res = NO_ERROR; + mSwapIntervalZero = (interval == 0); - return res; + return NO_ERROR; } int Surface::dequeueBuffer(android_native_buffer_t** buffer, @@ -186,7 +184,7 @@ int Surface::dequeueBuffer(android_native_buffer_t** buffer, int reqW = mReqWidth ? mReqWidth : mUserWidth; int reqH = mReqHeight ? mReqHeight : mUserHeight; sp fence; - status_t result = mGraphicBufferProducer->dequeueBuffer(&buf, &fence, + status_t result = mGraphicBufferProducer->dequeueBuffer(&buf, &fence, mSwapIntervalZero, reqW, reqH, mReqFormat, mReqUsage); if (result < 0) { ALOGV("dequeueBuffer: IGraphicBufferProducer::dequeueBuffer(%d, %d, %d, %d)" @@ -282,7 +280,7 @@ int Surface::queueBuffer(android_native_buffer_t* buffer, int fenceFd) { sp fence(fenceFd >= 0 ? new Fence(fenceFd) : Fence::NO_FENCE); IGraphicBufferProducer::QueueBufferOutput output; IGraphicBufferProducer::QueueBufferInput input(timestamp, crop, mScalingMode, - mTransform, fence); + mTransform, mSwapIntervalZero, fence); status_t err = mGraphicBufferProducer->queueBuffer(i, input, &output); if (err != OK) { ALOGE("queueBuffer: error queuing buffer to SurfaceTexture, %d", err); diff --git a/libs/gui/tests/BufferQueue_test.cpp b/libs/gui/tests/BufferQueue_test.cpp index 1f8e7fa0db..b691fc111f 100644 --- a/libs/gui/tests/BufferQueue_test.cpp +++ b/libs/gui/tests/BufferQueue_test.cpp @@ -71,12 +71,12 @@ TEST_F(BufferQueueTest, AcquireBuffer_ExceedsMaxAcquireCount_Fails) { sp fence; sp buf; IGraphicBufferProducer::QueueBufferInput qbi(0, Rect(0, 0, 1, 1), - NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, Fence::NO_FENCE); + NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, false, Fence::NO_FENCE); BufferQueue::BufferItem item; for (int i = 0; i < 2; i++) { ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, - mBQ->dequeueBuffer(&slot, &fence, 1, 1, 0, + mBQ->dequeueBuffer(&slot, &fence, false, 1, 1, 0, GRALLOC_USAGE_SW_READ_OFTEN)); ASSERT_EQ(OK, mBQ->requestBuffer(slot, &buf)); ASSERT_EQ(OK, mBQ->queueBuffer(slot, qbi, &qbo)); @@ -84,7 +84,7 @@ TEST_F(BufferQueueTest, AcquireBuffer_ExceedsMaxAcquireCount_Fails) { } ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, - mBQ->dequeueBuffer(&slot, &fence, 1, 1, 0, + mBQ->dequeueBuffer(&slot, &fence, false, 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/SurfaceTextureClient_test.cpp b/libs/gui/tests/SurfaceTextureClient_test.cpp index 9908cc9db5..158c94b696 100644 --- a/libs/gui/tests/SurfaceTextureClient_test.cpp +++ b/libs/gui/tests/SurfaceTextureClient_test.cpp @@ -361,7 +361,6 @@ TEST_F(SurfaceTextureClientTest, SurfaceTextureTooManyUpdateTexImage) { TEST_F(SurfaceTextureClientTest, SurfaceTextureSyncModeSlowRetire) { android_native_buffer_t* buf[3]; - ASSERT_EQ(OK, mANW->setSwapInterval(mANW.get(), 1)); ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 4)); ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[0])); ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[1])); @@ -382,7 +381,6 @@ TEST_F(SurfaceTextureClientTest, SurfaceTextureSyncModeSlowRetire) { TEST_F(SurfaceTextureClientTest, SurfaceTextureSyncModeFastRetire) { android_native_buffer_t* buf[3]; - ASSERT_EQ(OK, mANW->setSwapInterval(mANW.get(), 1)); ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 4)); ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[0])); ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[1])); @@ -403,7 +401,6 @@ TEST_F(SurfaceTextureClientTest, SurfaceTextureSyncModeFastRetire) { TEST_F(SurfaceTextureClientTest, SurfaceTextureSyncModeDQQR) { android_native_buffer_t* buf[3]; - ASSERT_EQ(OK, mANW->setSwapInterval(mANW.get(), 1)); ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 3)); ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[0])); @@ -429,7 +426,6 @@ TEST_F(SurfaceTextureClientTest, SurfaceTextureSyncModeDQQR) { TEST_F(SurfaceTextureClientTest, DISABLED_SurfaceTextureSyncModeDequeueCurrent) { android_native_buffer_t* buf[3]; android_native_buffer_t* firstBuf; - ASSERT_EQ(OK, mANW->setSwapInterval(mANW.get(), 1)); ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 3)); ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &firstBuf)); ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), firstBuf, -1)); @@ -449,7 +445,6 @@ TEST_F(SurfaceTextureClientTest, DISABLED_SurfaceTextureSyncModeDequeueCurrent) TEST_F(SurfaceTextureClientTest, SurfaceTextureSyncModeMinUndequeued) { android_native_buffer_t* buf[3]; - ASSERT_EQ(OK, mANW->setSwapInterval(mANW.get(), 1)); ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 3)); // We should be able to dequeue all the buffers before we've queued mANWy. @@ -528,7 +523,6 @@ TEST_F(SurfaceTextureClientTest, DISABLED_SurfaceTextureSyncModeWaitRetire) { }; android_native_buffer_t* buf[3]; - ASSERT_EQ(OK, mANW->setSwapInterval(mANW.get(), 1)); ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 3)); // dequeue/queue/update so we have a current buffer ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[0])); diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp index c92b66654e..57cb361710 100644 --- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp +++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp @@ -126,7 +126,7 @@ status_t VirtualDisplaySurface::advanceFrame() { mQueueBufferOutput.deflate(&mSinkBufferWidth, &mSinkBufferHeight, &transformHint, &numPendingBuffers); int sslot; - result = dequeueBuffer(SOURCE_SINK, 0, &sslot, &outFence); + result = dequeueBuffer(SOURCE_SINK, 0, &sslot, &outFence, false); if (result < 0) return result; mOutputProducerSlot = mapSource2ProducerSlot(SOURCE_SINK, sslot); @@ -196,7 +196,7 @@ void VirtualDisplaySurface::onFrameCommitted() { status_t result = mSource[SOURCE_SINK]->queueBuffer(sslot, QueueBufferInput(systemTime(), Rect(mSinkBufferWidth, mSinkBufferHeight), - NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, outFence), + NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, false, outFence), &qbo); if (result == NO_ERROR) { updateQueueBufferOutput(qbo); @@ -224,8 +224,8 @@ status_t VirtualDisplaySurface::setBufferCount(int bufferCount) { } status_t VirtualDisplaySurface::dequeueBuffer(Source source, - uint32_t format, int* sslot, sp* fence) { - status_t result = mSource[source]->dequeueBuffer(sslot, fence, + uint32_t format, int* sslot, sp* fence, bool async) { + status_t result = mSource[source]->dequeueBuffer(sslot, fence, async, mSinkBufferWidth, mSinkBufferHeight, format, mProducerUsage); if (result < 0) return result; @@ -257,7 +257,7 @@ status_t VirtualDisplaySurface::dequeueBuffer(Source source, return result; } -status_t VirtualDisplaySurface::dequeueBuffer(int* pslot, sp* fence, +status_t VirtualDisplaySurface::dequeueBuffer(int* pslot, sp* fence, bool async, uint32_t w, uint32_t h, uint32_t format, uint32_t usage) { VDS_LOGW_IF(mDbgState != DBG_STATE_PREPARED, "Unexpected dequeueBuffer() in %s state", dbgStateStr()); @@ -273,7 +273,7 @@ status_t VirtualDisplaySurface::dequeueBuffer(int* pslot, sp* fence, } int sslot; - status_t result = dequeueBuffer(source, format, &sslot, fence); + status_t result = dequeueBuffer(source, format, &sslot, fence, async); if (result >= 0) { *pslot = mapSource2ProducerSlot(source, sslot); } @@ -321,8 +321,9 @@ status_t VirtualDisplaySurface::queueBuffer(int pslot, Rect crop; int scalingMode; uint32_t transform; + bool async; input.deflate(×tamp, &crop, &scalingMode, &transform, - &mFbFence); + &async, &mFbFence); mFbProducerSlot = pslot; } diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h index 94b24d2e1f..dc9655b626 100644 --- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h +++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h @@ -95,7 +95,7 @@ private: // virtual status_t requestBuffer(int pslot, sp* outBuf); virtual status_t setBufferCount(int bufferCount); - virtual status_t dequeueBuffer(int* pslot, sp* fence, + virtual status_t dequeueBuffer(int* pslot, sp* fence, bool async, uint32_t w, uint32_t h, uint32_t format, uint32_t usage); virtual status_t queueBuffer(int pslot, const QueueBufferInput& input, QueueBufferOutput* output); @@ -109,7 +109,7 @@ private: // static Source fbSourceForCompositionType(CompositionType type); status_t dequeueBuffer(Source source, uint32_t format, - int* sslot, sp* fence); + int* sslot, sp* fence, bool async); void updateQueueBufferOutput(const QueueBufferOutput& qbo); void resetPerFrameState(); -- cgit v1.2.3-59-g8ed1b From 26a6f37cc06b8014edcedbee8d5558ca7da9abe3 Mon Sep 17 00:00:00 2001 From: Mathias Agopian Date: Thu, 18 Jul 2013 22:25:55 -0700 Subject: make sure to reset the framenumber when a buffer is marked FREE Change-Id: Ic45929f35553de209801f74e8006fb1bf0b25b45 --- libs/gui/BufferQueue.cpp | 3 +++ 1 file changed, 3 insertions(+) (limited to 'libs/gui/BufferQueue.cpp') diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp index cf8143135e..73bd4888ba 100644 --- a/libs/gui/BufferQueue.cpp +++ b/libs/gui/BufferQueue.cpp @@ -555,6 +555,9 @@ status_t BufferQueue::queueBuffer(int buf, // buffer slot currently queued is marked free if still tracked if (stillTracking(front)) { mSlots[front->mBuf].mBufferState = BufferSlot::FREE; + // reset the frame number of the freed buffer so that it is the first in + // line to be dequeued again. + mSlots[front->mBuf].mFrameNumber = 0; } // and we record the new buffer in the queued list *front = item; -- cgit v1.2.3-59-g8ed1b From 207c1e287c129e7ebf679a3aaf2076c3c47c1afb Mon Sep 17 00:00:00 2001 From: Mathias Agopian Date: Mon, 22 Jul 2013 18:00:53 -0700 Subject: fix log messages and bogus error message also assert when releasing a buffer and it has been queued Change-Id: I6f78d9ceb406ec85ff46c7b6d0c047b14063e3d0 --- libs/gui/BufferQueue.cpp | 41 ++++++++++++++++++----------------------- 1 file changed, 18 insertions(+), 23 deletions(-) (limited to 'libs/gui/BufferQueue.cpp') diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp index 73bd4888ba..ad2f1bb618 100644 --- a/libs/gui/BufferQueue.cpp +++ b/libs/gui/BufferQueue.cpp @@ -843,13 +843,13 @@ status_t BufferQueue::acquireBuffer(BufferItem *buffer, nsecs_t presentWhen) { if (presentWhen != 0 && desiredPresent > presentWhen && desiredPresent - presentWhen < MAX_FUTURE_NSEC) { - ALOGV("pts defer: des=%lld when=%lld (%lld) now=%lld", + ST_LOGV("pts defer: des=%lld when=%lld (%lld) now=%lld", desiredPresent, presentWhen, desiredPresent - presentWhen, systemTime(CLOCK_MONOTONIC)); return PRESENT_LATER; } if (presentWhen != 0) { - ALOGV("pts accept: %p[%d] sig=%lld des=%lld when=%lld (%lld)", + ST_LOGV("pts accept: %p[%d] sig=%lld des=%lld when=%lld (%lld)", mSlots, buf, mSlots[buf].mFence->getSignalTime(), desiredPresent, presentWhen, desiredPresent - presentWhen); } @@ -889,35 +889,31 @@ status_t BufferQueue::releaseBuffer( ATRACE_CALL(); ATRACE_BUFFER_INDEX(buf); - Mutex::Autolock _l(mMutex); - if (buf == INVALID_BUFFER_SLOT || fence == NULL) { return BAD_VALUE; } - // Check if this buffer slot is on the queue - bool slotQueued = false; - Fifo::iterator front(mQueue.begin()); - while (front != mQueue.end() && !slotQueued) { - if (front->mBuf == buf) - slotQueued = true; - front++; - } + Mutex::Autolock _l(mMutex); // If the frame number has changed because buffer has been reallocated, // we can ignore this releaseBuffer for the old buffer. if (frameNumber != mSlots[buf].mFrameNumber) { - // This should only occur if new buffer is still in the queue - ALOGE_IF(!slotQueued, - "received old buffer(#%lld) after new buffer(#%lld) on same " - "slot #%d already acquired", frameNumber, - mSlots[buf].mFrameNumber, buf); return STALE_BUFFER_SLOT; } - // this should never happen - ALOGE_IF(slotQueued, - "received new buffer(#%lld) on slot #%d that has not yet been " - "acquired", frameNumber, buf); + + + // Internal state consistency checks: + // Make sure this buffers hasn't been queued while we were owning it (acquired) + Fifo::iterator front(mQueue.begin()); + Fifo::const_iterator const end(mQueue.end()); + while (front != end) { + if (front->mBuf == buf) { + LOG_ALWAYS_FATAL("[%s] received new buffer(#%lld) on slot #%d that has not yet been " + "acquired", mConsumerName.string(), frameNumber, buf); + break; // never reached + } + front++; + } // The buffer can now only be released if its in the acquired state if (mSlots[buf].mBufferState == BufferSlot::ACQUIRED) { @@ -1007,8 +1003,7 @@ status_t BufferQueue::getReleasedBuffers(uint32_t* slotMask) { return NO_ERROR; } -status_t BufferQueue::setDefaultBufferSize(uint32_t w, uint32_t h) -{ +status_t BufferQueue::setDefaultBufferSize(uint32_t w, uint32_t h) { ST_LOGV("setDefaultBufferSize: w=%d, h=%d", w, h); if (!w || !h) { ST_LOGE("setDefaultBufferSize: dimensions cannot be 0 (w=%d, h=%d)", -- cgit v1.2.3-59-g8ed1b From 6bac363cbdca7f5c4135d66c0e379475ecbd7319 Mon Sep 17 00:00:00 2001 From: Mathias Agopian Date: Tue, 23 Jul 2013 21:50:20 -0700 Subject: Fix a race in BufferQueue BufferQueue::dequeueBuffer() could incorrectly return WOULD_BLOCK while in "cannot block" mode if it happened while a consumer acquired the last allowed buffer before releasing the old one (which is a valid thing to do). Change-Id: I318e5408871ba85e068ea9ef4dc9b578f1bb1043 --- libs/gui/BufferQueue.cpp | 44 +++++++++++++++++++++++++++----------------- 1 file changed, 27 insertions(+), 17 deletions(-) (limited to 'libs/gui/BufferQueue.cpp') diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp index 73bd4888ba..320f4cf738 100644 --- a/libs/gui/BufferQueue.cpp +++ b/libs/gui/BufferQueue.cpp @@ -268,7 +268,6 @@ status_t BufferQueue::dequeueBuffer(int *outBuf, sp* outFence, bool async usage |= mConsumerUsageBits; int found = -1; - int dequeuedCount = 0; bool tryAgain = true; while (tryAgain) { if (mAbandoned) { @@ -299,23 +298,28 @@ status_t BufferQueue::dequeueBuffer(int *outBuf, sp* outFence, bool async // look for a free buffer to give to the client found = INVALID_BUFFER_SLOT; - dequeuedCount = 0; + int dequeuedCount = 0; + int acquiredCount = 0; for (int i = 0; i < maxBufferCount; i++) { const int state = mSlots[i].mBufferState; - if (state == BufferSlot::DEQUEUED) { - dequeuedCount++; - } - - if (state == BufferSlot::FREE) { - /* We return the oldest of the free buffers to avoid - * stalling the producer if possible. This is because - * the consumer may still have pending reads of the - * buffers in flight. - */ - if ((found < 0) || - mSlots[i].mFrameNumber < mSlots[found].mFrameNumber) { - found = i; - } + switch (state) { + case BufferSlot::DEQUEUED: + dequeuedCount++; + break; + case BufferSlot::ACQUIRED: + acquiredCount++; + break; + case BufferSlot::FREE: + /* We return the oldest of the free buffers to avoid + * stalling the producer if possible. This is because + * the consumer may still have pending reads of the + * buffers in flight. + */ + if ((found < 0) || + mSlots[i].mFrameNumber < mSlots[found].mFrameNumber) { + found = i; + } + break; } } @@ -348,7 +352,13 @@ status_t BufferQueue::dequeueBuffer(int *outBuf, sp* outFence, bool async // the max buffer count to change. tryAgain = found == INVALID_BUFFER_SLOT; if (tryAgain) { - if (mDequeueBufferCannotBlock) { + // return an error if we're in "cannot block" mode (producer and consumer + // are controlled by the application) -- however, the consumer is allowed + // to acquire briefly an extra buffer (which could cause us to have to wait here) + // and that's okay because we know the wait will be brief (it happens + // if we dequeue a buffer while the consumer has acquired one but not released + // the old one yet -- for e.g.: see GLConsumer::updateTexImage()). + if (mDequeueBufferCannotBlock && (acquiredCount <= mMaxAcquiredBufferCount)) { ST_LOGE("dequeueBuffer: would block! returning an error instead."); return WOULD_BLOCK; } -- cgit v1.2.3-59-g8ed1b From ad678e18b66f495efa78dc3b9ab99b579945c9e2 Mon Sep 17 00:00:00 2001 From: Mathias Agopian Date: Tue, 23 Jul 2013 17:28:53 -0700 Subject: single buffer mode for BufferQueue Bug: 9891035 Change-Id: Id1ab5f911a6dc4c1d8235e65775b3d3635231ad4 --- include/gui/BufferQueue.h | 14 +++- include/gui/GLConsumer.h | 13 ++- libs/gui/BufferQueue.cpp | 28 ++++++- libs/gui/GLConsumer.cpp | 95 ++++++++++++++++++++-- .../DisplayHardware/FramebufferSurface.cpp | 2 +- services/surfaceflinger/SurfaceFlingerConsumer.cpp | 2 +- 6 files changed, 140 insertions(+), 14 deletions(-) (limited to 'libs/gui/BufferQueue.cpp') diff --git a/include/gui/BufferQueue.h b/include/gui/BufferQueue.h index 628678f604..cfce40dce1 100644 --- a/include/gui/BufferQueue.h +++ b/include/gui/BufferQueue.h @@ -340,6 +340,13 @@ public: // The count must be between 2 and NUM_BUFFER_SLOTS, inclusive. status_t setDefaultMaxBufferCount(int bufferCount); + // disableAsyncBuffer disables the extra buffer used in async mode + // (when both producer and consumer have set their "isControlledByApp" + // flag) and has dequeueBuffer() return WOULD_BLOCK instead. + // + // This can only be called before consumerConnect(). + status_t disableAsyncBuffer(); + // setMaxAcquiredBufferCount sets the maximum number of buffers that can // be acquired by the consumer at one time (default 1). This call will // fail if a producer is connected to the BufferQueue. @@ -364,6 +371,7 @@ public: // NATIVE_WINDOW_TRANSFORM_ROT_90. The default is 0 (no transform). status_t setTransformHint(uint32_t hint); + private: // freeBufferLocked frees the GraphicBuffer and sync resources for the // given slot. @@ -559,10 +567,14 @@ private: bool mConsumerControlledByApp; // mDequeueBufferCannotBlock whether dequeueBuffer() isn't allowed to block. - // this flag is set durring connect() when both consumer and producer are controlled + // this flag is set during connect() when both consumer and producer are controlled // by the application. bool mDequeueBufferCannotBlock; + // mUseAsyncBuffer whether an extra buffer is used in async mode to prevent + // dequeueBuffer() from ever blocking. + bool mUseAsyncBuffer; + // mConnectedApi indicates the producer API that is currently connected // to this BufferQueue. It defaults to NO_CONNECTED_API (= 0), and gets // updated by the connect and disconnect methods. diff --git a/include/gui/GLConsumer.h b/include/gui/GLConsumer.h index 1df5b42a00..ac4a8328be 100644 --- a/include/gui/GLConsumer.h +++ b/include/gui/GLConsumer.h @@ -98,6 +98,13 @@ public: // This calls doGLFenceWait to ensure proper synchronization. status_t updateTexImage(); + // releaseTexImage releases the texture acquired in updateTexImage(). + // This is intended to be used in single buffer mode. + // + // This call may only be made while the OpenGL ES context to which the + // target texture belongs is bound to the calling thread. + status_t releaseTexImage(); + // setReleaseFence stores a fence that will signal when the current buffer // is no longer being read. This fence will be returned to the producer // when the current buffer is released by updateTexImage(). Multiple @@ -251,7 +258,7 @@ protected: // This releases the buffer in the slot referenced by mCurrentTexture, // then updates state to refer to the BufferItem, which must be a // newly-acquired buffer. - status_t releaseAndUpdateLocked(const BufferQueue::BufferItem& item); + status_t updateAndReleaseLocked(const BufferQueue::BufferItem& item); // Binds mTexName and the current buffer to mTexTarget. Uses // mCurrentTexture if it's set, mCurrentTextureBuf if not. If the @@ -416,6 +423,10 @@ private: // It is set to false by detachFromContext, and then set to true again by // attachToContext. bool mAttached; + + // mReleasedTexImageBuffer is a dummy buffer used when in single buffer + // mode and releaseTexImage() has been called + sp mReleasedTexImageBuffer; }; // ---------------------------------------------------------------------------- diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp index 95ba09528a..45488ff8d8 100644 --- a/libs/gui/BufferQueue.cpp +++ b/libs/gui/BufferQueue.cpp @@ -72,6 +72,7 @@ BufferQueue::BufferQueue(const sp& allocator) : mOverrideMaxBufferCount(0), mConsumerControlledByApp(false), mDequeueBufferCannotBlock(false), + mUseAsyncBuffer(true), mConnectedApi(NO_CONNECTED_API), mAbandoned(false), mFrameCounter(0), @@ -100,7 +101,8 @@ BufferQueue::~BufferQueue() { } status_t BufferQueue::setDefaultMaxBufferCountLocked(int count) { - if (count < 2 || count > NUM_BUFFER_SLOTS) + const int minBufferCount = mUseAsyncBuffer ? 2 : 1; + if (count < minBufferCount || count > NUM_BUFFER_SLOTS) return BAD_VALUE; mDefaultMaxBufferCount = count; @@ -1033,6 +1035,17 @@ status_t BufferQueue::setDefaultMaxBufferCount(int bufferCount) { return setDefaultMaxBufferCountLocked(bufferCount); } +status_t BufferQueue::disableAsyncBuffer() { + ATRACE_CALL(); + Mutex::Autolock lock(mMutex); + if (mConsumerListener != NULL) { + ST_LOGE("disableAsyncBuffer: consumer already connected!"); + return INVALID_OPERATION; + } + mUseAsyncBuffer = false; + return NO_ERROR; +} + status_t BufferQueue::setMaxAcquiredBufferCount(int maxAcquiredBuffers) { ATRACE_CALL(); Mutex::Autolock lock(mMutex); @@ -1049,8 +1062,17 @@ status_t BufferQueue::setMaxAcquiredBufferCount(int maxAcquiredBuffers) { } int BufferQueue::getMinUndequeuedBufferCount(bool async) const { - return (mDequeueBufferCannotBlock || async) ? - mMaxAcquiredBufferCount+1 : mMaxAcquiredBufferCount; + // if dequeueBuffer is allowed to error out, we don't have to + // add an extra buffer. + if (!mUseAsyncBuffer) + return mMaxAcquiredBufferCount; + + // we're in async mode, or we want to prevent the app to + // deadlock itself, we throw-in an extra buffer to guarantee it. + if (mDequeueBufferCannotBlock || async) + return mMaxAcquiredBufferCount+1; + + return mMaxAcquiredBufferCount; } int BufferQueue::getMinMaxBufferCountLocked(bool async) const { diff --git a/libs/gui/GLConsumer.cpp b/libs/gui/GLConsumer.cpp index bd1671d564..b8a3d286f3 100644 --- a/libs/gui/GLConsumer.cpp +++ b/libs/gui/GLConsumer.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include @@ -49,6 +50,12 @@ namespace android { #define ST_LOGW(x, ...) ALOGW("[%s] "x, mName.string(), ##__VA_ARGS__) #define ST_LOGE(x, ...) ALOGE("[%s] "x, mName.string(), ##__VA_ARGS__) +static const struct { + size_t width, height; + char const* bits; +} kDebugData = { 11, 8, + "__X_____X_____X___X_____XXXXXXX___XX_XXX_XX_XXXXXXXXXXXX_XXXXXXX_XX_X_____X_X___XX_XX___" }; + // Transform matrices static float mtxIdentity[16] = { 1, 0, 0, 0, @@ -154,7 +161,7 @@ status_t GLConsumer::updateTexImage() { } // Release the previous buffer. - err = releaseAndUpdateLocked(item); + err = updateAndReleaseLocked(item); if (err != NO_ERROR) { // We always bind the texture. glBindTexture(mTexTarget, mTexName); @@ -165,6 +172,80 @@ status_t GLConsumer::updateTexImage() { return bindTextureImageLocked(); } + +status_t GLConsumer::releaseTexImage() { + ATRACE_CALL(); + ST_LOGV("releaseTexImage"); + Mutex::Autolock lock(mMutex); + + if (mAbandoned) { + ST_LOGE("releaseTexImage: GLConsumer is abandoned!"); + return NO_INIT; + } + + // Make sure the EGL state is the same as in previous calls. + status_t err = checkAndUpdateEglStateLocked(); + if (err != NO_ERROR) { + return err; + } + + // Update the GLConsumer state. + int buf = mCurrentTexture; + if (buf != BufferQueue::INVALID_BUFFER_SLOT) { + + ST_LOGV("releaseTexImage:(slot=%d", buf); + + // Do whatever sync ops we need to do before releasing the slot. + err = syncForReleaseLocked(mEglDisplay); + if (err != NO_ERROR) { + ST_LOGE("syncForReleaseLocked failed (slot=%d), err=%d", buf, err); + return err; + } + + err = releaseBufferLocked(buf, mSlots[buf].mGraphicBuffer, + mEglDisplay, EGL_NO_SYNC_KHR); + if (err < NO_ERROR) { + ST_LOGE("releaseTexImage: failed to release buffer: %s (%d)", + strerror(-err), err); + return err; + } + + if (CC_UNLIKELY(mReleasedTexImageBuffer == NULL)) { + // The first time, create the debug texture in case the application + // continues to use it. + sp buffer = new GraphicBuffer(11, 8, PIXEL_FORMAT_RGBA_8888, + GraphicBuffer::USAGE_SW_WRITE_RARELY); + uint32_t* bits; + buffer->lock(GraphicBuffer::USAGE_SW_WRITE_RARELY, reinterpret_cast(&bits)); + size_t w = buffer->getStride(); + size_t h = buffer->getHeight(); + memset(bits, 0, w*h*4); + for (size_t y=0 ; yunlock(); + mReleasedTexImageBuffer = buffer; + } + + mCurrentTexture = BufferQueue::INVALID_BUFFER_SLOT; + mCurrentTextureBuf = mReleasedTexImageBuffer; + mCurrentCrop.makeInvalid(); + mCurrentTransform = 0; + mCurrentScalingMode = NATIVE_WINDOW_SCALING_MODE_FREEZE; + mCurrentTimestamp = 0; + mCurrentFence = Fence::NO_FENCE; + + // bind a dummy texture + glBindTexture(mTexTarget, mTexName); + bindUnslottedBufferLocked(mEglDisplay); + } + + return NO_ERROR; +} + status_t GLConsumer::acquireBufferLocked(BufferQueue::BufferItem *item, nsecs_t presentWhen) { status_t err = ConsumerBase::acquireBufferLocked(item, presentWhen); @@ -202,12 +283,12 @@ status_t GLConsumer::releaseBufferLocked(int buf, return err; } -status_t GLConsumer::releaseAndUpdateLocked(const BufferQueue::BufferItem& item) +status_t GLConsumer::updateAndReleaseLocked(const BufferQueue::BufferItem& item) { status_t err = NO_ERROR; if (!mAttached) { - ST_LOGE("releaseAndUpdate: GLConsumer is not attached to an OpenGL " + ST_LOGE("updateAndRelease: GLConsumer is not attached to an OpenGL " "ES context"); return INVALID_OPERATION; } @@ -230,7 +311,7 @@ status_t GLConsumer::releaseAndUpdateLocked(const BufferQueue::BufferItem& item) if (mEglSlots[buf].mEglImage == EGL_NO_IMAGE_KHR) { EGLImageKHR image = createImage(mEglDisplay, mSlots[buf].mGraphicBuffer); if (image == EGL_NO_IMAGE_KHR) { - ST_LOGW("releaseAndUpdate: unable to createImage on display=%p slot=%d", + ST_LOGW("updateAndRelease: unable to createImage on display=%p slot=%d", mEglDisplay, buf); return UNKNOWN_ERROR; } @@ -249,7 +330,7 @@ status_t GLConsumer::releaseAndUpdateLocked(const BufferQueue::BufferItem& item) return err; } - ST_LOGV("releaseAndUpdate: (slot=%d buf=%p) -> (slot=%d buf=%p)", + ST_LOGV("updateAndRelease: (slot=%d buf=%p) -> (slot=%d buf=%p)", mCurrentTexture, mCurrentTextureBuf != NULL ? mCurrentTextureBuf->handle : 0, buf, mSlots[buf].mGraphicBuffer->handle); @@ -259,8 +340,8 @@ status_t GLConsumer::releaseAndUpdateLocked(const BufferQueue::BufferItem& item) status_t status = releaseBufferLocked( mCurrentTexture, mCurrentTextureBuf, mEglDisplay, mEglSlots[mCurrentTexture].mEglFence); - if (status != NO_ERROR && status != BufferQueue::STALE_BUFFER_SLOT) { - ST_LOGE("releaseAndUpdate: failed to release buffer: %s (%d)", + if (status < NO_ERROR) { + ST_LOGE("updateAndRelease: failed to release buffer: %s (%d)", strerror(-status), status); err = status; // keep going, with error raised [?] diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp index bd2f5f36e7..419b81cd4f 100644 --- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp +++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp @@ -108,7 +108,7 @@ status_t FramebufferSurface::nextBuffer(sp& outBuffer, sp& // Release the previous buffer. err = releaseBufferLocked(mCurrentBufferSlot, mCurrentBuffer, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR); - if (err != NO_ERROR && err != BufferQueue::STALE_BUFFER_SLOT) { + if (err < NO_ERROR) { ALOGE("error releasing buffer: %s (%d)", strerror(-err), err); return err; } diff --git a/services/surfaceflinger/SurfaceFlingerConsumer.cpp b/services/surfaceflinger/SurfaceFlingerConsumer.cpp index b181b60724..e95e057bf6 100644 --- a/services/surfaceflinger/SurfaceFlingerConsumer.cpp +++ b/services/surfaceflinger/SurfaceFlingerConsumer.cpp @@ -76,7 +76,7 @@ status_t SurfaceFlingerConsumer::updateTexImage(BufferRejecter* rejecter) } // Release the previous buffer. - err = releaseAndUpdateLocked(item); + err = updateAndReleaseLocked(item); if (err != NO_ERROR) { return err; } -- cgit v1.2.3-59-g8ed1b From f7c6087bcc6a85cc82fd8dd83566550f880600ec Mon Sep 17 00:00:00 2001 From: Eino-Ville Talvala Date: Tue, 30 Jul 2013 14:05:02 -0700 Subject: BufferQueue: Support query of consumer usage bits Bug: 9592202 Change-Id: I61a17758200e61adaca695b426db3df0f6637d4c --- libs/gui/BufferQueue.cpp | 3 +++ libs/gui/tests/Surface_test.cpp | 18 ++++++++++++++++++ 2 files changed, 21 insertions(+) (limited to 'libs/gui/BufferQueue.cpp') diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp index 45488ff8d8..f09d558e85 100644 --- a/libs/gui/BufferQueue.cpp +++ b/libs/gui/BufferQueue.cpp @@ -217,6 +217,9 @@ int BufferQueue::query(int what, int* outValue) case NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND: value = (mQueue.size() >= 2); break; + case NATIVE_WINDOW_CONSUMER_USAGE_BITS: + value = mConsumerUsageBits; + break; default: return BAD_VALUE; } diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index 953f6f91dc..bcdbedbaac 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -132,4 +133,21 @@ TEST_F(SurfaceTest, ConcreteTypeIsSurface) { EXPECT_EQ(NATIVE_WINDOW_SURFACE, result); } +TEST_F(SurfaceTest, QueryConsumerUsage) { + const int TEST_USAGE_FLAGS = + GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_HW_RENDER; + sp bq = new BufferQueue(); + sp c = new BufferItemConsumer(bq, + TEST_USAGE_FLAGS); + sp s = new Surface(c->getProducerInterface()); + + sp anw(s); + + int flags = -1; + int err = anw->query(anw.get(), NATIVE_WINDOW_CONSUMER_USAGE_BITS, &flags); + + ASSERT_EQ(NO_ERROR, err); + ASSERT_EQ(TEST_USAGE_FLAGS, flags); +} + } -- cgit v1.2.3-59-g8ed1b From ba93b3f8e403636b614a4a379f9421bc70dca84f Mon Sep 17 00:00:00 2001 From: Mathias Agopian Date: Thu, 1 Aug 2013 15:48:40 -0700 Subject: log an error when dequeueBuffer gets a NULL Fence Bug: 9858745 Change-Id: If35d6a7d770bf0a42d55bc55880a9ddb721fcfd0 --- libs/gui/BufferQueue.cpp | 13 +++++++++---- libs/gui/IGraphicBufferProducer.cpp | 11 ++++------- libs/gui/Surface.cpp | 10 ++++++---- libs/gui/SurfaceComposerClient.cpp | 2 +- 4 files changed, 20 insertions(+), 16 deletions(-) (limited to 'libs/gui/BufferQueue.cpp') diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp index 45488ff8d8..e20ac86799 100644 --- a/libs/gui/BufferQueue.cpp +++ b/libs/gui/BufferQueue.cpp @@ -406,6 +406,13 @@ status_t BufferQueue::dequeueBuffer(int *outBuf, sp* outFence, bool async returnFlags |= IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION; } + + if (CC_UNLIKELY(mSlots[buf].mFence == NULL)) { + ST_LOGE("dequeueBuffer: about to return a NULL fence from mSlot. " + "buf=%d, w=%d, h=%d, format=%d", + buf, buffer->width, buffer->height, buffer->format); + } + dpy = mSlots[buf].mEglDisplay; eglFence = mSlots[buf].mEglFence; *outFence = mSlots[buf].mFence; @@ -416,11 +423,9 @@ status_t BufferQueue::dequeueBuffer(int *outBuf, sp* outFence, bool async if (returnFlags & IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION) { status_t error; sp graphicBuffer( - mGraphicBufferAlloc->createGraphicBuffer( - w, h, format, usage, &error)); + mGraphicBufferAlloc->createGraphicBuffer(w, h, format, usage, &error)); if (graphicBuffer == 0) { - ST_LOGE("dequeueBuffer: SurfaceComposer::createGraphicBuffer " - "failed"); + ST_LOGE("dequeueBuffer: SurfaceComposer::createGraphicBuffer failed"); return error; } diff --git a/libs/gui/IGraphicBufferProducer.cpp b/libs/gui/IGraphicBufferProducer.cpp index 48b28708f7..e3d2a20dfd 100644 --- a/libs/gui/IGraphicBufferProducer.cpp +++ b/libs/gui/IGraphicBufferProducer.cpp @@ -94,13 +94,10 @@ public: return result; } *buf = reply.readInt32(); - 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. + bool nonNull = reply.readInt32(); + if (nonNull) { *fence = new Fence(); - reply.read(*(fence->get())); + reply.read(**fence); } result = reply.readInt32(); return result; @@ -209,7 +206,7 @@ status_t BnGraphicBufferProducer::onTransact( reply->writeInt32(buf); reply->writeInt32(fence != NULL); if (fence != NULL) { - reply->write(*fence.get()); + reply->write(*fence); } reply->writeInt32(result); return NO_ERROR; diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp index 998ea8ac8c..fdb7d3d93d 100644 --- a/libs/gui/Surface.cpp +++ b/libs/gui/Surface.cpp @@ -175,8 +175,7 @@ int Surface::setSwapInterval(int interval) { return NO_ERROR; } -int Surface::dequeueBuffer(android_native_buffer_t** buffer, - int* fenceFd) { +int Surface::dequeueBuffer(android_native_buffer_t** buffer, int* fenceFd) { ATRACE_CALL(); ALOGV("Surface::dequeueBuffer"); Mutex::Autolock lock(mMutex); @@ -193,6 +192,10 @@ int Surface::dequeueBuffer(android_native_buffer_t** buffer, return result; } sp& gbuf(mSlots[buf].buffer); + + // this should never happen + ALOGE_IF(fence == NULL, "Surface::dequeueBuffer: received null Fence! buf=%d", buf); + if (result & IGraphicBufferProducer::RELEASE_ALL_BUFFERS) { freeAllBuffers(); } @@ -200,8 +203,7 @@ int Surface::dequeueBuffer(android_native_buffer_t** buffer, if ((result & IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION) || gbuf == 0) { result = mGraphicBufferProducer->requestBuffer(buf, &gbuf); if (result != NO_ERROR) { - ALOGE("dequeueBuffer: IGraphicBufferProducer::requestBuffer failed: %d", - result); + ALOGE("dequeueBuffer: IGraphicBufferProducer::requestBuffer failed: %d", result); return result; } } diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 94f21b6452..bad4138832 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -653,7 +653,7 @@ status_t ScreenshotClient::update(const sp& display, mHaveBuffer = false; } - status_t err = s->captureScreen(display,cpuConsumer->getBufferQueue(), + status_t err = s->captureScreen(display, cpuConsumer->getBufferQueue(), reqWidth, reqHeight, minLayerZ, maxLayerZ, true); if (err == NO_ERROR) { -- cgit v1.2.3-59-g8ed1b From 14fab7dd794cd6bf29e6425340683c6221062b3c Mon Sep 17 00:00:00 2001 From: Andy McFadden Date: Thu, 1 Aug 2013 13:37:42 -0700 Subject: Drop frames based on presentation timestamp If there are two or more buffers pending that are ready for immediate presentation, drop all but the last one. Any code that didn't explicitly specify timestamps for buffers was using the default value (auto-generated "now"). As a result, surfaceflinger would drop frames whenever more than one buffer was queued. We now use zero as the auto-generated timestamp, and we don't set the timestamp in eglBeginFrame(). Change-Id: I187f42d33de227cd3411ff0dcd3b9ce1961457eb --- libs/gui/BufferQueue.cpp | 96 ++++++++++++++++++++++++++++++++-------------- libs/gui/Surface.cpp | 4 +- opengl/libs/EGL/eglApi.cpp | 5 --- 3 files changed, 69 insertions(+), 36 deletions(-) (limited to 'libs/gui/BufferQueue.cpp') diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp index 45488ff8d8..e22679e499 100644 --- a/libs/gui/BufferQueue.cpp +++ b/libs/gui/BufferQueue.cpp @@ -807,7 +807,7 @@ void BufferQueue::freeAllBuffersLocked() { } } -status_t BufferQueue::acquireBuffer(BufferItem *buffer, nsecs_t presentWhen) { +status_t BufferQueue::acquireBuffer(BufferItem *buffer, nsecs_t expectedPresent) { ATRACE_CALL(); Mutex::Autolock _l(mMutex); @@ -835,37 +835,77 @@ status_t BufferQueue::acquireBuffer(BufferItem *buffer, nsecs_t presentWhen) { } Fifo::iterator front(mQueue.begin()); - int buf = front->mBuf; - // Compare the buffer's desired presentation time to the predicted - // actual display time. - // - // The "presentWhen" argument indicates when the buffer is expected - // to be presented on-screen. If the buffer's desired-present time - // is earlier (less) than presentWhen, meaning it'll be displayed - // on time or possibly late, we acquire and return it. If we don't want - // to display it until after the presentWhen time, we return PRESENT_LATER - // without acquiring it. - // - // To be safe, we don't refuse to acquire the buffer if presentWhen is - // more than one second in the future beyond the desired present time - // (i.e. we'd be holding the buffer for a really long time). - const int MAX_FUTURE_NSEC = 1000000000ULL; - nsecs_t desiredPresent = front->mTimestamp; - if (presentWhen != 0 && desiredPresent > presentWhen && - desiredPresent - presentWhen < MAX_FUTURE_NSEC) - { - ST_LOGV("pts defer: des=%lld when=%lld (%lld) now=%lld", - desiredPresent, presentWhen, desiredPresent - presentWhen, + // If expectedPresent is specified, we may not want to return a buffer yet. + // If it's specified and there's more than one buffer queued, we may + // want to drop a buffer. + if (expectedPresent != 0) { + const int MAX_REASONABLE_NSEC = 1000000000ULL; // 1 second + + // The "expectedPresent" argument indicates when the buffer is expected + // to be presented on-screen. If the buffer's desired-present time + // is earlier (less) than expectedPresent, meaning it'll be displayed + // on time or possibly late if we show it ASAP, we acquire and return + // it. If we don't want to display it until after the expectedPresent + // time, we return PRESENT_LATER without acquiring it. + // + // To be safe, we don't defer acquisition if expectedPresent is + // more than one second in the future beyond the desired present time + // (i.e. we'd be holding the buffer for a long time). + // + // NOTE: code assumes monotonic time values from the system clock are + // positive. + while (mQueue.size() > 1) { + // If entry[1] is timely, drop entry[0] (and repeat). We apply + // an additional criteria here: we only drop the earlier buffer if + // our desiredPresent falls within +/- 1 second of the expected + // present. Otherwise, bogus desiredPresent times (e.g. 0 or + // a small relative timestamp), which normally mean "ignore the + // timestamp and acquire immediately", would cause us to drop + // frames. + // + // We may want to add an additional criteria: don't drop the + // earlier buffer if entry[1]'s fence hasn't signaled yet. + // + // (Vector front is [0], back is [size()-1]) + const BufferItem& bi(mQueue[1]); + nsecs_t desiredPresent = bi.mTimestamp; + if (desiredPresent < expectedPresent - MAX_REASONABLE_NSEC || + desiredPresent > expectedPresent) { + // This buffer is set to display in the near future, or + // desiredPresent is garbage. Either way we don't want to + // drop the previous buffer just to get this on screen sooner. + ST_LOGV("pts nodrop: des=%lld expect=%lld (%lld) now=%lld", + desiredPresent, expectedPresent, desiredPresent - expectedPresent, + systemTime(CLOCK_MONOTONIC)); + break; + } + ST_LOGV("pts drop: queue1des=%lld expect=%lld size=%d", + desiredPresent, expectedPresent, mQueue.size()); + if (stillTracking(front)) { + // front buffer is still in mSlots, so mark the slot as free + mSlots[front->mBuf].mBufferState = BufferSlot::FREE; + } + mQueue.erase(front); + front = mQueue.begin(); + } + + // See if the front buffer is due. + nsecs_t desiredPresent = front->mTimestamp; + if (desiredPresent > expectedPresent && + desiredPresent < expectedPresent + MAX_REASONABLE_NSEC) { + ST_LOGV("pts defer: des=%lld expect=%lld (%lld) now=%lld", + desiredPresent, expectedPresent, desiredPresent - expectedPresent, + systemTime(CLOCK_MONOTONIC)); + return PRESENT_LATER; + } + + ST_LOGV("pts accept: des=%lld expect=%lld (%lld) now=%lld", + desiredPresent, expectedPresent, desiredPresent - expectedPresent, systemTime(CLOCK_MONOTONIC)); - return PRESENT_LATER; - } - if (presentWhen != 0) { - ST_LOGV("pts accept: %p[%d] sig=%lld des=%lld when=%lld (%lld)", - mSlots, buf, mSlots[buf].mFence->getSignalTime(), - desiredPresent, presentWhen, desiredPresent - presentWhen); } + int buf = front->mBuf; *buffer = *front; ATRACE_BUFFER_INDEX(buf); diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp index 998ea8ac8c..e2ec6434ce 100644 --- a/libs/gui/Surface.cpp +++ b/libs/gui/Surface.cpp @@ -261,9 +261,7 @@ int Surface::queueBuffer(android_native_buffer_t* buffer, int fenceFd) { 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); + timestamp = 0; } else { timestamp = mTimestamp; } diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp index 6c285d37b6..6dfd30604d 100644 --- a/opengl/libs/EGL/eglApi.cpp +++ b/opengl/libs/EGL/eglApi.cpp @@ -499,11 +499,6 @@ void EGLAPI eglBeginFrame(EGLDisplay dpy, EGLSurface surface) { setError(EGL_BAD_SURFACE, EGL_FALSE); return; } - - int64_t timestamp = systemTime(SYSTEM_TIME_MONOTONIC); - - egl_surface_t const * const s = get_surface(surface); - native_window_set_buffers_timestamp(s->win.get(), timestamp); } // ---------------------------------------------------------------------------- -- cgit v1.2.3-59-g8ed1b From a4e19521ac4563f2ff6517bcfd63d9b8d33a6d0b Mon Sep 17 00:00:00 2001 From: Mathias Agopian Date: Wed, 31 Jul 2013 20:09:53 -0700 Subject: Binderize the consumer side of BufferQueue While currently untested, this should allow to move the BuffereQueue in the consumer process and have everything work as usual. Bug: 9265647 Change-Id: I9ca8f099f7c65b9a27b7e7a3643b46d1b58eacfc --- include/gui/BufferQueue.h | 137 ++----- include/gui/ConsumerBase.h | 3 +- include/gui/IConsumerListener.h | 83 +++++ include/gui/IGraphicBufferConsumer.h | 209 +++++++++++ libs/gui/Android.mk | 2 + libs/gui/BufferQueue.cpp | 15 +- libs/gui/ConsumerBase.cpp | 6 +- libs/gui/IConsumerListener.cpp | 77 ++++ libs/gui/IGraphicBufferConsumer.cpp | 459 ++++++++++++++++++++++++ libs/gui/tests/BufferQueue_test.cpp | 2 +- libs/gui/tests/SurfaceTexture_test.cpp | 2 +- opengl/tests/EGLTest/Android.mk | 1 + opengl/tests/EGLTest/EGL_test.cpp | 2 +- services/surfaceflinger/SurfaceTextureLayer.cpp | 3 +- 14 files changed, 882 insertions(+), 119 deletions(-) create mode 100644 include/gui/IConsumerListener.h create mode 100644 include/gui/IGraphicBufferConsumer.h create mode 100644 libs/gui/IConsumerListener.cpp create mode 100644 libs/gui/IGraphicBufferConsumer.cpp (limited to 'libs/gui/BufferQueue.cpp') diff --git a/include/gui/BufferQueue.h b/include/gui/BufferQueue.h index cfce40dce1..1fbfc2b4ef 100644 --- a/include/gui/BufferQueue.h +++ b/include/gui/BufferQueue.h @@ -20,8 +20,10 @@ #include #include +#include #include #include +#include #include #include @@ -33,7 +35,7 @@ namespace android { // ---------------------------------------------------------------------------- -class BufferQueue : public BnGraphicBufferProducer { +class BufferQueue : public BnGraphicBufferProducer, public BnGraphicBufferConsumer { public: enum { MIN_UNDEQUEUED_BUFFERS = 2 }; enum { NUM_BUFFER_SLOTS = 32 }; @@ -45,31 +47,8 @@ public: // producer and consumer can run asynchronously. enum { MAX_MAX_ACQUIRED_BUFFERS = NUM_BUFFER_SLOTS - 2 }; - // ConsumerListener is the interface through which the BufferQueue notifies - // the consumer of events that the consumer may wish to react to. Because - // the consumer will generally have a mutex that is locked during calls from - // the consumer to the BufferQueue, these calls from the BufferQueue to the - // consumer *MUST* be called only when the BufferQueue mutex is NOT locked. - struct ConsumerListener : public virtual RefBase { - // onFrameAvailable is called from queueBuffer each time an additional - // frame becomes available for consumption. This means that frames that - // are queued while in asynchronous mode only trigger the callback if no - // previous frames are pending. Frames queued while in synchronous mode - // always trigger the callback. - // - // This is called without any lock held and can be called concurrently - // by multiple threads. - virtual void onFrameAvailable() = 0; - - // onBuffersReleased is called to notify the buffer consumer that the - // BufferQueue has released its references to one or more GraphicBuffers - // contained in its slots. The buffer consumer should then call - // BufferQueue::getReleasedBuffers to retrieve the list of buffers - // - // This is called without any lock held and can be called concurrently - // by multiple threads. - virtual void onBuffersReleased() = 0; - }; + // for backward source compatibility + typedef ::android::ConsumerListener ConsumerListener; // ProxyConsumerListener is a ConsumerListener implementation that keeps a weak // reference to the actual consumer object. It forwards all calls to that @@ -80,19 +59,16 @@ public: // reference in the BufferQueue class is because we're planning to expose the // consumer side of a BufferQueue as a binder interface, which doesn't support // weak references. - class ProxyConsumerListener : public BufferQueue::ConsumerListener { + class ProxyConsumerListener : public BnConsumerListener { public: - - ProxyConsumerListener(const wp& consumerListener); + ProxyConsumerListener(const wp& consumerListener); virtual ~ProxyConsumerListener(); virtual void onFrameAvailable(); virtual void onBuffersReleased(); - private: - - // mConsumerListener is a weak reference to the ConsumerListener. This is + // mConsumerListener is a weak reference to the IConsumerListener. This is // the raison d'etre of ProxyConsumerListener. - wp mConsumerListener; + wp mConsumerListener; }; @@ -102,6 +78,14 @@ public: BufferQueue(const sp& allocator = NULL); virtual ~BufferQueue(); + // dump our state in a String + virtual void dump(String8& result) const; + virtual void dump(String8& result, const char* prefix) const; + + /* + * IGraphicBufferProducer interface + */ + // Query native window attributes. The "what" values are enumerated in // window.h (e.g. NATIVE_WINDOW_FORMAT). virtual int query(int what, int* value); @@ -216,62 +200,9 @@ public: // connected to the specified producer API. virtual status_t disconnect(int api); - // dump our state in a String - virtual void dump(String8& result) const; - virtual void dump(String8& result, const char* prefix) const; - - // public facing structure for BufferSlot - struct BufferItem { - - BufferItem() : - mTransform(0), - mScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE), - mTimestamp(0), - mFrameNumber(0), - mBuf(INVALID_BUFFER_SLOT), - mIsDroppable(false), - mAcquireCalled(false) { - mCrop.makeInvalid(); - } - // mGraphicBuffer points to the buffer allocated for this slot, or is NULL - // if the buffer in this slot has been acquired in the past (see - // BufferSlot.mAcquireCalled). - sp mGraphicBuffer; - - // mCrop is the current crop rectangle for this buffer slot. - Rect mCrop; - - // mTransform is the current transform flags for this buffer slot. - uint32_t mTransform; - - // mScalingMode is the current scaling mode for this buffer slot. - uint32_t mScalingMode; - - // mTimestamp is the current timestamp for this buffer slot. This gets - // to set by queueBuffer each time this slot is queued. - int64_t mTimestamp; - - // mFrameNumber is the number of the queued frame for this slot. - uint64_t mFrameNumber; - - // mBuf is the slot index of this buffer - int mBuf; - - // mFence is a fence that will signal when the buffer is idle. - sp mFence; - - // mIsDroppable whether this buffer was queued with the - // property that it can be replaced by a new buffer for the purpose of - // making sure dequeueBuffer() won't block. - // i.e.: was the BufferQueue in "mDequeueBufferCannotBlock" when this buffer - // was queued. - bool mIsDroppable; - - // Indicates whether this buffer has been seen by a consumer yet - bool mAcquireCalled; - }; - - // The following public functions are the consumer-facing interface + /* + * IGraphicBufferConsumer interface + */ // acquireBuffer attempts to acquire ownership of the next pending buffer in // the BufferQueue. If no buffer is pending then it returns -EINVAL. If a @@ -286,7 +217,7 @@ public: // future, the buffer won't be acquired, and PRESENT_LATER will be // returned. The presentation time is in nanoseconds, and the time base // is CLOCK_MONOTONIC. - status_t acquireBuffer(BufferItem *buffer, nsecs_t presentWhen); + virtual status_t acquireBuffer(BufferItem *buffer, nsecs_t presentWhen); // releaseBuffer releases a buffer slot from the consumer back to the // BufferQueue. This may be done while the buffer's contents are still @@ -300,7 +231,7 @@ public: // // Note that the dependencies on EGL will be removed once we switch to using // the Android HW Sync HAL. - status_t releaseBuffer(int buf, uint64_t frameNumber, + virtual status_t releaseBuffer(int buf, uint64_t frameNumber, EGLDisplay display, EGLSyncKHR fence, const sp& releaseFence); @@ -312,25 +243,25 @@ public: // the application. // // consumer may not be NULL. - status_t consumerConnect(const sp& consumer, bool controlledByApp); + virtual status_t consumerConnect(const sp& consumer, bool controlledByApp); // consumerDisconnect disconnects a consumer from the BufferQueue. All // buffers will be freed and the BufferQueue is placed in the "abandoned" // state, causing most interactions with the BufferQueue by the producer to // fail. - status_t consumerDisconnect(); + virtual status_t consumerDisconnect(); // getReleasedBuffers sets the value pointed to by slotMask to a bit mask // indicating which buffer slots have been released by the BufferQueue // but have not yet been released by the consumer. // // This should be called from the onBuffersReleased() callback. - status_t getReleasedBuffers(uint32_t* slotMask); + virtual status_t getReleasedBuffers(uint32_t* slotMask); // setDefaultBufferSize is used to set the size of buffers returned by // dequeueBuffer when a width and height of zero is requested. Default // is 1x1. - status_t setDefaultBufferSize(uint32_t w, uint32_t h); + virtual status_t setDefaultBufferSize(uint32_t w, uint32_t h); // setDefaultMaxBufferCount sets the default value for the maximum buffer // count (the initial default is 2). If the producer has requested a @@ -338,38 +269,38 @@ public: // take effect if the producer sets the count back to zero. // // The count must be between 2 and NUM_BUFFER_SLOTS, inclusive. - status_t setDefaultMaxBufferCount(int bufferCount); + virtual status_t setDefaultMaxBufferCount(int bufferCount); // disableAsyncBuffer disables the extra buffer used in async mode // (when both producer and consumer have set their "isControlledByApp" // flag) and has dequeueBuffer() return WOULD_BLOCK instead. // // This can only be called before consumerConnect(). - status_t disableAsyncBuffer(); + virtual status_t disableAsyncBuffer(); // setMaxAcquiredBufferCount sets the maximum number of buffers that can // be acquired by the consumer at one time (default 1). This call will // fail if a producer is connected to the BufferQueue. - status_t setMaxAcquiredBufferCount(int maxAcquiredBuffers); + virtual status_t setMaxAcquiredBufferCount(int maxAcquiredBuffers); // setConsumerName sets the name used in logging - void setConsumerName(const String8& name); + virtual void setConsumerName(const String8& name); // setDefaultBufferFormat allows the BufferQueue to create // GraphicBuffers of a defaultFormat if no format is specified // in dequeueBuffer. Formats are enumerated in graphics.h; the // initial default is HAL_PIXEL_FORMAT_RGBA_8888. - status_t setDefaultBufferFormat(uint32_t defaultFormat); + virtual status_t setDefaultBufferFormat(uint32_t defaultFormat); // setConsumerUsageBits will turn on additional usage bits for dequeueBuffer. // These are merged with the bits passed to dequeueBuffer. The values are // enumerated in gralloc.h, e.g. GRALLOC_USAGE_HW_RENDER; the default is 0. - status_t setConsumerUsageBits(uint32_t usage); + virtual status_t setConsumerUsageBits(uint32_t usage); // setTransformHint bakes in rotation to buffers so overlays can be used. // The values are enumerated in window.h, e.g. // NATIVE_WINDOW_TRANSFORM_ROT_90. The default is 0 (no transform). - status_t setTransformHint(uint32_t hint); + virtual status_t setTransformHint(uint32_t hint); private: @@ -560,7 +491,7 @@ private: // mConsumerListener is used to notify the connected consumer of // asynchronous events that it may wish to react to. It is initially set // to NULL and is written by consumerConnect and consumerDisconnect. - sp mConsumerListener; + sp mConsumerListener; // mConsumerControlledByApp whether the connected consumer is controlled by the // application. diff --git a/include/gui/ConsumerBase.h b/include/gui/ConsumerBase.h index 7b58bc5bb1..daad75709a 100644 --- a/include/gui/ConsumerBase.h +++ b/include/gui/ConsumerBase.h @@ -24,6 +24,7 @@ #include #include #include +#include namespace android { // ---------------------------------------------------------------------------- @@ -34,7 +35,7 @@ class String8; // handles common tasks like management of the connection to the BufferQueue // and the buffer pool. class ConsumerBase : public virtual RefBase, - protected BufferQueue::ConsumerListener { + protected ConsumerListener { public: struct FrameAvailableListener : public virtual RefBase { // onFrameAvailable() is called each time an additional frame becomes diff --git a/include/gui/IConsumerListener.h b/include/gui/IConsumerListener.h new file mode 100644 index 0000000000..ac2f9bb565 --- /dev/null +++ b/include/gui/IConsumerListener.h @@ -0,0 +1,83 @@ +/* + * Copyright (C) 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. + */ + +#ifndef ANDROID_GUI_ICONSUMERLISTENER_H +#define ANDROID_GUI_ICONSUMERLISTENER_H + +#include +#include + +#include +#include + +#include + +namespace android { +// ---------------------------------------------------------------------------- + +// ConsumerListener is the interface through which the BufferQueue notifies +// the consumer of events that the consumer may wish to react to. Because +// the consumer will generally have a mutex that is locked during calls from +// the consumer to the BufferQueue, these calls from the BufferQueue to the +// consumer *MUST* be called only when the BufferQueue mutex is NOT locked. + +class ConsumerListener : public virtual RefBase { +public: + ConsumerListener() { } + virtual ~ConsumerListener() { } + + // onFrameAvailable is called from queueBuffer each time an additional + // frame becomes available for consumption. This means that frames that + // are queued while in asynchronous mode only trigger the callback if no + // previous frames are pending. Frames queued while in synchronous mode + // always trigger the callback. + // + // This is called without any lock held and can be called concurrently + // by multiple threads. + virtual void onFrameAvailable() = 0; /* Asynchronous */ + + // onBuffersReleased is called to notify the buffer consumer that the + // BufferQueue has released its references to one or more GraphicBuffers + // contained in its slots. The buffer consumer should then call + // BufferQueue::getReleasedBuffers to retrieve the list of buffers + // + // This is called without any lock held and can be called concurrently + // by multiple threads. + virtual void onBuffersReleased() = 0; /* Asynchronous */ +}; + + +class IConsumerListener : public ConsumerListener, public IInterface +{ +public: + DECLARE_META_INTERFACE(ConsumerListener); +}; + +// ---------------------------------------------------------------------------- + +class BnConsumerListener : public BnInterface +{ +public: + virtual status_t onTransact( uint32_t code, + const Parcel& data, + Parcel* reply, + uint32_t flags = 0); +}; + +// ---------------------------------------------------------------------------- +}; // namespace android + +#endif // ANDROID_GUI_ICONSUMERLISTENER_H diff --git a/include/gui/IGraphicBufferConsumer.h b/include/gui/IGraphicBufferConsumer.h new file mode 100644 index 0000000000..82b50c8abd --- /dev/null +++ b/include/gui/IGraphicBufferConsumer.h @@ -0,0 +1,209 @@ +/* + * Copyright (C) 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. + */ + +#ifndef ANDROID_GUI_IGRAPHICBUFFERCONSUMER_H +#define ANDROID_GUI_IGRAPHICBUFFERCONSUMER_H + +#include +#include + +#include +#include +#include + +#include +#include + +namespace android { +// ---------------------------------------------------------------------------- + +class IConsumerListener; +class GraphicBuffer; +class Fence; + +class IGraphicBufferConsumer : public IInterface { + +public: + + // public facing structure for BufferSlot + class BufferItem : public Flattenable { + friend class Flattenable; + size_t getPodSize() const; + size_t getFlattenedSize() const; + size_t getFdCount() const; + status_t flatten(void*& buffer, size_t& size, int*& fds, size_t& count) const; + status_t unflatten(void const*& buffer, size_t& size, int const*& fds, size_t& count); + + public: + enum { INVALID_BUFFER_SLOT = -1 }; + BufferItem(); + + // mGraphicBuffer points to the buffer allocated for this slot, or is NULL + // if the buffer in this slot has been acquired in the past (see + // BufferSlot.mAcquireCalled). + sp mGraphicBuffer; + + // mFence is a fence that will signal when the buffer is idle. + sp mFence; + + // mCrop is the current crop rectangle for this buffer slot. + Rect mCrop; + + // mTransform is the current transform flags for this buffer slot. + uint32_t mTransform; + + // mScalingMode is the current scaling mode for this buffer slot. + uint32_t mScalingMode; + + // mTimestamp is the current timestamp for this buffer slot. This gets + // to set by queueBuffer each time this slot is queued. + int64_t mTimestamp; + + // mFrameNumber is the number of the queued frame for this slot. + uint64_t mFrameNumber; + + // mBuf is the slot index of this buffer + int mBuf; + + // mIsDroppable whether this buffer was queued with the + // property that it can be replaced by a new buffer for the purpose of + // making sure dequeueBuffer() won't block. + // i.e.: was the BufferQueue in "mDequeueBufferCannotBlock" when this buffer + // was queued. + bool mIsDroppable; + + // Indicates whether this buffer has been seen by a consumer yet + bool mAcquireCalled; + }; + + + // acquireBuffer attempts to acquire ownership of the next pending buffer in + // the BufferQueue. If no buffer is pending then it returns -EINVAL. If a + // buffer is successfully acquired, the information about the buffer is + // returned in BufferItem. If the buffer returned had previously been + // acquired then the BufferItem::mGraphicBuffer field of buffer is set to + // NULL and it is assumed that the consumer still holds a reference to the + // buffer. + // + // If presentWhen is nonzero, it indicates the time when the buffer will + // be displayed on screen. If the buffer's timestamp is farther in the + // future, the buffer won't be acquired, and PRESENT_LATER will be + // returned. The presentation time is in nanoseconds, and the time base + // is CLOCK_MONOTONIC. + virtual status_t acquireBuffer(BufferItem *buffer, nsecs_t presentWhen) = 0; + + // releaseBuffer releases a buffer slot from the consumer back to the + // BufferQueue. This may be done while the buffer's contents are still + // being accessed. The fence will signal when the buffer is no longer + // in use. frameNumber is used to indentify the exact buffer returned. + // + // If releaseBuffer returns STALE_BUFFER_SLOT, then the consumer must free + // any references to the just-released buffer that it might have, as if it + // had received a onBuffersReleased() call with a mask set for the released + // buffer. + // + // Note that the dependencies on EGL will be removed once we switch to using + // the Android HW Sync HAL. + virtual status_t releaseBuffer(int buf, uint64_t frameNumber, + EGLDisplay display, EGLSyncKHR fence, + const sp& releaseFence) = 0; + + // consumerConnect connects a consumer to the BufferQueue. Only one + // consumer may be connected, and when that consumer disconnects the + // BufferQueue is placed into the "abandoned" state, causing most + // interactions with the BufferQueue by the producer to fail. + // controlledByApp indicates whether the consumer is controlled by + // the application. + // + // consumer may not be NULL. + virtual status_t consumerConnect(const sp& consumer, bool controlledByApp) = 0; + + // consumerDisconnect disconnects a consumer from the BufferQueue. All + // buffers will be freed and the BufferQueue is placed in the "abandoned" + // state, causing most interactions with the BufferQueue by the producer to + // fail. + virtual status_t consumerDisconnect() = 0; + + // getReleasedBuffers sets the value pointed to by slotMask to a bit mask + // indicating which buffer slots have been released by the BufferQueue + // but have not yet been released by the consumer. + // + // This should be called from the onBuffersReleased() callback. + virtual status_t getReleasedBuffers(uint32_t* slotMask) = 0; + + // setDefaultBufferSize is used to set the size of buffers returned by + // dequeueBuffer when a width and height of zero is requested. Default + // is 1x1. + virtual status_t setDefaultBufferSize(uint32_t w, uint32_t h) = 0; + + // setDefaultMaxBufferCount sets the default value for the maximum buffer + // count (the initial default is 2). If the producer has requested a + // buffer count using setBufferCount, the default buffer count will only + // take effect if the producer sets the count back to zero. + // + // The count must be between 2 and NUM_BUFFER_SLOTS, inclusive. + virtual status_t setDefaultMaxBufferCount(int bufferCount) = 0; + + // disableAsyncBuffer disables the extra buffer used in async mode + // (when both producer and consumer have set their "isControlledByApp" + // flag) and has dequeueBuffer() return WOULD_BLOCK instead. + // + // This can only be called before consumerConnect(). + virtual status_t disableAsyncBuffer() = 0; + + // setMaxAcquiredBufferCount sets the maximum number of buffers that can + // be acquired by the consumer at one time (default 1). This call will + // fail if a producer is connected to the BufferQueue. + virtual status_t setMaxAcquiredBufferCount(int maxAcquiredBuffers) = 0; + + // setConsumerName sets the name used in logging + virtual void setConsumerName(const String8& name) = 0; + + // setDefaultBufferFormat allows the BufferQueue to create + // GraphicBuffers of a defaultFormat if no format is specified + // in dequeueBuffer. Formats are enumerated in graphics.h; the + // initial default is HAL_PIXEL_FORMAT_RGBA_8888. + virtual status_t setDefaultBufferFormat(uint32_t defaultFormat) = 0; + + // setConsumerUsageBits will turn on additional usage bits for dequeueBuffer. + // These are merged with the bits passed to dequeueBuffer. The values are + // enumerated in gralloc.h, e.g. GRALLOC_USAGE_HW_RENDER; the default is 0. + virtual status_t setConsumerUsageBits(uint32_t usage) = 0; + + // setTransformHint bakes in rotation to buffers so overlays can be used. + // The values are enumerated in window.h, e.g. + // NATIVE_WINDOW_TRANSFORM_ROT_90. The default is 0 (no transform). + virtual status_t setTransformHint(uint32_t hint) = 0; + +public: + DECLARE_META_INTERFACE(GraphicBufferConsumer); +}; + +// ---------------------------------------------------------------------------- + +class BnGraphicBufferConsumer : public BnInterface +{ +public: + virtual status_t onTransact( uint32_t code, + const Parcel& data, + Parcel* reply, + uint32_t flags = 0); +}; + +// ---------------------------------------------------------------------------- +}; // namespace android + +#endif // ANDROID_GUI_IGRAPHICBUFFERCONSUMER_H diff --git a/libs/gui/Android.mk b/libs/gui/Android.mk index f627e5d2b8..c14c9506ad 100644 --- a/libs/gui/Android.mk +++ b/libs/gui/Android.mk @@ -2,6 +2,8 @@ LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_SRC_FILES:= \ + IGraphicBufferConsumer.cpp \ + IConsumerListener.cpp \ BitTube.cpp \ BufferItemConsumer.cpp \ BufferQueue.cpp \ diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp index e20ac86799..8524a8b5fc 100644 --- a/libs/gui/BufferQueue.cpp +++ b/libs/gui/BufferQueue.cpp @@ -25,6 +25,7 @@ #include #include +#include #include #include @@ -138,7 +139,7 @@ status_t BufferQueue::setTransformHint(uint32_t hint) { status_t BufferQueue::setBufferCount(int bufferCount) { ST_LOGV("setBufferCount: count=%d", bufferCount); - sp listener; + sp listener; { Mutex::Autolock lock(mMutex); @@ -492,7 +493,7 @@ status_t BufferQueue::queueBuffer(int buf, return -EINVAL; } - sp listener; + sp listener; { // scope for the lock Mutex::Autolock lock(mMutex); @@ -675,7 +676,7 @@ status_t BufferQueue::disconnect(int api) { ST_LOGV("disconnect: api=%d", api); int err = NO_ERROR; - sp listener; + sp listener; { // Scope for the lock Mutex::Autolock lock(mMutex); @@ -951,7 +952,7 @@ status_t BufferQueue::releaseBuffer( return NO_ERROR; } -status_t BufferQueue::consumerConnect(const sp& consumerListener, +status_t BufferQueue::consumerConnect(const sp& consumerListener, bool controlledByApp) { ST_LOGV("consumerConnect"); Mutex::Autolock lock(mMutex); @@ -1127,20 +1128,20 @@ bool BufferQueue::stillTracking(const BufferItem *item) const { } BufferQueue::ProxyConsumerListener::ProxyConsumerListener( - const wp& consumerListener): + const wp& consumerListener): mConsumerListener(consumerListener) {} BufferQueue::ProxyConsumerListener::~ProxyConsumerListener() {} void BufferQueue::ProxyConsumerListener::onFrameAvailable() { - sp listener(mConsumerListener.promote()); + sp listener(mConsumerListener.promote()); if (listener != NULL) { listener->onFrameAvailable(); } } void BufferQueue::ProxyConsumerListener::onBuffersReleased() { - sp listener(mConsumerListener.promote()); + sp listener(mConsumerListener.promote()); if (listener != NULL) { listener->onBuffersReleased(); } diff --git a/libs/gui/ConsumerBase.cpp b/libs/gui/ConsumerBase.cpp index cd94ce19aa..d748786d98 100644 --- a/libs/gui/ConsumerBase.cpp +++ b/libs/gui/ConsumerBase.cpp @@ -61,10 +61,8 @@ ConsumerBase::ConsumerBase(const sp& bufferQueue, bool controlledBy // reference once the ctor ends, as that would cause the refcount of 'this' // dropping to 0 at the end of the ctor. Since all we need is a wp<...> // that's what we create. - wp listener; - sp proxy; - listener = static_cast(this); - proxy = new BufferQueue::ProxyConsumerListener(listener); + wp listener = static_cast(this); + sp proxy = new BufferQueue::ProxyConsumerListener(listener); status_t err = mBufferQueue->consumerConnect(proxy, controlledByApp); if (err != NO_ERROR) { diff --git a/libs/gui/IConsumerListener.cpp b/libs/gui/IConsumerListener.cpp new file mode 100644 index 0000000000..53044624af --- /dev/null +++ b/libs/gui/IConsumerListener.cpp @@ -0,0 +1,77 @@ +/* + * Copyright (C) 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. + */ + +#include +#include + +#include +#include + +#include + +// --------------------------------------------------------------------------- +namespace android { +// --------------------------------------------------------------------------- + +enum { + ON_FRAME_AVAILABLE = IBinder::FIRST_CALL_TRANSACTION, + ON_BUFFER_RELEASED +}; + +class BpConsumerListener : public BpInterface +{ +public: + BpConsumerListener(const sp& impl) + : BpInterface(impl) { + } + + virtual void onFrameAvailable() { + Parcel data, reply; + data.writeInterfaceToken(IConsumerListener::getInterfaceDescriptor()); + remote()->transact(ON_FRAME_AVAILABLE, data, &reply, IBinder::FLAG_ONEWAY); + } + + virtual void onBuffersReleased() { + Parcel data, reply; + data.writeInterfaceToken(IConsumerListener::getInterfaceDescriptor()); + remote()->transact(ON_BUFFER_RELEASED, data, &reply, IBinder::FLAG_ONEWAY); + } +}; + +IMPLEMENT_META_INTERFACE(ConsumerListener, "android.gui.IConsumerListener"); + +// ---------------------------------------------------------------------- + +status_t BnConsumerListener::onTransact( + uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) +{ + switch(code) { + case ON_FRAME_AVAILABLE: + CHECK_INTERFACE(IConsumerListener, data, reply); + onFrameAvailable(); + return NO_ERROR; + case ON_BUFFER_RELEASED: + CHECK_INTERFACE(IConsumerListener, data, reply); + onBuffersReleased(); + return NO_ERROR; + } + return BBinder::onTransact(code, data, reply, flags); +} + + +// --------------------------------------------------------------------------- +}; // namespace android +// --------------------------------------------------------------------------- diff --git a/libs/gui/IGraphicBufferConsumer.cpp b/libs/gui/IGraphicBufferConsumer.cpp new file mode 100644 index 0000000000..526328146d --- /dev/null +++ b/libs/gui/IGraphicBufferConsumer.cpp @@ -0,0 +1,459 @@ +/* + * Copyright (C) 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 EGL_EGLEXT_PROTOTYPES + +#include +#include + + +#include +#include + +#include + +#include +#include + +#include +#include + +#include +#include + +#include + +namespace android { +// --------------------------------------------------------------------------- + +IGraphicBufferConsumer::BufferItem::BufferItem() : + mTransform(0), + mScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE), + mTimestamp(0), + mFrameNumber(0), + mBuf(INVALID_BUFFER_SLOT), + mIsDroppable(false), + mAcquireCalled(false) { + mCrop.makeInvalid(); +} + +size_t IGraphicBufferConsumer::BufferItem::getPodSize() const { + size_t c = sizeof(mCrop) + + sizeof(mTransform) + + sizeof(mScalingMode) + + sizeof(mTimestamp) + + sizeof(mFrameNumber) + + sizeof(mBuf) + + sizeof(mIsDroppable) + + sizeof(mAcquireCalled); + return c; +} + +size_t IGraphicBufferConsumer::BufferItem::getFlattenedSize() const { + size_t c = 0; + if (mGraphicBuffer != 0) { + c += mGraphicBuffer->getFlattenedSize(); + FlattenableUtils::align<4>(c); + } + if (mFence != 0) { + c += mFence->getFlattenedSize(); + FlattenableUtils::align<4>(c); + } + return sizeof(int32_t) + c + getPodSize(); +} + +size_t IGraphicBufferConsumer::BufferItem::getFdCount() const { + size_t c = 0; + if (mGraphicBuffer != 0) { + c += mGraphicBuffer->getFdCount(); + } + if (mFence != 0) { + c += mFence->getFdCount(); + } + return c; +} + +status_t IGraphicBufferConsumer::BufferItem::flatten( + void*& buffer, size_t& size, int*& fds, size_t& count) const { + + // make sure we have enough space + if (count < BufferItem::getFlattenedSize()) { + return NO_MEMORY; + } + + // content flags are stored first + uint32_t& flags = *static_cast(buffer); + + // advance the pointer + FlattenableUtils::advance(buffer, size, sizeof(uint32_t)); + + flags = 0; + if (mGraphicBuffer != 0) { + status_t err = mGraphicBuffer->flatten(buffer, size, fds, count); + if (err) return err; + size -= FlattenableUtils::align<4>(buffer); + flags |= 1; + } + if (mFence != 0) { + status_t err = mFence->flatten(buffer, size, fds, count); + if (err) return err; + size -= FlattenableUtils::align<4>(buffer); + flags |= 2; + } + + // check we have enough space (in case flattening the fence/graphicbuffer lied to us) + if (size < getPodSize()) { + return NO_MEMORY; + } + + FlattenableUtils::write(buffer, size, mCrop); + FlattenableUtils::write(buffer, size, mTransform); + FlattenableUtils::write(buffer, size, mScalingMode); + FlattenableUtils::write(buffer, size, mTimestamp); + FlattenableUtils::write(buffer, size, mFrameNumber); + FlattenableUtils::write(buffer, size, mBuf); + FlattenableUtils::write(buffer, size, mIsDroppable); + FlattenableUtils::write(buffer, size, mAcquireCalled); + + return NO_ERROR; +} + +status_t IGraphicBufferConsumer::BufferItem::unflatten( + void const*& buffer, size_t& size, int const*& fds, size_t& count) { + + if (size < sizeof(uint32_t)) + return NO_MEMORY; + + uint32_t flags = 0; + FlattenableUtils::read(buffer, size, flags); + + if (flags & 1) { + mGraphicBuffer = new GraphicBuffer(); + status_t err = mGraphicBuffer->unflatten(buffer, size, fds, count); + if (err) return err; + size -= FlattenableUtils::align<4>(buffer); + } + + if (flags & 2) { + mFence = new Fence(); + status_t err = mFence->unflatten(buffer, size, fds, count); + if (err) return err; + size -= FlattenableUtils::align<4>(buffer); + } + + // check we have enough space + if (size < getPodSize()) { + return NO_MEMORY; + } + + FlattenableUtils::read(buffer, size, mCrop); + FlattenableUtils::read(buffer, size, mTransform); + FlattenableUtils::read(buffer, size, mScalingMode); + FlattenableUtils::read(buffer, size, mTimestamp); + FlattenableUtils::read(buffer, size, mFrameNumber); + FlattenableUtils::read(buffer, size, mBuf); + FlattenableUtils::read(buffer, size, mIsDroppable); + FlattenableUtils::read(buffer, size, mAcquireCalled); + + return NO_ERROR; +} + +// --------------------------------------------------------------------------- + +enum { + ACQUIRE_BUFFER = IBinder::FIRST_CALL_TRANSACTION, + RELEASE_BUFFER, + CONSUMER_CONNECT, + CONSUMER_DISCONNECT, + GET_RELEASED_BUFFERS, + SET_DEFAULT_BUFFER_SIZE, + SET_DEFAULT_MAX_BUFFER_COUNT, + DISABLE_ASYNC_BUFFER, + SET_MAX_ACQUIRED_BUFFER_COUNT, + SET_CONSUMER_NAME, + SET_DEFAULT_BUFFER_FORMAT, + SET_CONSUMER_USAGE_BITS, + SET_TRANSFORM_HINT +}; + + +class BpGraphicBufferConsumer : public BpInterface +{ +public: + BpGraphicBufferConsumer(const sp& impl) + : BpInterface(impl) + { + } + + virtual status_t acquireBuffer(BufferItem *buffer, nsecs_t presentWhen) { + Parcel data, reply; + data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor()); + data.writeInt64(presentWhen); + status_t result = remote()->transact(ACQUIRE_BUFFER, data, &reply); + if (result != NO_ERROR) { + return result; + } + result = reply.read(*buffer); + if (result != NO_ERROR) { + return result; + } + return reply.readInt32(); + } + + virtual status_t releaseBuffer(int buf, uint64_t frameNumber, + EGLDisplay display, EGLSyncKHR fence, + const sp& releaseFence) { + Parcel data, reply; + data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor()); + data.writeInt32(buf); + data.writeInt64(frameNumber); + data.write(*releaseFence); + status_t result = remote()->transact(RELEASE_BUFFER, data, &reply); + if (result != NO_ERROR) { + return result; + } + return reply.readInt32(); + } + + virtual status_t consumerConnect(const sp& consumer, bool controlledByApp) { + Parcel data, reply; + data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor()); + data.writeStrongBinder(consumer->asBinder()); + data.writeInt32(controlledByApp); + status_t result = remote()->transact(CONSUMER_CONNECT, data, &reply); + if (result != NO_ERROR) { + return result; + } + return reply.readInt32(); + } + + virtual status_t consumerDisconnect() { + Parcel data, reply; + data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor()); + status_t result = remote()->transact(CONSUMER_DISCONNECT, data, &reply); + if (result != NO_ERROR) { + return result; + } + return reply.readInt32(); + } + + virtual status_t getReleasedBuffers(uint32_t* slotMask) { + Parcel data, reply; + data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor()); + status_t result = remote()->transact(GET_RELEASED_BUFFERS, data, &reply); + if (result != NO_ERROR) { + return result; + } + *slotMask = reply.readInt32(); + return reply.readInt32(); + } + + virtual status_t setDefaultBufferSize(uint32_t w, uint32_t h) { + Parcel data, reply; + data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor()); + data.writeInt32(w); + data.writeInt32(h); + status_t result = remote()->transact(SET_DEFAULT_BUFFER_SIZE, data, &reply); + if (result != NO_ERROR) { + return result; + } + return reply.readInt32(); + } + + virtual status_t setDefaultMaxBufferCount(int bufferCount) { + Parcel data, reply; + data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor()); + data.writeInt32(bufferCount); + status_t result = remote()->transact(SET_DEFAULT_MAX_BUFFER_COUNT, data, &reply); + if (result != NO_ERROR) { + return result; + } + return reply.readInt32(); + } + + virtual status_t disableAsyncBuffer() { + Parcel data, reply; + data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor()); + status_t result = remote()->transact(DISABLE_ASYNC_BUFFER, data, &reply); + if (result != NO_ERROR) { + return result; + } + return reply.readInt32(); + } + + virtual status_t setMaxAcquiredBufferCount(int maxAcquiredBuffers) { + Parcel data, reply; + data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor()); + data.writeInt32(maxAcquiredBuffers); + status_t result = remote()->transact(SET_MAX_ACQUIRED_BUFFER_COUNT, data, &reply); + if (result != NO_ERROR) { + return result; + } + return reply.readInt32(); + } + + virtual void setConsumerName(const String8& name) { + Parcel data, reply; + data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor()); + data.writeString8(name); + remote()->transact(SET_CONSUMER_NAME, data, &reply); + } + + virtual status_t setDefaultBufferFormat(uint32_t defaultFormat) { + Parcel data, reply; + data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor()); + data.writeInt32(defaultFormat); + status_t result = remote()->transact(SET_DEFAULT_BUFFER_FORMAT, data, &reply); + if (result != NO_ERROR) { + return result; + } + return reply.readInt32(); + } + + virtual status_t setConsumerUsageBits(uint32_t usage) { + Parcel data, reply; + data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor()); + data.writeInt32(usage); + status_t result = remote()->transact(SET_CONSUMER_USAGE_BITS, data, &reply); + if (result != NO_ERROR) { + return result; + } + return reply.readInt32(); + } + + virtual status_t setTransformHint(uint32_t hint) { + Parcel data, reply; + data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor()); + data.writeInt32(hint); + status_t result = remote()->transact(SET_TRANSFORM_HINT, data, &reply); + if (result != NO_ERROR) { + return result; + } + return reply.readInt32(); + } +}; + +IMPLEMENT_META_INTERFACE(GraphicBufferConsumer, "android.gui.IGraphicBufferConsumer"); + +// ---------------------------------------------------------------------- + +status_t BnGraphicBufferConsumer::onTransact( + uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) +{ + switch(code) { + case ACQUIRE_BUFFER: { + CHECK_INTERFACE(IGraphicBufferConsumer, data, reply); + BufferItem item; + int64_t presentWhen = data.readInt64(); + status_t result = acquireBuffer(&item, presentWhen); + status_t err = reply->write(item); + if (err) return err; + reply->writeInt32(result); + return NO_ERROR; + } break; + case RELEASE_BUFFER: { + CHECK_INTERFACE(IGraphicBufferConsumer, data, reply); + int buf = data.readInt32(); + uint64_t frameNumber = data.readInt64(); + sp releaseFence = new Fence(); + status_t err = data.read(*releaseFence); + if (err) return err; + status_t result = releaseBuffer(buf, frameNumber, + EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, releaseFence); + reply->writeInt32(result); + return NO_ERROR; + } break; + case CONSUMER_CONNECT: { + CHECK_INTERFACE(IGraphicBufferConsumer, data, reply); + sp consumer = IConsumerListener::asInterface( data.readStrongBinder() ); + bool controlledByApp = data.readInt32(); + status_t result = consumerConnect(consumer, controlledByApp); + reply->writeInt32(result); + return NO_ERROR; + } break; + case CONSUMER_DISCONNECT: { + CHECK_INTERFACE(IGraphicBufferConsumer, data, reply); + status_t result = consumerDisconnect(); + reply->writeInt32(result); + return NO_ERROR; + } break; + case GET_RELEASED_BUFFERS: { + CHECK_INTERFACE(IGraphicBufferConsumer, data, reply); + uint32_t slotMask; + status_t result = getReleasedBuffers(&slotMask); + reply->writeInt32(slotMask); + reply->writeInt32(result); + return NO_ERROR; + } break; + case SET_DEFAULT_BUFFER_SIZE: { + CHECK_INTERFACE(IGraphicBufferConsumer, data, reply); + uint32_t w = data.readInt32(); + uint32_t h = data.readInt32(); + status_t result = setDefaultBufferSize(w, h); + reply->writeInt32(result); + return NO_ERROR; + } break; + case SET_DEFAULT_MAX_BUFFER_COUNT: { + CHECK_INTERFACE(IGraphicBufferConsumer, data, reply); + uint32_t bufferCount = data.readInt32(); + status_t result = setDefaultMaxBufferCount(bufferCount); + reply->writeInt32(result); + return NO_ERROR; + } break; + case DISABLE_ASYNC_BUFFER: { + CHECK_INTERFACE(IGraphicBufferConsumer, data, reply); + status_t result = disableAsyncBuffer(); + reply->writeInt32(result); + return NO_ERROR; + } break; + case SET_MAX_ACQUIRED_BUFFER_COUNT: { + CHECK_INTERFACE(IGraphicBufferConsumer, data, reply); + uint32_t maxAcquiredBuffers = data.readInt32(); + status_t result = setMaxAcquiredBufferCount(maxAcquiredBuffers); + reply->writeInt32(result); + return NO_ERROR; + } break; + case SET_CONSUMER_NAME: { + CHECK_INTERFACE(IGraphicBufferConsumer, data, reply); + setConsumerName( data.readString8() ); + return NO_ERROR; + } break; + case SET_DEFAULT_BUFFER_FORMAT: { + CHECK_INTERFACE(IGraphicBufferConsumer, data, reply); + uint32_t defaultFormat = data.readInt32(); + status_t result = setDefaultBufferFormat(defaultFormat); + reply->writeInt32(result); + return NO_ERROR; + } break; + case SET_CONSUMER_USAGE_BITS: { + CHECK_INTERFACE(IGraphicBufferConsumer, data, reply); + uint32_t usage = data.readInt32(); + status_t result = setConsumerUsageBits(usage); + reply->writeInt32(result); + return NO_ERROR; + } break; + case SET_TRANSFORM_HINT: { + CHECK_INTERFACE(IGraphicBufferConsumer, data, reply); + uint32_t hint = data.readInt32(); + status_t result = setTransformHint(hint); + reply->writeInt32(result); + return NO_ERROR; + } break; + } + return BBinder::onTransact(code, data, reply, flags); +} + +}; // namespace android diff --git a/libs/gui/tests/BufferQueue_test.cpp b/libs/gui/tests/BufferQueue_test.cpp index b691fc111f..da98c8d43e 100644 --- a/libs/gui/tests/BufferQueue_test.cpp +++ b/libs/gui/tests/BufferQueue_test.cpp @@ -55,7 +55,7 @@ protected: sp mBQ; }; -struct DummyConsumer : public BufferQueue::ConsumerListener { +struct DummyConsumer : public BnConsumerListener { virtual void onFrameAvailable() {} virtual void onBuffersReleased() {} }; diff --git a/libs/gui/tests/SurfaceTexture_test.cpp b/libs/gui/tests/SurfaceTexture_test.cpp index e6d87db252..ae223c6d8e 100644 --- a/libs/gui/tests/SurfaceTexture_test.cpp +++ b/libs/gui/tests/SurfaceTexture_test.cpp @@ -628,7 +628,7 @@ protected: // no way to forward the events. This DisconnectWaiter will not let the // disconnect finish until finishDisconnect() is called. It will // also block until a disconnect is called - class DisconnectWaiter : public BufferQueue::ConsumerListener { + class DisconnectWaiter : public BnConsumerListener { public: DisconnectWaiter () : mWaitForDisconnect(false), diff --git a/opengl/tests/EGLTest/Android.mk b/opengl/tests/EGLTest/Android.mk index 1a9ee5c783..f37efec713 100644 --- a/opengl/tests/EGLTest/Android.mk +++ b/opengl/tests/EGLTest/Android.mk @@ -13,6 +13,7 @@ LOCAL_SRC_FILES := \ LOCAL_SHARED_LIBRARIES := \ libEGL \ libcutils \ + libbinder \ libstlport \ libutils \ libgui \ diff --git a/opengl/tests/EGLTest/EGL_test.cpp b/opengl/tests/EGLTest/EGL_test.cpp index 86bbb84896..f6644fbfdb 100644 --- a/opengl/tests/EGLTest/EGL_test.cpp +++ b/opengl/tests/EGLTest/EGL_test.cpp @@ -100,7 +100,7 @@ TEST_F(EGLTest, EGLTerminateSucceedsWithRemainingObjects) { }; EXPECT_TRUE(eglChooseConfig(mEglDisplay, attrs, &config, 1, &numConfigs)); - struct DummyConsumer : public BufferQueue::ConsumerListener { + struct DummyConsumer : public BnConsumerListener { virtual void onFrameAvailable() {} virtual void onBuffersReleased() {} }; diff --git a/services/surfaceflinger/SurfaceTextureLayer.cpp b/services/surfaceflinger/SurfaceTextureLayer.cpp index b76dc0c502..9d79ce20e2 100644 --- a/services/surfaceflinger/SurfaceTextureLayer.cpp +++ b/services/surfaceflinger/SurfaceTextureLayer.cpp @@ -48,7 +48,8 @@ SurfaceTextureLayer::~SurfaceTextureLayer() { return true; } }; - flinger->postMessageAsync( new MessageCleanUpList(flinger, this) ); + flinger->postMessageAsync( + new MessageCleanUpList(flinger, static_cast(this)) ); } // --------------------------------------------------------------------------- -- cgit v1.2.3-59-g8ed1b From 4b49e08385a96398aa2633e096fe916dc9f08768 Mon Sep 17 00:00:00 2001 From: Andy McFadden Date: Fri, 2 Aug 2013 15:31:45 -0700 Subject: Roll back recent change Disable dropping of frames based on timestamp. Resume auto- generating timestamps in Surface. Bug 10151804 Change-Id: I15de26158e1d7ef22a5b150e685a126dc48ae2b4 --- libs/gui/BufferQueue.cpp | 2 +- libs/gui/Surface.cpp | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'libs/gui/BufferQueue.cpp') diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp index e22679e499..88159aacb5 100644 --- a/libs/gui/BufferQueue.cpp +++ b/libs/gui/BufferQueue.cpp @@ -855,7 +855,7 @@ status_t BufferQueue::acquireBuffer(BufferItem *buffer, nsecs_t expectedPresent) // // NOTE: code assumes monotonic time values from the system clock are // positive. - while (mQueue.size() > 1) { + while (false && mQueue.size() > 1) { // If entry[1] is timely, drop entry[0] (and repeat). We apply // an additional criteria here: we only drop the earlier buffer if // our desiredPresent falls within +/- 1 second of the expected diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp index e2ec6434ce..cfd29fed39 100644 --- a/libs/gui/Surface.cpp +++ b/libs/gui/Surface.cpp @@ -261,7 +261,9 @@ int Surface::queueBuffer(android_native_buffer_t* buffer, int fenceFd) { Mutex::Autolock lock(mMutex); int64_t timestamp; if (mTimestamp == NATIVE_WINDOW_TIMESTAMP_AUTO) { - timestamp = 0; + timestamp = systemTime(SYSTEM_TIME_MONOTONIC); + ALOGV("Surface::queueBuffer making up timestamp: %.2f ms", + timestamp / 1000000.f); } else { timestamp = mTimestamp; } -- cgit v1.2.3-59-g8ed1b From db89edc94bd2a78226b407f9f7261e202e7fa325 Mon Sep 17 00:00:00 2001 From: Mathias Agopian Date: Fri, 2 Aug 2013 01:40:18 -0700 Subject: All consumers now take an IGraphicBufferConsumer instead of a BufferQueue this means they only have access to the consumer end of the interface. we had a lot of code that assumed consumers where holding a BufferQueue (i.e.: both ends), so most of this change is untangling in fix that Bug: 9265647 Change-Id: Ic2e2596ee14c7535f51bf26d9a897a0fc036d22c --- include/gui/BufferItemConsumer.h | 2 -- include/gui/BufferQueue.h | 7 +++--- include/gui/ConsumerBase.h | 15 ++++------- include/gui/CpuConsumer.h | 4 +-- include/gui/GLConsumer.h | 12 +-------- include/gui/IGraphicBufferConsumer.h | 3 +++ include/gui/SurfaceComposerClient.h | 1 + libs/gui/BufferItemConsumer.cpp | 10 ++++---- libs/gui/BufferQueue.cpp | 4 --- libs/gui/ConsumerBase.cpp | 26 ++++++++----------- libs/gui/CpuConsumer.cpp | 12 ++++----- libs/gui/GLConsumer.cpp | 16 ++++++------ libs/gui/IGraphicBufferConsumer.cpp | 20 ++++++++++++++- libs/gui/SurfaceComposerClient.cpp | 6 ++--- libs/gui/tests/CpuConsumer_test.cpp | 2 +- libs/gui/tests/SurfaceTextureClient_test.cpp | 4 +-- libs/gui/tests/SurfaceTexture_test.cpp | 8 +++--- libs/gui/tests/Surface_test.cpp | 4 +-- .../glgen/stubs/egl/eglCreateWindowSurface.cpp | 8 +++--- services/surfaceflinger/DisplayDevice.cpp | 3 ++- services/surfaceflinger/DisplayDevice.h | 1 + .../DisplayHardware/DisplaySurface.h | 2 -- .../DisplayHardware/FramebufferSurface.cpp | 19 ++++++-------- .../DisplayHardware/FramebufferSurface.h | 4 +-- .../DisplayHardware/VirtualDisplaySurface.cpp | 29 ++++++++-------------- .../DisplayHardware/VirtualDisplaySurface.h | 4 +-- services/surfaceflinger/Layer.cpp | 10 ++++---- services/surfaceflinger/Layer.h | 3 ++- services/surfaceflinger/SurfaceFlinger.cpp | 26 +++++++++++++++---- services/surfaceflinger/SurfaceFlingerConsumer.h | 2 +- 30 files changed, 132 insertions(+), 135 deletions(-) (limited to 'libs/gui/BufferQueue.cpp') diff --git a/include/gui/BufferItemConsumer.h b/include/gui/BufferItemConsumer.h index 9370e81e38..52edf17fe4 100644 --- a/include/gui/BufferItemConsumer.h +++ b/include/gui/BufferItemConsumer.h @@ -87,8 +87,6 @@ class BufferItemConsumer: public ConsumerBase status_t releaseBuffer(const BufferItem &item, const sp& releaseFence = Fence::NO_FENCE); - sp getProducerInterface() const { return getBufferQueue(); } - // setDefaultBufferSize is used to set the size of buffers returned by // requestBuffers when a with and height of zero is requested. status_t setDefaultBufferSize(uint32_t w, uint32_t h); diff --git a/include/gui/BufferQueue.h b/include/gui/BufferQueue.h index 1fbfc2b4ef..7e404fe842 100644 --- a/include/gui/BufferQueue.h +++ b/include/gui/BufferQueue.h @@ -78,10 +78,6 @@ public: BufferQueue(const sp& allocator = NULL); virtual ~BufferQueue(); - // dump our state in a String - virtual void dump(String8& result) const; - virtual void dump(String8& result, const char* prefix) const; - /* * IGraphicBufferProducer interface */ @@ -302,6 +298,9 @@ public: // NATIVE_WINDOW_TRANSFORM_ROT_90. The default is 0 (no transform). virtual status_t setTransformHint(uint32_t hint); + // dump our state in a String + virtual void dump(String8& result, const char* prefix) const; + private: // freeBufferLocked frees the GraphicBuffer and sync resources for the diff --git a/include/gui/ConsumerBase.h b/include/gui/ConsumerBase.h index daad75709a..fb21185fd7 100644 --- a/include/gui/ConsumerBase.h +++ b/include/gui/ConsumerBase.h @@ -66,10 +66,6 @@ public: // log messages. void setName(const String8& name); - // getBufferQueue returns the BufferQueue object to which this - // ConsumerBase is connected. - sp getBufferQueue() const; - // dump writes the current state to a string. Child classes should add // their state to the dump by overriding the dumpLocked method, which is // called by these methods after locking the mutex. @@ -85,12 +81,11 @@ private: void operator=(const ConsumerBase&); protected: - // ConsumerBase constructs a new ConsumerBase object to consume image - // buffers from the given BufferQueue. + // buffers from the given IGraphicBufferConsumer. // The controlledByApp flag indicates that this consumer is under the application's // control. - ConsumerBase(const sp &bufferQueue, bool controlledByApp = false); + ConsumerBase(const sp& consumer, bool controlledByApp = false); // onLastStrongRef gets called by RefBase just before the dtor of the most // derived class. It is used to clean up the buffers so that ConsumerBase @@ -104,7 +99,7 @@ protected: // from the derived class. virtual void onLastStrongRef(const void* id); - // Implementation of the BufferQueue::ConsumerListener interface. These + // Implementation of the IConsumerListener interface. These // calls are used to notify the ConsumerBase of asynchronous events in the // BufferQueue. These methods should not need to be overridden by derived // classes, but if they are overridden the ConsumerBase implementation @@ -155,7 +150,7 @@ protected: // initialization that must take place the first time a buffer is assigned // to a slot. If it is overridden the derived class's implementation must // call ConsumerBase::acquireBufferLocked. - virtual status_t acquireBufferLocked(BufferQueue::BufferItem *item, + virtual status_t acquireBufferLocked(IGraphicBufferConsumer::BufferItem *item, nsecs_t presentWhen); // releaseBufferLocked relinquishes control over a buffer, returning that @@ -226,7 +221,7 @@ protected: // The ConsumerBase has-a BufferQueue and is responsible for creating this object // if none is supplied - sp mBufferQueue; + sp mConsumer; // mMutex is the mutex used to prevent concurrent access to the member // variables of ConsumerBase objects. It must be locked whenever the diff --git a/include/gui/CpuConsumer.h b/include/gui/CpuConsumer.h index 28903508b3..9290676caa 100644 --- a/include/gui/CpuConsumer.h +++ b/include/gui/CpuConsumer.h @@ -66,7 +66,7 @@ class CpuConsumer : public ConsumerBase // Create a new CPU consumer. The maxLockedBuffers parameter specifies // how many buffers can be locked for user access at the same time. - CpuConsumer(const sp& bq, + CpuConsumer(const sp& bq, uint32_t maxLockedBuffers, bool controlledByApp = false); virtual ~CpuConsumer(); @@ -104,8 +104,6 @@ class CpuConsumer : public ConsumerBase // lockNextBuffer. status_t unlockBuffer(const LockedBuffer &nativeBuffer); - sp getProducerInterface() const { return getBufferQueue(); } - private: // Maximum number of buffers that can be locked at a time uint32_t mMaxLockedBuffers; diff --git a/include/gui/GLConsumer.h b/include/gui/GLConsumer.h index ac4a8328be..4c9aa87514 100644 --- a/include/gui/GLConsumer.h +++ b/include/gui/GLConsumer.h @@ -32,10 +32,6 @@ #include #include -#define ANDROID_GRAPHICS_SURFACETEXTURE_JNI_ID "mSurfaceTexture" -#define ANDROID_GRAPHICS_FRAMEAVAILABLELISTENER_JNI_ID \ - "mFrameAvailableListener" - namespace android { // ---------------------------------------------------------------------------- @@ -85,7 +81,7 @@ public: // purely to allow a GLConsumer to be transferred from one consumer // context to another. If such a transfer is not needed there is no // requirement that either of these methods be called. - GLConsumer(const sp& bq, + GLConsumer(const sp& bq, GLuint tex, GLenum texTarget = GL_TEXTURE_EXTERNAL_OES, bool useFenceSync = true, bool isControlledByApp = false); @@ -194,12 +190,6 @@ public: status_t setConsumerUsageBits(uint32_t usage); status_t setTransformHint(uint32_t hint); - // getBufferQueue returns the BufferQueue object to which this - // GLConsumer is connected. - sp getBufferQueue() const { - return mBufferQueue; - } - // detachFromContext detaches the GLConsumer from the calling thread's // current OpenGL ES context. This context must be the same as the context // that was current for previous calls to updateTexImage. diff --git a/include/gui/IGraphicBufferConsumer.h b/include/gui/IGraphicBufferConsumer.h index 82b50c8abd..2ad302f480 100644 --- a/include/gui/IGraphicBufferConsumer.h +++ b/include/gui/IGraphicBufferConsumer.h @@ -188,6 +188,9 @@ public: // NATIVE_WINDOW_TRANSFORM_ROT_90. The default is 0 (no transform). virtual status_t setTransformHint(uint32_t hint) = 0; + // dump state into a string + virtual void dump(String8& result, const char* prefix) const = 0; + public: DECLARE_META_INTERFACE(GraphicBufferConsumer); }; diff --git a/include/gui/SurfaceComposerClient.h b/include/gui/SurfaceComposerClient.h index 6bf5b47f99..643d7cff72 100644 --- a/include/gui/SurfaceComposerClient.h +++ b/include/gui/SurfaceComposerClient.h @@ -165,6 +165,7 @@ public: private: mutable sp mCpuConsumer; + mutable sp mBufferQueue; CpuConsumer::LockedBuffer mBuffer; bool mHaveBuffer; diff --git a/libs/gui/BufferItemConsumer.cpp b/libs/gui/BufferItemConsumer.cpp index 0f818b76ff..350887a1f7 100644 --- a/libs/gui/BufferItemConsumer.cpp +++ b/libs/gui/BufferItemConsumer.cpp @@ -33,8 +33,8 @@ BufferItemConsumer::BufferItemConsumer(const sp& bq, uint32_t consumerUsage, int bufferCount, bool controlledByApp) : ConsumerBase(bq, controlledByApp) { - mBufferQueue->setConsumerUsageBits(consumerUsage); - mBufferQueue->setMaxAcquiredBufferCount(bufferCount); + mConsumer->setConsumerUsageBits(consumerUsage); + mConsumer->setMaxAcquiredBufferCount(bufferCount); } BufferItemConsumer::~BufferItemConsumer() { @@ -43,7 +43,7 @@ BufferItemConsumer::~BufferItemConsumer() { void BufferItemConsumer::setName(const String8& name) { Mutex::Autolock _l(mMutex); mName = name; - mBufferQueue->setConsumerName(name); + mConsumer->setConsumerName(name); } status_t BufferItemConsumer::acquireBuffer(BufferItem *item, @@ -95,12 +95,12 @@ status_t BufferItemConsumer::releaseBuffer(const BufferItem &item, status_t BufferItemConsumer::setDefaultBufferSize(uint32_t w, uint32_t h) { Mutex::Autolock _l(mMutex); - return mBufferQueue->setDefaultBufferSize(w, h); + return mConsumer->setDefaultBufferSize(w, h); } status_t BufferItemConsumer::setDefaultBufferFormat(uint32_t defaultFormat) { Mutex::Autolock _l(mMutex); - return mBufferQueue->setDefaultBufferFormat(defaultFormat); + return mConsumer->setDefaultBufferFormat(defaultFormat); } } // namespace android diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp index 07c2d943a4..033c2a6c45 100644 --- a/libs/gui/BufferQueue.cpp +++ b/libs/gui/BufferQueue.cpp @@ -720,10 +720,6 @@ status_t BufferQueue::disconnect(int api) { return err; } -void BufferQueue::dump(String8& result) const { - BufferQueue::dump(result, ""); -} - void BufferQueue::dump(String8& result, const char* prefix) const { Mutex::Autolock _l(mMutex); diff --git a/libs/gui/ConsumerBase.cpp b/libs/gui/ConsumerBase.cpp index d748786d98..c4ec8578a8 100644 --- a/libs/gui/ConsumerBase.cpp +++ b/libs/gui/ConsumerBase.cpp @@ -51,9 +51,9 @@ static int32_t createProcessUniqueId() { return android_atomic_inc(&globalCounter); } -ConsumerBase::ConsumerBase(const sp& bufferQueue, bool controlledByApp) : +ConsumerBase::ConsumerBase(const sp& bufferQueue, bool controlledByApp) : mAbandoned(false), - mBufferQueue(bufferQueue) { + mConsumer(bufferQueue) { // Choose a name using the PID and a process-unique ID. mName = String8::format("unnamed-%d-%d", getpid(), createProcessUniqueId()); @@ -64,12 +64,12 @@ ConsumerBase::ConsumerBase(const sp& bufferQueue, bool controlledBy wp listener = static_cast(this); sp proxy = new BufferQueue::ProxyConsumerListener(listener); - status_t err = mBufferQueue->consumerConnect(proxy, controlledByApp); + status_t err = mConsumer->consumerConnect(proxy, controlledByApp); if (err != NO_ERROR) { CB_LOGE("ConsumerBase: error connecting to BufferQueue: %s (%d)", strerror(-err), err); } else { - mBufferQueue->setConsumerName(mName); + mConsumer->setConsumerName(mName); } } @@ -96,12 +96,6 @@ void ConsumerBase::freeBufferLocked(int slotIndex) { mSlots[slotIndex].mFrameNumber = 0; } -// Used for refactoring, should not be in final interface -sp ConsumerBase::getBufferQueue() const { - Mutex::Autolock lock(mMutex); - return mBufferQueue; -} - void ConsumerBase::onFrameAvailable() { CB_LOGV("onFrameAvailable"); @@ -128,7 +122,7 @@ void ConsumerBase::onBuffersReleased() { } uint32_t mask = 0; - mBufferQueue->getReleasedBuffers(&mask); + mConsumer->getReleasedBuffers(&mask); for (int i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) { if (mask & (1 << i)) { freeBufferLocked(i); @@ -152,8 +146,8 @@ void ConsumerBase::abandonLocked() { freeBufferLocked(i); } // disconnect from the BufferQueue - mBufferQueue->consumerDisconnect(); - mBufferQueue.clear(); + mConsumer->consumerDisconnect(); + mConsumer.clear(); } void ConsumerBase::setFrameAvailableListener( @@ -176,13 +170,13 @@ void ConsumerBase::dumpLocked(String8& result, const char* prefix) const { result.appendFormat("%smAbandoned=%d\n", prefix, int(mAbandoned)); if (!mAbandoned) { - mBufferQueue->dump(result, prefix); + mConsumer->dump(result, prefix); } } status_t ConsumerBase::acquireBufferLocked(BufferQueue::BufferItem *item, nsecs_t presentWhen) { - status_t err = mBufferQueue->acquireBuffer(item, presentWhen); + status_t err = mConsumer->acquireBuffer(item, presentWhen); if (err != NO_ERROR) { return err; } @@ -247,7 +241,7 @@ status_t ConsumerBase::releaseBufferLocked( CB_LOGV("releaseBufferLocked: slot=%d/%llu", slot, mSlots[slot].mFrameNumber); - status_t err = mBufferQueue->releaseBuffer(slot, mSlots[slot].mFrameNumber, + status_t err = mConsumer->releaseBuffer(slot, mSlots[slot].mFrameNumber, display, eglFence, mSlots[slot].mFence); if (err == BufferQueue::STALE_BUFFER_SLOT) { freeBufferLocked(slot); diff --git a/libs/gui/CpuConsumer.cpp b/libs/gui/CpuConsumer.cpp index b8c00af0a7..3db46bceb8 100644 --- a/libs/gui/CpuConsumer.cpp +++ b/libs/gui/CpuConsumer.cpp @@ -30,7 +30,7 @@ namespace android { -CpuConsumer::CpuConsumer(const sp& bq, +CpuConsumer::CpuConsumer(const sp& bq, uint32_t maxLockedBuffers, bool controlledByApp) : ConsumerBase(bq, controlledByApp), mMaxLockedBuffers(maxLockedBuffers), @@ -39,8 +39,8 @@ CpuConsumer::CpuConsumer(const sp& bq, // Create tracking entries for locked buffers mAcquiredBuffers.insertAt(0, maxLockedBuffers); - mBufferQueue->setConsumerUsageBits(GRALLOC_USAGE_SW_READ_OFTEN); - mBufferQueue->setMaxAcquiredBufferCount(maxLockedBuffers); + mConsumer->setConsumerUsageBits(GRALLOC_USAGE_SW_READ_OFTEN); + mConsumer->setMaxAcquiredBufferCount(maxLockedBuffers); } CpuConsumer::~CpuConsumer() { @@ -52,19 +52,19 @@ CpuConsumer::~CpuConsumer() { void CpuConsumer::setName(const String8& name) { Mutex::Autolock _l(mMutex); mName = name; - mBufferQueue->setConsumerName(name); + mConsumer->setConsumerName(name); } status_t CpuConsumer::setDefaultBufferSize(uint32_t width, uint32_t height) { Mutex::Autolock _l(mMutex); - return mBufferQueue->setDefaultBufferSize(width, height); + return mConsumer->setDefaultBufferSize(width, height); } status_t CpuConsumer::setDefaultBufferFormat(uint32_t defaultFormat) { Mutex::Autolock _l(mMutex); - return mBufferQueue->setDefaultBufferFormat(defaultFormat); + return mConsumer->setDefaultBufferFormat(defaultFormat); } status_t CpuConsumer::lockNextBuffer(LockedBuffer *nativeBuffer) { diff --git a/libs/gui/GLConsumer.cpp b/libs/gui/GLConsumer.cpp index b8a3d286f3..363e25a16a 100644 --- a/libs/gui/GLConsumer.cpp +++ b/libs/gui/GLConsumer.cpp @@ -85,7 +85,7 @@ static float mtxRot90[16] = { static void mtxMul(float out[16], const float a[16], const float b[16]); -GLConsumer::GLConsumer(const sp& bq, GLuint tex, +GLConsumer::GLConsumer(const sp& bq, GLuint tex, GLenum texTarget, bool useFenceSync, bool isControlledByApp) : ConsumerBase(bq, isControlledByApp), mCurrentTransform(0), @@ -108,12 +108,12 @@ GLConsumer::GLConsumer(const sp& bq, GLuint tex, memcpy(mCurrentTransformMatrix, mtxIdentity, sizeof(mCurrentTransformMatrix)); - mBufferQueue->setConsumerUsageBits(DEFAULT_USAGE_FLAGS); + mConsumer->setConsumerUsageBits(DEFAULT_USAGE_FLAGS); } status_t GLConsumer::setDefaultMaxBufferCount(int bufferCount) { Mutex::Autolock lock(mMutex); - return mBufferQueue->setDefaultMaxBufferCount(bufferCount); + return mConsumer->setDefaultMaxBufferCount(bufferCount); } @@ -122,7 +122,7 @@ status_t GLConsumer::setDefaultBufferSize(uint32_t w, uint32_t h) Mutex::Autolock lock(mMutex); mDefaultWidth = w; mDefaultHeight = h; - return mBufferQueue->setDefaultBufferSize(w, h); + return mConsumer->setDefaultBufferSize(w, h); } status_t GLConsumer::updateTexImage() { @@ -946,23 +946,23 @@ void GLConsumer::abandonLocked() { void GLConsumer::setName(const String8& name) { Mutex::Autolock _l(mMutex); mName = name; - mBufferQueue->setConsumerName(name); + mConsumer->setConsumerName(name); } status_t GLConsumer::setDefaultBufferFormat(uint32_t defaultFormat) { Mutex::Autolock lock(mMutex); - return mBufferQueue->setDefaultBufferFormat(defaultFormat); + return mConsumer->setDefaultBufferFormat(defaultFormat); } status_t GLConsumer::setConsumerUsageBits(uint32_t usage) { Mutex::Autolock lock(mMutex); usage |= DEFAULT_USAGE_FLAGS; - return mBufferQueue->setConsumerUsageBits(usage); + return mConsumer->setConsumerUsageBits(usage); } status_t GLConsumer::setTransformHint(uint32_t hint) { Mutex::Autolock lock(mMutex); - return mBufferQueue->setTransformHint(hint); + return mConsumer->setTransformHint(hint); } void GLConsumer::dumpLocked(String8& result, const char* prefix) const diff --git a/libs/gui/IGraphicBufferConsumer.cpp b/libs/gui/IGraphicBufferConsumer.cpp index 526328146d..6d65016cf0 100644 --- a/libs/gui/IGraphicBufferConsumer.cpp +++ b/libs/gui/IGraphicBufferConsumer.cpp @@ -186,7 +186,8 @@ enum { SET_CONSUMER_NAME, SET_DEFAULT_BUFFER_FORMAT, SET_CONSUMER_USAGE_BITS, - SET_TRANSFORM_HINT + SET_TRANSFORM_HINT, + DUMP, }; @@ -344,6 +345,15 @@ public: } return reply.readInt32(); } + + virtual void dump(String8& result, const char* prefix) const { + Parcel data, reply; + data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor()); + data.writeString8(result); + data.writeString8(String8(prefix ? prefix : "")); + remote()->transact(DUMP, data, &reply); + reply.readString8(); + } }; IMPLEMENT_META_INTERFACE(GraphicBufferConsumer, "android.gui.IGraphicBufferConsumer"); @@ -452,6 +462,14 @@ status_t BnGraphicBufferConsumer::onTransact( reply->writeInt32(result); return NO_ERROR; } break; + case DUMP: { + CHECK_INTERFACE(IGraphicBufferConsumer, data, reply); + String8 result = data.readString8(); + String8 prefix = data.readString8(); + static_cast(this)->dump(result, prefix); + reply->writeString8(result); + return NO_ERROR; + } } return BBinder::onTransact(code, data, reply, flags); } diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index bad4138832..048553c7eb 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -633,8 +633,8 @@ ScreenshotClient::~ScreenshotClient() { sp ScreenshotClient::getCpuConsumer() const { if (mCpuConsumer == NULL) { - sp bq = new BufferQueue(); - mCpuConsumer = new CpuConsumer(bq, 1); + mBufferQueue = new BufferQueue(); + mCpuConsumer = new CpuConsumer(mBufferQueue, 1); mCpuConsumer->setName(String8("ScreenshotClient")); } return mCpuConsumer; @@ -653,7 +653,7 @@ status_t ScreenshotClient::update(const sp& display, mHaveBuffer = false; } - status_t err = s->captureScreen(display, cpuConsumer->getBufferQueue(), + status_t err = s->captureScreen(display, mBufferQueue, reqWidth, reqHeight, minLayerZ, maxLayerZ, true); if (err == NO_ERROR) { diff --git a/libs/gui/tests/CpuConsumer_test.cpp b/libs/gui/tests/CpuConsumer_test.cpp index f8a35b49e6..afbc026969 100644 --- a/libs/gui/tests/CpuConsumer_test.cpp +++ b/libs/gui/tests/CpuConsumer_test.cpp @@ -70,7 +70,7 @@ protected: mCC = new CpuConsumer(bq, params.maxLockedBuffers); String8 name("CpuConsumer_Under_Test"); mCC->setName(name); - mSTC = new Surface(mCC->getProducerInterface()); + mSTC = new Surface(bq); mANW = mSTC; } diff --git a/libs/gui/tests/SurfaceTextureClient_test.cpp b/libs/gui/tests/SurfaceTextureClient_test.cpp index 1de9c27921..459b00116a 100644 --- a/libs/gui/tests/SurfaceTextureClient_test.cpp +++ b/libs/gui/tests/SurfaceTextureClient_test.cpp @@ -42,7 +42,7 @@ protected: sp bq = new BufferQueue(); mST = new GLConsumer(bq, 123); - mSTC = new Surface(mST->getBufferQueue()); + mSTC = new Surface(bq); mANW = mSTC; // We need a valid GL context so we can test updateTexImage() @@ -710,7 +710,7 @@ protected: for (int i = 0; i < NUM_SURFACE_TEXTURES; i++) { sp bq = new BufferQueue(); sp st(new GLConsumer(bq, i)); - sp stc(new Surface(st->getBufferQueue())); + sp stc(new Surface(bq)); mEglSurfaces[i] = eglCreateWindowSurface(mEglDisplay, myConfig, static_cast(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 ae223c6d8e..05b0b670c6 100644 --- a/libs/gui/tests/SurfaceTexture_test.cpp +++ b/libs/gui/tests/SurfaceTexture_test.cpp @@ -387,7 +387,7 @@ protected: GLTest::SetUp(); sp bq = new BufferQueue(); mGlConsumer = new GLConsumer(bq, TEX_ID); - mSurface = new Surface(mGlConsumer->getBufferQueue()); + mSurface = new Surface(bq); mANW = mSurface.get(); } @@ -481,8 +481,9 @@ protected: virtual void SetUp() { GLTest::SetUp(); sp bq = new BufferQueue(); + mBQ = bq; mST = new GLConsumer(bq, TEX_ID); - mSTC = new Surface(mST->getBufferQueue()); + mSTC = new Surface(bq); mANW = mSTC; mTextureRenderer = new TextureRenderer(TEX_ID, mST); ASSERT_NO_FATAL_FAILURE(mTextureRenderer->SetUp()); @@ -672,6 +673,7 @@ protected: Condition mFrameCondition; }; + sp mBQ; sp mST; sp mSTC; sp mANW; @@ -1211,7 +1213,7 @@ TEST_F(SurfaceTextureGLTest, DisconnectStressTest) { }; sp dw(new DisconnectWaiter()); - mST->getBufferQueue()->consumerConnect(dw, false); + mBQ->consumerConnect(dw, false); sp pt(new ProducerThread(mANW)); diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index bcdbedbaac..0440c4c3ba 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -92,7 +92,7 @@ TEST_F(SurfaceTest, ScreenshotsOfProtectedBuffersSucceed) { sp consumer = new CpuConsumer(bq, 1); sp sf(ComposerService::getComposerService()); sp display(sf->getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain)); - ASSERT_EQ(NO_ERROR, sf->captureScreen(display, consumer->getBufferQueue(), + ASSERT_EQ(NO_ERROR, sf->captureScreen(display, bq, 64, 64, 0, 0x7fffffff, true)); // Set the PROTECTED usage bit and verify that the screenshot fails. Note @@ -121,7 +121,7 @@ TEST_F(SurfaceTest, ScreenshotsOfProtectedBuffersSucceed) { &buf)); ASSERT_EQ(NO_ERROR, anw->queueBuffer(anw.get(), buf, -1)); } - ASSERT_EQ(NO_ERROR, sf->captureScreen(display, consumer->getBufferQueue(), + ASSERT_EQ(NO_ERROR, sf->captureScreen(display, bq, 64, 64, 0, 0x7fffffff, true)); } diff --git a/opengl/tools/glgen/stubs/egl/eglCreateWindowSurface.cpp b/opengl/tools/glgen/stubs/egl/eglCreateWindowSurface.cpp index 906cd80fbb..0cfd8863d3 100644 --- a/opengl/tools/glgen/stubs/egl/eglCreateWindowSurface.cpp +++ b/opengl/tools/glgen/stubs/egl/eglCreateWindowSurface.cpp @@ -90,7 +90,7 @@ android_eglCreateWindowSurfaceTexture jint _remaining; EGLint *attrib_list = (EGLint *) 0; android::sp window; - android::sp glConsumer; + android::sp producer; if (!attrib_list_ref) { _exception = 1; @@ -111,12 +111,12 @@ not_valid_surface: _exceptionMessage = "Make sure the SurfaceView or associated SurfaceHolder has a valid Surface"; goto exit; } - glConsumer = android::SurfaceTexture_getSurfaceTexture(_env, win); + producer = android::SurfaceTexture_getProducer(_env, win); - if (glConsumer == NULL) + if (producer == NULL) goto not_valid_surface; - window = new android::Surface(glConsumer->getBufferQueue()); + window = new android::Surface(producer); if (window == NULL) goto not_valid_surface; diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp index c67f4d8f83..391131d16b 100644 --- a/services/surfaceflinger/DisplayDevice.cpp +++ b/services/surfaceflinger/DisplayDevice.cpp @@ -56,6 +56,7 @@ DisplayDevice::DisplayDevice( bool isSecure, const wp& displayToken, const sp& displaySurface, + const sp& producer, EGLConfig config) : mFlinger(flinger), mType(type), mHwcDisplayId(hwcId), @@ -73,7 +74,7 @@ DisplayDevice::DisplayDevice( mLayerStack(NO_LAYER_STACK), mOrientation() { - mNativeWindow = new Surface(mDisplaySurface->getIGraphicBufferProducer()); + mNativeWindow = new Surface(producer); ANativeWindow* const window = mNativeWindow.get(); int format; diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h index 748be1ab59..ecf855a79a 100644 --- a/services/surfaceflinger/DisplayDevice.h +++ b/services/surfaceflinger/DisplayDevice.h @@ -76,6 +76,7 @@ public: bool isSecure, const wp& displayToken, const sp& displaySurface, + const sp& producer, EGLConfig config); ~DisplayDevice(); diff --git a/services/surfaceflinger/DisplayHardware/DisplaySurface.h b/services/surfaceflinger/DisplayHardware/DisplaySurface.h index b0f460d30c..9192db5ba9 100644 --- a/services/surfaceflinger/DisplayHardware/DisplaySurface.h +++ b/services/surfaceflinger/DisplayHardware/DisplaySurface.h @@ -30,8 +30,6 @@ class String8; class DisplaySurface : public virtual RefBase { public: - virtual sp getIGraphicBufferProducer() const = 0; - // prepareFrame is called after the composition configuration is known but // before composition takes place. The DisplaySurface can use the // composition type to decide how to manage the flow of buffers between diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp index 419b81cd4f..807d4e17fa 100644 --- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp +++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp @@ -50,25 +50,22 @@ namespace android { * */ -FramebufferSurface::FramebufferSurface(HWComposer& hwc, int disp) : - ConsumerBase(new BufferQueue(new GraphicBufferAlloc())), +FramebufferSurface::FramebufferSurface(HWComposer& hwc, int disp, + const sp& consumer) : + ConsumerBase(consumer), mDisplayType(disp), mCurrentBufferSlot(-1), mCurrentBuffer(0), mHwc(hwc) { mName = "FramebufferSurface"; - mBufferQueue->setConsumerName(mName); - mBufferQueue->setConsumerUsageBits(GRALLOC_USAGE_HW_FB | + mConsumer->setConsumerName(mName); + mConsumer->setConsumerUsageBits(GRALLOC_USAGE_HW_FB | GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_COMPOSER); - mBufferQueue->setDefaultBufferFormat(mHwc.getFormat(disp)); - mBufferQueue->setDefaultBufferSize(mHwc.getWidth(disp), mHwc.getHeight(disp)); - mBufferQueue->setDefaultMaxBufferCount(NUM_FRAMEBUFFER_SURFACE_BUFFERS); -} - -sp FramebufferSurface::getIGraphicBufferProducer() const { - return getBufferQueue(); + mConsumer->setDefaultBufferFormat(mHwc.getFormat(disp)); + mConsumer->setDefaultBufferSize(mHwc.getWidth(disp), mHwc.getHeight(disp)); + mConsumer->setDefaultMaxBufferCount(NUM_FRAMEBUFFER_SURFACE_BUFFERS); } status_t FramebufferSurface::prepareFrame(CompositionType compositionType) { diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.h b/services/surfaceflinger/DisplayHardware/FramebufferSurface.h index 92a7f9b1e1..fcda287174 100644 --- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.h +++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.h @@ -37,9 +37,7 @@ class HWComposer; class FramebufferSurface : public ConsumerBase, public DisplaySurface { public: - FramebufferSurface(HWComposer& hwc, int disp); - - virtual sp getIGraphicBufferProducer() const; + FramebufferSurface(HWComposer& hwc, int disp, const sp& consumer); virtual status_t prepareFrame(CompositionType compositionType); virtual status_t compositionComplete(); diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp index 57cb361710..30b00845b3 100644 --- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp +++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp @@ -40,8 +40,10 @@ static const char* dbgCompositionTypeStr(DisplaySurface::CompositionType type) { } VirtualDisplaySurface::VirtualDisplaySurface(HWComposer& hwc, int32_t dispId, - const sp& sink, const String8& name) -: ConsumerBase(new BufferQueue()), + const sp& sink, + const sp& bq, + const String8& name) +: ConsumerBase(bq), mHwc(hwc), mDisplayId(dispId), mDisplayName(name), @@ -51,7 +53,7 @@ VirtualDisplaySurface::VirtualDisplaySurface(HWComposer& hwc, int32_t dispId, mDbgLastCompositionType(COMPOSITION_UNKNOWN) { mSource[SOURCE_SINK] = sink; - mSource[SOURCE_SCRATCH] = mBufferQueue; + mSource[SOURCE_SCRATCH] = bq; resetPerFrameState(); @@ -60,26 +62,15 @@ VirtualDisplaySurface::VirtualDisplaySurface(HWComposer& hwc, int32_t dispId, mSource[SOURCE_SINK]->query(NATIVE_WINDOW_HEIGHT, &sinkHeight); ConsumerBase::mName = String8::format("VDS: %s", mDisplayName.string()); - mBufferQueue->setConsumerName(ConsumerBase::mName); - mBufferQueue->setConsumerUsageBits(GRALLOC_USAGE_HW_COMPOSER); - mBufferQueue->setDefaultBufferSize(sinkWidth, sinkHeight); - mBufferQueue->setDefaultMaxBufferCount(2); + mConsumer->setConsumerName(ConsumerBase::mName); + mConsumer->setConsumerUsageBits(GRALLOC_USAGE_HW_COMPOSER); + mConsumer->setDefaultBufferSize(sinkWidth, sinkHeight); + mConsumer->setDefaultMaxBufferCount(2); } VirtualDisplaySurface::~VirtualDisplaySurface() { } -sp VirtualDisplaySurface::getIGraphicBufferProducer() const { - if (mDisplayId >= 0) { - return static_cast( - const_cast(this)); - } else { - // There won't be any interaction with HWC for this virtual display, - // so the GLES driver can pass buffers directly to the sink. - return mSource[SOURCE_SINK]; - } -} - status_t VirtualDisplaySurface::prepareFrame(CompositionType compositionType) { if (mDisplayId < 0) return NO_ERROR; @@ -294,7 +285,7 @@ status_t VirtualDisplaySurface::queueBuffer(int pslot, // Queue the buffer back into the scratch pool QueueBufferOutput scratchQBO; int sslot = mapProducer2SourceSlot(SOURCE_SCRATCH, pslot); - result = mBufferQueue->queueBuffer(sslot, input, &scratchQBO); + result = mSource[SOURCE_SCRATCH]->queueBuffer(sslot, input, &scratchQBO); if (result != NO_ERROR) return result; diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h index dc9655b626..64a8dce288 100644 --- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h +++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h @@ -68,17 +68,17 @@ class HWComposer; * is released and the output buffer is queued to the sink. */ class VirtualDisplaySurface : public DisplaySurface, - private BnGraphicBufferProducer, + public BnGraphicBufferProducer, private ConsumerBase { public: VirtualDisplaySurface(HWComposer& hwc, int32_t dispId, const sp& sink, + const sp& bq, const String8& name); // // DisplaySurface interface // - virtual sp getIGraphicBufferProducer() const; virtual status_t prepareFrame(CompositionType compositionType); virtual status_t compositionComplete(); virtual status_t advanceFrame(); diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 401b0f3ff1..2defe34db5 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -113,8 +113,8 @@ Layer::Layer(SurfaceFlinger* flinger, const sp& client, void Layer::onFirstRef() { // Creates a custom BufferQueue for SurfaceFlingerConsumer to use - sp bq = new SurfaceTextureLayer(mFlinger); - mSurfaceFlingerConsumer = new SurfaceFlingerConsumer(bq, mTextureName, + mBufferQueue = new SurfaceTextureLayer(mFlinger); + mSurfaceFlingerConsumer = new SurfaceFlingerConsumer(mBufferQueue, mTextureName, GL_TEXTURE_EXTERNAL_OES, false); mSurfaceFlingerConsumer->setConsumerUsageBits(getEffectiveUsage(0)); @@ -228,8 +228,8 @@ sp Layer::getHandle() { return new Handle(mFlinger, this); } -sp Layer::getBufferQueue() const { - return mSurfaceFlingerConsumer->getBufferQueue(); +sp Layer::getBufferQueue() const { + return mBufferQueue; } // --------------------------------------------------------------------------- @@ -926,7 +926,7 @@ Region Layer::latchBuffer(bool& recomputeVisibleRegions) } virtual bool reject(const sp& buf, - const BufferQueue::BufferItem& item) { + const IGraphicBufferConsumer::BufferItem& item) { if (buf == NULL) { return false; } diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 9093116b0f..8332a5af1e 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -154,7 +154,7 @@ public: Rect computeBounds() const; sp getHandle(); - sp getBufferQueue() const; + sp getBufferQueue() const; const String8& getName() const; // ----------------------------------------------------------------------- @@ -344,6 +344,7 @@ private: // constants sp mSurfaceFlingerConsumer; + sp mBufferQueue; GLuint mTextureName; bool mPremultipliedAlpha; String8 mName; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index b0e4002579..864dc3ef46 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -451,9 +451,11 @@ status_t SurfaceFlinger::readyToRun() createBuiltinDisplayLocked(type); wp token = mBuiltinDisplays[i]; + sp bq = new BufferQueue(new GraphicBufferAlloc()); + sp fbs = new FramebufferSurface(*mHwc, i, bq); sp hw = new DisplayDevice(this, type, allocateHwcDisplayId(type), isSecure, token, - new FramebufferSurface(*mHwc, i), + fbs, bq, mEGLConfig); if (i > DisplayDevice::DISPLAY_PRIMARY) { // FIXME: currently we don't get blank/unblank requests @@ -1101,16 +1103,29 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags) const DisplayDeviceState& state(curr[i]); sp dispSurface; + sp producer; + sp bq = new BufferQueue(new GraphicBufferAlloc()); + int32_t hwcDisplayId = -1; if (state.isVirtualDisplay()) { // Virtual displays without a surface are dormant: // they have external state (layer stack, projection, // etc.) but no internal state (i.e. a DisplayDevice). if (state.surface != NULL) { + hwcDisplayId = allocateHwcDisplayId(state.type); - dispSurface = new VirtualDisplaySurface( - *mHwc, hwcDisplayId, state.surface, + sp vds = new VirtualDisplaySurface( + *mHwc, hwcDisplayId, state.surface, bq, state.displayName); + + dispSurface = vds; + if (hwcDisplayId >= 0) { + producer = vds; + } else { + // There won't be any interaction with HWC for this virtual display, + // so the GLES driver can pass buffers directly to the sink. + producer = state.surface; + } } } else { ALOGE_IF(state.surface!=NULL, @@ -1120,14 +1135,15 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags) hwcDisplayId = allocateHwcDisplayId(state.type); // for supported (by hwc) displays we provide our // own rendering surface - dispSurface = new FramebufferSurface(*mHwc, state.type); + dispSurface = new FramebufferSurface(*mHwc, state.type, bq); + producer = bq; } const wp& display(curr.keyAt(i)); if (dispSurface != NULL) { sp hw = new DisplayDevice(this, state.type, hwcDisplayId, state.isSecure, - display, dispSurface, mEGLConfig); + display, dispSurface, producer, mEGLConfig); hw->setLayerStack(state.layerStack); hw->setProjection(state.orientation, state.viewport, state.frame); diff --git a/services/surfaceflinger/SurfaceFlingerConsumer.h b/services/surfaceflinger/SurfaceFlingerConsumer.h index 5de6d129c2..aa2b37fae0 100644 --- a/services/surfaceflinger/SurfaceFlingerConsumer.h +++ b/services/surfaceflinger/SurfaceFlingerConsumer.h @@ -36,7 +36,7 @@ public: class BufferRejecter { friend class SurfaceFlingerConsumer; virtual bool reject(const sp& buf, - const BufferQueue::BufferItem& item) = 0; + const IGraphicBufferConsumer::BufferItem& item) = 0; protected: virtual ~BufferRejecter() { } -- cgit v1.2.3-59-g8ed1b From 3c25621ad7d13f64d3ab95a27fa970fbc9998f73 Mon Sep 17 00:00:00 2001 From: Andy McFadden Date: Fri, 16 Aug 2013 14:55:39 -0700 Subject: Re-enable frame dropping for non-auto timestamps This change adds an entire field to note whether the timestamp was auto-generated by Surface or supplied by the application. The value is used when deciding whether or not to drop frames based on buffer presentation timestamps. If a desired presentation time was set explicitly, BufferQueue will use that value to decide if a frame should be dropped. If the timestamp was generated by Surface at the time the buffer was queued, the timestamp is ignored. Bug 10151804 Change-Id: Ibd571a7578351063b813cbdad2ddbeed70655ba5 --- include/gui/IGraphicBufferConsumer.h | 4 ++++ include/gui/IGraphicBufferProducer.h | 15 +++++++++------ libs/gui/BufferQueue.cpp | 12 ++++++++++-- libs/gui/IGraphicBufferConsumer.cpp | 4 ++++ libs/gui/IGraphicBufferProducer.cpp | 4 ++++ libs/gui/Surface.cpp | 6 ++++-- .../DisplayHardware/VirtualDisplaySurface.cpp | 7 ++++--- 7 files changed, 39 insertions(+), 13 deletions(-) (limited to 'libs/gui/BufferQueue.cpp') diff --git a/include/gui/IGraphicBufferConsumer.h b/include/gui/IGraphicBufferConsumer.h index 2ad302f480..3327b37720 100644 --- a/include/gui/IGraphicBufferConsumer.h +++ b/include/gui/IGraphicBufferConsumer.h @@ -72,6 +72,10 @@ public: // to set by queueBuffer each time this slot is queued. int64_t mTimestamp; + // mIsAutoTimestamp indicates whether mTimestamp was generated + // automatically when the buffer was queued. + bool mIsAutoTimestamp; + // mFrameNumber is the number of the queued frame for this slot. uint64_t mFrameNumber; diff --git a/include/gui/IGraphicBufferProducer.h b/include/gui/IGraphicBufferProducer.h index 033c7273c6..c3ede5ef74 100644 --- a/include/gui/IGraphicBufferProducer.h +++ b/include/gui/IGraphicBufferProducer.h @@ -108,15 +108,17 @@ public: struct QueueBufferInput : public Flattenable { friend class Flattenable; inline QueueBufferInput(const Parcel& parcel); - inline QueueBufferInput(int64_t timestamp, + inline QueueBufferInput(int64_t timestamp, bool isAutoTimestamp, const Rect& crop, int scalingMode, uint32_t transform, bool async, const sp& fence) - : timestamp(timestamp), crop(crop), scalingMode(scalingMode), - transform(transform), async(async), fence(fence) { } - inline void deflate(int64_t* outTimestamp, Rect* outCrop, - int* outScalingMode, uint32_t* outTransform, bool* outAsync, - sp* outFence) const { + : timestamp(timestamp), isAutoTimestamp(isAutoTimestamp), crop(crop), + scalingMode(scalingMode), transform(transform), async(async), + fence(fence) { } + inline void deflate(int64_t* outTimestamp, bool* outIsAutoTimestamp, + Rect* outCrop, int* outScalingMode, uint32_t* outTransform, + bool* outAsync, sp* outFence) const { *outTimestamp = timestamp; + *outIsAutoTimestamp = bool(isAutoTimestamp); *outCrop = crop; *outScalingMode = scalingMode; *outTransform = transform; @@ -132,6 +134,7 @@ public: private: int64_t timestamp; + int isAutoTimestamp; Rect crop; int scalingMode; uint32_t transform; diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp index 033c2a6c45..65007fa24a 100644 --- a/libs/gui/BufferQueue.cpp +++ b/libs/gui/BufferQueue.cpp @@ -475,10 +475,12 @@ status_t BufferQueue::queueBuffer(int buf, uint32_t transform; int scalingMode; int64_t timestamp; + bool isAutoTimestamp; bool async; sp fence; - input.deflate(×tamp, &crop, &scalingMode, &transform, &async, &fence); + input.deflate(×tamp, &isAutoTimestamp, &crop, &scalingMode, &transform, + &async, &fence); if (fence == NULL) { ST_LOGE("queueBuffer: fence is NULL"); @@ -558,6 +560,7 @@ status_t BufferQueue::queueBuffer(int buf, item.mTransform = transform; item.mScalingMode = scalingMode; item.mTimestamp = timestamp; + item.mIsAutoTimestamp = isAutoTimestamp; item.mFrameNumber = mFrameCounter; item.mBuf = buf; item.mFence = fence; @@ -860,7 +863,12 @@ status_t BufferQueue::acquireBuffer(BufferItem *buffer, nsecs_t expectedPresent) // // NOTE: code assumes monotonic time values from the system clock are // positive. - while (false && mQueue.size() > 1) { + + // Start by checking to see if we can drop frames. We skip this check + // if the timestamps are being auto-generated by Surface -- if the + // app isn't generating timestamps explicitly, they probably don't + // want frames to be discarded based on them. + while (mQueue.size() > 1 && !mQueue[0].mIsAutoTimestamp) { // If entry[1] is timely, drop entry[0] (and repeat). We apply // an additional criteria here: we only drop the earlier buffer if // our desiredPresent falls within +/- 1 second of the expected diff --git a/libs/gui/IGraphicBufferConsumer.cpp b/libs/gui/IGraphicBufferConsumer.cpp index 6d65016cf0..4db635ca12 100644 --- a/libs/gui/IGraphicBufferConsumer.cpp +++ b/libs/gui/IGraphicBufferConsumer.cpp @@ -43,6 +43,7 @@ IGraphicBufferConsumer::BufferItem::BufferItem() : mTransform(0), mScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE), mTimestamp(0), + mIsAutoTimestamp(false), mFrameNumber(0), mBuf(INVALID_BUFFER_SLOT), mIsDroppable(false), @@ -55,6 +56,7 @@ size_t IGraphicBufferConsumer::BufferItem::getPodSize() const { sizeof(mTransform) + sizeof(mScalingMode) + sizeof(mTimestamp) + + sizeof(mIsAutoTimestamp) + sizeof(mFrameNumber) + sizeof(mBuf) + sizeof(mIsDroppable) + @@ -123,6 +125,7 @@ status_t IGraphicBufferConsumer::BufferItem::flatten( FlattenableUtils::write(buffer, size, mTransform); FlattenableUtils::write(buffer, size, mScalingMode); FlattenableUtils::write(buffer, size, mTimestamp); + FlattenableUtils::write(buffer, size, mIsAutoTimestamp); FlattenableUtils::write(buffer, size, mFrameNumber); FlattenableUtils::write(buffer, size, mBuf); FlattenableUtils::write(buffer, size, mIsDroppable); @@ -163,6 +166,7 @@ status_t IGraphicBufferConsumer::BufferItem::unflatten( FlattenableUtils::read(buffer, size, mTransform); FlattenableUtils::read(buffer, size, mScalingMode); FlattenableUtils::read(buffer, size, mTimestamp); + FlattenableUtils::read(buffer, size, mIsAutoTimestamp); FlattenableUtils::read(buffer, size, mFrameNumber); FlattenableUtils::read(buffer, size, mBuf); FlattenableUtils::read(buffer, size, mIsDroppable); diff --git a/libs/gui/IGraphicBufferProducer.cpp b/libs/gui/IGraphicBufferProducer.cpp index e3d2a20dfd..3080220f4c 100644 --- a/libs/gui/IGraphicBufferProducer.cpp +++ b/libs/gui/IGraphicBufferProducer.cpp @@ -269,6 +269,7 @@ IGraphicBufferProducer::QueueBufferInput::QueueBufferInput(const Parcel& parcel) size_t IGraphicBufferProducer::QueueBufferInput::getFlattenedSize() const { return sizeof(timestamp) + + sizeof(isAutoTimestamp) + sizeof(crop) + sizeof(scalingMode) + sizeof(transform) @@ -287,6 +288,7 @@ status_t IGraphicBufferProducer::QueueBufferInput::flatten( return NO_MEMORY; } FlattenableUtils::write(buffer, size, timestamp); + FlattenableUtils::write(buffer, size, isAutoTimestamp); FlattenableUtils::write(buffer, size, crop); FlattenableUtils::write(buffer, size, scalingMode); FlattenableUtils::write(buffer, size, transform); @@ -299,6 +301,7 @@ status_t IGraphicBufferProducer::QueueBufferInput::unflatten( { size_t minNeeded = sizeof(timestamp) + + sizeof(isAutoTimestamp) + sizeof(crop) + sizeof(scalingMode) + sizeof(transform) @@ -309,6 +312,7 @@ status_t IGraphicBufferProducer::QueueBufferInput::unflatten( } FlattenableUtils::read(buffer, size, timestamp); + FlattenableUtils::read(buffer, size, isAutoTimestamp); FlattenableUtils::read(buffer, size, crop); FlattenableUtils::read(buffer, size, scalingMode); FlattenableUtils::read(buffer, size, transform); diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp index f3a7e5ea77..b9a12ed9a3 100644 --- a/libs/gui/Surface.cpp +++ b/libs/gui/Surface.cpp @@ -262,8 +262,10 @@ int Surface::queueBuffer(android_native_buffer_t* buffer, int fenceFd) { ALOGV("Surface::queueBuffer"); Mutex::Autolock lock(mMutex); int64_t timestamp; + bool isAutoTimestamp = false; if (mTimestamp == NATIVE_WINDOW_TIMESTAMP_AUTO) { timestamp = systemTime(SYSTEM_TIME_MONOTONIC); + isAutoTimestamp = true; ALOGV("Surface::queueBuffer making up timestamp: %.2f ms", timestamp / 1000000.f); } else { @@ -281,8 +283,8 @@ int Surface::queueBuffer(android_native_buffer_t* buffer, int fenceFd) { sp fence(fenceFd >= 0 ? new Fence(fenceFd) : Fence::NO_FENCE); IGraphicBufferProducer::QueueBufferOutput output; - IGraphicBufferProducer::QueueBufferInput input(timestamp, crop, mScalingMode, - mTransform, mSwapIntervalZero, fence); + IGraphicBufferProducer::QueueBufferInput input(timestamp, isAutoTimestamp, + crop, mScalingMode, mTransform, mSwapIntervalZero, fence); status_t err = mGraphicBufferProducer->queueBuffer(i, input, &output); if (err != OK) { ALOGE("queueBuffer: error queuing buffer to SurfaceTexture, %d", err); diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp index 30b00845b3..89c87c70f0 100644 --- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp +++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp @@ -185,7 +185,7 @@ void VirtualDisplaySurface::onFrameCommitted() { sp outFence = mHwc.getLastRetireFence(mDisplayId); VDS_LOGV("onFrameCommitted: queue sink sslot=%d", sslot); status_t result = mSource[SOURCE_SINK]->queueBuffer(sslot, - QueueBufferInput(systemTime(), + QueueBufferInput(systemTime(), false, Rect(mSinkBufferWidth, mSinkBufferHeight), NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, false, outFence), &qbo); @@ -309,12 +309,13 @@ status_t VirtualDisplaySurface::queueBuffer(int pslot, // Extract the GLES release fence for HWC to acquire int64_t timestamp; + bool isAutoTimestamp; Rect crop; int scalingMode; uint32_t transform; bool async; - input.deflate(×tamp, &crop, &scalingMode, &transform, - &async, &mFbFence); + input.deflate(×tamp, &isAutoTimestamp, &crop, &scalingMode, + &transform, &async, &mFbFence); mFbProducerSlot = pslot; } -- cgit v1.2.3-59-g8ed1b From 8db92553e9e6263cd41eaf1a1ebc9e3f88f92b5f Mon Sep 17 00:00:00 2001 From: Jesse Hall Date: Thu, 29 Aug 2013 16:03:50 -0700 Subject: Force async behavior for the virtual display output BufferQueue Bug: 10551087 Change-Id: I40bbb2b87d64420939a0ea309254f281437dab56 --- libs/gui/BufferQueue.cpp | 6 ++++-- .../DisplayHardware/VirtualDisplaySurface.cpp | 17 ++++++++++++----- .../DisplayHardware/VirtualDisplaySurface.h | 2 +- 3 files changed, 17 insertions(+), 8 deletions(-) (limited to 'libs/gui/BufferQueue.cpp') diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp index 65007fa24a..57a41f25c4 100644 --- a/libs/gui/BufferQueue.cpp +++ b/libs/gui/BufferQueue.cpp @@ -637,7 +637,8 @@ void BufferQueue::cancelBuffer(int buf, const sp& fence) { status_t BufferQueue::connect(int api, bool producerControlledByApp, QueueBufferOutput* output) { ATRACE_CALL(); - ST_LOGV("connect: api=%d", api); + ST_LOGV("connect: api=%d producerControlledByApp=%s", api, + producerControlledByApp ? "true" : "false"); Mutex::Autolock lock(mMutex); if (mAbandoned) { @@ -1001,7 +1002,8 @@ status_t BufferQueue::releaseBuffer( status_t BufferQueue::consumerConnect(const sp& consumerListener, bool controlledByApp) { - ST_LOGV("consumerConnect"); + ST_LOGV("consumerConnect controlledByApp=%s", + controlledByApp ? "true" : "false"); Mutex::Autolock lock(mMutex); if (mAbandoned) { diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp index 01ca38ae30..43d27bb24b 100644 --- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp +++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp @@ -175,9 +175,12 @@ void VirtualDisplaySurface::onFrameCommitted() { sp outFence = mHwc.getLastRetireFence(mDisplayId); VDS_LOGV("onFrameCommitted: queue sink sslot=%d", sslot); status_t result = mSource[SOURCE_SINK]->queueBuffer(sslot, - QueueBufferInput(systemTime(), false, + QueueBufferInput( + systemTime(), false /* isAutoTimestamp */, Rect(mSinkBufferWidth, mSinkBufferHeight), - NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, false, outFence), + NATIVE_WINDOW_SCALING_MODE_FREEZE, 0 /* transform */, + true /* async*/, + outFence), &qbo); if (result == NO_ERROR) { updateQueueBufferOutput(qbo); @@ -205,7 +208,10 @@ status_t VirtualDisplaySurface::setBufferCount(int bufferCount) { } status_t VirtualDisplaySurface::dequeueBuffer(Source source, - uint32_t format, int* sslot, sp* fence, bool async) { + uint32_t format, int* sslot, sp* fence) { + // Don't let a slow consumer block us + bool async = (source == SOURCE_SINK); + status_t result = mSource[source]->dequeueBuffer(sslot, fence, async, mSinkBufferWidth, mSinkBufferHeight, format, mProducerUsage); if (result < 0) @@ -244,6 +250,7 @@ status_t VirtualDisplaySurface::dequeueBuffer(int* pslot, sp* fence, bool "Unexpected dequeueBuffer() in %s state", dbgStateStr()); mDbgState = DBG_STATE_GLES; + VDS_LOGW_IF(!async, "EGL called dequeueBuffer with !async despite eglSwapInterval(0)"); VDS_LOGV("dequeueBuffer %dx%d fmt=%d usage=%#x", w, h, format, usage); status_t result = NO_ERROR; @@ -275,7 +282,7 @@ status_t VirtualDisplaySurface::dequeueBuffer(int* pslot, sp* fence, bool *fence = mOutputFence; } else { int sslot; - result = dequeueBuffer(source, format, &sslot, fence, async); + result = dequeueBuffer(source, format, &sslot, fence); if (result >= 0) { *pslot = mapSource2ProducerSlot(source, sslot); } @@ -391,7 +398,7 @@ status_t VirtualDisplaySurface::refreshOutputBuffer() { } int sslot; - status_t result = dequeueBuffer(SOURCE_SINK, 0, &sslot, &mOutputFence, false); + status_t result = dequeueBuffer(SOURCE_SINK, 0, &sslot, &mOutputFence); if (result < 0) return result; mOutputProducerSlot = mapSource2ProducerSlot(SOURCE_SINK, sslot); diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h index 4ab80e4f64..536007ec69 100644 --- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h +++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h @@ -110,7 +110,7 @@ private: // static Source fbSourceForCompositionType(CompositionType type); status_t dequeueBuffer(Source source, uint32_t format, - int* sslot, sp* fence, bool async); + int* sslot, sp* fence); void updateQueueBufferOutput(const QueueBufferOutput& qbo); void resetPerFrameState(); status_t refreshOutputBuffer(); -- cgit v1.2.3-59-g8ed1b From 365857df8b94c959dea984a63013f6e7730ef976 Mon Sep 17 00:00:00 2001 From: Mathias Agopian Date: Wed, 11 Sep 2013 19:35:45 -0700 Subject: Make sure do disconnect from a BQ when its client dies. Bug: 5679534 Change-Id: If447e8673df83fe0b1d6210641e0a48522501a53 --- include/gui/BufferQueue.h | 18 ++++++++++-- include/gui/IGraphicBufferProducer.h | 7 +++-- libs/gui/BufferQueue.cpp | 32 ++++++++++++++++++++-- libs/gui/IGraphicBufferProducer.cpp | 8 ++++-- libs/gui/Surface.cpp | 4 ++- .../DisplayHardware/VirtualDisplaySurface.cpp | 5 ++-- .../DisplayHardware/VirtualDisplaySurface.h | 3 +- 7 files changed, 63 insertions(+), 14 deletions(-) (limited to 'libs/gui/BufferQueue.cpp') diff --git a/include/gui/BufferQueue.h b/include/gui/BufferQueue.h index 7e404fe842..408956b6e7 100644 --- a/include/gui/BufferQueue.h +++ b/include/gui/BufferQueue.h @@ -20,6 +20,8 @@ #include #include +#include + #include #include #include @@ -35,7 +37,9 @@ namespace android { // ---------------------------------------------------------------------------- -class BufferQueue : public BnGraphicBufferProducer, public BnGraphicBufferConsumer { +class BufferQueue : public BnGraphicBufferProducer, + public BnGraphicBufferConsumer, + private IBinder::DeathRecipient { public: enum { MIN_UNDEQUEUED_BUFFERS = 2 }; enum { NUM_BUFFER_SLOTS = 32 }; @@ -78,6 +82,12 @@ public: BufferQueue(const sp& allocator = NULL); virtual ~BufferQueue(); + /* + * IBinder::DeathRecipient interface + */ + + virtual void binderDied(const wp& who); + /* * IGraphicBufferProducer interface */ @@ -184,7 +194,8 @@ public: // it's still connected to a producer). // // APIs are enumerated in window.h (e.g. NATIVE_WINDOW_API_CPU). - virtual status_t connect(int api, bool producerControlledByApp, QueueBufferOutput* output); + virtual status_t connect(const sp& token, + int api, bool producerControlledByApp, QueueBufferOutput* output); // disconnect attempts to disconnect a producer API from the BufferQueue. // Calling this method will cause any subsequent calls to other @@ -552,6 +563,9 @@ private: // mTransformHint is used to optimize for screen rotations uint32_t mTransformHint; + + // mConnectedProducerToken is used to set a binder death notification on the producer + sp mConnectedProducerToken; }; // ---------------------------------------------------------------------------- diff --git a/include/gui/IGraphicBufferProducer.h b/include/gui/IGraphicBufferProducer.h index c3ede5ef74..342ba08111 100644 --- a/include/gui/IGraphicBufferProducer.h +++ b/include/gui/IGraphicBufferProducer.h @@ -189,8 +189,11 @@ public: // // outWidth, outHeight and outTransform are filled with the default width // and height of the window and current transform applied to buffers, - // respectively. - virtual status_t connect(int api, bool producerControlledByApp, QueueBufferOutput* output) = 0; + // respectively. The token needs to be any binder object that lives in the + // producer process -- it is solely used for obtaining a death notification + // when the producer is killed. + virtual status_t connect(const sp& token, + int api, bool producerControlledByApp, QueueBufferOutput* output) = 0; // disconnect attempts to disconnect a client API from the // IGraphicBufferProducer. Calling this method will cause any subsequent diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp index 57a41f25c4..50e3079267 100644 --- a/libs/gui/BufferQueue.cpp +++ b/libs/gui/BufferQueue.cpp @@ -635,7 +635,9 @@ void BufferQueue::cancelBuffer(int buf, const sp& fence) { mDequeueCondition.broadcast(); } -status_t BufferQueue::connect(int api, bool producerControlledByApp, QueueBufferOutput* output) { + +status_t BufferQueue::connect(const sp& token, + int api, bool producerControlledByApp, QueueBufferOutput* output) { ATRACE_CALL(); ST_LOGV("connect: api=%d producerControlledByApp=%s", api, producerControlledByApp ? "true" : "false"); @@ -663,8 +665,14 @@ status_t BufferQueue::connect(int api, bool producerControlledByApp, QueueBuffer err = -EINVAL; } else { mConnectedApi = api; - output->inflate(mDefaultWidth, mDefaultHeight, mTransformHint, - mQueue.size()); + output->inflate(mDefaultWidth, mDefaultHeight, mTransformHint, mQueue.size()); + + // set-up a death notification so that we can disconnect automatically + // when/if the remote producer dies. + // This will fail with INVALID_OPERATION if the "token" is local to our process. + if (token->linkToDeath(static_cast(this)) == NO_ERROR) { + mConnectedProducerToken = token; + } } break; default: @@ -678,6 +686,16 @@ status_t BufferQueue::connect(int api, bool producerControlledByApp, QueueBuffer return err; } +void BufferQueue::binderDied(const wp& who) { + // If we're here, it means that a producer we were connected to died. + // We're GUARANTEED that we still are connected to it because it has no other way + // to get disconnected -- or -- we wouldn't be here because we're removing this + // callback upon disconnect. Therefore, it's okay to read mConnectedApi without + // synchronization here. + int api = mConnectedApi; + this->disconnect(api); +} + status_t BufferQueue::disconnect(int api) { ATRACE_CALL(); ST_LOGV("disconnect: api=%d", api); @@ -701,6 +719,14 @@ status_t BufferQueue::disconnect(int api) { case NATIVE_WINDOW_API_CAMERA: if (mConnectedApi == api) { freeAllBuffersLocked(); + // remove our death notification callback if we have one + sp token = mConnectedProducerToken; + if (token != NULL) { + // this can fail if we're here because of the death notification + // either way, we just ignore. + token->unlinkToDeath(static_cast(this)); + } + mConnectedProducerToken = NULL; mConnectedApi = NO_CONNECTED_API; mDequeueCondition.broadcast(); listener = mConsumerListener; diff --git a/libs/gui/IGraphicBufferProducer.cpp b/libs/gui/IGraphicBufferProducer.cpp index 3080220f4c..fc86e608ab 100644 --- a/libs/gui/IGraphicBufferProducer.cpp +++ b/libs/gui/IGraphicBufferProducer.cpp @@ -41,7 +41,6 @@ enum { DISCONNECT, }; - class BpGraphicBufferProducer : public BpInterface { public: @@ -139,9 +138,11 @@ public: return result; } - virtual status_t connect(int api, bool producerControlledByApp, QueueBufferOutput* output) { + virtual status_t connect(const sp& token, + int api, bool producerControlledByApp, QueueBufferOutput* output) { Parcel data, reply; data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor()); + data.writeStrongBinder(token); data.writeInt32(api); data.writeInt32(producerControlledByApp); status_t result = remote()->transact(CONNECT, data, &reply); @@ -241,12 +242,13 @@ status_t BnGraphicBufferProducer::onTransact( } break; case CONNECT: { CHECK_INTERFACE(IGraphicBufferProducer, data, reply); + sp token = data.readStrongBinder(); int api = data.readInt32(); bool producerControlledByApp = data.readInt32(); QueueBufferOutput* const output = reinterpret_cast( reply->writeInplace(sizeof(QueueBufferOutput))); - status_t res = connect(api, producerControlledByApp, output); + status_t res = connect(token, api, producerControlledByApp, output); reply->writeInt32(res); return NO_ERROR; } break; diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp index 1bae0fed49..27dbc4eeea 100644 --- a/libs/gui/Surface.cpp +++ b/libs/gui/Surface.cpp @@ -490,9 +490,10 @@ int Surface::dispatchUnlockAndPost(va_list args) { int Surface::connect(int api) { ATRACE_CALL(); ALOGV("Surface::connect"); + static sp sLife = new BBinder(); Mutex::Autolock lock(mMutex); IGraphicBufferProducer::QueueBufferOutput output; - int err = mGraphicBufferProducer->connect(api, mProducerControlledByApp, &output); + int err = mGraphicBufferProducer->connect(sLife, api, mProducerControlledByApp, &output); if (err == NO_ERROR) { uint32_t numPendingBuffers = 0; output.deflate(&mDefaultWidth, &mDefaultHeight, &mTransformHint, @@ -505,6 +506,7 @@ int Surface::connect(int api) { return err; } + int Surface::disconnect(int api) { ATRACE_CALL(); ALOGV("Surface::disconnect"); diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp index 43d27bb24b..c06043d4f4 100644 --- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp +++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp @@ -358,10 +358,11 @@ int VirtualDisplaySurface::query(int what, int* value) { return mSource[SOURCE_SINK]->query(what, value); } -status_t VirtualDisplaySurface::connect(int api, bool producerControlledByApp, +status_t VirtualDisplaySurface::connect(const sp& token, + int api, bool producerControlledByApp, QueueBufferOutput* output) { QueueBufferOutput qbo; - status_t result = mSource[SOURCE_SINK]->connect(api, producerControlledByApp, &qbo); + status_t result = mSource[SOURCE_SINK]->connect(token, api, producerControlledByApp, &qbo); if (result == NO_ERROR) { updateQueueBufferOutput(qbo); *output = mQueueBufferOutput; diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h index 536007ec69..18fb5a7e0d 100644 --- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h +++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h @@ -102,7 +102,8 @@ private: const QueueBufferInput& input, QueueBufferOutput* output); virtual void cancelBuffer(int pslot, const sp& fence); virtual int query(int what, int* value); - virtual status_t connect(int api, bool producerControlledByApp, QueueBufferOutput* output); + virtual status_t connect(const sp& token, + int api, bool producerControlledByApp, QueueBufferOutput* output); virtual status_t disconnect(int api); // -- cgit v1.2.3-59-g8ed1b From c1c05de415854eb7a13a16b7e22a22de8515123a Mon Sep 17 00:00:00 2001 From: Mathias Agopian Date: Tue, 17 Sep 2013 23:45:22 -0700 Subject: fix camera API 2.0 orientation we add a flag to ANativeWindow::setBufferTransform that means "apply the inverse rotation of the display this buffer is displayed onto to". Bug: 10804238 Change-Id: Id2447676271950463e8dbcef1b95935c5c3f32b2 --- include/gui/IGraphicBufferConsumer.h | 4 ++ include/ui/TMatHelpers.h | 2 +- libs/gui/BufferQueue.cpp | 3 +- libs/gui/IGraphicBufferConsumer.cpp | 8 +++- services/surfaceflinger/DisplayDevice.cpp | 19 +++++++++ services/surfaceflinger/DisplayDevice.h | 1 + services/surfaceflinger/Layer.cpp | 46 +++++++++++++++++++++- services/surfaceflinger/SurfaceFlingerConsumer.cpp | 13 ++++++ services/surfaceflinger/SurfaceFlingerConsumer.h | 10 +++++ 9 files changed, 100 insertions(+), 6 deletions(-) (limited to 'libs/gui/BufferQueue.cpp') diff --git a/include/gui/IGraphicBufferConsumer.h b/include/gui/IGraphicBufferConsumer.h index 3327b37720..0e35f1371e 100644 --- a/include/gui/IGraphicBufferConsumer.h +++ b/include/gui/IGraphicBufferConsumer.h @@ -91,6 +91,10 @@ public: // Indicates whether this buffer has been seen by a consumer yet bool mAcquireCalled; + + // Indicates this buffer must be transformed by the inverse transform of the screen + // it is displayed onto. This is applied after mTransform. + bool mTransformToDisplayInverse; }; diff --git a/include/ui/TMatHelpers.h b/include/ui/TMatHelpers.h index cead10a8ca..a6aadcad40 100644 --- a/include/ui/TMatHelpers.h +++ b/include/ui/TMatHelpers.h @@ -245,7 +245,7 @@ template class BASE, typename T> class TMatDebug { public: String8 asString() const { - return matrix::asString(*this); + return matrix::asString( static_cast< const BASE& >(*this) ); } }; diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp index 50e3079267..87d66e2b7f 100644 --- a/libs/gui/BufferQueue.cpp +++ b/libs/gui/BufferQueue.cpp @@ -557,7 +557,8 @@ status_t BufferQueue::queueBuffer(int buf, item.mAcquireCalled = mSlots[buf].mAcquireCalled; item.mGraphicBuffer = mSlots[buf].mGraphicBuffer; item.mCrop = crop; - item.mTransform = transform; + item.mTransform = transform & ~NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY; + item.mTransformToDisplayInverse = bool(transform & NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY); item.mScalingMode = scalingMode; item.mTimestamp = timestamp; item.mIsAutoTimestamp = isAutoTimestamp; diff --git a/libs/gui/IGraphicBufferConsumer.cpp b/libs/gui/IGraphicBufferConsumer.cpp index 4db635ca12..9574b61762 100644 --- a/libs/gui/IGraphicBufferConsumer.cpp +++ b/libs/gui/IGraphicBufferConsumer.cpp @@ -47,7 +47,8 @@ IGraphicBufferConsumer::BufferItem::BufferItem() : mFrameNumber(0), mBuf(INVALID_BUFFER_SLOT), mIsDroppable(false), - mAcquireCalled(false) { + mAcquireCalled(false), + mTransformToDisplayInverse(false) { mCrop.makeInvalid(); } @@ -60,7 +61,8 @@ size_t IGraphicBufferConsumer::BufferItem::getPodSize() const { sizeof(mFrameNumber) + sizeof(mBuf) + sizeof(mIsDroppable) + - sizeof(mAcquireCalled); + sizeof(mAcquireCalled) + + sizeof(mTransformToDisplayInverse); return c; } @@ -130,6 +132,7 @@ status_t IGraphicBufferConsumer::BufferItem::flatten( FlattenableUtils::write(buffer, size, mBuf); FlattenableUtils::write(buffer, size, mIsDroppable); FlattenableUtils::write(buffer, size, mAcquireCalled); + FlattenableUtils::write(buffer, size, mTransformToDisplayInverse); return NO_ERROR; } @@ -171,6 +174,7 @@ status_t IGraphicBufferConsumer::BufferItem::unflatten( FlattenableUtils::read(buffer, size, mBuf); FlattenableUtils::read(buffer, size, mIsDroppable); FlattenableUtils::read(buffer, size, mAcquireCalled); + FlattenableUtils::read(buffer, size, mTransformToDisplayInverse); return NO_ERROR; } diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp index 917d4cd3c9..800137bdf3 100644 --- a/services/surfaceflinger/DisplayDevice.cpp +++ b/services/surfaceflinger/DisplayDevice.cpp @@ -344,6 +344,25 @@ void DisplayDevice::setLayerStack(uint32_t stack) { // ---------------------------------------------------------------------------- +uint32_t DisplayDevice::getOrientationTransform() const { + uint32_t transform = 0; + switch (mOrientation) { + case DisplayState::eOrientationDefault: + transform = Transform::ROT_0; + break; + case DisplayState::eOrientation90: + transform = Transform::ROT_90; + break; + case DisplayState::eOrientation180: + transform = Transform::ROT_180; + break; + case DisplayState::eOrientation270: + transform = Transform::ROT_270; + break; + } + return transform; +} + status_t DisplayDevice::orientationToTransfrom( int orientation, int w, int h, Transform* tr) { diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h index e0b1370a58..c3abe89d6a 100644 --- a/services/surfaceflinger/DisplayDevice.h +++ b/services/surfaceflinger/DisplayDevice.h @@ -111,6 +111,7 @@ public: void setProjection(int orientation, const Rect& viewport, const Rect& frame); int getOrientation() const { return mOrientation; } + uint32_t getOrientationTransform() const; const Transform& getTransform() const { return mGlobalTransform; } const Rect getViewport() const { return mViewport; } const Rect getFrame() const { return mFrame; } diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index b610c20660..61af51faf5 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -376,7 +376,21 @@ void Layer::setGeometry( */ const Transform bufferOrientation(mCurrentTransform); - const Transform transform(tr * s.transform * bufferOrientation); + Transform transform(tr * s.transform * bufferOrientation); + + if (mSurfaceFlingerConsumer->getTransformToDisplayInverse()) { + /* + * the code below applies the display's inverse transform to the buffer + */ + uint32_t invTransform = hw->getOrientationTransform(); + // calculate the inverse transform + if (invTransform & NATIVE_WINDOW_TRANSFORM_ROT_90) { + invTransform ^= NATIVE_WINDOW_TRANSFORM_FLIP_V | + NATIVE_WINDOW_TRANSFORM_FLIP_H; + } + // and apply to the current transform + transform = transform * Transform(invTransform); + } // this gives us only the "orientation" component of the transform const uint32_t orientation = transform.getOrientation(); @@ -489,6 +503,34 @@ void Layer::onDraw(const sp& hw, const Region& clip) const mSurfaceFlingerConsumer->setFilteringEnabled(useFiltering); mSurfaceFlingerConsumer->getTransformMatrix(textureMatrix); + if (mSurfaceFlingerConsumer->getTransformToDisplayInverse()) { + + /* + * the code below applies the display's inverse transform to the texture transform + */ + + // create a 4x4 transform matrix from the display transform flags + const mat4 flipH(-1,0,0,0, 0,1,0,0, 0,0,1,0, 1,0,0,1); + const mat4 flipV( 1,0,0,0, 0,-1,0,0, 0,0,1,0, 0,1,0,1); + const mat4 rot90( 0,1,0,0, -1,0,0,0, 0,0,1,0, 1,0,0,1); + + mat4 tr; + uint32_t transform = hw->getOrientationTransform(); + if (transform & NATIVE_WINDOW_TRANSFORM_ROT_90) + tr = tr * rot90; + if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_H) + tr = tr * flipH; + if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_V) + tr = tr * flipV; + + // calculate the inverse + tr = inverse(tr); + + // and finally apply it to the original texture matrix + const mat4 texTransform(mat4(static_cast(textureMatrix)) * tr); + memcpy(textureMatrix, texTransform.asArray(), sizeof(textureMatrix)); + } + // Set things up for texturing. mTexture.setDimensions(mActiveBuffer->getWidth(), mActiveBuffer->getHeight()); mTexture.setFiltering(useFiltering); @@ -533,7 +575,7 @@ void Layer::drawWithOpenGL( * * The GL code below is more logical (imho), and the difference with * HWC is due to a limitation of the HWC API to integers -- a question - * is suspend is wether we should ignore this problem or revert to + * is suspend is whether we should ignore this problem or revert to * GL composition when a buffer scaling is applied (maybe with some * minimal value)? Or, we could make GL behave like HWC -- but this feel * like more of a hack. diff --git a/services/surfaceflinger/SurfaceFlingerConsumer.cpp b/services/surfaceflinger/SurfaceFlingerConsumer.cpp index 552372b144..6dc093e785 100644 --- a/services/surfaceflinger/SurfaceFlingerConsumer.cpp +++ b/services/surfaceflinger/SurfaceFlingerConsumer.cpp @@ -99,6 +99,19 @@ status_t SurfaceFlingerConsumer::bindTextureImage() return bindTextureImageLocked(); } +status_t SurfaceFlingerConsumer::acquireBufferLocked( + BufferQueue::BufferItem *item, nsecs_t presentWhen) { + status_t result = GLConsumer::acquireBufferLocked(item, presentWhen); + if (result == NO_ERROR) { + mTransformToDisplayInverse = item->mTransformToDisplayInverse; + } + return result; +} + +bool SurfaceFlingerConsumer::getTransformToDisplayInverse() const { + return mTransformToDisplayInverse; +} + // We need to determine the time when a buffer acquired now will be // displayed. This can be calculated: // time when previous buffer's actual-present fence was signaled diff --git a/services/surfaceflinger/SurfaceFlingerConsumer.h b/services/surfaceflinger/SurfaceFlingerConsumer.h index c7fc1641db..688ad32241 100644 --- a/services/surfaceflinger/SurfaceFlingerConsumer.h +++ b/services/surfaceflinger/SurfaceFlingerConsumer.h @@ -40,6 +40,8 @@ public: virtual ~BufferRejecter() { } }; + virtual status_t acquireBufferLocked(BufferQueue::BufferItem *item, nsecs_t presentWhen); + // This version of updateTexImage() takes a functor that may be used to // reject the newly acquired buffer. Unlike the GLConsumer version, // this does not guarantee that the buffer has been bound to the GL @@ -49,8 +51,16 @@ public: // See GLConsumer::bindTextureImageLocked(). status_t bindTextureImage(); + // must be called from SF main thread + bool getTransformToDisplayInverse() const; + private: nsecs_t computeExpectedPresent(); + + // Indicates this buffer must be transformed by the inverse transform of the screen + // it is displayed onto. This is applied after GLConsumer::mCurrentTransform. + // This must be set/read from SurfaceFlinger's main thread. + bool mTransformToDisplayInverse; }; // ---------------------------------------------------------------------------- -- cgit v1.2.3-59-g8ed1b From f0cf5f103cf9c54d59de4ed6f1d8ddd2302dec1b Mon Sep 17 00:00:00 2001 From: Jamie Gennis Date: Wed, 25 Sep 2013 17:21:56 -0700 Subject: BufferQueue: fix a test crash Bug: 10935880 Change-Id: If76e9fb055103bad0db7e6c16487532671573149 --- libs/gui/BufferQueue.cpp | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) (limited to 'libs/gui/BufferQueue.cpp') diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp index 87d66e2b7f..c165a68205 100644 --- a/libs/gui/BufferQueue.cpp +++ b/libs/gui/BufferQueue.cpp @@ -668,11 +668,15 @@ status_t BufferQueue::connect(const sp& token, mConnectedApi = api; output->inflate(mDefaultWidth, mDefaultHeight, mTransformHint, mQueue.size()); - // set-up a death notification so that we can disconnect automatically - // when/if the remote producer dies. - // This will fail with INVALID_OPERATION if the "token" is local to our process. - if (token->linkToDeath(static_cast(this)) == NO_ERROR) { - mConnectedProducerToken = token; + // set-up a death notification so that we can disconnect + // automatically when/if the remote producer dies. + if (token != NULL && token->remoteBinder() != NULL) { + status_t err = token->linkToDeath(static_cast(this)); + if (err == NO_ERROR) { + mConnectedProducerToken = token; + } else { + ALOGE("linkToDeath failed: %s (%d)", strerror(-err), err); + } } } break; -- cgit v1.2.3-59-g8ed1b