am 057a561a: am 57a9f5a0: am fd5f41be: Merge "libgui: Pass surface damage through BufferQueue"

* commit '057a561afbf30ede99b5ec627deec7ee11701f6d':
  libgui: Pass surface damage through BufferQueue
This commit is contained in:
Dan Stoza 2015-04-15 21:42:43 +00:00 committed by Android Git Automerger
commit 2992fcd0b2
11 changed files with 118 additions and 8 deletions

View File

@ -21,6 +21,7 @@
#include <EGL/eglext.h> #include <EGL/eglext.h>
#include <ui/Rect.h> #include <ui/Rect.h>
#include <ui/Region.h>
#include <system/graphics.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 // Indicates this buffer must be transformed by the inverse transform of the screen
// it is displayed onto. This is applied after mTransform. // it is displayed onto. This is applied after mTransform.
bool mTransformToDisplayInverse; bool mTransformToDisplayInverse;
// Describes the portion of the surface that has been modified since the
// previous frame
Region mSurfaceDamage;
}; };
} // namespace android } // namespace android

View File

@ -28,6 +28,7 @@
#include <ui/Fence.h> #include <ui/Fence.h>
#include <ui/GraphicBuffer.h> #include <ui/GraphicBuffer.h>
#include <ui/Rect.h> #include <ui/Rect.h>
#include <ui/Region.h>
namespace android { namespace android {
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@ -281,7 +282,7 @@ public:
: timestamp(timestamp), isAutoTimestamp(isAutoTimestamp), : timestamp(timestamp), isAutoTimestamp(isAutoTimestamp),
dataSpace(dataSpace), crop(crop), scalingMode(scalingMode), dataSpace(dataSpace), crop(crop), scalingMode(scalingMode),
transform(transform), stickyTransform(sticky), transform(transform), stickyTransform(sticky),
async(async), fence(fence) { } async(async), fence(fence), surfaceDamage() { }
inline void deflate(int64_t* outTimestamp, bool* outIsAutoTimestamp, inline void deflate(int64_t* outTimestamp, bool* outIsAutoTimestamp,
android_dataspace* outDataSpace, android_dataspace* outDataSpace,
Rect* outCrop, int* outScalingMode, 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 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); 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: private:
int64_t timestamp; int64_t timestamp;
int isAutoTimestamp; int isAutoTimestamp;
@ -316,6 +320,7 @@ public:
uint32_t stickyTransform; uint32_t stickyTransform;
int async; int async;
sp<Fence> fence; sp<Fence> fence;
Region surfaceDamage;
}; };
// QueueBufferOutput must be a POD structure // QueueBufferOutput must be a POD structure

View File

@ -147,6 +147,7 @@ private:
int dispatchUnlockAndPost(va_list args); int dispatchUnlockAndPost(va_list args);
int dispatchSetSidebandStream(va_list args); int dispatchSetSidebandStream(va_list args);
int dispatchSetBuffersDataSpace(va_list args); int dispatchSetBuffersDataSpace(va_list args);
int dispatchSetSurfaceDamage(va_list args);
protected: protected:
virtual int dequeueBuffer(ANativeWindowBuffer** buffer, int* fenceFd); virtual int dequeueBuffer(ANativeWindowBuffer** buffer, int* fenceFd);
@ -171,6 +172,7 @@ protected:
virtual int setBuffersDataSpace(android_dataspace dataSpace); virtual int setBuffersDataSpace(android_dataspace dataSpace);
virtual int setCrop(Rect const* rect); virtual int setCrop(Rect const* rect);
virtual int setUsage(uint32_t reqUsage); virtual int setUsage(uint32_t reqUsage);
virtual void setSurfaceDamage(android_native_rect_t* rects, size_t numRects);
public: public:
virtual int lock(ANativeWindow_Buffer* outBuffer, ARect* inOutDirtyBounds); virtual int lock(ANativeWindow_Buffer* outBuffer, ARect* inOutDirtyBounds);
@ -296,7 +298,12 @@ private:
sp<GraphicBuffer> mPostedBuffer; sp<GraphicBuffer> mPostedBuffer;
bool mConnectedToCpu; 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; Region mDirtyRegion;
}; };

View File

