SDL2-for-Pascal
                                
                                
                                
                                    SDL2-for-Pascal copied to clipboard
                            
                            
                            
                        SDL software renderer fails with Floating Point Exception
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.
                                    
                                    
                                    
                                
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.
@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?
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.
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.