From 5065a55291b67f584d7b0be3fa3cfc4e29a3cd1c Mon Sep 17 00:00:00 2001 From: Dan Stoza Date: Tue, 17 Mar 2015 16:23:42 -0700 Subject: libgui: Pass surface damage through BufferQueue This change adds support for passing surface damage all of the way down from the EGL interface through the consumer side of the BufferQueue. Depends on system/core change Ie645e6a52b37b5c1b3be19481e8348570d1aa62c Bug: 11239309 Change-Id: I4457ea826e9ade4ec187f973851d855b7b93a31b --- libs/gui/BufferItem.cpp | 8 +++++ libs/gui/BufferQueueProducer.cpp | 2 ++ libs/gui/IGraphicBufferProducer.cpp | 15 ++++++++-- libs/gui/Surface.cpp | 60 +++++++++++++++++++++++++++++++++++++ libs/ui/Rect.cpp | 2 ++ libs/ui/Region.cpp | 14 +++++++-- 6 files changed, 95 insertions(+), 6 deletions(-) (limited to 'libs') diff --git a/libs/gui/BufferItem.cpp b/libs/gui/BufferItem.cpp index 312fb3b0da..239da20a06 100644 --- a/libs/gui/BufferItem.cpp +++ b/libs/gui/BufferItem.cpp @@ -64,6 +64,8 @@ size_t BufferItem::getFlattenedSize() const { c += mFence->getFlattenedSize(); FlattenableUtils::align<4>(c); } + c += mSurfaceDamage.getFlattenedSize(); + FlattenableUtils::align<4>(c); return sizeof(int32_t) + c + getPodSize(); } @@ -105,6 +107,9 @@ status_t BufferItem::flatten( size -= FlattenableUtils::align<4>(buffer); flags |= 2; } + status_t err = mSurfaceDamage.flatten(buffer, size); + if (err) return err; + size -= FlattenableUtils::align<4>(buffer); // check we have enough space (in case flattening the fence/graphicbuffer lied to us) if (size < getPodSize()) { @@ -148,6 +153,9 @@ status_t BufferItem::unflatten( if (err) return err; size -= FlattenableUtils::align<4>(buffer); } + status_t err = mSurfaceDamage.unflatten(buffer, size); + if (err) return err; + size -= FlattenableUtils::align<4>(buffer); // check we have enough space if (size < getPodSize()) { diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp index 4c22ba3814..6452cddcf9 100644 --- a/libs/gui/BufferQueueProducer.cpp +++ b/libs/gui/BufferQueueProducer.cpp @@ -525,6 +525,7 @@ status_t BufferQueueProducer::queueBuffer(int slot, sp fence; input.deflate(×tamp, &isAutoTimestamp, &dataSpace, &crop, &scalingMode, &transform, &async, &fence, &stickyTransform); + Region surfaceDamage = input.getSurfaceDamage(); if (fence == NULL) { BQ_LOGE("queueBuffer: fence is NULL"); @@ -621,6 +622,7 @@ status_t BufferQueueProducer::queueBuffer(int slot, item.mSlot = slot; item.mFence = fence; item.mIsDroppable = mCore->mDequeueBufferCannotBlock || async; + item.mSurfaceDamage = surfaceDamage; mStickyTransform = stickyTransform; diff --git a/libs/gui/IGraphicBufferProducer.cpp b/libs/gui/IGraphicBufferProducer.cpp index a3e6fb2a25..b7982a9f59 100644 --- a/libs/gui/IGraphicBufferProducer.cpp +++ b/libs/gui/IGraphicBufferProducer.cpp @@ -446,7 +446,8 @@ size_t IGraphicBufferProducer::QueueBufferInput::getFlattenedSize() const { + sizeof(transform) + sizeof(stickyTransform) + sizeof(async) - + fence->getFlattenedSize(); + + fence->getFlattenedSize() + + surfaceDamage.getFlattenedSize(); } size_t IGraphicBufferProducer::QueueBufferInput::getFdCount() const { @@ -467,7 +468,11 @@ status_t IGraphicBufferProducer::QueueBufferInput::flatten( FlattenableUtils::write(buffer, size, transform); FlattenableUtils::write(buffer, size, stickyTransform); FlattenableUtils::write(buffer, size, async); - return fence->flatten(buffer, size, fds, count); + status_t result = fence->flatten(buffer, size, fds, count); + if (result != NO_ERROR) { + return result; + } + return surfaceDamage.flatten(buffer, size); } status_t IGraphicBufferProducer::QueueBufferInput::unflatten( @@ -497,7 +502,11 @@ status_t IGraphicBufferProducer::QueueBufferInput::unflatten( FlattenableUtils::read(buffer, size, async); fence = new Fence(); - return fence->unflatten(buffer, size, fds, count); + status_t result = fence->unflatten(buffer, size, fds, count); + if (result != NO_ERROR) { + return result; + } + return surfaceDamage.unflatten(buffer, size); } }; // namespace android diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp index b80890fc51..245f7a3745 100644 --- a/libs/gui/Surface.cpp +++ b/libs/gui/Surface.cpp @@ -27,6 +27,7 @@ #include #include +#include #include #include @@ -320,6 +321,25 @@ int Surface::queueBuffer(android_native_buffer_t* buffer, int fenceFd) { IGraphicBufferProducer::QueueBufferInput input(timestamp, isAutoTimestamp, mDataSpace, crop, mScalingMode, mTransform ^ mStickyTransform, mSwapIntervalZero, fence, mStickyTransform); + + if (mDirtyRegion.bounds() == Rect::INVALID_RECT) { + input.setSurfaceDamage(Region::INVALID_REGION); + } else { + // The surface damage was specified using the OpenGL ES convention of + // the origin being in the bottom-left corner. Here we flip to the + // convention that the rest of the system uses (top-left corner) by + // subtracting all top/bottom coordinates from the buffer height. + Region flippedRegion; + for (auto rect : mDirtyRegion) { + auto top = buffer->height - rect.bottom; + auto bottom = buffer->height - rect.top; + Rect flippedRect{rect.left, top, rect.right, bottom}; + flippedRegion.orSelf(flippedRect); + } + + input.setSurfaceDamage(flippedRegion); + } + status_t err = mGraphicBufferProducer->queueBuffer(i, input, &output); if (err != OK) { ALOGE("queueBuffer: error queuing buffer to SurfaceTexture, %d", err); @@ -336,6 +356,9 @@ int Surface::queueBuffer(android_native_buffer_t* buffer, int fenceFd) { mConsumerRunningBehind = (numPendingBuffers >= 2); + // Clear surface damage back to full-buffer + mDirtyRegion = Region::INVALID_REGION; + return err; } @@ -453,6 +476,9 @@ int Surface::perform(int operation, va_list args) case NATIVE_WINDOW_SET_BUFFERS_DATASPACE: res = dispatchSetBuffersDataSpace(args); break; + case NATIVE_WINDOW_SET_SURFACE_DAMAGE: + res = dispatchSetSurfaceDamage(args); + break; default: res = NAME_NOT_FOUND; break; @@ -556,6 +582,13 @@ int Surface::dispatchSetBuffersDataSpace(va_list args) { return setBuffersDataSpace(dataspace); } +int Surface::dispatchSetSurfaceDamage(va_list args) { + android_native_rect_t* rects = va_arg(args, android_native_rect_t*); + size_t numRects = va_arg(args, size_t); + setSurfaceDamage(rects, numRects); + return NO_ERROR; +} + int Surface::connect(int api) { static sp listener = new DummyProducerListener(); return connect(api, listener); @@ -582,7 +615,13 @@ int Surface::connect(int api, const sp& listener) { } if (!err && api == NATIVE_WINDOW_API_CPU) { mConnectedToCpu = true; + // Clear the dirty region in case we're switching from a non-CPU API + mDirtyRegion.clear(); + } else if (!err) { + // Initialize the dirty region for tracking surface damage + mDirtyRegion = Region::INVALID_REGION; } + return err; } @@ -800,6 +839,27 @@ void Surface::freeAllBuffers() { } } +void Surface::setSurfaceDamage(android_native_rect_t* rects, size_t numRects) { + ATRACE_CALL(); + ALOGV("Surface::setSurfaceDamage"); + Mutex::Autolock lock(mMutex); + + if (numRects == 0) { + mDirtyRegion = Region::INVALID_REGION; + return; + } + + mDirtyRegion.clear(); + for (size_t r = 0; r < numRects; ++r) { + // We intentionally flip top and bottom here, since because they're + // specified with a bottom-left origin, top > bottom, which fails + // validation in the Region class. We will fix this up when we flip to a + // top-left origin in queueBuffer. + Rect rect(rects[r].left, rects[r].bottom, rects[r].right, rects[r].top); + mDirtyRegion.orSelf(rect); + } +} + // ---------------------------------------------------------------------- // the lock/unlock APIs must be used from the same thread diff --git a/libs/ui/Rect.cpp b/libs/ui/Rect.cpp index b480f3a62b..dcce21f15a 100644 --- a/libs/ui/Rect.cpp +++ b/libs/ui/Rect.cpp @@ -19,6 +19,8 @@ namespace android { +const Rect Rect::INVALID_RECT{0, 0, -1, -1}; + static inline int32_t min(int32_t a, int32_t b) { return (a < b) ? a : b; } diff --git a/libs/ui/Region.cpp b/libs/ui/Region.cpp index 62ec35cfc6..3810da4049 100644 --- a/libs/ui/Region.cpp +++ b/libs/ui/Region.cpp @@ -53,6 +53,8 @@ enum { direction_RTL }; +const Region Region::INVALID_REGION(Rect::INVALID_RECT); + // ---------------------------------------------------------------------------- Region::Region() { @@ -517,8 +519,12 @@ bool Region::validate(const Region& reg, const char* name, bool silent) Rect b(*prev); while (cur != tail) { if (cur->isValid() == false) { - ALOGE_IF(!silent, "%s: region contains an invalid Rect", name); - result = false; + // We allow this particular flavor of invalid Rect, since it is used + // as a signal value in various parts of the system + if (*cur != Rect::INVALID_RECT) { + ALOGE_IF(!silent, "%s: region contains an invalid Rect", name); + result = false; + } } if (cur->right > region_operator::max_value) { ALOGE_IF(!silent, "%s: rect->right > max_value", name); @@ -690,7 +696,9 @@ void Region::boolean_operation(int op, Region& dst, const Region& lhs, const Rect& rhs, int dx, int dy) { - if (!rhs.isValid()) { + // We allow this particular flavor of invalid Rect, since it is used as a + // signal value in various parts of the system + if (!rhs.isValid() && rhs != Rect::INVALID_RECT) { ALOGE("Region::boolean_operation(op=%d) invalid Rect={%d,%d,%d,%d}", op, rhs.left, rhs.top, rhs.right, rhs.bottom); return; -- cgit v1.2.3-59-g8ed1b