8756ce38be
build and publish packages / distcc-avahi-aarch64 (push) Successful in 46s
build and publish packages / lmcp-any (push) Successful in 9s
build and publish packages / lmcp-debian (push) Successful in 4s
build and publish packages / claude-his-any (push) Successful in 7s
build and publish packages / ffmpeg-v4l2-request-aarch64 (push) Successful in 12m8s
build and publish packages / claude-his-debian (push) Successful in 5s
chromium-fourier: - patch 3/3 nv12-external-oes-on-modifier-external-only.patch — adds NativePixmapEGLBinding::ModifierRequiresExternalOES helper, extends OzoneImageGLTexturesHolder::GetBinding to honor EGL external_only flag for NV12 dmabufs on panfrost / panthor. Validated on ohm (RK3566 hantro mainline 6.19.10): bbb_1080p30_h264.mp4 plays at 34.7 % combined CPU vs ~131 % pre-patch baseline (~3.8x). - PKGBUILD pkgrel 1->2, source array + sha256sums + prepare() hook for patch 4, patch numbering 1/2,2/2 -> 1/3,2/3,3/3. - NEXT.md appended with 2026-04-28 section: patch 4 design, validation log, KWin GL_ALPHA bug pinpoint (preexisting since 2026-03-06, affects every wayland video client; unrelated to chromium-fourier), device-renumbering note (/dev/video1 = encoder post-reboot). - KWIN_PIVOT.md: 4-phase plan to identify and patch KWin's glTexImage2D(internalFormat=GL_ALPHA) site, ohm-only test plan, scope discipline. - patches/ now tracked (compiler-rt-adjust-paths, enable-v4l2, wayland-allow-direct-egl-gles2, nv12-external-oes); the dead-end chromeos-pipeline-bypass.patch removed. firefox-fourier: - 4 patches (gfxinfo v4l2 stateless fourccs, libwrapper hwdevice ctx, ffmpegvideo v4l2-request route, prefs v4l2-request default). - PKGBUILD bumped to firefox 150.0.1, Arch toolchain glue patches layered in, mozconfig with --without-wasm-sandboxed-libraries for ALARM, package() launcher fix (rm -f symlink before cat > to avoid ENOENT through the dangling /usr/local symlink mach install drops). - 150.0.1-1-aarch64.pkg.tar.zst built on boltzmann (95 MB), pending fresnel power-on for V4L2 stateless validation on RK3399.
211 lines
10 KiB
Markdown
211 lines
10 KiB
Markdown
# firefox-fourier — V4L2 Stateless Decoder Patch Plan
|
||
|
||
Plan to extend Firefox 149's V4L2 hardware decode path to cover Rockchip
|
||
mainline kernel boards (RK3399 rkvdec, RK3566/RK3588 hantro, RK3588
|
||
rkvdec2) by routing stateless `S264`/`S265`/`VP9F` fourccs through
|
||
libavcodec's `v4l2_request` hwaccel, which mainline FFmpeg surfaces via
|
||
`AV_HWDEVICE_TYPE_DRM` (no dedicated `_V4L2REQUEST` enum exists upstream
|
||
— confirmed against `libavutil/hwcontext.h`).
|
||
|
||
## 1. Files touched (in order)
|
||
|
||
| # | Path | Change | Lines |
|
||
|---|------|--------|-------|
|
||
| 1 | `widget/gtk/GfxInfo.cpp` | `V4L2ProbeDevice` (~L1030–1110): add `S264`/`S265`/`VP9F` matches alongside existing `H264`/`HEVC`/`VP90`. Set `mIsV4L2Supported = Some(true)` and OR the same `CODEC_HW_DEC_*` bits. Tag a new bool `mV4L2IsStateless` so downstream can branch. | +35 / -2 |
|
||
| 2 | `dom/media/platforms/ffmpeg/FFmpegLibWrapper.h` | Add wrappers for `av_hwdevice_ctx_create` (currently only `_alloc`/`_init` per L173–174) and `av_hwdevice_find_type_by_name`. Needed because stateless wants the *device-path-aware* `_create` form to bind `/dev/dri/renderD128`. | +4 / 0 |
|
||
| 3 | `dom/media/platforms/ffmpeg/FFmpegLibWrapper.cpp` | `dlsym` the two new pointers; gate behind `LIBAVUTIL_VERSION_MAJOR >= 56`. | +6 / 0 |
|
||
| 4 | `dom/media/platforms/ffmpeg/FFmpegVideoDecoder.h` | Add `AVBufferRef* mDRMDeviceContext = nullptr;` and `bool mUsingV4L2Request = false;` next to existing `mUsingV4L2`. | +3 / 0 |
|
||
| 5 | `dom/media/platforms/ffmpeg/FFmpegVideoDecoder.cpp` | New `CreateV4L2RequestDeviceContext()` modelled on `CreateVAAPIDeviceContext` (current uses `av_hwdevice_ctx_alloc(AV_HWDEVICE_TYPE_VAAPI)`). Wire it in alongside the existing V4L2 init branch (the one feeding `ChooseV4L2PixelFormat` at L~258). `FindVideoHardwareAVCodec` call at L708 stays unchanged for stateless — we want the *generic* `h264`/`hevc`/`vp9` decoder + a DRM hw_device_ctx, not a `_v4l2m2m` codec. | +90 / -5 |
|
||
| 6 | `modules/libpref/init/StaticPrefList.yaml` | New pref `media.ffmpeg.v4l2-request.enabled` mirroring `media.ffmpeg.vaapi.enabled` (default `@IS_LINUX@`). | +6 / 0 |
|
||
| 7 | `dom/media/ipc/RDDProcessHost.cpp` + sandbox policy file | Whitelist `/dev/media*`, `/dev/dri/renderD*`, `/dev/video*` for the RDD process (already partly done for VAAPI — verify `policy/linux/SandboxBrokerPolicyFactory.cpp`). | +6 / 0 |
|
||
|
||
Total: roughly **+150 / -10** across 7 files.
|
||
|
||
## 2. Probe extension — `GfxInfo.cpp::V4L2ProbeDevice`
|
||
|
||
Existing pattern (~L1075):
|
||
```cpp
|
||
if (outFormats.Contains("H264")) { mIsV4L2Supported = Some(true);
|
||
mV4L2SupportedCodecs |= CODEC_HW_DEC_H264; ... }
|
||
```
|
||
|
||
Add three siblings, each setting an additional `mV4L2IsStateless = true`:
|
||
```cpp
|
||
if (outFormats.Contains("S264")) { /* CODEC_HW_DEC_H264 | stateless */ }
|
||
if (outFormats.Contains("S265")) { /* CODEC_HW_DEC_HEVC | stateless */ }
|
||
if (outFormats.Contains("VP9F")) { /* CODEC_HW_DEC_VP9 | stateless */ }
|
||
```
|
||
|
||
Decision: do **not** introduce a separate `mIsV4L2StatelessSupported`.
|
||
Collapse under `mIsV4L2Supported` so the existing feature-gate plumbing
|
||
(`MediaCodecsSupport`, `gfxFeature::HW_DECODE_VIDEO`) flips identically
|
||
— only `mV4L2IsStateless` distinguishes the routing in step 3. Stateful
|
||
+ stateless on the same SoC (rare, but RK3588 has both rkvdec2 + hantro
|
||
VEPU) gracefully degrades to whichever codec wins enumeration order.
|
||
|
||
The capture-format gate (`YV12`/`NV12`) needs widening: stateless
|
||
decoders frequently expose only `NV12` or `NV15` (10-bit, RK3588 HEVC).
|
||
Add `NV15` and `NM12` (multiplanar NV12, hantro). Without this the
|
||
prober rejects an otherwise-good device.
|
||
|
||
## 3. Decoder routing — `FFmpegVideoDecoder.cpp`
|
||
|
||
Codec selection happens at **L651** (`AV_HWDEVICE_TYPE_VAAPI` →
|
||
`h264_vaapi`) and **L708** (the V4L2 fallback path → `h264_v4l2m2m` via
|
||
`FindVideoHardwareAVCodec(mLib, mCodecID)` resolving by suffix). The
|
||
stateless route diverges from both: the *codec* must remain the generic
|
||
`h264`/`hevc`/`vp9` decoder (libavcodec auto-binds `v4l2_request` from
|
||
its `hw_configs` when a DRM hw_device_ctx is attached). Pseudo-patch:
|
||
|
||
```cpp
|
||
if (gfxInfo.mUsingV4L2 && gfxInfo.mV4L2IsStateless) {
|
||
AVCodec* codec = mLib->avcodec_find_decoder(mCodecID); // generic
|
||
mCodecContext = mLib->avcodec_alloc_context3(codec);
|
||
if (!CreateV4L2RequestDeviceContext()) return false;
|
||
mCodecContext->get_format = ChooseV4L2PixelFormat; // already returns DRM_PRIME
|
||
mUsingV4L2Request = true;
|
||
}
|
||
```
|
||
|
||
`CreateV4L2RequestDeviceContext()` body:
|
||
```cpp
|
||
const char* drm = "/dev/dri/renderD128";
|
||
if (mLib->av_hwdevice_ctx_create(&mDRMDeviceContext,
|
||
AV_HWDEVICE_TYPE_DRM, drm, nullptr, 0) < 0) return false;
|
||
mCodecContext->hw_device_ctx = mLib->av_buffer_ref(mDRMDeviceContext);
|
||
```
|
||
|
||
`av_hwdevice_ctx_create` — not currently wrapped — is the entry point.
|
||
The codec's internal hwaccel selector then walks
|
||
`avcodec_get_hw_config()` and picks the entry whose `device_type ==
|
||
AV_HWDEVICE_TYPE_DRM` and `pix_fmt == AV_PIX_FMT_DRM_PRIME`, which is
|
||
the v4l2_request hwaccel registered in `libavcodec/v4l2_request_*.c`.
|
||
No `av_hwdevice_find_type_by_name("v4l2_request")` needed — stays an
|
||
internal libavcodec name.
|
||
|
||
## 4. Dmabuf / DRM_PRIME reuse
|
||
|
||
`ChooseV4L2PixelFormat` at L~258–270 already returns
|
||
`AV_PIX_FMT_DRM_PRIME` and is the *only* format the v4l2_request
|
||
hwaccel produces. The downstream consumer (DMABufSurfaceYUV import in
|
||
`FFmpegVideoFramePool.cpp`) is already DRM_PRIME-aware for the
|
||
stateful path — same code reads `AVDRMFrameDescriptor` from
|
||
`frame->data[0]`. **No new output handling required for NV12/YV12.**
|
||
|
||
10-bit caveat: RK3588 HEVC outputs `DRM_FORMAT_NV15` / `NV20`
|
||
(Mali-tile). Existing `WaylandDMABufSurface::CreateYUVSurface`
|
||
modifier list does not include `DRM_FORMAT_MOD_ARM_AFBC` or NV15
|
||
fourcc. Either reject 10-bit at probe (capture format gate above) or
|
||
extend `gfx/layers/DMABUFSurfaceImage.cpp` — out of scope for v1; gate
|
||
to NV12 only.
|
||
|
||
SAND format pollution Turner mentioned in bug 1969297 c#3 is
|
||
**Pi5-specific**; rkvdec/hantro do not produce SAND. Safe to ignore for
|
||
the Rockchip target.
|
||
|
||
## 5. Configuration
|
||
|
||
New pref:
|
||
```yaml
|
||
- name: media.ffmpeg.v4l2-request.enabled
|
||
type: RelaxedAtomicBool
|
||
value: @IS_LINUX@
|
||
mirror: always
|
||
```
|
||
|
||
No new env var. No `MOZ_X11_EGL`-style kludge. The existing
|
||
`MOZ_LOG=PlatformDecoderModule:5` covers diagnostics. Default-on
|
||
matches `media.ffmpeg.vaapi.enabled` shape; users get fallback to
|
||
software via existing failure paths if `av_hwdevice_ctx_create` fails
|
||
(e.g., missing `/dev/media0`).
|
||
|
||
## 6. Test plan (fresnel — RK3399, KDE Wayland)
|
||
|
||
1. `ls /dev/video* /dev/media*` — confirm `/dev/video0` (rkvdec
|
||
output) and `/dev/media0` exist.
|
||
2. `v4l2-ctl -d /dev/video0 --list-formats-out` — expect
|
||
`S264`/`S265`/`VP9F`.
|
||
3. Start: `MOZ_LOG="PlatformDecoderModule:5,FFmpegVideo:5"
|
||
firefox-fourier 2>&1 | tee fx.log`.
|
||
4. Open `https://test-videos.co.uk/bigbuckbunny/mp4-h264` 1080p clip.
|
||
5. Success markers in `fx.log`:
|
||
- `V4L2ProbeDevice: /dev/video0 supports S264 (stateless)`
|
||
- `Choosing FFmpeg pixel format for V4L2 video decoding.`
|
||
- `Requesting pixel format DRM PRIME`
|
||
- `av_hwdevice_ctx_create(DRM, /dev/dri/renderD128) ok`
|
||
- **No** `Using preferred software codec h264`.
|
||
6. `cat /sys/kernel/debug/clk/clk_summary | grep vdec` — clock should
|
||
be active during playback.
|
||
7. `top` — CPU < 40% on a single A72 core for 1080p H.264 (stock =
|
||
100% on all 6 cores).
|
||
|
||
## 7. Build + ship — `firefox-fourier` PKGBUILD
|
||
|
||
Mirror `chromium-fourier` shape exactly (sibling).
|
||
|
||
```bash
|
||
pkgname=firefox-fourier
|
||
pkgver=149.0
|
||
arch=('aarch64' 'x86_64')
|
||
makedepends=(rust clang lld nodejs python cbindgen nasm yasm wasi-libc-bin
|
||
gtk3 mesa libva ffmpeg) # ffmpeg only for headers via system libs
|
||
source=(
|
||
"https://archive.mozilla.org/pub/firefox/releases/${pkgver}/source/firefox-${pkgver}.source.tar.xz"
|
||
patches/0001-gfxinfo-v4l2-stateless-fourccs.patch
|
||
patches/0002-libwrapper-hwdevice-ctx-create.patch
|
||
patches/0003-ffmpegvideo-v4l2-request-route.patch
|
||
patches/0004-prefs-v4l2-request.patch
|
||
mozconfig
|
||
)
|
||
```
|
||
|
||
`prepare()`: `cd firefox-${pkgver}` → apply patches with `patch -Np1`.
|
||
`build()`: `MOZ_NOSPAM=1 ./mach build`. `package()`: `./mach install
|
||
DESTDIR=${pkgdir}`. `mozconfig` enables
|
||
`--enable-default-toolkit=cairo-gtk3-wayland`, `--with-system-ffmpeg`,
|
||
`ac_add_options --disable-tests`. **No** `--enable-media-gpu-process`
|
||
— let it default. Tarball is the official Mozilla source release (not
|
||
gecko-dev).
|
||
|
||
Extra makedepends vs. stock firefox PKGBUILD: none — this only
|
||
modifies existing C++.
|
||
|
||
## 8. Risk register (ranked)
|
||
|
||
1. **libavcodec ABI mismatch.** ALARM ships ffmpeg 7.x; Firefox dlopens
|
||
whatever's at `libavcodec.so.61`. If the v4l2_request hwaccel was
|
||
compiled out (Arch's ffmpeg has it; ALARM rebuild may not),
|
||
`av_hwdevice_ctx_create(DRM, ...)` succeeds but no codec binds —
|
||
silent fallback. Mitigation: `ffmpeg -hwaccels` should list `drm`.
|
||
2. **Renderer-process sandbox** blocks `/dev/dri/renderD128` open.
|
||
VAAPI already brokered this for RDD process; verify
|
||
`SandboxBrokerPolicyFactory.cpp` covers `/dev/media*` too — likely
|
||
doesn't.
|
||
3. **glxtest probe runs in stripped env.** `v4l2test` (the
|
||
FireTestProcess child) needs `cap_sys_admin` for
|
||
`VIDIOC_S_EXT_CTRLS` request API ioctls? No — request API just
|
||
needs `O_RDWR` on `/dev/media*`. Should be fine.
|
||
4. **Regression of stateful path.** Adding new fourccs is additive;
|
||
the routing branch is gated on `mV4L2IsStateless`. Stateful boards
|
||
(Pi4) untouched.
|
||
5. **NV15/10-bit on RK3588** — explicitly out-of-scope v1;
|
||
gate-rejected.
|
||
6. **rkvdec2 driver maturity.** Linux 6.12 mainline rkvdec2 H.264
|
||
works; HEVC/VP9 still upstream-pending on some boards. Probe will
|
||
skip what kernel doesn't expose.
|
||
7. **DMA-BUF modifier negotiation** with panfrost/panthor on Wayland
|
||
— already shaken out by chromium-fourier on RK3566; same code
|
||
path.
|
||
|
||
## 9. Upstream path (bug 1969297)
|
||
|
||
Split into 4 reviewable commits matching files 1, 2+3, 5, 6 from the
|
||
table. Add a gtest exercising `V4L2ProbeDevice` against a synthetic
|
||
v4l2test stdout containing `S264` (no kernel needed). Reach out to
|
||
skyevg (D252119 author) for review continuity. r? jya for the
|
||
FFmpegVideoDecoder change. The `av_hwdevice_ctx_create` wrapper
|
||
addition is a self-contained 6-liner that should land independently.
|
||
The 10-bit/SAND concerns Turner raised remain valid for Pi5 —
|
||
explicitly scope this series to **stateless DRM_PRIME NV12 only**,
|
||
leaving SAND for a follow-up bug.
|