Report about compiling Chromium 146 on FreeBSD ARM64 (with Hardware Video Decode) using ninja to speed up the process.

Hello to everyone.

This report documents the complete process of cross-compiling Chromium 146.0.7680.177 for FreeBSD 15.0 AArch64 patching it with the default patches but then patching the remaining code manually,error after error with the goal to compile the code with ninja to speed up the process of about the 20% ,skipping the use of a VM. The target is the Radxa Zero 3W single-board computer (Rockchip RK3566 SoC), with full hardware-accelerated video decode via the Hantro G1 VPU using VA-API. The build host is an x86_64 FreeBSD 14.3 machine running inside a ZFS environment.

If you find this work useful,it makes me happy and feel free to ask.

The end result is a fully working Chromium build with:

- Hardware-accelerated GPU compositing, Canvas, WebGL, WebGPU (via Panfrost/DRM)
- Hardware-accelerated H.264 video decode (via VA-API → Hantro VPU → /dev/dri/renderD128)

---
Hardware and Software

Code:
  ┌──────────────────┬──────────────────────────────────────────────────────┐
  │    Component     │                        Detail                        │                         
  ├──────────────────┼──────────────────────────────────────────────────────┤
  │ Target board     │ Radxa Zero 3W (Rockchip RK3566)                      │
  ├──────────────────┼──────────────────────────────────────────────────────┤
  │ Target OS        │ FreeBSD 15.0-CURRENT AArch64                         │                         
  ├──────────────────┼──────────────────────────────────────────────────────┤
  │ Build host       │ FreeBSD 14.x x86_64 (Linuxulator)                    │                         
  ├──────────────────┼──────────────────────────────────────────────────────┤                         
  │ Chromium version │ 146.0.7680.177                                       │
  ├──────────────────┼──────────────────────────────────────────────────────┤                         
  │ Compiler         │ Clang/LLVM 19 (cross, aarch64-unknown-freebsd15.0)   │
  ├──────────────────┼──────────────────────────────────────────────────────┤                         
  │ Rust             │ 1.92 (cross, custom sysroot with real aarch64 rlibs) │
  ├──────────────────┼──────────────────────────────────────────────────────┤                         
  │ GPU driver       │ Panfrost (DRM/KMS, OpenGL 3.1)                       │
  ├──────────────────┼──────────────────────────────────────────────────────┤                         
  │ Video decode     │ Hantro G1 VPU via hantro_drv_video.so (VA-API)       │
  └──────────────────┴──────────────────────────────────────────────────────┘

---
1. Build Configuration (args.gn)

The complete args.gn for cross-compiling from x86_64 FreeBSD to AArch64 FreeBSD:

Code:
target_os = "freebsd"                                                                                
target_cpu = "arm64"                                                                                
host_os = "freebsd"                                                                                  
host_cpu = "x64"                                          
is_clang = true                                                                                      
clang_use_chrome_plugins = false
use_lld = true                                                                                      
is_debug = false                                          

custom_toolchain = "//build/toolchain/freebsd:clang_arm64"                                          

use_sysroot = false                                                                                  
target_sysroot = "/path/to/aarch64-sysroot"                

clang_base_path = "/usr/local/llvm19"                                                                
clang_version = "19"                                                                                
cc_wrapper = "ccache"                                                                                

enable_backup_ref_ptr_support = false                                                                
fatal_linker_warnings = false
icu_use_data_file = false                                                                            
optimize_webui = true                                      
toolkit_views = true                                                                                
treat_warnings_as_errors = false                                                                    
use_allocator_shim = false
use_aura = true                                                                                      
use_custom_libcxx = true                                                                            
use_custom_libunwind = true
use_partition_alloc = true                                                                          
use_partition_alloc_as_malloc = false                      
use_system_harfbuzz = true                                                                          
use_system_libffi = true
use_system_libjpeg = true                                                                            
use_udev = false                                                                                    
use_dbus = true
use_gio = true                                                                                      

enable_rust = true
rust_sysroot_absolute = "/path/to/rust-arm64-sysroot"                                                
added_rust_stdlib_libs = [ "adler2", "rustc_literal_escaper" ]                                      
removed_rust_stdlib_libs = [ "adler" ]                                                              

