From fa94c64e0fcf3d8b7836b373ef1de989b852b87a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Thu, 30 Nov 2023 12:49:47 +0200 Subject: [PATCH] Gate *glGetProcAddress() functions behind a linker flag -sGL_ENABLE_GET_PROC_ADDRESS=1 so that we can restrict new GL extensions from being advertised in the future that *glGetProcAddress() cannot support. --- ChangeLog.md | 5 +++ embuilder.py | 1 + emcc.py | 5 +++ src/library_exceptions_stub.js | 2 +- src/library_sigs.js | 6 +++ src/library_webgl.js | 73 ++++++++++++++++++++++++++++++++++ src/settings.js | 7 ++++ system/lib/gl/gl.c | 4 ++ system/lib/gl/libprocaddr.c | 4 ++ system/lib/gl/webgl1.c | 4 ++ system/lib/gl/webgl2.c | 8 ++++ test/test_browser.py | 26 ++++++------ test/test_core.py | 1 + test/test_other.py | 15 +++++-- tools/settings.py | 3 ++ tools/system_libs.py | 17 ++++---- 16 files changed, 155 insertions(+), 26 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index 36ad0c40d9b8f..6d439988642c7 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -45,6 +45,11 @@ See docs/process.md for more on how version tagging works. - Update GLFW handling of touch events to avoid sending duplicate mousedown and and mouseup events. Maps touchmove to mousemove events for a single primary touch. (#20805) +- Breaking change: Using the `*glGetProcAddress()` family of functions now + requires passing a linker flag -sGL_ENABLE_GET_PROC_ADDRESS. This prevents + ports of native GL renderers from later accidentally attempting to activate + "dormant" features if web browser implementations gain new WebGL extensions in + the future, which `*glGetProcAddress()` is not able to support. (#20802) 3.1.49 - 11/14/23 ----------------- diff --git a/embuilder.py b/embuilder.py index 09ab396bbca68..bc674957cdb34 100755 --- a/embuilder.py +++ b/embuilder.py @@ -59,6 +59,7 @@ 'libmimalloc', 'libmimalloc-mt', 'libGL', + 'libGL-getprocaddr', 'libhtml5', 'libsockets', 'libstubs', diff --git a/emcc.py b/emcc.py index 279f6d4d9c045..f690895d27680 100644 --- a/emcc.py +++ b/emcc.py @@ -935,6 +935,11 @@ def phase_setup(options, state, newargs): else: settings.SUPPORT_LONGJMP = 'emscripten' + # SDL2 requires eglGetProcAddress() to work. + # NOTE: if SDL2 is updated to not rely on eglGetProcAddress(), this can be removed + if settings.USE_SDL == 2 or settings.USE_SDL_MIXER == 2 or settings.USE_SDL_GFX == 2: + default_setting('GL_ENABLE_GET_PROC_ADDRESS', 1) + return (newargs, input_files) diff --git a/src/library_exceptions_stub.js b/src/library_exceptions_stub.js index 5732ce3141173..37dfbd30ba72d 100644 --- a/src/library_exceptions_stub.js +++ b/src/library_exceptions_stub.js @@ -22,7 +22,7 @@ var LibraryExceptions = {}; ].forEach(function(name) { LibraryExceptions[name] = function() { abort(); }; #if !INCLUDE_FULL_LIBRARY - // This method of link-time error genertation is not compatible with INCLUDE_FULL_LIBRARY + // This method of link-time error generation is not compatible with INCLUDE_FULL_LIBRARY LibraryExceptions[name + '__deps'] = [function() { error(`DISABLE_EXCEPTION_THROWING was set (likely due to -fno-exceptions), which means no C++ exception throwing support code is linked in, but such support is required by symbol '${name}'. Either do not set DISABLE_EXCEPTION_THROWING (if you do want exception throwing) or compile all source files with -fno-except (so that no exceptions support code is required); also make sure DISABLE_EXCEPTION_CATCHING is set to the right value - if you want exceptions, it should be off, and vice versa.`); }]; diff --git a/src/library_sigs.js b/src/library_sigs.js index 8a543bec40021..b23759ca63e30 100644 --- a/src/library_sigs.js +++ b/src/library_sigs.js @@ -76,6 +76,7 @@ sigs = { SDL_GL_DeleteContext__sig: 'vp', SDL_GL_ExtensionSupported__sig: 'ip', SDL_GL_GetAttribute__sig: 'iip', + SDL_GL_GetProcAddress__sig: 'pp', SDL_GL_GetSwapInterval__sig: 'i', SDL_GL_MakeCurrent__sig: 'ipp', SDL_GL_SetAttribute__sig: 'iii', @@ -547,6 +548,7 @@ sigs = { eglGetCurrentSurface__sig: 'pi', eglGetDisplay__sig: 'pp', eglGetError__sig: 'i', + eglGetProcAddress__sig: 'pp', eglInitialize__sig: 'ippp', eglMakeCurrent__sig: 'ipppp', eglQueryAPI__sig: 'i', @@ -849,6 +851,8 @@ sigs = { emscripten_wasm_worker_post_function_vii__sig: 'vipii', emscripten_wasm_worker_post_function_viii__sig: 'vipiii', emscripten_wasm_worker_self_id__sig: 'i', + emscripten_webgl1_get_proc_address__sig: 'pp', + emscripten_webgl2_get_proc_address__sig: 'pp', emscripten_webgl_commit_frame__sig: 'i', emscripten_webgl_create_context__sig: 'ppp', emscripten_webgl_destroy_context__sig: 'ip', @@ -870,6 +874,7 @@ sigs = { emscripten_webgl_get_parameter_o__sig: 'ii', emscripten_webgl_get_parameter_utf8__sig: 'pi', emscripten_webgl_get_parameter_v__sig: 'iipii', + emscripten_webgl_get_proc_address__sig: 'pp', emscripten_webgl_get_program_info_log_utf8__sig: 'pi', emscripten_webgl_get_program_parameter_d__sig: 'dii', emscripten_webgl_get_shader_info_log_utf8__sig: 'pi', @@ -1387,6 +1392,7 @@ sigs = { glfwGetMouseWheel__sig: 'i', glfwGetNumberOfProcessors__sig: 'i', glfwGetPrimaryMonitor__sig: 'p', + glfwGetProcAddress__sig: 'pp', glfwGetRequiredInstanceExtensions__sig: 'pp', glfwGetThreadID__sig: 'i', glfwGetTime__sig: 'd', diff --git a/src/library_webgl.js b/src/library_webgl.js index cfde53ce6732d..4e43fff676ea6 100644 --- a/src/library_webgl.js +++ b/src/library_webgl.js @@ -739,6 +739,58 @@ for (/**@suppress{duplicate}*/var i = 0; i < {{{ GL_POOL_TEMP_BUFFERS_SIZE }}}; disableHalfFloatExtensionIfBroken(ctx); #endif + // If end user enables *glGetProcAddress() functionality, then we must filter out + // all future WebGL extensions from being passed to the user, and only restrict to advertising + // extensions that the *glGetProcAddress() function knows to handle. +#if GL_ENABLE_GET_PROC_ADDRESS + var _allSupportedExtensions = ctx.getSupportedExtensions; + var supportedExtensionsForGetProcAddress = [ +#if MIN_WEBGL_VERSION == 1 + // WebGL 1 extensions + 'ANGLE_instanced_arrays', + 'EXT_blend_minmax', + 'EXT_disjoint_timer_query', + 'EXT_frag_depth', + 'EXT_shader_texture_lod', + 'EXT_sRGB', + 'OES_element_index_uint', + 'OES_fbo_render_mipmap', + 'OES_standard_derivatives', + 'OES_texture_float', + 'OES_texture_half_float', + 'OES_texture_half_float_linear', + 'OES_vertex_array_object', + 'WEBGL_color_buffer_float', + 'WEBGL_depth_texture', + 'WEBGL_draw_buffers', +#endif +#if MAX_WEBGL_VERSION >= 2 + // WebGL 2 extensions + 'EXT_color_buffer_float', + 'EXT_disjoint_timer_query_webgl2', + 'EXT_texture_norm16', + 'WEBGL_clip_cull_distance', +#endif + // WebGL 1 and WebGL 2 extensions + 'EXT_color_buffer_half_float', + 'EXT_float_blend', + 'EXT_texture_compression_bptc', + 'EXT_texture_compression_rgtc', + 'EXT_texture_filter_anisotropic', + 'KHR_parallel_shader_compile', + 'OES_texture_float_linear', + 'WEBGL_compressed_texture_s3tc', + 'WEBGL_compressed_texture_s3tc_srgb', + 'WEBGL_debug_renderer_info', + 'WEBGL_debug_shaders', + 'WEBGL_lose_context', + 'WEBGL_multi_draw', + ]; + ctx.getSupportedExtensions = function() { + return (_allSupportedExtensions.apply(this) || []).filter(ext => supportedExtensionsForGetProcAddress.includes(ext)); + } +#endif + return handle; }, @@ -4219,6 +4271,27 @@ for (/**@suppress{duplicate}*/var i = 0; i < {{{ GL_POOL_TEMP_BUFFERS_SIZE }}}; #endif }; +#if !GL_ENABLE_GET_PROC_ADDRESS +[ + 'emscripten_webgl1_get_proc_address', + 'emscripten_webgl2_get_proc_address', + 'emscripten_webgl_get_proc_address', + 'SDL_GL_GetProcAddress', + 'eglGetProcAddress', + 'glfwGetProcAddress' +].forEach(function(name) { + LibraryGL[name] = function(name) { abort(); return 0; }; + // Due to the two pass nature of compiling .js files, + // in INCLUDE_FULL_LIBRARY mode, we must include the above + // stub functions, but not their __deps message handlers. +#if !INCLUDE_FULL_LIBRARY + LibraryGL[name + '__deps'] = [function() { + error(`linker: Undefined symbol: ${name}(). Please pass -sGL_ENABLE_GET_PROC_ADDRESS at link time to link in ${name}().`); + }]; +#endif +}); +#endif + // Simple pass-through functions. // - Starred ones have return values. // - [X] ones have X in the C name but not in the JS name diff --git a/src/settings.js b/src/settings.js index 910f48bd320c6..5e8392e4355de 100644 --- a/src/settings.js +++ b/src/settings.js @@ -589,6 +589,13 @@ var GL_DISABLE_HALF_FLOAT_EXTENSION_IF_BROKEN = false; // Set this to 0 to force-disable the workaround if you know the issue will not affect you. var GL_WORKAROUND_SAFARI_GETCONTEXT_BUG = true; +// If 1, link with support to *glGetProcAddress() functionality. +// In WebGL, *glGetProcAddress() causes a substantial code size and performance impact, since WebGL +// does not natively provide such functionality, and it must be emulated. Using *glGetProcAddress() +// is not recommended. If you still need to use this, e.g. when porting an existing renderer, +// you can link with -sGL_ENABLE_GET_PROC_ADDRESS=1 to get support for this functionality. +var GL_ENABLE_GET_PROC_ADDRESS = false; + // Use JavaScript math functions like Math.tan. This saves code size as we can avoid shipping // compiled musl code. However, it can be significantly slower as it calls out to JS. It // also may give different results as JS math is specced somewhat differently than libc, and diff --git a/system/lib/gl/gl.c b/system/lib/gl/gl.c index 39312ad58d577..13dfe170bd412 100644 --- a/system/lib/gl/gl.c +++ b/system/lib/gl/gl.c @@ -1569,6 +1569,8 @@ GLAPI void APIENTRY emscripten_glGetObjectParameteriv (GLhandleARB obj, GLenum p GLAPI void APIENTRY emscripten_glGetInfoLog (GLhandleARB obj, GLsizei maxLength, GLsizei *length, GLcharARB *infoLog); GLAPI void APIENTRY emscripten_glBindProgram (GLenum target, GLuint program); +#if GL_ENABLE_GET_PROC_ADDRESS + extern void *emscripten_webgl1_get_proc_address(const char *name); extern void *_webgl1_match_ext_proc_address_without_suffix(const char *name); extern void *emscripten_webgl2_get_proc_address(const char *name); @@ -1837,3 +1839,5 @@ extern void *emscripten_webgl_get_proc_address(const char *name) #endif return ptr; } + +#endif diff --git a/system/lib/gl/libprocaddr.c b/system/lib/gl/libprocaddr.c index b753dc8040763..45b0360bf4bdd 100644 --- a/system/lib/gl/libprocaddr.c +++ b/system/lib/gl/libprocaddr.c @@ -7,6 +7,8 @@ // GL proc address library integration +#if GL_ENABLE_GET_PROC_ADDRESS + extern void* emscripten_GetProcAddress(const char *name); __attribute__((weak)) // SDL2 will link in its own version of this @@ -21,3 +23,5 @@ void* eglGetProcAddress(const char* name) { void* glfwGetProcAddress(const char* name) { return emscripten_GetProcAddress(name); } + +#endif diff --git a/system/lib/gl/webgl1.c b/system/lib/gl/webgl1.c index 78afe29c23707..85e8cc392423d 100644 --- a/system/lib/gl/webgl1.c +++ b/system/lib/gl/webgl1.c @@ -579,6 +579,8 @@ RET_SYNC_GL_FUNCTION_3(EM_FUNC_SIG_VIII, void, glGetQueryObjectui64vEXT, GLenum, #endif // ~(__EMSCRIPTEN_PTHREADS__ && __EMSCRIPTEN_OFFSCREEN_FRAMEBUFFER__) +#if GL_ENABLE_GET_PROC_ADDRESS + // Returns a function pointer to the given WebGL 1 extension function, when queried without // a GL extension suffix such as "EXT", "OES", or "ANGLE". This function is used by // emscripten_GetProcAddress() to implement legacy GL emulation semantics for portability. @@ -797,3 +799,5 @@ void *emscripten_webgl1_get_proc_address(const char *name) { return 0; } + +#endif diff --git a/system/lib/gl/webgl2.c b/system/lib/gl/webgl2.c index 1362475437f72..e9790508ae438 100644 --- a/system/lib/gl/webgl2.c +++ b/system/lib/gl/webgl2.c @@ -4,6 +4,8 @@ * University of Illinois/NCSA Open Source License. Both these licenses can be * found in the LICENSE file. */ +#if defined(__EMSCRIPTEN_FULL_ES3__) || MAX_WEBGL_VERSION >= 2 + #include #include #include @@ -162,6 +164,8 @@ GL_APICALL void GL_APIENTRY glDrawBuffersWEBGL(GLsizei n, const GLenum *bufs) { #endif // ~__EMSCRIPTEN_PTHREADS__) && __EMSCRIPTEN_OFFSCREEN_FRAMEBUFFER__ +#if GL_ENABLE_GET_PROC_ADDRESS + // Returns a function pointer to the given WebGL 2 extension function, when queried without // a GL extension suffix such as "EXT", "OES", or "ANGLE". This function is used by // emscripten_GetProcAddress() to implement legacy GL emulation semantics for portability. @@ -319,3 +323,7 @@ void *emscripten_webgl2_get_proc_address(const char *name) { return 0; } + +#endif // GL_ENABLE_GET_PROC_ADDRESS + +#endif // defined(__EMSCRIPTEN_FULL_ES3__) || MAX_WEBGL_VERSION >= 2 diff --git a/test/test_browser.py b/test/test_browser.py index a5a56bd0dc319..4d90240471cde 100644 --- a/test/test_browser.py +++ b/test/test_browser.py @@ -1329,7 +1329,7 @@ def test_webgl_context_attributes(self): self.btest_exit('test_webgl_context_attributes_glut.c', args=['--js-library', 'check_webgl_attributes_support.js', '-DAA_ACTIVATED', '-DDEPTH_ACTIVATED', '-DSTENCIL_ACTIVATED', '-DALPHA_ACTIVATED', '-lGL', '-lglut', '-lGLEW']) self.btest_exit('test_webgl_context_attributes_sdl.c', args=['--js-library', 'check_webgl_attributes_support.js', '-DAA_ACTIVATED', '-DDEPTH_ACTIVATED', '-DSTENCIL_ACTIVATED', '-DALPHA_ACTIVATED', '-lGL', '-lSDL', '-lGLEW']) if not self.is_wasm64(): - self.btest_exit('test_webgl_context_attributes_sdl2.c', args=['--js-library', 'check_webgl_attributes_support.js', '-DAA_ACTIVATED', '-DDEPTH_ACTIVATED', '-DSTENCIL_ACTIVATED', '-DALPHA_ACTIVATED', '-lGL', '-sUSE_SDL=2', '-lGLEW']) + self.btest_exit('test_webgl_context_attributes_sdl2.c', args=['--js-library', 'check_webgl_attributes_support.js', '-DAA_ACTIVATED', '-DDEPTH_ACTIVATED', '-DSTENCIL_ACTIVATED', '-DALPHA_ACTIVATED', '-lGL', '-sUSE_SDL=2', '-lGLEW', '-sGL_ENABLE_GET_PROC_ADDRESS=1']) self.btest_exit('test_webgl_context_attributes_glfw.c', args=['--js-library', 'check_webgl_attributes_support.js', '-DAA_ACTIVATED', '-DDEPTH_ACTIVATED', '-DSTENCIL_ACTIVATED', '-DALPHA_ACTIVATED', '-lGL', '-lglfw', '-lGLEW']) # perform tests with attributes desactivated @@ -1584,7 +1584,7 @@ def test_sdl_ogl_p(self): def test_sdl_ogl_proc_alias(self): shutil.copyfile(test_file('screenshot.png'), 'screenshot.png') self.btest('test_sdl_ogl_proc_alias.c', reference='screenshot-gray-purple.png', reference_slack=1, - args=['-O2', '-g2', '-sINLINING_LIMIT', '--preload-file', 'screenshot.png', '-sLEGACY_GL_EMULATION', '--use-preload-plugins', '-lSDL', '-lGL']) + args=['-O2', '-g2', '-sINLINING_LIMIT', '--preload-file', 'screenshot.png', '-sLEGACY_GL_EMULATION', '-sGL_ENABLE_GET_PROC_ADDRESS', '--use-preload-plugins', '-lSDL', '-lGL']) @requires_graphics_hardware def test_sdl_fog_simple(self): @@ -1619,11 +1619,11 @@ def test_sdl_fog_linear(self): @requires_graphics_hardware def test_glfw(self): # Using only the `-l` flag - self.btest_exit('test_glfw.c', args=['-sLEGACY_GL_EMULATION', '-lglfw', '-lGL']) + self.btest_exit('test_glfw.c', args=['-sLEGACY_GL_EMULATION', '-lglfw', '-lGL', '-sGL_ENABLE_GET_PROC_ADDRESS']) # Using only the `-s` flag - self.btest_exit('test_glfw.c', args=['-sLEGACY_GL_EMULATION', '-sUSE_GLFW=2', '-lGL']) + self.btest_exit('test_glfw.c', args=['-sLEGACY_GL_EMULATION', '-sUSE_GLFW=2', '-lGL', '-sGL_ENABLE_GET_PROC_ADDRESS']) # Using both `-s` and `-l` flags - self.btest_exit('test_glfw.c', args=['-sLEGACY_GL_EMULATION', '-sUSE_GLFW=2', '-lglfw', '-lGL']) + self.btest_exit('test_glfw.c', args=['-sLEGACY_GL_EMULATION', '-sUSE_GLFW=2', '-lglfw', '-lGL', '-sGL_ENABLE_GET_PROC_ADDRESS']) def test_glfw_minimal(self): self.btest_exit('test_glfw_minimal.c', args=['-lglfw', '-lGL']) @@ -1633,7 +1633,7 @@ def test_glfw_time(self): self.btest_exit('test_glfw_time.c', args=['-sUSE_GLFW=3', '-lglfw', '-lGL']) def _test_egl_base(self, *args): - self.btest_exit('test_egl.c', args=['-O2', '-lEGL', '-lGL'] + list(args)) + self.btest_exit('test_egl.c', args=['-O2', '-lEGL', '-lGL', '-sGL_ENABLE_GET_PROC_ADDRESS'] + list(args)) @requires_graphics_hardware def test_egl(self): @@ -1815,7 +1815,7 @@ def test_glgears_animation(self): @requires_graphics_hardware def test_fulles2_sdlproc(self): - self.btest_exit('full_es2_sdlproc.c', assert_returncode=1, args=['-sGL_TESTING', '-DHAVE_BUILTIN_SINCOS', '-sFULL_ES2', '-lGL', '-lSDL', '-lglut']) + self.btest_exit('full_es2_sdlproc.c', assert_returncode=1, args=['-sGL_TESTING', '-DHAVE_BUILTIN_SINCOS', '-sFULL_ES2', '-lGL', '-lSDL', '-lglut', '-sGL_ENABLE_GET_PROC_ADDRESS']) @requires_graphics_hardware def test_glgears_deriv(self): @@ -1998,12 +1998,12 @@ def test_glframebufferattachmentinfo(self): @no_wasm64('TODO: LEGACY_GL_EMULATION + wasm64') @requires_graphics_hardware def test_sdl_glshader(self): - self.btest('test_sdl_glshader.c', reference='browser/test_sdl_glshader.png', args=['-O2', '--closure=1', '-sLEGACY_GL_EMULATION', '-lGL', '-lSDL']) + self.btest('test_sdl_glshader.c', reference='browser/test_sdl_glshader.png', args=['-O2', '--closure=1', '-sLEGACY_GL_EMULATION', '-lGL', '-lSDL', '-sGL_ENABLE_GET_PROC_ADDRESS']) @no_wasm64('TODO: LEGACY_GL_EMULATION + wasm64') @requires_graphics_hardware def test_sdl_glshader2(self): - self.btest_exit('test_sdl_glshader2.c', args=['-sLEGACY_GL_EMULATION', '-lGL', '-lSDL'], also_proxied=True) + self.btest_exit('test_sdl_glshader2.c', args=['-sLEGACY_GL_EMULATION', '-lGL', '-lSDL', '-sGL_ENABLE_GET_PROC_ADDRESS'], also_proxied=True) @requires_graphics_hardware def test_gl_glteximage(self): @@ -2145,7 +2145,7 @@ def test_cubegeom_proc(self, opts): return glBindBuffer; } ''') - self.btest('third_party/cubegeom/cubegeom_proc.c', reference='third_party/cubegeom/cubegeom.png', args=opts + ['side.c', '-sLEGACY_GL_EMULATION', '-lGL', '-lSDL']) + self.btest('third_party/cubegeom/cubegeom_proc.c', reference='third_party/cubegeom/cubegeom.png', args=opts + ['side.c', '-sLEGACY_GL_EMULATION', '-lGL', '-lSDL', '-sGL_ENABLE_GET_PROC_ADDRESS']) @no_wasm64('wasm64 + LEGACY_GL_EMULATION') @also_with_wasmfs @@ -2225,12 +2225,12 @@ def test_cubegeom_pre_vao_regal(self): @requires_graphics_hardware @no_swiftshader def test_cubegeom_pre2_vao(self): - self.btest('third_party/cubegeom/cubegeom_pre2_vao.c', reference='third_party/cubegeom/cubegeom_pre_vao.png', args=['-sLEGACY_GL_EMULATION', '-lGL', '-lSDL']) + self.btest('third_party/cubegeom/cubegeom_pre2_vao.c', reference='third_party/cubegeom/cubegeom_pre_vao.png', args=['-sLEGACY_GL_EMULATION', '-lGL', '-lSDL', '-sGL_ENABLE_GET_PROC_ADDRESS']) @no_wasm64('wasm64 + LEGACY_GL_EMULATION') @requires_graphics_hardware def test_cubegeom_pre2_vao2(self): - self.btest('third_party/cubegeom/cubegeom_pre2_vao2.c', reference='third_party/cubegeom/cubegeom_pre2_vao2.png', args=['-sLEGACY_GL_EMULATION', '-lGL', '-lSDL']) + self.btest('third_party/cubegeom/cubegeom_pre2_vao2.c', reference='third_party/cubegeom/cubegeom_pre2_vao2.png', args=['-sLEGACY_GL_EMULATION', '-lGL', '-lSDL', '-sGL_ENABLE_GET_PROC_ADDRESS']) @no_wasm64('wasm64 + LEGACY_GL_EMULATION') @requires_graphics_hardware @@ -3002,7 +3002,7 @@ def in_html(expected): @requires_graphics_hardware @parameterized({ 'no_gl': (['-DCLIENT_API=GLFW_NO_API'],), - 'gl_es': (['-DCLIENT_API=GLFW_OPENGL_ES_API'],) + 'gl_es': (['-DCLIENT_API=GLFW_OPENGL_ES_API', '-sGL_ENABLE_GET_PROC_ADDRESS'],) }) def test_glfw3(self, args): for opts in [[], ['-sLEGACY_GL_EMULATION'], ['-Os', '--closure=1']]: diff --git a/test/test_core.py b/test/test_core.py index 012c77ac7d614..44f1a5d0c7de0 100644 --- a/test/test_core.py +++ b/test/test_core.py @@ -9870,6 +9870,7 @@ def test_abort_on_exceptions_pthreads(self): @needs_dylink def test_gl_main_module(self): self.set_setting('MAIN_MODULE') + self.emcc_args += ['-sGL_ENABLE_GET_PROC_ADDRESS'] self.do_runf('core/test_gl_get_proc_address.c') @needs_dylink diff --git a/test/test_other.py b/test/test_other.py index 3208d72661286..3d6fcd10718fa 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -2416,7 +2416,7 @@ def test_undefined_symbols(self, action): delete_file('a.out.js') print('checking "%s" %s' % (args, value)) extra = ['-s', action + '_ON_UNDEFINED_SYMBOLS=%d' % value] if action else [] - proc = self.run_process([EMCC, '-sUSE_SDL', 'main.c'] + extra + args, stderr=PIPE, check=False) + proc = self.run_process([EMCC, '-sUSE_SDL', '-sGL_ENABLE_GET_PROC_ADDRESS', 'main.c'] + extra + args, stderr=PIPE, check=False) if common.EMTEST_VERBOSE: print(proc.stderr) if value or action is None: @@ -2460,9 +2460,16 @@ def test_undefined_data_symbols(self): def test_GetProcAddress_LEGACY_GL_EMULATION(self): # without legacy gl emulation, getting a proc from there should fail - self.do_other_test('test_GetProcAddress_LEGACY_GL_EMULATION.cpp', args=['0'], emcc_args=['-sLEGACY_GL_EMULATION=0']) + self.do_other_test('test_GetProcAddress_LEGACY_GL_EMULATION.cpp', args=['0'], emcc_args=['-sLEGACY_GL_EMULATION=0', '-sGL_ENABLE_GET_PROC_ADDRESS']) # with it, it should work - self.do_other_test('test_GetProcAddress_LEGACY_GL_EMULATION.cpp', args=['1'], emcc_args=['-sLEGACY_GL_EMULATION']) + self.do_other_test('test_GetProcAddress_LEGACY_GL_EMULATION.cpp', args=['1'], emcc_args=['-sLEGACY_GL_EMULATION', '-sGL_ENABLE_GET_PROC_ADDRESS']) + + # Verifies that is user is building without -sGL_ENABLE_GET_PROC_ADDRESS, then + # at link time they should get a helpful error message guiding them to enable + # the option. + def test_get_proc_address_error_message(self): + err = self.expect_fail([EMCC, test_file('other/test_GetProcAddress_LEGACY_GL_EMULATION.cpp')]) + self.assertContained('error: linker: Undefined symbol: SDL_GL_GetProcAddress(). Please pass -sGL_ENABLE_GET_PROC_ADDRESS at link time to link in SDL_GL_GetProcAddress().', err) def test_prepost(self): create_file('main.c', ''' @@ -12608,7 +12615,7 @@ def test_explicit_gl_linking(self): # Test that libGL can be linked explicitly via `-lGL` rather than implicitly. # Here we use NO_AUTO_NATIVE_LIBRARIES to disable the implicitly linking that normally # includes the native GL library. - self.run_process([EMCC, test_file('other/test_explicit_gl_linking.c'), '-sNO_AUTO_NATIVE_LIBRARIES', '-lGL']) + self.run_process([EMCC, test_file('other/test_explicit_gl_linking.c'), '-sNO_AUTO_NATIVE_LIBRARIES', '-lGL', '-sGL_ENABLE_GET_PROC_ADDRESS']) def test_no_main_with_PROXY_TO_PTHREAD(self): create_file('lib.c', r''' diff --git a/tools/settings.py b/tools/settings.py index a67f23998a8b9..4c9c885fc0aeb 100644 --- a/tools/settings.py +++ b/tools/settings.py @@ -81,6 +81,9 @@ 'OPT_LEVEL', 'DEBUG_LEVEL', + # Affects ports + 'GL_ENABLE_GET_PROC_ADDRESS', # NOTE: if SDL2 is updated to not rely on eglGetProcAddress(), this can be removed + # This is legacy setting that we happen to handle very early on 'RUNTIME_LINKED_LIBS', }.union(PORTS_SETTINGS) diff --git a/tools/system_libs.py b/tools/system_libs.py index fabefb0b62d63..e57043eb04141 100644 --- a/tools/system_libs.py +++ b/tools/system_libs.py @@ -1780,7 +1780,7 @@ class libGL(MTLibrary): name = 'libGL' src_dir = 'system/lib/gl' - src_files = ['gl.c', 'webgl1.c', 'libprocaddr.c'] + src_files = ['gl.c', 'webgl1.c', 'libprocaddr.c', 'webgl2.c'] cflags = ['-Oz', '-fno-inline-functions'] @@ -1789,10 +1789,7 @@ def __init__(self, **kwargs): self.is_webgl2 = kwargs.pop('is_webgl2') self.is_ofb = kwargs.pop('is_ofb') self.is_full_es3 = kwargs.pop('is_full_es3') - if self.is_webgl2 or self.is_full_es3: - # Don't use append or += here, otherwise we end up adding to - # the class member. - self.src_files = self.src_files + ['webgl2.c'] + self.is_enable_get_proc_address = kwargs.pop('is_enable_get_proc_address') super().__init__(**kwargs) def get_base_name(self): @@ -1805,23 +1802,26 @@ def get_base_name(self): name += '-ofb' if self.is_full_es3: name += '-full_es3' + if self.is_enable_get_proc_address: + name += '-getprocaddr' return name def get_cflags(self): cflags = super().get_cflags() if self.is_legacy: cflags += ['-DLEGACY_GL_EMULATION=1'] - if self.is_webgl2: - cflags += ['-DMAX_WEBGL_VERSION=2'] + cflags += [f'-DMAX_WEBGL_VERSION={2 if self.is_webgl2 else 1}'] if self.is_ofb: cflags += ['-D__EMSCRIPTEN_OFFSCREEN_FRAMEBUFFER__'] if self.is_full_es3: cflags += ['-D__EMSCRIPTEN_FULL_ES3__'] + if self.is_enable_get_proc_address: + cflags += ['-DGL_ENABLE_GET_PROC_ADDRESS=1'] return cflags @classmethod def vary_on(cls): - return super().vary_on() + ['is_legacy', 'is_webgl2', 'is_ofb', 'is_full_es3'] + return super().vary_on() + ['is_legacy', 'is_webgl2', 'is_ofb', 'is_full_es3', 'is_enable_get_proc_address'] @classmethod def get_default_variation(cls, **kwargs): @@ -1830,6 +1830,7 @@ def get_default_variation(cls, **kwargs): is_webgl2=settings.MAX_WEBGL_VERSION >= 2, is_ofb=settings.OFFSCREEN_FRAMEBUFFER, is_full_es3=settings.FULL_ES3, + is_enable_get_proc_address=settings.GL_ENABLE_GET_PROC_ADDRESS, **kwargs )