emscripten
emscripten copied to clipboard
Chrome passes browser.test_sdl2_canvas_proxy, but should actually fail
Debugging the failure of browser.test_sdl2_canvas_proxy in Firefox, it turns out that Chrome is behaving in a nonstandard manner in its WebGL2 implementation, which hides a SDL2 Emscripten port bug, and causes the test to accidentally pass.
In Firefox the test fails as is correct, unmasking the SDL2 bug.
Reported the Chrome bug in https://issues.chromium.org/issues/448407149
What is happening is that SDL2 attempts to compile the following fragment shader:
#extension GL_OES_EGL_image_external : require
#define mediump
#define highp
#define lowp
#define SDL_TEXCOORD_PRECISION
uniform samplerExternalOES u_texture;
varying mediump vec4 v_color;
varying SDL_TEXCOORD_PRECISION vec2 v_texCoord;
void main()
{
gl_FragColor = texture2D(u_texture, v_texCoord);
gl_FragColor *= v_color;
}
but GL_OES_EGL_image_external is not a ratified WebGL extension, and samplerExternalOES is not a valid keyword in WebGL. I.e. SDL2 is leaking a native EGL+OpenGLES2/3 extension shader into WebGL.
Still, Chrome happily compiles and links the above shader. That shader doesn't do anything in the browser.test_sdl2_canvas_proxy, it just is getting compiled in by SDL2, but never activated (it is not part of the test)
Firefox croaks on the above unrecognized shader, and because browser.test_sdl2_canvas_proxy is testing the ancient asynchronously proxied WebGL support, then there is this code in the proxying implementation:
43: { name: 'getShaderParameter', func: () => {assert(ctx.getShaderParameter(objects[buffer[i++]], buffer[i++]), 'we cannot handle errors, we are async proxied WebGL') },
which assert-fails in Firefox, as it should. Chrome is silently passing past since it compiled the shader.
After sidestepping the above assert(), there is still some issue at play with respect to the async proxied WebGL Worker mechanism and Emscripten's test harness : if I run the compiled test code outside Emscripten test harness in the emrun ad hoc server (with proxying enabled), the test will always pass.
But if I run the test case inside the Emscripten test harness, the rendered screen will always stay completely black.
If I disable --proxy-to-worker and @proxied directives in browser.test_sdl2_canvas_alpha, then the test also passes in Firefox in the Emscripten test harness. So the black screen issue is somehow related to proxying+Emscripten harness+Firefox. Maybe some kind of race condition.
Oh, and there's a long standing issue that was never fixed that is needed to make the test get past SDL2 context init: https://github.com/emscripten-core/emscripten/issues/7100
That can be fixed with this patch:
diff --git a/test/browser/test_sdl2_canvas_proxy.c b/test/browser/test_sdl2_canvas_proxy.c
index 69ca32b8f..7a3d8b569 100644
--- a/test/browser/test_sdl2_canvas_proxy.c
+++ b/test/browser/test_sdl2_canvas_proxy.c
@@ -11,6 +11,8 @@
#include <assert.h>
#include <emscripten.h>
+void unusedRaf() {}
+
int main(int argc, char **argv) {
FILE *f = fopen("data.txt", "rb");
assert(f);
@@ -27,8 +29,12 @@ int main(int argc, char **argv) {
SDL_Window *window;
SDL_Renderer *renderer;
+ emscripten_set_main_loop(unusedRaf, 0, 0);
+
SDL_CreateWindowAndRenderer(600, 450, 0, &window, &renderer);
+ emscripten_set_main_loop_timing(EM_TIMING_RAF, 0);
+
SDL_Surface *screen = SDL_CreateRGBSurface(0, 600, 450, 32, 0, 0, 0, 0);
SDL_LockSurface(screen);
@@ -47,6 +53,12 @@ int main(int argc, char **argv) {
// Don't quit - we need to reftest the canvas! SDL_Quit();
It seems to me that SDL2 users currently are all getting those emscripten_set_main_loop_timing: Cannot set timing mode for main loop since a main loop does not exist! Call emscripten_set_main_loop first to set one up. and Looks like you are rendering without using requestAnimationFrame for the main loop. You should use 0 for the frame rate in emscripten_set_main_loop in order to use requestAnimationFrame, as that can greatly improve your frame rates! warning spams.
In Emscripten test harness, that warning spam is turned into errors (by -Werror ?), so creating a SDL2 renderer doesn't work without those manual main loop tweaks sandwiched around SDL_CreateWindowAndRenderer().
I don't see any way in which the Cannot set timing mode for main loop since a main loop does not exist warning could ever be an error so I guess that tests are depending on emscripten_set_main_loop_timing not running into this condition maybe?
I don't see any way in which the
Cannot set timing mode for main loop since a main loop does not existwarning could ever be an error so I guess that tests are depending onemscripten_set_main_loop_timingnot running into this condition maybe?
Err, you are right. I now re-checked and those set_main_loop_timing prints were not actually causing the error, but it was the proxying assert all along.
I reopened https://github.com/emscripten-core/emscripten/issues/7100 so we can address that error spam
Turns out https://github.com/emscripten-core/emscripten/pull/25439 was all that was needed to fix the test in Firefox.