proprietary_codecs = true                                                                            
ffmpeg_branding = "Chrome"                                
enable_av1_decoder = true                                                                            
enable_dav1d_decoder = true
use_v4l2_codec = false   # must be false when use_vaapi = true                                      
use_vaapi = true         # enable VA-API for hardware video decode

enable_widevine = true                                                                              

use_ozone = true                                                                                    
ozone_platform_x11 = true                                  
ozone_platform_wayland = true

enable_webrtc = true
enable_pdf = true                                                                                    
enable_print_preview = true                                
use_cups = true
enable_extensions = true                                                                            
enable_hangout_services_extension = true
use_pangocairo = true                                                                                

use_pulseaudio = true
use_sndio = false                                                                                    
rtc_use_pipewire = false                                  

use_qt5 = false
use_qt6 = false                                                                                      

arm_control_flow_integrity = "none"                                                                  

concurrent_links = 2                                                                                
symbol_level = 1                                          
blink_symbol_level = 0                                                                              
is_component_build = false


Critical note: use_v4l2_codec and use_vaapi are mutually exclusive in Chromium's build system (media/gpu/BUILD.gn asserts !(use_v4l2_codec && use_vaapi)). Also, use_vaapi defaults to false for non-Linux and for ARM targets — it must be explicitly set to true in args.gn.

---
2. Sysroot: VA-API Stub Libraries

The cross-compilation sysroot needs link-time stubs for libva, libva-drm, and libva-x11. These are empty shared libraries that satisfy the linker — the real libraries live on the target device.

Copy VA headers from the target Radxa:

# On the target

Code:
scp -r /usr/local/include/va/ buildhost:/path/to/aarch64-sysroot/usr/local/include/

# pkg.conf files

Code:
scp /usr/local/libdata/pkgconfig/libva*.pc buildhost:/path/to/aarch64-sysroot/usr/local/libdata/pkgconfig/

Build ARM64 stub .so files on the build host:

Code:
CC=/usr/local/bin/clang                                                                             
TRIPLE=aarch64-unknown-freebsd15.0                                                                   
SYSROOT=/path/to/aarch64-sysroot                                                                     
 
# libva stub — list all symbols from the real libva.so.2 on your target:                             
# nm -D /usr/local/lib/libva.so.2 | awk '$2=="T"{print "void "$3"(void) {}"}' > libva_stub.c
$CC --target=$TRIPLE --sysroot=$SYSROOT -shared -fPIC -o $SYSROOT/usr/local/lib/libva.so libva_stub.c
                                                                                                      
# libva-drm stub                                                                                     
echo 'void vaGetDisplayDRM(void) {}' > libva_drm_stub.c                                             
$CC --target=$TRIPLE --sysroot=$SYSROOT -shared -fPIC -o $SYSROOT/usr/local/lib/libva-drm.so         
libva_drm_stub.c                                                                                     
                                                                                                      
# libva-x11 stub — include vaGetDisplay, vaPutSurface, VA_DRI2* symbols                             
$CC --target=$TRIPLE --sysroot=$SYSROOT -shared -fPIC -o $SYSROOT/usr/local/lib/libva-x11.so
libva_x11_stub.c                                                                                     
                                                            
# Symlink pkgconfig                                                                                 
ln -s /usr/local/libdata/pkgconfig/libva.pc $SYSROOT/usr/local/lib/pkgconfig/libva.pc
# (repeat for libva-drm.pc and libva-x11.pc)

---
3. Launch Flags

The following flags are required at runtime:

Code:
DISPLAY=:0 LIBVA_DRIVER_NAME=hantro /path/to/chrome \
    --no-sandbox \                                                                                     
    --ignore-gpu-blocklist \                                 
    --disable-features=FallbackToSWIfGLES3NotSupported \                                               
    --enable-features=AcceleratedVideoDecoder,VaapiIgnoreDriverChecks \
    --enable-accelerated-video-decode

Flag: LIBVA_DRIVER_NAME=hantro

