Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion rendercanvas/_loop.py
Original file line number Diff line number Diff line change
Expand Up @@ -372,7 +372,7 @@ def _rc_call_later(self, delay, callback):
This method is optional. A subclass must either implement ``_rc_add_task`` or ``_rc_call_later``.

* If you implememt this, make ``_rc_add_task()`` call ``super()._rc_add_task()``.
* If delay is zero, this should behave like "call_later".
* If delay is zero, this should behave like "call_soon".
* No need to catch errors from the callback; that's dealt with internally.
* Return None.
"""
Expand Down
29 changes: 21 additions & 8 deletions rendercanvas/_scheduler.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,17 @@
The scheduler class/loop.
"""

import sys
import time
import weakref

from ._coreutils import BaseEnum
from .utils.asyncs import sleep, Event


IS_WIN = sys.platform.startswith("win")


class UpdateMode(BaseEnum):
"""The UpdateMode enum specifies the different modes to schedule draws for the canvas."""

Expand Down Expand Up @@ -123,14 +127,23 @@ async def __scheduler_task(self):
delay = 1 / self._max_fps
delay = 0 if delay < 0 else delay # 0 means cannot keep up

# Offset delay for time spent on processing events, etc.
time_since_tick_start = time.perf_counter() - last_tick_time
delay -= time_since_tick_start
delay = max(0, delay)

# Wait. Even if delay is zero, it gives control back to the loop,
# allowing other tasks to do work.
await sleep(delay)
# Determine amount of sleep
sleep_time = delay - (time.perf_counter() - last_tick_time)

if IS_WIN:
# On Windows OS-level timers have an in accuracy of 15.6 ms.
# This can cause sleep to take longer than intended. So we sleep
# less, and then do a few small sync-sleeps that have high accuracy.
await sleep(max(0, sleep_time - 0.0156))
sleep_time = delay - (time.perf_counter() - last_tick_time)
while sleep_time > 0:
time.sleep(min(sleep_time, 0.001)) # sleep hard for at most 1ms
await sleep(0) # Allow other tasks to run but don't wait
sleep_time = delay - (time.perf_counter() - last_tick_time)
else:
# Wait. Even if delay is zero, it gives control back to the loop,
# allowing other tasks to do work.
await sleep(max(0, sleep_time))

# Below is the "tick"

Expand Down
2 changes: 0 additions & 2 deletions rendercanvas/qt.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@
WA_PaintOnScreen = QtCore.Qt.WidgetAttribute.WA_PaintOnScreen
WA_DeleteOnClose = QtCore.Qt.WidgetAttribute.WA_DeleteOnClose
WA_InputMethodEnabled = QtCore.Qt.WidgetAttribute.WA_InputMethodEnabled
PreciseTimer = QtCore.Qt.TimerType.PreciseTimer
KeyboardModifiers = QtCore.Qt.KeyboardModifier
FocusPolicy = QtCore.Qt.FocusPolicy
CursorShape = QtCore.Qt.CursorShape
Expand All @@ -42,7 +41,6 @@
WA_PaintOnScreen = QtCore.Qt.WA_PaintOnScreen
WA_DeleteOnClose = QtCore.Qt.WA_DeleteOnClose
WA_InputMethodEnabled = QtCore.Qt.WA_InputMethodEnabled
PreciseTimer = QtCore.Qt.PreciseTimer
KeyboardModifiers = QtCore.Qt
FocusPolicy = QtCore.Qt
CursorShape = QtCore.Qt
Expand Down
1 change: 1 addition & 0 deletions rendercanvas/raw.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ def _rc_run(self):
break
else:
# Wait until its time for it to be called
# Note that on Windows, the accuracy of the timeout is 15.6 ms
wait_time = wrapper.time - time.perf_counter()
self._event.wait(max(wait_time, 0))

Expand Down