summaryrefslogtreecommitdiffstats
path: root/libs
diff options
context:
space:
mode:
Diffstat (limited to 'libs')
-rw-r--r--libs/binder/IPCThreadState.cpp8
-rw-r--r--libs/binder/MemoryBase.cpp9
-rw-r--r--libs/binder/Parcel.cpp49
-rw-r--r--libs/gui/Android.mk23
-rw-r--r--libs/gui/BufferItemConsumer.cpp96
-rw-r--r--libs/gui/BufferQueue.cpp412
-rw-r--r--libs/gui/CleanSpec.mk52
-rw-r--r--libs/gui/ConsumerBase.cpp236
-rw-r--r--libs/gui/CpuConsumer.cpp159
-rw-r--r--libs/gui/GuiConfig.cpp38
-rw-r--r--libs/gui/IGraphicBufferAlloc.cpp2
-rw-r--r--libs/gui/ISensorServer.cpp4
-rw-r--r--libs/gui/ISurfaceComposer.cpp169
-rw-r--r--libs/gui/ISurfaceComposerClient.cpp5
-rw-r--r--libs/gui/ISurfaceTexture.cpp99
-rw-r--r--libs/gui/LayerState.cpp39
-rw-r--r--libs/gui/Sensor.cpp18
-rw-r--r--libs/gui/Surface.cpp33
-rw-r--r--libs/gui/SurfaceComposerClient.cpp373
-rw-r--r--libs/gui/SurfaceTexture.cpp501
-rw-r--r--libs/gui/SurfaceTextureClient.cpp222
-rw-r--r--libs/gui/tests/Android.mk7
-rw-r--r--libs/gui/tests/BufferQueue_test.cpp117
-rw-r--r--libs/gui/tests/CpuConsumer_test.cpp509
-rw-r--r--libs/gui/tests/SurfaceTextureClient_test.cpp194
-rw-r--r--libs/gui/tests/SurfaceTexture_test.cpp249
-rw-r--r--libs/gui/tests/Surface_test.cpp20
-rw-r--r--libs/ui/Android.mk9
-rw-r--r--libs/ui/Fence.cpp121
-rw-r--r--libs/ui/FramebufferNativeWindow.cpp71
-rw-r--r--libs/ui/GraphicBuffer.cpp7
-rw-r--r--libs/ui/GraphicBufferAllocator.cpp132
-rw-r--r--libs/ui/Region.cpp213
-rw-r--r--libs/ui/UiConfig.cpp36
-rw-r--r--libs/utils/Android.mk1
-rw-r--r--libs/utils/LinearTransform.cpp9
-rw-r--r--libs/utils/Log.cpp37
-rw-r--r--libs/utils/SystemClock.cpp92
-rw-r--r--libs/utils/Timers.cpp3
-rw-r--r--libs/utils/Trace.cpp4
-rw-r--r--libs/utils/VectorImpl.cpp48
-rw-r--r--libs/utils/ZipFileRO.cpp60
-rw-r--r--libs/utils/ZipUtils.cpp10
-rw-r--r--libs/utils/misc.cpp102
-rw-r--r--libs/utils/tests/Android.mk42
45 files changed, 3279 insertions, 1361 deletions
diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp
index 7e416b9..6e83faa 100644
--- a/libs/binder/IPCThreadState.cpp
+++ b/libs/binder/IPCThreadState.cpp
@@ -371,11 +371,6 @@ int IPCThreadState::getCallingUid()
return mCallingUid;
}
-int IPCThreadState::getOrigCallingUid()
-{
- return mOrigCallingUid;
-}
-
int64_t IPCThreadState::clearCallingIdentity()
{
int64_t token = ((int64_t)mCallingUid<<32) | mCallingPid;
@@ -646,7 +641,6 @@ IPCThreadState::IPCThreadState()
{
pthread_setspecific(gTLS, this);
clearCaller();
- mOrigCallingUid = mCallingUid;
mIn.setDataCapacity(256);
mOut.setDataCapacity(256);
}
@@ -998,7 +992,6 @@ status_t IPCThreadState::executeCommand(int32_t cmd)
mCallingPid = tr.sender_pid;
mCallingUid = tr.sender_euid;
- mOrigCallingUid = tr.sender_euid;
int curPrio = getpriority(PRIO_PROCESS, mMyThreadId);
if (gDisableBackgroundScheduling) {
@@ -1056,7 +1049,6 @@ status_t IPCThreadState::executeCommand(int32_t cmd)
mCallingPid = origPid;
mCallingUid = origUid;
- mOrigCallingUid = origUid;
IF_LOG_TRANSACTIONS() {
TextOutput::Bundle _b(alog);
diff --git a/libs/binder/MemoryBase.cpp b/libs/binder/MemoryBase.cpp
index 033066b..5c82330 100644
--- a/libs/binder/MemoryBase.cpp
+++ b/libs/binder/MemoryBase.cpp
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#define LOG_TAG "MemoryBase"
#include <stdlib.h>
#include <stdint.h>
@@ -44,3 +45,11 @@ MemoryBase::~MemoryBase()
// ---------------------------------------------------------------------------
}; // namespace android
+
+// Backwards compatibility for libdatabase_sqlcipher (http://b/8253769).
+extern "C" void _ZN7android10MemoryBaseC1ERKNS_2spINS_11IMemoryHeapEEEij(void*, void*, ssize_t, size_t);
+extern "C" void _ZN7android10MemoryBaseC1ERKNS_2spINS_11IMemoryHeapEEElj(void* obj, void* h, long o, unsigned int size) {
+ _ZN7android10MemoryBaseC1ERKNS_2spINS_11IMemoryHeapEEEij(obj, h, o, size);
+ ALOGW("Using temporary compatibility workaround for usage of MemoryBase "
+ "private API. Please fix your application!");
+}
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index 4c15913..c7bdcbc 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -627,11 +627,27 @@ status_t Parcel::writeFloat(float val)
return writeAligned(val);
}
+#if defined(__mips__) && defined(__mips_hard_float)
+
+status_t Parcel::writeDouble(double val)
+{
+ union {
+ double d;
+ unsigned long long ll;
+ } u;
+ u.d = val;
+ return writeAligned(u.ll);
+}
+
+#else
+
status_t Parcel::writeDouble(double val)
{
return writeAligned(val);
}
+#endif
+
status_t Parcel::writeIntPtr(intptr_t val)
{
return writeAligned(val);
@@ -962,17 +978,44 @@ float Parcel::readFloat() const
return readAligned<float>();
}
+#if defined(__mips__) && defined(__mips_hard_float)
+
status_t Parcel::readDouble(double *pArg) const
{
- return readAligned(pArg);
+ union {
+ double d;
+ unsigned long long ll;
+ } u;
+ status_t status;
+ status = readAligned(&u.ll);
+ *pArg = u.d;
+ return status;
+}
+
+double Parcel::readDouble() const
+{
+ union {
+ double d;
+ unsigned long long ll;
+ } u;
+ u.ll = readAligned<unsigned long long>();
+ return u.d;
}
+#else
+
+status_t Parcel::readDouble(double *pArg) const
+{
+ return readAligned(pArg);
+}
double Parcel::readDouble() const
{
return readAligned<double>();
}
+#endif
+
status_t Parcel::readIntPtr(intptr_t *pArg) const
{
return readAligned(pArg);
@@ -1429,6 +1472,8 @@ status_t Parcel::continueWrite(size_t desired)
if (objectsSize) {
objects = (size_t*)malloc(objectsSize*sizeof(size_t));
if (!objects) {
+ free(data);
+
mError = NO_MEMORY;
return NO_MEMORY;
}
@@ -1509,7 +1554,7 @@ status_t Parcel::continueWrite(size_t desired)
mError = NO_MEMORY;
return NO_MEMORY;
}
-
+
if(!(mDataCapacity == 0 && mObjects == NULL
&& mObjectsCapacity == 0)) {
ALOGE("continueWrite: %d/%p/%d/%d", mDataCapacity, mObjects, mObjectsCapacity, desired);
diff --git a/libs/gui/Android.mk b/libs/gui/Android.mk
index 8224847..d970a33 100644
--- a/libs/gui/Android.mk
+++ b/libs/gui/Android.mk
@@ -4,6 +4,7 @@ include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
BitTube.cpp \
BufferQueue.cpp \
+ ConsumerBase.cpp \
DisplayEventReceiver.cpp \
IDisplayEventConnection.cpp \
ISensorEventConnection.cpp \
@@ -21,17 +22,19 @@ LOCAL_SRC_FILES:= \
LayerState.cpp \
Surface.cpp \
SurfaceComposerClient.cpp \
- DummyConsumer.cpp
+ DummyConsumer.cpp \
+ CpuConsumer.cpp \
+ BufferItemConsumer.cpp \
+ GuiConfig.cpp
LOCAL_SHARED_LIBRARIES := \
- libcutils \
- libutils \
libbinder \
- libhardware \
- libhardware_legacy \
- libui \
+ libcutils \
libEGL \
libGLESv2 \
+ libsync \
+ libui \
+ libutils \
LOCAL_MODULE:= libgui
@@ -42,13 +45,17 @@ endif
ifeq ($(TARGET_BOARD_PLATFORM), s5pc110)
LOCAL_CFLAGS += -DUSE_FENCE_SYNC
endif
+ifeq ($(TARGET_BOARD_PLATFORM), exynos5)
+ LOCAL_CFLAGS += -DUSE_NATIVE_FENCE_SYNC
+ LOCAL_CFLAGS += -DUSE_WAIT_SYNC
+endif
ifneq ($(filter generic%,$(TARGET_DEVICE)),)
# Emulator build
LOCAL_CFLAGS += -DUSE_FENCE_SYNC
endif
-ifeq ($(TARGET_BOARD_PLATFORM), tegra)
- LOCAL_CFLAGS += -DALLOW_DEQUEUE_CURRENT_BUFFER
+ifeq ($(TARGET_BOARD_PLATFORM), msm8960)
+ LOCAL_CFLAGS += -DUSE_NATIVE_FENCE_SYNC
endif
include $(BUILD_SHARED_LIBRARY)
diff --git a/libs/gui/BufferItemConsumer.cpp b/libs/gui/BufferItemConsumer.cpp
new file mode 100644
index 0000000..5079883
--- /dev/null
+++ b/libs/gui/BufferItemConsumer.cpp
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2012 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_NDEBUG 0
+#define LOG_TAG "BufferItemConsumer"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+#include <utils/Log.h>
+
+#include <gui/BufferItemConsumer.h>
+
+#define BI_LOGV(x, ...) ALOGV("[%s] "x, mName.string(), ##__VA_ARGS__)
+#define BI_LOGD(x, ...) ALOGD("[%s] "x, mName.string(), ##__VA_ARGS__)
+#define BI_LOGI(x, ...) ALOGI("[%s] "x, mName.string(), ##__VA_ARGS__)
+#define BI_LOGW(x, ...) ALOGW("[%s] "x, mName.string(), ##__VA_ARGS__)
+#define BI_LOGE(x, ...) ALOGE("[%s] "x, mName.string(), ##__VA_ARGS__)
+
+namespace android {
+
+BufferItemConsumer::BufferItemConsumer(uint32_t consumerUsage,
+ int bufferCount, bool synchronousMode) :
+ ConsumerBase(new BufferQueue(true) )
+{
+ mBufferQueue->setConsumerUsageBits(consumerUsage);
+ mBufferQueue->setSynchronousMode(synchronousMode);
+ mBufferQueue->setMaxAcquiredBufferCount(bufferCount);
+}
+
+BufferItemConsumer::~BufferItemConsumer() {
+}
+
+void BufferItemConsumer::setName(const String8& name) {
+ Mutex::Autolock _l(mMutex);
+ mName = name;
+ mBufferQueue->setConsumerName(name);
+}
+
+status_t BufferItemConsumer::acquireBuffer(BufferItem *item, bool waitForFence) {
+ status_t err;
+
+ if (!item) return BAD_VALUE;
+
+ Mutex::Autolock _l(mMutex);
+
+ err = acquireBufferLocked(item);
+ if (err != OK) {
+ if (err != NO_BUFFER_AVAILABLE) {
+ BI_LOGE("Error acquiring buffer: %s (%d)", strerror(err), err);
+ }
+ return err;
+ }
+
+ if (waitForFence && item->mFence.get()) {
+ err = item->mFence->waitForever(1000, "BufferItemConsumer::acquireBuffer");
+ if (err != OK) {
+ BI_LOGE("Failed to wait for fence of acquired buffer: %s (%d)",
+ strerror(-err), err);
+ return err;
+ }
+ }
+
+ item->mGraphicBuffer = mSlots[item->mBuf].mGraphicBuffer;
+
+ return OK;
+}
+
+status_t BufferItemConsumer::releaseBuffer(const BufferItem &item,
+ const sp<Fence>& releaseFence) {
+ status_t err;
+
+ Mutex::Autolock _l(mMutex);
+
+ err = addReleaseFenceLocked(item.mBuf, releaseFence);
+
+ err = releaseBufferLocked(item.mBuf, EGL_NO_DISPLAY,
+ EGL_NO_SYNC_KHR);
+ if (err != OK) {
+ BI_LOGE("Failed to release buffer: %s (%d)",
+ strerror(-err), err);
+ }
+ return err;
+}
+
+} // namespace android
diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp
index a0774cf..086e298 100644
--- a/libs/gui/BufferQueue.cpp
+++ b/libs/gui/BufferQueue.cpp
@@ -32,23 +32,6 @@
#include <gui/SurfaceTexture.h>
#include <utils/Trace.h>
-// This compile option causes SurfaceTexture to return the buffer that is currently
-// attached to the GL texture from dequeueBuffer when no other buffers are
-// available. It requires the drivers (Gralloc, GL, OMX IL, and Camera) to do
-// implicit cross-process synchronization to prevent the buffer from being
-// written to before the buffer has (a) been detached from the GL texture and
-// (b) all GL reads from the buffer have completed.
-
-// During refactoring, do not support dequeuing the current buffer
-#undef ALLOW_DEQUEUE_CURRENT_BUFFER
-
-#ifdef ALLOW_DEQUEUE_CURRENT_BUFFER
-#define FLAG_ALLOW_DEQUEUE_CURRENT_BUFFER true
-#warning "ALLOW_DEQUEUE_CURRENT_BUFFER enabled"
-#else
-#define FLAG_ALLOW_DEQUEUE_CURRENT_BUFFER false
-#endif
-
// Macros for including the BufferQueue name in log messages
#define ST_LOGV(x, ...) ALOGV("[%s] "x, mConsumerName.string(), ##__VA_ARGS__)
#define ST_LOGD(x, ...) ALOGD("[%s] "x, mConsumerName.string(), ##__VA_ARGS__)
@@ -81,23 +64,20 @@ static const char* scalingModeName(int scalingMode) {
}
}
-BufferQueue::BufferQueue( bool allowSynchronousMode, int bufferCount ) :
+BufferQueue::BufferQueue(bool allowSynchronousMode,
+ const sp<IGraphicBufferAlloc>& allocator) :
mDefaultWidth(1),
mDefaultHeight(1),
- mPixelFormat(PIXEL_FORMAT_RGBA_8888),
- mMinUndequeuedBuffers(bufferCount),
- mMinAsyncBufferSlots(bufferCount + 1),
- mMinSyncBufferSlots(bufferCount),
- mBufferCount(mMinAsyncBufferSlots),
- mClientBufferCount(0),
- mServerBufferCount(mMinAsyncBufferSlots),
+ mMaxAcquiredBufferCount(1),
+ mDefaultMaxBufferCount(2),
+ mOverrideMaxBufferCount(0),
mSynchronousMode(false),
mAllowSynchronousMode(allowSynchronousMode),
mConnectedApi(NO_CONNECTED_API),
mAbandoned(false),
mFrameCounter(0),
mBufferHasBeenQueued(false),
- mDefaultBufferFormat(0),
+ mDefaultBufferFormat(PIXEL_FORMAT_RGBA_8888),
mConsumerUsageBits(0),
mTransformHint(0)
{
@@ -105,10 +85,14 @@ BufferQueue::BufferQueue( bool allowSynchronousMode, int bufferCount ) :
mConsumerName = String8::format("unnamed-%d-%d", getpid(), createProcessUniqueId());
ST_LOGV("BufferQueue");
- sp<ISurfaceComposer> composer(ComposerService::getComposerService());
- mGraphicBufferAlloc = composer->createGraphicBufferAlloc();
- if (mGraphicBufferAlloc == 0) {
- ST_LOGE("createGraphicBufferAlloc() failed in BufferQueue()");
+ if (allocator == NULL) {
+ sp<ISurfaceComposer> composer(ComposerService::getComposerService());
+ mGraphicBufferAlloc = composer->createGraphicBufferAlloc();
+ if (mGraphicBufferAlloc == 0) {
+ ST_LOGE("createGraphicBufferAlloc() failed in BufferQueue()");
+ }
+ } else {
+ mGraphicBufferAlloc = allocator;
}
}
@@ -116,38 +100,13 @@ BufferQueue::~BufferQueue() {
ST_LOGV("~BufferQueue");
}
-status_t BufferQueue::setBufferCountServerLocked(int bufferCount) {
- if (bufferCount > NUM_BUFFER_SLOTS)
+status_t BufferQueue::setDefaultMaxBufferCountLocked(int count) {
+ if (count < 2 || count > NUM_BUFFER_SLOTS)
return BAD_VALUE;
- // special-case, nothing to do
- if (bufferCount == mBufferCount)
- return OK;
-
- if (!mClientBufferCount &&
- bufferCount >= mBufferCount) {
- // easy, we just have more buffers
- mBufferCount = bufferCount;
- mServerBufferCount = bufferCount;
- mDequeueCondition.broadcast();
- } else {
- // we're here because we're either
- // - reducing the number of available buffers
- // - or there is a client-buffer-count in effect
-
- // less than 2 buffers is never allowed
- if (bufferCount < 2)
- return BAD_VALUE;
-
- // when there is non client-buffer-count in effect, the client is not
- // allowed to dequeue more than one buffer at a time,
- // so the next time they dequeue a buffer, we know that they don't
- // own one. the actual resizing will happen during the next
- // dequeueBuffer.
+ mDefaultMaxBufferCount = count;
+ mDequeueCondition.broadcast();
- mServerBufferCount = bufferCount;
- mDequeueCondition.broadcast();
- }
return OK;
}
@@ -174,6 +133,7 @@ status_t BufferQueue::setConsumerUsageBits(uint32_t usage) {
}
status_t BufferQueue::setTransformHint(uint32_t hint) {
+ ST_LOGV("setTransformHint: %02x", hint);
Mutex::Autolock lock(mMutex);
mTransformHint = hint;
return OK;
@@ -196,20 +156,19 @@ status_t BufferQueue::setBufferCount(int bufferCount) {
}
// Error out if the user has dequeued buffers
- for (int i=0 ; i<mBufferCount ; i++) {
+ int maxBufferCount = getMaxBufferCountLocked();
+ for (int i=0 ; i<maxBufferCount; i++) {
if (mSlots[i].mBufferState == BufferSlot::DEQUEUED) {
ST_LOGE("setBufferCount: client owns some buffers");
return -EINVAL;
}
}
- const int minBufferSlots = mSynchronousMode ?
- mMinSyncBufferSlots : mMinAsyncBufferSlots;
+ const int minBufferSlots = getMinMaxBufferCountLocked();
if (bufferCount == 0) {
- mClientBufferCount = 0;
- bufferCount = (mServerBufferCount >= minBufferSlots) ?
- mServerBufferCount : minBufferSlots;
- return setBufferCountServerLocked(bufferCount);
+ mOverrideMaxBufferCount = 0;
+ mDequeueCondition.broadcast();
+ return OK;
}
if (bufferCount < minBufferSlots) {
@@ -220,11 +179,11 @@ status_t BufferQueue::setBufferCount(int bufferCount) {
// here we're guaranteed that the client doesn't have dequeued buffers
// and will release all of its buffer references.
+ //
+ // XXX: Should this use drainQueueAndFreeBuffersLocked instead?
freeAllBuffersLocked();
- mBufferCount = bufferCount;
- mClientBufferCount = bufferCount;
+ mOverrideMaxBufferCount = bufferCount;
mBufferHasBeenQueued = false;
- mQueue.clear();
mDequeueCondition.broadcast();
listener = mConsumerListener;
} // scope for lock
@@ -255,11 +214,10 @@ int BufferQueue::query(int what, int* outValue)
value = mDefaultHeight;
break;
case NATIVE_WINDOW_FORMAT:
- value = mPixelFormat;
+ value = mDefaultBufferFormat;
break;
case NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS:
- value = mSynchronousMode ?
- (mMinUndequeuedBuffers-1) : mMinUndequeuedBuffers;
+ value = getMinUndequeuedBufferCountLocked();
break;
case NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND:
value = (mQueue.size() >= 2);
@@ -279,9 +237,17 @@ status_t BufferQueue::requestBuffer(int slot, sp<GraphicBuffer>* buf) {
ST_LOGE("requestBuffer: SurfaceTexture has been abandoned!");
return NO_INIT;
}
- if (slot < 0 || mBufferCount <= slot) {
+ int maxBufferCount = getMaxBufferCountLocked();
+ if (slot < 0 || maxBufferCount <= slot) {
ST_LOGE("requestBuffer: slot index out of range [0, %d]: %d",
- mBufferCount, slot);
+ maxBufferCount, slot);
+ return BAD_VALUE;
+ } else if (mSlots[slot].mBufferState != BufferSlot::DEQUEUED) {
+ // XXX: I vaguely recall there was some reason this can be valid, but
+ // for the life of me I can't recall under what circumstances that's
+ // the case.
+ ST_LOGE("requestBuffer: slot %d is not owned by the client (state=%d)",
+ slot, mSlots[slot].mBufferState);
return BAD_VALUE;
}
mSlots[slot].mRequestBufferCalled = true;
@@ -289,8 +255,8 @@ status_t BufferQueue::requestBuffer(int slot, sp<GraphicBuffer>* buf) {
return NO_ERROR;
}
-status_t BufferQueue::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h,
- uint32_t format, uint32_t usage) {
+status_t BufferQueue::dequeueBuffer(int *outBuf, sp<Fence>& outFence,
+ uint32_t w, uint32_t h, uint32_t format, uint32_t usage) {
ATRACE_CALL();
ST_LOGV("dequeueBuffer: w=%d h=%d fmt=%#x usage=%#x", w, h, format, usage);
@@ -301,7 +267,7 @@ status_t BufferQueue::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h,
status_t returnFlags(OK);
EGLDisplay dpy = EGL_NO_DISPLAY;
- EGLSyncKHR fence = EGL_NO_SYNC_KHR;
+ EGLSyncKHR eglFence = EGL_NO_SYNC_KHR;
{ // Scope for the lock
Mutex::Autolock lock(mMutex);
@@ -313,7 +279,6 @@ status_t BufferQueue::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h,
usage |= mConsumerUsageBits;
int found = -1;
- int foundSync = -1;
int dequeuedCount = 0;
bool tryAgain = true;
while (tryAgain) {
@@ -322,104 +287,67 @@ status_t BufferQueue::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h,
return NO_INIT;
}
- // We need to wait for the FIFO to drain if the number of buffer
- // needs to change.
- //
- // 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()
- // - OR -
- // setBufferCountServer() was set to a value incompatible with
- // the synchronization mode (for instance because the sync mode
- // changed since)
- //
- // As long as this condition is true AND the FIFO is not empty, we
- // wait on mDequeueCondition.
-
- const int minBufferCountNeeded = mSynchronousMode ?
- mMinSyncBufferSlots : mMinAsyncBufferSlots;
-
- const bool numberOfBuffersNeedsToChange = !mClientBufferCount &&
- ((mServerBufferCount != mBufferCount) ||
- (mServerBufferCount < minBufferCountNeeded));
-
- if (!mQueue.isEmpty() && numberOfBuffersNeedsToChange) {
- // wait for the FIFO to drain
- mDequeueCondition.wait(mMutex);
- // NOTE: we continue here because we need to reevaluate our
- // whole state (eg: we could be abandoned or disconnected)
- continue;
- }
+ const int maxBufferCount = getMaxBufferCountLocked();
- if (numberOfBuffersNeedsToChange) {
- // here we're guaranteed that mQueue is empty
- freeAllBuffersLocked();
- mBufferCount = mServerBufferCount;
- if (mBufferCount < minBufferCountNeeded)
- mBufferCount = minBufferCountNeeded;
- mBufferHasBeenQueued = false;
- returnFlags |= ISurfaceTexture::RELEASE_ALL_BUFFERS;
+ // Free up any buffers that are in slots beyond the max buffer
+ // count.
+ for (int i = maxBufferCount; i < NUM_BUFFER_SLOTS; i++) {
+ assert(mSlots[i].mBufferState == BufferSlot::FREE);
+ if (mSlots[i].mGraphicBuffer != NULL) {
+ freeBufferLocked(i);
+ returnFlags |= ISurfaceTexture::RELEASE_ALL_BUFFERS;
+ }
}
// look for a free buffer to give to the client
found = INVALID_BUFFER_SLOT;
- foundSync = INVALID_BUFFER_SLOT;
dequeuedCount = 0;
- for (int i = 0; i < mBufferCount; i++) {
+ for (int i = 0; i < maxBufferCount; i++) {
const int state = mSlots[i].mBufferState;
if (state == BufferSlot::DEQUEUED) {
dequeuedCount++;
}
- // this logic used to be if (FLAG_ALLOW_DEQUEUE_CURRENT_BUFFER)
- // but dequeuing the current buffer is disabled.
- if (false) {
- // This functionality has been temporarily removed so
- // BufferQueue and SurfaceTexture can be refactored into
- // separate objects
- } else {
- if (state == BufferSlot::FREE) {
- /* We return the oldest of the free buffers to avoid
- * stalling the producer if possible. This is because
- * the consumer may still have pending reads of the
- * buffers in flight.
- */
- bool isOlder = mSlots[i].mFrameNumber <
- mSlots[found].mFrameNumber;
- if (found < 0 || isOlder) {
- foundSync = i;
- found = i;
- }
+ if (state == BufferSlot::FREE) {
+ /* We return the oldest of the free buffers to avoid
+ * stalling the producer if possible. This is because
+ * the consumer may still have pending reads of the
+ * buffers in flight.
+ */
+ if ((found < 0) ||
+ mSlots[i].mFrameNumber < mSlots[found].mFrameNumber) {
+ found = i;
}
}
}
// clients are not allowed to dequeue more than one buffer
// if they didn't set a buffer count.
- if (!mClientBufferCount && dequeuedCount) {
+ if (!mOverrideMaxBufferCount && dequeuedCount) {
ST_LOGE("dequeueBuffer: can't dequeue multiple buffers without "
"setting the buffer count");
return -EINVAL;
}
// See whether a buffer has been queued since the last
- // setBufferCount so we know whether to perform the
- // mMinUndequeuedBuffers check below.
+ // setBufferCount so we know whether to perform the min undequeued
+ // buffers check below.
if (mBufferHasBeenQueued) {
// make sure the client is not trying to dequeue more buffers
// than allowed.
- const int avail = mBufferCount - (dequeuedCount+1);
- if (avail < (mMinUndequeuedBuffers-int(mSynchronousMode))) {
- ST_LOGE("dequeueBuffer: mMinUndequeuedBuffers=%d exceeded "
- "(dequeued=%d)",
- mMinUndequeuedBuffers-int(mSynchronousMode),
- dequeuedCount);
+ const int newUndequeuedCount = maxBufferCount - (dequeuedCount+1);
+ const int minUndequeuedCount = getMinUndequeuedBufferCountLocked();
+ if (newUndequeuedCount < minUndequeuedCount) {
+ ST_LOGE("dequeueBuffer: min undequeued buffer count (%d) "
+ "exceeded (dequeued=%d undequeudCount=%d)",
+ minUndequeuedCount, dequeuedCount,
+ newUndequeuedCount);
return -EBUSY;
}
}
- // if no buffer is found, wait for a buffer to be released
+ // If no buffer is found, wait for a buffer to be released or for
+ // the max buffer count to change.
tryAgain = found == INVALID_BUFFER_SLOT;
if (tryAgain) {
mDequeueCondition.wait(mMutex);
@@ -445,12 +373,6 @@ status_t BufferQueue::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h,
h = mDefaultHeight;
}
- const bool updateFormat = (format != 0);
- if (!updateFormat) {
- // keep the current (or default) format
- format = mPixelFormat;
- }
-
// buffer is now in DEQUEUED (but can also be current at the same time,
// if we're in synchronous mode)
mSlots[buf].mBufferState = BufferSlot::DEQUEUED;
@@ -462,35 +384,49 @@ status_t BufferQueue::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h,
(uint32_t(buffer->format) != format) ||
((uint32_t(buffer->usage) & usage) != usage))
{
- status_t error;
- sp<GraphicBuffer> graphicBuffer(
- mGraphicBufferAlloc->createGraphicBuffer(
- w, h, format, usage, &error));
- if (graphicBuffer == 0) {
- ST_LOGE("dequeueBuffer: SurfaceComposer::createGraphicBuffer "
- "failed");
- return error;
- }
- if (updateFormat) {
- mPixelFormat = format;
- }
-
mSlots[buf].mAcquireCalled = false;
- mSlots[buf].mGraphicBuffer = graphicBuffer;
+ mSlots[buf].mGraphicBuffer = NULL;
mSlots[buf].mRequestBufferCalled = false;
- mSlots[buf].mFence = EGL_NO_SYNC_KHR;
+ mSlots[buf].mEglFence = EGL_NO_SYNC_KHR;
+ mSlots[buf].mFence.clear();
mSlots[buf].mEglDisplay = EGL_NO_DISPLAY;
returnFlags |= ISurfaceTexture::BUFFER_NEEDS_REALLOCATION;
}
dpy = mSlots[buf].mEglDisplay;
- fence = mSlots[buf].mFence;
- mSlots[buf].mFence = EGL_NO_SYNC_KHR;
+ eglFence = mSlots[buf].mEglFence;
+ outFence = mSlots[buf].mFence;
+ mSlots[buf].mEglFence = EGL_NO_SYNC_KHR;
+ mSlots[buf].mFence.clear();
} // end lock scope
- if (fence != EGL_NO_SYNC_KHR) {
- EGLint result = eglClientWaitSyncKHR(dpy, fence, 0, 1000000000);
+ if (returnFlags & ISurfaceTexture::BUFFER_NEEDS_REALLOCATION) {
+ status_t error;
+ sp<GraphicBuffer> graphicBuffer(
+ mGraphicBufferAlloc->createGraphicBuffer(
+ w, h, format, usage, &error));
+ if (graphicBuffer == 0) {
+ ST_LOGE("dequeueBuffer: SurfaceComposer::createGraphicBuffer "
+ "failed");
+ return error;
+ }
+
+ { // Scope for the lock
+ Mutex::Autolock lock(mMutex);
+
+ if (mAbandoned) {
+ ST_LOGE("dequeueBuffer: SurfaceTexture has been abandoned!");
+ return NO_INIT;
+ }
+
+ mSlots[*outBuf].mGraphicBuffer = graphicBuffer;
+ }
+ }
+
+
+ if (eglFence != EGL_NO_SYNC_KHR) {
+ EGLint result = eglClientWaitSyncKHR(dpy, eglFence, 0, 1000000000);
// If something goes wrong, log the error, but return the buffer without
// synchronizing access to it. It's too late at this point to abort the
// dequeue operation.
@@ -499,7 +435,7 @@ status_t BufferQueue::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h,
} else if (result == EGL_TIMEOUT_EXPIRED_KHR) {
ST_LOGE("dequeueBuffer: timeout waiting for fence");
}
- eglDestroySyncKHR(dpy, fence);
+ eglDestroySyncKHR(dpy, eglFence);
}
ST_LOGV("dequeueBuffer: returning slot=%d buf=%p flags=%#x", *outBuf,
@@ -549,8 +485,9 @@ status_t BufferQueue::queueBuffer(int buf,
uint32_t transform;
int scalingMode;
int64_t timestamp;
+ sp<Fence> fence;
- input.deflate(&timestamp, &crop, &scalingMode, &transform);
+ input.deflate(&timestamp, &crop, &scalingMode, &transform, &fence);
ST_LOGV("queueBuffer: slot=%d time=%#llx crop=[%d,%d,%d,%d] tr=%#x "
"scale=%s",
@@ -565,9 +502,10 @@ status_t BufferQueue::queueBuffer(int buf,
ST_LOGE("queueBuffer: SurfaceTexture has been abandoned!");
return NO_INIT;
}
- if (buf < 0 || buf >= mBufferCount) {
+ int maxBufferCount = getMaxBufferCountLocked();
+ if (buf < 0 || buf >= maxBufferCount) {
ST_LOGE("queueBuffer: slot index out of range [0, %d]: %d",
- mBufferCount, buf);
+ maxBufferCount, buf);
return -EINVAL;
} else if (mSlots[buf].mBufferState != BufferSlot::DEQUEUED) {
ST_LOGE("queueBuffer: slot %d is not owned by the client "
@@ -617,6 +555,7 @@ status_t BufferQueue::queueBuffer(int buf,
mSlots[buf].mTimestamp = timestamp;
mSlots[buf].mCrop = crop;
mSlots[buf].mTransform = transform;
+ mSlots[buf].mFence = fence;
switch (scalingMode) {
case NATIVE_WINDOW_SCALING_MODE_FREEZE:
@@ -650,7 +589,7 @@ status_t BufferQueue::queueBuffer(int buf,
return OK;
}
-void BufferQueue::cancelBuffer(int buf) {
+void BufferQueue::cancelBuffer(int buf, sp<Fence> fence) {
ATRACE_CALL();
ST_LOGV("cancelBuffer: slot=%d", buf);
Mutex::Autolock lock(mMutex);
@@ -660,9 +599,10 @@ void BufferQueue::cancelBuffer(int buf) {
return;
}
- if (buf < 0 || buf >= mBufferCount) {
+ int maxBufferCount = getMaxBufferCountLocked();
+ if (buf < 0 || buf >= maxBufferCount) {
ST_LOGE("cancelBuffer: slot index out of range [0, %d]: %d",
- mBufferCount, buf);
+ maxBufferCount, buf);
return;
} else if (mSlots[buf].mBufferState != BufferSlot::DEQUEUED) {
ST_LOGE("cancelBuffer: slot %d is not owned by the client (state=%d)",
@@ -671,6 +611,7 @@ void BufferQueue::cancelBuffer(int buf) {
}
mSlots[buf].mBufferState = BufferSlot::FREE;
mSlots[buf].mFrameNumber = 0;
+ mSlots[buf].mFence = fence;
mDequeueCondition.broadcast();
}
@@ -781,11 +722,14 @@ void BufferQueue::dump(String8& result, const char* prefix,
fifo.append(buffer);
}
+ int maxBufferCount = getMaxBufferCountLocked();
+
snprintf(buffer, SIZE,
- "%s-BufferQueue mBufferCount=%d, mSynchronousMode=%d, default-size=[%dx%d], "
- "mPixelFormat=%d, FIFO(%d)={%s}\n",
- prefix, mBufferCount, mSynchronousMode, mDefaultWidth,
- mDefaultHeight, mPixelFormat, fifoSize, fifo.string());
+ "%s-BufferQueue maxBufferCount=%d, mSynchronousMode=%d, default-size=[%dx%d], "
+ "default-format=%d, transform-hint=%02x, FIFO(%d)={%s}\n",
+ prefix, maxBufferCount, mSynchronousMode, mDefaultWidth,
+ mDefaultHeight, mDefaultBufferFormat, mTransformHint,
+ fifoSize, fifo.string());
result.append(buffer);
@@ -801,7 +745,7 @@ void BufferQueue::dump(String8& result, const char* prefix,
}
} stateName;
- for (int i=0 ; i<mBufferCount ; i++) {
+ for (int i=0 ; i<maxBufferCount ; i++) {
const BufferSlot& slot(mSlots[i]);
snprintf(buffer, SIZE,
"%s%s[%02d] "
@@ -827,20 +771,22 @@ void BufferQueue::dump(String8& result, const char* prefix,
}
}
-void BufferQueue::freeBufferLocked(int i) {
- mSlots[i].mGraphicBuffer = 0;
- if (mSlots[i].mBufferState == BufferSlot::ACQUIRED) {
- mSlots[i].mNeedsCleanupOnRelease = true;
+void BufferQueue::freeBufferLocked(int slot) {
+ ST_LOGV("freeBufferLocked: slot=%d", slot);
+ mSlots[slot].mGraphicBuffer = 0;
+ if (mSlots[slot].mBufferState == BufferSlot::ACQUIRED) {
+ mSlots[slot].mNeedsCleanupOnRelease = true;
}
- mSlots[i].mBufferState = BufferSlot::FREE;
- mSlots[i].mFrameNumber = 0;
- mSlots[i].mAcquireCalled = false;
+ mSlots[slot].mBufferState = BufferSlot::FREE;
+ mSlots[slot].mFrameNumber = 0;
+ mSlots[slot].mAcquireCalled = false;
// destroy fence as BufferQueue now takes ownership
- if (mSlots[i].mFence != EGL_NO_SYNC_KHR) {
- eglDestroySyncKHR(mSlots[i].mEglDisplay, mSlots[i].mFence);
- mSlots[i].mFence = EGL_NO_SYNC_KHR;
+ if (mSlots[slot].mEglFence != EGL_NO_SYNC_KHR) {
+ eglDestroySyncKHR(mSlots[slot].mEglDisplay, mSlots[slot].mEglFence);
+ mSlots[slot].mEglFence = EGL_NO_SYNC_KHR;
}
+ mSlots[slot].mFence.clear();
}
void BufferQueue::freeAllBuffersLocked() {
@@ -856,6 +802,23 @@ void BufferQueue::freeAllBuffersLocked() {
status_t BufferQueue::acquireBuffer(BufferItem *buffer) {
ATRACE_CALL();
Mutex::Autolock _l(mMutex);
+
+ // Check that the consumer doesn't currently have the maximum number of
+ // buffers acquired. We allow the max buffer count to be exceeded by one
+ // buffer, so that the consumer can successfully set up the newly acquired
+ // buffer before releasing the old one.
+ int numAcquiredBuffers = 0;
+ for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
+ if (mSlots[i].mBufferState == BufferSlot::ACQUIRED) {
+ numAcquiredBuffers++;
+ }
+ }
+ if (numAcquiredBuffers >= mMaxAcquiredBufferCount+1) {
+ ST_LOGE("acquireBuffer: max acquired buffer count reached: %d (max=%d)",
+ numAcquiredBuffers, mMaxAcquiredBufferCount);
+ return INVALID_OPERATION;
+ }
+
// check if queue is empty
// In asynchronous mode the list is guaranteed to be one buffer
// deep, while in synchronous mode we use the oldest buffer.
@@ -876,9 +839,13 @@ status_t BufferQueue::acquireBuffer(BufferItem *buffer) {
buffer->mFrameNumber = mSlots[buf].mFrameNumber;
buffer->mTimestamp = mSlots[buf].mTimestamp;
buffer->mBuf = buf;
- mSlots[buf].mAcquireCalled = true;
+ buffer->mFence = mSlots[buf].mFence;
+ mSlots[buf].mAcquireCalled = true;
+ mSlots[buf].mNeedsCleanupOnRelease = false;
mSlots[buf].mBufferState = BufferSlot::ACQUIRED;
+ mSlots[buf].mFence.clear();
+
mQueue.erase(front);
mDequeueCondition.broadcast();
@@ -891,7 +858,7 @@ status_t BufferQueue::acquireBuffer(BufferItem *buffer) {
}
status_t BufferQueue::releaseBuffer(int buf, EGLDisplay display,
- EGLSyncKHR fence) {
+ EGLSyncKHR eglFence, const sp<Fence>& fence) {
ATRACE_CALL();
ATRACE_BUFFER_INDEX(buf);
@@ -902,6 +869,7 @@ status_t BufferQueue::releaseBuffer(int buf, EGLDisplay display,
}
mSlots[buf].mEglDisplay = display;
+ mSlots[buf].mEglFence = eglFence;
mSlots[buf].mFence = fence;
// The buffer can now only be released if its in the acquired state
@@ -987,10 +955,25 @@ status_t BufferQueue::setDefaultBufferSize(uint32_t w, uint32_t h)
return OK;
}
-status_t BufferQueue::setBufferCountServer(int bufferCount) {
+status_t BufferQueue::setDefaultMaxBufferCount(int bufferCount) {
ATRACE_CALL();
Mutex::Autolock lock(mMutex);
- return setBufferCountServerLocked(bufferCount);
+ return setDefaultMaxBufferCountLocked(bufferCount);
+}
+
+status_t BufferQueue::setMaxAcquiredBufferCount(int maxAcquiredBuffers) {
+ ATRACE_CALL();
+ Mutex::Autolock lock(mMutex);
+ if (maxAcquiredBuffers < 1 || maxAcquiredBuffers > MAX_MAX_ACQUIRED_BUFFERS) {
+ ST_LOGE("setMaxAcquiredBufferCount: invalid count specified: %d",
+ maxAcquiredBuffers);
+ return BAD_VALUE;
+ }
+ if (mConnectedApi != NO_CONNECTED_API) {
+ return INVALID_OPERATION;
+ }
+ mMaxAcquiredBufferCount = maxAcquiredBuffers;
+ return OK;
}
void BufferQueue::freeAllBuffersExceptHeadLocked() {
@@ -1034,6 +1017,41 @@ status_t BufferQueue::drainQueueAndFreeBuffersLocked() {
return err;
}
+int BufferQueue::getMinMaxBufferCountLocked() const {
+ return getMinUndequeuedBufferCountLocked() + 1;
+}
+
+int BufferQueue::getMinUndequeuedBufferCountLocked() const {
+ return mSynchronousMode ? mMaxAcquiredBufferCount :
+ mMaxAcquiredBufferCount + 1;
+}
+
+int BufferQueue::getMaxBufferCountLocked() const {
+ int minMaxBufferCount = getMinMaxBufferCountLocked();
+
+ int maxBufferCount = mDefaultMaxBufferCount;
+ if (maxBufferCount < minMaxBufferCount) {
+ maxBufferCount = minMaxBufferCount;
+ }
+ if (mOverrideMaxBufferCount != 0) {
+ assert(mOverrideMaxBufferCount >= minMaxBufferCount);
+ maxBufferCount = mOverrideMaxBufferCount;
+ }
+
+ // Any buffers that are dequeued by the producer or sitting in the queue
+ // waiting to be consumed need to have their slots preserved. Such
+ // buffers will temporarily keep the max buffer count up until the slots
+ // no longer need to be preserved.
+ for (int i = maxBufferCount; i < NUM_BUFFER_SLOTS; i++) {
+ BufferSlot::BufferState state = mSlots[i].mBufferState;
+ if (state == BufferSlot::QUEUED || state == BufferSlot::DEQUEUED) {
+ maxBufferCount = i + 1;
+ }
+ }
+
+ return maxBufferCount;
+}
+
BufferQueue::ProxyConsumerListener::ProxyConsumerListener(
const wp<BufferQueue::ConsumerListener>& consumerListener):
mConsumerListener(consumerListener) {}
diff --git a/libs/gui/CleanSpec.mk b/libs/gui/CleanSpec.mk
new file mode 100644
index 0000000..5a5144c
--- /dev/null
+++ b/libs/gui/CleanSpec.mk
@@ -0,0 +1,52 @@
+# Copyright (C) 2012 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.
+#
+
+# If you don't need to do a full clean build but would like to touch
+# a file or delete some intermediate files, add a clean step to the end
+# of the list. These steps will only be run once, if they haven't been
+# run before.
+#
+# E.g.:
+# $(call add-clean-step, touch -c external/sqlite/sqlite3.h)
+# $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libz_intermediates)
+#
+# Always use "touch -c" and "rm -f" or "rm -rf" to gracefully deal with
+# files that are missing or have been moved.
+#
+# Use $(PRODUCT_OUT) to get to the "out/target/product/blah/" directory.
+# Use $(OUT_DIR) to refer to the "out" directory.
+#
+# If you need to re-do something that's already mentioned, just copy
+# the command and add it to the bottom of the list. E.g., if a change
+# that you made last week required touching a file and a change you
+# made today requires touching the same file, just copy the old
+# touch step and add it to the end of the list.
+#
+# ************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
+# ************************************************
+
+# For example:
+#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/AndroidTests_intermediates)
+#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/core_intermediates)
+#$(call add-clean-step, find $(OUT_DIR) -type f -name "IGTalkSession*" -print0 | xargs -0 rm -f)
+#$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*)
+
+# ************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
+# ************************************************
+$(call add-clean-step, find $(PRODUCT_OUT) -type f -name "libgui*" -print0 | xargs -0 rm -f)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libgui_intermediates)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libgui_intermediates)
diff --git a/libs/gui/ConsumerBase.cpp b/libs/gui/ConsumerBase.cpp
new file mode 100644
index 0000000..624d7e0
--- /dev/null
+++ b/libs/gui/ConsumerBase.cpp
@@ -0,0 +1,236 @@
+/*
+ * Copyright (C) 2010 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 "ConsumerBase"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+//#define LOG_NDEBUG 0
+
+#define GL_GLEXT_PROTOTYPES
+#define EGL_EGLEXT_PROTOTYPES
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+
+#include <hardware/hardware.h>
+
+#include <gui/IGraphicBufferAlloc.h>
+#include <gui/ISurfaceComposer.h>
+#include <gui/SurfaceComposerClient.h>
+#include <gui/ConsumerBase.h>
+
+#include <private/gui/ComposerService.h>
+
+#include <utils/Log.h>
+#include <utils/String8.h>
+#include <utils/Trace.h>
+
+// Macros for including the ConsumerBase name in log messages
+#define CB_LOGV(x, ...) ALOGV("[%s] "x, mName.string(), ##__VA_ARGS__)
+#define CB_LOGD(x, ...) ALOGD("[%s] "x, mName.string(), ##__VA_ARGS__)
+#define CB_LOGI(x, ...) ALOGI("[%s] "x, mName.string(), ##__VA_ARGS__)
+#define CB_LOGW(x, ...) ALOGW("[%s] "x, mName.string(), ##__VA_ARGS__)
+#define CB_LOGE(x, ...) ALOGE("[%s] "x, mName.string(), ##__VA_ARGS__)
+
+namespace android {
+
+// Get an ID that's unique within this process.
+static int32_t createProcessUniqueId() {
+ static volatile int32_t globalCounter = 0;
+ return android_atomic_inc(&globalCounter);
+}
+
+ConsumerBase::ConsumerBase(const sp<BufferQueue>& bufferQueue) :
+ mAbandoned(false),
+ mBufferQueue(bufferQueue) {
+ // Choose a name using the PID and a process-unique ID.
+ mName = String8::format("unnamed-%d-%d", getpid(), createProcessUniqueId());
+
+ // Note that we can't create an sp<...>(this) in a ctor that will not keep a
+ // reference once the ctor ends, as that would cause the refcount of 'this'
+ // dropping to 0 at the end of the ctor. Since all we need is a wp<...>
+ // that's what we create.
+ wp<BufferQueue::ConsumerListener> listener;
+ sp<BufferQueue::ConsumerListener> proxy;
+ listener = static_cast<BufferQueue::ConsumerListener*>(this);
+ proxy = new BufferQueue::ProxyConsumerListener(listener);
+
+ status_t err = mBufferQueue->consumerConnect(proxy);
+ if (err != NO_ERROR) {
+ CB_LOGE("SurfaceTexture: error connecting to BufferQueue: %s (%d)",
+ strerror(-err), err);
+ } else {
+ mBufferQueue->setConsumerName(mName);
+ }
+}
+
+ConsumerBase::~ConsumerBase() {
+ CB_LOGV("~ConsumerBase");
+ abandon();
+}
+
+void ConsumerBase::freeBufferLocked(int slotIndex) {
+ CB_LOGV("freeBufferLocked: slotIndex=%d", slotIndex);
+ mSlots[slotIndex].mGraphicBuffer = 0;
+ mSlots[slotIndex].mFence = 0;
+}
+
+// Used for refactoring, should not be in final interface
+sp<BufferQueue> ConsumerBase::getBufferQueue() const {
+ Mutex::Autolock lock(mMutex);
+ return mBufferQueue;
+}
+
+void ConsumerBase::onFrameAvailable() {
+ CB_LOGV("onFrameAvailable");
+
+ sp<FrameAvailableListener> listener;
+ { // scope for the lock
+ Mutex::Autolock lock(mMutex);
+ listener = mFrameAvailableListener;
+ }
+
+ if (listener != NULL) {
+ CB_LOGV("actually calling onFrameAvailable");
+ listener->onFrameAvailable();
+ }
+}
+
+void ConsumerBase::onBuffersReleased() {
+ Mutex::Autolock lock(mMutex);
+
+ CB_LOGV("onBuffersReleased");
+
+ if (mAbandoned) {
+ // Nothing to do if we're already abandoned.
+ return;
+ }
+
+ uint32_t mask = 0;
+ mBufferQueue->getReleasedBuffers(&mask);
+ for (int i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
+ if (mask & (1 << i)) {
+ freeBufferLocked(i);
+ }
+ }
+}
+
+void ConsumerBase::abandon() {
+ CB_LOGV("abandon");
+ Mutex::Autolock lock(mMutex);
+
+ if (!mAbandoned) {
+ abandonLocked();
+ mAbandoned = true;
+ }
+}
+
+void ConsumerBase::abandonLocked() {
+ CB_LOGV("abandonLocked");
+ for (int i =0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
+ freeBufferLocked(i);
+ }
+ // disconnect from the BufferQueue
+ mBufferQueue->consumerDisconnect();
+ mBufferQueue.clear();
+}
+
+void ConsumerBase::setFrameAvailableListener(
+ const sp<FrameAvailableListener>& listener) {
+ CB_LOGV("setFrameAvailableListener");
+ Mutex::Autolock lock(mMutex);
+ mFrameAvailableListener = listener;
+}
+
+void ConsumerBase::dump(String8& result) const {
+ char buffer[1024];
+ dump(result, "", buffer, 1024);
+}
+
+void ConsumerBase::dump(String8& result, const char* prefix,
+ char* buffer, size_t size) const {
+ Mutex::Autolock _l(mMutex);
+ dumpLocked(result, prefix, buffer, size);
+}
+
+void ConsumerBase::dumpLocked(String8& result, const char* prefix,
+ char* buffer, size_t SIZE) const {
+ snprintf(buffer, SIZE, "%smAbandoned=%d\n", prefix, int(mAbandoned));
+ result.append(buffer);
+
+ if (!mAbandoned) {
+ mBufferQueue->dump(result, prefix, buffer, SIZE);
+ }
+}
+
+status_t ConsumerBase::acquireBufferLocked(BufferQueue::BufferItem *item) {
+ status_t err = mBufferQueue->acquireBuffer(item);
+ if (err != NO_ERROR) {
+ return err;
+ }
+
+ if (item->mGraphicBuffer != NULL) {
+ mSlots[item->mBuf].mGraphicBuffer = item->mGraphicBuffer;
+ }
+
+ mSlots[item->mBuf].mFence = item->mFence;
+
+ CB_LOGV("acquireBufferLocked: -> slot=%d", item->mBuf);
+
+ return OK;
+}
+
+status_t ConsumerBase::addReleaseFence(int slot, const sp<Fence>& fence) {
+ Mutex::Autolock lock(mMutex);
+ return addReleaseFenceLocked(slot, fence);
+}
+
+status_t ConsumerBase::addReleaseFenceLocked(int slot, const sp<Fence>& fence) {
+ CB_LOGV("addReleaseFenceLocked: slot=%d", slot);
+
+ if (!mSlots[slot].mFence.get()) {
+ mSlots[slot].mFence = fence;
+ } else {
+ sp<Fence> mergedFence = Fence::merge(
+ String8::format("%.28s:%d", mName.string(), slot),
+ mSlots[slot].mFence, fence);
+ if (!mergedFence.get()) {
+ CB_LOGE("failed to merge release fences");
+ // synchronization is broken, the best we can do is hope fences
+ // signal in order so the new fence will act like a union
+ mSlots[slot].mFence = fence;
+ return BAD_VALUE;
+ }
+ mSlots[slot].mFence = mergedFence;
+ }
+
+ return OK;
+}
+
+status_t ConsumerBase::releaseBufferLocked(int slot, EGLDisplay display,
+ EGLSyncKHR eglFence) {
+ CB_LOGV("releaseBufferLocked: slot=%d", slot);
+ status_t err = mBufferQueue->releaseBuffer(slot, display, eglFence,
+ mSlots[slot].mFence);
+ if (err == BufferQueue::STALE_BUFFER_SLOT) {
+ freeBufferLocked(slot);
+ }
+
+ mSlots[slot].mFence.clear();
+
+ return err;
+}
+
+} // namespace android \ No newline at end of file
diff --git a/libs/gui/CpuConsumer.cpp b/libs/gui/CpuConsumer.cpp
new file mode 100644
index 0000000..710e1af
--- /dev/null
+++ b/libs/gui/CpuConsumer.cpp
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2012 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_NDEBUG 0
+#define LOG_TAG "CpuConsumer"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+#include <utils/Log.h>
+
+#include <gui/CpuConsumer.h>
+
+#define CC_LOGV(x, ...) ALOGV("[%s] "x, mName.string(), ##__VA_ARGS__)
+#define CC_LOGD(x, ...) ALOGD("[%s] "x, mName.string(), ##__VA_ARGS__)
+#define CC_LOGI(x, ...) ALOGI("[%s] "x, mName.string(), ##__VA_ARGS__)
+#define CC_LOGW(x, ...) ALOGW("[%s] "x, mName.string(), ##__VA_ARGS__)
+#define CC_LOGE(x, ...) ALOGE("[%s] "x, mName.string(), ##__VA_ARGS__)
+
+namespace android {
+
+CpuConsumer::CpuConsumer(uint32_t maxLockedBuffers) :
+ ConsumerBase(new BufferQueue(true) ),
+ mMaxLockedBuffers(maxLockedBuffers),
+ mCurrentLockedBuffers(0)
+{
+
+ for (int i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
+ mBufferPointers[i] = NULL;
+ }
+
+ mBufferQueue->setSynchronousMode(true);
+ mBufferQueue->setConsumerUsageBits(GRALLOC_USAGE_SW_READ_OFTEN);
+ mBufferQueue->setMaxAcquiredBufferCount(maxLockedBuffers);
+}
+
+CpuConsumer::~CpuConsumer() {
+}
+
+void CpuConsumer::setName(const String8& name) {
+ Mutex::Autolock _l(mMutex);
+ mName = name;
+ mBufferQueue->setConsumerName(name);
+}
+
+status_t CpuConsumer::lockNextBuffer(LockedBuffer *nativeBuffer) {
+ status_t err;
+
+ if (!nativeBuffer) return BAD_VALUE;
+ if (mCurrentLockedBuffers == mMaxLockedBuffers) {
+ return INVALID_OPERATION;
+ }
+
+ BufferQueue::BufferItem b;
+
+ Mutex::Autolock _l(mMutex);
+
+ err = acquireBufferLocked(&b);
+ if (err != OK) {
+ if (err == BufferQueue::NO_BUFFER_AVAILABLE) {
+ return BAD_VALUE;
+ } else {
+ CC_LOGE("Error acquiring buffer: %s (%d)", strerror(err), err);
+ return err;
+ }
+ }
+
+ int buf = b.mBuf;
+
+ if (b.mFence.get()) {
+ err = b.mFence->waitForever(1000, "CpuConsumer::lockNextBuffer");
+ if (err != OK) {
+ CC_LOGE("Failed to wait for fence of acquired buffer: %s (%d)",
+ strerror(-err), err);
+ return err;
+ }
+ }
+
+ err = mSlots[buf].mGraphicBuffer->lock(
+ GraphicBuffer::USAGE_SW_READ_OFTEN,
+ b.mCrop,
+ &mBufferPointers[buf]);
+
+ if (mBufferPointers[buf] != NULL && err != OK) {
+ CC_LOGE("Unable to lock buffer for CPU reading: %s (%d)", strerror(-err),
+ err);
+ return err;
+ }
+
+ nativeBuffer->data = reinterpret_cast<uint8_t*>(mBufferPointers[buf]);
+ nativeBuffer->width = mSlots[buf].mGraphicBuffer->getWidth();
+ nativeBuffer->height = mSlots[buf].mGraphicBuffer->getHeight();
+ nativeBuffer->format = mSlots[buf].mGraphicBuffer->getPixelFormat();
+ nativeBuffer->stride = mSlots[buf].mGraphicBuffer->getStride();
+
+ nativeBuffer->crop = b.mCrop;
+ nativeBuffer->transform = b.mTransform;
+ nativeBuffer->scalingMode = b.mScalingMode;
+ nativeBuffer->timestamp = b.mTimestamp;
+ nativeBuffer->frameNumber = b.mFrameNumber;
+
+ mCurrentLockedBuffers++;
+
+ return OK;
+}
+
+status_t CpuConsumer::unlockBuffer(const LockedBuffer &nativeBuffer) {
+ Mutex::Autolock _l(mMutex);
+ int slotIndex = 0;
+ status_t err;
+
+ void *bufPtr = reinterpret_cast<void *>(nativeBuffer.data);
+ for (; slotIndex < BufferQueue::NUM_BUFFER_SLOTS; slotIndex++) {
+ if (bufPtr == mBufferPointers[slotIndex]) break;
+ }
+ if (slotIndex == BufferQueue::NUM_BUFFER_SLOTS) {
+ CC_LOGE("%s: Can't find buffer to free", __FUNCTION__);
+ return BAD_VALUE;
+ }
+
+ mBufferPointers[slotIndex] = NULL;
+ err = mSlots[slotIndex].mGraphicBuffer->unlock();
+ if (err != OK) {
+ CC_LOGE("%s: Unable to unlock graphic buffer %d", __FUNCTION__, slotIndex);
+ return err;
+ }
+ releaseBufferLocked(slotIndex, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR);
+
+ mCurrentLockedBuffers--;
+
+ return OK;
+}
+
+void CpuConsumer::freeBufferLocked(int slotIndex) {
+ if (mBufferPointers[slotIndex] != NULL) {
+ status_t err;
+ CC_LOGW("Buffer %d freed while locked by consumer", slotIndex);
+ mBufferPointers[slotIndex] = NULL;
+ err = mSlots[slotIndex].mGraphicBuffer->unlock();
+ if (err != OK) {
+ CC_LOGE("%s: Unable to unlock graphic buffer %d", __FUNCTION__,
+ slotIndex);
+ }
+ mCurrentLockedBuffers--;
+ }
+ ConsumerBase::freeBufferLocked(slotIndex);
+}
+
+} // namespace android
diff --git a/libs/gui/GuiConfig.cpp b/libs/gui/GuiConfig.cpp
new file mode 100644
index 0000000..bafd21a
--- /dev/null
+++ b/libs/gui/GuiConfig.cpp
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+#include <gui/GuiConfig.h>
+
+namespace android {
+
+void appendGuiConfigString(String8& configStr)
+{
+ static const char* config =
+ " [libgui"
+#ifdef USE_FENCE_SYNC
+ " USE_FENCE_SYNC"
+#endif
+#ifdef USE_NATIVE_FENCE_SYNC
+ " USE_NATIVE_FENCE_SYNC"
+#endif
+#ifdef USE_WAIT_SYNC
+ " USE_WAIT_SYNC"
+#endif
+ "]";
+ configStr.append(config);
+}
+
+}; // namespace android
diff --git a/libs/gui/IGraphicBufferAlloc.cpp b/libs/gui/IGraphicBufferAlloc.cpp
index a70a5e8..139f219 100644
--- a/libs/gui/IGraphicBufferAlloc.cpp
+++ b/libs/gui/IGraphicBufferAlloc.cpp
@@ -55,7 +55,7 @@ public:
status_t result = reply.readInt32();
if (result == NO_ERROR) {
graphicBuffer = new GraphicBuffer();
- reply.read(*graphicBuffer);
+ result = reply.read(*graphicBuffer);
// reply.readStrongBinder();
// here we don't even have to read the BufferReference from
// the parcel, it'll die with the parcel.
diff --git a/libs/gui/ISensorServer.cpp b/libs/gui/ISensorServer.cpp
index 7111092..0b76f37 100644
--- a/libs/gui/ISensorServer.cpp
+++ b/libs/gui/ISensorServer.cpp
@@ -55,7 +55,7 @@ public:
int32_t n = reply.readInt32();
v.setCapacity(n);
while (n--) {
- reply.read(static_cast<Flattenable&>(s));
+ reply.read(s);
v.add(s);
}
return v;
@@ -84,7 +84,7 @@ status_t BnSensorServer::onTransact(
size_t n = v.size();
reply->writeInt32(n);
for (size_t i=0 ; i<n ; i++) {
- reply->write(static_cast<const Flattenable&>(v[i]));
+ reply->write(v[i]);
}
return NO_ERROR;
} break;
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index 1f1794c..85a9488 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -68,26 +68,29 @@ public:
return interface_cast<IGraphicBufferAlloc>(reply.readStrongBinder());
}
- virtual sp<IMemoryHeap> getCblk() const
+ virtual void setTransactionState(
+ const Vector<ComposerState>& state,
+ const Vector<DisplayState>& displays,
+ uint32_t flags)
{
Parcel data, reply;
data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
- remote()->transact(BnSurfaceComposer::GET_CBLK, data, &reply);
- return interface_cast<IMemoryHeap>(reply.readStrongBinder());
- }
-
- virtual void setTransactionState(const Vector<ComposerState>& state,
- int orientation, uint32_t flags)
- {
- Parcel data, reply;
- data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
- Vector<ComposerState>::const_iterator b(state.begin());
- Vector<ComposerState>::const_iterator e(state.end());
- data.writeInt32(state.size());
- for ( ; b != e ; ++b ) {
- b->write(data);
+ {
+ Vector<ComposerState>::const_iterator b(state.begin());
+ Vector<ComposerState>::const_iterator e(state.end());
+ data.writeInt32(state.size());
+ for ( ; b != e ; ++b ) {
+ b->write(data);
+ }
+ }
+ {
+ Vector<DisplayState>::const_iterator b(displays.begin());
+ Vector<DisplayState>::const_iterator e(displays.end());
+ data.writeInt32(displays.size());
+ for ( ; b != e ; ++b ) {
+ b->write(data);
+ }
}
- data.writeInt32(orientation);
data.writeInt32(flags);
remote()->transact(BnSurfaceComposer::SET_TRANSACTION_STATE, data, &reply);
}
@@ -99,15 +102,15 @@ public:
remote()->transact(BnSurfaceComposer::BOOT_FINISHED, data, &reply);
}
- virtual status_t captureScreen(DisplayID dpy,
- sp<IMemoryHeap>* heap,
+ virtual status_t captureScreen(
+ const sp<IBinder>& display, sp<IMemoryHeap>* heap,
uint32_t* width, uint32_t* height, PixelFormat* format,
uint32_t reqWidth, uint32_t reqHeight,
uint32_t minLayerZ, uint32_t maxLayerZ)
{
Parcel data, reply;
data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
- data.writeInt32(dpy);
+ data.writeStrongBinder(display);
data.writeInt32(reqWidth);
data.writeInt32(reqHeight);
data.writeInt32(minLayerZ);
@@ -120,24 +123,6 @@ public:
return reply.readInt32();
}
- virtual status_t turnElectronBeamOff(int32_t mode)
- {
- Parcel data, reply;
- data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
- data.writeInt32(mode);
- remote()->transact(BnSurfaceComposer::TURN_ELECTRON_BEAM_OFF, data, &reply);
- return reply.readInt32();
- }
-
- virtual status_t turnElectronBeamOn(int32_t mode)
- {
- Parcel data, reply;
- data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
- data.writeInt32(mode);
- remote()->transact(BnSurfaceComposer::TURN_ELECTRON_BEAM_ON, data, &reply);
- return reply.readInt32();
- }
-
virtual bool authenticateSurfaceTexture(
const sp<ISurfaceTexture>& surfaceTexture) const
{
@@ -193,6 +178,51 @@ public:
result = interface_cast<IDisplayEventConnection>(reply.readStrongBinder());
return result;
}
+
+ virtual sp<IBinder> createDisplay(const String8& displayName, bool secure)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+ data.writeString8(displayName);
+ data.writeInt32(secure ? 1 : 0);
+ remote()->transact(BnSurfaceComposer::CREATE_DISPLAY, data, &reply);
+ return reply.readStrongBinder();
+ }
+
+ virtual sp<IBinder> getBuiltInDisplay(int32_t id)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+ data.writeInt32(id);
+ remote()->transact(BnSurfaceComposer::GET_BUILT_IN_DISPLAY, data, &reply);
+ return reply.readStrongBinder();
+ }
+
+ virtual void blank(const sp<IBinder>& display)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+ data.writeStrongBinder(display);
+ remote()->transact(BnSurfaceComposer::BLANK, data, &reply);
+ }
+
+ virtual void unblank(const sp<IBinder>& display)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+ data.writeStrongBinder(display);
+ remote()->transact(BnSurfaceComposer::UNBLANK, data, &reply);
+ }
+
+ virtual status_t getDisplayInfo(const sp<IBinder>& display, DisplayInfo* info)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+ data.writeStrongBinder(display);
+ remote()->transact(BnSurfaceComposer::GET_DISPLAY_INFO, data, &reply);
+ memcpy(info, reply.readInplace(sizeof(DisplayInfo)), sizeof(DisplayInfo));
+ return reply.readInt32();
+ }
};
IMPLEMENT_META_INTERFACE(SurfaceComposer, "android.ui.ISurfaceComposer");
@@ -223,22 +253,24 @@ status_t BnSurfaceComposer::onTransact(
s.read(data);
state.add(s);
}
- int orientation = data.readInt32();
+ count = data.readInt32();
+ DisplayState d;
+ Vector<DisplayState> displays;
+ displays.setCapacity(count);
+ for (size_t i=0 ; i<count ; i++) {
+ d.read(data);
+ displays.add(d);
+ }
uint32_t flags = data.readInt32();
- setTransactionState(state, orientation, flags);
+ setTransactionState(state, displays, flags);
} break;
case BOOT_FINISHED: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
bootFinished();
} break;
- case GET_CBLK: {
- CHECK_INTERFACE(ISurfaceComposer, data, reply);
- sp<IBinder> b = getCblk()->asBinder();
- reply->writeStrongBinder(b);
- } break;
case CAPTURE_SCREEN: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
- DisplayID dpy = data.readInt32();
+ sp<IBinder> display = data.readStrongBinder();
uint32_t reqWidth = data.readInt32();
uint32_t reqHeight = data.readInt32();
uint32_t minLayerZ = data.readInt32();
@@ -246,7 +278,7 @@ status_t BnSurfaceComposer::onTransact(
sp<IMemoryHeap> heap;
uint32_t w, h;
PixelFormat f;
- status_t res = captureScreen(dpy, &heap, &w, &h, &f,
+ status_t res = captureScreen(display, &heap, &w, &h, &f,
reqWidth, reqHeight, minLayerZ, maxLayerZ);
reply->writeStrongBinder(heap->asBinder());
reply->writeInt32(w);
@@ -254,18 +286,6 @@ status_t BnSurfaceComposer::onTransact(
reply->writeInt32(f);
reply->writeInt32(res);
} break;
- case TURN_ELECTRON_BEAM_OFF: {
- CHECK_INTERFACE(ISurfaceComposer, data, reply);
- int32_t mode = data.readInt32();
- status_t res = turnElectronBeamOff(mode);
- reply->writeInt32(res);
- } break;
- case TURN_ELECTRON_BEAM_ON: {
- CHECK_INTERFACE(ISurfaceComposer, data, reply);
- int32_t mode = data.readInt32();
- status_t res = turnElectronBeamOn(mode);
- reply->writeInt32(res);
- } break;
case AUTHENTICATE_SURFACE: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
sp<ISurfaceTexture> surfaceTexture =
@@ -279,6 +299,39 @@ status_t BnSurfaceComposer::onTransact(
reply->writeStrongBinder(connection->asBinder());
return NO_ERROR;
} break;
+ case CREATE_DISPLAY: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
+ String8 displayName = data.readString8();
+ bool secure = bool(data.readInt32());
+ sp<IBinder> display(createDisplay(displayName, secure));
+ reply->writeStrongBinder(display);
+ return NO_ERROR;
+ } break;
+ case GET_BUILT_IN_DISPLAY: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
+ int32_t id = data.readInt32();
+ sp<IBinder> display(getBuiltInDisplay(id));
+ reply->writeStrongBinder(display);
+ return NO_ERROR;
+ } break;
+ case BLANK: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
+ sp<IBinder> display = data.readStrongBinder();
+ blank(display);
+ } break;
+ case UNBLANK: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
+ sp<IBinder> display = data.readStrongBinder();
+ unblank(display);
+ } break;
+ case GET_DISPLAY_INFO: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
+ DisplayInfo info;
+ sp<IBinder> display = data.readStrongBinder();
+ status_t result = getDisplayInfo(display, &info);
+ memcpy(reply->writeInplace(sizeof(DisplayInfo)), &info, sizeof(DisplayInfo));
+ reply->writeInt32(result);
+ } break;
default:
return BBinder::onTransact(code, data, reply, flags);
}
diff --git a/libs/gui/ISurfaceComposerClient.cpp b/libs/gui/ISurfaceComposerClient.cpp
index ca9ed5b..8f7bc05 100644
--- a/libs/gui/ISurfaceComposerClient.cpp
+++ b/libs/gui/ISurfaceComposerClient.cpp
@@ -52,7 +52,6 @@ public:
virtual sp<ISurface> createSurface( surface_data_t* params,
const String8& name,
- DisplayID display,
uint32_t w,
uint32_t h,
PixelFormat format,
@@ -61,7 +60,6 @@ public:
Parcel data, reply;
data.writeInterfaceToken(ISurfaceComposerClient::getInterfaceDescriptor());
data.writeString8(name);
- data.writeInt32(display);
data.writeInt32(w);
data.writeInt32(h);
data.writeInt32(format);
@@ -93,12 +91,11 @@ status_t BnSurfaceComposerClient::onTransact(
CHECK_INTERFACE(ISurfaceComposerClient, data, reply);
surface_data_t params;
String8 name = data.readString8();
- DisplayID display = data.readInt32();
uint32_t w = data.readInt32();
uint32_t h = data.readInt32();
PixelFormat format = data.readInt32();
uint32_t flags = data.readInt32();
- sp<ISurface> s = createSurface(&params, name, display, w, h,
+ sp<ISurface> s = createSurface(&params, name, w, h,
format, flags);
params.writeToParcel(reply);
reply->writeStrongBinder(s->asBinder());
diff --git a/libs/gui/ISurfaceTexture.cpp b/libs/gui/ISurfaceTexture.cpp
index 3eb5e7a..a0b1e74 100644
--- a/libs/gui/ISurfaceTexture.cpp
+++ b/libs/gui/ISurfaceTexture.cpp
@@ -81,8 +81,8 @@ public:
return result;
}
- virtual status_t dequeueBuffer(int *buf, uint32_t w, uint32_t h,
- uint32_t format, uint32_t usage) {
+ virtual status_t dequeueBuffer(int *buf, sp<Fence>& fence,
+ uint32_t w, uint32_t h, uint32_t format, uint32_t usage) {
Parcel data, reply;
data.writeInterfaceToken(ISurfaceTexture::getInterfaceDescriptor());
data.writeInt32(w);
@@ -94,6 +94,12 @@ public:
return result;
}
*buf = reply.readInt32();
+ fence.clear();
+ bool hasFence = reply.readInt32();
+ if (hasFence) {
+ fence = new Fence();
+ reply.read(*fence.get());
+ }
result = reply.readInt32();
return result;
}
@@ -103,7 +109,7 @@ public:
Parcel data, reply;
data.writeInterfaceToken(ISurfaceTexture::getInterfaceDescriptor());
data.writeInt32(buf);
- memcpy(data.writeInplace(sizeof(input)), &input, sizeof(input));
+ data.write(input);
status_t result = remote()->transact(QUEUE_BUFFER, data, &reply);
if (result != NO_ERROR) {
return result;
@@ -113,10 +119,15 @@ public:
return result;
}
- virtual void cancelBuffer(int buf) {
+ virtual void cancelBuffer(int buf, sp<Fence> fence) {
Parcel data, reply;
+ bool hasFence = fence.get() && fence->isValid();
data.writeInterfaceToken(ISurfaceTexture::getInterfaceDescriptor());
data.writeInt32(buf);
+ data.writeInt32(hasFence);
+ if (hasFence) {
+ data.write(*fence.get());
+ }
remote()->transact(CANCEL_BUFFER, data, &reply);
}
@@ -205,28 +216,38 @@ status_t BnSurfaceTexture::onTransact(
uint32_t format = data.readInt32();
uint32_t usage = data.readInt32();
int buf;
- int result = dequeueBuffer(&buf, w, h, format, usage);
+ sp<Fence> fence;
+ int result = dequeueBuffer(&buf, fence, w, h, format, usage);
+ bool hasFence = fence.get() && fence->isValid();
reply->writeInt32(buf);
+ reply->writeInt32(hasFence);
+ if (hasFence) {
+ reply->write(*fence.get());
+ }
reply->writeInt32(result);
return NO_ERROR;
} break;
case QUEUE_BUFFER: {
CHECK_INTERFACE(ISurfaceTexture, data, reply);
int buf = data.readInt32();
- QueueBufferInput const* const input =
- reinterpret_cast<QueueBufferInput const *>(
- data.readInplace(sizeof(QueueBufferInput)));
+ QueueBufferInput input(data);
QueueBufferOutput* const output =
reinterpret_cast<QueueBufferOutput *>(
reply->writeInplace(sizeof(QueueBufferOutput)));
- status_t result = queueBuffer(buf, *input, output);
+ status_t result = queueBuffer(buf, input, output);
reply->writeInt32(result);
return NO_ERROR;
} break;
case CANCEL_BUFFER: {
CHECK_INTERFACE(ISurfaceTexture, data, reply);
int buf = data.readInt32();
- cancelBuffer(buf);
+ sp<Fence> fence;
+ bool hasFence = data.readInt32();
+ if (hasFence) {
+ fence = new Fence();
+ data.read(*fence.get());
+ }
+ cancelBuffer(buf, fence);
return NO_ERROR;
} break;
case QUERY: {
@@ -268,4 +289,62 @@ status_t BnSurfaceTexture::onTransact(
// ----------------------------------------------------------------------------
+static bool isValid(const sp<Fence>& fence) {
+ return fence.get() && fence->isValid();
+}
+
+ISurfaceTexture::QueueBufferInput::QueueBufferInput(const Parcel& parcel) {
+ parcel.read(*this);
+}
+
+size_t ISurfaceTexture::QueueBufferInput::getFlattenedSize() const
+{
+ return sizeof(timestamp)
+ + sizeof(crop)
+ + sizeof(scalingMode)
+ + sizeof(transform)
+ + sizeof(bool)
+ + (isValid(fence) ? fence->getFlattenedSize() : 0);
+}
+
+size_t ISurfaceTexture::QueueBufferInput::getFdCount() const
+{
+ return isValid(fence) ? fence->getFdCount() : 0;
+}
+
+status_t ISurfaceTexture::QueueBufferInput::flatten(void* buffer, size_t size,
+ int fds[], size_t count) const
+{
+ status_t err = NO_ERROR;
+ bool haveFence = isValid(fence);
+ char* p = (char*)buffer;
+ memcpy(p, &timestamp, sizeof(timestamp)); p += sizeof(timestamp);
+ memcpy(p, &crop, sizeof(crop)); p += sizeof(crop);
+ memcpy(p, &scalingMode, sizeof(scalingMode)); p += sizeof(scalingMode);
+ memcpy(p, &transform, sizeof(transform)); p += sizeof(transform);
+ memcpy(p, &haveFence, sizeof(haveFence)); p += sizeof(haveFence);
+ if (haveFence) {
+ err = fence->flatten(p, size - (p - (char*)buffer), fds, count);
+ }
+ return err;
+}
+
+status_t ISurfaceTexture::QueueBufferInput::unflatten(void const* buffer,
+ size_t size, int fds[], size_t count)
+{
+ status_t err = NO_ERROR;
+ bool haveFence;
+ const char* p = (const char*)buffer;
+ memcpy(&timestamp, p, sizeof(timestamp)); p += sizeof(timestamp);
+ memcpy(&crop, p, sizeof(crop)); p += sizeof(crop);
+ memcpy(&scalingMode, p, sizeof(scalingMode)); p += sizeof(scalingMode);
+ memcpy(&transform, p, sizeof(transform)); p += sizeof(transform);
+ memcpy(&haveFence, p, sizeof(haveFence)); p += sizeof(haveFence);
+ if (haveFence) {
+ fence = new Fence();
+ err = fence->unflatten(p, size - (p - (const char*)buffer), fds, count);
+ }
+ return err;
+}
+
}; // namespace android
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index 224c305..e2604f8 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -17,6 +17,7 @@
#include <utils/Errors.h>
#include <binder/Parcel.h>
#include <gui/ISurfaceComposerClient.h>
+#include <gui/ISurfaceTexture.h>
#include <private/gui/LayerState.h>
namespace android {
@@ -25,14 +26,7 @@ status_t layer_state_t::write(Parcel& output) const
{
status_t err;
- size_t len = transparentRegion.write(NULL, 0);
- err = output.writeInt32(len);
- if (err < NO_ERROR) return err;
-
- void* buf = output.writeInplace(len);
- if (buf == NULL) return NO_MEMORY;
-
- err = transparentRegion.write(buf, len);
+ err = output.write(transparentRegion);
if (err < NO_ERROR) return err;
// NOTE: regions are at the end of the structure
@@ -45,11 +39,8 @@ status_t layer_state_t::write(Parcel& output) const
status_t layer_state_t::read(const Parcel& input)
{
status_t err;
- size_t len = input.readInt32();
- void const* buf = input.readInplace(len);
- if (buf == NULL) return NO_MEMORY;
- err = transparentRegion.read(buf);
+ err = input.read(transparentRegion);
if (err < NO_ERROR) return err;
// NOTE: regions are at the end of the structure
@@ -69,4 +60,28 @@ status_t ComposerState::read(const Parcel& input) {
return state.read(input);
}
+
+status_t DisplayState::write(Parcel& output) const {
+ output.writeStrongBinder(token);
+ output.writeStrongBinder(surface->asBinder());
+ output.writeInt32(what);
+ output.writeInt32(layerStack);
+ output.writeInt32(orientation);
+ output.write(viewport);
+ output.write(frame);
+ return NO_ERROR;
+}
+
+status_t DisplayState::read(const Parcel& input) {
+ token = input.readStrongBinder();
+ surface = interface_cast<ISurfaceTexture>(input.readStrongBinder());
+ what = input.readInt32();
+ layerStack = input.readInt32();
+ orientation = input.readInt32();
+ input.read(viewport);
+ input.read(frame);
+ return NO_ERROR;
+}
+
+
}; // namespace android
diff --git a/libs/gui/Sensor.cpp b/libs/gui/Sensor.cpp
index 5cc76b4..c52a88f 100644
--- a/libs/gui/Sensor.cpp
+++ b/libs/gui/Sensor.cpp
@@ -98,7 +98,7 @@ int32_t Sensor::getVersion() const {
return mVersion;
}
-size_t Sensor::getFlattenedSize() const
+size_t Sensor::getSize() const
{
return sizeof(int32_t) + ((mName.length() + 3) & ~3) +
sizeof(int32_t) + ((mVendor.length() + 3) & ~3) +
@@ -107,11 +107,6 @@ size_t Sensor::getFlattenedSize() const
sizeof(int32_t);
}
-size_t Sensor::getFdCount() const
-{
- return 0;
-}
-
static inline
size_t write(void* buffer, size_t offset, const String8& value) {
memcpy(static_cast<char*>(buffer) + offset, value.string(), value.length());
@@ -130,12 +125,8 @@ size_t write(void* buffer, size_t offset, int32_t value) {
return sizeof(int32_t);
}
-status_t Sensor::flatten(void* buffer, size_t size,
- int fds[], size_t count) const
+status_t Sensor::flatten(void* buffer) const
{
- if (size < Sensor::getFlattenedSize())
- return -ENOMEM;
-
size_t offset = 0;
offset += write(buffer, offset, int32_t(mName.length()));
offset += write(buffer, offset, mName);
@@ -149,7 +140,6 @@ status_t Sensor::flatten(void* buffer, size_t size,
offset += write(buffer, offset, mResolution);
offset += write(buffer, offset, mPower);
offset += write(buffer, offset, mMinDelay);
-
return NO_ERROR;
}
@@ -171,8 +161,7 @@ size_t read(void const* buffer, size_t offset, int32_t* value) {
return sizeof(int32_t);
}
-status_t Sensor::unflatten(void const* buffer, size_t size,
- int fds[], size_t count)
+status_t Sensor::unflatten(void const* buffer, size_t size)
{
int32_t len;
size_t offset = 0;
@@ -188,7 +177,6 @@ status_t Sensor::unflatten(void const* buffer, size_t size,
offset += read(buffer, offset, &mResolution);
offset += read(buffer, offset, &mPower);
offset += read(buffer, offset, &mMinDelay);
-
return NO_ERROR;
}
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index d7590f0..1745061 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -92,6 +92,12 @@ bool SurfaceControl::isSameSurface(
return lhs->mSurface->asBinder() == rhs->mSurface->asBinder();
}
+status_t SurfaceControl::setLayerStack(int32_t layerStack) {
+ status_t err = validate();
+ if (err < 0) return err;
+ const sp<SurfaceComposerClient>& client(mClient);
+ return client->setLayerStack(mToken, layerStack);
+}
status_t SurfaceControl::setLayer(int32_t layer) {
status_t err = validate();
if (err < 0) return err;
@@ -116,23 +122,11 @@ status_t SurfaceControl::hide() {
const sp<SurfaceComposerClient>& client(mClient);
return client->hide(mToken);
}
-status_t SurfaceControl::show(int32_t layer) {
- status_t err = validate();
- if (err < 0) return err;
- const sp<SurfaceComposerClient>& client(mClient);
- return client->show(mToken, layer);
-}
-status_t SurfaceControl::freeze() {
+status_t SurfaceControl::show() {
status_t err = validate();
if (err < 0) return err;
const sp<SurfaceComposerClient>& client(mClient);
- return client->freeze(mToken);
-}
-status_t SurfaceControl::unfreeze() {
- status_t err = validate();
- if (err < 0) return err;
- const sp<SurfaceComposerClient>& client(mClient);
- return client->unfreeze(mToken);
+ return client->show(mToken);
}
status_t SurfaceControl::setFlags(uint32_t flags, uint32_t mask) {
status_t err = validate();
@@ -158,12 +152,6 @@ status_t SurfaceControl::setMatrix(float dsdx, float dtdx, float dsdy, float dtd
const sp<SurfaceComposerClient>& client(mClient);
return client->setMatrix(mToken, dsdx, dtdx, dsdy, dtdy);
}
-status_t SurfaceControl::setFreezeTint(uint32_t tint) {
- status_t err = validate();
- if (err < 0) return err;
- const sp<SurfaceComposerClient>& client(mClient);
- return client->setFreezeTint(mToken, tint);
-}
status_t SurfaceControl::setCrop(const Rect& crop) {
status_t err = validate();
if (err < 0) return err;
@@ -317,8 +305,11 @@ void Surface::init(const sp<ISurfaceTexture>& surfaceTexture)
setUsage(GraphicBuffer::USAGE_HW_RENDER);
}
+ // TODO: the display metrics should come from the display manager
DisplayInfo dinfo;
- SurfaceComposerClient::getDisplayInfo(0, &dinfo);
+ sp<IBinder> display = SurfaceComposerClient::getBuiltInDisplay(
+ ISurfaceComposer::eDisplayIdMain);
+ SurfaceComposerClient::getDisplayInfo(display, &dinfo);
const_cast<float&>(ANativeWindow::xdpi) = dinfo.xdpi;
const_cast<float&>(ANativeWindow::ydpi) = dinfo.ydpi;
const_cast<uint32_t&>(ANativeWindow::flags) = 0;
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 8fa2167..80dd6ee 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -38,7 +38,6 @@
#include <private/gui/ComposerService.h>
#include <private/gui/LayerState.h>
-#include <private/gui/SharedBufferStack.h>
namespace android {
// ---------------------------------------------------------------------------
@@ -47,37 +46,55 @@ ANDROID_SINGLETON_STATIC_INSTANCE(ComposerService);
ComposerService::ComposerService()
: Singleton<ComposerService>() {
+ Mutex::Autolock _l(mLock);
+ connectLocked();
+}
+
+void ComposerService::connectLocked() {
const String16 name("SurfaceFlinger");
while (getService(name, &mComposerService) != NO_ERROR) {
usleep(250000);
}
- mServerCblkMemory = mComposerService->getCblk();
- mServerCblk = static_cast<surface_flinger_cblk_t volatile *>(
- mServerCblkMemory->getBase());
-}
-
-sp<ISurfaceComposer> ComposerService::getComposerService() {
- return ComposerService::getInstance().mComposerService;
-}
+ assert(mComposerService != NULL);
+
+ // Create the death listener.
+ class DeathObserver : public IBinder::DeathRecipient {
+ ComposerService& mComposerService;
+ virtual void binderDied(const wp<IBinder>& who) {
+ ALOGW("ComposerService remote (surfaceflinger) died [%p]",
+ who.unsafe_get());
+ mComposerService.composerServiceDied();
+ }
+ public:
+ DeathObserver(ComposerService& mgr) : mComposerService(mgr) { }
+ };
-surface_flinger_cblk_t const volatile * ComposerService::getControlBlock() {
- return ComposerService::getInstance().mServerCblk;
+ mDeathObserver = new DeathObserver(*const_cast<ComposerService*>(this));
+ mComposerService->asBinder()->linkToDeath(mDeathObserver);
}
-static inline sp<ISurfaceComposer> getComposerService() {
- return ComposerService::getComposerService();
+/*static*/ sp<ISurfaceComposer> ComposerService::getComposerService() {
+ ComposerService& instance = ComposerService::getInstance();
+ Mutex::Autolock _l(instance.mLock);
+ if (instance.mComposerService == NULL) {
+ ComposerService::getInstance().connectLocked();
+ assert(instance.mComposerService != NULL);
+ ALOGD("ComposerService reconnected");
+ }
+ return instance.mComposerService;
}
-static inline surface_flinger_cblk_t const volatile * get_cblk() {
- return ComposerService::getControlBlock();
+void ComposerService::composerServiceDied()
+{
+ Mutex::Autolock _l(mLock);
+ mComposerService = NULL;
+ mDeathObserver = NULL;
}
// ---------------------------------------------------------------------------
-// NOTE: this is NOT a member function (it's a friend defined with its
-// declaration).
static inline
-int compare_type( const ComposerState& lhs, const ComposerState& rhs) {
+int compare_type(const ComposerState& lhs, const ComposerState& rhs) {
if (lhs.client < rhs.client) return -1;
if (lhs.client > rhs.client) return 1;
if (lhs.state.surface < rhs.state.surface) return -1;
@@ -85,26 +102,37 @@ int compare_type( const ComposerState& lhs, const ComposerState& rhs) {
return 0;
}
+static inline
+int compare_type(const DisplayState& lhs, const DisplayState& rhs) {
+ return compare_type(lhs.token, rhs.token);
+}
+
class Composer : public Singleton<Composer>
{
friend class Singleton<Composer>;
mutable Mutex mLock;
- SortedVector<ComposerState> mStates;
- int mOrientation;
+ SortedVector<ComposerState> mComposerStates;
+ SortedVector<DisplayState > mDisplayStates;
uint32_t mForceSynchronous;
+ bool mAnimation;
Composer() : Singleton<Composer>(),
- mOrientation(ISurfaceComposer::eOrientationUnchanged),
- mForceSynchronous(0)
+ mForceSynchronous(0),
+ mAnimation(false)
{ }
void closeGlobalTransactionImpl(bool synchronous);
+ void setAnimationTransactionImpl();
layer_state_t* getLayerStateLocked(
const sp<SurfaceComposerClient>& client, SurfaceID id);
+ DisplayState& getDisplayStateLocked(const sp<IBinder>& token);
+
public:
+ sp<IBinder> createDisplay(const String8& displayName, bool secure);
+ sp<IBinder> getBuiltInDisplay(int32_t id);
status_t setPosition(const sp<SurfaceComposerClient>& client, SurfaceID id,
float x, float y);
@@ -121,12 +149,22 @@ public:
float alpha);
status_t setMatrix(const sp<SurfaceComposerClient>& client, SurfaceID id,
float dsdx, float dtdx, float dsdy, float dtdy);
- status_t setFreezeTint(
- const sp<SurfaceComposerClient>& client, SurfaceID id,
- uint32_t tint);
status_t setOrientation(int orientation);
status_t setCrop(const sp<SurfaceComposerClient>& client, SurfaceID id,
const Rect& crop);
+ status_t setLayerStack(const sp<SurfaceComposerClient>& client,
+ SurfaceID id, uint32_t layerStack);
+
+ void setDisplaySurface(const sp<IBinder>& token, const sp<ISurfaceTexture>& surface);
+ void setDisplayLayerStack(const sp<IBinder>& token, uint32_t layerStack);
+ void setDisplayProjection(const sp<IBinder>& token,
+ uint32_t orientation,
+ const Rect& layerStackRect,
+ const Rect& displayRect);
+
+ static void setAnimationTransaction() {
+ Composer::getInstance().setAnimationTransactionImpl();
+ }
static void closeGlobalTransaction(bool synchronous) {
Composer::getInstance().closeGlobalTransactionImpl(synchronous);
@@ -137,28 +175,47 @@ ANDROID_SINGLETON_STATIC_INSTANCE(Composer);
// ---------------------------------------------------------------------------
+sp<IBinder> Composer::createDisplay(const String8& displayName, bool secure) {
+ return ComposerService::getComposerService()->createDisplay(displayName,
+ secure);
+}
+
+sp<IBinder> Composer::getBuiltInDisplay(int32_t id) {
+ return ComposerService::getComposerService()->getBuiltInDisplay(id);
+}
+
void Composer::closeGlobalTransactionImpl(bool synchronous) {
- sp<ISurfaceComposer> sm(getComposerService());
+ sp<ISurfaceComposer> sm(ComposerService::getComposerService());
Vector<ComposerState> transaction;
- int orientation;
+ Vector<DisplayState> displayTransaction;
uint32_t flags = 0;
{ // scope for the lock
Mutex::Autolock _l(mLock);
- transaction = mStates;
- mStates.clear();
+ transaction = mComposerStates;
+ mComposerStates.clear();
- orientation = mOrientation;
- mOrientation = ISurfaceComposer::eOrientationUnchanged;
+ displayTransaction = mDisplayStates;
+ mDisplayStates.clear();
if (synchronous || mForceSynchronous) {
flags |= ISurfaceComposer::eSynchronous;
}
+ if (mAnimation) {
+ flags |= ISurfaceComposer::eAnimation;
+ }
+
mForceSynchronous = false;
+ mAnimation = false;
}
- sm->setTransactionState(transaction, orientation, flags);
+ sm->setTransactionState(transaction, displayTransaction, flags);
+}
+
+void Composer::setAnimationTransactionImpl() {
+ Mutex::Autolock _l(mLock);
+ mAnimation = true;
}
layer_state_t* Composer::getLayerStateLocked(
@@ -168,13 +225,13 @@ layer_state_t* Composer::getLayerStateLocked(
s.client = client->mClient;
s.state.surface = id;
- ssize_t index = mStates.indexOf(s);
+ ssize_t index = mComposerStates.indexOf(s);
if (index < 0) {
// we don't have it, add an initialized layer_state to our list
- index = mStates.add(s);
+ index = mComposerStates.add(s);
}
- ComposerState* const out = mStates.editArray();
+ ComposerState* const out = mComposerStates.editArray();
return &(out[index].state);
}
@@ -184,7 +241,7 @@ status_t Composer::setPosition(const sp<SurfaceComposerClient>& client,
layer_state_t* s = getLayerStateLocked(client, id);
if (!s)
return BAD_INDEX;
- s->what |= ISurfaceComposer::ePositionChanged;
+ s->what |= layer_state_t::ePositionChanged;
s->x = x;
s->y = y;
return NO_ERROR;
@@ -196,7 +253,7 @@ status_t Composer::setSize(const sp<SurfaceComposerClient>& client,
layer_state_t* s = getLayerStateLocked(client, id);
if (!s)
return BAD_INDEX;
- s->what |= ISurfaceComposer::eSizeChanged;
+ s->what |= layer_state_t::eSizeChanged;
s->w = w;
s->h = h;
@@ -212,7 +269,7 @@ status_t Composer::setLayer(const sp<SurfaceComposerClient>& client,
layer_state_t* s = getLayerStateLocked(client, id);
if (!s)
return BAD_INDEX;
- s->what |= ISurfaceComposer::eLayerChanged;
+ s->what |= layer_state_t::eLayerChanged;
s->z = z;
return NO_ERROR;
}
@@ -224,7 +281,7 @@ status_t Composer::setFlags(const sp<SurfaceComposerClient>& client,
layer_state_t* s = getLayerStateLocked(client, id);
if (!s)
return BAD_INDEX;
- s->what |= ISurfaceComposer::eVisibilityChanged;
+ s->what |= layer_state_t::eVisibilityChanged;
s->flags &= ~mask;
s->flags |= (flags & mask);
s->mask |= mask;
@@ -238,7 +295,7 @@ status_t Composer::setTransparentRegionHint(
layer_state_t* s = getLayerStateLocked(client, id);
if (!s)
return BAD_INDEX;
- s->what |= ISurfaceComposer::eTransparentRegionChanged;
+ s->what |= layer_state_t::eTransparentRegionChanged;
s->transparentRegion = transparentRegion;
return NO_ERROR;
}
@@ -249,11 +306,22 @@ status_t Composer::setAlpha(const sp<SurfaceComposerClient>& client,
layer_state_t* s = getLayerStateLocked(client, id);
if (!s)
return BAD_INDEX;
- s->what |= ISurfaceComposer::eAlphaChanged;
+ s->what |= layer_state_t::eAlphaChanged;
s->alpha = alpha;
return NO_ERROR;
}
+status_t Composer::setLayerStack(const sp<SurfaceComposerClient>& client,
+ SurfaceID id, uint32_t layerStack) {
+ Mutex::Autolock _l(mLock);
+ layer_state_t* s = getLayerStateLocked(client, id);
+ if (!s)
+ return BAD_INDEX;
+ s->what |= layer_state_t::eLayerStackChanged;
+ s->layerStack = layerStack;
+ return NO_ERROR;
+}
+
status_t Composer::setMatrix(const sp<SurfaceComposerClient>& client,
SurfaceID id, float dsdx, float dtdx,
float dsdy, float dtdy) {
@@ -261,7 +329,7 @@ status_t Composer::setMatrix(const sp<SurfaceComposerClient>& client,
layer_state_t* s = getLayerStateLocked(client, id);
if (!s)
return BAD_INDEX;
- s->what |= ISurfaceComposer::eMatrixChanged;
+ s->what |= layer_state_t::eMatrixChanged;
layer_state_t::matrix22_t matrix;
matrix.dsdx = dsdx;
matrix.dtdx = dtdx;
@@ -271,36 +339,58 @@ status_t Composer::setMatrix(const sp<SurfaceComposerClient>& client,
return NO_ERROR;
}
-status_t Composer::setFreezeTint(const sp<SurfaceComposerClient>& client,
- SurfaceID id, uint32_t tint) {
+status_t Composer::setCrop(const sp<SurfaceComposerClient>& client,
+ SurfaceID id, const Rect& crop) {
Mutex::Autolock _l(mLock);
layer_state_t* s = getLayerStateLocked(client, id);
if (!s)
return BAD_INDEX;
- s->what |= ISurfaceComposer::eFreezeTintChanged;
- s->tint = tint;
+ s->what |= layer_state_t::eCropChanged;
+ s->crop = crop;
return NO_ERROR;
}
-status_t Composer::setOrientation(int orientation) {
- Mutex::Autolock _l(mLock);
- mOrientation = orientation;
+// ---------------------------------------------------------------------------
- // Changing the orientation makes the transaction synchronous.
- mForceSynchronous = true;
+DisplayState& Composer::getDisplayStateLocked(const sp<IBinder>& token) {
+ DisplayState s;
+ s.token = token;
+ ssize_t index = mDisplayStates.indexOf(s);
+ if (index < 0) {
+ // we don't have it, add an initialized layer_state to our list
+ s.what = 0;
+ index = mDisplayStates.add(s);
+ }
+ return mDisplayStates.editItemAt(index);
+}
- return NO_ERROR;
+void Composer::setDisplaySurface(const sp<IBinder>& token,
+ const sp<ISurfaceTexture>& surface) {
+ Mutex::Autolock _l(mLock);
+ DisplayState& s(getDisplayStateLocked(token));
+ s.surface = surface;
+ s.what |= DisplayState::eSurfaceChanged;
}
-status_t Composer::setCrop(const sp<SurfaceComposerClient>& client,
- SurfaceID id, const Rect& crop) {
+void Composer::setDisplayLayerStack(const sp<IBinder>& token,
+ uint32_t layerStack) {
Mutex::Autolock _l(mLock);
- layer_state_t* s = getLayerStateLocked(client, id);
- if (!s)
- return BAD_INDEX;
- s->what |= ISurfaceComposer::eCropChanged;
- s->crop = crop;
- return NO_ERROR;
+ DisplayState& s(getDisplayStateLocked(token));
+ s.layerStack = layerStack;
+ s.what |= DisplayState::eLayerStackChanged;
+}
+
+void Composer::setDisplayProjection(const sp<IBinder>& token,
+ uint32_t orientation,
+ const Rect& layerStackRect,
+ const Rect& displayRect) {
+ Mutex::Autolock _l(mLock);
+ DisplayState& s(getDisplayStateLocked(token));
+ s.orientation = orientation;
+ s.viewport = layerStackRect;
+ s.frame = displayRect;
+ s.what |= DisplayState::eDisplayProjectionChanged;
+ mForceSynchronous = true; // TODO: do we actually still need this?
}
// ---------------------------------------------------------------------------
@@ -311,7 +401,7 @@ SurfaceComposerClient::SurfaceComposerClient()
}
void SurfaceComposerClient::onFirstRef() {
- sp<ISurfaceComposer> sm(getComposerService());
+ sp<ISurfaceComposer> sm(ComposerService::getComposerService());
if (sm != 0) {
sp<ISurfaceComposerClient> conn = sm->createConnection();
if (conn != 0) {
@@ -336,7 +426,7 @@ sp<IBinder> SurfaceComposerClient::connection() const {
status_t SurfaceComposerClient::linkToComposerDeath(
const sp<IBinder::DeathRecipient>& recipient,
void* cookie, uint32_t flags) {
- sp<ISurfaceComposer> sm(getComposerService());
+ sp<ISurfaceComposer> sm(ComposerService::getComposerService());
return sm->asBinder()->linkToDeath(recipient, cookie, flags);
}
@@ -352,25 +442,7 @@ void SurfaceComposerClient::dispose() {
}
sp<SurfaceControl> SurfaceComposerClient::createSurface(
- DisplayID display,
- uint32_t w,
- uint32_t h,
- PixelFormat format,
- uint32_t flags)
-{
- String8 name;
- const size_t SIZE = 128;
- char buffer[SIZE];
- snprintf(buffer, SIZE, "<pid_%d>", getpid());
- name.append(buffer);
-
- return SurfaceComposerClient::createSurface(name, display,
- w, h, format, flags);
-}
-
-sp<SurfaceControl> SurfaceComposerClient::createSurface(
const String8& name,
- DisplayID display,
uint32_t w,
uint32_t h,
PixelFormat format,
@@ -380,7 +452,7 @@ sp<SurfaceControl> SurfaceComposerClient::createSurface(
if (mStatus == NO_ERROR) {
ISurfaceComposerClient::surface_data_t data;
sp<ISurface> surface = mClient->createSurface(&data, name,
- display, w, h, format, flags);
+ w, h, format, flags);
if (surface != 0) {
result = new SurfaceControl(this, surface, data);
}
@@ -388,6 +460,15 @@ sp<SurfaceControl> SurfaceComposerClient::createSurface(
return result;
}
+sp<IBinder> SurfaceComposerClient::createDisplay(const String8& displayName,
+ bool secure) {
+ return Composer::getInstance().createDisplay(displayName, secure);
+}
+
+sp<IBinder> SurfaceComposerClient::getBuiltInDisplay(int32_t id) {
+ return Composer::getInstance().getBuiltInDisplay(id);
+}
+
status_t SurfaceComposerClient::destroySurface(SurfaceID sid) {
if (mStatus != NO_ERROR)
return mStatus;
@@ -409,16 +490,16 @@ void SurfaceComposerClient::closeGlobalTransaction(bool synchronous) {
Composer::closeGlobalTransaction(synchronous);
}
+void SurfaceComposerClient::setAnimationTransaction() {
+ Composer::setAnimationTransaction();
+}
+
// ----------------------------------------------------------------------------
status_t SurfaceComposerClient::setCrop(SurfaceID id, const Rect& crop) {
return getComposer().setCrop(this, id, crop);
}
-status_t SurfaceComposerClient::setFreezeTint(SurfaceID id, uint32_t tint) {
- return getComposer().setFreezeTint(this, id, tint);
-}
-
status_t SurfaceComposerClient::setPosition(SurfaceID id, float x, float y) {
return getComposer().setPosition(this, id, x, y);
}
@@ -433,26 +514,14 @@ status_t SurfaceComposerClient::setLayer(SurfaceID id, int32_t z) {
status_t SurfaceComposerClient::hide(SurfaceID id) {
return getComposer().setFlags(this, id,
- ISurfaceComposer::eLayerHidden,
- ISurfaceComposer::eLayerHidden);
-}
-
-status_t SurfaceComposerClient::show(SurfaceID id, int32_t) {
- return getComposer().setFlags(this, id,
- 0,
- ISurfaceComposer::eLayerHidden);
-}
-
-status_t SurfaceComposerClient::freeze(SurfaceID id) {
- return getComposer().setFlags(this, id,
- ISurfaceComposer::eLayerFrozen,
- ISurfaceComposer::eLayerFrozen);
+ layer_state_t::eLayerHidden,
+ layer_state_t::eLayerHidden);
}
-status_t SurfaceComposerClient::unfreeze(SurfaceID id) {
+status_t SurfaceComposerClient::show(SurfaceID id) {
return getComposer().setFlags(this, id,
0,
- ISurfaceComposer::eLayerFrozen);
+ layer_state_t::eLayerHidden);
}
status_t SurfaceComposerClient::setFlags(SurfaceID id, uint32_t flags,
@@ -469,89 +538,49 @@ status_t SurfaceComposerClient::setAlpha(SurfaceID id, float alpha) {
return getComposer().setAlpha(this, id, alpha);
}
+status_t SurfaceComposerClient::setLayerStack(SurfaceID id, uint32_t layerStack) {
+ return getComposer().setLayerStack(this, id, layerStack);
+}
+
status_t SurfaceComposerClient::setMatrix(SurfaceID id, float dsdx, float dtdx,
float dsdy, float dtdy) {
return getComposer().setMatrix(this, id, dsdx, dtdx, dsdy, dtdy);
}
-status_t SurfaceComposerClient::setOrientation(DisplayID dpy,
- int orientation, uint32_t flags)
-{
- return Composer::getInstance().setOrientation(orientation);
-}
-
// ----------------------------------------------------------------------------
-status_t SurfaceComposerClient::getDisplayInfo(
- DisplayID dpy, DisplayInfo* info)
-{
- if (uint32_t(dpy)>=NUM_DISPLAY_MAX)
- return BAD_VALUE;
-
- volatile surface_flinger_cblk_t const * cblk = get_cblk();
- volatile display_cblk_t const * dcblk = cblk->displays + dpy;
-
- info->w = dcblk->w;
- info->h = dcblk->h;
- info->orientation = dcblk->orientation;
- info->xdpi = dcblk->xdpi;
- info->ydpi = dcblk->ydpi;
- info->fps = dcblk->fps;
- info->density = dcblk->density;
- return getPixelFormatInfo(dcblk->format, &(info->pixelFormatInfo));
+void SurfaceComposerClient::setDisplaySurface(const sp<IBinder>& token,
+ const sp<ISurfaceTexture>& surface) {
+ Composer::getInstance().setDisplaySurface(token, surface);
}
-ssize_t SurfaceComposerClient::getDisplayWidth(DisplayID dpy)
-{
- if (uint32_t(dpy)>=NUM_DISPLAY_MAX)
- return BAD_VALUE;
- volatile surface_flinger_cblk_t const * cblk = get_cblk();
- volatile display_cblk_t const * dcblk = cblk->displays + dpy;
- return dcblk->w;
+void SurfaceComposerClient::setDisplayLayerStack(const sp<IBinder>& token,
+ uint32_t layerStack) {
+ Composer::getInstance().setDisplayLayerStack(token, layerStack);
}
-ssize_t SurfaceComposerClient::getDisplayHeight(DisplayID dpy)
-{
- if (uint32_t(dpy)>=NUM_DISPLAY_MAX)
- return BAD_VALUE;
- volatile surface_flinger_cblk_t const * cblk = get_cblk();
- volatile display_cblk_t const * dcblk = cblk->displays + dpy;
- return dcblk->h;
+void SurfaceComposerClient::setDisplayProjection(const sp<IBinder>& token,
+ uint32_t orientation,
+ const Rect& layerStackRect,
+ const Rect& displayRect) {
+ Composer::getInstance().setDisplayProjection(token, orientation,
+ layerStackRect, displayRect);
}
-ssize_t SurfaceComposerClient::getDisplayOrientation(DisplayID dpy)
-{
- if (uint32_t(dpy)>=NUM_DISPLAY_MAX)
- return BAD_VALUE;
- volatile surface_flinger_cblk_t const * cblk = get_cblk();
- volatile display_cblk_t const * dcblk = cblk->displays + dpy;
- return dcblk->orientation;
-}
+// ----------------------------------------------------------------------------
-ssize_t SurfaceComposerClient::getNumberOfDisplays()
+status_t SurfaceComposerClient::getDisplayInfo(
+ const sp<IBinder>& display, DisplayInfo* info)
{
- volatile surface_flinger_cblk_t const * cblk = get_cblk();
- uint32_t connected = cblk->connected;
- int n = 0;
- while (connected) {
- if (connected&1) n++;
- connected >>= 1;
- }
- return n;
+ return ComposerService::getComposerService()->getDisplayInfo(display, info);
}
-// ----------------------------------------------------------------------------
-
-status_t SurfaceComposerClient::freezeDisplay(DisplayID dpy, uint32_t flags)
-{
- // This has been made a no-op because it can cause Gralloc buffer deadlocks.
- return NO_ERROR;
+void SurfaceComposerClient::blankDisplay(const sp<IBinder>& token) {
+ ComposerService::getComposerService()->blank(token);
}
-status_t SurfaceComposerClient::unfreezeDisplay(DisplayID dpy, uint32_t flags)
-{
- // This has been made a no-op because it can cause Gralloc buffer deadlocks.
- return NO_ERROR;
+void SurfaceComposerClient::unblankDisplay(const sp<IBinder>& token) {
+ ComposerService::getComposerService()->unblank(token);
}
// ----------------------------------------------------------------------------
@@ -560,30 +589,32 @@ ScreenshotClient::ScreenshotClient()
: mWidth(0), mHeight(0), mFormat(PIXEL_FORMAT_NONE) {
}
-status_t ScreenshotClient::update() {
+status_t ScreenshotClient::update(const sp<IBinder>& display) {
sp<ISurfaceComposer> s(ComposerService::getComposerService());
if (s == NULL) return NO_INIT;
mHeap = 0;
- return s->captureScreen(0, &mHeap,
+ return s->captureScreen(display, &mHeap,
&mWidth, &mHeight, &mFormat, 0, 0,
0, -1UL);
}
-status_t ScreenshotClient::update(uint32_t reqWidth, uint32_t reqHeight) {
+status_t ScreenshotClient::update(const sp<IBinder>& display,
+ uint32_t reqWidth, uint32_t reqHeight) {
sp<ISurfaceComposer> s(ComposerService::getComposerService());
if (s == NULL) return NO_INIT;
mHeap = 0;
- return s->captureScreen(0, &mHeap,
+ return s->captureScreen(display, &mHeap,
&mWidth, &mHeight, &mFormat, reqWidth, reqHeight,
0, -1UL);
}
-status_t ScreenshotClient::update(uint32_t reqWidth, uint32_t reqHeight,
+status_t ScreenshotClient::update(const sp<IBinder>& display,
+ uint32_t reqWidth, uint32_t reqHeight,
uint32_t minLayerZ, uint32_t maxLayerZ) {
sp<ISurfaceComposer> s(ComposerService::getComposerService());
if (s == NULL) return NO_INIT;
mHeap = 0;
- return s->captureScreen(0, &mHeap,
+ return s->captureScreen(display, &mHeap,
&mWidth, &mHeight, &mFormat, reqWidth, reqHeight,
minLayerZ, maxLayerZ);
}
diff --git a/libs/gui/SurfaceTexture.cpp b/libs/gui/SurfaceTexture.cpp
index 55be4bc..b4dfb5e 100644
--- a/libs/gui/SurfaceTexture.cpp
+++ b/libs/gui/SurfaceTexture.cpp
@@ -39,14 +39,28 @@
#include <utils/String8.h>
#include <utils/Trace.h>
-// This compile option makes SurfaceTexture use the EGL_KHR_fence_sync extension
-// to synchronize access to the buffers. It will cause dequeueBuffer to stall,
-// waiting for the GL reads for the buffer being dequeued to complete before
-// allowing the buffer to be dequeued.
+// This compile option makes SurfaceTexture use the
+// EGL_ANDROID_native_fence_sync extension to create Android native fences to
+// signal when all GLES reads for a given buffer have completed. It is not
+// compatible with using the EGL_KHR_fence_sync extension for the same
+// purpose.
+#ifdef USE_NATIVE_FENCE_SYNC
#ifdef USE_FENCE_SYNC
-#ifdef ALLOW_DEQUEUE_CURRENT_BUFFER
-#error "USE_FENCE_SYNC and ALLOW_DEQUEUE_CURRENT_BUFFER are incompatible"
+#error "USE_NATIVE_FENCE_SYNC and USE_FENCE_SYNC are incompatible"
#endif
+static const bool useNativeFenceSync = true;
+#else
+static const bool useNativeFenceSync = false;
+#endif
+
+// This compile option makes SurfaceTexture use the EGL_ANDROID_sync_wait
+// extension to insert server-side waits into the GLES command stream. This
+// feature requires the EGL_ANDROID_native_fence_sync and
+// EGL_ANDROID_wait_sync extensions.
+#ifdef USE_WAIT_SYNC
+static const bool useWaitSync = true;
+#else
+static const bool useWaitSync = false;
#endif
// Macros for including the SurfaceTexture name in log messages
@@ -98,14 +112,10 @@ static float mtxRot270[16] = {
static void mtxMul(float out[16], const float a[16], const float b[16]);
-// Get an ID that's unique within this process.
-static int32_t createProcessUniqueId() {
- static volatile int32_t globalCounter = 0;
- return android_atomic_inc(&globalCounter);
-}
SurfaceTexture::SurfaceTexture(GLuint tex, bool allowSynchronousMode,
GLenum texTarget, bool useFenceSync, const sp<BufferQueue> &bufferQueue) :
+ ConsumerBase(bufferQueue == 0 ? new BufferQueue(allowSynchronousMode) : bufferQueue),
mCurrentTransform(0),
mCurrentTimestamp(0),
mFilteringEnabled(true),
@@ -118,52 +128,20 @@ SurfaceTexture::SurfaceTexture(GLuint tex, bool allowSynchronousMode,
mTexTarget(texTarget),
mEglDisplay(EGL_NO_DISPLAY),
mEglContext(EGL_NO_CONTEXT),
- mAbandoned(false),
mCurrentTexture(BufferQueue::INVALID_BUFFER_SLOT),
mAttached(true)
{
- // Choose a name using the PID and a process-unique ID.
- mName = String8::format("unnamed-%d-%d", getpid(), createProcessUniqueId());
ST_LOGV("SurfaceTexture");
- if (bufferQueue == 0) {
- ST_LOGV("Creating a new BufferQueue");
- mBufferQueue = new BufferQueue(allowSynchronousMode);
- }
- else {
- mBufferQueue = bufferQueue;
- }
memcpy(mCurrentTransformMatrix, mtxIdentity,
sizeof(mCurrentTransformMatrix));
- // Note that we can't create an sp<...>(this) in a ctor that will not keep a
- // reference once the ctor ends, as that would cause the refcount of 'this'
- // dropping to 0 at the end of the ctor. Since all we need is a wp<...>
- // that's what we create.
- wp<BufferQueue::ConsumerListener> listener;
- sp<BufferQueue::ConsumerListener> proxy;
- listener = static_cast<BufferQueue::ConsumerListener*>(this);
- proxy = new BufferQueue::ProxyConsumerListener(listener);
-
- status_t err = mBufferQueue->consumerConnect(proxy);
- if (err != NO_ERROR) {
- ST_LOGE("SurfaceTexture: error connecting to BufferQueue: %s (%d)",
- strerror(-err), err);
- } else {
- mBufferQueue->setConsumerName(mName);
- mBufferQueue->setConsumerUsageBits(DEFAULT_USAGE_FLAGS);
- }
-}
-
-SurfaceTexture::~SurfaceTexture() {
- ST_LOGV("~SurfaceTexture");
-
- abandon();
+ mBufferQueue->setConsumerUsageBits(DEFAULT_USAGE_FLAGS);
}
-status_t SurfaceTexture::setBufferCountServer(int bufferCount) {
+status_t SurfaceTexture::setDefaultMaxBufferCount(int bufferCount) {
Mutex::Autolock lock(mMutex);
- return mBufferQueue->setBufferCountServer(bufferCount);
+ return mBufferQueue->setDefaultMaxBufferCount(bufferCount);
}
@@ -176,10 +154,48 @@ status_t SurfaceTexture::setDefaultBufferSize(uint32_t w, uint32_t h)
}
status_t SurfaceTexture::updateTexImage() {
- return SurfaceTexture::updateTexImage(NULL);
+ return SurfaceTexture::updateTexImage(NULL, false);
+}
+
+status_t SurfaceTexture::acquireBufferLocked(BufferQueue::BufferItem *item) {
+ status_t err = ConsumerBase::acquireBufferLocked(item);
+ if (err != NO_ERROR) {
+ return err;
+ }
+
+ int slot = item->mBuf;
+ if (item->mGraphicBuffer != NULL) {
+ if (mEglSlots[slot].mEglImage != EGL_NO_IMAGE_KHR) {
+ eglDestroyImageKHR(mEglDisplay, mEglSlots[slot].mEglImage);
+ mEglSlots[slot].mEglImage = EGL_NO_IMAGE_KHR;
+ }
+ }
+
+ // Update the GL texture object. We may have to do this even when
+ // item.mGraphicBuffer == NULL, if we destroyed the EGLImage when
+ // detaching from a context but the buffer has not been re-allocated.
+ if (mEglSlots[slot].mEglImage == EGL_NO_IMAGE_KHR) {
+ EGLImageKHR image = createImage(mEglDisplay, mSlots[slot].mGraphicBuffer);
+ if (image == EGL_NO_IMAGE_KHR) {
+ return UNKNOWN_ERROR;
+ }
+ mEglSlots[slot].mEglImage = image;
+ }
+
+ return NO_ERROR;
}
-status_t SurfaceTexture::updateTexImage(BufferRejecter* rejecter) {
+status_t SurfaceTexture::releaseBufferLocked(int buf, EGLDisplay display,
+ EGLSyncKHR eglFence) {
+ status_t err = ConsumerBase::releaseBufferLocked(buf, mEglDisplay,
+ eglFence);
+
+ mEglSlots[buf].mEglFence = EGL_NO_SYNC_KHR;
+
+ return err;
+}
+
+status_t SurfaceTexture::updateTexImage(BufferRejecter* rejecter, bool skipSync) {
ATRACE_CALL();
ST_LOGV("updateTexImage");
Mutex::Autolock lock(mMutex);
@@ -219,106 +235,84 @@ status_t SurfaceTexture::updateTexImage(BufferRejecter* rejecter) {
// In asynchronous mode the list is guaranteed to be one buffer
// deep, while in synchronous mode we use the oldest buffer.
- err = mBufferQueue->acquireBuffer(&item);
+ err = acquireBufferLocked(&item);
if (err == NO_ERROR) {
int buf = item.mBuf;
- // This buffer was newly allocated, so we need to clean up on our side
- if (item.mGraphicBuffer != NULL) {
- mEGLSlots[buf].mGraphicBuffer = 0;
- if (mEGLSlots[buf].mEglImage != EGL_NO_IMAGE_KHR) {
- eglDestroyImageKHR(dpy, mEGLSlots[buf].mEglImage);
- mEGLSlots[buf].mEglImage = EGL_NO_IMAGE_KHR;
- }
- mEGLSlots[buf].mGraphicBuffer = item.mGraphicBuffer;
- }
// we call the rejecter here, in case the caller has a reason to
// not accept this buffer. this is used by SurfaceFlinger to
// reject buffers which have the wrong size
- if (rejecter && rejecter->reject(mEGLSlots[buf].mGraphicBuffer, item)) {
- mBufferQueue->releaseBuffer(buf, dpy, mEGLSlots[buf].mFence);
- mEGLSlots[buf].mFence = EGL_NO_SYNC_KHR;
+ if (rejecter && rejecter->reject(mSlots[buf].mGraphicBuffer, item)) {
+ releaseBufferLocked(buf, dpy, EGL_NO_SYNC_KHR);
glBindTexture(mTexTarget, mTexName);
return NO_ERROR;
}
- // Update the GL texture object. We may have to do this even when
- // item.mGraphicBuffer == NULL, if we destroyed the EGLImage when
- // detaching from a context but the buffer has not been re-allocated.
- EGLImageKHR image = mEGLSlots[buf].mEglImage;
- if (image == EGL_NO_IMAGE_KHR) {
- if (mEGLSlots[buf].mGraphicBuffer == NULL) {
- ST_LOGE("updateTexImage: buffer at slot %d is null", buf);
- err = BAD_VALUE;
- } else {
- image = createImage(dpy, mEGLSlots[buf].mGraphicBuffer);
- mEGLSlots[buf].mEglImage = image;
- if (image == EGL_NO_IMAGE_KHR) {
- // NOTE: if dpy was invalid, createImage() is guaranteed to
- // fail. so we'd end up here.
- err = UNKNOWN_ERROR;
- }
- }
+ GLint error;
+ while ((error = glGetError()) != GL_NO_ERROR) {
+ ST_LOGW("updateTexImage: clearing GL error: %#04x", error);
}
- if (err == NO_ERROR) {
- GLint error;
- while ((error = glGetError()) != GL_NO_ERROR) {
- ST_LOGW("updateTexImage: clearing GL error: %#04x", error);
- }
-
- glBindTexture(mTexTarget, mTexName);
- glEGLImageTargetTexture2DOES(mTexTarget, (GLeglImageOES)image);
+ EGLImageKHR image = mEglSlots[buf].mEglImage;
+ glBindTexture(mTexTarget, mTexName);
+ glEGLImageTargetTexture2DOES(mTexTarget, (GLeglImageOES)image);
- while ((error = glGetError()) != GL_NO_ERROR) {
- ST_LOGE("updateTexImage: error binding external texture image %p "
- "(slot %d): %#04x", image, buf, error);
- err = UNKNOWN_ERROR;
- }
+ while ((error = glGetError()) != GL_NO_ERROR) {
+ ST_LOGE("updateTexImage: error binding external texture image %p "
+ "(slot %d): %#04x", image, buf, error);
+ err = UNKNOWN_ERROR;
+ }
- if (err == NO_ERROR) {
- err = syncForReleaseLocked(dpy);
- }
+ if (err == NO_ERROR) {
+ err = syncForReleaseLocked(dpy);
}
if (err != NO_ERROR) {
// Release the buffer we just acquired. It's not safe to
// release the old buffer, so instead we just drop the new frame.
- mBufferQueue->releaseBuffer(buf, dpy, mEGLSlots[buf].mFence);
- mEGLSlots[buf].mFence = EGL_NO_SYNC_KHR;
+ releaseBufferLocked(buf, dpy, EGL_NO_SYNC_KHR);
return err;
}
ST_LOGV("updateTexImage: (slot=%d buf=%p) -> (slot=%d buf=%p)",
mCurrentTexture,
mCurrentTextureBuf != NULL ? mCurrentTextureBuf->handle : 0,
- buf, item.mGraphicBuffer != NULL ? item.mGraphicBuffer->handle : 0);
+ buf, mSlots[buf].mGraphicBuffer->handle);
// release old buffer
if (mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) {
- status_t status = mBufferQueue->releaseBuffer(mCurrentTexture, dpy,
- mEGLSlots[mCurrentTexture].mFence);
-
- mEGLSlots[mCurrentTexture].mFence = EGL_NO_SYNC_KHR;
- if (status == BufferQueue::STALE_BUFFER_SLOT) {
- freeBufferLocked(mCurrentTexture);
- } else if (status != NO_ERROR) {
- ST_LOGE("updateTexImage: released invalid buffer");
+ status_t status = releaseBufferLocked(mCurrentTexture, dpy,
+ mEglSlots[mCurrentTexture].mEglFence);
+ if (status != NO_ERROR && status != BufferQueue::STALE_BUFFER_SLOT) {
+ ST_LOGE("updateTexImage: failed to release buffer: %s (%d)",
+ strerror(-status), status);
err = status;
}
}
// Update the SurfaceTexture state.
mCurrentTexture = buf;
- mCurrentTextureBuf = mEGLSlots[buf].mGraphicBuffer;
+ mCurrentTextureBuf = mSlots[buf].mGraphicBuffer;
mCurrentCrop = item.mCrop;
mCurrentTransform = item.mTransform;
mCurrentScalingMode = item.mScalingMode;
mCurrentTimestamp = item.mTimestamp;
- computeCurrentTransformMatrix();
+ mCurrentFence = item.mFence;
+ if (!skipSync) {
+ // SurfaceFlinger needs to lazily perform GLES synchronization
+ // only when it's actually going to use GLES for compositing.
+ // Eventually SurfaceFlinger should have its own consumer class,
+ // but for now we'll just hack it in to SurfaceTexture.
+ // SurfaceFlinger is responsible for calling doGLFenceWait before
+ // texturing from this SurfaceTexture.
+ doGLFenceWaitLocked();
+ }
+ computeCurrentTransformMatrixLocked();
} else {
if (err < 0) {
- ALOGE("updateTexImage failed on acquire %d", err);
+ ST_LOGE("updateTexImage: acquire failed: %s (%d)",
+ strerror(-err), err);
+ return err;
}
// We always bind the texture even if we don't update its contents.
glBindTexture(mTexTarget, mTexName);
@@ -328,6 +322,17 @@ status_t SurfaceTexture::updateTexImage(BufferRejecter* rejecter) {
return err;
}
+void SurfaceTexture::setReleaseFence(int fenceFd) {
+ sp<Fence> fence(new Fence(fenceFd));
+ if (fenceFd == -1 || mCurrentTexture == BufferQueue::INVALID_BUFFER_SLOT)
+ return;
+ status_t err = addReleaseFence(mCurrentTexture, fence);
+ if (err != OK) {
+ ST_LOGE("setReleaseFence: failed to add the fence: %s (%d)",
+ strerror(-err), err);
+ }
+}
+
status_t SurfaceTexture::detachFromContext() {
ATRACE_CALL();
ST_LOGV("detachFromContext");
@@ -371,10 +376,10 @@ status_t SurfaceTexture::detachFromContext() {
// SurfaceTexture gets attached to a new OpenGL ES context (and thus gets a
// new EGLDisplay).
for (int i =0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
- EGLImageKHR img = mEGLSlots[i].mEglImage;
+ EGLImageKHR img = mEglSlots[i].mEglImage;
if (img != EGL_NO_IMAGE_KHR) {
eglDestroyImageKHR(mEglDisplay, img);
- mEGLSlots[i].mEglImage = EGL_NO_IMAGE_KHR;
+ mEglSlots[i].mEglImage = EGL_NO_IMAGE_KHR;
}
}
@@ -461,36 +466,61 @@ status_t SurfaceTexture::attachToContext(GLuint tex) {
status_t SurfaceTexture::syncForReleaseLocked(EGLDisplay dpy) {
ST_LOGV("syncForReleaseLocked");
- if (mUseFenceSync && mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) {
- EGLSyncKHR fence = mEGLSlots[mCurrentTexture].mFence;
- if (fence != EGL_NO_SYNC_KHR) {
- // There is already a fence for the current slot. We need to wait
- // on that before replacing it with another fence to ensure that all
- // outstanding buffer accesses have completed before the producer
- // accesses it.
- EGLint result = eglClientWaitSyncKHR(dpy, fence, 0, 1000000000);
- if (result == EGL_FALSE) {
- ST_LOGE("syncForReleaseLocked: error waiting for previous "
- "fence: %#x", eglGetError());
+ if (mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) {
+ if (useNativeFenceSync) {
+ EGLSyncKHR sync = eglCreateSyncKHR(dpy,
+ EGL_SYNC_NATIVE_FENCE_ANDROID, NULL);
+ if (sync == EGL_NO_SYNC_KHR) {
+ ST_LOGE("syncForReleaseLocked: error creating EGL fence: %#x",
+ eglGetError());
return UNKNOWN_ERROR;
- } else if (result == EGL_TIMEOUT_EXPIRED_KHR) {
- ST_LOGE("syncForReleaseLocked: timeout waiting for previous "
- "fence");
- return TIMED_OUT;
}
- eglDestroySyncKHR(dpy, fence);
- }
+ glFlush();
+ int fenceFd = eglDupNativeFenceFDANDROID(dpy, sync);
+ eglDestroySyncKHR(dpy, sync);
+ if (fenceFd == EGL_NO_NATIVE_FENCE_FD_ANDROID) {
+ ST_LOGE("syncForReleaseLocked: error dup'ing native fence "
+ "fd: %#x", eglGetError());
+ return UNKNOWN_ERROR;
+ }
+ sp<Fence> fence(new Fence(fenceFd));
+ status_t err = addReleaseFenceLocked(mCurrentTexture, fence);
+ if (err != OK) {
+ ST_LOGE("syncForReleaseLocked: error adding release fence: "
+ "%s (%d)", strerror(-err), err);
+ return err;
+ }
+ } else if (mUseFenceSync) {
+ EGLSyncKHR fence = mEglSlots[mCurrentTexture].mEglFence;
+ if (fence != EGL_NO_SYNC_KHR) {
+ // There is already a fence for the current slot. We need to
+ // wait on that before replacing it with another fence to
+ // ensure that all outstanding buffer accesses have completed
+ // before the producer accesses it.
+ EGLint result = eglClientWaitSyncKHR(dpy, fence, 0, 1000000000);
+ if (result == EGL_FALSE) {
+ ST_LOGE("syncForReleaseLocked: error waiting for previous "
+ "fence: %#x", eglGetError());
+ return UNKNOWN_ERROR;
+ } else if (result == EGL_TIMEOUT_EXPIRED_KHR) {
+ ST_LOGE("syncForReleaseLocked: timeout waiting for previous "
+ "fence");
+ return TIMED_OUT;
+ }
+ eglDestroySyncKHR(dpy, fence);
+ }
- // Create a fence for the outstanding accesses in the current OpenGL ES
- // context.
- fence = eglCreateSyncKHR(dpy, EGL_SYNC_FENCE_KHR, NULL);
- if (fence == EGL_NO_SYNC_KHR) {
- ST_LOGE("syncForReleaseLocked: error creating fence: %#x",
- eglGetError());
- return UNKNOWN_ERROR;
+ // Create a fence for the outstanding accesses in the current
+ // OpenGL ES context.
+ fence = eglCreateSyncKHR(dpy, EGL_SYNC_FENCE_KHR, NULL);
+ if (fence == EGL_NO_SYNC_KHR) {
+ ST_LOGE("syncForReleaseLocked: error creating fence: %#x",
+ eglGetError());
+ return UNKNOWN_ERROR;
+ }
+ glFlush();
+ mEglSlots[mCurrentTexture].mEglFence = fence;
}
- glFlush();
- mEGLSlots[mCurrentTexture].mFence = fence;
}
return OK;
@@ -526,15 +556,24 @@ void SurfaceTexture::getTransformMatrix(float mtx[16]) {
void SurfaceTexture::setFilteringEnabled(bool enabled) {
Mutex::Autolock lock(mMutex);
+ if (mAbandoned) {
+ ST_LOGE("setFilteringEnabled: SurfaceTexture is abandoned!");
+ return;
+ }
bool needsRecompute = mFilteringEnabled != enabled;
mFilteringEnabled = enabled;
- if (needsRecompute) {
- computeCurrentTransformMatrix();
+
+ if (needsRecompute && mCurrentTextureBuf==NULL) {
+ ST_LOGD("setFilteringEnabled called with mCurrentTextureBuf == NULL");
+ }
+
+ if (needsRecompute && mCurrentTextureBuf != NULL) {
+ computeCurrentTransformMatrixLocked();
}
}
-void SurfaceTexture::computeCurrentTransformMatrix() {
- ST_LOGV("computeCurrentTransformMatrix");
+void SurfaceTexture::computeCurrentTransformMatrixLocked() {
+ ST_LOGV("computeCurrentTransformMatrixLocked");
float xform[16];
for (int i = 0; i < 16; i++) {
@@ -563,6 +602,11 @@ void SurfaceTexture::computeCurrentTransformMatrix() {
}
sp<GraphicBuffer>& buf(mCurrentTextureBuf);
+
+ if (buf == NULL) {
+ ST_LOGD("computeCurrentTransformMatrixLocked: mCurrentTextureBuf is NULL");
+ }
+
Rect cropRect = mCurrentCrop;
float tx = 0.0f, ty = 0.0f, sx = 1.0f, sy = 1.0f;
float bufferWidth = buf->getWidth();
@@ -587,11 +631,13 @@ void SurfaceTexture::computeCurrentTransformMatrix() {
// We know there's no subsampling of any channels, so we
// only need to shrink by a half a pixel.
shrinkAmount = 0.5;
+ break;
default:
// If we don't recognize the format, we must assume the
// worst case (that we care about), which is YUV420.
shrinkAmount = 1.0;
+ break;
}
}
@@ -631,13 +677,6 @@ nsecs_t SurfaceTexture::getTimestamp() {
return mCurrentTimestamp;
}
-void SurfaceTexture::setFrameAvailableListener(
- const sp<FrameAvailableListener>& listener) {
- ST_LOGV("setFrameAvailableListener");
- Mutex::Autolock lock(mMutex);
- mFrameAvailableListener = listener;
-}
-
EGLImageKHR SurfaceTexture::createImage(EGLDisplay dpy,
const sp<GraphicBuffer>& graphicBuffer) {
EGLClientBuffer cbuf = (EGLClientBuffer)graphicBuffer->getNativeBuffer();
@@ -705,6 +744,76 @@ uint32_t SurfaceTexture::getCurrentScalingMode() const {
return mCurrentScalingMode;
}
+sp<Fence> SurfaceTexture::getCurrentFence() const {
+ Mutex::Autolock lock(mMutex);
+ return mCurrentFence;
+}
+
+status_t SurfaceTexture::doGLFenceWait() const {
+ Mutex::Autolock lock(mMutex);
+ return doGLFenceWaitLocked();
+}
+
+status_t SurfaceTexture::doGLFenceWaitLocked() const {
+
+ EGLDisplay dpy = eglGetCurrentDisplay();
+ EGLContext ctx = eglGetCurrentContext();
+
+ if (mEglDisplay != dpy || mEglDisplay == EGL_NO_DISPLAY) {
+ ST_LOGE("doGLFenceWait: invalid current EGLDisplay");
+ return INVALID_OPERATION;
+ }
+
+ if (mEglContext != ctx || mEglContext == EGL_NO_CONTEXT) {
+ ST_LOGE("doGLFenceWait: invalid current EGLContext");
+ return INVALID_OPERATION;
+ }
+
+ if (mCurrentFence != NULL) {
+ if (useWaitSync) {
+ // Create an EGLSyncKHR from the current fence.
+ int fenceFd = mCurrentFence->dup();
+ if (fenceFd == -1) {
+ ST_LOGE("doGLFenceWait: error dup'ing fence fd: %d", errno);
+ return -errno;
+ }
+ EGLint attribs[] = {
+ EGL_SYNC_NATIVE_FENCE_FD_ANDROID, fenceFd,
+ EGL_NONE
+ };
+ EGLSyncKHR sync = eglCreateSyncKHR(dpy,
+ EGL_SYNC_NATIVE_FENCE_ANDROID, attribs);
+ if (sync == EGL_NO_SYNC_KHR) {
+ close(fenceFd);
+ ST_LOGE("doGLFenceWait: error creating EGL fence: %#x",
+ eglGetError());
+ return UNKNOWN_ERROR;
+ }
+
+ // XXX: The spec draft is inconsistent as to whether this should
+ // return an EGLint or void. Ignore the return value for now, as
+ // it's not strictly needed.
+ eglWaitSyncANDROID(dpy, sync, 0);
+ EGLint eglErr = eglGetError();
+ eglDestroySyncKHR(dpy, sync);
+ if (eglErr != EGL_SUCCESS) {
+ ST_LOGE("doGLFenceWait: error waiting for EGL fence: %#x",
+ eglErr);
+ return UNKNOWN_ERROR;
+ }
+ } else {
+ status_t err = mCurrentFence->waitForever(1000,
+ "SurfaceTexture::doGLFenceWaitLocked");
+ if (err != NO_ERROR) {
+ ST_LOGE("doGLFenceWait: error waiting for fence: %d", err);
+ return err;
+ }
+ }
+ }
+
+ return NO_ERROR;
+}
+
bool SurfaceTexture::isSynchronousMode() const {
Mutex::Autolock lock(mMutex);
return mBufferQueue->isSynchronousMode();
@@ -712,35 +821,22 @@ bool SurfaceTexture::isSynchronousMode() const {
void SurfaceTexture::freeBufferLocked(int slotIndex) {
ST_LOGV("freeBufferLocked: slotIndex=%d", slotIndex);
- mEGLSlots[slotIndex].mGraphicBuffer = 0;
if (slotIndex == mCurrentTexture) {
mCurrentTexture = BufferQueue::INVALID_BUFFER_SLOT;
}
- EGLImageKHR img = mEGLSlots[slotIndex].mEglImage;
+ EGLImageKHR img = mEglSlots[slotIndex].mEglImage;
if (img != EGL_NO_IMAGE_KHR) {
ST_LOGV("destroying EGLImage dpy=%p img=%p", mEglDisplay, img);
eglDestroyImageKHR(mEglDisplay, img);
}
- mEGLSlots[slotIndex].mEglImage = EGL_NO_IMAGE_KHR;
+ mEglSlots[slotIndex].mEglImage = EGL_NO_IMAGE_KHR;
+ ConsumerBase::freeBufferLocked(slotIndex);
}
-void SurfaceTexture::abandon() {
- ST_LOGV("abandon");
- Mutex::Autolock lock(mMutex);
-
- if (!mAbandoned) {
- mAbandoned = true;
- mCurrentTextureBuf.clear();
-
- // destroy all egl buffers
- for (int i =0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
- freeBufferLocked(i);
- }
-
- // disconnect from the BufferQueue
- mBufferQueue->consumerDisconnect();
- mBufferQueue.clear();
- }
+void SurfaceTexture::abandonLocked() {
+ ST_LOGV("abandonLocked");
+ mCurrentTextureBuf.clear();
+ ConsumerBase::abandonLocked();
}
void SurfaceTexture::setName(const String8& name) {
@@ -772,71 +868,18 @@ status_t SurfaceTexture::setSynchronousMode(bool enabled) {
return mBufferQueue->setSynchronousMode(enabled);
}
-// Used for refactoring, should not be in final interface
-sp<BufferQueue> SurfaceTexture::getBufferQueue() const {
- Mutex::Autolock lock(mMutex);
- return mBufferQueue;
-}
-
-void SurfaceTexture::onFrameAvailable() {
- ST_LOGV("onFrameAvailable");
-
- sp<FrameAvailableListener> listener;
- { // scope for the lock
- Mutex::Autolock lock(mMutex);
- listener = mFrameAvailableListener;
- }
-
- if (listener != NULL) {
- ST_LOGV("actually calling onFrameAvailable");
- listener->onFrameAvailable();
- }
-}
-
-void SurfaceTexture::onBuffersReleased() {
- ST_LOGV("onBuffersReleased");
-
- Mutex::Autolock lock(mMutex);
-
- if (mAbandoned) {
- // Nothing to do if we're already abandoned.
- return;
- }
-
- uint32_t mask = 0;
- mBufferQueue->getReleasedBuffers(&mask);
- for (int i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
- if (mask & (1 << i)) {
- freeBufferLocked(i);
- }
- }
-}
-
-void SurfaceTexture::dump(String8& result) const
-{
- char buffer[1024];
- dump(result, "", buffer, 1024);
-}
-
-void SurfaceTexture::dump(String8& result, const char* prefix,
- char* buffer, size_t SIZE) const
+void SurfaceTexture::dumpLocked(String8& result, const char* prefix,
+ char* buffer, size_t size) const
{
- Mutex::Autolock _l(mMutex);
- snprintf(buffer, SIZE, "%smTexName=%d, mAbandoned=%d\n", prefix, mTexName,
- int(mAbandoned));
- result.append(buffer);
-
- snprintf(buffer, SIZE,
- "%snext : {crop=[%d,%d,%d,%d], transform=0x%02x, current=%d}\n",
- prefix, mCurrentCrop.left,
- mCurrentCrop.top, mCurrentCrop.right, mCurrentCrop.bottom,
- mCurrentTransform, mCurrentTexture
- );
+ snprintf(buffer, size,
+ "%smTexName=%d mCurrentTexture=%d\n"
+ "%smCurrentCrop=[%d,%d,%d,%d] mCurrentTransform=%#x\n",
+ prefix, mTexName, mCurrentTexture, prefix, mCurrentCrop.left,
+ mCurrentCrop.top, mCurrentCrop.right, mCurrentCrop.bottom,
+ mCurrentTransform);
result.append(buffer);
- if (!mAbandoned) {
- mBufferQueue->dump(result, prefix, buffer, SIZE);
- }
+ ConsumerBase::dumpLocked(result, prefix, buffer, size);
}
static void mtxMul(float out[16], const float a[16], const float b[16]) {
diff --git a/libs/gui/SurfaceTextureClient.cpp b/libs/gui/SurfaceTextureClient.cpp
index f60f902..afdbf04 100644
--- a/libs/gui/SurfaceTextureClient.cpp
+++ b/libs/gui/SurfaceTextureClient.cpp
@@ -23,6 +23,8 @@
#include <utils/Log.h>
#include <utils/Trace.h>
+#include <ui/Fence.h>
+
#include <gui/ISurfaceComposer.h>
#include <gui/SurfaceComposerClient.h>
#include <gui/SurfaceTexture.h>
@@ -62,11 +64,15 @@ void SurfaceTextureClient::init() {
ANativeWindow::setSwapInterval = hook_setSwapInterval;
ANativeWindow::dequeueBuffer = hook_dequeueBuffer;
ANativeWindow::cancelBuffer = hook_cancelBuffer;
- ANativeWindow::lockBuffer = hook_lockBuffer;
ANativeWindow::queueBuffer = hook_queueBuffer;
ANativeWindow::query = hook_query;
ANativeWindow::perform = hook_perform;
+ ANativeWindow::dequeueBuffer_DEPRECATED = hook_dequeueBuffer_DEPRECATED;
+ ANativeWindow::cancelBuffer_DEPRECATED = hook_cancelBuffer_DEPRECATED;
+ ANativeWindow::lockBuffer_DEPRECATED = hook_lockBuffer_DEPRECATED;
+ ANativeWindow::queueBuffer_DEPRECATED = hook_queueBuffer_DEPRECATED;
+
const_cast<int&>(ANativeWindow::minSwapInterval) = 0;
const_cast<int&>(ANativeWindow::maxSwapInterval) = 1;
@@ -103,27 +109,57 @@ int SurfaceTextureClient::hook_setSwapInterval(ANativeWindow* window, int interv
}
int SurfaceTextureClient::hook_dequeueBuffer(ANativeWindow* window,
- ANativeWindowBuffer** buffer) {
+ ANativeWindowBuffer** buffer, int* fenceFd) {
SurfaceTextureClient* c = getSelf(window);
- return c->dequeueBuffer(buffer);
+ return c->dequeueBuffer(buffer, fenceFd);
}
int SurfaceTextureClient::hook_cancelBuffer(ANativeWindow* window,
+ ANativeWindowBuffer* buffer, int fenceFd) {
+ SurfaceTextureClient* c = getSelf(window);
+ return c->cancelBuffer(buffer, fenceFd);
+}
+
+int SurfaceTextureClient::hook_queueBuffer(ANativeWindow* window,
+ ANativeWindowBuffer* buffer, int fenceFd) {
+ SurfaceTextureClient* c = getSelf(window);
+ return c->queueBuffer(buffer, fenceFd);
+}
+
+int SurfaceTextureClient::hook_dequeueBuffer_DEPRECATED(ANativeWindow* window,
+ ANativeWindowBuffer** buffer) {
+ SurfaceTextureClient* c = getSelf(window);
+ ANativeWindowBuffer* buf;
+ int fenceFd = -1;
+ int result = c->dequeueBuffer(&buf, &fenceFd);
+ sp<Fence> fence(new Fence(fenceFd));
+ int waitResult = fence->waitForever(1000, "dequeueBuffer_DEPRECATED");
+ if (waitResult != OK) {
+ ALOGE("dequeueBuffer_DEPRECATED: Fence::wait returned an error: %d",
+ waitResult);
+ c->cancelBuffer(buf, -1);
+ return waitResult;
+ }
+ *buffer = buf;
+ return result;
+}
+
+int SurfaceTextureClient::hook_cancelBuffer_DEPRECATED(ANativeWindow* window,
ANativeWindowBuffer* buffer) {
SurfaceTextureClient* c = getSelf(window);
- return c->cancelBuffer(buffer);
+ return c->cancelBuffer(buffer, -1);
}
-int SurfaceTextureClient::hook_lockBuffer(ANativeWindow* window,
+int SurfaceTextureClient::hook_lockBuffer_DEPRECATED(ANativeWindow* window,
ANativeWindowBuffer* buffer) {
SurfaceTextureClient* c = getSelf(window);
- return c->lockBuffer(buffer);
+ return c->lockBuffer_DEPRECATED(buffer);
}
-int SurfaceTextureClient::hook_queueBuffer(ANativeWindow* window,
+int SurfaceTextureClient::hook_queueBuffer_DEPRECATED(ANativeWindow* window,
ANativeWindowBuffer* buffer) {
SurfaceTextureClient* c = getSelf(window);
- return c->queueBuffer(buffer);
+ return c->queueBuffer(buffer, -1);
}
int SurfaceTextureClient::hook_query(const ANativeWindow* window,
@@ -157,14 +193,16 @@ int SurfaceTextureClient::setSwapInterval(int interval) {
return res;
}
-int SurfaceTextureClient::dequeueBuffer(android_native_buffer_t** buffer) {
+int SurfaceTextureClient::dequeueBuffer(android_native_buffer_t** buffer,
+ int* fenceFd) {
ATRACE_CALL();
ALOGV("SurfaceTextureClient::dequeueBuffer");
Mutex::Autolock lock(mMutex);
int buf = -1;
int reqW = mReqWidth ? mReqWidth : mUserWidth;
int reqH = mReqHeight ? mReqHeight : mUserHeight;
- status_t result = mSurfaceTexture->dequeueBuffer(&buf, reqW, reqH,
+ sp<Fence> fence;
+ status_t result = mSurfaceTexture->dequeueBuffer(&buf, fence, reqW, reqH,
mReqFormat, mReqUsage);
if (result < 0) {
ALOGV("dequeueBuffer: ISurfaceTexture::dequeueBuffer(%d, %d, %d, %d)"
@@ -185,11 +223,25 @@ int SurfaceTextureClient::dequeueBuffer(android_native_buffer_t** buffer) {
return result;
}
}
+
+ if (fence.get()) {
+ *fenceFd = fence->dup();
+ if (*fenceFd == -1) {
+ ALOGE("dequeueBuffer: error duping fence: %d", errno);
+ // dup() should never fail; something is badly wrong. Soldier on
+ // and hope for the best; the worst that should happen is some
+ // visible corruption that lasts until the next frame.
+ }
+ } else {
+ *fenceFd = -1;
+ }
+
*buffer = gbuf.get();
return OK;
}
-int SurfaceTextureClient::cancelBuffer(android_native_buffer_t* buffer) {
+int SurfaceTextureClient::cancelBuffer(android_native_buffer_t* buffer,
+ int fenceFd) {
ATRACE_CALL();
ALOGV("SurfaceTextureClient::cancelBuffer");
Mutex::Autolock lock(mMutex);
@@ -197,7 +249,8 @@ int SurfaceTextureClient::cancelBuffer(android_native_buffer_t* buffer) {
if (i < 0) {
return i;
}
- mSurfaceTexture->cancelBuffer(i);
+ sp<Fence> fence(fenceFd >= 0 ? new Fence(fenceFd) : NULL);
+ mSurfaceTexture->cancelBuffer(i, fence);
return OK;
}
@@ -214,13 +267,13 @@ int SurfaceTextureClient::getSlotFromBufferLocked(
return BAD_VALUE;
}
-int SurfaceTextureClient::lockBuffer(android_native_buffer_t* buffer) {
+int SurfaceTextureClient::lockBuffer_DEPRECATED(android_native_buffer_t* buffer) {
ALOGV("SurfaceTextureClient::lockBuffer");
Mutex::Autolock lock(mMutex);
return OK;
}
-int SurfaceTextureClient::queueBuffer(android_native_buffer_t* buffer) {
+int SurfaceTextureClient::queueBuffer(android_native_buffer_t* buffer, int fenceFd) {
ATRACE_CALL();
ALOGV("SurfaceTextureClient::queueBuffer");
Mutex::Autolock lock(mMutex);
@@ -237,13 +290,15 @@ int SurfaceTextureClient::queueBuffer(android_native_buffer_t* buffer) {
return i;
}
+
// Make sure the crop rectangle is entirely inside the buffer.
Rect crop;
mCrop.intersect(Rect(buffer->width, buffer->height), &crop);
+ sp<Fence> fence(fenceFd >= 0 ? new Fence(fenceFd) : NULL);
ISurfaceTexture::QueueBufferOutput output;
ISurfaceTexture::QueueBufferInput input(timestamp, crop, mScalingMode,
- mTransform);
+ mTransform, fence);
status_t err = mSurfaceTexture->queueBuffer(i, input, &output);
if (err != OK) {
ALOGE("queueBuffer: error queuing buffer to SurfaceTexture, %d", err);
@@ -692,82 +747,87 @@ status_t SurfaceTextureClient::lock(
}
ANativeWindowBuffer* out;
- status_t err = dequeueBuffer(&out);
+ int fenceFd = -1;
+ status_t err = dequeueBuffer(&out, &fenceFd);
ALOGE_IF(err, "dequeueBuffer failed (%s)", strerror(-err));
if (err == NO_ERROR) {
sp<GraphicBuffer> backBuffer(GraphicBuffer::getSelf(out));
- err = lockBuffer(backBuffer.get());
- ALOGE_IF(err, "lockBuffer (handle=%p) failed (%s)",
- backBuffer->handle, strerror(-err));
- if (err == NO_ERROR) {
- const Rect bounds(backBuffer->width, backBuffer->height);
-
- Region newDirtyRegion;
- if (inOutDirtyBounds) {
- newDirtyRegion.set(static_cast<Rect const&>(*inOutDirtyBounds));
- newDirtyRegion.andSelf(bounds);
- } else {
- newDirtyRegion.set(bounds);
- }
+ sp<Fence> fence(new Fence(fenceFd));
- // figure out if we can copy the frontbuffer back
- const sp<GraphicBuffer>& frontBuffer(mPostedBuffer);
- const bool canCopyBack = (frontBuffer != 0 &&
- backBuffer->width == frontBuffer->width &&
- backBuffer->height == frontBuffer->height &&
- backBuffer->format == frontBuffer->format);
-
- if (canCopyBack) {
- // copy the area that is invalid and not repainted this round
- const Region copyback(mDirtyRegion.subtract(newDirtyRegion));
- if (!copyback.isEmpty())
- copyBlt(backBuffer, frontBuffer, copyback);
- } else {
- // if we can't copy-back anything, modify the user's dirty
- // region to make sure they redraw the whole buffer
- newDirtyRegion.set(bounds);
- mDirtyRegion.clear();
- Mutex::Autolock lock(mMutex);
- for (size_t i=0 ; i<NUM_BUFFER_SLOTS ; i++) {
- mSlots[i].dirtyRegion.clear();
- }
- }
+ err = fence->waitForever(1000, "SurfaceTextureClient::lock");
+ if (err != OK) {
+ ALOGE("Fence::wait failed (%s)", strerror(-err));
+ cancelBuffer(out, fenceFd);
+ return err;
+ }
+ const Rect bounds(backBuffer->width, backBuffer->height);
- { // scope for the lock
- Mutex::Autolock lock(mMutex);
- int backBufferSlot(getSlotFromBufferLocked(backBuffer.get()));
- if (backBufferSlot >= 0) {
- Region& dirtyRegion(mSlots[backBufferSlot].dirtyRegion);
- mDirtyRegion.subtract(dirtyRegion);
- dirtyRegion = newDirtyRegion;
- }
- }
+ Region newDirtyRegion;
+ if (inOutDirtyBounds) {
+ newDirtyRegion.set(static_cast<Rect const&>(*inOutDirtyBounds));
+ newDirtyRegion.andSelf(bounds);
+ } else {
+ newDirtyRegion.set(bounds);
+ }
- mDirtyRegion.orSelf(newDirtyRegion);
- if (inOutDirtyBounds) {
- *inOutDirtyBounds = newDirtyRegion.getBounds();
+ // figure out if we can copy the frontbuffer back
+ const sp<GraphicBuffer>& frontBuffer(mPostedBuffer);
+ const bool canCopyBack = (frontBuffer != 0 &&
+ backBuffer->width == frontBuffer->width &&
+ backBuffer->height == frontBuffer->height &&
+ backBuffer->format == frontBuffer->format);
+
+ if (canCopyBack) {
+ // copy the area that is invalid and not repainted this round
+ const Region copyback(mDirtyRegion.subtract(newDirtyRegion));
+ if (!copyback.isEmpty())
+ copyBlt(backBuffer, frontBuffer, copyback);
+ } else {
+ // if we can't copy-back anything, modify the user's dirty
+ // region to make sure they redraw the whole buffer
+ newDirtyRegion.set(bounds);
+ mDirtyRegion.clear();
+ Mutex::Autolock lock(mMutex);
+ for (size_t i=0 ; i<NUM_BUFFER_SLOTS ; i++) {
+ mSlots[i].dirtyRegion.clear();
}
+ }
+
- void* vaddr;
- status_t res = backBuffer->lock(
- GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
- newDirtyRegion.bounds(), &vaddr);
-
- ALOGW_IF(res, "failed locking buffer (handle = %p)",
- backBuffer->handle);
-
- if (res != 0) {
- err = INVALID_OPERATION;
- } else {
- mLockedBuffer = backBuffer;
- outBuffer->width = backBuffer->width;
- outBuffer->height = backBuffer->height;
- outBuffer->stride = backBuffer->stride;
- outBuffer->format = backBuffer->format;
- outBuffer->bits = vaddr;
+ { // scope for the lock
+ Mutex::Autolock lock(mMutex);
+ int backBufferSlot(getSlotFromBufferLocked(backBuffer.get()));
+ if (backBufferSlot >= 0) {
+ Region& dirtyRegion(mSlots[backBufferSlot].dirtyRegion);
+ mDirtyRegion.subtract(dirtyRegion);
+ dirtyRegion = newDirtyRegion;
}
}
+
+ mDirtyRegion.orSelf(newDirtyRegion);
+ if (inOutDirtyBounds) {
+ *inOutDirtyBounds = newDirtyRegion.getBounds();
+ }
+
+ void* vaddr;
+ status_t res = backBuffer->lock(
+ GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
+ newDirtyRegion.bounds(), &vaddr);
+
+ ALOGW_IF(res, "failed locking buffer (handle = %p)",
+ backBuffer->handle);
+
+ if (res != 0) {
+ err = INVALID_OPERATION;
+ } else {
+ mLockedBuffer = backBuffer;
+ outBuffer->width = backBuffer->width;
+ outBuffer->height = backBuffer->height;
+ outBuffer->stride = backBuffer->stride;
+ outBuffer->format = backBuffer->format;
+ outBuffer->bits = vaddr;
+ }
}
return err;
}
@@ -782,7 +842,7 @@ status_t SurfaceTextureClient::unlockAndPost()
status_t err = mLockedBuffer->unlock();
ALOGE_IF(err, "failed unlocking buffer (%p)", mLockedBuffer->handle);
- err = queueBuffer(mLockedBuffer.get());
+ err = queueBuffer(mLockedBuffer.get(), -1);
ALOGE_IF(err, "queueBuffer (handle=%p) failed (%s)",
mLockedBuffer->handle, strerror(-err));
diff --git a/libs/gui/tests/Android.mk b/libs/gui/tests/Android.mk
index 741534b..4a6f74f 100644
--- a/libs/gui/tests/Android.mk
+++ b/libs/gui/tests/Android.mk
@@ -2,14 +2,16 @@
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
-LOCAL_MODULE := SurfaceTexture_test
+LOCAL_MODULE := libgui_test
LOCAL_MODULE_TAGS := tests
LOCAL_SRC_FILES := \
- Surface_test.cpp \
+ BufferQueue_test.cpp \
+ CpuConsumer_test.cpp \
SurfaceTextureClient_test.cpp \
SurfaceTexture_test.cpp \
+ Surface_test.cpp \
LOCAL_SHARED_LIBRARIES := \
libEGL \
@@ -18,6 +20,7 @@ LOCAL_SHARED_LIBRARIES := \
libcutils \
libgui \
libstlport \
+ libsync \
libui \
libutils \
diff --git a/libs/gui/tests/BufferQueue_test.cpp b/libs/gui/tests/BufferQueue_test.cpp
new file mode 100644
index 0000000..817abb4
--- /dev/null
+++ b/libs/gui/tests/BufferQueue_test.cpp
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2012 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 "BufferQueue_test"
+//#define LOG_NDEBUG 0
+
+#include <gtest/gtest.h>
+
+#include <utils/String8.h>
+#include <utils/threads.h>
+
+#include <ui/GraphicBuffer.h>
+#include <ui/FramebufferNativeWindow.h>
+
+#include <gui/BufferQueue.h>
+
+namespace android {
+
+class BufferQueueTest : public ::testing::Test {
+protected:
+
+ BufferQueueTest() {}
+
+ virtual void SetUp() {
+ const ::testing::TestInfo* const testInfo =
+ ::testing::UnitTest::GetInstance()->current_test_info();
+ ALOGV("Begin test: %s.%s", testInfo->test_case_name(),
+ testInfo->name());
+
+ mBQ = new BufferQueue();
+ }
+
+ virtual void TearDown() {
+ mBQ.clear();
+
+ const ::testing::TestInfo* const testInfo =
+ ::testing::UnitTest::GetInstance()->current_test_info();
+ ALOGV("End test: %s.%s", testInfo->test_case_name(),
+ testInfo->name());
+ }
+
+ sp<BufferQueue> mBQ;
+};
+
+struct DummyConsumer : public BufferQueue::ConsumerListener {
+ virtual void onFrameAvailable() {}
+ virtual void onBuffersReleased() {}
+};
+
+TEST_F(BufferQueueTest, AcquireBuffer_ExceedsMaxAcquireCount_Fails) {
+ sp<DummyConsumer> dc(new DummyConsumer);
+ mBQ->consumerConnect(dc);
+ ISurfaceTexture::QueueBufferOutput qbo;
+ mBQ->connect(NATIVE_WINDOW_API_CPU, &qbo);
+ mBQ->setBufferCount(4);
+
+ int slot;
+ sp<Fence> fence;
+ sp<GraphicBuffer> buf;
+ ISurfaceTexture::QueueBufferInput qbi(0, Rect(0, 0, 1, 1),
+ NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, fence);
+ BufferQueue::BufferItem item;
+
+ for (int i = 0; i < 2; i++) {
+ ASSERT_EQ(ISurfaceTexture::BUFFER_NEEDS_REALLOCATION,
+ mBQ->dequeueBuffer(&slot, fence, 1, 1, 0,
+ GRALLOC_USAGE_SW_READ_OFTEN));
+ ASSERT_EQ(OK, mBQ->requestBuffer(slot, &buf));
+ ASSERT_EQ(OK, mBQ->queueBuffer(slot, qbi, &qbo));
+ ASSERT_EQ(OK, mBQ->acquireBuffer(&item));
+ }
+
+ ASSERT_EQ(ISurfaceTexture::BUFFER_NEEDS_REALLOCATION,
+ mBQ->dequeueBuffer(&slot, fence, 1, 1, 0,
+ GRALLOC_USAGE_SW_READ_OFTEN));
+ ASSERT_EQ(OK, mBQ->requestBuffer(slot, &buf));
+ ASSERT_EQ(OK, mBQ->queueBuffer(slot, qbi, &qbo));
+
+ // Acquire the third buffer, which should fail.
+ ASSERT_EQ(INVALID_OPERATION, mBQ->acquireBuffer(&item));
+}
+
+TEST_F(BufferQueueTest, SetMaxAcquiredBufferCountWithIllegalValues_ReturnsError) {
+ sp<DummyConsumer> dc(new DummyConsumer);
+ mBQ->consumerConnect(dc);
+
+ ASSERT_EQ(BAD_VALUE, mBQ->setMaxAcquiredBufferCount(0));
+ ASSERT_EQ(BAD_VALUE, mBQ->setMaxAcquiredBufferCount(-3));
+ ASSERT_EQ(BAD_VALUE, mBQ->setMaxAcquiredBufferCount(
+ BufferQueue::MAX_MAX_ACQUIRED_BUFFERS+1));
+ ASSERT_EQ(BAD_VALUE, mBQ->setMaxAcquiredBufferCount(100));
+}
+
+TEST_F(BufferQueueTest, SetMaxAcquiredBufferCountWithLegalValues_Succeeds) {
+ sp<DummyConsumer> dc(new DummyConsumer);
+ mBQ->consumerConnect(dc);
+
+ ASSERT_EQ(OK, mBQ->setMaxAcquiredBufferCount(1));
+ ASSERT_EQ(OK, mBQ->setMaxAcquiredBufferCount(2));
+ ASSERT_EQ(OK, mBQ->setMaxAcquiredBufferCount(
+ BufferQueue::MAX_MAX_ACQUIRED_BUFFERS));
+}
+
+} // namespace android
diff --git a/libs/gui/tests/CpuConsumer_test.cpp b/libs/gui/tests/CpuConsumer_test.cpp
new file mode 100644
index 0000000..72a36bf
--- /dev/null
+++ b/libs/gui/tests/CpuConsumer_test.cpp
@@ -0,0 +1,509 @@
+/*
+ * Copyright (C) 2012 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 "CpuConsumer_test"
+//#define LOG_NDEBUG 0
+//#define LOG_NNDEBUG 0
+
+#ifdef LOG_NNDEBUG
+#define ALOGVV(...) ALOGV(__VA_ARGS__)
+#else
+#define ALOGVV(...) ((void)0)
+#endif
+
+#include <gtest/gtest.h>
+#include <gui/CpuConsumer.h>
+#include <gui/SurfaceTextureClient.h>
+#include <ui/GraphicBuffer.h>
+#include <utils/String8.h>
+#include <utils/Thread.h>
+#include <utils/Mutex.h>
+#include <utils/Condition.h>
+
+#include <ui/FramebufferNativeWindow.h>
+
+namespace android {
+
+struct CpuConsumerTestParams {
+ uint32_t width;
+ uint32_t height;
+ int maxLockedBuffers;
+ PixelFormat format;
+};
+
+::std::ostream& operator<<(::std::ostream& os, const CpuConsumerTestParams& p) {
+ return os << "[ (" << p.width << ", " << p.height << "), B:"
+ << p.maxLockedBuffers << ", F:0x"
+ << ::std::hex << p.format << "]";
+}
+
+class CpuConsumerTest : public ::testing::TestWithParam<CpuConsumerTestParams> {
+protected:
+
+ virtual void SetUp() {
+ const ::testing::TestInfo* const test_info =
+ ::testing::UnitTest::GetInstance()->current_test_info();
+ CpuConsumerTestParams params = GetParam();
+ ALOGV("** Starting test %s (%d x %d, %d, 0x%x)",
+ test_info->name(),
+ params.width, params.height,
+ params.maxLockedBuffers, params.format);
+ mCC = new CpuConsumer(params.maxLockedBuffers);
+ String8 name("CpuConsumer_Under_Test");
+ mCC->setName(name);
+ mSTC = new SurfaceTextureClient(mCC->getProducerInterface());
+ mANW = mSTC;
+ }
+
+ virtual void TearDown() {
+ mANW.clear();
+ mSTC.clear();
+ mCC.clear();
+ }
+
+ class FrameWaiter : public CpuConsumer::FrameAvailableListener {
+ public:
+ FrameWaiter():
+ mPendingFrames(0) {
+ }
+
+ void waitForFrame() {
+ Mutex::Autolock lock(mMutex);
+ while (mPendingFrames == 0) {
+ mCondition.wait(mMutex);
+ }
+ mPendingFrames--;
+ }
+
+ virtual void onFrameAvailable() {
+ Mutex::Autolock lock(mMutex);
+ mPendingFrames++;
+ mCondition.signal();
+ }
+
+ int mPendingFrames;
+ Mutex mMutex;
+ Condition mCondition;
+ };
+
+ // Note that SurfaceTexture will lose the notifications
+ // onBuffersReleased and onFrameAvailable as there is currently
+ // no way to forward the events. This DisconnectWaiter will not let the
+ // disconnect finish until finishDisconnect() is called. It will
+ // also block until a disconnect is called
+ class DisconnectWaiter : public BufferQueue::ConsumerListener {
+ public:
+ DisconnectWaiter () :
+ mWaitForDisconnect(false),
+ mPendingFrames(0) {
+ }
+
+ void waitForFrame() {
+ Mutex::Autolock lock(mMutex);
+ while (mPendingFrames == 0) {
+ mFrameCondition.wait(mMutex);
+ }
+ mPendingFrames--;
+ }
+
+ virtual void onFrameAvailable() {
+ Mutex::Autolock lock(mMutex);
+ mPendingFrames++;
+ mFrameCondition.signal();
+ }
+
+ virtual void onBuffersReleased() {
+ Mutex::Autolock lock(mMutex);
+ while (!mWaitForDisconnect) {
+ mDisconnectCondition.wait(mMutex);
+ }
+ }
+
+ void finishDisconnect() {
+ Mutex::Autolock lock(mMutex);
+ mWaitForDisconnect = true;
+ mDisconnectCondition.signal();
+ }
+
+ private:
+ Mutex mMutex;
+
+ bool mWaitForDisconnect;
+ Condition mDisconnectCondition;
+
+ int mPendingFrames;
+ Condition mFrameCondition;
+ };
+
+ sp<CpuConsumer> mCC;
+ sp<SurfaceTextureClient> mSTC;
+ sp<ANativeWindow> mANW;
+};
+
+#define ASSERT_NO_ERROR(err, msg) \
+ ASSERT_EQ(NO_ERROR, err) << msg << strerror(-err)
+
+void checkPixel(const CpuConsumer::LockedBuffer &buf,
+ uint32_t x, uint32_t y, uint32_t r, uint32_t g, uint32_t b) {
+ // Ignores components that don't exist for given pixel
+ switch(buf.format) {
+ case HAL_PIXEL_FORMAT_RAW_SENSOR: {
+ String8 msg;
+ uint16_t *bPtr = (uint16_t*)buf.data;
+ bPtr += y * buf.stride + x;
+ // GRBG Bayer mosaic; only check the matching channel
+ switch( ((y & 1) << 1) | (x & 1) ) {
+ case 0: // G
+ case 3: // G
+ EXPECT_EQ(g, *bPtr);
+ break;
+ case 1: // R
+ EXPECT_EQ(r, *bPtr);
+ break;
+ case 2: // B
+ EXPECT_EQ(b, *bPtr);
+ break;
+ }
+ break;
+ }
+ default: {
+ ADD_FAILURE() << "Unknown format for check:" << buf.format;
+ break;
+ }
+ }
+}
+
+// Fill a YV12 buffer with a multi-colored checkerboard pattern
+void fillYV12Buffer(uint8_t* buf, int w, int h, int stride);
+
+// Fill a RAW sensor buffer with a multi-colored checkerboard pattern.
+// Assumes GRBG mosaic ordering. Result should be a grid in a 2x2 pattern
+// of [ R, B; G, W]
+void fillBayerRawBuffer(uint8_t* buf, int w, int h, int stride) {
+ ALOGVV("fillBayerRawBuffer: %p with %d x %d, stride %d", buf, w, h ,stride);
+ // Blocks need to be even-width/height, aim for 8-wide otherwise
+ const int blockWidth = (w > 16 ? w / 8 : 2) & ~0x1;
+ const int blockHeight = (h > 16 ? h / 8 : 2) & ~0x1;
+ for (int y = 0; y < h; y+=2) {
+ uint16_t *bPtr1 = ((uint16_t*)buf) + stride*y;
+ uint16_t *bPtr2 = bPtr1 + stride;
+ for (int x = 0; x < w; x+=2) {
+ int blockX = (x / blockWidth ) & 1;
+ int blockY = (y / blockHeight) & 1;
+ unsigned short r = (blockX == blockY) ? 1000 : 200;
+ unsigned short g = blockY ? 1000: 200;
+ unsigned short b = blockX ? 1000: 200;
+ // GR row
+ *bPtr1++ = g;
+ *bPtr1++ = r;
+ // BG row
+ *bPtr2++ = b;
+ *bPtr2++ = g;
+ }
+ }
+
+}
+
+void checkBayerRawBuffer(const CpuConsumer::LockedBuffer &buf) {
+ uint32_t w = buf.width;
+ uint32_t h = buf.height;
+ const int blockWidth = (w > 16 ? w / 8 : 2) & ~0x1;
+ const int blockHeight = (h > 16 ? h / 8 : 2) & ~0x1;
+ const int blockRows = h / blockHeight;
+ const int blockCols = w / blockWidth;
+
+ // Top-left square is red
+ checkPixel(buf, 0, 0, 1000, 200, 200);
+ checkPixel(buf, 1, 0, 1000, 200, 200);
+ checkPixel(buf, 0, 1, 1000, 200, 200);
+ checkPixel(buf, 1, 1, 1000, 200, 200);
+
+ // One-right square is blue
+ checkPixel(buf, blockWidth, 0, 200, 200, 1000);
+ checkPixel(buf, blockWidth + 1, 0, 200, 200, 1000);
+ checkPixel(buf, blockWidth, 1, 200, 200, 1000);
+ checkPixel(buf, blockWidth + 1, 1, 200, 200, 1000);
+
+ // One-down square is green
+ checkPixel(buf, 0, blockHeight, 200, 1000, 200);
+ checkPixel(buf, 1, blockHeight, 200, 1000, 200);
+ checkPixel(buf, 0, blockHeight + 1, 200, 1000, 200);
+ checkPixel(buf, 1, blockHeight + 1, 200, 1000, 200);
+
+ // One-diag square is white
+ checkPixel(buf, blockWidth, blockHeight, 1000, 1000, 1000);
+ checkPixel(buf, blockWidth + 1, blockHeight, 1000, 1000, 1000);
+ checkPixel(buf, blockWidth, blockHeight + 1, 1000, 1000, 1000);
+ checkPixel(buf, blockWidth + 1, blockHeight + 1, 1000, 1000, 1000);
+
+ // Test bottom-right pixel
+ const int maxBlockX = ((w-1) / blockWidth) & 0x1;
+ const int maxBlockY = ((w-1) / blockHeight) & 0x1;
+ unsigned short maxR = (maxBlockX == maxBlockY) ? 1000 : 200;
+ unsigned short maxG = maxBlockY ? 1000: 200;
+ unsigned short maxB = maxBlockX ? 1000: 200;
+ checkPixel(buf, w-1, h-1, maxR, maxG, maxB);
+}
+
+void fillYV12BufferRect(uint8_t* buf, int w, int h, int stride,
+ const android_native_rect_t& rect);
+
+void fillRGBA8Buffer(uint8_t* buf, int w, int h, int stride);
+
+void fillRGBA8BufferSolid(uint8_t* buf, int w, int h, int stride, uint8_t r,
+ uint8_t g, uint8_t b, uint8_t a);
+
+// Configures the ANativeWindow producer-side interface based on test parameters
+void configureANW(const sp<ANativeWindow>& anw,
+ 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_usage(anw.get(),
+ GRALLOC_USAGE_SW_WRITE_OFTEN);
+ ASSERT_NO_ERROR(err, "set_usage error: ");
+
+ int minUndequeuedBuffers;
+ err = anw.get()->query(anw.get(),
+ NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS,
+ &minUndequeuedBuffers);
+ ASSERT_NO_ERROR(err, "query error: ");
+
+ ALOGVV("Setting buffer count to %d",
+ maxBufferSlack + 1 + minUndequeuedBuffers);
+ err = native_window_set_buffer_count(anw.get(),
+ maxBufferSlack + 1 + minUndequeuedBuffers);
+ ASSERT_NO_ERROR(err, "set_buffer_count error: ");
+
+}
+
+// Produce one frame of image data; assumes format and resolution configuration
+// is already done.
+void produceOneFrame(const sp<ANativeWindow>& anw,
+ const CpuConsumerTestParams& params,
+ int64_t timestamp, uint32_t *stride) {
+ status_t err;
+ ANativeWindowBuffer* anb;
+ ALOGVV("Dequeue buffer from %p", anw.get());
+ err = native_window_dequeue_buffer_and_wait(anw.get(), &anb);
+ ASSERT_NO_ERROR(err, "dequeueBuffer error: ");
+
+ ASSERT_TRUE(anb != NULL);
+
+ sp<GraphicBuffer> buf(new GraphicBuffer(anb, false));
+
+ *stride = buf->getStride();
+ uint8_t* img = NULL;
+
+ ALOGVV("Lock buffer from %p for write", anw.get());
+ err = buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
+ ASSERT_NO_ERROR(err, "lock error: ");
+
+ switch (params.format) {
+ case HAL_PIXEL_FORMAT_YV12:
+ fillYV12Buffer(img, params.width, params.height, *stride);
+ break;
+ case HAL_PIXEL_FORMAT_RAW_SENSOR:
+ fillBayerRawBuffer(img, params.width, params.height, buf->getStride());
+ break;
+ default:
+ FAIL() << "Unknown pixel format under test!";
+ break;
+ }
+ ALOGVV("Unlock buffer from %p", anw.get());
+ err = buf->unlock();
+ ASSERT_NO_ERROR(err, "unlock error: ");
+
+ ALOGVV("Set timestamp to %p", anw.get());
+ err = native_window_set_buffers_timestamp(anw.get(), timestamp);
+ ASSERT_NO_ERROR(err, "set_buffers_timestamp error: ");
+
+ ALOGVV("Queue buffer to %p", anw.get());
+ err = anw->queueBuffer(anw.get(), buf->getNativeBuffer(), -1);
+ ASSERT_NO_ERROR(err, "queueBuffer error:");
+};
+
+// This test is disabled because the HAL_PIXEL_FORMAT_RAW_SENSOR format is not
+// supported on all devices.
+TEST_P(CpuConsumerTest, DISABLED_FromCpuSingle) {
+ status_t err;
+ CpuConsumerTestParams params = GetParam();
+
+ // Set up
+
+ ASSERT_NO_FATAL_FAILURE(configureANW(mANW, params, 1));
+
+ // Produce
+
+ const int64_t time = 12345678L;
+ uint32_t stride;
+ ASSERT_NO_FATAL_FAILURE(produceOneFrame(mANW, params, time,
+ &stride));
+
+ // Consume
+
+ CpuConsumer::LockedBuffer b;
+ err = mCC->lockNextBuffer(&b);
+ ASSERT_NO_ERROR(err, "getNextBuffer error: ");
+
+ ASSERT_TRUE(b.data != NULL);
+ EXPECT_EQ(params.width, b.width);
+ EXPECT_EQ(params.height, b.height);
+ EXPECT_EQ(params.format, b.format);
+ EXPECT_EQ(stride, b.stride);
+ EXPECT_EQ(time, b.timestamp);
+
+ checkBayerRawBuffer(b);
+ mCC->unlockBuffer(b);
+}
+
+// This test is disabled because the HAL_PIXEL_FORMAT_RAW_SENSOR format is not
+// supported on all devices.
+TEST_P(CpuConsumerTest, DISABLED_FromCpuManyInQueue) {
+ status_t err;
+ CpuConsumerTestParams params = GetParam();
+
+ const int numInQueue = 5;
+ // Set up
+
+ ASSERT_NO_FATAL_FAILURE(configureANW(mANW, params, numInQueue));
+
+ // Produce
+
+ const int64_t time[numInQueue] = { 1L, 2L, 3L, 4L, 5L};
+ uint32_t stride[numInQueue];
+
+ for (int i = 0; i < numInQueue; i++) {
+ ALOGV("Producing frame %d", i);
+ ASSERT_NO_FATAL_FAILURE(produceOneFrame(mANW, params, time[i],
+ &stride[i]));
+ }
+
+ // Consume
+
+ for (int i = 0; i < numInQueue; i++) {
+ ALOGV("Consuming frame %d", i);
+ CpuConsumer::LockedBuffer b;
+ err = mCC->lockNextBuffer(&b);
+ ASSERT_NO_ERROR(err, "getNextBuffer error: ");
+
+ ASSERT_TRUE(b.data != NULL);
+ EXPECT_EQ(params.width, b.width);
+ EXPECT_EQ(params.height, b.height);
+ EXPECT_EQ(params.format, b.format);
+ EXPECT_EQ(stride[i], b.stride);
+ EXPECT_EQ(time[i], b.timestamp);
+
+ checkBayerRawBuffer(b);
+
+ mCC->unlockBuffer(b);
+ }
+}
+
+// This test is disabled because the HAL_PIXEL_FORMAT_RAW_SENSOR format is not
+// supported on all devices.
+TEST_P(CpuConsumerTest, DISABLED_FromCpuLockMax) {
+ status_t err;
+ CpuConsumerTestParams params = GetParam();
+
+ // Set up
+
+ ASSERT_NO_FATAL_FAILURE(configureANW(mANW, params, params.maxLockedBuffers + 1));
+
+ // Produce
+
+ const int64_t time = 1234L;
+ uint32_t stride;
+
+ for (int i = 0; i < params.maxLockedBuffers + 1; i++) {
+ ALOGV("Producing frame %d", i);
+ ASSERT_NO_FATAL_FAILURE(produceOneFrame(mANW, params, time,
+ &stride));
+ }
+
+ // Consume
+
+ CpuConsumer::LockedBuffer *b = new CpuConsumer::LockedBuffer[params.maxLockedBuffers];
+ for (int i = 0; i < params.maxLockedBuffers; i++) {
+ ALOGV("Locking frame %d", i);
+ err = mCC->lockNextBuffer(&b[i]);
+ ASSERT_NO_ERROR(err, "getNextBuffer error: ");
+
+ ASSERT_TRUE(b[i].data != NULL);
+ EXPECT_EQ(params.width, b[i].width);
+ EXPECT_EQ(params.height, b[i].height);
+ EXPECT_EQ(params.format, b[i].format);
+ EXPECT_EQ(stride, b[i].stride);
+ EXPECT_EQ(time, b[i].timestamp);
+
+ checkBayerRawBuffer(b[i]);
+ }
+
+ ALOGV("Locking frame %d (too many)", params.maxLockedBuffers);
+ CpuConsumer::LockedBuffer bTooMuch;
+ err = mCC->lockNextBuffer(&bTooMuch);
+ ASSERT_TRUE(err == INVALID_OPERATION) << "Allowing too many locks";
+
+ ALOGV("Unlocking frame 0");
+ err = mCC->unlockBuffer(b[0]);
+ ASSERT_NO_ERROR(err, "Could not unlock buffer 0: ");
+
+ ALOGV("Locking frame %d (should work now)", params.maxLockedBuffers);
+ err = mCC->lockNextBuffer(&bTooMuch);
+ ASSERT_NO_ERROR(err, "Did not allow new lock after unlock");
+
+ ASSERT_TRUE(bTooMuch.data != NULL);
+ EXPECT_EQ(params.width, bTooMuch.width);
+ EXPECT_EQ(params.height, bTooMuch.height);
+ EXPECT_EQ(params.format, bTooMuch.format);
+ EXPECT_EQ(stride, bTooMuch.stride);
+ EXPECT_EQ(time, bTooMuch.timestamp);
+
+ checkBayerRawBuffer(bTooMuch);
+
+ ALOGV("Unlocking extra buffer");
+ err = mCC->unlockBuffer(bTooMuch);
+ ASSERT_NO_ERROR(err, "Could not unlock extra buffer: ");
+
+ ALOGV("Locking frame %d (no more available)", params.maxLockedBuffers + 1);
+ err = mCC->lockNextBuffer(&b[0]);
+ ASSERT_EQ(BAD_VALUE, err) << "Not out of buffers somehow";
+
+ for (int i = 1; i < params.maxLockedBuffers; i++) {
+ mCC->unlockBuffer(b[i]);
+ }
+
+ delete[] b;
+
+}
+
+CpuConsumerTestParams rawTestSets[] = {
+ { 512, 512, 1, HAL_PIXEL_FORMAT_RAW_SENSOR},
+ { 512, 512, 3, HAL_PIXEL_FORMAT_RAW_SENSOR},
+ { 2608, 1960, 1, HAL_PIXEL_FORMAT_RAW_SENSOR},
+ { 2608, 1960, 3, HAL_PIXEL_FORMAT_RAW_SENSOR},
+ { 100, 100, 1, HAL_PIXEL_FORMAT_RAW_SENSOR},
+ { 100, 100, 3, HAL_PIXEL_FORMAT_RAW_SENSOR}
+};
+
+INSTANTIATE_TEST_CASE_P(RawTests,
+ CpuConsumerTest,
+ ::testing::ValuesIn(rawTestSets));
+
+} // namespace android
diff --git a/libs/gui/tests/SurfaceTextureClient_test.cpp b/libs/gui/tests/SurfaceTextureClient_test.cpp
index 7d8dd33..ec14a0d 100644
--- a/libs/gui/tests/SurfaceTextureClient_test.cpp
+++ b/libs/gui/tests/SurfaceTextureClient_test.cpp
@@ -180,129 +180,129 @@ TEST_F(SurfaceTextureClientTest, BufferGeometryInvalidSizesFail) {
TEST_F(SurfaceTextureClientTest, DefaultGeometryValues) {
ANativeWindowBuffer* buf;
- ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf));
+ ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf));
EXPECT_EQ(1, buf->width);
EXPECT_EQ(1, buf->height);
EXPECT_EQ(PIXEL_FORMAT_RGBA_8888, buf->format);
- ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf));
+ ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf, -1));
}
TEST_F(SurfaceTextureClientTest, BufferGeometryCanBeSet) {
ANativeWindowBuffer* buf;
EXPECT_EQ(OK, native_window_set_buffers_geometry(mANW.get(), 16, 8, PIXEL_FORMAT_RGB_565));
- ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf));
+ 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_RGB_565, buf->format);
- ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf));
+ ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf, -1));
}
TEST_F(SurfaceTextureClientTest, BufferGeometryDefaultSizeSetFormat) {
ANativeWindowBuffer* buf;
EXPECT_EQ(OK, native_window_set_buffers_geometry(mANW.get(), 0, 0, PIXEL_FORMAT_RGB_565));
- ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf));
+ ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf));
EXPECT_EQ(1, buf->width);
EXPECT_EQ(1, buf->height);
EXPECT_EQ(PIXEL_FORMAT_RGB_565, buf->format);
- ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf));
+ ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf, -1));
}
TEST_F(SurfaceTextureClientTest, BufferGeometrySetSizeDefaultFormat) {
ANativeWindowBuffer* buf;
EXPECT_EQ(OK, native_window_set_buffers_geometry(mANW.get(), 16, 8, 0));
- ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf));
+ 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));
+ ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf, -1));
}
TEST_F(SurfaceTextureClientTest, BufferGeometrySizeCanBeUnset) {
ANativeWindowBuffer* buf;
EXPECT_EQ(OK, native_window_set_buffers_geometry(mANW.get(), 16, 8, 0));
- ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf));
+ 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));
+ ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf, -1));
EXPECT_EQ(OK, native_window_set_buffers_geometry(mANW.get(), 0, 0, 0));
- ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf));
+ ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf));
EXPECT_EQ(1, buf->width);
EXPECT_EQ(1, buf->height);
EXPECT_EQ(PIXEL_FORMAT_RGBA_8888, buf->format);
- ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf));
+ ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf, -1));
}
TEST_F(SurfaceTextureClientTest, BufferGeometrySizeCanBeChangedWithoutFormat) {
ANativeWindowBuffer* buf;
EXPECT_EQ(OK, native_window_set_buffers_geometry(mANW.get(), 0, 0, PIXEL_FORMAT_RGB_565));
- ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf));
+ ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf));
EXPECT_EQ(1, buf->width);
EXPECT_EQ(1, buf->height);
EXPECT_EQ(PIXEL_FORMAT_RGB_565, buf->format);
- ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf));
- EXPECT_EQ(OK, native_window_set_buffers_geometry(mANW.get(), 16, 8, 0));
- ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf));
+ ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf, -1));
+ EXPECT_EQ(OK, native_window_set_buffers_dimensions(mANW.get(), 16, 8));
+ 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_RGB_565, buf->format);
- ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf));
+ ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf, -1));
}
TEST_F(SurfaceTextureClientTest, SurfaceTextureSetDefaultSize) {
sp<SurfaceTexture> st(mST);
ANativeWindowBuffer* buf;
EXPECT_EQ(OK, st->setDefaultBufferSize(16, 8));
- ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf));
+ 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));
+ ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf, -1));
}
TEST_F(SurfaceTextureClientTest, SurfaceTextureSetDefaultSizeAfterDequeue) {
ANativeWindowBuffer* buf[2];
ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 4));
- ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[0]));
- ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[1]));
+ 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]);
- ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf[0]));
- ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf[1]));
+ ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf[0], -1));
+ ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf[1], -1));
EXPECT_EQ(OK, mST->setDefaultBufferSize(16, 8));
- ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[0]));
- ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[1]));
+ 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]);
EXPECT_EQ(16, buf[0]->width);
EXPECT_EQ(16, buf[1]->width);
EXPECT_EQ(8, buf[0]->height);
EXPECT_EQ(8, buf[1]->height);
- ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf[0]));
- ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf[1]));
+ ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf[0], -1));
+ ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf[1], -1));
}
TEST_F(SurfaceTextureClientTest, SurfaceTextureSetDefaultSizeVsGeometry) {
ANativeWindowBuffer* buf[2];
ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 4));
EXPECT_EQ(OK, mST->setDefaultBufferSize(16, 8));
- ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[0]));
- ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[1]));
+ 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]);
EXPECT_EQ(16, buf[0]->width);
EXPECT_EQ(16, buf[1]->width);
EXPECT_EQ(8, buf[0]->height);
EXPECT_EQ(8, buf[1]->height);
- ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf[0]));
- ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf[1]));
+ 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));
- ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[0]));
- ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[1]));
+ 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]);
EXPECT_EQ(12, buf[0]->width);
EXPECT_EQ(12, buf[1]->width);
EXPECT_EQ(24, buf[0]->height);
EXPECT_EQ(24, buf[1]->height);
- ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf[0]));
- ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf[1]));
+ ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf[0], -1));
+ ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf[1], -1));
}
TEST_F(SurfaceTextureClientTest, SurfaceTextureTooManyUpdateTexImage) {
@@ -310,18 +310,18 @@ TEST_F(SurfaceTextureClientTest, SurfaceTextureTooManyUpdateTexImage) {
ASSERT_EQ(OK, mST->setSynchronousMode(false));
ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 4));
- ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[0]));
- ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[0]));
+ ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[0]));
+ ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[0], -1));
EXPECT_EQ(OK, mST->updateTexImage());
EXPECT_EQ(OK, mST->updateTexImage());
ASSERT_EQ(OK, mST->setSynchronousMode(true));
ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 3));
- ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[0]));
- ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[0]));
- ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[1]));
- ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[1]));
+ ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[0]));
+ ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[0], -1));
+ ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[1]));
+ ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[1], -1));
EXPECT_EQ(OK, mST->updateTexImage());
EXPECT_EQ(OK, mST->updateTexImage());
@@ -332,15 +332,15 @@ TEST_F(SurfaceTextureClientTest, SurfaceTextureSyncModeSlowRetire) {
android_native_buffer_t* buf[3];
ASSERT_EQ(OK, mST->setSynchronousMode(true));
ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 4));
- ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[0]));
- ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[1]));
- ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[2]));
+ 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]));
+ ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[2]));
EXPECT_NE(buf[0], buf[1]);
EXPECT_NE(buf[1], buf[2]);
EXPECT_NE(buf[2], buf[0]);
- ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[0]));
- ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[1]));
- ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[2]));
+ ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[0], -1));
+ ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[1], -1));
+ ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[2], -1));
EXPECT_EQ(OK, mST->updateTexImage());
EXPECT_EQ(mST->getCurrentBuffer().get(), buf[0]);
EXPECT_EQ(OK, mST->updateTexImage());
@@ -353,19 +353,19 @@ TEST_F(SurfaceTextureClientTest, SurfaceTextureSyncModeFastRetire) {
android_native_buffer_t* buf[3];
ASSERT_EQ(OK, mST->setSynchronousMode(true));
ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 4));
- ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[0]));
- ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[1]));
- ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[2]));
+ 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]));
+ ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[2]));
EXPECT_NE(buf[0], buf[1]);
EXPECT_NE(buf[1], buf[2]);
EXPECT_NE(buf[2], buf[0]);
- ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[0]));
+ ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[0], -1));
EXPECT_EQ(OK, mST->updateTexImage());
EXPECT_EQ(mST->getCurrentBuffer().get(), buf[0]);
- ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[1]));
+ ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[1], -1));
EXPECT_EQ(OK, mST->updateTexImage());
EXPECT_EQ(mST->getCurrentBuffer().get(), buf[1]);
- ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[2]));
+ ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[2], -1));
EXPECT_EQ(OK, mST->updateTexImage());
EXPECT_EQ(mST->getCurrentBuffer().get(), buf[2]);
}
@@ -375,20 +375,20 @@ TEST_F(SurfaceTextureClientTest, SurfaceTextureSyncModeDQQR) {
ASSERT_EQ(OK, mST->setSynchronousMode(true));
ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 3));
- ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[0]));
- ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[0]));
+ ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[0]));
+ ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[0], -1));
EXPECT_EQ(OK, mST->updateTexImage());
EXPECT_EQ(mST->getCurrentBuffer().get(), buf[0]);
- ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[1]));
+ ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[1]));
EXPECT_NE(buf[0], buf[1]);
- ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[1]));
+ ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[1], -1));
EXPECT_EQ(OK, mST->updateTexImage());
EXPECT_EQ(mST->getCurrentBuffer().get(), buf[1]);
- ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[2]));
+ ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[2]));
EXPECT_NE(buf[1], buf[2]);
- ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[2]));
+ ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[2], -1));
EXPECT_EQ(OK, mST->updateTexImage());
EXPECT_EQ(mST->getCurrentBuffer().get(), buf[2]);
}
@@ -400,16 +400,16 @@ TEST_F(SurfaceTextureClientTest, DISABLED_SurfaceTextureSyncModeDequeueCurrent)
android_native_buffer_t* firstBuf;
ASSERT_EQ(OK, mST->setSynchronousMode(true));
ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 3));
- ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &firstBuf));
- ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), firstBuf));
+ ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &firstBuf));
+ ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), firstBuf, -1));
EXPECT_EQ(OK, mST->updateTexImage());
EXPECT_EQ(mST->getCurrentBuffer().get(), firstBuf);
- ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[0]));
- ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[0]));
- ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[1]));
- ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[1]));
- ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[2]));
- ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[2]));
+ ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[0]));
+ ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[0], -1));
+ ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[1]));
+ ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[1], -1));
+ ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[2]));
+ ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[2], -1));
EXPECT_NE(buf[0], buf[1]);
EXPECT_NE(buf[1], buf[2]);
EXPECT_NE(buf[2], buf[0]);
@@ -422,24 +422,24 @@ TEST_F(SurfaceTextureClientTest, SurfaceTextureSyncModeMinUndequeued) {
ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 3));
// We should be able to dequeue all the buffers before we've queued mANWy.
- EXPECT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[0]));
- EXPECT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[1]));
- EXPECT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[2]));
+ EXPECT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[0]));
+ EXPECT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[1]));
+ EXPECT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[2]));
- ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf[2]));
- ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[1]));
+ ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf[2], -1));
+ ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[1], -1));
EXPECT_EQ(OK, mST->updateTexImage());
EXPECT_EQ(mST->getCurrentBuffer().get(), buf[1]);
- EXPECT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[2]));
+ EXPECT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[2]));
// 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, mANW->dequeueBuffer(mANW.get(), &buf[1]));
+ EXPECT_EQ(-EBUSY, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[1]));
- ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf[0]));
- ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf[2]));
+ ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf[0], -1));
+ ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf[2], -1));
}
TEST_F(SurfaceTextureClientTest, SetCropCropsCrop) {
@@ -449,8 +449,8 @@ TEST_F(SurfaceTextureClientTest, SetCropCropsCrop) {
ASSERT_EQ(OK, native_window_set_buffers_dimensions(mANW.get(), 4, 4));
android_native_buffer_t* buf;
- ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf));
- ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf));
+ ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf));
+ ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf, -1));
ASSERT_EQ(OK, mST->updateTexImage());
Rect crop = mST->getCurrentCrop();
@@ -500,20 +500,20 @@ TEST_F(SurfaceTextureClientTest, DISABLED_SurfaceTextureSyncModeWaitRetire) {
ASSERT_EQ(OK, mST->setSynchronousMode(true));
ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 3));
// dequeue/queue/update so we have a current buffer
- ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[0]));
- ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[0]));
+ ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[0]));
+ ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[0], -1));
mST->updateTexImage();
MyThread* thread = new MyThread(mST);
sp<Thread> threadBase(thread);
- ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[0]));
- ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[0]));
+ ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[0]));
+ ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[0], -1));
thread->run();
- ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[1]));
- ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[1]));
- //ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[2]));
- //ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[2]));
+ ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[1]));
+ ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[1], -1));
+ //ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[2]));
+ //ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[2], -1));
thread->bufferDequeued();
thread->requestExitAndWait();
}
@@ -522,8 +522,8 @@ TEST_F(SurfaceTextureClientTest, GetTransformMatrixReturnsVerticalFlip) {
android_native_buffer_t* buf[3];
float mtx[16] = {};
ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 4));
- ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[0]));
- ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[0]));
+ ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[0]));
+ ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[0], -1));
ASSERT_EQ(OK, mST->updateTexImage());
mST->getTransformMatrix(mtx);
@@ -552,8 +552,8 @@ TEST_F(SurfaceTextureClientTest, GetTransformMatrixSucceedsAfterFreeingBuffers)
android_native_buffer_t* buf[3];
float mtx[16] = {};
ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 4));
- ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[0]));
- ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[0]));
+ ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf[0]));
+ ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[0], -1));
ASSERT_EQ(OK, mST->updateTexImage());
ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 6)); // frees buffers
mST->getTransformMatrix(mtx);
@@ -590,22 +590,22 @@ TEST_F(SurfaceTextureClientTest, GetTransformMatrixSucceedsAfterFreeingBuffersWi
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, mANW->dequeueBuffer(mANW.get(), &buf[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]));
+ ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[0], -1));
ASSERT_EQ(OK, mST->updateTexImage());
ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 6)); // frees buffers
mST->getTransformMatrix(mtx);
- // This accounts for the 1 texel shrink for each edge that's included in the
+ // This accounts for the .5 texel shrink for each edge that's included in the
// transform matrix to avoid texturing outside the crop region.
- EXPECT_EQ(.375f, mtx[0]);
+ EXPECT_EQ(0.5, mtx[0]);
EXPECT_EQ(0.f, mtx[1]);
EXPECT_EQ(0.f, mtx[2]);
EXPECT_EQ(0.f, mtx[3]);
EXPECT_EQ(0.f, mtx[4]);
- EXPECT_EQ(-.375f, mtx[5]);
+ EXPECT_EQ(-0.5, mtx[5]);
EXPECT_EQ(0.f, mtx[6]);
EXPECT_EQ(0.f, mtx[7]);
@@ -614,8 +614,8 @@ TEST_F(SurfaceTextureClientTest, GetTransformMatrixSucceedsAfterFreeingBuffersWi
EXPECT_EQ(1.f, mtx[10]);
EXPECT_EQ(0.f, mtx[11]);
- EXPECT_EQ(.125f, mtx[12]);
- EXPECT_EQ(.5f, mtx[13]);
+ EXPECT_EQ(0.0625f, mtx[12]);
+ EXPECT_EQ(0.5625f, mtx[13]);
EXPECT_EQ(0.f, mtx[14]);
EXPECT_EQ(1.f, mtx[15]);
}
diff --git a/libs/gui/tests/SurfaceTexture_test.cpp b/libs/gui/tests/SurfaceTexture_test.cpp
index 078c17b..d9b40cf 100644
--- a/libs/gui/tests/SurfaceTexture_test.cpp
+++ b/libs/gui/tests/SurfaceTexture_test.cpp
@@ -83,7 +83,7 @@ protected:
ASSERT_EQ(NO_ERROR, mComposerClient->initCheck());
mSurfaceControl = mComposerClient->createSurface(
- String8("Test Surface"), 0,
+ String8("Test Surface"),
getSurfaceWidth(), getSurfaceHeight(),
PIXEL_FORMAT_RGB_888, 0);
@@ -672,18 +672,19 @@ void fillRGBA8BufferSolid(uint8_t* buf, int w, int h, int stride, uint8_t r,
// Calls to this function should be wrapped in an ASSERT_NO_FATAL_FAILURE().
void produceOneRGBA8Frame(const sp<ANativeWindow>& anw) {
android_native_buffer_t* anb;
- ASSERT_EQ(NO_ERROR, anw->dequeueBuffer(anw.get(), &anb));
+ ASSERT_EQ(NO_ERROR, native_window_dequeue_buffer_and_wait(anw.get(),
+ &anb));
ASSERT_TRUE(anb != NULL);
sp<GraphicBuffer> buf(new GraphicBuffer(anb, false));
- ASSERT_EQ(NO_ERROR, anw->lockBuffer(anw.get(), buf->getNativeBuffer()));
uint8_t* img = NULL;
ASSERT_EQ(NO_ERROR, buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN,
(void**)(&img)));
fillRGBA8Buffer(img, buf->getWidth(), buf->getHeight(), buf->getStride());
ASSERT_EQ(NO_ERROR, buf->unlock());
- ASSERT_EQ(NO_ERROR, anw->queueBuffer(anw.get(), buf->getNativeBuffer()));
+ ASSERT_EQ(NO_ERROR, anw->queueBuffer(anw.get(), buf->getNativeBuffer(),
+ -1));
}
TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledYV12BufferNpot) {
@@ -696,20 +697,21 @@ TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledYV12BufferNpot) {
GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN));
ANativeWindowBuffer* anb;
- ASSERT_EQ(NO_ERROR, mANW->dequeueBuffer(mANW.get(), &anb));
+ ASSERT_EQ(NO_ERROR, native_window_dequeue_buffer_and_wait(mANW.get(),
+ &anb));
ASSERT_TRUE(anb != NULL);
sp<GraphicBuffer> buf(new GraphicBuffer(anb, false));
- ASSERT_EQ(NO_ERROR, mANW->lockBuffer(mANW.get(), buf->getNativeBuffer()));
// Fill the buffer with the a checkerboard pattern
uint8_t* img = NULL;
buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
fillYV12Buffer(img, texWidth, texHeight, buf->getStride());
buf->unlock();
- ASSERT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), buf->getNativeBuffer()));
+ ASSERT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), buf->getNativeBuffer(),
+ -1));
- mST->updateTexImage();
+ ASSERT_EQ(NO_ERROR, mST->updateTexImage());
glClearColor(0.2, 0.2, 0.2, 0.2);
glClear(GL_COLOR_BUFFER_BIT);
@@ -741,20 +743,21 @@ TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledYV12BufferPow2) {
GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN));
ANativeWindowBuffer* anb;
- ASSERT_EQ(NO_ERROR, mANW->dequeueBuffer(mANW.get(), &anb));
+ ASSERT_EQ(NO_ERROR, native_window_dequeue_buffer_and_wait(mANW.get(),
+ &anb));
ASSERT_TRUE(anb != NULL);
sp<GraphicBuffer> buf(new GraphicBuffer(anb, false));
- ASSERT_EQ(NO_ERROR, mANW->lockBuffer(mANW.get(), buf->getNativeBuffer()));
// Fill the buffer with the a checkerboard pattern
uint8_t* img = NULL;
buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
fillYV12Buffer(img, texWidth, texHeight, buf->getStride());
buf->unlock();
- ASSERT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), buf->getNativeBuffer()));
+ ASSERT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), buf->getNativeBuffer(),
+ -1));
- mST->updateTexImage();
+ ASSERT_EQ(NO_ERROR, mST->updateTexImage());
glClearColor(0.2, 0.2, 0.2, 0.2);
glClear(GL_COLOR_BUFFER_BIT);
@@ -801,21 +804,20 @@ TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledYV12BufferWithCrop) {
ASSERT_EQ(NO_ERROR, native_window_set_crop(mANW.get(), &crop));
ANativeWindowBuffer* anb;
- ASSERT_EQ(NO_ERROR, mANW->dequeueBuffer(mANW.get(), &anb));
+ ASSERT_EQ(NO_ERROR, native_window_dequeue_buffer_and_wait(mANW.get(),
+ &anb));
ASSERT_TRUE(anb != NULL);
sp<GraphicBuffer> buf(new GraphicBuffer(anb, false));
- ASSERT_EQ(NO_ERROR, mANW->lockBuffer(mANW.get(),
- buf->getNativeBuffer()));
uint8_t* img = NULL;
buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
fillYV12BufferRect(img, texWidth, texHeight, buf->getStride(), crop);
buf->unlock();
ASSERT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(),
- buf->getNativeBuffer()));
+ buf->getNativeBuffer(), -1));
- mST->updateTexImage();
+ ASSERT_EQ(NO_ERROR, mST->updateTexImage());
glClearColor(0.2, 0.2, 0.2, 0.2);
glClear(GL_COLOR_BUFFER_BIT);
@@ -846,7 +848,7 @@ TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledYV12BuffersRepeatedly) {
enum { numFrames = 1024 };
ASSERT_EQ(NO_ERROR, mST->setSynchronousMode(true));
- ASSERT_EQ(NO_ERROR, mST->setBufferCountServer(2));
+ 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_usage(mANW.get(),
@@ -877,7 +879,8 @@ TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledYV12BuffersRepeatedly) {
virtual bool threadLoop() {
for (int i = 0; i < numFrames; i++) {
ANativeWindowBuffer* anb;
- if (mANW->dequeueBuffer(mANW.get(), &anb) != NO_ERROR) {
+ if (native_window_dequeue_buffer_and_wait(mANW.get(),
+ &anb) != NO_ERROR) {
return false;
}
if (anb == NULL) {
@@ -885,10 +888,6 @@ TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledYV12BuffersRepeatedly) {
}
sp<GraphicBuffer> buf(new GraphicBuffer(anb, false));
- if (mANW->lockBuffer(mANW.get(), buf->getNativeBuffer())
- != NO_ERROR) {
- return false;
- }
const int yuvTexOffsetY = 0;
int stride = buf->getStride();
@@ -932,7 +931,7 @@ TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledYV12BuffersRepeatedly) {
}
buf->unlock();
- if (mANW->queueBuffer(mANW.get(), buf->getNativeBuffer())
+ if (mANW->queueBuffer(mANW.get(), buf->getNativeBuffer(), -1)
!= NO_ERROR) {
return false;
}
@@ -967,7 +966,7 @@ TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledYV12BuffersRepeatedly) {
if (i > 1) {
mFW->waitForFrame();
}
- mST->updateTexImage();
+ ASSERT_EQ(NO_ERROR, mST->updateTexImage());
drawTexture();
for (int j = 0; j < numTestPixels; j++) {
@@ -998,7 +997,7 @@ TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledRGBABufferNpot) {
ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW));
- mST->updateTexImage();
+ ASSERT_EQ(NO_ERROR, mST->updateTexImage());
glClearColor(0.2, 0.2, 0.2, 0.2);
glClear(GL_COLOR_BUFFER_BIT);
@@ -1040,7 +1039,7 @@ TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledRGBABufferPow2) {
ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW));
- mST->updateTexImage();
+ ASSERT_EQ(NO_ERROR, mST->updateTexImage());
glClearColor(0.2, 0.2, 0.2, 0.2);
glClear(GL_COLOR_BUFFER_BIT);
@@ -1093,13 +1092,14 @@ TEST_F(SurfaceTextureGLTest, DisconnectStressTest) {
for (int numFrames =0 ; numFrames < 2; numFrames ++) {
- if (mANW->dequeueBuffer(mANW.get(), &anb) != NO_ERROR) {
+ if (native_window_dequeue_buffer_and_wait(mANW.get(),
+ &anb) != NO_ERROR) {
return false;
}
if (anb == NULL) {
return false;
}
- if (mANW->queueBuffer(mANW.get(), anb)
+ if (mANW->queueBuffer(mANW.get(), anb, -1)
!= NO_ERROR) {
return false;
}
@@ -1147,11 +1147,11 @@ TEST_F(SurfaceTextureGLTest, DisconnectClearsCurrentTexture) {
ANativeWindowBuffer *anb;
- EXPECT_EQ (OK, mANW->dequeueBuffer(mANW.get(), &anb));
- EXPECT_EQ(OK, mANW->queueBuffer(mANW.get(), anb));
+ EXPECT_EQ (OK, native_window_dequeue_buffer_and_wait(mANW.get(), &anb));
+ EXPECT_EQ(OK, mANW->queueBuffer(mANW.get(), anb, -1));
- EXPECT_EQ (OK, mANW->dequeueBuffer(mANW.get(), &anb));
- EXPECT_EQ(OK, mANW->queueBuffer(mANW.get(), anb));
+ EXPECT_EQ (OK, native_window_dequeue_buffer_and_wait(mANW.get(), &anb));
+ EXPECT_EQ(OK, mANW->queueBuffer(mANW.get(), anb, -1));
EXPECT_EQ(OK,mST->updateTexImage());
EXPECT_EQ(OK,mST->updateTexImage());
@@ -1163,8 +1163,8 @@ TEST_F(SurfaceTextureGLTest, DisconnectClearsCurrentTexture) {
ASSERT_EQ(OK, mST->setSynchronousMode(true));
- EXPECT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &anb));
- EXPECT_EQ(OK, mANW->queueBuffer(mANW.get(), anb));
+ EXPECT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &anb));
+ EXPECT_EQ(OK, mANW->queueBuffer(mANW.get(), anb, -1));
// Will fail here if mCurrentTexture is not cleared properly
mFW->waitForFrame();
@@ -1193,10 +1193,10 @@ TEST_F(SurfaceTextureGLTest, ScaleToWindowMode) {
android_native_rect_t odd = {23, 78, 123, 477};
ASSERT_EQ(OK, native_window_set_crop(mANW.get(), &odd));
- EXPECT_EQ (OK, mANW->dequeueBuffer(mANW.get(), &anb));
- EXPECT_EQ(OK, mANW->queueBuffer(mANW.get(), anb));
+ EXPECT_EQ (OK, native_window_dequeue_buffer_and_wait(mANW.get(), &anb));
+ EXPECT_EQ(OK, mANW->queueBuffer(mANW.get(), anb, -1));
mFW->waitForFrame();
- EXPECT_EQ(OK,mST->updateTexImage());
+ EXPECT_EQ(OK, mST->updateTexImage());
Rect r = mST->getCurrentCrop();
assertRectEq(Rect(23, 78, 123, 477), r);
@@ -1227,10 +1227,10 @@ TEST_F(SurfaceTextureGLTest, CroppedScalingMode) {
// The crop is in the shape of (320, 180) === 16 x 9
android_native_rect_t standard = {10, 20, 330, 200};
ASSERT_EQ(OK, native_window_set_crop(mANW.get(), &standard));
- EXPECT_EQ (OK, mANW->dequeueBuffer(mANW.get(), &anb));
- EXPECT_EQ(OK, mANW->queueBuffer(mANW.get(), anb));
+ EXPECT_EQ (OK, native_window_dequeue_buffer_and_wait(mANW.get(), &anb));
+ EXPECT_EQ(OK, mANW->queueBuffer(mANW.get(), anb, -1));
mFW->waitForFrame();
- EXPECT_EQ(OK,mST->updateTexImage());
+ EXPECT_EQ(OK, mST->updateTexImage());
Rect r = mST->getCurrentCrop();
// crop should be the same as crop (same aspect ratio)
assertRectEq(Rect(10, 20, 330, 200), r);
@@ -1238,10 +1238,10 @@ TEST_F(SurfaceTextureGLTest, CroppedScalingMode) {
// make this wider then desired aspect 239 x 100 (2.39:1)
android_native_rect_t wide = {20, 30, 259, 130};
ASSERT_EQ(OK, native_window_set_crop(mANW.get(), &wide));
- EXPECT_EQ (OK, mANW->dequeueBuffer(mANW.get(), &anb));
- EXPECT_EQ(OK, mANW->queueBuffer(mANW.get(), anb));
+ EXPECT_EQ (OK, native_window_dequeue_buffer_and_wait(mANW.get(), &anb));
+ EXPECT_EQ(OK, mANW->queueBuffer(mANW.get(), anb, -1));
mFW->waitForFrame();
- EXPECT_EQ(OK,mST->updateTexImage());
+ EXPECT_EQ(OK, mST->updateTexImage());
r = mST->getCurrentCrop();
// crop should be the same height, but have cropped left and right borders
// offset is 30.6 px L+, R-
@@ -1250,10 +1250,10 @@ TEST_F(SurfaceTextureGLTest, CroppedScalingMode) {
// This image is taller then desired aspect 400 x 300 (4:3)
android_native_rect_t narrow = {0, 0, 400, 300};
ASSERT_EQ(OK, native_window_set_crop(mANW.get(), &narrow));
- EXPECT_EQ (OK, mANW->dequeueBuffer(mANW.get(), &anb));
- EXPECT_EQ(OK, mANW->queueBuffer(mANW.get(), anb));
+ EXPECT_EQ (OK, native_window_dequeue_buffer_and_wait(mANW.get(), &anb));
+ EXPECT_EQ(OK, mANW->queueBuffer(mANW.get(), anb, -1));
mFW->waitForFrame();
- EXPECT_EQ(OK,mST->updateTexImage());
+ EXPECT_EQ(OK, mST->updateTexImage());
r = mST->getCurrentCrop();
// crop should be the same width, but have cropped top and bottom borders
// offset is 37.5 px
@@ -1278,31 +1278,34 @@ TEST_F(SurfaceTextureGLTest, AbandonUnblocksDequeueBuffer) {
ANativeWindowBuffer* anb;
// Frame 1
- if (mANW->dequeueBuffer(mANW.get(), &anb) != NO_ERROR) {
+ if (native_window_dequeue_buffer_and_wait(mANW.get(),
+ &anb) != NO_ERROR) {
return false;
}
if (anb == NULL) {
return false;
}
- if (mANW->queueBuffer(mANW.get(), anb)
+ if (mANW->queueBuffer(mANW.get(), anb, -1)
!= NO_ERROR) {
return false;
}
// Frame 2
- if (mANW->dequeueBuffer(mANW.get(), &anb) != NO_ERROR) {
+ if (native_window_dequeue_buffer_and_wait(mANW.get(),
+ &anb) != NO_ERROR) {
return false;
}
if (anb == NULL) {
return false;
}
- if (mANW->queueBuffer(mANW.get(), anb)
+ if (mANW->queueBuffer(mANW.get(), anb, -1)
!= NO_ERROR) {
return false;
}
// Frame 3 - error expected
- mDequeueError = mANW->dequeueBuffer(mANW.get(), &anb);
+ mDequeueError = native_window_dequeue_buffer_and_wait(mANW.get(),
+ &anb);
return false;
}
@@ -1318,7 +1321,7 @@ TEST_F(SurfaceTextureGLTest, AbandonUnblocksDequeueBuffer) {
};
ASSERT_EQ(OK, mST->setSynchronousMode(true));
- ASSERT_EQ(OK, mST->setBufferCountServer(2));
+ ASSERT_EQ(OK, mST->setDefaultMaxBufferCount(2));
sp<Thread> pt(new ProducerThread(mANW));
pt->run();
@@ -1346,26 +1349,29 @@ TEST_F(SurfaceTextureGLTest, InvalidWidthOrHeightFails) {
// make sure it works with small textures
mST->setDefaultBufferSize(16, texHeight);
- EXPECT_EQ(NO_ERROR, mANW->dequeueBuffer(mANW.get(), &anb));
+ EXPECT_EQ(NO_ERROR, native_window_dequeue_buffer_and_wait(mANW.get(),
+ &anb));
EXPECT_EQ(16, anb->width);
EXPECT_EQ(texHeight, anb->height);
- EXPECT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), anb));
+ EXPECT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), anb, -1));
EXPECT_EQ(NO_ERROR, mST->updateTexImage());
// make sure it works with GL_MAX_TEXTURE_SIZE
mST->setDefaultBufferSize(maxTextureSize, texHeight);
- EXPECT_EQ(NO_ERROR, mANW->dequeueBuffer(mANW.get(), &anb));
+ EXPECT_EQ(NO_ERROR, native_window_dequeue_buffer_and_wait(mANW.get(),
+ &anb));
EXPECT_EQ(maxTextureSize, anb->width);
EXPECT_EQ(texHeight, anb->height);
- EXPECT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), anb));
+ EXPECT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), anb, -1));
EXPECT_EQ(NO_ERROR, mST->updateTexImage());
// make sure it fails with GL_MAX_TEXTURE_SIZE+1
mST->setDefaultBufferSize(maxTextureSize+1, texHeight);
- EXPECT_EQ(NO_ERROR, mANW->dequeueBuffer(mANW.get(), &anb));
+ EXPECT_EQ(NO_ERROR, native_window_dequeue_buffer_and_wait(mANW.get(),
+ &anb));
EXPECT_EQ(maxTextureSize+1, anb->width);
EXPECT_EQ(texHeight, anb->height);
- EXPECT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), anb));
+ EXPECT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), anb, -1));
ASSERT_NE(NO_ERROR, mST->updateTexImage());
}
@@ -1408,12 +1414,68 @@ protected:
EGLContext mProducerEglContext;
};
+TEST_F(SurfaceTextureGLToGLTest, TransformHintGetsRespected) {
+ const uint32_t texWidth = 32;
+ const uint32_t texHeight = 64;
+
+ mST->setDefaultBufferSize(texWidth, texHeight);
+ mST->setTransformHint(NATIVE_WINDOW_TRANSFORM_ROT_90);
+
+ // This test requires 3 buffers to avoid deadlock because we're
+ // both producer and consumer, and only using one thread.
+ mST->setDefaultMaxBufferCount(3);
+
+ // Do the producer side of things
+ EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mProducerEglSurface,
+ mProducerEglSurface, mProducerEglContext));
+ ASSERT_EQ(EGL_SUCCESS, eglGetError());
+
+ // Start a buffer with our chosen size and transform hint moving
+ // through the system.
+ glClear(GL_COLOR_BUFFER_BIT); // give the driver something to do
+ eglSwapBuffers(mEglDisplay, mProducerEglSurface);
+ mST->updateTexImage(); // consume it
+ // Swap again.
+ glClear(GL_COLOR_BUFFER_BIT);
+ eglSwapBuffers(mEglDisplay, mProducerEglSurface);
+ mST->updateTexImage();
+
+ // The current buffer should either show the effects of the transform
+ // hint (in the form of an inverse transform), or show that the
+ // transform hint has been ignored.
+ sp<GraphicBuffer> buf = mST->getCurrentBuffer();
+ if (mST->getCurrentTransform() == NATIVE_WINDOW_TRANSFORM_ROT_270) {
+ ASSERT_EQ(texWidth, buf->getHeight());
+ ASSERT_EQ(texHeight, buf->getWidth());
+ } else {
+ ASSERT_EQ(texWidth, buf->getWidth());
+ ASSERT_EQ(texHeight, buf->getHeight());
+ }
+
+ // Reset the transform hint and confirm that it takes.
+ mST->setTransformHint(0);
+ glClear(GL_COLOR_BUFFER_BIT);
+ eglSwapBuffers(mEglDisplay, mProducerEglSurface);
+ mST->updateTexImage();
+ glClear(GL_COLOR_BUFFER_BIT);
+ eglSwapBuffers(mEglDisplay, mProducerEglSurface);
+ mST->updateTexImage();
+
+ buf = mST->getCurrentBuffer();
+ ASSERT_EQ((uint32_t) 0, mST->getCurrentTransform());
+ ASSERT_EQ(texWidth, buf->getWidth());
+ ASSERT_EQ(texHeight, buf->getHeight());
+}
+
TEST_F(SurfaceTextureGLToGLTest, TexturingFromGLFilledRGBABufferPow2) {
const int texWidth = 64;
const int texHeight = 64;
mST->setDefaultBufferSize(texWidth, texHeight);
+ // This test requires 3 buffers to complete run on a single thread.
+ mST->setDefaultMaxBufferCount(3);
+
// Do the producer side of things
EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mProducerEglSurface,
mProducerEglSurface, mProducerEglContext));
@@ -1447,8 +1509,9 @@ TEST_F(SurfaceTextureGLToGLTest, TexturingFromGLFilledRGBABufferPow2) {
glDisable(GL_SCISSOR_TEST);
- mST->updateTexImage(); // Skip the first frame, which was empty
- mST->updateTexImage();
+ // Skip the first frame, which was empty
+ ASSERT_EQ(NO_ERROR, mST->updateTexImage());
+ ASSERT_EQ(NO_ERROR, mST->updateTexImage());
glClearColor(0.2, 0.2, 0.2, 0.2);
glClear(GL_COLOR_BUFFER_BIT);
@@ -1502,7 +1565,7 @@ TEST_F(SurfaceTextureGLToGLTest, EglDestroySurfaceUnrefsBuffers) {
mEglContext));
ASSERT_EQ(EGL_SUCCESS, eglGetError());
mFW->waitForFrame();
- mST->updateTexImage();
+ ASSERT_EQ(NO_ERROR, mST->updateTexImage());
buffers[i] = mST->getCurrentBuffer();
}
@@ -1578,7 +1641,7 @@ TEST_F(SurfaceTextureGLToGLTest, EglDestroySurfaceAfterAbandonUnrefsBuffers) {
TEST_F(SurfaceTextureGLToGLTest, EglSurfaceDefaultsToSynchronousMode) {
// This test requires 3 buffers to run on a single thread.
- mST->setBufferCountServer(3);
+ mST->setDefaultMaxBufferCount(3);
ASSERT_TRUE(mST->isSynchronousMode());
@@ -1605,6 +1668,9 @@ TEST_F(SurfaceTextureGLToGLTest, TexturingFromUserSizedGLFilledBuffer) {
enum { texWidth = 64 };
enum { texHeight = 64 };
+ // This test requires 3 buffers to complete run on a single thread.
+ mST->setDefaultMaxBufferCount(3);
+
// Set the user buffer size.
native_window_set_buffers_user_dimensions(mANW.get(), texWidth, texHeight);
@@ -1633,8 +1699,9 @@ TEST_F(SurfaceTextureGLToGLTest, TexturingFromUserSizedGLFilledBuffer) {
glDisable(GL_SCISSOR_TEST);
- mST->updateTexImage(); // Skip the first frame, which was empty
- mST->updateTexImage();
+ // Skip the first frame, which was empty
+ ASSERT_EQ(NO_ERROR, mST->updateTexImage());
+ ASSERT_EQ(NO_ERROR, mST->updateTexImage());
glClearColor(0.2, 0.2, 0.2, 0.2);
glClear(GL_COLOR_BUFFER_BIT);
@@ -1658,6 +1725,9 @@ TEST_F(SurfaceTextureGLToGLTest, TexturingFromPreRotatedUserSizedGLFilledBuffer)
enum { texWidth = 64 };
enum { texHeight = 16 };
+ // This test requires 3 buffers to complete run on a single thread.
+ mST->setDefaultMaxBufferCount(3);
+
// Set the transform hint.
mST->setTransformHint(NATIVE_WINDOW_TRANSFORM_ROT_90);
@@ -1690,8 +1760,9 @@ TEST_F(SurfaceTextureGLToGLTest, TexturingFromPreRotatedUserSizedGLFilledBuffer)
glDisable(GL_SCISSOR_TEST);
- mST->updateTexImage(); // Skip the first frame, which was empty
- mST->updateTexImage();
+ // Skip the first frame, which was empty
+ ASSERT_EQ(NO_ERROR, mST->updateTexImage());
+ ASSERT_EQ(NO_ERROR, mST->updateTexImage());
glClearColor(0.2, 0.2, 0.2, 0.2);
glClear(GL_COLOR_BUFFER_BIT);
@@ -1715,6 +1786,9 @@ TEST_F(SurfaceTextureGLToGLTest, TexturingFromPreRotatedGLFilledBuffer) {
enum { texWidth = 64 };
enum { texHeight = 16 };
+ // This test requires 3 buffers to complete run on a single thread.
+ mST->setDefaultMaxBufferCount(3);
+
// Set the transform hint.
mST->setTransformHint(NATIVE_WINDOW_TRANSFORM_ROT_90);
@@ -1747,8 +1821,9 @@ TEST_F(SurfaceTextureGLToGLTest, TexturingFromPreRotatedGLFilledBuffer) {
glDisable(GL_SCISSOR_TEST);
- mST->updateTexImage(); // Skip the first frame, which was empty
- mST->updateTexImage();
+ // Skip the first frame, which was empty
+ ASSERT_EQ(NO_ERROR, mST->updateTexImage());
+ ASSERT_EQ(NO_ERROR, mST->updateTexImage());
glClearColor(0.2, 0.2, 0.2, 0.2);
glClear(GL_COLOR_BUFFER_BIT);
@@ -1938,7 +2013,7 @@ TEST_F(SurfaceTextureGLThreadToGLTest,
runProducerThread(new PT());
mFC->waitForFrame();
- mST->updateTexImage();
+ ASSERT_EQ(NO_ERROR, mST->updateTexImage());
mFC->finishFrame();
// TODO: Add frame verification once RGB TEX_EXTERNAL_OES is supported!
@@ -1958,7 +2033,7 @@ TEST_F(SurfaceTextureGLThreadToGLTest,
mFC->waitForFrame();
mFC->finishFrame();
- mST->updateTexImage();
+ ASSERT_EQ(NO_ERROR, mST->updateTexImage());
// TODO: Add frame verification once RGB TEX_EXTERNAL_OES is supported!
}
@@ -1984,7 +2059,7 @@ TEST_F(SurfaceTextureGLThreadToGLTest,
for (int i = 0; i < NUM_ITERATIONS; i++) {
mFC->waitForFrame();
ALOGV("+updateTexImage");
- mST->updateTexImage();
+ ASSERT_EQ(NO_ERROR, mST->updateTexImage());
ALOGV("-updateTexImage");
mFC->finishFrame();
@@ -2014,7 +2089,7 @@ TEST_F(SurfaceTextureGLThreadToGLTest,
mFC->waitForFrame();
mFC->finishFrame();
ALOGV("+updateTexImage");
- mST->updateTexImage();
+ ASSERT_EQ(NO_ERROR, mST->updateTexImage());
ALOGV("-updateTexImage");
// TODO: Add frame verification once RGB TEX_EXTERNAL_OES is supported!
@@ -2039,7 +2114,7 @@ TEST_F(SurfaceTextureGLThreadToGLTest,
};
ASSERT_EQ(OK, mST->setSynchronousMode(true));
- ASSERT_EQ(OK, mST->setBufferCountServer(2));
+ ASSERT_EQ(OK, mST->setDefaultMaxBufferCount(2));
runProducerThread(new PT());
@@ -2053,10 +2128,10 @@ TEST_F(SurfaceTextureGLThreadToGLTest,
// We must call updateTexImage to consume the first frame so that the
// SurfaceTexture is able to reduce the buffer count to 2. This is because
// the GL driver may dequeue a buffer when the EGLSurface is created, and
- // that happens before we call setBufferCountServer. It's possible that the
+ // that happens before we call setDefaultMaxBufferCount. It's possible that the
// driver does not dequeue a buffer at EGLSurface creation time, so we
// cannot rely on this to cause the second dequeueBuffer call to block.
- mST->updateTexImage();
+ ASSERT_EQ(NO_ERROR, mST->updateTexImage());
mFC->waitForFrame();
mFC->finishFrame();
@@ -2075,15 +2150,15 @@ TEST_F(SurfaceTextureGLThreadToGLTest,
}
// Consume the two pending buffers to unblock the producer thread.
- mST->updateTexImage();
- mST->updateTexImage();
+ ASSERT_EQ(NO_ERROR, mST->updateTexImage());
+ ASSERT_EQ(NO_ERROR, mST->updateTexImage());
// Consume the remaining buffers from the producer thread.
for (int i = 0; i < NUM_ITERATIONS-3; i++) {
mFC->waitForFrame();
mFC->finishFrame();
ALOGV("+updateTexImage");
- mST->updateTexImage();
+ ASSERT_EQ(NO_ERROR, mST->updateTexImage());
ALOGV("-updateTexImage");
}
}
@@ -2134,11 +2209,11 @@ TEST_F(SurfaceTextureFBOTest, BlitFromCpuFilledBufferToFbo) {
GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN));
android_native_buffer_t* anb;
- ASSERT_EQ(NO_ERROR, mANW->dequeueBuffer(mANW.get(), &anb));
+ ASSERT_EQ(NO_ERROR, native_window_dequeue_buffer_and_wait(mANW.get(),
+ &anb));
ASSERT_TRUE(anb != NULL);
sp<GraphicBuffer> buf(new GraphicBuffer(anb, false));
- ASSERT_EQ(NO_ERROR, mANW->lockBuffer(mANW.get(), buf->getNativeBuffer()));
// Fill the buffer with green
uint8_t* img = NULL;
@@ -2146,7 +2221,8 @@ TEST_F(SurfaceTextureFBOTest, BlitFromCpuFilledBufferToFbo) {
fillRGBA8BufferSolid(img, texWidth, texHeight, buf->getStride(), 0, 255,
0, 255);
buf->unlock();
- ASSERT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), buf->getNativeBuffer()));
+ ASSERT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), buf->getNativeBuffer(),
+ -1));
ASSERT_EQ(NO_ERROR, mST->updateTexImage());
@@ -2157,12 +2233,11 @@ TEST_F(SurfaceTextureFBOTest, BlitFromCpuFilledBufferToFbo) {
for (int i = 0; i < 4; i++) {
SCOPED_TRACE(String8::format("frame %d", i).string());
- ASSERT_EQ(NO_ERROR, mANW->dequeueBuffer(mANW.get(), &anb));
+ ASSERT_EQ(NO_ERROR, native_window_dequeue_buffer_and_wait(mANW.get(),
+ &anb));
ASSERT_TRUE(anb != NULL);
buf = new GraphicBuffer(anb, false);
- ASSERT_EQ(NO_ERROR, mANW->lockBuffer(mANW.get(),
- buf->getNativeBuffer()));
// Fill the buffer with red
ASSERT_EQ(NO_ERROR, buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN,
@@ -2171,7 +2246,7 @@ TEST_F(SurfaceTextureFBOTest, BlitFromCpuFilledBufferToFbo) {
0, 255);
ASSERT_EQ(NO_ERROR, buf->unlock());
ASSERT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(),
- buf->getNativeBuffer()));
+ buf->getNativeBuffer(), -1));
ASSERT_EQ(NO_ERROR, mST->updateTexImage());
@@ -2580,7 +2655,7 @@ TEST_F(SurfaceTextureMultiContextGLTest,
TEST_F(SurfaceTextureMultiContextGLTest,
UpdateTexImageSucceedsForBufferConsumedBeforeDetach) {
ASSERT_EQ(NO_ERROR, mST->setSynchronousMode(true));
- ASSERT_EQ(NO_ERROR, mST->setBufferCountServer(2));
+ ASSERT_EQ(NO_ERROR, mST->setDefaultMaxBufferCount(2));
// produce two frames and consume them both on the primary context
ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW));
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index b585d68..545b547 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -33,7 +33,7 @@ protected:
ASSERT_EQ(NO_ERROR, mComposerClient->initCheck());
mSurfaceControl = mComposerClient->createSurface(
- String8("Test Surface"), 0, 32, 32, PIXEL_FORMAT_RGBA_8888, 0);
+ String8("Test Surface"), 32, 32, PIXEL_FORMAT_RGBA_8888, 0);
ASSERT_TRUE(mSurfaceControl != NULL);
ASSERT_TRUE(mSurfaceControl->isValid());
@@ -85,7 +85,8 @@ TEST_F(SurfaceTest, ScreenshotsOfProtectedBuffersSucceed) {
uint32_t w=0, h=0;
PixelFormat fmt=0;
sp<ISurfaceComposer> sf(ComposerService::getComposerService());
- ASSERT_EQ(NO_ERROR, sf->captureScreen(0, &heap, &w, &h, &fmt, 64, 64, 0,
+ sp<IBinder> display(sf->getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
+ ASSERT_EQ(NO_ERROR, sf->captureScreen(display, &heap, &w, &h, &fmt, 64, 64, 0,
0x7fffffff));
ASSERT_TRUE(heap != NULL);
@@ -97,26 +98,27 @@ TEST_F(SurfaceTest, ScreenshotsOfProtectedBuffersSucceed) {
ASSERT_EQ(NO_ERROR, native_window_set_buffer_count(anw.get(), 3));
ANativeWindowBuffer* buf = 0;
- status_t err = anw->dequeueBuffer(anw.get(), &buf);
+ status_t err = native_window_dequeue_buffer_and_wait(anw.get(), &buf);
if (err) {
// we could fail if GRALLOC_USAGE_PROTECTED is not supported.
// that's okay as long as this is the reason for the failure.
// try again without the GRALLOC_USAGE_PROTECTED bit.
ASSERT_EQ(NO_ERROR, native_window_set_usage(anw.get(), 0));
- ASSERT_EQ(NO_ERROR, anw->dequeueBuffer(anw.get(), &buf));
+ ASSERT_EQ(NO_ERROR, native_window_dequeue_buffer_and_wait(anw.get(),
+ &buf));
return;
}
- ASSERT_EQ(NO_ERROR, anw->cancelBuffer(anw.get(), buf));
+ ASSERT_EQ(NO_ERROR, anw->cancelBuffer(anw.get(), buf, -1));
for (int i = 0; i < 4; i++) {
// Loop to make sure SurfaceFlinger has retired a protected buffer.
- ASSERT_EQ(NO_ERROR, anw->dequeueBuffer(anw.get(), &buf));
- ASSERT_EQ(NO_ERROR, anw->lockBuffer(anw.get(), buf));
- ASSERT_EQ(NO_ERROR, anw->queueBuffer(anw.get(), buf));
+ ASSERT_EQ(NO_ERROR, native_window_dequeue_buffer_and_wait(anw.get(),
+ &buf));
+ ASSERT_EQ(NO_ERROR, anw->queueBuffer(anw.get(), buf, -1));
}
heap = 0;
w = h = fmt = 0;
- ASSERT_EQ(NO_ERROR, sf->captureScreen(0, &heap, &w, &h, &fmt,
+ ASSERT_EQ(NO_ERROR, sf->captureScreen(display, &heap, &w, &h, &fmt,
64, 64, 0, 0x7fffffff));
ASSERT_TRUE(heap != NULL);
}
diff --git a/libs/ui/Android.mk b/libs/ui/Android.mk
index 5aff7a4..0d2e44c 100644
--- a/libs/ui/Android.mk
+++ b/libs/ui/Android.mk
@@ -16,18 +16,21 @@ LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
+ Fence.cpp \
FramebufferNativeWindow.cpp \
GraphicBuffer.cpp \
GraphicBufferAllocator.cpp \
GraphicBufferMapper.cpp \
PixelFormat.cpp \
Rect.cpp \
- Region.cpp
+ Region.cpp \
+ UiConfig.cpp
LOCAL_SHARED_LIBRARIES := \
libcutils \
- libutils \
- libhardware
+ libhardware \
+ libsync \
+ libutils
ifneq ($(BOARD_FRAMEBUFFER_FORCE_FORMAT),)
LOCAL_CFLAGS += -DFRAMEBUFFER_FORCE_FORMAT=$(BOARD_FRAMEBUFFER_FORCE_FORMAT)
diff --git a/libs/ui/Fence.cpp b/libs/ui/Fence.cpp
new file mode 100644
index 0000000..d214b97
--- /dev/null
+++ b/libs/ui/Fence.cpp
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2012 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 "Fence"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+//#define LOG_NDEBUG 0
+
+#include <sync/sync.h>
+#include <ui/Fence.h>
+#include <unistd.h>
+#include <utils/Log.h>
+#include <utils/Trace.h>
+
+namespace android {
+
+const sp<Fence> Fence::NO_FENCE = sp<Fence>();
+
+Fence::Fence() :
+ mFenceFd(-1) {
+}
+
+Fence::Fence(int fenceFd) :
+ mFenceFd(fenceFd) {
+}
+
+Fence::~Fence() {
+ if (mFenceFd != -1) {
+ close(mFenceFd);
+ }
+}
+
+status_t Fence::wait(unsigned int timeout) {
+ ATRACE_CALL();
+ if (mFenceFd == -1) {
+ return NO_ERROR;
+ }
+ int err = sync_wait(mFenceFd, timeout);
+ return err < 0 ? -errno : status_t(NO_ERROR);
+}
+
+status_t Fence::waitForever(unsigned int warningTimeout, const char* logname) {
+ ATRACE_CALL();
+ if (mFenceFd == -1) {
+ return NO_ERROR;
+ }
+ int err = sync_wait(mFenceFd, warningTimeout);
+ if (err < 0 && errno == ETIME) {
+ ALOGE("%s: fence %d didn't signal in %u ms", logname, mFenceFd,
+ warningTimeout);
+ err = sync_wait(mFenceFd, TIMEOUT_NEVER);
+ }
+ return err < 0 ? -errno : status_t(NO_ERROR);
+}
+
+sp<Fence> Fence::merge(const String8& name, const sp<Fence>& f1,
+ const sp<Fence>& f2) {
+ ATRACE_CALL();
+ int result = sync_merge(name.string(), f1->mFenceFd, f2->mFenceFd);
+ if (result == -1) {
+ status_t err = -errno;
+ ALOGE("merge: sync_merge(\"%s\", %d, %d) returned an error: %s (%d)",
+ name.string(), f1->mFenceFd, f2->mFenceFd,
+ strerror(-err), err);
+ return NO_FENCE;
+ }
+ return sp<Fence>(new Fence(result));
+}
+
+int Fence::dup() const {
+ if (mFenceFd == -1) {
+ return -1;
+ }
+ return ::dup(mFenceFd);
+}
+
+size_t Fence::getFlattenedSize() const {
+ return 0;
+}
+
+size_t Fence::getFdCount() const {
+ return 1;
+}
+
+status_t Fence::flatten(void* buffer, size_t size, int fds[],
+ size_t count) const {
+ if (size != 0 || count != 1) {
+ return BAD_VALUE;
+ }
+
+ fds[0] = mFenceFd;
+ return NO_ERROR;
+}
+
+status_t Fence::unflatten(void const* buffer, size_t size, int fds[],
+ size_t count) {
+ if (size != 0 || count != 1) {
+ return BAD_VALUE;
+ }
+ if (mFenceFd != -1) {
+ // Don't unflatten if we already have a valid fd.
+ return INVALID_OPERATION;
+ }
+
+ mFenceFd = fds[0];
+ return NO_ERROR;
+}
+
+} // namespace android
diff --git a/libs/ui/FramebufferNativeWindow.cpp b/libs/ui/FramebufferNativeWindow.cpp
index dec99b6..31a69b2 100644
--- a/libs/ui/FramebufferNativeWindow.cpp
+++ b/libs/ui/FramebufferNativeWindow.cpp
@@ -28,6 +28,7 @@
#include <utils/RefBase.h>
#include <ui/ANativeObjectBase.h>
+#include <ui/Fence.h>
#include <ui/FramebufferNativeWindow.h>
#include <ui/Rect.h>
@@ -92,8 +93,13 @@ FramebufferNativeWindow::FramebufferNativeWindow()
mUpdateOnDemand = (fbDev->setUpdateRect != 0);
// initialize the buffer FIFO
- mNumBuffers = NUM_FRAME_BUFFERS;
- mNumFreeBuffers = NUM_FRAME_BUFFERS;
+ if(fbDev->numFramebuffers >= MIN_NUM_FRAME_BUFFERS &&
+ fbDev->numFramebuffers <= MAX_NUM_FRAME_BUFFERS){
+ mNumBuffers = fbDev->numFramebuffers;
+ } else {
+ mNumBuffers = MIN_NUM_FRAME_BUFFERS;
+ }
+ mNumFreeBuffers = mNumBuffers;
mBufferHead = mNumBuffers-1;
/*
@@ -145,19 +151,23 @@ FramebufferNativeWindow::FramebufferNativeWindow()
ANativeWindow::setSwapInterval = setSwapInterval;
ANativeWindow::dequeueBuffer = dequeueBuffer;
- ANativeWindow::lockBuffer = lockBuffer;
ANativeWindow::queueBuffer = queueBuffer;
ANativeWindow::query = query;
ANativeWindow::perform = perform;
+
+ ANativeWindow::dequeueBuffer_DEPRECATED = dequeueBuffer_DEPRECATED;
+ ANativeWindow::lockBuffer_DEPRECATED = lockBuffer_DEPRECATED;
+ ANativeWindow::queueBuffer_DEPRECATED = queueBuffer_DEPRECATED;
}
FramebufferNativeWindow::~FramebufferNativeWindow()
{
if (grDev) {
- if (buffers[0] != NULL)
- grDev->free(grDev, buffers[0]->handle);
- if (buffers[1] != NULL)
- grDev->free(grDev, buffers[1]->handle);
+ for(int i = 0; i < mNumBuffers; i++) {
+ if (buffers[i] != NULL) {
+ grDev->free(grDev, buffers[i]->handle);
+ }
+ }
gralloc_close(grDev);
}
@@ -207,9 +217,24 @@ int FramebufferNativeWindow::getCurrentBufferIndex() const
return index;
}
-int FramebufferNativeWindow::dequeueBuffer(ANativeWindow* window,
+int FramebufferNativeWindow::dequeueBuffer_DEPRECATED(ANativeWindow* window,
ANativeWindowBuffer** buffer)
{
+ int fenceFd = -1;
+ int result = dequeueBuffer(window, buffer, &fenceFd);
+ sp<Fence> fence(new Fence(fenceFd));
+ int waitResult = fence->wait(Fence::TIMEOUT_NEVER);
+ if (waitResult != OK) {
+ ALOGE("dequeueBuffer_DEPRECATED: Fence::wait returned an "
+ "error: %d", waitResult);
+ return waitResult;
+ }
+ return result;
+}
+
+int FramebufferNativeWindow::dequeueBuffer(ANativeWindow* window,
+ ANativeWindowBuffer** buffer, int* fenceFd)
+{
FramebufferNativeWindow* self = getSelf(window);
Mutex::Autolock _l(self->mutex);
framebuffer_device_t* fb = self->fbDev;
@@ -218,43 +243,45 @@ int FramebufferNativeWindow::dequeueBuffer(ANativeWindow* window,
if (self->mBufferHead >= self->mNumBuffers)
self->mBufferHead = 0;
- // wait for a free buffer
- while (!self->mNumFreeBuffers) {
+ // wait for a free non-front buffer
+ while (self->mNumFreeBuffers < 2) {
self->mCondition.wait(self->mutex);
}
+ ALOG_ASSERT(self->buffers[index] != self->front);
+
// get this buffer
self->mNumFreeBuffers--;
self->mCurrentBufferIndex = index;
*buffer = self->buffers[index].get();
+ *fenceFd = -1;
return 0;
}
-int FramebufferNativeWindow::lockBuffer(ANativeWindow* window,
+int FramebufferNativeWindow::lockBuffer_DEPRECATED(ANativeWindow* window,
ANativeWindowBuffer* buffer)
{
- FramebufferNativeWindow* self = getSelf(window);
- Mutex::Autolock _l(self->mutex);
-
- const int index = self->mCurrentBufferIndex;
-
- // wait that the buffer we're locking is not front anymore
- while (self->front == buffer) {
- self->mCondition.wait(self->mutex);
- }
-
return NO_ERROR;
}
-int FramebufferNativeWindow::queueBuffer(ANativeWindow* window,
+int FramebufferNativeWindow::queueBuffer_DEPRECATED(ANativeWindow* window,
ANativeWindowBuffer* buffer)
{
+ return queueBuffer(window, buffer, -1);
+}
+
+int FramebufferNativeWindow::queueBuffer(ANativeWindow* window,
+ ANativeWindowBuffer* buffer, int fenceFd)
+{
FramebufferNativeWindow* self = getSelf(window);
Mutex::Autolock _l(self->mutex);
framebuffer_device_t* fb = self->fbDev;
buffer_handle_t handle = static_cast<NativeBuffer*>(buffer)->handle;
+ sp<Fence> fence(new Fence(fenceFd));
+ fence->wait(Fence::TIMEOUT_NEVER);
+
const int index = self->mCurrentBufferIndex;
int res = fb->post(fb, handle);
self->front = static_cast<NativeBuffer*>(buffer);
diff --git a/libs/ui/GraphicBuffer.cpp b/libs/ui/GraphicBuffer.cpp
index 57063e5..b9cab85 100644
--- a/libs/ui/GraphicBuffer.cpp
+++ b/libs/ui/GraphicBuffer.cpp
@@ -258,7 +258,12 @@ status_t GraphicBuffer::unflatten(void const* buffer, size_t size,
mOwner = ownHandle;
if (handle != 0) {
- mBufferMapper.registerBuffer(handle);
+ status_t err = mBufferMapper.registerBuffer(handle);
+ if (err != NO_ERROR) {
+ ALOGE("unflatten: registerBuffer failed: %s (%d)",
+ strerror(-err), err);
+ return err;
+ }
}
return NO_ERROR;
diff --git a/libs/ui/GraphicBufferAllocator.cpp b/libs/ui/GraphicBufferAllocator.cpp
index ff550d9..fb43410 100644
--- a/libs/ui/GraphicBufferAllocator.cpp
+++ b/libs/ui/GraphicBufferAllocator.cpp
@@ -90,6 +90,105 @@ void GraphicBufferAllocator::dumpToSystemLog()
ALOGD("%s", s.string());
}
+class BufferLiberatorThread : public Thread {
+public:
+
+ static void queueCaptiveBuffer(buffer_handle_t handle) {
+ size_t queueSize;
+ {
+ Mutex::Autolock lock(sMutex);
+ if (sThread == NULL) {
+ sThread = new BufferLiberatorThread;
+ sThread->run("BufferLiberator");
+ }
+
+ sThread->mQueue.push_back(handle);
+ sThread->mQueuedCondition.signal();
+ queueSize = sThread->mQueue.size();
+ }
+ }
+
+ static void waitForLiberation() {
+ Mutex::Autolock lock(sMutex);
+
+ waitForLiberationLocked();
+ }
+
+ static void maybeWaitForLiberation() {
+ Mutex::Autolock lock(sMutex);
+ if (sThread != NULL) {
+ if (sThread->mQueue.size() > 8) {
+ waitForLiberationLocked();
+ }
+ }
+ }
+
+private:
+
+ BufferLiberatorThread() {}
+
+ virtual bool threadLoop() {
+ buffer_handle_t handle;
+ { // Scope for mutex
+ Mutex::Autolock lock(sMutex);
+ while (mQueue.isEmpty()) {
+ mQueuedCondition.wait(sMutex);
+ }
+ handle = mQueue[0];
+ }
+
+ status_t err;
+ GraphicBufferAllocator& gba(GraphicBufferAllocator::get());
+ { // Scope for tracing
+ ATRACE_NAME("gralloc::free");
+ err = gba.mAllocDev->free(gba.mAllocDev, handle);
+ }
+ ALOGW_IF(err, "free(...) failed %d (%s)", err, strerror(-err));
+
+ if (err == NO_ERROR) {
+ Mutex::Autolock _l(GraphicBufferAllocator::sLock);
+ KeyedVector<buffer_handle_t, GraphicBufferAllocator::alloc_rec_t>&
+ list(GraphicBufferAllocator::sAllocList);
+ list.removeItem(handle);
+ }
+
+ { // Scope for mutex
+ Mutex::Autolock lock(sMutex);
+ mQueue.removeAt(0);
+ mFreedCondition.broadcast();
+ }
+
+ return true;
+ }
+
+ static void waitForLiberationLocked() {
+ if (sThread == NULL) {
+ return;
+ }
+
+ const nsecs_t timeout = 500 * 1000 * 1000;
+ nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
+ nsecs_t timeToStop = now + timeout;
+ while (!sThread->mQueue.isEmpty() && now < timeToStop) {
+ sThread->mFreedCondition.waitRelative(sMutex, timeToStop - now);
+ now = systemTime(SYSTEM_TIME_MONOTONIC);
+ }
+
+ if (!sThread->mQueue.isEmpty()) {
+ ALOGW("waitForLiberationLocked timed out");
+ }
+ }
+
+ static Mutex sMutex;
+ static sp<BufferLiberatorThread> sThread;
+ Vector<buffer_handle_t> mQueue;
+ Condition mQueuedCondition;
+ Condition mFreedCondition;
+};
+
+Mutex BufferLiberatorThread::sMutex;
+sp<BufferLiberatorThread> BufferLiberatorThread::sThread;
+
status_t GraphicBufferAllocator::alloc(uint32_t w, uint32_t h, PixelFormat format,
int usage, buffer_handle_t* handle, int32_t* stride)
{
@@ -100,13 +199,24 @@ status_t GraphicBufferAllocator::alloc(uint32_t w, uint32_t h, PixelFormat forma
w = h = 1;
// we have a h/w allocator and h/w buffer is requested
- status_t err;
-
+ status_t err;
+
+ // If too many async frees are queued up then wait for some of them to
+ // complete before attempting to allocate more memory. This is exercised
+ // by the android.opengl.cts.GLSurfaceViewTest CTS test.
+ BufferLiberatorThread::maybeWaitForLiberation();
+
err = mAllocDev->alloc(mAllocDev, w, h, format, usage, handle, stride);
+ if (err != NO_ERROR) {
+ ALOGW("WOW! gralloc alloc failed, waiting for pending frees!");
+ BufferLiberatorThread::waitForLiberation();
+ err = mAllocDev->alloc(mAllocDev, w, h, format, usage, handle, stride);
+ }
+
ALOGW_IF(err, "alloc(%u, %u, %d, %08x, ...) failed %d (%s)",
w, h, format, usage, err, strerror(-err));
-
+
if (err == NO_ERROR) {
Mutex::Autolock _l(sLock);
KeyedVector<buffer_handle_t, alloc_rec_t>& list(sAllocList);
@@ -129,21 +239,11 @@ status_t GraphicBufferAllocator::alloc(uint32_t w, uint32_t h, PixelFormat forma
return err;
}
+
status_t GraphicBufferAllocator::free(buffer_handle_t handle)
{
- ATRACE_CALL();
- status_t err;
-
- err = mAllocDev->free(mAllocDev, handle);
-
- ALOGW_IF(err, "free(...) failed %d (%s)", err, strerror(-err));
- if (err == NO_ERROR) {
- Mutex::Autolock _l(sLock);
- KeyedVector<buffer_handle_t, alloc_rec_t>& list(sAllocList);
- list.removeItem(handle);
- }
-
- return err;
+ BufferLiberatorThread::queueCaptiveBuffer(handle);
+ return NO_ERROR;
}
// ---------------------------------------------------------------------------
diff --git a/libs/ui/Region.cpp b/libs/ui/Region.cpp
index 2c7cdf0..932ef68 100644
--- a/libs/ui/Region.cpp
+++ b/libs/ui/Region.cpp
@@ -20,6 +20,7 @@
#include <utils/Log.h>
#include <utils/String8.h>
+#include <utils/CallStack.h>
#include <ui/Rect.h>
#include <ui/Region.h>
@@ -48,28 +49,20 @@ enum {
// ----------------------------------------------------------------------------
-Region::Region()
- : mBounds(0,0)
-{
+Region::Region() {
+ mStorage.add(Rect(0,0));
}
Region::Region(const Region& rhs)
- : mBounds(rhs.mBounds), mStorage(rhs.mStorage)
+ : mStorage(rhs.mStorage)
{
#if VALIDATE_REGIONS
validate(rhs, "rhs copy-ctor");
#endif
}
-Region::Region(const Rect& rhs)
- : mBounds(rhs)
-{
-}
-
-Region::Region(const void* buffer)
-{
- status_t err = read(buffer);
- ALOGE_IF(err<0, "error %s reading Region from buffer", strerror(err));
+Region::Region(const Rect& rhs) {
+ mStorage.add(rhs);
}
Region::~Region()
@@ -82,43 +75,45 @@ Region& Region::operator = (const Region& rhs)
validate(*this, "this->operator=");
validate(rhs, "rhs.operator=");
#endif
- mBounds = rhs.mBounds;
mStorage = rhs.mStorage;
return *this;
}
Region& Region::makeBoundsSelf()
{
- mStorage.clear();
+ if (mStorage.size() >= 2) {
+ const Rect bounds(getBounds());
+ mStorage.clear();
+ mStorage.add(bounds);
+ }
return *this;
}
void Region::clear()
{
- mBounds.clear();
mStorage.clear();
+ mStorage.add(Rect(0,0));
}
void Region::set(const Rect& r)
{
- mBounds = r;
mStorage.clear();
+ mStorage.add(r);
}
void Region::set(uint32_t w, uint32_t h)
{
- mBounds = Rect(int(w), int(h));
mStorage.clear();
+ mStorage.add(Rect(w,h));
}
// ----------------------------------------------------------------------------
void Region::addRectUnchecked(int l, int t, int r, int b)
{
- mStorage.add(Rect(l,t,r,b));
-#if VALIDATE_REGIONS
- validate(*this, "addRectUnchecked");
-#endif
+ Rect rect(l,t,r,b);
+ size_t where = mStorage.size() - 1;
+ mStorage.insertAt(rect, where, 1);
}
// ----------------------------------------------------------------------------
@@ -258,7 +253,7 @@ const Region Region::operation(const Region& rhs, int dx, int dy, int op) const
// to obtain an optimal region.
class Region::rasterizer : public region_operator<Rect>::region_rasterizer
{
- Rect& bounds;
+ Rect bounds;
Vector<Rect>& storage;
Rect* head;
Rect* tail;
@@ -266,10 +261,7 @@ class Region::rasterizer : public region_operator<Rect>::region_rasterizer
Rect* cur;
public:
rasterizer(Region& reg)
- : bounds(reg.mBounds), storage(reg.mStorage), head(), tail(), cur() {
- bounds.top = bounds.bottom = 0;
- bounds.left = INT_MAX;
- bounds.right = INT_MIN;
+ : bounds(INT_MAX, 0, INT_MIN, 0), storage(reg.mStorage), head(), tail(), cur() {
storage.clear();
}
@@ -287,6 +279,7 @@ public:
bounds.left = 0;
bounds.right = 0;
}
+ storage.add(bounds);
}
virtual void operator()(const Rect& rect) {
@@ -342,44 +335,72 @@ private:
}
};
-bool Region::validate(const Region& reg, const char* name)
+bool Region::validate(const Region& reg, const char* name, bool silent)
{
bool result = true;
const_iterator cur = reg.begin();
const_iterator const tail = reg.end();
- const_iterator prev = cur++;
+ const_iterator prev = cur;
Rect b(*prev);
while (cur != tail) {
- b.left = b.left < cur->left ? b.left : cur->left;
- b.top = b.top < cur->top ? b.top : cur->top;
- b.right = b.right > cur->right ? b.right : cur->right;
- b.bottom = b.bottom > cur->bottom ? b.bottom : cur->bottom;
- if (cur->top == prev->top) {
- if (cur->bottom != prev->bottom) {
- ALOGE("%s: invalid span %p", name, cur);
+ if (cur->isValid() == false) {
+ ALOGE_IF(!silent, "%s: region contains an invalid Rect", name);
+ result = false;
+ }
+ if (cur->right > region_operator<Rect>::max_value) {
+ ALOGE_IF(!silent, "%s: rect->right > max_value", name);
+ result = false;
+ }
+ if (cur->bottom > region_operator<Rect>::max_value) {
+ ALOGE_IF(!silent, "%s: rect->right > max_value", name);
+ result = false;
+ }
+ if (prev != cur) {
+ b.left = b.left < cur->left ? b.left : cur->left;
+ b.top = b.top < cur->top ? b.top : cur->top;
+ b.right = b.right > cur->right ? b.right : cur->right;
+ b.bottom = b.bottom > cur->bottom ? b.bottom : cur->bottom;
+ if ((*prev < *cur) == false) {
+ ALOGE_IF(!silent, "%s: region's Rects not sorted", name);
result = false;
- } else if (cur->left < prev->right) {
- ALOGE("%s: spans overlap horizontally prev=%p, cur=%p",
+ }
+ if (cur->top == prev->top) {
+ if (cur->bottom != prev->bottom) {
+ ALOGE_IF(!silent, "%s: invalid span %p", name, cur);
+ result = false;
+ } else if (cur->left < prev->right) {
+ ALOGE_IF(!silent,
+ "%s: spans overlap horizontally prev=%p, cur=%p",
+ name, prev, cur);
+ result = false;
+ }
+ } else if (cur->top < prev->bottom) {
+ ALOGE_IF(!silent,
+ "%s: spans overlap vertically prev=%p, cur=%p",
name, prev, cur);
result = false;
}
- } else if (cur->top < prev->bottom) {
- ALOGE("%s: spans overlap vertically prev=%p, cur=%p",
- name, prev, cur);
- result = false;
+ prev = cur;
}
- prev = cur;
cur++;
}
if (b != reg.getBounds()) {
result = false;
- ALOGE("%s: invalid bounds [%d,%d,%d,%d] vs. [%d,%d,%d,%d]", name,
+ ALOGE_IF(!silent,
+ "%s: invalid bounds [%d,%d,%d,%d] vs. [%d,%d,%d,%d]", name,
b.left, b.top, b.right, b.bottom,
reg.getBounds().left, reg.getBounds().top,
reg.getBounds().right, reg.getBounds().bottom);
}
- if (result == false) {
+ if (reg.mStorage.size() == 2) {
+ result = false;
+ ALOGE_IF(!silent, "%s: mStorage size is 2, which is never valid", name);
+ }
+ if (result == false && !silent) {
reg.dump(name);
+ CallStack stack;
+ stack.update();
+ stack.dump("");
}
return result;
}
@@ -535,11 +556,10 @@ void Region::boolean_operation(int op, Region& dst,
void Region::translate(Region& reg, int dx, int dy)
{
- if (!reg.isEmpty()) {
+ if ((dx || dy) && !reg.isEmpty()) {
#if VALIDATE_REGIONS
validate(reg, "translate (before)");
#endif
- reg.mBounds.translate(dx, dy);
size_t count = reg.mStorage.size();
Rect* rects = reg.mStorage.editArray();
while (count) {
@@ -561,73 +581,54 @@ void Region::translate(Region& dst, const Region& reg, int dx, int dy)
// ----------------------------------------------------------------------------
-ssize_t Region::write(void* buffer, size_t size) const
-{
+size_t Region::getSize() const {
+ return mStorage.size() * sizeof(Rect);
+}
+
+status_t Region::flatten(void* buffer) const {
#if VALIDATE_REGIONS
- validate(*this, "write(buffer)");
+ validate(*this, "Region::flatten");
#endif
- const size_t count = mStorage.size();
- const size_t sizeNeeded = sizeof(int32_t) + (1+count)*sizeof(Rect);
- if (buffer != NULL) {
- if (sizeNeeded > size) return NO_MEMORY;
- int32_t* const p = static_cast<int32_t*>(buffer);
- *p = count;
- memcpy(p+1, &mBounds, sizeof(Rect));
- if (count) {
- memcpy(p+5, mStorage.array(), count*sizeof(Rect));
- }
- }
- return ssize_t(sizeNeeded);
+ Rect* rects = reinterpret_cast<Rect*>(buffer);
+ memcpy(rects, mStorage.array(), mStorage.size() * sizeof(Rect));
+ return NO_ERROR;
}
-ssize_t Region::read(const void* buffer)
-{
- int32_t const* const p = static_cast<int32_t const*>(buffer);
- const size_t count = *p;
- memcpy(&mBounds, p+1, sizeof(Rect));
- mStorage.clear();
- if (count) {
- mStorage.insertAt(0, count);
- memcpy(mStorage.editArray(), p+5, count*sizeof(Rect));
+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 VALIDATE_REGIONS
- validate(*this, "read(buffer)");
+ validate(result, "Region::unflatten");
#endif
- return ssize_t(sizeof(int32_t) + (1+count)*sizeof(Rect));
-}
-ssize_t Region::writeEmpty(void* buffer, size_t size)
-{
- const size_t sizeNeeded = sizeof(int32_t) + sizeof(Rect);
- if (sizeNeeded > size) return NO_MEMORY;
- int32_t* const p = static_cast<int32_t*>(buffer);
- memset(p, 0, sizeNeeded);
- return ssize_t(sizeNeeded);
-}
-
-bool Region::isEmpty(void* buffer)
-{
- int32_t const* const p = static_cast<int32_t const*>(buffer);
- Rect const* const b = reinterpret_cast<Rect const *>(p+1);
- return b->isEmpty();
+ if (!result.validate(result, "Region::unflatten", true)) {
+ ALOGE("Region::unflatten() failed, invalid region");
+ return BAD_VALUE;
+ }
+ mStorage = result.mStorage;
+ return NO_ERROR;
}
// ----------------------------------------------------------------------------
Region::const_iterator Region::begin() const {
- return isRect() ? &mBounds : mStorage.array();
+ return mStorage.array();
}
Region::const_iterator Region::end() const {
- if (isRect()) {
- if (isEmpty()) {
- return &mBounds;
- } else {
- return &mBounds + 1;
- }
- } else {
- return mStorage.array() + mStorage.size();
- }
+ size_t numRects = isRect() ? 1 : mStorage.size() - 1;
+ return mStorage.array() + numRects;
}
Rect const* Region::getArray(size_t* count) const {
@@ -637,14 +638,16 @@ Rect const* Region::getArray(size_t* count) const {
return b;
}
-size_t Region::getRects(Vector<Rect>& rectList) const
-{
- rectList = mStorage;
- if (rectList.isEmpty()) {
- rectList.clear();
- rectList.add(mBounds);
+SharedBuffer const* Region::getSharedBuffer(size_t* count) const {
+ // We can get to the SharedBuffer of a Vector<Rect> because Rect has
+ // a trivial destructor.
+ SharedBuffer const* sb = SharedBuffer::bufferFromData(mStorage.array());
+ if (count) {
+ size_t numRects = isRect() ? 1 : mStorage.size() - 1;
+ count[0] = numRects;
}
- return rectList.size();
+ sb->acquire();
+ return sb;
}
// ----------------------------------------------------------------------------
diff --git a/libs/ui/UiConfig.cpp b/libs/ui/UiConfig.cpp
new file mode 100644
index 0000000..8b2130e
--- /dev/null
+++ b/libs/ui/UiConfig.cpp
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+#include <ui/UiConfig.h>
+
+namespace android {
+
+#define STRINGIFY(x) #x
+#define TOSTRING(x) STRINGIFY(x)
+
+void appendUiConfigString(String8& configStr)
+{
+ static const char* config =
+ " [libui"
+#ifdef FRAMEBUFFER_FORCE_FORMAT
+ " FRAMEBUFFER_FORCE_FORMAT=" TOSTRING(FRAMEBUFFER_FORCE_FORMAT)
+#endif
+ "]";
+ configStr.append(config);
+}
+
+
+}; // namespace android
diff --git a/libs/utils/Android.mk b/libs/utils/Android.mk
index ddfb83e..c9f8fd4 100644
--- a/libs/utils/Android.mk
+++ b/libs/utils/Android.mk
@@ -26,6 +26,7 @@ commonSources:= \
FileMap.cpp \
Flattenable.cpp \
LinearTransform.cpp \
+ Log.cpp \
PropertyMap.cpp \
RefBase.cpp \
SharedBuffer.cpp \
diff --git a/libs/utils/LinearTransform.cpp b/libs/utils/LinearTransform.cpp
index d752415..b7d28d4 100644
--- a/libs/utils/LinearTransform.cpp
+++ b/libs/utils/LinearTransform.cpp
@@ -114,6 +114,7 @@ static bool linear_transform_s64_to_s64(
int64_t basis1,
int32_t N,
uint32_t D,
+ bool invert_frac,
int64_t basis2,
int64_t* out) {
uint64_t scaled, res;
@@ -137,8 +138,8 @@ static bool linear_transform_s64_to_s64(
is_neg = !is_neg;
if (!scale_u64_to_u64(abs_val,
- ABS(N),
- D,
+ invert_frac ? D : ABS(N),
+ invert_frac ? ABS(N) : D,
&scaled,
is_neg))
return false; // overflow/undeflow
@@ -191,6 +192,7 @@ bool LinearTransform::doForwardTransform(int64_t a_in, int64_t* b_out) const {
a_zero,
a_to_b_numer,
a_to_b_denom,
+ false,
b_zero,
b_out);
}
@@ -201,8 +203,9 @@ bool LinearTransform::doReverseTransform(int64_t b_in, int64_t* a_out) const {
return linear_transform_s64_to_s64(b_in,
b_zero,
- a_to_b_denom,
a_to_b_numer,
+ a_to_b_denom,
+ true,
a_zero,
a_out);
}
diff --git a/libs/utils/Log.cpp b/libs/utils/Log.cpp
new file mode 100644
index 0000000..bffb56e
--- /dev/null
+++ b/libs/utils/Log.cpp
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2012 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 "Log"
+
+#include <utils/Log.h>
+#include <utils/Timers.h>
+
+namespace android {
+
+LogIfSlow::LogIfSlow(const char* tag, android_LogPriority priority,
+ int timeoutMillis, const char* message) :
+ mTag(tag), mPriority(priority), mTimeoutMillis(timeoutMillis), mMessage(message),
+ mStart(systemTime(SYSTEM_TIME_BOOTTIME)) {
+}
+
+LogIfSlow::~LogIfSlow() {
+ int durationMillis = nanoseconds_to_milliseconds(systemTime(SYSTEM_TIME_BOOTTIME) - mStart);
+ if (durationMillis > mTimeoutMillis) {
+ LOG_PRI(mPriority, mTag, "%s: %dms", mMessage, durationMillis);
+ }
+}
+
+} // namespace android
diff --git a/libs/utils/SystemClock.cpp b/libs/utils/SystemClock.cpp
index 8b8ac10..ec2d82e 100644
--- a/libs/utils/SystemClock.cpp
+++ b/libs/utils/SystemClock.cpp
@@ -106,7 +106,74 @@ int64_t uptimeMillis()
*/
int64_t elapsedRealtime()
{
+ return nanoseconds_to_milliseconds(elapsedRealtimeNano());
+}
+
+#define METHOD_CLOCK_GETTIME 0
+#define METHOD_IOCTL 1
+#define METHOD_SYSTEMTIME 2
+
+static const char *gettime_method_names[] = {
+ "clock_gettime",
+ "ioctl",
+ "systemTime",
+};
+
+static inline void checkTimeStamps(int64_t timestamp,
+ int64_t volatile *prevTimestampPtr,
+ int volatile *prevMethodPtr,
+ int curMethod)
+{
+ /*
+ * Disable the check for SDK since the prebuilt toolchain doesn't contain
+ * gettid, and int64_t is different on the ARM platform
+ * (ie long vs long long).
+ */
+#ifdef ARCH_ARM
+ int64_t prevTimestamp = *prevTimestampPtr;
+ int prevMethod = *prevMethodPtr;
+
+ if (timestamp < prevTimestamp) {
+ ALOGW("time going backwards: prev %lld(%s) vs now %lld(%s), tid=%d",
+ prevTimestamp, gettime_method_names[prevMethod],
+ timestamp, gettime_method_names[curMethod],
+ gettid());
+ }
+ // NOTE - not atomic and may generate spurious warnings if the 64-bit
+ // write is interrupted or not observed as a whole.
+ *prevTimestampPtr = timestamp;
+ *prevMethodPtr = curMethod;
+#endif
+}
+
+/*
+ * native public static long elapsedRealtimeNano();
+ */
+int64_t elapsedRealtimeNano()
+{
#ifdef HAVE_ANDROID_OS
+ struct timespec ts;
+ int result;
+ int64_t timestamp;
+ static volatile int64_t prevTimestamp;
+ static volatile int prevMethod;
+
+#if 0
+ /*
+ * b/7100774
+ * clock_gettime appears to have clock skews and can sometimes return
+ * backwards values. Disable its use until we find out what's wrong.
+ */
+ result = clock_gettime(CLOCK_BOOTTIME, &ts);
+ if (result == 0) {
+ timestamp = seconds_to_nanoseconds(ts.tv_sec) + ts.tv_nsec;
+ checkTimeStamps(timestamp, &prevTimestamp, &prevMethod,
+ METHOD_CLOCK_GETTIME);
+ return timestamp;
+ }
+#endif
+
+ // CLOCK_BOOTTIME doesn't exist, fallback to /dev/alarm
static int s_fd = -1;
if (s_fd == -1) {
@@ -116,23 +183,24 @@ int64_t elapsedRealtime()
}
}
- struct timespec ts;
- int result = ioctl(s_fd,
+ result = ioctl(s_fd,
ANDROID_ALARM_GET_TIME(ANDROID_ALARM_ELAPSED_REALTIME), &ts);
if (result == 0) {
- int64_t when = seconds_to_nanoseconds(ts.tv_sec) + ts.tv_nsec;
- return (int64_t) nanoseconds_to_milliseconds(when);
- } else {
- // XXX: there was an error, probably because the driver didn't
- // exist ... this should return
- // a real error, like an exception!
- int64_t when = systemTime(SYSTEM_TIME_MONOTONIC);
- return (int64_t) nanoseconds_to_milliseconds(when);
+ timestamp = seconds_to_nanoseconds(ts.tv_sec) + ts.tv_nsec;
+ checkTimeStamps(timestamp, &prevTimestamp, &prevMethod, METHOD_IOCTL);
+ return timestamp;
}
+
+ // XXX: there was an error, probably because the driver didn't
+ // exist ... this should return
+ // a real error, like an exception!
+ timestamp = systemTime(SYSTEM_TIME_MONOTONIC);
+ checkTimeStamps(timestamp, &prevTimestamp, &prevMethod,
+ METHOD_SYSTEMTIME);
+ return timestamp;
#else
- int64_t when = systemTime(SYSTEM_TIME_MONOTONIC);
- return (int64_t) nanoseconds_to_milliseconds(when);
+ return systemTime(SYSTEM_TIME_MONOTONIC);
#endif
}
diff --git a/libs/utils/Timers.cpp b/libs/utils/Timers.cpp
index 64b4701..d4f8516 100644
--- a/libs/utils/Timers.cpp
+++ b/libs/utils/Timers.cpp
@@ -39,7 +39,8 @@ nsecs_t systemTime(int clock)
CLOCK_REALTIME,
CLOCK_MONOTONIC,
CLOCK_PROCESS_CPUTIME_ID,
- CLOCK_THREAD_CPUTIME_ID
+ CLOCK_THREAD_CPUTIME_ID,
+ CLOCK_BOOTTIME
};
struct timespec t;
t.tv_sec = t.tv_nsec = 0;
diff --git a/libs/utils/Trace.cpp b/libs/utils/Trace.cpp
index 5cd5731..f5aaea3 100644
--- a/libs/utils/Trace.cpp
+++ b/libs/utils/Trace.cpp
@@ -25,7 +25,7 @@ namespace android {
volatile int32_t Tracer::sIsReady = 0;
int Tracer::sTraceFD = -1;
-uint64_t Tracer::sEnabledTags = 0;
+uint64_t Tracer::sEnabledTags = ATRACE_TAG_NOT_READY;
Mutex Tracer::sMutex;
void Tracer::changeCallback() {
@@ -46,7 +46,7 @@ void Tracer::init() {
sTraceFD = open(traceFileName, O_WRONLY);
if (sTraceFD == -1) {
ALOGE("error opening trace file: %s (%d)", strerror(errno), errno);
- // sEnabledTags remains zero indicating that no tracing can occur
+ sEnabledTags = 0; // no tracing can occur
} else {
loadSystemProperty();
}
diff --git a/libs/utils/VectorImpl.cpp b/libs/utils/VectorImpl.cpp
index e78faa8..c3257bb 100644
--- a/libs/utils/VectorImpl.cpp
+++ b/libs/utils/VectorImpl.cpp
@@ -20,7 +20,8 @@
#include <stdlib.h>
#include <stdio.h>
-#include <utils/Log.h>
+#include <cutils/log.h>
+
#include <utils/Errors.h>
#include <utils/SharedBuffer.h>
#include <utils/VectorImpl.h>
@@ -50,15 +51,14 @@ VectorImpl::VectorImpl(const VectorImpl& rhs)
mFlags(rhs.mFlags), mItemSize(rhs.mItemSize)
{
if (mStorage) {
- SharedBuffer::sharedBuffer(mStorage)->acquire();
+ SharedBuffer::bufferFromData(mStorage)->acquire();
}
}
VectorImpl::~VectorImpl()
{
- ALOG_ASSERT(!mCount,
- "[%p] "
- "subclasses of VectorImpl must call finish_vector()"
+ ALOGW_IF(mCount,
+ "[%p] subclasses of VectorImpl must call finish_vector()"
" in their destructor. Leaking %d bytes.",
this, (int)(mCount*mItemSize));
// We can't call _do_destroy() here because the vtable is already gone.
@@ -66,14 +66,14 @@ VectorImpl::~VectorImpl()
VectorImpl& VectorImpl::operator = (const VectorImpl& rhs)
{
- ALOG_ASSERT(mItemSize == rhs.mItemSize,
+ LOG_ALWAYS_FATAL_IF(mItemSize != rhs.mItemSize,
"Vector<> have different types (this=%p, rhs=%p)", this, &rhs);
if (this != &rhs) {
release_storage();
if (rhs.mCount) {
mStorage = rhs.mStorage;
mCount = rhs.mCount;
- SharedBuffer::sharedBuffer(mStorage)->acquire();
+ SharedBuffer::bufferFromData(mStorage)->acquire();
} else {
mStorage = 0;
mCount = 0;
@@ -85,7 +85,7 @@ VectorImpl& VectorImpl::operator = (const VectorImpl& rhs)
void* VectorImpl::editArrayImpl()
{
if (mStorage) {
- SharedBuffer* sb = SharedBuffer::sharedBuffer(mStorage)->attemptEdit();
+ SharedBuffer* sb = SharedBuffer::bufferFromData(mStorage)->attemptEdit();
if (sb == 0) {
sb = SharedBuffer::alloc(capacity() * mItemSize);
if (sb) {
@@ -101,7 +101,7 @@ void* VectorImpl::editArrayImpl()
size_t VectorImpl::capacity() const
{
if (mStorage) {
- return SharedBuffer::sharedBuffer(mStorage)->size() / mItemSize;
+ return SharedBuffer::bufferFromData(mStorage)->size() / mItemSize;
}
return 0;
}
@@ -251,6 +251,10 @@ ssize_t VectorImpl::replaceAt(const void* prototype, size_t index)
ALOG_ASSERT(index<size(),
"[%p] replace: index=%d, size=%d", this, (int)index, (int)size());
+ if (index >= size()) {
+ return BAD_INDEX;
+ }
+
void* item = editItemLocation(index);
if (item != prototype) {
if (item == 0)
@@ -294,10 +298,13 @@ void* VectorImpl::editItemLocation(size_t index)
ALOG_ASSERT(index<capacity(),
"[%p] editItemLocation: index=%d, capacity=%d, count=%d",
this, (int)index, (int)capacity(), (int)mCount);
-
- void* buffer = editArrayImpl();
- if (buffer)
- return reinterpret_cast<char*>(buffer) + index*mItemSize;
+
+ if (index < capacity()) {
+ void* buffer = editArrayImpl();
+ if (buffer) {
+ return reinterpret_cast<char*>(buffer) + index*mItemSize;
+ }
+ }
return 0;
}
@@ -307,9 +314,12 @@ const void* VectorImpl::itemLocation(size_t index) const
"[%p] itemLocation: index=%d, capacity=%d, count=%d",
this, (int)index, (int)capacity(), (int)mCount);
- const void* buffer = arrayImpl();
- if (buffer)
- return reinterpret_cast<const char*>(buffer) + index*mItemSize;
+ if (index < capacity()) {
+ const void* buffer = arrayImpl();
+ if (buffer) {
+ return reinterpret_cast<const char*>(buffer) + index*mItemSize;
+ }
+ }
return 0;
}
@@ -336,7 +346,7 @@ ssize_t VectorImpl::setCapacity(size_t new_capacity)
void VectorImpl::release_storage()
{
if (mStorage) {
- const SharedBuffer* sb = SharedBuffer::sharedBuffer(mStorage);
+ const SharedBuffer* sb = SharedBuffer::bufferFromData(mStorage);
if (sb->release(SharedBuffer::eKeepStorage) == 1) {
_do_destroy(mStorage, mCount);
SharedBuffer::dealloc(sb);
@@ -362,7 +372,7 @@ void* VectorImpl::_grow(size_t where, size_t amount)
(mFlags & HAS_TRIVIAL_COPY) &&
(mFlags & HAS_TRIVIAL_DTOR))
{
- const SharedBuffer* cur_sb = SharedBuffer::sharedBuffer(mStorage);
+ const SharedBuffer* cur_sb = SharedBuffer::bufferFromData(mStorage);
SharedBuffer* sb = cur_sb->editResize(new_capacity * mItemSize);
mStorage = sb->data();
} else {
@@ -414,7 +424,7 @@ void VectorImpl::_shrink(size_t where, size_t amount)
(mFlags & HAS_TRIVIAL_COPY) &&
(mFlags & HAS_TRIVIAL_DTOR))
{
- const SharedBuffer* cur_sb = SharedBuffer::sharedBuffer(mStorage);
+ const SharedBuffer* cur_sb = SharedBuffer::bufferFromData(mStorage);
SharedBuffer* sb = cur_sb->editResize(new_capacity * mItemSize);
mStorage = sb->data();
} else {
diff --git a/libs/utils/ZipFileRO.cpp b/libs/utils/ZipFileRO.cpp
index cad7720..a1bfedb 100644
--- a/libs/utils/ZipFileRO.cpp
+++ b/libs/utils/ZipFileRO.cpp
@@ -20,6 +20,7 @@
#define LOG_TAG "zipro"
//#define LOG_NDEBUG 0
#include <utils/Log.h>
+#include <utils/Compat.h>
#include <utils/ZipFileRO.h>
#include <utils/misc.h>
#include <utils/threads.h>
@@ -32,14 +33,6 @@
#include <assert.h>
#include <unistd.h>
-#if HAVE_PRINTF_ZD
-# define ZD "%zd"
-# define ZD_TYPE ssize_t
-#else
-# define ZD "%ld"
-# define ZD_TYPE long
-#endif
-
/*
* We must open binary files using open(path, ... | O_BINARY) under Windows.
* Otherwise strange read errors will happen.
@@ -48,21 +41,6 @@
# define O_BINARY 0
#endif
-/*
- * TEMP_FAILURE_RETRY is defined by some, but not all, versions of
- * <unistd.h>. (Alas, it is not as standard as we'd hoped!) So, if it's
- * not already defined, then define it here.
- */
-#ifndef TEMP_FAILURE_RETRY
-/* Used to retry syscalls that can return EINTR. */
-#define TEMP_FAILURE_RETRY(exp) ({ \
- typeof (exp) _rc; \
- do { \
- _rc = (exp); \
- } while (_rc == -1 && errno == EINTR); \
- _rc; })
-#endif
-
using namespace android;
/*
@@ -118,7 +96,7 @@ ZipFileRO::~ZipFileRO() {
*/
int ZipFileRO::entryToIndex(const ZipEntryRO entry) const
{
- long ent = ((long) entry) - kZipEntryAdj;
+ long ent = ((intptr_t) entry) - kZipEntryAdj;
if (ent < 0 || ent >= mHashTableSize || mHashTable[ent].name == NULL) {
ALOGW("Invalid ZipEntryRO %p (%ld)\n", entry, ent);
return -1;
@@ -140,7 +118,7 @@ status_t ZipFileRO::open(const char* zipFileName)
/*
* Open and map the specified file.
*/
- fd = ::open(zipFileName, O_RDONLY | O_BINARY);
+ fd = TEMP_FAILURE_RETRY(::open(zipFileName, O_RDONLY | O_BINARY));
if (fd < 0) {
ALOGW("Unable to open zip '%s': %s\n", zipFileName, strerror(errno));
return NAME_NOT_FOUND;
@@ -320,6 +298,25 @@ bool ZipFileRO::mapCentralDirectory(void)
return true;
}
+
+/*
+ * Round up to the next highest power of 2.
+ *
+ * Found on http://graphics.stanford.edu/~seander/bithacks.html.
+ */
+static unsigned int roundUpPower2(unsigned int val)
+{
+ val--;
+ val |= val >> 1;
+ val |= val >> 2;
+ val |= val >> 4;
+ val |= val >> 8;
+ val |= val >> 16;
+ val++;
+
+ return val;
+}
+
bool ZipFileRO::parseZipArchive(void)
{
bool result = false;
@@ -459,7 +456,7 @@ ZipEntryRO ZipFileRO::findEntryByIndex(int idx) const
for (int ent = 0; ent < mHashTableSize; ent++) {
if (mHashTable[ent].name != NULL) {
if (idx-- == 0)
- return (ZipEntryRO) (ent + kZipEntryAdj);
+ return (ZipEntryRO) (intptr_t)(ent + kZipEntryAdj);
}
}
@@ -752,7 +749,7 @@ bool ZipFileRO::uncompressEntry(ZipEntryRO entry, int fd) const
ptr = (const unsigned char*) file->getDataPtr();
if (method == kCompressStored) {
- ssize_t actual = write(fd, ptr, uncompLen);
+ ssize_t actual = TEMP_FAILURE_RETRY(write(fd, ptr, uncompLen));
if (actual < 0) {
ALOGE("Write failed: %s\n", strerror(errno));
goto unmap;
@@ -901,9 +898,12 @@ bail:
(zerr == Z_STREAM_END && zstream.avail_out != sizeof(writeBuf)))
{
long writeSize = zstream.next_out - writeBuf;
- int cc = write(fd, writeBuf, writeSize);
- if (cc != (int) writeSize) {
- ALOGW("write failed in inflate (%d vs %ld)\n", cc, writeSize);
+ int cc = TEMP_FAILURE_RETRY(write(fd, writeBuf, writeSize));
+ if (cc < 0) {
+ ALOGW("write failed in inflate: %s", strerror(errno));
+ goto z_bail;
+ } else if (cc != (int) writeSize) {
+ ALOGW("write failed in inflate (%d vs %ld)", cc, writeSize);
goto z_bail;
}
diff --git a/libs/utils/ZipUtils.cpp b/libs/utils/ZipUtils.cpp
index cf5467b..a43bbb0 100644
--- a/libs/utils/ZipUtils.cpp
+++ b/libs/utils/ZipUtils.cpp
@@ -21,6 +21,7 @@
#define LOG_TAG "ziputil"
#include <utils/Log.h>
+#include <utils/Compat.h>
#include <utils/ZipUtils.h>
#include <utils/ZipFileRO.h>
@@ -98,10 +99,11 @@ using namespace android;
ALOGV("+++ reading %ld bytes (%ld left)\n",
getSize, compRemaining);
- int cc = read(fd, readBuf, getSize);
- if (cc != (int) getSize) {
- ALOGD("inflate read failed (%d vs %ld)\n",
- cc, getSize);
+ int cc = TEMP_FAILURE_RETRY(read(fd, readBuf, getSize));
+ if (cc < 0) {
+ ALOGW("inflate read failed: %s", strerror(errno));
+ } else if (cc != (int) getSize) {
+ ALOGW("inflate read failed (%d vs %ld)", cc, getSize);
goto z_bail;
}
diff --git a/libs/utils/misc.cpp b/libs/utils/misc.cpp
index b3c99e6..445a23a 100644
--- a/libs/utils/misc.cpp
+++ b/libs/utils/misc.cpp
@@ -39,90 +39,6 @@ using namespace android;
namespace android {
/*
- * Like strdup(), but uses C++ "new" operator instead of malloc.
- */
-char* strdupNew(const char* str)
-{
- char* newStr;
- int len;
-
- if (str == NULL)
- return NULL;
-
- len = strlen(str);
- newStr = new char[len+1];
- memcpy(newStr, str, len+1);
-
- return newStr;
-}
-
-/*
- * Concatenate an argument vector.
- */
-char* concatArgv(int argc, const char* const argv[])
-{
- char* newStr = NULL;
- int len, totalLen, posn, idx;
-
- /*
- * First, figure out the total length.
- */
- totalLen = idx = 0;
- while (1) {
- if (idx == argc || argv[idx] == NULL)
- break;
- if (idx)
- totalLen++; // leave a space between args
- totalLen += strlen(argv[idx]);
- idx++;
- }
-
- /*
- * Alloc the string.
- */
- newStr = new char[totalLen +1];
- if (newStr == NULL)
- return NULL;
-
- /*
- * Finally, allocate the string and copy data over.
- */
- idx = posn = 0;
- while (1) {
- if (idx == argc || argv[idx] == NULL)
- break;
- if (idx)
- newStr[posn++] = ' ';
-
- len = strlen(argv[idx]);
- memcpy(&newStr[posn], argv[idx], len);
- posn += len;
-
- idx++;
- }
-
- assert(posn == totalLen);
- newStr[posn] = '\0';
-
- return newStr;
-}
-
-/*
- * Count the #of args in an argument vector. Don't count the final NULL.
- */
-int countArgv(const char* const argv[])
-{
- int count = 0;
-
- while (argv[count] != NULL)
- count++;
-
- return count;
-}
-
-
-#include <stdio.h>
-/*
* Get a file's type.
*/
FileType getFileType(const char* fileName)
@@ -172,24 +88,6 @@ time_t getFileModDate(const char* fileName)
return sb.st_mtime;
}
-/*
- * Round up to the next highest power of 2.
- *
- * Found on http://graphics.stanford.edu/~seander/bithacks.html.
- */
-unsigned int roundUpPower2(unsigned int val)
-{
- val--;
- val |= val >> 1;
- val |= val >> 2;
- val |= val >> 4;
- val |= val >> 8;
- val |= val >> 16;
- val++;
-
- return val;
-}
-
struct sysprop_change_callback_info {
sysprop_change_callback callback;
int priority;
diff --git a/libs/utils/tests/Android.mk b/libs/utils/tests/Android.mk
index 0a5b379..5b2b5b1 100644
--- a/libs/utils/tests/Android.mk
+++ b/libs/utils/tests/Android.mk
@@ -4,42 +4,30 @@ include $(CLEAR_VARS)
# Build the unit tests.
test_src_files := \
- BasicHashtable_test.cpp \
- BlobCache_test.cpp \
- Looper_test.cpp \
- String8_test.cpp \
- Unicode_test.cpp \
- Vector_test.cpp \
- ZipFileRO_test.cpp
+ BasicHashtable_test.cpp \
+ BlobCache_test.cpp \
+ Looper_test.cpp \
+ String8_test.cpp \
+ Unicode_test.cpp \
+ Vector_test.cpp \
+ ZipFileRO_test.cpp
shared_libraries := \
- libz \
- liblog \
- libcutils \
- libutils \
- libstlport
+ libz \
+ liblog \
+ libcutils \
+ libutils \
+ libstlport
static_libraries := \
- libgtest \
- libgtest_main
-
-c_includes := \
- external/zlib \
- external/icu4c/common \
- bionic \
- bionic/libstdc++/include \
- external/gtest/include \
- external/stlport/stlport
-
-module_tags := eng tests
+ libgtest \
+ libgtest_main
$(foreach file,$(test_src_files), \
$(eval include $(CLEAR_VARS)) \
$(eval LOCAL_SHARED_LIBRARIES := $(shared_libraries)) \
$(eval LOCAL_STATIC_LIBRARIES := $(static_libraries)) \
- $(eval LOCAL_C_INCLUDES := $(c_includes)) \
$(eval LOCAL_SRC_FILES := $(file)) \
$(eval LOCAL_MODULE := $(notdir $(file:%.cpp=%))) \
- $(eval LOCAL_MODULE_TAGS := $(module_tags)) \
- $(eval include $(BUILD_EXECUTABLE)) \
+ $(eval include $(BUILD_NATIVE_TEST)) \
)