Frame Latency & Screen Tearing

-Edit- After seeing flowCRANE reply, I realized I should have asked what SDL specific thing should I do to reduce frame latency. Below is a C program, I’m interested in knowing if window tears and if someone knows how to reduce the latency on mac (press buttons to see the bar change color.) I tested on linux with x11 and I plan to test wayland this week

I’m trying to reduce frame latency as much as possible. I noticed (at least on my linux desktop) that SDL is delayed a few frames unless I use opengl and call SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 0). I tried doing something similar on mac but the delay doesn’t go away.

Calling the gl line breaks vsync but for my program it’s fine unless there’s tearing. I attached a C program to test input latency and tearing. I look at the screen to visually see if there’s tearing, then I video record myself pressing a button and see how many frames it takes to show up. I can see on my linux desktop (x11) with gl I have near 0 latency. Everything else I get no less than 30ms, sometimes it appears I have 90+

My question is

  1. What can I do to reduce the frame latency? I’m not familiar with the gpu api but if that’s my best option I can try it
  2. Does the code have tearing on your machine? I don’t see any on my linux desktop and I don’t have a windows machine to test on. On my mac both gl and non gl have no tearing and latency problem. You can use gl by running ./a.out nonZeroArg

Code is less than 100 lines. Should be easy enough to read/change/test
screenTest.c (2.4 KB)

I can tell you a bit about this, but more in the context of Microsoft Windows systems (mainly Windows 10). I’ll point out that I haven’t done any in-depth research on this, but rather rely on my own experiences and publicly available benchmarks that I’ve had the opportunity to review.


1. Disable double/triple buffering.

Although this should shorten the time it takes for a new frame to appear on the screen, rather than reducing input lag. If you have turned off double buffering and noticed a reduction in input lag, that’s great. In any case, by turning it off, screen tearing will be present.

2. Disablie V-Sync or other synchronization technologies (FreeSync, etc.).

This will allow the main game loop to perform more logic updates, and therefore react to input events faster. The downside is screen tearing and increased CPU usage (unless the main loop supports an updaterate cap).

3. Run the game in exclusive full screen mode.

In this mode, the game process takes direct control of the GPU and display, bypassing the Windows desktop composition (i.e. Desktop Window Manager – DWM). The lack of intermediaries means that keyboard/mouse input gets to the game faster, and frames are rendered and displayed without additional buffering.

An additional advantage is that the system recognizes that the game is running in exclusive mode and disables some system features (e.g. blocks the display of notification bubbles). The downside is that it is difficult to switch between applications, but SDL gives you the option to disable automatic minimization of a window when it loses focus (there is a hint for this).

4. Use exclusive fullscreen mode with lower than native resolution.

If you render the content of a new game frame directly onto the window texture, then obviously the smaller this texture is, the less there is to render. The gain may be negligible, but it’s still something. The faster a frame is rendered, the faster it will be possible to move on to the next logic update (depending on the implementation of the main loop).

5. Perform as many logic updates and renders as possible.

The main loop should do as many logic updates and renderings as the CPU can handle. With V-Sync disabled, the game process will be able to react to input very quickly and visualize it on the screen.

However, this approach has a lot of drawbacks. First, the game process will consume all available CPU time, which can cause excessive heat generation by the CPU, increased cooling, and power consumption. Preempting the CPU in this way can lead to lower system responsiveness and stability, although mainly on low-end or more heavily loaded machines. Another downside is that rendering thousands of frames per second is a waste of resources and power, since only 60 to 144 can appear on the screen. Screen tearing will of course also be present.

6. Use the highest possible priority for the game process.

Theoretically, the best performance will be achieved when the game process has real-time priority, but the possibility to use it depends on the operating system, user permissions, and other factors. In any case, the higher the priority of the game process, the more willingly the system scheduler will process its instructions.

Hello,

I tested your code on Linux (fully hacked mint, x11 + gl), and I got vertical lines moving from left to right, but no tearing (if I understand what you mean) when doing nothing, and a bit of, when e.g. moving the window.

See below:

About the load, I got ~ 20% when the window is fullscreen (only 10% after closing it).

EDIT : my current OpenGL profile

~$ glxinfo -B
name of display: :0.0
display: :0  screen: 0
direct rendering: Yes
Extended renderer info (GLX_MESA_query_renderer):
    Vendor: Intel (0x8086)
    Device: Mesa Intel(R) Graphics (ADL GT2) (0x46a8)
    Version: 22.0.5
    Accelerated: yes
    Video memory: 3072MB
    Unified memory: yes
    Preferred profile: core (0x1)
    Max core profile version: 4.6
    Max compat profile version: 4.6
    Max GLES1 profile version: 1.1
    Max GLES[23] profile version: 3.2
OpenGL vendor string: Intel
OpenGL renderer string: Mesa Intel(R) Graphics (ADL GT2)
OpenGL core profile version string: 4.6 (Core Profile) Mesa 22.0.5 (git-a735e96040)
OpenGL core profile shading language version string: 4.60
OpenGL core profile context flags: (none)
OpenGL core profile profile mask: core profile

OpenGL version string: 4.6 (Compatibility Profile) Mesa 22.0.5 (git-a735e96040)
OpenGL shading language version string: 4.60
OpenGL context flags: (none)
OpenGL profile mask: compatibility profile

HTH

Thanks. Knowing how it looks on other peoples machines is always the hard part!

If anyone else wants to try, I don’t know if there’s tearing on windows and I might try wayland on my machine using a live cd later

Thanks. I just realized I should have said what SDL specific thing do I need to do. My app is a gui program so users may be annoyed if I went into exclusive full screen mode :rofl: but also I only need to render on input and events (file rename, modified, etc)

Please attach a compiled version of this tester and I will check it on my Windows 10. Not everyone code in C/C++ and have tools for them. :wink:

That’s a tall order…
I’ll give it a shot. Maybe zig can compile this and link.

(post deleted by author)

Honestly I have no faith this will work. This build is more likely to work than the one in the deleted comment but if it doesn’t work you can try that one.

I compiled with zig without using any windows SDK. It’s very likely to have linking/dll problems

screenTest.zip (1.7 MB)

4191b531c242d54f036a3d84492a017b9b113444  screenTest.c
a009a36be2fa22e697dae12f5f1cb403c2cd848f  screenTest.exe
3bc366c600fbe2d1337921aa08069529963eb75c  SDL3.dll

I tested it on Windows 10 and everything works without a problem. The bars move smoothly, there is no screen tearing. Console output:

using default sdl
Driver #1 windows
Driver #2 offscreen
Driver #3 dummy
Driver windows VSync 1 pixel density 1.000000 gl 0000000000000000