Skip to content

Trying to import Hardware Accelleration / OpenGL from host to guest using environment variables to bind #344

@ivan-hc

Description

@ivan-hc

Hi @fsquillace , as we have already talked elsewhere, I'm creating JuNest-based ppImages in my project I've named "ArchImage".

As you have said at #342 :

I guess that's tricky and not necessarily it depends on JuNest itself. Drivers are only needed for the host linux kernel which is outside JuNest. If drivers are not installed by the host, JuNest cannot do much for it.

And as @ayaka14732 have suggested at #209 its necessary to build the same Nvidia drivers on the guest.

It almost seems like there is nothing that can be done, but solutions arise out of nowhere. For now I have managed to mount some components of the host system on the guest using various environment variables in my tests.

I plan to share them here to start a discussion about it.

I would also like to mention other contributors to this project who certainly know more than me, inviting them to participate in this research together. @cosmojg @cfriesicke @escape0707 @schance995 @neiser @hodapp512 @soraxas I would like to share what I'm working on.

They are just some functions I'm working on to made my Bottles-appimage work... for now without great progresses other than the detection of some libraries on my host system... all of them are listed at https://github.com/ivan-hc/Bottles-appimage/blob/main/AppRun

NOTE, my host system is Debian, so this may vary depending on your system.

Detect if the host runs an AMD / Intel /Nvidia driver to check the "Vendor"

# FIND THE VENDOR
VENDOR=$(glxinfo -B | grep "OpenGL vendor")
if [[ $VENDOR == *"Intel"* ]]; then
	export VK_ICD_FILENAMES="/usr/share/vulkan/icd.d/intel_icd.i686.json:/usr/share/vulkan/icd.d/intel_icd.x86_64.json"
	VENDORLIB="intel"
	export MESA_LOADER_DRIVER_OVERRIDE=$VENDORLIB
elif [[ $VENDOR == *"NVIDIA"* ]]; then
        NVIDIAJSON=$(find /usr/share -name "*nvidia*json" | sed 's/ /:/g')
	export VK_ICD_FILENAMES=$NVIDIAJSON
	VENDORLIB="nvidia"
	export MESA_LOADER_DRIVER_OVERRIDE=$VENDORLIB
elif [[ $VENDOR == *"Radeon"* ]]; then
	export VK_ICD_FILENAMES="/usr/share/vulkan/icd.d/radeon_icd.i686.json:/usr/share/vulkan/icd.d/radeon_icd.x86_64.json"
	VENDORLIB="radeon"
	export MESA_LOADER_DRIVER_OVERRIDE=$VENDORLIB
fi

Find libraries on the host

DRIPATH=$(find /usr/lib -name dri)
VDPAUPATH=$(find /usr/lib -maxdepth 2 -name vdpau)
export LIBVA_DRIVERS_PATH=$DRIPATH
export GLPATH=/lib:/lib64:/lib/x86_64-linux-gnu:/usr/lib
export VULKAN_DEVICE_INDEX=1
export __GLX_VENDOR_LIBRARY_NAME=mesa

function _host_accelleration(){
	LLVM=$(find /usr/lib -name "*LLVM*")
	for arg in $LLVM; do
		for var in $arg; do
			echo "$var"
		done
	done

	MESA=$(find /usr/lib -name "*mesa*.so*")
	for arg in $MESA; do
		for var in $arg; do
			echo "$var"
		done
	done

	D3D=$(find /usr/lib -name "*d3d*.so*")
	for arg in $D3D; do
		for var in $arg; do
			echo "$var"
		done
	done

	EGL=$(find /usr/lib -name "libEGL*" | grep -v "libEGL_mesa")
	for arg in $EGL; do
		for var in $arg; do
			echo "$var"
		done
	done

	STDC=$(find /usr/lib -name "*stdc*.so*")
	for arg in $STDC; do
		for var in $arg; do
			echo "$var"
		done
	done

	SWRAST=$(find /usr/lib -name "*swrast*")
	for arg in $SWRAST; do
		for var in $arg; do
			echo "$var"
		done
	done

	VULKAN=$(find /usr/lib -name "*vulkan*")
	for arg in $VULKAN; do
		for var in $arg; do
			echo "$var"
		done
	done
}

In the following step I'll try to list all the libraries found above into a file in ~/.cache (this step may be slower on some systems)

What to bind?

ACCELL_DRIVERS=$(echo $(echo "$(_host_accelleration)") | sed 's/ /:/g')
BINDLIBS=$(echo $(cat $HOME/.cache/hostdri2junest | uniq | sort -u) | sed 's/ /:/g')

