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.
