Page MenuHomeFreeBSD

www/linux-brave: DRM out of the box, GPU auto-detection
ClosedPublic

Authored by dteske on Aug 11 2026, 8:20 AM.
Tags
None
Referenced Files
Unknown Object (File)
Wed, Sep 30, 7:05 AM
Unknown Object (File)
Mon, Sep 28, 3:56 PM
Unknown Object (File)
Sun, Sep 27, 2:51 PM
Unknown Object (File)
Fri, Sep 25, 6:35 AM
Unknown Object (File)
Thu, Sep 24, 4:23 PM
Unknown Object (File)
Thu, Sep 24, 3:58 PM
Unknown Object (File)
Thu, Sep 24, 7:00 AM
Unknown Object (File)
Thu, Sep 24, 6:42 AM
Subscribers

Details

Summary

Add a WIDEVINE option (default on) so DRM playback works with no
browser-side setup once the CDM is present. The option links
${PREFIX}/lib/WidevineCdm into the Brave install directory, where the
component updater discovers it as a preinstalled component, and runs a
pre-launch seed script that sets brave.widevine_opted_in and maintains
the Widevine component hint file: Chromium registers the CDM at
startup from the hint and never repairs it itself, so the script
plants the hint before the first launch and repoints it when its
target no longer holds a CDM (e.g. after the CDM port is reinstalled),
while leaving intact hints -- including one naming a newer
component-updated CDM -- alone.

The option adds no dependency: Google's license permits fetching the
CDM but not redistributing it (www/linux-widevine-cdm is
no-pkg-mirror), so a RUN_DEPENDS would keep linux-brave itself off the
package mirrors. Everything the option installs is inert until the
user builds www/linux-widevine-cdm from ports -- the symlink dangles
and the seed script only acts when the CDM is present -- and DRM
starts working on the next launch after the CDM appears. Verified
against Netflix, Disney+, Hulu, Amazon Prime Video, discovery+, Dish
Anywhere, and Pandora, including recovery across a CDM
remove/reinstall cycle.

Wrapper improvements:

  • Re-exec under dbus-run-session when no session bus is present (new RUN_DEPENDS on devel/dbus).
  • Use hardware GL when a writable DRM render node and the Linux Mesa DRI drivers (graphics/linux-rl9-dri) are present, software rendering otherwise; BRAVE_GPU=1/0 forces.
  • With hardware GL, prefer ANGLE-on-Vulkan when the Linux Vulkan loader (x11-toolkits/linux-rl9-vulkan) and a hardware driver ICD are present: GL command streams from the Linux Mesa drivers have proven prone to GPU hangs on some kernel driver pairings, while the Vulkan path drives the same hardware reliably; BRAVE_VULKAN=1/0 forces.
  • Never inherit a FreeBSD-side LD_PRELOAD; drop --test-type (ImmediateCrash under the Linuxulator); fix PULSE_COOKIE (literal ~ never expanded inside quotes).
  • Fix pre-existing pulseaudio socket detection: pass -uw to sockstat (without -w long local addresses truncate, clipping the native socket path so the match never fired and PULSE_SERVER was never exported); quote $(whoami) against usernames bearing whitespace (pw(8) rejects them, vipw(8) does not).

Suppress the unsupported-flag warning banner via the supported
CommandLineFlagSecurityWarningsEnabled policy: the wrapper must pass
--no-sandbox because the Linuxulator lacks user namespaces.

Rewrite pkg-message to the essentials (Linuxulator setup, CDM install
step, Widevine and GPU behavior). Drop shared-mime-info dependency:
the package installs nothing under share/mime.

Diff Detail

Repository
R11 FreeBSD ports repository
Lint
Lint Skipped
Unit
Tests Skipped
Build Status
Buildable 75522
Build 72405: arc lint + arc unit

Event Timeline

There are a very large number of changes, so older changes are hidden. Show Older Changes
www/linux-brave/Makefile
31

Aren't these default values? We can probably drop these two knobs.

43

Yes, that's very similar to what www/chromium does.

dteske marked an inline comment as done.

Remove default-value variables for brevity (arrowd)

Other than that, LGTM.