@ -31,6 +31,8 @@ class Rect : public ARect, public LightFlattenablePod<Rect>
public: public:
typedef ARect::value_type value_type; typedef ARect::value_type value_type;
static const Rect INVALID_RECT;
// we don't provide copy-ctor and operator= on purpose // we don't provide copy-ctor and operator= on purpose
// because we want the compiler generated versions // because we want the compiler generated versions

View File

@ -35,6 +35,8 @@ class String8;
class Region : public LightFlattenable<Region> class Region : public LightFlattenable<Region>
{ {
public: public:
static const Region INVALID_REGION;
Region(); Region();
Region(const Region& rhs); Region(const Region& rhs);
explicit Region(const Rect& rhs); explicit Region(const Rect& rhs);

View File

@ -64,6 +64,8 @@ size_t BufferItem::getFlattenedSize() const {
c += mFence->getFlattenedSize(); c += mFence->getFlattenedSize();
FlattenableUtils::align<4>(c); FlattenableUtils::align<4>(c);
} }
c += mSurfaceDamage.getFlattenedSize();
FlattenableUtils::align<4>(c);
return sizeof(int32_t) + c + getPodSize(); return sizeof(int32_t) + c + getPodSize();
} }
@ -105,6 +107,9 @@ status_t BufferItem::flatten(
size -= FlattenableUtils::align<4>(buffer); size -= FlattenableUtils::align<4>(buffer);
flags |= 2; 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) // check we have enough space (in case flattening the fence/graphicbuffer lied to us)
if (size < getPodSize()) { if (size < getPodSize()) {
@ -148,6 +153,9 @@ status_t BufferItem::unflatten(
if (err) return err; if (err) return err;
size -= FlattenableUtils::align<4>(buffer); 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 // check we have enough space
if (size < getPodSize()) { if (size < getPodSize()) {

View File

@ -525,6 +525,7 @@ status_t BufferQueueProducer::queueBuffer(int slot,
sp<Fence> fence; sp<Fence> fence;
input.deflate(&timestamp, &isAutoTimestamp, &dataSpace, &crop, &scalingMode, input.deflate(&timestamp, &isAutoTimestamp, &dataSpace, &crop, &scalingMode,
&transform, &async, &fence, &stickyTransform); &transform, &async, &fence, &stickyTransform);
Region surfaceDamage = input.getSurfaceDamage();
if (fence == NULL) { if (fence == NULL) {
BQ_LOGE("queueBuffer: fence is NULL"); BQ_LOGE("queueBuffer: fence is NULL");
@ -621,6 +622,7 @@ status_t BufferQueueProducer::queueBuffer(int slot,
item.mSlot = slot; item.mSlot = slot;
item.mFence = fence; item.mFence = fence;
item.mIsDroppable = mCore->mDequeueBufferCannotBlock || async; item.mIsDroppable = mCore->mDequeueBufferCannotBlock || async;
item.mSurfaceDamage = surfaceDamage;
mStickyTransform = stickyTransform; mStickyTransform = stickyTransform;

View File

@ -446,7 +446,8 @@ size_t IGraphicBufferProducer::QueueBufferInput::getFlattenedSize() const {
+ sizeof(transform) + sizeof(transform)
+ sizeof(stickyTransform) + sizeof(stickyTransform)
+ sizeof(async) + sizeof(async)
+ fence->getFlattenedSize(); + fence->getFlattenedSize()
+ surfaceDamage.getFlattenedSize();
} }
size_t IGraphicBufferProducer::QueueBufferInput::getFdCount() const { size_t IGraphicBufferProducer::QueueBufferInput::getFdCount() const {
@ -467,7 +468,11 @@ status_t IGraphicBufferProducer::QueueBufferInput::flatten(
FlattenableUtils::write(buffer, size, transform); FlattenableUtils::write(buffer, size, transform);
FlattenableUtils::write(buffer, size, stickyTransform); FlattenableUtils::write(buffer, size, stickyTransform);
FlattenableUtils::write(buffer, size, async); 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( status_t IGraphicBufferProducer::QueueBufferInput::unflatten(
@ -497,7 +502,11 @@ status_t IGraphicBufferProducer::QueueBufferInput::unflatten(
FlattenableUtils::read(buffer, size, async); FlattenableUtils::read(buffer, size, async);
fence = new Fence(); 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 }; // namespace android

View File

@ -27,6 +27,7 @@
#include <utils/NativeHandle.h> #include <utils/NativeHandle.h>
#include <ui/Fence.h> #include <ui/Fence.h>
#include <ui/Region.h>
#include <gui/IProducerListener.h> #include <gui/IProducerListener.h>
#include <gui/ISurfaceComposer.h> #include <gui/ISurfaceComposer.h>
@ -320,6 +321,25 @@ int Surface::queueBuffer(android_native_buffer_t* buffer, int fenceFd) {
IGraphicBufferProducer::QueueBufferInput input(timestamp, isAutoTimestamp, IGraphicBufferProducer::QueueBufferInput input(timestamp, isAutoTimestamp,
mDataSpace, crop, mScalingMode, mTransform ^ mStickyTransform, mDataSpace, crop, mScalingMode, mTransform ^ mStickyTransform,
mSwapIntervalZero, fence, 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); status_t err = mGraphicBufferProducer->queueBuffer(i, input, &output);
if (err != OK) { if (err != OK) {
ALOGE("queueBuffer: error queuing buffer to SurfaceTexture, %d", err); 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); mConsumerRunningBehind = (numPendingBuffers >= 2);
// Clear surface damage back to full-buffer
mDirtyRegion = Region::INVALID_REGION;
return err; return err;
} }
@ -453,6 +476,9 @@ int Surface::perform(int operation, va_list args)
case NATIVE_WINDOW_SET_BUFFERS_DATASPACE: case NATIVE_WINDOW_SET_BUFFERS_DATASPACE:
res = dispatchSetBuffersDataSpace(args); res = dispatchSetBuffersDataSpace(args);
break; break;
case NATIVE_WINDOW_SET_SURFACE_DAMAGE:
res = dispatchSetSurfaceDamage(args);
break;
default: default:
res = NAME_NOT_FOUND; res = NAME_NOT_FOUND;
break; break;
@ -556,6 +582,13 @@ int Surface::dispatchSetBuffersDataSpace(va_list args) {
return setBuffersDataSpace(dataspace); 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) { int Surface::connect(int api) {
static sp<IProducerListener> listener = new DummyProducerListener(); static sp<IProducerListener> listener = new DummyProducerListener();
return connect(api, listener); return connect(api, listener);
@ -582,7 +615,13 @@ int Surface::connect(int api, const sp<IProducerListener>& listener) {
} }
if (!err && api == NATIVE_WINDOW_API_CPU) { if (!err && api == NATIVE_WINDOW_API_CPU) {
mConnectedToCpu = true; 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; 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 // the lock/unlock APIs must be used from the same thread

View File

@ -19,6 +19,8 @@
namespace android { namespace android {
const Rect Rect::INVALID_RECT{0, 0, -1, -1};
static inline int32_t min(int32_t a, int32_t b) { static inline int32_t min(int32_t a, int32_t b) {
return (a < b) ? a : b; return (a < b) ? a : b;
} }

View File

@ -53,6 +53,8 @@ enum {
direction_RTL direction_RTL
}; };
const Region Region::INVALID_REGION(Rect::INVALID_RECT);
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
Region::Region() { Region::Region() {
@ -517,8 +519,12 @@ bool Region::validate(const Region& reg, const char* name, bool silent)
Rect b(*prev); Rect b(*prev);
while (cur != tail) { while (cur != tail) {
if (cur->isValid() == false) { if (cur->isValid() == false) {
ALOGE_IF(!silent, "%s: region contains an invalid Rect", name); // We allow this particular flavor of invalid Rect, since it is used
result = false; // 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) { if (cur->right > region_operator<Rect>::max_value) {
ALOGE_IF(!silent, "%s: rect->right > max_value", name); 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 Region& lhs,
const Rect& rhs, int dx, int dy) 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}", ALOGE("Region::boolean_operation(op=%d) invalid Rect={%d,%d,%d,%d}",
op, rhs.left, rhs.top, rhs.right, rhs.bottom); op, rhs.left, rhs.top, rhs.right, rhs.bottom);
return; return;