From 2b6781eab49617d0ecaf32ec55f15b65e52db31b Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Mon, 26 Aug 2024 14:48:08 -0700 Subject: [PATCH] Fix calls to glCcompressedTexImage2D with null pixel data I believe this has always been an issue with emscripten's WebGL1 code which only recently became more prevalent with #21445. Fixes: #19300 --- src/library_webgl.js | 9 +++++++-- test/browser/test_anisotropic.c | 10 ++++++++++ test/test_browser.py | 8 ++++++-- 3 files changed, 23 insertions(+), 4 deletions(-) diff --git a/src/library_webgl.js b/src/library_webgl.js index fba440eb4b43..2d32c24f1ff4 100644 --- a/src/library_webgl.js +++ b/src/library_webgl.js @@ -1520,6 +1520,11 @@ for (/**@suppress{duplicate}*/var i = 0; i <= {{{ GL_POOL_TEMP_BUFFERS_SIZE }}}; }, glCompressedTexImage2D: (target, level, internalFormat, width, height, border, imageSize, data) => { + // `data` may be null here, which means "allocate uniniitalized space but + // don't upload" in GLES parlance, but `compressedTexImage2D` requires the + // final data parameter, so we simply pass a heap view starting at zero + // effectively uploading whatever happens to be near address zero. See + // https://github.com/emscripten-core/emscripten/issues/19300. #if MAX_WEBGL_VERSION >= 2 if ({{{ isCurrentContextWebGL2() }}}) { if (GLctx.currentPixelUnpackBufferBinding || !imageSize) { @@ -1533,7 +1538,7 @@ for (/**@suppress{duplicate}*/var i = 0; i <= {{{ GL_POOL_TEMP_BUFFERS_SIZE }}}; } #endif #if INCLUDE_WEBGL1_FALLBACK - GLctx.compressedTexImage2D(target, level, internalFormat, width, height, border, data ? {{{ makeHEAPView('U8', 'data', 'data+imageSize') }}} : null); + GLctx.compressedTexImage2D(target, level, internalFormat, width, height, border, {{{ makeHEAPView('U8', 'data', 'data+imageSize') }}}); #endif }, @@ -1552,7 +1557,7 @@ for (/**@suppress{duplicate}*/var i = 0; i <= {{{ GL_POOL_TEMP_BUFFERS_SIZE }}}; } #endif #if INCLUDE_WEBGL1_FALLBACK - GLctx.compressedTexSubImage2D(target, level, xoffset, yoffset, width, height, format, data ? {{{ makeHEAPView('U8', 'data', 'data+imageSize') }}} : null); + GLctx.compressedTexSubImage2D(target, level, xoffset, yoffset, width, height, format, {{{ makeHEAPView('U8', 'data', 'data+imageSize') }}}); #endif }, diff --git a/test/browser/test_anisotropic.c b/test/browser/test_anisotropic.c index 7b100cff34bb..23b75d92081d 100644 --- a/test/browser/test_anisotropic.c +++ b/test/browser/test_anisotropic.c @@ -115,7 +115,12 @@ int main(int argc, char *argv[]) while (level < 5) { printf("uploading level %d: %d, %d\n", level, w, h); assert(!glGetError()); +#if TEST_TEXSUBIMAGE + glCompressedTexImage2D(GL_TEXTURE_2D, level, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, w, h, 0, w*h, NULL); + glCompressedTexSubImage2D(GL_TEXTURE_2D, level, 0, 0, w, h, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, w*h, curr); +#else glCompressedTexImage2D(GL_TEXTURE_2D, level, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, w, h, 0, w*h, curr); +#endif assert(!glGetError()); curr += MAX(w, 4)*MAX(h, 4); w /= 2; @@ -136,7 +141,12 @@ int main(int argc, char *argv[]) while (level < 5) { printf("uploading level %d: %d, %d\n", level, w, h); assert(!glGetError()); +#if TEST_TEXSUBIMAGE + glCompressedTexImage2D(GL_TEXTURE_2D, level, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, w, h, 0, w*h, NULL); + glCompressedTexSubImage2D(GL_TEXTURE_2D, level, 0, 0, w, h, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, w*h, curr); +#else glCompressedTexImage2D(GL_TEXTURE_2D, level, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, w, h, 0, w*h, curr); +#endif assert(!glGetError()); curr += MAX(w, 4)*MAX(h, 4); w /= 2; diff --git a/test/test_browser.py b/test/test_browser.py index 4b79abbab509..bd3729447e89 100644 --- a/test/test_browser.py +++ b/test/test_browser.py @@ -2185,9 +2185,13 @@ def test_s3tc_ffp_only(self): self.reftest('s3tc.c', 's3tc.png', args=['--preload-file', 'screenshot.dds', '-sLEGACY_GL_EMULATION', '-sGL_FFP_ONLY', '-lGL', '-lSDL']) @requires_graphics_hardware - def test_anisotropic(self): + @parameterized({ + '': ([],), + 'subimage': (['-DTEST_TEXSUBIMAGE'],), + }) + def test_anisotropic(self, args): shutil.copyfile(test_file('browser/water.dds'), 'water.dds') - self.reftest('test_anisotropic.c', 'test_anisotropic.png', reference_slack=2, args=['--preload-file', 'water.dds', '-sLEGACY_GL_EMULATION', '-lGL', '-lSDL', '-Wno-incompatible-pointer-types']) + self.reftest('test_anisotropic.c', 'test_anisotropic.png', reference_slack=2, args=['--preload-file', 'water.dds', '-sLEGACY_GL_EMULATION', '-lGL', '-lSDL', '-Wno-incompatible-pointer-types'] + args) @requires_graphics_hardware def test_tex_nonbyte(self):