Emscripten: "Cannot set timing mode for main loop" & "You should use 0 for the frame rate in emscripten_set_main_loop"

Created on 7 Sep 2018  Â·  9Comments  Â·  Source: emscripten-core/emscripten

With the following program…:

#include <SDL2/SDL.h>
#include <emscripten.h>

void iterate()
{
}

int main(int, char**)
{
    auto pwindow = SDL_CreateWindow
    (
        "Test",
        SDL_WINDOWPOS_UNDEFINED,
        SDL_WINDOWPOS_UNDEFINED,
        640,
        480,
        SDL_WINDOW_RESIZABLE
    );

    auto prenderer = SDL_CreateRenderer
    (
        pwindow,
        -1,
        0
    );

    emscripten_set_main_loop(iterate, 0, 1);

    return 0;
}

… I get the following error in the web console: 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.

Since emscripten_set_main_loop_timing seems to be called by SDL_CreateRenderer, I try to fix my program like so:

#include <SDL2/SDL.h>
#include <emscripten.h>

void iterate()
{
    SDL_Window* pwindow;
    SDL_Renderer* prenderer;
    static auto first_call = true;

    if(first_call)
    {
        pwindow = SDL_CreateWindow
        (
            "Test",
            SDL_WINDOWPOS_UNDEFINED,
            SDL_WINDOWPOS_UNDEFINED,
            640,
            480,
            SDL_WINDOW_RESIZABLE
        );

        prenderer = SDL_CreateRenderer
        (
            pwindow,
            -1,
            0
        );

        first_call = false;
    }
}

int main(int, char**)
{
    emscripten_set_main_loop(iterate, 0, 1);

    return 0;
}

But now I get the following warning in the web console: 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!

It seems like there's no way to get neither of those errors.

Most helpful comment

That shouldn't work as emscripten_set_main_loop doesn't return, so your window/renderer won't be getting created. Also, calling SDL_CreateRenderer after setting the main loop overrides the main loop timing based on the SDL_RENDERER_PRESENTVSYNC flag. (EM_TIMING_RAF if set, EM_TIMING_SETTIMEOUT otherwise.)

Where the warning comes from:
SDL_CreateRenderer(..., 0) ->
GLES2_CreateRenderer(..., 0) ->
SDL_GL_SetSwapInterval(0) ->
SDL_EGL_SetSwapInterval(..., 0) ->
eglSwapInterval(... 0) ->
emscripten_set_main_loop_timing(EM_TIMING_SETTIMEOUT, 0) ->
"Looks like you are rendering without using requestAnimationFrame for the main loop..."

All 9 comments

This does seem odd, I'm not sure why SDL_CreateRenderer affects the main loop. And I confirm I see those warnings on the two cases in the test suite that use those two functions (tests/sdl2_gl_frames_swap.c, tests/sdl_togglefullscreen.c).

cc @Daft-Freak

For the second message, try creating the renderer with the SDL_RENDERER_PRESENTVSYNC flag. I think if you don't pass that the GLES renderer does eglSwapInterval(0). The first message is probably caused by the fact that it calls eglSwapInterval as well.

I'm having this same problem in porting a game to wasm. The code calls SDL_CreateRenderer long before the main loop is entered while setting up the UI for the first time. I get an error that it can't set timing because a main loop doesn't exist. I tried @Daft-Freak's suggestion to add the PRESENTVSYNC flag, but it doesn't seem to have changed anything. Any other ideas?

I am experiencing the same error "Cannot set timing, ..." with the following code

#include <iostream>

#include <SDL2/SDL.h>
#include <SDL2/SDL_ttf.h>

#include <emscripten.h>

void loop_handler(void*) {

}

int main(int argc, char** argv) {

  SDL_Init(SDL_INIT_VIDEO);
  TTF_Init();

  SDL_Window* win = SDL_CreateWindow("WebAssembly test", 0, 0, 800, 600, 0);
  SDL_Renderer* renderer = SDL_CreateRenderer(win, 0, 0);


  TTF_Font* font = TTF_OpenFont("assets/DejaVuSansMono.ttf", 100);
  SDL_Color white = {255, 255, 255};
  SDL_Surface* sf = TTF_RenderText_Solid(font, "WebAssembly rocks!", white);
  SDL_Texture* tex = SDL_CreateTextureFromSurface(renderer, sf);

  emscripten_set_main_loop_arg(loop_handler, nullptr, -1, 1);
  //  SDL_RenderCopy(renderer, tex, nullptr, nullptr);
  //  SDL_RenderPresent(renderer);  


  // std::cout << std::endl << "Hello World" << std::endl;

  // SDL_DestroyTexture(tex);
  // SDL_FreeSurface(sf);
  // SDL_DestroyRenderer(renderer);
  // SDL_DestroyWindow(win);

  // TTF_CloseFont(font);
  // TTF_Quit();
  // SDL_Quit();

  return 0;
}

You can just ignore the error, it's only there when ASSERTIONS is enabled and the main loop still gets created. To fix this we either need to allow calling emscripten_set_main_loop_timing before creating the main loop, or change eglSwapInterval to not use it.

The warning goes away if I do this, but I wonder if this could have other consequences:

#include <SDL2/SDL.h>
#include <emscripten.h>

void iterate()
{
    // Here I have some code animating a sprite
}

int main(int, char**)
{
    SDL_Init( SDL_INIT_VIDEO ); // I have this call, I guess it makes no difference

    emscripten_set_main_loop(iterate, 0, 1); // moved before creating window and renderer

    auto pwindow = SDL_CreateWindow
    (
        "Test",
        SDL_WINDOWPOS_UNDEFINED,
        SDL_WINDOWPOS_UNDEFINED,
        640,
        480,
        SDL_WINDOW_RESIZABLE
    );

    auto prenderer = SDL_CreateRenderer
    (
        pwindow,
        -1,
        0
    );

   return 0;
}

That shouldn't work as emscripten_set_main_loop doesn't return, so your window/renderer won't be getting created. Also, calling SDL_CreateRenderer after setting the main loop overrides the main loop timing based on the SDL_RENDERER_PRESENTVSYNC flag. (EM_TIMING_RAF if set, EM_TIMING_SETTIMEOUT otherwise.)

Where the warning comes from:
SDL_CreateRenderer(..., 0) ->
GLES2_CreateRenderer(..., 0) ->
SDL_GL_SetSwapInterval(0) ->
SDL_EGL_SetSwapInterval(..., 0) ->
eglSwapInterval(... 0) ->
emscripten_set_main_loop_timing(EM_TIMING_SETTIMEOUT, 0) ->
"Looks like you are rendering without using requestAnimationFrame for the main loop..."

Never mind then. I was assuming emscripten_set_main_loop only stored a pointer to the iterate function and returned right away.

I have the same errors. However, in my practice, "Cannot set timing mode for main loop" error message wont break the application. It is more like a warning.

Was this page helpful?
0 / 5 - 0 ratings