www/linux-brave/files/brave-browser.in
57

Is this var really needed? dbus-launch exports DBUS_SESSION_BUS_ADDRESS so that consecutive calls to dbus-launch would be no-op.

www/linux-brave/files/brave-widevine-seed.in
43

This should be %%LOCALBASE%%. Actually, you can obtain this value from sysctl user.localbase.

This revision is now accepted and ready to land.Aug 11 2026, 7:09 PM

I'd say the necessity of the "procfs guard" (is that LLM terminology?) is dubious at best (same issue as in https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=297426) and I don't quite get the point of the GPU stuff. Also export LIBGL_DRI3_DISABLE=1 workaround was obsoleted by https://github.com/freebsd/drm-kmod/pull/35 and it easily could interfer with the GPU acceleration.

Prefer %%LOCALBASE%% over %%PREFIX%% and rely solely on Dbus relaunch sentinel

This revision now requires review to proceed.Aug 11 2026, 8:34 PM

@arrowd thank you, if all looks good, I'll commit it with your re-approval

dteske removed a subscriber: iwtcex_gmail.com.

What's this about?

www/linux-brave/Makefile
56

How is this substitution used?

www/linux-brave/files/brave-browser.in
68

I don't get this part, why is it needed?

dteske removed a subscriber: iwtcex_gmail.com.

What's this about?

Procfs objection: unsupported and contradicted by controlled reproduction
GPU objection: no technical claim
DRI3 observation: concerns unchanged pre-existing code, so it is out of scope

Alex S. comment is largely provocation and drive-by objection, no concrete
evidence, further ... references the below:

https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=297426#c7

Where Alex’s opening (comment 3):

“are you just trying to waste everyone’s time?”

was plainly inappropriate.

I don't exactly enjoy my time trying to understand LLM dumps on the bug tracker. That itself is pretty rude.

www/linux-brave/Makefile
56

See %%BRAVE_WIDEVINE%% in the generated brave-browser wrapper; it records the build option and controls whether the wrapper invokes brave-widevine-seed.

Looking again, the adjacent executable check is sufficient because the helper is generated and installed only when WIDEVINE is enabled, while the package metadata already records the option.

Good catch. I’ll remove the BRAVE_WIDEVINE substitutions and use the helper's presence as the runtime condition.

I don't exactly enjoy my time trying to understand LLM dumps on the bug tracker. That itself is pretty rude.

Not LLM. Have you ever met Bruce Evans? He and I have a lot in common. May he RIP.

www/linux-brave/files/brave-browser.in
68

linux-rl9-fontconfig installs /compat/linux/etc/fonts as an absolute symlink to /usr/local/etc/fonts. From a Linux process, the default /etc/fonts/fonts.conf lookup currently fails through that symlink:

$ env -u FONTCONFIG_FILE -u FONTCONFIG_PATH \
    /compat/linux/usr/bin/fc-match sans
Fontconfig error: Cannot load default config file: No such file: (null)

Setting FONTCONFIG_PATH=/usr/local/etc/fonts makes the Linuxulator’s ENOENT fallback reach the host ports fontconfig tree; fc-match then loads fonts.conf and conf.d without error. That gives Brave the host ports fonts rather than fontconfig’s in-memory fallback. Testing also shows that FONTCONFIG_FILE is redundant once FONTCONFIG_PATH is set, so I can reduce this block to:

export FONTCONFIG_PATH="${FONTCONFIG_PATH:-/usr/local/etc/fonts}"

In addition to the two cleanup tasks for later today (eliminating FONTCONFIG_FILE and setting only FONTCONFIG_PATH plus eliminating BRAVE_WIDEVINE substitution), I propose we move from GL rendering to vulkan when the wrapper detects it as viable (passing --use-angle=vulkan).

In testing, when I loaded multiple sites using Widevine at the same time, it stressed GL rendering to the point that it was causing video glitches, most notably when opening a new tab (the fancy-pants backgrounds that brave rendered behind the widgets in a new tab were visually corrupted).

