Skip to content

Commit

Permalink
Move *glGetProcAddress() functions behind a linker flag -sGL_ENABLE_G…
Browse files Browse the repository at this point in the history
…ET_PROC_ADDRESS=1
  • Loading branch information
juj committed Nov 29, 2023
1 parent 58cf85c commit ad4240f
Show file tree
Hide file tree
Showing 13 changed files with 377 additions and 33 deletions.
6 changes: 6 additions & 0 deletions ChangeLog.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,12 @@ See docs/process.md for more on how version tagging works.
some time now (at least not by default), and is much less useful these days
given lazy compilation in VMs (which makes it impossible to truly benchmark
execution separately from compilation, which `BENCHMARK` hoped to do).
- The `*glGetProcAddress()` family of functions is now gated behind a linker flag
-sGL_ENABLE_GET_PROC_ADDRESS=1. This prevents ports of native GL renderers
from later enabling "dormant" features if WebGL implementations gain new
WebGL extensions in the future. (#20802)
- Added support for WebGL extensions EXT_clip_control, EXT_depth_clamp,
EXT_polygon_offset_clamp and WEBGL_polygon_mode (#20802)

3.1.49 - 11/14/23
-----------------
Expand Down
15 changes: 10 additions & 5 deletions src/library_html5_webgl.js
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,9 @@ var LibraryHtml5WebGL = {
'$webgl_enable_WEBGL_draw_instanced_base_vertex_base_instance',
'$webgl_enable_WEBGL_multi_draw_instanced_base_vertex_base_instance',
#endif
'$webgl_enable_EXT_polygon_offset_clamp',
'$webgl_enable_EXT_clip_control',
'$webgl_enable_WEBGL_polygon_mode',
'$webgl_enable_WEBGL_multi_draw',
#endif
],
Expand Down Expand Up @@ -360,21 +363,23 @@ var LibraryHtml5WebGL = {
#endif

if (extString == 'WEBGL_multi_draw') webgl_enable_WEBGL_multi_draw(GLctx);
if (extString == 'EXT_polygon_offset_clamp') webgl_enable_EXT_polygon_offset_clamp(GLctx);
if (extString == 'EXT_clip_control') webgl_enable_EXT_clip_control(GLctx);
if (extString == 'WEBGL_polygon_mode') webgl_enable_WEBGL_polygon_mode(GLctx);

#else

#if ASSERTIONS || GL_ASSERTIONS
#elif ASSERTIONS || GL_ASSERTIONS
if (['ANGLE_instanced_arrays',
'OES_vertex_array_object',
'WEBGL_draw_buffers',
'WEBGL_multi_draw',
'EXT_polygon_offset_clamp',
'EXT_clip_control',
'WEBGL_polygon_mode',
'WEBGL_draw_instanced_base_vertex_base_instance',
'WEBGL_multi_draw_instanced_base_vertex_base_instance'].includes(extString)) {
err('When building with -sGL_SUPPORT_SIMPLE_ENABLE_EXTENSIONS=0, function emscripten_webgl_enable_extension() cannot be used to enable extension '
+ extString + '! Use one of the functions emscripten_webgl_enable_*() to enable it!');
}
#endif

#endif

var ext = context.GLctx.getExtension(extString);
Expand Down
119 changes: 115 additions & 4 deletions src/library_webgl.js
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,9 @@ for (/**@suppress{duplicate}*/var i = 0; i < {{{ GL_POOL_TEMP_BUFFERS_SIZE }}};
$webgl_enable_ANGLE_instanced_arrays: (ctx) => {
// Extension available in WebGL 1 from Firefox 26 and Google Chrome 30 onwards. Core feature in WebGL 2.
var ext = ctx.getExtension('ANGLE_instanced_arrays');
// Because this extension is a core function in WebGL 2, assign the extension entry points in place of
// where the core functions will reside in WebGL 2. This way the calling code can call these without
// having to dynamically branch depending if running against WebGL 1 or WebGL 2.
if (ext) {
ctx['vertexAttribDivisor'] = (index, divisor) => ext['vertexAttribDivisorANGLE'](index, divisor);
ctx['drawArraysInstanced'] = (mode, first, count, primcount) => ext['drawArraysInstancedANGLE'](mode, first, count, primcount);
Expand Down Expand Up @@ -135,6 +138,27 @@ for (/**@suppress{duplicate}*/var i = 0; i < {{{ GL_POOL_TEMP_BUFFERS_SIZE }}};
emscripten_webgl_enable_WEBGL_multi_draw__deps: ['$webgl_enable_WEBGL_multi_draw'],
emscripten_webgl_enable_WEBGL_multi_draw: (ctx) => webgl_enable_WEBGL_multi_draw(GL.contexts[ctx].GLctx),

$webgl_enable_EXT_polygon_offset_clamp: (ctx) => {
return !!(ctx.extPolygonOffsetClamp = ctx.getExtension('EXT_polygon_offset_clamp'));
},

emscripten_webgl_enable_EXT_polygon_offset_clamp__deps: ['$webgl_enable_EXT_polygon_offset_clamp'],
emscripten_webgl_enable_EXT_polygon_offset_clamp: (ctx) => webgl_enable_EXT_polygon_offset_clamp(GL.contexts[ctx].GLctx),

$webgl_enable_EXT_clip_control: (ctx) => {
return !!(ctx.extClipControl = ctx.getExtension('EXT_clip_control'));
},

emscripten_webgl_enable_EXT_clip_control__deps: ['$webgl_enable_EXT_clip_control'],
emscripten_webgl_enable_EXT_clip_control: (ctx) => webgl_enable_EXT_clip_control(GL.contexts[ctx].GLctx),

$webgl_enable_WEBGL_polygon_mode: (ctx) => {
return !!(ctx.webglPolygonMode = ctx.getExtension('WEBGL_polygon_mode'));
},

emscripten_webgl_enable_WEBGL_polygon_mode__deps: ['$webgl_enable_WEBGL_polygon_mode'],
emscripten_webgl_enable_WEBGL_polygon_mode: (ctx) => webgl_enable_WEBGL_polygon_mode(GL.contexts[ctx].GLctx),

$GL__postset: 'var GLctx;',
#if GL_SUPPORT_AUTOMATIC_ENABLE_EXTENSIONS
// If GL_SUPPORT_AUTOMATIC_ENABLE_EXTENSIONS is enabled, GL.initExtensions() will call to initialize these.
Expand All @@ -152,6 +176,9 @@ for (/**@suppress{duplicate}*/var i = 0; i < {{{ GL_POOL_TEMP_BUFFERS_SIZE }}};
'$webgl_enable_WEBGL_draw_instanced_base_vertex_base_instance',
'$webgl_enable_WEBGL_multi_draw_instanced_base_vertex_base_instance',
#endif
'$webgl_enable_EXT_polygon_offset_clamp',
'$webgl_enable_EXT_clip_control',
'$webgl_enable_WEBGL_polygon_mode',
'$webgl_enable_WEBGL_multi_draw',
],
#endif
Expand Down Expand Up @@ -739,6 +766,65 @@ 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
ctx._allSupportedExtensions = ctx.getSupportedExtensions;
const 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',
'OES_draw_buffers_indexed',
'OVR_multiview2',
'WEBGL_clip_cull_distance',
'WEBGL_provoking_vertex',
#endif
// WebGL 1 and WebGL 2 extensions
'EXT_clip_control',
'EXT_color_buffer_half_float',
'EXT_depth_clamp',
'EXT_float_blend',
'EXT_polygon_offset_clamp',
'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',
'WEBGL_polygon_mode'
];
ctx.getSupportedExtensions = () => {
return (this._allSupportedExtensions() || []).filter(ext => supportedExtensionsForGetProcAddress.includes(ext));
}
#endif

return handle;
},

Expand Down Expand Up @@ -1156,6 +1242,11 @@ for (/**@suppress{duplicate}*/var i = 0; i < {{{ GL_POOL_TEMP_BUFFERS_SIZE }}};
context.anisotropicExt = GLctx.getExtension('EXT_texture_filter_anisotropic');
#endif

// Extensions that are available in both WebGL 1 and WebGL 2
webgl_enable_WEBGL_multi_draw(GLctx);
webgl_enable_EXT_polygon_offset_clamp(GLctx);
webgl_enable_EXT_clip_control(GLctx);
webgl_enable_WEBGL_polygon_mode(GLctx);
#if MIN_WEBGL_VERSION == 1
// Extensions that are only available in WebGL 1 (the calls will be no-ops
// if called on a WebGL 2 context active)
Expand All @@ -1167,9 +1258,7 @@ for (/**@suppress{duplicate}*/var i = 0; i < {{{ GL_POOL_TEMP_BUFFERS_SIZE }}};
// Extensions that are available from WebGL >= 2 (no-op if called on a WebGL 1 context active)
webgl_enable_WEBGL_draw_instanced_base_vertex_base_instance(GLctx);
webgl_enable_WEBGL_multi_draw_instanced_base_vertex_base_instance(GLctx);
#endif

#if MAX_WEBGL_VERSION >= 2
// On WebGL 2, EXT_disjoint_timer_query is replaced with an alternative
// that's based on core APIs, and exposes only the queryCounterEXT()
// entrypoint.
Expand All @@ -1186,8 +1275,6 @@ for (/**@suppress{duplicate}*/var i = 0; i < {{{ GL_POOL_TEMP_BUFFERS_SIZE }}};
GLctx.disjointTimerQueryExt = GLctx.getExtension("EXT_disjoint_timer_query");
}

webgl_enable_WEBGL_multi_draw(GLctx);

// .getSupportedExtensions() can return null if context is lost, so coerce
// to empty array.
var exts = GLctx.getSupportedExtensions() || [];
Expand Down Expand Up @@ -4217,6 +4304,30 @@ for (/**@suppress{duplicate}*/var i = 0; i < {{{ GL_POOL_TEMP_BUFFERS_SIZE }}};
return 1;
},
#endif

glPolygonOffsetClampEXT__sig: 'vfff',
glPolygonOffsetClampEXT: (factor, units, clamp) => {
#if GL_ASSERTIONS
assert(GLctx.extPolygonOffsetClamp, "EXT_polygon_offset_clamp not supported, or not enabled. Before calling glPolygonOffsetClampEXT(), call emscripten_webgl_enable_EXT_polygon_offset_clamp() to enable this extension, and verify that it returns true to indicate support. (alternatively, build with -sGL_SUPPORT_AUTOMATIC_ENABLE_EXTENSIONS=1 to enable all GL extensions by default)");
#endif
GLctx.extPolygonOffsetClamp['polygonOffsetClampEXT'](factor, units, clamp);
},

glClipControlEXT__sig: 'vii',
glClipControlEXT: (origin, depth) => {
#if GL_ASSERTIONS
assert(GLctx.extClipControl, "EXT_clip_control not supported, or not enabled. Before calling glClipControlEXT(), call emscripten_webgl_enable_EXT_clip_control() to enable this extension, and verify that it returns true to indicate support. (alternatively, build with -sGL_SUPPORT_AUTOMATIC_ENABLE_EXTENSIONS=1 to enable all GL extensions by default)");
#endif
GLctx.extClipControl['clipControlEXT'](origin, depth);
},

glPolygonModeWEBGL__sig: 'vii',
glPolygonModeWEBGL: (face, mode) => {
#if GL_ASSERTIONS
assert(GLctx.webglPolygonMode, "WEBGL_polygon_mode not supported, or not enabled. Before calling glPolygonModeWEBGL(), call emscripten_webgl_enable_WEBGL_polygon_mode() to enable this extension, and verify that it returns true to indicate support. (alternatively, build with -sGL_SUPPORT_AUTOMATIC_ENABLE_EXTENSIONS=1 to enable all GL extensions by default)");
#endif
GLctx.webglPolygonMode['polygonModeWEBGL'](face, mode);
},
};

// Simple pass-through functions.
Expand Down
7 changes: 7 additions & 0 deletions src/settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
6 changes: 6 additions & 0 deletions system/include/emscripten/html5_webgl.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,12 @@ EM_BOOL emscripten_webgl_enable_WEBGL_multi_draw(EMSCRIPTEN_WEBGL_CONTEXT_HANDLE

EM_BOOL emscripten_webgl_enable_WEBGL_multi_draw_instanced_base_vertex_base_instance(EMSCRIPTEN_WEBGL_CONTEXT_HANDLE context);

EM_BOOL emscripten_webgl_enable_EXT_polygon_offset_clamp(EMSCRIPTEN_WEBGL_CONTEXT_HANDLE context);

EM_BOOL emscripten_webgl_enable_EXT_clip_control(EMSCRIPTEN_WEBGL_CONTEXT_HANDLE context);

EM_BOOL emscripten_webgl_enable_WEBGL_polygon_mode(EMSCRIPTEN_WEBGL_CONTEXT_HANDLE context);

typedef EM_BOOL (*em_webgl_context_callback)(int eventType, const void *reserved, void *userData);
EMSCRIPTEN_RESULT emscripten_set_webglcontextlost_callback_on_thread(const char *target __attribute__((nonnull)), void *userData, EM_BOOL useCapture, em_webgl_context_callback callback, pthread_t targetThread);
EMSCRIPTEN_RESULT emscripten_set_webglcontextrestored_callback_on_thread(const char *target __attribute__((nonnull)), void *userData, EM_BOOL useCapture, em_webgl_context_callback callback, pthread_t targetThread);
Expand Down
Loading

0 comments on commit ad4240f

Please sign in to comment.