summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/gui/BufferItem.h5
-rw-r--r--include/gui/IGraphicBufferProducer.h7
-rw-r--r--include/gui/Surface.h9
-rw-r--r--include/ui/Rect.h2
-rw-r--r--include/ui/Region.h2
-rw-r--r--libs/gui/BufferItem.cpp8
-rw-r--r--libs/gui/BufferQueueProducer.cpp2
-rw-r--r--libs/gui/IGraphicBufferProducer.cpp15
-rw-r--r--libs/gui/Surface.cpp60
-rw-r--r--libs/ui/Rect.cpp2
-rw-r--r--libs/ui/Region.cpp14
11 files changed, 118 insertions, 8 deletions
diff --git a/include/gui/BufferItem.h b/include/gui/BufferItem.h
index cc41bae..000ef0e 100644
--- a/include/gui/BufferItem.h
+++ b/include/gui/BufferItem.h
@@ -21,6 +21,7 @@
#include <EGL/eglext.h>
#include <ui/Rect.h>
+#include <ui/Region.h>
#include <system/graphics.h>
@@ -106,6 +107,10 @@ class BufferItem : public Flattenable<BufferItem> {
// Indicates this buffer must be transformed by the inverse transform of the screen
// it is displayed onto. This is applied after mTransform.
bool mTransformToDisplayInverse;
+
+ // Describes the portion of the surface that has been modified since the
+ // previous frame
+ Region mSurfaceDamage;
};
} // namespace android
diff --git a/include/gui/IGraphicBufferProducer.h b/include/gui/IGraphicBufferProducer.h
index 374245a..2d99f24 100644
--- a/include/gui/IGraphicBufferProducer.h
+++ b/include/gui/IGraphicBufferProducer.h
@@ -28,6 +28,7 @@
#include <ui/Fence.h>
#include <ui/GraphicBuffer.h>
#include <ui/Rect.h>
+#include <ui/Region.h>
namespace android {
// ----------------------------------------------------------------------------
@@ -281,7 +282,7 @@ public:
: timestamp(timestamp), isAutoTimestamp(isAutoTimestamp),
dataSpace(dataSpace), crop(crop), scalingMode(scalingMode),
transform(transform), stickyTransform(sticky),
- async(async), fence(fence) { }
+ async(async), fence(fence), surfaceDamage() { }
inline void deflate(int64_t* outTimestamp, bool* outIsAutoTimestamp,
android_dataspace* outDataSpace,
Rect* outCrop, int* outScalingMode,
@@ -306,6 +307,9 @@ public:
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);
+ const Region& getSurfaceDamage() const { return surfaceDamage; }
+ void setSurfaceDamage(const Region& damage) { surfaceDamage = damage; }
+
private:
int64_t timestamp;
int isAutoTimestamp;
@@ -316,6 +320,7 @@ public:
uint32_t stickyTransform;
int async;
sp<Fence> fence;
+ Region surfaceDamage;
};
// QueueBufferOutput must be a POD structure
diff --git a/include/gui/Surface.h b/include/gui/Surface.h
index e973483..8217652 100644
--- a/include/gui/Surface.h
+++ b/include/gui/Surface.h
@@ -147,6 +147,7 @@ private:
int dispatchUnlockAndPost(va_list args);
int dispatchSetSidebandStream(va_list args);
int dispatchSetBuffersDataSpace(va_list args);
+ int dispatchSetSurfaceDamage(va_list args);
protected:
virtual int dequeueBuffer(ANativeWindowBuffer** buffer, int* fenceFd);
@@ -171,6 +172,7 @@ protected:
virtual int setBuffersDataSpace(android_dataspace dataSpace);
virtual int setCrop(Rect const* rect);
virtual int setUsage(uint32_t reqUsage);
+ virtual void setSurfaceDamage(android_native_rect_t* rects, size_t numRects);
public:
virtual int lock(ANativeWindow_Buffer* outBuffer, ARect* inOutDirtyBounds);
@@ -296,7 +298,12 @@ private:
sp<GraphicBuffer> mPostedBuffer;
bool mConnectedToCpu;
- // must be accessed from lock/unlock thread only
+ // In the lock/unlock context, this reflects the region that the producer
+ // wished to update and whether the Surface was able to copy the previous
+ // buffer back to allow a partial update.
+ //
+ // In the dequeue/queue context, this reflects the surface damage (the
+ // damage since the last frame) passed in by the producer.
Region mDirtyRegion;
};
diff --git a/include/ui/Rect.h b/include/ui/Rect.h
index 40d1166..3886f93 100644
--- a/include/ui/Rect.h
+++ b/include/ui/Rect.h
@@ -31,6 +31,8 @@ class Rect : public ARect, public LightFlattenablePod<Rect>
public:
typedef ARect::value_type value_type;
+ static const Rect INVALID_RECT;
+
// we don't provide copy-ctor and operator= on purpose
// because we want the compiler generated versions
diff --git a/include/ui/Region.h b/include/ui/Region.h
index 49740f7..2a14918 100644
--- a/include/ui/Region.h
+++ b/include/ui/Region.h
@@ -35,6 +35,8 @@ class String8;
class Region : public LightFlattenable<Region>
{
public:
+ static const Region INVALID_REGION;
+
Region();
Region(const Region& rhs);
explicit Region(const Rect& rhs);
diff --git a/libs/gui/BufferItem.cpp b/libs/gui/BufferItem.cpp
index 312fb3b..239da20 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 4c22ba3..6452cdd 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -525,6 +525,7 @@ status_t BufferQueueProducer::queueBuffer(int slot,
sp<Fence> fence;
input.deflate(&timestamp, &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 a3e6fb2..b7982a9 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 b80890f..245f7a3 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -27,6 +27,7 @@
#include <utils/NativeHandle.h>
#include <ui/Fence.h>
+#include <ui/Region.h>
#include <gui/IProducerListener.h>
#include <gui/ISurfaceComposer.h>
@@ -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<IProducerListener> listener = new DummyProducerListener();
return connect(api, listener);
@@ -582,7 +615,13 @@ int Surface::connect(int api, const sp<IProducerListener>& 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 b480f3a..dcce21f 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 62ec35c..3810da4 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<Rect>::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;