Merge "SensorService performance improvements." into lmp-dev
diff --git a/cmds/dumpstate/dumpstate.c b/cmds/dumpstate/dumpstate.c
index ff01da5..d2f99df 100644
--- a/cmds/dumpstate/dumpstate.c
+++ b/cmds/dumpstate/dumpstate.c
@@ -20,13 +20,13 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <sys/capability.h>
+#include <sys/prctl.h>
#include <sys/resource.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/wait.h>
#include <unistd.h>
-#include <sys/capability.h>
-#include <sys/prctl.h>
#include <cutils/properties.h>
@@ -45,6 +45,36 @@
#define PSTORE_LAST_KMSG "/sys/fs/pstore/console-ramoops"
+#define TOMBSTONE_DIR "/data/tombstones"
+#define TOMBSTONE_FILE_PREFIX TOMBSTONE_DIR "/tombstone_"
+/* Can accomodate a tombstone number up to 9999. */
+#define TOMBSTONE_MAX_LEN (sizeof(TOMBSTONE_FILE_PREFIX) + 4)
+#define NUM_TOMBSTONES 10
+
+typedef struct {
+ char name[TOMBSTONE_MAX_LEN];
+ int fd;
+} tombstone_data_t;
+
+static tombstone_data_t tombstone_data[NUM_TOMBSTONES];
+
+/* Get the fds of any tombstone that was modified in the last half an hour. */
+static void get_tombstone_fds(tombstone_data_t data[NUM_TOMBSTONES]) {
+ time_t thirty_minutes_ago = time(NULL) - 60*30;
+ for (size_t i = 0; i < NUM_TOMBSTONES; i++) {
+ snprintf(data[i].name, sizeof(data[i].name), "%s%02zu", TOMBSTONE_FILE_PREFIX, i);
+ int fd = open(data[i].name, O_RDONLY | O_CLOEXEC | O_NOFOLLOW);
+ struct stat st;
+ if (fstat(fd, &st) == 0 && S_ISREG(st.st_mode) &&
+ (time_t) st.st_mtime >= thirty_minutes_ago) {
+ data[i].fd = fd;
+ } else {
+ close(fd);
+ data[i].fd = -1;
+ }
+ }
+}
+
/* dumps the current system state to stdout */
static void dumpstate() {
time_t now = time(NULL);
@@ -119,7 +149,6 @@
run_command("EVENT LOG", 20, "logcat", "-b", "events", "-v", "threadtime", "-d", "*:v", NULL);
run_command("RADIO LOG", 20, "logcat", "-b", "radio", "-v", "threadtime", "-d", "*:v", NULL);
-
/* show the traces we collected in main(), if that was done */
if (dump_traces_path != NULL) {
dump_file("VM TRACES JUST NOW", dump_traces_path);
@@ -131,10 +160,13 @@
property_get("dalvik.vm.stack-trace-file", anr_traces_path, "");
if (!anr_traces_path[0]) {
printf("*** NO VM TRACES FILE DEFINED (dalvik.vm.stack-trace-file)\n\n");
- } else if (stat(anr_traces_path, &st)) {
- printf("*** NO ANR VM TRACES FILE (%s): %s\n\n", anr_traces_path, strerror(errno));
} else {
- dump_file("VM TRACES AT LAST ANR", anr_traces_path);
+ int fd = open(anr_traces_path, O_RDONLY | O_CLOEXEC | O_NOFOLLOW);
+ if (fd < 0) {
+ printf("*** NO ANR VM TRACES FILE (%s): %s\n\n", anr_traces_path, strerror(errno));
+ } else {
+ dump_file_from_fd("VM TRACES AT LAST ANR", anr_traces_path, fd);
+ }
}
/* slow traces for slow operations */
@@ -155,6 +187,18 @@
}
}
+ int dumped = 0;
+ for (size_t i = 0; i < NUM_TOMBSTONES; i++) {
+ if (tombstone_data[i].fd != -1) {
+ dumped = 1;
+ dump_file_from_fd("TOMBSTONE", tombstone_data[i].name, tombstone_data[i].fd);
+ tombstone_data[i].fd = -1;
+ }
+ }
+ if (!dumped) {
+ printf("*** NO TOMBSTONES to dump in %s\n\n", TOMBSTONE_DIR);
+ }
+
dump_file("NETWORK DEV INFO", "/proc/net/dev");
dump_file("QTAGUID NETWORK INTERFACES INFO", "/proc/net/xt_qtaguid/iface_stat_all");
dump_file("QTAGUID NETWORK INTERFACES INFO (xt)", "/proc/net/xt_qtaguid/iface_stat_fmt");
@@ -411,6 +455,9 @@
return -1;
}
+ /* Get the tombstone fds here while we are running as root. */
+ get_tombstone_fds(tombstone_data);
+
/* switch to non-root user and group */
gid_t groups[] = { AID_LOG, AID_SDCARD_R, AID_SDCARD_RW,
AID_MOUNT, AID_INET, AID_NET_BW_STATS };
diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h
index 111bda6..53bfff6 100644
--- a/cmds/dumpstate/dumpstate.h
+++ b/cmds/dumpstate/dumpstate.h
@@ -29,7 +29,10 @@
typedef void (for_each_userid_func)(int);
/* prints the contents of a file */
-int dump_file(const char *title, const char* path);
+int dump_file(const char *title, const char *path);
+
+/* prints the contents of the fd */
+int dump_file_from_fd(const char *title, const char *path, int fd);
/* forks a command and waits for it to finish -- terminate args with NULL */
int run_command(const char *title, int timeout_seconds, const char *command, ...);
@@ -71,7 +74,7 @@
void dump_route_tables();
/* Play a sound via Stagefright */
-void play_sound(const char* path);
+void play_sound(const char *path);
/* Implemented by libdumpstate_board to dump board-specific info */
void dumpstate_board();
diff --git a/cmds/dumpstate/utils.c b/cmds/dumpstate/utils.c
index 7694adb..a6d9ef6 100644
--- a/cmds/dumpstate/utils.c
+++ b/cmds/dumpstate/utils.c
@@ -249,8 +249,7 @@
}
/* prints the contents of a file */
-int dump_file(const char *title, const char* path) {
- char buffer[32768];
+int dump_file(const char *title, const char *path) {
int fd = open(path, O_RDONLY);
if (fd < 0) {
int err = errno;
@@ -259,6 +258,11 @@
if (title) printf("\n");
return -1;
}
+ return dump_file_from_fd(title, path, fd);
+}
+
+int dump_file_from_fd(const char *title, const char *path, int fd) {
+ char buffer[32768];
if (title) printf("------ %s (%s", title, path);
@@ -282,8 +286,8 @@
}
if (ret <= 0) break;
}
-
close(fd);
+
if (!newline) printf("\n");
if (title) printf("\n");
return 0;
diff --git a/include/gui/GLConsumer.h b/include/gui/GLConsumer.h
index 1aacee9..37530db 100644
--- a/include/gui/GLConsumer.h
+++ b/include/gui/GLConsumer.h
@@ -231,7 +231,7 @@
protected:
// abandonLocked overrides the ConsumerBase method to clear
- // mCurrentTextureBuf in addition to the ConsumerBase behavior.
+ // mCurrentTextureImage in addition to the ConsumerBase behavior.
virtual void abandonLocked();
// dumpLocked overrides the ConsumerBase method to dump GLConsumer-
@@ -262,7 +262,7 @@
status_t updateAndReleaseLocked(const BufferQueue::BufferItem& item);
// Binds mTexName and the current buffer to mTexTarget. Uses
- // mCurrentTexture if it's set, mCurrentTextureBuf if not. If the
+ // mCurrentTexture if it's set, mCurrentTextureImage if not. If the
// bind succeeds, this calls doGLFenceWait.
status_t bindTextureImageLocked();
@@ -275,11 +275,57 @@
status_t checkAndUpdateEglStateLocked(bool contextCheck = false);
private:
- // createImage creates a new EGLImage from a GraphicBuffer.
- EGLImageKHR createImage(EGLDisplay dpy,
- const sp<GraphicBuffer>& graphicBuffer, const Rect& crop);
+ // EglImage is a utility class for tracking and creating EGLImageKHRs. There
+ // is primarily just one image per slot, but there is also special cases:
+ // - For releaseTexImage, we use a debug image (mReleasedTexImage)
+ // - After freeBuffer, we must still keep the current image/buffer
+ // Reference counting EGLImages lets us handle all these cases easily while
+ // also only creating new EGLImages from buffers when required.
+ class EglImage : public LightRefBase<EglImage> {
+ public:
+ EglImage(sp<GraphicBuffer> graphicBuffer);
- // freeBufferLocked frees up the given buffer slot. If the slot has been
+ // createIfNeeded creates an EGLImage if required (we haven't created
+ // one yet, or the EGLDisplay or crop-rect has changed).
+ status_t createIfNeeded(EGLDisplay display, const Rect& cropRect);
+
+ // This calls glEGLImageTargetTexture2DOES to bind the image to the
+ // texture in the specified texture target.
+ void bindToTextureTarget(uint32_t texTarget);
+
+ const sp<GraphicBuffer>& graphicBuffer() { return mGraphicBuffer; }
+ const native_handle* graphicBufferHandle() {
+ return mGraphicBuffer == NULL ? NULL : mGraphicBuffer->handle;
+ }
+
+ private:
+ // Only allow instantiation using ref counting.
+ friend class LightRefBase<EglImage>;
+ virtual ~EglImage();
+
+ // createImage creates a new EGLImage from a GraphicBuffer.
+ EGLImageKHR createImage(EGLDisplay dpy,
+ const sp<GraphicBuffer>& graphicBuffer, const Rect& crop);
+
+ // Disallow copying
+ EglImage(const EglImage& rhs);
+ void operator = (const EglImage& rhs);
+
+ // mGraphicBuffer is the buffer that was used to create this image.
+ sp<GraphicBuffer> mGraphicBuffer;
+
+ // mEglImage is the EGLImage created from mGraphicBuffer.
+ EGLImageKHR mEglImage;
+
+ // mEGLDisplay is the EGLDisplay that was used to create mEglImage.
+ EGLDisplay mEglDisplay;
+
+ // mCropRect is the crop rectangle passed to EGL when mEglImage
+ // was created.
+ Rect mCropRect;
+ };
+
+ // freeBufferLocked frees up the given buffer slot. If the slot has been
// initialized this will release the reference to the GraphicBuffer in that
// slot and destroy the EGLImage in that slot. Otherwise it has no effect.
//
@@ -289,7 +335,7 @@
// computeCurrentTransformMatrixLocked computes the transform matrix for the
// current texture. It uses mCurrentTransform and the current GraphicBuffer
// to compute this matrix and stores it in mCurrentTransformMatrix.
- // mCurrentTextureBuf must not be NULL.
+ // mCurrentTextureImage must not be NULL.
void computeCurrentTransformMatrixLocked();
// doGLFenceWaitLocked inserts a wait command into the OpenGL ES command
@@ -303,13 +349,6 @@
// 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);
-
// returns a graphic buffer used when the texture image has been released
static sp<GraphicBuffer> getDebugTexImageBuffer();
@@ -319,10 +358,10 @@
// consume buffers as hardware textures.
static const uint32_t DEFAULT_USAGE_FLAGS = GraphicBuffer::USAGE_HW_TEXTURE;
- // mCurrentTextureBuf is the graphic buffer of the current texture. It's
+ // mCurrentTextureImage is the EglImage/buffer of the current texture. It's
// possible that this buffer is not associated with any buffer slot, so we
// must track it separately in order to support the getCurrentBuffer method.
- sp<GraphicBuffer> mCurrentTextureBuf;
+ sp<EglImage> mCurrentTextureImage;
// mCurrentCrop is the crop rectangle that applies to the current texture.
// It gets set each time updateTexImage is called.
@@ -382,17 +421,10 @@
// EGLSlot contains the information and object references that
// GLConsumer maintains about a BufferQueue buffer slot.
struct EglSlot {
- EglSlot()
- : mEglImage(EGL_NO_IMAGE_KHR),
- mEglFence(EGL_NO_SYNC_KHR) {
- }
+ EglSlot() : mEglFence(EGL_NO_SYNC_KHR) {}
// mEglImage is the EGLImage created from mGraphicBuffer.
- EGLImageKHR mEglImage;
-
- // mCropRect is the crop rectangle passed to EGL when mEglImage was
- // created.
- Rect mCropRect;
+ sp<EglImage> mEglImage;
// mFence is the EGL sync object that must signal before the buffer
// associated with this buffer slot may be dequeued. It is initialized
@@ -444,6 +476,7 @@
// mReleasedTexImageBuffer is a dummy buffer used when in single buffer
// mode and releaseTexImage() has been called
static sp<GraphicBuffer> sReleasedTexImageBuffer;
+ sp<EglImage> mReleasedTexImage;
};
// ----------------------------------------------------------------------------
diff --git a/libs/gui/GLConsumer.cpp b/libs/gui/GLConsumer.cpp
index 924fc0d..939c4a9 100644
--- a/libs/gui/GLConsumer.cpp
+++ b/libs/gui/GLConsumer.cpp
@@ -279,8 +279,12 @@
return err;
}
+ if (mReleasedTexImage == NULL) {
+ mReleasedTexImage = new EglImage(getDebugTexImageBuffer());
+ }
+
mCurrentTexture = BufferQueue::INVALID_BUFFER_SLOT;
- mCurrentTextureBuf = getDebugTexImageBuffer();
+ mCurrentTextureImage = mReleasedTexImage;
mCurrentCrop.makeInvalid();
mCurrentTransform = 0;
mCurrentScalingMode = NATIVE_WINDOW_SCALING_MODE_FREEZE;
@@ -288,9 +292,11 @@
mCurrentFence = Fence::NO_FENCE;
if (mAttached) {
- // bind a dummy texture
- glBindTexture(mTexTarget, mTexName);
- bindUnslottedBufferLocked(mEglDisplay);
+ // This binds a dummy buffer (mReleasedTexImage).
+ status_t err = bindTextureImageLocked();
+ if (err != NO_ERROR) {
+ return err;
+ }
} else {
// detached, don't touch the texture (and we may not even have an
// EGLDisplay here.
@@ -332,29 +338,12 @@
return err;
}
- int slot = item->mBuf;
- bool destroyEglImage = false;
-
- if (mEglSlots[slot].mEglImage != EGL_NO_IMAGE_KHR) {
- if (item->mGraphicBuffer != NULL) {
- // This buffer has not been acquired before, so we must assume
- // that any EGLImage in mEglSlots is stale.
- destroyEglImage = true;
- } else if (mEglSlots[slot].mCropRect != item->mCrop) {
- // We've already seen this buffer before, but it now has a
- // different crop rect, so we'll need to recreate the EGLImage if
- // we're using the EGL_ANDROID_image_crop extension.
- destroyEglImage = hasEglAndroidImageCrop();
- }
- }
-
- if (destroyEglImage) {
- if (!eglDestroyImageKHR(mEglDisplay, mEglSlots[slot].mEglImage)) {
- ST_LOGW("acquireBufferLocked: eglDestroyImageKHR failed for slot=%d",
- slot);
- // keep going
- }
- mEglSlots[slot].mEglImage = EGL_NO_IMAGE_KHR;
+ // If item->mGraphicBuffer is not null, this buffer has not been acquired
+ // before, so any prior EglImage created is using a stale buffer. This
+ // replaces any old EglImage with a new one (using the new buffer).
+ if (item->mGraphicBuffer != NULL) {
+ int slot = item->mBuf;
+ mEglSlots[slot].mEglImage = new EglImage(item->mGraphicBuffer);
}
return NO_ERROR;
@@ -395,29 +384,18 @@
return err;
}
- // If the mEglSlot entry is empty, create an EGLImage for the gralloc
- // buffer currently in the slot in ConsumerBase.
- //
+ // Ensure we have a valid EglImageKHR for the slot, creating an EglImage
+ // if nessessary, 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, item.mCrop);
- if (image == EGL_NO_IMAGE_KHR) {
- ST_LOGW("updateAndRelease: unable to createImage on display=%p slot=%d",
- mEglDisplay, buf);
- const sp<GraphicBuffer>& gb = mSlots[buf].mGraphicBuffer;
- ST_LOGW("buffer size=%ux%u st=%u usage=0x%x fmt=%d",
- gb->getWidth(), gb->getHeight(), gb->getStride(),
- gb->getUsage(), gb->getPixelFormat());
- releaseBufferLocked(buf, mSlots[buf].mGraphicBuffer,
- mEglDisplay, EGL_NO_SYNC_KHR);
- return UNKNOWN_ERROR;
- }
- mEglSlots[buf].mEglImage = image;
- mEglSlots[buf].mCropRect = item.mCrop;
+ // means the buffer was previously acquired).
+ err = mEglSlots[buf].mEglImage->createIfNeeded(mEglDisplay, item.mCrop);
+ if (err != NO_ERROR) {
+ ST_LOGW("updateAndRelease: unable to createImage on display=%p slot=%d",
+ mEglDisplay, buf);
+ releaseBufferLocked(buf, mSlots[buf].mGraphicBuffer,
+ mEglDisplay, EGL_NO_SYNC_KHR);
+ return UNKNOWN_ERROR;
}
// Do whatever sync ops we need to do before releasing the old slot.
@@ -433,15 +411,15 @@
}
ST_LOGV("updateAndRelease: (slot=%d buf=%p) -> (slot=%d buf=%p)",
- mCurrentTexture,
- mCurrentTextureBuf != NULL ? mCurrentTextureBuf->handle : 0,
+ mCurrentTexture, mCurrentTextureImage != NULL ?
+ mCurrentTextureImage->graphicBufferHandle() : 0,
buf, mSlots[buf].mGraphicBuffer->handle);
// release old buffer
if (mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) {
status_t status = releaseBufferLocked(
- mCurrentTexture, mCurrentTextureBuf, mEglDisplay,
- mEglSlots[mCurrentTexture].mEglFence);
+ mCurrentTexture, mCurrentTextureImage->graphicBuffer(),
+ mEglDisplay, mEglSlots[mCurrentTexture].mEglFence);
if (status < NO_ERROR) {
ST_LOGE("updateAndRelease: failed to release buffer: %s (%d)",
strerror(-status), status);
@@ -452,7 +430,7 @@
// Update the GLConsumer state.
mCurrentTexture = buf;
- mCurrentTextureBuf = mSlots[buf].mGraphicBuffer;
+ mCurrentTextureImage = mEglSlots[buf].mEglImage;
mCurrentCrop = item.mCrop;
mCurrentTransform = item.mTransform;
mCurrentScalingMode = item.mScalingMode;
@@ -477,25 +455,26 @@
}
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;
+ if (mCurrentTexture == BufferQueue::INVALID_BUFFER_SLOT &&
+ mCurrentTextureImage == NULL) {
+ ST_LOGE("bindTextureImage: no currently-bound texture");
+ return NO_INIT;
+ }
- glEGLImageTargetTexture2DOES(mTexTarget, (GLeglImageOES)image);
+ status_t err = mCurrentTextureImage->createIfNeeded(mEglDisplay,
+ mCurrentCrop);
- while ((error = glGetError()) != GL_NO_ERROR) {
- ST_LOGE("bindTextureImage: error binding external texture image %p"
- ": %#04x", image, error);
- return UNKNOWN_ERROR;
- }
+ if (err != NO_ERROR) {
+ ST_LOGW("bindTextureImage: can't create image on display=%p slot=%d",
+ mEglDisplay, mCurrentTexture);
+ return UNKNOWN_ERROR;
+ }
+
+ mCurrentTextureImage->bindToTextureTarget(mTexTarget);
+
+ while ((error = glGetError()) != GL_NO_ERROR) {
+ ST_LOGE("bindTextureImage: error binding external image: %#04x", error);
+ return UNKNOWN_ERROR;
}
// Wait for the new buffer to be ready.
@@ -537,7 +516,7 @@
if (fence->isValid() &&
mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) {
status_t err = addReleaseFence(mCurrentTexture,
- mCurrentTextureBuf, fence);
+ mCurrentTextureImage->graphicBuffer(), fence);
if (err != OK) {
ST_LOGE("setReleaseFence: failed to add the fence: %s (%d)",
strerror(-err), err);
@@ -583,18 +562,6 @@
glDeleteTextures(1, &mTexName);
}
- // 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
- // 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;
- if (img != EGL_NO_IMAGE_KHR) {
- eglDestroyImageKHR(mEglDisplay, img);
- mEglSlots[i].mEglImage = EGL_NO_IMAGE_KHR;
- }
- }
-
mEglDisplay = EGL_NO_DISPLAY;
mEglContext = EGL_NO_CONTEXT;
mAttached = false;
@@ -635,56 +602,25 @@
// buffer.
glBindTexture(mTexTarget, GLuint(tex));
- if (mCurrentTextureBuf != NULL) {
- // The EGLImageKHR that was associated with the slot was destroyed when
- // the GLConsumer was detached from the old context, so we need to
- // recreate it here.
- status_t err = bindUnslottedBufferLocked(dpy);
- if (err != NO_ERROR) {
- return err;
- }
- }
-
mEglDisplay = dpy;
mEglContext = ctx;
mTexName = tex;
mAttached = true;
+ if (mCurrentTextureImage != NULL) {
+ // This may wait for a buffer a second time. This is likely required if
+ // this is a different context, since otherwise the wait could be skipped
+ // by bouncing through another context. For the same context the extra
+ // wait is redundant.
+ status_t err = bindTextureImageLocked();
+ if (err != NO_ERROR) {
+ return err;
+ }
+ }
+
return OK;
}
-status_t GLConsumer::bindUnslottedBufferLocked(EGLDisplay dpy) {
- ST_LOGV("bindUnslottedBuffer ct=%d ctb=%p",
- mCurrentTexture, mCurrentTextureBuf.get());
-
- // Create a temporary EGLImageKHR.
- Rect crop;
- EGLImageKHR image = createImage(dpy, mCurrentTextureBuf, mCurrentCrop);
- 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");
@@ -708,7 +644,7 @@
}
sp<Fence> fence(new Fence(fenceFd));
status_t err = addReleaseFenceLocked(mCurrentTexture,
- mCurrentTextureBuf, fence);
+ mCurrentTextureImage->graphicBuffer(), fence);
if (err != OK) {
ST_LOGE("syncForReleaseLocked: error adding release fence: "
"%s (%d)", strerror(-err), err);
@@ -787,11 +723,11 @@
bool needsRecompute = mFilteringEnabled != enabled;
mFilteringEnabled = enabled;
- if (needsRecompute && mCurrentTextureBuf==NULL) {
- ST_LOGD("setFilteringEnabled called with mCurrentTextureBuf == NULL");
+ if (needsRecompute && mCurrentTextureImage==NULL) {
+ ST_LOGD("setFilteringEnabled called with mCurrentTextureImage == NULL");
}
- if (needsRecompute && mCurrentTextureBuf != NULL) {
+ if (needsRecompute && mCurrentTextureImage != NULL) {
computeCurrentTransformMatrixLocked();
}
}
@@ -825,10 +761,11 @@
}
}
- sp<GraphicBuffer>& buf(mCurrentTextureBuf);
+ sp<GraphicBuffer> buf = (mCurrentTextureImage == NULL) ?
+ NULL : mCurrentTextureImage->graphicBuffer();
if (buf == NULL) {
- ST_LOGD("computeCurrentTransformMatrixLocked: mCurrentTextureBuf is NULL");
+ ST_LOGD("computeCurrentTransformMatrixLocked: mCurrentTextureImage is NULL");
}
float mtxBeforeFlipV[16];
@@ -911,39 +848,10 @@
return mCurrentFrameNumber;
}
-EGLImageKHR GLConsumer::createImage(EGLDisplay dpy,
- const sp<GraphicBuffer>& graphicBuffer, const Rect& crop) {
- EGLClientBuffer cbuf = (EGLClientBuffer)graphicBuffer->getNativeBuffer();
- EGLint attrs[] = {
- EGL_IMAGE_PRESERVED_KHR, EGL_TRUE,
- EGL_IMAGE_CROP_LEFT_ANDROID, crop.left,
- EGL_IMAGE_CROP_TOP_ANDROID, crop.top,
- EGL_IMAGE_CROP_RIGHT_ANDROID, crop.right,
- EGL_IMAGE_CROP_BOTTOM_ANDROID, crop.bottom,
- EGL_NONE,
- };
- if (!crop.isValid()) {
- // No crop rect to set, so terminate the attrib array before the crop.
- attrs[2] = EGL_NONE;
- } else if (!isEglImageCroppable(crop)) {
- // The crop rect is not at the origin, so we can't set the crop on the
- // EGLImage because that's not allowed by the EGL_ANDROID_image_crop
- // extension. In the future we can add a layered extension that
- // removes this restriction if there is hardware that can support it.
- attrs[2] = EGL_NONE;
- }
- EGLImageKHR image = eglCreateImageKHR(dpy, EGL_NO_CONTEXT,
- EGL_NATIVE_BUFFER_ANDROID, cbuf, attrs);
- if (image == EGL_NO_IMAGE_KHR) {
- EGLint error = eglGetError();
- ST_LOGE("error creating EGLImage: %#x", error);
- }
- return image;
-}
-
sp<GraphicBuffer> GLConsumer::getCurrentBuffer() const {
Mutex::Autolock lock(mMutex);
- return mCurrentTextureBuf;
+ return (mCurrentTextureImage == NULL) ?
+ NULL : mCurrentTextureImage->graphicBuffer();
}
Rect GLConsumer::getCurrentCrop() const {
@@ -1067,18 +975,13 @@
if (slotIndex == mCurrentTexture) {
mCurrentTexture = BufferQueue::INVALID_BUFFER_SLOT;
}
- EGLImageKHR img = mEglSlots[slotIndex].mEglImage;
- if (img != EGL_NO_IMAGE_KHR) {
- ST_LOGV("destroying EGLImage dpy=%p img=%p", mEglDisplay, img);
- eglDestroyImageKHR(mEglDisplay, img);
- }
- mEglSlots[slotIndex].mEglImage = EGL_NO_IMAGE_KHR;
+ mEglSlots[slotIndex].mEglImage.clear();
ConsumerBase::freeBufferLocked(slotIndex);
}
void GLConsumer::abandonLocked() {
ST_LOGV("abandonLocked");
- mCurrentTextureBuf.clear();
+ mCurrentTextureImage.clear();
ConsumerBase::abandonLocked();
}
@@ -1138,4 +1041,87 @@
out[15] = a[3]*b[12] + a[7]*b[13] + a[11]*b[14] + a[15]*b[15];
}
+GLConsumer::EglImage::EglImage(sp<GraphicBuffer> graphicBuffer) :
+ mGraphicBuffer(graphicBuffer),
+ mEglImage(EGL_NO_IMAGE_KHR),
+ mEglDisplay(EGL_NO_DISPLAY) {
+}
+
+GLConsumer::EglImage::~EglImage() {
+ if (mEglImage != EGL_NO_IMAGE_KHR) {
+ if (!eglDestroyImageKHR(mEglDisplay, mEglImage)) {
+ ALOGE("~EglImage: eglDestroyImageKHR failed");
+ }
+ }
+}
+
+status_t GLConsumer::EglImage::createIfNeeded(EGLDisplay eglDisplay,
+ const Rect& cropRect) {
+ // If there's an image and it's no longer valid, destroy it.
+ bool haveImage = mEglImage != EGL_NO_IMAGE_KHR;
+ bool displayInvalid = mEglDisplay != eglDisplay;
+ bool cropInvalid = hasEglAndroidImageCrop() && mCropRect != cropRect;
+ if (haveImage && (displayInvalid || cropInvalid)) {
+ if (!eglDestroyImageKHR(mEglDisplay, mEglImage)) {
+ ALOGE("createIfNeeded: eglDestroyImageKHR failed");
+ }
+ mEglImage = EGL_NO_IMAGE_KHR;
+ mEglDisplay = EGL_NO_DISPLAY;
+ }
+
+ // If there's no image, create one.
+ if (mEglImage == EGL_NO_IMAGE_KHR) {
+ mEglDisplay = eglDisplay;
+ mCropRect = cropRect;
+ mEglImage = createImage(mEglDisplay, mGraphicBuffer, mCropRect);
+ }
+
+ // Fail if we can't create a valid image.
+ if (mEglImage == EGL_NO_IMAGE_KHR) {
+ mEglDisplay = EGL_NO_DISPLAY;
+ mCropRect.makeInvalid();
+ const sp<GraphicBuffer>& buffer = mGraphicBuffer;
+ ALOGE("Failed to create image. size=%ux%u st=%u usage=0x%x fmt=%d",
+ buffer->getWidth(), buffer->getHeight(), buffer->getStride(),
+ buffer->getUsage(), buffer->getPixelFormat());
+ return UNKNOWN_ERROR;
+ }
+
+ return OK;
+}
+
+void GLConsumer::EglImage::bindToTextureTarget(uint32_t texTarget) {
+ glEGLImageTargetTexture2DOES(texTarget, (GLeglImageOES)mEglImage);
+}
+
+EGLImageKHR GLConsumer::EglImage::createImage(EGLDisplay dpy,
+ const sp<GraphicBuffer>& graphicBuffer, const Rect& crop) {
+ EGLClientBuffer cbuf = (EGLClientBuffer)graphicBuffer->getNativeBuffer();
+ EGLint attrs[] = {
+ EGL_IMAGE_PRESERVED_KHR, EGL_TRUE,
+ EGL_IMAGE_CROP_LEFT_ANDROID, crop.left,
+ EGL_IMAGE_CROP_TOP_ANDROID, crop.top,
+ EGL_IMAGE_CROP_RIGHT_ANDROID, crop.right,
+ EGL_IMAGE_CROP_BOTTOM_ANDROID, crop.bottom,
+ EGL_NONE,
+ };
+ if (!crop.isValid()) {
+ // No crop rect to set, so terminate the attrib array before the crop.
+ attrs[2] = EGL_NONE;
+ } else if (!isEglImageCroppable(crop)) {
+ // The crop rect is not at the origin, so we can't set the crop on the
+ // EGLImage because that's not allowed by the EGL_ANDROID_image_crop
+ // extension. In the future we can add a layered extension that
+ // removes this restriction if there is hardware that can support it.
+ attrs[2] = EGL_NONE;
+ }
+ EGLImageKHR image = eglCreateImageKHR(dpy, EGL_NO_CONTEXT,
+ EGL_NATIVE_BUFFER_ANDROID, cbuf, attrs);
+ if (image == EGL_NO_IMAGE_KHR) {
+ EGLint error = eglGetError();
+ ALOGE("error creating EGLImage: %#x", error);
+ }
+ return image;
+}
+
}; // namespace android
diff --git a/opengl/libs/Android.mk b/opengl/libs/Android.mk
index 6b90243..cc5d544 100644
--- a/opengl/libs/Android.mk
+++ b/opengl/libs/Android.mk
@@ -112,21 +112,16 @@
LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
LOCAL_CFLAGS += -fvisibility=hidden
-include $(BUILD_SHARED_LIBRARY)
-
# Symlink libGLESv3.so -> libGLESv2.so
# Platform modules should link against libGLESv2.so (-lGLESv2), but NDK apps
# will be linked against libGLESv3.so.
-LIBGLESV2 := $(LOCAL_INSTALLED_MODULE)
-LIBGLESV3 := $(subst libGLESv2,libGLESv3,$(LIBGLESV2))
-$(LIBGLESV3): $(LIBGLESV2)
- @echo "Symlink: $@ -> $(notdir $<)"
- @mkdir -p $(dir $@)
- $(hide) ln -sf $(notdir $<) $@
-ALL_MODULES.$(LOCAL_MODULE).INSTALLED := \
- $(ALL_MODULES.$(LOCAL_MODULE).INSTALLED) $(LIBGLESV3)
-LIBGLESV2 :=
-LIBGLESV3 :=
+# Note we defer the evaluation of the LOCAL_POST_INSTALL_CMD,
+# so $(LOCAL_INSTALLED_MODULE) will be expanded to correct value,
+# even for both 32-bit and 64-bit installed files in multilib build.
+LOCAL_POST_INSTALL_CMD = \
+ $(hide) ln -sf $(notdir $(LOCAL_INSTALLED_MODULE)) $(dir $(LOCAL_INSTALLED_MODULE))libGLESv3.so
+
+include $(BUILD_SHARED_LIBRARY)
###############################################################################
# Build the ETC1 host static library