diff options
author | 2016-07-25 12:48:08 -0700 | |
---|---|---|
committer | 2016-11-17 11:45:20 -0800 | |
commit | 7c3ba8aa288755fad78ddbabcee0ad5a0610ac1c (patch) | |
tree | 674ba1739716363e0dfd66133026eaa09d29909f | |
parent | 3890c3995c4a52439844faeb80b5503d42b977d8 (diff) |
Update producer's cache of frame events in de/queue
* Cache is only updated during queue and dequeue if
the getFrameTimestamps is enabled.
* The consumer avoids sending a copy of the acquire
fence back to the producer since the producer
already has a copy.
Test: adb shell /data/nativetest/libgui_test/libgui_test
--gtest_filter=*GetFrameTimestamps*
Change-Id: I6a8b965ae79441a40893b5df937f9ed004fe7359
-rw-r--r-- | include/gui/BufferQueueProducer.h | 4 | ||||
-rw-r--r-- | include/gui/FrameTimestamps.h | 12 | ||||
-rw-r--r-- | include/gui/IGraphicBufferProducer.h | 46 | ||||
-rw-r--r-- | include/gui/Surface.h | 8 | ||||
-rw-r--r-- | libs/gui/BufferQueueProducer.cpp | 32 | ||||
-rw-r--r-- | libs/gui/FrameTimestamps.cpp | 10 | ||||
-rw-r--r-- | libs/gui/IGraphicBufferProducer.cpp | 91 | ||||
-rw-r--r-- | libs/gui/Surface.cpp | 67 | ||||
-rw-r--r-- | libs/gui/tests/BufferQueue_test.cpp | 85 | ||||
-rw-r--r-- | libs/gui/tests/IGraphicBufferProducer_test.cpp | 45 | ||||
-rw-r--r-- | libs/gui/tests/StreamSplitter_test.cpp | 12 | ||||
-rw-r--r-- | opengl/libs/EGL/eglApi.cpp | 5 | ||||
-rw-r--r-- | opengl/libs/EGL/egl_object.cpp | 2 | ||||
-rw-r--r-- | opengl/libs/EGL/egl_object.h | 1 | ||||
-rw-r--r-- | services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp | 11 | ||||
-rw-r--r-- | services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h | 3 | ||||
-rw-r--r-- | services/surfaceflinger/MonitoredProducer.cpp | 6 | ||||
-rw-r--r-- | services/surfaceflinger/MonitoredProducer.h | 3 |
18 files changed, 255 insertions, 188 deletions
diff --git a/include/gui/BufferQueueProducer.h b/include/gui/BufferQueueProducer.h index e6ee6c6b68..5541468998 100644 --- a/include/gui/BufferQueueProducer.h +++ b/include/gui/BufferQueueProducer.h @@ -80,9 +80,9 @@ 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 *outSlot, sp<Fence>* outFence, + status_t dequeueBuffer(int *outSlot, sp<Fence>* outFence, uint32_t width, uint32_t height, PixelFormat format, - uint32_t usage); + uint32_t usage, FrameEventHistoryDelta* outTimestamps) override; // See IGraphicBufferProducer::detachBuffer virtual status_t detachBuffer(int slot); diff --git a/include/gui/FrameTimestamps.h b/include/gui/FrameTimestamps.h index 50765978cb..0e95ec3ebe 100644 --- a/include/gui/FrameTimestamps.h +++ b/include/gui/FrameTimestamps.h @@ -226,7 +226,6 @@ private: nsecs_t mFirstRefreshStartTime{0}; nsecs_t mLastRefreshStartTime{0}; - sp<Fence> mAcquireFence{Fence::NO_FENCE}; sp<Fence> mGpuCompositionDoneFence{Fence::NO_FENCE}; sp<Fence> mDisplayPresentFence{Fence::NO_FENCE}; sp<Fence> mDisplayRetireFence{Fence::NO_FENCE}; @@ -234,13 +233,12 @@ private: // This is a static method with an auto return value so we can call // it without needing const and non-const versions. - template <typename ThisType> - static inline auto allFences(ThisType fed) -> - std::array<decltype(&fed->mAcquireFence), 5> { + template <typename ThisT> + static inline auto allFences(ThisT fed) -> + std::array<decltype(&fed->mReleaseFence), 4> { return {{ - &fed->mAcquireFence, &fed->mGpuCompositionDoneFence, - &fed->mDisplayPresentFence, &fed->mDisplayRetireFence, - &fed->mReleaseFence + &fed->mGpuCompositionDoneFence, &fed->mDisplayPresentFence, + &fed->mDisplayRetireFence, &fed->mReleaseFence }}; } }; diff --git a/include/gui/IGraphicBufferProducer.h b/include/gui/IGraphicBufferProducer.h index 612a9024c3..492db351b9 100644 --- a/include/gui/IGraphicBufferProducer.h +++ b/include/gui/IGraphicBufferProducer.h @@ -190,7 +190,8 @@ public: // All other negative values are an unknown error returned downstream // from the graphics allocator (typically errno). virtual status_t dequeueBuffer(int* slot, sp<Fence>* fence, uint32_t w, - uint32_t h, PixelFormat format, uint32_t usage) = 0; + uint32_t h, PixelFormat format, uint32_t usage, + FrameEventHistoryDelta* outTimestamps) = 0; // detachBuffer attempts to remove all ownership of the buffer in the given // slot from the buffer queue. If this call succeeds, the slot will be @@ -306,20 +307,23 @@ public: // set this to Fence::NO_FENCE if the buffer is ready immediately // sticky - the sticky transform set in Surface (only used by the LEGACY // camera mode). + // getFrameTimestamps - whether or not the latest frame timestamps + // should be retrieved from the consumer. inline QueueBufferInput(int64_t _timestamp, bool _isAutoTimestamp, android_dataspace _dataSpace, const Rect& _crop, int _scalingMode, uint32_t _transform, const sp<Fence>& _fence, - uint32_t _sticky = 0) + uint32_t _sticky = 0, bool _getFrameTimestamps = false) : timestamp(_timestamp), isAutoTimestamp(_isAutoTimestamp), dataSpace(_dataSpace), crop(_crop), scalingMode(_scalingMode), transform(_transform), stickyTransform(_sticky), fence(_fence), - surfaceDamage() { } + surfaceDamage(), getFrameTimestamps(_getFrameTimestamps) { } inline void deflate(int64_t* outTimestamp, bool* outIsAutoTimestamp, android_dataspace* outDataSpace, Rect* outCrop, int* outScalingMode, uint32_t* outTransform, sp<Fence>* outFence, - uint32_t* outStickyTransform = nullptr) const { + uint32_t* outStickyTransform = nullptr, + bool* outGetFrameTimestamps = nullptr) const { *outTimestamp = timestamp; *outIsAutoTimestamp = bool(isAutoTimestamp); *outDataSpace = dataSpace; @@ -330,9 +334,13 @@ public: if (outStickyTransform != NULL) { *outStickyTransform = stickyTransform; } + if (outGetFrameTimestamps) { + *outGetFrameTimestamps = getFrameTimestamps; + } } // Flattenable protocol + static constexpr size_t minFlattenedSize(); size_t getFlattenedSize() const; size_t getFdCount() const; status_t flatten(void*& buffer, size_t& size, int*& fds, size_t& count) const; @@ -351,37 +359,12 @@ public: uint32_t stickyTransform{0}; sp<Fence> fence; Region surfaceDamage; + bool getFrameTimestamps{false}; }; struct QueueBufferOutput : public Flattenable<QueueBufferOutput> { - // outWidth - filled with default width applied to the buffer - // outHeight - filled with default height applied to the buffer - // outTransformHint - filled with default transform applied to the buffer - // outNumPendingBuffers - num buffers queued that haven't yet been acquired - // (counting the currently queued buffer) - inline void deflate(uint32_t* outWidth, - uint32_t* outHeight, - uint32_t* outTransformHint, - uint32_t* outNumPendingBuffers, - uint64_t* outNextFrameNumber) const { - *outWidth = width; - *outHeight = height; - *outTransformHint = transformHint; - *outNumPendingBuffers = numPendingBuffers; - *outNextFrameNumber = nextFrameNumber; - } - - inline void inflate(uint32_t inWidth, uint32_t inHeight, - uint32_t inTransformHint, uint32_t inNumPendingBuffers, - uint64_t inNextFrameNumber) { - width = inWidth; - height = inHeight; - transformHint = inTransformHint; - numPendingBuffers = inNumPendingBuffers; - nextFrameNumber = inNextFrameNumber; - } - // Flattenable protocol + static constexpr size_t minFlattenedSize(); size_t getFlattenedSize() const; size_t getFdCount() const; status_t flatten(void*& buffer, size_t& size, int*& fds, size_t& count) const; @@ -392,6 +375,7 @@ public: uint32_t transformHint{0}; uint32_t numPendingBuffers{0}; uint64_t nextFrameNumber{0}; + FrameEventHistoryDelta frameTimestamps; }; virtual status_t queueBuffer(int slot, const QueueBufferInput& input, diff --git a/include/gui/Surface.h b/include/gui/Surface.h index c12d452c05..a10dad1ab9 100644 --- a/include/gui/Surface.h +++ b/include/gui/Surface.h @@ -134,6 +134,12 @@ public: status_t getLastQueuedBuffer(sp<GraphicBuffer>* outBuffer, sp<Fence>* outFence, float outTransformMatrix[16]); + /* Enables or disables frame timestamp tracking. It is disabled by default + * to avoid overhead during queue and dequeue for applications that don't + * need the feature. If disabled, calls to getFrameTimestamps will fail. + */ + void enableFrameTimestamps(bool enable); + // See IGraphicBufferProducer::getFrameTimestamps status_t getFrameTimestamps(uint64_t frameNumber, nsecs_t* outRequestedPresentTime, nsecs_t* outAcquireTime, @@ -192,6 +198,7 @@ private: int dispatchSetSurfaceDamage(va_list args); int dispatchSetSharedBufferMode(va_list args); int dispatchSetAutoRefresh(va_list args); + int dispatchEnableFrameTimestamps(va_list args); int dispatchGetFrameTimestamps(va_list args); protected: @@ -390,6 +397,7 @@ private: mutable bool mFrameTimestampsSupportsRetire; // A cached copy of the FrameEventHistory maintained by the consumer. + bool mEnableFrameTimestamps = false; ProducerFrameEventHistory mFrameEventHistory; }; diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp index e27fd7a836..75198d7c8b 100644 --- a/libs/gui/BufferQueueProducer.cpp +++ b/libs/gui/BufferQueueProducer.cpp @@ -348,7 +348,8 @@ status_t BufferQueueProducer::waitForFreeSlotThenRelock(FreeSlotCaller caller, status_t BufferQueueProducer::dequeueBuffer(int *outSlot, sp<android::Fence> *outFence, uint32_t width, uint32_t height, - PixelFormat format, uint32_t usage) { + PixelFormat format, uint32_t usage, + FrameEventHistoryDelta* outTimestamps) { ATRACE_CALL(); { // Autolock scope Mutex::Autolock lock(mCore->mMutex); @@ -560,6 +561,8 @@ status_t BufferQueueProducer::dequeueBuffer(int *outSlot, mSlots[*outSlot].mFrameNumber, mSlots[*outSlot].mGraphicBuffer->handle, returnFlags); + addAndGetFrameTimestamps(nullptr, outTimestamps); + return returnFlags; } @@ -748,8 +751,10 @@ status_t BufferQueueProducer::queueBuffer(int slot, uint32_t transform; uint32_t stickyTransform; sp<Fence> acquireFence; + bool getFrameTimestamps = false; input.deflate(&requestedPresentTimestamp, &isAutoTimestamp, &dataSpace, - &crop, &scalingMode, &transform, &acquireFence, &stickyTransform); + &crop, &scalingMode, &transform, &acquireFence, &stickyTransform, + &getFrameTimestamps); Region surfaceDamage = input.getSurfaceDamage(); if (acquireFence == NULL) { @@ -913,10 +918,11 @@ status_t BufferQueueProducer::queueBuffer(int slot, mCore->mDequeueCondition.broadcast(); mCore->mLastQueuedSlot = slot; - output->inflate(mCore->mDefaultWidth, mCore->mDefaultHeight, - mCore->mTransformHint, - static_cast<uint32_t>(mCore->mQueue.size()), - mCore->mFrameCounter + 1); + output->width = mCore->mDefaultWidth; + output->height = mCore->mDefaultHeight; + output->transformHint = mCore->mTransformHint; + output->numPendingBuffers = static_cast<uint32_t>(mCore->mQueue.size()); + output->nextFrameNumber = mCore->mFrameCounter + 1; ATRACE_INT(mCore->mConsumerName.string(), static_cast<int32_t>(mCore->mQueue.size())); @@ -975,7 +981,8 @@ status_t BufferQueueProducer::queueBuffer(int slot, requestedPresentTimestamp, acquireFence }; - addAndGetFrameTimestamps(&newFrameEventsEntry, nullptr); + addAndGetFrameTimestamps(&newFrameEventsEntry, + getFrameTimestamps ? &output->frameTimestamps : nullptr); return NO_ERROR; } @@ -1141,10 +1148,13 @@ status_t BufferQueueProducer::connect(const sp<IProducerListener>& listener, case NATIVE_WINDOW_API_MEDIA: case NATIVE_WINDOW_API_CAMERA: mCore->mConnectedApi = api; - output->inflate(mCore->mDefaultWidth, mCore->mDefaultHeight, - mCore->mTransformHint, - static_cast<uint32_t>(mCore->mQueue.size()), - mCore->mFrameCounter + 1); + + output->width = mCore->mDefaultWidth; + output->height = mCore->mDefaultHeight; + output->transformHint = mCore->mTransformHint; + output->numPendingBuffers = + static_cast<uint32_t>(mCore->mQueue.size()); + output->nextFrameNumber = mCore->mFrameCounter + 1; if (listener != NULL) { // Set up a death notification so that we can disconnect diff --git a/libs/gui/FrameTimestamps.cpp b/libs/gui/FrameTimestamps.cpp index 4b98cff615..30ff65ffa7 100644 --- a/libs/gui/FrameTimestamps.cpp +++ b/libs/gui/FrameTimestamps.cpp @@ -301,7 +301,6 @@ void ProducerFrameEventHistory::applyDelta( // Existing frame. Merge. // Consumer never sends timestamps of fences, only the fences // themselves, so we never need to update the fence timestamps here. - applyFenceDelta(&frame.acquireFence, d.mAcquireFence); applyFenceDelta( &frame.gpuCompositionDoneFence, d.mGpuCompositionDoneFence); applyFenceDelta(&frame.displayPresentFence, d.mDisplayPresentFence); @@ -318,7 +317,7 @@ void ProducerFrameEventHistory::applyDelta( // Set aquire fence and time at this point. frame.acquireTime = 0; - frame.acquireFence = d.mAcquireFence; + frame.acquireFence = Fence::NO_FENCE; // Reset fence-related timestamps frame.gpuCompositionDoneTime = 0; @@ -348,8 +347,11 @@ void ConsumerFrameEventHistory::addQueue(const NewFrameEventsEntry& newEntry) { newTimestamps.acquireFence = newEntry.acquireFence; newTimestamps.valid = true; mFrames[mQueueOffset] = newTimestamps; + + // Note: We avoid sending the acquire fence back to the caller since + // they have the original one already, so there is no need to set the + // acquire dirty bit. mFramesDirty[mQueueOffset].setDirty<FrameEvent::POSTED>(); - mFramesDirty[mQueueOffset].setDirty<FrameEvent::ACQUIRE>(); mQueueOffset = (mQueueOffset + 1) % mFrames.size(); } @@ -456,8 +458,6 @@ FrameEventsDelta::FrameEventsDelta( mLatchTime(frameTimestamps.latchTime), mFirstRefreshStartTime(frameTimestamps.firstRefreshStartTime), mLastRefreshStartTime(frameTimestamps.lastRefreshStartTime) { - mAcquireFence = dirtyFields.isDirty<FrameEvent::ACQUIRE>() ? - frameTimestamps.acquireFence : Fence::NO_FENCE; mGpuCompositionDoneFence = dirtyFields.isDirty<FrameEvent::GL_COMPOSITION_DONE>() ? frameTimestamps.gpuCompositionDoneFence : Fence::NO_FENCE; diff --git a/libs/gui/IGraphicBufferProducer.cpp b/libs/gui/IGraphicBufferProducer.cpp index bed7d53872..e37b65ba9c 100644 --- a/libs/gui/IGraphicBufferProducer.cpp +++ b/libs/gui/IGraphicBufferProducer.cpp @@ -118,14 +118,17 @@ public: } virtual status_t dequeueBuffer(int *buf, sp<Fence>* fence, uint32_t width, - uint32_t height, PixelFormat format, uint32_t usage) { + uint32_t height, PixelFormat format, uint32_t usage, + FrameEventHistoryDelta* outTimestamps) { Parcel data, reply; + bool getFrameTimestamps = (outTimestamps != nullptr); data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor()); data.writeUint32(width); data.writeUint32(height); data.writeInt32(static_cast<int32_t>(format)); data.writeUint32(usage); + data.writeBool(getFrameTimestamps); status_t result = remote()->transact(DEQUEUE_BUFFER, data, &reply); if (result != NO_ERROR) { @@ -139,6 +142,14 @@ public: fence->clear(); return result; } + if (getFrameTimestamps) { + result = reply.read(*outTimestamps); + if (result != NO_ERROR) { + ALOGE("IGBP::dequeueBuffer failed to read timestamps: %d", + result); + return result; + } + } result = reply.readInt32(); return result; } @@ -513,14 +524,19 @@ status_t BnGraphicBufferProducer::onTransact( uint32_t height = data.readUint32(); PixelFormat format = static_cast<PixelFormat>(data.readInt32()); uint32_t usage = data.readUint32(); + bool getTimestamps = data.readBool(); int buf = 0; sp<Fence> fence = Fence::NO_FENCE; + FrameEventHistoryDelta frameTimestamps; int result = dequeueBuffer(&buf, &fence, width, height, format, - usage); + usage, getTimestamps ? &frameTimestamps : nullptr); reply->writeInt32(buf); reply->write(*fence); + if (getTimestamps) { + reply->write(frameTimestamps); + } reply->writeInt32(result); return NO_ERROR; } @@ -563,14 +579,14 @@ status_t BnGraphicBufferProducer::onTransact( } case QUEUE_BUFFER: { CHECK_INTERFACE(IGraphicBufferProducer, data, reply); + int buf = data.readInt32(); QueueBufferInput input(data); - QueueBufferOutput output; status_t result = queueBuffer(buf, input, &output); - reply->write(output); reply->writeInt32(result); + return NO_ERROR; } case CANCEL_BUFFER: { @@ -740,16 +756,21 @@ IGraphicBufferProducer::QueueBufferInput::QueueBufferInput(const Parcel& parcel) parcel.read(*this); } +constexpr size_t IGraphicBufferProducer::QueueBufferInput::minFlattenedSize() { + return sizeof(timestamp) + + sizeof(isAutoTimestamp) + + sizeof(dataSpace) + + sizeof(crop) + + sizeof(scalingMode) + + sizeof(transform) + + sizeof(stickyTransform) + + sizeof(getFrameTimestamps); +} + size_t IGraphicBufferProducer::QueueBufferInput::getFlattenedSize() const { - return sizeof(timestamp) - + sizeof(isAutoTimestamp) - + sizeof(dataSpace) - + sizeof(crop) - + sizeof(scalingMode) - + sizeof(transform) - + sizeof(stickyTransform) - + fence->getFlattenedSize() - + surfaceDamage.getFlattenedSize(); + return minFlattenedSize() + + fence->getFlattenedSize() + + surfaceDamage.getFlattenedSize(); } size_t IGraphicBufferProducer::QueueBufferInput::getFdCount() const { @@ -762,6 +783,7 @@ status_t IGraphicBufferProducer::QueueBufferInput::flatten( if (size < getFlattenedSize()) { return NO_MEMORY; } + FlattenableUtils::write(buffer, size, timestamp); FlattenableUtils::write(buffer, size, isAutoTimestamp); FlattenableUtils::write(buffer, size, dataSpace); @@ -769,6 +791,8 @@ status_t IGraphicBufferProducer::QueueBufferInput::flatten( FlattenableUtils::write(buffer, size, scalingMode); FlattenableUtils::write(buffer, size, transform); FlattenableUtils::write(buffer, size, stickyTransform); + FlattenableUtils::write(buffer, size, getFrameTimestamps); + status_t result = fence->flatten(buffer, size, fds, count); if (result != NO_ERROR) { return result; @@ -779,16 +803,7 @@ status_t IGraphicBufferProducer::QueueBufferInput::flatten( status_t IGraphicBufferProducer::QueueBufferInput::unflatten( void const*& buffer, size_t& size, int const*& fds, size_t& count) { - size_t minNeeded = - sizeof(timestamp) - + sizeof(isAutoTimestamp) - + sizeof(dataSpace) - + sizeof(crop) - + sizeof(scalingMode) - + sizeof(transform) - + sizeof(stickyTransform); - - if (size < minNeeded) { + if (size < minFlattenedSize()) { return NO_MEMORY; } @@ -799,6 +814,7 @@ status_t IGraphicBufferProducer::QueueBufferInput::unflatten( FlattenableUtils::read(buffer, size, scalingMode); FlattenableUtils::read(buffer, size, transform); FlattenableUtils::read(buffer, size, stickyTransform); + FlattenableUtils::read(buffer, size, getFrameTimestamps); fence = new Fence(); status_t result = fence->unflatten(buffer, size, fds, count); @@ -809,49 +825,52 @@ status_t IGraphicBufferProducer::QueueBufferInput::unflatten( } // ---------------------------------------------------------------------------- +constexpr size_t IGraphicBufferProducer::QueueBufferOutput::minFlattenedSize() { + return sizeof(width) + + sizeof(height) + + sizeof(transformHint) + + sizeof(numPendingBuffers) + + sizeof(nextFrameNumber); +} size_t IGraphicBufferProducer::QueueBufferOutput::getFlattenedSize() const { - size_t size = sizeof(width) - + sizeof(height) - + sizeof(transformHint) - + sizeof(numPendingBuffers) - + sizeof(nextFrameNumber); - return size; + return minFlattenedSize() + frameTimestamps.getFlattenedSize(); } size_t IGraphicBufferProducer::QueueBufferOutput::getFdCount() const { - return 0; + return frameTimestamps.getFdCount(); } status_t IGraphicBufferProducer::QueueBufferOutput::flatten( - void*& buffer, size_t& size, int*& /*fds*/, size_t& /*count*/) const + void*& buffer, size_t& size, int*& fds, size_t& count) const { if (size < getFlattenedSize()) { return NO_MEMORY; } + FlattenableUtils::write(buffer, size, width); FlattenableUtils::write(buffer, size, height); FlattenableUtils::write(buffer, size, transformHint); FlattenableUtils::write(buffer, size, numPendingBuffers); FlattenableUtils::write(buffer, size, nextFrameNumber); - return NO_ERROR; + return frameTimestamps.flatten(buffer, size, fds, count); } status_t IGraphicBufferProducer::QueueBufferOutput::unflatten( - void const*& buffer, size_t& size, - int const*& /*fds*/, size_t& /*count*/) + void const*& buffer, size_t& size, int const*& fds, size_t& count) { - if (size < getFlattenedSize()) { + if (size < minFlattenedSize()) { return NO_MEMORY; } + FlattenableUtils::read(buffer, size, width); FlattenableUtils::read(buffer, size, height); FlattenableUtils::read(buffer, size, transformHint); FlattenableUtils::read(buffer, size, numPendingBuffers); FlattenableUtils::read(buffer, size, nextFrameNumber); - return NO_ERROR; + return frameTimestamps.unflatten(buffer, size, fds, count); } }; // namespace android diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp index c29101e4a0..6a02a77592 100644 --- a/libs/gui/Surface.cpp +++ b/libs/gui/Surface.cpp @@ -52,7 +52,8 @@ Surface::Surface( mNextFrameNumber(1), mQueriedSupportedTimestamps(false), mFrameTimestampsSupportsPresent(false), - mFrameTimestampsSupportsRetire(false) + mFrameTimestampsSupportsRetire(false), + mEnableFrameTimestamps(false) { // Initialize the ANativeWindow function pointers. ANativeWindow::setSwapInterval = hook_setSwapInterval; @@ -138,6 +139,11 @@ status_t Surface::getLastQueuedBuffer(sp<GraphicBuffer>* outBuffer, outTransformMatrix); } +void Surface::enableFrameTimestamps(bool enable) { + Mutex::Autolock lock(mMutex); + mEnableFrameTimestamps = enable; +} + status_t Surface::getFrameTimestamps(uint64_t frameNumber, nsecs_t* outRequestedPresentTime, nsecs_t* outAcquireTime, nsecs_t* outRefreshStartTime, nsecs_t* outGlCompositionDoneTime, @@ -147,6 +153,10 @@ status_t Surface::getFrameTimestamps(uint64_t frameNumber, Mutex::Autolock lock(mMutex); + if (!mEnableFrameTimestamps) { + return INVALID_OPERATION; + } + // Verify the requested timestamps are supported. querySupportedTimestampsLocked(); if (outDisplayPresentTime != nullptr && !mFrameTimestampsSupportsPresent) { @@ -308,6 +318,7 @@ int Surface::dequeueBuffer(android_native_buffer_t** buffer, int* fenceFd) { uint32_t reqHeight; PixelFormat reqFormat; uint32_t reqUsage; + bool enableFrameTimestamps; { Mutex::Autolock lock(mMutex); @@ -318,6 +329,8 @@ int Surface::dequeueBuffer(android_native_buffer_t** buffer, int* fenceFd) { reqFormat = mReqFormat; reqUsage = mReqUsage; + enableFrameTimestamps = mEnableFrameTimestamps; + if (mSharedBufferMode && mAutoRefresh && mSharedBufferSlot != BufferItem::INVALID_BUFFER_SLOT) { sp<GraphicBuffer>& gbuf(mSlots[mSharedBufferSlot].buffer); @@ -332,8 +345,13 @@ int Surface::dequeueBuffer(android_native_buffer_t** buffer, int* fenceFd) { int buf = -1; sp<Fence> fence; nsecs_t now = systemTime(); + + FrameEventHistoryDelta frameTimestamps; + FrameEventHistoryDelta* frameTimestampsOrNull = + enableFrameTimestamps ? &frameTimestamps : nullptr; + status_t result = mGraphicBufferProducer->dequeueBuffer(&buf, &fence, - reqWidth, reqHeight, reqFormat, reqUsage); + reqWidth, reqHeight, reqFormat, reqUsage, frameTimestampsOrNull); mLastDequeueDuration = systemTime() - now; if (result < 0) { @@ -354,6 +372,10 @@ int Surface::dequeueBuffer(android_native_buffer_t** buffer, int* fenceFd) { freeAllBuffers(); } + if (enableFrameTimestamps) { + mFrameEventHistory.applyDelta(frameTimestamps); + } + if ((result & IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION) || gbuf == 0) { result = mGraphicBufferProducer->requestBuffer(buf, &gbuf); if (result != NO_ERROR) { @@ -472,7 +494,7 @@ int Surface::queueBuffer(android_native_buffer_t* buffer, int fenceFd) { IGraphicBufferProducer::QueueBufferOutput output; IGraphicBufferProducer::QueueBufferInput input(timestamp, isAutoTimestamp, mDataSpace, crop, mScalingMode, mTransform ^ mStickyTransform, - fence, mStickyTransform); + fence, mStickyTransform, mEnableFrameTimestamps); if (mConnectedToCpu || mDirtyRegion.bounds() == Rect::INVALID_RECT) { input.setSurfaceDamage(Region::INVALID_REGION); @@ -544,17 +566,24 @@ int Surface::queueBuffer(android_native_buffer_t* buffer, int fenceFd) { ALOGE("queueBuffer: error queuing buffer to SurfaceTexture, %d", err); } - uint32_t numPendingBuffers = 0; - uint32_t hint = 0; - output.deflate(&mDefaultWidth, &mDefaultHeight, &hint, - &numPendingBuffers, &mNextFrameNumber); + if (mEnableFrameTimestamps) { + mFrameEventHistory.applyDelta(output.frameTimestamps); + // Update timestamps with the local acquire fence. + // The consumer doesn't send it back to prevent us from having two + // file descriptors of the same fence. + mFrameEventHistory.updateAcquireFence(mNextFrameNumber, fence); + } + + mDefaultWidth = output.width; + mDefaultHeight = output.height; + mNextFrameNumber = output.nextFrameNumber; // Disable transform hint if sticky transform is set. if (mStickyTransform == 0) { - mTransformHint = hint; + mTransformHint = output.transformHint; } - mConsumerRunningBehind = (numPendingBuffers >= 2); + mConsumerRunningBehind = (output.numPendingBuffers >= 2); if (!mConnectedToCpu) { // Clear surface damage back to full-buffer @@ -743,6 +772,9 @@ int Surface::perform(int operation, va_list args) case NATIVE_WINDOW_SET_AUTO_REFRESH: res = dispatchSetAutoRefresh(args); break; + case NATIVE_WINDOW_ENABLE_FRAME_TIMESTAMPS: + res = dispatchEnableFrameTimestamps(args); + break; case NATIVE_WINDOW_GET_FRAME_TIMESTAMPS: res = dispatchGetFrameTimestamps(args); break; @@ -866,6 +898,12 @@ int Surface::dispatchSetAutoRefresh(va_list args) { return setAutoRefresh(autoRefresh); } +int Surface::dispatchEnableFrameTimestamps(va_list args) { + bool enable = va_arg(args, int); + enableFrameTimestamps(enable); + return NO_ERROR; +} + int Surface::dispatchGetFrameTimestamps(va_list args) { uint32_t framesAgo = va_arg(args, uint32_t); nsecs_t* outRequestedPresentTime = va_arg(args, int64_t*); @@ -893,17 +931,16 @@ int Surface::connect(int api, const sp<IProducerListener>& listener) { IGraphicBufferProducer::QueueBufferOutput output; int err = mGraphicBufferProducer->connect(listener, api, mProducerControlledByApp, &output); if (err == NO_ERROR) { - uint32_t numPendingBuffers = 0; - uint32_t hint = 0; - output.deflate(&mDefaultWidth, &mDefaultHeight, &hint, - &numPendingBuffers, &mNextFrameNumber); + mDefaultWidth = output.width; + mDefaultHeight = output.height; + mNextFrameNumber = output.nextFrameNumber; // Disable transform hint if sticky transform is set. if (mStickyTransform == 0) { - mTransformHint = hint; + mTransformHint = output.transformHint; } - mConsumerRunningBehind = (numPendingBuffers >= 2); + mConsumerRunningBehind = (output.numPendingBuffers >= 2); } if (!err && api == NATIVE_WINDOW_API_CPU) { mConnectedToCpu = true; diff --git a/libs/gui/tests/BufferQueue_test.cpp b/libs/gui/tests/BufferQueue_test.cpp index 65df7dc991..98c0449706 100644 --- a/libs/gui/tests/BufferQueue_test.cpp +++ b/libs/gui/tests/BufferQueue_test.cpp @@ -139,7 +139,7 @@ TEST_F(BufferQueueTest, BufferQueueInAnotherProcess) { sp<GraphicBuffer> buffer; ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, - GRALLOC_USAGE_SW_WRITE_OFTEN)); + GRALLOC_USAGE_SW_WRITE_OFTEN, nullptr)); ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buffer)); uint32_t* dataIn; @@ -183,7 +183,7 @@ TEST_F(BufferQueueTest, AcquireBuffer_ExceedsMaxAcquireCount_Fails) { for (int i = 0; i < 2; i++) { ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, mProducer->dequeueBuffer(&slot, &fence, 1, 1, 0, - GRALLOC_USAGE_SW_READ_OFTEN)); + GRALLOC_USAGE_SW_READ_OFTEN, nullptr)); ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buf)); ASSERT_EQ(OK, mProducer->queueBuffer(slot, qbi, &qbo)); ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, 0)); @@ -191,7 +191,7 @@ TEST_F(BufferQueueTest, AcquireBuffer_ExceedsMaxAcquireCount_Fails) { ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, mProducer->dequeueBuffer(&slot, &fence, 1, 1, 0, - GRALLOC_USAGE_SW_READ_OFTEN)); + GRALLOC_USAGE_SW_READ_OFTEN, nullptr)); ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buf)); ASSERT_EQ(OK, mProducer->queueBuffer(slot, qbi, &qbo)); @@ -234,7 +234,7 @@ TEST_F(BufferQueueTest, SetMaxAcquiredBufferCountWithIllegalValues_ReturnsError) for (int i = 0; i < 3; i++) { ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, mProducer->dequeueBuffer(&slot, &fence, 1, 1, 0, - GRALLOC_USAGE_SW_READ_OFTEN)); + GRALLOC_USAGE_SW_READ_OFTEN, nullptr)); ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buf)); ASSERT_EQ(OK, mProducer->queueBuffer(slot, qbi, &qbo)); ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, 0)); @@ -270,7 +270,7 @@ TEST_F(BufferQueueTest, SetMaxAcquiredBufferCountWithLegalValues_Succeeds) { ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, mProducer->dequeueBuffer(&slot, &fence, 1, 1, 0, - GRALLOC_USAGE_SW_READ_OFTEN)); + GRALLOC_USAGE_SW_READ_OFTEN, nullptr)); ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buf)); ASSERT_EQ(OK, mProducer->queueBuffer(slot, qbi, &qbo)); ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, 0)); @@ -280,7 +280,7 @@ TEST_F(BufferQueueTest, SetMaxAcquiredBufferCountWithLegalValues_Succeeds) { for (int i = 0; i < 2; i++) { ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, mProducer->dequeueBuffer(&slot, &fence, 1, 1, 0, - GRALLOC_USAGE_SW_READ_OFTEN)); + GRALLOC_USAGE_SW_READ_OFTEN, nullptr)); ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buf)); ASSERT_EQ(OK, mProducer->queueBuffer(slot, qbi, &qbo)); ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, 0)); @@ -330,7 +330,7 @@ TEST_F(BufferQueueTest, DetachAndReattachOnProducerSide) { sp<GraphicBuffer> buffer; ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, - GRALLOC_USAGE_SW_WRITE_OFTEN)); + GRALLOC_USAGE_SW_WRITE_OFTEN, nullptr)); ASSERT_EQ(BAD_VALUE, mProducer->detachBuffer(slot)); // Not requested ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buffer)); ASSERT_EQ(OK, mProducer->detachBuffer(slot)); @@ -379,7 +379,7 @@ TEST_F(BufferQueueTest, DetachAndReattachOnConsumerSide) { sp<GraphicBuffer> buffer; ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, - GRALLOC_USAGE_SW_WRITE_OFTEN)); + GRALLOC_USAGE_SW_WRITE_OFTEN, nullptr)); ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buffer)); IGraphicBufferProducer::QueueBufferInput input(0, false, HAL_DATASPACE_UNKNOWN, Rect(0, 0, 1, 1), @@ -415,7 +415,7 @@ TEST_F(BufferQueueTest, DetachAndReattachOnConsumerSide) { ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, - GRALLOC_USAGE_SW_WRITE_OFTEN)); + GRALLOC_USAGE_SW_WRITE_OFTEN, nullptr)); ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buffer)); uint32_t* dataOut; @@ -438,7 +438,7 @@ TEST_F(BufferQueueTest, MoveFromConsumerToProducer) { sp<GraphicBuffer> buffer; ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, - GRALLOC_USAGE_SW_WRITE_OFTEN)); + GRALLOC_USAGE_SW_WRITE_OFTEN, nullptr)); ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buffer)); uint32_t* dataIn; @@ -487,13 +487,13 @@ TEST_F(BufferQueueTest, TestDisallowingAllocation) { // This should return an error since it would require an allocation ASSERT_EQ(OK, mProducer->allowAllocation(false)); ASSERT_EQ(WOULD_BLOCK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, - 0, GRALLOC_USAGE_SW_WRITE_OFTEN)); + 0, GRALLOC_USAGE_SW_WRITE_OFTEN, nullptr)); // This should succeed, now that we've lifted the prohibition ASSERT_EQ(OK, mProducer->allowAllocation(true)); ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, - GRALLOC_USAGE_SW_WRITE_OFTEN)); + GRALLOC_USAGE_SW_WRITE_OFTEN, nullptr)); // Release the previous buffer back to the BufferQueue mProducer->cancelBuffer(slot, fence); @@ -501,7 +501,7 @@ TEST_F(BufferQueueTest, TestDisallowingAllocation) { // This should fail since we're requesting a different size ASSERT_EQ(OK, mProducer->allowAllocation(false)); ASSERT_EQ(WOULD_BLOCK, mProducer->dequeueBuffer(&slot, &fence, - WIDTH * 2, HEIGHT * 2, 0, GRALLOC_USAGE_SW_WRITE_OFTEN)); + WIDTH * 2, HEIGHT * 2, 0, GRALLOC_USAGE_SW_WRITE_OFTEN, nullptr)); } TEST_F(BufferQueueTest, TestGenerationNumbers) { @@ -518,7 +518,7 @@ TEST_F(BufferQueueTest, TestGenerationNumbers) { int slot; sp<Fence> fence; ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, - mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0)); + mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr)); sp<GraphicBuffer> buffer; ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buffer)); @@ -561,7 +561,7 @@ TEST_F(BufferQueueTest, TestSharedBufferModeWithoutAutoRefresh) { sp<Fence> fence; sp<GraphicBuffer> buffer; ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, - mProducer->dequeueBuffer(&sharedSlot, &fence, 0, 0, 0, 0)); + mProducer->dequeueBuffer(&sharedSlot, &fence, 0, 0, 0, 0, nullptr)); ASSERT_EQ(OK, mProducer->requestBuffer(sharedSlot, &buffer)); // Queue the buffer @@ -575,7 +575,8 @@ TEST_F(BufferQueueTest, TestSharedBufferModeWithoutAutoRefresh) { // always the same one and because async mode gets enabled. int slot; for (int i = 0; i < 5; i++) { - ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0)); + ASSERT_EQ(OK, mProducer->dequeueBuffer( + &slot, &fence, 0, 0, 0, 0, nullptr)); ASSERT_EQ(sharedSlot, slot); ASSERT_EQ(OK, mProducer->queueBuffer(sharedSlot, input, &output)); } @@ -612,7 +613,7 @@ TEST_F(BufferQueueTest, TestSharedBufferModeWithAutoRefresh) { sp<Fence> fence; sp<GraphicBuffer> buffer; ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, - mProducer->dequeueBuffer(&sharedSlot, &fence, 0, 0, 0, 0)); + mProducer->dequeueBuffer(&sharedSlot, &fence, 0, 0, 0, 0, nullptr)); ASSERT_EQ(OK, mProducer->requestBuffer(sharedSlot, &buffer)); // Queue the buffer @@ -639,7 +640,8 @@ TEST_F(BufferQueueTest, TestSharedBufferModeWithAutoRefresh) { // always return the same one. int slot; for (int i = 0; i < 5; i++) { - ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0)); + ASSERT_EQ(OK, mProducer->dequeueBuffer( + &slot, &fence, 0, 0, 0, 0, nullptr)); ASSERT_EQ(sharedSlot, slot); ASSERT_EQ(OK, mProducer->queueBuffer(sharedSlot, input, &output)); } @@ -678,7 +680,7 @@ TEST_F(BufferQueueTest, TestSharedBufferModeUsingAlreadyDequeuedBuffer) { sp<Fence> fence; sp<GraphicBuffer> buffer; ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, - mProducer->dequeueBuffer(&sharedSlot, &fence, 0, 0, 0, 0)); + mProducer->dequeueBuffer(&sharedSlot, &fence, 0, 0, 0, 0, nullptr)); ASSERT_EQ(OK, mProducer->requestBuffer(sharedSlot, &buffer)); // Enable shared buffer mode @@ -695,7 +697,8 @@ TEST_F(BufferQueueTest, TestSharedBufferModeUsingAlreadyDequeuedBuffer) { // always the same one and because async mode gets enabled. int slot; for (int i = 0; i < 5; i++) { - ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0)); + ASSERT_EQ(OK, mProducer->dequeueBuffer( + &slot, &fence, 0, 0, 0, 0, nullptr)); ASSERT_EQ(sharedSlot, slot); ASSERT_EQ(OK, mProducer->queueBuffer(sharedSlot, input, &output)); } @@ -730,7 +733,8 @@ TEST_F(BufferQueueTest, TestTimeouts) { for (int i = 0; i < 5; ++i) { int slot = BufferQueue::INVALID_BUFFER_SLOT; sp<Fence> fence = Fence::NO_FENCE; - auto result = mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0); + auto result = mProducer->dequeueBuffer( + &slot, &fence, 0, 0, 0, 0, nullptr); if (i < 2) { ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, result); @@ -757,7 +761,8 @@ TEST_F(BufferQueueTest, TestTimeouts) { for (int i = 0; i < 2; ++i) { int slot = BufferQueue::INVALID_BUFFER_SLOT; sp<Fence> fence = Fence::NO_FENCE; - ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0)); + ASSERT_EQ(OK, mProducer->dequeueBuffer( + &slot, &fence, 0, 0, 0, 0, nullptr)); ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buffer)); IGraphicBufferProducer::QueueBufferInput input(0ull, true, HAL_DATASPACE_UNKNOWN, Rect::INVALID_RECT, @@ -768,7 +773,8 @@ TEST_F(BufferQueueTest, TestTimeouts) { int slot = BufferQueue::INVALID_BUFFER_SLOT; sp<Fence> fence = Fence::NO_FENCE; auto startTime = systemTime(); - ASSERT_EQ(TIMED_OUT, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0)); + ASSERT_EQ(TIMED_OUT, mProducer->dequeueBuffer( + &slot, &fence, 0, 0, 0, 0, nullptr)); ASSERT_GE(systemTime() - startTime, TIMEOUT); // We're technically attaching the same buffer multiple times (since we @@ -789,7 +795,7 @@ TEST_F(BufferQueueTest, CanAttachWhileDisallowingAllocation) { int slot = BufferQueue::INVALID_BUFFER_SLOT; sp<Fence> sourceFence; ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, - mProducer->dequeueBuffer(&slot, &sourceFence, 0, 0, 0, 0)); + mProducer->dequeueBuffer(&slot, &sourceFence, 0, 0, 0, 0, nullptr)); sp<GraphicBuffer> buffer; ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buffer)); ASSERT_EQ(OK, mProducer->detachBuffer(slot)); @@ -812,7 +818,7 @@ TEST_F(BufferQueueTest, CanRetrieveLastQueuedBuffer) { int slot = BufferQueue::INVALID_BUFFER_SLOT; sp<Fence> fence; ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, - mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0)); + mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr)); sp<GraphicBuffer> firstBuffer; ASSERT_EQ(OK, mProducer->requestBuffer(slot, &firstBuffer)); @@ -824,7 +830,7 @@ TEST_F(BufferQueueTest, CanRetrieveLastQueuedBuffer) { // Dequeue a second buffer slot = BufferQueue::INVALID_BUFFER_SLOT; ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, - mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0)); + mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr)); sp<GraphicBuffer> secondBuffer; ASSERT_EQ(OK, mProducer->requestBuffer(slot, &secondBuffer)); @@ -876,7 +882,7 @@ TEST_F(BufferQueueTest, TestOccupancyHistory) { mProducer->setMaxDequeuedBufferCount(3); for (size_t i = 0; i < 3; ++i) { status_t result = mProducer->dequeueBuffer(&slots[i], &fence, - 0, 0, 0, 0); + 0, 0, 0, 0, nullptr); ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, result); ASSERT_EQ(OK, mProducer->requestBuffer(slots[i], &buffer)); } @@ -889,7 +895,8 @@ TEST_F(BufferQueueTest, TestOccupancyHistory) { // The first segment is a two-buffer segment, so we only put one buffer into // the queue at a time for (size_t i = 0; i < 5; ++i) { - ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0)); + ASSERT_EQ(OK, mProducer->dequeueBuffer( + &slot, &fence, 0, 0, 0, 0, nullptr)); ASSERT_EQ(OK, mProducer->queueBuffer(slot, input, &output)); ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, 0)); ASSERT_EQ(OK, mConsumer->releaseBuffer(item.mSlot, item.mFrameNumber, @@ -904,16 +911,17 @@ TEST_F(BufferQueueTest, TestOccupancyHistory) { // two-buffer segment, but then at the end, we put two buffers in the queue // at the same time before draining it. for (size_t i = 0; i < 5; ++i) { - ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0)); + ASSERT_EQ(OK, mProducer->dequeueBuffer( + &slot, &fence, 0, 0, 0, 0, nullptr)); ASSERT_EQ(OK, mProducer->queueBuffer(slot, input, &output)); ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, 0)); ASSERT_EQ(OK, mConsumer->releaseBuffer(item.mSlot, item.mFrameNumber, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, Fence::NO_FENCE)); std::this_thread::sleep_for(16ms); } - ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0)); + ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr)); ASSERT_EQ(OK, mProducer->queueBuffer(slot, input, &output)); - ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0)); + ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr)); ASSERT_EQ(OK, mProducer->queueBuffer(slot, input, &output)); ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, 0)); ASSERT_EQ(OK, mConsumer->releaseBuffer(item.mSlot, item.mFrameNumber, @@ -928,10 +936,11 @@ TEST_F(BufferQueueTest, TestOccupancyHistory) { // The third segment is a triple-buffer segment, so the queue is switching // between one buffer and two buffers deep. - ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0)); + ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr)); ASSERT_EQ(OK, mProducer->queueBuffer(slot, input, &output)); for (size_t i = 0; i < 5; ++i) { - ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0)); + ASSERT_EQ(OK, mProducer->dequeueBuffer( + &slot, &fence, 0, 0, 0, 0, nullptr)); ASSERT_EQ(OK, mProducer->queueBuffer(slot, input, &output)); ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, 0)); ASSERT_EQ(OK, mConsumer->releaseBuffer(item.mSlot, item.mFrameNumber, @@ -1012,7 +1021,7 @@ TEST_F(BufferQueueTest, TestDiscardFreeBuffers) { mProducer->setMaxDequeuedBufferCount(4); for (size_t i = 0; i < 4; ++i) { status_t result = mProducer->dequeueBuffer(&slots[i], &fence, - 0, 0, 0, 0); + 0, 0, 0, 0, nullptr); ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, result); ASSERT_EQ(OK, mProducer->requestBuffer(slots[i], &buffer)); } @@ -1023,14 +1032,14 @@ TEST_F(BufferQueueTest, TestDiscardFreeBuffers) { // Get buffers in all states: dequeued, filled, acquired, free // Fill 3 buffers - ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0)); + ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr)); ASSERT_EQ(OK, mProducer->queueBuffer(slot, input, &output)); - ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0)); + ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr)); ASSERT_EQ(OK, mProducer->queueBuffer(slot, input, &output)); - ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0)); + ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr)); ASSERT_EQ(OK, mProducer->queueBuffer(slot, input, &output)); // Dequeue 1 buffer - ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0)); + ASSERT_EQ(OK, mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, 0, nullptr)); // Acquire and free 1 buffer ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, 0)); diff --git a/libs/gui/tests/IGraphicBufferProducer_test.cpp b/libs/gui/tests/IGraphicBufferProducer_test.cpp index 9f3304731e..0329a6d61f 100644 --- a/libs/gui/tests/IGraphicBufferProducer_test.cpp +++ b/libs/gui/tests/IGraphicBufferProducer_test.cpp @@ -196,7 +196,7 @@ protected: }; status_t dequeueBuffer(uint32_t w, uint32_t h, uint32_t format, uint32_t usage, DequeueBufferResult* result) { - return mProducer->dequeueBuffer(&result->slot, &result->fence, w, h, format, usage); + return mProducer->dequeueBuffer(&result->slot, &result->fence, w, h, format, usage, nullptr); } void setupDequeueRequestBuffer(int *slot, sp<Fence> *fence, @@ -210,7 +210,7 @@ protected: ASSERT_EQ(OK, ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION & (mProducer->dequeueBuffer(slot, fence, DEFAULT_WIDTH, - DEFAULT_HEIGHT, DEFAULT_FORMAT, TEST_PRODUCER_USAGE_BITS))); + DEFAULT_HEIGHT, DEFAULT_FORMAT, TEST_PRODUCER_USAGE_BITS, nullptr))); EXPECT_LE(0, *slot); EXPECT_GT(BufferQueue::NUM_BUFFER_SLOTS, *slot); @@ -349,7 +349,7 @@ TEST_F(IGraphicBufferProducerTest, Queue_Succeeds) { ASSERT_EQ(OK, ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION & (mProducer->dequeueBuffer(&dequeuedSlot, &dequeuedFence, DEFAULT_WIDTH, DEFAULT_HEIGHT, DEFAULT_FORMAT, - TEST_PRODUCER_USAGE_BITS))); + TEST_PRODUCER_USAGE_BITS, nullptr))); EXPECT_LE(0, dequeuedSlot); EXPECT_GT(BufferQueue::NUM_BUFFER_SLOTS, dequeuedSlot); @@ -366,20 +366,12 @@ TEST_F(IGraphicBufferProducerTest, Queue_Succeeds) { ASSERT_OK(mProducer->queueBuffer(dequeuedSlot, input, &output)); { - uint32_t width; - uint32_t height; - uint32_t transformHint; - uint32_t numPendingBuffers; - uint64_t nextFrameNumber; - - output.deflate(&width, &height, &transformHint, &numPendingBuffers, - &nextFrameNumber); - - EXPECT_EQ(DEFAULT_WIDTH, width); - EXPECT_EQ(DEFAULT_HEIGHT, height); - EXPECT_EQ(DEFAULT_TRANSFORM_HINT, transformHint); - EXPECT_EQ(1u, numPendingBuffers); // since queueBuffer was called exactly once - EXPECT_EQ(2u, nextFrameNumber); + EXPECT_EQ(DEFAULT_WIDTH, output.width); + EXPECT_EQ(DEFAULT_HEIGHT, output.height); + EXPECT_EQ(DEFAULT_TRANSFORM_HINT, output.transformHint); + // Since queueBuffer was called exactly once + EXPECT_EQ(1u, output.numPendingBuffers); + EXPECT_EQ(2u, output.nextFrameNumber); } // Buffer was not in the dequeued state @@ -416,7 +408,7 @@ TEST_F(IGraphicBufferProducerTest, Queue_ReturnsError) { ASSERT_EQ(OK, ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION & (mProducer->dequeueBuffer(&dequeuedSlot, &dequeuedFence, DEFAULT_WIDTH, DEFAULT_HEIGHT, DEFAULT_FORMAT, - TEST_PRODUCER_USAGE_BITS))); + TEST_PRODUCER_USAGE_BITS, nullptr))); // Slot was enqueued without requesting a buffer { @@ -485,7 +477,7 @@ TEST_F(IGraphicBufferProducerTest, CancelBuffer_DoesntCrash) { ASSERT_EQ(OK, ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION & (mProducer->dequeueBuffer(&dequeuedSlot, &dequeuedFence, DEFAULT_WIDTH, DEFAULT_HEIGHT, DEFAULT_FORMAT, - TEST_PRODUCER_USAGE_BITS))); + TEST_PRODUCER_USAGE_BITS, nullptr))); // No return code, but at least test that it doesn't blow up... // TODO: add a return code @@ -534,7 +526,7 @@ TEST_F(IGraphicBufferProducerTest, SetMaxDequeuedBufferCount_Succeeds) { (mProducer->dequeueBuffer(&dequeuedSlot, &dequeuedFence, DEFAULT_WIDTH, DEFAULT_HEIGHT, DEFAULT_FORMAT, - TEST_PRODUCER_USAGE_BITS))) + TEST_PRODUCER_USAGE_BITS, nullptr))) << "iteration: " << i << ", slot: " << dequeuedSlot; } @@ -571,7 +563,7 @@ TEST_F(IGraphicBufferProducerTest, SetMaxDequeuedBufferCount_Fails) { (mProducer->dequeueBuffer(&dequeuedSlot, &dequeuedFence, DEFAULT_WIDTH, DEFAULT_HEIGHT, DEFAULT_FORMAT, - TEST_PRODUCER_USAGE_BITS))) + TEST_PRODUCER_USAGE_BITS, nullptr))) << "slot: " << dequeuedSlot; } @@ -606,7 +598,8 @@ TEST_F(IGraphicBufferProducerTest, SetAsyncMode_Succeeds) { ASSERT_EQ(OK, ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION & (mProducer->dequeueBuffer(&dequeuedSlot, &dequeuedFence, DEFAULT_WIDTH, DEFAULT_HEIGHT, DEFAULT_FORMAT, - TEST_PRODUCER_USAGE_BITS))) << "slot : " << dequeuedSlot; + TEST_PRODUCER_USAGE_BITS, nullptr))) + << "slot : " << dequeuedSlot; ASSERT_OK(mProducer->requestBuffer(dequeuedSlot, &dequeuedBuffer)); ASSERT_OK(mProducer->queueBuffer(dequeuedSlot, input, &output)); } @@ -622,7 +615,8 @@ TEST_F(IGraphicBufferProducerTest, SetAsyncMode_Fails) { ASSERT_EQ(OK, ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION & (mProducer->dequeueBuffer(&dequeuedSlot, &dequeuedFence, DEFAULT_WIDTH, DEFAULT_HEIGHT, DEFAULT_FORMAT, - TEST_PRODUCER_USAGE_BITS))) << "slot: " << dequeuedSlot; + TEST_PRODUCER_USAGE_BITS, nullptr))) + << "slot: " << dequeuedSlot; } // Abandon buffer queue @@ -639,7 +633,7 @@ TEST_F(IGraphicBufferProducerTest, sp<Fence> fence; ASSERT_EQ(NO_INIT, mProducer->dequeueBuffer(&slot, &fence, DEFAULT_WIDTH, - DEFAULT_HEIGHT, DEFAULT_FORMAT, TEST_PRODUCER_USAGE_BITS)); + DEFAULT_HEIGHT, DEFAULT_FORMAT, TEST_PRODUCER_USAGE_BITS, nullptr)); } TEST_F(IGraphicBufferProducerTest, @@ -659,7 +653,8 @@ TEST_F(IGraphicBufferProducerTest, ASSERT_EQ(OK, ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION & (mProducer->dequeueBuffer(&slot, &fence, DEFAULT_WIDTH, - DEFAULT_HEIGHT, DEFAULT_FORMAT, TEST_PRODUCER_USAGE_BITS))); + DEFAULT_HEIGHT, DEFAULT_FORMAT, TEST_PRODUCER_USAGE_BITS, + nullptr))); EXPECT_LE(0, slot); EXPECT_GT(BufferQueue::NUM_BUFFER_SLOTS, slot); diff --git a/libs/gui/tests/StreamSplitter_test.cpp b/libs/gui/tests/StreamSplitter_test.cpp index 498492e179..80e30da84a 100644 --- a/libs/gui/tests/StreamSplitter_test.cpp +++ b/libs/gui/tests/StreamSplitter_test.cpp @@ -81,7 +81,7 @@ TEST_F(StreamSplitterTest, OneInputOneOutput) { sp<GraphicBuffer> buffer; ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, inputProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, - GRALLOC_USAGE_SW_WRITE_OFTEN)); + GRALLOC_USAGE_SW_WRITE_OFTEN, nullptr)); ASSERT_EQ(OK, inputProducer->requestBuffer(slot, &buffer)); uint32_t* dataIn; @@ -115,7 +115,7 @@ TEST_F(StreamSplitterTest, OneInputOneOutput) { // received the buffer back from the output BufferQueue ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, inputProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, - GRALLOC_USAGE_SW_WRITE_OFTEN)); + GRALLOC_USAGE_SW_WRITE_OFTEN, nullptr)); } TEST_F(StreamSplitterTest, OneInputMultipleOutputs) { @@ -153,7 +153,7 @@ TEST_F(StreamSplitterTest, OneInputMultipleOutputs) { sp<GraphicBuffer> buffer; ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, inputProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, - GRALLOC_USAGE_SW_WRITE_OFTEN)); + GRALLOC_USAGE_SW_WRITE_OFTEN, nullptr)); ASSERT_EQ(OK, inputProducer->requestBuffer(slot, &buffer)); uint32_t* dataIn; @@ -190,7 +190,7 @@ TEST_F(StreamSplitterTest, OneInputMultipleOutputs) { // received the buffer back from the output BufferQueues ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, inputProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, - GRALLOC_USAGE_SW_WRITE_OFTEN)); + GRALLOC_USAGE_SW_WRITE_OFTEN, nullptr)); } TEST_F(StreamSplitterTest, OutputAbandonment) { @@ -217,7 +217,7 @@ TEST_F(StreamSplitterTest, OutputAbandonment) { sp<GraphicBuffer> buffer; ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, inputProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, - GRALLOC_USAGE_SW_WRITE_OFTEN)); + GRALLOC_USAGE_SW_WRITE_OFTEN, nullptr)); ASSERT_EQ(OK, inputProducer->requestBuffer(slot, &buffer)); // Abandon the output @@ -230,7 +230,7 @@ TEST_F(StreamSplitterTest, OutputAbandonment) { // Input should be abandoned ASSERT_EQ(NO_INIT, inputProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, - GRALLOC_USAGE_SW_WRITE_OFTEN)); + GRALLOC_USAGE_SW_WRITE_OFTEN, nullptr)); } } // namespace android diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp index d5a02e35de..3d3df766a8 100644 --- a/opengl/libs/EGL/eglApi.cpp +++ b/opengl/libs/EGL/eglApi.cpp @@ -1218,7 +1218,6 @@ EGLBoolean eglSurfaceAttrib( if (!s->win.get()) { return setError(EGL_BAD_SURFACE, EGL_FALSE); } - s->enableTimestamps = value; int err = native_window_enable_frame_timestamps( s->win.get(), value ? true : false); return (err == NO_ERROR) ? EGL_TRUE : @@ -2040,7 +2039,7 @@ EGLBoolean eglGetFrameTimestampsANDROID(EGLDisplay dpy, EGLSurface surface, egl_surface_t const * const s = get_surface(surface); - if (!s->enableTimestamps) { + if (!s->win.get()) { return setError(EGL_BAD_SURFACE, EGL_FALSE); } @@ -2090,6 +2089,8 @@ EGLBoolean eglGetFrameTimestampsANDROID(EGLDisplay dpy, EGLSurface surface, return EGL_TRUE; case NAME_NOT_FOUND: return setError(EGL_BAD_ACCESS, EGL_FALSE); + case INVALID_OPERATION: + return setError(EGL_BAD_SURFACE, EGL_FALSE); case BAD_VALUE: return setError(EGL_BAD_PARAMETER, EGL_FALSE); default: diff --git a/opengl/libs/EGL/egl_object.cpp b/opengl/libs/EGL/egl_object.cpp index 6a76737f70..7fc56094bf 100644 --- a/opengl/libs/EGL/egl_object.cpp +++ b/opengl/libs/EGL/egl_object.cpp @@ -68,7 +68,7 @@ egl_surface_t::egl_surface_t(egl_display_t* dpy, EGLConfig config, EGLNativeWindowType win, EGLSurface surface, egl_connection_t const* cnx) : egl_object_t(dpy), surface(surface), config(config), win(win), cnx(cnx), - enableTimestamps(false), connected(true) + connected(true) {} egl_surface_t::~egl_surface_t() { diff --git a/opengl/libs/EGL/egl_object.h b/opengl/libs/EGL/egl_object.h index 3150ba6918..8ceba1d892 100644 --- a/opengl/libs/EGL/egl_object.h +++ b/opengl/libs/EGL/egl_object.h @@ -139,7 +139,6 @@ public: EGLConfig config; sp<ANativeWindow> win; egl_connection_t const* cnx; - bool enableTimestamps; private: bool connected; void disconnect(); diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp index 69902e2ba2..9de74d67f7 100644 --- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp +++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp @@ -340,7 +340,7 @@ status_t VirtualDisplaySurface::dequeueBuffer(Source source, LOG_FATAL_IF(mDisplayId < 0, "mDisplayId=%d but should not be < 0.", mDisplayId); status_t result = mSource[source]->dequeueBuffer(sslot, fence, - mSinkBufferWidth, mSinkBufferHeight, format, usage); + mSinkBufferWidth, mSinkBufferHeight, format, usage, nullptr); if (result < 0) return result; int pslot = mapSource2ProducerSlot(source, *sslot); @@ -379,9 +379,12 @@ status_t VirtualDisplaySurface::dequeueBuffer(Source source, } status_t VirtualDisplaySurface::dequeueBuffer(int* pslot, sp<Fence>* fence, - uint32_t w, uint32_t h, PixelFormat format, uint32_t usage) { - if (mDisplayId < 0) - return mSource[SOURCE_SINK]->dequeueBuffer(pslot, fence, w, h, format, usage); + uint32_t w, uint32_t h, PixelFormat format, uint32_t usage, + FrameEventHistoryDelta* outTimestamps) { + if (mDisplayId < 0) { + return mSource[SOURCE_SINK]->dequeueBuffer( + pslot, fence, w, h, format, usage, outTimestamps); + } VDS_LOGW_IF(mDbgState != DBG_STATE_PREPARED, "Unexpected dequeueBuffer() in %s state", dbgStateStr()); diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h index 70f717f8c2..b435bf56fb 100644 --- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h +++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h @@ -104,7 +104,8 @@ private: virtual status_t setMaxDequeuedBufferCount(int maxDequeuedBuffers); virtual status_t setAsyncMode(bool async); virtual status_t dequeueBuffer(int* pslot, sp<Fence>* fence, uint32_t w, - uint32_t h, PixelFormat format, uint32_t usage); + uint32_t h, PixelFormat format, uint32_t usage, + FrameEventHistoryDelta *outTimestamps); virtual status_t detachBuffer(int slot); virtual status_t detachNextBuffer(sp<GraphicBuffer>* outBuffer, sp<Fence>* outFence); diff --git a/services/surfaceflinger/MonitoredProducer.cpp b/services/surfaceflinger/MonitoredProducer.cpp index a2cc531d5e..359ca4e6a8 100644 --- a/services/surfaceflinger/MonitoredProducer.cpp +++ b/services/surfaceflinger/MonitoredProducer.cpp @@ -66,8 +66,10 @@ status_t MonitoredProducer::setAsyncMode(bool async) { } status_t MonitoredProducer::dequeueBuffer(int* slot, sp<Fence>* fence, - uint32_t w, uint32_t h, PixelFormat format, uint32_t usage) { - return mProducer->dequeueBuffer(slot, fence, w, h, format, usage); + uint32_t w, uint32_t h, PixelFormat format, uint32_t usage, + FrameEventHistoryDelta* outTimestamps) { + return mProducer->dequeueBuffer( + slot, fence, w, h, format, usage, outTimestamps); } status_t MonitoredProducer::detachBuffer(int slot) { diff --git a/services/surfaceflinger/MonitoredProducer.h b/services/surfaceflinger/MonitoredProducer.h index 3e64cae985..17adaa7395 100644 --- a/services/surfaceflinger/MonitoredProducer.h +++ b/services/surfaceflinger/MonitoredProducer.h @@ -38,7 +38,8 @@ public: virtual status_t setMaxDequeuedBufferCount(int maxDequeuedBuffers); virtual status_t setAsyncMode(bool async); virtual status_t dequeueBuffer(int* slot, sp<Fence>* fence, uint32_t w, - uint32_t h, PixelFormat format, uint32_t usage); + uint32_t h, PixelFormat format, uint32_t usage, + FrameEventHistoryDelta* outTimestamps); virtual status_t detachBuffer(int slot); virtual status_t detachNextBuffer(sp<GraphicBuffer>* outBuffer, sp<Fence>* outFence); |