Skip to content

SDL software renderer fails with Floating Point Exception #56

Description

@bunnylin

This is mostly for visibility - I'm not sure where this would be best fixed.

It seems any SDL application compiled with Pascal will crash if trying to use software renderer video output, on Linux. To verify, run any SDL application with the environment variable LIBGL_ALWAYS_SOFTWARE=1 set. The failure happens either immediately on SDL_InitSubSystem(SDL_INIT_VIDEO), or when calling SDL_CreateRenderer. The error that appears can be EInvalidOp: Invalid floating point operation or EDivByZero: Division by zero depending on environment.

Doing this through GDB, I got this callstack pointing at the LLVMpipe software rasterizer:

lp_build_tgsi_info () from /usr/lib64/dri/swrast_dri.so
llvmpipe_create_fs_state () from /usr/lib64/dri/swrast_dri.so
ureg_create_shader () from /usr/lib64/dri/swrast_dri.so
util_make_fragment_tex_shader_writemask () from /usr/lib64/dri/swrast_dri.so
util_make_fragment_tex_shader () from /usr/lib64/dri/swrast_dri.so
blitter_get_fs_texfetch_col () from /usr/lib64/dri/swrast_dri.so
util_blitter_cache_all_shaders () from /usr/lib64/dri/swrast_dri.so
llvmpipe_create_context () from /usr/lib64/dri/swrast_dri.so
st_api_create_context () from /usr/lib64/dri/swrast_dri.so
dri_create_context () from /usr/lib64/dri/swrast_dri.so
driCreateContextAttribs () from /usr/lib64/dri/swrast_dri.so
drisw_create_context_attribs () from /lib64/libGLX_mesa.so.0
dri_common_create_context () from /lib64/libGLX_mesa.so.0
CreateContext () from /lib64/libGLX_mesa.so.0
glXCreateContext () from /lib64/libGLX_mesa.so.0
glXCreateContext () from /lib64/libGLX.so.0
X11_GL_LoadLibrary.part.0 () from /lib64/libSDL2-2.0.so.0

So it's a problem in Mesa. This doesn't affect Pascal/SDL programs on Windows since users don't normally run Mesa there. An internet search turned up this bug: https://gitlab.freedesktop.org/mesa/mesa/-/issues/3096

They say the FPE should normally not be enabled in the first place, and the caller should just disable the exception mode. A commenter notes that the affected software was made with Delphi, which suggests to me that Free Pascal and Delphi are both deliberately keeping this FPE enabled (and are unlikely to change that because it would break compatibility).

As a workaround, it's simple to disable the exception by applying a mask, via the Math unit:

uses Math, SDL2;
var m : TFPUExceptionMask;
        window : PSDL_Window;
        renderer : PSDL_Renderer;
begin
        m := GetExceptionMask;
        include(m, exInvalidOp);
        SetExceptionMask(m); // <-- comment out this and it breaks again

        writeln(SDL_InitSubSystem(SDL_INIT_VIDEO));
        window := SDL_CreateWindow(NIL, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
                640, 400, SDL_WINDOW_SHOWN);
        if window = NIL then writeln('failed to create window: ' + SDL_GetError);
        renderer := SDL_CreateRenderer(window, -1, 0);
        if renderer = NIL then writeln('failed to get renderer: ' + SDL_GetError);
        writeln('no crash, all ok!');
end.

Activity

  1. suve commented on May 30, 2022

    @suve
    Collaborator

    Interesting. We could sidestep this by hiding SDL_CreateRenderer() behind a Pascal function that disables FPE, calls the SDL function, and restores the old exception mask - but I feel that this could be seen as invasive. The other issue is that we'd need to maintain a list of places that require this special handling.

  2. Free-Pascal-meets-SDL-Website commented on Jun 5, 2022

    @Free-Pascal-meets-SDL-Website
    Collaborator

    @bunnylin Thanks for this detailed report and the solution.

    hiding SDL_CreateRenderer() behind a Pascal function [...] but I feel that this could be seen as invasive.

    @suve It seems to happen on calling SDL_InitSubSystem(SDL_INIT_VIDEO) sometimes, too, hence wrapping this function alone would not cover all crashes. I agree about the invasiveness.

    Alternatively we could just simply add a Linux compiler hint referencing this issue for everybody to figure out themselves what is the best way to solve this in their projects. Downside: The hint will always be present in Linux then.

    What do you guys think?

  3. bunnylin commented on Jun 5, 2022

    @bunnylin
    Author

    If there was a way to suppress the hint after the developer has addressed it, that would be perfect, but user-specified hints don't get a handy number that could be masked. The visibility may still be preferable... the hint only appears when the unit is compiled, and during normal development you're unlikely to rebuild every unit after each change.

  4. Free-Pascal-meets-SDL-Website commented on Jun 6, 2022

    @Free-Pascal-meets-SDL-Website
    Collaborator

    The visibility may still be preferable... the hint only appears when the unit is compiled, and during normal development you're unlikely to rebuild every unit after each change.

    The downside is though, if someone compiled the units already (ignoring the hint) and later (days, months) runs into the crash he/she is likely not to remember the hint.

    Well, alternatively we could use the initilization part of the SDL2 unit to present the hint message. This would be a very verbose solution.

    Another alternative would be to introduce a compiler DEFINE for SDL2-For-Pascal hints to be spawned or suppress it. - I guess this would be too much for just one hint atm., but maybe for the future it may be useful to be introduced if further hints are necessary.

  5. added a commit that references this issue on Jul 15, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    waiting 3rd partyWaiting for other project to fix something

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions