Merge "libgui: Pass surface damage through BufferQueue"

This commit is contained in:
Dan Stoza 2015-04-15 20:26:55 +00:00 committed by Gerrit Code Review
commit fd5f41bee9
11 changed files with 118 additions and 8 deletions

View File

@ -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

View File

@ -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

View File

@ -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;
};

View File

@ -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

View File

@ -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);

View File

@ -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()) {

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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;
}

View File

@ -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;