Why it is needed: Tells libva to load hantro_drv_video.so instead of auto-detecting

────────────────────────────────────────
Flag: --ignore-gpu-blocklist

Why it is needed: Chrome's GPU blocklist disables acceleration for unknown/untested GPUs; Panfrost is not on the allowlist
────────────────────────────────────────
Flag: --disable-features=FallbackToSWIfGLES3NotSupported

Why it is needed: Panfrost exposes OpenGL 3.1, not 4.x. ANGLE cannot initialise GLES3. Without this flag,Chrome falls back to software rendering entirely instead of allowing a GLES2 fallback
────────────────────────────────────────

Flag: --enable-features=AcceleratedVideoDecoder

Why it is needed: The VA-API video decode feature is named "AcceleratedVideoDecoder" in media/base/media_switches.cc, not "VaapiVideoDecoder". It defaults to disabled when USE_VAAPI=0 at compile time; our build has USE_VAAPI=1 but the flag is still needed to override the default for FreeBSD
────────────────────────────────────────

Flag: --enable-features=VaapiIgnoreDriverChecks

Why it is needed: Skips Chrome's internal VA-API driver version/vendor checks

────────────────────────────────────────
Flag: --enable-accelerated-video-decode

Why it is needed: Legacy command-line switch, kept for compatibility

---
4. Verification

After launching Chrome with the flags above:

chrome://gpu shows :
Video Decode: Hardware accelerated

During H.264 video playback, the Hantro VPU accesses the DRM render node:

Code:
fstat | grep -E 'hantro|dri|video'                                                                   
# Expected output:                                                                                   
# chrome  <pid>  <fd>  /dev  112  crw-rw----  dri/renderD128  rw                                                                                                 
hantro_drv_video.so uses /dev/dri/renderD128 (the DRM render node), not /dev/hantro0 directly.

---
5. What Does NOT Work (yet)

- Hardware video encode: hantro_drv_video.so v0.1 does not implement VA-API encode entrypoints. Encode remains software-only.
- Vulkan: LLVMpipe Vulkan does not work with Chrome's ANGLE Vulkan renderer on this platform.
- WebRTC hardware encode: Same limitation as video encode above.

---
6. Files Changed (summary for patch submission)

Code:
  ┌──────────────────────────────────────────────────────────┬───────────────────────────────────────────┐
  │                           File                           │                  Change                   │
  ├──────────────────────────────────────────────────────────┼───────────────────────────────────────────┤
  │ out/freebsd-arm64/args.gn                                │ use_vaapi=true, use_v4l2_codec=false      │
  ├──────────────────────────────────────────────────────────┼───────────────────────────────────────────┤
  │ third_party/angle/src/gpu_info_util/SystemInfo_linux.cpp │ Placeholder GPU entry for ARM SoCs with   │
  │                                                          │ no PCI bus                                │
  ├──────────────────────────────────────────────────────────┼───────────────────────────────────────────┤
  │ media/gpu/vaapi/vaapi_jpeg_encoder.cc                    │ Replace 4 static_assert with DCHECK for   │
  │                                                          │ Clang 19 compatibility                    │
  ├──────────────────────────────────────────────────────────┼───────────────────────────────────────────┤
  │ media/gpu/vaapi/vaapi_wrapper.cc                         │ Fallback max resolution when VA-API       │
  │                                                          │ driver returns none                       │
  └──────────────────────────────────────────────────────────┴───────────────────────────────────────────┘

The first two patches address general FreeBSD ARM64 portability issues unrelated to VA-API and would benefit any Chromium build on ARM SoCs. Patches 3 and 4 are specific to VA-API on drivers (like Hantro) that do not fully implement the VA-API surface attribute query interface.

---
Tested on: Radxa Zero 3W (RK3566), FreeBSD 15.0-CURRENT AArch64, Chromium 146.0.7680.177, April 2026.

---

Patches and this report may be submitted to :

- FreeBSD ports tree: www/chromium maintainer
- FreeBSD forums: https://forums.freebsd.org
- FreeBSD Phabricator / GitHub mirror for patch review
 
Back
Top