udevbe / greenfield

HTML5 Wayland compositor :seedling:
GNU Affero General Public License v3.0
898 stars 27 forks source link

Starting apps silently fails on Termux & proot #145

Open pojntfx opened 1 month ago

pojntfx commented 1 month ago

Hi! I've been trying to get Greenfield to work on Android (non-rooted) through Termux and proot with the goal of getting GTK apps to run. This is possible by using Termux and proot, for example you can start hardware-accelerated GTK apps with Termux and Termux-X11 like so:

pkg install virglrenderer-android
virgl_test_server_android &

export DISPLAY=:0
termux-x11 :0 &

proot-distro login debian --shared-tmp
export DISPLAY=:0

export GALLIUM_DRIVER=virpipe MESA_GL_VERSION_OVERRIDE=4.0

export GDK_SCALE=3
gtk4-demo

It's not particularly fast, but it works. With GALLIUM_DRIVER=llvmpipe it uses software rendering, which also works.

The probably biggest issue with this stack however is that it's X11 only, and I would really like to use Wayland - which is where Greenfield could come in handy. I prepared a Docker simple image (https://github.com/pojntfx/hydrapile/tree/main/greenfield), which can successfully start without hardware acceleration (docker run -it -p 8080:8080 -p 8081:8081 pojntfx/greenfield) and with hardware acceleration (docker run -it --privileged -v /dev/dri:/dev/dri -p 8080:8080 -p 8081:8081 pojntfx/greenfield) on my x86_64 system (Dell XPS 13 Plus, i7-1280P) as well as a aarch64 server I've tried (without hardware acceleration, using Hetzner's ARM Cloud VPS servers, these ones: https://www.hetzner.com/press-release/arm64-cloud/).

So I then took the Docker image that can successfully run on said aarch64 server, copy it to my Android phone (Google Pixel 6 Pro), create a proot (Debian 12), and start the compositor proxy CLI and web server (see my notes). So far so good - everything starts up, the native Node extension also works:

node /work/packages/compositor-proxy-cli/dist/main.js --applications=.applications.json 
{time:"2024-05-28T23:32:57.107Z",name:"main",msg:"Starting compositor proxy with args: {
  applications: {
    '/kgx': { name: 'Console', executable: 'kgx', args: [], env: {} },
    '/gtk4-demo': { name: '', executable: 'gtk4-demo', args: [], env: {} },
    '/gtk4-widget-factory': { name: '', executable: 'gtk4-widget-factory', args: [], env: {} },
    '/adwaita-1-demo': { name: '', executable: 'adwaita-1-demo', args: [], env: {} },
    '/glxgears': { name: 'glxgears', executable: 'glxgears', args: [], env: {} },
    '/weston-terminal': {
      name: 'weston-terminal',
      executable: 'weston-terminal',
      args: [],
      env: {}
    }
  },
  help: false,
  'bind-ip': '0.0.0.0',
  'bind-port': '8081',
  'allow-origin': 'http://localhost:8080',
  'base-url': 'ws://localhost:8081',
  'render-device': '/dev/dri/renderD128',
  encoder: 'x264',
  'basic-auth': undefined
}"}
{time:"2024-05-28T23:32:57.114Z",name:"main",msg:"Compositor proxy started. Listening on 0.0.0.0:8081"}

When I then try to start an app (rem://localhost:8081/gtk4-demo, for example) the process starts successfully:

{time:"2024-05-28T23:33:51.198Z",name:"main",msg:"No proxy session exists for this compositor, spawning a new one."}
Can't open device path: /dev/dri/renderD128: Permission denied
Can't initialize EGL, wl_dmabuf and wl_drm disabled.{time:"2024-05-28T23:33:51.637Z",name:"native-compositor-session",msg:"Listening on: WAYLAND_DISPLAY="wayland-0"."}
unlinking stale lock file /tmp/.X1-lock
xserver listening on display :1
{time:"2024-05-28T23:33:51.641Z",name:"compositor-proxy-session",msg:"Session created."}
{time:"2024-05-28T23:33:51.641Z",name:"session-process",msg:"Session started."}
{time:"2024-05-28T23:33:51.642Z",name:"gtk4-demo",msg:"Launching application gtk4-demo with args [] and environment {"COLORTERM":"","MESA_GL_VERSION_OVERRIDE":"4.0","GALLIUM_DRIVER":"virpipe","PWD":"/root","XAUTHORITY":"/tmp/.X11-unix/Xauthority","EXTERNAL_STORAGE":"/sdcard","HOME":"/root","LANG":"en_US.UTF-8","DEX2OATBOOTCLASSPATH":"/apex/com.android.art/javalib/core-oj.jar:/apex/com.android.art/javalib/core-libart.jar:/apex/com.android.art/javalib/okhttp.jar:/apex/com.android.art/javalib/bouncycastle.jar:/apex/com.android.art/javalib/apache-xml.jar:/system/framework/framework.jar:/system/framework/framework-graphics.jar:/system/framework/framework-location.jar:/system/framework/framework-nfc.jar:/system/framework/ext.jar:/system/framework/telephony-common.jar:/system/framework/voip-common.jar:/system/framework/ims-common.jar:/apex/com.android.i18n/javalib/core-icu4j.jar","TMPDIR":"/tmp","ANDROID_DATA":"/data","TERM":"xterm-256color","USER":"root","RENDERER_ALLOW_SOFTWARE":"true","ANDROID_I18N_ROOT":"/apex/com.android.i18n","DISPLAY":":1","SHLVL":"1","ANDROID_ROOT":"/system","LIBGL_ALWAYS_SOFTWARE":"1","BOOTCLASSPATH":"/apex/com.android.art/javalib/core-oj.jar:/apex/com.android.art/javalib/core-libart.jar:/apex/com.android.art/javalib/okhttp.jar:/apex/com.android.art/javalib/bouncycastle.jar:/apex/com.android.art/javalib/apache-xml.jar:/system/framework/framework.jar:/system/framework/framework-graphics.jar:/system/framework/framework-location.jar:/system/framework/framework-nfc.jar:/system/framework/ext.jar:/system/framework/telephony-common.jar:/system/framework/voip-common.jar:/system/framework/ims-common.jar:/apex/com.android.i18n/javalib/core-icu4j.jar:/apex/com.android.adservices/javalib/framework-adservices.jar:/apex/com.android.adservices/javalib/framework-sdksandbox.jar:/apex/com.android.appsearch/javalib/framework-appsearch.jar:/apex/com.android.btservices/javalib/framework-bluetooth.jar:/apex/com.android.configinfrastructure/javalib/framework-configinfrastructure.jar:/apex/com.android.conscrypt/javalib/conscrypt.jar:/apex/com.android.devicelock/javalib/framework-devicelock.jar:/apex/com.android.healthfitness/javalib/framework-healthfitness.jar:/apex/com.android.ipsec/javalib/android.net.ipsec.ike.jar:/apex/com.android.media/javalib/updatable-media.jar:/apex/com.android.mediaprovider/javalib/framework-mediaprovider.jar:/apex/com.android.ondevicepersonalization/javalib/framework-ondevicepersonalization.jar:/apex/com.android.os.statsd/javalib/framework-statsd.jar:/apex/com.android.permission/javalib/framework-permission.jar:/apex/com.android.permission/javalib/framework-permission-s.jar:/apex/com.android.scheduling/javalib/framework-scheduling.jar:/apex/com.android.sdkext/javalib/framework-sdkextensions.jar:/apex/com.android.tethering/javalib/framework-connectivity.jar:/apex/com.android.tethering/javalib/framework-connectivity-t.jar:/apex/com.android.tethering/javalib/framework-tethering.jar:/apex/com.android.uwb/javalib/framework-uwb.jar:/apex/com.android.virt/javalib/framework-virtualization.jar:/apex/com.android.wifi/javalib/framework-wifi.jar","XDG_RUNTIME_DIR":"/tmp","MOZ_FAKE_NO_SANDBOX":"1","ANDROID_TZDATA_ROOT":"/apex/com.android.tzdata","PATH":"/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/games:/usr/games:/data/data/com.termux/files/usr/bin:/system/bin:/system/xbin","ANDROID_ART_ROOT":"/apex/com.android.art","PULSE_SERVER":"127.0.0.1","_":"/usr/bin/node","WAYLAND_DISPLAY":"wayland-0"}"}
{time:"2024-05-28T23:33:51.652Z",name:"gtk4-demo",msg:"Child process started."}
{time:"2024-05-28T23:33:51.769Z",name:"app",msg:"New signaling connection from http://localhost:8081/signal?compositorSessionId=sid66e46451adc24ea9&key=042ffc0b72fae947."}
{time:"2024-05-28T23:33:51.859Z",name:"native-compositor-session",msg:"New Wayland client."}
Spawned Xwayland server, pid 7185
(WW) Option "-listen" for file descriptors is deprecated
Please use "-listenfd" instead.

It also keeps running:

$ ps -aux | grep gtk4-demo
u0_a395   7181  0.1  0.1 164620 14524 pts/2    S<l+  1970   0:00 gtk4-demo

The browser console shows no bugs, and data is being sent through the WebSocket - the window just never shows up.

I noticed these logs:

Can't open device path: /dev/dri/renderD128: Permission denied
Can't initialize EGL, wl_dmabuf and wl_drm disabled.

Since we're on Android here we can't directly access the DRI devices. Could it maybe be an option to use software rendering, for example with pixman (like Weston) or something similar? Or am I missing a configuration flag that makes Greenfield not use the llvmpipe or virpipe GL backends?

I noticed that a similar error behavior (apps start successfully, but their windows are never rendered, and no obvious error messages show up) occurs on mainline Linux if I forget to install libegl1-mesa in the Docker container.

Any ideas what might be going on here? Am I maybe missing something obvious? I created a repo for reproduction.

Zubnix commented 1 month ago

Usually when everything seems to work but no applications are shown, it's the video encoding that's having issues.

Video encoding in Greenfield is implemented using GStreamer. You can try troubleshooting/changing the behavior of the encoding pipeline without recompiling by tweaking some environment variables. In your case, you can try to see what's going wrong by setting GST_DEBUG=4. That should give you a lot of output to sift through but will (hopefully) also tell you what's going wrong.

Keep in mind that Greenfield proxy (GStreamer actually) also must have some kind of OpenGL implementation (even if it's just a software one) because it relies on an OpenGL shader to do color splitting (alpha+opaque).

pojntfx commented 1 month ago

Thanks, yes that makes a lot of sense! I managed to get the actual encoding pipeline to work in proot on Android now, but it looks like for it's GL implementation to work properly some components always have to run in actual Android, not proot. I got GL to work on proot (and was able to render shaders w/o problems) - I'll try and use some of these debugging methods for Greenfield too & report back: https://github.com/pojntfx/hydrapile/blob/main/docs/termux-x11-gstreamer-ffmpeg.md