rm -f $HOME/.cache/libbinds $HOME/.cache/libbindbinds
echo $ACCELL_DRIVERS | tr ":" "\n" >> $HOME/.cache/libbinds
echo $BINDLIBS | tr ":" "\n" >> $HOME/.cache/libbinds
for arg in $(cat $HOME/.cache/libbinds); do
	for var in "$arg"; do
		echo "$arg $(echo $arg | sed 's#/x86_64-linux-gnu##g' | cut -d/ -f1,2,3 )" >> $HOME/.cache/libbindbinds
		break
	done
done
sed -i -e 's#^#--bind / / --bind #' $HOME/.cache/libbindbinds

BINDS=$(cat $HOME/.cache/libbinds | tr "\n" " ")

EXTRA: trying to mount libLLVM host/guest (I've disabled this for now)

HOST_LIBLLVM=$(find /usr/lib -name "*libLLVM*" | grep -v ".so.")
JUNEST_LIBLLVM=$(find $JUNEST_HOME/usr/lib -name "*libLLVM*" | grep -v ".so.")

All I've done then was to recreate the structure of directories to bind in the AppImage (in my use case), for those that use JuNest normally, the directories should be automatically mounted, like this.

Where $HERE is the current directory I'm using

HERE="$(dirname "$(readlink -f $0)")"` 

and $EXEC is the name of the program I take from the "Exec=" entry in its .desktop file

EXEC=$(grep -e '^Exec=.*' "${HERE}"/*.desktop | head -n 1 | cut -d "=" -f 2- | sed -e 's|%.||g')

here is how a command with namespaces should be (in my experimente):

function _exec(){
	if [[ $VENDOR == *"NVIDIA"* ]]; then
		$HERE/.local/share/junest/bin/junest -n -b "$BINDS\
			--bind /usr/lib/ConsoleKit $JUNEST_HOME/usr/lib/ConsoleKit\
			--bind $DRIPATH $JUNEST_HOME/usr/lib/dri\
			--bind /usr/libexec $JUNEST_HOME/usr/libexec\
			--bind /usr/lib/firmware $JUNEST_HOME/usr/lib/firmware\
			--bind /usr/lib/modules $JUNEST_HOME/usr/lib/modules\
			--bind /usr/lib/nvidia $JUNEST_HOME/usr/lib/nvidia\
			--bind /usr/lib/systemd $JUNEST_HOME/usr/lib/systemd\
			--bind /usr/lib/udev $JUNEST_HOME/usr/lib/udev\
			--bind $VDPAUPATH $JUNEST_HOME/usr/lib/vdpau\
			--bind /usr/lib/xorg $JUNEST_HOME/usr/lib/xorg\
			--bind /usr/share/bug $JUNEST_HOME/usr/share/bug\
			--bind /usr/share/dbus-1 $JUNEST_HOME/usr/share/dbus-1\
			--bind /usr/share/doc $JUNEST_HOME/usr/share/doc\
			--bind /usr/share/egl $JUNEST_HOME/usr/share/egl\
			--bind /usr/share/glvnd $JUNEST_HOME/usr/share/glvnd\
			--bind /usr/share/lightdm $JUNEST_HOME/usr/share/lightdm\
			--bind /usr/share/lintian $JUNEST_HOME/usr/share/lintian\
			--bind /usr/share/man $JUNEST_HOME/usr/share/man\
			--bind /usr/share/nvidia $JUNEST_HOME/usr/share/nvidia\
			--bind /usr/share/vulkan $JUNEST_HOME/usr/share/vulkan\
			--bind /usr/src $JUNEST_HOME/usr/src\
			" -- $EXEC "$@"
	else
		$HERE/.local/share/junest/bin/junest -n -b "\
			--bind $DRIPATH $JUNEST_HOME/usr/lib/dri\
			--bind /usr/libexec $JUNEST_HOME/usr/libexec\
			--bind /usr/lib/modules $JUNEST_HOME/usr/lib/modules\
			--bind /usr/lib/xorg $JUNEST_HOME/usr/lib/xorg\
			--bind /usr/share/dbus-1 $JUNEST_HOME/usr/share/dbus-1\
			--bind /usr/share/glvnd $JUNEST_HOME/usr/share/glvnd\
			--bind /usr/share/vulkan $JUNEST_HOME/usr/share/vulkan\
			--bind /usr/src $JUNEST_HOME/usr/src\
			" -- $EXEC "$@"
	fi
}
_exec

For now the result is that I've no more many of the error messages I had previously.

I've NOT reached my goal, but I'm near to a solution.

Are there any pieces missing or perhaps I added too many in my attempt?

I can't say it myself, surely some of you can do better.

My search was not possible without:

A special thanks to @mirkobrombin that redirected me to the right path... I'm trying to finish this journey. I hope not alone.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions