├── .gitignore ├── external └── .gitignore ├── requirements.txt ├── pulseaudio ├── pulseaudio-client.conf ├── pulseaudio-daemon.conf ├── entrypoint.sh ├── pulseaudio-default.pa └── Dockerfile ├── hostaudio ├── pulseaudio-client.conf └── Dockerfile ├── x11 └── Dockerfile ├── LICENSE ├── base └── Dockerfile └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | __pycache__/ 2 | -------------------------------------------------------------------------------- /external/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | natsort 2 | packaging 3 | requests 4 | -------------------------------------------------------------------------------- /pulseaudio/pulseaudio-client.conf: -------------------------------------------------------------------------------- 1 | # Ensure a PulseAudio server is automatically spawned on demand inside the container 2 | autospawn = yes 3 | -------------------------------------------------------------------------------- /pulseaudio/pulseaudio-daemon.conf: -------------------------------------------------------------------------------- 1 | default-sample-channels = 6 2 | default-sample-format = float32le 3 | default-sample-rate = 48000 4 | high-priority = no 5 | realtime-scheduling = no 6 | -------------------------------------------------------------------------------- /pulseaudio/entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Remove any PulseAudio files leftover from previous runs of the Unreal Engine 4 | # (Without this, PulseAudio will hang on startup if a container is restarted without a sufficient shutdown grace period) 5 | rm -rf ~/.config/pulse /tmp/pulse-* 6 | 7 | # Run the entrypoint command specified via our command-line parameters 8 | "$@" 9 | -------------------------------------------------------------------------------- /pulseaudio/pulseaudio-default.pa: -------------------------------------------------------------------------------- 1 | #!/usr/bin/pulseaudio -nF 2 | .fail 3 | 4 | # Load the native PulseAudio protocol implementation for communication over Unix sockets and disable authentication 5 | load-module module-native-protocol-unix auth-anonymous=1 6 | 7 | # Create a null sink to ensure the Unreal Engine has somewhere to send its audio output 8 | load-module module-always-sink 9 | -------------------------------------------------------------------------------- /hostaudio/pulseaudio-client.conf: -------------------------------------------------------------------------------- 1 | # Connect to the host system's PulseAudio server using the bind-mounted UNIX socket 2 | default-server = unix:/run/user/1000/pulse/native 3 | 4 | # Prevent a PulseAudio server from attempting to spawn in the container 5 | autospawn = no 6 | daemon-binary = /bin/true 7 | 8 | # Prevent the use of shared memory when communicating with the PulseAudio server 9 | enable-shm = false 10 | -------------------------------------------------------------------------------- /x11/Dockerfile: -------------------------------------------------------------------------------- 1 | ARG BASEIMAGE 2 | FROM ${BASEIMAGE} 3 | 4 | # Install the X11 runtime libraries so we can display the output of Unreal Engine projects on the host system's display 5 | USER root 6 | RUN --mount=type=cache,target=/var/cache/apt --mount=type=cache,target=/var/lib/apt \ 7 | apt-get update && apt-get install -y --no-install-recommends \ 8 | libfontconfig1 \ 9 | libfreetype6 \ 10 | libglu1 \ 11 | libsm6 \ 12 | libxcomposite1 \ 13 | libxcursor1 \ 14 | libxdamage1 \ 15 | libxi6 \ 16 | libxkbcommon-x11-0 \ 17 | libxrandr2 \ 18 | libxrender1 \ 19 | libxss1 \ 20 | libxtst6 \ 21 | libxv1 \ 22 | x11-xkb-utils \ 23 | xauth \ 24 | xfonts-base \ 25 | xkb-data 26 | USER ue4 27 | -------------------------------------------------------------------------------- /hostaudio/Dockerfile: -------------------------------------------------------------------------------- 1 | ARG BASEIMAGE 2 | FROM ${BASEIMAGE} 3 | 4 | # Install the PulseAudio command line tools package (client only, no server) 5 | USER root 6 | RUN --mount=type=cache,target=/var/cache/apt --mount=type=cache,target=/var/lib/apt \ 7 | apt-get update && apt-get install -y --no-install-recommends pulseaudio-utils 8 | USER ue4 9 | 10 | # Configure the PulseAudio client to connect to the host system's server using a bind-mounted UNIX socket 11 | COPY pulseaudio-client.conf /etc/pulse/client.conf 12 | 13 | # Instruct the Unreal Engine to use the SDL audio driver for PulseAudio 14 | # (This will prevent SDL from attempting to try other audio drivers if PulseAudio fails to initialise) 15 | ENV SDL_AUDIODRIVER pulse 16 | -------------------------------------------------------------------------------- /pulseaudio/Dockerfile: -------------------------------------------------------------------------------- 1 | ARG BASEIMAGE 2 | FROM ${BASEIMAGE} 3 | 4 | # Install the full PulseAudio package (client + server) 5 | USER root 6 | RUN --mount=type=cache,target=/var/cache/apt --mount=type=cache,target=/var/lib/apt \ 7 | apt-get update && apt-get install -y --no-install-recommends pulseaudio 8 | USER ue4 9 | 10 | # Configure the PulseAudio server to work correctly inside the container 11 | COPY pulseaudio-client.conf /etc/pulse/client.conf 12 | COPY pulseaudio-daemon.conf /etc/pulse/daemon.conf 13 | COPY pulseaudio-default.pa /etc/pulse/default.pa 14 | 15 | # Copy our entrypoint script into the image so it can be used to wrap Unreal Engine projects and ensure PulseAudio works smoothly 16 | COPY entrypoint.sh /usr/bin/entrypoint.sh 17 | USER root 18 | RUN chmod +x /usr/bin/entrypoint.sh 19 | USER ue4 20 | 21 | # Instruct the Unreal Engine to use the SDL audio driver for PulseAudio 22 | # (This will prevent SDL from attempting to try other audio drivers if PulseAudio fails to initialise) 23 | ENV SDL_AUDIODRIVER pulse 24 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 - 2023 Adam Rehn 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /base/Dockerfile: -------------------------------------------------------------------------------- 1 | ARG BASEIMAGE 2 | FROM ${BASEIMAGE} 3 | 4 | # Disable interactive prompts during package installation 5 | ENV DEBIAN_FRONTEND=noninteractive 6 | 7 | # Enable CUDA support (even when not using a CUDA base image), since evidently some versions of UE unconditionally assume 8 | # `libcuda.so.1` exists when using the NVIDIA proprietary drivers, and will fail to initialise the Vulkan RHI if it is missing 9 | ENV NVIDIA_DRIVER_CAPABILITIES ${NVIDIA_DRIVER_CAPABILITIES},compute 10 | 11 | # Add the "display" driver capability 12 | # (This allows us to run projects using VirtualGL, or with onscreen rendering when bind-mounting the host system's X11 socket) 13 | ENV NVIDIA_DRIVER_CAPABILITIES ${NVIDIA_DRIVER_CAPABILITIES},display 14 | 15 | # Enable NVENC support for use by Unreal Engine plugins that depend on it (e.g. Pixel Streaming) 16 | # (Note that adding `video` seems to implicitly enable `compute` as well, but we include separate directives here to clearly indicate the purpose of both) 17 | ENV NVIDIA_DRIVER_CAPABILITIES ${NVIDIA_DRIVER_CAPABILITIES},video 18 | 19 | # Enable Vulkan support 20 | RUN rm -f /etc/apt/apt.conf.d/docker-clean; echo 'Binary::apt::APT::Keep-Downloaded-Packages "true";' > /etc/apt/apt.conf.d/keep-cache 21 | RUN --mount=type=cache,target=/var/cache/apt --mount=type=cache,target=/var/lib/apt \ 22 | apt-get update && apt-get install -y --no-install-recommends libvulkan1 && \ 23 | VULKAN_API_VERSION=`dpkg -s libvulkan1 | grep -oP 'Version: [0-9|\.]+' | grep -oP '[0-9|\.]+'` && \ 24 | mkdir -p /etc/vulkan/icd.d/ && \ 25 | echo \ 26 | "{\ 27 | \"file_format_version\" : \"1.0.0\",\ 28 | \"ICD\": {\ 29 | \"library_path\": \"libGLX_nvidia.so.0\",\ 30 | \"api_version\" : \"${VULKAN_API_VERSION}\"\ 31 | }\ 32 | }" > /etc/vulkan/icd.d/nvidia_icd.json 33 | 34 | # Install the `xdg-user-dir` tool so the Unreal Engine can use it to locate the user's Documents directory 35 | RUN --mount=type=cache,target=/var/cache/apt --mount=type=cache,target=/var/lib/apt \ 36 | apt-get update && apt-get install -y --no-install-recommends xdg-user-dirs 37 | 38 | # Since the Unreal Engine refuses to run as the root user under Linux, create a non-root user 39 | RUN useradd --create-home --home /home/ue4 --shell /bin/bash --uid 1000 ue4 && \ 40 | usermod -a -G audio,video ue4 41 | USER ue4 42 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Container images for running packaged Unreal Engine projects 2 | 3 | The various tags of the [adamrehn/ue4-runtime](https://hub.docker.com/r/adamrehn/ue4-runtime) image provide minimal, pre-configured environments for running packaged Unreal Engine projects with full GPU acceleration via the [NVIDIA Container Toolkit](https://github.com/NVIDIA/nvidia-docker). (For more details on the NVIDIA Container Toolkit, see the [NVIDIA Container Toolkit primer](https://unrealcontainers.com/docs/concepts/nvidia-docker) on the Unreal Containers community hub.) Note that these images will work with packaged Linux builds **from any source**, not just builds packaged using the container images from the [ue4-docker](https://github.com/adamrehn/ue4-docker) project. 4 | 5 | Both OpenGL+Vulkan and OpenGL+Vulkan+CUDA variants are provided. Each image variant is also available in a configuration with the X11 runtime libraries bundled for displaying the output of packaged Unreal Engine projects on the host system's display. See the section [Using the X11 images](#using-the-x11-images) for usage details. 6 | 7 | For details on using these images to perform cloud rendering via the NVIDIA Container Toolkit, see the [Cloud rendering guide](https://unrealcontainers.com/docs/use-cases/cloud-rendering) on the Unreal Containers community hub. There are also [example Dockerfiles](https://github.com/adamrehn/ue4-example-dockerfiles) available that demonstrate various uses of Unreal Engine containers, including multi-stage build workflows that encapsulate packaged projects in variants of the `ue4-runtime` image. 8 | 9 | 10 | ## Alias tags 11 | 12 | The following tags are provided as convenient aliases for the fully-qualified tags of common image variants: 13 | 14 | - **latest** is an alias for **20.04-vulkan** 15 | - **20.04-opengl** is an alias for **20.04-vulkan** 16 | - **22.04-opengl** is an alias for **22.04-vulkan** 17 | - **noaudio** is an alias for **20.04-vulkan-noaudio** 18 | - **hostaudio** is an alias for **20.04-vulkan-hostaudio** 19 | - **x11** is an alias for **20.04-vulkan-x11** 20 | 21 | 22 | ## Ubuntu 22.04 tags 23 | 24 | - **22.04-vulkan**: Ubuntu 22.04 + OpenGL + Vulkan + PulseAudio Client + PulseAudio Server 25 | - **22.04-cudagl11**: Ubuntu 22.04 + OpenGL + Vulkan + CUDA 11.8.0 + PulseAudio Client + PulseAudio Server 26 | - **22.04-cudagl12**: Ubuntu 22.04 + OpenGL + Vulkan + CUDA 12.2.0 + PulseAudio Client + PulseAudio Server 27 | - **22.04-vulkan-noaudio**: Ubuntu 22.04 + OpenGL + Vulkan (no audio support) 28 | - **22.04-cudagl11-noaudio**: Ubuntu 22.04 + OpenGL + Vulkan + CUDA 11.8.0 (no audio support) 29 | - **22.04-cudagl12-noaudio**: Ubuntu 22.04 + OpenGL + Vulkan + CUDA 12.2.0 (no audio support) 30 | - **22.04-vulkan-hostaudio**: Ubuntu 22.04 + OpenGL + Vulkan + PulseAudio Client (uses host PulseAudio Server) 31 | - **22.04-cudagl11-hostaudio**: Ubuntu 22.04 + OpenGL + Vulkan + CUDA 11.8.0 + PulseAudio Client (uses host PulseAudio Server) 32 | - **22.04-cudagl12-hostaudio**: Ubuntu 22.04 + OpenGL + Vulkan + CUDA 12.2.0 + PulseAudio Client (uses host PulseAudio Server) 33 | - **22.04-vulkan-x11**: Ubuntu 22.04 + OpenGL + Vulkan + PulseAudio Client (uses host PulseAudio Server) + X11 34 | - **22.04-cudagl11-x11**: Ubuntu 22.04 + OpenGL + Vulkan + CUDA 11.8.0 + PulseAudio Client (uses host PulseAudio Server) + X11 35 | - **22.04-cudagl12-x11**: Ubuntu 22.04 + OpenGL + Vulkan + CUDA 12.2.0 + PulseAudio Client (uses host PulseAudio Server) + X11 36 | 37 | 38 | ## Ubuntu 20.04 tags 39 | 40 | - **20.04-vulkan**: Ubuntu 20.04 + OpenGL + Vulkan + PulseAudio Client + PulseAudio Server 41 | - **20.04-cudagl11**: Ubuntu 20.04 + OpenGL + Vulkan + CUDA 11.8.0 + PulseAudio Client + PulseAudio Server 42 | - **20.04-cudagl12**: Ubuntu 20.04 + OpenGL + Vulkan + CUDA 12.2.0 + PulseAudio Client + PulseAudio Server 43 | - **20.04-vulkan-noaudio**: Ubuntu 20.04 + OpenGL + Vulkan (no audio support) 44 | - **20.04-cudagl11-noaudio**: Ubuntu 20.04 + OpenGL + Vulkan + CUDA 11.8.0 (no audio support) 45 | - **20.04-cudagl12-noaudio**: Ubuntu 20.04 + OpenGL + Vulkan + CUDA 12.2.0 (no audio support) 46 | - **20.04-vulkan-hostaudio**: Ubuntu 20.04 + OpenGL + Vulkan + PulseAudio Client (uses host PulseAudio Server) 47 | - **20.04-cudagl11-hostaudio**: Ubuntu 20.04 + OpenGL + Vulkan + CUDA 11.8.0 + PulseAudio Client (uses host PulseAudio Server) 48 | - **20.04-cudagl12-hostaudio**: Ubuntu 20.04 + OpenGL + Vulkan + CUDA 12.2.0 + PulseAudio Client (uses host PulseAudio Server) 49 | - **20.04-vulkan-x11**: Ubuntu 20.04 + OpenGL + Vulkan + PulseAudio Client (uses host PulseAudio Server) + X11 50 | - **20.04-cudagl11-x11**: Ubuntu 20.04 + OpenGL + Vulkan + CUDA 11.8.0 + PulseAudio Client (uses host PulseAudio Server) + X11 51 | - **20.04-cudagl12-x11**: Ubuntu 20.04 + OpenGL + Vulkan + CUDA 12.2.0 + PulseAudio Client (uses host PulseAudio Server) + X11 52 | 53 | 54 | ## Vulkan rendering 55 | 56 | **Offscreen rendering with Vulkan requires projects built with Unreal Engine 4.25.0 or newer.** To render offscreen, specify the `-RenderOffscreen` flag when running your packaged Unreal project. 57 | 58 | Vulkan rendering under Unreal Engine 4.24 or older will require bind-mounting the X11 socket from the host system and propagating the `DISPLAY` environment variable so that output can be rendered to a window. See the section [Using the X11 images](#using-the-x11-images) for details on the required `docker run` flags. 59 | 60 | 61 | ## Audio output 62 | 63 | By default, the container images are configured to spawn a PulseAudio server on demand when packaged Unreal projects initialise audio output. This allows the Unreal Engine to produce audio output inside the container which can then be captured (e.g. using Pixel Streaming for Linux.) However, this behaviour may be undesirable for use cases where the host system's X11 socket is bind-mounted and output is displayed on the host, since audio output will not be propagated alongside the rendered output. The `hostaudio` configuration of each image variant overrides this default behaviour and instructs the Unreal Engine to instead use a PulseAudio socket bind-mounted from the host system, thus allowing audio output to be heard on the host. To bind-mount the PulseAudio socket from the host system, use the following flag: 64 | 65 | ```bash 66 | "-v/run/user/$UID/pulse:/run/user/1000/pulse" 67 | ``` 68 | 69 | 70 | ## Using the X11 images 71 | 72 | The `x11` configuration of each image variant extends the `hostaudio` configuration and adds the X11 libraries needed for running applications that create X11 windows. These images are designed for running containers locally and displaying the output of a packaged Unreal project directly on the host system's display. 73 | 74 | To run a container using an X11-enabled image, the Docker host system will need to be running an X11 server and you will need to bind-mount the host's X11 socket inside the container like so: 75 | 76 | ```bash 77 | # Replace "adamrehn/ue4-runtime:x11" with your chosen image tag 78 | docker run --gpus=all -v/tmp/.X11-unix:/tmp/.X11-unix:rw -e DISPLAY adamrehn/ue4-runtime:x11 bash 79 | ``` 80 | 81 | If you want audio output then you will need to bind-mount the host system's PulseAudio socket as well: 82 | 83 | ```bash 84 | # Replace "adamrehn/ue4-runtime:x11" with your chosen image tag 85 | docker run --gpus=all -v/tmp/.X11-unix:/tmp/.X11-unix:rw "-v/run/user/$UID/pulse:/run/user/1000/pulse" -e DISPLAY adamrehn/ue4-runtime:x11 bash 86 | ``` 87 | 88 | 89 | ## Building the images from source 90 | 91 | Building the container images from source requires Python 3.5 or newer and the dependency packages listed in [requirements.txt](https://github.com/adamrehn/ue4-runtime/blob/master/requirements.txt). 92 | 93 | To build the images, simply run `build.py`. This will automatically query Docker Hub to retrieve the list of available [nvidia/cuda](https://hub.docker.com/r/nvidia/cuda) base images based on Ubuntu LTS releases and build all variants of the `adamrehn/ue4-runtime` image accordingly. 94 | 95 | 96 | ## Legal 97 | 98 | Copyright © 2019 - 2023, Adam Rehn. Licensed under the MIT License, see the file [LICENSE](https://github.com/adamrehn/ue4-runtime/blob/master/LICENSE) for details. 99 | 100 | The file [pulseaudio-default.pa](./base/pulseaudio-default.pa) is adapted from the [default PulseAudio configuration data](https://github.com/pulseaudio/pulseaudio/blob/v12.2/src/daemon/default.pa.in), which is part of PulseAudio and is licensed under the [GNU Lesser General Public License version 2.1 or newer](https://github.com/pulseaudio/pulseaudio/blob/master/LGPL). 101 | --------------------------------------------------------------------------------