diff options
Diffstat (limited to 'opengl')
-rw-r--r-- | opengl/libs/EGL/Loader.cpp | 55 | ||||
-rw-r--r-- | opengl/libs/EGL/Loader.h | 15 | ||||
-rw-r--r-- | opengl/libs/EGL/egl.cpp | 46 | ||||
-rw-r--r-- | opengl/libs/EGL/eglApi.cpp | 481 | ||||
-rw-r--r-- | opengl/libs/EGL/egl_cache.cpp | 54 | ||||
-rw-r--r-- | opengl/libs/EGL/egl_display.cpp | 155 | ||||
-rw-r--r-- | opengl/libs/EGL/egl_display.h | 26 | ||||
-rw-r--r-- | opengl/libs/EGL/egl_object.cpp | 6 | ||||
-rw-r--r-- | opengl/libs/EGL/egl_object.h | 17 | ||||
-rw-r--r-- | opengl/libs/EGL/egldefs.h | 29 | ||||
-rw-r--r-- | opengl/libs/GLES_trace/src/gltrace_fixup.cpp | 154 |
11 files changed, 408 insertions, 630 deletions
diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp index 06be2ef..0b1016c 100644 --- a/opengl/libs/EGL/Loader.cpp +++ b/opengl/libs/EGL/Loader.cpp @@ -118,12 +118,6 @@ status_t Loader::driver_t::set(void* hnd, int32_t api) // ---------------------------------------------------------------------------- -Loader::entry_t::entry_t(int dpy, int impl, const char* tag) - : dpy(dpy), impl(impl), tag(tag) { -} - -// ---------------------------------------------------------------------------- - Loader::Loader() { char line[256]; @@ -131,8 +125,9 @@ Loader::Loader() /* Special case for GLES emulation */ if (checkGlesEmulationStatus() == 0) { - ALOGD("Emulator without GPU support detected. Fallback to software renderer."); - gConfig.add( entry_t(0, 0, "android") ); + ALOGD("Emulator without GPU support detected. " + "Fallback to software renderer."); + mDriverTag.setTo("android"); return; } @@ -141,14 +136,16 @@ Loader::Loader() if (cfg == NULL) { // default config ALOGD("egl.cfg not found, using default config"); - gConfig.add( entry_t(0, 0, "android") ); + mDriverTag.setTo("android"); } else { while (fgets(line, 256, cfg)) { - int dpy; - int impl; + int dpy, impl; if (sscanf(line, "%u %u %s", &dpy, &impl, tag) == 3) { //ALOGD(">>> %u %u %s", dpy, impl, tag); - gConfig.add( entry_t(dpy, impl, tag) ); + // We only load the h/w accelerated implementation + if (tag != String8("android")) { + mDriverTag = tag; + } } } fclose(cfg); @@ -160,30 +157,12 @@ Loader::~Loader() GLTrace_stop(); } -const char* Loader::getTag(int dpy, int impl) +void* Loader::open(egl_connection_t* cnx) { - const Vector<entry_t>& cfgs(gConfig); - const size_t c = cfgs.size(); - for (size_t i=0 ; i<c ; i++) { - if (dpy == cfgs[i].dpy) - if (impl == cfgs[i].impl) - return cfgs[i].tag.string(); - } - return 0; -} - -void* Loader::open(EGLNativeDisplayType display, int impl, egl_connection_t* cnx) -{ - /* - * TODO: if we don't find display/0, then use 0/0 - * (0/0 should always work) - */ - void* dso; - int index = int(display); driver_t* hnd = 0; - char const* tag = getTag(index, impl); + char const* tag = mDriverTag.string(); if (tag) { dso = load_driver("GLES", tag, cnx, EGL | GLESv1_CM | GLESv2); if (dso) { @@ -193,16 +172,14 @@ void* Loader::open(EGLNativeDisplayType display, int impl, egl_connection_t* cnx dso = load_driver("EGL", tag, cnx, EGL); if (dso) { hnd = new driver_t(dso); - // TODO: make this more automated hnd->set( load_driver("GLESv1_CM", tag, cnx, GLESv1_CM), GLESv1_CM ); - - hnd->set( load_driver("GLESv2", tag, cnx, GLESv2), GLESv2 ); + hnd->set( load_driver("GLESv2", tag, cnx, GLESv2), GLESv2 ); } } } - LOG_FATAL_IF(!index && !impl && !hnd, + LOG_FATAL_IF(!index && !hnd, "couldn't find the default OpenGL ES implementation " "for default display"); @@ -221,7 +198,7 @@ void Loader::init_api(void* dso, __eglMustCastToProperFunctionPointerType* curr, getProcAddressType getProcAddress) { - const size_t SIZE = 256; + const ssize_t SIZE = 256; char scrap[SIZE]; while (*api) { char const * name = *api; @@ -326,14 +303,14 @@ void *Loader::load_driver(const char* kind, const char *tag, if (mask & GLESv1_CM) { init_api(dso, gl_names, (__eglMustCastToProperFunctionPointerType*) - &cnx->hooks[GLESv1_INDEX]->gl, + &cnx->hooks[egl_connection_t::GLESv1_INDEX]->gl, getProcAddress); } if (mask & GLESv2) { init_api(dso, gl_names, (__eglMustCastToProperFunctionPointerType*) - &cnx->hooks[GLESv2_INDEX]->gl, + &cnx->hooks[egl_connection_t::GLESv2_INDEX]->gl, getProcAddress); } diff --git a/opengl/libs/EGL/Loader.h b/opengl/libs/EGL/Loader.h index 580d6e4..30773cb 100644 --- a/opengl/libs/EGL/Loader.h +++ b/opengl/libs/EGL/Loader.h @@ -24,7 +24,6 @@ #include <utils/Errors.h> #include <utils/Singleton.h> #include <utils/String8.h> -#include <utils/Vector.h> #include <EGL/egl.h> @@ -53,23 +52,13 @@ class Loader : public Singleton<Loader> void* dso[3]; }; - struct entry_t { - entry_t() { } - entry_t(int dpy, int impl, const char* tag); - int dpy; - int impl; - String8 tag; - }; - - Vector<entry_t> gConfig; + String8 mDriverTag; getProcAddressType getProcAddress; - const char* getTag(int dpy, int impl); - public: ~Loader(); - void* open(EGLNativeDisplayType display, int impl, egl_connection_t* cnx); + void* open(egl_connection_t* cnx); status_t close(void* driver); private: diff --git a/opengl/libs/EGL/egl.cpp b/opengl/libs/EGL/egl.cpp index 83933e5..4a56dcf 100644 --- a/opengl/libs/EGL/egl.cpp +++ b/opengl/libs/EGL/egl.cpp @@ -48,8 +48,8 @@ namespace android { // ---------------------------------------------------------------------------- -egl_connection_t gEGLImpl[IMPL_NUM_IMPLEMENTATIONS]; -gl_hooks_t gHooks[2][IMPL_NUM_IMPLEMENTATIONS]; +egl_connection_t gEGLImpl; +gl_hooks_t gHooks[2]; gl_hooks_t gHooksNoContext; pthread_key_t gGLWrapperKey = -1; @@ -187,16 +187,13 @@ egl_display_t* validate_display(EGLDisplay dpy) { return dp; } -egl_connection_t* validate_display_config(EGLDisplay dpy, EGLConfig config, +egl_connection_t* validate_display_config(EGLDisplay dpy, EGLConfig, egl_display_t const*& dp) { dp = validate_display(dpy); if (!dp) return (egl_connection_t*) NULL; - if (intptr_t(config) >= dp->numTotalConfigs) { - return setError(EGL_BAD_CONFIG, (egl_connection_t*)NULL); - } - egl_connection_t* const cnx = &gEGLImpl[dp->configs[intptr_t(config)].impl]; + egl_connection_t* const cnx = &gEGLImpl; if (cnx->dso == 0) { return setError(EGL_BAD_CONFIG, (egl_connection_t*)NULL); } @@ -228,7 +225,7 @@ EGLImageKHR egl_get_image_for_current_context(EGLImageKHR image) // EGL. egl_image_t const * const i = get_image(image); - return i->images[c->impl]; + return i->image; } // ---------------------------------------------------------------------------- @@ -266,34 +263,17 @@ static EGLBoolean egl_init_drivers_locked() { // get our driver loader Loader& loader(Loader::getInstance()); - // dynamically load all our EGL implementations - egl_connection_t* cnx; - - cnx = &gEGLImpl[IMPL_SOFTWARE]; - if (cnx->dso == 0) { - cnx->hooks[GLESv1_INDEX] = &gHooks[GLESv1_INDEX][IMPL_SOFTWARE]; - cnx->hooks[GLESv2_INDEX] = &gHooks[GLESv2_INDEX][IMPL_SOFTWARE]; - cnx->dso = loader.open(EGL_DEFAULT_DISPLAY, 0, cnx); - } - - cnx = &gEGLImpl[IMPL_HARDWARE]; + // dynamically load our EGL implementation + egl_connection_t* cnx = &gEGLImpl; if (cnx->dso == 0) { - char value[PROPERTY_VALUE_MAX]; - property_get("debug.egl.hw", value, "1"); - if (atoi(value) != 0) { - cnx->hooks[GLESv1_INDEX] = &gHooks[GLESv1_INDEX][IMPL_HARDWARE]; - cnx->hooks[GLESv2_INDEX] = &gHooks[GLESv2_INDEX][IMPL_HARDWARE]; - cnx->dso = loader.open(EGL_DEFAULT_DISPLAY, 1, cnx); - } else { - ALOGD("3D hardware acceleration is disabled"); - } - } - - if (!gEGLImpl[IMPL_SOFTWARE].dso && !gEGLImpl[IMPL_HARDWARE].dso) { - return EGL_FALSE; + cnx->hooks[egl_connection_t::GLESv1_INDEX] = + &gHooks[egl_connection_t::GLESv1_INDEX]; + cnx->hooks[egl_connection_t::GLESv2_INDEX] = + &gHooks[egl_connection_t::GLESv2_INDEX]; + cnx->dso = loader.open(cnx); } - return EGL_TRUE; + return cnx->dso ? EGL_TRUE : EGL_FALSE; } static pthread_mutex_t sInitDriverMutex = PTHREAD_MUTEX_INITIALIZER; diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp index 73aab26..bb2783d 100644 --- a/opengl/libs/EGL/eglApi.cpp +++ b/opengl/libs/EGL/eglApi.cpp @@ -44,6 +44,7 @@ #include "egl_impl.h" #include "egl_object.h" #include "egl_tls.h" +#include "egldefs.h" using namespace android; @@ -88,24 +89,6 @@ static void(*findProcAddress(const char* name, // ---------------------------------------------------------------------------- -template<typename T> -static __attribute__((noinline)) -int binarySearch(T const sortedArray[], int first, int last, T key) { - while (first <= last) { - int mid = (first + last) / 2; - if (sortedArray[mid] < key) { - first = mid + 1; - } else if (key < sortedArray[mid]) { - last = mid - 1; - } else { - return mid; - } - } - return -1; -} - -// ---------------------------------------------------------------------------- - namespace android { extern void setGLHooksThreadSpecific(gl_hooks_t const *value); extern EGLBoolean egl_init_drivers(); @@ -183,21 +166,20 @@ EGLBoolean eglGetConfigs( EGLDisplay dpy, egl_display_t const * const dp = validate_display(dpy); if (!dp) return EGL_FALSE; - GLint numConfigs = dp->numTotalConfigs; - if (!configs) { - *num_config = numConfigs; - return EGL_TRUE; + if (num_config==0) { + return setError(EGL_BAD_PARAMETER, EGL_FALSE); } - GLint n = 0; - for (intptr_t i=0 ; i<dp->numTotalConfigs && config_size ; i++) { - *configs++ = EGLConfig(i); - config_size--; - n++; + EGLBoolean res = EGL_FALSE; + *num_config = 0; + + egl_connection_t* const cnx = &gEGLImpl; + if (cnx->dso) { + res = cnx->egl.eglGetConfigs( + dp->disp.dpy, configs, config_size, num_config); } - - *num_config = n; - return EGL_TRUE; + + return res; } EGLBoolean eglChooseConfig( EGLDisplay dpy, const EGLint *attrib_list, @@ -213,105 +195,13 @@ EGLBoolean eglChooseConfig( EGLDisplay dpy, const EGLint *attrib_list, return setError(EGL_BAD_PARAMETER, EGL_FALSE); } - EGLint n; EGLBoolean res = EGL_FALSE; *num_config = 0; - - // It is unfortunate, but we need to remap the EGL_CONFIG_IDs, - // to do this, we have to go through the attrib_list array once - // to figure out both its size and if it contains an EGL_CONFIG_ID - // key. If so, the full array is copied and patched. - // NOTE: we assume that there can be only one occurrence - // of EGL_CONFIG_ID. - - EGLint patch_index = -1; - GLint attr; - size_t size = 0; - if (attrib_list) { - while ((attr=attrib_list[size]) != EGL_NONE) { - if (attr == EGL_CONFIG_ID) - patch_index = size; - size += 2; - } - } - if (patch_index >= 0) { - size += 2; // we need copy the sentinel as well - EGLint* new_list = (EGLint*)malloc(size*sizeof(EGLint)); - if (new_list == 0) - return setError(EGL_BAD_ALLOC, EGL_FALSE); - memcpy(new_list, attrib_list, size*sizeof(EGLint)); - - // patch the requested EGL_CONFIG_ID - bool found = false; - EGLConfig ourConfig(0); - EGLint& configId(new_list[patch_index+1]); - for (intptr_t i=0 ; i<dp->numTotalConfigs ; i++) { - if (dp->configs[i].configId == configId) { - ourConfig = EGLConfig(i); - configId = dp->configs[i].implConfigId; - found = true; - break; - } - } - - egl_connection_t* const cnx = &gEGLImpl[dp->configs[intptr_t(ourConfig)].impl]; - if (found && cnx->dso) { - // and switch to the new list - attrib_list = const_cast<const EGLint *>(new_list); - - // At this point, the only configuration that can match is - // dp->configs[i][index], however, we don't know if it would be - // rejected because of the other attributes, so we do have to call - // cnx->egl.eglChooseConfig() -- but we don't have to loop - // through all the EGLimpl[]. - // We also know we can only get a single config back, and we know - // which one. - - res = cnx->egl.eglChooseConfig( - dp->disp[ dp->configs[intptr_t(ourConfig)].impl ].dpy, - attrib_list, configs, config_size, &n); - if (res && n>0) { - // n has to be 0 or 1, by construction, and we already know - // which config it will return (since there can be only one). - if (configs) { - configs[0] = ourConfig; - } - *num_config = 1; - } - } - - free(const_cast<EGLint *>(attrib_list)); - return res; - } - - - for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) { - egl_connection_t* const cnx = &gEGLImpl[i]; - if (cnx->dso) { - if (cnx->egl.eglChooseConfig( - dp->disp[i].dpy, attrib_list, configs, config_size, &n)) { - if (configs) { - // now we need to convert these client EGLConfig to our - // internal EGLConfig format. - // This is done in O(n Log(n)) time. - for (int j=0 ; j<n ; j++) { - egl_config_t key(i, configs[j]); - intptr_t index = binarySearch<egl_config_t>( - dp->configs, 0, dp->numTotalConfigs, key); - if (index >= 0) { - configs[j] = EGLConfig(index); - } else { - return setError(EGL_BAD_CONFIG, EGL_FALSE); - } - } - configs += n; - config_size -= n; - } - *num_config += n; - res = EGL_TRUE; - } - } + egl_connection_t* const cnx = &gEGLImpl; + if (cnx->dso) { + res = cnx->egl.eglChooseConfig( + dp->disp.dpy, attrib_list, configs, config_size, num_config); } return res; } @@ -325,13 +215,8 @@ EGLBoolean eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config, egl_connection_t* cnx = validate_display_config(dpy, config, dp); if (!cnx) return EGL_FALSE; - if (attribute == EGL_CONFIG_ID) { - *value = dp->configs[intptr_t(config)].configId; - return EGL_TRUE; - } return cnx->egl.eglGetConfigAttrib( - dp->disp[ dp->configs[intptr_t(config)].impl ].dpy, - dp->configs[intptr_t(config)].config, attribute, value); + dp->disp.dpy, config, attribute, value); } // ---------------------------------------------------------------------------- @@ -347,8 +232,7 @@ EGLSurface eglCreateWindowSurface( EGLDisplay dpy, EGLConfig config, egl_display_t const* dp = 0; egl_connection_t* cnx = validate_display_config(dpy, config, dp); if (cnx) { - EGLDisplay iDpy = dp->disp[ dp->configs[intptr_t(config)].impl ].dpy; - EGLConfig iConfig = dp->configs[intptr_t(config)].config; + EGLDisplay iDpy = dp->disp.dpy; EGLint format; if (native_window_api_connect(window, NATIVE_WINDOW_API_EGL) != OK) { @@ -359,7 +243,7 @@ EGLSurface eglCreateWindowSurface( EGLDisplay dpy, EGLConfig config, // set the native window's buffers format to match this config if (cnx->egl.eglGetConfigAttrib(iDpy, - iConfig, EGL_NATIVE_VISUAL_ID, &format)) { + config, EGL_NATIVE_VISUAL_ID, &format)) { if (format != 0) { int err = native_window_set_buffers_format(window, format); if (err != 0) { @@ -377,10 +261,9 @@ EGLSurface eglCreateWindowSurface( EGLDisplay dpy, EGLConfig config, anw->setSwapInterval(anw, 1); EGLSurface surface = cnx->egl.eglCreateWindowSurface( - iDpy, iConfig, window, attrib_list); + iDpy, config, window, attrib_list); if (surface != EGL_NO_SURFACE) { - egl_surface_t* s = new egl_surface_t(dpy, config, window, surface, - dp->configs[intptr_t(config)].impl, cnx); + egl_surface_t* s = new egl_surface_t(dpy, config, window, surface, cnx); return s; } @@ -401,11 +284,9 @@ EGLSurface eglCreatePixmapSurface( EGLDisplay dpy, EGLConfig config, egl_connection_t* cnx = validate_display_config(dpy, config, dp); if (cnx) { EGLSurface surface = cnx->egl.eglCreatePixmapSurface( - dp->disp[ dp->configs[intptr_t(config)].impl ].dpy, - dp->configs[intptr_t(config)].config, pixmap, attrib_list); + dp->disp.dpy, config, pixmap, attrib_list); if (surface != EGL_NO_SURFACE) { - egl_surface_t* s = new egl_surface_t(dpy, config, NULL, surface, - dp->configs[intptr_t(config)].impl, cnx); + egl_surface_t* s = new egl_surface_t(dpy, config, NULL, surface, cnx); return s; } } @@ -421,11 +302,9 @@ EGLSurface eglCreatePbufferSurface( EGLDisplay dpy, EGLConfig config, egl_connection_t* cnx = validate_display_config(dpy, config, dp); if (cnx) { EGLSurface surface = cnx->egl.eglCreatePbufferSurface( - dp->disp[ dp->configs[intptr_t(config)].impl ].dpy, - dp->configs[intptr_t(config)].config, attrib_list); + dp->disp.dpy, config, attrib_list); if (surface != EGL_NO_SURFACE) { - egl_surface_t* s = new egl_surface_t(dpy, config, NULL, surface, - dp->configs[intptr_t(config)].impl, cnx); + egl_surface_t* s = new egl_surface_t(dpy, config, NULL, surface, cnx); return s; } } @@ -444,8 +323,7 @@ EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface surface) return setError(EGL_BAD_SURFACE, EGL_FALSE); egl_surface_t * const s = get_surface(surface); - EGLBoolean result = s->cnx->egl.eglDestroySurface( - dp->disp[s->impl].dpy, s->surface); + EGLBoolean result = s->cnx->egl.eglDestroySurface(dp->disp.dpy, s->surface); if (result == EGL_TRUE) { _s.terminate(); } @@ -465,16 +343,8 @@ EGLBoolean eglQuerySurface( EGLDisplay dpy, EGLSurface surface, return setError(EGL_BAD_SURFACE, EGL_FALSE); egl_surface_t const * const s = get_surface(surface); - EGLBoolean result(EGL_TRUE); - if (attribute == EGL_CONFIG_ID) { - // We need to remap EGL_CONFIG_IDs - *value = dp->configs[intptr_t(s->config)].configId; - } else { - result = s->cnx->egl.eglQuerySurface( - dp->disp[s->impl].dpy, s->surface, attribute, value); - } - - return result; + return s->cnx->egl.eglQuerySurface( + dp->disp.dpy, s->surface, attribute, value); } void EGLAPI eglBeginFrame(EGLDisplay dpy, EGLSurface surface) { @@ -514,9 +384,7 @@ EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config, share_list = c->context; } EGLContext context = cnx->egl.eglCreateContext( - dp->disp[ dp->configs[intptr_t(config)].impl ].dpy, - dp->configs[intptr_t(config)].config, - share_list, attrib_list); + dp->disp.dpy, config, share_list, attrib_list); if (context != EGL_NO_CONTEXT) { // figure out if it's a GLESv1 or GLESv2 int version = 0; @@ -526,15 +394,14 @@ EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config, GLint value = *attrib_list++; if (attr == EGL_CONTEXT_CLIENT_VERSION) { if (value == 1) { - version = GLESv1_INDEX; + version = egl_connection_t::GLESv1_INDEX; } else if (value == 2) { - version = GLESv2_INDEX; + version = egl_connection_t::GLESv2_INDEX; } } }; } - egl_context_t* c = new egl_context_t(dpy, context, config, - dp->configs[intptr_t(config)].impl, cnx, version); + egl_context_t* c = new egl_context_t(dpy, context, config, cnx, version); #if EGL_TRACE if (gEGLDebugLevel > 0) GLTrace_eglCreateContext(version, c); @@ -558,8 +425,7 @@ EGLBoolean eglDestroyContext(EGLDisplay dpy, EGLContext ctx) return setError(EGL_BAD_CONTEXT, EGL_FALSE); egl_context_t * const c = get_context(ctx); - EGLBoolean result = c->cnx->egl.eglDestroyContext( - dp->disp[c->impl].dpy, c->context); + EGLBoolean result = c->cnx->egl.eglDestroyContext(dp->disp.dpy, c->context); if (result == EGL_TRUE) { _c.terminate(); } @@ -625,20 +491,12 @@ EGLBoolean eglMakeCurrent( EGLDisplay dpy, EGLSurface draw, // retrieve the underlying implementation's draw EGLSurface if (draw != EGL_NO_SURFACE) { d = get_surface(draw); - // make sure the EGLContext and EGLSurface passed in are for - // the same driver - if (c && d->impl != c->impl) - return setError(EGL_BAD_MATCH, EGL_FALSE); impl_draw = d->surface; } // retrieve the underlying implementation's read EGLSurface if (read != EGL_NO_SURFACE) { r = get_surface(read); - // make sure the EGLContext and EGLSurface passed in are for - // the same driver - if (c && r->impl != c->impl) - return setError(EGL_BAD_MATCH, EGL_FALSE); impl_read = r->surface; } @@ -682,17 +540,9 @@ EGLBoolean eglQueryContext( EGLDisplay dpy, EGLContext ctx, if (!_c.get()) return setError(EGL_BAD_CONTEXT, EGL_FALSE); egl_context_t * const c = get_context(ctx); + return c->cnx->egl.eglQueryContext( + dp->disp.dpy, c->context, attribute, value); - EGLBoolean result(EGL_TRUE); - if (attribute == EGL_CONFIG_ID) { - *value = dp->configs[intptr_t(c->config)].configId; - } else { - // We need to remap EGL_CONFIG_IDs - result = c->cnx->egl.eglQueryContext( - dp->disp[c->impl].dpy, c->context, attribute, value); - } - - return result; } EGLContext eglGetCurrentContext(void) @@ -744,64 +594,37 @@ EGLDisplay eglGetCurrentDisplay(void) EGLBoolean eglWaitGL(void) { - // could be called before eglInitialize(), but we wouldn't have a context - // then, and this function would return GL_TRUE, which isn't wrong. - clearError(); - EGLBoolean res = EGL_TRUE; - EGLContext ctx = getContext(); - if (ctx) { - egl_context_t const * const c = get_context(ctx); - if (!c) return setError(EGL_BAD_CONTEXT, EGL_FALSE); - if (uint32_t(c->impl)>=2) - return setError(EGL_BAD_CONTEXT, EGL_FALSE); - egl_connection_t* const cnx = &gEGLImpl[c->impl]; - if (!cnx->dso) - return setError(EGL_BAD_CONTEXT, EGL_FALSE); - res = cnx->egl.eglWaitGL(); - } - return res; + egl_connection_t* const cnx = &gEGLImpl; + if (!cnx->dso) + return setError(EGL_BAD_CONTEXT, EGL_FALSE); + + return cnx->egl.eglWaitGL(); } EGLBoolean eglWaitNative(EGLint engine) { - // could be called before eglInitialize(), but we wouldn't have a context - // then, and this function would return GL_TRUE, which isn't wrong. - clearError(); - EGLBoolean res = EGL_TRUE; - EGLContext ctx = getContext(); - if (ctx) { - egl_context_t const * const c = get_context(ctx); - if (!c) return setError(EGL_BAD_CONTEXT, EGL_FALSE); - if (uint32_t(c->impl)>=2) - return setError(EGL_BAD_CONTEXT, EGL_FALSE); - egl_connection_t* const cnx = &gEGLImpl[c->impl]; - if (!cnx->dso) - return setError(EGL_BAD_CONTEXT, EGL_FALSE); - res = cnx->egl.eglWaitNative(engine); - } - return res; + egl_connection_t* const cnx = &gEGLImpl; + if (!cnx->dso) + return setError(EGL_BAD_CONTEXT, EGL_FALSE); + + return cnx->egl.eglWaitNative(engine); } EGLint eglGetError(void) { - EGLint result = EGL_SUCCESS; - EGLint err; - for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) { - err = EGL_SUCCESS; - egl_connection_t* const cnx = &gEGLImpl[i]; - if (cnx->dso) - err = cnx->egl.eglGetError(); - if (err!=EGL_SUCCESS && result==EGL_SUCCESS) - result = err; + EGLint err = EGL_SUCCESS; + egl_connection_t* const cnx = &gEGLImpl; + if (cnx->dso) { + err = cnx->egl.eglGetError(); } - err = egl_tls_t::getError(); - if (result == EGL_SUCCESS) - result = err; - return result; + if (err == EGL_SUCCESS) { + err = egl_tls_t::getError(); + } + return err; } // Note: Similar implementations of these functions also exist in @@ -885,20 +708,20 @@ __eglMustCastToProperFunctionPointerType eglGetProcAddress(const char *procname) if (!addr && (slot < MAX_NUMBER_OF_GL_EXTENSIONS)) { bool found = false; - for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) { - egl_connection_t* const cnx = &gEGLImpl[i]; - if (cnx->dso && cnx->egl.eglGetProcAddress) { - found = true; - // Extensions are independent of the bound context - cnx->hooks[GLESv1_INDEX]->ext.extensions[slot] = - cnx->hooks[GLESv2_INDEX]->ext.extensions[slot] = + + egl_connection_t* const cnx = &gEGLImpl; + if (cnx->dso && cnx->egl.eglGetProcAddress) { + found = true; + // Extensions are independent of the bound context + cnx->hooks[egl_connection_t::GLESv1_INDEX]->ext.extensions[slot] = + cnx->hooks[egl_connection_t::GLESv2_INDEX]->ext.extensions[slot] = #if EGL_TRACE - debugHooks->ext.extensions[slot] = - gHooksTrace.ext.extensions[slot] = + debugHooks->ext.extensions[slot] = + gHooksTrace.ext.extensions[slot] = #endif - cnx->egl.eglGetProcAddress(procname); - } + cnx->egl.eglGetProcAddress(procname); } + if (found) { addr = gExtensionForwarders[slot]; @@ -937,7 +760,7 @@ EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface draw) #endif egl_surface_t const * const s = get_surface(draw); - return s->cnx->egl.eglSwapBuffers(dp->disp[s->impl].dpy, s->surface); + return s->cnx->egl.eglSwapBuffers(dp->disp.dpy, s->surface); } EGLBoolean eglCopyBuffers( EGLDisplay dpy, EGLSurface surface, @@ -953,8 +776,7 @@ EGLBoolean eglCopyBuffers( EGLDisplay dpy, EGLSurface surface, return setError(EGL_BAD_SURFACE, EGL_FALSE); egl_surface_t const * const s = get_surface(surface); - return s->cnx->egl.eglCopyBuffers( - dp->disp[s->impl].dpy, s->surface, target); + return s->cnx->egl.eglCopyBuffers(dp->disp.dpy, s->surface, target); } const char* eglQueryString(EGLDisplay dpy, EGLint name) @@ -973,12 +795,8 @@ const char* eglQueryString(EGLDisplay dpy, EGLint name) return dp->getExtensionString(); case EGL_CLIENT_APIS: return dp->getClientApiString(); - case EGL_VERSION_HW_ANDROID: { - if (gEGLImpl[IMPL_HARDWARE].dso) { - return dp->disp[IMPL_HARDWARE].queryString.version; - } - return dp->disp[IMPL_SOFTWARE].queryString.version; - } + case EGL_VERSION_HW_ANDROID: + return dp->disp.queryString.version; } return setError(EGL_BAD_PARAMETER, (const char *)0); } @@ -1003,7 +821,7 @@ EGLBoolean eglSurfaceAttrib( egl_surface_t const * const s = get_surface(surface); if (s->cnx->egl.eglSurfaceAttrib) { return s->cnx->egl.eglSurfaceAttrib( - dp->disp[s->impl].dpy, s->surface, attribute, value); + dp->disp.dpy, s->surface, attribute, value); } return setError(EGL_BAD_SURFACE, EGL_FALSE); } @@ -1023,7 +841,7 @@ EGLBoolean eglBindTexImage( egl_surface_t const * const s = get_surface(surface); if (s->cnx->egl.eglBindTexImage) { return s->cnx->egl.eglBindTexImage( - dp->disp[s->impl].dpy, s->surface, buffer); + dp->disp.dpy, s->surface, buffer); } return setError(EGL_BAD_SURFACE, EGL_FALSE); } @@ -1043,7 +861,7 @@ EGLBoolean eglReleaseTexImage( egl_surface_t const * const s = get_surface(surface); if (s->cnx->egl.eglReleaseTexImage) { return s->cnx->egl.eglReleaseTexImage( - dp->disp[s->impl].dpy, s->surface, buffer); + dp->disp.dpy, s->surface, buffer); } return setError(EGL_BAD_SURFACE, EGL_FALSE); } @@ -1056,17 +874,11 @@ EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval) if (!dp) return EGL_FALSE; EGLBoolean res = EGL_TRUE; - for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) { - egl_connection_t* const cnx = &gEGLImpl[i]; - if (cnx->dso) { - if (cnx->egl.eglSwapInterval) { - if (cnx->egl.eglSwapInterval( - dp->disp[i].dpy, interval) == EGL_FALSE) { - res = EGL_FALSE; - } - } - } + egl_connection_t* const cnx = &gEGLImpl; + if (cnx->dso && cnx->egl.eglSwapInterval) { + res = cnx->egl.eglSwapInterval(dp->disp.dpy, interval); } + return res; } @@ -1079,23 +891,15 @@ EGLBoolean eglWaitClient(void) { clearError(); - // could be called before eglInitialize(), but we wouldn't have a context - // then, and this function would return GL_TRUE, which isn't wrong. - EGLBoolean res = EGL_TRUE; - EGLContext ctx = getContext(); - if (ctx) { - egl_context_t const * const c = get_context(ctx); - if (!c) return setError(EGL_BAD_CONTEXT, EGL_FALSE); - if (uint32_t(c->impl)>=2) - return setError(EGL_BAD_CONTEXT, EGL_FALSE); - egl_connection_t* const cnx = &gEGLImpl[c->impl]; - if (!cnx->dso) - return setError(EGL_BAD_CONTEXT, EGL_FALSE); - if (cnx->egl.eglWaitClient) { - res = cnx->egl.eglWaitClient(); - } else { - res = cnx->egl.eglWaitGL(); - } + egl_connection_t* const cnx = &gEGLImpl; + if (!cnx->dso) + return setError(EGL_BAD_CONTEXT, EGL_FALSE); + + EGLBoolean res; + if (cnx->egl.eglWaitClient) { + res = cnx->egl.eglWaitClient(); + } else { + res = cnx->egl.eglWaitGL(); } return res; } @@ -1110,15 +914,9 @@ EGLBoolean eglBindAPI(EGLenum api) // bind this API on all EGLs EGLBoolean res = EGL_TRUE; - for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) { - egl_connection_t* const cnx = &gEGLImpl[i]; - if (cnx->dso) { - if (cnx->egl.eglBindAPI) { - if (cnx->egl.eglBindAPI(api) == EGL_FALSE) { - res = EGL_FALSE; - } - } - } + egl_connection_t* const cnx = &gEGLImpl; + if (cnx->dso && cnx->egl.eglBindAPI) { + res = cnx->egl.eglBindAPI(api); } return res; } @@ -1131,16 +929,11 @@ EGLenum eglQueryAPI(void) return setError(EGL_BAD_PARAMETER, EGL_FALSE); } - for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) { - egl_connection_t* const cnx = &gEGLImpl[i]; - if (cnx->dso) { - if (cnx->egl.eglQueryAPI) { - // the first one we find is okay, because they all - // should be the same - return cnx->egl.eglQueryAPI(); - } - } + egl_connection_t* const cnx = &gEGLImpl; + if (cnx->dso && cnx->egl.eglQueryAPI) { + return cnx->egl.eglQueryAPI(); } + // or, it can only be OpenGL ES return EGL_OPENGL_ES_API; } @@ -1152,14 +945,11 @@ EGLBoolean eglReleaseThread(void) // If there is context bound to the thread, release it egl_display_t::loseCurrent(get_context(getContext())); - for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) { - egl_connection_t* const cnx = &gEGLImpl[i]; - if (cnx->dso) { - if (cnx->egl.eglReleaseThread) { - cnx->egl.eglReleaseThread(); - } - } + egl_connection_t* const cnx = &gEGLImpl; + if (cnx->dso && cnx->egl.eglReleaseThread) { + cnx->egl.eglReleaseThread(); } + egl_tls_t::clearTLS(); #if EGL_TRACE if (gEGLDebugLevel > 0) @@ -1179,9 +969,7 @@ EGLSurface eglCreatePbufferFromClientBuffer( if (!cnx) return EGL_FALSE; if (cnx->egl.eglCreatePbufferFromClientBuffer) { return cnx->egl.eglCreatePbufferFromClientBuffer( - dp->disp[ dp->configs[intptr_t(config)].impl ].dpy, - buftype, buffer, - dp->configs[intptr_t(config)].config, attrib_list); + dp->disp.dpy, buftype, buffer, config, attrib_list); } return setError(EGL_BAD_CONFIG, EGL_NO_SURFACE); } @@ -1205,7 +993,7 @@ EGLBoolean eglLockSurfaceKHR(EGLDisplay dpy, EGLSurface surface, egl_surface_t const * const s = get_surface(surface); if (s->cnx->egl.eglLockSurfaceKHR) { return s->cnx->egl.eglLockSurfaceKHR( - dp->disp[s->impl].dpy, s->surface, attrib_list); + dp->disp.dpy, s->surface, attrib_list); } return setError(EGL_BAD_DISPLAY, EGL_FALSE); } @@ -1223,8 +1011,7 @@ EGLBoolean eglUnlockSurfaceKHR(EGLDisplay dpy, EGLSurface surface) egl_surface_t const * const s = get_surface(surface); if (s->cnx->egl.eglUnlockSurfaceKHR) { - return s->cnx->egl.eglUnlockSurfaceKHR( - dp->disp[s->impl].dpy, s->surface); + return s->cnx->egl.eglUnlockSurfaceKHR(dp->disp.dpy, s->surface); } return setError(EGL_BAD_DISPLAY, EGL_FALSE); } @@ -1244,12 +1031,12 @@ EGLImageKHR eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target, egl_context_t * const c = get_context(ctx); // since we have an EGLContext, we know which implementation to use EGLImageKHR image = c->cnx->egl.eglCreateImageKHR( - dp->disp[c->impl].dpy, c->context, target, buffer, attrib_list); + dp->disp.dpy, c->context, target, buffer, attrib_list); if (image == EGL_NO_IMAGE_KHR) return image; egl_image_t* result = new egl_image_t(dpy, ctx); - result->images[c->impl] = image; + result->image = image; return (EGLImageKHR)result; } else { // EGL_NO_CONTEXT is a valid parameter @@ -1261,23 +1048,14 @@ EGLImageKHR eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLint currentError = eglGetError(); - EGLImageKHR implImages[IMPL_NUM_IMPLEMENTATIONS]; - bool success = false; - for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) { - egl_connection_t* const cnx = &gEGLImpl[i]; - implImages[i] = EGL_NO_IMAGE_KHR; - if (cnx->dso) { - if (cnx->egl.eglCreateImageKHR) { - implImages[i] = cnx->egl.eglCreateImageKHR( - dp->disp[i].dpy, ctx, target, buffer, attrib_list); - if (implImages[i] != EGL_NO_IMAGE_KHR) { - success = true; - } - } - } + EGLImageKHR implImage = EGL_NO_IMAGE_KHR; + egl_connection_t* const cnx = &gEGLImpl; + if (cnx->dso && cnx->egl.eglCreateImageKHR) { + implImage = cnx->egl.eglCreateImageKHR( + dp->disp.dpy, ctx, target, buffer, attrib_list); } - if (!success) { + if (implImage == EGL_NO_IMAGE_KHR) { // failure, if there was an error when we entered this function, // the error flag must not be updated. // Otherwise, the error is whatever happened in the implementation @@ -1289,13 +1067,12 @@ EGLImageKHR eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target, } else { // In case of success, we need to clear all error flags // (especially those caused by the implementation that didn't - // succeed). TODO: we could avoid this if we knew this was - // a "full" success (all implementation succeeded). + // succeed). eglGetError(); } egl_image_t* result = new egl_image_t(dpy, ctx); - memcpy(result->images, implImages, sizeof(implImages)); + result->image = implImage; return (EGLImageKHR)result; } } @@ -1312,19 +1089,17 @@ EGLBoolean eglDestroyImageKHR(EGLDisplay dpy, EGLImageKHR img) egl_image_t* image = get_image(img); bool success = false; - for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) { - egl_connection_t* const cnx = &gEGLImpl[i]; - if (image->images[i] != EGL_NO_IMAGE_KHR) { - if (cnx->dso) { - if (cnx->egl.eglDestroyImageKHR) { - if (cnx->egl.eglDestroyImageKHR( - dp->disp[i].dpy, image->images[i])) { - success = true; - } - } + + egl_connection_t* const cnx = &gEGLImpl; + if (image->image != EGL_NO_IMAGE_KHR) { + if (cnx->dso && cnx->egl.eglDestroyImageKHR) { + if (cnx->egl.eglDestroyImageKHR( + dp->disp.dpy, image->image)) { + success = true; } } } + if (!success) return EGL_FALSE; @@ -1354,7 +1129,7 @@ EGLSyncKHR eglCreateSyncKHR(EGLDisplay dpy, EGLenum type, const EGLint *attrib_l EGLSyncKHR result = EGL_NO_SYNC_KHR; if (c->cnx->egl.eglCreateSyncKHR) { EGLSyncKHR sync = c->cnx->egl.eglCreateSyncKHR( - dp->disp[c->impl].dpy, type, attrib_list); + dp->disp.dpy, type, attrib_list); if (sync == EGL_NO_SYNC_KHR) return sync; result = (egl_sync_t*)new egl_sync_t(dpy, ctx, sync); @@ -1382,7 +1157,7 @@ EGLBoolean eglDestroySyncKHR(EGLDisplay dpy, EGLSyncKHR sync) egl_context_t * const c = get_context(ctx); if (c->cnx->egl.eglDestroySyncKHR) { result = c->cnx->egl.eglDestroySyncKHR( - dp->disp[c->impl].dpy, syncObject->sync); + dp->disp.dpy, syncObject->sync); if (result) _s.terminate(); } @@ -1408,7 +1183,7 @@ EGLint eglClientWaitSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint flags, EGLTi egl_context_t * const c = get_context(ctx); if (c->cnx->egl.eglClientWaitSyncKHR) { return c->cnx->egl.eglClientWaitSyncKHR( - dp->disp[c->impl].dpy, syncObject->sync, flags, timeout); + dp->disp.dpy, syncObject->sync, flags, timeout); } return EGL_FALSE; @@ -1434,7 +1209,7 @@ EGLBoolean eglGetSyncAttribKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint attribute egl_context_t * const c = get_context(ctx); if (c->cnx->egl.eglGetSyncAttribKHR) { return c->cnx->egl.eglGetSyncAttribKHR( - dp->disp[c->impl].dpy, syncObject->sync, attribute, value); + dp->disp.dpy, syncObject->sync, attribute, value); } return EGL_FALSE; @@ -1458,12 +1233,10 @@ EGLuint64NV eglGetSystemTimeFrequencyNV() } EGLuint64NV ret = 0; - egl_connection_t* const cnx = &gEGLImpl[IMPL_HARDWARE]; + egl_connection_t* const cnx = &gEGLImpl; - if (cnx->dso) { - if (cnx->egl.eglGetSystemTimeFrequencyNV) { - return cnx->egl.eglGetSystemTimeFrequencyNV(); - } + if (cnx->dso && cnx->egl.eglGetSystemTimeFrequencyNV) { + return cnx->egl.eglGetSystemTimeFrequencyNV(); } return setErrorQuiet(EGL_BAD_DISPLAY, 0); @@ -1478,12 +1251,10 @@ EGLuint64NV eglGetSystemTimeNV() } EGLuint64NV ret = 0; - egl_connection_t* const cnx = &gEGLImpl[IMPL_HARDWARE]; + egl_connection_t* const cnx = &gEGLImpl; - if (cnx->dso) { - if (cnx->egl.eglGetSystemTimeNV) { - return cnx->egl.eglGetSystemTimeNV(); - } + if (cnx->dso && cnx->egl.eglGetSystemTimeNV) { + return cnx->egl.eglGetSystemTimeNV(); } return setErrorQuiet(EGL_BAD_DISPLAY, 0); diff --git a/opengl/libs/EGL/egl_cache.cpp b/opengl/libs/EGL/egl_cache.cpp index 7fd6519..c79fb5f 100644 --- a/opengl/libs/EGL/egl_cache.cpp +++ b/opengl/libs/EGL/egl_cache.cpp @@ -83,39 +83,39 @@ egl_cache_t* egl_cache_t::get() { void egl_cache_t::initialize(egl_display_t *display) { Mutex::Autolock lock(mMutex); - for (int i = 0; i < IMPL_NUM_IMPLEMENTATIONS; i++) { - egl_connection_t* const cnx = &gEGLImpl[i]; - if (cnx->dso && cnx->major >= 0 && cnx->minor >= 0) { - const char* exts = display->disp[i].queryString.extensions; - size_t bcExtLen = strlen(BC_EXT_STR); - size_t extsLen = strlen(exts); - bool equal = !strcmp(BC_EXT_STR, exts); - bool atStart = !strncmp(BC_EXT_STR " ", exts, bcExtLen+1); - bool atEnd = (bcExtLen+1) < extsLen && - !strcmp(" " BC_EXT_STR, exts + extsLen - (bcExtLen+1)); - bool inMiddle = strstr(exts, " " BC_EXT_STR " "); - if (equal || atStart || atEnd || inMiddle) { - PFNEGLSETBLOBCACHEFUNCSANDROIDPROC eglSetBlobCacheFuncsANDROID; - eglSetBlobCacheFuncsANDROID = - reinterpret_cast<PFNEGLSETBLOBCACHEFUNCSANDROIDPROC>( + + egl_connection_t* const cnx = &gEGLImpl; + if (cnx->dso && cnx->major >= 0 && cnx->minor >= 0) { + const char* exts = display->disp.queryString.extensions; + size_t bcExtLen = strlen(BC_EXT_STR); + size_t extsLen = strlen(exts); + bool equal = !strcmp(BC_EXT_STR, exts); + bool atStart = !strncmp(BC_EXT_STR " ", exts, bcExtLen+1); + bool atEnd = (bcExtLen+1) < extsLen && + !strcmp(" " BC_EXT_STR, exts + extsLen - (bcExtLen+1)); + bool inMiddle = strstr(exts, " " BC_EXT_STR " "); + if (equal || atStart || atEnd || inMiddle) { + PFNEGLSETBLOBCACHEFUNCSANDROIDPROC eglSetBlobCacheFuncsANDROID; + eglSetBlobCacheFuncsANDROID = + reinterpret_cast<PFNEGLSETBLOBCACHEFUNCSANDROIDPROC>( cnx->egl.eglGetProcAddress( "eglSetBlobCacheFuncsANDROID")); - if (eglSetBlobCacheFuncsANDROID == NULL) { - ALOGE("EGL_ANDROID_blob_cache advertised by display %d, " - "but unable to get eglSetBlobCacheFuncsANDROID", i); - continue; - } + if (eglSetBlobCacheFuncsANDROID == NULL) { + ALOGE("EGL_ANDROID_blob_cache advertised, " + "but unable to get eglSetBlobCacheFuncsANDROID"); + return; + } - eglSetBlobCacheFuncsANDROID(display->disp[i].dpy, - android::setBlob, android::getBlob); - EGLint err = cnx->egl.eglGetError(); - if (err != EGL_SUCCESS) { - ALOGE("eglSetBlobCacheFuncsANDROID resulted in an error: " - "%#x", err); - } + eglSetBlobCacheFuncsANDROID(display->disp.dpy, + android::setBlob, android::getBlob); + EGLint err = cnx->egl.eglGetError(); + if (err != EGL_SUCCESS) { + ALOGE("eglSetBlobCacheFuncsANDROID resulted in an error: " + "%#x", err); } } } + mInitialized = true; } diff --git a/opengl/libs/EGL/egl_display.cpp b/opengl/libs/EGL/egl_display.cpp index 6b2ae51..c85b4ce 100644 --- a/opengl/libs/EGL/egl_display.cpp +++ b/opengl/libs/EGL/egl_display.cpp @@ -60,18 +60,12 @@ static char const * const sExtensionString = extern void initEglTraceLevel(); extern void setGLHooksThreadSpecific(gl_hooks_t const *value); -static int cmp_configs(const void* a, const void *b) { - const egl_config_t& c0 = *(egl_config_t const *)a; - const egl_config_t& c1 = *(egl_config_t const *)b; - return c0<c1 ? -1 : (c1<c0 ? 1 : 0); -} - // ---------------------------------------------------------------------------- egl_display_t egl_display_t::sDisplay[NUM_DISPLAYS]; egl_display_t::egl_display_t() : - magic('_dpy'), numTotalConfigs(0), configs(0), refs(0) { + magic('_dpy'), refs(0) { } egl_display_t::~egl_display_t() { @@ -119,15 +113,13 @@ EGLDisplay egl_display_t::getDisplay(EGLNativeDisplayType display) { // get our driver loader Loader& loader(Loader::getInstance()); - for (int i = 0; i < IMPL_NUM_IMPLEMENTATIONS; i++) { - egl_connection_t* const cnx = &gEGLImpl[i]; - if (cnx->dso && disp[i].dpy == EGL_NO_DISPLAY) { - EGLDisplay dpy = cnx->egl.eglGetDisplay(display); - disp[i].dpy = dpy; - if (dpy == EGL_NO_DISPLAY) { - loader.close(cnx->dso); - cnx->dso = NULL; - } + egl_connection_t* const cnx = &gEGLImpl; + if (cnx->dso && disp.dpy == EGL_NO_DISPLAY) { + EGLDisplay dpy = cnx->egl.eglGetDisplay(display); + disp.dpy = dpy; + if (dpy == EGL_NO_DISPLAY) { + loader.close(cnx->dso); + cnx->dso = NULL; } } @@ -160,12 +152,11 @@ EGLBoolean egl_display_t::initialize(EGLint *major, EGLint *minor) { // initialize each EGL and // build our own extension string first, based on the extension we know // and the extension supported by our client implementation - for (int i = 0; i < IMPL_NUM_IMPLEMENTATIONS; i++) { - egl_connection_t* const cnx = &gEGLImpl[i]; - cnx->major = -1; - cnx->minor = -1; - if (!cnx->dso) - continue; + + egl_connection_t* const cnx = &gEGLImpl; + cnx->major = -1; + cnx->minor = -1; + if (cnx->dso) { #if defined(ADRENO130) #warning "Adreno-130 eglInitialize() workaround" @@ -177,31 +168,30 @@ EGLBoolean egl_display_t::initialize(EGLint *major, EGLint *minor) { * eglGetDisplay() before calling eglInitialize(); */ if (i == IMPL_HARDWARE) { - disp[i].dpy = - cnx->egl.eglGetDisplay(EGL_DEFAULT_DISPLAY); + disp[i].dpy = cnx->egl.eglGetDisplay(EGL_DEFAULT_DISPLAY); } #endif - EGLDisplay idpy = disp[i].dpy; + EGLDisplay idpy = disp.dpy; if (cnx->egl.eglInitialize(idpy, &cnx->major, &cnx->minor)) { - //ALOGD("initialized %d dpy=%p, ver=%d.%d, cnx=%p", - // i, idpy, cnx->major, cnx->minor, cnx); + //ALOGD("initialized dpy=%p, ver=%d.%d, cnx=%p", + // idpy, cnx->major, cnx->minor, cnx); // display is now initialized - disp[i].state = egl_display_t::INITIALIZED; + disp.state = egl_display_t::INITIALIZED; // get the query-strings for this display for each implementation - disp[i].queryString.vendor = cnx->egl.eglQueryString(idpy, + disp.queryString.vendor = cnx->egl.eglQueryString(idpy, EGL_VENDOR); - disp[i].queryString.version = cnx->egl.eglQueryString(idpy, + disp.queryString.version = cnx->egl.eglQueryString(idpy, EGL_VERSION); - disp[i].queryString.extensions = cnx->egl.eglQueryString(idpy, + disp.queryString.extensions = cnx->egl.eglQueryString(idpy, EGL_EXTENSIONS); - disp[i].queryString.clientApi = cnx->egl.eglQueryString(idpy, + disp.queryString.clientApi = cnx->egl.eglQueryString(idpy, EGL_CLIENT_APIS); } else { - ALOGW("%d: eglInitialize(%p) failed (%s)", i, idpy, + ALOGW("eglInitialize(%p) failed (%s)", idpy, egl_tls_t::egl_strerror(cnx->egl.eglGetError())); } } @@ -211,7 +201,7 @@ EGLBoolean egl_display_t::initialize(EGLint *major, EGLint *minor) { mVersionString.setTo(sVersionString); mClientApiString.setTo(sClientApiString); - // we only add extensions that exist in at least one implementation + // we only add extensions that exist in the implementation char const* start = sExtensionString; char const* end; do { @@ -223,15 +213,13 @@ EGLBoolean egl_display_t::initialize(EGLint *major, EGLint *minor) { if (len) { // NOTE: we could avoid the copy if we had strnstr. const String8 ext(start, len); - // now go through all implementations and look for this extension - for (int i = 0; i < IMPL_NUM_IMPLEMENTATIONS; i++) { - if (disp[i].queryString.extensions) { - // if we find it, add this extension string to our list - // (and don't forget the space) - const char* match = strstr(disp[i].queryString.extensions, ext.string()); - if (match && (match[len] == ' ' || match[len] == 0)) { - mExtensionString.append(start, len+1); - } + // now look for this extension + if (disp.queryString.extensions) { + // if we find it, add this extension string to our list + // (and don't forget the space) + const char* match = strstr(disp.queryString.extensions, ext.string()); + if (match && (match[len] == ' ' || match[len] == 0)) { + mExtensionString.append(start, len+1); } } } @@ -242,52 +230,12 @@ EGLBoolean egl_display_t::initialize(EGLint *major, EGLint *minor) { egl_cache_t::get()->initialize(this); - EGLBoolean res = EGL_FALSE; - for (int i = 0; i < IMPL_NUM_IMPLEMENTATIONS; i++) { - egl_connection_t* const cnx = &gEGLImpl[i]; - if (cnx->dso && cnx->major >= 0 && cnx->minor >= 0) { - EGLint n; - if (cnx->egl.eglGetConfigs(disp[i].dpy, 0, 0, &n)) { - disp[i].config = (EGLConfig*) malloc(sizeof(EGLConfig) * n); - if (disp[i].config) { - if (cnx->egl.eglGetConfigs(disp[i].dpy, disp[i].config, n, - &disp[i].numConfigs)) { - numTotalConfigs += n; - res = EGL_TRUE; - } - } - } - } - } - - if (res == EGL_TRUE) { - configs = new egl_config_t[numTotalConfigs]; - for (int i = 0, k = 0; i < IMPL_NUM_IMPLEMENTATIONS; i++) { - egl_connection_t* const cnx = &gEGLImpl[i]; - if (cnx->dso && cnx->major >= 0 && cnx->minor >= 0) { - for (int j = 0; j < disp[i].numConfigs; j++) { - configs[k].impl = i; - configs[k].config = disp[i].config[j]; - configs[k].configId = k + 1; // CONFIG_ID start at 1 - // store the implementation's CONFIG_ID - cnx->egl.eglGetConfigAttrib(disp[i].dpy, disp[i].config[j], - EGL_CONFIG_ID, &configs[k].implConfigId); - k++; - } - } - } - - // sort our configurations so we can do binary-searches - qsort(configs, numTotalConfigs, sizeof(egl_config_t), cmp_configs); - - refs++; - if (major != NULL) - *major = VERSION_MAJOR; - if (minor != NULL) - *minor = VERSION_MINOR; - return EGL_TRUE; - } - return setError(EGL_NOT_INITIALIZED, EGL_FALSE); + refs++; + if (major != NULL) + *major = VERSION_MAJOR; + if (minor != NULL) + *minor = VERSION_MINOR; + return EGL_TRUE; } EGLBoolean egl_display_t::terminate() { @@ -305,22 +253,15 @@ EGLBoolean egl_display_t::terminate() { } EGLBoolean res = EGL_FALSE; - for (int i = 0; i < IMPL_NUM_IMPLEMENTATIONS; i++) { - egl_connection_t* const cnx = &gEGLImpl[i]; - if (cnx->dso && disp[i].state == egl_display_t::INITIALIZED) { - if (cnx->egl.eglTerminate(disp[i].dpy) == EGL_FALSE) { - ALOGW("%d: eglTerminate(%p) failed (%s)", i, disp[i].dpy, - egl_tls_t::egl_strerror(cnx->egl.eglGetError())); - } - // REVISIT: it's unclear what to do if eglTerminate() fails - free(disp[i].config); - - disp[i].numConfigs = 0; - disp[i].config = 0; - disp[i].state = egl_display_t::TERMINATED; - - res = EGL_TRUE; + egl_connection_t* const cnx = &gEGLImpl; + if (cnx->dso && disp.state == egl_display_t::INITIALIZED) { + if (cnx->egl.eglTerminate(disp.dpy) == EGL_FALSE) { + ALOGW("eglTerminate(%p) failed (%s)", disp.dpy, + egl_tls_t::egl_strerror(cnx->egl.eglGetError())); } + // REVISIT: it's unclear what to do if eglTerminate() fails + disp.state = egl_display_t::TERMINATED; + res = EGL_TRUE; } // Mark all objects remaining in the list as terminated, unless @@ -337,8 +278,6 @@ EGLBoolean egl_display_t::terminate() { objects.clear(); refs--; - numTotalConfigs = 0; - delete[] configs; return res; } @@ -390,13 +329,13 @@ EGLBoolean egl_display_t::makeCurrent(egl_context_t* c, egl_context_t* cur_c, Mutex::Autolock _l(lock); if (c) { result = c->cnx->egl.eglMakeCurrent( - disp[c->impl].dpy, impl_draw, impl_read, impl_ctx); + disp.dpy, impl_draw, impl_read, impl_ctx); if (result == EGL_TRUE) { c->onMakeCurrent(draw, read); } } else { result = cur_c->cnx->egl.eglMakeCurrent( - disp[cur_c->impl].dpy, impl_draw, impl_read, impl_ctx); + disp.dpy, impl_draw, impl_read, impl_ctx); if (result == EGL_TRUE) { cur_c->onLooseCurrent(); } diff --git a/opengl/libs/EGL/egl_display.h b/opengl/libs/EGL/egl_display.h index f3c4ddf..6348228 100644 --- a/opengl/libs/EGL/egl_display.h +++ b/opengl/libs/EGL/egl_display.h @@ -44,23 +44,6 @@ class egl_connection_t; // ---------------------------------------------------------------------------- -struct egl_config_t { - egl_config_t() {} - egl_config_t(int impl, EGLConfig config) - : impl(impl), config(config), configId(0), implConfigId(0) { } - int impl; // the implementation this config is for - EGLConfig config; // the implementation's EGLConfig - EGLint configId; // our CONFIG_ID - EGLint implConfigId; // the implementation's CONFIG_ID - inline bool operator < (const egl_config_t& rhs) const { - if (impl < rhs.impl) return true; - if (impl > rhs.impl) return false; - return config < rhs.config; - } -}; - -// ---------------------------------------------------------------------------- - class EGLAPI egl_display_t { // marked as EGLAPI for testing purposes static egl_display_t sDisplay[NUM_DISPLAYS]; EGLDisplay getDisplay(EGLNativeDisplayType display); @@ -113,12 +96,9 @@ public: }; struct DisplayImpl { - DisplayImpl() : dpy(EGL_NO_DISPLAY), config(0), - state(NOT_INITIALIZED), numConfigs(0) { } + DisplayImpl() : dpy(EGL_NO_DISPLAY), state(NOT_INITIALIZED) { } EGLDisplay dpy; - EGLConfig* config; EGLint state; - EGLint numConfigs; strings_t queryString; }; @@ -126,9 +106,7 @@ private: uint32_t magic; public: - DisplayImpl disp[IMPL_NUM_IMPLEMENTATIONS]; - EGLint numTotalConfigs; - egl_config_t* configs; + DisplayImpl disp; private: uint32_t refs; diff --git a/opengl/libs/EGL/egl_object.cpp b/opengl/libs/EGL/egl_object.cpp index b660c53..d0cbb31 100644 --- a/opengl/libs/EGL/egl_object.cpp +++ b/opengl/libs/EGL/egl_object.cpp @@ -64,9 +64,9 @@ bool egl_object_t::get(egl_display_t const* display, egl_object_t* object) { // ---------------------------------------------------------------------------- egl_context_t::egl_context_t(EGLDisplay dpy, EGLContext context, EGLConfig config, - int impl, egl_connection_t const* cnx, int version) : + egl_connection_t const* cnx, int version) : egl_object_t(get_display(dpy)), dpy(dpy), context(context), - config(config), read(0), draw(0), impl(impl), cnx(cnx), + config(config), read(0), draw(0), cnx(cnx), version(version) { } @@ -87,7 +87,7 @@ void egl_context_t::onMakeCurrent(EGLSurface draw, EGLSurface read) { if (gl_extensions.isEmpty()) { // call the implementation's glGetString(GL_EXTENSIONS) - const char* exts = (const char *)gEGLImpl[impl].hooks[version]->gl.glGetString(GL_EXTENSIONS); + const char* exts = (const char *)gEGLImpl.hooks[version]->gl.glGetString(GL_EXTENSIONS); gl_extensions.setTo(exts); if (gl_extensions.find("GL_EXT_debug_marker") < 0) { String8 temp("GL_EXT_debug_marker "); diff --git a/opengl/libs/EGL/egl_object.h b/opengl/libs/EGL/egl_object.h index abd4cbb..f137bad 100644 --- a/opengl/libs/EGL/egl_object.h +++ b/opengl/libs/EGL/egl_object.h @@ -125,7 +125,7 @@ void egl_object_t::LocalRef<N,T>::terminate() { // ---------------------------------------------------------------------------- -class egl_surface_t: public egl_object_t { +class egl_surface_t : public egl_object_t { protected: ~egl_surface_t() { ANativeWindow* const window = win.get(); @@ -140,15 +140,14 @@ public: typedef egl_object_t::LocalRef<egl_surface_t, EGLSurface> Ref; egl_surface_t(EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win, - EGLSurface surface, int impl, egl_connection_t const* cnx) : + EGLSurface surface, egl_connection_t const* cnx) : egl_object_t(get_display(dpy)), dpy(dpy), surface(surface), - config(config), win(win), impl(impl), cnx(cnx) { + config(config), win(win), cnx(cnx) { } EGLDisplay dpy; EGLSurface surface; EGLConfig config; sp<ANativeWindow> win; - int impl; egl_connection_t const* cnx; }; @@ -159,7 +158,7 @@ public: typedef egl_object_t::LocalRef<egl_context_t, EGLContext> Ref; egl_context_t(EGLDisplay dpy, EGLContext context, EGLConfig config, - int impl, egl_connection_t const* cnx, int version); + egl_connection_t const* cnx, int version); void onLooseCurrent(); void onMakeCurrent(EGLSurface draw, EGLSurface read); @@ -169,7 +168,6 @@ public: EGLConfig config; EGLSurface read; EGLSurface draw; - int impl; egl_connection_t const* cnx; int version; String8 gl_extensions; @@ -182,12 +180,11 @@ public: typedef egl_object_t::LocalRef<egl_image_t, EGLImageKHR> Ref; egl_image_t(EGLDisplay dpy, EGLContext context) : - egl_object_t(get_display(dpy)), dpy(dpy), context(context) { - memset(images, 0, sizeof(images)); - } + egl_object_t(get_display(dpy)), + dpy(dpy), context(context), image(EGL_NO_IMAGE_KHR) { } EGLDisplay dpy; EGLContext context; - EGLImageKHR images[IMPL_NUM_IMPLEMENTATIONS]; + EGLImageKHR image; }; class egl_sync_t: public egl_object_t { diff --git a/opengl/libs/EGL/egldefs.h b/opengl/libs/EGL/egldefs.h index ff20957..c900c1c 100644 --- a/opengl/libs/EGL/egldefs.h +++ b/opengl/libs/EGL/egldefs.h @@ -19,31 +19,24 @@ #include "hooks.h" +#define VERSION_MAJOR 1 +#define VERSION_MINOR 4 + // ---------------------------------------------------------------------------- namespace android { // ---------------------------------------------------------------------------- -#define VERSION_MAJOR 1 -#define VERSION_MINOR 4 - // EGLDisplay are global, not attached to a given thread const unsigned int NUM_DISPLAYS = 1; -enum { - IMPL_HARDWARE = 0, - IMPL_SOFTWARE, - IMPL_NUM_IMPLEMENTATIONS -}; - -enum { - GLESv1_INDEX = 0, - GLESv2_INDEX = 1, -}; - // ---------------------------------------------------------------------------- -struct egl_connection_t -{ +struct egl_connection_t { + enum { + GLESv1_INDEX = 0, + GLESv2_INDEX = 1 + }; + inline egl_connection_t() : dso(0) { } void * dso; gl_hooks_t * hooks[2]; @@ -54,7 +47,7 @@ struct egl_connection_t // ---------------------------------------------------------------------------- -extern gl_hooks_t gHooks[2][IMPL_NUM_IMPLEMENTATIONS]; +extern gl_hooks_t gHooks[2]; extern gl_hooks_t gHooksNoContext; extern pthread_key_t gGLWrapperKey; extern "C" void gl_unimplemented(); @@ -63,7 +56,7 @@ extern "C" void gl_noop(); extern char const * const gl_names[]; extern char const * const egl_names[]; -extern egl_connection_t gEGLImpl[IMPL_NUM_IMPLEMENTATIONS]; +extern egl_connection_t gEGLImpl; // ---------------------------------------------------------------------------- }; // namespace android diff --git a/opengl/libs/GLES_trace/src/gltrace_fixup.cpp b/opengl/libs/GLES_trace/src/gltrace_fixup.cpp index 871b5dc..3e185bc 100644 --- a/opengl/libs/GLES_trace/src/gltrace_fixup.cpp +++ b/opengl/libs/GLES_trace/src/gltrace_fixup.cpp @@ -15,9 +15,13 @@ */ #include <cutils/log.h> +#include <GLES/gl.h> +#include <GLES/glext.h> #include <GLES2/gl2.h> +#include <GLES2/gl2ext.h> #include "gltrace.pb.h" +#include "gltrace_api.h" #include "gltrace_context.h" #include "gltrace_fixup.h" @@ -198,6 +202,20 @@ void fixup_glShaderSource(GLMessage *glmsg) { arg_strpp->add_charvalue(src); } +void fixup_glUniformGenericInteger(int argIndex, int nIntegers, GLMessage *glmsg) { + /* void glUniform?iv(GLint location, GLsizei count, const GLint *value); */ + GLMessage_DataType *arg_values = glmsg->mutable_args(argIndex); + GLint *src = (GLint*)arg_values->intvalue(0); + + arg_values->set_type(GLMessage::DataType::INT); + arg_values->set_isarray(true); + arg_values->clear_intvalue(); + + for (int i = 0; i < nIntegers; i++) { + arg_values->add_intvalue(*src++); + } +} + void fixup_glUniformGeneric(int argIndex, int nFloats, GLMessage *glmsg) { GLMessage_DataType *arg_values = glmsg->mutable_args(argIndex); GLfloat *src = (GLfloat*)arg_values->intvalue(0); @@ -223,6 +241,10 @@ void fixup_GenericIntArray(int argIndex, int nInts, GLMessage *glmsg) { GLMessage_DataType *arg_intarray = glmsg->mutable_args(argIndex); GLint *intp = (GLint *)arg_intarray->intvalue(0); + if (intp == NULL) { + return; + } + arg_intarray->set_type(GLMessage::DataType::INT); arg_intarray->set_isarray(true); arg_intarray->clear_intvalue(); @@ -232,6 +254,15 @@ void fixup_GenericIntArray(int argIndex, int nInts, GLMessage *glmsg) { } } +void fixup_GenericEnumArray(int argIndex, int nEnums, GLMessage *glmsg) { + // fixup as if they were ints + fixup_GenericIntArray(argIndex, nEnums, glmsg); + + // and then set the data type to be enum + GLMessage_DataType *arg_enumarray = glmsg->mutable_args(argIndex); + arg_enumarray->set_type(GLMessage::DataType::ENUM); +} + void fixup_glGenGeneric(GLMessage *glmsg) { /* void glGen*(GLsizei n, GLuint * buffers); */ GLMessage_DataType arg_n = glmsg->args(0); @@ -270,6 +301,84 @@ void fixup_glGetFloatv(GLMessage *glmsg) { arg_params->add_floatvalue(*src); } +void fixup_glLinkProgram(GLMessage *glmsg) { + /* void glLinkProgram(GLuint program); */ + GLuint program = glmsg->args(0).intvalue(0); + + /* We don't have to fixup this call, but as soon as a program is linked, + we obtain information about all active attributes and uniforms to + pass on to the debugger. Note that in order to pass this info to + the debugger, all we need to do is call the trace versions of the + necessary calls. */ + + GLint n, maxNameLength; + GLchar *name; + GLint size; + GLenum type; + + // obtain info regarding active attributes + GLTrace_glGetProgramiv(program, GL_ACTIVE_ATTRIBUTES, &n); + GLTrace_glGetProgramiv(program, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &maxNameLength); + + name = (GLchar *) malloc(maxNameLength); + for (int i = 0; i < n; i++) { + GLTrace_glGetActiveAttrib(program, i, maxNameLength, NULL, &size, &type, name); + } + free(name); + + // obtain info regarding active uniforms + GLTrace_glGetProgramiv(program, GL_ACTIVE_UNIFORMS, &n); + GLTrace_glGetProgramiv(program, GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxNameLength); + + name = (GLchar *) malloc(maxNameLength); + for (int i = 0; i < n; i++) { + GLTrace_glGetActiveUniform(program, i, maxNameLength, NULL, &size, &type, name); + } + free(name); +} + +/** Given a glGetActive[Uniform|Attrib] call, obtain the location + * of the variable in the call. + */ +int getShaderVariableLocation(GLTraceContext *context, GLMessage *glmsg) { + GLMessage_Function func = glmsg->function(); + if (func != GLMessage::glGetActiveAttrib && func != GLMessage::glGetActiveUniform) { + return -1; + } + + int program = glmsg->args(0).intvalue(0); + GLchar *name = (GLchar*) glmsg->args(6).intvalue(0); + + if (func == GLMessage::glGetActiveAttrib) { + return context->hooks->gl.glGetAttribLocation(program, name); + } else { + return context->hooks->gl.glGetUniformLocation(program, name); + } +} + +void fixup_glGetActiveAttribOrUniform(GLMessage *glmsg, int location) { + /* void glGetActiveAttrib(GLuint program, GLuint index, GLsizei bufsize, + GLsizei* length, GLint* size, GLenum* type, GLchar* name); */ + /* void glGetActiveUniform(GLuint program, GLuint index, GLsizei bufsize, + GLsizei* length, GLint* size, GLenum* type, GLchar* name) */ + + fixup_GenericIntArray(3, 1, glmsg); // length + fixup_GenericIntArray(4, 1, glmsg); // size + fixup_GenericEnumArray(5, 1, glmsg); // type + fixup_CStringPtr(6, glmsg); // name + + // The index argument in the glGetActive[Attrib|Uniform] functions + // does not correspond to the actual location index as used in + // glUniform*() or glVertexAttrib*() to actually upload the data. + // In order to make things simpler for the debugger, we also pass + // a hidden location argument that stores the actual location. + // append the location value to the end of the argument list + GLMessage_DataType *arg_location = glmsg->add_args(); + arg_location->set_isarray(false); + arg_location->set_type(GLMessage::DataType::INT); + arg_location->add_intvalue(location); +} + void fixupGLMessage(GLTraceContext *context, nsecs_t start, nsecs_t end, GLMessage *glmsg) { // for all messages, set the current context id glmsg->set_context_id(context->getId()); @@ -292,6 +401,19 @@ void fixupGLMessage(GLTraceContext *context, nsecs_t start, nsecs_t end, GLMessa case GLMessage::glGenTextures: /* void glGenTextures(GLsizei n, GLuint *textures); */ fixup_glGenGeneric(glmsg); break; + case GLMessage::glLinkProgram: /* void glLinkProgram(GLuint program); */ + fixup_glLinkProgram(glmsg); + break; + case GLMessage::glGetActiveAttrib: + fixup_glGetActiveAttribOrUniform(glmsg, getShaderVariableLocation(context, glmsg)); + break; + case GLMessage::glGetActiveUniform: + fixup_glGetActiveAttribOrUniform(glmsg, getShaderVariableLocation(context, glmsg)); + break; + case GLMessage::glBindAttribLocation: + /* void glBindAttribLocation(GLuint program, GLuint index, const GLchar* name); */ + fixup_CStringPtr(2, glmsg); + break; case GLMessage::glGetAttribLocation: case GLMessage::glGetUniformLocation: /* int glGetAttribLocation(GLuint program, const GLchar* name) */ @@ -331,6 +453,38 @@ void fixupGLMessage(GLTraceContext *context, nsecs_t start, nsecs_t end, GLMessa case GLMessage::glShaderSource: fixup_glShaderSource(glmsg); break; + case GLMessage::glUniform1iv: + /* void glUniform1iv(GLint location, GLsizei count, const GLint *value); */ + fixup_glUniformGenericInteger(2, 1, glmsg); + break; + case GLMessage::glUniform2iv: + /* void glUniform2iv(GLint location, GLsizei count, const GLint *value); */ + fixup_glUniformGenericInteger(2, 2, glmsg); + break; + case GLMessage::glUniform3iv: + /* void glUniform3iv(GLint location, GLsizei count, const GLint *value); */ + fixup_glUniformGenericInteger(2, 3, glmsg); + break; + case GLMessage::glUniform4iv: + /* void glUniform4iv(GLint location, GLsizei count, const GLint *value); */ + fixup_glUniformGenericInteger(2, 4, glmsg); + break; + case GLMessage::glUniform1fv: + /* void glUniform1fv(GLint location, GLsizei count, const GLfloat *value); */ + fixup_glUniformGeneric(2, 1, glmsg); + break; + case GLMessage::glUniform2fv: + /* void glUniform2fv(GLint location, GLsizei count, const GLfloat *value); */ + fixup_glUniformGeneric(2, 2, glmsg); + break; + case GLMessage::glUniform3fv: + /* void glUniform3fv(GLint location, GLsizei count, const GLfloat *value); */ + fixup_glUniformGeneric(2, 3, glmsg); + break; + case GLMessage::glUniform4fv: + /* void glUniform4fv(GLint location, GLsizei count, const GLfloat *value); */ + fixup_glUniformGeneric(2, 4, glmsg); + break; case GLMessage::glUniformMatrix2fv: /* void glUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) */ |