summaryrefslogtreecommitdiffstats
path: root/libs/gui
diff options
context:
space:
mode:
Diffstat (limited to 'libs/gui')
-rw-r--r--libs/gui/Android.mk46
-rw-r--r--libs/gui/BufferItemConsumer.cpp14
-rw-r--r--libs/gui/BufferQueue.cpp87
-rw-r--r--libs/gui/ConsumerBase.cpp26
-rw-r--r--libs/gui/CpuConsumer.cpp125
-rw-r--r--libs/gui/GLConsumer.cpp (renamed from libs/gui/SurfaceTexture.cpp)506
-rw-r--r--libs/gui/GraphicBufferAlloc.cpp53
-rw-r--r--libs/gui/GuiConfig.cpp10
-rw-r--r--libs/gui/IGraphicBufferProducer.cpp (renamed from libs/gui/ISurfaceTexture.cpp)118
-rw-r--r--libs/gui/ISurface.cpp66
-rw-r--r--libs/gui/ISurfaceComposer.cpp41
-rw-r--r--libs/gui/ISurfaceComposerClient.cpp56
-rw-r--r--libs/gui/LayerState.cpp54
-rw-r--r--libs/gui/Surface.cpp1013
-rw-r--r--libs/gui/SurfaceComposerClient.cpp209
-rw-r--r--libs/gui/SurfaceControl.cpp190
-rw-r--r--libs/gui/SurfaceTextureClient.cpp854
-rw-r--r--libs/gui/SyncFeatures.cpp94
-rw-r--r--libs/gui/tests/Android.mk1
-rw-r--r--libs/gui/tests/BufferQueue_test.cpp14
-rw-r--r--libs/gui/tests/CpuConsumer_test.cpp270
-rw-r--r--libs/gui/tests/SurfaceTextureClient_test.cpp56
-rw-r--r--libs/gui/tests/SurfaceTexture_test.cpp242
-rw-r--r--libs/gui/tests/Surface_test.cpp22
24 files changed, 2298 insertions, 1869 deletions
diff --git a/libs/gui/Android.mk b/libs/gui/Android.mk
index d970a33..c080f47 100644
--- a/libs/gui/Android.mk
+++ b/libs/gui/Android.mk
@@ -3,29 +3,30 @@ include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
BitTube.cpp \
+ BufferItemConsumer.cpp \
BufferQueue.cpp \
ConsumerBase.cpp \
+ CpuConsumer.cpp \
DisplayEventReceiver.cpp \
+ DummyConsumer.cpp \
+ GLConsumer.cpp \
+ GraphicBufferAlloc.cpp \
+ GuiConfig.cpp \
IDisplayEventConnection.cpp \
+ IGraphicBufferAlloc.cpp \
+ IGraphicBufferProducer.cpp \
ISensorEventConnection.cpp \
ISensorServer.cpp \
- ISurfaceTexture.cpp \
- Sensor.cpp \
- SensorEventQueue.cpp \
- SensorManager.cpp \
- SurfaceTexture.cpp \
- SurfaceTextureClient.cpp \
ISurfaceComposer.cpp \
- ISurface.cpp \
ISurfaceComposerClient.cpp \
- IGraphicBufferAlloc.cpp \
LayerState.cpp \
+ Sensor.cpp \
+ SensorEventQueue.cpp \
+ SensorManager.cpp \
Surface.cpp \
+ SurfaceControl.cpp \
SurfaceComposerClient.cpp \
- DummyConsumer.cpp \
- CpuConsumer.cpp \
- BufferItemConsumer.cpp \
- GuiConfig.cpp
+ SyncFeatures.cpp \
LOCAL_SHARED_LIBRARIES := \
libbinder \
@@ -35,27 +36,16 @@ LOCAL_SHARED_LIBRARIES := \
libsync \
libui \
libutils \
+ liblog
LOCAL_MODULE:= libgui
-ifeq ($(TARGET_BOARD_PLATFORM), omap4)
- LOCAL_CFLAGS += -DUSE_FENCE_SYNC
+ifeq ($(TARGET_BOARD_PLATFORM), tegra)
+ LOCAL_CFLAGS += -DDONT_USE_FENCE_SYNC
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), msm8960)
- LOCAL_CFLAGS += -DUSE_NATIVE_FENCE_SYNC
+ifeq ($(TARGET_BOARD_PLATFORM), tegra3)
+ LOCAL_CFLAGS += -DDONT_USE_FENCE_SYNC
endif
include $(BUILD_SHARED_LIBRARY)
diff --git a/libs/gui/BufferItemConsumer.cpp b/libs/gui/BufferItemConsumer.cpp
index 5079883..7db1b84 100644
--- a/libs/gui/BufferItemConsumer.cpp
+++ b/libs/gui/BufferItemConsumer.cpp
@@ -62,8 +62,8 @@ status_t BufferItemConsumer::acquireBuffer(BufferItem *item, bool waitForFence)
return err;
}
- if (waitForFence && item->mFence.get()) {
- err = item->mFence->waitForever(1000, "BufferItemConsumer::acquireBuffer");
+ if (waitForFence) {
+ err = item->mFence->waitForever("BufferItemConsumer::acquireBuffer");
if (err != OK) {
BI_LOGE("Failed to wait for fence of acquired buffer: %s (%d)",
strerror(-err), err);
@@ -93,4 +93,14 @@ status_t BufferItemConsumer::releaseBuffer(const BufferItem &item,
return err;
}
+status_t BufferItemConsumer::setDefaultBufferSize(uint32_t w, uint32_t h) {
+ Mutex::Autolock _l(mMutex);
+ return mBufferQueue->setDefaultBufferSize(w, h);
+}
+
+status_t BufferItemConsumer::setDefaultBufferFormat(uint32_t defaultFormat) {
+ Mutex::Autolock _l(mMutex);
+ return mBufferQueue->setDefaultBufferFormat(defaultFormat);
+}
+
} // namespace android
diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp
index 086e298..b4c7231 100644
--- a/libs/gui/BufferQueue.cpp
+++ b/libs/gui/BufferQueue.cpp
@@ -29,7 +29,6 @@
#include <private/gui/ComposerService.h>
#include <utils/Log.h>
-#include <gui/SurfaceTexture.h>
#include <utils/Trace.h>
// Macros for including the BufferQueue name in log messages
@@ -107,7 +106,7 @@ status_t BufferQueue::setDefaultMaxBufferCountLocked(int count) {
mDefaultMaxBufferCount = count;
mDequeueCondition.broadcast();
- return OK;
+ return NO_ERROR;
}
bool BufferQueue::isSynchronousMode() const {
@@ -123,20 +122,20 @@ void BufferQueue::setConsumerName(const String8& name) {
status_t BufferQueue::setDefaultBufferFormat(uint32_t defaultFormat) {
Mutex::Autolock lock(mMutex);
mDefaultBufferFormat = defaultFormat;
- return OK;
+ return NO_ERROR;
}
status_t BufferQueue::setConsumerUsageBits(uint32_t usage) {
Mutex::Autolock lock(mMutex);
mConsumerUsageBits = usage;
- return OK;
+ return NO_ERROR;
}
status_t BufferQueue::setTransformHint(uint32_t hint) {
ST_LOGV("setTransformHint: %02x", hint);
Mutex::Autolock lock(mMutex);
mTransformHint = hint;
- return OK;
+ return NO_ERROR;
}
status_t BufferQueue::setBufferCount(int bufferCount) {
@@ -147,11 +146,12 @@ status_t BufferQueue::setBufferCount(int bufferCount) {
Mutex::Autolock lock(mMutex);
if (mAbandoned) {
- ST_LOGE("setBufferCount: SurfaceTexture has been abandoned!");
+ ST_LOGE("setBufferCount: BufferQueue has been abandoned!");
return NO_INIT;
}
if (bufferCount > NUM_BUFFER_SLOTS) {
- ST_LOGE("setBufferCount: bufferCount larger than slots available");
+ ST_LOGE("setBufferCount: bufferCount too large (max %d)",
+ NUM_BUFFER_SLOTS);
return BAD_VALUE;
}
@@ -168,7 +168,7 @@ status_t BufferQueue::setBufferCount(int bufferCount) {
if (bufferCount == 0) {
mOverrideMaxBufferCount = 0;
mDequeueCondition.broadcast();
- return OK;
+ return NO_ERROR;
}
if (bufferCount < minBufferSlots) {
@@ -192,7 +192,7 @@ status_t BufferQueue::setBufferCount(int bufferCount) {
listener->onBuffersReleased();
}
- return OK;
+ return NO_ERROR;
}
int BufferQueue::query(int what, int* outValue)
@@ -201,7 +201,7 @@ int BufferQueue::query(int what, int* outValue)
Mutex::Autolock lock(mMutex);
if (mAbandoned) {
- ST_LOGE("query: SurfaceTexture has been abandoned!");
+ ST_LOGE("query: BufferQueue has been abandoned!");
return NO_INIT;
}
@@ -234,7 +234,7 @@ status_t BufferQueue::requestBuffer(int slot, sp<GraphicBuffer>* buf) {
ST_LOGV("requestBuffer: slot=%d", slot);
Mutex::Autolock lock(mMutex);
if (mAbandoned) {
- ST_LOGE("requestBuffer: SurfaceTexture has been abandoned!");
+ ST_LOGE("requestBuffer: BufferQueue has been abandoned!");
return NO_INIT;
}
int maxBufferCount = getMaxBufferCountLocked();
@@ -255,7 +255,7 @@ status_t BufferQueue::requestBuffer(int slot, sp<GraphicBuffer>* buf) {
return NO_ERROR;
}
-status_t BufferQueue::dequeueBuffer(int *outBuf, sp<Fence>& outFence,
+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);
@@ -283,7 +283,7 @@ status_t BufferQueue::dequeueBuffer(int *outBuf, sp<Fence>& outFence,
bool tryAgain = true;
while (tryAgain) {
if (mAbandoned) {
- ST_LOGE("dequeueBuffer: SurfaceTexture has been abandoned!");
+ ST_LOGE("dequeueBuffer: BufferQueue has been abandoned!");
return NO_INIT;
}
@@ -295,7 +295,7 @@ status_t BufferQueue::dequeueBuffer(int *outBuf, sp<Fence>& outFence,
assert(mSlots[i].mBufferState == BufferSlot::FREE);
if (mSlots[i].mGraphicBuffer != NULL) {
freeBufferLocked(i);
- returnFlags |= ISurfaceTexture::RELEASE_ALL_BUFFERS;
+ returnFlags |= IGraphicBufferProducer::RELEASE_ALL_BUFFERS;
}
}
@@ -373,8 +373,6 @@ status_t BufferQueue::dequeueBuffer(int *outBuf, sp<Fence>& outFence,
h = mDefaultHeight;
}
- // 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;
const sp<GraphicBuffer>& buffer(mSlots[buf].mGraphicBuffer);
@@ -388,20 +386,20 @@ status_t BufferQueue::dequeueBuffer(int *outBuf, sp<Fence>& outFence,
mSlots[buf].mGraphicBuffer = NULL;
mSlots[buf].mRequestBufferCalled = false;
mSlots[buf].mEglFence = EGL_NO_SYNC_KHR;
- mSlots[buf].mFence.clear();
+ mSlots[buf].mFence = Fence::NO_FENCE;
mSlots[buf].mEglDisplay = EGL_NO_DISPLAY;
- returnFlags |= ISurfaceTexture::BUFFER_NEEDS_REALLOCATION;
+ returnFlags |= IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION;
}
dpy = mSlots[buf].mEglDisplay;
eglFence = mSlots[buf].mEglFence;
- outFence = mSlots[buf].mFence;
+ *outFence = mSlots[buf].mFence;
mSlots[buf].mEglFence = EGL_NO_SYNC_KHR;
- mSlots[buf].mFence.clear();
+ mSlots[buf].mFence = Fence::NO_FENCE;
} // end lock scope
- if (returnFlags & ISurfaceTexture::BUFFER_NEEDS_REALLOCATION) {
+ if (returnFlags & IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION) {
status_t error;
sp<GraphicBuffer> graphicBuffer(
mGraphicBufferAlloc->createGraphicBuffer(
@@ -416,7 +414,7 @@ status_t BufferQueue::dequeueBuffer(int *outBuf, sp<Fence>& outFence,
Mutex::Autolock lock(mMutex);
if (mAbandoned) {
- ST_LOGE("dequeueBuffer: SurfaceTexture has been abandoned!");
+ ST_LOGE("dequeueBuffer: BufferQueue has been abandoned!");
return NO_INIT;
}
@@ -424,7 +422,6 @@ status_t BufferQueue::dequeueBuffer(int *outBuf, sp<Fence>& outFence,
}
}
-
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
@@ -450,7 +447,7 @@ status_t BufferQueue::setSynchronousMode(bool enabled) {
Mutex::Autolock lock(mMutex);
if (mAbandoned) {
- ST_LOGE("setSynchronousMode: SurfaceTexture has been abandoned!");
+ ST_LOGE("setSynchronousMode: BufferQueue has been abandoned!");
return NO_INIT;
}
@@ -489,6 +486,11 @@ status_t BufferQueue::queueBuffer(int buf,
input.deflate(&timestamp, &crop, &scalingMode, &transform, &fence);
+ if (fence == NULL) {
+ ST_LOGE("queueBuffer: fence is NULL");
+ return BAD_VALUE;
+ }
+
ST_LOGV("queueBuffer: slot=%d time=%#llx crop=[%d,%d,%d,%d] tr=%#x "
"scale=%s",
buf, timestamp, crop.left, crop.top, crop.right, crop.bottom,
@@ -499,7 +501,7 @@ status_t BufferQueue::queueBuffer(int buf,
{ // scope for the lock
Mutex::Autolock lock(mMutex);
if (mAbandoned) {
- ST_LOGE("queueBuffer: SurfaceTexture has been abandoned!");
+ ST_LOGE("queueBuffer: BufferQueue has been abandoned!");
return NO_INIT;
}
int maxBufferCount = getMaxBufferCountLocked();
@@ -586,10 +588,10 @@ status_t BufferQueue::queueBuffer(int buf,
if (listener != 0) {
listener->onFrameAvailable();
}
- return OK;
+ return NO_ERROR;
}
-void BufferQueue::cancelBuffer(int buf, sp<Fence> fence) {
+void BufferQueue::cancelBuffer(int buf, const sp<Fence>& fence) {
ATRACE_CALL();
ST_LOGV("cancelBuffer: slot=%d", buf);
Mutex::Autolock lock(mMutex);
@@ -608,6 +610,9 @@ void BufferQueue::cancelBuffer(int buf, sp<Fence> fence) {
ST_LOGE("cancelBuffer: slot %d is not owned by the client (state=%d)",
buf, mSlots[buf].mBufferState);
return;
+ } else if (fence == NULL) {
+ ST_LOGE("cancelBuffer: fence is NULL");
+ return;
}
mSlots[buf].mBufferState = BufferSlot::FREE;
mSlots[buf].mFrameNumber = 0;
@@ -786,7 +791,7 @@ void BufferQueue::freeBufferLocked(int slot) {
eglDestroySyncKHR(mSlots[slot].mEglDisplay, mSlots[slot].mEglFence);
mSlots[slot].mEglFence = EGL_NO_SYNC_KHR;
}
- mSlots[slot].mFence.clear();
+ mSlots[slot].mFence = Fence::NO_FENCE;
}
void BufferQueue::freeAllBuffersLocked() {
@@ -844,7 +849,7 @@ status_t BufferQueue::acquireBuffer(BufferItem *buffer) {
mSlots[buf].mAcquireCalled = true;
mSlots[buf].mNeedsCleanupOnRelease = false;
mSlots[buf].mBufferState = BufferSlot::ACQUIRED;
- mSlots[buf].mFence.clear();
+ mSlots[buf].mFence = Fence::NO_FENCE;
mQueue.erase(front);
mDequeueCondition.broadcast();
@@ -854,7 +859,7 @@ status_t BufferQueue::acquireBuffer(BufferItem *buffer) {
return NO_BUFFER_AVAILABLE;
}
- return OK;
+ return NO_ERROR;
}
status_t BufferQueue::releaseBuffer(int buf, EGLDisplay display,
@@ -864,8 +869,8 @@ status_t BufferQueue::releaseBuffer(int buf, EGLDisplay display,
Mutex::Autolock _l(mMutex);
- if (buf == INVALID_BUFFER_SLOT) {
- return -EINVAL;
+ if (buf == INVALID_BUFFER_SLOT || fence == NULL) {
+ return BAD_VALUE;
}
mSlots[buf].mEglDisplay = display;
@@ -885,7 +890,7 @@ status_t BufferQueue::releaseBuffer(int buf, EGLDisplay display,
}
mDequeueCondition.broadcast();
- return OK;
+ return NO_ERROR;
}
status_t BufferQueue::consumerConnect(const sp<ConsumerListener>& consumerListener) {
@@ -896,10 +901,14 @@ status_t BufferQueue::consumerConnect(const sp<ConsumerListener>& consumerListen
ST_LOGE("consumerConnect: BufferQueue has been abandoned!");
return NO_INIT;
}
+ if (consumerListener == NULL) {
+ ST_LOGE("consumerConnect: consumerListener may not be NULL");
+ return BAD_VALUE;
+ }
mConsumerListener = consumerListener;
- return OK;
+ return NO_ERROR;
}
status_t BufferQueue::consumerDisconnect() {
@@ -916,7 +925,7 @@ status_t BufferQueue::consumerDisconnect() {
mQueue.clear();
freeAllBuffersLocked();
mDequeueCondition.broadcast();
- return OK;
+ return NO_ERROR;
}
status_t BufferQueue::getReleasedBuffers(uint32_t* slotMask) {
@@ -952,7 +961,7 @@ status_t BufferQueue::setDefaultBufferSize(uint32_t w, uint32_t h)
Mutex::Autolock lock(mMutex);
mDefaultWidth = w;
mDefaultHeight = h;
- return OK;
+ return NO_ERROR;
}
status_t BufferQueue::setDefaultMaxBufferCount(int bufferCount) {
@@ -973,7 +982,7 @@ status_t BufferQueue::setMaxAcquiredBufferCount(int maxAcquiredBuffers) {
return INVALID_OPERATION;
}
mMaxAcquiredBufferCount = maxAcquiredBuffers;
- return OK;
+ return NO_ERROR;
}
void BufferQueue::freeAllBuffersExceptHeadLocked() {
@@ -991,7 +1000,7 @@ void BufferQueue::freeAllBuffersExceptHeadLocked() {
}
status_t BufferQueue::drainQueueLocked() {
- while (mSynchronousMode && !mQueue.isEmpty()) {
+ while (mSynchronousMode && mQueue.size() > 1) {
mDequeueCondition.wait(mMutex);
if (mAbandoned) {
ST_LOGE("drainQueueLocked: BufferQueue has been abandoned!");
@@ -1008,7 +1017,7 @@ status_t BufferQueue::drainQueueLocked() {
status_t BufferQueue::drainQueueAndFreeBuffersLocked() {
status_t err = drainQueueLocked();
if (err == NO_ERROR) {
- if (mSynchronousMode) {
+ if (mQueue.empty()) {
freeAllBuffersLocked();
} else {
freeAllBuffersExceptHeadLocked();
diff --git a/libs/gui/ConsumerBase.cpp b/libs/gui/ConsumerBase.cpp
index 624d7e0..4937b17 100644
--- a/libs/gui/ConsumerBase.cpp
+++ b/libs/gui/ConsumerBase.cpp
@@ -18,7 +18,6 @@
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
//#define LOG_NDEBUG 0
-#define GL_GLEXT_PROTOTYPES
#define EGL_EGLEXT_PROTOTYPES
#include <EGL/egl.h>
@@ -69,7 +68,7 @@ ConsumerBase::ConsumerBase(const sp<BufferQueue>& bufferQueue) :
status_t err = mBufferQueue->consumerConnect(proxy);
if (err != NO_ERROR) {
- CB_LOGE("SurfaceTexture: error connecting to BufferQueue: %s (%d)",
+ CB_LOGE("ConsumerBase: error connecting to BufferQueue: %s (%d)",
strerror(-err), err);
} else {
mBufferQueue->setConsumerName(mName);
@@ -77,14 +76,25 @@ ConsumerBase::ConsumerBase(const sp<BufferQueue>& bufferQueue) :
}
ConsumerBase::~ConsumerBase() {
- CB_LOGV("~ConsumerBase");
+ CB_LOGV("~ConsumerBase");
+ Mutex::Autolock lock(mMutex);
+
+ // Verify that abandon() has been called before we get here. This should
+ // be done by ConsumerBase::onLastStrongRef(), but it's possible for a
+ // derived class to override that method and not call
+ // ConsumerBase::onLastStrongRef().
+ LOG_ALWAYS_FATAL_IF(!mAbandoned, "[%s] ~ConsumerBase was called, but the "
+ "consumer is not abandoned!", mName.string());
+}
+
+void ConsumerBase::onLastStrongRef(const void* id) {
abandon();
}
void ConsumerBase::freeBufferLocked(int slotIndex) {
CB_LOGV("freeBufferLocked: slotIndex=%d", slotIndex);
mSlots[slotIndex].mGraphicBuffer = 0;
- mSlots[slotIndex].mFence = 0;
+ mSlots[slotIndex].mFence = Fence::NO_FENCE;
}
// Used for refactoring, should not be in final interface
@@ -99,7 +109,7 @@ void ConsumerBase::onFrameAvailable() {
sp<FrameAvailableListener> listener;
{ // scope for the lock
Mutex::Autolock lock(mMutex);
- listener = mFrameAvailableListener;
+ listener = mFrameAvailableListener.promote();
}
if (listener != NULL) {
@@ -148,7 +158,7 @@ void ConsumerBase::abandonLocked() {
}
void ConsumerBase::setFrameAvailableListener(
- const sp<FrameAvailableListener>& listener) {
+ const wp<FrameAvailableListener>& listener) {
CB_LOGV("setFrameAvailableListener");
Mutex::Autolock lock(mMutex);
mFrameAvailableListener = listener;
@@ -228,9 +238,9 @@ status_t ConsumerBase::releaseBufferLocked(int slot, EGLDisplay display,
freeBufferLocked(slot);
}
- mSlots[slot].mFence.clear();
+ mSlots[slot].mFence = Fence::NO_FENCE;
return err;
}
-} // namespace android \ No newline at end of file
+} // namespace android
diff --git a/libs/gui/CpuConsumer.cpp b/libs/gui/CpuConsumer.cpp
index 710e1af..0543649 100644
--- a/libs/gui/CpuConsumer.cpp
+++ b/libs/gui/CpuConsumer.cpp
@@ -17,8 +17,9 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "CpuConsumer"
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
-#include <utils/Log.h>
+#include <cutils/compiler.h>
+#include <utils/Log.h>
#include <gui/CpuConsumer.h>
#define CC_LOGV(x, ...) ALOGV("[%s] "x, mName.string(), ##__VA_ARGS__)
@@ -29,24 +30,25 @@
namespace android {
-CpuConsumer::CpuConsumer(uint32_t maxLockedBuffers) :
+CpuConsumer::CpuConsumer(uint32_t maxLockedBuffers, bool synchronousMode) :
ConsumerBase(new BufferQueue(true) ),
mMaxLockedBuffers(maxLockedBuffers),
mCurrentLockedBuffers(0)
{
+ // Create tracking entries for locked buffers
+ mAcquiredBuffers.insertAt(0, maxLockedBuffers);
- for (int i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
- mBufferPointers[i] = NULL;
- }
-
- mBufferQueue->setSynchronousMode(true);
+ mBufferQueue->setSynchronousMode(synchronousMode);
mBufferQueue->setConsumerUsageBits(GRALLOC_USAGE_SW_READ_OFTEN);
mBufferQueue->setMaxAcquiredBufferCount(maxLockedBuffers);
}
CpuConsumer::~CpuConsumer() {
+ // ConsumerBase destructor does all the work.
}
+
+
void CpuConsumer::setName(const String8& name) {
Mutex::Autolock _l(mMutex);
mName = name;
@@ -78,7 +80,7 @@ status_t CpuConsumer::lockNextBuffer(LockedBuffer *nativeBuffer) {
int buf = b.mBuf;
if (b.mFence.get()) {
- err = b.mFence->waitForever(1000, "CpuConsumer::lockNextBuffer");
+ err = b.mFence->waitForever("CpuConsumer::lockNextBuffer");
if (err != OK) {
CC_LOGE("Failed to wait for fence of acquired buffer: %s (%d)",
strerror(-err), err);
@@ -86,22 +88,57 @@ status_t CpuConsumer::lockNextBuffer(LockedBuffer *nativeBuffer) {
}
}
- err = mSlots[buf].mGraphicBuffer->lock(
- GraphicBuffer::USAGE_SW_READ_OFTEN,
- b.mCrop,
- &mBufferPointers[buf]);
+ void *bufferPointer = NULL;
+ android_ycbcr ycbcr = android_ycbcr();
- if (mBufferPointers[buf] != NULL && err != OK) {
- CC_LOGE("Unable to lock buffer for CPU reading: %s (%d)", strerror(-err),
- err);
- return err;
+ if (mSlots[buf].mGraphicBuffer->getPixelFormat() ==
+ HAL_PIXEL_FORMAT_YCbCr_420_888) {
+ err = mSlots[buf].mGraphicBuffer->lockYCbCr(
+ GraphicBuffer::USAGE_SW_READ_OFTEN,
+ b.mCrop,
+ &ycbcr);
+
+ if (err != OK) {
+ CC_LOGE("Unable to lock YCbCr buffer for CPU reading: %s (%d)",
+ strerror(-err), err);
+ return err;
+ }
+ bufferPointer = ycbcr.y;
+ } else {
+ err = mSlots[buf].mGraphicBuffer->lock(
+ GraphicBuffer::USAGE_SW_READ_OFTEN,
+ b.mCrop,
+ &bufferPointer);
+
+ if (err != OK) {
+ CC_LOGE("Unable to lock buffer for CPU reading: %s (%d)",
+ strerror(-err), err);
+ return err;
+ }
+ }
+
+ size_t lockedIdx = 0;
+ for (; lockedIdx < mMaxLockedBuffers; lockedIdx++) {
+ if (mAcquiredBuffers[lockedIdx].mSlot ==
+ BufferQueue::INVALID_BUFFER_SLOT) {
+ break;
+ }
}
+ assert(lockedIdx < mMaxLockedBuffers);
- nativeBuffer->data = reinterpret_cast<uint8_t*>(mBufferPointers[buf]);
+ AcquiredBuffer &ab = mAcquiredBuffers.editItemAt(lockedIdx);
+ ab.mSlot = buf;
+ ab.mBufferPointer = bufferPointer;
+ ab.mGraphicBuffer = mSlots[buf].mGraphicBuffer;
+
+ nativeBuffer->data =
+ reinterpret_cast<uint8_t*>(bufferPointer);
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->stride = (ycbcr.y != NULL) ?
+ ycbcr.ystride :
+ mSlots[buf].mGraphicBuffer->getStride();
nativeBuffer->crop = b.mCrop;
nativeBuffer->transform = b.mTransform;
@@ -109,6 +146,11 @@ status_t CpuConsumer::lockNextBuffer(LockedBuffer *nativeBuffer) {
nativeBuffer->timestamp = b.mTimestamp;
nativeBuffer->frameNumber = b.mFrameNumber;
+ nativeBuffer->dataCb = reinterpret_cast<uint8_t*>(ycbcr.cb);
+ nativeBuffer->dataCr = reinterpret_cast<uint8_t*>(ycbcr.cr);
+ nativeBuffer->chromaStride = ycbcr.cstride;
+ nativeBuffer->chromaStep = ycbcr.chroma_step;
+
mCurrentLockedBuffers++;
return OK;
@@ -116,43 +158,50 @@ status_t CpuConsumer::lockNextBuffer(LockedBuffer *nativeBuffer) {
status_t CpuConsumer::unlockBuffer(const LockedBuffer &nativeBuffer) {
Mutex::Autolock _l(mMutex);
- int slotIndex = 0;
+ size_t lockedIdx = 0;
status_t err;
void *bufPtr = reinterpret_cast<void *>(nativeBuffer.data);
- for (; slotIndex < BufferQueue::NUM_BUFFER_SLOTS; slotIndex++) {
- if (bufPtr == mBufferPointers[slotIndex]) break;
+ for (; lockedIdx < mMaxLockedBuffers; lockedIdx++) {
+ if (bufPtr == mAcquiredBuffers[lockedIdx].mBufferPointer) break;
}
- if (slotIndex == BufferQueue::NUM_BUFFER_SLOTS) {
+ if (lockedIdx == mMaxLockedBuffers) {
CC_LOGE("%s: Can't find buffer to free", __FUNCTION__);
return BAD_VALUE;
}
- mBufferPointers[slotIndex] = NULL;
- err = mSlots[slotIndex].mGraphicBuffer->unlock();
+ return releaseAcquiredBufferLocked(lockedIdx);
+}
+
+status_t CpuConsumer::releaseAcquiredBufferLocked(int lockedIdx) {
+ status_t err;
+
+ err = mAcquiredBuffers[lockedIdx].mGraphicBuffer->unlock();
if (err != OK) {
- CC_LOGE("%s: Unable to unlock graphic buffer %d", __FUNCTION__, slotIndex);
+ CC_LOGE("%s: Unable to unlock graphic buffer %d", __FUNCTION__,
+ lockedIdx);
return err;
}
- releaseBufferLocked(slotIndex, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR);
+ int buf = mAcquiredBuffers[lockedIdx].mSlot;
+
+ // release the buffer if it hasn't already been freed by the BufferQueue.
+ // This can happen, for example, when the producer of this buffer
+ // disconnected after this buffer was acquired.
+ if (CC_LIKELY(mAcquiredBuffers[lockedIdx].mGraphicBuffer ==
+ mSlots[buf].mGraphicBuffer)) {
+ releaseBufferLocked(buf, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR);
+ }
- mCurrentLockedBuffers--;
+ AcquiredBuffer &ab = mAcquiredBuffers.editItemAt(lockedIdx);
+ ab.mSlot = BufferQueue::INVALID_BUFFER_SLOT;
+ ab.mBufferPointer = NULL;
+ ab.mGraphicBuffer.clear();
+ 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);
}
diff --git a/libs/gui/SurfaceTexture.cpp b/libs/gui/GLConsumer.cpp
index b4dfb5e..dc46a51 100644
--- a/libs/gui/SurfaceTexture.cpp
+++ b/libs/gui/GLConsumer.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#define LOG_TAG "SurfaceTexture"
+#define LOG_TAG "GLConsumer"
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
//#define LOG_NDEBUG 0
@@ -28,50 +28,27 @@
#include <hardware/hardware.h>
+#include <gui/GLConsumer.h>
#include <gui/IGraphicBufferAlloc.h>
#include <gui/ISurfaceComposer.h>
#include <gui/SurfaceComposerClient.h>
-#include <gui/SurfaceTexture.h>
#include <private/gui/ComposerService.h>
+#include <private/gui/SyncFeatures.h>
#include <utils/Log.h>
#include <utils/String8.h>
#include <utils/Trace.h>
-// 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
-#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
+namespace android {
+
+// Macros for including the GLConsumer name in log messages
#define ST_LOGV(x, ...) ALOGV("[%s] "x, mName.string(), ##__VA_ARGS__)
#define ST_LOGD(x, ...) ALOGD("[%s] "x, mName.string(), ##__VA_ARGS__)
#define ST_LOGI(x, ...) ALOGI("[%s] "x, mName.string(), ##__VA_ARGS__)
#define ST_LOGW(x, ...) ALOGW("[%s] "x, mName.string(), ##__VA_ARGS__)
#define ST_LOGE(x, ...) ALOGE("[%s] "x, mName.string(), ##__VA_ARGS__)
-namespace android {
-
// Transform matrices
static float mtxIdentity[16] = {
1, 0, 0, 0,
@@ -97,41 +74,36 @@ static float mtxRot90[16] = {
0, 0, 1, 0,
1, 0, 0, 1,
};
-static float mtxRot180[16] = {
- -1, 0, 0, 0,
- 0, -1, 0, 0,
- 0, 0, 1, 0,
- 1, 1, 0, 1,
-};
-static float mtxRot270[16] = {
- 0, -1, 0, 0,
- 1, 0, 0, 0,
- 0, 0, 1, 0,
- 0, 1, 0, 1,
-};
static void mtxMul(float out[16], const float a[16], const float b[16]);
-SurfaceTexture::SurfaceTexture(GLuint tex, bool allowSynchronousMode,
+GLConsumer::GLConsumer(const sp<BufferQueue>& bq, GLuint tex,
+ GLenum texTarget, bool useFenceSync) :
+ ConsumerBase(bq),
+ mUseFenceSync(useFenceSync),
+ mTexTarget(texTarget) {}
+
+
+GLConsumer::GLConsumer(GLuint tex, bool allowSynchronousMode,
GLenum texTarget, bool useFenceSync, const sp<BufferQueue> &bufferQueue) :
ConsumerBase(bufferQueue == 0 ? new BufferQueue(allowSynchronousMode) : bufferQueue),
mCurrentTransform(0),
+ mCurrentScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
+ mCurrentFence(Fence::NO_FENCE),
mCurrentTimestamp(0),
+ mDefaultWidth(1),
+ mDefaultHeight(1),
mFilteringEnabled(true),
mTexName(tex),
-#ifdef USE_FENCE_SYNC
mUseFenceSync(useFenceSync),
-#else
- mUseFenceSync(false),
-#endif
mTexTarget(texTarget),
mEglDisplay(EGL_NO_DISPLAY),
mEglContext(EGL_NO_CONTEXT),
mCurrentTexture(BufferQueue::INVALID_BUFFER_SLOT),
mAttached(true)
{
- ST_LOGV("SurfaceTexture");
+ ST_LOGV("GLConsumer");
memcpy(mCurrentTransformMatrix, mtxIdentity,
sizeof(mCurrentTransformMatrix));
@@ -139,13 +111,13 @@ SurfaceTexture::SurfaceTexture(GLuint tex, bool allowSynchronousMode,
mBufferQueue->setConsumerUsageBits(DEFAULT_USAGE_FLAGS);
}
-status_t SurfaceTexture::setDefaultMaxBufferCount(int bufferCount) {
+status_t GLConsumer::setDefaultMaxBufferCount(int bufferCount) {
Mutex::Autolock lock(mMutex);
return mBufferQueue->setDefaultMaxBufferCount(bufferCount);
}
-status_t SurfaceTexture::setDefaultBufferSize(uint32_t w, uint32_t h)
+status_t GLConsumer::setDefaultBufferSize(uint32_t w, uint32_t h)
{
Mutex::Autolock lock(mMutex);
mDefaultWidth = w;
@@ -153,11 +125,54 @@ status_t SurfaceTexture::setDefaultBufferSize(uint32_t w, uint32_t h)
return mBufferQueue->setDefaultBufferSize(w, h);
}
-status_t SurfaceTexture::updateTexImage() {
- return SurfaceTexture::updateTexImage(NULL, false);
+status_t GLConsumer::updateTexImage() {
+ ATRACE_CALL();
+ ST_LOGV("updateTexImage");
+ Mutex::Autolock lock(mMutex);
+
+ if (mAbandoned) {
+ ST_LOGE("updateTexImage: GLConsumer is abandoned!");
+ return NO_INIT;
+ }
+
+ // Make sure the EGL state is the same as in previous calls.
+ status_t err = checkAndUpdateEglStateLocked();
+ if (err != NO_ERROR) {
+ return err;
+ }
+
+ BufferQueue::BufferItem item;
+
+ // Acquire the next buffer.
+ // In asynchronous mode the list is guaranteed to be one buffer
+ // deep, while in synchronous mode we use the oldest buffer.
+ err = acquireBufferLocked(&item);
+ if (err != NO_ERROR) {
+ if (err == BufferQueue::NO_BUFFER_AVAILABLE) {
+ // We always bind the texture even if we don't update its contents.
+ ST_LOGV("updateTexImage: no buffers were available");
+ glBindTexture(mTexTarget, mTexName);
+ err = NO_ERROR;
+ } else {
+ ST_LOGE("updateTexImage: acquire failed: %s (%d)",
+ strerror(-err), err);
+ }
+ return err;
+ }
+
+ // Release the previous buffer.
+ err = releaseAndUpdateLocked(item);
+ if (err != NO_ERROR) {
+ // We always bind the texture.
+ glBindTexture(mTexTarget, mTexName);
+ return err;
+ }
+
+ // Bind the new buffer to the GL texture, and wait until it's ready.
+ return bindTextureImageLocked();
}
-status_t SurfaceTexture::acquireBufferLocked(BufferQueue::BufferItem *item) {
+status_t GLConsumer::acquireBufferLocked(BufferQueue::BufferItem *item) {
status_t err = ConsumerBase::acquireBufferLocked(item);
if (err != NO_ERROR) {
return err;
@@ -165,186 +180,187 @@ status_t SurfaceTexture::acquireBufferLocked(BufferQueue::BufferItem *item) {
int slot = item->mBuf;
if (item->mGraphicBuffer != NULL) {
+ // This buffer has not been acquired before, so we must assume
+ // that any EGLImage in mEglSlots is stale.
if (mEglSlots[slot].mEglImage != EGL_NO_IMAGE_KHR) {
- eglDestroyImageKHR(mEglDisplay, mEglSlots[slot].mEglImage);
+ if (!eglDestroyImageKHR(mEglDisplay, mEglSlots[slot].mEglImage)) {
+ ST_LOGW("acquireBufferLocked: eglDestroyImageKHR failed for slot=%d",
+ slot);
+ // keep going
+ }
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::releaseBufferLocked(int buf, EGLDisplay display,
+status_t GLConsumer::releaseBufferLocked(int buf, EGLDisplay display,
EGLSyncKHR eglFence) {
- status_t err = ConsumerBase::releaseBufferLocked(buf, mEglDisplay,
- eglFence);
+ status_t err = ConsumerBase::releaseBufferLocked(buf, display, 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);
-
+status_t GLConsumer::releaseAndUpdateLocked(const BufferQueue::BufferItem& item)
+{
status_t err = NO_ERROR;
- if (mAbandoned) {
- ST_LOGE("updateTexImage: SurfaceTexture is abandoned!");
- return NO_INIT;
- }
-
if (!mAttached) {
- ST_LOGE("updateTexImage: SurfaceTexture is not attached to an OpenGL "
+ ST_LOGE("releaseAndUpdate: GLConsumer is not attached to an OpenGL "
"ES context");
return INVALID_OPERATION;
}
- EGLDisplay dpy = eglGetCurrentDisplay();
- EGLContext ctx = eglGetCurrentContext();
+ // Confirm state.
+ err = checkAndUpdateEglStateLocked();
+ if (err != NO_ERROR) {
+ return err;
+ }
- if ((mEglDisplay != dpy && mEglDisplay != EGL_NO_DISPLAY) ||
- dpy == EGL_NO_DISPLAY) {
- ST_LOGE("updateTexImage: invalid current EGLDisplay");
- return INVALID_OPERATION;
+ int buf = item.mBuf;
+
+ // If the mEglSlot entry is empty, create an EGLImage for the gralloc
+ // buffer currently in the slot in ConsumerBase.
+ //
+ // We may have to do this even when item.mGraphicBuffer == NULL (which
+ // means the buffer was previously acquired), if we destroyed the
+ // EGLImage when detaching from a context but the buffer has not been
+ // re-allocated.
+ if (mEglSlots[buf].mEglImage == EGL_NO_IMAGE_KHR) {
+ EGLImageKHR image = createImage(mEglDisplay, mSlots[buf].mGraphicBuffer);
+ if (image == EGL_NO_IMAGE_KHR) {
+ ST_LOGW("releaseAndUpdate: unable to createImage on display=%p slot=%d",
+ mEglDisplay, buf);
+ return UNKNOWN_ERROR;
+ }
+ mEglSlots[buf].mEglImage = image;
}
- if ((mEglContext != ctx && mEglContext != EGL_NO_CONTEXT) ||
- ctx == EGL_NO_CONTEXT) {
- ST_LOGE("updateTexImage: invalid current EGLContext");
- return INVALID_OPERATION;
+ // Do whatever sync ops we need to do before releasing the old slot.
+ err = syncForReleaseLocked(mEglDisplay);
+ 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.
+ releaseBufferLocked(buf, mEglDisplay, EGL_NO_SYNC_KHR);
+ return err;
}
- mEglDisplay = dpy;
- mEglContext = ctx;
+ ST_LOGV("releaseAndUpdate: (slot=%d buf=%p) -> (slot=%d buf=%p)",
+ mCurrentTexture,
+ mCurrentTextureBuf != NULL ? mCurrentTextureBuf->handle : 0,
+ buf, mSlots[buf].mGraphicBuffer->handle);
- BufferQueue::BufferItem item;
-
- // In asynchronous mode the list is guaranteed to be one buffer
- // deep, while in synchronous mode we use the oldest buffer.
- err = acquireBufferLocked(&item);
- if (err == NO_ERROR) {
- int buf = item.mBuf;
-
- // 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(mSlots[buf].mGraphicBuffer, item)) {
- releaseBufferLocked(buf, dpy, EGL_NO_SYNC_KHR);
- glBindTexture(mTexTarget, mTexName);
- return NO_ERROR;
+ // release old buffer
+ if (mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) {
+ status_t status = releaseBufferLocked(mCurrentTexture, mEglDisplay,
+ mEglSlots[mCurrentTexture].mEglFence);
+ if (status != NO_ERROR && status != BufferQueue::STALE_BUFFER_SLOT) {
+ ST_LOGE("releaseAndUpdate: failed to release buffer: %s (%d)",
+ strerror(-status), status);
+ err = status;
+ // keep going, with error raised [?]
}
+ }
- GLint error;
- while ((error = glGetError()) != GL_NO_ERROR) {
- ST_LOGW("updateTexImage: clearing GL error: %#04x", error);
- }
+ // Update the GLConsumer state.
+ mCurrentTexture = buf;
+ mCurrentTextureBuf = mSlots[buf].mGraphicBuffer;
+ mCurrentCrop = item.mCrop;
+ mCurrentTransform = item.mTransform;
+ mCurrentScalingMode = item.mScalingMode;
+ mCurrentTimestamp = item.mTimestamp;
+ mCurrentFence = item.mFence;
- EGLImageKHR image = mEglSlots[buf].mEglImage;
- glBindTexture(mTexTarget, mTexName);
- glEGLImageTargetTexture2DOES(mTexTarget, (GLeglImageOES)image);
+ computeCurrentTransformMatrixLocked();
- while ((error = glGetError()) != GL_NO_ERROR) {
- ST_LOGE("updateTexImage: error binding external texture image %p "
- "(slot %d): %#04x", image, buf, error);
- err = UNKNOWN_ERROR;
- }
+ return err;
+}
- if (err == NO_ERROR) {
- err = syncForReleaseLocked(dpy);
- }
+status_t GLConsumer::bindTextureImageLocked() {
+ if (mEglDisplay == EGL_NO_DISPLAY) {
+ ALOGE("bindTextureImage: invalid display");
+ return INVALID_OPERATION;
+ }
+ GLint error;
+ while ((error = glGetError()) != GL_NO_ERROR) {
+ ST_LOGW("bindTextureImage: clearing GL error: %#04x", error);
+ }
+
+ glBindTexture(mTexTarget, mTexName);
+ if (mCurrentTexture == BufferQueue::INVALID_BUFFER_SLOT) {
+ if (mCurrentTextureBuf == NULL) {
+ ST_LOGE("bindTextureImage: no currently-bound texture");
+ return NO_INIT;
+ }
+ status_t err = bindUnslottedBufferLocked(mEglDisplay);
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.
- releaseBufferLocked(buf, dpy, EGL_NO_SYNC_KHR);
return err;
}
+ } else {
+ EGLImageKHR image = mEglSlots[mCurrentTexture].mEglImage;
- ST_LOGV("updateTexImage: (slot=%d buf=%p) -> (slot=%d buf=%p)",
- mCurrentTexture,
- mCurrentTextureBuf != NULL ? mCurrentTextureBuf->handle : 0,
- buf, mSlots[buf].mGraphicBuffer->handle);
-
- // release old buffer
- if (mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) {
- 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;
- }
- }
+ glEGLImageTargetTexture2DOES(mTexTarget, (GLeglImageOES)image);
- // Update the SurfaceTexture state.
- mCurrentTexture = buf;
- mCurrentTextureBuf = mSlots[buf].mGraphicBuffer;
- mCurrentCrop = item.mCrop;
- mCurrentTransform = item.mTransform;
- mCurrentScalingMode = item.mScalingMode;
- mCurrentTimestamp = item.mTimestamp;
- 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) {
- ST_LOGE("updateTexImage: acquire failed: %s (%d)",
- strerror(-err), err);
- return err;
+ while ((error = glGetError()) != GL_NO_ERROR) {
+ ST_LOGE("bindTextureImage: error binding external texture image %p"
+ ": %#04x", image, error);
+ return UNKNOWN_ERROR;
}
- // We always bind the texture even if we don't update its contents.
- glBindTexture(mTexTarget, mTexName);
- return OK;
}
- return err;
+ // Wait for the new buffer to be ready.
+ return doGLFenceWaitLocked();
+
}
-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 GLConsumer::checkAndUpdateEglStateLocked() {
+ EGLDisplay dpy = eglGetCurrentDisplay();
+ EGLContext ctx = eglGetCurrentContext();
+
+ if ((mEglDisplay != dpy && mEglDisplay != EGL_NO_DISPLAY) ||
+ dpy == EGL_NO_DISPLAY) {
+ ST_LOGE("checkAndUpdateEglState: invalid current EGLDisplay");
+ return INVALID_OPERATION;
+ }
+
+ if ((mEglContext != ctx && mEglContext != EGL_NO_CONTEXT) ||
+ ctx == EGL_NO_CONTEXT) {
+ ST_LOGE("checkAndUpdateEglState: invalid current EGLContext");
+ return INVALID_OPERATION;
+ }
+
+ mEglDisplay = dpy;
+ mEglContext = ctx;
+ return NO_ERROR;
+}
+
+void GLConsumer::setReleaseFence(const sp<Fence>& fence) {
+ if (fence->isValid() &&
+ mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) {
+ 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() {
+status_t GLConsumer::detachFromContext() {
ATRACE_CALL();
ST_LOGV("detachFromContext");
Mutex::Autolock lock(mMutex);
if (mAbandoned) {
- ST_LOGE("detachFromContext: abandoned SurfaceTexture");
+ ST_LOGE("detachFromContext: abandoned GLConsumer");
return NO_INIT;
}
if (!mAttached) {
- ST_LOGE("detachFromContext: SurfaceTexture is not attached to a "
+ ST_LOGE("detachFromContext: GLConsumer is not attached to a "
"context");
return INVALID_OPERATION;
}
@@ -373,7 +389,7 @@ status_t SurfaceTexture::detachFromContext() {
// Because we're giving up the EGLDisplay we need to free all the EGLImages
// that are associated with it. They'll be recreated when the
- // SurfaceTexture gets attached to a new OpenGL ES context (and thus gets a
+ // GLConsumer 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;
@@ -390,18 +406,18 @@ status_t SurfaceTexture::detachFromContext() {
return OK;
}
-status_t SurfaceTexture::attachToContext(GLuint tex) {
+status_t GLConsumer::attachToContext(GLuint tex) {
ATRACE_CALL();
ST_LOGV("attachToContext");
Mutex::Autolock lock(mMutex);
if (mAbandoned) {
- ST_LOGE("attachToContext: abandoned SurfaceTexture");
+ ST_LOGE("attachToContext: abandoned GLConsumer");
return NO_INIT;
}
if (mAttached) {
- ST_LOGE("attachToContext: SurfaceTexture is already attached to a "
+ ST_LOGE("attachToContext: GLConsumer is already attached to a "
"context");
return INVALID_OPERATION;
}
@@ -425,32 +441,10 @@ status_t SurfaceTexture::attachToContext(GLuint tex) {
if (mCurrentTextureBuf != NULL) {
// The EGLImageKHR that was associated with the slot was destroyed when
- // the SurfaceTexture was detached from the old context, so we need to
+ // the GLConsumer was detached from the old context, so we need to
// recreate it here.
- EGLImageKHR image = createImage(dpy, mCurrentTextureBuf);
- if (image == EGL_NO_IMAGE_KHR) {
- return UNKNOWN_ERROR;
- }
-
- // Attach the current buffer to the GL texture.
- glEGLImageTargetTexture2DOES(mTexTarget, (GLeglImageOES)image);
-
- GLint error;
- status_t err = OK;
- while ((error = glGetError()) != GL_NO_ERROR) {
- ST_LOGE("attachToContext: error binding external texture image %p "
- "(slot %d): %#04x", image, mCurrentTexture, error);
- err = UNKNOWN_ERROR;
- }
-
- // We destroy the EGLImageKHR here because the current buffer may no
- // longer be associated with one of the buffer slots, so we have
- // nowhere to to store it. If the buffer is still associated with a
- // slot then another EGLImageKHR will be created next time that buffer
- // gets acquired in updateTexImage.
- eglDestroyImageKHR(dpy, image);
-
- if (err != OK) {
+ status_t err = bindUnslottedBufferLocked(dpy);
+ if (err != NO_ERROR) {
return err;
}
}
@@ -463,11 +457,43 @@ status_t SurfaceTexture::attachToContext(GLuint tex) {
return OK;
}
-status_t SurfaceTexture::syncForReleaseLocked(EGLDisplay dpy) {
+status_t GLConsumer::bindUnslottedBufferLocked(EGLDisplay dpy) {
+ ST_LOGV("bindUnslottedBuffer ct=%d ctb=%p",
+ mCurrentTexture, mCurrentTextureBuf.get());
+
+ // Create a temporary EGLImageKHR.
+ EGLImageKHR image = createImage(dpy, mCurrentTextureBuf);
+ if (image == EGL_NO_IMAGE_KHR) {
+ return UNKNOWN_ERROR;
+ }
+
+ // Attach the current buffer to the GL texture.
+ glEGLImageTargetTexture2DOES(mTexTarget, (GLeglImageOES)image);
+
+ GLint error;
+ status_t err = OK;
+ while ((error = glGetError()) != GL_NO_ERROR) {
+ ST_LOGE("bindUnslottedBuffer: error binding external texture image %p "
+ "(slot %d): %#04x", image, mCurrentTexture, error);
+ err = UNKNOWN_ERROR;
+ }
+
+ // We destroy the EGLImageKHR here because the current buffer may no
+ // longer be associated with one of the buffer slots, so we have
+ // nowhere to to store it. If the buffer is still associated with a
+ // slot then another EGLImageKHR will be created next time that buffer
+ // gets acquired in updateTexImage.
+ eglDestroyImageKHR(dpy, image);
+
+ return err;
+}
+
+
+status_t GLConsumer::syncForReleaseLocked(EGLDisplay dpy) {
ST_LOGV("syncForReleaseLocked");
if (mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) {
- if (useNativeFenceSync) {
+ if (SyncFeatures::getInstance().useNativeFenceSync()) {
EGLSyncKHR sync = eglCreateSyncKHR(dpy,
EGL_SYNC_NATIVE_FENCE_ANDROID, NULL);
if (sync == EGL_NO_SYNC_KHR) {
@@ -490,7 +516,7 @@ status_t SurfaceTexture::syncForReleaseLocked(EGLDisplay dpy) {
"%s (%d)", strerror(-err), err);
return err;
}
- } else if (mUseFenceSync) {
+ } else if (mUseFenceSync && SyncFeatures::getInstance().useFenceSync()) {
EGLSyncKHR fence = mEglSlots[mCurrentTexture].mEglFence;
if (fence != EGL_NO_SYNC_KHR) {
// There is already a fence for the current slot. We need to
@@ -526,7 +552,7 @@ status_t SurfaceTexture::syncForReleaseLocked(EGLDisplay dpy) {
return OK;
}
-bool SurfaceTexture::isExternalFormat(uint32_t format)
+bool GLConsumer::isExternalFormat(uint32_t format)
{
switch (format) {
// supported YUV formats
@@ -545,19 +571,19 @@ bool SurfaceTexture::isExternalFormat(uint32_t format)
return false;
}
-GLenum SurfaceTexture::getCurrentTextureTarget() const {
+GLenum GLConsumer::getCurrentTextureTarget() const {
return mTexTarget;
}
-void SurfaceTexture::getTransformMatrix(float mtx[16]) {
+void GLConsumer::getTransformMatrix(float mtx[16]) {
Mutex::Autolock lock(mMutex);
memcpy(mtx, mCurrentTransformMatrix, sizeof(mCurrentTransformMatrix));
}
-void SurfaceTexture::setFilteringEnabled(bool enabled) {
+void GLConsumer::setFilteringEnabled(bool enabled) {
Mutex::Autolock lock(mMutex);
if (mAbandoned) {
- ST_LOGE("setFilteringEnabled: SurfaceTexture is abandoned!");
+ ST_LOGE("setFilteringEnabled: GLConsumer is abandoned!");
return;
}
bool needsRecompute = mFilteringEnabled != enabled;
@@ -572,7 +598,7 @@ void SurfaceTexture::setFilteringEnabled(bool enabled) {
}
}
-void SurfaceTexture::computeCurrentTransformMatrixLocked() {
+void GLConsumer::computeCurrentTransformMatrixLocked() {
ST_LOGV("computeCurrentTransformMatrixLocked");
float xform[16];
@@ -665,19 +691,19 @@ void SurfaceTexture::computeCurrentTransformMatrixLocked() {
mtxMul(mtxBeforeFlipV, crop, xform);
// SurfaceFlinger expects the top of its window textures to be at a Y
- // coordinate of 0, so SurfaceTexture must behave the same way. We don't
+ // coordinate of 0, so GLConsumer must behave the same way. We don't
// want to expose this to applications, however, so we must add an
// additional vertical flip to the transform after all the other transforms.
mtxMul(mCurrentTransformMatrix, mtxFlipV, mtxBeforeFlipV);
}
-nsecs_t SurfaceTexture::getTimestamp() {
+nsecs_t GLConsumer::getTimestamp() {
ST_LOGV("getTimestamp");
Mutex::Autolock lock(mMutex);
return mCurrentTimestamp;
}
-EGLImageKHR SurfaceTexture::createImage(EGLDisplay dpy,
+EGLImageKHR GLConsumer::createImage(EGLDisplay dpy,
const sp<GraphicBuffer>& graphicBuffer) {
EGLClientBuffer cbuf = (EGLClientBuffer)graphicBuffer->getNativeBuffer();
EGLint attrs[] = {
@@ -693,12 +719,12 @@ EGLImageKHR SurfaceTexture::createImage(EGLDisplay dpy,
return image;
}
-sp<GraphicBuffer> SurfaceTexture::getCurrentBuffer() const {
+sp<GraphicBuffer> GLConsumer::getCurrentBuffer() const {
Mutex::Autolock lock(mMutex);
return mCurrentTextureBuf;
}
-Rect SurfaceTexture::getCurrentCrop() const {
+Rect GLConsumer::getCurrentCrop() const {
Mutex::Autolock lock(mMutex);
Rect outCrop = mCurrentCrop;
@@ -734,27 +760,27 @@ Rect SurfaceTexture::getCurrentCrop() const {
return outCrop;
}
-uint32_t SurfaceTexture::getCurrentTransform() const {
+uint32_t GLConsumer::getCurrentTransform() const {
Mutex::Autolock lock(mMutex);
return mCurrentTransform;
}
-uint32_t SurfaceTexture::getCurrentScalingMode() const {
+uint32_t GLConsumer::getCurrentScalingMode() const {
Mutex::Autolock lock(mMutex);
return mCurrentScalingMode;
}
-sp<Fence> SurfaceTexture::getCurrentFence() const {
+sp<Fence> GLConsumer::getCurrentFence() const {
Mutex::Autolock lock(mMutex);
return mCurrentFence;
}
-status_t SurfaceTexture::doGLFenceWait() const {
+status_t GLConsumer::doGLFenceWait() const {
Mutex::Autolock lock(mMutex);
return doGLFenceWaitLocked();
}
-status_t SurfaceTexture::doGLFenceWaitLocked() const {
+status_t GLConsumer::doGLFenceWaitLocked() const {
EGLDisplay dpy = eglGetCurrentDisplay();
EGLContext ctx = eglGetCurrentContext();
@@ -769,8 +795,8 @@ status_t SurfaceTexture::doGLFenceWaitLocked() const {
return INVALID_OPERATION;
}
- if (mCurrentFence != NULL) {
- if (useWaitSync) {
+ if (mCurrentFence->isValid()) {
+ if (SyncFeatures::getInstance().useWaitSync()) {
// Create an EGLSyncKHR from the current fence.
int fenceFd = mCurrentFence->dup();
if (fenceFd == -1) {
@@ -793,7 +819,7 @@ status_t SurfaceTexture::doGLFenceWaitLocked() const {
// 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);
+ eglWaitSyncKHR(dpy, sync, 0);
EGLint eglErr = eglGetError();
eglDestroySyncKHR(dpy, sync);
if (eglErr != EGL_SUCCESS) {
@@ -802,8 +828,8 @@ status_t SurfaceTexture::doGLFenceWaitLocked() const {
return UNKNOWN_ERROR;
}
} else {
- status_t err = mCurrentFence->waitForever(1000,
- "SurfaceTexture::doGLFenceWaitLocked");
+ status_t err = mCurrentFence->waitForever(
+ "GLConsumer::doGLFenceWaitLocked");
if (err != NO_ERROR) {
ST_LOGE("doGLFenceWait: error waiting for fence: %d", err);
return err;
@@ -814,12 +840,12 @@ status_t SurfaceTexture::doGLFenceWaitLocked() const {
return NO_ERROR;
}
-bool SurfaceTexture::isSynchronousMode() const {
+bool GLConsumer::isSynchronousMode() const {
Mutex::Autolock lock(mMutex);
return mBufferQueue->isSynchronousMode();
}
-void SurfaceTexture::freeBufferLocked(int slotIndex) {
+void GLConsumer::freeBufferLocked(int slotIndex) {
ST_LOGV("freeBufferLocked: slotIndex=%d", slotIndex);
if (slotIndex == mCurrentTexture) {
mCurrentTexture = BufferQueue::INVALID_BUFFER_SLOT;
@@ -833,42 +859,42 @@ void SurfaceTexture::freeBufferLocked(int slotIndex) {
ConsumerBase::freeBufferLocked(slotIndex);
}
-void SurfaceTexture::abandonLocked() {
+void GLConsumer::abandonLocked() {
ST_LOGV("abandonLocked");
mCurrentTextureBuf.clear();
ConsumerBase::abandonLocked();
}
-void SurfaceTexture::setName(const String8& name) {
+void GLConsumer::setName(const String8& name) {
Mutex::Autolock _l(mMutex);
mName = name;
mBufferQueue->setConsumerName(name);
}
-status_t SurfaceTexture::setDefaultBufferFormat(uint32_t defaultFormat) {
+status_t GLConsumer::setDefaultBufferFormat(uint32_t defaultFormat) {
Mutex::Autolock lock(mMutex);
return mBufferQueue->setDefaultBufferFormat(defaultFormat);
}
-status_t SurfaceTexture::setConsumerUsageBits(uint32_t usage) {
+status_t GLConsumer::setConsumerUsageBits(uint32_t usage) {
Mutex::Autolock lock(mMutex);
usage |= DEFAULT_USAGE_FLAGS;
return mBufferQueue->setConsumerUsageBits(usage);
}
-status_t SurfaceTexture::setTransformHint(uint32_t hint) {
+status_t GLConsumer::setTransformHint(uint32_t hint) {
Mutex::Autolock lock(mMutex);
return mBufferQueue->setTransformHint(hint);
}
-// Used for refactoring BufferQueue from SurfaceTexture
-// Should not be in final interface once users of SurfaceTexture are clean up.
-status_t SurfaceTexture::setSynchronousMode(bool enabled) {
+// Used for refactoring BufferQueue from GLConsumer
+// Should not be in final interface once users of GLConsumer are clean up.
+status_t GLConsumer::setSynchronousMode(bool enabled) {
Mutex::Autolock lock(mMutex);
return mBufferQueue->setSynchronousMode(enabled);
}
-void SurfaceTexture::dumpLocked(String8& result, const char* prefix,
+void GLConsumer::dumpLocked(String8& result, const char* prefix,
char* buffer, size_t size) const
{
snprintf(buffer, size,
diff --git a/libs/gui/GraphicBufferAlloc.cpp b/libs/gui/GraphicBufferAlloc.cpp
new file mode 100644
index 0000000..b360e81
--- /dev/null
+++ b/libs/gui/GraphicBufferAlloc.cpp
@@ -0,0 +1,53 @@
+/*
+ **
+ ** Copyright 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 <cutils/log.h>
+
+#include <ui/GraphicBuffer.h>
+
+#include <gui/GraphicBufferAlloc.h>
+
+// ----------------------------------------------------------------------------
+namespace android {
+// ----------------------------------------------------------------------------
+
+GraphicBufferAlloc::GraphicBufferAlloc() {
+}
+
+GraphicBufferAlloc::~GraphicBufferAlloc() {
+}
+
+sp<GraphicBuffer> GraphicBufferAlloc::createGraphicBuffer(uint32_t w, uint32_t h,
+ PixelFormat format, uint32_t usage, status_t* error) {
+ sp<GraphicBuffer> graphicBuffer(new GraphicBuffer(w, h, format, usage));
+ status_t err = graphicBuffer->initCheck();
+ *error = err;
+ if (err != 0 || graphicBuffer->handle == 0) {
+ if (err == NO_MEMORY) {
+ GraphicBuffer::dumpAllocationsToSystemLog();
+ }
+ ALOGE("GraphicBufferAlloc::createGraphicBuffer(w=%d, h=%d) "
+ "failed (%s), handle=%p",
+ w, h, strerror(-err), graphicBuffer->handle);
+ return 0;
+ }
+ return graphicBuffer;
+}
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+// ----------------------------------------------------------------------------
diff --git a/libs/gui/GuiConfig.cpp b/libs/gui/GuiConfig.cpp
index bafd21a..bc0c83c 100644
--- a/libs/gui/GuiConfig.cpp
+++ b/libs/gui/GuiConfig.cpp
@@ -22,14 +22,8 @@ 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"
+#ifdef DONT_USE_FENCE_SYNC
+ " DONT_USE_FENCE_SYNC"
#endif
"]";
configStr.append(config);
diff --git a/libs/gui/ISurfaceTexture.cpp b/libs/gui/IGraphicBufferProducer.cpp
index a0b1e74..63d7628 100644
--- a/libs/gui/ISurfaceTexture.cpp
+++ b/libs/gui/IGraphicBufferProducer.cpp
@@ -25,7 +25,7 @@
#include <binder/Parcel.h>
#include <binder/IInterface.h>
-#include <gui/ISurfaceTexture.h>
+#include <gui/IGraphicBufferProducer.h>
namespace android {
// ----------------------------------------------------------------------------
@@ -43,17 +43,17 @@ enum {
};
-class BpSurfaceTexture : public BpInterface<ISurfaceTexture>
+class BpGraphicBufferProducer : public BpInterface<IGraphicBufferProducer>
{
public:
- BpSurfaceTexture(const sp<IBinder>& impl)
- : BpInterface<ISurfaceTexture>(impl)
+ BpGraphicBufferProducer(const sp<IBinder>& impl)
+ : BpInterface<IGraphicBufferProducer>(impl)
{
}
virtual status_t requestBuffer(int bufferIdx, sp<GraphicBuffer>* buf) {
Parcel data, reply;
- data.writeInterfaceToken(ISurfaceTexture::getInterfaceDescriptor());
+ data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor());
data.writeInt32(bufferIdx);
status_t result =remote()->transact(REQUEST_BUFFER, data, &reply);
if (result != NO_ERROR) {
@@ -71,7 +71,7 @@ public:
virtual status_t setBufferCount(int bufferCount)
{
Parcel data, reply;
- data.writeInterfaceToken(ISurfaceTexture::getInterfaceDescriptor());
+ data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor());
data.writeInt32(bufferCount);
status_t result =remote()->transact(SET_BUFFER_COUNT, data, &reply);
if (result != NO_ERROR) {
@@ -81,10 +81,10 @@ public:
return result;
}
- virtual status_t dequeueBuffer(int *buf, sp<Fence>& fence,
+ 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.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor());
data.writeInt32(w);
data.writeInt32(h);
data.writeInt32(format);
@@ -94,11 +94,13 @@ public:
return result;
}
*buf = reply.readInt32();
- fence.clear();
- bool hasFence = reply.readInt32();
- if (hasFence) {
- fence = new Fence();
- reply.read(*fence.get());
+ bool fenceWasWritten = reply.readInt32();
+ if (fenceWasWritten) {
+ // If the fence was written by the callee, then overwrite the
+ // caller's fence here. If it wasn't written then don't touch the
+ // caller's fence.
+ *fence = new Fence();
+ reply.read(*(fence->get()));
}
result = reply.readInt32();
return result;
@@ -107,7 +109,7 @@ public:
virtual status_t queueBuffer(int buf,
const QueueBufferInput& input, QueueBufferOutput* output) {
Parcel data, reply;
- data.writeInterfaceToken(ISurfaceTexture::getInterfaceDescriptor());
+ data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor());
data.writeInt32(buf);
data.write(input);
status_t result = remote()->transact(QUEUE_BUFFER, data, &reply);
@@ -119,21 +121,17 @@ public:
return result;
}
- virtual void cancelBuffer(int buf, sp<Fence> fence) {
+ virtual void cancelBuffer(int buf, const sp<Fence>& fence) {
Parcel data, reply;
- bool hasFence = fence.get() && fence->isValid();
- data.writeInterfaceToken(ISurfaceTexture::getInterfaceDescriptor());
+ data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor());
data.writeInt32(buf);
- data.writeInt32(hasFence);
- if (hasFence) {
- data.write(*fence.get());
- }
+ data.write(*fence.get());
remote()->transact(CANCEL_BUFFER, data, &reply);
}
virtual int query(int what, int* value) {
Parcel data, reply;
- data.writeInterfaceToken(ISurfaceTexture::getInterfaceDescriptor());
+ data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor());
data.writeInt32(what);
status_t result = remote()->transact(QUERY, data, &reply);
if (result != NO_ERROR) {
@@ -146,7 +144,7 @@ public:
virtual status_t setSynchronousMode(bool enabled) {
Parcel data, reply;
- data.writeInterfaceToken(ISurfaceTexture::getInterfaceDescriptor());
+ data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor());
data.writeInt32(enabled);
status_t result = remote()->transact(SET_SYNCHRONOUS_MODE, data, &reply);
if (result != NO_ERROR) {
@@ -158,7 +156,7 @@ public:
virtual status_t connect(int api, QueueBufferOutput* output) {
Parcel data, reply;
- data.writeInterfaceToken(ISurfaceTexture::getInterfaceDescriptor());
+ data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor());
data.writeInt32(api);
status_t result = remote()->transact(CONNECT, data, &reply);
if (result != NO_ERROR) {
@@ -171,7 +169,7 @@ public:
virtual status_t disconnect(int api) {
Parcel data, reply;
- data.writeInterfaceToken(ISurfaceTexture::getInterfaceDescriptor());
+ data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor());
data.writeInt32(api);
status_t result =remote()->transact(DISCONNECT, data, &reply);
if (result != NO_ERROR) {
@@ -182,16 +180,16 @@ public:
}
};
-IMPLEMENT_META_INTERFACE(SurfaceTexture, "android.gui.SurfaceTexture");
+IMPLEMENT_META_INTERFACE(GraphicBufferProducer, "android.gui.IGraphicBufferProducer");
// ----------------------------------------------------------------------
-status_t BnSurfaceTexture::onTransact(
+status_t BnGraphicBufferProducer::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
switch(code) {
case REQUEST_BUFFER: {
- CHECK_INTERFACE(ISurfaceTexture, data, reply);
+ CHECK_INTERFACE(IGraphicBufferProducer, data, reply);
int bufferIdx = data.readInt32();
sp<GraphicBuffer> buffer;
int result = requestBuffer(bufferIdx, &buffer);
@@ -203,32 +201,31 @@ status_t BnSurfaceTexture::onTransact(
return NO_ERROR;
} break;
case SET_BUFFER_COUNT: {
- CHECK_INTERFACE(ISurfaceTexture, data, reply);
+ CHECK_INTERFACE(IGraphicBufferProducer, data, reply);
int bufferCount = data.readInt32();
int result = setBufferCount(bufferCount);
reply->writeInt32(result);
return NO_ERROR;
} break;
case DEQUEUE_BUFFER: {
- CHECK_INTERFACE(ISurfaceTexture, data, reply);
+ CHECK_INTERFACE(IGraphicBufferProducer, data, reply);
uint32_t w = data.readInt32();
uint32_t h = data.readInt32();
uint32_t format = data.readInt32();
uint32_t usage = data.readInt32();
int buf;
sp<Fence> fence;
- int result = dequeueBuffer(&buf, fence, w, h, format, usage);
- bool hasFence = fence.get() && fence->isValid();
+ int result = dequeueBuffer(&buf, &fence, w, h, format, usage);
reply->writeInt32(buf);
- reply->writeInt32(hasFence);
- if (hasFence) {
+ reply->writeInt32(fence != NULL);
+ if (fence != NULL) {
reply->write(*fence.get());
}
reply->writeInt32(result);
return NO_ERROR;
} break;
case QUEUE_BUFFER: {
- CHECK_INTERFACE(ISurfaceTexture, data, reply);
+ CHECK_INTERFACE(IGraphicBufferProducer, data, reply);
int buf = data.readInt32();
QueueBufferInput input(data);
QueueBufferOutput* const output =
@@ -239,19 +236,15 @@ status_t BnSurfaceTexture::onTransact(
return NO_ERROR;
} break;
case CANCEL_BUFFER: {
- CHECK_INTERFACE(ISurfaceTexture, data, reply);
+ CHECK_INTERFACE(IGraphicBufferProducer, data, reply);
int buf = data.readInt32();
- sp<Fence> fence;
- bool hasFence = data.readInt32();
- if (hasFence) {
- fence = new Fence();
- data.read(*fence.get());
- }
+ sp<Fence> fence = new Fence();
+ data.read(*fence.get());
cancelBuffer(buf, fence);
return NO_ERROR;
} break;
case QUERY: {
- CHECK_INTERFACE(ISurfaceTexture, data, reply);
+ CHECK_INTERFACE(IGraphicBufferProducer, data, reply);
int value;
int what = data.readInt32();
int res = query(what, &value);
@@ -260,14 +253,14 @@ status_t BnSurfaceTexture::onTransact(
return NO_ERROR;
} break;
case SET_SYNCHRONOUS_MODE: {
- CHECK_INTERFACE(ISurfaceTexture, data, reply);
+ CHECK_INTERFACE(IGraphicBufferProducer, data, reply);
bool enabled = data.readInt32();
status_t res = setSynchronousMode(enabled);
reply->writeInt32(res);
return NO_ERROR;
} break;
case CONNECT: {
- CHECK_INTERFACE(ISurfaceTexture, data, reply);
+ CHECK_INTERFACE(IGraphicBufferProducer, data, reply);
int api = data.readInt32();
QueueBufferOutput* const output =
reinterpret_cast<QueueBufferOutput *>(
@@ -277,7 +270,7 @@ status_t BnSurfaceTexture::onTransact(
return NO_ERROR;
} break;
case DISCONNECT: {
- CHECK_INTERFACE(ISurfaceTexture, data, reply);
+ CHECK_INTERFACE(IGraphicBufferProducer, data, reply);
int api = data.readInt32();
status_t res = disconnect(api);
reply->writeInt32(res);
@@ -289,61 +282,48 @@ status_t BnSurfaceTexture::onTransact(
// ----------------------------------------------------------------------------
-static bool isValid(const sp<Fence>& fence) {
- return fence.get() && fence->isValid();
-}
-
-ISurfaceTexture::QueueBufferInput::QueueBufferInput(const Parcel& parcel) {
+IGraphicBufferProducer::QueueBufferInput::QueueBufferInput(const Parcel& parcel) {
parcel.read(*this);
}
-size_t ISurfaceTexture::QueueBufferInput::getFlattenedSize() const
+size_t IGraphicBufferProducer::QueueBufferInput::getFlattenedSize() const
{
return sizeof(timestamp)
+ sizeof(crop)
+ sizeof(scalingMode)
+ sizeof(transform)
- + sizeof(bool)
- + (isValid(fence) ? fence->getFlattenedSize() : 0);
+ + fence->getFlattenedSize();
}
-size_t ISurfaceTexture::QueueBufferInput::getFdCount() const
+size_t IGraphicBufferProducer::QueueBufferInput::getFdCount() const
{
- return isValid(fence) ? fence->getFdCount() : 0;
+ return fence->getFdCount();
}
-status_t ISurfaceTexture::QueueBufferInput::flatten(void* buffer, size_t size,
+status_t IGraphicBufferProducer::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);
- }
+ err = fence->flatten(p, size - (p - (char*)buffer), fds, count);
return err;
}
-status_t ISurfaceTexture::QueueBufferInput::unflatten(void const* buffer,
+status_t IGraphicBufferProducer::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);
- }
+ fence = new Fence();
+ err = fence->unflatten(p, size - (p - (const char*)buffer), fds, count);
return err;
}
diff --git a/libs/gui/ISurface.cpp b/libs/gui/ISurface.cpp
deleted file mode 100644
index c2ea183..0000000
--- a/libs/gui/ISurface.cpp
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (C) 2007 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 "ISurface"
-
-#include <stdio.h>
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <binder/Parcel.h>
-
-#include <gui/ISurface.h>
-#include <gui/ISurfaceTexture.h>
-
-namespace android {
-
-// ----------------------------------------------------------------------
-
-class BpSurface : public BpInterface<ISurface>
-{
-public:
- BpSurface(const sp<IBinder>& impl)
- : BpInterface<ISurface>(impl)
- {
- }
-
- virtual sp<ISurfaceTexture> getSurfaceTexture() const {
- Parcel data, reply;
- data.writeInterfaceToken(ISurface::getInterfaceDescriptor());
- remote()->transact(GET_SURFACE_TEXTURE, data, &reply);
- return interface_cast<ISurfaceTexture>(reply.readStrongBinder());
- }
-};
-
-IMPLEMENT_META_INTERFACE(Surface, "android.ui.ISurface");
-
-// ----------------------------------------------------------------------
-
-status_t BnSurface::onTransact(
- uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
-{
- switch(code) {
- case GET_SURFACE_TEXTURE: {
- CHECK_INTERFACE(ISurface, data, reply);
- reply->writeStrongBinder( getSurfaceTexture()->asBinder() );
- return NO_ERROR;
- }
- default:
- return BBinder::onTransact(code, data, reply, flags);
- }
-}
-
-}; // namespace android
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index 85a9488..6442a86 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -28,7 +28,7 @@
#include <gui/BitTube.h>
#include <gui/IDisplayEventConnection.h>
#include <gui/ISurfaceComposer.h>
-#include <gui/ISurfaceTexture.h>
+#include <gui/IGraphicBufferProducer.h>
#include <private/gui/LayerState.h>
@@ -102,29 +102,27 @@ public:
remote()->transact(BnSurfaceComposer::BOOT_FINISHED, data, &reply);
}
- virtual status_t captureScreen(
- const sp<IBinder>& display, sp<IMemoryHeap>* heap,
- uint32_t* width, uint32_t* height, PixelFormat* format,
+ virtual status_t captureScreen(const sp<IBinder>& display,
+ const sp<IGraphicBufferProducer>& producer,
uint32_t reqWidth, uint32_t reqHeight,
- uint32_t minLayerZ, uint32_t maxLayerZ)
+ uint32_t minLayerZ, uint32_t maxLayerZ,
+ bool isCpuConsumer)
{
Parcel data, reply;
data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
data.writeStrongBinder(display);
+ data.writeStrongBinder(producer->asBinder());
data.writeInt32(reqWidth);
data.writeInt32(reqHeight);
data.writeInt32(minLayerZ);
data.writeInt32(maxLayerZ);
+ data.writeInt32(isCpuConsumer);
remote()->transact(BnSurfaceComposer::CAPTURE_SCREEN, data, &reply);
- *heap = interface_cast<IMemoryHeap>(reply.readStrongBinder());
- *width = reply.readInt32();
- *height = reply.readInt32();
- *format = reply.readInt32();
return reply.readInt32();
}
virtual bool authenticateSurfaceTexture(
- const sp<ISurfaceTexture>& surfaceTexture) const
+ const sp<IGraphicBufferProducer>& bufferProducer) const
{
Parcel data, reply;
int err = NO_ERROR;
@@ -135,7 +133,7 @@ public:
"interface descriptor: %s (%d)", strerror(-err), -err);
return false;
}
- err = data.writeStrongBinder(surfaceTexture->asBinder());
+ err = data.writeStrongBinder(bufferProducer->asBinder());
if (err != NO_ERROR) {
ALOGE("ISurfaceComposer::authenticateSurfaceTexture: error writing "
"strong binder to parcel: %s (%d)", strerror(-err), -err);
@@ -271,26 +269,23 @@ status_t BnSurfaceComposer::onTransact(
case CAPTURE_SCREEN: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
sp<IBinder> display = data.readStrongBinder();
+ sp<IGraphicBufferProducer> producer =
+ interface_cast<IGraphicBufferProducer>(data.readStrongBinder());
uint32_t reqWidth = data.readInt32();
uint32_t reqHeight = data.readInt32();
uint32_t minLayerZ = data.readInt32();
uint32_t maxLayerZ = data.readInt32();
- sp<IMemoryHeap> heap;
- uint32_t w, h;
- PixelFormat f;
- status_t res = captureScreen(display, &heap, &w, &h, &f,
- reqWidth, reqHeight, minLayerZ, maxLayerZ);
- reply->writeStrongBinder(heap->asBinder());
- reply->writeInt32(w);
- reply->writeInt32(h);
- reply->writeInt32(f);
+ bool isCpuConsumer = data.readInt32();
+ status_t res = captureScreen(display, producer,
+ reqWidth, reqHeight, minLayerZ, maxLayerZ,
+ isCpuConsumer);
reply->writeInt32(res);
} break;
case AUTHENTICATE_SURFACE: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
- sp<ISurfaceTexture> surfaceTexture =
- interface_cast<ISurfaceTexture>(data.readStrongBinder());
- int32_t result = authenticateSurfaceTexture(surfaceTexture) ? 1 : 0;
+ sp<IGraphicBufferProducer> bufferProducer =
+ interface_cast<IGraphicBufferProducer>(data.readStrongBinder());
+ int32_t result = authenticateSurfaceTexture(bufferProducer) ? 1 : 0;
reply->writeInt32(result);
} break;
case CREATE_DISPLAY_EVENT_CONNECTION: {
diff --git a/libs/gui/ISurfaceComposerClient.cpp b/libs/gui/ISurfaceComposerClient.cpp
index 8f7bc05..1adc134 100644
--- a/libs/gui/ISurfaceComposerClient.cpp
+++ b/libs/gui/ISurfaceComposerClient.cpp
@@ -29,7 +29,7 @@
#include <ui/Point.h>
#include <ui/Rect.h>
-#include <gui/ISurface.h>
+#include <gui/IGraphicBufferProducer.h>
#include <gui/ISurfaceComposerClient.h>
#include <private/gui/LayerState.h>
@@ -46,17 +46,13 @@ class BpSurfaceComposerClient : public BpInterface<ISurfaceComposerClient>
{
public:
BpSurfaceComposerClient(const sp<IBinder>& impl)
- : BpInterface<ISurfaceComposerClient>(impl)
- {
+ : BpInterface<ISurfaceComposerClient>(impl) {
}
- virtual sp<ISurface> createSurface( surface_data_t* params,
- const String8& name,
- uint32_t w,
- uint32_t h,
- PixelFormat format,
- uint32_t flags)
- {
+ virtual status_t createSurface(const String8& name, uint32_t w,
+ uint32_t h, PixelFormat format, uint32_t flags,
+ sp<IBinder>* handle,
+ sp<IGraphicBufferProducer>* gbp) {
Parcel data, reply;
data.writeInterfaceToken(ISurfaceComposerClient::getInterfaceDescriptor());
data.writeString8(name);
@@ -65,15 +61,15 @@ public:
data.writeInt32(format);
data.writeInt32(flags);
remote()->transact(CREATE_SURFACE, data, &reply);
- params->readFromParcel(reply);
- return interface_cast<ISurface>(reply.readStrongBinder());
+ *handle = reply.readStrongBinder();
+ *gbp = interface_cast<IGraphicBufferProducer>(reply.readStrongBinder());
+ return reply.readInt32();
}
- virtual status_t destroySurface(SurfaceID sid)
- {
+ virtual status_t destroySurface(const sp<IBinder>& handle) {
Parcel data, reply;
data.writeInterfaceToken(ISurfaceComposerClient::getInterfaceDescriptor());
- data.writeInt32(sid);
+ data.writeStrongBinder(handle);
remote()->transact(DESTROY_SURFACE, data, &reply);
return reply.readInt32();
}
@@ -89,21 +85,23 @@ status_t BnSurfaceComposerClient::onTransact(
switch(code) {
case CREATE_SURFACE: {
CHECK_INTERFACE(ISurfaceComposerClient, data, reply);
- surface_data_t params;
String8 name = data.readString8();
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, w, h,
- format, flags);
- params.writeToParcel(reply);
- reply->writeStrongBinder(s->asBinder());
+ sp<IBinder> handle;
+ sp<IGraphicBufferProducer> gbp;
+ status_t result = createSurface(name, w, h, format, flags,
+ &handle, &gbp);
+ reply->writeStrongBinder(handle);
+ reply->writeStrongBinder(gbp->asBinder());
+ reply->writeInt32(result);
return NO_ERROR;
} break;
case DESTROY_SURFACE: {
CHECK_INTERFACE(ISurfaceComposerClient, data, reply);
- reply->writeInt32( destroySurface( data.readInt32() ) );
+ reply->writeInt32( destroySurface( data.readStrongBinder() ) );
return NO_ERROR;
} break;
default:
@@ -111,20 +109,4 @@ status_t BnSurfaceComposerClient::onTransact(
}
}
-// ----------------------------------------------------------------------
-
-status_t ISurfaceComposerClient::surface_data_t::readFromParcel(const Parcel& parcel)
-{
- token = parcel.readInt32();
- identity = parcel.readInt32();
- return NO_ERROR;
-}
-
-status_t ISurfaceComposerClient::surface_data_t::writeToParcel(Parcel* parcel) const
-{
- parcel->writeInt32(token);
- parcel->writeInt32(identity);
- return NO_ERROR;
-}
-
}; // namespace android
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index e2604f8..acdbd77 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -17,36 +17,48 @@
#include <utils/Errors.h>
#include <binder/Parcel.h>
#include <gui/ISurfaceComposerClient.h>
-#include <gui/ISurfaceTexture.h>
+#include <gui/IGraphicBufferProducer.h>
#include <private/gui/LayerState.h>
namespace android {
status_t layer_state_t::write(Parcel& output) const
{
- status_t err;
-
- err = output.write(transparentRegion);
- if (err < NO_ERROR) return err;
-
- // NOTE: regions are at the end of the structure
- size_t size = sizeof(layer_state_t);
- size -= sizeof(transparentRegion);
- err = output.write(this, size);
- return err;
+ output.writeStrongBinder(surface);
+ output.writeInt32(what);
+ output.writeFloat(x);
+ output.writeFloat(y);
+ output.writeInt32(z);
+ output.writeInt32(w);
+ output.writeInt32(h);
+ output.writeInt32(layerStack);
+ output.writeFloat(alpha);
+ output.writeInt32(flags);
+ output.writeInt32(mask);
+ *reinterpret_cast<layer_state_t::matrix22_t *>(
+ output.writeInplace(sizeof(layer_state_t::matrix22_t))) = matrix;
+ output.write(crop);
+ output.write(transparentRegion);
+ return NO_ERROR;
}
status_t layer_state_t::read(const Parcel& input)
{
- status_t err;
-
- err = input.read(transparentRegion);
- if (err < NO_ERROR) return err;
-
- // NOTE: regions are at the end of the structure
- size_t size = sizeof(layer_state_t);
- size -= sizeof(transparentRegion);
- input.read(this, size);
+ surface = input.readStrongBinder();
+ what = input.readInt32();
+ x = input.readFloat();
+ y = input.readFloat();
+ z = input.readInt32();
+ w = input.readInt32();
+ h = input.readInt32();
+ layerStack = input.readInt32();
+ alpha = input.readFloat();
+ flags = input.readInt32();
+ mask = input.readInt32();
+ matrix = *reinterpret_cast<layer_state_t::matrix22_t const *>(
+ input.readInplace(sizeof(layer_state_t::matrix22_t)));
+ input.read(crop);
+ input.read(transparentRegion);
return NO_ERROR;
}
@@ -74,7 +86,7 @@ status_t DisplayState::write(Parcel& output) const {
status_t DisplayState::read(const Parcel& input) {
token = input.readStrongBinder();
- surface = interface_cast<ISurfaceTexture>(input.readStrongBinder());
+ surface = interface_cast<IGraphicBufferProducer>(input.readStrongBinder());
what = input.readInt32();
layerStack = input.readInt32();
orientation = input.readInt32();
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index 1745061..a616c1e 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007 The Android Open Source Project
+ * 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.
@@ -15,371 +15,820 @@
*/
#define LOG_TAG "Surface"
-
-#include <stdint.h>
-#include <errno.h>
-#include <sys/types.h>
-#include <sys/stat.h>
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+//#define LOG_NDEBUG 0
#include <android/native_window.h>
-#include <utils/CallStack.h>
-#include <utils/Errors.h>
-#include <utils/Log.h>
-#include <utils/threads.h>
+#include <binder/Parcel.h>
-#include <binder/IPCThreadState.h>
+#include <utils/Log.h>
+#include <utils/Trace.h>
-#include <ui/DisplayInfo.h>
-#include <ui/GraphicBuffer.h>
-#include <ui/Rect.h>
+#include <ui/Fence.h>
-#include <gui/ISurface.h>
#include <gui/ISurfaceComposer.h>
-#include <gui/Surface.h>
#include <gui/SurfaceComposerClient.h>
-#include <gui/SurfaceTextureClient.h>
+#include <gui/GLConsumer.h>
+#include <gui/Surface.h>
-namespace android {
+#include <private/gui/ComposerService.h>
-// ============================================================================
-// SurfaceControl
-// ============================================================================
+namespace android {
-SurfaceControl::SurfaceControl(
- const sp<SurfaceComposerClient>& client,
- const sp<ISurface>& surface,
- const ISurfaceComposerClient::surface_data_t& data)
- : mClient(client), mSurface(surface),
- mToken(data.token), mIdentity(data.identity)
+Surface::Surface(
+ const sp<IGraphicBufferProducer>& bufferProducer)
+ : mGraphicBufferProducer(bufferProducer)
{
+ // Initialize the ANativeWindow function pointers.
+ ANativeWindow::setSwapInterval = hook_setSwapInterval;
+ ANativeWindow::dequeueBuffer = hook_dequeueBuffer;
+ ANativeWindow::cancelBuffer = hook_cancelBuffer;
+ 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;
+
+ mReqWidth = 0;
+ mReqHeight = 0;
+ mReqFormat = 0;
+ mReqUsage = 0;
+ mTimestamp = NATIVE_WINDOW_TIMESTAMP_AUTO;
+ mCrop.clear();
+ mScalingMode = NATIVE_WINDOW_SCALING_MODE_FREEZE;
+ mTransform = 0;
+ mDefaultWidth = 0;
+ mDefaultHeight = 0;
+ mUserWidth = 0;
+ mUserHeight = 0;
+ mTransformHint = 0;
+ mConsumerRunningBehind = false;
+ mConnectedToCpu = false;
+}
+
+Surface::~Surface() {
+ if (mConnectedToCpu) {
+ Surface::disconnect(NATIVE_WINDOW_API_CPU);
+ }
}
-
-SurfaceControl::~SurfaceControl()
-{
- destroy();
+
+sp<IGraphicBufferProducer> Surface::getIGraphicBufferProducer() const {
+ return mGraphicBufferProducer;
}
-void SurfaceControl::destroy()
-{
- if (isValid()) {
- mClient->destroySurface(mToken);
- }
+int Surface::hook_setSwapInterval(ANativeWindow* window, int interval) {
+ Surface* c = getSelf(window);
+ return c->setSwapInterval(interval);
+}
- // clear all references and trigger an IPC now, to make sure things
- // happen without delay, since these resources are quite heavy.
- mClient.clear();
- mSurface.clear();
- IPCThreadState::self()->flushCommands();
+int Surface::hook_dequeueBuffer(ANativeWindow* window,
+ ANativeWindowBuffer** buffer, int* fenceFd) {
+ Surface* c = getSelf(window);
+ return c->dequeueBuffer(buffer, fenceFd);
}
-void SurfaceControl::clear()
-{
- // here, the window manager tells us explicitly that we should destroy
- // the surface's resource. Soon after this call, it will also release
- // its last reference (which will call the dtor); however, it is possible
- // that a client living in the same process still holds references which
- // would delay the call to the dtor -- that is why we need this explicit
- // "clear()" call.
- destroy();
+int Surface::hook_cancelBuffer(ANativeWindow* window,
+ ANativeWindowBuffer* buffer, int fenceFd) {
+ Surface* c = getSelf(window);
+ return c->cancelBuffer(buffer, fenceFd);
}
-bool SurfaceControl::isSameSurface(
- const sp<SurfaceControl>& lhs, const sp<SurfaceControl>& rhs)
-{
- if (lhs == 0 || rhs == 0)
- return false;
- 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;
- const sp<SurfaceComposerClient>& client(mClient);
- return client->setLayer(mToken, layer);
-}
-status_t SurfaceControl::setPosition(int32_t x, int32_t y) {
- status_t err = validate();
- if (err < 0) return err;
- const sp<SurfaceComposerClient>& client(mClient);
- return client->setPosition(mToken, x, y);
-}
-status_t SurfaceControl::setSize(uint32_t w, uint32_t h) {
- status_t err = validate();
- if (err < 0) return err;
- const sp<SurfaceComposerClient>& client(mClient);
- return client->setSize(mToken, w, h);
-}
-status_t SurfaceControl::hide() {
- status_t err = validate();
- if (err < 0) return err;
- const sp<SurfaceComposerClient>& client(mClient);
- return client->hide(mToken);
-}
-status_t SurfaceControl::show() {
- status_t err = validate();
- if (err < 0) return err;
- const sp<SurfaceComposerClient>& client(mClient);
- return client->show(mToken);
-}
-status_t SurfaceControl::setFlags(uint32_t flags, uint32_t mask) {
- status_t err = validate();
- if (err < 0) return err;
- const sp<SurfaceComposerClient>& client(mClient);
- return client->setFlags(mToken, flags, mask);
-}
-status_t SurfaceControl::setTransparentRegionHint(const Region& transparent) {
- status_t err = validate();
- if (err < 0) return err;
- const sp<SurfaceComposerClient>& client(mClient);
- return client->setTransparentRegionHint(mToken, transparent);
-}
-status_t SurfaceControl::setAlpha(float alpha) {
- status_t err = validate();
- if (err < 0) return err;
- const sp<SurfaceComposerClient>& client(mClient);
- return client->setAlpha(mToken, alpha);
-}
-status_t SurfaceControl::setMatrix(float dsdx, float dtdx, float dsdy, float dtdy) {
- status_t err = validate();
- if (err < 0) return err;
- const sp<SurfaceComposerClient>& client(mClient);
- return client->setMatrix(mToken, dsdx, dtdx, dsdy, dtdy);
-}
-status_t SurfaceControl::setCrop(const Rect& crop) {
- status_t err = validate();
- if (err < 0) return err;
- const sp<SurfaceComposerClient>& client(mClient);
- return client->setCrop(mToken, crop);
-}
-
-status_t SurfaceControl::validate() const
-{
- if (mToken<0 || mClient==0) {
- ALOGE("invalid token (%d, identity=%u) or client (%p)",
- mToken, mIdentity, mClient.get());
- return NO_INIT;
+int Surface::hook_queueBuffer(ANativeWindow* window,
+ ANativeWindowBuffer* buffer, int fenceFd) {
+ Surface* c = getSelf(window);
+ return c->queueBuffer(buffer, fenceFd);
+}
+
+int Surface::hook_dequeueBuffer_DEPRECATED(ANativeWindow* window,
+ ANativeWindowBuffer** buffer) {
+ Surface* c = getSelf(window);
+ ANativeWindowBuffer* buf;
+ int fenceFd = -1;
+ int result = c->dequeueBuffer(&buf, &fenceFd);
+ sp<Fence> fence(new Fence(fenceFd));
+ int waitResult = fence->waitForever("dequeueBuffer_DEPRECATED");
+ if (waitResult != OK) {
+ ALOGE("dequeueBuffer_DEPRECATED: Fence::wait returned an error: %d",
+ waitResult);
+ c->cancelBuffer(buf, -1);
+ return waitResult;
}
- return NO_ERROR;
+ *buffer = buf;
+ return result;
}
-status_t SurfaceControl::writeSurfaceToParcel(
- const sp<SurfaceControl>& control, Parcel* parcel)
-{
- sp<ISurface> sur;
- uint32_t identity = 0;
- if (SurfaceControl::isValid(control)) {
- sur = control->mSurface;
- identity = control->mIdentity;
+int Surface::hook_cancelBuffer_DEPRECATED(ANativeWindow* window,
+ ANativeWindowBuffer* buffer) {
+ Surface* c = getSelf(window);
+ return c->cancelBuffer(buffer, -1);
+}
+
+int Surface::hook_lockBuffer_DEPRECATED(ANativeWindow* window,
+ ANativeWindowBuffer* buffer) {
+ Surface* c = getSelf(window);
+ return c->lockBuffer_DEPRECATED(buffer);
+}
+
+int Surface::hook_queueBuffer_DEPRECATED(ANativeWindow* window,
+ ANativeWindowBuffer* buffer) {
+ Surface* c = getSelf(window);
+ return c->queueBuffer(buffer, -1);
+}
+
+int Surface::hook_query(const ANativeWindow* window,
+ int what, int* value) {
+ const Surface* c = getSelf(window);
+ return c->query(what, value);
+}
+
+int Surface::hook_perform(ANativeWindow* window, int operation, ...) {
+ va_list args;
+ va_start(args, operation);
+ Surface* c = getSelf(window);
+ return c->perform(operation, args);
+}
+
+int Surface::setSwapInterval(int interval) {
+ ATRACE_CALL();
+ // EGL specification states:
+ // interval is silently clamped to minimum and maximum implementation
+ // dependent values before being stored.
+ // Although we don't have to, we apply the same logic here.
+
+ if (interval < minSwapInterval)
+ interval = minSwapInterval;
+
+ if (interval > maxSwapInterval)
+ interval = maxSwapInterval;
+
+ status_t res = mGraphicBufferProducer->setSynchronousMode(interval ? true : false);
+
+ return res;
+}
+
+int Surface::dequeueBuffer(android_native_buffer_t** buffer,
+ int* fenceFd) {
+ ATRACE_CALL();
+ ALOGV("Surface::dequeueBuffer");
+ Mutex::Autolock lock(mMutex);
+ int buf = -1;
+ int reqW = mReqWidth ? mReqWidth : mUserWidth;
+ int reqH = mReqHeight ? mReqHeight : mUserHeight;
+ sp<Fence> fence;
+ status_t result = mGraphicBufferProducer->dequeueBuffer(&buf, &fence,
+ reqW, reqH, mReqFormat, mReqUsage);
+ if (result < 0) {
+ ALOGV("dequeueBuffer: IGraphicBufferProducer::dequeueBuffer(%d, %d, %d, %d)"
+ "failed: %d", mReqWidth, mReqHeight, mReqFormat, mReqUsage,
+ result);
+ return result;
}
- parcel->writeStrongBinder(sur!=0 ? sur->asBinder() : NULL);
- parcel->writeStrongBinder(NULL); // NULL ISurfaceTexture in this case.
- parcel->writeInt32(identity);
- return NO_ERROR;
+ sp<GraphicBuffer>& gbuf(mSlots[buf].buffer);
+ if (result & IGraphicBufferProducer::RELEASE_ALL_BUFFERS) {
+ freeAllBuffers();
+ }
+
+ if ((result & IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION) || gbuf == 0) {
+ result = mGraphicBufferProducer->requestBuffer(buf, &gbuf);
+ if (result != NO_ERROR) {
+ ALOGE("dequeueBuffer: IGraphicBufferProducer::requestBuffer failed: %d",
+ result);
+ return result;
+ }
+ }
+
+ if (fence->isValid()) {
+ *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;
}
-sp<Surface> SurfaceControl::getSurface() const
-{
- Mutex::Autolock _l(mLock);
- if (mSurfaceData == 0) {
- sp<SurfaceControl> surface_control(const_cast<SurfaceControl*>(this));
- mSurfaceData = new Surface(surface_control);
+int Surface::cancelBuffer(android_native_buffer_t* buffer,
+ int fenceFd) {
+ ATRACE_CALL();
+ ALOGV("Surface::cancelBuffer");
+ Mutex::Autolock lock(mMutex);
+ int i = getSlotFromBufferLocked(buffer);
+ if (i < 0) {
+ return i;
+ }
+ sp<Fence> fence(fenceFd >= 0 ? new Fence(fenceFd) : Fence::NO_FENCE);
+ mGraphicBufferProducer->cancelBuffer(i, fence);
+ return OK;
+}
+
+int Surface::getSlotFromBufferLocked(
+ android_native_buffer_t* buffer) const {
+ bool dumpedState = false;
+ for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
+ if (mSlots[i].buffer != NULL &&
+ mSlots[i].buffer->handle == buffer->handle) {
+ return i;
+ }
}
- return mSurfaceData;
+ ALOGE("getSlotFromBufferLocked: unknown buffer: %p", buffer->handle);
+ return BAD_VALUE;
}
-// ============================================================================
-// Surface
-// ============================================================================
+int Surface::lockBuffer_DEPRECATED(android_native_buffer_t* buffer) {
+ ALOGV("Surface::lockBuffer");
+ Mutex::Autolock lock(mMutex);
+ return OK;
+}
-// ---------------------------------------------------------------------------
+int Surface::queueBuffer(android_native_buffer_t* buffer, int fenceFd) {
+ ATRACE_CALL();
+ ALOGV("Surface::queueBuffer");
+ Mutex::Autolock lock(mMutex);
+ int64_t timestamp;
+ if (mTimestamp == NATIVE_WINDOW_TIMESTAMP_AUTO) {
+ timestamp = systemTime(SYSTEM_TIME_MONOTONIC);
+ ALOGV("Surface::queueBuffer making up timestamp: %.2f ms",
+ timestamp / 1000000.f);
+ } else {
+ timestamp = mTimestamp;
+ }
+ int i = getSlotFromBufferLocked(buffer);
+ if (i < 0) {
+ return i;
+ }
-Surface::Surface(const sp<SurfaceControl>& surface)
- : SurfaceTextureClient(),
- mSurface(surface->mSurface),
- mIdentity(surface->mIdentity)
-{
- sp<ISurfaceTexture> st;
- if (mSurface != NULL) {
- st = mSurface->getSurfaceTexture();
+
+ // 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) : Fence::NO_FENCE);
+ IGraphicBufferProducer::QueueBufferOutput output;
+ IGraphicBufferProducer::QueueBufferInput input(timestamp, crop, mScalingMode,
+ mTransform, fence);
+ status_t err = mGraphicBufferProducer->queueBuffer(i, input, &output);
+ if (err != OK) {
+ ALOGE("queueBuffer: error queuing buffer to SurfaceTexture, %d", err);
+ }
+ uint32_t numPendingBuffers = 0;
+ output.deflate(&mDefaultWidth, &mDefaultHeight, &mTransformHint,
+ &numPendingBuffers);
+
+ mConsumerRunningBehind = (numPendingBuffers >= 2);
+
+ return err;
+}
+
+int Surface::query(int what, int* value) const {
+ ATRACE_CALL();
+ ALOGV("Surface::query");
+ { // scope for the lock
+ Mutex::Autolock lock(mMutex);
+ switch (what) {
+ case NATIVE_WINDOW_FORMAT:
+ if (mReqFormat) {
+ *value = mReqFormat;
+ return NO_ERROR;
+ }
+ break;
+ case NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER: {
+ sp<ISurfaceComposer> composer(
+ ComposerService::getComposerService());
+ if (composer->authenticateSurfaceTexture(mGraphicBufferProducer)) {
+ *value = 1;
+ } else {
+ *value = 0;
+ }
+ return NO_ERROR;
+ }
+ case NATIVE_WINDOW_CONCRETE_TYPE:
+ *value = NATIVE_WINDOW_SURFACE;
+ return NO_ERROR;
+ case NATIVE_WINDOW_DEFAULT_WIDTH:
+ *value = mUserWidth ? mUserWidth : mDefaultWidth;
+ return NO_ERROR;
+ case NATIVE_WINDOW_DEFAULT_HEIGHT:
+ *value = mUserHeight ? mUserHeight : mDefaultHeight;
+ return NO_ERROR;
+ case NATIVE_WINDOW_TRANSFORM_HINT:
+ *value = mTransformHint;
+ return NO_ERROR;
+ case NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND: {
+ status_t err = NO_ERROR;
+ if (!mConsumerRunningBehind) {
+ *value = 0;
+ } else {
+ err = mGraphicBufferProducer->query(what, value);
+ if (err == NO_ERROR) {
+ mConsumerRunningBehind = *value;
+ }
+ }
+ return err;
+ }
+ }
}
- init(st);
+ return mGraphicBufferProducer->query(what, value);
}
-Surface::Surface(const Parcel& parcel, const sp<IBinder>& ref)
- : SurfaceTextureClient()
+int Surface::perform(int operation, va_list args)
{
- mSurface = interface_cast<ISurface>(ref);
- sp<IBinder> st_binder(parcel.readStrongBinder());
- sp<ISurfaceTexture> st;
- if (st_binder != NULL) {
- st = interface_cast<ISurfaceTexture>(st_binder);
- } else if (mSurface != NULL) {
- st = mSurface->getSurfaceTexture();
+ int res = NO_ERROR;
+ switch (operation) {
+ case NATIVE_WINDOW_CONNECT:
+ // deprecated. must return NO_ERROR.
+ break;
+ case NATIVE_WINDOW_DISCONNECT:
+ // deprecated. must return NO_ERROR.
+ break;
+ case NATIVE_WINDOW_SET_USAGE:
+ res = dispatchSetUsage(args);
+ break;
+ case NATIVE_WINDOW_SET_CROP:
+ res = dispatchSetCrop(args);
+ break;
+ case NATIVE_WINDOW_SET_BUFFER_COUNT:
+ res = dispatchSetBufferCount(args);
+ break;
+ case NATIVE_WINDOW_SET_BUFFERS_GEOMETRY:
+ res = dispatchSetBuffersGeometry(args);
+ break;
+ case NATIVE_WINDOW_SET_BUFFERS_TRANSFORM:
+ res = dispatchSetBuffersTransform(args);
+ break;
+ case NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP:
+ res = dispatchSetBuffersTimestamp(args);
+ break;
+ case NATIVE_WINDOW_SET_BUFFERS_DIMENSIONS:
+ res = dispatchSetBuffersDimensions(args);
+ break;
+ case NATIVE_WINDOW_SET_BUFFERS_USER_DIMENSIONS:
+ res = dispatchSetBuffersUserDimensions(args);
+ break;
+ case NATIVE_WINDOW_SET_BUFFERS_FORMAT:
+ res = dispatchSetBuffersFormat(args);
+ break;
+ case NATIVE_WINDOW_LOCK:
+ res = dispatchLock(args);
+ break;
+ case NATIVE_WINDOW_UNLOCK_AND_POST:
+ res = dispatchUnlockAndPost(args);
+ break;
+ case NATIVE_WINDOW_SET_SCALING_MODE:
+ res = dispatchSetScalingMode(args);
+ break;
+ case NATIVE_WINDOW_API_CONNECT:
+ res = dispatchConnect(args);
+ break;
+ case NATIVE_WINDOW_API_DISCONNECT:
+ res = dispatchDisconnect(args);
+ break;
+ default:
+ res = NAME_NOT_FOUND;
+ break;
}
+ return res;
+}
- mIdentity = parcel.readInt32();
- init(st);
+int Surface::dispatchConnect(va_list args) {
+ int api = va_arg(args, int);
+ return connect(api);
}
-Surface::Surface(const sp<ISurfaceTexture>& st)
- : SurfaceTextureClient(),
- mSurface(NULL),
- mIdentity(0)
-{
- init(st);
+int Surface::dispatchDisconnect(va_list args) {
+ int api = va_arg(args, int);
+ return disconnect(api);
}
-status_t Surface::writeToParcel(
- const sp<Surface>& surface, Parcel* parcel)
-{
- sp<ISurface> sur;
- sp<ISurfaceTexture> st;
- uint32_t identity = 0;
- if (Surface::isValid(surface)) {
- sur = surface->mSurface;
- st = surface->getISurfaceTexture();
- identity = surface->mIdentity;
- } else if (surface != 0 &&
- (surface->mSurface != NULL ||
- surface->getISurfaceTexture() != NULL)) {
- ALOGE("Parceling invalid surface with non-NULL ISurface/ISurfaceTexture as NULL: "
- "mSurface = %p, surfaceTexture = %p, mIdentity = %d, ",
- surface->mSurface.get(), surface->getISurfaceTexture().get(),
- surface->mIdentity);
+int Surface::dispatchSetUsage(va_list args) {
+ int usage = va_arg(args, int);
+ return setUsage(usage);
+}
+
+int Surface::dispatchSetCrop(va_list args) {
+ android_native_rect_t const* rect = va_arg(args, android_native_rect_t*);
+ return setCrop(reinterpret_cast<Rect const*>(rect));
+}
+
+int Surface::dispatchSetBufferCount(va_list args) {
+ size_t bufferCount = va_arg(args, size_t);
+ return setBufferCount(bufferCount);
+}
+
+int Surface::dispatchSetBuffersGeometry(va_list args) {
+ int w = va_arg(args, int);
+ int h = va_arg(args, int);
+ int f = va_arg(args, int);
+ int err = setBuffersDimensions(w, h);
+ if (err != 0) {
+ return err;
}
+ return setBuffersFormat(f);
+}
- parcel->writeStrongBinder(sur != NULL ? sur->asBinder() : NULL);
- parcel->writeStrongBinder(st != NULL ? st->asBinder() : NULL);
- parcel->writeInt32(identity);
- return NO_ERROR;
+int Surface::dispatchSetBuffersDimensions(va_list args) {
+ int w = va_arg(args, int);
+ int h = va_arg(args, int);
+ return setBuffersDimensions(w, h);
+}
+int Surface::dispatchSetBuffersUserDimensions(va_list args) {
+ int w = va_arg(args, int);
+ int h = va_arg(args, int);
+ return setBuffersUserDimensions(w, h);
}
-Mutex Surface::sCachedSurfacesLock;
-DefaultKeyedVector<wp<IBinder>, wp<Surface> > Surface::sCachedSurfaces;
+int Surface::dispatchSetBuffersFormat(va_list args) {
+ int f = va_arg(args, int);
+ return setBuffersFormat(f);
+}
-sp<Surface> Surface::readFromParcel(const Parcel& data) {
- Mutex::Autolock _l(sCachedSurfacesLock);
- sp<IBinder> binder(data.readStrongBinder());
- sp<Surface> surface = sCachedSurfaces.valueFor(binder).promote();
- if (surface == 0) {
- surface = new Surface(data, binder);
- sCachedSurfaces.add(binder, surface);
- } else {
- // The Surface was found in the cache, but we still should clear any
- // remaining data from the parcel.
- data.readStrongBinder(); // ISurfaceTexture
- data.readInt32(); // identity
+int Surface::dispatchSetScalingMode(va_list args) {
+ int m = va_arg(args, int);
+ return setScalingMode(m);
+}
+
+int Surface::dispatchSetBuffersTransform(va_list args) {
+ int transform = va_arg(args, int);
+ return setBuffersTransform(transform);
+}
+
+int Surface::dispatchSetBuffersTimestamp(va_list args) {
+ int64_t timestamp = va_arg(args, int64_t);
+ return setBuffersTimestamp(timestamp);
+}
+
+int Surface::dispatchLock(va_list args) {
+ ANativeWindow_Buffer* outBuffer = va_arg(args, ANativeWindow_Buffer*);
+ ARect* inOutDirtyBounds = va_arg(args, ARect*);
+ return lock(outBuffer, inOutDirtyBounds);
+}
+
+int Surface::dispatchUnlockAndPost(va_list args) {
+ return unlockAndPost();
+}
+
+
+int Surface::connect(int api) {
+ ATRACE_CALL();
+ ALOGV("Surface::connect");
+ Mutex::Autolock lock(mMutex);
+ IGraphicBufferProducer::QueueBufferOutput output;
+ int err = mGraphicBufferProducer->connect(api, &output);
+ if (err == NO_ERROR) {
+ uint32_t numPendingBuffers = 0;
+ output.deflate(&mDefaultWidth, &mDefaultHeight, &mTransformHint,
+ &numPendingBuffers);
+ mConsumerRunningBehind = (numPendingBuffers >= 2);
}
- if (surface->mSurface == NULL && surface->getISurfaceTexture() == NULL) {
- surface = 0;
+ if (!err && api == NATIVE_WINDOW_API_CPU) {
+ mConnectedToCpu = true;
}
- cleanCachedSurfacesLocked();
- return surface;
+ return err;
}
-// Remove the stale entries from the surface cache. This should only be called
-// with sCachedSurfacesLock held.
-void Surface::cleanCachedSurfacesLocked() {
- for (int i = sCachedSurfaces.size()-1; i >= 0; --i) {
- wp<Surface> s(sCachedSurfaces.valueAt(i));
- if (s == 0 || s.promote() == 0) {
- sCachedSurfaces.removeItemsAt(i);
+int Surface::disconnect(int api) {
+ ATRACE_CALL();
+ ALOGV("Surface::disconnect");
+ Mutex::Autolock lock(mMutex);
+ freeAllBuffers();
+ int err = mGraphicBufferProducer->disconnect(api);
+ if (!err) {
+ mReqFormat = 0;
+ mReqWidth = 0;
+ mReqHeight = 0;
+ mReqUsage = 0;
+ mCrop.clear();
+ mScalingMode = NATIVE_WINDOW_SCALING_MODE_FREEZE;
+ mTransform = 0;
+ if (api == NATIVE_WINDOW_API_CPU) {
+ mConnectedToCpu = false;
}
}
+ return err;
}
-void Surface::init(const sp<ISurfaceTexture>& surfaceTexture)
+int Surface::setUsage(uint32_t reqUsage)
{
- if (mSurface != NULL || surfaceTexture != NULL) {
- ALOGE_IF(surfaceTexture==0, "got a NULL ISurfaceTexture from ISurface");
- if (surfaceTexture != NULL) {
- setISurfaceTexture(surfaceTexture);
- setUsage(GraphicBuffer::USAGE_HW_RENDER);
- }
+ ALOGV("Surface::setUsage");
+ Mutex::Autolock lock(mMutex);
+ mReqUsage = reqUsage;
+ return OK;
+}
+
+int Surface::setCrop(Rect const* rect)
+{
+ ATRACE_CALL();
- // TODO: the display metrics should come from the display manager
- DisplayInfo 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;
+ Rect realRect;
+ if (rect == NULL || rect->isEmpty()) {
+ realRect.clear();
+ } else {
+ realRect = *rect;
}
+
+ ALOGV("Surface::setCrop rect=[%d %d %d %d]",
+ realRect.left, realRect.top, realRect.right, realRect.bottom);
+
+ Mutex::Autolock lock(mMutex);
+ mCrop = realRect;
+ return NO_ERROR;
}
-Surface::~Surface()
+int Surface::setBufferCount(int bufferCount)
{
- // clear all references and trigger an IPC now, to make sure things
- // happen without delay, since these resources are quite heavy.
- mSurface.clear();
- IPCThreadState::self()->flushCommands();
-}
+ ATRACE_CALL();
+ ALOGV("Surface::setBufferCount");
+ Mutex::Autolock lock(mMutex);
+
+ status_t err = mGraphicBufferProducer->setBufferCount(bufferCount);
+ ALOGE_IF(err, "IGraphicBufferProducer::setBufferCount(%d) returned %s",
+ bufferCount, strerror(-err));
-bool Surface::isValid() {
- return getISurfaceTexture() != NULL;
+ if (err == NO_ERROR) {
+ freeAllBuffers();
+ }
+
+ return err;
}
-sp<ISurfaceTexture> Surface::getSurfaceTexture() {
- return getISurfaceTexture();
+int Surface::setBuffersDimensions(int w, int h)
+{
+ ATRACE_CALL();
+ ALOGV("Surface::setBuffersDimensions");
+
+ if (w<0 || h<0)
+ return BAD_VALUE;
+
+ if ((w && !h) || (!w && h))
+ return BAD_VALUE;
+
+ Mutex::Autolock lock(mMutex);
+ mReqWidth = w;
+ mReqHeight = h;
+ return NO_ERROR;
}
-sp<IBinder> Surface::asBinder() const {
- return mSurface!=0 ? mSurface->asBinder() : 0;
+int Surface::setBuffersUserDimensions(int w, int h)
+{
+ ATRACE_CALL();
+ ALOGV("Surface::setBuffersUserDimensions");
+
+ if (w<0 || h<0)
+ return BAD_VALUE;
+
+ if ((w && !h) || (!w && h))
+ return BAD_VALUE;
+
+ Mutex::Autolock lock(mMutex);
+ mUserWidth = w;
+ mUserHeight = h;
+ return NO_ERROR;
}
-// ----------------------------------------------------------------------------
+int Surface::setBuffersFormat(int format)
+{
+ ALOGV("Surface::setBuffersFormat");
-int Surface::query(int what, int* value) const {
- switch (what) {
- case NATIVE_WINDOW_CONCRETE_TYPE:
- *value = NATIVE_WINDOW_SURFACE;
- return NO_ERROR;
+ if (format<0)
+ return BAD_VALUE;
+
+ Mutex::Autolock lock(mMutex);
+ mReqFormat = format;
+ return NO_ERROR;
+}
+
+int Surface::setScalingMode(int mode)
+{
+ ATRACE_CALL();
+ ALOGV("Surface::setScalingMode(%d)", mode);
+
+ switch (mode) {
+ case NATIVE_WINDOW_SCALING_MODE_FREEZE:
+ case NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW:
+ case NATIVE_WINDOW_SCALING_MODE_SCALE_CROP:
+ break;
+ default:
+ ALOGE("unknown scaling mode: %d", mode);
+ return BAD_VALUE;
}
- return SurfaceTextureClient::query(what, value);
+
+ Mutex::Autolock lock(mMutex);
+ mScalingMode = mode;
+ return NO_ERROR;
}
-// ----------------------------------------------------------------------------
+int Surface::setBuffersTransform(int transform)
+{
+ ATRACE_CALL();
+ ALOGV("Surface::setBuffersTransform");
+ Mutex::Autolock lock(mMutex);
+ mTransform = transform;
+ return NO_ERROR;
+}
-status_t Surface::lock(SurfaceInfo* other, Region* inOutDirtyRegion) {
- ANativeWindow_Buffer outBuffer;
+int Surface::setBuffersTimestamp(int64_t timestamp)
+{
+ ALOGV("Surface::setBuffersTimestamp");
+ Mutex::Autolock lock(mMutex);
+ mTimestamp = timestamp;
+ return NO_ERROR;
+}
- ARect temp;
- ARect* inOutDirtyBounds = NULL;
- if (inOutDirtyRegion) {
- temp = inOutDirtyRegion->getBounds();
- inOutDirtyBounds = &temp;
+void Surface::freeAllBuffers() {
+ for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
+ mSlots[i].buffer = 0;
}
+}
- status_t err = SurfaceTextureClient::lock(&outBuffer, inOutDirtyBounds);
+// ----------------------------------------------------------------------
+// the lock/unlock APIs must be used from the same thread
- if (err == NO_ERROR) {
- other->w = uint32_t(outBuffer.width);
- other->h = uint32_t(outBuffer.height);
- other->s = uint32_t(outBuffer.stride);
- other->usage = GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN;
- other->format = uint32_t(outBuffer.format);
- other->bits = outBuffer.bits;
+static status_t copyBlt(
+ const sp<GraphicBuffer>& dst,
+ const sp<GraphicBuffer>& src,
+ const Region& reg)
+{
+ // src and dst with, height and format must be identical. no verification
+ // is done here.
+ status_t err;
+ uint8_t const * src_bits = NULL;
+ err = src->lock(GRALLOC_USAGE_SW_READ_OFTEN, reg.bounds(), (void**)&src_bits);
+ ALOGE_IF(err, "error locking src buffer %s", strerror(-err));
+
+ uint8_t* dst_bits = NULL;
+ err = dst->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, reg.bounds(), (void**)&dst_bits);
+ ALOGE_IF(err, "error locking dst buffer %s", strerror(-err));
+
+ Region::const_iterator head(reg.begin());
+ Region::const_iterator tail(reg.end());
+ if (head != tail && src_bits && dst_bits) {
+ const size_t bpp = bytesPerPixel(src->format);
+ const size_t dbpr = dst->stride * bpp;
+ const size_t sbpr = src->stride * bpp;
+
+ while (head != tail) {
+ const Rect& r(*head++);
+ ssize_t h = r.height();
+ if (h <= 0) continue;
+ size_t size = r.width() * bpp;
+ uint8_t const * s = src_bits + (r.left + src->stride * r.top) * bpp;
+ uint8_t * d = dst_bits + (r.left + dst->stride * r.top) * bpp;
+ if (dbpr==sbpr && size==sbpr) {
+ size *= h;
+ h = 1;
+ }
+ do {
+ memcpy(d, s, size);
+ d += dbpr;
+ s += sbpr;
+ } while (--h > 0);
+ }
}
- if (inOutDirtyRegion) {
- inOutDirtyRegion->set( static_cast<Rect const&>(temp) );
+ if (src_bits)
+ src->unlock();
+
+ if (dst_bits)
+ dst->unlock();
+
+ return err;
+}
+
+// ----------------------------------------------------------------------------
+
+status_t Surface::lock(
+ ANativeWindow_Buffer* outBuffer, ARect* inOutDirtyBounds)
+{
+ if (mLockedBuffer != 0) {
+ ALOGE("Surface::lock failed, already locked");
+ return INVALID_OPERATION;
}
+ if (!mConnectedToCpu) {
+ int err = Surface::connect(NATIVE_WINDOW_API_CPU);
+ if (err) {
+ return err;
+ }
+ // we're intending to do software rendering from this point
+ setUsage(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN);
+ }
+
+ ANativeWindowBuffer* 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));
+ sp<Fence> fence(new Fence(fenceFd));
+
+ err = fence->waitForever("Surface::lock");
+ if (err != OK) {
+ ALOGE("Fence::wait failed (%s)", strerror(-err));
+ cancelBuffer(out, fenceFd);
+ return err;
+ }
+
+ 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);
+ }
+
+ // 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();
+ }
+ }
+
+
+ { // 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;
}
-status_t Surface::unlockAndPost() {
- return SurfaceTextureClient::unlockAndPost();
+status_t Surface::unlockAndPost()
+{
+ if (mLockedBuffer == 0) {
+ ALOGE("Surface::unlockAndPost failed, no locked buffer");
+ return INVALID_OPERATION;
+ }
+
+ status_t err = mLockedBuffer->unlock();
+ ALOGE_IF(err, "failed unlocking buffer (%p)", mLockedBuffer->handle);
+
+ err = queueBuffer(mLockedBuffer.get(), -1);
+ ALOGE_IF(err, "queueBuffer (handle=%p) failed (%s)",
+ mLockedBuffer->handle, strerror(-err));
+
+ mPostedBuffer = mLockedBuffer;
+ mLockedBuffer = 0;
+ return err;
}
-// ----------------------------------------------------------------------------
}; // namespace android
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 80dd6ee..f345df8 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -31,7 +31,8 @@
#include <ui/DisplayInfo.h>
-#include <gui/ISurface.h>
+#include <gui/CpuConsumer.h>
+#include <gui/IGraphicBufferProducer.h>
#include <gui/ISurfaceComposer.h>
#include <gui/ISurfaceComposerClient.h>
#include <gui/SurfaceComposerClient.h>
@@ -115,18 +116,20 @@ class Composer : public Singleton<Composer>
SortedVector<ComposerState> mComposerStates;
SortedVector<DisplayState > mDisplayStates;
uint32_t mForceSynchronous;
+ uint32_t mTransactionNestCount;
bool mAnimation;
Composer() : Singleton<Composer>(),
- mForceSynchronous(0),
+ mForceSynchronous(0), mTransactionNestCount(0),
mAnimation(false)
{ }
+ void openGlobalTransactionImpl();
void closeGlobalTransactionImpl(bool synchronous);
void setAnimationTransactionImpl();
layer_state_t* getLayerStateLocked(
- const sp<SurfaceComposerClient>& client, SurfaceID id);
+ const sp<SurfaceComposerClient>& client, const sp<IBinder>& id);
DisplayState& getDisplayStateLocked(const sp<IBinder>& token);
@@ -134,28 +137,29 @@ public:
sp<IBinder> createDisplay(const String8& displayName, bool secure);
sp<IBinder> getBuiltInDisplay(int32_t id);
- status_t setPosition(const sp<SurfaceComposerClient>& client, SurfaceID id,
+ status_t setPosition(const sp<SurfaceComposerClient>& client, const sp<IBinder>& id,
float x, float y);
- status_t setSize(const sp<SurfaceComposerClient>& client, SurfaceID id,
+ status_t setSize(const sp<SurfaceComposerClient>& client, const sp<IBinder>& id,
uint32_t w, uint32_t h);
- status_t setLayer(const sp<SurfaceComposerClient>& client, SurfaceID id,
+ status_t setLayer(const sp<SurfaceComposerClient>& client, const sp<IBinder>& id,
int32_t z);
- status_t setFlags(const sp<SurfaceComposerClient>& client, SurfaceID id,
+ status_t setFlags(const sp<SurfaceComposerClient>& client, const sp<IBinder>& id,
uint32_t flags, uint32_t mask);
status_t setTransparentRegionHint(
- const sp<SurfaceComposerClient>& client, SurfaceID id,
+ const sp<SurfaceComposerClient>& client, const sp<IBinder>& id,
const Region& transparentRegion);
- status_t setAlpha(const sp<SurfaceComposerClient>& client, SurfaceID id,
+ status_t setAlpha(const sp<SurfaceComposerClient>& client, const sp<IBinder>& id,
float alpha);
- status_t setMatrix(const sp<SurfaceComposerClient>& client, SurfaceID id,
+ status_t setMatrix(const sp<SurfaceComposerClient>& client, const sp<IBinder>& id,
float dsdx, float dtdx, float dsdy, float dtdy);
status_t setOrientation(int orientation);
- status_t setCrop(const sp<SurfaceComposerClient>& client, SurfaceID id,
+ status_t setCrop(const sp<SurfaceComposerClient>& client, const sp<IBinder>& id,
const Rect& crop);
status_t setLayerStack(const sp<SurfaceComposerClient>& client,
- SurfaceID id, uint32_t layerStack);
+ const sp<IBinder>& id, uint32_t layerStack);
- void setDisplaySurface(const sp<IBinder>& token, const sp<ISurfaceTexture>& surface);
+ void setDisplaySurface(const sp<IBinder>& token,
+ const sp<IGraphicBufferProducer>& bufferProducer);
void setDisplayLayerStack(const sp<IBinder>& token, uint32_t layerStack);
void setDisplayProjection(const sp<IBinder>& token,
uint32_t orientation,
@@ -166,6 +170,10 @@ public:
Composer::getInstance().setAnimationTransactionImpl();
}
+ static void openGlobalTransaction() {
+ Composer::getInstance().openGlobalTransactionImpl();
+ }
+
static void closeGlobalTransaction(bool synchronous) {
Composer::getInstance().closeGlobalTransactionImpl(synchronous);
}
@@ -184,6 +192,13 @@ sp<IBinder> Composer::getBuiltInDisplay(int32_t id) {
return ComposerService::getComposerService()->getBuiltInDisplay(id);
}
+void Composer::openGlobalTransactionImpl() {
+ { // scope for the lock
+ Mutex::Autolock _l(mLock);
+ mTransactionNestCount += 1;
+ }
+}
+
void Composer::closeGlobalTransactionImpl(bool synchronous) {
sp<ISurfaceComposer> sm(ComposerService::getComposerService());
@@ -193,13 +208,21 @@ void Composer::closeGlobalTransactionImpl(bool synchronous) {
{ // scope for the lock
Mutex::Autolock _l(mLock);
+ mForceSynchronous |= synchronous;
+ if (!mTransactionNestCount) {
+ ALOGW("At least one call to closeGlobalTransaction() was not matched by a prior "
+ "call to openGlobalTransaction().");
+ } else if (--mTransactionNestCount) {
+ return;
+ }
+
transaction = mComposerStates;
mComposerStates.clear();
displayTransaction = mDisplayStates;
mDisplayStates.clear();
- if (synchronous || mForceSynchronous) {
+ if (mForceSynchronous) {
flags |= ISurfaceComposer::eSynchronous;
}
if (mAnimation) {
@@ -219,7 +242,7 @@ void Composer::setAnimationTransactionImpl() {
}
layer_state_t* Composer::getLayerStateLocked(
- const sp<SurfaceComposerClient>& client, SurfaceID id) {
+ const sp<SurfaceComposerClient>& client, const sp<IBinder>& id) {
ComposerState s;
s.client = client->mClient;
@@ -236,7 +259,7 @@ layer_state_t* Composer::getLayerStateLocked(
}
status_t Composer::setPosition(const sp<SurfaceComposerClient>& client,
- SurfaceID id, float x, float y) {
+ const sp<IBinder>& id, float x, float y) {
Mutex::Autolock _l(mLock);
layer_state_t* s = getLayerStateLocked(client, id);
if (!s)
@@ -248,7 +271,7 @@ status_t Composer::setPosition(const sp<SurfaceComposerClient>& client,
}
status_t Composer::setSize(const sp<SurfaceComposerClient>& client,
- SurfaceID id, uint32_t w, uint32_t h) {
+ const sp<IBinder>& id, uint32_t w, uint32_t h) {
Mutex::Autolock _l(mLock);
layer_state_t* s = getLayerStateLocked(client, id);
if (!s)
@@ -264,7 +287,7 @@ status_t Composer::setSize(const sp<SurfaceComposerClient>& client,
}
status_t Composer::setLayer(const sp<SurfaceComposerClient>& client,
- SurfaceID id, int32_t z) {
+ const sp<IBinder>& id, int32_t z) {
Mutex::Autolock _l(mLock);
layer_state_t* s = getLayerStateLocked(client, id);
if (!s)
@@ -275,7 +298,7 @@ status_t Composer::setLayer(const sp<SurfaceComposerClient>& client,
}
status_t Composer::setFlags(const sp<SurfaceComposerClient>& client,
- SurfaceID id, uint32_t flags,
+ const sp<IBinder>& id, uint32_t flags,
uint32_t mask) {
Mutex::Autolock _l(mLock);
layer_state_t* s = getLayerStateLocked(client, id);
@@ -289,7 +312,7 @@ status_t Composer::setFlags(const sp<SurfaceComposerClient>& client,
}
status_t Composer::setTransparentRegionHint(
- const sp<SurfaceComposerClient>& client, SurfaceID id,
+ const sp<SurfaceComposerClient>& client, const sp<IBinder>& id,
const Region& transparentRegion) {
Mutex::Autolock _l(mLock);
layer_state_t* s = getLayerStateLocked(client, id);
@@ -301,7 +324,7 @@ status_t Composer::setTransparentRegionHint(
}
status_t Composer::setAlpha(const sp<SurfaceComposerClient>& client,
- SurfaceID id, float alpha) {
+ const sp<IBinder>& id, float alpha) {
Mutex::Autolock _l(mLock);
layer_state_t* s = getLayerStateLocked(client, id);
if (!s)
@@ -312,7 +335,7 @@ status_t Composer::setAlpha(const sp<SurfaceComposerClient>& client,
}
status_t Composer::setLayerStack(const sp<SurfaceComposerClient>& client,
- SurfaceID id, uint32_t layerStack) {
+ const sp<IBinder>& id, uint32_t layerStack) {
Mutex::Autolock _l(mLock);
layer_state_t* s = getLayerStateLocked(client, id);
if (!s)
@@ -323,7 +346,7 @@ status_t Composer::setLayerStack(const sp<SurfaceComposerClient>& client,
}
status_t Composer::setMatrix(const sp<SurfaceComposerClient>& client,
- SurfaceID id, float dsdx, float dtdx,
+ const sp<IBinder>& id, float dsdx, float dtdx,
float dsdy, float dtdy) {
Mutex::Autolock _l(mLock);
layer_state_t* s = getLayerStateLocked(client, id);
@@ -340,7 +363,7 @@ status_t Composer::setMatrix(const sp<SurfaceComposerClient>& client,
}
status_t Composer::setCrop(const sp<SurfaceComposerClient>& client,
- SurfaceID id, const Rect& crop) {
+ const sp<IBinder>& id, const Rect& crop) {
Mutex::Autolock _l(mLock);
layer_state_t* s = getLayerStateLocked(client, id);
if (!s)
@@ -365,10 +388,10 @@ DisplayState& Composer::getDisplayStateLocked(const sp<IBinder>& token) {
}
void Composer::setDisplaySurface(const sp<IBinder>& token,
- const sp<ISurfaceTexture>& surface) {
+ const sp<IGraphicBufferProducer>& bufferProducer) {
Mutex::Autolock _l(mLock);
DisplayState& s(getDisplayStateLocked(token));
- s.surface = surface;
+ s.surface = bufferProducer;
s.what |= DisplayState::eSurfaceChanged;
}
@@ -448,16 +471,18 @@ sp<SurfaceControl> SurfaceComposerClient::createSurface(
PixelFormat format,
uint32_t flags)
{
- sp<SurfaceControl> result;
+ sp<SurfaceControl> sur;
if (mStatus == NO_ERROR) {
- ISurfaceComposerClient::surface_data_t data;
- sp<ISurface> surface = mClient->createSurface(&data, name,
- w, h, format, flags);
- if (surface != 0) {
- result = new SurfaceControl(this, surface, data);
+ sp<IBinder> handle;
+ sp<IGraphicBufferProducer> gbp;
+ status_t err = mClient->createSurface(name, w, h, format, flags,
+ &handle, &gbp);
+ ALOGE_IF(err, "SurfaceComposerClient::createSurface error %s", strerror(-err));
+ if (err == NO_ERROR) {
+ sur = new SurfaceControl(this, handle, gbp);
}
}
- return result;
+ return sur;
}
sp<IBinder> SurfaceComposerClient::createDisplay(const String8& displayName,
@@ -469,7 +494,7 @@ sp<IBinder> SurfaceComposerClient::getBuiltInDisplay(int32_t id) {
return Composer::getInstance().getBuiltInDisplay(id);
}
-status_t SurfaceComposerClient::destroySurface(SurfaceID sid) {
+status_t SurfaceComposerClient::destroySurface(const sp<IBinder>& sid) {
if (mStatus != NO_ERROR)
return mStatus;
status_t err = mClient->destroySurface(sid);
@@ -483,7 +508,7 @@ inline Composer& SurfaceComposerClient::getComposer() {
// ----------------------------------------------------------------------------
void SurfaceComposerClient::openGlobalTransaction() {
- // Currently a no-op
+ Composer::openGlobalTransaction();
}
void SurfaceComposerClient::closeGlobalTransaction(bool synchronous) {
@@ -496,53 +521,53 @@ void SurfaceComposerClient::setAnimationTransaction() {
// ----------------------------------------------------------------------------
-status_t SurfaceComposerClient::setCrop(SurfaceID id, const Rect& crop) {
+status_t SurfaceComposerClient::setCrop(const sp<IBinder>& id, const Rect& crop) {
return getComposer().setCrop(this, id, crop);
}
-status_t SurfaceComposerClient::setPosition(SurfaceID id, float x, float y) {
+status_t SurfaceComposerClient::setPosition(const sp<IBinder>& id, float x, float y) {
return getComposer().setPosition(this, id, x, y);
}
-status_t SurfaceComposerClient::setSize(SurfaceID id, uint32_t w, uint32_t h) {
+status_t SurfaceComposerClient::setSize(const sp<IBinder>& id, uint32_t w, uint32_t h) {
return getComposer().setSize(this, id, w, h);
}
-status_t SurfaceComposerClient::setLayer(SurfaceID id, int32_t z) {
+status_t SurfaceComposerClient::setLayer(const sp<IBinder>& id, int32_t z) {
return getComposer().setLayer(this, id, z);
}
-status_t SurfaceComposerClient::hide(SurfaceID id) {
+status_t SurfaceComposerClient::hide(const sp<IBinder>& id) {
return getComposer().setFlags(this, id,
layer_state_t::eLayerHidden,
layer_state_t::eLayerHidden);
}
-status_t SurfaceComposerClient::show(SurfaceID id) {
+status_t SurfaceComposerClient::show(const sp<IBinder>& id) {
return getComposer().setFlags(this, id,
0,
layer_state_t::eLayerHidden);
}
-status_t SurfaceComposerClient::setFlags(SurfaceID id, uint32_t flags,
+status_t SurfaceComposerClient::setFlags(const sp<IBinder>& id, uint32_t flags,
uint32_t mask) {
return getComposer().setFlags(this, id, flags, mask);
}
-status_t SurfaceComposerClient::setTransparentRegionHint(SurfaceID id,
+status_t SurfaceComposerClient::setTransparentRegionHint(const sp<IBinder>& id,
const Region& transparentRegion) {
return getComposer().setTransparentRegionHint(this, id, transparentRegion);
}
-status_t SurfaceComposerClient::setAlpha(SurfaceID id, float alpha) {
+status_t SurfaceComposerClient::setAlpha(const sp<IBinder>& id, float alpha) {
return getComposer().setAlpha(this, id, alpha);
}
-status_t SurfaceComposerClient::setLayerStack(SurfaceID id, uint32_t layerStack) {
+status_t SurfaceComposerClient::setLayerStack(const sp<IBinder>& id, uint32_t layerStack) {
return getComposer().setLayerStack(this, id, layerStack);
}
-status_t SurfaceComposerClient::setMatrix(SurfaceID id, float dsdx, float dtdx,
+status_t SurfaceComposerClient::setMatrix(const sp<IBinder>& id, float dsdx, float dtdx,
float dsdy, float dtdy) {
return getComposer().setMatrix(this, id, dsdx, dtdx, dsdy, dtdy);
}
@@ -550,8 +575,8 @@ status_t SurfaceComposerClient::setMatrix(SurfaceID id, float dsdx, float dtdx,
// ----------------------------------------------------------------------------
void SurfaceComposerClient::setDisplaySurface(const sp<IBinder>& token,
- const sp<ISurfaceTexture>& surface) {
- Composer::getInstance().setDisplaySurface(token, surface);
+ const sp<IGraphicBufferProducer>& bufferProducer) {
+ Composer::getInstance().setDisplaySurface(token, bufferProducer);
}
void SurfaceComposerClient::setDisplayLayerStack(const sp<IBinder>& token,
@@ -585,27 +610,33 @@ void SurfaceComposerClient::unblankDisplay(const sp<IBinder>& token) {
// ----------------------------------------------------------------------------
+status_t ScreenshotClient::capture(
+ const sp<IBinder>& display,
+ const sp<IGraphicBufferProducer>& producer,
+ uint32_t reqWidth, uint32_t reqHeight,
+ uint32_t minLayerZ, uint32_t maxLayerZ) {
+ sp<ISurfaceComposer> s(ComposerService::getComposerService());
+ if (s == NULL) return NO_INIT;
+ return s->captureScreen(display, producer,
+ reqWidth, reqHeight, minLayerZ, maxLayerZ,
+ false);
+}
+
ScreenshotClient::ScreenshotClient()
- : mWidth(0), mHeight(0), mFormat(PIXEL_FORMAT_NONE) {
+ : mHaveBuffer(false) {
+ memset(&mBuffer, 0, sizeof(mBuffer));
}
-status_t ScreenshotClient::update(const sp<IBinder>& display) {
- sp<ISurfaceComposer> s(ComposerService::getComposerService());
- if (s == NULL) return NO_INIT;
- mHeap = 0;
- return s->captureScreen(display, &mHeap,
- &mWidth, &mHeight, &mFormat, 0, 0,
- 0, -1UL);
+ScreenshotClient::~ScreenshotClient() {
+ ScreenshotClient::release();
}
-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(display, &mHeap,
- &mWidth, &mHeight, &mFormat, reqWidth, reqHeight,
- 0, -1UL);
+sp<CpuConsumer> ScreenshotClient::getCpuConsumer() const {
+ if (mCpuConsumer == NULL) {
+ mCpuConsumer = new CpuConsumer(1);
+ mCpuConsumer->setName(String8("ScreenshotClient"));
+ }
+ return mCpuConsumer;
}
status_t ScreenshotClient::update(const sp<IBinder>& display,
@@ -613,38 +644,66 @@ status_t ScreenshotClient::update(const sp<IBinder>& display,
uint32_t minLayerZ, uint32_t maxLayerZ) {
sp<ISurfaceComposer> s(ComposerService::getComposerService());
if (s == NULL) return NO_INIT;
- mHeap = 0;
- return s->captureScreen(display, &mHeap,
- &mWidth, &mHeight, &mFormat, reqWidth, reqHeight,
- minLayerZ, maxLayerZ);
+ sp<CpuConsumer> cpuConsumer = getCpuConsumer();
+
+ if (mHaveBuffer) {
+ mCpuConsumer->unlockBuffer(mBuffer);
+ memset(&mBuffer, 0, sizeof(mBuffer));
+ mHaveBuffer = false;
+ }
+
+ status_t err = s->captureScreen(display,cpuConsumer->getBufferQueue(),
+ reqWidth, reqHeight, minLayerZ, maxLayerZ, true);
+
+ if (err == NO_ERROR) {
+ err = mCpuConsumer->lockNextBuffer(&mBuffer);
+ if (err == NO_ERROR) {
+ mHaveBuffer = true;
+ }
+ }
+ return err;
+}
+
+status_t ScreenshotClient::update(const sp<IBinder>& display) {
+ return ScreenshotClient::update(display, 0, 0, 0, -1UL);
+}
+
+status_t ScreenshotClient::update(const sp<IBinder>& display,
+ uint32_t reqWidth, uint32_t reqHeight) {
+ return ScreenshotClient::update(display, reqWidth, reqHeight, 0, -1UL);
}
void ScreenshotClient::release() {
- mHeap = 0;
+ if (mHaveBuffer) {
+ mCpuConsumer->unlockBuffer(mBuffer);
+ memset(&mBuffer, 0, sizeof(mBuffer));
+ mHaveBuffer = false;
+ }
+ mCpuConsumer.clear();
}
void const* ScreenshotClient::getPixels() const {
- return mHeap->getBase();
+ return mBuffer.data;
}
uint32_t ScreenshotClient::getWidth() const {
- return mWidth;
+ return mBuffer.width;
}
uint32_t ScreenshotClient::getHeight() const {
- return mHeight;
+ return mBuffer.height;
}
PixelFormat ScreenshotClient::getFormat() const {
- return mFormat;
+ return mBuffer.format;
}
uint32_t ScreenshotClient::getStride() const {
- return mWidth;
+ return mBuffer.stride;
}
size_t ScreenshotClient::getSize() const {
- return mHeap->getSize();
+ return mBuffer.stride * mBuffer.height * bytesPerPixel(mBuffer.format);
}
// ----------------------------------------------------------------------------
diff --git a/libs/gui/SurfaceControl.cpp b/libs/gui/SurfaceControl.cpp
new file mode 100644
index 0000000..f4e88f5
--- /dev/null
+++ b/libs/gui/SurfaceControl.cpp
@@ -0,0 +1,190 @@
+/*
+ * Copyright (C) 2007 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 "SurfaceControl"
+
+#include <stdint.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <android/native_window.h>
+
+#include <utils/CallStack.h>
+#include <utils/Errors.h>
+#include <utils/Log.h>
+#include <utils/threads.h>
+
+#include <binder/IPCThreadState.h>
+
+#include <ui/DisplayInfo.h>
+#include <ui/GraphicBuffer.h>
+#include <ui/Rect.h>
+
+#include <gui/ISurfaceComposer.h>
+#include <gui/Surface.h>
+#include <gui/SurfaceComposerClient.h>
+#include <gui/SurfaceControl.h>
+
+namespace android {
+
+// ============================================================================
+// SurfaceControl
+// ============================================================================
+
+SurfaceControl::SurfaceControl(
+ const sp<SurfaceComposerClient>& client,
+ const sp<IBinder>& handle,
+ const sp<IGraphicBufferProducer>& gbp)
+ : mClient(client), mHandle(handle), mGraphicBufferProducer(gbp)
+{
+}
+
+SurfaceControl::~SurfaceControl()
+{
+ destroy();
+}
+
+void SurfaceControl::destroy()
+{
+ if (isValid()) {
+ mClient->destroySurface(mHandle);
+ }
+ // clear all references and trigger an IPC now, to make sure things
+ // happen without delay, since these resources are quite heavy.
+ mClient.clear();
+ mHandle.clear();
+ mGraphicBufferProducer.clear();
+ IPCThreadState::self()->flushCommands();
+}
+
+void SurfaceControl::clear()
+{
+ // here, the window manager tells us explicitly that we should destroy
+ // the surface's resource. Soon after this call, it will also release
+ // its last reference (which will call the dtor); however, it is possible
+ // that a client living in the same process still holds references which
+ // would delay the call to the dtor -- that is why we need this explicit
+ // "clear()" call.
+ destroy();
+}
+
+bool SurfaceControl::isSameSurface(
+ const sp<SurfaceControl>& lhs, const sp<SurfaceControl>& rhs)
+{
+ if (lhs == 0 || rhs == 0)
+ return false;
+ return lhs->mHandle == rhs->mHandle;
+}
+
+status_t SurfaceControl::setLayerStack(int32_t layerStack) {
+ status_t err = validate();
+ if (err < 0) return err;
+ const sp<SurfaceComposerClient>& client(mClient);
+ return client->setLayerStack(mHandle, layerStack);
+}
+status_t SurfaceControl::setLayer(int32_t layer) {
+ status_t err = validate();
+ if (err < 0) return err;
+ const sp<SurfaceComposerClient>& client(mClient);
+ return client->setLayer(mHandle, layer);
+}
+status_t SurfaceControl::setPosition(float x, float y) {
+ status_t err = validate();
+ if (err < 0) return err;
+ const sp<SurfaceComposerClient>& client(mClient);
+ return client->setPosition(mHandle, x, y);
+}
+status_t SurfaceControl::setSize(uint32_t w, uint32_t h) {
+ status_t err = validate();
+ if (err < 0) return err;
+ const sp<SurfaceComposerClient>& client(mClient);
+ return client->setSize(mHandle, w, h);
+}
+status_t SurfaceControl::hide() {
+ status_t err = validate();
+ if (err < 0) return err;
+ const sp<SurfaceComposerClient>& client(mClient);
+ return client->hide(mHandle);
+}
+status_t SurfaceControl::show() {
+ status_t err = validate();
+ if (err < 0) return err;
+ const sp<SurfaceComposerClient>& client(mClient);
+ return client->show(mHandle);
+}
+status_t SurfaceControl::setFlags(uint32_t flags, uint32_t mask) {
+ status_t err = validate();
+ if (err < 0) return err;
+ const sp<SurfaceComposerClient>& client(mClient);
+ return client->setFlags(mHandle, flags, mask);
+}
+status_t SurfaceControl::setTransparentRegionHint(const Region& transparent) {
+ status_t err = validate();
+ if (err < 0) return err;
+ const sp<SurfaceComposerClient>& client(mClient);
+ return client->setTransparentRegionHint(mHandle, transparent);
+}
+status_t SurfaceControl::setAlpha(float alpha) {
+ status_t err = validate();
+ if (err < 0) return err;
+ const sp<SurfaceComposerClient>& client(mClient);
+ return client->setAlpha(mHandle, alpha);
+}
+status_t SurfaceControl::setMatrix(float dsdx, float dtdx, float dsdy, float dtdy) {
+ status_t err = validate();
+ if (err < 0) return err;
+ const sp<SurfaceComposerClient>& client(mClient);
+ return client->setMatrix(mHandle, dsdx, dtdx, dsdy, dtdy);
+}
+status_t SurfaceControl::setCrop(const Rect& crop) {
+ status_t err = validate();
+ if (err < 0) return err;
+ const sp<SurfaceComposerClient>& client(mClient);
+ return client->setCrop(mHandle, crop);
+}
+
+status_t SurfaceControl::validate() const
+{
+ if (mHandle==0 || mClient==0) {
+ ALOGE("invalid handle (%p) or client (%p)",
+ mHandle.get(), mClient.get());
+ return NO_INIT;
+ }
+ return NO_ERROR;
+}
+
+status_t SurfaceControl::writeSurfaceToParcel(
+ const sp<SurfaceControl>& control, Parcel* parcel)
+{
+ sp<IGraphicBufferProducer> bp;
+ if (control != NULL) {
+ bp = control->mGraphicBufferProducer;
+ }
+ return parcel->writeStrongBinder(bp->asBinder());
+}
+
+sp<Surface> SurfaceControl::getSurface() const
+{
+ Mutex::Autolock _l(mLock);
+ if (mSurfaceData == 0) {
+ mSurfaceData = new Surface(mGraphicBufferProducer);
+ }
+ return mSurfaceData;
+}
+
+// ----------------------------------------------------------------------------
+}; // namespace android
diff --git a/libs/gui/SurfaceTextureClient.cpp b/libs/gui/SurfaceTextureClient.cpp
deleted file mode 100644
index afdbf04..0000000
--- a/libs/gui/SurfaceTextureClient.cpp
+++ /dev/null
@@ -1,854 +0,0 @@
-/*
- * 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 "SurfaceTextureClient"
-#define ATRACE_TAG ATRACE_TAG_GRAPHICS
-//#define LOG_NDEBUG 0
-
-#include <android/native_window.h>
-
-#include <utils/Log.h>
-#include <utils/Trace.h>
-
-#include <ui/Fence.h>
-
-#include <gui/ISurfaceComposer.h>
-#include <gui/SurfaceComposerClient.h>
-#include <gui/SurfaceTexture.h>
-#include <gui/SurfaceTextureClient.h>
-
-#include <private/gui/ComposerService.h>
-
-namespace android {
-
-SurfaceTextureClient::SurfaceTextureClient(
- const sp<ISurfaceTexture>& surfaceTexture)
-{
- SurfaceTextureClient::init();
- SurfaceTextureClient::setISurfaceTexture(surfaceTexture);
-}
-
-// see SurfaceTextureClient.h
-SurfaceTextureClient::SurfaceTextureClient(const
- sp<SurfaceTexture>& surfaceTexture)
-{
- SurfaceTextureClient::init();
- SurfaceTextureClient::setISurfaceTexture(surfaceTexture->getBufferQueue());
-}
-
-SurfaceTextureClient::SurfaceTextureClient() {
- SurfaceTextureClient::init();
-}
-
-SurfaceTextureClient::~SurfaceTextureClient() {
- if (mConnectedToCpu) {
- SurfaceTextureClient::disconnect(NATIVE_WINDOW_API_CPU);
- }
-}
-
-void SurfaceTextureClient::init() {
- // Initialize the ANativeWindow function pointers.
- ANativeWindow::setSwapInterval = hook_setSwapInterval;
- ANativeWindow::dequeueBuffer = hook_dequeueBuffer;
- ANativeWindow::cancelBuffer = hook_cancelBuffer;
- 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;
-
- mReqWidth = 0;
- mReqHeight = 0;
- mReqFormat = 0;
- mReqUsage = 0;
- mTimestamp = NATIVE_WINDOW_TIMESTAMP_AUTO;
- mCrop.clear();
- mScalingMode = NATIVE_WINDOW_SCALING_MODE_FREEZE;
- mTransform = 0;
- mDefaultWidth = 0;
- mDefaultHeight = 0;
- mUserWidth = 0;
- mUserHeight = 0;
- mTransformHint = 0;
- mConsumerRunningBehind = false;
- mConnectedToCpu = false;
-}
-
-void SurfaceTextureClient::setISurfaceTexture(
- const sp<ISurfaceTexture>& surfaceTexture)
-{
- mSurfaceTexture = surfaceTexture;
-}
-
-sp<ISurfaceTexture> SurfaceTextureClient::getISurfaceTexture() const {
- return mSurfaceTexture;
-}
-
-int SurfaceTextureClient::hook_setSwapInterval(ANativeWindow* window, int interval) {
- SurfaceTextureClient* c = getSelf(window);
- return c->setSwapInterval(interval);
-}
-
-int SurfaceTextureClient::hook_dequeueBuffer(ANativeWindow* window,
- ANativeWindowBuffer** buffer, int* fenceFd) {
- SurfaceTextureClient* c = getSelf(window);
- 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, -1);
-}
-
-int SurfaceTextureClient::hook_lockBuffer_DEPRECATED(ANativeWindow* window,
- ANativeWindowBuffer* buffer) {
- SurfaceTextureClient* c = getSelf(window);
- return c->lockBuffer_DEPRECATED(buffer);
-}
-
-int SurfaceTextureClient::hook_queueBuffer_DEPRECATED(ANativeWindow* window,
- ANativeWindowBuffer* buffer) {
- SurfaceTextureClient* c = getSelf(window);
- return c->queueBuffer(buffer, -1);
-}
-
-int SurfaceTextureClient::hook_query(const ANativeWindow* window,
- int what, int* value) {
- const SurfaceTextureClient* c = getSelf(window);
- return c->query(what, value);
-}
-
-int SurfaceTextureClient::hook_perform(ANativeWindow* window, int operation, ...) {
- va_list args;
- va_start(args, operation);
- SurfaceTextureClient* c = getSelf(window);
- return c->perform(operation, args);
-}
-
-int SurfaceTextureClient::setSwapInterval(int interval) {
- ATRACE_CALL();
- // EGL specification states:
- // interval is silently clamped to minimum and maximum implementation
- // dependent values before being stored.
- // Although we don't have to, we apply the same logic here.
-
- if (interval < minSwapInterval)
- interval = minSwapInterval;
-
- if (interval > maxSwapInterval)
- interval = maxSwapInterval;
-
- status_t res = mSurfaceTexture->setSynchronousMode(interval ? true : false);
-
- return res;
-}
-
-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;
- 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)"
- "failed: %d", mReqWidth, mReqHeight, mReqFormat, mReqUsage,
- result);
- return result;
- }
- sp<GraphicBuffer>& gbuf(mSlots[buf].buffer);
- if (result & ISurfaceTexture::RELEASE_ALL_BUFFERS) {
- freeAllBuffers();
- }
-
- if ((result & ISurfaceTexture::BUFFER_NEEDS_REALLOCATION) || gbuf == 0) {
- result = mSurfaceTexture->requestBuffer(buf, &gbuf);
- if (result != NO_ERROR) {
- ALOGE("dequeueBuffer: ISurfaceTexture::requestBuffer failed: %d",
- result);
- 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 fenceFd) {
- ATRACE_CALL();
- ALOGV("SurfaceTextureClient::cancelBuffer");
- Mutex::Autolock lock(mMutex);
- int i = getSlotFromBufferLocked(buffer);
- if (i < 0) {
- return i;
- }
- sp<Fence> fence(fenceFd >= 0 ? new Fence(fenceFd) : NULL);
- mSurfaceTexture->cancelBuffer(i, fence);
- return OK;
-}
-
-int SurfaceTextureClient::getSlotFromBufferLocked(
- android_native_buffer_t* buffer) const {
- bool dumpedState = false;
- for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
- if (mSlots[i].buffer != NULL &&
- mSlots[i].buffer->handle == buffer->handle) {
- return i;
- }
- }
- ALOGE("getSlotFromBufferLocked: unknown buffer: %p", buffer->handle);
- return BAD_VALUE;
-}
-
-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 fenceFd) {
- ATRACE_CALL();
- ALOGV("SurfaceTextureClient::queueBuffer");
- Mutex::Autolock lock(mMutex);
- int64_t timestamp;
- if (mTimestamp == NATIVE_WINDOW_TIMESTAMP_AUTO) {
- timestamp = systemTime(SYSTEM_TIME_MONOTONIC);
- ALOGV("SurfaceTextureClient::queueBuffer making up timestamp: %.2f ms",
- timestamp / 1000000.f);
- } else {
- timestamp = mTimestamp;
- }
- int i = getSlotFromBufferLocked(buffer);
- if (i < 0) {
- 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, fence);
- status_t err = mSurfaceTexture->queueBuffer(i, input, &output);
- if (err != OK) {
- ALOGE("queueBuffer: error queuing buffer to SurfaceTexture, %d", err);
- }
- uint32_t numPendingBuffers = 0;
- output.deflate(&mDefaultWidth, &mDefaultHeight, &mTransformHint,
- &numPendingBuffers);
-
- mConsumerRunningBehind = (numPendingBuffers >= 2);
-
- return err;
-}
-
-int SurfaceTextureClient::query(int what, int* value) const {
- ATRACE_CALL();
- ALOGV("SurfaceTextureClient::query");
- { // scope for the lock
- Mutex::Autolock lock(mMutex);
- switch (what) {
- case NATIVE_WINDOW_FORMAT:
- if (mReqFormat) {
- *value = mReqFormat;
- return NO_ERROR;
- }
- break;
- case NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER: {
- sp<ISurfaceComposer> composer(
- ComposerService::getComposerService());
- if (composer->authenticateSurfaceTexture(mSurfaceTexture)) {
- *value = 1;
- } else {
- *value = 0;
- }
- return NO_ERROR;
- }
- case NATIVE_WINDOW_CONCRETE_TYPE:
- *value = NATIVE_WINDOW_SURFACE_TEXTURE_CLIENT;
- return NO_ERROR;
- case NATIVE_WINDOW_DEFAULT_WIDTH:
- *value = mUserWidth ? mUserWidth : mDefaultWidth;
- return NO_ERROR;
- case NATIVE_WINDOW_DEFAULT_HEIGHT:
- *value = mUserHeight ? mUserHeight : mDefaultHeight;
- return NO_ERROR;
- case NATIVE_WINDOW_TRANSFORM_HINT:
- *value = mTransformHint;
- return NO_ERROR;
- case NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND: {
- status_t err = NO_ERROR;
- if (!mConsumerRunningBehind) {
- *value = 0;
- } else {
- err = mSurfaceTexture->query(what, value);
- if (err == NO_ERROR) {
- mConsumerRunningBehind = *value;
- }
- }
- return err;
- }
- }
- }
- return mSurfaceTexture->query(what, value);
-}
-
-int SurfaceTextureClient::perform(int operation, va_list args)
-{
- int res = NO_ERROR;
- switch (operation) {
- case NATIVE_WINDOW_CONNECT:
- // deprecated. must return NO_ERROR.
- break;
- case NATIVE_WINDOW_DISCONNECT:
- // deprecated. must return NO_ERROR.
- break;
- case NATIVE_WINDOW_SET_USAGE:
- res = dispatchSetUsage(args);
- break;
- case NATIVE_WINDOW_SET_CROP:
- res = dispatchSetCrop(args);
- break;
- case NATIVE_WINDOW_SET_BUFFER_COUNT:
- res = dispatchSetBufferCount(args);
- break;
- case NATIVE_WINDOW_SET_BUFFERS_GEOMETRY:
- res = dispatchSetBuffersGeometry(args);
- break;
- case NATIVE_WINDOW_SET_BUFFERS_TRANSFORM:
- res = dispatchSetBuffersTransform(args);
- break;
- case NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP:
- res = dispatchSetBuffersTimestamp(args);
- break;
- case NATIVE_WINDOW_SET_BUFFERS_DIMENSIONS:
- res = dispatchSetBuffersDimensions(args);
- break;
- case NATIVE_WINDOW_SET_BUFFERS_USER_DIMENSIONS:
- res = dispatchSetBuffersUserDimensions(args);
- break;
- case NATIVE_WINDOW_SET_BUFFERS_FORMAT:
- res = dispatchSetBuffersFormat(args);
- break;
- case NATIVE_WINDOW_LOCK:
- res = dispatchLock(args);
- break;
- case NATIVE_WINDOW_UNLOCK_AND_POST:
- res = dispatchUnlockAndPost(args);
- break;
- case NATIVE_WINDOW_SET_SCALING_MODE:
- res = dispatchSetScalingMode(args);
- break;
- case NATIVE_WINDOW_API_CONNECT:
- res = dispatchConnect(args);
- break;
- case NATIVE_WINDOW_API_DISCONNECT:
- res = dispatchDisconnect(args);
- break;
- default:
- res = NAME_NOT_FOUND;
- break;
- }
- return res;
-}
-
-int SurfaceTextureClient::dispatchConnect(va_list args) {
- int api = va_arg(args, int);
- return connect(api);
-}
-
-int SurfaceTextureClient::dispatchDisconnect(va_list args) {
- int api = va_arg(args, int);
- return disconnect(api);
-}
-
-int SurfaceTextureClient::dispatchSetUsage(va_list args) {
- int usage = va_arg(args, int);
- return setUsage(usage);
-}
-
-int SurfaceTextureClient::dispatchSetCrop(va_list args) {
- android_native_rect_t const* rect = va_arg(args, android_native_rect_t*);
- return setCrop(reinterpret_cast<Rect const*>(rect));
-}
-
-int SurfaceTextureClient::dispatchSetBufferCount(va_list args) {
- size_t bufferCount = va_arg(args, size_t);
- return setBufferCount(bufferCount);
-}
-
-int SurfaceTextureClient::dispatchSetBuffersGeometry(va_list args) {
- int w = va_arg(args, int);
- int h = va_arg(args, int);
- int f = va_arg(args, int);
- int err = setBuffersDimensions(w, h);
- if (err != 0) {
- return err;
- }
- return setBuffersFormat(f);
-}
-
-int SurfaceTextureClient::dispatchSetBuffersDimensions(va_list args) {
- int w = va_arg(args, int);
- int h = va_arg(args, int);
- return setBuffersDimensions(w, h);
-}
-
-int SurfaceTextureClient::dispatchSetBuffersUserDimensions(va_list args) {
- int w = va_arg(args, int);
- int h = va_arg(args, int);
- return setBuffersUserDimensions(w, h);
-}
-
-int SurfaceTextureClient::dispatchSetBuffersFormat(va_list args) {
- int f = va_arg(args, int);
- return setBuffersFormat(f);
-}
-
-int SurfaceTextureClient::dispatchSetScalingMode(va_list args) {
- int m = va_arg(args, int);
- return setScalingMode(m);
-}
-
-int SurfaceTextureClient::dispatchSetBuffersTransform(va_list args) {
- int transform = va_arg(args, int);
- return setBuffersTransform(transform);
-}
-
-int SurfaceTextureClient::dispatchSetBuffersTimestamp(va_list args) {
- int64_t timestamp = va_arg(args, int64_t);
- return setBuffersTimestamp(timestamp);
-}
-
-int SurfaceTextureClient::dispatchLock(va_list args) {
- ANativeWindow_Buffer* outBuffer = va_arg(args, ANativeWindow_Buffer*);
- ARect* inOutDirtyBounds = va_arg(args, ARect*);
- return lock(outBuffer, inOutDirtyBounds);
-}
-
-int SurfaceTextureClient::dispatchUnlockAndPost(va_list args) {
- return unlockAndPost();
-}
-
-
-int SurfaceTextureClient::connect(int api) {
- ATRACE_CALL();
- ALOGV("SurfaceTextureClient::connect");
- Mutex::Autolock lock(mMutex);
- ISurfaceTexture::QueueBufferOutput output;
- int err = mSurfaceTexture->connect(api, &output);
- if (err == NO_ERROR) {
- uint32_t numPendingBuffers = 0;
- output.deflate(&mDefaultWidth, &mDefaultHeight, &mTransformHint,
- &numPendingBuffers);
- mConsumerRunningBehind = (numPendingBuffers >= 2);
- }
- if (!err && api == NATIVE_WINDOW_API_CPU) {
- mConnectedToCpu = true;
- }
- return err;
-}
-
-int SurfaceTextureClient::disconnect(int api) {
- ATRACE_CALL();
- ALOGV("SurfaceTextureClient::disconnect");
- Mutex::Autolock lock(mMutex);
- freeAllBuffers();
- int err = mSurfaceTexture->disconnect(api);
- if (!err) {
- mReqFormat = 0;
- mReqWidth = 0;
- mReqHeight = 0;
- mReqUsage = 0;
- mCrop.clear();
- mScalingMode = NATIVE_WINDOW_SCALING_MODE_FREEZE;
- mTransform = 0;
- if (api == NATIVE_WINDOW_API_CPU) {
- mConnectedToCpu = false;
- }
- }
- return err;
-}
-
-int SurfaceTextureClient::setUsage(uint32_t reqUsage)
-{
- ALOGV("SurfaceTextureClient::setUsage");
- Mutex::Autolock lock(mMutex);
- mReqUsage = reqUsage;
- return OK;
-}
-
-int SurfaceTextureClient::setCrop(Rect const* rect)
-{
- ATRACE_CALL();
-
- Rect realRect;
- if (rect == NULL || rect->isEmpty()) {
- realRect.clear();
- } else {
- realRect = *rect;
- }
-
- ALOGV("SurfaceTextureClient::setCrop rect=[%d %d %d %d]",
- realRect.left, realRect.top, realRect.right, realRect.bottom);
-
- Mutex::Autolock lock(mMutex);
- mCrop = realRect;
- return NO_ERROR;
-}
-
-int SurfaceTextureClient::setBufferCount(int bufferCount)
-{
- ATRACE_CALL();
- ALOGV("SurfaceTextureClient::setBufferCount");
- Mutex::Autolock lock(mMutex);
-
- status_t err = mSurfaceTexture->setBufferCount(bufferCount);
- ALOGE_IF(err, "ISurfaceTexture::setBufferCount(%d) returned %s",
- bufferCount, strerror(-err));
-
- if (err == NO_ERROR) {
- freeAllBuffers();
- }
-
- return err;
-}
-
-int SurfaceTextureClient::setBuffersDimensions(int w, int h)
-{
- ATRACE_CALL();
- ALOGV("SurfaceTextureClient::setBuffersDimensions");
-
- if (w<0 || h<0)
- return BAD_VALUE;
-
- if ((w && !h) || (!w && h))
- return BAD_VALUE;
-
- Mutex::Autolock lock(mMutex);
- mReqWidth = w;
- mReqHeight = h;
- return NO_ERROR;
-}
-
-int SurfaceTextureClient::setBuffersUserDimensions(int w, int h)
-{
- ATRACE_CALL();
- ALOGV("SurfaceTextureClient::setBuffersUserDimensions");
-
- if (w<0 || h<0)
- return BAD_VALUE;
-
- if ((w && !h) || (!w && h))
- return BAD_VALUE;
-
- Mutex::Autolock lock(mMutex);
- mUserWidth = w;
- mUserHeight = h;
- return NO_ERROR;
-}
-
-int SurfaceTextureClient::setBuffersFormat(int format)
-{
- ALOGV("SurfaceTextureClient::setBuffersFormat");
-
- if (format<0)
- return BAD_VALUE;
-
- Mutex::Autolock lock(mMutex);
- mReqFormat = format;
- return NO_ERROR;
-}
-
-int SurfaceTextureClient::setScalingMode(int mode)
-{
- ATRACE_CALL();
- ALOGV("SurfaceTextureClient::setScalingMode(%d)", mode);
-
- switch (mode) {
- case NATIVE_WINDOW_SCALING_MODE_FREEZE:
- case NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW:
- case NATIVE_WINDOW_SCALING_MODE_SCALE_CROP:
- break;
- default:
- ALOGE("unknown scaling mode: %d", mode);
- return BAD_VALUE;
- }
-
- Mutex::Autolock lock(mMutex);
- mScalingMode = mode;
- return NO_ERROR;
-}
-
-int SurfaceTextureClient::setBuffersTransform(int transform)
-{
- ATRACE_CALL();
- ALOGV("SurfaceTextureClient::setBuffersTransform");
- Mutex::Autolock lock(mMutex);
- mTransform = transform;
- return NO_ERROR;
-}
-
-int SurfaceTextureClient::setBuffersTimestamp(int64_t timestamp)
-{
- ALOGV("SurfaceTextureClient::setBuffersTimestamp");
- Mutex::Autolock lock(mMutex);
- mTimestamp = timestamp;
- return NO_ERROR;
-}
-
-void SurfaceTextureClient::freeAllBuffers() {
- for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
- mSlots[i].buffer = 0;
- }
-}
-
-// ----------------------------------------------------------------------
-// the lock/unlock APIs must be used from the same thread
-
-static status_t copyBlt(
- const sp<GraphicBuffer>& dst,
- const sp<GraphicBuffer>& src,
- const Region& reg)
-{
- // src and dst with, height and format must be identical. no verification
- // is done here.
- status_t err;
- uint8_t const * src_bits = NULL;
- err = src->lock(GRALLOC_USAGE_SW_READ_OFTEN, reg.bounds(), (void**)&src_bits);
- ALOGE_IF(err, "error locking src buffer %s", strerror(-err));
-
- uint8_t* dst_bits = NULL;
- err = dst->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, reg.bounds(), (void**)&dst_bits);
- ALOGE_IF(err, "error locking dst buffer %s", strerror(-err));
-
- Region::const_iterator head(reg.begin());
- Region::const_iterator tail(reg.end());
- if (head != tail && src_bits && dst_bits) {
- const size_t bpp = bytesPerPixel(src->format);
- const size_t dbpr = dst->stride * bpp;
- const size_t sbpr = src->stride * bpp;
-
- while (head != tail) {
- const Rect& r(*head++);
- ssize_t h = r.height();
- if (h <= 0) continue;
- size_t size = r.width() * bpp;
- uint8_t const * s = src_bits + (r.left + src->stride * r.top) * bpp;
- uint8_t * d = dst_bits + (r.left + dst->stride * r.top) * bpp;
- if (dbpr==sbpr && size==sbpr) {
- size *= h;
- h = 1;
- }
- do {
- memcpy(d, s, size);
- d += dbpr;
- s += sbpr;
- } while (--h > 0);
- }
- }
-
- if (src_bits)
- src->unlock();
-
- if (dst_bits)
- dst->unlock();
-
- return err;
-}
-
-// ----------------------------------------------------------------------------
-
-status_t SurfaceTextureClient::lock(
- ANativeWindow_Buffer* outBuffer, ARect* inOutDirtyBounds)
-{
- if (mLockedBuffer != 0) {
- ALOGE("Surface::lock failed, already locked");
- return INVALID_OPERATION;
- }
-
- if (!mConnectedToCpu) {
- int err = SurfaceTextureClient::connect(NATIVE_WINDOW_API_CPU);
- if (err) {
- return err;
- }
- // we're intending to do software rendering from this point
- setUsage(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN);
- }
-
- ANativeWindowBuffer* 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));
- sp<Fence> fence(new Fence(fenceFd));
-
- 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);
-
- Region newDirtyRegion;
- if (inOutDirtyBounds) {
- newDirtyRegion.set(static_cast<Rect const&>(*inOutDirtyBounds));
- newDirtyRegion.andSelf(bounds);
- } else {
- newDirtyRegion.set(bounds);
- }
-
- // 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();
- }
- }
-
-
- { // 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;
-}
-
-status_t SurfaceTextureClient::unlockAndPost()
-{
- if (mLockedBuffer == 0) {
- ALOGE("Surface::unlockAndPost failed, no locked buffer");
- return INVALID_OPERATION;
- }
-
- status_t err = mLockedBuffer->unlock();
- ALOGE_IF(err, "failed unlocking buffer (%p)", mLockedBuffer->handle);
-
- err = queueBuffer(mLockedBuffer.get(), -1);
- ALOGE_IF(err, "queueBuffer (handle=%p) failed (%s)",
- mLockedBuffer->handle, strerror(-err));
-
- mPostedBuffer = mLockedBuffer;
- mLockedBuffer = 0;
- return err;
-}
-
-}; // namespace android
diff --git a/libs/gui/SyncFeatures.cpp b/libs/gui/SyncFeatures.cpp
new file mode 100644
index 0000000..e5804a7
--- /dev/null
+++ b/libs/gui/SyncFeatures.cpp
@@ -0,0 +1,94 @@
+/*
+ ** Copyright 2013, 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 "GLConsumer"
+
+#define GL_GLEXT_PROTOTYPES
+#define EGL_EGLEXT_PROTOTYPES
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+
+#include <utils/Log.h>
+#include <utils/Singleton.h>
+#include <utils/String8.h>
+
+#include <private/gui/SyncFeatures.h>
+
+EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name);
+
+namespace android {
+
+ANDROID_SINGLETON_STATIC_INSTANCE(SyncFeatures);
+
+SyncFeatures::SyncFeatures() : Singleton<SyncFeatures>(),
+ mHasNativeFenceSync(false),
+ mHasFenceSync(false),
+ mHasWaitSync(false) {
+ EGLDisplay dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+ // This can only be called after EGL has been initialized; otherwise the
+ // check below will abort.
+ const char* exts = eglQueryStringImplementationANDROID(dpy, EGL_EXTENSIONS);
+ LOG_ALWAYS_FATAL_IF(exts == NULL, "eglQueryStringImplementationANDROID failed");
+ if (strstr(exts, "EGL_ANDROID_native_fence_sync")) {
+ // This makes GLConsumer 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.
+ mHasNativeFenceSync = true;
+ }
+ if (strstr(exts, "EGL_KHR_fence_sync")) {
+ mHasFenceSync = true;
+ }
+ if (strstr(exts, "EGL_KHR_wait_sync")) {
+ mHasWaitSync = true;
+ }
+ mString.append("[using:");
+ if (useNativeFenceSync()) {
+ mString.append(" EGL_ANDROID_native_fence_sync");
+ }
+ if (useFenceSync()) {
+ mString.append(" EGL_KHR_fence_sync");
+ }
+ if (useWaitSync()) {
+ mString.append(" EGL_KHR_wait_sync");
+ }
+ mString.append("]");
+}
+
+bool SyncFeatures::useNativeFenceSync() const {
+ // EGL_ANDROID_native_fence_sync is not compatible with using the
+ // EGL_KHR_fence_sync extension for the same purpose.
+ return mHasNativeFenceSync;
+}
+bool SyncFeatures::useFenceSync() const {
+#ifdef DONT_USE_FENCE_SYNC
+ // on some devices it's better to not use EGL_KHR_fence_sync
+ // even if they have it
+ return false;
+#endif
+ // currently we shall only attempt to use EGL_KHR_fence_sync if
+ // USE_FENCE_SYNC is set in our makefile
+ return !mHasNativeFenceSync && mHasFenceSync;
+}
+bool SyncFeatures::useWaitSync() const {
+ return (useNativeFenceSync() || useFenceSync()) && mHasWaitSync;
+}
+
+String8 SyncFeatures::toString() const {
+ return mString;
+}
+
+} // namespace android
diff --git a/libs/gui/tests/Android.mk b/libs/gui/tests/Android.mk
index 4a6f74f..21bd875 100644
--- a/libs/gui/tests/Android.mk
+++ b/libs/gui/tests/Android.mk
@@ -15,6 +15,7 @@ LOCAL_SRC_FILES := \
LOCAL_SHARED_LIBRARIES := \
libEGL \
+ libGLESv1_CM \
libGLESv2 \
libbinder \
libcutils \
diff --git a/libs/gui/tests/BufferQueue_test.cpp b/libs/gui/tests/BufferQueue_test.cpp
index 817abb4..62d215b 100644
--- a/libs/gui/tests/BufferQueue_test.cpp
+++ b/libs/gui/tests/BufferQueue_test.cpp
@@ -63,28 +63,28 @@ struct DummyConsumer : public BufferQueue::ConsumerListener {
TEST_F(BufferQueueTest, AcquireBuffer_ExceedsMaxAcquireCount_Fails) {
sp<DummyConsumer> dc(new DummyConsumer);
mBQ->consumerConnect(dc);
- ISurfaceTexture::QueueBufferOutput qbo;
+ IGraphicBufferProducer::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);
+ IGraphicBufferProducer::QueueBufferInput qbi(0, Rect(0, 0, 1, 1),
+ NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, Fence::NO_FENCE);
BufferQueue::BufferItem item;
for (int i = 0; i < 2; i++) {
- ASSERT_EQ(ISurfaceTexture::BUFFER_NEEDS_REALLOCATION,
- mBQ->dequeueBuffer(&slot, fence, 1, 1, 0,
+ ASSERT_EQ(IGraphicBufferProducer::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,
+ ASSERT_EQ(IGraphicBufferProducer::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));
diff --git a/libs/gui/tests/CpuConsumer_test.cpp b/libs/gui/tests/CpuConsumer_test.cpp
index 72a36bf..73fdd04 100644
--- a/libs/gui/tests/CpuConsumer_test.cpp
+++ b/libs/gui/tests/CpuConsumer_test.cpp
@@ -26,7 +26,7 @@
#include <gtest/gtest.h>
#include <gui/CpuConsumer.h>
-#include <gui/SurfaceTextureClient.h>
+#include <gui/Surface.h>
#include <ui/GraphicBuffer.h>
#include <utils/String8.h>
#include <utils/Thread.h>
@@ -35,6 +35,11 @@
#include <ui/FramebufferNativeWindow.h>
+#define CPU_CONSUMER_TEST_FORMAT_RAW 0
+#define CPU_CONSUMER_TEST_FORMAT_Y8 0
+#define CPU_CONSUMER_TEST_FORMAT_Y16 0
+#define CPU_CONSUMER_TEST_FORMAT_RGBA_8888 1
+
namespace android {
struct CpuConsumerTestParams {
@@ -64,7 +69,7 @@ protected:
mCC = new CpuConsumer(params.maxLockedBuffers);
String8 name("CpuConsumer_Under_Test");
mCC->setName(name);
- mSTC = new SurfaceTextureClient(mCC->getProducerInterface());
+ mSTC = new Surface(mCC->getProducerInterface());
mANW = mSTC;
}
@@ -149,7 +154,7 @@ protected:
};
sp<CpuConsumer> mCC;
- sp<SurfaceTextureClient> mSTC;
+ sp<Surface> mSTC;
sp<ANativeWindow> mANW;
};
@@ -157,7 +162,7 @@ protected:
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) {
+ uint32_t x, uint32_t y, uint32_t r, uint32_t g=0, uint32_t b=0) {
// Ignores components that don't exist for given pixel
switch(buf.format) {
case HAL_PIXEL_FORMAT_RAW_SENSOR: {
@@ -179,6 +184,31 @@ void checkPixel(const CpuConsumer::LockedBuffer &buf,
}
break;
}
+ // ignores g,b
+ case HAL_PIXEL_FORMAT_Y8: {
+ uint8_t *bPtr = (uint8_t*)buf.data;
+ bPtr += y * buf.stride + x;
+ EXPECT_EQ(r, *bPtr) << "at x = " << x << " y = " << y;
+ break;
+ }
+ // ignores g,b
+ case HAL_PIXEL_FORMAT_Y16: {
+ // stride is in pixels, not in bytes
+ uint16_t *bPtr = ((uint16_t*)buf.data) + y * buf.stride + x;
+
+ EXPECT_EQ(r, *bPtr) << "at x = " << x << " y = " << y;
+ break;
+ }
+ case HAL_PIXEL_FORMAT_RGBA_8888: {
+ const int bytesPerPixel = 4;
+ uint8_t *bPtr = (uint8_t*)buf.data;
+ bPtr += (y * buf.stride + x) * bytesPerPixel;
+
+ EXPECT_EQ(r, bPtr[0]) << "at x = " << x << " y = " << y;
+ EXPECT_EQ(g, bPtr[1]) << "at x = " << x << " y = " << y;
+ EXPECT_EQ(b, bPtr[2]) << "at x = " << x << " y = " << y;
+ break;
+ }
default: {
ADD_FAILURE() << "Unknown format for check:" << buf.format;
break;
@@ -189,6 +219,61 @@ void checkPixel(const CpuConsumer::LockedBuffer &buf,
// Fill a YV12 buffer with a multi-colored checkerboard pattern
void fillYV12Buffer(uint8_t* buf, int w, int h, int stride);
+// Fill a Y8/Y16 buffer with a multi-colored checkerboard pattern
+template <typename T> // T == uint8_t or uint16_t
+void fillGreyscaleBuffer(T* buf, int w, int h, int stride, int bpp) {
+ const int blockWidth = w > 16 ? w / 16 : 1;
+ const int blockHeight = h > 16 ? h / 16 : 1;
+ const int yuvTexOffsetY = 0;
+
+ ASSERT_TRUE(bpp == 8 || bpp == 16);
+ ASSERT_TRUE(sizeof(T)*8 == bpp);
+
+ // stride is in pixels, not in bytes
+ int yuvTexStrideY = stride;
+ for (int x = 0; x < w; x++) {
+ for (int y = 0; y < h; y++) {
+ int parityX = (x / blockWidth) & 1;
+ int parityY = (y / blockHeight) & 1;
+ T intensity = (parityX ^ parityY) ? 63 : 191;
+ buf[yuvTexOffsetY + (y * yuvTexStrideY) + x] = intensity;
+ }
+ }
+}
+
+inline uint8_t chooseColorRgba8888(int blockX, int blockY, uint8_t channel) {
+ const int colorVariations = 3;
+ uint8_t color = ((blockX % colorVariations) + (blockY % colorVariations))
+ % (colorVariations) == channel ? 191: 63;
+
+ return color;
+}
+
+// Fill a RGBA8888 buffer with a multi-colored checkerboard pattern
+void fillRgba8888Buffer(uint8_t* buf, int w, int h, int stride)
+{
+ const int blockWidth = w > 16 ? w / 16 : 1;
+ const int blockHeight = h > 16 ? h / 16 : 1;
+ const int bytesPerPixel = 4;
+
+ // stride is in pixels, not in bytes
+ for (int x = 0; x < w; ++x) {
+ for (int y = 0; y < h; ++y) {
+ int blockX = (x / blockWidth);
+ int blockY = (y / blockHeight);
+
+ uint8_t r = chooseColorRgba8888(blockX, blockY, 0);
+ uint8_t g = chooseColorRgba8888(blockX, blockY, 1);
+ uint8_t b = chooseColorRgba8888(blockX, blockY, 2);
+
+ buf[(y*stride + x)*bytesPerPixel + 0] = r;
+ buf[(y*stride + x)*bytesPerPixel + 1] = g;
+ buf[(y*stride + x)*bytesPerPixel + 2] = b;
+ buf[(y*stride + x)*bytesPerPixel + 3] = 255;
+ }
+ }
+}
+
// 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]
@@ -217,6 +302,89 @@ void fillBayerRawBuffer(uint8_t* buf, int w, int h, int stride) {
}
+template<typename T> // uint8_t or uint16_t
+void checkGreyscaleBuffer(const CpuConsumer::LockedBuffer &buf) {
+ uint32_t w = buf.width;
+ uint32_t h = buf.height;
+ const int blockWidth = w > 16 ? w / 16 : 1;
+ const int blockHeight = h > 16 ? h / 16 : 1;
+ const int blockRows = h / blockHeight;
+ const int blockCols = w / blockWidth;
+
+ // Top-left square is bright
+ checkPixel(buf, 0, 0, 191);
+ checkPixel(buf, 1, 0, 191);
+ checkPixel(buf, 0, 1, 191);
+ checkPixel(buf, 1, 1, 191);
+
+ // One-right square is dark
+ checkPixel(buf, blockWidth, 0, 63);
+ checkPixel(buf, blockWidth + 1, 0, 63);
+ checkPixel(buf, blockWidth, 1, 63);
+ checkPixel(buf, blockWidth + 1, 1, 63);
+
+ // One-down square is dark
+ checkPixel(buf, 0, blockHeight, 63);
+ checkPixel(buf, 1, blockHeight, 63);
+ checkPixel(buf, 0, blockHeight + 1, 63);
+ checkPixel(buf, 1, blockHeight + 1, 63);
+
+ // One-diag square is bright
+ checkPixel(buf, blockWidth, blockHeight, 191);
+ checkPixel(buf, blockWidth + 1, blockHeight, 191);
+ checkPixel(buf, blockWidth, blockHeight + 1, 191);
+ checkPixel(buf, blockWidth + 1, blockHeight + 1, 191);
+
+ // Test bottom-right pixel
+ const int maxBlockX = ((w-1 + (blockWidth-1)) / blockWidth) & 0x1;
+ const int maxBlockY = ((h-1 + (blockHeight-1)) / blockHeight) & 0x1;
+ uint32_t pixelValue = ((maxBlockX % 2) == (maxBlockY % 2)) ? 191 : 63;
+ checkPixel(buf, w-1, h-1, pixelValue);
+}
+
+void checkRgba8888Buffer(const CpuConsumer::LockedBuffer &buf) {
+ uint32_t w = buf.width;
+ uint32_t h = buf.height;
+ const int blockWidth = w > 16 ? w / 16 : 1;
+ const int blockHeight = h > 16 ? h / 16 : 1;
+ const int blockRows = h / blockHeight;
+ const int blockCols = w / blockWidth;
+
+ // Top-left square is bright red
+ checkPixel(buf, 0, 0, 191, 63, 63);
+ checkPixel(buf, 1, 0, 191, 63, 63);
+ checkPixel(buf, 0, 1, 191, 63, 63);
+ checkPixel(buf, 1, 1, 191, 63, 63);
+
+ // One-right square is bright green
+ checkPixel(buf, blockWidth, 0, 63, 191, 63);
+ checkPixel(buf, blockWidth + 1, 0, 63, 191, 63);
+ checkPixel(buf, blockWidth, 1, 63, 191, 63);
+ checkPixel(buf, blockWidth + 1, 1, 63, 191, 63);
+
+ // One-down square is bright green
+ checkPixel(buf, 0, blockHeight, 63, 191, 63);
+ checkPixel(buf, 1, blockHeight, 63, 191, 63);
+ checkPixel(buf, 0, blockHeight + 1, 63, 191, 63);
+ checkPixel(buf, 1, blockHeight + 1, 63, 191, 63);
+
+ // One-diag square is bright blue
+ checkPixel(buf, blockWidth, blockHeight, 63, 63, 191);
+ checkPixel(buf, blockWidth + 1, blockHeight, 63, 63, 191);
+ checkPixel(buf, blockWidth, blockHeight + 1, 63, 63, 191);
+ checkPixel(buf, blockWidth + 1, blockHeight + 1, 63, 63, 191);
+
+ // Test bottom-right pixel
+ {
+ const int maxBlockX = ((w-1) / blockWidth);
+ const int maxBlockY = ((h-1) / blockHeight);
+ uint8_t r = chooseColorRgba8888(maxBlockX, maxBlockY, 0);
+ uint8_t g = chooseColorRgba8888(maxBlockX, maxBlockY, 1);
+ uint8_t b = chooseColorRgba8888(maxBlockX, maxBlockY, 2);
+ checkPixel(buf, w-1, h-1, r, g, b);
+ }
+}
+
void checkBayerRawBuffer(const CpuConsumer::LockedBuffer &buf) {
uint32_t w = buf.width;
uint32_t h = buf.height;
@@ -258,6 +426,23 @@ void checkBayerRawBuffer(const CpuConsumer::LockedBuffer &buf) {
checkPixel(buf, w-1, h-1, maxR, maxG, maxB);
}
+void checkAnyBuffer(const CpuConsumer::LockedBuffer &buf, int format) {
+ switch (format) {
+ case HAL_PIXEL_FORMAT_RAW_SENSOR:
+ checkBayerRawBuffer(buf);
+ break;
+ case HAL_PIXEL_FORMAT_Y8:
+ checkGreyscaleBuffer<uint8_t>(buf);
+ break;
+ case HAL_PIXEL_FORMAT_Y16:
+ checkGreyscaleBuffer<uint16_t>(buf);
+ break;
+ case HAL_PIXEL_FORMAT_RGBA_8888:
+ checkRgba8888Buffer(buf);
+ break;
+ }
+}
+
void fillYV12BufferRect(uint8_t* buf, int w, int h, int stride,
const android_native_rect_t& rect);
@@ -322,6 +507,18 @@ void produceOneFrame(const sp<ANativeWindow>& anw,
case HAL_PIXEL_FORMAT_RAW_SENSOR:
fillBayerRawBuffer(img, params.width, params.height, buf->getStride());
break;
+ case HAL_PIXEL_FORMAT_Y8:
+ fillGreyscaleBuffer<uint8_t>(img, params.width, params.height,
+ buf->getStride(), /*bpp*/8);
+ break;
+ case HAL_PIXEL_FORMAT_Y16:
+ fillGreyscaleBuffer<uint16_t>((uint16_t*)img, params.width,
+ params.height, buf->getStride(),
+ /*bpp*/16);
+ break;
+ case HAL_PIXEL_FORMAT_RGBA_8888:
+ fillRgba8888Buffer(img, params.width, params.height, buf->getStride());
+ break;
default:
FAIL() << "Unknown pixel format under test!";
break;
@@ -341,7 +538,7 @@ void produceOneFrame(const sp<ANativeWindow>& anw,
// This test is disabled because the HAL_PIXEL_FORMAT_RAW_SENSOR format is not
// supported on all devices.
-TEST_P(CpuConsumerTest, DISABLED_FromCpuSingle) {
+TEST_P(CpuConsumerTest, FromCpuSingle) {
status_t err;
CpuConsumerTestParams params = GetParam();
@@ -369,13 +566,13 @@ TEST_P(CpuConsumerTest, DISABLED_FromCpuSingle) {
EXPECT_EQ(stride, b.stride);
EXPECT_EQ(time, b.timestamp);
- checkBayerRawBuffer(b);
+ checkAnyBuffer(b, GetParam().format);
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) {
+TEST_P(CpuConsumerTest, FromCpuManyInQueue) {
status_t err;
CpuConsumerTestParams params = GetParam();
@@ -410,7 +607,7 @@ TEST_P(CpuConsumerTest, DISABLED_FromCpuManyInQueue) {
EXPECT_EQ(stride[i], b.stride);
EXPECT_EQ(time[i], b.timestamp);
- checkBayerRawBuffer(b);
+ checkAnyBuffer(b, GetParam().format);
mCC->unlockBuffer(b);
}
@@ -418,7 +615,7 @@ TEST_P(CpuConsumerTest, DISABLED_FromCpuManyInQueue) {
// This test is disabled because the HAL_PIXEL_FORMAT_RAW_SENSOR format is not
// supported on all devices.
-TEST_P(CpuConsumerTest, DISABLED_FromCpuLockMax) {
+TEST_P(CpuConsumerTest, FromCpuLockMax) {
status_t err;
CpuConsumerTestParams params = GetParam();
@@ -452,7 +649,7 @@ TEST_P(CpuConsumerTest, DISABLED_FromCpuLockMax) {
EXPECT_EQ(stride, b[i].stride);
EXPECT_EQ(time, b[i].timestamp);
- checkBayerRawBuffer(b[i]);
+ checkAnyBuffer(b[i], GetParam().format);
}
ALOGV("Locking frame %d (too many)", params.maxLockedBuffers);
@@ -475,7 +672,7 @@ TEST_P(CpuConsumerTest, DISABLED_FromCpuLockMax) {
EXPECT_EQ(stride, bTooMuch.stride);
EXPECT_EQ(time, bTooMuch.timestamp);
- checkBayerRawBuffer(bTooMuch);
+ checkAnyBuffer(bTooMuch, GetParam().format);
ALOGV("Unlocking extra buffer");
err = mCC->unlockBuffer(bTooMuch);
@@ -493,17 +690,66 @@ TEST_P(CpuConsumerTest, DISABLED_FromCpuLockMax) {
}
+CpuConsumerTestParams y8TestSets[] = {
+ { 512, 512, 1, HAL_PIXEL_FORMAT_Y8},
+ { 512, 512, 3, HAL_PIXEL_FORMAT_Y8},
+ { 2608, 1960, 1, HAL_PIXEL_FORMAT_Y8},
+ { 2608, 1960, 3, HAL_PIXEL_FORMAT_Y8},
+ { 100, 100, 1, HAL_PIXEL_FORMAT_Y8},
+ { 100, 100, 3, HAL_PIXEL_FORMAT_Y8},
+};
+
+CpuConsumerTestParams y16TestSets[] = {
+ { 512, 512, 1, HAL_PIXEL_FORMAT_Y16},
+ { 512, 512, 3, HAL_PIXEL_FORMAT_Y16},
+ { 2608, 1960, 1, HAL_PIXEL_FORMAT_Y16},
+ { 2608, 1960, 3, HAL_PIXEL_FORMAT_Y16},
+ { 100, 100, 1, HAL_PIXEL_FORMAT_Y16},
+ { 100, 100, 3, HAL_PIXEL_FORMAT_Y16},
+};
+
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}
+ { 100, 100, 3, HAL_PIXEL_FORMAT_RAW_SENSOR},
+};
+
+CpuConsumerTestParams rgba8888TestSets[] = {
+ { 512, 512, 1, HAL_PIXEL_FORMAT_RGBA_8888},
+ { 512, 512, 3, HAL_PIXEL_FORMAT_RGBA_8888},
+ { 2608, 1960, 1, HAL_PIXEL_FORMAT_RGBA_8888},
+ { 2608, 1960, 3, HAL_PIXEL_FORMAT_RGBA_8888},
+ { 100, 100, 1, HAL_PIXEL_FORMAT_RGBA_8888},
+ { 100, 100, 3, HAL_PIXEL_FORMAT_RGBA_8888},
};
+#if CPU_CONSUMER_TEST_FORMAT_Y8
+INSTANTIATE_TEST_CASE_P(Y8Tests,
+ CpuConsumerTest,
+ ::testing::ValuesIn(y8TestSets));
+#endif
+
+#if CPU_CONSUMER_TEST_FORMAT_Y16
+INSTANTIATE_TEST_CASE_P(Y16Tests,
+ CpuConsumerTest,
+ ::testing::ValuesIn(y16TestSets));
+#endif
+
+#if CPU_CONSUMER_TEST_FORMAT_RAW
INSTANTIATE_TEST_CASE_P(RawTests,
CpuConsumerTest,
::testing::ValuesIn(rawTestSets));
+#endif
+
+#if CPU_CONSUMER_TEST_FORMAT_RGBA_8888
+INSTANTIATE_TEST_CASE_P(Rgba8888Tests,
+ CpuConsumerTest,
+ ::testing::ValuesIn(rgba8888TestSets));
+#endif
+
+
} // namespace android
diff --git a/libs/gui/tests/SurfaceTextureClient_test.cpp b/libs/gui/tests/SurfaceTextureClient_test.cpp
index ec14a0d..7376b4c 100644
--- a/libs/gui/tests/SurfaceTextureClient_test.cpp
+++ b/libs/gui/tests/SurfaceTextureClient_test.cpp
@@ -19,7 +19,7 @@
#include <EGL/egl.h>
#include <gtest/gtest.h>
-#include <gui/SurfaceTextureClient.h>
+#include <gui/Surface.h>
#include <system/graphics.h>
#include <utils/Log.h>
#include <utils/Thread.h>
@@ -40,8 +40,8 @@ protected:
ALOGV("Begin test: %s.%s", testInfo->test_case_name(),
testInfo->name());
- mST = new SurfaceTexture(123);
- mSTC = new SurfaceTextureClient(mST);
+ mST = new GLConsumer(123);
+ mSTC = new Surface(mST->getBufferQueue());
mANW = mSTC;
// We need a valid GL context so we can test updateTexImage()
@@ -61,6 +61,7 @@ protected:
&myConfig, 1, &numConfigs));
ASSERT_EQ(EGL_SUCCESS, eglGetError());
+ mEglConfig = myConfig;
EGLint pbufferAttribs[] = {
EGL_WIDTH, 16,
EGL_HEIGHT, 16,
@@ -95,24 +96,25 @@ protected:
virtual EGLint const* getConfigAttribs() {
static EGLint sDefaultConfigAttribs[] = {
- EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
+ EGL_SURFACE_TYPE, EGL_PBUFFER_BIT | EGL_WINDOW_BIT,
EGL_NONE
};
return sDefaultConfigAttribs;
}
- sp<SurfaceTexture> mST;
- sp<SurfaceTextureClient> mSTC;
+ sp<GLConsumer> mST;
+ sp<Surface> mSTC;
sp<ANativeWindow> mANW;
EGLDisplay mEglDisplay;
EGLSurface mEglSurface;
EGLContext mEglContext;
+ EGLConfig mEglConfig;
};
TEST_F(SurfaceTextureClientTest, GetISurfaceTextureIsNotNull) {
- sp<ISurfaceTexture> ist(mSTC->getISurfaceTexture());
+ sp<IGraphicBufferProducer> ist(mSTC->getIGraphicBufferProducer());
ASSERT_TRUE(ist != NULL);
}
@@ -128,7 +130,7 @@ TEST_F(SurfaceTextureClientTest, ConcreteTypeIsSurfaceTextureClient) {
int result = -123;
int err = mANW->query(mANW.get(), NATIVE_WINDOW_CONCRETE_TYPE, &result);
EXPECT_EQ(NO_ERROR, err);
- EXPECT_EQ(NATIVE_WINDOW_SURFACE_TEXTURE_CLIENT, result);
+ EXPECT_EQ(NATIVE_WINDOW_SURFACE, result);
}
TEST_F(SurfaceTextureClientTest, EglCreateWindowSurfaceSucceeds) {
@@ -169,6 +171,34 @@ TEST_F(SurfaceTextureClientTest, EglCreateWindowSurfaceSucceeds) {
eglTerminate(dpy);
}
+TEST_F(SurfaceTextureClientTest, EglSwapBuffersAbandonErrorIsEglBadSurface) {
+
+ EGLSurface eglSurface = eglCreateWindowSurface(mEglDisplay, mEglConfig, mANW.get(), NULL);
+ EXPECT_NE(EGL_NO_SURFACE, eglSurface);
+ EXPECT_EQ(EGL_SUCCESS, eglGetError());
+
+ EGLBoolean success = eglMakeCurrent(mEglDisplay, eglSurface, eglSurface, mEglContext);
+ EXPECT_TRUE(success);
+
+ glClear(GL_COLOR_BUFFER_BIT);
+ success = eglSwapBuffers(mEglDisplay, eglSurface);
+ EXPECT_TRUE(success);
+
+ mST->abandon();
+
+ glClear(GL_COLOR_BUFFER_BIT);
+ success = eglSwapBuffers(mEglDisplay, eglSurface);
+ EXPECT_FALSE(success);
+ EXPECT_EQ(EGL_BAD_SURFACE, eglGetError());
+
+ success = eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext);
+ ASSERT_TRUE(success);
+
+ if (eglSurface != EGL_NO_SURFACE) {
+ eglDestroySurface(mEglDisplay, eglSurface);
+ }
+}
+
TEST_F(SurfaceTextureClientTest, BufferGeometryInvalidSizesFail) {
EXPECT_GT(OK, native_window_set_buffers_geometry(mANW.get(), -1, 0, 0));
EXPECT_GT(OK, native_window_set_buffers_geometry(mANW.get(), 0, -1, 0));
@@ -250,7 +280,7 @@ TEST_F(SurfaceTextureClientTest, BufferGeometrySizeCanBeChangedWithoutFormat) {
}
TEST_F(SurfaceTextureClientTest, SurfaceTextureSetDefaultSize) {
- sp<SurfaceTexture> st(mST);
+ sp<GLConsumer> st(mST);
ANativeWindowBuffer* buf;
EXPECT_EQ(OK, st->setDefaultBufferSize(16, 8));
ASSERT_EQ(OK, native_window_dequeue_buffer_and_wait(mANW.get(), &buf));
@@ -464,7 +494,7 @@ TEST_F(SurfaceTextureClientTest, SetCropCropsCrop) {
// from the SurfaceTexture class.
TEST_F(SurfaceTextureClientTest, DISABLED_SurfaceTextureSyncModeWaitRetire) {
class MyThread : public Thread {
- sp<SurfaceTexture> mST;
+ sp<GLConsumer> mST;
EGLContext ctx;
EGLSurface sur;
EGLDisplay dpy;
@@ -480,7 +510,7 @@ TEST_F(SurfaceTextureClientTest, DISABLED_SurfaceTextureSyncModeWaitRetire) {
return false;
}
public:
- MyThread(const sp<SurfaceTexture>& mST)
+ MyThread(const sp<GLConsumer>& mST)
: mST(mST), mBufferRetired(false) {
ctx = eglGetCurrentContext();
sur = eglGetCurrentSurface(EGL_DRAW);
@@ -685,8 +715,8 @@ protected:
ASSERT_NE(EGL_NO_CONTEXT, mEglContext);
for (int i = 0; i < NUM_SURFACE_TEXTURES; i++) {
- sp<SurfaceTexture> st(new SurfaceTexture(i));
- sp<SurfaceTextureClient> stc(new SurfaceTextureClient(st));
+ sp<GLConsumer> st(new GLConsumer(i));
+ sp<Surface> stc(new Surface(st->getBufferQueue()));
mEglSurfaces[i] = eglCreateWindowSurface(mEglDisplay, myConfig,
static_cast<ANativeWindow*>(stc.get()), NULL);
ASSERT_EQ(EGL_SUCCESS, eglGetError());
diff --git a/libs/gui/tests/SurfaceTexture_test.cpp b/libs/gui/tests/SurfaceTexture_test.cpp
index d9b40cf..dd6c435 100644
--- a/libs/gui/tests/SurfaceTexture_test.cpp
+++ b/libs/gui/tests/SurfaceTexture_test.cpp
@@ -18,8 +18,7 @@
//#define LOG_NDEBUG 0
#include <gtest/gtest.h>
-#include <gui/SurfaceTexture.h>
-#include <gui/SurfaceTextureClient.h>
+#include <gui/GLConsumer.h>
#include <ui/GraphicBuffer.h>
#include <utils/String8.h>
#include <utils/threads.h>
@@ -30,10 +29,14 @@
#include <EGL/egl.h>
#include <EGL/eglext.h>
+#include <GLES/gl.h>
+#include <GLES/glext.h>
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
#include <ui/FramebufferNativeWindow.h>
+#include <utils/UniquePtr.h>
+#include <android/native_window.h>
namespace android {
@@ -202,7 +205,6 @@ protected:
while ((err = glGetError()) != GL_NO_ERROR) {
msg += String8::format(", %#x", err);
}
- fprintf(stderr, "pixel check failure: %s\n", msg.string());
return ::testing::AssertionFailure(
::testing::Message(msg.string()));
}
@@ -228,7 +230,6 @@ protected:
msg += String8::format("a(%d isn't %d)", pixel[3], a);
}
if (!msg.isEmpty()) {
- fprintf(stderr, "pixel check failure: %s\n", msg.string());
return ::testing::AssertionFailure(
::testing::Message(msg.string()));
} else {
@@ -378,14 +379,108 @@ static int abs(int value) {
// XXX: Code above this point should live elsewhere
+class MultiTextureConsumerTest : public GLTest {
+protected:
+ enum { TEX_ID = 123 };
+
+ virtual void SetUp() {
+ GLTest::SetUp();
+ mGlConsumer = new GLConsumer(TEX_ID);
+ mSurface = new Surface(mGlConsumer->getBufferQueue());
+ mANW = mSurface.get();
+
+ }
+ virtual void TearDown() {
+ GLTest::TearDown();
+ }
+ virtual EGLint const* getContextAttribs() {
+ return NULL;
+ }
+ virtual EGLint const* getConfigAttribs() {
+ static EGLint sDefaultConfigAttribs[] = {
+ EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
+ EGL_RED_SIZE, 8,
+ EGL_GREEN_SIZE, 8,
+ EGL_BLUE_SIZE, 8,
+ EGL_ALPHA_SIZE, 8,
+ EGL_NONE };
+
+ return sDefaultConfigAttribs;
+ }
+ sp<GLConsumer> mGlConsumer;
+ sp<Surface> mSurface;
+ ANativeWindow* mANW;
+};
+
+
+TEST_F(MultiTextureConsumerTest, EGLImageTargetWorks) {
+ ANativeWindow_Buffer buffer;
+
+ ASSERT_EQ(native_window_set_usage(mANW, GRALLOC_USAGE_SW_WRITE_OFTEN), NO_ERROR);
+ ASSERT_EQ(native_window_set_buffers_format(mANW, HAL_PIXEL_FORMAT_RGBA_8888), NO_ERROR);
+
+ glShadeModel(GL_FLAT);
+ glDisable(GL_DITHER);
+ glDisable(GL_CULL_FACE);
+ glViewport(0, 0, getSurfaceWidth(), getSurfaceHeight());
+ glOrthof(0, getSurfaceWidth(), 0, getSurfaceHeight(), 0, 1);
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glColor4f(1, 1, 1, 1);
+
+ glBindTexture(GL_TEXTURE_EXTERNAL_OES, TEX_ID);
+ glTexParameterx(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameterx(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ glTexParameterx(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameterx(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+
+ uint32_t texel = 0x80808080;
+ glBindTexture(GL_TEXTURE_2D, TEX_ID+1);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, &texel);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+
+ glActiveTexture(GL_TEXTURE1);
+ glBindTexture(GL_TEXTURE_2D, TEX_ID+1);
+ glEnable(GL_TEXTURE_2D);
+ glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_EXTERNAL_OES, TEX_ID);
+ glEnable(GL_TEXTURE_EXTERNAL_OES);
+ glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+
+ glClear(GL_COLOR_BUFFER_BIT);
+ for (int i=0 ; i<8 ; i++) {
+ mSurface->lock(&buffer, NULL);
+ memset(buffer.bits, (i&7) * 0x20, buffer.stride * buffer.height * 4);
+ mSurface->unlockAndPost();
+
+ mGlConsumer->updateTexImage();
+
+ GLfloat vertices[][2] = { {i*16.0f, 0}, {(i+1)*16.0f, 0}, {(i+1)*16.0f, 16.0f}, {i*16.0f, 16.0f} };
+ glVertexPointer(2, GL_FLOAT, 0, vertices);
+ glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+
+ ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
+ }
+
+ for (int i=0 ; i<8 ; i++) {
+ EXPECT_TRUE(checkPixel(i*16 + 8, 8, i*16, i*16, i*16, i*16, 0));
+ }
+}
+
+
+
class SurfaceTextureGLTest : public GLTest {
protected:
enum { TEX_ID = 123 };
virtual void SetUp() {
GLTest::SetUp();
- mST = new SurfaceTexture(TEX_ID);
- mSTC = new SurfaceTextureClient(mST);
+ mST = new GLConsumer(TEX_ID);
+ mSTC = new Surface(mST->getBufferQueue());
mANW = mSTC;
mTextureRenderer = new TextureRenderer(TEX_ID, mST);
ASSERT_NO_FATAL_FAILURE(mTextureRenderer->SetUp());
@@ -406,7 +501,7 @@ protected:
class TextureRenderer: public RefBase {
public:
- TextureRenderer(GLuint texName, const sp<SurfaceTexture>& st):
+ TextureRenderer(GLuint texName, const sp<GLConsumer>& st):
mTexName(texName),
mST(st) {
}
@@ -447,7 +542,7 @@ protected:
ASSERT_NE(-1, mTexMatrixHandle);
}
- // drawTexture draws the SurfaceTexture over the entire GL viewport.
+ // drawTexture draws the GLConsumer over the entire GL viewport.
void drawTexture() {
static const GLfloat triangleVertices[] = {
-1.0f, 1.0f,
@@ -494,14 +589,14 @@ protected:
}
GLuint mTexName;
- sp<SurfaceTexture> mST;
+ sp<GLConsumer> mST;
GLuint mPgm;
GLint mPositionHandle;
GLint mTexSamplerHandle;
GLint mTexMatrixHandle;
};
- class FrameWaiter : public SurfaceTexture::FrameAvailableListener {
+ class FrameWaiter : public GLConsumer::FrameAvailableListener {
public:
FrameWaiter():
mPendingFrames(0) {
@@ -526,7 +621,7 @@ protected:
Condition mCondition;
};
- // Note that SurfaceTexture will lose the notifications
+ // Note that GLConsumer 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
@@ -575,8 +670,8 @@ protected:
Condition mFrameCondition;
};
- sp<SurfaceTexture> mST;
- sp<SurfaceTextureClient> mSTC;
+ sp<GLConsumer> mST;
+ sp<Surface> mSTC;
sp<ANativeWindow> mANW;
sp<TextureRenderer> mTextureRenderer;
sp<FrameWaiter> mFW;
@@ -719,18 +814,18 @@ TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledYV12BufferNpot) {
glViewport(0, 0, texWidth, texHeight);
drawTexture();
- EXPECT_TRUE(checkPixel( 0, 0, 255, 127, 255, 255));
- EXPECT_TRUE(checkPixel(63, 0, 0, 133, 0, 255));
- EXPECT_TRUE(checkPixel(63, 65, 0, 133, 0, 255));
- EXPECT_TRUE(checkPixel( 0, 65, 255, 127, 255, 255));
-
- EXPECT_TRUE(checkPixel(22, 44, 255, 127, 255, 255));
- EXPECT_TRUE(checkPixel(45, 52, 255, 127, 255, 255));
- EXPECT_TRUE(checkPixel(52, 51, 98, 255, 73, 255));
- EXPECT_TRUE(checkPixel( 7, 31, 155, 0, 118, 255));
- EXPECT_TRUE(checkPixel(31, 9, 107, 24, 87, 255));
- EXPECT_TRUE(checkPixel(29, 35, 255, 127, 255, 255));
- EXPECT_TRUE(checkPixel(36, 22, 155, 29, 0, 255));
+ EXPECT_TRUE(checkPixel( 0, 0, 255, 127, 255, 255, 3));
+ EXPECT_TRUE(checkPixel(63, 0, 0, 133, 0, 255, 3));
+ EXPECT_TRUE(checkPixel(63, 65, 0, 133, 0, 255, 3));
+ EXPECT_TRUE(checkPixel( 0, 65, 255, 127, 255, 255, 3));
+
+ EXPECT_TRUE(checkPixel(22, 44, 255, 127, 255, 255, 3));
+ EXPECT_TRUE(checkPixel(45, 52, 255, 127, 255, 255, 3));
+ EXPECT_TRUE(checkPixel(52, 51, 98, 255, 73, 255, 3));
+ EXPECT_TRUE(checkPixel( 7, 31, 155, 0, 118, 255, 3));
+ EXPECT_TRUE(checkPixel(31, 9, 107, 24, 87, 255, 3));
+ EXPECT_TRUE(checkPixel(29, 35, 255, 127, 255, 255, 3));
+ EXPECT_TRUE(checkPixel(36, 22, 155, 29, 0, 255, 3));
}
TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledYV12BufferPow2) {
@@ -1070,7 +1165,7 @@ TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledRGBABufferPow2) {
EXPECT_TRUE(checkPixel( 3, 52, 35, 231, 35, 35));
}
-// Tests if SurfaceTexture and BufferQueue are robust enough
+// Tests if GLConsumer and BufferQueue are robust enough
// to handle a special case where updateTexImage is called
// in the middle of disconnect. This ordering is enforced
// by blocking in the disconnect callback.
@@ -1123,12 +1218,12 @@ TEST_F(SurfaceTextureGLTest, DisconnectStressTest) {
sp<Thread> pt(new ProducerThread(mANW));
pt->run();
- // eat a frame so SurfaceTexture will own an at least one slot
+ // eat a frame so GLConsumer will own an at least one slot
dw->waitForFrame();
EXPECT_EQ(OK,mST->updateTexImage());
dw->waitForFrame();
- // Could fail here as SurfaceTexture thinks it still owns the slot
+ // Could fail here as GLConsumer thinks it still owns the slot
// but bufferQueue has released all slots
EXPECT_EQ(OK,mST->updateTexImage());
@@ -1136,7 +1231,7 @@ TEST_F(SurfaceTextureGLTest, DisconnectStressTest) {
}
-// This test ensures that the SurfaceTexture clears the mCurrentTexture
+// This test ensures that the GLConsumer clears the mCurrentTexture
// when it is disconnected and reconnected. Otherwise it will
// attempt to release a buffer that it does not owned
TEST_F(SurfaceTextureGLTest, DisconnectClearsCurrentTexture) {
@@ -1581,7 +1676,7 @@ TEST_F(SurfaceTextureGLToGLTest, EglDestroySurfaceUnrefsBuffers) {
// This test should have the only reference to buffer 0.
EXPECT_EQ(1, buffers[0]->getStrongCount());
- // The SurfaceTexture should hold a single reference to buffer 1 in its
+ // The GLConsumer should hold a single reference to buffer 1 in its
// mCurrentBuffer member. All of the references in the slots should have
// been released.
EXPECT_EQ(2, buffers[1]->getStrongCount());
@@ -1615,7 +1710,7 @@ TEST_F(SurfaceTextureGLToGLTest, EglDestroySurfaceAfterAbandonUnrefsBuffers) {
buffers[i] = mST->getCurrentBuffer();
}
- // Abandon the SurfaceTexture, releasing the ref that the SurfaceTexture has
+ // Abandon the GLConsumer, releasing the ref that the GLConsumer has
// on buffers[2].
mST->abandon();
@@ -1639,6 +1734,81 @@ TEST_F(SurfaceTextureGLToGLTest, EglDestroySurfaceAfterAbandonUnrefsBuffers) {
}
}
+TEST_F(SurfaceTextureGLToGLTest, EglMakeCurrentBeforeConsumerDeathUnrefsBuffers) {
+ sp<GraphicBuffer> buffer;
+
+ EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mProducerEglSurface,
+ mProducerEglSurface, mProducerEglContext));
+
+ // Produce a frame
+ glClear(GL_COLOR_BUFFER_BIT);
+ EXPECT_TRUE(eglSwapBuffers(mEglDisplay, mProducerEglSurface));
+ ASSERT_EQ(EGL_SUCCESS, eglGetError());
+
+ // Destroy the EGLSurface.
+ EXPECT_TRUE(eglDestroySurface(mEglDisplay, mProducerEglSurface));
+ ASSERT_EQ(EGL_SUCCESS, eglGetError());
+ mProducerEglSurface = EGL_NO_SURFACE;
+ mSTC.clear();
+ mANW.clear();
+ mTextureRenderer.clear();
+
+ // Consume a frame
+ ASSERT_EQ(NO_ERROR, mST->updateTexImage());
+ buffer = mST->getCurrentBuffer();
+
+ // Destroy the GL texture object to release its ref
+ GLuint texID = TEX_ID;
+ glDeleteTextures(1, &texID);
+
+ // make un-current, all references to buffer should be gone
+ EXPECT_TRUE(eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE,
+ EGL_NO_SURFACE, EGL_NO_CONTEXT));
+
+ // Destroy consumer
+ mST.clear();
+
+ EXPECT_EQ(1, buffer->getStrongCount());
+}
+
+TEST_F(SurfaceTextureGLToGLTest, EglMakeCurrentAfterConsumerDeathUnrefsBuffers) {
+ sp<GraphicBuffer> buffer;
+
+ EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mProducerEglSurface,
+ mProducerEglSurface, mProducerEglContext));
+
+ // Produce a frame
+ glClear(GL_COLOR_BUFFER_BIT);
+ EXPECT_TRUE(eglSwapBuffers(mEglDisplay, mProducerEglSurface));
+ ASSERT_EQ(EGL_SUCCESS, eglGetError());
+
+ // Destroy the EGLSurface.
+ EXPECT_TRUE(eglDestroySurface(mEglDisplay, mProducerEglSurface));
+ ASSERT_EQ(EGL_SUCCESS, eglGetError());
+ mProducerEglSurface = EGL_NO_SURFACE;
+ mSTC.clear();
+ mANW.clear();
+ mTextureRenderer.clear();
+
+ // Consume a frame
+ ASSERT_EQ(NO_ERROR, mST->updateTexImage());
+ buffer = mST->getCurrentBuffer();
+
+ // Destroy the GL texture object to release its ref
+ GLuint texID = TEX_ID;
+ glDeleteTextures(1, &texID);
+
+ // Destroy consumer
+ mST.clear();
+
+ // make un-current, all references to buffer should be gone
+ EXPECT_TRUE(eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE,
+ EGL_NO_SURFACE, EGL_NO_CONTEXT));
+
+ EXPECT_EQ(1, buffer->getStrongCount());
+}
+
+
TEST_F(SurfaceTextureGLToGLTest, EglSurfaceDefaultsToSynchronousMode) {
// This test requires 3 buffers to run on a single thread.
mST->setDefaultMaxBufferCount(3);
@@ -1847,7 +2017,7 @@ TEST_F(SurfaceTextureGLToGLTest, TexturingFromPreRotatedGLFilledBuffer) {
* This test fixture is for testing GL -> GL texture streaming from one thread
* to another. It contains functionality to create a producer thread that will
* perform GL rendering to an ANativeWindow that feeds frames to a
- * SurfaceTexture. Additionally it supports interlocking the producer and
+ * GLConsumer. Additionally it supports interlocking the producer and
* consumer threads so that a specific sequence of calls can be
* deterministically created by the test.
*
@@ -1914,13 +2084,13 @@ protected:
// FrameCondition is a utility class for interlocking between the producer
// and consumer threads. The FrameCondition object should be created and
// destroyed in the consumer thread only. The consumer thread should set
- // the FrameCondition as the FrameAvailableListener of the SurfaceTexture,
+ // the FrameCondition as the FrameAvailableListener of the GLConsumer,
// and should call both waitForFrame and finishFrame once for each expected
// frame.
//
// This interlocking relies on the fact that onFrameAvailable gets called
- // synchronously from SurfaceTexture::queueBuffer.
- class FrameCondition : public SurfaceTexture::FrameAvailableListener {
+ // synchronously from GLConsumer::queueBuffer.
+ class FrameCondition : public GLConsumer::FrameAvailableListener {
public:
FrameCondition():
mFrameAvailable(false),
@@ -1951,7 +2121,7 @@ protected:
ALOGV("-finishFrame");
}
- // This should be called by SurfaceTexture on the producer thread.
+ // This should be called by GLConsumer on the producer thread.
virtual void onFrameAvailable() {
Mutex::Autolock lock(mMutex);
ALOGV("+onFrameAvailable");
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 545b547..429becf 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -23,11 +23,17 @@
#include <utils/String8.h>
#include <private/gui/ComposerService.h>
+#include <binder/ProcessState.h>
namespace android {
class SurfaceTest : public ::testing::Test {
protected:
+
+ SurfaceTest() {
+ ProcessState::self()->startThreadPool();
+ }
+
virtual void SetUp() {
mComposerClient = new SurfaceComposerClient;
ASSERT_EQ(NO_ERROR, mComposerClient->initCheck());
@@ -81,14 +87,11 @@ TEST_F(SurfaceTest, ScreenshotsOfProtectedBuffersSucceed) {
sp<ANativeWindow> anw(mSurface);
// Verify the screenshot works with no protected buffers.
- sp<IMemoryHeap> heap;
- uint32_t w=0, h=0;
- PixelFormat fmt=0;
+ sp<CpuConsumer> consumer = new CpuConsumer(1);
sp<ISurfaceComposer> sf(ComposerService::getComposerService());
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);
+ ASSERT_EQ(NO_ERROR, sf->captureScreen(display, consumer->getBufferQueue(),
+ 64, 64, 0, 0x7fffffff, true));
// Set the PROTECTED usage bit and verify that the screenshot fails. Note
// that we need to dequeue a buffer in order for it to actually get
@@ -116,11 +119,8 @@ TEST_F(SurfaceTest, ScreenshotsOfProtectedBuffersSucceed) {
&buf));
ASSERT_EQ(NO_ERROR, anw->queueBuffer(anw.get(), buf, -1));
}
- heap = 0;
- w = h = fmt = 0;
- ASSERT_EQ(NO_ERROR, sf->captureScreen(display, &heap, &w, &h, &fmt,
- 64, 64, 0, 0x7fffffff));
- ASSERT_TRUE(heap != NULL);
+ ASSERT_EQ(NO_ERROR, sf->captureScreen(display, consumer->getBufferQueue(),
+ 64, 64, 0, 0x7fffffff, true));
}
TEST_F(SurfaceTest, ConcreteTypeIsSurface) {