Using SDL_GL_SwapWindow() with Emscripten

When compiled with Emscripten I’m getting rendering anomalies (periodic black frames, resulting in ‘flashing’). This happens only on Safari, and only when using SDL_GL_SwapWindow(). Everything is fine with other browsers (those based on the Chrome engine, and Firefox) or when using SDL_RenderPresent() rather than SDL_GL_SwapWindow().

I’m yielding back to the browser immediately after calling SDL_GL_SwapWindow() or SDL_RenderPresent() so that the drawn frame can be displayed, which I believe is the correct way to do it. It means I am relying on SDL_GL_SwapWindow() not returning until the internal frame buffer has been updated; I’m not sure that is guaranteed, but I don’t know how else to do it.

Under the hood, are there differences between SDL_RenderPresent() and SDL_GL_SwapWindow() which might be important when using Emscripten?

So SDL_GL_SwapWindow will eventually call eglSwapBuffers in Emscripten and also work as a point to give control to the browser in case you are using asincify.

I think eglSwapBuffers doesn’t do anything unless the call is coming from a worker. I think the browser should naturally do the swap and that call is not needed. You mention it only happens in Safari when using it, so if you just remove it does it work alright in Safari and all other browsers?

I am not familiar with the SDL renderer so I don’t know what the other call does.

I’m not using asyncify, I’m explicitly returning control to the browser by exiting the mainloop after I’ve drawn my scene.

You mention it only happens in Safari when using it, so if you just remove it does it work alright in Safari and all other browsers?

I’d not tried that, but have now done so and it makes no difference at all (which is consistent with your belief that it does nothing in WebGL). So it’s not so much the call to SDL_GL_SwapWindow() which triggers the issue, but that I am drawing my scene using shaders (the heavy-lifting is done in glDrawArrays()) and not calling SDL_RenderPresent().

An additional piece of information is that this unwanted ‘flashing’ bevahior appeared in a fairly recent Emscripten update, earlier versions work OK and later versions exhibit the effect. I’ve bisected it to see exactly what the precise change was, but the Emscripten people cannot see how that change (which was related to timers) could have any effect at all on rendering, but it clearly does.

Hey, what GL are you using? Like, are you using WebGL or some layer of emulation (say OpenGL ES2 or some other)? Asking just because these emulations are some JS hacks in case there some timer in one of them - there probably isn’t, but I don’t know, haven’t looked into them looking for it.

WebGL, yes. The key call is glDrawArrays() which draws my scene using custom shaders.

Having discovered that SDL_GL_SwapWindow() seemingly does nothing and can be omitted, I tried replacing it with a glFlush() or glFinish() but it makes no difference either.

Found a mention here in their webgl saying that swap behavior is implicit

Yes I know it’s in a different line, but if you look you can see that Emscripten webgl isn’t REALLY WebGL as it tries to harmonize different implementations and versions…

Unfortunately now that I see this and reread your comment on timers, I ask if this is pthreads related and what kind of drawings are performed in the worker.

My experience with pthreads is that it’s not dependable yet, if you go in Unity Technologies GitHub organization you can see they have locked themselves in an older version of Emscripten - I think juj freelance for them too.

Anyway, if it’s flashing black/correct there has to be a point where it’s yielded to the browser but the canvas buffered has been cleared and other where the drawing has happened. If you only yield in one place in your code, then there has to be a way that state changes.

Other approach though is to open an issue in WebKit and mention that it has a different behavior between Chrome and Safari in macOS and then open a feedback on Apple development. When something has a different behavior they usually monitor a bit closely although they are silent about it - you will see many status changes in the issue, but no one will answer.

I’ve double-checked everything and I can’t see any way that it can yield back to the browser with the canvas not correctly drawn. In any case if it did ever do that it would surely fail on other browsers too, not just Safari.

What is interesting is that SDL_RenderPresent() doesn’t fail in the same way. Does it use shaders in the Emscripten build? If so it must be using code similar to mine so I wonder what the difference is.