Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
emscripten-core
GitHub Repository: emscripten-core/emscripten
Path: blob/main/src/lib/libhtml5_webgl.js
6174 views
1
/**
2
* @license
3
* Copyright 2014 The Emscripten Authors
4
* SPDX-License-Identifier: MIT
5
*/
6
7
var LibraryHtml5WebGL = {
8
// Writes a JS typed array containing 32-bit floats or ints to memory
9
$writeGLArray: (arr, dst, dstLength, heapType) => {
10
#if ASSERTIONS
11
assert(arr);
12
assert(typeof arr.length != 'undefined');
13
#endif
14
var len = arr.length;
15
var writeLength = dstLength < len ? dstLength : len;
16
var heap = heapType ? HEAPF32 : HEAP32;
17
// Works because HEAPF32 and HEAP32 have the same bytes-per-element
18
dst = {{{ getHeapOffset('dst', 'float') }}};
19
for (var i = 0; i < writeLength; ++i) {
20
heap[dst + i] = arr[i];
21
}
22
return len;
23
},
24
25
$webglPowerPreferences__internal: true,
26
$webglPowerPreferences: ['default', 'low-power', 'high-performance'],
27
28
#if PTHREADS && OFFSCREEN_FRAMEBUFFER
29
// In offscreen framebuffer mode, we implement a proxied version of the
30
// emscripten_webgl_create_context() function in JS.
31
emscripten_webgl_create_context_proxied__proxy: 'sync',
32
emscripten_webgl_create_context_proxied__deps: ['emscripten_webgl_do_create_context'],
33
emscripten_webgl_create_context_proxied: (target, attributes) =>
34
_emscripten_webgl_do_create_context(target, attributes),
35
36
// The other proxied GL commands are defined in C (guarded by the
37
// __EMSCRIPTEN_OFFSCREEN_FRAMEBUFFER__ definition).
38
#else
39
// When not in offscreen framebuffer mode, these functions are implemented
40
// in JS and forwarded without any proxying.
41
emscripten_webgl_create_context: 'emscripten_webgl_do_create_context',
42
43
emscripten_webgl_get_current_context: 'emscripten_webgl_do_get_current_context',
44
45
emscripten_webgl_commit_frame: 'emscripten_webgl_do_commit_frame',
46
#endif
47
48
#if OFFSCREENCANVAS_SUPPORT
49
emscripten_webgl_do_create_context__postset: `
50
registerPreMainLoop(() => {
51
// If the current GL context is an OffscreenCanvas, but it was initialized
52
// with implicit swap mode, perform the swap on behalf of the user.
53
if (GL.currentContext && !GL.currentContextIsProxied && !GL.currentContext.attributes.explicitSwapControl && GL.currentContext.GLctx.commit) {
54
GL.currentContext.GLctx.commit();
55
}
56
});`,
57
#endif
58
59
emscripten_webgl_do_create_context__deps: [
60
#if OFFSCREENCANVAS_SUPPORT
61
'$registerPreMainLoop',
62
'malloc',
63
'emscripten_supports_offscreencanvas',
64
#endif
65
#if PTHREADS && OFFSCREEN_FRAMEBUFFER
66
'emscripten_webgl_create_context_proxied',
67
#endif
68
'$webglPowerPreferences', '$findCanvasEventTarget'],
69
// This function performs proxying manually, depending on the style of context that is to be created.
70
emscripten_webgl_do_create_context: (target, attributes) => {
71
#if ASSERTIONS
72
assert(attributes);
73
#endif
74
var attr32 = {{{ getHeapOffset('attributes', 'i32') }}};
75
var powerPreference = HEAP32[attr32 + ({{{ C_STRUCTS.EmscriptenWebGLContextAttributes.powerPreference }}}>>2)];
76
var contextAttributes = {
77
'alpha': !!HEAP8[attributes + {{{ C_STRUCTS.EmscriptenWebGLContextAttributes.alpha }}}],
78
'depth': !!HEAP8[attributes + {{{ C_STRUCTS.EmscriptenWebGLContextAttributes.depth }}}],
79
'stencil': !!HEAP8[attributes + {{{ C_STRUCTS.EmscriptenWebGLContextAttributes.stencil }}}],
80
'antialias': !!HEAP8[attributes + {{{ C_STRUCTS.EmscriptenWebGLContextAttributes.antialias }}}],
81
'premultipliedAlpha': !!HEAP8[attributes + {{{ C_STRUCTS.EmscriptenWebGLContextAttributes.premultipliedAlpha }}}],
82
'preserveDrawingBuffer': !!HEAP8[attributes + {{{ C_STRUCTS.EmscriptenWebGLContextAttributes.preserveDrawingBuffer }}}],
83
'powerPreference': webglPowerPreferences[powerPreference],
84
'failIfMajorPerformanceCaveat': !!HEAP8[attributes + {{{ C_STRUCTS.EmscriptenWebGLContextAttributes.failIfMajorPerformanceCaveat }}}],
85
// The following are not predefined WebGL context attributes in the WebGL specification, so the property names can be minified by Closure.
86
majorVersion: HEAP32[attr32 + ({{{ C_STRUCTS.EmscriptenWebGLContextAttributes.majorVersion }}}>>2)],
87
minorVersion: HEAP32[attr32 + ({{{ C_STRUCTS.EmscriptenWebGLContextAttributes.minorVersion }}}>>2)],
88
enableExtensionsByDefault: HEAP8[attributes + {{{ C_STRUCTS.EmscriptenWebGLContextAttributes.enableExtensionsByDefault }}}],
89
explicitSwapControl: HEAP8[attributes + {{{ C_STRUCTS.EmscriptenWebGLContextAttributes.explicitSwapControl }}}],
90
proxyContextToMainThread: HEAP32[attr32 + ({{{ C_STRUCTS.EmscriptenWebGLContextAttributes.proxyContextToMainThread }}}>>2)],
91
renderViaOffscreenBackBuffer: HEAP8[attributes + {{{ C_STRUCTS.EmscriptenWebGLContextAttributes.renderViaOffscreenBackBuffer }}}]
92
};
93
94
95
#if ASSERTIONS
96
// TODO: Make these into hard errors at some point in the future
97
if (contextAttributes.majorVersion !== 1 && contextAttributes.majorVersion !== 2) {
98
err(`Invalid WebGL version requested: ${contextAttributes.majorVersion}`);
99
}
100
#if MIN_WEBGL_VERSION >= 2
101
if (contextAttributes.majorVersion !== 2) {
102
err('WebGL 1 requested but only WebGL 2 is supported (MIN_WEBGL_VERSION is 2)');
103
}
104
#elif MAX_WEBGL_VERSION == 1
105
if (contextAttributes.majorVersion !== 1) {
106
err('WebGL 2 requested but only WebGL 1 is supported (set -sMAX_WEBGL_VERSION=2 to fix the problem)');
107
}
108
#endif
109
#endif
110
111
var canvas = findCanvasEventTarget(target);
112
#if OFFSCREENCANVAS_SUPPORT
113
// If our canvas from findCanvasEventTarget is actually an offscreen canvas record, we should extract the inner canvas.
114
if (canvas?.canvas) { canvas = canvas.canvas; }
115
#endif
116
#if GL_DEBUG
117
var targetStr = UTF8ToString(target);
118
#endif
119
120
#if PTHREADS && OFFSCREEN_FRAMEBUFFER
121
// Create a WebGL context that is proxied to main thread if canvas was not found on worker, or if explicitly requested to do so.
122
if (ENVIRONMENT_IS_PTHREAD) {
123
if (contextAttributes.proxyContextToMainThread === {{{ cDefs.EMSCRIPTEN_WEBGL_CONTEXT_PROXY_ALWAYS }}} ||
124
(!canvas && contextAttributes.proxyContextToMainThread === {{{ cDefs.EMSCRIPTEN_WEBGL_CONTEXT_PROXY_FALLBACK }}})) {
125
// When WebGL context is being proxied via the main thread, we must render using an offscreen FBO render target to avoid WebGL's
126
// "implicit swap when callback exits" behavior. TODO: If OffscreenCanvas is supported, explicitSwapControl=true and still proxying,
127
// then this can be avoided, since OffscreenCanvas enables explicit swap control.
128
#if GL_DEBUG
129
if (contextAttributes.proxyContextToMainThread === {{{ cDefs.EMSCRIPTEN_WEBGL_CONTEXT_PROXY_ALWAYS }}}) dbg('EMSCRIPTEN_WEBGL_CONTEXT_PROXY_ALWAYS enabled, proxying WebGL rendering from pthread to main thread.');
130
if (!canvas && contextAttributes.proxyContextToMainThread === {{{ cDefs.EMSCRIPTEN_WEBGL_CONTEXT_PROXY_FALLBACK }}}) dbg(`Specified canvas target "${targetStr}" is not an OffscreenCanvas in the current pthread, but EMSCRIPTEN_WEBGL_CONTEXT_PROXY_FALLBACK is set. Proxying WebGL rendering from pthread to main thread.`);
131
dbg('Performance warning: forcing renderViaOffscreenBackBuffer=true and preserveDrawingBuffer=true since proxying WebGL rendering.');
132
#endif
133
// We will be proxying - if OffscreenCanvas is supported, we can proxy a bit more efficiently by avoiding having to create an Offscreen FBO.
134
if (!_emscripten_supports_offscreencanvas()) {
135
{{{ makeSetValue('attributes', C_STRUCTS.EmscriptenWebGLContextAttributes.renderViaOffscreenBackBuffer, '1', 'i8') }}};
136
{{{ makeSetValue('attributes', C_STRUCTS.EmscriptenWebGLContextAttributes.preserveDrawingBuffer, '1', 'i8') }}};
137
}
138
return _emscripten_webgl_create_context_proxied(target, attributes);
139
}
140
}
141
#endif
142
143
if (!canvas) {
144
#if GL_DEBUG
145
dbg(`emscripten_webgl_create_context failed: Unknown canvas target "${targetStr}"!`);
146
#endif
147
return 0;
148
}
149
150
#if OFFSCREENCANVAS_SUPPORT
151
if (canvas.offscreenCanvas) canvas = canvas.offscreenCanvas;
152
153
#if GL_DEBUG
154
if (_emscripten_supports_offscreencanvas() && canvas instanceof OffscreenCanvas) dbg(`emscripten_webgl_create_context: Creating an OffscreenCanvas-based WebGL context on target "${targetStr}"`);
155
else if (typeof HTMLCanvasElement != 'undefined' && canvas instanceof HTMLCanvasElement) dbg(`emscripten_webgl_create_context: Creating an HTMLCanvasElement-based WebGL context on target "${targetStr}"`);
156
#endif
157
158
if (contextAttributes.explicitSwapControl) {
159
var supportsOffscreenCanvas = canvas.transferControlToOffscreen || (_emscripten_supports_offscreencanvas() && canvas instanceof OffscreenCanvas);
160
161
if (!supportsOffscreenCanvas) {
162
#if OFFSCREEN_FRAMEBUFFER
163
if (!contextAttributes.renderViaOffscreenBackBuffer) {
164
contextAttributes.renderViaOffscreenBackBuffer = true;
165
#if GL_DEBUG
166
dbg('emscripten_webgl_create_context: Performance warning, OffscreenCanvas is not supported but explicitSwapControl was requested, so force-enabling renderViaOffscreenBackBuffer=true to allow explicit swapping!');
167
#endif
168
}
169
#else
170
#if GL_DEBUG
171
dbg('emscripten_webgl_create_context failed: OffscreenCanvas is not supported but explicitSwapControl was requested!');
172
#endif
173
return 0;
174
#endif
175
}
176
177
if (canvas.transferControlToOffscreen) {
178
#if GL_DEBUG
179
dbg(`explicitSwapControl requested: canvas.transferControlToOffscreen() on canvas "${targetStr}" to get .commit() function and not rely on implicit WebGL swap`);
180
#endif
181
if (!canvas.controlTransferredOffscreen) {
182
GL.offscreenCanvases[canvas.id] = {
183
canvas: canvas.transferControlToOffscreen(),
184
canvasSharedPtr: _malloc(12),
185
id: canvas.id
186
};
187
canvas.controlTransferredOffscreen = true;
188
} else if (!GL.offscreenCanvases[canvas.id]) {
189
#if GL_DEBUG
190
dbg(`OffscreenCanvas is supported, and canvas "${canvas.id}" has already before been transferred offscreen, but there is no known OffscreenCanvas with that name!`);
191
#endif
192
return 0;
193
}
194
canvas = GL.offscreenCanvases[canvas.id].canvas;
195
}
196
}
197
#else // !OFFSCREENCANVAS_SUPPORT
198
#if OFFSCREEN_FRAMEBUFFER
199
if (contextAttributes.explicitSwapControl && !contextAttributes.renderViaOffscreenBackBuffer) {
200
contextAttributes.renderViaOffscreenBackBuffer = true;
201
#if GL_DEBUG
202
dbg('emscripten_webgl_create_context: Performance warning, not building with OffscreenCanvas support enabled but explicitSwapControl was requested, so force-enabling renderViaOffscreenBackBuffer=true to allow explicit swapping!');
203
#endif
204
}
205
#else
206
if (contextAttributes.explicitSwapControl) {
207
#if GL_DEBUG
208
dbg('emscripten_webgl_create_context failed: explicitSwapControl is not supported, please rebuild with -sOFFSCREENCANVAS_SUPPORT to enable targeting the experimental OffscreenCanvas specification, or rebuild with -sOFFSCREEN_FRAMEBUFFER to emulate explicitSwapControl in the absence of OffscreenCanvas support!');
209
#endif
210
return 0;
211
}
212
#endif // ~!OFFSCREEN_FRAMEBUFFER
213
214
#endif // ~!OFFSCREENCANVAS_SUPPORT
215
216
var contextHandle = GL.createContext(canvas, contextAttributes);
217
return contextHandle;
218
},
219
220
#if PTHREADS && OFFSCREEN_FRAMEBUFFER
221
// Runs on the calling thread, proxies if needed.
222
emscripten_webgl_make_context_current_calling_thread__sig: 'ip',
223
emscripten_webgl_make_context_current_calling_thread: (contextHandle) => {
224
var success = GL.makeContextCurrent(contextHandle);
225
if (success) GL.currentContextIsProxied = false; // If succeeded above, we will have a local GL context from this thread (worker or main).
226
return success ? {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}} : {{{ cDefs.EMSCRIPTEN_RESULT_INVALID_PARAM }}};
227
},
228
// This function gets called in a pthread, after it has successfully activated (with make_current()) a proxied GL context to itself from the main thread.
229
// In this scenario, the pthread does not hold a high-level JS object to the GL context, because it lives on the main thread, in which case we record
230
// an integer pointer as a token value to represent the GL context activation from another thread. (when this function is called, the main browser thread
231
// has already accepted the GL context activation for our pthread, so that side is good)
232
#if GL_SUPPORT_EXPLICIT_SWAP_CONTROL
233
_emscripten_proxied_gl_context_activated_from_main_browser_thread__deps: ['$registerPreMainLoop'],
234
_emscripten_proxied_gl_context_activated_from_main_browser_thread__postjs: `
235
// If the current GL context is a proxied regular WebGL context, and was
236
// initialized with implicit swap mode on the main thread, and we are on the
237
// parent thread, perform the swap on behalf of the user.
238
registerPreMainLoop(() => {
239
if (GL.currentContext && GL.currentContextIsProxied) {
240
var explicitSwapControl = {{{ makeGetValue('GL.currentContext', 0, 'i32') }}};
241
if (!explicitSwapControl) _emscripten_webgl_commit_frame();
242
}
243
});`,
244
#endif
245
_emscripten_proxied_gl_context_activated_from_main_browser_thread: (contextHandle) => {
246
GLctx = Module['ctx'] = GL.currentContext = contextHandle;
247
GL.currentContextIsProxied = true;
248
},
249
#else
250
emscripten_webgl_make_context_current: (contextHandle) => {
251
var success = GL.makeContextCurrent(contextHandle);
252
return success ? {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}} : {{{ cDefs.EMSCRIPTEN_RESULT_INVALID_PARAM }}};
253
},
254
#endif
255
256
emscripten_webgl_do_get_current_context: () => GL.currentContext ? GL.currentContext.handle : 0,
257
258
emscripten_webgl_get_drawing_buffer_size__proxy: 'sync_on_webgl_context_handle_thread',
259
emscripten_webgl_get_drawing_buffer_size: (contextHandle, width, height) => {
260
var GLContext = GL.getContext(contextHandle);
261
262
if (!GLContext || !GLContext.GLctx || !width || !height) {
263
return {{{ cDefs.EMSCRIPTEN_RESULT_INVALID_PARAM }}};
264
}
265
{{{ makeSetValue('width', '0', 'GLContext.GLctx.drawingBufferWidth', 'i32') }}};
266
{{{ makeSetValue('height', '0', 'GLContext.GLctx.drawingBufferHeight', 'i32') }}};
267
return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}};
268
},
269
270
emscripten_webgl_do_commit_frame: () => {
271
#if TRACE_WEBGL_CALLS
272
var threadId = (typeof _pthread_self != 'undefined') ? _pthread_self : () => 1;
273
err(`[Thread ${threadId()}, GL ctx: ${GL.currentContext.handle}]: emscripten_webgl_do_commit_frame()`);
274
#endif
275
if (!GL.currentContext || !GL.currentContext.GLctx) {
276
#if GL_DEBUG
277
dbg('emscripten_webgl_commit_frame() failed: no GL context set current via emscripten_webgl_make_context_current()!');
278
#endif
279
return {{{ cDefs.EMSCRIPTEN_RESULT_INVALID_TARGET }}};
280
}
281
282
#if OFFSCREEN_FRAMEBUFFER
283
if (GL.currentContext.defaultFbo) {
284
GL.blitOffscreenFramebuffer(GL.currentContext);
285
#if GL_DEBUG && OFFSCREENCANVAS_SUPPORT
286
if (GL.currentContext.GLctx.commit) dbg('emscripten_webgl_commit_frame(): Offscreen framebuffer should never have gotten created when canvas is in OffscreenCanvas mode, since it is redundant and not necessary');
287
#endif
288
return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}};
289
}
290
#endif
291
if (!GL.currentContext.attributes.explicitSwapControl) {
292
#if GL_DEBUG
293
dbg('emscripten_webgl_commit_frame() cannot be called for canvases with implicit swap control mode!');
294
#endif
295
return {{{ cDefs.EMSCRIPTEN_RESULT_INVALID_TARGET }}};
296
}
297
// We would do GL.currentContext.GLctx.commit(); here, but the current implementation
298
// in browsers has removed it - swap is implicit, so this function is a no-op for now
299
// (until/unless the spec changes).
300
return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}};
301
},
302
303
emscripten_webgl_get_context_attributes__proxy: 'sync_on_webgl_context_handle_thread',
304
emscripten_webgl_get_context_attributes__deps: ['$webglPowerPreferences'],
305
emscripten_webgl_get_context_attributes: (c, a) => {
306
if (!a) return {{{ cDefs.EMSCRIPTEN_RESULT_INVALID_PARAM }}};
307
c = GL.contexts[c];
308
if (!c) return {{{ cDefs.EMSCRIPTEN_RESULT_INVALID_TARGET }}};
309
var t = c.GLctx?.getContextAttributes();
310
if (!t) return {{{ cDefs.EMSCRIPTEN_RESULT_INVALID_TARGET }}};
311
312
{{{ makeSetValue('a', C_STRUCTS.EmscriptenWebGLContextAttributes.alpha, 't.alpha', 'i8') }}};
313
{{{ makeSetValue('a', C_STRUCTS.EmscriptenWebGLContextAttributes.depth, 't.depth', 'i8') }}};
314
{{{ makeSetValue('a', C_STRUCTS.EmscriptenWebGLContextAttributes.stencil, 't.stencil', 'i8') }}};
315
{{{ makeSetValue('a', C_STRUCTS.EmscriptenWebGLContextAttributes.antialias, 't.antialias', 'i8') }}};
316
{{{ makeSetValue('a', C_STRUCTS.EmscriptenWebGLContextAttributes.premultipliedAlpha, 't.premultipliedAlpha', 'i8') }}};
317
{{{ makeSetValue('a', C_STRUCTS.EmscriptenWebGLContextAttributes.preserveDrawingBuffer, 't.preserveDrawingBuffer', 'i8') }}};
318
var power = t['powerPreference'] && webglPowerPreferences.indexOf(t['powerPreference']);
319
{{{ makeSetValue('a', C_STRUCTS.EmscriptenWebGLContextAttributes.powerPreference, 'power', 'i32') }}};
320
{{{ makeSetValue('a', C_STRUCTS.EmscriptenWebGLContextAttributes.failIfMajorPerformanceCaveat, 't.failIfMajorPerformanceCaveat', 'i8') }}};
321
{{{ makeSetValue('a', C_STRUCTS.EmscriptenWebGLContextAttributes.majorVersion, 'c.version', 'i32') }}};
322
{{{ makeSetValue('a', C_STRUCTS.EmscriptenWebGLContextAttributes.minorVersion, 0, 'i32') }}};
323
#if GL_SUPPORT_AUTOMATIC_ENABLE_EXTENSIONS
324
{{{ makeSetValue('a', C_STRUCTS.EmscriptenWebGLContextAttributes.enableExtensionsByDefault, 'c.attributes.enableExtensionsByDefault', 'i8') }}};
325
#endif
326
#if GL_SUPPORT_EXPLICIT_SWAP_CONTROL
327
{{{ makeSetValue('a', C_STRUCTS.EmscriptenWebGLContextAttributes.explicitSwapControl, 'c.attributes.explicitSwapControl', 'i8') }}};
328
#endif
329
return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}};
330
},
331
332
emscripten_webgl_destroy_context__proxy: 'sync_on_webgl_context_handle_thread',
333
emscripten_webgl_destroy_context: (contextHandle) => {
334
if (GL.currentContext == contextHandle) GL.currentContext = 0;
335
GL.deleteContext(contextHandle);
336
},
337
338
#if PTHREADS
339
// Special function that will be invoked on the thread calling emscripten_webgl_destroy_context(), before routing
340
// the call over to the target thread.
341
$emscripten_webgl_destroy_context_before_on_calling_thread__deps: ['emscripten_webgl_get_current_context', 'emscripten_webgl_make_context_current'],
342
$emscripten_webgl_destroy_context_before_on_calling_thread: (contextHandle) => {
343
if (_emscripten_webgl_get_current_context() == contextHandle) _emscripten_webgl_make_context_current(0);
344
},
345
#endif
346
347
emscripten_webgl_enable_extension__deps: [
348
#if GL_SUPPORT_SIMPLE_ENABLE_EXTENSIONS
349
#if MIN_WEBGL_VERSION == 1
350
'$webgl_enable_ANGLE_instanced_arrays',
351
'$webgl_enable_OES_vertex_array_object',
352
'$webgl_enable_WEBGL_draw_buffers',
353
#endif
354
#if MAX_WEBGL_VERSION >= 2
355
'$webgl_enable_WEBGL_draw_instanced_base_vertex_base_instance',
356
'$webgl_enable_WEBGL_multi_draw_instanced_base_vertex_base_instance',
357
#endif
358
'$webgl_enable_EXT_polygon_offset_clamp',
359
'$webgl_enable_EXT_clip_control',
360
'$webgl_enable_WEBGL_polygon_mode',
361
'$webgl_enable_WEBGL_multi_draw',
362
#endif
363
],
364
emscripten_webgl_enable_extension__proxy: 'sync_on_webgl_context_handle_thread',
365
emscripten_webgl_enable_extension: (contextHandle, extension) => {
366
var context = GL.getContext(contextHandle);
367
var extString = UTF8ToString(extension);
368
#if GL_EXTENSIONS_IN_PREFIXED_FORMAT
369
if (extString.startsWith('GL_')) extString = extString.slice(3); // Allow enabling extensions both with "GL_" prefix and without.
370
#endif
371
372
#if GL_SUPPORT_SIMPLE_ENABLE_EXTENSIONS
373
// Switch-board that pulls in code for all GL extensions, even if those are not used :/
374
// Build with -sGL_SUPPORT_SIMPLE_ENABLE_EXTENSIONS=0 to avoid this.
375
376
#if MIN_WEBGL_VERSION == 1
377
// Obtain function entry points to WebGL 1 extension related functions.
378
if (extString == 'ANGLE_instanced_arrays') webgl_enable_ANGLE_instanced_arrays(GLctx);
379
if (extString == 'OES_vertex_array_object') webgl_enable_OES_vertex_array_object(GLctx);
380
if (extString == 'WEBGL_draw_buffers') webgl_enable_WEBGL_draw_buffers(GLctx);
381
#endif
382
383
#if MAX_WEBGL_VERSION >= 2
384
if (extString == 'WEBGL_draw_instanced_base_vertex_base_instance') webgl_enable_WEBGL_draw_instanced_base_vertex_base_instance(GLctx);
385
if (extString == 'WEBGL_multi_draw_instanced_base_vertex_base_instance') webgl_enable_WEBGL_multi_draw_instanced_base_vertex_base_instance(GLctx);
386
#endif
387
388
if (extString == 'WEBGL_multi_draw') webgl_enable_WEBGL_multi_draw(GLctx);
389
if (extString == 'EXT_polygon_offset_clamp') webgl_enable_EXT_polygon_offset_clamp(GLctx);
390
if (extString == 'EXT_clip_control') webgl_enable_EXT_clip_control(GLctx);
391
if (extString == 'WEBGL_polygon_mode') webgl_enable_WEBGL_polygon_mode(GLctx);
392
393
#elif ASSERTIONS || GL_ASSERTIONS
394
if (['ANGLE_instanced_arrays',
395
'OES_vertex_array_object',
396
'WEBGL_draw_buffers',
397
'WEBGL_multi_draw',
398
'EXT_polygon_offset_clamp',
399
'EXT_clip_control',
400
'WEBGL_polygon_mode',
401
'WEBGL_draw_instanced_base_vertex_base_instance',
402
'WEBGL_multi_draw_instanced_base_vertex_base_instance'].includes(extString)) {
403
err('When building with -sGL_SUPPORT_SIMPLE_ENABLE_EXTENSIONS=0, function emscripten_webgl_enable_extension() cannot be used to enable extension '
404
+ extString + '! Use one of the functions emscripten_webgl_enable_*() to enable it!');
405
}
406
#endif
407
408
var ext = context.GLctx.getExtension(extString);
409
return !!ext;
410
},
411
412
emscripten_supports_offscreencanvas: () =>
413
// TODO: Add a new build mode, e.g. OFFSCREENCANVAS_SUPPORT=2, which
414
// necessitates OffscreenCanvas support at build time, and "return 1;" here in that build mode.
415
#if OFFSCREENCANVAS_SUPPORT
416
typeof OffscreenCanvas != 'undefined'
417
#else
418
0
419
#endif
420
,
421
422
$registerWebGlEventCallback__deps: ['$JSEvents', '$findEventTarget'],
423
$registerWebGlEventCallback: (target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString, targetThread) => {
424
#if PTHREADS
425
targetThread = JSEvents.getTargetThreadForEventCallback(targetThread);
426
#endif
427
428
#if !DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR
429
target ||= Module['canvas'];
430
#endif
431
432
var webGlEventHandlerFunc = (e) => {
433
#if PTHREADS
434
if (targetThread) __emscripten_run_callback_on_thread(targetThread, callbackfunc, eventTypeId, 0, userData);
435
else
436
#endif
437
if ({{{ makeDynCall('iiii', 'callbackfunc') }}}(eventTypeId, 0, userData)) e.preventDefault();
438
};
439
440
var eventHandler = {
441
target: findEventTarget(target),
442
eventTypeString,
443
eventTypeId,
444
userData,
445
callbackfunc,
446
handlerFunc: webGlEventHandlerFunc,
447
useCapture
448
};
449
JSEvents.registerOrRemoveHandler(eventHandler);
450
},
451
452
emscripten_set_webglcontextlost_callback_on_thread__proxy: 'sync',
453
emscripten_set_webglcontextlost_callback_on_thread__deps: ['$registerWebGlEventCallback'],
454
emscripten_set_webglcontextlost_callback_on_thread: (target, userData, useCapture, callbackfunc, targetThread) => {
455
registerWebGlEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_WEBGLCONTEXTLOST }}}, "webglcontextlost", targetThread);
456
return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}};
457
},
458
459
emscripten_set_webglcontextrestored_callback_on_thread__proxy: 'sync',
460
emscripten_set_webglcontextrestored_callback_on_thread__deps: ['$registerWebGlEventCallback'],
461
emscripten_set_webglcontextrestored_callback_on_thread: (target, userData, useCapture, callbackfunc, targetThread) => {
462
registerWebGlEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_WEBGLCONTEXTRESTORED }}}, "webglcontextrestored", targetThread);
463
return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}};
464
},
465
466
emscripten_is_webgl_context_lost__proxy: 'sync_on_webgl_context_handle_thread',
467
emscripten_is_webgl_context_lost: (contextHandle) =>
468
!GL.contexts[contextHandle] || GL.contexts[contextHandle].GLctx.isContextLost(), // No context ~> lost context.
469
470
emscripten_webgl_get_supported_extensions__proxy: 'sync_on_current_webgl_context_thread',
471
emscripten_webgl_get_supported_extensions__deps: ['$stringToNewUTF8'],
472
// Here we report the full list of extensions supported by WebGL rather than
473
// using getEmscriptenSupportedExtensions which filters the list based on
474
// what is has explicit support in.
475
emscripten_webgl_get_supported_extensions: () =>
476
stringToNewUTF8(GLctx.getSupportedExtensions().join(' ')),
477
478
emscripten_webgl_get_program_parameter_d__proxy: 'sync_on_current_webgl_context_thread',
479
emscripten_webgl_get_program_parameter_d: (program, param) =>
480
GLctx.getProgramParameter(GL.programs[program], param),
481
482
emscripten_webgl_get_program_info_log_utf8__proxy: 'sync_on_current_webgl_context_thread',
483
emscripten_webgl_get_program_info_log_utf8__deps: ['$stringToNewUTF8'],
484
emscripten_webgl_get_program_info_log_utf8: (program) =>
485
stringToNewUTF8(GLctx.getProgramInfoLog(GL.programs[program])),
486
487
emscripten_webgl_get_shader_parameter_d__proxy: 'sync_on_current_webgl_context_thread',
488
emscripten_webgl_get_shader_parameter_d: (shader, param) =>
489
GLctx.getShaderParameter(GL.shaders[shader], param),
490
491
emscripten_webgl_get_shader_info_log_utf8__proxy: 'sync_on_current_webgl_context_thread',
492
emscripten_webgl_get_shader_info_log_utf8__deps: ['$stringToNewUTF8'],
493
emscripten_webgl_get_shader_info_log_utf8: (shader) =>
494
stringToNewUTF8(GLctx.getShaderInfoLog(GL.shaders[shader])),
495
496
emscripten_webgl_get_shader_source_utf8__proxy: 'sync_on_current_webgl_context_thread',
497
emscripten_webgl_get_shader_source_utf8__deps: ['$stringToNewUTF8'],
498
emscripten_webgl_get_shader_source_utf8: (shader) =>
499
stringToNewUTF8(GLctx.getShaderSource(GL.shaders[shader])),
500
501
emscripten_webgl_get_vertex_attrib_d__proxy: 'sync_on_current_webgl_context_thread',
502
emscripten_webgl_get_vertex_attrib_d: (index, param) =>
503
GLctx.getVertexAttrib(index, param),
504
505
emscripten_webgl_get_vertex_attrib_o__proxy: 'sync_on_current_webgl_context_thread',
506
emscripten_webgl_get_vertex_attrib_o: (index, param) => {
507
var obj = GLctx.getVertexAttrib(index, param);
508
return obj?.name;
509
},
510
511
emscripten_webgl_get_vertex_attrib_v__proxy: 'sync_on_current_webgl_context_thread',
512
emscripten_webgl_get_vertex_attrib_v__deps: ['$writeGLArray'],
513
emscripten_webgl_get_vertex_attrib_v: (index, param, dst, dstLength, dstType) =>
514
writeGLArray(GLctx.getVertexAttrib(index, param), dst, dstLength, dstType),
515
516
emscripten_webgl_get_uniform_d__proxy: 'sync_on_current_webgl_context_thread',
517
emscripten_webgl_get_uniform_d__deps: ['$webglGetUniformLocation'],
518
emscripten_webgl_get_uniform_d: (program, location) =>
519
GLctx.getUniform(GL.programs[program], webglGetUniformLocation(location)),
520
521
emscripten_webgl_get_uniform_v__proxy: 'sync_on_current_webgl_context_thread',
522
emscripten_webgl_get_uniform_v__deps: ['$writeGLArray', '$webglGetUniformLocation'],
523
emscripten_webgl_get_uniform_v: (program, location, dst, dstLength, dstType) =>
524
writeGLArray(GLctx.getUniform(GL.programs[program], webglGetUniformLocation(location)), dst, dstLength, dstType),
525
526
emscripten_webgl_get_parameter_v__proxy: 'sync_on_current_webgl_context_thread',
527
emscripten_webgl_get_parameter_v__deps: ['$writeGLArray'],
528
emscripten_webgl_get_parameter_v: (param, dst, dstLength, dstType) =>
529
writeGLArray(GLctx.getParameter(param), dst, dstLength, dstType),
530
531
emscripten_webgl_get_parameter_d__proxy: 'sync_on_current_webgl_context_thread',
532
emscripten_webgl_get_parameter_d: (param) => GLctx.getParameter(param),
533
534
emscripten_webgl_get_parameter_o__proxy: 'sync_on_current_webgl_context_thread',
535
emscripten_webgl_get_parameter_o: (param) => {
536
var obj = GLctx.getParameter(param);
537
return obj?.name;
538
},
539
540
emscripten_webgl_get_parameter_utf8__deps: ['$stringToNewUTF8'],
541
emscripten_webgl_get_parameter_utf8__proxy: 'sync_on_current_webgl_context_thread',
542
emscripten_webgl_get_parameter_utf8: (param) => stringToNewUTF8(GLctx.getParameter(param)),
543
544
emscripten_webgl_get_parameter_i64v__proxy: 'sync_on_current_webgl_context_thread',
545
emscripten_webgl_get_parameter_i64v__deps: ['$writeI53ToI64'],
546
emscripten_webgl_get_parameter_i64v: (param, dst) => writeI53ToI64(dst, GLctx.getParameter(param)),
547
};
548
549
550
function handleWebGLProxying(funcs) {
551
#if PTHREADS
552
// Process 'sync_on_webgl_context_handle_thread' and
553
// 'sync_on_current_webgl_context_thread' pseudo-proxying modes to appropriate
554
// proxying mechanism, either proxying on-demand, unconditionally, or never,
555
// depending on build modes.
556
// 'sync_on_webgl_context_handle_thread' is used for function signatures that
557
// take a HTML5 WebGL context handle object as the first argument.
558
// 'sync_on_current_webgl_context_thread' is used for functions that operate on
559
// the implicit "current WebGL context" as activated via
560
// emscripten_webgl_make_current() function.
561
function listOfNFunctionArgs(func) {
562
const args = [];
563
for (var i = 0; i < func.length; ++i) {
564
args.push('p' + i);
565
}
566
return args;
567
}
568
569
const targetingOffscreenCanvas = {{{ OFFSCREENCANVAS_SUPPORT }}};
570
const targetingOffscreenFramebuffer = {{{ OFFSCREEN_FRAMEBUFFER }}};
571
572
for (const i in funcs) {
573
// Is this a function that takes GL context handle as first argument?
574
const proxyContextHandle = funcs[i + '__proxy'] == 'sync_on_webgl_context_handle_thread';
575
576
// Is this a function that operates on the implicit current GL context object?
577
const proxyCurrentContext = funcs[i + '__proxy'] == 'sync_on_current_webgl_context_thread';
578
579
if (!proxyContextHandle && !proxyCurrentContext) {
580
continue; // no resolving of pseudo-proxying needed for this function.
581
}
582
583
if (targetingOffscreenCanvas && (targetingOffscreenFramebuffer || proxyContextHandle)) {
584
// Dynamically check at runtime whether the current thread owns the GL context
585
// handle/current GL context object. If not, proxy the call to main thread.
586
// TODO: this handles the calling pthread and main thread cases, but not yet
587
// the case from pthread->pthread.
588
const sig = funcs[i + '__sig'] || LibraryManager.library[i + '__sig']
589
assert(sig);
590
funcs[i + '_calling_thread'] = funcs[i];
591
funcs[i + '_main_thread'] = i + '_calling_thread';
592
funcs[i + '_main_thread__proxy'] = 'sync';
593
funcs[i + '_main_thread__sig'] = sig;
594
funcs[i + '__deps'] ??= [];
595
funcs[i + '__deps'].push(i + '_calling_thread');
596
funcs[i + '__deps'].push(i + '_main_thread');
597
delete funcs[i + '__proxy'];
598
const funcArgs = listOfNFunctionArgs(funcs[i]);
599
const funcArgsString = funcArgs.join(',');
600
const retStatement = sig[0] != 'v' ? 'return' : '';
601
const contextCheck = proxyContextHandle ? 'GL.contexts[p0]' : 'GLctx';
602
var funcBody = `${retStatement} ${contextCheck} ? _${i}_calling_thread(${funcArgsString}) : _${i}_main_thread(${funcArgsString});`;
603
if (funcs[i + '_before_on_calling_thread']) {
604
funcs[i + '__deps'].push('$' + i + '_before_on_calling_thread');
605
funcBody = `${i}_before_on_calling_thread(${funcArgsString}); ` + funcBody;
606
}
607
funcs[i] = new Function(funcArgs, funcBody);
608
} else if (targetingOffscreenFramebuffer) {
609
// When targeting only OFFSCREEN_FRAMEBUFFER, unconditionally proxy all GL
610
// calls to main thread.
611
funcs[i + '__proxy'] = 'sync';
612
} else {
613
// Building without OFFSCREENCANVAS_SUPPORT or OFFSCREEN_FRAMEBUFFER; or building
614
// with OFFSCREENCANVAS_SUPPORT and no OFFSCREEN_FRAMEBUFFER: the application
615
// will only utilize WebGL in the main browser thread, and in the calling thread.
616
// Remove the WebGL proxying directives.
617
delete funcs[i + '__proxy'];
618
}
619
}
620
#else
621
// In single threaded mode just delete our custom __proxy attributes, otherwise
622
// they will causes errors in the JS compiler.
623
for (const i in funcs) {
624
delete funcs[i + '__proxy'];
625
}
626
#endif // PTHREADS
627
}
628
629
handleWebGLProxying(LibraryHtml5WebGL);
630
631
#if LibraryManager.has('libwebgl.js')
632
autoAddDeps(LibraryHtml5WebGL, '$GL');
633
#endif
634
635
addToLibrary(LibraryHtml5WebGL);
636
637