Name ANDROID_blob_cache Name Strings EGL_ANDROID_blob_cache Contributors Jamie Gennis Contact Jamie Gennis, Google Inc. (jgennis 'at' google.com) Status Complete Version Version 3, December 13, 2012 Number EGL Extension #48 Dependencies Requires EGL 1.0 This extension is written against the wording of the EGL 1.4 Specification Overview Shader compilation and optimization has been a troublesome aspect of OpenGL programming for a long time. It can consume seconds of CPU cycles during application start-up. Additionally, state-based re-compiles done internally by the drivers add an unpredictable element to application performance tuning, often leading to occasional pauses in otherwise smooth animations. This extension provides a mechanism through which client API implementations may cache shader binaries after they are compiled. It may then retrieve those cached shaders during subsequent executions of the same program. The management of the cache is handled by the application (or middleware), allowing it to be tuned to a particular platform or environment. While the focus of this extension is on providing a persistent cache for shader binaries, it may also be useful for caching other data. This is perfectly acceptable, but the guarantees provided (or lack thereof) were designed around the shader use case. Note that although this extension is written as if the application implements the caching functionality, on the Android OS it is implemented as part of the Android EGL module. This extension is not exposed to applications on Android, but will be used automatically in every application that uses EGL if it is supported by the underlying device-specific EGL implementation. New Types /* * EGLsizeiANDROID is a signed integer type for representing the size of a * memory buffer. */ #include <khrplatform.h> typedef khronos_ssize_t EGLsizeiANDROID; /* * EGLSetBlobFunc is a pointer to an application-provided function that a * client API implementation may use to insert a key/value pair into the * cache. */ typedef void (*EGLSetBlobFuncANDROID) (const void* key, EGLsizeiANDROID keySize, const void* value, EGLsizeiANDROID valueSize) /* * EGLGetBlobFunc is a pointer to an application-provided function that a * client API implementation may use to retrieve a cached value from the * cache. */ typedef EGLsizeiANDROID (*EGLGetBlobFuncANDROID) (const void* key, EGLsizeiANDROID keySize, void* value, EGLsizeiANDROID valueSize) New Procedures and Functions void eglSetBlobCacheFuncsANDROID(EGLDisplay dpy, EGLSetBlobFuncANDROID set, EGLGetBlobFuncANDROID get); New Tokens None. Changes to Chapter 3 of the EGL 1.4 Specification (EGL Functions and Errors) Add a new subsection after Section 3.8, page 50 (Synchronization Primitives) "3.9 Persistent Caching In order to facilitate persistent caching of internal client API state that is slow to compute or collect, the application may specify callback function pointers through which the client APIs can request data be cached and retrieved. The command void eglSetBlobCacheFuncsANDROID(EGLDisplay dpy, EGLSetBlobFuncANDROID set, EGLGetBlobFuncANDROID get); sets the callback function pointers that client APIs associated with display <dpy> can use to interact with caching functionality provided by the application. <set> points to a function that inserts a new value into the cache and associates it with the given key. <get> points to a function that retrieves from the cache the value associated with a given key. The semantics of these callback functions are described in Section 3.9.1 (Cache Operations). Cache functions may only be specified once during the lifetime of an EGLDisplay. The <set> and <get> functions may be called at any time and from any thread from the time at which eglSetBlobCacheFuncsANDROID is called until the time that the last resource associated with <dpy> is deleted and <dpy> itself is terminated. Concurrent calls to these functions from different threads is also allowed. If eglSetBlobCacheFuncsANDROID generates an error then all client APIs must behave as though eglSetBlobCacheFuncsANDROID was not called for the display <dpy>. If <set> or <get> is NULL then an EGL_BAD_PARAMETER error is generated. If a successful eglSetBlobCacheFuncsANDROID call was already made for <dpy> and the display has not since been terminated then an EGL_BAD_PARAMETER error is generated. 3.9.1 Cache Operations To insert a new binary value into the cache and associate it with a given key, a client API implementation can call the application-provided callback function void (*set) (const void* key, EGLsizeiANDROID keySize, const void* value, EGLsizeiANDROID valueSize) <key> and <value> are pointers to the beginning of the key and value, respectively, that are to be inserted. <keySize> and <valueSize> specify the size in bytes of the data pointed to by <key> and <value>, respectively. No guarantees are made as to whether a given key/value pair is present in the cache after the set call. If a different value has been associated with the given key in the past then it is undefined which value, if any, is associated with the key after the set call. Note that while there are no guarantees, the cache implementation should attempt to cache the most recently set value for a given key. To retrieve the binary value associated with a given key from the cache, a client API implementation can call the application-provided callback function EGLsizeiANDROID (*get) (const void* key, EGLsizeiANDROID keySize, void* value, EGLsizeiANDROID valueSize) <key> is a pointer to the beginning of the key. <keySize> specifies the size in bytes of the binary key pointed to by <key>. If the cache contains a value associated with the given key then the size of that binary value in bytes is returned. Otherwise 0 is returned. If the cache contains a value for the given key and its size in bytes is less than or equal to <valueSize> then the value is written to the memory pointed to by <value>. Otherwise nothing is written to the memory pointed to by <value>. Issues 1. How should errors be handled in the callback functions? RESOLVED: No guarantees are made about the presence of values in the cache, so there should not be a need to return error information to the client API implementation. The cache implementation can simply drop a value if it encounters an error during the 'set' callback. Similarly, it can simply return 0 if it encouters an error in a 'get' callback. 2. When a client API driver gets updated, that may need to invalidate previously cached entries. How can the driver handle this situation? RESPONSE: There are a number of ways the driver can handle this situation. The recommended way is to include the driver version in all cache keys. That way each driver version will use a set of cache keys that are unique to that version, and conflicts should never occur. Updating the driver could then leave a number of values in the cache that will never be requested again. If needed, the cache implementation can handle those values in some way, but the driver does not need to take any special action. 3. How much data can be stored in the cache? RESPONSE: This is entirely dependent upon the cache implementation. Presumably it will be tuned to store enough data to be useful, but not enough to become problematic. :) Revision History #3 (Jon Leech, December 13, 2012) - Fix typo in New Functions section & assign extension #. #2 (Jamie Gennis, April 25, 2011) - Swapped the order of the size and pointer arguments to the get and set functions. #1 (Jamie Gennis, April 22, 2011) - Initial draft.