diff --git a/.github/workflows/linux_build_matrix.yml b/.github/workflows/linux_build_matrix.yml index 1bd0e4ce3e..38c30b0b6b 100644 --- a/.github/workflows/linux_build_matrix.yml +++ b/.github/workflows/linux_build_matrix.yml @@ -11,7 +11,7 @@ on: jobs: build_gcc_lto: name: "GCC" - uses: ./.github/workflows/linux_build.yml + uses: ./.github/workflows/linux_build_wx.yml with: jobName: "with LTO" compiler: gcc @@ -22,7 +22,7 @@ jobs: # (PCH conflicts with ccache, fixed by https://gitlab.kitware.com/cmake/cmake/-/merge_requests/4400) build_gcc_nopch: name: "GCC" - uses: ./.github/workflows/linux_build.yml + uses: ./.github/workflows/linux_build_wx.yml with: jobName: "No PCH" compiler: gcc @@ -32,7 +32,7 @@ jobs: build_gcc_nopch_avx2: name: "GCC" - uses: ./.github/workflows/linux_build.yml + uses: ./.github/workflows/linux_build_wx.yml with: jobName: "AVX2 and No PCH" compiler: gcc @@ -42,10 +42,33 @@ jobs: build_clang_nopch: name: "Clang" - uses: ./.github/workflows/linux_build.yml + uses: ./.github/workflows/linux_build_wx.yml with: jobName: "No PCH" compiler: clang cmakeflags: "" detail: " nopch" secrets: inherit + + build_linux_qt_sse4: + name: "AppImage" + uses: ./.github/workflows/linux_build_qt.yml + with: + jobName: "Qt SSE4" + compiler: clang + cmakeflags: "" + simd: "SSE4" + buildAppImage: true + secrets: inherit + + build_linux_qt_avx2: + name: "AppImage" + uses: ./.github/workflows/linux_build_qt.yml + with: + jobName: "Qt AVX2" + detail: "" + compiler: clang + cmakeflags: "-DARCH_FLAG=-march=haswell" + simd: "AVX2" + buildAppImage: true + secrets: inherit diff --git a/.github/workflows/linux_build_qt.yml b/.github/workflows/linux_build_qt.yml new file mode 100644 index 0000000000..769520e3ca --- /dev/null +++ b/.github/workflows/linux_build_qt.yml @@ -0,0 +1,129 @@ +name: Linux Build Steps + +on: + workflow_call: + inputs: + jobName: + required: true + type: string + os: + required: false + type: string + default: ubuntu-20.04 + platform: + required: false + type: string + default: x64 + compiler: + required: true + type: string + cmakeflags: + required: true + type: string + buildAppImage: + required: false + type: boolean + default: false + detail: + required: false + type: string + default: "" + simd: + required: false + type: string + default: "" + +jobs: + build_linux: + name: ${{ inputs.jobName }} + runs-on: ${{ inputs.os }} + # Set some sort of timeout in the event of run-away builds. We are limited on concurrent jobs so, get rid of them. + timeout-minutes: 60 + env: + CCACHE_BASEDIR: ${{ github.workspace }} + CCACHE_DIR: ${{ github.workspace }}/.ccache + CCACHE_COMPRESS: true + CCACHE_COMPRESSLEVEL: 9 + CCACHE_MAXSIZE: 100M + + steps: + - name: Checkout Repository + uses: actions/checkout@v3 + with: + submodules: recursive + + - name: Prepare Artifact Metadata + id: artifact-metadata + shell: bash + env: + OS: linux + GUI_FRAMEWORK: QT + ARCH: ${{ inputs.platform }} + SIMD: ${{ inputs.simd }} + EVENT_NAME: ${{ github.event_name }} + PR_TITLE: ${{ github.event.pull_request.title }} + PR_NUM: ${{ github.event.pull_request.number }} + PR_SHA: ${{ github.event.pull_request.head.sha }} + run: ./.github/workflows/scripts/common/name-artifacts.sh + + # -- SETUP CCACHE - https://cristianadam.eu/20200113/speeding-up-c-plus-plus-github-actions-using-ccache/ + - name: Prepare ccache timestamp + id: ccache_cache_timestamp + shell: cmake -P {0} + run: | + string(TIMESTAMP current_date "%Y-%m-%d-%H;%M;%S" UTC) + message("::set-output name=timestamp::${current_date}") + + - name: ccache cache files + uses: actions/cache@v3 + with: + path: .ccache + key: ${{ inputs.os }} ${{ inputs.platform }} ${{ inputs.compiler }} ${{ inputs.simd }} ${{ inputs.detail }} ccache ${{ steps.ccache_cache_timestamp.outputs.timestamp }} + restore-keys: ${{ inputs.os }} ${{ inputs.platform }} ${{ inputs.compiler }} ${{ inputs.simd }} ${{ inputs.detail }} ccache + + - name: Install Packages + env: + COMPILER: ${{ inputs.compiler }} + run: .github/workflows/scripts/linux/install-packages-qt.sh + + - name: Cache Dependencies + id: cache-deps + uses: actions/cache@v3 + with: + path: ~/deps + key: ${{ inputs.os }} ${{ inputs.platform }} ${{ inputs.gui }} deps ${{ hashFiles('.github/workflows/scripts/linux/build-dependencies-qt.sh') }} + + - name: Build Dependencies + if: steps.cache-deps.outputs.cache-hit != 'true' + run: .github/workflows/scripts/linux/build-dependencies-qt.sh + + - name: Generate CMake + env: + COMPILER: ${{ inputs.compiler }} + ADDITIONAL_CMAKE_ARGS: ${{ inputs.cmakeflags }} + run: .github/workflows/scripts/linux/generate-cmake-qt.sh + + - name: Build PCSX2 + working-directory: build + run: ../.github/workflows/scripts/linux/compile.sh + + - name: Run Tests + working-directory: ./build + run: ninja unittests + + - name: Package AppImage + if: inputs.buildAppImage == true + env: + NAME: ${{ steps.artifact-metadata.outputs.artifact-name }} + run: | + ninja -C build install + .github/workflows/scripts/linux/appimage-qt.sh "$(realpath .)" "$HOME/deps" "$NAME" + mkdir -p "$GITHUB_WORKSPACE"/ci-artifacts/ + mv "${NAME}.AppImage" "$GITHUB_WORKSPACE"/ci-artifacts/ + + - name: Upload artifact + if: inputs.buildAppImage == true + uses: actions/upload-artifact@v3 + with: + name: ${{ steps.artifact-metadata.outputs.artifact-name }} + path: ci-artifacts diff --git a/.github/workflows/linux_build.yml b/.github/workflows/linux_build_wx.yml similarity index 100% rename from .github/workflows/linux_build.yml rename to .github/workflows/linux_build_wx.yml diff --git a/.github/workflows/release_pipeline.yml b/.github/workflows/release_pipeline.yml index 94bf7d9c9a..6ece4f6c59 100644 --- a/.github/workflows/release_pipeline.yml +++ b/.github/workflows/release_pipeline.yml @@ -11,7 +11,7 @@ jobs: build_gcc_lto: if: github.repository == 'PCSX2/pcsx2' name: "Linux - AppImage" - uses: ./.github/workflows/linux_build.yml + uses: ./.github/workflows/linux_build_wx.yml with: jobName: "wxWidgets" compiler: gcc @@ -19,6 +19,31 @@ jobs: buildAppImage: true secrets: inherit + build_linux_qt_sse4: + if: github.repository == 'PCSX2/pcsx2' + name: "Linux - AppImage SSE4" + uses: ./.github/workflows/linux_build_qt.yml + with: + jobName: "Qt" + compiler: clang + cmakeflags: "" + simd: "SSE4" + buildAppImage: true + secrets: inherit + + build_linux_qt_avx2: + if: github.repository == 'PCSX2/pcsx2' + name: "Linux - AppImage AVX2" + uses: ./.github/workflows/linux_build_qt.yml + with: + jobName: "Qt" + detail: "" + compiler: clang + cmakeflags: "-DARCH_FLAG=-march=haswell" + simd: "AVX2" + buildAppImage: true + secrets: inherit + # Windows build_wx_sse4: if: github.repository == 'PCSX2/pcsx2' @@ -82,6 +107,8 @@ jobs: if: github.repository == 'PCSX2/pcsx2' needs: - build_gcc_lto + - build_linux_qt_sse4 + - build_linux_qt_avx2 - build_wx_sse4 - build_wx_avx2 - build_qt_sse4 diff --git a/.github/workflows/scripts/common/name-artifacts.sh b/.github/workflows/scripts/common/name-artifacts.sh index 4f823daf9f..dd2e6618ff 100755 --- a/.github/workflows/scripts/common/name-artifacts.sh +++ b/.github/workflows/scripts/common/name-artifacts.sh @@ -21,7 +21,7 @@ NAME="" if [ "${OS}" == "macos" ]; then NAME="PCSX2-${OS}-${GUI_FRAMEWORK}" -elif [ "${OS}" == "windows" ]; then +elif [[ "${OS}" == "windows" || ("$OS" == "linux" && "$GUI_FRAMEWORK" == "QT") ]]; then NAME="PCSX2-${OS}-${GUI_FRAMEWORK}-${ARCH}-${SIMD}" else NAME="PCSX2-${OS}-${GUI_FRAMEWORK}-${ARCH}" diff --git a/.github/workflows/scripts/linux/AppRun-qt b/.github/workflows/scripts/linux/AppRun-qt new file mode 100755 index 0000000000..973b76be02 --- /dev/null +++ b/.github/workflows/scripts/linux/AppRun-qt @@ -0,0 +1,4 @@ +#!/bin/sh + +cd "$(dirname "$0")" +exec ./usr/bin/pcsx2-qt "$@" diff --git a/.github/workflows/scripts/linux/appimage-qt.sh b/.github/workflows/scripts/linux/appimage-qt.sh new file mode 100755 index 0000000000..72a471fa1f --- /dev/null +++ b/.github/workflows/scripts/linux/appimage-qt.sh @@ -0,0 +1,253 @@ +#!/usr/bin/env bash + +# This is free and unencumbered software released into the public domain. +# +# Anyone is free to copy, modify, publish, use, compile, sell, or +# distribute this software, either in source code form or as a compiled +# binary, for any purpose, commercial or non-commercial, and by any +# means. +# +# In jurisdictions that recognize copyright laws, the author or authors +# of this software dedicate any and all copyright interest in the +# software to the public domain. We make this dedication for the benefit +# of the public at large and to the detriment of our heirs and +# successors. We intend this dedication to be an overt act of +# relinquishment in perpetuity of all present and future rights to this +# software under copyright law. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +# IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +# OTHER DEALINGS IN THE SOFTWARE. +# +# For more information, please refer to + +if [ "$#" -ne 3 ]; then + echo "Syntax: $0 " + exit 1 +fi + +PCSX2DIR=$1 +DEPSDIR=$2 +NAME=$3 + +BINDIR="$PCSX2DIR/bin" + +BINARY=pcsx2-qt +APPDIRNAME=PCSX2.AppDir +STRIP=llvm-strip-12 + +declare -a SYSLIBS=( + "libaio.so.1" + "libz.so.1" + "libuuid.so.1" + "libapparmor.so.1" + "libblkid.so.1" + "libbsd.so.0" + "libdbus-1.so.3" + "libgcrypt.so.20" + "liblzma.so.5" + "libmount.so.1" + "libnsl.so.1" + "libpcre.so.3" + "libselinux.so.1" + "libsystemd.so.0" + "libudev.so.1" + "libwrap.so.0" + "libharfbuzz.so.0" + "libFLAC.so.8" + "libSoundTouch.so.1" + "libXau.so.6" + "libXcomposite.so.1" + "libXcursor.so.1" + "libXdamage.so.1" + "libXdmcp.so.6" + "libXext.so.6" + "libXfixes.so.3" + "libXi.so.6" + "libXinerama.so.1" + "libXrandr.so.2" + "libXrender.so.1" + "libXxf86vm.so.1" + "libasyncns.so.0" + "libcrypto.so.1.1" + "libjpeg.so.8" + "liblz4.so.1" + "libogg.so.0" + "libpcap.so.0.8" + "libpng16.so.16" + "libpulse.so.0" + "libsamplerate.so.0" + "libsndfile.so.1" + "libvorbis.so.0" + "libvorbisenc.so.2" + "libxcb.so.1" + "libxcb-render.so.0" + "libxcb-shm.so.0" + "libxkbcommon.so.0" + "libxkbcommon-x11.so.0" + "pulseaudio/libpulsecommon-13.99.so" + "libfreetype.so.6" + "libpcre2-16.so.0" + "libexpat.so.1" + "libffi.so.7" + "libgraphite2.so.3" + "libresolv.so.2" + "libgpg-error.so.0" + "libpcre2-16.so.0" + "libpng16.so.16" + "libxcb-icccm.so.4" + "libxcb-image.so.0" + "libxcb-keysyms.so.1" + "libxcb-randr.so.0" + "libxcb-render.so.0" + "libxcb-render-util.so.0" + "libxcb-shape.so.0" + "libxcb-sync.so.1" + "libxcb-util.so.1" + "libxcb-xfixes.so.0" + "libxcb-xkb.so.1" + "libevdev.so.2" + "libgudev-1.0.so.0" + "libinput.so.10" + "libjpeg.so.8" + "libmtdev.so.1" + "libpng16.so.16" + "libudev.so.1" + "libuuid.so.1" +) + +declare -a DEPLIBS=( + "libSDL2-2.0.so.0" +) + +declare -a QTLIBS=( + "libQt6Core.so.6" + "libQt6Gui.so.6" + "libQt6Network.so.6" + "libQt6OpenGL.so.6" + "libQt6Svg.so.6" + "libQt6WaylandClient.so.6" + "libQt6WaylandCompositor.so.6" + "libQt6WaylandEglClientHwIntegration.so.6" + "libQt6WaylandEglCompositorHwIntegration.so.6" + "libQt6Widgets.so.6" + "libQt6XcbQpa.so.6" +) + +declare -a QTPLUGINS=( + "plugins/iconengines" + "plugins/imageformats" + "plugins/platforms" + #"plugins/platformthemes" # Enable this if we want to ship GTK+ themes at any point. + "plugins/wayland-decoration-client" + "plugins/wayland-graphics-integration-client" + "plugins/wayland-graphics-integration-server" + "plugins/wayland-shell-integration" + "plugins/xcbglintegrations" +) + +set -e + +if [ ! -f appimagetool-x86_64.AppImage ]; then + wget https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage + chmod +x appimagetool-x86_64.AppImage +fi + +OUTDIR=$(realpath "./$APPDIRNAME") +SCRIPTDIR=$(dirname "${BASH_SOURCE[0]}") +rm -fr "$OUTDIR" +mkdir "$OUTDIR" + +mkdir -p "$OUTDIR/usr/bin" "$OUTDIR/usr/lib" "$OUTDIR/usr/lib/pulseaudio" + +echo "Copying binary and resources..." +cp -a "$BINDIR/$BINARY" "$BINDIR/resources" "$BINDIR/shaders" "$OUTDIR/usr/bin" + +# Don't need old wx locales. +rm -fr "$OUTDIR/usr/bin/resources/locale" + +# Patch RPATH so the binary goes hunting for shared libraries in the AppDir instead of system. +echo "Patching RPATH in ${BINARY}..." +patchelf --set-rpath '$ORIGIN/../lib' "$OUTDIR/usr/bin/$BINARY" + +# Currently we leave the main binary unstripped, uncomment if this is not desired. +#$STRIP "$OUTDIR/usr/bin/$BINARY" + +# Libraries we pull in from the system. +echo "Copying system libraries..." +for lib in "${SYSLIBS[@]}"; do + blib=$(basename "$lib") + if [ -f "/lib/x86_64-linux-gnu/$lib" ]; then + cp "/lib/x86_64-linux-gnu/$lib" "$OUTDIR/usr/lib/$blib" + elif [ -f "$CHROOT/usr/lib/x86_64-linux-gnu/$lib" ]; then + cp "$CHROOT/usr/lib/x86_64-linux-gnu/$lib" "$OUTDIR/usr/lib/$blib" + elif [ -f "$CHROOT/lib/$lib" ]; then + cp "$CHROOT/lib/$lib" "$OUTDIR/usr/lib/$blib" + elif [ -f "$CHROOT/usr/lib/$lib" ]; then + cp "$CHROOT/usr/lib/$lib" "$OUTDIR/usr/lib/$blib" + else + echo "*** Failed to find '$blib'" + exit 1 + fi + + $STRIP "$OUTDIR/usr/lib/$blib" +done + +# Dependencies we built, at this point it's just SDL. +echo "Copying dependency libraries..." +for lib in "${DEPLIBS[@]}"; do + blib=$(basename "$lib") + if [ -f "$DEPSDIR/lib/$lib" ]; then + cp "$DEPSDIR/lib/$lib" "$OUTDIR/usr/lib/$blib" + else + echo "*** Failed to find '$blib'" + exit 1 + fi + + $STRIP "$OUTDIR/usr/lib/$blib" +done + +echo "Copying Qt libraries..." +for lib in "${QTLIBS[@]}"; do + cp -aL "$DEPSDIR/lib/$lib" "$OUTDIR/usr/lib" + $STRIP "$OUTDIR/usr/lib/$lib" +done + +echo "Copying Qt plugins..." +mkdir -p "$OUTDIR/usr/lib/plugins" +for plugin in "${QTPLUGINS[@]}"; do + mkdir -p "$OUTDIR/usr/lib/$plugin" + cp -aL "$DEPSDIR/$plugin"/*.so "$OUTDIR/usr/lib/$plugin/" +done + +for so in $(find "$OUTDIR/usr/lib/plugins" -iname '*.so'); do + # This is ../../ because it's usually plugins/group/name.so + echo "Patching RPATH in ${so}..." + patchelf --set-rpath '$ORIGIN/../..' "$so" + $STRIP "$so" +done + +for so in $(find "$OUTDIR/usr/lib" -maxdepth 1); do + if [ -f "$so" ]; then + echo "Patching RPATH in ${so}" + patchelf --set-rpath '$ORIGIN' "$so" + fi +done + +echo "Creating qt.conf..." +cat > "$OUTDIR/usr/bin/qt.conf" << EOF +[Paths] +Plugins = ../lib/plugins +EOF + +echo "Copy desktop/icon..." +cp "$PCSX2DIR/pcsx2/gui/Resources/AppIcon64.png" "$OUTDIR/PCSX2.png" +cp "$SCRIPTDIR/pcsx2-qt.desktop" "$OUTDIR/PCSX2.desktop" +cp "$SCRIPTDIR/AppRun-qt" "$OUTDIR/AppRun" + +echo "Generate AppImage" +./appimagetool-x86_64.AppImage -v "$OUTDIR" "$NAME.AppImage" diff --git a/.github/workflows/scripts/linux/build-dependencies-qt.sh b/.github/workflows/scripts/linux/build-dependencies-qt.sh new file mode 100755 index 0000000000..55a35cc64f --- /dev/null +++ b/.github/workflows/scripts/linux/build-dependencies-qt.sh @@ -0,0 +1,112 @@ +#!/usr/bin/env bash + +set -e + +INSTALLDIR="$HOME/deps" +NPROCS="$(getconf _NPROCESSORS_ONLN)" +SDL=SDL2-2.0.22 +QT=6.3.0 + +mkdir -p deps-build +cd deps-build + +cat > SHASUMS < "$HOME/clang-toolchain.cmake" << EOF +set(CMAKE_C_COMPILER /usr/bin/clang-12) +set(CMAKE_CXX_COMPILER /usr/bin/clang++-12) +set(CMAKE_EXE_LINKER_FLAGS_INIT "-fuse-ld=lld") +set(CMAKE_MODULE_LINKER_FLAGS_INIT "-fuse-ld=lld") +set(CMAKE_SHARED_LINKER_FLAGS_INIT "-fuse-ld=lld") +EOF + ADDITIONAL_CMAKE_ARGS="$ADDITIONAL_CMAKE_ARGS -DCMAKE_INTERPROCEDURAL_OPTIMIZATION=ON -DCMAKE_TOOLCHAIN_FILE=$HOME/clang-toolchain.cmake" +fi + +echo "Additional CMake Args - ${ADDITIONAL_CMAKE_ARGS}" + +# Generate CMake into ./build +# DISABLE_ADVANCE_SIMD is needed otherwise we end up doing -march=native. + +# shellcheck disable=SC2086 +cmake \ + -B build \ + -G Ninja \ + $ADDITIONAL_CMAKE_ARGS \ + -DCMAKE_CXX_COMPILER_LAUNCHER=ccache \ + -DCMAKE_BUILD_TYPE=Release \ + -DQT_BUILD=ON \ + -DWAYLAND_API=ON \ + -DXDG_STD=TRUE \ + -DDISABLE_PCSX2_WRAPPER=ON \ + -DDISABLE_SETCAP=ON \ + -DCMAKE_PREFIX_PATH="$HOME/deps" \ + -DUSE_SYSTEM_SDL2=ON \ + -DUSE_SYSTEM_ZSTD=OFF \ + -DDISABLE_ADVANCE_SIMD=TRUE + diff --git a/.github/workflows/scripts/linux/install-packages-qt.sh b/.github/workflows/scripts/linux/install-packages-qt.sh new file mode 100755 index 0000000000..fb0805a102 --- /dev/null +++ b/.github/workflows/scripts/linux/install-packages-qt.sh @@ -0,0 +1,72 @@ +#!/bin/bash + +set -e + +# Packages - Build and Qt +declare -a BUILD_PACKAGES=( + "build-essential" + "git" + "cmake" + "ccache" + "ninja-build" + "libclang-dev" # Qt goes hunting for libclang-11 specifically. + "libclang-11-dev" + "libclang-12-dev" + "patchelf" + "libglib2.0-dev" + "libfontconfig1-dev" + "libharfbuzz-dev" + "libjpeg-dev" + "libpng-dev" + "libfreetype-dev" + "libinput-dev" + "libxcb-*-dev" + "libxkbcommon-dev" + "libxkbcommon-x11-dev" + "libxrender-dev" + "libwayland-dev" + "libgl1-mesa-dev" + "libegl-dev" + "libegl1-mesa-dev" + "libgl1-mesa-dev" + "libssl-dev" +) + +# Packages - PCSX2 +declare -a PCSX2_PACKAGES=( + "libaio-dev" + "libbz2-dev" + "libegl1-mesa-dev" + "libgl1-mesa-dev" + "libgtk-3-dev" + "libharfbuzz-dev" + "libjpeg-dev" + "liblzma-dev" + "libpcap0.8-dev" + "libpng-dev" + "libpulse-dev" + "librsvg2-dev" + "libsamplerate0-dev" + "libsoundtouch-dev" + "libudev-dev" + "libx11-xcb-dev" + "pkg-config" + "zlib1g-dev" +) + +if [ "${COMPILER}" = "gcc" ]; then + BUILD_PACKAGES+=("g++-10") +else + BUILD_PACKAGES+=("llvm-12" "lld-12" "clang-12") +fi + +sudo apt-get -qq update + +# Install packages needed for building +echo "Will install the following packages for building - ${BUILD_PACKAGES[*]}" +sudo apt-get -y install "${BUILD_PACKAGES[@]}" + +# Install packages needed by pcsx2 +PCSX2_PACKAGES=("${PCSX2_PACKAGES[@]}") +echo "Will install the following packages for pcsx2 - ${PCSX2_PACKAGES[*]}" +sudo apt-get -y install "${PCSX2_PACKAGES[@]}" diff --git a/.github/workflows/scripts/linux/pcsx2-qt.desktop b/.github/workflows/scripts/linux/pcsx2-qt.desktop new file mode 100644 index 0000000000..30ae545b42 --- /dev/null +++ b/.github/workflows/scripts/linux/pcsx2-qt.desktop @@ -0,0 +1,12 @@ +[Desktop Entry] +Version=1.0 +Terminal=false +Type=Application +Name=PCSX2 +StartupWMClass=PCSX2 +GenericName=PlayStation 2 Emulator +Comment=Sony PlayStation 2 emulator +Exec=pcsx2-qt +Icon=PCSX2 +Keywords=game;emulator; +Categories=Game;Emulator;