blob: 27697aba2c055f95b45ee65721611e179d85b14f [file] [log] [blame]
Jesse Hall94cdba92013-07-11 09:40:35 -07001/*
Mathias Agopiande586972009-05-28 17:39:03 -07002 ** Copyright 2007, The Android Open Source Project
3 **
Jesse Hall94cdba92013-07-11 09:40:35 -07004 ** Licensed under the Apache License, Version 2.0 (the "License");
5 ** you may not use this file except in compliance with the License.
6 ** You may obtain a copy of the License at
Mathias Agopiande586972009-05-28 17:39:03 -07007 **
Jesse Hall94cdba92013-07-11 09:40:35 -07008 ** http://www.apache.org/licenses/LICENSE-2.0
Mathias Agopiande586972009-05-28 17:39:03 -07009 **
Jesse Hall94cdba92013-07-11 09:40:35 -070010 ** Unless required by applicable law or agreed to in writing, software
11 ** distributed under the License is distributed on an "AS IS" BASIS,
12 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 ** See the License for the specific language governing permissions and
Mathias Agopiande586972009-05-28 17:39:03 -070014 ** limitations under the License.
15 */
16
Jesse Hall7a8d83e2016-12-20 15:24:28 -080017//#define LOG_NDEBUG 0
18
19#include <array>
Mathias Agopiande586972009-05-28 17:39:03 -070020#include <ctype.h>
Mathias Agopian99381422013-04-23 20:52:29 +020021#include <dirent.h>
Mark Salyzyna5e161b2016-09-29 08:08:05 -070022#include <dlfcn.h>
23#include <errno.h>
24#include <limits.h>
25#include <stdio.h>
26#include <stdlib.h>
27#include <string.h>
Mathias Agopiande586972009-05-28 17:39:03 -070028
Jesse Hall7a8d83e2016-12-20 15:24:28 -080029#include <android/dlext.h>
David 'Digit' Turner80b30c22011-08-26 17:38:47 +020030#include <cutils/properties.h>
Mark Salyzyn7823e122016-09-29 08:08:05 -070031#include <log/log.h>
Mathias Agopiande586972009-05-28 17:39:03 -070032
33#include <EGL/egl.h>
34
Mathias Agopian1cadb252011-05-23 17:26:14 -070035#include "egldefs.h"
Mathias Agopian1cadb252011-05-23 17:26:14 -070036#include "Loader.h"
Mathias Agopiande586972009-05-28 17:39:03 -070037
38// ----------------------------------------------------------------------------
39namespace android {
40// ----------------------------------------------------------------------------
41
42
43/*
Mathias Agopian99381422013-04-23 20:52:29 +020044 * EGL userspace drivers must be provided either:
45 * - as a single library:
46 * /vendor/lib/egl/libGLES.so
47 *
48 * - as separate libraries:
49 * /vendor/lib/egl/libEGL.so
50 * /vendor/lib/egl/libGLESv1_CM.so
51 * /vendor/lib/egl/libGLESv2.so
52 *
53 * The software renderer for the emulator must be provided as a single
54 * library at:
55 *
56 * /system/lib/egl/libGLES_android.so
57 *
58 *
59 * For backward compatibility and to facilitate the transition to
60 * this new naming scheme, the loader will additionally look for:
Jesse Hall94cdba92013-07-11 09:40:35 -070061 *
Mathias Agopian99381422013-04-23 20:52:29 +020062 * /{vendor|system}/lib/egl/lib{GLES | [EGL|GLESv1_CM|GLESv2]}_*.so
Jesse Hall94cdba92013-07-11 09:40:35 -070063 *
Mathias Agopiande586972009-05-28 17:39:03 -070064 */
65
66ANDROID_SINGLETON_STATIC_INSTANCE( Loader )
67
David 'Digit' Turner80b30c22011-08-26 17:38:47 +020068/* This function is called to check whether we run inside the emulator,
69 * and if this is the case whether GLES GPU emulation is supported.
70 *
71 * Returned values are:
72 * -1 -> not running inside the emulator
73 * 0 -> running inside the emulator, but GPU emulation not supported
74 * 1 -> running inside the emulator, GPU emulation is supported
Nicolas Capens776951f2015-11-06 10:10:21 -050075 * through the "emulation" host-side OpenGL ES implementation.
76 * 2 -> running inside the emulator, GPU emulation is supported
77 * through a guest-side vendor driver's OpenGL ES implementation.
David 'Digit' Turner80b30c22011-08-26 17:38:47 +020078 */
79static int
80checkGlesEmulationStatus(void)
81{
82 /* We're going to check for the following kernel parameters:
83 *
84 * qemu=1 -> tells us that we run inside the emulator
85 * android.qemu.gles=<number> -> tells us the GLES GPU emulation status
86 *
87 * Note that we will return <number> if we find it. This let us support
88 * more additionnal emulation modes in the future.
89 */
90 char prop[PROPERTY_VALUE_MAX];
91 int result = -1;
92
93 /* First, check for qemu=1 */
94 property_get("ro.kernel.qemu",prop,"0");
95 if (atoi(prop) != 1)
96 return -1;
97
98 /* We are in the emulator, get GPU status value */
bohu69e5b1a2016-02-19 17:15:20 -080099 property_get("qemu.gles",prop,"0");
David 'Digit' Turner80b30c22011-08-26 17:38:47 +0200100 return atoi(prop);
101}
102
Mathias Agopiande586972009-05-28 17:39:03 -0700103// ----------------------------------------------------------------------------
104
Jesse Hall94cdba92013-07-11 09:40:35 -0700105Loader::driver_t::driver_t(void* gles)
Mathias Agopiande586972009-05-28 17:39:03 -0700106{
107 dso[0] = gles;
108 for (size_t i=1 ; i<NELEM(dso) ; i++)
109 dso[i] = 0;
110}
111
Jesse Hall94cdba92013-07-11 09:40:35 -0700112Loader::driver_t::~driver_t()
Mathias Agopiande586972009-05-28 17:39:03 -0700113{
114 for (size_t i=0 ; i<NELEM(dso) ; i++) {
115 if (dso[i]) {
116 dlclose(dso[i]);
117 dso[i] = 0;
118 }
119 }
120}
121
122status_t Loader::driver_t::set(void* hnd, int32_t api)
123{
124 switch (api) {
125 case EGL:
126 dso[0] = hnd;
127 break;
128 case GLESv1_CM:
129 dso[1] = hnd;
130 break;
131 case GLESv2:
132 dso[2] = hnd;
133 break;
134 default:
135 return BAD_INDEX;
136 }
137 return NO_ERROR;
138}
139
140// ----------------------------------------------------------------------------
141
Mathias Agopiande586972009-05-28 17:39:03 -0700142Loader::Loader()
Jesse Hall7a8d83e2016-12-20 15:24:28 -0800143 : getProcAddress(NULL),
144 mLibGui(nullptr),
145 mGetDriverNamespace(nullptr)
146{
147 // FIXME: See note in GraphicsEnv.h about android_getDriverNamespace().
148 // libgui should already be loaded in any process that uses libEGL, but
149 // if for some reason it isn't, then we're not going to get a driver
150 // namespace anyway, so don't force it to be loaded.
151 mLibGui = dlopen("libgui.so", RTLD_NOLOAD | RTLD_LOCAL | RTLD_LAZY);
152 if (!mLibGui) {
153 ALOGD("failed to load libgui: %s", dlerror());
154 return;
155 }
156 mGetDriverNamespace = reinterpret_cast<decltype(mGetDriverNamespace)>(
157 dlsym(mLibGui, "android_getDriverNamespace"));
Mathias Agopiande586972009-05-28 17:39:03 -0700158}
159
Mathias Agopian99381422013-04-23 20:52:29 +0200160Loader::~Loader() {
Jesse Hall7a8d83e2016-12-20 15:24:28 -0800161 if (mLibGui)
162 dlclose(mLibGui);
Mathias Agopiande586972009-05-28 17:39:03 -0700163}
164
Jesse Hallc07b5202013-07-04 12:08:16 -0700165static void* load_wrapper(const char* path) {
166 void* so = dlopen(path, RTLD_NOW | RTLD_LOCAL);
167 ALOGE_IF(!so, "dlopen(\"%s\") failed: %s", path, dlerror());
168 return so;
169}
170
Evgenii Stepanovc2466e62015-07-08 15:49:52 -0700171#ifndef EGL_WRAPPER_DIR
172#if defined(__LP64__)
173#define EGL_WRAPPER_DIR "/system/lib64"
174#else
175#define EGL_WRAPPER_DIR "/system/lib"
176#endif
177#endif
178
bohu69e5b1a2016-02-19 17:15:20 -0800179static void setEmulatorGlesValue(void) {
180 char prop[PROPERTY_VALUE_MAX];
181 property_get("ro.kernel.qemu", prop, "0");
182 if (atoi(prop) != 1) return;
183
184 property_get("ro.kernel.qemu.gles",prop,"0");
185 if (atoi(prop) == 1) {
186 ALOGD("Emulator has host GPU support, qemu.gles is set to 1.");
187 property_set("qemu.gles", "1");
188 return;
189 }
190
191 // for now, checking the following
192 // directory is good enough for emulator system images
193 const char* vendor_lib_path =
194#if defined(__LP64__)
195 "/vendor/lib64/egl";
196#else
197 "/vendor/lib/egl";
198#endif
199
200 const bool has_vendor_lib = (access(vendor_lib_path, R_OK) == 0);
201 if (has_vendor_lib) {
202 ALOGD("Emulator has vendor provided software renderer, qemu.gles is set to 2.");
203 property_set("qemu.gles", "2");
204 } else {
205 ALOGD("Emulator without GPU support detected. "
206 "Fallback to legacy software renderer, qemu.gles is set to 0.");
207 property_set("qemu.gles", "0");
208 }
209}
210
Mathias Agopianada798b2012-02-13 17:09:30 -0800211void* Loader::open(egl_connection_t* cnx)
Mathias Agopiande586972009-05-28 17:39:03 -0700212{
Mathias Agopiande586972009-05-28 17:39:03 -0700213 void* dso;
Mathias Agopiande586972009-05-28 17:39:03 -0700214 driver_t* hnd = 0;
Jesse Hall94cdba92013-07-11 09:40:35 -0700215
bohu69e5b1a2016-02-19 17:15:20 -0800216 setEmulatorGlesValue();
217
Mathias Agopian99381422013-04-23 20:52:29 +0200218 dso = load_driver("GLES", cnx, EGL | GLESv1_CM | GLESv2);
219 if (dso) {
220 hnd = new driver_t(dso);
221 } else {
222 // Always load EGL first
223 dso = load_driver("EGL", cnx, EGL);
Mathias Agopiande586972009-05-28 17:39:03 -0700224 if (dso) {
225 hnd = new driver_t(dso);
Mathias Agopian99381422013-04-23 20:52:29 +0200226 hnd->set( load_driver("GLESv1_CM", cnx, GLESv1_CM), GLESv1_CM );
227 hnd->set( load_driver("GLESv2", cnx, GLESv2), GLESv2 );
Mathias Agopiande586972009-05-28 17:39:03 -0700228 }
229 }
230
Mathias Agopian99381422013-04-23 20:52:29 +0200231 LOG_ALWAYS_FATAL_IF(!hnd, "couldn't find an OpenGL ES implementation");
Jesse Hallc07b5202013-07-04 12:08:16 -0700232
Evgenii Stepanovc2466e62015-07-08 15:49:52 -0700233 cnx->libEgl = load_wrapper(EGL_WRAPPER_DIR "/libEGL.so");
234 cnx->libGles2 = load_wrapper(EGL_WRAPPER_DIR "/libGLESv2.so");
235 cnx->libGles1 = load_wrapper(EGL_WRAPPER_DIR "/libGLESv1_CM.so");
236
Michael Chockc0ec5e22014-01-27 08:14:33 -0800237 LOG_ALWAYS_FATAL_IF(!cnx->libEgl,
238 "couldn't load system EGL wrapper libraries");
239
Jesse Hallc07b5202013-07-04 12:08:16 -0700240 LOG_ALWAYS_FATAL_IF(!cnx->libGles2 || !cnx->libGles1,
241 "couldn't load system OpenGL ES wrapper libraries");
242
Mathias Agopiande586972009-05-28 17:39:03 -0700243 return (void*)hnd;
244}
245
246status_t Loader::close(void* driver)
247{
248 driver_t* hnd = (driver_t*)driver;
249 delete hnd;
250 return NO_ERROR;
251}
252
Jesse Hall94cdba92013-07-11 09:40:35 -0700253void Loader::init_api(void* dso,
254 char const * const * api,
255 __eglMustCastToProperFunctionPointerType* curr,
256 getProcAddressType getProcAddress)
Mathias Agopiande586972009-05-28 17:39:03 -0700257{
Mathias Agopian7773c432012-02-13 20:06:08 -0800258 const ssize_t SIZE = 256;
Mathias Agopian0ad71a92011-05-11 20:37:47 -0700259 char scrap[SIZE];
Mathias Agopiande586972009-05-28 17:39:03 -0700260 while (*api) {
261 char const * name = *api;
Jesse Hall94cdba92013-07-11 09:40:35 -0700262 __eglMustCastToProperFunctionPointerType f =
Mathias Agopiande586972009-05-28 17:39:03 -0700263 (__eglMustCastToProperFunctionPointerType)dlsym(dso, name);
264 if (f == NULL) {
265 // couldn't find the entry-point, use eglGetProcAddress()
266 f = getProcAddress(name);
267 }
268 if (f == NULL) {
269 // Try without the OES postfix
270 ssize_t index = ssize_t(strlen(name)) - 3;
Mathias Agopian0ad71a92011-05-11 20:37:47 -0700271 if ((index>0 && (index<SIZE-1)) && (!strcmp(name+index, "OES"))) {
Mathias Agopiande586972009-05-28 17:39:03 -0700272 strncpy(scrap, name, index);
273 scrap[index] = 0;
274 f = (__eglMustCastToProperFunctionPointerType)dlsym(dso, scrap);
Steve Block9d453682011-12-20 16:23:08 +0000275 //ALOGD_IF(f, "found <%s> instead", scrap);
Mathias Agopiande586972009-05-28 17:39:03 -0700276 }
277 }
278 if (f == NULL) {
279 // Try with the OES postfix
Mathias Agopian0ad71a92011-05-11 20:37:47 -0700280 ssize_t index = ssize_t(strlen(name)) - 3;
281 if (index>0 && strcmp(name+index, "OES")) {
282 snprintf(scrap, SIZE, "%sOES", name);
Mathias Agopiande586972009-05-28 17:39:03 -0700283 f = (__eglMustCastToProperFunctionPointerType)dlsym(dso, scrap);
Steve Block9d453682011-12-20 16:23:08 +0000284 //ALOGD_IF(f, "found <%s> instead", scrap);
Mathias Agopiande586972009-05-28 17:39:03 -0700285 }
286 }
287 if (f == NULL) {
Steve Block9d453682011-12-20 16:23:08 +0000288 //ALOGD("%s", name);
Mathias Agopiande586972009-05-28 17:39:03 -0700289 f = (__eglMustCastToProperFunctionPointerType)gl_unimplemented;
Mathias Agopian48d438d2012-01-28 21:44:00 -0800290
291 /*
292 * GL_EXT_debug_label is special, we always report it as
293 * supported, it's handled by GLES_trace. If GLES_trace is not
294 * enabled, then these are no-ops.
295 */
296 if (!strcmp(name, "glInsertEventMarkerEXT")) {
297 f = (__eglMustCastToProperFunctionPointerType)gl_noop;
298 } else if (!strcmp(name, "glPushGroupMarkerEXT")) {
299 f = (__eglMustCastToProperFunctionPointerType)gl_noop;
300 } else if (!strcmp(name, "glPopGroupMarkerEXT")) {
301 f = (__eglMustCastToProperFunctionPointerType)gl_noop;
302 }
Mathias Agopiande586972009-05-28 17:39:03 -0700303 }
304 *curr++ = f;
305 api++;
306 }
307}
308
Jesse Hall7a8d83e2016-12-20 15:24:28 -0800309static void* load_system_driver(const char* kind) {
Mathias Agopian99381422013-04-23 20:52:29 +0200310 class MatchFile {
311 public:
312 static String8 find(const char* kind) {
313 String8 result;
Nicolas Capens776951f2015-11-06 10:10:21 -0500314 int emulationStatus = checkGlesEmulationStatus();
315 switch (emulationStatus) {
316 case 0:
Nicolas Capens776951f2015-11-06 10:10:21 -0500317#if defined(__LP64__)
318 result.setTo("/system/lib64/egl/libGLES_android.so");
319#else
320 result.setTo("/system/lib/egl/libGLES_android.so");
321#endif
322 return result;
323 case 1:
324 // Use host-side OpenGL through the "emulation" library
325#if defined(__LP64__)
326 result.appendFormat("/system/lib64/egl/lib%s_emulation.so", kind);
327#else
328 result.appendFormat("/system/lib/egl/lib%s_emulation.so", kind);
329#endif
330 return result;
331 default:
332 // Not in emulator, or use other guest-side implementation
333 break;
334 }
335
Mathias Agopian99381422013-04-23 20:52:29 +0200336 String8 pattern;
337 pattern.appendFormat("lib%s", kind);
338 const char* const searchPaths[] = {
Dan Willemsen8edb8f52014-02-16 10:23:54 -0800339#if defined(__LP64__)
340 "/vendor/lib64/egl",
341 "/system/lib64/egl"
342#else
Mathias Agopian99381422013-04-23 20:52:29 +0200343 "/vendor/lib/egl",
344 "/system/lib/egl"
Dan Willemsen8edb8f52014-02-16 10:23:54 -0800345#endif
Mathias Agopian99381422013-04-23 20:52:29 +0200346 };
Brian Swetland2b9e4f62010-09-20 12:58:15 -0700347
Mathias Agopian99381422013-04-23 20:52:29 +0200348 // first, we search for the exact name of the GLES userspace
349 // driver in both locations.
350 // i.e.:
351 // libGLES.so, or:
352 // libEGL.so, libGLESv1_CM.so, libGLESv2.so
353
354 for (size_t i=0 ; i<NELEM(searchPaths) ; i++) {
355 if (find(result, pattern, searchPaths[i], true)) {
356 return result;
357 }
358 }
359
360 // for compatibility with the old "egl.cfg" naming convention
361 // we look for files that match:
362 // libGLES_*.so, or:
363 // libEGL_*.so, libGLESv1_CM_*.so, libGLESv2_*.so
364
365 pattern.append("_");
366 for (size_t i=0 ; i<NELEM(searchPaths) ; i++) {
367 if (find(result, pattern, searchPaths[i], false)) {
368 return result;
369 }
370 }
371
372 // we didn't find the driver. gah.
373 result.clear();
374 return result;
Brian Swetland2b9e4f62010-09-20 12:58:15 -0700375 }
Mathias Agopian99381422013-04-23 20:52:29 +0200376
377 private:
378 static bool find(String8& result,
379 const String8& pattern, const char* const search, bool exact) {
Mathias Agopian99381422013-04-23 20:52:29 +0200380 if (exact) {
381 String8 absolutePath;
382 absolutePath.appendFormat("%s/%s.so", search, pattern.string());
383 if (!access(absolutePath.string(), R_OK)) {
384 result = absolutePath;
385 return true;
386 }
387 return false;
388 }
389
390 DIR* d = opendir(search);
391 if (d != NULL) {
392 struct dirent cur;
393 struct dirent* e;
394 while (readdir_r(d, &cur, &e) == 0 && e) {
395 if (e->d_type == DT_DIR) {
396 continue;
397 }
398 if (!strcmp(e->d_name, "libGLES_android.so")) {
399 // always skip the software renderer
400 continue;
401 }
402 if (strstr(e->d_name, pattern.string()) == e->d_name) {
403 if (!strcmp(e->d_name + strlen(e->d_name) - 3, ".so")) {
404 result.clear();
405 result.appendFormat("%s/%s", search, e->d_name);
406 closedir(d);
407 return true;
408 }
409 }
410 }
411 closedir(d);
412 }
413 return false;
414 }
415 };
416
417
418 String8 absolutePath = MatchFile::find(kind);
419 if (absolutePath.isEmpty()) {
420 // this happens often, we don't want to log an error
421 return 0;
Mathias Agopian8c173842009-09-20 16:01:02 -0700422 }
Mathias Agopian99381422013-04-23 20:52:29 +0200423 const char* const driver_absolute_path = absolutePath.string();
Mathias Agopiande586972009-05-28 17:39:03 -0700424
Mathias Agopian8c173842009-09-20 16:01:02 -0700425 void* dso = dlopen(driver_absolute_path, RTLD_NOW | RTLD_LOCAL);
426 if (dso == 0) {
427 const char* err = dlerror();
Steve Blocke6f43dd2012-01-06 19:20:56 +0000428 ALOGE("load_driver(%s): %s", driver_absolute_path, err?err:"unknown");
Mathias Agopian8c173842009-09-20 16:01:02 -0700429 return 0;
430 }
431
Steve Block9d453682011-12-20 16:23:08 +0000432 ALOGD("loaded %s", driver_absolute_path);
Mathias Agopianbaca89c2009-08-20 19:09:34 -0700433
Jesse Hall7a8d83e2016-12-20 15:24:28 -0800434 return dso;
435}
436
437static const std::array<const char*, 2> HAL_SUBNAME_KEY_PROPERTIES = {{
438 "ro.hardware.egl",
439 "ro.board.platform",
440}};
441
442static void* load_updated_driver(const char* kind, android_namespace_t* ns) {
443 const android_dlextinfo dlextinfo = {
444 .flags = ANDROID_DLEXT_USE_NAMESPACE,
445 .library_namespace = ns,
446 };
447 void* so = nullptr;
448 char prop[PROPERTY_VALUE_MAX + 1];
449 for (auto key : HAL_SUBNAME_KEY_PROPERTIES) {
450 if (property_get(key, prop, nullptr) > 0) {
451 String8 name;
452 name.appendFormat("lib%s_%s.so", kind, prop);
453 so = android_dlopen_ext(name.string(), RTLD_LOCAL | RTLD_NOW,
454 &dlextinfo);
455 if (so)
456 return so;
457 }
458 }
459 return nullptr;
460}
461
462void *Loader::load_driver(const char* kind,
463 egl_connection_t* cnx, uint32_t mask)
464{
465 void* dso = nullptr;
466 if (mGetDriverNamespace) {
467 android_namespace_t* ns = mGetDriverNamespace();
468 if (ns) {
469 dso = load_updated_driver(kind, ns);
470 }
471 }
472 if (!dso) {
473 dso = load_system_driver(kind);
474 if (!dso)
475 return NULL;
476 }
477
Mathias Agopiande586972009-05-28 17:39:03 -0700478 if (mask & EGL) {
479 getProcAddress = (getProcAddressType)dlsym(dso, "eglGetProcAddress");
480
Jesse Hall94cdba92013-07-11 09:40:35 -0700481 ALOGE_IF(!getProcAddress,
Jesse Hall7a8d83e2016-12-20 15:24:28 -0800482 "can't find eglGetProcAddress() in EGL driver library");
Mathias Agopiande586972009-05-28 17:39:03 -0700483
Mathias Agopian618fa102009-10-14 02:06:37 -0700484 egl_t* egl = &cnx->egl;
Mathias Agopiande586972009-05-28 17:39:03 -0700485 __eglMustCastToProperFunctionPointerType* curr =
486 (__eglMustCastToProperFunctionPointerType*)egl;
487 char const * const * api = egl_names;
488 while (*api) {
489 char const * name = *api;
Jesse Hall94cdba92013-07-11 09:40:35 -0700490 __eglMustCastToProperFunctionPointerType f =
Mathias Agopiande586972009-05-28 17:39:03 -0700491 (__eglMustCastToProperFunctionPointerType)dlsym(dso, name);
492 if (f == NULL) {
493 // couldn't find the entry-point, use eglGetProcAddress()
494 f = getProcAddress(name);
495 if (f == NULL) {
496 f = (__eglMustCastToProperFunctionPointerType)0;
497 }
498 }
499 *curr++ = f;
500 api++;
501 }
502 }
Jesse Hall94cdba92013-07-11 09:40:35 -0700503
Mathias Agopiande586972009-05-28 17:39:03 -0700504 if (mask & GLESv1_CM) {
Mathias Agopian618fa102009-10-14 02:06:37 -0700505 init_api(dso, gl_names,
506 (__eglMustCastToProperFunctionPointerType*)
Mathias Agopian7773c432012-02-13 20:06:08 -0800507 &cnx->hooks[egl_connection_t::GLESv1_INDEX]->gl,
Mathias Agopian618fa102009-10-14 02:06:37 -0700508 getProcAddress);
Mathias Agopiande586972009-05-28 17:39:03 -0700509 }
510
511 if (mask & GLESv2) {
Mathias Agopian618fa102009-10-14 02:06:37 -0700512 init_api(dso, gl_names,
513 (__eglMustCastToProperFunctionPointerType*)
Mathias Agopian7773c432012-02-13 20:06:08 -0800514 &cnx->hooks[egl_connection_t::GLESv2_INDEX]->gl,
Mathias Agopiande586972009-05-28 17:39:03 -0700515 getProcAddress);
516 }
Jesse Hall94cdba92013-07-11 09:40:35 -0700517
Mathias Agopiande586972009-05-28 17:39:03 -0700518 return dso;
519}
520
521// ----------------------------------------------------------------------------
522}; // namespace android
523// ----------------------------------------------------------------------------