diff options
author | 2021-05-18 00:42:56 -0400 | |
---|---|---|
committer | 2021-05-19 14:46:53 -0400 | |
commit | aa5a0b26bbeb37f60e091729405bd57169d1dcbc (patch) | |
tree | 6a599a026aa27aa6bb578519b34975cf9bc357b4 | |
parent | 18c797058c7b4a02a0af26f73115beb448650135 (diff) |
Add a better getLastQueuedBuffer
Avoid obfuscation via a matrix that's not necessarily useful or in
the desired origin of the caller. Instead return the source data,
which is also a lot smaller than the matrix is...
Bug: 183553027
Test: atest android.view.cts.PixelCopyTest (+new testBufferQueueCrop)
Change-Id: I1f7b5981405b2f20293bce9119414fc7780b8eb6
-rw-r--r-- | libs/gui/BufferQueueProducer.cpp | 20 | ||||
-rw-r--r-- | libs/gui/IGraphicBufferProducer.cpp | 95 | ||||
-rw-r--r-- | libs/gui/Surface.cpp | 36 | ||||
-rw-r--r-- | libs/gui/include/gui/BufferQueueProducer.h | 4 | ||||
-rw-r--r-- | libs/gui/include/gui/IGraphicBufferProducer.h | 16 | ||||
-rw-r--r-- | libs/gui/include/gui/Surface.h | 1 | ||||
-rw-r--r-- | libs/nativewindow/include/system/window.h | 26 |
7 files changed, 198 insertions, 0 deletions
diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp index a7cf39add9..df308d897b 100644 --- a/libs/gui/BufferQueueProducer.cpp +++ b/libs/gui/BufferQueueProducer.cpp @@ -1621,6 +1621,26 @@ status_t BufferQueueProducer::getLastQueuedBuffer(sp<GraphicBuffer>* outBuffer, return NO_ERROR; } +status_t BufferQueueProducer::getLastQueuedBuffer(sp<GraphicBuffer>* outBuffer, sp<Fence>* outFence, + Rect* outRect, uint32_t* outTransform) { + ATRACE_CALL(); + BQ_LOGV("getLastQueuedBuffer"); + + std::lock_guard<std::mutex> lock(mCore->mMutex); + if (mCore->mLastQueuedSlot == BufferItem::INVALID_BUFFER_SLOT) { + *outBuffer = nullptr; + *outFence = Fence::NO_FENCE; + return NO_ERROR; + } + + *outBuffer = mSlots[mCore->mLastQueuedSlot].mGraphicBuffer; + *outFence = mLastQueueBufferFence; + *outRect = mLastQueuedCrop; + *outTransform = mLastQueuedTransform; + + return NO_ERROR; +} + void BufferQueueProducer::getFrameTimestamps(FrameEventHistoryDelta* outDelta) { addAndGetFrameTimestamps(nullptr, outDelta); } diff --git a/libs/gui/IGraphicBufferProducer.cpp b/libs/gui/IGraphicBufferProducer.cpp index c1f9b85229..797069c798 100644 --- a/libs/gui/IGraphicBufferProducer.cpp +++ b/libs/gui/IGraphicBufferProducer.cpp @@ -81,6 +81,7 @@ enum { QUEUE_BUFFERS, CANCEL_BUFFERS, QUERY_MULTIPLE, + GET_LAST_QUEUED_BUFFER2, }; class BpGraphicBufferProducer : public BpInterface<IGraphicBufferProducer> @@ -646,6 +647,56 @@ public: return result; } + virtual status_t getLastQueuedBuffer(sp<GraphicBuffer>* outBuffer, sp<Fence>* outFence, + Rect* outRect, uint32_t* outTransform) override { + Parcel data, reply; + data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor()); + status_t result = remote()->transact(GET_LAST_QUEUED_BUFFER2, data, &reply); + if (result != NO_ERROR) { + ALOGE("getLastQueuedBuffer failed to transact: %d", result); + return result; + } + status_t remoteError = NO_ERROR; + result = reply.readInt32(&remoteError); + if (result != NO_ERROR) { + ALOGE("getLastQueuedBuffer failed to read status: %d", result); + return result; + } + if (remoteError != NO_ERROR) { + return remoteError; + } + bool hasBuffer = false; + result = reply.readBool(&hasBuffer); + if (result != NO_ERROR) { + ALOGE("getLastQueuedBuffer failed to read buffer: %d", result); + return result; + } + sp<GraphicBuffer> buffer; + if (hasBuffer) { + buffer = new GraphicBuffer(); + result = reply.read(*buffer); + if (result == NO_ERROR) { + result = reply.read(*outRect); + } + if (result == NO_ERROR) { + result = reply.readUint32(outTransform); + } + } + if (result != NO_ERROR) { + ALOGE("getLastQueuedBuffer failed to read buffer: %d", result); + return result; + } + sp<Fence> fence(new Fence); + result = reply.read(*fence); + if (result != NO_ERROR) { + ALOGE("getLastQueuedBuffer failed to read fence: %d", result); + return result; + } + *outBuffer = buffer; + *outFence = fence; + return result; + } + virtual void getFrameTimestamps(FrameEventHistoryDelta* outDelta) { Parcel data, reply; status_t result = data.writeInterfaceToken( @@ -870,6 +921,11 @@ public: outBuffer, outFence, outTransformMatrix); } + status_t getLastQueuedBuffer(sp<GraphicBuffer>* outBuffer, sp<Fence>* outFence, Rect* outRect, + uint32_t* outTransform) override { + return mBase->getLastQueuedBuffer(outBuffer, outFence, outRect, outTransform); + } + void getFrameTimestamps(FrameEventHistoryDelta* outDelta) override { return mBase->getFrameTimestamps(outDelta); } @@ -1362,6 +1418,45 @@ status_t BnGraphicBufferProducer::onTransact( } return NO_ERROR; } + case GET_LAST_QUEUED_BUFFER2: { + CHECK_INTERFACE(IGraphicBufferProducer, data, reply); + sp<GraphicBuffer> buffer(nullptr); + sp<Fence> fence(Fence::NO_FENCE); + Rect crop; + uint32_t transform; + status_t result = getLastQueuedBuffer(&buffer, &fence, &crop, &transform); + reply->writeInt32(result); + if (result != NO_ERROR) { + return result; + } + if (!buffer.get()) { + reply->writeBool(false); + } else { + reply->writeBool(true); + result = reply->write(*buffer); + if (result == NO_ERROR) { + result = reply->write(crop); + } + if (result == NO_ERROR) { + result = reply->writeUint32(transform); + } + } + if (result != NO_ERROR) { + ALOGE("getLastQueuedBuffer failed to write buffer: %d", result); + return result; + } + if (fence == nullptr) { + ALOGE("getLastQueuedBuffer returned a NULL fence, setting to Fence::NO_FENCE"); + fence = Fence::NO_FENCE; + } + result = reply->write(*fence); + if (result != NO_ERROR) { + ALOGE("getLastQueuedBuffer failed to write fence: %d", result); + return result; + } + return NO_ERROR; + } + case GET_FRAME_TIMESTAMPS: { CHECK_INTERFACE(IGraphicBufferProducer, data, reply); FrameEventHistoryDelta frameTimestamps; diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp index 2fc9d47b89..89e80c1808 100644 --- a/libs/gui/Surface.cpp +++ b/libs/gui/Surface.cpp @@ -1492,6 +1492,9 @@ int Surface::perform(int operation, va_list args) case NATIVE_WINDOW_GET_LAST_QUEUED_BUFFER: res = dispatchGetLastQueuedBuffer(args); break; + case NATIVE_WINDOW_GET_LAST_QUEUED_BUFFER2: + res = dispatchGetLastQueuedBuffer2(args); + break; case NATIVE_WINDOW_SET_FRAME_TIMELINE_INFO: res = dispatchSetFrameTimelineInfo(args); break; @@ -1805,6 +1808,39 @@ int Surface::dispatchGetLastQueuedBuffer(va_list args) { return result; } +int Surface::dispatchGetLastQueuedBuffer2(va_list args) { + AHardwareBuffer** buffer = va_arg(args, AHardwareBuffer**); + int* fence = va_arg(args, int*); + ARect* crop = va_arg(args, ARect*); + uint32_t* transform = va_arg(args, uint32_t*); + sp<GraphicBuffer> graphicBuffer; + sp<Fence> spFence; + + Rect r; + int result = + mGraphicBufferProducer->getLastQueuedBuffer(&graphicBuffer, &spFence, &r, transform); + + if (graphicBuffer != nullptr) { + *buffer = graphicBuffer->toAHardwareBuffer(); + AHardwareBuffer_acquire(*buffer); + + // Avoid setting crop* unless buffer is valid (matches IGBP behavior) + crop->left = r.left; + crop->top = r.top; + crop->right = r.right; + crop->bottom = r.bottom; + } else { + *buffer = nullptr; + } + + if (spFence != nullptr) { + *fence = spFence->dup(); + } else { + *fence = -1; + } + return result; +} + int Surface::dispatchSetFrameTimelineInfo(va_list args) { ATRACE_CALL(); auto frameTimelineVsyncId = static_cast<int64_t>(va_arg(args, int64_t)); diff --git a/libs/gui/include/gui/BufferQueueProducer.h b/libs/gui/include/gui/BufferQueueProducer.h index a7f7d1defa..0ad3075a4d 100644 --- a/libs/gui/include/gui/BufferQueueProducer.h +++ b/libs/gui/include/gui/BufferQueueProducer.h @@ -186,6 +186,10 @@ public: virtual status_t getLastQueuedBuffer(sp<GraphicBuffer>* outBuffer, sp<Fence>* outFence, float outTransformMatrix[16]) override; + // See IGraphicBufferProducer::getLastQueuedBuffer + virtual status_t getLastQueuedBuffer(sp<GraphicBuffer>* outBuffer, sp<Fence>* outFence, + Rect* outRect, uint32_t* outTransform) override; + // See IGraphicBufferProducer::getFrameTimestamps virtual void getFrameTimestamps(FrameEventHistoryDelta* outDelta) override; diff --git a/libs/gui/include/gui/IGraphicBufferProducer.h b/libs/gui/include/gui/IGraphicBufferProducer.h index c3b92622b6..98df83453d 100644 --- a/libs/gui/include/gui/IGraphicBufferProducer.h +++ b/libs/gui/include/gui/IGraphicBufferProducer.h @@ -640,6 +640,22 @@ public: virtual status_t getLastQueuedBuffer(sp<GraphicBuffer>* outBuffer, sp<Fence>* outFence, float outTransformMatrix[16]) = 0; + // Returns the last queued buffer along with a fence which must signal + // before the contents of the buffer are read. If there are no buffers in + // the queue, outBuffer will be populated with nullptr and outFence will be + // populated with Fence::NO_FENCE + // + // outRect & outTransform are not modified if outBuffer is null. + // + // Returns NO_ERROR or the status of the Binder transaction + virtual status_t getLastQueuedBuffer([[maybe_unused]] sp<GraphicBuffer>* outBuffer, + [[maybe_unused]] sp<Fence>* outFence, + [[maybe_unused]] Rect* outRect, + [[maybe_unused]] uint32_t* outTransform) { + // Too many things implement IGraphicBufferProducer... + return UNKNOWN_TRANSACTION; + } + // Gets the frame events that haven't already been retrieved. virtual void getFrameTimestamps(FrameEventHistoryDelta* /*outDelta*/) {} diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h index d22bdaaa98..250e13fe26 100644 --- a/libs/gui/include/gui/Surface.h +++ b/libs/gui/include/gui/Surface.h @@ -276,6 +276,7 @@ private: int dispatchAddQueueInterceptor(va_list args); int dispatchAddQueryInterceptor(va_list args); int dispatchGetLastQueuedBuffer(va_list args); + int dispatchGetLastQueuedBuffer2(va_list args); int dispatchSetFrameTimelineInfo(va_list args); int dispatchGetExtraBufferCount(va_list args); bool transformToDisplayInverse(); diff --git a/libs/nativewindow/include/system/window.h b/libs/nativewindow/include/system/window.h index cc82bb4699..935eded983 100644 --- a/libs/nativewindow/include/system/window.h +++ b/libs/nativewindow/include/system/window.h @@ -257,6 +257,7 @@ enum { NATIVE_WINDOW_SET_QUERY_INTERCEPTOR = 47, /* private */ NATIVE_WINDOW_SET_FRAME_TIMELINE_INFO = 48, /* private */ NATIVE_WINDOW_GET_EXTRA_BUFFER_COUNT = 49, /* private */ + NATIVE_WINDOW_GET_LAST_QUEUED_BUFFER2 = 50, /* private */ // clang-format on }; @@ -1067,6 +1068,31 @@ static inline int ANativeWindow_getLastQueuedBuffer(ANativeWindow* window, } /** + * Retrieves the last queued buffer for this window, along with the fence that + * fires when the buffer is ready to be read. The cropRect & transform should be applied to the + * buffer's content. + * + * If there was no buffer previously queued, then outBuffer will be NULL and + * the value of outFence will be -1. + * + * Note that if outBuffer is not NULL, then the caller will hold a reference + * onto the buffer. Accordingly, the caller must call AHardwareBuffer_release + * when the buffer is no longer needed so that the system may reclaim the + * buffer. + * + * \return NO_ERROR on success. + * \return NO_MEMORY if there was insufficient memory. + * \return STATUS_UNKNOWN_TRANSACTION if this ANativeWindow doesn't support this method, callers + * should fall back to ANativeWindow_getLastQueuedBuffer instead. + */ +static inline int ANativeWindow_getLastQueuedBuffer2(ANativeWindow* window, + AHardwareBuffer** outBuffer, int* outFence, + ARect* outCropRect, uint32_t* outTransform) { + return window->perform(window, NATIVE_WINDOW_GET_LAST_QUEUED_BUFFER2, outBuffer, outFence, + outCropRect, outTransform); +} + +/** * Retrieves an identifier for the next frame to be queued by this window. * * \return the next frame id. |