Skip to content

Commit 911263d

Browse files
Jamie GennisAndroid (Google) Code Review
authored andcommitted
Merge changes I18e5e789,I5cbaae2d into ics-mr1
* changes: EGL: implement loading and saving the cache EGL: use an in-memory the blob cache
2 parents 95482b6 + d90bf39 commit 911263d

File tree

7 files changed

+460
-21
lines changed

7 files changed

+460
-21
lines changed

opengl/include/EGL/eglext.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,21 @@ typedef EGLuint64NV (EGLAPIENTRYP PFNEGLGETSYSTEMTIMEFREQUENCYNVPROC)(void);
256256
typedef EGLuint64NV (EGLAPIENTRYP PFNEGLGETSYSTEMTIMENVPROC)(void);
257257
#endif
258258

259+
260+
/* EGL_ANDROID_blob_cache
261+
*/
262+
#ifndef EGL_ANDROID_blob_cache
263+
#define EGL_ANDROID_blob_cache 1
264+
typedef khronos_ssize_t EGLsizei;
265+
typedef void (*EGLSetBlobFunc) (const void* key, EGLsizei keySize, const void* value, EGLsizei valueSize);
266+
typedef EGLsizei (*EGLGetBlobFunc) (const void* key, EGLsizei keySize, void* value, EGLsizei valueSize);
267+
#ifdef EGL_EGLEXT_PROTOTYPES
268+
EGLAPI void EGLAPIENTRY eglSetBlobCacheFuncs(EGLDisplay dpy, EGLSetBlobFunc set, EGLGetBlobFunc get);
269+
#endif /* EGL_EGLEXT_PROTOTYPES */
270+
typedef void (EGLAPIENTRYP PFNEGLSETBLOBCACHEFUNCSPROC) (EGLDisplay dpy,
271+
EGLSetBlobFunc set, EGLGetBlobFunc get);
272+
#endif
273+
259274
#ifdef __cplusplus
260275
}
261276
#endif

opengl/libs/EGL/egl_cache.cpp

Lines changed: 238 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -19,44 +19,59 @@
1919
#include "egl_impl.h"
2020
#include "egldefs.h"
2121

