Skip to content

fix(core): Comprehensive fixes and performance optimizations#18

Draft
ehfd wants to merge 9 commits into
linuxserver:masterfrom
ehfd:comprehensive-fixes
Draft

fix(core): Comprehensive fixes and performance optimizations#18
ehfd wants to merge 9 commits into
linuxserver:masterfrom
ehfd:comprehensive-fixes

Conversation

@ehfd

@ehfd ehfd commented Jun 13, 2026

Copy link
Copy Markdown
Collaborator

Complementary to selkies-project/selkies#254. Backward-incompatible components.

@ehfd ehfd changed the title fix(core): Performance optimizations fix(core): Comprehensive fixes and performance optimizations Jun 13, 2026
@ehfd ehfd force-pushed the comprehensive-fixes branch 6 times, most recently from 16230a8 to 6d157bd Compare June 20, 2026 10:16
@ehfd ehfd force-pushed the comprehensive-fixes branch 9 times, most recently from 8eca424 to aeb6f84 Compare June 22, 2026 06:36
@ehfd ehfd force-pushed the comprehensive-fixes branch 3 times, most recently from a7fefd2 to b867225 Compare June 25, 2026 05:10
@ehfd ehfd force-pushed the comprehensive-fixes branch from b867225 to 84f20c4 Compare July 2, 2026 12:28
@ehfd ehfd requested a review from Copilot July 2, 2026 13:08

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR consolidates pixelflux into a single self-contained Rust (PyO3) extension module that implements both X11 and Wayland capture plus encoding/conversion, while adding substantial performance, safety, and operational improvements across the capture/encode pipeline (NVENC/VA-API/software), including multi-GPU container handling and runtime API/version negotiation.

Changes:

  • Packaging/build refactor: drop the legacy Python/C++ packaging layers and build a single pixelflux Rust extension via setuptools-rust + updated cibuildwheel configuration.
  • New/rewritten capture + pipeline components: add an X11 XShm capture path in Rust, a shared pipeline for full-frame decisions (paint-over/recovery IDR), and a bounded recording sink for H.264 fan-out.
  • Encoder/runtime hardening & perf: multi-GPU NVENC ioctl filtering, NVENC API negotiation, VA-API cleanup + host-input path, software encoder optimizations (thread-local JPEG compressor, x264 open/close serialization, improved damage hashing).

Reviewed changes

