Merge "Check orientation range has been initialized first"
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 @@
// 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/BufferQueueCore.h b/include/gui/BufferQueueCore.h
index 40026bd..9a43516 100644
--- a/include/gui/BufferQueueCore.h
+++ b/include/gui/BufferQueueCore.h
@@ -30,6 +30,9 @@
#include <utils/Trace.h>
#include <utils/Vector.h>
+#include <list>
+#include <set>
+
#define BQ_LOGV(x, ...) ALOGV("[%s] " x, mConsumerName.string(), ##__VA_ARGS__)
#define BQ_LOGD(x, ...) ALOGD("[%s] " x, mConsumerName.string(), ##__VA_ARGS__)
#define BQ_LOGI(x, ...) ALOGI("[%s] " x, mConsumerName.string(), ##__VA_ARGS__)
@@ -123,6 +126,10 @@
// waitWhileAllocatingLocked blocks until mIsAllocating is false.
void waitWhileAllocatingLocked() const;
+ // validateConsistencyLocked ensures that the free lists are in sync with
+ // the information stored in mSlots
+ void validateConsistencyLocked() const;
+
// mAllocator is the connection to SurfaceFlinger that is used to allocate
// new GraphicBuffer objects.
sp<IGraphicBufferAlloc> mAllocator;
@@ -177,6 +184,14 @@
// mQueue is a FIFO of queued buffers used in synchronous mode.
Fifo mQueue;
+ // mFreeSlots contains all of the slots which are FREE and do not currently
+ // have a buffer attached
+ std::set<int> mFreeSlots;
+
+ // mFreeBuffers contains all of the slots which are FREE and currently have
+ // a buffer attached
+ std::list<int> mFreeBuffers;
+
// mOverrideMaxBufferCount is the limit on the number of buffers that will
// be allocated at one time. This value is set by the producer by calling
// setBufferCount. The default is 0, which means that the producer doesn't
@@ -251,6 +266,10 @@
// mIsAllocatingCondition is a condition variable used by producers to wait until mIsAllocating
// becomes false.
mutable Condition mIsAllocatingCondition;
+
+ // mAllowAllocation determines whether dequeueBuffer is allowed to allocate
+ // new buffers
+ bool mAllowAllocation;
}; // class BufferQueueCore
} // namespace android
diff --git a/include/gui/BufferQueueProducer.h b/include/gui/BufferQueueProducer.h
index f794ea3..ed660fb 100644
--- a/include/gui/BufferQueueProducer.h
+++ b/include/gui/BufferQueueProducer.h
@@ -172,6 +172,9 @@
virtual void allocateBuffers(bool async, uint32_t width, uint32_t height,
PixelFormat format, uint32_t usage);
+ // See IGraphicBufferProducer::allowAllocation
+ virtual status_t allowAllocation(bool allow);
+
private:
// This is required by the IBinder::DeathRecipient interface
virtual void binderDied(const wp<IBinder>& who);
diff --git a/include/gui/IGraphicBufferProducer.h b/include/gui/IGraphicBufferProducer.h
index 374245a..5c50b2b 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 @@
: 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 @@
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 @@
uint32_t stickyTransform;
int async;
sp<Fence> fence;
+ Region surfaceDamage;
};
// QueueBufferOutput must be a POD structure
@@ -453,6 +458,18 @@
// allocated, this function has no effect.
virtual void allocateBuffers(bool async, uint32_t width, uint32_t height,
PixelFormat format, uint32_t usage) = 0;
+
+ // Sets whether dequeueBuffer is allowed to allocate new buffers.
+ //
+ // Normally dequeueBuffer does not discriminate between free slots which
+ // already have an allocated buffer and those which do not, and will
+ // allocate a new buffer if the slot doesn't have a buffer or if the slot's
+ // buffer doesn't match the requested size, format, or usage. This method
+ // allows the producer to restrict the eligible slots to those which already
+ // have an allocated buffer of the correct size, format, and usage. If no
+ // eligible slot is available, dequeueBuffer will block or return an error
+ // as usual.
+ virtual status_t allowAllocation(bool allow) = 0;
};
// ----------------------------------------------------------------------------
diff --git a/include/gui/Surface.h b/include/gui/Surface.h
index e973483..a9f78cf 100644
--- a/include/gui/Surface.h
+++ b/include/gui/Surface.h
@@ -147,6 +147,7 @@
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 @@
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 @@
sp<GraphicBuffer> mPostedBuffer;
bool mConnectedToCpu;
- // must be accessed from lock/unlock thread only
+ // When a CPU producer is attached, this reflects the region that the
+ // producer wished to update as well as whether the Surface was able to copy
+ // the previous buffer back to allow a partial update.
+ //
+ // When a non-CPU producer is attached, this reflects the surface damage
+ // (the change since the previous frame) passed in by the producer.
Region mDirtyRegion;
};
diff --git a/include/ui/GraphicBuffer.h b/include/ui/GraphicBuffer.h
index cea94fc..f91d192 100644
--- a/include/ui/GraphicBuffer.h
+++ b/include/ui/GraphicBuffer.h
@@ -97,6 +97,9 @@
status_t reallocate(uint32_t inWidth, uint32_t inHeight,
PixelFormat inFormat, uint32_t inUsage);
+ bool needsReallocation(uint32_t inWidth, uint32_t inHeight,
+ PixelFormat inFormat, uint32_t inUsage);
+
status_t lock(uint32_t inUsage, void** vaddr);
status_t lock(uint32_t inUsage, const Rect& rect, void** vaddr);
// For HAL_PIXEL_FORMAT_YCbCr_420_888
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 @@
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 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..5793d40 100644
--- a/libs/gui/BufferItem.cpp
+++ b/libs/gui/BufferItem.cpp
@@ -39,50 +39,66 @@
BufferItem::~BufferItem() {}
+template <typename T>
+static void addAligned(size_t& size, T /* value */) {
+ size = FlattenableUtils::align<sizeof(T)>(size);
+ size += sizeof(T);
+}
+
size_t BufferItem::getPodSize() const {
- size_t c = sizeof(mCrop) +
- sizeof(mTransform) +
- sizeof(mScalingMode) +
- sizeof(mTimestamp) +
- sizeof(mIsAutoTimestamp) +
- sizeof(mDataSpace) +
- sizeof(mFrameNumber) +
- sizeof(mSlot) +
- sizeof(mIsDroppable) +
- sizeof(mAcquireCalled) +
- sizeof(mTransformToDisplayInverse);
- return c;
+ // Must align<8> before writing these fields for this to be correct
+ size_t size = 0;
+ addAligned(size, mCrop);
+ addAligned(size, mTransform);
+ addAligned(size, mScalingMode);
+ addAligned(size, mTimestamp);
+ addAligned(size, mIsAutoTimestamp);
+ addAligned(size, mDataSpace);
+ addAligned(size, mFrameNumber);
+ addAligned(size, mSlot);
+ addAligned(size, mIsDroppable);
+ addAligned(size, mAcquireCalled);
+ addAligned(size, mTransformToDisplayInverse);
+ return size;
}
size_t BufferItem::getFlattenedSize() const {
- size_t c = 0;
+ size_t size = sizeof(uint32_t); // Flags
if (mGraphicBuffer != 0) {
- c += mGraphicBuffer->getFlattenedSize();
- FlattenableUtils::align<4>(c);
+ size += mGraphicBuffer->getFlattenedSize();
+ FlattenableUtils::align<4>(size);
}
if (mFence != 0) {
- c += mFence->getFlattenedSize();
- FlattenableUtils::align<4>(c);
+ size += mFence->getFlattenedSize();
+ FlattenableUtils::align<4>(size);
}
- return sizeof(int32_t) + c + getPodSize();
+ size += mSurfaceDamage.getFlattenedSize();
+ size = FlattenableUtils::align<8>(size);
+ return size + getPodSize();
}
size_t BufferItem::getFdCount() const {
- size_t c = 0;
+ size_t count = 0;
if (mGraphicBuffer != 0) {
- c += mGraphicBuffer->getFdCount();
+ count += mGraphicBuffer->getFdCount();
}
if (mFence != 0) {
- c += mFence->getFdCount();
+ count += mFence->getFdCount();
}
- return c;
+ return count;
+}
+
+template <typename T>
+static void writeAligned(void*& buffer, size_t& size, T value) {
+ size -= FlattenableUtils::align<alignof(T)>(buffer);
+ FlattenableUtils::write(buffer, size, value);
}
status_t BufferItem::flatten(
void*& buffer, size_t& size, int*& fds, size_t& count) const {
// make sure we have enough space
- if (count < BufferItem::getFlattenedSize()) {
+ if (size < BufferItem::getFlattenedSize()) {
return NO_MEMORY;
}
@@ -106,31 +122,45 @@
flags |= 2;
}
- // check we have enough space (in case flattening the fence/graphicbuffer lied to us)
+ status_t err = mSurfaceDamage.flatten(buffer, size);
+ if (err) return err;
+ FlattenableUtils::advance(buffer, size, mSurfaceDamage.getFlattenedSize());
+
+ // Must align<8> so that getPodSize returns the correct value
+ size -= FlattenableUtils::align<8>(buffer);
+
+ // Check we still have enough space
if (size < getPodSize()) {
return NO_MEMORY;
}
- FlattenableUtils::write(buffer, size, mCrop);
- FlattenableUtils::write(buffer, size, mTransform);
- FlattenableUtils::write(buffer, size, mScalingMode);
- FlattenableUtils::write(buffer, size, mTimestamp);
- FlattenableUtils::write(buffer, size, mIsAutoTimestamp);
- FlattenableUtils::write(buffer, size, mDataSpace);
- FlattenableUtils::write(buffer, size, mFrameNumber);
- FlattenableUtils::write(buffer, size, mSlot);
- FlattenableUtils::write(buffer, size, mIsDroppable);
- FlattenableUtils::write(buffer, size, mAcquireCalled);
- FlattenableUtils::write(buffer, size, mTransformToDisplayInverse);
+ writeAligned(buffer, size, mCrop);
+ writeAligned(buffer, size, mTransform);
+ writeAligned(buffer, size, mScalingMode);
+ writeAligned(buffer, size, mTimestamp);
+ writeAligned(buffer, size, mIsAutoTimestamp);
+ writeAligned(buffer, size, mDataSpace);
+ writeAligned(buffer, size, mFrameNumber);
+ writeAligned(buffer, size, mSlot);
+ writeAligned(buffer, size, mIsDroppable);
+ writeAligned(buffer, size, mAcquireCalled);
+ writeAligned(buffer, size, mTransformToDisplayInverse);
return NO_ERROR;
}
+template <typename T>
+static void readAligned(const void*& buffer, size_t& size, T& value) {
+ size -= FlattenableUtils::align<alignof(T)>(buffer);
+ FlattenableUtils::read(buffer, size, value);
+}
+
status_t BufferItem::unflatten(
void const*& buffer, size_t& size, int const*& fds, size_t& count) {
- if (size < sizeof(uint32_t))
+ if (size < sizeof(uint32_t)) {
return NO_MEMORY;
+ }
uint32_t flags = 0;
FlattenableUtils::read(buffer, size, flags);
@@ -149,22 +179,29 @@
size -= FlattenableUtils::align<4>(buffer);
}
- // check we have enough space
+ status_t err = mSurfaceDamage.unflatten(buffer, size);
+ if (err) return err;
+ FlattenableUtils::advance(buffer, size, mSurfaceDamage.getFlattenedSize());
+
+ // Must align<8> so that getPodSize returns the correct value
+ size -= FlattenableUtils::align<8>(buffer);
+
+ // Check we still have enough space
if (size < getPodSize()) {
return NO_MEMORY;
}
- FlattenableUtils::read(buffer, size, mCrop);
- FlattenableUtils::read(buffer, size, mTransform);
- FlattenableUtils::read(buffer, size, mScalingMode);
- FlattenableUtils::read(buffer, size, mTimestamp);
- FlattenableUtils::read(buffer, size, mIsAutoTimestamp);
- FlattenableUtils::read(buffer, size, mDataSpace);
- FlattenableUtils::read(buffer, size, mFrameNumber);
- FlattenableUtils::read(buffer, size, mSlot);
- FlattenableUtils::read(buffer, size, mIsDroppable);
- FlattenableUtils::read(buffer, size, mAcquireCalled);
- FlattenableUtils::read(buffer, size, mTransformToDisplayInverse);
+ readAligned(buffer, size, mCrop);
+ readAligned(buffer, size, mTransform);
+ readAligned(buffer, size, mScalingMode);
+ readAligned(buffer, size, mTimestamp);
+ readAligned(buffer, size, mIsAutoTimestamp);
+ readAligned(buffer, size, mDataSpace);
+ readAligned(buffer, size, mFrameNumber);
+ readAligned(buffer, size, mSlot);
+ readAligned(buffer, size, mIsDroppable);
+ readAligned(buffer, size, mAcquireCalled);
+ readAligned(buffer, size, mTransformToDisplayInverse);
return NO_ERROR;
}
diff --git a/libs/gui/BufferQueueConsumer.cpp b/libs/gui/BufferQueueConsumer.cpp
index 526c3b7..c7d5e00 100644
--- a/libs/gui/BufferQueueConsumer.cpp
+++ b/libs/gui/BufferQueueConsumer.cpp
@@ -120,6 +120,7 @@
if (mCore->stillTracking(front)) {
// Front buffer is still in mSlots, so mark the slot as free
mSlots[front->mSlot].mBufferState = BufferSlot::FREE;
+ mCore->mFreeBuffers.push_back(front->mSlot);
}
mCore->mQueue.erase(front);
front = mCore->mQueue.begin();
@@ -173,6 +174,8 @@
ATRACE_INT(mCore->mConsumerName.string(), mCore->mQueue.size());
+ mCore->validateConsistencyLocked();
+
return NO_ERROR;
}
@@ -199,6 +202,7 @@
mCore->freeBufferLocked(slot);
mCore->mDequeueCondition.broadcast();
+ mCore->validateConsistencyLocked();
return NO_ERROR;
}
@@ -217,18 +221,11 @@
Mutex::Autolock lock(mCore->mMutex);
- // Make sure we don't have too many acquired buffers and find a free slot
- // to put the buffer into (the oldest if there are multiple).
+ // Make sure we don't have too many acquired buffers
int numAcquiredBuffers = 0;
- int found = BufferQueueCore::INVALID_BUFFER_SLOT;
for (int s = 0; s < BufferQueueDefs::NUM_BUFFER_SLOTS; ++s) {
if (mSlots[s].mBufferState == BufferSlot::ACQUIRED) {
++numAcquiredBuffers;
- } else if (mSlots[s].mBufferState == BufferSlot::FREE) {
- if (found == BufferQueueCore::INVALID_BUFFER_SLOT ||
- mSlots[s].mFrameNumber < mSlots[found].mFrameNumber) {
- found = s;
- }
}
}
@@ -238,6 +235,17 @@
mCore->mMaxAcquiredBufferCount);
return INVALID_OPERATION;
}
+
+ // Find a free slot to put the buffer into
+ int found = BufferQueueCore::INVALID_BUFFER_SLOT;
+ if (!mCore->mFreeSlots.empty()) {
+ auto slot = mCore->mFreeSlots.begin();
+ found = *slot;
+ mCore->mFreeSlots.erase(slot);
+ } else if (!mCore->mFreeBuffers.empty()) {
+ found = mCore->mFreeBuffers.front();
+ mCore->mFreeBuffers.remove(found);
+ }
if (found == BufferQueueCore::INVALID_BUFFER_SLOT) {
BQ_LOGE("attachBuffer(P): could not find free buffer slot");
return NO_MEMORY;
@@ -271,6 +279,8 @@
// for attached buffers.
mSlots[*outSlot].mAcquireCalled = false;
+ mCore->validateConsistencyLocked();
+
return NO_ERROR;
}
@@ -311,6 +321,7 @@
mSlots[slot].mEglFence = eglFence;
mSlots[slot].mFence = releaseFence;
mSlots[slot].mBufferState = BufferSlot::FREE;
+ mCore->mFreeBuffers.push_back(slot);
listener = mCore->mConnectedProducerListener;
BQ_LOGV("releaseBuffer: releasing slot %d", slot);
} else if (mSlots[slot].mNeedsCleanupOnRelease) {
@@ -325,6 +336,7 @@
}
mCore->mDequeueCondition.broadcast();
+ mCore->validateConsistencyLocked();
} // Autolock scope
// Call back without lock held
diff --git a/libs/gui/BufferQueueCore.cpp b/libs/gui/BufferQueueCore.cpp
index edebc45..bc75ca7 100644
--- a/libs/gui/BufferQueueCore.cpp
+++ b/libs/gui/BufferQueueCore.cpp
@@ -53,6 +53,8 @@
mConnectedProducerListener(),
mSlots(),
mQueue(),
+ mFreeSlots(),
+ mFreeBuffers(),
mOverrideMaxBufferCount(0),
mDequeueCondition(),
mUseAsyncBuffer(true),
@@ -67,7 +69,8 @@
mFrameCounter(0),
mTransformHint(0),
mIsAllocating(false),
- mIsAllocatingCondition()
+ mIsAllocatingCondition(),
+ mAllowAllocation(true)
{
if (allocator == NULL) {
sp<ISurfaceComposer> composer(ComposerService::getComposerService());
@@ -76,6 +79,9 @@
BQ_LOGE("createGraphicBufferAlloc failed");
}
}
+ for (int slot = 0; slot < BufferQueueDefs::NUM_BUFFER_SLOTS; ++slot) {
+ mFreeSlots.insert(slot);
+ }
}
BufferQueueCore::~BufferQueueCore() {}
@@ -190,12 +196,20 @@
void BufferQueueCore::freeBufferLocked(int slot) {
BQ_LOGV("freeBufferLocked: slot %d", slot);
+ bool hadBuffer = mSlots[slot].mGraphicBuffer != NULL;
mSlots[slot].mGraphicBuffer.clear();
if (mSlots[slot].mBufferState == BufferSlot::ACQUIRED) {
mSlots[slot].mNeedsCleanupOnRelease = true;
}
+ if (mSlots[slot].mBufferState != BufferSlot::FREE) {
+ mFreeSlots.insert(slot);
+ } else if (hadBuffer) {
+ // If the slot was FREE, but we had a buffer, we need to move this slot
+ // from the free buffers list to the the free slots list
+ mFreeBuffers.remove(slot);
+ mFreeSlots.insert(slot);
+ }
mSlots[slot].mBufferState = BufferSlot::FREE;
- mSlots[slot].mFrameNumber = UINT32_MAX;
mSlots[slot].mAcquireCalled = false;
// Destroy fence as BufferQueue now takes ownership
@@ -204,6 +218,7 @@
mSlots[slot].mEglFence = EGL_NO_SYNC_KHR;
}
mSlots[slot].mFence = Fence::NO_FENCE;
+ validateConsistencyLocked();
}
void BufferQueueCore::freeAllBuffersLocked() {
@@ -236,4 +251,48 @@
}
}
+void BufferQueueCore::validateConsistencyLocked() const {
+ static const useconds_t PAUSE_TIME = 0;
+ for (int slot = 0; slot < BufferQueueDefs::NUM_BUFFER_SLOTS; ++slot) {
+ bool isInFreeSlots = mFreeSlots.count(slot) != 0;
+ bool isInFreeBuffers =
+ std::find(mFreeBuffers.cbegin(), mFreeBuffers.cend(), slot) !=
+ mFreeBuffers.cend();
+ if (mSlots[slot].mBufferState == BufferSlot::FREE) {
+ if (mSlots[slot].mGraphicBuffer == NULL) {
+ if (!isInFreeSlots) {
+ BQ_LOGE("Slot %d is FREE but is not in mFreeSlots", slot);
+ usleep(PAUSE_TIME);
+ }
+ if (isInFreeBuffers) {
+ BQ_LOGE("Slot %d is in mFreeSlots "
+ "but is also in mFreeBuffers", slot);
+ usleep(PAUSE_TIME);
+ }
+ } else {
+ if (!isInFreeBuffers) {
+ BQ_LOGE("Slot %d is FREE but is not in mFreeBuffers", slot);
+ usleep(PAUSE_TIME);
+ }
+ if (isInFreeSlots) {
+ BQ_LOGE("Slot %d is in mFreeBuffers "
+ "but is also in mFreeSlots", slot);
+ usleep(PAUSE_TIME);
+ }
+ }
+ } else {
+ if (isInFreeSlots) {
+ BQ_LOGE("Slot %d is in mFreeSlots but is not FREE (%d)",
+ slot, mSlots[slot].mBufferState);
+ usleep(PAUSE_TIME);
+ }
+ if (isInFreeBuffers) {
+ BQ_LOGE("Slot %d is in mFreeBuffers but is not FREE (%d)",
+ slot, mSlots[slot].mBufferState);
+ usleep(PAUSE_TIME);
+ }
+ }
+ }
+}
+
} // namespace android
diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
index 4c22ba3..86e45c8 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -161,8 +161,6 @@
}
}
- // Look for a free buffer to give to the client
- *found = BufferQueueCore::INVALID_BUFFER_SLOT;
int dequeuedCount = 0;
int acquiredCount = 0;
for (int s = 0; s < maxBufferCount; ++s) {
@@ -173,15 +171,6 @@
case BufferSlot::ACQUIRED:
++acquiredCount;
break;
- case BufferSlot::FREE:
- // We return the oldest of the free buffers to avoid
- // stalling the producer if possible, since the consumer
- // may still have pending reads of in-flight buffers
- if (*found == BufferQueueCore::INVALID_BUFFER_SLOT ||
- mSlots[s].mFrameNumber < mSlots[*found].mFrameNumber) {
- *found = s;
- }
- break;
default:
break;
}
@@ -214,6 +203,8 @@
}
}
+ *found = BufferQueueCore::INVALID_BUFFER_SLOT;
+
// If we disconnect and reconnect quickly, we can be in a state where
// our slots are empty but we have many buffers in the queue. This can
// cause us to run out of memory if we outrun the consumer. Wait here if
@@ -223,6 +214,19 @@
if (tooManyBuffers) {
BQ_LOGV("%s: queue size is %zu, waiting", caller,
mCore->mQueue.size());
+ } else {
+ if (!mCore->mFreeBuffers.empty()) {
+ auto slot = mCore->mFreeBuffers.begin();
+ *found = *slot;
+ mCore->mFreeBuffers.erase(slot);
+ } else if (mCore->mAllowAllocation && !mCore->mFreeSlots.empty()) {
+ auto slot = mCore->mFreeSlots.begin();
+ // Only return free slots up to the max buffer count
+ if (*slot < maxBufferCount) {
+ *found = *slot;
+ mCore->mFreeSlots.erase(slot);
+ }
+ }
}
// If no buffer is found, or if the queue has too many buffers
@@ -281,17 +285,39 @@
// Enable the usage bits the consumer requested
usage |= mCore->mConsumerUsageBits;
- int found;
- status_t status = waitForFreeSlotThenRelock("dequeueBuffer", async,
- &found, &returnFlags);
- if (status != NO_ERROR) {
- return status;
+ const bool useDefaultSize = !width && !height;
+ if (useDefaultSize) {
+ width = mCore->mDefaultWidth;
+ height = mCore->mDefaultHeight;
}
- // This should not happen
- if (found == BufferQueueCore::INVALID_BUFFER_SLOT) {
- BQ_LOGE("dequeueBuffer: no available buffer slots");
- return -EBUSY;
+ int found = BufferItem::INVALID_BUFFER_SLOT;
+ while (found == BufferItem::INVALID_BUFFER_SLOT) {
+ status_t status = waitForFreeSlotThenRelock("dequeueBuffer", async,
+ &found, &returnFlags);
+ if (status != NO_ERROR) {
+ return status;
+ }
+
+ // This should not happen
+ if (found == BufferQueueCore::INVALID_BUFFER_SLOT) {
+ BQ_LOGE("dequeueBuffer: no available buffer slots");
+ return -EBUSY;
+ }
+
+ const sp<GraphicBuffer>& buffer(mSlots[found].mGraphicBuffer);
+
+ // If we are not allowed to allocate new buffers,
+ // waitForFreeSlotThenRelock must have returned a slot containing a
+ // buffer. If this buffer would require reallocation to meet the
+ // requested attributes, we free it and attempt to get another one.
+ if (!mCore->mAllowAllocation) {
+ if (buffer->needsReallocation(width, height, format, usage)) {
+ mCore->freeBufferLocked(found);
+ found = BufferItem::INVALID_BUFFER_SLOT;
+ continue;
+ }
+ }
}
*outSlot = found;
@@ -299,20 +325,11 @@
attachedByConsumer = mSlots[found].mAttachedByConsumer;
- const bool useDefaultSize = !width && !height;
- if (useDefaultSize) {
- width = mCore->mDefaultWidth;
- height = mCore->mDefaultHeight;
- }
-
mSlots[found].mBufferState = BufferSlot::DEQUEUED;
const sp<GraphicBuffer>& buffer(mSlots[found].mGraphicBuffer);
if ((buffer == NULL) ||
- (static_cast<uint32_t>(buffer->width) != width) ||
- (static_cast<uint32_t>(buffer->height) != height) ||
- (buffer->format != format) ||
- ((static_cast<uint32_t>(buffer->usage) & usage) != usage))
+ buffer->needsReallocation(width, height, format, usage))
{
mSlots[found].mAcquireCalled = false;
mSlots[found].mGraphicBuffer = NULL;
@@ -335,6 +352,8 @@
*outFence = mSlots[found].mFence;
mSlots[found].mEglFence = EGL_NO_SYNC_KHR;
mSlots[found].mFence = Fence::NO_FENCE;
+
+ mCore->validateConsistencyLocked();
} // Autolock scope
if (returnFlags & BUFFER_NEEDS_REALLOCATION) {
@@ -355,7 +374,6 @@
return NO_INIT;
}
- mSlots[*outSlot].mFrameNumber = UINT32_MAX;
mSlots[*outSlot].mGraphicBuffer = graphicBuffer;
} // Autolock scope
}
@@ -414,6 +432,7 @@
mCore->freeBufferLocked(slot);
mCore->mDequeueCondition.broadcast();
+ mCore->validateConsistencyLocked();
return NO_ERROR;
}
@@ -438,27 +457,19 @@
return NO_INIT;
}
- // Find the oldest valid slot
- int found = BufferQueueCore::INVALID_BUFFER_SLOT;
- for (int s = 0; s < BufferQueueDefs::NUM_BUFFER_SLOTS; ++s) {
- if (mSlots[s].mBufferState == BufferSlot::FREE &&
- mSlots[s].mGraphicBuffer != NULL) {
- if (found == BufferQueueCore::INVALID_BUFFER_SLOT ||
- mSlots[s].mFrameNumber < mSlots[found].mFrameNumber) {
- found = s;
- }
- }
- }
-
- if (found == BufferQueueCore::INVALID_BUFFER_SLOT) {
+ if (mCore->mFreeBuffers.empty()) {
return NO_MEMORY;
}
+ int found = mCore->mFreeBuffers.front();
+ mCore->mFreeBuffers.remove(found);
+
BQ_LOGV("detachNextBuffer detached slot %d", found);
*outBuffer = mSlots[found].mGraphicBuffer;
*outFence = mSlots[found].mFence;
mCore->freeBufferLocked(found);
+ mCore->validateConsistencyLocked();
return NO_ERROR;
}
@@ -506,6 +517,8 @@
mSlots[*outSlot].mFence = Fence::NO_FENCE;
mSlots[*outSlot].mRequestBufferCalled = true;
+ mCore->validateConsistencyLocked();
+
return returnFlags;
}
@@ -525,6 +538,7 @@
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 +635,7 @@
item.mSlot = slot;
item.mFence = fence;
item.mIsDroppable = mCore->mDequeueBufferCannotBlock || async;
+ item.mSurfaceDamage = surfaceDamage;
mStickyTransform = stickyTransform;
@@ -638,9 +653,7 @@
// mark it as freed
if (mCore->stillTracking(front)) {
mSlots[front->mSlot].mBufferState = BufferSlot::FREE;
- // Reset the frame number of the freed buffer so that it is
- // the first in line to be dequeued again
- mSlots[front->mSlot].mFrameNumber = 0;
+ mCore->mFreeBuffers.push_front(front->mSlot);
}
// Overwrite the droppable buffer with the incoming one
*front = item;
@@ -662,6 +675,8 @@
// Take a ticket for the callback functions
callbackTicket = mNextCallbackTicket++;
+
+ mCore->validateConsistencyLocked();
} // Autolock scope
// Wait without lock held
@@ -722,10 +737,11 @@
return;
}
+ mCore->mFreeBuffers.push_front(slot);
mSlots[slot].mBufferState = BufferSlot::FREE;
- mSlots[slot].mFrameNumber = 0;
mSlots[slot].mFence = fence;
mCore->mDequeueCondition.broadcast();
+ mCore->validateConsistencyLocked();
}
int BufferQueueProducer::query(int what, int *outValue) {
@@ -930,6 +946,12 @@
Mutex::Autolock lock(mCore->mMutex);
mCore->waitWhileAllocatingLocked();
+ if (!mCore->mAllowAllocation) {
+ BQ_LOGE("allocateBuffers: allocation is not allowed for this "
+ "BufferQueue");
+ return;
+ }
+
int currentBufferCount = 0;
for (int slot = 0; slot < BufferQueueDefs::NUM_BUFFER_SLOTS; ++slot) {
if (mSlots[slot].mGraphicBuffer != NULL) {
@@ -1007,17 +1029,32 @@
}
mCore->freeBufferLocked(slot); // Clean up the slot first
mSlots[slot].mGraphicBuffer = buffers[i];
- mSlots[slot].mFrameNumber = 0;
mSlots[slot].mFence = Fence::NO_FENCE;
+
+ // freeBufferLocked puts this slot on the free slots list. Since
+ // we then attached a buffer, move the slot to free buffer list.
+ mCore->mFreeSlots.erase(slot);
+ mCore->mFreeBuffers.push_front(slot);
+
BQ_LOGV("allocateBuffers: allocated a new buffer in slot %d", slot);
}
mCore->mIsAllocating = false;
mCore->mIsAllocatingCondition.broadcast();
+ mCore->validateConsistencyLocked();
} // Autolock scope
}
}
+status_t BufferQueueProducer::allowAllocation(bool allow) {
+ ATRACE_CALL();
+ BQ_LOGV("allowAllocation: %s", allow ? "true" : "false");
+
+ Mutex::Autolock lock(mCore->mMutex);
+ mCore->mAllowAllocation = allow;
+ return NO_ERROR;
+}
+
void BufferQueueProducer::binderDied(const wp<android::IBinder>& /* who */) {
// If we're here, it means that a producer we were connected to died.
// We're guaranteed that we are still connected to it because we remove
diff --git a/libs/gui/IGraphicBufferProducer.cpp b/libs/gui/IGraphicBufferProducer.cpp
index a3e6fb2..7093ffa 100644
--- a/libs/gui/IGraphicBufferProducer.cpp
+++ b/libs/gui/IGraphicBufferProducer.cpp
@@ -46,6 +46,7 @@
DISCONNECT,
SET_SIDEBAND_STREAM,
ALLOCATE_BUFFERS,
+ ALLOW_ALLOCATION,
};
class BpGraphicBufferProducer : public BpInterface<IGraphicBufferProducer>
@@ -271,6 +272,18 @@
ALOGE("allocateBuffers failed to transact: %d", result);
}
}
+
+ virtual status_t allowAllocation(bool allow) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor());
+ data.writeInt32(static_cast<int32_t>(allow));
+ status_t result = remote()->transact(ALLOW_ALLOCATION, data, &reply);
+ if (result != NO_ERROR) {
+ return result;
+ }
+ result = reply.readInt32();
+ return result;
+ }
};
// Out-of-line virtual method definition to trigger vtable emission in this
@@ -418,7 +431,7 @@
reply->writeInt32(result);
return NO_ERROR;
}
- case ALLOCATE_BUFFERS:
+ case ALLOCATE_BUFFERS: {
CHECK_INTERFACE(IGraphicBufferProducer, data, reply);
bool async = static_cast<bool>(data.readInt32());
uint32_t width = data.readUint32();
@@ -427,6 +440,14 @@
uint32_t usage = data.readUint32();
allocateBuffers(async, width, height, format, usage);
return NO_ERROR;
+ }
+ case ALLOW_ALLOCATION: {
+ CHECK_INTERFACE(IGraphicBufferProducer, data, reply);
+ bool allow = static_cast<bool>(data.readInt32());
+ status_t result = allowAllocation(allow);
+ reply->writeInt32(result);
+ return NO_ERROR;
+ }
}
return BBinder::onTransact(code, data, reply, flags);
}
@@ -446,7 +467,8 @@
+ sizeof(transform)
+ sizeof(stickyTransform)
+ sizeof(async)
- + fence->getFlattenedSize();
+ + fence->getFlattenedSize()
+ + surfaceDamage.getFlattenedSize();
}
size_t IGraphicBufferProducer::QueueBufferInput::getFdCount() const {
@@ -467,7 +489,11 @@
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 +523,11 @@
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..b8acad2 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 @@
IGraphicBufferProducer::QueueBufferInput input(timestamp, isAutoTimestamp,
mDataSpace, crop, mScalingMode, mTransform ^ mStickyTransform,
mSwapIntervalZero, fence, mStickyTransform);
+
+ if (mConnectedToCpu || 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,11 @@
mConsumerRunningBehind = (numPendingBuffers >= 2);
+ if (!mConnectedToCpu) {
+ // Clear surface damage back to full-buffer
+ mDirtyRegion = Region::INVALID_REGION;
+ }
+
return err;
}
@@ -453,6 +478,9 @@
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 +584,13 @@
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 +617,13 @@
}
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 +841,27 @@
}
}
+void Surface::setSurfaceDamage(android_native_rect_t* rects, size_t numRects) {
+ ATRACE_CALL();
+ ALOGV("Surface::setSurfaceDamage");
+ Mutex::Autolock lock(mMutex);
+
+ if (mConnectedToCpu || 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/gui/tests/Android.mk b/libs/gui/tests/Android.mk
index 128a32a..6ad9986 100644
--- a/libs/gui/tests/Android.mk
+++ b/libs/gui/tests/Android.mk
@@ -3,6 +3,8 @@
include $(CLEAR_VARS)
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
+LOCAL_CLANG := true
+
LOCAL_MODULE := libgui_test
LOCAL_MODULE_TAGS := tests
diff --git a/libs/gui/tests/BufferQueue_test.cpp b/libs/gui/tests/BufferQueue_test.cpp
index c38c797..1584fef 100644
--- a/libs/gui/tests/BufferQueue_test.cpp
+++ b/libs/gui/tests/BufferQueue_test.cpp
@@ -73,6 +73,8 @@
virtual void onSidebandStreamChanged() {}
};
+static const uint32_t TEST_DATA = 0x12345678u;
+
// XXX: Tests that fork a process to hold the BufferQueue must run before tests
// that use a local BufferQueue, or else Binder will get unhappy
TEST_F(BufferQueueTest, BufferQueueInAnotherProcess) {
@@ -122,7 +124,7 @@
uint32_t* dataIn;
ASSERT_EQ(OK, buffer->lock(GraphicBuffer::USAGE_SW_WRITE_OFTEN,
reinterpret_cast<void**>(&dataIn)));
- *dataIn = 0x12345678;
+ *dataIn = TEST_DATA;
ASSERT_EQ(OK, buffer->unlock());
IGraphicBufferProducer::QueueBufferInput input(0, false,
@@ -136,7 +138,7 @@
uint32_t* dataOut;
ASSERT_EQ(OK, item.mGraphicBuffer->lock(GraphicBuffer::USAGE_SW_READ_OFTEN,
reinterpret_cast<void**>(&dataOut)));
- ASSERT_EQ(*dataOut, 0x12345678);
+ ASSERT_EQ(*dataOut, TEST_DATA);
ASSERT_EQ(OK, item.mGraphicBuffer->unlock());
}
@@ -239,7 +241,7 @@
uint32_t* dataIn;
ASSERT_EQ(OK, buffer->lock(GraphicBuffer::USAGE_SW_WRITE_OFTEN,
reinterpret_cast<void**>(&dataIn)));
- *dataIn = 0x12345678;
+ *dataIn = TEST_DATA;
ASSERT_EQ(OK, buffer->unlock());
int newSlot;
@@ -258,7 +260,7 @@
uint32_t* dataOut;
ASSERT_EQ(OK, item.mGraphicBuffer->lock(GraphicBuffer::USAGE_SW_READ_OFTEN,
reinterpret_cast<void**>(&dataOut)));
- ASSERT_EQ(*dataOut, 0x12345678);
+ ASSERT_EQ(*dataOut, TEST_DATA);
ASSERT_EQ(OK, item.mGraphicBuffer->unlock());
}
@@ -297,7 +299,7 @@
ASSERT_EQ(OK, item.mGraphicBuffer->lock(
GraphicBuffer::USAGE_SW_WRITE_OFTEN,
reinterpret_cast<void**>(&dataIn)));
- *dataIn = 0x12345678;
+ *dataIn = TEST_DATA;
ASSERT_EQ(OK, item.mGraphicBuffer->unlock());
int newSlot;
@@ -317,7 +319,7 @@
uint32_t* dataOut;
ASSERT_EQ(OK, buffer->lock(GraphicBuffer::USAGE_SW_READ_OFTEN,
reinterpret_cast<void**>(&dataOut)));
- ASSERT_EQ(*dataOut, 0x12345678);
+ ASSERT_EQ(*dataOut, TEST_DATA);
ASSERT_EQ(OK, buffer->unlock());
}
@@ -340,7 +342,7 @@
uint32_t* dataIn;
ASSERT_EQ(OK, buffer->lock(GraphicBuffer::USAGE_SW_WRITE_OFTEN,
reinterpret_cast<void**>(&dataIn)));
- *dataIn = 0x12345678;
+ *dataIn = TEST_DATA;
ASSERT_EQ(OK, buffer->unlock());
IGraphicBufferProducer::QueueBufferInput input(0, false,
@@ -360,8 +362,44 @@
uint32_t* dataOut;
ASSERT_EQ(OK, item.mGraphicBuffer->lock(GraphicBuffer::USAGE_SW_READ_OFTEN,
reinterpret_cast<void**>(&dataOut)));
- ASSERT_EQ(*dataOut, 0x12345678);
+ ASSERT_EQ(*dataOut, TEST_DATA);
ASSERT_EQ(OK, item.mGraphicBuffer->unlock());
}
+TEST_F(BufferQueueTest, TestDisallowingAllocation) {
+ createBufferQueue();
+ sp<DummyConsumer> dc(new DummyConsumer);
+ ASSERT_EQ(OK, mConsumer->consumerConnect(dc, true));
+ IGraphicBufferProducer::QueueBufferOutput output;
+ ASSERT_EQ(OK, mProducer->connect(new DummyProducerListener,
+ NATIVE_WINDOW_API_CPU, true, &output));
+
+ static const uint32_t WIDTH = 320;
+ static const uint32_t HEIGHT = 240;
+
+ ASSERT_EQ(OK, mConsumer->setDefaultBufferSize(WIDTH, HEIGHT));
+
+ int slot;
+ sp<Fence> fence;
+ sp<GraphicBuffer> buffer;
+ // This should return an error since it would require an allocation
+ ASSERT_EQ(OK, mProducer->allowAllocation(false));
+ ASSERT_EQ(WOULD_BLOCK, mProducer->dequeueBuffer(&slot, &fence, false, 0, 0,
+ 0, GRALLOC_USAGE_SW_WRITE_OFTEN));
+
+ // This should succeed, now that we've lifted the prohibition
+ ASSERT_EQ(OK, mProducer->allowAllocation(true));
+ ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION,
+ mProducer->dequeueBuffer(&slot, &fence, false, 0, 0, 0,
+ GRALLOC_USAGE_SW_WRITE_OFTEN));
+
+ // Release the previous buffer back to the BufferQueue
+ mProducer->cancelBuffer(slot, fence);
+
+ // This should fail since we're requesting a different size
+ ASSERT_EQ(OK, mProducer->allowAllocation(false));
+ ASSERT_EQ(WOULD_BLOCK, mProducer->dequeueBuffer(&slot, &fence, false,
+ WIDTH * 2, HEIGHT * 2, 0, GRALLOC_USAGE_SW_WRITE_OFTEN));
+}
+
} // namespace android
diff --git a/libs/gui/tests/CpuConsumer_test.cpp b/libs/gui/tests/CpuConsumer_test.cpp
index 0beca92..2dc9ccc 100644
--- a/libs/gui/tests/CpuConsumer_test.cpp
+++ b/libs/gui/tests/CpuConsumer_test.cpp
@@ -94,7 +94,7 @@
mPendingFrames--;
}
- virtual void onFrameAvailable() {
+ virtual void onFrameAvailable(const BufferItem&) {
Mutex::Autolock lock(mMutex);
mPendingFrames++;
mCondition.signal();
@@ -125,7 +125,7 @@
mPendingFrames--;
}
- virtual void onFrameAvailable() {
+ virtual void onFrameAvailable(const BufferItem&) {
Mutex::Autolock lock(mMutex);
mPendingFrames++;
mFrameCondition.signal();
@@ -457,9 +457,12 @@
const CpuConsumerTestParams& params,
int maxBufferSlack) {
status_t err;
- err = native_window_set_buffers_geometry(anw.get(),
- params.width, params.height, params.format);
- ASSERT_NO_ERROR(err, "set_buffers_geometry error: ");
+ err = native_window_set_buffers_dimensions(anw.get(),
+ params.width, params.height);
+ ASSERT_NO_ERROR(err, "set_buffers_dimensions error: ");
+
+ err = native_window_set_buffers_format(anw.get(), params.format);
+ ASSERT_NO_ERROR(err, "set_buffers_format error: ");
err = native_window_set_usage(anw.get(),
GRALLOC_USAGE_SW_WRITE_OFTEN);
diff --git a/libs/gui/tests/IGraphicBufferProducer_test.cpp b/libs/gui/tests/IGraphicBufferProducer_test.cpp
index c904a6b..ff58420 100644
--- a/libs/gui/tests/IGraphicBufferProducer_test.cpp
+++ b/libs/gui/tests/IGraphicBufferProducer_test.cpp
@@ -38,31 +38,31 @@
#define TEST_CONTROLLED_BY_APP false
#define TEST_PRODUCER_USAGE_BITS (0)
-// TODO: Make these public constants in a header
-enum {
- // Default dimensions before setDefaultBufferSize is called
- DEFAULT_WIDTH = 1,
- DEFAULT_HEIGHT = 1,
-
- // Default format before setDefaultBufferFormat is called
- DEFAULT_FORMAT = HAL_PIXEL_FORMAT_RGBA_8888,
-
- // Default transform hint before setTransformHint is called
- DEFAULT_TRANSFORM_HINT = 0,
-};
-
namespace android {
namespace {
-// Parameters for a generic "valid" input for queueBuffer.
-const int64_t QUEUE_BUFFER_INPUT_TIMESTAMP = 1384888611;
-const bool QUEUE_BUFFER_INPUT_IS_AUTO_TIMESTAMP = false;
-const android_dataspace QUEUE_BUFFER_INPUT_DATASPACE = HAL_DATASPACE_UNKNOWN;
-const Rect QUEUE_BUFFER_INPUT_RECT = Rect(DEFAULT_WIDTH, DEFAULT_HEIGHT);
-const int QUEUE_BUFFER_INPUT_SCALING_MODE = 0;
-const int QUEUE_BUFFER_INPUT_TRANSFORM = 0;
-const bool QUEUE_BUFFER_INPUT_ASYNC = false;
-const sp<Fence> QUEUE_BUFFER_INPUT_FENCE = Fence::NO_FENCE;
+ // Default dimensions before setDefaultBufferSize is called
+ const uint32_t DEFAULT_WIDTH = 1;
+ const uint32_t DEFAULT_HEIGHT = 1;
+
+ // Default format before setDefaultBufferFormat is called
+ const PixelFormat DEFAULT_FORMAT = HAL_PIXEL_FORMAT_RGBA_8888;
+
+ // Default transform hint before setTransformHint is called
+ const uint32_t DEFAULT_TRANSFORM_HINT = 0;
+
+ // TODO: Make these constants in header
+ const int DEFAULT_CONSUMER_USAGE_BITS = 0;
+
+ // Parameters for a generic "valid" input for queueBuffer.
+ const int64_t QUEUE_BUFFER_INPUT_TIMESTAMP = 1384888611;
+ const bool QUEUE_BUFFER_INPUT_IS_AUTO_TIMESTAMP = false;
+ const android_dataspace QUEUE_BUFFER_INPUT_DATASPACE = HAL_DATASPACE_UNKNOWN;
+ const Rect QUEUE_BUFFER_INPUT_RECT = Rect(DEFAULT_WIDTH, DEFAULT_HEIGHT);
+ const int QUEUE_BUFFER_INPUT_SCALING_MODE = 0;
+ const int QUEUE_BUFFER_INPUT_TRANSFORM = 0;
+ const bool QUEUE_BUFFER_INPUT_ASYNC = false;
+ const sp<Fence> QUEUE_BUFFER_INPUT_FENCE = Fence::NO_FENCE;
}; // namespace anonymous
struct DummyConsumer : public BnConsumerListener {
@@ -273,15 +273,12 @@
TEST_F(IGraphicBufferProducerTest, Query_Succeeds) {
ASSERT_NO_FATAL_FAILURE(ConnectProducer());
- // TODO: Make these constants in header
- const int DEFAULT_CONSUMER_USAGE_BITS = 0;
-
- int value = -1;
+ int32_t value = -1;
EXPECT_OK(mProducer->query(NATIVE_WINDOW_WIDTH, &value));
- EXPECT_EQ(DEFAULT_WIDTH, value);
+ EXPECT_EQ(DEFAULT_WIDTH, static_cast<uint32_t>(value));
EXPECT_OK(mProducer->query(NATIVE_WINDOW_HEIGHT, &value));
- EXPECT_EQ(DEFAULT_HEIGHT, value);
+ EXPECT_EQ(DEFAULT_HEIGHT, static_cast<uint32_t>(value));
EXPECT_OK(mProducer->query(NATIVE_WINDOW_FORMAT, &value));
EXPECT_EQ(DEFAULT_FORMAT, value);
@@ -302,7 +299,7 @@
ASSERT_NO_FATAL_FAILURE(ConnectProducer());
// One past the end of the last 'query' enum value. Update this if we add more enums.
- const int NATIVE_WINDOW_QUERY_LAST_OFF_BY_ONE = NATIVE_WINDOW_CONSUMER_USAGE_BITS + 1;
+ const int NATIVE_WINDOW_QUERY_LAST_OFF_BY_ONE = NATIVE_WINDOW_DEFAULT_DATASPACE + 1;
int value;
// What was out of range
@@ -369,7 +366,7 @@
EXPECT_EQ(DEFAULT_WIDTH, width);
EXPECT_EQ(DEFAULT_HEIGHT, height);
EXPECT_EQ(DEFAULT_TRANSFORM_HINT, transformHint);
- EXPECT_EQ(1, numPendingBuffers); // since queueBuffer was called exactly once
+ EXPECT_EQ(1u, numPendingBuffers); // since queueBuffer was called exactly once
}
// Buffer was not in the dequeued state
diff --git a/libs/gui/tests/SRGB_test.cpp b/libs/gui/tests/SRGB_test.cpp
index e5907e7..3b11b97 100644
--- a/libs/gui/tests/SRGB_test.cpp
+++ b/libs/gui/tests/SRGB_test.cpp
@@ -17,6 +17,10 @@
#define LOG_TAG "SRGB_test"
//#define LOG_NDEBUG 0
+// Ignore for this file because it flags every instance of
+// ASSERT_EQ(GL_NO_ERROR, glGetError());
+#pragma clang diagnostic ignored "-Wsign-compare"
+
#include "GLTest.h"
#include <math.h>
@@ -329,9 +333,9 @@
ANativeWindow_Buffer outBuffer;
ARect outBufferBounds;
mOutputSurface->lock(&outBuffer, &outBufferBounds);
- ASSERT_EQ(mLockedBuffer.width, outBuffer.width);
- ASSERT_EQ(mLockedBuffer.height, outBuffer.height);
- ASSERT_EQ(mLockedBuffer.stride, outBuffer.stride);
+ ASSERT_EQ(mLockedBuffer.width, static_cast<uint32_t>(outBuffer.width));
+ ASSERT_EQ(mLockedBuffer.height, static_cast<uint32_t>(outBuffer.height));
+ ASSERT_EQ(mLockedBuffer.stride, static_cast<uint32_t>(outBuffer.stride));
if (mLockedBuffer.format == outBuffer.format) {
memcpy(outBuffer.bits, mLockedBuffer.data, bufferSize);
@@ -401,7 +405,8 @@
// the debug surface if necessary
}
-TEST_F(SRGBTest, RenderToSRGBSurface) {
+// XXX: Disabled since we don't currently expect this to work
+TEST_F(SRGBTest, DISABLED_RenderToSRGBSurface) {
ASSERT_NO_FATAL_FAILURE(initShaders());
// By default, the first buffer we write into will be RGB
diff --git a/libs/gui/tests/StreamSplitter_test.cpp b/libs/gui/tests/StreamSplitter_test.cpp
index 767c7c6..00cc39d 100644
--- a/libs/gui/tests/StreamSplitter_test.cpp
+++ b/libs/gui/tests/StreamSplitter_test.cpp
@@ -76,6 +76,8 @@
int mAllocCount;
};
+static const uint32_t TEST_DATA = 0x12345678u;
+
TEST_F(StreamSplitterTest, OneInputOneOutput) {
sp<CountedAllocator> allocator(new CountedAllocator);
@@ -108,7 +110,7 @@
uint32_t* dataIn;
ASSERT_EQ(OK, buffer->lock(GraphicBuffer::USAGE_SW_WRITE_OFTEN,
reinterpret_cast<void**>(&dataIn)));
- *dataIn = 0x12345678;
+ *dataIn = TEST_DATA;
ASSERT_EQ(OK, buffer->unlock());
IGraphicBufferProducer::QueueBufferInput qbInput(0, false,
@@ -123,7 +125,7 @@
uint32_t* dataOut;
ASSERT_EQ(OK, item.mGraphicBuffer->lock(GraphicBuffer::USAGE_SW_READ_OFTEN,
reinterpret_cast<void**>(&dataOut)));
- ASSERT_EQ(*dataOut, 0x12345678);
+ ASSERT_EQ(*dataOut, TEST_DATA);
ASSERT_EQ(OK, item.mGraphicBuffer->unlock());
ASSERT_EQ(OK, outputConsumer->releaseBuffer(item.mBuf, item.mFrameNumber,
@@ -175,7 +177,7 @@
uint32_t* dataIn;
ASSERT_EQ(OK, buffer->lock(GraphicBuffer::USAGE_SW_WRITE_OFTEN,
reinterpret_cast<void**>(&dataIn)));
- *dataIn = 0x12345678;
+ *dataIn = TEST_DATA;
ASSERT_EQ(OK, buffer->unlock());
IGraphicBufferProducer::QueueBufferInput qbInput(0, false,
@@ -191,7 +193,7 @@
uint32_t* dataOut;
ASSERT_EQ(OK, item.mGraphicBuffer->lock(GraphicBuffer::USAGE_SW_READ_OFTEN,
reinterpret_cast<void**>(&dataOut)));
- ASSERT_EQ(*dataOut, 0x12345678);
+ ASSERT_EQ(*dataOut, TEST_DATA);
ASSERT_EQ(OK, item.mGraphicBuffer->unlock());
ASSERT_EQ(OK, outputConsumers[output]->releaseBuffer(item.mBuf,
diff --git a/libs/gui/tests/SurfaceTextureClient_test.cpp b/libs/gui/tests/SurfaceTextureClient_test.cpp
index 8cdf3bc..d750cd0 100644
--- a/libs/gui/tests/SurfaceTextureClient_test.cpp
+++ b/libs/gui/tests/SurfaceTextureClient_test.cpp
@@ -207,12 +207,8 @@
}
TEST_F(SurfaceTextureClientTest, BufferGeometryInvalidSizesFail) {
- EXPECT_GT(OK, native_window_set_buffers_geometry(mANW.get(), -1, 0, 0));
- EXPECT_GT(OK, native_window_set_buffers_geometry(mANW.get(), 0, -1, 0));
- EXPECT_GT(OK, native_window_set_buffers_geometry(mANW.get(), 0, 0, -1));
- EXPECT_GT(OK, native_window_set_buffers_geometry(mANW.get(), -1, -1, 0));
- EXPECT_GT(OK, native_window_set_buffers_geometry(mANW.get(), 0, 8, 0));
- EXPECT_GT(OK, native_window_set_buffers_geometry(mANW.get(), 8, 0, 0));
+ EXPECT_GT(OK, native_window_set_buffers_dimensions(mANW.get(), 0, 8));
+ EXPECT_GT(OK, native_window_set_buffers_dimensions(mANW.get(), 8, 0));
}
TEST_F(SurfaceTextureClientTest, DefaultGeometryValues) {
@@ -226,7 +222,8 @@
TEST_F(SurfaceTextureClientTest, BufferGeometryCanBeSet) {
ANativeWindowBuffer* buf;
- EXPECT_EQ(OK, native_window_set_buffers_geometry(mANW.get(), 16, 8, PIXEL_FORMAT_RGB_565));
+ EXPECT_EQ(OK, native_window_set_buffers_dimensions(mANW.get(), 16, 8));
+ EXPECT_EQ(OK, native_window_set_buffers_format(mANW.get(), PIXEL_FORMAT_RGB_565));
ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf));
EXPECT_EQ(16, buf->width);
EXPECT_EQ(8, buf->height);
@@ -236,7 +233,8 @@
TEST_F(SurfaceTextureClientTest, BufferGeometryDefaultSizeSetFormat) {
ANativeWindowBuffer* buf;
- EXPECT_EQ(OK, native_window_set_buffers_geometry(mANW.get(), 0, 0, PIXEL_FORMAT_RGB_565));
+ EXPECT_EQ(OK, native_window_set_buffers_dimensions(mANW.get(), 0, 0));
+ EXPECT_EQ(OK, native_window_set_buffers_format(mANW.get(), PIXEL_FORMAT_RGB_565));
ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf));
EXPECT_EQ(1, buf->width);
EXPECT_EQ(1, buf->height);
@@ -246,7 +244,8 @@
TEST_F(SurfaceTextureClientTest, BufferGeometrySetSizeDefaultFormat) {
ANativeWindowBuffer* buf;
- EXPECT_EQ(OK, native_window_set_buffers_geometry(mANW.get(), 16, 8, 0));
+ EXPECT_EQ(OK, native_window_set_buffers_dimensions(mANW.get(), 16, 8));
+ EXPECT_EQ(OK, native_window_set_buffers_format(mANW.get(), 0));
ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf));
EXPECT_EQ(16, buf->width);
EXPECT_EQ(8, buf->height);
@@ -256,13 +255,15 @@
TEST_F(SurfaceTextureClientTest, BufferGeometrySizeCanBeUnset) {
ANativeWindowBuffer* buf;
- EXPECT_EQ(OK, native_window_set_buffers_geometry(mANW.get(), 16, 8, 0));
+ EXPECT_EQ(OK, native_window_set_buffers_dimensions(mANW.get(), 16, 8));
+ EXPECT_EQ(OK, native_window_set_buffers_format(mANW.get(), 0));
ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf));
EXPECT_EQ(16, buf->width);
EXPECT_EQ(8, buf->height);
EXPECT_EQ(PIXEL_FORMAT_RGBA_8888, buf->format);
ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf, -1));
- EXPECT_EQ(OK, native_window_set_buffers_geometry(mANW.get(), 0, 0, 0));
+ EXPECT_EQ(OK, native_window_set_buffers_dimensions(mANW.get(), 0, 0));
+ EXPECT_EQ(OK, native_window_set_buffers_format(mANW.get(), 0));
ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf));
EXPECT_EQ(1, buf->width);
EXPECT_EQ(1, buf->height);
@@ -272,7 +273,8 @@
TEST_F(SurfaceTextureClientTest, BufferGeometrySizeCanBeChangedWithoutFormat) {
ANativeWindowBuffer* buf;
- EXPECT_EQ(OK, native_window_set_buffers_geometry(mANW.get(), 0, 0, PIXEL_FORMAT_RGB_565));
+ EXPECT_EQ(OK, native_window_set_buffers_dimensions(mANW.get(), 0, 0));
+ EXPECT_EQ(OK, native_window_set_buffers_format(mANW.get(), PIXEL_FORMAT_RGB_565));
ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf));
EXPECT_EQ(1, buf->width);
EXPECT_EQ(1, buf->height);
@@ -330,7 +332,8 @@
EXPECT_EQ(8, buf[1]->height);
ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf[0], -1));
ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf[1], -1));
- EXPECT_EQ(OK, native_window_set_buffers_geometry(mANW.get(), 12, 24, 0));
+ EXPECT_EQ(OK, native_window_set_buffers_dimensions(mANW.get(), 12, 24));
+ EXPECT_EQ(OK, native_window_set_buffers_format(mANW.get(), 0));
ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[0]));
ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[1]));
EXPECT_NE(buf[0], buf[1]);
@@ -468,7 +471,8 @@
// Once we've queued a buffer, however we should not be able to dequeue more
// than (buffer-count - MIN_UNDEQUEUED_BUFFERS), which is 2 in this case.
- EXPECT_EQ(-EBUSY, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[1]));
+ EXPECT_EQ(INVALID_OPERATION,
+ native_window_dequeue_buffer_and_wait(mANW.get(), &buf[1]));
ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf[0], -1));
ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf[2], -1));
@@ -620,7 +624,8 @@
crop.bottom = 5;
ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 4));
- ASSERT_EQ(OK, native_window_set_buffers_geometry(mANW.get(), 8, 8, 0));
+ ASSERT_EQ(OK, native_window_set_buffers_dimensions(mANW.get(), 8, 8));
+ ASSERT_EQ(OK, native_window_set_buffers_format(mANW.get(), 0));
ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[0]));
ASSERT_EQ(OK, native_window_set_crop(mANW.get(), &crop));
ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[0], -1));
@@ -668,7 +673,8 @@
const int numFmts = (sizeof(fmts) / sizeof(fmts[0]));
for (int i = 0; i < numFmts; i++) {
int fmt = -1;
- ASSERT_EQ(OK, native_window_set_buffers_geometry(anw.get(), 0, 0, fmts[i]));
+ ASSERT_EQ(OK, native_window_set_buffers_dimensions(anw.get(), 0, 0));
+ ASSERT_EQ(OK, native_window_set_buffers_format(anw.get(), fmts[i]));
ASSERT_EQ(OK, anw->query(anw.get(), NATIVE_WINDOW_FORMAT, &fmt));
EXPECT_EQ(fmts[i], fmt);
}
diff --git a/libs/gui/tests/SurfaceTextureFBO_test.cpp b/libs/gui/tests/SurfaceTextureFBO_test.cpp
index b165ae6..c243fc0 100644
--- a/libs/gui/tests/SurfaceTextureFBO_test.cpp
+++ b/libs/gui/tests/SurfaceTextureFBO_test.cpp
@@ -27,8 +27,10 @@
const int texWidth = 64;
const int texHeight = 64;
- ASSERT_EQ(NO_ERROR, native_window_set_buffers_geometry(mANW.get(),
- texWidth, texHeight, HAL_PIXEL_FORMAT_RGBA_8888));
+ ASSERT_EQ(NO_ERROR, native_window_set_buffers_dimensions(mANW.get(),
+ texWidth, texHeight));
+ ASSERT_EQ(NO_ERROR, native_window_set_buffers_format(mANW.get(),
+ HAL_PIXEL_FORMAT_RGBA_8888));
ASSERT_EQ(NO_ERROR, native_window_set_usage(mANW.get(),
GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN));
diff --git a/libs/gui/tests/SurfaceTextureGL_test.cpp b/libs/gui/tests/SurfaceTextureGL_test.cpp
index fa1e1b7..fad133f 100644
--- a/libs/gui/tests/SurfaceTextureGL_test.cpp
+++ b/libs/gui/tests/SurfaceTextureGL_test.cpp
@@ -28,8 +28,10 @@
const int texWidth = 64;
const int texHeight = 66;
- ASSERT_EQ(NO_ERROR, native_window_set_buffers_geometry(mANW.get(),
- texWidth, texHeight, HAL_PIXEL_FORMAT_YV12));
+ ASSERT_EQ(NO_ERROR, native_window_set_buffers_dimensions(mANW.get(),
+ texWidth, texHeight));
+ ASSERT_EQ(NO_ERROR, native_window_set_buffers_format(mANW.get(),
+ HAL_PIXEL_FORMAT_YV12));
ASSERT_EQ(NO_ERROR, native_window_set_usage(mANW.get(),
GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN));
@@ -74,8 +76,10 @@
const int texWidth = 64;
const int texHeight = 64;
- ASSERT_EQ(NO_ERROR, native_window_set_buffers_geometry(mANW.get(),
- texWidth, texHeight, HAL_PIXEL_FORMAT_YV12));
+ ASSERT_EQ(NO_ERROR, native_window_set_buffers_dimensions(mANW.get(),
+ texWidth, texHeight));
+ ASSERT_EQ(NO_ERROR, native_window_set_buffers_format(mANW.get(),
+ HAL_PIXEL_FORMAT_YV12));
ASSERT_EQ(NO_ERROR, native_window_set_usage(mANW.get(),
GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN));
@@ -120,8 +124,10 @@
const int texWidth = 64;
const int texHeight = 66;
- ASSERT_EQ(NO_ERROR, native_window_set_buffers_geometry(mANW.get(),
- texWidth, texHeight, HAL_PIXEL_FORMAT_YV12));
+ ASSERT_EQ(NO_ERROR, native_window_set_buffers_dimensions(mANW.get(),
+ texWidth, texHeight));
+ ASSERT_EQ(NO_ERROR, native_window_set_buffers_format(mANW.get(),
+ HAL_PIXEL_FORMAT_YV12));
ASSERT_EQ(NO_ERROR, native_window_set_usage(mANW.get(),
GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN));
@@ -185,8 +191,10 @@
enum { numFrames = 1024 };
ASSERT_EQ(NO_ERROR, mST->setDefaultMaxBufferCount(2));
- ASSERT_EQ(NO_ERROR, native_window_set_buffers_geometry(mANW.get(),
- texWidth, texHeight, HAL_PIXEL_FORMAT_YV12));
+ ASSERT_EQ(NO_ERROR, native_window_set_buffers_dimensions(mANW.get(),
+ texWidth, texHeight));
+ ASSERT_EQ(NO_ERROR, native_window_set_buffers_format(mANW.get(),
+ HAL_PIXEL_FORMAT_YV12));
ASSERT_EQ(NO_ERROR, native_window_set_usage(mANW.get(),
GRALLOC_USAGE_SW_WRITE_OFTEN));
@@ -326,8 +334,10 @@
const int texWidth = 64;
const int texHeight = 66;
- ASSERT_EQ(NO_ERROR, native_window_set_buffers_geometry(mANW.get(),
- texWidth, texHeight, HAL_PIXEL_FORMAT_RGBA_8888));
+ ASSERT_EQ(NO_ERROR, native_window_set_buffers_dimensions(mANW.get(),
+ texWidth, texHeight));
+ ASSERT_EQ(NO_ERROR, native_window_set_buffers_format(mANW.get(),
+ HAL_PIXEL_FORMAT_RGBA_8888));
ASSERT_EQ(NO_ERROR, native_window_set_usage(mANW.get(),
GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN));
@@ -368,8 +378,10 @@
const int texWidth = 64;
const int texHeight = 64;
- ASSERT_EQ(NO_ERROR, native_window_set_buffers_geometry(mANW.get(),
- texWidth, texHeight, HAL_PIXEL_FORMAT_RGBA_8888));
+ ASSERT_EQ(NO_ERROR, native_window_set_buffers_dimensions(mANW.get(),
+ texWidth, texHeight));
+ ASSERT_EQ(NO_ERROR, native_window_set_buffers_format(mANW.get(),
+ HAL_PIXEL_FORMAT_RGBA_8888));
ASSERT_EQ(NO_ERROR, native_window_set_usage(mANW.get(),
GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN));
diff --git a/libs/ui/Fence.cpp b/libs/ui/Fence.cpp
index 9cf2881..bf24ffb 100644
--- a/libs/ui/Fence.cpp
+++ b/libs/ui/Fence.cpp
@@ -130,7 +130,7 @@
}
size_t Fence::getFlattenedSize() const {
- return 1;
+ return 4;
}
size_t Fence::getFdCount() const {
@@ -141,7 +141,9 @@
if (size < getFlattenedSize() || count < getFdCount()) {
return NO_MEMORY;
}
- FlattenableUtils::write(buffer, size, getFdCount());
+ // Cast to uint32_t since the size of a size_t can vary between 32- and
+ // 64-bit processes
+ FlattenableUtils::write(buffer, size, static_cast<uint32_t>(getFdCount()));
if (isValid()) {
*fds++ = mFenceFd;
count--;
diff --git a/libs/ui/GraphicBuffer.cpp b/libs/ui/GraphicBuffer.cpp
index 638ac62..6a42a22 100644
--- a/libs/ui/GraphicBuffer.cpp
+++ b/libs/ui/GraphicBuffer.cpp
@@ -152,6 +152,16 @@
return initSize(inWidth, inHeight, inFormat, inUsage);
}
+bool GraphicBuffer::needsReallocation(uint32_t inWidth, uint32_t inHeight,
+ PixelFormat inFormat, uint32_t inUsage)
+{
+ if (static_cast<int>(inWidth) != width) return true;
+ if (static_cast<int>(inHeight) != height) return true;
+ if (inFormat != format) return true;
+ if ((static_cast<uint32_t>(usage) & inUsage) != inUsage) return true;
+ return false;
+}
+
status_t GraphicBuffer::initSize(uint32_t inWidth, uint32_t inHeight,
PixelFormat inFormat, uint32_t inUsage)
{
@@ -303,7 +313,7 @@
static_cast<size_t>(handle->numInts) * sizeof(int));
}
- buffer = reinterpret_cast<void*>(static_cast<int*>(buffer) + sizeNeeded);
+ buffer = static_cast<void*>(static_cast<uint8_t*>(buffer) + sizeNeeded);
size -= sizeNeeded;
if (handle) {
fds += handle->numFds;
@@ -385,7 +395,7 @@
}
}
- buffer = reinterpret_cast<void const*>(static_cast<int const*>(buffer) + sizeNeeded);
+ buffer = static_cast<void const*>(static_cast<uint8_t const*>(buffer) + sizeNeeded);
size -= sizeNeeded;
fds += numFds;
count -= numFds;
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 91fa216..3810da4 100644
--- a/libs/ui/Region.cpp
+++ b/libs/ui/Region.cpp
@@ -53,6 +53,8 @@
direction_RTL
};
+const Region Region::INVALID_REGION(Rect::INVALID_RECT);
+
// ----------------------------------------------------------------------------
Region::Region() {
@@ -130,43 +132,42 @@
// prevIndex can't be -1 here because if endLastSpan is set to a
// value greater than -1 (allowing the loop to execute),
// beginLastSpan (and therefore prevIndex) will also be increased
- const Rect* prev = &dst[static_cast<size_t>(prevIndex)];
-
+ const Rect prev = dst[static_cast<size_t>(prevIndex)];
if (spanDirection == direction_RTL) {
// iterating over previous span RTL, quit if it's too far left
- if (prev->right <= left) break;
+ if (prev.right <= left) break;
- if (prev->right > left && prev->right < right) {
- dst.add(Rect(prev->right, top, right, bottom));
- right = prev->right;
+ if (prev.right > left && prev.right < right) {
+ dst.add(Rect(prev.right, top, right, bottom));
+ right = prev.right;
}
- if (prev->left > left && prev->left < right) {
- dst.add(Rect(prev->left, top, right, bottom));
- right = prev->left;
+ if (prev.left > left && prev.left < right) {
+ dst.add(Rect(prev.left, top, right, bottom));
+ right = prev.left;
}
// if an entry in the previous span is too far right, nothing further left in the
// current span will need it
- if (prev->left >= right) {
+ if (prev.left >= right) {
beginLastSpan = prevIndex;
}
} else {
// iterating over previous span LTR, quit if it's too far right
- if (prev->left >= right) break;
+ if (prev.left >= right) break;
- if (prev->left > left && prev->left < right) {
- dst.add(Rect(left, top, prev->left, bottom));
- left = prev->left;
+ if (prev.left > left && prev.left < right) {
+ dst.add(Rect(left, top, prev.left, bottom));
+ left = prev.left;
}
- if (prev->right > left && prev->right < right) {
- dst.add(Rect(left, top, prev->right, bottom));
- left = prev->right;
+ if (prev.right > left && prev.right < right) {
+ dst.add(Rect(left, top, prev.right, bottom));
+ left = prev.right;
}
// if an entry in the previous span is too far left, nothing further right in the
// current span will need it
- if (prev->right <= left) {
+ if (prev.right <= left) {
beginLastSpan = prevIndex;
}
}
@@ -518,8 +519,12 @@
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);
@@ -691,7 +696,9 @@
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;
@@ -754,35 +761,52 @@
// ----------------------------------------------------------------------------
size_t Region::getFlattenedSize() const {
- return mStorage.size() * sizeof(Rect);
+ return sizeof(uint32_t) + mStorage.size() * sizeof(Rect);
}
status_t Region::flatten(void* buffer, size_t size) const {
#if VALIDATE_REGIONS
validate(*this, "Region::flatten");
#endif
- if (size < mStorage.size() * sizeof(Rect)) {
+ if (size < getFlattenedSize()) {
return NO_MEMORY;
}
- Rect* rects = reinterpret_cast<Rect*>(buffer);
- memcpy(rects, mStorage.array(), mStorage.size() * sizeof(Rect));
+ // Cast to uint32_t since the size of a size_t can vary between 32- and
+ // 64-bit processes
+ FlattenableUtils::write(buffer, size, static_cast<uint32_t>(mStorage.size()));
+ for (auto rect : mStorage) {
+ status_t result = rect.flatten(buffer, size);
+ if (result != NO_ERROR) {
+ return result;
+ }
+ FlattenableUtils::advance(buffer, size, sizeof(rect));
+ }
return NO_ERROR;
}
status_t Region::unflatten(void const* buffer, size_t size) {
- Region result;
- if (size >= sizeof(Rect)) {
- Rect const* rects = reinterpret_cast<Rect const*>(buffer);
- size_t count = size / sizeof(Rect);
- if (count > 0) {
- result.mStorage.clear();
- ssize_t err = result.mStorage.insertAt(0, count);
- if (err < 0) {
- return status_t(err);
- }
- memcpy(result.mStorage.editArray(), rects, count*sizeof(Rect));
- }
+ if (size < sizeof(uint32_t)) {
+ return NO_MEMORY;
}
+
+ uint32_t numRects = 0;
+ FlattenableUtils::read(buffer, size, numRects);
+ if (size < numRects * sizeof(Rect)) {
+ return NO_MEMORY;
+ }
+
+ Region result;
+ result.mStorage.clear();
+ for (size_t r = 0; r < numRects; ++r) {
+ Rect rect;
+ status_t status = rect.unflatten(buffer, size);
+ if (status != NO_ERROR) {
+ return status;
+ }
+ FlattenableUtils::advance(buffer, size, sizeof(rect));
+ result.mStorage.push_back(rect);
+ }
+
#if VALIDATE_REGIONS
validate(result, "Region::unflatten");
#endif
diff --git a/opengl/include/EGL/eglext.h b/opengl/include/EGL/eglext.h
index 3b2984a..25f7607 100644
--- a/opengl/include/EGL/eglext.h
+++ b/opengl/include/EGL/eglext.h
@@ -176,6 +176,15 @@
#define EGL_BITMAP_PIXEL_SIZE_KHR 0x3110
#endif
+#ifndef EGL_KHR_partial_update
+#define EGL_KHR_partial_update 1
+#define EGL_BUFFER_AGE_KHR 0x313D
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLSETDAMAGEREGIONKHRPROC) (EGLDisplay dpy, EGLSurface surface, EGLint *rects, EGLint n_rects);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglSetDamageRegionKHR (EGLDisplay dpy, EGLSurface surface, EGLint *rects, EGLint n_rects);
+#endif
+#endif /* EGL_KHR_partial_update */
+
#ifndef EGL_NV_coverage_sample
#define EGL_NV_coverage_sample 1
#define EGL_COVERAGE_BUFFERS_NV 0x30E0
@@ -440,6 +449,14 @@
/* No tokens/entry points, just relaxes an error condition */
#endif
+#ifndef EGL_KHR_swap_buffers_with_damage
+#define EGL_KHR_swap_buffers_with_damage 1
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLSWAPBUFFERSWITHDAMAGEKHRPROC) (EGLDisplay dpy, EGLSurface surface, EGLint *rects, EGLint n_rects);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglSwapBuffersWithDamageKHR (EGLDisplay dpy, EGLSurface surface, EGLint *rects, EGLint n_rects);
+#endif
+#endif /* EGL_KHR_swap_buffers_with_damage */
+
#ifdef EGL_KHR_stream /* Requires KHR_stream extension */
#ifndef EGL_KHR_stream_cross_process_fd
#define EGL_KHR_stream_cross_process_fd 1
diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp
index 11a13c3..f5b90dd 100644
--- a/opengl/libs/EGL/eglApi.cpp
+++ b/opengl/libs/EGL/eglApi.cpp
@@ -80,6 +80,7 @@
extern char const * const gBuiltinExtensionString =
"EGL_KHR_get_all_proc_addresses "
"EGL_ANDROID_presentation_time "
+ "EGL_KHR_swap_buffers_with_damage "
;
extern char const * const gExtensionString =
"EGL_KHR_image " // mandatory
@@ -100,6 +101,8 @@
"EGL_ANDROID_image_native_buffer " // mandatory
"EGL_KHR_wait_sync " // strongly recommended
"EGL_ANDROID_recordable " // mandatory
+ "EGL_KHR_partial_update " // strongly recommended
+ "EGL_EXT_buffer_age " // strongly recommended with partial_update
;
// extensions not exposed to applications but used by the ANDROID system
@@ -152,6 +155,14 @@
// EGL_ANDROID_presentation_time
{ "eglPresentationTimeANDROID",
(__eglMustCastToProperFunctionPointerType)&eglPresentationTimeANDROID },
+
+ // EGL_KHR_swap_buffers_with_damage
+ { "eglSwapBuffersWithDamageKHR",
+ (__eglMustCastToProperFunctionPointerType)&eglSwapBuffersWithDamageKHR },
+
+ // EGL_KHR_partial_update
+ { "eglSetDamageRegionKHR",
+ (__eglMustCastToProperFunctionPointerType)&eglSetDamageRegionKHR },
};
/*
@@ -1021,7 +1032,8 @@
Mutex mMutex;
};
-EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface draw)
+EGLBoolean eglSwapBuffersWithDamageKHR(EGLDisplay dpy, EGLSurface draw,
+ EGLint *rects, EGLint n_rects)
{
ATRACE_CALL();
clearError();
@@ -1080,7 +1092,38 @@
}
}
- return s->cnx->egl.eglSwapBuffers(dp->disp.dpy, s->surface);
+ if (n_rects == 0) {
+ return s->cnx->egl.eglSwapBuffers(dp->disp.dpy, s->surface);
+ }
+
+ Vector<android_native_rect_t> androidRects;
+ for (int r = 0; r < n_rects; ++r) {
+ int offset = r * 4;
+ int x = rects[offset];
+ int y = rects[offset + 1];
+ int width = rects[offset + 2];
+ int height = rects[offset + 3];
+ android_native_rect_t androidRect;
+ androidRect.left = x;
+ androidRect.top = y + height;
+ androidRect.right = x + width;
+ androidRect.bottom = y;
+ androidRects.push_back(androidRect);
+ }
+ native_window_set_surface_damage(s->win.get(), androidRects.array(),
+ androidRects.size());
+
+ if (s->cnx->egl.eglSwapBuffersWithDamageKHR) {
+ return s->cnx->egl.eglSwapBuffersWithDamageKHR(dp->disp.dpy, s->surface,
+ rects, n_rects);
+ } else {
+ return s->cnx->egl.eglSwapBuffers(dp->disp.dpy, s->surface);
+ }
+}
+
+EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface surface)
+{
+ return eglSwapBuffersWithDamageKHR(dpy, surface, NULL, 0);
}
EGLBoolean eglCopyBuffers( EGLDisplay dpy, EGLSurface surface,
@@ -1569,3 +1612,32 @@
return setErrorQuiet(EGL_BAD_DISPLAY, 0);
}
+
+// ----------------------------------------------------------------------------
+// Partial update extension
+// ----------------------------------------------------------------------------
+EGLBoolean eglSetDamageRegionKHR(EGLDisplay dpy, EGLSurface surface,
+ EGLint *rects, EGLint n_rects)
+{
+ clearError();
+
+ const egl_display_ptr dp = validate_display(dpy);
+ if (!dp) {
+ setError(EGL_BAD_DISPLAY, EGL_FALSE);
+ return EGL_FALSE;
+ }
+
+ SurfaceRef _s(dp.get(), surface);
+ if (!_s.get()) {
+ setError(EGL_BAD_SURFACE, EGL_FALSE);
+ return EGL_FALSE;
+ }
+
+ egl_surface_t const * const s = get_surface(surface);
+ if (s->cnx->egl.eglSetDamageRegionKHR) {
+ return s->cnx->egl.eglSetDamageRegionKHR(dp->disp.dpy, s->surface,
+ rects, n_rects);
+ }
+
+ return EGL_FALSE;
+}
diff --git a/opengl/libs/EGL/egl_entries.in b/opengl/libs/EGL/egl_entries.in
index 70d0e52..1e27cb6 100644
--- a/opengl/libs/EGL/egl_entries.in
+++ b/opengl/libs/EGL/egl_entries.in
@@ -89,4 +89,9 @@
/* IMG extensions */
EGL_ENTRY(EGLBoolean, eglHibernateProcessIMG, void)
-EGL_ENTRY(EGLBoolean, eglAwakenProcessIMG, void)
\ No newline at end of file
+EGL_ENTRY(EGLBoolean, eglAwakenProcessIMG, void)
+
+/* Partial update extensions */
+
+EGL_ENTRY(EGLBoolean, eglSwapBuffersWithDamageKHR, EGLDisplay, EGLSurface, EGLint *, EGLint)
+EGL_ENTRY(EGLBoolean, eglSetDamageRegionKHR, EGLDisplay, EGLSurface, EGLint *, EGLint)
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 77a9a19..c8b36ec 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -1020,6 +1020,21 @@
SharedBuffer const* sb = reg.getSharedBuffer(&visibleRegion.numRects);
visibleRegion.rects = reinterpret_cast<hwc_rect_t const *>(sb->data());
}
+ virtual void setSurfaceDamage(const Region& reg) {
+ if (!hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_5)) {
+ return;
+ }
+ hwc_region_t& surfaceDamage = getLayer()->surfaceDamage;
+ // We encode default full-screen damage as INVALID_RECT upstream, but as
+ // 0 rects for HWComposer
+ if (reg.isRect() && reg.getBounds() == Rect::INVALID_RECT) {
+ surfaceDamage.numRects = 0;
+ surfaceDamage.rects = NULL;
+ return;
+ }
+ SharedBuffer const* sb = reg.getSharedBuffer(&surfaceDamage.numRects);
+ surfaceDamage.rects = reinterpret_cast<hwc_rect_t const *>(sb->data());
+ }
virtual void setSidebandStream(const sp<NativeHandle>& stream) {
ALOG_ASSERT(stream->handle() != NULL);
getLayer()->compositionType = HWC_SIDEBAND;
@@ -1050,6 +1065,18 @@
}
getLayer()->acquireFenceFd = -1;
+
+ if (!hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_5)) {
+ return;
+ }
+
+ hwc_region_t& surfaceDamage = getLayer()->surfaceDamage;
+ sb = SharedBuffer::bufferFromData(surfaceDamage.rects);
+ if (sb) {
+ sb->release();
+ surfaceDamage.numRects = 0;
+ surfaceDamage.rects = NULL;
+ }
}
};
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index a62ac5c..28d8c65 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -168,6 +168,7 @@
virtual void setFrame(const Rect& frame) = 0;
virtual void setCrop(const FloatRect& crop) = 0;
virtual void setVisibleRegionScreen(const Region& reg) = 0;
+ virtual void setSurfaceDamage(const Region& reg) = 0;
virtual void setSidebandStream(const sp<NativeHandle>& stream) = 0;
virtual void setBuffer(const sp<GraphicBuffer>& buffer) = 0;
virtual void setAcquireFenceFd(int fenceFd) = 0;
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
index 0e94f0d..11cbdc6 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
@@ -526,6 +526,10 @@
// TODO: Should we actually allocate buffers for a virtual display?
}
+status_t VirtualDisplaySurface::allowAllocation(bool /* allow */) {
+ return INVALID_OPERATION;
+}
+
void VirtualDisplaySurface::updateQueueBufferOutput(
const QueueBufferOutput& qbo) {
uint32_t w, h, transformHint, numPendingBuffers;
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
index 0a3f4a1..97af980 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
@@ -115,6 +115,7 @@
virtual status_t setSidebandStream(const sp<NativeHandle>& stream);
virtual void allocateBuffers(bool async, uint32_t width, uint32_t height,
PixelFormat format, uint32_t usage);
+ virtual status_t allowAllocation(bool allow);
//
// Utility methods
diff --git a/services/surfaceflinger/EventThread.cpp b/services/surfaceflinger/EventThread.cpp
index 9b6360e..f760200 100644
--- a/services/surfaceflinger/EventThread.cpp
+++ b/services/surfaceflinger/EventThread.cpp
@@ -71,6 +71,11 @@
mVsyncHintSent = false;
}
+void EventThread::setPhaseOffset(nsecs_t phaseOffset) {
+ Mutex::Autolock _l(mLock);
+ mVSyncSource->setPhaseOffset(phaseOffset);
+}
+
void EventThread::sendVsyncHintOnLocked() {
struct itimerspec ts;
if(!mVsyncHintSent) {
diff --git a/services/surfaceflinger/EventThread.h b/services/surfaceflinger/EventThread.h
index d1c4fcd..9ba179a 100644
--- a/services/surfaceflinger/EventThread.h
+++ b/services/surfaceflinger/EventThread.h
@@ -51,6 +51,7 @@
virtual ~VSyncSource() {}
virtual void setVSyncEnabled(bool enable) = 0;
virtual void setCallback(const sp<Callback>& callback) = 0;
+ virtual void setPhaseOffset(nsecs_t phaseOffset) = 0;
};
class EventThread : public Thread, private VSyncSource::Callback {
@@ -99,6 +100,8 @@
void dump(String8& result) const;
void sendVsyncHintOff();
+ void setPhaseOffset(nsecs_t phaseOffset);
+
private:
virtual bool threadLoop();
virtual void onFirstRef();
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 2ac4765..2944c63 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -513,6 +513,16 @@
Region visible = tr.transform(visibleRegion.intersect(hw->getViewport()));
layer.setVisibleRegionScreen(visible);
+ // Pass full-surface damage down untouched
+ if (surfaceDamageRegion.isRect() &&
+ surfaceDamageRegion.getBounds() == Rect::INVALID_RECT) {
+ layer.setSurfaceDamage(surfaceDamageRegion);
+ } else {
+ Region surfaceDamage =
+ tr.transform(surfaceDamageRegion.intersect(hw->getViewport()));
+ layer.setSurfaceDamage(surfaceDamage);
+ }
+
if (mSidebandStream.get()) {
layer.setSidebandStream(mSidebandStream);
} else {
@@ -908,7 +918,7 @@
const bool resizePending = (c.requested.w != c.active.w) ||
(c.requested.h != c.active.h);
- if (resizePending) {
+ if (resizePending && mSidebandStream == NULL) {
// don't let Layer::doTransaction update the drawing state
// if we have a pending resize, unless we are in fixed-size mode.
// the drawing state will be updated only once we receive a buffer
@@ -917,6 +927,10 @@
// in particular, we want to make sure the clip (which is part
// of the geometry state) is latched together with the size but is
// latched immediately when no resizing is involved.
+ //
+ // If a sideband stream is attached, however, we want to skip this
+ // optimization so that transactions aren't missed when a buffer
+ // never arrives
flags |= eDontUpdateGeometryState;
}
@@ -1034,6 +1048,18 @@
return true;
}
+void Layer::useSurfaceDamage() {
+ if (mFlinger->mForceFullDamage) {
+ surfaceDamageRegion = Region::INVALID_REGION;
+ } else {
+ surfaceDamageRegion = mSurfaceFlingerConsumer->getSurfaceDamage();
+ }
+}
+
+void Layer::useEmptyDamage() {
+ surfaceDamageRegion.clear();
+}
+
// ----------------------------------------------------------------------------
// pageflip handling...
// ----------------------------------------------------------------------------
@@ -1349,6 +1375,7 @@
s.activeTransparentRegion.dump(result, "transparentRegion");
visibleRegion.dump(result, "visibleRegion");
+ surfaceDamageRegion.dump(result, "surfaceDamageRegion");
sp<Client> client(mClientRef.promote());
result.appendFormat( " "
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 424c03e..46c17e5 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -76,6 +76,7 @@
Region visibleRegion;
Region coveredRegion;
Region visibleNonTransparentRegion;
+ Region surfaceDamageRegion;
// Layer serial number. This gives layers an explicit ordering, so we
// have a stable sort order when their layer stack and Z-order are
@@ -137,6 +138,12 @@
bool setCrop(const Rect& crop);
bool setLayerStack(uint32_t layerStack);
+ // If we have received a new buffer this frame, we will pass its surface
+ // damage down to hardware composer. Otherwise, we must send a region with
+ // one empty rect.
+ void useSurfaceDamage();
+ void useEmptyDamage();
+
uint32_t getTransactionFlags(uint32_t flags);
uint32_t setTransactionFlags(uint32_t flags);
diff --git a/services/surfaceflinger/MonitoredProducer.cpp b/services/surfaceflinger/MonitoredProducer.cpp
index e4e7d42..9fb555b 100644
--- a/services/surfaceflinger/MonitoredProducer.cpp
+++ b/services/surfaceflinger/MonitoredProducer.cpp
@@ -110,6 +110,10 @@
mProducer->allocateBuffers(async, width, height, format, usage);
}
+status_t MonitoredProducer::allowAllocation(bool allow) {
+ return mProducer->allowAllocation(allow);
+}
+
IBinder* MonitoredProducer::onAsBinder() {
return IInterface::asBinder(mProducer).get();
}
diff --git a/services/surfaceflinger/MonitoredProducer.h b/services/surfaceflinger/MonitoredProducer.h
index aec3e85..b2f8293 100644
--- a/services/surfaceflinger/MonitoredProducer.h
+++ b/services/surfaceflinger/MonitoredProducer.h
@@ -53,6 +53,7 @@
virtual status_t setSidebandStream(const sp<NativeHandle>& stream);
virtual void allocateBuffers(bool async, uint32_t width, uint32_t height,
PixelFormat format, uint32_t usage);
+ virtual status_t allowAllocation(bool allow);
virtual IBinder* onAsBinder();
private:
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 9dc140e..df4ac2e 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -145,6 +145,7 @@
mDebugInTransaction(0),
mLastTransactionTime(0),
mBootFinished(false),
+ mForceFullDamage(false),
mPrimaryHWVsyncEnabled(false),
mHWVsyncAvailable(false),
mDaltonize(false),
@@ -319,17 +320,20 @@
DispSyncSource(DispSync* dispSync, nsecs_t phaseOffset, bool traceVsync,
const char* label) :
mValue(0),
- mPhaseOffset(phaseOffset),
mTraceVsync(traceVsync),
mVsyncOnLabel(String8::format("VsyncOn-%s", label)),
mVsyncEventLabel(String8::format("VSYNC-%s", label)),
- mDispSync(dispSync) {}
+ mDispSync(dispSync),
+ mCallbackMutex(),
+ mCallback(),
+ mVsyncMutex(),
+ mPhaseOffset(phaseOffset),
+ mEnabled(false) {}
virtual ~DispSyncSource() {}
virtual void setVSyncEnabled(bool enable) {
- // Do NOT lock the mutex here so as to avoid any mutex ordering issues
- // with locking it in the onDispSyncEvent callback.
+ Mutex::Autolock lock(mVsyncMutex);
if (enable) {
status_t err = mDispSync->addEventListener(mPhaseOffset,
static_cast<DispSync::Callback*>(this));
@@ -347,18 +351,54 @@
}
//ATRACE_INT(mVsyncOnLabel.string(), 0);
}
+ mEnabled = enable;
}
virtual void setCallback(const sp<VSyncSource::Callback>& callback) {
- Mutex::Autolock lock(mMutex);
+ Mutex::Autolock lock(mCallbackMutex);
mCallback = callback;
}
+ virtual void setPhaseOffset(nsecs_t phaseOffset) {
+ Mutex::Autolock lock(mVsyncMutex);
+
+ // Normalize phaseOffset to [0, period)
+ auto period = mDispSync->getPeriod();
+ phaseOffset %= period;
+ if (phaseOffset < 0) {
+ // If we're here, then phaseOffset is in (-period, 0). After this
+ // operation, it will be in (0, period)
+ phaseOffset += period;
+ }
+ mPhaseOffset = phaseOffset;
+
+ // If we're not enabled, we don't need to mess with the listeners
+ if (!mEnabled) {
+ return;
+ }
+
+ // Remove the listener with the old offset
+ status_t err = mDispSync->removeEventListener(
+ static_cast<DispSync::Callback*>(this));
+ if (err != NO_ERROR) {
+ ALOGE("error unregistering vsync callback: %s (%d)",
+ strerror(-err), err);
+ }
+
+ // Add a listener with the new offset
+ err = mDispSync->addEventListener(mPhaseOffset,
+ static_cast<DispSync::Callback*>(this));
+ if (err != NO_ERROR) {
+ ALOGE("error registering vsync callback: %s (%d)",
+ strerror(-err), err);
+ }
+ }
+
private:
virtual void onDispSyncEvent(nsecs_t when) {
sp<VSyncSource::Callback> callback;
{
- Mutex::Autolock lock(mMutex);
+ Mutex::Autolock lock(mCallbackMutex);
callback = mCallback;
if (mTraceVsync) {
@@ -374,14 +414,18 @@
int mValue;
- const nsecs_t mPhaseOffset;
const bool mTraceVsync;
const String8 mVsyncOnLabel;
const String8 mVsyncEventLabel;
DispSync* mDispSync;
+
+ Mutex mCallbackMutex; // Protects the following
sp<VSyncSource::Callback> mCallback;
- Mutex mMutex;
+
+ Mutex mVsyncMutex; // Protects the following
+ nsecs_t mPhaseOffset;
+ bool mEnabled;
};
void SurfaceFlinger::init() {
@@ -1725,12 +1769,17 @@
frameQueued = true;
if (layer->shouldPresentNow(mPrimaryDispSync)) {
layersWithQueuedFrames.push_back(layer.get());
+ } else {
+ layer->useEmptyDamage();
}
+ } else {
+ layer->useEmptyDamage();
}
}
for (size_t i = 0, count = layersWithQueuedFrames.size() ; i<count ; i++) {
Layer* layer = layersWithQueuedFrames[i];
const Region dirty(layer->latchBuffer(visibleRegions));
+ layer->useSurfaceDamage();
const Layer::State& s(layer->getDrawingState());
invalidateLayerStack(s.layerStack, dirty);
}
@@ -2876,6 +2925,21 @@
mPrimaryDispSync.setRefreshSkipCount(n);
return NO_ERROR;
}
+ case 1017: {
+ n = data.readInt32();
+ mForceFullDamage = static_cast<bool>(n);
+ return NO_ERROR;
+ }
+ case 1018: { // Modify Choreographer's phase offset
+ n = data.readInt32();
+ mEventThread->setPhaseOffset(static_cast<nsecs_t>(n));
+ return NO_ERROR;
+ }
+ case 1019: { // Modify SurfaceFlinger's phase offset
+ n = data.readInt32();
+ mSFEventThread->setPhaseOffset(static_cast<nsecs_t>(n));
+ return NO_ERROR;
+ }
}
}
return err;
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 4deb815..a06d1be 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -469,6 +469,7 @@
volatile nsecs_t mDebugInTransaction;
nsecs_t mLastTransactionTime;
bool mBootFinished;
+ bool mForceFullDamage;
// these are thread safe
mutable MessageQueue mEventQueue;
diff --git a/services/surfaceflinger/SurfaceFlingerConsumer.cpp b/services/surfaceflinger/SurfaceFlingerConsumer.cpp
index abf3993..19c497a 100644
--- a/services/surfaceflinger/SurfaceFlingerConsumer.cpp
+++ b/services/surfaceflinger/SurfaceFlingerConsumer.cpp
@@ -108,6 +108,7 @@
status_t result = GLConsumer::acquireBufferLocked(item, presentWhen);
if (result == NO_ERROR) {
mTransformToDisplayInverse = item->mTransformToDisplayInverse;
+ mSurfaceDamage = item->mSurfaceDamage;
}
return result;
}
@@ -116,6 +117,10 @@
return mTransformToDisplayInverse;
}
+const Region& SurfaceFlingerConsumer::getSurfaceDamage() const {
+ return mSurfaceDamage;
+}
+
sp<NativeHandle> SurfaceFlingerConsumer::getSidebandStream() const {
return mConsumer->getSidebandStream();
}
diff --git a/services/surfaceflinger/SurfaceFlingerConsumer.h b/services/surfaceflinger/SurfaceFlingerConsumer.h
index d1cf9b9..1aaba18 100644
--- a/services/surfaceflinger/SurfaceFlingerConsumer.h
+++ b/services/surfaceflinger/SurfaceFlingerConsumer.h
@@ -35,7 +35,7 @@
SurfaceFlingerConsumer(const sp<IGraphicBufferConsumer>& consumer,
uint32_t tex)
: GLConsumer(consumer, tex, GLConsumer::TEXTURE_EXTERNAL, false, false),
- mTransformToDisplayInverse(false)
+ mTransformToDisplayInverse(false), mSurfaceDamage()
{}
class BufferRejecter {
@@ -60,6 +60,7 @@
// must be called from SF main thread
bool getTransformToDisplayInverse() const;
+ const Region& getSurfaceDamage() const;
// Sets the contents changed listener. This should be used instead of
// ConsumerBase::setFrameAvailableListener().
@@ -78,6 +79,9 @@
// it is displayed onto. This is applied after GLConsumer::mCurrentTransform.
// This must be set/read from SurfaceFlinger's main thread.
bool mTransformToDisplayInverse;
+
+ // The portion of this surface that has changed since the previous frame
+ Region mSurfaceDamage;
};
// ----------------------------------------------------------------------------