22+
#include <fcntl.h>
23+
#include <sys/mman.h>
24+
#include <sys/stat.h>
25+
#include <sys/types.h>
26+
#include <unistd.h>
27+
28+
// Cache size limits.
29+
static const size_t maxKeySize = 1024;
30+
static const size_t maxValueSize = 4096;
31+
static const size_t maxTotalSize = 64 * 1024;
32+
33+
// Cache file header
34+
static const char* cacheFileMagic = "EGL$";
35+
static const size_t cacheFileHeaderSize = 8;
36+
2237
// ----------------------------------------------------------------------------
2338
namespace android {
2439
// ----------------------------------------------------------------------------
2540

2641
#define BC_EXT_STR "EGL_ANDROID_blob_cache"
2742

2843
//
29-
// EGL_ANDROID_blob_cache types and functions
44+
// Callback functions passed to EGL.
3045
//
31-
typedef khronos_ssize_t EGLsizei;
32-
33-
typedef void (*EGLSetBlobFunc) (const void* key, EGLsizei keySize,
34-
const void* value, EGLsizei valueSize);
35-
36-
typedef EGLsizei (*EGLGetBlobFunc) (const void* key, EGLsizei keySize,
37-
void* value, EGLsizei valueSize);
46+
static void setBlob(const void* key, EGLsizei keySize, const void* value,
47+
EGLsizei valueSize) {
48+
egl_cache_t::get()->setBlob(key, keySize, value, valueSize);
49+
}
3850

39-
typedef void (EGLAPIENTRYP PFNEGLSETBLOBCACHEFUNCSPROC) (EGLDisplay dpy,
40-
EGLSetBlobFunc set, EGLGetBlobFunc get);
51+
static EGLsizei getBlob(const void* key, EGLsizei keySize, void* value,
52+
EGLsizei valueSize) {
53+
return egl_cache_t::get()->getBlob(key, keySize, value, valueSize);
54+
}
4155

4256
//
4357
// egl_cache_t definition
4458
//
45-
static void setBlob(const void* key, EGLsizei keySize, const void* value,
46-
EGLsizei valueSize) {
59+
egl_cache_t::egl_cache_t() :
60+
mInitialized(false),
61+
mBlobCache(NULL) {
4762
}
4863

49-
static EGLsizei getBlob(const void* key, EGLsizei keySize, void* value,
50-
EGLsizei valueSize) {
51-
return 0;
64+
egl_cache_t::~egl_cache_t() {
5265
}
5366

67+
egl_cache_t egl_cache_t::sCache;
68+
5469
egl_cache_t* egl_cache_t::get() {
55-
static egl_cache_t theCache;
56-
return &theCache;
70+
return &sCache;
5771
}
5872

5973
void egl_cache_t::initialize(egl_display_t *display) {
74+
Mutex::Autolock lock(mMutex);
6075
for (int i = 0; i < IMPL_NUM_IMPLEMENTATIONS; i++) {
6176
egl_connection_t* const cnx = &gEGLImpl[i];
6277
if (cnx->dso && cnx->major >= 0 && cnx->minor >= 0) {
@@ -79,7 +94,8 @@ void egl_cache_t::initialize(egl_display_t *display) {
7994
continue;
8095
}
8196

82-
eglSetBlobCacheFuncs(display->disp[i].dpy, setBlob, getBlob);
97+
eglSetBlobCacheFuncs(display->disp[i].dpy, android::setBlob,
98+
android::getBlob);
8399
EGLint err = cnx->egl.eglGetError();
84100
if (err != EGL_SUCCESS) {
85101
LOGE("eglSetBlobCacheFuncs resulted in an error: %#x",
@@ -88,6 +104,210 @@ void egl_cache_t::initialize(egl_display_t *display) {
88104
}
89105
}
90106
}
107+
mInitialized = true;
108+
}
109+
110+
void egl_cache_t::terminate() {
111+
Mutex::Autolock lock(mMutex);
112+
if (mBlobCache != NULL) {
113+
saveBlobCacheLocked();
114+
mBlobCache = NULL;
115+
}
116+
mInitialized = false;
117+
}
118+
119+
void egl_cache_t::setBlob(const void* key, EGLsizei keySize, const void* value,
120+
EGLsizei valueSize) {
121+
Mutex::Autolock lock(mMutex);
122+
123+
if (keySize < 0 || valueSize < 0) {
124+
LOGW("EGL_ANDROID_blob_cache set: negative sizes are not allowed");
125+
return;
126+
}
127+
128+
if (mInitialized) {
129+
sp<BlobCache> bc = getBlobCacheLocked();
130+
bc->set(key, keySize, value, valueSize);
131+
}
132+
}
133+
134+
EGLsizei egl_cache_t::getBlob(const void* key, EGLsizei keySize, void* value,
135+
EGLsizei valueSize) {
136+
Mutex::Autolock lock(mMutex);
137+
138+
if (keySize < 0 || valueSize < 0) {
139+
LOGW("EGL_ANDROID_blob_cache set: negative sizes are not allowed");
140+
return 0;
141+
}
142+
143+
if (mInitialized) {
144+
sp<BlobCache> bc = getBlobCacheLocked();
145+
return bc->get(key, keySize, value, valueSize);
146+
}
147+
return 0;
148+
}
149+
150+
void egl_cache_t::setCacheFilename(const char* filename) {
151+
Mutex::Autolock lock(mMutex);
152+
mFilename = filename;
153+
}
154+
155+
sp<BlobCache> egl_cache_t::getBlobCacheLocked() {
156+
if (mBlobCache == NULL) {
157+
mBlobCache = new BlobCache(maxKeySize, maxValueSize, maxTotalSize);
158+
loadBlobCacheLocked();
159+
}
160+
return mBlobCache;
161+
}
162+
163+
static uint32_t crc32c(const uint8_t* buf, size_t len) {
164+
const uint32_t polyBits = 0x82F63B78;
165+
uint32_t r = 0;
166+
for (size_t i = 0; i < len; i++) {
167+
r ^= buf[i];
168+
for (int j = 0; j < 8; j++) {
169+
if (r & 1) {
170+
r = (r >> 1) ^ polyBits;
171+
} else {
172+
r >>= 1;
173+
}
174+
}
175+
}
176+
return r;
177+
}
178+
179+
void egl_cache_t::saveBlobCacheLocked() {
180+
if (mFilename.length() > 0) {
181+
size_t cacheSize = mBlobCache->getFlattenedSize();
182+
size_t headerSize = cacheFileHeaderSize;
183+
const char* fname = mFilename.string();
184+
185+
// Try to create the file with no permissions so we can write it
186+
// without anyone trying to read it.
187+
int fd = open(fname, O_CREAT | O_EXCL | O_RDWR, 0);
188+
if (fd == -1) {
189+
if (errno == EEXIST) {
190+
// The file exists, delete it and try again.
191+
if (unlink(fname) == -1) {
192+
// No point in retrying if the unlink failed.
193+
LOGE("error unlinking cache file %s: %s (%d)", fname,
194+
strerror(errno), errno);
195+
return;
196+
}
197+
// Retry now that we've unlinked the file.
198+
fd = open(fname, O_CREAT | O_EXCL | O_RDWR, 0);
199+
}
200+
if (fd == -1) {
201+
LOGE("error creating cache file %s: %s (%d)", fname,
202+
strerror(errno), errno);
203+
return;
204+
}
205+
}
206+
207+
size_t fileSize = headerSize + cacheSize;
208+
if (ftruncate(fd, fileSize) == -1) {
209+
LOGE("error setting cache file size: %s (%d)", strerror(errno),
210+
errno);
211+
close(fd);
212+
unlink(fname);
213+
return;
214+
}
215+
216+
uint8_t* buf = reinterpret_cast<uint8_t*>(mmap(NULL, fileSize,
217+
PROT_WRITE, MAP_SHARED, fd, 0));
218+
if (buf == MAP_FAILED) {
219+
LOGE("error mmaping cache file: %s (%d)", strerror(errno),
220+
errno);
221+
close(fd);
222+
unlink(fname);
223+
return;
224+
}
225+
226+
status_t err = mBlobCache->flatten(buf + headerSize, cacheSize, NULL,
227+
0);
228+
if (err != OK) {
229+
LOGE("error writing cache contents: %s (%d)", strerror(-err),
230+
-err);
231+
munmap(buf, fileSize);
232+
close(fd);
233+
unlink(fname);
234+
return;
235+
}
236+
237+
// Write the file magic and CRC
238+
memcpy(buf, cacheFileMagic, 4);
239+
uint32_t* crc = reinterpret_cast<uint32_t*>(buf + 4);
240+
*crc = crc32c(buf + headerSize, cacheSize);
241+
242+
munmap(buf, fileSize);
243+
fchmod(fd, S_IRUSR);
244+
close(fd);
245+
}
246+
}
247+
248+
void egl_cache_t::loadBlobCacheLocked() {
249+
if (mFilename.length() > 0) {
250+
size_t headerSize = cacheFileHeaderSize;
251+
252+
int fd = open(mFilename.string(), O_RDONLY, 0);
253+
if (fd == -1) {
254+
if (errno != ENOENT) {
255+
LOGE("error opening cache file %s: %s (%d)", mFilename.string(),
256+
strerror(errno), errno);
257+
}
258+
return;
259+
}
260+
261+
struct stat statBuf;
262+
if (fstat(fd, &statBuf) == -1) {
263+
LOGE("error stat'ing cache file: %s (%d)", strerror(errno), errno);
264+
close(fd);
265+
return;
266+
}
267+
268+
// Sanity check the size before trying to mmap it.
269+
size_t fileSize = statBuf.st_size;
270+
if (fileSize > maxTotalSize * 2) {
271+
LOGE("cache file is too large: %#llx", statBuf.st_size);
272+
close(fd);
273+
return;
274+
}
275+
276+
uint8_t* buf = reinterpret_cast<uint8_t*>(mmap(NULL, fileSize,
277+
PROT_READ, MAP_PRIVATE, fd, 0));
278+
if (buf == MAP_FAILED) {
279+
LOGE("error mmaping cache file: %s (%d)", strerror(errno),
280+
errno);
281+
close(fd);
282+
return;
283+
}
284+
285+
// Check the file magic and CRC
286+
size_t cacheSize = fileSize - headerSize;
287+
if (memcmp(buf, cacheFileMagic, 4) != 0) {
288+
LOGE("cache file has bad mojo");
289+
close(fd);
290+
return;
291+
}
292+
uint32_t* crc = reinterpret_cast<uint32_t*>(buf + 4);
293+
if (crc32c(buf + headerSize, cacheSize) != *crc) {
294+
LOGE("cache file failed CRC check");
295+
close(fd);
296+
return;
297+
}
298+
299+
status_t err = mBlobCache->unflatten(buf + headerSize, cacheSize, NULL, 0);
300+
if (err != OK) {
301+
LOGE("error reading cache contents: %s (%d)", strerror(-err),
302+
-err);
303+
munmap(buf, fileSize);
304+
close(fd);
305+
return;
306+
}
307+
308+
munmap(buf, fileSize);
309+
close(fd);
310+
}
91311
}
92312

93313
// ----------------------------------------------------------------------------

0 commit comments

Comments
 (0)