Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SDL software renderer fails with Floating Point Exception #56

Open
bunnylin opened this issue May 29, 2022 · 4 comments
Open

SDL software renderer fails with Floating Point Exception #56

bunnylin opened this issue May 29, 2022 · 4 comments
Labels
waiting 3rd party Waiting for other project to fix something

Comments

@bunnylin
Copy link

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.
@suve
Copy link
Collaborator

suve commented May 30, 2022

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.

@Free-Pascal-meets-SDL-Website
Copy link
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?

@bunnylin
Copy link
Author

bunnylin commented Jun 5, 2022

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.

@Free-Pascal-meets-SDL-Website
Copy link
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.

@Free-Pascal-meets-SDL-Website Free-Pascal-meets-SDL-Website added the waiting 3rd party Waiting for other project to fix something label Jun 17, 2022
suve added a commit to suve/LD25 that referenced this issue Jul 15, 2022
See: PascalGameDevelopment/SDL2-for-Pascal#56
According to this GitHub Issue, when initializing the software renderer
on Linux, SDL2 triggers a crash in Mesa code. This happens because
FPC and Delphi enable FPE checking by default. This commit disables
those exceptions for the duration of SDL2 video initialization,
which should prevent crashes while using the software renderer.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
waiting 3rd party Waiting for other project to fix something
Projects
None yet
Development

No branches or pull requests

3 participants