Merge "Fix 5555408: allow emergency button to be disabled on SIM/PUK unlock screen" into ics-mr1
diff --git a/opengl/include/EGL/eglext.h b/opengl/include/EGL/eglext.h
index a08932a..8e8e26c 100644
--- a/opengl/include/EGL/eglext.h
+++ b/opengl/include/EGL/eglext.h
@@ -256,6 +256,21 @@
typedef EGLuint64NV (EGLAPIENTRYP PFNEGLGETSYSTEMTIMENVPROC)(void);
#endif
+
+/* EGL_ANDROID_blob_cache
+ */
+#ifndef EGL_ANDROID_blob_cache
+#define EGL_ANDROID_blob_cache 1
+typedef khronos_ssize_t EGLsizei;
+typedef void (*EGLSetBlobFunc) (const void* key, EGLsizei keySize, const void* value, EGLsizei valueSize);
+typedef EGLsizei (*EGLGetBlobFunc) (const void* key, EGLsizei keySize, void* value, EGLsizei valueSize);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI void EGLAPIENTRY eglSetBlobCacheFuncs(EGLDisplay dpy, EGLSetBlobFunc set, EGLGetBlobFunc get);
+#endif /* EGL_EGLEXT_PROTOTYPES */
+typedef void (EGLAPIENTRYP PFNEGLSETBLOBCACHEFUNCSPROC) (EGLDisplay dpy,
+ EGLSetBlobFunc set, EGLGetBlobFunc get);
+#endif
+
#ifdef __cplusplus
}
#endif
diff --git a/opengl/libs/EGL/egl_cache.cpp b/opengl/libs/EGL/egl_cache.cpp
index 1e64302..522421b 100644
--- a/opengl/libs/EGL/egl_cache.cpp
+++ b/opengl/libs/EGL/egl_cache.cpp
@@ -19,6 +19,24 @@
#include "egl_impl.h"
#include "egldefs.h"
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+// Cache size limits.
+static const size_t maxKeySize = 1024;
+static const size_t maxValueSize = 4096;
+static const size_t maxTotalSize = 64 * 1024;
+
+// Cache file header
+static const char* cacheFileMagic = "EGL$";
+static const size_t cacheFileHeaderSize = 8;
+
+// The time in seconds to wait before saving newly inserted cache entries.
+static const unsigned int deferredSaveDelay = 4;
+
// ----------------------------------------------------------------------------
namespace android {
// ----------------------------------------------------------------------------
@@ -26,37 +44,37 @@
#define BC_EXT_STR "EGL_ANDROID_blob_cache"
//
-// EGL_ANDROID_blob_cache types and functions
-//
-typedef khronos_ssize_t EGLsizei;
-
-typedef void (*EGLSetBlobFunc) (const void* key, EGLsizei keySize,
- const void* value, EGLsizei valueSize);
-
-typedef EGLsizei (*EGLGetBlobFunc) (const void* key, EGLsizei keySize,
- void* value, EGLsizei valueSize);
-
-typedef void (EGLAPIENTRYP PFNEGLSETBLOBCACHEFUNCSPROC) (EGLDisplay dpy,
- EGLSetBlobFunc set, EGLGetBlobFunc get);
-
-//
-// egl_cache_t definition
+// Callback functions passed to EGL.
//
static void setBlob(const void* key, EGLsizei keySize, const void* value,
EGLsizei valueSize) {
+ egl_cache_t::get()->setBlob(key, keySize, value, valueSize);
}
static EGLsizei getBlob(const void* key, EGLsizei keySize, void* value,
EGLsizei valueSize) {
- return 0;
+ return egl_cache_t::get()->getBlob(key, keySize, value, valueSize);
}
+//
+// egl_cache_t definition
+//
+egl_cache_t::egl_cache_t() :
+ mInitialized(false),
+ mBlobCache(NULL) {
+}
+
+egl_cache_t::~egl_cache_t() {
+}
+
+egl_cache_t egl_cache_t::sCache;
+
egl_cache_t* egl_cache_t::get() {
- static egl_cache_t theCache;
- return &theCache;
+ return &sCache;
}
void egl_cache_t::initialize(egl_display_t *display) {
+ Mutex::Autolock lock(mMutex);
for (int i = 0; i < IMPL_NUM_IMPLEMENTATIONS; i++) {
egl_connection_t* const cnx = &gEGLImpl[i];
if (cnx->dso && cnx->major >= 0 && cnx->minor >= 0) {
@@ -79,7 +97,8 @@
continue;
}
- eglSetBlobCacheFuncs(display->disp[i].dpy, setBlob, getBlob);
+ eglSetBlobCacheFuncs(display->disp[i].dpy, android::setBlob,
+ android::getBlob);
EGLint err = cnx->egl.eglGetError();
if (err != EGL_SUCCESS) {
LOGE("eglSetBlobCacheFuncs resulted in an error: %#x",
@@ -88,6 +107,234 @@
}
}
}
+ mInitialized = true;
+}
+
+void egl_cache_t::terminate() {
+ Mutex::Autolock lock(mMutex);
+ if (mBlobCache != NULL) {
+ saveBlobCacheLocked();
+ mBlobCache = NULL;
+ }
+ mInitialized = false;
+}
+
+void egl_cache_t::setBlob(const void* key, EGLsizei keySize, const void* value,
+ EGLsizei valueSize) {
+ Mutex::Autolock lock(mMutex);
+
+ if (keySize < 0 || valueSize < 0) {
+ LOGW("EGL_ANDROID_blob_cache set: negative sizes are not allowed");
+ return;
+ }
+
+ if (mInitialized) {
+ sp<BlobCache> bc = getBlobCacheLocked();
+ bc->set(key, keySize, value, valueSize);
+
+ if (!mSavePending) {
+ class DeferredSaveThread : public Thread {
+ public:
+ DeferredSaveThread() : Thread(false) {}
+
+ virtual bool threadLoop() {
+ sleep(deferredSaveDelay);
+ egl_cache_t* c = egl_cache_t::get();
+ Mutex::Autolock lock(c->mMutex);
+ if (c->mInitialized) {
+ c->saveBlobCacheLocked();
+ }
+ c->mSavePending = false;
+ return false;
+ }
+ };
+
+ // The thread will hold a strong ref to itself until it has finished
+ // running, so there's no need to keep a ref around.
+ sp<Thread> deferredSaveThread(new DeferredSaveThread());
+ mSavePending = true;
+ deferredSaveThread->run();
+ }
+ }
+}
+
+EGLsizei egl_cache_t::getBlob(const void* key, EGLsizei keySize, void* value,
+ EGLsizei valueSize) {
+ Mutex::Autolock lock(mMutex);
+
+ if (keySize < 0 || valueSize < 0) {
+ LOGW("EGL_ANDROID_blob_cache set: negative sizes are not allowed");
+ return 0;
+ }
+
+ if (mInitialized) {
+ sp<BlobCache> bc = getBlobCacheLocked();
+ return bc->get(key, keySize, value, valueSize);
+ }
+ return 0;
+}
+
+void egl_cache_t::setCacheFilename(const char* filename) {
+ Mutex::Autolock lock(mMutex);
+ mFilename = filename;
+}
+
+sp<BlobCache> egl_cache_t::getBlobCacheLocked() {
+ if (mBlobCache == NULL) {
+ mBlobCache = new BlobCache(maxKeySize, maxValueSize, maxTotalSize);
+ loadBlobCacheLocked();
+ }
+ return mBlobCache;
+}
+
+static uint32_t crc32c(const uint8_t* buf, size_t len) {
+ const uint32_t polyBits = 0x82F63B78;
+ uint32_t r = 0;
+ for (size_t i = 0; i < len; i++) {
+ r ^= buf[i];
+ for (int j = 0; j < 8; j++) {
+ if (r & 1) {
+ r = (r >> 1) ^ polyBits;
+ } else {
+ r >>= 1;
+ }
+ }
+ }
+ return r;
+}
+
+void egl_cache_t::saveBlobCacheLocked() {
+ if (mFilename.length() > 0) {
+ size_t cacheSize = mBlobCache->getFlattenedSize();
+ size_t headerSize = cacheFileHeaderSize;
+ const char* fname = mFilename.string();
+
+ // Try to create the file with no permissions so we can write it
+ // without anyone trying to read it.
+ int fd = open(fname, O_CREAT | O_EXCL | O_RDWR, 0);
+ if (fd == -1) {
+ if (errno == EEXIST) {
+ // The file exists, delete it and try again.
+ if (unlink(fname) == -1) {
+ // No point in retrying if the unlink failed.
+ LOGE("error unlinking cache file %s: %s (%d)", fname,
+ strerror(errno), errno);
+ return;
+ }
+ // Retry now that we've unlinked the file.
+ fd = open(fname, O_CREAT | O_EXCL | O_RDWR, 0);
+ }
+ if (fd == -1) {
+ LOGE("error creating cache file %s: %s (%d)", fname,
+ strerror(errno), errno);
+ return;
+ }
+ }
+
+ size_t fileSize = headerSize + cacheSize;
+ if (ftruncate(fd, fileSize) == -1) {
+ LOGE("error setting cache file size: %s (%d)", strerror(errno),
+ errno);
+ close(fd);
+ unlink(fname);
+ return;
+ }
+
+ uint8_t* buf = reinterpret_cast<uint8_t*>(mmap(NULL, fileSize,
+ PROT_WRITE, MAP_SHARED, fd, 0));
+ if (buf == MAP_FAILED) {
+ LOGE("error mmaping cache file: %s (%d)", strerror(errno),
+ errno);
+ close(fd);
+ unlink(fname);
+ return;
+ }
+
+ status_t err = mBlobCache->flatten(buf + headerSize, cacheSize, NULL,
+ 0);
+ if (err != OK) {
+ LOGE("error writing cache contents: %s (%d)", strerror(-err),
+ -err);
+ munmap(buf, fileSize);
+ close(fd);
+ unlink(fname);
+ return;
+ }
+
+ // Write the file magic and CRC
+ memcpy(buf, cacheFileMagic, 4);
+ uint32_t* crc = reinterpret_cast<uint32_t*>(buf + 4);
+ *crc = crc32c(buf + headerSize, cacheSize);
+
+ munmap(buf, fileSize);
+ fchmod(fd, S_IRUSR);
+ close(fd);
+ }
+}
+
+void egl_cache_t::loadBlobCacheLocked() {
+ if (mFilename.length() > 0) {
+ size_t headerSize = cacheFileHeaderSize;
+
+ int fd = open(mFilename.string(), O_RDONLY, 0);
+ if (fd == -1) {
+ if (errno != ENOENT) {
+ LOGE("error opening cache file %s: %s (%d)", mFilename.string(),
+ strerror(errno), errno);
+ }
+ return;
+ }
+
+ struct stat statBuf;
+ if (fstat(fd, &statBuf) == -1) {
+ LOGE("error stat'ing cache file: %s (%d)", strerror(errno), errno);
+ close(fd);
+ return;
+ }
+
+ // Sanity check the size before trying to mmap it.
+ size_t fileSize = statBuf.st_size;
+ if (fileSize > maxTotalSize * 2) {
+ LOGE("cache file is too large: %#llx", statBuf.st_size);
+ close(fd);
+ return;
+ }
+
+ uint8_t* buf = reinterpret_cast<uint8_t*>(mmap(NULL, fileSize,
+ PROT_READ, MAP_PRIVATE, fd, 0));
+ if (buf == MAP_FAILED) {
+ LOGE("error mmaping cache file: %s (%d)", strerror(errno),
+ errno);
+ close(fd);
+ return;
+ }
+
+ // Check the file magic and CRC
+ size_t cacheSize = fileSize - headerSize;
+ if (memcmp(buf, cacheFileMagic, 4) != 0) {
+ LOGE("cache file has bad mojo");
+ close(fd);
+ return;
+ }
+ uint32_t* crc = reinterpret_cast<uint32_t*>(buf + 4);
+ if (crc32c(buf + headerSize, cacheSize) != *crc) {
+ LOGE("cache file failed CRC check");
+ close(fd);
+ return;
+ }
+
+ status_t err = mBlobCache->unflatten(buf + headerSize, cacheSize, NULL, 0);
+ if (err != OK) {
+ LOGE("error reading cache contents: %s (%d)", strerror(-err),
+ -err);
+ munmap(buf, fileSize);
+ close(fd);
+ return;
+ }
+
+ munmap(buf, fileSize);
+ close(fd);
+ }
}
// ----------------------------------------------------------------------------
diff --git a/opengl/libs/EGL/egl_cache.h b/opengl/libs/EGL/egl_cache.h
index 1fcfacc..4389623 100644
--- a/opengl/libs/EGL/egl_cache.h
+++ b/opengl/libs/EGL/egl_cache.h
@@ -14,20 +14,117 @@
** limitations under the License.
*/
+#ifndef ANDROID_EGL_CACHE_H
+#define ANDROID_EGL_CACHE_H
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+
+#include <utils/BlobCache.h>
+#include <utils/String8.h>
+#include <utils/StrongPointer.h>
+
// ----------------------------------------------------------------------------
namespace android {
// ----------------------------------------------------------------------------
class egl_display_t;
-class egl_cache_t {
+class EGLAPI egl_cache_t {
public:
+ // get returns a pointer to the singleton egl_cache_t object. This
+ // singleton object will never be destroyed.
static egl_cache_t* get();
+ // initialize puts the egl_cache_t into an initialized state, such that it
+ // is able to insert and retrieve entries from the cache. This should be
+ // called when EGL is initialized. When not in the initialized state the
+ // getBlob and setBlob methods will return without performing any cache
+ // operations.
void initialize(egl_display_t* display);
+
+ // terminate puts the egl_cache_t back into the uninitialized state. When
+ // in this state the getBlob and setBlob methods will return without
+ // performing any cache operations.
+ void terminate();
+
+ // setBlob attempts to insert a new key/value blob pair into the cache.
+ // This will be called by the hardware vendor's EGL implementation via the
+ // EGL_ANDROID_blob_cache extension.
+ void setBlob(const void* key, EGLsizei keySize, const void* value,
+ EGLsizei valueSize);
+
+ // getBlob attempts to retrieve the value blob associated with a given key
+ // blob from cache. This will be called by the hardware vendor's EGL
+ // implementation via the EGL_ANDROID_blob_cache extension.
+ EGLsizei getBlob(const void* key, EGLsizei keySize, void* value,
+ EGLsizei valueSize);
+
+ // setCacheFilename sets the name of the file that should be used to store
+ // cache contents from one program invocation to another.
+ void setCacheFilename(const char* filename);
+
+private:
+ // Creation and (the lack of) destruction is handled internally.
+ egl_cache_t();
+ ~egl_cache_t();
+
+ // Copying is disallowed.
+ egl_cache_t(const egl_cache_t&); // not implemented
+ void operator=(const egl_cache_t&); // not implemented
+
+ // getBlobCacheLocked returns the BlobCache object being used to store the
+ // key/value blob pairs. If the BlobCache object has not yet been created,
+ // this will do so, loading the serialized cache contents from disk if
+ // possible.
+ sp<BlobCache> getBlobCacheLocked();
+
+ // saveBlobCache attempts to save the current contents of mBlobCache to
+ // disk.
+ void saveBlobCacheLocked();
+
+ // loadBlobCache attempts to load the saved cache contents from disk into
+ // mBlobCache.
+ void loadBlobCacheLocked();
+
+ // mInitialized indicates whether the egl_cache_t is in the initialized
+ // state. It is initialized to false at construction time, and gets set to
+ // true when initialize is called. It is set back to false when terminate
+ // is called. When in this state, the cache behaves as normal. When not,
+ // the getBlob and setBlob methods will return without performing any cache
+ // operations.
+ bool mInitialized;
+
+ // mBlobCache is the cache in which the key/value blob pairs are stored. It
+ // is initially NULL, and will be initialized by getBlobCacheLocked the
+ // first time it's needed.
+ sp<BlobCache> mBlobCache;
+
+ // mFilename is the name of the file for storing cache contents in between
+ // program invocations. It is initialized to an empty string at
+ // construction time, and can be set with the setCacheFilename method. An
+ // empty string indicates that the cache should not be saved to or restored
+ // from disk.
+ String8 mFilename;
+
+ // mSavePending indicates whether or not a deferred save operation is
+ // pending. Each time a key/value pair is inserted into the cache via
+ // setBlob, a deferred save is initiated if one is not already pending.
+ // This will wait some amount of time and then trigger a save of the cache
+ // contents to disk.
+ bool mSavePending;
+
+ // mMutex is the mutex used to prevent concurrent access to the member
+ // variables. It must be locked whenever the member variables are accessed.
+ mutable Mutex mMutex;
+
+ // sCache is the singleton egl_cache_t object.
+ static egl_cache_t sCache;
};
// ----------------------------------------------------------------------------
}; // namespace android
// ----------------------------------------------------------------------------
+
+#endif // ANDROID_EGL_CACHE_H
diff --git a/opengl/libs/EGL/egl_display.cpp b/opengl/libs/EGL/egl_display.cpp
index 0f92864..558ca77 100644
--- a/opengl/libs/EGL/egl_display.cpp
+++ b/opengl/libs/EGL/egl_display.cpp
@@ -44,6 +44,7 @@
egl_display_t::~egl_display_t() {
magic = 0;
+ egl_cache_t::get()->terminate();
}
egl_display_t* egl_display_t::get(EGLDisplay dpy) {
diff --git a/opengl/libs/EGL/egl_display.h b/opengl/libs/EGL/egl_display.h
index 113595f..1c1092c 100644
--- a/opengl/libs/EGL/egl_display.h
+++ b/opengl/libs/EGL/egl_display.h
@@ -59,7 +59,7 @@
// ----------------------------------------------------------------------------
-class egl_display_t {
+class EGLAPI egl_display_t { // marked as EGLAPI for testing purposes
static egl_display_t sDisplay[NUM_DISPLAYS];
EGLDisplay getDisplay(EGLNativeDisplayType display);
@@ -141,4 +141,3 @@
// ----------------------------------------------------------------------------
#endif // ANDROID_EGL_DISPLAY_H
-
diff --git a/opengl/tests/EGLTest/Android.mk b/opengl/tests/EGLTest/Android.mk
index 92d7eb1..14104d1 100644
--- a/opengl/tests/EGLTest/Android.mk
+++ b/opengl/tests/EGLTest/Android.mk
@@ -7,6 +7,7 @@
LOCAL_MODULE_TAGS := tests
LOCAL_SRC_FILES := \
+ egl_cache_test.cpp \
EGL_test.cpp \
LOCAL_SHARED_LIBRARIES := \
@@ -21,9 +22,12 @@
LOCAL_C_INCLUDES := \
bionic \
+ bionic/libc/private \
bionic/libstdc++/include \
external/gtest/include \
external/stlport/stlport \
+ frameworks/base/opengl/libs \
+ frameworks/base/opengl/libs/EGL \
include $(BUILD_EXECUTABLE)
diff --git a/opengl/tests/EGLTest/egl_cache_test.cpp b/opengl/tests/EGLTest/egl_cache_test.cpp
new file mode 100644
index 0000000..c7d9e3e
--- /dev/null
+++ b/opengl/tests/EGLTest/egl_cache_test.cpp
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "EGL_test"
+//#define LOG_NDEBUG 0
+
+#include <gtest/gtest.h>
+
+#include <utils/Log.h>
+
+#include "egl_cache.h"
+#include "egl_display.h"
+
+namespace android {
+
+class EGLCacheTest : public ::testing::Test {
+protected:
+ virtual void SetUp() {
+ mCache = egl_cache_t::get();
+ }
+
+ virtual void TearDown() {
+ mCache->setCacheFilename("");
+ mCache->terminate();
+ }
+
+ egl_cache_t* mCache;
+};
+
+TEST_F(EGLCacheTest, UninitializedCacheAlwaysMisses) {
+ char buf[4] = { 0xee, 0xee, 0xee, 0xee };
+ mCache->setBlob("abcd", 4, "efgh", 4);
+ ASSERT_EQ(0, mCache->getBlob("abcd", 4, buf, 4));
+ ASSERT_EQ(0xee, buf[0]);
+ ASSERT_EQ(0xee, buf[1]);
+ ASSERT_EQ(0xee, buf[2]);
+ ASSERT_EQ(0xee, buf[3]);
+}
+
+TEST_F(EGLCacheTest, InitializedCacheAlwaysHits) {
+ char buf[4] = { 0xee, 0xee, 0xee, 0xee };
+ mCache->initialize(egl_display_t::get(EGL_DEFAULT_DISPLAY));
+ mCache->setBlob("abcd", 4, "efgh", 4);
+ ASSERT_EQ(4, mCache->getBlob("abcd", 4, buf, 4));
+ ASSERT_EQ('e', buf[0]);
+ ASSERT_EQ('f', buf[1]);
+ ASSERT_EQ('g', buf[2]);
+ ASSERT_EQ('h', buf[3]);
+}
+
+TEST_F(EGLCacheTest, TerminatedCacheAlwaysMisses) {
+ char buf[4] = { 0xee, 0xee, 0xee, 0xee };
+ mCache->initialize(egl_display_t::get(EGL_DEFAULT_DISPLAY));
+ mCache->setBlob("abcd", 4, "efgh", 4);
+ mCache->terminate();
+ ASSERT_EQ(0, mCache->getBlob("abcd", 4, buf, 4));
+ ASSERT_EQ(0xee, buf[0]);
+ ASSERT_EQ(0xee, buf[1]);
+ ASSERT_EQ(0xee, buf[2]);
+ ASSERT_EQ(0xee, buf[3]);
+}
+
+class EGLCacheSerializationTest : public EGLCacheTest {
+
+protected:
+
+ virtual void SetUp() {
+ EGLCacheTest::SetUp();
+
+ char* tn = tempnam("/sdcard", "EGL_test-cache-");
+ mFilename = tn;
+ free(tn);
+ }
+
+ virtual void TearDown() {
+ unlink(mFilename.string());
+ EGLCacheTest::TearDown();
+ }
+
+ String8 mFilename;
+};
+
+TEST_F(EGLCacheSerializationTest, ReinitializedCacheContainsValues) {
+ char buf[4] = { 0xee, 0xee, 0xee, 0xee };
+ mCache->setCacheFilename(mFilename);
+ mCache->initialize(egl_display_t::get(EGL_DEFAULT_DISPLAY));
+ mCache->setBlob("abcd", 4, "efgh", 4);
+ mCache->terminate();
+ mCache->initialize(egl_display_t::get(EGL_DEFAULT_DISPLAY));
+ ASSERT_EQ(4, mCache->getBlob("abcd", 4, buf, 4));
+ ASSERT_EQ('e', buf[0]);
+ ASSERT_EQ('f', buf[1]);
+ ASSERT_EQ('g', buf[2]);
+ ASSERT_EQ('h', buf[3]);
+}
+
+}
diff --git a/services/surfaceflinger/LayerScreenshot.cpp b/services/surfaceflinger/LayerScreenshot.cpp
index e30ccbf..68e6660 100644
--- a/services/surfaceflinger/LayerScreenshot.cpp
+++ b/services/surfaceflinger/LayerScreenshot.cpp
@@ -27,6 +27,7 @@
#include "SurfaceFlinger.h"
#include "DisplayHardware/DisplayHardware.h"
+
namespace android {
// ---------------------------------------------------------------------------
@@ -45,23 +46,64 @@
}
}
+status_t LayerScreenshot::captureLocked() {
+ GLfloat u, v;
+ status_t result = mFlinger->renderScreenToTextureLocked(0, &mTextureName, &u, &v);
+ if (result != NO_ERROR) {
+ return result;
+ }
+ initTexture(u, v);
+ return NO_ERROR;
+}
+
status_t LayerScreenshot::capture() {
GLfloat u, v;
status_t result = mFlinger->renderScreenToTexture(0, &mTextureName, &u, &v);
if (result != NO_ERROR) {
return result;
}
+ initTexture(u, v);
+ return NO_ERROR;
+}
+void LayerScreenshot::initTexture(GLfloat u, GLfloat v) {
glBindTexture(GL_TEXTURE_2D, mTextureName);
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
-
mTexCoords[0] = 0; mTexCoords[1] = v;
mTexCoords[2] = 0; mTexCoords[3] = 0;
mTexCoords[4] = u; mTexCoords[5] = 0;
mTexCoords[6] = u; mTexCoords[7] = v;
+}
- return NO_ERROR;
+void LayerScreenshot::initStates(uint32_t w, uint32_t h, uint32_t flags) {
+ LayerBaseClient::initStates(w, h, flags);
+ if (!(flags & ISurfaceComposer::eHidden)) {
+ capture();
+ }
+}
+
+uint32_t LayerScreenshot::doTransaction(uint32_t flags)
+{
+ const Layer::State& draw(drawingState());
+ const Layer::State& curr(currentState());
+
+ if (draw.flags & ISurfaceComposer::eLayerHidden) {
+ if (!(curr.flags & ISurfaceComposer::eLayerHidden)) {
+ // we're going from hidden to visible
+ status_t err = captureLocked();
+ if (err != NO_ERROR) {
+ LOGW("createScreenshotSurface failed (%s)", strerror(-err));
+ }
+ }
+ } else if (curr.flags & ISurfaceComposer::eLayerHidden) {
+ // we're going from visible to hidden
+ if (mTextureName) {
+ glDeleteTextures(1, &mTextureName);
+ mTextureName = 0;
+ }
+ }
+ return LayerBaseClient::doTransaction(flags);
}
void LayerScreenshot::onDraw(const Region& clip) const
diff --git a/services/surfaceflinger/LayerScreenshot.h b/services/surfaceflinger/LayerScreenshot.h
index e3a2b19..ab90047 100644
--- a/services/surfaceflinger/LayerScreenshot.h
+++ b/services/surfaceflinger/LayerScreenshot.h
@@ -41,12 +41,18 @@
status_t capture();
+ virtual void initStates(uint32_t w, uint32_t h, uint32_t flags);
+ virtual uint32_t doTransaction(uint32_t flags);
virtual void onDraw(const Region& clip) const;
virtual bool isOpaque() const { return false; }
virtual bool isSecure() const { return false; }
virtual bool isProtectedByApp() const { return false; }
virtual bool isProtectedByDRM() const { return false; }
virtual const char* getTypeId() const { return "LayerScreenshot"; }
+
+private:
+ status_t captureLocked();
+ void initTexture(GLfloat u, GLfloat v);
};
// ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index a6d4147..1b00e93 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -1217,23 +1217,25 @@
sp<Client> client( static_cast<Client *>(s.client.get()) );
transactionFlags |= setClientStateLocked(client, s.state);
}
- if (transactionFlags) {
- setTransactionFlags(transactionFlags);
- }
- // if this is a synchronous transaction, wait for it to take effect before
- // returning.
- if (flags & eSynchronous) {
- mTransationPending = true;
- }
- while (mTransationPending) {
- status_t err = mTransactionCV.waitRelative(mStateLock, s2ns(5));
- if (CC_UNLIKELY(err != NO_ERROR)) {
- // just in case something goes wrong in SF, return to the
- // called after a few seconds.
- LOGW_IF(err == TIMED_OUT, "closeGlobalTransaction timed out!");
- mTransationPending = false;
- break;
+ if (transactionFlags) {
+ // this triggers the transaction
+ setTransactionFlags(transactionFlags);
+
+ // if this is a synchronous transaction, wait for it to take effect
+ // before returning.
+ if (flags & eSynchronous) {
+ mTransationPending = true;
+ }
+ while (mTransationPending) {
+ status_t err = mTransactionCV.waitRelative(mStateLock, s2ns(5));
+ if (CC_UNLIKELY(err != NO_ERROR)) {
+ // just in case something goes wrong in SF, return to the
+ // called after a few seconds.
+ LOGW_IF(err == TIMED_OUT, "closeGlobalTransaction timed out!");
+ mTransationPending = false;
+ break;
+ }
}
}
}
@@ -1360,11 +1362,6 @@
uint32_t w, uint32_t h, uint32_t flags)
{
sp<LayerScreenshot> layer = new LayerScreenshot(this, display, client);
- status_t err = layer->capture();
- if (err != NO_ERROR) {
- layer.clear();
- LOGW("createScreenshotSurface failed (%s)", strerror(-err));
- }
return layer;
}
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index ea5bfa7..17028db 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -186,6 +186,8 @@
status_t renderScreenToTexture(DisplayID dpy,
GLuint* textureName, GLfloat* uOut, GLfloat* vOut);
+ status_t renderScreenToTextureLocked(DisplayID dpy,
+ GLuint* textureName, GLfloat* uOut, GLfloat* vOut);
status_t postMessageAsync(const sp<MessageBase>& msg,
nsecs_t reltime=0, uint32_t flags = 0);
@@ -328,8 +330,6 @@
status_t turnElectronBeamOnImplLocked(int32_t mode);
status_t electronBeamOffAnimationImplLocked();
status_t electronBeamOnAnimationImplLocked();
- status_t renderScreenToTextureLocked(DisplayID dpy,
- GLuint* textureName, GLfloat* uOut, GLfloat* vOut);
void debugFlashRegions();
void debugShowFPS() const;