am 3cb007e4: am 911263dc: Merge changes I18e5e789,I5cbaae2d into ics-mr1
* commit '3cb007e44db1e169747528f62a118575f3b04d56': EGL: implement loading and saving the cache EGL: use an in-memory the blob cache
This commit is contained in:
commit
2ea8829002
@ -256,6 +256,21 @@ typedef EGLuint64NV (EGLAPIENTRYP PFNEGLGETSYSTEMTIMEFREQUENCYNVPROC)(void);
|
|||||||
typedef EGLuint64NV (EGLAPIENTRYP PFNEGLGETSYSTEMTIMENVPROC)(void);
|
typedef EGLuint64NV (EGLAPIENTRYP PFNEGLGETSYSTEMTIMENVPROC)(void);
|
||||||
#endif
|
#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
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -19,6 +19,21 @@
|
|||||||
#include "egl_impl.h"
|
#include "egl_impl.h"
|
||||||
#include "egldefs.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;
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
namespace android {
|
namespace android {
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
@ -26,37 +41,37 @@ namespace android {
|
|||||||
#define BC_EXT_STR "EGL_ANDROID_blob_cache"
|
#define BC_EXT_STR "EGL_ANDROID_blob_cache"
|
||||||
|
|
||||||
//
|
//
|
||||||
// EGL_ANDROID_blob_cache types and functions
|
// Callback functions passed to EGL.
|
||||||
//
|
|
||||||
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
|
|
||||||
//
|
//
|
||||||
static void setBlob(const void* key, EGLsizei keySize, const void* value,
|
static void setBlob(const void* key, EGLsizei keySize, const void* value,
|
||||||
EGLsizei valueSize) {
|
EGLsizei valueSize) {
|
||||||
|
egl_cache_t::get()->setBlob(key, keySize, value, valueSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
static EGLsizei getBlob(const void* key, EGLsizei keySize, void* value,
|
static EGLsizei getBlob(const void* key, EGLsizei keySize, void* value,
|
||||||
EGLsizei valueSize) {
|
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() {
|
egl_cache_t* egl_cache_t::get() {
|
||||||
static egl_cache_t theCache;
|
return &sCache;
|
||||||
return &theCache;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void egl_cache_t::initialize(egl_display_t *display) {
|
void egl_cache_t::initialize(egl_display_t *display) {
|
||||||
|
Mutex::Autolock lock(mMutex);
|
||||||
for (int i = 0; i < IMPL_NUM_IMPLEMENTATIONS; i++) {
|
for (int i = 0; i < IMPL_NUM_IMPLEMENTATIONS; i++) {
|
||||||
egl_connection_t* const cnx = &gEGLImpl[i];
|
egl_connection_t* const cnx = &gEGLImpl[i];
|
||||||
if (cnx->dso && cnx->major >= 0 && cnx->minor >= 0) {
|
if (cnx->dso && cnx->major >= 0 && cnx->minor >= 0) {
|
||||||
@ -79,7 +94,8 @@ void egl_cache_t::initialize(egl_display_t *display) {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
eglSetBlobCacheFuncs(display->disp[i].dpy, setBlob, getBlob);
|
eglSetBlobCacheFuncs(display->disp[i].dpy, android::setBlob,
|
||||||
|
android::getBlob);
|
||||||
EGLint err = cnx->egl.eglGetError();
|
EGLint err = cnx->egl.eglGetError();
|
||||||
if (err != EGL_SUCCESS) {
|
if (err != EGL_SUCCESS) {
|
||||||
LOGE("eglSetBlobCacheFuncs resulted in an error: %#x",
|
LOGE("eglSetBlobCacheFuncs resulted in an error: %#x",
|
||||||
@ -88,6 +104,210 @@ void egl_cache_t::initialize(egl_display_t *display) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
@ -14,20 +14,110 @@
|
|||||||
** limitations under the License.
|
** 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 {
|
namespace android {
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
class egl_display_t;
|
class egl_display_t;
|
||||||
|
|
||||||
class egl_cache_t {
|
class EGLAPI egl_cache_t {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
// get returns a pointer to the singleton egl_cache_t object. This
|
||||||
|
// singleton object will never be destroyed.
|
||||||
static egl_cache_t* get();
|
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);
|
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;
|
||||||
|
|
||||||
|
// 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
|
}; // namespace android
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#endif // ANDROID_EGL_CACHE_H
|
||||||
|
@ -44,6 +44,7 @@ egl_display_t::egl_display_t() :
|
|||||||
|
|
||||||
egl_display_t::~egl_display_t() {
|
egl_display_t::~egl_display_t() {
|
||||||
magic = 0;
|
magic = 0;
|
||||||
|
egl_cache_t::get()->terminate();
|
||||||
}
|
}
|
||||||
|
|
||||||
egl_display_t* egl_display_t::get(EGLDisplay dpy) {
|
egl_display_t* egl_display_t::get(EGLDisplay dpy) {
|
||||||
|
@ -59,7 +59,7 @@ struct egl_config_t {
|
|||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
class egl_display_t {
|
class EGLAPI egl_display_t { // marked as EGLAPI for testing purposes
|
||||||
static egl_display_t sDisplay[NUM_DISPLAYS];
|
static egl_display_t sDisplay[NUM_DISPLAYS];
|
||||||
EGLDisplay getDisplay(EGLNativeDisplayType display);
|
EGLDisplay getDisplay(EGLNativeDisplayType display);
|
||||||
|
|
||||||
@ -141,4 +141,3 @@ EGLBoolean validate_display_surface(EGLDisplay dpy, EGLSurface surface);
|
|||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
#endif // ANDROID_EGL_DISPLAY_H
|
#endif // ANDROID_EGL_DISPLAY_H
|
||||||
|
|
||||||
|
@ -7,6 +7,7 @@ LOCAL_MODULE := EGL_test
|
|||||||
LOCAL_MODULE_TAGS := tests
|
LOCAL_MODULE_TAGS := tests
|
||||||
|
|
||||||
LOCAL_SRC_FILES := \
|
LOCAL_SRC_FILES := \
|
||||||
|
egl_cache_test.cpp \
|
||||||
EGL_test.cpp \
|
EGL_test.cpp \
|
||||||
|
|
||||||
LOCAL_SHARED_LIBRARIES := \
|
LOCAL_SHARED_LIBRARIES := \
|
||||||
@ -21,9 +22,12 @@ LOCAL_STATIC_LIBRARIES := \
|
|||||||
|
|
||||||
LOCAL_C_INCLUDES := \
|
LOCAL_C_INCLUDES := \
|
||||||
bionic \
|
bionic \
|
||||||
|
bionic/libc/private \
|
||||||
bionic/libstdc++/include \
|
bionic/libstdc++/include \
|
||||||
external/gtest/include \
|
external/gtest/include \
|
||||||
external/stlport/stlport \
|
external/stlport/stlport \
|
||||||
|
frameworks/base/opengl/libs \
|
||||||
|
frameworks/base/opengl/libs/EGL \
|
||||||
|
|
||||||
include $(BUILD_EXECUTABLE)
|
include $(BUILD_EXECUTABLE)
|
||||||
|
|
||||||
|
110
opengl/tests/EGLTest/egl_cache_test.cpp
Normal file
110
opengl/tests/EGLTest/egl_cache_test.cpp
Normal file
@ -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]);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user