diff --git a/AUTHORS b/AUTHORS index c8442bc455abc..b8413836e278c 100644 --- a/AUTHORS +++ b/AUTHORS @@ -595,3 +595,4 @@ a license to everyone to use it as detailed in LICENSE.) * Piotr Wierciński * 郑苏波 (Super Zheng) * James Hu +* Philipp Muigg (copyright owned by Siemens) diff --git a/src/library_webgl.js b/src/library_webgl.js index 6450c6440a8bb..5eb81d4f882a0 100644 --- a/src/library_webgl.js +++ b/src/library_webgl.js @@ -376,7 +376,7 @@ var LibraryGL = { var source = ''; for (var i = 0; i < count; ++i) { var len = length ? {{{ makeGetValue('length', 'i*4', 'i32') }}} : -1; - source += UTF8ToString({{{ makeGetValue('string', 'i*4', 'i32') }}}, len < 0 ? undefined : len); + source += UTF8ToString({{{ makeGetValue('string', `i*${POINTER_SIZE}`, '*') }}}, len < 0 ? undefined : len); } #if LEGACY_GL_EMULATION // Let's see if we need to enable the standard derivatives extension @@ -1424,7 +1424,7 @@ var LibraryGL = { }, glCompressedTexImage2D: (target, level, internalFormat, width, height, border, imageSize, data) => { -#if MAX_WEBGL_VERSION >= 2 +#if MAX_WEBGL_VERSION >= 2 && !MEMORY64 if ({{{ isCurrentContextWebGL2() }}}) { // WebGL 2 provides new garbage-free entry points to call to WebGL. Use those always when possible. if (GLctx.currentPixelUnpackBufferBinding || !imageSize) { GLctx.compressedTexImage2D(target, level, internalFormat, width, height, border, imageSize, data); @@ -1439,7 +1439,7 @@ var LibraryGL = { glCompressedTexSubImage2D: (target, level, xoffset, yoffset, width, height, format, imageSize, data) => { -#if MAX_WEBGL_VERSION >= 2 +#if MAX_WEBGL_VERSION >= 2 && !MEMORY64 if ({{{ isCurrentContextWebGL2() }}}) { // WebGL 2 provides new garbage-free entry points to call to WebGL. Use those always when possible. if (GLctx.currentPixelUnpackBufferBinding || !imageSize) { GLctx.compressedTexSubImage2D(target, level, xoffset, yoffset, width, height, format, imageSize, data); @@ -1502,13 +1502,14 @@ var LibraryGL = { $emscriptenWebGLGetTexPixelData: (type, format, width, height, pixels, internalFormat) => { var heap = heapObjectForWebGLType(type); var shift = heapAccessShiftForWebGLHeap(heap); - var byteSize = 1<> shift) << shift == pixels, 'Pointer to texture data passed to texture get function must be aligned to the byte size of the pixel type!'); + assert({{{ isPtrAligned('pixels', '2 ** shift') }}}, 'Pointer to texture data passed to texture get function must be aligned to the byte size of the pixel type!'); #endif - return heap.subarray(pixels >> shift, pixels + bytes >> shift); + {{{ convertPtrToIdx('pixels', 'shift') }}} + {{{ convertPtrToIdx('bytes', 'shift') }}} + return heap.subarray(pixels, pixels + bytes); }, glTexImage2D__deps: ['$emscriptenWebGLGetTexPixelData' @@ -1536,6 +1537,8 @@ var LibraryGL = { } } #endif + +#if MAX_WEBGL_VERSION >= 2 && !MEMORY64 if ({{{ isCurrentContextWebGL2() }}}) { // WebGL 2 provides new garbage-free entry points to call to WebGL. Use those always when possible. if (GLctx.currentPixelUnpackBufferBinding) { @@ -1548,6 +1551,8 @@ var LibraryGL = { } return; } +#endif + #endif GLctx.texImage2D(target, level, internalFormat, width, height, border, format, type, pixels ? emscriptenWebGLGetTexPixelData(type, format, width, height, pixels, internalFormat) : null); }, @@ -1558,7 +1563,7 @@ var LibraryGL = { #endif ], glTexSubImage2D: (target, level, xoffset, yoffset, width, height, format, type, pixels) => { -#if MAX_WEBGL_VERSION >= 2 +#if MAX_WEBGL_VERSION >= 2 && !MEMORY64 #if WEBGL2_BACKWARDS_COMPATIBILITY_EMULATION if ({{{ isCurrentContextWebGL2() }}}) { // In WebGL 1 to do half float textures, one uses the type enum GL_HALF_FLOAT_OES, but in @@ -1567,6 +1572,8 @@ var LibraryGL = { if (type == 0x8d61/*GL_HALF_FLOAT_OES*/) type = 0x140B /*GL_HALF_FLOAT*/; } #endif + +#if MIN_WEBGL_VERSION >= 2 && !MEMORY64 if ({{{ isCurrentContextWebGL2() }}}) { // WebGL 2 provides new garbage-free entry points to call to WebGL. Use those always when possible. if (GLctx.currentPixelUnpackBufferBinding) { @@ -1579,6 +1586,8 @@ var LibraryGL = { } return; } +#endif + #endif var pixelData = null; if (pixels) pixelData = emscriptenWebGLGetTexPixelData(type, format, width, height, pixels, 0); @@ -1591,7 +1600,7 @@ var LibraryGL = { #endif ], glReadPixels: (x, y, width, height, format, type, pixels) => { -#if MAX_WEBGL_VERSION >= 2 +#if MAX_WEBGL_VERSION >= 2 && !MEMORY64 if ({{{ isCurrentContextWebGL2() }}}) { // WebGL 2 provides new garbage-free entry points to call to WebGL. Use those always when possible. if (GLctx.currentPixelPackBufferBinding) { GLctx.readPixels(x, y, width, height, format, type, pixels); @@ -1760,7 +1769,7 @@ var LibraryGL = { } #endif -#if MAX_WEBGL_VERSION >= 2 +#if MAX_WEBGL_VERSION >= 2 && !MEMORY64 if ({{{ isCurrentContextWebGL2() }}}) { // WebGL 2 provides new garbage-free entry points to call to WebGL. Use those always when possible. // If size is zero, WebGL would interpret uploading the whole input arraybuffer (starting from given offset), which would // not make sense in WebAssembly, so avoid uploading if size is zero. However we must still call bufferData to establish a @@ -1775,13 +1784,13 @@ var LibraryGL = { // N.b. here first form specifies a heap subarray, second form an integer size, so the ?: code here is polymorphic. It is advised to avoid // randomly mixing both uses in calling code, to avoid any potential JS engine JIT issues. GLctx.bufferData(target, data ? HEAPU8.subarray(data, data+size) : size, usage); -#if MAX_WEBGL_VERSION >= 2 +#if MAX_WEBGL_VERSION >= 2 && !MEMORY64 } #endif }, glBufferSubData: (target, offset, size, data) => { -#if MAX_WEBGL_VERSION >= 2 +#if MAX_WEBGL_VERSION >= 2 && !MEMORY64 if ({{{ isCurrentContextWebGL2() }}}) { // WebGL 2 provides new garbage-free entry points to call to WebGL. Use those always when possible. size && GLctx.bufferSubData(target, offset, HEAPU8, data, size); return; @@ -1791,7 +1800,7 @@ var LibraryGL = { }, // Queries EXT - glGenQueriesEXT__sig: 'vii', + glGenQueriesEXT__sig: 'vip', glGenQueriesEXT: (n, ids) => { for (var i = 0; i < n; i++) { var query = GLctx.disjointTimerQueryExt['createQueryEXT'](); @@ -1810,7 +1819,7 @@ var LibraryGL = { } }, - glDeleteQueriesEXT__sig: 'vii', + glDeleteQueriesEXT__sig: 'vip', glDeleteQueriesEXT: (n, ids) => { for (var i = 0; i < n; i++) { var id = {{{ makeGetValue('ids', 'i*4', 'i32') }}}; @@ -1852,7 +1861,7 @@ var LibraryGL = { GLctx.disjointTimerQueryExt['queryCounterEXT'](GL.queries[id], target); }, - glGetQueryivEXT__sig: 'viii', + glGetQueryivEXT__sig: 'viip', glGetQueryivEXT: (target, pname, params) => { if (!params) { // GLES2 specification does not specify how to behave if params is a null pointer. Since calling this function does not make sense @@ -1866,7 +1875,7 @@ var LibraryGL = { {{{ makeSetValue('params', '0', 'GLctx.disjointTimerQueryExt[\'getQueryEXT\'](target, pname)', 'i32') }}}; }, - glGetQueryObjectivEXT__sig: 'viii', + glGetQueryObjectivEXT__sig: 'viip', glGetQueryObjectivEXT: (id, pname, params) => { if (!params) { // GLES2 specification does not specify how to behave if params is a null pointer. Since calling this function does not make sense @@ -1892,7 +1901,7 @@ var LibraryGL = { }, glGetQueryObjectuivEXT: 'glGetQueryObjectivEXT', - glGetQueryObjecti64vEXT__sig: 'viii', + glGetQueryObjecti64vEXT__sig: 'viip', glGetQueryObjecti64vEXT__deps: ['$writeI53ToI64'], glGetQueryObjecti64vEXT: (id, pname, params) => { if (!params) { @@ -2245,7 +2254,7 @@ var LibraryGL = { err("glGetVertexAttribPointer on client-side array: not supported, bad data returned"); } #endif - {{{ makeSetValue('pointer', '0', 'GLctx.getVertexAttribOffset(index, pname)', 'i32') }}}; + {{{ makeSetValue('pointer', '0', 'GLctx.getVertexAttribOffset(index, pname)', '*') }}}; }, glUniform1f__deps: ['$webglGetUniformLocation'], @@ -2320,17 +2329,17 @@ var LibraryGL = { glUniform1iv: (location, count, value) => { #if GL_ASSERTIONS GL.validateGLObjectID(GLctx.currentProgram.uniformLocsById, location, 'glUniform1iv', 'location'); - assert((value & 3) == 0, 'Pointer to integer data passed to glUniform1iv must be aligned to four bytes!'); + assert({{{ isPtrAligned('value', 4) }}}, 'Pointer to integer data passed to glUniform1iv must be aligned to four bytes!'); #endif -#if MIN_WEBGL_VERSION >= 2 +#if MIN_WEBGL_VERSION >= 2 && !MEMORY64 #if GL_ASSERTIONS assert(GL.currentContext.version >= 2); #endif count && GLctx.uniform1iv(webglGetUniformLocation(location), HEAP32, value>>2, count); #else -#if MAX_WEBGL_VERSION >= 2 +#if MAX_WEBGL_VERSION >= 2 && !MEMORY64 if ({{{ isCurrentContextWebGL2() }}}) { // WebGL 2 provides new garbage-free entry points to call to WebGL. Use those always when possible. count && GLctx.uniform1iv(webglGetUniformLocation(location), HEAP32, value>>2, count); return; @@ -2364,17 +2373,17 @@ var LibraryGL = { glUniform2iv: (location, count, value) => { #if GL_ASSERTIONS GL.validateGLObjectID(GLctx.currentProgram.uniformLocsById, location, 'glUniform2iv', 'location'); - assert((value & 3) == 0, 'Pointer to integer data passed to glUniform2iv must be aligned to four bytes!'); + assert({{{ isPtrAligned('value', 4) }}}, 'Pointer to integer data passed to glUniform2iv must be aligned to four bytes!'); #endif -#if MIN_WEBGL_VERSION >= 2 +#if MIN_WEBGL_VERSION >= 2 && !MEMORY64 #if GL_ASSERTIONS assert(GL.currentContext.version >= 2); #endif count && GLctx.uniform2iv(webglGetUniformLocation(location), HEAP32, value>>2, count*2); #else -#if MAX_WEBGL_VERSION >= 2 +#if MAX_WEBGL_VERSION >= 2 && !MEMORY64 if ({{{ isCurrentContextWebGL2() }}}) { // WebGL 2 provides new garbage-free entry points to call to WebGL. Use those always when possible. count && GLctx.uniform2iv(webglGetUniformLocation(location), HEAP32, value>>2, count*2); return; @@ -2409,17 +2418,17 @@ var LibraryGL = { glUniform3iv: (location, count, value) => { #if GL_ASSERTIONS GL.validateGLObjectID(GLctx.currentProgram.uniformLocsById, location, 'glUniform3iv', 'location'); - assert((value & 3) == 0, 'Pointer to integer data passed to glUniform3iv must be aligned to four bytes!'); + assert({{{ isPtrAligned('value', 4) }}}, 'Pointer to integer data passed to glUniform3iv must be aligned to four bytes!'); #endif -#if MIN_WEBGL_VERSION >= 2 +#if MIN_WEBGL_VERSION >= 2 && !MEMORY64 #if GL_ASSERTIONS assert(GL.currentContext.version >= 2); #endif count && GLctx.uniform3iv(webglGetUniformLocation(location), HEAP32, value>>2, count*3); #else -#if MAX_WEBGL_VERSION >= 2 +#if MAX_WEBGL_VERSION >= 2 && !MEMORY64 if ({{{ isCurrentContextWebGL2() }}}) { // WebGL 2 provides new garbage-free entry points to call to WebGL. Use those always when possible. count && GLctx.uniform3iv(webglGetUniformLocation(location), HEAP32, value>>2, count*3); return; @@ -2455,24 +2464,24 @@ var LibraryGL = { glUniform4iv: (location, count, value) => { #if GL_ASSERTIONS GL.validateGLObjectID(GLctx.currentProgram.uniformLocsById, location, 'glUniform4iv', 'location'); - assert((value & 3) == 0, 'Pointer to integer data passed to glUniform4iv must be aligned to four bytes!'); + assert({{{ isPtrAligned('value', 4) }}}, 'Pointer to integer data passed to glUniform4iv must be aligned to four bytes!'); #endif -#if MIN_WEBGL_VERSION >= 2 +#if MIN_WEBGL_VERSION >= 2 && !MEMORY64 #if GL_ASSERTIONS assert(GL.currentContext.version >= 2); #endif count && GLctx.uniform4iv(webglGetUniformLocation(location), HEAP32, value>>2, count*4); #else -#if MAX_WEBGL_VERSION >= 2 +#if MAX_WEBGL_VERSION >= 2 && !MEMORY64 if ({{{ isCurrentContextWebGL2() }}}) { // WebGL 2 provides new garbage-free entry points to call to WebGL. Use those always when possible. count && GLctx.uniform4iv(webglGetUniformLocation(location), HEAP32, value>>2, count*4); return; } #endif -#if GL_POOL_TEMP_BUFFERS +#if GL_POOL_TEMP_BUFFERS && !MEMORY64 if (count <= {{{ GL_POOL_TEMP_BUFFERS_SIZE / 4 }}}) { // avoid allocation when uploading few enough uniforms var view = miniTempWebGLIntBuffers[4*count-1]; @@ -2502,24 +2511,24 @@ var LibraryGL = { glUniform1fv: (location, count, value) => { #if GL_ASSERTIONS GL.validateGLObjectID(GLctx.currentProgram.uniformLocsById, location, 'glUniform1fv', 'location'); - assert((value & 3) == 0, 'Pointer to float data passed to glUniform1fv must be aligned to four bytes!'); + assert({{{ isPtrAligned('value', 4) }}}, 'Pointer to float data passed to glUniform1fv must be aligned to four bytes!'); #endif -#if MIN_WEBGL_VERSION >= 2 +#if MIN_WEBGL_VERSION >= 2 && !MEMORY64 #if GL_ASSERTIONS assert(GL.currentContext.version >= 2); #endif count && GLctx.uniform1fv(webglGetUniformLocation(location), HEAPF32, value>>2, count); #else -#if MAX_WEBGL_VERSION >= 2 +#if MAX_WEBGL_VERSION >= 2 && !MEMORY64 if ({{{ isCurrentContextWebGL2() }}}) { // WebGL 2 provides new garbage-free entry points to call to WebGL. Use those always when possible. count && GLctx.uniform1fv(webglGetUniformLocation(location), HEAPF32, value>>2, count); return; } #endif -#if GL_POOL_TEMP_BUFFERS +#if GL_POOL_TEMP_BUFFERS && !MEMORY64 if (count <= {{{ GL_POOL_TEMP_BUFFERS_SIZE }}}) { // avoid allocation when uploading few enough uniforms var view = miniTempWebGLFloatBuffers[count-1]; @@ -2546,24 +2555,24 @@ var LibraryGL = { glUniform2fv: (location, count, value) => { #if GL_ASSERTIONS GL.validateGLObjectID(GLctx.currentProgram.uniformLocsById, location, 'glUniform2fv', 'location'); - assert((value & 3) == 0, 'Pointer to float data passed to glUniform2fv must be aligned to four bytes!'); + assert({{{ isPtrAligned('value', 4) }}}, 'Pointer to float data passed to glUniform2fv must be aligned to four bytes!'); #endif -#if MIN_WEBGL_VERSION >= 2 +#if MIN_WEBGL_VERSION >= 2 && !MEMORY64 #if GL_ASSERTIONS assert(GL.currentContext.version >= 2); #endif count && GLctx.uniform2fv(webglGetUniformLocation(location), HEAPF32, value>>2, count*2); #else -#if MAX_WEBGL_VERSION >= 2 +#if MAX_WEBGL_VERSION >= 2 && !MEMORY64 if ({{{ isCurrentContextWebGL2() }}}) { // WebGL 2 provides new garbage-free entry points to call to WebGL. Use those always when possible. count && GLctx.uniform2fv(webglGetUniformLocation(location), HEAPF32, value>>2, count*2); return; } #endif -#if GL_POOL_TEMP_BUFFERS +#if GL_POOL_TEMP_BUFFERS && !MEMORY64 if (count <= {{{ GL_POOL_TEMP_BUFFERS_SIZE / 2 }}}) { // avoid allocation when uploading few enough uniforms var view = miniTempWebGLFloatBuffers[2*count-1]; @@ -2591,24 +2600,24 @@ var LibraryGL = { glUniform3fv: (location, count, value) => { #if GL_ASSERTIONS GL.validateGLObjectID(GLctx.currentProgram.uniformLocsById, location, 'glUniform3fv', 'location'); - assert((value & 3) == 0, 'Pointer to float data passed to glUniform3fv must be aligned to four bytes!' + value); + assert({{{ isPtrAligned('value', 4) }}}, 'Pointer to float data passed to glUniform3fv must be aligned to four bytes!'); #endif -#if MIN_WEBGL_VERSION >= 2 +#if MIN_WEBGL_VERSION >= 2 && !MEMORY64 #if GL_ASSERTIONS assert(GL.currentContext.version >= 2); #endif count && GLctx.uniform3fv(webglGetUniformLocation(location), HEAPF32, value>>2, count*3); #else -#if MAX_WEBGL_VERSION >= 2 +#if MAX_WEBGL_VERSION >= 2 && !MEMORY64 if ({{{ isCurrentContextWebGL2() }}}) { // WebGL 2 provides new garbage-free entry points to call to WebGL. Use those always when possible. count && GLctx.uniform3fv(webglGetUniformLocation(location), HEAPF32, value>>2, count*3); return; } #endif -#if GL_POOL_TEMP_BUFFERS +#if GL_POOL_TEMP_BUFFERS && !MEMORY64 if (count <= {{{ GL_POOL_TEMP_BUFFERS_SIZE / 3 }}}) { // avoid allocation when uploading few enough uniforms var view = miniTempWebGLFloatBuffers[3*count-1]; @@ -2637,36 +2646,35 @@ var LibraryGL = { glUniform4fv: (location, count, value) => { #if GL_ASSERTIONS GL.validateGLObjectID(GLctx.currentProgram.uniformLocsById, location, 'glUniform4fv', 'location'); - assert((value & 3) == 0, 'Pointer to float data passed to glUniform4fv must be aligned to four bytes!'); + assert({{{ isPtrAligned('value', 4) }}}, 'Pointer to float data passed to glUniform4fv must be aligned to four bytes!'); #endif -#if MIN_WEBGL_VERSION >= 2 +#if MIN_WEBGL_VERSION >= 2 && !MEMORY64 #if GL_ASSERTIONS assert(GL.currentContext.version >= 2); #endif count && GLctx.uniform4fv(webglGetUniformLocation(location), HEAPF32, value>>2, count*4); #else -#if MAX_WEBGL_VERSION >= 2 +#if MAX_WEBGL_VERSION >= 2 && !MEMORY64 if ({{{ isCurrentContextWebGL2() }}}) { // WebGL 2 provides new garbage-free entry points to call to WebGL. Use those always when possible. count && GLctx.uniform4fv(webglGetUniformLocation(location), HEAPF32, value>>2, count*4); return; } #endif -#if GL_POOL_TEMP_BUFFERS +#if GL_POOL_TEMP_BUFFERS && !MEMORY64 if (count <= {{{ GL_POOL_TEMP_BUFFERS_SIZE / 4 }}}) { // avoid allocation when uploading few enough uniforms var view = miniTempWebGLFloatBuffers[4*count-1]; - // hoist the heap out of the loop for size and for pthreads+growth. + // hoist the heap out of the loop for pthreads+growth. var heap = HEAPF32; - value >>= 2; + {{{ convertPtrToIdx('value', 2) }}}; for (var i = 0; i < 4 * count; i += 4) { - var dst = value + i; - view[i] = heap[dst]; - view[i + 1] = heap[dst + 1]; - view[i + 2] = heap[dst + 2]; - view[i + 3] = heap[dst + 3]; + view[i] = heap[value++]; + view[i + 1] = heap[value++]; + view[i + 2] = heap[value++]; + view[i + 3] = heap[value++]; } } else #endif @@ -2688,24 +2696,24 @@ var LibraryGL = { glUniformMatrix2fv: (location, count, transpose, value) => { #if GL_ASSERTIONS GL.validateGLObjectID(GLctx.currentProgram.uniformLocsById, location, 'glUniformMatrix2fv', 'location'); - assert((value & 3) == 0, 'Pointer to float data passed to glUniformMatrix2fv must be aligned to four bytes!'); + assert({{{ isPtrAligned('value', 4) }}}, 'Pointer to float data passed to glUniformMatrix2fv must be aligned to four bytes!'); #endif -#if MIN_WEBGL_VERSION >= 2 +#if MIN_WEBGL_VERSION >= 2 && !MEMORY64 #if GL_ASSERTIONS assert(GL.currentContext.version >= 2); #endif count && GLctx.uniformMatrix2fv(webglGetUniformLocation(location), !!transpose, HEAPF32, value>>2, count*4); #else -#if MAX_WEBGL_VERSION >= 2 +#if MAX_WEBGL_VERSION >= 2 && !MEMORY64 if ({{{ isCurrentContextWebGL2() }}}) { // WebGL 2 provides new garbage-free entry points to call to WebGL. Use those always when possible. count && GLctx.uniformMatrix2fv(webglGetUniformLocation(location), !!transpose, HEAPF32, value>>2, count*4); return; } #endif -#if GL_POOL_TEMP_BUFFERS +#if GL_POOL_TEMP_BUFFERS && !MEMORY64 if (count <= {{{ GL_POOL_TEMP_BUFFERS_SIZE / 4 }}}) { // avoid allocation when uploading few enough uniforms var view = miniTempWebGLFloatBuffers[4*count-1]; @@ -2735,24 +2743,24 @@ var LibraryGL = { glUniformMatrix3fv: (location, count, transpose, value) => { #if GL_ASSERTIONS GL.validateGLObjectID(GLctx.currentProgram.uniformLocsById, location, 'glUniformMatrix3fv', 'location'); - assert((value & 3) == 0, 'Pointer to float data passed to glUniformMatrix3fv must be aligned to four bytes!'); + assert({{{ isPtrAligned('value', 4) }}}, 'Pointer to float data passed to glUniformMatrix3fv must be aligned to four bytes!'); #endif -#if MIN_WEBGL_VERSION >= 2 +#if MIN_WEBGL_VERSION >= 2 && !MEMORY64 #if GL_ASSERTIONS assert(GL.currentContext.version >= 2); #endif count && GLctx.uniformMatrix3fv(webglGetUniformLocation(location), !!transpose, HEAPF32, value>>2, count*9); #else -#if MAX_WEBGL_VERSION >= 2 +#if MAX_WEBGL_VERSION >= 2 && !MEMORY64 if ({{{ isCurrentContextWebGL2() }}}) { // WebGL 2 provides new garbage-free entry points to call to WebGL. Use those always when possible. count && GLctx.uniformMatrix3fv(webglGetUniformLocation(location), !!transpose, HEAPF32, value>>2, count*9); return; } #endif -#if GL_POOL_TEMP_BUFFERS +#if GL_POOL_TEMP_BUFFERS && !MEMORY64 if (count <= {{{ GL_POOL_TEMP_BUFFERS_SIZE / 9 }}}) { // avoid allocation when uploading few enough uniforms var view = miniTempWebGLFloatBuffers[9*count-1]; @@ -2787,48 +2795,47 @@ var LibraryGL = { glUniformMatrix4fv: (location, count, transpose, value) => { #if GL_ASSERTIONS GL.validateGLObjectID(GLctx.currentProgram.uniformLocsById, location, 'glUniformMatrix4fv', 'location'); - assert((value & 3) == 0, 'Pointer to float data passed to glUniformMatrix4fv must be aligned to four bytes!'); + assert({{{ isPtrAligned('value', 4) }}}, 'Pointer to float data passed to glUniformMatrix4fv must be aligned to four bytes!'); #endif -#if MIN_WEBGL_VERSION >= 2 +#if MIN_WEBGL_VERSION >= 2 && !MEMORY64 #if GL_ASSERTIONS assert(GL.currentContext.version >= 2); #endif count && GLctx.uniformMatrix4fv(webglGetUniformLocation(location), !!transpose, HEAPF32, value>>2, count*16); #else -#if MAX_WEBGL_VERSION >= 2 +#if MAX_WEBGL_VERSION >= 2 && !MEMORY64 if ({{{ isCurrentContextWebGL2() }}}) { // WebGL 2 provides new garbage-free entry points to call to WebGL. Use those always when possible. count && GLctx.uniformMatrix4fv(webglGetUniformLocation(location), !!transpose, HEAPF32, value>>2, count*16); return; } #endif -#if GL_POOL_TEMP_BUFFERS +#if GL_POOL_TEMP_BUFFERS && !MEMORY64 if (count <= {{{ GL_POOL_TEMP_BUFFERS_SIZE / 16 }}}) { // avoid allocation when uploading few enough uniforms var view = miniTempWebGLFloatBuffers[16*count-1]; - // hoist the heap out of the loop for size and for pthreads+growth. + // hoist the heap out of the loop for pthreads+growth. var heap = HEAPF32; - value >>= 2; + {{{ convertPtrToIdx('value', 2) }}}; for (var i = 0; i < 16 * count; i += 16) { - var dst = value + i; - view[i] = heap[dst]; - view[i + 1] = heap[dst + 1]; - view[i + 2] = heap[dst + 2]; - view[i + 3] = heap[dst + 3]; - view[i + 4] = heap[dst + 4]; - view[i + 5] = heap[dst + 5]; - view[i + 6] = heap[dst + 6]; - view[i + 7] = heap[dst + 7]; - view[i + 8] = heap[dst + 8]; - view[i + 9] = heap[dst + 9]; - view[i + 10] = heap[dst + 10]; - view[i + 11] = heap[dst + 11]; - view[i + 12] = heap[dst + 12]; - view[i + 13] = heap[dst + 13]; - view[i + 14] = heap[dst + 14]; - view[i + 15] = heap[dst + 15]; + view[i] = heap[value++]; + view[i + 1] = heap[value++]; + view[i + 2] = heap[value++]; + view[i + 3] = heap[value++]; + view[i + 4] = heap[value++]; + view[i + 5] = heap[value++]; + view[i + 6] = heap[value++]; + view[i + 7] = heap[value++]; + view[i + 8] = heap[value++]; + view[i + 9] = heap[value++]; + view[i + 10] = heap[value++]; + view[i + 11] = heap[value++]; + view[i + 12] = heap[value++]; + view[i + 13] = heap[value++]; + view[i + 14] = heap[value++]; + view[i + 15] = heap[value++]; } } else #endif @@ -2877,38 +2884,40 @@ var LibraryGL = { glVertexAttrib1fv: (index, v) => { #if GL_ASSERTIONS - assert((v & 3) == 0, 'Pointer to float data passed to glVertexAttrib1fv must be aligned to four bytes!'); + assert({{{ isPtrAligned('v', 4) }}}, 'Pointer to float data passed to glVertexAttrib1fv must be aligned to four bytes!'); assert(v != 0, 'Null pointer passed to glVertexAttrib1fv!'); #endif - GLctx.vertexAttrib1f(index, HEAPF32[v>>2]); + GLctx.vertexAttrib1f(index, HEAPF32[{{{ getHeapOffset('v', 'float') }}}]); }, glVertexAttrib2fv: (index, v) => { #if GL_ASSERTIONS - assert((v & 3) == 0, 'Pointer to float data passed to glVertexAttrib2fv must be aligned to four bytes!'); + assert({{{ isPtrAligned('v', 4) }}}, 'Pointer to float data passed to glVertexAttrib2fv must be aligned to four bytes!'); assert(v != 0, 'Null pointer passed to glVertexAttrib2fv!'); #endif - GLctx.vertexAttrib2f(index, HEAPF32[v>>2], HEAPF32[v+4>>2]); + {{{ convertPtrToIdx('v', 2) }}}; + GLctx.vertexAttrib2f(index, HEAPF32[v++], HEAPF32[v]); }, glVertexAttrib3fv: (index, v) => { #if GL_ASSERTIONS - assert((v & 3) == 0, 'Pointer to float data passed to glVertexAttrib3fv must be aligned to four bytes!'); + assert({{{ isPtrAligned('v', 4) }}}, 'Pointer to float data passed to glVertexAttrib3fv must be aligned to four bytes!'); assert(v != 0, 'Null pointer passed to glVertexAttrib3fv!'); #endif - GLctx.vertexAttrib3f(index, HEAPF32[v>>2], HEAPF32[v+4>>2], HEAPF32[v+8>>2]); + {{{ convertPtrToIdx('v', 2) }}}; + GLctx.vertexAttrib3f(index, HEAPF32[v++], HEAPF32[v++], HEAPF32[v]); }, glVertexAttrib4fv: (index, v) => { #if GL_ASSERTIONS - assert((v & 3) == 0, 'Pointer to float data passed to glVertexAttrib4fv must be aligned to four bytes!'); assert(v != 0, 'Null pointer passed to glVertexAttrib4fv!'); #endif - GLctx.vertexAttrib4f(index, HEAPF32[v>>2], HEAPF32[v+4>>2], HEAPF32[v+8>>2], HEAPF32[v+12>>2]); + {{{ convertPtrToIdx('v', 2) }}}; + GLctx.vertexAttrib4f(index, HEAPF32[v++], HEAPF32[v++], HEAPF32[v++], HEAPF32[v]); }, glGetAttribLocation: (program, name) => { @@ -3844,9 +3853,9 @@ var LibraryGL = { GLctx.multiDrawWebgl['multiDrawArraysWEBGL']( mode, HEAP32, - firsts >> 2, + {{{ getHeapOffset('firsts', 'i32') }}}, HEAP32, - counts >> 2, + {{{ getHeapOffset('counts', 'i32') }}}, drawcount); }, @@ -3856,11 +3865,11 @@ var LibraryGL = { GLctx.multiDrawWebgl['multiDrawArraysInstancedWEBGL']( mode, HEAP32, - firsts >> 2, + {{{ getHeapOffset('firsts', 'i32') }}}, HEAP32, - counts >> 2, + {{{ getHeapOffset('counts', 'i32') }}}, HEAP32, - instanceCounts >> 2, + {{{ getHeapOffset('instanceCounts', 'i32') }}}, drawcount); }, @@ -3871,25 +3880,25 @@ var LibraryGL = { GLctx.multiDrawWebgl['multiDrawElementsWEBGL']( mode, HEAP32, - counts >> 2, + {{{ getHeapOffset('counts', 'i32') }}}, type, HEAP32, - offsets >> 2, + {{{ getHeapOffset('offsets', 'i32') }}}, drawcount); }, - glMultiDrawElementsInstancedWEBGL__sig: 'viiiiii', + glMultiDrawElementsInstancedWEBGL__sig: 'vipippi', glMultiDrawElementsInstancedANGLE: 'glMultiDrawElementsInstancedWEBGL', glMultiDrawElementsInstancedWEBGL: (mode, counts, type, offsets, instanceCounts, drawcount) => { GLctx.multiDrawWebgl['multiDrawElementsInstancedWEBGL']( mode, HEAP32, - counts >> 2, + {{{ getHeapOffset('counts', 'i32') }}}, type, HEAP32, - offsets >> 2, + {{{ getHeapOffset('offsets', 'i32') }}}, HEAP32, - instanceCounts >> 2, + {{{ getHeapOffset('instanceCounts', 'i32') }}}, drawcount); }, diff --git a/src/library_webgl2.js b/src/library_webgl2.js index 59971cd42b793..46b17f1c5b727 100644 --- a/src/library_webgl2.js +++ b/src/library_webgl2.js @@ -157,20 +157,36 @@ var LibraryWebGL2 = { if (GLctx.currentPixelUnpackBufferBinding) { GLctx.texImage3D(target, level, internalFormat, width, height, depth, border, format, type, pixels); } else if (pixels) { +#if MEMORY64 + var pixelData = null; + if (pixels) pixelData = emscriptenWebGLGetTexPixelData(type, format, width, height*depth, pixels, 0); + GLctx.texImage3D(target, level, internalFormat, width, height, depth, border, format, type, pixelData); +#else var heap = heapObjectForWebGLType(type); GLctx.texImage3D(target, level, internalFormat, width, height, depth, border, format, type, heap, pixels >> heapAccessShiftForWebGLHeap(heap)); +#endif } else { GLctx.texImage3D(target, level, internalFormat, width, height, depth, border, format, type, null); } }, - glTexSubImage3D__deps: ['$heapObjectForWebGLType', '$heapAccessShiftForWebGLHeap'], + glTexSubImage3D__deps: ['$heapObjectForWebGLType', '$heapAccessShiftForWebGLHeap' +#if MEMORY64 + , '$emscriptenWebGLGetTexPixelData' +#endif + ], glTexSubImage3D: (target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, pixels) => { if (GLctx.currentPixelUnpackBufferBinding) { GLctx.texSubImage3D(target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, pixels); } else if (pixels) { +#if MEMORY64 + var pixelData = null; + if (pixels) pixelData = emscriptenWebGLGetTexPixelData(type, format, width, height*depth, pixels, 0); + GLctx.texSubImage3D(target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, pixelData); +#else var heap = heapObjectForWebGLType(type); GLctx.texSubImage3D(target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, heap, pixels >> heapAccessShiftForWebGLHeap(heap)); +#endif } else { GLctx.texSubImage3D(target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, null); } @@ -630,7 +646,7 @@ var LibraryWebGL2 = { assert((value & 3) == 0, 'Pointer to integer data passed to glClearBufferiv must be aligned to four bytes!'); #endif - GLctx.clearBufferiv(buffer, drawbuffer, HEAP32, value>>2); + GLctx.clearBufferiv(buffer, drawbuffer, HEAP32, {{{ getHeapOffset('value', "i32") }}}); }, glClearBufferuiv: (buffer, drawbuffer, value) => { @@ -638,7 +654,7 @@ var LibraryWebGL2 = { assert((value & 3) == 0, 'Pointer to integer data passed to glClearBufferuiv must be aligned to four bytes!'); #endif - GLctx.clearBufferuiv(buffer, drawbuffer, HEAPU32, value>>2); + GLctx.clearBufferuiv(buffer, drawbuffer, HEAP32, {{{ getHeapOffset('value', "u32") }}}); }, glClearBufferfv: (buffer, drawbuffer, value) => { @@ -646,7 +662,7 @@ var LibraryWebGL2 = { assert((value & 3) == 0, 'Pointer to float data passed to glClearBufferfv must be aligned to four bytes!'); #endif - GLctx.clearBufferfv(buffer, drawbuffer, HEAPF32, value>>2); + GLctx.clearBufferfv(buffer, drawbuffer, HEAPF32, {{{ getHeapOffset('value', 'float') }}}); }, glFenceSync: (condition, flags) => { @@ -784,7 +800,7 @@ var LibraryWebGL2 = { GL.validateGLObjectID(GLctx.currentProgram.uniformLocsById, location, 'glUniform1uiv', 'location'); assert((value & 3) == 0, 'Pointer to integer data passed to glUniform1uiv must be aligned to four bytes!'); #endif - count && GLctx.uniform1uiv(webglGetUniformLocation(location), HEAPU32, value>>2, count); + GLctx.uniform1uiv(webglGetUniformLocation(location), HEAPU32, {{{ getHeapOffset('value', 'u32') }}}, count); }, glUniform2uiv__deps: ['$webglGetUniformLocation'], @@ -793,7 +809,7 @@ var LibraryWebGL2 = { GL.validateGLObjectID(GLctx.currentProgram.uniformLocsById, location, 'glUniform2uiv', 'location'); assert((value & 3) == 0, 'Pointer to integer data passed to glUniform2uiv must be aligned to four bytes!'); #endif - count && GLctx.uniform2uiv(webglGetUniformLocation(location), HEAPU32, value>>2, count*2); + GLctx.uniform2uiv(webglGetUniformLocation(location), HEAPU32, {{{ getHeapOffset('value', 'u32') }}}, count*2); }, glUniform3uiv__deps: ['$webglGetUniformLocation'], @@ -802,7 +818,7 @@ var LibraryWebGL2 = { GL.validateGLObjectID(GLctx.currentProgram.uniformLocsById, location, 'glUniform3uiv', 'location'); assert((value & 3) == 0, 'Pointer to integer data passed to glUniform3uiv must be aligned to four bytes!'); #endif - count && GLctx.uniform3uiv(webglGetUniformLocation(location), HEAPU32, value>>2, count*3); + GLctx.uniform3uiv(webglGetUniformLocation(location), HEAPU32, {{{ getHeapOffset('value', 'u32') }}}, count*3); }, glUniform4uiv__deps: ['$webglGetUniformLocation'], @@ -811,7 +827,7 @@ var LibraryWebGL2 = { GL.validateGLObjectID(GLctx.currentProgram.uniformLocsById, location, 'glUniform4uiv', 'location'); assert((value & 3) == 0, 'Pointer to integer data passed to glUniform4uiv must be aligned to four bytes!'); #endif - count && GLctx.uniform4uiv(webglGetUniformLocation(location), HEAPU32, value>>2, count*4); + GLctx.uniform4uiv(webglGetUniformLocation(location), HEAPU32, {{{ getHeapOffset('value', 'u32') }}}, count*4); }, glUniformMatrix2x3fv__deps: ['$webglGetUniformLocation'], @@ -820,7 +836,7 @@ var LibraryWebGL2 = { GL.validateGLObjectID(GLctx.currentProgram.uniformLocsById, location, 'glUniformMatrix2x3fv', 'location'); assert((value & 3) == 0, 'Pointer to float data passed to glUniformMatrix2x3fv must be aligned to four bytes!'); #endif - count && GLctx.uniformMatrix2x3fv(webglGetUniformLocation(location), !!transpose, HEAPF32, value>>2, count*6); + GLctx.uniformMatrix2x3fv(webglGetUniformLocation(location), !!transpose, HEAPF32, {{{ getHeapOffset('value', 'float') }}}, count*6); }, glUniformMatrix3x2fv__deps: ['$webglGetUniformLocation'], @@ -829,7 +845,7 @@ var LibraryWebGL2 = { GL.validateGLObjectID(GLctx.currentProgram.uniformLocsById, location, 'glUniformMatrix3x2fv', 'location'); assert((value & 3) == 0, 'Pointer to float data passed to glUniformMatrix3x2fv must be aligned to four bytes!'); #endif - count && GLctx.uniformMatrix3x2fv(webglGetUniformLocation(location), !!transpose, HEAPF32, value>>2, count*6); + GLctx.uniformMatrix3x2fv(webglGetUniformLocation(location), !!transpose, HEAPF32, {{{ getHeapOffset('value', 'float') }}}, count*6); }, glUniformMatrix2x4fv__deps: ['$webglGetUniformLocation'], @@ -838,7 +854,7 @@ var LibraryWebGL2 = { GL.validateGLObjectID(GLctx.currentProgram.uniformLocsById, location, 'glUniformMatrix2x4fv', 'location'); assert((value & 3) == 0, 'Pointer to float data passed to glUniformMatrix2x4fv must be aligned to four bytes!'); #endif - count && GLctx.uniformMatrix2x4fv(webglGetUniformLocation(location), !!transpose, HEAPF32, value>>2, count*8); + GLctx.uniformMatrix2x4fv(webglGetUniformLocation(location), !!transpose, HEAPF32, {{{ getHeapOffset('value', 'float') }}}, count*8); }, glUniformMatrix4x2fv__deps: ['$webglGetUniformLocation'], @@ -847,7 +863,7 @@ var LibraryWebGL2 = { GL.validateGLObjectID(GLctx.currentProgram.uniformLocsById, location, 'glUniformMatrix4x2fv', 'location'); assert((value & 3) == 0, 'Pointer to float data passed to glUniformMatrix4x2fv must be aligned to four bytes!'); #endif - count && GLctx.uniformMatrix4x2fv(webglGetUniformLocation(location), !!transpose, HEAPF32, value>>2, count*8); + GLctx.uniformMatrix4x2fv(webglGetUniformLocation(location), !!transpose, HEAPF32, {{{ getHeapOffset('value', 'float') }}}, count*8); }, glUniformMatrix3x4fv__deps: ['$webglGetUniformLocation'], @@ -856,7 +872,7 @@ var LibraryWebGL2 = { GL.validateGLObjectID(GLctx.currentProgram.uniformLocsById, location, 'glUniformMatrix3x4fv', 'location'); assert((value & 3) == 0, 'Pointer to float data passed to glUniformMatrix3x4fv must be aligned to four bytes!'); #endif - count && GLctx.uniformMatrix3x4fv(webglGetUniformLocation(location), !!transpose, HEAPF32, value>>2, count*12); + GLctx.uniformMatrix3x4fv(webglGetUniformLocation(location), !!transpose, HEAPF32, {{{ getHeapOffset('value', 'float') }}}, count*12); }, glUniformMatrix4x3fv__deps: ['$webglGetUniformLocation'], @@ -865,7 +881,7 @@ var LibraryWebGL2 = { GL.validateGLObjectID(GLctx.currentProgram.uniformLocsById, location, 'glUniformMatrix4x3fv', 'location'); assert((value & 3) == 0, 'Pointer to float data passed to glUniformMatrix4x3fv must be aligned to four bytes!'); #endif - count && GLctx.uniformMatrix4x3fv(webglGetUniformLocation(location), !!transpose, HEAPF32, value>>2, count*12); + GLctx.uniformMatrix4x3fv(webglGetUniformLocation(location), !!transpose, HEAPF32, {{{ getHeapOffset('value', 'float') }}}, count*12); }, glVertexAttribI4iv: (index, v) => { @@ -873,7 +889,8 @@ var LibraryWebGL2 = { assert((v & 3) == 0, 'Pointer to integer data passed to glVertexAttribI4iv must be aligned to four bytes!'); assert(v != 0, 'Null pointer passed to glVertexAttribI4iv!'); #endif - GLctx.vertexAttribI4i(index, HEAP32[v>>2], HEAP32[v+4>>2], HEAP32[v+8>>2], HEAP32[v+12>>2]); + {{{ convertPtrToIdx('v', 2) }}} + GLctx.vertexAttribI4i(index, HEAP32[v++], HEAP32[v++], HEAP32[v++], HEAP32[v]); }, glVertexAttribI4uiv: (index, v) => { @@ -881,7 +898,8 @@ var LibraryWebGL2 = { assert((v & 3) == 0, 'Pointer to integer data passed to glVertexAttribI4uiv must be aligned to four bytes!'); assert(v != 0, 'Null pointer passed to glVertexAttribI4uiv!'); #endif - GLctx.vertexAttribI4ui(index, HEAPU32[v>>2], HEAPU32[v+4>>2], HEAPU32[v+8>>2], HEAPU32[v+12>>2]); + {{{ convertPtrToIdx('v', 2) }}} + GLctx.vertexAttribI4ui(index, HEAPU32[v++], HEAPU32[v++], HEAPU32[v++], HEAPU32[v]); }, glProgramParameteri: (program, pname, value) => { @@ -957,7 +975,7 @@ var LibraryWebGL2 = { glDrawArraysInstancedBaseInstance: 'glDrawArraysInstancedBaseInstanceWEBGL', glDrawArraysInstancedBaseInstanceANGLE: 'glDrawArraysInstancedBaseInstanceWEBGL', - glDrawElementsInstancedBaseVertexBaseInstanceWEBGL__sig: 'viiiiiii', + glDrawElementsInstancedBaseVertexBaseInstanceWEBGL__sig: 'viiipiii', glDrawElementsInstancedBaseVertexBaseInstanceWEBGL: (mode, count, type, offset, instanceCount, baseVertex, baseinstance) => { GLctx.dibvbi['drawElementsInstancedBaseVertexBaseInstanceWEBGL'](mode, count, type, offset, instanceCount, baseVertex, baseinstance); }, @@ -971,37 +989,37 @@ var LibraryWebGL2 = { emscripten_webgl_enable_WEBGL_draw_instanced_base_vertex_base_instance: (ctx) => webgl_enable_WEBGL_draw_instanced_base_vertex_base_instance(GL.contexts[ctx].GLctx), - glMultiDrawArraysInstancedBaseInstanceWEBGL__sig: 'viiiiii', + glMultiDrawArraysInstancedBaseInstanceWEBGL__sig: 'viipppi', glMultiDrawArraysInstancedBaseInstanceWEBGL: (mode, firsts, counts, instanceCounts, baseInstances, drawCount) => { GLctx.mdibvbi['multiDrawArraysInstancedBaseInstanceWEBGL']( mode, HEAP32, - firsts >> 2, + {{{ getHeapOffset('firsts', 'i32') }}}, HEAP32, - counts >> 2, + {{{ getHeapOffset('counts', 'i32') }}}, HEAP32, - instanceCounts >> 2, + {{{ getHeapOffset('instanceCounts', 'i32') }}}, HEAPU32, - baseInstances >> 2, + {{{ getHeapOffset('baseInstances', 'i32') }}}, drawCount); }, glMultiDrawArraysInstancedBaseInstanceANGLE: 'glMultiDrawArraysInstancedBaseInstanceWEBGL', - glMultiDrawElementsInstancedBaseVertexBaseInstanceWEBGL__sig: 'viiiiiiii', + glMultiDrawElementsInstancedBaseVertexBaseInstanceWEBGL__sig: 'vipippppi', glMultiDrawElementsInstancedBaseVertexBaseInstanceWEBGL: (mode, counts, type, offsets, instanceCounts, baseVertices, baseInstances, drawCount) => { GLctx.mdibvbi['multiDrawElementsInstancedBaseVertexBaseInstanceWEBGL']( mode, HEAP32, - counts >> 2, + {{{ getHeapOffset('counts', 'i32') }}}, type, HEAP32, - offsets >> 2, + {{{ getHeapOffset('offsets', 'i32') }}}, HEAP32, - instanceCounts >> 2, + {{{ getHeapOffset('instanceCounts', 'i32') }}}, HEAP32, - baseVertices >> 2, + {{{ getHeapOffset('baseVertices', 'i32') }}}, HEAPU32, - baseInstances >> 2, + {{{ getHeapOffset('baseInstances', 'i32') }}}, drawCount); }, glMultiDrawElementsInstancedBaseVertexBaseInstanceANGLE: 'glMultiDrawElementsInstancedBaseVertexBaseInstanceWEBGL', diff --git a/src/parseTools.js b/src/parseTools.js index 9d7296cfbab3c..88d9362368041 100644 --- a/src/parseTools.js +++ b/src/parseTools.js @@ -424,8 +424,13 @@ function makeSetValueImpl(ptr, pos, value, type) { function makeHEAPView(which, start, end) { const size = parseInt(which.replace('U', '').replace('F', '')) / 8; - const shift = Math.log2(size); - const mod = size == 1 ? '' : (CAN_ADDRESS_2GB || MEMORY64) ? ('>>>' + shift) : ('>>' + shift); + let mod; + if (MEMORY64) { + mod = size == 1 ? '' : ('/' + size); + } else { + const shift = Math.log2(size); + mod = size == 1 ? '' : CAN_ADDRESS_2GB ? ('>>>' + shift) : ('>>' + shift); + } return `HEAP${which}.subarray((${start})${mod}, (${end})${mod})`; } @@ -920,6 +925,34 @@ function to64(x) { return `BigInt(${x})`; } +// Generates an expression that tests whether a pointer (either a BigInt or a signed int32 JS Number) is aligned to the given byte multiple. +function isPtrAligned(ptr, alignment) { + if (MEMORY64) return /^\d+$/.test(alignment) ? `BigInt(${ptr}) % ${alignment}n == 0n` : `BigInt(${ptr}) % BigInt(${alignment}) == 0n`; + return `${ptr} % ${alignment} == 0`; +} + +const MAX_MEMORY53 = 2 ** 53; // == 9007199254740992 + +// Converts a pointer (either a BigInt or a signed int32 JS Number) in-place to an index on the heap (a BigInt or an unsigned JS Number). +// N.B. in ASSERTIONS mode may generate two statements (in form "a;b;"). +function convertPtrToIdx(ptr, accessWidth) { + const assertPointerAlignment = ASSERTIONS ? `assert(${isPtrAligned(ptr, `2 ** ${accessWidth}`)});` : ''; + + let conversion; + if (MEMORY64) { + // if our address space would ever get larger than 53 bits, we could do something like this: + // if (MAXIMUM_MEMORY > MAX_MEMORY53) conversion = /^\d+$/.test(accessWidth) ? `${ptr} >>= ${accessWidth}n` : `${ptr} >>= BigInt(${accessWidth})`; + assert(MAXIMUM_MEMORY <= MAX_MEMORY53); + conversion = accessWidth ? `${ptr} = ${ptr} / (2 ** ${accessWidth})` : ''; + } else if (CAN_ADDRESS_2GB) { + conversion = accessWidth ? `${ptr} >>>= ${accessWidth}` : ''; + } else { + conversion = accessWidth ? `${ptr} >>= ${accessWidth}` : ''; + } + + return assertPointerAlignment + conversion; +} + // Add assertions to catch common errors when using the Promise object we // create on Module.ready() and return from MODULARIZE Module() invocations. function addReadyPromiseAssertions(promise) {