Merge "Add NULL check to CallStack::toString"
diff --git a/cmds/installd/Android.mk b/cmds/installd/Android.mk
index 1dd4ee5..6eecb20 100644
--- a/cmds/installd/Android.mk
+++ b/cmds/installd/Android.mk
@@ -11,9 +11,8 @@
LOCAL_SRC_FILES := \
$(common_src_files)
-
+LOCAL_CFLAGS := -std=gnu99
LOCAL_MODULE := libinstalld
-
LOCAL_MODULE_TAGS := eng tests
include $(BUILD_STATIC_LIBRARY)
@@ -36,7 +35,7 @@
libdiskusage
LOCAL_MODULE := installd
-
+LOCAL_CFLAGS := -std=gnu99
LOCAL_MODULE_TAGS := optional
include $(BUILD_EXECUTABLE)
diff --git a/cmds/installd/commands.c b/cmds/installd/commands.c
index 2a54710..e22fa6a 100644
--- a/cmds/installd/commands.c
+++ b/cmds/installd/commands.c
@@ -28,13 +28,15 @@
dir_rec_t android_media_dir;
dir_rec_array_t android_system_dirs;
-int install(const char *pkgname, uid_t uid, gid_t gid)
+int install(const char *pkgname, uid_t uid, gid_t gid, bool restrictHomeDir)
{
char pkgdir[PKG_PATH_MAX];
char libsymlink[PKG_PATH_MAX];
char applibdir[PKG_PATH_MAX];
struct stat libStat;
+ mode_t defaultMode = restrictHomeDir ? 0700 : 0751;
+
if ((uid < AID_SYSTEM) || (gid < AID_SYSTEM)) {
ALOGE("invalid uid/gid: %d %d\n", uid, gid);
return -1;
@@ -55,11 +57,11 @@
return -1;
}
- if (mkdir(pkgdir, 0751) < 0) {
+ if (mkdir(pkgdir, defaultMode) < 0) {
ALOGE("cannot create dir '%s': %s\n", pkgdir, strerror(errno));
return -1;
}
- if (chmod(pkgdir, 0751) < 0) {
+ if (chmod(pkgdir, defaultMode) < 0) {
ALOGE("cannot chmod dir '%s': %s\n", pkgdir, strerror(errno));
unlink(pkgdir);
return -1;
@@ -184,13 +186,15 @@
return delete_dir_contents(pkgdir, 0, "lib");
}
-int make_user_data(const char *pkgname, uid_t uid, uid_t persona)
+int make_user_data(const char *pkgname, uid_t uid, uid_t persona, bool restrictHomeDir)
{
char pkgdir[PKG_PATH_MAX];
char applibdir[PKG_PATH_MAX];
char libsymlink[PKG_PATH_MAX];
struct stat libStat;
+ mode_t defaultMode = restrictHomeDir ? 0700 : 0751;
+
// Create the data dir for the package
if (create_pkg_path(pkgdir, pkgname, PKG_DIR_POSTFIX, persona)) {
return -1;
@@ -204,11 +208,11 @@
return -1;
}
- if (mkdir(pkgdir, 0751) < 0) {
+ if (mkdir(pkgdir, defaultMode) < 0) {
ALOGE("cannot create dir '%s': %s\n", pkgdir, strerror(errno));
return -errno;
}
- if (chmod(pkgdir, 0751) < 0) {
+ if (chmod(pkgdir, defaultMode) < 0) {
ALOGE("cannot chmod dir '%s': %s\n", pkgdir, strerror(errno));
unlink(pkgdir);
return -errno;
@@ -283,53 +287,6 @@
return 0;
}
-int clone_persona_data(uid_t src_persona, uid_t target_persona, int copy)
-{
- char src_data_dir[PKG_PATH_MAX];
- char pkg_path[PKG_PATH_MAX];
- DIR *d;
- struct dirent *de;
- struct stat s;
- uid_t uid;
-
- if (create_persona_path(src_data_dir, src_persona)) {
- return -1;
- }
-
- d = opendir(src_data_dir);
- if (d != NULL) {
- while ((de = readdir(d))) {
- const char *name = de->d_name;
-
- if (de->d_type == DT_DIR) {
- int subfd;
- /* always skip "." and ".." */
- if (name[0] == '.') {
- if (name[1] == 0) continue;
- if ((name[1] == '.') && (name[2] == 0)) continue;
- }
- /* Create the full path to the package's data dir */
- create_pkg_path(pkg_path, name, PKG_DIR_POSTFIX, src_persona);
- /* Get the file stat */
- if (stat(pkg_path, &s) < 0) continue;
- /* Get the uid of the package */
- ALOGI("Adding datadir for uid = %lu\n", s.st_uid);
- uid = (uid_t) s.st_uid % PER_USER_RANGE;
- /* Create the directory for the target */
- make_user_data(name, uid + target_persona * PER_USER_RANGE,
- target_persona);
- }
- }
- closedir(d);
- }
-
- if (ensure_media_user_dirs((userid_t) target_persona) == -1) {
- return -1;
- }
-
- return 0;
-}
-
int delete_cache(const char *pkgname, uid_t persona)
{
char cachedir[PKG_PATH_MAX];
diff --git a/cmds/installd/installd.c b/cmds/installd/installd.c
index 21d674a..bf21102 100644
--- a/cmds/installd/installd.c
+++ b/cmds/installd/installd.c
@@ -31,7 +31,11 @@
static int do_install(char **arg, char reply[REPLY_MAX])
{
- return install(arg[0], atoi(arg[1]), atoi(arg[2])); /* pkgname, uid, gid */
+ bool restrictHomeDir = (strncmp(arg[3], "false", 6) != 0);
+ return install(arg[0], /* pkgname */
+ atoi(arg[1]), /* uid */
+ atoi(arg[2]), /* gid */
+ restrictHomeDir); /* restrictHomeDir */
}
static int do_dexopt(char **arg, char reply[REPLY_MAX])
@@ -103,7 +107,11 @@
static int do_mk_user_data(char **arg, char reply[REPLY_MAX])
{
- return make_user_data(arg[0], atoi(arg[1]), atoi(arg[2])); /* pkgname, uid, userid */
+ bool restrictHomeDir = (strncmp(arg[3], "false", 6) != 0);
+ return make_user_data(arg[0], /* pkgname */
+ atoi(arg[1]), /* uid */
+ atoi(arg[2]), /* userid */
+ restrictHomeDir); /* restrictHomeDir */
}
static int do_rm_user(char **arg, char reply[REPLY_MAX])
@@ -111,11 +119,6 @@
return delete_persona(atoi(arg[0])); /* userid */
}
-static int do_clone_user_data(char **arg, char reply[REPLY_MAX])
-{
- return clone_persona_data(atoi(arg[0]), atoi(arg[1]), atoi(arg[2]));
-}
-
static int do_movefiles(char **arg, char reply[REPLY_MAX])
{
return movefiles();
@@ -134,7 +137,7 @@
struct cmdinfo cmds[] = {
{ "ping", 0, do_ping },
- { "install", 3, do_install },
+ { "install", 4, do_install },
{ "dexopt", 3, do_dexopt },
{ "movedex", 2, do_move_dex },
{ "rmdex", 1, do_rm_dex },
@@ -147,9 +150,8 @@
{ "rmuserdata", 2, do_rm_user_data },
{ "movefiles", 0, do_movefiles },
{ "linklib", 3, do_linklib },
- { "mkuserdata", 3, do_mk_user_data },
+ { "mkuserdata", 4, do_mk_user_data },
{ "rmuser", 1, do_rm_user },
- { "cloneuserdata", 3, do_clone_user_data },
};
static int readx(int s, void *_buf, int count)
diff --git a/cmds/installd/installd.h b/cmds/installd/installd.h
index 0500c23..cf2bed6 100644
--- a/cmds/installd/installd.h
+++ b/cmds/installd/installd.h
@@ -20,6 +20,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
+#include <stdbool.h>
#include <inttypes.h>
#include <sys/stat.h>
#include <dirent.h>
@@ -192,14 +193,15 @@
/* commands.c */
-int install(const char *pkgname, uid_t uid, gid_t gid);
+int install(const char *pkgname, uid_t uid, gid_t gid,
+ bool restrictHomeDirectory);
int uninstall(const char *pkgname, uid_t persona);
int renamepkg(const char *oldpkgname, const char *newpkgname);
int fix_uid(const char *pkgname, uid_t uid, gid_t gid);
int delete_user_data(const char *pkgname, uid_t persona);
-int make_user_data(const char *pkgname, uid_t uid, uid_t persona);
+int make_user_data(const char *pkgname, uid_t uid, uid_t persona,
+ bool restrictHomeDirectory);
int delete_persona(uid_t persona);
-int clone_persona_data(uid_t src_persona, uid_t target_persona, int copy);
int delete_cache(const char *pkgname, uid_t persona);
int move_dex(const char *src, const char *dst);
int rm_dex(const char *path);
diff --git a/include/android/bitmap.h b/include/android/bitmap.h
index 5078277..6e18763 100644
--- a/include/android/bitmap.h
+++ b/include/android/bitmap.h
@@ -24,11 +24,14 @@
extern "C" {
#endif
-#define ANDROID_BITMAP_RESUT_SUCCESS 0
+#define ANDROID_BITMAP_RESULT_SUCCESS 0
#define ANDROID_BITMAP_RESULT_BAD_PARAMETER -1
#define ANDROID_BITMAP_RESULT_JNI_EXCEPTION -2
#define ANDROID_BITMAP_RESULT_ALLOCATION_FAILED -3
+/* Backward compatibility: this macro used to be misspelled. */
+#define ANDROID_BITMAP_RESUT_SUCCESS ANDROID_BITMAP_RESULT_SUCCESS
+
enum AndroidBitmapFormat {
ANDROID_BITMAP_FORMAT_NONE = 0,
ANDROID_BITMAP_FORMAT_RGBA_8888 = 1,
diff --git a/include/gui/BufferQueue.h b/include/gui/BufferQueue.h
index 9e265ba..88bcd8f 100644
--- a/include/gui/BufferQueue.h
+++ b/include/gui/BufferQueue.h
@@ -182,8 +182,9 @@
mBuf(INVALID_BUFFER_SLOT) {
mCrop.makeInvalid();
}
- // mGraphicBuffer points to the buffer allocated for this slot or is NULL
- // if no buffer has been allocated.
+ // mGraphicBuffer points to the buffer allocated for this slot, or is NULL
+ // if the buffer in this slot has been acquired in the past (see
+ // BufferSlot.mAcquireCalled).
sp<GraphicBuffer> mGraphicBuffer;
// mCrop is the current crop rectangle for this buffer slot.
diff --git a/services/surfaceflinger/DisplayHardware/GraphicBufferAlloc.h b/include/gui/GraphicBufferAlloc.h
similarity index 100%
rename from services/surfaceflinger/DisplayHardware/GraphicBufferAlloc.h
rename to include/gui/GraphicBufferAlloc.h
diff --git a/include/gui/SurfaceTexture.h b/include/gui/SurfaceTexture.h
index b498a5c..ae5d57a 100644
--- a/include/gui/SurfaceTexture.h
+++ b/include/gui/SurfaceTexture.h
@@ -74,14 +74,13 @@
GLenum texTarget = GL_TEXTURE_EXTERNAL_OES, bool useFenceSync = true,
const sp<BufferQueue> &bufferQueue = 0);
- // updateTexImage sets the image contents of the target texture to that of
- // the most recently queued buffer.
+ // updateTexImage acquires the most recently queued buffer, and sets the
+ // image contents of the target texture to it.
//
// This call may only be made while the OpenGL ES context to which the
// target texture belongs is bound to the calling thread.
//
- // After calling this method the doGLFenceWait method must be called
- // before issuing OpenGL ES commands that access the texture contents.
+ // This calls doGLFenceWait to ensure proper synchronization.
status_t updateTexImage();
// setReleaseFence stores a fence file descriptor that will signal when the
@@ -161,8 +160,7 @@
// doGLFenceWait inserts a wait command into the OpenGL ES command stream
// to ensure that it is safe for future OpenGL ES commands to access the
- // current texture buffer. This must be called each time updateTexImage
- // is called before issuing OpenGL ES commands that access the texture.
+ // current texture buffer.
status_t doGLFenceWait() const;
// isSynchronousMode returns whether the SurfaceTexture is currently in
@@ -233,23 +231,33 @@
virtual status_t releaseBufferLocked(int buf, EGLDisplay display,
EGLSyncKHR eglFence);
+ status_t releaseBufferLocked(int buf, EGLSyncKHR eglFence) {
+ return releaseBufferLocked(buf, mEglDisplay, eglFence);
+ }
+
static bool isExternalFormat(uint32_t format);
-private:
- // this version of updateTexImage() takes a functor used to reject or not
- // the newly acquired buffer.
- // this API is TEMPORARY and intended to be used by SurfaceFlinger only,
- // which is why class Layer is made a friend of SurfaceTexture below.
- class BufferRejecter {
- friend class SurfaceTexture;
- virtual bool reject(const sp<GraphicBuffer>& buf,
- const BufferQueue::BufferItem& item) = 0;
- protected:
- virtual ~BufferRejecter() { }
- };
- friend class Layer;
- status_t updateTexImage(BufferRejecter* rejecter, bool skipSync);
+ // This releases the buffer in the slot referenced by mCurrentTexture,
+ // then updates state to refer to the BufferItem, which must be a
+ // newly-acquired buffer.
+ status_t releaseAndUpdateLocked(const BufferQueue::BufferItem& item);
+ // Binds mTexName and the current buffer to mTexTarget. Uses
+ // mCurrentTexture if it's set, mCurrentTextureBuf if not. If the
+ // bind succeeds, this calls doGLFenceWait.
+ status_t bindTextureImageLocked();
+
+ // Gets the current EGLDisplay and EGLContext values, and compares them
+ // to mEglDisplay and mEglContext. If the fields have been previously
+ // set, the values must match; if not, the fields are set to the current
+ // values.
+ status_t checkAndUpdateEglStateLocked();
+
+ // If set, SurfaceTexture will use the EGL_ANDROID_native_fence_sync
+ // extension to create Android native fences for GLES activity.
+ static const bool sUseNativeFenceSync;
+
+private:
// createImage creates a new EGLImage from a GraphicBuffer.
EGLImageKHR createImage(EGLDisplay dpy,
const sp<GraphicBuffer>& graphicBuffer);
@@ -269,9 +277,7 @@
// doGLFenceWaitLocked inserts a wait command into the OpenGL ES command
// stream to ensure that it is safe for future OpenGL ES commands to
- // access the current texture buffer. This must be called each time
- // updateTexImage is called before issuing OpenGL ES commands that access
- // the texture.
+ // access the current texture buffer.
status_t doGLFenceWaitLocked() const;
// syncForReleaseLocked performs the synchronization needed to release the
@@ -280,6 +286,13 @@
// before the outstanding accesses have completed.
status_t syncForReleaseLocked(EGLDisplay dpy);
+ // Normally, when we bind a buffer to a texture target, we bind a buffer
+ // that is referenced by an entry in mEglSlots. In some situations we
+ // have a buffer in mCurrentTextureBuf, but no corresponding entry for
+ // it in our slot array. bindUnslottedBuffer handles that situation by
+ // binding the buffer without touching the EglSlots.
+ status_t bindUnslottedBufferLocked(EGLDisplay dpy);
+
// The default consumer usage flags that SurfaceTexture always sets on its
// BufferQueue instance; these will be OR:d with any additional flags passed
// from the SurfaceTexture user. In particular, SurfaceTexture will always
@@ -344,8 +357,8 @@
// EGLSlot contains the information and object references that
// SurfaceTexture maintains about a BufferQueue buffer slot.
- struct EGLSlot {
- EGLSlot()
+ struct EglSlot {
+ EglSlot()
: mEglImage(EGL_NO_IMAGE_KHR),
mEglFence(EGL_NO_SYNC_KHR) {
}
@@ -379,7 +392,7 @@
// slot that has not yet been used. The buffer allocated to a slot will also
// be replaced if the requested buffer usage or geometry differs from that
// of the buffer allocated to a slot.
- EGLSlot mEglSlots[BufferQueue::NUM_BUFFER_SLOTS];
+ EglSlot mEglSlots[BufferQueue::NUM_BUFFER_SLOTS];
// mCurrentTexture is the buffer slot index of the buffer that is currently
// bound to the OpenGL texture. It is initialized to INVALID_BUFFER_SLOT,
diff --git a/include/gui/SurfaceTextureClient.h b/include/gui/SurfaceTextureClient.h
index 50fd1ba..56d861a 100644
--- a/include/gui/SurfaceTextureClient.h
+++ b/include/gui/SurfaceTextureClient.h
@@ -41,12 +41,6 @@
SurfaceTextureClient(const sp<ISurfaceTexture>& surfaceTexture);
- // SurfaceTextureClient is overloaded to assist in refactoring ST and BQ.
- // SurfaceTexture is no longer an ISurfaceTexture, so client code
- // calling the original constructor will fail. Thus this convenience method
- // passes in the surfaceTexture's bufferQueue to the init method.
- SurfaceTextureClient(const sp<SurfaceTexture>& surfaceTexture);
-
sp<ISurfaceTexture> getISurfaceTexture() const;
protected:
diff --git a/include/utils/Mutex.h b/include/utils/Mutex.h
index de6fb39..dd201c8 100644
--- a/include/utils/Mutex.h
+++ b/include/utils/Mutex.h
@@ -91,10 +91,10 @@
inline Mutex::Mutex() {
pthread_mutex_init(&mMutex, NULL);
}
-inline Mutex::Mutex(const char* name) {
+inline Mutex::Mutex(__attribute__((unused)) const char* name) {
pthread_mutex_init(&mMutex, NULL);
}
-inline Mutex::Mutex(int type, const char* name) {
+inline Mutex::Mutex(int type, __attribute__((unused)) const char* name) {
if (type == SHARED) {
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
diff --git a/include/utils/RWLock.h b/include/utils/RWLock.h
index a5abea2..90beb5f 100644
--- a/include/utils/RWLock.h
+++ b/include/utils/RWLock.h
@@ -84,10 +84,10 @@
inline RWLock::RWLock() {
pthread_rwlock_init(&mRWLock, NULL);
}
-inline RWLock::RWLock(const char* name) {
+inline RWLock::RWLock(__attribute__((unused)) const char* name) {
pthread_rwlock_init(&mRWLock, NULL);
}
-inline RWLock::RWLock(int type, const char* name) {
+inline RWLock::RWLock(int type, __attribute__((unused)) const char* name) {
if (type == SHARED) {
pthread_rwlockattr_t attr;
pthread_rwlockattr_init(&attr);
diff --git a/include/utils/RefBase.h b/include/utils/RefBase.h
index 99f5182..0a8e10a 100644
--- a/include/utils/RefBase.h
+++ b/include/utils/RefBase.h
@@ -165,10 +165,10 @@
{
public:
inline LightRefBase() : mCount(0) { }
- inline void incStrong(const void* id) const {
+ inline void incStrong(__attribute__((unused)) const void* id) const {
android_atomic_inc(&mCount);
}
- inline void decStrong(const void* id) const {
+ inline void decStrong(__attribute__((unused)) const void* id) const {
if (android_atomic_dec(&mCount) == 1) {
delete static_cast<const T*>(this);
}
diff --git a/libs/gui/Android.mk b/libs/gui/Android.mk
index d970a33..04444e9 100644
--- a/libs/gui/Android.mk
+++ b/libs/gui/Android.mk
@@ -3,29 +3,30 @@
LOCAL_SRC_FILES:= \
BitTube.cpp \
+ BufferItemConsumer.cpp \
BufferQueue.cpp \
ConsumerBase.cpp \
+ CpuConsumer.cpp \
DisplayEventReceiver.cpp \
+ DummyConsumer.cpp \
+ GraphicBufferAlloc.cpp \
+ GuiConfig.cpp \
IDisplayEventConnection.cpp \
+ IGraphicBufferAlloc.cpp \
ISensorEventConnection.cpp \
ISensorServer.cpp \
+ ISurface.cpp \
+ ISurfaceComposer.cpp \
+ ISurfaceComposerClient.cpp \
ISurfaceTexture.cpp \
+ LayerState.cpp \
Sensor.cpp \
SensorEventQueue.cpp \
SensorManager.cpp \
- SurfaceTexture.cpp \
- SurfaceTextureClient.cpp \
- ISurfaceComposer.cpp \
- ISurface.cpp \
- ISurfaceComposerClient.cpp \
- IGraphicBufferAlloc.cpp \
- LayerState.cpp \
Surface.cpp \
SurfaceComposerClient.cpp \
- DummyConsumer.cpp \
- CpuConsumer.cpp \
- BufferItemConsumer.cpp \
- GuiConfig.cpp
+ SurfaceTexture.cpp \
+ SurfaceTextureClient.cpp \
LOCAL_SHARED_LIBRARIES := \
libbinder \
diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp
index 086e298..609e7d2 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
diff --git a/services/surfaceflinger/DisplayHardware/GraphicBufferAlloc.cpp b/libs/gui/GraphicBufferAlloc.cpp
similarity index 96%
rename from services/surfaceflinger/DisplayHardware/GraphicBufferAlloc.cpp
rename to libs/gui/GraphicBufferAlloc.cpp
index 965ff01..b360e81 100644
--- a/services/surfaceflinger/DisplayHardware/GraphicBufferAlloc.cpp
+++ b/libs/gui/GraphicBufferAlloc.cpp
@@ -19,7 +19,7 @@
#include <ui/GraphicBuffer.h>
-#include "DisplayHardware/GraphicBufferAlloc.h"
+#include <gui/GraphicBufferAlloc.h>
// ----------------------------------------------------------------------------
namespace android {
diff --git a/libs/gui/SurfaceTexture.cpp b/libs/gui/SurfaceTexture.cpp
index b4dfb5e..ee3079e 100644
--- a/libs/gui/SurfaceTexture.cpp
+++ b/libs/gui/SurfaceTexture.cpp
@@ -39,6 +39,8 @@
#include <utils/String8.h>
#include <utils/Trace.h>
+namespace android {
+
// 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
@@ -48,9 +50,9 @@
#ifdef USE_FENCE_SYNC
#error "USE_NATIVE_FENCE_SYNC and USE_FENCE_SYNC are incompatible"
#endif
-static const bool useNativeFenceSync = true;
+const bool SurfaceTexture::sUseNativeFenceSync = true;
#else
-static const bool useNativeFenceSync = false;
+const bool SurfaceTexture::sUseNativeFenceSync = false;
#endif
// This compile option makes SurfaceTexture use the EGL_ANDROID_sync_wait
@@ -70,8 +72,6 @@
#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,
@@ -154,7 +154,50 @@
}
status_t SurfaceTexture::updateTexImage() {
- return SurfaceTexture::updateTexImage(NULL, false);
+ ATRACE_CALL();
+ ST_LOGV("updateTexImage");
+ Mutex::Autolock lock(mMutex);
+
+ if (mAbandoned) {
+ ST_LOGE("updateTexImage: SurfaceTexture 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) {
@@ -165,161 +208,162 @@
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,
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 SurfaceTexture::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: SurfaceTexture is not attached to an OpenGL "
"ES context");
return INVALID_OPERATION;
}
+ // Confirm state.
+ err = checkAndUpdateEglStateLocked();
+ if (err != NO_ERROR) {
+ return err;
+ }
+
+ 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;
+ }
+
+ // 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;
+ }
+
+ ST_LOGV("releaseAndUpdate: (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, 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 [?]
+ }
+ }
+
+ // 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;
+
+ computeCurrentTransformMatrixLocked();
+
+ return err;
+}
+
+status_t SurfaceTexture::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) {
+ return err;
+ }
+ } else {
+ EGLImageKHR image = mEglSlots[mCurrentTexture].mEglImage;
+
+ glEGLImageTargetTexture2DOES(mTexTarget, (GLeglImageOES)image);
+
+ while ((error = glGetError()) != GL_NO_ERROR) {
+ ST_LOGE("bindTextureImage: error binding external texture image %p"
+ ": %#04x", image, error);
+ return UNKNOWN_ERROR;
+ }
+ }
+
+ // Wait for the new buffer to be ready.
+ return doGLFenceWaitLocked();
+
+}
+
+status_t SurfaceTexture::checkAndUpdateEglStateLocked() {
EGLDisplay dpy = eglGetCurrentDisplay();
EGLContext ctx = eglGetCurrentContext();
if ((mEglDisplay != dpy && mEglDisplay != EGL_NO_DISPLAY) ||
dpy == EGL_NO_DISPLAY) {
- ST_LOGE("updateTexImage: invalid current EGLDisplay");
+ ST_LOGE("checkAndUpdateEglState: invalid current EGLDisplay");
return INVALID_OPERATION;
}
if ((mEglContext != ctx && mEglContext != EGL_NO_CONTEXT) ||
ctx == EGL_NO_CONTEXT) {
- ST_LOGE("updateTexImage: invalid current EGLContext");
+ ST_LOGE("checkAndUpdateEglState: invalid current EGLContext");
return INVALID_OPERATION;
}
mEglDisplay = dpy;
mEglContext = ctx;
-
- 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;
- }
-
- GLint error;
- while ((error = glGetError()) != GL_NO_ERROR) {
- ST_LOGW("updateTexImage: clearing GL error: %#04x", error);
- }
-
- EGLImageKHR image = mEglSlots[buf].mEglImage;
- glBindTexture(mTexTarget, mTexName);
- glEGLImageTargetTexture2DOES(mTexTarget, (GLeglImageOES)image);
-
- while ((error = glGetError()) != GL_NO_ERROR) {
- ST_LOGE("updateTexImage: error binding external texture image %p "
- "(slot %d): %#04x", image, buf, error);
- err = UNKNOWN_ERROR;
- }
-
- if (err == NO_ERROR) {
- err = syncForReleaseLocked(dpy);
- }
-
- if (err != NO_ERROR) {
- // Release the buffer we just acquired. It's not safe to
- // release the old buffer, so instead we just drop the new frame.
- releaseBufferLocked(buf, dpy, EGL_NO_SYNC_KHR);
- return err;
- }
-
- ST_LOGV("updateTexImage: (slot=%d buf=%p) -> (slot=%d buf=%p)",
- mCurrentTexture,
- mCurrentTextureBuf != NULL ? mCurrentTextureBuf->handle : 0,
- buf, 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;
- }
- }
-
- // 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;
- }
- // We always bind the texture even if we don't update its contents.
- glBindTexture(mTexTarget, mTexName);
- return OK;
- }
-
- return err;
+ return NO_ERROR;
}
void SurfaceTexture::setReleaseFence(int fenceFd) {
@@ -427,30 +471,8 @@
// The EGLImageKHR that was associated with the slot was destroyed when
// the SurfaceTexture 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 +485,43 @@
return OK;
}
+status_t SurfaceTexture::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 SurfaceTexture::syncForReleaseLocked(EGLDisplay dpy) {
ST_LOGV("syncForReleaseLocked");
if (mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) {
- if (useNativeFenceSync) {
+ if (sUseNativeFenceSync) {
EGLSyncKHR sync = eglCreateSyncKHR(dpy,
EGL_SYNC_NATIVE_FENCE_ANDROID, NULL);
if (sync == EGL_NO_SYNC_KHR) {
diff --git a/libs/gui/SurfaceTextureClient.cpp b/libs/gui/SurfaceTextureClient.cpp
index afdbf04..7588b9e 100644
--- a/libs/gui/SurfaceTextureClient.cpp
+++ b/libs/gui/SurfaceTextureClient.cpp
@@ -41,14 +41,6 @@
SurfaceTextureClient::setISurfaceTexture(surfaceTexture);
}
-// see SurfaceTextureClient.h
-SurfaceTextureClient::SurfaceTextureClient(const
- sp<SurfaceTexture>& surfaceTexture)
-{
- SurfaceTextureClient::init();
- SurfaceTextureClient::setISurfaceTexture(surfaceTexture->getBufferQueue());
-}
-
SurfaceTextureClient::SurfaceTextureClient() {
SurfaceTextureClient::init();
}
diff --git a/libs/gui/tests/SurfaceTextureClient_test.cpp b/libs/gui/tests/SurfaceTextureClient_test.cpp
index ec14a0d..baeca06 100644
--- a/libs/gui/tests/SurfaceTextureClient_test.cpp
+++ b/libs/gui/tests/SurfaceTextureClient_test.cpp
@@ -41,7 +41,7 @@
testInfo->name());
mST = new SurfaceTexture(123);
- mSTC = new SurfaceTextureClient(mST);
+ mSTC = new SurfaceTextureClient(mST->getBufferQueue());
mANW = mSTC;
// We need a valid GL context so we can test updateTexImage()
@@ -686,7 +686,7 @@
for (int i = 0; i < NUM_SURFACE_TEXTURES; i++) {
sp<SurfaceTexture> st(new SurfaceTexture(i));
- sp<SurfaceTextureClient> stc(new SurfaceTextureClient(st));
+ sp<SurfaceTextureClient> stc(new SurfaceTextureClient(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..58976ad 100644
--- a/libs/gui/tests/SurfaceTexture_test.cpp
+++ b/libs/gui/tests/SurfaceTexture_test.cpp
@@ -385,7 +385,7 @@
virtual void SetUp() {
GLTest::SetUp();
mST = new SurfaceTexture(TEX_ID);
- mSTC = new SurfaceTextureClient(mST);
+ mSTC = new SurfaceTextureClient(mST->getBufferQueue());
mANW = mSTC;
mTextureRenderer = new TextureRenderer(TEX_ID, mST);
ASSERT_NO_FATAL_FAILURE(mTextureRenderer->SetUp());
diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk
index 329bbd5..b4b19b4 100644
--- a/services/surfaceflinger/Android.mk
+++ b/services/surfaceflinger/Android.mk
@@ -11,12 +11,12 @@
LayerDim.cpp \
LayerScreenshot.cpp \
DisplayHardware/FramebufferSurface.cpp \
- DisplayHardware/GraphicBufferAlloc.cpp \
DisplayHardware/HWComposer.cpp \
DisplayHardware/PowerHAL.cpp \
GLExtensions.cpp \
MessageQueue.cpp \
SurfaceFlinger.cpp \
+ SurfaceFlingerConsumer.cpp \
SurfaceTextureLayer.cpp \
Transform.cpp \
diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
index 6c86a53..cccb29b 100644
--- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
@@ -30,10 +30,10 @@
#include <hardware/hardware.h>
#include <gui/SurfaceTextureClient.h>
+#include <gui/GraphicBufferAlloc.h>
#include <ui/GraphicBuffer.h>
#include "DisplayHardware/FramebufferSurface.h"
-#include "DisplayHardware/GraphicBufferAlloc.h"
#include "DisplayHardware/HWComposer.h"
#ifndef NUM_FRAMEBUFFER_SURFACE_BUFFERS
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index b6aa005..a1d46d9 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -73,7 +73,7 @@
HWComposer::HWCLayerInterface* layer) {
LayerBaseClient::onLayerDisplayed(hw, layer);
if (layer) {
- mSurfaceTexture->setReleaseFence(layer->getAndResetReleaseFenceFd());
+ mSurfaceFlingerConsumer->setReleaseFence(layer->getAndResetReleaseFenceFd());
}
}
@@ -81,20 +81,20 @@
{
LayerBaseClient::onFirstRef();
- // Creates a custom BufferQueue for SurfaceTexture to use
+ // Creates a custom BufferQueue for SurfaceFlingerConsumer to use
sp<BufferQueue> bq = new SurfaceTextureLayer();
- mSurfaceTexture = new SurfaceTexture(mTextureName, true,
+ mSurfaceFlingerConsumer = new SurfaceFlingerConsumer(mTextureName, true,
GL_TEXTURE_EXTERNAL_OES, false, bq);
- mSurfaceTexture->setConsumerUsageBits(getEffectiveUsage(0));
- mSurfaceTexture->setFrameAvailableListener(this);
- mSurfaceTexture->setSynchronousMode(true);
+ mSurfaceFlingerConsumer->setConsumerUsageBits(getEffectiveUsage(0));
+ mSurfaceFlingerConsumer->setFrameAvailableListener(this);
+ mSurfaceFlingerConsumer->setSynchronousMode(true);
#ifdef TARGET_DISABLE_TRIPLE_BUFFERING
#warning "disabling triple buffering"
- mSurfaceTexture->setDefaultMaxBufferCount(2);
+ mSurfaceFlingerConsumer->setDefaultMaxBufferCount(2);
#else
- mSurfaceTexture->setDefaultMaxBufferCount(3);
+ mSurfaceFlingerConsumer->setDefaultMaxBufferCount(3);
#endif
const sp<const DisplayDevice> hw(mFlinger->getDefaultDisplayDevice());
@@ -115,12 +115,12 @@
// in the purgatory list
void Layer::onRemoved()
{
- mSurfaceTexture->abandon();
+ mSurfaceFlingerConsumer->abandon();
}
void Layer::setName(const String8& name) {
LayerBase::setName(name);
- mSurfaceTexture->setName(name);
+ mSurfaceFlingerConsumer->setName(name);
}
sp<ISurface> Layer::createSurface()
@@ -131,7 +131,7 @@
sp<ISurfaceTexture> res;
sp<const Layer> that( mOwner.promote() );
if (that != NULL) {
- res = that->mSurfaceTexture->getBufferQueue();
+ res = that->mSurfaceFlingerConsumer->getBufferQueue();
}
return res;
}
@@ -146,7 +146,7 @@
wp<IBinder> Layer::getSurfaceTextureBinder() const
{
- return mSurfaceTexture->getBufferQueue()->asBinder();
+ return mSurfaceFlingerConsumer->getBufferQueue()->asBinder();
}
status_t Layer::setBuffers( uint32_t w, uint32_t h,
@@ -177,15 +177,15 @@
mOpaqueLayer = (flags & ISurfaceComposerClient::eOpaque);
mCurrentOpacity = getOpacityForFormat(format);
- mSurfaceTexture->setDefaultBufferSize(w, h);
- mSurfaceTexture->setDefaultBufferFormat(format);
- mSurfaceTexture->setConsumerUsageBits(getEffectiveUsage(0));
+ mSurfaceFlingerConsumer->setDefaultBufferSize(w, h);
+ mSurfaceFlingerConsumer->setDefaultBufferFormat(format);
+ mSurfaceFlingerConsumer->setConsumerUsageBits(getEffectiveUsage(0));
return NO_ERROR;
}
Rect Layer::computeBufferCrop() const {
- // Start with the SurfaceTexture's buffer crop...
+ // Start with the SurfaceFlingerConsumer's buffer crop...
Rect crop;
if (!mCurrentCrop.isEmpty()) {
crop = mCurrentCrop;
@@ -202,7 +202,7 @@
if (!s.active.crop.isEmpty()) {
// Transform the window crop to match the buffer coordinate system,
// which means using the inverse of the current transform set on the
- // SurfaceTexture.
+ // SurfaceFlingerConsumer.
uint32_t invTransform = mCurrentTransform;
int winWidth = s.active.w;
int winHeight = s.active.h;
@@ -284,7 +284,7 @@
// acquire fence the first time a new buffer is acquired on EACH display.
if (layer.getCompositionType() == HWC_OVERLAY) {
- sp<Fence> fence = mSurfaceTexture->getCurrentFence();
+ sp<Fence> fence = mSurfaceFlingerConsumer->getCurrentFence();
if (fence.get()) {
fenceFd = fence->dup();
if (fenceFd == -1) {
@@ -327,9 +327,11 @@
return;
}
- status_t err = mSurfaceTexture->doGLFenceWait();
- if (err != OK) {
- ALOGE("onDraw: failed waiting for fence: %d", err);
+ // Bind the current buffer to the GL texture, and wait for it to be
+ // ready for us to draw into.
+ status_t err = mSurfaceFlingerConsumer->bindTextureImage();
+ if (err != NO_ERROR) {
+ ALOGW("onDraw: bindTextureImage failed (err=%d)", err);
// Go ahead and draw the buffer anyway; no matter what we do the screen
// is probably going to have something visibly wrong.
}
@@ -342,8 +344,8 @@
// Query the texture matrix given our current filtering mode.
float textureMatrix[16];
- mSurfaceTexture->setFilteringEnabled(useFiltering);
- mSurfaceTexture->getTransformMatrix(textureMatrix);
+ mSurfaceFlingerConsumer->setFilteringEnabled(useFiltering);
+ mSurfaceFlingerConsumer->getTransformMatrix(textureMatrix);
// Set things up for texturing.
glBindTexture(GL_TEXTURE_EXTERNAL_OES, mTextureName);
@@ -462,7 +464,7 @@
// record the new size, form this point on, when the client request
// a buffer, it'll get the new size.
- mSurfaceTexture->setDefaultBufferSize(
+ mSurfaceFlingerConsumer->setDefaultBufferSize(
temp.requested.w, temp.requested.h);
}
@@ -507,13 +509,10 @@
void Layer::onPostComposition() {
if (mFrameLatencyNeeded) {
- nsecs_t desiredPresentTime = mSurfaceTexture->getTimestamp();
+ nsecs_t desiredPresentTime = mSurfaceFlingerConsumer->getTimestamp();
mFrameTracker.setDesiredPresentTime(desiredPresentTime);
- sp<Fence> frameReadyFence = mSurfaceTexture->getCurrentFence();
- // XXX: Temporarily don't use the fence from the SurfaceTexture to
- // work around a driver bug.
- frameReadyFence.clear();
+ sp<Fence> frameReadyFence = mSurfaceFlingerConsumer->getCurrentFence();
if (frameReadyFence != NULL) {
mFrameTracker.setFrameReadyFence(frameReadyFence);
} else {
@@ -570,7 +569,7 @@
mFlinger->signalLayerUpdate();
}
- struct Reject : public SurfaceTexture::BufferRejecter {
+ struct Reject : public SurfaceFlingerConsumer::BufferRejecter {
Layer::State& front;
Layer::State& current;
bool& recomputeVisibleRegions;
@@ -655,14 +654,14 @@
Reject r(mDrawingState, currentState(), recomputeVisibleRegions);
- if (mSurfaceTexture->updateTexImage(&r, true) < NO_ERROR) {
+ if (mSurfaceFlingerConsumer->updateTexImage(&r) != NO_ERROR) {
// something happened!
recomputeVisibleRegions = true;
return outDirtyRegion;
}
// update the active buffer
- mActiveBuffer = mSurfaceTexture->getCurrentBuffer();
+ mActiveBuffer = mSurfaceFlingerConsumer->getCurrentBuffer();
if (mActiveBuffer == NULL) {
// this can only happen if the very first buffer was rejected.
return outDirtyRegion;
@@ -676,9 +675,9 @@
recomputeVisibleRegions = true;
}
- Rect crop(mSurfaceTexture->getCurrentCrop());
- const uint32_t transform(mSurfaceTexture->getCurrentTransform());
- const uint32_t scalingMode(mSurfaceTexture->getCurrentScalingMode());
+ Rect crop(mSurfaceFlingerConsumer->getCurrentCrop());
+ const uint32_t transform(mSurfaceFlingerConsumer->getCurrentTransform());
+ const uint32_t scalingMode(mSurfaceFlingerConsumer->getCurrentScalingMode());
if ((crop != mCurrentCrop) ||
(transform != mCurrentTransform) ||
(scalingMode != mCurrentScalingMode))
@@ -737,8 +736,8 @@
result.append(buffer);
- if (mSurfaceTexture != 0) {
- mSurfaceTexture->dump(result, " ", buffer, SIZE);
+ if (mSurfaceFlingerConsumer != 0) {
+ mSurfaceFlingerConsumer->dump(result, " ", buffer, SIZE);
}
}
@@ -780,7 +779,7 @@
orientation = 0;
}
}
- mSurfaceTexture->setTransformHint(orientation);
+ mSurfaceFlingerConsumer->setTransformHint(orientation);
}
// ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 5ea3eb4..2d4afc4 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -20,8 +20,6 @@
#include <stdint.h>
#include <sys/types.h>
-#include <gui/SurfaceTexture.h>
-
#include <utils/Timers.h>
#include <ui/GraphicBuffer.h>
@@ -34,6 +32,7 @@
#include <GLES/gl.h>
#include <GLES/glext.h>
+#include "SurfaceFlingerConsumer.h"
#include "FrameTracker.h"
#include "LayerBase.h"
#include "SurfaceTextureLayer.h"
@@ -49,7 +48,7 @@
// ---------------------------------------------------------------------------
class Layer : public LayerBaseClient,
- public SurfaceTexture::FrameAvailableListener
+ public SurfaceFlingerConsumer::FrameAvailableListener
{
public:
Layer(SurfaceFlinger* flinger, const sp<Client>& client);
@@ -92,7 +91,7 @@
// only for debugging
inline const sp<GraphicBuffer>& getActiveBuffer() const { return mActiveBuffer; }
- // Updates the transform hint in our SurfaceTexture to match
+ // Updates the transform hint in our SurfaceFlingerConsumer to match
// the current orientation of the display device.
virtual void updateTransformHint(const sp<const DisplayDevice>& hw) const;
@@ -110,13 +109,13 @@
Rect computeBufferCrop() const;
static bool getOpacityForFormat(uint32_t format);
- // Interface implementation for SurfaceTexture::FrameAvailableListener
+ // Interface implementation for SurfaceFlingerConsumer::FrameAvailableListener
virtual void onFrameAvailable();
// -----------------------------------------------------------------------
// constants
- sp<SurfaceTexture> mSurfaceTexture;
+ sp<SurfaceFlingerConsumer> mSurfaceFlingerConsumer;
GLuint mTextureName;
// thread-safe
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 41c5cce..f65b82f 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -40,6 +40,7 @@
#include <gui/GuiConfig.h>
#include <gui/IDisplayEventConnection.h>
#include <gui/SurfaceTextureClient.h>
+#include <gui/GraphicBufferAlloc.h>
#include <ui/GraphicBufferAllocator.h>
#include <ui/PixelFormat.h>
@@ -65,7 +66,6 @@
#include "SurfaceFlinger.h"
#include "DisplayHardware/FramebufferSurface.h"
-#include "DisplayHardware/GraphicBufferAlloc.h"
#include "DisplayHardware/HWComposer.h"
diff --git a/services/surfaceflinger/SurfaceFlingerConsumer.cpp b/services/surfaceflinger/SurfaceFlingerConsumer.cpp
new file mode 100644
index 0000000..a316896
--- /dev/null
+++ b/services/surfaceflinger/SurfaceFlingerConsumer.cpp
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
+#include "SurfaceFlingerConsumer.h"
+
+#include <utils/Trace.h>
+#include <utils/Errors.h>
+
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+status_t SurfaceFlingerConsumer::updateTexImage(BufferRejecter* rejecter)
+{
+ ATRACE_CALL();
+ ALOGV("updateTexImage");
+ Mutex::Autolock lock(mMutex);
+
+ if (mAbandoned) {
+ ALOGE("updateTexImage: SurfaceTexture 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) {
+ // This variant of updateTexImage does not guarantee that the
+ // texture is bound, so no need to call glBindTexture.
+ err = NO_ERROR;
+ } else {
+ ALOGE("updateTexImage: acquire failed: %s (%d)",
+ strerror(-err), err);
+ }
+ return err;
+ }
+
+
+ // 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
+ int buf = item.mBuf;
+ if (rejecter && rejecter->reject(mSlots[buf].mGraphicBuffer, item)) {
+ releaseBufferLocked(buf, EGL_NO_SYNC_KHR);
+ return NO_ERROR;
+ }
+
+ // Release the previous buffer.
+ err = releaseAndUpdateLocked(item);
+ if (err != NO_ERROR) {
+ return err;
+ }
+
+ if (!sUseNativeFenceSync) {
+ // Bind the new buffer to the GL texture.
+ //
+ // Older devices require the "implicit" synchronization provided
+ // by glEGLImageTargetTexture2DOES, which this method calls. Newer
+ // devices will either call this in Layer::onDraw, or (if it's not
+ // a GL-composited layer) not at all.
+ err = bindTextureImageLocked();
+ }
+
+ return err;
+}
+
+status_t SurfaceFlingerConsumer::bindTextureImage()
+{
+ Mutex::Autolock lock(mMutex);
+
+ return bindTextureImageLocked();
+}
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+
diff --git a/services/surfaceflinger/SurfaceFlingerConsumer.h b/services/surfaceflinger/SurfaceFlingerConsumer.h
new file mode 100644
index 0000000..308a288
--- /dev/null
+++ b/services/surfaceflinger/SurfaceFlingerConsumer.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_SURFACEFLINGERCONSUMER_H
+#define ANDROID_SURFACEFLINGERCONSUMER_H
+
+#include <gui/SurfaceTexture.h>
+
+namespace android {
+// ----------------------------------------------------------------------------
+
+/*
+ * This is a thin wrapper around SurfaceTexture.
+ */
+class SurfaceFlingerConsumer : public SurfaceTexture {
+public:
+ SurfaceFlingerConsumer(GLuint tex, bool allowSynchronousMode = true,
+ GLenum texTarget = GL_TEXTURE_EXTERNAL_OES, bool useFenceSync = true,
+ const sp<BufferQueue> &bufferQueue = 0)
+ : SurfaceTexture(tex, allowSynchronousMode, texTarget, useFenceSync,
+ bufferQueue)
+ {}
+
+ class BufferRejecter {
+ friend class SurfaceFlingerConsumer;
+ virtual bool reject(const sp<GraphicBuffer>& buf,
+ const BufferQueue::BufferItem& item) = 0;
+
+ protected:
+ virtual ~BufferRejecter() { }
+ };
+
+ // This version of updateTexImage() takes a functor that may be used to
+ // reject the newly acquired buffer. Unlike the SurfaceTexture version,
+ // this does not guarantee that the buffer has been bound to the GL
+ // texture.
+ status_t updateTexImage(BufferRejecter* rejecter);
+
+ // See SurfaceTexture::bindTextureImageLocked().
+ status_t bindTextureImage();
+};
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_SURFACEFLINGERCONSUMER_H