From cffb2b316cc080c365b484c512e5124779e5f0f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Sat, 26 Aug 2017 15:36:35 +0300 Subject: [PATCH 1/3] Rewrite EGL API as a C library to make it multithreading capable out of the box without needing to proxy. --- src/library_egl.js | 606 ----------------------------------- src/modules.js | 1 - system/lib/egl.symbols | 34 ++ system/lib/egl/library_egl.c | 570 ++++++++++++++++++++++++++++++++ tools/shared.py | 7 +- tools/system_libs.py | 6 + 6 files changed, 612 insertions(+), 612 deletions(-) delete mode 100644 src/library_egl.js create mode 100644 system/lib/egl.symbols create mode 100644 system/lib/egl/library_egl.c diff --git a/src/library_egl.js b/src/library_egl.js deleted file mode 100644 index 48262e3374155..0000000000000 --- a/src/library_egl.js +++ /dev/null @@ -1,606 +0,0 @@ -/* - The EGL implementation supports only one EGLNativeDisplayType, the EGL_DEFAULT_DISPLAY. - This native display type returns the only supported EGLDisplay handle with the magic value 62000. - There is only a single EGLConfig configuration supported, that has the magic value 62002. - The implementation only allows a single EGLContext to be created, that has the magic value of 62004. (multiple creations silently return this same context) - The implementation only creates a single EGLSurface, a handle with the magic value of 62006. (multiple creations silently return the same surface) -*/ - -var LibraryEGL = { - $EGL__deps: ['$Browser'], - $EGL: { - // This variable tracks the success status of the most recently invoked EGL function call. - errorCode: 0x3000 /* EGL_SUCCESS */, - defaultDisplayInitialized: false, - currentContext: 0 /* EGL_NO_CONTEXT */, - currentReadSurface: 0 /* EGL_NO_SURFACE */, - currentDrawSurface: 0 /* EGL_NO_SURFACE */, - - stringCache: {}, - - setErrorCode: function(code) { - EGL.errorCode = code; - }, - - chooseConfig: function(display, attribList, config, config_size, numConfigs) { - if (display != 62000 /* Magic ID for Emscripten 'default display' */) { - EGL.setErrorCode(0x3008 /* EGL_BAD_DISPLAY */); - return 0; - } - // TODO: read attribList. - if ((!config || !config_size) && !numConfigs) { - EGL.setErrorCode(0x300C /* EGL_BAD_PARAMETER */); - return 0; - } - if (numConfigs) { - {{{ makeSetValue('numConfigs', '0', '1', 'i32') }}}; // Total number of supported configs: 1. - } - if (config && config_size > 0) { - {{{ makeSetValue('config', '0', '62002' /* Magic ID for the only EGLConfig supported by Emscripten */, 'i32') }}}; - } - - EGL.setErrorCode(0x3000 /* EGL_SUCCESS */); - return 1; - }, - }, - - // EGLAPI EGLDisplay EGLAPIENTRY eglGetDisplay(EGLNativeDisplayType display_id); - eglGetDisplay: function(nativeDisplayType) { - EGL.setErrorCode(0x3000 /* EGL_SUCCESS */); - // Note: As a 'conformant' implementation of EGL, we would prefer to init here only if the user - // calls this function with EGL_DEFAULT_DISPLAY. Other display IDs would be preferred to be unsupported - // and EGL_NO_DISPLAY returned. Uncomment the following code lines to do this. - // Instead, an alternative route has been preferred, namely that the Emscripten EGL implementation - // "emulates" X11, and eglGetDisplay is expected to accept/receive a pointer to an X11 Display object. - // Therefore, be lax and allow anything to be passed in, and return the magic handle to our default EGLDisplay object. - -// if (nativeDisplayType == 0 /* EGL_DEFAULT_DISPLAY */) { - return 62000; // Magic ID for Emscripten 'default display' -// } -// else -// return 0; // EGL_NO_DISPLAY - }, - - // EGLAPI EGLBoolean EGLAPIENTRY eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor); - eglInitialize: function(display, majorVersion, minorVersion) { - if (display == 62000 /* Magic ID for Emscripten 'default display' */) { - if (majorVersion) { - {{{ makeSetValue('majorVersion', '0', '1', 'i32') }}}; // Advertise EGL Major version: '1' - } - if (minorVersion) { - {{{ makeSetValue('minorVersion', '0', '4', 'i32') }}}; // Advertise EGL Minor version: '4' - } - EGL.defaultDisplayInitialized = true; - EGL.setErrorCode(0x3000 /* EGL_SUCCESS */); - return 1; - } - else { - EGL.setErrorCode(0x3008 /* EGL_BAD_DISPLAY */); - return 0; - } - }, - - // EGLAPI EGLBoolean EGLAPIENTRY eglTerminate(EGLDisplay dpy); - eglTerminate: function(display) { - if (display != 62000 /* Magic ID for Emscripten 'default display' */) { - EGL.setErrorCode(0x3008 /* EGL_BAD_DISPLAY */); - return 0; - } - EGL.currentContext = 0; - EGL.currentReadSurface = 0; - EGL.currentDrawSurface = 0; - EGL.defaultDisplayInitialized = false; - EGL.setErrorCode(0x3000 /* EGL_SUCCESS */); - return 1; - }, - - // EGLAPI EGLBoolean EGLAPIENTRY eglGetConfigs(EGLDisplay dpy, EGLConfig *configs, EGLint config_size, EGLint *num_config); - eglGetConfigs: function(display, configs, config_size, numConfigs) { - return EGL.chooseConfig(display, 0, configs, config_size, numConfigs); - }, - - // EGLAPI EGLBoolean EGLAPIENTRY eglChooseConfig(EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *configs, EGLint config_size, EGLint *num_config); - eglChooseConfig: function(display, attrib_list, configs, config_size, numConfigs) { - return EGL.chooseConfig(display, attrib_list, configs, config_size, numConfigs); - }, - - // EGLAPI EGLBoolean EGLAPIENTRY eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint *value); - eglGetConfigAttrib: function(display, config, attribute, value) { - if (display != 62000 /* Magic ID for Emscripten 'default display' */) { - EGL.setErrorCode(0x3008 /* EGL_BAD_DISPLAY */); - return 0; - } - if (config != 62002 /* Magic ID for the only EGLConfig supported by Emscripten */) { - EGL.setErrorCode(0x3005 /* EGL_BAD_CONFIG */); - return 0; - } - if (!value) { - EGL.setErrorCode(0x300C /* EGL_BAD_PARAMETER */); - return 0; - } - EGL.setErrorCode(0x3000 /* EGL_SUCCESS */); - switch(attribute) { - case 0x3020: // EGL_BUFFER_SIZE - {{{ makeSetValue('value', '0', '32' /* 8 bits for each A,R,G,B. */, 'i32') }}}; - return 1; - case 0x3021: // EGL_ALPHA_SIZE - {{{ makeSetValue('value', '0', '8' /* 8 bits for alpha channel. */, 'i32') }}}; - return 1; - case 0x3022: // EGL_BLUE_SIZE - {{{ makeSetValue('value', '0', '8' /* 8 bits for blue channel. */, 'i32') }}}; - return 1; - case 0x3023: // EGL_GREEN_SIZE - {{{ makeSetValue('value', '0', '8' /* 8 bits for green channel. */, 'i32') }}}; - return 1; - case 0x3024: // EGL_RED_SIZE - {{{ makeSetValue('value', '0', '8' /* 8 bits for red channel. */, 'i32') }}}; - return 1; - case 0x3025: // EGL_DEPTH_SIZE - {{{ makeSetValue('value', '0', '24' /* 24 bits for depth buffer. TODO: This is hardcoded, add support for this! */, 'i32') }}}; - return 1; - case 0x3026: // EGL_STENCIL_SIZE - {{{ makeSetValue('value', '0', '8' /* 8 bits for stencil buffer. TODO: This is hardcoded, add support for this! */, 'i32') }}}; - return 1; - case 0x3027: // EGL_CONFIG_CAVEAT - // We can return here one of EGL_NONE (0x3038), EGL_SLOW_CONFIG (0x3050) or EGL_NON_CONFORMANT_CONFIG (0x3051). - {{{ makeSetValue('value', '0', '0x3038' /* EGL_NONE */, 'i32') }}}; - return 1; - case 0x3028: // EGL_CONFIG_ID - {{{ makeSetValue('value', '0', '62002' /* Magic ID for the only EGLConfig supported by Emscripten */, 'i32') }}}; - return 1; - case 0x3029: // EGL_LEVEL - {{{ makeSetValue('value', '0', '0' /* Z order/depth layer for this level. Not applicable for Emscripten. */, 'i32') }}}; - return 1; - case 0x302A: // EGL_MAX_PBUFFER_HEIGHT - {{{ makeSetValue('value', '0', '4096', 'i32') }}}; - return 1; - case 0x302B: // EGL_MAX_PBUFFER_PIXELS - {{{ makeSetValue('value', '0', '16777216' /* 4096 * 4096 */, 'i32') }}}; - return 1; - case 0x302C: // EGL_MAX_PBUFFER_WIDTH - {{{ makeSetValue('value', '0', '4096', 'i32') }}}; - return 1; - case 0x302D: // EGL_NATIVE_RENDERABLE - {{{ makeSetValue('value', '0', '0' /* This config does not allow co-rendering with other 'native' rendering APIs. */, 'i32') }}}; - return 1; - case 0x302E: // EGL_NATIVE_VISUAL_ID - {{{ makeSetValue('value', '0', '0' /* N/A for Emscripten. */, 'i32') }}}; - return 1; - case 0x302F: // EGL_NATIVE_VISUAL_TYPE - {{{ makeSetValue('value', '0', '0x3038' /* EGL_NONE */, 'i32') }}}; - return 1; - case 0x3031: // EGL_SAMPLES - {{{ makeSetValue('value', '0', '4' /* 2x2 Multisampling */, 'i32') }}}; - return 1; - case 0x3032: // EGL_SAMPLE_BUFFERS - {{{ makeSetValue('value', '0', '1' /* Multisampling enabled */, 'i32') }}}; - return 1; - case 0x3033: // EGL_SURFACE_TYPE - {{{ makeSetValue('value', '0', '0x0004' /* EGL_WINDOW_BIT */, 'i32') }}}; - return 1; - case 0x3034: // EGL_TRANSPARENT_TYPE - // If this returns EGL_TRANSPARENT_RGB (0x3052), transparency is used through color-keying. No such thing applies to Emscripten canvas. - {{{ makeSetValue('value', '0', '0x3038' /* EGL_NONE */, 'i32') }}}; - return 1; - case 0x3035: // EGL_TRANSPARENT_BLUE_VALUE - case 0x3036: // EGL_TRANSPARENT_GREEN_VALUE - case 0x3037: // EGL_TRANSPARENT_RED_VALUE - // "If EGL_TRANSPARENT_TYPE is EGL_NONE, then the values for EGL_TRANSPARENT_RED_VALUE, EGL_TRANSPARENT_GREEN_VALUE, and EGL_TRANSPARENT_BLUE_VALUE are undefined." - {{{ makeSetValue('value', '0', '-1' /* Report a "does not apply" value. */, 'i32') }}}; - return 1; - case 0x3039: // EGL_BIND_TO_TEXTURE_RGB - case 0x303A: // EGL_BIND_TO_TEXTURE_RGBA - {{{ makeSetValue('value', '0', '0' /* Only pbuffers would be bindable, but these are not supported. */, 'i32') }}}; - return 1; - case 0x303B: // EGL_MIN_SWAP_INTERVAL - case 0x303C: // EGL_MAX_SWAP_INTERVAL - {{{ makeSetValue('value', '0', '1' /* TODO: Currently this is not strictly true, since user can specify custom presentation interval in JS requestAnimationFrame/emscripten_set_main_loop. */, 'i32') }}}; - return 1; - case 0x303D: // EGL_LUMINANCE_SIZE - case 0x303E: // EGL_ALPHA_MASK_SIZE - {{{ makeSetValue('value', '0', '0' /* N/A in this config. */, 'i32') }}}; - return 1; - case 0x303F: // EGL_COLOR_BUFFER_TYPE - // EGL has two types of buffers: EGL_RGB_BUFFER and EGL_LUMINANCE_BUFFER. - {{{ makeSetValue('value', '0', '0x308E' /* EGL_RGB_BUFFER */, 'i32') }}}; - return 1; - case 0x3040: // EGL_RENDERABLE_TYPE - // A bit combination of EGL_OPENGL_ES_BIT,EGL_OPENVG_BIT,EGL_OPENGL_ES2_BIT and EGL_OPENGL_BIT. - {{{ makeSetValue('value', '0', '0x0004' /* EGL_OPENGL_ES2_BIT */, 'i32') }}}; - return 1; - case 0x3042: // EGL_CONFORMANT - // "EGL_CONFORMANT is a mask indicating if a client API context created with respect to the corresponding EGLConfig will pass the required conformance tests for that API." - {{{ makeSetValue('value', '0', '0' /* EGL_OPENGL_ES2_BIT */, 'i32') }}}; - return 1; - default: - EGL.setErrorCode(0x3004 /* EGL_BAD_ATTRIBUTE */); - return 0; - } - }, - - // EGLAPI EGLSurface EGLAPIENTRY eglCreateWindowSurface(EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win, const EGLint *attrib_list); - eglCreateWindowSurface: function(display, config, win, attrib_list) { - if (display != 62000 /* Magic ID for Emscripten 'default display' */) { - EGL.setErrorCode(0x3008 /* EGL_BAD_DISPLAY */); - return 0; - } - if (config != 62002 /* Magic ID for the only EGLConfig supported by Emscripten */) { - EGL.setErrorCode(0x3005 /* EGL_BAD_CONFIG */); - return 0; - } - // TODO: Examine attrib_list! Parameters that can be present there are: - // - EGL_RENDER_BUFFER (must be EGL_BACK_BUFFER) - // - EGL_VG_COLORSPACE (can't be set) - // - EGL_VG_ALPHA_FORMAT (can't be set) - EGL.setErrorCode(0x3000 /* EGL_SUCCESS */); - return 62006; /* Magic ID for Emscripten 'default surface' */ - }, - - // EGLAPI EGLBoolean EGLAPIENTRY eglDestroySurface(EGLDisplay display, EGLSurface surface); - eglDestroySurface: function(display, surface) { - if (display != 62000 /* Magic ID for Emscripten 'default display' */) { - EGL.setErrorCode(0x3008 /* EGL_BAD_DISPLAY */); - return 0; - } - if (surface != 62006 /* Magic ID for the only EGLSurface supported by Emscripten */) { - EGL.setErrorCode(0x300D /* EGL_BAD_SURFACE */); - return 1; - } - if (EGL.currentReadSurface == surface) { - EGL.currentReadSurface = 0; - } - if (EGL.currentDrawSurface == surface) { - EGL.currentDrawSurface = 0; - } - EGL.setErrorCode(0x3000 /* EGL_SUCCESS */); - return 1; /* Magic ID for Emscripten 'default surface' */ - }, - - eglCreateContext__deps: ['glutInitDisplayMode', 'glutCreateWindow', '$GL'], - - // EGLAPI EGLContext EGLAPIENTRY eglCreateContext(EGLDisplay dpy, EGLConfig config, EGLContext share_context, const EGLint *attrib_list); - eglCreateContext: function(display, config, hmm, contextAttribs) { - if (display != 62000 /* Magic ID for Emscripten 'default display' */) { - EGL.setErrorCode(0x3008 /* EGL_BAD_DISPLAY */); - return 0; - } - - // EGL 1.4 spec says default EGL_CONTEXT_CLIENT_VERSION is GLES1, but this is not supported by Emscripten. - // So user must pass EGL_CONTEXT_CLIENT_VERSION == 2 to initialize EGL. - var glesContextVersion = 1; - for(;;) { - var param = {{{ makeGetValue('contextAttribs', '0', 'i32') }}}; - if (param == 0x3098 /*EGL_CONTEXT_CLIENT_VERSION*/) { - glesContextVersion = {{{ makeGetValue('contextAttribs', '4', 'i32') }}}; - } else if (param == 0x3038 /*EGL_NONE*/) { - break; - } else { - /* EGL1.4 specifies only EGL_CONTEXT_CLIENT_VERSION as supported attribute */ - EGL.setErrorCode(0x3004 /*EGL_BAD_ATTRIBUTE*/); - return 0; - } - contextAttribs += 8; - } - if (glesContextVersion != 2) { -#if GL_ASSERTIONS - Module.printErr('When initializing GLES2/WebGL1 via EGL, one must pass EGL_CONTEXT_CLIENT_VERSION = 2 to GL context attributes! GLES version ' + glesContextVersion + ' is not supported!'); -#endif - EGL.setErrorCode(0x3005 /* EGL_BAD_CONFIG */); - return 0; /* EGL_NO_CONTEXT */ - } - - _glutInitDisplayMode(0xB2 /* GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH | GLUT_MULTISAMPLE | GLUT_STENCIL */); - EGL.windowID = _glutCreateWindow(); - if (EGL.windowID != 0) { - EGL.setErrorCode(0x3000 /* EGL_SUCCESS */); - // Note: This function only creates a context, but it shall not make it active. - return 62004; // Magic ID for Emscripten EGLContext - } else { - EGL.setErrorCode(0x3009 /* EGL_BAD_MATCH */); // By the EGL 1.4 spec, an implementation that does not support GLES2 (WebGL in this case), this error code is set. - return 0; /* EGL_NO_CONTEXT */ - } - }, - - eglDestroyContext__deps: ['glutDestroyWindow', '$GL'], - - // EGLAPI EGLBoolean EGLAPIENTRY eglDestroyContext(EGLDisplay dpy, EGLContext context); - eglDestroyContext: function(display, context) { - if (display != 62000 /* Magic ID for Emscripten 'default display' */) { - EGL.setErrorCode(0x3008 /* EGL_BAD_DISPLAY */); - return 0; - } - if (context != 62004 /* Magic ID for Emscripten EGLContext */) { - EGL.setErrorCode(0x3006 /* EGL_BAD_CONTEXT */); - return 0; - } - - _glutDestroyWindow(EGL.windowID); - EGL.setErrorCode(0x3000 /* EGL_SUCCESS */); - if (EGL.currentContext == context) { - EGL.currentContext = 0; - } - return 1 /* EGL_TRUE */; - }, - - // EGLAPI EGLBoolean EGLAPIENTRY eglDestroyContext(EGLDisplay dpy, EGLContext ctx); - eglDestroyContext: function(display, context) { - if (display != 62000 /* Magic ID for Emscripten 'default display' */) { - EGL.setErrorCode(0x3008 /* EGL_BAD_DISPLAY */); - return 0; - } - - if (context != 62004 /* Magic ID for Emscripten EGLContext */) { - EGL.setErrorCode(0x3006 /* EGL_BAD_CONTEXT */); - return 0; - } - - EGL.setErrorCode(0x3000 /* EGL_SUCCESS */); - return 1; - }, - - // EGLAPI EGLBoolean EGLAPIENTRY eglQuerySurface(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint *value); - eglQuerySurface: function(display, surface, attribute, value) { - if (display != 62000 /* Magic ID for Emscripten 'default display' */) { - EGL.setErrorCode(0x3008 /* EGL_BAD_DISPLAY */); - return 0; - } - if (surface != 62006 /* Magic ID for Emscripten 'default surface' */) { - EGL.setErrorCode(0x300D /* EGL_BAD_SURFACE */); - return 0; - } - if (!value) { - EGL.setErrorCode(0x300C /* EGL_BAD_PARAMETER */); - return 0; - } - EGL.setErrorCode(0x3000 /* EGL_SUCCESS */); - switch(attribute) { - case 0x3028: // EGL_CONFIG_ID - {{{ makeSetValue('value', '0', '62002' /* A magic value for the only EGLConfig configuration ID supported by Emscripten. */, 'i32') }}}; - return 1; - case 0x3058: // EGL_LARGEST_PBUFFER - // Odd EGL API: If surface is not a pbuffer surface, 'value' should not be written to. It's not specified as an error, so true should(?) be returned. - // Existing Android implementation seems to do so at least. - return 1; - case 0x3057: // EGL_WIDTH - {{{ makeSetValue('value', '0', 'Module.canvas.width', 'i32') }}}; - return 1; - case 0x3056: // EGL_HEIGHT - {{{ makeSetValue('value', '0', 'Module.canvas.height', 'i32') }}}; - return 1; - case 0x3090: // EGL_HORIZONTAL_RESOLUTION - {{{ makeSetValue('value', '0', '-1' /* EGL_UNKNOWN */, 'i32') }}}; - return 1; - case 0x3091: // EGL_VERTICAL_RESOLUTION - {{{ makeSetValue('value', '0', '-1' /* EGL_UNKNOWN */, 'i32') }}}; - return 1; - case 0x3092: // EGL_PIXEL_ASPECT_RATIO - {{{ makeSetValue('value', '0', '-1' /* EGL_UNKNOWN */, 'i32') }}}; - return 1; - case 0x3086: // EGL_RENDER_BUFFER - // The main surface is bound to the visible canvas window - it's always backbuffered. - // Alternative to EGL_BACK_BUFFER would be EGL_SINGLE_BUFFER. - {{{ makeSetValue('value', '0', '0x3084' /* EGL_BACK_BUFFER */, 'i32') }}}; - return 1; - case 0x3099: // EGL_MULTISAMPLE_RESOLVE - {{{ makeSetValue('value', '0', '0x309A' /* EGL_MULTISAMPLE_RESOLVE_DEFAULT */, 'i32') }}}; - return 1; - case 0x3093: // EGL_SWAP_BEHAVIOR - // The two possibilities are EGL_BUFFER_PRESERVED and EGL_BUFFER_DESTROYED. Slightly unsure which is the - // case for browser environment, but advertise the 'weaker' behavior to be sure. - {{{ makeSetValue('value', '0', '0x3095' /* EGL_BUFFER_DESTROYED */, 'i32') }}}; - return 1; - case 0x3080: // EGL_TEXTURE_FORMAT - case 0x3081: // EGL_TEXTURE_TARGET - case 0x3082: // EGL_MIPMAP_TEXTURE - case 0x3083: // EGL_MIPMAP_LEVEL - // This is a window surface, not a pbuffer surface. Spec: - // "Querying EGL_TEXTURE_FORMAT, EGL_TEXTURE_TARGET, EGL_MIPMAP_TEXTURE, or EGL_MIPMAP_LEVEL for a non-pbuffer surface is not an error, but value is not modified." - // So pass-through. - return 1; - default: - EGL.setErrorCode(0x3004 /* EGL_BAD_ATTRIBUTE */); - return 0; - } - }, - - // EGLAPI EGLBoolean EGLAPIENTRY eglQueryContext(EGLDisplay dpy, EGLContext ctx, EGLint attribute, EGLint *value); - eglQueryContext: function(display, context, attribute, value) { - if (display != 62000 /* Magic ID for Emscripten 'default display' */) { - EGL.setErrorCode(0x3008 /* EGL_BAD_DISPLAY */); - return 0; - } - //\todo An EGL_NOT_INITIALIZED error is generated if EGL is not initialized for dpy. - if (context != 62004 /* Magic ID for Emscripten EGLContext */) { - EGL.setErrorCode(0x3006 /* EGL_BAD_CONTEXT */); - return 0; - } - if (!value) { - EGL.setErrorCode(0x300C /* EGL_BAD_PARAMETER */); - return 0; - } - - EGL.setErrorCode(0x3000 /* EGL_SUCCESS */); - switch(attribute) { - case 0x3028: // EGL_CONFIG_ID - {{{ makeSetValue('value', '0', '62002' /* A magic value for the only EGLConfig configuration ID supported by Emscripten. */, 'i32') }}}; - return 1; - case 0x3097: // EGL_CONTEXT_CLIENT_TYPE - {{{ makeSetValue('value', '0', '0x30A0' /* EGL_OPENGL_ES_API */, 'i32') }}}; - return 1; - case 0x3098: // EGL_CONTEXT_CLIENT_VERSION - {{{ makeSetValue('value', '0', '2' /* GLES2 context */, 'i32') }}}; // We always report the context to be a GLES2 context (and not a GLES1 context) - return 1; - case 0x3086: // EGL_RENDER_BUFFER - // The context is bound to the visible canvas window - it's always backbuffered. - // Alternative to EGL_BACK_BUFFER would be EGL_SINGLE_BUFFER. - {{{ makeSetValue('value', '0', '0x3084' /* EGL_BACK_BUFFER */, 'i32') }}}; - return 1; - default: - EGL.setErrorCode(0x3004 /* EGL_BAD_ATTRIBUTE */); - return 0; - } - }, - - // EGLAPI EGLint EGLAPIENTRY eglGetError(void); - eglGetError: function() { - return EGL.errorCode; - }, - - // EGLAPI const char * EGLAPIENTRY eglQueryString(EGLDisplay dpy, EGLint name); - eglQueryString: function(display, name) { - if (display != 62000 /* Magic ID for Emscripten 'default display' */) { - EGL.setErrorCode(0x3008 /* EGL_BAD_DISPLAY */); - return 0; - } - //\todo An EGL_NOT_INITIALIZED error is generated if EGL is not initialized for dpy. - EGL.setErrorCode(0x3000 /* EGL_SUCCESS */); - if (EGL.stringCache[name]) return EGL.stringCache[name]; - var ret; - switch(name) { - case 0x3053 /* EGL_VENDOR */: ret = allocate(intArrayFromString("Emscripten"), 'i8', ALLOC_NORMAL); break; - case 0x3054 /* EGL_VERSION */: ret = allocate(intArrayFromString("1.4 Emscripten EGL"), 'i8', ALLOC_NORMAL); break; - case 0x3055 /* EGL_EXTENSIONS */: ret = allocate(intArrayFromString(""), 'i8', ALLOC_NORMAL); break; // Currently not supporting any EGL extensions. - case 0x308D /* EGL_CLIENT_APIS */: ret = allocate(intArrayFromString("OpenGL_ES"), 'i8', ALLOC_NORMAL); break; - default: - EGL.setErrorCode(0x300C /* EGL_BAD_PARAMETER */); - return 0; - } - EGL.stringCache[name] = ret; - return ret; - }, - - // EGLAPI EGLBoolean EGLAPIENTRY eglBindAPI(EGLenum api); - eglBindAPI: function(api) { - if (api == 0x30A0 /* EGL_OPENGL_ES_API */) { - EGL.setErrorCode(0x3000 /* EGL_SUCCESS */); - return 1; - } else { // if (api == 0x30A1 /* EGL_OPENVG_API */ || api == 0x30A2 /* EGL_OPENGL_API */) { - EGL.setErrorCode(0x300C /* EGL_BAD_PARAMETER */); - return 0; - } - }, - - // EGLAPI EGLenum EGLAPIENTRY eglQueryAPI(void); - eglQueryAPI: function() { - EGL.setErrorCode(0x3000 /* EGL_SUCCESS */); - return 0x30A0; // EGL_OPENGL_ES_API - }, - - // EGLAPI EGLBoolean EGLAPIENTRY eglWaitClient(void); - eglWaitClient: function() { - EGL.setErrorCode(0x3000 /* EGL_SUCCESS */); - return 1; - }, - - // EGLAPI EGLBoolean EGLAPIENTRY eglWaitNative(EGLint engine); - eglWaitNative: function(nativeEngineId) { - EGL.setErrorCode(0x3000 /* EGL_SUCCESS */); - return 1; - }, - - - // EGLAPI EGLBoolean EGLAPIENTRY eglWaitGL(void); - eglWaitGL: 'eglWaitClient', - - // EGLAPI EGLBoolean EGLAPIENTRY eglSwapInterval(EGLDisplay dpy, EGLint interval); - eglSwapInterval__deps: ['emscripten_set_main_loop_timing'], - eglSwapInterval: function(display, interval) { - if (display != 62000 /* Magic ID for Emscripten 'default display' */) { - EGL.setErrorCode(0x3008 /* EGL_BAD_DISPLAY */); - return 0; - } - if (interval == 0) _emscripten_set_main_loop_timing(0/*EM_TIMING_SETTIMEOUT*/, 0); - else _emscripten_set_main_loop_timing(1/*EM_TIMING_RAF*/, interval); - - EGL.setErrorCode(0x3000 /* EGL_SUCCESS */); - return 1; - }, - - // EGLAPI EGLBoolean EGLAPIENTRY eglMakeCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx); - eglMakeCurrent: function(display, draw, read, context) { - if (display != 62000 /* Magic ID for Emscripten 'default display' */) { - EGL.setErrorCode(0x3008 /* EGL_BAD_DISPLAY */); - return 0 /* EGL_FALSE */; - } - //\todo An EGL_NOT_INITIALIZED error is generated if EGL is not initialized for dpy. - if (context != 0 && context != 62004 /* Magic ID for Emscripten EGLContext */) { - EGL.setErrorCode(0x3006 /* EGL_BAD_CONTEXT */); - return 0; - } - if ((read != 0 && read != 62006) || (draw != 0 && draw != 62006 /* Magic ID for Emscripten 'default surface' */)) { - EGL.setErrorCode(0x300D /* EGL_BAD_SURFACE */); - return 0; - } - EGL.currentContext = context; - EGL.currentDrawSurface = draw; - EGL.currentReadSurface = read; - EGL.setErrorCode(0x3000 /* EGL_SUCCESS */); - return 1 /* EGL_TRUE */; - }, - - // EGLAPI EGLContext EGLAPIENTRY eglGetCurrentContext(void); - eglGetCurrentContext: function() { - return EGL.currentContext; - }, - - // EGLAPI EGLSurface EGLAPIENTRY eglGetCurrentSurface(EGLint readdraw); - eglGetCurrentSurface: function(readdraw) { - if (readdraw == 0x305A /* EGL_READ */) { - return EGL.currentReadSurface; - } else if (readdraw == 0x3059 /* EGL_DRAW */) { - return EGL.currentDrawSurface; - } else { - EGL.setErrorCode(0x300C /* EGL_BAD_PARAMETER */); - return 0 /* EGL_NO_SURFACE */; - } - }, - - // EGLAPI EGLDisplay EGLAPIENTRY eglGetCurrentDisplay(void); - eglGetCurrentDisplay: function() { - return EGL.currentContext ? 62000 /* Magic ID for Emscripten 'default display' */ : 0; - }, - - // EGLAPI EGLBoolean EGLAPIENTRY eglSwapBuffers(EGLDisplay dpy, EGLSurface surface); - eglSwapBuffers: function() { -#if PROXY_TO_WORKER - if (Browser.doSwapBuffers) Browser.doSwapBuffers(); -#endif - - if (!EGL.defaultDisplayInitialized) { - EGL.setErrorCode(0x3001 /* EGL_NOT_INITIALIZED */); - } else if (!Module.ctx) { - EGL.setErrorCode(0x3002 /* EGL_BAD_ACCESS */); - } else if (Module.ctx.isContextLost()) { - EGL.setErrorCode(0x300E /* EGL_CONTEXT_LOST */); - } else { - // According to documentation this does an implicit flush. - // Due to discussion at https://github.com/kripken/emscripten/pull/1871 - // the flush was removed since this _may_ result in slowing code down. - //_glFlush(); - EGL.setErrorCode(0x3000 /* EGL_SUCCESS */); - return 1 /* EGL_TRUE */; - } - return 0 /* EGL_FALSE */; - }, - - eglGetProcAddress__deps: ['emscripten_GetProcAddress'], - eglGetProcAddress: function(name_) { - return _emscripten_GetProcAddress(name_); - }, - - eglReleaseThread: function() { - // Equivalent to eglMakeCurrent with EGL_NO_CONTEXT and EGL_NO_SURFACE. - EGL.currentContext = 0; - EGL.currentReadSurface = 0; - EGL.currentDrawSurface = 0; - // EGL spec v1.4 p.55: - // "calling eglGetError immediately following a successful call to eglReleaseThread should not be done. - // Such a call will return EGL_SUCCESS - but will also result in reallocating per-thread state." - EGL.setErrorCode(0x3000 /* EGL_SUCCESS */); - return 1 /* EGL_TRUE */; - } -}; - -autoAddDeps(LibraryEGL, '$EGL'); - -mergeInto(LibraryManager.library, LibraryEGL); diff --git a/src/modules.js b/src/modules.js index fe56a9c62ad4d..58b13921e0d35 100644 --- a/src/modules.js +++ b/src/modules.js @@ -140,7 +140,6 @@ var LibraryManager = { 'library_gl.js', 'library_glut.js', 'library_xlib.js', - 'library_egl.js', 'library_openal.js', 'library_glfw.js', 'library_uuid.js', diff --git a/system/lib/egl.symbols b/system/lib/egl.symbols new file mode 100644 index 0000000000000..b1e18a336debf --- /dev/null +++ b/system/lib/egl.symbols @@ -0,0 +1,34 @@ + T eglBindAPI + T eglBindTexImage + T eglChooseConfig + T eglCopyBuffers + T eglCreateContext + T eglCreatePbufferFromClientBuffer + T eglCreatePbufferSurface + T eglCreatePixmapSurface + T eglCreateWindowSurface + T eglDestroyContext + T eglDestroySurface + T eglGetConfigAttrib + T eglGetConfigs + T eglGetCurrentContext + T eglGetCurrentDisplay + T eglGetCurrentSurface + T eglGetDisplay + T eglGetError + T eglGetProcAddress + T eglInitialize + T eglMakeCurrent + T eglQueryAPI + T eglQueryContext + T eglQueryString + T eglQuerySurface + T eglReleaseTexImage + T eglReleaseThread + T eglSurfaceAttrib + T eglSwapBuffers + T eglSwapInterval + T eglTerminate + T eglWaitClient + T eglWaitGL + T eglWaitNative diff --git a/system/lib/egl/library_egl.c b/system/lib/egl/library_egl.c new file mode 100644 index 0000000000000..d18e1eee9b816 --- /dev/null +++ b/system/lib/egl/library_egl.c @@ -0,0 +1,570 @@ +#include +#include +#include + +// TODO: These should be thread local +static EGLint eglError = EGL_SUCCESS; +static EGLSurface eglCurrentReadSurface = 0; +static EGLSurface eglCurrentDrawSurface = 0; + +// Process wide: +static EGLint eglDefaultDisplayInitialized = 0; +static EMSCRIPTEN_WEBGL_CONTEXT_HANDLE windowID = 0; + +#define EMSCRIPTEN_EGL_MAGIC_ID_FOR_DEFAULT_DISPLAY ((EGLDisplay)62000) +#define EMSCRIPTEN_EGL_MAGIC_ID_FOR_DEFAULT_CONFIG ((EGLConfig)62002) +#define EMSCRIPTEN_EGL_MAGIC_ID_FOR_DEFAULT_SURFACE ((EGLSurface)62006) + +EGLAPI EGLint EGLAPIENTRY eglGetError(void) +{ + return eglError; +} + +EGLAPI EGLDisplay EGLAPIENTRY eglGetDisplay(EGLNativeDisplayType display_id) +{ + eglError = EGL_SUCCESS; + + // Note: As a 'conformant' implementation of EGL, we would prefer to init here only if the user + // calls this function with EGL_DEFAULT_DISPLAY. Other display IDs would be preferred to be unsupported + // and EGL_NO_DISPLAY returned. Uncomment the following code lines to do this. + // Instead, an alternative route has been preferred, namely that the Emscripten EGL implementation + // "emulates" X11, and eglGetDisplay is expected to accept/receive a pointer to an X11 Display object. + // Therefore, be lax and allow anything to be passed in, and return the magic handle to our default EGLDisplay object. + +// if (nativeDisplayType == 0 /* EGL_DEFAULT_DISPLAY */) { + return EMSCRIPTEN_EGL_MAGIC_ID_FOR_DEFAULT_DISPLAY; // Magic ID for Emscripten 'default display' +// } +// else +// return EGL_FALSE; // EGL_NO_DISPLAY +} + +EGLAPI EGLBoolean EGLAPIENTRY eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor) +{ + if (dpy != EMSCRIPTEN_EGL_MAGIC_ID_FOR_DEFAULT_DISPLAY) + { + eglError = EGL_BAD_DISPLAY; + return EGL_FALSE; + } + + if (major) *major = 1; + if (minor) *minor = 4; + eglDefaultDisplayInitialized = 1; + eglError = EGL_SUCCESS; + return EGL_TRUE; +} + +EGLAPI EGLBoolean EGLAPIENTRY eglTerminate(EGLDisplay dpy) +{ + if (dpy != EMSCRIPTEN_EGL_MAGIC_ID_FOR_DEFAULT_DISPLAY) + { + eglError = EGL_BAD_DISPLAY; + return EGL_FALSE; + } + emscripten_webgl_make_context_current(0); + eglCurrentReadSurface = 0; + eglCurrentDrawSurface = 0; + eglDefaultDisplayInitialized = 0; + eglError = EGL_SUCCESS; + return EGL_TRUE; +} + +EGLAPI const char * EGLAPIENTRY eglQueryString(EGLDisplay dpy, EGLint name) +{ + if (dpy != EMSCRIPTEN_EGL_MAGIC_ID_FOR_DEFAULT_DISPLAY) + { + eglError = EGL_BAD_DISPLAY; + return 0; + } + //\todo An EGL_NOT_INITIALIZED error is generated if EGL is not initialized for dpy. + eglError = EGL_SUCCESS; + switch(name) + { + case EGL_VENDOR: return "Emscripten"; + case EGL_VERSION: return "1.4 Emscripten EGL"; + case EGL_EXTENSIONS: return ""; + case EGL_CLIENT_APIS: return "OpenGL_ES"; + default: + eglError = EGL_BAD_PARAMETER; + return 0; + } +} + +EGLAPI EGLBoolean EGLAPIENTRY eglChooseConfig(EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *configs, EGLint config_size, EGLint *num_config) +{ + if (dpy != EMSCRIPTEN_EGL_MAGIC_ID_FOR_DEFAULT_DISPLAY) + { + eglError = EGL_BAD_DISPLAY; + return EGL_FALSE; + } + if ((!configs || !config_size) && !num_config) + { + eglError = EGL_BAD_PARAMETER; + return EGL_FALSE; + } + if (num_config) *num_config = 1; + if (configs && config_size > 0) configs[0] = EMSCRIPTEN_EGL_MAGIC_ID_FOR_DEFAULT_CONFIG; + + eglError = EGL_SUCCESS; + return EGL_TRUE; +} + +EGLAPI EGLBoolean EGLAPIENTRY eglGetConfigs(EGLDisplay dpy, EGLConfig *configs, EGLint config_size, EGLint *num_config) +{ + return eglChooseConfig(dpy, 0, configs, config_size, num_config); +} + + +EGLAPI EGLBoolean EGLAPIENTRY eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint *value) +{ + if (dpy != EMSCRIPTEN_EGL_MAGIC_ID_FOR_DEFAULT_DISPLAY) + { + eglError = EGL_BAD_DISPLAY; + return EGL_FALSE; + } + + if (config != EMSCRIPTEN_EGL_MAGIC_ID_FOR_DEFAULT_CONFIG) + { + eglError = EGL_BAD_CONFIG; + return EGL_FALSE; + } + + if (!value) + { + eglError = EGL_BAD_PARAMETER; + return EGL_FALSE; + } + + eglError = EGL_SUCCESS; + + switch(attribute) + { + case EGL_BUFFER_SIZE: *value = 32; return EGL_TRUE; + case EGL_ALPHA_SIZE: *value = 8; return EGL_TRUE; // TODO: This is hardcoded, add support for this + case EGL_BLUE_SIZE: + case EGL_GREEN_SIZE: + case EGL_RED_SIZE: + *value = 8; return EGL_TRUE; + case EGL_DEPTH_SIZE: *value = 24; return EGL_TRUE; // TODO: This is hardcoded, add support for this + case EGL_STENCIL_SIZE: *value = 8; return EGL_TRUE; // TODO: This is hardcoded, add support for this + // We can return here one of EGL_NONE (0x3038), EGL_SLOW_CONFIG (0x3050) or EGL_NON_CONFORMANT_CONFIG (0x3051). + case EGL_CONFIG_CAVEAT: *value = EGL_NONE; return EGL_TRUE; + case EGL_CONFIG_ID: *value = (EGLint)EMSCRIPTEN_EGL_MAGIC_ID_FOR_DEFAULT_CONFIG; return EGL_TRUE; + case EGL_LEVEL: *value = 0; return EGL_TRUE; + case EGL_MAX_PBUFFER_HEIGHT: *value = 4096; return EGL_TRUE; + case EGL_MAX_PBUFFER_PIXELS: *value = 4096 * 4096; return EGL_TRUE; + case EGL_MAX_PBUFFER_WIDTH: *value = 4096; return EGL_TRUE; + case EGL_NATIVE_RENDERABLE: *value = 0; return EGL_TRUE; + case EGL_NATIVE_VISUAL_ID: *value = 0; return EGL_TRUE; + case EGL_NATIVE_VISUAL_TYPE: *value = EGL_NONE; return EGL_TRUE; + case EGL_SAMPLES: *value = 4; return EGL_TRUE; + case EGL_SAMPLE_BUFFERS: *value = 1; return EGL_TRUE; + case EGL_SURFACE_TYPE: *value = EGL_WINDOW_BIT; return EGL_TRUE; + case EGL_TRANSPARENT_TYPE: *value = EGL_NONE; return EGL_TRUE; + case EGL_TRANSPARENT_BLUE_VALUE: + case EGL_TRANSPARENT_GREEN_VALUE: + case EGL_TRANSPARENT_RED_VALUE: + *value = -1; return EGL_TRUE; + case EGL_BIND_TO_TEXTURE_RGB: + case EGL_BIND_TO_TEXTURE_RGBA: + *value = 0; return EGL_TRUE; + case EGL_MIN_SWAP_INTERVAL: *value = 0; return EGL_TRUE; + case EGL_MAX_SWAP_INTERVAL: *value = 32; return EGL_TRUE; // This is arbitrary, we can allow unlimited slow swap intervals, but cap to something semi-reasonable + case EGL_LUMINANCE_SIZE: + case EGL_ALPHA_MASK_SIZE: + *value = 0; + return EGL_TRUE; + case EGL_COLOR_BUFFER_TYPE: *value = EGL_RGB_BUFFER; return EGL_TRUE; + case EGL_RENDERABLE_TYPE: *value = EGL_OPENGL_ES2_BIT; return EGL_TRUE; + case EGL_CONFORMANT: *value = 0; return EGL_TRUE; + default: + eglError = EGL_BAD_ATTRIBUTE; + return EGL_FALSE; + } +} + +EGLAPI EGLSurface EGLAPIENTRY eglCreateWindowSurface(EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win, const EGLint *attrib_list) +{ + if (dpy != EMSCRIPTEN_EGL_MAGIC_ID_FOR_DEFAULT_DISPLAY) + { + eglError = EGL_BAD_DISPLAY; + return 0; + } + + if (config != EMSCRIPTEN_EGL_MAGIC_ID_FOR_DEFAULT_CONFIG) + { + eglError = EGL_BAD_CONFIG; + return 0; + } + + eglError = EGL_SUCCESS; + return EMSCRIPTEN_EGL_MAGIC_ID_FOR_DEFAULT_SURFACE; +} + +EGLAPI EGLSurface EGLAPIENTRY eglCreatePbufferSurface(EGLDisplay dpy, EGLConfig config, const EGLint *attrib_list) +{ + eglError = EGL_BAD_ACCESS; // Use in place of a "Not implemented" flag + return 0; +} + +EGLAPI EGLSurface EGLAPIENTRY eglCreatePixmapSurface(EGLDisplay dpy, EGLConfig config, EGLNativePixmapType pixmap, const EGLint *attrib_list) +{ + eglError = EGL_BAD_ACCESS; // Use in place of a "Not implemented" flag + return 0; +} + +EGLAPI EGLBoolean EGLAPIENTRY eglDestroySurface(EGLDisplay dpy, EGLSurface surface) +{ + if (dpy != EMSCRIPTEN_EGL_MAGIC_ID_FOR_DEFAULT_DISPLAY) + { + eglError = EGL_BAD_DISPLAY; + return EGL_FALSE; + } + + if (surface != EMSCRIPTEN_EGL_MAGIC_ID_FOR_DEFAULT_SURFACE) + { + eglError = EGL_BAD_SURFACE; + return EGL_FALSE; + } + + if (eglCurrentReadSurface == surface) eglCurrentReadSurface = 0; + if (eglCurrentDrawSurface == surface) eglCurrentDrawSurface = 0; + eglError = EGL_SUCCESS; + return EGL_TRUE; + +} + +EGLAPI EGLBoolean EGLAPIENTRY eglQuerySurface(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint *value) +{ + if (dpy != EMSCRIPTEN_EGL_MAGIC_ID_FOR_DEFAULT_DISPLAY) + { + eglError = EGL_BAD_DISPLAY; + return EGL_FALSE; + } + + if (surface != EMSCRIPTEN_EGL_MAGIC_ID_FOR_DEFAULT_SURFACE) + { + eglError = EGL_BAD_SURFACE; + return EGL_FALSE; + } + + if (!value) + { + eglError = EGL_BAD_PARAMETER; + return EGL_FALSE; + } + + eglError = EGL_SUCCESS; + + switch(attribute) + { + case EGL_CONFIG_ID: *value = (EGLint)EMSCRIPTEN_EGL_MAGIC_ID_FOR_DEFAULT_CONFIG; return EGL_TRUE; + case EGL_LARGEST_PBUFFER: + // Odd EGL API: If surface is not a pbuffer surface, 'value' should not be written to. It's not specified as an error, so true should(?) be returned. + // Existing Android implementation seems to do so at least. + return EGL_TRUE; + case EGL_WIDTH: + case EGL_HEIGHT: + { + int w, h; + emscripten_get_canvas_element_size(NULL, &w, &h); // TODO: Figure out which canvas to query here. + *value = (attribute == EGL_WIDTH) ? w : h; + return EGL_TRUE; + } + case EGL_HORIZONTAL_RESOLUTION: + case EGL_VERTICAL_RESOLUTION: + case EGL_PIXEL_ASPECT_RATIO: + *value = EGL_UNKNOWN; + return EGL_TRUE; + case EGL_RENDER_BUFFER: *value = EGL_BACK_BUFFER; return EGL_TRUE; + case EGL_MULTISAMPLE_RESOLVE: *value = EGL_MULTISAMPLE_RESOLVE_DEFAULT; return EGL_TRUE; + case EGL_SWAP_BEHAVIOR: *value = EGL_BUFFER_DESTROYED; return EGL_TRUE; // TODO: Add support for EGL_BUFFER_PRESERVED and pass it to preserveDrawingBuffer of the context creation API + case EGL_TEXTURE_FORMAT: + case EGL_TEXTURE_TARGET: + case EGL_MIPMAP_TEXTURE: + case EGL_MIPMAP_LEVEL: + // This is a window surface, not a pbuffer surface. Spec: + // "Querying EGL_TEXTURE_FORMAT, EGL_TEXTURE_TARGET, EGL_MIPMAP_TEXTURE, or EGL_MIPMAP_LEVEL for a non-pbuffer surface is not an error, but value is not modified." + // So pass-through. + return EGL_TRUE; + default: + eglError = EGL_BAD_ATTRIBUTE; + return EGL_FALSE; + } +} + +EGLAPI EGLBoolean EGLAPIENTRY eglBindAPI(EGLenum api) +{ + if (api == EGL_OPENGL_ES_API) + { + eglError = EGL_SUCCESS; + return EGL_TRUE; + } + eglError = EGL_BAD_PARAMETER; + return EGL_FALSE; +} + +EGLAPI EGLenum EGLAPIENTRY eglQueryAPI(void) +{ + eglError = EGL_SUCCESS; + return EGL_OPENGL_ES_API; +} + +EGLAPI EGLBoolean EGLAPIENTRY eglWaitClient(void) +{ + eglError = EGL_SUCCESS; + return EGL_TRUE; +} + +EGLAPI EGLBoolean EGLAPIENTRY eglReleaseThread(void) +{ + // Equivalent to eglMakeCurrent with EGL_NO_CONTEXT and EGL_NO_SURFACE. + emscripten_webgl_make_context_current(0); + eglCurrentReadSurface = 0; + eglCurrentDrawSurface = 0; + + // EGL spec v1.4 p.55: + // "calling eglGetError immediately following a successful call to eglReleaseThread should not be done. + // Such a call will return EGL_SUCCESS - but will also result in reallocating per-thread state." + eglError = EGL_SUCCESS; + return EGL_TRUE; +} + +EGLAPI EGLSurface EGLAPIENTRY eglCreatePbufferFromClientBuffer(EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer, EGLConfig config, const EGLint *attrib_list) +{ + eglError = EGL_BAD_ACCESS; // Use in place of a "Not implemented" flag + return 0; +} + +EGLAPI EGLBoolean EGLAPIENTRY eglSurfaceAttrib(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value) +{ + eglError = EGL_BAD_ACCESS; // Use in place of a "Not implemented" flag + return EGL_FALSE; +} + +EGLAPI EGLBoolean EGLAPIENTRY eglBindTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer) +{ + eglError = EGL_BAD_ACCESS; // Use in place of a "Not implemented" flag + return EGL_FALSE; +} + +EGLAPI EGLBoolean EGLAPIENTRY eglReleaseTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer) +{ + eglError = EGL_BAD_ACCESS; // Use in place of a "Not implemented" flag + return EGL_FALSE; +} + + +EGLAPI EGLBoolean EGLAPIENTRY eglSwapInterval(EGLDisplay dpy, EGLint interval) +{ + if (dpy != EMSCRIPTEN_EGL_MAGIC_ID_FOR_DEFAULT_DISPLAY) + { + eglError = EGL_BAD_DISPLAY; + return EGL_FALSE; + } + + if (interval == 0) emscripten_set_main_loop_timing(EM_TIMING_SETIMMEDIATE, 0); + else emscripten_set_main_loop_timing(EM_TIMING_RAF, interval); + eglError = EGL_SUCCESS; + return EGL_TRUE; +} + + +EGLAPI EGLContext EGLAPIENTRY eglCreateContext(EGLDisplay dpy, EGLConfig config, EGLContext share_context, const EGLint *attrib_list) +{ + if (dpy != EMSCRIPTEN_EGL_MAGIC_ID_FOR_DEFAULT_DISPLAY) + { + eglError = EGL_BAD_DISPLAY; + return EGL_FALSE; + } + + if (!attrib_list) + { + eglError = EGL_BAD_PARAMETER; + return EGL_FALSE; + } + + // EGL 1.4 spec says default EGL_CONTEXT_CLIENT_VERSION is GLES1, but this is not supported by Emscripten. + // So user must pass EGL_CONTEXT_CLIENT_VERSION == 2 to initialize EGL. + int glesContextVersion = 1; + while(*attrib_list != EGL_NONE) + { + switch(*attrib_list) + { + case EGL_CONTEXT_CLIENT_VERSION: glesContextVersion = attrib_list[1]; break; + default: + eglError = EGL_BAD_ATTRIBUTE; + return EGL_NO_CONTEXT; + } + attrib_list += 2; + } + if (glesContextVersion != 2) + { + fprintf(stderr, "When initializing GLES2/WebGL 1 via EGL, one must pass EGL_CONTEXT_CLIENT_VERSION = 2 to GL context attributes! GLES version %d is not supported!\n", glesContextVersion); + eglError = EGL_BAD_CONFIG; + return EGL_NO_CONTEXT; + } + + EmscriptenWebGLContextAttributes attr; + emscripten_webgl_init_context_attributes(&attr); + attr.depth = 1; + attr.stencil = 1; + attr.alpha = 0; + // TODO: Make this the default +// attr.explicitSwapControl = 1; + windowID = emscripten_webgl_create_context(0, &attr); + eglError = windowID ? EGL_SUCCESS : EGL_BAD_MATCH; + return (EGLContext)windowID; +} + +EGLAPI EGLBoolean EGLAPIENTRY eglDestroyContext(EGLDisplay dpy, EGLContext ctx) +{ + if (dpy != EMSCRIPTEN_EGL_MAGIC_ID_FOR_DEFAULT_DISPLAY) + { + eglError = EGL_BAD_DISPLAY; + return EGL_FALSE; + } + + if (emscripten_webgl_get_current_context() == (EMSCRIPTEN_WEBGL_CONTEXT_HANDLE)ctx) emscripten_webgl_make_context_current(0); + + EMSCRIPTEN_RESULT res = emscripten_webgl_destroy_context((EMSCRIPTEN_WEBGL_CONTEXT_HANDLE)ctx); + if (res >= 0) + { + eglError = EGL_SUCCESS; + return EGL_TRUE; + } + return EGL_FALSE; +} + +EGLAPI EGLBoolean EGLAPIENTRY eglMakeCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx) +{ + if (dpy != EMSCRIPTEN_EGL_MAGIC_ID_FOR_DEFAULT_DISPLAY) + { + eglError = EGL_BAD_DISPLAY; + return EGL_FALSE; + } + + // TODO: Test if context is valid + + if ((read != EGL_NO_SURFACE && read != EMSCRIPTEN_EGL_MAGIC_ID_FOR_DEFAULT_SURFACE) || (draw != EGL_NO_SURFACE && draw != EMSCRIPTEN_EGL_MAGIC_ID_FOR_DEFAULT_SURFACE)) + { + eglError = EGL_BAD_SURFACE; + return EGL_FALSE; + } + + EMSCRIPTEN_RESULT res = emscripten_webgl_make_context_current((EMSCRIPTEN_WEBGL_CONTEXT_HANDLE)ctx); + if (res >= 0) + { + eglCurrentReadSurface = read; + eglCurrentDrawSurface = draw; + eglError = EGL_SUCCESS; + return EGL_TRUE; + } + return EGL_FALSE; +} + +EGLAPI EGLContext EGLAPIENTRY eglGetCurrentContext(void) +{ + return (EGLContext)emscripten_webgl_get_current_context(); +} + +EGLAPI EGLSurface EGLAPIENTRY eglGetCurrentSurface(EGLint readdraw) +{ + if (readdraw == EGL_READ) return eglCurrentReadSurface; + else if (readdraw == EGL_DRAW) return eglCurrentDrawSurface; + else + { + eglError = EGL_BAD_PARAMETER; + return EGL_NO_SURFACE; + } +} + +EGLAPI EGLDisplay EGLAPIENTRY eglGetCurrentDisplay(void) +{ + return (emscripten_webgl_get_current_context() != 0) ? EMSCRIPTEN_EGL_MAGIC_ID_FOR_DEFAULT_DISPLAY : 0; +} + +EGLAPI EGLBoolean EGLAPIENTRY eglQueryContext(EGLDisplay dpy, EGLContext ctx, EGLint attribute, EGLint *value) +{ + if (dpy != EMSCRIPTEN_EGL_MAGIC_ID_FOR_DEFAULT_DISPLAY) + { + eglError = EGL_BAD_DISPLAY; + return EGL_FALSE; + } + + // TODO An EGL_NOT_INITIALIZED error is generated if EGL is not initialized for dpy. + + // TODO Test if ctx is valid context + + if (!value) + { + eglError = EGL_BAD_PARAMETER; + return EGL_FALSE; + } + + eglError = EGL_SUCCESS; + switch(attribute) + { + case EGL_CONFIG_ID: *value = (EGLint)EMSCRIPTEN_EGL_MAGIC_ID_FOR_DEFAULT_CONFIG; return EGL_TRUE; + case EGL_CONTEXT_CLIENT_TYPE: *value = EGL_OPENGL_ES_API; return EGL_TRUE; + case EGL_CONTEXT_CLIENT_VERSION: *value = 2; return EGL_TRUE; + case EGL_RENDER_BUFFER: *value = EGL_BACK_BUFFER; return EGL_TRUE; + default: + eglError = EGL_BAD_ATTRIBUTE; + return EGL_FALSE; + } +} + +EGLAPI EGLBoolean EGLAPIENTRY eglWaitGL(void) +{ + eglError = EGL_SUCCESS; + return EGL_TRUE; +} + +EGLAPI EGLBoolean EGLAPIENTRY eglWaitNative(EGLint engine) +{ + eglError = EGL_SUCCESS; + return EGL_TRUE; +} + +EGLAPI EGLBoolean EGLAPIENTRY eglSwapBuffers(EGLDisplay dpy, EGLSurface surface) +{ + if (dpy != EMSCRIPTEN_EGL_MAGIC_ID_FOR_DEFAULT_DISPLAY) + { + eglError = EGL_BAD_DISPLAY; + return EGL_FALSE; + } + + if (surface != EMSCRIPTEN_EGL_MAGIC_ID_FOR_DEFAULT_SURFACE) + { + eglError = EGL_BAD_SURFACE; + return EGL_FALSE; + } + + if (!eglDefaultDisplayInitialized) + { + eglError = EGL_NOT_INITIALIZED; + return EGL_FALSE; + } + + EMSCRIPTEN_RESULT res = emscripten_webgl_commit_frame(); + if (res >= 0) + { + eglError = EGL_SUCCESS; + return EGL_TRUE; + } + eglError = EGL_BAD_ACCESS; + return EGL_FALSE; +} + +EGLAPI EGLBoolean EGLAPIENTRY eglCopyBuffers(EGLDisplay dpy, EGLSurface surface, EGLNativePixmapType target) +{ + eglError = EGL_BAD_ACCESS; // Use in place of a "Not implemented" flag + return 0; +} + +void* emscripten_GetProcAddress(const char *name_); + +EGLAPI __eglMustCastToProperFunctionPointerType EGLAPIENTRY eglGetProcAddress(const char *procname) +{ + return emscripten_GetProcAddress(procname); +} diff --git a/tools/shared.py b/tools/shared.py index add6c1037d2cb..6a241038442e2 100644 --- a/tools/shared.py +++ b/tools/shared.py @@ -2339,7 +2339,7 @@ def path_to_system_js_libraries(library_name): js_system_libraries = { 'c': '', 'dl': '', - 'EGL': 'library_egl.js', + 'EGL': '', 'GL': 'library_gl.js', 'GLESv2': 'library_gl.js', 'GLEW': 'library_glew.js', @@ -2361,9 +2361,6 @@ def path_to_system_js_libraries(library_name): if len(js_system_libraries[library_name]) > 0: library_files += [js_system_libraries[library_name]] - # TODO: This is unintentional due to historical reasons. Improve EGL to use HTML5 API to avoid depending on GLUT. - if library_name == 'EGL': library_files += ['library_glut.js'] - elif library_name.endswith('.js') and os.path.isfile(path_from_root('src', 'library_' + library_name)): library_files += ['library_' + library_name] else: @@ -2384,7 +2381,7 @@ def path_to_system_js_libraries_for_settings(link_settings): if 'ASYNCIFY=1' in link_settings: system_js_libraries += ['library_async.js'] if 'LZ4=1' in link_settings: system_js_libraries += ['library_lz4.js'] if 'USE_SDL=1' in link_settings: system_js_libraries += ['library_sdl.js'] - if 'USE_SDL=2' in link_settings: system_js_libraries += ['library_egl.js', 'library_glut.js', 'library_gl.js'] + if 'USE_SDL=2' in link_settings: system_js_libraries += ['library_glut.js', 'library_gl.js'] return [path_from_root('src', x) for x in system_js_libraries] @staticmethod diff --git a/tools/system_libs.py b/tools/system_libs.py index b6cf81b1a81fb..ac483622d28a7 100755 --- a/tools/system_libs.py +++ b/tools/system_libs.py @@ -54,6 +54,7 @@ def read_symbols(path): libcxxabi_symbols = read_symbols(shared.path_from_root('system', 'lib', 'libcxxabi', 'symbols')) gl_symbols = read_symbols(shared.path_from_root('system', 'lib', 'gl.symbols')) al_symbols = read_symbols(shared.path_from_root('system', 'lib', 'al.symbols')) + egl_symbols = read_symbols(shared.path_from_root('system', 'lib', 'egl.symbols')) compiler_rt_symbols = read_symbols(shared.path_from_root('system', 'lib', 'compiler-rt.symbols')) pthreads_symbols = read_symbols(shared.path_from_root('system', 'lib', 'pthreads.symbols')) asmjs_pthreads_symbols = read_symbols(shared.path_from_root('system', 'lib', 'asmjs_pthreads.symbols')) @@ -185,6 +186,10 @@ def create_pthreads_asmjs(libname): pthreads_files = [os.path.join('pthread', 'library_pthread_asmjs.c')] return build_libc(libname, pthreads_files, ['-O2', '-s', 'USE_PTHREADS=1']) + def create_egl(libname): + egl_files = [os.path.join('egl', 'library_egl.c')] + return build_libc(libname, egl_files, []) + def create_wasm_libc(libname): # in asm.js we just use Math.sin etc., which is good for code size. But # wasm doesn't have such builtins, so we need to bundle in more code @@ -449,6 +454,7 @@ class Dummy(object): ('al', 'bc', create_al, al_symbols, ['libc'], False), ('html5', 'bc', create_html5, html5_symbols, ['html5'], False), ('compiler-rt', 'a', create_compiler_rt, compiler_rt_symbols, ['libc'], False), + ('egl', 'bc', create_egl, egl_symbols, ['libc'], False), (dlmalloc_name(), 'bc', create_dlmalloc, [], [], False)] if shared.Settings.USE_PTHREADS: From 89c6dc0a08cb4376a468c9bf48d273a5939365cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Tue, 17 Oct 2017 18:18:25 +0300 Subject: [PATCH 2/3] Implement first version of EGL config choosing. --- system/lib/egl/library_egl.c | 112 ++++++++++++++++++++++++++--------- 1 file changed, 83 insertions(+), 29 deletions(-) diff --git a/system/lib/egl/library_egl.c b/system/lib/egl/library_egl.c index d18e1eee9b816..6c60d3c937387 100644 --- a/system/lib/egl/library_egl.c +++ b/system/lib/egl/library_egl.c @@ -6,15 +6,34 @@ static EGLint eglError = EGL_SUCCESS; static EGLSurface eglCurrentReadSurface = 0; static EGLSurface eglCurrentDrawSurface = 0; +static EGLConfig eglCurrentInitializedConfig = (EGLConfig)0; // TODO: This should not be a singleton // Process wide: static EGLint eglDefaultDisplayInitialized = 0; static EMSCRIPTEN_WEBGL_CONTEXT_HANDLE windowID = 0; #define EMSCRIPTEN_EGL_MAGIC_ID_FOR_DEFAULT_DISPLAY ((EGLDisplay)62000) -#define EMSCRIPTEN_EGL_MAGIC_ID_FOR_DEFAULT_CONFIG ((EGLConfig)62002) #define EMSCRIPTEN_EGL_MAGIC_ID_FOR_DEFAULT_SURFACE ((EGLSurface)62006) +// Currently there are few enough configuration options for creating a WebGL context +// that all the permutations can fit in an uint32. Therefore use bit packing to represent +// these combinations to avoid having to enumerate a list fo all combos, to save memory. +// This is an internal implementation detail, and can be changed in the future if the number of options +// increases to become too large to fit in an uint32/uint64. +#define EM_EGL_ALPHA_BIT 0x1 +#define EM_EGL_DEPTH_BIT 0x2 +#define EM_EGL_STENCIL_BIT 0x4 +#define EM_EGL_ANTIALIAS_BIT 0x8 +#define EM_EGL_PREMULTIPLIED_ALPHA_BIT 0x10 +#define EM_EGL_PRESERVE_DRAWING_BUFFER_BIT 0x20 +#define EM_EGL_PREFER_LOW_POWER_TO_HIGH_PERFORMANCE_BIT 0x40 +#define EM_EGL_FAIL_IF_MAJOR_PERFORMANCE_CAVEAT_BIT 0x80 +#define EM_EGL_WEBGL2_BIT 0x100 +#define EM_EGL_ENABLE_EXTENSIONS_BY_DEFAULT_BIT 0x200 +#define EM_EGL_EXPLICIT_SWAP_CONTROL_BIT 0x400 +#define EM_EGL_PROXY_TO_MAIN_THREAD_BIT 0x800 +#define EM_EGL_RENDER_VIA_OFFSCREEN_BACK_BUFFER_BIT 0x1000 + EGLAPI EGLint EGLAPIENTRY eglGetError(void) { return eglError; @@ -89,6 +108,14 @@ EGLAPI const char * EGLAPIENTRY eglQueryString(EGLDisplay dpy, EGLint name) } } +static EGLBoolean ConfigPassesFilter(EGLConfig config, const EGLint *attrib_list) +{ + if (!attrib_list) return EGL_TRUE; + + + return EGL_TRUE; +} + EGLAPI EGLBoolean EGLAPIENTRY eglChooseConfig(EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *configs, EGLint config_size, EGLint *num_config) { if (dpy != EMSCRIPTEN_EGL_MAGIC_ID_FOR_DEFAULT_DISPLAY) @@ -101,9 +128,29 @@ EGLAPI EGLBoolean EGLAPIENTRY eglChooseConfig(EGLDisplay dpy, const EGLint *attr eglError = EGL_BAD_PARAMETER; return EGL_FALSE; } - if (num_config) *num_config = 1; - if (configs && config_size > 0) configs[0] = EMSCRIPTEN_EGL_MAGIC_ID_FOR_DEFAULT_CONFIG; + const int baseConfig = EM_EGL_ENABLE_EXTENSIONS_BY_DEFAULT_BIT; + int numMatchingConfigs = 0; + if (!configs) config_size = 0x7FFFFFFF; + + for(int a = 0; a <= EM_EGL_ALPHA_BIT; a += EM_EGL_ALPHA_BIT) + for(int d = 0; d <= EM_EGL_DEPTH_BIT; d += EM_EGL_DEPTH_BIT) + for(int s = 0; s <= EM_EGL_STENCIL_BIT; s += EM_EGL_STENCIL_BIT) + for(int aa = 0; aa <= EM_EGL_ANTIALIAS_BIT; aa += EM_EGL_ANTIALIAS_BIT) + for(int es3 = 0; es3 <= EM_EGL_WEBGL2_BIT; es3 += EM_EGL_WEBGL2_BIT) + { + if (numMatchingConfigs >= config_size) + break; + + EGLConfig config = (EGLConfig)(baseConfig | a | d | s | aa | es3); + if (ConfigPassesFilter(config, attrib_list)) + { + if (configs) configs[numMatchingConfigs] = config; + ++numMatchingConfigs; + } + } + + *num_config = numMatchingConfigs; eglError = EGL_SUCCESS; return EGL_TRUE; } @@ -113,7 +160,6 @@ EGLAPI EGLBoolean EGLAPIENTRY eglGetConfigs(EGLDisplay dpy, EGLConfig *configs, return eglChooseConfig(dpy, 0, configs, config_size, num_config); } - EGLAPI EGLBoolean EGLAPIENTRY eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint *value) { if (dpy != EMSCRIPTEN_EGL_MAGIC_ID_FOR_DEFAULT_DISPLAY) @@ -122,12 +168,6 @@ EGLAPI EGLBoolean EGLAPIENTRY eglGetConfigAttrib(EGLDisplay dpy, EGLConfig confi return EGL_FALSE; } - if (config != EMSCRIPTEN_EGL_MAGIC_ID_FOR_DEFAULT_CONFIG) - { - eglError = EGL_BAD_CONFIG; - return EGL_FALSE; - } - if (!value) { eglError = EGL_BAD_PARAMETER; @@ -139,16 +179,16 @@ EGLAPI EGLBoolean EGLAPIENTRY eglGetConfigAttrib(EGLDisplay dpy, EGLConfig confi switch(attribute) { case EGL_BUFFER_SIZE: *value = 32; return EGL_TRUE; - case EGL_ALPHA_SIZE: *value = 8; return EGL_TRUE; // TODO: This is hardcoded, add support for this + case EGL_ALPHA_SIZE: *value = ((EGLint)config & EM_EGL_ALPHA_BIT) ? 8 : 0; return EGL_TRUE; case EGL_BLUE_SIZE: case EGL_GREEN_SIZE: case EGL_RED_SIZE: *value = 8; return EGL_TRUE; - case EGL_DEPTH_SIZE: *value = 24; return EGL_TRUE; // TODO: This is hardcoded, add support for this - case EGL_STENCIL_SIZE: *value = 8; return EGL_TRUE; // TODO: This is hardcoded, add support for this + case EGL_DEPTH_SIZE: *value = ((EGLint)config & EM_EGL_DEPTH_BIT) ? 24 : 0; return EGL_TRUE; + case EGL_STENCIL_SIZE: *value = ((EGLint)config & EM_EGL_STENCIL_BIT) ? 8 : 0; return EGL_TRUE; // We can return here one of EGL_NONE (0x3038), EGL_SLOW_CONFIG (0x3050) or EGL_NON_CONFORMANT_CONFIG (0x3051). case EGL_CONFIG_CAVEAT: *value = EGL_NONE; return EGL_TRUE; - case EGL_CONFIG_ID: *value = (EGLint)EMSCRIPTEN_EGL_MAGIC_ID_FOR_DEFAULT_CONFIG; return EGL_TRUE; + case EGL_CONFIG_ID: *value = (EGLint)config; return EGL_TRUE; case EGL_LEVEL: *value = 0; return EGL_TRUE; case EGL_MAX_PBUFFER_HEIGHT: *value = 4096; return EGL_TRUE; case EGL_MAX_PBUFFER_PIXELS: *value = 4096 * 4096; return EGL_TRUE; @@ -156,8 +196,8 @@ EGLAPI EGLBoolean EGLAPIENTRY eglGetConfigAttrib(EGLDisplay dpy, EGLConfig confi case EGL_NATIVE_RENDERABLE: *value = 0; return EGL_TRUE; case EGL_NATIVE_VISUAL_ID: *value = 0; return EGL_TRUE; case EGL_NATIVE_VISUAL_TYPE: *value = EGL_NONE; return EGL_TRUE; - case EGL_SAMPLES: *value = 4; return EGL_TRUE; - case EGL_SAMPLE_BUFFERS: *value = 1; return EGL_TRUE; + case EGL_SAMPLES: *value = ((EGLint)config & EM_EGL_ANTIALIAS_BIT) ? 4 : 0; return EGL_TRUE; + case EGL_SAMPLE_BUFFERS: *value = ((EGLint)config & EM_EGL_ANTIALIAS_BIT) ? 1 : 0; return EGL_TRUE; case EGL_SURFACE_TYPE: *value = EGL_WINDOW_BIT; return EGL_TRUE; case EGL_TRANSPARENT_TYPE: *value = EGL_NONE; return EGL_TRUE; case EGL_TRANSPARENT_BLUE_VALUE: @@ -190,12 +230,6 @@ EGLAPI EGLSurface EGLAPIENTRY eglCreateWindowSurface(EGLDisplay dpy, EGLConfig c return 0; } - if (config != EMSCRIPTEN_EGL_MAGIC_ID_FOR_DEFAULT_CONFIG) - { - eglError = EGL_BAD_CONFIG; - return 0; - } - eglError = EGL_SUCCESS; return EMSCRIPTEN_EGL_MAGIC_ID_FOR_DEFAULT_SURFACE; } @@ -257,7 +291,7 @@ EGLAPI EGLBoolean EGLAPIENTRY eglQuerySurface(EGLDisplay dpy, EGLSurface surface switch(attribute) { - case EGL_CONFIG_ID: *value = (EGLint)EMSCRIPTEN_EGL_MAGIC_ID_FOR_DEFAULT_CONFIG; return EGL_TRUE; + case EGL_CONFIG_ID: *value = (EGLint)eglCurrentInitializedConfig; return EGL_TRUE; case EGL_LARGEST_PBUFFER: // Odd EGL API: If surface is not a pbuffer surface, 'value' should not be written to. It's not specified as an error, so true should(?) be returned. // Existing Android implementation seems to do so at least. @@ -406,13 +440,26 @@ EGLAPI EGLContext EGLAPIENTRY eglCreateContext(EGLDisplay dpy, EGLConfig config, EmscriptenWebGLContextAttributes attr; emscripten_webgl_init_context_attributes(&attr); - attr.depth = 1; - attr.stencil = 1; - attr.alpha = 0; - // TODO: Make this the default -// attr.explicitSwapControl = 1; + attr.alpha = ((EGLint)config & EM_EGL_ALPHA_BIT) ? 1 : 0; + attr.depth = ((EGLint)config & EM_EGL_DEPTH_BIT) ? 1 : 0; + attr.stencil = ((EGLint)config & EM_EGL_STENCIL_BIT) ? 1 : 0; + attr.antialias = ((EGLint)config & EM_EGL_ANTIALIAS_BIT) ? 1 : 0; + attr.premultipliedAlpha = ((EGLint)config & EM_EGL_PREMULTIPLIED_ALPHA_BIT) ? 1 : 0; + attr.preserveDrawingBuffer = ((EGLint)config & EM_EGL_PRESERVE_DRAWING_BUFFER_BIT) ? 1 : 0; + attr.preferLowPowerToHighPerformance = ((EGLint)config & EM_EGL_PREFER_LOW_POWER_TO_HIGH_PERFORMANCE_BIT) ? 1 : 0; + attr.failIfMajorPerformanceCaveat = ((EGLint)config & EM_EGL_FAIL_IF_MAJOR_PERFORMANCE_CAVEAT_BIT) ? 1 : 0; + attr.majorVersion = ((EGLint)config & EM_EGL_WEBGL2_BIT) ? 2 : 1; + attr.minorVersion = 0; + attr.enableExtensionsByDefault = ((EGLint)config & EM_EGL_ENABLE_EXTENSIONS_BY_DEFAULT_BIT) ? 1 : 0; + attr.explicitSwapControl = ((EGLint)config & EM_EGL_EXPLICIT_SWAP_CONTROL_BIT) ? 1 : 0; + attr.proxyContextToMainThread = ((EGLint)config & EM_EGL_PROXY_TO_MAIN_THREAD_BIT) ? 1 : 0; + attr.renderViaOffscreenBackBuffer = ((EGLint)config & EM_EGL_RENDER_VIA_OFFSCREEN_BACK_BUFFER_BIT) ? 1 : 0; windowID = emscripten_webgl_create_context(0, &attr); eglError = windowID ? EGL_SUCCESS : EGL_BAD_MATCH; + if (EGL_SUCCESS) + { + eglCurrentInitializedConfig = config; + } return (EGLContext)windowID; } @@ -432,6 +479,8 @@ EGLAPI EGLBoolean EGLAPIENTRY eglDestroyContext(EGLDisplay dpy, EGLContext ctx) eglError = EGL_SUCCESS; return EGL_TRUE; } + + eglCurrentInitializedConfig = (EGLConfig)0; return EGL_FALSE; } @@ -504,7 +553,7 @@ EGLAPI EGLBoolean EGLAPIENTRY eglQueryContext(EGLDisplay dpy, EGLContext ctx, EG eglError = EGL_SUCCESS; switch(attribute) { - case EGL_CONFIG_ID: *value = (EGLint)EMSCRIPTEN_EGL_MAGIC_ID_FOR_DEFAULT_CONFIG; return EGL_TRUE; + case EGL_CONFIG_ID: *value = (EGLint)eglCurrentInitializedConfig; return EGL_TRUE; case EGL_CONTEXT_CLIENT_TYPE: *value = EGL_OPENGL_ES_API; return EGL_TRUE; case EGL_CONTEXT_CLIENT_VERSION: *value = 2; return EGL_TRUE; case EGL_RENDER_BUFFER: *value = EGL_BACK_BUFFER; return EGL_TRUE; @@ -547,6 +596,7 @@ EGLAPI EGLBoolean EGLAPIENTRY eglSwapBuffers(EGLDisplay dpy, EGLSurface surface) } EMSCRIPTEN_RESULT res = emscripten_webgl_commit_frame(); +#if 0 if (res >= 0) { eglError = EGL_SUCCESS; @@ -554,6 +604,10 @@ EGLAPI EGLBoolean EGLAPIENTRY eglSwapBuffers(EGLDisplay dpy, EGLSurface surface) } eglError = EGL_BAD_ACCESS; return EGL_FALSE; +#else + eglError = EGL_SUCCESS; + return EGL_TRUE; +#endif } EGLAPI EGLBoolean EGLAPIENTRY eglCopyBuffers(EGLDisplay dpy, EGLSurface surface, EGLNativePixmapType target) From 12e65c09488ec01f3ae0c50891f09053356c96fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Tue, 17 Oct 2017 18:58:03 +0300 Subject: [PATCH 3/3] Add filtering in eglChooseConfig --- system/lib/egl/library_egl.c | 38 +++++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/system/lib/egl/library_egl.c b/system/lib/egl/library_egl.c index 6c60d3c937387..d491169d11c0a 100644 --- a/system/lib/egl/library_egl.c +++ b/system/lib/egl/library_egl.c @@ -112,7 +112,43 @@ static EGLBoolean ConfigPassesFilter(EGLConfig config, const EGLint *attrib_list { if (!attrib_list) return EGL_TRUE; - + while(*attrib_list) + { + EGLint key = *attrib_list++; + EGLint value = *attrib_list++; + switch(key) + { + //case EGL_BUFFER_SIZE: + //case EGL_RED_SIZE: + //case EGL_GREEN_SIZE: + //case EGL_BLUE_SIZE: + //case EGL_LUMINANCE_SIZE: + case EGL_ALPHA_SIZE: if (value > 0 && ((EGLint)config & EM_EGL_ALPHA_BIT) == 0) return EGL_FALSE; + //case EGL_ALPHA_MASK_SIZE: + //case EGL_BIND_TO_TEXTURE_RGB: + //case EGL_BIND_TO_TEXTURE_RGBA: + //case EGL_COLOR_BUFFER_TYPE: + //case EGL_CONFIG_CAVEAT: + //case EGL_CONFIG_ID: + //case EGL_CONFORMANT: + case EGL_DEPTH_SIZE: if (value > 0 && ((EGLint)config & EM_EGL_DEPTH_BIT) == 0) return EGL_FALSE; + //case EGL_LEVEL: + //case EGL_MATCH_NATIVE_PIXMAP: + //case EGL_MAX_SWAP_INTERVAL: + //case EGL_MIN_SWAP_INTERVAL: + //case EGL_NATIVE_RENDERABLE: + //case EGL_NATIVE_VISUAL_TYPE: + //case EGL_RENDERABLE_TYPE: + case EGL_SAMPLE_BUFFERS: if (value > 0 && ((EGLint)config & EM_EGL_ANTIALIAS_BIT) == 0) return EGL_FALSE; + case EGL_SAMPLES: if (value > 0 && ((EGLint)config & EM_EGL_ANTIALIAS_BIT) == 0) return EGL_FALSE; + case EGL_STENCIL_SIZE: if (value > 0 && ((EGLint)config & EM_EGL_STENCIL_BIT) == 0) return EGL_FALSE; + //case EGL_SURFACE_TYPE: + //case EGL_TRANSPARENT_TYPE: + //case EGL_TRANSPARENT_RED_VALUE: + //case EGL_TRANSPARENT_GREEN_VALUE: + //case EGL_TRANSPARENT_BLUE_VALUE: + } + } return EGL_TRUE; }