This is under i915 and I tried multiple drm-6*-kmods and multiple Mesa kits. Consistently I can get Mesa GL to exhibit render-engine hangs. Albeit brave recovers gracefully but kept falling back to software rendering in the process and that is both annoying and sub-optimal. A snippet of my dmesg during those hangs (wherein after brave has suffered 3 or 4 of these, it goes back to software rendering):

20:09:37 GPU HANG: ecode 12:1:c05fffff, in brave
20:09:38 Resetting rcs0 for CS error
20:09:51 GPU HANG: ecode 12:1:00600000, in brave
20:09:52 Resetting rcs0 for CS error
20:09:56 GPU HANG: ecode 12:1:77dffbfa, in brave
20:09:56 Resetting rcs0 for CS error

That's 3 hangs in 19 seconds under linux-rl9-dri 25.2.7 (achieved by Ctrl+T, Ctrl+W repeatedly)

Mesa 24.2.8 was no help (excluding the possibility of a 25.2-specific regression), seeing 3 hangs in 26 seconds:

20:33:07 GPU HANG: ecode 12:1:00600000, in brave
20:33:08 Resetting rcs0 for CS error
20:33:23 GPU HANG: ecode 12:1:00200000, in brave
20:33:23 Resetting rcs0 for CS error
20:33:32 GPU HANG: ecode 12:1:859ffffb, in brave
20:33:33 Resetting rcs0 for preemption time out

It's not just limited to brave though. Stressing brave with Mesa GL even horked my desktop interface a few times.

ANGLE-on-Vulkan tested very stable on drm-66-kmod. I stressed the bejeezus out of it and it remained connected to /dev/drm/0 (with none of the dmesg resets)

So in the dust-up on the previous nits, I also intend to raise in the wrapper vulkan awareness and pass --use-angle=vulkan when appropriate.

Also, currently battling an issue where dbus-launch sticks around after browser exit (expected but they are stacking instead of re-use). Expect a fix for that to come in the next update too.

www/linux-brave/files/brave-browser.in
68

Hmm, I do get the "Cannot load default config file: No such file: (null)" error message with and without /proc mounted, but at the same time I get a correct font match in both cases.

Also, currently battling an issue where dbus-launch sticks around after browser exit. Expect a fix for that to come in the next update too.

Is it really needed, by the way? Applications should only create buses if they want to have a separate bus for their own needs. Does Brave talk to its children via dbus?

Also, currently battling an issue where dbus-launch sticks around after browser exit. Expect a fix for that to come in the next update too.

Is it really needed, by the way? Applications should only create buses if they want to have a separate bus for their own needs. Does Brave talk to its children via dbus?

The value-add we bring with dbus-launch is inhibition of screensaver invocation when Netflix is playing.

All part of my master plan to replace my Apple TV with a Framework Laptop 12

EDIT:

Running dbus-monitor "interface='org.freedesktop.ScreenSaver'" when Netflix video starts playing, you'll see something like:

method call time=1786568426.421178 sender=:1.50 -> destination=org.freedesktop.ScreenSaver serial=52 path=/org/freedesktop/ScreenSaver; interface=org.freedesktop.ScreenSaver; member=Inhibit
   string "/usr/local/share/brave/brave"
   string "Video Wake Lock"

and when Netflix video stops playing, you'll see something like:

method call time=1786568422.553844 sender=:1.50 -> destination=org.freedesktop.ScreenSaver serial=46 path=/org/freedesktop/ScreenSaver; interface=org.freedesktop.ScreenSaver; member=UnInhibit
   uint32 5

NB: important part is member=UnInhibit

www/linux-brave/files/brave-browser.in
68

Nothing to do with /proc on this one.

The match line is the misleading part. Compare the two runs side by side:

$ export FONTCONFIG_PATH=/usr/local/etc/fonts
$ /compat/linux/usr/bin/fc-match sans
DejaVuSans.ttf: "DejaVu Sans" "Book"

against:

$ export FONTCONFIG_PATH=xxx
$ /compat/linux/usr/bin/fc-match sans
Fontconfig error: Cannot load default config file: No such file: (null)
DejaVuMathTeXGyre.ttf: "DejaVu Math TeX Gyre" "Regular"

When you get the error, you're probably not getting the font you want.

Two different fonts returned when asking for "sans" -- only when you get rid of the error do you get the correct font. DejaVuMathTeXGyre is not what we want for "sans" match.

fc-match prints a font regardless, but when it can't find the config, it prints an arbitrary result. What it returns is based on luck; on my system it returns a math font, on your system it might return a sane choice.

In Brave, it looks like wrong font used for closed captioning when playing Netflix video for example.

Also, currently battling an issue where dbus-launch sticks around after browser exit. Expect a fix for that to come in the next update too.

Is it really needed, by the way? Applications should only create buses if they want to have a separate bus for their own needs. Does Brave talk to its children via dbus?

The value-add we bring with dbus-launch is inhibition of screensaver invocation when Netflix is playing.

All part of my master plan to replace my Apple TV with a Framework Laptop 12

sure but shouldn't your X environment be starting dbus-launch and setting up the XDG stuff for its window manager and child processes to run in?

Also, currently battling an issue where dbus-launch sticks around after browser exit. Expect a fix for that to come in the next update too.

Is it really needed, by the way? Applications should only create buses if they want to have a separate bus for their own needs. Does Brave talk to its children via dbus?

The value-add we bring with dbus-launch is inhibition of screensaver invocation when Netflix is playing.

All part of my master plan to replace my Apple TV with a Framework Laptop 12

sure but shouldn't your X environment be starting dbus-launch and setting up the XDG stuff for its window manager and child processes to run in?

Correct. I run fvwm3 and wasn't starting a session bus at all (xautolock knows nothing of dbus). Fixed: fvwm3 starts one bus, a small ScreenSaver shim on it drives xautolock, Brave inherits. The wrapper still has to handle bus-less setups: without any bus Chromium spams connection retries and site notifications (org.freedesktop.Notifications) never fire. Next diff swaps the fallback from dbus-launch to dbus-run-session, which dies with the browser instead of stacking.

Keeping a bus alive even on bus-less setups isn't just spam control. Brave exports MPRIS over it, which is what my framework-keyboard work rides to wire the play/pause, rewind, and fast-forward keys on the Framework laptops into the browser.

Caught a couple more technical debt issues in the wrapper:

  • the pulseaudio detection at the top fails to pass -uw (instead of args lacking -w -- -u added for good measure) to sockstat which can lead to truncation of long local-address values (e.g., /var/run/xdg/$USER/pulse/native cutting off the word native that the awk searches for)
  • a username with a space in it can break the awk -v me=$(whoami) invocation [* see below NB]

This can prevent audio from working in some instances.

  • NB: pw useradd may disallow a space in the username, but vipw does not. A common use-case would be someone setting up a login that uses "first last" nomenclature (perfectly valid; strange, but valid)
  1. Fix dbus integration (dbus-launch -> dbus-run-session)
  2. Remove BRAVE_WIDEVINE from SUB_LIST (arrowd)
  3. Fix pulseaudio detection (pre-existing issue)
  4. Favor angle-on-vulkan over Mesa GL (w/ pkg-message updates)
  5. Remove unnecessary FONTCONFIG_FILE (rely on FONTCONFIG_PATH) (~arrowd)
dteske edited the summary of this revision. (Show Details)

Tested dbus integration with working pause/play, rewind, and fast-forward integration, and screensaver inhibit all working regardless of whether WM is bus-less or not. In a bus-less WM session, it brings its own bus run that tears down on browser exit

The fontconfig setup is really a fix for CURRENT that deals with broken symlink resolution at-present -- that needs to be bisected separately, but until then keeping the setting is harmless and produces the desired results even on CURRENT

Tested dbus integration with working pause/play, rewind, and fast-forward integration, and screensaver inhibit all working regardless of whether WM is bus-less or not. In a bus-less WM session, it brings its own bus run that tears down on browser exit

I wonder if a proper way to handle this is what Obsidian does https://cgit.freebsd.org/ports/tree/textproc/obsidian/files/obsidian.in

Anyways, I think I provided all the useful input I could, but I don't wear the emulation@ hat, so I can't formally approve this.