Copilot reviewed 27 out of 36 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
setup.py Switches distribution to a single Rust extension module (pixelflux) and removes the legacy C++ build path.
pyproject.toml Updates cibuildwheel build matrix and provisioning steps for the new single-extension build.
README.md Updates installation/docs to match the new single Rust extension API and zero-copy frame model.
MANIFEST.in Updates sdist includes for the new Rust crate layout.
pixelflux/Cargo.toml Introduces the new unified Rust crate (cdylib) and dependency set (ffmpeg-next 8.1 pinned, smithay, x11rb, nvcodec-sys).
pixelflux/.gitignore Adds Rust build outputs to ignore list.
pixelflux/init.py Removes the legacy ctypes-based Python wrapper layer.
pixelflux/src/x11/mod.rs Adds a Rust X11 XShm capture implementation with a bounded capture→encode handoff.
pixelflux/src/pipeline.rs Adds shared full-frame decision logic (paint-over + recovery/on-demand IDR policy).
pixelflux/src/recording_sink.rs Adds an out-of-band Unix socket H.264 recording sink with per-client bounded queues.
pixelflux/src/wayland/mod.rs Defines Wayland module structure for the unified crate.
pixelflux/src/wayland/frontend.rs Cursor hashing/stride hardening, cache eviction changes, and callback GIL attachment updates.
pixelflux/src/wayland/cursor.rs Hardens xcursor parsing against empty-image cursor files.
pixelflux/src/encoders/mod.rs Adds unified encoder module layout.
pixelflux/src/encoders/software.rs Performance + correctness work: thread-local JPEG compressor, x264 open/close serialization, new damage hashing, header omission support, rate control improvements.
pixelflux/src/encoders/nvenc.rs NVENC API negotiation, multi-GPU container filtering install, header omission, better error handling and resource teardown.
pixelflux/src/encoders/vaapi.rs Improves unwind safety/cleanup, adds host-input VAAPI path, supports header omission, and rate-control fixes.
pixelflux/src/encoders/overlay.rs Adds overlay/watermark state utilities for Smithay rendering.
pixelflux/src/nvgpufilter.rs Adds GOT-patched ioctl filter to drop unreachable GPUs inside containers on affected drivers.
pixelflux/nvcodec-sys/* Introduces an in-tree NVENC/CUDA binding crate with optional regen flow.
pixelflux_wayland/* Removes the old separate Wayland extension crate (now unified).
example/screen_to_browser.py Updates example usage to the new callback/frame object API and zero-copy send model.
Comments suppressed due to low confidence (2)

pixelflux/src/encoders/software.rs:84

  • Using bitrate_kbps.abs() can overflow for i32::MIN (wrap in release / panic in debug), which could misconfigure x264 rate control. Prefer saturating_abs() for a safe, bounded value.
    pixelflux/src/encoders/software.rs:155
  • Using bitrate_kbps.abs() can overflow for i32::MIN (wrap in release / panic in debug). Use saturating_abs() so runtime rate updates can't trigger an overflow edge case.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread MANIFEST.in
Comment thread pixelflux/src/x11/mod.rs
Comment thread pixelflux/src/x11/mod.rs Outdated
@ehfd ehfd force-pushed the comprehensive-fixes branch 5 times, most recently from 48fde0f to d8973bf Compare July 5, 2026 06:41
@rmounce

rmounce commented Jul 7, 2026

Copy link
Copy Markdown

Two findings from second-eye testing this branch (together with selkies-project/selkies#254) on an Ubuntu noble (lsio-based) image, Intel laptop:

1. The module can't import on noble even for X11-only use: undefined symbol: wl_client_set_max_buffer_size. The wayland crate is built with its libwayland_1_23 feature, so the compiled module references wl_client_set_max_buffer_size (added in wayland 1.23) at load time. Noble ships wayland 1.22, so a wheel built from source on noble fails at import pixelflux even when only X11 capture will ever be used (and selkies then degrades — see the companion report on selkies#254). We worked around it by source-building wayland 1.23.1 into /usr/local (recipe posted on selkies#254). Worth considering loading the wayland side lazily / feature-gating 1.23, or documenting the floor — noble is what the linuxserver images are on today.

2. VA-API encode on X11 always falls back to software: the filter graph is parsed before the VAAPI device is attached. On an Intel iGPU where the device derive and avcodec_open2 on h264_vaapi all succeed, capture start logs:

[hwupload @ 0x...] A hardware device reference is required to upload frames to.
[AVFilterGraph @ 0x...] Error processing filtergraph: Invalid argument
[x11] VAAPI init failed (Failed to parse filter graph); falling back to software

In vaapi.rs new_impl, the loop that sets hw_device_ctx on the graph's filters runs after avfilter_graph_parse_ptr — but with ffmpeg 8.1, hwupload's format negotiation happens inside the parse call, so it errors out before the attach loop is reached. Only the X11/host_input path is affected: its buffersrc is plain BGRA with no hw_frames_ctx, so hwupload can only get the device from the filter's hw_device_ctx; the Wayland path's hwmap can derive it from the DRM-PRIME buffersrc's frames context, and NVENC doesn't use this graph. A fix is to split parsing from initialization with the avfilter_graph_segment_* API (parse → create filters → set hw_device_ctx → init/apply), which is how the ffmpeg CLI orders it.

🤖 Generated with Claude Code

@ehfd ehfd force-pushed the comprehensive-fixes branch from 8dbc8ab to b32a178 Compare July 7, 2026 10:08
@ehfd

ehfd commented Jul 7, 2026

Copy link
Copy Markdown
Collaborator Author

@ehfd ehfd force-pushed the comprehensive-fixes branch from b0c37a8 to 6c64fc7 Compare July 8, 2026 16:53
@ehfd ehfd force-pushed the comprehensive-fixes branch from 4169dab to a08bf5c Compare July 9, 2026 07:29
@ehfd ehfd force-pushed the comprehensive-fixes branch from a08bf5c to 6d0edad Compare July 9, 2026 09:16
Comment thread pixelflux/src/lib.rs
let mut width: i32 = if initial_width > 0 { initial_width } else { 1024 };
let mut height: i32 = if initial_height > 0 { initial_height } else { 768 };

if let Ok(w_str) = std::env::var("SELKIES_MANUAL_WIDTH") {

@ehfd ehfd Jul 9, 2026

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@thelamer I moved all envvars into Selkies configurations and exposed them through internal ABI configurations pushed from Selkies (harder to manage lists of environments otherwise). Not desired.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will be the only one without re-writing the standard module init to accept vars on just loading the module or making a new function to just init the display without starting the stream. This seems like the easiest way and is battle tested.

@ehfd ehfd Jul 9, 2026

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then, I must refactor it on Sunday. Just let me know of similar things and I'll refactor it later on.

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.

4 participants