Skip to content

v0.2.1

Choose a tag to compare

@Shalasere Shalasere released this 09 Sep 18:18
· 241 commits to main since this release

Contents

bc250_drv_video.so and its matching compiled shaders (shaders/*.spv), built from the current main.

Install: copy bc250_drv_video.so and shaders/ into the repository root, then run sudo ./tools/setup_bazzite.sh (Bazzite/Silverblue/Kinoite) or sudo ./tools/setup_steamos.sh (SteamOS/HoloISO). Both scripts require the compiled shaders directory; bc250_drv_video.so alone is non-functional.

Fixes since v0.2.0 (93 commits)

1. pic_init_qp_minus26 range violation.
h264_encoder_set_qp() wrote the raw QP into pps.pic_init_qp without the -26 offset the field's encoding requires (ITU-T H.264, bitstream.h). At QP ≈ 26, this produced a value one past the legal maximum (25), which any spec-compliant decoder rejects. Fix: pps.pic_init_qp = qp - 26. Not exercised by synthetic test content, which never sets a nonzero pic_init_qp.

2. P-slice skip decision omitted chroma residual.
The skip-legality check (mb_has_any_luma_nonzero) considered only luma coefficients. Per ITU-T 8.4.1.1, a P_Skip macroblock must carry zero residual for the entire macroblock, chroma included. A macroblock with nonzero chroma residual and zero luma residual was still certified skip-legal, dropping the chroma correction from the bitstream. Because the GPU-side reference reconstruction (reconstruct.comp) applied that same chroma residual unconditionally, the encoder's own future-frame reference retained a correction that was never transmitted — a one-way divergence uncorrected until the next IDR. Fix: mb_has_any_chroma_nonzero(), applied at both skip-decision sites (CAVLC, CABAC). Effect measured via the project's PSNR/SSIM harness: 51.5 dB → 59.6 dB average, SSIM 0.996 → 0.9994.

3. Slice bitstream buffer undersized for real content.
rbsp_buf_size = (end_mb - start_mb) * 64 + 4096 — a 64 bytes/macroblock budget calibrated against synthetic test patterns with low per-block AC energy. Real content at low QP exceeds this; on overflow, both the CAVLC and CABAC writers detect the condition and stop writing (no memory-safety issue) but the resulting bitstream is truncated at that point, desyncing any downstream decoder. Fix: 768 bytes/macroblock. Verified against captured frames from a real session that reproduced the overflow: PSNR 22.3 dB → 52.1 dB, zero decode errors, zero overflow events (previously logged as CABAC slice buffer overflow).

4. Executable bit lost on every .sh script in the repository.
Tracked file mode was 100644 (non-executable) across the board — an artifact of this repository having been edited from an NTFS checkout, which does not represent the Unix executable bit. Fixed via git update-index --chmod=+x on every script; internal script-to-script invocations of install_dkms.sh changed from ./install_dkms.sh to bash ./install_dkms.sh as a defense against recurrence.

Testing on hardware

  1. Driver load. LIBVA_DRIVER_NAME=bc250 vainfo should list the driver (AMD BC-250 RDNA2 Compute VA-API Driver) and enumerate at minimum an H.264 Main/High profile with VAEntrypointEncSlice. A missing driver entry or vaInitialize failure indicates the .so or LIBVA_DRIVERS_PATH is not correctly installed — re-check the setup script's summary output.
  2. Shader load. journalctl --user-unit=<sunshine unit> (or the equivalent stderr capture for whatever VA-API client is used) should show no [bc250-gpu] shader-load errors on first encode dispatch. This is where a missing/mismatched shaders/*.spv set surfaces if the install-time check was somehow bypassed.
  3. Synthetic correctness gate. If build tools are available, tools/quality_test.sh runs a real encode of synthetic content through the installed pipeline and scores decoded output against ground truth via PSNR/SSIM (pass threshold: 25 dB average). This does not require a streaming client and takes under a minute.
  4. Real client session. Configure Sunshine's Video Encoder to VA-API, connect a Moonlight client, and inspect ~/.config/sunshine/sunshine.log for CLIENT CONNECTED with no immediately following decode/codec errors on the client side. grep -i overflow against the driver's stderr (journal, if run under systemd) should return nothing.
  5. Sustained-motion / scene-change check. To exercise the open rate-control issue below: stream content with an abrupt large-area screen change (e.g. scrolling a content-heavy list, switching applications) and watch for a visible quality drop that persists for longer than roughly one GOP interval (default: a few seconds) rather than recovering within a frame or two. Its presence is expected pending a rate-control fix; its absence would itself be worth reporting, as it would suggest the underlying condition is content- or path-dependent in a way not yet characterized.

Open issue, not fixed in this release

Rate control (rate_control.c) responds to a large single-frame bitrate excursion by holding QP elevated for the duration required to drain a 1-second leaky-bucket buffer (RC_CBR mode), rather than the 2-frame low-latency buffer already implemented as RC_LOW_LATENCY and documented in-code as intended for this exact use case. rc_init() currently hardcodes RC_CBR regardless of context. Effect: a legitimate content-complexity spike produces a visible, sustained quality drop lasting up to a full GOP. Root cause identified and reproduced offline; no fix applied. See docs/DEVLOG.md for the full trace.