Merge "b/5080166 Enalbe multi-touch on external touch escreen."
diff --git a/include/gui/ISurfaceTexture.h b/include/gui/ISurfaceTexture.h
index 1eda646..50626a0 100644
--- a/include/gui/ISurfaceTexture.h
+++ b/include/gui/ISurfaceTexture.h
@@ -111,7 +111,12 @@
//
// This method will fail if the connect was previously called on the
// SurfaceTexture and no corresponding disconnect call was made.
- virtual status_t connect(int api) = 0;
+ //
+ // outWidth, outHeight and outTransform are filled with the default width
+ // and height of the window and current transform applied to buffers,
+ // respectively.
+ virtual status_t connect(int api,
+ uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransform) = 0;
// disconnect attempts to disconnect a client API from the SurfaceTexture.
// Calling this method will cause any subsequent calls to other
diff --git a/include/gui/SurfaceTexture.h b/include/gui/SurfaceTexture.h
index 2a8e725..a6fb12e 100644
--- a/include/gui/SurfaceTexture.h
+++ b/include/gui/SurfaceTexture.h
@@ -106,7 +106,8 @@
//
// This method will fail if the connect was previously called on the
// SurfaceTexture and no corresponding disconnect call was made.
- virtual status_t connect(int api);
+ virtual status_t connect(int api,
+ uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransform);
// disconnect attempts to disconnect a client API from the SurfaceTexture.
// Calling this method will cause any subsequent calls to other
@@ -207,9 +208,28 @@
protected:
- // freeAllBuffers frees the resources (both GraphicBuffer and EGLImage) for
- // all slots.
- void freeAllBuffers();
+ // freeBufferLocked frees the resources (both GraphicBuffer and EGLImage)
+ // for the given slot.
+ void freeBufferLocked(int index);
+
+ // freeAllBuffersLocked frees the resources (both GraphicBuffer and
+ // EGLImage) for all slots.
+ void freeAllBuffersLocked();
+
+ // freeAllBuffersExceptHeadLocked frees the resources (both GraphicBuffer
+ // and EGLImage) for all slots except the head of mQueue
+ void freeAllBuffersExceptHeadLocked();
+
+ // drainQueueLocked drains the buffer queue if we're in synchronous mode
+ // returns immediately otherwise. return NO_INIT if SurfaceTexture
+ // became abandoned or disconnected during this call.
+ status_t drainQueueLocked();
+
+ // drainQueueAndFreeBuffersLocked drains the buffer queue if we're in
+ // synchronous mode and free all buffers. In asynchronous mode, all buffers
+ // are freed except the current buffer.
+ status_t drainQueueAndFreeBuffersLocked();
+
static bool isExternalFormat(uint32_t format);
private:
diff --git a/include/ui/Input.h b/include/ui/Input.h
index c9f694a..f1385a0 100644
--- a/include/ui/Input.h
+++ b/include/ui/Input.h
@@ -206,10 +206,17 @@
float getAxisValue(int32_t axis) const;
status_t setAxisValue(int32_t axis, float value);
- float* editAxisValue(int32_t axis);
void scale(float scale);
+ inline float getX() const {
+ return getAxisValue(AMOTION_EVENT_AXIS_X);
+ }
+
+ inline float getY() const {
+ return getAxisValue(AMOTION_EVENT_AXIS_Y);
+ }
+
#ifdef HAVE_ANDROID_OS
status_t readFromParcel(Parcel* parcel);
status_t writeToParcel(Parcel* parcel) const;
diff --git a/include/utils/BitSet.h b/include/utils/BitSet.h
index 600017e..9452e86 100644
--- a/include/utils/BitSet.h
+++ b/include/utils/BitSet.h
@@ -68,6 +68,30 @@
// Result is undefined if all bits are unmarked.
inline uint32_t lastMarkedBit() const { return 31 - __builtin_ctz(value); }
+ // Finds the first marked bit in the set and clears it. Returns the bit index.
+ // Result is undefined if all bits are unmarked.
+ inline uint32_t clearFirstMarkedBit() {
+ uint32_t n = firstMarkedBit();
+ clearBit(n);
+ return n;
+ }
+
+ // Finds the first unmarked bit in the set and marks it. Returns the bit index.
+ // Result is undefined if all bits are marked.
+ inline uint32_t markFirstUnmarkedBit() {
+ uint32_t n = firstUnmarkedBit();
+ markBit(n);
+ return n;
+ }
+
+ // Finds the last marked bit in the set and clears it. Returns the bit index.
+ // Result is undefined if all bits are unmarked.
+ inline uint32_t clearLastMarkedBit() {
+ uint32_t n = lastMarkedBit();
+ clearBit(n);
+ return n;
+ }
+
// Gets the index of the specified bit in the set, which is the number of
// marked bits that appear before the specified bit.
inline uint32_t getIndexOfBit(uint32_t n) const {
diff --git a/include/utils/RefBase.h b/include/utils/RefBase.h
index ca17082..c7a9b78 100644
--- a/include/utils/RefBase.h
+++ b/include/utils/RefBase.h
@@ -80,9 +80,12 @@
void incWeak(const void* id);
void decWeak(const void* id);
+ // acquires a strong reference if there is already one.
bool attemptIncStrong(const void* id);
- //! This is only safe if you have set OBJECT_LIFETIME_FOREVER.
+ // acquires a weak reference if there is already one.
+ // This is not always safe. see ProcessState.cpp and BpBinder.cpp
+ // for proper use.
bool attemptIncWeak(const void* id);
//! DEBUGGING ONLY: Get current weak ref count.
@@ -116,28 +119,15 @@
typedef RefBase basetype;
- // used to override the RefBase destruction.
- class Destroyer {
- friend class RefBase;
- friend class weakref_type;
- public:
- virtual ~Destroyer();
- private:
- virtual void destroy(RefBase const* base) = 0;
- };
-
- // Make sure to never acquire a strong reference from this function. The
- // same restrictions than for destructors apply.
- void setDestroyer(Destroyer* destroyer);
-
protected:
RefBase();
virtual ~RefBase();
//! Flags for extendObjectLifetime()
enum {
+ OBJECT_LIFETIME_STRONG = 0x0000,
OBJECT_LIFETIME_WEAK = 0x0001,
- OBJECT_LIFETIME_FOREVER = 0x0003
+ OBJECT_LIFETIME_MASK = 0x0001
};
void extendObjectLifetime(int32_t mode);
@@ -163,7 +153,7 @@
RefBase(const RefBase& o);
RefBase& operator=(const RefBase& o);
-
+
weakref_impl* const mRefs;
};
diff --git a/include/utils/ZipFileRO.h b/include/utils/ZipFileRO.h
index 3a99979..547e36a 100644
--- a/include/utils/ZipFileRO.h
+++ b/include/utils/ZipFileRO.h
@@ -38,6 +38,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
+#include <time.h>
namespace android {
@@ -174,6 +175,20 @@
size_t uncompLen, size_t compLen);
/*
+ * Utility function to convert ZIP's time format to a timespec struct.
+ */
+ static inline void zipTimeToTimespec(long when, struct tm* timespec) {
+ const long date = when >> 16;
+ timespec->tm_year = ((date >> 9) & 0x7F) + 80; // Zip is years since 1980
+ timespec->tm_mon = (date >> 5) & 0x0F;
+ timespec->tm_mday = date & 0x1F;
+
+ timespec->tm_hour = (when >> 11) & 0x1F;
+ timespec->tm_min = (when >> 5) & 0x3F;
+ timespec->tm_sec = (when & 0x1F) << 1;
+ }
+
+ /*
* Some basic functions for raw data manipulation. "LE" means
* Little Endian.
*/
diff --git a/include/utils/threads.h b/include/utils/threads.h
index c8e9c04..c84a9b4 100644
--- a/include/utils/threads.h
+++ b/include/utils/threads.h
@@ -20,6 +20,7 @@
#include <stdint.h>
#include <sys/types.h>
#include <time.h>
+#include <system/graphics.h>
#if defined(HAVE_PTHREADS)
# include <pthread.h>
@@ -42,8 +43,8 @@
* ** Keep in sync with android.os.Process.java **
* ***********************************************
*
- * This maps directly to the "nice" priorites we use in Android.
- * A thread priority should be chosen inverse-proportinally to
+ * This maps directly to the "nice" priorities we use in Android.
+ * A thread priority should be chosen inverse-proportionally to
* the amount of work the thread is expected to do. The more work
* a thread will do, the less favorable priority it should get so that
* it doesn't starve the system. Threads not behaving properly might
@@ -66,7 +67,7 @@
ANDROID_PRIORITY_DISPLAY = -4,
/* ui service treads might want to run at a urgent display (uncommon) */
- ANDROID_PRIORITY_URGENT_DISPLAY = -8,
+ ANDROID_PRIORITY_URGENT_DISPLAY = HAL_PRIORITY_URGENT_DISPLAY,
/* all normal audio threads */
ANDROID_PRIORITY_AUDIO = -16,
diff --git a/libs/gui/ISurfaceTexture.cpp b/libs/gui/ISurfaceTexture.cpp
index 55246dc..babd2c0 100644
--- a/libs/gui/ISurfaceTexture.cpp
+++ b/libs/gui/ISurfaceTexture.cpp
@@ -162,11 +162,15 @@
return result;
}
- virtual status_t connect(int api) {
+ virtual status_t connect(int api,
+ uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransform) {
Parcel data, reply;
data.writeInterfaceToken(ISurfaceTexture::getInterfaceDescriptor());
data.writeInt32(api);
remote()->transact(CONNECT, data, &reply);
+ *outWidth = reply.readInt32();
+ *outHeight = reply.readInt32();
+ *outTransform = reply.readInt32();
status_t result = reply.readInt32();
return result;
}
@@ -283,7 +287,12 @@
case CONNECT: {
CHECK_INTERFACE(ISurfaceTexture, data, reply);
int api = data.readInt32();
- status_t res = connect(api);
+ uint32_t outWidth, outHeight, outTransform;
+ status_t res = connect(api,
+ &outWidth, &outHeight, &outTransform);
+ reply->writeInt32(outWidth);
+ reply->writeInt32(outHeight);
+ reply->writeInt32(outTransform);
reply->writeInt32(res);
return NO_ERROR;
} break;
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index ccf98e5..2c70251 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -277,6 +277,11 @@
if (surface == 0) {
surface = new Surface(data, binder);
sCachedSurfaces.add(binder, surface);
+ } else {
+ // The Surface was found in the cache, but we still should clear any
+ // remaining data from the parcel.
+ data.readStrongBinder(); // ISurfaceTexture
+ data.readInt32(); // identity
}
if (surface->mSurface == NULL && surface->getISurfaceTexture() == NULL) {
surface = 0;
diff --git a/libs/gui/SurfaceTexture.cpp b/libs/gui/SurfaceTexture.cpp
index 16755ad..7ac4343 100644
--- a/libs/gui/SurfaceTexture.cpp
+++ b/libs/gui/SurfaceTexture.cpp
@@ -104,7 +104,7 @@
SurfaceTexture::~SurfaceTexture() {
LOGV("SurfaceTexture::~SurfaceTexture");
- freeAllBuffers();
+ freeAllBuffersLocked();
}
status_t SurfaceTexture::setBufferCountServerLocked(int bufferCount) {
@@ -154,7 +154,6 @@
LOGE("setBufferCount: SurfaceTexture has been abandoned!");
return NO_INIT;
}
-
if (bufferCount > NUM_BUFFER_SLOTS) {
LOGE("setBufferCount: bufferCount larger than slots available");
return BAD_VALUE;
@@ -168,24 +167,24 @@
}
}
+ const int minBufferSlots = mSynchronousMode ?
+ MIN_SYNC_BUFFER_SLOTS : MIN_ASYNC_BUFFER_SLOTS;
if (bufferCount == 0) {
- const int minBufferSlots = mSynchronousMode ?
- MIN_SYNC_BUFFER_SLOTS : MIN_ASYNC_BUFFER_SLOTS;
mClientBufferCount = 0;
bufferCount = (mServerBufferCount >= minBufferSlots) ?
mServerBufferCount : minBufferSlots;
return setBufferCountServerLocked(bufferCount);
}
- // We don't allow the client to set a buffer-count less than
- // MIN_ASYNC_BUFFER_SLOTS (3), there is no reason for it.
- if (bufferCount < MIN_ASYNC_BUFFER_SLOTS) {
+ if (bufferCount < minBufferSlots) {
+ LOGE("setBufferCount: requested buffer count (%d) is less than "
+ "minimum (%d)", bufferCount, minBufferSlots);
return BAD_VALUE;
}
// here we're guaranteed that the client doesn't have dequeued buffers
// and will release all of its buffer references.
- freeAllBuffers();
+ freeAllBuffersLocked();
mBufferCount = bufferCount;
mClientBufferCount = bufferCount;
mCurrentTexture = INVALID_BUFFER_SLOT;
@@ -228,11 +227,6 @@
uint32_t format, uint32_t usage) {
LOGV("SurfaceTexture::dequeueBuffer");
- if (mAbandoned) {
- LOGE("dequeueBuffer: SurfaceTexture has been abandoned!");
- return NO_INIT;
- }
-
if ((w && !h) || (!w && h)) {
LOGE("dequeueBuffer: invalid size: w=%u, h=%u", w, h);
return BAD_VALUE;
@@ -246,10 +240,15 @@
int dequeuedCount = 0;
bool tryAgain = true;
while (tryAgain) {
+ if (mAbandoned) {
+ LOGE("dequeueBuffer: SurfaceTexture has been abandoned!");
+ return NO_INIT;
+ }
+
// We need to wait for the FIFO to drain if the number of buffer
// needs to change.
//
- // The condition "number of buffer needs to change" is true if
+ // The condition "number of buffers needs to change" is true if
// - the client doesn't care about how many buffers there are
// - AND the actual number of buffer is different from what was
// set in the last setBufferCountServer()
@@ -261,31 +260,24 @@
// As long as this condition is true AND the FIFO is not empty, we
// wait on mDequeueCondition.
- int minBufferCountNeeded = mSynchronousMode ?
+ const int minBufferCountNeeded = mSynchronousMode ?
MIN_SYNC_BUFFER_SLOTS : MIN_ASYNC_BUFFER_SLOTS;
- if (!mClientBufferCount &&
+ const bool numberOfBuffersNeedsToChange = !mClientBufferCount &&
((mServerBufferCount != mBufferCount) ||
- (mServerBufferCount < minBufferCountNeeded))) {
+ (mServerBufferCount < minBufferCountNeeded));
+
+ if (!mQueue.isEmpty() && numberOfBuffersNeedsToChange) {
// wait for the FIFO to drain
- while (!mQueue.isEmpty()) {
- mDequeueCondition.wait(mMutex);
- if (mAbandoned) {
- LOGE("dequeueBuffer: SurfaceTexture was abandoned while "
- "blocked!");
- return NO_INIT;
- }
- }
- minBufferCountNeeded = mSynchronousMode ?
- MIN_SYNC_BUFFER_SLOTS : MIN_ASYNC_BUFFER_SLOTS;
+ mDequeueCondition.wait(mMutex);
+ // NOTE: we continue here because we need to reevaluate our
+ // whole state (eg: we could be abandoned or disconnected)
+ continue;
}
-
- if (!mClientBufferCount &&
- ((mServerBufferCount != mBufferCount) ||
- (mServerBufferCount < minBufferCountNeeded))) {
+ if (numberOfBuffersNeedsToChange) {
// here we're guaranteed that mQueue is empty
- freeAllBuffers();
+ freeAllBuffersLocked();
mBufferCount = mServerBufferCount;
if (mBufferCount < minBufferCountNeeded)
mBufferCount = minBufferCountNeeded;
@@ -414,9 +406,9 @@
if (!enabled) {
// going to asynchronous mode, drain the queue
- while (mSynchronousMode != enabled && !mQueue.isEmpty()) {
- mDequeueCondition.wait(mMutex);
- }
+ err = drainQueueLocked();
+ if (err != NO_ERROR)
+ return err;
}
if (mSynchronousMode != enabled) {
@@ -548,7 +540,8 @@
return OK;
}
-status_t SurfaceTexture::connect(int api) {
+status_t SurfaceTexture::connect(int api,
+ uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransform) {
LOGV("SurfaceTexture::connect(this=%p, %d)", this, api);
Mutex::Autolock lock(mMutex);
@@ -569,6 +562,9 @@
err = -EINVAL;
} else {
mConnectedApi = api;
+ *outWidth = mDefaultWidth;
+ *outHeight = mDefaultHeight;
+ *outTransform = 0;
}
break;
default:
@@ -594,7 +590,9 @@
case NATIVE_WINDOW_API_MEDIA:
case NATIVE_WINDOW_API_CAMERA:
if (mConnectedApi == api) {
+ drainQueueAndFreeBuffersLocked();
mConnectedApi = NO_CONNECTED_API;
+ mDequeueCondition.signal();
} else {
LOGE("disconnect: connected to another api (cur=%d, req=%d)",
mConnectedApi, api);
@@ -628,6 +626,11 @@
LOGV("SurfaceTexture::updateTexImage");
Mutex::Autolock lock(mMutex);
+ if (mAbandoned) {
+ LOGE("calling updateTexImage() on an abandoned SurfaceTexture");
+ return NO_INIT;
+ }
+
// In asynchronous mode the list is guaranteed to be one buffer
// deep, while in synchronous mode we use the oldest buffer.
if (!mQueue.empty()) {
@@ -638,6 +641,10 @@
EGLImageKHR image = mSlots[buf].mEglImage;
if (image == EGL_NO_IMAGE_KHR) {
EGLDisplay dpy = eglGetCurrentDisplay();
+ if (mSlots[buf].mGraphicBuffer == 0) {
+ LOGE("buffer at slot %d is null", buf);
+ return BAD_VALUE;
+ }
image = createImage(dpy, mSlots[buf].mGraphicBuffer);
mSlots[buf].mEglImage = image;
mSlots[buf].mEglDisplay = dpy;
@@ -827,18 +834,66 @@
mFrameAvailableListener = listener;
}
-void SurfaceTexture::freeAllBuffers() {
+void SurfaceTexture::freeBufferLocked(int i) {
+ mSlots[i].mGraphicBuffer = 0;
+ mSlots[i].mBufferState = BufferSlot::FREE;
+ if (mSlots[i].mEglImage != EGL_NO_IMAGE_KHR) {
+ eglDestroyImageKHR(mSlots[i].mEglDisplay, mSlots[i].mEglImage);
+ mSlots[i].mEglImage = EGL_NO_IMAGE_KHR;
+ mSlots[i].mEglDisplay = EGL_NO_DISPLAY;
+ }
+}
+
+void SurfaceTexture::freeAllBuffersLocked() {
+ LOGW_IF(!mQueue.isEmpty(),
+ "freeAllBuffersLocked called but mQueue is not empty");
for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
- mSlots[i].mGraphicBuffer = 0;
- mSlots[i].mBufferState = BufferSlot::FREE;
- if (mSlots[i].mEglImage != EGL_NO_IMAGE_KHR) {
- eglDestroyImageKHR(mSlots[i].mEglDisplay, mSlots[i].mEglImage);
- mSlots[i].mEglImage = EGL_NO_IMAGE_KHR;
- mSlots[i].mEglDisplay = EGL_NO_DISPLAY;
+ freeBufferLocked(i);
+ }
+}
+
+void SurfaceTexture::freeAllBuffersExceptHeadLocked() {
+ LOGW_IF(!mQueue.isEmpty(),
+ "freeAllBuffersExceptCurrentLocked called but mQueue is not empty");
+ int head = -1;
+ if (!mQueue.empty()) {
+ Fifo::iterator front(mQueue.begin());
+ head = *front;
+ }
+ for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
+ if (i != head) {
+ freeBufferLocked(i);
}
}
}
+status_t SurfaceTexture::drainQueueLocked() {
+ while (mSynchronousMode && !mQueue.isEmpty()) {
+ mDequeueCondition.wait(mMutex);
+ if (mAbandoned) {
+ LOGE("drainQueueLocked: SurfaceTexture has been abandoned!");
+ return NO_INIT;
+ }
+ if (mConnectedApi == NO_CONNECTED_API) {
+ LOGE("drainQueueLocked: SurfaceTexture is not connected!");
+ return NO_INIT;
+ }
+ }
+ return NO_ERROR;
+}
+
+status_t SurfaceTexture::drainQueueAndFreeBuffersLocked() {
+ status_t err = drainQueueLocked();
+ if (err == NO_ERROR) {
+ if (mSynchronousMode) {
+ freeAllBuffersLocked();
+ } else {
+ freeAllBuffersExceptHeadLocked();
+ }
+ }
+ return err;
+}
+
EGLImageKHR SurfaceTexture::createImage(EGLDisplay dpy,
const sp<GraphicBuffer>& graphicBuffer) {
EGLClientBuffer cbuf = (EGLClientBuffer)graphicBuffer->getNativeBuffer();
@@ -908,8 +963,10 @@
void SurfaceTexture::abandon() {
Mutex::Autolock lock(mMutex);
- freeAllBuffers();
+ mQueue.clear();
mAbandoned = true;
+ mCurrentTextureBuf.clear();
+ freeAllBuffersLocked();
mDequeueCondition.signal();
}
@@ -965,13 +1022,24 @@
for (int i=0 ; i<mBufferCount ; i++) {
const BufferSlot& slot(mSlots[i]);
snprintf(buffer, SIZE,
- "%s%s[%02d] state=%-8s, crop=[%d,%d,%d,%d], transform=0x%02x, "
- "timestamp=%lld\n",
- prefix, (i==mCurrentTexture)?">":" ", i, stateName(slot.mBufferState),
+ "%s%s[%02d] "
+ "state=%-8s, crop=[%d,%d,%d,%d], "
+ "transform=0x%02x, timestamp=%lld",
+ prefix, (i==mCurrentTexture)?">":" ", i,
+ stateName(slot.mBufferState),
slot.mCrop.left, slot.mCrop.top, slot.mCrop.right, slot.mCrop.bottom,
slot.mTransform, slot.mTimestamp
);
result.append(buffer);
+
+ const sp<GraphicBuffer>& buf(slot.mGraphicBuffer);
+ if (buf != NULL) {
+ snprintf(buffer, SIZE,
+ ", %p [%4ux%4u:%4u,%3X]",
+ buf->handle, buf->width, buf->height, buf->stride, buf->format);
+ result.append(buffer);
+ }
+ result.append("\n");
}
}
diff --git a/libs/gui/SurfaceTextureClient.cpp b/libs/gui/SurfaceTextureClient.cpp
index e6837ea..e91be84 100644
--- a/libs/gui/SurfaceTextureClient.cpp
+++ b/libs/gui/SurfaceTextureClient.cpp
@@ -258,10 +258,10 @@
int res = NO_ERROR;
switch (operation) {
case NATIVE_WINDOW_CONNECT:
- res = dispatchConnect(args);
+ // deprecated. must return NO_ERROR.
break;
case NATIVE_WINDOW_DISCONNECT:
- res = dispatchDisconnect(args);
+ // deprecated. must return NO_ERROR.
break;
case NATIVE_WINDOW_SET_USAGE:
res = dispatchSetUsage(args);
@@ -296,6 +296,12 @@
case NATIVE_WINDOW_SET_SCALING_MODE:
res = dispatchSetScalingMode(args);
break;
+ case NATIVE_WINDOW_API_CONNECT:
+ res = dispatchConnect(args);
+ break;
+ case NATIVE_WINDOW_API_DISCONNECT:
+ res = dispatchDisconnect(args);
+ break;
default:
res = NAME_NOT_FOUND;
break;
@@ -379,7 +385,8 @@
int SurfaceTextureClient::connect(int api) {
LOGV("SurfaceTextureClient::connect");
Mutex::Autolock lock(mMutex);
- int err = mSurfaceTexture->connect(api);
+ int err = mSurfaceTexture->connect(api,
+ &mDefaultWidth, &mDefaultHeight, &mTransformHint);
if (!err && api == NATIVE_WINDOW_API_CPU) {
mConnectedToCpu = true;
}
diff --git a/libs/ui/EGLUtils.cpp b/libs/ui/EGLUtils.cpp
index 020646b..f24a71d 100644
--- a/libs/ui/EGLUtils.cpp
+++ b/libs/ui/EGLUtils.cpp
@@ -24,8 +24,6 @@
#include <EGL/egl.h>
-#include <system/graphics.h>
-
#include <private/ui/android_natives_priv.h>
// ----------------------------------------------------------------------------
@@ -69,49 +67,31 @@
return BAD_VALUE;
// Get all the "potential match" configs...
- if (eglChooseConfig(dpy, attrs, 0, 0, &numConfigs) == EGL_FALSE)
+ if (eglGetConfigs(dpy, NULL, 0, &numConfigs) == EGL_FALSE)
return BAD_VALUE;
- if (numConfigs) {
- EGLConfig* const configs = new EGLConfig[numConfigs];
- if (eglChooseConfig(dpy, attrs, configs, numConfigs, &n) == EGL_FALSE) {
- delete [] configs;
- return BAD_VALUE;
- }
-
- bool hasAlpha = false;
- switch (format) {
- case HAL_PIXEL_FORMAT_RGBA_8888:
- case HAL_PIXEL_FORMAT_BGRA_8888:
- case HAL_PIXEL_FORMAT_RGBA_5551:
- case HAL_PIXEL_FORMAT_RGBA_4444:
- hasAlpha = true;
- break;
- }
-
- // The first config is guaranteed to over-satisfy the constraints
- EGLConfig config = configs[0];
-
- // go through the list and skip configs that over-satisfy our needs
- int i;
- for (i=0 ; i<n ; i++) {
- if (!hasAlpha) {
- EGLint alphaSize;
- eglGetConfigAttrib(dpy, configs[i], EGL_ALPHA_SIZE, &alphaSize);
- if (alphaSize > 0) {
- continue;
- }
- }
+ EGLConfig* const configs = (EGLConfig*)malloc(sizeof(EGLConfig)*numConfigs);
+ if (eglChooseConfig(dpy, attrs, configs, numConfigs, &n) == EGL_FALSE) {
+ free(configs);
+ return BAD_VALUE;
+ }
+
+ int i;
+ EGLConfig config = NULL;
+ for (i=0 ; i<n ; i++) {
+ EGLint nativeVisualId = 0;
+ eglGetConfigAttrib(dpy, configs[i], EGL_NATIVE_VISUAL_ID, &nativeVisualId);
+ if (nativeVisualId>0 && format == nativeVisualId) {
config = configs[i];
break;
}
+ }
- delete [] configs;
-
- if (i<n) {
- *outConfig = config;
- return NO_ERROR;
- }
+ free(configs);
+
+ if (i<n) {
+ *outConfig = config;
+ return NO_ERROR;
}
return NAME_NOT_FOUND;
diff --git a/libs/ui/FramebufferNativeWindow.cpp b/libs/ui/FramebufferNativeWindow.cpp
index 0e8ae61..8949730 100644
--- a/libs/ui/FramebufferNativeWindow.cpp
+++ b/libs/ui/FramebufferNativeWindow.cpp
@@ -317,6 +317,8 @@
case NATIVE_WINDOW_SET_BUFFERS_DIMENSIONS:
case NATIVE_WINDOW_SET_BUFFERS_FORMAT:
case NATIVE_WINDOW_SET_BUFFERS_TRANSFORM:
+ case NATIVE_WINDOW_API_CONNECT:
+ case NATIVE_WINDOW_API_DISCONNECT:
// TODO: we should implement these
return NO_ERROR;
diff --git a/libs/ui/GraphicBufferAllocator.cpp b/libs/ui/GraphicBufferAllocator.cpp
index 33ef1fc..e75415b 100644
--- a/libs/ui/GraphicBufferAllocator.cpp
+++ b/libs/ui/GraphicBufferAllocator.cpp
@@ -61,13 +61,19 @@
const size_t c = list.size();
for (size_t i=0 ; i<c ; i++) {
const alloc_rec_t& rec(list.valueAt(i));
- snprintf(buffer, SIZE, "%10p: %7.2f KiB | %4u (%4u) x %4u | %8X | 0x%08x\n",
- list.keyAt(i), rec.size/1024.0f,
- rec.w, rec.s, rec.h, rec.format, rec.usage);
+ if (rec.size) {
+ snprintf(buffer, SIZE, "%10p: %7.2f KiB | %4u (%4u) x %4u | %8X | 0x%08x\n",
+ list.keyAt(i), rec.size/1024.0f,
+ rec.w, rec.s, rec.h, rec.format, rec.usage);
+ } else {
+ snprintf(buffer, SIZE, "%10p: unknown | %4u (%4u) x %4u | %8X | 0x%08x\n",
+ list.keyAt(i),
+ rec.w, rec.s, rec.h, rec.format, rec.usage);
+ }
result.append(buffer);
total += rec.size;
}
- snprintf(buffer, SIZE, "Total allocated: %.2f KB\n", total/1024.0f);
+ snprintf(buffer, SIZE, "Total allocated (estimate): %.2f KB\n", total/1024.0f);
result.append(buffer);
if (mAllocDev->common.version >= 1 && mAllocDev->dump) {
mAllocDev->dump(mAllocDev, buffer, SIZE);
@@ -101,13 +107,19 @@
if (err == NO_ERROR) {
Mutex::Autolock _l(sLock);
KeyedVector<buffer_handle_t, alloc_rec_t>& list(sAllocList);
+ int bpp = bytesPerPixel(format);
+ if (bpp < 0) {
+ // probably a HAL custom format. in any case, we don't know
+ // what its pixel size is.
+ bpp = 0;
+ }
alloc_rec_t rec;
rec.w = w;
rec.h = h;
rec.s = *stride;
rec.format = format;
rec.usage = usage;
- rec.size = h * stride[0] * bytesPerPixel(format);
+ rec.size = h * stride[0] * bpp;
list.add(*handle, rec);
}
diff --git a/libs/ui/Input.cpp b/libs/ui/Input.cpp
index 0af7f80..688b998 100644
--- a/libs/ui/Input.cpp
+++ b/libs/ui/Input.cpp
@@ -280,6 +280,9 @@
uint64_t axisBit = 1LL << axis;
uint32_t index = __builtin_popcountll(bits & (axisBit - 1LL));
if (!(bits & axisBit)) {
+ if (value == 0) {
+ return OK; // axes with value 0 do not need to be stored
+ }
uint32_t count = __builtin_popcountll(bits);
if (count >= MAX_AXES) {
tooManyAxes(axis);
@@ -294,23 +297,10 @@
return OK;
}
-float* PointerCoords::editAxisValue(int32_t axis) {
- if (axis < 0 || axis > 63) {
- return NULL;
- }
-
- uint64_t axisBit = 1LL << axis;
- if (!(bits & axisBit)) {
- return NULL;
- }
- uint32_t index = __builtin_popcountll(bits & (axisBit - 1LL));
- return &values[index];
-}
-
static inline void scaleAxisValue(PointerCoords& c, int axis, float scaleFactor) {
- float* value = c.editAxisValue(axis);
- if (value) {
- *value *= scaleFactor;
+ float value = c.getAxisValue(axis);
+ if (value != 0) {
+ c.setAxisValue(axis, value * scaleFactor);
}
}
@@ -574,20 +564,14 @@
size_t numSamples = mSamplePointerCoords.size();
for (size_t i = 0; i < numSamples; i++) {
PointerCoords& c = mSamplePointerCoords.editItemAt(i);
- float* xPtr = c.editAxisValue(AMOTION_EVENT_AXIS_X);
- float* yPtr = c.editAxisValue(AMOTION_EVENT_AXIS_Y);
- if (xPtr && yPtr) {
- float x = *xPtr + oldXOffset;
- float y = *yPtr + oldYOffset;
- matrix->mapXY(SkFloatToScalar(x), SkFloatToScalar(y), & point);
- *xPtr = SkScalarToFloat(point.fX) - newXOffset;
- *yPtr = SkScalarToFloat(point.fY) - newYOffset;
- }
+ float x = c.getAxisValue(AMOTION_EVENT_AXIS_X) + oldXOffset;
+ float y = c.getAxisValue(AMOTION_EVENT_AXIS_Y) + oldYOffset;
+ matrix->mapXY(SkFloatToScalar(x), SkFloatToScalar(y), &point);
+ c.setAxisValue(AMOTION_EVENT_AXIS_X, SkScalarToFloat(point.fX) - newXOffset);
+ c.setAxisValue(AMOTION_EVENT_AXIS_Y, SkScalarToFloat(point.fY) - newYOffset);
- float* orientationPtr = c.editAxisValue(AMOTION_EVENT_AXIS_ORIENTATION);
- if (orientationPtr) {
- *orientationPtr = transformAngle(matrix, *orientationPtr);
- }
+ float orientation = c.getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION);
+ c.setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, transformAngle(matrix, orientation));
}
}
@@ -727,7 +711,7 @@
}
while (idBits.count() > MAX_POINTERS) {
- idBits.clearBit(idBits.lastMarkedBit());
+ idBits.clearLastMarkedBit();
}
Movement& movement = mMovements[mIndex];
@@ -776,7 +760,7 @@
// We do this on down instead of on up because the client may want to query the
// final velocity for a pointer that just went up.
BitSet32 downIdBits;
- downIdBits.markBit(event->getActionIndex());
+ downIdBits.markBit(event->getPointerId(event->getActionIndex()));
clearPointers(downIdBits);
break;
}
diff --git a/libs/ui/tests/Android.mk b/libs/ui/tests/Android.mk
index 693a32a..700b604 100644
--- a/libs/ui/tests/Android.mk
+++ b/libs/ui/tests/Android.mk
@@ -45,4 +45,4 @@
)
# Build the manual test programs.
-include $(call all-subdir-makefiles)
+include $(call all-makefiles-under, $(LOCAL_PATH))
diff --git a/libs/ui/tests/InputEvent_test.cpp b/libs/ui/tests/InputEvent_test.cpp
index e48d5b7..e21c464 100644
--- a/libs/ui/tests/InputEvent_test.cpp
+++ b/libs/ui/tests/InputEvent_test.cpp
@@ -52,9 +52,6 @@
ASSERT_EQ(0, coords.getAxisValue(1))
<< "getAxisValue should return zero because axis is not present";
- ASSERT_EQ(NULL, coords.editAxisValue(0))
- << "editAxisValue should return null because axis is not present";
-
// Set first axis.
ASSERT_EQ(OK, coords.setAxisValue(1, 5));
ASSERT_EQ(0x00000002ULL, coords.bits);
@@ -96,26 +93,17 @@
ASSERT_EQ(2, coords.getAxisValue(3))
<< "getAxisValue should return value of axis";
- // Edit an existing axis value in place.
- valuePtr = coords.editAxisValue(1);
- ASSERT_EQ(5, *valuePtr)
- << "editAxisValue should return pointer to axis value";
-
- *valuePtr = 7;
- ASSERT_EQ(7, coords.getAxisValue(1))
- << "getAxisValue should return value of axis";
-
// Set an axis with an id between the others. (inserting value in the middle)
ASSERT_EQ(OK, coords.setAxisValue(2, 1));
ASSERT_EQ(0x0000000fULL, coords.bits);
ASSERT_EQ(4, coords.values[0]);
- ASSERT_EQ(7, coords.values[1]);
+ ASSERT_EQ(5, coords.values[1]);
ASSERT_EQ(1, coords.values[2]);
ASSERT_EQ(2, coords.values[3]);
ASSERT_EQ(4, coords.getAxisValue(0))
<< "getAxisValue should return value of axis";
- ASSERT_EQ(7, coords.getAxisValue(1))
+ ASSERT_EQ(5, coords.getAxisValue(1))
<< "getAxisValue should return value of axis";
ASSERT_EQ(1, coords.getAxisValue(2))
<< "getAxisValue should return value of axis";
diff --git a/libs/utils/RefBase.cpp b/libs/utils/RefBase.cpp
index 8db2009..37d061c 100644
--- a/libs/utils/RefBase.cpp
+++ b/libs/utils/RefBase.cpp
@@ -49,11 +49,6 @@
// ---------------------------------------------------------------------------
-RefBase::Destroyer::~Destroyer() {
-}
-
-// ---------------------------------------------------------------------------
-
class RefBase::weakref_impl : public RefBase::weakref_type
{
public:
@@ -61,7 +56,6 @@
volatile int32_t mWeak;
RefBase* const mBase;
volatile int32_t mFlags;
- Destroyer* mDestroyer;
#if !DEBUG_REFS
@@ -70,7 +64,6 @@
, mWeak(0)
, mBase(base)
, mFlags(0)
- , mDestroyer(0)
{
}
@@ -113,7 +106,7 @@
LOGD("\t%c ID %p (ref %d):", inc, refs->id, refs->ref);
#if DEBUG_REFS_CALLSTACK_ENABLED
refs->stack.dump();
-#endif;
+#endif
refs = refs->next;
}
}
@@ -131,7 +124,7 @@
LOGD("\t%c ID %p (ref %d):", inc, refs->id, refs->ref);
#if DEBUG_REFS_CALLSTACK_ENABLED
refs->stack.dump();
-#endif;
+#endif
refs = refs->next;
}
}
@@ -193,7 +186,7 @@
String8 text;
{
- Mutex::Autolock _l(const_cast<weakref_impl*>(this)->mMutex);
+ Mutex::Autolock _l(mMutex);
char buf[128];
sprintf(buf, "Strong references on RefBase %p (weakref_type %p):\n", mBase, this);
text.append(buf);
@@ -318,7 +311,7 @@
}
}
- Mutex mMutex;
+ mutable Mutex mMutex;
ref_entry* mStrongRefs;
ref_entry* mWeakRefs;
@@ -348,7 +341,7 @@
}
android_atomic_add(-INITIAL_STRONG_VALUE, &refs->mStrong);
- const_cast<RefBase*>(this)->onFirstRef();
+ refs->mBase->onFirstRef();
}
void RefBase::decStrong(const void* id) const
@@ -361,13 +354,9 @@
#endif
LOG_ASSERT(c >= 1, "decStrong() called on %p too many times", refs);
if (c == 1) {
- const_cast<RefBase*>(this)->onLastStrongRef(id);
- if ((refs->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK) {
- if (refs->mDestroyer) {
- refs->mDestroyer->destroy(this);
- } else {
- delete this;
- }
+ refs->mBase->onLastStrongRef(id);
+ if ((refs->mFlags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_STRONG) {
+ delete this;
}
}
refs->decWeak(id);
@@ -391,7 +380,7 @@
android_atomic_add(-INITIAL_STRONG_VALUE, &refs->mStrong);
// fall through...
case 0:
- const_cast<RefBase*>(this)->onFirstRef();
+ refs->mBase->onFirstRef();
}
}
@@ -400,10 +389,6 @@
return mRefs->mStrong;
}
-void RefBase::setDestroyer(RefBase::Destroyer* destroyer) {
- mRefs->mDestroyer = destroyer;
-}
-
RefBase* RefBase::weakref_type::refBase() const
{
return static_cast<const weakref_impl*>(this)->mBase;
@@ -417,6 +402,7 @@
LOG_ASSERT(c >= 0, "incWeak called on %p after last weak ref", this);
}
+
void RefBase::weakref_type::decWeak(const void* id)
{
weakref_impl* const impl = static_cast<weakref_impl*>(this);
@@ -424,30 +410,27 @@
const int32_t c = android_atomic_dec(&impl->mWeak);
LOG_ASSERT(c >= 1, "decWeak called on %p too many times", this);
if (c != 1) return;
-
- if ((impl->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK) {
+
+ if ((impl->mFlags&OBJECT_LIFETIME_WEAK) == OBJECT_LIFETIME_STRONG) {
+ // This is the regular lifetime case. The object is destroyed
+ // when the last strong reference goes away. Since weakref_impl
+ // outlive the object, it is not destroyed in the dtor, and
+ // we'll have to do it here.
if (impl->mStrong == INITIAL_STRONG_VALUE) {
- if (impl->mBase) {
- if (impl->mDestroyer) {
- impl->mDestroyer->destroy(impl->mBase);
- } else {
- delete impl->mBase;
- }
- }
+ // Special case: we never had a strong reference, so we need to
+ // destroy the object now.
+ delete impl->mBase;
} else {
// LOGV("Freeing refs %p of old RefBase %p\n", this, impl->mBase);
delete impl;
}
} else {
+ // less common case: lifetime is OBJECT_LIFETIME_{WEAK|FOREVER}
impl->mBase->onLastWeakRef(id);
- if ((impl->mFlags&OBJECT_LIFETIME_FOREVER) != OBJECT_LIFETIME_FOREVER) {
- if (impl->mBase) {
- if (impl->mDestroyer) {
- impl->mDestroyer->destroy(impl->mBase);
- } else {
- delete impl->mBase;
- }
- }
+ if ((impl->mFlags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_WEAK) {
+ // this is the OBJECT_LIFETIME_WEAK case. The last weak-reference
+ // is gone, we can destroy the object.
+ delete impl->mBase;
}
}
}
@@ -569,11 +552,23 @@
RefBase::~RefBase()
{
- if ((mRefs->mFlags & OBJECT_LIFETIME_WEAK) == OBJECT_LIFETIME_WEAK) {
- if (mRefs->mWeak == 0) {
- delete mRefs;
+ if (mRefs->mStrong == INITIAL_STRONG_VALUE) {
+ // we never acquired a strong (and/or weak) reference on this object.
+ delete mRefs;
+ } else {
+ // life-time of this object is extended to WEAK or FOREVER, in
+ // which case weakref_impl doesn't out-live the object and we
+ // can free it now.
+ if ((mRefs->mFlags & OBJECT_LIFETIME_MASK) != OBJECT_LIFETIME_STRONG) {
+ // It's possible that the weak count is not 0 if the object
+ // re-acquired a weak reference in its destructor
+ if (mRefs->mWeak == 0) {
+ delete mRefs;
+ }
}
}
+ // for debugging purposes, clear this.
+ const_cast<weakref_impl*&>(mRefs) = NULL;
}
void RefBase::extendObjectLifetime(int32_t mode)
diff --git a/libs/utils/tests/Android.mk b/libs/utils/tests/Android.mk
index 8726a53..b97f52f 100644
--- a/libs/utils/tests/Android.mk
+++ b/libs/utils/tests/Android.mk
@@ -8,7 +8,8 @@
ObbFile_test.cpp \
Looper_test.cpp \
String8_test.cpp \
- Unicode_test.cpp
+ Unicode_test.cpp \
+ ZipFileRO_test.cpp \
shared_libraries := \
libz \
diff --git a/libs/utils/tests/ZipFileRO_test.cpp b/libs/utils/tests/ZipFileRO_test.cpp
new file mode 100644
index 0000000..7a1d0bd
--- /dev/null
+++ b/libs/utils/tests/ZipFileRO_test.cpp
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "ZipFileRO_test"
+#include <utils/Log.h>
+#include <utils/ZipFileRO.h>
+
+#include <gtest/gtest.h>
+
+#include <fcntl.h>
+#include <string.h>
+
+namespace android {
+
+class ZipFileROTest : public testing::Test {
+protected:
+ virtual void SetUp() {
+ }
+
+ virtual void TearDown() {
+ }
+};
+
+TEST_F(ZipFileROTest, ZipTimeConvertSuccess) {
+ struct tm t;
+
+ // 2011-06-29 14:40:40
+ long when = 0x3EDD7514;
+
+ ZipFileRO::zipTimeToTimespec(when, &t);
+
+ EXPECT_EQ(2011, t.tm_year + 1900)
+ << "Year was improperly converted.";
+
+ EXPECT_EQ(6, t.tm_mon)
+ << "Month was improperly converted.";
+
+ EXPECT_EQ(29, t.tm_mday)
+ << "Day was improperly converted.";
+
+ EXPECT_EQ(14, t.tm_hour)
+ << "Hour was improperly converted.";
+
+ EXPECT_EQ(40, t.tm_min)
+ << "Minute was improperly converted.";
+
+ EXPECT_EQ(40, t.tm_sec)
+ << "Second was improperly converted.";
+}
+
+}
diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp
index ba5d29a..10cea22 100644
--- a/opengl/libs/EGL/eglApi.cpp
+++ b/opengl/libs/EGL/eglApi.cpp
@@ -363,6 +363,12 @@
EGLConfig iConfig = dp->configs[intptr_t(config)].config;
EGLint format;
+ if (native_window_api_connect(window, NATIVE_WINDOW_API_EGL) != OK) {
+ LOGE("EGLNativeWindowType %p already connected to another API",
+ window);
+ return setError(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE);
+ }
+
// set the native window's buffers format to match this config
if (cnx->egl.eglGetConfigAttrib(iDpy,
iConfig, EGL_NATIVE_VISUAL_ID, &format)) {
@@ -371,6 +377,7 @@
if (err != 0) {
LOGE("error setting native window pixel format: %s (%d)",
strerror(-err), err);
+ native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL);
return setError(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE);
}
}
@@ -383,6 +390,10 @@
dp->configs[intptr_t(config)].impl, cnx);
return s;
}
+
+ // EGLSurface creation failed
+ native_window_set_buffers_format(window, 0);
+ native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL);
}
return EGL_NO_SURFACE;
}
@@ -443,8 +454,12 @@
EGLBoolean result = s->cnx->egl.eglDestroySurface(
dp->disp[s->impl].dpy, s->surface);
if (result == EGL_TRUE) {
- if (s->win != NULL) {
- native_window_set_buffers_geometry(s->win.get(), 0, 0, 0);
+ ANativeWindow* const window = s->win.get();
+ if (window != NULL) {
+ native_window_set_buffers_format(window, 0);
+ if (native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL)) {
+ LOGE("EGLNativeWindowType %p disconnected failed", window);
+ }
}
_s.terminate();
}
diff --git a/opengl/tests/swapinterval/swapinterval.cpp b/opengl/tests/swapinterval/swapinterval.cpp
index df53b62..8ca031b 100644
--- a/opengl/tests/swapinterval/swapinterval.cpp
+++ b/opengl/tests/swapinterval/swapinterval.cpp
@@ -48,31 +48,35 @@
EGLNativeWindowType window = android_createDisplaySurface();
dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
- eglInitialize(dpy, 0 ,0) ;//&majorVersion, &minorVersion);
+ eglInitialize(dpy, &majorVersion, &minorVersion);
eglGetConfigs(dpy, NULL, 0, &numConfigs);
printf("# configs = %d\n", numConfigs);
status_t err = EGLUtils::selectConfigForNativeWindow(
dpy, configAttribs, window, &config);
if (err) {
- fprintf(stderr, "couldn't find an EGLConfig matching the screen format\n");
+ fprintf(stderr, "error: %s", EGLUtils::strerror(eglGetError()));
+ eglTerminate(dpy);
return 0;
}
- EGLint r,g,b,a;
+ EGLint r,g,b,a, vid;
eglGetConfigAttrib(dpy, config, EGL_RED_SIZE, &r);
eglGetConfigAttrib(dpy, config, EGL_GREEN_SIZE, &g);
eglGetConfigAttrib(dpy, config, EGL_BLUE_SIZE, &b);
eglGetConfigAttrib(dpy, config, EGL_ALPHA_SIZE, &a);
+ eglGetConfigAttrib(dpy, config, EGL_NATIVE_VISUAL_ID, &vid);
surface = eglCreateWindowSurface(dpy, config, window, NULL);
if (surface == EGL_NO_SURFACE) {
EGLint err = eglGetError();
- fprintf(stderr, "%s, config=%p, format = %d-%d-%d-%d\n",
- EGLUtils::strerror(err), config, r,g,b,a);
+ fprintf(stderr, "error: %s, config=%p, format = %d-%d-%d-%d, visual-id = %d\n",
+ EGLUtils::strerror(err), config, r,g,b,a, vid);
+ eglTerminate(dpy);
return 0;
} else {
- printf("config=%p, format = %d-%d-%d-%d\n", config, r,g,b,a);
+ printf("config=%p, format = %d-%d-%d-%d, visual-id = %d\n",
+ config, r,g,b,a, vid);
}
context = eglCreateContext(dpy, config, NULL, NULL);
diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk
index f67c82e..b178e49 100644
--- a/services/surfaceflinger/Android.mk
+++ b/services/surfaceflinger/Android.mk
@@ -22,7 +22,7 @@
LOCAL_CFLAGS += -DNO_RGBX_8888
endif
ifeq ($(TARGET_BOARD_PLATFORM), s5pc110)
- LOCAL_CFLAGS += -DHAS_CONTEXT_PRIORITY
+ LOCAL_CFLAGS += -DHAS_CONTEXT_PRIORITY -DNEVER_DEFAULT_TO_ASYNC_MODE
endif
diff --git a/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp b/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp
index 7bf3e0a..f4be168 100644
--- a/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp
+++ b/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp
@@ -40,6 +40,7 @@
#include "GLExtensions.h"
#include "HWComposer.h"
+#include "SurfaceFlinger.h"
using namespace android;
@@ -75,7 +76,7 @@
const sp<SurfaceFlinger>& flinger,
uint32_t dpy)
: DisplayHardwareBase(flinger, dpy),
- mFlags(0), mHwc(0)
+ mFlinger(flinger), mFlags(0), mHwc(0)
{
init(dpy);
}
@@ -310,7 +311,7 @@
// initialize the H/W composer
- mHwc = new HWComposer();
+ mHwc = new HWComposer(mFlinger);
if (mHwc->initCheck() == NO_ERROR) {
mHwc->setFrameBuffer(mDisplay, mSurface);
}
diff --git a/services/surfaceflinger/DisplayHardware/DisplayHardware.h b/services/surfaceflinger/DisplayHardware/DisplayHardware.h
index cdf89fd..40a6f1e 100644
--- a/services/surfaceflinger/DisplayHardware/DisplayHardware.h
+++ b/services/surfaceflinger/DisplayHardware/DisplayHardware.h
@@ -95,6 +95,7 @@
void init(uint32_t displayIndex) __attribute__((noinline));
void fini() __attribute__((noinline));
+ sp<SurfaceFlinger> mFlinger;
EGLDisplay mDisplay;
EGLSurface mSurface;
EGLContext mContext;
diff --git a/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.h b/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.h
index 30eb258..3ebc7b6 100644
--- a/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.h
+++ b/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.h
@@ -37,7 +37,7 @@
~DisplayHardwareBase();
- // console managment
+ // console management
void releaseScreen() const;
void acquireScreen() const;
bool isScreenAcquired() const;
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 4a3b20d..7d1bdf0 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -30,12 +30,14 @@
#include <EGL/egl.h>
#include "HWComposer.h"
+#include "SurfaceFlinger.h"
namespace android {
// ---------------------------------------------------------------------------
-HWComposer::HWComposer()
- : mModule(0), mHwc(0), mList(0), mCapacity(0),
+HWComposer::HWComposer(const sp<SurfaceFlinger>& flinger)
+ : mFlinger(flinger),
+ mModule(0), mHwc(0), mList(0), mCapacity(0),
mDpy(EGL_NO_DISPLAY), mSur(EGL_NO_SURFACE)
{
int err = hw_get_module(HWC_HARDWARE_MODULE_ID, &mModule);
@@ -44,6 +46,13 @@
err = hwc_open(mModule, &mHwc);
LOGE_IF(err, "%s device failed to initialize (%s)",
HWC_HARDWARE_COMPOSER, strerror(-err));
+ if (err == 0) {
+ if (mHwc->registerProcs) {
+ mCBContext.hwc = this;
+ mCBContext.procs.invalidate = &hook_invalidate;
+ mHwc->registerProcs(mHwc, &mCBContext.procs);
+ }
+ }
}
}
@@ -58,6 +67,14 @@
return mHwc ? NO_ERROR : NO_INIT;
}
+void HWComposer::hook_invalidate(struct hwc_procs* procs) {
+ reinterpret_cast<cb_context *>(procs)->hwc->invalidate();
+}
+
+void HWComposer::invalidate() {
+ mFlinger->signalEvent();
+}
+
void HWComposer::setFrameBuffer(EGLDisplay dpy, EGLSurface sur) {
mDpy = (hwc_display_t)dpy;
mSur = (hwc_surface_t)sur;
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index 5a9e9eb..983898a 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -24,16 +24,19 @@
#include <hardware/hwcomposer.h>
+#include <utils/StrongPointer.h>
+
namespace android {
// ---------------------------------------------------------------------------
class String8;
+class SurfaceFlinger;
class HWComposer
{
public:
- HWComposer();
+ HWComposer(const sp<SurfaceFlinger>& flinger);
~HWComposer();
status_t initCheck() const;
@@ -60,12 +63,21 @@
void dump(String8& out, char* scratch, size_t SIZE) const;
private:
+ struct cb_context {
+ hwc_procs_t procs;
+ HWComposer* hwc;
+ };
+ static void hook_invalidate(struct hwc_procs* procs);
+ void invalidate();
+
+ sp<SurfaceFlinger> mFlinger;
hw_module_t const* mModule;
hwc_composer_device_t* mHwc;
hwc_layer_list_t* mList;
size_t mCapacity;
hwc_display_t mDpy;
hwc_surface_t mSur;
+ cb_context mCBContext;
};
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 7d6a14d..0425fc3 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -65,14 +65,9 @@
glGenTextures(1, &mTextureName);
}
-void Layer::destroy(RefBase const* base) {
- mFlinger->destroyLayer(static_cast<LayerBase const*>(base));
-}
-
void Layer::onFirstRef()
{
LayerBaseClient::onFirstRef();
- setDestroyer(this);
struct FrameQueuedListener : public SurfaceTexture::FrameAvailableListener {
FrameQueuedListener(Layer* layer) : mLayer(layer) { }
@@ -93,7 +88,16 @@
Layer::~Layer()
{
- glDeleteTextures(1, &mTextureName);
+ class MessageDestroyGLState : public MessageBase {
+ GLuint texture;
+ public:
+ MessageDestroyGLState(GLuint texture) : texture(texture) { }
+ virtual bool handler() {
+ glDeleteTextures(1, &texture);
+ return true;
+ }
+ };
+ mFlinger->postMessageAsync( new MessageDestroyGLState(mTextureName) );
}
void Layer::onFrameQueued() {
@@ -105,6 +109,7 @@
// in the purgatory list
void Layer::onRemoved()
{
+ mSurfaceTexture->abandon();
}
sp<ISurface> Layer::createSurface()
@@ -171,17 +176,14 @@
void Layer::setGeometry(hwc_layer_t* hwcl)
{
- hwcl->compositionType = HWC_FRAMEBUFFER;
- hwcl->hints = 0;
- hwcl->flags = 0;
- hwcl->transform = 0;
- hwcl->blending = HWC_BLENDING_NONE;
+ LayerBaseClient::setGeometry(hwcl);
+
+ hwcl->flags &= ~HWC_SKIP_LAYER;
// we can't do alpha-fade with the hwc HAL
const State& s(drawingState());
if (s.alpha < 0xFF) {
hwcl->flags = HWC_SKIP_LAYER;
- return;
}
/*
@@ -189,14 +191,13 @@
* 1) buffer orientation/flip/mirror
* 2) state transformation (window manager)
* 3) layer orientation (screen orientation)
+ * mOrientation is already the composition of (2) and (3)
* (NOTE: the matrices are multiplied in reverse order)
*/
const Transform bufferOrientation(mCurrentTransform);
- const Transform& stateTransform(s.transform);
const Transform layerOrientation(mOrientation);
-
- const Transform tr(layerOrientation * stateTransform * bufferOrientation);
+ const Transform tr(layerOrientation * bufferOrientation);
// this gives us only the "orientation" component of the transform
const uint32_t finalTransform = tr.getOrientation();
@@ -204,26 +205,9 @@
// we can only handle simple transformation
if (finalTransform & Transform::ROT_INVALID) {
hwcl->flags = HWC_SKIP_LAYER;
- return;
+ } else {
+ hwcl->transform = finalTransform;
}
-
- hwcl->transform = finalTransform;
-
- if (!isOpaque()) {
- hwcl->blending = mPremultipliedAlpha ?
- HWC_BLENDING_PREMULT : HWC_BLENDING_COVERAGE;
- }
-
- // scaling is already applied in mTransformedBounds
- hwcl->displayFrame.left = mTransformedBounds.left;
- hwcl->displayFrame.top = mTransformedBounds.top;
- hwcl->displayFrame.right = mTransformedBounds.right;
- hwcl->displayFrame.bottom = mTransformedBounds.bottom;
-
- hwcl->visibleRegionScreen.rects =
- reinterpret_cast<hwc_rect_t const *>(
- visibleRegionScreen.getArray(
- &hwcl->visibleRegionScreen.numRects));
}
void Layer::setPerFrameData(hwc_layer_t* hwcl) {
@@ -234,9 +218,9 @@
// HWC handle it.
hwcl->flags |= HWC_SKIP_LAYER;
hwcl->handle = NULL;
- return;
+ } else {
+ hwcl->handle = buffer->handle;
}
- hwcl->handle = buffer->handle;
if (isCropped()) {
hwcl->sourceCrop.left = mCurrentCrop.left;
@@ -246,8 +230,13 @@
} else {
hwcl->sourceCrop.left = 0;
hwcl->sourceCrop.top = 0;
- hwcl->sourceCrop.right = buffer->width;
- hwcl->sourceCrop.bottom = buffer->height;
+ if (buffer != NULL) {
+ hwcl->sourceCrop.right = buffer->width;
+ hwcl->sourceCrop.bottom = buffer->height;
+ } else {
+ hwcl->sourceCrop.right = mTransformedBounds.width();
+ hwcl->sourceCrop.bottom = mTransformedBounds.height();
+ }
}
}
@@ -326,8 +315,9 @@
{
// if we don't have a buffer yet, we're translucent regardless of the
// layer's opaque flag.
- if (mActiveBuffer == 0)
+ if (mActiveBuffer == 0) {
return false;
+ }
// if the layer has the opaque flag, then we're always opaque,
// otherwise we use the current buffer's format.
@@ -411,6 +401,8 @@
void Layer::lockPageFlip(bool& recomputeVisibleRegions)
{
if (mQueuedFrames > 0) {
+ const bool oldOpacity = isOpaque();
+
// signal another event if we have more frames pending
if (android_atomic_dec(&mQueuedFrames) > 1) {
mFlinger->signalEvent();
@@ -438,9 +430,8 @@
mFlinger->invalidateHwcGeometry();
}
- const bool opacity(getOpacityForFormat(mActiveBuffer->format));
- if (opacity != mCurrentOpacity) {
- mCurrentOpacity = opacity;
+ mCurrentOpacity = getOpacityForFormat(mActiveBuffer->format);
+ if (oldOpacity != isOpaque()) {
recomputeVisibleRegions = true;
}
@@ -545,7 +536,7 @@
}
snprintf(buffer, SIZE,
" "
- "format=%2d, activeBuffer=[%3ux%3u:%3u,%3u],"
+ "format=%2d, activeBuffer=[%4ux%4u:%4u,%3X],"
" freezeLock=%p, queued-frames=%d\n",
mFormat, w0, h0, s0,f0,
getFreezeLock().get(), mQueuedFrames);
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index ddfc666..d3ddab4 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -45,7 +45,7 @@
// ---------------------------------------------------------------------------
-class Layer : public LayerBaseClient, private RefBase::Destroyer
+class Layer : public LayerBaseClient
{
public:
Layer(SurfaceFlinger* flinger, DisplayID display,
@@ -78,7 +78,6 @@
inline const sp<FreezeLock>& getFreezeLock() const { return mFreezeLock; }
protected:
- virtual void destroy(RefBase const* base);
virtual void onFirstRef();
virtual void dump(String8& result, char* scratch, size_t size) const;
diff --git a/services/surfaceflinger/LayerBase.cpp b/services/surfaceflinger/LayerBase.cpp
index c86c659..e04c533 100644
--- a/services/surfaceflinger/LayerBase.cpp
+++ b/services/surfaceflinger/LayerBase.cpp
@@ -302,13 +302,47 @@
}
}
-void LayerBase::setGeometry(hwc_layer_t* hwcl) {
- hwcl->flags |= HWC_SKIP_LAYER;
+void LayerBase::setGeometry(hwc_layer_t* hwcl)
+{
+ hwcl->compositionType = HWC_FRAMEBUFFER;
+ hwcl->hints = 0;
+ hwcl->flags = HWC_SKIP_LAYER;
+ hwcl->transform = 0;
+ hwcl->blending = HWC_BLENDING_NONE;
+
+ // this gives us only the "orientation" component of the transform
+ const State& s(drawingState());
+ const uint32_t finalTransform = s.transform.getOrientation();
+ // we can only handle simple transformation
+ if (finalTransform & Transform::ROT_INVALID) {
+ hwcl->flags = HWC_SKIP_LAYER;
+ } else {
+ hwcl->transform = finalTransform;
+ }
+
+ if (!isOpaque()) {
+ hwcl->blending = mPremultipliedAlpha ?
+ HWC_BLENDING_PREMULT : HWC_BLENDING_COVERAGE;
+ }
+
+ // scaling is already applied in mTransformedBounds
+ hwcl->displayFrame.left = mTransformedBounds.left;
+ hwcl->displayFrame.top = mTransformedBounds.top;
+ hwcl->displayFrame.right = mTransformedBounds.right;
+ hwcl->displayFrame.bottom = mTransformedBounds.bottom;
+ hwcl->visibleRegionScreen.rects =
+ reinterpret_cast<hwc_rect_t const *>(
+ visibleRegionScreen.getArray(
+ &hwcl->visibleRegionScreen.numRects));
}
void LayerBase::setPerFrameData(hwc_layer_t* hwcl) {
hwcl->compositionType = HWC_FRAMEBUFFER;
hwcl->handle = NULL;
+ hwcl->sourceCrop.left = 0;
+ hwcl->sourceCrop.top = 0;
+ hwcl->sourceCrop.right = mTransformedBounds.width();
+ hwcl->sourceCrop.bottom = mTransformedBounds.height();
}
void LayerBase::setFiltering(bool filtering)
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 4a27701..082effe 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -402,9 +402,6 @@
{
waitForEvent();
- // call Layer's destructor
- handleDestroyLayers();
-
// check for transactions
if (UNLIKELY(mConsoleSignals)) {
handleConsoleEvents();
@@ -597,31 +594,6 @@
commitTransaction();
}
-void SurfaceFlinger::destroyLayer(LayerBase const* layer)
-{
- Mutex::Autolock _l(mDestroyedLayerLock);
- mDestroyedLayers.add(layer);
- signalEvent();
-}
-
-void SurfaceFlinger::handleDestroyLayers()
-{
- Vector<LayerBase const *> destroyedLayers;
-
- { // scope for the lock
- Mutex::Autolock _l(mDestroyedLayerLock);
- destroyedLayers = mDestroyedLayers;
- mDestroyedLayers.clear();
- }
-
- // call destructors without a lock held
- const size_t count = destroyedLayers.size();
- for (size_t i=0 ; i<count ; i++) {
- //LOGD("destroying %s", destroyedLayers[i]->getName().string());
- delete destroyedLayers[i];
- }
-}
-
sp<FreezeLock> SurfaceFlinger::getFreezeLock() const
{
return new FreezeLock(const_cast<SurfaceFlinger *>(this));
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 15661f0..6f93f5b 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -189,7 +189,6 @@
status_t addLayer(const sp<LayerBase>& layer);
status_t invalidateLayerVisibility(const sp<LayerBase>& layer);
void invalidateHwcGeometry();
- void destroyLayer(LayerBase const* layer);
sp<Layer> getLayer(const sp<ISurface>& sur) const;
@@ -266,7 +265,6 @@
void handleConsoleEvents();
void handleTransaction(uint32_t transactionFlags);
void handleTransactionLocked(uint32_t transactionFlags);
- void handleDestroyLayers();
void computeVisibleRegions(
const LayerVector& currentLayers,
diff --git a/services/surfaceflinger/SurfaceTextureLayer.cpp b/services/surfaceflinger/SurfaceTextureLayer.cpp
index 91e010f..79cd0c3 100644
--- a/services/surfaceflinger/SurfaceTextureLayer.cpp
+++ b/services/surfaceflinger/SurfaceTextureLayer.cpp
@@ -86,6 +86,42 @@
return res;
}
+status_t SurfaceTextureLayer::connect(int api,
+ uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransform) {
+ status_t err = SurfaceTexture::connect(api,
+ outWidth, outHeight, outTransform);
+ if (err == NO_ERROR) {
+ sp<Layer> layer(mLayer.promote());
+ if (layer != NULL) {
+ uint32_t orientation = layer->getOrientation();
+ if (orientation & Transform::ROT_INVALID) {
+ orientation = 0;
+ }
+ *outTransform = orientation;
+ }
+ switch(api) {
+ case NATIVE_WINDOW_API_MEDIA:
+ case NATIVE_WINDOW_API_CAMERA:
+ // Camera preview and videos are rate-limited on the producer
+ // side. If enabled for this build, we use async mode to always
+ // show the most recent frame at the cost of requiring an
+ // additional buffer.
+#ifndef NEVER_DEFAULT_TO_ASYNC_MODE
+ err = setSynchronousMode(false);
+ break;
+#endif
+ // fall through to set synchronous mode when not defaulting to
+ // async mode.
+ deafult:
+ err = setSynchronousMode(true);
+ break;
+ }
+ if (err != NO_ERROR) {
+ disconnect(api);
+ }
+ }
+ return err;
+}
// ---------------------------------------------------------------------------
}; // namespace android
diff --git a/services/surfaceflinger/SurfaceTextureLayer.h b/services/surfaceflinger/SurfaceTextureLayer.h
index 29a9cbe..9508524 100644
--- a/services/surfaceflinger/SurfaceTextureLayer.h
+++ b/services/surfaceflinger/SurfaceTextureLayer.h
@@ -50,6 +50,9 @@
virtual status_t dequeueBuffer(int *buf, uint32_t w, uint32_t h,
uint32_t format, uint32_t usage);
+
+ virtual status_t connect(int api,
+ uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransform);
};
// ---------------------------------------------------------------------------