Merge "am e06cba2..e06cba2 from mirror-m-wireless-internal-release"
diff --git a/include/binder/IPCThreadState.h b/include/binder/IPCThreadState.h
index 60c2242..1853cff 100644
--- a/include/binder/IPCThreadState.h
+++ b/include/binder/IPCThreadState.h
@@ -76,14 +76,18 @@
BpBinder* proxy);
static void shutdown();
-
+
// Call this to disable switching threads to background scheduling when
// receiving incoming IPC calls. This is specifically here for the
// Android system process, since it expects to have background apps calling
// in to it but doesn't want to acquire locks in its services while in
// the background.
static void disableBackgroundScheduling(bool disable);
-
+
+ // Call blocks until the number of executing binder threads is less than
+ // the maximum number of binder threads threads allowed for this process.
+ void blockUntilThreadAvailable();
+
private:
IPCThreadState();
~IPCThreadState();
@@ -101,9 +105,9 @@
status_t getAndExecuteCommand();
status_t executeCommand(int32_t command);
void processPendingDerefs();
-
+
void clearCaller();
-
+
static void threadDestructor(void *st);
static void freeBuffer(Parcel* parcel,
const uint8_t* data, size_t dataSize,
@@ -114,7 +118,7 @@
const pid_t mMyThreadId;
Vector<BBinder*> mPendingStrongDerefs;
Vector<RefBase::weakref_type*> mPendingWeakDerefs;
-
+
Parcel mIn;
Parcel mOut;
status_t mLastError;
diff --git a/include/binder/ProcessState.h b/include/binder/ProcessState.h
index 3bc978d..f9edc2a 100644
--- a/include/binder/ProcessState.h
+++ b/include/binder/ProcessState.h
@@ -24,6 +24,8 @@
#include <utils/threads.h>
+#include <pthread.h>
+
// ---------------------------------------------------------------------------
namespace android {
@@ -71,25 +73,33 @@
ProcessState(const ProcessState& o);
ProcessState& operator=(const ProcessState& o);
String8 makeBinderThreadName();
-
+
struct handle_entry {
IBinder* binder;
RefBase::weakref_type* refs;
};
-
+
handle_entry* lookupHandleLocked(int32_t handle);
int mDriverFD;
void* mVMStart;
-
+
+ // Protects thread count variable below.
+ pthread_mutex_t mThreadCountLock;
+ pthread_cond_t mThreadCountDecrement;
+ // Number of binder threads current executing a command.
+ size_t mExecutingThreadsCount;
+ // Maximum number for binder threads allowed for this process.
+ size_t mMaxThreads;
+
mutable Mutex mLock; // protects everything below.
-
+
Vector<handle_entry>mHandleToObject;
bool mManagesContexts;
context_check_func mBinderContextCheckFunc;
void* mBinderContextUserData;
-
+
KeyedVector<String16, sp<IBinder> >
mContexts;
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/IGraphicBufferProducer.h b/include/gui/IGraphicBufferProducer.h
index 374245a..2d99f24 100644
--- a/include/gui/IGraphicBufferProducer.h
+++ b/include/gui/IGraphicBufferProducer.h
@@ -28,6 +28,7 @@
#include <ui/Fence.h>
#include <ui/GraphicBuffer.h>
#include <ui/Rect.h>
+#include <ui/Region.h>
namespace android {
// ----------------------------------------------------------------------------
@@ -281,7 +282,7 @@
: 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
diff --git a/include/gui/Surface.h b/include/gui/Surface.h
index e973483..8217652 100644
--- a/include/gui/Surface.h
+++ b/include/gui/Surface.h
@@ -147,6 +147,7 @@
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
+ // In the lock/unlock context, this reflects the region that the producer
+ // wished to update and whether the Surface was able to copy the previous
+ // buffer back to allow a partial update.
+ //
+ // In the dequeue/queue context, this reflects the surface damage (the
+ // damage since the last frame) passed in by the producer.
Region mDirtyRegion;
};
diff --git a/include/ui/Rect.h b/include/ui/Rect.h
index 40d1166..3886f93 100644
--- a/include/ui/Rect.h
+++ b/include/ui/Rect.h
@@ -31,6 +31,8 @@
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/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp
index 9f68aa8..2baf474 100644
--- a/libs/binder/IPCThreadState.cpp
+++ b/libs/binder/IPCThreadState.cpp
@@ -399,6 +399,17 @@
talkWithDriver(false);
}
+void IPCThreadState::blockUntilThreadAvailable()
+{
+ pthread_mutex_lock(&mProcess->mThreadCountLock);
+ while (mProcess->mExecutingThreadsCount >= mProcess->mMaxThreads) {
+ ALOGW("Waiting for thread to be free. mExecutingThreadsCount=%i mMaxThreads=%i\n",
+ mProcess->mExecutingThreadsCount, mProcess->mMaxThreads);
+ pthread_cond_wait(&mProcess->mThreadCountDecrement, &mProcess->mThreadCountLock);
+ }
+ pthread_mutex_unlock(&mProcess->mThreadCountLock);
+}
+
status_t IPCThreadState::getAndExecuteCommand()
{
status_t result;
@@ -414,8 +425,17 @@
<< getReturnString(cmd) << endl;
}
+ pthread_mutex_lock(&mProcess->mThreadCountLock);
+ mProcess->mExecutingThreadsCount++;
+ pthread_mutex_unlock(&mProcess->mThreadCountLock);
+
result = executeCommand(cmd);
+ pthread_mutex_lock(&mProcess->mThreadCountLock);
+ mProcess->mExecutingThreadsCount--;
+ pthread_cond_broadcast(&mProcess->mThreadCountDecrement);
+ pthread_mutex_unlock(&mProcess->mThreadCountLock);
+
// After executing the command, ensure that the thread is returned to the
// foreground cgroup before rejoining the pool. The driver takes care of
// restoring the priority, but doesn't do anything with cgroups so we
diff --git a/libs/binder/ProcessState.cpp b/libs/binder/ProcessState.cpp
index 303d6cf..016d3c5 100644
--- a/libs/binder/ProcessState.cpp
+++ b/libs/binder/ProcessState.cpp
@@ -42,12 +42,13 @@
#include <sys/stat.h>
#define BINDER_VM_SIZE ((1*1024*1024) - (4096 *2))
+#define DEFAULT_MAX_BINDER_THREADS 15
// ---------------------------------------------------------------------------
namespace android {
-
+
class PoolThread : public Thread
{
public:
@@ -294,7 +295,9 @@
status_t ProcessState::setThreadPoolMaxThreadCount(size_t maxThreads) {
status_t result = NO_ERROR;
- if (ioctl(mDriverFD, BINDER_SET_MAX_THREADS, &maxThreads) == -1) {
+ if (ioctl(mDriverFD, BINDER_SET_MAX_THREADS, &maxThreads) != -1) {
+ mMaxThreads = maxThreads;
+ } else {
result = -errno;
ALOGE("Binder ioctl to set max threads failed: %s", strerror(-result));
}
@@ -322,7 +325,7 @@
close(fd);
fd = -1;
}
- size_t maxThreads = 15;
+ size_t maxThreads = DEFAULT_MAX_BINDER_THREADS;
result = ioctl(fd, BINDER_SET_MAX_THREADS, &maxThreads);
if (result == -1) {
ALOGE("Binder ioctl to set max threads failed: %s", strerror(errno));
@@ -336,6 +339,10 @@
ProcessState::ProcessState()
: mDriverFD(open_driver())
, mVMStart(MAP_FAILED)
+ , mThreadCountLock(PTHREAD_MUTEX_INITIALIZER)
+ , mThreadCountDecrement(PTHREAD_COND_INITIALIZER)
+ , mExecutingThreadsCount(0)
+ , mMaxThreads(DEFAULT_MAX_BINDER_THREADS)
, mManagesContexts(false)
, mBinderContextCheckFunc(NULL)
, mBinderContextUserData(NULL)
diff --git a/libs/gui/BufferItem.cpp b/libs/gui/BufferItem.cpp
index 312fb3b..239da20 100644
--- a/libs/gui/BufferItem.cpp
+++ b/libs/gui/BufferItem.cpp
@@ -64,6 +64,8 @@
c += mFence->getFlattenedSize();
FlattenableUtils::align<4>(c);
}
+ c += mSurfaceDamage.getFlattenedSize();
+ FlattenableUtils::align<4>(c);
return sizeof(int32_t) + c + getPodSize();
}
@@ -105,6 +107,9 @@
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 @@
if (err) return err;
size -= FlattenableUtils::align<4>(buffer);
}
+ status_t err = mSurfaceDamage.unflatten(buffer, size);
+ if (err) return err;
+ size -= FlattenableUtils::align<4>(buffer);
// check we have enough space
if (size < getPodSize()) {
diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
index 4c22ba3..6452cdd 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -525,6 +525,7 @@
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 @@
item.mSlot = slot;
item.mFence = fence;
item.mIsDroppable = mCore->mDequeueBufferCannotBlock || async;
+ item.mSurfaceDamage = surfaceDamage;
mStickyTransform = stickyTransform;
diff --git a/libs/gui/IGraphicBufferProducer.cpp b/libs/gui/IGraphicBufferProducer.cpp
index a3e6fb2..b7982a9 100644
--- a/libs/gui/IGraphicBufferProducer.cpp
+++ b/libs/gui/IGraphicBufferProducer.cpp
@@ -446,7 +446,8 @@
+ sizeof(transform)
+ sizeof(stickyTransform)
+ sizeof(async)
- + fence->getFlattenedSize();
+ + fence->getFlattenedSize()
+ + surfaceDamage.getFlattenedSize();
}
size_t IGraphicBufferProducer::QueueBufferInput::getFdCount() const {
@@ -467,7 +468,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 +502,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..245f7a3 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -27,6 +27,7 @@
#include <utils/NativeHandle.h>
#include <ui/Fence.h>
+#include <ui/Region.h>
#include <gui/IProducerListener.h>
#include <gui/ISurfaceComposer.h>
@@ -320,6 +321,25 @@
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 @@
mConsumerRunningBehind = (numPendingBuffers >= 2);
+ // Clear surface damage back to full-buffer
+ mDirtyRegion = Region::INVALID_REGION;
+
return err;
}
@@ -453,6 +476,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 +582,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 +615,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 +839,27 @@
}
}
+void Surface::setSurfaceDamage(android_native_rect_t* rects, size_t numRects) {
+ ATRACE_CALL();
+ ALOGV("Surface::setSurfaceDamage");
+ Mutex::Autolock lock(mMutex);
+
+ if (numRects == 0) {
+ mDirtyRegion = Region::INVALID_REGION;
+ return;
+ }
+
+ mDirtyRegion.clear();
+ for (size_t r = 0; r < numRects; ++r) {
+ // We intentionally flip top and bottom here, since because they're
+ // specified with a bottom-left origin, top > bottom, which fails
+ // validation in the Region class. We will fix this up when we flip to a
+ // top-left origin in queueBuffer.
+ Rect rect(rects[r].left, rects[r].bottom, rects[r].right, rects[r].top);
+ mDirtyRegion.orSelf(rect);
+ }
+}
+
// ----------------------------------------------------------------------
// the lock/unlock APIs must be used from the same thread
diff --git a/libs/ui/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/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 53ef193..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() {
@@ -517,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);
@@ -690,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;
@@ -753,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/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..7bb7529 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 {
@@ -1034,6 +1044,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 +1371,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/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 69550b8..1419557 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),
@@ -323,17 +324,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));
@@ -351,18 +355,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) {
@@ -378,14 +418,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() {
@@ -1749,12 +1793,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);
}
@@ -2930,6 +2979,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 34f0aaa..d2654d4 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -471,6 +471,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;
};
// ----------------------------------------------------------------------------