dteske retitled this revision from www/linux-brave: DRM out of the box, procfs guard, GPU auto-detection to www/linux-brave: DRM out of the box, GPU auto-detection.Aug 15 2026, 6:29 AM
dteske edited the summary of this revision. (Show Details)
dteske edited the summary of this revision. (Show Details)

Tested dbus integration with working pause/play, rewind, and fast-forward integration, and screensaver inhibit all working regardless of whether WM is bus-less or not. In a bus-less WM session, it brings its own bus run that tears down on browser exit

I wonder if a proper way to handle this is what Obsidian does https://cgit.freebsd.org/ports/tree/textproc/obsidian/files/obsidian.in

Thanks Gleb — I looked at Obsidian’s DBUS_SESSION_BUS_ADDRESS=autolaunch:. That is the usual Chromium empty-address workaround, and it fits native electronfix apps where FreeBSD libdbus does the autolaunch.

For linux-brave I am keeping dbus-run-session on purpose. We need a real session bus when the WM provides none, with a concrete unix:path=… in the environment before the Linux binary starts, and the bus must go away when the browser exits. The autolaunch / dbus-launch path leaves session buses behind across launches in bus-less WMs; dbus-run-session ties the bus lifetime to the wrapper so that does not stack. That is the behavior I already verified (media keys, pause/play, screensaver inhibit) with and without a pre-existing session bus.

Anyways, I think I provided all the useful input I could, but I don't wear the emulation@ hat, so I can't formally approve this.

Thanks.

At present we still can't (shouldn't) merge this until we get https://reviews.freebsd.org/D58855 merged

Otherwise, anyone running 16.0-CURRENT will not realize the full benefits (read: the program won't even launch if the user has not configured native procfs to run concurrently alongside linprocfs)

I am decoupling this from D58855 because the issue as far as I can see is that without D58855, only 16.0-CURRENT users will be unable to run the browser; secondly, D58855 affects a LOT more than just www/linux-brave (without D58855 any linux program that lives outside of emul_path -- /compat/linux -- presently has issues with broken symlinks on 16.0-CURRENT)

www/linux-brave/Makefile
37

Could this be simplified by just having EXTRACT_SUFX= .${ARCH:S,amd64,x86-64,}.rpm?

83

Please use post-install-WIDEVINE-on for this stuff.

Updates

  • Rebase atop f4f2f98ba7d8dc542a967e3ba7d7f1231624792c (fluffy)
  • Utilize ARCH:S for EXTRACT_SUFX (fuz)
  • Replace PORT_OPTIONS:MWIDEVINE with option-target (fuz)
  • Satisfy portlint, clamp pkg-descr to 80c, move DISTFILES

testport ... failed (working on fix for failed checksum step)
portclippy ... happy
portfmt -D ... ok
portlint ... fine

poudriere testport caught upstream shenanigans. Brave re-uploaded the v1.94.117 (Aug 27) release assets after f4f2f98ba7d8 bump was committed by fluffy

Fix distinfo following upstream asset swap

testport ... success
portclippy ... happy
portfmt -D ... ok
portlint ... fine

I think the port can be committed as is, but please check the three optional items mentioned.
Approved for commit and LGTM.

www/linux-brave/Makefile
74

I recommend using COPYTREE_SHARE or at least ${CP} -R over the historical -r option.

78

Does INSTALL_DATA not work for this one?

91

This is fine, though use of the RLN script is typically easier to understand for these things. Sorry I didn't catch that on my first pass.

This revision is now accepted and ready to land.Sun, Sep 20, 10:15 PM
dteske added inline comments.
www/linux-brave/Makefile
91

Tried it; RLN cannot make this one. RLN (aka install -l rs) runs realpath on the source, and this link dangles by design until www/linux-widevine-cdm is installed, so no link gets created. It also crosses from PREFIX into LOCALBASE, where a relative link breaks if PREFIX != LOCALBASE. Have to keep ${LN} -sf

dteske added inline comments.
www/linux-brave/Makefile
74

Will do in a follow-up review: ${CP} -R. COPYTREE_SHARE chmods files to SHAREMODE, which would strip the execute bits off the brave
binaries, but the fix moving away from the historical -r is still good

78

It does. Will do in a follow-up review.

@fuz I created D59867 for follow-up to implement optional items mentioned