Skip to content

Commit ad4240f

Browse files
committed
Move *glGetProcAddress() functions behind a linker flag -sGL_ENABLE_GET_PROC_ADDRESS=1
1 parent 58cf85c commit ad4240f

File tree

13 files changed

+377
-33
lines changed

13 files changed

+377
-33
lines changed

ChangeLog.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,12 @@ See docs/process.md for more on how version tagging works.
3939
some time now (at least not by default), and is much less useful these days
4040
given lazy compilation in VMs (which makes it impossible to truly benchmark
4141
execution separately from compilation, which `BENCHMARK` hoped to do).
42+
- The `*glGetProcAddress()` family of functions is now gated behind a linker flag
43+
-sGL_ENABLE_GET_PROC_ADDRESS=1. This prevents ports of native GL renderers
44+
from later enabling "dormant" features if WebGL implementations gain new
45+
WebGL extensions in the future. (#20802)
46+
- Added support for WebGL extensions EXT_clip_control, EXT_depth_clamp,
47+
EXT_polygon_offset_clamp and WEBGL_polygon_mode (#20802)
4248

4349
3.1.49 - 11/14/23
4450
-----------------

src/library_html5_webgl.js

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -332,6 +332,9 @@ var LibraryHtml5WebGL = {
332332
'$webgl_enable_WEBGL_draw_instanced_base_vertex_base_instance',
333333
'$webgl_enable_WEBGL_multi_draw_instanced_base_vertex_base_instance',
334334
#endif
335+
'$webgl_enable_EXT_polygon_offset_clamp',
336+
'$webgl_enable_EXT_clip_control',
337+
'$webgl_enable_WEBGL_polygon_mode',
335338
'$webgl_enable_WEBGL_multi_draw',
336339
#endif
337340
],
@@ -360,21 +363,23 @@ var LibraryHtml5WebGL = {
360363
#endif
361364

362365
if (extString == 'WEBGL_multi_draw') webgl_enable_WEBGL_multi_draw(GLctx);
366+
if (extString == 'EXT_polygon_offset_clamp') webgl_enable_EXT_polygon_offset_clamp(GLctx);
367+
if (extString == 'EXT_clip_control') webgl_enable_EXT_clip_control(GLctx);
368+
if (extString == 'WEBGL_polygon_mode') webgl_enable_WEBGL_polygon_mode(GLctx);
363369

364-
#else
365-
366-
#if ASSERTIONS || GL_ASSERTIONS
370+
#elif ASSERTIONS || GL_ASSERTIONS
367371
if (['ANGLE_instanced_arrays',
368372
'OES_vertex_array_object',
369373
'WEBGL_draw_buffers',
370374
'WEBGL_multi_draw',
375+
'EXT_polygon_offset_clamp',
376+
'EXT_clip_control',
377+
'WEBGL_polygon_mode',
371378
'WEBGL_draw_instanced_base_vertex_base_instance',
372379
'WEBGL_multi_draw_instanced_base_vertex_base_instance'].includes(extString)) {
373380
err('When building with -sGL_SUPPORT_SIMPLE_ENABLE_EXTENSIONS=0, function emscripten_webgl_enable_extension() cannot be used to enable extension '
374381
+ extString + '! Use one of the functions emscripten_webgl_enable_*() to enable it!');
375382
}
376-
#endif
377-
378383
#endif
379384

380385
var ext = context.GLctx.getExtension(extString);

src/library_webgl.js

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

141+
$webgl_enable_EXT_polygon_offset_clamp: (ctx) => {
142+
return !!(ctx.extPolygonOffsetClamp = ctx.getExtension('EXT_polygon_offset_clamp'));
143+
},
144+
145+
emscripten_webgl_enable_EXT_polygon_offset_clamp__deps: ['$webgl_enable_EXT_polygon_offset_clamp'],
146+
emscripten_webgl_enable_EXT_polygon_offset_clamp: (ctx) => webgl_enable_EXT_polygon_offset_clamp(GL.contexts[ctx].GLctx),
147+
148+
$webgl_enable_EXT_clip_control: (ctx) => {
149+
return !!(ctx.extClipControl = ctx.getExtension('EXT_clip_control'));
150+
},
151+
152+
emscripten_webgl_enable_EXT_clip_control__deps: ['$webgl_enable_EXT_clip_control'],
153+
emscripten_webgl_enable_EXT_clip_control: (ctx) => webgl_enable_EXT_clip_control(GL.contexts[ctx].GLctx),
154+
155+
$webgl_enable_WEBGL_polygon_mode: (ctx) => {
156+
return !!(ctx.webglPolygonMode = ctx.getExtension('WEBGL_polygon_mode'));
157+
},
158+
159+
emscripten_webgl_enable_WEBGL_polygon_mode__deps: ['$webgl_enable_WEBGL_polygon_mode'],
160+
emscripten_webgl_enable_WEBGL_polygon_mode: (ctx) => webgl_enable_WEBGL_polygon_mode(GL.contexts[ctx].GLctx),
161+
138162
$GL__postset: 'var GLctx;',
139163
#if GL_SUPPORT_AUTOMATIC_ENABLE_EXTENSIONS
140164
// If GL_SUPPORT_AUTOMATIC_ENABLE_EXTENSIONS is enabled, GL.initExtensions() will call to initialize these.
@@ -152,6 +176,9 @@ for (/**@suppress{duplicate}*/var i = 0; i < {{{ GL_POOL_TEMP_BUFFERS_SIZE }}};
152176
'$webgl_enable_WEBGL_draw_instanced_base_vertex_base_instance',
153177
'$webgl_enable_WEBGL_multi_draw_instanced_base_vertex_base_instance',
154178
#endif
179+
'$webgl_enable_EXT_polygon_offset_clamp',
180+
'$webgl_enable_EXT_clip_control',
181+
'$webgl_enable_WEBGL_polygon_mode',
155182
'$webgl_enable_WEBGL_multi_draw',
156183
],
157184
#endif
@@ -739,6 +766,65 @@ for (/**@suppress{duplicate}*/var i = 0; i < {{{ GL_POOL_TEMP_BUFFERS_SIZE }}};
739766
disableHalfFloatExtensionIfBroken(ctx);
740767
#endif
741768

769+
// If end user enables *glGetProcAddress() functionality, then we must filter out
770+
// all future WebGL extensions from being passed to the user, and only restrict to advertising
771+
// extensions that the *glGetProcAddress() function knows to handle.
772+
#if GL_ENABLE_GET_PROC_ADDRESS
773+
ctx._allSupportedExtensions = ctx.getSupportedExtensions;
774+
const supportedExtensionsForGetProcAddress = [
775+
#if MIN_WEBGL_VERSION == 1
776+
// WebGL 1 extensions
777+
'ANGLE_instanced_arrays',
778+
'EXT_blend_minmax',
779+
'EXT_disjoint_timer_query',
780+
'EXT_frag_depth',
781+
'EXT_shader_texture_lod',
782+
'EXT_sRGB',
783+
'OES_element_index_uint',
784+
'OES_fbo_render_mipmap',
785+
'OES_standard_derivatives',
786+
'OES_texture_float',
787+
'OES_texture_half_float',
788+
'OES_texture_half_float_linear',
789+
'OES_vertex_array_object',
790+
'WEBGL_color_buffer_float',
791+
'WEBGL_depth_texture',
792+
'WEBGL_draw_buffers',
793+
#endif
794+
#if MAX_WEBGL_VERSION >= 2
795+
// WebGL 2 extensions
796+
'EXT_color_buffer_float',
797+
'EXT_disjoint_timer_query_webgl2',
798+
'EXT_texture_norm16',
799+
'OES_draw_buffers_indexed',
800+
'OVR_multiview2',
801+
'WEBGL_clip_cull_distance',
802+
'WEBGL_provoking_vertex',
803+
#endif
804+
// WebGL 1 and WebGL 2 extensions
805+
'EXT_clip_control',
806+
'EXT_color_buffer_half_float',
807+
'EXT_depth_clamp',
808+
'EXT_float_blend',
809+
'EXT_polygon_offset_clamp',
810+
'EXT_texture_compression_bptc',
811+
'EXT_texture_compression_rgtc',
812+
'EXT_texture_filter_anisotropic',
813+
'KHR_parallel_shader_compile',
814+
'OES_texture_float_linear',
815+
'WEBGL_compressed_texture_s3tc',
816+
'WEBGL_compressed_texture_s3tc_srgb',
817+
'WEBGL_debug_renderer_info',
818+
'WEBGL_debug_shaders',
819+
'WEBGL_lose_context',
820+
'WEBGL_multi_draw',
821+
'WEBGL_polygon_mode'
822+
];
823+
ctx.getSupportedExtensions = () => {
824+
return (this._allSupportedExtensions() || []).filter(ext => supportedExtensionsForGetProcAddress.includes(ext));
825+
}
826+
#endif
827+
742828
return handle;
743829
},
744830

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

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

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

1189-
webgl_enable_WEBGL_multi_draw(GLctx);
1190-
11911278
// .getSupportedExtensions() can return null if context is lost, so coerce
11921279
// to empty array.
11931280
var exts = GLctx.getSupportedExtensions() || [];
@@ -4217,6 +4304,30 @@ for (/**@suppress{duplicate}*/var i = 0; i < {{{ GL_POOL_TEMP_BUFFERS_SIZE }}};
42174304
return 1;
42184305
},
42194306
#endif
4307+
4308+
glPolygonOffsetClampEXT__sig: 'vfff',
4309+
glPolygonOffsetClampEXT: (factor, units, clamp) => {
4310+
#if GL_ASSERTIONS
4311+
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)");
4312+
#endif
4313+
GLctx.extPolygonOffsetClamp['polygonOffsetClampEXT'](factor, units, clamp);
4314+
},
4315+
4316+
glClipControlEXT__sig: 'vii',
4317+
glClipControlEXT: (origin, depth) => {
4318+
#if GL_ASSERTIONS
4319+
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)");
4320+
#endif
4321+
GLctx.extClipControl['clipControlEXT'](origin, depth);
4322+
},
4323+
4324+
glPolygonModeWEBGL__sig: 'vii',
4325+
glPolygonModeWEBGL: (face, mode) => {
4326+
#if GL_ASSERTIONS
4327+
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)");
4328+
#endif
4329+
GLctx.webglPolygonMode['polygonModeWEBGL'](face, mode);
4330+
},
42204331
};
42214332

42224333
// Simple pass-through functions.

src/settings.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -589,6 +589,13 @@ var GL_DISABLE_HALF_FLOAT_EXTENSION_IF_BROKEN = false;
589589
// Set this to 0 to force-disable the workaround if you know the issue will not affect you.
590590
var GL_WORKAROUND_SAFARI_GETCONTEXT_BUG = true;
591591

592+
// If 1, link with support to *glGetProcAddress() functionality.
593+
// In WebGL, *glGetProcAddress() causes a substantial code size and performance impact, since WebGL
594+
// does not natively provide such functionality, and it must be emulated. Using *glGetProcAddress()
595+
// is not recommended. If you still need to use this, e.g. when porting an existing renderer,
596+
// you can link with -sGL_ENABLE_GET_PROC_ADDRESS=1 to get support for this functionality.
597+
var GL_ENABLE_GET_PROC_ADDRESS = false;
598+
592599
// Use JavaScript math functions like Math.tan. This saves code size as we can avoid shipping
593600
// compiled musl code. However, it can be significantly slower as it calls out to JS. It
594601
// also may give different results as JS math is specced somewhat differently than libc, and

system/include/emscripten/html5_webgl.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,12 @@ EM_BOOL emscripten_webgl_enable_WEBGL_multi_draw(EMSCRIPTEN_WEBGL_CONTEXT_HANDLE
7373

7474
EM_BOOL emscripten_webgl_enable_WEBGL_multi_draw_instanced_base_vertex_base_instance(EMSCRIPTEN_WEBGL_CONTEXT_HANDLE context);
7575

76+
EM_BOOL emscripten_webgl_enable_EXT_polygon_offset_clamp(EMSCRIPTEN_WEBGL_CONTEXT_HANDLE context);
77+
78+
EM_BOOL emscripten_webgl_enable_EXT_clip_control(EMSCRIPTEN_WEBGL_CONTEXT_HANDLE context);
79+
80+
EM_BOOL emscripten_webgl_enable_WEBGL_polygon_mode(EMSCRIPTEN_WEBGL_CONTEXT_HANDLE context);
81+
7682
typedef EM_BOOL (*em_webgl_context_callback)(int eventType, const void *reserved, void *userData);
7783
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);
7884
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);

0 commit comments

Comments
 (0)