Merge "libgui: Pass surface damage through BufferQueue"
This commit is contained in:
commit
fd5f41bee9
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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()) {
|
||||
|
@ -525,6 +525,7 @@ status_t BufferQueueProducer::queueBuffer(int slot,
|
||||
sp<Fence> 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;
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -53,6 +53,8 @@ enum {
|
||||
direction_RTL
|
||||
};
|
||||
|
||||
const Region Region::INVALID_REGION(Rect::INVALID_RECT);
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
Region::Region() {
|
||||
@ -517,9 +519,13 @@ bool Region::validate(const Region& reg, const char* name, bool silent)
|
||||
Rect b(*prev);
|
||||
while (cur != tail) {
|
||||
if (cur->isValid() == 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);
|
||||
result = false;
|
||||
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user