diff --git a/src/lib/libwebgl.js b/src/lib/libwebgl.js index bc6a602734487..27e2eb065c899 100644 --- a/src/lib/libwebgl.js +++ b/src/lib/libwebgl.js @@ -330,6 +330,10 @@ for (/**@suppress{duplicate}*/var i = 0; i <= {{{ GL_POOL_TEMP_BUFFERS_SIZE }}}; unpackAlignment: 4, // default alignment is 4 bytes unpackRowLength: 0, +#if INCLUDE_WEBGL1_FALLBACK && MAX_WEBGL_VERSION >= 2 + packRowLength: 0, +#endif + // Records a GL error condition that occurred, stored until user calls // glGetError() to fetch it. As per GLES2 spec, only the first error is // remembered, and subsequent errors are discarded until the user has @@ -1289,6 +1293,10 @@ for (/**@suppress{duplicate}*/var i = 0; i <= {{{ GL_POOL_TEMP_BUFFERS_SIZE }}}; GL.unpackAlignment = param; } else if (pname == {{{ cDefs.GL_UNPACK_ROW_LENGTH }}}) { GL.unpackRowLength = param; +#if INCLUDE_WEBGL1_FALLBACK && MAX_WEBGL_VERSION >= 2 + } else if (pname == {{{ cDefs.GL_PACK_ROW_LENGTH }}}) { + GL.packRowLength = param; +#endif } GLctx.pixelStorei(pname, param); }, @@ -1773,7 +1781,12 @@ for (/**@suppress{duplicate}*/var i = 0; i <= {{{ GL_POOL_TEMP_BUFFERS_SIZE }}}; } #endif #if INCLUDE_WEBGL1_FALLBACK - var pixelData = emscriptenWebGLGetTexPixelData(type, format, width, height, pixels); +#if MAX_WEBGL_VERSION >= 2 + var stride = Math.max(width, GL.packRowLength); +#else + var stride = width; // GL_PACK_ROW_LENGTH does not exist yet in WebGL 1. +#endif + var pixelData = emscriptenWebGLGetTexPixelData(type, format, stride, height, pixels); if (!pixelData) { GL.recordError(0x500/*GL_INVALID_ENUM*/); #if GL_ASSERTIONS diff --git a/src/struct_info.json b/src/struct_info.json index e4852a0b44b92..88e0afb7fd228 100644 --- a/src/struct_info.json +++ b/src/struct_info.json @@ -1317,6 +1317,7 @@ { "file": "GL/gl.h", "defines": [ + "GL_PACK_ROW_LENGTH", "GL_UNPACK_ALIGNMENT", "GL_UNPACK_ROW_LENGTH" ] diff --git a/src/struct_info_generated.json b/src/struct_info_generated.json index 54c755a8dd05c..9517cd8a3333e 100644 --- a/src/struct_info_generated.json +++ b/src/struct_info_generated.json @@ -301,6 +301,7 @@ "File::DirectoryKind": 2, "File::SymlinkKind": 3, "File::UnknownKind": 0, + "GL_PACK_ROW_LENGTH": 3330, "GL_UNPACK_ALIGNMENT": 3317, "GL_UNPACK_ROW_LENGTH": 3314, "ICANON": 2, diff --git a/test/browser/webgl2_readpixels_pack_row_length.c b/test/browser/webgl2_readpixels_pack_row_length.c new file mode 100644 index 0000000000000..00484e8514810 --- /dev/null +++ b/test/browser/webgl2_readpixels_pack_row_length.c @@ -0,0 +1,31 @@ +// Tests that glReadPixels() works when GL_PACK_ROW_LENGTH > read width. +#include +#include +#include +#include + +int main() { + EmscriptenWebGLContextAttributes attrs; + emscripten_webgl_init_context_attributes(&attrs); + attrs.majorVersion = 2; + EMSCRIPTEN_WEBGL_CONTEXT_HANDLE ctx = emscripten_webgl_create_context("#canvas", &attrs); + emscripten_webgl_make_context_current(ctx); + + // Clear framebuffer to red. + glClearColor(1, 0, 0, 1); + glClear(GL_COLOR_BUFFER_BIT); + + // Read 8 pixels wide into a buffer with row length 32. + glPixelStorei(GL_PACK_ROW_LENGTH, 32); + GLubyte buf[32 * 2 * 4]; + memset(buf, 0, sizeof(buf)); + glReadPixels(0, 0, 8, 2, GL_RGBA, GL_UNSIGNED_BYTE, buf); + + // Verify pixel at (0,0) is red. + assert(buf[0] == 255 && buf[1] == 0 && buf[2] == 0 && buf[3] == 255); + + // Verify that pixel at (0,1) was read to address at stride 32 (pixels), so is red as well. + assert(buf[32*4] == 255 && buf[32*4+1] == 0 && buf[32*4+2] == 0 && buf[32*4+3] == 255); + + return 0; +} diff --git a/test/test_browser.py b/test/test_browser.py index e4dd6ebeabe35..fb08607873a04 100644 --- a/test/test_browser.py +++ b/test/test_browser.py @@ -1255,6 +1255,10 @@ def test_webgl2_ubo_layout_binding(self): def test_webgl2_texsubimage3d(self): self.btest_exit('webgl2_texsubimage3d.c', cflags=['-sMIN_WEBGL_VERSION=2']) + @requires_webgl2 + def test_webgl2_readpixels(self): + self.btest_exit('webgl2_readpixels_pack_row_length.c', cflags=['-sMIN_WEBGL_VERSION=2']) + # Test that -sGL_PREINITIALIZED_CONTEXT works and allows user to set Module['preinitializedWebGLContext'] to a preinitialized WebGL context. @requires_graphics_hardware def test_preinitialized_webgl_context(self):