Home | History | Annotate | Download | only in EGL
      1 # GLES Layers
      2 
      3 ## EGL Loader Initialization
      4 After standard entrypoints have all been populated unmodified, a GLES LayerLoader will be instantiated.  If debug layers are enabled, the LayerLoader will scan specified directories for layers, just like the Vulkan loader does.
      5 
      6 If layering is enabled, the loader will search for and enumerate a specified layer list.  The layer list will be specified by colon separated filenames (see [Enabling layers](#Enabling-layers) below).
      7 
      8 The layers will be traversed in the order they are specified, so the first layer will be directly below the application.  For each layer, it will track two entrypoints from the layer.  `AndroidGLESLayer_Initialize` and `AndroidGLESLayer_GetProcAddress`.
      9 ```cpp
     10 typedef void* (*PFNEGLGETNEXTLAYERPROCADDRESSPROC)(void*, const char*);
     11 void* AndroidGLESLayer_Initialize(void* layer_id, PFNEGLGETNEXTLAYERPROCADDRESSPROC get_next_layer_proc_address))
     12 ```
     13 
     14 `AndroidGLESLayer_Initialize` is a new function that provides an identifier for the layer to use (layer_id) and an entrypoint that can be called to look up functions below the layer.  The entrypoint can be used like so:
     15 ```cpp
     16 const char* func = "eglFoo";
     17 void* gpa = get_next_layer_proc_address(layer_id, func);
     18 ```
     19 
     20 Note that only GLES2+ entrypoints will be provided. If a layer tries to make independent GLES 1.x calls, they will be routed to GLES2+ libraries, which may not behave as expected.  Application calls to 1.x will not be affected.
     21 
     22 AndroidGLESLayer_GetProcAddress is a new function designed for this layering system.  It takes the address of the next call in the chain that the layer should call when finished.  If there is only one layer, next will point directly to the driver for most functions.
     23 ```cpp
     24 void* AndroidGLESLayer_GetProcAddress(const char *funcName, EGLFuncPointer next)
     25 ```
     26 
     27 For each layer found, the GLES LayerLoader will call `AndroidGLESLayer_Initialize`, and then walk libEGLs function lists and call `AndroidGLESLayer_GetProcAddress` for all known functions.   The layer can track that next address with any means it wants.  If the layer does not intercept the function, `AndroidGLESLayer_GetProcAddress` must return the same function address it was passed.  The LayerLoader will then update the function hook list to point to the layers entrypoint.
     28 
     29 The layers are not required to do anything with the info provided by `AndroidGLESLayer_Initialize` or get_next_layer_proc_address, but providing them makes it easier for existing layers (like GAPID and RenderDoc) to support Android.  That way a layer can look up functions independently (i.e. not wait for calls to `AndroidGLESLayer_GetProcAddress`).  Layers must be sure to use gen_next_layer_proc_address if they look up function calls instead of eglGetProcAddress or they will not get an accurate answer.  eglGetProcAddress must be passed down the chain to the platform.
     30 
     31 ## Placing layers
     32 
     33 Where layers can be found, in order of priority
     34  1. System location for root
     35     This requires root access
     36     ```bash
     37     adb root
     38     adb disable-verity
     39     adb reboot
     40     adb root
     41     adb shell setenforce 0
     42     adb shell mkdir -p /data/local/debug/gles
     43     adb push <layer>.so /data/local/debug/gles/
     44     ```
     45 
     46  2. Application's base directory
     47     Target application must be debuggable, or you must have root access:
     48      ```bash
     49      adb push libGLTrace.so /data/local/tmp
     50      adb shell run-as com.android.gl2jni cp /data/local/tmp/libGLTrace.so .
     51      adb shell run-as com.android.gl2jni ls | grep libGLTrace
     52       libGLTrace.so
     53      ```
     54 
     55  3. External APK
     56     Determine the ABI of your target application, then install an APK containing the layers you wish to load:
     57     ```bash
     58     adb install --abi armeabi-v7a layers.apk
     59     ```
     60 
     61  4. In the target application's APK
     62 
     63 ## Enabling layers
     64 
     65 ### Per application
     66 Note these settings will persist across reboots:
     67 ```bash
     68 # Enable layers
     69 adb shell settings put global enable_gpu_debug_layers 1
     70 
     71 # Specify target application
     72 adb shell settings put global gpu_debug_app <package_name>
     73 
     74 # Specify layer list (from top to bottom)
     75 adb shell settings put global gpu_debug_layers_gles <layer1:layer2:layerN>
     76 
     77 # Specify a package to search for layers
     78 adb shell settings put global gpu_debug_layer_app <layer_package>
     79 ```
     80 To disable the per-app layers:
     81 ```
     82 adb shell settings delete global enable_gpu_debug_layers
     83 adb shell settings delete global gpu_debug_app
     84 adb shell settings delete global gpu_debug_layers_gles
     85 adb shell settings delete global gpu_debug_layer_app
     86 ```
     87 
     88 ### Globally
     89 These will be cleared on reboot:
     90 ```bash
     91 # This will attempt to load layers for all applications, including native executables
     92 adb shell setprop debug.gles.layers <layer1:layer2:layerN>
     93 ```
     94 
     95 
     96 ## Creating a layer
     97 
     98 Layers must expose the following two functions described above:
     99 ```cpp
    100 AndroidGLESLayer_Initialize
    101 AndroidGLESLayer_GetProcAddress
    102 ```
    103 
    104 For a simple layer that just wants to intercept a handful of functions, a passively initialized layer is the way to go.  It can simply wait for the EGL Loader to initialize the function it cares about.  See below for an example of creating a passive layer.
    105 
    106 For more formalized layers that need to fully initialize up front, or layers that needs to look up extensions not known to the EGL loader, active layer initialization is the way to go.  The layer can utilize get_next_layer_proc_address provided by `AndroidGLESLayer_Initialize` to look up a function at any time.  The layer must still respond to `AndroidGLESLayer_GetProcAddress` requests from the loader so the platform knows where to route calls. See below for an example of creating an active layer.
    107 
    108 ### Example Passive Layer Initialization
    109 ```cpp
    110 namespace {
    111 
    112 std::unordered_map<std::string, EGLFuncPointer> funcMap;
    113 
    114 EGLAPI EGLBoolean EGLAPIENTRY glesLayer_eglChooseConfig (
    115   EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *configs, EGLint config_size,
    116   EGLint *num_config) {
    117 
    118   EGLFuncPointer entry = funcMap["eglChooseConfig"];
    119 
    120   typedef EGLBoolean (*PFNEGLCHOOSECONFIGPROC)(
    121     EGLDisplay, const EGLint*, EGLConfig*, EGLint, EGLint*);
    122 
    123   PFNEGLCHOOSECONFIGPROC next = reinterpret_cast<PFNEGLCHOOSECONFIGPROC>(entry);
    124 
    125   return next(dpy, attrib_list, configs, config_size, num_config);
    126 }
    127 
    128 EGLAPI EGLFuncPointer EGLAPIENTRY eglGPA(const char* funcName) {
    129 
    130   #define GETPROCADDR(func) if(!strcmp(funcName, #func)) { \
    131     return (EGLFuncPointer)glesLayer_##func; }
    132 
    133   GETPROCADDR(eglChooseConfig);
    134 
    135   // Don't return anything for unrecognized functions
    136   return nullptr;
    137 }
    138 
    139 EGLAPI void EGLAPIENTRY glesLayer_InitializeLayer(
    140   void* layer_id, PFNEGLGETNEXTLAYERPROCADDRESSPROC get_next_layer_proc_address) {
    141      // This function is purposefully empty, since this layer does not proactively
    142      // look up any entrypoints
    143   }
    144 
    145 EGLAPI EGLFuncPointer EGLAPIENTRY glesLayer_GetLayerProcAddress(
    146   const char* funcName, EGLFuncPointer next) {
    147   EGLFuncPointer entry = eglGPA(funcName);
    148   if (entry != nullptr) {
    149     funcMap[std::string(funcName)] = next;
    150     return entry;
    151   }
    152   return next;
    153 }
    154 
    155 }  // namespace
    156 
    157 extern "C" {
    158   __attribute((visibility("default"))) EGLAPI void AndroidGLESLayer_Initialize(
    159     void* layer_id, PFNEGLGETNEXTLAYERPROCADDRESSPROC get_next_layer_proc_address) {
    160     return (void)glesLayer_InitializeLayer(layer_id, get_next_layer_proc_address);
    161   }
    162   __attribute((visibility("default"))) EGLAPI void* AndroidGLESLayer_GetProcAddres(
    163     const char *funcName, EGLFuncPointer next) {
    164     return (void*)glesLayer_GetLayerProcAddress(funcName, next);
    165   }
    166 }
    167 ```
    168 
    169 ### Example Active Layer Initialization
    170 ```cpp
    171 namespace {
    172 
    173 std::unordered_map<std::string, EGLFuncPointer> funcMap;
    174 
    175 EGLAPI EGLBoolean EGLAPIENTRY glesLayer_eglChooseConfig (
    176   EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *configs, EGLint config_size,
    177   EGLint *num_config) {
    178 
    179   EGLFuncPointer entry = funcMap["eglChooseConfig"];
    180 
    181   typedef EGLBoolean (*PFNEGLCHOOSECONFIGPROC)(
    182     EGLDisplay, const EGLint*, EGLConfig*, EGLint, EGLint*);
    183 
    184   PFNEGLCHOOSECONFIGPROC next = reinterpret_cast<PFNEGLCHOOSECONFIGPROC>(entry);
    185 
    186   return next(dpy, attrib_list, configs, config_size, num_config);
    187 }
    188 
    189 EGLAPI EGLFuncPointer EGLAPIENTRY eglGPA(const char* funcName) {
    190 
    191   #define GETPROCADDR(func) if(!strcmp(funcName, #func)) { \
    192     return (EGLFuncPointer)glesLayer_##func; }
    193 
    194   GETPROCADDR(eglChooseConfig);
    195 
    196   // Don't return anything for unrecognized functions
    197   return nullptr;
    198 }
    199 
    200 EGLAPI void EGLAPIENTRY glesLayer_InitializeLayer(
    201   void* layer_id, PFNEGLGETNEXTLAYERPROCADDRESSPROC get_next_layer_proc_address) {
    202 
    203   // Note: This is where the layer would populate its function map with all the
    204   // functions it cares about
    205   const char* func = eglChooseConfig;
    206   funcMap[func] = get_next_layer_proc_address(layer_id, func);
    207 }
    208 
    209 EGLAPI EGLFuncPointer EGLAPIENTRY glesLayer_GetLayerProcAddress(
    210   const char* funcName, EGLFuncPointer next) {
    211   EGLFuncPointer entry = eglGPA(funcName);
    212   if (entry != nullptr) {
    213     return entry;
    214   }
    215 
    216   return next;
    217 }
    218 
    219 }  // namespace
    220 
    221 extern "C" {
    222   __attribute((visibility("default"))) EGLAPI void AndroidGLESLayer_Initialize(
    223     void* layer_id, PFNEGLGETNEXTLAYERPROCADDRESSPROC get_next_layer_proc_address) {
    224     return (void)glesLayer_InitializeLayer(layer_id, get_next_layer_proc_address);
    225   }
    226   __attribute((visibility("default"))) EGLAPI void* AndroidGLESLayer_GetProcAddres(
    227     const char *funcName, EGLFuncPointer next) {
    228     return (void*)glesLayer_GetLayerProcAddress(funcName, next);
    229   }
    230 }
    231 ```
    232 
    233 ## Caveats
    234 Only supports GLES 2.0+.
    235 
    236 When layering is enabled, GLES 1.x exclusive functions will continue to route to GLES 1.x drivers.  But functions shared with GLES 2.0+ (like glGetString) will be routed to 2.0+ drivers, which can cause confusion.
    237 
    238 ## FAQ
    239  - Who can use layers?
    240    - GLES Layers can be loaded by any debuggable application, or for any application if you have root access
    241  - How do we know if layers are working on a device?
    242    - This feature is backed by Android CTS, so you can run `atest CtsGpuToolsHostTestCases`
    243  - How does a app determine if this feature is supported?
    244    - There are two ways.  First you can check against the version of Android.
    245      ```bash
    246      # Q is the first that will support this, so look for `Q` or 10 for release
    247      adb shell getprop ro.build.version.sdk 
    248      # Or look for the SDK version, which should be 29 for Q
    249      adb shell getprop ro.build.version.sdk
    250      ```
    251    - Secondly, if you want to determine from an application that can't call out to ADB for this, you can check for the [EGL_ANDROID_GLES_layers](../../specs/EGL_ANDROID_GLES_layers.txt). It simply indicates support of this layering system:
    252      ```cpp
    253      std::string display_extensions = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
    254      if (display_extension.find("EGL_ANDROID_GLES_layers") != std::string::npos)
    255      {
    256         // Layers are supported!
    257      }
    258      ```
    259