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

Potential framerate fix #2586

Closed
wants to merge 5 commits into from
Closed
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
68 changes: 41 additions & 27 deletions arcade/application.py
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,8 @@ def __init__(
# If more time resolution is needed in fixed updates, devs can do 'sub-stepping'.
self._fixed_rate = fixed_rate
self._fixed_frame_cap = fixed_frame_cap
self.set_update_rate(update_rate)
# self.set_update_rate(update_rate)
pyglet.clock.schedule_interval(self._next_frame, 1/60)

self.set_vsync(vsync)

Expand Down Expand Up @@ -527,32 +528,32 @@ def _dispatch_updates(self, delta_time: float) -> None:
fixed_count += 1
self.dispatch_event("on_update", GLOBAL_CLOCK.delta_time)

def set_update_rate(self, rate: float) -> None:
"""
Set how often the on_update function should be dispatched.
For example::

# Set the update rate to 60 times per second.
self.set_update_rate(1 / 60)

Args:
rate: Update frequency in seconds
"""
self._update_rate = rate
pyglet.clock.unschedule(self._dispatch_updates)
pyglet.clock.schedule_interval(self._dispatch_updates, rate)

def set_draw_rate(self, rate: float) -> None:
"""
Set how often the on_draw function should be run.
For example::

# Set the draw rate to 60 frames per second.
set.set_draw_rate(1 / 60)
"""
self._draw_rate = rate
pyglet.clock.unschedule(pyglet.app.event_loop._redraw_windows)
pyglet.clock.schedule_interval(pyglet.app.event_loop._redraw_windows, self._draw_rate)
# def set_update_rate(self, rate: float) -> None:
# """
# Set how often the on_update function should be dispatched.
# For example::

# # Set the update rate to 60 times per second.
# self.set_update_rate(1 / 60)

# Args:
# rate: Update frequency in seconds
# """
# self._update_rate = rate
# pyglet.clock.unschedule(self._dispatch_updates)
# pyglet.clock.schedule_interval(self._dispatch_updates, rate)

# def set_draw_rate(self, rate: float) -> None:
# """
# Set how often the on_draw function should be run.
# For example::

# # Set the draw rate to 60 frames per second.
# set.set_draw_rate(1 / 60)
# """
# self._draw_rate = rate
# pyglet.clock.unschedule(pyglet.app.event_loop._redraw_windows)
# pyglet.clock.schedule_interval(pyglet.app.event_loop._redraw_windows, self._draw_rate)

def on_mouse_motion(self, x: int, y: int, dx: int, dy: int) -> EVENT_HANDLE_STATE:
"""
Expand Down Expand Up @@ -1019,6 +1020,19 @@ def hide_view(self) -> None:
self.remove_handlers(self._current_view)
self._current_view = None

def _next_frame(self, delta_time: float) -> None:
"""
Internal method called by Pyglet's clock to advance the next frame.

This method exists to ensure that exactly one update and one draw
is called per frame. Generic interval events are not stable enough
to ensure this.
"""
# print("next frame", delta_time)
self._dispatch_updates(delta_time)
self.dispatch_event("on_draw")
self.flip()

def flip(self) -> None:
"""
Present the rendered content to the screen.
Expand Down
75 changes: 38 additions & 37 deletions arcade/window_commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ def run(view: View | None = None) -> None:
if window.context:
active.on_draw()

# windwow could be closed in on_draw
# window could be closed in on_draw
if window.context:
window.flip()

Expand All @@ -143,42 +143,43 @@ def run(view: View | None = None) -> None:
else:
import sys

if sys.platform != "win32":
# For non windows platforms, just do pyglet run
pyglet.app.run(window._draw_rate)
else:
# Ok, some Windows platforms have a timer resolution > 15 ms. That can
# drop our FPS to 32 FPS or so. This reduces resolution so we can keep
# FPS up.
import contextlib
import ctypes
from ctypes import wintypes

winmm = ctypes.WinDLL("winmm")

class TIMECAPS(ctypes.Structure):
_fields_ = (("wPeriodMin", wintypes.UINT), ("wPeriodMax", wintypes.UINT))

def _check_time_err(err, func, args):
if err:
raise WindowsError("%s error %d" % (func.__name__, err))
return args

winmm.timeGetDevCaps.errcheck = _check_time_err
winmm.timeBeginPeriod.errcheck = _check_time_err
winmm.timeEndPeriod.errcheck = _check_time_err

@contextlib.contextmanager
def timer_resolution(msecs=0):
caps = TIMECAPS()
winmm.timeGetDevCaps(ctypes.byref(caps), ctypes.sizeof(caps))
msecs = min(max(msecs, caps.wPeriodMin), caps.wPeriodMax)
winmm.timeBeginPeriod(msecs)
yield
winmm.timeEndPeriod(msecs)

with timer_resolution(msecs=10):
pyglet.app.run(window._draw_rate)
pyglet.app.run(None)
# if sys.platform != "win32":
# # For non windows platforms, just do pyglet run
# pyglet.app.run(window._draw_rate)
# else:
# # Ok, some Windows platforms have a timer resolution > 15 ms. That can
# # drop our FPS to 32 FPS or so. This reduces resolution so we can keep
# # FPS up.
# import contextlib
# import ctypes
# from ctypes import wintypes

# winmm = ctypes.WinDLL("winmm")

# class TIMECAPS(ctypes.Structure):
# _fields_ = (("wPeriodMin", wintypes.UINT), ("wPeriodMax", wintypes.UINT))

# def _check_time_err(err, func, args):
# if err:
# raise WindowsError("%s error %d" % (func.__name__, err))
# return args

# winmm.timeGetDevCaps.errcheck = _check_time_err
# winmm.timeBeginPeriod.errcheck = _check_time_err
# winmm.timeEndPeriod.errcheck = _check_time_err

# @contextlib.contextmanager
# def timer_resolution(msecs=0):
# caps = TIMECAPS()
# winmm.timeGetDevCaps(ctypes.byref(caps), ctypes.sizeof(caps))
# msecs = min(max(msecs, caps.wPeriodMin), caps.wPeriodMax)
# winmm.timeBeginPeriod(msecs)
# yield
# winmm.timeEndPeriod(msecs)

# with timer_resolution(msecs=10):
# pyglet.app.run(None)


def exit() -> None:
Expand Down
Loading