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

Fix CPU usage when using vsync #90

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

markusgritsch
Copy link
Contributor

I noticed that the CPU usage increases over time when using setVSync(true), which is the default. This happens even for a simple example like lines.nim.

When using setVSync(false), this does not happen, but of course this has the drawback of tearing or not smooth screen updates.

The main difference when using setVSync(false) is in proc run*() where waiting is done manually using delay(). However, it seems that when solely relying on vsync, CPU usage seems to increase over time.

As a solution this pull request adds a delay(1) even for the vsync case, if sleepTime is not smaller than 1.0 ms. This fixes the reported CPU usage problem.

I noticed that the CPU usage increases over time when using `setVSync(true)`, which is the default. This happens even for a simple example like `lines.nim`.

When using `setVSync(false)`, this does not happen, but of course this has the drawback of tearing or not smooth screen updates.

The main difference when using `setVSync(false)` is in `proc run*()` where waiting is done manually using `delay()`. However, it seems that when solely relying on vsync, CPU usage seems to increase over time.

As a solution this pull request adds a delay(1) even for the vsync case, if `sleepTime` is not smaller than 1.0 ms. This fixes the reported CPU usage problem.
@ftsf
Copy link
Owner

ftsf commented Feb 23, 2022

Are you seeing this behaviour on Linux? We've seen similar before on Linux where vsync doesn't appear to be supported correctly.

@markusgritsch
Copy link
Contributor Author

markusgritsch commented Feb 24, 2022

No, I'm using Windows 10 on an Intel HD Graphics 2000. The fan of my Notebook makes high CPU usage very noticable :)

@ftsf
Copy link
Owner

ftsf commented Feb 24, 2022

Perhaps we can do something to determine if vsync is working correctly or not, if the time between loops is super short (and not close to vsync frequency), we could disable vsync mode and use the wait timer instead

@markusgritsch
Copy link
Contributor Author

Hmm, I would not prefer having the wait timer approach being automatically turned on, as it has the mentioned drawbacks on its own. The proposed kludge fixes the vsync CPU issue for me, and I can enjoy smooth scrolling. If it does not gets mainlined, I can live with it too :)

@ftsf
Copy link
Owner

ftsf commented Feb 24, 2022

If you're getting high CPU usage with vsync mode it's likely vsync is not working correctly. We've encountered a bunch of cases where some setups do not actually do vsync and thus return instantly and create high CPU load. So I think some form of detection as to whether vsync is working may be necessary.

@markusgritsch
Copy link
Contributor Author

But it's working when relying on vsync just a little bit later, by using the delay(1).

@markusgritsch
Copy link
Contributor Author

markusgritsch commented Feb 24, 2022

Also, I don't think vsync is broken on my hardware per se, because a) it can be "fixed" with the above workaround, and b) I don't experience any issues when using Pyxel. I tried the same example to test smooth screen updates with Pyxel and with Nico:

import pyxel

x = 0

def update():
  pass

def draw():
  global x
  pyxel.cls(0)
  pyxel.line(x, 0, x, 128, 7)
  x += 1
  x %= 128

pyxel.init(128, 128, title="Pyxel", fps=60)
pyxel.mouse(True)
pyxel.run(update, draw)
import nico

var x = 0

proc gameInit() =
  # setVSync(false)
  setColor(8)

proc gameUpdate(dt: Pfloat) =
  discard

proc gameDraw() =
  cls()
  line(x,0,x,64)
  x += 1
  x = x mod 128

nico.init("nico", "test")
fixedSize(true)
integerScale(true)
nico.createWindow("nico", 128, 128, 4)
nico.run(gameInit, gameUpdate, gameDraw)

Skipped screen updates are immediately visible by jumps in the moving line when uncomminting setVSync(false). It runs super smooth when not disabling vsync.

The Pyxel version runs with 1.5% CPU usage out of the box (also smooth).
With the fix applied, CPU usage stays low at 2.5% also with the Nico version.

I use the same SDL2.dll on both examples.

I haven't looked into what Pyxel does different from Nico regarding the SDL configuration.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants