How to enable Vulkan on /compat/linux

Assuming you have Vulkan compatible hardware you can enable it on /compat/linux by creating a new "linux" service script (or edit the existing /etc/rc.d/linux service file, just replace linux_vlk with linux) with the following:

Bash:
#!/bin/sh
#
#

# PROVIDE: linux
# REQUIRE: kldxref zfs
# KEYWORD: nojail

. /etc/rc.subr

name="linux_vlk"
desc="Enable Linux ABI"
rcvar="linux_vlk-enable"
start_cmd="${name}_start"
stop_cmd=":"

linux_mount() {
    local _fs _mount_point
    _fs="$1"
    _mount_point="$2"
    shift 2
    if ! mount | grep -q "^$_fs on $_mount_point ("; then
        mkdir -p "$_mount_point"
        mount "$@" -t "$_fs" "$_fs" "$_mount_point"
    fi
}

enable_vulkan()
{
    # this will change to /compat/linux/sys/.sys
    ROOT_PATH="$(sysctl -n compat.linux.emul_path)"

    # Note, as this has to be, by force, a simple SH script we will have to stick with a single card

    mkdir -p ${ROOT_PATH}/sys/class/drm;
    mkdir -p ${ROOT_PATH}/sys/dev/char;

    cd $ROOT_PATH/sys

    # we only handle one card for now
    for card_dir in .sys/class/drm/card*; do
        uevent=$(cat "${card_dir}/device/uevent")
        pci_id=$(echo $uevent | sed -e "s/.*PCI_ID=//g" | sed -e "s/ .*//")
        ln -s ../../.sys/class/drm/card0 class/drm/card0

        # corresponding char device
        mkdir -p ${ROOT_PATH}/sys/dev/char/226:0
        echo "1" > ${ROOT_PATH}/sys/dev/char/226:0/boot_display
        echo "226:0" > ${ROOT_PATH}/sys/dev/char/226:0/dev
        ln -s ../../../.sys/class/drm/card0/device dev/char/226:0/device
        ln -s ../../../.sys/class/drm dev/char/226:0/subsystem

        cat <<EOF > dev/char/226:0/uevent
MAJOR=226
MINOR=0
DEVNAME=dri/card0
DEVTYPE=drm_minor
EOF

        # also create the renderD node
        mkdir -p ${ROOT_PATH}/sys/class/drm/renderD128
        echo "1" > ${ROOT_PATH}/sys/class/drm/renderD128/boot_display
        echo "226:128" > ${ROOT_PATH}/sys/class/drm/renderD128/dev
        cat <<EOF > ${ROOT_PATH}/sys/class/drm/renderD128/uevent
MAJOR=226
MINOR=128
DEVNAME=dri/renderD128
DEVTYPE=drm_minor
EOF
        # link the device
        ln -s ../../drm class/drm/renderD128/subsystem
        ln -s ../card0/device class/drm/renderD128/device

        # corresponding char device
        mkdir -p ${ROOT_PATH}/sys/dev/char/226:128
        echo "1" > ${ROOT_PATH}/sys/dev/char/226:128/boot_display
        echo "226:128" > ${ROOT_PATH}/sys/dev/char/226:128/dev
        ln -s ../../../.sys/class/drm/card0/device dev/char/226:128/device
        ln -s ../../../.sys/class/drm dev/char/226:128/subsystem
        cat <<EOF > ${ROOT_PATH}/sys/dev/char/226:128/uevent
MAJOR=226
MINOR=128
DEVNAME=dri/renderD128
DEVTYPE=drm_minor
EOF
        # assign the rw permissions for everyone
        # TODO figure out if we want to instead just assign the render group
        chmod 666 ${ROOT_PATH}/dev/dri/renderD128

        break
    done

    # Link other class and sys directories
    cd class
    for path in ../.sys/class/*; do
        dname=$(basename ${path})
        if [ ! -d ./${dname} ]; then
            ln -s $path $dname;
        fi;
    done
    cd ..
    for path in ./.sys/*; do
        dname=$(basename ${path})
        if [ ! -d ./${dname} ]; then
            ln -s $path $dname;
        fi;
    done
}

linux_start()
{
    local _emul_path _tmpdir

    case `sysctl -n hw.machine_arch` in
    aarch64)
        load_kld -e 'linux64elf' linux64
        ;;
    amd64)
        load_kld -e 'linuxelf' linux
        load_kld -e 'linux64elf' linux64
        ;;
    i386)
        load_kld -e 'linuxelf' linux
        ;;
    esac

    _emul_path="$(sysctl -n compat.linux.emul_path)"

    if [ -x ${_emul_path}/sbin/ldconfigDisabled ]; then
        _tmpdir=`mktemp -d -t linux-ldconfig`
        ${_emul_path}/sbin/ldconfig -C ${_tmpdir}/ld.so.cache
        if ! cmp -s ${_tmpdir}/ld.so.cache ${_emul_path}/etc/ld.so.cache; then
            cat ${_tmpdir}/ld.so.cache > ${_emul_path}/etc/ld.so.cache
        fi
        rm -rf ${_tmpdir}
    fi

    # Linux uses the pre-pts(4) tty naming scheme.
    load_kld pty

    # Explicitly load the filesystem modules; they are usually required,
    # even with linux_mounts_enable="NO".
    load_kld fdescfs
    load_kld linprocfs
    load_kld linsysfs

    # Handle unbranded ELF executables by defaulting to ELFOSABI_LINUX.
    if [ `sysctl -ni kern.elf64.fallback_brand` -eq "-1" ]; then
        sysctl kern.elf64.fallback_brand=3 > /dev/null
    fi

    if [ `sysctl -ni kern.elf32.fallback_brand` -eq "-1" ]; then
        sysctl kern.elf32.fallback_brand=3 > /dev/null
    fi

    if checkyesno linux_mounts_enable; then
        linux_mount linprocfs "${_emul_path}/proc" -o nocover
        if checkyesno linux_vulkan_enable; then
            # make sure we have our fake sys directory
            mkdir -p "${_emul_path}/sys/.sys"
            linux_mount linsysfs "${_emul_path}/sys/.sys" -o nocover
        else
            linux_mount linsysfs "${_emul_path}/sys" -o nocover
        fi
        linux_mount devfs "${_emul_path}/dev" -o nocover
        linux_mount fdescfs "${_emul_path}/dev/fd" -o nocover,linrdlnk
        linux_mount tmpfs "${_emul_path}/dev/shm" -o nocover,mode=1777
    fi

    # enable vulkan
    if checkyesno linux_vulkan_enable; then
        enable_vulkan;
    fi
}

load_rc_config $name

# doesn't make sense to run in a svcj: kernel modules and FS-mounting
linux_svcj="NO"

run_rc_command "$1"

Please note that there are several gotchas with this solution:
  • Only tested on FreeBSD 15 (amd64), and in any case centos7 would have subpar support for more recent cards
  • Only one card supported (the first being exposed), so for multiple cards feel free to replicate what is done in the enable_vulkan function, renderD devices start with 128+n, where n is the id of the associated card
  • Not tested with NVIDIA cards and will probably not work as is
  • You will need to install at least linux-rl9-vulkan-loader, linux-rl9-dri
  • To avoid issues, you need to set linux_mounts_enable="YES" and linux_vulkan_enable="YES" on /etc/rc.conf
  • If you are using this ad an alternative linux service remember to disable the default with linux_enable="NO" in /etc/rc.conf
  • The /dev/dri/renderD128 node will have 666 permissions (there are other solutions, like changing the group to "render" but that needs to be aligned with the FreeBSD groups so...)
Why this?
Because I wanted Vulkan support on /compat/linux and linsysfs does not do it yet (see bug 278363, drm-kmod issue 290 and review D26836).
Also note that due to the version of mesa on rocky (25.0.7) at least for AMD cards you might have better performance with the proprietary driver: https://amdgpu-install.readthedocs.io/en/latest/

Disclaimer
This script is given as is, I've tested it on my machine and it works, but that's it. If you find this useful feel free to contribute/share and help with the relevant issues.
 
Back
Top