1# GLES Layers 2 3## EGL Loader Initialization 4After 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 6If 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 8The 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 10typedef void* (*PFNEGLGETNEXTLAYERPROCADDRESSPROC)(void*, const char*); 11void* 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 16const char* func = "eglFoo"; 17void* gpa = get_next_layer_proc_address(layer_id, func); 18``` 19 20Note 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 22AndroidGLESLayer_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 24void* AndroidGLESLayer_GetProcAddress(const char *funcName, EGLFuncPointer next) 25``` 26 27For each layer found, the GLES LayerLoader will call `AndroidGLESLayer_Initialize`, and then walk libEGL’s 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 layer’s entrypoint. 28 29The 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 33Where 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 66Note these settings will persist across reboots: 67```bash 68# Enable layers 69adb shell settings put global enable_gpu_debug_layers 1 70 71# Specify target application 72adb shell settings put global gpu_debug_app <package_name> 73 74# Specify layer list (from top to bottom) 75adb shell settings put global gpu_debug_layers_gles <layer1:layer2:layerN> 76 77# Specify a package to search for layers 78adb shell settings put global gpu_debug_layer_app <layer_package> 79``` 80To disable the per-app layers: 81``` 82adb shell settings delete global enable_gpu_debug_layers 83adb shell settings delete global gpu_debug_app 84adb shell settings delete global gpu_debug_layers_gles 85adb shell settings delete global gpu_debug_layer_app 86``` 87 88### Globally 89These will be cleared on reboot: 90```bash 91# This will attempt to load layers for all applications, including native executables 92adb shell setprop debug.gles.layers <layer1:layer2:layerN> 93``` 94 95 96## Creating a layer 97 98Layers must expose the following two functions described above: 99```cpp 100AndroidGLESLayer_Initialize 101AndroidGLESLayer_GetProcAddress 102``` 103 104For 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 106For 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 110namespace { 111 112std::unordered_map<std::string, EGLFuncPointer> funcMap; 113 114EGLAPI 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 128EGLAPI 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 139EGLAPI 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 145EGLAPI 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 157extern "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 171namespace { 172 173std::unordered_map<std::string, EGLFuncPointer> funcMap; 174 175EGLAPI 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 189EGLAPI 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 200EGLAPI 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 209EGLAPI 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 221extern "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 234Only supports GLES 2.0+. 235 236When 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