Need help -- Why does this code fail? SDL2 and OpenGL ES 3

587 views
Skip to first unread message

Anton Strickland

unread,
Oct 30, 2021, 9:46:19 PM10/30/21
to emscripten-discuss
I have been stuck on a very simple issue for multiple days and need someone who knows what they are doing. I'm trying to use SDL2 and WebGL2 (OpenGL ES 3) and sometimes it works, but sometimes it doesn't, depending on seemingly arbitrary code. Please help. See here for the full details and source code:


Basically, I have a simple program (just over 100 lines of code) that changes the background color of the screen by calling glClear(). Probably the most basic OpenGL program one can write. When the color is pink, that means it's working, and when it's black, it's not working. In the above link there is main.cpp which works correctly. I have been doing trial and error for this past week commenting out random lines of code to isolate the problem, but it seems like changing arbitrary lines of code stops it from working. I've noticed that it happens when calling some SDL functions, but even just commenting out printing to the console is enough to break it. See main.cpp for details.

I don't know if this is just an issue with me not understanding how this works or if this is an actual bug in emscripten or the SDL port. it's frustrating because when it works, it works all the way (I can use shaders and textures to have a working app), but if I change just a tiny little thing (even just commenting out an unrelated line of code), suddenly nothing works at all. I have no idea where to even start debugging this.

I would imagine that there has to be a way to do this since people are obviously making WebGL games in C++, but since there are no tutorials online for how to do that it becomes impossible to even set up a simple "hello world" script. I purchased a book on how to make games in web assembly but they use the SDL renderer and not OpenGL rendering. Other OpenGL web assembly tutorials just use OpenGL without SDL. Surely there must be a way to use them together as I have done for my desktop app?

I have already reached out on the discord but to no avail so far. Someone suggested adding -fsanitize=address when compiling but that actually causes the above working code to stop working. I don't really have the time to just wait for an answer so I'm hoping this post will get the attention of more people.

So I know this is getting long, but I'm very confused. Since technically by code works, but it's one step away from breaking, and I have no idea what that step is or why. My ultimate goal is to copy and paste this code into a larger project, but every time I do so, it results in a black screen with no indication of what I did wrong.

I would like to understand a few things: 
  • Is this a problem with my code, my makefile, SDL, or emscripten?
  • If this is not a problem with my code, is someone going to fix the issue?
  • If my desktop code is Open GL 3.3, should I be using OpenGL ES 3 or is that part of the problem? And what files do I need to include and where do I get them (if what I have isn't correct?)
  • What is the proper way to set up an emscripten webgl context? My source code includes two different ways of setting it up and I am not sure which is correct, even after trial and error.
  • Can I get someone who is willing to at least compile the code themselves and try out different solutions until they find something that can provide an explanation? I don't want someone to suggest adding a single argument to my makefile, and then hours later I get home to try it out and realize that it actually causes the program to fail. My program is small enough that someone can copy and paste it together, compile it, and run it in less than 2 minutes. There is no reason to not do that yourself to check that it works before suggesting a solution to me. I am just a little frustrated at this point so please don't take it the wrong way, I just want someone to take me seriously so I can move on to the next step of my project.
  • If this mailing list is not the best place to quickly get help like that, who do I need to contact? I am willing to pay for work if that needs to be done, but I don't think that should be necessary to get a "hello world" program up and running, especially when I've already come this far on my own.


Shlomi Fish

unread,
Oct 31, 2021, 1:23:53 AM10/31/21
to emscripte...@googlegroups.com
Hi all!

On Sat, 30 Oct 2021 18:46:19 -0700 (PDT)
Anton Strickland <antonmst...@gmail.com> wrote:

> I have been stuck on a very simple issue for multiple days and need someone
> who knows what they are doing. I'm trying to use SDL2 and WebGL2 (OpenGL ES
> 3) and sometimes it works, but sometimes it doesn't, depending on seemingly
> arbitrary code. Please help. See here for the full details and source code:
>
> https://gist.github.com/AntonStrickland/433c911151ca73826ee679b120fe8d9e
>

Note that I was able to reproduce the issue on fedora v34 x86-64 with firefox:

```
System:
Host: telaviv1.shlomifish.org Kernel: 5.14.14-200.fc34.x86_64 x86_64
bits: 64 Desktop: Xfce 4.16.0 Distro: Fedora release 34 (Thirty Four)
CPU:
Info: Dual Core model: Intel Core i3-2100 bits: 64 type: MT MCP cache:
L2: 3 MiB
Speed: 2750 MHz min/max: 1600/3100 MHz Core speeds (MHz): 1: 2750
2: 2698 3: 2709 4: 2694
Graphics:
Device-1: Intel 2nd Generation Core Processor Family Integrated Graphics
driver: i915 v: kernel Display: x11 server: X.Org 1.20.11 driver: loaded:
modesetting unloaded: fbdev,vesa resolution: 1920x1080~60Hz
OpenGL: renderer: Mesa DRI Intel HD Graphics 2000 (SNB GT1)
v: 3.3 Mesa 21.1.8
```

As a side note: main.cpp has some trailing whitespace:
https://perl-begin.org/tutorials/bad-elements/#trailing-whitespace
> - Is this a problem with my code, my makefile, SDL, or emscripten?
> - If this is not a problem with my code, is someone going to fix the
> issue?
> - If my desktop code is Open GL 3.3, should I be using OpenGL ES 3 or is
> that part of the problem? And what files do I need to include and where do
> I get them (if what I have isn't correct?)
> - What is the proper way to set up an emscripten webgl context? My
> source code includes two different ways of setting it up and I am not sure
> which is correct, even after trial and error.
> - Can I get someone who is willing to at least compile the code
> themselves and try out different solutions until they find something that
> can provide an explanation? I don't want someone to suggest adding a
> single argument to my makefile, and then hours later I get home to try it out
> and realize that it actually causes the program to fail. My program is small
> enough that someone can copy and paste it together, compile it, and run it
> in less than 2 minutes. There is no reason to not do that yourself to
> check that it works before suggesting a solution to me. I am just a little
> frustrated at this point so please don't take it the wrong way, I just
> want someone to take me seriously so I can move on to the next step of my
> project.
> - If this mailing list is not the best place to quickly get help like
> that, who do I need to contact? I am willing to pay for work if that needs
> to be done, but I don't think that should be necessary to get a "hello
> world" program up and running, especially when I've already come this far
> on my own.
>
>
>



--

Shlomi Fish https://www.shlomifish.org/
Free (Creative Commons) Music Downloads, Reviews and more - https://jamendo.com/

<LeoNerd> “I hear eclipse is really nice, but I’m still waiting for it to
load.”
— Freenode’s #perl

Please reply to list if it's a mailing list post - https://shlom.in/reply .

Anton Strickland

unread,
Nov 1, 2021, 7:38:16 AM11/1/21
to emscripten-discuss
I'm glad someone was able to reproduce it, but that didn't answer any of my questions.

I've tried a few more things and maybe the issue is related to strings in some way. If I add a class that takes a string as a parameter in the constructor, and then ONLY if I instantiate it, like so:

class Test 
{
public:
    Test(std::string test) {} ;
};

int main() 
{
    Test test("test");
    InitOpenGL(1280, 720, window, mainContext);
    BeforeMainLoop();

    return 1;
}

Then that also results in a black screen. Instantiating a vector of strings also results in a black screen, like so:
std::vector<std::string> languages = { "english", "japanese" };

And my original problem with the Log function also happens to involve strings on some level. If I change the constructor from a string to a const char* then it works. But changing all instances of strings to const char* is not ideal (my program needs strings), and I actually tried that with the Log function and that did not help, so I'm still looking for a solution. So hopefully this information is helpful for someone to figure out what is wrong and how to fix it.

Floh

unread,
Nov 1, 2021, 10:16:29 AM11/1/21
to emscripten-discuss
I'm also able to reproduce the problem on macOS with Chrome and Safari, but no idea either what's going wrong there.

However, I suspect it's not the use of std::string, but that iostream is the culprit, because if I replace std::cout with printf but keep std::string, it works (replacing cout with printf is a good idea anyway, because cout adds an incredible amount of bloat last I checked).

Floh

unread,
Nov 1, 2021, 10:20:16 AM11/1/21
to emscripten-discuss
PS: if you just want to get something on screen in a cross-platform application, but don't care if it's SDL2 or GL, check out my sokol headers:


No guarantee that this will protect you from any C++ shenanigans though, the headers can be used from C++, but since I prefer plain old C these days, most of the sample code is written in C (and the few C++ samples - mainly the Dear ImGui stuff - doesn't use the STL).

Anton Strickland

unread,
Nov 2, 2021, 3:09:08 AM11/2/21
to emscripten-discuss
It looks like I have found a solution thanks to someone in the Discord server. Here is what I changed:

  EmscriptenWebGLContextAttributes attrs;
    attrs.antialias = true;
    attrs.majorVersion = 3;
    attrs.minorVersion = 2;
    attrs.alpha = true;
    attrs.powerPreference = EM_WEBGL_POWER_PREFERENCE_DEFAULT;

    // The following lines must be done in exact order, or it will break!
    emscripten_webgl_init_context_attributes(&attrs); // you MUST init the attributes before creating the context
    attrs.majorVersion = 3; // you MUST set the version AFTER the above line
    EMSCRIPTEN_WEBGL_CONTEXT_HANDLE webgl_context = emscripten_webgl_create_context("#canvas", &attrs);
    emscripten_webgl_make_context_current(webgl_context);
    mainContext = SDL_GL_CreateContext(window);

When you modify my main.cpp with this code then it actually shows the game on the screen and all of the above errors I mentioned disappear. So the solution is to call emscripten_webgl_init_context_attributes between creating the attributes and before creating the context. However, if you do that then it sets up the webgl context using OpenGL ES 2.0 (WebGL 1.0) which is not what I want (because I would need to change all my shader code). So that's why you need to set the attributes AGAIN after calling it (to set majorVersion=3) which results in OpenGL ES 3.0 / WebGL 2.0.

Of course I have no idea WHY any of this needs to be done. I hope this can either be fixed or documented somewhere with an explanation.

I managed to copy and paste this code into my larger game project and it worked like a charm. However, I get a different (unrelated) error now which is that the browser crashes because it runs out of memory... but at least I can see the game now. The preloaded data file is ~80 MB which isn't huge by video game standards, but it might be too big for the browser to download. I did set ALLOW_MEMORY_GROWTH=1 but that didn't seem to prevent the issue. If anyone can help me out with that too please let me know. Thanks.

Floh

unread,
Nov 2, 2021, 7:00:26 AM11/2/21
to emscripten-discuss
Ah dang, yeah totally makes sense. I guess that's one of those pitfalls in C that are so obvious that one gets blind about.

> Of course I have no idea WHY any of this needs to be done.

The line:

EmscriptenWebGLContextAttributes attrs;

...means that 'attrs' has random memory content (because it's a C struct, not a C++ class with constructor), and the emscripten_webgl_init_context_attributes() call initializes the memory to something sane (probably just clearing the memory to zero). This initialization pattern is fairly common in C APIs, but not in C++ APIs.

Cheers!

Floh

unread,
Nov 2, 2021, 7:05:15 AM11/2/21
to emscripten-discuss
> However, I get a different (unrelated) error now which is that the browser crashes because it runs out of memory...

This sounds like a memory leak, AFAIK memory growth is now enabled by default in WASM, so ALLOW_MEMORY_GROWTH is redundant.

Emscripten has various features to aid with memory debugging, this is probably a good starting point:

Anton Strickland

unread,
Nov 3, 2021, 12:48:27 AM11/3/21
to emscripten-discuss
Apparently I was able to get past the memory issue by compiling with optimization flag -O3.

I will check out that link though, it might help me in the future.

Thanks!

Floh

unread,
Nov 3, 2021, 5:06:56 AM11/3/21
to emscripten-discuss
> ... by compiling with optimization flag -O3.

Uh oh, that doesn't sound right :) If your code has different behaviour between optimized and non-optimized builds I would definitely look into this as early as possible, because any later time will only make debugging much worse. Non-initialized memory (like the initial webgl-attributes issue) are one common reason for such differences, so there's probably uninitialized memory lurking elsewhere too.

Reply all
Reply to author
Forward
0 new messages