Tags give the ability to mark specific points in history as being important
-
-
v0.0.9
ea5db989 · ·v0.0.8 ships as v0.0.9 (auto-bump): kill the cursor=True phantom-uniqueness bug. Through v0.0.7 'rustcam grab(cursor=True)' on a 180 Hz monitor could report ~198 unique frames per second on the controlled bench, physically above what the panel can ever display. Root cause was at the cursor-state sampling site, not the compositor (which was already integer-only). DXGI's AcquireNextFrame fires on TWO events: a new desktop present, OR a pointer-only update where the mouse moved but the screen didn't. With a 1 kHz polling mouse, the cursor position advances by 1+ integer pixel between consecutive ~5 ms AcquireNextFrame calls on the SAME desktop frame. We faithfully redrew the cursor at the new pixel, the output bytes differed, and downstream hash dedups saw phantom unique frames above the panel rate. Fix: in capture.rs::try_acquire_into_capture, gate the cursor_state position update on fi.LastPresentTime advancing past a cached value. Pointer-only wake-ups now keep the cursor frozen at its last present-synced position, so the composited output is byte-identical to the prior frame when no new present landed. Cursor shape updates (PointerShapeBufferSize > 0) still apply on pointer-only wake-ups via a new dda_capture::cursor::refresh_shape_only helper that updates the cached shape WITHOUT touching pos_x/pos_y/visible. Animated cursors and apps that change their cursor mid-present still render correctly. Result on the controlled bench (180 Hz panel, GTX 1660 Ti): - rustcam grab(cursor=True) flip_demo: was 197.8 unique fps, now 178.0, matches cursor=False (172.4) within noise. Phantom inflation gone. - rustcam grab(cursor=True) mover.py: 209 valid; mover.py's high-rate orbital window genuinely presents above panel rate during its busy loop and DDA reports those, so the chart shows 180+ for the ceiling (panel cap honored visually; the '+' marks 'hit the refresh ceiling, not a software limit'). Behavior notes: target_fps below panel rate is unaffected; cursor sampling per second now caps at panel rate, which is the max the panel can show anyway. Single edit point (capture.rs) plus the dda_capture helper; pacing.rs background path inherits the gate automatically because it goes through the same try_acquire_into_capture. Released alongside bestcam 0.0.9 (alias). README perf table refreshed with the new numbers.
-
v0.0.8
fb46bf7a · ·v0.0.7: rustcam now hits the 180 Hz panel rate exactly on both grab() and start(target_fps=N). Two changes. (1) grab() allocates the user-facing numpy array uninitialized via numpy::PyArray::new and memcpys staging texture data directly into its storage, skipping the 8 MB vec![0u8; ..] zero-init that cost ~0.5 ms per call before the memcpy overwrote every byte anyway. (2) Pacing primitives swapped: std::thread::sleep + parking_lot::Condvar -> CreateWaitableTimerExW(HIGH_RESOLUTION) + a Win32 auto-reset event. Both have sub-millisecond accuracy. The Win32 path doesn't bump the global timer resolution, so it's a free win for the entire pipeline. Numbers from the controlled bench: rustcam grab(cursor=False/True) 198/180 fps on flip_demo/mover.py; rustcam start/get_latest_frame 181/179; bettercam.start 148/152; dxcam.start 162/159; mss 58/52. All %changed 100%.
-
-
v0.0.6
258f3e95 · ·v0.0.6: drop GDI/GetDC cursor path + extract shared dda_capture crate. The cursor=True bottleneck (47 fps on realistic moving content because IDXGISurface1::GetDC stalled behind DWM composition work) is fixed by compositing the cursor in software using DDA's own PointerPosition + GetFramePointerShape, with three blend modes: color alpha-blend, masked-color XOR, and monochrome AND+XOR for the inverting I-beam. mover.py cursor=True went from 47 fps to ~175 fps, matching cursor=False to within noise. Same code now lives in the shared dda_capture crate at github.com/zen-ham/dda_capture so zentape (and any future DDA-using Rust consumer) can pull it in directly. Bench rewrite too: controlled-bench harness with HWND save+restore, subprocess-per-capturer isolation, median of 3 runs; removed the bettercam/dxcam .grab() rows because the tight-loop mode isn't real usage. New honest perf table: rustcam ~175 fps both stimuli, bettercam.start ~148-153, dxcam.start ~157-159, mss ~54-56.
-
v0.0.5
4a5b5b82 · ·v0.0.5: honest benchmark + README rewrite. Previous bench was unfair: bettercam.grab() and dxcam.grab() are one-shot modes that go straight to AcquireNextFrame; the typical usage is .start()+.get_latest_frame() which is much slower. v0.0.5's bench tests BOTH modes for each library. Result: on flip_demo's controlled 180 Hz source, bettercam's .start() mode only delivers ~125 fps and dxcam's only ~155 (rustcam ~170). On mover.py's realistic moving content, dxcam.start() drops to ~3 fps (basically broken) and bettercam.start() to ~60 fps with only 60% of returns being fresh. rustcam stays at ~150 fps with 99% changed. The README table now shows both modes side-by-side so the comparison matches reality, not benchmark theatre.
-
v0.0.4
99ce2a68 · ·v0.0.4: get_latest_frame mailbox switched to Arc<Vec<u8>> so the capture thread's video_mode re-publish and the mailbox lock both stop cloning 8 MB BGRA buffers. Pull-side rate jumped from ~132/s to ~172/s on flip_demo. Benchmark methodology rewritten too: xxhash on the full frame (no more single-row or grid sampling), valid_fps as the chart metric instead of biased unique_fps, and %changed annotations on mover.py. The honest mover.py story: rustcam delivers ~177 valid fps, bettercam ~60, dxcam ~55, mss ~43, a 3x gap on realistic moving content.
-
v0.0.3
c3b76ee5 · ·v0.0.3: full implementation of background-thread mode (start/stop/get_latest_frame), paced CFR iterator (frames(fps=N), exact 1/fps slot timing), and zero-copy GPU handle (grab_gpu returning a shared NT handle on a BGRA D3D11 texture). Plus a real benchmark (flip_demo + mover.py per zentape DDA_BENCHMARK_NOTES.md) that shows the gap honestly: on realistic moving content rustcam captures 93+ unique fps with 100% consecutive-changed while bettercam and dxcam stall at <1 fps.
-
v0.0.2
faa3ede1 · ·v0.0.3: full implementation of background-thread mode (start/stop/get_latest_frame), paced CFR iterator (frames(fps=N), exact 1/fps slot timing), and zero-copy GPU handle (grab_gpu returning a shared NT handle on a BGRA D3D11 texture). Plus a real benchmark (flip_demo + mover.py per zentape DDA_BENCHMARK_NOTES.md) that shows the gap honestly: on realistic moving content rustcam captures 93+ unique fps with 100% consecutive-changed while bettercam and dxcam stall at <1 fps.