Skip to content

Commit 9ce53c9

Browse files
committed
Cleanup debounce
Assume that the debounced function is a member function, store the debounce data in the first argument (the class instance)
1 parent aed2fab commit 9ce53c9

2 files changed

Lines changed: 34 additions & 25 deletions

File tree

webgpu/canvas.py

Lines changed: 30 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -12,38 +12,50 @@
1212
_TARGET_FPS = 60
1313

1414

15+
@dataclass
16+
class _DebounceData:
17+
t_last: float | None = None
18+
timer: threading.Timer | None = None
19+
20+
1521
def debounce(arg=None):
1622
def decorator(func):
1723
if platform.is_pyodide:
1824
return arg
1925

2026
# Render only once every 1/_TARGET_FPS seconds
2127
@functools.wraps(func)
22-
def debounced(*args, **kwargs):
23-
if debounced.timer is not None:
28+
def debounced(obj, *args, **kwargs):
29+
if not hasattr(obj, "_debounce_data"):
30+
obj._debounce_data = {}
31+
32+
fname = func.__name__
33+
if obj._debounce_data.get(fname, None) is None:
34+
obj._debounce_data[fname] = _DebounceData(None, None)
35+
36+
data = obj._debounce_data[fname]
37+
38+
if data.timer is not None:
2439
# we already have a render scheduled, so do nothing
2540
return
2641

2742
def f():
2843
# clear the timer, so we can schedule a new one with the next function call
2944
t = time.time()
30-
func(*args, **kwargs)
31-
debounced.timer = None
32-
debounced.t_last = t
45+
func(obj, *args, **kwargs)
46+
data.timer = None
47+
data.t_last = t
3348

34-
if debounced.t_last is None:
49+
if data.t_last is None:
3550
# first call -> just call the function immediately
36-
debounced.t_last = time.time()
51+
data.t_last = time.time()
3752
f()
3853
return
3954

40-
t_wait = max(1 / target_fps - (time.time() - debounced.t_last), 0)
41-
debounced.timer = threading.Timer(t_wait, f)
42-
debounced.timer.start()
55+
t_wait = max(1 / target_fps - (time.time() - data.t_last), 0)
56+
data.timer = threading.Timer(t_wait, f)
57+
data.timer.start()
4358

44-
debounced.timer = None
45-
debounced.t_last = None
46-
debounced._original = func
4759
return debounced
4860

4961
if callable(arg):
@@ -77,7 +89,7 @@ class Canvas:
7789
_on_update_html_canvas: list[Callable]
7890

7991
def __init__(self, device, canvas, multisample_count=4):
80-
self._update_mutex = threading.Lock()
92+
self._update_mutex = threading.RLock()
8193
self.target_texture = None
8294

8395
self._on_resize_callbacks = []
@@ -168,11 +180,11 @@ def on_intersection(observer_entry, args):
168180
self._resize_observer.observe(self.canvas)
169181
self._intersection_observer.observe(self.canvas)
170182

171-
for func in self._on_update_html_canvas:
172-
func(html_canvas)
183+
for func in self._on_update_html_canvas:
184+
func(html_canvas)
173185

174-
self.width = self.height = 0 # force resize
175-
self.resize._original(self)
186+
self.width = self.height = 0 # force resize
187+
self.resize()
176188

177189
def on_resize(self, func: Callable):
178190
self._on_resize_callbacks.append(func)
@@ -181,9 +193,6 @@ def on_update_html_canvas(self, func: Callable):
181193
self._on_update_html_canvas.append(func)
182194

183195
def save_screenshot(self, filename: str):
184-
if self.target_texture is None:
185-
self.resize._original(self)
186-
187196
with self._update_mutex:
188197
path = pathlib.Path(filename)
189198
format = path.suffix[1:]

webgpu/scene.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
from threading import Lock
2-
31
import numpy as np
42
import time
53

@@ -47,7 +45,7 @@ def __init__(
4745
camera.transform.rotate(20, 0)
4846
light = light or Light()
4947
self.options = RenderOptions(camera, light)
50-
self._render_mutex = Lock()
48+
self._render_mutex = None
5149

5250
self._id = id
5351
self.render_objects = render_objects
@@ -75,7 +73,7 @@ def __setstate__(self, state):
7573
self.options = state["render_options"]
7674
self.canvas = None
7775
self.input_handler = InputHandler()
78-
self._render_mutex = Lock()
76+
self._render_mutex = None
7977

8078
if is_pyodide:
8179
_scenes_by_id[self._id] = self
@@ -96,6 +94,8 @@ def init(self, canvas):
9694
self.input_handler.set_canvas(canvas.canvas)
9795
self.options.set_canvas(canvas)
9896

97+
self._render_mutex = canvas._update_mutex
98+
9999
with self._render_mutex:
100100
self.options.timestamp = time.time()
101101
self.options.update_buffers()

0 commit comments

Comments
 (0)