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