Repository: flightlessmango/MangoHud Branch: master Commit: f2e45e9f2a36 Files: 187 Total size: 2.2 MB Directory structure: gitextract_zt6zshhe/ ├── .editorconfig ├── .github/ │ ├── ISSUE_TEMPLATE/ │ │ └── -bug-report----issue.md │ ├── dependabot.yml │ └── workflows/ │ ├── arch-package.yml │ ├── build-package.yml │ ├── build-source.yml │ ├── mingw.yml │ ├── param-check.yml │ └── ubuntu.yml ├── .gitignore ├── .gitmodules ├── LICENSE ├── README.md ├── bin/ │ ├── gen_enum_to_str.py │ ├── mangohud-setup.sh │ ├── mangohud.in │ ├── mangoplot.py │ ├── meson.build │ ├── vk_dispatch_table_gen.py │ ├── vk_entrypoints.py │ ├── vk_extensions.py │ └── vk_extensions_gen.py ├── build-source.sh ├── build-srt.sh ├── build-with-srt-docker.sh ├── build.sh ├── build_deps.sh ├── control/ │ ├── setup.cfg │ ├── setup.py │ └── src/ │ └── control/ │ └── __init__.py ├── data/ │ ├── MangoHud.conf │ ├── io.github.flightlessmango.mangohud.metainfo.xml │ ├── mangoapp.1 │ ├── mangohud.1 │ ├── meson.build │ └── presets.conf ├── include/ │ ├── .editorconfig │ ├── IconsForkAwesome.h │ ├── KHR/ │ │ └── khrplatform.h │ ├── elfhacks.h │ ├── filesystem.h │ ├── glad/ │ │ └── glad.h │ ├── nvml.h │ └── vulkan/ │ └── vk_util.h ├── meson.build ├── meson_options.txt ├── mingw32.txt ├── mingw64.txt ├── pkgbuild/ │ └── PKGBUILD ├── src/ │ ├── amdgpu.cpp │ ├── amdgpu.h │ ├── app/ │ │ ├── control.c │ │ ├── main.cpp │ │ ├── mangoapp.h │ │ └── mangoapp_proto.h │ ├── battery.cpp │ ├── battery.h │ ├── blacklist.cpp │ ├── blacklist.h │ ├── config.cpp │ ├── config.h │ ├── control.cpp │ ├── cpu.cpp │ ├── cpu.h │ ├── cpu_win32.cpp │ ├── dbus.cpp │ ├── dbus_helpers.h │ ├── dbus_info.h │ ├── device.cpp │ ├── device.h │ ├── elfhacks.c │ ├── fcat.h │ ├── fex.cpp │ ├── fex.h │ ├── file_utils.cpp │ ├── file_utils.h │ ├── file_utils_win32.cpp │ ├── font.cpp │ ├── font_default.h │ ├── font_unispace.c │ ├── forkawesome.h │ ├── fps_limiter.h │ ├── fps_metrics.h │ ├── ftrace.cpp │ ├── ftrace.h │ ├── gl/ │ │ ├── gl.h │ │ ├── gl_hud.cpp │ │ ├── gl_hud.h │ │ ├── gl_renderer.cpp │ │ ├── gl_renderer.h │ │ ├── glad.c │ │ ├── inject_egl.cpp │ │ ├── inject_glx.cpp │ │ └── shim.c │ ├── gpu.cpp │ ├── gpu.h │ ├── gpu_fdinfo.cpp │ ├── gpu_fdinfo.h │ ├── gpu_metrics_util.h │ ├── hud_elements.cpp │ ├── hud_elements.h │ ├── imgui_utils.h │ ├── iostats.cpp │ ├── iostats.h │ ├── keybinds.cpp │ ├── keybinds.h │ ├── loaders/ │ │ ├── loader_dbus.cpp │ │ ├── loader_dbus.h │ │ ├── loader_glx.cpp │ │ ├── loader_glx.h │ │ ├── loader_nvctrl.cpp │ │ ├── loader_nvctrl.h │ │ ├── loader_nvml.cpp │ │ ├── loader_nvml.h │ │ ├── loader_x11.cpp │ │ └── loader_x11.h │ ├── logging.cpp │ ├── logging.h │ ├── mangohud.json.in │ ├── mangohud.version │ ├── memory.cpp │ ├── memory.h │ ├── mesa/ │ │ ├── c11_compat.h │ │ ├── c99_compat.h │ │ ├── no_extern_c.h │ │ └── util/ │ │ ├── detect_os.h │ │ ├── macros.h │ │ ├── os_socket.c │ │ ├── os_socket.h │ │ ├── os_time.c │ │ └── os_time.h │ ├── meson.build │ ├── net.cpp │ ├── net.h │ ├── notify.cpp │ ├── notify.h │ ├── nvapi.cpp │ ├── nvidia.cpp │ ├── nvidia.h │ ├── overlay.cpp │ ├── overlay.frag │ ├── overlay.h │ ├── overlay.vert │ ├── overlay_params.cpp │ ├── overlay_params.h │ ├── pci_ids.cpp │ ├── pci_ids.h │ ├── real_dlsym.c │ ├── real_dlsym.h │ ├── shared_x11.cpp │ ├── shared_x11.h │ ├── shell.cpp │ ├── shell.h │ ├── string_utils.h │ ├── timing.hpp │ ├── vulkan.cpp │ ├── wayland_hook.h │ ├── wayland_keybinds.cpp │ ├── win/ │ │ ├── d3d11_hook.cpp │ │ ├── d3d11_hook.h │ │ ├── d3d12_hook.cpp │ │ ├── d3d12_hook.h │ │ ├── d3d_shared.cpp │ │ ├── d3d_shared.h │ │ ├── dxgi.cpp │ │ ├── dxgi.h │ │ ├── kiero.cpp │ │ ├── kiero.h │ │ ├── main.cpp │ │ └── win_shared.h │ └── winesync.h ├── steamrt.Dockerfile.in ├── subprojects/ │ ├── cmocka.wrap │ ├── imgui.wrap │ ├── implot.wrap │ ├── minhook.wrap │ ├── packagefiles/ │ │ ├── vulkan-headers/ │ │ │ └── meson.build │ │ └── vulkan-utility-libraries/ │ │ └── meson.build │ ├── spdlog.wrap │ ├── vulkan-headers.wrap │ └── vulkan-utility-libraries.wrap ├── tests/ │ ├── gpu_metrics │ ├── gpu_metrics_apu │ ├── gpu_metrics_invalid │ ├── params.py │ └── test_amdgpu.cpp └── version.h.in ================================================ FILE CONTENTS ================================================ ================================================ FILE: .editorconfig ================================================ # See http://editorconfig.org to read about the EditorConfig format. # - Automatically supported by VS2017+ and most common IDE or text editors. # - For older VS2010 to VS2015, install https://marketplace.visualstudio.com/items?itemName=EditorConfigTeam.EditorConfig # top-most EditorConfig file root = true # Default settings: # Use 4 spaces as indentation [*] indent_style = space indent_size = 4 insert_final_newline = true trim_trailing_whitespace = true [src/overlay*{cpp,h}] indent_size = 3 [src/{keybinds,vulkan}.{cpp,h}] indent_size = 3 [src/mesa/**] indent_size = 3 [meson.build] indent_size = 2 ================================================ FILE: .github/ISSUE_TEMPLATE/-bug-report----issue.md ================================================ --- name: "[Bug report] - Issue" about: Create a report to help us improve title: '' labels: '' assignees: '' --- ⚠️ **Do not report issues for unsupported or old MangoHud versions.** Please verify the issue still occurs on the latest release before submitting. --- ## Describe the bug A clear and concise description of what the bug is. ## System information Please provide all relevant details. - **Linux distribution** - **Kernel version** - **MangoHud version** - **MangoHud config** (attach or paste if non default) - **Launch options** - **Application or game** - **GPU model and driver** - **Display server** (X11 or Wayland) ## Expected behavior What you expected to happen. ## Actual behavior What actually happened. ## Logs Include log captured with `MANGOHUD_LOG_LEVEL=debug` set Wrap logs in code blocks. ## Screenshots If applicable, add screenshots to help explain the problem. ## Additional context Any other information that might be useful. ================================================ FILE: .github/dependabot.yml ================================================ version: 2 updates: - package-ecosystem: "github-actions" directory: "/" schedule: interval: "weekly" ================================================ FILE: .github/workflows/arch-package.yml ================================================ name: arch package on: workflow_dispatch: jobs: build-arch-pkg: runs-on: ubuntu-latest container: image: archlinux:latest steps: - name: set git global safe directory run: | pacman -Syu git --noconfirm git config --global --add safe.directory $(realpath .) - uses: actions/checkout@v3 - name: Install prerequisites run: | echo "ParallelDownloads = 10" >> /etc/pacman.conf echo "\n" && echo "[multilib]" >> /etc/pacman.conf echo "Include = /etc/pacman.d/mirrorlist" >> /etc/pacman.conf pacman -Syu base-devel sudo meson python-mako glslang hub python-numpy python-matplotlib --noconfirm - name: makepkg run: | useradd -m builduser echo "builduser ALL=(ALL) NOPASSWD:ALL" > /etc/sudoers.d/builduser chmod 0440 /etc/sudoers.d/builduser chown -R builduser:builduser pkgbuild cd pkgbuild pkgver=$(git describe --tags | sed -r 's/^v//;s/([^-]*-g)/r\1/;s/-/./g') sed -i "s/pkgver=.*/pkgver=$pkgver/g" PKGBUILD sudo -u builduser -- sh -c "makepkg -fsCc --noconfirm" - name: Edit release and add files env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | set -x assets=() for pkg in ./pkgbuild/*mangohud*.tar.zst; do echo $pkg; assets+=("-a" "$pkg") done; tag_name="${GITHUB_REF##*/}" hub release edit "${assets[@]}" -m "" "$tag_name" ================================================ FILE: .github/workflows/build-package.yml ================================================ name: Build release package on: release: types: [published] jobs: build: runs-on: ubuntu-24.04 steps: - uses: actions/checkout@v3 - name: Install build tools run: | set -x sudo dpkg --add-architecture i386 sudo apt update sudo apt -y install gcc-multilib g++-multilib ninja-build python3-setuptools \ python3-wheel mesa-common-dev libxnvctrl-dev libdbus-1-dev \ python3-numpy python3-matplotlib unzip libxkbcommon-dev libwayland-dev wget unzip \ libxkbcommon-dev:i386 libwayland-dev:i386 gh python3-mako meson pkgconf pkg-config wget https://github.com/KhronosGroup/glslang/releases/download/SDK-candidate-26-Jul-2020/glslang-master-linux-Release.zip unzip glslang-master-linux-Release.zip bin/glslangValidator sudo install -m755 bin/glslangValidator /usr/local/bin/ command -v pkg-config && pkg-config --version - name: Prepare Artifact Git Info shell: bash run: | echo "##[set-output name=branch;]${GITHUB_REF#refs/heads/}" ARTIFACT_NAME="commit-$(git rev-parse --short "$GITHUB_SHA")" if [ ${{ github.event_name == 'pull_request' }} ]; then echo "##[set-output name=short-sha;]$(git rev-parse --short "${{ github.event.pull_request.head.sha }}")" if [ ! -z "${{ github.event.pull_request.number }}" ]; then ARTIFACT_NAME="pr-${{ github.event.pull_request.number }}-commit-$(git rev-parse --short "${{ github.event.pull_request.head.sha }}")" fi else echo "##[set-output name=short-sha;]$(git rev-parse --short "$GITHUB_SHA")" fi echo "##[set-output name=artifact-metadata;]$ARTIFACT_NAME" - name: Build and package run: | ./build-source.sh ./build.sh build -Dwerror=true package release - name: Upload assets to release env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | tag_name="${GITHUB_REF##*/}" for pkg in ./build/*.tar.*; do gh release upload "$tag_name" "$pkg" --clobber done - name: Upload artifact uses: actions/upload-artifact@v4 continue-on-error: true with: name: MangoHud-${{steps.git-vars.outputs.artifact-metadata}} path: ${{runner.workspace}}/MangoHud/build/MangoHud-*tar.gz retention-days: 30 ================================================ FILE: .github/workflows/build-source.yml ================================================ name: Build source tars on: workflow_dispatch: release: types: [published] jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: Run build-source.sh env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | set -x sudo apt update sudo apt -y install gcc g++ ninja-build python3-pip python3-setuptools \ python3-wheel pkg-config mesa-common-dev libx11-dev \ libxnvctrl-dev libdbus-1-dev glslang-tools hub libxkbcommon-dev \ libwayland-dev wget unzip python3-mako meson ./build-source.sh assets=() for asset in ./MangoHud-*-Source*.tar.*; do assets+=("-a" "$asset") done tag_name="${GITHUB_REF##*/}" hub release edit "${assets[@]}" -m "" "$tag_name" #hub release create "${assets[@]}" -m "$tag_name" "$tag_name" - name: Upload artifact uses: actions/upload-artifact@v4 continue-on-error: true with: name: MangoHud-${{steps.git-vars.outputs.artifact-metadata}} path: ${{runner.workspace}}/MangoHud/build/MangoHud-*tar.gz retention-days: 30 ================================================ FILE: .github/workflows/mingw.yml ================================================ name: Mingw build testing on: [push, pull_request] jobs: build-mingw: runs-on: ubuntu-latest container: image: archlinux:latest steps: - uses: actions/checkout@v3 - name: Install prerequisites run: | pacman -Syu mingw-w64-gcc meson python-mako glslang mingw-w64-headers git --noconfirm - name: configure run: meson setup --cross-file mingw64.txt build64 - name: build run: ninja -C build64 ================================================ FILE: .github/workflows/param-check.yml ================================================ name: param check on: push: paths: - 'src/overlay_params.h' - 'README.md' - 'data/MangoHud.conf' jobs: param-check: runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v3 - name: Set up Python uses: actions/setup-python@v4 with: python-version: '3.11.2' # Replace with the version of Python you want to use - name: Run Python script run: | cd tests python params.py ================================================ FILE: .github/workflows/ubuntu.yml ================================================ name: Ubuntu build testing on: [push, pull_request] jobs: build-test: strategy: matrix: compiler: [clang, gcc] os: [ubuntu-24.04] runs-on: ${{ matrix.os }} steps: - name: 'Checkout' uses: actions/checkout@v3 - name: 'Install prerequisites' run: | sudo apt-get update sudo apt-get install -y \ appstream \ glslang-tools \ ninja-build \ python3-mako \ python3-setuptools \ python3-wheel \ mesa-common-dev \ libcmocka-dev \ libdbus-1-dev \ libglfw3-dev \ libwayland-dev \ libxnvctrl-dev \ libxkbcommon-dev \ meson - name: 'Install clang' if: ${{ (matrix.compiler == 'clang') }} run: | sudo apt-get install -y clang echo "CC=clang" >> "$GITHUB_ENV" echo "CXX=clang++" >> "$GITHUB_ENV" - name: 'Install gcc' if: ${{ (matrix.compiler == 'gcc') }} run: | sudo apt-get install -y gcc g++ echo "CC=gcc" >> "$GITHUB_ENV" echo "CXX=g++" >> "$GITHUB_ENV" - name: 'Configure' run: meson setup ./builddir --prefix=/usr -D include_doc=true -D with_xnvctrl=enabled -D with_x11=enabled -D with_wayland=enabled -D with_dbus=enabled -D mangoapp=true -D mangohudctl=true -D tests=enabled --werror - name: 'Build' run: meson compile -C ./builddir || ninja -C ./builddir - name: 'Install' run: sudo meson install -C ./builddir ================================================ FILE: .gitignore ================================================ build builddir __pycache__ .vscode MangoHud*.tar.* pkg mangohud*.tar.* lib32-mangohud*.tar.* # Prerequisites *.d # Compiled Object files *.slo *.lo *.o *.obj # Precompiled Headers *.gch *.pch # Compiled Dynamic libraries *.so *.dylib *.dll # Compiled Static libraries *.lai *.la *.a *.lib # Executables *.exe *.out *.app # subprojects subprojects/packagecache/ subprojects/Vulkan-Headers-*/ subprojects/Vulkan-Utility-Libraries-*/ subprojects/imgui-*/ subprojects/spdlog-*/ subprojects/nlohmann_json-*/ subprojects/implot-*/ subprojects/cmocka/ #GNU Global Metadata **/GPATH **/GRTAGS **/GTAGS ================================================ FILE: .gitmodules ================================================ [submodule "modules/minhook"] path = modules/minhook url = https://github.com/flightlessmango/minhook ================================================ FILE: LICENSE ================================================ MIT License Copyright (c) 2020 flightlessmango Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 OR COPYRIGHT HOLDERS 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. ================================================ FILE: README.md ================================================ # MangoHud A Vulkan and OpenGL overlay for monitoring FPS, temperatures, CPU/GPU load and more. ![Example gif showing a standard performance readout with frametimes](assets/overlay_example.gif) --- - [MangoHud](#mangohud) - [Installation - Build From Source](#installation---build-from-source) - [Dependencies](#dependencies) - [Building with build script](#building-with-build-script) - [Installation - Pre-packaged Binaries](#installation---pre-packaged-binaries) - [GitHub releases](#github-releases) - [Arch-based distributions](#arch-based-distributions) - [Debian, Ubuntu](#debian-ubuntu) - [Fedora](#fedora) - [Solus](#solus) - [openSUSE](#opensuse) - [Flatpak](#flatpak) - [Normal usage](#normal-usage) - [OpenGL](#opengl) - [Hud configuration](#hud-configuration) - [Environment Variables: **`MANGOHUD_CONFIG`**, **`MANGOHUD_CONFIGFILE`**, and **`MANGOHUD_PRESETSFILE`**](#environment-variables) - [Vsync](#vsync) - [OpenGL Vsync](#opengl-vsync) - [Vulkan Vsync](#vulkan-vsync) - [Keybindings](#keybindings) - [Workarounds](#workarounds) - [FPS logging](#fps-logging) - [Online visualization: FlightlessMango.com](#online-visualization-flightlessmangocom) - [Local visualization: `mangoplot`](#local-visualization-mangoplot) - [Metrics support by GPU vendor/driver](#metrics-support-by-gpu-vendordriver) ## Installation - Build From Source --- If you wish to compile MangoHud to keep up to date with any changes - first clone this repository and cd into it: ``` git clone --recurse-submodules https://github.com/flightlessmango/MangoHud.git cd MangoHud ``` Using `meson` to install "manually": ``` meson build ninja -C build install ``` By default, meson should install MangoHud to `/usr/local`. Specify install prefix with `--prefix=/usr` if desired. Add `-Dappend_libdir_mangohud=false` option to meson to not append `mangohud` to libdir if desired (e.g. /usr/local/lib/mangohud). To install 32-bit build on 64-bit distro, specify proper `libdir`: `lib32` for Arch, `lib/i386-linux-gnu` on Debian-based distros. RPM-based distros usually install 32-bit libraries to `/usr/lib` and 64-bit to `/usr/lib64`. You may have to change `PKG_CONFIG_PATH` to point to correct folders for your distro. ``` CC="gcc -m32" \ CXX="g++ -m32" \ PKG_CONFIG_PATH="/usr/lib32/pkgconfig:/usr/lib/i386-linux-gnu/pkgconfig:/usr/lib/pkgconfig" \ meson build32 --libdir lib32 ninja -C build32 install ``` ### Dependencies Install necessary development packages. - gcc, g++ - or gcc-multilib, g++-multilib for 32-bit support - meson >=0.54 - ninja (ninja-build) - glslang - libGL/libEGL (libglvnd, mesa-common-dev, mesa-libGL-devel etc) - X11 (libx11-dev) - XNVCtrl (libxnvctrl-dev), optional, use `-Dwith_xnvctrl=disabled` option with `meson` to disable - D-Bus (libdbus-1-dev), optional, use `-Dwith_dbus=disabled` option with `meson` to disable - wayland-client - xkbcommon Python 3 libraries: - Mako (python3-mako or install with `pip`) If distro's packaged `meson` is too old and gives build errors, install newer version with `pip` (`python3-pip`). ### Meson options | Option | Default | Description | -------- | ------- | - | with_nvml | enabled |Required for NVIDIA GPU metrics on wayland | with_xnvctrl | enabled |Required for NVIDIA GPU metrics on older GPUs | with_x11 | enabled |Required for keybinds on x11 | with_wayland | enabled |Required for keybinds on wayland | with_dbus | enabled |Required for using the media features | mangoapp | false |Includes mangoapp | mangohudctl | false |Include mangohudctl | tests | auto |Includes tests | mangoplot | true |Includes mangoplot ### Building with build script You can also use `build.sh` script to do some things automatically like install dependencies, if distro is supported but it usually assumes you are running on x86_64 architecture. To just build it, execute: ``` ./build.sh build ``` You can also pass arguments to meson: ``` ./build.sh build -Dwith_xnvctrl=disabled ``` Resulting files will be install to `./build/release` folder. If you have compiled MangoHud from source, to install it, execute: ``` ./build.sh install ``` You can then subsequently uninstall MangoHud via the following command ``` ./build.sh uninstall ``` To tar up the resulting binaries into a package and create a release tar with installer script, execute: ``` ./build.sh package release ``` or combine the commands, although `package` should also call `build` if it doesn't find the built libs: ``` ./build.sh build package release ``` If you have built MangoHud before and suddenly it fails, you can try cleaning the `build` folder, execute: ``` ./build.sh clean ``` Currently it just does `rm -fr build` and clears subprojects. __NOTE: If you are running an Ubuntu-based, Arch-based, Fedora-based, or openSUSE-based distro, the build script will automatically detect and prompt you to install missing build dependencies. If you run into any issues with this please report them!__ ## Installation - Pre-packaged Binaries --- ### GitHub releases If you do not wish to compile anything, simply download the file under [Releases](https://github.com/flightlessmango/MangoHud/releases), extract it, and from within the extracted folder in terminal, execute: ``` ./mangohud-setup.sh install ``` ### Arch-based distributions If you are using an Arch-based distribution, install [`mangohud`](https://archlinux.org/packages/extra/x86_64/mangohud/) and [`lib32-mangohud`](https://archlinux.org/packages/multilib/x86_64/lib32-mangohud/) from the `extra`/`multilib` repository. [`mangohud-git`](https://aur.archlinux.org/packages/mangohud-git/) and [`lib32-mangohud-git`](https://aur.archlinux.org/packages/lib32-mangohud-git/) are available on the AUR to be installed via your favourite AUR helper. These can help fix issues with the hud not activating when using stable releases from pacman! If you are building it by yourself, you need to enable multilib repository, by editing pacman config: ``` sudo nano /etc/pacman.conf ``` and uncomment: ```txt #[multilib] #Include = /etc/pacman.d/mirrorlist ``` then save the file and execute: ``` sudo pacman -Syy ``` ### Debian, Ubuntu If you are using Debian 11 (Bullseye) or later, Ubuntu 21.10 (Impish) or later, or distro derived from them, to install the [MangoHud](https://tracker.debian.org/pkg/mangohud) package, execute: ``` sudo apt install mangohud ``` Optionally, if you also need MangoHud for 32-bit applications, on Debian you can execute: ``` sudo apt install mangohud:i386 ``` The 32-bit package is not available on Ubuntu. ### Fedora If you are using Fedora, to install the [MangoHud](https://src.fedoraproject.org/rpms/mangohud) package, execute: ``` sudo dnf install mangohud ``` ### Solus If you are using Solus, to install [MangoHud](https://dev.getsol.us/source/mangohud/) simply execute: ``` sudo eopkg it mangohud ``` ### openSUSE If you run openSUSE Leap or Tumbleweed you can get Mangohud from the official repositories. There are two packages, [mangohud](https://software.opensuse.org/package/mangohud) for 64bit and [mangohud-32bit](https://software.opensuse.org/package/mangohud-32bit) for 32bit application support. To have Mangohud working for both 32bit and 64bit applications you need to install both packages even on a 64bit operating system. ``` sudo zypper in mangohud mangohud-32bit ``` Leap doesn't seem to have the 32bit package. Leap 15.2 ``` sudo zypper addrepo -f https://download.opensuse.org/repositories/games:tools/openSUSE_Leap_15.2/games:tools.repo sudo zypper install mangohud ``` Leap 15.3 ``` sudo zypper addrepo -f https://download.opensuse.org/repositories/games:tools/openSUSE_Leap_15.3/games:tools.repo sudo zypper install mangohud ``` ### Flatpak If you are using Flatpaks, you will have to add the [Flathub repository](https://flatpak.org/setup/) for your specific distribution, and then, to install it, execute: For flatpak: ``` flatpak install org.freedesktop.Platform.VulkanLayer.MangoHud ``` To enable MangoHud for all Steam games: ``` flatpak override --user --env=MANGOHUD=1 com.valvesoftware.Steam ``` ## Normal usage --- To enable the MangoHud overlay layer for Vulkan and OpenGL, run : `mangohud /path/to/app` For Lutris games, go to the System options in Lutris (make sure that advanced options are enabled) and add this to the `Command prefix` setting: `mangohud` For Steam games, you can add this as a launch option: `mangohud %command%` Or alternatively, add `MANGOHUD=1` to your shell profile (Vulkan only). ## OpenGL OpenGL games may also need `dlsym` hooking, which is now enabled by default. Set the `MANGOHUD_DLSYM` env to `0` to disable like `MANGOHUD_DLSYM=0 %command%` for Steam. Some Linux native OpenGL games overrides LD_PRELOAD and stops MangoHud from working. You can sometimes fix this by editing LD_PRELOAD in the start script `LD_PRELOAD=/path/to/mangohud/lib/` ## gamescope To enable mangohud with gamescope you need to install mangoapp. `gamescope --mangoapp -- %command%` Using normal mangohud with gamescope is not supported. ## Hud configuration MangoHud comes with a config file which can be used to set configuration options globally or per application. Usually it is installed as `/usr/share/doc/mangohud/MangoHud.conf.example` or [get a copy from here](https://raw.githubusercontent.com/flightlessmango/MangoHud/master/data/MangoHud.conf). The priorities of different config files are: 1. `/path/to/application/dir/MangoHud.conf` 2. Per-application configuration in ~/.config/MangoHud: 1. `~/.config/MangoHud/.conf` for native applications, where `` is the case sensitive name of the executable 2. `~/.config/MangoHud/wine-.conf` for wine/proton apps, where `` is the case sensitive name of the executable without the `.exe` ending 3. `~/.config/MangoHud/MangoHud.conf` Example: For Overwatch, this would be `wine-Overwatch.conf` (even though the executable you run from Lutris is `Battle.net.exe`, the actual game executable name is `Overwatch.exe`). If you start the game from the terminal with MangoHud enabled (for example by starting Lutris from the terminal), MangoHud will print the config file names it is looking for. You can find an example config in /usr/share/doc/mangohud [GOverlay](https://github.com/benjamimgois/goverlay) is a GUI application that can be used to manage the config --- ### Environment Variables You can also customize the hud by using the `MANGOHUD_CONFIG` environment variable while separating different options with a comma. This takes priority over any config file. You can also specify configuration file with `MANGOHUD_CONFIGFILE=/path/to/config` for applications whose names are hard to guess (java, python etc). You can also specify presets file with `MANGOHUD_PRESETSFILE=/path/to/config`. This is especially useful when running mangohud in a sandbox such as flatpak. You can also specify custom hud libraries for OpenGL using `MANGOHUD_OPENGL_LIBS=/path/to/libMangoHud_opengl.so`. This is useful for testing MangoHud without modifying the installation on your system. A partial list of parameters are below. See the config file for a complete list. Parameters that are enabled by default have to be explicitly disabled. These (currently) are `fps`, `frame_timing`, `cpu_stats` (cpu load), `gpu_stats` (gpu load), and each can be disabled by setting the corresponding variable to 0 (e.g., fps=0). | Variable | Description | |------------------------------------|---------------------------------------------------------------------------------------| | `af` | Anisotropic filtering level. Improves sharpness of textures viewed at an angle `0`-`16` | | `alpha` | Set the opacity of all text and frametime graph `0.0`-`1.0` | | `arch` | Show if the application is 32- or 64-bit | | `autostart_log=` | Starts the log after X seconds from mangohud init | | `background_alpha` | Set the opacity of the background `0.0`-`1.0` | | `battery_color` | Change the battery text color | | `battery_icon` | Display battery icon instead of percent | | `battery_watt` | Display wattage for the battery option | | `battery_time` | Display remaining time for battery option | | `battery` | Display current battery percent and energy consumption | | `benchmark_percentiles` | Configure which framerate percentiles are shown in the logging summary. Default is `97,AVG,1,0.1` | | `bicubic` | Force bicubic filtering | | `blacklist` | Add a program to the blacklist. e.g `blacklist=vkcube,WatchDogs2.exe` | | `cellpadding_y` | Set the vertical cellpadding, default is `-0.085` | | `control=` | Sets up a unix socket with a specific name that can be connected to with mangohud-control.
I.e. `control=mangohud` or `control=mangohud-%p` (`%p` will be replaced by process id) | | `core_load_change` | Change the colors of cpu core loads, uses the same data from `cpu_load_value` and `cpu_load_change` | | `core_load` | Display load & frequency per core | | `core_type` | Display CPU core type per core. For Intel, it shows which cores are performance and efficient cores, for ARM it shows core codenames like A52, A53, A76, etc... | | `core_bars` | Change the display of `core_load` from numbers to vertical bars | | `cpu_load_change` | Change the color of the CPU load depending on load | | `cpu_load_color` | Set the colors for the gpu load change low, medium and high. e.g `cpu_load_color=0000FF,00FFFF,FF00FF` | | `cpu_load_value` | Set the values for medium and high load e.g `cpu_load_value=50,90` | | `cpu_mhz` | Show the CPUs current MHz | | `cpu_power`
`gpu_power` | Display CPU/GPU draw in watts | | `cpu_temp`
`gpu_temp`
`gpu_junction_temp`
`gpu_mem_temp` | Display current CPU/GPU temperature | | `cpu_custom_temp_sensor` | Use custom hwmon sensor for cpu temperature. e.g `cpu_custom_temp_sensor=cpuss0_2,temp3_input`.| | `cpu_text`
`gpu_text` | Override CPU and GPU text. `gpu_text` is a list in case of multiple GPUs | | `cpu_efficiency` | Display CPU efficiency in frames per joule | | `custom_text_center` | Display a custom text centered useful for a header e.g `custom_text_center=FlightLessMango Benchmarks` | | `custom_text` | Display a custom text e.g `custom_text=Fsync enabled` | | `debug` | Shows the graph of gamescope app frametimes and latency (only on gamescope obviously) | | `device_battery_icon` | Display wirless device battery icon. | | `device_battery` | Display wireless device battery percent. Currently supported arguments `gamepad` and `mouse` e.g `device_battery=gamepad,mouse` | | `display_server` | Display the current display session (e.g. X11 or wayland) | | `dynamic_frame_timing` | This changes frame_timing y-axis to correspond with the current maximum and minimum frametime instead of being a static 0-50 | | `engine_short_names` | Display a short version of the used engine (e.g. `OGL` instead of `OpenGL`) | | `engine_version` | Display OpenGL or vulkan and vulkan-based render engine's version | | `exec` | Display output of bash command in next column, e.g. `custom_text=/home` , `exec=df -h /home \| tail -n 1`. Only works with `legacy_layout=0` | | `exec_name` | Display current exec name | | `fan` | Shows the Steam Deck fan rpm | | `fcat` | Enables frame capture analysis | | `fcat_overlay_width=` | Sets the width of fcat. Default is `24` | | `fcat_screen_edge=` | Decides the edge fcat is displayed on. A value between `1` and `4` | | `font_file_text` | Change text font. Otherwise `font_file` is used | | `font_file` | Change default font (set location to .TTF/.OTF file) | | `font_glyph_ranges` | Specify extra font glyph ranges, comma separated: `korean`, `chinese`, `chinese_simplified`, `japanese`, `cyrillic`, `thai`, `vietnamese`, `latin_ext_a`, `latin_ext_b`. If you experience crashes or text is just squares, reduce font size or glyph ranges | | `font_scale=` | Set global font scale. Default is `1.0` | | `font_scale_media_player` | Change size of media player text relative to `font_size` | | `font_size=` | Customizable font size. Default is `24` | | `font_size_secondary=` | Customizable font size for secondary metrics. Default is `0.55 * font_size`, except if `no_small_font` is set, in which case the default value is `font_size` | | `font_size_text=` | Customizable font size for other text like media metadata. Default is `24` | | `fps_color_change` | Change the FPS text color depepending on the FPS value | | `fps_color=` | Choose the colors that the fps changes to when `fps_color_change` is enabled. Corresponds with fps_value. Default is `b22222,fdfd09,39f900` | | `fps_limit_method` | If FPS limiter should wait before or after presenting a frame. Choose `late` (default) for the lowest latency or `early` for the smoothest frametimes | | `fps_limit` | Limit the apps framerate. Comma-separated list of one or more FPS values. `0` means unlimited | | `fps_only` | Show FPS only. ***Not meant to be used with other display params*** | | `fps_sampling_period=` | Time interval between two sampling points for gathering the FPS in milliseconds. Default is `500` | | `fps_value` | Choose the break points where `fps_color_change` changes colors between. E.g `60,144`, default is `30,60` | | `fps_metrics` | Takes a list of decimal values or the value avg, e.g `avg,0.001` | | `reset_fps_metrics` | Reset fps metrics keybind, default is `Shift_R+F9` | | `fps_text` | Display custom text for engine name in front of FPS | | `frame_count` | Display frame count | | `frametime` | Display frametime next to FPS text | | `frame_timing_detailed` | Display frame timing in a more detailed chart | | `fsr` | Display the status of FSR (only works in gamescope) | | `hdr` | Display the status of HDR (only works in gamescope) | | `refresh_rate` | Display the current refresh rate (only works in gamescope) | | `full` | Enable most of the toggleable parameters (currently excludes `histogram`) | | `gamemode` | Show if GameMode is on | | `gpu_color`
`cpu_color`
`vram_color`
`ram_color`
`io_color`
`engine_color`
`frametime_color`
`background_color`
`text_color`
`media_player_color`
`network_color` | Change default colors: `gpu_color=RRGGBB` | | `gpu_core_clock`
`gpu_mem_clock`| Display GPU core/memory frequency | | `gpu_fan` | GPU fan in RPM, except NVIDIA where it is a percentage | | `gpu_load_change` | Change the color of the GPU load depending on load | | `gpu_load_color` | Set the colors for the gpu load change low,medium and high. e.g `gpu_load_color=0000FF,00FFFF,FF00FF` | | `gpu_load_value` | Set the values for medium and high load e.g `gpu_load_value=50,90` | | `gpu_name` | Display GPU name from pci.ids | | `gpu_voltage` | Display GPU voltage | | `gpu_list` | List GPUs to display `gpu_list=0,1` | | `gpu_efficiency` | Display GPU efficiency in frames per joule | | `gpu_power_limit` | Display GPU power limit | | `hide_fsr_sharpness` | Hides the sharpness info for the `fsr` option (only available in gamescope) | | `histogram` | Change FPS graph to histogram | | `horizontal` | Display Mangohud in a horizontal position | | `horizontal_separator_color` | Set the colors for the horizontal separators (horizontal layout only) | | `horizontal_stretch` | Stretches the background to the screens width in `horizontal` mode | | `hud_compact` | Display compact version of MangoHud | | `hud_no_margin` | Remove margins around MangoHud | | `io_read`
`io_write` | Show non-cached IO read/write, in MiB/s | | `log_duration` | Set amount of time the logging will run for (in seconds) | | `log_interval` | Change the default log interval in milliseconds. Default is `0` | | `log_versioning` | Adds more headers and information such as versioning to the log. This format is not supported on flightlessmango.com (yet) | | `media_player_format` | Format media player metadata. Add extra text etc. Semi-colon breaks to new line. Defaults to `{title};{artist};{album}` | | `media_player_name` | Force media player DBus service name without the `org.mpris.MediaPlayer2` part, like `spotify`, `vlc`, `audacious` or `cantata`. If none is set, MangoHud tries to switch between currently playing players | | `media_player` | Show media player metadata | | `no_display` | Hide the HUD by default | | `no_small_font` | Use primary font size for smaller text like units | | `offset_x` `offset_y` | HUD position offsets | | `output_file` | Set location and name of the log file | | `output_folder` | Set location of the output files (Required for logging) | | `pci_dev` | Select GPU device in multi-gpu setups | | `permit_upload` | Allow uploading of logs to Flightlessmango.com | | `picmip` | Mip-map LoD bias. Negative values will increase texture sharpness (and aliasing). Positive values will increase texture blurriness `-16`-`16` | | `position=` | Location of the HUD: `top-left` (default), `top-right`, `middle-left`, `middle-right`, `bottom-left`, `bottom-right`, `top-center`, `bottom-center` | | `preset=` | Comma separated list of one or more presets. Default is `-1,0,1,2,3,4`. Available presets:
`0` (No Hud)
`1` (FPS Only)
`2` (Horizontal)
`3` (Extended)
`4` (Detailed)
User defined presets can be created by using a [presets.conf](data/presets.conf) file in `~/.config/MangoHud/`. | | `procmem`
`procmem_shared`, `procmem_virt`| Displays process' memory usage: resident, shared and/or virtual. `procmem` (resident) also toggles others off if disabled | | `proc_vram` | Display process' VRAM usage | | `ram`
`vram` | Display system RAM/VRAM usage | | `ram_temp` | Display RAM temperature (only supports DDR5 with `spd5118` driver) | | `read_cfg` | Add to MANGOHUD_CONFIG as first parameter to also load config file. Otherwise only `MANGOHUD_CONFIG` parameters are used | | `reload_cfg=` | Change keybind for reloading the config. Default = `Shift_L+F4` | | `resolution` | Display the current resolution | | `retro` | Disable linear texture filtering. Makes textures look blocky | | `round_corners` | Change the amount of roundness of the corners have e.g `round_corners=10.0` | | `show_fps_limit` | Display the current FPS limit | | `swap` | Display swap space usage next to system RAM usage | | `table_columns` | Set the number of table columns for ImGui, defaults to 3 | | `temp_fahrenheit` | Show temperature in Fahrenheit | | `text_outline` | Draw an outline around text for better readability. Enabled by default. | | `text_outline_color=` | Set the color of `text_outline`. Default = `000000` | | `text_outline_thickness=` | Set the thickness of `text_outline`. Default = `1.5` | | `throttling_status` | Show if GPU is throttling based on Power, current, temp or "other" (Only shows if throttling is currently happening). Currently disabled by default for Nvidia as it causes lag on 3000 series | | `throttling_status_graph` | Same as `throttling_status` but displays throttling in the frametime graph and only power and temp throttling | | `time`
`time_format=%T` | Display local time. See [std::put_time](https://en.cppreference.com/w/cpp/io/manip/put_time) for formatting help. NOTE: Sometimes apps may set `TZ` (timezone) environment variable to UTC/GMT | | `time_no_label` | Remove the label before time | | `toggle_fps_limit` | Cycle between FPS limits (needs at least two values set with `fps_limit`). Defaults to `Shift_L+F1` | | `toggle_preset` | Cycle between Presets. Defaults to `Shift_R+F10` | | `toggle_hud=`
`toggle_logging=` | Modifiable toggle hotkeys. Default are `Shift_R+F12` and `Shift_L+F2`, respectively | | `toggle_hud_position` | Toggle MangoHud position. Default is `R_Shift+F11` | | `trilinear` | Force trilinear filtering | | `upload_log` | Change keybind for uploading log | | `upload_logs` | Enables automatic uploads of logs to flightlessmango.com | | `version` | Show current MangoHud version | | `vkbasalt` | Show if vkBasalt is on | | `vsync`
`gl_vsync` | Set Vsync for OpenGL or Vulkan | | `vulkan_present_mode=` | Override Vulkan [present mode](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPresentModeKHR.html) using specified mode name (takes precedence over `vsync=`) | | `vulkan_driver` | Display used Vulkan driver (radv/amdgpu-pro/amdvlk) | | `width=`
`height=` | Customizable HUD dimensions (in pixels) | | `wine_color` | Change color of the wine/proton text | | `wine` | Show current Wine or Proton version in use | | `winesync` | Show wine sync method in use | | `present_mode` | Shows current vulkan [present mode](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPresentModeKHR.html) or vsync status in opengl | | `network` | Show network interfaces tx and rx kb/s. You can specify interface with `network=eth0` | | `fex_stats` | Show FEX-Emu statistics. Default = `status+apptype+hotthreads+jitload+sigbus+smc+softfloat` | | `ftrace` | Display information about trace events reported through ftrace | | `flip_efficiency` | Flips CPU and GPU efficiency to joules per frame | Example: `MANGOHUD_CONFIG=cpu_temp,gpu_temp,position=top-right,height=500,font_size=32` Because comma is also used as option delimiter and needs to be escaped for values with a backslash, you can use `+` like `MANGOHUD_CONFIG=fps_limit=60+30+0` instead. *Note: Width and Height are set automatically based on the font_size, but can be overridden.* *Note: RAPL is currently used for Intel and AMD Zen CPUs to show power draw with `cpu_power` which may be unreadable for non-root users due to [vulnerability](https://platypusattack.com/). The corresponding `energy_uj` file has to be readable by corresponding user, e.g. by running `chmod o+r /sys/class/powercap/intel-rapl\:0/energy_uj` as root, else the power shown will be **0 W**, though having the file readable may potentially be a security vulnerability persisting until system reboots.* *Note: The [zenpower3](https://git.exozy.me/a/zenpower3) or [zenergy](https://github.com/boukehaarsma23/zenergy) kernel driver must be installed to show the power draw of Ryzen CPUs.* ## Vsync ### OpenGL Vsync - `-1` = Adaptive sync - `0` = Off - `1` = On - `n` = Sync to refresh rate / n. ### Vulkan Vsync - `0` = Adaptive VSync (FIFO_RELAXED_KHR) - `1` = Off (IMMEDIATE_KHR) - `2` = Mailbox (VSync with uncapped FPS) (MAILBOX_KHR) - `3` = On (FIFO_KHR) Not all vulkan vsync options may be supported on your device, you can check what your device supports here [vulkan.gpuinfo.org](https://vulkan.gpuinfo.org/listsurfacepresentmodes.php?platform=linux) ## Keybindings - `Shift_L+F2` : Toggle Logging - `Shift_L+F4` : Reload Config - `Shift_R+F12` : Toggle Hud - `Shift_R+F9` : Reset FPS metrics ## Workarounds Options starting with "gl_*" are for OpenGL. - `gl_size_query = viewport` : Specify what to use for getting display size. Options are "viewport", "scissorbox" or disabled. Defaults to using glXQueryDrawable. - `gl_bind_framebuffer = 0..N` : (Re)bind given framebuffer before MangoHud gets drawn. Helps with Crusader Kings III. - `gl_dont_flip = 1` : Don't swap origin if using GL_UPPER_LEFT. Helps with Ryujinx. ## FPS logging You must set a valid path for `output_folder` in your configuration to store logs in. When you toggle logging (default keybind is `Shift_L+F2`), a file is created with the game name plus a date & timestamp in your `output_folder`. Log files can be visualized with two different tools: online and locally. ### Online visualization: FlightlessMango.com Log files can be (batch) uploaded to [FlightlessMango.com](https://flightlessmango.com/games/user_benchmarks), which will then take care of creating a frametime graph and a summary with 1% min / average framerate / 97th percentile in a table form and a horizontal bar chart form. Notes: - Uploaded benchmarks are public: you can share them with anyone by simply giving them the link. - Benchmark filenames are used as legend in the produced tables and graphs, they can be renamed after the upload. ![Gif illustrating the log uploading process](assets/log_upload_example.gif) ### Local visualization: `mangoplot` `mangoplot` is a plotting script that is shipped with `MangoHud`: on a given folder, it takes each log file, makes a 1D heatmap of its framerates, then stacks the heats maps vertically to form a 2D graph for easy visual comparison between benchmarks. Example output: ![Overwatch 2 windows 11 vs linux](assets/Overwatch2-w11-vs-linux.svg) Overwatch 2, 5950X + 5700XT, low graphics preset, FHD, 50% render scale ## Metrics support by GPU vendor/driver
Nvidia AMD Intel Discrete Intel Integrated Panfrost/Panthor driver
i915 xe i915/xe
Usage% 🟢 🟢 🟢 🟢 🟢 🟢
Temperature 🟢 🟢 🟢 🟢 🔴 🟢
Junction Temperature 🔴 🟢 🔴 🔴 🔴 🔴
Memory Temperature 🔴 🟢 🔴 🟢 🔴 🔴
Process VRAM 🟢 🟢 🟢 🟢 🟢 🟢
System VRAM 🟢 🟢 🔴 🔴 🔴 🔴
Total VRAM 🟢 🟢 🔴 🔴 🔴 🔴
Memory Clock 🟢 🟢 🔴 🔴 🔴 🔴
Core Clock 🟢 🟢 🟢 🟢 🟢 🟢
Power Usage 🟢 🟢 🟢 🟢 🔴 🔴
Throttling Status 🟢 🟢 🟢 🟢 🟢 🔴
Fan Speed 🟢 🟢 🟢 🟢 🔴 🔴
Voltage 🔴 🟢 🟢 🟢 🔴 🔴
#### Intel notes - GPU temperature for `i915` requires **linux 6.13+** - Fan speed for `i915` requires **linux 6.12+** - GPU temperature and vram temperature for `xe` requires **linux 6.15+** - Fan speed for `xe` requires **linux 6.16+** - GPU usage and memory usage shows usage of current process, not total system usage (it's an issue on intel's side) - https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/14153 - https://gitlab.freedesktop.org/drm/xe/kernel/-/issues/4861 - Integrated Intel GPUs are **limited** due to lack of hwmon interface (it's an issue on intel's side, [i915 source](https://github.com/torvalds/linux/blob/5fc31936081919a8572a3d644f3fbb258038f337/drivers/gpu/drm/i915/i915_hwmon.c#L914-L916), [xe source](https://github.com/torvalds/linux/blob/5fc31936081919a8572a3d644f3fbb258038f337/drivers/gpu/drm/xe/xe_hwmon.c#L824-L826)) #### Panfrost and Panthor notes - GPU usage requires `echo N | sudo tee /sys/class/drm/renderD*/device/profiling` - Where N is a number, 1 for panfrost and 3 for panthor. ================================================ FILE: bin/gen_enum_to_str.py ================================================ # Copyright © 2017 Intel Corporation # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # 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 OR COPYRIGHT HOLDERS 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. """Create enum to string functions for vulkan using vk.xml.""" import argparse import functools import os import re import textwrap import xml.etree.ElementTree as et from mako.template import Template from vk_extensions import Extension, filter_api, get_all_required COPYRIGHT = textwrap.dedent(u"""\ * Copyright © 2017 Intel Corporation * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * 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 OR COPYRIGHT HOLDERS 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.""") C_TEMPLATE = Template(textwrap.dedent(u"""\ /* Autogenerated file -- do not edit * generated by ${file} * ${copyright} */ #include #include #include #include "../src/mesa/util/macros.h" #include "vk_enum_to_str.h" % for enum in enums: % if enum.guard: #ifdef ${enum.guard} % endif const char * vk_${enum.name[2:]}_to_str(${enum.name} input) { switch((int64_t)input) { % for v in sorted(enum.values.keys()): case ${v}: return "${enum.values[v]}"; % endfor case ${enum.max_enum_name}: return "${enum.max_enum_name}"; default: return "Unknown ${enum.name} value."; } } % if enum.guard: #endif % endif %endfor % for enum in bitmasks: % if enum.guard: #ifdef ${enum.guard} % endif const char * vk_${enum.name[2:]}_to_str(${enum.name} input) { switch((int64_t)input) { % for v in sorted(enum.values.keys()): case ${v}: return "${enum.values[v]}"; % endfor default: return "Unknown ${enum.name} value."; } } % if enum.guard: #endif % endif %endfor size_t vk_structure_type_size(const struct VkBaseInStructure *item) { switch((int)item->sType) { % for struct in structs: % if struct.extension is not None and struct.extension.define is not None: #ifdef ${struct.extension.define} case ${struct.stype}: return sizeof(${struct.name}); #endif % else: case ${struct.stype}: return sizeof(${struct.name}); % endif %endfor case VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO: return sizeof(VkLayerInstanceCreateInfo); case VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO: return sizeof(VkLayerDeviceCreateInfo); default: UNREACHABLE("Undefined struct type."); } } const char * vk_ObjectType_to_ObjectName(VkObjectType type) { switch((int)type) { % for object_type in sorted(object_types[0].enum_to_name.keys()): case ${object_type}: return "${object_types[0].enum_to_name[object_type]}"; % endfor default: return "Unknown VkObjectType value."; } } """)) H_TEMPLATE = Template(textwrap.dedent(u"""\ /* Autogenerated file -- do not edit * generated by ${file} * ${copyright} */ #ifndef MESA_VK_ENUM_TO_STR_H #define MESA_VK_ENUM_TO_STR_H #include #ifdef __cplusplus extern "C" { #endif % for enum in enums: % if enum.guard: #ifdef ${enum.guard} % endif const char * vk_${enum.name[2:]}_to_str(${enum.name} input); % if enum.guard: #endif % endif % endfor % for enum in bitmasks: % if enum.guard: #ifdef ${enum.guard} % endif const char * vk_${enum.name[2:]}_to_str(${enum.name} input); % if enum.guard: #endif % endif % endfor size_t vk_structure_type_size(const struct VkBaseInStructure *item); const char * vk_ObjectType_to_ObjectName(VkObjectType type); #ifdef __cplusplus } /* extern "C" */ #endif #endif """)) H_DEFINE_TEMPLATE = Template(textwrap.dedent(u"""\ /* Autogenerated file -- do not edit * generated by ${file} * ${copyright} */ #ifndef MESA_VK_ENUM_DEFINES_H #define MESA_VK_ENUM_DEFINES_H #include #ifdef __cplusplus extern "C" { #endif % for ext in extensions: #define _${ext.name}_number (${ext.number}) % endfor % for enum in bitmasks: % if enum.bitwidth > 32: <% continue %> % endif % if enum.guard: #ifdef ${enum.guard} % endif #define ${enum.all_bits_name()} ${hex(enum.all_bits_value())}u % if enum.guard: #endif % endif % endfor % for enum in bitmasks: % if enum.bitwidth < 64: <% continue %> % endif /* Redefine bitmask values of ${enum.name} */ % if enum.guard: #ifdef ${enum.guard} % endif % for n, v in enum.name_to_value.items(): #define ${n} (${hex(v)}ULL) % endfor % if enum.guard: #endif % endif % endfor static inline VkFormatFeatureFlags vk_format_features2_to_features(VkFormatFeatureFlags2 features2) { return features2 & VK_ALL_FORMAT_FEATURE_FLAG_BITS; } #ifdef __cplusplus } /* extern "C" */ #endif #endif """)) class NamedFactory(object): """Factory for creating enums.""" def __init__(self, type_): self.registry = {} self.type = type_ def __call__(self, name, **kwargs): try: return self.registry[name] except KeyError: n = self.registry[name] = self.type(name, **kwargs) return n def get(self, name): return self.registry.get(name) class VkExtension(object): """Simple struct-like class representing extensions""" def __init__(self, name, number=None, define=None): self.name = name self.number = number self.define = define def CamelCase_to_SHOUT_CASE(s): return (s[:1] + re.sub(r'(? len(name): self.values[value] = name # Now that the value has been fully added, resolve aliases, if any. if name in self.name_to_alias_list: for alias in self.name_to_alias_list[name]: self.add_value(alias, value) del self.name_to_alias_list[name] def add_value_from_xml(self, elem, extension=None): self.extension = extension if 'value' in elem.attrib: self.add_value(elem.attrib['name'], value=int(elem.attrib['value'], base=0)) elif 'bitpos' in elem.attrib: self.add_value(elem.attrib['name'], value=(1 << int(elem.attrib['bitpos'], base=0))) elif 'alias' in elem.attrib: self.add_value(elem.attrib['name'], alias=elem.attrib['alias']) else: error = 'dir' in elem.attrib and elem.attrib['dir'] == '-' if 'extnumber' in elem.attrib: extnum = int(elem.attrib['extnumber']) else: extnum = extension.number self.add_value(elem.attrib['name'], extnum=extnum, offset=int(elem.attrib['offset']), error=error) def set_guard(self, g): self.guard = g class VkChainStruct(object): """Simple struct-like class representing a single Vulkan struct identified with a VkStructureType""" def __init__(self, name, stype): self.name = name self.stype = stype self.extension = None def struct_get_stype(xml_node): for member in xml_node.findall('./member'): name = member.findall('./name') if len(name) > 0 and name[0].text == "sType": return member.get('values') return None class VkObjectType(object): """Simple struct-like class representing a single Vulkan object type""" def __init__(self, name): self.name = name self.enum_to_name = dict() def parse_xml(enum_factory, ext_factory, struct_factory, bitmask_factory, obj_type_factory, filename, beta): """Parse the XML file. Accumulate results into the factories. This parser is a memory efficient iterative XML parser that returns a list of VkEnum objects. """ xml = et.parse(filename) api = 'vulkan' required_types = get_all_required(xml, 'type', api, beta) for enum_type in xml.findall('./enums[@type="enum"]'): if not filter_api(enum_type, api): continue type_name = enum_type.attrib['name'] if not type_name in required_types: continue enum = enum_factory(type_name) for value in enum_type.findall('./enum'): if filter_api(value, api): enum.add_value_from_xml(value) # For bitmask we only add the Enum selected for convenience. for enum_type in xml.findall('./enums[@type="bitmask"]'): if not filter_api(enum_type, api): continue type_name = enum_type.attrib['name'] if not type_name in required_types: continue bitwidth = int(enum_type.attrib.get('bitwidth', 32)) enum = bitmask_factory(type_name, bitwidth=bitwidth) for value in enum_type.findall('./enum'): if filter_api(value, api): enum.add_value_from_xml(value) for feature in xml.findall('./feature'): if not api in feature.attrib['api'].split(','): continue for value in feature.findall('./require/enum[@extends]'): extends = value.attrib['extends'] enum = enum_factory.get(extends) if enum is not None: enum.add_value_from_xml(value) enum = bitmask_factory.get(extends) if enum is not None: enum.add_value_from_xml(value) for struct_type in xml.findall('./types/type[@category="struct"]'): if not filter_api(struct_type, api): continue name = struct_type.attrib['name'] if name not in required_types: continue stype = struct_get_stype(struct_type) if stype is not None: struct_factory(name, stype=stype) platform_define = {} for platform in xml.findall('./platforms/platform'): name = platform.attrib['name'] define = platform.attrib['protect'] platform_define[name] = define for ext_elem in xml.findall('./extensions/extension'): ext = Extension.from_xml(ext_elem) if api not in ext.supported: continue define = platform_define.get(ext.platform, None) extension = ext_factory(ext.name, number=ext.number, define=define) for req_elem in ext_elem.findall('./require'): if not filter_api(req_elem, api): continue for value in req_elem.findall('./enum[@extends]'): extends = value.attrib['extends'] enum = enum_factory.get(extends) if enum is not None: enum.add_value_from_xml(value, extension) enum = bitmask_factory.get(extends) if enum is not None: enum.add_value_from_xml(value, extension) for t in req_elem.findall('./type'): struct = struct_factory.get(t.attrib['name']) if struct is not None: struct.extension = extension if define: for value in ext_elem.findall('./require/type[@name]'): enum = enum_factory.get(value.attrib['name']) if enum is not None: enum.set_guard(define) enum = bitmask_factory.get(value.attrib['name']) if enum is not None: enum.set_guard(define) obj_type_enum = enum_factory.get("VkObjectType") obj_types = obj_type_factory("VkObjectType") for object_type in xml.findall('./types/type[@category="handle"]'): for object_name in object_type.findall('./name'): # Convert to int to avoid undefined enums enum = object_type.attrib['objtypeenum'] # Annoyingly, object types are hard to filter by API so just # look for whether or not we can find the enum name in the # VkObjectType enum. if enum not in obj_type_enum.name_to_value: continue enum_val = obj_type_enum.name_to_value[enum] obj_types.enum_to_name[enum_val] = object_name.text def main(): parser = argparse.ArgumentParser() parser.add_argument('--beta', required=True, help='Enable beta extensions.') parser.add_argument('--xml', required=True, help='Vulkan API XML files', action='append', dest='xml_files') parser.add_argument('--out-c', help='Output C file', required=True) parser.add_argument('--out-h', help='Output H file', required=True) parser.add_argument('--out-d', help='Output defines H file', required=True) args = parser.parse_args() enum_factory = NamedFactory(VkEnum) ext_factory = NamedFactory(VkExtension) struct_factory = NamedFactory(VkChainStruct) obj_type_factory = NamedFactory(VkObjectType) bitmask_factory = NamedFactory(VkEnum) for filename in args.xml_files: parse_xml(enum_factory, ext_factory, struct_factory, bitmask_factory, obj_type_factory, filename, args.beta) enums = sorted(enum_factory.registry.values(), key=lambda e: e.name) extensions = sorted(ext_factory.registry.values(), key=lambda e: e.name) structs = sorted(struct_factory.registry.values(), key=lambda e: e.name) bitmasks = sorted(bitmask_factory.registry.values(), key=lambda e: e.name) object_types = sorted(obj_type_factory.registry.values(), key=lambda e: e.name) for template, file_ in [(C_TEMPLATE, args.out_c), (H_TEMPLATE, args.out_h), (H_DEFINE_TEMPLATE, args.out_d)]: with open(file_, 'w', encoding='utf-8') as f: f.write(template.render( file=os.path.basename(__file__), enums=enums, extensions=extensions, structs=structs, bitmasks=bitmasks, object_types=object_types, copyright=COPYRIGHT)) if __name__ == '__main__': main() ================================================ FILE: bin/mangohud-setup.sh ================================================ #!/usr/bin/env bash OS_RELEASE_FILES=("/etc/os-release" "/usr/lib/os-release") XDG_CONFIG_HOME="${XDG_CONFIG_HOME:-$HOME/.config}" MANGOHUD_CONFIG_DIR="$XDG_CONFIG_HOME/MangoHud" SU_CMD=$(command -v sudo || command -v doas || echo) # doas requires a double dash if the command it runs will include any dashes, # so append a double dash to the command [[ $SU_CMD == *doas ]] && SU_CMD="$SU_CMD -- " # Correctly identify the os-release file. for os_release in ${OS_RELEASE_FILES[@]} ; do if [[ ! -e "${os_release}" ]]; then continue fi DISTRO=$(sed -rn 's/^ID(_LIKE)*=(.+)/\2/p' ${os_release} | sed 's/"//g') done mangohud_usage() { echo 'Accepted arguments: "install", "uninstall".' } mangohud_config() { mkdir -p "${MANGOHUD_CONFIG_DIR}" echo You can use the example configuration file from echo /usr/share/doc/mangohud/MangoHud.conf.example echo as a starting point by copying it to echo ${MANGOHUD_CONFIG_DIR}/MangoHud.conf echo } mangohud_uninstall() { [ "$UID" -eq 0 ] || exec $SU_CMD bash "$0" uninstall rm -rfv "/usr/lib/mangohud" rm -fv "/usr/share/vulkan/implicit_layer.d/MangoHud.x86.json" rm -fv "/usr/share/vulkan/implicit_layer.d/MangoHud.x86_64.json" rm -fv "/usr/share/vulkan/implicit_layer.d/MangoHud.json" rm -frv "/usr/share/doc/mangohud" rm -fv "/usr/share/man/man1/mangohud.1" rm -fv "/usr/bin/mangohud" rm -fv "/usr/bin/mangoplot" rm -fv "/usr/bin/mangohud.x86" } mangohud_install() { rm -rf "$HOME/.local/share/MangoHud/" rm -f "$HOME/.local/share/vulkan/implicit_layer.d/"{mangohud32.json,mangohud64.json} [ "$UID" -eq 0 ] || mangohud_config [ "$UID" -eq 0 ] || tar xf MangoHud-package.tar [ "$UID" -eq 0 ] || exec $SU_CMD bash "$0" install mangohud_uninstall DEFAULTLIB=lib32 for i in $DISTRO; do case $i in *arch*) DEFAULTLIB=lib64 ;; esac done echo DEFAULTLIB: $DEFAULTLIB /usr/bin/install -Dvm644 ./usr/lib/mangohud/lib64/libMangoHud.so /usr/lib/mangohud/lib64/libMangoHud.so /usr/bin/install -Dvm644 ./usr/lib/mangohud/lib32/libMangoHud.so /usr/lib/mangohud/lib32/libMangoHud.so /usr/bin/install -Dvm644 ./usr/lib/mangohud/lib64/libMangoHud_opengl.so /usr/lib/mangohud/lib64/libMangoHud_opengl.so /usr/bin/install -Dvm644 ./usr/lib/mangohud/lib32/libMangoHud_opengl.so /usr/lib/mangohud/lib32/libMangoHud_opengl.so /usr/bin/install -Dvm644 ./usr/lib/mangohud/lib64/libMangoHud_shim.so /usr/lib/mangohud/lib64/libMangoHud_shim.so /usr/bin/install -Dvm644 ./usr/lib/mangohud/lib32/libMangoHud_shim.so /usr/lib/mangohud/lib32/libMangoHud_shim.so /usr/bin/install -Dvm644 ./usr/share/vulkan/implicit_layer.d/MangoHud.x86_64.json /usr/share/vulkan/implicit_layer.d/MangoHud.x86_64.json /usr/bin/install -Dvm644 ./usr/share/vulkan/implicit_layer.d/MangoHud.x86.json /usr/share/vulkan/implicit_layer.d/MangoHud.x86.json /usr/bin/install -Dvm644 ./usr/share/man/man1/mangohud.1 /usr/share/man/man1/mangohud.1 /usr/bin/install -Dvm644 ./usr/share/doc/mangohud/MangoHud.conf.example /usr/share/doc/mangohud/MangoHud.conf.example /usr/bin/install -vm755 ./usr/bin/mangohud /usr/bin/mangohud /usr/bin/install -vm755 ./usr/bin/mangoplot /usr/bin/mangoplot ln -sv $DEFAULTLIB /usr/lib/mangohud/lib # FIXME get the triplet somehow ln -sv lib64 /usr/lib/mangohud/x86_64 ln -sv lib64 /usr/lib/mangohud/x86_64-linux-gnu ln -sv . /usr/lib/mangohud/lib64/x86_64 ln -sv . /usr/lib/mangohud/lib64/x86_64-linux-gnu ln -sv lib32 /usr/lib/mangohud/i686 ln -sv lib32 /usr/lib/mangohud/i386-linux-gnu ln -sv lib32 /usr/lib/mangohud/i686-linux-gnu mkdir -p /usr/lib/mangohud/tls ln -sv ../lib64 /usr/lib/mangohud/tls/x86_64 ln -sv ../lib32 /usr/lib/mangohud/tls/i686 # Some distros search in $prefix/x86_64-linux-gnu/tls/x86_64 etc instead if [ ! -e /usr/lib/mangohud/lib/i386-linux-gnu ]; then ln -sv ../lib32 /usr/lib/mangohud/lib/i386-linux-gnu fi if [ ! -e /usr/lib/mangohud/lib/i686-linux-gnu ]; then ln -sv ../lib32 /usr/lib/mangohud/lib/i686-linux-gnu fi if [ ! -e /usr/lib/mangohud/lib/x86_64-linux-gnu ]; then ln -sv ../lib64 /usr/lib/mangohud/lib/x86_64-linux-gnu fi # $LIB can be "lib/tls/x86_64"? ln -sv ../tls /usr/lib/mangohud/lib/tls # Let's not clean up because this can be destructive # rm -rf ./usr echo "MangoHud Installed" } for a in $@; do case $a in "install") mangohud_install;; "uninstall") mangohud_uninstall;; *) echo "Unrecognized command argument: $a" mangohud_usage esac done if [ -z $@ ]; then mangohud_usage fi ================================================ FILE: bin/mangohud.in ================================================ #!/bin/sh if [ "$#" -eq 0 ]; then programname=$(basename "$0") echo "ERROR: No program supplied" echo echo "Usage: $programname " exit 1 fi # Add exe names newline separated to the string to disable LD_PRELOAD DISABLE_LD_PRELOAD=" cs2.sh RiseOfTheTombRaider.sh " MANGOHUD_LIB_NAME="@ld_libdir_mangohud@libMangoHud_shim.so" if [ "$1" = "--version" ]; then echo @version@ exit 0 fi if [ "$1" = "--dlsym" ]; then # no-op, dlsym enabled by default shift fi # grab all arguments from command_line command_line="$*" # flag for disable_preload disable_preload=false # Check if the script name or any of the executables in DISABLE_LD_PRELOAD are in the command line for exe in $DISABLE_LD_PRELOAD; do if echo "$command_line" | grep -q "$exe"; then disable_preload=true break fi done if [ "$disable_preload" = true ]; then exec env MANGOHUD=1 "$@" else # Make sure we don't append mangohud lib multiple times # otherwise, this could cause issues with the steam runtime case ":${LD_PRELOAD-}:" in (*:$MANGOHUD_LIB_NAME:*) ;; (*) # Preload using the plain filenames of the libs, the dynamic linker will # figure out whether the 32 or 64 bit version should be used LD_PRELOAD="${LD_PRELOAD:+$LD_PRELOAD:}${MANGOHUD_LIB_NAME}" esac exec env MANGOHUD=1 LD_PRELOAD="${LD_PRELOAD}" "$@" fi ================================================ FILE: bin/mangoplot.py ================================================ #!/usr/bin/env python r""" Script to plot all the MangoHud benchmarks contained in a given folder. """ from pathlib import Path import argparse import csv from typing import List, Union import numpy as np import matplotlib.pyplot as plt from matplotlib.widgets import Cursor from matplotlib.colors import LinearSegmentedColormap from matplotlib.ticker import EngFormatter plt.rcParams['font.family'] = "Lato,serif" plt.rcParams['font.weight'] = "600" background_color = "#1A1C1D" legend_facecolor = "#585f63" legend_textcolor = "#cccbc9" text_color = "#e8e6e3" mango_color = "#BB770A" graphbox_linewidth = 1.5 mango_cmap = LinearSegmentedColormap.from_list("mango_heat", [background_color, mango_color]) def identity(val): r""" returns the value as-is """ return val def get_integer(val: str) -> int: r""" interprets the str 'val' as an integer and returns it """ if is_integer(val): return int(val) else: raise ValueError("Casting a non integer value: ", val) def is_integer(s: str) -> bool: r""" tests if 's' is an integer and returns a bool """ try: int(s) return True except ValueError: return False def get_float(val): r""" interprets the str 'val' as a float and returns it """ if is_float(val): return float(val) else: return float("nan") def is_float(s: str) -> bool: r""" tests if 's' is an float and returns a bool """ try: float(s) return True except ValueError: return False class Database: r""" A class that contains all the csv files within the folder that it is instanced with """ def __init__(self, data_folder_path=None, csv_separator=" ", filename_var_separator="|"): self.datafiles = [] self.result_names_col = None self.result_values_col = None self.sim_settings_names_col = None self.sim_settings_values_col = None if data_folder_path: self.load_from_folder( data_folder_path, csv_separator, filename_var_separator) def load_from_folder(self, data_folder_path, csv_separator=" ", filename_var_separator="|"): r""" Load all CSV files form the given folder """ filepaths = list(Path(data_folder_path).rglob("*.csv")) self.datafiles = [] N = len(filepaths) print(f"Loading {N} benchmark files") for filepath in filepaths: try: datafile = BenchmarkFile( str(filepath), csv_separator=csv_separator, filename_var_separator=filename_var_separator) self.datafiles.append(datafile) except Exception: pass self.datafiles.sort() class BenchmarkFile: r""" A class that represents a single CSV file, can load CSV files with arbitrary separators. It can return separately any column of the file and any mathematical combinations of its columns. """ def __init__(self, filepath="", filename_var_separator="|", csv_separator=" "): self.csv_separator = csv_separator self.filepath = Path(filepath) self.filename = self.filepath.name self.filename_var_separator = filename_var_separator self.variables = dict() self.skip_lines = None self.columns = [] self.column_name_to_index = dict() self._is_data_loaded = False if not self.filepath.is_file(): raise Exception("CSV file does not exist") self._read_column_names() def __lt__(self, other): stem = self.filename[:-4] # remove the trailing ".csv" other_stem = other.filename[:-4] if stem.startswith(other_stem): return False elif stem.startswith(other_stem): return True else: return stem < other_stem def set_variable(self, name, value): r""" Saves a variable within the datafile instance Note: it will not be saved to disk, it's just a helper method to attach variables to a given data file. """ self.variables[name] = value def get_variable(self, name): r""" Retrieves a saved variable in the instance """ return self.variables[name] def _read_column_names(self): r""" Read the first few lines of the benchmark file to look for the row taht contains the benchmark's column names i.e. "fps", "frametime", "cpu_load"... etc and save the columns names and their index Note: we decide that we found the right row by looking if it contains "fps" not the best approach, but it works TM """ with open(self.filepath) as open_file: reader = csv.reader(open_file, delimiter=self.csv_separator) found_fps_column = False for row_number, row_content in enumerate(reader): if row_number > 100: # did not find the row that starts with the # 'fps' column up until here. give up. break if "fps" in row_content: self.skip_lines = row_number + 1 found_fps_column = True for col, col_name in enumerate(row_content): if col_name in self.column_name_to_index: raise Exception("Two columns have the same name") self.column_name_to_index[col_name] = col if not found_fps_column: raise Exception("Not a benchmark file") def _load_data(self): r""" Load the benchmark data into memory. """ def extend_columns(new_column_num): current_row_num = 0 if self.columns: current_row_num = len(self.columns[0]) assert (all([len(column) == current_row_num for column in self.columns])) current_column_num = len(self.columns) if new_column_num >= current_column_num: self.columns += [["" for j in range(current_row_num)] for i in range(new_column_num - current_column_num)] # no need to load data if it's already loaded if self._is_data_loaded: return with open(self.filepath) as open_file: reader = csv.reader(open_file, delimiter=self.csv_separator) self._is_data_loaded = True for row_number, row_content in enumerate(reader): if row_number <= self.skip_lines: continue extend_columns(len(row_content)) for col, val in enumerate(row_content): self.columns[col].append(val) # Delete any eventual empty column if all([val == "" for val in self.columns[-1]]): del self.columns[-1] def get_column_names(self) -> List[str]: r""" Returns the list of columns names of the csv file. """ return list(self.column_name_to_index.keys()) def get(self, col: str, data_type: str = "float") \ -> Union[List[float], List[str], List[int], List[complex]]: r""" Returns the column `col`. Parameters ---------- col : str The desired column name to retrieve, or its index data_type : str "string", "integer" or "float", the type to cast the data to before returning it. Returns ------- A list of `data_type` containing the column `col` """ if not self._is_data_loaded: self._load_data() if len(self.columns) == 0: raise ValueError("Datafile empty, can't return any data") data_caster_dict = { "string": identity, "float": get_float, "integer": get_integer } if data_type not in data_caster_dict: raise ValueError("the given `data_type' doesn't match any " "known types. Which are `string', `integer', " "`float' or `complex'") if is_integer(col): # the column's index is given return [data_caster_dict[data_type](val) for val in self.columns[col]] if col in self.column_name_to_index: # a column name has been given return [data_caster_dict[data_type](val) for val in self.columns[self.column_name_to_index[col]]] raise Exception("Column {} does not exist".format(col)) if __name__ == '__main__': parser = argparse.ArgumentParser( description='Plot all the MangoHud benchmarks contained in a given folder.') parser.add_argument('folder', metavar='folder', nargs=1, help='path the a MangoHud benchmark folder') args = parser.parse_args() bench_folder_path = Path(args.folder[0]) if not bench_folder_path.is_dir(): print(f"The path '{bench_folder_path.absolute()}' " "does not point to an existing folder") exit(1) fps_subdivs = 1.0 # one division every fps_subdivs FPS y_labels = [] # bench files x_labels = [] # FPS subidivions database = Database(bench_folder_path, csv_separator=',') distributions = [] if len(database.datafiles) == 0: print(f"The folder \n {bench_folder_path.absolute()} \n" "contains no CSV file " "(make sure they have the .csv extension)") exit(1) for datafile in database.datafiles: bar_distribution = [] # sort array to get percentiles fps_array = np.sort(datafile.get("fps")) # save percentiles if len(fps_array) < 10000: print(f"'{datafile.filename}' simulation " "isn't long enough for precise statistics") datafile.set_variable("selected", False) continue # Save label only if this file has long enough simulation y_labels.append(datafile.filename[:-4]) datafile.set_variable("selected", True) # Save percentiles datafile.set_variable("0.1%", fps_array[int(float(len(fps_array))*0.001)]) datafile.set_variable("1%", fps_array[int(float(len(fps_array))*0.01)]) datafile.set_variable("50%", fps_array[int(float(len(fps_array))*0.5)]) datafile.set_variable("average fps", np.average(fps_array)) for frame_num, fps in enumerate(fps_array): if fps > 1000: print("FPS value above 1000, omitting outlier.") continue index = int(fps/fps_subdivs) for i in range(len(bar_distribution), index+1): bar_distribution.append(0) bar_distribution[index] += 1 distributions.append(bar_distribution) if not distributions: print("Nothing to plot, exiting.") exit(1) num_benchs = len(distributions) max_size = 0 for distrib in distributions: max_size = max(max_size, len(distrib)) for distrib in distributions: for i in range(len(distrib), max_size): distrib.append(0) for i in range(max_size): x_labels.append(str(fps_subdivs * i)) fig, ax = plt.subplots() # change color of the graph box to the same color as the text for spine in ['left', 'right', 'bottom', 'top']: ax.spines[spine].set_color(text_color) ax.spines[spine].set_linewidth(graphbox_linewidth) im = ax.imshow(distributions, aspect="auto", extent=[0, max_size*fps_subdivs, 0, num_benchs], cmap=mango_cmap) # draw thick line that separates each benchmark for i in range(len(y_labels)+1): ax.axhline(float(i), color=text_color, lw=graphbox_linewidth) i = 0 for datafile in database.datafiles: if datafile.get_variable("selected"): kwargs = dict(ymin=(num_benchs-i-1+0.15)/num_benchs, ymax=(num_benchs-i-0.15)/num_benchs, lw=3) ax.axvline(datafile.get_variable("0.1%"), color='#35260f', label=("0.1%" if i == 0 else None), **kwargs) ax.axvline(datafile.get_variable("1%"), color='#6E4503', label=("1%" if i == 0 else None), **kwargs) ax.axvline(datafile.get_variable("50%"), color='#0967BA', label=("50%" if i == 0 else None), **kwargs) ax.axvline(datafile.get_variable("average fps"), color='#003A6E', label=("Average" if i == 0 else None), **kwargs) i += 1 ax.tick_params(axis='y', colors=text_color) ax.tick_params(axis='x', colors=text_color) ax.set_yticks(np.arange(len(y_labels)-0.5, 0, -1), labels=y_labels) ax.grid(False) fig.set_facecolor(background_color) ax.ticklabel_format(axis='x', style='plain') formatter0 = EngFormatter(unit='FPS') ax.xaxis.set_major_formatter(formatter0) plt.tight_layout() plt.legend(facecolor=legend_facecolor, labelcolor=legend_textcolor) cursor = Cursor(ax, horizOn=False, color='#6c49abff', linewidth=4, useblit=True) plt.show() ================================================ FILE: bin/meson.build ================================================ # runtime dependencies for `mangoplot`: matplotlib and a GUI backed like PyQt5 install_data( 'mangoplot.py', install_dir: get_option('bindir'), rename: 'mangoplot', install_mode: 'rwxr-xr-x' ) ================================================ FILE: bin/vk_dispatch_table_gen.py ================================================ COPYRIGHT = """\ /* * Copyright 2020 Intel Corporation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sub license, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice (including the * next paragraph) shall be included in all copies or substantial portions * of the Software. * * 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 NON-INFRINGEMENT. * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS 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. */ """ import argparse import math import os from mako.template import Template # Mesa-local imports must be declared in meson variable # '{file_without_suffix}_depend_files'. from vk_entrypoints import get_entrypoints_from_xml # We generate a static hash table for entry point lookup # (vkGetProcAddress). We use a linear congruential generator for our hash # function and a power-of-two size table. The prime numbers are determined # experimentally. TEMPLATE_H = Template(COPYRIGHT + """\ /* This file generated from ${filename}, don't edit directly. */ #ifndef VK_DISPATCH_TABLE_H #define VK_DISPATCH_TABLE_H #include "vulkan/vulkan.h" #include "vk_extensions.h" /* Windows api conflict */ #ifdef _WIN32 #include #ifdef CreateSemaphore #undef CreateSemaphore #endif #ifdef CreateEvent #undef CreateEvent #endif #endif #ifdef __cplusplus extern "C" { #endif #ifdef _MSC_VER VKAPI_ATTR void VKAPI_CALL vk_entrypoint_stub(void); #endif <%def name="dispatch_table(entrypoints)"> % for e in entrypoints: % if e.alias: <% continue %> % endif % if e.guard is not None: #ifdef ${e.guard} % endif % if e.aliases: union { PFN_vk${e.name} ${e.name}; % for a in e.aliases: PFN_vk${a.name} ${a.name}; % endfor }; % else: PFN_vk${e.name} ${e.name}; % endif % if e.guard is not None: #else % if e.aliases: union { PFN_vkVoidFunction ${e.name}; % for a in e.aliases: PFN_vkVoidFunction ${a.name}; % endfor }; % else: PFN_vkVoidFunction ${e.name}; % endif #endif % endif % endfor <%def name="entrypoint_table(type, entrypoints)"> struct vk_${type}_entrypoint_table { % for e in entrypoints: % if e.guard is not None: #ifdef ${e.guard} % endif PFN_vk${e.name} ${e.name}; % if e.guard is not None: #else PFN_vkVoidFunction ${e.name}; # endif % endif % endfor }; struct vk_instance_dispatch_table { ${dispatch_table(instance_entrypoints)} }; struct vk_physical_device_dispatch_table { ${dispatch_table(physical_device_entrypoints)} }; struct vk_device_dispatch_table { ${dispatch_table(device_entrypoints)} }; struct vk_dispatch_table { union { struct { struct vk_instance_dispatch_table instance; struct vk_physical_device_dispatch_table physical_device; struct vk_device_dispatch_table device; }; struct { ${dispatch_table(instance_entrypoints)} ${dispatch_table(physical_device_entrypoints)} ${dispatch_table(device_entrypoints)} }; }; }; ${entrypoint_table('instance', instance_entrypoints)} ${entrypoint_table('physical_device', physical_device_entrypoints)} ${entrypoint_table('device', device_entrypoints)} <%def name="uncompacted_dispatch_table(entrypoints)"> % for e in entrypoints: % if e.alias: <% continue %> % endif % if e.guard is not None: #ifdef ${e.guard} % endif PFN_vk${e.name} ${e.name}; % if e.aliases: % for a in e.aliases: PFN_vk${a.name} ${a.name}; % endfor % endif % if e.guard is not None: #else PFN_vkVoidFunction ${e.name}; % if e.aliases: % for a in e.aliases: PFN_vkVoidFunction ${a.name}; % endfor % endif #endif % endif % endfor struct vk_instance_uncompacted_dispatch_table { ${uncompacted_dispatch_table(instance_entrypoints)} }; struct vk_physical_device_uncompacted_dispatch_table { ${uncompacted_dispatch_table(physical_device_entrypoints)} }; struct vk_device_uncompacted_dispatch_table { ${uncompacted_dispatch_table(device_entrypoints)} }; struct vk_uncompacted_dispatch_table { union { struct { struct vk_instance_uncompacted_dispatch_table instance; struct vk_physical_device_uncompacted_dispatch_table physical_device; struct vk_device_uncompacted_dispatch_table device; }; struct { ${uncompacted_dispatch_table(instance_entrypoints)} ${uncompacted_dispatch_table(physical_device_entrypoints)} ${uncompacted_dispatch_table(device_entrypoints)} }; }; }; void vk_instance_dispatch_table_load(struct vk_instance_dispatch_table *table, PFN_vkGetInstanceProcAddr gpa, VkInstance instance); void vk_physical_device_dispatch_table_load(struct vk_physical_device_dispatch_table *table, PFN_vkGetInstanceProcAddr gpa, VkInstance instance); void vk_device_dispatch_table_load(struct vk_device_dispatch_table *table, PFN_vkGetDeviceProcAddr gpa, VkDevice device); void vk_instance_uncompacted_dispatch_table_load(struct vk_instance_uncompacted_dispatch_table *table, PFN_vkGetInstanceProcAddr gpa, VkInstance instance); void vk_physical_device_uncompacted_dispatch_table_load(struct vk_physical_device_uncompacted_dispatch_table *table, PFN_vkGetInstanceProcAddr gpa, VkInstance instance); void vk_device_uncompacted_dispatch_table_load(struct vk_device_uncompacted_dispatch_table *table, PFN_vkGetDeviceProcAddr gpa, VkDevice device); void vk_instance_dispatch_table_from_entrypoints( struct vk_instance_dispatch_table *dispatch_table, const struct vk_instance_entrypoint_table *entrypoint_table, bool overwrite); void vk_physical_device_dispatch_table_from_entrypoints( struct vk_physical_device_dispatch_table *dispatch_table, const struct vk_physical_device_entrypoint_table *entrypoint_table, bool overwrite); void vk_device_dispatch_table_from_entrypoints( struct vk_device_dispatch_table *dispatch_table, const struct vk_device_entrypoint_table *entrypoint_table, bool overwrite); PFN_vkVoidFunction vk_instance_dispatch_table_get(const struct vk_instance_dispatch_table *table, const char *name); PFN_vkVoidFunction vk_physical_device_dispatch_table_get(const struct vk_physical_device_dispatch_table *table, const char *name); PFN_vkVoidFunction vk_device_dispatch_table_get(const struct vk_device_dispatch_table *table, const char *name); PFN_vkVoidFunction vk_instance_dispatch_table_get_if_supported( const struct vk_instance_dispatch_table *table, const char *name, uint32_t core_version, const struct vk_instance_extension_table *instance_exts); PFN_vkVoidFunction vk_physical_device_dispatch_table_get_if_supported( const struct vk_physical_device_dispatch_table *table, const char *name, uint32_t core_version, const struct vk_instance_extension_table *instance_exts); PFN_vkVoidFunction vk_device_dispatch_table_get_if_supported( const struct vk_device_dispatch_table *table, const char *name, uint32_t core_version, const struct vk_instance_extension_table *instance_exts, const struct vk_device_extension_table *device_exts); #ifdef __cplusplus } #endif #endif /* VK_DISPATCH_TABLE_H */ """) TEMPLATE_C = Template(COPYRIGHT + """\ /* This file generated from ${filename}, don't edit directly. */ #include "vk_dispatch_table.h" #include "../src/mesa/util/macros.h" #include "string.h" <%def name="load_dispatch_table(type, VkType, ProcAddr, entrypoints)"> void vk_${type}_dispatch_table_load(struct vk_${type}_dispatch_table *table, PFN_vk${ProcAddr} gpa, ${VkType} obj) { % if type != 'physical_device': table->${ProcAddr} = gpa; % endif % for e in entrypoints: % if e.alias or e.name == '${ProcAddr}': <% continue %> % endif % if e.guard is not None: #ifdef ${e.guard} % endif table->${e.name} = (PFN_vk${e.name}) gpa(obj, "vk${e.name}"); % for a in e.aliases: if (table->${e.name} == NULL) { table->${e.name} = (PFN_vk${e.name}) gpa(obj, "vk${a.name}"); } % endfor % if e.guard is not None: #endif % endif % endfor } ${load_dispatch_table('instance', 'VkInstance', 'GetInstanceProcAddr', instance_entrypoints)} ${load_dispatch_table('physical_device', 'VkInstance', 'GetInstanceProcAddr', physical_device_entrypoints)} ${load_dispatch_table('device', 'VkDevice', 'GetDeviceProcAddr', device_entrypoints)} <%def name="load_uncompacted_dispatch_table(type, VkType, ProcAddr, entrypoints)"> void vk_${type}_uncompacted_dispatch_table_load(struct vk_${type}_uncompacted_dispatch_table *table, PFN_vk${ProcAddr} gpa, ${VkType} obj) { % if type != 'physical_device': table->${ProcAddr} = gpa; % endif % for e in entrypoints: % if e.alias or e.name == '${ProcAddr}': <% continue %> % endif % if e.guard is not None: #ifdef ${e.guard} % endif table->${e.name} = (PFN_vk${e.name}) gpa(obj, "vk${e.name}"); % for a in e.aliases: table->${a.name} = (PFN_vk${a.name}) gpa(obj, "vk${a.name}"); if (table->${e.name} && !table->${a.name}) table->${a.name} = (PFN_vk${a.name}) table->${e.name}; if (!table->${e.name}) table->${e.name} = (PFN_vk${e.name}) table->${a.name}; % endfor % if e.guard is not None: #endif % endif % endfor } ${load_uncompacted_dispatch_table('instance', 'VkInstance', 'GetInstanceProcAddr', instance_entrypoints)} ${load_uncompacted_dispatch_table('physical_device', 'VkInstance', 'GetInstanceProcAddr', physical_device_entrypoints)} ${load_uncompacted_dispatch_table('device', 'VkDevice', 'GetDeviceProcAddr', device_entrypoints)} struct string_map_entry { uint32_t name; uint32_t hash; uint32_t num; }; /* We use a big string constant to avoid lots of reloctions from the entry * point table to lots of little strings. The entries in the entry point table * store the index into this big string. */ <%def name="strmap(strmap, prefix)"> static const char ${prefix}_strings[] = % for s in strmap.sorted_strings: "${s.string}\\0" % endfor ; static const struct string_map_entry ${prefix}_string_map_entries[] = { % for s in strmap.sorted_strings: { ${s.offset}, ${'{:0=#8x}'.format(s.hash)}, ${s.num} }, /* ${s.string} */ % endfor }; /* Hash table stats: * size ${len(strmap.sorted_strings)} entries * collisions entries: % for i in range(10): * ${i}${'+' if i == 9 else ' '} ${strmap.collisions[i]} % endfor */ #define none 0xffff static const uint16_t ${prefix}_string_map[${strmap.hash_size}] = { % for e in strmap.mapping: ${ '{:0=#6x}'.format(e) if e >= 0 else 'none' }, % endfor }; static int ${prefix}_string_map_lookup(const char *str) { static const uint32_t prime_factor = ${strmap.prime_factor}; static const uint32_t prime_step = ${strmap.prime_step}; const struct string_map_entry *e; uint32_t hash, h; uint16_t i; const char *p; hash = 0; for (p = str; *p; p++) hash = hash * prime_factor + *p; h = hash; while (1) { i = ${prefix}_string_map[h & ${strmap.hash_mask}]; if (i == none) return -1; e = &${prefix}_string_map_entries[i]; if (e->hash == hash && strcmp(str, ${prefix}_strings + e->name) == 0) return e->num; h += prime_step; } return -1; } ${strmap(instance_strmap, 'instance')} ${strmap(physical_device_strmap, 'physical_device')} ${strmap(device_strmap, 'device')} <% assert len(instance_entrypoints) < 2**8 %> static const uint8_t instance_compaction_table[] = { % for e in instance_entrypoints: ${e.disp_table_index}, % endfor }; <% assert len(physical_device_entrypoints) < 2**8 %> static const uint8_t physical_device_compaction_table[] = { % for e in physical_device_entrypoints: ${e.disp_table_index}, % endfor }; <% assert len(device_entrypoints) < 2**16 %> static const uint16_t device_compaction_table[] = { % for e in device_entrypoints: ${e.disp_table_index}, % endfor }; static bool vk_instance_entrypoint_is_enabled(int index, uint32_t core_version, const struct vk_instance_extension_table *instance) { switch (index) { % for e in instance_entrypoints: case ${e.entry_table_index}: /* ${e.name} */ % if e.core_version: return ${e.core_version.c_vk_version()} <= core_version; % elif e.extensions: % for ext in e.extensions: % if ext.type == 'instance': if (instance->${ext.name[3:]}) return true; % else: /* All device extensions are considered enabled at the instance level */ return true; % endif % endfor return false; % else: return true; % endif % endfor default: return false; } } /** Return true if the core version or extension in which the given entrypoint * is defined is enabled. * * If device is NULL, all device extensions are considered enabled. */ static bool vk_physical_device_entrypoint_is_enabled(int index, uint32_t core_version, const struct vk_instance_extension_table *instance) { switch (index) { % for e in physical_device_entrypoints: case ${e.entry_table_index}: /* ${e.name} */ % if e.core_version: return ${e.core_version.c_vk_version()} <= core_version; % elif e.extensions: % for ext in e.extensions: % if ext.type == 'instance': if (instance->${ext.name[3:]}) return true; % else: /* All device extensions are considered enabled at the instance level */ return true; % endif % endfor return false; % else: return true; % endif % endfor default: return false; } } /** Return true if the core version or extension in which the given entrypoint * is defined is enabled. * * If device is NULL, all device extensions are considered enabled. */ static bool vk_device_entrypoint_is_enabled(int index, uint32_t core_version, const struct vk_instance_extension_table *instance, const struct vk_device_extension_table *device) { switch (index) { % for e in device_entrypoints: case ${e.entry_table_index}: /* ${e.name} */ % if e.core_version: return ${e.core_version.c_vk_version()} <= core_version; % elif e.extensions: % for ext in e.extensions: % if ext.type == 'instance': if (instance->${ext.name[3:]}) return true; % else: if (!device || device->${ext.name[3:]}) return true; % endif % endfor return false; % else: return true; % endif % endfor default: return false; } } #ifdef _MSC_VER VKAPI_ATTR void VKAPI_CALL vk_entrypoint_stub(void) { UNREACHABLE("Entrypoint not implemented"); } static const void *get_function_target(const void *func) { const uint8_t *address = func; #ifdef _M_X64 /* Incremental linking may indirect through relative jump */ if (*address == 0xE9) { /* Compute JMP target if the first byte is opcode 0xE9 */ uint32_t offset; memcpy(&offset, address + 1, 4); address += offset + 5; } #else /* Add other platforms here if necessary */ #endif return address; } static bool vk_function_is_stub(PFN_vkVoidFunction func) { return (func == vk_entrypoint_stub) || (get_function_target(func) == get_function_target(vk_entrypoint_stub)); } #endif <%def name="dispatch_table_from_entrypoints(type)"> void vk_${type}_dispatch_table_from_entrypoints( struct vk_${type}_dispatch_table *dispatch_table, const struct vk_${type}_entrypoint_table *entrypoint_table, bool overwrite) { PFN_vkVoidFunction *disp = (PFN_vkVoidFunction *)dispatch_table; PFN_vkVoidFunction *entry = (PFN_vkVoidFunction *)entrypoint_table; if (overwrite) { memset(dispatch_table, 0, sizeof(*dispatch_table)); for (unsigned i = 0; i < ARRAY_SIZE(${type}_compaction_table); i++) { #ifdef _MSC_VER assert(entry[i] != NULL); if (vk_function_is_stub(entry[i])) #else if (entry[i] == NULL) #endif continue; unsigned disp_index = ${type}_compaction_table[i]; assert(disp[disp_index] == NULL); disp[disp_index] = entry[i]; } } else { for (unsigned i = 0; i < ARRAY_SIZE(${type}_compaction_table); i++) { unsigned disp_index = ${type}_compaction_table[i]; #ifdef _MSC_VER assert(entry[i] != NULL); if (disp[disp_index] == NULL && !vk_function_is_stub(entry[i])) #else if (disp[disp_index] == NULL) #endif disp[disp_index] = entry[i]; } } } ${dispatch_table_from_entrypoints('instance')} ${dispatch_table_from_entrypoints('physical_device')} ${dispatch_table_from_entrypoints('device')} <%def name="lookup_funcs(type)"> static PFN_vkVoidFunction vk_${type}_dispatch_table_get_for_entry_index( const struct vk_${type}_dispatch_table *table, int entry_index) { assert(entry_index >= 0); assert((size_t)entry_index < ARRAY_SIZE(${type}_compaction_table)); int disp_index = ${type}_compaction_table[entry_index]; return ((PFN_vkVoidFunction *)table)[disp_index]; } PFN_vkVoidFunction vk_${type}_dispatch_table_get( const struct vk_${type}_dispatch_table *table, const char *name) { int entry_index = ${type}_string_map_lookup(name); if (entry_index < 0) return NULL; return vk_${type}_dispatch_table_get_for_entry_index(table, entry_index); } ${lookup_funcs('instance')} ${lookup_funcs('physical_device')} ${lookup_funcs('device')} PFN_vkVoidFunction vk_instance_dispatch_table_get_if_supported( const struct vk_instance_dispatch_table *table, const char *name, uint32_t core_version, const struct vk_instance_extension_table *instance_exts) { int entry_index = instance_string_map_lookup(name); if (entry_index < 0) return NULL; if (!vk_instance_entrypoint_is_enabled(entry_index, core_version, instance_exts)) return NULL; return vk_instance_dispatch_table_get_for_entry_index(table, entry_index); } PFN_vkVoidFunction vk_physical_device_dispatch_table_get_if_supported( const struct vk_physical_device_dispatch_table *table, const char *name, uint32_t core_version, const struct vk_instance_extension_table *instance_exts) { int entry_index = physical_device_string_map_lookup(name); if (entry_index < 0) return NULL; if (!vk_physical_device_entrypoint_is_enabled(entry_index, core_version, instance_exts)) return NULL; return vk_physical_device_dispatch_table_get_for_entry_index(table, entry_index); } PFN_vkVoidFunction vk_device_dispatch_table_get_if_supported( const struct vk_device_dispatch_table *table, const char *name, uint32_t core_version, const struct vk_instance_extension_table *instance_exts, const struct vk_device_extension_table *device_exts) { int entry_index = device_string_map_lookup(name); if (entry_index < 0) return NULL; if (!vk_device_entrypoint_is_enabled(entry_index, core_version, instance_exts, device_exts)) return NULL; return vk_device_dispatch_table_get_for_entry_index(table, entry_index); } """) U32_MASK = 2**32 - 1 PRIME_FACTOR = 5024183 PRIME_STEP = 19 class StringIntMapEntry: def __init__(self, string, num): self.string = string self.num = num # Calculate the same hash value that we will calculate in C. h = 0 for c in string: h = ((h * PRIME_FACTOR) + ord(c)) & U32_MASK self.hash = h self.offset = None def round_to_pow2(x): return 2**int(math.ceil(math.log(x, 2))) class StringIntMap: def __init__(self): self.baked = False self.strings = {} def add_string(self, string, num): assert not self.baked assert string not in self.strings assert 0 <= num < 2**31 self.strings[string] = StringIntMapEntry(string, num) def bake(self): self.sorted_strings = \ sorted(self.strings.values(), key=lambda x: x.string) offset = 0 for entry in self.sorted_strings: entry.offset = offset offset += len(entry.string) + 1 # Save off some values that we'll need in C self.hash_size = round_to_pow2(len(self.strings) * 1.25) self.hash_mask = self.hash_size - 1 self.prime_factor = PRIME_FACTOR self.prime_step = PRIME_STEP self.mapping = [-1] * self.hash_size self.collisions = [0] * 10 for idx, s in enumerate(self.sorted_strings): level = 0 h = s.hash while self.mapping[h & self.hash_mask] >= 0: h = h + PRIME_STEP level = level + 1 self.collisions[min(level, 9)] += 1 self.mapping[h & self.hash_mask] = idx def main(): parser = argparse.ArgumentParser() parser.add_argument('--out-c', help='Output C file.') parser.add_argument('--out-h', help='Output H file.') parser.add_argument('--beta', required=True, help='Enable beta extensions.') parser.add_argument('--xml', help='Vulkan API XML file.', required=True, action='append', dest='xml_files') args = parser.parse_args() entrypoints = get_entrypoints_from_xml(args.xml_files, args.beta) device_entrypoints = [] physical_device_entrypoints = [] instance_entrypoints = [] for e in entrypoints: if e.is_device_entrypoint(): device_entrypoints.append(e) elif e.is_physical_device_entrypoint(): physical_device_entrypoints.append(e) else: instance_entrypoints.append(e) for i, e in enumerate(e for e in device_entrypoints if not e.alias): e.disp_table_index = i device_strmap = StringIntMap() for i, e in enumerate(device_entrypoints): e.entry_table_index = i device_strmap.add_string("vk" + e.name, e.entry_table_index) device_strmap.bake() for i, e in enumerate(e for e in physical_device_entrypoints if not e.alias): e.disp_table_index = i physical_device_strmap = StringIntMap() for i, e in enumerate(physical_device_entrypoints): e.entry_table_index = i physical_device_strmap.add_string("vk" + e.name, e.entry_table_index) physical_device_strmap.bake() for i, e in enumerate(e for e in instance_entrypoints if not e.alias): e.disp_table_index = i instance_strmap = StringIntMap() for i, e in enumerate(instance_entrypoints): e.entry_table_index = i instance_strmap.add_string("vk" + e.name, e.entry_table_index) instance_strmap.bake() # For outputting entrypoints.h we generate a anv_EntryPoint() prototype # per entry point. try: if args.out_h: with open(args.out_h, 'w', encoding='utf-8') as f: f.write(TEMPLATE_H.render(instance_entrypoints=instance_entrypoints, physical_device_entrypoints=physical_device_entrypoints, device_entrypoints=device_entrypoints, filename=os.path.basename(__file__))) if args.out_c: with open(args.out_c, 'w', encoding='utf-8') as f: f.write(TEMPLATE_C.render(instance_entrypoints=instance_entrypoints, physical_device_entrypoints=physical_device_entrypoints, device_entrypoints=device_entrypoints, instance_strmap=instance_strmap, physical_device_strmap=physical_device_strmap, device_strmap=device_strmap, filename=os.path.basename(__file__))) except Exception: # In the event there's an error, this imports some helpers from mako # to print a useful stack trace and prints it, then exits with # status 1, if python is run with debug; otherwise it just raises # the exception import sys from mako import exceptions print(exceptions.text_error_template().render(), file=sys.stderr) sys.exit(1) if __name__ == '__main__': main() ================================================ FILE: bin/vk_entrypoints.py ================================================ # Copyright 2020 Intel Corporation # # Permission is hereby granted, free of charge, to any person obtaining a # copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sub license, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice (including the # next paragraph) shall be included in all copies or substantial portions # of the Software. # # 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 NON-INFRINGEMENT. # IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS 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. import xml.etree.ElementTree as et from collections import OrderedDict, namedtuple # Mesa-local imports must be declared in meson variable # '{file_without_suffix}_depend_files'. from vk_extensions import get_all_required, filter_api EntrypointParam = namedtuple('EntrypointParam', 'type name decl len') class EntrypointBase: def __init__(self, name): assert name.startswith('vk') self.name = name[2:] self.alias = None self.guard = None self.entry_table_index = None # Extensions which require this entrypoint self.core_version = None self.extensions = [] def prefixed_name(self, prefix): return prefix + '_' + self.name class Entrypoint(EntrypointBase): def __init__(self, name, return_type, params): super(Entrypoint, self).__init__(name) self.return_type = return_type self.params = params self.guard = None self.aliases = [] self.disp_table_index = None def is_physical_device_entrypoint(self): return self.params[0].type in ('VkPhysicalDevice', ) def is_device_entrypoint(self): return self.params[0].type in ('VkDevice', 'VkCommandBuffer', 'VkQueue') def decl_params(self, start=0): return ', '.join(p.decl for p in self.params[start:]) def call_params(self, start=0): return ', '.join(p.name for p in self.params[start:]) class EntrypointAlias(EntrypointBase): def __init__(self, name, entrypoint): super(EntrypointAlias, self).__init__(name) self.alias = entrypoint entrypoint.aliases.append(self) def is_physical_device_entrypoint(self): return self.alias.is_physical_device_entrypoint() def is_device_entrypoint(self): return self.alias.is_device_entrypoint() def prefixed_name(self, prefix): return self.alias.prefixed_name(prefix) @property def params(self): return self.alias.params @property def return_type(self): return self.alias.return_type @property def disp_table_index(self): return self.alias.disp_table_index def decl_params(self): return self.alias.decl_params() def call_params(self): return self.alias.call_params() def get_entrypoints(doc, api, beta): """Extract the entry points from the registry.""" entrypoints = OrderedDict() required = get_all_required(doc, 'command', api, beta) for command in doc.findall('./commands/command'): if not filter_api(command, api): continue if 'alias' in command.attrib: name = command.attrib['name'] target = command.attrib['alias'] e = EntrypointAlias(name, entrypoints[target]) else: name = command.find('./proto/name').text ret_type = command.find('./proto/type').text params = [EntrypointParam( type=p.find('./type').text, name=p.find('./name').text, decl=''.join(p.itertext()), len=p.attrib.get('altlen', p.attrib.get('len', None)) ) for p in command.findall('./param') if filter_api(p, api)] # They really need to be unique e = Entrypoint(name, ret_type, params) if name not in required: continue r = required[name] e.core_version = r.core_version e.extensions = r.extensions e.guard = r.guard assert name not in entrypoints, name entrypoints[name] = e return entrypoints.values() def get_entrypoints_from_xml(xml_files, beta, api='vulkan'): entrypoints = [] for filename in xml_files: doc = et.parse(filename) entrypoints += get_entrypoints(doc, api, beta) return entrypoints ================================================ FILE: bin/vk_extensions.py ================================================ import copy import re import xml.etree.ElementTree as et def get_api_list(s): apis = [] for a in s.split(','): if a == 'disabled': continue assert a in ('vulkan', 'vulkansc') apis.append(a) return apis class Extension: def __init__(self, name, number, ext_version): self.name = name self.type = None self.number = number self.platform = None self.provisional = False self.ext_version = int(ext_version) self.supported = [] def from_xml(ext_elem): name = ext_elem.attrib['name'] number = int(ext_elem.attrib['number']) supported = get_api_list(ext_elem.attrib['supported']) if name == 'VK_ANDROID_native_buffer': assert not supported supported = ['vulkan'] if not supported: return Extension(name, number, 0) version = None for enum_elem in ext_elem.findall('.require/enum'): if enum_elem.attrib['name'].endswith('_SPEC_VERSION'): # Skip alias SPEC_VERSIONs if 'value' in enum_elem.attrib: assert version is None version = int(enum_elem.attrib['value']) assert version is not None ext = Extension(name, number, version) ext.type = ext_elem.attrib['type'] ext.platform = ext_elem.attrib.get('platform', None) ext.provisional = ext_elem.attrib.get('provisional', False) ext.supported = supported return ext def c_android_condition(self): # if it's an EXT or vendor extension, it's allowed if not self.name.startswith(ANDROID_EXTENSION_WHITELIST_PREFIXES): return 'true' allowed_version = ALLOWED_ANDROID_VERSION.get(self.name, None) if allowed_version is None: return 'false' return 'ANDROID_API_LEVEL >= %d' % (allowed_version) class ApiVersion: def __init__(self, version): self.version = version class VkVersion: def __init__(self, string): split = string.split('.') self.major = int(split[0]) self.minor = int(split[1]) if len(split) > 2: assert len(split) == 3 self.patch = int(split[2]) else: self.patch = None # Sanity check. The range bits are required by the definition of the # VK_MAKE_VERSION macro assert self.major < 1024 and self.minor < 1024 assert self.patch is None or self.patch < 4096 assert str(self) == string def __str__(self): ver_list = [str(self.major), str(self.minor)] if self.patch is not None: ver_list.append(str(self.patch)) return '.'.join(ver_list) def c_vk_version(self): ver_list = [str(self.major), str(self.minor), str(self.patch or 0)] return 'VK_MAKE_VERSION(' + ', '.join(ver_list) + ')' def __int_ver(self): # This is just an expansion of VK_VERSION return (self.major << 22) | (self.minor << 12) | (self.patch or 0) def __gt__(self, other): # If only one of them has a patch version, "ignore" it by making # other's patch version match self. if (self.patch is None) != (other.patch is None): other = copy.copy(other) other.patch = self.patch return self.__int_ver() > other.__int_ver() def __le__(self, other): return not self.__gt__(other) # Sort the extension list the way we expect: KHR, then EXT, then vendors # alphabetically. For digits, read them as a whole number sort that. # eg.: VK_KHR_8bit_storage < VK_KHR_16bit_storage < VK_EXT_acquire_xlib_display def extension_order(ext): order = [] for substring in re.split('(KHR|EXT|[0-9]+)', ext.name): if substring == 'KHR': order.append(1) if substring == 'EXT': order.append(2) elif substring.isdigit(): order.append(int(substring)) else: order.append(substring) return order def get_all_exts_from_xml(xml, api='vulkan'): """ Get a list of all Vulkan extensions. """ xml = et.parse(xml) extensions = [] for ext_elem in xml.findall('.extensions/extension'): ext = Extension.from_xml(ext_elem) if api in ext.supported: extensions.append(ext) return sorted(extensions, key=extension_order) def init_exts_from_xml(xml, extensions, platform_defines): """ Walk the Vulkan XML and fill out extra extension information. """ xml = et.parse(xml) ext_name_map = {} for ext in extensions: ext_name_map[ext.name] = ext # KHR_display is missing from the list. platform_defines.append('VK_USE_PLATFORM_DISPLAY_KHR') for platform in xml.findall('./platforms/platform'): platform_defines.append(platform.attrib['protect']) for ext_elem in xml.findall('.extensions/extension'): ext_name = ext_elem.attrib['name'] if ext_name not in ext_name_map: continue ext = ext_name_map[ext_name] ext.type = ext_elem.attrib['type'] class Requirements: def __init__(self, core_version=None): self.core_version = core_version self.extensions = [] self.guard = None def add_extension(self, ext): for e in self.extensions: if e == ext: return; assert e.name != ext.name self.extensions.append(ext) def filter_api(elem, api): if 'api' not in elem.attrib: return True return api in elem.attrib['api'].split(',') def get_alias(aliases, name): if name in aliases: # in case the spec registry adds an alias chain later return get_alias(aliases, aliases[name]) return name def get_all_required(xml, thing, api, beta): things = {} aliases = {} for struct in xml.findall('./types/type[@category="struct"][@alias]'): if not filter_api(struct, api): continue name = struct.attrib['name'] alias = struct.attrib['alias'] aliases[name] = alias for feature in xml.findall('./feature'): if not filter_api(feature, api): continue version = VkVersion(feature.attrib['number']) for t in feature.findall('./require/' + thing): name = t.attrib['name'] if name in things: assert things[name].core_version <= version else: things[name] = Requirements(core_version=version) for extension in xml.findall('.extensions/extension'): ext = Extension.from_xml(extension) if api not in ext.supported: continue if beta != 'true' and ext.provisional: continue for require in extension.findall('./require'): if not filter_api(require, api): continue for t in require.findall('./' + thing): name = get_alias(aliases, t.attrib['name']) r = things.setdefault(name, Requirements()) r.add_extension(ext) platform_defines = {} for platform in xml.findall('./platforms/platform'): name = platform.attrib['name'] define = platform.attrib['protect'] platform_defines[name] = define for req in things.values(): if req.core_version is not None: continue for ext in req.extensions: if ext.platform in platform_defines: req.guard = platform_defines[ext.platform] break return things # Mapping between extension name and the android version in which the extension # was whitelisted in Android CTS's dEQP-VK.info.device_extensions and # dEQP-VK.api.info.android.no_unknown_extensions, excluding those blocked by # android.graphics.cts.VulkanFeaturesTest#testVulkanBlockedExtensions. ALLOWED_ANDROID_VERSION = { # checkInstanceExtensions on oreo-cts-release "VK_KHR_surface": 26, "VK_KHR_display": 26, "VK_KHR_android_surface": 26, "VK_KHR_mir_surface": 26, "VK_KHR_wayland_surface": 26, "VK_KHR_win32_surface": 26, "VK_KHR_xcb_surface": 26, "VK_KHR_xlib_surface": 26, "VK_KHR_get_physical_device_properties2": 26, "VK_KHR_get_surface_capabilities2": 26, "VK_KHR_external_memory_capabilities": 26, "VK_KHR_external_semaphore_capabilities": 26, "VK_KHR_external_fence_capabilities": 26, # on pie-cts-release "VK_KHR_device_group_creation": 28, "VK_KHR_get_display_properties2": 28, # on android10-tests-release "VK_KHR_surface_protected_capabilities": 29, # on android13-tests-release "VK_KHR_portability_enumeration": 33, # checkDeviceExtensions on oreo-cts-release "VK_KHR_swapchain": 26, "VK_KHR_display_swapchain": 26, "VK_KHR_sampler_mirror_clamp_to_edge": 26, "VK_KHR_shader_draw_parameters": 26, "VK_KHR_maintenance1": 26, "VK_KHR_push_descriptor": 26, "VK_KHR_descriptor_update_template": 26, "VK_KHR_incremental_present": 26, "VK_KHR_shared_presentable_image": 26, "VK_KHR_storage_buffer_storage_class": 26, "VK_KHR_16bit_storage": 26, "VK_KHR_get_memory_requirements2": 26, "VK_KHR_external_memory": 26, "VK_KHR_external_memory_fd": 26, "VK_KHR_external_memory_win32": 26, "VK_KHR_external_semaphore": 26, "VK_KHR_external_semaphore_fd": 26, "VK_KHR_external_semaphore_win32": 26, "VK_KHR_external_fence": 26, "VK_KHR_external_fence_fd": 26, "VK_KHR_external_fence_win32": 26, "VK_KHR_win32_keyed_mutex": 26, "VK_KHR_dedicated_allocation": 26, "VK_KHR_variable_pointers": 26, "VK_KHR_relaxed_block_layout": 26, "VK_KHR_bind_memory2": 26, "VK_KHR_maintenance2": 26, "VK_KHR_image_format_list": 26, "VK_KHR_sampler_ycbcr_conversion": 26, # on oreo-mr1-cts-release "VK_KHR_draw_indirect_count": 27, # on pie-cts-release "VK_KHR_device_group": 28, "VK_KHR_multiview": 28, "VK_KHR_maintenance3": 28, "VK_KHR_create_renderpass2": 28, "VK_KHR_driver_properties": 28, # on android10-tests-release "VK_KHR_shader_float_controls": 29, "VK_KHR_shader_float16_int8": 29, "VK_KHR_8bit_storage": 29, "VK_KHR_depth_stencil_resolve": 29, "VK_KHR_swapchain_mutable_format": 29, "VK_KHR_shader_atomic_int64": 29, "VK_KHR_vulkan_memory_model": 29, "VK_KHR_swapchain_mutable_format": 29, "VK_KHR_uniform_buffer_standard_layout": 29, # on android11-tests-release "VK_KHR_imageless_framebuffer": 30, "VK_KHR_shader_subgroup_extended_types": 30, "VK_KHR_buffer_device_address": 30, "VK_KHR_separate_depth_stencil_layouts": 30, "VK_KHR_timeline_semaphore": 30, "VK_KHR_spirv_1_4": 30, "VK_KHR_pipeline_executable_properties": 30, "VK_KHR_shader_clock": 30, # blocked by testVulkanBlockedExtensions # "VK_KHR_performance_query": 30, "VK_KHR_shader_non_semantic_info": 30, "VK_KHR_copy_commands2": 30, # on android12-tests-release "VK_KHR_shader_terminate_invocation": 31, "VK_KHR_ray_tracing_pipeline": 31, "VK_KHR_ray_query": 31, "VK_KHR_acceleration_structure": 31, "VK_KHR_pipeline_library": 31, "VK_KHR_deferred_host_operations": 31, "VK_KHR_fragment_shading_rate": 31, "VK_KHR_zero_initialize_workgroup_memory": 31, "VK_KHR_workgroup_memory_explicit_layout": 31, "VK_KHR_synchronization2": 31, "VK_KHR_shader_integer_dot_product": 31, # on android13-tests-release "VK_KHR_dynamic_rendering": 33, "VK_KHR_format_feature_flags2": 33, "VK_KHR_global_priority": 33, "VK_KHR_maintenance4": 33, "VK_KHR_portability_subset": 33, "VK_KHR_present_id": 33, "VK_KHR_present_wait": 33, "VK_KHR_shader_subgroup_uniform_control_flow": 33, # on android14-tests-release "VK_KHR_fragment_shader_barycentric": 34, "VK_KHR_ray_tracing_maintenance1": 34, # blocked by testVulkanBlockedExtensions # "VK_KHR_video_decode_h264": 34, # "VK_KHR_video_decode_h265": 34, # "VK_KHR_video_decode_queue": 34, # "VK_KHR_video_queue": 34, # on android15-tests-release "VK_KHR_calibrated_timestamps": 35, "VK_KHR_cooperative_matrix": 35, "VK_KHR_dynamic_rendering_local_read": 35, "VK_KHR_index_type_uint8": 35, "VK_KHR_line_rasterization": 35, "VK_KHR_load_store_op_none": 35, "VK_KHR_maintenance5": 35, "VK_KHR_maintenance6": 35, "VK_KHR_map_memory2": 35, "VK_KHR_ray_tracing_position_fetch": 35, "VK_KHR_shader_expect_assume": 35, "VK_KHR_shader_float_controls2": 35, "VK_KHR_shader_maximal_reconvergence": 35, "VK_KHR_shader_quad_control": 35, "VK_KHR_shader_subgroup_rotate": 35, "VK_KHR_vertex_attribute_divisor": 35, # blocked by testVulkanBlockedExtensions # "VK_KHR_video_decode_av1": 35, # "VK_KHR_video_encode_h264": 35, # "VK_KHR_video_encode_h265": 35, # "VK_KHR_video_encode_queue": 35, # "VK_KHR_video_maintenance1": 35, # testNoUnknownExtensions on oreo-cts-release "VK_GOOGLE_display_timing": 26, # on pie-cts-release "VK_ANDROID_external_memory_android_hardware_buffer": 28, # on android11-tests-release "VK_GOOGLE_decorate_string": 30, "VK_GOOGLE_hlsl_functionality1": 30, # on android13-tests-release "VK_GOOGLE_surfaceless_query": 33, # on android15-tests-release "VK_ANDROID_external_format_resolve": 35, # this HAL extension is always allowed and will be filtered out by the # loader "VK_ANDROID_native_buffer": 26, } # Extensions with these prefixes are checked in Android CTS, and thus must be # whitelisted per the preceding dict. ANDROID_EXTENSION_WHITELIST_PREFIXES = ( "VK_KHX", "VK_KHR", "VK_GOOGLE", "VK_ANDROID" ) ================================================ FILE: bin/vk_extensions_gen.py ================================================ COPYRIGHT = """\ /* * Copyright 2017 Intel Corporation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sub license, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice (including the * next paragraph) shall be included in all copies or substantial portions * of the Software. * * 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 NON-INFRINGEMENT. * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS 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. */ """ import argparse from mako.template import Template # Mesa-local imports must be declared in meson variable # '{file_without_suffix}_depend_files'. from vk_extensions import get_all_exts_from_xml, init_exts_from_xml _TEMPLATE_H = Template(COPYRIGHT + """ #ifndef VK_EXTENSIONS_H #define VK_EXTENSIONS_H #include <%def name="extension_table(type, extensions)"> #define VK_${type.upper()}_EXTENSION_COUNT ${len(extensions)} extern const VkExtensionProperties vk_${type}_extensions[]; struct vk_${type}_extension_table { union { bool extensions[VK_${type.upper()}_EXTENSION_COUNT]; struct { %for ext in extensions: bool ${ext.name[3:]}; %endfor }; /* Workaround for "error: too many initializers for vk_${type}_extension_table" */ struct { %for ext in extensions: bool ${ext.name[3:]}; %endfor } table; }; }; ${extension_table('instance', instance_extensions)} ${extension_table('device', device_extensions)} struct vk_physical_device; #ifdef ANDROID_STRICT extern const struct vk_instance_extension_table vk_android_allowed_instance_extensions; extern const struct vk_device_extension_table vk_android_allowed_device_extensions; #endif #endif /* VK_EXTENSIONS_H */ """) _TEMPLATE_C = Template(COPYRIGHT + """ #include "vulkan/vulkan_core.h" #include "vk_extensions.h" const VkExtensionProperties vk_instance_extensions[VK_INSTANCE_EXTENSION_COUNT] = { %for ext in instance_extensions: {"${ext.name}", ${ext.ext_version}}, %endfor }; const VkExtensionProperties vk_device_extensions[VK_DEVICE_EXTENSION_COUNT] = { %for ext in device_extensions: {"${ext.name}", ${ext.ext_version}}, %endfor }; #ifdef ANDROID_STRICT const struct vk_instance_extension_table vk_android_allowed_instance_extensions = { %for ext in instance_extensions: .${ext.name[3:]} = ${ext.c_android_condition()}, %endfor }; const struct vk_device_extension_table vk_android_allowed_device_extensions = { %for ext in device_extensions: .${ext.name[3:]} = ${ext.c_android_condition()}, %endfor }; #endif """) def gen_extensions(xml_files, extensions, out_c, out_h): platform_defines = [] for filename in xml_files: init_exts_from_xml(filename, extensions, platform_defines) for ext in extensions: assert ext.type in {'instance', 'device'} template_env = { 'instance_extensions': [e for e in extensions if e.type == 'instance'], 'device_extensions': [e for e in extensions if e.type == 'device'], 'platform_defines': platform_defines, } if out_h: with open(out_h, 'w', encoding='utf-8') as f: f.write(_TEMPLATE_H.render(**template_env)) if out_c: with open(out_c, 'w', encoding='utf-8') as f: f.write(_TEMPLATE_C.render(**template_env)) def main(): parser = argparse.ArgumentParser() parser.add_argument('--out-c', help='Output C file.') parser.add_argument('--out-h', help='Output H file.') parser.add_argument('--xml', help='Vulkan API XML file.', required=True, action='append', dest='xml_files') args = parser.parse_args() extensions = [] for filename in args.xml_files: extensions += get_all_exts_from_xml(filename) gen_extensions(args.xml_files, extensions, args.out_c, args.out_h) if __name__ == '__main__': main() ================================================ FILE: build-source.sh ================================================ #!/bin/sh VERSION=$(git describe --tags --dirty) NAME=MangoHud-${VERSION} TAR_NAME=${NAME}-Source.tar.xz DFSG_TAR_NAME=${NAME}-Source-DFSG.tar.xz # remove existing files rm -rf sourcedir rm -rf ${NAME} rm -f ${TAR_NAME} rm -f ${DFSG_TAR_NAME} # create tarball with meson meson setup sourcedir meson dist --formats=xztar --include-subprojects --no-tests -C sourcedir mv sourcedir/meson-dist/*.tar.xz ${TAR_NAME} # create DFSG compliant version # unpack since tarball is compressed mkdir ${NAME} tar -xf ${TAR_NAME} --strip 1 -C ${NAME} # nvml.h is not DFSG compliant rm ${NAME}/include/nvml.h # minhook not needed rm -r ${NAME}/modules/minhook # spdlog from system rm -r ${NAME}/subprojects/spdlog-* # nlohmann_json from system rm -r ${NAME}/subprojects/nlohmann_json-* # remove some vulkan clutter rm -r ${NAME}/subprojects/Vulkan-Headers-*/cmake ${NAME}/subprojects/Vulkan-Headers-*/BUILD.gn # remove some dear imgui clutter rm -rf ${NAME}/subprojects/imgui-*/examples # compress new sources tar -cJf ${DFSG_TAR_NAME} ${NAME} # cleanup rm -r sourcedir rm -r ${NAME} ================================================ FILE: build-srt.sh ================================================ #!/usr/bin/env bash # Specialized build script for Steam Runtime SDK docker set -e IFS=" " read -ra debian_chroot < /etc/debian_chroot LOCAL_CC=${CC:-gcc-5} LOCAL_CXX=${CXX:-g++-5} RUNTIME=${RUNTIME:-${debian_chroot[1]}} SRT_VERSION=${SRT_VERSION:-${debian_chroot[2]}} VERSION=$(git describe --long --tags --always | sed 's/\([^-]*-g\)/r\1/;s/-/./g;s/^v//') dependencies() { if [[ ! -f build-srt/release/usr/lib/libMangoHud.so ]]; then install() { set +e for i in ${DEPS[@]}; do dpkg-query -s "$i" &> /dev/null if [[ $? == 1 ]]; then INSTALL="$INSTALL""$i " fi done if [[ ! -z "$INSTALL" ]]; then apt-get update apt-get -y install $INSTALL fi set -e } echo "# Checking Dependencies" DEPS=(${LOCAL_CC}-multilib ${LOCAL_CXX}-multilib unzip) install # use py3.5 with scout, otherwise hope python is new enough set +e which python3.5 >/dev/null if [ $? -eq 0 ]; then # py3.2 is weird ln -sf python3.5 /usr/bin/python3 fi set -e if [[ ! -f ./bin/get-pip.py ]]; then curl https://bootstrap.pypa.io/pip/3.5/get-pip.py -o bin/get-pip.py python3 ./bin/get-pip.py fi pip3 install 'meson>=0.54' mako if [[ ! -f /usr/include/NVCtrl/NVCtrl.h ]]; then curl -LO http://mirrors.kernel.org/ubuntu/pool/main/n/nvidia-settings/libxnvctrl0_440.64-0ubuntu1_amd64.deb curl -LO http://mirrors.kernel.org/ubuntu/pool/main/n/nvidia-settings/libxnvctrl-dev_440.64-0ubuntu1_amd64.deb dpkg -i libxnvctrl0_440.64-0ubuntu1_amd64.deb libxnvctrl-dev_440.64-0ubuntu1_amd64.deb fi # preinstalled 7.10.xxxx #if [[ ! -f /usr/local/bin/glslangValidator ]]; then # curl -LO https://github.com/KhronosGroup/glslang/releases/download/master-tot/glslang-master-linux-Release.zip # unzip glslang-master-linux-Release.zip bin/glslangValidator # /usr/bin/install -m755 bin/glslangValidator /usr/local/bin/ # rm bin/glslangValidator glslang-master-linux-Release.zip #fi fi } configure() { dependencies git submodule update --init if [[ ! -f "build-srt/meson64/build.ninja" ]]; then export CC="${LOCAL_CC}" export CXX="${LOCAL_CXX}" meson build-srt/meson64 --libdir lib/mangohud/lib --prefix /usr -Dappend_libdir_mangohud=false $@ ${CONFIGURE_OPTS} fi if [[ ! -f "build-srt/meson32/build.ninja" ]]; then export CC="${LOCAL_CC} -m32" export CXX="${LOCAL_CXX} -m32" export PKG_CONFIG_PATH="/usr/lib32/pkgconfig:/usr/lib/i386-linux-gnu/pkgconfig:/usr/lib/pkgconfig:${PKG_CONFIG_PATH_32}" meson build-srt/meson32 --libdir lib/mangohud/lib32 --prefix /usr -Dappend_libdir_mangohud=false $@ ${CONFIGURE_OPTS} fi } build() { if [[ ! -f "build-srt/meson64/build.ninja" || ! -f "build-srt/meson32/build.ninja" ]]; then configure $@ fi DESTDIR="$PWD/build-srt/release" ninja -C build-srt/meson32 install DESTDIR="$PWD/build-srt/release" ninja -C build-srt/meson64 install } package() { LIB="build-srt/release/usr/lib/mangohud/lib/libMangoHud.so" LIB32="build-srt/release/usr/lib/mangohud/lib32/libMangoHud.so" if [[ ! -f "$LIB" || "$LIB" -ot "build-srt/meson64/src/libMangoHud.so" ]]; then build fi tar --numeric-owner --owner=0 --group=0 \ -C build-srt/release -cvf "build-srt/MangoHud-package.tar" . } release() { rm build-srt/MangoHud-package.tar mkdir -p build-srt/MangoHud package cp --preserve=mode bin/mangohud-setup.sh build-srt/MangoHud/mangohud-setup.sh cp build-srt/MangoHud-package.tar build-srt/MangoHud/MangoHud-package.tar tar --numeric-owner --owner=0 --group=0 \ -C build-srt -czvf build-srt/MangoHud-${VERSION}_${RUNTIME}-${SRT_VERSION}.tar.gz MangoHud } clean() { rm -rf "build-srt/" } usage() { if test -z $1; then echo "Unrecognized command argument: $a" else echo "$0 requires one argument" fi echo -e "\nUsage: $0 \n" echo "Available commands:" echo -e "\tpull\t\tPull latest commits (code) from Git" echo -e "\tconfigure\tEnsures that dependencies are installed, updates git submodules, and generates files needed for building MangoHud. This is automatically run by the build command" echo -e "\tbuild\t\tIf needed runs configure and then builds (compiles) MangoHud" echo -e "\tpackage\t\tRuns build if needed and then builds a tar package from MangoHud" echo -e "\tclean\t\tRemoves build directory" echo -e "\trelease\t\tBuilds a MangoHud release tar package" } if [[ -z $@ ]]; then usage no-args fi while [ $# -gt 0 ]; do OPTS=() arg="$1" shift while [ $# -gt 0 ] ; do case $1 in -*) OPTS+=("$1") shift ;; *) break ;; esac; done echo -e "\e[1mCommand:\e[92m" $arg "\e[94m"${OPTS[@]}"\e[39m\e[0m" case $arg in "configure") configure ${OPTS[@]};; "build") build ${OPTS[@]};; "package") package;; "clean") clean;; "release") release;; *) usage esac done ================================================ FILE: build-with-srt-docker.sh ================================================ #!/usr/bin/env bash # Usage example: $0 master soldier 0.20210618.0 set -u if [ $# -eq 2 ]; then echo Specify runtime version too exit 1 fi SRCDIR=$PWD BRANCH="${1:-master}" # soldier 0.20210618.0 or newer # scout 0.20210630.0 or newer RUNTIME="${2:-soldier}" VERSION="${3:-0.20210618.0}" IMAGE="steamrt_${RUNTIME}_${VERSION}_amd64:mango-${RUNTIME}" BASEURL="https://repo.steampowered.com/steamrt-images-${RUNTIME}/snapshots/${VERSION}" CACHEDIR="./cache/steamrt-images-${RUNTIME}/snapshots/${VERSION}" mkdir -p "${CACHEDIR}" echo -e "\e[1mBuilding branch \e[92m${BRANCH}\e[39m using \e[92m${RUNTIME}:${VERSION}\e[39m runtime\e[0m" if ! docker inspect --type=image ${IMAGE} 2>&1 >/dev/null ; then rm -fr ./cache/empty set -e mkdir -p ./cache/empty sed "s/%RUNTIME%/${RUNTIME}/g" steamrt.Dockerfile.in > ./cache/steamrt.Dockerfile wget -P "${CACHEDIR}" -c ${BASEURL}/com.valvesoftware.SteamRuntime.Sdk-amd64,i386-${RUNTIME}-sysroot.tar.gz cp --reflink=always "${CACHEDIR}/com.valvesoftware.SteamRuntime.Sdk-amd64,i386-${RUNTIME}-sysroot.tar.gz" ./cache/empty/ docker build -f ./cache/steamrt.Dockerfile -t ${IMAGE} ./cache/empty fi docker run --entrypoint=/bin/sh --rm -i -v "${SRCDIR}/srt-output:/output" ${IMAGE} << EOF export RUNTIME=${RUNTIME} export SRT_VERSION=${VERSION} git clone git://github.com/flightlessmango/MangoHud.git . --branch ${BRANCH} --recurse-submodules --progress ./build-srt.sh clean build package release cp -v build-srt/MangoHud*tar.gz /output/ EOF ================================================ FILE: build.sh ================================================ #!/usr/bin/env bash set -e # Import the variables for dependencies source ./build_deps.sh OS_RELEASE_FILES=("/etc/os-release" "/usr/lib/os-release") XDG_DATA_HOME="${XDG_DATA_HOME:-$HOME/.local/share}" XDG_CONFIG_HOME="${XDG_CONFIG_HOME:-$HOME/.config}" CONFIG_DIR="$XDG_CONFIG_HOME/MangoHud" VERSION=$(git describe --long --tags --always | sed 's/\([^-]*-g\)/r\1/;s/-/./g;s/^v//') SU_CMD=$(command -v sudo || command -v doas || echo) MACHINE=$(uname -m || echo) # doas requires a double dash if the command it runs will include any dashes, # so append a double dash to the command [[ $SU_CMD == *doas ]] && SU_CMD="$SU_CMD -- " # Correctly identify the os-release file. for os_release in ${OS_RELEASE_FILES[@]} ; do if [[ ! -e "${os_release}" ]]; then continue fi DISTRO=$(sed -rn 's/^ID(_LIKE)*=(.+)/\L\2/p' ${os_release} | sed 's/"//g') done dependencies() { if [[ ! -f build/release/usr/lib/libMangoHud.so ]]; then missing_deps() { echo "# Missing dependencies:$INSTALL" read -rp "Do you wish the script to install these packages? [y/N]" PERMISSION case "$PERMISSION" in "y"|"Y") echo "Attempting to install missing packages"; sleep 0.5;; *) echo "Continuing with missing dependencies"; sleep 1;; esac } dep_install() { set +e for i in $(eval echo $DEPS); do $MANAGER_QUERY "$i" &> /dev/null if [[ $? == 1 ]]; then INSTALL="$INSTALL""$i " fi done if [[ ! -z "$INSTALL" ]]; then missing_deps if [[ "$PERMISSION" == "Y" || "$PERMISSION" == "y" ]]; then $SU_CMD $MANAGER_INSTALL $INSTALL fi fi set -e } for i in $DISTRO; do echo "# Checking dependencies for \"$i\"" case $i in *arch*|*manjaro*|*artix*|*SteamOS*) MANAGER_QUERY="pacman -Q" MANAGER_INSTALL="pacman -S" DEPS="{${DEPS_ARCH}}" dep_install break ;; *fedora*|*nobara*) MANAGER_QUERY="dnf list installed" MANAGER_INSTALL="dnf install" DEPS="{${DEPS_FEDORA}}" dep_install unset INSTALL DEPS="{glibc-devel.i686,libstdc++-devel.i686,libX11-devel.i686,wayland-devel.i686,libxkbcommon-devel.i686}" dep_install break ;; *debian*|*ubuntu*|*deepin*|*pop*) MANAGER_QUERY="dpkg-query -s" MANAGER_INSTALL="apt install" DEPS="{${DEPS_DEBIAN}}" if ! dpkg --print-foreign-architectures | grep i386 > /dev/null; then echo "i386 architecture is not enabled. adding it." $SU_CMD dpkg --add-architecture i386 $SU_CMD apt update fi dep_install if [[ ! -f /usr/local/bin/glslangValidator ]]; then wget https://github.com/KhronosGroup/glslang/releases/download/master-tot/glslang-master-linux-Release.zip unzip glslang-master-linux-Release.zip bin/glslangValidator $SU_CMD /usr/bin/install -m755 bin/glslangValidator /usr/local/bin/ rm bin/glslangValidator glslang-master-linux-Release.zip fi break ;; *suse*) echo "You may have to enable packman repository for some extra packages: ${DEPS_SUSE_EXTRA}" echo "Leap: zypper ar -cfp 90 https://ftp.gwdg.de/pub/linux/misc/packman/suse/openSUSE_Leap_15.1/ packman" echo "Tumbleweed: zypper ar -cfp 90 http://ftp.gwdg.de/pub/linux/misc/packman/suse/openSUSE_Tumbleweed/ packman" MANAGER_QUERY="rpm -q" MANAGER_INSTALL="zypper install" DEPS="{${DEPS_SUSE},${DEPS_SUSE_EXTRA}}" dep_install if [[ $(pip3 show meson; echo $?) == 1 ]]; then $SU_CMD pip3 install 'meson>=0.54' fi break ;; *solus*) unset MANAGER_QUERY unset DEPS MANAGER_INSTALL="eopkg it" local packages=(${DEPS_SOLUS//,/ }) # eopkg doesn't emit exit codes properly, so use the python API to find if a package is installed. for package in ${packages[@]}; do python -c "import pisi.db; import sys; idb = pisi.db.installdb.InstallDB(); sys.exit(0 if idb.has_package(\"${package}\") else 1)" if [[ $? -ne 0 ]]; then INSTALL="${INSTALL}""${package} " fi done # likewise, ensure the whole system.devel component is satisfied python -c "import pisi.db; import sys; idb = pisi.db.installdb.InstallDB(); cdb = pisi.db.componentdb.ComponentDB(); mpkgs = [x for x in cdb.get_packages('system.devel') if not idb.has_package(x)]; sys.exit(0 if len(mpkgs) == 0 else 1)" if [[ $? -ne 0 ]]; then INSTALL="${INSTALL}""-c system.devel " fi dep_install break ;; *) echo "# Unable to find distro information!" echo "# Attempting to build regardless" esac done fi } configure() { dependencies git submodule update --init --depth 50 CONFIGURE_OPTS="-Dwerror=true" if [[ ! -f "build/meson64/build.ninja" ]]; then meson setup build/meson64 --libdir lib/mangohud/lib64 --prefix /usr -Dappend_libdir_mangohud=false $@ ${CONFIGURE_OPTS} fi if [[ ! -f "build/meson32/build.ninja" && "$MACHINE" = "x86_64" ]]; then export CC="gcc -m32" export CXX="g++ -m32" export PKG_CONFIG_PATH="/usr/lib32/pkgconfig:/usr/lib/i386-linux-gnu/pkgconfig:/usr/lib/pkgconfig:${PKG_CONFIG_PATH_32}" meson setup build/meson32 --libdir lib/mangohud/lib32 --prefix /usr -Dappend_libdir_mangohud=false $@ ${CONFIGURE_OPTS} fi } build() { if [[ ! -f "build/meson64/build.ninja" ]]; then configure $@ fi DESTDIR="$PWD/build/release" ninja -C build/meson64 install if [ "$MACHINE" = "x86_64" ]; then DESTDIR="$PWD/build/release" ninja -C build/meson32 install fi sed -i 's:/usr/\\$LIB:/usr/lib/mangohud/\\$LIB:g' "$PWD/build/release/usr/bin/mangohud" } package() { LIB="build/release/usr/lib/mangohud/lib64/libMangoHud.so" LIB32="build/release/usr/lib/mangohud/lib32/libMangoHud.so" if [[ ! -f "$LIB" || "$LIB" -ot "build/meson64/src/libMangoHud.so" ]]; then build fi tar --numeric-owner --owner=0 --group=0 \ -C build/release -cvf "build/MangoHud-package.tar" . } release() { rm build/MangoHud-package.tar mkdir -p build/MangoHud package cp --preserve=mode bin/mangohud-setup.sh build/MangoHud/mangohud-setup.sh cp build/MangoHud-package.tar build/MangoHud/MangoHud-package.tar tar --numeric-owner --owner=0 --group=0 \ -C build -czvf build/MangoHud-$VERSION.tar.gz MangoHud } uninstall() { [ "$UID" -eq 0 ] || exec $SU_CMD bash "$0" uninstall rm -rfv "/usr/lib/mangohud" rm -rfv "/usr/share/doc/mangohud" rm -fv "/usr/share/man/man1/mangohud.1" rm -fv "/usr/share/vulkan/implicit_layer.d/mangohud.json" rm -fv "/usr/share/vulkan/implicit_layer.d/MangoHud.json" rm -fv "/usr/share/vulkan/implicit_layer.d/MangoHud.x86.json" rm -fv "/usr/share/vulkan/implicit_layer.d/MangoHud.x86_64.json" rm -fv "/usr/bin/mangohud" rm -fv "/usr/bin/mangoplot" rm -fv "/usr/bin/mangohud.x86" } install() { rm -rf "$HOME/.local/share/MangoHud/" rm -f "$HOME/.local/share/vulkan/implicit_layer.d/"{mangohud32.json,mangohud64.json} [ "$UID" -eq 0 ] || mkdir -pv "${CONFIG_DIR}" [ "$UID" -eq 0 ] || build [ "$UID" -eq 0 ] || exec $SU_CMD bash "$0" install uninstall DEFAULTLIB=lib32 for i in $DISTRO; do case $i in *arch*) DEFAULTLIB=lib64 ;; esac done if [ "$MACHINE" != "x86_64" ]; then # Native libs DEFAULTLIB=lib64 fi echo DEFAULTLIB: $DEFAULTLIB /usr/bin/install -Dvm644 ./build/release/usr/lib/mangohud/lib64/libMangoHud.so /usr/lib/mangohud/lib64/libMangoHud.so /usr/bin/install -Dvm644 ./build/release/usr/lib/mangohud/lib64/libMangoHud_opengl.so /usr/lib/mangohud/lib64/libMangoHud_opengl.so /usr/bin/install -Dvm644 ./build/release/usr/lib/mangohud/lib64/libMangoHud_shim.so /usr/lib/mangohud/lib64/libMangoHud_shim.so if [ "$MACHINE" = "x86_64" ]; then /usr/bin/install -Dvm644 ./build/release/usr/lib/mangohud/lib32/libMangoHud.so /usr/lib/mangohud/lib32/libMangoHud.so /usr/bin/install -Dvm644 ./build/release/usr/lib/mangohud/lib32/libMangoHud_opengl.so /usr/lib/mangohud/lib32/libMangoHud_opengl.so /usr/bin/install -Dvm644 ./build/release/usr/lib/mangohud/lib32/libMangoHud_shim.so /usr/lib/mangohud/lib32/libMangoHud_shim.so fi /usr/bin/install -Dvm644 ./build/release/usr/share/vulkan/implicit_layer.d/MangoHud.x86_64.json /usr/share/vulkan/implicit_layer.d/MangoHud.x86_64.json /usr/bin/install -Dvm644 ./build/release/usr/share/vulkan/implicit_layer.d/MangoHud.x86.json /usr/share/vulkan/implicit_layer.d/MangoHud.x86.json /usr/bin/install -Dvm644 ./build/release/usr/share/man/man1/mangohud.1 /usr/share/man/man1/mangohud.1 /usr/bin/install -Dvm644 ./build/release/usr/share/doc/mangohud/MangoHud.conf.example /usr/share/doc/mangohud/MangoHud.conf.example /usr/bin/install -vm755 ./build/release/usr/bin/mangohud /usr/bin/mangohud /usr/bin/install -vm755 ./build/release/usr/bin/mangoplot /usr/bin/mangoplot ln -sv $DEFAULTLIB /usr/lib/mangohud/lib # FIXME get the triplet somehow ln -sv lib64 /usr/lib/mangohud/x86_64 ln -sv lib64 /usr/lib/mangohud/x86_64-linux-gnu ln -sv . /usr/lib/mangohud/lib64/x86_64 ln -sv . /usr/lib/mangohud/lib64/x86_64-linux-gnu ln -sv lib32 /usr/lib/mangohud/i686 ln -sv lib32 /usr/lib/mangohud/i386-linux-gnu ln -sv lib32 /usr/lib/mangohud/i686-linux-gnu mkdir -p /usr/lib/mangohud/tls ln -sv ../lib64 /usr/lib/mangohud/tls/x86_64 ln -sv ../lib32 /usr/lib/mangohud/tls/i686 # Some distros search in $prefix/x86_64-linux-gnu/tls/x86_64 etc instead if [ ! -e /usr/lib/mangohud/lib/i386-linux-gnu ]; then ln -sv ../lib32 /usr/lib/mangohud/lib/i386-linux-gnu fi if [ ! -e /usr/lib/mangohud/lib/i686-linux-gnu ]; then ln -sv ../lib32 /usr/lib/mangohud/lib/i686-linux-gnu fi if [ ! -e /usr/lib/mangohud/lib/x86_64-linux-gnu ]; then ln -sv ../lib64 /usr/lib/mangohud/lib/x86_64-linux-gnu fi # $LIB can be "lib/tls/x86_64"? ln -sv ../tls /usr/lib/mangohud/lib/tls #ln -sv lib64 /usr/lib/mangohud/aarch64-linux-gnu #ln -sv lib64 /usr/lib/mangohud/arm-linux-gnueabihf echo "MangoHud Installed" } reinstall() { build package install } clean() { rm -rf "build" rm -rf subprojects/*/ } usage() { if test -z $1; then echo "Unrecognized command argument: $arg" else echo "$0 requires one argument" fi echo -e "\nUsage: $0 \n" echo "Available commands:" echo -e "\tpull\t\tPull latest commits (code) from Git" echo -e "\tconfigure\tEnsures that dependencies are installed, updates git submodules, and generates files needed for building MangoHud. This is automatically run by the build command" echo -e "\tbuild\t\tIf needed runs configure and then builds (compiles) MangoHud" echo -e "\tpackage\t\tRuns build if needed and then builds a tar package from MangoHud" echo -e "\tinstall\t\tInstall MangoHud onto your system" echo -e "\treinstall\tRuns build, then package, and finally install" echo -e "\tclean\t\tRemoves build directory" echo -e "\tuninstall\tRemoves installed MangoHud files from your system" echo -e "\trelease\t\tBuilds a MangoHud release tar package" } if [[ -z $@ ]]; then usage no-args fi while [ $# -gt 0 ]; do OPTS=() arg="$1" shift while [ $# -gt 0 ] ; do case $1 in -*) OPTS+=("$1") shift ;; *) break ;; esac; done echo -e "\e[1mCommand:\e[92m" $arg "\e[94m"${OPTS[@]}"\e[39m\e[0m" case $arg in "pull") git pull ${OPTS[@]};; "configure") configure ${OPTS[@]};; "build") build ${OPTS[@]};; "build_dbg") build --buildtype=debug -Dglibcxx_asserts=true ${OPTS[@]};; "package") package;; "install") install;; "reinstall") reinstall;; "clean") clean;; "uninstall") uninstall;; "release") release;; *) usage esac done ================================================ FILE: build_deps.sh ================================================ DEPS_ARCH="gcc,meson,pkgconf,python-mako,glslang,libglvnd,lib32-libglvnd,libxnvctrl,libdrm,python-numpy,python-matplotlib,libxkbcommon,lib32-libxkbcommon" DEPS_FEDORA="meson,gcc,gcc-c++,libX11-devel,glslang,python3-mako,mesa-libGL-devel,libXNVCtrl-devel,dbus-devel,python3-numpy,python3-matplotlib,libstdc++-static,libstdc++-static.i686,libxkbcommon-devel,wayland-devel" DEPS_DEBIAN="gcc,g++,gcc-multilib,g++-multilib,ninja-build,meson,python3-mako,python3-setuptools,python3-wheel,pkg-config,mesa-common-dev,libx11-dev,libxnvctrl-dev,libdbus-1-dev,python3-numpy,python3-matplotlib,libxkbcommon-dev,libxkbcommon-dev:i386,libwayland-dev,libwayland-dev:i386" DEPS_SOLUS="mesalib-32bit-devel,glslang,libstdc++-32bit,glibc-32bit-devel,mako,numpy,matplotlib,libxkbcommon-devel" DEPS_SUSE="gcc-c++,gcc-c++-32bit,libpkgconf-devel,ninja,python3-pip,python3-Mako,libX11-devel,glslang-devel,glibc-devel,glibc-devel-32bit,libstdc++-devel,libstdc++-devel-32bit,Mesa-libGL-devel,dbus-1-devel,python-numpy,python-matplotlib,libxkbcommon-devel,libxkbcommon-devel-32bit,wayland-devel-32bit" DEPS_SUSE_EXTRA="libXNVCtrl-devel" ================================================ FILE: control/setup.cfg ================================================ [metadata] name = mangohud_control version = 0.0.1 author = Simon Hallsten author_email = flightlessmangoyt@gmail.com description = control interface for mangohud classifiers = Programming Language :: Python :: 3 License :: OSI Approved :: MIT License Operating System :: Linux [options] package_dir = = src packages = find: python_requires = >=3.6 [options.packages.find] where = src [options.entry_points] console_scripts = mangohud-control = control:main [pycodestyle] max-line-length = 160 ================================================ FILE: control/setup.py ================================================ import site import sys from setuptools import setup if __name__ == "__main__": setup() # See https://github.com/pypa/pip/issues/7953 site.ENABLE_USER_SITE = "--user" in sys.argv[1:] ================================================ FILE: control/src/control/__init__.py ================================================ #!/usr/bin/env python3 import os import socket import sys import select from select import EPOLLIN, EPOLLPRI, EPOLLERR import time from collections import namedtuple import argparse TIMEOUT = 1.0 # seconds VERSION_HEADER = bytearray('MangoHudControlVersion', 'utf-8') DEVICE_NAME_HEADER = bytearray('DeviceName', 'utf-8') MANGOHUD_VERSION_HEADER = bytearray('MangoHudVersion', 'utf-8') DEFAULT_SERVER_ADDRESS = "\0mangohud" class Connection: def __init__(self, path): # Create a Unix Domain socket and connect sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) try: sock.connect(path) except socket.error as msg: print(msg) sys.exit(1) self.sock = sock # initialize poll interface and register socket epoll = select.epoll() epoll.register(sock, EPOLLIN | EPOLLPRI | EPOLLERR) self.epoll = epoll def recv(self, timeout): ''' timeout as float in seconds returns: - None on error or disconnection - bytes() (empty) on timeout ''' events = self.epoll.poll(timeout) for ev in events: (fd, event) = ev if fd != self.sock.fileno(): continue # check for socket error if event & EPOLLERR: return None # EPOLLIN or EPOLLPRI, just read the message msg = self.sock.recv(4096) # socket disconnected if len(msg) == 0: return None return msg return bytes() def send(self, msg): self.sock.send(msg) class MsgParser: MSGBEGIN = bytes(':', 'utf-8')[0] MSGEND = bytes(';', 'utf-8')[0] MSGSEP = bytes('=', 'utf-8')[0] def __init__(self, conn): self.cmdpos = 0 self.parampos = 0 self.bufferpos = 0 self.reading_cmd = False self.reading_param = False self.buffer = None self.cmd = bytearray(4096) self.param = bytearray(4096) self.conn = conn def readCmd(self, ncmds, timeout=TIMEOUT): ''' returns: - None on error or disconnection - bytes() (empty) on timeout ''' parsed = [] remaining = timeout while remaining > 0 and ncmds > 0: now = time.monotonic() if self.buffer == None: self.buffer = self.conn.recv(remaining) self.bufferpos = 0 # disconnected or error if self.buffer == None: return None for i in range(self.bufferpos, len(self.buffer)): c = self.buffer[i] self.bufferpos += 1 if c == self.MSGBEGIN: self.cmdpos = 0 self.parampos = 0 self.reading_cmd = True self.reading_param = False elif c == self.MSGEND: if not self.reading_cmd: continue self.reading_cmd = False self.reading_param = False cmd = self.cmd[0:self.cmdpos] param = self.param[0:self.parampos] self.reading_cmd = False self.reading_param = False parsed.append((cmd, param)) ncmds -= 1 if ncmds == 0: break elif c == self.MSGSEP: if self.reading_cmd: self.reading_param = True else: if self.reading_param: self.param[self.parampos] = c self.parampos += 1 elif self.reading_cmd: self.cmd[self.cmdpos] = c self.cmdpos += 1 # if we read the entire buffer and didn't finish the command, # throw it away self.buffer = None # check if we have time for another iteration elapsed = time.monotonic() - now remaining = max(0, remaining - elapsed) # timeout return parsed def control(args): if args.socket: address = '\0' + args.socket else: address = DEFAULT_SERVER_ADDRESS conn = Connection(address) msgparser = MsgParser(conn) version = None name = None mangohud_version = None msgs = msgparser.readCmd(3) for m in msgs: cmd, param = m if cmd == VERSION_HEADER: version = int(param) elif cmd == DEVICE_NAME_HEADER: name = param.decode('utf-8') elif cmd == MANGOHUD_VERSION_HEADER: mangohud_version = param.decode('utf-8') if args.info: info = "Protocol Version: {}\n" info += "Device Name: {}\n" info += "MangoHud Version: {}" print(info.format(version, name, mangohud_version)) if args.cmd == 'toggle-logging': conn.send(bytearray(':logging;', 'utf-8')) elif args.cmd == 'start-logging': conn.send(bytearray(':logging=1;', 'utf-8')) elif args.cmd == 'stop-logging': conn.send(bytearray(':logging=0;', 'utf-8')) now = time.monotonic() while True: msg = str(conn.recv(3)) if "LoggingFinished" in msg: print("Logging has stopped") exit(0) elapsed = time.monotonic() - now if elapsed > 3: print("Stop logging timed out") exit(1) elif args.cmd == 'toggle-hud': conn.send(bytearray(':hud;', 'utf-8')) elif args.cmd == 'toggle-fcat': conn.send(bytearray(':fcat;', 'utf-8')) def main(): parser = argparse.ArgumentParser(description='MangoHud control client') parser.add_argument('--info', action='store_true', help='Print info from socket') parser.add_argument('--socket', '-s', type=str, help='Path to socket') commands = parser.add_subparsers(help='commands to run', dest='cmd') commands.add_parser('toggle-hud') commands.add_parser('toggle-logging') commands.add_parser('start-logging') commands.add_parser('stop-logging') commands.add_parser('toggle-fcat') args = parser.parse_args() control(args) if __name__ == '__main__': main() ================================================ FILE: data/MangoHud.conf ================================================ ### MangoHud configuration file ### Uncomment any options you wish to enable. Default options are left uncommented ### Use some_parameter=0 to disable a parameter (only works with on/off parameters) ### Everything below can be used / overridden with the environment variable MANGOHUD_CONFIG instead ################ INFORMATIONAL ################# ## prints possible options on stdout # help ################ PERFORMANCE ################# ### Limit the application FPS. Comma-separated list of one or more FPS values (e.g. 0,30,60). 0 means unlimited (unless VSynced) # fps_limit=0 ### early = wait before present, late = wait after present # fps_limit_method= ### Vulkan Present Mode. Overrides application present mode. Takes precedence over `vsync=`. # Present Modes: # immediate # mailbox # fifo # fifo_relaxed # shared_demand_refresh # shared_continuous_refresh # fifo_latest_ready # Present Modes Documentation: # https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPresentModeKHR.html # vulkan_present_mode=mailbox ### VSync [0-3] 0 = adaptive; 1 = off; 2 = mailbox; 3 = on # vsync=-1 ### OpenGL VSync [0-N] 0 = off; >=1 = wait for N v-blanks, N > 1 acts as a FPS limiter (FPS = display refresh rate / N) # gl_vsync=-2 ### Mip-map LoD bias. Negative values will increase texture sharpness (and aliasing) ## Positive values will increase texture blurriness (-16 to 16) # picmip=-17 ### Anisotropic filtering level. Improves sharpness of textures viewed at an angle (0 to 16) # af=-1 ### Force bicubic filtering # bicubic ### Force trilinear filtering # trilinear ### Disable linear texture filtering. Makes textures look blocky # retro ################### VISUAL ################### ### Legacy layout # legacy_layout=0 ### pre defined presets # -1 = default # 0 = no display # 1 = fps only # 2 = horizontal view # 3 = extended # 4 = high detailed information # preset=-1 ### Enable most of the toggleable parameters (currently excludes `histogram`) # full ### Show FPS only. ***Not meant to be used with other display params*** # fps_only ### Display custom centered text, useful for a header # custom_text_center= ### Display the current system time # time ## removes the time label # time_no_label ### Time formatting examples ## %H:%M ## [ %T %F ] ## %X # locally formatted time, because of limited glyph range, missing characters may show as '?' (e.g. Japanese) # time_format="%T" ### Display MangoHud version # version ### Display the current GPU information ## Note: gpu_mem_clock and gpu_mem_temp also need "vram" to be enabled gpu_stats # gpu_temp # gpu_junction_temp # gpu_core_clock # gpu_mem_temp # gpu_mem_clock # gpu_power # gpu_power_limit # gpu_text= # gpu_load_change # gpu_load_value=60,90 # gpu_load_color=39F900,FDFD09,B22222 ## GPU fan in rpm on AMD, FAN in percent on NVIDIA # gpu_fan ## gpu_voltage only works on AMD GPUs # gpu_voltage ## Select list of GPUs to display # gpu_list=0,1 # gpu_efficiency ### Display the current CPU information cpu_stats # cpu_temp # cpu_power # cpu_text= # cpu_mhz # cpu_load_change # cpu_load_value=60,90 # cpu_load_color=39F900,FDFD09,B22222 # cpu_efficiency ### Display the current CPU load & frequency for each core # core_load # core_load_change # core_bars # core_type ### Display IO read and write for the app (not system) # io_read # io_write ### Display system vram / ram / swap space usage # vram # ram # swap ### Display per process memory usage ## Show resident memory and other types, if enabled # procmem # procmem_shared # procmem_virt # proc_vram ### Display battery information # battery # battery_icon # device_battery=gamepad,mouse # device_battery_icon # battery_watt # battery_time ### Display FPS and frametime fps # fps_sampling_period=500 # fps_color_change # fps_value=30,60 # fps_color=B22222,FDFD09,39F900 # fps_text="" frametime # frame_count ## fps_metrics takes a list of decimal values or the value avg # fps_metrics=avg,0.01 ### Display GPU throttling status based on Power, current, temp or "other" ## Only shows if throttling is currently happening throttling_status ## Same as throttling_status but displays throttling on the frametime graph #throttling_status_graph ### Display miscellaneous information # engine_version # engine_short_names # gpu_name # vulkan_driver # wine # exec_name # winesync # present_mode ### Display loaded MangoHud architecture # arch ### Display the frametime line graph frame_timing # frame_timing_detailed # dynamic_frame_timing # histogram ### Display GameMode / vkBasalt running status # gamemode # vkbasalt ### Gamescope related options ## Display the status of FSR (only works in gamescope) # fsr ## Hides the sharpness info for the `fsr` option (only available in gamescope) # hide_fsr_sharpness ## Shows the graph of gamescope app frametimes and latency (only on gamescope obviously) # debug ## Display the status of HDR (only works in gamescope) # hdr ## Display the current refresh rate (only works in gamescope) # refresh_rate ### graphs displays one or more graphs that you chose ## separated by ",", available graphs are ## gpu_load,cpu_load,gpu_core_clock,gpu_mem_clock,vram,ram,cpu_temp,gpu_temp # graphs= ### mangoapp related options ## Enables mangoapp to be displayed above the Steam UI # mangoapp_steam ### Steam Deck options ## Shows the Steam Deck fan rpm # fan ### Display current FPS limit # show_fps_limit ### Display the current resolution # resolution ### Display current display session # display_server ### Display temperature in fahrenheit # temp_fahrenheit ## Display efficiency in joules per frame # flip_efficiency ### Display custom text # custom_text= ### Display output of Bash command in next column # exec= ### Display media player metadata # media_player ## for example spotify # media_player_name= ## Format metadata, lines are delimited by ; (wip) ## example: {title};{artist};{album} ## example: Track:;{title};By:;{artist};From:;{album} # media_player_format=title,artist,album ### Network interface throughput # network ## Network can take arguments but it's not required. ## without arguments it shows all interfaces ## arguments set which interfaces will be displayed # network=eth0,wlo1 ### Change the hud font size # font_size=24 # font_scale=1.0 # font_size_text=24 # font_scale_media_player=0.55 # no_small_font ### Change default font (set location to TTF/OTF file) ## Set font for the whole hud # font_file= ## Set font only for text like media player metadata # font_file_text= ## Set font glyph ranges. Defaults to Latin-only. Don't forget to set font_file/font_file_text to font that supports these ## Probably don't enable all at once because of memory usage and hardware limits concerns ## If you experience crashes or text is just squares, reduce glyph range or reduce font size # font_glyph_ranges=korean,chinese,chinese_simplified,japanese,cyrillic,thai,vietnamese,latin_ext_a,latin_ext_b ### Outline text text_outline # text_outline_color = 000000 # text_outline_thickness = 1.5 ### Change the hud position # position=top-left ### Change the corner roundness # round_corners=0 ### Remove margins around MangoHud # hud_no_margin ### Display compact version of MangoHud # hud_compact ### Display MangoHud in a horizontal position # horizontal # horizontal_stretch ### Disable / hide the hud by default # no_display ### Show FEX-Emu statistics ## Only useful for Arm64 devices running applications under emulation # fex_stats ### Hud position offset # offset_x=0 # offset_y=0 ### Hud dimensions # width=0 # height=140 # table_columns=3 # cellpadding_y=-0.085 ### Hud transparency / alpha # background_alpha=0.5 # alpha=1.0 ### FCAT overlay ### This enables an FCAT overlay to perform frametime analysis on the final image stream. ### Enable the overlay # fcat ### Set the width of the FCAT overlay. ### 24 is a performance optimization on AMD GPUs that should not have adverse effects on nVidia GPUs. ### A minimum of 20 pixels is recommended by nVidia. # fcat_overlay_width=24 ### Set the screen edge, this can be useful for special displays that don't update from top edge to bottom. This goes from 0 (left side) to 3 (top edge), counter-clockwise. # fcat_screen_edge=0 ### Color customization # text_color=FFFFFF # gpu_color=2E9762 # cpu_color=2E97CB # vram_color=AD64C1 # ram_color=C26693 # engine_color=EB5B5B # io_color=A491D3 # frametime_color=00FF00 # background_color=020202 # media_player_color=FFFFFF # wine_color=EB5B5B # battery_color=FF9078 # network_color=E07B85 # horizontal_separator_color=AD64C1 ### Specify GPU with PCI bus ID ### Set to 'domain:bus:slot.function' ### Example: ### $ lspci | grep A770 ### 03:00.0 VGA compatible controller: Intel Corporation DG2 [Arc A770] (rev 08) # pci_dev=0000:03:00.0 ### Blacklist # blacklist= ### Control over socket ### Enable and set socket name, '%p' is replaced with process id ## example: mangohud ## example: mangohud-%p # control = -1 ### ftrace tracepoint display ## Enable display of tracepoint information gathered from ftrace. MangoHud will parse ## out the necessary data from the ftrace pipe, ftrace itself still has to be configured ## manually (enabling the desired event, applying any filtering etc.). The user running ## MangoHud will require permission to access the default-mounted tracefs (expected at ## /sys/kernel/tracing/). ## ## When parsing ftrace output, currently only the `key=value` format for event fields is ## expected. This is the most common format used in events, but it's not standardized. ## ## Three types of display are available: ## - `histogram/drm_vblank_event`, a histogram of event occurrence ## - `linegraph/devfreq_monitor/freq`, a line graph of an event field's numerical value ## - `label/devfreq_frequency/dev_name`, a textual presentation of an event field's value ## ## The displays are set through the `ftrace` option. Multiple displays can be specified. # ftrace=histogram/drm_vblank_event+linegraph/devfreq_monitor/freq ################ WORKAROUNDS ################# ### Options starting with "gl_*" are for OpenGL ### Specify what to use for getting display size. Options are "viewport", "scissorbox" or disabled. Defaults to using glXQueryDrawable # gl_size_query=viewport ### (Re)bind given framebuffer before MangoHud gets drawn. Helps with Crusader Kings III # gl_bind_framebuffer=0 ### Don't swap origin if using GL_UPPER_LEFT. Helps with Ryujinx # gl_dont_flip=1 ################ INTERACTION ################# ### Change toggle keybinds for the hud & logging # toggle_hud=Shift_R+F12 # toggle_hud_position=Shift_R+F11 # toggle_preset=Shift_R+F10 # toggle_fps_limit=Shift_L+F1 # toggle_logging=Shift_L+F2 # reload_cfg=Shift_L+F4 # upload_log=Shift_L+F3 # reset_fps_metrics=Shift_R+f9 #################### LOG ##################### ### Automatically start the log after X seconds # autostart_log= ### Set amount of time in seconds that the logging will run for # log_duration= ### Change the default log interval, 0 is default # log_interval=0 ### Set location of the output files (required for logging) # output_folder=/home//mangologs ### Permit uploading logs directly to FlightlessMango.com ## set to 1 to enable # permit_upload=0 ### Define a '+'-separated list of percentiles shown in the benchmark results ### Use "AVG" to get a mean average. Default percentiles are 97+AVG+1+0.1 ## example: ['97', 'AVG', '1', '0.1'] # benchmark_percentiles=97,AVG ## Adds more headers and information such as versioning to the log. This format is not supported on flightlessmango.com (yet) # log_versioning ## Enable automatic uploads of logs to flightlessmango.com # upload_logs # output_file="" ================================================ FILE: data/io.github.flightlessmango.mangohud.metainfo.xml ================================================ io.github.flightlessmango.mangohud MangoHud Vulkan/OpenGL overlay for monitoring FPS, temperatures, CPU/GPU load and more FlightlessMango io.github.flightlessmango.mangohud CC0-1.0 MIT

A modification of the Mesa Vulkan overlay, including GUI improvements with HUD configuration, temperature reporting, and logging capabilities. Includes a script (mangohud) to start it on any OpenGL or Vulkan application.

Example https://raw.githubusercontent.com/flightlessmango/MangoHud/master/assets/overlay_example.gif Log uploading walkthrough https://raw.githubusercontent.com/flightlessmango/MangoHud/master/assets/log_upload_example.gif https://github.com/flightlessmango/MangoHud https://github.com/flightlessmango/MangoHud/issues https://www.paypal.me/flightlessmango mangohud Utility Game
================================================ FILE: data/mangoapp.1 ================================================ .\" Manpage for mangoapp. .TH mangoapp 1 "" "" "mangoapp" .SH NAME mangoapp \- transparent background application with a built in mangohud .SH SYNOPSIS \fBmangoapp\fR .SH DESCRIPTION MangoHud is a Vulkan/OpenGL overlay for monitoring FPS, temperatures, CPU/GPU load and more. .PP Mangoapp is a transparent background opengl application with a built in MangoHud. It's designed to be run inside a gamescope instance which will display mangoapp ontop of gamescopes output. It also takes frame information from gamescope. The purpose of this is to "easily" make MangoHud compatible with any application, or at least any application that gamescope can run. This solves issues with some OpenGL games and certain ports that have stdc++ issues as it's no longer directly injected into the game. .SH USAGE Create a script (e.g. \fBrun.sh\fR) containing the app you want to run (e.g. \fBvkcube\fR) and \fBmangoapp\fR like so: .PP .RS 4 .EX #!/bin/sh vkcube& mangoapp .EE .RE .PP And then run it with \fBgamescope ./run.sh\fR. .SH SEE ALSO mangohud(1) .SH ABOUT MangoHud development takes place at \fIhttps://github.com/flightlessmango/MangoHud\fR. .br Benchmarks created with MangoHud can be uploaded to \fIhttps://flightlessmango.com\fR. ================================================ FILE: data/mangohud.1 ================================================ .\" Manpage for mangohud. .TH mangohud 1 "" "" "mangohud" .SH NAME mangohud \- enable MangoHud on any application .SH SYNOPSIS \fBmangohud\fR [--dlsym] COMMAND .SH DESCRIPTION MangoHud is a Vulkan/OpenGL overlay for monitoring FPS, temperatures, CPU/GPU load and more. .SH USAGE MangoHud can be enabled for Vulkan applications by setting \fBMANGOHUD=1\fR as environment variable. .br To load MangoHud for any application, including OpenGL applications, the \fBmangohud\fR executable can be used. It preloads a library via ld into the application. .br Note: some OpenGL applications may also need dlsym hooking. This can be done by passing option \fB--dlsym\fR or by setting \fBMANGOHUD_DLSYM=1\fR as environment variable. .SH CONFIG MangoHud comes with a config file which can be used to set configuration options globally or per application. The priorities of different config files are: .LP .RS 4 /path/to/application/MangoHud.conf .br $XDG_CONFIG_HOME/MangoHud/{application_name}.conf .br $XDG_CONFIG_HOME/MangoHud/MangoHud.conf .RS -4 .LP An example config file is located in /usr/share/doc/mangohud/MangoHud.conf, containing all available options. .LP A custom config file location can also be specified with the \fBMANGOHUD_CONFIGFILE\fR environment variable. .br Config options can also be set with the \fBMANGOHUD_CONFIG\fR environment variable. This takes priority over any config file. .SH EXAMPLES OpenGL: \fBmangohud glxgears\fR .br Vulkan: \fBMANGOHUD=1 vkcube\fR .br Steam: set your launch option to \fBmangohud %command%\fR .br Lutris: add \fBmangohud\fR to the Command prefix setting .br OpenGL with dlsym: \fBmangohud --dlsym glxgears\fR .br Custom config options: \fBMANGOHUD_CONFIG="gpu_stats=0,font_size=12" mangohud glxgears\fR .SH ABOUT MangoHud development takes place at \fIhttps://github.com/flightlessmango/MangoHud\fR. .br Benchmarks created with MangoHud can be uploaded to \fIhttps://flightlessmango.com\fR. ================================================ FILE: data/meson.build ================================================ man1dir = join_paths(get_option('mandir'), 'man1') datadir = get_option('datadir') metainfo_file = files('io.github.flightlessmango.mangohud.metainfo.xml') icon_file = files('io.github.flightlessmango.mangohud.svg') # Validate metainfo file ascli_exe = find_program('appstreamcli', required: get_option('tests')) if ascli_exe.found() test('validate metainfo file', ascli_exe, args: ['validate', '--no-net', '--pedantic', metainfo_file] ) endif # Install metainfo file install_data( metainfo_file, install_dir: join_paths(datadir, 'metainfo'), install_tag : 'doc', ) # Install icon for metainfo install_data( icon_file, install_dir: join_paths(datadir, 'icons', 'hicolor', 'scalable', 'apps'), install_tag : 'doc', ) # Install man pages install_man( files('mangohud.1'), install_dir: man1dir, ) if get_option('mangoapp') install_man( files('mangoapp.1'), install_dir: man1dir, ) endif install_data( files('MangoHud.conf'), install_dir : join_paths(get_option('datadir'), 'doc', 'mangohud'), rename : ['MangoHud.conf.example'], install_tag : 'doc', ) install_data( files('presets.conf'), install_dir : join_paths(get_option('datadir'), 'doc', 'mangohud'), rename : ['presets.conf.example'], install_tag : 'doc', ) ================================================ FILE: data/presets.conf ================================================ [preset 1] no_display [preset 2] legacy_layout=0 cpu_stats=0 gpu_stats=0 fps fps_only=1 frametime=0 ================================================ FILE: include/.editorconfig ================================================ # ignore this folder root = true ================================================ FILE: include/IconsForkAwesome.h ================================================ // Generated by https://github.com/juliettef/IconFontCppHeaders script GenerateIconFontCppHeaders.py for languages C and C++ // from https://raw.githubusercontent.com/ForkAwesome/Fork-Awesome/master/src/icons/icons.yml // for use with https://github.com/ForkAwesome/Fork-Awesome/blob/master/fonts/forkawesome-webfont.ttf #pragma once #define FONT_ICON_FILE_NAME_FK "forkawesome-webfont.ttf" #define ICON_MIN_FK 0xf000 #define ICON_MAX_FK 0xf35f #define ICON_FK_GLASS "\xef\x80\x80" // U+f000 #define ICON_FK_MUSIC "\xef\x80\x81" // U+f001 #define ICON_FK_SEARCH "\xef\x80\x82" // U+f002 #define ICON_FK_ENVELOPE_O "\xef\x80\x83" // U+f003 #define ICON_FK_HEART "\xef\x80\x84" // U+f004 #define ICON_FK_STAR "\xef\x80\x85" // U+f005 #define ICON_FK_STAR_O "\xef\x80\x86" // U+f006 #define ICON_FK_USER "\xef\x80\x87" // U+f007 #define ICON_FK_FILM "\xef\x80\x88" // U+f008 #define ICON_FK_TH_LARGE "\xef\x80\x89" // U+f009 #define ICON_FK_TH "\xef\x80\x8a" // U+f00a #define ICON_FK_TH_LIST "\xef\x80\x8b" // U+f00b #define ICON_FK_CHECK "\xef\x80\x8c" // U+f00c #define ICON_FK_TIMES "\xef\x80\x8d" // U+f00d #define ICON_FK_SEARCH_PLUS "\xef\x80\x8e" // U+f00e #define ICON_FK_SEARCH_MINUS "\xef\x80\x90" // U+f010 #define ICON_FK_POWER_OFF "\xef\x80\x91" // U+f011 #define ICON_FK_SIGNAL "\xef\x80\x92" // U+f012 #define ICON_FK_COG "\xef\x80\x93" // U+f013 #define ICON_FK_TRASH_O "\xef\x80\x94" // U+f014 #define ICON_FK_HOME "\xef\x80\x95" // U+f015 #define ICON_FK_FILE_O "\xef\x80\x96" // U+f016 #define ICON_FK_CLOCK_O "\xef\x80\x97" // U+f017 #define ICON_FK_ROAD "\xef\x80\x98" // U+f018 #define ICON_FK_DOWNLOAD "\xef\x80\x99" // U+f019 #define ICON_FK_ARROW_CIRCLE_O_DOWN "\xef\x80\x9a" // U+f01a #define ICON_FK_ARROW_CIRCLE_O_UP "\xef\x80\x9b" // U+f01b #define ICON_FK_INBOX "\xef\x80\x9c" // U+f01c #define ICON_FK_PLAY_CIRCLE_O "\xef\x80\x9d" // U+f01d #define ICON_FK_REPEAT "\xef\x80\x9e" // U+f01e #define ICON_FK_REFRESH "\xef\x80\xa1" // U+f021 #define ICON_FK_LIST_ALT "\xef\x80\xa2" // U+f022 #define ICON_FK_LOCK "\xef\x80\xa3" // U+f023 #define ICON_FK_FLAG "\xef\x80\xa4" // U+f024 #define ICON_FK_HEADPHONES "\xef\x80\xa5" // U+f025 #define ICON_FK_VOLUME_OFF "\xef\x80\xa6" // U+f026 #define ICON_FK_VOLUME_DOWN "\xef\x80\xa7" // U+f027 #define ICON_FK_VOLUME_UP "\xef\x80\xa8" // U+f028 #define ICON_FK_QRCODE "\xef\x80\xa9" // U+f029 #define ICON_FK_BARCODE "\xef\x80\xaa" // U+f02a #define ICON_FK_TAG "\xef\x80\xab" // U+f02b #define ICON_FK_TAGS "\xef\x80\xac" // U+f02c #define ICON_FK_BOOK "\xef\x80\xad" // U+f02d #define ICON_FK_BOOKMARK "\xef\x80\xae" // U+f02e #define ICON_FK_PRINT "\xef\x80\xaf" // U+f02f #define ICON_FK_CAMERA "\xef\x80\xb0" // U+f030 #define ICON_FK_FONT "\xef\x80\xb1" // U+f031 #define ICON_FK_BOLD "\xef\x80\xb2" // U+f032 #define ICON_FK_ITALIC "\xef\x80\xb3" // U+f033 #define ICON_FK_TEXT_HEIGHT "\xef\x80\xb4" // U+f034 #define ICON_FK_TEXT_WIDTH "\xef\x80\xb5" // U+f035 #define ICON_FK_ALIGN_LEFT "\xef\x80\xb6" // U+f036 #define ICON_FK_ALIGN_CENTER "\xef\x80\xb7" // U+f037 #define ICON_FK_ALIGN_RIGHT "\xef\x80\xb8" // U+f038 #define ICON_FK_ALIGN_JUSTIFY "\xef\x80\xb9" // U+f039 #define ICON_FK_LIST "\xef\x80\xba" // U+f03a #define ICON_FK_OUTDENT "\xef\x80\xbb" // U+f03b #define ICON_FK_INDENT "\xef\x80\xbc" // U+f03c #define ICON_FK_VIDEO_CAMERA "\xef\x80\xbd" // U+f03d #define ICON_FK_PICTURE_O "\xef\x80\xbe" // U+f03e #define ICON_FK_PENCIL "\xef\x81\x80" // U+f040 #define ICON_FK_MAP_MARKER "\xef\x81\x81" // U+f041 #define ICON_FK_ADJUST "\xef\x81\x82" // U+f042 #define ICON_FK_TINT "\xef\x81\x83" // U+f043 #define ICON_FK_PENCIL_SQUARE_O "\xef\x81\x84" // U+f044 #define ICON_FK_SHARE_SQUARE_O "\xef\x81\x85" // U+f045 #define ICON_FK_CHECK_SQUARE_O "\xef\x81\x86" // U+f046 #define ICON_FK_ARROWS "\xef\x81\x87" // U+f047 #define ICON_FK_STEP_BACKWARD "\xef\x81\x88" // U+f048 #define ICON_FK_FAST_BACKWARD "\xef\x81\x89" // U+f049 #define ICON_FK_BACKWARD "\xef\x81\x8a" // U+f04a #define ICON_FK_PLAY "\xef\x81\x8b" // U+f04b #define ICON_FK_PAUSE "\xef\x81\x8c" // U+f04c #define ICON_FK_STOP "\xef\x81\x8d" // U+f04d #define ICON_FK_FORWARD "\xef\x81\x8e" // U+f04e #define ICON_FK_FAST_FORWARD "\xef\x81\x90" // U+f050 #define ICON_FK_STEP_FORWARD "\xef\x81\x91" // U+f051 #define ICON_FK_EJECT "\xef\x81\x92" // U+f052 #define ICON_FK_CHEVRON_LEFT "\xef\x81\x93" // U+f053 #define ICON_FK_CHEVRON_RIGHT "\xef\x81\x94" // U+f054 #define ICON_FK_PLUS_CIRCLE "\xef\x81\x95" // U+f055 #define ICON_FK_MINUS_CIRCLE "\xef\x81\x96" // U+f056 #define ICON_FK_TIMES_CIRCLE "\xef\x81\x97" // U+f057 #define ICON_FK_CHECK_CIRCLE "\xef\x81\x98" // U+f058 #define ICON_FK_QUESTION_CIRCLE "\xef\x81\x99" // U+f059 #define ICON_FK_INFO_CIRCLE "\xef\x81\x9a" // U+f05a #define ICON_FK_CROSSHAIRS "\xef\x81\x9b" // U+f05b #define ICON_FK_TIMES_CIRCLE_O "\xef\x81\x9c" // U+f05c #define ICON_FK_CHECK_CIRCLE_O "\xef\x81\x9d" // U+f05d #define ICON_FK_BAN "\xef\x81\x9e" // U+f05e #define ICON_FK_ARROW_LEFT "\xef\x81\xa0" // U+f060 #define ICON_FK_ARROW_RIGHT "\xef\x81\xa1" // U+f061 #define ICON_FK_ARROW_UP "\xef\x81\xa2" // U+f062 #define ICON_FK_ARROW_DOWN "\xef\x81\xa3" // U+f063 #define ICON_FK_SHARE "\xef\x81\xa4" // U+f064 #define ICON_FK_EXPAND "\xef\x81\xa5" // U+f065 #define ICON_FK_COMPRESS "\xef\x81\xa6" // U+f066 #define ICON_FK_PLUS "\xef\x81\xa7" // U+f067 #define ICON_FK_MINUS "\xef\x81\xa8" // U+f068 #define ICON_FK_ASTERISK "\xef\x81\xa9" // U+f069 #define ICON_FK_EXCLAMATION_CIRCLE "\xef\x81\xaa" // U+f06a #define ICON_FK_GIFT "\xef\x81\xab" // U+f06b #define ICON_FK_LEAF "\xef\x81\xac" // U+f06c #define ICON_FK_FIRE "\xef\x81\xad" // U+f06d #define ICON_FK_EYE "\xef\x81\xae" // U+f06e #define ICON_FK_EYE_SLASH "\xef\x81\xb0" // U+f070 #define ICON_FK_EXCLAMATION_TRIANGLE "\xef\x81\xb1" // U+f071 #define ICON_FK_PLANE "\xef\x81\xb2" // U+f072 #define ICON_FK_CALENDAR "\xef\x81\xb3" // U+f073 #define ICON_FK_RANDOM "\xef\x81\xb4" // U+f074 #define ICON_FK_COMMENT "\xef\x81\xb5" // U+f075 #define ICON_FK_MAGNET "\xef\x81\xb6" // U+f076 #define ICON_FK_CHEVRON_UP "\xef\x81\xb7" // U+f077 #define ICON_FK_CHEVRON_DOWN "\xef\x81\xb8" // U+f078 #define ICON_FK_RETWEET "\xef\x81\xb9" // U+f079 #define ICON_FK_SHOPPING_CART "\xef\x81\xba" // U+f07a #define ICON_FK_FOLDER "\xef\x81\xbb" // U+f07b #define ICON_FK_FOLDER_OPEN "\xef\x81\xbc" // U+f07c #define ICON_FK_ARROWS_V "\xef\x81\xbd" // U+f07d #define ICON_FK_ARROWS_H "\xef\x81\xbe" // U+f07e #define ICON_FK_BAR_CHART "\xef\x82\x80" // U+f080 #define ICON_FK_TWITTER_SQUARE "\xef\x82\x81" // U+f081 #define ICON_FK_FACEBOOK_SQUARE "\xef\x82\x82" // U+f082 #define ICON_FK_CAMERA_RETRO "\xef\x82\x83" // U+f083 #define ICON_FK_KEY "\xef\x82\x84" // U+f084 #define ICON_FK_COGS "\xef\x82\x85" // U+f085 #define ICON_FK_COMMENTS "\xef\x82\x86" // U+f086 #define ICON_FK_THUMBS_O_UP "\xef\x82\x87" // U+f087 #define ICON_FK_THUMBS_O_DOWN "\xef\x82\x88" // U+f088 #define ICON_FK_STAR_HALF "\xef\x82\x89" // U+f089 #define ICON_FK_HEART_O "\xef\x82\x8a" // U+f08a #define ICON_FK_SIGN_OUT "\xef\x82\x8b" // U+f08b #define ICON_FK_LINKEDIN_SQUARE "\xef\x82\x8c" // U+f08c #define ICON_FK_THUMB_TACK "\xef\x82\x8d" // U+f08d #define ICON_FK_EXTERNAL_LINK "\xef\x82\x8e" // U+f08e #define ICON_FK_SIGN_IN "\xef\x82\x90" // U+f090 #define ICON_FK_TROPHY "\xef\x82\x91" // U+f091 #define ICON_FK_GITHUB_SQUARE "\xef\x82\x92" // U+f092 #define ICON_FK_UPLOAD "\xef\x82\x93" // U+f093 #define ICON_FK_LEMON_O "\xef\x82\x94" // U+f094 #define ICON_FK_PHONE "\xef\x82\x95" // U+f095 #define ICON_FK_SQUARE_O "\xef\x82\x96" // U+f096 #define ICON_FK_BOOKMARK_O "\xef\x82\x97" // U+f097 #define ICON_FK_PHONE_SQUARE "\xef\x82\x98" // U+f098 #define ICON_FK_TWITTER "\xef\x82\x99" // U+f099 #define ICON_FK_FACEBOOK "\xef\x82\x9a" // U+f09a #define ICON_FK_GITHUB "\xef\x82\x9b" // U+f09b #define ICON_FK_UNLOCK "\xef\x82\x9c" // U+f09c #define ICON_FK_CREDIT_CARD "\xef\x82\x9d" // U+f09d #define ICON_FK_RSS "\xef\x82\x9e" // U+f09e #define ICON_FK_HDD_O "\xef\x82\xa0" // U+f0a0 #define ICON_FK_BULLHORN "\xef\x82\xa1" // U+f0a1 #define ICON_FK_BELL_O "\xef\x83\xb3" // U+f0f3 #define ICON_FK_CERTIFICATE "\xef\x82\xa3" // U+f0a3 #define ICON_FK_HAND_O_RIGHT "\xef\x82\xa4" // U+f0a4 #define ICON_FK_HAND_O_LEFT "\xef\x82\xa5" // U+f0a5 #define ICON_FK_HAND_O_UP "\xef\x82\xa6" // U+f0a6 #define ICON_FK_HAND_O_DOWN "\xef\x82\xa7" // U+f0a7 #define ICON_FK_ARROW_CIRCLE_LEFT "\xef\x82\xa8" // U+f0a8 #define ICON_FK_ARROW_CIRCLE_RIGHT "\xef\x82\xa9" // U+f0a9 #define ICON_FK_ARROW_CIRCLE_UP "\xef\x82\xaa" // U+f0aa #define ICON_FK_ARROW_CIRCLE_DOWN "\xef\x82\xab" // U+f0ab #define ICON_FK_GLOBE "\xef\x82\xac" // U+f0ac #define ICON_FK_GLOBE_E "\xef\x8c\x84" // U+f304 #define ICON_FK_GLOBE_W "\xef\x8c\x85" // U+f305 #define ICON_FK_WRENCH "\xef\x82\xad" // U+f0ad #define ICON_FK_TASKS "\xef\x82\xae" // U+f0ae #define ICON_FK_FILTER "\xef\x82\xb0" // U+f0b0 #define ICON_FK_BRIEFCASE "\xef\x82\xb1" // U+f0b1 #define ICON_FK_ARROWS_ALT "\xef\x82\xb2" // U+f0b2 #define ICON_FK_USERS "\xef\x83\x80" // U+f0c0 #define ICON_FK_LINK "\xef\x83\x81" // U+f0c1 #define ICON_FK_CLOUD "\xef\x83\x82" // U+f0c2 #define ICON_FK_FLASK "\xef\x83\x83" // U+f0c3 #define ICON_FK_SCISSORS "\xef\x83\x84" // U+f0c4 #define ICON_FK_FILES_O "\xef\x83\x85" // U+f0c5 #define ICON_FK_PAPERCLIP "\xef\x83\x86" // U+f0c6 #define ICON_FK_FLOPPY_O "\xef\x83\x87" // U+f0c7 #define ICON_FK_SQUARE "\xef\x83\x88" // U+f0c8 #define ICON_FK_BARS "\xef\x83\x89" // U+f0c9 #define ICON_FK_LIST_UL "\xef\x83\x8a" // U+f0ca #define ICON_FK_LIST_OL "\xef\x83\x8b" // U+f0cb #define ICON_FK_STRIKETHROUGH "\xef\x83\x8c" // U+f0cc #define ICON_FK_UNDERLINE "\xef\x83\x8d" // U+f0cd #define ICON_FK_TABLE "\xef\x83\x8e" // U+f0ce #define ICON_FK_MAGIC "\xef\x83\x90" // U+f0d0 #define ICON_FK_TRUCK "\xef\x83\x91" // U+f0d1 #define ICON_FK_PINTEREST "\xef\x83\x92" // U+f0d2 #define ICON_FK_PINTEREST_SQUARE "\xef\x83\x93" // U+f0d3 #define ICON_FK_GOOGLE_PLUS_SQUARE "\xef\x83\x94" // U+f0d4 #define ICON_FK_GOOGLE_PLUS "\xef\x83\x95" // U+f0d5 #define ICON_FK_MONEY "\xef\x83\x96" // U+f0d6 #define ICON_FK_CARET_DOWN "\xef\x83\x97" // U+f0d7 #define ICON_FK_CARET_UP "\xef\x83\x98" // U+f0d8 #define ICON_FK_CARET_LEFT "\xef\x83\x99" // U+f0d9 #define ICON_FK_CARET_RIGHT "\xef\x83\x9a" // U+f0da #define ICON_FK_COLUMNS "\xef\x83\x9b" // U+f0db #define ICON_FK_SORT "\xef\x83\x9c" // U+f0dc #define ICON_FK_SORT_DESC "\xef\x83\x9d" // U+f0dd #define ICON_FK_SORT_ASC "\xef\x83\x9e" // U+f0de #define ICON_FK_ENVELOPE "\xef\x83\xa0" // U+f0e0 #define ICON_FK_LINKEDIN "\xef\x83\xa1" // U+f0e1 #define ICON_FK_UNDO "\xef\x83\xa2" // U+f0e2 #define ICON_FK_GAVEL "\xef\x83\xa3" // U+f0e3 #define ICON_FK_TACHOMETER "\xef\x83\xa4" // U+f0e4 #define ICON_FK_COMMENT_O "\xef\x83\xa5" // U+f0e5 #define ICON_FK_COMMENTS_O "\xef\x83\xa6" // U+f0e6 #define ICON_FK_BOLT "\xef\x83\xa7" // U+f0e7 #define ICON_FK_SITEMAP "\xef\x83\xa8" // U+f0e8 #define ICON_FK_UMBRELLA "\xef\x83\xa9" // U+f0e9 #define ICON_FK_CLIPBOARD "\xef\x83\xaa" // U+f0ea #define ICON_FK_LIGHTBULB_O "\xef\x83\xab" // U+f0eb #define ICON_FK_EXCHANGE "\xef\x83\xac" // U+f0ec #define ICON_FK_CLOUD_DOWNLOAD "\xef\x83\xad" // U+f0ed #define ICON_FK_CLOUD_UPLOAD "\xef\x83\xae" // U+f0ee #define ICON_FK_USER_MD "\xef\x83\xb0" // U+f0f0 #define ICON_FK_STETHOSCOPE "\xef\x83\xb1" // U+f0f1 #define ICON_FK_SUITCASE "\xef\x83\xb2" // U+f0f2 #define ICON_FK_BELL "\xef\x82\xa2" // U+f0a2 #define ICON_FK_COFFEE "\xef\x83\xb4" // U+f0f4 #define ICON_FK_CUTLERY "\xef\x83\xb5" // U+f0f5 #define ICON_FK_FILE_TEXT_O "\xef\x83\xb6" // U+f0f6 #define ICON_FK_BUILDING_O "\xef\x83\xb7" // U+f0f7 #define ICON_FK_HOSPITAL_O "\xef\x83\xb8" // U+f0f8 #define ICON_FK_AMBULANCE "\xef\x83\xb9" // U+f0f9 #define ICON_FK_MEDKIT "\xef\x83\xba" // U+f0fa #define ICON_FK_FIGHTER_JET "\xef\x83\xbb" // U+f0fb #define ICON_FK_BEER "\xef\x83\xbc" // U+f0fc #define ICON_FK_H_SQUARE "\xef\x83\xbd" // U+f0fd #define ICON_FK_PLUS_SQUARE "\xef\x83\xbe" // U+f0fe #define ICON_FK_ANGLE_DOUBLE_LEFT "\xef\x84\x80" // U+f100 #define ICON_FK_ANGLE_DOUBLE_RIGHT "\xef\x84\x81" // U+f101 #define ICON_FK_ANGLE_DOUBLE_UP "\xef\x84\x82" // U+f102 #define ICON_FK_ANGLE_DOUBLE_DOWN "\xef\x84\x83" // U+f103 #define ICON_FK_ANGLE_LEFT "\xef\x84\x84" // U+f104 #define ICON_FK_ANGLE_RIGHT "\xef\x84\x85" // U+f105 #define ICON_FK_ANGLE_UP "\xef\x84\x86" // U+f106 #define ICON_FK_ANGLE_DOWN "\xef\x84\x87" // U+f107 #define ICON_FK_DESKTOP "\xef\x84\x88" // U+f108 #define ICON_FK_LAPTOP "\xef\x84\x89" // U+f109 #define ICON_FK_TABLET "\xef\x84\x8a" // U+f10a #define ICON_FK_MOBILE "\xef\x84\x8b" // U+f10b #define ICON_FK_CIRCLE_O "\xef\x84\x8c" // U+f10c #define ICON_FK_QUOTE_LEFT "\xef\x84\x8d" // U+f10d #define ICON_FK_QUOTE_RIGHT "\xef\x84\x8e" // U+f10e #define ICON_FK_SPINNER "\xef\x84\x90" // U+f110 #define ICON_FK_CIRCLE "\xef\x84\x91" // U+f111 #define ICON_FK_REPLY "\xef\x84\x92" // U+f112 #define ICON_FK_GITHUB_ALT "\xef\x84\x93" // U+f113 #define ICON_FK_FOLDER_O "\xef\x84\x94" // U+f114 #define ICON_FK_FOLDER_OPEN_O "\xef\x84\x95" // U+f115 #define ICON_FK_SMILE_O "\xef\x84\x98" // U+f118 #define ICON_FK_FROWN_O "\xef\x84\x99" // U+f119 #define ICON_FK_MEH_O "\xef\x84\x9a" // U+f11a #define ICON_FK_GAMEPAD "\xef\x84\x9b" // U+f11b #define ICON_FK_KEYBOARD_O "\xef\x84\x9c" // U+f11c #define ICON_FK_FLAG_O "\xef\x84\x9d" // U+f11d #define ICON_FK_FLAG_CHECKERED "\xef\x84\x9e" // U+f11e #define ICON_FK_TERMINAL "\xef\x84\xa0" // U+f120 #define ICON_FK_CODE "\xef\x84\xa1" // U+f121 #define ICON_FK_REPLY_ALL "\xef\x84\xa2" // U+f122 #define ICON_FK_STAR_HALF_O "\xef\x84\xa3" // U+f123 #define ICON_FK_LOCATION_ARROW "\xef\x84\xa4" // U+f124 #define ICON_FK_CROP "\xef\x84\xa5" // U+f125 #define ICON_FK_CODE_FORK "\xef\x84\xa6" // U+f126 #define ICON_FK_CHAIN_BROKEN "\xef\x84\xa7" // U+f127 #define ICON_FK_QUESTION "\xef\x84\xa8" // U+f128 #define ICON_FK_INFO "\xef\x84\xa9" // U+f129 #define ICON_FK_EXCLAMATION "\xef\x84\xaa" // U+f12a #define ICON_FK_SUPERSCRIPT "\xef\x84\xab" // U+f12b #define ICON_FK_SUBSCRIPT "\xef\x84\xac" // U+f12c #define ICON_FK_ERASER "\xef\x84\xad" // U+f12d #define ICON_FK_PUZZLE_PIECE "\xef\x84\xae" // U+f12e #define ICON_FK_MICROPHONE "\xef\x84\xb0" // U+f130 #define ICON_FK_MICROPHONE_SLASH "\xef\x84\xb1" // U+f131 #define ICON_FK_SHIELD "\xef\x84\xb2" // U+f132 #define ICON_FK_CALENDAR_O "\xef\x84\xb3" // U+f133 #define ICON_FK_FIRE_EXTINGUISHER "\xef\x84\xb4" // U+f134 #define ICON_FK_ROCKET "\xef\x84\xb5" // U+f135 #define ICON_FK_MAXCDN "\xef\x84\xb6" // U+f136 #define ICON_FK_CHEVRON_CIRCLE_LEFT "\xef\x84\xb7" // U+f137 #define ICON_FK_CHEVRON_CIRCLE_RIGHT "\xef\x84\xb8" // U+f138 #define ICON_FK_CHEVRON_CIRCLE_UP "\xef\x84\xb9" // U+f139 #define ICON_FK_CHEVRON_CIRCLE_DOWN "\xef\x84\xba" // U+f13a #define ICON_FK_HTML5 "\xef\x84\xbb" // U+f13b #define ICON_FK_CSS3 "\xef\x84\xbc" // U+f13c #define ICON_FK_ANCHOR "\xef\x84\xbd" // U+f13d #define ICON_FK_UNLOCK_ALT "\xef\x84\xbe" // U+f13e #define ICON_FK_BULLSEYE "\xef\x85\x80" // U+f140 #define ICON_FK_ELLIPSIS_H "\xef\x85\x81" // U+f141 #define ICON_FK_ELLIPSIS_V "\xef\x85\x82" // U+f142 #define ICON_FK_RSS_SQUARE "\xef\x85\x83" // U+f143 #define ICON_FK_PLAY_CIRCLE "\xef\x85\x84" // U+f144 #define ICON_FK_TICKET "\xef\x85\x85" // U+f145 #define ICON_FK_MINUS_SQUARE "\xef\x85\x86" // U+f146 #define ICON_FK_MINUS_SQUARE_O "\xef\x85\x87" // U+f147 #define ICON_FK_LEVEL_UP "\xef\x85\x88" // U+f148 #define ICON_FK_LEVEL_DOWN "\xef\x85\x89" // U+f149 #define ICON_FK_CHECK_SQUARE "\xef\x85\x8a" // U+f14a #define ICON_FK_PENCIL_SQUARE "\xef\x85\x8b" // U+f14b #define ICON_FK_EXTERNAL_LINK_SQUARE "\xef\x85\x8c" // U+f14c #define ICON_FK_SHARE_SQUARE "\xef\x85\x8d" // U+f14d #define ICON_FK_COMPASS "\xef\x85\x8e" // U+f14e #define ICON_FK_CARET_SQUARE_O_DOWN "\xef\x85\x90" // U+f150 #define ICON_FK_CARET_SQUARE_O_UP "\xef\x85\x91" // U+f151 #define ICON_FK_CARET_SQUARE_O_RIGHT "\xef\x85\x92" // U+f152 #define ICON_FK_EUR "\xef\x85\x93" // U+f153 #define ICON_FK_GBP "\xef\x85\x94" // U+f154 #define ICON_FK_USD "\xef\x85\x95" // U+f155 #define ICON_FK_INR "\xef\x85\x96" // U+f156 #define ICON_FK_JPY "\xef\x85\x97" // U+f157 #define ICON_FK_RUB "\xef\x85\x98" // U+f158 #define ICON_FK_KRW "\xef\x85\x99" // U+f159 #define ICON_FK_BTC "\xef\x85\x9a" // U+f15a #define ICON_FK_FILE "\xef\x85\x9b" // U+f15b #define ICON_FK_FILE_TEXT "\xef\x85\x9c" // U+f15c #define ICON_FK_SORT_ALPHA_ASC "\xef\x85\x9d" // U+f15d #define ICON_FK_SORT_ALPHA_DESC "\xef\x85\x9e" // U+f15e #define ICON_FK_SORT_AMOUNT_ASC "\xef\x85\xa0" // U+f160 #define ICON_FK_SORT_AMOUNT_DESC "\xef\x85\xa1" // U+f161 #define ICON_FK_SORT_NUMERIC_ASC "\xef\x85\xa2" // U+f162 #define ICON_FK_SORT_NUMERIC_DESC "\xef\x85\xa3" // U+f163 #define ICON_FK_THUMBS_UP "\xef\x85\xa4" // U+f164 #define ICON_FK_THUMBS_DOWN "\xef\x85\xa5" // U+f165 #define ICON_FK_YOUTUBE_SQUARE "\xef\x85\xa6" // U+f166 #define ICON_FK_YOUTUBE "\xef\x85\xa7" // U+f167 #define ICON_FK_XING "\xef\x85\xa8" // U+f168 #define ICON_FK_XING_SQUARE "\xef\x85\xa9" // U+f169 #define ICON_FK_YOUTUBE_PLAY "\xef\x85\xaa" // U+f16a #define ICON_FK_DROPBOX "\xef\x85\xab" // U+f16b #define ICON_FK_STACK_OVERFLOW "\xef\x85\xac" // U+f16c #define ICON_FK_INSTAGRAM "\xef\x85\xad" // U+f16d #define ICON_FK_FLICKR "\xef\x85\xae" // U+f16e #define ICON_FK_ADN "\xef\x85\xb0" // U+f170 #define ICON_FK_BITBUCKET "\xef\x85\xb1" // U+f171 #define ICON_FK_BITBUCKET_SQUARE "\xef\x85\xb2" // U+f172 #define ICON_FK_TUMBLR "\xef\x85\xb3" // U+f173 #define ICON_FK_TUMBLR_SQUARE "\xef\x85\xb4" // U+f174 #define ICON_FK_LONG_ARROW_DOWN "\xef\x85\xb5" // U+f175 #define ICON_FK_LONG_ARROW_UP "\xef\x85\xb6" // U+f176 #define ICON_FK_LONG_ARROW_LEFT "\xef\x85\xb7" // U+f177 #define ICON_FK_LONG_ARROW_RIGHT "\xef\x85\xb8" // U+f178 #define ICON_FK_APPLE "\xef\x85\xb9" // U+f179 #define ICON_FK_WINDOWS "\xef\x85\xba" // U+f17a #define ICON_FK_ANDROID "\xef\x85\xbb" // U+f17b #define ICON_FK_LINUX "\xef\x85\xbc" // U+f17c #define ICON_FK_DRIBBBLE "\xef\x85\xbd" // U+f17d #define ICON_FK_SKYPE "\xef\x85\xbe" // U+f17e #define ICON_FK_FOURSQUARE "\xef\x86\x80" // U+f180 #define ICON_FK_TRELLO "\xef\x86\x81" // U+f181 #define ICON_FK_FEMALE "\xef\x86\x82" // U+f182 #define ICON_FK_MALE "\xef\x86\x83" // U+f183 #define ICON_FK_GRATIPAY "\xef\x86\x84" // U+f184 #define ICON_FK_SUN_O "\xef\x86\x85" // U+f185 #define ICON_FK_MOON_O "\xef\x86\x86" // U+f186 #define ICON_FK_ARCHIVE "\xef\x86\x87" // U+f187 #define ICON_FK_BUG "\xef\x86\x88" // U+f188 #define ICON_FK_VK "\xef\x86\x89" // U+f189 #define ICON_FK_WEIBO "\xef\x86\x8a" // U+f18a #define ICON_FK_RENREN "\xef\x86\x8b" // U+f18b #define ICON_FK_PAGELINES "\xef\x86\x8c" // U+f18c #define ICON_FK_STACK_EXCHANGE "\xef\x86\x8d" // U+f18d #define ICON_FK_ARROW_CIRCLE_O_RIGHT "\xef\x86\x8e" // U+f18e #define ICON_FK_ARROW_CIRCLE_O_LEFT "\xef\x86\x90" // U+f190 #define ICON_FK_CARET_SQUARE_O_LEFT "\xef\x86\x91" // U+f191 #define ICON_FK_DOT_CIRCLE_O "\xef\x86\x92" // U+f192 #define ICON_FK_WHEELCHAIR "\xef\x86\x93" // U+f193 #define ICON_FK_VIMEO_SQUARE "\xef\x86\x94" // U+f194 #define ICON_FK_TRY "\xef\x86\x95" // U+f195 #define ICON_FK_PLUS_SQUARE_O "\xef\x86\x96" // U+f196 #define ICON_FK_SPACE_SHUTTLE "\xef\x86\x97" // U+f197 #define ICON_FK_SLACK "\xef\x86\x98" // U+f198 #define ICON_FK_ENVELOPE_SQUARE "\xef\x86\x99" // U+f199 #define ICON_FK_WORDPRESS "\xef\x86\x9a" // U+f19a #define ICON_FK_OPENID "\xef\x86\x9b" // U+f19b #define ICON_FK_UNIVERSITY "\xef\x86\x9c" // U+f19c #define ICON_FK_GRADUATION_CAP "\xef\x86\x9d" // U+f19d #define ICON_FK_YAHOO "\xef\x86\x9e" // U+f19e #define ICON_FK_GOOGLE "\xef\x86\xa0" // U+f1a0 #define ICON_FK_REDDIT "\xef\x86\xa1" // U+f1a1 #define ICON_FK_REDDIT_SQUARE "\xef\x86\xa2" // U+f1a2 #define ICON_FK_STUMBLEUPON_CIRCLE "\xef\x86\xa3" // U+f1a3 #define ICON_FK_STUMBLEUPON "\xef\x86\xa4" // U+f1a4 #define ICON_FK_DELICIOUS "\xef\x86\xa5" // U+f1a5 #define ICON_FK_DIGG "\xef\x86\xa6" // U+f1a6 #define ICON_FK_DRUPAL "\xef\x86\xa9" // U+f1a9 #define ICON_FK_JOOMLA "\xef\x86\xaa" // U+f1aa #define ICON_FK_LANGUAGE "\xef\x86\xab" // U+f1ab #define ICON_FK_FAX "\xef\x86\xac" // U+f1ac #define ICON_FK_BUILDING "\xef\x86\xad" // U+f1ad #define ICON_FK_CHILD "\xef\x86\xae" // U+f1ae #define ICON_FK_PAW "\xef\x86\xb0" // U+f1b0 #define ICON_FK_SPOON "\xef\x86\xb1" // U+f1b1 #define ICON_FK_CUBE "\xef\x86\xb2" // U+f1b2 #define ICON_FK_CUBES "\xef\x86\xb3" // U+f1b3 #define ICON_FK_BEHANCE "\xef\x86\xb4" // U+f1b4 #define ICON_FK_BEHANCE_SQUARE "\xef\x86\xb5" // U+f1b5 #define ICON_FK_STEAM "\xef\x86\xb6" // U+f1b6 #define ICON_FK_STEAM_SQUARE "\xef\x86\xb7" // U+f1b7 #define ICON_FK_RECYCLE "\xef\x86\xb8" // U+f1b8 #define ICON_FK_CAR "\xef\x86\xb9" // U+f1b9 #define ICON_FK_TAXI "\xef\x86\xba" // U+f1ba #define ICON_FK_TREE "\xef\x86\xbb" // U+f1bb #define ICON_FK_SPOTIFY "\xef\x86\xbc" // U+f1bc #define ICON_FK_DEVIANTART "\xef\x86\xbd" // U+f1bd #define ICON_FK_SOUNDCLOUD "\xef\x86\xbe" // U+f1be #define ICON_FK_DATABASE "\xef\x87\x80" // U+f1c0 #define ICON_FK_FILE_PDF_O "\xef\x87\x81" // U+f1c1 #define ICON_FK_FILE_WORD_O "\xef\x87\x82" // U+f1c2 #define ICON_FK_FILE_EXCEL_O "\xef\x87\x83" // U+f1c3 #define ICON_FK_FILE_POWERPOINT_O "\xef\x87\x84" // U+f1c4 #define ICON_FK_FILE_IMAGE_O "\xef\x87\x85" // U+f1c5 #define ICON_FK_FILE_ARCHIVE_O "\xef\x87\x86" // U+f1c6 #define ICON_FK_FILE_AUDIO_O "\xef\x87\x87" // U+f1c7 #define ICON_FK_FILE_VIDEO_O "\xef\x87\x88" // U+f1c8 #define ICON_FK_FILE_CODE_O "\xef\x87\x89" // U+f1c9 #define ICON_FK_VINE "\xef\x87\x8a" // U+f1ca #define ICON_FK_CODEPEN "\xef\x87\x8b" // U+f1cb #define ICON_FK_JSFIDDLE "\xef\x87\x8c" // U+f1cc #define ICON_FK_LIFE_RING "\xef\x87\x8d" // U+f1cd #define ICON_FK_CIRCLE_O_NOTCH "\xef\x87\x8e" // U+f1ce #define ICON_FK_REBEL "\xef\x87\x90" // U+f1d0 #define ICON_FK_EMPIRE "\xef\x87\x91" // U+f1d1 #define ICON_FK_GIT_SQUARE "\xef\x87\x92" // U+f1d2 #define ICON_FK_GIT "\xef\x87\x93" // U+f1d3 #define ICON_FK_HACKER_NEWS "\xef\x87\x94" // U+f1d4 #define ICON_FK_TENCENT_WEIBO "\xef\x87\x95" // U+f1d5 #define ICON_FK_QQ "\xef\x87\x96" // U+f1d6 #define ICON_FK_WEIXIN "\xef\x87\x97" // U+f1d7 #define ICON_FK_PAPER_PLANE "\xef\x87\x98" // U+f1d8 #define ICON_FK_PAPER_PLANE_O "\xef\x87\x99" // U+f1d9 #define ICON_FK_HISTORY "\xef\x87\x9a" // U+f1da #define ICON_FK_CIRCLE_THIN "\xef\x87\x9b" // U+f1db #define ICON_FK_HEADER "\xef\x87\x9c" // U+f1dc #define ICON_FK_PARAGRAPH "\xef\x87\x9d" // U+f1dd #define ICON_FK_SLIDERS "\xef\x87\x9e" // U+f1de #define ICON_FK_SHARE_ALT "\xef\x87\xa0" // U+f1e0 #define ICON_FK_SHARE_ALT_SQUARE "\xef\x87\xa1" // U+f1e1 #define ICON_FK_BOMB "\xef\x87\xa2" // U+f1e2 #define ICON_FK_FUTBOL_O "\xef\x87\xa3" // U+f1e3 #define ICON_FK_TTY "\xef\x87\xa4" // U+f1e4 #define ICON_FK_BINOCULARS "\xef\x87\xa5" // U+f1e5 #define ICON_FK_PLUG "\xef\x87\xa6" // U+f1e6 #define ICON_FK_SLIDESHARE "\xef\x87\xa7" // U+f1e7 #define ICON_FK_TWITCH "\xef\x87\xa8" // U+f1e8 #define ICON_FK_YELP "\xef\x87\xa9" // U+f1e9 #define ICON_FK_NEWSPAPER_O "\xef\x87\xaa" // U+f1ea #define ICON_FK_WIFI "\xef\x87\xab" // U+f1eb #define ICON_FK_CALCULATOR "\xef\x87\xac" // U+f1ec #define ICON_FK_PAYPAL "\xef\x87\xad" // U+f1ed #define ICON_FK_GOOGLE_WALLET "\xef\x87\xae" // U+f1ee #define ICON_FK_CC_VISA "\xef\x87\xb0" // U+f1f0 #define ICON_FK_CC_MASTERCARD "\xef\x87\xb1" // U+f1f1 #define ICON_FK_CC_DISCOVER "\xef\x87\xb2" // U+f1f2 #define ICON_FK_CC_AMEX "\xef\x87\xb3" // U+f1f3 #define ICON_FK_CC_PAYPAL "\xef\x87\xb4" // U+f1f4 #define ICON_FK_CC_STRIPE "\xef\x87\xb5" // U+f1f5 #define ICON_FK_BELL_SLASH "\xef\x87\xb6" // U+f1f6 #define ICON_FK_BELL_SLASH_O "\xef\x87\xb7" // U+f1f7 #define ICON_FK_TRASH "\xef\x87\xb8" // U+f1f8 #define ICON_FK_COPYRIGHT "\xef\x87\xb9" // U+f1f9 #define ICON_FK_AT "\xef\x87\xba" // U+f1fa #define ICON_FK_EYEDROPPER "\xef\x87\xbb" // U+f1fb #define ICON_FK_PAINT_BRUSH "\xef\x87\xbc" // U+f1fc #define ICON_FK_BIRTHDAY_CAKE "\xef\x87\xbd" // U+f1fd #define ICON_FK_AREA_CHART "\xef\x87\xbe" // U+f1fe #define ICON_FK_PIE_CHART "\xef\x88\x80" // U+f200 #define ICON_FK_LINE_CHART "\xef\x88\x81" // U+f201 #define ICON_FK_LASTFM "\xef\x88\x82" // U+f202 #define ICON_FK_LASTFM_SQUARE "\xef\x88\x83" // U+f203 #define ICON_FK_TOGGLE_OFF "\xef\x88\x84" // U+f204 #define ICON_FK_TOGGLE_ON "\xef\x88\x85" // U+f205 #define ICON_FK_BICYCLE "\xef\x88\x86" // U+f206 #define ICON_FK_BUS "\xef\x88\x87" // U+f207 #define ICON_FK_IOXHOST "\xef\x88\x88" // U+f208 #define ICON_FK_ANGELLIST "\xef\x88\x89" // U+f209 #define ICON_FK_CC "\xef\x88\x8a" // U+f20a #define ICON_FK_ILS "\xef\x88\x8b" // U+f20b #define ICON_FK_MEANPATH "\xef\x88\x8c" // U+f20c #define ICON_FK_BUYSELLADS "\xef\x88\x8d" // U+f20d #define ICON_FK_CONNECTDEVELOP "\xef\x88\x8e" // U+f20e #define ICON_FK_DASHCUBE "\xef\x88\x90" // U+f210 #define ICON_FK_FORUMBEE "\xef\x88\x91" // U+f211 #define ICON_FK_LEANPUB "\xef\x88\x92" // U+f212 #define ICON_FK_SELLSY "\xef\x88\x93" // U+f213 #define ICON_FK_SHIRTSINBULK "\xef\x88\x94" // U+f214 #define ICON_FK_SIMPLYBUILT "\xef\x88\x95" // U+f215 #define ICON_FK_SKYATLAS "\xef\x88\x96" // U+f216 #define ICON_FK_CART_PLUS "\xef\x88\x97" // U+f217 #define ICON_FK_CART_ARROW_DOWN "\xef\x88\x98" // U+f218 #define ICON_FK_DIAMOND "\xef\x88\x99" // U+f219 #define ICON_FK_SHIP "\xef\x88\x9a" // U+f21a #define ICON_FK_USER_SECRET "\xef\x88\x9b" // U+f21b #define ICON_FK_MOTORCYCLE "\xef\x88\x9c" // U+f21c #define ICON_FK_STREET_VIEW "\xef\x88\x9d" // U+f21d #define ICON_FK_HEARTBEAT "\xef\x88\x9e" // U+f21e #define ICON_FK_VENUS "\xef\x88\xa1" // U+f221 #define ICON_FK_MARS "\xef\x88\xa2" // U+f222 #define ICON_FK_MERCURY "\xef\x88\xa3" // U+f223 #define ICON_FK_TRANSGENDER "\xef\x88\xa4" // U+f224 #define ICON_FK_TRANSGENDER_ALT "\xef\x88\xa5" // U+f225 #define ICON_FK_VENUS_DOUBLE "\xef\x88\xa6" // U+f226 #define ICON_FK_MARS_DOUBLE "\xef\x88\xa7" // U+f227 #define ICON_FK_VENUS_MARS "\xef\x88\xa8" // U+f228 #define ICON_FK_MARS_STROKE "\xef\x88\xa9" // U+f229 #define ICON_FK_MARS_STROKE_V "\xef\x88\xaa" // U+f22a #define ICON_FK_MARS_STROKE_H "\xef\x88\xab" // U+f22b #define ICON_FK_NEUTER "\xef\x88\xac" // U+f22c #define ICON_FK_GENDERLESS "\xef\x88\xad" // U+f22d #define ICON_FK_FACEBOOK_OFFICIAL "\xef\x88\xb0" // U+f230 #define ICON_FK_PINTEREST_P "\xef\x88\xb1" // U+f231 #define ICON_FK_WHATSAPP "\xef\x88\xb2" // U+f232 #define ICON_FK_SERVER "\xef\x88\xb3" // U+f233 #define ICON_FK_USER_PLUS "\xef\x88\xb4" // U+f234 #define ICON_FK_USER_TIMES "\xef\x88\xb5" // U+f235 #define ICON_FK_BED "\xef\x88\xb6" // U+f236 #define ICON_FK_VIACOIN "\xef\x88\xb7" // U+f237 #define ICON_FK_TRAIN "\xef\x88\xb8" // U+f238 #define ICON_FK_SUBWAY "\xef\x88\xb9" // U+f239 #define ICON_FK_MEDIUM "\xef\x88\xba" // U+f23a #define ICON_FK_MEDIUM_SQUARE "\xef\x8b\xb8" // U+f2f8 #define ICON_FK_Y_COMBINATOR "\xef\x88\xbb" // U+f23b #define ICON_FK_OPTIN_MONSTER "\xef\x88\xbc" // U+f23c #define ICON_FK_OPENCART "\xef\x88\xbd" // U+f23d #define ICON_FK_EXPEDITEDSSL "\xef\x88\xbe" // U+f23e #define ICON_FK_BATTERY_FULL "\xef\x89\x80" // U+f240 #define ICON_FK_BATTERY_THREE_QUARTERS "\xef\x89\x81" // U+f241 #define ICON_FK_BATTERY_HALF "\xef\x89\x82" // U+f242 #define ICON_FK_BATTERY_QUARTER "\xef\x89\x83" // U+f243 #define ICON_FK_BATTERY_EMPTY "\xef\x89\x84" // U+f244 #define ICON_FK_MOUSE_POINTER "\xef\x89\x85" // U+f245 #define ICON_FK_I_CURSOR "\xef\x89\x86" // U+f246 #define ICON_FK_OBJECT_GROUP "\xef\x89\x87" // U+f247 #define ICON_FK_OBJECT_UNGROUP "\xef\x89\x88" // U+f248 #define ICON_FK_STICKY_NOTE "\xef\x89\x89" // U+f249 #define ICON_FK_STICKY_NOTE_O "\xef\x89\x8a" // U+f24a #define ICON_FK_CC_JCB "\xef\x89\x8b" // U+f24b #define ICON_FK_CC_DINERS_CLUB "\xef\x89\x8c" // U+f24c #define ICON_FK_CLONE "\xef\x89\x8d" // U+f24d #define ICON_FK_BALANCE_SCALE "\xef\x89\x8e" // U+f24e #define ICON_FK_HOURGLASS_O "\xef\x89\x90" // U+f250 #define ICON_FK_HOURGLASS_START "\xef\x89\x91" // U+f251 #define ICON_FK_HOURGLASS_HALF "\xef\x89\x92" // U+f252 #define ICON_FK_HOURGLASS_END "\xef\x89\x93" // U+f253 #define ICON_FK_HOURGLASS "\xef\x89\x94" // U+f254 #define ICON_FK_HAND_ROCK_O "\xef\x89\x95" // U+f255 #define ICON_FK_HAND_PAPER_O "\xef\x89\x96" // U+f256 #define ICON_FK_HAND_SCISSORS_O "\xef\x89\x97" // U+f257 #define ICON_FK_HAND_LIZARD_O "\xef\x89\x98" // U+f258 #define ICON_FK_HAND_SPOCK_O "\xef\x89\x99" // U+f259 #define ICON_FK_HAND_POINTER_O "\xef\x89\x9a" // U+f25a #define ICON_FK_HAND_PEACE_O "\xef\x89\x9b" // U+f25b #define ICON_FK_TRADEMARK "\xef\x89\x9c" // U+f25c #define ICON_FK_REGISTERED "\xef\x89\x9d" // U+f25d #define ICON_FK_CREATIVE_COMMONS "\xef\x89\x9e" // U+f25e #define ICON_FK_GG "\xef\x89\xa0" // U+f260 #define ICON_FK_GG_CIRCLE "\xef\x89\xa1" // U+f261 #define ICON_FK_TRIPADVISOR "\xef\x89\xa2" // U+f262 #define ICON_FK_ODNOKLASSNIKI "\xef\x89\xa3" // U+f263 #define ICON_FK_ODNOKLASSNIKI_SQUARE "\xef\x89\xa4" // U+f264 #define ICON_FK_GET_POCKET "\xef\x89\xa5" // U+f265 #define ICON_FK_WIKIPEDIA_W "\xef\x89\xa6" // U+f266 #define ICON_FK_SAFARI "\xef\x89\xa7" // U+f267 #define ICON_FK_CHROME "\xef\x89\xa8" // U+f268 #define ICON_FK_FIREFOX "\xef\x89\xa9" // U+f269 #define ICON_FK_OPERA "\xef\x89\xaa" // U+f26a #define ICON_FK_INTERNET_EXPLORER "\xef\x89\xab" // U+f26b #define ICON_FK_TELEVISION "\xef\x89\xac" // U+f26c #define ICON_FK_CONTAO "\xef\x89\xad" // U+f26d #define ICON_FK_500PX "\xef\x89\xae" // U+f26e #define ICON_FK_AMAZON "\xef\x89\xb0" // U+f270 #define ICON_FK_CALENDAR_PLUS_O "\xef\x89\xb1" // U+f271 #define ICON_FK_CALENDAR_MINUS_O "\xef\x89\xb2" // U+f272 #define ICON_FK_CALENDAR_TIMES_O "\xef\x89\xb3" // U+f273 #define ICON_FK_CALENDAR_CHECK_O "\xef\x89\xb4" // U+f274 #define ICON_FK_INDUSTRY "\xef\x89\xb5" // U+f275 #define ICON_FK_MAP_PIN "\xef\x89\xb6" // U+f276 #define ICON_FK_MAP_SIGNS "\xef\x89\xb7" // U+f277 #define ICON_FK_MAP_O "\xef\x89\xb8" // U+f278 #define ICON_FK_MAP "\xef\x89\xb9" // U+f279 #define ICON_FK_COMMENTING "\xef\x89\xba" // U+f27a #define ICON_FK_COMMENTING_O "\xef\x89\xbb" // U+f27b #define ICON_FK_HOUZZ "\xef\x89\xbc" // U+f27c #define ICON_FK_VIMEO "\xef\x89\xbd" // U+f27d #define ICON_FK_BLACK_TIE "\xef\x89\xbe" // U+f27e #define ICON_FK_FONTICONS "\xef\x8a\x80" // U+f280 #define ICON_FK_REDDIT_ALIEN "\xef\x8a\x81" // U+f281 #define ICON_FK_EDGE "\xef\x8a\x82" // U+f282 #define ICON_FK_CREDIT_CARD_ALT "\xef\x8a\x83" // U+f283 #define ICON_FK_CODIEPIE "\xef\x8a\x84" // U+f284 #define ICON_FK_MODX "\xef\x8a\x85" // U+f285 #define ICON_FK_FORT_AWESOME "\xef\x8a\x86" // U+f286 #define ICON_FK_USB "\xef\x8a\x87" // U+f287 #define ICON_FK_PRODUCT_HUNT "\xef\x8a\x88" // U+f288 #define ICON_FK_MIXCLOUD "\xef\x8a\x89" // U+f289 #define ICON_FK_SCRIBD "\xef\x8a\x8a" // U+f28a #define ICON_FK_PAUSE_CIRCLE "\xef\x8a\x8b" // U+f28b #define ICON_FK_PAUSE_CIRCLE_O "\xef\x8a\x8c" // U+f28c #define ICON_FK_STOP_CIRCLE "\xef\x8a\x8d" // U+f28d #define ICON_FK_STOP_CIRCLE_O "\xef\x8a\x8e" // U+f28e #define ICON_FK_SHOPPING_BAG "\xef\x8a\x90" // U+f290 #define ICON_FK_SHOPPING_BASKET "\xef\x8a\x91" // U+f291 #define ICON_FK_HASHTAG "\xef\x8a\x92" // U+f292 #define ICON_FK_BLUETOOTH "\xef\x8a\x93" // U+f293 #define ICON_FK_BLUETOOTH_B "\xef\x8a\x94" // U+f294 #define ICON_FK_PERCENT "\xef\x8a\x95" // U+f295 #define ICON_FK_GITLAB "\xef\x8a\x96" // U+f296 #define ICON_FK_WPBEGINNER "\xef\x8a\x97" // U+f297 #define ICON_FK_WPFORMS "\xef\x8a\x98" // U+f298 #define ICON_FK_ENVIRA "\xef\x8a\x99" // U+f299 #define ICON_FK_UNIVERSAL_ACCESS "\xef\x8a\x9a" // U+f29a #define ICON_FK_WHEELCHAIR_ALT "\xef\x8a\x9b" // U+f29b #define ICON_FK_QUESTION_CIRCLE_O "\xef\x8a\x9c" // U+f29c #define ICON_FK_BLIND "\xef\x8a\x9d" // U+f29d #define ICON_FK_AUDIO_DESCRIPTION "\xef\x8a\x9e" // U+f29e #define ICON_FK_VOLUME_CONTROL_PHONE "\xef\x8a\xa0" // U+f2a0 #define ICON_FK_BRAILLE "\xef\x8a\xa1" // U+f2a1 #define ICON_FK_ASSISTIVE_LISTENING_SYSTEMS "\xef\x8a\xa2" // U+f2a2 #define ICON_FK_AMERICAN_SIGN_LANGUAGE_INTERPRETING "\xef\x8a\xa3" // U+f2a3 #define ICON_FK_DEAF "\xef\x8a\xa4" // U+f2a4 #define ICON_FK_GLIDE "\xef\x8a\xa5" // U+f2a5 #define ICON_FK_GLIDE_G "\xef\x8a\xa6" // U+f2a6 #define ICON_FK_SIGN_LANGUAGE "\xef\x8a\xa7" // U+f2a7 #define ICON_FK_LOW_VISION "\xef\x8a\xa8" // U+f2a8 #define ICON_FK_VIADEO "\xef\x8a\xa9" // U+f2a9 #define ICON_FK_VIADEO_SQUARE "\xef\x8a\xaa" // U+f2aa #define ICON_FK_SNAPCHAT "\xef\x8a\xab" // U+f2ab #define ICON_FK_SNAPCHAT_GHOST "\xef\x8a\xac" // U+f2ac #define ICON_FK_SNAPCHAT_SQUARE "\xef\x8a\xad" // U+f2ad #define ICON_FK_FIRST_ORDER "\xef\x8a\xb0" // U+f2b0 #define ICON_FK_YOAST "\xef\x8a\xb1" // U+f2b1 #define ICON_FK_THEMEISLE "\xef\x8a\xb2" // U+f2b2 #define ICON_FK_GOOGLE_PLUS_OFFICIAL "\xef\x8a\xb3" // U+f2b3 #define ICON_FK_FONT_AWESOME "\xef\x8a\xb4" // U+f2b4 #define ICON_FK_HANDSHAKE_O "\xef\x8a\xb5" // U+f2b5 #define ICON_FK_ENVELOPE_OPEN "\xef\x8a\xb6" // U+f2b6 #define ICON_FK_ENVELOPE_OPEN_O "\xef\x8a\xb7" // U+f2b7 #define ICON_FK_LINODE "\xef\x8a\xb8" // U+f2b8 #define ICON_FK_ADDRESS_BOOK "\xef\x8a\xb9" // U+f2b9 #define ICON_FK_ADDRESS_BOOK_O "\xef\x8a\xba" // U+f2ba #define ICON_FK_ADDRESS_CARD "\xef\x8a\xbb" // U+f2bb #define ICON_FK_ADDRESS_CARD_O "\xef\x8a\xbc" // U+f2bc #define ICON_FK_USER_CIRCLE "\xef\x8a\xbd" // U+f2bd #define ICON_FK_USER_CIRCLE_O "\xef\x8a\xbe" // U+f2be #define ICON_FK_USER_O "\xef\x8b\x80" // U+f2c0 #define ICON_FK_ID_BADGE "\xef\x8b\x81" // U+f2c1 #define ICON_FK_ID_CARD "\xef\x8b\x82" // U+f2c2 #define ICON_FK_ID_CARD_O "\xef\x8b\x83" // U+f2c3 #define ICON_FK_QUORA "\xef\x8b\x84" // U+f2c4 #define ICON_FK_FREE_CODE_CAMP "\xef\x8b\x85" // U+f2c5 #define ICON_FK_TELEGRAM "\xef\x8b\x86" // U+f2c6 #define ICON_FK_THERMOMETER_FULL "\xef\x8b\x87" // U+f2c7 #define ICON_FK_THERMOMETER_THREE_QUARTERS "\xef\x8b\x88" // U+f2c8 #define ICON_FK_THERMOMETER_HALF "\xef\x8b\x89" // U+f2c9 #define ICON_FK_THERMOMETER_QUARTER "\xef\x8b\x8a" // U+f2ca #define ICON_FK_THERMOMETER_EMPTY "\xef\x8b\x8b" // U+f2cb #define ICON_FK_SHOWER "\xef\x8b\x8c" // U+f2cc #define ICON_FK_BATH "\xef\x8b\x8d" // U+f2cd #define ICON_FK_PODCAST "\xef\x8b\x8e" // U+f2ce #define ICON_FK_WINDOW_MAXIMIZE "\xef\x8b\x90" // U+f2d0 #define ICON_FK_WINDOW_MINIMIZE "\xef\x8b\x91" // U+f2d1 #define ICON_FK_WINDOW_RESTORE "\xef\x8b\x92" // U+f2d2 #define ICON_FK_WINDOW_CLOSE "\xef\x8b\x93" // U+f2d3 #define ICON_FK_WINDOW_CLOSE_O "\xef\x8b\x94" // U+f2d4 #define ICON_FK_BANDCAMP "\xef\x8b\x95" // U+f2d5 #define ICON_FK_GRAV "\xef\x8b\x96" // U+f2d6 #define ICON_FK_ETSY "\xef\x8b\x97" // U+f2d7 #define ICON_FK_IMDB "\xef\x8b\x98" // U+f2d8 #define ICON_FK_RAVELRY "\xef\x8b\x99" // U+f2d9 #define ICON_FK_EERCAST "\xef\x8b\x9a" // U+f2da #define ICON_FK_MICROCHIP "\xef\x8b\x9b" // U+f2db #define ICON_FK_SNOWFLAKE_O "\xef\x8b\x9c" // U+f2dc #define ICON_FK_SUPERPOWERS "\xef\x8b\x9d" // U+f2dd #define ICON_FK_WPEXPLORER "\xef\x8b\x9e" // U+f2de #define ICON_FK_MEETUP "\xef\x8b\xa0" // U+f2e0 #define ICON_FK_MASTODON "\xef\x8b\xa1" // U+f2e1 #define ICON_FK_MASTODON_ALT "\xef\x8b\xa2" // U+f2e2 #define ICON_FK_FORK_AWESOME "\xef\x8b\xa3" // U+f2e3 #define ICON_FK_PEERTUBE "\xef\x8b\xa4" // U+f2e4 #define ICON_FK_DIASPORA "\xef\x8b\xa5" // U+f2e5 #define ICON_FK_FRIENDICA "\xef\x8b\xa6" // U+f2e6 #define ICON_FK_GNU_SOCIAL "\xef\x8b\xa7" // U+f2e7 #define ICON_FK_LIBERAPAY_SQUARE "\xef\x8b\xa8" // U+f2e8 #define ICON_FK_LIBERAPAY "\xef\x8b\xa9" // U+f2e9 #define ICON_FK_SCUTTLEBUTT "\xef\x8b\xaa" // U+f2ea #define ICON_FK_HUBZILLA "\xef\x8b\xab" // U+f2eb #define ICON_FK_SOCIAL_HOME "\xef\x8b\xac" // U+f2ec #define ICON_FK_ARTSTATION "\xef\x8b\xad" // U+f2ed #define ICON_FK_DISCORD "\xef\x8b\xae" // U+f2ee #define ICON_FK_DISCORD_ALT "\xef\x8b\xaf" // U+f2ef #define ICON_FK_PATREON "\xef\x8b\xb0" // U+f2f0 #define ICON_FK_SNOWDRIFT "\xef\x8b\xb1" // U+f2f1 #define ICON_FK_ACTIVITYPUB "\xef\x8b\xb2" // U+f2f2 #define ICON_FK_ETHEREUM "\xef\x8b\xb3" // U+f2f3 #define ICON_FK_KEYBASE "\xef\x8b\xb4" // U+f2f4 #define ICON_FK_SHAARLI "\xef\x8b\xb5" // U+f2f5 #define ICON_FK_SHAARLI_O "\xef\x8b\xb6" // U+f2f6 #define ICON_FK_KEY_MODERN "\xef\x8b\xb7" // U+f2f7 #define ICON_FK_XMPP "\xef\x8b\xb9" // U+f2f9 #define ICON_FK_ARCHIVE_ORG "\xef\x8b\xbc" // U+f2fc #define ICON_FK_FREEDOMBOX "\xef\x8b\xbd" // U+f2fd #define ICON_FK_FACEBOOK_MESSENGER "\xef\x8b\xbe" // U+f2fe #define ICON_FK_DEBIAN "\xef\x8b\xbf" // U+f2ff #define ICON_FK_MASTODON_SQUARE "\xef\x8c\x80" // U+f300 #define ICON_FK_TIPEEE "\xef\x8c\x81" // U+f301 #define ICON_FK_REACT "\xef\x8c\x82" // U+f302 #define ICON_FK_DOGMAZIC "\xef\x8c\x83" // U+f303 #define ICON_FK_ZOTERO "\xef\x8c\x89" // U+f309 #define ICON_FK_NODEJS "\xef\x8c\x88" // U+f308 #define ICON_FK_NEXTCLOUD "\xef\x8c\x86" // U+f306 #define ICON_FK_NEXTCLOUD_SQUARE "\xef\x8c\x87" // U+f307 #define ICON_FK_HACKADAY "\xef\x8c\x8a" // U+f30a #define ICON_FK_LARAVEL "\xef\x8c\x8b" // U+f30b #define ICON_FK_SIGNALAPP "\xef\x8c\x8c" // U+f30c #define ICON_FK_GNUPG "\xef\x8c\x8d" // U+f30d #define ICON_FK_PHP "\xef\x8c\x8e" // U+f30e #define ICON_FK_FFMPEG "\xef\x8c\x8f" // U+f30f #define ICON_FK_JOPLIN "\xef\x8c\x90" // U+f310 #define ICON_FK_SYNCTHING "\xef\x8c\x91" // U+f311 #define ICON_FK_INKSCAPE "\xef\x8c\x92" // U+f312 #define ICON_FK_MATRIX_ORG "\xef\x8c\x93" // U+f313 #define ICON_FK_PIXELFED "\xef\x8c\x94" // U+f314 #define ICON_FK_BOOTSTRAP "\xef\x8c\x95" // U+f315 #define ICON_FK_DEV_TO "\xef\x8c\x96" // U+f316 #define ICON_FK_HASHNODE "\xef\x8c\x97" // U+f317 #define ICON_FK_JIRAFEAU "\xef\x8c\x98" // U+f318 #define ICON_FK_EMBY "\xef\x8c\x99" // U+f319 #define ICON_FK_WIKIDATA "\xef\x8c\x9a" // U+f31a #define ICON_FK_GIMP "\xef\x8c\x9b" // U+f31b #define ICON_FK_C "\xef\x8c\x9c" // U+f31c #define ICON_FK_DIGITALOCEAN "\xef\x8c\x9d" // U+f31d #define ICON_FK_ATT "\xef\x8c\x9e" // U+f31e #define ICON_FK_GITEA "\xef\x8c\x9f" // U+f31f #define ICON_FK_FILE_EPUB "\xef\x8c\xa1" // U+f321 #define ICON_FK_PYTHON "\xef\x8c\xa2" // U+f322 #define ICON_FK_ARCHLINUX "\xef\x8c\xa3" // U+f323 #define ICON_FK_PLEROMA "\xef\x8c\xa4" // U+f324 #define ICON_FK_UNSPLASH "\xef\x8c\xa5" // U+f325 #define ICON_FK_HACKSTER "\xef\x8c\xa6" // U+f326 #define ICON_FK_SPELL_CHECK "\xef\x8c\xa7" // U+f327 #define ICON_FK_MOON "\xef\x8c\xa8" // U+f328 #define ICON_FK_SUN "\xef\x8c\xa9" // U+f329 #define ICON_FK_F_DROID "\xef\x8c\xaa" // U+f32a #define ICON_FK_BIOMETRIC "\xef\x8c\xab" // U+f32b #define ICON_FK_WIRE "\xef\x8c\xac" // U+f32c #define ICON_FK_TOR_ONION "\xef\x8c\xae" // U+f32e #define ICON_FK_VOLUME_MUTE "\xef\x8c\xaf" // U+f32f #define ICON_FK_BELL_RINGING "\xef\x8c\xad" // U+f32d #define ICON_FK_BELL_RINGING_O "\xef\x8c\xb0" // U+f330 #define ICON_FK_HAL "\xef\x8c\xb3" // U+f333 #define ICON_FK_JUPYTER "\xef\x8c\xb5" // U+f335 #define ICON_FK_JULIA "\xef\x8c\xb4" // U+f334 #define ICON_FK_CLASSICPRESS "\xef\x8c\xb1" // U+f331 #define ICON_FK_CLASSICPRESS_CIRCLE "\xef\x8c\xb2" // U+f332 #define ICON_FK_OPEN_COLLECTIVE "\xef\x8c\xb6" // U+f336 #define ICON_FK_ORCID "\xef\x8c\xb7" // U+f337 #define ICON_FK_RESEARCHGATE "\xef\x8c\xb8" // U+f338 #define ICON_FK_FUNKWHALE "\xef\x8c\xb9" // U+f339 #define ICON_FK_ASKFM "\xef\x8c\xba" // U+f33a #define ICON_FK_BLOCKSTACK "\xef\x8c\xbb" // U+f33b #define ICON_FK_BOARDGAMEGEEK "\xef\x8c\xbc" // U+f33c #define ICON_FK_BUNNY "\xef\x8d\x9f" // U+f35f #define ICON_FK_BUYMEACOFFEE "\xef\x8c\xbd" // U+f33d #define ICON_FK_CC_BY "\xef\x8c\xbe" // U+f33e #define ICON_FK_CC_CC "\xef\x8c\xbf" // U+f33f #define ICON_FK_CC_NC_EU "\xef\x8d\x81" // U+f341 #define ICON_FK_CC_NC_JP "\xef\x8d\x82" // U+f342 #define ICON_FK_CC_NC "\xef\x8d\x80" // U+f340 #define ICON_FK_CC_ND "\xef\x8d\x83" // U+f343 #define ICON_FK_CC_PD "\xef\x8d\x84" // U+f344 #define ICON_FK_CC_REMIX "\xef\x8d\x85" // U+f345 #define ICON_FK_CC_SA "\xef\x8d\x86" // U+f346 #define ICON_FK_CC_SHARE "\xef\x8d\x87" // U+f347 #define ICON_FK_CC_ZERO "\xef\x8d\x88" // U+f348 #define ICON_FK_CONWAY_GLIDER "\xef\x8d\x89" // U+f349 #define ICON_FK_CSHARP "\xef\x8d\x8a" // U+f34a #define ICON_FK_EMAIL_BULK "\xef\x8d\x8b" // U+f34b #define ICON_FK_EMAIL_BULK_O "\xef\x8d\x8c" // U+f34c #define ICON_FK_GNU "\xef\x8d\x8d" // U+f34d #define ICON_FK_GOOGLE_PLAY "\xef\x8d\x8e" // U+f34e #define ICON_FK_HEROKU "\xef\x8d\x8f" // U+f34f #define ICON_FK_HOME_ASSISTANT "\xef\x8d\x90" // U+f350 #define ICON_FK_JAVA "\xef\x8d\x91" // U+f351 #define ICON_FK_MARIADB "\xef\x8d\x92" // U+f352 #define ICON_FK_MARKDOWN "\xef\x8d\x93" // U+f353 #define ICON_FK_MYSQL "\xef\x8d\x94" // U+f354 #define ICON_FK_NORDCAST "\xef\x8d\x95" // U+f355 #define ICON_FK_PLUME "\xef\x8d\x96" // U+f356 #define ICON_FK_POSTGRESQL "\xef\x8d\x97" // U+f357 #define ICON_FK_SASS_ALT "\xef\x8d\x99" // U+f359 #define ICON_FK_SASS "\xef\x8d\x98" // U+f358 #define ICON_FK_SKATE "\xef\x8d\x9a" // U+f35a #define ICON_FK_SKETCHFAB "\xef\x8d\x9b" // U+f35b #define ICON_FK_TEX "\xef\x8d\x9c" // U+f35c #define ICON_FK_TEXTPATTERN "\xef\x8d\x9d" // U+f35d #define ICON_FK_UNITY "\xef\x8d\x9e" // U+f35e ================================================ FILE: include/KHR/khrplatform.h ================================================ #ifndef __khrplatform_h_ #define __khrplatform_h_ /* ** Copyright (c) 2008-2018 The Khronos Group Inc. ** ** Permission is hereby granted, free of charge, to any person obtaining a ** copy of this software and/or associated documentation files (the ** "Materials"), to deal in the Materials without restriction, including ** without limitation the rights to use, copy, modify, merge, publish, ** distribute, sublicense, and/or sell copies of the Materials, and to ** permit persons to whom the Materials are furnished to do so, subject to ** the following conditions: ** ** The above copyright notice and this permission notice shall be included ** in all copies or substantial portions of the Materials. ** ** THE MATERIALS ARE 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 OR COPYRIGHT HOLDERS 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 ** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. */ /* Khronos platform-specific types and definitions. * * The master copy of khrplatform.h is maintained in the Khronos EGL * Registry repository at https://github.com/KhronosGroup/EGL-Registry * The last semantic modification to khrplatform.h was at commit ID: * 67a3e0864c2d75ea5287b9f3d2eb74a745936692 * * Adopters may modify this file to suit their platform. Adopters are * encouraged to submit platform specific modifications to the Khronos * group so that they can be included in future versions of this file. * Please submit changes by filing pull requests or issues on * the EGL Registry repository linked above. * * * See the Implementer's Guidelines for information about where this file * should be located on your system and for more details of its use: * http://www.khronos.org/registry/implementers_guide.pdf * * This file should be included as * #include * by Khronos client API header files that use its types and defines. * * The types in khrplatform.h should only be used to define API-specific types. * * Types defined in khrplatform.h: * khronos_int8_t signed 8 bit * khronos_uint8_t unsigned 8 bit * khronos_int16_t signed 16 bit * khronos_uint16_t unsigned 16 bit * khronos_int32_t signed 32 bit * khronos_uint32_t unsigned 32 bit * khronos_int64_t signed 64 bit * khronos_uint64_t unsigned 64 bit * khronos_intptr_t signed same number of bits as a pointer * khronos_uintptr_t unsigned same number of bits as a pointer * khronos_ssize_t signed size * khronos_usize_t unsigned size * khronos_float_t signed 32 bit floating point * khronos_time_ns_t unsigned 64 bit time in nanoseconds * khronos_utime_nanoseconds_t unsigned time interval or absolute time in * nanoseconds * khronos_stime_nanoseconds_t signed time interval in nanoseconds * khronos_boolean_enum_t enumerated boolean type. This should * only be used as a base type when a client API's boolean type is * an enum. Client APIs which use an integer or other type for * booleans cannot use this as the base type for their boolean. * * Tokens defined in khrplatform.h: * * KHRONOS_FALSE, KHRONOS_TRUE Enumerated boolean false/true values. * * KHRONOS_SUPPORT_INT64 is 1 if 64 bit integers are supported; otherwise 0. * KHRONOS_SUPPORT_FLOAT is 1 if floats are supported; otherwise 0. * * Calling convention macros defined in this file: * KHRONOS_APICALL * KHRONOS_APIENTRY * KHRONOS_APIATTRIBUTES * * These may be used in function prototypes as: * * KHRONOS_APICALL void KHRONOS_APIENTRY funcname( * int arg1, * int arg2) KHRONOS_APIATTRIBUTES; */ #if defined(__SCITECH_SNAP__) && !defined(KHRONOS_STATIC) # define KHRONOS_STATIC 1 #endif /*------------------------------------------------------------------------- * Definition of KHRONOS_APICALL *------------------------------------------------------------------------- * This precedes the return type of the function in the function prototype. */ #if defined(KHRONOS_STATIC) /* If the preprocessor constant KHRONOS_STATIC is defined, make the * header compatible with static linking. */ # define KHRONOS_APICALL #elif defined(_WIN32) # define KHRONOS_APICALL __declspec(dllimport) #elif defined (__SYMBIAN32__) # define KHRONOS_APICALL IMPORT_C #elif defined(__ANDROID__) # define KHRONOS_APICALL __attribute__((visibility("default"))) #else # define KHRONOS_APICALL #endif /*------------------------------------------------------------------------- * Definition of KHRONOS_APIENTRY *------------------------------------------------------------------------- * This follows the return type of the function and precedes the function * name in the function prototype. */ #if defined(_WIN32) && !defined(_WIN32_WCE) && !defined(KHRONOS_STATIC) /* Win32 but not WinCE */ # define KHRONOS_APIENTRY __stdcall #else # define KHRONOS_APIENTRY #endif /*------------------------------------------------------------------------- * Definition of KHRONOS_APIATTRIBUTES *------------------------------------------------------------------------- * This follows the closing parenthesis of the function prototype arguments. */ #if defined (__ARMCC_2__) #define KHRONOS_APIATTRIBUTES __softfp #else #define KHRONOS_APIATTRIBUTES #endif /*------------------------------------------------------------------------- * basic type definitions *-----------------------------------------------------------------------*/ #if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(__GNUC__) || defined(__SCO__) || defined(__USLC__) /* * Using */ #include typedef int32_t khronos_int32_t; typedef uint32_t khronos_uint32_t; typedef int64_t khronos_int64_t; typedef uint64_t khronos_uint64_t; #define KHRONOS_SUPPORT_INT64 1 #define KHRONOS_SUPPORT_FLOAT 1 #elif defined(__VMS ) || defined(__sgi) /* * Using */ #include typedef int32_t khronos_int32_t; typedef uint32_t khronos_uint32_t; typedef int64_t khronos_int64_t; typedef uint64_t khronos_uint64_t; #define KHRONOS_SUPPORT_INT64 1 #define KHRONOS_SUPPORT_FLOAT 1 #elif defined(_WIN32) && !defined(__SCITECH_SNAP__) /* * Win32 */ typedef __int32 khronos_int32_t; typedef unsigned __int32 khronos_uint32_t; typedef __int64 khronos_int64_t; typedef unsigned __int64 khronos_uint64_t; #define KHRONOS_SUPPORT_INT64 1 #define KHRONOS_SUPPORT_FLOAT 1 #elif defined(__sun__) || defined(__digital__) /* * Sun or Digital */ typedef int khronos_int32_t; typedef unsigned int khronos_uint32_t; #if defined(__arch64__) || defined(_LP64) typedef long int khronos_int64_t; typedef unsigned long int khronos_uint64_t; #else typedef long long int khronos_int64_t; typedef unsigned long long int khronos_uint64_t; #endif /* __arch64__ */ #define KHRONOS_SUPPORT_INT64 1 #define KHRONOS_SUPPORT_FLOAT 1 #elif 0 /* * Hypothetical platform with no float or int64 support */ typedef int khronos_int32_t; typedef unsigned int khronos_uint32_t; #define KHRONOS_SUPPORT_INT64 0 #define KHRONOS_SUPPORT_FLOAT 0 #else /* * Generic fallback */ #include typedef int32_t khronos_int32_t; typedef uint32_t khronos_uint32_t; typedef int64_t khronos_int64_t; typedef uint64_t khronos_uint64_t; #define KHRONOS_SUPPORT_INT64 1 #define KHRONOS_SUPPORT_FLOAT 1 #endif /* * Types that are (so far) the same on all platforms */ typedef signed char khronos_int8_t; typedef unsigned char khronos_uint8_t; typedef signed short int khronos_int16_t; typedef unsigned short int khronos_uint16_t; /* * Types that differ between LLP64 and LP64 architectures - in LLP64, * pointers are 64 bits, but 'long' is still 32 bits. Win64 appears * to be the only LLP64 architecture in current use. */ #ifdef _WIN64 typedef signed long long int khronos_intptr_t; typedef unsigned long long int khronos_uintptr_t; typedef signed long long int khronos_ssize_t; typedef unsigned long long int khronos_usize_t; #else typedef signed long int khronos_intptr_t; typedef unsigned long int khronos_uintptr_t; typedef signed long int khronos_ssize_t; typedef unsigned long int khronos_usize_t; #endif #if KHRONOS_SUPPORT_FLOAT /* * Float type */ typedef float khronos_float_t; #endif #if KHRONOS_SUPPORT_INT64 /* Time types * * These types can be used to represent a time interval in nanoseconds or * an absolute Unadjusted System Time. Unadjusted System Time is the number * of nanoseconds since some arbitrary system event (e.g. since the last * time the system booted). The Unadjusted System Time is an unsigned * 64 bit value that wraps back to 0 every 584 years. Time intervals * may be either signed or unsigned. */ typedef khronos_uint64_t khronos_utime_nanoseconds_t; typedef khronos_int64_t khronos_stime_nanoseconds_t; #endif /* * Dummy value used to pad enum types to 32 bits. */ #ifndef KHRONOS_MAX_ENUM #define KHRONOS_MAX_ENUM 0x7FFFFFFF #endif /* * Enumerated boolean type * * Values other than zero should be considered to be true. Therefore * comparisons should not be made against KHRONOS_TRUE. */ typedef enum { KHRONOS_FALSE = 0, KHRONOS_TRUE = 1, KHRONOS_BOOLEAN_ENUM_FORCE_SIZE = KHRONOS_MAX_ENUM } khronos_boolean_enum_t; #endif /* __khrplatform_h_ */ ================================================ FILE: include/elfhacks.h ================================================ /** * \file src/elfhacks.h * \brief elfhacks application interface * \author Pyry Haulos * \date 2007-2008 */ /* elfhacks.h -- Various ELF run-time hacks version 0.4.1, March 9th, 2008 Copyright (C) 2007-2008 Pyry Haulos This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. Pyry Haulos */ #pragma once #include #include #include #ifdef __cplusplus extern "C" { #endif //#define __PUBLIC __attribute__ ((visibility ("default"))) #define __PUBLIC #if UINTPTR_MAX == 0xffffffffffffffff # define __elf64 #else # define __elf32 #endif #ifdef __elf64 # define ELFW_R_SYM ELF64_R_SYM # define ElfW_Sword Elf64_Sxword #else # ifdef __elf32 # define ELFW_R_SYM ELF32_R_SYM # define ElfW_Sword Elf32_Sword # else # error neither __elf32 nor __elf64 is defined # endif #endif /** * \defgroup elfhacks elfhacks * Elfhacks is a collection of functions that aim for retvieving * or modifying progam's dynamic linking information at run-time. * \{ */ /** * \brief elfhacks program object */ typedef struct { /** file name */ const char *name; /** base address in memory */ ElfW(Addr) addr; /** program headers */ const ElfW(Phdr) *phdr; /** number of program headers */ ElfW(Half) phnum; /** .dynamic */ ElfW(Dyn) *dynamic; /** .symtab */ ElfW(Sym) *symtab; /** .strtab */ const char *strtab; /** symbol hash table (DT_HASH) */ ElfW(Word) *hash; /** symbol hash table (DT_GNU_HASH) */ Elf32_Word *gnu_hash; } eh_obj_t; /** * \brief elfhacks symbol */ typedef struct { /** symbol name */ const char *name; /** corresponding ElfW(Sym) */ ElfW(Sym) *sym; /** elfhacks object this symbol is associated to */ eh_obj_t *obj; } eh_sym_t; /** * \brief elfhacks relocation */ typedef struct { /** symbol this relocation is associated to */ eh_sym_t *sym; /** corresponding ElfW(Rel) (NULL if this is Rela) */ ElfW(Rel) *rel; /** corresponding ElfW(Rela) (NULL if this is Rel) */ ElfW(Rela) *rela; /** elfhacks program object */ eh_obj_t *obj; } eh_rel_t; /** * \brief Iterate objects callback */ typedef int (*eh_iterate_obj_callback_func)(eh_obj_t *obj, void *arg); /** * \brief Iterate symbols callback */ typedef int (*eh_iterate_sym_callback_func)(eh_sym_t *sym, void *arg); /** * \brief Iterate relocations callback */ typedef int (*eh_iterate_rel_callback_func)(eh_rel_t *rel, void *arg); /** * \brief Initializes eh_obj_t for given soname * * Matching is done using fnmatch() so wildcards and other standard * filename metacharacters and expressions work. * * If soname is NULL, this function returns the main program object. * \param obj elfhacks object * \param soname object's soname (see /proc/pid/maps) or NULL for main * \return 0 on success otherwise a positive error code */ __PUBLIC int eh_find_obj(eh_obj_t *obj, const char *soname); /** * \brief Walk through list of objects * \param callback callback function * \param arg argument passed to callback function * \return 0 on success otherwise an error code */ __PUBLIC int eh_iterate_obj(eh_iterate_obj_callback_func callback, void *arg); /** * \brief Finds symbol in object's .dynsym and retrvieves its value. * \param obj elfhacks program object * \param name symbol to find * \param to returned value * \return 0 on success otherwise a positive error code */ __PUBLIC int eh_find_sym(eh_obj_t *obj, const char *name, void **to); /** * \brief Walk through list of symbols in object * \param obj elfhacks program object * \param callback callback function * \param arg argument passed to callback function * \return 0 on success otherwise an error code */ __PUBLIC int eh_iterate_sym(eh_obj_t *obj, eh_iterate_sym_callback_func callback, void *arg); /** * \brief Iterates through object's .rel.plt and .rela.plt and sets every * occurrence of some symbol to the specified value. * \param obj elfhacks program object * \param sym symbol to replace * \param val new value * \return 0 on success otherwise a positive error code */ __PUBLIC int eh_set_rel(eh_obj_t *obj, const char *sym, void *val); /** * \brief Walk through object's .rel.plt and .rela.plt * \param obj elfhacks program object * \param callback callback function * \param arg argument passed to callback function */ __PUBLIC int eh_iterate_rel(eh_obj_t *obj, eh_iterate_rel_callback_func callback, void *arg); /** * \brief Destroy eh_obj_t object. * \param obj elfhacks program object * \return 0 on success otherwise a positive error code */ __PUBLIC int eh_destroy_obj(eh_obj_t *obj); /** \} */ #ifdef __cplusplus } #endif ================================================ FILE: include/filesystem.h ================================================ //--------------------------------------------------------------------------------------- // // ghc::filesystem - A C++17-like filesystem implementation for C++11/C++14/C++17/C++20 // //--------------------------------------------------------------------------------------- // // Copyright (c) 2018, Steffen Schümann // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in all // copies or substantial portions of the Software. // // 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 OR COPYRIGHT HOLDERS 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. // //--------------------------------------------------------------------------------------- // // To dynamically select std::filesystem where available on most platforms, // you could use: // // #if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || (defined(__cplusplus) && __cplusplus >= 201703L)) && defined(__has_include) // #if __has_include() && (!defined(__MAC_OS_X_VERSION_MIN_REQUIRED) || __MAC_OS_X_VERSION_MIN_REQUIRED >= 101500) // #define GHC_USE_STD_FS // #include // namespace fs = std::filesystem; // #endif // #endif // #ifndef GHC_USE_STD_FS // #include // namespace fs = ghc::filesystem; // #endif // //--------------------------------------------------------------------------------------- #ifndef GHC_FILESYSTEM_H #define GHC_FILESYSTEM_H // #define BSD manifest constant only in // sys/param.h #ifndef _WIN32 #include #endif #ifndef GHC_OS_DETECTED #if defined(__APPLE__) && defined(__MACH__) #define GHC_OS_MACOS #elif defined(__linux__) #define GHC_OS_LINUX #if defined(__ANDROID__) #define GHC_OS_ANDROID #endif #elif defined(_WIN64) #define GHC_OS_WINDOWS #define GHC_OS_WIN64 #elif defined(_WIN32) #define GHC_OS_WINDOWS #define GHC_OS_WIN32 #elif defined(__CYGWIN__) #define GHC_OS_CYGWIN #elif defined(__svr4__) #define GHC_OS_SYS5R4 #elif defined(BSD) #define GHC_OS_BSD #elif defined(__EMSCRIPTEN__) #define GHC_OS_WEB #include #else #error "Operating system currently not supported!" #endif #define GHC_OS_DETECTED #if (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) #if _MSVC_LANG == 201703L #define GHC_FILESYSTEM_RUNNING_CPP17 #else #define GHC_FILESYSTEM_RUNNING_CPP20 #endif #elif (defined(__cplusplus) && __cplusplus >= 201703L) #if __cplusplus == 201703L #define GHC_FILESYSTEM_RUNNING_CPP17 #else #define GHC_FILESYSTEM_RUNNING_CPP20 #endif #endif #endif #if defined(GHC_FILESYSTEM_IMPLEMENTATION) #define GHC_EXPAND_IMPL #define GHC_INLINE #ifdef GHC_OS_WINDOWS #ifndef GHC_FS_API #define GHC_FS_API #endif #ifndef GHC_FS_API_CLASS #define GHC_FS_API_CLASS #endif #else #ifndef GHC_FS_API #define GHC_FS_API __attribute__((visibility("default"))) #endif #ifndef GHC_FS_API_CLASS #define GHC_FS_API_CLASS __attribute__((visibility("default"))) #endif #endif #elif defined(GHC_FILESYSTEM_FWD) #define GHC_INLINE #ifdef GHC_OS_WINDOWS #ifndef GHC_FS_API #define GHC_FS_API extern #endif #ifndef GHC_FS_API_CLASS #define GHC_FS_API_CLASS #endif #else #ifndef GHC_FS_API #define GHC_FS_API extern #endif #ifndef GHC_FS_API_CLASS #define GHC_FS_API_CLASS #endif #endif #else #define GHC_EXPAND_IMPL #define GHC_INLINE inline #ifndef GHC_FS_API #define GHC_FS_API #endif #ifndef GHC_FS_API_CLASS #define GHC_FS_API_CLASS #endif #endif #ifdef GHC_EXPAND_IMPL #ifdef GHC_OS_WINDOWS #include // additional includes #include #include #include #include #include #else #include #include #include #include #include #include #include #include #ifdef GHC_OS_ANDROID #include #if __ANDROID_API__ < 12 #include #endif #include #define statvfs statfs #else #include #endif #ifdef GHC_OS_CYGWIN #include #endif #if !defined(__ANDROID__) || __ANDROID_API__ >= 26 #include #endif #endif #ifdef GHC_OS_MACOS #include #endif #if defined(__cpp_impl_three_way_comparison) && defined(__has_include) #if __has_include() #define GHC_HAS_THREEWAY_COMP #include #endif #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #else // GHC_EXPAND_IMPL #if defined(__cpp_impl_three_way_comparison) && defined(__has_include) #if __has_include() #define GHC_HAS_THREEWAY_COMP #include #endif #endif #include #include #include #include #include #include #include #ifdef GHC_OS_WINDOWS #include #endif #endif // GHC_EXPAND_IMPL // After standard library includes. // Standard library support for std::string_view. #if defined(__cpp_lib_string_view) #define GHC_HAS_STD_STRING_VIEW #elif defined(_LIBCPP_VERSION) && (_LIBCPP_VERSION >= 4000) && (__cplusplus >= 201402) #define GHC_HAS_STD_STRING_VIEW #elif defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE >= 7) && (__cplusplus >= 201703) #define GHC_HAS_STD_STRING_VIEW #elif defined(_MSC_VER) && (_MSC_VER >= 1910 && _MSVC_LANG >= 201703) #define GHC_HAS_STD_STRING_VIEW #endif // Standard library support for std::experimental::string_view. #if defined(_LIBCPP_VERSION) && (_LIBCPP_VERSION >= 3700 && _LIBCPP_VERSION < 7000) && (__cplusplus >= 201402) #define GHC_HAS_STD_EXPERIMENTAL_STRING_VIEW #elif defined(__GNUC__) && (((__GNUC__ == 4) && (__GNUC_MINOR__ >= 9)) || (__GNUC__ > 4)) && (__cplusplus >= 201402) #define GHC_HAS_STD_EXPERIMENTAL_STRING_VIEW #endif #if defined(GHC_HAS_STD_STRING_VIEW) #include #elif defined(GHC_HAS_STD_EXPERIMENTAL_STRING_VIEW) #include #endif //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Behaviour Switches (see README.md, should match the config in test/filesystem_test.cpp): //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Enforce C++17 API where possible when compiling for C++20, handles the following cases: // * fs::path::u8string() returns std::string instead of std::u8string // #define GHC_FILESYSTEM_ENFORCE_CPP17_API //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // LWG #2682 disables the since then invalid use of the copy option create_symlinks on directories // configure LWG conformance () #define LWG_2682_BEHAVIOUR //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // LWG #2395 makes crate_directory/create_directories not emit an error if there is a regular // file with that name, it is superseded by P1164R1, so only activate if really needed // #define LWG_2935_BEHAVIOUR //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // LWG #2936 enables new element wise (more expensive) path comparison // * if this->root_name().native().compare(p.root_name().native()) != 0 return result // * if this->has_root_directory() and !p.has_root_directory() return -1 // * if !this->has_root_directory() and p.has_root_directory() return -1 // * else result of element wise comparison of path iteration where first comparison is != 0 or 0 // if all comparisons are 0 (on Windows this implementation does case insensitive root_name() // comparison) #define LWG_2936_BEHAVIOUR //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // LWG #2937 enforces that fs::equivalent emits an error, if !fs::exists(p1)||!exists(p2) #define LWG_2937_BEHAVIOUR //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // UTF8-Everywhere is the original behaviour of ghc::filesystem. But since v1.5 the windows // version defaults to std::wstring storage backend. Still all std::string will be interpreted // as UTF-8 encoded. With this define you can enfoce the old behavior on Windows, using // std::string as backend and for fs::path::native() and char for fs::path::c_str(). This // needs more conversions so it is (an was before v1.5) slower, bot might help keeping source // homogeneous in a multi platform project. // #define GHC_WIN_DISABLE_WSTRING_STORAGE_TYPE //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Raise errors/exceptions when invalid unicode codepoints or UTF-8 sequences are found, // instead of replacing them with the unicode replacement character (U+FFFD). // #define GHC_RAISE_UNICODE_ERRORS //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Automatic prefix windows path with "\\?\" if they would break the MAX_PATH length. // instead of replacing them with the unicode replacement character (U+FFFD). #ifndef GHC_WIN_DISABLE_AUTO_PREFIXES #define GHC_WIN_AUTO_PREFIX_LONG_PATH #endif // GHC_WIN_DISABLE_AUTO_PREFIXES //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // ghc::filesystem version in decimal (major * 10000 + minor * 100 + patch) #define GHC_FILESYSTEM_VERSION 10504L #if !defined(GHC_WITH_EXCEPTIONS) && (defined(__EXCEPTIONS) || defined(__cpp_exceptions) || defined(_CPPUNWIND)) #define GHC_WITH_EXCEPTIONS #endif #if !defined(GHC_WITH_EXCEPTIONS) && defined(GHC_RAISE_UNICODE_ERRORS) #error "Can't raise unicode errors with exception support disabled" #endif namespace ghc { namespace filesystem { #if defined(GHC_HAS_CUSTOM_STRING_VIEW) #define GHC_WITH_STRING_VIEW #elif defined(GHC_HAS_STD_STRING_VIEW) #define GHC_WITH_STRING_VIEW using std::basic_string_view; #elif defined(GHC_HAS_STD_EXPERIMENTAL_STRING_VIEW) #define GHC_WITH_STRING_VIEW using std::experimental::basic_string_view; #endif // temporary existing exception type for yet unimplemented parts class GHC_FS_API_CLASS not_implemented_exception : public std::logic_error { public: not_implemented_exception() : std::logic_error("function not implemented yet.") { } }; template class path_helper_base { public: using value_type = char_type; #ifdef GHC_OS_WINDOWS static constexpr value_type preferred_separator = '\\'; #else static constexpr value_type preferred_separator = '/'; #endif }; #if __cplusplus < 201703L template constexpr char_type path_helper_base::preferred_separator; #endif #ifdef GHC_OS_WINDOWS class path; namespace detail { bool has_executable_extension(const path& p); } #endif // 30.10.8 class path class GHC_FS_API_CLASS path #if defined(GHC_OS_WINDOWS) && !defined(GHC_WIN_DISABLE_WSTRING_STORAGE_TYPE) #define GHC_USE_WCHAR_T #define GHC_NATIVEWP(p) p.c_str() #define GHC_PLATFORM_LITERAL(str) L##str : private path_helper_base { public: using path_helper_base::value_type; #else #define GHC_NATIVEWP(p) p.wstring().c_str() #define GHC_PLATFORM_LITERAL(str) str : private path_helper_base { public: using path_helper_base::value_type; #endif using string_type = std::basic_string; using path_helper_base::preferred_separator; // 30.10.10.1 enumeration format /// The path format in which the constructor argument is given. enum format { generic_format, ///< The generic format, internally used by ///< ghc::filesystem::path with slashes native_format, ///< The format native to the current platform this code ///< is build for auto_format, ///< Try to auto-detect the format, fallback to native }; template struct _is_basic_string : std::false_type { }; template struct _is_basic_string> : std::true_type { }; template struct _is_basic_string, std::allocator>> : std::true_type { }; #ifdef GHC_WITH_STRING_VIEW template struct _is_basic_string> : std::true_type { }; template struct _is_basic_string>> : std::true_type { }; #endif template using path_type = typename std::enable_if::value, path>::type; template using path_from_string = typename std::enable_if<_is_basic_string::value || std::is_same::type>::value || std::is_same::type>::value || std::is_same::type>::value || std::is_same::type>::value, path>::type; template using path_type_EcharT = typename std::enable_if::value || std::is_same::value || std::is_same::value || std::is_same::value, path>::type; // 30.10.8.4.1 constructors and destructor path() noexcept; path(const path& p); path(path&& p) noexcept; path(string_type&& source, format fmt = auto_format); template > path(const Source& source, format fmt = auto_format); template path(InputIterator first, InputIterator last, format fmt = auto_format); #ifdef GHC_WITH_EXCEPTIONS template > path(const Source& source, const std::locale& loc, format fmt = auto_format); template path(InputIterator first, InputIterator last, const std::locale& loc, format fmt = auto_format); #endif ~path(); // 30.10.8.4.2 assignments path& operator=(const path& p); path& operator=(path&& p) noexcept; path& operator=(string_type&& source); path& assign(string_type&& source); template path& operator=(const Source& source); template path& assign(const Source& source); template path& assign(InputIterator first, InputIterator last); // 30.10.8.4.3 appends path& operator/=(const path& p); template path& operator/=(const Source& source); template path& append(const Source& source); template path& append(InputIterator first, InputIterator last); // 30.10.8.4.4 concatenation path& operator+=(const path& x); path& operator+=(const string_type& x); #ifdef GHC_WITH_STRING_VIEW path& operator+=(basic_string_view x); #endif path& operator+=(const value_type* x); path& operator+=(value_type x); template path_from_string& operator+=(const Source& x); template path_type_EcharT& operator+=(EcharT x); template path& concat(const Source& x); template path& concat(InputIterator first, InputIterator last); // 30.10.8.4.5 modifiers void clear() noexcept; path& make_preferred(); path& remove_filename(); path& replace_filename(const path& replacement); path& replace_extension(const path& replacement = path()); void swap(path& rhs) noexcept; // 30.10.8.4.6 native format observers const string_type& native() const noexcept; const value_type* c_str() const noexcept; operator string_type() const; template , class Allocator = std::allocator> std::basic_string string(const Allocator& a = Allocator()) const; std::string string() const; std::wstring wstring() const; #if defined(__cpp_lib_char8_t) && !defined(GHC_FILESYSTEM_ENFORCE_CPP17_API) std::u8string u8string() const; #else std::string u8string() const; #endif std::u16string u16string() const; std::u32string u32string() const; // 30.10.8.4.7 generic format observers template , class Allocator = std::allocator> std::basic_string generic_string(const Allocator& a = Allocator()) const; std::string generic_string() const; std::wstring generic_wstring() const; #if defined(__cpp_lib_char8_t) && !defined(GHC_FILESYSTEM_ENFORCE_CPP17_API) std::u8string generic_u8string() const; #else std::string generic_u8string() const; #endif std::u16string generic_u16string() const; std::u32string generic_u32string() const; // 30.10.8.4.8 compare int compare(const path& p) const noexcept; int compare(const string_type& s) const; #ifdef GHC_WITH_STRING_VIEW int compare(basic_string_view s) const; #endif int compare(const value_type* s) const; // 30.10.8.4.9 decomposition path root_name() const; path root_directory() const; path root_path() const; path relative_path() const; path parent_path() const; path filename() const; path stem() const; path extension() const; // 30.10.8.4.10 query bool empty() const noexcept; bool has_root_name() const; bool has_root_directory() const; bool has_root_path() const; bool has_relative_path() const; bool has_parent_path() const; bool has_filename() const; bool has_stem() const; bool has_extension() const; bool is_absolute() const; bool is_relative() const; // 30.10.8.4.11 generation path lexically_normal() const; path lexically_relative(const path& base) const; path lexically_proximate(const path& base) const; // 30.10.8.5 iterators class iterator; using const_iterator = iterator; iterator begin() const; iterator end() const; private: using impl_value_type = value_type; using impl_string_type = std::basic_string; friend class directory_iterator; void append_name(const value_type* name); static constexpr impl_value_type generic_separator = '/'; template class input_iterator_range { public: typedef InputIterator iterator; typedef InputIterator const_iterator; typedef typename InputIterator::difference_type difference_type; input_iterator_range(const InputIterator& first, const InputIterator& last) : _first(first) , _last(last) { } InputIterator begin() const { return _first; } InputIterator end() const { return _last; } private: InputIterator _first; InputIterator _last; }; friend void swap(path& lhs, path& rhs) noexcept; friend size_t hash_value(const path& p) noexcept; friend path canonical(const path& p, std::error_code& ec); string_type::size_type root_name_length() const noexcept; void postprocess_path_with_format(format fmt); void check_long_path(); impl_string_type _path; #ifdef GHC_OS_WINDOWS void handle_prefixes(); friend bool detail::has_executable_extension(const path& p); #ifdef GHC_WIN_AUTO_PREFIX_LONG_PATH string_type::size_type _prefixLength{0}; #else // GHC_WIN_AUTO_PREFIX_LONG_PATH static const string_type::size_type _prefixLength{0}; #endif // GHC_WIN_AUTO_PREFIX_LONG_PATH #else static const string_type::size_type _prefixLength{0}; #endif }; // 30.10.8.6 path non-member functions GHC_FS_API void swap(path& lhs, path& rhs) noexcept; GHC_FS_API size_t hash_value(const path& p) noexcept; #ifdef GHC_HAS_THREEWAY_COMP GHC_FS_API std::strong_ordering operator<=>(const path& lhs, const path& rhs) noexcept; #endif GHC_FS_API bool operator==(const path& lhs, const path& rhs) noexcept; GHC_FS_API bool operator!=(const path& lhs, const path& rhs) noexcept; GHC_FS_API bool operator<(const path& lhs, const path& rhs) noexcept; GHC_FS_API bool operator<=(const path& lhs, const path& rhs) noexcept; GHC_FS_API bool operator>(const path& lhs, const path& rhs) noexcept; GHC_FS_API bool operator>=(const path& lhs, const path& rhs) noexcept; GHC_FS_API path operator/(const path& lhs, const path& rhs); // 30.10.8.6.1 path inserter and extractor template std::basic_ostream& operator<<(std::basic_ostream& os, const path& p); template std::basic_istream& operator>>(std::basic_istream& is, path& p); // 30.10.8.6.2 path factory functions template > #if defined(__cpp_lib_char8_t) && !defined(GHC_FILESYSTEM_ENFORCE_CPP17_API) [[deprecated("use ghc::filesystem::path::path() with std::u8string instead")]] #endif path u8path(const Source& source); template #if defined(__cpp_lib_char8_t) && !defined(GHC_FILESYSTEM_ENFORCE_CPP17_API) [[deprecated("use ghc::filesystem::path::path() with std::u8string instead")]] #endif path u8path(InputIterator first, InputIterator last); // 30.10.9 class filesystem_error class GHC_FS_API_CLASS filesystem_error : public std::system_error { public: filesystem_error(const std::string& what_arg, std::error_code ec); filesystem_error(const std::string& what_arg, const path& p1, std::error_code ec); filesystem_error(const std::string& what_arg, const path& p1, const path& p2, std::error_code ec); const path& path1() const noexcept; const path& path2() const noexcept; const char* what() const noexcept override; private: std::string _what_arg; std::error_code _ec; path _p1, _p2; }; class GHC_FS_API_CLASS path::iterator { public: using value_type = const path; using difference_type = std::ptrdiff_t; using pointer = const path*; using reference = const path&; using iterator_category = std::bidirectional_iterator_tag; iterator(); iterator(const path& p, const impl_string_type::const_iterator& pos); iterator& operator++(); iterator operator++(int); iterator& operator--(); iterator operator--(int); bool operator==(const iterator& other) const; bool operator!=(const iterator& other) const; reference operator*() const; pointer operator->() const; private: friend class path; impl_string_type::const_iterator increment(const impl_string_type::const_iterator& pos) const; impl_string_type::const_iterator decrement(const impl_string_type::const_iterator& pos) const; void updateCurrent(); impl_string_type::const_iterator _first; impl_string_type::const_iterator _last; impl_string_type::const_iterator _prefix; impl_string_type::const_iterator _root; impl_string_type::const_iterator _iter; path _current; }; struct space_info { uintmax_t capacity; uintmax_t free; uintmax_t available; }; // 30.10.10, enumerations enum class file_type { none, not_found, regular, directory, symlink, block, character, fifo, socket, unknown, }; enum class perms : uint16_t { none = 0, owner_read = 0400, owner_write = 0200, owner_exec = 0100, owner_all = 0700, group_read = 040, group_write = 020, group_exec = 010, group_all = 070, others_read = 04, others_write = 02, others_exec = 01, others_all = 07, all = 0777, set_uid = 04000, set_gid = 02000, sticky_bit = 01000, mask = 07777, unknown = 0xffff }; enum class perm_options : uint16_t { replace = 3, add = 1, remove = 2, nofollow = 4, }; enum class copy_options : uint16_t { none = 0, skip_existing = 1, overwrite_existing = 2, update_existing = 4, recursive = 8, copy_symlinks = 0x10, skip_symlinks = 0x20, directories_only = 0x40, create_symlinks = 0x80, #ifndef GHC_OS_WEB create_hard_links = 0x100 #endif }; enum class directory_options : uint16_t { none = 0, follow_directory_symlink = 1, skip_permission_denied = 2, }; // 30.10.11 class file_status class GHC_FS_API_CLASS file_status { public: // 30.10.11.1 constructors and destructor file_status() noexcept; explicit file_status(file_type ft, perms prms = perms::unknown) noexcept; file_status(const file_status&) noexcept; file_status(file_status&&) noexcept; ~file_status(); // assignments: file_status& operator=(const file_status&) noexcept; file_status& operator=(file_status&&) noexcept; // 30.10.11.3 modifiers void type(file_type ft) noexcept; void permissions(perms prms) noexcept; // 30.10.11.2 observers file_type type() const noexcept; perms permissions() const noexcept; friend bool operator==(const file_status& lhs, const file_status& rhs) noexcept { return lhs.type() == rhs.type() && lhs.permissions() == rhs.permissions(); } private: file_type _type; perms _perms; }; using file_time_type = std::chrono::time_point; // 30.10.12 Class directory_entry class GHC_FS_API_CLASS directory_entry { public: // 30.10.12.1 constructors and destructor directory_entry() noexcept = default; directory_entry(const directory_entry&) = default; directory_entry(directory_entry&&) noexcept = default; #ifdef GHC_WITH_EXCEPTIONS explicit directory_entry(const path& p); #endif directory_entry(const path& p, std::error_code& ec); ~directory_entry(); // assignments: directory_entry& operator=(const directory_entry&) = default; directory_entry& operator=(directory_entry&&) noexcept = default; // 30.10.12.2 modifiers #ifdef GHC_WITH_EXCEPTIONS void assign(const path& p); void replace_filename(const path& p); void refresh(); #endif void assign(const path& p, std::error_code& ec); void replace_filename(const path& p, std::error_code& ec); void refresh(std::error_code& ec) noexcept; // 30.10.12.3 observers const filesystem::path& path() const noexcept; operator const filesystem::path&() const noexcept; #ifdef GHC_WITH_EXCEPTIONS bool exists() const; bool is_block_file() const; bool is_character_file() const; bool is_directory() const; bool is_fifo() const; bool is_other() const; bool is_regular_file() const; bool is_socket() const; bool is_symlink() const; uintmax_t file_size() const; file_time_type last_write_time() const; file_status status() const; file_status symlink_status() const; #endif bool exists(std::error_code& ec) const noexcept; bool is_block_file(std::error_code& ec) const noexcept; bool is_character_file(std::error_code& ec) const noexcept; bool is_directory(std::error_code& ec) const noexcept; bool is_fifo(std::error_code& ec) const noexcept; bool is_other(std::error_code& ec) const noexcept; bool is_regular_file(std::error_code& ec) const noexcept; bool is_socket(std::error_code& ec) const noexcept; bool is_symlink(std::error_code& ec) const noexcept; uintmax_t file_size(std::error_code& ec) const noexcept; file_time_type last_write_time(std::error_code& ec) const noexcept; file_status status(std::error_code& ec) const noexcept; file_status symlink_status(std::error_code& ec) const noexcept; #ifndef GHC_OS_WEB #ifdef GHC_WITH_EXCEPTIONS uintmax_t hard_link_count() const; #endif uintmax_t hard_link_count(std::error_code& ec) const noexcept; #endif #ifdef GHC_HAS_THREEWAY_COMP std::strong_ordering operator<=>(const directory_entry& rhs) const noexcept; #endif bool operator<(const directory_entry& rhs) const noexcept; bool operator==(const directory_entry& rhs) const noexcept; bool operator!=(const directory_entry& rhs) const noexcept; bool operator<=(const directory_entry& rhs) const noexcept; bool operator>(const directory_entry& rhs) const noexcept; bool operator>=(const directory_entry& rhs) const noexcept; private: friend class directory_iterator; #ifdef GHC_WITH_EXCEPTIONS file_type status_file_type() const; #endif file_type status_file_type(std::error_code& ec) const noexcept; filesystem::path _path; file_status _status; file_status _symlink_status; uintmax_t _file_size = static_cast(-1); #ifndef GHC_OS_WINDOWS uintmax_t _hard_link_count = static_cast(-1); #endif time_t _last_write_time = 0; }; // 30.10.13 Class directory_iterator class GHC_FS_API_CLASS directory_iterator { public: class GHC_FS_API_CLASS proxy { public: const directory_entry& operator*() const& noexcept { return _dir_entry; } directory_entry operator*() && noexcept { return std::move(_dir_entry); } private: explicit proxy(const directory_entry& dir_entry) : _dir_entry(dir_entry) { } friend class directory_iterator; friend class recursive_directory_iterator; directory_entry _dir_entry; }; using iterator_category = std::input_iterator_tag; using value_type = directory_entry; using difference_type = std::ptrdiff_t; using pointer = const directory_entry*; using reference = const directory_entry&; // 30.10.13.1 member functions directory_iterator() noexcept; #ifdef GHC_WITH_EXCEPTIONS explicit directory_iterator(const path& p); directory_iterator(const path& p, directory_options options); #endif directory_iterator(const path& p, std::error_code& ec) noexcept; directory_iterator(const path& p, directory_options options, std::error_code& ec) noexcept; directory_iterator(const directory_iterator& rhs); directory_iterator(directory_iterator&& rhs) noexcept; ~directory_iterator(); directory_iterator& operator=(const directory_iterator& rhs); directory_iterator& operator=(directory_iterator&& rhs) noexcept; const directory_entry& operator*() const; const directory_entry* operator->() const; #ifdef GHC_WITH_EXCEPTIONS directory_iterator& operator++(); #endif directory_iterator& increment(std::error_code& ec) noexcept; // other members as required by 27.2.3, input iterators #ifdef GHC_WITH_EXCEPTIONS proxy operator++(int) { proxy p{**this}; ++*this; return p; } #endif bool operator==(const directory_iterator& rhs) const; bool operator!=(const directory_iterator& rhs) const; private: friend class recursive_directory_iterator; class impl; std::shared_ptr _impl; }; // 30.10.13.2 directory_iterator non-member functions GHC_FS_API directory_iterator begin(directory_iterator iter) noexcept; GHC_FS_API directory_iterator end(const directory_iterator&) noexcept; // 30.10.14 class recursive_directory_iterator class GHC_FS_API_CLASS recursive_directory_iterator { public: using iterator_category = std::input_iterator_tag; using value_type = directory_entry; using difference_type = std::ptrdiff_t; using pointer = const directory_entry*; using reference = const directory_entry&; // 30.10.14.1 constructors and destructor recursive_directory_iterator() noexcept; #ifdef GHC_WITH_EXCEPTIONS explicit recursive_directory_iterator(const path& p); recursive_directory_iterator(const path& p, directory_options options); #endif recursive_directory_iterator(const path& p, directory_options options, std::error_code& ec) noexcept; recursive_directory_iterator(const path& p, std::error_code& ec) noexcept; recursive_directory_iterator(const recursive_directory_iterator& rhs); recursive_directory_iterator(recursive_directory_iterator&& rhs) noexcept; ~recursive_directory_iterator(); // 30.10.14.1 observers directory_options options() const; int depth() const; bool recursion_pending() const; const directory_entry& operator*() const; const directory_entry* operator->() const; // 30.10.14.1 modifiers recursive_directory_iterator& recursive_directory_iterator& operator=(const recursive_directory_iterator& rhs); recursive_directory_iterator& operator=(recursive_directory_iterator&& rhs) noexcept; #ifdef GHC_WITH_EXCEPTIONS recursive_directory_iterator& operator++(); #endif recursive_directory_iterator& increment(std::error_code& ec) noexcept; #ifdef GHC_WITH_EXCEPTIONS void pop(); #endif void pop(std::error_code& ec); void disable_recursion_pending(); // other members as required by 27.2.3, input iterators #ifdef GHC_WITH_EXCEPTIONS directory_iterator::proxy operator++(int) { directory_iterator::proxy proxy{**this}; ++*this; return proxy; } #endif bool operator==(const recursive_directory_iterator& rhs) const; bool operator!=(const recursive_directory_iterator& rhs) const; private: struct recursive_directory_iterator_impl { directory_options _options; bool _recursion_pending; std::stack _dir_iter_stack; recursive_directory_iterator_impl(directory_options options, bool recursion_pending) : _options(options) , _recursion_pending(recursion_pending) { } }; std::shared_ptr _impl; }; // 30.10.14.2 directory_iterator non-member functions GHC_FS_API recursive_directory_iterator begin(recursive_directory_iterator iter) noexcept; GHC_FS_API recursive_directory_iterator end(const recursive_directory_iterator&) noexcept; // 30.10.15 filesystem operations #ifdef GHC_WITH_EXCEPTIONS GHC_FS_API path absolute(const path& p); GHC_FS_API path canonical(const path& p); GHC_FS_API void copy(const path& from, const path& to); GHC_FS_API void copy(const path& from, const path& to, copy_options options); GHC_FS_API bool copy_file(const path& from, const path& to); GHC_FS_API bool copy_file(const path& from, const path& to, copy_options option); GHC_FS_API void copy_symlink(const path& existing_symlink, const path& new_symlink); GHC_FS_API bool create_directories(const path& p); GHC_FS_API bool create_directory(const path& p); GHC_FS_API bool create_directory(const path& p, const path& attributes); GHC_FS_API void create_directory_symlink(const path& to, const path& new_symlink); GHC_FS_API void create_symlink(const path& to, const path& new_symlink); GHC_FS_API path current_path(); GHC_FS_API void current_path(const path& p); GHC_FS_API bool exists(const path& p); GHC_FS_API bool equivalent(const path& p1, const path& p2); GHC_FS_API uintmax_t file_size(const path& p); GHC_FS_API bool is_block_file(const path& p); GHC_FS_API bool is_character_file(const path& p); GHC_FS_API bool is_directory(const path& p); GHC_FS_API bool is_empty(const path& p); GHC_FS_API bool is_fifo(const path& p); GHC_FS_API bool is_other(const path& p); GHC_FS_API bool is_regular_file(const path& p); GHC_FS_API bool is_socket(const path& p); GHC_FS_API bool is_symlink(const path& p); GHC_FS_API file_time_type last_write_time(const path& p); GHC_FS_API void last_write_time(const path& p, file_time_type new_time); GHC_FS_API void permissions(const path& p, perms prms, perm_options opts = perm_options::replace); GHC_FS_API path proximate(const path& p, const path& base = current_path()); GHC_FS_API path read_symlink(const path& p); GHC_FS_API path relative(const path& p, const path& base = current_path()); GHC_FS_API bool remove(const path& p); GHC_FS_API uintmax_t remove_all(const path& p); GHC_FS_API void rename(const path& from, const path& to); GHC_FS_API void resize_file(const path& p, uintmax_t size); GHC_FS_API space_info space(const path& p); GHC_FS_API file_status status(const path& p); GHC_FS_API file_status symlink_status(const path& p); GHC_FS_API path temp_directory_path(); GHC_FS_API path weakly_canonical(const path& p); #endif GHC_FS_API path absolute(const path& p, std::error_code& ec); GHC_FS_API path canonical(const path& p, std::error_code& ec); GHC_FS_API void copy(const path& from, const path& to, std::error_code& ec) noexcept; GHC_FS_API void copy(const path& from, const path& to, copy_options options, std::error_code& ec) noexcept; GHC_FS_API bool copy_file(const path& from, const path& to, std::error_code& ec) noexcept; GHC_FS_API bool copy_file(const path& from, const path& to, copy_options option, std::error_code& ec) noexcept; GHC_FS_API void copy_symlink(const path& existing_symlink, const path& new_symlink, std::error_code& ec) noexcept; GHC_FS_API bool create_directories(const path& p, std::error_code& ec) noexcept; GHC_FS_API bool create_directory(const path& p, std::error_code& ec) noexcept; GHC_FS_API bool create_directory(const path& p, const path& attributes, std::error_code& ec) noexcept; GHC_FS_API void create_directory_symlink(const path& to, const path& new_symlink, std::error_code& ec) noexcept; GHC_FS_API void create_symlink(const path& to, const path& new_symlink, std::error_code& ec) noexcept; GHC_FS_API path current_path(std::error_code& ec); GHC_FS_API void current_path(const path& p, std::error_code& ec) noexcept; GHC_FS_API bool exists(file_status s) noexcept; GHC_FS_API bool exists(const path& p, std::error_code& ec) noexcept; GHC_FS_API bool equivalent(const path& p1, const path& p2, std::error_code& ec) noexcept; GHC_FS_API uintmax_t file_size(const path& p, std::error_code& ec) noexcept; GHC_FS_API bool is_block_file(file_status s) noexcept; GHC_FS_API bool is_block_file(const path& p, std::error_code& ec) noexcept; GHC_FS_API bool is_character_file(file_status s) noexcept; GHC_FS_API bool is_character_file(const path& p, std::error_code& ec) noexcept; GHC_FS_API bool is_directory(file_status s) noexcept; GHC_FS_API bool is_directory(const path& p, std::error_code& ec) noexcept; GHC_FS_API bool is_empty(const path& p, std::error_code& ec) noexcept; GHC_FS_API bool is_fifo(file_status s) noexcept; GHC_FS_API bool is_fifo(const path& p, std::error_code& ec) noexcept; GHC_FS_API bool is_other(file_status s) noexcept; GHC_FS_API bool is_other(const path& p, std::error_code& ec) noexcept; GHC_FS_API bool is_regular_file(file_status s) noexcept; GHC_FS_API bool is_regular_file(const path& p, std::error_code& ec) noexcept; GHC_FS_API bool is_socket(file_status s) noexcept; GHC_FS_API bool is_socket(const path& p, std::error_code& ec) noexcept; GHC_FS_API bool is_symlink(file_status s) noexcept; GHC_FS_API bool is_symlink(const path& p, std::error_code& ec) noexcept; GHC_FS_API file_time_type last_write_time(const path& p, std::error_code& ec) noexcept; GHC_FS_API void last_write_time(const path& p, file_time_type new_time, std::error_code& ec) noexcept; GHC_FS_API void permissions(const path& p, perms prms, std::error_code& ec) noexcept; GHC_FS_API void permissions(const path& p, perms prms, perm_options opts, std::error_code& ec) noexcept; GHC_FS_API path proximate(const path& p, std::error_code& ec); GHC_FS_API path proximate(const path& p, const path& base, std::error_code& ec); GHC_FS_API path read_symlink(const path& p, std::error_code& ec); GHC_FS_API path relative(const path& p, std::error_code& ec); GHC_FS_API path relative(const path& p, const path& base, std::error_code& ec); GHC_FS_API bool remove(const path& p, std::error_code& ec) noexcept; GHC_FS_API uintmax_t remove_all(const path& p, std::error_code& ec) noexcept; GHC_FS_API void rename(const path& from, const path& to, std::error_code& ec) noexcept; GHC_FS_API void resize_file(const path& p, uintmax_t size, std::error_code& ec) noexcept; GHC_FS_API space_info space(const path& p, std::error_code& ec) noexcept; GHC_FS_API file_status status(const path& p, std::error_code& ec) noexcept; GHC_FS_API bool status_known(file_status s) noexcept; GHC_FS_API file_status symlink_status(const path& p, std::error_code& ec) noexcept; GHC_FS_API path temp_directory_path(std::error_code& ec) noexcept; GHC_FS_API path weakly_canonical(const path& p, std::error_code& ec) noexcept; #ifndef GHC_OS_WEB #ifdef GHC_WITH_EXCEPTIONS GHC_FS_API void create_hard_link(const path& to, const path& new_hard_link); GHC_FS_API uintmax_t hard_link_count(const path& p); #endif GHC_FS_API void create_hard_link(const path& to, const path& new_hard_link, std::error_code& ec) noexcept; GHC_FS_API uintmax_t hard_link_count(const path& p, std::error_code& ec) noexcept; #endif // Non-C++17 add-on std::fstream wrappers with path template > class basic_filebuf : public std::basic_filebuf { public: basic_filebuf() {} ~basic_filebuf() override {} basic_filebuf(const basic_filebuf&) = delete; const basic_filebuf& operator=(const basic_filebuf&) = delete; basic_filebuf* open(const path& p, std::ios_base::openmode mode) { #if defined(GHC_OS_WINDOWS) && !defined(__GLIBCXX__) return std::basic_filebuf::open(p.wstring().c_str(), mode) ? this : 0; #else return std::basic_filebuf::open(p.string().c_str(), mode) ? this : 0; #endif } }; template > class basic_ifstream : public std::basic_ifstream { public: basic_ifstream() {} #if defined(GHC_OS_WINDOWS) && !defined(__GLIBCXX__) explicit basic_ifstream(const path& p, std::ios_base::openmode mode = std::ios_base::in) : std::basic_ifstream(p.wstring().c_str(), mode) { } void open(const path& p, std::ios_base::openmode mode = std::ios_base::in) { std::basic_ifstream::open(p.wstring().c_str(), mode); } #else explicit basic_ifstream(const path& p, std::ios_base::openmode mode = std::ios_base::in) : std::basic_ifstream(p.string().c_str(), mode) { } void open(const path& p, std::ios_base::openmode mode = std::ios_base::in) { std::basic_ifstream::open(p.string().c_str(), mode); } #endif basic_ifstream(const basic_ifstream&) = delete; const basic_ifstream& operator=(const basic_ifstream&) = delete; ~basic_ifstream() override {} }; template > class basic_ofstream : public std::basic_ofstream { public: basic_ofstream() {} #if defined(GHC_OS_WINDOWS) && !defined(__GLIBCXX__) explicit basic_ofstream(const path& p, std::ios_base::openmode mode = std::ios_base::out) : std::basic_ofstream(p.wstring().c_str(), mode) { } void open(const path& p, std::ios_base::openmode mode = std::ios_base::out) { std::basic_ofstream::open(p.wstring().c_str(), mode); } #else explicit basic_ofstream(const path& p, std::ios_base::openmode mode = std::ios_base::out) : std::basic_ofstream(p.string().c_str(), mode) { } void open(const path& p, std::ios_base::openmode mode = std::ios_base::out) { std::basic_ofstream::open(p.string().c_str(), mode); } #endif basic_ofstream(const basic_ofstream&) = delete; const basic_ofstream& operator=(const basic_ofstream&) = delete; ~basic_ofstream() override {} }; template > class basic_fstream : public std::basic_fstream { public: basic_fstream() {} #if defined(GHC_OS_WINDOWS) && !defined(__GLIBCXX__) explicit basic_fstream(const path& p, std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out) : std::basic_fstream(p.wstring().c_str(), mode) { } void open(const path& p, std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out) { std::basic_fstream::open(p.wstring().c_str(), mode); } #else explicit basic_fstream(const path& p, std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out) : std::basic_fstream(p.string().c_str(), mode) { } void open(const path& p, std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out) { std::basic_fstream::open(p.string().c_str(), mode); } #endif basic_fstream(const basic_fstream&) = delete; const basic_fstream& operator=(const basic_fstream&) = delete; ~basic_fstream() override {} }; typedef basic_filebuf filebuf; typedef basic_filebuf wfilebuf; typedef basic_ifstream ifstream; typedef basic_ifstream wifstream; typedef basic_ofstream ofstream; typedef basic_ofstream wofstream; typedef basic_fstream fstream; typedef basic_fstream wfstream; class GHC_FS_API_CLASS u8arguments { public: u8arguments(int& argc, char**& argv); ~u8arguments() { _refargc = _argc; _refargv = _argv; } bool valid() const { return _isvalid; } private: int _argc; char** _argv; int& _refargc; char**& _refargv; bool _isvalid; #ifdef GHC_OS_WINDOWS std::vector _args; std::vector _argp; #endif }; //------------------------------------------------------------------------------------------------- // Implementation //------------------------------------------------------------------------------------------------- namespace detail { enum utf8_states_t { S_STRT = 0, S_RJCT = 8 }; GHC_FS_API void appendUTF8(std::string& str, uint32_t unicode); GHC_FS_API bool is_surrogate(uint32_t c); GHC_FS_API bool is_high_surrogate(uint32_t c); GHC_FS_API bool is_low_surrogate(uint32_t c); GHC_FS_API unsigned consumeUtf8Fragment(const unsigned state, const uint8_t fragment, uint32_t& codepoint); enum class portable_error { none = 0, exists, not_found, not_supported, not_implemented, invalid_argument, is_a_directory, }; GHC_FS_API std::error_code make_error_code(portable_error err); #ifdef GHC_OS_WINDOWS GHC_FS_API std::error_code make_system_error(uint32_t err = 0); #else GHC_FS_API std::error_code make_system_error(int err = 0); #endif } // namespace detail namespace detail { #ifdef GHC_EXPAND_IMPL GHC_INLINE std::error_code make_error_code(portable_error err) { #ifdef GHC_OS_WINDOWS switch (err) { case portable_error::none: return std::error_code(); case portable_error::exists: return std::error_code(ERROR_ALREADY_EXISTS, std::system_category()); case portable_error::not_found: return std::error_code(ERROR_PATH_NOT_FOUND, std::system_category()); case portable_error::not_supported: return std::error_code(ERROR_NOT_SUPPORTED, std::system_category()); case portable_error::not_implemented: return std::error_code(ERROR_CALL_NOT_IMPLEMENTED, std::system_category()); case portable_error::invalid_argument: return std::error_code(ERROR_INVALID_PARAMETER, std::system_category()); case portable_error::is_a_directory: #ifdef ERROR_DIRECTORY_NOT_SUPPORTED return std::error_code(ERROR_DIRECTORY_NOT_SUPPORTED, std::system_category()); #else return std::error_code(ERROR_NOT_SUPPORTED, std::system_category()); #endif } #else switch (err) { case portable_error::none: return std::error_code(); case portable_error::exists: return std::error_code(EEXIST, std::system_category()); case portable_error::not_found: return std::error_code(ENOENT, std::system_category()); case portable_error::not_supported: return std::error_code(ENOTSUP, std::system_category()); case portable_error::not_implemented: return std::error_code(ENOSYS, std::system_category()); case portable_error::invalid_argument: return std::error_code(EINVAL, std::system_category()); case portable_error::is_a_directory: return std::error_code(EISDIR, std::system_category()); } #endif return std::error_code(); } #ifdef GHC_OS_WINDOWS GHC_INLINE std::error_code make_system_error(uint32_t err) { return std::error_code(err ? static_cast(err) : static_cast(::GetLastError()), std::system_category()); } #else GHC_INLINE std::error_code make_system_error(int err) { return std::error_code(err ? err : errno, std::system_category()); } #endif #endif // GHC_EXPAND_IMPL template using EnableBitmask = typename std::enable_if::value || std::is_same::value || std::is_same::value || std::is_same::value, Enum>::type; } // namespace detail template constexpr detail::EnableBitmask operator&(Enum X, Enum Y) { using underlying = typename std::underlying_type::type; return static_cast(static_cast(X) & static_cast(Y)); } template constexpr detail::EnableBitmask operator|(Enum X, Enum Y) { using underlying = typename std::underlying_type::type; return static_cast(static_cast(X) | static_cast(Y)); } template constexpr detail::EnableBitmask operator^(Enum X, Enum Y) { using underlying = typename std::underlying_type::type; return static_cast(static_cast(X) ^ static_cast(Y)); } template constexpr detail::EnableBitmask operator~(Enum X) { using underlying = typename std::underlying_type::type; return static_cast(~static_cast(X)); } template detail::EnableBitmask& operator&=(Enum& X, Enum Y) { X = X & Y; return X; } template detail::EnableBitmask& operator|=(Enum& X, Enum Y) { X = X | Y; return X; } template detail::EnableBitmask& operator^=(Enum& X, Enum Y) { X = X ^ Y; return X; } #ifdef GHC_EXPAND_IMPL namespace detail { GHC_INLINE bool in_range(uint32_t c, uint32_t lo, uint32_t hi) { return (static_cast(c - lo) < (hi - lo + 1)); } GHC_INLINE bool is_surrogate(uint32_t c) { return in_range(c, 0xd800, 0xdfff); } GHC_INLINE bool is_high_surrogate(uint32_t c) { return (c & 0xfffffc00) == 0xd800; } GHC_INLINE bool is_low_surrogate(uint32_t c) { return (c & 0xfffffc00) == 0xdc00; } GHC_INLINE void appendUTF8(std::string& str, uint32_t unicode) { if (unicode <= 0x7f) { str.push_back(static_cast(unicode)); } else if (unicode >= 0x80 && unicode <= 0x7ff) { str.push_back(static_cast((unicode >> 6) + 192)); str.push_back(static_cast((unicode & 0x3f) + 128)); } else if ((unicode >= 0x800 && unicode <= 0xd7ff) || (unicode >= 0xe000 && unicode <= 0xffff)) { str.push_back(static_cast((unicode >> 12) + 224)); str.push_back(static_cast(((unicode & 0xfff) >> 6) + 128)); str.push_back(static_cast((unicode & 0x3f) + 128)); } else if (unicode >= 0x10000 && unicode <= 0x10ffff) { str.push_back(static_cast((unicode >> 18) + 240)); str.push_back(static_cast(((unicode & 0x3ffff) >> 12) + 128)); str.push_back(static_cast(((unicode & 0xfff) >> 6) + 128)); str.push_back(static_cast((unicode & 0x3f) + 128)); } else { #ifdef GHC_RAISE_UNICODE_ERRORS throw filesystem_error("Illegal code point for unicode character.", str, std::make_error_code(std::errc::illegal_byte_sequence)); #else appendUTF8(str, 0xfffd); #endif } } // Thanks to Bjoern Hoehrmann (https://bjoern.hoehrmann.de/utf-8/decoder/dfa/) // and Taylor R Campbell for the ideas to this DFA approach of UTF-8 decoding; // Generating debugging and shrinking my own DFA from scratch was a day of fun! GHC_INLINE unsigned consumeUtf8Fragment(const unsigned state, const uint8_t fragment, uint32_t& codepoint) { static const uint32_t utf8_state_info[] = { // encoded states 0x11111111u, 0x11111111u, 0x77777777u, 0x77777777u, 0x88888888u, 0x88888888u, 0x88888888u, 0x88888888u, 0x22222299u, 0x22222222u, 0x22222222u, 0x22222222u, 0x3333333au, 0x33433333u, 0x9995666bu, 0x99999999u, 0x88888880u, 0x22818108u, 0x88888881u, 0x88888882u, 0x88888884u, 0x88888887u, 0x88888886u, 0x82218108u, 0x82281108u, 0x88888888u, 0x88888883u, 0x88888885u, 0u, 0u, 0u, 0u, }; uint8_t category = fragment < 128 ? 0 : (utf8_state_info[(fragment >> 3) & 0xf] >> ((fragment & 7) << 2)) & 0xf; codepoint = (state ? (codepoint << 6) | (fragment & 0x3fu) : (0xffu >> category) & fragment); return state == S_RJCT ? static_cast(S_RJCT) : static_cast((utf8_state_info[category + 16] >> (state << 2)) & 0xf); } GHC_INLINE bool validUtf8(const std::string& utf8String) { std::string::const_iterator iter = utf8String.begin(); unsigned utf8_state = S_STRT; std::uint32_t codepoint = 0; while (iter < utf8String.end()) { if ((utf8_state = consumeUtf8Fragment(utf8_state, static_cast(*iter++), codepoint)) == S_RJCT) { return false; } } if (utf8_state) { return false; } return true; } } // namespace detail #endif namespace detail { template ::value && (sizeof(typename Utf8String::value_type) == 1) && (sizeof(typename StringType::value_type) == 1)>::type* = nullptr> inline StringType fromUtf8(const Utf8String& utf8String, const typename StringType::allocator_type& alloc = typename StringType::allocator_type()) { return StringType(utf8String.begin(), utf8String.end(), alloc); } template ::value && (sizeof(typename Utf8String::value_type) == 1) && (sizeof(typename StringType::value_type) == 2)>::type* = nullptr> inline StringType fromUtf8(const Utf8String& utf8String, const typename StringType::allocator_type& alloc = typename StringType::allocator_type()) { StringType result(alloc); result.reserve(utf8String.length()); auto iter = utf8String.cbegin(); unsigned utf8_state = S_STRT; std::uint32_t codepoint = 0; while (iter < utf8String.cend()) { if ((utf8_state = consumeUtf8Fragment(utf8_state, static_cast(*iter++), codepoint)) == S_STRT) { if (codepoint <= 0xffff) { result += static_cast(codepoint); } else { codepoint -= 0x10000; result += static_cast((codepoint >> 10) + 0xd800); result += static_cast((codepoint & 0x3ff) + 0xdc00); } codepoint = 0; } else if (utf8_state == S_RJCT) { #ifdef GHC_RAISE_UNICODE_ERRORS throw filesystem_error("Illegal byte sequence for unicode character.", utf8String, std::make_error_code(std::errc::illegal_byte_sequence)); #else result += static_cast(0xfffd); utf8_state = S_STRT; codepoint = 0; #endif } } if (utf8_state) { #ifdef GHC_RAISE_UNICODE_ERRORS throw filesystem_error("Illegal byte sequence for unicode character.", utf8String, std::make_error_code(std::errc::illegal_byte_sequence)); #else result += static_cast(0xfffd); #endif } return result; } template ::value && (sizeof(typename Utf8String::value_type) == 1) && (sizeof(typename StringType::value_type) == 4)>::type* = nullptr> inline StringType fromUtf8(const Utf8String& utf8String, const typename StringType::allocator_type& alloc = typename StringType::allocator_type()) { StringType result(alloc); result.reserve(utf8String.length()); auto iter = utf8String.cbegin(); unsigned utf8_state = S_STRT; std::uint32_t codepoint = 0; while (iter < utf8String.cend()) { if ((utf8_state = consumeUtf8Fragment(utf8_state, static_cast(*iter++), codepoint)) == S_STRT) { result += static_cast(codepoint); codepoint = 0; } else if (utf8_state == S_RJCT) { #ifdef GHC_RAISE_UNICODE_ERRORS throw filesystem_error("Illegal byte sequence for unicode character.", utf8String, std::make_error_code(std::errc::illegal_byte_sequence)); #else result += static_cast(0xfffd); utf8_state = S_STRT; codepoint = 0; #endif } } if (utf8_state) { #ifdef GHC_RAISE_UNICODE_ERRORS throw filesystem_error("Illegal byte sequence for unicode character.", utf8String, std::make_error_code(std::errc::illegal_byte_sequence)); #else result += static_cast(0xfffd); #endif } return result; } template inline StringType fromUtf8(const charT (&utf8String)[N]) { #ifdef GHC_WITH_STRING_VIEW return fromUtf8(basic_string_view(utf8String, N - 1)); #else return fromUtf8(std::basic_string(utf8String, N - 1)); #endif } template ::value && (sizeof(typename strT::value_type) == 1), int>::type size = 1> inline std::string toUtf8(const strT& unicodeString) { return std::string(unicodeString.begin(), unicodeString.end()); } template ::value && (sizeof(typename strT::value_type) == 2), int>::type size = 2> inline std::string toUtf8(const strT& unicodeString) { std::string result; for (auto iter = unicodeString.begin(); iter != unicodeString.end(); ++iter) { char32_t c = *iter; if (is_surrogate(c)) { ++iter; if (iter != unicodeString.end() && is_high_surrogate(c) && is_low_surrogate(*iter)) { appendUTF8(result, (char32_t(c) << 10) + *iter - 0x35fdc00); } else { #ifdef GHC_RAISE_UNICODE_ERRORS throw filesystem_error("Illegal code point for unicode character.", result, std::make_error_code(std::errc::illegal_byte_sequence)); #else appendUTF8(result, 0xfffd); if (iter == unicodeString.end()) { break; } #endif } } else { appendUTF8(result, c); } } return result; } template ::value && (sizeof(typename strT::value_type) == 4), int>::type size = 4> inline std::string toUtf8(const strT& unicodeString) { std::string result; for (auto c : unicodeString) { appendUTF8(result, static_cast(c)); } return result; } template inline std::string toUtf8(const charT* unicodeString) { #ifdef GHC_WITH_STRING_VIEW return toUtf8(basic_string_view>(unicodeString)); #else return toUtf8(std::basic_string>(unicodeString)); #endif } #ifdef GHC_USE_WCHAR_T template ::value && (sizeof(typename WString::value_type) == 2) && (sizeof(typename StringType::value_type) == 1), bool>::type = false> inline StringType fromWChar(const WString& wString, const typename StringType::allocator_type& alloc = typename StringType::allocator_type()) { auto temp = toUtf8(wString); return StringType(temp.begin(), temp.end(), alloc); } template ::value && (sizeof(typename WString::value_type) == 2) && (sizeof(typename StringType::value_type) == 2), bool>::type = false> inline StringType fromWChar(const WString& wString, const typename StringType::allocator_type& alloc = typename StringType::allocator_type()) { return StringType(wString.begin(), wString.end(), alloc); } template ::value && (sizeof(typename WString::value_type) == 2) && (sizeof(typename StringType::value_type) == 4), bool>::type = false> inline StringType fromWChar(const WString& wString, const typename StringType::allocator_type& alloc = typename StringType::allocator_type()) { auto temp = toUtf8(wString); return fromUtf8(temp, alloc); } template ::value && (sizeof(typename strT::value_type) == 1), bool>::type = false> inline std::wstring toWChar(const strT& unicodeString) { return fromUtf8(unicodeString); } template ::value && (sizeof(typename strT::value_type) == 2), bool>::type = false> inline std::wstring toWChar(const strT& unicodeString) { return std::wstring(unicodeString.begin(), unicodeString.end()); } template ::value && (sizeof(typename strT::value_type) == 4), bool>::type = false> inline std::wstring toWChar(const strT& unicodeString) { auto temp = toUtf8(unicodeString); return fromUtf8(temp); } template inline std::wstring toWChar(const charT* unicodeString) { #ifdef GHC_WITH_STRING_VIEW return toWChar(basic_string_view>(unicodeString)); #else return toWChar(std::basic_string>(unicodeString)); #endif } #endif // GHC_USE_WCHAR_T } // namespace detail #ifdef GHC_EXPAND_IMPL namespace detail { template ::value, bool>::type = true> GHC_INLINE bool startsWith(const strT& what, const strT& with) { return with.length() <= what.length() && equal(with.begin(), with.end(), what.begin()); } template ::value, bool>::type = true> GHC_INLINE bool endsWith(const strT& what, const strT& with) { return with.length() <= what.length() && what.compare(what.length() - with.length(), with.size(), with) == 0; } } // namespace detail GHC_INLINE void path::check_long_path() { #if defined(GHC_OS_WINDOWS) && defined(GHC_WIN_AUTO_PREFIX_LONG_PATH) if (is_absolute() && _path.length() >= MAX_PATH - 12 && !detail::startsWith(_path, impl_string_type(GHC_PLATFORM_LITERAL("\\\\?\\")))) { postprocess_path_with_format(native_format); } #endif } GHC_INLINE void path::postprocess_path_with_format(path::format fmt) { #ifdef GHC_RAISE_UNICODE_ERRORS if (!detail::validUtf8(_path)) { path t; t._path = _path; throw filesystem_error("Illegal byte sequence for unicode character.", t, std::make_error_code(std::errc::illegal_byte_sequence)); } #endif switch (fmt) { #ifdef GHC_OS_WINDOWS case path::native_format: case path::auto_format: case path::generic_format: for (auto& c : _path) { if (c == generic_separator) { c = preferred_separator; } } #ifdef GHC_WIN_AUTO_PREFIX_LONG_PATH if (is_absolute() && _path.length() >= MAX_PATH - 12 && !detail::startsWith(_path, impl_string_type(GHC_PLATFORM_LITERAL("\\\\?\\")))) { _path = GHC_PLATFORM_LITERAL("\\\\?\\") + _path; } #endif handle_prefixes(); break; #else case path::auto_format: case path::native_format: case path::generic_format: // nothing to do break; #endif } if (_path.length() > _prefixLength + 2 && _path[_prefixLength] == preferred_separator && _path[_prefixLength + 1] == preferred_separator && _path[_prefixLength + 2] != preferred_separator) { impl_string_type::iterator new_end = std::unique(_path.begin() + static_cast(_prefixLength) + 2, _path.end(), [](path::value_type lhs, path::value_type rhs) { return lhs == rhs && lhs == preferred_separator; }); _path.erase(new_end, _path.end()); } else { impl_string_type::iterator new_end = std::unique(_path.begin() + static_cast(_prefixLength), _path.end(), [](path::value_type lhs, path::value_type rhs) { return lhs == rhs && lhs == preferred_separator; }); _path.erase(new_end, _path.end()); } } #endif // GHC_EXPAND_IMPL template inline path::path(const Source& source, format fmt) #ifdef GHC_USE_WCHAR_T : _path(detail::toWChar(source)) #else : _path(detail::toUtf8(source)) #endif { postprocess_path_with_format(fmt); } template inline path u8path(const Source& source) { return path(source); } template inline path u8path(InputIterator first, InputIterator last) { return path(first, last); } template inline path::path(InputIterator first, InputIterator last, format fmt) : path(std::basic_string::value_type>(first, last), fmt) { // delegated } #ifdef GHC_EXPAND_IMPL namespace detail { GHC_INLINE bool equals_simple_insensitive(const path::value_type* str1, const path::value_type* str2) { #ifdef GHC_OS_WINDOWS #ifdef __GNUC__ while (::tolower((unsigned char)*str1) == ::tolower((unsigned char)*str2++)) { if (*str1++ == 0) return true; } return false; #else // __GNUC__ #ifdef GHC_USE_WCHAR_T return 0 == ::_wcsicmp(str1, str2); #else // GHC_USE_WCHAR_T return 0 == ::_stricmp(str1, str2); #endif // GHC_USE_WCHAR_T #endif // __GNUC__ #else // GHC_OS_WINDOWS return 0 == ::strcasecmp(str1, str2); #endif // GHC_OS_WINDOWS } GHC_INLINE int compare_simple_insensitive(const path::value_type* str1, size_t len1, const path::value_type* str2, size_t len2) { while (len1 > 0 && len2 > 0 && ::tolower(static_cast(*str1)) == ::tolower(static_cast(*str2))) { --len1; --len2; ++str1; ++str2; } if (len1 && len2) { return *str1 < *str2 ? -1 : 1; } if (len1 == 0 && len2 == 0) { return 0; } return len1 == 0 ? -1 : 1; } GHC_INLINE const char* strerror_adapter(char* gnu, char*) { return gnu; } GHC_INLINE const char* strerror_adapter(int posix, char* buffer) { if (posix) { return "Error in strerror_r!"; } return buffer; } template GHC_INLINE std::string systemErrorText(ErrorNumber code = 0) { #if defined(GHC_OS_WINDOWS) LPVOID msgBuf; DWORD dw = code ? static_cast(code) : ::GetLastError(); FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, dw, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR)&msgBuf, 0, NULL); std::string msg = toUtf8(std::wstring((LPWSTR)msgBuf)); LocalFree(msgBuf); return msg; #else char buffer[512]; return strerror_adapter(strerror_r(code ? code : errno, buffer, sizeof(buffer)), buffer); #endif } #ifdef GHC_OS_WINDOWS using CreateSymbolicLinkW_fp = BOOLEAN(WINAPI*)(LPCWSTR, LPCWSTR, DWORD); using CreateHardLinkW_fp = BOOLEAN(WINAPI*)(LPCWSTR, LPCWSTR, LPSECURITY_ATTRIBUTES); GHC_INLINE void create_symlink(const path& target_name, const path& new_symlink, bool to_directory, std::error_code& ec) { std::error_code tec; auto fs = status(target_name, tec); if ((fs.type() == file_type::directory && !to_directory) || (fs.type() == file_type::regular && to_directory)) { ec = detail::make_error_code(detail::portable_error::not_supported); return; } #if defined(__GNUC__) && __GNUC__ >= 8 #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wcast-function-type" #endif static CreateSymbolicLinkW_fp api_call = reinterpret_cast(GetProcAddress(GetModuleHandleW(L"kernel32.dll"), "CreateSymbolicLinkW")); #if defined(__GNUC__) && __GNUC__ >= 8 #pragma GCC diagnostic pop #endif if (api_call) { if (api_call(detail::fromUtf8(new_symlink.u8string()).c_str(), detail::fromUtf8(target_name.u8string()).c_str(), to_directory ? 1 : 0) == 0) { auto result = ::GetLastError(); if (result == ERROR_PRIVILEGE_NOT_HELD && api_call(detail::fromUtf8(new_symlink.u8string()).c_str(), detail::fromUtf8(target_name.u8string()).c_str(), to_directory ? 3 : 2) != 0) { return; } ec = detail::make_system_error(result); } } else { ec = detail::make_system_error(ERROR_NOT_SUPPORTED); } } GHC_INLINE void create_hardlink(const path& target_name, const path& new_hardlink, std::error_code& ec) { #if defined(__GNUC__) && __GNUC__ >= 8 #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wcast-function-type" #endif static CreateHardLinkW_fp api_call = reinterpret_cast(GetProcAddress(GetModuleHandleW(L"kernel32.dll"), "CreateHardLinkW")); #if defined(__GNUC__) && __GNUC__ >= 8 #pragma GCC diagnostic pop #endif if (api_call) { if (api_call(GHC_NATIVEWP(new_hardlink), GHC_NATIVEWP(target_name), NULL) == 0) { ec = detail::make_system_error(); } } else { ec = detail::make_system_error(ERROR_NOT_SUPPORTED); } } GHC_INLINE path getFullPathName(const wchar_t* p, std::error_code& ec) { ULONG size = ::GetFullPathNameW(p, 0, 0, 0); if (size) { std::vector buf(size, 0); ULONG s2 = GetFullPathNameW(p, size, buf.data(), nullptr); if (s2 && s2 < size) { return path(std::wstring(buf.data(), s2)); } } ec = detail::make_system_error(); return path(); } #else GHC_INLINE void create_symlink(const path& target_name, const path& new_symlink, bool, std::error_code& ec) { if (::symlink(target_name.c_str(), new_symlink.c_str()) != 0) { ec = detail::make_system_error(); } } #ifndef GHC_OS_WEB GHC_INLINE void create_hardlink(const path& target_name, const path& new_hardlink, std::error_code& ec) { if (::link(target_name.c_str(), new_hardlink.c_str()) != 0) { ec = detail::make_system_error(); } } #endif #endif template GHC_INLINE file_status file_status_from_st_mode(T mode) { #ifdef GHC_OS_WINDOWS file_type ft = file_type::unknown; if ((mode & _S_IFDIR) == _S_IFDIR) { ft = file_type::directory; } else if ((mode & _S_IFREG) == _S_IFREG) { ft = file_type::regular; } else if ((mode & _S_IFCHR) == _S_IFCHR) { ft = file_type::character; } perms prms = static_cast(mode & 0xfff); return file_status(ft, prms); #else file_type ft = file_type::unknown; if (S_ISDIR(mode)) { ft = file_type::directory; } else if (S_ISREG(mode)) { ft = file_type::regular; } else if (S_ISCHR(mode)) { ft = file_type::character; } else if (S_ISBLK(mode)) { ft = file_type::block; } else if (S_ISFIFO(mode)) { ft = file_type::fifo; } else if (S_ISLNK(mode)) { ft = file_type::symlink; } else if (S_ISSOCK(mode)) { ft = file_type::socket; } perms prms = static_cast(mode & 0xfff); return file_status(ft, prms); #endif } GHC_INLINE path resolveSymlink(const path& p, std::error_code& ec) { #ifdef GHC_OS_WINDOWS #ifndef REPARSE_DATA_BUFFER_HEADER_SIZE typedef struct _REPARSE_DATA_BUFFER { ULONG ReparseTag; USHORT ReparseDataLength; USHORT Reserved; union { struct { USHORT SubstituteNameOffset; USHORT SubstituteNameLength; USHORT PrintNameOffset; USHORT PrintNameLength; ULONG Flags; WCHAR PathBuffer[1]; } SymbolicLinkReparseBuffer; struct { USHORT SubstituteNameOffset; USHORT SubstituteNameLength; USHORT PrintNameOffset; USHORT PrintNameLength; WCHAR PathBuffer[1]; } MountPointReparseBuffer; struct { UCHAR DataBuffer[1]; } GenericReparseBuffer; } DUMMYUNIONNAME; } REPARSE_DATA_BUFFER; #ifndef MAXIMUM_REPARSE_DATA_BUFFER_SIZE #define MAXIMUM_REPARSE_DATA_BUFFER_SIZE (16 * 1024) #endif #endif std::shared_ptr file(CreateFileW(GHC_NATIVEWP(p), 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 0, OPEN_EXISTING, FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, 0), CloseHandle); if (file.get() == INVALID_HANDLE_VALUE) { ec = detail::make_system_error(); return path(); } std::shared_ptr reparseData((REPARSE_DATA_BUFFER*)std::calloc(1, MAXIMUM_REPARSE_DATA_BUFFER_SIZE), std::free); ULONG bufferUsed; path result; if (DeviceIoControl(file.get(), FSCTL_GET_REPARSE_POINT, 0, 0, reparseData.get(), MAXIMUM_REPARSE_DATA_BUFFER_SIZE, &bufferUsed, 0)) { if (IsReparseTagMicrosoft(reparseData->ReparseTag)) { switch (reparseData->ReparseTag) { case IO_REPARSE_TAG_SYMLINK: { auto printName = std::wstring(&reparseData->SymbolicLinkReparseBuffer.PathBuffer[reparseData->SymbolicLinkReparseBuffer.PrintNameOffset / sizeof(WCHAR)], reparseData->SymbolicLinkReparseBuffer.PrintNameLength / sizeof(WCHAR)); auto substituteName = std::wstring(&reparseData->SymbolicLinkReparseBuffer.PathBuffer[reparseData->SymbolicLinkReparseBuffer.SubstituteNameOffset / sizeof(WCHAR)], reparseData->SymbolicLinkReparseBuffer.SubstituteNameLength / sizeof(WCHAR)); if (detail::endsWith(substituteName, printName) && detail::startsWith(substituteName, std::wstring(L"\\??\\"))) { result = printName; } else { result = substituteName; } if (reparseData->SymbolicLinkReparseBuffer.Flags & 0x1 /*SYMLINK_FLAG_RELATIVE*/) { result = p.parent_path() / result; } break; } case IO_REPARSE_TAG_MOUNT_POINT: result = std::wstring(&reparseData->MountPointReparseBuffer.PathBuffer[reparseData->MountPointReparseBuffer.SubstituteNameOffset / sizeof(WCHAR)], reparseData->MountPointReparseBuffer.SubstituteNameLength / sizeof(WCHAR)); break; default: break; } } } else { ec = detail::make_system_error(); } return result; #else size_t bufferSize = 256; while (true) { std::vector buffer(bufferSize, static_cast(0)); auto rc = ::readlink(p.c_str(), buffer.data(), buffer.size()); if (rc < 0) { ec = detail::make_system_error(); return path(); } else if (rc < static_cast(bufferSize)) { return path(std::string(buffer.data(), static_cast(rc))); } bufferSize *= 2; } return path(); #endif } #ifdef GHC_OS_WINDOWS GHC_INLINE time_t timeFromFILETIME(const FILETIME& ft) { ULARGE_INTEGER ull; ull.LowPart = ft.dwLowDateTime; ull.HighPart = ft.dwHighDateTime; return static_cast(ull.QuadPart / 10000000ULL - 11644473600ULL); } GHC_INLINE void timeToFILETIME(time_t t, FILETIME& ft) { LONGLONG ll; ll = Int32x32To64(t, 10000000) + 116444736000000000; ft.dwLowDateTime = static_cast(ll); ft.dwHighDateTime = static_cast(ll >> 32); } template GHC_INLINE uintmax_t hard_links_from_INFO(const INFO* info) { return static_cast(-1); } template <> GHC_INLINE uintmax_t hard_links_from_INFO(const BY_HANDLE_FILE_INFORMATION* info) { return info->nNumberOfLinks; } template GHC_INLINE file_status status_from_INFO(const path& p, const INFO* info, std::error_code&, uintmax_t* sz = nullptr, time_t* lwt = nullptr) { file_type ft = file_type::unknown; if ((info->dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) { ft = file_type::symlink; } else { if ((info->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { ft = file_type::directory; } else { ft = file_type::regular; } } perms prms = perms::owner_read | perms::group_read | perms::others_read; if (!(info->dwFileAttributes & FILE_ATTRIBUTE_READONLY)) { prms = prms | perms::owner_write | perms::group_write | perms::others_write; } if (has_executable_extension(p)) { prms = prms | perms::owner_exec | perms::group_exec | perms::others_exec; } if (sz) { *sz = static_cast(info->nFileSizeHigh) << (sizeof(info->nFileSizeHigh) * 8) | info->nFileSizeLow; } if (lwt) { *lwt = detail::timeFromFILETIME(info->ftLastWriteTime); } return file_status(ft, prms); } #endif GHC_INLINE bool is_not_found_error(std::error_code& ec) { #ifdef GHC_OS_WINDOWS return ec.value() == ERROR_FILE_NOT_FOUND || ec.value() == ERROR_PATH_NOT_FOUND || ec.value() == ERROR_INVALID_NAME; #else return ec.value() == ENOENT || ec.value() == ENOTDIR; #endif } GHC_INLINE file_status symlink_status_ex(const path& p, std::error_code& ec, uintmax_t* sz = nullptr, uintmax_t* nhl = nullptr, time_t* lwt = nullptr) noexcept { #ifdef GHC_OS_WINDOWS file_status fs; WIN32_FILE_ATTRIBUTE_DATA attr; if (!GetFileAttributesExW(GHC_NATIVEWP(p), GetFileExInfoStandard, &attr)) { ec = detail::make_system_error(); } else { ec.clear(); fs = detail::status_from_INFO(p, &attr, ec, sz, lwt); if (nhl) { *nhl = 0; } if (attr.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) { fs.type(file_type::symlink); } } if (detail::is_not_found_error(ec)) { return file_status(file_type::not_found); } return ec ? file_status(file_type::none) : fs; #else (void)sz; (void)nhl; (void)lwt; struct ::stat fs; auto result = ::lstat(p.c_str(), &fs); if (result == 0) { ec.clear(); file_status f_s = detail::file_status_from_st_mode(fs.st_mode); return f_s; } ec = detail::make_system_error(); if (detail::is_not_found_error(ec)) { return file_status(file_type::not_found, perms::unknown); } return file_status(file_type::none); #endif } GHC_INLINE file_status status_ex(const path& p, std::error_code& ec, file_status* sls = nullptr, uintmax_t* sz = nullptr, uintmax_t* nhl = nullptr, time_t* lwt = nullptr, int recurse_count = 0) noexcept { ec.clear(); #ifdef GHC_OS_WINDOWS if (recurse_count > 16) { ec = detail::make_system_error(0x2A9 /*ERROR_STOPPED_ON_SYMLINK*/); return file_status(file_type::unknown); } WIN32_FILE_ATTRIBUTE_DATA attr; if (!::GetFileAttributesExW(GHC_NATIVEWP(p), GetFileExInfoStandard, &attr)) { ec = detail::make_system_error(); } else if (attr.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) { path target = resolveSymlink(p, ec); file_status result; if (!ec && !target.empty()) { if (sls) { *sls = status_from_INFO(p, &attr, ec); } return detail::status_ex(target, ec, nullptr, sz, nhl, lwt, recurse_count + 1); } return file_status(file_type::unknown); } if (ec) { if (detail::is_not_found_error(ec)) { return file_status(file_type::not_found); } return file_status(file_type::none); } if (nhl) { *nhl = 0; } return detail::status_from_INFO(p, &attr, ec, sz, lwt); #else (void)recurse_count; struct ::stat st; auto result = ::lstat(p.c_str(), &st); if (result == 0) { ec.clear(); file_status fs = detail::file_status_from_st_mode(st.st_mode); if (sls) { *sls = fs; } if (fs.type() == file_type::symlink) { result = ::stat(p.c_str(), &st); if (result == 0) { fs = detail::file_status_from_st_mode(st.st_mode); } else { ec = detail::make_system_error(); if (detail::is_not_found_error(ec)) { return file_status(file_type::not_found, perms::unknown); } return file_status(file_type::none); } } if (sz) { *sz = static_cast(st.st_size); } if (nhl) { *nhl = st.st_nlink; } if (lwt) { *lwt = st.st_mtime; } return fs; } else { ec = detail::make_system_error(); if (detail::is_not_found_error(ec)) { return file_status(file_type::not_found, perms::unknown); } return file_status(file_type::none); } #endif } } // namespace detail GHC_INLINE u8arguments::u8arguments(int& argc, char**& argv) : _argc(argc) , _argv(argv) , _refargc(argc) , _refargv(argv) , _isvalid(false) { #ifdef GHC_OS_WINDOWS LPWSTR* p; p = ::CommandLineToArgvW(::GetCommandLineW(), &argc); _args.reserve(static_cast(argc)); _argp.reserve(static_cast(argc)); for (size_t i = 0; i < static_cast(argc); ++i) { _args.push_back(detail::toUtf8(std::wstring(p[i]))); _argp.push_back((char*)_args[i].data()); } argv = _argp.data(); ::LocalFree(p); _isvalid = true; #else std::setlocale(LC_ALL, ""); #if defined(__ANDROID__) && __ANDROID_API__ < 26 _isvalid = true; #else if (detail::equals_simple_insensitive(::nl_langinfo(CODESET), "UTF-8")) { _isvalid = true; } #endif #endif } //----------------------------------------------------------------------------- // 30.10.8.4.1 constructors and destructor GHC_INLINE path::path() noexcept {} GHC_INLINE path::path(const path& p) : _path(p._path) #if defined(GHC_OS_WINDOWS) && defined(GHC_WIN_AUTO_PREFIX_LONG_PATH) , _prefixLength(p._prefixLength) #endif { } GHC_INLINE path::path(path&& p) noexcept : _path(std::move(p._path)) #if defined(GHC_OS_WINDOWS) && defined(GHC_WIN_AUTO_PREFIX_LONG_PATH) , _prefixLength(p._prefixLength) #endif { } GHC_INLINE path::path(string_type&& source, format fmt) : _path(std::move(source)) { postprocess_path_with_format(fmt); } #endif // GHC_EXPAND_IMPL #ifdef GHC_WITH_EXCEPTIONS template inline path::path(const Source& source, const std::locale& loc, format fmt) : path(source, fmt) { std::string locName = loc.name(); if (!(locName.length() >= 5 && (locName.substr(locName.length() - 5) == "UTF-8" || locName.substr(locName.length() - 5) == "utf-8"))) { throw filesystem_error("This implementation only supports UTF-8 locales!", path(_path), detail::make_error_code(detail::portable_error::not_supported)); } } template inline path::path(InputIterator first, InputIterator last, const std::locale& loc, format fmt) : path(std::basic_string::value_type>(first, last), fmt) { std::string locName = loc.name(); if (!(locName.length() >= 5 && (locName.substr(locName.length() - 5) == "UTF-8" || locName.substr(locName.length() - 5) == "utf-8"))) { throw filesystem_error("This implementation only supports UTF-8 locales!", path(_path), detail::make_error_code(detail::portable_error::not_supported)); } } #endif #ifdef GHC_EXPAND_IMPL GHC_INLINE path::~path() {} //----------------------------------------------------------------------------- // 30.10.8.4.2 assignments GHC_INLINE path& path::operator=(const path& p) { _path = p._path; #if defined(GHC_OS_WINDOWS) && defined(GHC_WIN_AUTO_PREFIX_LONG_PATH) _prefixLength = p._prefixLength; #endif return *this; } GHC_INLINE path& path::operator=(path&& p) noexcept { _path = std::move(p._path); #if defined(GHC_OS_WINDOWS) && defined(GHC_WIN_AUTO_PREFIX_LONG_PATH) _prefixLength = p._prefixLength; #endif return *this; } GHC_INLINE path& path::operator=(path::string_type&& source) { return assign(source); } GHC_INLINE path& path::assign(path::string_type&& source) { _path = std::move(source); postprocess_path_with_format(native_format); return *this; } #endif // GHC_EXPAND_IMPL template inline path& path::operator=(const Source& source) { return assign(source); } template inline path& path::assign(const Source& source) { #ifdef GHC_USE_WCHAR_T _path.assign(detail::toWChar(source)); #else _path.assign(detail::toUtf8(source)); #endif postprocess_path_with_format(native_format); return *this; } template <> inline path& path::assign(const path& source) { _path = source._path; #if defined(GHC_OS_WINDOWS) && defined(GHC_WIN_AUTO_PREFIX_LONG_PATH) _prefixLength = source._prefixLength; #endif return *this; } template inline path& path::assign(InputIterator first, InputIterator last) { _path.assign(first, last); postprocess_path_with_format(native_format); return *this; } #ifdef GHC_EXPAND_IMPL //----------------------------------------------------------------------------- // 30.10.8.4.3 appends GHC_INLINE path& path::operator/=(const path& p) { if (p.empty()) { // was: if ((!has_root_directory() && is_absolute()) || has_filename()) if (!_path.empty() && _path[_path.length() - 1] != preferred_separator && _path[_path.length() - 1] != ':') { _path += preferred_separator; } return *this; } if ((p.is_absolute() && (_path != root_name()._path || p._path != "/")) || (p.has_root_name() && p.root_name() != root_name())) { assign(p); return *this; } if (p.has_root_directory()) { assign(root_name()); } else if ((!has_root_directory() && is_absolute()) || has_filename()) { _path += preferred_separator; } auto iter = p.begin(); bool first = true; if (p.has_root_name()) { ++iter; } while (iter != p.end()) { if (!first && !(!_path.empty() && _path[_path.length() - 1] == preferred_separator)) { _path += preferred_separator; } first = false; _path += (*iter++).native(); } check_long_path(); return *this; } GHC_INLINE void path::append_name(const value_type* name) { if (_path.empty()) { this->operator/=(path(name)); } else { if (_path.back() != path::preferred_separator) { _path.push_back(path::preferred_separator); } _path += name; check_long_path(); } } #endif // GHC_EXPAND_IMPL template inline path& path::operator/=(const Source& source) { return append(source); } template inline path& path::append(const Source& source) { return this->operator/=(path(source)); } template <> inline path& path::append(const path& p) { return this->operator/=(p); } template inline path& path::append(InputIterator first, InputIterator last) { std::basic_string::value_type> part(first, last); return append(part); } #ifdef GHC_EXPAND_IMPL //----------------------------------------------------------------------------- // 30.10.8.4.4 concatenation GHC_INLINE path& path::operator+=(const path& x) { return concat(x._path); } GHC_INLINE path& path::operator+=(const string_type& x) { return concat(x); } #ifdef GHC_WITH_STRING_VIEW GHC_INLINE path& path::operator+=(basic_string_view x) { return concat(x); } #endif GHC_INLINE path& path::operator+=(const value_type* x) { #ifdef GHC_WITH_STRING_VIEW basic_string_view part(x); #else string_type part(x); #endif return concat(part); } GHC_INLINE path& path::operator+=(value_type x) { #ifdef GHC_OS_WINDOWS if (x == generic_separator) { x = preferred_separator; } #endif if (_path.empty() || _path.back() != preferred_separator) { _path += x; } check_long_path(); return *this; } #endif // GHC_EXPAND_IMPL template inline path::path_from_string& path::operator+=(const Source& x) { return concat(x); } template inline path::path_type_EcharT& path::operator+=(EcharT x) { #ifdef GHC_WITH_STRING_VIEW basic_string_view part(&x, 1); #else std::basic_string part(1, x); #endif concat(part); return *this; } template inline path& path::concat(const Source& x) { path p(x); _path += p._path; postprocess_path_with_format(native_format); return *this; } template inline path& path::concat(InputIterator first, InputIterator last) { _path.append(first, last); postprocess_path_with_format(native_format); return *this; } #ifdef GHC_EXPAND_IMPL //----------------------------------------------------------------------------- // 30.10.8.4.5 modifiers GHC_INLINE void path::clear() noexcept { _path.clear(); #if defined(GHC_OS_WINDOWS) && defined(GHC_WIN_AUTO_PREFIX_LONG_PATH) _prefixLength = 0; #endif } GHC_INLINE path& path::make_preferred() { // as this filesystem implementation only uses generic_format // internally, this must be a no-op return *this; } GHC_INLINE path& path::remove_filename() { if (has_filename()) { _path.erase(_path.size() - filename()._path.size()); } return *this; } GHC_INLINE path& path::replace_filename(const path& replacement) { remove_filename(); return append(replacement); } GHC_INLINE path& path::replace_extension(const path& replacement) { if (has_extension()) { _path.erase(_path.size() - extension()._path.size()); } if (!replacement.empty() && replacement._path[0] != '.') { _path += '.'; } return concat(replacement); } GHC_INLINE void path::swap(path& rhs) noexcept { _path.swap(rhs._path); #if defined(GHC_OS_WINDOWS) && defined(GHC_WIN_AUTO_PREFIX_LONG_PATH) std::swap(_prefixLength, rhs._prefixLength); #endif } //----------------------------------------------------------------------------- // 30.10.8.4.6, native format observers GHC_INLINE const path::string_type& path::native() const noexcept { return _path; } GHC_INLINE const path::value_type* path::c_str() const noexcept { return native().c_str(); } GHC_INLINE path::operator path::string_type() const { return native(); } #endif // GHC_EXPAND_IMPL template inline std::basic_string path::string(const Allocator& a) const { #ifdef GHC_USE_WCHAR_T return detail::fromWChar>(_path, a); #else return detail::fromUtf8>(_path, a); #endif } #ifdef GHC_EXPAND_IMPL GHC_INLINE std::string path::string() const { #ifdef GHC_USE_WCHAR_T return detail::toUtf8(native()); #else return native(); #endif } GHC_INLINE std::wstring path::wstring() const { #ifdef GHC_USE_WCHAR_T return native(); #else return detail::fromUtf8(native()); #endif } #if defined(__cpp_lib_char8_t) && !defined(GHC_FILESYSTEM_ENFORCE_CPP17_API) GHC_INLINE std::u8string path::u8string() const { #ifdef GHC_USE_WCHAR_T return std::u8string(reinterpret_cast(detail::toUtf8(native()).c_str())); #else return std::u8string(reinterpret_cast(c_str())); #endif } #else GHC_INLINE std::string path::u8string() const { #ifdef GHC_USE_WCHAR_T return detail::toUtf8(native()); #else return native(); #endif } #endif GHC_INLINE std::u16string path::u16string() const { // TODO: optimize return detail::fromUtf8(string()); } GHC_INLINE std::u32string path::u32string() const { // TODO: optimize return detail::fromUtf8(string()); } #endif // GHC_EXPAND_IMPL //----------------------------------------------------------------------------- // 30.10.8.4.7, generic format observers template inline std::basic_string path::generic_string(const Allocator& a) const { #ifdef GHC_OS_WINDOWS #ifdef GHC_USE_WCHAR_T auto result = detail::fromWChar, path::string_type>(_path, a); #else auto result = detail::fromUtf8>(_path, a); #endif for (auto& c : result) { if (c == preferred_separator) { c = generic_separator; } } return result; #else return detail::fromUtf8>(_path, a); #endif } #ifdef GHC_EXPAND_IMPL GHC_INLINE std::string path::generic_string() const { #ifdef GHC_OS_WINDOWS return generic_string(); #else return _path; #endif } GHC_INLINE std::wstring path::generic_wstring() const { #ifdef GHC_OS_WINDOWS return generic_string(); #else return detail::fromUtf8(_path); #endif } // namespace filesystem #if defined(__cpp_lib_char8_t) && !defined(GHC_FILESYSTEM_ENFORCE_CPP17_API) GHC_INLINE std::u8string path::generic_u8string() const { #ifdef GHC_OS_WINDOWS return generic_string(); #else return std::u8string(reinterpret_cast(_path.c_str())); #endif } #else GHC_INLINE std::string path::generic_u8string() const { #ifdef GHC_OS_WINDOWS return generic_string(); #else return _path; #endif } #endif GHC_INLINE std::u16string path::generic_u16string() const { #ifdef GHC_OS_WINDOWS return generic_string(); #else return detail::fromUtf8(_path); #endif } GHC_INLINE std::u32string path::generic_u32string() const { #ifdef GHC_OS_WINDOWS return generic_string(); #else return detail::fromUtf8(_path); #endif } //----------------------------------------------------------------------------- // 30.10.8.4.8, compare GHC_INLINE int path::compare(const path& p) const noexcept { #ifdef LWG_2936_BEHAVIOUR auto rnl1 = root_name_length(); auto rnl2 = p.root_name_length(); #ifdef GHC_OS_WINDOWS auto rnc = detail::compare_simple_insensitive(_path.c_str(), rnl1, p._path.c_str(), rnl2); #else auto rnc = _path.compare(0, rnl1, p._path, 0, (std::min(rnl1, rnl2))); #endif if (rnc) { return rnc; } bool hrd1 = has_root_directory(), hrd2 = p.has_root_directory(); if (hrd1 != hrd2) { return hrd1 ? 1 : -1; } if (hrd1) { ++rnl1; ++rnl2; } auto iter1 = _path.begin() + static_cast(rnl1); auto iter2 = p._path.begin() + static_cast(rnl2); while (iter1 != _path.end() && iter2 != p._path.end() && *iter1 == *iter2) { ++iter1; ++iter2; } if (iter1 == _path.end()) { return iter2 == p._path.end() ? 0 : -1; } if (iter2 == p._path.end()) { return 1; } if (*iter1 == preferred_separator) { return -1; } if (*iter2 == preferred_separator) { return 1; } return *iter1 < *iter2 ? -1 : 1; #else // LWG_2936_BEHAVIOUR #ifdef GHC_OS_WINDOWS auto rnl1 = root_name_length(); auto rnl2 = p.root_name_length(); auto rnc = detail::compare_simple_insensitive(_path.c_str(), rnl1, p._path.c_str(), rnl2); if (rnc) { return rnc; } return _path.compare(rnl1, std::string::npos, p._path, rnl2, std::string::npos); #else return _path.compare(p._path); #endif #endif } GHC_INLINE int path::compare(const string_type& s) const { return compare(path(s)); } #ifdef GHC_WITH_STRING_VIEW GHC_INLINE int path::compare(basic_string_view s) const { return compare(path(s)); } #endif GHC_INLINE int path::compare(const value_type* s) const { return compare(path(s)); } //----------------------------------------------------------------------------- // 30.10.8.4.9, decomposition #ifdef GHC_OS_WINDOWS GHC_INLINE void path::handle_prefixes() { #if defined(GHC_WIN_AUTO_PREFIX_LONG_PATH) _prefixLength = 0; if (_path.length() >= 6 && _path[2] == '?' && std::toupper(static_cast(_path[4])) >= 'A' && std::toupper(static_cast(_path[4])) <= 'Z' && _path[5] == ':') { if (detail::startsWith(_path, impl_string_type(GHC_PLATFORM_LITERAL("\\\\?\\"))) || detail::startsWith(_path, impl_string_type(GHC_PLATFORM_LITERAL("\\??\\")))) { _prefixLength = 4; } } #endif // GHC_WIN_AUTO_PREFIX_LONG_PATH } #endif GHC_INLINE path::string_type::size_type path::root_name_length() const noexcept { #ifdef GHC_OS_WINDOWS if (_path.length() >= _prefixLength + 2 && std::toupper(static_cast(_path[_prefixLength])) >= 'A' && std::toupper(static_cast(_path[_prefixLength])) <= 'Z' && _path[_prefixLength + 1] == ':') { return 2; } #endif if (_path.length() > _prefixLength + 2 && _path[_prefixLength] == preferred_separator && _path[_prefixLength + 1] == preferred_separator && _path[_prefixLength + 2] != preferred_separator && std::isprint(_path[_prefixLength + 2])) { impl_string_type::size_type pos = _path.find(preferred_separator, _prefixLength + 3); if (pos == impl_string_type::npos) { return _path.length(); } else { return pos; } } return 0; } GHC_INLINE path path::root_name() const { return path(_path.substr(_prefixLength, root_name_length()), native_format); } GHC_INLINE path path::root_directory() const { if (has_root_directory()) { static const path _root_dir(std::string(1, preferred_separator), native_format); return _root_dir; } return path(); } GHC_INLINE path path::root_path() const { return path(root_name().string() + root_directory().string(), native_format); } GHC_INLINE path path::relative_path() const { auto rootPathLen = _prefixLength + root_name_length() + (has_root_directory() ? 1 : 0); return path(_path.substr((std::min)(rootPathLen, _path.length())), generic_format); } GHC_INLINE path path::parent_path() const { auto rootPathLen = _prefixLength + root_name_length() + (has_root_directory() ? 1 : 0); if (rootPathLen < _path.length()) { if (empty()) { return path(); } else { auto piter = end(); auto iter = piter.decrement(_path.end()); if (iter > _path.begin() + static_cast(rootPathLen) && *iter != preferred_separator) { --iter; } return path(_path.begin(), iter, native_format); } } else { return *this; } } GHC_INLINE path path::filename() const { return !has_relative_path() ? path() : path(*--end()); } GHC_INLINE path path::stem() const { impl_string_type fn = filename().native(); if (fn != "." && fn != "..") { impl_string_type::size_type pos = fn.rfind('.'); if (pos != impl_string_type::npos && pos > 0) { return path{fn.substr(0, pos), native_format}; } } return path{fn, native_format}; } GHC_INLINE path path::extension() const { if (has_relative_path()) { auto iter = end(); const auto& fn = *--iter; impl_string_type::size_type pos = fn._path.rfind('.'); if (pos != std::string::npos && pos > 0) { return path(fn._path.substr(pos), native_format); } } return path(); } #ifdef GHC_OS_WINDOWS namespace detail { GHC_INLINE bool has_executable_extension(const path& p) { if (p.has_relative_path()) { auto iter = p.end(); const auto& fn = *--iter; auto pos = fn._path.find_last_of('.'); if (pos == std::string::npos || pos == 0 || fn._path.length() - pos != 3) { return false; } const path::value_type* ext = fn._path.c_str() + pos + 1; if (detail::equals_simple_insensitive(ext, GHC_PLATFORM_LITERAL("exe")) || detail::equals_simple_insensitive(ext, GHC_PLATFORM_LITERAL("cmd")) || detail::equals_simple_insensitive(ext, GHC_PLATFORM_LITERAL("bat")) || detail::equals_simple_insensitive(ext, GHC_PLATFORM_LITERAL("com"))) { return true; } } return false; } } // namespace detail #endif //----------------------------------------------------------------------------- // 30.10.8.4.10, query GHC_INLINE bool path::empty() const noexcept { return _path.empty(); } GHC_INLINE bool path::has_root_name() const { return root_name_length() > 0; } GHC_INLINE bool path::has_root_directory() const { auto rootLen = _prefixLength + root_name_length(); return (_path.length() > rootLen && _path[rootLen] == preferred_separator); } GHC_INLINE bool path::has_root_path() const { return has_root_name() || has_root_directory(); } GHC_INLINE bool path::has_relative_path() const { auto rootPathLen = _prefixLength + root_name_length() + (has_root_directory() ? 1 : 0); return rootPathLen < _path.length(); } GHC_INLINE bool path::has_parent_path() const { return !parent_path().empty(); } GHC_INLINE bool path::has_filename() const { return has_relative_path() && !filename().empty(); } GHC_INLINE bool path::has_stem() const { return !stem().empty(); } GHC_INLINE bool path::has_extension() const { return !extension().empty(); } GHC_INLINE bool path::is_absolute() const { #ifdef GHC_OS_WINDOWS return has_root_name() && has_root_directory(); #else return has_root_directory(); #endif } GHC_INLINE bool path::is_relative() const { return !is_absolute(); } //----------------------------------------------------------------------------- // 30.10.8.4.11, generation GHC_INLINE path path::lexically_normal() const { path dest; bool lastDotDot = false; for (string_type s : *this) { if (s == ".") { dest /= ""; continue; } else if (s == ".." && !dest.empty()) { auto root = root_path(); if (dest == root) { continue; } else if (*(--dest.end()) != "..") { if (dest._path.back() == preferred_separator) { dest._path.pop_back(); } dest.remove_filename(); continue; } } if (!(s.empty() && lastDotDot)) { dest /= s; } lastDotDot = s == ".."; } if (dest.empty()) { dest = "."; } return dest; } GHC_INLINE path path::lexically_relative(const path& base) const { if (root_name() != base.root_name() || is_absolute() != base.is_absolute() || (!has_root_directory() && base.has_root_directory())) { return path(); } const_iterator a = begin(), b = base.begin(); while (a != end() && b != base.end() && *a == *b) { ++a; ++b; } if (a == end() && b == base.end()) { return path("."); } int count = 0; for (const auto& element : input_iterator_range(b, base.end())) { if (element != "." && element != "" && element != "..") { ++count; } else if (element == "..") { --count; } } if (count < 0) { return path(); } path result; for (int i = 0; i < count; ++i) { result /= ".."; } for (const auto& element : input_iterator_range(a, end())) { result /= element; } return result; } GHC_INLINE path path::lexically_proximate(const path& base) const { path result = lexically_relative(base); return result.empty() ? *this : result; } //----------------------------------------------------------------------------- // 30.10.8.5, iterators GHC_INLINE path::iterator::iterator() {} GHC_INLINE path::iterator::iterator(const path& p, const impl_string_type::const_iterator& pos) : _first(p._path.begin()) , _last(p._path.end()) , _prefix(_first + static_cast(p._prefixLength)) , _root(p.has_root_directory() ? _first + static_cast(p._prefixLength + p.root_name_length()) : _last) , _iter(pos) { if(pos != _last) { updateCurrent(); } } GHC_INLINE path::impl_string_type::const_iterator path::iterator::increment(const path::impl_string_type::const_iterator& pos) const { path::impl_string_type::const_iterator i = pos; bool fromStart = i == _first || i == _prefix; if (i != _last) { if (fromStart && i == _first && _prefix > _first) { i = _prefix; } else if (*i++ == preferred_separator) { // we can only sit on a slash if it is a network name or a root if (i != _last && *i == preferred_separator) { if (fromStart && !(i + 1 != _last && *(i + 1) == preferred_separator)) { // leadind double slashes detected, treat this and the // following until a slash as one unit i = std::find(++i, _last, preferred_separator); } else { // skip redundant slashes while (i != _last && *i == preferred_separator) { ++i; } } } } else { if (fromStart && i != _last && *i == ':') { ++i; } else { i = std::find(i, _last, preferred_separator); } } } return i; } GHC_INLINE path::impl_string_type::const_iterator path::iterator::decrement(const path::impl_string_type::const_iterator& pos) const { path::impl_string_type::const_iterator i = pos; if (i != _first) { --i; // if this is now the root slash or the trailing slash, we are done, // else check for network name if (i != _root && (pos != _last || *i != preferred_separator)) { #ifdef GHC_OS_WINDOWS static const impl_string_type seps = GHC_PLATFORM_LITERAL("\\:"); i = std::find_first_of(std::reverse_iterator(i), std::reverse_iterator(_first), seps.begin(), seps.end()).base(); if (i > _first && *i == ':') { i++; } #else i = std::find(std::reverse_iterator(i), std::reverse_iterator(_first), preferred_separator).base(); #endif // Now we have to check if this is a network name if (i - _first == 2 && *_first == preferred_separator && *(_first + 1) == preferred_separator) { i -= 2; } } } return i; } GHC_INLINE void path::iterator::updateCurrent() { if ((_iter == _last) || (_iter != _first && _iter != _last && (*_iter == preferred_separator && _iter != _root) && (_iter + 1 == _last))) { _current.clear(); } else { _current.assign(_iter, increment(_iter)); } } GHC_INLINE path::iterator& path::iterator::operator++() { _iter = increment(_iter); while (_iter != _last && // we didn't reach the end _iter != _root && // this is not a root position *_iter == preferred_separator && // we are on a separator (_iter + 1) != _last // the slash is not the last char ) { ++_iter; } updateCurrent(); return *this; } GHC_INLINE path::iterator path::iterator::operator++(int) { path::iterator i{*this}; ++(*this); return i; } GHC_INLINE path::iterator& path::iterator::operator--() { _iter = decrement(_iter); updateCurrent(); return *this; } GHC_INLINE path::iterator path::iterator::operator--(int) { auto i = *this; --(*this); return i; } GHC_INLINE bool path::iterator::operator==(const path::iterator& other) const { return _iter == other._iter; } GHC_INLINE bool path::iterator::operator!=(const path::iterator& other) const { return _iter != other._iter; } GHC_INLINE path::iterator::reference path::iterator::operator*() const { return _current; } GHC_INLINE path::iterator::pointer path::iterator::operator->() const { return &_current; } GHC_INLINE path::iterator path::begin() const { return iterator(*this, _path.begin()); } GHC_INLINE path::iterator path::end() const { return iterator(*this, _path.end()); } //----------------------------------------------------------------------------- // 30.10.8.6, path non-member functions GHC_INLINE void swap(path& lhs, path& rhs) noexcept { swap(lhs._path, rhs._path); } GHC_INLINE size_t hash_value(const path& p) noexcept { return std::hash()(p.generic_string()); } #ifdef GHC_HAS_THREEWAY_COMP GHC_INLINE std::strong_ordering operator<=>(const path& lhs, const path& rhs) noexcept { return lhs.compare(rhs) <=> 0; } #endif GHC_INLINE bool operator==(const path& lhs, const path& rhs) noexcept { return lhs.compare(rhs) == 0; } GHC_INLINE bool operator!=(const path& lhs, const path& rhs) noexcept { return !(lhs == rhs); } GHC_INLINE bool operator<(const path& lhs, const path& rhs) noexcept { return lhs.compare(rhs) < 0; } GHC_INLINE bool operator<=(const path& lhs, const path& rhs) noexcept { return lhs.compare(rhs) <= 0; } GHC_INLINE bool operator>(const path& lhs, const path& rhs) noexcept { return lhs.compare(rhs) > 0; } GHC_INLINE bool operator>=(const path& lhs, const path& rhs) noexcept { return lhs.compare(rhs) >= 0; } GHC_INLINE path operator/(const path& lhs, const path& rhs) { path result(lhs); result /= rhs; return result; } #endif // GHC_EXPAND_IMPL //----------------------------------------------------------------------------- // 30.10.8.6.1 path inserter and extractor template inline std::basic_ostream& operator<<(std::basic_ostream& os, const path& p) { os << "\""; auto ps = p.string(); for (auto c : ps) { if (c == '"' || c == '\\') { os << '\\'; } os << c; } os << "\""; return os; } template inline std::basic_istream& operator>>(std::basic_istream& is, path& p) { std::basic_string tmp; charT c; is >> c; if (c == '"') { auto sf = is.flags(); is >> std::noskipws; while (is) { auto c2 = is.get(); if (is) { if (c2 == '\\') { c2 = is.get(); if (is) { tmp += static_cast(c2); } } else if (c2 == '"') { break; } else { tmp += static_cast(c2); } } } if ((sf & std::ios_base::skipws) == std::ios_base::skipws) { is >> std::skipws; } p = path(tmp); } else { is >> tmp; p = path(static_cast(c) + tmp); } return is; } #ifdef GHC_EXPAND_IMPL //----------------------------------------------------------------------------- // 30.10.9 Class filesystem_error GHC_INLINE filesystem_error::filesystem_error(const std::string& what_arg, std::error_code ec) : std::system_error(ec, what_arg) , _what_arg(what_arg) , _ec(ec) { } GHC_INLINE filesystem_error::filesystem_error(const std::string& what_arg, const path& p1, std::error_code ec) : std::system_error(ec, what_arg) , _what_arg(what_arg) , _ec(ec) , _p1(p1) { if (!_p1.empty()) { _what_arg += ": '" + _p1.string() + "'"; } } GHC_INLINE filesystem_error::filesystem_error(const std::string& what_arg, const path& p1, const path& p2, std::error_code ec) : std::system_error(ec, what_arg) , _what_arg(what_arg) , _ec(ec) , _p1(p1) , _p2(p2) { if (!_p1.empty()) { _what_arg += ": '" + _p1.string() + "'"; } if (!_p2.empty()) { _what_arg += ", '" + _p2.string() + "'"; } } GHC_INLINE const path& filesystem_error::path1() const noexcept { return _p1; } GHC_INLINE const path& filesystem_error::path2() const noexcept { return _p2; } GHC_INLINE const char* filesystem_error::what() const noexcept { return _what_arg.c_str(); } //----------------------------------------------------------------------------- // 30.10.15, filesystem operations #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE path absolute(const path& p) { std::error_code ec; path result = absolute(p, ec); if (ec) { throw filesystem_error(detail::systemErrorText(ec.value()), p, ec); } return result; } #endif GHC_INLINE path absolute(const path& p, std::error_code& ec) { ec.clear(); #ifdef GHC_OS_WINDOWS if (p.empty()) { return absolute(current_path(ec), ec) / ""; } ULONG size = ::GetFullPathNameW(GHC_NATIVEWP(p), 0, 0, 0); if (size) { std::vector buf(size, 0); ULONG s2 = GetFullPathNameW(GHC_NATIVEWP(p), size, buf.data(), nullptr); if (s2 && s2 < size) { path result = path(std::wstring(buf.data(), s2)); if (p.filename() == ".") { result /= "."; } return result; } } ec = detail::make_system_error(); return path(); #else path base = current_path(ec); if (!ec) { if (p.empty()) { return base / p; } if (p.has_root_name()) { if (p.has_root_directory()) { return p; } else { return p.root_name() / base.root_directory() / base.relative_path() / p.relative_path(); } } else { if (p.has_root_directory()) { return base.root_name() / p; } else { return base / p; } } } ec = detail::make_system_error(); return path(); #endif } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE path canonical(const path& p) { std::error_code ec; auto result = canonical(p, ec); if (ec) { throw filesystem_error(detail::systemErrorText(ec.value()), p, ec); } return result; } #endif GHC_INLINE path canonical(const path& p, std::error_code& ec) { if (p.empty()) { ec = detail::make_error_code(detail::portable_error::not_found); return path(); } path work = p.is_absolute() ? p : absolute(p, ec); path result; auto fs = status(work, ec); if (ec) { return path(); } if (fs.type() == file_type::not_found) { ec = detail::make_error_code(detail::portable_error::not_found); return path(); } bool redo; do { auto rootPathLen = work._prefixLength + work.root_name_length() + (work.has_root_directory() ? 1 : 0); redo = false; result.clear(); for (auto pe : work) { if (pe.empty() || pe == ".") { continue; } else if (pe == "..") { result = result.parent_path(); continue; } else if ((result / pe).string().length() <= rootPathLen) { result /= pe; continue; } auto sls = symlink_status(result / pe, ec); if (ec) { return path(); } if (is_symlink(sls)) { redo = true; auto target = read_symlink(result / pe, ec); if (ec) { return path(); } if (target.is_absolute()) { result = target; continue; } else { result /= target; continue; } } else { result /= pe; } } work = result; } while (redo); ec.clear(); return result; } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE void copy(const path& from, const path& to) { copy(from, to, copy_options::none); } GHC_INLINE void copy(const path& from, const path& to, copy_options options) { std::error_code ec; copy(from, to, options, ec); if (ec) { throw filesystem_error(detail::systemErrorText(ec.value()), from, to, ec); } } #endif GHC_INLINE void copy(const path& from, const path& to, std::error_code& ec) noexcept { copy(from, to, copy_options::none, ec); } GHC_INLINE void copy(const path& from, const path& to, copy_options options, std::error_code& ec) noexcept { std::error_code tec; file_status fs_from, fs_to; ec.clear(); if ((options & (copy_options::skip_symlinks | copy_options::copy_symlinks | copy_options::create_symlinks)) != copy_options::none) { fs_from = symlink_status(from, ec); } else { fs_from = status(from, ec); } if (!exists(fs_from)) { if (!ec) { ec = detail::make_error_code(detail::portable_error::not_found); } return; } if ((options & (copy_options::skip_symlinks | copy_options::create_symlinks)) != copy_options::none) { fs_to = symlink_status(to, tec); } else { fs_to = status(to, tec); } if (is_other(fs_from) || is_other(fs_to) || (is_directory(fs_from) && is_regular_file(fs_to)) || (exists(fs_to) && equivalent(from, to, ec))) { ec = detail::make_error_code(detail::portable_error::invalid_argument); } else if (is_symlink(fs_from)) { if ((options & copy_options::skip_symlinks) == copy_options::none) { if (!exists(fs_to) && (options & copy_options::copy_symlinks) != copy_options::none) { copy_symlink(from, to, ec); } else { ec = detail::make_error_code(detail::portable_error::invalid_argument); } } } else if (is_regular_file(fs_from)) { if ((options & copy_options::directories_only) == copy_options::none) { if ((options & copy_options::create_symlinks) != copy_options::none) { create_symlink(from.is_absolute() ? from : canonical(from, ec), to, ec); } #ifndef GHC_OS_WEB else if ((options & copy_options::create_hard_links) != copy_options::none) { create_hard_link(from, to, ec); } #endif else if (is_directory(fs_to)) { copy_file(from, to / from.filename(), options, ec); } else { copy_file(from, to, options, ec); } } } #ifdef LWG_2682_BEHAVIOUR else if (is_directory(fs_from) && (options & copy_options::create_symlinks) != copy_options::none) { ec = detail::make_error_code(detail::portable_error::is_a_directory); } #endif else if (is_directory(fs_from) && (options == copy_options::none || (options & copy_options::recursive) != copy_options::none)) { if (!exists(fs_to)) { create_directory(to, from, ec); if (ec) { return; } } for (auto iter = directory_iterator(from, ec); iter != directory_iterator(); iter.increment(ec)) { if (!ec) { copy(iter->path(), to / iter->path().filename(), options | static_cast(0x8000), ec); } if (ec) { return; } } } return; } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE bool copy_file(const path& from, const path& to) { return copy_file(from, to, copy_options::none); } GHC_INLINE bool copy_file(const path& from, const path& to, copy_options option) { std::error_code ec; auto result = copy_file(from, to, option, ec); if (ec) { throw filesystem_error(detail::systemErrorText(ec.value()), from, to, ec); } return result; } #endif GHC_INLINE bool copy_file(const path& from, const path& to, std::error_code& ec) noexcept { return copy_file(from, to, copy_options::none, ec); } GHC_INLINE bool copy_file(const path& from, const path& to, copy_options options, std::error_code& ec) noexcept { std::error_code tecf, tect; auto sf = status(from, tecf); auto st = status(to, tect); bool overwrite = false; ec.clear(); if (!is_regular_file(sf)) { ec = tecf; return false; } if (exists(st) && (!is_regular_file(st) || equivalent(from, to, ec) || (options & (copy_options::skip_existing | copy_options::overwrite_existing | copy_options::update_existing)) == copy_options::none)) { ec = tect ? tect : detail::make_error_code(detail::portable_error::exists); return false; } if (exists(st)) { if ((options & copy_options::update_existing) == copy_options::update_existing) { auto from_time = last_write_time(from, ec); if (ec) { ec = detail::make_system_error(); return false; } auto to_time = last_write_time(to, ec); if (ec) { ec = detail::make_system_error(); return false; } if (from_time <= to_time) { return false; } } overwrite = true; } #ifdef GHC_OS_WINDOWS if (!::CopyFileW(GHC_NATIVEWP(from), GHC_NATIVEWP(to), !overwrite)) { ec = detail::make_system_error(); return false; } return true; #else std::vector buffer(16384, '\0'); int in = -1, out = -1; if ((in = ::open(from.c_str(), O_RDONLY)) < 0) { ec = detail::make_system_error(); return false; } int mode = O_CREAT | O_WRONLY | O_TRUNC; if (!overwrite) { mode |= O_EXCL; } if ((out = ::open(to.c_str(), mode, static_cast(sf.permissions() & perms::all))) < 0) { ec = detail::make_system_error(); ::close(in); return false; } ssize_t br, bw; while ((br = ::read(in, buffer.data(), buffer.size())) > 0) { ssize_t offset = 0; do { if ((bw = ::write(out, buffer.data() + offset, static_cast(br))) > 0) { br -= bw; offset += bw; } else if (bw < 0) { ec = detail::make_system_error(); ::close(in); ::close(out); return false; } } while (br); } ::close(in); ::close(out); return true; #endif } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE void copy_symlink(const path& existing_symlink, const path& new_symlink) { std::error_code ec; copy_symlink(existing_symlink, new_symlink, ec); if (ec) { throw filesystem_error(detail::systemErrorText(ec.value()), existing_symlink, new_symlink, ec); } } #endif GHC_INLINE void copy_symlink(const path& existing_symlink, const path& new_symlink, std::error_code& ec) noexcept { ec.clear(); auto to = read_symlink(existing_symlink, ec); if (!ec) { if (exists(to, ec) && is_directory(to, ec)) { create_directory_symlink(to, new_symlink, ec); } else { create_symlink(to, new_symlink, ec); } } } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE bool create_directories(const path& p) { std::error_code ec; auto result = create_directories(p, ec); if (ec) { throw filesystem_error(detail::systemErrorText(ec.value()), p, ec); } return result; } #endif GHC_INLINE bool create_directories(const path& p, std::error_code& ec) noexcept { path current; ec.clear(); bool didCreate = false; for (path::string_type part : p) { current /= part; if (current != p.root_name() && current != p.root_path()) { std::error_code tec; auto fs = status(current, tec); if (tec && fs.type() != file_type::not_found) { ec = tec; return false; } if (!exists(fs)) { create_directory(current, ec); if (ec) { std::error_code tmp_ec; if (is_directory(current, tmp_ec)) { ec.clear(); } else { return false; } } didCreate = true; } #ifndef LWG_2935_BEHAVIOUR else if (!is_directory(fs)) { ec = detail::make_error_code(detail::portable_error::exists); return false; } #endif } } return didCreate; } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE bool create_directory(const path& p) { std::error_code ec; auto result = create_directory(p, path(), ec); if (ec) { throw filesystem_error(detail::systemErrorText(ec.value()), p, ec); } return result; } #endif GHC_INLINE bool create_directory(const path& p, std::error_code& ec) noexcept { return create_directory(p, path(), ec); } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE bool create_directory(const path& p, const path& attributes) { std::error_code ec; auto result = create_directory(p, attributes, ec); if (ec) { throw filesystem_error(detail::systemErrorText(ec.value()), p, ec); } return result; } #endif GHC_INLINE bool create_directory(const path& p, const path& attributes, std::error_code& ec) noexcept { std::error_code tec; ec.clear(); auto fs = status(p, tec); #ifdef LWG_2935_BEHAVIOUR if (status_known(fs) && exists(fs)) { return false; } #else if (status_known(fs) && exists(fs) && is_directory(fs)) { return false; } #endif #ifdef GHC_OS_WINDOWS if (!attributes.empty()) { if (!::CreateDirectoryExW(GHC_NATIVEWP(attributes), GHC_NATIVEWP(p), NULL)) { ec = detail::make_system_error(); return false; } } else if (!::CreateDirectoryW(GHC_NATIVEWP(p), NULL)) { ec = detail::make_system_error(); return false; } #else ::mode_t attribs = static_cast(perms::all); if (!attributes.empty()) { struct ::stat fileStat; if (::stat(attributes.c_str(), &fileStat) != 0) { ec = detail::make_system_error(); return false; } attribs = fileStat.st_mode; } if (::mkdir(p.c_str(), attribs) != 0) { ec = detail::make_system_error(); return false; } #endif return true; } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE void create_directory_symlink(const path& to, const path& new_symlink) { std::error_code ec; create_directory_symlink(to, new_symlink, ec); if (ec) { throw filesystem_error(detail::systemErrorText(ec.value()), to, new_symlink, ec); } } #endif GHC_INLINE void create_directory_symlink(const path& to, const path& new_symlink, std::error_code& ec) noexcept { detail::create_symlink(to, new_symlink, true, ec); } #ifndef GHC_OS_WEB #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE void create_hard_link(const path& to, const path& new_hard_link) { std::error_code ec; create_hard_link(to, new_hard_link, ec); if (ec) { throw filesystem_error(detail::systemErrorText(ec.value()), to, new_hard_link, ec); } } #endif GHC_INLINE void create_hard_link(const path& to, const path& new_hard_link, std::error_code& ec) noexcept { detail::create_hardlink(to, new_hard_link, ec); } #endif #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE void create_symlink(const path& to, const path& new_symlink) { std::error_code ec; create_symlink(to, new_symlink, ec); if (ec) { throw filesystem_error(detail::systemErrorText(ec.value()), to, new_symlink, ec); } } #endif GHC_INLINE void create_symlink(const path& to, const path& new_symlink, std::error_code& ec) noexcept { detail::create_symlink(to, new_symlink, false, ec); } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE path current_path() { std::error_code ec; auto result = current_path(ec); if (ec) { throw filesystem_error(detail::systemErrorText(ec.value()), ec); } return result; } #endif GHC_INLINE path current_path(std::error_code& ec) { ec.clear(); #ifdef GHC_OS_WINDOWS DWORD pathlen = ::GetCurrentDirectoryW(0, 0); std::unique_ptr buffer(new wchar_t[size_t(pathlen) + 1]); if (::GetCurrentDirectoryW(pathlen, buffer.get()) == 0) { ec = detail::make_system_error(); return path(); } return path(std::wstring(buffer.get()), path::native_format); #else size_t pathlen = static_cast(std::max(int(::pathconf(".", _PC_PATH_MAX)), int(PATH_MAX))); std::unique_ptr buffer(new char[pathlen + 1]); if (::getcwd(buffer.get(), pathlen) == nullptr) { ec = detail::make_system_error(); return path(); } return path(buffer.get()); #endif } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE void current_path(const path& p) { std::error_code ec; current_path(p, ec); if (ec) { throw filesystem_error(detail::systemErrorText(ec.value()), p, ec); } } #endif GHC_INLINE void current_path(const path& p, std::error_code& ec) noexcept { ec.clear(); #ifdef GHC_OS_WINDOWS if (!::SetCurrentDirectoryW(GHC_NATIVEWP(p))) { ec = detail::make_system_error(); } #else if (::chdir(p.string().c_str()) == -1) { ec = detail::make_system_error(); } #endif } GHC_INLINE bool exists(file_status s) noexcept { return status_known(s) && s.type() != file_type::not_found; } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE bool exists(const path& p) { return exists(status(p)); } #endif GHC_INLINE bool exists(const path& p, std::error_code& ec) noexcept { file_status s = status(p, ec); if (status_known(s)) { ec.clear(); } return exists(s); } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE bool equivalent(const path& p1, const path& p2) { std::error_code ec; bool result = equivalent(p1, p2, ec); if (ec) { throw filesystem_error(detail::systemErrorText(ec.value()), p1, p2, ec); } return result; } #endif GHC_INLINE bool equivalent(const path& p1, const path& p2, std::error_code& ec) noexcept { ec.clear(); #ifdef GHC_OS_WINDOWS std::shared_ptr file1(::CreateFileW(GHC_NATIVEWP(p1), 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0), CloseHandle); auto e1 = ::GetLastError(); std::shared_ptr file2(::CreateFileW(GHC_NATIVEWP(p2), 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0), CloseHandle); if (file1.get() == INVALID_HANDLE_VALUE || file2.get() == INVALID_HANDLE_VALUE) { #ifdef LWG_2937_BEHAVIOUR ec = detail::make_system_error(e1 ? e1 : ::GetLastError()); #else if (file1 == file2) { ec = detail::make_system_error(e1 ? e1 : ::GetLastError()); } #endif return false; } BY_HANDLE_FILE_INFORMATION inf1, inf2; if (!::GetFileInformationByHandle(file1.get(), &inf1)) { ec = detail::make_system_error(); return false; } if (!::GetFileInformationByHandle(file2.get(), &inf2)) { ec = detail::make_system_error(); return false; } return inf1.ftLastWriteTime.dwLowDateTime == inf2.ftLastWriteTime.dwLowDateTime && inf1.ftLastWriteTime.dwHighDateTime == inf2.ftLastWriteTime.dwHighDateTime && inf1.nFileIndexHigh == inf2.nFileIndexHigh && inf1.nFileIndexLow == inf2.nFileIndexLow && inf1.nFileSizeHigh == inf2.nFileSizeHigh && inf1.nFileSizeLow == inf2.nFileSizeLow && inf1.dwVolumeSerialNumber == inf2.dwVolumeSerialNumber; #else struct ::stat s1, s2; auto rc1 = ::stat(p1.c_str(), &s1); auto e1 = errno; auto rc2 = ::stat(p2.c_str(), &s2); if (rc1 || rc2) { #ifdef LWG_2937_BEHAVIOUR ec = detail::make_system_error(e1 ? e1 : errno); #else if (rc1 && rc2) { ec = detail::make_system_error(e1 ? e1 : errno); } #endif return false; } return s1.st_dev == s2.st_dev && s1.st_ino == s2.st_ino && s1.st_size == s2.st_size && s1.st_mtime == s2.st_mtime; #endif } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE uintmax_t file_size(const path& p) { std::error_code ec; auto result = file_size(p, ec); if (ec) { throw filesystem_error(detail::systemErrorText(ec.value()), p, ec); } return result; } #endif GHC_INLINE uintmax_t file_size(const path& p, std::error_code& ec) noexcept { ec.clear(); #ifdef GHC_OS_WINDOWS WIN32_FILE_ATTRIBUTE_DATA attr; if (!GetFileAttributesExW(GHC_NATIVEWP(p), GetFileExInfoStandard, &attr)) { ec = detail::make_system_error(); return static_cast(-1); } return static_cast(attr.nFileSizeHigh) << (sizeof(attr.nFileSizeHigh) * 8) | attr.nFileSizeLow; #else struct ::stat fileStat; if (::stat(p.c_str(), &fileStat) == -1) { ec = detail::make_system_error(); return static_cast(-1); } return static_cast(fileStat.st_size); #endif } #ifndef GHC_OS_WEB #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE uintmax_t hard_link_count(const path& p) { std::error_code ec; auto result = hard_link_count(p, ec); if (ec) { throw filesystem_error(detail::systemErrorText(ec.value()), p, ec); } return result; } #endif GHC_INLINE uintmax_t hard_link_count(const path& p, std::error_code& ec) noexcept { ec.clear(); #ifdef GHC_OS_WINDOWS uintmax_t result = static_cast(-1); std::shared_ptr file(::CreateFileW(GHC_NATIVEWP(p), 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0), CloseHandle); BY_HANDLE_FILE_INFORMATION inf; if (file.get() == INVALID_HANDLE_VALUE) { ec = detail::make_system_error(); } else { if (!::GetFileInformationByHandle(file.get(), &inf)) { ec = detail::make_system_error(); } else { result = inf.nNumberOfLinks; } } return result; #else uintmax_t result = 0; file_status fs = detail::status_ex(p, ec, nullptr, nullptr, &result, nullptr); if (fs.type() == file_type::not_found) { ec = detail::make_error_code(detail::portable_error::not_found); } return ec ? static_cast(-1) : result; #endif } #endif GHC_INLINE bool is_block_file(file_status s) noexcept { return s.type() == file_type::block; } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE bool is_block_file(const path& p) { return is_block_file(status(p)); } #endif GHC_INLINE bool is_block_file(const path& p, std::error_code& ec) noexcept { return is_block_file(status(p, ec)); } GHC_INLINE bool is_character_file(file_status s) noexcept { return s.type() == file_type::character; } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE bool is_character_file(const path& p) { return is_character_file(status(p)); } #endif GHC_INLINE bool is_character_file(const path& p, std::error_code& ec) noexcept { return is_character_file(status(p, ec)); } GHC_INLINE bool is_directory(file_status s) noexcept { return s.type() == file_type::directory; } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE bool is_directory(const path& p) { return is_directory(status(p)); } #endif GHC_INLINE bool is_directory(const path& p, std::error_code& ec) noexcept { return is_directory(status(p, ec)); } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE bool is_empty(const path& p) { if (is_directory(p)) { return directory_iterator(p) == directory_iterator(); } else { return file_size(p) == 0; } } #endif GHC_INLINE bool is_empty(const path& p, std::error_code& ec) noexcept { auto fs = status(p, ec); if (ec) { return false; } if (is_directory(fs)) { directory_iterator iter(p, ec); if (ec) { return false; } return iter == directory_iterator(); } else { auto sz = file_size(p, ec); if (ec) { return false; } return sz == 0; } } GHC_INLINE bool is_fifo(file_status s) noexcept { return s.type() == file_type::fifo; } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE bool is_fifo(const path& p) { return is_fifo(status(p)); } #endif GHC_INLINE bool is_fifo(const path& p, std::error_code& ec) noexcept { return is_fifo(status(p, ec)); } GHC_INLINE bool is_other(file_status s) noexcept { return exists(s) && !is_regular_file(s) && !is_directory(s) && !is_symlink(s); } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE bool is_other(const path& p) { return is_other(status(p)); } #endif GHC_INLINE bool is_other(const path& p, std::error_code& ec) noexcept { return is_other(status(p, ec)); } GHC_INLINE bool is_regular_file(file_status s) noexcept { return s.type() == file_type::regular; } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE bool is_regular_file(const path& p) { return is_regular_file(status(p)); } #endif GHC_INLINE bool is_regular_file(const path& p, std::error_code& ec) noexcept { return is_regular_file(status(p, ec)); } GHC_INLINE bool is_socket(file_status s) noexcept { return s.type() == file_type::socket; } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE bool is_socket(const path& p) { return is_socket(status(p)); } #endif GHC_INLINE bool is_socket(const path& p, std::error_code& ec) noexcept { return is_socket(status(p, ec)); } GHC_INLINE bool is_symlink(file_status s) noexcept { return s.type() == file_type::symlink; } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE bool is_symlink(const path& p) { return is_symlink(symlink_status(p)); } #endif GHC_INLINE bool is_symlink(const path& p, std::error_code& ec) noexcept { return is_symlink(symlink_status(p, ec)); } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE file_time_type last_write_time(const path& p) { std::error_code ec; auto result = last_write_time(p, ec); if (ec) { throw filesystem_error(detail::systemErrorText(ec.value()), p, ec); } return result; } #endif GHC_INLINE file_time_type last_write_time(const path& p, std::error_code& ec) noexcept { time_t result = 0; ec.clear(); file_status fs = detail::status_ex(p, ec, nullptr, nullptr, nullptr, &result); return ec ? (file_time_type::min)() : std::chrono::system_clock::from_time_t(result); } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE void last_write_time(const path& p, file_time_type new_time) { std::error_code ec; last_write_time(p, new_time, ec); if (ec) { throw filesystem_error(detail::systemErrorText(ec.value()), p, ec); } } #endif GHC_INLINE void last_write_time(const path& p, file_time_type new_time, std::error_code& ec) noexcept { ec.clear(); auto d = new_time.time_since_epoch(); #ifdef GHC_OS_WINDOWS std::shared_ptr file(::CreateFileW(GHC_NATIVEWP(p), FILE_WRITE_ATTRIBUTES, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL), ::CloseHandle); FILETIME ft; auto tt = std::chrono::duration_cast(d).count() * 10 + 116444736000000000; ft.dwLowDateTime = static_cast(tt); ft.dwHighDateTime = static_cast(tt >> 32); if (!::SetFileTime(file.get(), 0, 0, &ft)) { ec = detail::make_system_error(); } #elif defined(GHC_OS_MACOS) #ifdef __MAC_OS_X_VERSION_MIN_REQUIRED #if __MAC_OS_X_VERSION_MIN_REQUIRED < 101300 struct ::stat fs; if (::stat(p.c_str(), &fs) == 0) { struct ::timeval tv[2]; tv[0].tv_sec = fs.st_atimespec.tv_sec; tv[0].tv_usec = static_cast(fs.st_atimespec.tv_nsec / 1000); tv[1].tv_sec = std::chrono::duration_cast(d).count(); tv[1].tv_usec = static_cast(std::chrono::duration_cast(d).count() % 1000000); if (::utimes(p.c_str(), tv) == 0) { return; } } ec = detail::make_system_error(); return; #else struct ::timespec times[2]; times[0].tv_sec = 0; times[0].tv_nsec = UTIME_OMIT; times[1].tv_sec = std::chrono::duration_cast(d).count(); times[1].tv_nsec = 0; // std::chrono::duration_cast(d).count() % 1000000000; if (::utimensat(AT_FDCWD, p.c_str(), times, AT_SYMLINK_NOFOLLOW) != 0) { ec = detail::make_system_error(); } return; #endif #endif #else #ifndef UTIME_OMIT #define UTIME_OMIT ((1l << 30) - 2l) #endif struct ::timespec times[2]; times[0].tv_sec = 0; times[0].tv_nsec = UTIME_OMIT; times[1].tv_sec = static_cast(std::chrono::duration_cast(d).count()); times[1].tv_nsec = static_cast(std::chrono::duration_cast(d).count() % 1000000000); #if defined(__ANDROID_API__) && __ANDROID_API__ < 12 if (syscall(__NR_utimensat, AT_FDCWD, p.c_str(), times, AT_SYMLINK_NOFOLLOW) != 0) { #else if (::utimensat(AT_FDCWD, p.c_str(), times, AT_SYMLINK_NOFOLLOW) != 0) { #endif ec = detail::make_system_error(); } return; #endif } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE void permissions(const path& p, perms prms, perm_options opts) { std::error_code ec; permissions(p, prms, opts, ec); if (ec) { throw filesystem_error(detail::systemErrorText(ec.value()), p, ec); } } #endif GHC_INLINE void permissions(const path& p, perms prms, std::error_code& ec) noexcept { permissions(p, prms, perm_options::replace, ec); } GHC_INLINE void permissions(const path& p, perms prms, perm_options opts, std::error_code& ec) noexcept { if (static_cast(opts & (perm_options::replace | perm_options::add | perm_options::remove)) == 0) { ec = detail::make_error_code(detail::portable_error::invalid_argument); return; } auto fs = symlink_status(p, ec); if ((opts & perm_options::replace) != perm_options::replace) { if ((opts & perm_options::add) == perm_options::add) { prms = fs.permissions() | prms; } else { prms = fs.permissions() & ~prms; } } #ifdef GHC_OS_WINDOWS #ifdef __GNUC__ auto oldAttr = GetFileAttributesW(GHC_NATIVEWP(p)); if (oldAttr != INVALID_FILE_ATTRIBUTES) { DWORD newAttr = ((prms & perms::owner_write) == perms::owner_write) ? oldAttr & ~(static_cast(FILE_ATTRIBUTE_READONLY)) : oldAttr | FILE_ATTRIBUTE_READONLY; if (oldAttr == newAttr || SetFileAttributesW(GHC_NATIVEWP(p), newAttr)) { return; } } ec = detail::make_system_error(); #else int mode = 0; if ((prms & perms::owner_read) == perms::owner_read) { mode |= _S_IREAD; } if ((prms & perms::owner_write) == perms::owner_write) { mode |= _S_IWRITE; } if (::_wchmod(p.wstring().c_str(), mode) != 0) { ec = detail::make_system_error(); } #endif #else if ((opts & perm_options::nofollow) != perm_options::nofollow) { if (::chmod(p.c_str(), static_cast(prms)) != 0) { ec = detail::make_system_error(); } } #endif } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE path proximate(const path& p, std::error_code& ec) { auto cp = current_path(ec); if (!ec) { return proximate(p, cp, ec); } return path(); } #endif #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE path proximate(const path& p, const path& base) { return weakly_canonical(p).lexically_proximate(weakly_canonical(base)); } #endif GHC_INLINE path proximate(const path& p, const path& base, std::error_code& ec) { return weakly_canonical(p, ec).lexically_proximate(weakly_canonical(base, ec)); } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE path read_symlink(const path& p) { std::error_code ec; auto result = read_symlink(p, ec); if (ec) { throw filesystem_error(detail::systemErrorText(ec.value()), p, ec); } return result; } #endif GHC_INLINE path read_symlink(const path& p, std::error_code& ec) { file_status fs = symlink_status(p, ec); if (fs.type() != file_type::symlink) { ec = detail::make_error_code(detail::portable_error::invalid_argument); return path(); } auto result = detail::resolveSymlink(p, ec); return ec ? path() : result; } GHC_INLINE path relative(const path& p, std::error_code& ec) { return relative(p, current_path(ec), ec); } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE path relative(const path& p, const path& base) { return weakly_canonical(p).lexically_relative(weakly_canonical(base)); } #endif GHC_INLINE path relative(const path& p, const path& base, std::error_code& ec) { return weakly_canonical(p, ec).lexically_relative(weakly_canonical(base, ec)); } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE bool remove(const path& p) { std::error_code ec; auto result = remove(p, ec); if (ec) { throw filesystem_error(detail::systemErrorText(ec.value()), p, ec); } return result; } #endif GHC_INLINE bool remove(const path& p, std::error_code& ec) noexcept { ec.clear(); #ifdef GHC_OS_WINDOWS #ifdef GHC_USE_WCHAR_T auto cstr = p.c_str(); #else std::wstring np = detail::fromUtf8(p.u8string()); auto cstr = np.c_str(); #endif DWORD attr = GetFileAttributesW(cstr); if (attr == INVALID_FILE_ATTRIBUTES) { auto error = ::GetLastError(); if (error == ERROR_FILE_NOT_FOUND || error == ERROR_PATH_NOT_FOUND) { return false; } ec = detail::make_system_error(error); } if (!ec) { if (attr & FILE_ATTRIBUTE_DIRECTORY) { if (!RemoveDirectoryW(cstr)) { ec = detail::make_system_error(); } } else { if (!DeleteFileW(cstr)) { ec = detail::make_system_error(); } } } #else if (::remove(p.c_str()) == -1) { auto error = errno; if (error == ENOENT) { return false; } ec = detail::make_system_error(); } #endif return ec ? false : true; } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE uintmax_t remove_all(const path& p) { std::error_code ec; auto result = remove_all(p, ec); if (ec) { throw filesystem_error(detail::systemErrorText(ec.value()), p, ec); } return result; } #endif GHC_INLINE uintmax_t remove_all(const path& p, std::error_code& ec) noexcept { ec.clear(); uintmax_t count = 0; if (p == "/") { ec = detail::make_error_code(detail::portable_error::not_supported); return static_cast(-1); } std::error_code tec; auto fs = status(p, tec); if (exists(fs) && is_directory(fs)) { for (auto iter = directory_iterator(p, ec); iter != directory_iterator(); iter.increment(ec)) { if (ec && !detail::is_not_found_error(ec)) { break; } bool is_symlink_result = iter->is_symlink(ec); if (ec) return static_cast(-1); if (!is_symlink_result && iter->is_directory(ec)) { count += remove_all(iter->path(), ec); if (ec) { return static_cast(-1); } } else { if (!ec) { remove(iter->path(), ec); } if (ec) { return static_cast(-1); } ++count; } } } if (!ec) { if (remove(p, ec)) { ++count; } } if (ec) { return static_cast(-1); } return count; } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE void rename(const path& from, const path& to) { std::error_code ec; rename(from, to, ec); if (ec) { throw filesystem_error(detail::systemErrorText(ec.value()), from, to, ec); } } #endif GHC_INLINE void rename(const path& from, const path& to, std::error_code& ec) noexcept { ec.clear(); #ifdef GHC_OS_WINDOWS if (from != to) { if (!MoveFileExW(GHC_NATIVEWP(from), GHC_NATIVEWP(to), (DWORD)MOVEFILE_REPLACE_EXISTING)) { ec = detail::make_system_error(); } } #else if (from != to) { if (::rename(from.c_str(), to.c_str()) != 0) { ec = detail::make_system_error(); } } #endif } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE void resize_file(const path& p, uintmax_t size) { std::error_code ec; resize_file(p, size, ec); if (ec) { throw filesystem_error(detail::systemErrorText(ec.value()), p, ec); } } #endif GHC_INLINE void resize_file(const path& p, uintmax_t size, std::error_code& ec) noexcept { ec.clear(); #ifdef GHC_OS_WINDOWS LARGE_INTEGER lisize; lisize.QuadPart = static_cast(size); if (lisize.QuadPart < 0) { #ifdef ERROR_FILE_TOO_LARGE ec = detail::make_system_error(ERROR_FILE_TOO_LARGE); #else ec = detail::make_system_error(223); #endif return; } std::shared_ptr file(CreateFileW(GHC_NATIVEWP(p), GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL), CloseHandle); if (file.get() == INVALID_HANDLE_VALUE) { ec = detail::make_system_error(); } else if (SetFilePointerEx(file.get(), lisize, NULL, FILE_BEGIN) == 0 || SetEndOfFile(file.get()) == 0) { ec = detail::make_system_error(); } #else if (::truncate(p.c_str(), static_cast(size)) != 0) { ec = detail::make_system_error(); } #endif } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE space_info space(const path& p) { std::error_code ec; auto result = space(p, ec); if (ec) { throw filesystem_error(detail::systemErrorText(ec.value()), p, ec); } return result; } #endif GHC_INLINE space_info space(const path& p, std::error_code& ec) noexcept { ec.clear(); #ifdef GHC_OS_WINDOWS ULARGE_INTEGER freeBytesAvailableToCaller = {{ 0, 0 }}; ULARGE_INTEGER totalNumberOfBytes = {{ 0, 0 }}; ULARGE_INTEGER totalNumberOfFreeBytes = {{ 0, 0 }}; if (!GetDiskFreeSpaceExW(GHC_NATIVEWP(p), &freeBytesAvailableToCaller, &totalNumberOfBytes, &totalNumberOfFreeBytes)) { ec = detail::make_system_error(); return {static_cast(-1), static_cast(-1), static_cast(-1)}; } return {static_cast(totalNumberOfBytes.QuadPart), static_cast(totalNumberOfFreeBytes.QuadPart), static_cast(freeBytesAvailableToCaller.QuadPart)}; #else struct ::statvfs sfs; if (::statvfs(p.c_str(), &sfs) != 0) { ec = detail::make_system_error(); return {static_cast(-1), static_cast(-1), static_cast(-1)}; } return {static_cast(sfs.f_blocks * sfs.f_frsize), static_cast(sfs.f_bfree * sfs.f_frsize), static_cast(sfs.f_bavail * sfs.f_frsize)}; #endif } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE file_status status(const path& p) { std::error_code ec; auto result = status(p, ec); if (result.type() == file_type::none) { throw filesystem_error(detail::systemErrorText(ec.value()), p, ec); } return result; } #endif GHC_INLINE file_status status(const path& p, std::error_code& ec) noexcept { return detail::status_ex(p, ec); } GHC_INLINE bool status_known(file_status s) noexcept { return s.type() != file_type::none; } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE file_status symlink_status(const path& p) { std::error_code ec; auto result = symlink_status(p, ec); if (result.type() == file_type::none) { throw filesystem_error(detail::systemErrorText(ec.value()), ec); } return result; } #endif GHC_INLINE file_status symlink_status(const path& p, std::error_code& ec) noexcept { return detail::symlink_status_ex(p, ec); } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE path temp_directory_path() { std::error_code ec; path result = temp_directory_path(ec); if (ec) { throw filesystem_error(detail::systemErrorText(ec.value()), ec); } return result; } #endif GHC_INLINE path temp_directory_path(std::error_code& ec) noexcept { ec.clear(); #ifdef GHC_OS_WINDOWS wchar_t buffer[512]; auto rc = GetTempPathW(511, buffer); if (!rc || rc > 511) { ec = detail::make_system_error(); return path(); } return path(std::wstring(buffer)); #else static const char* temp_vars[] = {"TMPDIR", "TMP", "TEMP", "TEMPDIR", nullptr}; const char* temp_path = nullptr; for (auto temp_name = temp_vars; *temp_name != nullptr; ++temp_name) { temp_path = std::getenv(*temp_name); if (temp_path) { return path(temp_path); } } return path("/tmp"); #endif } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE path weakly_canonical(const path& p) { std::error_code ec; auto result = weakly_canonical(p, ec); if (ec) { throw filesystem_error(detail::systemErrorText(ec.value()), p, ec); } return result; } #endif GHC_INLINE path weakly_canonical(const path& p, std::error_code& ec) noexcept { path result; ec.clear(); bool scan = true; for (auto pe : p) { if (scan) { std::error_code tec; if (exists(result / pe, tec)) { result /= pe; } else { if (ec) { return path(); } scan = false; if (!result.empty()) { result = canonical(result, ec) / pe; if (ec) { break; } } else { result /= pe; } } } else { result /= pe; } } if (scan) { if (!result.empty()) { result = canonical(result, ec); } } return ec ? path() : result.lexically_normal(); } //----------------------------------------------------------------------------- // 30.10.11 class file_status // 30.10.11.1 constructors and destructor GHC_INLINE file_status::file_status() noexcept : file_status(file_type::none) { } GHC_INLINE file_status::file_status(file_type ft, perms prms) noexcept : _type(ft) , _perms(prms) { } GHC_INLINE file_status::file_status(const file_status& other) noexcept : _type(other._type) , _perms(other._perms) { } GHC_INLINE file_status::file_status(file_status&& other) noexcept : _type(other._type) , _perms(other._perms) { } GHC_INLINE file_status::~file_status() {} // assignments: GHC_INLINE file_status& file_status::operator=(const file_status& rhs) noexcept { _type = rhs._type; _perms = rhs._perms; return *this; } GHC_INLINE file_status& file_status::operator=(file_status&& rhs) noexcept { _type = rhs._type; _perms = rhs._perms; return *this; } // 30.10.11.3 modifiers GHC_INLINE void file_status::type(file_type ft) noexcept { _type = ft; } GHC_INLINE void file_status::permissions(perms prms) noexcept { _perms = prms; } // 30.10.11.2 observers GHC_INLINE file_type file_status::type() const noexcept { return _type; } GHC_INLINE perms file_status::permissions() const noexcept { return _perms; } //----------------------------------------------------------------------------- // 30.10.12 class directory_entry // 30.10.12.1 constructors and destructor // directory_entry::directory_entry() noexcept = default; // directory_entry::directory_entry(const directory_entry&) = default; // directory_entry::directory_entry(directory_entry&&) noexcept = default; #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE directory_entry::directory_entry(const filesystem::path& p) : _path(p) , _file_size(static_cast(-1)) #ifndef GHC_OS_WINDOWS , _hard_link_count(static_cast(-1)) #endif , _last_write_time(0) { refresh(); } #endif GHC_INLINE directory_entry::directory_entry(const filesystem::path& p, std::error_code& ec) : _path(p) , _file_size(static_cast(-1)) #ifndef GHC_OS_WINDOWS , _hard_link_count(static_cast(-1)) #endif , _last_write_time(0) { refresh(ec); } GHC_INLINE directory_entry::~directory_entry() {} // assignments: // directory_entry& directory_entry::operator=(const directory_entry&) = default; // directory_entry& directory_entry::operator=(directory_entry&&) noexcept = default; // 30.10.12.2 directory_entry modifiers #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE void directory_entry::assign(const filesystem::path& p) { _path = p; refresh(); } #endif GHC_INLINE void directory_entry::assign(const filesystem::path& p, std::error_code& ec) { _path = p; refresh(ec); } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE void directory_entry::replace_filename(const filesystem::path& p) { _path.replace_filename(p); refresh(); } #endif GHC_INLINE void directory_entry::replace_filename(const filesystem::path& p, std::error_code& ec) { _path.replace_filename(p); refresh(ec); } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE void directory_entry::refresh() { std::error_code ec; refresh(ec); if (ec) { throw filesystem_error(detail::systemErrorText(ec.value()), _path, ec); } } #endif GHC_INLINE void directory_entry::refresh(std::error_code& ec) noexcept { #ifdef GHC_OS_WINDOWS _status = detail::status_ex(_path, ec, &_symlink_status, &_file_size, nullptr, &_last_write_time); #else _status = detail::status_ex(_path, ec, &_symlink_status, &_file_size, &_hard_link_count, &_last_write_time); #endif } // 30.10.12.3 directory_entry observers GHC_INLINE const filesystem::path& directory_entry::path() const noexcept { return _path; } GHC_INLINE directory_entry::operator const filesystem::path&() const noexcept { return _path; } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE file_type directory_entry::status_file_type() const { return _status.type() != file_type::none ? _status.type() : filesystem::status(path()).type(); } #endif GHC_INLINE file_type directory_entry::status_file_type(std::error_code& ec) const noexcept { if(_status.type() != file_type::none) { ec.clear(); return _status.type(); } return filesystem::status(path(), ec).type(); } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE bool directory_entry::exists() const { return status_file_type() != file_type::not_found; } #endif GHC_INLINE bool directory_entry::exists(std::error_code& ec) const noexcept { return status_file_type(ec) != file_type::not_found; } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE bool directory_entry::is_block_file() const { return status_file_type() == file_type::block; } #endif GHC_INLINE bool directory_entry::is_block_file(std::error_code& ec) const noexcept { return status_file_type(ec) == file_type::block; } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE bool directory_entry::is_character_file() const { return status_file_type() == file_type::character; } #endif GHC_INLINE bool directory_entry::is_character_file(std::error_code& ec) const noexcept { return status_file_type(ec) == file_type::character; } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE bool directory_entry::is_directory() const { return status_file_type() == file_type::directory; } #endif GHC_INLINE bool directory_entry::is_directory(std::error_code& ec) const noexcept { return status_file_type(ec) == file_type::directory; } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE bool directory_entry::is_fifo() const { return status_file_type() == file_type::fifo; } #endif GHC_INLINE bool directory_entry::is_fifo(std::error_code& ec) const noexcept { return status_file_type(ec) == file_type::fifo; } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE bool directory_entry::is_other() const { auto ft = status_file_type(); return ft != file_type::none && ft != file_type::not_found && ft != file_type::regular && ft != file_type::directory && !is_symlink(); } #endif GHC_INLINE bool directory_entry::is_other(std::error_code& ec) const noexcept { auto ft = status_file_type(ec); bool other = ft != file_type::none && ft != file_type::not_found && ft != file_type::regular && ft != file_type::directory && !is_symlink(ec); return !ec && other; } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE bool directory_entry::is_regular_file() const { return status_file_type() == file_type::regular; } #endif GHC_INLINE bool directory_entry::is_regular_file(std::error_code& ec) const noexcept { return status_file_type(ec) == file_type::regular; } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE bool directory_entry::is_socket() const { return status_file_type() == file_type::socket; } #endif GHC_INLINE bool directory_entry::is_socket(std::error_code& ec) const noexcept { return status_file_type(ec) == file_type::socket; } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE bool directory_entry::is_symlink() const { return _symlink_status.type() != file_type::none ? _symlink_status.type() == file_type::symlink : filesystem::is_symlink(symlink_status()); } #endif GHC_INLINE bool directory_entry::is_symlink(std::error_code& ec) const noexcept { if(_symlink_status.type() != file_type::none) { ec.clear(); return _symlink_status.type() == file_type::symlink; } return filesystem::is_symlink(symlink_status(ec)); } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE uintmax_t directory_entry::file_size() const { if (_file_size != static_cast(-1)) { return _file_size; } return filesystem::file_size(path()); } #endif GHC_INLINE uintmax_t directory_entry::file_size(std::error_code& ec) const noexcept { if (_file_size != static_cast(-1)) { ec.clear(); return _file_size; } return filesystem::file_size(path(), ec); } #ifndef GHC_OS_WEB #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE uintmax_t directory_entry::hard_link_count() const { #ifndef GHC_OS_WINDOWS if (_hard_link_count != static_cast(-1)) { return _hard_link_count; } #endif return filesystem::hard_link_count(path()); } #endif GHC_INLINE uintmax_t directory_entry::hard_link_count(std::error_code& ec) const noexcept { #ifndef GHC_OS_WINDOWS if (_hard_link_count != static_cast(-1)) { ec.clear(); return _hard_link_count; } #endif return filesystem::hard_link_count(path(), ec); } #endif #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE file_time_type directory_entry::last_write_time() const { if (_last_write_time != 0) { return std::chrono::system_clock::from_time_t(_last_write_time); } return filesystem::last_write_time(path()); } #endif GHC_INLINE file_time_type directory_entry::last_write_time(std::error_code& ec) const noexcept { if (_last_write_time != 0) { ec.clear(); return std::chrono::system_clock::from_time_t(_last_write_time); } return filesystem::last_write_time(path(), ec); } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE file_status directory_entry::status() const { if (_status.type() != file_type::none && _status.permissions() != perms::unknown) { return _status; } return filesystem::status(path()); } #endif GHC_INLINE file_status directory_entry::status(std::error_code& ec) const noexcept { if (_status.type() != file_type::none && _status.permissions() != perms::unknown) { ec.clear(); return _status; } return filesystem::status(path(), ec); } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE file_status directory_entry::symlink_status() const { if (_symlink_status.type() != file_type::none && _symlink_status.permissions() != perms::unknown) { return _symlink_status; } return filesystem::symlink_status(path()); } #endif GHC_INLINE file_status directory_entry::symlink_status(std::error_code& ec) const noexcept { if (_symlink_status.type() != file_type::none && _symlink_status.permissions() != perms::unknown) { ec.clear(); return _symlink_status; } return filesystem::symlink_status(path(), ec); } #ifdef GHC_HAS_THREEWAY_COMP GHC_INLINE std::strong_ordering directory_entry::operator<=>(const directory_entry& rhs) const noexcept { return _path <=> rhs._path; } #endif GHC_INLINE bool directory_entry::operator<(const directory_entry& rhs) const noexcept { return _path < rhs._path; } GHC_INLINE bool directory_entry::operator==(const directory_entry& rhs) const noexcept { return _path == rhs._path; } GHC_INLINE bool directory_entry::operator!=(const directory_entry& rhs) const noexcept { return _path != rhs._path; } GHC_INLINE bool directory_entry::operator<=(const directory_entry& rhs) const noexcept { return _path <= rhs._path; } GHC_INLINE bool directory_entry::operator>(const directory_entry& rhs) const noexcept { return _path > rhs._path; } GHC_INLINE bool directory_entry::operator>=(const directory_entry& rhs) const noexcept { return _path >= rhs._path; } //----------------------------------------------------------------------------- // 30.10.13 class directory_iterator #ifdef GHC_OS_WINDOWS class directory_iterator::impl { public: impl(const path& p, directory_options options) : _base(p) , _options(options) , _dirHandle(INVALID_HANDLE_VALUE) { if (!_base.empty()) { ZeroMemory(&_findData, sizeof(WIN32_FIND_DATAW)); if ((_dirHandle = FindFirstFileW(GHC_NATIVEWP((_base / "*")), &_findData)) != INVALID_HANDLE_VALUE) { if (std::wstring(_findData.cFileName) == L"." || std::wstring(_findData.cFileName) == L"..") { increment(_ec); } else { _dir_entry._path = _base / std::wstring(_findData.cFileName); copyToDirEntry(_ec); } } else { auto error = ::GetLastError(); _base = filesystem::path(); if (error != ERROR_ACCESS_DENIED || (options & directory_options::skip_permission_denied) == directory_options::none) { _ec = detail::make_system_error(); } } } } impl(const impl& other) = delete; ~impl() { if (_dirHandle != INVALID_HANDLE_VALUE) { FindClose(_dirHandle); _dirHandle = INVALID_HANDLE_VALUE; } } void increment(std::error_code& ec) { if (_dirHandle != INVALID_HANDLE_VALUE) { do { if (FindNextFileW(_dirHandle, &_findData)) { _dir_entry._path = _base; #ifdef GHC_USE_WCHAR_T _dir_entry._path.append_name(_findData.cFileName); #else #ifdef GHC_RAISE_UNICODE_ERRORS try { _dir_entry._path.append_name(detail::toUtf8(_findData.cFileName).c_str()); } catch (filesystem_error& fe) { ec = fe.code(); return; } #else _dir_entry._path.append_name(detail::toUtf8(_findData.cFileName).c_str()); #endif #endif copyToDirEntry(ec); } else { auto err = ::GetLastError(); if (err != ERROR_NO_MORE_FILES) { _ec = ec = detail::make_system_error(err); } FindClose(_dirHandle); _dirHandle = INVALID_HANDLE_VALUE; _dir_entry._path.clear(); break; } } while (std::wstring(_findData.cFileName) == L"." || std::wstring(_findData.cFileName) == L".."); } else { ec = _ec; } } void copyToDirEntry(std::error_code& ec) { if (_findData.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) { _dir_entry._status = detail::status_ex(_dir_entry._path, ec, &_dir_entry._symlink_status, &_dir_entry._file_size, nullptr, &_dir_entry._last_write_time); } else { _dir_entry._status = detail::status_from_INFO(_dir_entry._path, &_findData, ec, &_dir_entry._file_size, &_dir_entry._last_write_time); _dir_entry._symlink_status = _dir_entry._status; } if (ec) { if (_dir_entry._status.type() != file_type::none && _dir_entry._symlink_status.type() != file_type::none) { ec.clear(); } else { _dir_entry._file_size = static_cast(-1); _dir_entry._last_write_time = 0; } } } path _base; directory_options _options; WIN32_FIND_DATAW _findData; HANDLE _dirHandle; directory_entry _dir_entry; std::error_code _ec; }; #else // POSIX implementation class directory_iterator::impl { public: impl(const path& path, directory_options options) : _base(path) , _options(options) , _dir(nullptr) , _entry(nullptr) { if (!path.empty()) { _dir = ::opendir(path.native().c_str()); if (!_dir) { auto error = errno; _base = filesystem::path(); if ((error != EACCES && error != EPERM) || (options & directory_options::skip_permission_denied) == directory_options::none) { _ec = detail::make_system_error(); } } else { increment(_ec); } } } impl(const impl& other) = delete; ~impl() { if (_dir) { ::closedir(_dir); } } void increment(std::error_code& ec) { if (_dir) { bool skip; do { skip = false; errno = 0; _entry = ::readdir(_dir); if (_entry) { _dir_entry._path = _base; _dir_entry._path.append_name(_entry->d_name); copyToDirEntry(); if (ec && (ec.value() == EACCES || ec.value() == EPERM) && (_options & directory_options::skip_permission_denied) == directory_options::skip_permission_denied) { ec.clear(); skip = true; } } else { ::closedir(_dir); _dir = nullptr; _dir_entry._path.clear(); if (errno) { ec = detail::make_system_error(); } break; } } while (skip || std::strcmp(_entry->d_name, ".") == 0 || std::strcmp(_entry->d_name, "..") == 0); } } void copyToDirEntry() { _dir_entry._symlink_status.permissions(perms::unknown); switch(_entry->d_type) { case DT_BLK: _dir_entry._symlink_status.type(file_type::block); break; case DT_CHR: _dir_entry._symlink_status.type(file_type::character); break; case DT_DIR: _dir_entry._symlink_status.type(file_type::directory); break; case DT_FIFO: _dir_entry._symlink_status.type(file_type::fifo); break; case DT_LNK: _dir_entry._symlink_status.type(file_type::symlink); break; case DT_REG: _dir_entry._symlink_status.type(file_type::regular); break; case DT_SOCK: _dir_entry._symlink_status.type(file_type::socket); break; default: _dir_entry._symlink_status.type(file_type::unknown); break; } if (_entry->d_type != DT_LNK) { _dir_entry._status = _dir_entry._symlink_status; } else { _dir_entry._status.type(file_type::none); _dir_entry._status.permissions(perms::unknown); } _dir_entry._file_size = static_cast(-1); _dir_entry._hard_link_count = static_cast(-1); _dir_entry._last_write_time = 0; } path _base; directory_options _options; DIR* _dir; struct ::dirent* _entry; directory_entry _dir_entry; std::error_code _ec; }; #endif // 30.10.13.1 member functions GHC_INLINE directory_iterator::directory_iterator() noexcept : _impl(new impl(path(), directory_options::none)) { } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE directory_iterator::directory_iterator(const path& p) : _impl(new impl(p, directory_options::none)) { if (_impl->_ec) { throw filesystem_error(detail::systemErrorText(_impl->_ec.value()), p, _impl->_ec); } _impl->_ec.clear(); } GHC_INLINE directory_iterator::directory_iterator(const path& p, directory_options options) : _impl(new impl(p, options)) { if (_impl->_ec) { throw filesystem_error(detail::systemErrorText(_impl->_ec.value()), p, _impl->_ec); } } #endif GHC_INLINE directory_iterator::directory_iterator(const path& p, std::error_code& ec) noexcept : _impl(new impl(p, directory_options::none)) { if (_impl->_ec) { ec = _impl->_ec; } } GHC_INLINE directory_iterator::directory_iterator(const path& p, directory_options options, std::error_code& ec) noexcept : _impl(new impl(p, options)) { if (_impl->_ec) { ec = _impl->_ec; } } GHC_INLINE directory_iterator::directory_iterator(const directory_iterator& rhs) : _impl(rhs._impl) { } GHC_INLINE directory_iterator::directory_iterator(directory_iterator&& rhs) noexcept : _impl(std::move(rhs._impl)) { } GHC_INLINE directory_iterator::~directory_iterator() {} GHC_INLINE directory_iterator& directory_iterator::operator=(const directory_iterator& rhs) { _impl = rhs._impl; return *this; } GHC_INLINE directory_iterator& directory_iterator::operator=(directory_iterator&& rhs) noexcept { _impl = std::move(rhs._impl); return *this; } GHC_INLINE const directory_entry& directory_iterator::operator*() const { return _impl->_dir_entry; } GHC_INLINE const directory_entry* directory_iterator::operator->() const { return &_impl->_dir_entry; } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE directory_iterator& directory_iterator::operator++() { std::error_code ec; _impl->increment(ec); if (ec) { throw filesystem_error(detail::systemErrorText(ec.value()), _impl->_dir_entry._path, ec); } return *this; } #endif GHC_INLINE directory_iterator& directory_iterator::increment(std::error_code& ec) noexcept { _impl->increment(ec); return *this; } GHC_INLINE bool directory_iterator::operator==(const directory_iterator& rhs) const { return _impl->_dir_entry._path == rhs._impl->_dir_entry._path; } GHC_INLINE bool directory_iterator::operator!=(const directory_iterator& rhs) const { return _impl->_dir_entry._path != rhs._impl->_dir_entry._path; } // 30.10.13.2 directory_iterator non-member functions GHC_INLINE directory_iterator begin(directory_iterator iter) noexcept { return iter; } GHC_INLINE directory_iterator end(const directory_iterator&) noexcept { return directory_iterator(); } //----------------------------------------------------------------------------- // 30.10.14 class recursive_directory_iterator GHC_INLINE recursive_directory_iterator::recursive_directory_iterator() noexcept : _impl(new recursive_directory_iterator_impl(directory_options::none, true)) { _impl->_dir_iter_stack.push(directory_iterator()); } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE recursive_directory_iterator::recursive_directory_iterator(const path& p) : _impl(new recursive_directory_iterator_impl(directory_options::none, true)) { _impl->_dir_iter_stack.push(directory_iterator(p)); } GHC_INLINE recursive_directory_iterator::recursive_directory_iterator(const path& p, directory_options options) : _impl(new recursive_directory_iterator_impl(options, true)) { _impl->_dir_iter_stack.push(directory_iterator(p, options)); } #endif GHC_INLINE recursive_directory_iterator::recursive_directory_iterator(const path& p, directory_options options, std::error_code& ec) noexcept : _impl(new recursive_directory_iterator_impl(options, true)) { _impl->_dir_iter_stack.push(directory_iterator(p, options, ec)); } GHC_INLINE recursive_directory_iterator::recursive_directory_iterator(const path& p, std::error_code& ec) noexcept : _impl(new recursive_directory_iterator_impl(directory_options::none, true)) { _impl->_dir_iter_stack.push(directory_iterator(p, ec)); } GHC_INLINE recursive_directory_iterator::recursive_directory_iterator(const recursive_directory_iterator& rhs) : _impl(rhs._impl) { } GHC_INLINE recursive_directory_iterator::recursive_directory_iterator(recursive_directory_iterator&& rhs) noexcept : _impl(std::move(rhs._impl)) { } GHC_INLINE recursive_directory_iterator::~recursive_directory_iterator() {} // 30.10.14.1 observers GHC_INLINE directory_options recursive_directory_iterator::options() const { return _impl->_options; } GHC_INLINE int recursive_directory_iterator::depth() const { return static_cast(_impl->_dir_iter_stack.size() - 1); } GHC_INLINE bool recursive_directory_iterator::recursion_pending() const { return _impl->_recursion_pending; } GHC_INLINE const directory_entry& recursive_directory_iterator::operator*() const { return *(_impl->_dir_iter_stack.top()); } GHC_INLINE const directory_entry* recursive_directory_iterator::operator->() const { return &(*(_impl->_dir_iter_stack.top())); } // 30.10.14.1 modifiers recursive_directory_iterator& GHC_INLINE recursive_directory_iterator& recursive_directory_iterator::operator=(const recursive_directory_iterator& rhs) { _impl = rhs._impl; return *this; } GHC_INLINE recursive_directory_iterator& recursive_directory_iterator::operator=(recursive_directory_iterator&& rhs) noexcept { _impl = std::move(rhs._impl); return *this; } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE recursive_directory_iterator& recursive_directory_iterator::operator++() { std::error_code ec; increment(ec); if (ec) { throw filesystem_error(detail::systemErrorText(ec.value()), _impl->_dir_iter_stack.empty() ? path() : _impl->_dir_iter_stack.top()->path(), ec); } return *this; } #endif GHC_INLINE recursive_directory_iterator& recursive_directory_iterator::increment(std::error_code& ec) noexcept { bool isDir = (*this)->is_directory(ec); bool isSymLink = !ec && (*this)->is_symlink(ec); if(!ec) { if (recursion_pending() && isDir && (!isSymLink || (options() & directory_options::follow_directory_symlink) != directory_options::none)) { _impl->_dir_iter_stack.push(directory_iterator((*this)->path(), _impl->_options, ec)); } else { _impl->_dir_iter_stack.top().increment(ec); } if (!ec) { while (depth() && _impl->_dir_iter_stack.top() == directory_iterator()) { _impl->_dir_iter_stack.pop(); _impl->_dir_iter_stack.top().increment(ec); } } else if (!_impl->_dir_iter_stack.empty()) { _impl->_dir_iter_stack.pop(); } _impl->_recursion_pending = true; } return *this; } #ifdef GHC_WITH_EXCEPTIONS GHC_INLINE void recursive_directory_iterator::pop() { std::error_code ec; pop(ec); if (ec) { throw filesystem_error(detail::systemErrorText(ec.value()), _impl->_dir_iter_stack.empty() ? path() : _impl->_dir_iter_stack.top()->path(), ec); } } #endif GHC_INLINE void recursive_directory_iterator::pop(std::error_code& ec) { if (depth() == 0) { *this = recursive_directory_iterator(); } else { do { _impl->_dir_iter_stack.pop(); _impl->_dir_iter_stack.top().increment(ec); } while (depth() && _impl->_dir_iter_stack.top() == directory_iterator()); } } GHC_INLINE void recursive_directory_iterator::disable_recursion_pending() { _impl->_recursion_pending = false; } // other members as required by 27.2.3, input iterators GHC_INLINE bool recursive_directory_iterator::operator==(const recursive_directory_iterator& rhs) const { return _impl->_dir_iter_stack.top() == rhs._impl->_dir_iter_stack.top(); } GHC_INLINE bool recursive_directory_iterator::operator!=(const recursive_directory_iterator& rhs) const { return _impl->_dir_iter_stack.top() != rhs._impl->_dir_iter_stack.top(); } // 30.10.14.2 directory_iterator non-member functions GHC_INLINE recursive_directory_iterator begin(recursive_directory_iterator iter) noexcept { return iter; } GHC_INLINE recursive_directory_iterator end(const recursive_directory_iterator&) noexcept { return recursive_directory_iterator(); } #endif // GHC_EXPAND_IMPL } // namespace filesystem } // namespace ghc // cleanup some macros #undef GHC_INLINE #undef GHC_EXPAND_IMPL #endif // GHC_FILESYSTEM_H ================================================ FILE: include/glad/glad.h ================================================ /* OpenGL, OpenGL ES loader generated by glad 0.1.33 on Thu Apr 9 12:37:38 2020. Language/Generator: C/C++ Specification: gl APIs: gl=4.6, gles2=3.2 Profile: compatibility Extensions: GL_ARB_clip_control, GL_EXT_clip_control Loader: True Local files: False Omit khrplatform: False Reproducible: False Commandline: --profile="compatibility" --api="gl=4.6,gles2=3.2" --generator="c" --spec="gl" --extensions="GL_ARB_clip_control,GL_EXT_clip_control" Online: https://glad.dav1d.de/#profile=compatibility&language=c&specification=gl&loader=on&api=gl%3D4.6&api=gles2%3D3.2&extensions=GL_ARB_clip_control&extensions=GL_EXT_clip_control */ #ifndef __glad_h_ #define __glad_h_ #ifdef __gl_h_ #error OpenGL header already included, remove this include, glad already provides it #endif #define __gl_h_ #ifdef __gl2_h_ #error OpenGL ES 2 header already included, remove this include, glad already provides it #endif #define __gl2_h_ #ifdef __gl3_h_ #error OpenGL ES 3 header already included, remove this include, glad already provides it #endif #define __gl3_h_ #if defined(_WIN32) && !defined(APIENTRY) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__) #define APIENTRY __stdcall #endif #ifndef APIENTRY #define APIENTRY #endif #ifndef APIENTRYP #define APIENTRYP APIENTRY * #endif #ifndef GLAPIENTRY #define GLAPIENTRY APIENTRY #endif #ifdef __cplusplus extern "C" { #endif struct gladGLversionStruct { int major; int minor; }; typedef void* (* GLADloadproc)(const char *name); #ifndef GLAPI # if defined(GLAD_GLAPI_EXPORT) # if defined(_WIN32) || defined(__CYGWIN__) # if defined(GLAD_GLAPI_EXPORT_BUILD) # if defined(__GNUC__) # define GLAPI __attribute__ ((dllexport)) extern # else # define GLAPI __declspec(dllexport) extern # endif # else # if defined(__GNUC__) # define GLAPI __attribute__ ((dllimport)) extern # else # define GLAPI __declspec(dllimport) extern # endif # endif # elif defined(__GNUC__) && defined(GLAD_GLAPI_EXPORT_BUILD) # define GLAPI __attribute__ ((visibility ("default"))) extern # else # define GLAPI extern # endif # else # define GLAPI extern # endif #endif GLAPI struct gladGLversionStruct GLVersion; GLAPI int gladLoadGL(void); GLAPI int gladLoadGLLoader(GLADloadproc); GLAPI int gladLoadGLES2Loader(GLADloadproc); #include typedef unsigned int GLenum; typedef unsigned char GLboolean; typedef unsigned int GLbitfield; typedef void GLvoid; typedef khronos_int8_t GLbyte; typedef khronos_uint8_t GLubyte; typedef khronos_int16_t GLshort; typedef khronos_uint16_t GLushort; typedef int GLint; typedef unsigned int GLuint; typedef khronos_int32_t GLclampx; typedef int GLsizei; typedef khronos_float_t GLfloat; typedef khronos_float_t GLclampf; typedef double GLdouble; typedef double GLclampd; typedef void *GLeglClientBufferEXT; typedef void *GLeglImageOES; typedef char GLchar; typedef char GLcharARB; #ifdef __APPLE__ typedef void *GLhandleARB; #else typedef unsigned int GLhandleARB; #endif typedef khronos_uint16_t GLhalf; typedef khronos_uint16_t GLhalfARB; typedef khronos_int32_t GLfixed; typedef khronos_intptr_t GLintptr; typedef khronos_intptr_t GLintptrARB; typedef khronos_ssize_t GLsizeiptr; typedef khronos_ssize_t GLsizeiptrARB; typedef khronos_int64_t GLint64; typedef khronos_int64_t GLint64EXT; typedef khronos_uint64_t GLuint64; typedef khronos_uint64_t GLuint64EXT; typedef struct __GLsync *GLsync; struct _cl_context; struct _cl_event; typedef void (APIENTRY *GLDEBUGPROC)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam); typedef void (APIENTRY *GLDEBUGPROCARB)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam); typedef void (APIENTRY *GLDEBUGPROCKHR)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam); typedef void (APIENTRY *GLDEBUGPROCAMD)(GLuint id,GLenum category,GLenum severity,GLsizei length,const GLchar *message,void *userParam); typedef unsigned short GLhalfNV; typedef GLintptr GLvdpauSurfaceNV; typedef void (APIENTRY *GLVULKANPROCNV)(void); #define GL_DEPTH_BUFFER_BIT 0x00000100 #define GL_STENCIL_BUFFER_BIT 0x00000400 #define GL_COLOR_BUFFER_BIT 0x00004000 #define GL_FALSE 0 #define GL_TRUE 1 #define GL_POINTS 0x0000 #define GL_LINES 0x0001 #define GL_LINE_LOOP 0x0002 #define GL_LINE_STRIP 0x0003 #define GL_TRIANGLES 0x0004 #define GL_TRIANGLE_STRIP 0x0005 #define GL_TRIANGLE_FAN 0x0006 #define GL_QUADS 0x0007 #define GL_NEVER 0x0200 #define GL_LESS 0x0201 #define GL_EQUAL 0x0202 #define GL_LEQUAL 0x0203 #define GL_GREATER 0x0204 #define GL_NOTEQUAL 0x0205 #define GL_GEQUAL 0x0206 #define GL_ALWAYS 0x0207 #define GL_ZERO 0 #define GL_ONE 1 #define GL_SRC_COLOR 0x0300 #define GL_ONE_MINUS_SRC_COLOR 0x0301 #define GL_SRC_ALPHA 0x0302 #define GL_ONE_MINUS_SRC_ALPHA 0x0303 #define GL_DST_ALPHA 0x0304 #define GL_ONE_MINUS_DST_ALPHA 0x0305 #define GL_DST_COLOR 0x0306 #define GL_ONE_MINUS_DST_COLOR 0x0307 #define GL_SRC_ALPHA_SATURATE 0x0308 #define GL_NONE 0 #define GL_FRONT_LEFT 0x0400 #define GL_FRONT_RIGHT 0x0401 #define GL_BACK_LEFT 0x0402 #define GL_BACK_RIGHT 0x0403 #define GL_FRONT 0x0404 #define GL_BACK 0x0405 #define GL_LEFT 0x0406 #define GL_RIGHT 0x0407 #define GL_FRONT_AND_BACK 0x0408 #define GL_NO_ERROR 0 #define GL_INVALID_ENUM 0x0500 #define GL_INVALID_VALUE 0x0501 #define GL_INVALID_OPERATION 0x0502 #define GL_OUT_OF_MEMORY 0x0505 #define GL_CW 0x0900 #define GL_CCW 0x0901 #define GL_POINT_SIZE 0x0B11 #define GL_POINT_SIZE_RANGE 0x0B12 #define GL_POINT_SIZE_GRANULARITY 0x0B13 #define GL_LINE_SMOOTH 0x0B20 #define GL_LINE_WIDTH 0x0B21 #define GL_LINE_WIDTH_RANGE 0x0B22 #define GL_LINE_WIDTH_GRANULARITY 0x0B23 #define GL_POLYGON_MODE 0x0B40 #define GL_POLYGON_SMOOTH 0x0B41 #define GL_CULL_FACE 0x0B44 #define GL_CULL_FACE_MODE 0x0B45 #define GL_FRONT_FACE 0x0B46 #define GL_DEPTH_RANGE 0x0B70 #define GL_DEPTH_TEST 0x0B71 #define GL_DEPTH_WRITEMASK 0x0B72 #define GL_DEPTH_CLEAR_VALUE 0x0B73 #define GL_DEPTH_FUNC 0x0B74 #define GL_STENCIL_TEST 0x0B90 #define GL_STENCIL_CLEAR_VALUE 0x0B91 #define GL_STENCIL_FUNC 0x0B92 #define GL_STENCIL_VALUE_MASK 0x0B93 #define GL_STENCIL_FAIL 0x0B94 #define GL_STENCIL_PASS_DEPTH_FAIL 0x0B95 #define GL_STENCIL_PASS_DEPTH_PASS 0x0B96 #define GL_STENCIL_REF 0x0B97 #define GL_STENCIL_WRITEMASK 0x0B98 #define GL_VIEWPORT 0x0BA2 #define GL_DITHER 0x0BD0 #define GL_BLEND_DST 0x0BE0 #define GL_BLEND_SRC 0x0BE1 #define GL_BLEND 0x0BE2 #define GL_LOGIC_OP_MODE 0x0BF0 #define GL_DRAW_BUFFER 0x0C01 #define GL_READ_BUFFER 0x0C02 #define GL_SCISSOR_BOX 0x0C10 #define GL_SCISSOR_TEST 0x0C11 #define GL_COLOR_CLEAR_VALUE 0x0C22 #define GL_COLOR_WRITEMASK 0x0C23 #define GL_DOUBLEBUFFER 0x0C32 #define GL_STEREO 0x0C33 #define GL_LINE_SMOOTH_HINT 0x0C52 #define GL_POLYGON_SMOOTH_HINT 0x0C53 #define GL_UNPACK_SWAP_BYTES 0x0CF0 #define GL_UNPACK_LSB_FIRST 0x0CF1 #define GL_UNPACK_ROW_LENGTH 0x0CF2 #define GL_UNPACK_SKIP_ROWS 0x0CF3 #define GL_UNPACK_SKIP_PIXELS 0x0CF4 #define GL_UNPACK_ALIGNMENT 0x0CF5 #define GL_PACK_SWAP_BYTES 0x0D00 #define GL_PACK_LSB_FIRST 0x0D01 #define GL_PACK_ROW_LENGTH 0x0D02 #define GL_PACK_SKIP_ROWS 0x0D03 #define GL_PACK_SKIP_PIXELS 0x0D04 #define GL_PACK_ALIGNMENT 0x0D05 #define GL_MAX_TEXTURE_SIZE 0x0D33 #define GL_MAX_VIEWPORT_DIMS 0x0D3A #define GL_SUBPIXEL_BITS 0x0D50 #define GL_TEXTURE_1D 0x0DE0 #define GL_TEXTURE_2D 0x0DE1 #define GL_TEXTURE_WIDTH 0x1000 #define GL_TEXTURE_HEIGHT 0x1001 #define GL_TEXTURE_BORDER_COLOR 0x1004 #define GL_DONT_CARE 0x1100 #define GL_FASTEST 0x1101 #define GL_NICEST 0x1102 #define GL_BYTE 0x1400 #define GL_UNSIGNED_BYTE 0x1401 #define GL_SHORT 0x1402 #define GL_UNSIGNED_SHORT 0x1403 #define GL_INT 0x1404 #define GL_UNSIGNED_INT 0x1405 #define GL_FLOAT 0x1406 #define GL_STACK_OVERFLOW 0x0503 #define GL_STACK_UNDERFLOW 0x0504 #define GL_CLEAR 0x1500 #define GL_AND 0x1501 #define GL_AND_REVERSE 0x1502 #define GL_COPY 0x1503 #define GL_AND_INVERTED 0x1504 #define GL_NOOP 0x1505 #define GL_XOR 0x1506 #define GL_OR 0x1507 #define GL_NOR 0x1508 #define GL_EQUIV 0x1509 #define GL_INVERT 0x150A #define GL_OR_REVERSE 0x150B #define GL_COPY_INVERTED 0x150C #define GL_OR_INVERTED 0x150D #define GL_NAND 0x150E #define GL_SET 0x150F #define GL_TEXTURE 0x1702 #define GL_COLOR 0x1800 #define GL_DEPTH 0x1801 #define GL_STENCIL 0x1802 #define GL_STENCIL_INDEX 0x1901 #define GL_DEPTH_COMPONENT 0x1902 #define GL_RED 0x1903 #define GL_GREEN 0x1904 #define GL_BLUE 0x1905 #define GL_ALPHA 0x1906 #define GL_RGB 0x1907 #define GL_RGBA 0x1908 #define GL_POINT 0x1B00 #define GL_LINE 0x1B01 #define GL_FILL 0x1B02 #define GL_KEEP 0x1E00 #define GL_REPLACE 0x1E01 #define GL_INCR 0x1E02 #define GL_DECR 0x1E03 #define GL_VENDOR 0x1F00 #define GL_RENDERER 0x1F01 #define GL_VERSION 0x1F02 #define GL_EXTENSIONS 0x1F03 #define GL_NEAREST 0x2600 #define GL_LINEAR 0x2601 #define GL_NEAREST_MIPMAP_NEAREST 0x2700 #define GL_LINEAR_MIPMAP_NEAREST 0x2701 #define GL_NEAREST_MIPMAP_LINEAR 0x2702 #define GL_LINEAR_MIPMAP_LINEAR 0x2703 #define GL_TEXTURE_MAG_FILTER 0x2800 #define GL_TEXTURE_MIN_FILTER 0x2801 #define GL_TEXTURE_WRAP_S 0x2802 #define GL_TEXTURE_WRAP_T 0x2803 #define GL_REPEAT 0x2901 #define GL_CURRENT_BIT 0x00000001 #define GL_POINT_BIT 0x00000002 #define GL_LINE_BIT 0x00000004 #define GL_POLYGON_BIT 0x00000008 #define GL_POLYGON_STIPPLE_BIT 0x00000010 #define GL_PIXEL_MODE_BIT 0x00000020 #define GL_LIGHTING_BIT 0x00000040 #define GL_FOG_BIT 0x00000080 #define GL_ACCUM_BUFFER_BIT 0x00000200 #define GL_VIEWPORT_BIT 0x00000800 #define GL_TRANSFORM_BIT 0x00001000 #define GL_ENABLE_BIT 0x00002000 #define GL_HINT_BIT 0x00008000 #define GL_EVAL_BIT 0x00010000 #define GL_LIST_BIT 0x00020000 #define GL_TEXTURE_BIT 0x00040000 #define GL_SCISSOR_BIT 0x00080000 #define GL_ALL_ATTRIB_BITS 0xFFFFFFFF #define GL_QUAD_STRIP 0x0008 #define GL_POLYGON 0x0009 #define GL_ACCUM 0x0100 #define GL_LOAD 0x0101 #define GL_RETURN 0x0102 #define GL_MULT 0x0103 #define GL_ADD 0x0104 #define GL_AUX0 0x0409 #define GL_AUX1 0x040A #define GL_AUX2 0x040B #define GL_AUX3 0x040C #define GL_2D 0x0600 #define GL_3D 0x0601 #define GL_3D_COLOR 0x0602 #define GL_3D_COLOR_TEXTURE 0x0603 #define GL_4D_COLOR_TEXTURE 0x0604 #define GL_PASS_THROUGH_TOKEN 0x0700 #define GL_POINT_TOKEN 0x0701 #define GL_LINE_TOKEN 0x0702 #define GL_POLYGON_TOKEN 0x0703 #define GL_BITMAP_TOKEN 0x0704 #define GL_DRAW_PIXEL_TOKEN 0x0705 #define GL_COPY_PIXEL_TOKEN 0x0706 #define GL_LINE_RESET_TOKEN 0x0707 #define GL_EXP 0x0800 #define GL_EXP2 0x0801 #define GL_COEFF 0x0A00 #define GL_ORDER 0x0A01 #define GL_DOMAIN 0x0A02 #define GL_PIXEL_MAP_I_TO_I 0x0C70 #define GL_PIXEL_MAP_S_TO_S 0x0C71 #define GL_PIXEL_MAP_I_TO_R 0x0C72 #define GL_PIXEL_MAP_I_TO_G 0x0C73 #define GL_PIXEL_MAP_I_TO_B 0x0C74 #define GL_PIXEL_MAP_I_TO_A 0x0C75 #define GL_PIXEL_MAP_R_TO_R 0x0C76 #define GL_PIXEL_MAP_G_TO_G 0x0C77 #define GL_PIXEL_MAP_B_TO_B 0x0C78 #define GL_PIXEL_MAP_A_TO_A 0x0C79 #define GL_CURRENT_COLOR 0x0B00 #define GL_CURRENT_INDEX 0x0B01 #define GL_CURRENT_NORMAL 0x0B02 #define GL_CURRENT_TEXTURE_COORDS 0x0B03 #define GL_CURRENT_RASTER_COLOR 0x0B04 #define GL_CURRENT_RASTER_INDEX 0x0B05 #define GL_CURRENT_RASTER_TEXTURE_COORDS 0x0B06 #define GL_CURRENT_RASTER_POSITION 0x0B07 #define GL_CURRENT_RASTER_POSITION_VALID 0x0B08 #define GL_CURRENT_RASTER_DISTANCE 0x0B09 #define GL_POINT_SMOOTH 0x0B10 #define GL_LINE_STIPPLE 0x0B24 #define GL_LINE_STIPPLE_PATTERN 0x0B25 #define GL_LINE_STIPPLE_REPEAT 0x0B26 #define GL_LIST_MODE 0x0B30 #define GL_MAX_LIST_NESTING 0x0B31 #define GL_LIST_BASE 0x0B32 #define GL_LIST_INDEX 0x0B33 #define GL_POLYGON_STIPPLE 0x0B42 #define GL_EDGE_FLAG 0x0B43 #define GL_LIGHTING 0x0B50 #define GL_LIGHT_MODEL_LOCAL_VIEWER 0x0B51 #define GL_LIGHT_MODEL_TWO_SIDE 0x0B52 #define GL_LIGHT_MODEL_AMBIENT 0x0B53 #define GL_SHADE_MODEL 0x0B54 #define GL_COLOR_MATERIAL_FACE 0x0B55 #define GL_COLOR_MATERIAL_PARAMETER 0x0B56 #define GL_COLOR_MATERIAL 0x0B57 #define GL_FOG 0x0B60 #define GL_FOG_INDEX 0x0B61 #define GL_FOG_DENSITY 0x0B62 #define GL_FOG_START 0x0B63 #define GL_FOG_END 0x0B64 #define GL_FOG_MODE 0x0B65 #define GL_FOG_COLOR 0x0B66 #define GL_ACCUM_CLEAR_VALUE 0x0B80 #define GL_MATRIX_MODE 0x0BA0 #define GL_NORMALIZE 0x0BA1 #define GL_MODELVIEW_STACK_DEPTH 0x0BA3 #define GL_PROJECTION_STACK_DEPTH 0x0BA4 #define GL_TEXTURE_STACK_DEPTH 0x0BA5 #define GL_MODELVIEW_MATRIX 0x0BA6 #define GL_PROJECTION_MATRIX 0x0BA7 #define GL_TEXTURE_MATRIX 0x0BA8 #define GL_ATTRIB_STACK_DEPTH 0x0BB0 #define GL_ALPHA_TEST 0x0BC0 #define GL_ALPHA_TEST_FUNC 0x0BC1 #define GL_ALPHA_TEST_REF 0x0BC2 #define GL_LOGIC_OP 0x0BF1 #define GL_AUX_BUFFERS 0x0C00 #define GL_INDEX_CLEAR_VALUE 0x0C20 #define GL_INDEX_WRITEMASK 0x0C21 #define GL_INDEX_MODE 0x0C30 #define GL_RGBA_MODE 0x0C31 #define GL_RENDER_MODE 0x0C40 #define GL_PERSPECTIVE_CORRECTION_HINT 0x0C50 #define GL_POINT_SMOOTH_HINT 0x0C51 #define GL_FOG_HINT 0x0C54 #define GL_TEXTURE_GEN_S 0x0C60 #define GL_TEXTURE_GEN_T 0x0C61 #define GL_TEXTURE_GEN_R 0x0C62 #define GL_TEXTURE_GEN_Q 0x0C63 #define GL_PIXEL_MAP_I_TO_I_SIZE 0x0CB0 #define GL_PIXEL_MAP_S_TO_S_SIZE 0x0CB1 #define GL_PIXEL_MAP_I_TO_R_SIZE 0x0CB2 #define GL_PIXEL_MAP_I_TO_G_SIZE 0x0CB3 #define GL_PIXEL_MAP_I_TO_B_SIZE 0x0CB4 #define GL_PIXEL_MAP_I_TO_A_SIZE 0x0CB5 #define GL_PIXEL_MAP_R_TO_R_SIZE 0x0CB6 #define GL_PIXEL_MAP_G_TO_G_SIZE 0x0CB7 #define GL_PIXEL_MAP_B_TO_B_SIZE 0x0CB8 #define GL_PIXEL_MAP_A_TO_A_SIZE 0x0CB9 #define GL_MAP_COLOR 0x0D10 #define GL_MAP_STENCIL 0x0D11 #define GL_INDEX_SHIFT 0x0D12 #define GL_INDEX_OFFSET 0x0D13 #define GL_RED_SCALE 0x0D14 #define GL_RED_BIAS 0x0D15 #define GL_ZOOM_X 0x0D16 #define GL_ZOOM_Y 0x0D17 #define GL_GREEN_SCALE 0x0D18 #define GL_GREEN_BIAS 0x0D19 #define GL_BLUE_SCALE 0x0D1A #define GL_BLUE_BIAS 0x0D1B #define GL_ALPHA_SCALE 0x0D1C #define GL_ALPHA_BIAS 0x0D1D #define GL_DEPTH_SCALE 0x0D1E #define GL_DEPTH_BIAS 0x0D1F #define GL_MAX_EVAL_ORDER 0x0D30 #define GL_MAX_LIGHTS 0x0D31 #define GL_MAX_CLIP_PLANES 0x0D32 #define GL_MAX_PIXEL_MAP_TABLE 0x0D34 #define GL_MAX_ATTRIB_STACK_DEPTH 0x0D35 #define GL_MAX_MODELVIEW_STACK_DEPTH 0x0D36 #define GL_MAX_NAME_STACK_DEPTH 0x0D37 #define GL_MAX_PROJECTION_STACK_DEPTH 0x0D38 #define GL_MAX_TEXTURE_STACK_DEPTH 0x0D39 #define GL_INDEX_BITS 0x0D51 #define GL_RED_BITS 0x0D52 #define GL_GREEN_BITS 0x0D53 #define GL_BLUE_BITS 0x0D54 #define GL_ALPHA_BITS 0x0D55 #define GL_DEPTH_BITS 0x0D56 #define GL_STENCIL_BITS 0x0D57 #define GL_ACCUM_RED_BITS 0x0D58 #define GL_ACCUM_GREEN_BITS 0x0D59 #define GL_ACCUM_BLUE_BITS 0x0D5A #define GL_ACCUM_ALPHA_BITS 0x0D5B #define GL_NAME_STACK_DEPTH 0x0D70 #define GL_AUTO_NORMAL 0x0D80 #define GL_MAP1_COLOR_4 0x0D90 #define GL_MAP1_INDEX 0x0D91 #define GL_MAP1_NORMAL 0x0D92 #define GL_MAP1_TEXTURE_COORD_1 0x0D93 #define GL_MAP1_TEXTURE_COORD_2 0x0D94 #define GL_MAP1_TEXTURE_COORD_3 0x0D95 #define GL_MAP1_TEXTURE_COORD_4 0x0D96 #define GL_MAP1_VERTEX_3 0x0D97 #define GL_MAP1_VERTEX_4 0x0D98 #define GL_MAP2_COLOR_4 0x0DB0 #define GL_MAP2_INDEX 0x0DB1 #define GL_MAP2_NORMAL 0x0DB2 #define GL_MAP2_TEXTURE_COORD_1 0x0DB3 #define GL_MAP2_TEXTURE_COORD_2 0x0DB4 #define GL_MAP2_TEXTURE_COORD_3 0x0DB5 #define GL_MAP2_TEXTURE_COORD_4 0x0DB6 #define GL_MAP2_VERTEX_3 0x0DB7 #define GL_MAP2_VERTEX_4 0x0DB8 #define GL_MAP1_GRID_DOMAIN 0x0DD0 #define GL_MAP1_GRID_SEGMENTS 0x0DD1 #define GL_MAP2_GRID_DOMAIN 0x0DD2 #define GL_MAP2_GRID_SEGMENTS 0x0DD3 #define GL_TEXTURE_COMPONENTS 0x1003 #define GL_TEXTURE_BORDER 0x1005 #define GL_AMBIENT 0x1200 #define GL_DIFFUSE 0x1201 #define GL_SPECULAR 0x1202 #define GL_POSITION 0x1203 #define GL_SPOT_DIRECTION 0x1204 #define GL_SPOT_EXPONENT 0x1205 #define GL_SPOT_CUTOFF 0x1206 #define GL_CONSTANT_ATTENUATION 0x1207 #define GL_LINEAR_ATTENUATION 0x1208 #define GL_QUADRATIC_ATTENUATION 0x1209 #define GL_COMPILE 0x1300 #define GL_COMPILE_AND_EXECUTE 0x1301 #define GL_2_BYTES 0x1407 #define GL_3_BYTES 0x1408 #define GL_4_BYTES 0x1409 #define GL_EMISSION 0x1600 #define GL_SHININESS 0x1601 #define GL_AMBIENT_AND_DIFFUSE 0x1602 #define GL_COLOR_INDEXES 0x1603 #define GL_MODELVIEW 0x1700 #define GL_PROJECTION 0x1701 #define GL_COLOR_INDEX 0x1900 #define GL_LUMINANCE 0x1909 #define GL_LUMINANCE_ALPHA 0x190A #define GL_BITMAP 0x1A00 #define GL_RENDER 0x1C00 #define GL_FEEDBACK 0x1C01 #define GL_SELECT 0x1C02 #define GL_FLAT 0x1D00 #define GL_SMOOTH 0x1D01 #define GL_S 0x2000 #define GL_T 0x2001 #define GL_R 0x2002 #define GL_Q 0x2003 #define GL_MODULATE 0x2100 #define GL_DECAL 0x2101 #define GL_TEXTURE_ENV_MODE 0x2200 #define GL_TEXTURE_ENV_COLOR 0x2201 #define GL_TEXTURE_ENV 0x2300 #define GL_EYE_LINEAR 0x2400 #define GL_OBJECT_LINEAR 0x2401 #define GL_SPHERE_MAP 0x2402 #define GL_TEXTURE_GEN_MODE 0x2500 #define GL_OBJECT_PLANE 0x2501 #define GL_EYE_PLANE 0x2502 #define GL_CLAMP 0x2900 #define GL_CLIP_PLANE0 0x3000 #define GL_CLIP_PLANE1 0x3001 #define GL_CLIP_PLANE2 0x3002 #define GL_CLIP_PLANE3 0x3003 #define GL_CLIP_PLANE4 0x3004 #define GL_CLIP_PLANE5 0x3005 #define GL_LIGHT0 0x4000 #define GL_LIGHT1 0x4001 #define GL_LIGHT2 0x4002 #define GL_LIGHT3 0x4003 #define GL_LIGHT4 0x4004 #define GL_LIGHT5 0x4005 #define GL_LIGHT6 0x4006 #define GL_LIGHT7 0x4007 #define GL_COLOR_LOGIC_OP 0x0BF2 #define GL_POLYGON_OFFSET_UNITS 0x2A00 #define GL_POLYGON_OFFSET_POINT 0x2A01 #define GL_POLYGON_OFFSET_LINE 0x2A02 #define GL_POLYGON_OFFSET_FILL 0x8037 #define GL_POLYGON_OFFSET_FACTOR 0x8038 #define GL_TEXTURE_BINDING_1D 0x8068 #define GL_TEXTURE_BINDING_2D 0x8069 #define GL_TEXTURE_INTERNAL_FORMAT 0x1003 #define GL_TEXTURE_RED_SIZE 0x805C #define GL_TEXTURE_GREEN_SIZE 0x805D #define GL_TEXTURE_BLUE_SIZE 0x805E #define GL_TEXTURE_ALPHA_SIZE 0x805F #define GL_DOUBLE 0x140A #define GL_PROXY_TEXTURE_1D 0x8063 #define GL_PROXY_TEXTURE_2D 0x8064 #define GL_R3_G3_B2 0x2A10 #define GL_RGB4 0x804F #define GL_RGB5 0x8050 #define GL_RGB8 0x8051 #define GL_RGB10 0x8052 #define GL_RGB12 0x8053 #define GL_RGB16 0x8054 #define GL_RGBA2 0x8055 #define GL_RGBA4 0x8056 #define GL_RGB5_A1 0x8057 #define GL_RGBA8 0x8058 #define GL_RGB10_A2 0x8059 #define GL_RGBA12 0x805A #define GL_RGBA16 0x805B #define GL_CLIENT_PIXEL_STORE_BIT 0x00000001 #define GL_CLIENT_VERTEX_ARRAY_BIT 0x00000002 #define GL_CLIENT_ALL_ATTRIB_BITS 0xFFFFFFFF #define GL_VERTEX_ARRAY_POINTER 0x808E #define GL_NORMAL_ARRAY_POINTER 0x808F #define GL_COLOR_ARRAY_POINTER 0x8090 #define GL_INDEX_ARRAY_POINTER 0x8091 #define GL_TEXTURE_COORD_ARRAY_POINTER 0x8092 #define GL_EDGE_FLAG_ARRAY_POINTER 0x8093 #define GL_FEEDBACK_BUFFER_POINTER 0x0DF0 #define GL_SELECTION_BUFFER_POINTER 0x0DF3 #define GL_CLIENT_ATTRIB_STACK_DEPTH 0x0BB1 #define GL_INDEX_LOGIC_OP 0x0BF1 #define GL_MAX_CLIENT_ATTRIB_STACK_DEPTH 0x0D3B #define GL_FEEDBACK_BUFFER_SIZE 0x0DF1 #define GL_FEEDBACK_BUFFER_TYPE 0x0DF2 #define GL_SELECTION_BUFFER_SIZE 0x0DF4 #define GL_VERTEX_ARRAY 0x8074 #define GL_NORMAL_ARRAY 0x8075 #define GL_COLOR_ARRAY 0x8076 #define GL_INDEX_ARRAY 0x8077 #define GL_TEXTURE_COORD_ARRAY 0x8078 #define GL_EDGE_FLAG_ARRAY 0x8079 #define GL_VERTEX_ARRAY_SIZE 0x807A #define GL_VERTEX_ARRAY_TYPE 0x807B #define GL_VERTEX_ARRAY_STRIDE 0x807C #define GL_NORMAL_ARRAY_TYPE 0x807E #define GL_NORMAL_ARRAY_STRIDE 0x807F #define GL_COLOR_ARRAY_SIZE 0x8081 #define GL_COLOR_ARRAY_TYPE 0x8082 #define GL_COLOR_ARRAY_STRIDE 0x8083 #define GL_INDEX_ARRAY_TYPE 0x8085 #define GL_INDEX_ARRAY_STRIDE 0x8086 #define GL_TEXTURE_COORD_ARRAY_SIZE 0x8088 #define GL_TEXTURE_COORD_ARRAY_TYPE 0x8089 #define GL_TEXTURE_COORD_ARRAY_STRIDE 0x808A #define GL_EDGE_FLAG_ARRAY_STRIDE 0x808C #define GL_TEXTURE_LUMINANCE_SIZE 0x8060 #define GL_TEXTURE_INTENSITY_SIZE 0x8061 #define GL_TEXTURE_PRIORITY 0x8066 #define GL_TEXTURE_RESIDENT 0x8067 #define GL_ALPHA4 0x803B #define GL_ALPHA8 0x803C #define GL_ALPHA12 0x803D #define GL_ALPHA16 0x803E #define GL_LUMINANCE4 0x803F #define GL_LUMINANCE8 0x8040 #define GL_LUMINANCE12 0x8041 #define GL_LUMINANCE16 0x8042 #define GL_LUMINANCE4_ALPHA4 0x8043 #define GL_LUMINANCE6_ALPHA2 0x8044 #define GL_LUMINANCE8_ALPHA8 0x8045 #define GL_LUMINANCE12_ALPHA4 0x8046 #define GL_LUMINANCE12_ALPHA12 0x8047 #define GL_LUMINANCE16_ALPHA16 0x8048 #define GL_INTENSITY 0x8049 #define GL_INTENSITY4 0x804A #define GL_INTENSITY8 0x804B #define GL_INTENSITY12 0x804C #define GL_INTENSITY16 0x804D #define GL_V2F 0x2A20 #define GL_V3F 0x2A21 #define GL_C4UB_V2F 0x2A22 #define GL_C4UB_V3F 0x2A23 #define GL_C3F_V3F 0x2A24 #define GL_N3F_V3F 0x2A25 #define GL_C4F_N3F_V3F 0x2A26 #define GL_T2F_V3F 0x2A27 #define GL_T4F_V4F 0x2A28 #define GL_T2F_C4UB_V3F 0x2A29 #define GL_T2F_C3F_V3F 0x2A2A #define GL_T2F_N3F_V3F 0x2A2B #define GL_T2F_C4F_N3F_V3F 0x2A2C #define GL_T4F_C4F_N3F_V4F 0x2A2D #define GL_UNSIGNED_BYTE_3_3_2 0x8032 #define GL_UNSIGNED_SHORT_4_4_4_4 0x8033 #define GL_UNSIGNED_SHORT_5_5_5_1 0x8034 #define GL_UNSIGNED_INT_8_8_8_8 0x8035 #define GL_UNSIGNED_INT_10_10_10_2 0x8036 #define GL_TEXTURE_BINDING_3D 0x806A #define GL_PACK_SKIP_IMAGES 0x806B #define GL_PACK_IMAGE_HEIGHT 0x806C #define GL_UNPACK_SKIP_IMAGES 0x806D #define GL_UNPACK_IMAGE_HEIGHT 0x806E #define GL_TEXTURE_3D 0x806F #define GL_PROXY_TEXTURE_3D 0x8070 #define GL_TEXTURE_DEPTH 0x8071 #define GL_TEXTURE_WRAP_R 0x8072 #define GL_MAX_3D_TEXTURE_SIZE 0x8073 #define GL_UNSIGNED_BYTE_2_3_3_REV 0x8362 #define GL_UNSIGNED_SHORT_5_6_5 0x8363 #define GL_UNSIGNED_SHORT_5_6_5_REV 0x8364 #define GL_UNSIGNED_SHORT_4_4_4_4_REV 0x8365 #define GL_UNSIGNED_SHORT_1_5_5_5_REV 0x8366 #define GL_UNSIGNED_INT_8_8_8_8_REV 0x8367 #define GL_UNSIGNED_INT_2_10_10_10_REV 0x8368 #define GL_BGR 0x80E0 #define GL_BGRA 0x80E1 #define GL_MAX_ELEMENTS_VERTICES 0x80E8 #define GL_MAX_ELEMENTS_INDICES 0x80E9 #define GL_CLAMP_TO_EDGE 0x812F #define GL_TEXTURE_MIN_LOD 0x813A #define GL_TEXTURE_MAX_LOD 0x813B #define GL_TEXTURE_BASE_LEVEL 0x813C #define GL_TEXTURE_MAX_LEVEL 0x813D #define GL_SMOOTH_POINT_SIZE_RANGE 0x0B12 #define GL_SMOOTH_POINT_SIZE_GRANULARITY 0x0B13 #define GL_SMOOTH_LINE_WIDTH_RANGE 0x0B22 #define GL_SMOOTH_LINE_WIDTH_GRANULARITY 0x0B23 #define GL_ALIASED_LINE_WIDTH_RANGE 0x846E #define GL_RESCALE_NORMAL 0x803A #define GL_LIGHT_MODEL_COLOR_CONTROL 0x81F8 #define GL_SINGLE_COLOR 0x81F9 #define GL_SEPARATE_SPECULAR_COLOR 0x81FA #define GL_ALIASED_POINT_SIZE_RANGE 0x846D #define GL_TEXTURE0 0x84C0 #define GL_TEXTURE1 0x84C1 #define GL_TEXTURE2 0x84C2 #define GL_TEXTURE3 0x84C3 #define GL_TEXTURE4 0x84C4 #define GL_TEXTURE5 0x84C5 #define GL_TEXTURE6 0x84C6 #define GL_TEXTURE7 0x84C7 #define GL_TEXTURE8 0x84C8 #define GL_TEXTURE9 0x84C9 #define GL_TEXTURE10 0x84CA #define GL_TEXTURE11 0x84CB #define GL_TEXTURE12 0x84CC #define GL_TEXTURE13 0x84CD #define GL_TEXTURE14 0x84CE #define GL_TEXTURE15 0x84CF #define GL_TEXTURE16 0x84D0 #define GL_TEXTURE17 0x84D1 #define GL_TEXTURE18 0x84D2 #define GL_TEXTURE19 0x84D3 #define GL_TEXTURE20 0x84D4 #define GL_TEXTURE21 0x84D5 #define GL_TEXTURE22 0x84D6 #define GL_TEXTURE23 0x84D7 #define GL_TEXTURE24 0x84D8 #define GL_TEXTURE25 0x84D9 #define GL_TEXTURE26 0x84DA #define GL_TEXTURE27 0x84DB #define GL_TEXTURE28 0x84DC #define GL_TEXTURE29 0x84DD #define GL_TEXTURE30 0x84DE #define GL_TEXTURE31 0x84DF #define GL_ACTIVE_TEXTURE 0x84E0 #define GL_MULTISAMPLE 0x809D #define GL_SAMPLE_ALPHA_TO_COVERAGE 0x809E #define GL_SAMPLE_ALPHA_TO_ONE 0x809F #define GL_SAMPLE_COVERAGE 0x80A0 #define GL_SAMPLE_BUFFERS 0x80A8 #define GL_SAMPLES 0x80A9 #define GL_SAMPLE_COVERAGE_VALUE 0x80AA #define GL_SAMPLE_COVERAGE_INVERT 0x80AB #define GL_TEXTURE_CUBE_MAP 0x8513 #define GL_TEXTURE_BINDING_CUBE_MAP 0x8514 #define GL_TEXTURE_CUBE_MAP_POSITIVE_X 0x8515 #define GL_TEXTURE_CUBE_MAP_NEGATIVE_X 0x8516 #define GL_TEXTURE_CUBE_MAP_POSITIVE_Y 0x8517 #define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x8518 #define GL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x8519 #define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x851A #define GL_PROXY_TEXTURE_CUBE_MAP 0x851B #define GL_MAX_CUBE_MAP_TEXTURE_SIZE 0x851C #define GL_COMPRESSED_RGB 0x84ED #define GL_COMPRESSED_RGBA 0x84EE #define GL_TEXTURE_COMPRESSION_HINT 0x84EF #define GL_TEXTURE_COMPRESSED_IMAGE_SIZE 0x86A0 #define GL_TEXTURE_COMPRESSED 0x86A1 #define GL_NUM_COMPRESSED_TEXTURE_FORMATS 0x86A2 #define GL_COMPRESSED_TEXTURE_FORMATS 0x86A3 #define GL_CLAMP_TO_BORDER 0x812D #define GL_CLIENT_ACTIVE_TEXTURE 0x84E1 #define GL_MAX_TEXTURE_UNITS 0x84E2 #define GL_TRANSPOSE_MODELVIEW_MATRIX 0x84E3 #define GL_TRANSPOSE_PROJECTION_MATRIX 0x84E4 #define GL_TRANSPOSE_TEXTURE_MATRIX 0x84E5 #define GL_TRANSPOSE_COLOR_MATRIX 0x84E6 #define GL_MULTISAMPLE_BIT 0x20000000 #define GL_NORMAL_MAP 0x8511 #define GL_REFLECTION_MAP 0x8512 #define GL_COMPRESSED_ALPHA 0x84E9 #define GL_COMPRESSED_LUMINANCE 0x84EA #define GL_COMPRESSED_LUMINANCE_ALPHA 0x84EB #define GL_COMPRESSED_INTENSITY 0x84EC #define GL_COMBINE 0x8570 #define GL_COMBINE_RGB 0x8571 #define GL_COMBINE_ALPHA 0x8572 #define GL_SOURCE0_RGB 0x8580 #define GL_SOURCE1_RGB 0x8581 #define GL_SOURCE2_RGB 0x8582 #define GL_SOURCE0_ALPHA 0x8588 #define GL_SOURCE1_ALPHA 0x8589 #define GL_SOURCE2_ALPHA 0x858A #define GL_OPERAND0_RGB 0x8590 #define GL_OPERAND1_RGB 0x8591 #define GL_OPERAND2_RGB 0x8592 #define GL_OPERAND0_ALPHA 0x8598 #define GL_OPERAND1_ALPHA 0x8599 #define GL_OPERAND2_ALPHA 0x859A #define GL_RGB_SCALE 0x8573 #define GL_ADD_SIGNED 0x8574 #define GL_INTERPOLATE 0x8575 #define GL_SUBTRACT 0x84E7 #define GL_CONSTANT 0x8576 #define GL_PRIMARY_COLOR 0x8577 #define GL_PREVIOUS 0x8578 #define GL_DOT3_RGB 0x86AE #define GL_DOT3_RGBA 0x86AF #define GL_BLEND_DST_RGB 0x80C8 #define GL_BLEND_SRC_RGB 0x80C9 #define GL_BLEND_DST_ALPHA 0x80CA #define GL_BLEND_SRC_ALPHA 0x80CB #define GL_POINT_FADE_THRESHOLD_SIZE 0x8128 #define GL_DEPTH_COMPONENT16 0x81A5 #define GL_DEPTH_COMPONENT24 0x81A6 #define GL_DEPTH_COMPONENT32 0x81A7 #define GL_MIRRORED_REPEAT 0x8370 #define GL_MAX_TEXTURE_LOD_BIAS 0x84FD #define GL_TEXTURE_LOD_BIAS 0x8501 #define GL_INCR_WRAP 0x8507 #define GL_DECR_WRAP 0x8508 #define GL_TEXTURE_DEPTH_SIZE 0x884A #define GL_TEXTURE_COMPARE_MODE 0x884C #define GL_TEXTURE_COMPARE_FUNC 0x884D #define GL_POINT_SIZE_MIN 0x8126 #define GL_POINT_SIZE_MAX 0x8127 #define GL_POINT_DISTANCE_ATTENUATION 0x8129 #define GL_GENERATE_MIPMAP 0x8191 #define GL_GENERATE_MIPMAP_HINT 0x8192 #define GL_FOG_COORDINATE_SOURCE 0x8450 #define GL_FOG_COORDINATE 0x8451 #define GL_FRAGMENT_DEPTH 0x8452 #define GL_CURRENT_FOG_COORDINATE 0x8453 #define GL_FOG_COORDINATE_ARRAY_TYPE 0x8454 #define GL_FOG_COORDINATE_ARRAY_STRIDE 0x8455 #define GL_FOG_COORDINATE_ARRAY_POINTER 0x8456 #define GL_FOG_COORDINATE_ARRAY 0x8457 #define GL_COLOR_SUM 0x8458 #define GL_CURRENT_SECONDARY_COLOR 0x8459 #define GL_SECONDARY_COLOR_ARRAY_SIZE 0x845A #define GL_SECONDARY_COLOR_ARRAY_TYPE 0x845B #define GL_SECONDARY_COLOR_ARRAY_STRIDE 0x845C #define GL_SECONDARY_COLOR_ARRAY_POINTER 0x845D #define GL_SECONDARY_COLOR_ARRAY 0x845E #define GL_TEXTURE_FILTER_CONTROL 0x8500 #define GL_DEPTH_TEXTURE_MODE 0x884B #define GL_COMPARE_R_TO_TEXTURE 0x884E #define GL_BLEND_COLOR 0x8005 #define GL_BLEND_EQUATION 0x8009 #define GL_CONSTANT_COLOR 0x8001 #define GL_ONE_MINUS_CONSTANT_COLOR 0x8002 #define GL_CONSTANT_ALPHA 0x8003 #define GL_ONE_MINUS_CONSTANT_ALPHA 0x8004 #define GL_FUNC_ADD 0x8006 #define GL_FUNC_REVERSE_SUBTRACT 0x800B #define GL_FUNC_SUBTRACT 0x800A #define GL_MIN 0x8007 #define GL_MAX 0x8008 #define GL_BUFFER_SIZE 0x8764 #define GL_BUFFER_USAGE 0x8765 #define GL_QUERY_COUNTER_BITS 0x8864 #define GL_CURRENT_QUERY 0x8865 #define GL_QUERY_RESULT 0x8866 #define GL_QUERY_RESULT_AVAILABLE 0x8867 #define GL_ARRAY_BUFFER 0x8892 #define GL_ELEMENT_ARRAY_BUFFER 0x8893 #define GL_ARRAY_BUFFER_BINDING 0x8894 #define GL_ELEMENT_ARRAY_BUFFER_BINDING 0x8895 #define GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING 0x889F #define GL_READ_ONLY 0x88B8 #define GL_WRITE_ONLY 0x88B9 #define GL_READ_WRITE 0x88BA #define GL_BUFFER_ACCESS 0x88BB #define GL_BUFFER_MAPPED 0x88BC #define GL_BUFFER_MAP_POINTER 0x88BD #define GL_STREAM_DRAW 0x88E0 #define GL_STREAM_READ 0x88E1 #define GL_STREAM_COPY 0x88E2 #define GL_STATIC_DRAW 0x88E4 #define GL_STATIC_READ 0x88E5 #define GL_STATIC_COPY 0x88E6 #define GL_DYNAMIC_DRAW 0x88E8 #define GL_DYNAMIC_READ 0x88E9 #define GL_DYNAMIC_COPY 0x88EA #define GL_SAMPLES_PASSED 0x8914 #define GL_SRC1_ALPHA 0x8589 #define GL_VERTEX_ARRAY_BUFFER_BINDING 0x8896 #define GL_NORMAL_ARRAY_BUFFER_BINDING 0x8897 #define GL_COLOR_ARRAY_BUFFER_BINDING 0x8898 #define GL_INDEX_ARRAY_BUFFER_BINDING 0x8899 #define GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING 0x889A #define GL_EDGE_FLAG_ARRAY_BUFFER_BINDING 0x889B #define GL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING 0x889C #define GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING 0x889D #define GL_WEIGHT_ARRAY_BUFFER_BINDING 0x889E #define GL_FOG_COORD_SRC 0x8450 #define GL_FOG_COORD 0x8451 #define GL_CURRENT_FOG_COORD 0x8453 #define GL_FOG_COORD_ARRAY_TYPE 0x8454 #define GL_FOG_COORD_ARRAY_STRIDE 0x8455 #define GL_FOG_COORD_ARRAY_POINTER 0x8456 #define GL_FOG_COORD_ARRAY 0x8457 #define GL_FOG_COORD_ARRAY_BUFFER_BINDING 0x889D #define GL_SRC0_RGB 0x8580 #define GL_SRC1_RGB 0x8581 #define GL_SRC2_RGB 0x8582 #define GL_SRC0_ALPHA 0x8588 #define GL_SRC2_ALPHA 0x858A #define GL_BLEND_EQUATION_RGB 0x8009 #define GL_VERTEX_ATTRIB_ARRAY_ENABLED 0x8622 #define GL_VERTEX_ATTRIB_ARRAY_SIZE 0x8623 #define GL_VERTEX_ATTRIB_ARRAY_STRIDE 0x8624 #define GL_VERTEX_ATTRIB_ARRAY_TYPE 0x8625 #define GL_CURRENT_VERTEX_ATTRIB 0x8626 #define GL_VERTEX_PROGRAM_POINT_SIZE 0x8642 #define GL_VERTEX_ATTRIB_ARRAY_POINTER 0x8645 #define GL_STENCIL_BACK_FUNC 0x8800 #define GL_STENCIL_BACK_FAIL 0x8801 #define GL_STENCIL_BACK_PASS_DEPTH_FAIL 0x8802 #define GL_STENCIL_BACK_PASS_DEPTH_PASS 0x8803 #define GL_MAX_DRAW_BUFFERS 0x8824 #define GL_DRAW_BUFFER0 0x8825 #define GL_DRAW_BUFFER1 0x8826 #define GL_DRAW_BUFFER2 0x8827 #define GL_DRAW_BUFFER3 0x8828 #define GL_DRAW_BUFFER4 0x8829 #define GL_DRAW_BUFFER5 0x882A #define GL_DRAW_BUFFER6 0x882B #define GL_DRAW_BUFFER7 0x882C #define GL_DRAW_BUFFER8 0x882D #define GL_DRAW_BUFFER9 0x882E #define GL_DRAW_BUFFER10 0x882F #define GL_DRAW_BUFFER11 0x8830 #define GL_DRAW_BUFFER12 0x8831 #define GL_DRAW_BUFFER13 0x8832 #define GL_DRAW_BUFFER14 0x8833 #define GL_DRAW_BUFFER15 0x8834 #define GL_BLEND_EQUATION_ALPHA 0x883D #define GL_MAX_VERTEX_ATTRIBS 0x8869 #define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED 0x886A #define GL_MAX_TEXTURE_IMAGE_UNITS 0x8872 #define GL_FRAGMENT_SHADER 0x8B30 #define GL_VERTEX_SHADER 0x8B31 #define GL_MAX_FRAGMENT_UNIFORM_COMPONENTS 0x8B49 #define GL_MAX_VERTEX_UNIFORM_COMPONENTS 0x8B4A #define GL_MAX_VARYING_FLOATS 0x8B4B #define GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS 0x8B4C #define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS 0x8B4D #define GL_SHADER_TYPE 0x8B4F #define GL_FLOAT_VEC2 0x8B50 #define GL_FLOAT_VEC3 0x8B51 #define GL_FLOAT_VEC4 0x8B52 #define GL_INT_VEC2 0x8B53 #define GL_INT_VEC3 0x8B54 #define GL_INT_VEC4 0x8B55 #define GL_BOOL 0x8B56 #define GL_BOOL_VEC2 0x8B57 #define GL_BOOL_VEC3 0x8B58 #define GL_BOOL_VEC4 0x8B59 #define GL_FLOAT_MAT2 0x8B5A #define GL_FLOAT_MAT3 0x8B5B #define GL_FLOAT_MAT4 0x8B5C #define GL_SAMPLER_1D 0x8B5D #define GL_SAMPLER_2D 0x8B5E #define GL_SAMPLER_3D 0x8B5F #define GL_SAMPLER_CUBE 0x8B60 #define GL_SAMPLER_1D_SHADOW 0x8B61 #define GL_SAMPLER_2D_SHADOW 0x8B62 #define GL_DELETE_STATUS 0x8B80 #define GL_COMPILE_STATUS 0x8B81 #define GL_LINK_STATUS 0x8B82 #define GL_VALIDATE_STATUS 0x8B83 #define GL_INFO_LOG_LENGTH 0x8B84 #define GL_ATTACHED_SHADERS 0x8B85 #define GL_ACTIVE_UNIFORMS 0x8B86 #define GL_ACTIVE_UNIFORM_MAX_LENGTH 0x8B87 #define GL_SHADER_SOURCE_LENGTH 0x8B88 #define GL_ACTIVE_ATTRIBUTES 0x8B89 #define GL_ACTIVE_ATTRIBUTE_MAX_LENGTH 0x8B8A #define GL_FRAGMENT_SHADER_DERIVATIVE_HINT 0x8B8B #define GL_SHADING_LANGUAGE_VERSION 0x8B8C #define GL_CURRENT_PROGRAM 0x8B8D #define GL_POINT_SPRITE_COORD_ORIGIN 0x8CA0 #define GL_LOWER_LEFT 0x8CA1 #define GL_UPPER_LEFT 0x8CA2 #define GL_STENCIL_BACK_REF 0x8CA3 #define GL_STENCIL_BACK_VALUE_MASK 0x8CA4 #define GL_STENCIL_BACK_WRITEMASK 0x8CA5 #define GL_VERTEX_PROGRAM_TWO_SIDE 0x8643 #define GL_POINT_SPRITE 0x8861 #define GL_COORD_REPLACE 0x8862 #define GL_MAX_TEXTURE_COORDS 0x8871 #define GL_PIXEL_PACK_BUFFER 0x88EB #define GL_PIXEL_UNPACK_BUFFER 0x88EC #define GL_PIXEL_PACK_BUFFER_BINDING 0x88ED #define GL_PIXEL_UNPACK_BUFFER_BINDING 0x88EF #define GL_FLOAT_MAT2x3 0x8B65 #define GL_FLOAT_MAT2x4 0x8B66 #define GL_FLOAT_MAT3x2 0x8B67 #define GL_FLOAT_MAT3x4 0x8B68 #define GL_FLOAT_MAT4x2 0x8B69 #define GL_FLOAT_MAT4x3 0x8B6A #define GL_SRGB 0x8C40 #define GL_SRGB8 0x8C41 #define GL_SRGB_ALPHA 0x8C42 #define GL_SRGB8_ALPHA8 0x8C43 #define GL_COMPRESSED_SRGB 0x8C48 #define GL_COMPRESSED_SRGB_ALPHA 0x8C49 #define GL_CURRENT_RASTER_SECONDARY_COLOR 0x845F #define GL_SLUMINANCE_ALPHA 0x8C44 #define GL_SLUMINANCE8_ALPHA8 0x8C45 #define GL_SLUMINANCE 0x8C46 #define GL_SLUMINANCE8 0x8C47 #define GL_COMPRESSED_SLUMINANCE 0x8C4A #define GL_COMPRESSED_SLUMINANCE_ALPHA 0x8C4B #define GL_COMPARE_REF_TO_TEXTURE 0x884E #define GL_CLIP_DISTANCE0 0x3000 #define GL_CLIP_DISTANCE1 0x3001 #define GL_CLIP_DISTANCE2 0x3002 #define GL_CLIP_DISTANCE3 0x3003 #define GL_CLIP_DISTANCE4 0x3004 #define GL_CLIP_DISTANCE5 0x3005 #define GL_CLIP_DISTANCE6 0x3006 #define GL_CLIP_DISTANCE7 0x3007 #define GL_MAX_CLIP_DISTANCES 0x0D32 #define GL_MAJOR_VERSION 0x821B #define GL_MINOR_VERSION 0x821C #define GL_NUM_EXTENSIONS 0x821D #define GL_CONTEXT_FLAGS 0x821E #define GL_COMPRESSED_RED 0x8225 #define GL_COMPRESSED_RG 0x8226 #define GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT 0x00000001 #define GL_RGBA32F 0x8814 #define GL_RGB32F 0x8815 #define GL_RGBA16F 0x881A #define GL_RGB16F 0x881B #define GL_VERTEX_ATTRIB_ARRAY_INTEGER 0x88FD #define GL_MAX_ARRAY_TEXTURE_LAYERS 0x88FF #define GL_MIN_PROGRAM_TEXEL_OFFSET 0x8904 #define GL_MAX_PROGRAM_TEXEL_OFFSET 0x8905 #define GL_CLAMP_READ_COLOR 0x891C #define GL_FIXED_ONLY 0x891D #define GL_MAX_VARYING_COMPONENTS 0x8B4B #define GL_TEXTURE_1D_ARRAY 0x8C18 #define GL_PROXY_TEXTURE_1D_ARRAY 0x8C19 #define GL_TEXTURE_2D_ARRAY 0x8C1A #define GL_PROXY_TEXTURE_2D_ARRAY 0x8C1B #define GL_TEXTURE_BINDING_1D_ARRAY 0x8C1C #define GL_TEXTURE_BINDING_2D_ARRAY 0x8C1D #define GL_R11F_G11F_B10F 0x8C3A #define GL_UNSIGNED_INT_10F_11F_11F_REV 0x8C3B #define GL_RGB9_E5 0x8C3D #define GL_UNSIGNED_INT_5_9_9_9_REV 0x8C3E #define GL_TEXTURE_SHARED_SIZE 0x8C3F #define GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH 0x8C76 #define GL_TRANSFORM_FEEDBACK_BUFFER_MODE 0x8C7F #define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS 0x8C80 #define GL_TRANSFORM_FEEDBACK_VARYINGS 0x8C83 #define GL_TRANSFORM_FEEDBACK_BUFFER_START 0x8C84 #define GL_TRANSFORM_FEEDBACK_BUFFER_SIZE 0x8C85 #define GL_PRIMITIVES_GENERATED 0x8C87 #define GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN 0x8C88 #define GL_RASTERIZER_DISCARD 0x8C89 #define GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS 0x8C8A #define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS 0x8C8B #define GL_INTERLEAVED_ATTRIBS 0x8C8C #define GL_SEPARATE_ATTRIBS 0x8C8D #define GL_TRANSFORM_FEEDBACK_BUFFER 0x8C8E #define GL_TRANSFORM_FEEDBACK_BUFFER_BINDING 0x8C8F #define GL_RGBA32UI 0x8D70 #define GL_RGB32UI 0x8D71 #define GL_RGBA16UI 0x8D76 #define GL_RGB16UI 0x8D77 #define GL_RGBA8UI 0x8D7C #define GL_RGB8UI 0x8D7D #define GL_RGBA32I 0x8D82 #define GL_RGB32I 0x8D83 #define GL_RGBA16I 0x8D88 #define GL_RGB16I 0x8D89 #define GL_RGBA8I 0x8D8E #define GL_RGB8I 0x8D8F #define GL_RED_INTEGER 0x8D94 #define GL_GREEN_INTEGER 0x8D95 #define GL_BLUE_INTEGER 0x8D96 #define GL_RGB_INTEGER 0x8D98 #define GL_RGBA_INTEGER 0x8D99 #define GL_BGR_INTEGER 0x8D9A #define GL_BGRA_INTEGER 0x8D9B #define GL_SAMPLER_1D_ARRAY 0x8DC0 #define GL_SAMPLER_2D_ARRAY 0x8DC1 #define GL_SAMPLER_1D_ARRAY_SHADOW 0x8DC3 #define GL_SAMPLER_2D_ARRAY_SHADOW 0x8DC4 #define GL_SAMPLER_CUBE_SHADOW 0x8DC5 #define GL_UNSIGNED_INT_VEC2 0x8DC6 #define GL_UNSIGNED_INT_VEC3 0x8DC7 #define GL_UNSIGNED_INT_VEC4 0x8DC8 #define GL_INT_SAMPLER_1D 0x8DC9 #define GL_INT_SAMPLER_2D 0x8DCA #define GL_INT_SAMPLER_3D 0x8DCB #define GL_INT_SAMPLER_CUBE 0x8DCC #define GL_INT_SAMPLER_1D_ARRAY 0x8DCE #define GL_INT_SAMPLER_2D_ARRAY 0x8DCF #define GL_UNSIGNED_INT_SAMPLER_1D 0x8DD1 #define GL_UNSIGNED_INT_SAMPLER_2D 0x8DD2 #define GL_UNSIGNED_INT_SAMPLER_3D 0x8DD3 #define GL_UNSIGNED_INT_SAMPLER_CUBE 0x8DD4 #define GL_UNSIGNED_INT_SAMPLER_1D_ARRAY 0x8DD6 #define GL_UNSIGNED_INT_SAMPLER_2D_ARRAY 0x8DD7 #define GL_QUERY_WAIT 0x8E13 #define GL_QUERY_NO_WAIT 0x8E14 #define GL_QUERY_BY_REGION_WAIT 0x8E15 #define GL_QUERY_BY_REGION_NO_WAIT 0x8E16 #define GL_BUFFER_ACCESS_FLAGS 0x911F #define GL_BUFFER_MAP_LENGTH 0x9120 #define GL_BUFFER_MAP_OFFSET 0x9121 #define GL_DEPTH_COMPONENT32F 0x8CAC #define GL_DEPTH32F_STENCIL8 0x8CAD #define GL_FLOAT_32_UNSIGNED_INT_24_8_REV 0x8DAD #define GL_INVALID_FRAMEBUFFER_OPERATION 0x0506 #define GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING 0x8210 #define GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE 0x8211 #define GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE 0x8212 #define GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE 0x8213 #define GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE 0x8214 #define GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE 0x8215 #define GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE 0x8216 #define GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE 0x8217 #define GL_FRAMEBUFFER_DEFAULT 0x8218 #define GL_FRAMEBUFFER_UNDEFINED 0x8219 #define GL_DEPTH_STENCIL_ATTACHMENT 0x821A #define GL_MAX_RENDERBUFFER_SIZE 0x84E8 #define GL_DEPTH_STENCIL 0x84F9 #define GL_UNSIGNED_INT_24_8 0x84FA #define GL_DEPTH24_STENCIL8 0x88F0 #define GL_TEXTURE_STENCIL_SIZE 0x88F1 #define GL_TEXTURE_RED_TYPE 0x8C10 #define GL_TEXTURE_GREEN_TYPE 0x8C11 #define GL_TEXTURE_BLUE_TYPE 0x8C12 #define GL_TEXTURE_ALPHA_TYPE 0x8C13 #define GL_TEXTURE_DEPTH_TYPE 0x8C16 #define GL_UNSIGNED_NORMALIZED 0x8C17 #define GL_FRAMEBUFFER_BINDING 0x8CA6 #define GL_DRAW_FRAMEBUFFER_BINDING 0x8CA6 #define GL_RENDERBUFFER_BINDING 0x8CA7 #define GL_READ_FRAMEBUFFER 0x8CA8 #define GL_DRAW_FRAMEBUFFER 0x8CA9 #define GL_READ_FRAMEBUFFER_BINDING 0x8CAA #define GL_RENDERBUFFER_SAMPLES 0x8CAB #define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE 0x8CD0 #define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME 0x8CD1 #define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL 0x8CD2 #define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE 0x8CD3 #define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER 0x8CD4 #define GL_FRAMEBUFFER_COMPLETE 0x8CD5 #define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT 0x8CD6 #define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT 0x8CD7 #define GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER 0x8CDB #define GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER 0x8CDC #define GL_FRAMEBUFFER_UNSUPPORTED 0x8CDD #define GL_MAX_COLOR_ATTACHMENTS 0x8CDF #define GL_COLOR_ATTACHMENT0 0x8CE0 #define GL_COLOR_ATTACHMENT1 0x8CE1 #define GL_COLOR_ATTACHMENT2 0x8CE2 #define GL_COLOR_ATTACHMENT3 0x8CE3 #define GL_COLOR_ATTACHMENT4 0x8CE4 #define GL_COLOR_ATTACHMENT5 0x8CE5 #define GL_COLOR_ATTACHMENT6 0x8CE6 #define GL_COLOR_ATTACHMENT7 0x8CE7 #define GL_COLOR_ATTACHMENT8 0x8CE8 #define GL_COLOR_ATTACHMENT9 0x8CE9 #define GL_COLOR_ATTACHMENT10 0x8CEA #define GL_COLOR_ATTACHMENT11 0x8CEB #define GL_COLOR_ATTACHMENT12 0x8CEC #define GL_COLOR_ATTACHMENT13 0x8CED #define GL_COLOR_ATTACHMENT14 0x8CEE #define GL_COLOR_ATTACHMENT15 0x8CEF #define GL_COLOR_ATTACHMENT16 0x8CF0 #define GL_COLOR_ATTACHMENT17 0x8CF1 #define GL_COLOR_ATTACHMENT18 0x8CF2 #define GL_COLOR_ATTACHMENT19 0x8CF3 #define GL_COLOR_ATTACHMENT20 0x8CF4 #define GL_COLOR_ATTACHMENT21 0x8CF5 #define GL_COLOR_ATTACHMENT22 0x8CF6 #define GL_COLOR_ATTACHMENT23 0x8CF7 #define GL_COLOR_ATTACHMENT24 0x8CF8 #define GL_COLOR_ATTACHMENT25 0x8CF9 #define GL_COLOR_ATTACHMENT26 0x8CFA #define GL_COLOR_ATTACHMENT27 0x8CFB #define GL_COLOR_ATTACHMENT28 0x8CFC #define GL_COLOR_ATTACHMENT29 0x8CFD #define GL_COLOR_ATTACHMENT30 0x8CFE #define GL_COLOR_ATTACHMENT31 0x8CFF #define GL_DEPTH_ATTACHMENT 0x8D00 #define GL_STENCIL_ATTACHMENT 0x8D20 #define GL_FRAMEBUFFER 0x8D40 #define GL_RENDERBUFFER 0x8D41 #define GL_RENDERBUFFER_WIDTH 0x8D42 #define GL_RENDERBUFFER_HEIGHT 0x8D43 #define GL_RENDERBUFFER_INTERNAL_FORMAT 0x8D44 #define GL_STENCIL_INDEX1 0x8D46 #define GL_STENCIL_INDEX4 0x8D47 #define GL_STENCIL_INDEX8 0x8D48 #define GL_STENCIL_INDEX16 0x8D49 #define GL_RENDERBUFFER_RED_SIZE 0x8D50 #define GL_RENDERBUFFER_GREEN_SIZE 0x8D51 #define GL_RENDERBUFFER_BLUE_SIZE 0x8D52 #define GL_RENDERBUFFER_ALPHA_SIZE 0x8D53 #define GL_RENDERBUFFER_DEPTH_SIZE 0x8D54 #define GL_RENDERBUFFER_STENCIL_SIZE 0x8D55 #define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE 0x8D56 #define GL_MAX_SAMPLES 0x8D57 #define GL_INDEX 0x8222 #define GL_TEXTURE_LUMINANCE_TYPE 0x8C14 #define GL_TEXTURE_INTENSITY_TYPE 0x8C15 #define GL_FRAMEBUFFER_SRGB 0x8DB9 #define GL_HALF_FLOAT 0x140B #define GL_MAP_READ_BIT 0x0001 #define GL_MAP_WRITE_BIT 0x0002 #define GL_MAP_INVALIDATE_RANGE_BIT 0x0004 #define GL_MAP_INVALIDATE_BUFFER_BIT 0x0008 #define GL_MAP_FLUSH_EXPLICIT_BIT 0x0010 #define GL_MAP_UNSYNCHRONIZED_BIT 0x0020 #define GL_COMPRESSED_RED_RGTC1 0x8DBB #define GL_COMPRESSED_SIGNED_RED_RGTC1 0x8DBC #define GL_COMPRESSED_RG_RGTC2 0x8DBD #define GL_COMPRESSED_SIGNED_RG_RGTC2 0x8DBE #define GL_RG 0x8227 #define GL_RG_INTEGER 0x8228 #define GL_R8 0x8229 #define GL_R16 0x822A #define GL_RG8 0x822B #define GL_RG16 0x822C #define GL_R16F 0x822D #define GL_R32F 0x822E #define GL_RG16F 0x822F #define GL_RG32F 0x8230 #define GL_R8I 0x8231 #define GL_R8UI 0x8232 #define GL_R16I 0x8233 #define GL_R16UI 0x8234 #define GL_R32I 0x8235 #define GL_R32UI 0x8236 #define GL_RG8I 0x8237 #define GL_RG8UI 0x8238 #define GL_RG16I 0x8239 #define GL_RG16UI 0x823A #define GL_RG32I 0x823B #define GL_RG32UI 0x823C #define GL_VERTEX_ARRAY_BINDING 0x85B5 #define GL_CLAMP_VERTEX_COLOR 0x891A #define GL_CLAMP_FRAGMENT_COLOR 0x891B #define GL_ALPHA_INTEGER 0x8D97 #define GL_SAMPLER_2D_RECT 0x8B63 #define GL_SAMPLER_2D_RECT_SHADOW 0x8B64 #define GL_SAMPLER_BUFFER 0x8DC2 #define GL_INT_SAMPLER_2D_RECT 0x8DCD #define GL_INT_SAMPLER_BUFFER 0x8DD0 #define GL_UNSIGNED_INT_SAMPLER_2D_RECT 0x8DD5 #define GL_UNSIGNED_INT_SAMPLER_BUFFER 0x8DD8 #define GL_TEXTURE_BUFFER 0x8C2A #define GL_MAX_TEXTURE_BUFFER_SIZE 0x8C2B #define GL_TEXTURE_BINDING_BUFFER 0x8C2C #define GL_TEXTURE_BUFFER_DATA_STORE_BINDING 0x8C2D #define GL_TEXTURE_RECTANGLE 0x84F5 #define GL_TEXTURE_BINDING_RECTANGLE 0x84F6 #define GL_PROXY_TEXTURE_RECTANGLE 0x84F7 #define GL_MAX_RECTANGLE_TEXTURE_SIZE 0x84F8 #define GL_R8_SNORM 0x8F94 #define GL_RG8_SNORM 0x8F95 #define GL_RGB8_SNORM 0x8F96 #define GL_RGBA8_SNORM 0x8F97 #define GL_R16_SNORM 0x8F98 #define GL_RG16_SNORM 0x8F99 #define GL_RGB16_SNORM 0x8F9A #define GL_RGBA16_SNORM 0x8F9B #define GL_SIGNED_NORMALIZED 0x8F9C #define GL_PRIMITIVE_RESTART 0x8F9D #define GL_PRIMITIVE_RESTART_INDEX 0x8F9E #define GL_COPY_READ_BUFFER 0x8F36 #define GL_COPY_WRITE_BUFFER 0x8F37 #define GL_UNIFORM_BUFFER 0x8A11 #define GL_UNIFORM_BUFFER_BINDING 0x8A28 #define GL_UNIFORM_BUFFER_START 0x8A29 #define GL_UNIFORM_BUFFER_SIZE 0x8A2A #define GL_MAX_VERTEX_UNIFORM_BLOCKS 0x8A2B #define GL_MAX_GEOMETRY_UNIFORM_BLOCKS 0x8A2C #define GL_MAX_FRAGMENT_UNIFORM_BLOCKS 0x8A2D #define GL_MAX_COMBINED_UNIFORM_BLOCKS 0x8A2E #define GL_MAX_UNIFORM_BUFFER_BINDINGS 0x8A2F #define GL_MAX_UNIFORM_BLOCK_SIZE 0x8A30 #define GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS 0x8A31 #define GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS 0x8A32 #define GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS 0x8A33 #define GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT 0x8A34 #define GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH 0x8A35 #define GL_ACTIVE_UNIFORM_BLOCKS 0x8A36 #define GL_UNIFORM_TYPE 0x8A37 #define GL_UNIFORM_SIZE 0x8A38 #define GL_UNIFORM_NAME_LENGTH 0x8A39 #define GL_UNIFORM_BLOCK_INDEX 0x8A3A #define GL_UNIFORM_OFFSET 0x8A3B #define GL_UNIFORM_ARRAY_STRIDE 0x8A3C #define GL_UNIFORM_MATRIX_STRIDE 0x8A3D #define GL_UNIFORM_IS_ROW_MAJOR 0x8A3E #define GL_UNIFORM_BLOCK_BINDING 0x8A3F #define GL_UNIFORM_BLOCK_DATA_SIZE 0x8A40 #define GL_UNIFORM_BLOCK_NAME_LENGTH 0x8A41 #define GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS 0x8A42 #define GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES 0x8A43 #define GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER 0x8A44 #define GL_UNIFORM_BLOCK_REFERENCED_BY_GEOMETRY_SHADER 0x8A45 #define GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER 0x8A46 #define GL_INVALID_INDEX 0xFFFFFFFF #define GL_CONTEXT_CORE_PROFILE_BIT 0x00000001 #define GL_CONTEXT_COMPATIBILITY_PROFILE_BIT 0x00000002 #define GL_LINES_ADJACENCY 0x000A #define GL_LINE_STRIP_ADJACENCY 0x000B #define GL_TRIANGLES_ADJACENCY 0x000C #define GL_TRIANGLE_STRIP_ADJACENCY 0x000D #define GL_PROGRAM_POINT_SIZE 0x8642 #define GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS 0x8C29 #define GL_FRAMEBUFFER_ATTACHMENT_LAYERED 0x8DA7 #define GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS 0x8DA8 #define GL_GEOMETRY_SHADER 0x8DD9 #define GL_GEOMETRY_VERTICES_OUT 0x8916 #define GL_GEOMETRY_INPUT_TYPE 0x8917 #define GL_GEOMETRY_OUTPUT_TYPE 0x8918 #define GL_MAX_GEOMETRY_UNIFORM_COMPONENTS 0x8DDF #define GL_MAX_GEOMETRY_OUTPUT_VERTICES 0x8DE0 #define GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS 0x8DE1 #define GL_MAX_VERTEX_OUTPUT_COMPONENTS 0x9122 #define GL_MAX_GEOMETRY_INPUT_COMPONENTS 0x9123 #define GL_MAX_GEOMETRY_OUTPUT_COMPONENTS 0x9124 #define GL_MAX_FRAGMENT_INPUT_COMPONENTS 0x9125 #define GL_CONTEXT_PROFILE_MASK 0x9126 #define GL_DEPTH_CLAMP 0x864F #define GL_QUADS_FOLLOW_PROVOKING_VERTEX_CONVENTION 0x8E4C #define GL_FIRST_VERTEX_CONVENTION 0x8E4D #define GL_LAST_VERTEX_CONVENTION 0x8E4E #define GL_PROVOKING_VERTEX 0x8E4F #define GL_TEXTURE_CUBE_MAP_SEAMLESS 0x884F #define GL_MAX_SERVER_WAIT_TIMEOUT 0x9111 #define GL_OBJECT_TYPE 0x9112 #define GL_SYNC_CONDITION 0x9113 #define GL_SYNC_STATUS 0x9114 #define GL_SYNC_FLAGS 0x9115 #define GL_SYNC_FENCE 0x9116 #define GL_SYNC_GPU_COMMANDS_COMPLETE 0x9117 #define GL_UNSIGNALED 0x9118 #define GL_SIGNALED 0x9119 #define GL_ALREADY_SIGNALED 0x911A #define GL_TIMEOUT_EXPIRED 0x911B #define GL_CONDITION_SATISFIED 0x911C #define GL_WAIT_FAILED 0x911D #define GL_TIMEOUT_IGNORED 0xFFFFFFFFFFFFFFFF #define GL_SYNC_FLUSH_COMMANDS_BIT 0x00000001 #define GL_SAMPLE_POSITION 0x8E50 #define GL_SAMPLE_MASK 0x8E51 #define GL_SAMPLE_MASK_VALUE 0x8E52 #define GL_MAX_SAMPLE_MASK_WORDS 0x8E59 #define GL_TEXTURE_2D_MULTISAMPLE 0x9100 #define GL_PROXY_TEXTURE_2D_MULTISAMPLE 0x9101 #define GL_TEXTURE_2D_MULTISAMPLE_ARRAY 0x9102 #define GL_PROXY_TEXTURE_2D_MULTISAMPLE_ARRAY 0x9103 #define GL_TEXTURE_BINDING_2D_MULTISAMPLE 0x9104 #define GL_TEXTURE_BINDING_2D_MULTISAMPLE_ARRAY 0x9105 #define GL_TEXTURE_SAMPLES 0x9106 #define GL_TEXTURE_FIXED_SAMPLE_LOCATIONS 0x9107 #define GL_SAMPLER_2D_MULTISAMPLE 0x9108 #define GL_INT_SAMPLER_2D_MULTISAMPLE 0x9109 #define GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE 0x910A #define GL_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910B #define GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910C #define GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY 0x910D #define GL_MAX_COLOR_TEXTURE_SAMPLES 0x910E #define GL_MAX_DEPTH_TEXTURE_SAMPLES 0x910F #define GL_MAX_INTEGER_SAMPLES 0x9110 #define GL_VERTEX_ATTRIB_ARRAY_DIVISOR 0x88FE #define GL_SRC1_COLOR 0x88F9 #define GL_ONE_MINUS_SRC1_COLOR 0x88FA #define GL_ONE_MINUS_SRC1_ALPHA 0x88FB #define GL_MAX_DUAL_SOURCE_DRAW_BUFFERS 0x88FC #define GL_ANY_SAMPLES_PASSED 0x8C2F #define GL_SAMPLER_BINDING 0x8919 #define GL_RGB10_A2UI 0x906F #define GL_TEXTURE_SWIZZLE_R 0x8E42 #define GL_TEXTURE_SWIZZLE_G 0x8E43 #define GL_TEXTURE_SWIZZLE_B 0x8E44 #define GL_TEXTURE_SWIZZLE_A 0x8E45 #define GL_TEXTURE_SWIZZLE_RGBA 0x8E46 #define GL_TIME_ELAPSED 0x88BF #define GL_TIMESTAMP 0x8E28 #define GL_INT_2_10_10_10_REV 0x8D9F #define GL_SAMPLE_SHADING 0x8C36 #define GL_MIN_SAMPLE_SHADING_VALUE 0x8C37 #define GL_MIN_PROGRAM_TEXTURE_GATHER_OFFSET 0x8E5E #define GL_MAX_PROGRAM_TEXTURE_GATHER_OFFSET 0x8E5F #define GL_TEXTURE_CUBE_MAP_ARRAY 0x9009 #define GL_TEXTURE_BINDING_CUBE_MAP_ARRAY 0x900A #define GL_PROXY_TEXTURE_CUBE_MAP_ARRAY 0x900B #define GL_SAMPLER_CUBE_MAP_ARRAY 0x900C #define GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW 0x900D #define GL_INT_SAMPLER_CUBE_MAP_ARRAY 0x900E #define GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY 0x900F #define GL_DRAW_INDIRECT_BUFFER 0x8F3F #define GL_DRAW_INDIRECT_BUFFER_BINDING 0x8F43 #define GL_GEOMETRY_SHADER_INVOCATIONS 0x887F #define GL_MAX_GEOMETRY_SHADER_INVOCATIONS 0x8E5A #define GL_MIN_FRAGMENT_INTERPOLATION_OFFSET 0x8E5B #define GL_MAX_FRAGMENT_INTERPOLATION_OFFSET 0x8E5C #define GL_FRAGMENT_INTERPOLATION_OFFSET_BITS 0x8E5D #define GL_MAX_VERTEX_STREAMS 0x8E71 #define GL_DOUBLE_VEC2 0x8FFC #define GL_DOUBLE_VEC3 0x8FFD #define GL_DOUBLE_VEC4 0x8FFE #define GL_DOUBLE_MAT2 0x8F46 #define GL_DOUBLE_MAT3 0x8F47 #define GL_DOUBLE_MAT4 0x8F48 #define GL_DOUBLE_MAT2x3 0x8F49 #define GL_DOUBLE_MAT2x4 0x8F4A #define GL_DOUBLE_MAT3x2 0x8F4B #define GL_DOUBLE_MAT3x4 0x8F4C #define GL_DOUBLE_MAT4x2 0x8F4D #define GL_DOUBLE_MAT4x3 0x8F4E #define GL_ACTIVE_SUBROUTINES 0x8DE5 #define GL_ACTIVE_SUBROUTINE_UNIFORMS 0x8DE6 #define GL_ACTIVE_SUBROUTINE_UNIFORM_LOCATIONS 0x8E47 #define GL_ACTIVE_SUBROUTINE_MAX_LENGTH 0x8E48 #define GL_ACTIVE_SUBROUTINE_UNIFORM_MAX_LENGTH 0x8E49 #define GL_MAX_SUBROUTINES 0x8DE7 #define GL_MAX_SUBROUTINE_UNIFORM_LOCATIONS 0x8DE8 #define GL_NUM_COMPATIBLE_SUBROUTINES 0x8E4A #define GL_COMPATIBLE_SUBROUTINES 0x8E4B #define GL_PATCHES 0x000E #define GL_PATCH_VERTICES 0x8E72 #define GL_PATCH_DEFAULT_INNER_LEVEL 0x8E73 #define GL_PATCH_DEFAULT_OUTER_LEVEL 0x8E74 #define GL_TESS_CONTROL_OUTPUT_VERTICES 0x8E75 #define GL_TESS_GEN_MODE 0x8E76 #define GL_TESS_GEN_SPACING 0x8E77 #define GL_TESS_GEN_VERTEX_ORDER 0x8E78 #define GL_TESS_GEN_POINT_MODE 0x8E79 #define GL_ISOLINES 0x8E7A #define GL_FRACTIONAL_ODD 0x8E7B #define GL_FRACTIONAL_EVEN 0x8E7C #define GL_MAX_PATCH_VERTICES 0x8E7D #define GL_MAX_TESS_GEN_LEVEL 0x8E7E #define GL_MAX_TESS_CONTROL_UNIFORM_COMPONENTS 0x8E7F #define GL_MAX_TESS_EVALUATION_UNIFORM_COMPONENTS 0x8E80 #define GL_MAX_TESS_CONTROL_TEXTURE_IMAGE_UNITS 0x8E81 #define GL_MAX_TESS_EVALUATION_TEXTURE_IMAGE_UNITS 0x8E82 #define GL_MAX_TESS_CONTROL_OUTPUT_COMPONENTS 0x8E83 #define GL_MAX_TESS_PATCH_COMPONENTS 0x8E84 #define GL_MAX_TESS_CONTROL_TOTAL_OUTPUT_COMPONENTS 0x8E85 #define GL_MAX_TESS_EVALUATION_OUTPUT_COMPONENTS 0x8E86 #define GL_MAX_TESS_CONTROL_UNIFORM_BLOCKS 0x8E89 #define GL_MAX_TESS_EVALUATION_UNIFORM_BLOCKS 0x8E8A #define GL_MAX_TESS_CONTROL_INPUT_COMPONENTS 0x886C #define GL_MAX_TESS_EVALUATION_INPUT_COMPONENTS 0x886D #define GL_MAX_COMBINED_TESS_CONTROL_UNIFORM_COMPONENTS 0x8E1E #define GL_MAX_COMBINED_TESS_EVALUATION_UNIFORM_COMPONENTS 0x8E1F #define GL_UNIFORM_BLOCK_REFERENCED_BY_TESS_CONTROL_SHADER 0x84F0 #define GL_UNIFORM_BLOCK_REFERENCED_BY_TESS_EVALUATION_SHADER 0x84F1 #define GL_TESS_EVALUATION_SHADER 0x8E87 #define GL_TESS_CONTROL_SHADER 0x8E88 #define GL_TRANSFORM_FEEDBACK 0x8E22 #define GL_TRANSFORM_FEEDBACK_BUFFER_PAUSED 0x8E23 #define GL_TRANSFORM_FEEDBACK_BUFFER_ACTIVE 0x8E24 #define GL_TRANSFORM_FEEDBACK_BINDING 0x8E25 #define GL_MAX_TRANSFORM_FEEDBACK_BUFFERS 0x8E70 #define GL_FIXED 0x140C #define GL_IMPLEMENTATION_COLOR_READ_TYPE 0x8B9A #define GL_IMPLEMENTATION_COLOR_READ_FORMAT 0x8B9B #define GL_LOW_FLOAT 0x8DF0 #define GL_MEDIUM_FLOAT 0x8DF1 #define GL_HIGH_FLOAT 0x8DF2 #define GL_LOW_INT 0x8DF3 #define GL_MEDIUM_INT 0x8DF4 #define GL_HIGH_INT 0x8DF5 #define GL_SHADER_COMPILER 0x8DFA #define GL_SHADER_BINARY_FORMATS 0x8DF8 #define GL_NUM_SHADER_BINARY_FORMATS 0x8DF9 #define GL_MAX_VERTEX_UNIFORM_VECTORS 0x8DFB #define GL_MAX_VARYING_VECTORS 0x8DFC #define GL_MAX_FRAGMENT_UNIFORM_VECTORS 0x8DFD #define GL_RGB565 0x8D62 #define GL_PROGRAM_BINARY_RETRIEVABLE_HINT 0x8257 #define GL_PROGRAM_BINARY_LENGTH 0x8741 #define GL_NUM_PROGRAM_BINARY_FORMATS 0x87FE #define GL_PROGRAM_BINARY_FORMATS 0x87FF #define GL_VERTEX_SHADER_BIT 0x00000001 #define GL_FRAGMENT_SHADER_BIT 0x00000002 #define GL_GEOMETRY_SHADER_BIT 0x00000004 #define GL_TESS_CONTROL_SHADER_BIT 0x00000008 #define GL_TESS_EVALUATION_SHADER_BIT 0x00000010 #define GL_ALL_SHADER_BITS 0xFFFFFFFF #define GL_PROGRAM_SEPARABLE 0x8258 #define GL_ACTIVE_PROGRAM 0x8259 #define GL_PROGRAM_PIPELINE_BINDING 0x825A #define GL_MAX_VIEWPORTS 0x825B #define GL_VIEWPORT_SUBPIXEL_BITS 0x825C #define GL_VIEWPORT_BOUNDS_RANGE 0x825D #define GL_LAYER_PROVOKING_VERTEX 0x825E #define GL_VIEWPORT_INDEX_PROVOKING_VERTEX 0x825F #define GL_UNDEFINED_VERTEX 0x8260 #define GL_COPY_READ_BUFFER_BINDING 0x8F36 #define GL_COPY_WRITE_BUFFER_BINDING 0x8F37 #define GL_TRANSFORM_FEEDBACK_ACTIVE 0x8E24 #define GL_TRANSFORM_FEEDBACK_PAUSED 0x8E23 #define GL_UNPACK_COMPRESSED_BLOCK_WIDTH 0x9127 #define GL_UNPACK_COMPRESSED_BLOCK_HEIGHT 0x9128 #define GL_UNPACK_COMPRESSED_BLOCK_DEPTH 0x9129 #define GL_UNPACK_COMPRESSED_BLOCK_SIZE 0x912A #define GL_PACK_COMPRESSED_BLOCK_WIDTH 0x912B #define GL_PACK_COMPRESSED_BLOCK_HEIGHT 0x912C #define GL_PACK_COMPRESSED_BLOCK_DEPTH 0x912D #define GL_PACK_COMPRESSED_BLOCK_SIZE 0x912E #define GL_NUM_SAMPLE_COUNTS 0x9380 #define GL_MIN_MAP_BUFFER_ALIGNMENT 0x90BC #define GL_ATOMIC_COUNTER_BUFFER 0x92C0 #define GL_ATOMIC_COUNTER_BUFFER_BINDING 0x92C1 #define GL_ATOMIC_COUNTER_BUFFER_START 0x92C2 #define GL_ATOMIC_COUNTER_BUFFER_SIZE 0x92C3 #define GL_ATOMIC_COUNTER_BUFFER_DATA_SIZE 0x92C4 #define GL_ATOMIC_COUNTER_BUFFER_ACTIVE_ATOMIC_COUNTERS 0x92C5 #define GL_ATOMIC_COUNTER_BUFFER_ACTIVE_ATOMIC_COUNTER_INDICES 0x92C6 #define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_VERTEX_SHADER 0x92C7 #define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_TESS_CONTROL_SHADER 0x92C8 #define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_TESS_EVALUATION_SHADER 0x92C9 #define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_GEOMETRY_SHADER 0x92CA #define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_FRAGMENT_SHADER 0x92CB #define GL_MAX_VERTEX_ATOMIC_COUNTER_BUFFERS 0x92CC #define GL_MAX_TESS_CONTROL_ATOMIC_COUNTER_BUFFERS 0x92CD #define GL_MAX_TESS_EVALUATION_ATOMIC_COUNTER_BUFFERS 0x92CE #define GL_MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS 0x92CF #define GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS 0x92D0 #define GL_MAX_COMBINED_ATOMIC_COUNTER_BUFFERS 0x92D1 #define GL_MAX_VERTEX_ATOMIC_COUNTERS 0x92D2 #define GL_MAX_TESS_CONTROL_ATOMIC_COUNTERS 0x92D3 #define GL_MAX_TESS_EVALUATION_ATOMIC_COUNTERS 0x92D4 #define GL_MAX_GEOMETRY_ATOMIC_COUNTERS 0x92D5 #define GL_MAX_FRAGMENT_ATOMIC_COUNTERS 0x92D6 #define GL_MAX_COMBINED_ATOMIC_COUNTERS 0x92D7 #define GL_MAX_ATOMIC_COUNTER_BUFFER_SIZE 0x92D8 #define GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS 0x92DC #define GL_ACTIVE_ATOMIC_COUNTER_BUFFERS 0x92D9 #define GL_UNIFORM_ATOMIC_COUNTER_BUFFER_INDEX 0x92DA #define GL_UNSIGNED_INT_ATOMIC_COUNTER 0x92DB #define GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT 0x00000001 #define GL_ELEMENT_ARRAY_BARRIER_BIT 0x00000002 #define GL_UNIFORM_BARRIER_BIT 0x00000004 #define GL_TEXTURE_FETCH_BARRIER_BIT 0x00000008 #define GL_SHADER_IMAGE_ACCESS_BARRIER_BIT 0x00000020 #define GL_COMMAND_BARRIER_BIT 0x00000040 #define GL_PIXEL_BUFFER_BARRIER_BIT 0x00000080 #define GL_TEXTURE_UPDATE_BARRIER_BIT 0x00000100 #define GL_BUFFER_UPDATE_BARRIER_BIT 0x00000200 #define GL_FRAMEBUFFER_BARRIER_BIT 0x00000400 #define GL_TRANSFORM_FEEDBACK_BARRIER_BIT 0x00000800 #define GL_ATOMIC_COUNTER_BARRIER_BIT 0x00001000 #define GL_ALL_BARRIER_BITS 0xFFFFFFFF #define GL_MAX_IMAGE_UNITS 0x8F38 #define GL_MAX_COMBINED_IMAGE_UNITS_AND_FRAGMENT_OUTPUTS 0x8F39 #define GL_IMAGE_BINDING_NAME 0x8F3A #define GL_IMAGE_BINDING_LEVEL 0x8F3B #define GL_IMAGE_BINDING_LAYERED 0x8F3C #define GL_IMAGE_BINDING_LAYER 0x8F3D #define GL_IMAGE_BINDING_ACCESS 0x8F3E #define GL_IMAGE_1D 0x904C #define GL_IMAGE_2D 0x904D #define GL_IMAGE_3D 0x904E #define GL_IMAGE_2D_RECT 0x904F #define GL_IMAGE_CUBE 0x9050 #define GL_IMAGE_BUFFER 0x9051 #define GL_IMAGE_1D_ARRAY 0x9052 #define GL_IMAGE_2D_ARRAY 0x9053 #define GL_IMAGE_CUBE_MAP_ARRAY 0x9054 #define GL_IMAGE_2D_MULTISAMPLE 0x9055 #define GL_IMAGE_2D_MULTISAMPLE_ARRAY 0x9056 #define GL_INT_IMAGE_1D 0x9057 #define GL_INT_IMAGE_2D 0x9058 #define GL_INT_IMAGE_3D 0x9059 #define GL_INT_IMAGE_2D_RECT 0x905A #define GL_INT_IMAGE_CUBE 0x905B #define GL_INT_IMAGE_BUFFER 0x905C #define GL_INT_IMAGE_1D_ARRAY 0x905D #define GL_INT_IMAGE_2D_ARRAY 0x905E #define GL_INT_IMAGE_CUBE_MAP_ARRAY 0x905F #define GL_INT_IMAGE_2D_MULTISAMPLE 0x9060 #define GL_INT_IMAGE_2D_MULTISAMPLE_ARRAY 0x9061 #define GL_UNSIGNED_INT_IMAGE_1D 0x9062 #define GL_UNSIGNED_INT_IMAGE_2D 0x9063 #define GL_UNSIGNED_INT_IMAGE_3D 0x9064 #define GL_UNSIGNED_INT_IMAGE_2D_RECT 0x9065 #define GL_UNSIGNED_INT_IMAGE_CUBE 0x9066 #define GL_UNSIGNED_INT_IMAGE_BUFFER 0x9067 #define GL_UNSIGNED_INT_IMAGE_1D_ARRAY 0x9068 #define GL_UNSIGNED_INT_IMAGE_2D_ARRAY 0x9069 #define GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY 0x906A #define GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE 0x906B #define GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY 0x906C #define GL_MAX_IMAGE_SAMPLES 0x906D #define GL_IMAGE_BINDING_FORMAT 0x906E #define GL_IMAGE_FORMAT_COMPATIBILITY_TYPE 0x90C7 #define GL_IMAGE_FORMAT_COMPATIBILITY_BY_SIZE 0x90C8 #define GL_IMAGE_FORMAT_COMPATIBILITY_BY_CLASS 0x90C9 #define GL_MAX_VERTEX_IMAGE_UNIFORMS 0x90CA #define GL_MAX_TESS_CONTROL_IMAGE_UNIFORMS 0x90CB #define GL_MAX_TESS_EVALUATION_IMAGE_UNIFORMS 0x90CC #define GL_MAX_GEOMETRY_IMAGE_UNIFORMS 0x90CD #define GL_MAX_FRAGMENT_IMAGE_UNIFORMS 0x90CE #define GL_MAX_COMBINED_IMAGE_UNIFORMS 0x90CF #define GL_COMPRESSED_RGBA_BPTC_UNORM 0x8E8C #define GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM 0x8E8D #define GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT 0x8E8E #define GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT 0x8E8F #define GL_TEXTURE_IMMUTABLE_FORMAT 0x912F #define GL_NUM_SHADING_LANGUAGE_VERSIONS 0x82E9 #define GL_VERTEX_ATTRIB_ARRAY_LONG 0x874E #define GL_COMPRESSED_RGB8_ETC2 0x9274 #define GL_COMPRESSED_SRGB8_ETC2 0x9275 #define GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2 0x9276 #define GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2 0x9277 #define GL_COMPRESSED_RGBA8_ETC2_EAC 0x9278 #define GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC 0x9279 #define GL_COMPRESSED_R11_EAC 0x9270 #define GL_COMPRESSED_SIGNED_R11_EAC 0x9271 #define GL_COMPRESSED_RG11_EAC 0x9272 #define GL_COMPRESSED_SIGNED_RG11_EAC 0x9273 #define GL_PRIMITIVE_RESTART_FIXED_INDEX 0x8D69 #define GL_ANY_SAMPLES_PASSED_CONSERVATIVE 0x8D6A #define GL_MAX_ELEMENT_INDEX 0x8D6B #define GL_COMPUTE_SHADER 0x91B9 #define GL_MAX_COMPUTE_UNIFORM_BLOCKS 0x91BB #define GL_MAX_COMPUTE_TEXTURE_IMAGE_UNITS 0x91BC #define GL_MAX_COMPUTE_IMAGE_UNIFORMS 0x91BD #define GL_MAX_COMPUTE_SHARED_MEMORY_SIZE 0x8262 #define GL_MAX_COMPUTE_UNIFORM_COMPONENTS 0x8263 #define GL_MAX_COMPUTE_ATOMIC_COUNTER_BUFFERS 0x8264 #define GL_MAX_COMPUTE_ATOMIC_COUNTERS 0x8265 #define GL_MAX_COMBINED_COMPUTE_UNIFORM_COMPONENTS 0x8266 #define GL_MAX_COMPUTE_WORK_GROUP_INVOCATIONS 0x90EB #define GL_MAX_COMPUTE_WORK_GROUP_COUNT 0x91BE #define GL_MAX_COMPUTE_WORK_GROUP_SIZE 0x91BF #define GL_COMPUTE_WORK_GROUP_SIZE 0x8267 #define GL_UNIFORM_BLOCK_REFERENCED_BY_COMPUTE_SHADER 0x90EC #define GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_COMPUTE_SHADER 0x90ED #define GL_DISPATCH_INDIRECT_BUFFER 0x90EE #define GL_DISPATCH_INDIRECT_BUFFER_BINDING 0x90EF #define GL_COMPUTE_SHADER_BIT 0x00000020 #define GL_DEBUG_OUTPUT_SYNCHRONOUS 0x8242 #define GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH 0x8243 #define GL_DEBUG_CALLBACK_FUNCTION 0x8244 #define GL_DEBUG_CALLBACK_USER_PARAM 0x8245 #define GL_DEBUG_SOURCE_API 0x8246 #define GL_DEBUG_SOURCE_WINDOW_SYSTEM 0x8247 #define GL_DEBUG_SOURCE_SHADER_COMPILER 0x8248 #define GL_DEBUG_SOURCE_THIRD_PARTY 0x8249 #define GL_DEBUG_SOURCE_APPLICATION 0x824A #define GL_DEBUG_SOURCE_OTHER 0x824B #define GL_DEBUG_TYPE_ERROR 0x824C #define GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR 0x824D #define GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR 0x824E #define GL_DEBUG_TYPE_PORTABILITY 0x824F #define GL_DEBUG_TYPE_PERFORMANCE 0x8250 #define GL_DEBUG_TYPE_OTHER 0x8251 #define GL_MAX_DEBUG_MESSAGE_LENGTH 0x9143 #define GL_MAX_DEBUG_LOGGED_MESSAGES 0x9144 #define GL_DEBUG_LOGGED_MESSAGES 0x9145 #define GL_DEBUG_SEVERITY_HIGH 0x9146 #define GL_DEBUG_SEVERITY_MEDIUM 0x9147 #define GL_DEBUG_SEVERITY_LOW 0x9148 #define GL_DEBUG_TYPE_MARKER 0x8268 #define GL_DEBUG_TYPE_PUSH_GROUP 0x8269 #define GL_DEBUG_TYPE_POP_GROUP 0x826A #define GL_DEBUG_SEVERITY_NOTIFICATION 0x826B #define GL_MAX_DEBUG_GROUP_STACK_DEPTH 0x826C #define GL_DEBUG_GROUP_STACK_DEPTH 0x826D #define GL_BUFFER 0x82E0 #define GL_SHADER 0x82E1 #define GL_PROGRAM 0x82E2 #define GL_QUERY 0x82E3 #define GL_PROGRAM_PIPELINE 0x82E4 #define GL_SAMPLER 0x82E6 #define GL_MAX_LABEL_LENGTH 0x82E8 #define GL_DEBUG_OUTPUT 0x92E0 #define GL_CONTEXT_FLAG_DEBUG_BIT 0x00000002 #define GL_MAX_UNIFORM_LOCATIONS 0x826E #define GL_FRAMEBUFFER_DEFAULT_WIDTH 0x9310 #define GL_FRAMEBUFFER_DEFAULT_HEIGHT 0x9311 #define GL_FRAMEBUFFER_DEFAULT_LAYERS 0x9312 #define GL_FRAMEBUFFER_DEFAULT_SAMPLES 0x9313 #define GL_FRAMEBUFFER_DEFAULT_FIXED_SAMPLE_LOCATIONS 0x9314 #define GL_MAX_FRAMEBUFFER_WIDTH 0x9315 #define GL_MAX_FRAMEBUFFER_HEIGHT 0x9316 #define GL_MAX_FRAMEBUFFER_LAYERS 0x9317 #define GL_MAX_FRAMEBUFFER_SAMPLES 0x9318 #define GL_INTERNALFORMAT_SUPPORTED 0x826F #define GL_INTERNALFORMAT_PREFERRED 0x8270 #define GL_INTERNALFORMAT_RED_SIZE 0x8271 #define GL_INTERNALFORMAT_GREEN_SIZE 0x8272 #define GL_INTERNALFORMAT_BLUE_SIZE 0x8273 #define GL_INTERNALFORMAT_ALPHA_SIZE 0x8274 #define GL_INTERNALFORMAT_DEPTH_SIZE 0x8275 #define GL_INTERNALFORMAT_STENCIL_SIZE 0x8276 #define GL_INTERNALFORMAT_SHARED_SIZE 0x8277 #define GL_INTERNALFORMAT_RED_TYPE 0x8278 #define GL_INTERNALFORMAT_GREEN_TYPE 0x8279 #define GL_INTERNALFORMAT_BLUE_TYPE 0x827A #define GL_INTERNALFORMAT_ALPHA_TYPE 0x827B #define GL_INTERNALFORMAT_DEPTH_TYPE 0x827C #define GL_INTERNALFORMAT_STENCIL_TYPE 0x827D #define GL_MAX_WIDTH 0x827E #define GL_MAX_HEIGHT 0x827F #define GL_MAX_DEPTH 0x8280 #define GL_MAX_LAYERS 0x8281 #define GL_MAX_COMBINED_DIMENSIONS 0x8282 #define GL_COLOR_COMPONENTS 0x8283 #define GL_DEPTH_COMPONENTS 0x8284 #define GL_STENCIL_COMPONENTS 0x8285 #define GL_COLOR_RENDERABLE 0x8286 #define GL_DEPTH_RENDERABLE 0x8287 #define GL_STENCIL_RENDERABLE 0x8288 #define GL_FRAMEBUFFER_RENDERABLE 0x8289 #define GL_FRAMEBUFFER_RENDERABLE_LAYERED 0x828A #define GL_FRAMEBUFFER_BLEND 0x828B #define GL_READ_PIXELS 0x828C #define GL_READ_PIXELS_FORMAT 0x828D #define GL_READ_PIXELS_TYPE 0x828E #define GL_TEXTURE_IMAGE_FORMAT 0x828F #define GL_TEXTURE_IMAGE_TYPE 0x8290 #define GL_GET_TEXTURE_IMAGE_FORMAT 0x8291 #define GL_GET_TEXTURE_IMAGE_TYPE 0x8292 #define GL_MIPMAP 0x8293 #define GL_MANUAL_GENERATE_MIPMAP 0x8294 #define GL_AUTO_GENERATE_MIPMAP 0x8295 #define GL_COLOR_ENCODING 0x8296 #define GL_SRGB_READ 0x8297 #define GL_SRGB_WRITE 0x8298 #define GL_FILTER 0x829A #define GL_VERTEX_TEXTURE 0x829B #define GL_TESS_CONTROL_TEXTURE 0x829C #define GL_TESS_EVALUATION_TEXTURE 0x829D #define GL_GEOMETRY_TEXTURE 0x829E #define GL_FRAGMENT_TEXTURE 0x829F #define GL_COMPUTE_TEXTURE 0x82A0 #define GL_TEXTURE_SHADOW 0x82A1 #define GL_TEXTURE_GATHER 0x82A2 #define GL_TEXTURE_GATHER_SHADOW 0x82A3 #define GL_SHADER_IMAGE_LOAD 0x82A4 #define GL_SHADER_IMAGE_STORE 0x82A5 #define GL_SHADER_IMAGE_ATOMIC 0x82A6 #define GL_IMAGE_TEXEL_SIZE 0x82A7 #define GL_IMAGE_COMPATIBILITY_CLASS 0x82A8 #define GL_IMAGE_PIXEL_FORMAT 0x82A9 #define GL_IMAGE_PIXEL_TYPE 0x82AA #define GL_SIMULTANEOUS_TEXTURE_AND_DEPTH_TEST 0x82AC #define GL_SIMULTANEOUS_TEXTURE_AND_STENCIL_TEST 0x82AD #define GL_SIMULTANEOUS_TEXTURE_AND_DEPTH_WRITE 0x82AE #define GL_SIMULTANEOUS_TEXTURE_AND_STENCIL_WRITE 0x82AF #define GL_TEXTURE_COMPRESSED_BLOCK_WIDTH 0x82B1 #define GL_TEXTURE_COMPRESSED_BLOCK_HEIGHT 0x82B2 #define GL_TEXTURE_COMPRESSED_BLOCK_SIZE 0x82B3 #define GL_CLEAR_BUFFER 0x82B4 #define GL_TEXTURE_VIEW 0x82B5 #define GL_VIEW_COMPATIBILITY_CLASS 0x82B6 #define GL_FULL_SUPPORT 0x82B7 #define GL_CAVEAT_SUPPORT 0x82B8 #define GL_IMAGE_CLASS_4_X_32 0x82B9 #define GL_IMAGE_CLASS_2_X_32 0x82BA #define GL_IMAGE_CLASS_1_X_32 0x82BB #define GL_IMAGE_CLASS_4_X_16 0x82BC #define GL_IMAGE_CLASS_2_X_16 0x82BD #define GL_IMAGE_CLASS_1_X_16 0x82BE #define GL_IMAGE_CLASS_4_X_8 0x82BF #define GL_IMAGE_CLASS_2_X_8 0x82C0 #define GL_IMAGE_CLASS_1_X_8 0x82C1 #define GL_IMAGE_CLASS_11_11_10 0x82C2 #define GL_IMAGE_CLASS_10_10_10_2 0x82C3 #define GL_VIEW_CLASS_128_BITS 0x82C4 #define GL_VIEW_CLASS_96_BITS 0x82C5 #define GL_VIEW_CLASS_64_BITS 0x82C6 #define GL_VIEW_CLASS_48_BITS 0x82C7 #define GL_VIEW_CLASS_32_BITS 0x82C8 #define GL_VIEW_CLASS_24_BITS 0x82C9 #define GL_VIEW_CLASS_16_BITS 0x82CA #define GL_VIEW_CLASS_8_BITS 0x82CB #define GL_VIEW_CLASS_S3TC_DXT1_RGB 0x82CC #define GL_VIEW_CLASS_S3TC_DXT1_RGBA 0x82CD #define GL_VIEW_CLASS_S3TC_DXT3_RGBA 0x82CE #define GL_VIEW_CLASS_S3TC_DXT5_RGBA 0x82CF #define GL_VIEW_CLASS_RGTC1_RED 0x82D0 #define GL_VIEW_CLASS_RGTC2_RG 0x82D1 #define GL_VIEW_CLASS_BPTC_UNORM 0x82D2 #define GL_VIEW_CLASS_BPTC_FLOAT 0x82D3 #define GL_UNIFORM 0x92E1 #define GL_UNIFORM_BLOCK 0x92E2 #define GL_PROGRAM_INPUT 0x92E3 #define GL_PROGRAM_OUTPUT 0x92E4 #define GL_BUFFER_VARIABLE 0x92E5 #define GL_SHADER_STORAGE_BLOCK 0x92E6 #define GL_VERTEX_SUBROUTINE 0x92E8 #define GL_TESS_CONTROL_SUBROUTINE 0x92E9 #define GL_TESS_EVALUATION_SUBROUTINE 0x92EA #define GL_GEOMETRY_SUBROUTINE 0x92EB #define GL_FRAGMENT_SUBROUTINE 0x92EC #define GL_COMPUTE_SUBROUTINE 0x92ED #define GL_VERTEX_SUBROUTINE_UNIFORM 0x92EE #define GL_TESS_CONTROL_SUBROUTINE_UNIFORM 0x92EF #define GL_TESS_EVALUATION_SUBROUTINE_UNIFORM 0x92F0 #define GL_GEOMETRY_SUBROUTINE_UNIFORM 0x92F1 #define GL_FRAGMENT_SUBROUTINE_UNIFORM 0x92F2 #define GL_COMPUTE_SUBROUTINE_UNIFORM 0x92F3 #define GL_TRANSFORM_FEEDBACK_VARYING 0x92F4 #define GL_ACTIVE_RESOURCES 0x92F5 #define GL_MAX_NAME_LENGTH 0x92F6 #define GL_MAX_NUM_ACTIVE_VARIABLES 0x92F7 #define GL_MAX_NUM_COMPATIBLE_SUBROUTINES 0x92F8 #define GL_NAME_LENGTH 0x92F9 #define GL_TYPE 0x92FA #define GL_ARRAY_SIZE 0x92FB #define GL_OFFSET 0x92FC #define GL_BLOCK_INDEX 0x92FD #define GL_ARRAY_STRIDE 0x92FE #define GL_MATRIX_STRIDE 0x92FF #define GL_IS_ROW_MAJOR 0x9300 #define GL_ATOMIC_COUNTER_BUFFER_INDEX 0x9301 #define GL_BUFFER_BINDING 0x9302 #define GL_BUFFER_DATA_SIZE 0x9303 #define GL_NUM_ACTIVE_VARIABLES 0x9304 #define GL_ACTIVE_VARIABLES 0x9305 #define GL_REFERENCED_BY_VERTEX_SHADER 0x9306 #define GL_REFERENCED_BY_TESS_CONTROL_SHADER 0x9307 #define GL_REFERENCED_BY_TESS_EVALUATION_SHADER 0x9308 #define GL_REFERENCED_BY_GEOMETRY_SHADER 0x9309 #define GL_REFERENCED_BY_FRAGMENT_SHADER 0x930A #define GL_REFERENCED_BY_COMPUTE_SHADER 0x930B #define GL_TOP_LEVEL_ARRAY_SIZE 0x930C #define GL_TOP_LEVEL_ARRAY_STRIDE 0x930D #define GL_LOCATION 0x930E #define GL_LOCATION_INDEX 0x930F #define GL_IS_PER_PATCH 0x92E7 #define GL_SHADER_STORAGE_BUFFER 0x90D2 #define GL_SHADER_STORAGE_BUFFER_BINDING 0x90D3 #define GL_SHADER_STORAGE_BUFFER_START 0x90D4 #define GL_SHADER_STORAGE_BUFFER_SIZE 0x90D5 #define GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS 0x90D6 #define GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS 0x90D7 #define GL_MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS 0x90D8 #define GL_MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS 0x90D9 #define GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS 0x90DA #define GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS 0x90DB #define GL_MAX_COMBINED_SHADER_STORAGE_BLOCKS 0x90DC #define GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS 0x90DD #define GL_MAX_SHADER_STORAGE_BLOCK_SIZE 0x90DE #define GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT 0x90DF #define GL_SHADER_STORAGE_BARRIER_BIT 0x00002000 #define GL_MAX_COMBINED_SHADER_OUTPUT_RESOURCES 0x8F39 #define GL_DEPTH_STENCIL_TEXTURE_MODE 0x90EA #define GL_TEXTURE_BUFFER_OFFSET 0x919D #define GL_TEXTURE_BUFFER_SIZE 0x919E #define GL_TEXTURE_BUFFER_OFFSET_ALIGNMENT 0x919F #define GL_TEXTURE_VIEW_MIN_LEVEL 0x82DB #define GL_TEXTURE_VIEW_NUM_LEVELS 0x82DC #define GL_TEXTURE_VIEW_MIN_LAYER 0x82DD #define GL_TEXTURE_VIEW_NUM_LAYERS 0x82DE #define GL_TEXTURE_IMMUTABLE_LEVELS 0x82DF #define GL_VERTEX_ATTRIB_BINDING 0x82D4 #define GL_VERTEX_ATTRIB_RELATIVE_OFFSET 0x82D5 #define GL_VERTEX_BINDING_DIVISOR 0x82D6 #define GL_VERTEX_BINDING_OFFSET 0x82D7 #define GL_VERTEX_BINDING_STRIDE 0x82D8 #define GL_MAX_VERTEX_ATTRIB_RELATIVE_OFFSET 0x82D9 #define GL_MAX_VERTEX_ATTRIB_BINDINGS 0x82DA #define GL_VERTEX_BINDING_BUFFER 0x8F4F #define GL_DISPLAY_LIST 0x82E7 #define GL_MAX_VERTEX_ATTRIB_STRIDE 0x82E5 #define GL_PRIMITIVE_RESTART_FOR_PATCHES_SUPPORTED 0x8221 #define GL_TEXTURE_BUFFER_BINDING 0x8C2A #define GL_MAP_PERSISTENT_BIT 0x0040 #define GL_MAP_COHERENT_BIT 0x0080 #define GL_DYNAMIC_STORAGE_BIT 0x0100 #define GL_CLIENT_STORAGE_BIT 0x0200 #define GL_CLIENT_MAPPED_BUFFER_BARRIER_BIT 0x00004000 #define GL_BUFFER_IMMUTABLE_STORAGE 0x821F #define GL_BUFFER_STORAGE_FLAGS 0x8220 #define GL_CLEAR_TEXTURE 0x9365 #define GL_LOCATION_COMPONENT 0x934A #define GL_TRANSFORM_FEEDBACK_BUFFER_INDEX 0x934B #define GL_TRANSFORM_FEEDBACK_BUFFER_STRIDE 0x934C #define GL_QUERY_BUFFER 0x9192 #define GL_QUERY_BUFFER_BARRIER_BIT 0x00008000 #define GL_QUERY_BUFFER_BINDING 0x9193 #define GL_QUERY_RESULT_NO_WAIT 0x9194 #define GL_MIRROR_CLAMP_TO_EDGE 0x8743 #define GL_CONTEXT_LOST 0x0507 #define GL_NEGATIVE_ONE_TO_ONE 0x935E #define GL_ZERO_TO_ONE 0x935F #define GL_CLIP_ORIGIN 0x935C #define GL_CLIP_DEPTH_MODE 0x935D #define GL_QUERY_WAIT_INVERTED 0x8E17 #define GL_QUERY_NO_WAIT_INVERTED 0x8E18 #define GL_QUERY_BY_REGION_WAIT_INVERTED 0x8E19 #define GL_QUERY_BY_REGION_NO_WAIT_INVERTED 0x8E1A #define GL_MAX_CULL_DISTANCES 0x82F9 #define GL_MAX_COMBINED_CLIP_AND_CULL_DISTANCES 0x82FA #define GL_TEXTURE_TARGET 0x1006 #define GL_QUERY_TARGET 0x82EA #define GL_GUILTY_CONTEXT_RESET 0x8253 #define GL_INNOCENT_CONTEXT_RESET 0x8254 #define GL_UNKNOWN_CONTEXT_RESET 0x8255 #define GL_RESET_NOTIFICATION_STRATEGY 0x8256 #define GL_LOSE_CONTEXT_ON_RESET 0x8252 #define GL_NO_RESET_NOTIFICATION 0x8261 #define GL_CONTEXT_FLAG_ROBUST_ACCESS_BIT 0x00000004 #define GL_CONTEXT_RELEASE_BEHAVIOR 0x82FB #define GL_CONTEXT_RELEASE_BEHAVIOR_FLUSH 0x82FC #define GL_SHADER_BINARY_FORMAT_SPIR_V 0x9551 #define GL_SPIR_V_BINARY 0x9552 #define GL_PARAMETER_BUFFER 0x80EE #define GL_PARAMETER_BUFFER_BINDING 0x80EF #define GL_CONTEXT_FLAG_NO_ERROR_BIT 0x00000008 #define GL_VERTICES_SUBMITTED 0x82EE #define GL_PRIMITIVES_SUBMITTED 0x82EF #define GL_VERTEX_SHADER_INVOCATIONS 0x82F0 #define GL_TESS_CONTROL_SHADER_PATCHES 0x82F1 #define GL_TESS_EVALUATION_SHADER_INVOCATIONS 0x82F2 #define GL_GEOMETRY_SHADER_PRIMITIVES_EMITTED 0x82F3 #define GL_FRAGMENT_SHADER_INVOCATIONS 0x82F4 #define GL_COMPUTE_SHADER_INVOCATIONS 0x82F5 #define GL_CLIPPING_INPUT_PRIMITIVES 0x82F6 #define GL_CLIPPING_OUTPUT_PRIMITIVES 0x82F7 #define GL_POLYGON_OFFSET_CLAMP 0x8E1B #define GL_SPIR_V_EXTENSIONS 0x9553 #define GL_NUM_SPIR_V_EXTENSIONS 0x9554 #define GL_TEXTURE_MAX_ANISOTROPY 0x84FE #define GL_MAX_TEXTURE_MAX_ANISOTROPY 0x84FF #define GL_TRANSFORM_FEEDBACK_OVERFLOW 0x82EC #define GL_TRANSFORM_FEEDBACK_STREAM_OVERFLOW 0x82ED #define GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS 0x8CD9 #define GL_MULTISAMPLE_LINE_WIDTH_RANGE 0x9381 #define GL_MULTISAMPLE_LINE_WIDTH_GRANULARITY 0x9382 #define GL_MULTIPLY 0x9294 #define GL_SCREEN 0x9295 #define GL_OVERLAY 0x9296 #define GL_DARKEN 0x9297 #define GL_LIGHTEN 0x9298 #define GL_COLORDODGE 0x9299 #define GL_COLORBURN 0x929A #define GL_HARDLIGHT 0x929B #define GL_SOFTLIGHT 0x929C #define GL_DIFFERENCE 0x929E #define GL_EXCLUSION 0x92A0 #define GL_HSL_HUE 0x92AD #define GL_HSL_SATURATION 0x92AE #define GL_HSL_COLOR 0x92AF #define GL_HSL_LUMINOSITY 0x92B0 #define GL_PRIMITIVE_BOUNDING_BOX 0x92BE #define GL_COMPRESSED_RGBA_ASTC_4x4 0x93B0 #define GL_COMPRESSED_RGBA_ASTC_5x4 0x93B1 #define GL_COMPRESSED_RGBA_ASTC_5x5 0x93B2 #define GL_COMPRESSED_RGBA_ASTC_6x5 0x93B3 #define GL_COMPRESSED_RGBA_ASTC_6x6 0x93B4 #define GL_COMPRESSED_RGBA_ASTC_8x5 0x93B5 #define GL_COMPRESSED_RGBA_ASTC_8x6 0x93B6 #define GL_COMPRESSED_RGBA_ASTC_8x8 0x93B7 #define GL_COMPRESSED_RGBA_ASTC_10x5 0x93B8 #define GL_COMPRESSED_RGBA_ASTC_10x6 0x93B9 #define GL_COMPRESSED_RGBA_ASTC_10x8 0x93BA #define GL_COMPRESSED_RGBA_ASTC_10x10 0x93BB #define GL_COMPRESSED_RGBA_ASTC_12x10 0x93BC #define GL_COMPRESSED_RGBA_ASTC_12x12 0x93BD #define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4 0x93D0 #define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4 0x93D1 #define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5 0x93D2 #define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5 0x93D3 #define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6 0x93D4 #define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5 0x93D5 #define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6 0x93D6 #define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8 0x93D7 #define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5 0x93D8 #define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6 0x93D9 #define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8 0x93DA #define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10 0x93DB #define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10 0x93DC #define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12 0x93DD #ifndef GL_VERSION_1_0 #define GL_VERSION_1_0 1 GLAPI int GLAD_GL_VERSION_1_0; typedef void (APIENTRYP PFNGLCULLFACEPROC)(GLenum mode); GLAPI PFNGLCULLFACEPROC glad_glCullFace; #define glCullFace glad_glCullFace typedef void (APIENTRYP PFNGLFRONTFACEPROC)(GLenum mode); GLAPI PFNGLFRONTFACEPROC glad_glFrontFace; #define glFrontFace glad_glFrontFace typedef void (APIENTRYP PFNGLHINTPROC)(GLenum target, GLenum mode); GLAPI PFNGLHINTPROC glad_glHint; #define glHint glad_glHint typedef void (APIENTRYP PFNGLLINEWIDTHPROC)(GLfloat width); GLAPI PFNGLLINEWIDTHPROC glad_glLineWidth; #define glLineWidth glad_glLineWidth typedef void (APIENTRYP PFNGLPOINTSIZEPROC)(GLfloat size); GLAPI PFNGLPOINTSIZEPROC glad_glPointSize; #define glPointSize glad_glPointSize typedef void (APIENTRYP PFNGLPOLYGONMODEPROC)(GLenum face, GLenum mode); GLAPI PFNGLPOLYGONMODEPROC glad_glPolygonMode; #define glPolygonMode glad_glPolygonMode typedef void (APIENTRYP PFNGLSCISSORPROC)(GLint x, GLint y, GLsizei width, GLsizei height); GLAPI PFNGLSCISSORPROC glad_glScissor; #define glScissor glad_glScissor typedef void (APIENTRYP PFNGLTEXPARAMETERFPROC)(GLenum target, GLenum pname, GLfloat param); GLAPI PFNGLTEXPARAMETERFPROC glad_glTexParameterf; #define glTexParameterf glad_glTexParameterf typedef void (APIENTRYP PFNGLTEXPARAMETERFVPROC)(GLenum target, GLenum pname, const GLfloat *params); GLAPI PFNGLTEXPARAMETERFVPROC glad_glTexParameterfv; #define glTexParameterfv glad_glTexParameterfv typedef void (APIENTRYP PFNGLTEXPARAMETERIPROC)(GLenum target, GLenum pname, GLint param); GLAPI PFNGLTEXPARAMETERIPROC glad_glTexParameteri; #define glTexParameteri glad_glTexParameteri typedef void (APIENTRYP PFNGLTEXPARAMETERIVPROC)(GLenum target, GLenum pname, const GLint *params); GLAPI PFNGLTEXPARAMETERIVPROC glad_glTexParameteriv; #define glTexParameteriv glad_glTexParameteriv typedef void (APIENTRYP PFNGLTEXIMAGE1DPROC)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const void *pixels); GLAPI PFNGLTEXIMAGE1DPROC glad_glTexImage1D; #define glTexImage1D glad_glTexImage1D typedef void (APIENTRYP PFNGLTEXIMAGE2DPROC)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels); GLAPI PFNGLTEXIMAGE2DPROC glad_glTexImage2D; #define glTexImage2D glad_glTexImage2D typedef void (APIENTRYP PFNGLDRAWBUFFERPROC)(GLenum buf); GLAPI PFNGLDRAWBUFFERPROC glad_glDrawBuffer; #define glDrawBuffer glad_glDrawBuffer typedef void (APIENTRYP PFNGLCLEARPROC)(GLbitfield mask); GLAPI PFNGLCLEARPROC glad_glClear; #define glClear glad_glClear typedef void (APIENTRYP PFNGLCLEARCOLORPROC)(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); GLAPI PFNGLCLEARCOLORPROC glad_glClearColor; #define glClearColor glad_glClearColor typedef void (APIENTRYP PFNGLCLEARSTENCILPROC)(GLint s); GLAPI PFNGLCLEARSTENCILPROC glad_glClearStencil; #define glClearStencil glad_glClearStencil typedef void (APIENTRYP PFNGLCLEARDEPTHPROC)(GLdouble depth); GLAPI PFNGLCLEARDEPTHPROC glad_glClearDepth; #define glClearDepth glad_glClearDepth typedef void (APIENTRYP PFNGLSTENCILMASKPROC)(GLuint mask); GLAPI PFNGLSTENCILMASKPROC glad_glStencilMask; #define glStencilMask glad_glStencilMask typedef void (APIENTRYP PFNGLCOLORMASKPROC)(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha); GLAPI PFNGLCOLORMASKPROC glad_glColorMask; #define glColorMask glad_glColorMask typedef void (APIENTRYP PFNGLDEPTHMASKPROC)(GLboolean flag); GLAPI PFNGLDEPTHMASKPROC glad_glDepthMask; #define glDepthMask glad_glDepthMask typedef void (APIENTRYP PFNGLDISABLEPROC)(GLenum cap); GLAPI PFNGLDISABLEPROC glad_glDisable; #define glDisable glad_glDisable typedef void (APIENTRYP PFNGLENABLEPROC)(GLenum cap); GLAPI PFNGLENABLEPROC glad_glEnable; #define glEnable glad_glEnable typedef void (APIENTRYP PFNGLFINISHPROC)(void); GLAPI PFNGLFINISHPROC glad_glFinish; #define glFinish glad_glFinish typedef void (APIENTRYP PFNGLFLUSHPROC)(void); GLAPI PFNGLFLUSHPROC glad_glFlush; #define glFlush glad_glFlush typedef void (APIENTRYP PFNGLBLENDFUNCPROC)(GLenum sfactor, GLenum dfactor); GLAPI PFNGLBLENDFUNCPROC glad_glBlendFunc; #define glBlendFunc glad_glBlendFunc typedef void (APIENTRYP PFNGLLOGICOPPROC)(GLenum opcode); GLAPI PFNGLLOGICOPPROC glad_glLogicOp; #define glLogicOp glad_glLogicOp typedef void (APIENTRYP PFNGLSTENCILFUNCPROC)(GLenum func, GLint ref, GLuint mask); GLAPI PFNGLSTENCILFUNCPROC glad_glStencilFunc; #define glStencilFunc glad_glStencilFunc typedef void (APIENTRYP PFNGLSTENCILOPPROC)(GLenum fail, GLenum zfail, GLenum zpass); GLAPI PFNGLSTENCILOPPROC glad_glStencilOp; #define glStencilOp glad_glStencilOp typedef void (APIENTRYP PFNGLDEPTHFUNCPROC)(GLenum func); GLAPI PFNGLDEPTHFUNCPROC glad_glDepthFunc; #define glDepthFunc glad_glDepthFunc typedef void (APIENTRYP PFNGLPIXELSTOREFPROC)(GLenum pname, GLfloat param); GLAPI PFNGLPIXELSTOREFPROC glad_glPixelStoref; #define glPixelStoref glad_glPixelStoref typedef void (APIENTRYP PFNGLPIXELSTOREIPROC)(GLenum pname, GLint param); GLAPI PFNGLPIXELSTOREIPROC glad_glPixelStorei; #define glPixelStorei glad_glPixelStorei typedef void (APIENTRYP PFNGLREADBUFFERPROC)(GLenum src); GLAPI PFNGLREADBUFFERPROC glad_glReadBuffer; #define glReadBuffer glad_glReadBuffer typedef void (APIENTRYP PFNGLREADPIXELSPROC)(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void *pixels); GLAPI PFNGLREADPIXELSPROC glad_glReadPixels; #define glReadPixels glad_glReadPixels typedef void (APIENTRYP PFNGLGETBOOLEANVPROC)(GLenum pname, GLboolean *data); GLAPI PFNGLGETBOOLEANVPROC glad_glGetBooleanv; #define glGetBooleanv glad_glGetBooleanv typedef void (APIENTRYP PFNGLGETDOUBLEVPROC)(GLenum pname, GLdouble *data); GLAPI PFNGLGETDOUBLEVPROC glad_glGetDoublev; #define glGetDoublev glad_glGetDoublev typedef GLenum (APIENTRYP PFNGLGETERRORPROC)(void); GLAPI PFNGLGETERRORPROC glad_glGetError; #define glGetError glad_glGetError typedef void (APIENTRYP PFNGLGETFLOATVPROC)(GLenum pname, GLfloat *data); GLAPI PFNGLGETFLOATVPROC glad_glGetFloatv; #define glGetFloatv glad_glGetFloatv typedef void (APIENTRYP PFNGLGETINTEGERVPROC)(GLenum pname, GLint *data); GLAPI PFNGLGETINTEGERVPROC glad_glGetIntegerv; #define glGetIntegerv glad_glGetIntegerv typedef const GLubyte * (APIENTRYP PFNGLGETSTRINGPROC)(GLenum name); GLAPI PFNGLGETSTRINGPROC glad_glGetString; #define glGetString glad_glGetString typedef void (APIENTRYP PFNGLGETTEXIMAGEPROC)(GLenum target, GLint level, GLenum format, GLenum type, void *pixels); GLAPI PFNGLGETTEXIMAGEPROC glad_glGetTexImage; #define glGetTexImage glad_glGetTexImage typedef void (APIENTRYP PFNGLGETTEXPARAMETERFVPROC)(GLenum target, GLenum pname, GLfloat *params); GLAPI PFNGLGETTEXPARAMETERFVPROC glad_glGetTexParameterfv; #define glGetTexParameterfv glad_glGetTexParameterfv typedef void (APIENTRYP PFNGLGETTEXPARAMETERIVPROC)(GLenum target, GLenum pname, GLint *params); GLAPI PFNGLGETTEXPARAMETERIVPROC glad_glGetTexParameteriv; #define glGetTexParameteriv glad_glGetTexParameteriv typedef void (APIENTRYP PFNGLGETTEXLEVELPARAMETERFVPROC)(GLenum target, GLint level, GLenum pname, GLfloat *params); GLAPI PFNGLGETTEXLEVELPARAMETERFVPROC glad_glGetTexLevelParameterfv; #define glGetTexLevelParameterfv glad_glGetTexLevelParameterfv typedef void (APIENTRYP PFNGLGETTEXLEVELPARAMETERIVPROC)(GLenum target, GLint level, GLenum pname, GLint *params); GLAPI PFNGLGETTEXLEVELPARAMETERIVPROC glad_glGetTexLevelParameteriv; #define glGetTexLevelParameteriv glad_glGetTexLevelParameteriv typedef GLboolean (APIENTRYP PFNGLISENABLEDPROC)(GLenum cap); GLAPI PFNGLISENABLEDPROC glad_glIsEnabled; #define glIsEnabled glad_glIsEnabled typedef void (APIENTRYP PFNGLDEPTHRANGEPROC)(GLdouble n, GLdouble f); GLAPI PFNGLDEPTHRANGEPROC glad_glDepthRange; #define glDepthRange glad_glDepthRange typedef void (APIENTRYP PFNGLVIEWPORTPROC)(GLint x, GLint y, GLsizei width, GLsizei height); GLAPI PFNGLVIEWPORTPROC glad_glViewport; #define glViewport glad_glViewport typedef void (APIENTRYP PFNGLNEWLISTPROC)(GLuint list, GLenum mode); GLAPI PFNGLNEWLISTPROC glad_glNewList; #define glNewList glad_glNewList typedef void (APIENTRYP PFNGLENDLISTPROC)(void); GLAPI PFNGLENDLISTPROC glad_glEndList; #define glEndList glad_glEndList typedef void (APIENTRYP PFNGLCALLLISTPROC)(GLuint list); GLAPI PFNGLCALLLISTPROC glad_glCallList; #define glCallList glad_glCallList typedef void (APIENTRYP PFNGLCALLLISTSPROC)(GLsizei n, GLenum type, const void *lists); GLAPI PFNGLCALLLISTSPROC glad_glCallLists; #define glCallLists glad_glCallLists typedef void (APIENTRYP PFNGLDELETELISTSPROC)(GLuint list, GLsizei range); GLAPI PFNGLDELETELISTSPROC glad_glDeleteLists; #define glDeleteLists glad_glDeleteLists typedef GLuint (APIENTRYP PFNGLGENLISTSPROC)(GLsizei range); GLAPI PFNGLGENLISTSPROC glad_glGenLists; #define glGenLists glad_glGenLists typedef void (APIENTRYP PFNGLLISTBASEPROC)(GLuint base); GLAPI PFNGLLISTBASEPROC glad_glListBase; #define glListBase glad_glListBase typedef void (APIENTRYP PFNGLBEGINPROC)(GLenum mode); GLAPI PFNGLBEGINPROC glad_glBegin; #define glBegin glad_glBegin typedef void (APIENTRYP PFNGLBITMAPPROC)(GLsizei width, GLsizei height, GLfloat xorig, GLfloat yorig, GLfloat xmove, GLfloat ymove, const GLubyte *bitmap); GLAPI PFNGLBITMAPPROC glad_glBitmap; #define glBitmap glad_glBitmap typedef void (APIENTRYP PFNGLCOLOR3BPROC)(GLbyte red, GLbyte green, GLbyte blue); GLAPI PFNGLCOLOR3BPROC glad_glColor3b; #define glColor3b glad_glColor3b typedef void (APIENTRYP PFNGLCOLOR3BVPROC)(const GLbyte *v); GLAPI PFNGLCOLOR3BVPROC glad_glColor3bv; #define glColor3bv glad_glColor3bv typedef void (APIENTRYP PFNGLCOLOR3DPROC)(GLdouble red, GLdouble green, GLdouble blue); GLAPI PFNGLCOLOR3DPROC glad_glColor3d; #define glColor3d glad_glColor3d typedef void (APIENTRYP PFNGLCOLOR3DVPROC)(const GLdouble *v); GLAPI PFNGLCOLOR3DVPROC glad_glColor3dv; #define glColor3dv glad_glColor3dv typedef void (APIENTRYP PFNGLCOLOR3FPROC)(GLfloat red, GLfloat green, GLfloat blue); GLAPI PFNGLCOLOR3FPROC glad_glColor3f; #define glColor3f glad_glColor3f typedef void (APIENTRYP PFNGLCOLOR3FVPROC)(const GLfloat *v); GLAPI PFNGLCOLOR3FVPROC glad_glColor3fv; #define glColor3fv glad_glColor3fv typedef void (APIENTRYP PFNGLCOLOR3IPROC)(GLint red, GLint green, GLint blue); GLAPI PFNGLCOLOR3IPROC glad_glColor3i; #define glColor3i glad_glColor3i typedef void (APIENTRYP PFNGLCOLOR3IVPROC)(const GLint *v); GLAPI PFNGLCOLOR3IVPROC glad_glColor3iv; #define glColor3iv glad_glColor3iv typedef void (APIENTRYP PFNGLCOLOR3SPROC)(GLshort red, GLshort green, GLshort blue); GLAPI PFNGLCOLOR3SPROC glad_glColor3s; #define glColor3s glad_glColor3s typedef void (APIENTRYP PFNGLCOLOR3SVPROC)(const GLshort *v); GLAPI PFNGLCOLOR3SVPROC glad_glColor3sv; #define glColor3sv glad_glColor3sv typedef void (APIENTRYP PFNGLCOLOR3UBPROC)(GLubyte red, GLubyte green, GLubyte blue); GLAPI PFNGLCOLOR3UBPROC glad_glColor3ub; #define glColor3ub glad_glColor3ub typedef void (APIENTRYP PFNGLCOLOR3UBVPROC)(const GLubyte *v); GLAPI PFNGLCOLOR3UBVPROC glad_glColor3ubv; #define glColor3ubv glad_glColor3ubv typedef void (APIENTRYP PFNGLCOLOR3UIPROC)(GLuint red, GLuint green, GLuint blue); GLAPI PFNGLCOLOR3UIPROC glad_glColor3ui; #define glColor3ui glad_glColor3ui typedef void (APIENTRYP PFNGLCOLOR3UIVPROC)(const GLuint *v); GLAPI PFNGLCOLOR3UIVPROC glad_glColor3uiv; #define glColor3uiv glad_glColor3uiv typedef void (APIENTRYP PFNGLCOLOR3USPROC)(GLushort red, GLushort green, GLushort blue); GLAPI PFNGLCOLOR3USPROC glad_glColor3us; #define glColor3us glad_glColor3us typedef void (APIENTRYP PFNGLCOLOR3USVPROC)(const GLushort *v); GLAPI PFNGLCOLOR3USVPROC glad_glColor3usv; #define glColor3usv glad_glColor3usv typedef void (APIENTRYP PFNGLCOLOR4BPROC)(GLbyte red, GLbyte green, GLbyte blue, GLbyte alpha); GLAPI PFNGLCOLOR4BPROC glad_glColor4b; #define glColor4b glad_glColor4b typedef void (APIENTRYP PFNGLCOLOR4BVPROC)(const GLbyte *v); GLAPI PFNGLCOLOR4BVPROC glad_glColor4bv; #define glColor4bv glad_glColor4bv typedef void (APIENTRYP PFNGLCOLOR4DPROC)(GLdouble red, GLdouble green, GLdouble blue, GLdouble alpha); GLAPI PFNGLCOLOR4DPROC glad_glColor4d; #define glColor4d glad_glColor4d typedef void (APIENTRYP PFNGLCOLOR4DVPROC)(const GLdouble *v); GLAPI PFNGLCOLOR4DVPROC glad_glColor4dv; #define glColor4dv glad_glColor4dv typedef void (APIENTRYP PFNGLCOLOR4FPROC)(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); GLAPI PFNGLCOLOR4FPROC glad_glColor4f; #define glColor4f glad_glColor4f typedef void (APIENTRYP PFNGLCOLOR4FVPROC)(const GLfloat *v); GLAPI PFNGLCOLOR4FVPROC glad_glColor4fv; #define glColor4fv glad_glColor4fv typedef void (APIENTRYP PFNGLCOLOR4IPROC)(GLint red, GLint green, GLint blue, GLint alpha); GLAPI PFNGLCOLOR4IPROC glad_glColor4i; #define glColor4i glad_glColor4i typedef void (APIENTRYP PFNGLCOLOR4IVPROC)(const GLint *v); GLAPI PFNGLCOLOR4IVPROC glad_glColor4iv; #define glColor4iv glad_glColor4iv typedef void (APIENTRYP PFNGLCOLOR4SPROC)(GLshort red, GLshort green, GLshort blue, GLshort alpha); GLAPI PFNGLCOLOR4SPROC glad_glColor4s; #define glColor4s glad_glColor4s typedef void (APIENTRYP PFNGLCOLOR4SVPROC)(const GLshort *v); GLAPI PFNGLCOLOR4SVPROC glad_glColor4sv; #define glColor4sv glad_glColor4sv typedef void (APIENTRYP PFNGLCOLOR4UBPROC)(GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha); GLAPI PFNGLCOLOR4UBPROC glad_glColor4ub; #define glColor4ub glad_glColor4ub typedef void (APIENTRYP PFNGLCOLOR4UBVPROC)(const GLubyte *v); GLAPI PFNGLCOLOR4UBVPROC glad_glColor4ubv; #define glColor4ubv glad_glColor4ubv typedef void (APIENTRYP PFNGLCOLOR4UIPROC)(GLuint red, GLuint green, GLuint blue, GLuint alpha); GLAPI PFNGLCOLOR4UIPROC glad_glColor4ui; #define glColor4ui glad_glColor4ui typedef void (APIENTRYP PFNGLCOLOR4UIVPROC)(const GLuint *v); GLAPI PFNGLCOLOR4UIVPROC glad_glColor4uiv; #define glColor4uiv glad_glColor4uiv typedef void (APIENTRYP PFNGLCOLOR4USPROC)(GLushort red, GLushort green, GLushort blue, GLushort alpha); GLAPI PFNGLCOLOR4USPROC glad_glColor4us; #define glColor4us glad_glColor4us typedef void (APIENTRYP PFNGLCOLOR4USVPROC)(const GLushort *v); GLAPI PFNGLCOLOR4USVPROC glad_glColor4usv; #define glColor4usv glad_glColor4usv typedef void (APIENTRYP PFNGLEDGEFLAGPROC)(GLboolean flag); GLAPI PFNGLEDGEFLAGPROC glad_glEdgeFlag; #define glEdgeFlag glad_glEdgeFlag typedef void (APIENTRYP PFNGLEDGEFLAGVPROC)(const GLboolean *flag); GLAPI PFNGLEDGEFLAGVPROC glad_glEdgeFlagv; #define glEdgeFlagv glad_glEdgeFlagv typedef void (APIENTRYP PFNGLENDPROC)(void); GLAPI PFNGLENDPROC glad_glEnd; #define glEnd glad_glEnd typedef void (APIENTRYP PFNGLINDEXDPROC)(GLdouble c); GLAPI PFNGLINDEXDPROC glad_glIndexd; #define glIndexd glad_glIndexd typedef void (APIENTRYP PFNGLINDEXDVPROC)(const GLdouble *c); GLAPI PFNGLINDEXDVPROC glad_glIndexdv; #define glIndexdv glad_glIndexdv typedef void (APIENTRYP PFNGLINDEXFPROC)(GLfloat c); GLAPI PFNGLINDEXFPROC glad_glIndexf; #define glIndexf glad_glIndexf typedef void (APIENTRYP PFNGLINDEXFVPROC)(const GLfloat *c); GLAPI PFNGLINDEXFVPROC glad_glIndexfv; #define glIndexfv glad_glIndexfv typedef void (APIENTRYP PFNGLINDEXIPROC)(GLint c); GLAPI PFNGLINDEXIPROC glad_glIndexi; #define glIndexi glad_glIndexi typedef void (APIENTRYP PFNGLINDEXIVPROC)(const GLint *c); GLAPI PFNGLINDEXIVPROC glad_glIndexiv; #define glIndexiv glad_glIndexiv typedef void (APIENTRYP PFNGLINDEXSPROC)(GLshort c); GLAPI PFNGLINDEXSPROC glad_glIndexs; #define glIndexs glad_glIndexs typedef void (APIENTRYP PFNGLINDEXSVPROC)(const GLshort *c); GLAPI PFNGLINDEXSVPROC glad_glIndexsv; #define glIndexsv glad_glIndexsv typedef void (APIENTRYP PFNGLNORMAL3BPROC)(GLbyte nx, GLbyte ny, GLbyte nz); GLAPI PFNGLNORMAL3BPROC glad_glNormal3b; #define glNormal3b glad_glNormal3b typedef void (APIENTRYP PFNGLNORMAL3BVPROC)(const GLbyte *v); GLAPI PFNGLNORMAL3BVPROC glad_glNormal3bv; #define glNormal3bv glad_glNormal3bv typedef void (APIENTRYP PFNGLNORMAL3DPROC)(GLdouble nx, GLdouble ny, GLdouble nz); GLAPI PFNGLNORMAL3DPROC glad_glNormal3d; #define glNormal3d glad_glNormal3d typedef void (APIENTRYP PFNGLNORMAL3DVPROC)(const GLdouble *v); GLAPI PFNGLNORMAL3DVPROC glad_glNormal3dv; #define glNormal3dv glad_glNormal3dv typedef void (APIENTRYP PFNGLNORMAL3FPROC)(GLfloat nx, GLfloat ny, GLfloat nz); GLAPI PFNGLNORMAL3FPROC glad_glNormal3f; #define glNormal3f glad_glNormal3f typedef void (APIENTRYP PFNGLNORMAL3FVPROC)(const GLfloat *v); GLAPI PFNGLNORMAL3FVPROC glad_glNormal3fv; #define glNormal3fv glad_glNormal3fv typedef void (APIENTRYP PFNGLNORMAL3IPROC)(GLint nx, GLint ny, GLint nz); GLAPI PFNGLNORMAL3IPROC glad_glNormal3i; #define glNormal3i glad_glNormal3i typedef void (APIENTRYP PFNGLNORMAL3IVPROC)(const GLint *v); GLAPI PFNGLNORMAL3IVPROC glad_glNormal3iv; #define glNormal3iv glad_glNormal3iv typedef void (APIENTRYP PFNGLNORMAL3SPROC)(GLshort nx, GLshort ny, GLshort nz); GLAPI PFNGLNORMAL3SPROC glad_glNormal3s; #define glNormal3s glad_glNormal3s typedef void (APIENTRYP PFNGLNORMAL3SVPROC)(const GLshort *v); GLAPI PFNGLNORMAL3SVPROC glad_glNormal3sv; #define glNormal3sv glad_glNormal3sv typedef void (APIENTRYP PFNGLRASTERPOS2DPROC)(GLdouble x, GLdouble y); GLAPI PFNGLRASTERPOS2DPROC glad_glRasterPos2d; #define glRasterPos2d glad_glRasterPos2d typedef void (APIENTRYP PFNGLRASTERPOS2DVPROC)(const GLdouble *v); GLAPI PFNGLRASTERPOS2DVPROC glad_glRasterPos2dv; #define glRasterPos2dv glad_glRasterPos2dv typedef void (APIENTRYP PFNGLRASTERPOS2FPROC)(GLfloat x, GLfloat y); GLAPI PFNGLRASTERPOS2FPROC glad_glRasterPos2f; #define glRasterPos2f glad_glRasterPos2f typedef void (APIENTRYP PFNGLRASTERPOS2FVPROC)(const GLfloat *v); GLAPI PFNGLRASTERPOS2FVPROC glad_glRasterPos2fv; #define glRasterPos2fv glad_glRasterPos2fv typedef void (APIENTRYP PFNGLRASTERPOS2IPROC)(GLint x, GLint y); GLAPI PFNGLRASTERPOS2IPROC glad_glRasterPos2i; #define glRasterPos2i glad_glRasterPos2i typedef void (APIENTRYP PFNGLRASTERPOS2IVPROC)(const GLint *v); GLAPI PFNGLRASTERPOS2IVPROC glad_glRasterPos2iv; #define glRasterPos2iv glad_glRasterPos2iv typedef void (APIENTRYP PFNGLRASTERPOS2SPROC)(GLshort x, GLshort y); GLAPI PFNGLRASTERPOS2SPROC glad_glRasterPos2s; #define glRasterPos2s glad_glRasterPos2s typedef void (APIENTRYP PFNGLRASTERPOS2SVPROC)(const GLshort *v); GLAPI PFNGLRASTERPOS2SVPROC glad_glRasterPos2sv; #define glRasterPos2sv glad_glRasterPos2sv typedef void (APIENTRYP PFNGLRASTERPOS3DPROC)(GLdouble x, GLdouble y, GLdouble z); GLAPI PFNGLRASTERPOS3DPROC glad_glRasterPos3d; #define glRasterPos3d glad_glRasterPos3d typedef void (APIENTRYP PFNGLRASTERPOS3DVPROC)(const GLdouble *v); GLAPI PFNGLRASTERPOS3DVPROC glad_glRasterPos3dv; #define glRasterPos3dv glad_glRasterPos3dv typedef void (APIENTRYP PFNGLRASTERPOS3FPROC)(GLfloat x, GLfloat y, GLfloat z); GLAPI PFNGLRASTERPOS3FPROC glad_glRasterPos3f; #define glRasterPos3f glad_glRasterPos3f typedef void (APIENTRYP PFNGLRASTERPOS3FVPROC)(const GLfloat *v); GLAPI PFNGLRASTERPOS3FVPROC glad_glRasterPos3fv; #define glRasterPos3fv glad_glRasterPos3fv typedef void (APIENTRYP PFNGLRASTERPOS3IPROC)(GLint x, GLint y, GLint z); GLAPI PFNGLRASTERPOS3IPROC glad_glRasterPos3i; #define glRasterPos3i glad_glRasterPos3i typedef void (APIENTRYP PFNGLRASTERPOS3IVPROC)(const GLint *v); GLAPI PFNGLRASTERPOS3IVPROC glad_glRasterPos3iv; #define glRasterPos3iv glad_glRasterPos3iv typedef void (APIENTRYP PFNGLRASTERPOS3SPROC)(GLshort x, GLshort y, GLshort z); GLAPI PFNGLRASTERPOS3SPROC glad_glRasterPos3s; #define glRasterPos3s glad_glRasterPos3s typedef void (APIENTRYP PFNGLRASTERPOS3SVPROC)(const GLshort *v); GLAPI PFNGLRASTERPOS3SVPROC glad_glRasterPos3sv; #define glRasterPos3sv glad_glRasterPos3sv typedef void (APIENTRYP PFNGLRASTERPOS4DPROC)(GLdouble x, GLdouble y, GLdouble z, GLdouble w); GLAPI PFNGLRASTERPOS4DPROC glad_glRasterPos4d; #define glRasterPos4d glad_glRasterPos4d typedef void (APIENTRYP PFNGLRASTERPOS4DVPROC)(const GLdouble *v); GLAPI PFNGLRASTERPOS4DVPROC glad_glRasterPos4dv; #define glRasterPos4dv glad_glRasterPos4dv typedef void (APIENTRYP PFNGLRASTERPOS4FPROC)(GLfloat x, GLfloat y, GLfloat z, GLfloat w); GLAPI PFNGLRASTERPOS4FPROC glad_glRasterPos4f; #define glRasterPos4f glad_glRasterPos4f typedef void (APIENTRYP PFNGLRASTERPOS4FVPROC)(const GLfloat *v); GLAPI PFNGLRASTERPOS4FVPROC glad_glRasterPos4fv; #define glRasterPos4fv glad_glRasterPos4fv typedef void (APIENTRYP PFNGLRASTERPOS4IPROC)(GLint x, GLint y, GLint z, GLint w); GLAPI PFNGLRASTERPOS4IPROC glad_glRasterPos4i; #define glRasterPos4i glad_glRasterPos4i typedef void (APIENTRYP PFNGLRASTERPOS4IVPROC)(const GLint *v); GLAPI PFNGLRASTERPOS4IVPROC glad_glRasterPos4iv; #define glRasterPos4iv glad_glRasterPos4iv typedef void (APIENTRYP PFNGLRASTERPOS4SPROC)(GLshort x, GLshort y, GLshort z, GLshort w); GLAPI PFNGLRASTERPOS4SPROC glad_glRasterPos4s; #define glRasterPos4s glad_glRasterPos4s typedef void (APIENTRYP PFNGLRASTERPOS4SVPROC)(const GLshort *v); GLAPI PFNGLRASTERPOS4SVPROC glad_glRasterPos4sv; #define glRasterPos4sv glad_glRasterPos4sv typedef void (APIENTRYP PFNGLRECTDPROC)(GLdouble x1, GLdouble y1, GLdouble x2, GLdouble y2); GLAPI PFNGLRECTDPROC glad_glRectd; #define glRectd glad_glRectd typedef void (APIENTRYP PFNGLRECTDVPROC)(const GLdouble *v1, const GLdouble *v2); GLAPI PFNGLRECTDVPROC glad_glRectdv; #define glRectdv glad_glRectdv typedef void (APIENTRYP PFNGLRECTFPROC)(GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2); GLAPI PFNGLRECTFPROC glad_glRectf; #define glRectf glad_glRectf typedef void (APIENTRYP PFNGLRECTFVPROC)(const GLfloat *v1, const GLfloat *v2); GLAPI PFNGLRECTFVPROC glad_glRectfv; #define glRectfv glad_glRectfv typedef void (APIENTRYP PFNGLRECTIPROC)(GLint x1, GLint y1, GLint x2, GLint y2); GLAPI PFNGLRECTIPROC glad_glRecti; #define glRecti glad_glRecti typedef void (APIENTRYP PFNGLRECTIVPROC)(const GLint *v1, const GLint *v2); GLAPI PFNGLRECTIVPROC glad_glRectiv; #define glRectiv glad_glRectiv typedef void (APIENTRYP PFNGLRECTSPROC)(GLshort x1, GLshort y1, GLshort x2, GLshort y2); GLAPI PFNGLRECTSPROC glad_glRects; #define glRects glad_glRects typedef void (APIENTRYP PFNGLRECTSVPROC)(const GLshort *v1, const GLshort *v2); GLAPI PFNGLRECTSVPROC glad_glRectsv; #define glRectsv glad_glRectsv typedef void (APIENTRYP PFNGLTEXCOORD1DPROC)(GLdouble s); GLAPI PFNGLTEXCOORD1DPROC glad_glTexCoord1d; #define glTexCoord1d glad_glTexCoord1d typedef void (APIENTRYP PFNGLTEXCOORD1DVPROC)(const GLdouble *v); GLAPI PFNGLTEXCOORD1DVPROC glad_glTexCoord1dv; #define glTexCoord1dv glad_glTexCoord1dv typedef void (APIENTRYP PFNGLTEXCOORD1FPROC)(GLfloat s); GLAPI PFNGLTEXCOORD1FPROC glad_glTexCoord1f; #define glTexCoord1f glad_glTexCoord1f typedef void (APIENTRYP PFNGLTEXCOORD1FVPROC)(const GLfloat *v); GLAPI PFNGLTEXCOORD1FVPROC glad_glTexCoord1fv; #define glTexCoord1fv glad_glTexCoord1fv typedef void (APIENTRYP PFNGLTEXCOORD1IPROC)(GLint s); GLAPI PFNGLTEXCOORD1IPROC glad_glTexCoord1i; #define glTexCoord1i glad_glTexCoord1i typedef void (APIENTRYP PFNGLTEXCOORD1IVPROC)(const GLint *v); GLAPI PFNGLTEXCOORD1IVPROC glad_glTexCoord1iv; #define glTexCoord1iv glad_glTexCoord1iv typedef void (APIENTRYP PFNGLTEXCOORD1SPROC)(GLshort s); GLAPI PFNGLTEXCOORD1SPROC glad_glTexCoord1s; #define glTexCoord1s glad_glTexCoord1s typedef void (APIENTRYP PFNGLTEXCOORD1SVPROC)(const GLshort *v); GLAPI PFNGLTEXCOORD1SVPROC glad_glTexCoord1sv; #define glTexCoord1sv glad_glTexCoord1sv typedef void (APIENTRYP PFNGLTEXCOORD2DPROC)(GLdouble s, GLdouble t); GLAPI PFNGLTEXCOORD2DPROC glad_glTexCoord2d; #define glTexCoord2d glad_glTexCoord2d typedef void (APIENTRYP PFNGLTEXCOORD2DVPROC)(const GLdouble *v); GLAPI PFNGLTEXCOORD2DVPROC glad_glTexCoord2dv; #define glTexCoord2dv glad_glTexCoord2dv typedef void (APIENTRYP PFNGLTEXCOORD2FPROC)(GLfloat s, GLfloat t); GLAPI PFNGLTEXCOORD2FPROC glad_glTexCoord2f; #define glTexCoord2f glad_glTexCoord2f typedef void (APIENTRYP PFNGLTEXCOORD2FVPROC)(const GLfloat *v); GLAPI PFNGLTEXCOORD2FVPROC glad_glTexCoord2fv; #define glTexCoord2fv glad_glTexCoord2fv typedef void (APIENTRYP PFNGLTEXCOORD2IPROC)(GLint s, GLint t); GLAPI PFNGLTEXCOORD2IPROC glad_glTexCoord2i; #define glTexCoord2i glad_glTexCoord2i typedef void (APIENTRYP PFNGLTEXCOORD2IVPROC)(const GLint *v); GLAPI PFNGLTEXCOORD2IVPROC glad_glTexCoord2iv; #define glTexCoord2iv glad_glTexCoord2iv typedef void (APIENTRYP PFNGLTEXCOORD2SPROC)(GLshort s, GLshort t); GLAPI PFNGLTEXCOORD2SPROC glad_glTexCoord2s; #define glTexCoord2s glad_glTexCoord2s typedef void (APIENTRYP PFNGLTEXCOORD2SVPROC)(const GLshort *v); GLAPI PFNGLTEXCOORD2SVPROC glad_glTexCoord2sv; #define glTexCoord2sv glad_glTexCoord2sv typedef void (APIENTRYP PFNGLTEXCOORD3DPROC)(GLdouble s, GLdouble t, GLdouble r); GLAPI PFNGLTEXCOORD3DPROC glad_glTexCoord3d; #define glTexCoord3d glad_glTexCoord3d typedef void (APIENTRYP PFNGLTEXCOORD3DVPROC)(const GLdouble *v); GLAPI PFNGLTEXCOORD3DVPROC glad_glTexCoord3dv; #define glTexCoord3dv glad_glTexCoord3dv typedef void (APIENTRYP PFNGLTEXCOORD3FPROC)(GLfloat s, GLfloat t, GLfloat r); GLAPI PFNGLTEXCOORD3FPROC glad_glTexCoord3f; #define glTexCoord3f glad_glTexCoord3f typedef void (APIENTRYP PFNGLTEXCOORD3FVPROC)(const GLfloat *v); GLAPI PFNGLTEXCOORD3FVPROC glad_glTexCoord3fv; #define glTexCoord3fv glad_glTexCoord3fv typedef void (APIENTRYP PFNGLTEXCOORD3IPROC)(GLint s, GLint t, GLint r); GLAPI PFNGLTEXCOORD3IPROC glad_glTexCoord3i; #define glTexCoord3i glad_glTexCoord3i typedef void (APIENTRYP PFNGLTEXCOORD3IVPROC)(const GLint *v); GLAPI PFNGLTEXCOORD3IVPROC glad_glTexCoord3iv; #define glTexCoord3iv glad_glTexCoord3iv typedef void (APIENTRYP PFNGLTEXCOORD3SPROC)(GLshort s, GLshort t, GLshort r); GLAPI PFNGLTEXCOORD3SPROC glad_glTexCoord3s; #define glTexCoord3s glad_glTexCoord3s typedef void (APIENTRYP PFNGLTEXCOORD3SVPROC)(const GLshort *v); GLAPI PFNGLTEXCOORD3SVPROC glad_glTexCoord3sv; #define glTexCoord3sv glad_glTexCoord3sv typedef void (APIENTRYP PFNGLTEXCOORD4DPROC)(GLdouble s, GLdouble t, GLdouble r, GLdouble q); GLAPI PFNGLTEXCOORD4DPROC glad_glTexCoord4d; #define glTexCoord4d glad_glTexCoord4d typedef void (APIENTRYP PFNGLTEXCOORD4DVPROC)(const GLdouble *v); GLAPI PFNGLTEXCOORD4DVPROC glad_glTexCoord4dv; #define glTexCoord4dv glad_glTexCoord4dv typedef void (APIENTRYP PFNGLTEXCOORD4FPROC)(GLfloat s, GLfloat t, GLfloat r, GLfloat q); GLAPI PFNGLTEXCOORD4FPROC glad_glTexCoord4f; #define glTexCoord4f glad_glTexCoord4f typedef void (APIENTRYP PFNGLTEXCOORD4FVPROC)(const GLfloat *v); GLAPI PFNGLTEXCOORD4FVPROC glad_glTexCoord4fv; #define glTexCoord4fv glad_glTexCoord4fv typedef void (APIENTRYP PFNGLTEXCOORD4IPROC)(GLint s, GLint t, GLint r, GLint q); GLAPI PFNGLTEXCOORD4IPROC glad_glTexCoord4i; #define glTexCoord4i glad_glTexCoord4i typedef void (APIENTRYP PFNGLTEXCOORD4IVPROC)(const GLint *v); GLAPI PFNGLTEXCOORD4IVPROC glad_glTexCoord4iv; #define glTexCoord4iv glad_glTexCoord4iv typedef void (APIENTRYP PFNGLTEXCOORD4SPROC)(GLshort s, GLshort t, GLshort r, GLshort q); GLAPI PFNGLTEXCOORD4SPROC glad_glTexCoord4s; #define glTexCoord4s glad_glTexCoord4s typedef void (APIENTRYP PFNGLTEXCOORD4SVPROC)(const GLshort *v); GLAPI PFNGLTEXCOORD4SVPROC glad_glTexCoord4sv; #define glTexCoord4sv glad_glTexCoord4sv typedef void (APIENTRYP PFNGLVERTEX2DPROC)(GLdouble x, GLdouble y); GLAPI PFNGLVERTEX2DPROC glad_glVertex2d; #define glVertex2d glad_glVertex2d typedef void (APIENTRYP PFNGLVERTEX2DVPROC)(const GLdouble *v); GLAPI PFNGLVERTEX2DVPROC glad_glVertex2dv; #define glVertex2dv glad_glVertex2dv typedef void (APIENTRYP PFNGLVERTEX2FPROC)(GLfloat x, GLfloat y); GLAPI PFNGLVERTEX2FPROC glad_glVertex2f; #define glVertex2f glad_glVertex2f typedef void (APIENTRYP PFNGLVERTEX2FVPROC)(const GLfloat *v); GLAPI PFNGLVERTEX2FVPROC glad_glVertex2fv; #define glVertex2fv glad_glVertex2fv typedef void (APIENTRYP PFNGLVERTEX2IPROC)(GLint x, GLint y); GLAPI PFNGLVERTEX2IPROC glad_glVertex2i; #define glVertex2i glad_glVertex2i typedef void (APIENTRYP PFNGLVERTEX2IVPROC)(const GLint *v); GLAPI PFNGLVERTEX2IVPROC glad_glVertex2iv; #define glVertex2iv glad_glVertex2iv typedef void (APIENTRYP PFNGLVERTEX2SPROC)(GLshort x, GLshort y); GLAPI PFNGLVERTEX2SPROC glad_glVertex2s; #define glVertex2s glad_glVertex2s typedef void (APIENTRYP PFNGLVERTEX2SVPROC)(const GLshort *v); GLAPI PFNGLVERTEX2SVPROC glad_glVertex2sv; #define glVertex2sv glad_glVertex2sv typedef void (APIENTRYP PFNGLVERTEX3DPROC)(GLdouble x, GLdouble y, GLdouble z); GLAPI PFNGLVERTEX3DPROC glad_glVertex3d; #define glVertex3d glad_glVertex3d typedef void (APIENTRYP PFNGLVERTEX3DVPROC)(const GLdouble *v); GLAPI PFNGLVERTEX3DVPROC glad_glVertex3dv; #define glVertex3dv glad_glVertex3dv typedef void (APIENTRYP PFNGLVERTEX3FPROC)(GLfloat x, GLfloat y, GLfloat z); GLAPI PFNGLVERTEX3FPROC glad_glVertex3f; #define glVertex3f glad_glVertex3f typedef void (APIENTRYP PFNGLVERTEX3FVPROC)(const GLfloat *v); GLAPI PFNGLVERTEX3FVPROC glad_glVertex3fv; #define glVertex3fv glad_glVertex3fv typedef void (APIENTRYP PFNGLVERTEX3IPROC)(GLint x, GLint y, GLint z); GLAPI PFNGLVERTEX3IPROC glad_glVertex3i; #define glVertex3i glad_glVertex3i typedef void (APIENTRYP PFNGLVERTEX3IVPROC)(const GLint *v); GLAPI PFNGLVERTEX3IVPROC glad_glVertex3iv; #define glVertex3iv glad_glVertex3iv typedef void (APIENTRYP PFNGLVERTEX3SPROC)(GLshort x, GLshort y, GLshort z); GLAPI PFNGLVERTEX3SPROC glad_glVertex3s; #define glVertex3s glad_glVertex3s typedef void (APIENTRYP PFNGLVERTEX3SVPROC)(const GLshort *v); GLAPI PFNGLVERTEX3SVPROC glad_glVertex3sv; #define glVertex3sv glad_glVertex3sv typedef void (APIENTRYP PFNGLVERTEX4DPROC)(GLdouble x, GLdouble y, GLdouble z, GLdouble w); GLAPI PFNGLVERTEX4DPROC glad_glVertex4d; #define glVertex4d glad_glVertex4d typedef void (APIENTRYP PFNGLVERTEX4DVPROC)(const GLdouble *v); GLAPI PFNGLVERTEX4DVPROC glad_glVertex4dv; #define glVertex4dv glad_glVertex4dv typedef void (APIENTRYP PFNGLVERTEX4FPROC)(GLfloat x, GLfloat y, GLfloat z, GLfloat w); GLAPI PFNGLVERTEX4FPROC glad_glVertex4f; #define glVertex4f glad_glVertex4f typedef void (APIENTRYP PFNGLVERTEX4FVPROC)(const GLfloat *v); GLAPI PFNGLVERTEX4FVPROC glad_glVertex4fv; #define glVertex4fv glad_glVertex4fv typedef void (APIENTRYP PFNGLVERTEX4IPROC)(GLint x, GLint y, GLint z, GLint w); GLAPI PFNGLVERTEX4IPROC glad_glVertex4i; #define glVertex4i glad_glVertex4i typedef void (APIENTRYP PFNGLVERTEX4IVPROC)(const GLint *v); GLAPI PFNGLVERTEX4IVPROC glad_glVertex4iv; #define glVertex4iv glad_glVertex4iv typedef void (APIENTRYP PFNGLVERTEX4SPROC)(GLshort x, GLshort y, GLshort z, GLshort w); GLAPI PFNGLVERTEX4SPROC glad_glVertex4s; #define glVertex4s glad_glVertex4s typedef void (APIENTRYP PFNGLVERTEX4SVPROC)(const GLshort *v); GLAPI PFNGLVERTEX4SVPROC glad_glVertex4sv; #define glVertex4sv glad_glVertex4sv typedef void (APIENTRYP PFNGLCLIPPLANEPROC)(GLenum plane, const GLdouble *equation); GLAPI PFNGLCLIPPLANEPROC glad_glClipPlane; #define glClipPlane glad_glClipPlane typedef void (APIENTRYP PFNGLCOLORMATERIALPROC)(GLenum face, GLenum mode); GLAPI PFNGLCOLORMATERIALPROC glad_glColorMaterial; #define glColorMaterial glad_glColorMaterial typedef void (APIENTRYP PFNGLFOGFPROC)(GLenum pname, GLfloat param); GLAPI PFNGLFOGFPROC glad_glFogf; #define glFogf glad_glFogf typedef void (APIENTRYP PFNGLFOGFVPROC)(GLenum pname, const GLfloat *params); GLAPI PFNGLFOGFVPROC glad_glFogfv; #define glFogfv glad_glFogfv typedef void (APIENTRYP PFNGLFOGIPROC)(GLenum pname, GLint param); GLAPI PFNGLFOGIPROC glad_glFogi; #define glFogi glad_glFogi typedef void (APIENTRYP PFNGLFOGIVPROC)(GLenum pname, const GLint *params); GLAPI PFNGLFOGIVPROC glad_glFogiv; #define glFogiv glad_glFogiv typedef void (APIENTRYP PFNGLLIGHTFPROC)(GLenum light, GLenum pname, GLfloat param); GLAPI PFNGLLIGHTFPROC glad_glLightf; #define glLightf glad_glLightf typedef void (APIENTRYP PFNGLLIGHTFVPROC)(GLenum light, GLenum pname, const GLfloat *params); GLAPI PFNGLLIGHTFVPROC glad_glLightfv; #define glLightfv glad_glLightfv typedef void (APIENTRYP PFNGLLIGHTIPROC)(GLenum light, GLenum pname, GLint param); GLAPI PFNGLLIGHTIPROC glad_glLighti; #define glLighti glad_glLighti typedef void (APIENTRYP PFNGLLIGHTIVPROC)(GLenum light, GLenum pname, const GLint *params); GLAPI PFNGLLIGHTIVPROC glad_glLightiv; #define glLightiv glad_glLightiv typedef void (APIENTRYP PFNGLLIGHTMODELFPROC)(GLenum pname, GLfloat param); GLAPI PFNGLLIGHTMODELFPROC glad_glLightModelf; #define glLightModelf glad_glLightModelf typedef void (APIENTRYP PFNGLLIGHTMODELFVPROC)(GLenum pname, const GLfloat *params); GLAPI PFNGLLIGHTMODELFVPROC glad_glLightModelfv; #define glLightModelfv glad_glLightModelfv typedef void (APIENTRYP PFNGLLIGHTMODELIPROC)(GLenum pname, GLint param); GLAPI PFNGLLIGHTMODELIPROC glad_glLightModeli; #define glLightModeli glad_glLightModeli typedef void (APIENTRYP PFNGLLIGHTMODELIVPROC)(GLenum pname, const GLint *params); GLAPI PFNGLLIGHTMODELIVPROC glad_glLightModeliv; #define glLightModeliv glad_glLightModeliv typedef void (APIENTRYP PFNGLLINESTIPPLEPROC)(GLint factor, GLushort pattern); GLAPI PFNGLLINESTIPPLEPROC glad_glLineStipple; #define glLineStipple glad_glLineStipple typedef void (APIENTRYP PFNGLMATERIALFPROC)(GLenum face, GLenum pname, GLfloat param); GLAPI PFNGLMATERIALFPROC glad_glMaterialf; #define glMaterialf glad_glMaterialf typedef void (APIENTRYP PFNGLMATERIALFVPROC)(GLenum face, GLenum pname, const GLfloat *params); GLAPI PFNGLMATERIALFVPROC glad_glMaterialfv; #define glMaterialfv glad_glMaterialfv typedef void (APIENTRYP PFNGLMATERIALIPROC)(GLenum face, GLenum pname, GLint param); GLAPI PFNGLMATERIALIPROC glad_glMateriali; #define glMateriali glad_glMateriali typedef void (APIENTRYP PFNGLMATERIALIVPROC)(GLenum face, GLenum pname, const GLint *params); GLAPI PFNGLMATERIALIVPROC glad_glMaterialiv; #define glMaterialiv glad_glMaterialiv typedef void (APIENTRYP PFNGLPOLYGONSTIPPLEPROC)(const GLubyte *mask); GLAPI PFNGLPOLYGONSTIPPLEPROC glad_glPolygonStipple; #define glPolygonStipple glad_glPolygonStipple typedef void (APIENTRYP PFNGLSHADEMODELPROC)(GLenum mode); GLAPI PFNGLSHADEMODELPROC glad_glShadeModel; #define glShadeModel glad_glShadeModel typedef void (APIENTRYP PFNGLTEXENVFPROC)(GLenum target, GLenum pname, GLfloat param); GLAPI PFNGLTEXENVFPROC glad_glTexEnvf; #define glTexEnvf glad_glTexEnvf typedef void (APIENTRYP PFNGLTEXENVFVPROC)(GLenum target, GLenum pname, const GLfloat *params); GLAPI PFNGLTEXENVFVPROC glad_glTexEnvfv; #define glTexEnvfv glad_glTexEnvfv typedef void (APIENTRYP PFNGLTEXENVIPROC)(GLenum target, GLenum pname, GLint param); GLAPI PFNGLTEXENVIPROC glad_glTexEnvi; #define glTexEnvi glad_glTexEnvi typedef void (APIENTRYP PFNGLTEXENVIVPROC)(GLenum target, GLenum pname, const GLint *params); GLAPI PFNGLTEXENVIVPROC glad_glTexEnviv; #define glTexEnviv glad_glTexEnviv typedef void (APIENTRYP PFNGLTEXGENDPROC)(GLenum coord, GLenum pname, GLdouble param); GLAPI PFNGLTEXGENDPROC glad_glTexGend; #define glTexGend glad_glTexGend typedef void (APIENTRYP PFNGLTEXGENDVPROC)(GLenum coord, GLenum pname, const GLdouble *params); GLAPI PFNGLTEXGENDVPROC glad_glTexGendv; #define glTexGendv glad_glTexGendv typedef void (APIENTRYP PFNGLTEXGENFPROC)(GLenum coord, GLenum pname, GLfloat param); GLAPI PFNGLTEXGENFPROC glad_glTexGenf; #define glTexGenf glad_glTexGenf typedef void (APIENTRYP PFNGLTEXGENFVPROC)(GLenum coord, GLenum pname, const GLfloat *params); GLAPI PFNGLTEXGENFVPROC glad_glTexGenfv; #define glTexGenfv glad_glTexGenfv typedef void (APIENTRYP PFNGLTEXGENIPROC)(GLenum coord, GLenum pname, GLint param); GLAPI PFNGLTEXGENIPROC glad_glTexGeni; #define glTexGeni glad_glTexGeni typedef void (APIENTRYP PFNGLTEXGENIVPROC)(GLenum coord, GLenum pname, const GLint *params); GLAPI PFNGLTEXGENIVPROC glad_glTexGeniv; #define glTexGeniv glad_glTexGeniv typedef void (APIENTRYP PFNGLFEEDBACKBUFFERPROC)(GLsizei size, GLenum type, GLfloat *buffer); GLAPI PFNGLFEEDBACKBUFFERPROC glad_glFeedbackBuffer; #define glFeedbackBuffer glad_glFeedbackBuffer typedef void (APIENTRYP PFNGLSELECTBUFFERPROC)(GLsizei size, GLuint *buffer); GLAPI PFNGLSELECTBUFFERPROC glad_glSelectBuffer; #define glSelectBuffer glad_glSelectBuffer typedef GLint (APIENTRYP PFNGLRENDERMODEPROC)(GLenum mode); GLAPI PFNGLRENDERMODEPROC glad_glRenderMode; #define glRenderMode glad_glRenderMode typedef void (APIENTRYP PFNGLINITNAMESPROC)(void); GLAPI PFNGLINITNAMESPROC glad_glInitNames; #define glInitNames glad_glInitNames typedef void (APIENTRYP PFNGLLOADNAMEPROC)(GLuint name); GLAPI PFNGLLOADNAMEPROC glad_glLoadName; #define glLoadName glad_glLoadName typedef void (APIENTRYP PFNGLPASSTHROUGHPROC)(GLfloat token); GLAPI PFNGLPASSTHROUGHPROC glad_glPassThrough; #define glPassThrough glad_glPassThrough typedef void (APIENTRYP PFNGLPOPNAMEPROC)(void); GLAPI PFNGLPOPNAMEPROC glad_glPopName; #define glPopName glad_glPopName typedef void (APIENTRYP PFNGLPUSHNAMEPROC)(GLuint name); GLAPI PFNGLPUSHNAMEPROC glad_glPushName; #define glPushName glad_glPushName typedef void (APIENTRYP PFNGLCLEARACCUMPROC)(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); GLAPI PFNGLCLEARACCUMPROC glad_glClearAccum; #define glClearAccum glad_glClearAccum typedef void (APIENTRYP PFNGLCLEARINDEXPROC)(GLfloat c); GLAPI PFNGLCLEARINDEXPROC glad_glClearIndex; #define glClearIndex glad_glClearIndex typedef void (APIENTRYP PFNGLINDEXMASKPROC)(GLuint mask); GLAPI PFNGLINDEXMASKPROC glad_glIndexMask; #define glIndexMask glad_glIndexMask typedef void (APIENTRYP PFNGLACCUMPROC)(GLenum op, GLfloat value); GLAPI PFNGLACCUMPROC glad_glAccum; #define glAccum glad_glAccum typedef void (APIENTRYP PFNGLPOPATTRIBPROC)(void); GLAPI PFNGLPOPATTRIBPROC glad_glPopAttrib; #define glPopAttrib glad_glPopAttrib typedef void (APIENTRYP PFNGLPUSHATTRIBPROC)(GLbitfield mask); GLAPI PFNGLPUSHATTRIBPROC glad_glPushAttrib; #define glPushAttrib glad_glPushAttrib typedef void (APIENTRYP PFNGLMAP1DPROC)(GLenum target, GLdouble u1, GLdouble u2, GLint stride, GLint order, const GLdouble *points); GLAPI PFNGLMAP1DPROC glad_glMap1d; #define glMap1d glad_glMap1d typedef void (APIENTRYP PFNGLMAP1FPROC)(GLenum target, GLfloat u1, GLfloat u2, GLint stride, GLint order, const GLfloat *points); GLAPI PFNGLMAP1FPROC glad_glMap1f; #define glMap1f glad_glMap1f typedef void (APIENTRYP PFNGLMAP2DPROC)(GLenum target, GLdouble u1, GLdouble u2, GLint ustride, GLint uorder, GLdouble v1, GLdouble v2, GLint vstride, GLint vorder, const GLdouble *points); GLAPI PFNGLMAP2DPROC glad_glMap2d; #define glMap2d glad_glMap2d typedef void (APIENTRYP PFNGLMAP2FPROC)(GLenum target, GLfloat u1, GLfloat u2, GLint ustride, GLint uorder, GLfloat v1, GLfloat v2, GLint vstride, GLint vorder, const GLfloat *points); GLAPI PFNGLMAP2FPROC glad_glMap2f; #define glMap2f glad_glMap2f typedef void (APIENTRYP PFNGLMAPGRID1DPROC)(GLint un, GLdouble u1, GLdouble u2); GLAPI PFNGLMAPGRID1DPROC glad_glMapGrid1d; #define glMapGrid1d glad_glMapGrid1d typedef void (APIENTRYP PFNGLMAPGRID1FPROC)(GLint un, GLfloat u1, GLfloat u2); GLAPI PFNGLMAPGRID1FPROC glad_glMapGrid1f; #define glMapGrid1f glad_glMapGrid1f typedef void (APIENTRYP PFNGLMAPGRID2DPROC)(GLint un, GLdouble u1, GLdouble u2, GLint vn, GLdouble v1, GLdouble v2); GLAPI PFNGLMAPGRID2DPROC glad_glMapGrid2d; #define glMapGrid2d glad_glMapGrid2d typedef void (APIENTRYP PFNGLMAPGRID2FPROC)(GLint un, GLfloat u1, GLfloat u2, GLint vn, GLfloat v1, GLfloat v2); GLAPI PFNGLMAPGRID2FPROC glad_glMapGrid2f; #define glMapGrid2f glad_glMapGrid2f typedef void (APIENTRYP PFNGLEVALCOORD1DPROC)(GLdouble u); GLAPI PFNGLEVALCOORD1DPROC glad_glEvalCoord1d; #define glEvalCoord1d glad_glEvalCoord1d typedef void (APIENTRYP PFNGLEVALCOORD1DVPROC)(const GLdouble *u); GLAPI PFNGLEVALCOORD1DVPROC glad_glEvalCoord1dv; #define glEvalCoord1dv glad_glEvalCoord1dv typedef void (APIENTRYP PFNGLEVALCOORD1FPROC)(GLfloat u); GLAPI PFNGLEVALCOORD1FPROC glad_glEvalCoord1f; #define glEvalCoord1f glad_glEvalCoord1f typedef void (APIENTRYP PFNGLEVALCOORD1FVPROC)(const GLfloat *u); GLAPI PFNGLEVALCOORD1FVPROC glad_glEvalCoord1fv; #define glEvalCoord1fv glad_glEvalCoord1fv typedef void (APIENTRYP PFNGLEVALCOORD2DPROC)(GLdouble u, GLdouble v); GLAPI PFNGLEVALCOORD2DPROC glad_glEvalCoord2d; #define glEvalCoord2d glad_glEvalCoord2d typedef void (APIENTRYP PFNGLEVALCOORD2DVPROC)(const GLdouble *u); GLAPI PFNGLEVALCOORD2DVPROC glad_glEvalCoord2dv; #define glEvalCoord2dv glad_glEvalCoord2dv typedef void (APIENTRYP PFNGLEVALCOORD2FPROC)(GLfloat u, GLfloat v); GLAPI PFNGLEVALCOORD2FPROC glad_glEvalCoord2f; #define glEvalCoord2f glad_glEvalCoord2f typedef void (APIENTRYP PFNGLEVALCOORD2FVPROC)(const GLfloat *u); GLAPI PFNGLEVALCOORD2FVPROC glad_glEvalCoord2fv; #define glEvalCoord2fv glad_glEvalCoord2fv typedef void (APIENTRYP PFNGLEVALMESH1PROC)(GLenum mode, GLint i1, GLint i2); GLAPI PFNGLEVALMESH1PROC glad_glEvalMesh1; #define glEvalMesh1 glad_glEvalMesh1 typedef void (APIENTRYP PFNGLEVALPOINT1PROC)(GLint i); GLAPI PFNGLEVALPOINT1PROC glad_glEvalPoint1; #define glEvalPoint1 glad_glEvalPoint1 typedef void (APIENTRYP PFNGLEVALMESH2PROC)(GLenum mode, GLint i1, GLint i2, GLint j1, GLint j2); GLAPI PFNGLEVALMESH2PROC glad_glEvalMesh2; #define glEvalMesh2 glad_glEvalMesh2 typedef void (APIENTRYP PFNGLEVALPOINT2PROC)(GLint i, GLint j); GLAPI PFNGLEVALPOINT2PROC glad_glEvalPoint2; #define glEvalPoint2 glad_glEvalPoint2 typedef void (APIENTRYP PFNGLALPHAFUNCPROC)(GLenum func, GLfloat ref); GLAPI PFNGLALPHAFUNCPROC glad_glAlphaFunc; #define glAlphaFunc glad_glAlphaFunc typedef void (APIENTRYP PFNGLPIXELZOOMPROC)(GLfloat xfactor, GLfloat yfactor); GLAPI PFNGLPIXELZOOMPROC glad_glPixelZoom; #define glPixelZoom glad_glPixelZoom typedef void (APIENTRYP PFNGLPIXELTRANSFERFPROC)(GLenum pname, GLfloat param); GLAPI PFNGLPIXELTRANSFERFPROC glad_glPixelTransferf; #define glPixelTransferf glad_glPixelTransferf typedef void (APIENTRYP PFNGLPIXELTRANSFERIPROC)(GLenum pname, GLint param); GLAPI PFNGLPIXELTRANSFERIPROC glad_glPixelTransferi; #define glPixelTransferi glad_glPixelTransferi typedef void (APIENTRYP PFNGLPIXELMAPFVPROC)(GLenum map, GLsizei mapsize, const GLfloat *values); GLAPI PFNGLPIXELMAPFVPROC glad_glPixelMapfv; #define glPixelMapfv glad_glPixelMapfv typedef void (APIENTRYP PFNGLPIXELMAPUIVPROC)(GLenum map, GLsizei mapsize, const GLuint *values); GLAPI PFNGLPIXELMAPUIVPROC glad_glPixelMapuiv; #define glPixelMapuiv glad_glPixelMapuiv typedef void (APIENTRYP PFNGLPIXELMAPUSVPROC)(GLenum map, GLsizei mapsize, const GLushort *values); GLAPI PFNGLPIXELMAPUSVPROC glad_glPixelMapusv; #define glPixelMapusv glad_glPixelMapusv typedef void (APIENTRYP PFNGLCOPYPIXELSPROC)(GLint x, GLint y, GLsizei width, GLsizei height, GLenum type); GLAPI PFNGLCOPYPIXELSPROC glad_glCopyPixels; #define glCopyPixels glad_glCopyPixels typedef void (APIENTRYP PFNGLDRAWPIXELSPROC)(GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels); GLAPI PFNGLDRAWPIXELSPROC glad_glDrawPixels; #define glDrawPixels glad_glDrawPixels typedef void (APIENTRYP PFNGLGETCLIPPLANEPROC)(GLenum plane, GLdouble *equation); GLAPI PFNGLGETCLIPPLANEPROC glad_glGetClipPlane; #define glGetClipPlane glad_glGetClipPlane typedef void (APIENTRYP PFNGLGETLIGHTFVPROC)(GLenum light, GLenum pname, GLfloat *params); GLAPI PFNGLGETLIGHTFVPROC glad_glGetLightfv; #define glGetLightfv glad_glGetLightfv typedef void (APIENTRYP PFNGLGETLIGHTIVPROC)(GLenum light, GLenum pname, GLint *params); GLAPI PFNGLGETLIGHTIVPROC glad_glGetLightiv; #define glGetLightiv glad_glGetLightiv typedef void (APIENTRYP PFNGLGETMAPDVPROC)(GLenum target, GLenum query, GLdouble *v); GLAPI PFNGLGETMAPDVPROC glad_glGetMapdv; #define glGetMapdv glad_glGetMapdv typedef void (APIENTRYP PFNGLGETMAPFVPROC)(GLenum target, GLenum query, GLfloat *v); GLAPI PFNGLGETMAPFVPROC glad_glGetMapfv; #define glGetMapfv glad_glGetMapfv typedef void (APIENTRYP PFNGLGETMAPIVPROC)(GLenum target, GLenum query, GLint *v); GLAPI PFNGLGETMAPIVPROC glad_glGetMapiv; #define glGetMapiv glad_glGetMapiv typedef void (APIENTRYP PFNGLGETMATERIALFVPROC)(GLenum face, GLenum pname, GLfloat *params); GLAPI PFNGLGETMATERIALFVPROC glad_glGetMaterialfv; #define glGetMaterialfv glad_glGetMaterialfv typedef void (APIENTRYP PFNGLGETMATERIALIVPROC)(GLenum face, GLenum pname, GLint *params); GLAPI PFNGLGETMATERIALIVPROC glad_glGetMaterialiv; #define glGetMaterialiv glad_glGetMaterialiv typedef void (APIENTRYP PFNGLGETPIXELMAPFVPROC)(GLenum map, GLfloat *values); GLAPI PFNGLGETPIXELMAPFVPROC glad_glGetPixelMapfv; #define glGetPixelMapfv glad_glGetPixelMapfv typedef void (APIENTRYP PFNGLGETPIXELMAPUIVPROC)(GLenum map, GLuint *values); GLAPI PFNGLGETPIXELMAPUIVPROC glad_glGetPixelMapuiv; #define glGetPixelMapuiv glad_glGetPixelMapuiv typedef void (APIENTRYP PFNGLGETPIXELMAPUSVPROC)(GLenum map, GLushort *values); GLAPI PFNGLGETPIXELMAPUSVPROC glad_glGetPixelMapusv; #define glGetPixelMapusv glad_glGetPixelMapusv typedef void (APIENTRYP PFNGLGETPOLYGONSTIPPLEPROC)(GLubyte *mask); GLAPI PFNGLGETPOLYGONSTIPPLEPROC glad_glGetPolygonStipple; #define glGetPolygonStipple glad_glGetPolygonStipple typedef void (APIENTRYP PFNGLGETTEXENVFVPROC)(GLenum target, GLenum pname, GLfloat *params); GLAPI PFNGLGETTEXENVFVPROC glad_glGetTexEnvfv; #define glGetTexEnvfv glad_glGetTexEnvfv typedef void (APIENTRYP PFNGLGETTEXENVIVPROC)(GLenum target, GLenum pname, GLint *params); GLAPI PFNGLGETTEXENVIVPROC glad_glGetTexEnviv; #define glGetTexEnviv glad_glGetTexEnviv typedef void (APIENTRYP PFNGLGETTEXGENDVPROC)(GLenum coord, GLenum pname, GLdouble *params); GLAPI PFNGLGETTEXGENDVPROC glad_glGetTexGendv; #define glGetTexGendv glad_glGetTexGendv typedef void (APIENTRYP PFNGLGETTEXGENFVPROC)(GLenum coord, GLenum pname, GLfloat *params); GLAPI PFNGLGETTEXGENFVPROC glad_glGetTexGenfv; #define glGetTexGenfv glad_glGetTexGenfv typedef void (APIENTRYP PFNGLGETTEXGENIVPROC)(GLenum coord, GLenum pname, GLint *params); GLAPI PFNGLGETTEXGENIVPROC glad_glGetTexGeniv; #define glGetTexGeniv glad_glGetTexGeniv typedef GLboolean (APIENTRYP PFNGLISLISTPROC)(GLuint list); GLAPI PFNGLISLISTPROC glad_glIsList; #define glIsList glad_glIsList typedef void (APIENTRYP PFNGLFRUSTUMPROC)(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar); GLAPI PFNGLFRUSTUMPROC glad_glFrustum; #define glFrustum glad_glFrustum typedef void (APIENTRYP PFNGLLOADIDENTITYPROC)(void); GLAPI PFNGLLOADIDENTITYPROC glad_glLoadIdentity; #define glLoadIdentity glad_glLoadIdentity typedef void (APIENTRYP PFNGLLOADMATRIXFPROC)(const GLfloat *m); GLAPI PFNGLLOADMATRIXFPROC glad_glLoadMatrixf; #define glLoadMatrixf glad_glLoadMatrixf typedef void (APIENTRYP PFNGLLOADMATRIXDPROC)(const GLdouble *m); GLAPI PFNGLLOADMATRIXDPROC glad_glLoadMatrixd; #define glLoadMatrixd glad_glLoadMatrixd typedef void (APIENTRYP PFNGLMATRIXMODEPROC)(GLenum mode); GLAPI PFNGLMATRIXMODEPROC glad_glMatrixMode; #define glMatrixMode glad_glMatrixMode typedef void (APIENTRYP PFNGLMULTMATRIXFPROC)(const GLfloat *m); GLAPI PFNGLMULTMATRIXFPROC glad_glMultMatrixf; #define glMultMatrixf glad_glMultMatrixf typedef void (APIENTRYP PFNGLMULTMATRIXDPROC)(const GLdouble *m); GLAPI PFNGLMULTMATRIXDPROC glad_glMultMatrixd; #define glMultMatrixd glad_glMultMatrixd typedef void (APIENTRYP PFNGLORTHOPROC)(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar); GLAPI PFNGLORTHOPROC glad_glOrtho; #define glOrtho glad_glOrtho typedef void (APIENTRYP PFNGLPOPMATRIXPROC)(void); GLAPI PFNGLPOPMATRIXPROC glad_glPopMatrix; #define glPopMatrix glad_glPopMatrix typedef void (APIENTRYP PFNGLPUSHMATRIXPROC)(void); GLAPI PFNGLPUSHMATRIXPROC glad_glPushMatrix; #define glPushMatrix glad_glPushMatrix typedef void (APIENTRYP PFNGLROTATEDPROC)(GLdouble angle, GLdouble x, GLdouble y, GLdouble z); GLAPI PFNGLROTATEDPROC glad_glRotated; #define glRotated glad_glRotated typedef void (APIENTRYP PFNGLROTATEFPROC)(GLfloat angle, GLfloat x, GLfloat y, GLfloat z); GLAPI PFNGLROTATEFPROC glad_glRotatef; #define glRotatef glad_glRotatef typedef void (APIENTRYP PFNGLSCALEDPROC)(GLdouble x, GLdouble y, GLdouble z); GLAPI PFNGLSCALEDPROC glad_glScaled; #define glScaled glad_glScaled typedef void (APIENTRYP PFNGLSCALEFPROC)(GLfloat x, GLfloat y, GLfloat z); GLAPI PFNGLSCALEFPROC glad_glScalef; #define glScalef glad_glScalef typedef void (APIENTRYP PFNGLTRANSLATEDPROC)(GLdouble x, GLdouble y, GLdouble z); GLAPI PFNGLTRANSLATEDPROC glad_glTranslated; #define glTranslated glad_glTranslated typedef void (APIENTRYP PFNGLTRANSLATEFPROC)(GLfloat x, GLfloat y, GLfloat z); GLAPI PFNGLTRANSLATEFPROC glad_glTranslatef; #define glTranslatef glad_glTranslatef #endif #ifndef GL_VERSION_1_1 #define GL_VERSION_1_1 1 GLAPI int GLAD_GL_VERSION_1_1; typedef void (APIENTRYP PFNGLDRAWARRAYSPROC)(GLenum mode, GLint first, GLsizei count); GLAPI PFNGLDRAWARRAYSPROC glad_glDrawArrays; #define glDrawArrays glad_glDrawArrays typedef void (APIENTRYP PFNGLDRAWELEMENTSPROC)(GLenum mode, GLsizei count, GLenum type, const void *indices); GLAPI PFNGLDRAWELEMENTSPROC glad_glDrawElements; #define glDrawElements glad_glDrawElements typedef void (APIENTRYP PFNGLGETPOINTERVPROC)(GLenum pname, void **params); GLAPI PFNGLGETPOINTERVPROC glad_glGetPointerv; #define glGetPointerv glad_glGetPointerv typedef void (APIENTRYP PFNGLPOLYGONOFFSETPROC)(GLfloat factor, GLfloat units); GLAPI PFNGLPOLYGONOFFSETPROC glad_glPolygonOffset; #define glPolygonOffset glad_glPolygonOffset typedef void (APIENTRYP PFNGLCOPYTEXIMAGE1DPROC)(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border); GLAPI PFNGLCOPYTEXIMAGE1DPROC glad_glCopyTexImage1D; #define glCopyTexImage1D glad_glCopyTexImage1D typedef void (APIENTRYP PFNGLCOPYTEXIMAGE2DPROC)(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); GLAPI PFNGLCOPYTEXIMAGE2DPROC glad_glCopyTexImage2D; #define glCopyTexImage2D glad_glCopyTexImage2D typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE1DPROC)(GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); GLAPI PFNGLCOPYTEXSUBIMAGE1DPROC glad_glCopyTexSubImage1D; #define glCopyTexSubImage1D glad_glCopyTexSubImage1D typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE2DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); GLAPI PFNGLCOPYTEXSUBIMAGE2DPROC glad_glCopyTexSubImage2D; #define glCopyTexSubImage2D glad_glCopyTexSubImage2D typedef void (APIENTRYP PFNGLTEXSUBIMAGE1DPROC)(GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void *pixels); GLAPI PFNGLTEXSUBIMAGE1DPROC glad_glTexSubImage1D; #define glTexSubImage1D glad_glTexSubImage1D typedef void (APIENTRYP PFNGLTEXSUBIMAGE2DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels); GLAPI PFNGLTEXSUBIMAGE2DPROC glad_glTexSubImage2D; #define glTexSubImage2D glad_glTexSubImage2D typedef void (APIENTRYP PFNGLBINDTEXTUREPROC)(GLenum target, GLuint texture); GLAPI PFNGLBINDTEXTUREPROC glad_glBindTexture; #define glBindTexture glad_glBindTexture typedef void (APIENTRYP PFNGLDELETETEXTURESPROC)(GLsizei n, const GLuint *textures); GLAPI PFNGLDELETETEXTURESPROC glad_glDeleteTextures; #define glDeleteTextures glad_glDeleteTextures typedef void (APIENTRYP PFNGLGENTEXTURESPROC)(GLsizei n, GLuint *textures); GLAPI PFNGLGENTEXTURESPROC glad_glGenTextures; #define glGenTextures glad_glGenTextures typedef GLboolean (APIENTRYP PFNGLISTEXTUREPROC)(GLuint texture); GLAPI PFNGLISTEXTUREPROC glad_glIsTexture; #define glIsTexture glad_glIsTexture typedef void (APIENTRYP PFNGLARRAYELEMENTPROC)(GLint i); GLAPI PFNGLARRAYELEMENTPROC glad_glArrayElement; #define glArrayElement glad_glArrayElement typedef void (APIENTRYP PFNGLCOLORPOINTERPROC)(GLint size, GLenum type, GLsizei stride, const void *pointer); GLAPI PFNGLCOLORPOINTERPROC glad_glColorPointer; #define glColorPointer glad_glColorPointer typedef void (APIENTRYP PFNGLDISABLECLIENTSTATEPROC)(GLenum array); GLAPI PFNGLDISABLECLIENTSTATEPROC glad_glDisableClientState; #define glDisableClientState glad_glDisableClientState typedef void (APIENTRYP PFNGLEDGEFLAGPOINTERPROC)(GLsizei stride, const void *pointer); GLAPI PFNGLEDGEFLAGPOINTERPROC glad_glEdgeFlagPointer; #define glEdgeFlagPointer glad_glEdgeFlagPointer typedef void (APIENTRYP PFNGLENABLECLIENTSTATEPROC)(GLenum array); GLAPI PFNGLENABLECLIENTSTATEPROC glad_glEnableClientState; #define glEnableClientState glad_glEnableClientState typedef void (APIENTRYP PFNGLINDEXPOINTERPROC)(GLenum type, GLsizei stride, const void *pointer); GLAPI PFNGLINDEXPOINTERPROC glad_glIndexPointer; #define glIndexPointer glad_glIndexPointer typedef void (APIENTRYP PFNGLINTERLEAVEDARRAYSPROC)(GLenum format, GLsizei stride, const void *pointer); GLAPI PFNGLINTERLEAVEDARRAYSPROC glad_glInterleavedArrays; #define glInterleavedArrays glad_glInterleavedArrays typedef void (APIENTRYP PFNGLNORMALPOINTERPROC)(GLenum type, GLsizei stride, const void *pointer); GLAPI PFNGLNORMALPOINTERPROC glad_glNormalPointer; #define glNormalPointer glad_glNormalPointer typedef void (APIENTRYP PFNGLTEXCOORDPOINTERPROC)(GLint size, GLenum type, GLsizei stride, const void *pointer); GLAPI PFNGLTEXCOORDPOINTERPROC glad_glTexCoordPointer; #define glTexCoordPointer glad_glTexCoordPointer typedef void (APIENTRYP PFNGLVERTEXPOINTERPROC)(GLint size, GLenum type, GLsizei stride, const void *pointer); GLAPI PFNGLVERTEXPOINTERPROC glad_glVertexPointer; #define glVertexPointer glad_glVertexPointer typedef GLboolean (APIENTRYP PFNGLARETEXTURESRESIDENTPROC)(GLsizei n, const GLuint *textures, GLboolean *residences); GLAPI PFNGLARETEXTURESRESIDENTPROC glad_glAreTexturesResident; #define glAreTexturesResident glad_glAreTexturesResident typedef void (APIENTRYP PFNGLPRIORITIZETEXTURESPROC)(GLsizei n, const GLuint *textures, const GLfloat *priorities); GLAPI PFNGLPRIORITIZETEXTURESPROC glad_glPrioritizeTextures; #define glPrioritizeTextures glad_glPrioritizeTextures typedef void (APIENTRYP PFNGLINDEXUBPROC)(GLubyte c); GLAPI PFNGLINDEXUBPROC glad_glIndexub; #define glIndexub glad_glIndexub typedef void (APIENTRYP PFNGLINDEXUBVPROC)(const GLubyte *c); GLAPI PFNGLINDEXUBVPROC glad_glIndexubv; #define glIndexubv glad_glIndexubv typedef void (APIENTRYP PFNGLPOPCLIENTATTRIBPROC)(void); GLAPI PFNGLPOPCLIENTATTRIBPROC glad_glPopClientAttrib; #define glPopClientAttrib glad_glPopClientAttrib typedef void (APIENTRYP PFNGLPUSHCLIENTATTRIBPROC)(GLbitfield mask); GLAPI PFNGLPUSHCLIENTATTRIBPROC glad_glPushClientAttrib; #define glPushClientAttrib glad_glPushClientAttrib #endif #ifndef GL_VERSION_1_2 #define GL_VERSION_1_2 1 GLAPI int GLAD_GL_VERSION_1_2; typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTSPROC)(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices); GLAPI PFNGLDRAWRANGEELEMENTSPROC glad_glDrawRangeElements; #define glDrawRangeElements glad_glDrawRangeElements typedef void (APIENTRYP PFNGLTEXIMAGE3DPROC)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *pixels); GLAPI PFNGLTEXIMAGE3DPROC glad_glTexImage3D; #define glTexImage3D glad_glTexImage3D typedef void (APIENTRYP PFNGLTEXSUBIMAGE3DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels); GLAPI PFNGLTEXSUBIMAGE3DPROC glad_glTexSubImage3D; #define glTexSubImage3D glad_glTexSubImage3D typedef void (APIENTRYP PFNGLCOPYTEXSUBIMAGE3DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); GLAPI PFNGLCOPYTEXSUBIMAGE3DPROC glad_glCopyTexSubImage3D; #define glCopyTexSubImage3D glad_glCopyTexSubImage3D #endif #ifndef GL_VERSION_1_3 #define GL_VERSION_1_3 1 GLAPI int GLAD_GL_VERSION_1_3; typedef void (APIENTRYP PFNGLACTIVETEXTUREPROC)(GLenum texture); GLAPI PFNGLACTIVETEXTUREPROC glad_glActiveTexture; #define glActiveTexture glad_glActiveTexture typedef void (APIENTRYP PFNGLSAMPLECOVERAGEPROC)(GLfloat value, GLboolean invert); GLAPI PFNGLSAMPLECOVERAGEPROC glad_glSampleCoverage; #define glSampleCoverage glad_glSampleCoverage typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE3DPROC)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *data); GLAPI PFNGLCOMPRESSEDTEXIMAGE3DPROC glad_glCompressedTexImage3D; #define glCompressedTexImage3D glad_glCompressedTexImage3D typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE2DPROC)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *data); GLAPI PFNGLCOMPRESSEDTEXIMAGE2DPROC glad_glCompressedTexImage2D; #define glCompressedTexImage2D glad_glCompressedTexImage2D typedef void (APIENTRYP PFNGLCOMPRESSEDTEXIMAGE1DPROC)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const void *data); GLAPI PFNGLCOMPRESSEDTEXIMAGE1DPROC glad_glCompressedTexImage1D; #define glCompressedTexImage1D glad_glCompressedTexImage1D typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *data); GLAPI PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC glad_glCompressedTexSubImage3D; #define glCompressedTexSubImage3D glad_glCompressedTexSubImage3D typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data); GLAPI PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC glad_glCompressedTexSubImage2D; #define glCompressedTexSubImage2D glad_glCompressedTexSubImage2D typedef void (APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC)(GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void *data); GLAPI PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC glad_glCompressedTexSubImage1D; #define glCompressedTexSubImage1D glad_glCompressedTexSubImage1D typedef void (APIENTRYP PFNGLGETCOMPRESSEDTEXIMAGEPROC)(GLenum target, GLint level, void *img); GLAPI PFNGLGETCOMPRESSEDTEXIMAGEPROC glad_glGetCompressedTexImage; #define glGetCompressedTexImage glad_glGetCompressedTexImage typedef void (APIENTRYP PFNGLCLIENTACTIVETEXTUREPROC)(GLenum texture); GLAPI PFNGLCLIENTACTIVETEXTUREPROC glad_glClientActiveTexture; #define glClientActiveTexture glad_glClientActiveTexture typedef void (APIENTRYP PFNGLMULTITEXCOORD1DPROC)(GLenum target, GLdouble s); GLAPI PFNGLMULTITEXCOORD1DPROC glad_glMultiTexCoord1d; #define glMultiTexCoord1d glad_glMultiTexCoord1d typedef void (APIENTRYP PFNGLMULTITEXCOORD1DVPROC)(GLenum target, const GLdouble *v); GLAPI PFNGLMULTITEXCOORD1DVPROC glad_glMultiTexCoord1dv; #define glMultiTexCoord1dv glad_glMultiTexCoord1dv typedef void (APIENTRYP PFNGLMULTITEXCOORD1FPROC)(GLenum target, GLfloat s); GLAPI PFNGLMULTITEXCOORD1FPROC glad_glMultiTexCoord1f; #define glMultiTexCoord1f glad_glMultiTexCoord1f typedef void (APIENTRYP PFNGLMULTITEXCOORD1FVPROC)(GLenum target, const GLfloat *v); GLAPI PFNGLMULTITEXCOORD1FVPROC glad_glMultiTexCoord1fv; #define glMultiTexCoord1fv glad_glMultiTexCoord1fv typedef void (APIENTRYP PFNGLMULTITEXCOORD1IPROC)(GLenum target, GLint s); GLAPI PFNGLMULTITEXCOORD1IPROC glad_glMultiTexCoord1i; #define glMultiTexCoord1i glad_glMultiTexCoord1i typedef void (APIENTRYP PFNGLMULTITEXCOORD1IVPROC)(GLenum target, const GLint *v); GLAPI PFNGLMULTITEXCOORD1IVPROC glad_glMultiTexCoord1iv; #define glMultiTexCoord1iv glad_glMultiTexCoord1iv typedef void (APIENTRYP PFNGLMULTITEXCOORD1SPROC)(GLenum target, GLshort s); GLAPI PFNGLMULTITEXCOORD1SPROC glad_glMultiTexCoord1s; #define glMultiTexCoord1s glad_glMultiTexCoord1s typedef void (APIENTRYP PFNGLMULTITEXCOORD1SVPROC)(GLenum target, const GLshort *v); GLAPI PFNGLMULTITEXCOORD1SVPROC glad_glMultiTexCoord1sv; #define glMultiTexCoord1sv glad_glMultiTexCoord1sv typedef void (APIENTRYP PFNGLMULTITEXCOORD2DPROC)(GLenum target, GLdouble s, GLdouble t); GLAPI PFNGLMULTITEXCOORD2DPROC glad_glMultiTexCoord2d; #define glMultiTexCoord2d glad_glMultiTexCoord2d typedef void (APIENTRYP PFNGLMULTITEXCOORD2DVPROC)(GLenum target, const GLdouble *v); GLAPI PFNGLMULTITEXCOORD2DVPROC glad_glMultiTexCoord2dv; #define glMultiTexCoord2dv glad_glMultiTexCoord2dv typedef void (APIENTRYP PFNGLMULTITEXCOORD2FPROC)(GLenum target, GLfloat s, GLfloat t); GLAPI PFNGLMULTITEXCOORD2FPROC glad_glMultiTexCoord2f; #define glMultiTexCoord2f glad_glMultiTexCoord2f typedef void (APIENTRYP PFNGLMULTITEXCOORD2FVPROC)(GLenum target, const GLfloat *v); GLAPI PFNGLMULTITEXCOORD2FVPROC glad_glMultiTexCoord2fv; #define glMultiTexCoord2fv glad_glMultiTexCoord2fv typedef void (APIENTRYP PFNGLMULTITEXCOORD2IPROC)(GLenum target, GLint s, GLint t); GLAPI PFNGLMULTITEXCOORD2IPROC glad_glMultiTexCoord2i; #define glMultiTexCoord2i glad_glMultiTexCoord2i typedef void (APIENTRYP PFNGLMULTITEXCOORD2IVPROC)(GLenum target, const GLint *v); GLAPI PFNGLMULTITEXCOORD2IVPROC glad_glMultiTexCoord2iv; #define glMultiTexCoord2iv glad_glMultiTexCoord2iv typedef void (APIENTRYP PFNGLMULTITEXCOORD2SPROC)(GLenum target, GLshort s, GLshort t); GLAPI PFNGLMULTITEXCOORD2SPROC glad_glMultiTexCoord2s; #define glMultiTexCoord2s glad_glMultiTexCoord2s typedef void (APIENTRYP PFNGLMULTITEXCOORD2SVPROC)(GLenum target, const GLshort *v); GLAPI PFNGLMULTITEXCOORD2SVPROC glad_glMultiTexCoord2sv; #define glMultiTexCoord2sv glad_glMultiTexCoord2sv typedef void (APIENTRYP PFNGLMULTITEXCOORD3DPROC)(GLenum target, GLdouble s, GLdouble t, GLdouble r); GLAPI PFNGLMULTITEXCOORD3DPROC glad_glMultiTexCoord3d; #define glMultiTexCoord3d glad_glMultiTexCoord3d typedef void (APIENTRYP PFNGLMULTITEXCOORD3DVPROC)(GLenum target, const GLdouble *v); GLAPI PFNGLMULTITEXCOORD3DVPROC glad_glMultiTexCoord3dv; #define glMultiTexCoord3dv glad_glMultiTexCoord3dv typedef void (APIENTRYP PFNGLMULTITEXCOORD3FPROC)(GLenum target, GLfloat s, GLfloat t, GLfloat r); GLAPI PFNGLMULTITEXCOORD3FPROC glad_glMultiTexCoord3f; #define glMultiTexCoord3f glad_glMultiTexCoord3f typedef void (APIENTRYP PFNGLMULTITEXCOORD3FVPROC)(GLenum target, const GLfloat *v); GLAPI PFNGLMULTITEXCOORD3FVPROC glad_glMultiTexCoord3fv; #define glMultiTexCoord3fv glad_glMultiTexCoord3fv typedef void (APIENTRYP PFNGLMULTITEXCOORD3IPROC)(GLenum target, GLint s, GLint t, GLint r); GLAPI PFNGLMULTITEXCOORD3IPROC glad_glMultiTexCoord3i; #define glMultiTexCoord3i glad_glMultiTexCoord3i typedef void (APIENTRYP PFNGLMULTITEXCOORD3IVPROC)(GLenum target, const GLint *v); GLAPI PFNGLMULTITEXCOORD3IVPROC glad_glMultiTexCoord3iv; #define glMultiTexCoord3iv glad_glMultiTexCoord3iv typedef void (APIENTRYP PFNGLMULTITEXCOORD3SPROC)(GLenum target, GLshort s, GLshort t, GLshort r); GLAPI PFNGLMULTITEXCOORD3SPROC glad_glMultiTexCoord3s; #define glMultiTexCoord3s glad_glMultiTexCoord3s typedef void (APIENTRYP PFNGLMULTITEXCOORD3SVPROC)(GLenum target, const GLshort *v); GLAPI PFNGLMULTITEXCOORD3SVPROC glad_glMultiTexCoord3sv; #define glMultiTexCoord3sv glad_glMultiTexCoord3sv typedef void (APIENTRYP PFNGLMULTITEXCOORD4DPROC)(GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q); GLAPI PFNGLMULTITEXCOORD4DPROC glad_glMultiTexCoord4d; #define glMultiTexCoord4d glad_glMultiTexCoord4d typedef void (APIENTRYP PFNGLMULTITEXCOORD4DVPROC)(GLenum target, const GLdouble *v); GLAPI PFNGLMULTITEXCOORD4DVPROC glad_glMultiTexCoord4dv; #define glMultiTexCoord4dv glad_glMultiTexCoord4dv typedef void (APIENTRYP PFNGLMULTITEXCOORD4FPROC)(GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q); GLAPI PFNGLMULTITEXCOORD4FPROC glad_glMultiTexCoord4f; #define glMultiTexCoord4f glad_glMultiTexCoord4f typedef void (APIENTRYP PFNGLMULTITEXCOORD4FVPROC)(GLenum target, const GLfloat *v); GLAPI PFNGLMULTITEXCOORD4FVPROC glad_glMultiTexCoord4fv; #define glMultiTexCoord4fv glad_glMultiTexCoord4fv typedef void (APIENTRYP PFNGLMULTITEXCOORD4IPROC)(GLenum target, GLint s, GLint t, GLint r, GLint q); GLAPI PFNGLMULTITEXCOORD4IPROC glad_glMultiTexCoord4i; #define glMultiTexCoord4i glad_glMultiTexCoord4i typedef void (APIENTRYP PFNGLMULTITEXCOORD4IVPROC)(GLenum target, const GLint *v); GLAPI PFNGLMULTITEXCOORD4IVPROC glad_glMultiTexCoord4iv; #define glMultiTexCoord4iv glad_glMultiTexCoord4iv typedef void (APIENTRYP PFNGLMULTITEXCOORD4SPROC)(GLenum target, GLshort s, GLshort t, GLshort r, GLshort q); GLAPI PFNGLMULTITEXCOORD4SPROC glad_glMultiTexCoord4s; #define glMultiTexCoord4s glad_glMultiTexCoord4s typedef void (APIENTRYP PFNGLMULTITEXCOORD4SVPROC)(GLenum target, const GLshort *v); GLAPI PFNGLMULTITEXCOORD4SVPROC glad_glMultiTexCoord4sv; #define glMultiTexCoord4sv glad_glMultiTexCoord4sv typedef void (APIENTRYP PFNGLLOADTRANSPOSEMATRIXFPROC)(const GLfloat *m); GLAPI PFNGLLOADTRANSPOSEMATRIXFPROC glad_glLoadTransposeMatrixf; #define glLoadTransposeMatrixf glad_glLoadTransposeMatrixf typedef void (APIENTRYP PFNGLLOADTRANSPOSEMATRIXDPROC)(const GLdouble *m); GLAPI PFNGLLOADTRANSPOSEMATRIXDPROC glad_glLoadTransposeMatrixd; #define glLoadTransposeMatrixd glad_glLoadTransposeMatrixd typedef void (APIENTRYP PFNGLMULTTRANSPOSEMATRIXFPROC)(const GLfloat *m); GLAPI PFNGLMULTTRANSPOSEMATRIXFPROC glad_glMultTransposeMatrixf; #define glMultTransposeMatrixf glad_glMultTransposeMatrixf typedef void (APIENTRYP PFNGLMULTTRANSPOSEMATRIXDPROC)(const GLdouble *m); GLAPI PFNGLMULTTRANSPOSEMATRIXDPROC glad_glMultTransposeMatrixd; #define glMultTransposeMatrixd glad_glMultTransposeMatrixd #endif #ifndef GL_VERSION_1_4 #define GL_VERSION_1_4 1 GLAPI int GLAD_GL_VERSION_1_4; typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEPROC)(GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha); GLAPI PFNGLBLENDFUNCSEPARATEPROC glad_glBlendFuncSeparate; #define glBlendFuncSeparate glad_glBlendFuncSeparate typedef void (APIENTRYP PFNGLMULTIDRAWARRAYSPROC)(GLenum mode, const GLint *first, const GLsizei *count, GLsizei drawcount); GLAPI PFNGLMULTIDRAWARRAYSPROC glad_glMultiDrawArrays; #define glMultiDrawArrays glad_glMultiDrawArrays typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSPROC)(GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei drawcount); GLAPI PFNGLMULTIDRAWELEMENTSPROC glad_glMultiDrawElements; #define glMultiDrawElements glad_glMultiDrawElements typedef void (APIENTRYP PFNGLPOINTPARAMETERFPROC)(GLenum pname, GLfloat param); GLAPI PFNGLPOINTPARAMETERFPROC glad_glPointParameterf; #define glPointParameterf glad_glPointParameterf typedef void (APIENTRYP PFNGLPOINTPARAMETERFVPROC)(GLenum pname, const GLfloat *params); GLAPI PFNGLPOINTPARAMETERFVPROC glad_glPointParameterfv; #define glPointParameterfv glad_glPointParameterfv typedef void (APIENTRYP PFNGLPOINTPARAMETERIPROC)(GLenum pname, GLint param); GLAPI PFNGLPOINTPARAMETERIPROC glad_glPointParameteri; #define glPointParameteri glad_glPointParameteri typedef void (APIENTRYP PFNGLPOINTPARAMETERIVPROC)(GLenum pname, const GLint *params); GLAPI PFNGLPOINTPARAMETERIVPROC glad_glPointParameteriv; #define glPointParameteriv glad_glPointParameteriv typedef void (APIENTRYP PFNGLFOGCOORDFPROC)(GLfloat coord); GLAPI PFNGLFOGCOORDFPROC glad_glFogCoordf; #define glFogCoordf glad_glFogCoordf typedef void (APIENTRYP PFNGLFOGCOORDFVPROC)(const GLfloat *coord); GLAPI PFNGLFOGCOORDFVPROC glad_glFogCoordfv; #define glFogCoordfv glad_glFogCoordfv typedef void (APIENTRYP PFNGLFOGCOORDDPROC)(GLdouble coord); GLAPI PFNGLFOGCOORDDPROC glad_glFogCoordd; #define glFogCoordd glad_glFogCoordd typedef void (APIENTRYP PFNGLFOGCOORDDVPROC)(const GLdouble *coord); GLAPI PFNGLFOGCOORDDVPROC glad_glFogCoorddv; #define glFogCoorddv glad_glFogCoorddv typedef void (APIENTRYP PFNGLFOGCOORDPOINTERPROC)(GLenum type, GLsizei stride, const void *pointer); GLAPI PFNGLFOGCOORDPOINTERPROC glad_glFogCoordPointer; #define glFogCoordPointer glad_glFogCoordPointer typedef void (APIENTRYP PFNGLSECONDARYCOLOR3BPROC)(GLbyte red, GLbyte green, GLbyte blue); GLAPI PFNGLSECONDARYCOLOR3BPROC glad_glSecondaryColor3b; #define glSecondaryColor3b glad_glSecondaryColor3b typedef void (APIENTRYP PFNGLSECONDARYCOLOR3BVPROC)(const GLbyte *v); GLAPI PFNGLSECONDARYCOLOR3BVPROC glad_glSecondaryColor3bv; #define glSecondaryColor3bv glad_glSecondaryColor3bv typedef void (APIENTRYP PFNGLSECONDARYCOLOR3DPROC)(GLdouble red, GLdouble green, GLdouble blue); GLAPI PFNGLSECONDARYCOLOR3DPROC glad_glSecondaryColor3d; #define glSecondaryColor3d glad_glSecondaryColor3d typedef void (APIENTRYP PFNGLSECONDARYCOLOR3DVPROC)(const GLdouble *v); GLAPI PFNGLSECONDARYCOLOR3DVPROC glad_glSecondaryColor3dv; #define glSecondaryColor3dv glad_glSecondaryColor3dv typedef void (APIENTRYP PFNGLSECONDARYCOLOR3FPROC)(GLfloat red, GLfloat green, GLfloat blue); GLAPI PFNGLSECONDARYCOLOR3FPROC glad_glSecondaryColor3f; #define glSecondaryColor3f glad_glSecondaryColor3f typedef void (APIENTRYP PFNGLSECONDARYCOLOR3FVPROC)(const GLfloat *v); GLAPI PFNGLSECONDARYCOLOR3FVPROC glad_glSecondaryColor3fv; #define glSecondaryColor3fv glad_glSecondaryColor3fv typedef void (APIENTRYP PFNGLSECONDARYCOLOR3IPROC)(GLint red, GLint green, GLint blue); GLAPI PFNGLSECONDARYCOLOR3IPROC glad_glSecondaryColor3i; #define glSecondaryColor3i glad_glSecondaryColor3i typedef void (APIENTRYP PFNGLSECONDARYCOLOR3IVPROC)(const GLint *v); GLAPI PFNGLSECONDARYCOLOR3IVPROC glad_glSecondaryColor3iv; #define glSecondaryColor3iv glad_glSecondaryColor3iv typedef void (APIENTRYP PFNGLSECONDARYCOLOR3SPROC)(GLshort red, GLshort green, GLshort blue); GLAPI PFNGLSECONDARYCOLOR3SPROC glad_glSecondaryColor3s; #define glSecondaryColor3s glad_glSecondaryColor3s typedef void (APIENTRYP PFNGLSECONDARYCOLOR3SVPROC)(const GLshort *v); GLAPI PFNGLSECONDARYCOLOR3SVPROC glad_glSecondaryColor3sv; #define glSecondaryColor3sv glad_glSecondaryColor3sv typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UBPROC)(GLubyte red, GLubyte green, GLubyte blue); GLAPI PFNGLSECONDARYCOLOR3UBPROC glad_glSecondaryColor3ub; #define glSecondaryColor3ub glad_glSecondaryColor3ub typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UBVPROC)(const GLubyte *v); GLAPI PFNGLSECONDARYCOLOR3UBVPROC glad_glSecondaryColor3ubv; #define glSecondaryColor3ubv glad_glSecondaryColor3ubv typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UIPROC)(GLuint red, GLuint green, GLuint blue); GLAPI PFNGLSECONDARYCOLOR3UIPROC glad_glSecondaryColor3ui; #define glSecondaryColor3ui glad_glSecondaryColor3ui typedef void (APIENTRYP PFNGLSECONDARYCOLOR3UIVPROC)(const GLuint *v); GLAPI PFNGLSECONDARYCOLOR3UIVPROC glad_glSecondaryColor3uiv; #define glSecondaryColor3uiv glad_glSecondaryColor3uiv typedef void (APIENTRYP PFNGLSECONDARYCOLOR3USPROC)(GLushort red, GLushort green, GLushort blue); GLAPI PFNGLSECONDARYCOLOR3USPROC glad_glSecondaryColor3us; #define glSecondaryColor3us glad_glSecondaryColor3us typedef void (APIENTRYP PFNGLSECONDARYCOLOR3USVPROC)(const GLushort *v); GLAPI PFNGLSECONDARYCOLOR3USVPROC glad_glSecondaryColor3usv; #define glSecondaryColor3usv glad_glSecondaryColor3usv typedef void (APIENTRYP PFNGLSECONDARYCOLORPOINTERPROC)(GLint size, GLenum type, GLsizei stride, const void *pointer); GLAPI PFNGLSECONDARYCOLORPOINTERPROC glad_glSecondaryColorPointer; #define glSecondaryColorPointer glad_glSecondaryColorPointer typedef void (APIENTRYP PFNGLWINDOWPOS2DPROC)(GLdouble x, GLdouble y); GLAPI PFNGLWINDOWPOS2DPROC glad_glWindowPos2d; #define glWindowPos2d glad_glWindowPos2d typedef void (APIENTRYP PFNGLWINDOWPOS2DVPROC)(const GLdouble *v); GLAPI PFNGLWINDOWPOS2DVPROC glad_glWindowPos2dv; #define glWindowPos2dv glad_glWindowPos2dv typedef void (APIENTRYP PFNGLWINDOWPOS2FPROC)(GLfloat x, GLfloat y); GLAPI PFNGLWINDOWPOS2FPROC glad_glWindowPos2f; #define glWindowPos2f glad_glWindowPos2f typedef void (APIENTRYP PFNGLWINDOWPOS2FVPROC)(const GLfloat *v); GLAPI PFNGLWINDOWPOS2FVPROC glad_glWindowPos2fv; #define glWindowPos2fv glad_glWindowPos2fv typedef void (APIENTRYP PFNGLWINDOWPOS2IPROC)(GLint x, GLint y); GLAPI PFNGLWINDOWPOS2IPROC glad_glWindowPos2i; #define glWindowPos2i glad_glWindowPos2i typedef void (APIENTRYP PFNGLWINDOWPOS2IVPROC)(const GLint *v); GLAPI PFNGLWINDOWPOS2IVPROC glad_glWindowPos2iv; #define glWindowPos2iv glad_glWindowPos2iv typedef void (APIENTRYP PFNGLWINDOWPOS2SPROC)(GLshort x, GLshort y); GLAPI PFNGLWINDOWPOS2SPROC glad_glWindowPos2s; #define glWindowPos2s glad_glWindowPos2s typedef void (APIENTRYP PFNGLWINDOWPOS2SVPROC)(const GLshort *v); GLAPI PFNGLWINDOWPOS2SVPROC glad_glWindowPos2sv; #define glWindowPos2sv glad_glWindowPos2sv typedef void (APIENTRYP PFNGLWINDOWPOS3DPROC)(GLdouble x, GLdouble y, GLdouble z); GLAPI PFNGLWINDOWPOS3DPROC glad_glWindowPos3d; #define glWindowPos3d glad_glWindowPos3d typedef void (APIENTRYP PFNGLWINDOWPOS3DVPROC)(const GLdouble *v); GLAPI PFNGLWINDOWPOS3DVPROC glad_glWindowPos3dv; #define glWindowPos3dv glad_glWindowPos3dv typedef void (APIENTRYP PFNGLWINDOWPOS3FPROC)(GLfloat x, GLfloat y, GLfloat z); GLAPI PFNGLWINDOWPOS3FPROC glad_glWindowPos3f; #define glWindowPos3f glad_glWindowPos3f typedef void (APIENTRYP PFNGLWINDOWPOS3FVPROC)(const GLfloat *v); GLAPI PFNGLWINDOWPOS3FVPROC glad_glWindowPos3fv; #define glWindowPos3fv glad_glWindowPos3fv typedef void (APIENTRYP PFNGLWINDOWPOS3IPROC)(GLint x, GLint y, GLint z); GLAPI PFNGLWINDOWPOS3IPROC glad_glWindowPos3i; #define glWindowPos3i glad_glWindowPos3i typedef void (APIENTRYP PFNGLWINDOWPOS3IVPROC)(const GLint *v); GLAPI PFNGLWINDOWPOS3IVPROC glad_glWindowPos3iv; #define glWindowPos3iv glad_glWindowPos3iv typedef void (APIENTRYP PFNGLWINDOWPOS3SPROC)(GLshort x, GLshort y, GLshort z); GLAPI PFNGLWINDOWPOS3SPROC glad_glWindowPos3s; #define glWindowPos3s glad_glWindowPos3s typedef void (APIENTRYP PFNGLWINDOWPOS3SVPROC)(const GLshort *v); GLAPI PFNGLWINDOWPOS3SVPROC glad_glWindowPos3sv; #define glWindowPos3sv glad_glWindowPos3sv typedef void (APIENTRYP PFNGLBLENDCOLORPROC)(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); GLAPI PFNGLBLENDCOLORPROC glad_glBlendColor; #define glBlendColor glad_glBlendColor typedef void (APIENTRYP PFNGLBLENDEQUATIONPROC)(GLenum mode); GLAPI PFNGLBLENDEQUATIONPROC glad_glBlendEquation; #define glBlendEquation glad_glBlendEquation #endif #ifndef GL_VERSION_1_5 #define GL_VERSION_1_5 1 GLAPI int GLAD_GL_VERSION_1_5; typedef void (APIENTRYP PFNGLGENQUERIESPROC)(GLsizei n, GLuint *ids); GLAPI PFNGLGENQUERIESPROC glad_glGenQueries; #define glGenQueries glad_glGenQueries typedef void (APIENTRYP PFNGLDELETEQUERIESPROC)(GLsizei n, const GLuint *ids); GLAPI PFNGLDELETEQUERIESPROC glad_glDeleteQueries; #define glDeleteQueries glad_glDeleteQueries typedef GLboolean (APIENTRYP PFNGLISQUERYPROC)(GLuint id); GLAPI PFNGLISQUERYPROC glad_glIsQuery; #define glIsQuery glad_glIsQuery typedef void (APIENTRYP PFNGLBEGINQUERYPROC)(GLenum target, GLuint id); GLAPI PFNGLBEGINQUERYPROC glad_glBeginQuery; #define glBeginQuery glad_glBeginQuery typedef void (APIENTRYP PFNGLENDQUERYPROC)(GLenum target); GLAPI PFNGLENDQUERYPROC glad_glEndQuery; #define glEndQuery glad_glEndQuery typedef void (APIENTRYP PFNGLGETQUERYIVPROC)(GLenum target, GLenum pname, GLint *params); GLAPI PFNGLGETQUERYIVPROC glad_glGetQueryiv; #define glGetQueryiv glad_glGetQueryiv typedef void (APIENTRYP PFNGLGETQUERYOBJECTIVPROC)(GLuint id, GLenum pname, GLint *params); GLAPI PFNGLGETQUERYOBJECTIVPROC glad_glGetQueryObjectiv; #define glGetQueryObjectiv glad_glGetQueryObjectiv typedef void (APIENTRYP PFNGLGETQUERYOBJECTUIVPROC)(GLuint id, GLenum pname, GLuint *params); GLAPI PFNGLGETQUERYOBJECTUIVPROC glad_glGetQueryObjectuiv; #define glGetQueryObjectuiv glad_glGetQueryObjectuiv typedef void (APIENTRYP PFNGLBINDBUFFERPROC)(GLenum target, GLuint buffer); GLAPI PFNGLBINDBUFFERPROC glad_glBindBuffer; #define glBindBuffer glad_glBindBuffer typedef void (APIENTRYP PFNGLDELETEBUFFERSPROC)(GLsizei n, const GLuint *buffers); GLAPI PFNGLDELETEBUFFERSPROC glad_glDeleteBuffers; #define glDeleteBuffers glad_glDeleteBuffers typedef void (APIENTRYP PFNGLGENBUFFERSPROC)(GLsizei n, GLuint *buffers); GLAPI PFNGLGENBUFFERSPROC glad_glGenBuffers; #define glGenBuffers glad_glGenBuffers typedef GLboolean (APIENTRYP PFNGLISBUFFERPROC)(GLuint buffer); GLAPI PFNGLISBUFFERPROC glad_glIsBuffer; #define glIsBuffer glad_glIsBuffer typedef void (APIENTRYP PFNGLBUFFERDATAPROC)(GLenum target, GLsizeiptr size, const void *data, GLenum usage); GLAPI PFNGLBUFFERDATAPROC glad_glBufferData; #define glBufferData glad_glBufferData typedef void (APIENTRYP PFNGLBUFFERSUBDATAPROC)(GLenum target, GLintptr offset, GLsizeiptr size, const void *data); GLAPI PFNGLBUFFERSUBDATAPROC glad_glBufferSubData; #define glBufferSubData glad_glBufferSubData typedef void (APIENTRYP PFNGLGETBUFFERSUBDATAPROC)(GLenum target, GLintptr offset, GLsizeiptr size, void *data); GLAPI PFNGLGETBUFFERSUBDATAPROC glad_glGetBufferSubData; #define glGetBufferSubData glad_glGetBufferSubData typedef void * (APIENTRYP PFNGLMAPBUFFERPROC)(GLenum target, GLenum access); GLAPI PFNGLMAPBUFFERPROC glad_glMapBuffer; #define glMapBuffer glad_glMapBuffer typedef GLboolean (APIENTRYP PFNGLUNMAPBUFFERPROC)(GLenum target); GLAPI PFNGLUNMAPBUFFERPROC glad_glUnmapBuffer; #define glUnmapBuffer glad_glUnmapBuffer typedef void (APIENTRYP PFNGLGETBUFFERPARAMETERIVPROC)(GLenum target, GLenum pname, GLint *params); GLAPI PFNGLGETBUFFERPARAMETERIVPROC glad_glGetBufferParameteriv; #define glGetBufferParameteriv glad_glGetBufferParameteriv typedef void (APIENTRYP PFNGLGETBUFFERPOINTERVPROC)(GLenum target, GLenum pname, void **params); GLAPI PFNGLGETBUFFERPOINTERVPROC glad_glGetBufferPointerv; #define glGetBufferPointerv glad_glGetBufferPointerv #endif #ifndef GL_VERSION_2_0 #define GL_VERSION_2_0 1 GLAPI int GLAD_GL_VERSION_2_0; typedef void (APIENTRYP PFNGLBLENDEQUATIONSEPARATEPROC)(GLenum modeRGB, GLenum modeAlpha); GLAPI PFNGLBLENDEQUATIONSEPARATEPROC glad_glBlendEquationSeparate; #define glBlendEquationSeparate glad_glBlendEquationSeparate typedef void (APIENTRYP PFNGLDRAWBUFFERSPROC)(GLsizei n, const GLenum *bufs); GLAPI PFNGLDRAWBUFFERSPROC glad_glDrawBuffers; #define glDrawBuffers glad_glDrawBuffers typedef void (APIENTRYP PFNGLSTENCILOPSEPARATEPROC)(GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass); GLAPI PFNGLSTENCILOPSEPARATEPROC glad_glStencilOpSeparate; #define glStencilOpSeparate glad_glStencilOpSeparate typedef void (APIENTRYP PFNGLSTENCILFUNCSEPARATEPROC)(GLenum face, GLenum func, GLint ref, GLuint mask); GLAPI PFNGLSTENCILFUNCSEPARATEPROC glad_glStencilFuncSeparate; #define glStencilFuncSeparate glad_glStencilFuncSeparate typedef void (APIENTRYP PFNGLSTENCILMASKSEPARATEPROC)(GLenum face, GLuint mask); GLAPI PFNGLSTENCILMASKSEPARATEPROC glad_glStencilMaskSeparate; #define glStencilMaskSeparate glad_glStencilMaskSeparate typedef void (APIENTRYP PFNGLATTACHSHADERPROC)(GLuint program, GLuint shader); GLAPI PFNGLATTACHSHADERPROC glad_glAttachShader; #define glAttachShader glad_glAttachShader typedef void (APIENTRYP PFNGLBINDATTRIBLOCATIONPROC)(GLuint program, GLuint index, const GLchar *name); GLAPI PFNGLBINDATTRIBLOCATIONPROC glad_glBindAttribLocation; #define glBindAttribLocation glad_glBindAttribLocation typedef void (APIENTRYP PFNGLCOMPILESHADERPROC)(GLuint shader); GLAPI PFNGLCOMPILESHADERPROC glad_glCompileShader; #define glCompileShader glad_glCompileShader typedef GLuint (APIENTRYP PFNGLCREATEPROGRAMPROC)(void); GLAPI PFNGLCREATEPROGRAMPROC glad_glCreateProgram; #define glCreateProgram glad_glCreateProgram typedef GLuint (APIENTRYP PFNGLCREATESHADERPROC)(GLenum type); GLAPI PFNGLCREATESHADERPROC glad_glCreateShader; #define glCreateShader glad_glCreateShader typedef void (APIENTRYP PFNGLDELETEPROGRAMPROC)(GLuint program); GLAPI PFNGLDELETEPROGRAMPROC glad_glDeleteProgram; #define glDeleteProgram glad_glDeleteProgram typedef void (APIENTRYP PFNGLDELETESHADERPROC)(GLuint shader); GLAPI PFNGLDELETESHADERPROC glad_glDeleteShader; #define glDeleteShader glad_glDeleteShader typedef void (APIENTRYP PFNGLDETACHSHADERPROC)(GLuint program, GLuint shader); GLAPI PFNGLDETACHSHADERPROC glad_glDetachShader; #define glDetachShader glad_glDetachShader typedef void (APIENTRYP PFNGLDISABLEVERTEXATTRIBARRAYPROC)(GLuint index); GLAPI PFNGLDISABLEVERTEXATTRIBARRAYPROC glad_glDisableVertexAttribArray; #define glDisableVertexAttribArray glad_glDisableVertexAttribArray typedef void (APIENTRYP PFNGLENABLEVERTEXATTRIBARRAYPROC)(GLuint index); GLAPI PFNGLENABLEVERTEXATTRIBARRAYPROC glad_glEnableVertexAttribArray; #define glEnableVertexAttribArray glad_glEnableVertexAttribArray typedef void (APIENTRYP PFNGLGETACTIVEATTRIBPROC)(GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name); GLAPI PFNGLGETACTIVEATTRIBPROC glad_glGetActiveAttrib; #define glGetActiveAttrib glad_glGetActiveAttrib typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMPROC)(GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name); GLAPI PFNGLGETACTIVEUNIFORMPROC glad_glGetActiveUniform; #define glGetActiveUniform glad_glGetActiveUniform typedef void (APIENTRYP PFNGLGETATTACHEDSHADERSPROC)(GLuint program, GLsizei maxCount, GLsizei *count, GLuint *shaders); GLAPI PFNGLGETATTACHEDSHADERSPROC glad_glGetAttachedShaders; #define glGetAttachedShaders glad_glGetAttachedShaders typedef GLint (APIENTRYP PFNGLGETATTRIBLOCATIONPROC)(GLuint program, const GLchar *name); GLAPI PFNGLGETATTRIBLOCATIONPROC glad_glGetAttribLocation; #define glGetAttribLocation glad_glGetAttribLocation typedef void (APIENTRYP PFNGLGETPROGRAMIVPROC)(GLuint program, GLenum pname, GLint *params); GLAPI PFNGLGETPROGRAMIVPROC glad_glGetProgramiv; #define glGetProgramiv glad_glGetProgramiv typedef void (APIENTRYP PFNGLGETPROGRAMINFOLOGPROC)(GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog); GLAPI PFNGLGETPROGRAMINFOLOGPROC glad_glGetProgramInfoLog; #define glGetProgramInfoLog glad_glGetProgramInfoLog typedef void (APIENTRYP PFNGLGETSHADERIVPROC)(GLuint shader, GLenum pname, GLint *params); GLAPI PFNGLGETSHADERIVPROC glad_glGetShaderiv; #define glGetShaderiv glad_glGetShaderiv typedef void (APIENTRYP PFNGLGETSHADERINFOLOGPROC)(GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog); GLAPI PFNGLGETSHADERINFOLOGPROC glad_glGetShaderInfoLog; #define glGetShaderInfoLog glad_glGetShaderInfoLog typedef void (APIENTRYP PFNGLGETSHADERSOURCEPROC)(GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *source); GLAPI PFNGLGETSHADERSOURCEPROC glad_glGetShaderSource; #define glGetShaderSource glad_glGetShaderSource typedef GLint (APIENTRYP PFNGLGETUNIFORMLOCATIONPROC)(GLuint program, const GLchar *name); GLAPI PFNGLGETUNIFORMLOCATIONPROC glad_glGetUniformLocation; #define glGetUniformLocation glad_glGetUniformLocation typedef void (APIENTRYP PFNGLGETUNIFORMFVPROC)(GLuint program, GLint location, GLfloat *params); GLAPI PFNGLGETUNIFORMFVPROC glad_glGetUniformfv; #define glGetUniformfv glad_glGetUniformfv typedef void (APIENTRYP PFNGLGETUNIFORMIVPROC)(GLuint program, GLint location, GLint *params); GLAPI PFNGLGETUNIFORMIVPROC glad_glGetUniformiv; #define glGetUniformiv glad_glGetUniformiv typedef void (APIENTRYP PFNGLGETVERTEXATTRIBDVPROC)(GLuint index, GLenum pname, GLdouble *params); GLAPI PFNGLGETVERTEXATTRIBDVPROC glad_glGetVertexAttribdv; #define glGetVertexAttribdv glad_glGetVertexAttribdv typedef void (APIENTRYP PFNGLGETVERTEXATTRIBFVPROC)(GLuint index, GLenum pname, GLfloat *params); GLAPI PFNGLGETVERTEXATTRIBFVPROC glad_glGetVertexAttribfv; #define glGetVertexAttribfv glad_glGetVertexAttribfv typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIVPROC)(GLuint index, GLenum pname, GLint *params); GLAPI PFNGLGETVERTEXATTRIBIVPROC glad_glGetVertexAttribiv; #define glGetVertexAttribiv glad_glGetVertexAttribiv typedef void (APIENTRYP PFNGLGETVERTEXATTRIBPOINTERVPROC)(GLuint index, GLenum pname, void **pointer); GLAPI PFNGLGETVERTEXATTRIBPOINTERVPROC glad_glGetVertexAttribPointerv; #define glGetVertexAttribPointerv glad_glGetVertexAttribPointerv typedef GLboolean (APIENTRYP PFNGLISPROGRAMPROC)(GLuint program); GLAPI PFNGLISPROGRAMPROC glad_glIsProgram; #define glIsProgram glad_glIsProgram typedef GLboolean (APIENTRYP PFNGLISSHADERPROC)(GLuint shader); GLAPI PFNGLISSHADERPROC glad_glIsShader; #define glIsShader glad_glIsShader typedef void (APIENTRYP PFNGLLINKPROGRAMPROC)(GLuint program); GLAPI PFNGLLINKPROGRAMPROC glad_glLinkProgram; #define glLinkProgram glad_glLinkProgram typedef void (APIENTRYP PFNGLSHADERSOURCEPROC)(GLuint shader, GLsizei count, const GLchar *const*string, const GLint *length); GLAPI PFNGLSHADERSOURCEPROC glad_glShaderSource; #define glShaderSource glad_glShaderSource typedef void (APIENTRYP PFNGLUSEPROGRAMPROC)(GLuint program); GLAPI PFNGLUSEPROGRAMPROC glad_glUseProgram; #define glUseProgram glad_glUseProgram typedef void (APIENTRYP PFNGLUNIFORM1FPROC)(GLint location, GLfloat v0); GLAPI PFNGLUNIFORM1FPROC glad_glUniform1f; #define glUniform1f glad_glUniform1f typedef void (APIENTRYP PFNGLUNIFORM2FPROC)(GLint location, GLfloat v0, GLfloat v1); GLAPI PFNGLUNIFORM2FPROC glad_glUniform2f; #define glUniform2f glad_glUniform2f typedef void (APIENTRYP PFNGLUNIFORM3FPROC)(GLint location, GLfloat v0, GLfloat v1, GLfloat v2); GLAPI PFNGLUNIFORM3FPROC glad_glUniform3f; #define glUniform3f glad_glUniform3f typedef void (APIENTRYP PFNGLUNIFORM4FPROC)(GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); GLAPI PFNGLUNIFORM4FPROC glad_glUniform4f; #define glUniform4f glad_glUniform4f typedef void (APIENTRYP PFNGLUNIFORM1IPROC)(GLint location, GLint v0); GLAPI PFNGLUNIFORM1IPROC glad_glUniform1i; #define glUniform1i glad_glUniform1i typedef void (APIENTRYP PFNGLUNIFORM2IPROC)(GLint location, GLint v0, GLint v1); GLAPI PFNGLUNIFORM2IPROC glad_glUniform2i; #define glUniform2i glad_glUniform2i typedef void (APIENTRYP PFNGLUNIFORM3IPROC)(GLint location, GLint v0, GLint v1, GLint v2); GLAPI PFNGLUNIFORM3IPROC glad_glUniform3i; #define glUniform3i glad_glUniform3i typedef void (APIENTRYP PFNGLUNIFORM4IPROC)(GLint location, GLint v0, GLint v1, GLint v2, GLint v3); GLAPI PFNGLUNIFORM4IPROC glad_glUniform4i; #define glUniform4i glad_glUniform4i typedef void (APIENTRYP PFNGLUNIFORM1FVPROC)(GLint location, GLsizei count, const GLfloat *value); GLAPI PFNGLUNIFORM1FVPROC glad_glUniform1fv; #define glUniform1fv glad_glUniform1fv typedef void (APIENTRYP PFNGLUNIFORM2FVPROC)(GLint location, GLsizei count, const GLfloat *value); GLAPI PFNGLUNIFORM2FVPROC glad_glUniform2fv; #define glUniform2fv glad_glUniform2fv typedef void (APIENTRYP PFNGLUNIFORM3FVPROC)(GLint location, GLsizei count, const GLfloat *value); GLAPI PFNGLUNIFORM3FVPROC glad_glUniform3fv; #define glUniform3fv glad_glUniform3fv typedef void (APIENTRYP PFNGLUNIFORM4FVPROC)(GLint location, GLsizei count, const GLfloat *value); GLAPI PFNGLUNIFORM4FVPROC glad_glUniform4fv; #define glUniform4fv glad_glUniform4fv typedef void (APIENTRYP PFNGLUNIFORM1IVPROC)(GLint location, GLsizei count, const GLint *value); GLAPI PFNGLUNIFORM1IVPROC glad_glUniform1iv; #define glUniform1iv glad_glUniform1iv typedef void (APIENTRYP PFNGLUNIFORM2IVPROC)(GLint location, GLsizei count, const GLint *value); GLAPI PFNGLUNIFORM2IVPROC glad_glUniform2iv; #define glUniform2iv glad_glUniform2iv typedef void (APIENTRYP PFNGLUNIFORM3IVPROC)(GLint location, GLsizei count, const GLint *value); GLAPI PFNGLUNIFORM3IVPROC glad_glUniform3iv; #define glUniform3iv glad_glUniform3iv typedef void (APIENTRYP PFNGLUNIFORM4IVPROC)(GLint location, GLsizei count, const GLint *value); GLAPI PFNGLUNIFORM4IVPROC glad_glUniform4iv; #define glUniform4iv glad_glUniform4iv typedef void (APIENTRYP PFNGLUNIFORMMATRIX2FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GLAPI PFNGLUNIFORMMATRIX2FVPROC glad_glUniformMatrix2fv; #define glUniformMatrix2fv glad_glUniformMatrix2fv typedef void (APIENTRYP PFNGLUNIFORMMATRIX3FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GLAPI PFNGLUNIFORMMATRIX3FVPROC glad_glUniformMatrix3fv; #define glUniformMatrix3fv glad_glUniformMatrix3fv typedef void (APIENTRYP PFNGLUNIFORMMATRIX4FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GLAPI PFNGLUNIFORMMATRIX4FVPROC glad_glUniformMatrix4fv; #define glUniformMatrix4fv glad_glUniformMatrix4fv typedef void (APIENTRYP PFNGLVALIDATEPROGRAMPROC)(GLuint program); GLAPI PFNGLVALIDATEPROGRAMPROC glad_glValidateProgram; #define glValidateProgram glad_glValidateProgram typedef void (APIENTRYP PFNGLVERTEXATTRIB1DPROC)(GLuint index, GLdouble x); GLAPI PFNGLVERTEXATTRIB1DPROC glad_glVertexAttrib1d; #define glVertexAttrib1d glad_glVertexAttrib1d typedef void (APIENTRYP PFNGLVERTEXATTRIB1DVPROC)(GLuint index, const GLdouble *v); GLAPI PFNGLVERTEXATTRIB1DVPROC glad_glVertexAttrib1dv; #define glVertexAttrib1dv glad_glVertexAttrib1dv typedef void (APIENTRYP PFNGLVERTEXATTRIB1FPROC)(GLuint index, GLfloat x); GLAPI PFNGLVERTEXATTRIB1FPROC glad_glVertexAttrib1f; #define glVertexAttrib1f glad_glVertexAttrib1f typedef void (APIENTRYP PFNGLVERTEXATTRIB1FVPROC)(GLuint index, const GLfloat *v); GLAPI PFNGLVERTEXATTRIB1FVPROC glad_glVertexAttrib1fv; #define glVertexAttrib1fv glad_glVertexAttrib1fv typedef void (APIENTRYP PFNGLVERTEXATTRIB1SPROC)(GLuint index, GLshort x); GLAPI PFNGLVERTEXATTRIB1SPROC glad_glVertexAttrib1s; #define glVertexAttrib1s glad_glVertexAttrib1s typedef void (APIENTRYP PFNGLVERTEXATTRIB1SVPROC)(GLuint index, const GLshort *v); GLAPI PFNGLVERTEXATTRIB1SVPROC glad_glVertexAttrib1sv; #define glVertexAttrib1sv glad_glVertexAttrib1sv typedef void (APIENTRYP PFNGLVERTEXATTRIB2DPROC)(GLuint index, GLdouble x, GLdouble y); GLAPI PFNGLVERTEXATTRIB2DPROC glad_glVertexAttrib2d; #define glVertexAttrib2d glad_glVertexAttrib2d typedef void (APIENTRYP PFNGLVERTEXATTRIB2DVPROC)(GLuint index, const GLdouble *v); GLAPI PFNGLVERTEXATTRIB2DVPROC glad_glVertexAttrib2dv; #define glVertexAttrib2dv glad_glVertexAttrib2dv typedef void (APIENTRYP PFNGLVERTEXATTRIB2FPROC)(GLuint index, GLfloat x, GLfloat y); GLAPI PFNGLVERTEXATTRIB2FPROC glad_glVertexAttrib2f; #define glVertexAttrib2f glad_glVertexAttrib2f typedef void (APIENTRYP PFNGLVERTEXATTRIB2FVPROC)(GLuint index, const GLfloat *v); GLAPI PFNGLVERTEXATTRIB2FVPROC glad_glVertexAttrib2fv; #define glVertexAttrib2fv glad_glVertexAttrib2fv typedef void (APIENTRYP PFNGLVERTEXATTRIB2SPROC)(GLuint index, GLshort x, GLshort y); GLAPI PFNGLVERTEXATTRIB2SPROC glad_glVertexAttrib2s; #define glVertexAttrib2s glad_glVertexAttrib2s typedef void (APIENTRYP PFNGLVERTEXATTRIB2SVPROC)(GLuint index, const GLshort *v); GLAPI PFNGLVERTEXATTRIB2SVPROC glad_glVertexAttrib2sv; #define glVertexAttrib2sv glad_glVertexAttrib2sv typedef void (APIENTRYP PFNGLVERTEXATTRIB3DPROC)(GLuint index, GLdouble x, GLdouble y, GLdouble z); GLAPI PFNGLVERTEXATTRIB3DPROC glad_glVertexAttrib3d; #define glVertexAttrib3d glad_glVertexAttrib3d typedef void (APIENTRYP PFNGLVERTEXATTRIB3DVPROC)(GLuint index, const GLdouble *v); GLAPI PFNGLVERTEXATTRIB3DVPROC glad_glVertexAttrib3dv; #define glVertexAttrib3dv glad_glVertexAttrib3dv typedef void (APIENTRYP PFNGLVERTEXATTRIB3FPROC)(GLuint index, GLfloat x, GLfloat y, GLfloat z); GLAPI PFNGLVERTEXATTRIB3FPROC glad_glVertexAttrib3f; #define glVertexAttrib3f glad_glVertexAttrib3f typedef void (APIENTRYP PFNGLVERTEXATTRIB3FVPROC)(GLuint index, const GLfloat *v); GLAPI PFNGLVERTEXATTRIB3FVPROC glad_glVertexAttrib3fv; #define glVertexAttrib3fv glad_glVertexAttrib3fv typedef void (APIENTRYP PFNGLVERTEXATTRIB3SPROC)(GLuint index, GLshort x, GLshort y, GLshort z); GLAPI PFNGLVERTEXATTRIB3SPROC glad_glVertexAttrib3s; #define glVertexAttrib3s glad_glVertexAttrib3s typedef void (APIENTRYP PFNGLVERTEXATTRIB3SVPROC)(GLuint index, const GLshort *v); GLAPI PFNGLVERTEXATTRIB3SVPROC glad_glVertexAttrib3sv; #define glVertexAttrib3sv glad_glVertexAttrib3sv typedef void (APIENTRYP PFNGLVERTEXATTRIB4NBVPROC)(GLuint index, const GLbyte *v); GLAPI PFNGLVERTEXATTRIB4NBVPROC glad_glVertexAttrib4Nbv; #define glVertexAttrib4Nbv glad_glVertexAttrib4Nbv typedef void (APIENTRYP PFNGLVERTEXATTRIB4NIVPROC)(GLuint index, const GLint *v); GLAPI PFNGLVERTEXATTRIB4NIVPROC glad_glVertexAttrib4Niv; #define glVertexAttrib4Niv glad_glVertexAttrib4Niv typedef void (APIENTRYP PFNGLVERTEXATTRIB4NSVPROC)(GLuint index, const GLshort *v); GLAPI PFNGLVERTEXATTRIB4NSVPROC glad_glVertexAttrib4Nsv; #define glVertexAttrib4Nsv glad_glVertexAttrib4Nsv typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUBPROC)(GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w); GLAPI PFNGLVERTEXATTRIB4NUBPROC glad_glVertexAttrib4Nub; #define glVertexAttrib4Nub glad_glVertexAttrib4Nub typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUBVPROC)(GLuint index, const GLubyte *v); GLAPI PFNGLVERTEXATTRIB4NUBVPROC glad_glVertexAttrib4Nubv; #define glVertexAttrib4Nubv glad_glVertexAttrib4Nubv typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUIVPROC)(GLuint index, const GLuint *v); GLAPI PFNGLVERTEXATTRIB4NUIVPROC glad_glVertexAttrib4Nuiv; #define glVertexAttrib4Nuiv glad_glVertexAttrib4Nuiv typedef void (APIENTRYP PFNGLVERTEXATTRIB4NUSVPROC)(GLuint index, const GLushort *v); GLAPI PFNGLVERTEXATTRIB4NUSVPROC glad_glVertexAttrib4Nusv; #define glVertexAttrib4Nusv glad_glVertexAttrib4Nusv typedef void (APIENTRYP PFNGLVERTEXATTRIB4BVPROC)(GLuint index, const GLbyte *v); GLAPI PFNGLVERTEXATTRIB4BVPROC glad_glVertexAttrib4bv; #define glVertexAttrib4bv glad_glVertexAttrib4bv typedef void (APIENTRYP PFNGLVERTEXATTRIB4DPROC)(GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); GLAPI PFNGLVERTEXATTRIB4DPROC glad_glVertexAttrib4d; #define glVertexAttrib4d glad_glVertexAttrib4d typedef void (APIENTRYP PFNGLVERTEXATTRIB4DVPROC)(GLuint index, const GLdouble *v); GLAPI PFNGLVERTEXATTRIB4DVPROC glad_glVertexAttrib4dv; #define glVertexAttrib4dv glad_glVertexAttrib4dv typedef void (APIENTRYP PFNGLVERTEXATTRIB4FPROC)(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); GLAPI PFNGLVERTEXATTRIB4FPROC glad_glVertexAttrib4f; #define glVertexAttrib4f glad_glVertexAttrib4f typedef void (APIENTRYP PFNGLVERTEXATTRIB4FVPROC)(GLuint index, const GLfloat *v); GLAPI PFNGLVERTEXATTRIB4FVPROC glad_glVertexAttrib4fv; #define glVertexAttrib4fv glad_glVertexAttrib4fv typedef void (APIENTRYP PFNGLVERTEXATTRIB4IVPROC)(GLuint index, const GLint *v); GLAPI PFNGLVERTEXATTRIB4IVPROC glad_glVertexAttrib4iv; #define glVertexAttrib4iv glad_glVertexAttrib4iv typedef void (APIENTRYP PFNGLVERTEXATTRIB4SPROC)(GLuint index, GLshort x, GLshort y, GLshort z, GLshort w); GLAPI PFNGLVERTEXATTRIB4SPROC glad_glVertexAttrib4s; #define glVertexAttrib4s glad_glVertexAttrib4s typedef void (APIENTRYP PFNGLVERTEXATTRIB4SVPROC)(GLuint index, const GLshort *v); GLAPI PFNGLVERTEXATTRIB4SVPROC glad_glVertexAttrib4sv; #define glVertexAttrib4sv glad_glVertexAttrib4sv typedef void (APIENTRYP PFNGLVERTEXATTRIB4UBVPROC)(GLuint index, const GLubyte *v); GLAPI PFNGLVERTEXATTRIB4UBVPROC glad_glVertexAttrib4ubv; #define glVertexAttrib4ubv glad_glVertexAttrib4ubv typedef void (APIENTRYP PFNGLVERTEXATTRIB4UIVPROC)(GLuint index, const GLuint *v); GLAPI PFNGLVERTEXATTRIB4UIVPROC glad_glVertexAttrib4uiv; #define glVertexAttrib4uiv glad_glVertexAttrib4uiv typedef void (APIENTRYP PFNGLVERTEXATTRIB4USVPROC)(GLuint index, const GLushort *v); GLAPI PFNGLVERTEXATTRIB4USVPROC glad_glVertexAttrib4usv; #define glVertexAttrib4usv glad_glVertexAttrib4usv typedef void (APIENTRYP PFNGLVERTEXATTRIBPOINTERPROC)(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer); GLAPI PFNGLVERTEXATTRIBPOINTERPROC glad_glVertexAttribPointer; #define glVertexAttribPointer glad_glVertexAttribPointer #endif #ifndef GL_VERSION_2_1 #define GL_VERSION_2_1 1 GLAPI int GLAD_GL_VERSION_2_1; typedef void (APIENTRYP PFNGLUNIFORMMATRIX2X3FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GLAPI PFNGLUNIFORMMATRIX2X3FVPROC glad_glUniformMatrix2x3fv; #define glUniformMatrix2x3fv glad_glUniformMatrix2x3fv typedef void (APIENTRYP PFNGLUNIFORMMATRIX3X2FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GLAPI PFNGLUNIFORMMATRIX3X2FVPROC glad_glUniformMatrix3x2fv; #define glUniformMatrix3x2fv glad_glUniformMatrix3x2fv typedef void (APIENTRYP PFNGLUNIFORMMATRIX2X4FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GLAPI PFNGLUNIFORMMATRIX2X4FVPROC glad_glUniformMatrix2x4fv; #define glUniformMatrix2x4fv glad_glUniformMatrix2x4fv typedef void (APIENTRYP PFNGLUNIFORMMATRIX4X2FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GLAPI PFNGLUNIFORMMATRIX4X2FVPROC glad_glUniformMatrix4x2fv; #define glUniformMatrix4x2fv glad_glUniformMatrix4x2fv typedef void (APIENTRYP PFNGLUNIFORMMATRIX3X4FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GLAPI PFNGLUNIFORMMATRIX3X4FVPROC glad_glUniformMatrix3x4fv; #define glUniformMatrix3x4fv glad_glUniformMatrix3x4fv typedef void (APIENTRYP PFNGLUNIFORMMATRIX4X3FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GLAPI PFNGLUNIFORMMATRIX4X3FVPROC glad_glUniformMatrix4x3fv; #define glUniformMatrix4x3fv glad_glUniformMatrix4x3fv #endif #ifndef GL_VERSION_3_0 #define GL_VERSION_3_0 1 GLAPI int GLAD_GL_VERSION_3_0; typedef void (APIENTRYP PFNGLCOLORMASKIPROC)(GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a); GLAPI PFNGLCOLORMASKIPROC glad_glColorMaski; #define glColorMaski glad_glColorMaski typedef void (APIENTRYP PFNGLGETBOOLEANI_VPROC)(GLenum target, GLuint index, GLboolean *data); GLAPI PFNGLGETBOOLEANI_VPROC glad_glGetBooleani_v; #define glGetBooleani_v glad_glGetBooleani_v typedef void (APIENTRYP PFNGLGETINTEGERI_VPROC)(GLenum target, GLuint index, GLint *data); GLAPI PFNGLGETINTEGERI_VPROC glad_glGetIntegeri_v; #define glGetIntegeri_v glad_glGetIntegeri_v typedef void (APIENTRYP PFNGLENABLEIPROC)(GLenum target, GLuint index); GLAPI PFNGLENABLEIPROC glad_glEnablei; #define glEnablei glad_glEnablei typedef void (APIENTRYP PFNGLDISABLEIPROC)(GLenum target, GLuint index); GLAPI PFNGLDISABLEIPROC glad_glDisablei; #define glDisablei glad_glDisablei typedef GLboolean (APIENTRYP PFNGLISENABLEDIPROC)(GLenum target, GLuint index); GLAPI PFNGLISENABLEDIPROC glad_glIsEnabledi; #define glIsEnabledi glad_glIsEnabledi typedef void (APIENTRYP PFNGLBEGINTRANSFORMFEEDBACKPROC)(GLenum primitiveMode); GLAPI PFNGLBEGINTRANSFORMFEEDBACKPROC glad_glBeginTransformFeedback; #define glBeginTransformFeedback glad_glBeginTransformFeedback typedef void (APIENTRYP PFNGLENDTRANSFORMFEEDBACKPROC)(void); GLAPI PFNGLENDTRANSFORMFEEDBACKPROC glad_glEndTransformFeedback; #define glEndTransformFeedback glad_glEndTransformFeedback typedef void (APIENTRYP PFNGLBINDBUFFERRANGEPROC)(GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size); GLAPI PFNGLBINDBUFFERRANGEPROC glad_glBindBufferRange; #define glBindBufferRange glad_glBindBufferRange typedef void (APIENTRYP PFNGLBINDBUFFERBASEPROC)(GLenum target, GLuint index, GLuint buffer); GLAPI PFNGLBINDBUFFERBASEPROC glad_glBindBufferBase; #define glBindBufferBase glad_glBindBufferBase typedef void (APIENTRYP PFNGLTRANSFORMFEEDBACKVARYINGSPROC)(GLuint program, GLsizei count, const GLchar *const*varyings, GLenum bufferMode); GLAPI PFNGLTRANSFORMFEEDBACKVARYINGSPROC glad_glTransformFeedbackVaryings; #define glTransformFeedbackVaryings glad_glTransformFeedbackVaryings typedef void (APIENTRYP PFNGLGETTRANSFORMFEEDBACKVARYINGPROC)(GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name); GLAPI PFNGLGETTRANSFORMFEEDBACKVARYINGPROC glad_glGetTransformFeedbackVarying; #define glGetTransformFeedbackVarying glad_glGetTransformFeedbackVarying typedef void (APIENTRYP PFNGLCLAMPCOLORPROC)(GLenum target, GLenum clamp); GLAPI PFNGLCLAMPCOLORPROC glad_glClampColor; #define glClampColor glad_glClampColor typedef void (APIENTRYP PFNGLBEGINCONDITIONALRENDERPROC)(GLuint id, GLenum mode); GLAPI PFNGLBEGINCONDITIONALRENDERPROC glad_glBeginConditionalRender; #define glBeginConditionalRender glad_glBeginConditionalRender typedef void (APIENTRYP PFNGLENDCONDITIONALRENDERPROC)(void); GLAPI PFNGLENDCONDITIONALRENDERPROC glad_glEndConditionalRender; #define glEndConditionalRender glad_glEndConditionalRender typedef void (APIENTRYP PFNGLVERTEXATTRIBIPOINTERPROC)(GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer); GLAPI PFNGLVERTEXATTRIBIPOINTERPROC glad_glVertexAttribIPointer; #define glVertexAttribIPointer glad_glVertexAttribIPointer typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIIVPROC)(GLuint index, GLenum pname, GLint *params); GLAPI PFNGLGETVERTEXATTRIBIIVPROC glad_glGetVertexAttribIiv; #define glGetVertexAttribIiv glad_glGetVertexAttribIiv typedef void (APIENTRYP PFNGLGETVERTEXATTRIBIUIVPROC)(GLuint index, GLenum pname, GLuint *params); GLAPI PFNGLGETVERTEXATTRIBIUIVPROC glad_glGetVertexAttribIuiv; #define glGetVertexAttribIuiv glad_glGetVertexAttribIuiv typedef void (APIENTRYP PFNGLVERTEXATTRIBI1IPROC)(GLuint index, GLint x); GLAPI PFNGLVERTEXATTRIBI1IPROC glad_glVertexAttribI1i; #define glVertexAttribI1i glad_glVertexAttribI1i typedef void (APIENTRYP PFNGLVERTEXATTRIBI2IPROC)(GLuint index, GLint x, GLint y); GLAPI PFNGLVERTEXATTRIBI2IPROC glad_glVertexAttribI2i; #define glVertexAttribI2i glad_glVertexAttribI2i typedef void (APIENTRYP PFNGLVERTEXATTRIBI3IPROC)(GLuint index, GLint x, GLint y, GLint z); GLAPI PFNGLVERTEXATTRIBI3IPROC glad_glVertexAttribI3i; #define glVertexAttribI3i glad_glVertexAttribI3i typedef void (APIENTRYP PFNGLVERTEXATTRIBI4IPROC)(GLuint index, GLint x, GLint y, GLint z, GLint w); GLAPI PFNGLVERTEXATTRIBI4IPROC glad_glVertexAttribI4i; #define glVertexAttribI4i glad_glVertexAttribI4i typedef void (APIENTRYP PFNGLVERTEXATTRIBI1UIPROC)(GLuint index, GLuint x); GLAPI PFNGLVERTEXATTRIBI1UIPROC glad_glVertexAttribI1ui; #define glVertexAttribI1ui glad_glVertexAttribI1ui typedef void (APIENTRYP PFNGLVERTEXATTRIBI2UIPROC)(GLuint index, GLuint x, GLuint y); GLAPI PFNGLVERTEXATTRIBI2UIPROC glad_glVertexAttribI2ui; #define glVertexAttribI2ui glad_glVertexAttribI2ui typedef void (APIENTRYP PFNGLVERTEXATTRIBI3UIPROC)(GLuint index, GLuint x, GLuint y, GLuint z); GLAPI PFNGLVERTEXATTRIBI3UIPROC glad_glVertexAttribI3ui; #define glVertexAttribI3ui glad_glVertexAttribI3ui typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UIPROC)(GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); GLAPI PFNGLVERTEXATTRIBI4UIPROC glad_glVertexAttribI4ui; #define glVertexAttribI4ui glad_glVertexAttribI4ui typedef void (APIENTRYP PFNGLVERTEXATTRIBI1IVPROC)(GLuint index, const GLint *v); GLAPI PFNGLVERTEXATTRIBI1IVPROC glad_glVertexAttribI1iv; #define glVertexAttribI1iv glad_glVertexAttribI1iv typedef void (APIENTRYP PFNGLVERTEXATTRIBI2IVPROC)(GLuint index, const GLint *v); GLAPI PFNGLVERTEXATTRIBI2IVPROC glad_glVertexAttribI2iv; #define glVertexAttribI2iv glad_glVertexAttribI2iv typedef void (APIENTRYP PFNGLVERTEXATTRIBI3IVPROC)(GLuint index, const GLint *v); GLAPI PFNGLVERTEXATTRIBI3IVPROC glad_glVertexAttribI3iv; #define glVertexAttribI3iv glad_glVertexAttribI3iv typedef void (APIENTRYP PFNGLVERTEXATTRIBI4IVPROC)(GLuint index, const GLint *v); GLAPI PFNGLVERTEXATTRIBI4IVPROC glad_glVertexAttribI4iv; #define glVertexAttribI4iv glad_glVertexAttribI4iv typedef void (APIENTRYP PFNGLVERTEXATTRIBI1UIVPROC)(GLuint index, const GLuint *v); GLAPI PFNGLVERTEXATTRIBI1UIVPROC glad_glVertexAttribI1uiv; #define glVertexAttribI1uiv glad_glVertexAttribI1uiv typedef void (APIENTRYP PFNGLVERTEXATTRIBI2UIVPROC)(GLuint index, const GLuint *v); GLAPI PFNGLVERTEXATTRIBI2UIVPROC glad_glVertexAttribI2uiv; #define glVertexAttribI2uiv glad_glVertexAttribI2uiv typedef void (APIENTRYP PFNGLVERTEXATTRIBI3UIVPROC)(GLuint index, const GLuint *v); GLAPI PFNGLVERTEXATTRIBI3UIVPROC glad_glVertexAttribI3uiv; #define glVertexAttribI3uiv glad_glVertexAttribI3uiv typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UIVPROC)(GLuint index, const GLuint *v); GLAPI PFNGLVERTEXATTRIBI4UIVPROC glad_glVertexAttribI4uiv; #define glVertexAttribI4uiv glad_glVertexAttribI4uiv typedef void (APIENTRYP PFNGLVERTEXATTRIBI4BVPROC)(GLuint index, const GLbyte *v); GLAPI PFNGLVERTEXATTRIBI4BVPROC glad_glVertexAttribI4bv; #define glVertexAttribI4bv glad_glVertexAttribI4bv typedef void (APIENTRYP PFNGLVERTEXATTRIBI4SVPROC)(GLuint index, const GLshort *v); GLAPI PFNGLVERTEXATTRIBI4SVPROC glad_glVertexAttribI4sv; #define glVertexAttribI4sv glad_glVertexAttribI4sv typedef void (APIENTRYP PFNGLVERTEXATTRIBI4UBVPROC)(GLuint index, const GLubyte *v); GLAPI PFNGLVERTEXATTRIBI4UBVPROC glad_glVertexAttribI4ubv; #define glVertexAttribI4ubv glad_glVertexAttribI4ubv typedef void (APIENTRYP PFNGLVERTEXATTRIBI4USVPROC)(GLuint index, const GLushort *v); GLAPI PFNGLVERTEXATTRIBI4USVPROC glad_glVertexAttribI4usv; #define glVertexAttribI4usv glad_glVertexAttribI4usv typedef void (APIENTRYP PFNGLGETUNIFORMUIVPROC)(GLuint program, GLint location, GLuint *params); GLAPI PFNGLGETUNIFORMUIVPROC glad_glGetUniformuiv; #define glGetUniformuiv glad_glGetUniformuiv typedef void (APIENTRYP PFNGLBINDFRAGDATALOCATIONPROC)(GLuint program, GLuint color, const GLchar *name); GLAPI PFNGLBINDFRAGDATALOCATIONPROC glad_glBindFragDataLocation; #define glBindFragDataLocation glad_glBindFragDataLocation typedef GLint (APIENTRYP PFNGLGETFRAGDATALOCATIONPROC)(GLuint program, const GLchar *name); GLAPI PFNGLGETFRAGDATALOCATIONPROC glad_glGetFragDataLocation; #define glGetFragDataLocation glad_glGetFragDataLocation typedef void (APIENTRYP PFNGLUNIFORM1UIPROC)(GLint location, GLuint v0); GLAPI PFNGLUNIFORM1UIPROC glad_glUniform1ui; #define glUniform1ui glad_glUniform1ui typedef void (APIENTRYP PFNGLUNIFORM2UIPROC)(GLint location, GLuint v0, GLuint v1); GLAPI PFNGLUNIFORM2UIPROC glad_glUniform2ui; #define glUniform2ui glad_glUniform2ui typedef void (APIENTRYP PFNGLUNIFORM3UIPROC)(GLint location, GLuint v0, GLuint v1, GLuint v2); GLAPI PFNGLUNIFORM3UIPROC glad_glUniform3ui; #define glUniform3ui glad_glUniform3ui typedef void (APIENTRYP PFNGLUNIFORM4UIPROC)(GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); GLAPI PFNGLUNIFORM4UIPROC glad_glUniform4ui; #define glUniform4ui glad_glUniform4ui typedef void (APIENTRYP PFNGLUNIFORM1UIVPROC)(GLint location, GLsizei count, const GLuint *value); GLAPI PFNGLUNIFORM1UIVPROC glad_glUniform1uiv; #define glUniform1uiv glad_glUniform1uiv typedef void (APIENTRYP PFNGLUNIFORM2UIVPROC)(GLint location, GLsizei count, const GLuint *value); GLAPI PFNGLUNIFORM2UIVPROC glad_glUniform2uiv; #define glUniform2uiv glad_glUniform2uiv typedef void (APIENTRYP PFNGLUNIFORM3UIVPROC)(GLint location, GLsizei count, const GLuint *value); GLAPI PFNGLUNIFORM3UIVPROC glad_glUniform3uiv; #define glUniform3uiv glad_glUniform3uiv typedef void (APIENTRYP PFNGLUNIFORM4UIVPROC)(GLint location, GLsizei count, const GLuint *value); GLAPI PFNGLUNIFORM4UIVPROC glad_glUniform4uiv; #define glUniform4uiv glad_glUniform4uiv typedef void (APIENTRYP PFNGLTEXPARAMETERIIVPROC)(GLenum target, GLenum pname, const GLint *params); GLAPI PFNGLTEXPARAMETERIIVPROC glad_glTexParameterIiv; #define glTexParameterIiv glad_glTexParameterIiv typedef void (APIENTRYP PFNGLTEXPARAMETERIUIVPROC)(GLenum target, GLenum pname, const GLuint *params); GLAPI PFNGLTEXPARAMETERIUIVPROC glad_glTexParameterIuiv; #define glTexParameterIuiv glad_glTexParameterIuiv typedef void (APIENTRYP PFNGLGETTEXPARAMETERIIVPROC)(GLenum target, GLenum pname, GLint *params); GLAPI PFNGLGETTEXPARAMETERIIVPROC glad_glGetTexParameterIiv; #define glGetTexParameterIiv glad_glGetTexParameterIiv typedef void (APIENTRYP PFNGLGETTEXPARAMETERIUIVPROC)(GLenum target, GLenum pname, GLuint *params); GLAPI PFNGLGETTEXPARAMETERIUIVPROC glad_glGetTexParameterIuiv; #define glGetTexParameterIuiv glad_glGetTexParameterIuiv typedef void (APIENTRYP PFNGLCLEARBUFFERIVPROC)(GLenum buffer, GLint drawbuffer, const GLint *value); GLAPI PFNGLCLEARBUFFERIVPROC glad_glClearBufferiv; #define glClearBufferiv glad_glClearBufferiv typedef void (APIENTRYP PFNGLCLEARBUFFERUIVPROC)(GLenum buffer, GLint drawbuffer, const GLuint *value); GLAPI PFNGLCLEARBUFFERUIVPROC glad_glClearBufferuiv; #define glClearBufferuiv glad_glClearBufferuiv typedef void (APIENTRYP PFNGLCLEARBUFFERFVPROC)(GLenum buffer, GLint drawbuffer, const GLfloat *value); GLAPI PFNGLCLEARBUFFERFVPROC glad_glClearBufferfv; #define glClearBufferfv glad_glClearBufferfv typedef void (APIENTRYP PFNGLCLEARBUFFERFIPROC)(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil); GLAPI PFNGLCLEARBUFFERFIPROC glad_glClearBufferfi; #define glClearBufferfi glad_glClearBufferfi typedef const GLubyte * (APIENTRYP PFNGLGETSTRINGIPROC)(GLenum name, GLuint index); GLAPI PFNGLGETSTRINGIPROC glad_glGetStringi; #define glGetStringi glad_glGetStringi typedef GLboolean (APIENTRYP PFNGLISRENDERBUFFERPROC)(GLuint renderbuffer); GLAPI PFNGLISRENDERBUFFERPROC glad_glIsRenderbuffer; #define glIsRenderbuffer glad_glIsRenderbuffer typedef void (APIENTRYP PFNGLBINDRENDERBUFFERPROC)(GLenum target, GLuint renderbuffer); GLAPI PFNGLBINDRENDERBUFFERPROC glad_glBindRenderbuffer; #define glBindRenderbuffer glad_glBindRenderbuffer typedef void (APIENTRYP PFNGLDELETERENDERBUFFERSPROC)(GLsizei n, const GLuint *renderbuffers); GLAPI PFNGLDELETERENDERBUFFERSPROC glad_glDeleteRenderbuffers; #define glDeleteRenderbuffers glad_glDeleteRenderbuffers typedef void (APIENTRYP PFNGLGENRENDERBUFFERSPROC)(GLsizei n, GLuint *renderbuffers); GLAPI PFNGLGENRENDERBUFFERSPROC glad_glGenRenderbuffers; #define glGenRenderbuffers glad_glGenRenderbuffers typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEPROC)(GLenum target, GLenum internalformat, GLsizei width, GLsizei height); GLAPI PFNGLRENDERBUFFERSTORAGEPROC glad_glRenderbufferStorage; #define glRenderbufferStorage glad_glRenderbufferStorage typedef void (APIENTRYP PFNGLGETRENDERBUFFERPARAMETERIVPROC)(GLenum target, GLenum pname, GLint *params); GLAPI PFNGLGETRENDERBUFFERPARAMETERIVPROC glad_glGetRenderbufferParameteriv; #define glGetRenderbufferParameteriv glad_glGetRenderbufferParameteriv typedef GLboolean (APIENTRYP PFNGLISFRAMEBUFFERPROC)(GLuint framebuffer); GLAPI PFNGLISFRAMEBUFFERPROC glad_glIsFramebuffer; #define glIsFramebuffer glad_glIsFramebuffer typedef void (APIENTRYP PFNGLBINDFRAMEBUFFERPROC)(GLenum target, GLuint framebuffer); GLAPI PFNGLBINDFRAMEBUFFERPROC glad_glBindFramebuffer; #define glBindFramebuffer glad_glBindFramebuffer typedef void (APIENTRYP PFNGLDELETEFRAMEBUFFERSPROC)(GLsizei n, const GLuint *framebuffers); GLAPI PFNGLDELETEFRAMEBUFFERSPROC glad_glDeleteFramebuffers; #define glDeleteFramebuffers glad_glDeleteFramebuffers typedef void (APIENTRYP PFNGLGENFRAMEBUFFERSPROC)(GLsizei n, GLuint *framebuffers); GLAPI PFNGLGENFRAMEBUFFERSPROC glad_glGenFramebuffers; #define glGenFramebuffers glad_glGenFramebuffers typedef GLenum (APIENTRYP PFNGLCHECKFRAMEBUFFERSTATUSPROC)(GLenum target); GLAPI PFNGLCHECKFRAMEBUFFERSTATUSPROC glad_glCheckFramebufferStatus; #define glCheckFramebufferStatus glad_glCheckFramebufferStatus typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE1DPROC)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); GLAPI PFNGLFRAMEBUFFERTEXTURE1DPROC glad_glFramebufferTexture1D; #define glFramebufferTexture1D glad_glFramebufferTexture1D typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE2DPROC)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); GLAPI PFNGLFRAMEBUFFERTEXTURE2DPROC glad_glFramebufferTexture2D; #define glFramebufferTexture2D glad_glFramebufferTexture2D typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE3DPROC)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset); GLAPI PFNGLFRAMEBUFFERTEXTURE3DPROC glad_glFramebufferTexture3D; #define glFramebufferTexture3D glad_glFramebufferTexture3D typedef void (APIENTRYP PFNGLFRAMEBUFFERRENDERBUFFERPROC)(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); GLAPI PFNGLFRAMEBUFFERRENDERBUFFERPROC glad_glFramebufferRenderbuffer; #define glFramebufferRenderbuffer glad_glFramebufferRenderbuffer typedef void (APIENTRYP PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC)(GLenum target, GLenum attachment, GLenum pname, GLint *params); GLAPI PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC glad_glGetFramebufferAttachmentParameteriv; #define glGetFramebufferAttachmentParameteriv glad_glGetFramebufferAttachmentParameteriv typedef void (APIENTRYP PFNGLGENERATEMIPMAPPROC)(GLenum target); GLAPI PFNGLGENERATEMIPMAPPROC glad_glGenerateMipmap; #define glGenerateMipmap glad_glGenerateMipmap typedef void (APIENTRYP PFNGLBLITFRAMEBUFFERPROC)(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); GLAPI PFNGLBLITFRAMEBUFFERPROC glad_glBlitFramebuffer; #define glBlitFramebuffer glad_glBlitFramebuffer typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); GLAPI PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC glad_glRenderbufferStorageMultisample; #define glRenderbufferStorageMultisample glad_glRenderbufferStorageMultisample typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURELAYERPROC)(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer); GLAPI PFNGLFRAMEBUFFERTEXTURELAYERPROC glad_glFramebufferTextureLayer; #define glFramebufferTextureLayer glad_glFramebufferTextureLayer typedef void * (APIENTRYP PFNGLMAPBUFFERRANGEPROC)(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access); GLAPI PFNGLMAPBUFFERRANGEPROC glad_glMapBufferRange; #define glMapBufferRange glad_glMapBufferRange typedef void (APIENTRYP PFNGLFLUSHMAPPEDBUFFERRANGEPROC)(GLenum target, GLintptr offset, GLsizeiptr length); GLAPI PFNGLFLUSHMAPPEDBUFFERRANGEPROC glad_glFlushMappedBufferRange; #define glFlushMappedBufferRange glad_glFlushMappedBufferRange typedef void (APIENTRYP PFNGLBINDVERTEXARRAYPROC)(GLuint array); GLAPI PFNGLBINDVERTEXARRAYPROC glad_glBindVertexArray; #define glBindVertexArray glad_glBindVertexArray typedef void (APIENTRYP PFNGLDELETEVERTEXARRAYSPROC)(GLsizei n, const GLuint *arrays); GLAPI PFNGLDELETEVERTEXARRAYSPROC glad_glDeleteVertexArrays; #define glDeleteVertexArrays glad_glDeleteVertexArrays typedef void (APIENTRYP PFNGLGENVERTEXARRAYSPROC)(GLsizei n, GLuint *arrays); GLAPI PFNGLGENVERTEXARRAYSPROC glad_glGenVertexArrays; #define glGenVertexArrays glad_glGenVertexArrays typedef GLboolean (APIENTRYP PFNGLISVERTEXARRAYPROC)(GLuint array); GLAPI PFNGLISVERTEXARRAYPROC glad_glIsVertexArray; #define glIsVertexArray glad_glIsVertexArray #endif #ifndef GL_VERSION_3_1 #define GL_VERSION_3_1 1 GLAPI int GLAD_GL_VERSION_3_1; typedef void (APIENTRYP PFNGLDRAWARRAYSINSTANCEDPROC)(GLenum mode, GLint first, GLsizei count, GLsizei instancecount); GLAPI PFNGLDRAWARRAYSINSTANCEDPROC glad_glDrawArraysInstanced; #define glDrawArraysInstanced glad_glDrawArraysInstanced typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDPROC)(GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount); GLAPI PFNGLDRAWELEMENTSINSTANCEDPROC glad_glDrawElementsInstanced; #define glDrawElementsInstanced glad_glDrawElementsInstanced typedef void (APIENTRYP PFNGLTEXBUFFERPROC)(GLenum target, GLenum internalformat, GLuint buffer); GLAPI PFNGLTEXBUFFERPROC glad_glTexBuffer; #define glTexBuffer glad_glTexBuffer typedef void (APIENTRYP PFNGLPRIMITIVERESTARTINDEXPROC)(GLuint index); GLAPI PFNGLPRIMITIVERESTARTINDEXPROC glad_glPrimitiveRestartIndex; #define glPrimitiveRestartIndex glad_glPrimitiveRestartIndex typedef void (APIENTRYP PFNGLCOPYBUFFERSUBDATAPROC)(GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size); GLAPI PFNGLCOPYBUFFERSUBDATAPROC glad_glCopyBufferSubData; #define glCopyBufferSubData glad_glCopyBufferSubData typedef void (APIENTRYP PFNGLGETUNIFORMINDICESPROC)(GLuint program, GLsizei uniformCount, const GLchar *const*uniformNames, GLuint *uniformIndices); GLAPI PFNGLGETUNIFORMINDICESPROC glad_glGetUniformIndices; #define glGetUniformIndices glad_glGetUniformIndices typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMSIVPROC)(GLuint program, GLsizei uniformCount, const GLuint *uniformIndices, GLenum pname, GLint *params); GLAPI PFNGLGETACTIVEUNIFORMSIVPROC glad_glGetActiveUniformsiv; #define glGetActiveUniformsiv glad_glGetActiveUniformsiv typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMNAMEPROC)(GLuint program, GLuint uniformIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformName); GLAPI PFNGLGETACTIVEUNIFORMNAMEPROC glad_glGetActiveUniformName; #define glGetActiveUniformName glad_glGetActiveUniformName typedef GLuint (APIENTRYP PFNGLGETUNIFORMBLOCKINDEXPROC)(GLuint program, const GLchar *uniformBlockName); GLAPI PFNGLGETUNIFORMBLOCKINDEXPROC glad_glGetUniformBlockIndex; #define glGetUniformBlockIndex glad_glGetUniformBlockIndex typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMBLOCKIVPROC)(GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint *params); GLAPI PFNGLGETACTIVEUNIFORMBLOCKIVPROC glad_glGetActiveUniformBlockiv; #define glGetActiveUniformBlockiv glad_glGetActiveUniformBlockiv typedef void (APIENTRYP PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC)(GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName); GLAPI PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC glad_glGetActiveUniformBlockName; #define glGetActiveUniformBlockName glad_glGetActiveUniformBlockName typedef void (APIENTRYP PFNGLUNIFORMBLOCKBINDINGPROC)(GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding); GLAPI PFNGLUNIFORMBLOCKBINDINGPROC glad_glUniformBlockBinding; #define glUniformBlockBinding glad_glUniformBlockBinding #endif #ifndef GL_VERSION_3_2 #define GL_VERSION_3_2 1 GLAPI int GLAD_GL_VERSION_3_2; typedef void (APIENTRYP PFNGLDRAWELEMENTSBASEVERTEXPROC)(GLenum mode, GLsizei count, GLenum type, const void *indices, GLint basevertex); GLAPI PFNGLDRAWELEMENTSBASEVERTEXPROC glad_glDrawElementsBaseVertex; #define glDrawElementsBaseVertex glad_glDrawElementsBaseVertex typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC)(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices, GLint basevertex); GLAPI PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC glad_glDrawRangeElementsBaseVertex; #define glDrawRangeElementsBaseVertex glad_glDrawRangeElementsBaseVertex typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC)(GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex); GLAPI PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC glad_glDrawElementsInstancedBaseVertex; #define glDrawElementsInstancedBaseVertex glad_glDrawElementsInstancedBaseVertex typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC)(GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei drawcount, const GLint *basevertex); GLAPI PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC glad_glMultiDrawElementsBaseVertex; #define glMultiDrawElementsBaseVertex glad_glMultiDrawElementsBaseVertex typedef void (APIENTRYP PFNGLPROVOKINGVERTEXPROC)(GLenum mode); GLAPI PFNGLPROVOKINGVERTEXPROC glad_glProvokingVertex; #define glProvokingVertex glad_glProvokingVertex typedef GLsync (APIENTRYP PFNGLFENCESYNCPROC)(GLenum condition, GLbitfield flags); GLAPI PFNGLFENCESYNCPROC glad_glFenceSync; #define glFenceSync glad_glFenceSync typedef GLboolean (APIENTRYP PFNGLISSYNCPROC)(GLsync sync); GLAPI PFNGLISSYNCPROC glad_glIsSync; #define glIsSync glad_glIsSync typedef void (APIENTRYP PFNGLDELETESYNCPROC)(GLsync sync); GLAPI PFNGLDELETESYNCPROC glad_glDeleteSync; #define glDeleteSync glad_glDeleteSync typedef GLenum (APIENTRYP PFNGLCLIENTWAITSYNCPROC)(GLsync sync, GLbitfield flags, GLuint64 timeout); GLAPI PFNGLCLIENTWAITSYNCPROC glad_glClientWaitSync; #define glClientWaitSync glad_glClientWaitSync typedef void (APIENTRYP PFNGLWAITSYNCPROC)(GLsync sync, GLbitfield flags, GLuint64 timeout); GLAPI PFNGLWAITSYNCPROC glad_glWaitSync; #define glWaitSync glad_glWaitSync typedef void (APIENTRYP PFNGLGETINTEGER64VPROC)(GLenum pname, GLint64 *data); GLAPI PFNGLGETINTEGER64VPROC glad_glGetInteger64v; #define glGetInteger64v glad_glGetInteger64v typedef void (APIENTRYP PFNGLGETSYNCIVPROC)(GLsync sync, GLenum pname, GLsizei count, GLsizei *length, GLint *values); GLAPI PFNGLGETSYNCIVPROC glad_glGetSynciv; #define glGetSynciv glad_glGetSynciv typedef void (APIENTRYP PFNGLGETINTEGER64I_VPROC)(GLenum target, GLuint index, GLint64 *data); GLAPI PFNGLGETINTEGER64I_VPROC glad_glGetInteger64i_v; #define glGetInteger64i_v glad_glGetInteger64i_v typedef void (APIENTRYP PFNGLGETBUFFERPARAMETERI64VPROC)(GLenum target, GLenum pname, GLint64 *params); GLAPI PFNGLGETBUFFERPARAMETERI64VPROC glad_glGetBufferParameteri64v; #define glGetBufferParameteri64v glad_glGetBufferParameteri64v typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTUREPROC)(GLenum target, GLenum attachment, GLuint texture, GLint level); GLAPI PFNGLFRAMEBUFFERTEXTUREPROC glad_glFramebufferTexture; #define glFramebufferTexture glad_glFramebufferTexture typedef void (APIENTRYP PFNGLTEXIMAGE2DMULTISAMPLEPROC)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations); GLAPI PFNGLTEXIMAGE2DMULTISAMPLEPROC glad_glTexImage2DMultisample; #define glTexImage2DMultisample glad_glTexImage2DMultisample typedef void (APIENTRYP PFNGLTEXIMAGE3DMULTISAMPLEPROC)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations); GLAPI PFNGLTEXIMAGE3DMULTISAMPLEPROC glad_glTexImage3DMultisample; #define glTexImage3DMultisample glad_glTexImage3DMultisample typedef void (APIENTRYP PFNGLGETMULTISAMPLEFVPROC)(GLenum pname, GLuint index, GLfloat *val); GLAPI PFNGLGETMULTISAMPLEFVPROC glad_glGetMultisamplefv; #define glGetMultisamplefv glad_glGetMultisamplefv typedef void (APIENTRYP PFNGLSAMPLEMASKIPROC)(GLuint maskNumber, GLbitfield mask); GLAPI PFNGLSAMPLEMASKIPROC glad_glSampleMaski; #define glSampleMaski glad_glSampleMaski #endif #ifndef GL_VERSION_3_3 #define GL_VERSION_3_3 1 GLAPI int GLAD_GL_VERSION_3_3; typedef void (APIENTRYP PFNGLBINDFRAGDATALOCATIONINDEXEDPROC)(GLuint program, GLuint colorNumber, GLuint index, const GLchar *name); GLAPI PFNGLBINDFRAGDATALOCATIONINDEXEDPROC glad_glBindFragDataLocationIndexed; #define glBindFragDataLocationIndexed glad_glBindFragDataLocationIndexed typedef GLint (APIENTRYP PFNGLGETFRAGDATAINDEXPROC)(GLuint program, const GLchar *name); GLAPI PFNGLGETFRAGDATAINDEXPROC glad_glGetFragDataIndex; #define glGetFragDataIndex glad_glGetFragDataIndex typedef void (APIENTRYP PFNGLGENSAMPLERSPROC)(GLsizei count, GLuint *samplers); GLAPI PFNGLGENSAMPLERSPROC glad_glGenSamplers; #define glGenSamplers glad_glGenSamplers typedef void (APIENTRYP PFNGLDELETESAMPLERSPROC)(GLsizei count, const GLuint *samplers); GLAPI PFNGLDELETESAMPLERSPROC glad_glDeleteSamplers; #define glDeleteSamplers glad_glDeleteSamplers typedef GLboolean (APIENTRYP PFNGLISSAMPLERPROC)(GLuint sampler); GLAPI PFNGLISSAMPLERPROC glad_glIsSampler; #define glIsSampler glad_glIsSampler typedef void (APIENTRYP PFNGLBINDSAMPLERPROC)(GLuint unit, GLuint sampler); GLAPI PFNGLBINDSAMPLERPROC glad_glBindSampler; #define glBindSampler glad_glBindSampler typedef void (APIENTRYP PFNGLSAMPLERPARAMETERIPROC)(GLuint sampler, GLenum pname, GLint param); GLAPI PFNGLSAMPLERPARAMETERIPROC glad_glSamplerParameteri; #define glSamplerParameteri glad_glSamplerParameteri typedef void (APIENTRYP PFNGLSAMPLERPARAMETERIVPROC)(GLuint sampler, GLenum pname, const GLint *param); GLAPI PFNGLSAMPLERPARAMETERIVPROC glad_glSamplerParameteriv; #define glSamplerParameteriv glad_glSamplerParameteriv typedef void (APIENTRYP PFNGLSAMPLERPARAMETERFPROC)(GLuint sampler, GLenum pname, GLfloat param); GLAPI PFNGLSAMPLERPARAMETERFPROC glad_glSamplerParameterf; #define glSamplerParameterf glad_glSamplerParameterf typedef void (APIENTRYP PFNGLSAMPLERPARAMETERFVPROC)(GLuint sampler, GLenum pname, const GLfloat *param); GLAPI PFNGLSAMPLERPARAMETERFVPROC glad_glSamplerParameterfv; #define glSamplerParameterfv glad_glSamplerParameterfv typedef void (APIENTRYP PFNGLSAMPLERPARAMETERIIVPROC)(GLuint sampler, GLenum pname, const GLint *param); GLAPI PFNGLSAMPLERPARAMETERIIVPROC glad_glSamplerParameterIiv; #define glSamplerParameterIiv glad_glSamplerParameterIiv typedef void (APIENTRYP PFNGLSAMPLERPARAMETERIUIVPROC)(GLuint sampler, GLenum pname, const GLuint *param); GLAPI PFNGLSAMPLERPARAMETERIUIVPROC glad_glSamplerParameterIuiv; #define glSamplerParameterIuiv glad_glSamplerParameterIuiv typedef void (APIENTRYP PFNGLGETSAMPLERPARAMETERIVPROC)(GLuint sampler, GLenum pname, GLint *params); GLAPI PFNGLGETSAMPLERPARAMETERIVPROC glad_glGetSamplerParameteriv; #define glGetSamplerParameteriv glad_glGetSamplerParameteriv typedef void (APIENTRYP PFNGLGETSAMPLERPARAMETERIIVPROC)(GLuint sampler, GLenum pname, GLint *params); GLAPI PFNGLGETSAMPLERPARAMETERIIVPROC glad_glGetSamplerParameterIiv; #define glGetSamplerParameterIiv glad_glGetSamplerParameterIiv typedef void (APIENTRYP PFNGLGETSAMPLERPARAMETERFVPROC)(GLuint sampler, GLenum pname, GLfloat *params); GLAPI PFNGLGETSAMPLERPARAMETERFVPROC glad_glGetSamplerParameterfv; #define glGetSamplerParameterfv glad_glGetSamplerParameterfv typedef void (APIENTRYP PFNGLGETSAMPLERPARAMETERIUIVPROC)(GLuint sampler, GLenum pname, GLuint *params); GLAPI PFNGLGETSAMPLERPARAMETERIUIVPROC glad_glGetSamplerParameterIuiv; #define glGetSamplerParameterIuiv glad_glGetSamplerParameterIuiv typedef void (APIENTRYP PFNGLQUERYCOUNTERPROC)(GLuint id, GLenum target); GLAPI PFNGLQUERYCOUNTERPROC glad_glQueryCounter; #define glQueryCounter glad_glQueryCounter typedef void (APIENTRYP PFNGLGETQUERYOBJECTI64VPROC)(GLuint id, GLenum pname, GLint64 *params); GLAPI PFNGLGETQUERYOBJECTI64VPROC glad_glGetQueryObjecti64v; #define glGetQueryObjecti64v glad_glGetQueryObjecti64v typedef void (APIENTRYP PFNGLGETQUERYOBJECTUI64VPROC)(GLuint id, GLenum pname, GLuint64 *params); GLAPI PFNGLGETQUERYOBJECTUI64VPROC glad_glGetQueryObjectui64v; #define glGetQueryObjectui64v glad_glGetQueryObjectui64v typedef void (APIENTRYP PFNGLVERTEXATTRIBDIVISORPROC)(GLuint index, GLuint divisor); GLAPI PFNGLVERTEXATTRIBDIVISORPROC glad_glVertexAttribDivisor; #define glVertexAttribDivisor glad_glVertexAttribDivisor typedef void (APIENTRYP PFNGLVERTEXATTRIBP1UIPROC)(GLuint index, GLenum type, GLboolean normalized, GLuint value); GLAPI PFNGLVERTEXATTRIBP1UIPROC glad_glVertexAttribP1ui; #define glVertexAttribP1ui glad_glVertexAttribP1ui typedef void (APIENTRYP PFNGLVERTEXATTRIBP1UIVPROC)(GLuint index, GLenum type, GLboolean normalized, const GLuint *value); GLAPI PFNGLVERTEXATTRIBP1UIVPROC glad_glVertexAttribP1uiv; #define glVertexAttribP1uiv glad_glVertexAttribP1uiv typedef void (APIENTRYP PFNGLVERTEXATTRIBP2UIPROC)(GLuint index, GLenum type, GLboolean normalized, GLuint value); GLAPI PFNGLVERTEXATTRIBP2UIPROC glad_glVertexAttribP2ui; #define glVertexAttribP2ui glad_glVertexAttribP2ui typedef void (APIENTRYP PFNGLVERTEXATTRIBP2UIVPROC)(GLuint index, GLenum type, GLboolean normalized, const GLuint *value); GLAPI PFNGLVERTEXATTRIBP2UIVPROC glad_glVertexAttribP2uiv; #define glVertexAttribP2uiv glad_glVertexAttribP2uiv typedef void (APIENTRYP PFNGLVERTEXATTRIBP3UIPROC)(GLuint index, GLenum type, GLboolean normalized, GLuint value); GLAPI PFNGLVERTEXATTRIBP3UIPROC glad_glVertexAttribP3ui; #define glVertexAttribP3ui glad_glVertexAttribP3ui typedef void (APIENTRYP PFNGLVERTEXATTRIBP3UIVPROC)(GLuint index, GLenum type, GLboolean normalized, const GLuint *value); GLAPI PFNGLVERTEXATTRIBP3UIVPROC glad_glVertexAttribP3uiv; #define glVertexAttribP3uiv glad_glVertexAttribP3uiv typedef void (APIENTRYP PFNGLVERTEXATTRIBP4UIPROC)(GLuint index, GLenum type, GLboolean normalized, GLuint value); GLAPI PFNGLVERTEXATTRIBP4UIPROC glad_glVertexAttribP4ui; #define glVertexAttribP4ui glad_glVertexAttribP4ui typedef void (APIENTRYP PFNGLVERTEXATTRIBP4UIVPROC)(GLuint index, GLenum type, GLboolean normalized, const GLuint *value); GLAPI PFNGLVERTEXATTRIBP4UIVPROC glad_glVertexAttribP4uiv; #define glVertexAttribP4uiv glad_glVertexAttribP4uiv typedef void (APIENTRYP PFNGLVERTEXP2UIPROC)(GLenum type, GLuint value); GLAPI PFNGLVERTEXP2UIPROC glad_glVertexP2ui; #define glVertexP2ui glad_glVertexP2ui typedef void (APIENTRYP PFNGLVERTEXP2UIVPROC)(GLenum type, const GLuint *value); GLAPI PFNGLVERTEXP2UIVPROC glad_glVertexP2uiv; #define glVertexP2uiv glad_glVertexP2uiv typedef void (APIENTRYP PFNGLVERTEXP3UIPROC)(GLenum type, GLuint value); GLAPI PFNGLVERTEXP3UIPROC glad_glVertexP3ui; #define glVertexP3ui glad_glVertexP3ui typedef void (APIENTRYP PFNGLVERTEXP3UIVPROC)(GLenum type, const GLuint *value); GLAPI PFNGLVERTEXP3UIVPROC glad_glVertexP3uiv; #define glVertexP3uiv glad_glVertexP3uiv typedef void (APIENTRYP PFNGLVERTEXP4UIPROC)(GLenum type, GLuint value); GLAPI PFNGLVERTEXP4UIPROC glad_glVertexP4ui; #define glVertexP4ui glad_glVertexP4ui typedef void (APIENTRYP PFNGLVERTEXP4UIVPROC)(GLenum type, const GLuint *value); GLAPI PFNGLVERTEXP4UIVPROC glad_glVertexP4uiv; #define glVertexP4uiv glad_glVertexP4uiv typedef void (APIENTRYP PFNGLTEXCOORDP1UIPROC)(GLenum type, GLuint coords); GLAPI PFNGLTEXCOORDP1UIPROC glad_glTexCoordP1ui; #define glTexCoordP1ui glad_glTexCoordP1ui typedef void (APIENTRYP PFNGLTEXCOORDP1UIVPROC)(GLenum type, const GLuint *coords); GLAPI PFNGLTEXCOORDP1UIVPROC glad_glTexCoordP1uiv; #define glTexCoordP1uiv glad_glTexCoordP1uiv typedef void (APIENTRYP PFNGLTEXCOORDP2UIPROC)(GLenum type, GLuint coords); GLAPI PFNGLTEXCOORDP2UIPROC glad_glTexCoordP2ui; #define glTexCoordP2ui glad_glTexCoordP2ui typedef void (APIENTRYP PFNGLTEXCOORDP2UIVPROC)(GLenum type, const GLuint *coords); GLAPI PFNGLTEXCOORDP2UIVPROC glad_glTexCoordP2uiv; #define glTexCoordP2uiv glad_glTexCoordP2uiv typedef void (APIENTRYP PFNGLTEXCOORDP3UIPROC)(GLenum type, GLuint coords); GLAPI PFNGLTEXCOORDP3UIPROC glad_glTexCoordP3ui; #define glTexCoordP3ui glad_glTexCoordP3ui typedef void (APIENTRYP PFNGLTEXCOORDP3UIVPROC)(GLenum type, const GLuint *coords); GLAPI PFNGLTEXCOORDP3UIVPROC glad_glTexCoordP3uiv; #define glTexCoordP3uiv glad_glTexCoordP3uiv typedef void (APIENTRYP PFNGLTEXCOORDP4UIPROC)(GLenum type, GLuint coords); GLAPI PFNGLTEXCOORDP4UIPROC glad_glTexCoordP4ui; #define glTexCoordP4ui glad_glTexCoordP4ui typedef void (APIENTRYP PFNGLTEXCOORDP4UIVPROC)(GLenum type, const GLuint *coords); GLAPI PFNGLTEXCOORDP4UIVPROC glad_glTexCoordP4uiv; #define glTexCoordP4uiv glad_glTexCoordP4uiv typedef void (APIENTRYP PFNGLMULTITEXCOORDP1UIPROC)(GLenum texture, GLenum type, GLuint coords); GLAPI PFNGLMULTITEXCOORDP1UIPROC glad_glMultiTexCoordP1ui; #define glMultiTexCoordP1ui glad_glMultiTexCoordP1ui typedef void (APIENTRYP PFNGLMULTITEXCOORDP1UIVPROC)(GLenum texture, GLenum type, const GLuint *coords); GLAPI PFNGLMULTITEXCOORDP1UIVPROC glad_glMultiTexCoordP1uiv; #define glMultiTexCoordP1uiv glad_glMultiTexCoordP1uiv typedef void (APIENTRYP PFNGLMULTITEXCOORDP2UIPROC)(GLenum texture, GLenum type, GLuint coords); GLAPI PFNGLMULTITEXCOORDP2UIPROC glad_glMultiTexCoordP2ui; #define glMultiTexCoordP2ui glad_glMultiTexCoordP2ui typedef void (APIENTRYP PFNGLMULTITEXCOORDP2UIVPROC)(GLenum texture, GLenum type, const GLuint *coords); GLAPI PFNGLMULTITEXCOORDP2UIVPROC glad_glMultiTexCoordP2uiv; #define glMultiTexCoordP2uiv glad_glMultiTexCoordP2uiv typedef void (APIENTRYP PFNGLMULTITEXCOORDP3UIPROC)(GLenum texture, GLenum type, GLuint coords); GLAPI PFNGLMULTITEXCOORDP3UIPROC glad_glMultiTexCoordP3ui; #define glMultiTexCoordP3ui glad_glMultiTexCoordP3ui typedef void (APIENTRYP PFNGLMULTITEXCOORDP3UIVPROC)(GLenum texture, GLenum type, const GLuint *coords); GLAPI PFNGLMULTITEXCOORDP3UIVPROC glad_glMultiTexCoordP3uiv; #define glMultiTexCoordP3uiv glad_glMultiTexCoordP3uiv typedef void (APIENTRYP PFNGLMULTITEXCOORDP4UIPROC)(GLenum texture, GLenum type, GLuint coords); GLAPI PFNGLMULTITEXCOORDP4UIPROC glad_glMultiTexCoordP4ui; #define glMultiTexCoordP4ui glad_glMultiTexCoordP4ui typedef void (APIENTRYP PFNGLMULTITEXCOORDP4UIVPROC)(GLenum texture, GLenum type, const GLuint *coords); GLAPI PFNGLMULTITEXCOORDP4UIVPROC glad_glMultiTexCoordP4uiv; #define glMultiTexCoordP4uiv glad_glMultiTexCoordP4uiv typedef void (APIENTRYP PFNGLNORMALP3UIPROC)(GLenum type, GLuint coords); GLAPI PFNGLNORMALP3UIPROC glad_glNormalP3ui; #define glNormalP3ui glad_glNormalP3ui typedef void (APIENTRYP PFNGLNORMALP3UIVPROC)(GLenum type, const GLuint *coords); GLAPI PFNGLNORMALP3UIVPROC glad_glNormalP3uiv; #define glNormalP3uiv glad_glNormalP3uiv typedef void (APIENTRYP PFNGLCOLORP3UIPROC)(GLenum type, GLuint color); GLAPI PFNGLCOLORP3UIPROC glad_glColorP3ui; #define glColorP3ui glad_glColorP3ui typedef void (APIENTRYP PFNGLCOLORP3UIVPROC)(GLenum type, const GLuint *color); GLAPI PFNGLCOLORP3UIVPROC glad_glColorP3uiv; #define glColorP3uiv glad_glColorP3uiv typedef void (APIENTRYP PFNGLCOLORP4UIPROC)(GLenum type, GLuint color); GLAPI PFNGLCOLORP4UIPROC glad_glColorP4ui; #define glColorP4ui glad_glColorP4ui typedef void (APIENTRYP PFNGLCOLORP4UIVPROC)(GLenum type, const GLuint *color); GLAPI PFNGLCOLORP4UIVPROC glad_glColorP4uiv; #define glColorP4uiv glad_glColorP4uiv typedef void (APIENTRYP PFNGLSECONDARYCOLORP3UIPROC)(GLenum type, GLuint color); GLAPI PFNGLSECONDARYCOLORP3UIPROC glad_glSecondaryColorP3ui; #define glSecondaryColorP3ui glad_glSecondaryColorP3ui typedef void (APIENTRYP PFNGLSECONDARYCOLORP3UIVPROC)(GLenum type, const GLuint *color); GLAPI PFNGLSECONDARYCOLORP3UIVPROC glad_glSecondaryColorP3uiv; #define glSecondaryColorP3uiv glad_glSecondaryColorP3uiv #endif #ifndef GL_VERSION_4_0 #define GL_VERSION_4_0 1 GLAPI int GLAD_GL_VERSION_4_0; typedef void (APIENTRYP PFNGLMINSAMPLESHADINGPROC)(GLfloat value); GLAPI PFNGLMINSAMPLESHADINGPROC glad_glMinSampleShading; #define glMinSampleShading glad_glMinSampleShading typedef void (APIENTRYP PFNGLBLENDEQUATIONIPROC)(GLuint buf, GLenum mode); GLAPI PFNGLBLENDEQUATIONIPROC glad_glBlendEquationi; #define glBlendEquationi glad_glBlendEquationi typedef void (APIENTRYP PFNGLBLENDEQUATIONSEPARATEIPROC)(GLuint buf, GLenum modeRGB, GLenum modeAlpha); GLAPI PFNGLBLENDEQUATIONSEPARATEIPROC glad_glBlendEquationSeparatei; #define glBlendEquationSeparatei glad_glBlendEquationSeparatei typedef void (APIENTRYP PFNGLBLENDFUNCIPROC)(GLuint buf, GLenum src, GLenum dst); GLAPI PFNGLBLENDFUNCIPROC glad_glBlendFunci; #define glBlendFunci glad_glBlendFunci typedef void (APIENTRYP PFNGLBLENDFUNCSEPARATEIPROC)(GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha); GLAPI PFNGLBLENDFUNCSEPARATEIPROC glad_glBlendFuncSeparatei; #define glBlendFuncSeparatei glad_glBlendFuncSeparatei typedef void (APIENTRYP PFNGLDRAWARRAYSINDIRECTPROC)(GLenum mode, const void *indirect); GLAPI PFNGLDRAWARRAYSINDIRECTPROC glad_glDrawArraysIndirect; #define glDrawArraysIndirect glad_glDrawArraysIndirect typedef void (APIENTRYP PFNGLDRAWELEMENTSINDIRECTPROC)(GLenum mode, GLenum type, const void *indirect); GLAPI PFNGLDRAWELEMENTSINDIRECTPROC glad_glDrawElementsIndirect; #define glDrawElementsIndirect glad_glDrawElementsIndirect typedef void (APIENTRYP PFNGLUNIFORM1DPROC)(GLint location, GLdouble x); GLAPI PFNGLUNIFORM1DPROC glad_glUniform1d; #define glUniform1d glad_glUniform1d typedef void (APIENTRYP PFNGLUNIFORM2DPROC)(GLint location, GLdouble x, GLdouble y); GLAPI PFNGLUNIFORM2DPROC glad_glUniform2d; #define glUniform2d glad_glUniform2d typedef void (APIENTRYP PFNGLUNIFORM3DPROC)(GLint location, GLdouble x, GLdouble y, GLdouble z); GLAPI PFNGLUNIFORM3DPROC glad_glUniform3d; #define glUniform3d glad_glUniform3d typedef void (APIENTRYP PFNGLUNIFORM4DPROC)(GLint location, GLdouble x, GLdouble y, GLdouble z, GLdouble w); GLAPI PFNGLUNIFORM4DPROC glad_glUniform4d; #define glUniform4d glad_glUniform4d typedef void (APIENTRYP PFNGLUNIFORM1DVPROC)(GLint location, GLsizei count, const GLdouble *value); GLAPI PFNGLUNIFORM1DVPROC glad_glUniform1dv; #define glUniform1dv glad_glUniform1dv typedef void (APIENTRYP PFNGLUNIFORM2DVPROC)(GLint location, GLsizei count, const GLdouble *value); GLAPI PFNGLUNIFORM2DVPROC glad_glUniform2dv; #define glUniform2dv glad_glUniform2dv typedef void (APIENTRYP PFNGLUNIFORM3DVPROC)(GLint location, GLsizei count, const GLdouble *value); GLAPI PFNGLUNIFORM3DVPROC glad_glUniform3dv; #define glUniform3dv glad_glUniform3dv typedef void (APIENTRYP PFNGLUNIFORM4DVPROC)(GLint location, GLsizei count, const GLdouble *value); GLAPI PFNGLUNIFORM4DVPROC glad_glUniform4dv; #define glUniform4dv glad_glUniform4dv typedef void (APIENTRYP PFNGLUNIFORMMATRIX2DVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); GLAPI PFNGLUNIFORMMATRIX2DVPROC glad_glUniformMatrix2dv; #define glUniformMatrix2dv glad_glUniformMatrix2dv typedef void (APIENTRYP PFNGLUNIFORMMATRIX3DVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); GLAPI PFNGLUNIFORMMATRIX3DVPROC glad_glUniformMatrix3dv; #define glUniformMatrix3dv glad_glUniformMatrix3dv typedef void (APIENTRYP PFNGLUNIFORMMATRIX4DVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); GLAPI PFNGLUNIFORMMATRIX4DVPROC glad_glUniformMatrix4dv; #define glUniformMatrix4dv glad_glUniformMatrix4dv typedef void (APIENTRYP PFNGLUNIFORMMATRIX2X3DVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); GLAPI PFNGLUNIFORMMATRIX2X3DVPROC glad_glUniformMatrix2x3dv; #define glUniformMatrix2x3dv glad_glUniformMatrix2x3dv typedef void (APIENTRYP PFNGLUNIFORMMATRIX2X4DVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); GLAPI PFNGLUNIFORMMATRIX2X4DVPROC glad_glUniformMatrix2x4dv; #define glUniformMatrix2x4dv glad_glUniformMatrix2x4dv typedef void (APIENTRYP PFNGLUNIFORMMATRIX3X2DVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); GLAPI PFNGLUNIFORMMATRIX3X2DVPROC glad_glUniformMatrix3x2dv; #define glUniformMatrix3x2dv glad_glUniformMatrix3x2dv typedef void (APIENTRYP PFNGLUNIFORMMATRIX3X4DVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); GLAPI PFNGLUNIFORMMATRIX3X4DVPROC glad_glUniformMatrix3x4dv; #define glUniformMatrix3x4dv glad_glUniformMatrix3x4dv typedef void (APIENTRYP PFNGLUNIFORMMATRIX4X2DVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); GLAPI PFNGLUNIFORMMATRIX4X2DVPROC glad_glUniformMatrix4x2dv; #define glUniformMatrix4x2dv glad_glUniformMatrix4x2dv typedef void (APIENTRYP PFNGLUNIFORMMATRIX4X3DVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); GLAPI PFNGLUNIFORMMATRIX4X3DVPROC glad_glUniformMatrix4x3dv; #define glUniformMatrix4x3dv glad_glUniformMatrix4x3dv typedef void (APIENTRYP PFNGLGETUNIFORMDVPROC)(GLuint program, GLint location, GLdouble *params); GLAPI PFNGLGETUNIFORMDVPROC glad_glGetUniformdv; #define glGetUniformdv glad_glGetUniformdv typedef GLint (APIENTRYP PFNGLGETSUBROUTINEUNIFORMLOCATIONPROC)(GLuint program, GLenum shadertype, const GLchar *name); GLAPI PFNGLGETSUBROUTINEUNIFORMLOCATIONPROC glad_glGetSubroutineUniformLocation; #define glGetSubroutineUniformLocation glad_glGetSubroutineUniformLocation typedef GLuint (APIENTRYP PFNGLGETSUBROUTINEINDEXPROC)(GLuint program, GLenum shadertype, const GLchar *name); GLAPI PFNGLGETSUBROUTINEINDEXPROC glad_glGetSubroutineIndex; #define glGetSubroutineIndex glad_glGetSubroutineIndex typedef void (APIENTRYP PFNGLGETACTIVESUBROUTINEUNIFORMIVPROC)(GLuint program, GLenum shadertype, GLuint index, GLenum pname, GLint *values); GLAPI PFNGLGETACTIVESUBROUTINEUNIFORMIVPROC glad_glGetActiveSubroutineUniformiv; #define glGetActiveSubroutineUniformiv glad_glGetActiveSubroutineUniformiv typedef void (APIENTRYP PFNGLGETACTIVESUBROUTINEUNIFORMNAMEPROC)(GLuint program, GLenum shadertype, GLuint index, GLsizei bufSize, GLsizei *length, GLchar *name); GLAPI PFNGLGETACTIVESUBROUTINEUNIFORMNAMEPROC glad_glGetActiveSubroutineUniformName; #define glGetActiveSubroutineUniformName glad_glGetActiveSubroutineUniformName typedef void (APIENTRYP PFNGLGETACTIVESUBROUTINENAMEPROC)(GLuint program, GLenum shadertype, GLuint index, GLsizei bufSize, GLsizei *length, GLchar *name); GLAPI PFNGLGETACTIVESUBROUTINENAMEPROC glad_glGetActiveSubroutineName; #define glGetActiveSubroutineName glad_glGetActiveSubroutineName typedef void (APIENTRYP PFNGLUNIFORMSUBROUTINESUIVPROC)(GLenum shadertype, GLsizei count, const GLuint *indices); GLAPI PFNGLUNIFORMSUBROUTINESUIVPROC glad_glUniformSubroutinesuiv; #define glUniformSubroutinesuiv glad_glUniformSubroutinesuiv typedef void (APIENTRYP PFNGLGETUNIFORMSUBROUTINEUIVPROC)(GLenum shadertype, GLint location, GLuint *params); GLAPI PFNGLGETUNIFORMSUBROUTINEUIVPROC glad_glGetUniformSubroutineuiv; #define glGetUniformSubroutineuiv glad_glGetUniformSubroutineuiv typedef void (APIENTRYP PFNGLGETPROGRAMSTAGEIVPROC)(GLuint program, GLenum shadertype, GLenum pname, GLint *values); GLAPI PFNGLGETPROGRAMSTAGEIVPROC glad_glGetProgramStageiv; #define glGetProgramStageiv glad_glGetProgramStageiv typedef void (APIENTRYP PFNGLPATCHPARAMETERIPROC)(GLenum pname, GLint value); GLAPI PFNGLPATCHPARAMETERIPROC glad_glPatchParameteri; #define glPatchParameteri glad_glPatchParameteri typedef void (APIENTRYP PFNGLPATCHPARAMETERFVPROC)(GLenum pname, const GLfloat *values); GLAPI PFNGLPATCHPARAMETERFVPROC glad_glPatchParameterfv; #define glPatchParameterfv glad_glPatchParameterfv typedef void (APIENTRYP PFNGLBINDTRANSFORMFEEDBACKPROC)(GLenum target, GLuint id); GLAPI PFNGLBINDTRANSFORMFEEDBACKPROC glad_glBindTransformFeedback; #define glBindTransformFeedback glad_glBindTransformFeedback typedef void (APIENTRYP PFNGLDELETETRANSFORMFEEDBACKSPROC)(GLsizei n, const GLuint *ids); GLAPI PFNGLDELETETRANSFORMFEEDBACKSPROC glad_glDeleteTransformFeedbacks; #define glDeleteTransformFeedbacks glad_glDeleteTransformFeedbacks typedef void (APIENTRYP PFNGLGENTRANSFORMFEEDBACKSPROC)(GLsizei n, GLuint *ids); GLAPI PFNGLGENTRANSFORMFEEDBACKSPROC glad_glGenTransformFeedbacks; #define glGenTransformFeedbacks glad_glGenTransformFeedbacks typedef GLboolean (APIENTRYP PFNGLISTRANSFORMFEEDBACKPROC)(GLuint id); GLAPI PFNGLISTRANSFORMFEEDBACKPROC glad_glIsTransformFeedback; #define glIsTransformFeedback glad_glIsTransformFeedback typedef void (APIENTRYP PFNGLPAUSETRANSFORMFEEDBACKPROC)(void); GLAPI PFNGLPAUSETRANSFORMFEEDBACKPROC glad_glPauseTransformFeedback; #define glPauseTransformFeedback glad_glPauseTransformFeedback typedef void (APIENTRYP PFNGLRESUMETRANSFORMFEEDBACKPROC)(void); GLAPI PFNGLRESUMETRANSFORMFEEDBACKPROC glad_glResumeTransformFeedback; #define glResumeTransformFeedback glad_glResumeTransformFeedback typedef void (APIENTRYP PFNGLDRAWTRANSFORMFEEDBACKPROC)(GLenum mode, GLuint id); GLAPI PFNGLDRAWTRANSFORMFEEDBACKPROC glad_glDrawTransformFeedback; #define glDrawTransformFeedback glad_glDrawTransformFeedback typedef void (APIENTRYP PFNGLDRAWTRANSFORMFEEDBACKSTREAMPROC)(GLenum mode, GLuint id, GLuint stream); GLAPI PFNGLDRAWTRANSFORMFEEDBACKSTREAMPROC glad_glDrawTransformFeedbackStream; #define glDrawTransformFeedbackStream glad_glDrawTransformFeedbackStream typedef void (APIENTRYP PFNGLBEGINQUERYINDEXEDPROC)(GLenum target, GLuint index, GLuint id); GLAPI PFNGLBEGINQUERYINDEXEDPROC glad_glBeginQueryIndexed; #define glBeginQueryIndexed glad_glBeginQueryIndexed typedef void (APIENTRYP PFNGLENDQUERYINDEXEDPROC)(GLenum target, GLuint index); GLAPI PFNGLENDQUERYINDEXEDPROC glad_glEndQueryIndexed; #define glEndQueryIndexed glad_glEndQueryIndexed typedef void (APIENTRYP PFNGLGETQUERYINDEXEDIVPROC)(GLenum target, GLuint index, GLenum pname, GLint *params); GLAPI PFNGLGETQUERYINDEXEDIVPROC glad_glGetQueryIndexediv; #define glGetQueryIndexediv glad_glGetQueryIndexediv #endif #ifndef GL_VERSION_4_1 #define GL_VERSION_4_1 1 GLAPI int GLAD_GL_VERSION_4_1; typedef void (APIENTRYP PFNGLRELEASESHADERCOMPILERPROC)(void); GLAPI PFNGLRELEASESHADERCOMPILERPROC glad_glReleaseShaderCompiler; #define glReleaseShaderCompiler glad_glReleaseShaderCompiler typedef void (APIENTRYP PFNGLSHADERBINARYPROC)(GLsizei count, const GLuint *shaders, GLenum binaryformat, const void *binary, GLsizei length); GLAPI PFNGLSHADERBINARYPROC glad_glShaderBinary; #define glShaderBinary glad_glShaderBinary typedef void (APIENTRYP PFNGLGETSHADERPRECISIONFORMATPROC)(GLenum shadertype, GLenum precisiontype, GLint *range, GLint *precision); GLAPI PFNGLGETSHADERPRECISIONFORMATPROC glad_glGetShaderPrecisionFormat; #define glGetShaderPrecisionFormat glad_glGetShaderPrecisionFormat typedef void (APIENTRYP PFNGLDEPTHRANGEFPROC)(GLfloat n, GLfloat f); GLAPI PFNGLDEPTHRANGEFPROC glad_glDepthRangef; #define glDepthRangef glad_glDepthRangef typedef void (APIENTRYP PFNGLCLEARDEPTHFPROC)(GLfloat d); GLAPI PFNGLCLEARDEPTHFPROC glad_glClearDepthf; #define glClearDepthf glad_glClearDepthf typedef void (APIENTRYP PFNGLGETPROGRAMBINARYPROC)(GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, void *binary); GLAPI PFNGLGETPROGRAMBINARYPROC glad_glGetProgramBinary; #define glGetProgramBinary glad_glGetProgramBinary typedef void (APIENTRYP PFNGLPROGRAMBINARYPROC)(GLuint program, GLenum binaryFormat, const void *binary, GLsizei length); GLAPI PFNGLPROGRAMBINARYPROC glad_glProgramBinary; #define glProgramBinary glad_glProgramBinary typedef void (APIENTRYP PFNGLPROGRAMPARAMETERIPROC)(GLuint program, GLenum pname, GLint value); GLAPI PFNGLPROGRAMPARAMETERIPROC glad_glProgramParameteri; #define glProgramParameteri glad_glProgramParameteri typedef void (APIENTRYP PFNGLUSEPROGRAMSTAGESPROC)(GLuint pipeline, GLbitfield stages, GLuint program); GLAPI PFNGLUSEPROGRAMSTAGESPROC glad_glUseProgramStages; #define glUseProgramStages glad_glUseProgramStages typedef void (APIENTRYP PFNGLACTIVESHADERPROGRAMPROC)(GLuint pipeline, GLuint program); GLAPI PFNGLACTIVESHADERPROGRAMPROC glad_glActiveShaderProgram; #define glActiveShaderProgram glad_glActiveShaderProgram typedef GLuint (APIENTRYP PFNGLCREATESHADERPROGRAMVPROC)(GLenum type, GLsizei count, const GLchar *const*strings); GLAPI PFNGLCREATESHADERPROGRAMVPROC glad_glCreateShaderProgramv; #define glCreateShaderProgramv glad_glCreateShaderProgramv typedef void (APIENTRYP PFNGLBINDPROGRAMPIPELINEPROC)(GLuint pipeline); GLAPI PFNGLBINDPROGRAMPIPELINEPROC glad_glBindProgramPipeline; #define glBindProgramPipeline glad_glBindProgramPipeline typedef void (APIENTRYP PFNGLDELETEPROGRAMPIPELINESPROC)(GLsizei n, const GLuint *pipelines); GLAPI PFNGLDELETEPROGRAMPIPELINESPROC glad_glDeleteProgramPipelines; #define glDeleteProgramPipelines glad_glDeleteProgramPipelines typedef void (APIENTRYP PFNGLGENPROGRAMPIPELINESPROC)(GLsizei n, GLuint *pipelines); GLAPI PFNGLGENPROGRAMPIPELINESPROC glad_glGenProgramPipelines; #define glGenProgramPipelines glad_glGenProgramPipelines typedef GLboolean (APIENTRYP PFNGLISPROGRAMPIPELINEPROC)(GLuint pipeline); GLAPI PFNGLISPROGRAMPIPELINEPROC glad_glIsProgramPipeline; #define glIsProgramPipeline glad_glIsProgramPipeline typedef void (APIENTRYP PFNGLGETPROGRAMPIPELINEIVPROC)(GLuint pipeline, GLenum pname, GLint *params); GLAPI PFNGLGETPROGRAMPIPELINEIVPROC glad_glGetProgramPipelineiv; #define glGetProgramPipelineiv glad_glGetProgramPipelineiv typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1IPROC)(GLuint program, GLint location, GLint v0); GLAPI PFNGLPROGRAMUNIFORM1IPROC glad_glProgramUniform1i; #define glProgramUniform1i glad_glProgramUniform1i typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1IVPROC)(GLuint program, GLint location, GLsizei count, const GLint *value); GLAPI PFNGLPROGRAMUNIFORM1IVPROC glad_glProgramUniform1iv; #define glProgramUniform1iv glad_glProgramUniform1iv typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1FPROC)(GLuint program, GLint location, GLfloat v0); GLAPI PFNGLPROGRAMUNIFORM1FPROC glad_glProgramUniform1f; #define glProgramUniform1f glad_glProgramUniform1f typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1FVPROC)(GLuint program, GLint location, GLsizei count, const GLfloat *value); GLAPI PFNGLPROGRAMUNIFORM1FVPROC glad_glProgramUniform1fv; #define glProgramUniform1fv glad_glProgramUniform1fv typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1DPROC)(GLuint program, GLint location, GLdouble v0); GLAPI PFNGLPROGRAMUNIFORM1DPROC glad_glProgramUniform1d; #define glProgramUniform1d glad_glProgramUniform1d typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1DVPROC)(GLuint program, GLint location, GLsizei count, const GLdouble *value); GLAPI PFNGLPROGRAMUNIFORM1DVPROC glad_glProgramUniform1dv; #define glProgramUniform1dv glad_glProgramUniform1dv typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1UIPROC)(GLuint program, GLint location, GLuint v0); GLAPI PFNGLPROGRAMUNIFORM1UIPROC glad_glProgramUniform1ui; #define glProgramUniform1ui glad_glProgramUniform1ui typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1UIVPROC)(GLuint program, GLint location, GLsizei count, const GLuint *value); GLAPI PFNGLPROGRAMUNIFORM1UIVPROC glad_glProgramUniform1uiv; #define glProgramUniform1uiv glad_glProgramUniform1uiv typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2IPROC)(GLuint program, GLint location, GLint v0, GLint v1); GLAPI PFNGLPROGRAMUNIFORM2IPROC glad_glProgramUniform2i; #define glProgramUniform2i glad_glProgramUniform2i typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2IVPROC)(GLuint program, GLint location, GLsizei count, const GLint *value); GLAPI PFNGLPROGRAMUNIFORM2IVPROC glad_glProgramUniform2iv; #define glProgramUniform2iv glad_glProgramUniform2iv typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2FPROC)(GLuint program, GLint location, GLfloat v0, GLfloat v1); GLAPI PFNGLPROGRAMUNIFORM2FPROC glad_glProgramUniform2f; #define glProgramUniform2f glad_glProgramUniform2f typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2FVPROC)(GLuint program, GLint location, GLsizei count, const GLfloat *value); GLAPI PFNGLPROGRAMUNIFORM2FVPROC glad_glProgramUniform2fv; #define glProgramUniform2fv glad_glProgramUniform2fv typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2DPROC)(GLuint program, GLint location, GLdouble v0, GLdouble v1); GLAPI PFNGLPROGRAMUNIFORM2DPROC glad_glProgramUniform2d; #define glProgramUniform2d glad_glProgramUniform2d typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2DVPROC)(GLuint program, GLint location, GLsizei count, const GLdouble *value); GLAPI PFNGLPROGRAMUNIFORM2DVPROC glad_glProgramUniform2dv; #define glProgramUniform2dv glad_glProgramUniform2dv typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2UIPROC)(GLuint program, GLint location, GLuint v0, GLuint v1); GLAPI PFNGLPROGRAMUNIFORM2UIPROC glad_glProgramUniform2ui; #define glProgramUniform2ui glad_glProgramUniform2ui typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2UIVPROC)(GLuint program, GLint location, GLsizei count, const GLuint *value); GLAPI PFNGLPROGRAMUNIFORM2UIVPROC glad_glProgramUniform2uiv; #define glProgramUniform2uiv glad_glProgramUniform2uiv typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3IPROC)(GLuint program, GLint location, GLint v0, GLint v1, GLint v2); GLAPI PFNGLPROGRAMUNIFORM3IPROC glad_glProgramUniform3i; #define glProgramUniform3i glad_glProgramUniform3i typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3IVPROC)(GLuint program, GLint location, GLsizei count, const GLint *value); GLAPI PFNGLPROGRAMUNIFORM3IVPROC glad_glProgramUniform3iv; #define glProgramUniform3iv glad_glProgramUniform3iv typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3FPROC)(GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2); GLAPI PFNGLPROGRAMUNIFORM3FPROC glad_glProgramUniform3f; #define glProgramUniform3f glad_glProgramUniform3f typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3FVPROC)(GLuint program, GLint location, GLsizei count, const GLfloat *value); GLAPI PFNGLPROGRAMUNIFORM3FVPROC glad_glProgramUniform3fv; #define glProgramUniform3fv glad_glProgramUniform3fv typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3DPROC)(GLuint program, GLint location, GLdouble v0, GLdouble v1, GLdouble v2); GLAPI PFNGLPROGRAMUNIFORM3DPROC glad_glProgramUniform3d; #define glProgramUniform3d glad_glProgramUniform3d typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3DVPROC)(GLuint program, GLint location, GLsizei count, const GLdouble *value); GLAPI PFNGLPROGRAMUNIFORM3DVPROC glad_glProgramUniform3dv; #define glProgramUniform3dv glad_glProgramUniform3dv typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3UIPROC)(GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2); GLAPI PFNGLPROGRAMUNIFORM3UIPROC glad_glProgramUniform3ui; #define glProgramUniform3ui glad_glProgramUniform3ui typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3UIVPROC)(GLuint program, GLint location, GLsizei count, const GLuint *value); GLAPI PFNGLPROGRAMUNIFORM3UIVPROC glad_glProgramUniform3uiv; #define glProgramUniform3uiv glad_glProgramUniform3uiv typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4IPROC)(GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLint v3); GLAPI PFNGLPROGRAMUNIFORM4IPROC glad_glProgramUniform4i; #define glProgramUniform4i glad_glProgramUniform4i typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4IVPROC)(GLuint program, GLint location, GLsizei count, const GLint *value); GLAPI PFNGLPROGRAMUNIFORM4IVPROC glad_glProgramUniform4iv; #define glProgramUniform4iv glad_glProgramUniform4iv typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4FPROC)(GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); GLAPI PFNGLPROGRAMUNIFORM4FPROC glad_glProgramUniform4f; #define glProgramUniform4f glad_glProgramUniform4f typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4FVPROC)(GLuint program, GLint location, GLsizei count, const GLfloat *value); GLAPI PFNGLPROGRAMUNIFORM4FVPROC glad_glProgramUniform4fv; #define glProgramUniform4fv glad_glProgramUniform4fv typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4DPROC)(GLuint program, GLint location, GLdouble v0, GLdouble v1, GLdouble v2, GLdouble v3); GLAPI PFNGLPROGRAMUNIFORM4DPROC glad_glProgramUniform4d; #define glProgramUniform4d glad_glProgramUniform4d typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4DVPROC)(GLuint program, GLint location, GLsizei count, const GLdouble *value); GLAPI PFNGLPROGRAMUNIFORM4DVPROC glad_glProgramUniform4dv; #define glProgramUniform4dv glad_glProgramUniform4dv typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4UIPROC)(GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); GLAPI PFNGLPROGRAMUNIFORM4UIPROC glad_glProgramUniform4ui; #define glProgramUniform4ui glad_glProgramUniform4ui typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4UIVPROC)(GLuint program, GLint location, GLsizei count, const GLuint *value); GLAPI PFNGLPROGRAMUNIFORM4UIVPROC glad_glProgramUniform4uiv; #define glProgramUniform4uiv glad_glProgramUniform4uiv typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2FVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GLAPI PFNGLPROGRAMUNIFORMMATRIX2FVPROC glad_glProgramUniformMatrix2fv; #define glProgramUniformMatrix2fv glad_glProgramUniformMatrix2fv typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3FVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GLAPI PFNGLPROGRAMUNIFORMMATRIX3FVPROC glad_glProgramUniformMatrix3fv; #define glProgramUniformMatrix3fv glad_glProgramUniformMatrix3fv typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4FVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GLAPI PFNGLPROGRAMUNIFORMMATRIX4FVPROC glad_glProgramUniformMatrix4fv; #define glProgramUniformMatrix4fv glad_glProgramUniformMatrix4fv typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2DVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); GLAPI PFNGLPROGRAMUNIFORMMATRIX2DVPROC glad_glProgramUniformMatrix2dv; #define glProgramUniformMatrix2dv glad_glProgramUniformMatrix2dv typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3DVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); GLAPI PFNGLPROGRAMUNIFORMMATRIX3DVPROC glad_glProgramUniformMatrix3dv; #define glProgramUniformMatrix3dv glad_glProgramUniformMatrix3dv typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4DVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); GLAPI PFNGLPROGRAMUNIFORMMATRIX4DVPROC glad_glProgramUniformMatrix4dv; #define glProgramUniformMatrix4dv glad_glProgramUniformMatrix4dv typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X3FVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GLAPI PFNGLPROGRAMUNIFORMMATRIX2X3FVPROC glad_glProgramUniformMatrix2x3fv; #define glProgramUniformMatrix2x3fv glad_glProgramUniformMatrix2x3fv typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X2FVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GLAPI PFNGLPROGRAMUNIFORMMATRIX3X2FVPROC glad_glProgramUniformMatrix3x2fv; #define glProgramUniformMatrix3x2fv glad_glProgramUniformMatrix3x2fv typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X4FVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GLAPI PFNGLPROGRAMUNIFORMMATRIX2X4FVPROC glad_glProgramUniformMatrix2x4fv; #define glProgramUniformMatrix2x4fv glad_glProgramUniformMatrix2x4fv typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X2FVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GLAPI PFNGLPROGRAMUNIFORMMATRIX4X2FVPROC glad_glProgramUniformMatrix4x2fv; #define glProgramUniformMatrix4x2fv glad_glProgramUniformMatrix4x2fv typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X4FVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GLAPI PFNGLPROGRAMUNIFORMMATRIX3X4FVPROC glad_glProgramUniformMatrix3x4fv; #define glProgramUniformMatrix3x4fv glad_glProgramUniformMatrix3x4fv typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X3FVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GLAPI PFNGLPROGRAMUNIFORMMATRIX4X3FVPROC glad_glProgramUniformMatrix4x3fv; #define glProgramUniformMatrix4x3fv glad_glProgramUniformMatrix4x3fv typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X3DVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); GLAPI PFNGLPROGRAMUNIFORMMATRIX2X3DVPROC glad_glProgramUniformMatrix2x3dv; #define glProgramUniformMatrix2x3dv glad_glProgramUniformMatrix2x3dv typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X2DVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); GLAPI PFNGLPROGRAMUNIFORMMATRIX3X2DVPROC glad_glProgramUniformMatrix3x2dv; #define glProgramUniformMatrix3x2dv glad_glProgramUniformMatrix3x2dv typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2X4DVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); GLAPI PFNGLPROGRAMUNIFORMMATRIX2X4DVPROC glad_glProgramUniformMatrix2x4dv; #define glProgramUniformMatrix2x4dv glad_glProgramUniformMatrix2x4dv typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X2DVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); GLAPI PFNGLPROGRAMUNIFORMMATRIX4X2DVPROC glad_glProgramUniformMatrix4x2dv; #define glProgramUniformMatrix4x2dv glad_glProgramUniformMatrix4x2dv typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3X4DVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); GLAPI PFNGLPROGRAMUNIFORMMATRIX3X4DVPROC glad_glProgramUniformMatrix3x4dv; #define glProgramUniformMatrix3x4dv glad_glProgramUniformMatrix3x4dv typedef void (APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4X3DVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); GLAPI PFNGLPROGRAMUNIFORMMATRIX4X3DVPROC glad_glProgramUniformMatrix4x3dv; #define glProgramUniformMatrix4x3dv glad_glProgramUniformMatrix4x3dv typedef void (APIENTRYP PFNGLVALIDATEPROGRAMPIPELINEPROC)(GLuint pipeline); GLAPI PFNGLVALIDATEPROGRAMPIPELINEPROC glad_glValidateProgramPipeline; #define glValidateProgramPipeline glad_glValidateProgramPipeline typedef void (APIENTRYP PFNGLGETPROGRAMPIPELINEINFOLOGPROC)(GLuint pipeline, GLsizei bufSize, GLsizei *length, GLchar *infoLog); GLAPI PFNGLGETPROGRAMPIPELINEINFOLOGPROC glad_glGetProgramPipelineInfoLog; #define glGetProgramPipelineInfoLog glad_glGetProgramPipelineInfoLog typedef void (APIENTRYP PFNGLVERTEXATTRIBL1DPROC)(GLuint index, GLdouble x); GLAPI PFNGLVERTEXATTRIBL1DPROC glad_glVertexAttribL1d; #define glVertexAttribL1d glad_glVertexAttribL1d typedef void (APIENTRYP PFNGLVERTEXATTRIBL2DPROC)(GLuint index, GLdouble x, GLdouble y); GLAPI PFNGLVERTEXATTRIBL2DPROC glad_glVertexAttribL2d; #define glVertexAttribL2d glad_glVertexAttribL2d typedef void (APIENTRYP PFNGLVERTEXATTRIBL3DPROC)(GLuint index, GLdouble x, GLdouble y, GLdouble z); GLAPI PFNGLVERTEXATTRIBL3DPROC glad_glVertexAttribL3d; #define glVertexAttribL3d glad_glVertexAttribL3d typedef void (APIENTRYP PFNGLVERTEXATTRIBL4DPROC)(GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); GLAPI PFNGLVERTEXATTRIBL4DPROC glad_glVertexAttribL4d; #define glVertexAttribL4d glad_glVertexAttribL4d typedef void (APIENTRYP PFNGLVERTEXATTRIBL1DVPROC)(GLuint index, const GLdouble *v); GLAPI PFNGLVERTEXATTRIBL1DVPROC glad_glVertexAttribL1dv; #define glVertexAttribL1dv glad_glVertexAttribL1dv typedef void (APIENTRYP PFNGLVERTEXATTRIBL2DVPROC)(GLuint index, const GLdouble *v); GLAPI PFNGLVERTEXATTRIBL2DVPROC glad_glVertexAttribL2dv; #define glVertexAttribL2dv glad_glVertexAttribL2dv typedef void (APIENTRYP PFNGLVERTEXATTRIBL3DVPROC)(GLuint index, const GLdouble *v); GLAPI PFNGLVERTEXATTRIBL3DVPROC glad_glVertexAttribL3dv; #define glVertexAttribL3dv glad_glVertexAttribL3dv typedef void (APIENTRYP PFNGLVERTEXATTRIBL4DVPROC)(GLuint index, const GLdouble *v); GLAPI PFNGLVERTEXATTRIBL4DVPROC glad_glVertexAttribL4dv; #define glVertexAttribL4dv glad_glVertexAttribL4dv typedef void (APIENTRYP PFNGLVERTEXATTRIBLPOINTERPROC)(GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer); GLAPI PFNGLVERTEXATTRIBLPOINTERPROC glad_glVertexAttribLPointer; #define glVertexAttribLPointer glad_glVertexAttribLPointer typedef void (APIENTRYP PFNGLGETVERTEXATTRIBLDVPROC)(GLuint index, GLenum pname, GLdouble *params); GLAPI PFNGLGETVERTEXATTRIBLDVPROC glad_glGetVertexAttribLdv; #define glGetVertexAttribLdv glad_glGetVertexAttribLdv typedef void (APIENTRYP PFNGLVIEWPORTARRAYVPROC)(GLuint first, GLsizei count, const GLfloat *v); GLAPI PFNGLVIEWPORTARRAYVPROC glad_glViewportArrayv; #define glViewportArrayv glad_glViewportArrayv typedef void (APIENTRYP PFNGLVIEWPORTINDEXEDFPROC)(GLuint index, GLfloat x, GLfloat y, GLfloat w, GLfloat h); GLAPI PFNGLVIEWPORTINDEXEDFPROC glad_glViewportIndexedf; #define glViewportIndexedf glad_glViewportIndexedf typedef void (APIENTRYP PFNGLVIEWPORTINDEXEDFVPROC)(GLuint index, const GLfloat *v); GLAPI PFNGLVIEWPORTINDEXEDFVPROC glad_glViewportIndexedfv; #define glViewportIndexedfv glad_glViewportIndexedfv typedef void (APIENTRYP PFNGLSCISSORARRAYVPROC)(GLuint first, GLsizei count, const GLint *v); GLAPI PFNGLSCISSORARRAYVPROC glad_glScissorArrayv; #define glScissorArrayv glad_glScissorArrayv typedef void (APIENTRYP PFNGLSCISSORINDEXEDPROC)(GLuint index, GLint left, GLint bottom, GLsizei width, GLsizei height); GLAPI PFNGLSCISSORINDEXEDPROC glad_glScissorIndexed; #define glScissorIndexed glad_glScissorIndexed typedef void (APIENTRYP PFNGLSCISSORINDEXEDVPROC)(GLuint index, const GLint *v); GLAPI PFNGLSCISSORINDEXEDVPROC glad_glScissorIndexedv; #define glScissorIndexedv glad_glScissorIndexedv typedef void (APIENTRYP PFNGLDEPTHRANGEARRAYVPROC)(GLuint first, GLsizei count, const GLdouble *v); GLAPI PFNGLDEPTHRANGEARRAYVPROC glad_glDepthRangeArrayv; #define glDepthRangeArrayv glad_glDepthRangeArrayv typedef void (APIENTRYP PFNGLDEPTHRANGEINDEXEDPROC)(GLuint index, GLdouble n, GLdouble f); GLAPI PFNGLDEPTHRANGEINDEXEDPROC glad_glDepthRangeIndexed; #define glDepthRangeIndexed glad_glDepthRangeIndexed typedef void (APIENTRYP PFNGLGETFLOATI_VPROC)(GLenum target, GLuint index, GLfloat *data); GLAPI PFNGLGETFLOATI_VPROC glad_glGetFloati_v; #define glGetFloati_v glad_glGetFloati_v typedef void (APIENTRYP PFNGLGETDOUBLEI_VPROC)(GLenum target, GLuint index, GLdouble *data); GLAPI PFNGLGETDOUBLEI_VPROC glad_glGetDoublei_v; #define glGetDoublei_v glad_glGetDoublei_v #endif #ifndef GL_VERSION_4_2 #define GL_VERSION_4_2 1 GLAPI int GLAD_GL_VERSION_4_2; typedef void (APIENTRYP PFNGLDRAWARRAYSINSTANCEDBASEINSTANCEPROC)(GLenum mode, GLint first, GLsizei count, GLsizei instancecount, GLuint baseinstance); GLAPI PFNGLDRAWARRAYSINSTANCEDBASEINSTANCEPROC glad_glDrawArraysInstancedBaseInstance; #define glDrawArraysInstancedBaseInstance glad_glDrawArraysInstancedBaseInstance typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDBASEINSTANCEPROC)(GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLuint baseinstance); GLAPI PFNGLDRAWELEMENTSINSTANCEDBASEINSTANCEPROC glad_glDrawElementsInstancedBaseInstance; #define glDrawElementsInstancedBaseInstance glad_glDrawElementsInstancedBaseInstance typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEPROC)(GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex, GLuint baseinstance); GLAPI PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEPROC glad_glDrawElementsInstancedBaseVertexBaseInstance; #define glDrawElementsInstancedBaseVertexBaseInstance glad_glDrawElementsInstancedBaseVertexBaseInstance typedef void (APIENTRYP PFNGLGETINTERNALFORMATIVPROC)(GLenum target, GLenum internalformat, GLenum pname, GLsizei count, GLint *params); GLAPI PFNGLGETINTERNALFORMATIVPROC glad_glGetInternalformativ; #define glGetInternalformativ glad_glGetInternalformativ typedef void (APIENTRYP PFNGLGETACTIVEATOMICCOUNTERBUFFERIVPROC)(GLuint program, GLuint bufferIndex, GLenum pname, GLint *params); GLAPI PFNGLGETACTIVEATOMICCOUNTERBUFFERIVPROC glad_glGetActiveAtomicCounterBufferiv; #define glGetActiveAtomicCounterBufferiv glad_glGetActiveAtomicCounterBufferiv typedef void (APIENTRYP PFNGLBINDIMAGETEXTUREPROC)(GLuint unit, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access, GLenum format); GLAPI PFNGLBINDIMAGETEXTUREPROC glad_glBindImageTexture; #define glBindImageTexture glad_glBindImageTexture typedef void (APIENTRYP PFNGLMEMORYBARRIERPROC)(GLbitfield barriers); GLAPI PFNGLMEMORYBARRIERPROC glad_glMemoryBarrier; #define glMemoryBarrier glad_glMemoryBarrier typedef void (APIENTRYP PFNGLTEXSTORAGE1DPROC)(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width); GLAPI PFNGLTEXSTORAGE1DPROC glad_glTexStorage1D; #define glTexStorage1D glad_glTexStorage1D typedef void (APIENTRYP PFNGLTEXSTORAGE2DPROC)(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height); GLAPI PFNGLTEXSTORAGE2DPROC glad_glTexStorage2D; #define glTexStorage2D glad_glTexStorage2D typedef void (APIENTRYP PFNGLTEXSTORAGE3DPROC)(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); GLAPI PFNGLTEXSTORAGE3DPROC glad_glTexStorage3D; #define glTexStorage3D glad_glTexStorage3D typedef void (APIENTRYP PFNGLDRAWTRANSFORMFEEDBACKINSTANCEDPROC)(GLenum mode, GLuint id, GLsizei instancecount); GLAPI PFNGLDRAWTRANSFORMFEEDBACKINSTANCEDPROC glad_glDrawTransformFeedbackInstanced; #define glDrawTransformFeedbackInstanced glad_glDrawTransformFeedbackInstanced typedef void (APIENTRYP PFNGLDRAWTRANSFORMFEEDBACKSTREAMINSTANCEDPROC)(GLenum mode, GLuint id, GLuint stream, GLsizei instancecount); GLAPI PFNGLDRAWTRANSFORMFEEDBACKSTREAMINSTANCEDPROC glad_glDrawTransformFeedbackStreamInstanced; #define glDrawTransformFeedbackStreamInstanced glad_glDrawTransformFeedbackStreamInstanced #endif #ifndef GL_VERSION_4_3 #define GL_VERSION_4_3 1 GLAPI int GLAD_GL_VERSION_4_3; typedef void (APIENTRYP PFNGLCLEARBUFFERDATAPROC)(GLenum target, GLenum internalformat, GLenum format, GLenum type, const void *data); GLAPI PFNGLCLEARBUFFERDATAPROC glad_glClearBufferData; #define glClearBufferData glad_glClearBufferData typedef void (APIENTRYP PFNGLCLEARBUFFERSUBDATAPROC)(GLenum target, GLenum internalformat, GLintptr offset, GLsizeiptr size, GLenum format, GLenum type, const void *data); GLAPI PFNGLCLEARBUFFERSUBDATAPROC glad_glClearBufferSubData; #define glClearBufferSubData glad_glClearBufferSubData typedef void (APIENTRYP PFNGLDISPATCHCOMPUTEPROC)(GLuint num_groups_x, GLuint num_groups_y, GLuint num_groups_z); GLAPI PFNGLDISPATCHCOMPUTEPROC glad_glDispatchCompute; #define glDispatchCompute glad_glDispatchCompute typedef void (APIENTRYP PFNGLDISPATCHCOMPUTEINDIRECTPROC)(GLintptr indirect); GLAPI PFNGLDISPATCHCOMPUTEINDIRECTPROC glad_glDispatchComputeIndirect; #define glDispatchComputeIndirect glad_glDispatchComputeIndirect typedef void (APIENTRYP PFNGLCOPYIMAGESUBDATAPROC)(GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth); GLAPI PFNGLCOPYIMAGESUBDATAPROC glad_glCopyImageSubData; #define glCopyImageSubData glad_glCopyImageSubData typedef void (APIENTRYP PFNGLFRAMEBUFFERPARAMETERIPROC)(GLenum target, GLenum pname, GLint param); GLAPI PFNGLFRAMEBUFFERPARAMETERIPROC glad_glFramebufferParameteri; #define glFramebufferParameteri glad_glFramebufferParameteri typedef void (APIENTRYP PFNGLGETFRAMEBUFFERPARAMETERIVPROC)(GLenum target, GLenum pname, GLint *params); GLAPI PFNGLGETFRAMEBUFFERPARAMETERIVPROC glad_glGetFramebufferParameteriv; #define glGetFramebufferParameteriv glad_glGetFramebufferParameteriv typedef void (APIENTRYP PFNGLGETINTERNALFORMATI64VPROC)(GLenum target, GLenum internalformat, GLenum pname, GLsizei count, GLint64 *params); GLAPI PFNGLGETINTERNALFORMATI64VPROC glad_glGetInternalformati64v; #define glGetInternalformati64v glad_glGetInternalformati64v typedef void (APIENTRYP PFNGLINVALIDATETEXSUBIMAGEPROC)(GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth); GLAPI PFNGLINVALIDATETEXSUBIMAGEPROC glad_glInvalidateTexSubImage; #define glInvalidateTexSubImage glad_glInvalidateTexSubImage typedef void (APIENTRYP PFNGLINVALIDATETEXIMAGEPROC)(GLuint texture, GLint level); GLAPI PFNGLINVALIDATETEXIMAGEPROC glad_glInvalidateTexImage; #define glInvalidateTexImage glad_glInvalidateTexImage typedef void (APIENTRYP PFNGLINVALIDATEBUFFERSUBDATAPROC)(GLuint buffer, GLintptr offset, GLsizeiptr length); GLAPI PFNGLINVALIDATEBUFFERSUBDATAPROC glad_glInvalidateBufferSubData; #define glInvalidateBufferSubData glad_glInvalidateBufferSubData typedef void (APIENTRYP PFNGLINVALIDATEBUFFERDATAPROC)(GLuint buffer); GLAPI PFNGLINVALIDATEBUFFERDATAPROC glad_glInvalidateBufferData; #define glInvalidateBufferData glad_glInvalidateBufferData typedef void (APIENTRYP PFNGLINVALIDATEFRAMEBUFFERPROC)(GLenum target, GLsizei numAttachments, const GLenum *attachments); GLAPI PFNGLINVALIDATEFRAMEBUFFERPROC glad_glInvalidateFramebuffer; #define glInvalidateFramebuffer glad_glInvalidateFramebuffer typedef void (APIENTRYP PFNGLINVALIDATESUBFRAMEBUFFERPROC)(GLenum target, GLsizei numAttachments, const GLenum *attachments, GLint x, GLint y, GLsizei width, GLsizei height); GLAPI PFNGLINVALIDATESUBFRAMEBUFFERPROC glad_glInvalidateSubFramebuffer; #define glInvalidateSubFramebuffer glad_glInvalidateSubFramebuffer typedef void (APIENTRYP PFNGLMULTIDRAWARRAYSINDIRECTPROC)(GLenum mode, const void *indirect, GLsizei drawcount, GLsizei stride); GLAPI PFNGLMULTIDRAWARRAYSINDIRECTPROC glad_glMultiDrawArraysIndirect; #define glMultiDrawArraysIndirect glad_glMultiDrawArraysIndirect typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSINDIRECTPROC)(GLenum mode, GLenum type, const void *indirect, GLsizei drawcount, GLsizei stride); GLAPI PFNGLMULTIDRAWELEMENTSINDIRECTPROC glad_glMultiDrawElementsIndirect; #define glMultiDrawElementsIndirect glad_glMultiDrawElementsIndirect typedef void (APIENTRYP PFNGLGETPROGRAMINTERFACEIVPROC)(GLuint program, GLenum programInterface, GLenum pname, GLint *params); GLAPI PFNGLGETPROGRAMINTERFACEIVPROC glad_glGetProgramInterfaceiv; #define glGetProgramInterfaceiv glad_glGetProgramInterfaceiv typedef GLuint (APIENTRYP PFNGLGETPROGRAMRESOURCEINDEXPROC)(GLuint program, GLenum programInterface, const GLchar *name); GLAPI PFNGLGETPROGRAMRESOURCEINDEXPROC glad_glGetProgramResourceIndex; #define glGetProgramResourceIndex glad_glGetProgramResourceIndex typedef void (APIENTRYP PFNGLGETPROGRAMRESOURCENAMEPROC)(GLuint program, GLenum programInterface, GLuint index, GLsizei bufSize, GLsizei *length, GLchar *name); GLAPI PFNGLGETPROGRAMRESOURCENAMEPROC glad_glGetProgramResourceName; #define glGetProgramResourceName glad_glGetProgramResourceName typedef void (APIENTRYP PFNGLGETPROGRAMRESOURCEIVPROC)(GLuint program, GLenum programInterface, GLuint index, GLsizei propCount, const GLenum *props, GLsizei count, GLsizei *length, GLint *params); GLAPI PFNGLGETPROGRAMRESOURCEIVPROC glad_glGetProgramResourceiv; #define glGetProgramResourceiv glad_glGetProgramResourceiv typedef GLint (APIENTRYP PFNGLGETPROGRAMRESOURCELOCATIONPROC)(GLuint program, GLenum programInterface, const GLchar *name); GLAPI PFNGLGETPROGRAMRESOURCELOCATIONPROC glad_glGetProgramResourceLocation; #define glGetProgramResourceLocation glad_glGetProgramResourceLocation typedef GLint (APIENTRYP PFNGLGETPROGRAMRESOURCELOCATIONINDEXPROC)(GLuint program, GLenum programInterface, const GLchar *name); GLAPI PFNGLGETPROGRAMRESOURCELOCATIONINDEXPROC glad_glGetProgramResourceLocationIndex; #define glGetProgramResourceLocationIndex glad_glGetProgramResourceLocationIndex typedef void (APIENTRYP PFNGLSHADERSTORAGEBLOCKBINDINGPROC)(GLuint program, GLuint storageBlockIndex, GLuint storageBlockBinding); GLAPI PFNGLSHADERSTORAGEBLOCKBINDINGPROC glad_glShaderStorageBlockBinding; #define glShaderStorageBlockBinding glad_glShaderStorageBlockBinding typedef void (APIENTRYP PFNGLTEXBUFFERRANGEPROC)(GLenum target, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size); GLAPI PFNGLTEXBUFFERRANGEPROC glad_glTexBufferRange; #define glTexBufferRange glad_glTexBufferRange typedef void (APIENTRYP PFNGLTEXSTORAGE2DMULTISAMPLEPROC)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations); GLAPI PFNGLTEXSTORAGE2DMULTISAMPLEPROC glad_glTexStorage2DMultisample; #define glTexStorage2DMultisample glad_glTexStorage2DMultisample typedef void (APIENTRYP PFNGLTEXSTORAGE3DMULTISAMPLEPROC)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations); GLAPI PFNGLTEXSTORAGE3DMULTISAMPLEPROC glad_glTexStorage3DMultisample; #define glTexStorage3DMultisample glad_glTexStorage3DMultisample typedef void (APIENTRYP PFNGLTEXTUREVIEWPROC)(GLuint texture, GLenum target, GLuint origtexture, GLenum internalformat, GLuint minlevel, GLuint numlevels, GLuint minlayer, GLuint numlayers); GLAPI PFNGLTEXTUREVIEWPROC glad_glTextureView; #define glTextureView glad_glTextureView typedef void (APIENTRYP PFNGLBINDVERTEXBUFFERPROC)(GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride); GLAPI PFNGLBINDVERTEXBUFFERPROC glad_glBindVertexBuffer; #define glBindVertexBuffer glad_glBindVertexBuffer typedef void (APIENTRYP PFNGLVERTEXATTRIBFORMATPROC)(GLuint attribindex, GLint size, GLenum type, GLboolean normalized, GLuint relativeoffset); GLAPI PFNGLVERTEXATTRIBFORMATPROC glad_glVertexAttribFormat; #define glVertexAttribFormat glad_glVertexAttribFormat typedef void (APIENTRYP PFNGLVERTEXATTRIBIFORMATPROC)(GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset); GLAPI PFNGLVERTEXATTRIBIFORMATPROC glad_glVertexAttribIFormat; #define glVertexAttribIFormat glad_glVertexAttribIFormat typedef void (APIENTRYP PFNGLVERTEXATTRIBLFORMATPROC)(GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset); GLAPI PFNGLVERTEXATTRIBLFORMATPROC glad_glVertexAttribLFormat; #define glVertexAttribLFormat glad_glVertexAttribLFormat typedef void (APIENTRYP PFNGLVERTEXATTRIBBINDINGPROC)(GLuint attribindex, GLuint bindingindex); GLAPI PFNGLVERTEXATTRIBBINDINGPROC glad_glVertexAttribBinding; #define glVertexAttribBinding glad_glVertexAttribBinding typedef void (APIENTRYP PFNGLVERTEXBINDINGDIVISORPROC)(GLuint bindingindex, GLuint divisor); GLAPI PFNGLVERTEXBINDINGDIVISORPROC glad_glVertexBindingDivisor; #define glVertexBindingDivisor glad_glVertexBindingDivisor typedef void (APIENTRYP PFNGLDEBUGMESSAGECONTROLPROC)(GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled); GLAPI PFNGLDEBUGMESSAGECONTROLPROC glad_glDebugMessageControl; #define glDebugMessageControl glad_glDebugMessageControl typedef void (APIENTRYP PFNGLDEBUGMESSAGEINSERTPROC)(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf); GLAPI PFNGLDEBUGMESSAGEINSERTPROC glad_glDebugMessageInsert; #define glDebugMessageInsert glad_glDebugMessageInsert typedef void (APIENTRYP PFNGLDEBUGMESSAGECALLBACKPROC)(GLDEBUGPROC callback, const void *userParam); GLAPI PFNGLDEBUGMESSAGECALLBACKPROC glad_glDebugMessageCallback; #define glDebugMessageCallback glad_glDebugMessageCallback typedef GLuint (APIENTRYP PFNGLGETDEBUGMESSAGELOGPROC)(GLuint count, GLsizei bufSize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog); GLAPI PFNGLGETDEBUGMESSAGELOGPROC glad_glGetDebugMessageLog; #define glGetDebugMessageLog glad_glGetDebugMessageLog typedef void (APIENTRYP PFNGLPUSHDEBUGGROUPPROC)(GLenum source, GLuint id, GLsizei length, const GLchar *message); GLAPI PFNGLPUSHDEBUGGROUPPROC glad_glPushDebugGroup; #define glPushDebugGroup glad_glPushDebugGroup typedef void (APIENTRYP PFNGLPOPDEBUGGROUPPROC)(void); GLAPI PFNGLPOPDEBUGGROUPPROC glad_glPopDebugGroup; #define glPopDebugGroup glad_glPopDebugGroup typedef void (APIENTRYP PFNGLOBJECTLABELPROC)(GLenum identifier, GLuint name, GLsizei length, const GLchar *label); GLAPI PFNGLOBJECTLABELPROC glad_glObjectLabel; #define glObjectLabel glad_glObjectLabel typedef void (APIENTRYP PFNGLGETOBJECTLABELPROC)(GLenum identifier, GLuint name, GLsizei bufSize, GLsizei *length, GLchar *label); GLAPI PFNGLGETOBJECTLABELPROC glad_glGetObjectLabel; #define glGetObjectLabel glad_glGetObjectLabel typedef void (APIENTRYP PFNGLOBJECTPTRLABELPROC)(const void *ptr, GLsizei length, const GLchar *label); GLAPI PFNGLOBJECTPTRLABELPROC glad_glObjectPtrLabel; #define glObjectPtrLabel glad_glObjectPtrLabel typedef void (APIENTRYP PFNGLGETOBJECTPTRLABELPROC)(const void *ptr, GLsizei bufSize, GLsizei *length, GLchar *label); GLAPI PFNGLGETOBJECTPTRLABELPROC glad_glGetObjectPtrLabel; #define glGetObjectPtrLabel glad_glGetObjectPtrLabel #endif #ifndef GL_VERSION_4_4 #define GL_VERSION_4_4 1 GLAPI int GLAD_GL_VERSION_4_4; typedef void (APIENTRYP PFNGLBUFFERSTORAGEPROC)(GLenum target, GLsizeiptr size, const void *data, GLbitfield flags); GLAPI PFNGLBUFFERSTORAGEPROC glad_glBufferStorage; #define glBufferStorage glad_glBufferStorage typedef void (APIENTRYP PFNGLCLEARTEXIMAGEPROC)(GLuint texture, GLint level, GLenum format, GLenum type, const void *data); GLAPI PFNGLCLEARTEXIMAGEPROC glad_glClearTexImage; #define glClearTexImage glad_glClearTexImage typedef void (APIENTRYP PFNGLCLEARTEXSUBIMAGEPROC)(GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *data); GLAPI PFNGLCLEARTEXSUBIMAGEPROC glad_glClearTexSubImage; #define glClearTexSubImage glad_glClearTexSubImage typedef void (APIENTRYP PFNGLBINDBUFFERSBASEPROC)(GLenum target, GLuint first, GLsizei count, const GLuint *buffers); GLAPI PFNGLBINDBUFFERSBASEPROC glad_glBindBuffersBase; #define glBindBuffersBase glad_glBindBuffersBase typedef void (APIENTRYP PFNGLBINDBUFFERSRANGEPROC)(GLenum target, GLuint first, GLsizei count, const GLuint *buffers, const GLintptr *offsets, const GLsizeiptr *sizes); GLAPI PFNGLBINDBUFFERSRANGEPROC glad_glBindBuffersRange; #define glBindBuffersRange glad_glBindBuffersRange typedef void (APIENTRYP PFNGLBINDTEXTURESPROC)(GLuint first, GLsizei count, const GLuint *textures); GLAPI PFNGLBINDTEXTURESPROC glad_glBindTextures; #define glBindTextures glad_glBindTextures typedef void (APIENTRYP PFNGLBINDSAMPLERSPROC)(GLuint first, GLsizei count, const GLuint *samplers); GLAPI PFNGLBINDSAMPLERSPROC glad_glBindSamplers; #define glBindSamplers glad_glBindSamplers typedef void (APIENTRYP PFNGLBINDIMAGETEXTURESPROC)(GLuint first, GLsizei count, const GLuint *textures); GLAPI PFNGLBINDIMAGETEXTURESPROC glad_glBindImageTextures; #define glBindImageTextures glad_glBindImageTextures typedef void (APIENTRYP PFNGLBINDVERTEXBUFFERSPROC)(GLuint first, GLsizei count, const GLuint *buffers, const GLintptr *offsets, const GLsizei *strides); GLAPI PFNGLBINDVERTEXBUFFERSPROC glad_glBindVertexBuffers; #define glBindVertexBuffers glad_glBindVertexBuffers #endif #ifndef GL_VERSION_4_5 #define GL_VERSION_4_5 1 GLAPI int GLAD_GL_VERSION_4_5; typedef void (APIENTRYP PFNGLCLIPCONTROLPROC)(GLenum origin, GLenum depth); GLAPI PFNGLCLIPCONTROLPROC glad_glClipControl; #define glClipControl glad_glClipControl typedef void (APIENTRYP PFNGLCREATETRANSFORMFEEDBACKSPROC)(GLsizei n, GLuint *ids); GLAPI PFNGLCREATETRANSFORMFEEDBACKSPROC glad_glCreateTransformFeedbacks; #define glCreateTransformFeedbacks glad_glCreateTransformFeedbacks typedef void (APIENTRYP PFNGLTRANSFORMFEEDBACKBUFFERBASEPROC)(GLuint xfb, GLuint index, GLuint buffer); GLAPI PFNGLTRANSFORMFEEDBACKBUFFERBASEPROC glad_glTransformFeedbackBufferBase; #define glTransformFeedbackBufferBase glad_glTransformFeedbackBufferBase typedef void (APIENTRYP PFNGLTRANSFORMFEEDBACKBUFFERRANGEPROC)(GLuint xfb, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size); GLAPI PFNGLTRANSFORMFEEDBACKBUFFERRANGEPROC glad_glTransformFeedbackBufferRange; #define glTransformFeedbackBufferRange glad_glTransformFeedbackBufferRange typedef void (APIENTRYP PFNGLGETTRANSFORMFEEDBACKIVPROC)(GLuint xfb, GLenum pname, GLint *param); GLAPI PFNGLGETTRANSFORMFEEDBACKIVPROC glad_glGetTransformFeedbackiv; #define glGetTransformFeedbackiv glad_glGetTransformFeedbackiv typedef void (APIENTRYP PFNGLGETTRANSFORMFEEDBACKI_VPROC)(GLuint xfb, GLenum pname, GLuint index, GLint *param); GLAPI PFNGLGETTRANSFORMFEEDBACKI_VPROC glad_glGetTransformFeedbacki_v; #define glGetTransformFeedbacki_v glad_glGetTransformFeedbacki_v typedef void (APIENTRYP PFNGLGETTRANSFORMFEEDBACKI64_VPROC)(GLuint xfb, GLenum pname, GLuint index, GLint64 *param); GLAPI PFNGLGETTRANSFORMFEEDBACKI64_VPROC glad_glGetTransformFeedbacki64_v; #define glGetTransformFeedbacki64_v glad_glGetTransformFeedbacki64_v typedef void (APIENTRYP PFNGLCREATEBUFFERSPROC)(GLsizei n, GLuint *buffers); GLAPI PFNGLCREATEBUFFERSPROC glad_glCreateBuffers; #define glCreateBuffers glad_glCreateBuffers typedef void (APIENTRYP PFNGLNAMEDBUFFERSTORAGEPROC)(GLuint buffer, GLsizeiptr size, const void *data, GLbitfield flags); GLAPI PFNGLNAMEDBUFFERSTORAGEPROC glad_glNamedBufferStorage; #define glNamedBufferStorage glad_glNamedBufferStorage typedef void (APIENTRYP PFNGLNAMEDBUFFERDATAPROC)(GLuint buffer, GLsizeiptr size, const void *data, GLenum usage); GLAPI PFNGLNAMEDBUFFERDATAPROC glad_glNamedBufferData; #define glNamedBufferData glad_glNamedBufferData typedef void (APIENTRYP PFNGLNAMEDBUFFERSUBDATAPROC)(GLuint buffer, GLintptr offset, GLsizeiptr size, const void *data); GLAPI PFNGLNAMEDBUFFERSUBDATAPROC glad_glNamedBufferSubData; #define glNamedBufferSubData glad_glNamedBufferSubData typedef void (APIENTRYP PFNGLCOPYNAMEDBUFFERSUBDATAPROC)(GLuint readBuffer, GLuint writeBuffer, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size); GLAPI PFNGLCOPYNAMEDBUFFERSUBDATAPROC glad_glCopyNamedBufferSubData; #define glCopyNamedBufferSubData glad_glCopyNamedBufferSubData typedef void (APIENTRYP PFNGLCLEARNAMEDBUFFERDATAPROC)(GLuint buffer, GLenum internalformat, GLenum format, GLenum type, const void *data); GLAPI PFNGLCLEARNAMEDBUFFERDATAPROC glad_glClearNamedBufferData; #define glClearNamedBufferData glad_glClearNamedBufferData typedef void (APIENTRYP PFNGLCLEARNAMEDBUFFERSUBDATAPROC)(GLuint buffer, GLenum internalformat, GLintptr offset, GLsizeiptr size, GLenum format, GLenum type, const void *data); GLAPI PFNGLCLEARNAMEDBUFFERSUBDATAPROC glad_glClearNamedBufferSubData; #define glClearNamedBufferSubData glad_glClearNamedBufferSubData typedef void * (APIENTRYP PFNGLMAPNAMEDBUFFERPROC)(GLuint buffer, GLenum access); GLAPI PFNGLMAPNAMEDBUFFERPROC glad_glMapNamedBuffer; #define glMapNamedBuffer glad_glMapNamedBuffer typedef void * (APIENTRYP PFNGLMAPNAMEDBUFFERRANGEPROC)(GLuint buffer, GLintptr offset, GLsizeiptr length, GLbitfield access); GLAPI PFNGLMAPNAMEDBUFFERRANGEPROC glad_glMapNamedBufferRange; #define glMapNamedBufferRange glad_glMapNamedBufferRange typedef GLboolean (APIENTRYP PFNGLUNMAPNAMEDBUFFERPROC)(GLuint buffer); GLAPI PFNGLUNMAPNAMEDBUFFERPROC glad_glUnmapNamedBuffer; #define glUnmapNamedBuffer glad_glUnmapNamedBuffer typedef void (APIENTRYP PFNGLFLUSHMAPPEDNAMEDBUFFERRANGEPROC)(GLuint buffer, GLintptr offset, GLsizeiptr length); GLAPI PFNGLFLUSHMAPPEDNAMEDBUFFERRANGEPROC glad_glFlushMappedNamedBufferRange; #define glFlushMappedNamedBufferRange glad_glFlushMappedNamedBufferRange typedef void (APIENTRYP PFNGLGETNAMEDBUFFERPARAMETERIVPROC)(GLuint buffer, GLenum pname, GLint *params); GLAPI PFNGLGETNAMEDBUFFERPARAMETERIVPROC glad_glGetNamedBufferParameteriv; #define glGetNamedBufferParameteriv glad_glGetNamedBufferParameteriv typedef void (APIENTRYP PFNGLGETNAMEDBUFFERPARAMETERI64VPROC)(GLuint buffer, GLenum pname, GLint64 *params); GLAPI PFNGLGETNAMEDBUFFERPARAMETERI64VPROC glad_glGetNamedBufferParameteri64v; #define glGetNamedBufferParameteri64v glad_glGetNamedBufferParameteri64v typedef void (APIENTRYP PFNGLGETNAMEDBUFFERPOINTERVPROC)(GLuint buffer, GLenum pname, void **params); GLAPI PFNGLGETNAMEDBUFFERPOINTERVPROC glad_glGetNamedBufferPointerv; #define glGetNamedBufferPointerv glad_glGetNamedBufferPointerv typedef void (APIENTRYP PFNGLGETNAMEDBUFFERSUBDATAPROC)(GLuint buffer, GLintptr offset, GLsizeiptr size, void *data); GLAPI PFNGLGETNAMEDBUFFERSUBDATAPROC glad_glGetNamedBufferSubData; #define glGetNamedBufferSubData glad_glGetNamedBufferSubData typedef void (APIENTRYP PFNGLCREATEFRAMEBUFFERSPROC)(GLsizei n, GLuint *framebuffers); GLAPI PFNGLCREATEFRAMEBUFFERSPROC glad_glCreateFramebuffers; #define glCreateFramebuffers glad_glCreateFramebuffers typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERRENDERBUFFERPROC)(GLuint framebuffer, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); GLAPI PFNGLNAMEDFRAMEBUFFERRENDERBUFFERPROC glad_glNamedFramebufferRenderbuffer; #define glNamedFramebufferRenderbuffer glad_glNamedFramebufferRenderbuffer typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERPARAMETERIPROC)(GLuint framebuffer, GLenum pname, GLint param); GLAPI PFNGLNAMEDFRAMEBUFFERPARAMETERIPROC glad_glNamedFramebufferParameteri; #define glNamedFramebufferParameteri glad_glNamedFramebufferParameteri typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERTEXTUREPROC)(GLuint framebuffer, GLenum attachment, GLuint texture, GLint level); GLAPI PFNGLNAMEDFRAMEBUFFERTEXTUREPROC glad_glNamedFramebufferTexture; #define glNamedFramebufferTexture glad_glNamedFramebufferTexture typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERTEXTURELAYERPROC)(GLuint framebuffer, GLenum attachment, GLuint texture, GLint level, GLint layer); GLAPI PFNGLNAMEDFRAMEBUFFERTEXTURELAYERPROC glad_glNamedFramebufferTextureLayer; #define glNamedFramebufferTextureLayer glad_glNamedFramebufferTextureLayer typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERDRAWBUFFERPROC)(GLuint framebuffer, GLenum buf); GLAPI PFNGLNAMEDFRAMEBUFFERDRAWBUFFERPROC glad_glNamedFramebufferDrawBuffer; #define glNamedFramebufferDrawBuffer glad_glNamedFramebufferDrawBuffer typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERDRAWBUFFERSPROC)(GLuint framebuffer, GLsizei n, const GLenum *bufs); GLAPI PFNGLNAMEDFRAMEBUFFERDRAWBUFFERSPROC glad_glNamedFramebufferDrawBuffers; #define glNamedFramebufferDrawBuffers glad_glNamedFramebufferDrawBuffers typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERREADBUFFERPROC)(GLuint framebuffer, GLenum src); GLAPI PFNGLNAMEDFRAMEBUFFERREADBUFFERPROC glad_glNamedFramebufferReadBuffer; #define glNamedFramebufferReadBuffer glad_glNamedFramebufferReadBuffer typedef void (APIENTRYP PFNGLINVALIDATENAMEDFRAMEBUFFERDATAPROC)(GLuint framebuffer, GLsizei numAttachments, const GLenum *attachments); GLAPI PFNGLINVALIDATENAMEDFRAMEBUFFERDATAPROC glad_glInvalidateNamedFramebufferData; #define glInvalidateNamedFramebufferData glad_glInvalidateNamedFramebufferData typedef void (APIENTRYP PFNGLINVALIDATENAMEDFRAMEBUFFERSUBDATAPROC)(GLuint framebuffer, GLsizei numAttachments, const GLenum *attachments, GLint x, GLint y, GLsizei width, GLsizei height); GLAPI PFNGLINVALIDATENAMEDFRAMEBUFFERSUBDATAPROC glad_glInvalidateNamedFramebufferSubData; #define glInvalidateNamedFramebufferSubData glad_glInvalidateNamedFramebufferSubData typedef void (APIENTRYP PFNGLCLEARNAMEDFRAMEBUFFERIVPROC)(GLuint framebuffer, GLenum buffer, GLint drawbuffer, const GLint *value); GLAPI PFNGLCLEARNAMEDFRAMEBUFFERIVPROC glad_glClearNamedFramebufferiv; #define glClearNamedFramebufferiv glad_glClearNamedFramebufferiv typedef void (APIENTRYP PFNGLCLEARNAMEDFRAMEBUFFERUIVPROC)(GLuint framebuffer, GLenum buffer, GLint drawbuffer, const GLuint *value); GLAPI PFNGLCLEARNAMEDFRAMEBUFFERUIVPROC glad_glClearNamedFramebufferuiv; #define glClearNamedFramebufferuiv glad_glClearNamedFramebufferuiv typedef void (APIENTRYP PFNGLCLEARNAMEDFRAMEBUFFERFVPROC)(GLuint framebuffer, GLenum buffer, GLint drawbuffer, const GLfloat *value); GLAPI PFNGLCLEARNAMEDFRAMEBUFFERFVPROC glad_glClearNamedFramebufferfv; #define glClearNamedFramebufferfv glad_glClearNamedFramebufferfv typedef void (APIENTRYP PFNGLCLEARNAMEDFRAMEBUFFERFIPROC)(GLuint framebuffer, GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil); GLAPI PFNGLCLEARNAMEDFRAMEBUFFERFIPROC glad_glClearNamedFramebufferfi; #define glClearNamedFramebufferfi glad_glClearNamedFramebufferfi typedef void (APIENTRYP PFNGLBLITNAMEDFRAMEBUFFERPROC)(GLuint readFramebuffer, GLuint drawFramebuffer, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); GLAPI PFNGLBLITNAMEDFRAMEBUFFERPROC glad_glBlitNamedFramebuffer; #define glBlitNamedFramebuffer glad_glBlitNamedFramebuffer typedef GLenum (APIENTRYP PFNGLCHECKNAMEDFRAMEBUFFERSTATUSPROC)(GLuint framebuffer, GLenum target); GLAPI PFNGLCHECKNAMEDFRAMEBUFFERSTATUSPROC glad_glCheckNamedFramebufferStatus; #define glCheckNamedFramebufferStatus glad_glCheckNamedFramebufferStatus typedef void (APIENTRYP PFNGLGETNAMEDFRAMEBUFFERPARAMETERIVPROC)(GLuint framebuffer, GLenum pname, GLint *param); GLAPI PFNGLGETNAMEDFRAMEBUFFERPARAMETERIVPROC glad_glGetNamedFramebufferParameteriv; #define glGetNamedFramebufferParameteriv glad_glGetNamedFramebufferParameteriv typedef void (APIENTRYP PFNGLGETNAMEDFRAMEBUFFERATTACHMENTPARAMETERIVPROC)(GLuint framebuffer, GLenum attachment, GLenum pname, GLint *params); GLAPI PFNGLGETNAMEDFRAMEBUFFERATTACHMENTPARAMETERIVPROC glad_glGetNamedFramebufferAttachmentParameteriv; #define glGetNamedFramebufferAttachmentParameteriv glad_glGetNamedFramebufferAttachmentParameteriv typedef void (APIENTRYP PFNGLCREATERENDERBUFFERSPROC)(GLsizei n, GLuint *renderbuffers); GLAPI PFNGLCREATERENDERBUFFERSPROC glad_glCreateRenderbuffers; #define glCreateRenderbuffers glad_glCreateRenderbuffers typedef void (APIENTRYP PFNGLNAMEDRENDERBUFFERSTORAGEPROC)(GLuint renderbuffer, GLenum internalformat, GLsizei width, GLsizei height); GLAPI PFNGLNAMEDRENDERBUFFERSTORAGEPROC glad_glNamedRenderbufferStorage; #define glNamedRenderbufferStorage glad_glNamedRenderbufferStorage typedef void (APIENTRYP PFNGLNAMEDRENDERBUFFERSTORAGEMULTISAMPLEPROC)(GLuint renderbuffer, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); GLAPI PFNGLNAMEDRENDERBUFFERSTORAGEMULTISAMPLEPROC glad_glNamedRenderbufferStorageMultisample; #define glNamedRenderbufferStorageMultisample glad_glNamedRenderbufferStorageMultisample typedef void (APIENTRYP PFNGLGETNAMEDRENDERBUFFERPARAMETERIVPROC)(GLuint renderbuffer, GLenum pname, GLint *params); GLAPI PFNGLGETNAMEDRENDERBUFFERPARAMETERIVPROC glad_glGetNamedRenderbufferParameteriv; #define glGetNamedRenderbufferParameteriv glad_glGetNamedRenderbufferParameteriv typedef void (APIENTRYP PFNGLCREATETEXTURESPROC)(GLenum target, GLsizei n, GLuint *textures); GLAPI PFNGLCREATETEXTURESPROC glad_glCreateTextures; #define glCreateTextures glad_glCreateTextures typedef void (APIENTRYP PFNGLTEXTUREBUFFERPROC)(GLuint texture, GLenum internalformat, GLuint buffer); GLAPI PFNGLTEXTUREBUFFERPROC glad_glTextureBuffer; #define glTextureBuffer glad_glTextureBuffer typedef void (APIENTRYP PFNGLTEXTUREBUFFERRANGEPROC)(GLuint texture, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size); GLAPI PFNGLTEXTUREBUFFERRANGEPROC glad_glTextureBufferRange; #define glTextureBufferRange glad_glTextureBufferRange typedef void (APIENTRYP PFNGLTEXTURESTORAGE1DPROC)(GLuint texture, GLsizei levels, GLenum internalformat, GLsizei width); GLAPI PFNGLTEXTURESTORAGE1DPROC glad_glTextureStorage1D; #define glTextureStorage1D glad_glTextureStorage1D typedef void (APIENTRYP PFNGLTEXTURESTORAGE2DPROC)(GLuint texture, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height); GLAPI PFNGLTEXTURESTORAGE2DPROC glad_glTextureStorage2D; #define glTextureStorage2D glad_glTextureStorage2D typedef void (APIENTRYP PFNGLTEXTURESTORAGE3DPROC)(GLuint texture, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth); GLAPI PFNGLTEXTURESTORAGE3DPROC glad_glTextureStorage3D; #define glTextureStorage3D glad_glTextureStorage3D typedef void (APIENTRYP PFNGLTEXTURESTORAGE2DMULTISAMPLEPROC)(GLuint texture, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations); GLAPI PFNGLTEXTURESTORAGE2DMULTISAMPLEPROC glad_glTextureStorage2DMultisample; #define glTextureStorage2DMultisample glad_glTextureStorage2DMultisample typedef void (APIENTRYP PFNGLTEXTURESTORAGE3DMULTISAMPLEPROC)(GLuint texture, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations); GLAPI PFNGLTEXTURESTORAGE3DMULTISAMPLEPROC glad_glTextureStorage3DMultisample; #define glTextureStorage3DMultisample glad_glTextureStorage3DMultisample typedef void (APIENTRYP PFNGLTEXTURESUBIMAGE1DPROC)(GLuint texture, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void *pixels); GLAPI PFNGLTEXTURESUBIMAGE1DPROC glad_glTextureSubImage1D; #define glTextureSubImage1D glad_glTextureSubImage1D typedef void (APIENTRYP PFNGLTEXTURESUBIMAGE2DPROC)(GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels); GLAPI PFNGLTEXTURESUBIMAGE2DPROC glad_glTextureSubImage2D; #define glTextureSubImage2D glad_glTextureSubImage2D typedef void (APIENTRYP PFNGLTEXTURESUBIMAGE3DPROC)(GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *pixels); GLAPI PFNGLTEXTURESUBIMAGE3DPROC glad_glTextureSubImage3D; #define glTextureSubImage3D glad_glTextureSubImage3D typedef void (APIENTRYP PFNGLCOMPRESSEDTEXTURESUBIMAGE1DPROC)(GLuint texture, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void *data); GLAPI PFNGLCOMPRESSEDTEXTURESUBIMAGE1DPROC glad_glCompressedTextureSubImage1D; #define glCompressedTextureSubImage1D glad_glCompressedTextureSubImage1D typedef void (APIENTRYP PFNGLCOMPRESSEDTEXTURESUBIMAGE2DPROC)(GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data); GLAPI PFNGLCOMPRESSEDTEXTURESUBIMAGE2DPROC glad_glCompressedTextureSubImage2D; #define glCompressedTextureSubImage2D glad_glCompressedTextureSubImage2D typedef void (APIENTRYP PFNGLCOMPRESSEDTEXTURESUBIMAGE3DPROC)(GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *data); GLAPI PFNGLCOMPRESSEDTEXTURESUBIMAGE3DPROC glad_glCompressedTextureSubImage3D; #define glCompressedTextureSubImage3D glad_glCompressedTextureSubImage3D typedef void (APIENTRYP PFNGLCOPYTEXTURESUBIMAGE1DPROC)(GLuint texture, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); GLAPI PFNGLCOPYTEXTURESUBIMAGE1DPROC glad_glCopyTextureSubImage1D; #define glCopyTextureSubImage1D glad_glCopyTextureSubImage1D typedef void (APIENTRYP PFNGLCOPYTEXTURESUBIMAGE2DPROC)(GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); GLAPI PFNGLCOPYTEXTURESUBIMAGE2DPROC glad_glCopyTextureSubImage2D; #define glCopyTextureSubImage2D glad_glCopyTextureSubImage2D typedef void (APIENTRYP PFNGLCOPYTEXTURESUBIMAGE3DPROC)(GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); GLAPI PFNGLCOPYTEXTURESUBIMAGE3DPROC glad_glCopyTextureSubImage3D; #define glCopyTextureSubImage3D glad_glCopyTextureSubImage3D typedef void (APIENTRYP PFNGLTEXTUREPARAMETERFPROC)(GLuint texture, GLenum pname, GLfloat param); GLAPI PFNGLTEXTUREPARAMETERFPROC glad_glTextureParameterf; #define glTextureParameterf glad_glTextureParameterf typedef void (APIENTRYP PFNGLTEXTUREPARAMETERFVPROC)(GLuint texture, GLenum pname, const GLfloat *param); GLAPI PFNGLTEXTUREPARAMETERFVPROC glad_glTextureParameterfv; #define glTextureParameterfv glad_glTextureParameterfv typedef void (APIENTRYP PFNGLTEXTUREPARAMETERIPROC)(GLuint texture, GLenum pname, GLint param); GLAPI PFNGLTEXTUREPARAMETERIPROC glad_glTextureParameteri; #define glTextureParameteri glad_glTextureParameteri typedef void (APIENTRYP PFNGLTEXTUREPARAMETERIIVPROC)(GLuint texture, GLenum pname, const GLint *params); GLAPI PFNGLTEXTUREPARAMETERIIVPROC glad_glTextureParameterIiv; #define glTextureParameterIiv glad_glTextureParameterIiv typedef void (APIENTRYP PFNGLTEXTUREPARAMETERIUIVPROC)(GLuint texture, GLenum pname, const GLuint *params); GLAPI PFNGLTEXTUREPARAMETERIUIVPROC glad_glTextureParameterIuiv; #define glTextureParameterIuiv glad_glTextureParameterIuiv typedef void (APIENTRYP PFNGLTEXTUREPARAMETERIVPROC)(GLuint texture, GLenum pname, const GLint *param); GLAPI PFNGLTEXTUREPARAMETERIVPROC glad_glTextureParameteriv; #define glTextureParameteriv glad_glTextureParameteriv typedef void (APIENTRYP PFNGLGENERATETEXTUREMIPMAPPROC)(GLuint texture); GLAPI PFNGLGENERATETEXTUREMIPMAPPROC glad_glGenerateTextureMipmap; #define glGenerateTextureMipmap glad_glGenerateTextureMipmap typedef void (APIENTRYP PFNGLBINDTEXTUREUNITPROC)(GLuint unit, GLuint texture); GLAPI PFNGLBINDTEXTUREUNITPROC glad_glBindTextureUnit; #define glBindTextureUnit glad_glBindTextureUnit typedef void (APIENTRYP PFNGLGETTEXTUREIMAGEPROC)(GLuint texture, GLint level, GLenum format, GLenum type, GLsizei bufSize, void *pixels); GLAPI PFNGLGETTEXTUREIMAGEPROC glad_glGetTextureImage; #define glGetTextureImage glad_glGetTextureImage typedef void (APIENTRYP PFNGLGETCOMPRESSEDTEXTUREIMAGEPROC)(GLuint texture, GLint level, GLsizei bufSize, void *pixels); GLAPI PFNGLGETCOMPRESSEDTEXTUREIMAGEPROC glad_glGetCompressedTextureImage; #define glGetCompressedTextureImage glad_glGetCompressedTextureImage typedef void (APIENTRYP PFNGLGETTEXTURELEVELPARAMETERFVPROC)(GLuint texture, GLint level, GLenum pname, GLfloat *params); GLAPI PFNGLGETTEXTURELEVELPARAMETERFVPROC glad_glGetTextureLevelParameterfv; #define glGetTextureLevelParameterfv glad_glGetTextureLevelParameterfv typedef void (APIENTRYP PFNGLGETTEXTURELEVELPARAMETERIVPROC)(GLuint texture, GLint level, GLenum pname, GLint *params); GLAPI PFNGLGETTEXTURELEVELPARAMETERIVPROC glad_glGetTextureLevelParameteriv; #define glGetTextureLevelParameteriv glad_glGetTextureLevelParameteriv typedef void (APIENTRYP PFNGLGETTEXTUREPARAMETERFVPROC)(GLuint texture, GLenum pname, GLfloat *params); GLAPI PFNGLGETTEXTUREPARAMETERFVPROC glad_glGetTextureParameterfv; #define glGetTextureParameterfv glad_glGetTextureParameterfv typedef void (APIENTRYP PFNGLGETTEXTUREPARAMETERIIVPROC)(GLuint texture, GLenum pname, GLint *params); GLAPI PFNGLGETTEXTUREPARAMETERIIVPROC glad_glGetTextureParameterIiv; #define glGetTextureParameterIiv glad_glGetTextureParameterIiv typedef void (APIENTRYP PFNGLGETTEXTUREPARAMETERIUIVPROC)(GLuint texture, GLenum pname, GLuint *params); GLAPI PFNGLGETTEXTUREPARAMETERIUIVPROC glad_glGetTextureParameterIuiv; #define glGetTextureParameterIuiv glad_glGetTextureParameterIuiv typedef void (APIENTRYP PFNGLGETTEXTUREPARAMETERIVPROC)(GLuint texture, GLenum pname, GLint *params); GLAPI PFNGLGETTEXTUREPARAMETERIVPROC glad_glGetTextureParameteriv; #define glGetTextureParameteriv glad_glGetTextureParameteriv typedef void (APIENTRYP PFNGLCREATEVERTEXARRAYSPROC)(GLsizei n, GLuint *arrays); GLAPI PFNGLCREATEVERTEXARRAYSPROC glad_glCreateVertexArrays; #define glCreateVertexArrays glad_glCreateVertexArrays typedef void (APIENTRYP PFNGLDISABLEVERTEXARRAYATTRIBPROC)(GLuint vaobj, GLuint index); GLAPI PFNGLDISABLEVERTEXARRAYATTRIBPROC glad_glDisableVertexArrayAttrib; #define glDisableVertexArrayAttrib glad_glDisableVertexArrayAttrib typedef void (APIENTRYP PFNGLENABLEVERTEXARRAYATTRIBPROC)(GLuint vaobj, GLuint index); GLAPI PFNGLENABLEVERTEXARRAYATTRIBPROC glad_glEnableVertexArrayAttrib; #define glEnableVertexArrayAttrib glad_glEnableVertexArrayAttrib typedef void (APIENTRYP PFNGLVERTEXARRAYELEMENTBUFFERPROC)(GLuint vaobj, GLuint buffer); GLAPI PFNGLVERTEXARRAYELEMENTBUFFERPROC glad_glVertexArrayElementBuffer; #define glVertexArrayElementBuffer glad_glVertexArrayElementBuffer typedef void (APIENTRYP PFNGLVERTEXARRAYVERTEXBUFFERPROC)(GLuint vaobj, GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride); GLAPI PFNGLVERTEXARRAYVERTEXBUFFERPROC glad_glVertexArrayVertexBuffer; #define glVertexArrayVertexBuffer glad_glVertexArrayVertexBuffer typedef void (APIENTRYP PFNGLVERTEXARRAYVERTEXBUFFERSPROC)(GLuint vaobj, GLuint first, GLsizei count, const GLuint *buffers, const GLintptr *offsets, const GLsizei *strides); GLAPI PFNGLVERTEXARRAYVERTEXBUFFERSPROC glad_glVertexArrayVertexBuffers; #define glVertexArrayVertexBuffers glad_glVertexArrayVertexBuffers typedef void (APIENTRYP PFNGLVERTEXARRAYATTRIBBINDINGPROC)(GLuint vaobj, GLuint attribindex, GLuint bindingindex); GLAPI PFNGLVERTEXARRAYATTRIBBINDINGPROC glad_glVertexArrayAttribBinding; #define glVertexArrayAttribBinding glad_glVertexArrayAttribBinding typedef void (APIENTRYP PFNGLVERTEXARRAYATTRIBFORMATPROC)(GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLboolean normalized, GLuint relativeoffset); GLAPI PFNGLVERTEXARRAYATTRIBFORMATPROC glad_glVertexArrayAttribFormat; #define glVertexArrayAttribFormat glad_glVertexArrayAttribFormat typedef void (APIENTRYP PFNGLVERTEXARRAYATTRIBIFORMATPROC)(GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset); GLAPI PFNGLVERTEXARRAYATTRIBIFORMATPROC glad_glVertexArrayAttribIFormat; #define glVertexArrayAttribIFormat glad_glVertexArrayAttribIFormat typedef void (APIENTRYP PFNGLVERTEXARRAYATTRIBLFORMATPROC)(GLuint vaobj, GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset); GLAPI PFNGLVERTEXARRAYATTRIBLFORMATPROC glad_glVertexArrayAttribLFormat; #define glVertexArrayAttribLFormat glad_glVertexArrayAttribLFormat typedef void (APIENTRYP PFNGLVERTEXARRAYBINDINGDIVISORPROC)(GLuint vaobj, GLuint bindingindex, GLuint divisor); GLAPI PFNGLVERTEXARRAYBINDINGDIVISORPROC glad_glVertexArrayBindingDivisor; #define glVertexArrayBindingDivisor glad_glVertexArrayBindingDivisor typedef void (APIENTRYP PFNGLGETVERTEXARRAYIVPROC)(GLuint vaobj, GLenum pname, GLint *param); GLAPI PFNGLGETVERTEXARRAYIVPROC glad_glGetVertexArrayiv; #define glGetVertexArrayiv glad_glGetVertexArrayiv typedef void (APIENTRYP PFNGLGETVERTEXARRAYINDEXEDIVPROC)(GLuint vaobj, GLuint index, GLenum pname, GLint *param); GLAPI PFNGLGETVERTEXARRAYINDEXEDIVPROC glad_glGetVertexArrayIndexediv; #define glGetVertexArrayIndexediv glad_glGetVertexArrayIndexediv typedef void (APIENTRYP PFNGLGETVERTEXARRAYINDEXED64IVPROC)(GLuint vaobj, GLuint index, GLenum pname, GLint64 *param); GLAPI PFNGLGETVERTEXARRAYINDEXED64IVPROC glad_glGetVertexArrayIndexed64iv; #define glGetVertexArrayIndexed64iv glad_glGetVertexArrayIndexed64iv typedef void (APIENTRYP PFNGLCREATESAMPLERSPROC)(GLsizei n, GLuint *samplers); GLAPI PFNGLCREATESAMPLERSPROC glad_glCreateSamplers; #define glCreateSamplers glad_glCreateSamplers typedef void (APIENTRYP PFNGLCREATEPROGRAMPIPELINESPROC)(GLsizei n, GLuint *pipelines); GLAPI PFNGLCREATEPROGRAMPIPELINESPROC glad_glCreateProgramPipelines; #define glCreateProgramPipelines glad_glCreateProgramPipelines typedef void (APIENTRYP PFNGLCREATEQUERIESPROC)(GLenum target, GLsizei n, GLuint *ids); GLAPI PFNGLCREATEQUERIESPROC glad_glCreateQueries; #define glCreateQueries glad_glCreateQueries typedef void (APIENTRYP PFNGLGETQUERYBUFFEROBJECTI64VPROC)(GLuint id, GLuint buffer, GLenum pname, GLintptr offset); GLAPI PFNGLGETQUERYBUFFEROBJECTI64VPROC glad_glGetQueryBufferObjecti64v; #define glGetQueryBufferObjecti64v glad_glGetQueryBufferObjecti64v typedef void (APIENTRYP PFNGLGETQUERYBUFFEROBJECTIVPROC)(GLuint id, GLuint buffer, GLenum pname, GLintptr offset); GLAPI PFNGLGETQUERYBUFFEROBJECTIVPROC glad_glGetQueryBufferObjectiv; #define glGetQueryBufferObjectiv glad_glGetQueryBufferObjectiv typedef void (APIENTRYP PFNGLGETQUERYBUFFEROBJECTUI64VPROC)(GLuint id, GLuint buffer, GLenum pname, GLintptr offset); GLAPI PFNGLGETQUERYBUFFEROBJECTUI64VPROC glad_glGetQueryBufferObjectui64v; #define glGetQueryBufferObjectui64v glad_glGetQueryBufferObjectui64v typedef void (APIENTRYP PFNGLGETQUERYBUFFEROBJECTUIVPROC)(GLuint id, GLuint buffer, GLenum pname, GLintptr offset); GLAPI PFNGLGETQUERYBUFFEROBJECTUIVPROC glad_glGetQueryBufferObjectuiv; #define glGetQueryBufferObjectuiv glad_glGetQueryBufferObjectuiv typedef void (APIENTRYP PFNGLMEMORYBARRIERBYREGIONPROC)(GLbitfield barriers); GLAPI PFNGLMEMORYBARRIERBYREGIONPROC glad_glMemoryBarrierByRegion; #define glMemoryBarrierByRegion glad_glMemoryBarrierByRegion typedef void (APIENTRYP PFNGLGETTEXTURESUBIMAGEPROC)(GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, GLsizei bufSize, void *pixels); GLAPI PFNGLGETTEXTURESUBIMAGEPROC glad_glGetTextureSubImage; #define glGetTextureSubImage glad_glGetTextureSubImage typedef void (APIENTRYP PFNGLGETCOMPRESSEDTEXTURESUBIMAGEPROC)(GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLsizei bufSize, void *pixels); GLAPI PFNGLGETCOMPRESSEDTEXTURESUBIMAGEPROC glad_glGetCompressedTextureSubImage; #define glGetCompressedTextureSubImage glad_glGetCompressedTextureSubImage typedef GLenum (APIENTRYP PFNGLGETGRAPHICSRESETSTATUSPROC)(void); GLAPI PFNGLGETGRAPHICSRESETSTATUSPROC glad_glGetGraphicsResetStatus; #define glGetGraphicsResetStatus glad_glGetGraphicsResetStatus typedef void (APIENTRYP PFNGLGETNCOMPRESSEDTEXIMAGEPROC)(GLenum target, GLint lod, GLsizei bufSize, void *pixels); GLAPI PFNGLGETNCOMPRESSEDTEXIMAGEPROC glad_glGetnCompressedTexImage; #define glGetnCompressedTexImage glad_glGetnCompressedTexImage typedef void (APIENTRYP PFNGLGETNTEXIMAGEPROC)(GLenum target, GLint level, GLenum format, GLenum type, GLsizei bufSize, void *pixels); GLAPI PFNGLGETNTEXIMAGEPROC glad_glGetnTexImage; #define glGetnTexImage glad_glGetnTexImage typedef void (APIENTRYP PFNGLGETNUNIFORMDVPROC)(GLuint program, GLint location, GLsizei bufSize, GLdouble *params); GLAPI PFNGLGETNUNIFORMDVPROC glad_glGetnUniformdv; #define glGetnUniformdv glad_glGetnUniformdv typedef void (APIENTRYP PFNGLGETNUNIFORMFVPROC)(GLuint program, GLint location, GLsizei bufSize, GLfloat *params); GLAPI PFNGLGETNUNIFORMFVPROC glad_glGetnUniformfv; #define glGetnUniformfv glad_glGetnUniformfv typedef void (APIENTRYP PFNGLGETNUNIFORMIVPROC)(GLuint program, GLint location, GLsizei bufSize, GLint *params); GLAPI PFNGLGETNUNIFORMIVPROC glad_glGetnUniformiv; #define glGetnUniformiv glad_glGetnUniformiv typedef void (APIENTRYP PFNGLGETNUNIFORMUIVPROC)(GLuint program, GLint location, GLsizei bufSize, GLuint *params); GLAPI PFNGLGETNUNIFORMUIVPROC glad_glGetnUniformuiv; #define glGetnUniformuiv glad_glGetnUniformuiv typedef void (APIENTRYP PFNGLREADNPIXELSPROC)(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data); GLAPI PFNGLREADNPIXELSPROC glad_glReadnPixels; #define glReadnPixels glad_glReadnPixels typedef void (APIENTRYP PFNGLGETNMAPDVPROC)(GLenum target, GLenum query, GLsizei bufSize, GLdouble *v); GLAPI PFNGLGETNMAPDVPROC glad_glGetnMapdv; #define glGetnMapdv glad_glGetnMapdv typedef void (APIENTRYP PFNGLGETNMAPFVPROC)(GLenum target, GLenum query, GLsizei bufSize, GLfloat *v); GLAPI PFNGLGETNMAPFVPROC glad_glGetnMapfv; #define glGetnMapfv glad_glGetnMapfv typedef void (APIENTRYP PFNGLGETNMAPIVPROC)(GLenum target, GLenum query, GLsizei bufSize, GLint *v); GLAPI PFNGLGETNMAPIVPROC glad_glGetnMapiv; #define glGetnMapiv glad_glGetnMapiv typedef void (APIENTRYP PFNGLGETNPIXELMAPFVPROC)(GLenum map, GLsizei bufSize, GLfloat *values); GLAPI PFNGLGETNPIXELMAPFVPROC glad_glGetnPixelMapfv; #define glGetnPixelMapfv glad_glGetnPixelMapfv typedef void (APIENTRYP PFNGLGETNPIXELMAPUIVPROC)(GLenum map, GLsizei bufSize, GLuint *values); GLAPI PFNGLGETNPIXELMAPUIVPROC glad_glGetnPixelMapuiv; #define glGetnPixelMapuiv glad_glGetnPixelMapuiv typedef void (APIENTRYP PFNGLGETNPIXELMAPUSVPROC)(GLenum map, GLsizei bufSize, GLushort *values); GLAPI PFNGLGETNPIXELMAPUSVPROC glad_glGetnPixelMapusv; #define glGetnPixelMapusv glad_glGetnPixelMapusv typedef void (APIENTRYP PFNGLGETNPOLYGONSTIPPLEPROC)(GLsizei bufSize, GLubyte *pattern); GLAPI PFNGLGETNPOLYGONSTIPPLEPROC glad_glGetnPolygonStipple; #define glGetnPolygonStipple glad_glGetnPolygonStipple typedef void (APIENTRYP PFNGLGETNCOLORTABLEPROC)(GLenum target, GLenum format, GLenum type, GLsizei bufSize, void *table); GLAPI PFNGLGETNCOLORTABLEPROC glad_glGetnColorTable; #define glGetnColorTable glad_glGetnColorTable typedef void (APIENTRYP PFNGLGETNCONVOLUTIONFILTERPROC)(GLenum target, GLenum format, GLenum type, GLsizei bufSize, void *image); GLAPI PFNGLGETNCONVOLUTIONFILTERPROC glad_glGetnConvolutionFilter; #define glGetnConvolutionFilter glad_glGetnConvolutionFilter typedef void (APIENTRYP PFNGLGETNSEPARABLEFILTERPROC)(GLenum target, GLenum format, GLenum type, GLsizei rowBufSize, void *row, GLsizei columnBufSize, void *column, void *span); GLAPI PFNGLGETNSEPARABLEFILTERPROC glad_glGetnSeparableFilter; #define glGetnSeparableFilter glad_glGetnSeparableFilter typedef void (APIENTRYP PFNGLGETNHISTOGRAMPROC)(GLenum target, GLboolean reset, GLenum format, GLenum type, GLsizei bufSize, void *values); GLAPI PFNGLGETNHISTOGRAMPROC glad_glGetnHistogram; #define glGetnHistogram glad_glGetnHistogram typedef void (APIENTRYP PFNGLGETNMINMAXPROC)(GLenum target, GLboolean reset, GLenum format, GLenum type, GLsizei bufSize, void *values); GLAPI PFNGLGETNMINMAXPROC glad_glGetnMinmax; #define glGetnMinmax glad_glGetnMinmax typedef void (APIENTRYP PFNGLTEXTUREBARRIERPROC)(void); GLAPI PFNGLTEXTUREBARRIERPROC glad_glTextureBarrier; #define glTextureBarrier glad_glTextureBarrier #endif #ifndef GL_VERSION_4_6 #define GL_VERSION_4_6 1 GLAPI int GLAD_GL_VERSION_4_6; typedef void (APIENTRYP PFNGLSPECIALIZESHADERPROC)(GLuint shader, const GLchar *pEntryPoint, GLuint numSpecializationConstants, const GLuint *pConstantIndex, const GLuint *pConstantValue); GLAPI PFNGLSPECIALIZESHADERPROC glad_glSpecializeShader; #define glSpecializeShader glad_glSpecializeShader typedef void (APIENTRYP PFNGLMULTIDRAWARRAYSINDIRECTCOUNTPROC)(GLenum mode, const void *indirect, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride); GLAPI PFNGLMULTIDRAWARRAYSINDIRECTCOUNTPROC glad_glMultiDrawArraysIndirectCount; #define glMultiDrawArraysIndirectCount glad_glMultiDrawArraysIndirectCount typedef void (APIENTRYP PFNGLMULTIDRAWELEMENTSINDIRECTCOUNTPROC)(GLenum mode, GLenum type, const void *indirect, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride); GLAPI PFNGLMULTIDRAWELEMENTSINDIRECTCOUNTPROC glad_glMultiDrawElementsIndirectCount; #define glMultiDrawElementsIndirectCount glad_glMultiDrawElementsIndirectCount typedef void (APIENTRYP PFNGLPOLYGONOFFSETCLAMPPROC)(GLfloat factor, GLfloat units, GLfloat clamp); GLAPI PFNGLPOLYGONOFFSETCLAMPPROC glad_glPolygonOffsetClamp; #define glPolygonOffsetClamp glad_glPolygonOffsetClamp #endif #ifndef GL_ES_VERSION_2_0 #define GL_ES_VERSION_2_0 1 GLAPI int GLAD_GL_ES_VERSION_2_0; #endif #ifndef GL_ES_VERSION_3_0 #define GL_ES_VERSION_3_0 1 GLAPI int GLAD_GL_ES_VERSION_3_0; #endif #ifndef GL_ES_VERSION_3_1 #define GL_ES_VERSION_3_1 1 GLAPI int GLAD_GL_ES_VERSION_3_1; #endif #ifndef GL_ES_VERSION_3_2 #define GL_ES_VERSION_3_2 1 GLAPI int GLAD_GL_ES_VERSION_3_2; typedef void (APIENTRYP PFNGLBLENDBARRIERPROC)(void); GLAPI PFNGLBLENDBARRIERPROC glad_glBlendBarrier; #define glBlendBarrier glad_glBlendBarrier typedef void (APIENTRYP PFNGLPRIMITIVEBOUNDINGBOXPROC)(GLfloat minX, GLfloat minY, GLfloat minZ, GLfloat minW, GLfloat maxX, GLfloat maxY, GLfloat maxZ, GLfloat maxW); GLAPI PFNGLPRIMITIVEBOUNDINGBOXPROC glad_glPrimitiveBoundingBox; #define glPrimitiveBoundingBox glad_glPrimitiveBoundingBox #endif #define GL_LOWER_LEFT_EXT 0x8CA1 #define GL_UPPER_LEFT_EXT 0x8CA2 #define GL_NEGATIVE_ONE_TO_ONE_EXT 0x935E #define GL_ZERO_TO_ONE_EXT 0x935F #define GL_CLIP_ORIGIN_EXT 0x935C #define GL_CLIP_DEPTH_MODE_EXT 0x935D #ifndef GL_ARB_clip_control #define GL_ARB_clip_control 1 GLAPI int GLAD_GL_ARB_clip_control; #endif #ifndef GL_EXT_clip_control #define GL_EXT_clip_control 1 GLAPI int GLAD_GL_EXT_clip_control; typedef void (APIENTRYP PFNGLCLIPCONTROLEXTPROC)(GLenum origin, GLenum depth); GLAPI PFNGLCLIPCONTROLEXTPROC glad_glClipControlEXT; #define glClipControlEXT glad_glClipControlEXT #endif #ifdef __cplusplus } #endif #endif ================================================ FILE: include/nvml.h ================================================ /* * Copyright 1993-2019 NVIDIA Corporation. All rights reserved. * * NOTICE TO USER: * * This source code is subject to NVIDIA ownership rights under U.S. and * international Copyright laws. Users and possessors of this source code * are hereby granted a nonexclusive, royalty-free license to use this code * in individual and commercial software. * * NVIDIA MAKES NO REPRESENTATION ABOUT THE SUITABILITY OF THIS SOURCE * CODE FOR ANY PURPOSE. IT IS PROVIDED "AS IS" WITHOUT EXPRESS OR * IMPLIED WARRANTY OF ANY KIND. NVIDIA DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOURCE CODE, INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE. * IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL, * OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE * OR PERFORMANCE OF THIS SOURCE CODE. * * U.S. Government End Users. This source code is a "commercial item" as * that term is defined at 48 C.F.R. 2.101 (OCT 1995), consisting of * "commercial computer software" and "commercial computer software * documentation" as such terms are used in 48 C.F.R. 12.212 (SEPT 1995) * and is provided to the U.S. Government only as a commercial end item. * Consistent with 48 C.F.R.12.212 and 48 C.F.R. 227.7202-1 through * 227.7202-4 (JUNE 1995), all U.S. Government End Users acquire the * source code with only those rights set forth herein. * * Any use of this source code in individual and commercial software must * include, in the user documentation and internal comments to the code, * the above Disclaimer and U.S. Government End Users Notice. */ /* NVML API Reference The NVIDIA Management Library (NVML) is a C-based programmatic interface for monitoring and managing various states within NVIDIA Tesla &tm; GPUs. It is intended to be a platform for building 3rd party applications, and is also the underlying library for the NVIDIA-supported nvidia-smi tool. NVML is thread-safe so it is safe to make simultaneous NVML calls from multiple threads. API Documentation Supported platforms: - Windows: Windows Server 2008 R2 64bit, Windows Server 2012 R2 64bit, Windows 7 64bit, Windows 8 64bit, Windows 10 64bit - Linux: 32-bit and 64-bit - Hypervisors: Windows Server 2008R2/2012 Hyper-V 64bit, Citrix XenServer 6.2 SP1+, VMware ESX 5.1/5.5 Supported products: - Full Support - All Tesla products, starting with the Fermi architecture - All Quadro products, starting with the Fermi architecture - All GRID products, starting with the Kepler architecture - Selected GeForce Titan products - Limited Support - All Geforce products, starting with the Fermi architecture The NVML library can be found at \%ProgramW6432\%\\"NVIDIA Corporation"\\NVSMI\\ on Windows. It is not be added to the system path by default. To dynamically link to NVML, add this path to the PATH environmental variable. To dynamically load NVML, call LoadLibrary with this path. On Linux the NVML library will be found on the standard library path. For 64 bit Linux, both the 32 bit and 64 bit NVML libraries will be installed. Online documentation for this library is available at http://docs.nvidia.com/deploy/nvml-api/index.html */ #ifndef __nvml_nvml_h__ #define __nvml_nvml_h__ #ifdef __cplusplus extern "C" { #endif /* * On Windows, set up methods for DLL export * define NVML_STATIC_IMPORT when using nvml_loader library */ #if defined _WINDOWS #if !defined NVML_STATIC_IMPORT #if defined NVML_LIB_EXPORT #define DECLDIR __declspec(dllexport) #else #define DECLDIR __declspec(dllimport) #endif #else #define DECLDIR #endif #else #define DECLDIR #endif /** * NVML API versioning support */ #define NVML_API_VERSION 10 #define NVML_API_VERSION_STR "10" #define nvmlInit nvmlInit_v2 #define nvmlDeviceGetPciInfo nvmlDeviceGetPciInfo_v3 #define nvmlDeviceGetCount nvmlDeviceGetCount_v2 #define nvmlDeviceGetHandleByIndex nvmlDeviceGetHandleByIndex_v2 #define nvmlDeviceGetHandleByPciBusId nvmlDeviceGetHandleByPciBusId_v2 #define nvmlDeviceGetNvLinkRemotePciInfo nvmlDeviceGetNvLinkRemotePciInfo_v2 #define nvmlDeviceRemoveGpu nvmlDeviceRemoveGpu_v2 #define nvmlDeviceGetGridLicensableFeatures nvmlDeviceGetGridLicensableFeatures_v3 /***************************************************************************************************/ /** @defgroup nvmlDeviceStructs Device Structs * @{ */ /***************************************************************************************************/ /** * Special constant that some fields take when they are not available. * Used when only part of the struct is not available. * * Each structure explicitly states when to check for this value. */ #define NVML_VALUE_NOT_AVAILABLE (-1) typedef struct nvmlDevice_st* nvmlDevice_t; /** * Buffer size guaranteed to be large enough for pci bus id */ #define NVML_DEVICE_PCI_BUS_ID_BUFFER_SIZE 32 /** * Buffer size guaranteed to be large enough for pci bus id for ::busIdLegacy */ #define NVML_DEVICE_PCI_BUS_ID_BUFFER_V2_SIZE 16 /** * PCI information about a GPU device. */ typedef struct nvmlPciInfo_st { char busIdLegacy[NVML_DEVICE_PCI_BUS_ID_BUFFER_V2_SIZE]; //!< The legacy tuple domain:bus:device.function PCI identifier (& NULL terminator) unsigned int domain; //!< The PCI domain on which the device's bus resides, 0 to 0xffffffff unsigned int bus; //!< The bus on which the device resides, 0 to 0xff unsigned int device; //!< The device's id on the bus, 0 to 31 unsigned int pciDeviceId; //!< The combined 16-bit device id and 16-bit vendor id // Added in NVML 2.285 API unsigned int pciSubSystemId; //!< The 32-bit Sub System Device ID char busId[NVML_DEVICE_PCI_BUS_ID_BUFFER_SIZE]; //!< The tuple domain:bus:device.function PCI identifier (& NULL terminator) } nvmlPciInfo_t; /** * PCI format string for ::busIdLegacy */ #define NVML_DEVICE_PCI_BUS_ID_LEGACY_FMT "%04X:%02X:%02X.0" /** * PCI format string for ::busId */ #define NVML_DEVICE_PCI_BUS_ID_FMT "%08X:%02X:%02X.0" /** * Utility macro for filling the pci bus id format from a nvmlPciInfo_t */ #define NVML_DEVICE_PCI_BUS_ID_FMT_ARGS(pciInfo) (pciInfo)->domain, \ (pciInfo)->bus, \ (pciInfo)->device /** * Detailed ECC error counts for a device. * * @deprecated Different GPU families can have different memory error counters * See \ref nvmlDeviceGetMemoryErrorCounter */ typedef struct nvmlEccErrorCounts_st { unsigned long long l1Cache; //!< L1 cache errors unsigned long long l2Cache; //!< L2 cache errors unsigned long long deviceMemory; //!< Device memory errors unsigned long long registerFile; //!< Register file errors } nvmlEccErrorCounts_t; /** * Utilization information for a device. * Each sample period may be between 1 second and 1/6 second, depending on the product being queried. */ typedef struct nvmlUtilization_st { unsigned int gpu; //!< Percent of time over the past sample period during which one or more kernels was executing on the GPU unsigned int memory; //!< Percent of time over the past sample period during which global (device) memory was being read or written } nvmlUtilization_t; /** * Memory allocation information for a device. */ typedef struct nvmlMemory_st { unsigned long long total; //!< Total installed FB memory (in bytes) unsigned long long free; //!< Unallocated FB memory (in bytes) unsigned long long used; //!< Allocated FB memory (in bytes). Note that the driver/GPU always sets aside a small amount of memory for bookkeeping } nvmlMemory_t; /** * BAR1 Memory allocation Information for a device */ typedef struct nvmlBAR1Memory_st { unsigned long long bar1Total; //!< Total BAR1 Memory (in bytes) unsigned long long bar1Free; //!< Unallocated BAR1 Memory (in bytes) unsigned long long bar1Used; //!< Allocated Used Memory (in bytes) }nvmlBAR1Memory_t; /** * Information about running compute processes on the GPU */ typedef struct nvmlProcessInfo_st { unsigned int pid; //!< Process ID unsigned long long usedGpuMemory; //!< Amount of used GPU memory in bytes. //! Under WDDM, \ref NVML_VALUE_NOT_AVAILABLE is always reported //! because Windows KMD manages all the memory and not the NVIDIA driver } nvmlProcessInfo_t; /** * Enum to represent type of bridge chip */ typedef enum nvmlBridgeChipType_enum { NVML_BRIDGE_CHIP_PLX = 0, NVML_BRIDGE_CHIP_BRO4 = 1 }nvmlBridgeChipType_t; /** * Maximum number of NvLink links supported */ #define NVML_NVLINK_MAX_LINKS 6 /** * Enum to represent the NvLink utilization counter packet units */ typedef enum nvmlNvLinkUtilizationCountUnits_enum { NVML_NVLINK_COUNTER_UNIT_CYCLES = 0, // count by cycles NVML_NVLINK_COUNTER_UNIT_PACKETS = 1, // count by packets NVML_NVLINK_COUNTER_UNIT_BYTES = 2, // count by bytes NVML_NVLINK_COUNTER_UNIT_RESERVED = 3, // count reserved for internal use // this must be last NVML_NVLINK_COUNTER_UNIT_COUNT } nvmlNvLinkUtilizationCountUnits_t; /** * Enum to represent the NvLink utilization counter packet types to count * ** this is ONLY applicable with the units as packets or bytes * ** as specified in \a nvmlNvLinkUtilizationCountUnits_t * ** all packet filter descriptions are target GPU centric * ** these can be "OR'd" together */ typedef enum nvmlNvLinkUtilizationCountPktTypes_enum { NVML_NVLINK_COUNTER_PKTFILTER_NOP = 0x1, // no operation packets NVML_NVLINK_COUNTER_PKTFILTER_READ = 0x2, // read packets NVML_NVLINK_COUNTER_PKTFILTER_WRITE = 0x4, // write packets NVML_NVLINK_COUNTER_PKTFILTER_RATOM = 0x8, // reduction atomic requests NVML_NVLINK_COUNTER_PKTFILTER_NRATOM = 0x10, // non-reduction atomic requests NVML_NVLINK_COUNTER_PKTFILTER_FLUSH = 0x20, // flush requests NVML_NVLINK_COUNTER_PKTFILTER_RESPDATA = 0x40, // responses with data NVML_NVLINK_COUNTER_PKTFILTER_RESPNODATA = 0x80, // responses without data NVML_NVLINK_COUNTER_PKTFILTER_ALL = 0xFF // all packets } nvmlNvLinkUtilizationCountPktTypes_t; /** * Struct to define the NVLINK counter controls */ typedef struct nvmlNvLinkUtilizationControl_st { nvmlNvLinkUtilizationCountUnits_t units; nvmlNvLinkUtilizationCountPktTypes_t pktfilter; } nvmlNvLinkUtilizationControl_t; /** * Enum to represent NvLink queryable capabilities */ typedef enum nvmlNvLinkCapability_enum { NVML_NVLINK_CAP_P2P_SUPPORTED = 0, // P2P over NVLink is supported NVML_NVLINK_CAP_SYSMEM_ACCESS = 1, // Access to system memory is supported NVML_NVLINK_CAP_P2P_ATOMICS = 2, // P2P atomics are supported NVML_NVLINK_CAP_SYSMEM_ATOMICS= 3, // System memory atomics are supported NVML_NVLINK_CAP_SLI_BRIDGE = 4, // SLI is supported over this link NVML_NVLINK_CAP_VALID = 5, // Link is supported on this device // should be last NVML_NVLINK_CAP_COUNT } nvmlNvLinkCapability_t; /** * Enum to represent NvLink queryable error counters */ typedef enum nvmlNvLinkErrorCounter_enum { NVML_NVLINK_ERROR_DL_REPLAY = 0, // Data link transmit replay error counter NVML_NVLINK_ERROR_DL_RECOVERY = 1, // Data link transmit recovery error counter NVML_NVLINK_ERROR_DL_CRC_FLIT = 2, // Data link receive flow control digit CRC error counter NVML_NVLINK_ERROR_DL_CRC_DATA = 3, // Data link receive data CRC error counter // this must be last NVML_NVLINK_ERROR_COUNT } nvmlNvLinkErrorCounter_t; /** * Represents level relationships within a system between two GPUs * The enums are spaced to allow for future relationships */ typedef enum nvmlGpuLevel_enum { NVML_TOPOLOGY_INTERNAL = 0, // e.g. Tesla K80 NVML_TOPOLOGY_SINGLE = 10, // all devices that only need traverse a single PCIe switch NVML_TOPOLOGY_MULTIPLE = 20, // all devices that need not traverse a host bridge NVML_TOPOLOGY_HOSTBRIDGE = 30, // all devices that are connected to the same host bridge NVML_TOPOLOGY_NODE = 40, // all devices that are connected to the same NUMA node but possibly multiple host bridges NVML_TOPOLOGY_SYSTEM = 50, // all devices in the system // there is purposefully no COUNT here because of the need for spacing above } nvmlGpuTopologyLevel_t; /* Compatibility for CPU->NODE renaming */ #define NVML_TOPOLOGY_CPU NVML_TOPOLOGY_NODE /* P2P Capability Index Status*/ typedef enum nvmlGpuP2PStatus_enum { NVML_P2P_STATUS_OK = 0, NVML_P2P_STATUS_CHIPSET_NOT_SUPPORED, NVML_P2P_STATUS_GPU_NOT_SUPPORTED, NVML_P2P_STATUS_IOH_TOPOLOGY_NOT_SUPPORTED, NVML_P2P_STATUS_DISABLED_BY_REGKEY, NVML_P2P_STATUS_NOT_SUPPORTED, NVML_P2P_STATUS_UNKNOWN } nvmlGpuP2PStatus_t; /* P2P Capability Index*/ typedef enum nvmlGpuP2PCapsIndex_enum { NVML_P2P_CAPS_INDEX_READ = 0, NVML_P2P_CAPS_INDEX_WRITE, NVML_P2P_CAPS_INDEX_NVLINK, NVML_P2P_CAPS_INDEX_ATOMICS, NVML_P2P_CAPS_INDEX_PROP, NVML_P2P_CAPS_INDEX_UNKNOWN }nvmlGpuP2PCapsIndex_t; /** * Maximum limit on Physical Bridges per Board */ #define NVML_MAX_PHYSICAL_BRIDGE (128) /** * Information about the Bridge Chip Firmware */ typedef struct nvmlBridgeChipInfo_st { nvmlBridgeChipType_t type; //!< Type of Bridge Chip unsigned int fwVersion; //!< Firmware Version. 0=Version is unavailable }nvmlBridgeChipInfo_t; /** * This structure stores the complete Hierarchy of the Bridge Chip within the board. The immediate * bridge is stored at index 0 of bridgeInfoList, parent to immediate bridge is at index 1 and so forth. */ typedef struct nvmlBridgeChipHierarchy_st { unsigned char bridgeCount; //!< Number of Bridge Chips on the Board nvmlBridgeChipInfo_t bridgeChipInfo[NVML_MAX_PHYSICAL_BRIDGE]; //!< Hierarchy of Bridge Chips on the board }nvmlBridgeChipHierarchy_t; /** * Represents Type of Sampling Event */ typedef enum nvmlSamplingType_enum { NVML_TOTAL_POWER_SAMPLES = 0, //!< To represent total power drawn by GPU NVML_GPU_UTILIZATION_SAMPLES = 1, //!< To represent percent of time during which one or more kernels was executing on the GPU NVML_MEMORY_UTILIZATION_SAMPLES = 2, //!< To represent percent of time during which global (device) memory was being read or written NVML_ENC_UTILIZATION_SAMPLES = 3, //!< To represent percent of time during which NVENC remains busy NVML_DEC_UTILIZATION_SAMPLES = 4, //!< To represent percent of time during which NVDEC remains busy NVML_PROCESSOR_CLK_SAMPLES = 5, //!< To represent processor clock samples NVML_MEMORY_CLK_SAMPLES = 6, //!< To represent memory clock samples // Keep this last NVML_SAMPLINGTYPE_COUNT }nvmlSamplingType_t; /** * Represents the queryable PCIe utilization counters */ typedef enum nvmlPcieUtilCounter_enum { NVML_PCIE_UTIL_TX_BYTES = 0, // 1KB granularity NVML_PCIE_UTIL_RX_BYTES = 1, // 1KB granularity // Keep this last NVML_PCIE_UTIL_COUNT } nvmlPcieUtilCounter_t; /** * Represents the type for sample value returned */ typedef enum nvmlValueType_enum { NVML_VALUE_TYPE_DOUBLE = 0, NVML_VALUE_TYPE_UNSIGNED_INT = 1, NVML_VALUE_TYPE_UNSIGNED_LONG = 2, NVML_VALUE_TYPE_UNSIGNED_LONG_LONG = 3, NVML_VALUE_TYPE_SIGNED_LONG_LONG = 4, // Keep this last NVML_VALUE_TYPE_COUNT }nvmlValueType_t; /** * Union to represent different types of Value */ typedef union nvmlValue_st { double dVal; //!< If the value is double unsigned int uiVal; //!< If the value is unsigned int unsigned long ulVal; //!< If the value is unsigned long unsigned long long ullVal; //!< If the value is unsigned long long signed long long sllVal; //!< If the value is signed long long }nvmlValue_t; /** * Information for Sample */ typedef struct nvmlSample_st { unsigned long long timeStamp; //!< CPU Timestamp in microseconds nvmlValue_t sampleValue; //!< Sample Value }nvmlSample_t; /** * Represents type of perf policy for which violation times can be queried */ typedef enum nvmlPerfPolicyType_enum { NVML_PERF_POLICY_POWER = 0, //!< How long did power violations cause the GPU to be below application clocks NVML_PERF_POLICY_THERMAL = 1, //!< How long did thermal violations cause the GPU to be below application clocks NVML_PERF_POLICY_SYNC_BOOST = 2, //!< How long did sync boost cause the GPU to be below application clocks NVML_PERF_POLICY_BOARD_LIMIT = 3, //!< How long did the board limit cause the GPU to be below application clocks NVML_PERF_POLICY_LOW_UTILIZATION = 4, //!< How long did low utilization cause the GPU to be below application clocks NVML_PERF_POLICY_RELIABILITY = 5, //!< How long did the board reliability limit cause the GPU to be below application clocks NVML_PERF_POLICY_TOTAL_APP_CLOCKS = 10, //!< Total time the GPU was held below application clocks by any limiter (0 - 5 above) NVML_PERF_POLICY_TOTAL_BASE_CLOCKS = 11, //!< Total time the GPU was held below base clocks // Keep this last NVML_PERF_POLICY_COUNT }nvmlPerfPolicyType_t; /** * Struct to hold perf policy violation status data */ typedef struct nvmlViolationTime_st { unsigned long long referenceTime; //!< referenceTime represents CPU timestamp in microseconds unsigned long long violationTime; //!< violationTime in Nanoseconds }nvmlViolationTime_t; /** @} */ /***************************************************************************************************/ /** @defgroup nvmlDeviceEnumvs Device Enums * @{ */ /***************************************************************************************************/ /** * Generic enable/disable enum. */ typedef enum nvmlEnableState_enum { NVML_FEATURE_DISABLED = 0, //!< Feature disabled NVML_FEATURE_ENABLED = 1 //!< Feature enabled } nvmlEnableState_t; //! Generic flag used to specify the default behavior of some functions. See description of particular functions for details. #define nvmlFlagDefault 0x00 //! Generic flag used to force some behavior. See description of particular functions for details. #define nvmlFlagForce 0x01 /** * * The Brand of the GPU * */ typedef enum nvmlBrandType_enum { NVML_BRAND_UNKNOWN = 0, NVML_BRAND_QUADRO = 1, NVML_BRAND_TESLA = 2, NVML_BRAND_NVS = 3, NVML_BRAND_GRID = 4, NVML_BRAND_GEFORCE = 5, NVML_BRAND_TITAN = 6, // Keep this last NVML_BRAND_COUNT } nvmlBrandType_t; /** * Temperature thresholds. */ typedef enum nvmlTemperatureThresholds_enum { NVML_TEMPERATURE_THRESHOLD_SHUTDOWN = 0, // Temperature at which the GPU will shut down // for HW protection NVML_TEMPERATURE_THRESHOLD_SLOWDOWN = 1, // Temperature at which the GPU will begin HW slowdown NVML_TEMPERATURE_THRESHOLD_MEM_MAX = 2, // Memory Temperature at which the GPU will begin SW slowdown NVML_TEMPERATURE_THRESHOLD_GPU_MAX = 3, // GPU Temperature at which the GPU can be throttled below base clock // Keep this last NVML_TEMPERATURE_THRESHOLD_COUNT } nvmlTemperatureThresholds_t; /** * Temperature sensors. */ typedef enum nvmlTemperatureSensors_enum { NVML_TEMPERATURE_GPU = 0, //!< Temperature sensor for the GPU die // Keep this last NVML_TEMPERATURE_COUNT } nvmlTemperatureSensors_t; /** * Compute mode. * * NVML_COMPUTEMODE_EXCLUSIVE_PROCESS was added in CUDA 4.0. * Earlier CUDA versions supported a single exclusive mode, * which is equivalent to NVML_COMPUTEMODE_EXCLUSIVE_THREAD in CUDA 4.0 and beyond. */ typedef enum nvmlComputeMode_enum { NVML_COMPUTEMODE_DEFAULT = 0, //!< Default compute mode -- multiple contexts per device NVML_COMPUTEMODE_EXCLUSIVE_THREAD = 1, //!< Support Removed NVML_COMPUTEMODE_PROHIBITED = 2, //!< Compute-prohibited mode -- no contexts per device NVML_COMPUTEMODE_EXCLUSIVE_PROCESS = 3, //!< Compute-exclusive-process mode -- only one context per device, usable from multiple threads at a time // Keep this last NVML_COMPUTEMODE_COUNT } nvmlComputeMode_t; /** * ECC bit types. * * @deprecated See \ref nvmlMemoryErrorType_t for a more flexible type */ #define nvmlEccBitType_t nvmlMemoryErrorType_t /** * Single bit ECC errors * * @deprecated Mapped to \ref NVML_MEMORY_ERROR_TYPE_CORRECTED */ #define NVML_SINGLE_BIT_ECC NVML_MEMORY_ERROR_TYPE_CORRECTED /** * Double bit ECC errors * * @deprecated Mapped to \ref NVML_MEMORY_ERROR_TYPE_UNCORRECTED */ #define NVML_DOUBLE_BIT_ECC NVML_MEMORY_ERROR_TYPE_UNCORRECTED /** * Memory error types */ typedef enum nvmlMemoryErrorType_enum { /** * A memory error that was corrected * * For ECC errors, these are single bit errors * For Texture memory, these are errors fixed by resend */ NVML_MEMORY_ERROR_TYPE_CORRECTED = 0, /** * A memory error that was not corrected * * For ECC errors, these are double bit errors * For Texture memory, these are errors where the resend fails */ NVML_MEMORY_ERROR_TYPE_UNCORRECTED = 1, // Keep this last NVML_MEMORY_ERROR_TYPE_COUNT //!< Count of memory error types } nvmlMemoryErrorType_t; /** * ECC counter types. * * Note: Volatile counts are reset each time the driver loads. On Windows this is once per boot. On Linux this can be more frequent. * On Linux the driver unloads when no active clients exist. If persistence mode is enabled or there is always a driver * client active (e.g. X11), then Linux also sees per-boot behavior. If not, volatile counts are reset each time a compute app * is run. */ typedef enum nvmlEccCounterType_enum { NVML_VOLATILE_ECC = 0, //!< Volatile counts are reset each time the driver loads. NVML_AGGREGATE_ECC = 1, //!< Aggregate counts persist across reboots (i.e. for the lifetime of the device) // Keep this last NVML_ECC_COUNTER_TYPE_COUNT //!< Count of memory counter types } nvmlEccCounterType_t; /** * Clock types. * * All speeds are in Mhz. */ typedef enum nvmlClockType_enum { NVML_CLOCK_GRAPHICS = 0, //!< Graphics clock domain NVML_CLOCK_SM = 1, //!< SM clock domain NVML_CLOCK_MEM = 2, //!< Memory clock domain NVML_CLOCK_VIDEO = 3, //!< Video encoder/decoder clock domain // Keep this last NVML_CLOCK_COUNT //!< Count of clock types } nvmlClockType_t; /** * Clock Ids. These are used in combination with nvmlClockType_t * to specify a single clock value. */ typedef enum nvmlClockId_enum { NVML_CLOCK_ID_CURRENT = 0, //!< Current actual clock value NVML_CLOCK_ID_APP_CLOCK_TARGET = 1, //!< Target application clock NVML_CLOCK_ID_APP_CLOCK_DEFAULT = 2, //!< Default application clock target NVML_CLOCK_ID_CUSTOMER_BOOST_MAX = 3, //!< OEM-defined maximum clock rate //Keep this last NVML_CLOCK_ID_COUNT //!< Count of Clock Ids. } nvmlClockId_t; /** * Driver models. * * Windows only. */ typedef enum nvmlDriverModel_enum { NVML_DRIVER_WDDM = 0, //!< WDDM driver model -- GPU treated as a display device NVML_DRIVER_WDM = 1 //!< WDM (TCC) model (recommended) -- GPU treated as a generic device } nvmlDriverModel_t; /** * Allowed PStates. */ typedef enum nvmlPStates_enum { NVML_PSTATE_0 = 0, //!< Performance state 0 -- Maximum Performance NVML_PSTATE_1 = 1, //!< Performance state 1 NVML_PSTATE_2 = 2, //!< Performance state 2 NVML_PSTATE_3 = 3, //!< Performance state 3 NVML_PSTATE_4 = 4, //!< Performance state 4 NVML_PSTATE_5 = 5, //!< Performance state 5 NVML_PSTATE_6 = 6, //!< Performance state 6 NVML_PSTATE_7 = 7, //!< Performance state 7 NVML_PSTATE_8 = 8, //!< Performance state 8 NVML_PSTATE_9 = 9, //!< Performance state 9 NVML_PSTATE_10 = 10, //!< Performance state 10 NVML_PSTATE_11 = 11, //!< Performance state 11 NVML_PSTATE_12 = 12, //!< Performance state 12 NVML_PSTATE_13 = 13, //!< Performance state 13 NVML_PSTATE_14 = 14, //!< Performance state 14 NVML_PSTATE_15 = 15, //!< Performance state 15 -- Minimum Performance NVML_PSTATE_UNKNOWN = 32 //!< Unknown performance state } nvmlPstates_t; /** * GPU Operation Mode * * GOM allows to reduce power usage and optimize GPU throughput by disabling GPU features. * * Each GOM is designed to meet specific user needs. */ typedef enum nvmlGom_enum { NVML_GOM_ALL_ON = 0, //!< Everything is enabled and running at full speed NVML_GOM_COMPUTE = 1, //!< Designed for running only compute tasks. Graphics operations //!< are not allowed NVML_GOM_LOW_DP = 2 //!< Designed for running graphics applications that don't require //!< high bandwidth double precision } nvmlGpuOperationMode_t; /** * Available infoROM objects. */ typedef enum nvmlInforomObject_enum { NVML_INFOROM_OEM = 0, //!< An object defined by OEM NVML_INFOROM_ECC = 1, //!< The ECC object determining the level of ECC support NVML_INFOROM_POWER = 2, //!< The power management object // Keep this last NVML_INFOROM_COUNT //!< This counts the number of infoROM objects the driver knows about } nvmlInforomObject_t; /** * Return values for NVML API calls. */ typedef enum nvmlReturn_enum { // cppcheck-suppress * NVML_SUCCESS = 0, //!< The operation was successful NVML_ERROR_UNINITIALIZED = 1, //!< NVML was not first initialized with nvmlInit() NVML_ERROR_INVALID_ARGUMENT = 2, //!< A supplied argument is invalid NVML_ERROR_NOT_SUPPORTED = 3, //!< The requested operation is not available on target device NVML_ERROR_NO_PERMISSION = 4, //!< The current user does not have permission for operation NVML_ERROR_ALREADY_INITIALIZED = 5, //!< Deprecated: Multiple initializations are now allowed through ref counting NVML_ERROR_NOT_FOUND = 6, //!< A query to find an object was unsuccessful NVML_ERROR_INSUFFICIENT_SIZE = 7, //!< An input argument is not large enough NVML_ERROR_INSUFFICIENT_POWER = 8, //!< A device's external power cables are not properly attached NVML_ERROR_DRIVER_NOT_LOADED = 9, //!< NVIDIA driver is not loaded NVML_ERROR_TIMEOUT = 10, //!< User provided timeout passed NVML_ERROR_IRQ_ISSUE = 11, //!< NVIDIA Kernel detected an interrupt issue with a GPU NVML_ERROR_LIBRARY_NOT_FOUND = 12, //!< NVML Shared Library couldn't be found or loaded NVML_ERROR_FUNCTION_NOT_FOUND = 13, //!< Local version of NVML doesn't implement this function NVML_ERROR_CORRUPTED_INFOROM = 14, //!< infoROM is corrupted NVML_ERROR_GPU_IS_LOST = 15, //!< The GPU has fallen off the bus or has otherwise become inaccessible NVML_ERROR_RESET_REQUIRED = 16, //!< The GPU requires a reset before it can be used again NVML_ERROR_OPERATING_SYSTEM = 17, //!< The GPU control device has been blocked by the operating system/cgroups NVML_ERROR_LIB_RM_VERSION_MISMATCH = 18, //!< RM detects a driver/library version mismatch NVML_ERROR_IN_USE = 19, //!< An operation cannot be performed because the GPU is currently in use NVML_ERROR_MEMORY = 20, //!< Insufficient memory NVML_ERROR_NO_DATA = 21, //!usedGpuMemory is not supported unsigned long long time; //!< Amount of time in ms during which the compute context was active. The time is reported as 0 if //!< the process is not terminated unsigned long long startTime; //!< CPU Timestamp in usec representing start time for the process unsigned int isRunning; //!< Flag to represent if the process is running (1 for running, 0 for terminated) unsigned int reserved[5]; //!< Reserved for future use } nvmlAccountingStats_t; /** @} */ /***************************************************************************************************/ /***************************************************************************************************/ /** @defgroup nvmlEncoderStructs Encoder Structs * @{ */ /***************************************************************************************************/ /** * Represents type of encoder for capacity can be queried */ typedef enum nvmlEncoderQueryType_enum { NVML_ENCODER_QUERY_H264 = 0, //!< H264 encoder NVML_ENCODER_QUERY_HEVC = 1, //!< HEVC encoder }nvmlEncoderType_t; /** * Structure to hold encoder session data */ typedef struct nvmlEncoderSessionInfo_st { unsigned int sessionId; //!< Unique session ID unsigned int pid; //!< Owning process ID nvmlVgpuInstance_t vgpuInstance; //!< Owning vGPU instance ID (only valid on vGPU hosts, otherwise zero) nvmlEncoderType_t codecType; //!< Video encoder type unsigned int hResolution; //!< Current encode horizontal resolution unsigned int vResolution; //!< Current encode vertical resolution unsigned int averageFps; //!< Moving average encode frames per second unsigned int averageLatency; //!< Moving average encode latency in microseconds }nvmlEncoderSessionInfo_t; /** @} */ /***************************************************************************************************/ /** @defgroup nvmlFBCStructs Frame Buffer Capture Structures * @{ */ /***************************************************************************************************/ /** * Represents frame buffer capture session type */ typedef enum nvmlFBCSessionType_enum { NVML_FBC_SESSION_TYPE_UNKNOWN = 0, //!< Unknwon NVML_FBC_SESSION_TYPE_TOSYS, //!< ToSys NVML_FBC_SESSION_TYPE_CUDA, //!< Cuda NVML_FBC_SESSION_TYPE_VID, //!< Vid NVML_FBC_SESSION_TYPE_HWENC, //!< HEnc } nvmlFBCSessionType_t; /** * Structure to hold frame buffer capture sessions stats */ typedef struct nvmlFBCStats_st { unsigned int sessionsCount; //!< Total no of sessions unsigned int averageFPS; //!< Moving average new frames captured per second unsigned int averageLatency; //!< Moving average new frame capture latency in microseconds } nvmlFBCStats_t; #define NVML_NVFBC_SESSION_FLAG_DIFFMAP_ENABLED 0x00000001 //!< Bit specifying differential map state. #define NVML_NVFBC_SESSION_FLAG_CLASSIFICATIONMAP_ENABLED 0x00000002 //!< Bit specifying classification map state. #define NVML_NVFBC_SESSION_FLAG_CAPTURE_WITH_WAIT_NO_WAIT 0x00000004 //!< Bit specifying if capture was requested as non-blocking call. #define NVML_NVFBC_SESSION_FLAG_CAPTURE_WITH_WAIT_INFINITE 0x00000008 //!< Bit specifying if capture was requested as blocking call. #define NVML_NVFBC_SESSION_FLAG_CAPTURE_WITH_WAIT_TIMEOUT 0x00000010 //!< Bit specifying if capture was requested as blocking call with timeout period. /** * Structure to hold FBC session data */ typedef struct nvmlFBCSessionInfo_st { unsigned int sessionId; //!< Unique session ID unsigned int pid; //!< Owning process ID nvmlVgpuInstance_t vgpuInstance; //!< Owning vGPU instance ID (only valid on vGPU hosts, otherwise zero) unsigned int displayOrdinal; //!< Display identifier nvmlFBCSessionType_t sessionType; //!< Type of frame buffer capture session unsigned int sessionFlags; //!< Session flags (one or more of NVML_NVFBC_SESSION_FLAG_XXX). unsigned int hMaxResolution; //!< Max horizontal resolution supported by the capture session unsigned int vMaxResolution; //!< Max vertical resolution supported by the capture session unsigned int hResolution; //!< Horizontal resolution requested by caller in capture call unsigned int vResolution; //!< Vertical resolution requested by caller in capture call unsigned int averageFPS; //!< Moving average new frames captured per second unsigned int averageLatency; //!< Moving average new frame capture latency in microseconds } nvmlFBCSessionInfo_t; /** @} */ /***************************************************************************************************/ /** @defgroup nvmlDrainDefs definitions related to the drain state * @{ */ /***************************************************************************************************/ /** * Is the GPU device to be removed from the kernel by nvmlDeviceRemoveGpu() */ typedef enum nvmlDetachGpuState_enum { NVML_DETACH_GPU_KEEP = 0, NVML_DETACH_GPU_REMOVE, } nvmlDetachGpuState_t; /** * Parent bridge PCIe link state requested by nvmlDeviceRemoveGpu() */ typedef enum nvmlPcieLinkState_enum { NVML_PCIE_LINK_KEEP = 0, NVML_PCIE_LINK_SHUT_DOWN, } nvmlPcieLinkState_t; /** @} */ /***************************************************************************************************/ /** @defgroup nvmlInitializationAndCleanup Initialization and Cleanup * This chapter describes the methods that handle NVML initialization and cleanup. * It is the user's responsibility to call \ref nvmlInit() before calling any other methods, and * nvmlShutdown() once NVML is no longer being used. * @{ */ /***************************************************************************************************/ #define NVML_INIT_FLAG_NO_GPUS 1 //!< Don't fail nvmlInit() when no GPUs are found #define NVML_INIT_FLAG_NO_ATTACH 2 //!< Don't attach GPUs /** * Initialize NVML, but don't initialize any GPUs yet. * * \note nvmlInit_v3 introduces a "flags" argument, that allows passing boolean values * modifying the behaviour of nvmlInit(). * \note In NVML 5.319 new nvmlInit_v2 has replaced nvmlInit"_v1" (default in NVML 4.304 and older) that * did initialize all GPU devices in the system. * * This allows NVML to communicate with a GPU * when other GPUs in the system are unstable or in a bad state. When using this API, GPUs are * discovered and initialized in nvmlDeviceGetHandleBy* functions instead. * * \note To contrast nvmlInit_v2 with nvmlInit"_v1", NVML 4.304 nvmlInit"_v1" will fail when any detected GPU is in * a bad or unstable state. * * For all products. * * This method, should be called once before invoking any other methods in the library. * A reference count of the number of initializations is maintained. Shutdown only occurs * when the reference count reaches zero. * * @return * - \ref NVML_SUCCESS if NVML has been properly initialized * - \ref NVML_ERROR_DRIVER_NOT_LOADED if NVIDIA driver is not running * - \ref NVML_ERROR_NO_PERMISSION if NVML does not have permission to talk to the driver * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlInit(void); /** * nvmlInitWithFlags is a variant of nvmlInit(), that allows passing a set of boolean values * modifying the behaviour of nvmlInit(). * Other than the "flags" parameter it is completely similar to \ref nvmlInit. * * For all products. * * @param flags behaviour modifier flags * * @return * - \ref NVML_SUCCESS if NVML has been properly initialized * - \ref NVML_ERROR_DRIVER_NOT_LOADED if NVIDIA driver is not running * - \ref NVML_ERROR_NO_PERMISSION if NVML does not have permission to talk to the driver * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlInitWithFlags(unsigned int flags); /** * Shut down NVML by releasing all GPU resources previously allocated with \ref nvmlInit(). * * For all products. * * This method should be called after NVML work is done, once for each call to \ref nvmlInit() * A reference count of the number of initializations is maintained. Shutdown only occurs * when the reference count reaches zero. For backwards compatibility, no error is reported if * nvmlShutdown() is called more times than nvmlInit(). * * @return * - \ref NVML_SUCCESS if NVML has been properly shut down * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlShutdown(void); /** @} */ /***************************************************************************************************/ /** @defgroup nvmlErrorReporting Error reporting * This chapter describes helper functions for error reporting routines. * @{ */ /***************************************************************************************************/ /** * Helper method for converting NVML error codes into readable strings. * * For all products. * * @param result NVML error code to convert * * @return String representation of the error. * */ const DECLDIR char* nvmlErrorString(nvmlReturn_t result); /** @} */ /***************************************************************************************************/ /** @defgroup nvmlConstants Constants * @{ */ /***************************************************************************************************/ /** * Buffer size guaranteed to be large enough for \ref nvmlDeviceGetInforomVersion and \ref nvmlDeviceGetInforomImageVersion */ #define NVML_DEVICE_INFOROM_VERSION_BUFFER_SIZE 16 /** * Buffer size guaranteed to be large enough for \ref nvmlDeviceGetUUID */ #define NVML_DEVICE_UUID_BUFFER_SIZE 80 /** * Buffer size guaranteed to be large enough for \ref nvmlDeviceGetBoardPartNumber */ #define NVML_DEVICE_PART_NUMBER_BUFFER_SIZE 80 /** * Buffer size guaranteed to be large enough for \ref nvmlSystemGetDriverVersion */ #define NVML_SYSTEM_DRIVER_VERSION_BUFFER_SIZE 80 /** * Buffer size guaranteed to be large enough for \ref nvmlSystemGetNVMLVersion */ #define NVML_SYSTEM_NVML_VERSION_BUFFER_SIZE 80 /** * Buffer size guaranteed to be large enough for \ref nvmlDeviceGetName */ #define NVML_DEVICE_NAME_BUFFER_SIZE 64 /** * Buffer size guaranteed to be large enough for \ref nvmlDeviceGetSerial */ #define NVML_DEVICE_SERIAL_BUFFER_SIZE 30 /** * Buffer size guaranteed to be large enough for \ref nvmlDeviceGetVbiosVersion */ #define NVML_DEVICE_VBIOS_VERSION_BUFFER_SIZE 32 /** @} */ /***************************************************************************************************/ /** @defgroup nvmlSystemQueries System Queries * This chapter describes the queries that NVML can perform against the local system. These queries * are not device-specific. * @{ */ /***************************************************************************************************/ /** * Retrieves the version of the system's graphics driver. * * For all products. * * The version identifier is an alphanumeric string. It will not exceed 80 characters in length * (including the NULL terminator). See \ref nvmlConstants::NVML_SYSTEM_DRIVER_VERSION_BUFFER_SIZE. * * @param version Reference in which to return the version identifier * @param length The maximum allowed length of the string returned in \a version * * @return * - \ref NVML_SUCCESS if \a version has been set * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a version is NULL * - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a length is too small */ nvmlReturn_t DECLDIR nvmlSystemGetDriverVersion(char *version, unsigned int length); /** * Retrieves the version of the NVML library. * * For all products. * * The version identifier is an alphanumeric string. It will not exceed 80 characters in length * (including the NULL terminator). See \ref nvmlConstants::NVML_SYSTEM_NVML_VERSION_BUFFER_SIZE. * * @param version Reference in which to return the version identifier * @param length The maximum allowed length of the string returned in \a version * * @return * - \ref NVML_SUCCESS if \a version has been set * - \ref NVML_ERROR_INVALID_ARGUMENT if \a version is NULL * - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a length is too small */ nvmlReturn_t DECLDIR nvmlSystemGetNVMLVersion(char *version, unsigned int length); /** * Retrieves the version of the CUDA driver. * * For all products. * * The CUDA driver version returned will be retreived from the currently installed version of CUDA. * If the cuda library is not found, this function will return a known supported version number. * * @param cudaDriverVersion Reference in which to return the version identifier * * @return * - \ref NVML_SUCCESS if \a cudaDriverVersion has been set * - \ref NVML_ERROR_INVALID_ARGUMENT if \a cudaDriverVersion is NULL */ nvmlReturn_t DECLDIR nvmlSystemGetCudaDriverVersion(int *cudaDriverVersion); /** * Retrieves the version of the CUDA driver from the shared library. * * For all products. * * The returned CUDA driver version by calling cuDriverGetVersion() * * @param cudaDriverVersion Reference in which to return the version identifier * * @return * - \ref NVML_SUCCESS if \a cudaDriverVersion has been set * - \ref NVML_ERROR_INVALID_ARGUMENT if \a cudaDriverVersion is NULL * - \ref NVML_ERROR_LIBRARY_NOT_FOUND if \a libcuda.so.1 or libcuda.dll is not found * - \ref NVML_ERROR_FUNCTION_NOT_FOUND if \a cuDriverGetVersion() is not found in the shared library */ nvmlReturn_t DECLDIR nvmlSystemGetCudaDriverVersion_v2(int *cudaDriverVersion); /** * Macros for converting the CUDA driver version number to Major and Minor version numbers. */ #define NVML_CUDA_DRIVER_VERSION_MAJOR(v) ((v)/1000) #define NVML_CUDA_DRIVER_VERSION_MINOR(v) (((v)%1000)/10) /** * Gets name of the process with provided process id * * For all products. * * Returned process name is cropped to provided length. * name string is encoded in ANSI. * * @param pid The identifier of the process * @param name Reference in which to return the process name * @param length The maximum allowed length of the string returned in \a name * * @return * - \ref NVML_SUCCESS if \a name has been set * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a name is NULL or \a length is 0. * - \ref NVML_ERROR_NOT_FOUND if process doesn't exists * - \ref NVML_ERROR_NO_PERMISSION if the user doesn't have permission to perform this operation * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlSystemGetProcessName(unsigned int pid, char *name, unsigned int length); /** @} */ /***************************************************************************************************/ /** @defgroup nvmlUnitQueries Unit Queries * This chapter describes that queries that NVML can perform against each unit. For S-class systems only. * In each case the device is identified with an nvmlUnit_t handle. This handle is obtained by * calling \ref nvmlUnitGetHandleByIndex(). * @{ */ /***************************************************************************************************/ /** * Retrieves the number of units in the system. * * For S-class products. * * @param unitCount Reference in which to return the number of units * * @return * - \ref NVML_SUCCESS if \a unitCount has been set * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a unitCount is NULL * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlUnitGetCount(unsigned int *unitCount); /** * Acquire the handle for a particular unit, based on its index. * * For S-class products. * * Valid indices are derived from the \a unitCount returned by \ref nvmlUnitGetCount(). * For example, if \a unitCount is 2 the valid indices are 0 and 1, corresponding to UNIT 0 and UNIT 1. * * The order in which NVML enumerates units has no guarantees of consistency between reboots. * * @param index The index of the target unit, >= 0 and < \a unitCount * @param unit Reference in which to return the unit handle * * @return * - \ref NVML_SUCCESS if \a unit has been set * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a index is invalid or \a unit is NULL * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlUnitGetHandleByIndex(unsigned int index, nvmlUnit_t *unit); /** * Retrieves the static information associated with a unit. * * For S-class products. * * See \ref nvmlUnitInfo_t for details on available unit info. * * @param unit The identifier of the target unit * @param info Reference in which to return the unit information * * @return * - \ref NVML_SUCCESS if \a info has been populated * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a unit is invalid or \a info is NULL */ nvmlReturn_t DECLDIR nvmlUnitGetUnitInfo(nvmlUnit_t unit, nvmlUnitInfo_t *info); /** * Retrieves the LED state associated with this unit. * * For S-class products. * * See \ref nvmlLedState_t for details on allowed states. * * @param unit The identifier of the target unit * @param state Reference in which to return the current LED state * * @return * - \ref NVML_SUCCESS if \a state has been set * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a unit is invalid or \a state is NULL * - \ref NVML_ERROR_NOT_SUPPORTED if this is not an S-class product * - \ref NVML_ERROR_UNKNOWN on any unexpected error * * @see nvmlUnitSetLedState() */ nvmlReturn_t DECLDIR nvmlUnitGetLedState(nvmlUnit_t unit, nvmlLedState_t *state); /** * Retrieves the PSU stats for the unit. * * For S-class products. * * See \ref nvmlPSUInfo_t for details on available PSU info. * * @param unit The identifier of the target unit * @param psu Reference in which to return the PSU information * * @return * - \ref NVML_SUCCESS if \a psu has been populated * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a unit is invalid or \a psu is NULL * - \ref NVML_ERROR_NOT_SUPPORTED if this is not an S-class product * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlUnitGetPsuInfo(nvmlUnit_t unit, nvmlPSUInfo_t *psu); /** * Retrieves the temperature readings for the unit, in degrees C. * * For S-class products. * * Depending on the product, readings may be available for intake (type=0), * exhaust (type=1) and board (type=2). * * @param unit The identifier of the target unit * @param type The type of reading to take * @param temp Reference in which to return the intake temperature * * @return * - \ref NVML_SUCCESS if \a temp has been populated * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a unit or \a type is invalid or \a temp is NULL * - \ref NVML_ERROR_NOT_SUPPORTED if this is not an S-class product * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlUnitGetTemperature(nvmlUnit_t unit, unsigned int type, unsigned int *temp); /** * Retrieves the fan speed readings for the unit. * * For S-class products. * * See \ref nvmlUnitFanSpeeds_t for details on available fan speed info. * * @param unit The identifier of the target unit * @param fanSpeeds Reference in which to return the fan speed information * * @return * - \ref NVML_SUCCESS if \a fanSpeeds has been populated * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a unit is invalid or \a fanSpeeds is NULL * - \ref NVML_ERROR_NOT_SUPPORTED if this is not an S-class product * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlUnitGetFanSpeedInfo(nvmlUnit_t unit, nvmlUnitFanSpeeds_t *fanSpeeds); /** * Retrieves the set of GPU devices that are attached to the specified unit. * * For S-class products. * * The \a deviceCount argument is expected to be set to the size of the input \a devices array. * * @param unit The identifier of the target unit * @param deviceCount Reference in which to provide the \a devices array size, and * to return the number of attached GPU devices * @param devices Reference in which to return the references to the attached GPU devices * * @return * - \ref NVML_SUCCESS if \a deviceCount and \a devices have been populated * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a deviceCount indicates that the \a devices array is too small * - \ref NVML_ERROR_INVALID_ARGUMENT if \a unit is invalid, either of \a deviceCount or \a devices is NULL * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlUnitGetDevices(nvmlUnit_t unit, unsigned int *deviceCount, nvmlDevice_t *devices); /** * Retrieves the IDs and firmware versions for any Host Interface Cards (HICs) in the system. * * For S-class products. * * The \a hwbcCount argument is expected to be set to the size of the input \a hwbcEntries array. * The HIC must be connected to an S-class system for it to be reported by this function. * * @param hwbcCount Size of hwbcEntries array * @param hwbcEntries Array holding information about hwbc * * @return * - \ref NVML_SUCCESS if \a hwbcCount and \a hwbcEntries have been populated * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if either \a hwbcCount or \a hwbcEntries is NULL * - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a hwbcCount indicates that the \a hwbcEntries array is too small */ nvmlReturn_t DECLDIR nvmlSystemGetHicVersion(unsigned int *hwbcCount, nvmlHwbcEntry_t *hwbcEntries); /** @} */ /***************************************************************************************************/ /** @defgroup nvmlDeviceQueries Device Queries * This chapter describes that queries that NVML can perform against each device. * In each case the device is identified with an nvmlDevice_t handle. This handle is obtained by * calling one of \ref nvmlDeviceGetHandleByIndex(), \ref nvmlDeviceGetHandleBySerial(), * \ref nvmlDeviceGetHandleByPciBusId(). or \ref nvmlDeviceGetHandleByUUID(). * @{ */ /***************************************************************************************************/ /** * Retrieves the number of compute devices in the system. A compute device is a single GPU. * * For all products. * * Note: New nvmlDeviceGetCount_v2 (default in NVML 5.319) returns count of all devices in the system * even if nvmlDeviceGetHandleByIndex_v2 returns NVML_ERROR_NO_PERMISSION for such device. * Update your code to handle this error, or use NVML 4.304 or older nvml header file. * For backward binary compatibility reasons _v1 version of the API is still present in the shared * library. * Old _v1 version of nvmlDeviceGetCount doesn't count devices that NVML has no permission to talk to. * * @param deviceCount Reference in which to return the number of accessible devices * * @return * - \ref NVML_SUCCESS if \a deviceCount has been set * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a deviceCount is NULL * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlDeviceGetCount(unsigned int *deviceCount); /** * Acquire the handle for a particular device, based on its index. * * For all products. * * Valid indices are derived from the \a accessibleDevices count returned by * \ref nvmlDeviceGetCount(). For example, if \a accessibleDevices is 2 the valid indices * are 0 and 1, corresponding to GPU 0 and GPU 1. * * The order in which NVML enumerates devices has no guarantees of consistency between reboots. For that reason it * is recommended that devices be looked up by their PCI ids or UUID. See * \ref nvmlDeviceGetHandleByUUID() and \ref nvmlDeviceGetHandleByPciBusId(). * * Note: The NVML index may not correlate with other APIs, such as the CUDA device index. * * Starting from NVML 5, this API causes NVML to initialize the target GPU * NVML may initialize additional GPUs if: * - The target GPU is an SLI slave * * Note: New nvmlDeviceGetCount_v2 (default in NVML 5.319) returns count of all devices in the system * even if nvmlDeviceGetHandleByIndex_v2 returns NVML_ERROR_NO_PERMISSION for such device. * Update your code to handle this error, or use NVML 4.304 or older nvml header file. * For backward binary compatibility reasons _v1 version of the API is still present in the shared * library. * Old _v1 version of nvmlDeviceGetCount doesn't count devices that NVML has no permission to talk to. * * This means that nvmlDeviceGetHandleByIndex_v2 and _v1 can return different devices for the same index. * If you don't touch macros that map old (_v1) versions to _v2 versions at the top of the file you don't * need to worry about that. * * @param index The index of the target GPU, >= 0 and < \a accessibleDevices * @param device Reference in which to return the device handle * * @return * - \ref NVML_SUCCESS if \a device has been set * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a index is invalid or \a device is NULL * - \ref NVML_ERROR_INSUFFICIENT_POWER if any attached devices have improperly attached external power cables * - \ref NVML_ERROR_NO_PERMISSION if the user doesn't have permission to talk to this device * - \ref NVML_ERROR_IRQ_ISSUE if NVIDIA kernel detected an interrupt issue with the attached GPUs * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible * - \ref NVML_ERROR_UNKNOWN on any unexpected error * * @see nvmlDeviceGetIndex * @see nvmlDeviceGetCount */ nvmlReturn_t DECLDIR nvmlDeviceGetHandleByIndex(unsigned int index, nvmlDevice_t *device); /** * Acquire the handle for a particular device, based on its board serial number. * * For Fermi &tm; or newer fully supported devices. * * This number corresponds to the value printed directly on the board, and to the value returned by * \ref nvmlDeviceGetSerial(). * * @deprecated Since more than one GPU can exist on a single board this function is deprecated in favor * of \ref nvmlDeviceGetHandleByUUID. * For dual GPU boards this function will return NVML_ERROR_INVALID_ARGUMENT. * * Starting from NVML 5, this API causes NVML to initialize the target GPU * NVML may initialize additional GPUs as it searches for the target GPU * * @param serial The board serial number of the target GPU * @param device Reference in which to return the device handle * * @return * - \ref NVML_SUCCESS if \a device has been set * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a serial is invalid, \a device is NULL or more than one * device has the same serial (dual GPU boards) * - \ref NVML_ERROR_NOT_FOUND if \a serial does not match a valid device on the system * - \ref NVML_ERROR_INSUFFICIENT_POWER if any attached devices have improperly attached external power cables * - \ref NVML_ERROR_IRQ_ISSUE if NVIDIA kernel detected an interrupt issue with the attached GPUs * - \ref NVML_ERROR_GPU_IS_LOST if any GPU has fallen off the bus or is otherwise inaccessible * - \ref NVML_ERROR_UNKNOWN on any unexpected error * * @see nvmlDeviceGetSerial * @see nvmlDeviceGetHandleByUUID */ nvmlReturn_t DECLDIR nvmlDeviceGetHandleBySerial(const char *serial, nvmlDevice_t *device); /** * Acquire the handle for a particular device, based on its globally unique immutable UUID associated with each device. * * For all products. * * @param uuid The UUID of the target GPU * @param device Reference in which to return the device handle * * Starting from NVML 5, this API causes NVML to initialize the target GPU * NVML may initialize additional GPUs as it searches for the target GPU * * @return * - \ref NVML_SUCCESS if \a device has been set * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a uuid is invalid or \a device is null * - \ref NVML_ERROR_NOT_FOUND if \a uuid does not match a valid device on the system * - \ref NVML_ERROR_INSUFFICIENT_POWER if any attached devices have improperly attached external power cables * - \ref NVML_ERROR_IRQ_ISSUE if NVIDIA kernel detected an interrupt issue with the attached GPUs * - \ref NVML_ERROR_GPU_IS_LOST if any GPU has fallen off the bus or is otherwise inaccessible * - \ref NVML_ERROR_UNKNOWN on any unexpected error * * @see nvmlDeviceGetUUID */ nvmlReturn_t DECLDIR nvmlDeviceGetHandleByUUID(const char *uuid, nvmlDevice_t *device); /** * Acquire the handle for a particular device, based on its PCI bus id. * * For all products. * * This value corresponds to the nvmlPciInfo_t::busId returned by \ref nvmlDeviceGetPciInfo(). * * Starting from NVML 5, this API causes NVML to initialize the target GPU * NVML may initialize additional GPUs if: * - The target GPU is an SLI slave * * \note NVML 4.304 and older version of nvmlDeviceGetHandleByPciBusId"_v1" returns NVML_ERROR_NOT_FOUND * instead of NVML_ERROR_NO_PERMISSION. * * @param pciBusId The PCI bus id of the target GPU * @param device Reference in which to return the device handle * * @return * - \ref NVML_SUCCESS if \a device has been set * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a pciBusId is invalid or \a device is NULL * - \ref NVML_ERROR_NOT_FOUND if \a pciBusId does not match a valid device on the system * - \ref NVML_ERROR_INSUFFICIENT_POWER if the attached device has improperly attached external power cables * - \ref NVML_ERROR_NO_PERMISSION if the user doesn't have permission to talk to this device * - \ref NVML_ERROR_IRQ_ISSUE if NVIDIA kernel detected an interrupt issue with the attached GPUs * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlDeviceGetHandleByPciBusId(const char *pciBusId, nvmlDevice_t *device); /** * Retrieves the name of this device. * * For all products. * * The name is an alphanumeric string that denotes a particular product, e.g. Tesla &tm; C2070. It will not * exceed 64 characters in length (including the NULL terminator). See \ref * nvmlConstants::NVML_DEVICE_NAME_BUFFER_SIZE. * * @param device The identifier of the target device * @param name Reference in which to return the product name * @param length The maximum allowed length of the string returned in \a name * * @return * - \ref NVML_SUCCESS if \a name has been set * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, or \a name is NULL * - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a length is too small * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlDeviceGetName(nvmlDevice_t device, char *name, unsigned int length); /** * Retrieves the brand of this device. * * For all products. * * The type is a member of \ref nvmlBrandType_t defined above. * * @param device The identifier of the target device * @param type Reference in which to return the product brand type * * @return * - \ref NVML_SUCCESS if \a name has been set * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, or \a type is NULL * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlDeviceGetBrand(nvmlDevice_t device, nvmlBrandType_t *type); /** * Retrieves the NVML index of this device. * * For all products. * * Valid indices are derived from the \a accessibleDevices count returned by * \ref nvmlDeviceGetCount(). For example, if \a accessibleDevices is 2 the valid indices * are 0 and 1, corresponding to GPU 0 and GPU 1. * * The order in which NVML enumerates devices has no guarantees of consistency between reboots. For that reason it * is recommended that devices be looked up by their PCI ids or GPU UUID. See * \ref nvmlDeviceGetHandleByPciBusId() and \ref nvmlDeviceGetHandleByUUID(). * * Note: The NVML index may not correlate with other APIs, such as the CUDA device index. * * @param device The identifier of the target device * @param index Reference in which to return the NVML index of the device * * @return * - \ref NVML_SUCCESS if \a index has been set * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, or \a index is NULL * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible * - \ref NVML_ERROR_UNKNOWN on any unexpected error * * @see nvmlDeviceGetHandleByIndex() * @see nvmlDeviceGetCount() */ nvmlReturn_t DECLDIR nvmlDeviceGetIndex(nvmlDevice_t device, unsigned int *index); /** * Retrieves the globally unique board serial number associated with this device's board. * * For all products with an inforom. * * The serial number is an alphanumeric string that will not exceed 30 characters (including the NULL terminator). * This number matches the serial number tag that is physically attached to the board. See \ref * nvmlConstants::NVML_DEVICE_SERIAL_BUFFER_SIZE. * * @param device The identifier of the target device * @param serial Reference in which to return the board/module serial number * @param length The maximum allowed length of the string returned in \a serial * * @return * - \ref NVML_SUCCESS if \a serial has been set * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, or \a serial is NULL * - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a length is too small * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlDeviceGetSerial(nvmlDevice_t device, char *serial, unsigned int length); /** * Retrieves an array of unsigned ints (sized to cpuSetSize) of bitmasks with the ideal CPU affinity for the device * For example, if processors 0, 1, 32, and 33 are ideal for the device and cpuSetSize == 2, * result[0] = 0x3, result[1] = 0x3 * * For Kepler &tm; or newer fully supported devices. * Supported on Linux only. * * @param device The identifier of the target device * @param cpuSetSize The size of the cpuSet array that is safe to access * @param cpuSet Array reference in which to return a bitmask of CPUs, 64 CPUs per * unsigned long on 64-bit machines, 32 on 32-bit machines * * @return * - \ref NVML_SUCCESS if \a cpuAffinity has been filled * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, cpuSetSize == 0, or cpuSet is NULL * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlDeviceGetCpuAffinity(nvmlDevice_t device, unsigned int cpuSetSize, unsigned long *cpuSet); /** * Sets the ideal affinity for the calling thread and device using the guidelines * given in nvmlDeviceGetCpuAffinity(). Note, this is a change as of version 8.0. * Older versions set the affinity for a calling process and all children. * Currently supports up to 64 processors. * * For Kepler &tm; or newer fully supported devices. * Supported on Linux only. * * @param device The identifier of the target device * * @return * - \ref NVML_SUCCESS if the calling process has been successfully bound * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlDeviceSetCpuAffinity(nvmlDevice_t device); /** * Clear all affinity bindings for the calling thread. Note, this is a change as of version * 8.0 as older versions cleared the affinity for a calling process and all children. * * For Kepler &tm; or newer fully supported devices. * Supported on Linux only. * * @param device The identifier of the target device * * @return * - \ref NVML_SUCCESS if the calling process has been successfully unbound * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlDeviceClearCpuAffinity(nvmlDevice_t device); /** * Retrieve the common ancestor for two devices * For all products. * Supported on Linux only. * * @param device1 The identifier of the first device * @param device2 The identifier of the second device * @param pathInfo A \ref nvmlGpuTopologyLevel_t that gives the path type * * @return * - \ref NVML_SUCCESS if \a pathInfo has been set * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device1, or \a device2 is invalid, or \a pathInfo is NULL * - \ref NVML_ERROR_NOT_SUPPORTED if the device or OS does not support this feature * - \ref NVML_ERROR_UNKNOWN an error has occurred in underlying topology discovery */ nvmlReturn_t DECLDIR nvmlDeviceGetTopologyCommonAncestor(nvmlDevice_t device1, nvmlDevice_t device2, nvmlGpuTopologyLevel_t *pathInfo); /** * Retrieve the set of GPUs that are nearest to a given device at a specific interconnectivity level * For all products. * Supported on Linux only. * * @param device The identifier of the first device * @param level The \ref nvmlGpuTopologyLevel_t level to search for other GPUs * @param count When zero, is set to the number of matching GPUs such that \a deviceArray * can be malloc'd. When non-zero, \a deviceArray will be filled with \a count * number of device handles. * @param deviceArray An array of device handles for GPUs found at \a level * * @return * - \ref NVML_SUCCESS if \a deviceArray or \a count (if initially zero) has been set * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device, \a level, or \a count is invalid, or \a deviceArray is NULL with a non-zero \a count * - \ref NVML_ERROR_NOT_SUPPORTED if the device or OS does not support this feature * - \ref NVML_ERROR_UNKNOWN an error has occurred in underlying topology discovery */ nvmlReturn_t DECLDIR nvmlDeviceGetTopologyNearestGpus(nvmlDevice_t device, nvmlGpuTopologyLevel_t level, unsigned int *count, nvmlDevice_t *deviceArray); /** * Retrieve the set of GPUs that have a CPU affinity with the given CPU number * For all products. * Supported on Linux only. * * @param cpuNumber The CPU number * @param count When zero, is set to the number of matching GPUs such that \a deviceArray * can be malloc'd. When non-zero, \a deviceArray will be filled with \a count * number of device handles. * @param deviceArray An array of device handles for GPUs found with affinity to \a cpuNumber * * @return * - \ref NVML_SUCCESS if \a deviceArray or \a count (if initially zero) has been set * - \ref NVML_ERROR_INVALID_ARGUMENT if \a cpuNumber, or \a count is invalid, or \a deviceArray is NULL with a non-zero \a count * - \ref NVML_ERROR_NOT_SUPPORTED if the device or OS does not support this feature * - \ref NVML_ERROR_UNKNOWN an error has occurred in underlying topology discovery */ nvmlReturn_t DECLDIR nvmlSystemGetTopologyGpuSet(unsigned int cpuNumber, unsigned int *count, nvmlDevice_t *deviceArray); /** * Retrieve the status for a given p2p capability index between a given pair of GPU * * @param device1 The first device * @param device2 The second device * @param p2pIndex p2p Capability Index being looked for between \a device1 and \a device2 * @param p2pStatus Reference in which to return the status of the \a p2pIndex * between \a device1 and \a device2 * @return * - \ref NVML_SUCCESS if \a p2pStatus has been populated * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device1 or \a device2 or \a p2pIndex is invalid or \a p2pStatus is NULL * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlDeviceGetP2PStatus(nvmlDevice_t device1, nvmlDevice_t device2, nvmlGpuP2PCapsIndex_t p2pIndex,nvmlGpuP2PStatus_t *p2pStatus); /** * Retrieves the globally unique immutable UUID associated with this device, as a 5 part hexadecimal string, * that augments the immutable, board serial identifier. * * For all products. * * The UUID is a globally unique identifier. It is the only available identifier for pre-Fermi-architecture products. * It does NOT correspond to any identifier printed on the board. It will not exceed 80 characters in length * (including the NULL terminator). See \ref nvmlConstants::NVML_DEVICE_UUID_BUFFER_SIZE. * * @param device The identifier of the target device * @param uuid Reference in which to return the GPU UUID * @param length The maximum allowed length of the string returned in \a uuid * * @return * - \ref NVML_SUCCESS if \a uuid has been set * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, or \a uuid is NULL * - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a length is too small * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlDeviceGetUUID(nvmlDevice_t device, char *uuid, unsigned int length); /** * Retrieves minor number for the device. The minor number for the device is such that the Nvidia device node file for * each GPU will have the form /dev/nvidia[minor number]. * * For all products. * Supported only for Linux * * @param device The identifier of the target device * @param minorNumber Reference in which to return the minor number for the device * @return * - \ref NVML_SUCCESS if the minor number is successfully retrieved * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a minorNumber is NULL * - \ref NVML_ERROR_NOT_SUPPORTED if this query is not supported by the device * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlDeviceGetMinorNumber(nvmlDevice_t device, unsigned int *minorNumber); /** * Retrieves the the device board part number which is programmed into the board's InfoROM * * For all products. * * @param device Identifier of the target device * @param partNumber Reference to the buffer to return * @param length Length of the buffer reference * * @return * - \ref NVML_SUCCESS if \a partNumber has been set * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_NOT_SUPPORTED if the needed VBIOS fields have not been filled * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a serial is NULL * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlDeviceGetBoardPartNumber(nvmlDevice_t device, char* partNumber, unsigned int length); /** * Retrieves the version information for the device's infoROM object. * * For all products with an inforom. * * Fermi and higher parts have non-volatile on-board memory for persisting device info, such as aggregate * ECC counts. The version of the data structures in this memory may change from time to time. It will not * exceed 16 characters in length (including the NULL terminator). * See \ref nvmlConstants::NVML_DEVICE_INFOROM_VERSION_BUFFER_SIZE. * * See \ref nvmlInforomObject_t for details on the available infoROM objects. * * @param device The identifier of the target device * @param object The target infoROM object * @param version Reference in which to return the infoROM version * @param length The maximum allowed length of the string returned in \a version * * @return * - \ref NVML_SUCCESS if \a version has been set * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a version is NULL * - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a length is too small * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not have an infoROM * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible * - \ref NVML_ERROR_UNKNOWN on any unexpected error * * @see nvmlDeviceGetInforomImageVersion */ nvmlReturn_t DECLDIR nvmlDeviceGetInforomVersion(nvmlDevice_t device, nvmlInforomObject_t object, char *version, unsigned int length); /** * Retrieves the global infoROM image version * * For all products with an inforom. * * Image version just like VBIOS version uniquely describes the exact version of the infoROM flashed on the board * in contrast to infoROM object version which is only an indicator of supported features. * Version string will not exceed 16 characters in length (including the NULL terminator). * See \ref nvmlConstants::NVML_DEVICE_INFOROM_VERSION_BUFFER_SIZE. * * @param device The identifier of the target device * @param version Reference in which to return the infoROM image version * @param length The maximum allowed length of the string returned in \a version * * @return * - \ref NVML_SUCCESS if \a version has been set * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a version is NULL * - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a length is too small * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not have an infoROM * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible * - \ref NVML_ERROR_UNKNOWN on any unexpected error * * @see nvmlDeviceGetInforomVersion */ nvmlReturn_t DECLDIR nvmlDeviceGetInforomImageVersion(nvmlDevice_t device, char *version, unsigned int length); /** * Retrieves the checksum of the configuration stored in the device's infoROM. * * For all products with an inforom. * * Can be used to make sure that two GPUs have the exact same configuration. * Current checksum takes into account configuration stored in PWR and ECC infoROM objects. * Checksum can change between driver releases or when user changes configuration (e.g. disable/enable ECC) * * @param device The identifier of the target device * @param checksum Reference in which to return the infoROM configuration checksum * * @return * - \ref NVML_SUCCESS if \a checksum has been set * - \ref NVML_ERROR_CORRUPTED_INFOROM if the device's checksum couldn't be retrieved due to infoROM corruption * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a checksum is NULL * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlDeviceGetInforomConfigurationChecksum(nvmlDevice_t device, unsigned int *checksum); /** * Reads the infoROM from the flash and verifies the checksums. * * For all products with an inforom. * * @param device The identifier of the target device * * @return * - \ref NVML_SUCCESS if infoROM is not corrupted * - \ref NVML_ERROR_CORRUPTED_INFOROM if the device's infoROM is corrupted * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlDeviceValidateInforom(nvmlDevice_t device); /** * Retrieves the display mode for the device. * * For all products. * * This method indicates whether a physical display (e.g. monitor) is currently connected to * any of the device's connectors. * * See \ref nvmlEnableState_t for details on allowed modes. * * @param device The identifier of the target device * @param display Reference in which to return the display mode * * @return * - \ref NVML_SUCCESS if \a display has been set * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a display is NULL * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlDeviceGetDisplayMode(nvmlDevice_t device, nvmlEnableState_t *display); /** * Retrieves the display active state for the device. * * For all products. * * This method indicates whether a display is initialized on the device. * For example whether X Server is attached to this device and has allocated memory for the screen. * * Display can be active even when no monitor is physically attached. * * See \ref nvmlEnableState_t for details on allowed modes. * * @param device The identifier of the target device * @param isActive Reference in which to return the display active state * * @return * - \ref NVML_SUCCESS if \a isActive has been set * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a isActive is NULL * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlDeviceGetDisplayActive(nvmlDevice_t device, nvmlEnableState_t *isActive); /** * Retrieves the persistence mode associated with this device. * * For all products. * For Linux only. * * When driver persistence mode is enabled the driver software state is not torn down when the last * client disconnects. By default this feature is disabled. * * See \ref nvmlEnableState_t for details on allowed modes. * * @param device The identifier of the target device * @param mode Reference in which to return the current driver persistence mode * * @return * - \ref NVML_SUCCESS if \a mode has been set * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a mode is NULL * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible * - \ref NVML_ERROR_UNKNOWN on any unexpected error * * @see nvmlDeviceSetPersistenceMode() */ nvmlReturn_t DECLDIR nvmlDeviceGetPersistenceMode(nvmlDevice_t device, nvmlEnableState_t *mode); /** * Retrieves the PCI attributes of this device. * * For all products. * * See \ref nvmlPciInfo_t for details on the available PCI info. * * @param device The identifier of the target device * @param pci Reference in which to return the PCI info * * @return * - \ref NVML_SUCCESS if \a pci has been populated * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a pci is NULL * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlDeviceGetPciInfo(nvmlDevice_t device, nvmlPciInfo_t *pci); /** * Retrieves the maximum PCIe link generation possible with this device and system * * I.E. for a generation 2 PCIe device attached to a generation 1 PCIe bus the max link generation this function will * report is generation 1. * * For Fermi &tm; or newer fully supported devices. * * @param device The identifier of the target device * @param maxLinkGen Reference in which to return the max PCIe link generation * * @return * - \ref NVML_SUCCESS if \a maxLinkGen has been populated * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a maxLinkGen is null * - \ref NVML_ERROR_NOT_SUPPORTED if PCIe link information is not available * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlDeviceGetMaxPcieLinkGeneration(nvmlDevice_t device, unsigned int *maxLinkGen); /** * Retrieves the maximum PCIe link width possible with this device and system * * I.E. for a device with a 16x PCIe bus width attached to a 8x PCIe system bus this function will report * a max link width of 8. * * For Fermi &tm; or newer fully supported devices. * * @param device The identifier of the target device * @param maxLinkWidth Reference in which to return the max PCIe link generation * * @return * - \ref NVML_SUCCESS if \a maxLinkWidth has been populated * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a maxLinkWidth is null * - \ref NVML_ERROR_NOT_SUPPORTED if PCIe link information is not available * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlDeviceGetMaxPcieLinkWidth(nvmlDevice_t device, unsigned int *maxLinkWidth); /** * Retrieves the current PCIe link generation * * For Fermi &tm; or newer fully supported devices. * * @param device The identifier of the target device * @param currLinkGen Reference in which to return the current PCIe link generation * * @return * - \ref NVML_SUCCESS if \a currLinkGen has been populated * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a currLinkGen is null * - \ref NVML_ERROR_NOT_SUPPORTED if PCIe link information is not available * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlDeviceGetCurrPcieLinkGeneration(nvmlDevice_t device, unsigned int *currLinkGen); /** * Retrieves the current PCIe link width * * For Fermi &tm; or newer fully supported devices. * * @param device The identifier of the target device * @param currLinkWidth Reference in which to return the current PCIe link generation * * @return * - \ref NVML_SUCCESS if \a currLinkWidth has been populated * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a currLinkWidth is null * - \ref NVML_ERROR_NOT_SUPPORTED if PCIe link information is not available * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlDeviceGetCurrPcieLinkWidth(nvmlDevice_t device, unsigned int *currLinkWidth); /** * Retrieve PCIe utilization information. * This function is querying a byte counter over a 20ms interval and thus is the * PCIe throughput over that interval. * * For Maxwell &tm; or newer fully supported devices. * * This method is not supported in virtual machines running virtual GPU (vGPU). * * @param device The identifier of the target device * @param counter The specific counter that should be queried \ref nvmlPcieUtilCounter_t * @param value Reference in which to return throughput in KB/s * * @return * - \ref NVML_SUCCESS if \a value has been set * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device or \a counter is invalid, or \a value is NULL * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlDeviceGetPcieThroughput(nvmlDevice_t device, nvmlPcieUtilCounter_t counter, unsigned int *value); /** * Retrieve the PCIe replay counter. * * For Kepler &tm; or newer fully supported devices. * * @param device The identifier of the target device * @param value Reference in which to return the counter's value * * @return * - \ref NVML_SUCCESS if \a value has been set * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, or \a value is NULL * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlDeviceGetPcieReplayCounter(nvmlDevice_t device, unsigned int *value); /** * Retrieves the current clock speeds for the device. * * For Fermi &tm; or newer fully supported devices. * * See \ref nvmlClockType_t for details on available clock information. * * @param device The identifier of the target device * @param type Identify which clock domain to query * @param clock Reference in which to return the clock speed in MHz * * @return * - \ref NVML_SUCCESS if \a clock has been set * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a clock is NULL * - \ref NVML_ERROR_NOT_SUPPORTED if the device cannot report the specified clock * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlDeviceGetClockInfo(nvmlDevice_t device, nvmlClockType_t type, unsigned int *clock); /** * Retrieves the maximum clock speeds for the device. * * For Fermi &tm; or newer fully supported devices. * * See \ref nvmlClockType_t for details on available clock information. * * \note On GPUs from Fermi family current P0 clocks (reported by \ref nvmlDeviceGetClockInfo) can differ from max clocks * by few MHz. * * @param device The identifier of the target device * @param type Identify which clock domain to query * @param clock Reference in which to return the clock speed in MHz * * @return * - \ref NVML_SUCCESS if \a clock has been set * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a clock is NULL * - \ref NVML_ERROR_NOT_SUPPORTED if the device cannot report the specified clock * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlDeviceGetMaxClockInfo(nvmlDevice_t device, nvmlClockType_t type, unsigned int *clock); /** * Retrieves the current setting of a clock that applications will use unless an overspec situation occurs. * Can be changed using \ref nvmlDeviceSetApplicationsClocks. * * For Kepler &tm; or newer fully supported devices. * * @param device The identifier of the target device * @param clockType Identify which clock domain to query * @param clockMHz Reference in which to return the clock in MHz * * @return * - \ref NVML_SUCCESS if \a clockMHz has been set * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a clockMHz is NULL or \a clockType is invalid * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlDeviceGetApplicationsClock(nvmlDevice_t device, nvmlClockType_t clockType, unsigned int *clockMHz); /** * Retrieves the default applications clock that GPU boots with or * defaults to after \ref nvmlDeviceResetApplicationsClocks call. * * For Kepler &tm; or newer fully supported devices. * * @param device The identifier of the target device * @param clockType Identify which clock domain to query * @param clockMHz Reference in which to return the default clock in MHz * * @return * - \ref NVML_SUCCESS if \a clockMHz has been set * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a clockMHz is NULL or \a clockType is invalid * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible * - \ref NVML_ERROR_UNKNOWN on any unexpected error * * \see nvmlDeviceGetApplicationsClock */ nvmlReturn_t DECLDIR nvmlDeviceGetDefaultApplicationsClock(nvmlDevice_t device, nvmlClockType_t clockType, unsigned int *clockMHz); /** * Resets the application clock to the default value * * This is the applications clock that will be used after system reboot or driver reload. * Default value is constant, but the current value an be changed using \ref nvmlDeviceSetApplicationsClocks. * * On Pascal and newer hardware, if clocks were previously locked with \ref nvmlDeviceSetApplicationsClocks, * this call will unlock clocks. This returns clocks their default behavior ofautomatically boosting above * base clocks as thermal limits allow. * * @see nvmlDeviceGetApplicationsClock * @see nvmlDeviceSetApplicationsClocks * * For Fermi &tm; or newer non-GeForce fully supported devices and Maxwell or newer GeForce devices. * * @param device The identifier of the target device * * @return * - \ref NVML_SUCCESS if new settings were successfully set * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlDeviceResetApplicationsClocks(nvmlDevice_t device); /** * Retrieves the clock speed for the clock specified by the clock type and clock ID. * * For Kepler &tm; or newer fully supported devices. * * @param device The identifier of the target device * @param clockType Identify which clock domain to query * @param clockId Identify which clock in the domain to query * @param clockMHz Reference in which to return the clock in MHz * * @return * - \ref NVML_SUCCESS if \a clockMHz has been set * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a clockMHz is NULL or \a clockType is invalid * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlDeviceGetClock(nvmlDevice_t device, nvmlClockType_t clockType, nvmlClockId_t clockId, unsigned int *clockMHz); /** * Retrieves the customer defined maximum boost clock speed specified by the given clock type. * * For Pascal &tm; or newer fully supported devices. * * @param device The identifier of the target device * @param clockType Identify which clock domain to query * @param clockMHz Reference in which to return the clock in MHz * * @return * - \ref NVML_SUCCESS if \a clockMHz has been set * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a clockMHz is NULL or \a clockType is invalid * - \ref NVML_ERROR_NOT_SUPPORTED if the device or the \a clockType on this device does not support this feature * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlDeviceGetMaxCustomerBoostClock(nvmlDevice_t device, nvmlClockType_t clockType, unsigned int *clockMHz); /** * Retrieves the list of possible memory clocks that can be used as an argument for \ref nvmlDeviceSetApplicationsClocks. * * For Kepler &tm; or newer fully supported devices. * * @param device The identifier of the target device * @param count Reference in which to provide the \a clocksMHz array size, and * to return the number of elements * @param clocksMHz Reference in which to return the clock in MHz * * @return * - \ref NVML_SUCCESS if \a count and \a clocksMHz have been populated * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a count is NULL * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature * - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a count is too small (\a count is set to the number of * required elements) * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible * - \ref NVML_ERROR_UNKNOWN on any unexpected error * * @see nvmlDeviceSetApplicationsClocks * @see nvmlDeviceGetSupportedGraphicsClocks */ nvmlReturn_t DECLDIR nvmlDeviceGetSupportedMemoryClocks(nvmlDevice_t device, unsigned int *count, unsigned int *clocksMHz); /** * Retrieves the list of possible graphics clocks that can be used as an argument for \ref nvmlDeviceSetApplicationsClocks. * * For Kepler &tm; or newer fully supported devices. * * @param device The identifier of the target device * @param memoryClockMHz Memory clock for which to return possible graphics clocks * @param count Reference in which to provide the \a clocksMHz array size, and * to return the number of elements * @param clocksMHz Reference in which to return the clocks in MHz * * @return * - \ref NVML_SUCCESS if \a count and \a clocksMHz have been populated * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_NOT_FOUND if the specified \a memoryClockMHz is not a supported frequency * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a clock is NULL * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature * - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a count is too small * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible * - \ref NVML_ERROR_UNKNOWN on any unexpected error * * @see nvmlDeviceSetApplicationsClocks * @see nvmlDeviceGetSupportedMemoryClocks */ nvmlReturn_t DECLDIR nvmlDeviceGetSupportedGraphicsClocks(nvmlDevice_t device, unsigned int memoryClockMHz, unsigned int *count, unsigned int *clocksMHz); /** * Retrieve the current state of Auto Boosted clocks on a device and store it in \a isEnabled * * For Kepler &tm; or newer fully supported devices. * * Auto Boosted clocks are enabled by default on some hardware, allowing the GPU to run at higher clock rates * to maximize performance as thermal limits allow. * * On Pascal and newer hardware, Auto Aoosted clocks are controlled through application clocks. * Use \ref nvmlDeviceSetApplicationsClocks and \ref nvmlDeviceResetApplicationsClocks to control Auto Boost * behavior. * * @param device The identifier of the target device * @param isEnabled Where to store the current state of Auto Boosted clocks of the target device * @param defaultIsEnabled Where to store the default Auto Boosted clocks behavior of the target device that the device will * revert to when no applications are using the GPU * * @return * - \ref NVML_SUCCESS If \a isEnabled has been been set with the Auto Boosted clocks state of \a device * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a isEnabled is NULL * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support Auto Boosted clocks * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible * - \ref NVML_ERROR_UNKNOWN on any unexpected error * */ nvmlReturn_t DECLDIR nvmlDeviceGetAutoBoostedClocksEnabled(nvmlDevice_t device, nvmlEnableState_t *isEnabled, nvmlEnableState_t *defaultIsEnabled); /** * Try to set the current state of Auto Boosted clocks on a device. * * For Kepler &tm; or newer fully supported devices. * * Auto Boosted clocks are enabled by default on some hardware, allowing the GPU to run at higher clock rates * to maximize performance as thermal limits allow. Auto Boosted clocks should be disabled if fixed clock * rates are desired. * * Non-root users may use this API by default but can be restricted by root from using this API by calling * \ref nvmlDeviceSetAPIRestriction with apiType=NVML_RESTRICTED_API_SET_AUTO_BOOSTED_CLOCKS. * Note: Persistence Mode is required to modify current Auto Boost settings, therefore, it must be enabled. * * On Pascal and newer hardware, Auto Boosted clocks are controlled through application clocks. * Use \ref nvmlDeviceSetApplicationsClocks and \ref nvmlDeviceResetApplicationsClocks to control Auto Boost * behavior. * * @param device The identifier of the target device * @param enabled What state to try to set Auto Boosted clocks of the target device to * * @return * - \ref NVML_SUCCESS If the Auto Boosted clocks were successfully set to the state specified by \a enabled * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support Auto Boosted clocks * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible * - \ref NVML_ERROR_UNKNOWN on any unexpected error * */ nvmlReturn_t DECLDIR nvmlDeviceSetAutoBoostedClocksEnabled(nvmlDevice_t device, nvmlEnableState_t enabled); /** * Try to set the default state of Auto Boosted clocks on a device. This is the default state that Auto Boosted clocks will * return to when no compute running processes (e.g. CUDA application which have an active context) are running * * For Kepler &tm; or newer non-GeForce fully supported devices and Maxwell or newer GeForce devices. * Requires root/admin permissions. * * Auto Boosted clocks are enabled by default on some hardware, allowing the GPU to run at higher clock rates * to maximize performance as thermal limits allow. Auto Boosted clocks should be disabled if fixed clock * rates are desired. * * On Pascal and newer hardware, Auto Boosted clocks are controlled through application clocks. * Use \ref nvmlDeviceSetApplicationsClocks and \ref nvmlDeviceResetApplicationsClocks to control Auto Boost * behavior. * * @param device The identifier of the target device * @param enabled What state to try to set default Auto Boosted clocks of the target device to * @param flags Flags that change the default behavior. Currently Unused. * * @return * - \ref NVML_SUCCESS If the Auto Boosted clock's default state was successfully set to the state specified by \a enabled * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_NO_PERMISSION If the calling user does not have permission to change Auto Boosted clock's default state. * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support Auto Boosted clocks * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible * - \ref NVML_ERROR_UNKNOWN on any unexpected error * */ nvmlReturn_t DECLDIR nvmlDeviceSetDefaultAutoBoostedClocksEnabled(nvmlDevice_t device, nvmlEnableState_t enabled, unsigned int flags); /** * Retrieves the intended operating speed of the device's fan. * * Note: The reported speed is the intended fan speed. If the fan is physically blocked and unable to spin, the * output will not match the actual fan speed. * * For all discrete products with dedicated fans. * * The fan speed is expressed as a percent of the maximum, i.e. full speed is 100%. * * @param device The identifier of the target device * @param speed Reference in which to return the fan speed percentage * * @return * - \ref NVML_SUCCESS if \a speed has been set * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a speed is NULL * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not have a fan * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlDeviceGetFanSpeed(nvmlDevice_t device, unsigned int *speed); /** * Retrieves the intended operating speed of the device's specified fan. * * Note: The reported speed is the intended fan speed. If the fan is physically blocked and unable to spin, the * output will not match the actual fan speed. * * For all discrete products with dedicated fans. * * The fan speed is expressed as a percentage of the maximum, i.e. full speed is 100% * * @param device The identifier of the target device * @param fan The index of the target fan, zero indexed. * @param speed Reference in which to return the fan speed percentage * * @return * - \ref NVML_SUCCESS if \a speed has been set * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, \a fan is not an acceptable index, or \a speed is NULL * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not have a fan or is newer than Maxwell * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlDeviceGetFanSpeed_v2(nvmlDevice_t device, unsigned int fan, unsigned int * speed); /** * Retrieves the current temperature readings for the device, in degrees C. * * For all products. * * See \ref nvmlTemperatureSensors_t for details on available temperature sensors. * * @param device The identifier of the target device * @param sensorType Flag that indicates which sensor reading to retrieve * @param temp Reference in which to return the temperature reading * * @return * - \ref NVML_SUCCESS if \a temp has been set * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, \a sensorType is invalid or \a temp is NULL * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not have the specified sensor * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlDeviceGetTemperature(nvmlDevice_t device, nvmlTemperatureSensors_t sensorType, unsigned int *temp); /** * Retrieves the temperature threshold for the GPU with the specified threshold type in degrees C. * * For Kepler &tm; or newer fully supported devices. * * See \ref nvmlTemperatureThresholds_t for details on available temperature thresholds. * * @param device The identifier of the target device * @param thresholdType The type of threshold value queried * @param temp Reference in which to return the temperature reading * @return * - \ref NVML_SUCCESS if \a temp has been set * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, \a thresholdType is invalid or \a temp is NULL * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not have a temperature sensor or is unsupported * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlDeviceGetTemperatureThreshold(nvmlDevice_t device, nvmlTemperatureThresholds_t thresholdType, unsigned int *temp); /** * Retrieves the current performance state for the device. * * For Fermi &tm; or newer fully supported devices. * * See \ref nvmlPstates_t for details on allowed performance states. * * @param device The identifier of the target device * @param pState Reference in which to return the performance state reading * * @return * - \ref NVML_SUCCESS if \a pState has been set * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a pState is NULL * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlDeviceGetPerformanceState(nvmlDevice_t device, nvmlPstates_t *pState); /** * Retrieves current clocks throttling reasons. * * For all fully supported products. * * \note More than one bit can be enabled at the same time. Multiple reasons can be affecting clocks at once. * * @param device The identifier of the target device * @param clocksThrottleReasons Reference in which to return bitmask of active clocks throttle * reasons * * @return * - \ref NVML_SUCCESS if \a clocksThrottleReasons has been set * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a clocksThrottleReasons is NULL * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible * - \ref NVML_ERROR_UNKNOWN on any unexpected error * * @see nvmlClocksThrottleReasons * @see nvmlDeviceGetSupportedClocksThrottleReasons */ nvmlReturn_t DECLDIR nvmlDeviceGetCurrentClocksThrottleReasons(nvmlDevice_t device, unsigned long long *clocksThrottleReasons); /** * Retrieves bitmask of supported clocks throttle reasons that can be returned by * \ref nvmlDeviceGetCurrentClocksThrottleReasons * * For all fully supported products. * * This method is not supported in virtual machines running virtual GPU (vGPU). * * @param device The identifier of the target device * @param supportedClocksThrottleReasons Reference in which to return bitmask of supported * clocks throttle reasons * * @return * - \ref NVML_SUCCESS if \a supportedClocksThrottleReasons has been set * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a supportedClocksThrottleReasons is NULL * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible * - \ref NVML_ERROR_UNKNOWN on any unexpected error * * @see nvmlClocksThrottleReasons * @see nvmlDeviceGetCurrentClocksThrottleReasons */ nvmlReturn_t DECLDIR nvmlDeviceGetSupportedClocksThrottleReasons(nvmlDevice_t device, unsigned long long *supportedClocksThrottleReasons); /** * Deprecated: Use \ref nvmlDeviceGetPerformanceState. This function exposes an incorrect generalization. * * Retrieve the current performance state for the device. * * For Fermi &tm; or newer fully supported devices. * * See \ref nvmlPstates_t for details on allowed performance states. * * @param device The identifier of the target device * @param pState Reference in which to return the performance state reading * * @return * - \ref NVML_SUCCESS if \a pState has been set * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a pState is NULL * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlDeviceGetPowerState(nvmlDevice_t device, nvmlPstates_t *pState); /** * This API has been deprecated. * * Retrieves the power management mode associated with this device. * * For products from the Fermi family. * - Requires \a NVML_INFOROM_POWER version 3.0 or higher. * * For from the Kepler or newer families. * - Does not require \a NVML_INFOROM_POWER object. * * This flag indicates whether any power management algorithm is currently active on the device. An * enabled state does not necessarily mean the device is being actively throttled -- only that * that the driver will do so if the appropriate conditions are met. * * See \ref nvmlEnableState_t for details on allowed modes. * * @param device The identifier of the target device * @param mode Reference in which to return the current power management mode * * @return * - \ref NVML_SUCCESS if \a mode has been set * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a mode is NULL * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlDeviceGetPowerManagementMode(nvmlDevice_t device, nvmlEnableState_t *mode); /** * Retrieves the power management limit associated with this device. * * For Fermi &tm; or newer fully supported devices. * * The power limit defines the upper boundary for the card's power draw. If * the card's total power draw reaches this limit the power management algorithm kicks in. * * This reading is only available if power management mode is supported. * See \ref nvmlDeviceGetPowerManagementMode. * * @param device The identifier of the target device * @param limit Reference in which to return the power management limit in milliwatts * * @return * - \ref NVML_SUCCESS if \a limit has been set * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a limit is NULL * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlDeviceGetPowerManagementLimit(nvmlDevice_t device, unsigned int *limit); /** * Retrieves information about possible values of power management limits on this device. * * For Kepler &tm; or newer fully supported devices. * * @param device The identifier of the target device * @param minLimit Reference in which to return the minimum power management limit in milliwatts * @param maxLimit Reference in which to return the maximum power management limit in milliwatts * * @return * - \ref NVML_SUCCESS if \a minLimit and \a maxLimit have been set * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a minLimit or \a maxLimit is NULL * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible * - \ref NVML_ERROR_UNKNOWN on any unexpected error * * @see nvmlDeviceSetPowerManagementLimit */ nvmlReturn_t DECLDIR nvmlDeviceGetPowerManagementLimitConstraints(nvmlDevice_t device, unsigned int *minLimit, unsigned int *maxLimit); /** * Retrieves default power management limit on this device, in milliwatts. * Default power management limit is a power management limit that the device boots with. * * For Kepler &tm; or newer fully supported devices. * * @param device The identifier of the target device * @param defaultLimit Reference in which to return the default power management limit in milliwatts * * @return * - \ref NVML_SUCCESS if \a defaultLimit has been set * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a defaultLimit is NULL * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlDeviceGetPowerManagementDefaultLimit(nvmlDevice_t device, unsigned int *defaultLimit); /** * Retrieves power usage for this GPU in milliwatts and its associated circuitry (e.g. memory) * * For Fermi &tm; or newer fully supported devices. * * On Fermi and Kepler GPUs the reading is accurate to within +/- 5% of current power draw. * * It is only available if power management mode is supported. See \ref nvmlDeviceGetPowerManagementMode. * * @param device The identifier of the target device * @param power Reference in which to return the power usage information * * @return * - \ref NVML_SUCCESS if \a power has been populated * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a power is NULL * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support power readings * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlDeviceGetPowerUsage(nvmlDevice_t device, unsigned int *power); /** * Retrieves total energy consumption for this GPU in millijoules (mJ) since the driver was last reloaded * * For newer than Pascal &tm; fully supported devices. * * @param device The identifier of the target device * @param energy Reference in which to return the energy consumption information * * @return * - \ref NVML_SUCCESS if \a energy has been populated * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a energy is NULL * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support energy readings * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlDeviceGetTotalEnergyConsumption(nvmlDevice_t device, unsigned long long *energy); /** * Get the effective power limit that the driver enforces after taking into account all limiters * * Note: This can be different from the \ref nvmlDeviceGetPowerManagementLimit if other limits are set elsewhere * This includes the out of band power limit interface * * For Kepler &tm; or newer fully supported devices. * * @param device The device to communicate with * @param limit Reference in which to return the power management limit in milliwatts * * @return * - \ref NVML_SUCCESS if \a limit has been set * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a limit is NULL * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlDeviceGetEnforcedPowerLimit(nvmlDevice_t device, unsigned int *limit); /** * Retrieves the current GOM and pending GOM (the one that GPU will switch to after reboot). * * For GK110 M-class and X-class Tesla &tm; products from the Kepler family. * Modes \ref NVML_GOM_LOW_DP and \ref NVML_GOM_ALL_ON are supported on fully supported GeForce products. * Not supported on Quadro ® and Tesla &tm; C-class products. * * @param device The identifier of the target device * @param current Reference in which to return the current GOM * @param pending Reference in which to return the pending GOM * * @return * - \ref NVML_SUCCESS if \a mode has been populated * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a current or \a pending is NULL * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible * - \ref NVML_ERROR_UNKNOWN on any unexpected error * * @see nvmlGpuOperationMode_t * @see nvmlDeviceSetGpuOperationMode */ nvmlReturn_t DECLDIR nvmlDeviceGetGpuOperationMode(nvmlDevice_t device, nvmlGpuOperationMode_t *current, nvmlGpuOperationMode_t *pending); /** * Retrieves the amount of used, free and total memory available on the device, in bytes. * * For all products. * * Enabling ECC reduces the amount of total available memory, due to the extra required parity bits. * Under WDDM most device memory is allocated and managed on startup by Windows. * * Under Linux and Windows TCC, the reported amount of used memory is equal to the sum of memory allocated * by all active channels on the device. * * See \ref nvmlMemory_t for details on available memory info. * * @param device The identifier of the target device * @param memory Reference in which to return the memory information * * @return * - \ref NVML_SUCCESS if \a memory has been populated * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a memory is NULL * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlDeviceGetMemoryInfo(nvmlDevice_t device, nvmlMemory_t *memory); /** * Retrieves the current compute mode for the device. * * For all products. * * See \ref nvmlComputeMode_t for details on allowed compute modes. * * @param device The identifier of the target device * @param mode Reference in which to return the current compute mode * * @return * - \ref NVML_SUCCESS if \a mode has been set * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a mode is NULL * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible * - \ref NVML_ERROR_UNKNOWN on any unexpected error * * @see nvmlDeviceSetComputeMode() */ nvmlReturn_t DECLDIR nvmlDeviceGetComputeMode(nvmlDevice_t device, nvmlComputeMode_t *mode); /** * Retrieves the CUDA compute capability of the device. * * For all products. * * Returns the major and minor compute capability version numbers of the * device. The major and minor versions are equivalent to the * CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MINOR and * CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MAJOR attributes that would be * returned by CUDA's cuDeviceGetAttribute(). * * @param device The identifier of the target device * @param major Reference in which to return the major CUDA compute capability * @param minor Reference in which to return the minor CUDA compute capability * * @return * - \ref NVML_SUCCESS if \a major and \a minor have been set * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a major or \a minor are NULL * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlDeviceGetCudaComputeCapability(nvmlDevice_t device, int *major, int *minor); /** * Retrieves the current and pending ECC modes for the device. * * For Fermi &tm; or newer fully supported devices. * Only applicable to devices with ECC. * Requires \a NVML_INFOROM_ECC version 1.0 or higher. * * Changing ECC modes requires a reboot. The "pending" ECC mode refers to the target mode following * the next reboot. * * See \ref nvmlEnableState_t for details on allowed modes. * * @param device The identifier of the target device * @param current Reference in which to return the current ECC mode * @param pending Reference in which to return the pending ECC mode * * @return * - \ref NVML_SUCCESS if \a current and \a pending have been set * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or either \a current or \a pending is NULL * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible * - \ref NVML_ERROR_UNKNOWN on any unexpected error * * @see nvmlDeviceSetEccMode() */ nvmlReturn_t DECLDIR nvmlDeviceGetEccMode(nvmlDevice_t device, nvmlEnableState_t *current, nvmlEnableState_t *pending); /** * Retrieves the device boardId from 0-N. * Devices with the same boardId indicate GPUs connected to the same PLX. Use in conjunction with * \ref nvmlDeviceGetMultiGpuBoard() to decide if they are on the same board as well. * The boardId returned is a unique ID for the current configuration. Uniqueness and ordering across * reboots and system configurations is not guaranteed (i.e. if a Tesla K40c returns 0x100 and * the two GPUs on a Tesla K10 in the same system returns 0x200 it is not guaranteed they will * always return those values but they will always be different from each other). * * * For Fermi &tm; or newer fully supported devices. * * @param device The identifier of the target device * @param boardId Reference in which to return the device's board ID * * @return * - \ref NVML_SUCCESS if \a boardId has been set * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a boardId is NULL * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlDeviceGetBoardId(nvmlDevice_t device, unsigned int *boardId); /** * Retrieves whether the device is on a Multi-GPU Board * Devices that are on multi-GPU boards will set \a multiGpuBool to a non-zero value. * * For Fermi &tm; or newer fully supported devices. * * @param device The identifier of the target device * @param multiGpuBool Reference in which to return a zero or non-zero value * to indicate whether the device is on a multi GPU board * * @return * - \ref NVML_SUCCESS if \a multiGpuBool has been set * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a multiGpuBool is NULL * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlDeviceGetMultiGpuBoard(nvmlDevice_t device, unsigned int *multiGpuBool); /** * Retrieves the total ECC error counts for the device. * * For Fermi &tm; or newer fully supported devices. * Only applicable to devices with ECC. * Requires \a NVML_INFOROM_ECC version 1.0 or higher. * Requires ECC Mode to be enabled. * * The total error count is the sum of errors across each of the separate memory systems, i.e. the total set of * errors across the entire device. * * See \ref nvmlMemoryErrorType_t for a description of available error types.\n * See \ref nvmlEccCounterType_t for a description of available counter types. * * @param device The identifier of the target device * @param errorType Flag that specifies the type of the errors. * @param counterType Flag that specifies the counter-type of the errors. * @param eccCounts Reference in which to return the specified ECC errors * * @return * - \ref NVML_SUCCESS if \a eccCounts has been set * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device, \a errorType or \a counterType is invalid, or \a eccCounts is NULL * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible * - \ref NVML_ERROR_UNKNOWN on any unexpected error * * @see nvmlDeviceClearEccErrorCounts() */ nvmlReturn_t DECLDIR nvmlDeviceGetTotalEccErrors(nvmlDevice_t device, nvmlMemoryErrorType_t errorType, nvmlEccCounterType_t counterType, unsigned long long *eccCounts); /** * Retrieves the detailed ECC error counts for the device. * * @deprecated This API supports only a fixed set of ECC error locations * On different GPU architectures different locations are supported * See \ref nvmlDeviceGetMemoryErrorCounter * * For Fermi &tm; or newer fully supported devices. * Only applicable to devices with ECC. * Requires \a NVML_INFOROM_ECC version 2.0 or higher to report aggregate location-based ECC counts. * Requires \a NVML_INFOROM_ECC version 1.0 or higher to report all other ECC counts. * Requires ECC Mode to be enabled. * * Detailed errors provide separate ECC counts for specific parts of the memory system. * * Reports zero for unsupported ECC error counters when a subset of ECC error counters are supported. * * See \ref nvmlMemoryErrorType_t for a description of available bit types.\n * See \ref nvmlEccCounterType_t for a description of available counter types.\n * See \ref nvmlEccErrorCounts_t for a description of provided detailed ECC counts. * * @param device The identifier of the target device * @param errorType Flag that specifies the type of the errors. * @param counterType Flag that specifies the counter-type of the errors. * @param eccCounts Reference in which to return the specified ECC errors * * @return * - \ref NVML_SUCCESS if \a eccCounts has been populated * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device, \a errorType or \a counterType is invalid, or \a eccCounts is NULL * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible * - \ref NVML_ERROR_UNKNOWN on any unexpected error * * @see nvmlDeviceClearEccErrorCounts() */ nvmlReturn_t DECLDIR nvmlDeviceGetDetailedEccErrors(nvmlDevice_t device, nvmlMemoryErrorType_t errorType, nvmlEccCounterType_t counterType, nvmlEccErrorCounts_t *eccCounts); /** * Retrieves the requested memory error counter for the device. * * For Fermi &tm; or newer fully supported devices. * Requires \a NVML_INFOROM_ECC version 2.0 or higher to report aggregate location-based memory error counts. * Requires \a NVML_INFOROM_ECC version 1.0 or higher to report all other memory error counts. * * Only applicable to devices with ECC. * * Requires ECC Mode to be enabled. * * See \ref nvmlMemoryErrorType_t for a description of available memory error types.\n * See \ref nvmlEccCounterType_t for a description of available counter types.\n * See \ref nvmlMemoryLocation_t for a description of available counter locations.\n * * @param device The identifier of the target device * @param errorType Flag that specifies the type of error. * @param counterType Flag that specifies the counter-type of the errors. * @param locationType Specifies the location of the counter. * @param count Reference in which to return the ECC counter * * @return * - \ref NVML_SUCCESS if \a count has been populated * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device, \a bitTyp,e \a counterType or \a locationType is * invalid, or \a count is NULL * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support ECC error reporting in the specified memory * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlDeviceGetMemoryErrorCounter(nvmlDevice_t device, nvmlMemoryErrorType_t errorType, nvmlEccCounterType_t counterType, nvmlMemoryLocation_t locationType, unsigned long long *count); /** * Retrieves the current utilization rates for the device's major subsystems. * * For Fermi &tm; or newer fully supported devices. * * See \ref nvmlUtilization_t for details on available utilization rates. * * \note During driver initialization when ECC is enabled one can see high GPU and Memory Utilization readings. * This is caused by ECC Memory Scrubbing mechanism that is performed during driver initialization. * * @param device The identifier of the target device * @param utilization Reference in which to return the utilization information * * @return * - \ref NVML_SUCCESS if \a utilization has been populated * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a utilization is NULL * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlDeviceGetUtilizationRates(nvmlDevice_t device, nvmlUtilization_t *utilization); /** * Retrieves the current utilization and sampling size in microseconds for the Encoder * * For Kepler &tm; or newer fully supported devices. * * @param device The identifier of the target device * @param utilization Reference to an unsigned int for encoder utilization info * @param samplingPeriodUs Reference to an unsigned int for the sampling period in US * * @return * - \ref NVML_SUCCESS if \a utilization has been populated * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, \a utilization is NULL, or \a samplingPeriodUs is NULL * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlDeviceGetEncoderUtilization(nvmlDevice_t device, unsigned int *utilization, unsigned int *samplingPeriodUs); /** * Retrieves the current capacity of the device's encoder, as a percentage of maximum encoder capacity with valid values in the range 0-100. * * For Maxwell &tm; or newer fully supported devices. * * @param device The identifier of the target device * @param encoderQueryType Type of encoder to query * @param encoderCapacity Reference to an unsigned int for the encoder capacity * * @return * - \ref NVML_SUCCESS if \a encoderCapacity is fetched * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a encoderCapacity is NULL, or \a device or \a encoderQueryType * are invalid * - \ref NVML_ERROR_NOT_SUPPORTED if device does not support the encoder specified in \a encodeQueryType * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlDeviceGetEncoderCapacity (nvmlDevice_t device, nvmlEncoderType_t encoderQueryType, unsigned int *encoderCapacity); /** * Retrieves the current encoder statistics for a given device. * * For Maxwell &tm; or newer fully supported devices. * * @param device The identifier of the target device * @param sessionCount Reference to an unsigned int for count of active encoder sessions * @param averageFps Reference to an unsigned int for trailing average FPS of all active sessions * @param averageLatency Reference to an unsigned int for encode latency in microseconds * * @return * - \ref NVML_SUCCESS if \a sessionCount, \a averageFps and \a averageLatency is fetched * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a sessionCount, or \a device or \a averageFps, * or \a averageLatency is NULL * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlDeviceGetEncoderStats (nvmlDevice_t device, unsigned int *sessionCount, unsigned int *averageFps, unsigned int *averageLatency); /** * Retrieves information about active encoder sessions on a target device. * * An array of active encoder sessions is returned in the caller-supplied buffer pointed at by \a sessionInfos. The * array elememt count is passed in \a sessionCount, and \a sessionCount is used to return the number of sessions * written to the buffer. * * If the supplied buffer is not large enough to accomodate the active session array, the function returns * NVML_ERROR_INSUFFICIENT_SIZE, with the element count of nvmlEncoderSessionInfo_t array required in \a sessionCount. * To query the number of active encoder sessions, call this function with *sessionCount = 0. The code will return * NVML_SUCCESS with number of active encoder sessions updated in *sessionCount. * * For Maxwell &tm; or newer fully supported devices. * * @param device The identifier of the target device * @param sessionCount Reference to caller supplied array size, and returns the number of sessions. * @param sessionInfos Reference in which to return the session information * * @return * - \ref NVML_SUCCESS if \a sessionInfos is fetched * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a sessionCount is too small, array element count is returned in \a sessionCount * - \ref NVML_ERROR_INVALID_ARGUMENT if \a sessionCount is NULL. * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlDeviceGetEncoderSessions(nvmlDevice_t device, unsigned int *sessionCount, nvmlEncoderSessionInfo_t *sessionInfos); /** * Retrieves the current utilization and sampling size in microseconds for the Decoder * * For Kepler &tm; or newer fully supported devices. * * @param device The identifier of the target device * @param utilization Reference to an unsigned int for decoder utilization info * @param samplingPeriodUs Reference to an unsigned int for the sampling period in US * * @return * - \ref NVML_SUCCESS if \a utilization has been populated * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, \a utilization is NULL, or \a samplingPeriodUs is NULL * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlDeviceGetDecoderUtilization(nvmlDevice_t device, unsigned int *utilization, unsigned int *samplingPeriodUs); /** * Retrieves the active frame buffer capture sessions statistics for a given device. * * For Maxwell &tm; or newer fully supported devices. * * @param device The identifier of the target device * @param fbcStats Reference to nvmlFBCStats_t structure contianing NvFBC stats * * @return * - \ref NVML_SUCCESS if \a fbcStats is fetched * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a fbcStats is NULL * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlDeviceGetFBCStats(nvmlDevice_t device, nvmlFBCStats_t *fbcStats); /** * Retrieves information about active frame buffer capture sessions on a target device. * * An array of active FBC sessions is returned in the caller-supplied buffer pointed at by \a sessionInfo. The * array element count is passed in \a sessionCount, and \a sessionCount is used to return the number of sessions * written to the buffer. * * If the supplied buffer is not large enough to accomodate the active session array, the function returns * NVML_ERROR_INSUFFICIENT_SIZE, with the element count of nvmlFBCSessionInfo_t array required in \a sessionCount. * To query the number of active FBC sessions, call this function with *sessionCount = 0. The code will return * NVML_SUCCESS with number of active FBC sessions updated in *sessionCount. * * For Maxwell &tm; or newer fully supported devices. * * @note hResolution, vResolution, averageFPS and averageLatency data for a FBC session returned in \a sessionInfo may * be zero if there are no new frames captured since the session started. * * @param device The identifier of the target device * @param sessionCount Reference to caller supplied array size, and returns the number of sessions. * @param sessionInfo Reference in which to return the session information * * @return * - \ref NVML_SUCCESS if \a sessionInfo is fetched * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a sessionCount is too small, array element count is returned in \a sessionCount * - \ref NVML_ERROR_INVALID_ARGUMENT if \a sessionCount is NULL. * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlDeviceGetFBCSessions(nvmlDevice_t device, unsigned int *sessionCount, nvmlFBCSessionInfo_t *sessionInfo); /** * Retrieves the current and pending driver model for the device. * * For Fermi &tm; or newer fully supported devices. * For windows only. * * On Windows platforms the device driver can run in either WDDM or WDM (TCC) mode. If a display is attached * to the device it must run in WDDM mode. TCC mode is preferred if a display is not attached. * * See \ref nvmlDriverModel_t for details on available driver models. * * @param device The identifier of the target device * @param current Reference in which to return the current driver model * @param pending Reference in which to return the pending driver model * * @return * - \ref NVML_SUCCESS if either \a current and/or \a pending have been set * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or both \a current and \a pending are NULL * - \ref NVML_ERROR_NOT_SUPPORTED if the platform is not windows * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible * - \ref NVML_ERROR_UNKNOWN on any unexpected error * * @see nvmlDeviceSetDriverModel() */ nvmlReturn_t DECLDIR nvmlDeviceGetDriverModel(nvmlDevice_t device, nvmlDriverModel_t *current, nvmlDriverModel_t *pending); /** * Get VBIOS version of the device. * * For all products. * * The VBIOS version may change from time to time. It will not exceed 32 characters in length * (including the NULL terminator). See \ref nvmlConstants::NVML_DEVICE_VBIOS_VERSION_BUFFER_SIZE. * * @param device The identifier of the target device * @param version Reference to which to return the VBIOS version * @param length The maximum allowed length of the string returned in \a version * * @return * - \ref NVML_SUCCESS if \a version has been set * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, or \a version is NULL * - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a length is too small * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlDeviceGetVbiosVersion(nvmlDevice_t device, char *version, unsigned int length); /** * Get Bridge Chip Information for all the bridge chips on the board. * * For all fully supported products. * Only applicable to multi-GPU products. * * @param device The identifier of the target device * @param bridgeHierarchy Reference to the returned bridge chip Hierarchy * * @return * - \ref NVML_SUCCESS if bridge chip exists * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, or \a bridgeInfo is NULL * - \ref NVML_ERROR_NOT_SUPPORTED if bridge chip not supported on the device * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible * - \ref NVML_ERROR_UNKNOWN on any unexpected error * */ nvmlReturn_t DECLDIR nvmlDeviceGetBridgeChipInfo(nvmlDevice_t device, nvmlBridgeChipHierarchy_t *bridgeHierarchy); /** * Get information about processes with a compute context on a device * * For Fermi &tm; or newer fully supported devices. * * This function returns information only about compute running processes (e.g. CUDA application which have * active context). Any graphics applications (e.g. using OpenGL, DirectX) won't be listed by this function. * * To query the current number of running compute processes, call this function with *infoCount = 0. The * return code will be NVML_ERROR_INSUFFICIENT_SIZE, or NVML_SUCCESS if none are running. For this call * \a infos is allowed to be NULL. * * The usedGpuMemory field returned is all of the memory used by the application. * * Keep in mind that information returned by this call is dynamic and the number of elements might change in * time. Allocate more space for \a infos table in case new compute processes are spawned. * * @param device The identifier of the target device * @param infoCount Reference in which to provide the \a infos array size, and * to return the number of returned elements * @param infos Reference in which to return the process information * * @return * - \ref NVML_SUCCESS if \a infoCount and \a infos have been populated * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a infoCount indicates that the \a infos array is too small * \a infoCount will contain minimal amount of space necessary for * the call to complete * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, either of \a infoCount or \a infos is NULL * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible * - \ref NVML_ERROR_UNKNOWN on any unexpected error * * @see \ref nvmlSystemGetProcessName */ nvmlReturn_t DECLDIR nvmlDeviceGetComputeRunningProcesses(nvmlDevice_t device, unsigned int *infoCount, nvmlProcessInfo_t *infos); /** * Get information about processes with a graphics context on a device * * For Kepler &tm; or newer fully supported devices. * * This function returns information only about graphics based processes * (eg. applications using OpenGL, DirectX) * * To query the current number of running graphics processes, call this function with *infoCount = 0. The * return code will be NVML_ERROR_INSUFFICIENT_SIZE, or NVML_SUCCESS if none are running. For this call * \a infos is allowed to be NULL. * * The usedGpuMemory field returned is all of the memory used by the application. * * Keep in mind that information returned by this call is dynamic and the number of elements might change in * time. Allocate more space for \a infos table in case new graphics processes are spawned. * * @param device The identifier of the target device * @param infoCount Reference in which to provide the \a infos array size, and * to return the number of returned elements * @param infos Reference in which to return the process information * * @return * - \ref NVML_SUCCESS if \a infoCount and \a infos have been populated * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a infoCount indicates that the \a infos array is too small * \a infoCount will contain minimal amount of space necessary for * the call to complete * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, either of \a infoCount or \a infos is NULL * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible * - \ref NVML_ERROR_UNKNOWN on any unexpected error * * @see \ref nvmlSystemGetProcessName */ nvmlReturn_t DECLDIR nvmlDeviceGetGraphicsRunningProcesses(nvmlDevice_t device, unsigned int *infoCount, nvmlProcessInfo_t *infos); /** * Check if the GPU devices are on the same physical board. * * For all fully supported products. * * @param device1 The first GPU device * @param device2 The second GPU device * @param onSameBoard Reference in which to return the status. * Non-zero indicates that the GPUs are on the same board. * * @return * - \ref NVML_SUCCESS if \a onSameBoard has been set * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a dev1 or \a dev2 are invalid or \a onSameBoard is NULL * - \ref NVML_ERROR_NOT_SUPPORTED if this check is not supported by the device * - \ref NVML_ERROR_GPU_IS_LOST if the either GPU has fallen off the bus or is otherwise inaccessible * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlDeviceOnSameBoard(nvmlDevice_t device1, nvmlDevice_t device2, int *onSameBoard); /** * Retrieves the root/admin permissions on the target API. See \a nvmlRestrictedAPI_t for the list of supported APIs. * If an API is restricted only root users can call that API. See \a nvmlDeviceSetAPIRestriction to change current permissions. * * For all fully supported products. * * @param device The identifier of the target device * @param apiType Target API type for this operation * @param isRestricted Reference in which to return the current restriction * NVML_FEATURE_ENABLED indicates that the API is root-only * NVML_FEATURE_DISABLED indicates that the API is accessible to all users * * @return * - \ref NVML_SUCCESS if \a isRestricted has been set * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, \a apiType incorrect or \a isRestricted is NULL * - \ref NVML_ERROR_NOT_SUPPORTED if this query is not supported by the device or the device does not support * the feature that is being queried (E.G. Enabling/disabling Auto Boosted clocks is * not supported by the device) * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible * - \ref NVML_ERROR_UNKNOWN on any unexpected error * * @see nvmlRestrictedAPI_t */ nvmlReturn_t DECLDIR nvmlDeviceGetAPIRestriction(nvmlDevice_t device, nvmlRestrictedAPI_t apiType, nvmlEnableState_t *isRestricted); /** * Gets recent samples for the GPU. * * For Kepler &tm; or newer fully supported devices. * * Based on type, this method can be used to fetch the power, utilization or clock samples maintained in the buffer by * the driver. * * Power, Utilization and Clock samples are returned as type "unsigned int" for the union nvmlValue_t. * * To get the size of samples that user needs to allocate, the method is invoked with samples set to NULL. * The returned samplesCount will provide the number of samples that can be queried. The user needs to * allocate the buffer with size as samplesCount * sizeof(nvmlSample_t). * * lastSeenTimeStamp represents CPU timestamp in microseconds. Set it to 0 to fetch all the samples maintained by the * underlying buffer. Set lastSeenTimeStamp to one of the timeStamps retrieved from the date of the previous query * to get more recent samples. * * This method fetches the number of entries which can be accommodated in the provided samples array, and the * reference samplesCount is updated to indicate how many samples were actually retrieved. The advantage of using this * method for samples in contrast to polling via existing methods is to get get higher frequency data at lower polling cost. * * @param device The identifier for the target device * @param type Type of sampling event * @param lastSeenTimeStamp Return only samples with timestamp greater than lastSeenTimeStamp. * @param sampleValType Output parameter to represent the type of sample value as described in nvmlSampleVal_t * @param sampleCount Reference to provide the number of elements which can be queried in samples array * @param samples Reference in which samples are returned * @return * - \ref NVML_SUCCESS if samples are successfully retrieved * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, \a samplesCount is NULL or * reference to \a sampleCount is 0 for non null \a samples * - \ref NVML_ERROR_NOT_SUPPORTED if this query is not supported by the device * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible * - \ref NVML_ERROR_NOT_FOUND if sample entries are not found * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlDeviceGetSamples(nvmlDevice_t device, nvmlSamplingType_t type, unsigned long long lastSeenTimeStamp, nvmlValueType_t *sampleValType, unsigned int *sampleCount, nvmlSample_t *samples); /** * Gets Total, Available and Used size of BAR1 memory. * * BAR1 is used to map the FB (device memory) so that it can be directly accessed by the CPU or by 3rd party * devices (peer-to-peer on the PCIE bus). * * For Kepler &tm; or newer fully supported devices. * * @param device The identifier of the target device * @param bar1Memory Reference in which BAR1 memory * information is returned. * * @return * - \ref NVML_SUCCESS if BAR1 memory is successfully retrieved * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, \a bar1Memory is NULL * - \ref NVML_ERROR_NOT_SUPPORTED if this query is not supported by the device * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible * - \ref NVML_ERROR_UNKNOWN on any unexpected error * */ nvmlReturn_t DECLDIR nvmlDeviceGetBAR1MemoryInfo(nvmlDevice_t device, nvmlBAR1Memory_t *bar1Memory); /** * Gets the duration of time during which the device was throttled (lower than requested clocks) due to power * or thermal constraints. * * The method is important to users who are tying to understand if their GPUs throttle at any point during their applications. The * difference in violation times at two different reference times gives the indication of GPU throttling event. * * Violation for thermal capping is not supported at this time. * * For Kepler &tm; or newer fully supported devices. * * @param device The identifier of the target device * @param perfPolicyType Represents Performance policy which can trigger GPU throttling * @param violTime Reference to which violation time related information is returned * * * @return * - \ref NVML_SUCCESS if violation time is successfully retrieved * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, \a perfPolicyType is invalid, or \a violTime is NULL * - \ref NVML_ERROR_NOT_SUPPORTED if this query is not supported by the device * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible * */ nvmlReturn_t DECLDIR nvmlDeviceGetViolationStatus(nvmlDevice_t device, nvmlPerfPolicyType_t perfPolicyType, nvmlViolationTime_t *violTime); /** * @} */ /** @addtogroup nvmlAccountingStats * @{ */ /** * Queries the state of per process accounting mode. * * For Kepler &tm; or newer fully supported devices. * * See \ref nvmlDeviceGetAccountingStats for more details. * See \ref nvmlDeviceSetAccountingMode * * @param device The identifier of the target device * @param mode Reference in which to return the current accounting mode * * @return * - \ref NVML_SUCCESS if the mode has been successfully retrieved * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a mode are NULL * - \ref NVML_ERROR_NOT_SUPPORTED if the device doesn't support this feature * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlDeviceGetAccountingMode(nvmlDevice_t device, nvmlEnableState_t *mode); /** * Queries process's accounting stats. * * For Kepler &tm; or newer fully supported devices. * * Accounting stats capture GPU utilization and other statistics across the lifetime of a process. * Accounting stats can be queried during life time of the process and after its termination. * The time field in \ref nvmlAccountingStats_t is reported as 0 during the lifetime of the process and * updated to actual running time after its termination. * Accounting stats are kept in a circular buffer, newly created processes overwrite information about old * processes. * * See \ref nvmlAccountingStats_t for description of each returned metric. * List of processes that can be queried can be retrieved from \ref nvmlDeviceGetAccountingPids. * * @note Accounting Mode needs to be on. See \ref nvmlDeviceGetAccountingMode. * @note Only compute and graphics applications stats can be queried. Monitoring applications stats can't be * queried since they don't contribute to GPU utilization. * @note In case of pid collision stats of only the latest process (that terminated last) will be reported * * @warning On Kepler devices per process statistics are accurate only if there's one process running on a GPU. * * @param device The identifier of the target device * @param pid Process Id of the target process to query stats for * @param stats Reference in which to return the process's accounting stats * * @return * - \ref NVML_SUCCESS if stats have been successfully retrieved * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a stats are NULL * - \ref NVML_ERROR_NOT_FOUND if process stats were not found * - \ref NVML_ERROR_NOT_SUPPORTED if the device doesn't support this feature or accounting mode is disabled * - \ref NVML_ERROR_UNKNOWN on any unexpected error * * @see nvmlDeviceGetAccountingBufferSize */ nvmlReturn_t DECLDIR nvmlDeviceGetAccountingStats(nvmlDevice_t device, unsigned int pid, nvmlAccountingStats_t *stats); /** * Queries list of processes that can be queried for accounting stats. The list of processes returned * can be in running or terminated state. * * For Kepler &tm; or newer fully supported devices. * * To just query the number of processes ready to be queried, call this function with *count = 0 and * pids=NULL. The return code will be NVML_ERROR_INSUFFICIENT_SIZE, or NVML_SUCCESS if list is empty. * * For more details see \ref nvmlDeviceGetAccountingStats. * * @note In case of PID collision some processes might not be accessible before the circular buffer is full. * * @param device The identifier of the target device * @param count Reference in which to provide the \a pids array size, and * to return the number of elements ready to be queried * @param pids Reference in which to return list of process ids * * @return * - \ref NVML_SUCCESS if pids were successfully retrieved * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a count is NULL * - \ref NVML_ERROR_NOT_SUPPORTED if the device doesn't support this feature or accounting mode is disabled * - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a count is too small (\a count is set to * expected value) * - \ref NVML_ERROR_UNKNOWN on any unexpected error * * @see nvmlDeviceGetAccountingBufferSize */ nvmlReturn_t DECLDIR nvmlDeviceGetAccountingPids(nvmlDevice_t device, unsigned int *count, unsigned int *pids); /** * Returns the number of processes that the circular buffer with accounting pids can hold. * * For Kepler &tm; or newer fully supported devices. * * This is the maximum number of processes that accounting information will be stored for before information * about oldest processes will get overwritten by information about new processes. * * @param device The identifier of the target device * @param bufferSize Reference in which to provide the size (in number of elements) * of the circular buffer for accounting stats. * * @return * - \ref NVML_SUCCESS if buffer size was successfully retrieved * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a bufferSize is NULL * - \ref NVML_ERROR_NOT_SUPPORTED if the device doesn't support this feature or accounting mode is disabled * - \ref NVML_ERROR_UNKNOWN on any unexpected error * * @see nvmlDeviceGetAccountingStats * @see nvmlDeviceGetAccountingPids */ nvmlReturn_t DECLDIR nvmlDeviceGetAccountingBufferSize(nvmlDevice_t device, unsigned int *bufferSize); /** @} */ /** @addtogroup nvmlDeviceQueries * @{ */ /** * Returns the list of retired pages by source, including pages that are pending retirement * The address information provided from this API is the hardware address of the page that was retired. Note * that this does not match the virtual address used in CUDA, but will match the address information in XID 63 * * For Kepler &tm; or newer fully supported devices. * * @param device The identifier of the target device * @param cause Filter page addresses by cause of retirement * @param pageCount Reference in which to provide the \a addresses buffer size, and * to return the number of retired pages that match \a cause * Set to 0 to query the size without allocating an \a addresses buffer * @param addresses Buffer to write the page addresses into * * @return * - \ref NVML_SUCCESS if \a pageCount was populated and \a addresses was filled * - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a pageCount indicates the buffer is not large enough to store all the * matching page addresses. \a pageCount is set to the needed size. * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, \a pageCount is NULL, \a cause is invalid, or * \a addresses is NULL * - \ref NVML_ERROR_NOT_SUPPORTED if the device doesn't support this feature * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlDeviceGetRetiredPages(nvmlDevice_t device, nvmlPageRetirementCause_t cause, unsigned int *pageCount, unsigned long long *addresses); /** * Returns the list of retired pages by source, including pages that are pending retirement * The address information provided from this API is the hardware address of the page that was retired. Note * that this does not match the virtual address used in CUDA, but will match the address information in XID 63 * * \note nvmlDeviceGetRetiredPages_v2 adds an additional timestamps paramter to return the time of each page's * retirement. * * For Kepler &tm; or newer fully supported devices. * * @param device The identifier of the target device * @param cause Filter page addresses by cause of retirement * @param pageCount Reference in which to provide the \a addresses buffer size, and * to return the number of retired pages that match \a cause * Set to 0 to query the size without allocating an \a addresses buffer * @param addresses Buffer to write the page addresses into * @param timestamps Buffer to write the timestamps of page retirement, additional for _v2 * * @return * - \ref NVML_SUCCESS if \a pageCount was populated and \a addresses was filled * - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a pageCount indicates the buffer is not large enough to store all the * matching page addresses. \a pageCount is set to the needed size. * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, \a pageCount is NULL, \a cause is invalid, or * \a addresses is NULL * - \ref NVML_ERROR_NOT_SUPPORTED if the device doesn't support this feature * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlDeviceGetRetiredPages_v2(nvmlDevice_t device, nvmlPageRetirementCause_t cause, unsigned int *pageCount, unsigned long long *addresses, unsigned long long *timestamps); /** * Check if any pages are pending retirement and need a reboot to fully retire. * * For Kepler &tm; or newer fully supported devices. * * @param device The identifier of the target device * @param isPending Reference in which to return the pending status * * @return * - \ref NVML_SUCCESS if \a isPending was populated * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a isPending is NULL * - \ref NVML_ERROR_NOT_SUPPORTED if the device doesn't support this feature * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlDeviceGetRetiredPagesPendingStatus(nvmlDevice_t device, nvmlEnableState_t *isPending); /** @} */ /***************************************************************************************************/ /** @defgroup nvmlUnitCommands Unit Commands * This chapter describes NVML operations that change the state of the unit. For S-class products. * Each of these requires root/admin access. Non-admin users will see an NVML_ERROR_NO_PERMISSION * error code when invoking any of these methods. * @{ */ /***************************************************************************************************/ /** * Set the LED state for the unit. The LED can be either green (0) or amber (1). * * For S-class products. * Requires root/admin permissions. * * This operation takes effect immediately. * * * Current S-Class products don't provide unique LEDs for each unit. As such, both front * and back LEDs will be toggled in unison regardless of which unit is specified with this command. * * See \ref nvmlLedColor_t for available colors. * * @param unit The identifier of the target unit * @param color The target LED color * * @return * - \ref NVML_SUCCESS if the LED color has been set * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a unit or \a color is invalid * - \ref NVML_ERROR_NOT_SUPPORTED if this is not an S-class product * - \ref NVML_ERROR_NO_PERMISSION if the user doesn't have permission to perform this operation * - \ref NVML_ERROR_UNKNOWN on any unexpected error * * @see nvmlUnitGetLedState() */ nvmlReturn_t DECLDIR nvmlUnitSetLedState(nvmlUnit_t unit, nvmlLedColor_t color); /** @} */ /***************************************************************************************************/ /** @defgroup nvmlDeviceCommands Device Commands * This chapter describes NVML operations that change the state of the device. * Each of these requires root/admin access. Non-admin users will see an NVML_ERROR_NO_PERMISSION * error code when invoking any of these methods. * @{ */ /***************************************************************************************************/ /** * Set the persistence mode for the device. * * For all products. * For Linux only. * Requires root/admin permissions. * * The persistence mode determines whether the GPU driver software is torn down after the last client * exits. * * This operation takes effect immediately. It is not persistent across reboots. After each reboot the * persistence mode is reset to "Disabled". * * See \ref nvmlEnableState_t for available modes. * * After calling this API with mode set to NVML_FEATURE_DISABLED on a device that has its own NUMA * memory, the given device handle will no longer be valid, and to continue to interact with this * device, a new handle should be obtained from one of the nvmlDeviceGetHandleBy*() APIs. This * limitation is currently only applicable to devices that have a coherent NVLink connection to * system memory. * * @param device The identifier of the target device * @param mode The target persistence mode * * @return * - \ref NVML_SUCCESS if the persistence mode was set * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a mode is invalid * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature * - \ref NVML_ERROR_NO_PERMISSION if the user doesn't have permission to perform this operation * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible * - \ref NVML_ERROR_UNKNOWN on any unexpected error * * @see nvmlDeviceGetPersistenceMode() */ nvmlReturn_t DECLDIR nvmlDeviceSetPersistenceMode(nvmlDevice_t device, nvmlEnableState_t mode); /** * Set the compute mode for the device. * * For all products. * Requires root/admin permissions. * * The compute mode determines whether a GPU can be used for compute operations and whether it can * be shared across contexts. * * This operation takes effect immediately. Under Linux it is not persistent across reboots and * always resets to "Default". Under windows it is persistent. * * Under windows compute mode may only be set to DEFAULT when running in WDDM * * See \ref nvmlComputeMode_t for details on available compute modes. * * @param device The identifier of the target device * @param mode The target compute mode * * @return * - \ref NVML_SUCCESS if the compute mode was set * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a mode is invalid * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature * - \ref NVML_ERROR_NO_PERMISSION if the user doesn't have permission to perform this operation * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible * - \ref NVML_ERROR_UNKNOWN on any unexpected error * * @see nvmlDeviceGetComputeMode() */ nvmlReturn_t DECLDIR nvmlDeviceSetComputeMode(nvmlDevice_t device, nvmlComputeMode_t mode); /** * Set the ECC mode for the device. * * For Kepler &tm; or newer fully supported devices. * Only applicable to devices with ECC. * Requires \a NVML_INFOROM_ECC version 1.0 or higher. * Requires root/admin permissions. * * The ECC mode determines whether the GPU enables its ECC support. * * This operation takes effect after the next reboot. * * See \ref nvmlEnableState_t for details on available modes. * * @param device The identifier of the target device * @param ecc The target ECC mode * * @return * - \ref NVML_SUCCESS if the ECC mode was set * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a ecc is invalid * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature * - \ref NVML_ERROR_NO_PERMISSION if the user doesn't have permission to perform this operation * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible * - \ref NVML_ERROR_UNKNOWN on any unexpected error * * @see nvmlDeviceGetEccMode() */ nvmlReturn_t DECLDIR nvmlDeviceSetEccMode(nvmlDevice_t device, nvmlEnableState_t ecc); /** * Clear the ECC error and other memory error counts for the device. * * For Kepler &tm; or newer fully supported devices. * Only applicable to devices with ECC. * Requires \a NVML_INFOROM_ECC version 2.0 or higher to clear aggregate location-based ECC counts. * Requires \a NVML_INFOROM_ECC version 1.0 or higher to clear all other ECC counts. * Requires root/admin permissions. * Requires ECC Mode to be enabled. * * Sets all of the specified ECC counters to 0, including both detailed and total counts. * * This operation takes effect immediately. * * See \ref nvmlMemoryErrorType_t for details on available counter types. * * @param device The identifier of the target device * @param counterType Flag that indicates which type of errors should be cleared. * * @return * - \ref NVML_SUCCESS if the error counts were cleared * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a counterType is invalid * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature * - \ref NVML_ERROR_NO_PERMISSION if the user doesn't have permission to perform this operation * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible * - \ref NVML_ERROR_UNKNOWN on any unexpected error * * @see * - nvmlDeviceGetDetailedEccErrors() * - nvmlDeviceGetTotalEccErrors() */ nvmlReturn_t DECLDIR nvmlDeviceClearEccErrorCounts(nvmlDevice_t device, nvmlEccCounterType_t counterType); /** * Set the driver model for the device. * * For Fermi &tm; or newer fully supported devices. * For windows only. * Requires root/admin permissions. * * On Windows platforms the device driver can run in either WDDM or WDM (TCC) mode. If a display is attached * to the device it must run in WDDM mode. * * It is possible to force the change to WDM (TCC) while the display is still attached with a force flag (nvmlFlagForce). * This should only be done if the host is subsequently powered down and the display is detached from the device * before the next reboot. * * This operation takes effect after the next reboot. * * Windows driver model may only be set to WDDM when running in DEFAULT compute mode. * * Change driver model to WDDM is not supported when GPU doesn't support graphics acceleration or * will not support it after reboot. See \ref nvmlDeviceSetGpuOperationMode. * * See \ref nvmlDriverModel_t for details on available driver models. * See \ref nvmlFlagDefault and \ref nvmlFlagForce * * @param device The identifier of the target device * @param driverModel The target driver model * @param flags Flags that change the default behavior * * @return * - \ref NVML_SUCCESS if the driver model has been set * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a driverModel is invalid * - \ref NVML_ERROR_NOT_SUPPORTED if the platform is not windows or the device does not support this feature * - \ref NVML_ERROR_NO_PERMISSION if the user doesn't have permission to perform this operation * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible * - \ref NVML_ERROR_UNKNOWN on any unexpected error * * @see nvmlDeviceGetDriverModel() */ nvmlReturn_t DECLDIR nvmlDeviceSetDriverModel(nvmlDevice_t device, nvmlDriverModel_t driverModel, unsigned int flags); /** * Set clocks that device will lock to. * * Sets the clocks that the device will be running at to the value in the range of minGpuClockMHz to maxGpuClockMHz. * Setting this will supercede application clock values and take effect regardless if a cuda app is running. * See /ref nvmlDeviceSetApplicationsClocks * * Can be used as a setting to request constant performance. * * Requires root/admin permissions. * * After system reboot or driver reload applications clocks go back to their default value. * See \ref nvmlDeviceResetGpuLockedClocks. * * For newer than Pascal &tm; fully supported devices. * * @param device The identifier of the target device * @param minGpuClockMHz Requested minimum gpu clock in MHz * @param maxGpuClockMHz Requested maximum gpu clock in MHz * * @return * - \ref NVML_SUCCESS if new settings were successfully set * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a minGpuClockMHz and \a maxGpuClockMHz * is not a valid clock combination * - \ref NVML_ERROR_NO_PERMISSION if the user doesn't have permission to perform this operation * - \ref NVML_ERROR_NOT_SUPPORTED if the device doesn't support this feature * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlDeviceSetGpuLockedClocks(nvmlDevice_t device, unsigned int minGpuClockMHz, unsigned int maxGpuClockMHz); /** * Resets the gpu clock to the default value * * This is the gpu clock that will be used after system reboot or driver reload. * Default values are idle clocks, but the current values can be changed using \ref nvmlDeviceSetApplicationsClocks. * * @see nvmlDeviceSetGpuLockedClocks * * For newer than Pascal &tm; fully supported devices. * * @param device The identifier of the target device * * @return * - \ref NVML_SUCCESS if new settings were successfully set * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlDeviceResetGpuLockedClocks(nvmlDevice_t device); /** * Set clocks that applications will lock to. * * Sets the clocks that compute and graphics applications will be running at. * e.g. CUDA driver requests these clocks during context creation which means this property * defines clocks at which CUDA applications will be running unless some overspec event * occurs (e.g. over power, over thermal or external HW brake). * * Can be used as a setting to request constant performance. * * On Pascal and newer hardware, this will automatically disable automatic boosting of clocks. * * On K80 and newer Kepler and Maxwell GPUs, users desiring fixed performance should also call * \ref nvmlDeviceSetAutoBoostedClocksEnabled to prevent clocks from automatically boosting * above the clock value being set. * * For Kepler &tm; or newer non-GeForce fully supported devices and Maxwell or newer GeForce devices. * Requires root/admin permissions. * * See \ref nvmlDeviceGetSupportedMemoryClocks and \ref nvmlDeviceGetSupportedGraphicsClocks * for details on how to list available clocks combinations. * * After system reboot or driver reload applications clocks go back to their default value. * See \ref nvmlDeviceResetApplicationsClocks. * * @param device The identifier of the target device * @param memClockMHz Requested memory clock in MHz * @param graphicsClockMHz Requested graphics clock in MHz * * @return * - \ref NVML_SUCCESS if new settings were successfully set * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a memClockMHz and \a graphicsClockMHz * is not a valid clock combination * - \ref NVML_ERROR_NO_PERMISSION if the user doesn't have permission to perform this operation * - \ref NVML_ERROR_NOT_SUPPORTED if the device doesn't support this feature * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlDeviceSetApplicationsClocks(nvmlDevice_t device, unsigned int memClockMHz, unsigned int graphicsClockMHz); /** * Set new power limit of this device. * * For Kepler &tm; or newer fully supported devices. * Requires root/admin permissions. * * See \ref nvmlDeviceGetPowerManagementLimitConstraints to check the allowed ranges of values. * * \note Limit is not persistent across reboots or driver unloads. * Enable persistent mode to prevent driver from unloading when no application is using the device. * * @param device The identifier of the target device * @param limit Power management limit in milliwatts to set * * @return * - \ref NVML_SUCCESS if \a limit has been set * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a defaultLimit is out of range * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible * - \ref NVML_ERROR_UNKNOWN on any unexpected error * * @see nvmlDeviceGetPowerManagementLimitConstraints * @see nvmlDeviceGetPowerManagementDefaultLimit */ nvmlReturn_t DECLDIR nvmlDeviceSetPowerManagementLimit(nvmlDevice_t device, unsigned int limit); /** * Sets new GOM. See \a nvmlGpuOperationMode_t for details. * * For GK110 M-class and X-class Tesla &tm; products from the Kepler family. * Modes \ref NVML_GOM_LOW_DP and \ref NVML_GOM_ALL_ON are supported on fully supported GeForce products. * Not supported on Quadro ® and Tesla &tm; C-class products. * Requires root/admin permissions. * * Changing GOMs requires a reboot. * The reboot requirement might be removed in the future. * * Compute only GOMs don't support graphics acceleration. Under windows switching to these GOMs when * pending driver model is WDDM is not supported. See \ref nvmlDeviceSetDriverModel. * * @param device The identifier of the target device * @param mode Target GOM * * @return * - \ref NVML_SUCCESS if \a mode has been set * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a mode incorrect * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support GOM or specific mode * - \ref NVML_ERROR_NO_PERMISSION if the user doesn't have permission to perform this operation * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible * - \ref NVML_ERROR_UNKNOWN on any unexpected error * * @see nvmlGpuOperationMode_t * @see nvmlDeviceGetGpuOperationMode */ nvmlReturn_t DECLDIR nvmlDeviceSetGpuOperationMode(nvmlDevice_t device, nvmlGpuOperationMode_t mode); /** * Changes the root/admin restructions on certain APIs. See \a nvmlRestrictedAPI_t for the list of supported APIs. * This method can be used by a root/admin user to give non-root/admin access to certain otherwise-restricted APIs. * The new setting lasts for the lifetime of the NVIDIA driver; it is not persistent. See \a nvmlDeviceGetAPIRestriction * to query the current restriction settings. * * For Kepler &tm; or newer fully supported devices. * Requires root/admin permissions. * * @param device The identifier of the target device * @param apiType Target API type for this operation * @param isRestricted The target restriction * * @return * - \ref NVML_SUCCESS if \a isRestricted has been set * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a apiType incorrect * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support changing API restrictions or the device does not support * the feature that api restrictions are being set for (E.G. Enabling/disabling auto * boosted clocks is not supported by the device) * - \ref NVML_ERROR_NO_PERMISSION if the user doesn't have permission to perform this operation * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible * - \ref NVML_ERROR_UNKNOWN on any unexpected error * * @see nvmlRestrictedAPI_t */ nvmlReturn_t DECLDIR nvmlDeviceSetAPIRestriction(nvmlDevice_t device, nvmlRestrictedAPI_t apiType, nvmlEnableState_t isRestricted); /** * @} */ /** @addtogroup nvmlAccountingStats * @{ */ /** * Enables or disables per process accounting. * * For Kepler &tm; or newer fully supported devices. * Requires root/admin permissions. * * @note This setting is not persistent and will default to disabled after driver unloads. * Enable persistence mode to be sure the setting doesn't switch off to disabled. * * @note Enabling accounting mode has no negative impact on the GPU performance. * * @note Disabling accounting clears all accounting pids information. * * See \ref nvmlDeviceGetAccountingMode * See \ref nvmlDeviceGetAccountingStats * See \ref nvmlDeviceClearAccountingPids * * @param device The identifier of the target device * @param mode The target accounting mode * * @return * - \ref NVML_SUCCESS if the new mode has been set * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device or \a mode are invalid * - \ref NVML_ERROR_NOT_SUPPORTED if the device doesn't support this feature * - \ref NVML_ERROR_NO_PERMISSION if the user doesn't have permission to perform this operation * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlDeviceSetAccountingMode(nvmlDevice_t device, nvmlEnableState_t mode); /** * Clears accounting information about all processes that have already terminated. * * For Kepler &tm; or newer fully supported devices. * Requires root/admin permissions. * * See \ref nvmlDeviceGetAccountingMode * See \ref nvmlDeviceGetAccountingStats * See \ref nvmlDeviceSetAccountingMode * * @param device The identifier of the target device * * @return * - \ref NVML_SUCCESS if accounting information has been cleared * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device are invalid * - \ref NVML_ERROR_NOT_SUPPORTED if the device doesn't support this feature * - \ref NVML_ERROR_NO_PERMISSION if the user doesn't have permission to perform this operation * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlDeviceClearAccountingPids(nvmlDevice_t device); /** @} */ /***************************************************************************************************/ /** @defgroup NvLink NvLink Methods * This chapter describes methods that NVML can perform on NVLINK enabled devices. * @{ */ /***************************************************************************************************/ /** * Retrieves the state of the device's NvLink for the link specified * * For Pascal &tm; or newer fully supported devices. * * @param device The identifier of the target device * @param link Specifies the NvLink link to be queried * @param isActive \a nvmlEnableState_t where NVML_FEATURE_ENABLED indicates that * the link is active and NVML_FEATURE_DISABLED indicates it * is inactive * * @return * - \ref NVML_SUCCESS if \a isActive has been set * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device or \a link is invalid or \a isActive is NULL * - \ref NVML_ERROR_NOT_SUPPORTED if the device doesn't support this feature * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlDeviceGetNvLinkState(nvmlDevice_t device, unsigned int link, nvmlEnableState_t *isActive); /** * Retrieves the version of the device's NvLink for the link specified * * For Pascal &tm; or newer fully supported devices. * * @param device The identifier of the target device * @param link Specifies the NvLink link to be queried * @param version Requested NvLink version * * @return * - \ref NVML_SUCCESS if \a version has been set * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device or \a link is invalid or \a version is NULL * - \ref NVML_ERROR_NOT_SUPPORTED if the device doesn't support this feature * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlDeviceGetNvLinkVersion(nvmlDevice_t device, unsigned int link, unsigned int *version); /** * Retrieves the requested capability from the device's NvLink for the link specified * Please refer to the \a nvmlNvLinkCapability_t structure for the specific caps that can be queried * The return value should be treated as a boolean. * * For Pascal &tm; or newer fully supported devices. * * @param device The identifier of the target device * @param link Specifies the NvLink link to be queried * @param capability Specifies the \a nvmlNvLinkCapability_t to be queried * @param capResult A boolean for the queried capability indicating that feature is available * * @return * - \ref NVML_SUCCESS if \a capResult has been set * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device, \a link, or \a capability is invalid or \a capResult is NULL * - \ref NVML_ERROR_NOT_SUPPORTED if the device doesn't support this feature * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlDeviceGetNvLinkCapability(nvmlDevice_t device, unsigned int link, nvmlNvLinkCapability_t capability, unsigned int *capResult); /** * Retrieves the PCI information for the remote node on a NvLink link * Note: pciSubSystemId is not filled in this function and is indeterminate * * For Pascal &tm; or newer fully supported devices. * * @param device The identifier of the target device * @param link Specifies the NvLink link to be queried * @param pci \a nvmlPciInfo_t of the remote node for the specified link * * @return * - \ref NVML_SUCCESS if \a pci has been set * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device or \a link is invalid or \a pci is NULL * - \ref NVML_ERROR_NOT_SUPPORTED if the device doesn't support this feature * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlDeviceGetNvLinkRemotePciInfo(nvmlDevice_t device, unsigned int link, nvmlPciInfo_t *pci); /** * Retrieves the specified error counter value * Please refer to \a nvmlNvLinkErrorCounter_t for error counters that are available * * For Pascal &tm; or newer fully supported devices. * * @param device The identifier of the target device * @param link Specifies the NvLink link to be queried * @param counter Specifies the NvLink counter to be queried * @param counterValue Returned counter value * * @return * - \ref NVML_SUCCESS if \a counter has been set * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device, \a link, or \a counter is invalid or \a counterValue is NULL * - \ref NVML_ERROR_NOT_SUPPORTED if the device doesn't support this feature * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlDeviceGetNvLinkErrorCounter(nvmlDevice_t device, unsigned int link, nvmlNvLinkErrorCounter_t counter, unsigned long long *counterValue); /** * Resets all error counters to zero * Please refer to \a nvmlNvLinkErrorCounter_t for the list of error counters that are reset * * For Pascal &tm; or newer fully supported devices. * * @param device The identifier of the target device * @param link Specifies the NvLink link to be queried * * @return * - \ref NVML_SUCCESS if the reset is successful * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device or \a link is invalid * - \ref NVML_ERROR_NOT_SUPPORTED if the device doesn't support this feature * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlDeviceResetNvLinkErrorCounters(nvmlDevice_t device, unsigned int link); /** * Set the NVLINK utilization counter control information for the specified counter, 0 or 1. * Please refer to \a nvmlNvLinkUtilizationControl_t for the structure definition. Performs a reset * of the counters if the reset parameter is non-zero. * * For Pascal &tm; or newer fully supported devices. * * @param device The identifier of the target device * @param counter Specifies the counter that should be set (0 or 1). * @param link Specifies the NvLink link to be queried * @param control A reference to the \a nvmlNvLinkUtilizationControl_t to set * @param reset Resets the counters on set if non-zero * * @return * - \ref NVML_SUCCESS if the control has been set successfully * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device, \a counter, \a link, or \a control is invalid * - \ref NVML_ERROR_NOT_SUPPORTED if the device doesn't support this feature * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlDeviceSetNvLinkUtilizationControl(nvmlDevice_t device, unsigned int link, unsigned int counter, nvmlNvLinkUtilizationControl_t *control, unsigned int reset); /** * Get the NVLINK utilization counter control information for the specified counter, 0 or 1. * Please refer to \a nvmlNvLinkUtilizationControl_t for the structure definition * * For Pascal &tm; or newer fully supported devices. * * @param device The identifier of the target device * @param counter Specifies the counter that should be set (0 or 1). * @param link Specifies the NvLink link to be queried * @param control A reference to the \a nvmlNvLinkUtilizationControl_t to place information * * @return * - \ref NVML_SUCCESS if the control has been set successfully * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device, \a counter, \a link, or \a control is invalid * - \ref NVML_ERROR_NOT_SUPPORTED if the device doesn't support this feature * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlDeviceGetNvLinkUtilizationControl(nvmlDevice_t device, unsigned int link, unsigned int counter, nvmlNvLinkUtilizationControl_t *control); /** * Retrieve the NVLINK utilization counter based on the current control for a specified counter. * In general it is good practice to use \a nvmlDeviceSetNvLinkUtilizationControl * before reading the utilization counters as they have no default state * * For Pascal &tm; or newer fully supported devices. * * @param device The identifier of the target device * @param link Specifies the NvLink link to be queried * @param counter Specifies the counter that should be read (0 or 1). * @param rxcounter Receive counter return value * @param txcounter Transmit counter return value * * @return * - \ref NVML_SUCCESS if \a rxcounter and \a txcounter have been successfully set * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device, \a counter, or \a link is invalid or \a rxcounter or \a txcounter are NULL * - \ref NVML_ERROR_NOT_SUPPORTED if the device doesn't support this feature * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlDeviceGetNvLinkUtilizationCounter(nvmlDevice_t device, unsigned int link, unsigned int counter, unsigned long long *rxcounter, unsigned long long *txcounter); /** * Freeze the NVLINK utilization counters * Both the receive and transmit counters are operated on by this function * * For Pascal &tm; or newer fully supported devices. * * @param device The identifier of the target device * @param link Specifies the NvLink link to be queried * @param counter Specifies the counter that should be frozen (0 or 1). * @param freeze NVML_FEATURE_ENABLED = freeze the receive and transmit counters * NVML_FEATURE_DISABLED = unfreeze the receive and transmit counters * * @return * - \ref NVML_SUCCESS if counters were successfully frozen or unfrozen * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device, \a link, \a counter, or \a freeze is invalid * - \ref NVML_ERROR_NOT_SUPPORTED if the device doesn't support this feature * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlDeviceFreezeNvLinkUtilizationCounter (nvmlDevice_t device, unsigned int link, unsigned int counter, nvmlEnableState_t freeze); /** * Reset the NVLINK utilization counters * Both the receive and transmit counters are operated on by this function * * For Pascal &tm; or newer fully supported devices. * * @param device The identifier of the target device * @param link Specifies the NvLink link to be reset * @param counter Specifies the counter that should be reset (0 or 1) * * @return * - \ref NVML_SUCCESS if counters were successfully reset * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device, \a link, or \a counter is invalid * - \ref NVML_ERROR_NOT_SUPPORTED if the device doesn't support this feature * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlDeviceResetNvLinkUtilizationCounter (nvmlDevice_t device, unsigned int link, unsigned int counter); /** @} */ /***************************************************************************************************/ /** @defgroup nvmlEvents Event Handling Methods * This chapter describes methods that NVML can perform against each device to register and wait for * some event to occur. * @{ */ /***************************************************************************************************/ /** * Create an empty set of events. * Event set should be freed by \ref nvmlEventSetFree * * For Fermi &tm; or newer fully supported devices. * @param set Reference in which to return the event handle * * @return * - \ref NVML_SUCCESS if the event has been set * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a set is NULL * - \ref NVML_ERROR_UNKNOWN on any unexpected error * * @see nvmlEventSetFree */ nvmlReturn_t DECLDIR nvmlEventSetCreate(nvmlEventSet_t *set); /** * Starts recording of events on a specified devices and add the events to specified \ref nvmlEventSet_t * * For Fermi &tm; or newer fully supported devices. * Ecc events are available only on ECC enabled devices (see \ref nvmlDeviceGetTotalEccErrors) * Power capping events are available only on Power Management enabled devices (see \ref nvmlDeviceGetPowerManagementMode) * * For Linux only. * * \b IMPORTANT: Operations on \a set are not thread safe * * This call starts recording of events on specific device. * All events that occurred before this call are not recorded. * Checking if some event occurred can be done with \ref nvmlEventSetWait * * If function reports NVML_ERROR_UNKNOWN, event set is in undefined state and should be freed. * If function reports NVML_ERROR_NOT_SUPPORTED, event set can still be used. None of the requested eventTypes * are registered in that case. * * @param device The identifier of the target device * @param eventTypes Bitmask of \ref nvmlEventType to record * @param set Set to which add new event types * * @return * - \ref NVML_SUCCESS if the event has been set * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a eventTypes is invalid or \a set is NULL * - \ref NVML_ERROR_NOT_SUPPORTED if the platform does not support this feature or some of requested event types * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible * - \ref NVML_ERROR_UNKNOWN on any unexpected error * * @see nvmlEventType * @see nvmlDeviceGetSupportedEventTypes * @see nvmlEventSetWait * @see nvmlEventSetFree */ nvmlReturn_t DECLDIR nvmlDeviceRegisterEvents(nvmlDevice_t device, unsigned long long eventTypes, nvmlEventSet_t set); /** * Returns information about events supported on device * * For Fermi &tm; or newer fully supported devices. * * Events are not supported on Windows. So this function returns an empty mask in \a eventTypes on Windows. * * @param device The identifier of the target device * @param eventTypes Reference in which to return bitmask of supported events * * @return * - \ref NVML_SUCCESS if the eventTypes has been set * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a eventType is NULL * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible * - \ref NVML_ERROR_UNKNOWN on any unexpected error * * @see nvmlEventType * @see nvmlDeviceRegisterEvents */ nvmlReturn_t DECLDIR nvmlDeviceGetSupportedEventTypes(nvmlDevice_t device, unsigned long long *eventTypes); /** * Waits on events and delivers events * * For Fermi &tm; or newer fully supported devices. * * If some events are ready to be delivered at the time of the call, function returns immediately. * If there are no events ready to be delivered, function sleeps till event arrives * but not longer than specified timeout. This function in certain conditions can return before * specified timeout passes (e.g. when interrupt arrives) * * In case of xid error, the function returns the most recent xid error type seen by the system. If there are multiple * xid errors generated before nvmlEventSetWait is invoked then the last seen xid error type is returned for all * xid error events. * * @param set Reference to set of events to wait on * @param data Reference in which to return event data * @param timeoutms Maximum amount of wait time in milliseconds for registered event * * @return * - \ref NVML_SUCCESS if the data has been set * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a data is NULL * - \ref NVML_ERROR_TIMEOUT if no event arrived in specified timeout or interrupt arrived * - \ref NVML_ERROR_GPU_IS_LOST if a GPU has fallen off the bus or is otherwise inaccessible * - \ref NVML_ERROR_UNKNOWN on any unexpected error * * @see nvmlEventType * @see nvmlDeviceRegisterEvents */ nvmlReturn_t DECLDIR nvmlEventSetWait(nvmlEventSet_t set, nvmlEventData_t * data, unsigned int timeoutms); /** * Releases events in the set * * For Fermi &tm; or newer fully supported devices. * * @param set Reference to events to be released * * @return * - \ref NVML_SUCCESS if the event has been successfully released * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_UNKNOWN on any unexpected error * * @see nvmlDeviceRegisterEvents */ nvmlReturn_t DECLDIR nvmlEventSetFree(nvmlEventSet_t set); /** @} */ /***************************************************************************************************/ /** @defgroup nvmlZPI Drain states * This chapter describes methods that NVML can perform against each device to control their drain state * and recognition by NVML and NVIDIA kernel driver. These methods can be used with out-of-band tools to * power on/off GPUs, enable robust reset scenarios, etc. * @{ */ /***************************************************************************************************/ /** * Modify the drain state of a GPU. This method forces a GPU to no longer accept new incoming requests. * Any new NVML process will no longer see this GPU. Persistence mode for this GPU must be turned off before * this call is made. * Must be called as administrator. * For Linux only. * * For Pascal &tm; or newer fully supported devices. * Some Kepler devices supported. * * @param pciInfo The PCI address of the GPU drain state to be modified * @param newState The drain state that should be entered, see \ref nvmlEnableState_t * * @return * - \ref NVML_SUCCESS if counters were successfully reset * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a nvmlIndex or \a newState is invalid * - \ref NVML_ERROR_NOT_SUPPORTED if the device doesn't support this feature * - \ref NVML_ERROR_NO_PERMISSION if the calling process has insufficient permissions to perform operation * - \ref NVML_ERROR_IN_USE if the device has persistence mode turned on * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlDeviceModifyDrainState (nvmlPciInfo_t *pciInfo, nvmlEnableState_t newState); /** * Query the drain state of a GPU. This method is used to check if a GPU is in a currently draining * state. * For Linux only. * * For Pascal &tm; or newer fully supported devices. * Some Kepler devices supported. * * @param pciInfo The PCI address of the GPU drain state to be queried * @param currentState The current drain state for this GPU, see \ref nvmlEnableState_t * * @return * - \ref NVML_SUCCESS if counters were successfully reset * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a nvmlIndex or \a currentState is invalid * - \ref NVML_ERROR_NOT_SUPPORTED if the device doesn't support this feature * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlDeviceQueryDrainState (nvmlPciInfo_t *pciInfo, nvmlEnableState_t *currentState); /** * This method will remove the specified GPU from the view of both NVML and the NVIDIA kernel driver * as long as no other processes are attached. If other processes are attached, this call will return * NVML_ERROR_IN_USE and the GPU will be returned to its original "draining" state. Note: the * only situation where a process can still be attached after nvmlDeviceModifyDrainState() is called * to initiate the draining state is if that process was using, and is still using, a GPU before the * call was made. Also note, persistence mode counts as an attachment to the GPU thus it must be disabled * prior to this call. * * For long-running NVML processes please note that this will change the enumeration of current GPUs. * For example, if there are four GPUs present and GPU1 is removed, the new enumeration will be 0-2. * Also, device handles after the removed GPU will not be valid and must be re-established. * Must be run as administrator. * For Linux only. * * For Pascal &tm; or newer fully supported devices. * Some Kepler devices supported. * * @param pciInfo The PCI address of the GPU to be removed * @param gpuState Whether the GPU is to be removed, from the OS * see \ref nvmlDetachGpuState_t * @param linkState Requested upstream PCIe link state, see \ref nvmlPcieLinkState_t * * @return * - \ref NVML_SUCCESS if counters were successfully reset * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a nvmlIndex is invalid * - \ref NVML_ERROR_NOT_SUPPORTED if the device doesn't support this feature * - \ref NVML_ERROR_IN_USE if the device is still in use and cannot be removed */ nvmlReturn_t DECLDIR nvmlDeviceRemoveGpu (nvmlPciInfo_t *pciInfo, nvmlDetachGpuState_t gpuState, nvmlPcieLinkState_t linkState); /** * Request the OS and the NVIDIA kernel driver to rediscover a portion of the PCI subsystem looking for GPUs that * were previously removed. The portion of the PCI tree can be narrowed by specifying a domain, bus, and device. * If all are zeroes then the entire PCI tree will be searched. Please note that for long-running NVML processes * the enumeration will change based on how many GPUs are discovered and where they are inserted in bus order. * * In addition, all newly discovered GPUs will be initialized and their ECC scrubbed which may take several seconds * per GPU. Also, all device handles are no longer guaranteed to be valid post discovery. * * Must be run as administrator. * For Linux only. * * For Pascal &tm; or newer fully supported devices. * Some Kepler devices supported. * * @param pciInfo The PCI tree to be searched. Only the domain, bus, and device * fields are used in this call. * * @return * - \ref NVML_SUCCESS if counters were successfully reset * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a pciInfo is invalid * - \ref NVML_ERROR_NOT_SUPPORTED if the operating system does not support this feature * - \ref NVML_ERROR_OPERATING_SYSTEM if the operating system is denying this feature * - \ref NVML_ERROR_NO_PERMISSION if the calling process has insufficient permissions to perform operation * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlDeviceDiscoverGpus (nvmlPciInfo_t *pciInfo); /** @} */ /***************************************************************************************************/ /** @defgroup nvmlFieldValueQueries Field Value Queries * This chapter describes NVML operations that are associated with retrieving Field Values from NVML * @{ */ /***************************************************************************************************/ /** * Request values for a list of fields for a device. This API allows multiple fields to be queried at once. * If any of the underlying fieldIds are populated by the same driver call, the results for those field IDs * will be populated from a single call rather than making a driver call for each fieldId. * * @param device The device handle of the GPU to request field values for * @param valuesCount Number of entries in values that should be retrieved * @param values Array of \a valuesCount structures to hold field values. * Each value's fieldId must be populated prior to this call * * @return * - \ref NVML_SUCCESS if any values in \a values were populated. Note that you must * check the nvmlReturn field of each value for each individual * status * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a values is NULL */ nvmlReturn_t DECLDIR nvmlDeviceGetFieldValues(nvmlDevice_t device, int valuesCount, nvmlFieldValue_t *values); /** @} */ /***************************************************************************************************/ /** @defgroup gridVirtual GRID Virtualization Enums, Constants and Structs * @{ */ /** @} */ /***************************************************************************************************/ /***************************************************************************************************/ /** @defgroup nvmlGridQueries GRID Virtualization APIs * This chapter describes operations that are associated with NVIDIA GRID products. * @{ */ /***************************************************************************************************/ /** * This method is used to get the virtualization mode corresponding to the GPU. * * For Kepler &tm; or newer fully supported devices. * * @param device Identifier of the target device * @param pVirtualMode Reference to virtualization mode. One of NVML_GPU_VIRTUALIZATION_? * * @return * - \ref NVML_SUCCESS if \a pVirtualMode is fetched * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a pVirtualMode is NULL * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlDeviceGetVirtualizationMode(nvmlDevice_t device, nvmlGpuVirtualizationMode_t *pVirtualMode); /** * Queries if SR-IOV host operation is supported on a vGPU supported device. * * Checks whether SR-IOV host capability is supported by the device and the * driver, and indicates device is in SR-IOV mode if both of these conditions * are true. * * @param device The identifier of the target device * @param pHostVgpuMode Reference in which to return the current vGPU mode * * @return * - \ref NVML_SUCCESS if device's vGPU mode has been successfully retrieved * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device handle is 0 or \a pVgpuMode is NULL * - \ref NVML_ERROR_NOT_SUPPORTED if \a device doesn't support this feature. * - \ref NVML_ERROR_UNKNOWN if any unexpected error occurred */ nvmlReturn_t DECLDIR nvmlDeviceGetHostVgpuMode(nvmlDevice_t device, nvmlHostVgpuMode_t *pHostVgpuMode); /** * This method is used to set the virtualization mode corresponding to the GPU. * * For Kepler &tm; or newer fully supported devices. * * @param device Identifier of the target device * @param virtualMode virtualization mode. One of NVML_GPU_VIRTUALIZATION_? * * @return * - \ref NVML_SUCCESS if \a pVirtualMode is set * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid or \a pVirtualMode is NULL * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible * - \ref NVML_ERROR_NOT_SUPPORTED if setting of virtualization mode is not supported. * - \ref NVML_ERROR_NO_PERMISSION if setting of virtualization mode is not allowed for this client. */ nvmlReturn_t DECLDIR nvmlDeviceSetVirtualizationMode(nvmlDevice_t device, nvmlGpuVirtualizationMode_t virtualMode); /** * Retrieve the GRID licensable features. * * Identifies whether the system supports GRID Software Licensing. If it does, return the list of licensable feature(s) * and their current license status. * * @param device Identifier of the target device * @param pGridLicensableFeatures Pointer to structure in which GRID licensable features are returned * * @return * - \ref NVML_SUCCESS if licensable features are successfully retrieved * - \ref NVML_ERROR_INVALID_ARGUMENT if \a pGridLicensableFeatures is NULL * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlDeviceGetGridLicensableFeatures(nvmlDevice_t device, nvmlGridLicensableFeatures_t *pGridLicensableFeatures); /** * Retrieves the current utilization and process ID * * For Maxwell &tm; or newer fully supported devices. * * Reads recent utilization of GPU SM (3D/Compute), framebuffer, video encoder, and video decoder for processes running. * Utilization values are returned as an array of utilization sample structures in the caller-supplied buffer pointed at * by \a utilization. One utilization sample structure is returned per process running, that had some non-zero utilization * during the last sample period. It includes the CPU timestamp at which the samples were recorded. Individual utilization values * are returned as "unsigned int" values. * * To read utilization values, first determine the size of buffer required to hold the samples by invoking the function with * \a utilization set to NULL. The caller should allocate a buffer of size * processSamplesCount * sizeof(nvmlProcessUtilizationSample_t). Invoke the function again with the allocated buffer passed * in \a utilization, and \a processSamplesCount set to the number of entries the buffer is sized for. * * On successful return, the function updates \a processSamplesCount with the number of process utilization sample * structures that were actually written. This may differ from a previously read value as instances are created or * destroyed. * * lastSeenTimeStamp represents the CPU timestamp in microseconds at which utilization samples were last read. Set it to 0 * to read utilization based on all the samples maintained by the driver's internal sample buffer. Set lastSeenTimeStamp * to a timeStamp retrieved from a previous query to read utilization since the previous query. * * @param device The identifier of the target device * @param utilization Pointer to caller-supplied buffer in which guest process utilization samples are returned * @param processSamplesCount Pointer to caller-supplied array size, and returns number of processes running * @param lastSeenTimeStamp Return only samples with timestamp greater than lastSeenTimeStamp. * @return * - \ref NVML_SUCCESS if \a utilization has been populated * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, \a utilization is NULL, or \a samplingPeriodUs is NULL * - \ref NVML_ERROR_NOT_SUPPORTED if the device does not support this feature * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlDeviceGetProcessUtilization(nvmlDevice_t device, nvmlProcessUtilizationSample_t *utilization, unsigned int *processSamplesCount, unsigned long long lastSeenTimeStamp); /** @} */ /***************************************************************************************************/ /** @defgroup nvmlVgpu GRID vGPU Management * @{ * * This chapter describes APIs supporting NVIDIA GRID vGPU */ /***************************************************************************************************/ /** * Retrieve the supported vGPU types on a physical GPU (device). * * An array of supported vGPU types for the physical GPU indicated by \a device is returned in the caller-supplied buffer * pointed at by \a vgpuTypeIds. The element count of nvmlVgpuTypeId_t array is passed in \a vgpuCount, and \a vgpuCount * is used to return the number of vGPU types written to the buffer. * * If the supplied buffer is not large enough to accomodate the vGPU type array, the function returns * NVML_ERROR_INSUFFICIENT_SIZE, with the element count of nvmlVgpuTypeId_t array required in \a vgpuCount. * To query the number of vGPU types supported for the GPU, call this function with *vgpuCount = 0. * The code will return NVML_ERROR_INSUFFICIENT_SIZE, or NVML_SUCCESS if no vGPU types are supported. * * @param device The identifier of the target device * @param vgpuCount Pointer to caller-supplied array size, and returns number of vGPU types * @param vgpuTypeIds Pointer to caller-supplied array in which to return list of vGPU types * * @return * - \ref NVML_SUCCESS successful completion * - \ref NVML_ERROR_INSUFFICIENT_SIZE \a vgpuTypeIds buffer is too small, array element count is returned in \a vgpuCount * - \ref NVML_ERROR_INVALID_ARGUMENT if \a vgpuCount is NULL or \a device is invalid * - \ref NVML_ERROR_NOT_SUPPORTED if vGPU is not supported by the device * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlDeviceGetSupportedVgpus(nvmlDevice_t device, unsigned int *vgpuCount, nvmlVgpuTypeId_t *vgpuTypeIds); /** * Retrieve the currently creatable vGPU types on a physical GPU (device). * * An array of creatable vGPU types for the physical GPU indicated by \a device is returned in the caller-supplied buffer * pointed at by \a vgpuTypeIds. The element count of nvmlVgpuTypeId_t array is passed in \a vgpuCount, and \a vgpuCount * is used to return the number of vGPU types written to the buffer. * * The creatable vGPU types for a device may differ over time, as there may be restrictions on what type of vGPU types * can concurrently run on a device. For example, if only one vGPU type is allowed at a time on a device, then the creatable * list will be restricted to whatever vGPU type is already running on the device. * * If the supplied buffer is not large enough to accomodate the vGPU type array, the function returns * NVML_ERROR_INSUFFICIENT_SIZE, with the element count of nvmlVgpuTypeId_t array required in \a vgpuCount. * To query the number of vGPU types createable for the GPU, call this function with *vgpuCount = 0. * The code will return NVML_ERROR_INSUFFICIENT_SIZE, or NVML_SUCCESS if no vGPU types are creatable. * * @param device The identifier of the target device * @param vgpuCount Pointer to caller-supplied array size, and returns number of vGPU types * @param vgpuTypeIds Pointer to caller-supplied array in which to return list of vGPU types * * @return * - \ref NVML_SUCCESS successful completion * - \ref NVML_ERROR_INSUFFICIENT_SIZE \a vgpuTypeIds buffer is too small, array element count is returned in \a vgpuCount * - \ref NVML_ERROR_INVALID_ARGUMENT if \a vgpuCount is NULL * - \ref NVML_ERROR_NOT_SUPPORTED if vGPU is not supported by the device * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlDeviceGetCreatableVgpus(nvmlDevice_t device, unsigned int *vgpuCount, nvmlVgpuTypeId_t *vgpuTypeIds); /** * Retrieve the class of a vGPU type. It will not exceed 64 characters in length (including the NUL terminator). * See \ref nvmlConstants::NVML_DEVICE_NAME_BUFFER_SIZE. * * For Kepler &tm; or newer fully supported devices. * * @param vgpuTypeId Handle to vGPU type * @param vgpuTypeClass Pointer to string array to return class in * @param size Size of string * * @return * - \ref NVML_SUCCESS successful completion * - \ref NVML_ERROR_INVALID_ARGUMENT if \a vgpuTypeId is invalid, or \a vgpuTypeClass is NULL * - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a size is too small * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlVgpuTypeGetClass(nvmlVgpuTypeId_t vgpuTypeId, char *vgpuTypeClass, unsigned int *size); /** * Retrieve the vGPU type name. * * The name is an alphanumeric string that denotes a particular vGPU, e.g. GRID M60-2Q. It will not * exceed 64 characters in length (including the NUL terminator). See \ref * nvmlConstants::NVML_DEVICE_NAME_BUFFER_SIZE. * * For Kepler &tm; or newer fully supported devices. * * @param vgpuTypeId Handle to vGPU type * @param vgpuTypeName Pointer to buffer to return name * @param size Size of buffer * * @return * - \ref NVML_SUCCESS successful completion * - \ref NVML_ERROR_INVALID_ARGUMENT if \a vgpuTypeId is invalid, or \a name is NULL * - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a size is too small * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlVgpuTypeGetName(nvmlVgpuTypeId_t vgpuTypeId, char *vgpuTypeName, unsigned int *size); /** * Retrieve the device ID of a vGPU type. * * For Kepler &tm; or newer fully supported devices. * * @param vgpuTypeId Handle to vGPU type * @param deviceID Device ID and vendor ID of the device contained in single 32 bit value * @param subsystemID Subsytem ID and subsytem vendor ID of the device contained in single 32 bit value * * @return * - \ref NVML_SUCCESS successful completion * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a vgpuTypeId is invalid, or \a deviceId or \a subsystemID are NULL * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlVgpuTypeGetDeviceID(nvmlVgpuTypeId_t vgpuTypeId, unsigned long long *deviceID, unsigned long long *subsystemID); /** * Retrieve the vGPU framebuffer size in bytes. * * For Kepler &tm; or newer fully supported devices. * * @param vgpuTypeId Handle to vGPU type * @param fbSize Pointer to framebuffer size in bytes * * @return * - \ref NVML_SUCCESS successful completion * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a vgpuTypeId is invalid, or \a fbSize is NULL * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlVgpuTypeGetFramebufferSize(nvmlVgpuTypeId_t vgpuTypeId, unsigned long long *fbSize); /** * Retrieve count of vGPU's supported display heads. * * For Kepler &tm; or newer fully supported devices. * * @param vgpuTypeId Handle to vGPU type * @param numDisplayHeads Pointer to number of display heads * * @return * - \ref NVML_SUCCESS successful completion * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a vgpuTypeId is invalid, or \a numDisplayHeads is NULL * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlVgpuTypeGetNumDisplayHeads(nvmlVgpuTypeId_t vgpuTypeId, unsigned int *numDisplayHeads); /** * Retrieve vGPU display head's maximum supported resolution. * * For Kepler &tm; or newer fully supported devices. * * @param vgpuTypeId Handle to vGPU type * @param displayIndex Zero-based index of display head * @param xdim Pointer to maximum number of pixels in X dimension * @param ydim Pointer to maximum number of pixels in Y dimension * * @return * - \ref NVML_SUCCESS successful completion * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a vgpuTypeId is invalid, or \a xdim or \a ydim are NULL, or \a displayIndex * is out of range. * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlVgpuTypeGetResolution(nvmlVgpuTypeId_t vgpuTypeId, unsigned int displayIndex, unsigned int *xdim, unsigned int *ydim); /** * Retrieve license requirements for a vGPU type * * The license type and version required to run the specified vGPU type is returned as an alphanumeric string, in the form * ",", for example "GRID-Virtual-PC,2.0". If a vGPU is runnable with* more than one type of license, * the licenses are delimited by a semicolon, for example "GRID-Virtual-PC,2.0;GRID-Virtual-WS,2.0;GRID-Virtual-WS-Ext,2.0". * * The total length of the returned string will not exceed 128 characters, including the NUL terminator. * See \ref nvmlVgpuConstants::NVML_GRID_LICENSE_BUFFER_SIZE. * * For Kepler &tm; or newer fully supported devices. * * @param vgpuTypeId Handle to vGPU type * @param vgpuTypeLicenseString Pointer to buffer to return license info * @param size Size of \a vgpuTypeLicenseString buffer * * @return * - \ref NVML_SUCCESS successful completion * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a vgpuTypeId is invalid, or \a vgpuTypeLicenseString is NULL * - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a size is too small * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlVgpuTypeGetLicense(nvmlVgpuTypeId_t vgpuTypeId, char *vgpuTypeLicenseString, unsigned int size); /** * Retrieve the static frame rate limit value of the vGPU type * * For Kepler &tm; or newer fully supported devices. * * @param vgpuTypeId Handle to vGPU type * @param frameRateLimit Reference to return the frame rate limit value * @return * - \ref NVML_SUCCESS successful completion * - \ref NVML_ERROR_NOT_SUPPORTED if frame rate limiter is turned off for the vGPU type * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a vgpuTypeId is invalid, or \a frameRateLimit is NULL * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlVgpuTypeGetFrameRateLimit(nvmlVgpuTypeId_t vgpuTypeId, unsigned int *frameRateLimit); /** * Retrieve the maximum number of vGPU instances creatable on a device for given vGPU type * * For Kepler &tm; or newer fully supported devices. * * @param device The identifier of the target device * @param vgpuTypeId Handle to vGPU type * @param vgpuInstanceCount Pointer to get the max number of vGPU instances * that can be created on a deicve for given vgpuTypeId * @return * - \ref NVML_SUCCESS successful completion * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a vgpuTypeId is invalid or is not supported on target device, * or \a vgpuInstanceCount is NULL * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlVgpuTypeGetMaxInstances(nvmlDevice_t device, nvmlVgpuTypeId_t vgpuTypeId, unsigned int *vgpuInstanceCount); /** * Retrieve the maximum number of vGPU instances supported per VM for given vGPU type * * For Kepler &tm; or newer fully supported devices. * * @param vgpuTypeId Handle to vGPU type * @param vgpuInstanceCountPerVm Pointer to get the max number of vGPU instances supported per VM for given \a vgpuTypeId * @return * - \ref NVML_SUCCESS successful completion * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a vgpuTypeId is invalid, or \a vgpuInstanceCountPerVm is NULL * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlVgpuTypeGetMaxInstancesPerVm(nvmlVgpuTypeId_t vgpuTypeId, unsigned int *vgpuInstanceCountPerVm); /** * Retrieve the active vGPU instances on a device. * * An array of active vGPU instances is returned in the caller-supplied buffer pointed at by \a vgpuInstances. The * array elememt count is passed in \a vgpuCount, and \a vgpuCount is used to return the number of vGPU instances * written to the buffer. * * If the supplied buffer is not large enough to accomodate the vGPU instance array, the function returns * NVML_ERROR_INSUFFICIENT_SIZE, with the element count of nvmlVgpuInstance_t array required in \a vgpuCount. * To query the number of active vGPU instances, call this function with *vgpuCount = 0. The code will return * NVML_ERROR_INSUFFICIENT_SIZE, or NVML_SUCCESS if no vGPU Types are supported. * * For Kepler &tm; or newer fully supported devices. * * @param device The identifier of the target device * @param vgpuCount Pointer which passes in the array size as well as get * back the number of types * @param vgpuInstances Pointer to array in which to return list of vGPU instances * * @return * - \ref NVML_SUCCESS successful completion * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, or \a vgpuCount is NULL * - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a size is too small * - \ref NVML_ERROR_NOT_SUPPORTED if vGPU is not supported by the device * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlDeviceGetActiveVgpus(nvmlDevice_t device, unsigned int *vgpuCount, nvmlVgpuInstance_t *vgpuInstances); /** * Retrieve the VM ID associated with a vGPU instance. * * The VM ID is returned as a string, not exceeding 80 characters in length (including the NUL terminator). * See \ref nvmlConstants::NVML_DEVICE_UUID_BUFFER_SIZE. * * The format of the VM ID varies by platform, and is indicated by the type identifier returned in \a vmIdType. * * For Kepler &tm; or newer fully supported devices. * * @param vgpuInstance Identifier of the target vGPU instance * @param vmId Pointer to caller-supplied buffer to hold VM ID * @param size Size of buffer in bytes * @param vmIdType Pointer to hold VM ID type * * @return * - \ref NVML_SUCCESS successful completion * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a vmId or \a vmIdType is NULL, or \a vgpuInstance is 0 * - \ref NVML_ERROR_NOT_FOUND if \a vgpuInstance does not match a valid active vGPU instance on the system * - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a size is too small * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlVgpuInstanceGetVmID(nvmlVgpuInstance_t vgpuInstance, char *vmId, unsigned int size, nvmlVgpuVmIdType_t *vmIdType); /** * Retrieve the UUID of a vGPU instance. * * The UUID is a globally unique identifier associated with the vGPU, and is returned as a 5-part hexadecimal string, * not exceeding 80 characters in length (including the NULL terminator). * See \ref nvmlConstants::NVML_DEVICE_UUID_BUFFER_SIZE. * * For Kepler &tm; or newer fully supported devices. * * @param vgpuInstance Identifier of the target vGPU instance * @param uuid Pointer to caller-supplied buffer to hold vGPU UUID * @param size Size of buffer in bytes * * @return * - \ref NVML_SUCCESS successful completion * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a vgpuInstance is 0, or \a uuid is NULL * - \ref NVML_ERROR_NOT_FOUND if \a vgpuInstance does not match a valid active vGPU instance on the system * - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a size is too small * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlVgpuInstanceGetUUID(nvmlVgpuInstance_t vgpuInstance, char *uuid, unsigned int size); /** * Retrieve the NVIDIA driver version installed in the VM associated with a vGPU. * * The version is returned as an alphanumeric string in the caller-supplied buffer \a version. The length of the version * string will not exceed 80 characters in length (including the NUL terminator). * See \ref nvmlConstants::NVML_SYSTEM_DRIVER_VERSION_BUFFER_SIZE. * * nvmlVgpuInstanceGetVmDriverVersion() may be called at any time for a vGPU instance. The guest VM driver version is * returned as "Unknown" if no NVIDIA driver is installed in the VM, or the VM has not yet booted to the point where the * NVIDIA driver is loaded and initialized. * * For Kepler &tm; or newer fully supported devices. * * @param vgpuInstance Identifier of the target vGPU instance * @param version Caller-supplied buffer to return driver version string * @param length Size of \a version buffer * * @return * - \ref NVML_SUCCESS if \a version has been set * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a vgpuInstance is 0 * - \ref NVML_ERROR_NOT_FOUND if \a vgpuInstance does not match a valid active vGPU instance on the system * - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a length is too small * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlVgpuInstanceGetVmDriverVersion(nvmlVgpuInstance_t vgpuInstance, char* version, unsigned int length); /** * Retrieve the framebuffer usage in bytes. * * Framebuffer usage is the amont of vGPU framebuffer memory that is currently in use by the VM. * * For Kepler &tm; or newer fully supported devices. * * @param vgpuInstance The identifier of the target instance * @param fbUsage Pointer to framebuffer usage in bytes * * @return * - \ref NVML_SUCCESS successful completion * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a vgpuInstance is 0, or \a fbUsage is NULL * - \ref NVML_ERROR_NOT_FOUND if \a vgpuInstance does not match a valid active vGPU instance on the system * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlVgpuInstanceGetFbUsage(nvmlVgpuInstance_t vgpuInstance, unsigned long long *fbUsage); /** * Retrieve the current licensing state of the vGPU instance. * * If the vGPU is currently licensed, \a licensed is set to 1, otherwise it is set to 0. * * For Kepler &tm; or newer fully supported devices. * * @param vgpuInstance Identifier of the target vGPU instance * @param licensed Reference to return the licensing status * * @return * - \ref NVML_SUCCESS if \a licensed has been set * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a vgpuInstance is 0, or \a licensed is NULL * - \ref NVML_ERROR_NOT_FOUND if \a vgpuInstance does not match a valid active vGPU instance on the system * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlVgpuInstanceGetLicenseStatus(nvmlVgpuInstance_t vgpuInstance, unsigned int *licensed); /** * Retrieve the vGPU type of a vGPU instance. * * Returns the vGPU type ID of vgpu assigned to the vGPU instance. * * For Kepler &tm; or newer fully supported devices. * * @param vgpuInstance Identifier of the target vGPU instance * @param vgpuTypeId Reference to return the vgpuTypeId * * @return * - \ref NVML_SUCCESS if \a vgpuTypeId has been set * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a vgpuInstance is 0, or \a vgpuTypeId is NULL * - \ref NVML_ERROR_NOT_FOUND if \a vgpuInstance does not match a valid active vGPU instance on the system * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlVgpuInstanceGetType(nvmlVgpuInstance_t vgpuInstance, nvmlVgpuTypeId_t *vgpuTypeId); /** * Retrieve the frame rate limit set for the vGPU instance. * * Returns the value of the frame rate limit set for the vGPU instance * * For Kepler &tm; or newer fully supported devices. * * @param vgpuInstance Identifier of the target vGPU instance * @param frameRateLimit Reference to return the frame rate limit * * @return * - \ref NVML_SUCCESS if \a frameRateLimit has been set * - \ref NVML_ERROR_NOT_SUPPORTED if frame rate limiter is turned off for the vGPU type * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a vgpuInstance is 0, or \a frameRateLimit is NULL * - \ref NVML_ERROR_NOT_FOUND if \a vgpuInstance does not match a valid active vGPU instance on the system * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlVgpuInstanceGetFrameRateLimit(nvmlVgpuInstance_t vgpuInstance, unsigned int *frameRateLimit); /** * Retrieve the current ECC mode of vGPU instance. * * @param vgpuInstance The identifier of the target vGPU instance * @param eccMode Reference in which to return the current ECC mode * * @return * - \ref NVML_SUCCESS if the vgpuInstance's ECC mode has been successfully retrieved * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a vgpuInstance is 0, or \a mode is NULL * - \ref NVML_ERROR_NOT_FOUND if \a vgpuInstance does not match a valid active vGPU instance on the system * - \ref NVML_ERROR_NOT_SUPPORTED if the vGPU doesn't support this feature * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlVgpuInstanceGetEccMode(nvmlVgpuInstance_t vgpuInstance, nvmlEnableState_t *eccMode); /** * Retrieve the encoder capacity of a vGPU instance, as a percentage of maximum encoder capacity with valid values in the range 0-100. * * For Maxwell &tm; or newer fully supported devices. * * @param vgpuInstance Identifier of the target vGPU instance * @param encoderCapacity Reference to an unsigned int for the encoder capacity * * @return * - \ref NVML_SUCCESS if \a encoderCapacity has been retrived * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a vgpuInstance is 0, or \a encoderQueryType is invalid * - \ref NVML_ERROR_NOT_FOUND if \a vgpuInstance does not match a valid active vGPU instance on the system * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlVgpuInstanceGetEncoderCapacity(nvmlVgpuInstance_t vgpuInstance, unsigned int *encoderCapacity); /** * Set the encoder capacity of a vGPU instance, as a percentage of maximum encoder capacity with valid values in the range 0-100. * * For Maxwell &tm; or newer fully supported devices. * * @param vgpuInstance Identifier of the target vGPU instance * @param encoderCapacity Unsigned int for the encoder capacity value * * @return * - \ref NVML_SUCCESS if \a encoderCapacity has been set * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a vgpuInstance is 0, or \a encoderCapacity is out of range of 0-100. * - \ref NVML_ERROR_NOT_FOUND if \a vgpuInstance does not match a valid active vGPU instance on the system * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlVgpuInstanceSetEncoderCapacity(nvmlVgpuInstance_t vgpuInstance, unsigned int encoderCapacity); /** * Retrieves the current encoder statistics of a vGPU Instance * * For Maxwell &tm; or newer fully supported devices. * * @param vgpuInstance Identifier of the target vGPU instance * @param sessionCount Reference to an unsigned int for count of active encoder sessions * @param averageFps Reference to an unsigned int for trailing average FPS of all active sessions * @param averageLatency Reference to an unsigned int for encode latency in microseconds * * @return * - \ref NVML_SUCCESS if \a sessionCount, \a averageFps and \a averageLatency is fetched * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a sessionCount , or \a averageFps or \a averageLatency is NULL * or \a vgpuInstance is 0. * - \ref NVML_ERROR_NOT_FOUND if \a vgpuInstance does not match a valid active vGPU instance on the system * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlVgpuInstanceGetEncoderStats(nvmlVgpuInstance_t vgpuInstance, unsigned int *sessionCount, unsigned int *averageFps, unsigned int *averageLatency); /** * Retrieves information about all active encoder sessions on a vGPU Instance. * * An array of active encoder sessions is returned in the caller-supplied buffer pointed at by \a sessionInfo. The * array element count is passed in \a sessionCount, and \a sessionCount is used to return the number of sessions * written to the buffer. * * If the supplied buffer is not large enough to accomodate the active session array, the function returns * NVML_ERROR_INSUFFICIENT_SIZE, with the element count of nvmlEncoderSessionInfo_t array required in \a sessionCount. * To query the number of active encoder sessions, call this function with *sessionCount = 0. The code will return * NVML_SUCCESS with number of active encoder sessions updated in *sessionCount. * * For Maxwell &tm; or newer fully supported devices. * * @param vgpuInstance Identifier of the target vGPU instance * @param sessionCount Reference to caller supplied array size, and returns * the number of sessions. * @param sessionInfo Reference to caller supplied array in which the list * of session information us returned. * * @return * - \ref NVML_SUCCESS if \a sessionInfo is fetched * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a sessionCount is too small, array element count is returned in \a sessionCount * - \ref NVML_ERROR_INVALID_ARGUMENT if \a sessionCount is NULL, or \a vgpuInstance is 0. * - \ref NVML_ERROR_NOT_FOUND if \a vgpuInstance does not match a valid active vGPU instance on the system * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlVgpuInstanceGetEncoderSessions(nvmlVgpuInstance_t vgpuInstance, unsigned int *sessionCount, nvmlEncoderSessionInfo_t *sessionInfo); /** * Retrieves the active frame buffer capture sessions statistics of a vGPU Instance * * For Maxwell &tm; or newer fully supported devices. * * @param vgpuInstance Identifier of the target vGPU instance * @param fbcStats Reference to nvmlFBCStats_t structure contianing NvFBC stats * * @return * - \ref NVML_SUCCESS if \a fbcStats is fetched * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a vgpuInstance is 0, or \a fbcStats is NULL * - \ref NVML_ERROR_NOT_FOUND if \a vgpuInstance does not match a valid active vGPU instance on the system * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlVgpuInstanceGetFBCStats(nvmlVgpuInstance_t vgpuInstance, nvmlFBCStats_t *fbcStats); /** * Retrieves information about active frame buffer capture sessions on a vGPU Instance. * * An array of active FBC sessions is returned in the caller-supplied buffer pointed at by \a sessionInfo. The * array element count is passed in \a sessionCount, and \a sessionCount is used to return the number of sessions * written to the buffer. * * If the supplied buffer is not large enough to accomodate the active session array, the function returns * NVML_ERROR_INSUFFICIENT_SIZE, with the element count of nvmlFBCSessionInfo_t array required in \a sessionCount. * To query the number of active FBC sessions, call this function with *sessionCount = 0. The code will return * NVML_SUCCESS with number of active FBC sessions updated in *sessionCount. * * For Maxwell &tm; or newer fully supported devices. * * @note hResolution, vResolution, averageFPS and averageLatency data for a FBC session returned in \a sessionInfo may * be zero if there are no new frames captured since the session started. * * @param vgpuInstance Identifier of the target vGPU instance * @param sessionCount Reference to caller supplied array size, and returns the number of sessions. * @param sessionInfo Reference in which to return the session information * * @return * - \ref NVML_SUCCESS if \a sessionInfo is fetched * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a vgpuInstance is 0, or \a sessionCount is NULL. * - \ref NVML_ERROR_NOT_FOUND if \a vgpuInstance does not match a valid active vGPU instance on the system * - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a sessionCount is too small, array element count is returned in \a sessionCount * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlVgpuInstanceGetFBCSessions(nvmlVgpuInstance_t vgpuInstance, unsigned int *sessionCount, nvmlFBCSessionInfo_t *sessionInfo); /** @} */ /***************************************************************************************************/ /** @defgroup nvml GRID Virtualization Migration * This chapter describes operations that are associated with vGPU Migration. * @{ */ /***************************************************************************************************/ /** * Structure representing range of vGPU versions. */ typedef struct nvmlVgpuVersion_st { unsigned int minVersion; //!< Minimum vGPU version. unsigned int maxVersion; //!< Maximum vGPU version. } nvmlVgpuVersion_t; /** * vGPU metadata structure. */ typedef struct nvmlVgpuMetadata_st { unsigned int version; //!< Current version of the structure unsigned int revision; //!< Current revision of the structure nvmlVgpuGuestInfoState_t guestInfoState; //!< Current state of Guest-dependent fields char guestDriverVersion[NVML_SYSTEM_DRIVER_VERSION_BUFFER_SIZE]; //!< Version of driver installed in guest char hostDriverVersion[NVML_SYSTEM_DRIVER_VERSION_BUFFER_SIZE]; //!< Version of driver installed in host unsigned int reserved[6]; //!< Reserved for internal use unsigned int vgpuVirtualizationCaps; //!< vGPU virtualizaion capabilities bitfileld unsigned int guestVgpuVersion; //!< vGPU version of guest driver unsigned int opaqueDataSize; //!< Size of opaque data field in bytes char opaqueData[4]; //!< Opaque data } nvmlVgpuMetadata_t; /** * Physical GPU metadata structure */ typedef struct nvmlVgpuPgpuMetadata_st { unsigned int version; //!< Current version of the structure unsigned int revision; //!< Current revision of the structure char hostDriverVersion[NVML_SYSTEM_DRIVER_VERSION_BUFFER_SIZE]; //!< Host driver version unsigned int pgpuVirtualizationCaps; //!< Pgpu virtualizaion capabilities bitfileld unsigned int reserved[5]; //!< Reserved for internal use nvmlVgpuVersion_t hostSupportedVgpuRange; //!< vGPU version range supported by host driver unsigned int opaqueDataSize; //!< Size of opaque data field in bytes char opaqueData[4]; //!< Opaque data } nvmlVgpuPgpuMetadata_t; /** * vGPU VM compatibility codes */ typedef enum nvmlVgpuVmCompatibility_enum { NVML_VGPU_VM_COMPATIBILITY_NONE = 0x0, //!< vGPU is not runnable NVML_VGPU_VM_COMPATIBILITY_COLD = 0x1, //!< vGPU is runnable from a cold / powered-off state (ACPI S5) NVML_VGPU_VM_COMPATIBILITY_HIBERNATE = 0x2, //!< vGPU is runnable from a hibernated state (ACPI S4) NVML_VGPU_VM_COMPATIBILITY_SLEEP = 0x4, //!< vGPU is runnable from a sleeped state (ACPI S3) NVML_VGPU_VM_COMPATIBILITY_LIVE = 0x8, //!< vGPU is runnable from a live/paused (ACPI S0) } nvmlVgpuVmCompatibility_t; /** * vGPU-pGPU compatibility limit codes */ typedef enum nvmlVgpuPgpuCompatibilityLimitCode_enum { NVML_VGPU_COMPATIBILITY_LIMIT_NONE = 0x0, //!< Compatibility is not limited. NVML_VGPU_COMPATIBILITY_LIMIT_HOST_DRIVER = 0x1, //!< ompatibility is limited by host driver version. NVML_VGPU_COMPATIBILITY_LIMIT_GUEST_DRIVER = 0x2, //!< Compatibility is limited by guest driver version. NVML_VGPU_COMPATIBILITY_LIMIT_GPU = 0x4, //!< Compatibility is limited by GPU hardware. NVML_VGPU_COMPATIBILITY_LIMIT_OTHER = 0x80000000, //!< Compatibility is limited by an undefined factor. } nvmlVgpuPgpuCompatibilityLimitCode_t; /** * vGPU-pGPU compatibility structure */ typedef struct nvmlVgpuPgpuCompatibility_st { nvmlVgpuVmCompatibility_t vgpuVmCompatibility; //!< Compatibility of vGPU VM. See \ref nvmlVgpuVmCompatibility_t nvmlVgpuPgpuCompatibilityLimitCode_t compatibilityLimitCode; //!< Limiting factor for vGPU-pGPU compatibility. See \ref nvmlVgpuPgpuCompatibilityLimitCode_t } nvmlVgpuPgpuCompatibility_t; /** * Returns vGPU metadata structure for a running vGPU. The structure contains information about the vGPU and its associated VM * such as the currently installed NVIDIA guest driver version, together with host driver version and an opaque data section * containing internal state. * * nvmlVgpuInstanceGetMetadata() may be called at any time for a vGPU instance. Some fields in the returned structure are * dependent on information obtained from the guest VM, which may not yet have reached a state where that information * is available. The current state of these dependent fields is reflected in the info structure's \ref nvmlVgpuGuestInfoState_t field. * * The VMM may choose to read and save the vGPU's VM info as persistent metadata associated with the VM, and provide * it to GRID Virtual GPU Manager when creating a vGPU for subsequent instances of the VM. * * The caller passes in a buffer via \a vgpuMetadata, with the size of the buffer in \a bufferSize. If the vGPU Metadata structure * is too large to fit in the supplied buffer, the function returns NVML_ERROR_INSUFFICIENT_SIZE with the size needed * in \a bufferSize. * * @param vgpuInstance vGPU instance handle * @param vgpuMetadata Pointer to caller-supplied buffer into which vGPU metadata is written * @param bufferSize Size of vgpuMetadata buffer * * @return * - \ref NVML_SUCCESS vGPU metadata structure was successfully returned * - \ref NVML_ERROR_INSUFFICIENT_SIZE vgpuMetadata buffer is too small, required size is returned in \a bufferSize * - \ref NVML_ERROR_INVALID_ARGUMENT if \a bufferSize is NULL or \a vgpuInstance is 0; if \a vgpuMetadata is NULL and the value of \a bufferSize is not 0. * - \ref NVML_ERROR_NOT_FOUND if \a vgpuInstance does not match a valid active vGPU instance on the system * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlVgpuInstanceGetMetadata(nvmlVgpuInstance_t vgpuInstance, nvmlVgpuMetadata_t *vgpuMetadata, unsigned int *bufferSize); /** * Returns a vGPU metadata structure for the physical GPU indicated by \a device. The structure contains information about * the GPU and the currently installed NVIDIA host driver version that's controlling it, together with an opaque data section * containing internal state. * * The caller passes in a buffer via \a pgpuMetadata, with the size of the buffer in \a bufferSize. If the \a pgpuMetadata * structure is too large to fit in the supplied buffer, the function returns NVML_ERROR_INSUFFICIENT_SIZE with the size needed * in \a bufferSize. * * @param device The identifier of the target device * @param pgpuMetadata Pointer to caller-supplied buffer into which \a pgpuMetadata is written * @param bufferSize Pointer to size of \a pgpuMetadata buffer * * @return * - \ref NVML_SUCCESS GPU metadata structure was successfully returned * - \ref NVML_ERROR_INSUFFICIENT_SIZE pgpuMetadata buffer is too small, required size is returned in \a bufferSize * - \ref NVML_ERROR_INVALID_ARGUMENT if \a bufferSize is NULL or \a device is invalid; if \a pgpuMetadata is NULL and the value of \a bufferSize is not 0. * - \ref NVML_ERROR_NOT_SUPPORTED vGPU is not supported by the system * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlDeviceGetVgpuMetadata(nvmlDevice_t device, nvmlVgpuPgpuMetadata_t *pgpuMetadata, unsigned int *bufferSize); /** * Takes a vGPU instance metadata structure read from \ref nvmlVgpuInstanceGetMetadata(), and a vGPU metadata structure for a * physical GPU read from \ref nvmlDeviceGetVgpuMetadata(), and returns compatibility information of the vGPU instance and the * physical GPU. * * The caller passes in a buffer via \a compatibilityInfo, into which a compatibility information structure is written. The * structure defines the states in which the vGPU / VM may be booted on the physical GPU. If the vGPU / VM compatibility * with the physical GPU is limited, a limit code indicates the factor limiting compability. * (see \ref nvmlVgpuPgpuCompatibilityLimitCode_t for details). * * Note: vGPU compatibility does not take into account dynamic capacity conditions that may limit a system's ability to * boot a given vGPU or associated VM. * * @param vgpuMetadata Pointer to caller-supplied vGPU metadata structure * @param pgpuMetadata Pointer to caller-supplied GPU metadata structure * @param compatibilityInfo Pointer to caller-supplied buffer to hold compatibility info * * @return * - \ref NVML_SUCCESS vGPU metadata structure was successfully returned * - \ref NVML_ERROR_INVALID_ARGUMENT if \a vgpuMetadata or \a pgpuMetadata or \a bufferSize are NULL * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlGetVgpuCompatibility(nvmlVgpuMetadata_t *vgpuMetadata, nvmlVgpuPgpuMetadata_t *pgpuMetadata, nvmlVgpuPgpuCompatibility_t *compatibilityInfo); /** * Returns the properties of the physical GPU indicated by the device in an ascii-encoded string format. * * The caller passes in a buffer via \a pgpuMetadata, with the size of the buffer in \a bufferSize. If the * string is too large to fit in the supplied buffer, the function returns NVML_ERROR_INSUFFICIENT_SIZE with the size needed * in \a bufferSize. * * @param device The identifier of the target device * @param pgpuMetadata Pointer to caller-supplied buffer into which \a pgpuMetadata is written * @param bufferSize Pointer to size of \a pgpuMetadata buffer * * @return * - \ref NVML_SUCCESS GPU metadata structure was successfully returned * - \ref NVML_ERROR_INSUFFICIENT_SIZE \a pgpuMetadata buffer is too small, required size is returned in \a bufferSize * - \ref NVML_ERROR_INVALID_ARGUMENT if \a bufferSize is NULL or \a device is invalid; if \a pgpuMetadata is NULL and the value of \a bufferSize is not 0. * - \ref NVML_ERROR_NOT_SUPPORTED if vGPU is not supported by the system * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlDeviceGetPgpuMetadataString(nvmlDevice_t device, char *pgpuMetadata, unsigned int *bufferSize); /* * Virtual GPU (vGPU) version * * The NVIDIA vGPU Manager and the guest drivers are tagged with a range of supported vGPU versions. This determines the range of NVIDIA guest driver versions that * are compatible for vGPU feature support with a given NVIDIA vGPU Manager. For vGPU feature support, the range of supported versions for the NVIDIA vGPU Manager * and the guest driver must overlap. Otherwise, the guest driver fails to load in the VM. * * When the NVIDIA guest driver loads, either when the VM is booted or when the driver is installed or upgraded, a negotiation occurs between the guest driver * and the NVIDIA vGPU Manager to select the highest mutually compatible vGPU version. The negotiated vGPU version stays the same across VM migration. */ /** * Query the ranges of supported vGPU versions. * * This function gets the linear range of supported vGPU versions that is preset for the NVIDIA vGPU Manager and the range set by an administrator. * If the preset range has not been overridden by \ref nvmlSetVgpuVersion, both ranges are the same. * * The caller passes pointers to the following \ref nvmlVgpuVersion_t structures, into which the NVIDIA vGPU Manager writes the ranges: * 1. \a supported structure that represents the preset range of vGPU versions supported by the NVIDIA vGPU Manager. * 2. \a current structure that represents the range of supported vGPU versions set by an administrator. By default, this range is the same as the preset range. * * @param supported Pointer to the structure in which the preset range of vGPU versions supported by the NVIDIA vGPU Manager is written * @param current Pointer to the structure in which the range of supported vGPU versions set by an administrator is written * * @return * - \ref NVML_SUCCESS The vGPU version range structures were successfully obtained. * - \ref NVML_ERROR_NOT_SUPPORTED The API is not supported. * - \ref NVML_ERROR_INVALID_ARGUMENT The \a supported parameter or the \a current parameter is NULL. * - \ref NVML_ERROR_UNKNOWN An error occurred while the data was being fetched. */ nvmlReturn_t DECLDIR nvmlGetVgpuVersion(nvmlVgpuVersion_t *supported, nvmlVgpuVersion_t *current); /** * Override the preset range of vGPU versions supported by the NVIDIA vGPU Manager with a range set by an administrator. * * This function configures the NVIDIA vGPU Manager with a range of supported vGPU versions set by an administrator. This range must be a subset of the * preset range that the NVIDIA vGPU Manager supports. The custom range set by an administrator takes precedence over the preset range and is advertised to * the guest VM for negotiating the vGPU version. See \ref nvmlGetVgpuVersion for details of how to query the preset range of versions supported. * * This function takes a pointer to vGPU version range structure \ref nvmlVgpuVersion_t as input to override the preset vGPU version range that the NVIDIA vGPU Manager supports. * * After host system reboot or driver reload, the range of supported versions reverts to the range that is preset for the NVIDIA vGPU Manager. * * @note 1. The range set by the administrator must be a subset of the preset range that the NVIDIA vGPU Manager supports. Otherwise, an error is returned. * 2. If the range of supported guest driver versions does not overlap the range set by the administrator, the guest driver fails to load. * 3. If the range of supported guest driver versions overlaps the range set by the administrator, the guest driver will load with a negotiated * vGPU version that is the maximum value in the overlapping range. * 4. No VMs must be running on the host when this function is called. If a VM is running on the host, the call to this function fails. * * @param vgpuVersion Pointer to a caller-supplied range of supported vGPU versions. * * @return * - \ref NVML_SUCCESS The preset range of supported vGPU versions was successfully overridden. * - \ref NVML_ERROR_NOT_SUPPORTED The API is not supported. * - \ref NVML_ERROR_IN_USE The range was not overridden because a VM is running on the host. * - \ref NVML_ERROR_INVALID_ARGUMENT The \a vgpuVersion parameter specifies a range that is outside the range supported by the NVIDIA vGPU Manager or if \a vgpuVersion is NULL. */ nvmlReturn_t DECLDIR nvmlSetVgpuVersion(nvmlVgpuVersion_t *vgpuVersion); /** @} */ /***************************************************************************************************/ /** @defgroup nvmlUtil GRID Virtualization Utilization and Accounting * This chapter describes operations that are associated with vGPU Utilization and Accounting. * @{ */ /***************************************************************************************************/ /** * Retrieves current utilization for vGPUs on a physical GPU (device). * * For Kepler &tm; or newer fully supported devices. * * Reads recent utilization of GPU SM (3D/Compute), framebuffer, video encoder, and video decoder for vGPU instances running * on a device. Utilization values are returned as an array of utilization sample structures in the caller-supplied buffer * pointed at by \a utilizationSamples. One utilization sample structure is returned per vGPU instance, and includes the * CPU timestamp at which the samples were recorded. Individual utilization values are returned as "unsigned int" values * in nvmlValue_t unions. The function sets the caller-supplied \a sampleValType to NVML_VALUE_TYPE_UNSIGNED_INT to * indicate the returned value type. * * To read utilization values, first determine the size of buffer required to hold the samples by invoking the function with * \a utilizationSamples set to NULL. The function will return NVML_ERROR_INSUFFICIENT_SIZE, with the current vGPU instance * count in \a vgpuInstanceSamplesCount, or NVML_SUCCESS if the current vGPU instance count is zero. The caller should allocate * a buffer of size vgpuInstanceSamplesCount * sizeof(nvmlVgpuInstanceUtilizationSample_t). Invoke the function again with * the allocated buffer passed in \a utilizationSamples, and \a vgpuInstanceSamplesCount set to the number of entries the * buffer is sized for. * * On successful return, the function updates \a vgpuInstanceSampleCount with the number of vGPU utilization sample * structures that were actually written. This may differ from a previously read value as vGPU instances are created or * destroyed. * * lastSeenTimeStamp represents the CPU timestamp in microseconds at which utilization samples were last read. Set it to 0 * to read utilization based on all the samples maintained by the driver's internal sample buffer. Set lastSeenTimeStamp * to a timeStamp retrieved from a previous query to read utilization since the previous query. * * @param device The identifier for the target device * @param lastSeenTimeStamp Return only samples with timestamp greater than lastSeenTimeStamp. * @param sampleValType Pointer to caller-supplied buffer to hold the type of returned sample values * @param vgpuInstanceSamplesCount Pointer to caller-supplied array size, and returns number of vGPU instances * @param utilizationSamples Pointer to caller-supplied buffer in which vGPU utilization samples are returned * @return * - \ref NVML_SUCCESS if utilization samples are successfully retrieved * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, \a vgpuInstanceSamplesCount or \a sampleValType is * NULL, or a sample count of 0 is passed with a non-NULL \a utilizationSamples * - \ref NVML_ERROR_INSUFFICIENT_SIZE if supplied \a vgpuInstanceSamplesCount is too small to return samples for all * vGPU instances currently executing on the device * - \ref NVML_ERROR_NOT_SUPPORTED if vGPU is not supported by the device * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible * - \ref NVML_ERROR_NOT_FOUND if sample entries are not found * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlDeviceGetVgpuUtilization(nvmlDevice_t device, unsigned long long lastSeenTimeStamp, nvmlValueType_t *sampleValType, unsigned int *vgpuInstanceSamplesCount, nvmlVgpuInstanceUtilizationSample_t *utilizationSamples); /** * Retrieves current utilization for processes running on vGPUs on a physical GPU (device). * * For Maxwell &tm; or newer fully supported devices. * * Reads recent utilization of GPU SM (3D/Compute), framebuffer, video encoder, and video decoder for processes running on * vGPU instances active on a device. Utilization values are returned as an array of utilization sample structures in the * caller-supplied buffer pointed at by \a utilizationSamples. One utilization sample structure is returned per process running * on vGPU instances, that had some non-zero utilization during the last sample period. It includes the CPU timestamp at which * the samples were recorded. Individual utilization values are returned as "unsigned int" values. * * To read utilization values, first determine the size of buffer required to hold the samples by invoking the function with * \a utilizationSamples set to NULL. The function will return NVML_ERROR_INSUFFICIENT_SIZE, with the current vGPU instance * count in \a vgpuProcessSamplesCount. The caller should allocate a buffer of size * vgpuProcessSamplesCount * sizeof(nvmlVgpuProcessUtilizationSample_t). Invoke the function again with * the allocated buffer passed in \a utilizationSamples, and \a vgpuProcessSamplesCount set to the number of entries the * buffer is sized for. * * On successful return, the function updates \a vgpuSubProcessSampleCount with the number of vGPU sub process utilization sample * structures that were actually written. This may differ from a previously read value depending on the number of processes that are active * in any given sample period. * * lastSeenTimeStamp represents the CPU timestamp in microseconds at which utilization samples were last read. Set it to 0 * to read utilization based on all the samples maintained by the driver's internal sample buffer. Set lastSeenTimeStamp * to a timeStamp retrieved from a previous query to read utilization since the previous query. * * @param device The identifier for the target device * @param lastSeenTimeStamp Return only samples with timestamp greater than lastSeenTimeStamp. * @param vgpuProcessSamplesCount Pointer to caller-supplied array size, and returns number of processes running on vGPU instances * @param utilizationSamples Pointer to caller-supplied buffer in which vGPU sub process utilization samples are returned * @return * - \ref NVML_SUCCESS if utilization samples are successfully retrieved * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a device is invalid, \a vgpuProcessSamplesCount or a sample count of 0 is * passed with a non-NULL \a utilizationSamples * - \ref NVML_ERROR_INSUFFICIENT_SIZE if supplied \a vgpuProcessSamplesCount is too small to return samples for all * vGPU instances currently executing on the device * - \ref NVML_ERROR_NOT_SUPPORTED if vGPU is not supported by the device * - \ref NVML_ERROR_GPU_IS_LOST if the target GPU has fallen off the bus or is otherwise inaccessible * - \ref NVML_ERROR_NOT_FOUND if sample entries are not found * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlDeviceGetVgpuProcessUtilization(nvmlDevice_t device, unsigned long long lastSeenTimeStamp, unsigned int *vgpuProcessSamplesCount, nvmlVgpuProcessUtilizationSample_t *utilizationSamples); /** * Queries the state of per process accounting mode on vGPU. * * For Maxwell &tm; or newer fully supported devices. * * @param vgpuInstance The identifier of the target vGPU VM * @param mode Reference in which to return the current accounting mode * * @return * - \ref NVML_SUCCESS if the mode has been successfully retrieved * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a vgpuInstance is 0, or \a mode is NULL * - \ref NVML_ERROR_NOT_FOUND if \a vgpuInstance does not match a valid active vGPU instance on the system * - \ref NVML_ERROR_NOT_SUPPORTED if the vGPU doesn't support this feature * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlVgpuInstanceGetAccountingMode(nvmlVgpuInstance_t vgpuInstance, nvmlEnableState_t *mode); /** * Queries list of processes running on vGPU that can be queried for accounting stats. The list of processes * returned can be in running or terminated state. * * For Maxwell &tm; or newer fully supported devices. * * To just query the maximum number of processes that can be queried, call this function with *count = 0 and * pids=NULL. The return code will be NVML_ERROR_INSUFFICIENT_SIZE, or NVML_SUCCESS if list is empty. * * For more details see \ref nvmlVgpuInstanceGetAccountingStats. * * @note In case of PID collision some processes might not be accessible before the circular buffer is full. * * @param vgpuInstance The identifier of the target vGPU VM * @param count Reference in which to provide the \a pids array size, and * to return the number of elements ready to be queried * @param pids Reference in which to return list of process ids * * @return * - \ref NVML_SUCCESS if pids were successfully retrieved * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a vgpuInstance is 0, or \a count is NULL * - \ref NVML_ERROR_NOT_FOUND if \a vgpuInstance does not match a valid active vGPU instance on the system * - \ref NVML_ERROR_NOT_SUPPORTED if the vGPU doesn't support this feature or accounting mode is disabled * - \ref NVML_ERROR_INSUFFICIENT_SIZE if \a count is too small (\a count is set to expected value) * - \ref NVML_ERROR_UNKNOWN on any unexpected error * * @see nvmlVgpuInstanceGetAccountingPids */ nvmlReturn_t DECLDIR nvmlVgpuInstanceGetAccountingPids(nvmlVgpuInstance_t vgpuInstance, unsigned int *count, unsigned int *pids); /** * Queries process's accounting stats. * * For Maxwell &tm; or newer fully supported devices. * * Accounting stats capture GPU utilization and other statistics across the lifetime of a process, and * can be queried during life time of the process or after its termination. * The time field in \ref nvmlAccountingStats_t is reported as 0 during the lifetime of the process and * updated to actual running time after its termination. * Accounting stats are kept in a circular buffer, newly created processes overwrite information about old * processes. * * See \ref nvmlAccountingStats_t for description of each returned metric. * List of processes that can be queried can be retrieved from \ref nvmlVgpuInstanceGetAccountingPids. * * @note Accounting Mode needs to be on. See \ref nvmlVgpuInstanceGetAccountingMode. * @note Only compute and graphics applications stats can be queried. Monitoring applications stats can't be * queried since they don't contribute to GPU utilization. * @note In case of pid collision stats of only the latest process (that terminated last) will be reported * * @param vgpuInstance The identifier of the target vGPU VM * @param pid Process Id of the target process to query stats for * @param stats Reference in which to return the process's accounting stats * * @return * - \ref NVML_SUCCESS if stats have been successfully retrieved * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a vgpuInstance is 0, or \a stats is NULL * - \ref NVML_ERROR_NOT_FOUND if \a vgpuInstance does not match a valid active vGPU instance on the system * or \a stats is not found * - \ref NVML_ERROR_NOT_SUPPORTED if the vGPU doesn't support this feature or accounting mode is disabled * - \ref NVML_ERROR_UNKNOWN on any unexpected error */ nvmlReturn_t DECLDIR nvmlVgpuInstanceGetAccountingStats(nvmlVgpuInstance_t vgpuInstance, unsigned int pid, nvmlAccountingStats_t *stats); /** @} */ /***************************************************************************************************/ /** @defgroup nvmlGpuBlacklistQueries GPU Blacklist Queries * This chapter describes NVML operations that are associated with blacklisted GPUs. * @{ */ /***************************************************************************************************/ /** * Blacklist GPU device information **/ typedef struct nvmlBlacklistDeviceInfo_st { nvmlPciInfo_t pciInfo; //!< The PCI information for the blacklisted GPU char uuid[NVML_DEVICE_UUID_BUFFER_SIZE]; //!< The ASCII string UUID for the blacklisted GPU } nvmlBlacklistDeviceInfo_t; /** * Retrieves the number of blacklisted GPU devices in the system. * * For all products. * * @param deviceCount Reference in which to return the number of blacklisted devices * * @return * - \ref NVML_SUCCESS if \a deviceCount has been set * - \ref NVML_ERROR_INVALID_ARGUMENT if \a deviceCount is NULL */ nvmlReturn_t DECLDIR nvmlGetBlacklistDeviceCount(unsigned int *deviceCount); /** * Acquire the device information for a blacklisted device, based on its index. * * For all products. * * Valid indices are derived from the \a deviceCount returned by * \ref nvmlGetBlacklistDeviceCount(). For example, if \a deviceCount is 2 the valid indices * are 0 and 1, corresponding to GPU 0 and GPU 1. * * @param index The index of the target GPU, >= 0 and < \a deviceCount * @param info Reference in which to return the device information * * @return * - \ref NVML_SUCCESS if \a device has been set * - \ref NVML_ERROR_INVALID_ARGUMENT if \a index is invalid or \a info is NULL * * @see nvmlGetBlacklistDeviceCount */ nvmlReturn_t DECLDIR nvmlGetBlacklistDeviceInfoByIndex(unsigned int index, nvmlBlacklistDeviceInfo_t *info); /** @} */ /** * NVML API versioning support */ #if defined(__NVML_API_VERSION_INTERNAL) #undef nvmlDeviceGetGridLicensableFeatures #undef nvmlDeviceRemoveGpu #undef nvmlDeviceGetNvLinkRemotePciInfo #undef nvmlDeviceGetPciInfo #undef nvmlDeviceGetCount #undef nvmlDeviceGetHandleByIndex #undef nvmlDeviceGetHandleByPciBusId #undef nvmlInit #endif #ifdef __cplusplus } #endif #endif ================================================ FILE: include/vulkan/vk_util.h ================================================ /* * Copyright © 2017 Intel Corporation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice (including the next * paragraph) shall be included in all copies or substantial portions of the * Software. * * 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 OR COPYRIGHT HOLDERS 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. */ #ifndef VK_UTIL_H #define VK_UTIL_H #ifdef __cplusplus extern "C" { #endif /* common inlines and macros for vulkan drivers */ #include #define vk_foreach_struct(__iter, __start) \ for (struct VkBaseOutStructure *__iter = (struct VkBaseOutStructure *)(__start); \ __iter; __iter = __iter->pNext) #define vk_foreach_struct_const(__iter, __start) \ for (const struct VkBaseInStructure *__iter = (const struct VkBaseInStructure *)(__start); \ __iter; __iter = __iter->pNext) /** * A wrapper for a Vulkan output array. A Vulkan output array is one that * follows the convention of the parameters to * vkGetPhysicalDeviceQueueFamilyProperties(). * * Example Usage: * * VkResult * vkGetPhysicalDeviceQueueFamilyProperties( * VkPhysicalDevice physicalDevice, * uint32_t* pQueueFamilyPropertyCount, * VkQueueFamilyProperties* pQueueFamilyProperties) * { * VK_OUTARRAY_MAKE(props, pQueueFamilyProperties, * pQueueFamilyPropertyCount); * * vk_outarray_append(&props, p) { * p->queueFlags = ...; * p->queueCount = ...; * } * * vk_outarray_append(&props, p) { * p->queueFlags = ...; * p->queueCount = ...; * } * * return vk_outarray_status(&props); * } */ struct __vk_outarray { /** May be null. */ void *data; /** * Capacity, in number of elements. Capacity is unlimited (UINT32_MAX) if * data is null. */ uint32_t cap; /** * Count of elements successfully written to the array. Every write is * considered successful if data is null. */ uint32_t *filled_len; /** * Count of elements that would have been written to the array if its * capacity were sufficient. Vulkan functions often return VK_INCOMPLETE * when `*filled_len < wanted_len`. */ uint32_t wanted_len; }; static inline void __vk_outarray_init(struct __vk_outarray *a, void *data, uint32_t *restrict len) { a->data = data; a->cap = *len; a->filled_len = len; *a->filled_len = 0; a->wanted_len = 0; if (a->data == NULL) a->cap = UINT32_MAX; } static inline VkResult __vk_outarray_status(const struct __vk_outarray *a) { if (*a->filled_len < a->wanted_len) return VK_INCOMPLETE; else return VK_SUCCESS; } static inline void * __vk_outarray_next(struct __vk_outarray *a, size_t elem_size) { void *p = NULL; a->wanted_len += 1; if (*a->filled_len >= a->cap) return NULL; if (a->data != NULL) p = (uint8_t *)a->data + (*a->filled_len) * elem_size; *a->filled_len += 1; return p; } #define vk_outarray(elem_t) \ struct { \ struct __vk_outarray base; \ elem_t meta[]; \ } #define vk_outarray_typeof_elem(a) __typeof__((a)->meta[0]) #define vk_outarray_sizeof_elem(a) sizeof((a)->meta[0]) #define vk_outarray_init(a, data, len) \ __vk_outarray_init(&(a)->base, (data), (len)) #define VK_OUTARRAY_MAKE(name, data, len) \ vk_outarray(__typeof__((data)[0])) name; \ vk_outarray_init(&name, (data), (len)) #define vk_outarray_status(a) \ __vk_outarray_status(&(a)->base) #define vk_outarray_next(a) \ ((vk_outarray_typeof_elem(a) *) \ __vk_outarray_next(&(a)->base, vk_outarray_sizeof_elem(a))) /** * Append to a Vulkan output array. * * This is a block-based macro. For example: * * vk_outarray_append(&a, elem) { * elem->foo = ...; * elem->bar = ...; * } * * The array `a` has type `vk_outarray(elem_t) *`. It is usually declared with * VK_OUTARRAY_MAKE(). The variable `elem` is block-scoped and has type * `elem_t *`. * * The macro unconditionally increments the array's `wanted_len`. If the array * is not full, then the macro also increment its `filled_len` and then * executes the block. When the block is executed, `elem` is non-null and * points to the newly appended element. */ #define vk_outarray_append(a, elem) \ for (vk_outarray_typeof_elem(a) *elem = vk_outarray_next(a); \ elem != NULL; elem = NULL) static inline void * __vk_find_struct(void *start, VkStructureType sType) { vk_foreach_struct(s, start) { if (s->sType == sType) return s; } return NULL; } #define vk_find_struct(__start, __sType) \ __vk_find_struct((__start), VK_STRUCTURE_TYPE_##__sType) #define vk_find_struct_const(__start, __sType) \ (const void *)__vk_find_struct((void *)(__start), VK_STRUCTURE_TYPE_##__sType) static inline void __vk_append_struct(void *start, void *element) { vk_foreach_struct(s, start) { if (s->pNext) continue; s->pNext = (struct VkBaseOutStructure *) element; break; } } uint32_t vk_get_driver_version(void); uint32_t vk_get_version_override(void); #define VK_EXT_OFFSET (1000000000UL) #define VK_ENUM_EXTENSION(__enum) \ ((__enum) >= VK_EXT_OFFSET ? ((((__enum) - VK_EXT_OFFSET) / 1000UL) + 1) : 0) #define VK_ENUM_OFFSET(__enum) \ ((__enum) >= VK_EXT_OFFSET ? ((__enum) % 1000) : (__enum)) #ifdef __cplusplus } #endif #endif /* VK_UTIL_H */ ================================================ FILE: meson.build ================================================ project('MangoHud', ['c', 'cpp'], version : 'v0.8.3', license : 'MIT', meson_version: '>=0.60.0', default_options : ['buildtype=release', 'c_std=c99', 'cpp_std=c++17', 'warning_level=2'] ) cc = meson.get_compiler('c') cpp = meson.get_compiler('cpp') prog_python = import('python').find_installation('python3', modules: ['mako']) null_dep = dependency('', required : false) mangohud_version = vcs_tag( command: ['git', 'describe', '--tags', '--dirty=+'], input: 'version.h.in', output: 'version.h') mangohud_version_dep = declare_dependency(sources : mangohud_version) pre_args = [ '-D__STDC_CONSTANT_MACROS', '-D__STDC_FORMAT_MACROS', '-D__STDC_LIMIT_MACROS', '-DPACKAGE_VERSION="@0@"'.format(meson.project_version()), '-DSPDLOG_COMPILED_LIB' ] if get_option('buildtype') == 'debug' pre_args += '-DDEBUG' endif # Always set max spdlog level, handle this using MANGOHUD_LOG_LEVEL instead. pre_args += '-DSPDLOG_ACTIVE_LEVEL=SPDLOG_LEVEL_TRACE' # TODO: this is very incomplete is_unixy = false if ['linux', 'cygwin', 'gnu'].contains(host_machine.system()) pre_args += '-D_GNU_SOURCE' pre_args += '-DHAVE_PTHREAD' is_unixy = true endif if host_machine.system() == 'linux' pre_args += '-DHAVE_FTRACE' endif if get_option('glibcxx_asserts') pre_args += '-D_GLIBCXX_ASSERTIONS' endif # Check for GCC style atomics if cc.compiles('''#include int main() { struct { uint64_t *v; } x; return (int)__atomic_load_n(x.v, __ATOMIC_ACQUIRE) & (int)__atomic_add_fetch(x.v, (uint64_t)1, __ATOMIC_ACQ_REL); }''', name : 'GCC atomic builtins') pre_args += '-DUSE_GCC_ATOMIC_BUILTINS' endif # Not in C99, needs POSIX if cc.compiles(''' #define _GNU_SOURCE #include int main() { struct timespec ts; return timespec_get(&ts, TIME_UTC); }''', name : 'Supports timespec_get') pre_args += '-DHAVE_TIMESPEC_GET' endif # Check for GCC style builtins foreach b : ['bswap32', 'bswap64', 'clz', 'clzll', 'ctz', 'expect', 'ffs', 'ffsll', 'popcount', 'popcountll', 'unreachable'] if cc.has_function(b) pre_args += '-DHAVE___BUILTIN_@0@'.format(b.to_upper()) endif endforeach vulkan_wsi_args = [] vulkan_wsi_deps = [] if is_unixy dep_x11 = dependency('x11', required: get_option('with_x11')) dep_wayland_client = dependency('wayland-client', required: get_option('with_wayland'), version : '>=1.11') dbus_dep = dependency('dbus-1', required: get_option('with_dbus')).partial_dependency(compile_args : true, includes : true) dep_xkb = dependency('xkbcommon', required: get_option('with_x11').enabled() or get_option('with_wayland').enabled()) vulkan_wsi_deps += dep_xkb else dep_x11 = null_dep dep_wayland_client = null_dep dbus_dep = null_dep endif if dep_x11.found() vulkan_wsi_args += ['-DVK_USE_PLATFORM_XLIB_KHR'] vulkan_wsi_deps += dep_x11.partial_dependency(compile_args : true, includes : true) endif if dep_wayland_client.found() vulkan_wsi_args += ['-DVK_USE_PLATFORM_WAYLAND_KHR'] vulkan_wsi_deps += dep_wayland_client endif if is_unixy and not dep_x11.found() and not dep_wayland_client.found() error('At least one of "with_x11" and "with_wayland" should be enabled') endif inc_common = [ include_directories('include'), ] dep_pthread = dependency('threads') add_project_arguments( cc.get_supported_arguments([ '-Werror=implicit-function-declaration', '-Werror=missing-declarations', '-Werror=missing-prototypes', '-Werror=return-type', '-Werror=incompatible-pointer-types', '-Wno-unused-parameter', '-Qunused-arguments', '-fno-math-errno', '-fno-trapping-math', '-Wno-missing-field-initializers', ]), language : ['c'], ) add_project_arguments( cpp.get_supported_arguments([ '-Werror=missing-declarations', '-Werror=return-type', '-Wno-unused-parameter', '-Qunused-arguments', '-fno-math-errno', '-fno-trapping-math', '-Wno-non-virtual-dtor', '-Wno-missing-field-initializers', ]), language : ['cpp'], ) foreach a : pre_args add_project_arguments(a, language : ['c', 'cpp']) endforeach # check for dl support if is_unixy if cc.has_function('dlopen') dep_dl = null_dep else dep_dl = cc.find_library('dl') endif # check for linking with rt by default if cc.has_function('clock_gettime') dep_rt = null_dep else dep_rt = cc.find_library('rt') endif else dep_dl = null_dep dep_rt = null_dep endif # Commented code can be used if mangohud start using latest SDK Vulkan-Headers # Allowing user to build mangohud using system Vulkan-Headers # if not dependency('VulkanHeaders').found() vulkan_headers_sp = subproject('vulkan-headers') vulkan_headers_api_xml = vulkan_headers_sp.get_variable('vulkan_api_xml') dep_vulkan_headers = vulkan_headers_sp.get_variable('vulkan_headers_dep') vulkan_utility_libraries_sp = subproject('vulkan-utility-libraries') dep_vulkan_utility_libraries = vulkan_utility_libraries_sp.get_variable('vulkan_utility_libraries_dep') # else # dep_vulkan_headers = dependency('VulkanHeaders', required: true) # vulkan_headers_api_xml = files('/usr/share/vulkan/registry/vk.xml') # endif vk_enum_to_str = custom_target( 'vk_enum_to_str', input : ['bin/gen_enum_to_str.py', vulkan_headers_api_xml], output : ['vk_enum_to_str.c', 'vk_enum_to_str.h', 'vk_enum_defines.h'], command : [ prog_python, '@INPUT0@', '--xml', '@INPUT1@', '--out-c', '@OUTPUT0@', '--out-h', '@OUTPUT1@', '--out-d', '@OUTPUT2@', '--beta', 'false' ], ) vk_dispatch_table = custom_target( 'vk_dispatch_table', input : ['bin/vk_dispatch_table_gen.py', vulkan_headers_api_xml], output : ['vk_dispatch_table.c', 'vk_dispatch_table.h'], command : [ prog_python, '@INPUT0@', '--xml', '@INPUT1@', '--out-c', '@OUTPUT0@', '--out-h', '@OUTPUT1@', '--beta', 'false' ], ) vk_extensions = custom_target( 'vk_extensions', input : ['bin/vk_extensions_gen.py', vulkan_headers_api_xml], output : ['vk_extensions.c', 'vk_extensions.h'], command : [ prog_python, '@INPUT0@', '--xml', '@INPUT1@', '--out-c', '@OUTPUT0@', '--out-h', '@OUTPUT1@' ], ) imgui_options = [ 'default_library=static', 'werror=false', # use 'auto_features=disabled' once available: https://github.com/mesonbuild/meson/issues/5320 'dx9=disabled', 'dx10=disabled', 'dx11=disabled', 'dx12=disabled', 'metal=disabled', 'opengl=disabled', 'vulkan=disabled', 'glfw=disabled', 'sdl2=disabled', 'sdl3=disabled', 'osx=disabled', 'win=disabled', 'allegro5=disabled', 'webgpu=disabled', 'sdl2_renderer=disabled', 'sdl3_renderer=disabled', 'osx=disabled', 'win=disabled' ] sizeof_ptr = cc.sizeof('void*') if sizeof_ptr == 8 pre_args += '-DMANGOHUD_ARCH="64bit"' elif sizeof_ptr == 4 pre_args += '-DMANGOHUD_ARCH="32bit"' endif if get_option('mangoapp') imgui_options += [ 'opengl=enabled', 'glfw=enabled', ] endif imgui_sp = subproject('imgui', default_options: imgui_options) dearimgui_dep = imgui_sp.get_variable('imgui_dep') meson.override_dependency('imgui', dearimgui_dep) implot_sp = subproject('implot', default_options: ['default_library=static']) implot_dep = implot_sp.get_variable('implot_dep') spdlog_options = [ 'default_library=static', 'compile_library=true', 'werror=false', 'tests=disabled', 'external_fmt=disabled', 'std_format=disabled' ] spdlog_dep = dependency('spdlog', required: false) if get_option('use_system_spdlog').disabled() or not spdlog_dep.found() if get_option('use_system_spdlog').enabled() warning('spdlog dependency not found following back to submodule') endif spdlog_sp = subproject('spdlog', default_options: spdlog_options) spdlog_dep = spdlog_sp.get_variable('spdlog_dep') endif if ['windows', 'mingw'].contains(host_machine.system()) minhook_dep = dependency('minhook', fallback: ['minhook', 'minhook_dep'], required: true) windows_deps = [ minhook_dep, ] else windows_deps = null_dep endif if get_option('mangoapp') glfw3_dep = dependency('glfw3') endif subdir('src') if get_option('include_doc') subdir('data') endif if get_option('tests').enabled() # cmocka_dep = dependency('cmocka', fallback: ['cmocka', 'cmocka_dep']) # e = executable('amdgpu', 'tests/test_amdgpu.cpp', # files( # 'src/amdgpu.cpp', # 'src/cpu.cpp', # 'src/gpu.cpp', # 'src/gpu_fdinfo.cpp', # 'src/nvidia.cpp', # 'src/mesa/util/os_time.c', # 'src/file_utils.cpp', # 'src/hud_elements.cpp' # ), # cpp_args: ['-DTEST_ONLY'], # dependencies: [ # cmocka_dep, # spdlog_dep, # implot_dep, # dearimgui_dep # ], # include_directories: inc_common) # test('test amdgpu', e, workdir : meson.project_source_root() + '/tests') endif # install helper scripts if get_option('mangoplot').enabled() subdir('bin') endif ================================================ FILE: meson_options.txt ================================================ option('glibcxx_asserts', type : 'boolean', value : false) option('use_system_spdlog', type : 'feature', value : 'disabled', description: 'Use system spdlog library') option('append_libdir_mangohud', type : 'boolean', value : true, description: 'Append "mangohud" to libdir path or not.') option('include_doc', type : 'boolean', value : true, description: 'Include the example config, man pages, appstream files etc.') option('with_nvml', type : 'combo', value : 'enabled', choices: ['enabled', 'system', 'disabled'], description: 'Enable NVML support') option('with_xnvctrl', type : 'feature', value : 'enabled', description: 'Enable XNVCtrl support') option('with_x11', type : 'feature', value : 'enabled') option('with_wayland', type : 'feature', value : 'enabled') option('with_dbus', type : 'feature', value : 'enabled') option('loglevel', type: 'combo', choices : ['trace', 'debug', 'info', 'warn', 'err', 'critical', 'off'], value : 'info', description: 'Max log level in non-debug build') option('mangoapp', type: 'boolean', value : false) option('mangohudctl', type: 'boolean', value : false) option('tests', type: 'feature', value: 'auto', description: 'Run tests') option('mangoplot', type: 'feature', value: 'enabled') option('dynamic_string_tokens', type: 'boolean', value: true, description: 'Use dynamic string tokens in LD_PRELOAD') option('with_fex', type : 'boolean', value : false) ================================================ FILE: mingw32.txt ================================================ [binaries] c = 'i686-w64-mingw32-gcc' cpp = 'i686-w64-mingw32-g++' ar = 'i686-w64-mingw32-ar' strip = 'i686-w64-mingw32-strip' pkg-config = 'i686-w64-mingw32-pkg-config' sh = '/usr/bin/sh' [properties] needs_exe_wrapper = true [host_machine] system = 'windows' cpu_family = 'x86' cpu = 'i686' endian = 'little' ================================================ FILE: mingw64.txt ================================================ [binaries] c = 'x86_64-w64-mingw32-gcc' cpp = 'x86_64-w64-mingw32-g++' ar = 'x86_64-w64-mingw32-ar' strip = 'x86_64-w64-mingw32-strip' pkg-config = 'x86_64-w64-mingw32-pkg-config' sh = '/usr/bin/sh' [properties] needs_exe_wrapper = true [host_machine] system = 'windows' cpu_family = 'x86_64' cpu = 'x86_64' endian = 'little' ================================================ FILE: pkgbuild/PKGBUILD ================================================ # Maintainer: Simon Hallsten pkgname=('mangohud' 'lib32-mangohud') pkgver=0.8.3.rc1.r36.ga2a54f5e pkgrel=1 pkgdesc="Vulkan and OpenGL overlay to display performance information" arch=('x86_64') makedepends=('dbus' 'gcc' 'meson' 'python-mako' 'libx11' 'lib32-libx11' 'git' 'pkgconf' 'vulkan-headers') depends=('glslang' 'libglvnd' 'lib32-libglvnd' 'glfw' 'python-numpy' 'python-matplotlib' 'libxrandr' 'libxkbcommon' 'lib32-libxkbcommon') replaces=('vulkan-mesa-layer-mango') license=('MIT') source=( "mangohud"::"git+https://github.com/flightlessmango/MangoHud.git#branch=master" "mangohud-minhook"::"git+https://github.com/flightlessmango/minhook.git" "imgui-1.91.6.tar.gz::https://github.com/ocornut/imgui/archive/refs/tags/v1.91.6.tar.gz" "imgui_1.91.6-3_patch.zip::https://wrapdb.mesonbuild.com/v2/imgui_1.91.6-3/get_patch" "spdlog-1.14.1.tar.gz::https://github.com/gabime/spdlog/archive/refs/tags/v1.14.1.tar.gz" "spdlog_1.14.1-1_patch.zip::https://wrapdb.mesonbuild.com/v2/spdlog_1.14.1-1/get_patch" "vulkan-headers-1.4.346.tar.gz::https://github.com/KhronosGroup/Vulkan-Headers/archive/v1.4.346.tar.gz" "vulkan-utility-libraries-1.4.346.tar.gz::https://github.com/KhronosGroup/Vulkan-Utility-Libraries/archive/v1.4.346.tar.gz" "implot-0.16.zip::https://github.com/epezent/implot/archive/refs/tags/v0.16.zip" "implot_0.16-1_patch.zip::https://wrapdb.mesonbuild.com/v2/implot_0.16-1/get_patch" ) sha256sums=( 'SKIP' 'SKIP' 'c5fbc5dcab1d46064001c3b84d7a88812985cde7e0e9ced03f5677bec1ba502a' '2f7977114ba07d06559aaf8890a92a4ebd25186592d4447954605aaf2244634d' '1586508029a7d0670dfcb2d97575dcdc242d3868a259742b69f100801ab4e16b' 'ae878e732330ea1048f90d7e117c40c0cd2a6fb8ae5492c7955818ce3aaade6c' "5bb77f5d7b460e255a9e51affc00d64354986b55cf577d8eab28529cad01fc80" "372eb525103ecb4e3a04d030b2a9778ebc67853bbdc82ce6747de3757d432ad9" "24f772c688f6b8a6e19d7efc10e4923a04a915f13d487b08b83553aa62ae1708" "1c6b1462066a5452fa50c1da1dd47fed841f28232972c82d778f2962936568c7" ) _build_args="-Dappend_libdir_mangohud=false -Dwith_xnvctrl=disabled -Dtests=disabled" pkgver() { cd "$srcdir/mangohud" git describe --tags | sed -r 's/^v//;s/([^-]*-g)/r\1/;s/-/./g' } prepare() { cd "${srcdir}/mangohud" git submodule init git config submodule.modules/minhook.url "$srcdir/mangohud-minhook" git -c protocol.file.allow=always submodule update # meson subprojects ln -sv "$srcdir/imgui-1.91.6" subprojects ln -sv "$srcdir/spdlog-1.14.1" subprojects ln -sv "$srcdir/Vulkan-Headers-1.4.346" subprojects cp -rvt "subprojects/Vulkan-Headers-1.4.346" -- "subprojects/packagefiles/vulkan-headers/"* ln -sv "$srcdir/Vulkan-Utility-Libraries-1.4.346" subprojects cp -rvt "subprojects/Vulkan-Utility-Libraries-1.4.346" -- "subprojects/packagefiles/vulkan-utility-libraries/"* ln -sv "$srcdir/implot-0.16" subprojects } build() { arch-meson mangohud build64 \ ${_build_args} -Dmangoapp=true -Dmangohudctl=true ninja -C build64 export CC="${CC:-gcc} -m32" export CXX="${CXX:-g++} -m32" export PKG_CONFIG_PATH="/usr/lib32/pkgconfig:/usr/lib/i386-linux-gnu/pkgconfig:/usr/lib/pkgconfig:${PKG_CONFIG_PATH_32}" export LLVM_CONFIG="/usr/bin/llvm-config32" arch-meson mangohud build32 \ --libdir=lib32 \ -Dmangoapp=false \ -Dmangohudctl=false \ ${_build_args} ninja -C build32 } package_mangohud() { provides=("mangohud") conflicts=('mangohud-common') DESTDIR="${pkgdir}" ninja -C build64 install } package_lib32-mangohud() { provides=("lib32-mangohud") DESTDIR="${pkgdir}" ninja -C build32 install rm -rf "$pkgdir/usr/bin" rm -rf "$pkgdir/usr/share" install -m644 -Dt "$pkgdir/usr/share/vulkan/implicit_layer.d" "$srcdir/build32/src/MangoHud.x86.json" } ================================================ FILE: src/amdgpu.cpp ================================================ #include #include #ifdef __linux__ #include #endif #include "amdgpu.h" #include "gpu.h" #include "cpu.h" #include "overlay.h" #include "hud_elements.h" #include "logging.h" #include "mesa/util/macros.h" #define IS_VALID_METRIC(FIELD) (FIELD != 0xffff) void AMDGPU::get_instant_metrics(struct amdgpu_common_metrics *metrics) { FILE *f; uint8_t buf[sizeof(struct gpu_metrics_v3_0)+1]; // big enough for v1.3/v2.4/v3.0 struct metrics_table_header *header = (struct metrics_table_header *)buf; f = fopen(gpu_metrics_path.c_str(), "rb"); if (!f) return; size_t nread = fread(buf, 1, sizeof(buf), f); fclose(f); if (nread < sizeof(*header)) { SPDLOG_DEBUG("amdgpu metrics file '{}' may be corrupted (read {} bytes, need at least {})", gpu_metrics_path, nread, sizeof(*header)); return; } if (nread == sizeof(buf)) { // File may be larger than our buffer, so we might have truncated it SPDLOG_DEBUG("amdgpu metrics file '{}' may be larger than the buffer ({} bytes)", gpu_metrics_path, sizeof(buf)); return; } bool is_power=false, is_current=false, is_temp=false, is_other=false; if (header->format_revision == 1) { // Desktop GPUs struct gpu_metrics_v1_3 *amdgpu_metrics = (struct gpu_metrics_v1_3 *) buf; metrics->gpu_load_percent = amdgpu_metrics->average_gfx_activity; metrics->average_gfx_power_w = amdgpu_metrics->average_socket_power; metrics->current_gfxclk_mhz = amdgpu_metrics->current_gfxclk; metrics->current_uclk_mhz = amdgpu_metrics->current_uclk; metrics->gpu_temp_c = amdgpu_metrics->temperature_edge; metrics->fan_speed = amdgpu_metrics->current_fan_speed; uint64_t indep = amdgpu_metrics->indep_throttle_status; // RDNA 3 almost always shows the TEMP_HOTSPOT throtting flag, // so clear that bit indep &= ~(1ull << TEMP_HOTSPOT_BIT); // your existing quirk is_power = ((indep >> 0) & 0xFF) != 0; is_current = ((indep >> 16) & 0xFF) != 0; is_temp = ((indep >> 32) & 0xFFFF) != 0; is_other = ((indep >> 56) & 0xFF) != 0; if (throttling) throttling->indep_throttle_status = indep; } else if (header->format_revision == 2) { // APUs this->is_apu = true; struct gpu_metrics_v2_3 *amdgpu_metrics = (struct gpu_metrics_v2_3 *) buf; metrics->gpu_load_percent = amdgpu_metrics->average_gfx_activity; metrics->average_gfx_power_w = amdgpu_metrics->average_gfx_power / 1000.f; if( IS_VALID_METRIC(amdgpu_metrics->average_cpu_power) ) { // prefered method metrics->average_cpu_power_w = amdgpu_metrics->average_cpu_power / 1000.f; } else if( IS_VALID_METRIC(amdgpu_metrics->average_core_power[0]) ) { // fallback 1: sum of core power metrics->average_cpu_power_w = 0; unsigned i = 0; do metrics->average_cpu_power_w = metrics->average_cpu_power_w + amdgpu_metrics->average_core_power[i] / 1000.f; while (++i < ARRAY_SIZE(amdgpu_metrics->average_core_power) && IS_VALID_METRIC(amdgpu_metrics->average_core_power[i])); } else if( IS_VALID_METRIC(amdgpu_metrics->average_socket_power) && IS_VALID_METRIC(amdgpu_metrics->average_gfx_power) ) { // fallback 2: estimate cpu power frostd::string pci_dev, uint32_t deviceID, uint32_t vendorID metrics->soc_temp_c = 0; } if( IS_VALID_METRIC(amdgpu_metrics->temperature_gfx) ) { // prefered method metrics->gpu_temp_c = amdgpu_metrics->temperature_gfx / 100; } else if( header->content_revision >= 3 && IS_VALID_METRIC(amdgpu_metrics->average_temperature_gfx) ) { // fallback 1 metrics->gpu_temp_c = amdgpu_metrics->average_temperature_gfx / 100; } else { // giving up metrics->gpu_temp_c = 0; } int cpu_temp = 0; if( IS_VALID_METRIC(amdgpu_metrics->temperature_core[0]) ) { // prefered method unsigned i = 0; do cpu_temp = MAX(cpu_temp, amdgpu_metrics->temperature_core[i]); while (++i < ARRAY_SIZE(amdgpu_metrics->temperature_core) && IS_VALID_METRIC(amdgpu_metrics->temperature_core[i])); metrics->apu_cpu_temp_c = cpu_temp / 100; } else if( header->content_revision >= 3 && IS_VALID_METRIC(amdgpu_metrics->average_temperature_core[0]) ) { // fallback 1 unsigned i = 0; do cpu_temp = MAX(cpu_temp, amdgpu_metrics->average_temperature_core[i]); while (++i < ARRAY_SIZE(amdgpu_metrics->average_temperature_core) && IS_VALID_METRIC(amdgpu_metrics->average_temperature_core[i])); metrics->apu_cpu_temp_c = cpu_temp / 100; } else if( cpuStats.ReadcpuTempFile(cpu_temp) ) { // fallback 2: Try temp from file 'm_cpuTempFile' of 'cpu.cpp' metrics->apu_cpu_temp_c = cpu_temp; } else { // giving up metrics->apu_cpu_temp_c = 0; } if( IS_VALID_METRIC(amdgpu_metrics->current_gfxclk) ) { // prefered method metrics->current_gfxclk_mhz = amdgpu_metrics->current_gfxclk; } else if( IS_VALID_METRIC(amdgpu_metrics->average_gfxclk_frequency) ) { // fallback 1 metrics->current_gfxclk_mhz = amdgpu_metrics->average_gfxclk_frequency; } else { // giving up metrics->current_gfxclk_mhz = 0; } if( IS_VALID_METRIC(amdgpu_metrics->current_uclk) ) { // prefered method metrics->current_uclk_mhz = amdgpu_metrics->current_uclk; } else if( IS_VALID_METRIC(amdgpu_metrics->average_uclk_frequency) ) { // fallback 1 metrics->current_uclk_mhz = amdgpu_metrics->average_uclk_frequency; } else { // giving up metrics->current_uclk_mhz = 0; } if(header->content_revision >= 2) { uint64_t indep = amdgpu_metrics->indep_throttle_status; is_power = ((indep >> 0) & 0xFF) != 0; is_current = ((indep >> 16) & 0xFF) != 0; is_temp = ((indep >> 32) & 0xFFFF) != 0; is_other = ((indep >> 56) & 0xFF) != 0; if (throttling) throttling->indep_throttle_status = indep; } } else if (header->format_revision == 3) { this->is_apu = true; struct gpu_metrics_v3_0 *amdgpu_metrics = (struct gpu_metrics_v3_0 *) buf; metrics->gpu_temp_c = amdgpu_metrics->temperature_gfx / 100; metrics->soc_temp_c = amdgpu_metrics->temperature_soc / 100; uint16_t cpu_temp = 0; for (unsigned i = 0; i < ARRAY_SIZE(amdgpu_metrics->temperature_core); i++) { if (!IS_VALID_METRIC(amdgpu_metrics->temperature_core[i])) break; cpu_temp = MAX(cpu_temp, amdgpu_metrics->temperature_core[i]); } metrics->apu_cpu_temp_c = cpu_temp / 100; metrics->gpu_load_percent = amdgpu_metrics->average_gfx_activity; // average_apu_power includes gfx_power so remove that from cpu_power int64_t apu_power = amdgpu_metrics->average_apu_power; int64_t gfx_power = amdgpu_metrics->average_gfx_power; metrics->average_cpu_power_w = float(apu_power - gfx_power) / 1000.0; if (metrics->average_cpu_power_w < 0) metrics->average_cpu_power_w = 0; metrics->average_gfx_power_w = amdgpu_metrics->average_gfx_power / 1000.0; metrics->current_gfxclk_mhz = amdgpu_metrics->average_gfxclk_frequency; metrics->current_uclk_mhz = amdgpu_metrics->average_uclk_frequency; if (previous_metrics.common_header.structure_size == 0) { previous_metrics = *amdgpu_metrics; is_temp = false; is_power = false; is_current = false; is_other = false; if (throttling) { throttling->use_v3 = true; throttling->v3_power.store(false); throttling->v3_thermal.store(false); } return; } else { uint32_t d_thm_core = V3_THROTTLING_DELTA(thm_core); uint32_t d_thm_gfx = V3_THROTTLING_DELTA(thm_gfx); uint32_t d_thm_soc = V3_THROTTLING_DELTA(thm_soc); uint32_t d_spl = V3_THROTTLING_DELTA(spl); uint32_t d_fppt = V3_THROTTLING_DELTA(fppt); uint32_t d_sppt = V3_THROTTLING_DELTA(sppt); uint32_t d_prochot = V3_THROTTLING_DELTA(prochot); is_temp = (d_thm_core | d_thm_gfx | d_thm_soc | d_prochot) > 0; is_power = (d_spl | d_fppt | d_sppt) > 0; // there is no current throttling flags in v3_0 is_current = false; // also no "other" throttling in v3_0 is_other = false; previous_metrics = *amdgpu_metrics; if (throttling) { throttling->use_v3 = true; // we only check spl, this attempts to match how we handle it in v1 and v2 // as close as we can throttling->v3_power.store(d_spl > 0); throttling->v3_thermal.store(is_temp); } } } /* Throttling: See https://elixir.bootlin.com/linux/latest/source/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h for the offsets */ metrics->is_power_throttled = is_power; metrics->is_current_throttled = is_current; metrics->is_temp_throttled = is_temp; metrics->is_other_throttled = is_other; } void AMDGPU::get_samples_and_copy(struct amdgpu_common_metrics metrics_buffer[METRICS_SAMPLE_COUNT], bool &gpu_load_needs_dividing) { while (!stop_thread) { // Get all the samples for (size_t cur_sample_id=0; cur_sample_id < METRICS_SAMPLE_COUNT; cur_sample_id++) { if (gpu_metrics_is_valid) get_instant_metrics(&metrics_buffer[cur_sample_id]); // Detect and fix if the gpu load is reported in centipercent if (gpu_load_needs_dividing || metrics_buffer[cur_sample_id].gpu_load_percent > 100){ gpu_load_needs_dividing = true; metrics_buffer[cur_sample_id].gpu_load_percent /= 100; } // frequently check if thread should stop so we don't get stuck for 500ms for (int ms = 0; ms < METRICS_POLLING_PERIOD_MS; ms++) { if (stop_thread) break; usleep(1000); } } if (stop_thread) break; std::unique_lock lock(metrics_mutex); cond_var.wait(lock, [this]() { return !paused || stop_thread; }); // do one pass of metrics from sysfs nodes // then we replace with GPU metrics if it's available get_sysfs_metrics(); #ifndef TEST_ONLY metrics.proc_vram_used = fdinfo_helper->amdgpu_helper_get_proc_vram(); #endif if (gpu_metrics_is_valid) { UPDATE_METRIC_AVERAGE(gpu_load_percent); UPDATE_METRIC_AVERAGE_FLOAT(average_gfx_power_w); UPDATE_METRIC_AVERAGE_FLOAT(average_cpu_power_w); UPDATE_METRIC_AVERAGE(current_gfxclk_mhz); UPDATE_METRIC_AVERAGE(current_uclk_mhz); UPDATE_METRIC_AVERAGE(soc_temp_c); UPDATE_METRIC_AVERAGE(gpu_temp_c); UPDATE_METRIC_AVERAGE(apu_cpu_temp_c); UPDATE_METRIC_MAX(is_power_throttled); UPDATE_METRIC_MAX(is_current_throttled); UPDATE_METRIC_MAX(is_temp_throttled); UPDATE_METRIC_MAX(is_other_throttled); UPDATE_METRIC_MAX(fan_speed); metrics.fan_rpm = true; metrics.load = amdgpu_common_metrics.gpu_load_percent; metrics.powerUsage = amdgpu_common_metrics.average_gfx_power_w; metrics.MemClock = amdgpu_common_metrics.current_uclk_mhz; // Use hwmon instead, see gpu.cpp if ( device_id == 0x1435 || device_id == 0x163f ) { // If we are on VANGOGH (Steam Deck), then // always use core clock from GPU metrics. metrics.CoreClock = amdgpu_common_metrics.current_gfxclk_mhz; } metrics.temp = amdgpu_common_metrics.gpu_temp_c; metrics.apu_cpu_power = amdgpu_common_metrics.average_cpu_power_w; metrics.apu_cpu_temp = amdgpu_common_metrics.apu_cpu_temp_c; metrics.is_power_throttled = amdgpu_common_metrics.is_power_throttled; metrics.is_current_throttled = amdgpu_common_metrics.is_current_throttled; metrics.is_temp_throttled = amdgpu_common_metrics.is_temp_throttled; metrics.is_other_throttled = amdgpu_common_metrics.is_other_throttled; // Set only if gpu_metrics has value larger than 0, otherwise use hwmon if (amdgpu_common_metrics.fan_speed > 0) metrics.fan_speed = amdgpu_common_metrics.fan_speed; } } } void AMDGPU::metrics_polling_thread() { struct amdgpu_common_metrics metrics_buffer[METRICS_SAMPLE_COUNT]; bool gpu_load_needs_dividing = false; //some GPUs report load as centipercent // Initial poll of the metrics, so that we have values to display as fast as possible get_instant_metrics(&amdgpu_common_metrics); if (amdgpu_common_metrics.gpu_load_percent > 100){ gpu_load_needs_dividing = true; amdgpu_common_metrics.gpu_load_percent /= 100; } // Set all the fields to 0 by default. Only done once as we're just replacing previous values after memset(metrics_buffer, 0, sizeof(metrics_buffer)); while (!stop_thread) { #ifndef TEST_ONLY if (get_params()->no_display && !logger->is_active()) usleep(100000); else #endif get_samples_and_copy(metrics_buffer, gpu_load_needs_dividing); } } void AMDGPU::get_sysfs_metrics() { int64_t value = 0; if (sysfs_nodes.busy) { rewind(sysfs_nodes.busy); fflush(sysfs_nodes.busy); int value = 0; if (fscanf(sysfs_nodes.busy, "%d", &value) != 1) value = 0; metrics.load = value; } if (sysfs_nodes.memory_clock) { rewind(sysfs_nodes.memory_clock); fflush(sysfs_nodes.memory_clock); if (fscanf(sysfs_nodes.memory_clock, "%" PRId64, &value) != 1) value = 0; metrics.MemClock = value / 1000000; } // TODO: on some gpus this will use the power1_input instead // this value is instantaneous and should be averaged over time // probably just average everything in this function to be safe #ifndef TEST_ONLY if (get_params()->enabled[OVERLAY_PARAM_ENABLED_gpu_power]) { // NOTE: Do not read power1_average if it is not enabled, as some // older GPUs may hang when reading the sysfs node. metrics.powerUsage = 0; } else #endif if (sysfs_nodes.power_usage) { rewind(sysfs_nodes.power_usage); fflush(sysfs_nodes.power_usage); if (fscanf(sysfs_nodes.power_usage, "%" PRId64, &value) != 1) value = 0; metrics.powerUsage = value / 1000000; } #ifndef TEST_ONLY if (!get_params()->enabled[OVERLAY_PARAM_ENABLED_gpu_power_limit]) { // NOTE: Do not read power1_cap if it is not enabled, as some // older GPUs may hang when reading the sysfs node. metrics.powerLimit = 0; } else #endif if (sysfs_nodes.power_limit) { rewind(sysfs_nodes.power_limit); fflush(sysfs_nodes.power_limit); if (fscanf(sysfs_nodes.power_limit, "%" PRId64, &value) != 1) value = 0; metrics.powerLimit = value / 1000000; } if (sysfs_nodes.fan) { rewind(sysfs_nodes.fan); fflush(sysfs_nodes.fan); if (fscanf(sysfs_nodes.fan, "%" PRId64, &value) != 1) value = 0; metrics.fan_speed = value; metrics.fan_rpm = true; } if (sysfs_nodes.vram_total) { rewind(sysfs_nodes.vram_total); fflush(sysfs_nodes.vram_total); if (fscanf(sysfs_nodes.vram_total, "%" PRId64, &value) != 1) value = 0; metrics.memoryTotal = float(value) / (1024 * 1024 * 1024); } if (sysfs_nodes.vram_used) { rewind(sysfs_nodes.vram_used); fflush(sysfs_nodes.vram_used); if (fscanf(sysfs_nodes.vram_used, "%" PRId64, &value) != 1) value = 0; metrics.sys_vram_used = float(value) / (1024 * 1024 * 1024); } // On some GPUs SMU can sometimes return the wrong temperature. // As HWMON is way more visible than the SMU metrics, let's always trust it as it is the most likely to work if (sysfs_nodes.core_clock) { rewind(sysfs_nodes.core_clock); fflush(sysfs_nodes.core_clock); if (fscanf(sysfs_nodes.core_clock, "%" PRId64, &value) != 1) value = 0; metrics.CoreClock = value / 1000000; } if (sysfs_nodes.temp){ rewind(sysfs_nodes.temp); fflush(sysfs_nodes.temp); int value = 0; if (fscanf(sysfs_nodes.temp, "%d", &value) != 1) value = 0; metrics.temp = value / 1000; } if (sysfs_nodes.junction_temp){ rewind(sysfs_nodes.junction_temp); fflush(sysfs_nodes.junction_temp); int value = 0; if (fscanf(sysfs_nodes.junction_temp, "%d", &value) != 1) value = 0; metrics.junction_temp = value / 1000; } if (sysfs_nodes.memory_temp){ rewind(sysfs_nodes.memory_temp); fflush(sysfs_nodes.memory_temp); int value = 0; if (fscanf(sysfs_nodes.memory_temp, "%d", &value) != 1) value = 0; metrics.memory_temp = value / 1000; } if (sysfs_nodes.gtt_used) { rewind(sysfs_nodes.gtt_used); fflush(sysfs_nodes.gtt_used); if (fscanf(sysfs_nodes.gtt_used, "%" PRId64, &value) != 1) value = 0; metrics.gtt_used = float(value) / (1024 * 1024 * 1024); } if (sysfs_nodes.gpu_voltage_soc) { rewind(sysfs_nodes.gpu_voltage_soc); fflush(sysfs_nodes.gpu_voltage_soc); if (fscanf(sysfs_nodes.gpu_voltage_soc, "%" PRId64, &value) != 1) value = 0; metrics.voltage = value; } } AMDGPU::AMDGPU(std::string pci_dev, uint32_t device_id, uint32_t vendor_id) { this->pci_dev = pci_dev; this->device_id = device_id; this->vendor_id = vendor_id; const std::string device_path = "/sys/bus/pci/devices/" + pci_dev; gpu_metrics_path = device_path + "/gpu_metrics"; // Just check that the metrics file exists and is readable FILE *f = fopen(gpu_metrics_path.c_str(), "rb"); if (f) { gpu_metrics_is_valid = true; fclose(f); } else { gpu_metrics_is_valid = false; SPDLOG_DEBUG("Failed to open gpu_metrics at '{}'", gpu_metrics_path); } sysfs_nodes.busy = fopen((device_path + "/gpu_busy_percent").c_str(), "r"); sysfs_nodes.vram_total = fopen((device_path + "/mem_info_vram_total").c_str(), "r"); sysfs_nodes.vram_used = fopen((device_path + "/mem_info_vram_used").c_str(), "r"); sysfs_nodes.gtt_used = fopen((device_path + "/mem_info_gtt_used").c_str(), "r"); const std::string hwmon_path = device_path + "/hwmon/"; if (fs::exists(hwmon_path)){ const auto dirs = ls(hwmon_path.c_str(), "hwmon", LS_DIRS); for (const auto& dir : dirs) { sysfs_nodes.temp = fopen((hwmon_path + dir + "/temp1_input").c_str(), "r"); sysfs_nodes.junction_temp = fopen((hwmon_path + dir + "/temp2_input").c_str(), "r"); sysfs_nodes.memory_temp = fopen((hwmon_path + dir + "/temp3_input").c_str(), "r"); sysfs_nodes.core_clock = fopen((hwmon_path + dir + "/freq1_input").c_str(), "r"); sysfs_nodes.gpu_voltage_soc = fopen((hwmon_path + dir + "/in0_input").c_str(), "r"); sysfs_nodes.memory_clock = fopen((hwmon_path + dir + "/freq2_input").c_str(), "r"); for (std::string p : { "power1_average", "power1_input" }) { std::string sensor = hwmon_path + dir + "/" + p; if (!fs::exists(sensor)) continue; sysfs_nodes.power_usage = fopen(sensor.c_str(), "r"); break; } sysfs_nodes.power_limit = fopen((hwmon_path + dir + "/power1_cap").c_str(), "r"); sysfs_nodes.fan = fopen((hwmon_path + dir + "/fan1_input").c_str(), "r"); } } throttling = std::make_shared(0x1002); #ifndef TEST_ONLY fdinfo_helper = std::make_unique("amdgpu", pci_dev, "", /*called_from_amdgpu_cpp=*/ true); #endif thread = std::thread(&AMDGPU::metrics_polling_thread, this); pthread_setname_np(thread.native_handle(), "mangohud-amdgpu"); } ================================================ FILE: src/amdgpu.h ================================================ #pragma once #include #include #include #include #include "overlay_params.h" #include #include #include #include #include #include #include #include "gpu_metrics_util.h" #ifndef TEST_ONLY #include "gpu_fdinfo.h" #endif #define NUM_HBM_INSTANCES 4 #define TEMP_HOTSPOT_BIT 36ull #define UPDATE_METRIC_AVERAGE(FIELD) do { int value_sum = 0; for (size_t s=0; s < METRICS_SAMPLE_COUNT; s++) { value_sum += metrics_buffer[s].FIELD; } amdgpu_common_metrics.FIELD = value_sum / METRICS_SAMPLE_COUNT; } while(0) #define UPDATE_METRIC_AVERAGE_FLOAT(FIELD) do { float value_sum = 0; for (size_t s=0; s < METRICS_SAMPLE_COUNT; s++) { value_sum += metrics_buffer[s].FIELD; } amdgpu_common_metrics.FIELD = value_sum / METRICS_SAMPLE_COUNT; } while(0) #define UPDATE_METRIC_MAX(FIELD) do { int cur_max = metrics_buffer[0].FIELD; for (size_t s=1; s < METRICS_SAMPLE_COUNT; s++) { cur_max = MAX(cur_max, metrics_buffer[s].FIELD); }; amdgpu_common_metrics.FIELD = cur_max; } while(0) #define UPDATE_METRIC_LAST(FIELD) do { amdgpu_common_metrics.FIELD = metrics_buffer[METRICS_SAMPLE_COUNT - 1].FIELD; } while(0) #ifdef _WIN32 #define MAX(x, y) (((x) > (y)) ? (x) : (y)) #endif struct metrics_table_header { uint16_t structure_size; uint8_t format_revision; uint8_t content_revision; }; struct gpu_metrics_v1_3 { struct metrics_table_header common_header; /* Temperature */ uint16_t temperature_edge; uint16_t temperature_hotspot; uint16_t temperature_mem; uint16_t temperature_vrgfx; uint16_t temperature_vrsoc; uint16_t temperature_vrmem; /* Utilization */ uint16_t average_gfx_activity; uint16_t average_umc_activity; // memory controller uint16_t average_mm_activity; // UVD or VCN /* Power/Energy */ uint16_t average_socket_power; uint64_t energy_accumulator; /* Driver attached timestamp (in ns) */ uint64_t system_clock_counter; /* Average clocks */ uint16_t average_gfxclk_frequency; uint16_t average_socclk_frequency; uint16_t average_uclk_frequency; uint16_t average_vclk0_frequency; uint16_t average_dclk0_frequency; uint16_t average_vclk1_frequency; uint16_t average_dclk1_frequency; /* Current clocks */ uint16_t current_gfxclk; uint16_t current_socclk; uint16_t current_uclk; uint16_t current_vclk0; uint16_t current_dclk0; uint16_t current_vclk1; uint16_t current_dclk1; /* Throttle status */ uint32_t throttle_status; /* Fans */ uint16_t current_fan_speed; /* Link width/speed */ uint16_t pcie_link_width; uint16_t pcie_link_speed; // in 0.1 GT/s uint16_t padding; uint32_t gfx_activity_acc; uint32_t mem_activity_acc; uint16_t temperature_hbm[NUM_HBM_INSTANCES]; /* PMFW attached timestamp (10ns resolution) */ uint64_t firmware_timestamp; /* Voltage (mV) */ uint16_t voltage_soc; uint16_t voltage_gfx; uint16_t voltage_mem; uint16_t padding1; /* Throttle status (ASIC independent) */ uint64_t indep_throttle_status; }; struct gpu_metrics_v2_3 { struct metrics_table_header common_header; /* Temperature */ uint16_t temperature_gfx; // gfx temperature on APUs uint16_t temperature_soc; // soc temperature on APUs uint16_t temperature_core[8]; // CPU core temperature on APUs uint16_t temperature_l3[2]; /* Utilization */ uint16_t average_gfx_activity; uint16_t average_mm_activity; // UVD or VCN /* Driver attached timestamp (in ns) */ uint64_t system_clock_counter; /* Power/Energy */ uint16_t average_socket_power; // dGPU + APU power on A + A platform uint16_t average_cpu_power; uint16_t average_soc_power; uint16_t average_gfx_power; uint16_t average_core_power[8]; // CPU core power on APUs /* Average clocks */ uint16_t average_gfxclk_frequency; uint16_t average_socclk_frequency; uint16_t average_uclk_frequency; uint16_t average_fclk_frequency; uint16_t average_vclk_frequency; uint16_t average_dclk_frequency; /* Current clocks */ uint16_t current_gfxclk; uint16_t current_socclk; uint16_t current_uclk; uint16_t current_fclk; uint16_t current_vclk; uint16_t current_dclk; uint16_t current_coreclk[8]; // CPU core clocks uint16_t current_l3clk[2]; /* Throttle status (ASIC dependent) */ uint32_t throttle_status; /* Fans */ uint16_t fan_pwm; uint16_t padding[3]; /* Throttle status (ASIC independent) */ uint64_t indep_throttle_status; /* Average Temperature */ uint16_t average_temperature_gfx; // average gfx temperature on APUs uint16_t average_temperature_soc; // average soc temperature on APUs uint16_t average_temperature_core[8]; // average CPU core temperature on APUs uint16_t average_temperature_l3[2]; }; struct gpu_metrics_v2_4 { struct metrics_table_header common_header; /* Temperature (unit: centi-Celsius) */ uint16_t temperature_gfx; uint16_t temperature_soc; uint16_t temperature_core[8]; uint16_t temperature_l3[2]; /* Utilization (unit: centi) */ uint16_t average_gfx_activity; uint16_t average_mm_activity; /* Driver attached timestamp (in ns) */ uint64_t system_clock_counter; /* Power/Energy (unit: mW) */ uint16_t average_socket_power; uint16_t average_cpu_power; uint16_t average_soc_power; uint16_t average_gfx_power; uint16_t average_core_power[8]; /* Average clocks (unit: MHz) */ uint16_t average_gfxclk_frequency; uint16_t average_socclk_frequency; uint16_t average_uclk_frequency; uint16_t average_fclk_frequency; uint16_t average_vclk_frequency; uint16_t average_dclk_frequency; /* Current clocks (unit: MHz) */ uint16_t current_gfxclk; uint16_t current_socclk; uint16_t current_uclk; uint16_t current_fclk; uint16_t current_vclk; uint16_t current_dclk; uint16_t current_coreclk[8]; uint16_t current_l3clk[2]; /* Throttle status (ASIC dependent) */ uint32_t throttle_status; /* Fans */ uint16_t fan_pwm; uint16_t padding[3]; /* Throttle status (ASIC independent) */ uint64_t indep_throttle_status; /* Average Temperature (unit: centi-Celsius) */ uint16_t average_temperature_gfx; uint16_t average_temperature_soc; uint16_t average_temperature_core[8]; uint16_t average_temperature_l3[2]; /* Power/Voltage (unit: mV) */ uint16_t average_cpu_voltage; uint16_t average_soc_voltage; uint16_t average_gfx_voltage; /* Power/Current (unit: mA) */ uint16_t average_cpu_current; uint16_t average_soc_current; uint16_t average_gfx_current; }; struct gpu_metrics_v3_0 { struct metrics_table_header common_header; /* Temperature */ /* gfx temperature on APUs */ uint16_t temperature_gfx; /* soc temperature on APUs */ uint16_t temperature_soc; /* CPU core temperature on APUs */ uint16_t temperature_core[16]; /* skin temperature on APUs */ uint16_t temperature_skin; /* Utilization */ /* time filtered GFX busy % [0-100] */ uint16_t average_gfx_activity; /* time filtered VCN busy % [0-100] */ uint16_t average_vcn_activity; /* time filtered IPU per-column busy % [0-100] */ uint16_t average_ipu_activity[8]; /* time filtered per-core C0 residency % [0-100]*/ uint16_t average_core_c0_activity[16]; /* time filtered DRAM read bandwidth [MB/sec] */ uint16_t average_dram_reads; /* time filtered DRAM write bandwidth [MB/sec] */ uint16_t average_dram_writes; /* time filtered IPU read bandwidth [MB/sec] */ uint16_t average_ipu_reads; /* time filtered IPU write bandwidth [MB/sec] */ uint16_t average_ipu_writes; /* Driver attached timestamp (in ns) */ uint64_t system_clock_counter; /* Power/Energy */ /* time filtered power used for PPT/STAPM [APU+dGPU] [mW] */ uint32_t average_socket_power; /* time filtered IPU power [mW] */ uint16_t average_ipu_power; /* time filtered APU power [mW] */ uint32_t average_apu_power; /* time filtered GFX power [mW] */ uint32_t average_gfx_power; /* time filtered dGPU power [mW] */ uint32_t average_dgpu_power; /* time filtered sum of core power across all cores in the socket [mW] */ uint32_t average_all_core_power; /* calculated core power [mW] */ uint16_t average_core_power[16]; /* time filtered total system power [mW] */ uint16_t average_sys_power; /* maximum IRM defined STAPM power limit [mW] */ uint16_t stapm_power_limit; /* time filtered STAPM power limit [mW] */ uint16_t current_stapm_power_limit; /* time filtered clocks [MHz] */ uint16_t average_gfxclk_frequency; uint16_t average_socclk_frequency; uint16_t average_vpeclk_frequency; uint16_t average_ipuclk_frequency; uint16_t average_fclk_frequency; uint16_t average_vclk_frequency; uint16_t average_uclk_frequency; uint16_t average_mpipu_frequency; /* Current clocks */ /* target core frequency [MHz] */ uint16_t current_coreclk[16]; /* CCLK frequency limit enforced on classic cores [MHz] */ uint16_t current_core_maxfreq; /* GFXCLK frequency limit enforced on GFX [MHz] */ uint16_t current_gfx_maxfreq; /* Throttle Residency (ASIC dependent) */ uint32_t throttle_residency_prochot; uint32_t throttle_residency_spl; uint32_t throttle_residency_fppt; uint32_t throttle_residency_sppt; uint32_t throttle_residency_thm_core; uint32_t throttle_residency_thm_gfx; uint32_t throttle_residency_thm_soc; /* Metrics table alpha filter time constant [us] */ uint32_t time_filter_alphavalue; }; struct amdgpu_files { FILE *vram_total; FILE *vram_used; /* The following can be NULL, in that case we're using the gpu_metrics node */ FILE *busy; FILE *temp; FILE *junction_temp; FILE *memory_temp; FILE *core_clock; FILE *memory_clock; FILE *power_usage; FILE *power_limit; FILE *gtt_used; FILE *fan; FILE *gpu_voltage_soc; }; /* This structure is used to communicate the latest values of the amdgpu metrics. * The direction of communication is amdgpu_polling_thread -> amdgpu_get_metrics(). */ struct amdgpu_common_metrics { /* Load level: averaged across the sampling period */ uint16_t gpu_load_percent; // uint16_t mem_load_percent; /* Power usage: averaged across the sampling period */ float average_gfx_power_w; float average_cpu_power_w; /* Clocks: latest value of the clock */ uint16_t current_gfxclk_mhz; uint16_t current_uclk_mhz; /* Temperatures: maximum values over the sampling period */ uint16_t soc_temp_c; uint16_t gpu_temp_c; uint16_t apu_cpu_temp_c; /* throttling status */ bool is_power_throttled; bool is_current_throttled; bool is_temp_throttled; bool is_other_throttled; uint16_t fan_speed; }; extern std::string metrics_path; class AMDGPU { public: bool is_apu = false; std::shared_ptr throttling; AMDGPU(std::string pci_dev, uint32_t device_id, uint32_t vendor_id); ~AMDGPU() { stop_thread = true; if (thread.joinable()) thread.join(); } void get_instant_metrics(struct amdgpu_common_metrics *metrics); void get_samples_and_copy(struct amdgpu_common_metrics metrics_buffer[METRICS_SAMPLE_COUNT], bool &gpu_load_needs_dividing); gpu_metrics copy_metrics() { std::lock_guard lock(metrics_mutex); return metrics; }; void pause() { paused = true; cond_var.notify_one(); }; void resume() { paused = false; cond_var.notify_one(); } private: std::string pci_dev; std::string gpu_metrics_path; uint32_t device_id; uint32_t vendor_id; std::condition_variable amdgpu_c; std::thread thread; struct amdgpu_files sysfs_nodes = {}; bool gpu_metrics_is_valid = false; std::condition_variable cond_var; std::atomic stop_thread{false}; std::atomic paused{false}; std::mutex metrics_mutex; gpu_metrics metrics; struct amdgpu_common_metrics amdgpu_common_metrics; struct gpu_metrics_v3_0 previous_metrics{}; #define V3_THROTTLING_DELTA(name) \ ((amdgpu_metrics)->throttle_residency_##name - (previous_metrics).throttle_residency_##name) #ifndef TEST_ONLY std::unique_ptr fdinfo_helper; #endif void get_sysfs_metrics(); void metrics_polling_thread(); }; ================================================ FILE: src/app/control.c ================================================ #include #include #include #include #include #include #include "mangoapp_proto.h" static void help_and_quit() { fprintf(stderr, "Usage: mangohudctl [set|toggle] attribute [value]\n"); fprintf(stderr, " mangohudctl reload-cfg\n"); fprintf(stderr, "Attributes:\n"); fprintf(stderr, " no_display hides or shows hud\n"); fprintf(stderr, " log_session handles logging status\n"); fprintf(stderr, " reload_config reloads the config\n"); fprintf(stderr, "Accepted values:\n"); fprintf(stderr, " true\n"); fprintf(stderr, " false\n"); fprintf(stderr, " 1\n"); fprintf(stderr, " 0\n"); exit(1); } static bool str_to_bool(const char *value) { if (strcasecmp(value, "true") == 0 || strcmp(value, "1") == 0) return true; else if (strcasecmp(value, "false") == 0 || strcmp(value, "0") == 0) return false; /* invalid boolean, display a nice error message saying that */ fprintf(stderr, "The value '%s' is not an accepted boolean. Use 0/1 or true/false\n", value); exit(1); } int main(int argc, char *argv[]) { /* Set up message queue */ int key = ftok("mangoapp", 65); int msgid = msgget(key, 0666 | IPC_CREAT); /* Create the message that we will send to mangohud */ struct mangoapp_ctrl_msgid1_v1 ctrl_msg = { .hdr.msg_type = 2, .hdr.ctrl_msg_type = 1, .hdr.version = 1, }; uint8_t value; if (argc <= 2) help_and_quit(); if (strcmp(argv[1], "set") == 0) { if (argc != 4) help_and_quit(); value = str_to_bool(argv[3]) ? 1 : 2; } else if (strcmp(argv[1], "toggle") == 0) { if (argc != 3) help_and_quit(); value = 3; } else { help_and_quit(); } if (strcmp(argv[2], "no_display") == 0) ctrl_msg.no_display = value; else if (strcmp(argv[2], "log_session") == 0) ctrl_msg.log_session = value; else if (strcmp(argv[2], "reload_config") == 0) ctrl_msg.reload_config = value; else help_and_quit(); msgsnd(msgid, &ctrl_msg, sizeof(struct mangoapp_ctrl_msgid1_v1), IPC_NOWAIT); return 0; } ================================================ FILE: src/app/main.cpp ================================================ // Dear ImGui: standalone example application for GLFW + OpenGL 3, using programmable pipeline // (GLFW is a cross-platform general purpose library for handling windows, inputs, OpenGL/Vulkan/Metal graphics context creation, etc.) // If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp. // Read online: https://github.com/ocornut/imgui/tree/master/docs #include #include #include "imgui.h" #include "imgui_impl_glfw.h" #include "imgui_impl_opengl3.h" #include #include #include #include "../overlay.h" #include "notify.h" #include "mangoapp.h" #include "mangoapp_proto.h" #include #ifdef __linux__ #include "implot.h" #endif #define GLFW_EXPOSE_NATIVE_X11 #include #include #include #include using namespace std; static void glfw_error_callback(int error, const char* description) { fprintf(stderr, "Glfw Error %d: %s\n", error, description); } swapchain_stats sw_stats {}; overlay_params params {}; static ImVec2 window_size; static uint32_t vendorID; static std::string deviceName; static notify_thread notifier; static int msgid; static bool mangoapp_paused = false; std::mutex mangoapp_m; std::condition_variable mangoapp_cv; static uint8_t raw_msg[1024] = {0}; static uint32_t screenWidth, screenHeight; static std::atomic_bool g_x_dead{false}; static bool x_connection_ok(Display* dpy) { if (!dpy) return false; int fd = XConnectionNumber(dpy); if (fd < 0) return false; pollfd p{fd, 0, 0}; if (poll(&p, 1, 0) < 0) return false; return (p.revents & (POLLERR | POLLHUP | POLLNVAL)) == 0; } static unsigned int get_prop(const char* propName){ if (g_x_dead.load()) return -1; Display *x11_display = glfwGetX11Display(); // Make sure Xorg display is still there before continuing if (!x_connection_ok(x11_display)) { g_x_dead.store(true); return -1; } Atom gamescope_focused = XInternAtom(x11_display, propName, false); auto scr = DefaultScreen(x11_display); auto root = RootWindow(x11_display, scr); Atom actual; int format; unsigned long n, left; uint64_t *data; int result = XGetWindowProperty(x11_display, root, gamescope_focused, 0L, 1L, false, XA_CARDINAL, &actual, &format, &n, &left, ( unsigned char** )&data); if (result == Success && data != NULL){ unsigned int i; memcpy(&i, data, sizeof(unsigned int)); XFree((void *) data); return i; } return -1; } static void ctrl_thread(){ while (1){ const struct mangoapp_ctrl_msgid1_v1 *mangoapp_ctrl_v1 = (const struct mangoapp_ctrl_msgid1_v1*) raw_msg; memset(raw_msg, 0, sizeof(raw_msg)); msgrcv(msgid, (void *) raw_msg, sizeof(raw_msg), 2, 0); switch (mangoapp_ctrl_v1->log_session) { case 0: // Keep as-is break; case 1: if (!logger->is_active()) logger->start_logging(); break; case 2: if (logger->is_active()) logger->stop_logging(); break; case 3: logger->is_active() ? logger->stop_logging() : logger->start_logging(); break; } switch (mangoapp_ctrl_v1->reload_config) { case 0: break; case 1: parse_overlay_config(¶ms, getenv("MANGOHUD_CONFIG"), false); break; case 2: break; case 3: parse_overlay_config(¶ms, getenv("MANGOHUD_CONFIG"), false); break; } { std::lock_guard lk(mangoapp_m); auto real_params = get_params(); switch (mangoapp_ctrl_v1->no_display){ case 0: // Keep as-is break; case 1: real_params->no_display = 1; break; case 2: real_params->no_display = 0; break; case 3: real_params->no_display ? real_params->no_display = 0 : real_params->no_display = 1; break; } } mangoapp_cv.notify_one(); } } bool new_frame = false; static void gamescope_frametime(uint64_t app_frametime_ns, uint64_t latency_ns){ if (app_frametime_ns != uint64_t(-1)) { float app_frametime_ms = app_frametime_ns / 1000000.f; HUDElements.gamescope_debug_app.push_back(app_frametime_ms); if (HUDElements.gamescope_debug_app.size() > 200) HUDElements.gamescope_debug_app.erase(HUDElements.gamescope_debug_app.begin()); } float latency_ms = latency_ns / 1000000.f; if (latency_ns == uint64_t(-1)) latency_ms = -1; HUDElements.gamescope_debug_latency.push_back(latency_ms); if (HUDElements.gamescope_debug_latency.size() > 200) HUDElements.gamescope_debug_latency.erase(HUDElements.gamescope_debug_latency.begin()); } static void msg_read_thread(){ for (size_t i = 0; i < 200; i++){ HUDElements.gamescope_debug_app.push_back(0); HUDElements.gamescope_debug_latency.push_back(0); } int key = ftok("mangoapp", 65); msgid = msgget(key, 0666 | IPC_CREAT); // uint32_t previous_pid = 0; const struct mangoapp_msg_header *hdr = (const struct mangoapp_msg_header*) raw_msg; const struct mangoapp_msg_v1 *mangoapp_v1 = (const struct mangoapp_msg_v1*) raw_msg; uint32_t previous_game_pid = 0; while (1){ // make sure that the message recieved is compatible // and that we're not trying to use variables that don't exist (yet) size_t msg_size = msgrcv(msgid, (void *) raw_msg, sizeof(raw_msg), 1, 0); if (msg_size != size_t(-1)) { if (hdr->version == 1){ if (msg_size > offsetof(struct mangoapp_msg_v1, pid)) { HUDElements.g_gamescopePid = mangoapp_v1->pid; if (previous_game_pid != mangoapp_v1->pid) { previous_game_pid = mangoapp_v1->pid; check_for_vkbasalt_and_gamemode(); } } if (msg_size > offsetof(struct mangoapp_msg_v1, visible_frametime_ns)){ auto real_params = get_params(); bool should_new_frame = false; if (mangoapp_v1->visible_frametime_ns != ~(0lu) && (!real_params->no_display || logger->is_active())) { update_hud_info_with_frametime(sw_stats, params, vendorID, mangoapp_v1->visible_frametime_ns); should_new_frame = true; } if (msg_size > offsetof(mangoapp_msg_v1, fsrUpscale)){ HUDElements.g_fsrUpscale = mangoapp_v1->fsrUpscale; if (real_params->fsr_steam_sharpness < 0) HUDElements.g_fsrSharpness = mangoapp_v1->fsrSharpness; else HUDElements.g_fsrSharpness = real_params->fsr_steam_sharpness - mangoapp_v1->fsrSharpness; } if (!real_params->enabled[OVERLAY_PARAM_ENABLED_mangoapp_steam]){ steam_focused = get_prop("GAMESCOPE_FOCUSED_APP_GFX") == 769; } else { steam_focused = false; } if (msg_size > offsetof(mangoapp_msg_v1, latency_ns)) gamescope_frametime(mangoapp_v1->app_frametime_ns, mangoapp_v1->latency_ns); if (should_new_frame) { { std::unique_lock lk(mangoapp_m); new_frame = true; } mangoapp_cv.notify_one(); screenWidth = mangoapp_v1->outputWidth; screenHeight = mangoapp_v1->outputHeight; } } } else { printf("Unsupported mangoapp struct version: %i\n", hdr->version); } } else { printf("mangoapp: msgrcv returned -1 with error %d - %s\n", errno, strerror(errno)); } } } static const char *GamescopeOverlayProperty = "GAMESCOPE_EXTERNAL_OVERLAY"; static GLFWwindow* init(const char* glsl_version){ init_spdlog(); GLFWwindow *window = glfwCreateWindow(1280, 800, "mangoapp overlay window", NULL, NULL); Display *x11_display = glfwGetX11Display(); Window x11_window = glfwGetX11Window(window); if (x11_window && x11_display) { // Set atom for gamescope to render as an overlay. Atom overlay_atom = XInternAtom (x11_display, GamescopeOverlayProperty, False); uint32_t value = 1; XChangeProperty(x11_display, x11_window, overlay_atom, XA_CARDINAL, 32, PropertyNewValue, (unsigned char *)&value, 1); } glfwMakeContextCurrent(window); glfwSwapInterval(1); // Enable vsync ImGui::CreateContext(); #ifdef __linux__ ImPlot::CreateContext(); #endif ImGuiIO& io = ImGui::GetIO(); (void)io; io.IniFilename = NULL; ImGui::StyleColorsDark(); ImGui_ImplGlfw_InitForOpenGL(window, true); ImGui_ImplOpenGL3_Init(glsl_version); return window; } static void shutdown(GLFWwindow* window){ ImGui_ImplOpenGL3_Shutdown(); ImGui_ImplGlfw_Shutdown(); ImGui::DestroyContext(); glfwDestroyWindow(window); } static void get_atom_info(){ HUDElements.hdr_status = get_prop("GAMESCOPE_COLOR_APP_WANTS_HDR_FEEDBACK"); HUDElements.refresh = get_prop("GAMESCOPE_DISPLAY_REFRESH_RATE_FEEDBACK"); } static bool render(GLFWwindow* window, overlay_params& real_params) { if (HUDElements.colors.update) HUDElements.convert_colors(params); if (sw_stats.font_params_hash != params.font_params_hash) { sw_stats.font_params_hash = params.font_params_hash; create_fonts(nullptr, params, sw_stats.font_small, sw_stats.font_text, sw_stats.font_secondary); ImGui_ImplOpenGL3_CreateFontsTexture(); } ImGui_ImplGlfw_NewFrame(); ImGui_ImplOpenGL3_NewFrame(); ImGui::NewFrame(); overlay_new_frame(real_params); position_layer(sw_stats, real_params, window_size); render_imgui(sw_stats, real_params, window_size, true); get_atom_info(); overlay_end_frame(); static bool window_size_changed = false; int w, h; glfwGetWindowSize(window, &w, &h); window_size_changed = w != window_size.x || h != window_size.y; if (real_params.enabled[OVERLAY_PARAM_ENABLED_horizontal]) // trying to reduce height will break direct scanout in some cases // just leave it for now, we'll revisit it in server glfwSetWindowSize(window, screenWidth, screenHeight); ImGui::EndFrame(); return window_size_changed; } int main(int, char**) { XInitThreads(); // Setup window glfwSetErrorCallback(glfw_error_callback); if (!glfwInit()) return 1; const char* glsl_version = "#version 130"; glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0); glfwWindowHint(GLFW_RESIZABLE, 1); glfwWindowHint(GLFW_TRANSPARENT_FRAMEBUFFER, 1); glfwWindowHint(GLFW_DEPTH_BITS, 0); glfwWindowHint(GLFW_STENCIL_BITS, 0); // Create window with graphics context GLFWwindow* window = init(glsl_version); Display *x11_display = glfwGetX11Display(); Window x11_window = glfwGetX11Window(window); Atom overlay_atom = XInternAtom (x11_display, GamescopeOverlayProperty, False); // Setup Platform/Renderer backends int control_client = -1; parse_overlay_config(¶ms, getenv("MANGOHUD_CONFIG"), false); create_fonts(nullptr, params, sw_stats.font_small, sw_stats.font_text, sw_stats.font_secondary); HUDElements.convert_colors(params); init_cpu_stats(params); notifier.params = ¶ms; start_notifier(notifier); auto real_params = get_params(); window_size = ImVec2(real_params->width, real_params->height); deviceName = (char*)glGetString(GL_RENDERER); sw_stats.deviceName = deviceName; SPDLOG_DEBUG("mangoapp deviceName: {}", deviceName); #define GLX_RENDERER_VENDOR_ID_MESA 0x8183 auto pfn_glXQueryCurrentRendererIntegerMESA = (Bool (*)(int, unsigned int*)) (glfwGetProcAddress("glXQueryCurrentRendererIntegerMESA")); // This will return 0x0 vendorID on NVIDIA so just go to else if (pfn_glXQueryCurrentRendererIntegerMESA && vendorID != 0x0) { pfn_glXQueryCurrentRendererIntegerMESA(GLX_RENDERER_VENDOR_ID_MESA, &vendorID); SPDLOG_DEBUG("mangoapp vendorID: {:#x}", vendorID); } else { if (deviceName.find("Radeon") != std::string::npos || deviceName.find("AMD") != std::string::npos){ vendorID = 0x1002; } else if (deviceName.find("Intel") != std::string::npos) { vendorID = 0x8086; } else { vendorID = 0x10de; } } HUDElements.vendorID = vendorID; init_system_info(); sw_stats.engine = EngineTypes::GAMESCOPE; std::thread(msg_read_thread).detach(); std::thread(ctrl_thread).detach(); if (!logger) logger = std::make_unique(¶ms); Atom noFocusAtom = XInternAtom(x11_display, "GAMESCOPE_NO_FOCUS", False); uint32_t value = 1; XChangeProperty(x11_display, x11_window, noFocusAtom, XA_CARDINAL, 32, PropModeReplace, (unsigned char *)&value, 1); // Main loop while (!glfwWindowShouldClose(window)){ real_params = get_params(); check_keybinds(*real_params); if (!real_params->no_display && new_frame){ if (mangoapp_paused){ glfwShowWindow(window); render(window, *real_params); uint32_t value = 1; XChangeProperty(x11_display, x11_window, overlay_atom, XA_CARDINAL, 32, PropModeReplace, (unsigned char *)&value, 1); XSync(x11_display, 0); mangoapp_paused = false; // resume all GPU threads if (gpus) for (auto gpu : gpus->available_gpus) gpu->resume(); } { if (render(window, *real_params)) { // If we need to resize our window, give it another couple of rounds for the // stupid display size stuff to propagate through ImGUI (using NDC and scaling // in GL makes me a very unhappy boy.) render(window, *real_params); render(window, *real_params); } if (real_params->control >= 0) { control_client_check(real_params->control, control_client, deviceName); process_control_socket(control_client, params); } } // Rendering ImGui::Render(); glEnable(GL_DEPTH_TEST); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glClearColor(0, 0, 0, 0); glClear(GL_COLOR_BUFFER_BIT); ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); glfwSwapBuffers(window); } else if (!mangoapp_paused) { glClearColor(0, 0, 0, 0); glClear(GL_COLOR_BUFFER_BIT); glfwSwapBuffers(window); glfwHideWindow(window); uint32_t value = 0; XChangeProperty(x11_display, x11_window, overlay_atom, XA_CARDINAL, 32, PropModeReplace, (unsigned char *)&value, 1); XSync(x11_display, 0); mangoapp_paused = true; // pause all GPUs threads if (gpus) for (auto gpu : gpus->available_gpus) gpu->pause(); // If mangoapp is hidden, using mangoapp_cv.wait() causes a hang. // Because of this hang, we can't detect if the user presses R_SHIFT + F12, // which prevents mangoapp from being unhidden. // To address this, replace mangoapp_cv.wait() with sleep(). // // If severe power usage issues arise, find an alternative solution. // std::unique_lock lk(mangoapp_m); // mangoapp_cv.wait(lk, []{return !get_params()->no_display;}); } else { usleep(500000); } } // Cleanup shutdown(window); glfwTerminate(); return 0; } ================================================ FILE: src/app/mangoapp.h ================================================ #pragma once #include #include #include #include extern std::mutex mangoapp_m; extern std::condition_variable mangoapp_cv; ================================================ FILE: src/app/mangoapp_proto.h ================================================ #include struct mangoapp_msg_header { long msg_type; // Message queue ID, never change uint32_t version; /* for major changes in the way things work */ } __attribute__((packed)); struct mangoapp_msg_v1 { struct mangoapp_msg_header hdr; uint32_t pid; uint64_t visible_frametime_ns; uint8_t fsrUpscale; uint8_t fsrSharpness; // For debugging uint64_t app_frametime_ns; uint64_t latency_ns; uint32_t outputWidth; uint32_t outputHeight; // WARNING: Always ADD fields, never remove or repurpose fields } __attribute__((packed)); struct mangoapp_ctrl_header { long msg_type; // Message queue ID, never change uint32_t ctrl_msg_type; /* This is a way to share the same thread between multiple types of messages */ uint32_t version; /* version of the message type, for backwards incompatible changes */ } __attribute__((packed)); struct mangoapp_ctrl_msgid1_v1 { struct mangoapp_ctrl_header hdr; // When a field is set to 0, it should always mean "ignore" or "no changes" uint8_t no_display; // 0x0 = ignore; 0x1 = disable; 0x2 = enable; 0x3 = toggle uint8_t log_session; // 0x0 = ignore; 0x1 = start a session; 0x2 = stop the current session; 0x3 = toggle logging char log_session_name[64]; // if byte 0 is NULL, ignore. Needs to be set when starting/toggling a session if we want to override the default name uint8_t reload_config; // WARNING: Always ADD fields, never remove or repurpose fields } __attribute__((packed)); ================================================ FILE: src/battery.cpp ================================================ #include #include #include "battery.h" namespace fs = ghc::filesystem; using namespace std; void BatteryStats::numBattery() { int batteryCount = 0; if (!fs::exists("/sys/class/power_supply/")) { batteryCount = 0; } fs::path path("/sys/class/power_supply/"); for (auto& p : fs::directory_iterator(path)) { string fileName = p.path().filename(); if (fileName.find("BAT") != std::string::npos) { battPath[batteryCount] = p.path(); batteryCount += 1; } } batt_count = batteryCount; batt_check = true; } void BatteryStats::update() { if (!batt_check) { numBattery(); if (batt_count == 0) { SPDLOG_ERROR("No battery found"); } } if (batt_count > 0) { current_watt = getPower(); current_percent = getPercent(); remaining_time = getTimeRemaining(); } } float BatteryStats::getPercent() { float charge_n = 0; float charge_f = 0; for(int i = 0; i < batt_count; i++) { string syspath = battPath[i]; string charge_now = syspath + "/charge_now"; string charge_full = syspath + "/charge_full"; string energy_now = syspath + "/energy_now"; string energy_full = syspath + "/energy_full"; string capacity = syspath + "/capacity"; if (fs::exists(charge_now)) { std::ifstream input(charge_now); std::string line; if(std::getline(input, line)) { charge_n += (stof(line) / 1000000); } std::ifstream input2(charge_full); if(std::getline(input2, line)) { charge_f += (stof(line) / 1000000); } } else if (fs::exists(energy_now)) { std::ifstream input(energy_now); std::string line; if(std::getline(input, line)) { charge_n += (stof(line) / 1000000); } std::ifstream input2(energy_full); if(std::getline(input2, line)) { charge_f += (stof(line) / 1000000); } } else { // using /sys/class/power_supply/BAT*/capacity // No way to get an accurate reading just average the percents if mutiple batteries std::ifstream input(capacity); std::string line; if(std::getline(input, line)) { charge_n += stof(line) / 100; charge_f = batt_count; } } } return (charge_n / charge_f) * 100; } float BatteryStats::getPower() { float power_w = 0.0f; for (int i = 0; i < batt_count; i++) { string syspath = battPath[i]; string current_now = syspath + "/current_now"; string voltage_now = syspath + "/voltage_now"; string power_now = syspath + "/power_now"; string status = syspath + "/status"; { std::ifstream input(status); std::string line; if (std::getline(input, line)) { current_status = line; state[i] = current_status; } } if (state[i] == "Charging" || state[i] == "Unknown" || state[i] == "Full") { // TODO if we have multiple batteries, we will return 0 if just one of them is charging return 0.0f; } // Prefer power_now (µW) when available. if (fs::exists(power_now)) { std::ifstream input(power_now); std::string line; if (std::getline(input, line)) { power_w += std::fabs(stof(line)) / 1000000.0f; } continue; } if (fs::exists(current_now) && fs::exists(voltage_now)) { float i_ua = 0.0f; float v_uv = 0.0f; { std::ifstream input(current_now); std::string line; if (std::getline(input, line)) { i_ua = stof(line); } } { std::ifstream input(voltage_now); std::string line; if (std::getline(input, line)) { v_uv = stof(line); } } power_w += (std::fabs(i_ua) * std::fabs(v_uv)) * 1e-12f; } } return power_w; } float BatteryStats::getTimeRemaining() { float current = 0.0f; float charge = 0.0f; for (int i = 0; i < batt_count; i++) { string syspath = battPath[i]; string current_now = syspath + "/current_now"; string charge_now = syspath + "/charge_now"; string energy_now = syspath + "/energy_now"; string voltage_now = syspath + "/voltage_now"; string power_now = syspath + "/power_now"; if (fs::exists(current_now)) { std::ifstream input(current_now); std::string line; if (std::getline(input, line)) { current_now_vec.push_back(std::fabs(stof(line))); } } else if (fs::exists(power_now) && fs::exists(voltage_now)) { float voltage = 0.0f; float power = 0.0f; { std::ifstream input_voltage(voltage_now); std::string line; if (std::getline(input_voltage, line)) { voltage = stof(line); } } { std::ifstream input_power(power_now); std::string line; if (std::getline(input_power, line)) { power = stof(line); } } if (voltage > 0.0f) { // (µW / µV) = µA current_now_vec.push_back(std::fabs(power) / voltage); } } if (fs::exists(charge_now)) { std::ifstream input(charge_now); std::string line; if (std::getline(input, line)) { charge += stof(line); } } else if (fs::exists(energy_now) && fs::exists(voltage_now)) { float energy = 0.0f; float voltage = 0.0f; { std::ifstream input_energy(energy_now); std::string line; if (std::getline(input_energy, line)) { energy = stof(line); } } { std::ifstream input_voltage(voltage_now); std::string line; if (std::getline(input_voltage, line)) { voltage = stof(line); } } if (voltage > 0.0f) { // (µWh / µV) = µAh charge += energy / voltage; } } if (current_now_vec.size() > 25) { current_now_vec.erase(current_now_vec.begin()); } } if (current_now_vec.empty()) { return 0.0f; } for (const auto& current_now_sample : current_now_vec) { current += current_now_sample; } current /= static_cast(current_now_vec.size()); if (current <= 0.0f) { return 0.0f; } return charge / current; } BatteryStats Battery_Stats; ================================================ FILE: src/battery.h ================================================ #pragma once #include class BatteryStats{ public: void numBattery(); void update(); float getPower(); float getPercent(); float getTimeRemaining(); std::string battPath[2]; float current_watt = 0; float current_percent = 0; float remaining_time = 0; std::string current_status; std::string state [2]; int batt_count=0; bool batt_check = false; std::vector current_now_vec = {}; }; extern BatteryStats Battery_Stats; ================================================ FILE: src/blacklist.cpp ================================================ #include #include #include #include #include #include "blacklist.h" #include "string_utils.h" #include "file_utils.h" namespace fs = ghc::filesystem; std::string global_proc_name; std::string global_engine_name; static std::string get_proc_name() { // Note: It is possible to use GNU program_invocation_short_name. const std::string proc_name = get_wine_exe_name(/*keep_ext=*/true); if (!proc_name.empty()) { return proc_name; } return get_basename(get_exe_path()); } static std::vector blacklist { "Amazon Games UI.exe", "Battle.net.exe", "BethesdaNetLauncher.exe", "EADesktop.exe", "EALauncher.exe", "EpicGamesLauncher.exe", "EpicWebHelper.exe", "explorer.exe", "ffxivlauncher.exe", "ffxivlauncher64.exe", "GalaxyClient.exe", "gamescope", "GardenGate_Launcher.exe", "gldriverquery", "halloy", "IGOProxy.exe", "IGOProxy64.exe", "iexplore.exe", "InsurgencyEAC.exe", "Launcher", //Paradox Interactive Launcher "LeagueClient.exe", "LeagueClientUxRender.exe", "MarneLauncher.exe", "MarvelRivals_Launcher.exe", "monado-service", "Origin.exe", "OriginThinSetupInternal.exe", "plutonium.exe", "plutonium-launcher-win32.exe", "REDlauncher.exe", "REDprelauncher.exe", "RSI Launcher.exe", "rundll32.exe", "SocialClubHelper.exe", "StarCitizen_Launcher.exe", "steam", "Steam.exe", "steamwebhelper", "steamwebhelper.exe", "tabtip.exe", "UplayWebCore.exe", "vrcompositor", "vulkandriverquery", }; static std::vector blacklist_engine { "GTK" }; static bool check_blacklisted() { std::string proc_name = get_proc_name(); std::string engine_name = global_engine_name; global_proc_name = proc_name; bool blacklisted = std::find(blacklist.begin(), blacklist.end(), proc_name) != blacklist.end(); blacklisted |= std::find(blacklist_engine.begin(), blacklist_engine.end(), engine_name) != blacklist_engine.end(); static bool printed = false; if(blacklisted && !printed) { printed = true; SPDLOG_INFO("process '{}' is blacklisted in MangoHud", proc_name); } return blacklisted; } bool is_blacklisted(bool force_recheck) { static bool blacklisted = check_blacklisted(); if (force_recheck) blacklisted = check_blacklisted(); return blacklisted; } void add_blacklist(const std::string& new_item) { // check if item exits in blacklist before adding new item if(std::find(blacklist.begin(), blacklist.end(), new_item) != blacklist.end()) { return; } blacklist.push_back (new_item); is_blacklisted(true); } ================================================ FILE: src/blacklist.h ================================================ #pragma once #ifndef MANGOHUD_BLACKLIST_H #define MANGOHUD_BLACKLIST_H #include bool is_blacklisted(bool force_recheck = false); void add_blacklist(const std::string& proc); extern std::string global_proc_name; extern std::string global_engine_name; #endif //MANGOHUD_BLACKLIST_H ================================================ FILE: src/config.cpp ================================================ #include #include #include #include #include #include #include #include #include "config.h" #include "file_utils.h" #include "string_utils.h" #include "hud_elements.h" #include "blacklist.h" void parseConfigLine(std::string line, std::unordered_map& options) { std::string param, value; if (line.find("#") != std::string::npos) line = line.erase(line.find("#"), std::string::npos); size_t equal = line.find("="); if (equal == std::string::npos) value = "1"; else value = line.substr(equal+1); param = line.substr(0, equal); trim(param); trim(value); if (!param.empty()){ HUDElements.options.push_back({param, value}); options[param] = value; } } static std::string get_program_dir() { const std::string exe_path = get_exe_path(); if (exe_path.empty()) { return std::string(); } const auto n = exe_path.find_last_of('/'); if (n != std::string::npos) { return exe_path.substr(0, n); } return std::string(); } std::string get_program_name() { const std::string exe_path = get_exe_path(); std::string basename = "unknown"; if (exe_path.empty()) { return basename; } const auto n = exe_path.find_last_of('/'); if (n == std::string::npos) { return basename; } if (n < exe_path.size() - 1) { // An executable's name. basename = exe_path.substr(n + 1); } return basename; } static void enumerate_config_files(std::vector& paths) { static const char *mangohud_dir = "/MangoHud/"; const std::string data_dir = get_data_dir(); const std::string config_dir = get_config_dir(); const std::string program_name = get_program_name(); if (config_dir.empty()) { // If we can't find 'HOME' just abandon hope. return; } paths.push_back(config_dir + mangohud_dir + "MangoHud.conf"); paths.push_back("/etc/MangoHud.conf"); if (is_blacklisted()) { // Don't bother looking for conf file return; } if (!program_name.empty()) { paths.push_back(config_dir + mangohud_dir + program_name + ".conf"); } const std::string program_dir = get_program_dir(); if (!program_dir.empty()) { paths.push_back(program_dir + "/MangoHud.conf"); } const std::string wine_program_name = get_wine_exe_name(); if (!wine_program_name.empty()) { paths.push_back(config_dir + mangohud_dir + "wine-" + wine_program_name + ".conf"); } } void parseConfigFile(overlay_params& params) { std::vector paths; const char *cfg_file = getenv("MANGOHUD_CONFIGFILE"); if (cfg_file) paths.push_back(cfg_file); else enumerate_config_files(paths); #ifdef _WIN32 paths.push_back("C:\\mangohud\\MangoHud.conf"); #endif std::string line; for (auto p = paths.rbegin(); p != paths.rend(); p++) { std::ifstream stream(*p); if (!stream.good()) { // printing just so user has an idea of possible configs SPDLOG_DEBUG("skipping config: '{}' [ not found ]", *p); continue; } stream.imbue(std::locale::classic()); SPDLOG_DEBUG("parsing config: '{}'", *p); while (std::getline(stream, line)) { parseConfigLine(line, params.options); } params.config_file_path = *p; return; } } ================================================ FILE: src/config.h ================================================ #pragma once #ifndef MANGOHUD_CONFIG_H #define MANGOHUD_CONFIG_H #include "overlay_params.h" #include void parseConfigFile(overlay_params& p); std::string get_program_name(); void parseConfigLine(std::string line, std::unordered_map& options); #endif //MANGOHUD_CONFIG_H ================================================ FILE: src/control.cpp ================================================ #include #include #include #include #include #include "mesa/util/os_socket.h" #include "overlay.h" #include "version.h" #include "app/mangoapp.h" int global_control_client; using namespace std; static void parse_command(overlay_params ¶ms, const char *cmd, unsigned cmdlen, const char *param, unsigned paramlen) { if (!strncmp(cmd, "hud", cmdlen)) { get_params()->no_display = !get_params()->no_display; } else if (!strncmp(cmd, "logging", cmdlen)) { if (param && param[0]) { int value = atoi(param); if (!value && logger->is_active()) logger->stop_logging(); else if (value > 0 && !logger->is_active()) logger->start_logging(); } else { if (logger->is_active()) logger->stop_logging(); else logger->start_logging(); } } else if (!strncmp(cmd, "fcat", cmdlen)) { params.enabled[OVERLAY_PARAM_ENABLED_fcat] = !params.enabled[OVERLAY_PARAM_ENABLED_fcat]; } } #define BUFSIZE 4096 /** * This function will process commands through the control file. * * A command starts with a colon, followed by the command, and followed by an * option '=' and a parameter. It has to end with a semi-colon. A full command * + parameter looks like: * * :cmd=param; */ static void process_char(const int control_client, overlay_params ¶ms, char c) { static char cmd[BUFSIZE]; static char param[BUFSIZE]; static unsigned cmdpos = 0; static unsigned parampos = 0; static bool reading_cmd = false; static bool reading_param = false; switch (c) { case ':': cmdpos = 0; parampos = 0; reading_cmd = true; reading_param = false; break; case ';': if (!reading_cmd) break; cmd[cmdpos++] = '\0'; param[parampos++] = '\0'; parse_command(params, cmd, cmdpos, param, parampos); reading_cmd = false; reading_param = false; break; case '=': if (!reading_cmd) break; reading_param = true; break; default: if (!reading_cmd) break; if (reading_param) { /* overflow means an invalid parameter */ if (parampos >= BUFSIZE - 1) { reading_cmd = false; reading_param = false; break; } param[parampos++] = c; } else { /* overflow means an invalid command */ if (cmdpos >= BUFSIZE - 1) { reading_cmd = false; break; } cmd[cmdpos++] = c; } } } void control_send(int control_client, const char *cmd, unsigned cmdlen, const char *param, unsigned paramlen) { unsigned msglen = 0; char buffer[BUFSIZE]; assert(cmdlen + paramlen + 3 < BUFSIZE); buffer[msglen++] = ':'; memcpy(&buffer[msglen], cmd, cmdlen); msglen += cmdlen; if (paramlen > 0) { buffer[msglen++] = '='; memcpy(&buffer[msglen], param, paramlen); msglen += paramlen; buffer[msglen++] = ';'; } os_socket_send(control_client, buffer, msglen, MSG_NOSIGNAL); } static void control_send_connection_string(int control_client, const std::string& deviceName) { const char *controlVersionCmd = "MangoHudControlVersion"; const char *controlVersionString = "1"; control_send(control_client, controlVersionCmd, strlen(controlVersionCmd), controlVersionString, strlen(controlVersionString)); const char *deviceCmd = "DeviceName"; control_send(control_client, deviceCmd, strlen(deviceCmd), deviceName.c_str(), deviceName.size()); const char *versionCmd = "MangoHudVersion"; const char *versionString = "MangoHud " MANGOHUD_VERSION; control_send(control_client, versionCmd, strlen(versionCmd), versionString, strlen(versionString)); } void control_client_check(int control, int& control_client, const std::string& deviceName) { /* Already connected, just return. */ if (control_client >= 0){ global_control_client = control_client; return; } int socket = os_socket_accept(control); if (socket == -1) { if (errno != EAGAIN && errno != EWOULDBLOCK && errno != ECONNABORTED) fprintf(stderr, "ERROR on socket: %s\n", strerror(errno)); return; } if (socket >= 0) { os_socket_block(socket, false); control_client = socket; control_send_connection_string(control_client, deviceName); } } static void control_client_disconnected(int& control_client) { os_socket_close(control_client); control_client = -1; } void process_control_socket(int& control_client, overlay_params ¶ms) { if (control_client >= 0) { char buf[BUFSIZE]; while (true) { ssize_t n = os_socket_recv(control_client, buf, BUFSIZE, 0); if (n == -1) { if (errno == EAGAIN || errno == EWOULDBLOCK) { /* nothing to read, try again later */ break; } if (errno != ECONNRESET) fprintf(stderr, "ERROR on connection: %s\n", strerror(errno)); control_client_disconnected(control_client); } else if (n == 0) { /* recv() returns 0 when the client disconnects */ control_client_disconnected(control_client); } for (ssize_t i = 0; i < n; i++) { process_char(control_client, params, buf[i]); } /* If we try to read BUFSIZE and receive BUFSIZE bytes from the * socket, there's a good chance that there's still more data to be * read, so we will try again. Otherwise, simply be done for this * iteration and try again on the next frame. */ if (n < BUFSIZE) break; } } } ================================================ FILE: src/cpu.cpp ================================================ #include "cpu.h" #include #include #include #include #include #include #include #include #include #include #include #include "string_utils.h" #include "gpu.h" #include "hud_elements.h" #ifndef TEST_ONLY #include "hud_elements.h" #endif #ifndef PROCDIR #define PROCDIR "/proc" #endif #ifndef PROCSTATFILE #define PROCSTATFILE PROCDIR "/stat" #endif #ifndef PROCMEMINFOFILE #define PROCMEMINFOFILE PROCDIR "/meminfo" #endif #ifndef PROCCPUINFOFILE #define PROCCPUINFOFILE PROCDIR "/cpuinfo" #endif #include "file_utils.h" static void calculateCPUData(CPUData& cpuData, unsigned long long int usertime, unsigned long long int nicetime, unsigned long long int systemtime, unsigned long long int idletime, unsigned long long int ioWait, unsigned long long int irq, unsigned long long int softIrq, unsigned long long int steal, unsigned long long int guest, unsigned long long int guestnice) { // Guest time is already accounted in usertime usertime = usertime - guest; nicetime = nicetime - guestnice; // Fields existing on kernels >= 2.6 // (and RHEL's patched kernel 2.4...) unsigned long long int idlealltime = idletime + ioWait; unsigned long long int systemalltime = systemtime + irq + softIrq; unsigned long long int virtalltime = guest + guestnice; unsigned long long int totaltime = usertime + nicetime + systemalltime + idlealltime + steal + virtalltime; // Since we do a subtraction (usertime - guest) and cputime64_to_clock_t() // used in /proc/stat rounds down numbers, it can lead to a case where the // integer overflow. #define WRAP_SUBTRACT(a,b) (a > b) ? a - b : 0 cpuData.userPeriod = WRAP_SUBTRACT(usertime, cpuData.userTime); cpuData.nicePeriod = WRAP_SUBTRACT(nicetime, cpuData.niceTime); cpuData.systemPeriod = WRAP_SUBTRACT(systemtime, cpuData.systemTime); cpuData.systemAllPeriod = WRAP_SUBTRACT(systemalltime, cpuData.systemAllTime); cpuData.idleAllPeriod = WRAP_SUBTRACT(idlealltime, cpuData.idleAllTime); cpuData.idlePeriod = WRAP_SUBTRACT(idletime, cpuData.idleTime); cpuData.ioWaitPeriod = WRAP_SUBTRACT(ioWait, cpuData.ioWaitTime); cpuData.irqPeriod = WRAP_SUBTRACT(irq, cpuData.irqTime); cpuData.softIrqPeriod = WRAP_SUBTRACT(softIrq, cpuData.softIrqTime); cpuData.stealPeriod = WRAP_SUBTRACT(steal, cpuData.stealTime); cpuData.guestPeriod = WRAP_SUBTRACT(virtalltime, cpuData.guestTime); cpuData.totalPeriod = WRAP_SUBTRACT(totaltime, cpuData.totalTime); #undef WRAP_SUBTRACT cpuData.userTime = usertime; cpuData.niceTime = nicetime; cpuData.systemTime = systemtime; cpuData.systemAllTime = systemalltime; cpuData.idleAllTime = idlealltime; cpuData.idleTime = idletime; cpuData.ioWaitTime = ioWait; cpuData.irqTime = irq; cpuData.softIrqTime = softIrq; cpuData.stealTime = steal; cpuData.guestTime = virtalltime; cpuData.totalTime = totaltime; if (cpuData.totalPeriod == 0) return; float total = (float)cpuData.totalPeriod; float v[4]; v[0] = cpuData.nicePeriod * 100.0f / total; v[1] = cpuData.userPeriod * 100.0f / total; /* if not detailed */ v[2] = cpuData.systemAllPeriod * 100.0f / total; v[3] = (cpuData.stealPeriod + cpuData.guestPeriod) * 100.0f / total; //cpuData.percent = std::clamp(v[0]+v[1]+v[2]+v[3], 0.0f, 100.0f); cpuData.percent = std::min(std::max(v[0]+v[1]+v[2]+v[3], 0.0f), 100.0f); } CPUStats::CPUStats() { } CPUStats::~CPUStats() { if (m_cpuTempFile) { fclose(m_cpuTempFile); m_cpuTempFile = nullptr; } } bool CPUStats::Init() { if (m_inited) return true; std::string line; std::ifstream file (PROCSTATFILE); bool first = true; m_cpuData.clear(); if (!file.is_open()) { SPDLOG_ERROR("Failed to opening " PROCSTATFILE); return false; } do { if (!std::getline(file, line)) { SPDLOG_DEBUG("Failed to read all of " PROCSTATFILE); return false; } else if (starts_with(line, "cpu")) { if (first) { first =false; continue; } CPUData cpu = {}; cpu.totalTime = 1; cpu.totalPeriod = 1; sscanf(line.c_str(), "cpu%4d ", &cpu.cpu_id); m_cpuData.push_back(cpu); } else if (starts_with(line, "btime ")) { // C++ way, kind of noisy //std::istringstream token( line ); //std::string s; //token >> s; //token >> m_boottime; // assume that if btime got read, that everything else is OK too sscanf(line.c_str(), "btime %lld\n", &m_boottime); break; } } while(true); #ifndef TEST_ONLY if (get_params()->enabled[OVERLAY_PARAM_ENABLED_core_type]) get_cpu_cores_types(); #endif m_inited = true; return UpdateCPUData(); } bool CPUStats::Reinit() { m_inited = false; return Init(); } //TODO take sampling interval into account? bool CPUStats::UpdateCPUData() { unsigned long long int usertime, nicetime, systemtime, idletime; unsigned long long int ioWait, irq, softIrq, steal, guest, guestnice; int cpuid = -1; size_t cpu_count = 0; if (!m_inited) return false; std::string line; std::ifstream file (PROCSTATFILE); bool ret = false; if (!file.is_open()) { SPDLOG_ERROR("Failed to opening " PROCSTATFILE); return false; } do { if (!std::getline(file, line)) { break; } else if (!ret && sscanf(line.c_str(), "cpu %16llu %16llu %16llu %16llu %16llu %16llu %16llu %16llu %16llu %16llu", &usertime, &nicetime, &systemtime, &idletime, &ioWait, &irq, &softIrq, &steal, &guest, &guestnice) == 10) { ret = true; calculateCPUData(m_cpuDataTotal, usertime, nicetime, systemtime, idletime, ioWait, irq, softIrq, steal, guest, guestnice); } else if (sscanf(line.c_str(), "cpu%4d %16llu %16llu %16llu %16llu %16llu %16llu %16llu %16llu %16llu %16llu", &cpuid, &usertime, &nicetime, &systemtime, &idletime, &ioWait, &irq, &softIrq, &steal, &guest, &guestnice) == 11) { //SPDLOG_DEBUG("Parsing 'cpu{}' line:{}", cpuid, line); if (!ret) { SPDLOG_DEBUG("Failed to parse 'cpu' line:{}", line); return false; } if (cpuid < 0 /* can it? */) { SPDLOG_DEBUG("Cpu id '{}' is out of bounds", cpuid); return false; } if (cpu_count + 1 > m_cpuData.size() || m_cpuData[cpu_count].cpu_id != cpuid) { SPDLOG_DEBUG("Cpu id '{}' is out of bounds or wrong index, reiniting", cpuid); return Reinit(); } CPUData& cpuData = m_cpuData[cpu_count]; calculateCPUData(cpuData, usertime, nicetime, systemtime, idletime, ioWait, irq, softIrq, steal, guest, guestnice); cpuid = -1; cpu_count++; } else { break; } } while(true); if (cpu_count < m_cpuData.size()) m_cpuData.resize(cpu_count); m_cpuPeriod = (double)m_cpuData[0].totalPeriod / m_cpuData.size(); m_updatedCPUs = true; return ret; } bool CPUStats::UpdateCoreMhz() { m_coreMhz.clear(); FILE *fp; static bool scaling_freq = true; if (scaling_freq){ for (auto& cpu : m_cpuData){ std::string path = "/sys/devices/system/cpu/cpu" + std::to_string(cpu.cpu_id) + "/cpufreq/scaling_cur_freq"; if ((fp = fopen(path.c_str(), "r"))){ int64_t temp; if (fscanf(fp, "%" PRId64, &temp) != 1) temp = 0; cpu.mhz = temp / 1000; fclose(fp); scaling_freq = true; } else { scaling_freq = false; break; } } } else { static std::ifstream cpuInfo(PROCCPUINFOFILE); static std::string row; size_t i = 0; while (std::getline(cpuInfo, row) && i < m_cpuData.size()) { if (row.find("MHz") != std::string::npos){ row = std::regex_replace(row, std::regex(R"([^0-9.])"), ""); if (!try_stoi(m_cpuData[i].mhz, row)) m_cpuData[i].mhz = 0; i++; } } } m_cpuDataTotal.cpu_mhz = 0; for (auto data : m_cpuData) if (data.mhz > m_cpuDataTotal.cpu_mhz) m_cpuDataTotal.cpu_mhz = data.mhz; return true; } bool CPUStats::ReadcpuTempFile(int& temp) { if (!m_cpuTempFile) return false; rewind(m_cpuTempFile); fflush(m_cpuTempFile); bool ret = (fscanf(m_cpuTempFile, "%d", &temp) == 1); temp = temp / 1000; return ret; } bool CPUStats::UpdateCpuTemp() { if (gpus) { for (auto gpu : gpus->available_gpus) { if (gpu->is_apu()) { m_cpuDataTotal.temp = gpu->metrics.apu_cpu_temp; return true; } } } int temp = 0; bool ret = ReadcpuTempFile(temp); m_cpuDataTotal.temp = temp; return ret; } static bool get_cpu_power_k10temp(CPUPowerData* cpuPowerData, float& power) { CPUPowerData_k10temp* powerData_k10temp = (CPUPowerData_k10temp*)cpuPowerData; if(powerData_k10temp->corePowerFile || powerData_k10temp->socPowerFile) { rewind(powerData_k10temp->corePowerFile); rewind(powerData_k10temp->socPowerFile); fflush(powerData_k10temp->corePowerFile); fflush(powerData_k10temp->socPowerFile); int corePower, socPower; if (fscanf(powerData_k10temp->corePowerFile, "%d", &corePower) != 1) goto voltagebased; if (fscanf(powerData_k10temp->socPowerFile, "%d", &socPower) != 1) goto voltagebased; power = (corePower + socPower) / 1000000; return true; } voltagebased: if (!powerData_k10temp->coreVoltageFile || !powerData_k10temp->coreCurrentFile || !powerData_k10temp->socVoltageFile || !powerData_k10temp->socCurrentFile) return false; rewind(powerData_k10temp->coreVoltageFile); rewind(powerData_k10temp->coreCurrentFile); rewind(powerData_k10temp->socVoltageFile); rewind(powerData_k10temp->socCurrentFile); fflush(powerData_k10temp->coreVoltageFile); fflush(powerData_k10temp->coreCurrentFile); fflush(powerData_k10temp->socVoltageFile); fflush(powerData_k10temp->socCurrentFile); int coreVoltage, coreCurrent; int socVoltage, socCurrent; if (fscanf(powerData_k10temp->coreVoltageFile, "%d", &coreVoltage) != 1) return false; if (fscanf(powerData_k10temp->coreCurrentFile, "%d", &coreCurrent) != 1) return false; if (fscanf(powerData_k10temp->socVoltageFile, "%d", &socVoltage) != 1) return false; if (fscanf(powerData_k10temp->socCurrentFile, "%d", &socCurrent) != 1) return false; power = (coreVoltage * coreCurrent + socVoltage * socCurrent) / 1000000; return true; } static bool get_cpu_power_zenpower(CPUPowerData* cpuPowerData, float& power) { CPUPowerData_zenpower* powerData_zenpower = (CPUPowerData_zenpower*)cpuPowerData; if (!powerData_zenpower->corePowerFile || !powerData_zenpower->socPowerFile) return false; rewind(powerData_zenpower->corePowerFile); rewind(powerData_zenpower->socPowerFile); fflush(powerData_zenpower->corePowerFile); fflush(powerData_zenpower->socPowerFile); int corePower, socPower; if (fscanf(powerData_zenpower->corePowerFile, "%d", &corePower) != 1) return false; if (fscanf(powerData_zenpower->socPowerFile, "%d", &socPower) != 1) return false; power = (corePower + socPower) / 1000000; return true; } static bool get_cpu_power_zenergy(CPUPowerData* cpuPowerData, float& power) { CPUPowerData_zenergy* powerData_zenergy = (CPUPowerData_zenergy*)cpuPowerData; if (!powerData_zenergy->energyCounterFile) return false; rewind(powerData_zenergy->energyCounterFile); fflush(powerData_zenergy->energyCounterFile); uint64_t energyCounterValue = 0; if (fscanf(powerData_zenergy->energyCounterFile, "%" SCNu64, &energyCounterValue) != 1) return false; Clock::time_point now = Clock::now(); Clock::duration timeDiff = now - powerData_zenergy->lastCounterValueTime; int64_t timeDiffMicro = std::chrono::duration_cast(timeDiff).count(); uint64_t energyCounterDiff = energyCounterValue - powerData_zenergy->lastCounterValue; if (powerData_zenergy->lastCounterValue > 0 && energyCounterValue > powerData_zenergy->lastCounterValue) power = (float) energyCounterDiff / (float) timeDiffMicro; powerData_zenergy->lastCounterValue = energyCounterValue; powerData_zenergy->lastCounterValueTime = now; return true; } static bool get_cpu_power_rapl(CPUPowerData* cpuPowerData, float& power) { CPUPowerData_rapl* powerData_rapl = (CPUPowerData_rapl*)cpuPowerData; if (!powerData_rapl->energyCounterFile) return false; rewind(powerData_rapl->energyCounterFile); fflush(powerData_rapl->energyCounterFile); uint64_t energyCounterValue = 0; if (fscanf(powerData_rapl->energyCounterFile, "%" SCNu64, &energyCounterValue) != 1) return false; Clock::time_point now = Clock::now(); Clock::duration timeDiff = now - powerData_rapl->lastCounterValueTime; int64_t timeDiffMicro = std::chrono::duration_cast(timeDiff).count(); uint64_t energyCounterDiff = energyCounterValue - powerData_rapl->lastCounterValue; if (powerData_rapl->lastCounterValue > 0 && energyCounterValue > powerData_rapl->lastCounterValue) power = energyCounterDiff / timeDiffMicro; powerData_rapl->lastCounterValue = energyCounterValue; powerData_rapl->lastCounterValueTime = now; return true; } static bool get_cpu_power_amdgpu(float& power) { if (gpus) for (auto gpu : gpus->available_gpus) if (gpu->is_apu()) { power = gpu->metrics.apu_cpu_power; return true; } return false; } static bool get_cpu_power_xgene(CPUPowerData* cpuPowerData, float& power) { CPUPowerData_xgene* powerData_xgene = (CPUPowerData_xgene*)cpuPowerData; if (!powerData_xgene->powerFile) return false; rewind(powerData_xgene->powerFile); fflush(powerData_xgene->powerFile); uint64_t powerValue = 0; if (fscanf(powerData_xgene->powerFile, "%" SCNu64, &powerValue) != 1) return false; power = (float) powerValue / 1000000.0f; return true; } bool CPUStats::UpdateCpuPower() { InitCpuPowerData(); if(!m_cpuPowerData) return false; float power = 0; switch(m_cpuPowerData->source) { case CPU_POWER_K10TEMP: if (!get_cpu_power_k10temp(m_cpuPowerData.get(), power)) return false; break; case CPU_POWER_ZENPOWER: if (!get_cpu_power_zenpower(m_cpuPowerData.get(), power)) return false; break; case CPU_POWER_ZENERGY: if (!get_cpu_power_zenergy(m_cpuPowerData.get(), power)) return false; break; case CPU_POWER_RAPL: if (!get_cpu_power_rapl(m_cpuPowerData.get(), power)) return false; break; case CPU_POWER_AMDGPU: if (!get_cpu_power_amdgpu(power)) return false; break; case CPU_POWER_XGENE: if (!get_cpu_power_xgene(m_cpuPowerData.get(), power)) return false; break; default: return false; } m_cpuDataTotal.power = power; return true; } static bool find_input(const std::string& path, const char* input_prefix, std::string& input, const std::string& name) { auto files = ls(path.c_str(), input_prefix, LS_FILES); for (auto& file : files) { if (!ends_with(file, "_label")) continue; auto label = read_line(path + "/" + file); if (label != name) continue; auto uscore = file.find_first_of("_"); if (uscore != std::string::npos) { file.erase(uscore, std::string::npos); input = path + "/" + file + "_input"; //9 characters should not overflow the 32-bit int return std::stoi(read_line(input).substr(0, 9)) > 0; } } return false; } static bool find_fallback_input(const std::string& path, const char* input_prefix, std::string& input) { auto files = ls(path.c_str(), input_prefix, LS_FILES); if (!files.size()) return false; std::sort(files.begin(), files.end()); for (auto& file : files) { if (!ends_with(file, "_input")) continue; input = path + "/" + file; SPDLOG_DEBUG("fallback cpu {} input: {}", input_prefix, input); return true; } return false; } static void check_thermal_zones(std::string& path, std::string& input) { std::string sysfs_thermal = "/sys/class/thermal/"; if (!fs::exists(sysfs_thermal)) return; for (auto& d : fs::directory_iterator(sysfs_thermal)) { if (d.path().filename().string().substr(0, 12) != "thermal_zone") continue; std::string type = read_line(d / "type"); if (type.substr(0, 6) != "cpuss-") continue; path = d.path(); input = d / "temp"; return; } } bool CPUStats::GetCpuFile() { if (m_cpuTempFile) return true; std::string name, path, input; std::string hwmon = "/sys/class/hwmon/"; std::smatch match; auto dirs = ls(hwmon.c_str()); for (auto& dir : dirs) { path = hwmon + dir; name = read_line(path + "/name"); SPDLOG_DEBUG("hwmon: sensor name: {}", name); std::map custom_sensor = get_params()->cpu_custom_temp_sensor; if (!custom_sensor["hwmon_name"].empty() && !custom_sensor["hwmon_input"].empty()) { if (name != custom_sensor["hwmon_name"]) continue; find_fallback_input(path, custom_sensor["hwmon_input"].c_str(), input); break; } else if (name == "coretemp") { find_input(path, "temp", input, "Package id 0"); break; } else if ((name == "zenpower" || name == "k10temp")) { if (!find_input(path, "temp", input, "Tdie")) find_input(path, "temp", input, "Tctl"); break; } else if (name == "atk0110") { find_input(path, "temp", input, "CPU Temperature"); break; } else if (name == "it8603") { find_input(path, "temp", input, "temp1"); break; } else if (starts_with(name, "cpuss0_")) { find_fallback_input(path, "temp1", input); break; } else if (starts_with(name, "nct")) { // Only break if nct module has TSI0_TEMP node if (find_input(path, "temp", input, "TSI0_TEMP")) break; } else if (name == "asusec") { // Only break if module has CPU node if (find_input(path, "temp", input, "CPU")) break; } else if (name == "l_pcs") { // E2K (Elbrus 2000) CPU temperature module find_input(path, "temp", input, "Node 0 Max"); break; } else if (std::regex_match(name, match, std::regex("cpu\\d*_thermal"))) { find_fallback_input(path, "temp1", input); break; } else if (name == "apm_xgene") { find_input(path, "temp", input, "SoC Temperature"); break; } else { path.clear(); } } if (path.empty()) { try { check_thermal_zones(path, input); } catch (fs::filesystem_error& ex) { SPDLOG_DEBUG("check_thermal_zones: {}", ex.what()); } } if (input.empty() || !file_exists(input)) { SPDLOG_ERROR("Could not find cpu temp sensor location"); return false; } SPDLOG_INFO("hwmon: using input: {}", input); m_cpuTempFile = fopen(input.c_str(), "r"); return true; } static CPUPowerData_k10temp* init_cpu_power_data_k10temp(const std::string path) { auto powerData = std::make_unique(); std::string coreVoltageInput, coreCurrentInput; std::string socVoltageInput, socCurrentInput; std::string socPowerInput, corePowerInput; if(find_input(path, "power", corePowerInput, "Pcore") && find_input(path, "power", socPowerInput, "Psoc")) { powerData->corePowerFile = fopen(corePowerInput.c_str(), "r"); powerData->socPowerFile = fopen(socPowerInput.c_str(), "r"); SPDLOG_DEBUG("hwmon: using input: {}", corePowerInput); SPDLOG_DEBUG("hwmon: using input: {}", socPowerInput); return powerData.release(); } if(!find_input(path, "in", coreVoltageInput, "Vcore")) return nullptr; if(!find_input(path, "curr", coreCurrentInput, "Icore")) return nullptr; if(!find_input(path, "in", socVoltageInput, "Vsoc")) return nullptr; if(!find_input(path, "curr", socCurrentInput, "Isoc")) return nullptr; SPDLOG_DEBUG("hwmon: using input: {}", coreVoltageInput); SPDLOG_DEBUG("hwmon: using input: {}", coreCurrentInput); SPDLOG_DEBUG("hwmon: using input: {}", socVoltageInput); SPDLOG_DEBUG("hwmon: using input: {}", socCurrentInput); powerData->coreVoltageFile = fopen(coreVoltageInput.c_str(), "r"); powerData->coreCurrentFile = fopen(coreCurrentInput.c_str(), "r"); powerData->socVoltageFile = fopen(socVoltageInput.c_str(), "r"); powerData->socCurrentFile = fopen(socCurrentInput.c_str(), "r"); return powerData.release(); } static CPUPowerData_zenpower* init_cpu_power_data_zenpower(const std::string path) { auto powerData = std::make_unique(); std::string corePowerInput, socPowerInput; if(!find_input(path, "power", corePowerInput, "SVI2_P_Core")) return nullptr; if(!find_input(path, "power", socPowerInput, "SVI2_P_SoC")) return nullptr; SPDLOG_DEBUG("hwmon: using input: {}", corePowerInput); SPDLOG_DEBUG("hwmon: using input: {}", socPowerInput); powerData->corePowerFile = fopen(corePowerInput.c_str(), "r"); powerData->socPowerFile = fopen(socPowerInput.c_str(), "r"); return powerData.release(); } static CPUPowerData_zenergy* init_cpu_power_data_zenergy(const std::string path) { auto powerData = std::make_unique(); std::string energyCounterPath; if(!find_input(path, "energy", energyCounterPath, "Esocket0")) return nullptr; SPDLOG_DEBUG("hwmon: using input: {}", energyCounterPath); powerData->energyCounterFile = fopen(energyCounterPath.c_str(), "r"); return powerData.release(); } static CPUPowerData_rapl* init_cpu_power_data_rapl(const std::string path) { auto powerData = std::make_unique(); std::string energyCounterPath = path + "/energy_uj"; if (!file_exists(energyCounterPath)) return nullptr; powerData->energyCounterFile = fopen(energyCounterPath.c_str(), "r"); if (!powerData->energyCounterFile) { SPDLOG_DEBUG("Rapl: energy_uj is not accessible"); powerData->energyCounterFile = nullptr; return nullptr; } return powerData.release(); } static CPUPowerData_xgene* init_cpu_power_data_xgene(const std::string path) { auto powerData = std::make_unique(); std::string powerPath; if(!find_input(path, "power", powerPath, "CPU power")) return nullptr; SPDLOG_DEBUG("hwmon: using input: {}", powerPath); powerData->powerFile = fopen(powerPath.c_str(), "r"); return powerData.release(); } bool CPUStats::InitCpuPowerData() { if(m_cpuPowerData != nullptr) return true; // only try to find a valid method 5 times static int retries = 0; if (retries >= 5) return true; retries++; std::string name, path; std::string hwmon = "/sys/class/hwmon/"; CPUPowerData* cpuPowerData = nullptr; auto dirs = ls(hwmon.c_str()); for (auto& dir : dirs) { path = hwmon + dir; name = read_line(path + "/name"); SPDLOG_DEBUG("hwmon: sensor name: {}", name); if (name == "k10temp") { cpuPowerData = (CPUPowerData*)init_cpu_power_data_k10temp(path); } else if (name == "zenpower") { cpuPowerData = (CPUPowerData*)init_cpu_power_data_zenpower(path); break; } else if (name == "zenergy") { cpuPowerData = (CPUPowerData*)init_cpu_power_data_zenergy(path); break; } else if (name == "apm_xgene") { cpuPowerData = (CPUPowerData*)init_cpu_power_data_xgene(path); break; } } if (!cpuPowerData) { if (gpus) { for (auto gpu : gpus->available_gpus) { if (gpu->vendor_id == 0x1002 && gpu->is_apu() && gpu->get_metrics().apu_cpu_power > 0) { auto powerData = std::make_unique(); cpuPowerData = (CPUPowerData*)powerData.release(); } } } } if (!cpuPowerData) { std::string powercap = "/sys/class/powercap/"; auto powercap_dirs = ls(powercap.c_str()); for (auto& dir : powercap_dirs) { path = powercap + dir; name = read_line(path + "/name"); SPDLOG_DEBUG("powercap: name: {}", name); if (name == "package-0") { cpuPowerData = (CPUPowerData*)init_cpu_power_data_rapl(path); break; } } } if(cpuPowerData == nullptr) { SPDLOG_ERROR("Failed to initialize CPU power data"); return false; } m_cpuPowerData.reset(cpuPowerData); return true; } void CPUStats::get_cpu_cores_types() { #if defined(__x86_64__) || defined(__i386__) std::ifstream cpuinfo(PROCCPUINFOFILE); if (!cpuinfo.is_open()) { SPDLOG_ERROR("failed to open {}", PROCCPUINFOFILE); return; } std::string vendor = "unknown"; for (std::string line; std::getline(cpuinfo, line);) { if (line.empty() || line.find(":") + 1 == line.length()) continue; std::string key = line.substr(0, line.find(":") - 1); std::string val = line.substr(key.length() + 3); if (key == "vendor_id") { vendor = val; break; } } SPDLOG_INFO("cpu vendor: {}", vendor); if (vendor == "GenuineIntel") get_cpu_cores_types_intel(); #endif #if defined(__arm__) || defined(__aarch64__) get_cpu_cores_types_arm(); #endif } void CPUStats::get_cpu_cores_types_intel() { for (auto const& it : intel_cores) { auto key = it.first; auto file = it.second; std::ifstream core_file(file); if (!core_file.is_open()) { SPDLOG_ERROR("failed to open core info file"); return; } std::string cpus; std::getline(core_file, cpus); std::regex rx("(\\d+)-(\\d+)"); std::smatch matches; if (!std::regex_match(cpus, matches, rx) || matches.size() != 3) continue; int start = 0, end = 0; try { start = std::stoi(matches[1]); end = std::stoi(matches[2]) + 1; } catch (...) { SPDLOG_ERROR("error parsing cpus \"{}\"", cpus); } for (int i = start; i < end; i++) { for (size_t k = 0; k < m_cpuData.size(); k++) { if (m_cpuData[k].cpu_id != i) continue; m_cpuData[k].label = key; break; } } } } void CPUStats::get_cpu_cores_types_arm() { std::ifstream cpuinfo(PROCCPUINFOFILE); if (!cpuinfo.is_open()) { SPDLOG_ERROR("failed to open {}", PROCCPUINFOFILE); return; } uint8_t cur_core = 0; bool detected_first_core = false; for (std::string line; std::getline(cpuinfo, line);) { if (line.empty() || line.find(":") + 1 == line.length()) continue; auto key = line.substr(0, line.find(":") - 1); auto val = line.substr(key.length() + 3); if (key != "CPU part") continue; if (detected_first_core) cur_core += 1; else detected_first_core = true; std::string core_type; try { core_type = arm_cores.at(val); SPDLOG_INFO("found {} core", core_type); } catch(const std::out_of_range& ex) { SPDLOG_WARN("unknown cpu part {}", val); continue; } // just in case for (size_t i = 0; i < m_cpuData.size(); i++) { if (m_cpuData[i].cpu_id != cur_core) continue; m_cpuData[i].label = core_type; } } } CPUStats cpuStats; ================================================ FILE: src/cpu.h ================================================ #pragma once #ifndef MANGOHUD_CPU_H #define MANGOHUD_CPU_H #include #include #include #include #include #ifdef WIN32 #include #endif #include "timing.hpp" #include "gpu.h" typedef struct CPUData_ { unsigned long long int totalTime; unsigned long long int userTime; unsigned long long int systemTime; unsigned long long int systemAllTime; unsigned long long int idleAllTime; unsigned long long int idleTime; unsigned long long int niceTime; unsigned long long int ioWaitTime; unsigned long long int irqTime; unsigned long long int softIrqTime; unsigned long long int stealTime; unsigned long long int guestTime; unsigned long long int totalPeriod; unsigned long long int userPeriod; unsigned long long int systemPeriod; unsigned long long int systemAllPeriod; unsigned long long int idleAllPeriod; unsigned long long int idlePeriod; unsigned long long int nicePeriod; unsigned long long int ioWaitPeriod; unsigned long long int irqPeriod; unsigned long long int softIrqPeriod; unsigned long long int stealPeriod; unsigned long long int guestPeriod; int cpu_id; float percent; int mhz; int temp; int cpu_mhz; float power; std::string label = "unknown"; } CPUData; enum { CPU_POWER_K10TEMP, CPU_POWER_ZENPOWER, CPU_POWER_ZENERGY, CPU_POWER_RAPL, CPU_POWER_AMDGPU, CPU_POWER_XGENE }; struct CPUPowerData { virtual ~CPUPowerData() = default; int source; }; struct CPUPowerData_k10temp : public CPUPowerData { CPUPowerData_k10temp() { this->source = CPU_POWER_K10TEMP; }; ~CPUPowerData_k10temp() { if(this->coreVoltageFile) fclose(this->coreVoltageFile); if(this->coreCurrentFile) fclose(this->coreCurrentFile); if(this->socVoltageFile) fclose(this->socVoltageFile); if(this->socCurrentFile) fclose(this->socCurrentFile); if(this->corePowerFile) fclose(this->corePowerFile); if(this->socPowerFile) fclose(this->socPowerFile); }; FILE* coreVoltageFile {nullptr}; FILE* coreCurrentFile {nullptr}; FILE* socVoltageFile {nullptr}; FILE* socCurrentFile {nullptr}; FILE* corePowerFile {nullptr}; FILE* socPowerFile {nullptr}; }; struct CPUPowerData_zenpower : public CPUPowerData { CPUPowerData_zenpower() { this->source = CPU_POWER_ZENPOWER; }; ~CPUPowerData_zenpower() { if(this->corePowerFile) fclose(this->corePowerFile); if(this->socPowerFile) fclose(this->socPowerFile); }; FILE* corePowerFile {nullptr}; FILE* socPowerFile {nullptr}; }; struct CPUPowerData_zenergy : public CPUPowerData { CPUPowerData_zenergy() { this->source = CPU_POWER_ZENERGY; this->lastCounterValue = 0; this->lastCounterValueTime = Clock::now(); }; ~CPUPowerData_zenergy() { if(this->energyCounterFile) fclose(this->energyCounterFile); }; FILE* energyCounterFile {nullptr}; uint64_t lastCounterValue; Clock::time_point lastCounterValueTime; }; struct CPUPowerData_rapl : public CPUPowerData { CPUPowerData_rapl() { this->source = CPU_POWER_RAPL; this->lastCounterValue = 0; this->lastCounterValueTime = Clock::now(); }; ~CPUPowerData_rapl() { if(this->energyCounterFile) fclose(this->energyCounterFile); }; FILE* energyCounterFile {nullptr}; uint64_t lastCounterValue; Clock::time_point lastCounterValueTime; }; struct CPUPowerData_amdgpu : public CPUPowerData { CPUPowerData_amdgpu() { this->source = CPU_POWER_AMDGPU; }; }; struct CPUPowerData_xgene : public CPUPowerData { CPUPowerData_xgene() { this->source = CPU_POWER_XGENE; }; ~CPUPowerData_xgene() { if(this->powerFile) fclose(this->powerFile); }; FILE* powerFile {nullptr}; }; class CPUStats { public: CPUStats(); ~CPUStats(); bool Init(); bool Reinit(); bool Updated() { return m_updatedCPUs; } bool UpdateCPUData(); bool UpdateCoreMhz(); bool UpdateCpuTemp(); bool UpdateCpuPower(); bool ReadcpuTempFile(int& temp); bool GetCpuFile(); bool InitCpuPowerData(); double GetCPUPeriod() { return m_cpuPeriod; } void get_cpu_cores_types(); void get_cpu_cores_types_intel(); void get_cpu_cores_types_arm(); const std::vector& GetCPUData() const { return m_cpuData; } const CPUData& GetCPUDataTotal() const { return m_cpuDataTotal; } private: unsigned long long int m_boottime = 0; std::vector m_cpuData; CPUData m_cpuDataTotal {}; std::vector m_coreMhz; double m_cpuPeriod = 0; bool m_updatedCPUs = false; // TODO use caching or just update? bool m_inited = false; FILE *m_cpuTempFile = nullptr; std::unique_ptr m_cpuPowerData; const std::map intel_cores = { {"P", "/sys/devices/cpu_core/cpus"}, {"E", "/sys/devices/cpu_atom/cpus"} }; const std::map arm_cores = { // Performance cores {"0xd07", "A57"}, {"0xd08", "A72"}, {"0xd09", "A73"}, {"0xd0a", "A75"}, {"0xd0b", "A76"}, {"0xd0c", "A77"}, {"0xd41", "A78"}, {"0xd44", "X1"}, {"0xd4d", "X2"}, {"0xd4e", "X3"}, {"0xd47", "A710"}, {"0xd4f", "A720"}, {"0xd4b", "X4"}, // Efficiency Cores {"0xd03", "A53"}, {"0xd05", "A55"}, {"0xd46", "A510"}, {"0xd4a", "A520"}, // General-Purpose Cores {"0xd04", "A35"}, {"0xd06", "A65"} }; }; extern CPUStats cpuStats; #ifdef WIN32 uint64_t FileTimeToInt64( const FILETIME& ft ); #endif #endif //MANGOHUD_CPU_H ================================================ FILE: src/cpu_win32.cpp ================================================ #include #include #include #include "cpu.h" #include #define SystemProcessorPerformanceInformation 0x8 #define SystemBasicInformation 0x0 FILETIME last_userTime, last_kernelTime, last_idleTime; uint64_t FileTimeToInt64( const FILETIME& ft ) { ULARGE_INTEGER uli = { 0 }; uli.LowPart = ft.dwLowDateTime; uli.HighPart = ft.dwHighDateTime; return uli.QuadPart; } bool CPUStats::UpdateCPUData() { #define NUMBER_OF_PROCESSORS (8) #define PROCESSOR_BUFFER_SIZE (NUMBER_OF_PROCESSORS * 8) static ULONG64 ProcessorIdleTimeBuffer [ PROCESSOR_BUFFER_SIZE ]; FILETIME IdleTime, KernelTime, UserTime; static unsigned long long PrevTotal = 0; static unsigned long long PrevIdle = 0; static unsigned long long PrevUser = 0; unsigned long long ThisTotal; unsigned long long ThisIdle, ThisKernel, ThisUser; unsigned long long TotalSinceLast, IdleSinceLast, UserSinceLast; // GET THE KERNEL / USER / IDLE times. // And oh, BTW, kernel time includes idle time GetSystemTimes( & IdleTime, & KernelTime, & UserTime); ThisIdle = FileTimeToInt64(IdleTime); ThisKernel = FileTimeToInt64 (KernelTime); ThisUser = FileTimeToInt64 (UserTime); ThisTotal = ThisKernel + ThisUser; TotalSinceLast = ThisTotal - PrevTotal; IdleSinceLast = ThisIdle - PrevIdle; UserSinceLast = ThisUser - PrevUser; double Headroom; Headroom = (double)IdleSinceLast / (double)TotalSinceLast ; double Load; Load = 1.0 - Headroom; Headroom *= 100.0; // to make it percent Load *= 100.0; // percent PrevTotal = ThisTotal; PrevIdle = ThisIdle; PrevUser = ThisUser; // print results to output window of VS when run in Debug m_cpuDataTotal.percent = Load; return true; } bool CPUStats::ReadcpuTempFile(int&) { return false; } CPUStats::CPUStats() { } CPUStats::~CPUStats() { } CPUStats cpuStats; ================================================ FILE: src/dbus.cpp ================================================ #include #include #include #include #include "dbus_helpers.h" #include "dbus_info.h" #include "string_utils.h" #include "file_utils.h" using ms = std::chrono::milliseconds; using namespace DBus_helpers; #define DBUS_TIMEOUT 2000 // ms struct mutexed_metadata main_metadata; namespace dbusmgr { dbus_manager dbus_mgr; } template static void assign_metadata_value(metadata& meta, const std::string& key, const T& value) { if (key == "PlaybackStatus") { meta.playing = (value == "Playing"); meta.got_playback_data = true; } else if (key == "xesam:title") { meta.title = value; meta.got_song_data = true; meta.valid = true; } else if (key == "xesam:artist") { meta.artists = value; meta.got_song_data = true; meta.valid = true; } else if (key == "xesam:album") { meta.album = value; meta.got_song_data = true; meta.valid = true; } else if (key == "mpris:artUrl") { meta.artUrl = value; meta.got_song_data = true; } else if (key == "xesam:url") { // HACK if there's no metadata then use this to clear old ones meta.got_song_data = true; } } static std::string format_signal(const dbusmgr::DBusSignal& s) { std::stringstream ss; ss << "type='signal',interface='" << s.intf << "'"; ss << ",member='" << s.signal << "'"; return ss.str(); } static void parse_song_data(DBusMessageIter_wrap iter, metadata& meta){ iter.string_map_for_each([&meta](const std::string& key, DBusMessageIter_wrap it) { std::string val; if (it.is_primitive()) { val = it.get_stringified(); } else if (it.is_array()) { it.array_for_each_stringify([&](const std::string& str) { if (val.empty()) { val = str; } else { val += ", " + str; } }); } assign_metadata_value(meta, key, val); }); } static void parse_mpris_properties(libdbus_loader& dbus, DBusMessage* msg, std::string& source, metadata& meta) { /** * Expected response Format: * string, * map{ * "Metadata" -> multimap, * "PlaybackStatus" -> string * } */ auto iter = DBusMessageIter_wrap(msg, &dbus); source = iter.get_primitive(); if (source != "org.mpris.MediaPlayer2.Player") return; iter.next(); if (!iter.is_array()) return; iter.string_map_for_each([&meta](std::string& key, DBusMessageIter_wrap it) { if (key == "Metadata") { parse_song_data(it, meta); } else if (key == "PlaybackStatus") { auto val = it.get_stringified(); assign_metadata_value(meta, key, val); } }); meta.valid = (meta.artists.size() || !meta.title.empty()); } static bool dbus_get_name_owner(dbusmgr::dbus_manager& dbus_mgr, std::string& name_owner, const char* name) { auto reply = DBusMessage_wrap::new_method_call( "org.freedesktop.DBus", "/org/freedesktop/DBus", "org.freedesktop.DBus", "GetNameOwner", &dbus_mgr.dbus()) .argument(name) .send_with_reply_and_block(dbus_mgr.get_conn(), DBUS_TIMEOUT); if (!reply) return false; auto iter = reply.iter(); if (!iter.is_string()) return false; name_owner = iter.get_primitive(); return true; } static bool dbus_get_player_property(dbusmgr::dbus_manager& dbus_mgr, metadata& meta, const char* dest, const char* prop) { auto reply = DBusMessage_wrap::new_method_call(dest, "/org/mpris/MediaPlayer2", "org.freedesktop.DBus.Properties", "Get", &dbus_mgr.dbus()) .argument("org.mpris.MediaPlayer2.Player") .argument(prop) .send_with_reply_and_block(dbus_mgr.get_conn(), DBUS_TIMEOUT); if (!reply) return false; auto iter = reply.iter(); if (iter.is_array()) { parse_song_data(iter, meta); } else if (iter.is_primitive()) { assign_metadata_value(meta, prop, iter.get_stringified()); } else { return false; } return true; } namespace dbusmgr { bool dbus_manager::get_media_player_metadata(metadata& meta, std::string name) { if (name == "") name = m_active_player; if (name == "") return false; meta = {}; dbus_get_player_property(*this, meta, name.c_str(), "Metadata"); dbus_get_player_property(*this, meta, name.c_str(), "PlaybackStatus"); meta.valid = (meta.artists.size() || !meta.title.empty()); return true; } bool dbus_manager::init_internal() { if (!m_dbus_ldr.IsLoaded() && !m_dbus_ldr.Load("libdbus-1.so.3")) { SPDLOG_ERROR("Could not load libdbus-1.so.3"); return false; } m_dbus_ldr.error_init(&m_error); m_dbus_ldr.threads_init_default(); if (nullptr == (m_dbus_conn = m_dbus_ldr.bus_get(DBUS_BUS_SESSION, &m_error))) { SPDLOG_ERROR("{}", m_error.message); m_dbus_ldr.error_free(&m_error); return false; } SPDLOG_DEBUG("Connected to D-Bus as \"{}\"", m_dbus_ldr.bus_get_unique_name(m_dbus_conn)); m_dbus_ldr.connection_add_filter(m_dbus_conn, filter_signals, reinterpret_cast(this), nullptr); start_thread(); dbus_list_name_to_owner(); m_inited = true; return true; } bool dbus_manager::init(Service srv) { if (!m_inited && !init_internal()) return false; connect_to_signals(srv); m_active_srvs |= srv; return true; } bool dbus_manager::init_mpris(const std::string& requested_player) { if (!requested_player.empty()) { m_requested_player = "org.mpris.MediaPlayer2." + requested_player; } else m_requested_player.clear(); if (m_active_srvs & SRV_MPRIS) { select_active_player(); return true; } SPDLOG_WARN("D-Bus hasn't been inited yet."); return false; } bool dbus_manager::select_active_player() { auto old_active_player = m_active_player; m_active_player = ""; metadata meta {}; if (!m_requested_player.empty()) { // If the requested player is available, use it if (m_name_owners.count(m_requested_player) > 0) { m_active_player = m_requested_player; SPDLOG_DEBUG("Selecting requested player: {}", m_requested_player); get_media_player_metadata(meta, m_active_player); } } else { // If no player is requested, use any player that is currently playing if (m_active_player.empty()) { auto it = std::find_if(m_name_owners.begin(), m_name_owners.end(), [this, &meta](auto& entry){ auto& name = entry.first; this->get_media_player_metadata(meta, name); if(meta.playing) { return true; } else { meta = {}; return false; } }); if(it != m_name_owners.end()){ m_active_player = it->first; SPDLOG_DEBUG("Selecting fallback player: {}", m_active_player); } } } if (!m_active_player.empty()) { onNewPlayer(meta); return true; } else { SPDLOG_DEBUG("No active players"); if (!old_active_player.empty()) { onNoPlayer(); } return false; } } void dbus_manager::deinit(Service srv) { if (!m_inited) return; m_active_srvs &= ~srv; if (m_dbus_conn) disconnect_from_signals(srv); // unreference system bus connection instead of closing it if (m_dbus_conn && !m_active_srvs) { m_dbus_ldr.connection_remove_filter(m_dbus_conn, filter_signals, reinterpret_cast(this)); stop_thread(); m_dbus_ldr.connection_unref(m_dbus_conn); m_dbus_conn = nullptr; m_dbus_ldr.error_free(&m_error); m_inited = false; } } dbus_manager::~dbus_manager() { deinit(static_cast(m_active_srvs)); } DBusHandlerResult dbus_manager::filter_signals(DBusConnection* conn, DBusMessage* msg, void* userData) { auto& manager = *reinterpret_cast(userData); for (auto& sig : manager.m_signals) { if (manager.m_dbus_ldr.message_is_signal(msg, sig.intf, sig.signal)) { auto sender = manager.m_dbus_ldr.message_get_sender(msg); if ((manager.*(sig.handler))(msg, sender)) return DBUS_HANDLER_RESULT_HANDLED; else return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } } return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } bool dbus_manager::handle_properties_changed(DBusMessage* msg, const char* sender) { std::string source; metadata meta; parse_mpris_properties(m_dbus_ldr, msg, source, meta); #ifndef NDEBUG std::cerr << "PropertiesChanged Signal received:\n"; std::cerr << "\tSource: " << source << "\n"; std::cerr << "active_player: " << m_active_player << "\n"; std::cerr << "active_player's owner: " << m_name_owners[m_active_player] << "\n"; std::cerr << "sender: " << sender << "\n"; #endif if (source != "org.mpris.MediaPlayer2.Player") return false; if (m_active_player == "" || (m_requested_player.empty() && !main_metadata.meta.playing)) { select_active_player(); } else if (m_name_owners[m_active_player] == sender) { onPlayerUpdate(meta); } return true; } bool dbus_manager::handle_name_owner_changed(DBusMessage* _msg, const char* sender) { std::vector str; for (auto iter = DBusMessageIter_wrap(_msg, &m_dbus_ldr); iter; iter.next()) { str.push_back(iter.get_primitive()); } // register new name if (str.size() == 3 && starts_with(str[0], "org.mpris.MediaPlayer2.") && !str[2].empty()) { m_name_owners[str[0]] = str[2]; if (str[0] == m_requested_player) { select_active_player(); } } // did a player quit? if (str[2].empty()) { if (str.size() == 3 && str[0] == m_active_player) { m_name_owners.erase(str[0]); select_active_player(); } } return true; } bool dbus_manager::gamemode_enabled(pid_t pid) { if (!m_inited) return false; static int isvc = file_exists("/.flatpak-info") ? 1 : 0; const struct dbus_ep { const char *name; const char *path; const char *iface; } svc[] { { "com.feralinteractive.GameMode", "/com/feralinteractive/GameMode", "com.feralinteractive.GameMode" }, { "org.freedesktop.portal.Desktop", "/org/freedesktop/portal/desktop", "org.freedesktop.portal.GameMode" } }; auto reply = DBusMessage_wrap::new_method_call( svc[isvc].name, svc[isvc].path, svc[isvc].iface, "QueryStatus", &dbus_mgr.dbus()) .argument(pid) .send_with_reply_and_block(dbus_mgr.get_conn(), DBUS_TIMEOUT); if (!reply) return false; auto iter = reply.iter(); if (!iter.is_signed()) return false; return !!iter.get_primitive(); } bool dbus_manager::handle_game_registered(DBusMessage* _msg, const char* sender) { auto iter = DBusMessageIter_wrap(_msg, &m_dbus_ldr); auto pid = iter.get_primitive(); iter.next(); auto path = iter.get_primitive(); SPDLOG_INFO("Game registered: {} '{}'", pid, path); return true; } bool dbus_manager::handle_game_unregistered(DBusMessage* _msg, const char* sender) { auto iter = DBusMessageIter_wrap(_msg, &m_dbus_ldr); auto pid = iter.get_primitive(); iter.next(); auto path = iter.get_primitive(); SPDLOG_INFO("Game unregistered: {} '{}'", pid, path); return true; } void dbus_manager::connect_to_signals(Service srv) { for (auto kv : m_signals) { if (!(kv.srv & srv)) continue; auto signal = format_signal(kv); m_dbus_ldr.bus_add_match(m_dbus_conn, signal.c_str(), &m_error); if (m_dbus_ldr.error_is_set(&m_error)) { SPDLOG_ERROR("{}: {}", m_error.name, m_error.message); m_dbus_ldr.error_free(&m_error); // return; } } } void dbus_manager::disconnect_from_signals(Service srv) { for (auto kv : m_signals) { if (!(kv.srv & srv)) continue; auto signal = format_signal(kv); m_dbus_ldr.bus_remove_match(m_dbus_conn, signal.c_str(), &m_error); if (m_dbus_ldr.error_is_set(&m_error)) { #ifndef NDEBUG // spdlog might be destroyed by now std::cerr << "[MANGOHUD] [debug] " << __func__ << " " << m_error.name << ": " << m_error.message << std::endl; #endif m_dbus_ldr.error_free(&m_error); } } } bool dbus_manager::dbus_list_name_to_owner() { auto reply = DBusMessage_wrap::new_method_call( "org.freedesktop.DBus", "/org/freedesktop/DBus", "org.freedesktop.DBus", "ListNames", &dbus_mgr.dbus()) .send_with_reply_and_block(dbus_mgr.get_conn(), DBUS_TIMEOUT); if (!reply) return false; auto iter = reply.iter(); if (!iter.is_array()) { return false; } iter.array_for_each_value([&](std::string name) { if (!starts_with(name, "org.mpris.MediaPlayer2.")) return; std::string owner; if (dbus_get_name_owner(dbus_mgr, owner, name.c_str())) { m_name_owners[name] = owner; } }); return true; } void dbus_manager::stop_thread() { m_quit = true; if (m_thread.joinable()) m_thread.join(); } void dbus_manager::start_thread() { stop_thread(); m_quit = false; m_thread = std::thread(&dbus_manager::dbus_thread, this); pthread_setname_np(m_thread.native_handle(), "mangohud-dbus"); } void dbus_manager::dbus_thread() { using namespace std::chrono_literals; while (!m_quit && m_dbus_ldr.connection_read_write_dispatch(m_dbus_conn, 0)) std::this_thread::sleep_for(10ms); } void dbus_manager::onNoPlayer() { std::lock_guard lck(main_metadata.mtx); main_metadata.meta = {}; main_metadata.ticker = {}; } void dbus_manager::onNewPlayer(metadata& meta) { std::lock_guard lck(main_metadata.mtx); main_metadata.meta = meta; main_metadata.ticker = {}; } void dbus_manager::onPlayerUpdate(metadata& meta) { std::lock_guard lck(main_metadata.mtx); if (meta.got_song_data) { // If the song has changed, reset the ticker if (main_metadata.meta.artists != meta.artists || main_metadata.meta.album != meta.album || main_metadata.meta.title != meta.title) { main_metadata.ticker = {}; } main_metadata.meta = meta; main_metadata.meta.playing = true; } if (meta.got_playback_data) { main_metadata.meta.playing = meta.playing; } } } // namespace dbusmgr ================================================ FILE: src/dbus_helpers.h ================================================ #pragma once #ifndef MANGOHUD_DBUS_HELPERS #define MANGOHUD_DBUS_HELPERS #include #include #include #include "loaders/loader_dbus.h" namespace DBus_helpers { namespace detail { // clang-format off template struct dbus_type_traits{}; template<> struct dbus_type_traits { const int value = DBUS_TYPE_BOOLEAN; const bool is_fixed = true; }; template<> struct dbus_type_traits { const int value = DBUS_TYPE_BYTE; const bool is_fixed = true; }; template<> struct dbus_type_traits { const int value = DBUS_TYPE_UINT16; const bool is_fixed = true; }; template<> struct dbus_type_traits { const int value = DBUS_TYPE_UINT32; const bool is_fixed = true; }; template<> struct dbus_type_traits { const int value = DBUS_TYPE_UINT64; const bool is_fixed = true; }; template<> struct dbus_type_traits { const int value = DBUS_TYPE_INT16; const bool is_fixed = true; }; template<> struct dbus_type_traits { const int value = DBUS_TYPE_INT32; const bool is_fixed = true; }; template<> struct dbus_type_traits { const int value = DBUS_TYPE_INT64; const bool is_fixed = true; }; template<> struct dbus_type_traits { const int value = DBUS_TYPE_DOUBLE; const bool is_fixed = true; }; template<> struct dbus_type_traits { const int value = DBUS_TYPE_STRING; const bool is_fixed = false; }; // clang-format on template const int dbus_type_identifier = dbus_type_traits().value; template const bool is_fixed = dbus_type_traits().is_fixed; } // namespace detail class DBusMessageIter_wrap { public: DBusMessageIter_wrap(DBusMessage* msg, libdbus_loader* loader); DBusMessageIter_wrap(DBusMessageIter iter, libdbus_loader* loader); // Type accessors int type() const noexcept { return m_type; } bool is_unsigned() const noexcept; bool is_signed() const noexcept; bool is_string() const noexcept; bool is_double() const noexcept; bool is_primitive() const noexcept; bool is_array() const noexcept; operator bool() const noexcept { return type() != DBUS_TYPE_INVALID; } // Value accessors // Primitives template auto get_primitive() -> T; auto get_unsigned() -> uint64_t; auto get_signed() -> int64_t; auto get_stringified() -> std::string; // Composites auto get_array_iter() -> DBusMessageIter_wrap; auto get_dict_entry_iter() -> DBusMessageIter_wrap; // Looping template void array_for_each(Callable); template void array_for_each_stringify(Callable); template void array_for_each_value(Callable); template void string_map_for_each(Callable); template void string_multimap_for_each_stringify(Callable); auto next() -> DBusMessageIter_wrap&; private: DBusMessageIter resolve_variants() { auto iter = m_Iter; auto field_type = m_DBus->message_iter_get_arg_type(&m_Iter); while (field_type == DBUS_TYPE_VARIANT) { m_DBus->message_iter_recurse(&iter, &iter); field_type = m_DBus->message_iter_get_arg_type(&iter); } return iter; } DBusMessageIter m_Iter; DBusMessageIter m_resolved_iter; int m_type; libdbus_loader* m_DBus; }; DBusMessageIter_wrap::DBusMessageIter_wrap(DBusMessage* msg, libdbus_loader* loader) { m_DBus = loader; if (msg) { m_DBus->message_iter_init(msg, &m_Iter); m_resolved_iter = resolve_variants(); m_type = m_DBus->message_iter_get_arg_type(&m_resolved_iter); } else { m_type = DBUS_TYPE_INVALID; } } DBusMessageIter_wrap::DBusMessageIter_wrap(DBusMessageIter iter, libdbus_loader* loader) : m_Iter(iter), m_DBus(loader) { m_resolved_iter = resolve_variants(); m_type = m_DBus->message_iter_get_arg_type(&m_resolved_iter); } bool DBusMessageIter_wrap::is_unsigned() const noexcept { return ((type() == DBUS_TYPE_BYTE) || (type() == DBUS_TYPE_INT16) || (type() == DBUS_TYPE_INT32) || (type() == DBUS_TYPE_INT64)); } bool DBusMessageIter_wrap::is_signed() const noexcept { return ((type() == DBUS_TYPE_INT16) || (type() == DBUS_TYPE_INT32) || (type() == DBUS_TYPE_INT64)); } bool DBusMessageIter_wrap::is_string() const noexcept { return (type() == DBUS_TYPE_STRING); } bool DBusMessageIter_wrap::is_double() const noexcept { return (type() == DBUS_TYPE_DOUBLE); } bool DBusMessageIter_wrap::is_primitive() const noexcept { return (is_double() || is_signed() || is_unsigned() || is_string()); } bool DBusMessageIter_wrap::is_array() const noexcept { return (type() == DBUS_TYPE_ARRAY); } template auto DBusMessageIter_wrap::get_primitive() -> T { auto requested_type = detail::dbus_type_identifier; if (type() == DBUS_TYPE_OBJECT_PATH && requested_type == DBUS_TYPE_STRING) { // no special type, just a string } else if (requested_type != type()) { SPDLOG_ERROR("Type mismatch: '{}' vs '{}'", ((char)requested_type), (char)type()); #ifndef NDEBUG raise(SIGTRAP); #endif return T(); } T ret; m_DBus->message_iter_get_basic(&m_resolved_iter, &ret); return ret; } template <> auto DBusMessageIter_wrap::get_primitive() -> std::string { auto s = get_primitive(); if (!s) return std::string(); return std::string(s); } uint64_t DBusMessageIter_wrap::get_unsigned() { auto t = type(); switch (t) { case DBUS_TYPE_BYTE: return get_primitive(); case DBUS_TYPE_UINT16: return get_primitive(); case DBUS_TYPE_UINT32: return get_primitive(); case DBUS_TYPE_UINT64: return get_primitive(); default: return 0; } } int64_t DBusMessageIter_wrap::get_signed() { auto t = type(); switch (t) { case DBUS_TYPE_INT16: return get_primitive(); case DBUS_TYPE_INT32: return get_primitive(); case DBUS_TYPE_INT64: return get_primitive(); default: return 0; } } auto DBusMessageIter_wrap::get_stringified() -> std::string { if (is_string()) return get_primitive(); if (is_unsigned()) return std::to_string(get_unsigned()); if (is_signed()) return std::to_string(get_signed()); if (is_double()) return std::to_string(get_primitive()); SPDLOG_ERROR("stringify failed"); return std::string(); } auto DBusMessageIter_wrap::get_array_iter() -> DBusMessageIter_wrap { if (!is_array()) { SPDLOG_ERROR("Not an array; {}", (char)type()); return DBusMessageIter_wrap(DBusMessageIter{}, m_DBus); } DBusMessageIter ret; m_DBus->message_iter_recurse(&m_resolved_iter, &ret); return DBusMessageIter_wrap(ret, m_DBus); } auto DBusMessageIter_wrap::get_dict_entry_iter() -> DBusMessageIter_wrap { if (type() != DBUS_TYPE_DICT_ENTRY) { SPDLOG_ERROR("Not a dict entry {}", (char)type()); return DBusMessageIter_wrap(DBusMessageIter{}, m_DBus); } DBusMessageIter ret; m_DBus->message_iter_recurse(&m_resolved_iter, &ret); return DBusMessageIter_wrap(ret, m_DBus); } template void DBusMessageIter_wrap::array_for_each_value(Callable action) { auto iter = get_array_iter(); for (; iter; iter.next()) { action(iter.get_primitive()); } } template void DBusMessageIter_wrap::array_for_each(Callable action) { auto iter = get_array_iter(); for (; iter; iter.next()) { action(iter); } } template void DBusMessageIter_wrap::array_for_each_stringify(Callable action) { auto iter = get_array_iter(); for (; iter; iter.next()) { action(iter.get_stringified()); } } template void DBusMessageIter_wrap::string_map_for_each(T action) { auto iter = get_array_iter(); for (; iter; iter.next()) { auto it = iter.get_dict_entry_iter(); auto key = it.get_primitive(); it.next(); action(key, it); } } template void DBusMessageIter_wrap::string_multimap_for_each_stringify(T action) { string_map_for_each([&action](const std::string& key, DBusMessageIter_wrap it) { if (it.is_array()) { it.array_for_each_stringify( [&](const std::string& val) { action(key, val); }); } else if (it.is_primitive()) { action(key, it.get_stringified()); } }); } auto DBusMessageIter_wrap::next() -> DBusMessageIter_wrap& { if (!*this) return *this; m_DBus->message_iter_next(&m_Iter); // Resolve any variants m_resolved_iter = resolve_variants(); m_type = m_DBus->message_iter_get_arg_type(&m_resolved_iter); return *this; } class DBusMessage_wrap { public: DBusMessage_wrap(DBusMessage* msg, libdbus_loader* ldr, bool owning = false) : m_owning(owning), m_msg(msg), m_DBus(ldr) {} ~DBusMessage_wrap() { free_if_owning(); } DBusMessage_wrap(const DBusMessage_wrap&) = delete; DBusMessage_wrap(DBusMessage_wrap&&) = default; operator bool() const noexcept { return m_msg != nullptr; } template DBusMessage_wrap& argument(T arg); DBusMessage_wrap send_with_reply_and_block(DBusConnection* conn, int timeout); DBusMessageIter_wrap iter() { return DBusMessageIter_wrap(m_msg, m_DBus); } static DBusMessage_wrap new_method_call(const std::string& bus_name, const std::string& path, const std::string& iface, const std::string& method, libdbus_loader* loader); private: void free_if_owning(); bool m_owning; DBusMessage* m_msg; libdbus_loader* m_DBus; std::vector m_args; }; template DBusMessage_wrap& DBusMessage_wrap::argument(T arg) { if (!m_msg) return *this; if (!m_DBus->message_append_args(m_msg, detail::dbus_type_identifier, &arg, DBUS_TYPE_INVALID)) { free_if_owning(); } return *this; } template <> DBusMessage_wrap& DBusMessage_wrap::argument( const std::string& str) { return argument(str.c_str()); } DBusMessage_wrap DBusMessage_wrap::send_with_reply_and_block( DBusConnection* conn, int timeout) { if (!m_msg) { return DBusMessage_wrap(nullptr, m_DBus); } DBusError err; m_DBus->error_init(&err); auto reply = m_DBus->connection_send_with_reply_and_block(conn, m_msg, timeout, &err); if (reply == nullptr) { SPDLOG_ERROR("[{}]: {}", __func__, err.message); free_if_owning(); m_DBus->error_free(&err); } return DBusMessage_wrap(reply, m_DBus, true); } DBusMessage_wrap DBusMessage_wrap::new_method_call(const std::string& bus_name, const std::string& path, const std::string& iface, const std::string& method, libdbus_loader* loader) { auto msg = loader->message_new_method_call( (bus_name.empty()) ? nullptr : bus_name.c_str(), path.c_str(), (iface.empty()) ? nullptr : iface.c_str(), method.c_str()); return DBusMessage_wrap(msg, loader, true); } void DBusMessage_wrap::free_if_owning() { if (m_msg and m_owning) { m_DBus->message_unref(m_msg); } m_msg = nullptr; } } // namespace DBus_helpers #endif // MANGOHUD_DBUS_HELPERS ================================================ FILE: src/dbus_info.h ================================================ #pragma once #ifndef MANGOHUD_DBUS_INFO_H #define MANGOHUD_DBUS_INFO_H #ifdef HAVE_DBUS #include #include #include #include #include #include #include #include #include #include "loaders/loader_dbus.h" struct metadata { // std::vector artists; std::string artists; // pre-concatenate std::string title; std::string album; std::string something; std::string artUrl; bool playing = false; bool valid = false; bool got_song_data = false; bool got_playback_data = false; }; struct mp_fmt { std::string text; float width; }; struct mutexed_metadata { std::mutex mtx; metadata meta; struct { float pos; float longest; int dir = -1; bool needs_recalc = true; std::vector formatted; } ticker; }; enum SignalType { ST_NAMEOWNERCHANGED, ST_PROPERTIESCHANGED, }; extern struct mutexed_metadata main_metadata; namespace dbusmgr { class dbus_manager; using signal_handler_func = bool (dbus_manager::*)(DBusMessage*, const char*); enum Service { SRV_NONE = 0, SRV_MPRIS = (1ul << 0), SRV_GAMEMODE = (1ul << 1), SRV_ALL = 0xFFFFFFFF, }; struct DBusSignal { Service srv; const char* intf; const char* signal; signal_handler_func handler; }; class dbus_manager { public: dbus_manager() {} ~dbus_manager(); bool init(Service srv); bool init_mpris(const std::string& requested_player); void deinit(Service srv); bool get_media_player_metadata(metadata& meta, std::string name = ""); void connect_to_signals(Service srv); void disconnect_from_signals(Service srv); DBusConnection* get_conn() const { return m_dbus_conn; } bool gamemode_enabled(pid_t pid); libdbus_loader& dbus() { return m_dbus_ldr; } protected: bool init_internal(); void stop_thread(); void start_thread(); void dbus_thread(); bool dbus_list_name_to_owner(); bool select_active_player(); static DBusHandlerResult filter_signals(DBusConnection*, DBusMessage*, void*); bool handle_properties_changed(DBusMessage*, const char*); bool handle_name_owner_changed(DBusMessage*, const char*); bool handle_game_registered(DBusMessage*, const char*); bool handle_game_unregistered(DBusMessage*, const char*); void onNewPlayer( metadata& meta); // A different player has become the active player void onNoPlayer(); // There is no longer any player active void onPlayerUpdate( metadata& meta); // The active player has sent an update DBusError m_error; DBusConnection* m_dbus_conn = nullptr; bool m_quit = false; bool m_inited = false; std::thread m_thread; libdbus_loader m_dbus_ldr; std::unordered_map m_name_owners; std::string m_requested_player; std::string m_active_player; uint32_t m_active_srvs = SRV_NONE; const std::array m_signals{{ {SRV_MPRIS, "org.freedesktop.DBus", "NameOwnerChanged", &dbus_manager::handle_name_owner_changed}, {SRV_MPRIS, "org.freedesktop.DBus.Properties", "PropertiesChanged", &dbus_manager::handle_properties_changed}, // {SRV_GAMEMODE, "com.feralinteractive.GameMode", "GameRegistered", // &dbus_manager::handle_game_registered}, // {SRV_GAMEMODE, "com.feralinteractive.GameMode", "GameUnregistered", // &dbus_manager::handle_game_unregistered}, }}; }; extern dbus_manager dbus_mgr; } // namespace dbusmgr bool get_media_player_metadata(dbusmgr::dbus_manager& dbus, const std::string& name, metadata& meta); #endif // HAVE_DBUS #endif //MANGOHUD_DBUS_INFO_H ================================================ FILE: src/device.cpp ================================================ #include "device.h" #include #include #include #include namespace fs = ghc::filesystem; using namespace std; std::mutex device_lock; std::vector device_data; std::vector list; bool device_found = false; bool check_gamepad = false; bool check_mouse = false; int device_count = 0; int xbox_count = 0; int ds4_count = 0; int ds5_count = 0; int switch_count = 0; int bitdo_count = 0; int logi_count = 0; //Logitech devices, mice & keyboards etc. int shield_count = 0; std::string xbox_paths [2]{"gip","xpadneo"}; static bool operator<(const device_batt& a, const device_batt& b) { return a.name < b.name; } void device_update(const struct overlay_params& params){ std::unique_lock l(device_lock); fs::path path("/sys/class/power_supply"); list.clear(); xbox_count = 0; ds4_count = 0; ds5_count = 0; switch_count = 0; bitdo_count = 0; shield_count = 0; for (auto &p : fs::directory_iterator(path)) { string fileName = p.path().filename(); //Gamepads if (std::find(params.device_battery.begin(), params.device_battery.end(), "gamepad") != params.device_battery.end()){ check_gamepad = true; //CHECK XONE AND XPADNEO DEVICES for (string n : xbox_paths ) { if (fileName.find(n) != std::string::npos) { list.push_back(p.path()); device_found = true; xbox_count += 1; } } //CHECK FOR DUAL SHOCK 4 DEVICES if (fileName.find("sony_controller") != std::string::npos) { list.push_back(p.path()); device_found = true; ds4_count +=1 ; } if (fileName.find("ps-controller") != std::string::npos) { list.push_back(p.path()); device_found = true; ds5_count +=1 ; } //CHECK FOR NINTENDO SWITCH DEVICES if (fileName.find("nintendo_switch_controller") != std::string::npos) { list.push_back(p.path()); device_found = true; switch_count += 1; } //CHECK * BITDO DEVICES if (fileName.find("hid-e4") != std::string::npos) { list.push_back(p.path()); device_found = true; bitdo_count += 1; } //CHECK NVIDIA SHIELD DEVICES if (fileName.find("thunderstrike") != std::string::npos) { list.push_back(p.path()); device_found = true; shield_count += 1; } } // Mice and Keyboards //CHECK LOGITECH DEVICES if (std::find(params.device_battery.begin(), params.device_battery.end(), "mouse") != params.device_battery.end()) { check_mouse = true; if (fileName.find("hidpp_battery") != std::string::npos) { list.push_back(p.path()); device_found = true; } } } } void device_info () { std::unique_lock l(device_lock); device_count = 0; device_data.clear(); //gamepad counters int xbox_counter = 0; int ds4_counter = 0; int ds5_counter = 0; int switch_counter = 0; int bitdo_counter = 0; int shield_counter = 0; for (auto &path : list ) { //Set devices paths std::string capacity = path + "/capacity"; std::string capacity_level = path + "/capacity_level"; std::string status = path + "/status"; std::string model = path + "/model_name"; std::ifstream input_capacity(capacity); std::ifstream input_capacity_level(capacity_level); std::ifstream input_status(status); std::ifstream device_name(model); std::string line; device_data.push_back(device_batt()); // GAMEPADS //Xone and xpadneo devices if (check_gamepad == true) { if (path.find("gip") != std::string::npos || path.find("xpadneo") != std::string::npos) { if (xbox_count == 1 ) device_data[device_count].name = "XBOX PAD"; else device_data[device_count].name = "XBOX PAD-" + to_string(xbox_counter + 1); xbox_counter++; } //DualShock 4 devices if (path.find("sony_controller") != std::string::npos) { if (ds4_count == 1) device_data[device_count].name = "DS4 PAD"; else device_data[device_count].name = "DS4 PAD-" + to_string(ds4_counter + 1); ds4_counter++; } //DualSense 5 devices //Dual Shock 4 added to hid-playstation in Linux 6.2 if (path.find("ps-controller") != std::string::npos) { if (ds5_count == 1) device_data[device_count].name = "DS4/5 PAD"; else device_data[device_count].name = "DS4/5 PAD-" + to_string(ds5_counter + 1); ds5_counter++; } //Nintendo Switch devices if (path.find("nintendo_switch_controller") != std::string::npos) { if (switch_count == 1) device_data[device_count].name = "SWITCH PAD"; else device_data[device_count].name = "SWITCH PAD-" + to_string(switch_counter + 1); switch_counter++; } //8bitdo devices if (path.find("hid-e4") != std::string::npos) { if (bitdo_count == 1) device_data[device_count].name = "8BITDO PAD"; else device_data[device_count].name = "8BITDO PAD-" + to_string(bitdo_counter + 1); bitdo_counter++; } //Shield devices if (path.find("thunderstrike") != std::string::npos) { if (shield_count == 1) device_data[device_count].name = "SHIELD PAD"; else device_data[device_count].name = "SHIELD PAD-" + to_string(shield_counter + 1); shield_counter++; } } // MICE AND KEYBOARDS //Logitech Devices if (check_mouse == true) { if (path.find("hidpp_battery") != std::string::npos) { // Find a good way truncate name or retreive device type before using this // if (std::getline(device_name, line)) { // device_data[device_count].name = line; // } device_data[device_count].name = "LOGI MOUSE/KB"; } } //Get device charging status if (std::getline(input_status, line)) { if (line == "Charging" || line == "Full") device_data[device_count].is_charging = true; } //Get device Battery if (fs::exists(capacity)) { if (std::getline(input_capacity, line)) { device_data[device_count].battery_percent = line; device_data[device_count].report_percent = true; switch(std::stoi(line)) { case 0 ... 25: device_data[device_count].battery = "Low"; break; case 26 ... 49: device_data[device_count].battery = "Normal"; break; case 50 ... 74: device_data[device_count].battery = "High"; break; case 75 ... 100: device_data[device_count].battery = "Full"; break; } } } else { if (std::getline(input_capacity_level, line)) { device_data[device_count].battery = line; } } std::sort(device_data.begin(), device_data.end()); device_count += 1; } } ================================================ FILE: src/device.h ================================================ #pragma once #ifndef MANGOHUD_DEVICE_H #define MANGOHUD_DEVICE_H #include #include #include "overlay_params.h" struct overlay_params; struct device_batt { std::string battery; std::string name; bool report_percent; std::string battery_percent; bool is_charging; }; extern std::vector device_data; extern std::mutex device_lock; extern bool device_found; extern int device_count; void device_update(const overlay_params& params); void device_info(); #endif // MANGOHUD_DEVICE_H ================================================ FILE: src/elfhacks.c ================================================ /** * \file src/elfhacks.c * \brief various ELF run-time hacks * \author Pyry Haulos * \date 2007-2008 * For conditions of distribution and use, see copyright notice in elfhacks.h */ #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #include #include #include #include #include #include #include #include "elfhacks.h" #ifndef __ELF_NATIVE_CLASS #include "sys/reg.h" #define __ELF_NATIVE_CLASS __WORDSIZE #endif /** * \addtogroup elfhacks * \{ */ #if defined(__GLIBC__) && !(defined(__riscv) || defined(__mips__)) # define ABS_ADDR(obj, ptr) (ptr) #else # define ABS_ADDR(obj, ptr) ((obj->addr) + (ptr)) #endif struct eh_iterate_callback_args { eh_iterate_obj_callback_func callback; void *arg; }; int eh_check_addr(eh_obj_t *obj, const void *addr); int eh_find_callback(struct dl_phdr_info *info, size_t size, void *argptr); int eh_find_next_dyn(eh_obj_t *obj, ElfW_Sword tag, int i, ElfW(Dyn) **next); int eh_init_obj(eh_obj_t *obj); int eh_set_rela_plt(eh_obj_t *obj, int p, const char *sym, void *val); int eh_set_rel_plt(eh_obj_t *obj, int p, const char *sym, void *val); int eh_iterate_rela_plt(eh_obj_t *obj, int p, eh_iterate_rel_callback_func callback, void *arg); int eh_iterate_rel_plt(eh_obj_t *obj, int p, eh_iterate_rel_callback_func callback, void *arg); int eh_iterate_callback(struct dl_phdr_info *info, size_t size, void *argptr); int eh_find_sym_hash(eh_obj_t *obj, const char *name, eh_sym_t *sym); int eh_find_sym_gnu_hash(eh_obj_t *obj, const char *name, eh_sym_t *sym); ElfW(Word) eh_hash_elf(const char *name); Elf32_Word eh_hash_gnu(const char *name); int eh_find_callback(struct dl_phdr_info *info, size_t size, void *argptr) { eh_obj_t *find = (eh_obj_t *) argptr; if (find->name == NULL) { if (strcmp(info->dlpi_name, "")) return 0; } else if (fnmatch(find->name, info->dlpi_name, 0)) return 0; if (find->name == NULL) /* TODO readlink? */ find->name = "/proc/self/exe"; else find->name = info->dlpi_name; find->addr = info->dlpi_addr; /* segment headers */ find->phdr = info->dlpi_phdr; find->phnum = info->dlpi_phnum; return 0; } int eh_iterate_callback(struct dl_phdr_info *info, size_t size, void *argptr) { struct eh_iterate_callback_args *args = argptr; eh_obj_t obj; int ret = 0; /* eh_init_obj needs phdr and phnum */ obj.phdr = info->dlpi_phdr; obj.phnum = info->dlpi_phnum; obj.addr = info->dlpi_addr; obj.name = info->dlpi_name; if ((ret = eh_init_obj(&obj))) { if (ret == ENOTSUP) /* just skip */ return 0; return ret; } if ((ret = args->callback(&obj, args->arg))) return ret; if ((ret = eh_destroy_obj(&obj))) return ret; return 0; } int eh_iterate_obj(eh_iterate_obj_callback_func callback, void *arg) { int ret; struct eh_iterate_callback_args args; args.callback = callback; args.arg = arg; if ((ret = dl_iterate_phdr(eh_iterate_callback, &args))) return ret; return 0; } int eh_find_obj(eh_obj_t *obj, const char *soname) { /* This function uses glibc-specific dl_iterate_phdr(). Another way could be parsing /proc/self/exe or using pmap() on Solaris or *BSD */ obj->phdr = NULL; obj->name = soname; dl_iterate_phdr(eh_find_callback, obj); if (!obj->phdr) return EAGAIN; return eh_init_obj(obj); } int eh_check_addr(eh_obj_t *obj, const void *addr) { /* Check that given address is inside program's memory maps. PT_LOAD program headers tell us where program has been loaded into. */ int p; for (p = 0; p < obj->phnum; p++) { if (obj->phdr[p].p_type == PT_LOAD) { if (((ElfW(Addr)) addr < obj->phdr[p].p_memsz + obj->phdr[p].p_vaddr + obj->addr) && ((ElfW(Addr)) addr >= obj->phdr[p].p_vaddr + obj->addr)) return 0; } } return EINVAL; } int eh_init_obj(eh_obj_t *obj) { /* ELF spec says in section header documentation, that: "An object file may have only one dynamic section." Let's assume it means that object has only one PT_DYNAMIC as well. */ int p; obj->dynamic = NULL; for (p = 0; p < obj->phnum; p++) { if (obj->phdr[p].p_type == PT_DYNAMIC) { if (obj->dynamic) return ENOTSUP; obj->dynamic = (ElfW(Dyn) *) (obj->phdr[p].p_vaddr + obj->addr); } } if (!obj->dynamic) return ENOTSUP; /* ELF spec says that program is allowed to have more than one .strtab but does not describe how string table indexes translate to multiple string tables. And spec says that only one SHT_HASH is allowed, does it mean that obj has only one DT_HASH? About .symtab it does not mention anything about if multiple symbol tables are allowed or not. Maybe st_shndx is the key here? */ obj->strtab = NULL; obj->hash = NULL; obj->gnu_hash = NULL; obj->symtab = NULL; p = 0; while (obj->dynamic[p].d_tag != DT_NULL) { if (obj->dynamic[p].d_tag == DT_STRTAB) { if (obj->strtab) return ENOTSUP; obj->strtab = (const char *) ABS_ADDR(obj, obj->dynamic[p].d_un.d_ptr); } else if (obj->dynamic[p].d_tag == DT_HASH) { if (obj->hash) return ENOTSUP; obj->hash = (ElfW(Word) *) ABS_ADDR(obj, obj->dynamic[p].d_un.d_ptr); } else if (obj->dynamic[p].d_tag == DT_GNU_HASH) { if (obj->gnu_hash) return ENOTSUP; obj->gnu_hash = (Elf32_Word *) ABS_ADDR(obj, obj->dynamic[p].d_un.d_ptr); } else if (obj->dynamic[p].d_tag == DT_SYMTAB) { if (obj->symtab) return ENOTSUP; obj->symtab = (ElfW(Sym) *) ABS_ADDR(obj, obj->dynamic[p].d_un.d_ptr); } p++; } /* This is here to catch b0rken headers (vdso) */ if ((eh_check_addr(obj, (const void *) obj->strtab)) | (eh_check_addr(obj, (const void *) obj->symtab))) return ENOTSUP; if (obj->hash) { /* DT_HASH found */ if (eh_check_addr(obj, (void *) obj->hash)) obj->hash = NULL; } else if (obj->gnu_hash) { /* DT_GNU_HASH found */ if (eh_check_addr(obj, (void *) obj->gnu_hash)) obj->gnu_hash = NULL; } return 0; } int eh_find_sym(eh_obj_t *obj, const char *name, void **to) { eh_sym_t sym; /* DT_GNU_HASH is faster ;) */ if (obj->gnu_hash) { if (!eh_find_sym_gnu_hash(obj, name, &sym)) { *to = (void *) (sym.sym->st_value + obj->addr); return 0; } } /* maybe it is in DT_HASH or DT_GNU_HASH is not present */ if (obj->hash) { if (!eh_find_sym_hash(obj, name, &sym)) { *to = (void *) (sym.sym->st_value + obj->addr); return 0; } } return EAGAIN; } ElfW(Word) eh_hash_elf(const char *name) { ElfW(Word) tmp, hash = 0; const unsigned char *uname = (const unsigned char *) name; int c; while ((c = *uname++) != '\0') { hash = (hash << 4) + c; if ((tmp = (hash & 0xf0000000)) != 0) { hash ^= tmp >> 24; hash ^= tmp; } } return hash; } int eh_find_sym_hash(eh_obj_t *obj, const char *name, eh_sym_t *sym) { ElfW(Word) hash, *chain; ElfW(Sym) *esym; unsigned int bucket_idx, idx; if (!obj->hash) return ENOTSUP; if (obj->hash[0] == 0) return EAGAIN; hash = eh_hash_elf(name); /* First item in DT_HASH is nbucket, second is nchain. hash % nbucket gives us our bucket index. */ bucket_idx = obj->hash[2 + (hash % obj->hash[0])]; chain = &obj->hash[2 + obj->hash[0] + bucket_idx]; idx = 0; sym->sym = NULL; /* we have to check symtab[bucket_idx] first */ esym = &obj->symtab[bucket_idx]; if (esym->st_name) { if (!strcmp(&obj->strtab[esym->st_name], name)) sym->sym = esym; } while ((sym->sym == NULL) && (chain[idx] != STN_UNDEF)) { esym = &obj->symtab[chain[idx]]; if (esym->st_name) { if (!strcmp(&obj->strtab[esym->st_name], name)) sym->sym = esym; } idx++; } /* symbol not found */ if (sym->sym == NULL) return EAGAIN; sym->obj = obj; sym->name = &obj->strtab[sym->sym->st_name]; return 0; } Elf32_Word eh_hash_gnu(const char *name) { Elf32_Word hash = 5381; const unsigned char *uname = (const unsigned char *) name; int c; while ((c = *uname++) != '\0') hash = (hash << 5) + hash + c; return hash & 0xffffffff; } int eh_find_sym_gnu_hash(eh_obj_t *obj, const char *name, eh_sym_t *sym) { Elf32_Word *buckets, *chain_zero, *hasharr; ElfW(Addr) *bitmask, bitmask_word; Elf32_Word symbias, bitmask_nwords, bucket, nbuckets, bitmask_idxbits, shift; Elf32_Word hash, hashbit1, hashbit2; ElfW(Sym) *esym; if (!obj->gnu_hash) return ENOTSUP; if (obj->gnu_hash[0] == 0) return EAGAIN; sym->sym = NULL; /* Initialize our hash table stuff DT_GNU_HASH is(?): [nbuckets] [symbias] [bitmask_nwords] [shift] [bitmask_nwords * ElfW(Addr)] <- bitmask [nbuckets * Elf32_Word] <- buckets ...chains? - symbias... */ nbuckets = obj->gnu_hash[0]; symbias = obj->gnu_hash[1]; bitmask_nwords = obj->gnu_hash[2]; /* must be power of two */ bitmask_idxbits = bitmask_nwords - 1; shift = obj->gnu_hash[3]; bitmask = (ElfW(Addr) *) &obj->gnu_hash[4]; buckets = &obj->gnu_hash[4 + (__ELF_NATIVE_CLASS / 32) * bitmask_nwords]; chain_zero = &buckets[nbuckets] - symbias; /* hash our symbol */ hash = eh_hash_gnu(name); /* bitmask stuff... no idea really :D */ bitmask_word = bitmask[(hash / __ELF_NATIVE_CLASS) & bitmask_idxbits]; hashbit1 = hash & (__ELF_NATIVE_CLASS - 1); hashbit2 = (hash >> shift) & (__ELF_NATIVE_CLASS - 1); /* wtf this does actually? */ if (!((bitmask_word >> hashbit1) & (bitmask_word >> hashbit2) & 1)) return EAGAIN; /* locate bucket */ bucket = buckets[hash % nbuckets]; if (bucket == 0) return EAGAIN; /* and find match in chain */ hasharr = &chain_zero[bucket]; do { if (((*hasharr ^ hash) >> 1) == 0) { /* hash matches, but does the name? */ esym = &obj->symtab[hasharr - chain_zero]; if (esym->st_name) { if (!strcmp(&obj->strtab[esym->st_name], name)) { sym->sym = esym; break; } } } } while ((*hasharr++ & 1u) == 0); /* symbol not found */ if (sym->sym == NULL) return EAGAIN; sym->obj = obj; sym->name = &obj->strtab[sym->sym->st_name]; return 0; } int eh_iterate_sym(eh_obj_t *obj, eh_iterate_sym_callback_func callback, void *arg) { return ENOTSUP; } int eh_find_next_dyn(eh_obj_t *obj, ElfW_Sword tag, int i, ElfW(Dyn) **next) { /* first from i + 1 to end, then from start to i - 1 */ int p; *next = NULL; p = i + 1; while (obj->dynamic[p].d_tag != DT_NULL) { if (obj->dynamic[p].d_tag == tag) { *next = &obj->dynamic[p]; return 0; } p++; } p = 0; while ((obj->dynamic[i].d_tag != DT_NULL) && (p < i)) { if (obj->dynamic[p].d_tag == tag) { *next = &obj->dynamic[p]; return 0; } p++; } return EAGAIN; } int eh_set_rela_plt(eh_obj_t *obj, int p, const char *sym, void *val) { ElfW(Rela) *rela = (ElfW(Rela) *) ABS_ADDR(obj, obj->dynamic[p].d_un.d_ptr); ElfW(Dyn) *relasize; unsigned int i; /* DT_PLTRELSZ contains PLT relocs size in bytes */ if (eh_find_next_dyn(obj, DT_PLTRELSZ, p, &relasize)) return EINVAL; /* b0rken elf :/ */ for (i = 0; i < relasize->d_un.d_val / sizeof(ElfW(Rela)); i++) { if (!obj->symtab[ELFW_R_SYM(rela[i].r_info)].st_name) continue; if (!strcmp(&obj->strtab[obj->symtab[ELFW_R_SYM(rela[i].r_info)].st_name], sym)) *((void **) (rela[i].r_offset + obj->addr)) = val; } return 0; } int eh_set_rel_plt(eh_obj_t *obj, int p, const char *sym, void *val) { ElfW(Rel) *rel = (ElfW(Rel) *) ABS_ADDR(obj, obj->dynamic[p].d_un.d_ptr); ElfW(Dyn) *relsize; unsigned int i; if (eh_find_next_dyn(obj, DT_PLTRELSZ, p, &relsize)) return EINVAL; /* b0rken elf :/ */ for (i = 0; i < relsize->d_un.d_val / sizeof(ElfW(Rel)); i++) { if (!obj->symtab[ELFW_R_SYM(rel[i].r_info)].st_name) continue; if (!strcmp(&obj->strtab[obj->symtab[ELFW_R_SYM(rel[i].r_info)].st_name], sym)) *((void **) (rel[i].r_offset + obj->addr)) = val; } return 0; } int eh_set_rel(eh_obj_t *obj, const char *sym, void *val) { /* Elf spec states that object is allowed to have multiple .rel.plt and .rela.plt tables, so we will support 'em - here. */ ElfW(Dyn) *pltrel; int ret, p = 0; while (obj->dynamic[p].d_tag != DT_NULL) { /* DT_JMPREL contains .rel.plt or .rela.plt */ if (obj->dynamic[p].d_tag == DT_JMPREL) { /* DT_PLTREL tells if it is Rela or Rel */ eh_find_next_dyn(obj, DT_PLTREL, p, &pltrel); if (pltrel->d_un.d_val == DT_RELA) { if ((ret = eh_set_rela_plt(obj, p, sym, val))) return ret; } else if (pltrel->d_un.d_val == DT_REL) { if ((ret = eh_set_rel_plt(obj, p, sym, val))) return ret; } else return EINVAL; } p++; } return 0; } int eh_iterate_rela_plt(eh_obj_t *obj, int p, eh_iterate_rel_callback_func callback, void *arg) { ElfW(Rela) *rela = (ElfW(Rela) *) ABS_ADDR(obj, obj->dynamic[p].d_un.d_ptr); ElfW(Dyn) *relasize; eh_rel_t rel; eh_sym_t sym; unsigned int i, ret; rel.sym = &sym; rel.rel = NULL; rel.obj = obj; if (eh_find_next_dyn(obj, DT_PLTRELSZ, p, &relasize)) return EINVAL; for (i = 0; i < relasize->d_un.d_val / sizeof(ElfW(Rela)); i++) { rel.rela = &rela[i]; sym.sym = &obj->symtab[ELFW_R_SYM(rel.rela->r_info)]; if (sym.sym->st_name) sym.name = &obj->strtab[sym.sym->st_name]; else sym.name = NULL; if ((ret = callback(&rel, arg))) return ret; } return 0; } int eh_iterate_rel_plt(eh_obj_t *obj, int p, eh_iterate_rel_callback_func callback, void *arg) { ElfW(Rel) *relp = (ElfW(Rel) *) ABS_ADDR(obj, obj->dynamic[p].d_un.d_ptr); ElfW(Dyn) *relsize; eh_rel_t rel; eh_sym_t sym; unsigned int i, ret; rel.sym = &sym; rel.rela = NULL; rel.obj = obj; if (eh_find_next_dyn(obj, DT_PLTRELSZ, p, &relsize)) return EINVAL; for (i = 0; i < relsize->d_un.d_val / sizeof(ElfW(Rel)); i++) { rel.rel = &relp[i]; sym.sym = &obj->symtab[ELFW_R_SYM(rel.rel->r_info)]; if (sym.sym->st_name) sym.name = &obj->strtab[sym.sym->st_name]; else sym.name = NULL; if ((ret = callback(&rel, arg))) return ret; } return 0; } int eh_iterate_rel(eh_obj_t *obj, eh_iterate_rel_callback_func callback, void *arg) { ElfW(Dyn) *pltrel; int ret, p = 0; while (obj->dynamic[p].d_tag != DT_NULL) { if (obj->dynamic[p].d_tag == DT_JMPREL) { eh_find_next_dyn(obj, DT_PLTREL, p, &pltrel); if (pltrel->d_un.d_val == DT_RELA) { if ((ret = eh_iterate_rela_plt(obj, p, callback, arg))) return ret; } else if (pltrel->d_un.d_val == DT_REL) { if ((ret = eh_iterate_rel_plt(obj, p, callback, arg))) return ret; } else return EINVAL; } p++; } return 0; } int eh_destroy_obj(eh_obj_t *obj) { obj->phdr = NULL; return 0; } /** \} */ ================================================ FILE: src/fcat.h ================================================ #pragma once #ifndef MANGOHUD_FCAT_H #define MANGOHUD_FCAT_H #include #include #include #include #include #include #include #include "timing.hpp" #include "overlay_params.h" #include "overlay.h" struct fcatoverlay{ const struct overlay_params* params = nullptr; const std::array sequence={{{255, 255, 255},{0, 255, 0},{0, 0, 255},{255, 0, 0},{0, 128, 128},{0, 0, 128},{0, 128, 0},{0, 255, 255},{128, 0, 0},{192, 192, 192},{128, 0, 128},{128, 128, 0},{128, 128, 128},{255, 0, 255},{255, 255, 0},{255, 128, 0}}}; void update(const struct overlay_params* params_){ params=params_; }; ImColor get_next_color (const swapchain_stats& sw_stats){ size_t currentColor = sw_stats.n_frames % 16;// should probably be sequence.size(); but this doesn't matter as all FCAT analysis tools use this exact 16 colour sequence. ImColor output = sequence[currentColor]; return output; }; std::array get_overlay_corners() { unsigned short screen_edge=params->fcat_screen_edge; auto window_size = ImVec2(params->fcat_overlay_width,ImGui::GetIO().DisplaySize.y); auto p_min = ImVec2(0.,0.); auto p_max = ImVec2(window_size.x,ImGui::GetIO().DisplaySize.y); //Switch the used screen edge, this enables capture from devices with any screen orientation. //This goes counter-clockwise from the left edge (0) switch (screen_edge) { default: case 0: break; case 1: window_size = ImVec2(ImGui::GetIO().DisplaySize.x,window_size.x); p_min = ImVec2(0,ImGui::GetIO().DisplaySize.y - window_size.y); p_max = ImVec2(ImGui::GetIO().DisplaySize.x,ImGui::GetIO().DisplaySize.y); break; case 2: window_size = ImVec2(window_size.x,ImGui::GetIO().DisplaySize.y); p_min = ImVec2(ImGui::GetIO().DisplaySize.x-window_size.x,0); p_max = ImVec2(ImGui::GetIO().DisplaySize.x,ImGui::GetIO().DisplaySize.y); break; case 3: window_size = ImVec2(ImGui::GetIO().DisplaySize.x,window_size.x); p_min = ImVec2(0,0); p_max = ImVec2(ImGui::GetIO().DisplaySize.x,window_size.y); break; } std::array output={{p_min,p_max,window_size}}; return output; }; }; #endif ================================================ FILE: src/fex.cpp ================================================ #include #include #include #include #include #include "fex.h" #include "hud_elements.h" #include "mesa/util/macros.h" #if defined(__x86_64__) || defined(__i386__) #include #endif constexpr uint64_t AlignUp(uint64_t Value, uint64_t Alignment) { return Value + (Alignment - Value % Alignment) % Alignment; } namespace fex { const char* fex_status = "Not Found!"; std::string fex_version; std::vector fex_load_data(200,0.f); fex_event_counts sigbus_counts; fex_event_counts smc_counts; fex_event_counts softfloat_counts; std::vector fex_max_thread_loads; constexpr static uint32_t MAXIMUM_THREAD_WAIT_TIME = 10; // FEX-Emu stats definitions // Semantically these match upstream FEX-Emu. constexpr uint32_t FEX_STATS_VERSION = 2; enum class AppType : uint8_t { LINUX_32, LINUX_64, WIN_ARM64EC, WIN_WOW64, }; // The profile statistics header that is at the base of the shared memory mapped from FEX. // The version member is guaranteed to be first, to ensure that any version changes can be picked up immediately. struct fex_stats_header { uint8_t Version; AppType app_type; uint16_t thread_stats_size; char fex_version[48]; // Atomic variables. std::atomic_ref isn't available until C++20, so need to use GCC builtin atomics to access. uint32_t Head; uint32_t Size; uint32_t Pad; }; // The thread-specific datapoints. If TID is zero then it is deallocated and happens to still be in the linked list. struct fex_thread_stats { // Atomic variables. uint32_t Next; uint32_t TID; // Thread-specific stats. uint64_t AccumulatedJITTime; uint64_t AccumulatedSignalTime; uint64_t AccumulatedSIGBUSCount; uint64_t AccumulatedSMCEvents; uint64_t AccumulatedFloatFallbackCount; }; // This is guaranteed by FEX. static_assert(sizeof(fex_thread_stats) % 16 == 0, ""); // Sampled stats information struct fex_stats { int pid {-1}; int shm_fd {-1}; bool first_sample = true; uint32_t shm_size{}; uint64_t cycle_counter_frequency{}; size_t hardware_concurrency{}; size_t page_size{}; void* shm_base{}; size_t fex_thread_stats_size {}; fex_stats_header* head{}; fex_thread_stats* stats{}; struct retained_stats { std::chrono::time_point last_seen{}; fex_thread_stats previous{}; fex_thread_stats current{}; }; std::chrono::time_point previous_sample_period; std::map sampled_stats; }; fex_stats g_stats {}; const char* get_fex_app_type() { if (!g_stats.head) { return "Unknown"; } // These are the only application types that FEX-Emu supports today. // Linux32: A 32-bit x86 Linux application // Linux64: A 64-bit x86_64 Linux application // arm64ec: A 64-bit x86_64 WINE application // wow64: A 32-bit x86 WINE application switch (g_stats.head->app_type) { case AppType::LINUX_32: return "Linux32"; case AppType::LINUX_64: return "Linux64"; case AppType::WIN_ARM64EC: return "arm64ec"; case AppType::WIN_WOW64: return "wow64"; default: return "Unknown"; } } static fex_thread_stats *offset_to_stats(void* shm_base, uint32_t *offset) { const auto ld = __atomic_load_n(offset, __ATOMIC_RELAXED); if (ld == 0) return nullptr; return reinterpret_cast(reinterpret_cast(shm_base) + ld); } static fex_thread_stats *offset_to_stats(void* shm_base, uint32_t offset) { if (offset == 0) return nullptr; return reinterpret_cast(reinterpret_cast(shm_base) + offset); } #ifdef __aarch64__ static void memory_barrier() { asm volatile("dmb ishst" ::: "memory"); } static uint64_t get_cycle_counter_frequency() { uint64_t result; asm ("mrs %[res], CNTFRQ_EL0;" : [res] "=r" (result)); return result; } bool is_fex_capable() { // All aarch64 systems are fex capable. return true; } #elif defined(__x86_64__) || defined(__i386__) static void memory_barrier() { // Intentionally empty. } static void cpuid(uint32_t leaf, uint32_t &eax, uint32_t &ebx, uint32_t &ecx, uint32_t &edx) { asm volatile("cpuid" : "=a"(eax), "=b"(ebx), "=c"(ecx), "=d"(edx) : "a"(leaf), "c"(0)); } bool is_fex_capable() { // FEX-Emu CPUID documentation: https://github.com/FEX-Emu/FEX/blob/main/docs/CPUID.md const uint32_t HYPERVISOR_BIT = 1U << 31; const char FEXHypervisorString[] = "FEXIFEXIEMU"; char HypervisorString[4 * 3]; uint32_t eax, ebx, ecx, edx; // Check that the hypervisor bit is set first. Not required, but good to do. cpuid(1, eax, ebx, ecx, edx); if ((ecx & HYPERVISOR_BIT) != HYPERVISOR_BIT) return false; // Once the hypervisor bit is set, query the hypervisor leaf. cpuid(0x4000'0000U, eax, ebx, ecx, edx); if (eax == 0) return false; // If the hypervisor description matches FEX then we're good. memcpy(&HypervisorString[0], &ebx, sizeof(uint32_t)); memcpy(&HypervisorString[4], &ecx, sizeof(uint32_t)); memcpy(&HypervisorString[8], &edx, sizeof(uint32_t)); if (strncmp(HypervisorString, FEXHypervisorString, sizeof(HypervisorString)) != 0) return false; return true; } static uint64_t get_cycle_counter_frequency() { // In a FEX-Emu environment, the cycle counter frequency is exposed in CPUID leaf 0x15. // This matches x86 Intel semantics on latest CPUs, see their documentation for the exact implementation details. uint32_t eax, ebx, ecx, edx; cpuid(0, eax, ebx, ecx, edx); if (eax < 0x15) return 0; cpuid(0x15U, eax, ebx, ecx, edx); // Ignore scale in ebx // Baseline clock is provided in ecx. return ecx; } #endif static void atomic_copy_thread_stats(fex_thread_stats *dest, const fex_thread_stats *src) { #if defined(__x86_64__) || defined(__i386__) // For x86 platforms, XMM copies are atomic when aligned. So this guarantees single-copy atomicity. // x86 has no equivalent of an true "atomic" 128-bit GPR loadstore until APX. // For FEX emulating x86 platforms, this is also a guarantee for ARMv8.4 and newer. using copy_type = __m128; #else // For ARM64 platforms this is basically guaranteed to turn in to ldp+stp. // For ARM8.4 this gives us single-copy atomicity guarantees. using copy_type = __uint128_t; #endif const auto elements_to_copy = g_stats.fex_thread_stats_size / sizeof(copy_type); auto d_i = reinterpret_cast(dest); auto s_i = reinterpret_cast(src); for (size_t i = 0; i < elements_to_copy; ++i) { d_i[i] = s_i[i]; } } static void destroy_shm() { munmap(g_stats.shm_base, g_stats.shm_size); close(g_stats.shm_fd); g_stats.shm_fd = -1; g_stats.shm_size = 0; g_stats.shm_base = nullptr; g_stats.head = nullptr; g_stats.stats = nullptr; g_stats.sampled_stats.clear(); } static void init_shm(int pid) { // Initialize global hardware stats. g_stats.cycle_counter_frequency = get_cycle_counter_frequency(); g_stats.hardware_concurrency = std::thread::hardware_concurrency(); g_stats.page_size = sysconf(_SC_PAGESIZE); if (g_stats.page_size <= 0) g_stats.page_size = 4096; // Try and open a FEX stats file that relates to the PID in focus. // If this fails then it is non-fatal, just means FEX isn't creating stats for that process. std::string f = "fex-"; f += std::to_string(pid); f += "-stats"; int fd {-1}; struct stat buf{}; uint64_t shm_size{}; void* shm_base{MAP_FAILED}; fex_stats_header *header{}; fd = shm_open(f.c_str(), O_RDONLY, 0); if (fd == -1) { goto err; } if (fstat(fd, &buf) == -1) { goto err; } if (buf.st_size < static_cast(sizeof(fex_stats_header))) { goto err; } shm_size = AlignUp(buf.st_size, g_stats.page_size); shm_base = mmap(nullptr, shm_size, PROT_READ, MAP_SHARED, fd, 0); if (shm_base == MAP_FAILED) { goto err; } memory_barrier(); header = reinterpret_cast(shm_base); if (header->Version != FEX_STATS_VERSION) { // If the version read doesn't match the implementation then we can't read. fex_status = "version mismatch"; goto err; } if (g_stats.shm_fd != -1) { // Destroy first if the FD changed. destroy_shm(); } // Cache off the information, we have successfully loaded the stats SHM. g_stats.pid = pid; g_stats.shm_fd = fd; g_stats.shm_size = shm_size; g_stats.shm_base = shm_base; g_stats.head = header; g_stats.stats = offset_to_stats(shm_base, &header->Head); g_stats.previous_sample_period = std::chrono::steady_clock::now(); g_stats.first_sample = true; g_stats.sampled_stats.clear(); g_stats.fex_thread_stats_size = sizeof(fex_thread_stats); if (g_stats.head->thread_stats_size) { // If thread stats size is provided, use that, as long as it is smaller than tracking size. g_stats.fex_thread_stats_size = std::min(g_stats.head->thread_stats_size, g_stats.fex_thread_stats_size); } fex_version = std::string {header->fex_version, strnlen(header->fex_version, sizeof(header->fex_version))}; sigbus_counts.account_time(g_stats.previous_sample_period); smc_counts.account_time(g_stats.previous_sample_period); softfloat_counts.account_time(g_stats.previous_sample_period); std::fill(fex_load_data.begin(), fex_load_data.end(), 0.0); fex_max_thread_loads.clear(); return; err: if (fd != -1) { close(fd); } if (shm_base != MAP_FAILED) { munmap(shm_base, shm_size); } } static void check_shm_update_necessary() { // If the SHM has changed size then we need to unmap and remap with the new size. // Required since FEX may grow the SHM region to fit more threads, although previous thread data won't be invalidated. memory_barrier(); auto new_shm_size = AlignUp(__atomic_load_n(&g_stats.head->Size, __ATOMIC_RELAXED), g_stats.page_size); if (g_stats.shm_size == new_shm_size) { return; } munmap(g_stats.shm_base, g_stats.shm_size); g_stats.shm_size = new_shm_size; g_stats.shm_base = mmap(nullptr, new_shm_size, PROT_READ, MAP_SHARED, g_stats.shm_fd, 0); g_stats.head = reinterpret_cast(g_stats.shm_base); g_stats.stats = offset_to_stats(g_stats.shm_base, &g_stats.head->Head); g_stats.fex_thread_stats_size = sizeof(fex_thread_stats); if (g_stats.head->thread_stats_size) { // If thread stats size is provided, use that, as long as it is smaller than tracking size. g_stats.fex_thread_stats_size = std::min(g_stats.head->thread_stats_size, g_stats.fex_thread_stats_size); } } bool is_fex_pid_found() { return g_stats.pid != -1; } void update_fex_stats() { auto gs_pid = HUDElements.g_gamescopePid > 0 ? HUDElements.g_gamescopePid : ::getpid(); if (gs_pid < 1) { // No PID yet. return; } if (g_stats.pid != gs_pid) { // PID changed, likely gamescope changed focus. init_shm(gs_pid); } if (g_stats.pid == -1) { // PID became invalid. Likely due to error reading SHM. return; } // Check if SHM changed first. check_shm_update_necessary(); // Before reading stats, a memory barrier needs to be done. // This ensures visibility of the stats before reading, as they use weak atomics for writes. memory_barrier(); // Sample the stats and store them off. // Sampling these quickly lets us become a loose sampling profiler, since FEX updates these constantly. uint32_t *header_offset_atomic = &g_stats.head->Head; auto now = std::chrono::steady_clock::now(); for (auto header_offset = __atomic_load_n(header_offset_atomic, __ATOMIC_RELAXED); header_offset != 0; header_offset = __atomic_load_n(header_offset_atomic, __ATOMIC_RELAXED)) { if (header_offset >= g_stats.shm_size) break; fex_thread_stats *stat = offset_to_stats(g_stats.shm_base, header_offset); const auto TID = __atomic_load_n(&stat->TID, __ATOMIC_RELAXED); if (TID != 0) { fex_stats::retained_stats &sampled_stats = g_stats.sampled_stats[TID]; atomic_copy_thread_stats(&sampled_stats.current, stat); sampled_stats.last_seen = now; } header_offset_atomic = &stat->Next; } if (g_stats.first_sample) { // Skip first sample, it'll look crazy. g_stats.first_sample = false; fex_status = "Accumulating"; return; } // Update the status with the FEX version. fex_status = fex_version.c_str(); // Accumulate full JIT time uint64_t total_jit_time{}; uint64_t total_sigbus_events{}; uint64_t total_smc_events{}; uint64_t total_softfloat_events{}; size_t threads_sampled{}; #define accumulate(dest, name) dest += it->second.current.name - it->second.previous.name std::vector hottest_threads{}; for (auto it = g_stats.sampled_stats.begin(); it != g_stats.sampled_stats.end();) { ++threads_sampled; uint64_t total_time{}; accumulate(total_time, AccumulatedJITTime); accumulate(total_time, AccumulatedSignalTime); accumulate(total_sigbus_events, AccumulatedSIGBUSCount); accumulate(total_smc_events, AccumulatedSMCEvents); accumulate(total_softfloat_events, AccumulatedFloatFallbackCount); memcpy(&it->second.previous, &it->second.current, g_stats.fex_thread_stats_size); total_jit_time += total_time; if ((now - it->second.last_seen) >= std::chrono::seconds(MAXIMUM_THREAD_WAIT_TIME)) { it = g_stats.sampled_stats.erase(it); continue; } hottest_threads.emplace_back(total_time); ++it; } std::sort(hottest_threads.begin(), hottest_threads.end(), std::greater()); // Calculate loads based on the sample period that occurred. // FEX-Emu only counts cycles for the amount of time, so we need to calculate load based on the number of cycles that the sample period has. const auto sample_period = now - g_stats.previous_sample_period; const double NanosecondsInSeconds = 1'000'000'000.0; const double SamplePeriodNanoseconds = std::chrono::duration_cast(sample_period).count(); const double MaximumCyclesInSecond = (double)g_stats.cycle_counter_frequency; const double MaximumCyclesInSamplePeriod = MaximumCyclesInSecond * (SamplePeriodNanoseconds / NanosecondsInSeconds); const double MaximumCoresThreadsPossible = std::min(g_stats.hardware_concurrency, threads_sampled); // Calculate the percentage of JIT time that could possibly exist inside the sample period. double fex_load = ((double)total_jit_time / (MaximumCyclesInSamplePeriod * MaximumCoresThreadsPossible)) * 100.0; size_t minimum_hot_threads = std::min(g_stats.hardware_concurrency, hottest_threads.size()); // For the top thread-loads, we are only ever showing up to how many hardware threads are available. fex_max_thread_loads.resize(minimum_hot_threads); for (size_t i = 0; i < minimum_hot_threads; ++i) { fex_max_thread_loads[i] = ((double)hottest_threads[i] / MaximumCyclesInSamplePeriod) * 100.0; } sigbus_counts.account(total_sigbus_events, now); smc_counts.account(total_smc_events, now); softfloat_counts.account(total_softfloat_events, now); g_stats.previous_sample_period = now; fex_load_data.push_back(fex_load); fex_load_data.erase(fex_load_data.begin()); } } ================================================ FILE: src/fex.h ================================================ #pragma once #ifdef HAVE_FEX #ifndef MANGOHUD_FEX_H #define MANGOHUD_FEX_H #include #include #include namespace fex { bool is_fex_capable(); bool is_fex_pid_found(); const char* get_fex_app_type(); extern const char* fex_status; extern std::string fex_version; extern std::vector fex_load_data; struct fex_event_counts { public: void account(uint64_t total, std::chrono::time_point now) { count = total; last_sample_count += total; const auto diff = now - last_chrono; if (diff >= std::chrono::seconds(1)) { // Calculate the average over the last second. const double NanosecondsInSeconds = 1'000'000'000.0; const auto diff_ns = std::chrono::duration_cast(diff).count(); const double Percentage = (double)diff_ns / NanosecondsInSeconds; average_sec = double(last_sample_count) * Percentage; last_sample_count = 0; last_chrono = now; } } void account_time(std::chrono::time_point now) { last_chrono = now; } uint64_t Count() const { return count; } double Avg() const { return average_sec; } private: uint64_t count{}; uint64_t last_sample_count{}; double average_sec{}; std::chrono::time_point last_chrono{}; }; extern fex_event_counts sigbus_counts; extern fex_event_counts smc_counts; extern fex_event_counts softfloat_counts; extern std::vector fex_max_thread_loads; void update_fex_stats(); } #endif //MANGOHUD_FEX_H #endif //HAVE_FEX ================================================ FILE: src/file_utils.cpp ================================================ #include "file_utils.h" #include "string_utils.h" #include #include #include #include #include #include #include #include #include #ifndef PROCDIR #define PROCDIR "/proc" #endif std::string read_line(const std::string& filename) { std::string line; std::ifstream file(filename); if (file.fail()){ return line; } std::getline(file, line); return line; } std::string get_basename(const std::string&& path) { auto npos = path.find_last_of("/\\"); if (npos == std::string::npos) return path; if (npos < path.size() - 1) return path.substr(npos + 1); return path; } #ifdef __linux__ std::vector ls(const char* root, const char* prefix, LS_FLAGS flags) { std::vector list; struct dirent* dp; DIR* dirp = opendir(root); if (!dirp) { SPDLOG_ERROR("Error opening directory '{}': {}", root, strerror(errno)); return list; } while ((dp = readdir(dirp))) { if ((prefix && !starts_with(dp->d_name, prefix)) || !strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..")) continue; switch (dp->d_type) { case DT_LNK: { struct stat s; std::string path(root); if (path.back() != '/') path += "/"; path += dp->d_name; if (stat(path.c_str(), &s)) continue; if (((flags & LS_DIRS) && S_ISDIR(s.st_mode)) || ((flags & LS_FILES) && S_ISREG(s.st_mode))) { list.push_back(dp->d_name); } break; } case DT_DIR: if (flags & LS_DIRS) list.push_back(dp->d_name); break; case DT_REG: if (flags & LS_FILES) list.push_back(dp->d_name); break; } } closedir(dirp); return list; } bool file_exists(const std::string& path) { struct stat s; return !stat(path.c_str(), &s) && !S_ISDIR(s.st_mode); } bool dir_exists(const std::string& path) { struct stat s; return !stat(path.c_str(), &s) && S_ISDIR(s.st_mode); } std::string read_symlink(const char * link) { char result[PATH_MAX] {}; ssize_t count = readlink(link, result, PATH_MAX); return std::string(result, (count > 0) ? count : 0); } std::string read_symlink(const std::string&& link) { return read_symlink(link.c_str()); } std::string get_exe_path() { return read_symlink(PROCDIR "/self/exe"); } std::string get_wine_exe_name(bool keep_ext) { const std::string exe_path = get_exe_path(); if (!ends_with(exe_path, "wine-preloader") && !ends_with(exe_path, "wine64-preloader")) { return std::string(); } std::string line = read_line(PROCDIR "/self/comm"); // max 16 characters though if (ends_with(line, ".exe", true)) { auto dot = keep_ext ? std::string::npos : line.find_last_of('.'); return line.substr(0, dot); } std::ifstream cmdline(PROCDIR "/self/cmdline"); // Iterate over arguments (separated by NUL byte). while (std::getline(cmdline, line, '\0')) { auto n = std::string::npos; if (!line.empty() && ((n = line.find_last_of("/\\")) != std::string::npos) && n < line.size() - 1) // have at least one character { auto dot = keep_ext ? std::string::npos : line.find_last_of('.'); if (dot < n) dot = line.size(); return line.substr(n + 1, dot - n - 1); } else if (ends_with(line, ".exe", true)) { auto dot = keep_ext ? std::string::npos : line.find_last_of('.'); return line.substr(0, dot); } } return std::string(); } std::string get_home_dir() { std::string path; const char* p = getenv("HOME"); if (p) path = p; return path; } std::string get_data_dir() { const char* p = getenv("XDG_DATA_HOME"); if (p) return p; std::string path = get_home_dir(); if (!path.empty()) path += "/.local/share"; return path; } std::string get_config_dir() { const char* p = getenv("XDG_CONFIG_HOME"); if (p) return p; std::string path = get_home_dir(); if (!path.empty()) path += "/.config"; return path; } bool lib_loaded(const std::string& lib, pid_t pid) { std::string who = pid != -1 ? std::to_string(pid) : "self"; auto paths = { fs::path("/proc") / who / "map_files", fs::path("/proc") / who / "fd" }; for (auto& path : paths) { if (dir_exists(path.string())) { for (auto& p : fs::directory_iterator(path)) { auto file = p.path().string(); auto sym = read_symlink(file.c_str()); if (to_lower(sym).find(lib) != std::string::npos) { return true; } } } else { SPDLOG_DEBUG("tried to access path that doesn't exist {}", path.string()); } } return false; } std::string remove_parentheses(const std::string& text) { // Remove parentheses and text between them std::regex pattern("\\([^)]*\\)"); return std::regex_replace(text, pattern, ""); } std::string to_lower(const std::string& str) { std::string lowered = str; std::transform(lowered.begin(), lowered.end(), lowered.begin(), [](unsigned char c) { return std::tolower(c); }); return lowered; } #endif // __linux__ ================================================ FILE: src/file_utils.h ================================================ #pragma once #ifndef MANGOHUD_FILE_UTILS_H #define MANGOHUD_FILE_UTILS_H #include #include #include #include #include namespace fs = ghc::filesystem; enum LS_FLAGS { LS_DIRS = 0x01, LS_FILES = 0x02, }; std::string read_line(const std::string& filename); std::vector ls(const char* root, const char* prefix = nullptr, LS_FLAGS flags = LS_DIRS); bool file_exists(const std::string& path); bool dir_exists(const std::string& path); std::string read_symlink(const char * link); std::string read_symlink(const std::string&& link); std::string get_basename(const std::string&& path); //prefix so it doesn't conflict libgen std::string get_exe_path(); std::string get_wine_exe_name(bool keep_ext = false); std::string get_home_dir(); std::string get_data_dir(); std::string get_config_dir(); bool lib_loaded(const std::string& lib, pid_t pid); std::string remove_parentheses(const std::string&); std::string to_lower(const std::string& str); #endif //MANGOHUD_FILE_UTILS_H ================================================ FILE: src/file_utils_win32.cpp ================================================ #include "file_utils.h" #include "string_utils.h" #include #include std::vector ls(const char* root, const char* prefix, LS_FLAGS flags) { std::vector list; return list; } bool file_exists(const std::string& path) { return false; } bool dir_exists(const std::string& path) { return false; } std::string get_exe_path() { return std::string(); } std::string get_wine_exe_name(bool keep_ext) { return std::string(); } std::string get_home_dir() { std::string path; return path; } std::string get_data_dir() { std::string path; return path; } std::string get_config_dir() { std::string path; return path; } ================================================ FILE: src/font.cpp ================================================ #include #include "overlay.h" #include "file_utils.h" #include "font_default.h" #include "IconsForkAwesome.h" #include "forkawesome.h" void create_fonts(ImFontAtlas* font_atlas, const overlay_params& params, ImFont*& small_font, ImFont*& text_font, ImFont*& secondary_font) { auto& io = ImGui::GetIO(); if (!font_atlas) font_atlas = io.Fonts; font_atlas->Clear(); ImGui::GetIO().FontGlobalScale = params.font_scale; // set here too so ImGui::CalcTextSize is correct float font_size = params.font_size; if (font_size < FLT_EPSILON) font_size = 24; float font_size_text = params.font_size_text; if (font_size_text < FLT_EPSILON) font_size_text = font_size; float font_size_secondary = params.font_size_secondary; if (font_size_secondary > font_size || font_size_secondary < FLT_EPSILON) font_size_secondary = font_size; static const ImWchar default_range[] = { 0x0020, 0x00FF, // Basic Latin + Latin Supplement 0x2018, 0x201F, // Bunch of quotation marks //0x0100, 0x017F, // Latin Extended-A //0x2103, 0x2103, // Degree Celsius //0x2109, 0x2109, // Degree Fahrenheit 0, }; // Load Icon file and merge to exisitng font ImFontConfig config; config.MergeMode = true; // ImGui changed OversampleH default to 2, but it appears to sometimes cause // crashing issues in 32bit applications. config.OversampleH = 1; config.OversampleV = 1; config.PixelSnapH = true; static const ImWchar icon_ranges[] = { ICON_MIN_FK, ICON_MAX_FK, 0 }; ImVector glyph_ranges; ImFontGlyphRangesBuilder builder; builder.AddRanges(font_atlas->GetGlyphRangesDefault()); if (params.font_glyph_ranges & FG_KOREAN) builder.AddRanges(font_atlas->GetGlyphRangesKorean()); if (params.font_glyph_ranges & FG_CHINESE_FULL) builder.AddRanges(font_atlas->GetGlyphRangesChineseFull()); if (params.font_glyph_ranges & FG_CHINESE_SIMPLIFIED) builder.AddRanges(font_atlas->GetGlyphRangesChineseSimplifiedCommon()); if (params.font_glyph_ranges & FG_JAPANESE) builder.AddRanges(font_atlas->GetGlyphRangesJapanese()); // Not exactly Shift JIS compatible? if (params.font_glyph_ranges & FG_CYRILLIC) builder.AddRanges(font_atlas->GetGlyphRangesCyrillic()); if (params.font_glyph_ranges & FG_THAI) builder.AddRanges(font_atlas->GetGlyphRangesThai()); if (params.font_glyph_ranges & FG_VIETNAMESE) builder.AddRanges(font_atlas->GetGlyphRangesVietnamese()); if (params.font_glyph_ranges & FG_LATIN_EXT_A) { constexpr ImWchar latin_ext_a[] { 0x0100, 0x017F, 0 }; builder.AddRanges(latin_ext_a); } if (params.font_glyph_ranges & FG_LATIN_EXT_B) { constexpr ImWchar latin_ext_b[] { 0x0180, 0x024F, 0 }; builder.AddRanges(latin_ext_b); } builder.BuildRanges(&glyph_ranges); bool same_font = (params.font_file == params.font_file_text || params.font_file_text.empty()); bool text_same_size = (font_size == font_size_text); bool secondary_same_size = (font_size == font_size_secondary); // ImGui takes ownership of the data, no need to free it if (!params.font_file.empty() && file_exists(params.font_file)) { font_atlas->AddFontFromFileTTF(params.font_file.c_str(), font_size, nullptr, same_font && text_same_size ? glyph_ranges.Data : default_range); font_atlas->AddFontFromMemoryCompressedBase85TTF(forkawesome_compressed_data_base85, font_size, &config, icon_ranges); if (params.no_small_font) small_font = font_atlas->Fonts[0]; else { small_font = font_atlas->AddFontFromFileTTF(params.font_file.c_str(), font_size * 0.55f, nullptr, default_range); font_atlas->AddFontFromMemoryCompressedBase85TTF(forkawesome_compressed_data_base85, font_size * 0.55f, &config, icon_ranges); } if (secondary_same_size) { secondary_font = font_atlas->Fonts[0]; } else { secondary_font = font_atlas->AddFontFromFileTTF(params.font_file.c_str(), font_size_secondary, nullptr, default_range); font_atlas->AddFontFromMemoryCompressedBase85TTF(forkawesome_compressed_data_base85, font_size_secondary, &config, icon_ranges); } } else { const char* ttf_compressed_base85 = GetDefaultCompressedFontDataTTFBase85(); font_atlas->AddFontFromMemoryCompressedBase85TTF(ttf_compressed_base85, font_size, nullptr, default_range); font_atlas->AddFontFromMemoryCompressedBase85TTF(forkawesome_compressed_data_base85, font_size, &config, icon_ranges); if (params.no_small_font) small_font = font_atlas->Fonts[0]; else { small_font = font_atlas->AddFontFromMemoryCompressedBase85TTF(ttf_compressed_base85, font_size * 0.55f, nullptr, default_range); font_atlas->AddFontFromMemoryCompressedBase85TTF(forkawesome_compressed_data_base85, font_size * 0.55f, &config, icon_ranges); } if (secondary_same_size) { secondary_font = font_atlas->Fonts[0]; } else { secondary_font = font_atlas->AddFontFromMemoryCompressedBase85TTF(ttf_compressed_base85, font_size_secondary, nullptr, default_range); font_atlas->AddFontFromMemoryCompressedBase85TTF(forkawesome_compressed_data_base85, font_size_secondary, &config, icon_ranges); } } auto font_file_text = params.font_file_text; if (font_file_text.empty()) font_file_text = params.font_file; if ((!same_font || !text_same_size) && file_exists(font_file_text)) text_font = font_atlas->AddFontFromFileTTF(font_file_text.c_str(), font_size_text, nullptr, glyph_ranges.Data); else text_font = font_atlas->Fonts[0]; font_atlas->Build(); } ================================================ FILE: src/font_default.h ================================================ #pragma once #ifndef MANGOHUD_FONT_DEFAULT_H #define MANGOHUD_FONT_DEFAULT_H #ifdef __cplusplus extern "C" { #endif const char* GetDefaultCompressedFontDataTTFBase85(void); #ifdef __cplusplus } #endif #endif // MANGOHUD_FONT_DEFAULT_H ================================================ FILE: src/font_unispace.c ================================================ #include "font_default.h" static const char ttf_compressed_data_base85[178490+1] = "7])########0tO6'/###W),##1xL$#Q6>##U[n42f)']>#tG:;$Z2XGHQ=WO#/HAi^K@tc3DJk7DQO2$2iO]._b(35&*a(*HMY`=-J3S>-x^Nj0#-0%J" "f9-eB0[qr$7[.nT7-deW.;h^`IIo]7C2N(<-JRUV$g3JuB=]G%`-a8]XL6YY#EK[^I5a00FPj=m.,*m<-dI0h4l%S+H" "&Qf$p-gHo[AYqr$EeFVCC&4$.T&BDbLNr'#dHuY#EC(7#.M(Z#u7`'8Qb3G`fNE3k?;%)3W?q?BWOap%0=Im/s[(##sD4;-DcrQM`>B`?847;-*lBvd(+JM'W?]c`7nN&#VHv0,xNa-$" "Wo8gL.Ag;-'YP8.B)B>#(ok&#B=vu#+(:B##Su>#aH`t-U^UANSn_aNu'^fLD4pfLHqDw$2+RS%6C35&:[jl&>tJM'B6,/(FNcf(JgCG)N)%)*RA[`*VY5C=ku5GUKV6Kn,87O0do7SHDP8Wa%29[#]i9`;=J:dSt+;hlTc;l.6D>&:fu>*RFV?" ".k'8@2-_o@6E?PAwKbKc'O%1#.M<1#<4B2#TwP3#d9v3#iQD4#kWM4#spr4#uv%5#%3A5#'9J5#-Kf5#2Qo5#7j=6#<,c6#A2l6#1gY+#L$S-#EE=I#A;L/#0hb.#>L`,#VKFI#cF31#" "sq@-#Q<+I#D0f-#,Z.H#6b7H#rvI-#4ABsLs=X4#YsH0#HdkI#aQHC#x[FU%5bt4J/9v1B%;NfLikdV$u$DJ:iu#)-9p92L7?>#BJqJ#nhlF#O.e0#" "-)[0#5SE1#=x&2#=lj1#w3/vLUrZYQWc1MTOw&Sn@4tu5vj^]4A+=>5-Z;;6@l@A4KsBSIKXwv?igWV$TA@D*ZKbHW53F8%db:8.*mCD3uCRm8tT%H#7U5j#`Ano#Frc/$:c$4$P]eh," "lv@=-FZF>-V5:?-#YEA-L.aL-54Lv-#nIt->ZXu-[lHw-fV+'.#Zo4v/]b?/Z9F&#AK(xLt>E?#jjBB#0v)D#2YkR-.n7^.[;eo#`b0W0*U&U-96f=-YDOJMe$c(P:wjBO1,J6M3LV(v" "F*Q7vP]q3vKJU3vC213v;pb2v6dO2vt9;0vTfteu(diOu8)eKu+YdnlsZVClLB2ClF*dBl)os@lYLk5lwX;ck6)PekwM]dk^H)ckWjX]k5moE8ml$hcR?%@#q=8a%uvV]+QpNJ:rHSP&" ".su(3kCkZ2,CS<$$Mwm0Md*P(3IL,3+b<:.IZD.3m]WI)x3vr-=n/K1cs%f3sJ))3x?7f3JOQh,aO5rJRm9DEK'&JCt)/E+_I.[-^deg)MQ[^5NaW&5IW5o/q,8(svA#)$*eJ+uUo7T%" "(2.o/bD+H=e:`(,-%9%>1nVJ>#1u9'#-Mc##b+<'#A@7,=*5G>##kn>#'k&&=4UA2'r,b;$.%[8%947W$br9&$vpFk0jn0N(NkY)4w?t&_YftAu$T5Fug$itL" "7S6##2tvC#=M_PM@m<3;NDWC?vfP>#vZs%=2`Cv#3%M$#/s1K*Ia8U)sq[b%BXj%=Ct:B#WOs]7WCpF-d0ju0[aNL#hK)s?$gxo.EwtNFL/5##n5YY#VMwI/tbnZ7PSofL)<#gLY@R>#" ";);Z#97VZ#9%78%Hl7[##(ZQ8>IET%8ckZg%eT>$D*&&,47?c*$DXI)ws*1#3Qr0(5qZ0)k02N()vsI3N#G:.E7g;.B]fZpue-lL;c1p.Ae]ZKKjp0#%^2*@&2ei0^iVR#BA+*r[eT:g" "r;4a=W#YEM9H?##'vgK-=G/e%G-^f1Pps+;nMDq%ABGn&+DY>#98c?#:=[S%;>n8@;1[s$47e8%;/.O4W10*#?XwW$r%&(#hSR12EKRl1Dplq/Z-;97p/3?k2(Dq1DN80r_,]YVO'" ".q1DN@p=j1p:gF4$UD.3FH7l1um7W?dl@d)4(XD#XbN)#'et293-K]=+&###R5OK3Zn?g)@JG##r7k.3VjIp0mCE=.Go'J)1DS5'I$XX$85>##VA`0(vuK8." "L,B.*[*'u$BKc8/s<9-mU#+jLYIbn-rUA['YcQiTQ:+;/_*+HpI'ie/KD56Beu`50x,H3'v:#_+ta]W.NR6w/^cH<.s:,_+[vC0($/gbinq2u7HN0f3'-(<-E4H;JIH=>-N?h:HTm[a7" "HODsJb..A6PI]],P_i],5dQY5S8q'#](N%$m?O&#piLY7u.dY#h_&*#tUBp7g,&F.]'m+#'.ZQ81S:v#)B=;$'u,m8`ovs.rQDq/?28L(2#]d)aW+T8)CGH38%1N(#w8s7]bj5Aj>%&4" "(V'v5_b>g)/vQJ(,2S[():np.)Q93C=*c,.rV2l0cBIg)1D&#mPA)e=oAS[,wDt$6t.9+CmsJ23YDc%,'Asm9(#+PAl#?8.$),##LuvC#KLV,#Il$V8Ob7p&k3qA#EObd8RB0j(X[=_/" "oRi*%BXj%=(ok&#aYbv%E-i#$:Xew#;v'W-lsKaP'mN71h)i?#gG(7#M?8W7ejXZ-;tlanOC0*#%w]]=8$YJ(VjUq)-a>.Z$wiic)pK/N(Yt-thWdEj1Cm;hLnjuH3)CJV(t,?n&" "2Ne-3L]=Z8[+U&?x#uBCA*I0)hc6m0sDV-,+C,%$:E9(6qBZFI*b>Z.)>>##@`f&#P0WmLa'U]=JB,<-%uSE#e4Al'F.)$#`KKY$M1x*3jA[L(s3si0jfE.3(P(H-=:fT%mtu$?G)?T8" "<(jL3bXBp&$lbM(w-6L.,Y*'utQVh3s#EB+wnrV$A-R,*W^(&MN.XG#Q2.w#]4i$#=0J?##SrB#P+5gLi]_:%Zk_a4,g;Q/F]+&+Q'vTJp_UN<(u`=0B(v#BIMP%LQcvdECrD:Be*>Z0" "O;Li<*WTG=cIE/(g*SP&lZ0[[=lj]7Ff1Z#+GcY#-WUV?EL?)=SaFn'q+>V7?,>>#T2QeOmO$##%3xu#pFc^?o^xB/]RNP&0A58.'eZ0)r&;d2)wZ)47'8MZ#+-Po$AH'[.%U-HjATf:" "*a>SIuW5^,Zp0pplt)3&E7M8.D])>1MDhLgA3q6*?bs&5?#YM0V[(16/%eX-.wK^uCn[xC@`x&#]#'2#0-ex-(d=78Tbb&#TH9HO6D6a$.H*7N[Ulp/bM@;6]*X:2ltVmL2cJR0QW'B#" "a+7Y>'8Wc8XJF&#r5N506:WA5&t^I*j6IP/h`Rp0h=2v#i_&*#6@o#.+]hE5(wS]=2L82'jK.##D_m(+Qg?D*Na>j'_=o#.[P^88C@-$$4.,Q':**785W?C#FS180^aRB5(;#B5Q6rhL" "xa)l($x/C+L&@hEnMQR&W2f>64$BrQT^:#.TRqR1jko*=qPH.UZqZX-*K*A+Fd8e*`K&kkJ]/kX]0+m/R@-5/4Svu#+E7`$8_8m&;[(]$e5Kn&MBbA#u$Dnspq.[#9OnA,/;b9D1I@x6>J))3>U^:/0pvC#CV180" "[ZIB5uqxD#IAOb)=N$TS_Y_Z-T]G<.h5&12H0iVI:_uE2miZ597N_QCX5OJ-@2`]0oiLY7eY(v#BLMmL6^vY#Nt[(S%=BK1Vax],.J=.)m_HP/jg&(So^0#$#5ZH.iF3]-ndAW-UK5[T" "5W(<-eW;^5cD^Q(%)XE*QDZ]uY_,@-,J>C+p;4+.9ZY]u/'xf$ex4V&.u.),[s_>.&Ysc+DBALCp90v7a4n0#uF)20`;`Y50,c9&_?]f1OE:q%VYA*[X8,##*>cY#/&O&%8_8m&uVmX$" "W:jl&8`($#lgn0#wYIvRvDg;.]L3]-:[TD3q1-v=,4iLgwV_oamaG7eku;5FngG7eWYJtCu(4GMguQlLIt[.M>M.U./VC;$@CXr.+Ex>#gZh?BNPuY#>xr62YiW]+_MhZ-%6lk0p<6g)" "d1)W-U.^TraTL,3x?7f3ICuM(8J)]b5BGV/a)=$6*6^M#>Y'/)pJY]u&]KNCXqtD>0U;6;VQ-/2Z*Cp9&v:*nfww5/jvK'#C7;kL+)j;$]D1pL$@h]=0S:v#PLl>$biuw0fJCZ-ZlW]+" "P>e;%R3'Q/%NCD34tFA#0(rP8Oq*H;=J&v5u'7]6/xrB#OY*4.^7Ws8vcEm1x42W/X)9<7rB,N'&)Se,vf%4$uKj<7`rNhN>po0)>$=F5HW(2;_:9xX:8e7&N.)&9[P0K-Nv%v2#%3]>#p#.wGpLL`;v#H_+T%E]^l8aaJA,2_cL2" "?s8b4]`MP02vm3'[ra]+DwlH3*W8f3mOo$$sa*wp7DXI)Xc=Z,qm<:.%Hk58]Q3A'm;a;=%GGQ'Ngg&=vO?M<_GD4'OJ2.R_YL?-HGJ60CZ;#-Mc##bCA?$%&###+KCV?-1+v-2'qL;$%:B#" "m2Ahu;')*%hATf:2lQR<6mn51#NE^#Rm9LNKYvY#,dQq('29$$;X)>PJA+bOZ_^YQeV2T%$wp4Jr:Ionou^V$61eX-Y##Yu$$Zju4`fmCw*)UC[tu=PuYm>#b)Bu%cp>V/BImruh'JU#a[g[MYwWtL]Mo(#TMZ$$k3=&#tIIZ7^n>B#2i-s$nZ,)/*DY>#L2#qrUQ+?#stYQ88+Rs$/CXkDISY>-hvS;." "T/1Z-5r9f)S90q%cI#v,5V.n&r(@j:c$**GMGG:.e#>g-Z7(f)7aS#60&Xk'`On@-^4&q/)=mV#D@;n(,HHe66;ug3Qp]3<jTv70oC?#6xH8%" "5^(v#W:=,MP^Q##6jCv>0WAs%Q-[S#eQ(@Z#1Z]Q(+a;Q/$9uk0@Ir8.Jm4:.*bM8.$%`s*22F8YS2rD8" "49(2$x=KU#=k=6#9cq;-oUnf4Sww%#oiLY7ho_V$i_&*#.fh;$0W`,#u.Zs-bT`l8_%e=.)IOI@#Tk=W%`'([.#]o-)G&9f31EQJ(fj`#5hZvA5QmpV.vo2o&j39>." "+kRNP=YVAP3vxZ$G*L$.@lx(>Rt1e3Q';F=Y_*m/(h,H6Jii$:t%'tq5]&*#t2wiLiDjJ'wBb?nL#>-;f%$[-kmqc)i&l]#>M.Xfp?\?O(vcMD3CugXul>67&l@=M(6gF+`h/=-*h$kx-" "s]1R)23T[uoKHw-M1L#6$lwE5vqJfL@:>G2Ssxc3Q6s5'4qr+;rmb?K;l1/:Z*xa+gj>n&;%`?#O&+g&ECuM(cS>(o)tF.E/#[P;;$T.2qKeQo.CpDwA#5^qE@Rfd'&#Sdl/wl#RE`(aq'+`Wj$[%lgLpj*V0" "2Xof1sq1##Dx=wL2U%=aRp0(>YY#-^UV?vBsM-,Ls'%?Cw(uv9.Vn@X-ad`#55QZIqlGQR&l:x1(M(mc)x>wA5KZ5o/gq-F'" "X`x.C[mmJauQwq$ET#[T#G-5/%GrKGW85##5,:W$3Csl&nGcY#R&r]$YweW-@,5L#Q?V-M?AIxi`V]'Ms0jFV[0ibik,42Uh,wA#14k>Rco^W79,ko76:q#$(>cY#a>tZ%$EeA#I*+W-" "=$+qi-p9BY2;@wY`[KNC344tB@Qi-#8%mlLAdbjLaLj$#+D#jL0$1&=1>HX$H,,##(1G0.LU`mLd^j$#:#?s.gfqB#rv9H%fu.&4`N.8#;/(j8-7&iftAu;Y^C64P$u-OL+Sn" "sM_lLOWOjLh=*mL#u<$#m-:t%,55##g?%##'/,##AJl;$3Csl&hW]m(onkq&T]eh(_&`,)P;*F3*&E,)bE1K(&S>f&usSgp;AGKUp#2oeKRN+V,x`oI.E)uLjFT_-9DJwBN0X'6]8@Y%" "9pwO;Z`V'6#YJL(6otM(T+SHuuB&j-2]GF72KwE7KM*RW)U#?.6V(v##x#xL@Q$##xgwY#4L82'd?:'f#vPj(0[ChLU@P]##f=T58" "QDGF@u%18.cIG,M-C158Z.x+M4'22NRlv##,d7#/+Q4b+g69e?\?fH#d#L05l?+d%.S[_pL`0p@uOd#`-EZdX/djJ%#x2O`+dY1$-;)jV,.Z-a.Lhca3;LHw-BV7m0pPi1+BYFI)39T%#X2rt%ma_c)dGr80>IjT.)&###>Ws'%h9_c)d&d3'C%v##F[Et$,SdW-,<*Bm$JrB#ppmA5OG=>." "gY40QFx7/$m3&w@(8]>8mcj5$OQj(RAtif5:mcj#3t9'#rVH(#/DY)')b,E,'8G>#(Yq(2V93N7a+wKe--HQ8@S[Vr]7f$x+2N=lM(FGWa:#.jCrO08X[X-,n/>GIfm'&>-f;-#A)ofLo^)Z#';u)N9X-##" "2i0f)iGVk'*&F-=.C(f)co=Z,hh:8.dxrB#'YeD*6qB#UD.&4vcMD3-pN@tj/hq%p%M@0cFUF*TJd]uKo-h(iTTQ&93D#?#ZX-*i09>.qJPq(cU'c3k8oc=)PFv8`+KfLVk-##_5YY##t9'#" "5'jV7C/,##wfY5&2#Hp.B<1K(exU@e0Bx9.94=`#@HOd[+&xAu6T$`C$),##.>Hs-?hZ.M>uDv#3Csl&gWDa-TZqvRl5p%#iw0(4sbV/)G@xr%Jk3B6[Qr*1fCog(`C;8(E8q5Srw:Z." ",Tlr/bdtAu;F-[-BV7m03@pEu;SB(6Hmif[g?R##5>'^%2V:v#vWR>#$wSA=2c_;$Pb`mL" "&?W$#t#41#:H(l00=N/)E/W;.uY4USC&l:At_W$QPr+]$#E:oL8n4L##&Mc#%?KU#iw4E9&J@&,*4Fm/OJuX7hx1Z#+)6X$R2,##<##v#+JuY#`-N3(gk/2'i]@L(*eQeM%FD,)ET$6/" "%+,;dP3TDRV$EOGW.F3c]o9^u$9F]uQweH#$paT#Moj1#iEqhL-C^nLxuv##b[FW%/d=p7;)Ns%gp-[B7[Z*N:Ix9.jbt3Hhp^@k'1$b[R//'HWbQLMkV?X7R>cY#" ".DG>#Y9^p9rWxB/^VumL[:_l%nlic)&0fX-ZxF)4blO1^mE`Xu$Q-`WJ,RFuX?Wa#b_A>#iEFM'faAG`+BGY>S)8)=[Q4<-YUjd>fm3WSSS0i)-BAfhx^Q._0#eetrb98[oq'60[W'B#" "#cprEwf/J=[T.e-'aom(IQTV&#m,p7.PU`mLQ6iH-5De.%1uQ._)HAG`q'uC$3F8(3Br;]bYf,m/?Q$)*(5v>#B,rE@dNr(E&&###bNr0(efqB#BVw;%R/35A$j=tdU3qB#o;`W#" "Ho##om+T+nr^s&(5G>#f]2a+<>I3-31eX-k2]HuvV5UMsS3'#.U#N#^JhhL`5cP]P@ml/4I&r.L/mju.J=]GW/%kf%&4TMrB#FS+Q'g)ug$%B_v1FXsZup%,V/T-)*4lbMY-^U.p/(*6K`;W>L1D@.M9@VOq0Chf%-jolMCG@KE*F9__e" "k+$51Bu$kcZ)k" ";5Rr%M?o;-mBml$)^2Msqvwo;*'+B,dZU>?CNk;-oU/eqUA1[f+.)dRA_#,lda*OfG&^+UD>=/JSuB4aY^,n/)O';VP##d>=k2'7(f)jAqB#m&l]#O+.t-?=?:At+7m0LO8e%B+eJ74dt>ns9ZG*`E?E1Zf+.)j9Ut%V_rO'RPaE*vVWb*ex@JLFY%e>oj&I*KBUt%" "=kI5%D^o],h'b5&.Z>&#:,Kc$r&pc;^9LdkOF-##w####9NF7%Vo:Z#`IU?^)>Ng1_;[L(%O[X-:?uk0Xe?#@eBOQ'-T/i)0q3L#Tmx%)e@p,2Jnk'+SxT1P*'FJLEg8O(%15o/6ZcUm" "Q.g-#R5-$vj%<`#krn%#h>cX7]o-W$j#]GMJkWb$4L@>#iDcN(hE%##PWx],gq/E+@P3<%3LCs?9,*Z6iFYg3gV`G)b'mo79->)4m?*?5Ra0`/AePvcv#&k(vPe51ZEg8SDOsd*X$IKu" "?x2l2c3Cd)XTW-*iHh+kKSuh)&A851O:Od)`]D?[S/7+#GKJW7P]C;$#70*#k1BP8;eB#$0&wJ16$(,)mgWq.sV`,)E`/GP-9x9.C=S_#a#$c%<+[1evv%k(?[jE*oh[0$)Jfh1B=.M9" "utnP0(G`Um4M]*7*N9XoIm6+#3rC$#[*SlLUmt%=8&QpLrF/W$.Q4?#,CvQ8*2;GYa9a;$4[S2'KKgQ&I(KmA8w%t%uiic)AtlX?[W^`P28Ylu:,r2$6h?aevP6tBC_l-#C9]uG3cP>#" "]/uN(pSQ]4F:<;$t.:kF(PXGM'21&=0S:v#P7e^&rqr$#]%xh(`'&%#%kj;-Obj?'[gx9.%IgBJ?aZ.quY*Q1n(?p/v6?V#B>GJLLr7M;)r2[&:;D^#^0A,KvYtn-J>wTM4)EwK0O=G2" "A(n>#kKj;-u2Xr$OTi6Nw4OcMjGbV$^_jl&QvCT%I;*F3<.[>#(D0N(u%BI&2_:Y#kT;j%fM5bu2u`Cj+?>2'HC]*@dH&d3]qH/2WdO5;d[4t?>gf6K3j-sZvDpEuWa7e#7=>R<;r)R<" "_$CJL+E/SUMOmY#F$Bp.('Ov#c3sJ4'%5.)f>Mk'JR[s$N&ic)bP#68xw?w^oLJZ1%$xENaunL(#U9*PSJgj)r@0#,C$2XC1c,gLbKj$#W2J;@X04m'N3=W-jVfqDiKPJ(5gX&OEhAVQ" "tprj(rB]'.Zkr^9ocXvI$6v%.s&niL.^WmLfjJ%#sNUp&J7.l)D+G1;a+C>%f2s$P76" "UWB49oe?_usMT+4S=HJ3<7[Y#VdBM''B'_S4W8>,h`Rp0+GG##'9,##v90*#(wS]=2L82'%m#N(p3F$1(s%1(TBK6&B3pi'a+C)NwUF:.WTD.34RlQWP?ti0;.W#1Rm>#d9%##N>[9Mm#[`*bc#wWj%=)Zp8.)3,#>IFPa3" "aAeL(*J]L('?uk0,T/i)44`[,an7T%K]R_#m_Y)4HeZfC(ttD*j,(43.5.qR6[OaXL&%i-mF#jB#G>K3No)hXAw)#0P5YY#44e0#g-xb%7-&:)&Aip.g_?X-.);LN>l*F3>,x#VUcm;6]8T]lis8V7$M$M`6,A#`d,tL=H-##/5YY#UFSd;,K4m'@Gpd3BIr8.<8vY$aP]#%#WleX,)(bX056X0" "-nB^up%%Su_LhaMGLihL*IgnLc<3$#`bk8&3YC;$MKoRL9]fF-S[`*%eE3$#ei[h(#_Z0)RnF%$2cE<%ed*5]<;)&g7H+BJZcCp#[3Jqu,NGTkI'^E#`p5X$ewAM'YorE@%Y)20,eL(-'VntD#Qt+T%;2)i0@bL/)<6<-*LqY>TE+@xxe%U;_c;uNBlos2>G2CC/s$)G:;$.sH8@*S:v#up@>#*NI`$+M(v#0h;A+uf.1(" "GOes$GPcb]o@;SO&#P,cs1,a_V?$,>>#" "%?G>#Kqq(EBW]I*&?gw#xwMhh>5+?r$D0o[lcFsTFQLsL)dk8$aL7%#ju_Y7c;,##9PP>#,a-8@btxE@fV1v#;2@8%$10*#HF:." "o]d8/)$fF4FPo=%rM[L(oYRD*uc>`I0A4K1qF%E54N&S'Y$tP&u'*m/-k'G;*b;w8J`9^>[@A7,79Y?*Nlc>#/F)##N).*-m5^%#v6uw$+Ml>##QYs-aV#pZqv%]UtGM;mlA%.Yu>#3iU;$>>`Z#stYQ8cq&Q/9?$)*" "cCXI)bI4I$+&ta*INLD3D>07EK5h'[j-4Abx=iee7-TV-Qdq0#AH0m/$b;DEO*pp9:V@oLR0fS%x7g_#DLw+2U/>G`-l68%[mYv.#90W-n(Ok+$<0W-fjjSpl/QJ(BbLhLtc0>GOiR-$" "5/MG#6E@[uRAlwL-VZY#K`KrQK0I9i,r[(#Eu3[7IFA8%<1D;$nb&*#5.@8%72e8@-Y:;$6/I8@AoF^#W#coL5BHZ$/p_V$#Y^l8:r$##k3k:8(dr%4K77<.@e;D+>^MK(0%eX-goj>>" "cGv;%g-.1C2n3-Xd2Rl1q:gF4OIugL;4_F*ttBk$Sf8crJo+C+q-8m,731:%(bw9.KuN/2MwkQ#++Z(+-O(d3H^pr.fdt9%4PFO'8OYKLO50&$QFB3r/)]L3]-j,(QptptSN%f@qL4CVm20bVs#QSa)#^d0'#3ODC;*+BqD.VM'#+]hV$5JT#&" "2(@s$2)%s$%70*#$$g]=2S:v#%qWV$--m+#EqW9%)s.[[pJL@-);E://r68%r3hxRT%g+Mw+:kLoPFjL=bk;.6/I8@.ElXC3_tV7,E]jLl;$##]b#AO/Lx8%3q?OOZ4Dj9p7t]7ONwg)" "kE9D38*V80[:LJ)_;XjL[>JX-1mrg(27E:.];/Lt6$BK1gc``3;=bx-]]WI)oikO2_o598O7]>.WP@&4CIR>#Pgvu-AJ.2N;<;S0bNs13(3.(>Iu@T%,K*+30Rr/FV5aB43:/^?F0YX$" "-n;f#iJ3x-wZ8:/Vu2=4^5.G<,S.,QI&[+<,P%,QF:Gv.,_vWL^R[m'kej5MVD(cAJ5YY#`nq%FV7>@-x%c&o$$m$o/*" "Wu,##F?4Y-T4Gl;kmjR8)Ed&4Fi^,-we;Zum;Sa+,B^r.O.Yb*5loB,W:1+$X7#d3/t=Z*f)KA,OGW4'FGC=oPg]a+(5n0#_W_r?(q/p%bQsr$8=RS%D?%<$x?]spkG**4(^*E*A@=`#" "jC+Jd*MFfd%nu2E,wXM60t/gL6M-##Vr>r#MHP)M_7:W7E,>>#=,^>#)>cY#wDcY#xdY+#m$G59H6%Z$$KW&48_Y)46a?/(0s7P#Tr;wX4*P:vw-AC@pf(B#@/D9.;hfi';S=OWes0B#" "*Gc>#W`s]+R;G##khw[#ESa)#JXI%#8Ja)##pr>#m4058&RP)3V;G>#/MP>#HMG?#,fh;$[D1pL?@R>#/N`,#:C39%:vO?#5T>^=@IET%Aomd+PRkU2U`Lk+T4es$tO#s/63tD<:_Wp%" "E7dZ%1Vs]7cA^*+tmP]4Fg*Q1j-3d*TBsH*lJVk'R3'q%<7%@#%*>k0,R(f)Y@'u?l@)h)LYaF3?-;o0G+IV+n00&4CIR>#SMfQ0]sZ*=vnHo1du]51C&Mv-VEHn0F,Mv-dPkE4qeK60" "4i_+4rkgQ0:9dxbmG,f*Yr7q9/q_]4<412Dc*[o1d`EW/dBEP2cJ[v.-Q6RCG'Eq:GZ^3MxFbq0$),##/%lm#Mfe[>xen&,nr^s&8#uX^l8+Z`Om@$##0Suu#ZJ4g24/F4'?L82'`2Mk'?xU?#ngn0#,Yuv,sg'P3%I4GVUjfM0$#nx4I@n>#n4058" ")dEp@?g/&$($m+#=ORw#0-8>,)GXI)ZNgQ&K6OA#nlp)5$rXI)55%&4xPt]Oj6_iBnhoQ0VSmlPfM@h(68Ve$j_eM0A10Y.;S:@6VwDD+`&K&,n[61M^OJ#M;@v2$fke%#GCMkL*^vY#" "oDT>o`60v$,DSfL^c$G*`d5n&EIIW$G$Lu]ApoA,8gfX-/-6fE)P_s-O/aT/g)1P^mG5<.Ms*.)w=-m/P)G_5LP+=Is&Fd*jU$1M@ZSo#T4A9$<5>##FE.,DZd2[$GhDsuv)VOBlTLfL" "JF-##Z1.[#_qg[1I^fW7M>Y>#'8>##SMe?Tbwo,;a6Hk(gbtM(_&`,).uv9.oajiE=t1I3J=UmEkh;a4IQ,o/R[*m/G'WSRpaKA4hjSM3qu<PwD88.t5P_&UVc##4,>>#" "06S^Hf;?T/mRIM'*pb@kZ5,ugl)-&''Dq8.XQB<1S$Q,g_Lu(#HV3T#[_P/$VYu##Sc)^#%,>>#T?D*tE*)#@=g2'4Csl&,fWP&3^Nx%57'L5]owN'+/###" "'G0b*uX'f)u2%Z>R%:3(i95`HMYi7I20GNk'G9pM'6?T<-wS?i$4i^5U" "eJI#%m@6u69j0J1rU$I0Kfs#RJP_du%LSQ0:#=,W,Ii0(B513MPG#?1:GD^O=gLaNJs$(*,##.P(v#)KkZgx87gL6Hj$#" "@Aei*3>JZR4RXD#`Q_L;;$Xn0bl@d)Lov[-L3rI3sh;.>(Db]+h+h#r[wd42`tjTv7=ohV$PQHh%Rp98%hq2t_tx*GMON-^=F**aEe7`o_#4L+*(ROW8a>),)Nmcj'<<,Q/2;2T/" ".cg/)tk%T.*bM8.M3or'0(m]/P.k$UOQC1U,UvS/gV46(.&=e)e,D0(i_7w#WGiA5Lk(+r2`lM'c'$Z(V$#L6E8;UYWC?7P?>#.c1?#1#US%" "37nS%6p=?#&*T&=2Ep8.)w8&=JONs-K@cKVv_;;$lsGQ:3JZZ?w]###jPr0(Gx/wJrI4**27E:.6KbV$s_-lL_54b+6ax9.>?C6Gkh:rdd7ool,?,2)(lLq^Z[$/LPfLX.w1MD^XjLT7OG%I`g/3^pY3'-'uJE$[L::X@H>#" "1OEW-=AE0?-qrlfljd.%nWbd8HEj0;1BVC?B1*?#6YP###oDU`@Zu>[L:$##Mkw;Hhu^>$oGLs-0IrKM-Ifs$d3G=2U-4K*?YG>#dVI-),6$:9KR8KUHL%f$qu.Q:.T7KN`#1q%SI%f$" "_GF)=$P-h-3,g6E3=%BOI.>#_5YY#cK17#@ZUI5Kd''#^0%J&6mn51Eg0aE]J5j`Zm5x7QaPY<@CRs-*e^v7vnjd=hA$i$9%=gWoM;T&1gvnS7`Jc$e,6W8_]kdM14ab$d,JjD" "'.%##4[fi'cc*s6`5HJ(*;3>5I=e>#.JcY#sIpl8Q1]p&s(Rs$QETW-<*7*lv@Nk'TBK6&FKPJ(h]qB#bed4%NCuM(k;oO(L#G:.MjxM&p.%i-^FL+*QGd]uQq.3UcpTIuwWXY1(^)B#" "Of4;?)Y4duvX7m0iEk8.PkIJ1NlC)4M7W20#2?5/S_$##2QUKE+0,[7vjUV?ED/]$@4I8%6G*T@7:.<$,aC;$1H@<&aw2w5;SG>#(U%t-@Xm(+w+oh(JU<5&QG@L(5&il0I8T[fa]27#" "/l1x/`-*g2f:330Fj3e3i[O@$&Lg;qat96A#%e_#DlU?-ZCM?#Y6'Y$iO$##p+%?I-]R=8>MgvHhAE;$[qas8C?#W./1M9.5S&mAY,l8.($gx=,0oPA5Y7a+3^5C/PMG##'/pj1[15f2" "3@bc2NA,G4Gn&+O%7EjTG5q-%ru.Q:f(=<)X]G*Re4m&F?p$?9%9x-W$b=#=C?#0>C2OI1Mv/P(5SV,G4Cjje3Wo#T&" "VxF(#>hD]FdZ?crULRP&=&Wd&em;9DL*tM**$4Q/eC4D#?S(XJ1+YaIUb7<:;9*<:3ZCtJ011^Jm####0cCvuCfR)$Dxw%#&K6(#D*QX$,GP##IM.$$O5.1(.]Cv#388d/,')B-+S1v#" ";3G>#s@O($4`3/%Dipl8[ak;.:=q(Eo9(S2w4.5Jmqf]?w`,##g2P#-bsGn&F)sx+U&Qj'C$]I*UYf)*>[f5/AUr8._1XiKV?d0))>WD#vu.&4uW/7/&B;T%1f>f)i=+'r." "Ofgh(j39>.eS.P'hGXi(U10PFW%Yj:J;*owt$&S4k'Ed8e*P=LX#Xu[X-hl####)>>#P5YY#`.Tk$vbZY#ox6V8&EiT/rj=#-dFd>#4OD](Q5G>#,sQ#X8&<.(:3^?g1N_=A-/]u>#p]C;$m&$Y8c2Z;%e)Ik0`4H>#N#:;.NQo],$3Ss%E32ao(JHs-uHB;8IUvV%Ms)Z-Fm@#/XG$W.8XlgjLqp(4AeH?,(W#aETQ;h`]W7DEc1?5/" "_*%##pI^l8X5At%-55##,`[3'#^*H=T/[+#64%[#X>gl8II9j(m4OFG*[Q4(kp=G2?%<;$*VL;$1dx>#xt>681]b&#N&Y?GmP$(#c==.)D.`$#8sgZ-#M-kC>p5K)`5qB#bM?p.dxrB#" "EZko)3jqC0/SL+4rqsAPmaG7e#?Ek=T),##I5YY#`R5+#(&iY71LGQWan)?#w:Z-6cbI)0g0H3nrZj'xgFp.Xc=Z,IVf3OkNXLDvR(C&T/E+=;En8@GuEb3" "BgdC#Yv9%%q%81(*;kE*X.YgV)vpf)gI>C+P'rn12,jH,njx6/2toc;F'J`49'up%>DXQ1uLT90dK4C5]OJ:/]:>B8[2dAuTf9P4Xt&%#I+65/?x8^6;0nr-aK+'#9ICP8*`$s$V',+3" "4-xA6efHW.kloA?jwK#$bo8N%8>#$5[1Q>#M^t:.::U+*Ww39%X]3&+quU'#UJDK8G^>d0]Y#'HoW:h2+6'BCR8%l&eT-Tq1d-@C(Xqs_Aq/q4nW.'FFZQ" "dwgB+ktbW%iFOW/M+=>51l.>>nmX?#:LNT%8d`,#2Mc##l+*jNs(YW%[I=-2Lt2D+P4`#7?R5R0'bq,3uqZ5'_lJ#$1sGNj-Mv&#>#vR8m&0cC;$I$%:4VS.Cp5aExLP)4earRDfGE.3e&&J3XE/[#7rs9)Y-VpT5SDx-,kBloS],G4umJ'+T_@`>#h1.[#*4e0#<6>14Kd''#j,>>#`P)T)P+NBFlBpqBG/5#-gj/v-Psb>-a4B>,N.sqB'D`'#" "K.@V8i.I21fo*m9o:o98:rNY5S^wh21uH##QSB@%cc_&FI3w_#?P($-rAMk'?iu>#da,;%E:_E[O[H>HsQnA#UKMA.1u)13?aX29Kt5al@tHQ835?Z$jv5Y8br+3)aj$125wq*4DvjI3" ",JS1cES%mSK&'J3GQR12FBu$Q4s^B+@v9kF&l$##$DR&Q,xR(#4txRn%+X/1$TBJ1SmZ3'B+`;$T4.m%1I/W--?b:U2DZX$&W7L(I[=PT" "<@JflnP#D#xpG(#H55T'1f(?#ri_V$4sNx%&wD'%Pa3]%eBD>PaX_Q&AWUK(_>Mk'GR<5&_ljHZC&rl0<(^JDm(Jp8.U6gLRKL&=C=%w#+=mQ8%7Ds%?1@m'Ms/Y/B<7)f;X76:ov7" "=`jE*KpIw2?NuO0+_pt8-*#114#=Y5$%Mga_r1i:3FWH*l/E*[]2p;-BEdE&Jk%##gPru5JWWf:gT#i*ONnQ8@4I8%Zj=oL9f^^FW#UsJeR$)%47][#uZQ0)ji6<.H3/&,%,]L(W^,iNuW%F7H>Hl=-A;RS,lLkeSZ7c6D-kQZ/k9G3Z;%gH/W-Pat0NReJ60)rA02,_:O1YFLIZZgb1:M=klt" "XxclL7Oc[7*drN*SmSp7'g8UDNuhW7dxYc4DK[L2tn`OF]u->-r@%o;rO&FeQrxFex[U0Mdb-L23q_k1#.G31Vl#T&IU+T%c,i:d<9%8[-l68%o1FS7Se*?#-]hV$45'^%-V:;$1phV?" "YIW-?k9]nL^n-##v,>>##mGT%+/###I-BQ&JVD(=kmTc-/jo2)@O9]$:%xC#vp%$U##Nwtm#FYK:#^?O&#wC@Z7k`_V$lc1^#=F%@#n@B58Y,e,E(AcY#" "p,<.saZ*7XEp30#*Yk0@<_=%a3FA#s3si00R:a4m(qb$sk'+*+.,T%C=3:.bhR@#=Bs*6Vvpn/OVLg0P_*)+uPe51rjA^FF/@;Y#=G]#-2Bo)=kP76]AVI;BH&8:s6e'&" "4LM8$-K[IqxeYC5#ZQN09OtA#gcZY#80?>8u.MT/^((f)kE#jhHX-%*=UKWpUX%<=d>Hn?o@bmm$&4LBp>6JTF78NVZ;%4hb&FJ;Z0)K-1,)+x>c*?Bn*N>uOd;Ux6La" "&xZL-b5>m;3F+Q'V_,/?K?7.M,ldC+07?c*vI'+*6o1T&Cd4-vewAM'XuZW8cWa$#Qx%8@*`$s$3Nhx4t>#4LgQ&sxNS7&;cY#91CGD80hQ//(wo%O>7L(iBCUi/Yqp7XAE`#'upl8S996&DjqK(b>Mk'" "QQ53'ctc6s[Zfo8VU>W.ei<877OU8@@Ei`Fgq3aXxk,K3-2%6/2Vk--b]QpZ$u&UH;^O&+,h&%Y%HBrA#xr8c0" ".=,)#3fLZ#irH2Nw^h>&8lS/d;1vZ,ODa;9#[@9.B:o)#>FDmLif?>#" "-uu#_B=@n6xJu%Ld-8@=;P(HujT1;fI=@7pHD/#ws/X:Tsb>-=.)XJ$C0X:CLR29Cgt`SUfGlLv%k4#QNQ8&B&Jk;" "Yhr*%@MXSq>4dmRl1QD-WB?D-G`e+PkI6>+j4`D4uPiX7mPdA#q40588+Rs$)?o>#iq?[^3Q*H=kM*R'YYV50Ashl0x_%E4-RKfLQVr]PI*,@MJEih.[PHW.A5*f%O.BmJhR;h`]W7DE" "&2?5/I@$##]FOcM3dSZ7.EVL.'qJ]=&xRt-_)$#>^8F',k&d3'?7.[#f=?e4l^w##5>F*$(sC$#^3=&#,7#)#+q&&=;%`v#`krW$l0a:K:^b',[vrx+FBo],+GXI)vW-22,]Es%rDQJ(" "uAOZ6CH:a#'i'U%r7q8.uv-ou@-26(KIZ&YroJ7/v#*4g)$4XBZDIHfM(d93'gNY$8@So>w-IlY$#gBVuPbGx(mwkQ>#DF$G*v14.)b,)O'wmJj(XOtWqafW&#O;^;-wWJn." "`Wt&#_n@a$C_=h>Uec^$)>P>#0v:Z#uwYQ8Fn$HD4e+T8R8CsHoO7a+*eRh,J?%?$YAUPMQTxv6$Rt$#,Qo],VXI%#@#qZ-am#7&D5%&4_T/i)J*)pJmL<$6]vZ)4k&l]#iZn/PSgtA#" "#olT9GCm<7D9gn/n'Prj?g_11q*TW(T@`v#`6/SB:q@6<97`RBFAYQ<0hRf**@Es-BbsVA-9Hv$+V3j$r0WmL]1C&=uH<+(Mo`=-M#/c*@7x(3B,6W84UrDN8Ag0%h?/<-xOb2%Q4]_#" ">_B-)?dLl0gWI3T%Kj@Q-n1O$%nB#vaY+#stYQ8u0`J:`^k6'qo-W$-Ttr$/7?m8Ykk#-5SvS/2Slo.K6mH3f%.f;h8G3DCXOD#cF-;s`DDr9XN-$$gpM.CxU=t9TL5b@" "tb%/1QXa'5+R&,2Ua@M9nD6A#m'oB0.J1v#1N`,#CgXveWxF]%mXu.:r]ju/K.RW.DRHc*_TT6&-a,,2:YvX$X)pGD=.dg)=J&v5(k%)]Y@EZ'oxBr7@(5Dk]C['&QUgS]52JbSqDd@d;-`DX[87K$MNZ%](#ErvN:<_:*4Kd''#M,>>#6+tg(" "N>YY#-^UV?GM:<-(;Y_$#eibltA^<$UWlA#C4n[--xJq/>p(B#/bjY-;,6w-If?T.`1.[#wW;m$`4-RE%.%RE7dxQE$tSc;_9tr$4.7s$#A8'$'.gfLV`;v#r;R7*ZJ`B#[p:80M^nL2" "$J*X.1KYA#+n]r.)(up@KNJ;i4XEs-P4J$m+#Ss+$G)JtM(_Ztg$GH%#vm,CkbPk>_A6N.B4LF_/#TS;4#Edav%1oqr$7,%W?8a82^aHZY#r+TV-$C+kbw>'%#e7.Z7xCrv#9UWT%5%M?#92c?#9u6W$:a.d#" "0:jl&tl_V$)%6m8K`###$]KF*bd(,)$3nENok0b*ujrI3RDL8%ocfA4o$h@p#$-Wn@%q_n9.;SG>#coU<-SksY$(.on87bxS8KH#XAHQ/0:hxQw^%7k0:?Hd;`%u-ro,D@Z7gAP##:7e8%=/MZ#1E>=-UmSn$TH('," "#%U+*;u_amo:8L()4YgLmg?>#jGCM'$q*m/$m6A4&^j/?9%v'D/:;W9$-b;ou,R#1Z-$DnA-;(Ei-tr@OXJH/i)R6u_0NkY)4gp:Q#g6V-PK2Lq^Qkt^C=&&2Yi_dtJ" "^tO9+@Ac58@'E'#X]Q(#UPQ_#d*^sTTex3'%qHh1i;oO(ROt.L353p[0#6tLR15%Mn@6##CMG13It9'#;L7%#nOs'#(hs%=PKA#G$?6$$&*Mc#1C/2'6BHm/fcWI)[NgQ&[4&70Omu/(" "@Uw9.&B/lB:R;=.ZeAk#%bRB5#p-;(%m_sH0J:a*u@sN0T5-$vuk]&$Yx9hL/.^%#'O']7XPlo$#+9Q&>$#N'kAlY#8c;q%6Y:v#(6TS%^MNr&K+h+*^qr$#uaDD+87q+*.+?c*c$tE," "v[0b*m?bU._kY)4=nx/.(IUb*k$=Q/G>#FCsM-8lIf$qRZY#hV-R9)88dsM7.Z72?v[T:@8_9N(3owN'Pho20?q82'lcRh(B;uLW" "A2oiLFO6'$>OtA#Z+##BHe#%/)j''VWO1:ZU'9p@G&b-+JwBwQx:H6P<]XUH^#.l[=gLU6Mg*Gbk30,c$s$M>Rh(vUk-ZASPw9?Vlw9" "?*qjCrd%##7B3STi?9C-IbTn$[p(N0->G##-VCv#WsRfLVW6M*GNsjtgwv>@Uk2IN?pZ##E$###s'P[$RNnA%Zkc+#v'dQ82c_;$%3xu#)%$m83GG>#iX4gL#OHL-r_DI.WT^`3D(H/2" "*Fe;-W$tnLsa8#%J:)H4Jv`sfcpS3Mw7J(''ml=-CKWU-e;`iNuG5gLXp(+$>AWi-.c8`7E9nQ8K=]$^-G^MY4>#29]%(m94/Ok=90Gk=Rk@a5-WSW%7oU;$rpY@.-'9&=IXe,=Og&ZM" "1fAN-7(7m%+Y$##e8vx4.:2i^jln51hA?I%oE'qR+QsM-x63#MjcAouo_:Y7gx$s$.iqr$)SMmCHIhl80IqA#$b=c/>QSW7PSuY#bw>^#4cDdOc&1'#,Yu##VNO=$.]JL(2'2K(6otM(" "/&JX#5?:;$wurtEJS>+rxLrd*tI*n/RDlX7%_5n&-Wi]./>Y>#fwnm%uvY=(pEGJ(p%Oe)iiqB#8'CC#7m9hGRu`=-" "iHWe$00;W//>P>#6Z>W-*EvX?XVBNEo=AL(F3XA@#A`'#/lR)ZxET_-ws/X:?DXI)%sES7'55##&6,###U,'$c,(W-fFAgOn=kA+3i6m%H/T?nrK'1;vFlD4Y[ReQfvv`*%6=NB_iCv[" "r4?h-u*Jk=+wBM'O1E*6$G`'#FjO`^hr?FVnkX#EIkXfc*+a@Y#@rT7h@" "wjSU`Dj9W-kcT8.cCv#NtU]$_SqZ-5F#gLue6l1Enhd->o]cPu*hb*F%KK1,TLj'+pm#UKHs<7jDJnN&9EnNO').&*xAh;Q'sbNNiPrd#)>>#@.J=-o39c.EqUY7Ts+@n" "q93*%WSUS%AD.'F&k;W%AFg+Mv^A5Bpci`Fki#aND:nQ8^GXk%?t.RAwhx>Igl)?;LFl98Q[<;$-Y:;$?V69%/L?l(3eQhii4#DZEZ%'>uu#/vZS@%$Y<-fUl0&cF[PB%wrc<;N1U.[Q1,3^E9S)iVfgFx=6##IlK`#3t9'#W3=&#(+g(#)J1v#3>B#&gSBXoUe)?#" "qh]/1:DUK*W2SY,6FZG*oc6x-A0;hLi4JH)27E:.H:w_Faa?T.SH:a#@mQv$t@0+*sII[#Vi=RDdG]v1YV]h(?WIh2F<4>-kZBS%VCEL1J(0GV8_#26>##.5YY#V4e0#" "(dZ(#Gu3[7?(A8%9%)v#jb&*#.;cY#;GT#&2cc##^]OgLDMwQ8.DlY#OsmG2#%TE#4k`)5=eln0Mb?,*#%+Jc>#tsb>-1sES77B:=+" "t>]Y,,PbI)g82O'Hbn[#0xGo$b,rE@YR)?@bQW2MS9UuAcG0$-M)AL(H%)Z#?XY-,cecHPu(]dD-:NpBZZOo2s>cX7k7`V$p?u#%1lLv#" "M0`H,4%co7(^bm'fV%l'KsL1.heR3:%R>)4RU/30R,=.3cI=@$CO@(FGJo`=4(Mp&3flRA_EhB#TD6C#'S

/Hu4d3" "xtQLM0#Og(_%#'-R$0Z$PJY>#rGal8f-27W[L.t-2;jr?r%7@^E,%m0)/]^.U1.[#nM)Y$N7H;I?A$aAF*=`A:s1B#BlqW$6k=Rah5>#l1.[#F$Fr$.7[Y#u[Al:#PPH3AuQ>#xg/&=A<0<-#rGt&_(;?#B-0q%Q;2'obE:K(PEO,m" "(;1_AqK$'#9=*9%X8/m-m?'Tai*iOBT]tm'h`Rp0Lsm`*>#`)5Z_Y)4[o%Jq%pS@T'5fKo?uP)D$OiE?tkD#0pw.S?,Wld(sc@>Xu]WRQlXYCi@eEQ" "_B`@>:f(pJ7s#d*XxclLE,k4#d[?ZIxRbA#7^Bb*99.e2`4H>#qE_c33IPn0jrQW.e-s.lFEWN9%5ot'A;8F-fF90%PZe%%Cnm`EegV8&+VRt-b3R`EpBb'I?`8F-aU0_%*u$##w3r+;" ":#pG3AD1:'MT-?;.T.k*LC4F-`W&4wk9.pQ?(#.YqP'u.n6`w)pYDioKdOA,6`)Lg,Q/,7#)#.Pu>#ICXsHY+X-ZnRfi1h]$<.4wUs?J0(KEhh?lL%O&mD@#2_]QHOU." "?Rd(+EF7WA)Z`A.&>uu#kqp,2l2h'#=iwZ7^#;^#m+058v<8K'-[Bx7_a`s%.Y(Z#O)k>5^(-##O^eL2ax@M1@1YI)KR[s$YfEA+@-5[?LV6W,ZKl^.[s$4^`,#/Jl>#" "IlN2EDs2L)i3FG2e#p&,04$K)6+m=&I)>>#P5YY#Bl0gLaFp-#TGJ_'ZEX#7vo8?$(5,##1NS_'&5[#@mMN>,Z0p3VpK&'&MJv`,Pb$+Q@r?>#[sBM'3H+m/12V`3C([>#Z`7M+P]8D$" ",)###vxdQ/oMPW.Gk2D+5)q8.55SX%AEg8.X$nO([/TV'0c37/oSlr/DMfa*VkC<<$^9/h,H1H>[72Y[S%HLMmLw,R##6GB#&>q&6&6S<5&8Q[W&[=S+)vq.@#^%oL(#;=.)" "G:%@#t7O_$$qNEEak%9&)TUV?\?ke;-cQ_#'upl89PG>#Wv10(>JI+6eD%Y%J?M&#)CwGM2_WiK=:3Ec>`8o:Nr$v9(;AL(N7xe%Q`h<-U+d9'PAcY#/GG>#awi5a71cS7Bd-LWD0[Q8:)Gs'BZ->8L:?uuBdNw9" "XZfs7$3*?6Kd''#to,X&0CW:@)TQuSD1,]RQN'2BjxaL>)G5HMBMD2%dwK]@u23gS:I+_.,D@Z7nT(k*jXggU64wR>Zjv/;fZk?#pDWXC=XUZ%t6Y?esn=&;AFYrD8.R<-Vp%3%#4XR/" "75v(3FDm89eM*o2@_'?EYBVwCR_l,2SZBM'YDpc;#^U`3@l?>#xml+#u*mQ80S:v#02-9%8hxi'qo-W$)B=;$++-m8dQ-[-%0fX-9O[X-)G#c*4Vk?>+Ng;.Sr1iCd1qN([nH*Xw'RK)" ";a/iC_xIP^]l?T.l'h-#RJ1MbJVGs31G8MBtqU>#BFrr$q@<3$'8P>#k-Jq$cYG>#wa&&=+DlY#9]md+Wjc'&#$wf;%l9^#i%k0,RI6##bc'<&)Yqr$L;@L(ecqB#6cE<%]HM`N_:c99" "@oC)*I(7$IcakxB$MB`N(i#%.`Ix+M-@)&.PmThNlDZY#O<90)w9$`4jkf$NI;8GV384'#&6`c#BmtgLtGj$#t^cO-Y^JZ0)Buu>-AP>#_:SfL<[7.MVO?>#:6YY#MK44Mh;n+#o[li9" "JkZgL(k)P(k'Uj(2$Yk0>]WF3I)tI3$3Tv-ePJsn`J)p/v4e^5Yo73:BU&w#Aj0Z-bUsX.IU,H3%V/;/k&&t#cn.m*MG4s/GAHVH*MnhC,7V=/$%Jl#s9b$MP@W$#d'ojM?9$c*lk%t-" "Tu[fLer#j'eWtK)(&###+Duu#t%Y7*B1?T'AL)j,k]-f;cqgZHac)T/i6(Z-qws*,4tv_+hABa+hnsx-SF9'vUL?>#q^FM'#k-eZFviu5#BQa#%Rat.2.)`+x#wZ.Q4YM(`Z[o[Hghm&spSn/.R#R&H`###WVd_#F1xe*nTV[.0R:a4ElL5/SDIpMTO)uLcc@)*iENfLQ]Oo2E5YY#=t9'#-Mc##" "Wcd�-u9qRXmY#+qgS@,jtȣW$*s?W%_kEX$O/O1)ZgKZ-vgJP^U.9]FSZx&&$/gbiaP;4#J(-5/QHT>6Qwi02b;Vs/$4J[#,;G>#54LK%E_c^$loZWB3=CW-Lb1F*06@d)s9Z)4" "KJjD#TMrB#jBFA#$Y0f)9,B+4hC]hXlMl]#JA1R'u.NF3oF^M/3R5R0?b%?5?H'-.W1(f)7i+vmf&xg)enax-MH:N9Vt%d4VRsX4+P`pHh79K2?mb+1E)Mv-d[BBl2Ltt.4UA2'-xTk$h[R0)mZeX-sc`,)P5]k;n3-O(W^Tv-6YTN(.:%)(@-Q&>PFQ21KVD/Ua7BfCP#0*+kCN.LOWp6&&OE;HBcSd+^6wlLxI3$#W%j>$" "')###+Ex>#vUdYoN7$##x;<+NXltA#6^JeGB4^V6Gwd2O^Z4nE$b#d)6klcE:wK'dH1(58?dlaXv_g/3nc@L(aTc2;)17xGg.lA#,=5H&E57m0TC-X]10QD-8>'5;k`KM>QYK>H;aT>H" "loPM-3D//.:?Qw7^S+:&=hap%E[>3'Jm_g(0cje+9Cue)GfG>#(opb*v+4I)bZc_-/n.X-N)>>#Z]L=-e%:IS@7rdMNmZY'M)S&#UY+H*h_Ms-*m9e*n>f9JB-K88b>392?c.i*b_#o^" "/S?>#aBmY,gpsc;W?Va'l,e`*fYRQ/vuD%$0(XO+vlX/2buVS3L#####-S>#KS/b*2phT.^^A@#F6Eu.DlfLgO]Bb.XW;#v])Z3#g2Ix0g($HN'X65N2M6##:Fk]#>'U%189/W7OiU;$" "(,,##@]]&#Z#+iCE&D$^lR=F3w_]9MsfLU`3[4nahPWS$gt=`oi>kJ-B>pV-kkin#@O1).sudmMGmRv$,Pl>#/V1v#;Dwo%-qC?%%Lb?Km5-Q/" "vw$PHF:.9EsI3>iJGMV?BsMY+M4fg,7>;xSPwT(Qf@tC;9/:LLpM1hbtM(^3N+`uCpO]n]1bI(Eou,kI529IS#v#5FNP&" "h`Rp0:x_v#'mD*eRMlY#0rC$#W@]v7lh?lL6_9,NQ2aBU$TpN#p';pMqqJfLbe*$#-dR)$Z(V$#`9F&#=Ja)#&[%-#?rQ.#)N_V%IKe8@Q[Iw#R/)k'+;>##?Y:@#6H#^=M[[w#'.ZQ8" "7S:v#1/L<$4L82'`W2i<^#xh2K-8x9f)&(H_+Ahfi'Gx@@>k@hXQ]aEZ61L9T&_AV/kXIPQ@jZCY,+$3E^E?9/F5YY#)0up8^7fp&g####Ks3g&',:8.gUs`uuR_+i-@-b[1v.U&l1(58RXe>#*8,##.KCV?B1.s$=C8L(i*?,GlR?x69B7g)HLuZ%eT/i)<=6g)'wZ)45hN-*TV)B#9H*C+[pc)M]rU]=fuhB#sQQ$8SW1#.F.%#J,qT%PCvl/@iBTTs[0^+6ax9.Tm1T/5d_s-/omd5Smj`5<1k:8r2(j0-%nK#1s-Yu$Us`u;S8Hg0gw#MAF$l$Ig55&rt)RrX/UxWD#u?lD#(e+H(MHlD#7%x[-3+gm0_9hP>Hrq;eaBFX7@'BR/?QOB20Oe68C=/R/`GEvEG(1-@42Qk0v94M04E&O(dv$BPB.6V3Vk^HdnPOV-i7TP8C`@-d_wFQ#xFwm0jn0N(" "LUaJ1J:)iu(I.m/nrducScFe-$I9D3vfF/21k`s%8N$0%_wPg1pjxw#.&Es%T>$_u95VT#`Dl>#&1v7$3%-iglMjI#Mn>3#xp(G#g>%@#?%ffLn1$X0;.=`#veJE#_YCqL+-g%#F$8nL" "%M>gLj[)Z#*_uc+'U;8.)$o_Yn-&fuPUpA8la`Fi2_mbimS#oL3T-N:e1OA+IKru,6lju5r-)q4_*@g)(Mwm0UH:a#ae_F*stC.3xE6^4@V*w$C]R_#R(1+*Q(7]6L77<.hHK:%BJ^P:" "M;>F+JCce)m.4J2>tWU.,eh80(%Ki1`4D;$dHMd2dPh;.bb`KiU1[K)M/B<7[9GRCk2YO0xXV+5mgShCBRFR0WxA-=XJ,##1q2`#EE'VmK/(&=&;ju5X^00.GAYY#t#Zi-51@0/a+&L;A5XjB;.:-bu-[Vo]5QEOY-_SGB,%%ZhLGB?>#Vl24Dl#'%#>6S?##SrB#s`%E37jt-$" "(LM8.mDsI3_+xC#0[0@Jbx-`Y9vMbQO,0fa3`(SmT_idu5-7LCE[AuuMW4oLJ[]w#'bft'mA5&#+[E.DjriW%B?@W$%P*n0s'Y>-UBIv$G)C<.,j?S@4O7>%StVV$67RS%B3`v##Jwm0" "(KD,):K_#$;<w&DuY_G[e$0_M<%6h_V$>Frj2*obA#1qM[$'H@D$v=xs'_Yvo%M5DX(vTuJ]o1IF%*WCxu14.[#KL17#-Yu##UE31#J&###F,HM'" "hw&mB:=,&ueGMfLYZ7fMea7DENBZ]+tCF&#N)[ihN4RMLg$C2:`uUk+TxD_&e$s-$Xa=.$$%/F%qFm-$*c;&5Ne1p/KnL50P^A,3J'I21?wdw')4p.VA5_oQ>6DFP8/l/fM13ls-$PC-j12APk4iN_w0k88_J>@Lk+:Nk-$n-lk4Zs0F%ej6F%]ifiB_idw'@i*.?*/EkF:JK21kg*:)V]?kO" "L;w9)3DO_&@xSkkI:oV7^*U;.BY9R3;,D_&(nj-$4`J><-1kBK-=M#<-g7T;-`5T;-06T;-?5T;-A6T;-@Z(*%Zr-F%L/l-$*j^w^uk.F%)sp-$&jp-$" "'Pc_8NO3F%Z[r-$fIQF.oheG*;p,g)p;-ef#<-v-R^OA*@q7Jn1p/ZO^F%1V,RsMJ-F%>jcG*et:_Jt.X&H5u#<-g-n6%?KjDNk_;u7eNYF%WLX>-" "4C%^Ou`5oLgno4QYLI*NSJlDNlJT,MahDu7jf(G%_qt9)'kj-$-4U_&VY#WoS$U,M]7QA%qW+?I`Bj.Ne9$<-C6s'%->wEn(.=:2)H'd3(MV8RSOQ-N,9$<-`rA@RomKDMjnS/NC>T,M" "5lO^TiH-^9x/MtrPoLgcm)Mqa;xL_IBvL$M%2N:EK887g%RNL`D_&[hPG%-a>&5Okt-$?x2F%n6$j:;:B.$&CF_&XH_]PTpo;-CGY)%" "fjm2`M1$-NF.94MA:xiLtkiU8/9`D+l9_M:*[7p&b:G,MG/M1NUuj;9l-.<]J4$##RV`S%XZPrZ8IZ`EdRqf:HXcrZ'L0g(5/0)EN`dfUHAvM'5RXMK_`1T%latfUu=%H2qJ+m]Z6QGr" "0/@a3I@nYlRnCgChQX;m.Y+<6idMsZoF@6&%UGT@uJo5]2@mm8LZxZ#h2mmJxEn)jDExg:XLbaW@22EOsH`:@HU7" "N#:URcg3bsmCJE-" "5r)p-m?T^-1Ruj-u+:v-k]e1._jI9.dILC.#g^j.Y11_.%gg//o>Mw.IP@5/Mcb>/`jEI//PHS/&UW]/jJ[10Octu/Iw?)0qCH40u,[D0@?[h0Cc0V0`],c0=OAm0XS%x0H+?01E_?@1" ":WEe1C%qR1])^#2XWCk18i7&2[5@12/RH<2kZ+J2944#3koWi2?9at2]72)34Se53]7;D3jm=N3GWZw3lmFj3'(F:4CUV-4Q^f64DJYZ4CIMH4K^oQ4LoCw4fT=f4S,Yn4XUR=5&;w-5" "rJJU5)%2D5E,lN5+)<]5TN)p5MMZ-)-6e)&66lLY?61^OJ6PInp6`/h_6x*9j6pqLw65QO+78o6P7<]kF7HbWm74E%a7i#Z488.5$8XA+/8fL:88#EbB8J$Bj8BR([8Rs[e8fq-p8" "9i)&9qL+393+WA9m#2h9#v#[921N*:30Bn9?uVx9aauG:IHp3:c9[9:(Cl?:k/`d:$::S:org_:Iuqw:9f2&;,J`1;H)b>;UrKG;^#2L;Ks-X;`VYg;gQWm;Q:@8N;Ce3#QlRfLm?Q.#" "4Nc##rAP##OvK'#KS3rL>DmB&u,+,M.Y5;-bNrdbR8RtLYa`m$PoQS%EU^R*MM:;$AVm_&cZZ`*Ecm_&XO/2'^Un_&+QC_&5(o_&,TC_&BOo_&)@=G2/wo_&ZINP&`]q_&[LNP&kxh_&" "$Vdl/vCi_&n2BdH`9C" "'ditBBjerL:vAeGl#oUCTe0@-T1D5B`EQ@-8q5)F2AhoD:H*vH3i7FH>P%l=*T1O=2oLnB1uwiC=n5)F5U%F-&p>hF)s8oDw?vsBQZ=lEnrCkLeE+)>W^:(6djeM1V#f%'#;1eG38vLF" "+YD'PSO,-MXmSE-%O;9CuicdG/iCrCgHaE=kW_J;foLN(8qL.fipL(FD/#DX-J,Ok4T-x?0J)@X(V3Mk+%$Kq;6tF_&6Cn-$^Q+F7JERfCS0K5BETfu-1G##^?G##:F^2#`5s<#:cjL#]_^:#_4m3#o@/=#eG8=#t8J5#`+78#" "4uI-#m3B2#SB[8#Q0@8#i[*9#iOn8#1Nm;#^sN9#qh<9#:=x-#P;K2#$%X9#bC+.#Rg;<#mN=.#MTF.#RZO.#2?)4#Y#(/#[)1/#b;L/#dAU/#0Sv;#lY$0#n`-0#sf60#(F24#wrH0#" "%/e0#TmD<#;Uu>#4`1?#8lC?#,px=#0%V?#1/PY#3.i?#D:%@#HF7@#LRI@#P_[@#Tkn@#Xw*A#7QJ=#;0=A#a9OA#eEbA#iQtA#m^0B#qjBB#tm9'#&)_B#%3qB#)?-C#-K?C#1WQC#" "5ddC#:x,;#>rvC#=&3D#A2ED#E>WD#IJjD#MV&E#Qc8E#lIf5#ppJE#Y%^E#^1pE#b=,F#jdf=#Z0?;#VK>F#jUPF#nbcF#rnuF#v$2G#$1DG#(=VG#,IiG#0U%H#4b7H#8nIH#@@:R#" ">*fH#A-]-#GBZ;#1=+I#HH=I#e;':#6OB:#3[T:#3C0:#nL4.#Z_,3#+[XI#RgkI#Vs'J#Z):J#GVx5#8pF6#Joq7#8j=6#l5n0#nSE1#@%.8#LPC7#T6LJ##rs1#VqG3#WrM<#[@T2#" "hji4#GLg2#t4(R#E9P>#m.jD%KGRR2q^);&6JrEH381SDkoH&Fu@ViFv.1VC(3f:C$]eFHpg`9C]&77*25emMDbCp7)`I'Iu)IQMEkLp7-2vLF]Ta2B5$89&Y_nFHR/0I6:fsjNEn?m8" "o)W-M;Ve?3R&+%up9-OgkBkNQasj9&5H1Fs86h--^U%'MXsTBdAYGD'7d;%ALRe-vmJF%" "nBoNM8c.dD+=d;%+s4c-vmJF%vs0hNG:NJ:Cc#4EZGmL>FXGLOTpoG;'+OGH*mWRMM)PH;JQAp&sa=KM#)+aE(xg>$tpia-pH3I$tjbkMw$1oM[;@IOF^BBF6FHv$O/R]-xm&+%XZHHF" "brlKFgtkkM4J0^F,7Hv$=j[m-#q&+%m)VOD%Lv-lE&cS>'LAvW-q,k0GA:9SMS`HB=ECDp&M8mW-q,k0GBCToMwxuOMAg>vG5'&X%O9`9CrdM=B.Hpb%$9ClMc?LSMRP6#>^sKG$" "F/7m/]@poD`?b'%DW5W-^dDeZFXpoMQVd>>(0Nv$J8.Q/Y4^oDtFoVH/q[5'<$mO-RAvW-nkiAZq()WH=W=U&e%VeG%^4rC#8A^&P)H<-2)H<-R/dW-x#8kEV+Gv>*G%'I6c,pM%;DPMr5V8I76Jt%X^IUC-mgoDI(dPNW%&W?kO$sI'Ip9;XdZL27II29*HLc$LXvlEr7999twp?H*p_aH.HXnD3qMfL" "JF-##$)>>#K3w>P;@e3#cOj-$&t9'#vdlb#O'>uut8X$Mws4U%,q+/1fdfpC.w4/1#KTV[>b*N$X(+N$=ut`-c`pCOG)=s-C6n'&8ap`?D?839m7T)096AT&j]+Z2TZaJ2" "bg/eaR4wiCes`@BNGZa<<$2R3W9Vk+/Tl'&[.n'&dSng+:pq`?pgfi0T]f88?`f88/tqY?cWUT1&ul<.&1>?-K%mMBx'v3+]3S?#HVxiL" "`EBB-0_3uL-;5Z2)[S4=Gs2f+3QUD?=5Ok+1KtC?Nx%a+UG27E6K)N$Jk2Q8XO`Y#_0>?83C(gLq.h88mTg5#EmM^[I@'_[%TX0G)woM03?c/1-5)E/1u99_b`qpL,p#-.KU=5Ma1tv8" "e<`;%LBi'#+WIg%xLJE-xZa5Bc>l[MV.X]+c,Oq22`$V[Q-krcm:'$VC?JR#<.$]#H&&HSD=2hV8&[sEN1*op?-`xGqVwUhHQ?'&RE" "K-WQ89*A%B,h_gLTrtW[Oeh*>5o.?#@B#W[1f&WI9dC01d'@5;1Y`X-Nh5R*GIGR*9@/t[s19E>EE2n&BN1X1KNlj0q@HP8=`x88f%9I$)w/I$eY3)*E+?']Ujmx[sqdsA?fx881(8/M" "E@BN0v0,O4FP%a+(^s63$wn5BBMXV.$xDQ8%kUL.()Jm#wHsW-/54K-VC9F%cE,_JE.9v-VC9F%eK,_JQ'vW.]&QY[c7vW[?F(tq*ZIE-pr@['=&Im#3C/F%W7=Q0H)rG/PFbm0P)lN1Gqq?-A]1s7-9?<.Umu>-Mg18UPaFY--.8AnB#O5`P-Lmm*MmfC12x@HP8EktW[m89I*lrJ#2lYnV[M0'qL>-)41BG$)*bf-@->u68.==*p.t2Gx9" "h:_5B+ktpLK&-Q#jh^#2NYWI)'BOK2lS*)**SEjLLYDm0J])q0em-=.*$GGOB.)g2bhb>-nQ=v-%=ufL]hev6ONjj<7C4g7-#fm#,7%a+W+$$$qi-<8uG@g%>^3uLVPq%/HsD^[fL>9'" ",JJE-DCU694gd_#N3nB.&0*9B6bQ][:+xg+5.JpAUC3p.hBB5Bg]IW[b7)Q9PW(;.n.fP9[Jn*%cg-R<%2;nN>dc<.Or)pA<$qV[1uipL8mToL#gipLje'KMU#`5/^>1a+Jx3/OB]mS1" "8SkW[$HX>-uWa5/=JHp.=m@P1LM-7*xN*9.%.fu-V''nL-t]5BgV#d3XO>na43l6[v[.M'EYcMGnow7:R5s.SHdM:x8Ks-0oMs7;?69KeMKs78DpTVX[_846ljS8-75?-" "`^+pA:cT18MW1E4lC+j1'G2q14PXD-C2Dt[4$lk0lQ=fN5PneOu&uCPIbo(P%w-51oIhWRbE751fGWEOP&QY[mP(HO6TUs.Ifim1Q%DwKua&T>.c^b>-$ldm%E]72NT:R51qZ?t72+3v6>o/Z-8tsr$B@etqM*)tq5`t8T^2$6#NYWI)AcjA1lj4g7:R#t7WCD>#(p.^1.bg88]@QkLeZWmL(BB49" "`f-@-#[a5B@,@U2Lm@g%'p1d8rAhD9W=)##`S,<-jS,<-(r(9.J9?Q#wNC2:CHNX()Q3O+Y+vlL30BnL%+p+Mo5KnLH:)=-)2#HM$B^nLB53>57g<,<$]bA#tsVG-vS,<-%V,<-BIrIM+mGoL6:)=-6u@Y-]+(F.$+Jb%%0Pb%7&4O+15L>?CHNX(9,4O+VoYlLC;)pL%+p+M)A2pLH:)=-92#HM6Lv81X4LmC-]i5M7@$T4V*bSA^Gu`43(JpA" "lS*)*E8[V[c1M9.?G(W3[9^PBeQHX14hx'&sP+I-5kx'&Y^uMCh?xeNW7]6MS&c?-F5g,MZL4RM]nHlLf?8:1gvr[0=#x+?h%9fSiBn$@8.>1R8.K3P49YNIh,V2S4;2ZR%@&g6c+aq-vA4rkL>7,AV%e.Jm#H1Pd&]'89]gj/I$3?0I$W<:>]HBw29#;l)'dwrs[vV_v[x7@4=J3:gN6%]v#nlp/M" "eYrN$,7Dt-DLwoL]VvQ#^W,N$hYV##$gOFD4'<4#"; const char* GetDefaultCompressedFontDataTTFBase85(void) { return ttf_compressed_data_base85; } ================================================ FILE: src/forkawesome.h ================================================ // File: 'forkawesome-webfont.ttf' (218132 bytes) // Exported using binary_to_compressed_c.cpp #pragma once static const char forkawesome_compressed_data_base85[214910+1] = "7])#######91@P)'/###[),##0rC$#Q6>##T@;*>[VPlmI$g]=5g>11gZn42d%&XpG,>>#I&g<6aNV=BmXpxb-OJM'^5YY#D2XGH-VSA$NiFJ(LjK8/d_(*Hlme+M:6h]=3YN$5#-0%J" "a+msP.*8>,rM/m&0.d-Q@pV-TT$=(^K-G&WbDE-FqEn/<_[FHv'=gu;?^01=G#cDE-BqEn/DJ[^I&IP+%u3S>-kfWX%34^=BUkAr'X>wu#jx###^bCiF" "cLV%%&>%v#q,'##$rvQjQ&###(Df$SodPirc[4gL)>$##4+0oQ87,F%t$pOoE7np%xF[w'OMYY#N$H$aw$E5x-##C>uumwmo%L0vhLEAgV-04FX(r#?v$-d8KMW=6##R9dA#cC&W7" ".ALe$OG:;$c7(;Q^5Gb%hXjrm(J8Dt.4r5/1_FV?w,QfLblMv#BCkh#0:-eM@m-^4.,<6Cor8;-'j]##p+@cV,&6MTO->>#MkKI$k7?>#A2nu5+x0^#$g(T.G[qr$rVjfL-:K/LW:4gL" "&8T;-::#-M$C>,MLtUaNq9N$#NOuwLje`=-g1ukL(C>,MPZH'vbVC_&P(A&,gJ+x'jbE.-6O_>$fH[caHwC#$Pj&:).OvV%,FQZ$le68%SI4v-Ji*gL4@,gL9kL)NF;#gL'=5,M/.G(N" "?mL)N_,Q)NW)ukLOS#<-]UhlL6(0jKQ0E:))3,F%SYY##iCs9)?EMb%vSAR3Ha8xt3G###eL#$&cPhLrwl;-&:e;-TpiiL]5]jLPRmuu8l5.?pF$##CYek4#fJ_/&sMkF)fkxu/I>HM@I5**?rsfDXhCZ$vW3_NNOP,M" "s5v5M_V=5]kik##dn^k+o[h/#bL6.NFE:@-_3nMMkr-A-NLx>-d1G?-HpI3%uZnVo#(^fLq:T;-h:t$%OmK.ZfNkd++F5gLV%0/LoT).-k_G,MRIpL8?%$Z$T^S2`(@,gL-F5gLGVG-M" "cY[r7M;Q9i,TC_&q4)9.B@uu#[edum2fj-$:%K*#UTj-$12*x'46nwB&*,F%t3@kt,TC_&J2,'$6@2X--0F.vg5Jv$V/;.MiE;/#(aNjL]XAV/Nv[@tQDtXuOfO,MC%*/UQuefLjJ)G`" "xi&&t$vS]tSe4-veo5R*22@qL#YhlL(Nx,v0)S)v6^?UP?A,gL?:#gL_3YSn&:e;-45]k8L_8oHj9;U.l%l2fj-$OOo1vqCpV-e1(F.dc1T.H0*##IGu[MlK&c$m]sVPEa:)N_?;G`:OC^#M`[FMiX^@%=uNrLUKx>-'SP8.oIh7%x8v-$4.$=tmv$'L_r$" "T&vhLL@,gLPApJLSlc;-A$5Y#W%,Idv$#;U7%-Tt;-Rcb4%+9,F%GZNjL)V`=OM0oJMu4$###[@V'1&[w';7Lk+*eu2;'Lu(N*L>gLR5l?-T)oJM-+?%N" "cL>gLEUqP8Wq^>$/X;s%WCV2`mD=5]]bE_8Z@Ok4B9icj`#3xBj8'##9b%Y-?v0F%kv]kFM;>uus7T;-%ji].VH:;$&3q5'Mhkk0Q[gFrbw$##&hV=u9I=>Z3iI9i<-j8vsXQ-HJ5a/$" "2=6;#Zdj-$h24K3;ICp7_3Hv$2N5O-AvtsNb`./MKc+p7o]L_&6_v;#t?Lk+`3hW/HM_3'D&Co:_A=eU_&h.7Q/*iQS%XRUV$6WIk=*:Z;%c5/?$K*:7%MDUk+Rod--U;>uuLBw,v" "%A>uu6HDiL*9o,v2SM2iQ>:@-PZCx$TW):M0aEO8S-h-6T8K&>k@d-H2Gk&-24pfL5AC580GwctfibKMcQN;&O(r<-k;Kw%JZF_/RWe;%M8;.M>VRFNU9[A4@NR_8SO)##?F=F.?HW@t" "=5b,MdFY9#E:L+v2M`f8Ltvd+>q.>-I+iE%x&&Rs,udR*1=:Km9%5Ii>R.?G@*R<>@Kk48/J.qH,'##V]'##,'LKEN(Ui9Vb-Z$%uu#88H`-+B=_/?Rbw'FruXu%Ie2M)1K/L/>`#6OsnfhN?D_&Jm2Aur/(&YF'%Z$" "^K-Aur?L&#V08KY%_N68p9Xa&l2D*MdZQhM&0k20vdsD-^N.U.hndo%`O#<-U7T;-g?%'M*vv##t'cYYV%e--3,[w'oYJv$8m*J-" "g8ggLiCg;-#G5s-nlRfLMC?>#x6FGMm8#&#[97#Mi*qRDigWV$lh5;-1^2t,?t4D7kAm7$LGa#&2qk)@0qgKJ5qacn8qK$<YqQ(x[q#_H_qdulbqO9:fq:Sgiq" "$e+mqe%OpqO>#cYlS.?7YY#r).m/#Auu#JH:;$Jq]G2TZqr$%d68%7lQS%pvmo%%XjfL" "DXPgLiuv#>]XbgLV)GT[l2=B.;6)PP8.oLIV6a7Wv6<_*87G=S;7w$kV7,GnV7FE1s7N^1s7kdP88il%98]-BP8lVjfL" "@4nAm?U`mLVhjmLlnJgsF:Xgj0p;*G2(W*,Dt7nLq(mZeE$AnLH6KnLmR`[.H6]nLEHfhE2nQha1`hO)Bd4R*hYtjt^RQw9NpHk4VcxE77#a*#Jh0kX2i*kbpsZ9#oIg--NW1R3n^+R<" "hlU%#mx;*#T5Ck=m*u7#IJF/#3KWkLt*59#7-;-#'2mEI*Z*:#E:#F7dQ`-#<,2R3+nH-Z2F='#kKw1#@J>$#&O+kb+ZCk=K&U-HA@R1#4Qs=#dh_0#3VmEIsJY:(LSKR`63/l<#/nF6" "DV2`@,&GxSMMb:_1N_:qoqarL(.lrLW/lrL8oRG?t99sLQO8/lu?BsL9LCsLfp-TMwKTsLO`_sL0fhsL&FHms$_psLUv-tL$w-tLC(qa[(w>tLl,@tLI5ItLe9RtLP@[tLxDetL@x]$p" "Q)rnW0Q2uL+d.kuLO-kuL4,kuL03tuLF1Qce8,&vLc?0vLNc[25B'Lp3Y4Z9MXWK&#Oil2#Tr'RE^3<0#:%.R<'RQk+" "gL^9#8$n/#c&j--i`d'#MwBgLu;]0#tZM9ihxJ-Zb@U.#*ib-#bU;3#1*f$#$ZHwK;8,=#F1m9;vecE[=f]Ee?qoEITj:6#J;YnL.B@;#_G7_Arn99#+uZw0&'vE@_wiER`$jERX9Lk4" "j3%/#IsBwTwo.2l'##qf^o/[9)##mj)##gZ`=-Hf=00(=$##B8+##KRZL--A:@-8*LS-'gF?-&bCH-hPq)08^*##5Q*##%DrP-m=8F-%6S>-.gF?-qB;=-" "b2QD-/Nx>-X?9C-YK,[.m%###))7./v=###<+m-$5)<-s/3eCs#=*`suFE%t65T;-vZlS.qPa@to5T;-qQP8.nY&]t*SJ`t5k?Cu*;cY#sE(v#_OC;$dX_V$(.m/sBsl&USSM'GVjfL=w(hLbsKn/_Y=0hahX0Ld*ChLh:.UR*$x0:VnTw0s0g5#XtC/#M.,.#IjY6#tct1#xQcgLbbEB-B%Vp.^3E>#VYl-$YLD>#tpE>#;pF>#" "vI8r//C@>#>rC>#Wq.>-OG+_.i7?>#S;8F-JM#<-LHvD-(p-A-%W_@-=86L-I7Af.$NB>#bX`=-oKx>-9cEB-rY@Q-GPZL-+oYH0s'E>#iZA>#7Ym-$J4D>#[gk-$0?F>#7k*J-qg(P-" "dr:T.nNA>#?-OJ-cYlS.Du?>#eM#<-/`CH-P=Ps/g(D>#WMC>#OcEB-_ure.m,>>#i5T;-H&wX.gfC>#A:7I-1;C`.&E>>#4/PG-(#Mi34j>>#gWF>#(CA>#8rD>#hO@>#8N&C1lYC>#" "^+@>#fAC>#=@FV.$u@>#eo8Z.I6B>#8aO_.<^>>#:aO_.Z]?>#U?:@-R3_W.HtA>#'%v[.di?>#5ZlS.%LF>#@+Yg.PfD>#op-A-5j)M-B]AN-<1QD-ceF?-Gs:T.d4E>#CIvD--bGuG-Jn7^.cv>>#vpDq/$fE>#?]@>#Nn7^.M+A>#QgG<-dr.>-SbDE--)LS-M6T;-X+Yg.OqF>#n4S>-A&kB-jm+G-rBrP-MV^C-_s:T.dAD>#kt2B1YsC>#Wi@>#5Q?>#CRgc." "sYD>#'Jbr.<[B>#fhk-$9=Z5TOF5MT&g=mTvXl.Uk8kiUE2Y/Vs&.GVLW=KVf1IcV6:e(W$6T,W]B*DW.YmGWDLE`W/^,)Xg]CDXBLa`X92d`X(Xx%Yh#L&Y%$#>Y-$cAYc->YY4dvV[" "6lQo[X3_8]](3P]=1TS]dSno]q$lo]U.05^S*65^_h>Q^LB/M^xMJi^,p*2_Ja9#*3YEnYhN&#+6YEnbSHk=wf%:)uGdw'h#N-Z4U.F.7mw^foZ4F%t/6(#" "J%0:#DA1R_Y#-02RA-oFuG-8JwA-GPZL-C86L-Mn,D-,R[I-" "b)=45CHbY##3^Y#Y']Y#Qc_Y#e?]Y#mU`Y#rqEn/))ZY#i=`Y#V]Me.4?^Y#iYlS.*q]Y#s8x#/h%`Y#Nfm-$g0aY#?MZY#3Nei.>IaY##bDE-wYlS.$4]Y#U9Bc./NYY#D`CH-#DsM-" "El6a.mV_Y#FeF?-v+f'0BsYY#M=aY#n%kB-;[Lh.]d^Y#*'KV-J4S>-U)Xj.3$cY#a:7I-jk*J-vVjY.jUaY#x>EY.ufZY#vp-A-n:7I-KbDE-uW_@-NgG<-PgG<-g4S>-8rdT-/.OJ-" "ODsM-/)LS->&kB-6Mdl.]@]Y#/spk.IY[Y#_ufN-;FtJ-wXkV.:%bY#t4S>-4X_@-d+Yg.Tf[Y#&HuG-x*MP-)Mx>-`6T;-dUi].5L^Y#/(-p/nBYY#m>`Y#4%Us.DoaY#g[k-$.&_Y#" "IsZY#66ZY#coCt//p`Y#EX^Y#X&,s/.d`Y#W1bY#e96L-_Y?T-C/s:1hK_Y#NNZY#rW_Y#b3RA->Z`=-a5?l.'obY#CLwA--)l?-_Vi].Zs[Y#MxgK-@fQX.VJbY#tlw:07&#v#[0wu#TLm-$.w&v#b:$v#oR$v#uawu#gM9g-9WuH?x'ZYY-l68%Y86Q#" "Af2;]r9T1ph6=W$G(w2$)rus-[B1,M7C>,Mp`7K%d5%V6rd=R*m=pO(FaKZ-,83LG)^b?X-0k'u$ZVd8/7%x[-;@u)4u]DD3@#QA#" "C@A@h(#)+ei05nOJ(j7(s-q>>x6Lf^I**YN]'JM>c4kiE.3.G^l8`tL5DX8i*%48v*?EGiE3" "U(cS7J?.'5:libV9&>h)lY67CMwCT/*KwVu$O0O0@ZZG32J:;$7/=GMX0:e$UNc##D####,03/MuwSfLxBS#.u1h8.<2`^#J:8Y.pV*i(T=)?#h-[guT#9iu&](?#A]wG;[Dm]uB*07Q" "K(]qFV=fV$H[`V$#kUK#$8^fLmw@8%P92^uJ98=/+@u2OHI.o`5BOojOps+/SxefLqJd5L/AP##x.ju5oZ%##gen8%>I.[#J>]BA8Dw;8'Q]^$OE9E-iaE^,'ktK26_ln0d8eV.AvH-)" "e2q^#WBBU%Rp14')Co5XCMUr.1$8E+Bv)(T,0'jZ,N'',JMB,>js%_J=G0#fJP:Q7Fn-)bb_J1o`i0-c:?#Yx_V$Q8QZ$wN8@TQ'L>GZ:j7@M6o7@K&.F#o`6K#'fBK-X6_s2d-3205oHgufv^FicGb4d_M@OXa0)6XKEK3L" "Xr@/LUi8>,5Wx88?fp58wiVD3n>j.3Th+/(*O13()MQ##Kw.uY8OPh1ZFs3Ma/9U;uTAO(Yn#ruU$GV#J,H:Upp9YSE?66LEDI=TZn#xMYoECl.1NP&#&5>#0JE/LQiou,<@,87'n>PA" "hDQiKRrd+V(4)##cT^:/x)Qv$lf/+*sj$bew,?8`p&$@+K`t/uB#$EFG]u8neF@):lbMF;#gLvp&-#T3n0#ZdtVfP:?>#F^'X-A*(0Eo:eP0Qo^h3MefL;*x>GM3.dW-Wm.6+G##Yu#OL@-#M,W-39Y%'-&e%'" "?7PBc0.m7'58:.Y&#u?r?^sQ.29$8kM(pt//-VH[lF3$mx43j@+0hrVB#vO:&O'o&/L;x+Auf=[l+-gWB0x>nA#mqF8Mx.#Gi)J+Au/uB#$8K;L-r,[&#KQ9dON3bnH2F(@8%&Y@C#i_Z=7No^I*7nJ,2Wt+N'GM1eN47DcNF>#(_Aj0H=^v-Ut;8.X5Gd3vf%&4" "Z;5-35NCD3/k5/(L?f;->1/O*g0(,)1[94'eRJ$l-MrC&k`lW-i*&XJ>([xk`N^$9J=RYG';ds--j>R:)#.xgnv?D*WKMwgd]tfMcwV+4&;L';W87n0ieYeu,0TEuq;BO;7nSe$q3n0#L#^q'Vjqt%.lYg)jAqB#BQ'T.Rq@.*AVTKpHRTcQqO]*Jq.YwaaawDBI$tGjdZ67=NN" "WS;[G'rYW-042X:eJ3cM)1#,MoAKYGvU5W-u:at(4[QZt.7$Z$k:xjk*U#H2Z:;8%c4sJ))3pM.)*02'J3?MDn<-Vi3=4AWt(:]QA#=*W>h'Q>q#:';K_ai_2:7Mh=Q3'NBOF2n3'451f'15Wf2Hd8B+" ":+Q3'<>A^PTa5n&$<.=1Ee(hL3Z7)*>pRg1]FmO*_>>(,`1cB(cUNQ&8$73'UO9:@f+mb+wZLHM+[Uk1qx.n&C1I#QP;q=1Q2vP3@S6=1GpY]#>Yqr$NV%JL" "Ren'&s3DP85Z&##$Tp<-HHHQ'cO&2)%M4I)A/v[-@CI>#d4NT/V7@W$(_Aj0j*am8s,#H3=6F2MVE8x,8&B.*EdCO'^e$IM4,u4S-3@2Li/?k'mtf&$ISW1BrsG=%Ol+J&YmTr(2'-?8" ",K+8L(bf4_H91*p%EbP`/9GKxIR]%/_bdKaX+IBu.`HJfLQbQuu)]qr$#E>##WYCu7:6^;.5QaU-kP4o$EX#8Ht7/hbAa#,DS47H'K2't0pEu?[G3'tvNZ#u+$Et'@l(5LEF$0%IFL#[/;Zu[$^iB841'5T=OGMok@ath@oY-lq;[0`b9au" "+#W?#v$G+)24br/k@c=#,Um$$NV%JLYr@/LW+5;-irN)#B>oW&-]#<-%w+1'c]<+3b]J,3W?T:%tc(T/cu+G4)?c-;cvPg)77t[$4Ca8.OQZd33POg1%@$EtQ>l(5P.AZNh'XfNU.5'5d/fw,U<1C4" ">ii&-q]hB#e;,A#e`CB#x,N=M5;nx-a8?/;XlRfNTQD15'TXB,3[,.)+4850&CfU+3-g[u&7dp0m,T%#xD-(#lmMbNnJXD#fkIp.YND.3TE)617etD#JXL58>Da@$NgZ@bPR2ZuXvET%" "pRJO'1TChLTRjJ8h+*vQ=hf4(t.)w&NVS.&(9s5(VualAdDDO',3X[#ajF@&(OWa5aKx(9vjF$.BSUv-?D,c4No^I*4qNM-%p)..E:2mL>-PS7LMtjYCU3[ullgw1O0GO'&2487JY?%b" "tv]hTF?6##9Wox$(2###SKb&#t73j1p*mV-<=@8%L)?s.GVLW-@N?EP*7P.)=8PY#eAY>#]`,5hBk%?5ltKH#ApA?/(]'O+[fUN&arbS7liwMp,rf&$xWY.q@$'m&23BkuRY29/`Uo47" "NR7*+)hA@uHM-?.a?W$#[`)0;7tVw$ax;9/*-+c426.)*L0-i1;d0Au4Jr0(?ptY-RHfS8iew_#$ltZu^rq,)E'J'/Zq%[u>sAjrNFhl8dv]G34Q*?5[q'E#G.,Q'Y&l]#KG>c47f7%-" "Jn@8%b`vIO_/E.3se>']m4Z##M]Oo79+`w,U5g`:L.m(6RTcZULbR39/oBfU+-p9x9SP>bnQ5&X%pbO-)x3=(MvNK@N8$EG'i_7MT" "v+qM#ReBtLg@RxktpqbrUv?rC*+8C8i&X1)e61nLx-$O*%@h-Mn?DX-xv@=(^()?#U9]nLYV07/qx8;-1FhX)4EQiKjh6_Q%Y'lUjVWn'S8dk2HluwPc13C=7SnW&F,B.*Nd`[%CthT7" "5%S)&>Xd--5.hk+6T9@Mhk^gL*mkA#/IZD-(76<-R2o'O4N:`3Tch@-q>)&.2V>F>Dv0^#,h]c2-JE/LIPou,ESXV-*/rv-Ox/bGmrfF4t<7f3a49>,mLREn7F7##" "(J'0$.dYD%s`cA#H(:J#Vp.'5Qi;=EedBeu@i@+0i%s^#/c5fa9RlYu#)G75ng<7%?bG/LlGQ]483LG)4DvT%.W8f3QmuX$8'E<%GO=j1ld(^>mUBN(QV>c4vb6&/a^D.3C-Gb%3jES7" ":vvddaIf2;ICg`auL(eTq]3gOs5aIq/Hp7/)nIro,?)bK1(;oKPX`B+Aiu.:a9c3'Z$]<$e*V-4-e3Juk:AP'$rU41Tf@E+ClkG*V[=g5%1)e3K.KfLevhP/Yg8e$D>#+#%m^m'W::8." "T#qG;U%hC,.e_F*O29f3nu_>$nH%x,A]DD3n=m;-aI00/TKc8/WlgWh/>.Q/OpjM)*j^I?M^Zd2GhAp8sxbFiV+cFiWJ,$.0*9l+Y/]7*_2//N:lmC#0Kw'l2I[OX^o#a=$'8h(0GXS7" "S-Q@-h'VQAwu)s$V$p[t0L#w&HsAL,2Q^[M-#qh=[hcPXLLsqe:erou:w,L/JP:;$D0LhL%xiI.9uYV-?/.T%E8mA#OZ>x#;&X1)%lp[tNgAE+#I[c;?u@?$E8oU+Uq[c;YUI2LNRt9)" "B.KfLKL6##G^^>$>D9C-VHH@.Dnn8%$0$N0r[5l1q:gF44+]UR32t.L-gnj'HZFu-9Ht-$AfSl')PncIQDMnSB;@p.0%hf)2>tm1>iu8..P0^+YhG'#'&>uuii8e$Brpk.D1g*#E)V,." "kqt(Nb$,G4#g``3I^4L#TkEl+['UfLWvNl(+IHh,GkRP/(krj%N);cY93p^+hJBM)_[Lo:he<9/96&$PLAJ.h(?p7/x2Q;%&W/NO&hRj1P]$1,^VW^$m'p_u*2r:6:>6S/DijB4Yg^R4" "5TTR/NuAv5bXZ_uD*o3+=?c=$h[uC+;;%@#mia9@.ku5Vj[i9oZ%##4*x9.GIgZ-t&#A#VRG)409tM(=n1eM5=`9.:#G:.DosY-" ";p,g)w_B#$1lH)4g)C<.msXq.0`qG3u3V'8#^i.LOc%/Lxh1p.OSLnu8_C(&L)G>#&A(v#L>)0u$oK^#%_%L#1]Nh##]txun-Lk+F)wILuu&[Gq;NIvu#5FNP&EQ(,)U]W]+fh18.vsai00);D3Zt$##Pg;hLfn/,MgxD'N/:#gL@^g8SMvL+Y0/@_N2L&9*=VURA$^WveiLjubC.KJ&*43K*$$C;.JLD7$_]pTr.CB,'##" "BC)?#w#9Z-d.<9/QM>c4JiZx6FHuD#&]bA#X81O+nT^:%5IL,3b2x;%.0ihLq%>c4B#4-*i`U_&h%AA457n2&5$0fNQ.h'%sqA[u.b#&8c5m'Qt&:u$.`1?#LQ0u$rHjv#I88#,j.e?$" "3u_;$8K$.22iLZ#O^9u$]PI-)Fp+',YK&[##ZT1*'QTm94e8n+[Yaa*W0gN,9%//1NB+at/NcN'VvD'+rfGb%f(YwLDd%FQ80MC$oj(*uGfGMEJ'`A$-sJ^+d[c_+:tQ@/i/CQ&5YR&G" ",,N[$s@kA+?Y%9.cIGC+(QKZ-%R]@#PW]#GXpYDIMP>_+P9cx#GnOm's7Ll%7#vtN_b$##$&>uupaUV$kxw%#n#]I*j1)W-I)>CdGuX58n_*c4ss*#PB5vS/B1$(+hbd.:h)m/2UC/i)" "t2P'&0pBDt-T.8'J$_xXuB?/MbKFp%3e;s%'?BW-C+^&Z_?<$#t7E)#_>QJ(C`:5/wAOZ6>Ho(<2E(a4dPA3%qQ)gLJLpk$6M6W-dka3/LwnL5/x5]CuwKP6<[W^/)58WKj" "R@)J'7Co[7&P8GVaMMoSL>&K>#^&O05oR0cM/gKW7MBL-)w1>X(o_`?#1%bf#wWcr/PYDW-VJ6>#B6>##UjxE%T6###K?O&#L####0k'u$K.oC#UW$Y86IXD#N+^v>%8-4(^?>WY" "ia*2$Fwf[-)o)v>#CU1N;8NP?$rO#V%SewW$_q.YuR&a-,)'*($JnLun86q#$Gj=$Wd1O'9v]&,74[s$Q^u/(7>&Z#dFB?+t>hq%oC&t%`d>N'jF#$$NV%JL4*GD3dePhL:x@d)XMYx6%(-?$PLd4(%/u/2]m-H3&Qmp/n`WI)Yf=Z,#Jp;-%DVo%cmri0)/ESIDkF<8OHMP:C;P>#I;lT80]eN3#dJA8YN4?#mk*j';u9Q&ET-)*Yp?l1ml]MB" "NfER*akojMUbP]-nwQ,4GYm^HI/r81j#?eumqbA#SC-61@h+=$lC6w3J=Vw@sj-B+rK?V9FJ05'oX.c+(q:'ud1-a*,K#s.aI4+3-hQ*1FXRW$(-Mc#6%:]5u8Yh3dOFA-f&[.S(2u<9" "[e@%#$&>uuW^UV$2'*)#GdF0lJP,G4EF(*4][_a4SwC.3nelv$@=@8%YuOv$)+%Q/q%^F*X;Qv$axWvG?;Rv$K`Ud.sJ$5J95$Y6dORX-eYQM27OYY$Y+))/FhNp%v=@W([PDO'4'D$Y" "jgoj014>/,3Q/4_v<^P/LZ;?%g/cP&xvpQ&?VXe#?LEp%3wP:&Dm$.2v[VTRaprx%F>OKLSl-$uI&d#7OjP&ig3T):0jD+VKJ'/'B#7^nF,a0L'>" "lc`E#9cuY#-c_;$^GbGuNX1_Fx5vk0tVQN'Ig/bHtQD%,`Psa*sgQ8DR<8@#Ll2b$WPY##`iw1Bd:(##puN$%0#fD*xUcT'+`NT/`]d8/X@[s$7q%M)v0Tp9" "Jn9a#6xH1M0[tD#F7YB4w+m]#lsB:%$3Tv-hHeF4Nr0+*t@SfL7-]P/H=[x6TOr_,SA@d)('[d3J[Bx7FBLQ91N/##j_3r7n.CR'+GxV6'T%iEXMG>#jl]&?v)Yp%-Ml>#.ih;$9-8Kr" "*:?a$4T%p&0q-B$FxkS7ZAI3'7,^xt:'>j'JtM=->KB40ssOY$.SC;$Mi,p,m6:gQCm&xl69IejNi(I5':vZ_b%$3g5x#mQng)" "6gC^#68hV.X9&u-xds`-%%Z<-5u]GMbvX?-$Ag;-)h(1&Rl*F&4Ml%uQ@G#$4U/VZHvxPQYqt%7WO^Oe'021BhJ]=h%Ga?ZSSEA6,'#(X<$OW@`&JwU#$Rp.F.wHB&,3HK/)nh%xplVs&#Eu$s$" "%0p8.SA@r%l.&@Qak%6M<*=CMTh>;-G`74'-ZA^#(2a'8kh%[#[ULhLU*x4&LJlq7#5cA#ZaKm/B3=&#IA3I)SLXR-J*eZ<1jwA,3Y5lLTE2-*_.=6'[0sZuZ7IJu.+wOY*;HLItAGv(" ")LjQ//f)%bwvU,);9jUN/uxIIpDY;)u87[BQLH##UjxE%)8[0#8xL$#p8q'#=''u$+dfF43c?X-$X>r%melK&fX^8/KJv1'LQ#]#%2k3GSk4#G5GSS7s6sT42sDu/h>$" "YD-t.QLUnu(VR[0&>K/)+34C/-PofLDV/2T/i)HrUv-F^?d))2pb4YIYjLeC0@#H`G>#KjE.3Z_[@#1N.Q@2eV5*k+)ul=^hA4" "+;wA4-l2%bt_NPoN%g1BYb]+42bMjLXF8:La,3.M58+**ZX9H3JP`,u2U`k#Z-qDX;BgF/['9'#CS)42S_d##(FWJ'+2ur-BL75/W76;-H>TjaHfu4S=1#?(NVPp'-^pA#O%8P#+U#M#$][9:h$#bIhtq)3Y@h#,cg#)%pq.b.5Tjw.:fujo7t%:'#Wu$s$/&3,)/he58BHMH*vu.l'iFVdE=vj5A*EY=7tf>x#`1tM(d/Z]4V)ZA#tYUSIZf'#BV(kM(KB*=-::m/=WF1%bfS'JI1IvG4DU/m&659F*9NYI8%?&'$" "ctr#&PQopAM4X1Bd#mS@gV@l@DsLoS#W_pL%DVrAat6x9'df>a5_r;IR+m/(t''_-aus^.Ao*?8wwn?9(IUoe.ZQ+M]J0#,R(dV@(xs^-K4n0#tlIfL(IK/LSIDM0'0&##&61X-VT+a?" "uc2X%@8;c435-J*SC%s$ax;9/Oqs>-Yo&+*>H,h1jE7f3OPWD#OJ,G4x2shLg-B/LaoJ'#^U>C+d?#t$U4*l%JC;D+I;j3p%`T_+Y23KVvK$o>w/1$g53']*bp%+?$JLwj4O0E;]huMjiZ#siK/DrkZi2&n&f=104-*$8GX$PEo>-WVuO/(8[0#'*2BQ=,f3%$EQu0M,]n$eKX,*4]f^$pabW-rbkwp" "b^+9.C=7s$uCJ-2FORs$D:uhg?vT[uj5ZCF&l'B#6EmtL*YEl*Em#]b^TxW-;*A#e`d9M'$<'w#.i)'MD$p@#S_$x-bD.+MR7emLxZ?>##&5>#0GY##L'B['7x4gLQROZ64f*F3QDr$'" "GL75/u3YD#)fXI)2E&C%UEW@,bsS/Y13K:HUMh)O-l%$><)D+x$1v%M,=#&l=RW$%3/Hx*3A)h'2H-N%Xb3" "L,5R*o.>J&4sDE-Db+w$RJQtC+27>>iwwT(88lSRn:JW$*VQW-GA3BKJeWDXp?0B-Kw0AX9)Uw0FKN+N)?-##$g=3))xL.QVKovOQvksP*<6E2wfo=#57@W$4f1$#Q$(,)2h+T.:2Cv-" "3Oo'&q93Q'<2_pB5f+o7ke]Yc2xms-P&9kLJ9MhL7#*D+HXHE+$GX?gvdSe$=).K1(QnW$tH.%#Dg6)*.Trj;)j@c=44dK)bk]Lp_%+.)&:x#/b=+.)A3Ob%^ZB=$6T)Wu%OPdMR-;.M" "D]xIFO%lA#1w5D-u=RA--LNNMdYE^-Hdv?B3;4^#L.PG-gX`=-f63O9xJr>Rxxc&#S,>>#+87<.8KJMFqL]L(1fqc$atuM(4(XD#'K+P(K?(P:pfd?$$8,xu9dV1L6$E3t1<,A#01:B#" "e`CB#8qdQ'_C;mLcb=<%[9mA#52^S'_Bmp0EAtFNb/@fQGjJ+MJ[AE+dZYSMh+x>Q=Z*b&RAR]4ggSd3lZ*G4ZoCp.H7Gm'*8_e$xiWI)$PkGMA:XF3WcJD*JP1?%?=F9)`g0.)q@2D+" "?DiD+]^AWQ/.p+MO+%X-7H:w1bamA#gfRc**P18.Ogi8/&^aHZ*wR3X4]SfLt84D#i+P3``6j;$-*Zb3+>:el+Jv;@^tq(E*lVI.S*<$upBD$$#iXt?]eU(E(:Bg/)iXi(4`/.)7N%j:" "X7G#$3:sp.NuJ*#x/2vBgs6l1qCn;%ZC(LPGP,G4_R(f)R35N'hl;gF4l-cp<)+FWKr`v1)`IXvB^#iH3Q=" "2di0C=LX69>ne2ixi`PFK%M&>t]f1dv`wg$0+dM/,x9.i`5<-f1'bDd(u&#a3xp(8wip$3*(6M>#TfLK/1S-A5Vh.;#S[#R>ojLdR@%bw>g*%>qVYP:U:C&" "DN/G[b_IT.]a.-#qc)t%FkRP/w;_p.ms#E3UqjT`%BqB#wch[G#:Ev6x)8F.#<7x0vsU;.,7]s-x@7fN5;ClLJEWVZLZ29/m3hfVPeV1Lr'onV`?4R/-ODE+f$H&W6[*gVG@';MhRv<-" "::/Z$u(F7#G.,Q'M0/%#=oAD7ivrKC,%.C>,nG>qVfK*X?@K]]`[LB&RXk[O#'t6ouuo#BJh;OA#Twm.MJ$<>0XZ,A49,P,;'V`$'+h'u$)T.)*M7%s$;)MB#_rHs-*dfiLwW*?#rHP3R]O%&^:/ev(^uK3)u3h_KN>rHbU$A/p=tX$]-wiL1-@_;'V[gs'gI(>M12H*VP[)*Hee)4WAYCj?2pHdlDN^#?n+G4-YOs.+NfmOw<$T/uFPS.$&>uuE9lc-)]]E%iFB@%" "FZobZ`6_S-je48M6_-lL,/39/S^J+4Ia/KMGS75/._#V/ViI`ak$[@HQ.MvUk'R3Tm&?`I34s'o7l=E^[#JN$q3;)RW%0<,A#/@PD4I2?[CsQj8.acRL(p(n;%Zm21d?R#N#;DOjLIslP&6hx+2kYqG*^Ro*&7n@TKb5QJ(9VW/2" ">c(e$_k4D#9Y7c?F>a+rrx6NQ7PqFEa=3?Q?0DB+e^_D*8TV>QfkR_&[1D?#:$_8/%]v7/[6vIMw*Cg%1dRt1NGf*7`%-YS7dC5^#D.PH81XX&#aq`PaH/->>.*pAZBR+W%8Jf&4u4%Dk'OFc>$&u9'#o.tS7>6cf(TE6Q9YFBN(j$0N0OU<9/-d%H)jb$lL^Es?#NMhP-nVXTF+5=`E#-el5`-+cnL_Ns$#R3n0#VfUV$dM7%#-5p,MbGAs$" "YiWI)+2pb4Rf.b/XI]C#D]Y##P(xJ1x-,Q'CO=j1'un$$icm#'G`k/Mn[Zx6_UiS%:Qr_,P4-5/qC?%kfa37/04m_+vNtL#RML]#5pq^uM]A9l9I5tQOIbn0rVVP0RUeS%]?5m:3++p%" ">A+:FvqsG]g7OQ/CNjd*e3Q2(Q'^:/xe1r)9X-0))jVnJGQsPA(L(]b1_Z[$:HQ[7uDC>$KnW9%Y_;`53$I<&';9Ygq^Xj(fnDQ/5rTN($jqPMu+LS-Zgi.08Ufi'Vh$##A$)&(>LugL" "B&qR/D_pfLOII&4h/qR/v(A/L-n1-2NnFIwD3*Mc##d?KJ(vAYc2J+65/4DXI)[(sM0" "J6X=$FgU`3;nC#?PX1*4HjE.3Dk[s$fg;T/@J,G4#MsAFYC.$T?RP@tTGS@tevasM6^e.hj5fL^/PG^]S?q7JRCe`E?(Vl/:`Yl/ewf$Pd=eM'7h[i#.]cSDOsT@t_0?-JgTV2fFjL>5" "CqvDK.+CJ)qR-igqHRrubpBXm>1gYm$RbOodCP##F.YwL;fr:#Ee[%#Nc/*#Hsgo.j>%&4F-p8%7:*M-g*k@:MLP8/lD4j1)t+K.p6$`4_/._,gCF.)Ei(?#v`XSGMLcKa2DN>HLo@0Bjg(;-g01gpmP)CL=Yc;EOA@%1OX$KpbY-Os?jUrU,V%v@ZR/u^KrHxcvT#w.TiXUgoP5%k#gas_mP.##ceYw5cJtr-cs,<." "tRt<6[[g9afMMO'<7Ha3v9p7eL3^Q&o;Zx4J_@w#9WlE7o&Lv-o5@^$aK?W.$,P:v`32#P<9#)3:E-)*LW1,)f'4,%x--ONIC#uo##v*FI%" "_$q:#mom(#@->>#cr2@$'FA<-SuFo$iekD#-Iff1i%>c4D8v[-K)'J3*hlf(f9_Z-]CI8%i_xjK[[jv6uU>c4sVmX1Bf?MT6Kt[,Vf'716`[h(h/Br$GY?%bZGI-)@9ax?n6F:8=6ax5" "DbuA#Z?Ig#V.xJ2L_x-f)T/;@n8%Va)*4(DPjLk>L&72l`^#w?uD#[eX@$ppVsudRL3;kpE(3?t0>$6=<5&:=I8%T3&e*J^KB^EZHG;m:u.UMwF%XZ[of%,7)U%N08@#JH5j'>LeS%+[Zl1CjjG#" "0YN?p*HS]:ILf>.DqCP89K?UCca?.J:Z_4J/.ltN+]VSG=QH)F=xR]['ku55/*Px6*/1_>$>[-_#-`MouN@`Q#*v^e-N:kL;hL`;$" "57`h3.+1^#,SAcOYm('#1H:j056oG;[8DG)OA2<%M;1]&+/`5/sk$GX)=K[>+o5seF8][#R%n0)$ix'41;MD)co&/)WQ`x.VIvG;>DQk=,7aW-vh)f46`j>5Nu%5D;]Dm&L.N'MU@9C-" "]?KoL`?;,)1F_0>^@[5/(5[0#it7nLk_(u$cI=j1Ci%&4J]d8/Y.(@%S%>p:J17%-OvLG)2uWj$ToQ8LFUX/2+5eW%9%x[-=89#,(A*F3q.Q##+)=o7A=%<$&]v7/1To2)_POS73Q$ca" ")AVq%Mw%/L[_v[)1&@%b.l4AuHa7:.]%R`aaI=Q/h6==$J'bt$%vWS77GxL(&GF+*w=Ob*8osILP^S?#7#jZu(Sf@#5C:B#$wA.&`o-x-P0+3:(O6$v/i8e$*Mc##m+3)#`F<tq^#O-BR;RPFSe[]iXeEX'1p92hlSNgAE+apo7/a^O]#2p4@'bb+/(ZeR<$6*no[qq?1M=>U1Ml0S`a`ZAr.@6##-hi<%U7[0#avK'#TG1@GC5G)4/vcr$CH^@#,5Rv$g&?a3.PC%S" ";:mp1J4@]u2NVE87mV)4lKxnLI_lS7#e$YYd>h>fjqBj$S>1T2&idh#WNc]u,VoH+/^(B#dS3N0_HDbA:lD)%rNHAO0T-##%8cY#T6###'g#H.jAqB#WbHq@S%C^#A(Ir@unw2LxgA@#" "B.$lL,cu(j%2q=#Z=9G&-g-@'LDU/)xP)E-6+:%/lde##-RDREWu$s$TekD#$Sr<-#D&n&O.9#oU3`H-3Y0wL7;#gLce6b%S6[0#-Mc##A4i$#9,>>#@BrHM*6fX-K1*(&1=C^#'tn+M" "Q_Q##LW8e$.CiT.OM0>#5N_]4$>G##&9X*%L6a-$O<(v#K__jt(5[0#>aps-l=;mLYLo8%H-p8%$3iD3;kRP/jUKF*DxXI)$uh8.6WPA#AD;-*uKU&$?\?EE4;R9U%Tm_u7]ht89:JQYJ" "1sA]Jn29dOM0,l@o7fS'JI^.]JY<>Vr%wg66'UUTG,ib=>B=OYc65w.,;^M.<$fOkr?CvR?I$meo(]ndY#W/HAY#[]/.+pm4A):pV.n'?vA*]rB#" "mE'>.K)'J32J+ed4i:8.KkFqIX#h>$+j4s1VK=YmPa.E76S6LdZS(EM1+B/LlZV_#,Yc255Yu/&@o;fnKYVqVq3n0#9m+REafUV$^)V$#Uqn%#nd0'#f+vlLEKxV'`ksJsw*ZV-4n,/(" "*9d/(=SM_&'8tM(riC3=B'iE4k&B.*,MJ4$##<;.2.2E/vLx`8%#>FAO6uiWI)PGUv-0S<+3?_#V/JI]C#-$x/#SVO&fQ0r3TF%'eO]brCEQ/" ")rtlA?xaU0r1tLBXwk*faRALVoZCL#nM%g1.noT(;90ac`(1v9iDp%B#mn]0s8d3bNfce`*6g9<-;1]gsUG>f*l,>LM^/f)*c9OA#3c#<%tThhL5bi8.Cc*w$&Lj?#ax;9/HlF9/YekD#QV>c4t3Tw6K]B.*eo^I*wV))3f]6=.x1fL(" "&7^N6l(MBSOG]>hr`?ODq,97;7Go/1eNFq%VM*u-+3*E*nOB6&D>gT&^Ueh_X/ID*AQkD%+Bx;Q-Ha5(>7FE&Z;([-`vF[0swraO-$_m&V>^p&;?vR&MJ)<-G@f&'<%A5J2/TU'nVVO'" "IB-5J#Aen&m$nK(G#4s6#h^404=s;$9SmO(OYa>25O-.M^3@/vE:BO;#/t3;@4nb%%&4'm(?-B*'u$dfeD*cBB:%1TWjLDo*w$N63-*90Ea4dm6W%MWPA#ed,nuOFu%@;>l,3Ft[[#*JuY#2Yu>#$Lv?,M2OgP''^E#?/#b#umKB&4w3U.2fUv#Z(ffLT5YN)vYvPTO55cu" "7Hk`,c29?Hk(ZLLGojhu?fi=(_h49%JFR8%:7[8%4u$s$VV`p/#%DNIYUE4OJPN>g&W)t.fnv>#R>0A$9%`v#IC@8%h?N8(ZGD,>D0uq;-WfB;xd2w$*Mc##wYO.#]1ra%Pc[:/'TfF4" ".48d;dL'N(J]3'oJ(XD#;_#V/ilwU/O-Hb%D,D:%-Q9.$%BqB#koXjL>2V2:>`CE4[C[x6kQ7lLWxSfL7FEN3ml,##uR39/P0U:&R:X[N%R=MS3w=/&='i;rdXSBBC$pMY0m^$#Vj=.-,jILG00U%'t&eX`sxK:Zx@796K0@#GG,p:NjUX8V*@n;" "SJTn0#X>`#s%Ep/4;@I2<(o]u31t3;:YG,*@-iwD$>kP#31'j:f$VB*f)NfDZ-o),##)UO2$I%q:#6,>>#kt,,GD7cS7'K)m@C8.#ETW-:rE=(%N[L(Lov[-+O0#$1Qck-:-(F,?*vM(,p^I*S?O]9A;Mw;89,[8%A-re32Zr<1b/aC$m_>;-L@=X(JG:;$;EMM%g_fi'(sq%48<.J3h#Rl1$F,gLG#YD#kDDD3]77<.`K@+4" "7fffLteZx6IS'i)>Ac97-Y3As(G^V:5Atu5IbI?nUXkX:i`Bv#^_b<6D[d.h-Qxs6-Z[#ijbmg33'd)uJG9]T4=n?83(9GMZ=Bg2+)nr:en'^#q^Z'#-JE/L]9]f1m_(/:PD'N(hw%_S" "?lh8.V4i?#CT(T/:Vd8/K)'J3%lMDdCZBS/(H^@#DRbi(8?a`#X.g[uhdZJ(PKKY$JErL+)*5k3GU5`#WS#6wT[%" "OGY##4(,87w,ShLFV7I'c3YD#O,:gFvsw`Eke'^#HfAAua55o;krDO'YhPB#g'X1)Mti`@pnB^#1X9IDIc0^#A5/Z$V8f>IG7L<.,P/%bVEdA#hIij(xm.>#uNYk4C4XrL;8*>.N&)'#" "SGc%&IVFS7>Ri2MN[_p7lAre3hcMD375^+4]77<.INpf1I9(u(K(L584F:B#b@efu5[&0%=^2edgk'M8Y(U^#EWc3'wE/j-7d,HO9^CD3X^388]f'^#Plb_#AnaT%wBQC+2=%v#K;)MK" "l`fx$$4;J:J+65/MfXI)`R3]-(csD#uTJO9]SbA#?EbB.tA*W@trF3bu[NT/F?)F=&8P)4EGwRC1P2]-7:Prd+*Cc`@t;>#9t&CLCLvSGqY>B,e*@_HV]-%bYmE8;<878/m5I%fe0er/" ":f*?83bZk%NQ1p/86`7WLds*YDD#?W8+nDLj^XPT'@FqT7D30I4DLb50x(GCHNjH$0qbTk$*x$##<]+?Ic3e##IXI%#jd0'#,Q?(#d'suL-?5V/n,wD*;]Gs->oq,N" "KO^C4[[;R*Diww'HZ_`3_I^_4e,i*39aQ(#mVWI)C+TC4m*ZQ'._5GMwT(E4R#QA#6H()3SV>c4iB7f3Cv+G4:p?A4WF9a#nVe)*^$Jw#-Ovv$D+p_4/v)Qha3J8%fdF`_O6>#du5>#dC6>#9+`w," "-h5C4lpB4-%3&dMaLetf+wt4:31Y`#qaR90NIaT/lXQ@)>`Ma,qx8;-RQjr4XuI/Ld?q.CXT^`3KlR_#M;^+4sf6<.peT,2[=@8%@I.[#xL'f)hu/+*1D]/1wHuD#-Tg[#YCh8.&gbKM" "1Xv)4$2f]47YucMe:BY%M@`[,]&PA#lZ'R&Kw&6&Mg$-)URDYn4rB[81YVsAXl_+*vdM4B;w4V5BCbWhO1A1u?cfS5)6u9)F_&RCk1.N:8qJUT/*->n&2MO)vQbZ#6xUZ#deAYcj$N]," "Hn-G*w=_j(u/JI*dgDi2skbdL,$fH*/u-,*l8C0ij%J4Xg7Ex4NlM`FIObM*0CkaFk*7-8peZO2Su?M*Z?MK(ZQ9u$l@OfLrwSfLU$WV$)8[0#t,>>#t?bCMhNgk$Bg:9/]P@&42+$P." "stC.30Z,T.m]WI)->pV-S6tgl,91#$tB:a#Umf;-%a$W%-aA/LhTILC,U2G31aFx%Ra^guas==.bcrg(s(t.3hKCP'k:8T&&OSw#vXIV8-*Id)j)Y:Oq'-_+Spr.3Ifc?,Nuk@5t9D$%" "kana+SB4(5%_GR&B]&K2ZiX0L,VNa<&c)c+X`Nn)KR7s$<9uC523bB,_8A/3M9DDUk+Tl2%bfS'JICxLe$K/5##k7ig$.)f&#%BN/MiX/@#0q1,)X]$7,xAt=#)Zt`?D4^E*a)9o8(cL'#2Au4S76tCE4+;o8rFHrB>*C*#Nt]?0Xc7C#.NQ_#TXpQ*,J5UA" "c]1C&L9Tv-Nghc)qfeD*oh$],o(TF45fPmk(D.u2(q%>+*XS.U%vDhW$:T8A,0=hp7" "*(g2'ORlxB[Y@-)/2mW.(T***xBxJ1QG`>$q2nM5DDd40fNu`W(Q-a#N_wW$%;k*4Jp%YSgh$##VeQ##Tb$##G&e)*]?^M'vS5FYWh?lLu3XF3;o7T%?T/)*I>%&4SsY=$uV8f3+g^I*" "H-p8%v/YT8llPqT#-BQZo3:P.JRAvD&GJ&,'#lCRF`t/<%$28@6opvoY<." "jBFA#&D0N(0-k-$Z;%6/%X5k>WgCT/EYE5vL*KmZZC&tuk`wj`WPu4&F(vl/1-u8#X@=gLGt5.%S6[0#)Oi,#HTF.#gY$0#<.*xBfuPg)D.[s$*_j)4l3qA$+Q?T.W`wv$&?pv-bNJ8%" "[J@d)p`[D*?@i?#lwkj1w?vr-hF#v,/e&g1%GNG)ig'u$Pvq%4TeLhLgo+G4EjjbNSe%BPJu;9/Rf?K)aK7f3WY5<-?-J>-:4xi$V$w_jBs+A#Mc[;BWv7x.SXd[/v0j.ALq,/,C8O:0" "YrrG5DsQI2&uP.)FAke)LhN9%vnf9&lKT5:?Of@#@" "jNfGG/[6c*-+D<-&v)D@u$ToLs8Mu$I/;6&ku2p/A6GN'EUa5&ZKT7/euC;$bq(F$JB+d;.'MLgWaG.L==e8%YhV20D[eW$pD-*3O$f8%wk+u%pb=gL0CBp&G-X=$ERiZ#@l1v#P>#R+&6/PDRv$vdm_>s?C@.dM8f3H+7X1'w3V7$HX>h%31'5l%>o7l-$p'uL8]?]A%rHtt$&xP3'cQSe$SK/##)KW-?7W-dttw?gL)6A:l?Gg=#PfjlA7YN-)I9pr-SoIfL)U#gLZ:;8%,YJV6kp^W-" "o:U13+kIP/;JjD#U%V%6UMeD*.Fq`Na@6##c9JY-#+Lk+p6NH$kIW`#f?eh(ZB4V.KScF`XK6g)I7SGV,AGfGg5%[#JfUxPpZtl&c#?ru`,r:.ggbx#ar5]kro6U#q++T%7q'8,1bM)+" "f:C0*?AbFNq5v3'8w+fu'h>J)Kh7.iqfE>,_Kqo.Oufi(*GKB`SAX>k-^,p*%bkfi'lH*20cHCFeZ9x;-[qT:^'%ZV-#F;8.tBo8%k.ca*iQTQ/So(:8pHCE#-PNh#ZA74'&@_g1" "GX3/U@@%P'9/8b*tQW,8$)q3(8vAg4s.5Y@a5,@#slZiMP6S3q/4K-)Xf?%b+:hB#WG9J'P@)?uE]ub#l9M)+@@s/40rACuO#[Y#DQk7IZr@/L0/V`3VB')3wkh8.81I20WEj?#`qi?#" "u^/I$owkj1YS;cFX%pG3cA#C/L.7x#J0uJ(8oR34;KrL;`Z7duo0@B$v&Dg(rG>B,U,5=%,qkx#P6)B8#-EE#ejFQ#Git6Lxh0]Ow(3/L##'bu%@IF#gL$7AnW9s7.2v^,*/*#I" "(hf:AmW2>2%Gch3W7Zf_ssHxK:Eu_e3]:oDS8kvR0[pBxqM#eV$9?pn/%t[K)MS0xt:*+tYi:&##sVo9vY>IW$#v7nL,:L+*@Cr?#Ws/028Fn8%GPF/MCu;9/hL&<7C4NT/HM,W-qlhe$" "J#[]4J[R1Mw-L+*orGe6jt=Q/1@?i,t26K`K_RA,A'D:&)5Yv,cHLXLsPSd>>#6Qv$5jr%.xb-x6xU>c4v'D.3jpB:%n3,W%X3U:<2b0o,[o/s9MFb4'Nd1b,E2Z>-A9s:=UHWu$+mTh3FAZsDJiK#$" "E0>PPFSD16$$R&4'P,c*$M0b*A0q5'15-=7+OjO59@2>o$.KIL(njtx#b.FC=KuL,NbfprS8RO8&sX,87A)'##Zax9." "Gq[P/QB%:/qwkj1s:Rv$m&l]#926F%dov[-[YWI)ku/+*LwnU.2r-x6J6G<%Uw3XA[K]s$#T0<7sS(h$_Pc)47%x[-^:/T%4a[D*uS-v$k&B.*t'[>-Ag2s/JiqV$NmdQ'b;eh(HkMj9" "2hF^,cY;.Y%/IWDT$CFW5ha22H'S9.79%P'-opF*.r=)4r8*/Ld7%[-1c:Z#N`&i1?cZ8/;Jop0N&LM)$RhL;-:]p." "Xk6J=4p&@B&>`^#WZ[345FipThCYnCq@mx6%/NwSO8f5Nm@gG=hMn'$&>FM(wNbw7/OO&#D]458kM&A$PDRv$=?E1)NDn;%&3m;%?;Rv$j9K;g)']t-9d?['1VKF*@@ni0BxF)4#,]]4" "Yp?d)4`ms-uxDK;kP1E4[4pL(Xf(T.nG.)*;`Ys-*c7+8Mbc;fT12&&Y5###>8E)#?->>#o1TV6" "o^54iego8%B[e<$@]WF3tcMD36cYs-xm;hLLMp.*EU@lL.4F`#;p_/1n,Y,2p;Tv-msHd)8`Ys-j)sHMmX?x6vU>c4-].t'vU]L(jptX$sOtAunlbR0>S9p7%r3j14=^Z$*.PA>u@vjt" "L.oC#'S$6%]XGsSn.LQ4Zb2(8)9V*4&7X1;;CZS7E+>C:EI7W-(,*T^gTZ)4%gL>$Nt*g3KdVa-R.;aYo%I;%p)588xMF&#sL'^#=h&9.n&U'#t@^)3ITR12tLn;%Eg$H)ZH-)*o3q+M" "D<-sI*^/]$c,g[ug'1.).CNl(&_Np(QPt(E:FGb%TlX(seF-##`(Aq.U)wN+ILnGHTfQX.q#acuI01lLX?e-JEiOwTZo(bRl5Bm'e@V&04`p>,,]WF3;(/+/Ne4D#47:d6X'/W$t,'70XSR5@0C4QPt(E&7B2C:3b8.[Tx7/FoHX-J3b%TV####'&>uuUdUV$Ug1$#GY`O#x:5G'26Qv$F7,Q'`AhY$lo[:/=X^:/a56N'wC,s-Fa[iL29`T." "c(4E*pO`S%35Eh1-lR_#-[X,24G@A4xH:a#+J4^4UH()3HiZx6348C#*Ij?#+j+G4(8o]4i8``389ZZ$H'5N'hCbI)^%#,P1v#0x?s$7`L;$JAG#%Z=,c*@Ca'4V.wB&7L39%0JuY#HY./2[ZG[>Kuc_+;9fa+YVsa*9CC^=s9+9%0`:Z#vg.],odpQ&V%;q'MC@W$J0OT%m`q&=C:mY#" "J#`3EU.`D)o&&@D`+8L;)+p7*mJM91g([0Gj'Shrv#/DY>#0fU;$Zw041Mj.j2k3=t$b)F.D6xQ8%5VY>#LqsP&-*Dc#C[YliG`j87(WP,cxX#H-eoKoX`ZuZqhSRs3%L(s&e8/e/Yt1Re$`.?uRt1E9KN#K@p/Nml*r$GJaS&0+K4l4*As9" "7####1VjfLe,B/L0)>=%I8W]+4fju5j,KZ-WR1DNCZIb'*KcrH-7#H3rLvwPaeH##$#nILQlK##w[5<-&cPW-6vG+>#C;.JLe=U##r4`$'" "gC)?#sr$TINT9N(cu+G4&=Qd2)lcw,jk=6']98wuHZ1G)995O0VDd?$BJ,]u#9:P0MX@@#QW+A#lpPW,tC$##x>ap'^*[##=Q?D*nsx+2ESXV-G0kqK0h6g)(=tH?n?lD#]_G)4hbtM(" "GNl'@jLN`#O$#Yu[0YBA8Dw;8JG3F/C>-H+,6`+MYPU=#%VclAq@YS7:7clAt^S##Kq+Yu3CIq$U+kZp;ip?L/jpquh+`B8-I3'5-`(FAV0N?REHU*#f;d]4%-YL:,.VT/=9#p%)0ihL" "G*tY$'(]%-F9@['`x;9/-JQs-7X(hLifps7HCk05E9[Z$o42O#92cTr?-g[uZM8L(p`6fUp(>/-oML^uL&fp/OA_M#=S7U.i&-n&[auO-W]=Z->5Mn3J?iB#KeMT/j:k.),FPm4nnI^P" ">-YX$mBp34UQ@_JsL5_J`O%%#:K9-m:)S/L:hFJ(8f3>5c+M]=)6&##TFq8.[ge4(]u_8.4jWI)aMYs-s?$gL[Mvu>%,a[$`bLs-;va.3YCl;-Zfv@-%5cn0RjDE4us3-*s9uD#g-v(N" "/>E`#Z7g3NiC3*%fP`V8D&8/Ln%fOSKqMd)%T_QCRNRg<_gmnhQpoKb'CmV-)>2:D_7W58fPc8;VMlQV=n'/LCAS1<0v6n0^+H`O3d.jOmaqOCJCQZ8,kCo0" "L*rp/Jl$bHCW,1M&d$jui4.X$'bgFVC,dd$gqtr.;ViB#N(8>-XIVS%H,###pb=mA:#XV-%NNcDXT^`3GH5<.ogK>$vkh8.HweP/L5l%&rA81,1r0DNC4MrAj.h#$/&EG)iR,3Da+mp8" "D&,d3b.-o$6[(f)6V]C4S)ZA#a_CofZS(_,er7-)DE)n',(2w,2x^7fV85',hgb48ROjo/mDX2,TX&50b,4%$463m=7$V=f(Klc>;9@uf7`Mt-encjL$-D#$,rc(+D-6>%$dC_&f;5'," "f<@uQW95)M1-W`+&RXjLMBfx,U#xbLP/0JE/L>u###Wb8j0n:gF4?W8f37eX@$?,J-mBuQA#,=eCVClimuxK)g#o<%'VQXWS9Xa-B0$Wx.LWhG8%" "tqYX4$YtT#xlx+7Yd.@7kWaY#9s-JLw#H/LY+pu,_tu,*:2Cv-=jQJ(j0w;6)_Aj0;(m>#(VTN(B6J;Q]RCht6U9*5w%6H+Xq_`$.w3V7ThbIq3MaIqj3j`?).N)$hJ9A9I1U^u+3Vx=" "GG_A#P2]nL'a88%EA.JL2JP###On(-QS,<-n0OR/pxJ+*a)YA#3a3gLDceA4ef6<.i#[)*" "a^D.3gk;[066oP'(YQH3M;A(4jHSP/[j.gLS;MB#m4K+*1rSfL^h?lLhx`v#gR+T%wfkI#CerV$40Q0(9[nCG;#NB5i+m=M2<6JM>Zm855#>>^xkBt-GVa4xfLXWcx#Pb.%t9*iZ#pa,T%GwJuG9Il2(tr1?#Cce>#`+4FPOE/+>YB*54Ww9q%" "wV.3'Zfv_P>nw[/4am_P(;SC#C0CO@Q=%6Il:p.jaRLMO&CI$_39GVK(6K)xicx##0GY##e_lr-&a:D32@YY/" "n#:h$rq4D#b/v[-<)]L(?F*?#poXV-P+Kq@q%g*%7*0fNLR]GV^?Pj0cb5'5V2UlSt?XB#%_lp8`**fh'F,cMqR8S#mxW05W#xd#'P5Gi,(_>$obT)nqk>;-&P8GVl%0I6%YP`u.Hcpu" "P-8luHbrO#U;)ku75]Cux;dl/(qkU$V&Z<-49s#MRR_e$su60#2sgo.-$^5/J^D.3E@%lLa0`EN%Q8f3A.ikLmc'b$74VPNCDMXG]%V0HuJRW6Hxc>u;:a3E" "cepS%I@Z)>6u@U+LB&*+]bps6H()Zu8#@M=UX7293DsrU[nOvGZ?gUG/dum&'*bZ#&Uk8E#a^_sI4$H=mM$h*L0&a+&`Ok+>$F?#P+SJ=/DBC-vhF$'TBYc2iH%##*c?X-GOFb3J?gf1" "]ucZe+I1N(j%2E4k&B.*Kuiq%=WU;H6TfI*D7H>#Ot]=u'bK*f'^#,]JDtr2IlL;Kl'0dWe`*>(t.L&A3/LnQE?#Y_.[uGLbr.lFl=#Qoq'&" "G3GY>4aT/)70A>-#E`x.OR+onuTl>R+&U*%S6[0#t]wM(.$Imi`X'mAl0xW-=wuE7rMCp.Q3=&#p79u?2<]@>v7'#(feCLNgAE+xUkA#*bTgL#K?uuEhUV$B;4gL" "/V>&#,pm(#?G4>BOsSk9=VbA#Q&d<-a+-xPTwo3%rl$SV#u,Z$+uMQ&4c[oqU/O_OcbwAM?7;J#aaPs-Ej4u*Ge](Ba>d-@uuvf=q$904&#VC,+#AZO.#OQUV$->xI.U/stC.3qYVO'?K@+45CHC#m>sI3w?lD#%l2Q/.2HwPB;R/(8)O1FZK9E5+Yjl05_Ld2V_Hq7Ax_c;I:(a#Cd^,2Ic;C,8-mA>" "t4NP:dPf:9>[45opp,k0@whI#If-n9^/klo_p@`&V0MiQ.#'OJP2V607(>q)'I*x=$&6*GOr9d%Lb49R]@bAMN)3Y72h#$.DXI)U<=W-csh((pwn7W%b)EG*a9SL#" "g&RA8aXYN'AlGV'^&>>J`06<8>JWNDq,OW#[V`H*go4h#dl4[,2G*N1g,VP:)oUR1sL<^#HYUHMZc%T%WO,N1lV1BL;AeT.Qp;H6Yh7s$No'>@:%_S:Qo$N)0bowu" "Dp(cFj.F=.S4Ye))jQn&^mjaEh]ms.i>6j:Z7ou.81v_+PZ5s83Z-&##YAK1O/:/#6@'02kiE.3SLCwgoE->%#oh8.hp?d)$`TF*kC4wp3H+wp<_2j1oB=m/6T4,^>@2,&5+Q@;6kl34'9[Et$_oTA?uf2,5_a=U.`jPj'ENU,)8*0X'>P/^;cMr;$r2a$%K0>N'hRpB+J:0LE@E3iH*gQ/*cp9Y$" "?/6Bt@^[h(Z7ub'^a0^#-WF;$2Mc>#'w_v%uC.tHC*^Vm+<46/TG:.*EcY>?7%[#vMEa*AI*t$&[Nm/st0`N$/jn1ML=A-Bqt0;*PZRUG](:+Htc9MEpOC." "-`($#wq>v$8C;a*HsZq.]S8f3(,j4DaJSF4GLm<-L*4A'4ZvREr2.?8*K+Z4XMNH#W-E`dC&+dqC&>^B9R.SLDO5Ox(<" ")IX2'O5###*[qJC70E%$QPW]+rgai0Vh$##UpKB#%dEa*2It/1V)ZA#pwr?#>V&E#J5)E3.ruo.l`,r#UjE[tD2*[cRXIs$#D]Dt'W(e,Ac1p.*&K7cwYl-$W$G@NGiD+V+uK#$kBn]-" "CJi-66([D4lFDj(7?^k4qrJduT=*>.+i'PA311^#FiGW-#M&q^oU+l$*Mc##K_R%#Je:t%*2tM(#Cs?#A));?H^BN(phQ5/h9qk$G=g;.8P%OrdL'N(j'U&$MPsD#t<7f35IL,3sZ(N;" "7,=ODqp#/LFg/^br1`XKMaAG;n0%X-EM15SdnwIL$'VY7%biW-s9w5/CPC;$iTPZc1,sIVh4H##(KNb7lE(/L;nuE7ThL7[r3;L;:Xv=#adBq%=@q(E>a/7MXnH>#TcjE*t`CB#cHf.*" "h/+jLgK$ca']%3:^R$j:T+WE.i(>c4Z2QA#It*mL/-8C#$OJw#$`^F*ZHuD#3`<9/d@H,3[p+W-_*[s0#Pr,%gZFx#i`_^#nsFU.MSY##cGaBgLxD2)-8u*EVdL[Dv3brD5OKs0<`fV%" "94.s$8N5TYY&iRElJ)U%ss`.34>:lB[YwouU%]H#+7=*$&U.dueH0s@fm?d/nbMNSm0%h5v$a_8V/=p&+;&x$;S5#@h3B=MQ)k`64bG)-`FP]+PA1@)H#]0aT#xn(9#kW@4V8J&4;" "5Bo3knp7f3d$]nj63rpj/C;/#1RHo$#ba.1p-#01>018^,N3Z^)d5EKE;#l;S*X5&r`d*3-36mX*q52MuZ9(4Taci*gJ2k^^caT%U0;&.3K=D#uU-SU*iarAx4XmCDSb5&041F*d>8>S" "q_E0Yqu:#.@Lvf2rNm7:pPI9C7ca,$Z3*5#YX^`N:5p%#Y]>lL+3#V/EkqR'(QtV$07$`4?;Rv$Y^D.3f%N,B+4dcVJUaN`*g" "ne5X`#5Zj8e$/l:$#l,_'#a,>>#X02N(EV]C4max9." "lq.[#T;i`3_gp_,XkZt-_?rJ):ce*3NU,d3*j,*([5>>#+=F`RTX&[#%QDM0YH7^K&Q-+%E;;-ExmUBS=h>K$Kq/N/QTDA+;s$;%3kZC#qkB`a6UAK)w);;Px381$(f1nWdRJW7Uf./Lu,G3b4]8jK6d1e35IL,39:%[u.8?1M8gAE+o^fx#2D%q.aXQ@),5r<1F),##fP^-6Ds%.6=39Z-bK#fE.1-?$ap/%ucI0=1%o9B#SS39/WS,<-" "8?,1NXlj.LCQQGM(7QJ(1d(T/^R<#.SC;mLx0(TMU>@?$V@kB-)rg%%+;k=KgcfF4p+dY#wHSvMLZ?MTZvV8/NOL$$NV%JL/JE/LbUU?^k%$##Tn@X-.30r.B%'Z-0_c=(SxolAeH]X$" "g7Eh#?7AO9Q.3@$MV>C'fU'mAb?A=$#-5wfVl&-#3lBw/B_UV$qrC$#9qnr'Vtmq7QRNpBc`gs7cns+jxYkp7Dwbxu054^#A%Nk-nMg=:q3n0#H&###Pd:RW((;YP>c@I-2-e'(Rqwjk" "(&h##AZv%+Ca.:TmnG,*tt$],>J))3%[*G4PCGI)7x68%b;qB#HweP/nqkj1.P?W-Pvd].ktU91OlAONM:oP3l]8v9Pb./:34dT:gF(?&XScG44G]C4,3/<&JY*/.qsIl;4K=WAD997n" "ew,?8BFA:/,MN024OGR0PcSB#7E[S3f31?%PLUj(P=+/2qSv#+osZ/##6sA0M+HuM(nw+gL>cv)4+gB.*c5J5B82/=%qH@X-vx?C#fgNv6JZm3+,=ucu;oIH#" "3jDA=O#Z@CnGO._`OmD>OdJ._(5G>#WtOO0h7<&Z.vW1u(x,V#dqbWB$f=Uhnt5$[)Iou8?@dQ(x5V%nPE5&FeTt1w2m34Zi)HOWk5-&HL6hF?s/RW+lj]bsX->G]n1d*" "Jm_N0$d(T/qiWI):Q^A=`W&w6s1'J3:mnD*f.K#5N]R&4'n6^$KNg@#qYVO'WCh8.J-xP//@wmLQ#lU%KsV./u^J+4XS-E/xD;MKjW/[#P_w<$MEtx#v.Oi(994',ZZpr%lbcZ,uh89&" "`,MK(M?^M'x-_AR^AUlS>WlRK/[L*4@h7DEetEdE0kR`E36Do05oXC.M-'u$'rd2(13qE@rp5r%`mvE7Q-mgL9vg^+M'oS%dA:g);VDqLxpxjLCn_<.xVii0gi8T/nU,Q8$/s<%S%PV-" "(ZYc2Rvs+;@;@K:;a21)9@&s$<4i?#OHOA#Bhp:/??$)*`-%##M'As$,R7x,eh$=%[cJD*n0kX." ">^?\?$FG?p.;@n8%tPP1:8`0j(oHRA$+<4euO>huL1Q7i1FJiB5t_,T#+=`T#qkW1:=96Z$U2P1:L?'5qU30SnEC=/L@tG1GwAwqA&g3gE8O2^OfA2noJnK*>tI]L(>?Xo(tBWP/?I&q0" "L,[TMu`/%#MixgOV.Dl-P&N3X=1T3KC;cA#PibV%sg'u$MujOfw*[9E*PWv-DTQ.l029n@+KuL`&Z5oJAR.motrM8&op*ge5uv$p@xaY-F9/e$vTFaI" "K.Guu#D(v#08[0#E,>>#Gu$s$ikkj1tiYX$JUP8/JIBT%HqB:%`P&J35<6s(tJTJ'`ZLK(R#%ouVXUg(g>>'H=2'w=qA#x[N31wWD[%bdURu$Tb&TGZ29/bR51x_uc((,)&n)9'Xh%[#PIwI/N#U^ulv`xF'vZCuG@l(5cqTs/+rr?#+F+3L[bfr/;.C;-" "_B:I$2J3rLr#eFuL0k&5Lngr/T%sQ0;pgI_QO:cDx2MfLY$@##RN&I$S6[0#[j9'#+->>#q(#b[A_Xg;PH0_,HB6l1WE/[#;-rhL3U_F*WC[x6tU>c4NI.[#Dt/W-,a5F%+24Q'>%NT/" "-tLH8lp8t+[$6V-x*+a3M97j?O=AJZ#=7:$[(+#Z5&6M>f`Q8)ljQoT9@M%>+-BtEo5n&NVS.&wN_v%V?XX$Wepq%q08C&d(u#mZ'O#^2pWA%$pjL;B`W'$U+naeODZuXR;Q'N+YwLH#xv&%^DV#C),njZJ#0h:.NMQYnVR;99RmQoBMB#th)?#iL0+*" "u6@x%Uq2?^>h6=M(6nr%X)/BO0W<..^sFgLxjbk1[>7h(8YN-)O`alAe[6NSV#eQ%-e8e$UNc##1h7-#Bn[p7_2V9/#RU&$)CFA#0J8Q_Y9^:/@D,c4QAp.*;6*jL](FN.J29f3hicD4" "vT*COR7NT/iCS_##YB2BH_Q>oX8-?$RI?/u&h.a&/Xhw8*o4*G`'hE5^1LM9m<0@SYTF+5D,BR;xjq69ePC;$7-GND7%3ZuHB)'I@/2.j-RZd3vWvMO?KLTKB-Qs'&p(^)0`:+G0eG5C" "amT&-QJ-v6i8db?v8/'5vJcB,I;BO;sdG-2a^m8&77uR0j0D)HjU8Gi4K2,&I)###E?MW&5>NR:@O_s-&on8%mCY;-_,hf1IUFb3+g^I*stC.3wkh8.<`4I)QE5fEn+u3+pdv;^1-;hL" "ga[eMkrZ=.+gB.*R?s;6GDP@tTGS@t:9HE++rt<6h.t3;U<:J`^mt3-P[wm/HD%7&Fs5dj-meq.`E#SVjxUdG`rQCqaN087@5/" "x9%;Qo(3UMUKQr)/c:+G4j(j9%nm$$K>W]+H=$##FF3]-oatW8+t@X-/tZ(HjAGA#8gC1.8%:hLgK'/L$v+>#`w6Z@7X/E$AOr.LZ2-T.[*Gb@tk[U.S0P>F;TWpvP29E&MkPE0/1.eoeEg*#TBXb:1pXk/Yp>&xh%ai4T7/c68%T.lr-WNT`31EQJ(U@ZV-,39Z-" "&'-/(fpp^-$'=7%%NM,3ksNluuYmS*%P2h'#g,>>#Unn8%h1r58Qv],3RTf0:n%,d3" "3]up7>f%RNofv/1CM&/L$r`h3^:=F5Np3_$*lK#$r/(V%FnP-)fe0##)(f`aCLI5C_ej$4H_P%$98.b6;Et7/n(b1B#YkA#*BdW-4@i$0c*(,)-BNJMb#sr$3QEv$?5Q0)aX18.DqCP8" "upN=Q+`cA#*4@m%:39Z-6W*Z$4.a<-/Y=b*JhM/2DdCO'[_=h(,2Fo7&PZxkTDPr)l'f<$n)iXQ(dL#$Gqs^%I.d#&$u]+M5eGPMi;DG)uwcZ$T6###YwQAIl/_5#^[*9#HsM<#47r?#" "r>-C#5kZl$@4vr-WZwms3W'njr=q_O@<$Z$PmN:IPrbA#J59;2F.VQ7]EOxp#2tM($rPaP`b][>;xkA#;J?:rX7-##7(cxu1xB#$*C#G.T1)^#)W2`]p__jtXJ`QjJtv8'_+-5/SZDA+" "9aCY$V4l%lWh.<-l%]a*>)d&OtmF%T[XR?-<:^@RrXSRR$^]=#?khp$BeP9MFKG,MVQ02'/WLV.bNB:#H#$BGKldRBdPl>[i&#A#`id8.D.Y)4GV;h)DO1x5u'7]6GD]eMGxvfXC3peE" "Y,p,3+I@X---#Sj]WQ6'Ep+6893r8KtL6>#n1Po7.%7>#w4pGME0l@&;KKpTCCPS7El@`apkPS7I<&KWq87c,?d(K$$r.'5JuuE>G^$Yde.%:XUiB[bsT.?7%s$?k,L%ps7f3OU5GMt=Rv$.ia>H)g?#6/bc1%dYDD3,JOae_xX,'6dfF4'$fF4MPsD#b[.O97uv_#e,97;N8oReQ3C_'MWJZ#h%3=(:uJO'" ":$baa2vBf'CFVT.eH@E+$RYO%hEt7/;fk.)Ww-H+^X(>$sxTh5rB(/L-oH8%Pwc>u'`V&.xY?>Qc'Z%.'19+M=Mw$A[u19/uC/GVMXIq;KfOS7tDI&#Vw=g1S6[0#nd0'#>Ja)#G,FcM" "R0@+;Y/.Z$gZCS-uK-a$JRhV@7X/E$AJW[VE34<-PO`X-(t?)fBQ`*G7rJfL4nL5/YasH$]W5lLh,h2'Oj'B#Kn]20i;oO(Bm1T/e,5L#0v4c4TQ4L#rxgI*JXh)3m&B.*jAqB#tu(Y$" "[,U:%0nlXl9?Cl7^GcH+3-g[u0v>qaDw72LE:tH-ZtQ[V(JV2MXT_E#k58V#N0jA+1x%B-+C-_u9;Bq%q+N3l,r&W%1*1V%[L1&lh`siLVC/cV6uA>.(/5##T1^&=D3C/LAdZ`*5nOJ(" "*A0+*8%eX-*&Vv-b5:R/)SE]-T[I[#Yx$,;.i_jtDJF9Vg[dA#=bR`a[w'/LOS9>#8FQo7G9>RlDB7Z7ZOcO-1Ji-?wa]*%T-f8.&sgo.?D)<-p[_m8N)>)4vVC#6(1^k$9mYT%b&B.*" "iH@E+8R(^u>bU_&+Z__&T+AhXj(J4$jjm8/>K>.8J0f%u3FUB#=@oU+-;Zf_hivg:tvn_SRY#aNs76PN*0P-(_XT]u'iEVMo0,A#xF,-M?\?qg-t36kOSMXV2d-0DPBj6##td1($weH(#" "apB'#(18xG%iv;%pp<8RV-RM9.7CB+e=4:&.]m&M:$Q:&OO-K#xMrbRx0eS+jHu$0%X'+.3h+SINw3F70TdERjXK&#fx`m/27Yd3w0`.3cfb#C6+#V)S/iERl_/)OL.8REE]m&M0;sX-" "f_*Ob[" "4EY&T9cb4%W:`W-^LM2rkv96&_D>E8*(p6*nu(T.hIcB$;^BK-^cg,.0UD78QE_^#?t'SI^i:X16-kW-TW.UD3_Wn89n$W]V/17Ufi'mQEM0Ue$##B[q@/dZ'u$$dHtH@)>)4xNqA#-hUX%c6re30S#K)&8lo7jL#nxw#1CY,'FI4_JNYUV$Dn_d-" "BdPp2Z-KefL;+%6,MJ@[^&tj?D*CD4;-a@:[,.XtD#^`9a*SY.<-9MMHe" "YFJGV%fd@&5i7$'O^`m$OJE/L2:CP8(n4t-DbhfM5TKl<`>rZ^ZSl##j3l#%T6###=4i$#1avw$EvbxFP1T;.^u;#G@m*VLg5(u$lo>d31MvwPw'hD4K)'J3" ";_h4f$XhL;nB`V6p$v3;Fh%VMOC->u[C.lLMKC*uKY+CAPF$/qD6.Cuq2k3GdVbfL:cb5M:itPMvvi3MSXfRnNDJ/;KP0c$Tp%;M-Ns3;+uSh5EN$`WvP@>Qt@B&GSOFL5+U/kkQnwjk" "VlFZ$1TXgL:wP^$l+=a*^[iHDJ'A='fo8j%]fUV$f._'#;e*x#A>*T@o[CE4M29f3#Ki5##r:N&lr3:74k?fkuJHrD+" "aVrk'Dn?m8+=GhH/D0p&dpo7/U':I$46,xulqJ4NqSLs-+wIfLxrJ%#/$loL:IWO'vR7C#tS))3()7`&hO]:/v?]s$J5h*%0jWI)+DWD#TGE,)P[e<$Eo3@$?;f>%Oe_F*&>Ej0jpB:%" "*fX3+atN,+#`0^#WD]T%qjG+I0aLBZOt:wH8_&'RLM,S=4qr^7D3.HNl5Gd@$xnROv]?v6g%peEjCD8WJNRkWf/:cN18B+>8=uFP4&xqJeWiR&e@4fIxaER1cXa0;*SmPfD%-G6id_,)" "01G$8R#*EVS/trC`lv>-I;qEHZc4K%MZ-hMYAO#*pr6D?B:%*X@G;^b7_S]NCD3CcK+*P&hbt,Y$K+DZq'4AlXW@vXgj(1(0,MeFkJ--n8g16CW?Q94s^uSwu`8ToQj*2>>Z5:u@na.@1l'" "&?Lm0D*[p*LYU$-ZGgn]V`&JNtlTP#''BKW0jY4S)QIb@bnJ;/p/pPV&g4/MZWqP8)7ZK)dhLS.BXGS7c68R'>%NT/BP,G4p&PA#5aUv617LP86Is@$0Zc8/kIA(#.1H;-bC:[,/XtD#" ")1m=&MlP%/27J//w?d(+PBaFNuF:V%GET[u.,97;^^`fL)+@20,#I*ZPwSLpjS/F%=I#2p.])puntuP&;BJ/JHVGsLUqU905#-k0Lh_ub'r;:B=pTbA#,m.a3C+cIh(LiojJc_puOZ<3h'YxT#s-`@-w0'C-Z24n-OX%+%&i8V?M1S1dNhXafNC>jZR3-RAOX?vJ(;vB)4q`l/)bl?b#m,eA#7TJ;>#H(]i$HDn;%%jE.3dBXA#JI]C#:wT30+gB.*TdB:%556X1RWgf1o(r>$XQ%U/oUFb3$jVD3Z3rhLc>ri435-J*)[aDYMwY5Cjvk.nomn7Bgii(,R-nit" "85li(<19h(ofi0EWKZL.Q]FhSt8GV7%pdlC1%%t'v*r<-J@9GPD+lLbhpA:Jtalv,N*(Po_NuD-_d8Kus#Iq.&;O**JX:^5LB(O'Y'f<$/IA>.`WCQ/nJ)Q/^dF;H>$+^,02+v%fMU^#" "Vqke)EGlv6?nfx&_uZ$YERKut3@M9@&'##g&p8%[8/IM4b<30x_NT/JETv-CR_6##*R;w$#eH(#[Qk&#P`NH&nV.)*uf[>%.ARY>6:$pt-VLAh;" "[=46']bO-)&@)P2(`BB+%r+B.IEw68LwH#QF2$" "cv_*MDt+=$Ww&Q&%J4Aut7cR-BDKc$ZfUV$ZN7%#`,>>#Ut(0ap1,c42nL+*Hc$s$d#MG)>j2EGA,Xl(KkRP/af-g)Mm5-*/]A6'R2l-;A66D,;Qg:H]Kg2'm7V(,K?'u$mTsi0qF+$W" "S9`B#&cGP#l:sN(K+DE%K,8L(YMLuG'-'[ukxxAKKZaK(G6+A#E9kK<7)_`/_Z`=,ksOfLQbQuu&tK/%;&q:#-WajLBq.C#h'cJ(jOdP/V`&+*/hYt%KGt1)cx=c4pp%J3/_XX$>M*)W" "lPlIU_Sg06U`8s&YHa4SV2^F*4J4S7?+i*%2DvX$-n+K-ZcS(sRd%&,h-Z(sRoTP8Ct5<6KXBr6OOciBEaZ_uCBqW-./I/pwclA#FD[E-VO,F#<=D^u9r=^4pg2C#LV.JL[xT##9f###" "65;-%^TAX-UG@A4ij[3O&vPA#vcmILljb5&i47%b#mig(IR/2'pi`k'#;HntMqiV$I`XS7GIK9&k&m,)ZI$##JL^,2Uc^Y#a,mx4ESXV-`oXV-29sPAl'tY--ouPA,5%+4u3YD#4tFA#" "9)b.3tfrk's%%T.NePFuKH5s-XQaH?)?o%uFO+,'H(=1sZTtp%i)Kf'diIfLv?b'MT8>E?'&L#$7qpO&O@sp%B14,sc5IhLDLH##@>r5/9(V$#,pj-=+$qj(PDRv$st<4:F47b4FrCZ#" "E35N'a:^Y,Y6qT`=M>c4m[d)%RuB<%5C[x6I'G=(K7:&55d(i#.*bZM(sip3w-U.9U*t71.1k3Gf]6+%ri6h4WhtT/<(d<-lr6]-kL)+%kF`e$DOv[?GCW+L0s'w6J.(Y?3Y_.G)DMX-" "D_/`&uixB+<=bFdUd`a4^X4=7o19f3C9o.*R_[@#vQYsI)5dK)iRm5/Q@u)4" "pdjW#hWBf+Crx[u]BHg)rU]FuDgF.qV8GB,0.lA#BRrt-W=IlMpWx(#2IfBJ$$#+%Hr[1KA?l%l])ds-xWJ%RrJ?DIH*R@DaSM'wR4]fb5F7&`#AOsZ94P2sJfLShQuu" "%Auu#p3###o7E)#QH(l'lsUO'rvi^O&`Zx6n7u*c2Ej'%EkVl(A,m]#Xg_1(l;[IM7l8;62)X61-.@lL;F>e)b8:/3*?]p0XC0h(CHZC''`DO#t)fwLl'WFNDO`d*W?e:AwBr+*dQ-M(" "RGDL1HREa+LGqW7ot`8(&>^Z,$>ks6V2lE[XZt2Lr`WY,WGtR8]?e#6%^Tv-dZ%N%LA*F3o#H>>h:ie35IL,370fB/VdDA+uv3V7e`c8.:Et7/EaSq)2Voq)wdJe$O@fV%XV[f%-T`I/" "'*=@MH0(Z$S/P:v7,Cc`c-ki'B+$##6'0X-1Mpe=u:.$$fUUD.X&FE+L#@^,@^s/M0GMB#*F7E+N%Vr.Sm^CM(Q>s-Z++cMQ8,,MLFZY#xbLP/=OdDE=0Wf:@hq=.KmLT/^CI8%Z+YV-" "LK#x#_ZnG*Cnfc2#UCa#*Q_#$n$eX-/W8f3J%rJWWgDE4KjE.3vW1T%loX%$PUaq*2JY>#5:<5&wC1uuWVN9OqcKi#Fi:v#)p=%P[C$<_0KZVu^s#a3N6th3>t-l1vuML+t%>LF+D*C?" "=e>SnD5Ai0BCR8%Z%gb*?b?8.mWYLmc8hm&GS3?mk:8tuucNFfW'@U7>aFm1/(_g2x'6V@t7p>IXpm)6;:t]-OSRBM$C6>#TonfL@ffM:uS+Z$hGS#$(9rk.gCLV$ca2.0,&0lN%H=q:" "sshk.j#>M1`E$1/LW^a5@RnTiNjS=uYLkGM+>uu#?hH9i$.ZV-I69u$T1h8._%NT/cq4D#5IL,3i9wK#qp+Yu40s-(p:aIL,u$>#q/3hL).gfL).gfL3gxK#'M&I$7Lt*,vLe60DM#<-" "Efo87$),##[6M4%T6###7->>#-c4OCI8%+'r-MmcYx6K]B.*R4cM<]wNq8-:fA#" ";9.mKKm=)>TC3dE^N3g,e7at.ssq)&`@`?#HM+v,Ag2u`'/+*uY7A@T.1;]a/='cJ(ljpu.],o90$>#G+'C4`(KL(xXxfLTpkj1" ";UL*[s&B.*Q$Qo7P>@#bsMZIHH$uiJ:9d?(#Zu^##9-(,)8eZi9[-wX-ieUB%&(1+*sQ&J3/Ux[#N'^:/'[:AXGRR<$q^HW&KhM]FRlNr$.QrvB6QWu94hlJ(*saE*XgU,)>]*.5(Y+CAoeBR'HsH4$Tcq@-J'HZ%C)9duYv39%CIxf(]pWU[9Q_r$jW4A-6:Y'$3h1p.[wtR:[0Lh>[E*Ma#gG&#ar+G43.ZZs%$=x-.)$fID3npt6)NgVu5gb8YcH3v(N4;#hL_sW1)V.?_/x:Z$0" ")E.=1uDBq>O*exKl$?T/&@Gm'JR?s%>`<#-T(5^#hN4oMJtaF.$NM4fTLP#$Pk(tLm'rH-dPViLV:x/M@%jH-*Ja+MO6NFMT%du%U4c>$WJ$^5+u&jCmkpHm0Ys)#?+lo7,t^>#Z$SX-dJ?C#/g>#7jR1KoL]]$6UYCa=8suYK`fSmo`uhu,/aiBQ&ZQ#Nx53WxD#l$E4l#%<9[0#3,>>#cK:,)(DxfLq_21)HDmA#f$$ruG@9Uu0t420>o%P#=jeI:A9mH/BNC/L41>(s?(#/C" "P5SO#a3;Hai3Fm/@oqr$*Mc##rPJG&p1`5/^oq;$8tu&>.x_E4l/^I*hf]Y,O=^'H2IXD#seFd2Ynn8%_]B.*[*'u$IiTt6ud#]>+*Wm/A#ad3Q@O%$T`.<$eQnAIrNb%4i=E&AFXwS%" "Xbi?#T4FT%%9>jrvk/c$aq>tR%)Lt'Jt[@#R44=$Y`jN2;22ku9TMZ#l,RlXlWl#&Ub5A5jEV0Ch(j[#leV1L)L8..5p1@S5.j^H(i8=(/ZDT)q#i9(]wr$#[QQ5.*w,tL" "^cc&#OdaID)Gn#6j:R(#dT?x.lo8f31m@d)+Z1p/dPZ&ubDg;-UuVu$f4.H+##gI@eg'^#E6rB#%CF8%E_.U+c)S.M,N@%b6S'Z$^umh'Jg:D3Xd3#&umCK%,r0hL&I)s?w+G&##X<^-##*VUV$D,0etqap-<^o>1kL0f6/Zbfr/tD*MMJ=6##=(L#$vY9)OKr5<-(DNfLui_d-t8:TN" "1**+lS2sm$8rbA#.qtYCQWD:MQbFwNi5vs-i10p7>s[a+H3%29&LvU75;Mt.Ag:9/[5MG)p&PA#eIN$6]NTu.%H6C#Fi<<%MSZ,*,Uln*xwIU(5U3r1V#:B#=ufI_?cRL(^2'i&o-50L" "p7WiK*k6,oWCx^'U#)4'uaJ;g?*f:.Xcxu,%BZa&&Z=7;F]o$.cPj9'Hkb05tnWP&d4nK(5JdN#DUN#D=h86&CKa<%f8[eeU-uM.L(SZwZ9UGnCu)hYn(4Ogh(/fjILm3bp%&,###I.2pR)=j'&;h=G211RW$P%NQ99xlG*.G+_.U(Ls-oXU).o;U&='u@Z5^T$H)e+6J*q?crd#hO=cR;x(Ea,..)" "V@4C42U1<)_H'r(;6D].O4)x[t11`$d3c&N^#I);&/KN+KVpj9'/l.g34v*505Q+M5KlN:LEOUZ##X&p;-5NFF(Sq3XAYbw[-" "q.Q##6>aILNgAE+#Ag;-H50v&aUrMM-1;)EW.L#$qx8;-T=me'6ipj%(wMFaRrE@$lAm#ul_[h(-->#0_PcM):<9/x9%J3E^Tv--80j%Lu'At0q7%)/aXj)5+=HV(GOS7/OAL(;KSm(`MOS7b_E+//heBS6.kaa+'J'/>cs.L$>sIL.9sm.uc+:vYQF$/>qn%#Gs9-mZA*F3tC)?#t(MB#" "G%V%6#QBv-_bEN0i%YF'CIjW.+B'%MZS@%bCo6hGw((c':Q>q%D3(,)p0ow:rFa-?ECQ--F%'/LgqtH)/#>#D@Y)4Ukp+M(:<9/EiXu%pMZ]4^oc;-'5XN((p:&TFoTH#jZiZu-&mN'j=0N(@JO;-7WO=lu#h,,DlRc<>B:GVq?ZB#" "R96rA$TxE'^V#Q'hkF41.kH;-#fH=lf;rlAVgH=.Pc?V@$nT['%4js-=^jjLU[am$*vOv,?T$H)6p;+33#K+*+SAW]fqQ##-;>V-9+`w,3Gh2810h^#L7U_+P5598ZJfpAEhw7/jDo.M" "avW1)2iLhL10YX$Ls4t7sD]RNMsq%4qkYm85o*B,Ya+X$B7&Q/eoi^#x]DD3_#pM`a)_#$0n<6)IMck,WETMbbqP]-C5rj'I*=x#;jO'YER-n&QZfs71]MS]RY)<-wralA995O04s%WA" "JkuE6s*?w#R=BMBI/(LVf12Z#Y;_p&Mn^d2+GY##S-4&#R>-C#GKPJ(kS[XdG#7_#O*>uuN$[guYDTJDahkA#bF6Q'A3=CLGJ,Fu^:cY#ub#V#`DF8N(DOPATpb<-MURb%rP8>,TJ%XL" "q*js-Cr%r8m'cv.7o%pIb.@%b5W'[utq@L(KBF$0e+bj&YA.h1q'[#-C)O`+'`Q;.$K>,EKSUg*v.U,.]f5p80<(IR.9uAuDQSh(S@;mLw,PS72R8HRo:RI.4QYA#oio[u]2YCj/fp&#" "Eu$s$Qq@n%c:oV7Hi`6EgMWGjXmQ%+11^p7v#1^#ZW,=&8Q7^u'#89$5#[*NG6%5fc[`W-Q3n0#U&lq$Yh7-#v9L+*G*TM'pYY&#n^)2%S385/j[RQ/jqC.3(cK+*G3VB#1jM[$vBo8%" "rl(T.t4Iv$':]T%+;:8.AQCD3,1Q872nL+*s0f#$C1i;$w62`+Kw60)D1LI7aj*.)xg3v#1vDd%+?NE#(r=_@@(Vv#u&M4'N>wH)/YfP'HcbC#q;06&_(0^+@F;v#_=n6&I$4]#hVvLK" "[*Ct(B=_f)In]2'mK/DVI.d>#3(7W$3](Z#piYC)msL-)WJEO'3'pNgiEqhL8x,-VBlc>#.`Cv#oxB0GgMlZG^D+t&eWJ]&40X.$`hfr/21e8%+,>>#uFPS.SlI/Ln^5'A$BYg$T^=<-" "pYqW$g7%s$0ljj1q:Rv$YGdJ;.1T;.g_T,2Rq@.*C^LO'/@9h(YDZZAidcp.IoK__x>eS%XXP3'h>+qAeKII#2j*.)UcNT#/j0*W)n`uPaf,@0G61B'u%W9))Q;h(a&XIK#(TjK:.*p%" "rMj8AhCKO'qc%[uoRh05,QNC#qi=>#&7`##0K&##Enn8%$w%<6Ms:9/&_#`%*geD*Q/DP-<,`l-4Vw<(Sr2v$2c#AV-GR@'DO[mGAPg)=22Kd<7IPN1b^.90@n>$cirHEN=$5JEf&mt$D#4]%Pb@w#]RC&?6[9W(AM^n1v$WrA4j9E+PWk5kc+=h(QgQ,&sc,f*/K3FNOIP/PF,l$;G>c4AsqH%Z3m3+N+es--7UhL@[V-*a]B.*tAHO'clkpYS*=Q'" "dHG_b`-hOfc(24'%F8:*Bt9h(752JUEX?;Mx2cS72K(<-N%BwYrBjM0:'ld68='5H/6(TerZu" "f'ui*2)F`WfArK(TI84'Vg%@>d6JX'M8]E'8/5##wn,Z$6#`1.:cGlL[0^:/Dn@X-leWt$mtc)PerWZ%`IE(&B?e>5',^6E$_US7QaOIuC,R" ".oYs->tj`X(:4S]uJt&/Lit%wWOYXq*JBXsX1w@T&RHE'ge#Q2PW9hB#Nb5n&)mYN#.hge$ps1k'rlSI-[_$##&&>uu?&ek$,XH(#sNi,#A?T:%W$5N'gHE:." "b3ng)J&d8/e?.J3&S+F3U6;hLMV#J*J,tI3$=rkLw(2#$7O4@$*M0N(1p,x6/xlW-mSh$'gaU#%&0KqRwf[9%CHquK5TxU0+ec3)W:h43K'k5&l$L:hrdUQ=ZwD=Jd.pp,++MA?`5HT%" "NApj27;i_,f+2V.[MOq0Vm@v5D`P$6-now#nh,+,NF)hE^ZY=$s`Sxt1NSi^@KpM#,#GKN>#S`jE*skZY#sncv$" "VxIfLl>T%#KSj**i%^F*0]WF3MBJv&UXH##6^TlS;4T=YPuG;-?Jr$b93dr/JFH##o-'O'Y&R**Jx%ctl#xq.u%0'5b<^.?RAnx4KVR'A>qwX-)#F#$?L3N(#]^b*oV0b*AP;wPkIMG`" "ehPp/m&UdO-Ye@d,2Fo7dDDO'#?Q*&<=$?$Dt-.MemN=c#71Au'[:Au4Q-e%=$[ZTt&3+R8%vxpN&]3qa*[-8u*#]qT%GcsDuZ>ox&BL*p%-V-L.@=-XxP&Pj7im&BP0[gC-KYG?(H?$tr=>#OQ?dkE?(*#Hsgo.nGUv-1]WF3eM#WoH3@K)$3Tv-$t`a4fDc8.7@j?##Y+T%k]B.*<_G)4" "'$fF469v;%abQP/NQGX$chqf3w_603FtK*S;t$Rp;'n_HB#Ue*&/a0((#3SCF/)(=&N9IQ$0-l,KK0P#FaUg(EPceJLVsq:oY5`>+3DQ/(2L2Fja:U%Qr(<$jb[M*H@>nDOk:,2ef:S[" "WpY/(3oF[5NQGuG.p+aNJnQ1Mqdh%OSWp9,k$S/)+@6fVBWPsO$lQ.8fV_>$kc[`t&7kU-_T_o-RSJW&/rJfLTk?##Ta]*%>7[0#Iqn%#c+wQ%0M0+*^rqxnwrrG)lU9+*Mq[s$S6;=." "FkRP/Jc7C#)$fF4&,]]4nPCgCGQ:a#KjE.3pfWI)G$5N'*oJ,3a(-5/MMds.uS*KVCYQ=lNgAE+/#q7/d/ao'wX8L(G1KZ5WkmB85UKXJUGQW.CEbn2`46C+Gw8Q&+i>C+@FS[-OE1,)" "Y?gM'EHhc)(O=@MZk5`-4;ia6wn&/LN#;cAJLf[mY#Nsj`-l3BQ0rrgM)G79,3ignc*9FSw-dcVO'3Zu.:Q>Zv$T)bo7u$BE#wG^s$l.J01ei&f)" "w#9Z-#o$],]TdP.?f)T/XuVH%`Ulo7CnUE4+V'v5hbK+*(DpV-/kP^$;O]iDqpi(^u" "VMo48px[v5xFTA?[0rH)9)`p/x6/],.87%-FI:=6q:#M-fx,'I,*GL:D)5xuH&#'R7p&e>MT%hqfi'fBai0hqAS@]#QiKN`HfUCns@b(7l)4NDn;%_^D.3" "L)9f3?UZg)0q3L#E&wJ(O$j8.s^v)4jwNcYapFX$uc+gL`50i)+g^I*:oEX(+k+T.xQ*c4h_IU.$cGg).3`X/L5K+4pdwt-;pCW-]lwU/Jj:9/$-6N'Fp?d)n&PA#Rnu`4%[*G4bov;%" "U+fw'O`NF3%I$T/'9',.JG2;?KO1E4Lax9.c^[I-QxVO=rdn8@A4TM(rk(@,_lcDu'Bh0<@/[W/#Ios$vUSM'8P487-&Q<.@NCB-.'P9%0U/m&pXiC,%TXiCPd&+.A5,Yu'%Ma#BC-68" "nhF1pp`Y=1ApNI)#n<*OUU@x03pZp.)iO5;78p[%#p7T&OV5g)k4)c+F(0G3<`v3^)(dI)x4KP8jHP'AT7g2BBjM4(7<+/.dY+g9$vD]X#iDrQO:,2(lBX]u?W#j'vMu_F)hZO0" "`K_1p,Y3h)dnRP'DMD9/6KV-6Q##',t_6K3`,wd)[Va4UZA8q3)JAp=I&@j'I$?51-MY5>oRN_&k)E'>5Eol/t=nU@Ml#]dvgLD,rQV]5Q_'c+'&1fu:KA[#K+`ZuQKQ_+V<#B=EHU'#" ".D###Hhtrdlx&58#iZp.7$S-#*`W1#oD]5#MYWI)KeUN(ont[$pM8f38QA+4H0nO(O]f;S:@>L%n02N(*lXF3=_Tu.AEC:%V,+Z6l(9f3SM.U%ln+D#w>pA,l@[C#M@i?#xVlS/Jj:9/" "W=[x6]0x@-qSID*quD%$9Kt6/vNHH3PfCE%VekD#K=M-QB<0r.wjPU%U_5d/(f^F*MCI%@vCFJEd/2:CLmo`?rQow#4P(0Le@@&G*j1]kPT8sH8A,QA3[." "8)p=usAlc#t9S&L$;mpT7d>u(_#('>;]kp3Rcrd(bPIq4]D6&^.qg0O/=#)gs+S/>bPJCW,]n1p+@`aRxJ+*pi-C#TfV$u" "l0gLT/HuK1bKF#$bDKfL5R$m8+==kO5+mKPrX<9/N'*=%_Dic)Y1K+*tEnb41L`t-kk4GM_<5V/;]@A4_;F,'KJB.*g95q)kYQU%upk/cMTu/(hfxw#.;I-`d@>fC>NqG)kP6:%0#K=u" "L4dDjSUU+'QOZ>#:;$n&cZ3YuHoY3'R,Ku&nsp^#stSp&sr9`j`^WE(*%*7'R2Puu4L<9%uP8=#Ft7nL+FnM1nXW@$>dp_,`/l]#qSID*_?T:%B4r?#a>Zv$ink/2e1F_$*]7C#Y985/" ".u587F%sD3$9RS#2X*M_OjAP:FgnP'EaftuJ94lfx+@W.3CjXQ8CqR'Ap+Y#anFY#G,i;$9Uj5&`NOt$fs=Y79aZdN,L=]?l+tE*E+Vv#De*p%" "3u$W$L1V=QK0M-MwKs$#?#Xb$mOUAO9-(,)U]W]+B+$##FbR@#FM[&4H;shLNS9d4N:V?#ehDsu=,'Y$f[e@##5H:R'6J>#vRm@=6rn+)YG:g17=K`*$>ru>g[^7[u@fV6*ET:mGBkUm" "B;s'M+N$C#l-0xAC7Q>#`4iUm8^T:mWuZM'[-(fqW$H>,fo_@bFeNG2)5###i305o,O)<%=wfi'__#'#($nO(ElL5/$'g8%6$6GM*-;($5x:?#=*P=$vexhBCqQ#$TD)V?,8+h8),Xe#" "v)OU#N7>S.LtU;-d`TUu%)[guDS@KU,ISA+IXhiQUvnJusYUPJXPsd#6-x(:NO)Cxl>#*O)[$HmBI;An[xIUN]Q+qC?c$;-AQ?,6cufFbXGMqZPrd1Iq^#;%sDS4hJ`Wk7hum" "fdxD4JNE`WDMYc-,9i`A.@d2ic?W$#h^nlBL7^G3e;@N0PDRv$.cW@$iZZ>J;Ma610S^quUU?X7[O7i3e]%:D2X.w3u@D+,3]7wf?v$Nnk]4/pc/(ML]`$CTp%uHN*7R" "Y3xW$XF-9._nrv#jwJY.'kGR#eChmTslcY#u$@C-?N4S(8EaP(I.]',iJR8L#8mj#:EWs%=nK=%0$a%,tox>,sR$9.]5xLCI+KI2o0BU%][j=.b&[q%u;Qs-jjopX7Ogc3JQSB/-pS?," "OUGu%F%(HZ&>#5L]s$G+TC4*oi?#xg;E4eLG.)@4[s$Lq[P/&_*G4n5;,)0cNT/*Lum'f>'t73]CE4i.<9/wUKp7-(X^,kh^F*" "e$St1cFRh*=:?jdw-QB$n-hpMV&-l2ku?.tW$oM*OUgu9^,)6HK(A2+qutC4?/8txS%ehv>#Pm(4'Dc.v#/A4#-+$ol/j-gT%JP/$1" ":?XeDk+6]6&#vatO3$?Zv$DX)P(" "V$vM((36N'v.NF3s`?v6InAw'iYa(780Id3HPG>#=2Wh%xRS(4%2Ww0jiX<9:E$+8LbP2;_=ID*73g@#gCNM9n[APD7MWkuDK45EB7FG26GlhuF^8xtl&tV$L75/" "`3@6s/@KT%V+8I(1OTF&G.)Zu4#bp%8_KO':QA$lZC03(b?=6&s]i-))KBf'Q7Q^t9C33MIYvu#CdL7#p>eA#Ru)T.BKc8/BZ-2Sn`aK>EcRUh]CM2C/b-/=Y3b+UQl=*Eg;-)1w/=&%a..w;VgLDNd)/l^b6&9]5=:6t:CAFOTF&@DW-XV&eZ3dc,*IL?_H7QrhL;rXI)U3B:%3ij-$4.?c4Z2QA#jgtX$<$-SL1=0d>DLM.=nNkGROfAA:Dn$N1U9S?I9qdI#aD6?K" "IrtY-1=oT%2KPTm-Gj],xWGZ.8uH:A1kIP$rGt3;aAIR&A9`OEcR[w#3G###'&>uuYg8e$Q6>##`OwP/Z0Wq.hb?X-5:GF%FriOu^`rS%sw$0u$]31uU2V?u&9VJ1#Yl@F%DvRI9O)h#" "'X+.u,x4wLxKG,Mq1B/L'&Lq;wMsx+R,Tc;nl7R*<,Bf30d%H)*Y#<-#1Zo$(_'T.SZ'u$c@K^$Ut;8.vkh8.Y6mS/Hl;P(XAic);M>c43v+G4V0`.3j4-J*o+SfLSZhV%Y)'J3J;U%k" "@A4X5V:%WD+G4%Fq6*&vjI)&@&s$`'A>-rJhw-Q`>lL8=Vs-sPqw-Z,jhL3F5gLhIj?#s`[D*F]X$/qa&],lL&:)_K)T/Ha*XCtm6^$s`VO'?I.[#)Js:/YiWI)xKqhL" "V@,gLB]@U.K*t?#hO6iM^^o8%9;JC4]Ve]47s$O=M_a3=M^*<%?w6u6h[T8/bM,H3$`[@#t.%h)4+T=%>nt[$G,f>$:uHs-/oCkL'TrhL>#lI)GN_$'df6<.vBhhLC/L+*=.i,3%Ck]#" "T@gA#r@rQsbG+jL%BGGMq6pfL5r+G4aY5lLC0K;-HD?L-l:dH.G<'u$7E$^,RE-_SwG6C#hc8T/A-+mL:;n]4B0+qiCPhD4Y>P%MTS5W-c/UHm-.9e?*iqP'?BwTVUZi2D>>iu_v#0](?#,U[g:,F:#?@H'$-Ge&q%esP3'nQV)+UQhG)J_Gw5M&[)*2A38&cMD4'i_^+*]1;@#rPYx#('W`+L+wo%KUws$J^1K(" "Qxfb*JoG>#r$#2[qN(RE/a+JilY#AbE9%IJ2G#g0I=-3rq;$)SNj1iiiG)=g[w#=*9N05iI?$:V(v#" "=?2XILBwR&&A6hG?HHd)A1mY#[5.l'/'%0<&-pP&7f1v#>LjP&xe%l#HR7W$9i:Z#qB6k(K2EH&Gka9%9Le<$v`_2'G-kp%.AP>#7f_;$B12?#%Kd]4V[I8%<38E+,'ATA2l#@/#.rs-" ",[85)LA@n9_m8A,[FJU7:d1Y$QCH>#BL<5&bGF[,Pom@-96-3'HInW$MdT#$3<;LLYiE$8>oR$$x7[pI%e?U&,;G>#cE=T%CUHK)ZfR<$&YxX/(4i_.V?0W$X&-h4Dces$fu]^+S6Dj(" "hdGN'tBhj(e,67&o:-$6eGxL2A/uY-V4i?#k(o1(SD+I#k7+gL-80M#M9>3'&q1G#FL.W$8VP>#HFnS%2`:v#&h:w()1;`+'@rs-5vlG2Ni6:7e1u^#R+`s1c6)j(l,eG=;((f)<+jv#" "vE')3H8B58fKk9%5h-Z,m_rv#mKOq%k]r>5K0;>5GsT$-n&dffB+VM7l'BwXJ(JmCK(n_+gLM,^&$`DM,)5oCZ#QYsE*ATC0(RU7<$8u-W$71R8%3M_G+B(N&-" "O8a&+IUOE,sool(j59f)e2t%,(;9p7d-_>$/$hj'66-j'+QTe*2:9U%:R39%j9S0:0U=g1_)b@,w9UG-kejJ+0csS&&I-C+57RW$`N#Cb9oU;$=On8%n%8_4q'A$lH:2?#,DG>#J_rV$" "vB3T%Bw82'GnS2'7(7s$7VC;$bW?'+x.fL(Z04=$V6$2(c@5?,LfG>#D)&#,_(H>#&rsP&Rg>R&WR=0(Pias%Odhg('n>_-LeJ2'%J=a*`/vj':[^q%P*fs$Z@7s$ATDW/r86l:w`[1(" "`B6L2<^,L4?@lo30HqYJ,pA>,Lt['9*AUoDcaxl2AfmY#4QPA#Kpln&#;FQ's0A9K'C*W-ig.iLLU3S&wqGt&Ygj`+=P###m7bZ%ppN$#kd0'#.Q?(#c*2,#Usgo.w>v;%de2Q/L[=%$" "@1vV-iL0+*f*H875ESP/*Lj?#vN[5/;'Xn/N2m;%RT5<.M4M9.2MMT/vKt-*qSID*^dp_,/?n4(<>)cTH;0lXheq(>cY#r0fb;Y+?>90B5p'ISpM#$E)3;h7d.)U@hS.7[FB6V`E8&'MK['$U1L5>CBd)NcHo?fAfv8D(`V$b.G+8/Z_T6e^RD;%utI#ncW=)W^m49TQ9[u" "7rEQ#mI$E5=4(S0J_.W$5+Is$OOx:dkWo<->Z./&LBY)#-->>#cj>,26P@&40Pr_,m(TF4g48C##F/[#m&l]#q%^F*ig'u$Dfn$$.m@d)^^D.3A>=,MR]XjLX.w8/qC,c4>;gF4x2shL" "'t1C$u7XI)/mtoR*Ivl;Lf1&,TvO@F]:]aEE#=$OwL](G'QK(]qFlT0%'#;=,M$x8E#dD+J452ka*Q)i0(_Unh*j^wU7e-3p1" ":j/V:sD7v.$>jO'eTHH3i1%@-mxV5M?%HGQZ@b7(V=fV$])FODX)mW-XJq$']####&&>uuaU60%FKb&#Qi8*#kB%iHhx$C$5N'MPmp/?eSM'" "Q^v)4cx(o%6'B.*(^'G+_>m-/WB,^(ht-OTx$7IvZ)*;&Q]u3wNT%5[[L:Z$;I=>dU^7pI9s6073Ib=b$K)acR$B)kUl'e3?e6SXpY%`Jqr." "vOoau#pd`(;3a-*IruYuh?Xp%cj$gL9,04EsX6@#d*HtL`_D6&JU7G;:h@%>hobA#(XdF<`)[_#XTMZuv][h(wABf'd-EnOvg4F/(]'O+9aCY$8ulca%3f'/ta]e$->qc[t'uP(^ur>,<834j6/`hr?#Cg^:ZwoPB,(HfQE&WFn*:d>U2LY/GMw>5,Mlku&#I+NM-Tnq).#xS8Spgar$wpV?$9TF+5Dlo>88LC_&ck5c#d_weuA7ix0qEc1B" "93dr/G+Z=G$?$pf2c6F%.6Biu/8=r.JZ_.GX9dRN'jT*%S6[0#Y?Ouor6B.<9/?1[s$ikkj1;@i?#dSPp8ca&&$BC.9(SUfq/H^(V.,3Od*dj)k1f0x<$._bW'tBEciX_0*-'FR&," "]#lu-i;soAV&l%9h%Op@w%>>#3Uruu&:;J:WNT`3.v*Q'Y&l]#e3so.FEuJ(lh)Q/x:Ls-_%Is$bp*P(g.<9/[j:9/Bb^u.+J,G4Wg*G4E+ro.FV'f)g1^F*a&ID*0H%H@U_wchP;/+%" "i&O]Fil9%kLIMZu4N@<-i[?%kLCDZuoE%W$I(0-&=C%@#djgo/[u*-&Y0PQ#]*SY-@a71,0Cm&OxX&%7x(0mAaOw6&50-js?vHOAMd10(g*ma$HcBasgE1hL?Q()3HZAp&H9]Y-;V4L," "iYm3'w[C$#%&>uupB3l$b;r$#$sgo.=J-W.qC,c4n?_hLI8E.3w0s;$StP8/B#Cj(0UE6jrd5N'8']u-b-ikL3)$`,M_WZ41kU7e`uh4vPWi)MdBY>#,ER(N/_nUmPB/JcQ-B?1i*u]>" "KRsnRP+=$-ON>)MXsUE4'miL6+3K'MI@2[Jw?rNJVTb1UL=NUe'a;204S@XfdF<7R@>fP'isI3%`JE/LI8W]+NO$##K77<.+d%H)kHL,3/p#R8'>h>$_4(-4b-dfCS$J<-mC.q.4Y29/" "vsJe$*?uue;G^$&_&*#l####jAqB#l4K+*g:Ls-fIe<$6o0N(Od5,2=$(K15?85/o]d8/u3YD#95h*%T)ZA#9)b.3^nr?#EI]C#" "$(x@-FEvTMp);i8,ueh(72bl$r>>TBml_OCp]YF>g;4,.)g%a/(4>#GpM&uc#=l@%$d98N0bTd`*T=`[,[1Wg*[(X.)>u$<$%=F#H%2f%A,:79.m%6J6?t+j'mTcn&S6Y/(.*[4([ELo0w-&[#N?06&" ">_Et$7NR8';`/(4$h(M)U4DZ#/f$s$]vUg((hGv.I6:m&4u-s$ci=;-0OWv#dueS-Z*G50vkvlLKpE7Mc:a6/d_%W$eMwd)KXUX%eTa:.g7U'+Dkww#*0>W80hjm/YD*s$1]tX$@%mY#" ">OjP&G=B.,[Q&m2M+[S%30EU:QP7n&gg6)*^HF]#FTuJ('gff3A`us6Gi3s%oPLl0ID`$JB(;v#=GA87B3Kq%*Mc##*hKJ%H>f-#BL7%#t>$(#7H4.#ssgo.YcCW-wLNC&g+TC4q_QP/" "sMYx6Z&PA#FOVS.b:ofLAfw]4b$@K)WcX;-V>%&4O>@[',-U:%)m?A4w0`.359+Q'KINq2jDfY,FHVb7T@=<%&7U`$U[0:)5dg2K(" "#ir4^d4(PEO0^6g^eMH#,S)ku?qlqub-xGVB#_lkqE75/j^Znu[6ZruQN;kORNRV?5r+@$L3Ot$esR'2/:jV$+8J?57P3/>-hSj0^4jd%oWLA7o<&W$=4bD#*kqU/Y@)G+T,Xv6,6;,," "EU7&,[$k7.K;gB+wKTB-W:(_+E?>3'a$'Q&m6e^.g.n#An4j4^E<0^9t'm5R5/s20_G(;M/S-?Ig*YJ#-_i:NM$v]'6MuY#2*X>7hX#R&xRF[5Le,?A,Id?K5ce;7;rb?KM;wZ$3FuGu" "3aOi(xk0u]I,Gl(Z&w12,mv6:Sx$HDIZu##S'+&#Q=h8.VntD#%8H>#QUI8%K3H5J?@-DE2RSM'1j>,21u68%+dfF4=,M5XHv,iP@l1_wI`,F6#j'UsB:%>2^F*5^NjLG4]T%E66H-P3`tBscP5(" "DjlFV;<)D+fdoi0T@]2IwM9C&]`6=9uX$VlJ^+:0&S'3PS-F9:Js$Xt*9%6bfM'@5`YAh_]P/X^o+>x+9L(5c=a*URaGH`'EsWb'wmF01o>p42JiSO;u(IO#<*cJ(6FU'HT5o-)[6k>7CVW6Jwt.492r(JPpP=h>#" "(_Aj04cQ7VbPic)13t-$b.qn'afh)DC.$#.Z($7-XJ#Mv&AI$+A2'3hDE#j)GuuH12I$[hSW8[L@s:3.]*+$NYc27-CG)T1h8.HQBC)#k[r*7,$Zu^`Y3'" "8_>C'W_`?#Zq>n&oEWDYi%n8.BExDtJ9Yt-=R_c*WZ,=-0;7OX4WY0:kFN@$x<1J)9DQd+gFq_(#aCB#U?L@+bN1RuEpop&m,:Z$vjF&u(P]7.`9(,)aeT&#bv'-%p,Wm1n.fa-fS&3%;B3oA" "3N1^#RdSf$0Dqa*v^CU%-15##)]$s$g%q:#oid(#Ag;.7wv^]%`<9/miE.3g@SfL9-NT/" ".J+gLm++E*J)Dp.a^D.3Ok(k`eGQZ$xsqInr92B>7d+G.M_V<-iqjiDO8Nc3;b%/3mD=n86o?xjW+P,'Q6eTi$$VFrWd:fj53cx`VBTj*i,cg3w;st4TlBB#p[SE@=nkA#.$>D3-JE/L" "hE%##>:M;$BKc8/wb[s$VkJZ6CE(E#I8ss?q6bB,@Jg.*]3B:%x.vb%8Ge(#*g@J2ej5nuNUW_'lJ>s$Z]aE*hh>W-/i8U)&'Lv'vD(SI9STJ`m_fq).qDXaYvw$).)W?8DW10(`rMj9" ":`em/P`[h(a/'d$He%Y-4`xb%n/r4'$sb$McLvu#46V&#>8@i.$WH(#-jaf/vkh8.pZ'u$-SsxS7H7eMeT]L(Z'YUIAwOvI7C9/L8G.cVc4jF@F4s3rI3V?+^,[/l]#M=@8%d7Rb4lY*E*a`MB#t=Us-hLo+M](81$Y_M8.]]B.*^TK>$MQY8/IA1rUY5K-)T[gk;" "/w14'FCxQF,hZNL4REW14>Z8(`QR&42pvs8pH-DsAEp(G:`Q=l,pr#ACc(O,hx#@?ca^>$1tXO:dp_7uB/2GVI+S[-hjYJ(hD3&+w:HX7..=x#ab3X.?3Tw#boBo.[MOJ2iBB+igGge*" "[XFl7,3Xxk5iGE+jX[2'nldb<;4n0#NQW@tTLr8%^+$v#O'i(EKTEV/xCM;$K`:Z#(TPW.FhMl(Dh5A4nKEJ:O4Fm'0fvb%*XJs$FVU10`)YA#fd]s$U_[Q/mbK+*[cJD*Po'gLCITC4" "Ee#1N%iLMc]]c?On8%XxRfL5kmc*cbGU2KvRU2@xaJDYOPHME]j8&qx8;-XChl%'S-5/;2ogFrDQJ(?@i?#$d(T/-OWh#/A0+*5HSF4" "h*c,2-U%],`S-v$%D+^46_E;$%S]T%Q7g7-bds:4EM2q1Hx^N0;.8$$P5Pc42d@+0Beu/2uT9#,#o^b*$cpb*;(MT.UO?9.0O;E'2x6=lfv2K)w>p59x*.H-XkmYu^>l(5CXq^5MF0H<" ">uJM+R,DK(@7.W$/l1T.SipV*>vwm-*f0wg$DO,MnTR##T%T*#+n@-#R%(,)a'85/HsUO'1SY>#%IuD#tQP(-lMPA#4hDbNAf`x-rn8Y.NMfD*.m@d)srwD*hl&+*0NO'c-hA;q:bt$S1^xQc=q*Xkr?%fjxNTeCxb6RAxb7A8N05v:FS>PJH#_Xq,)RZ`u?3A(v#h]1Z#m0=5&:[sl&Wei?#7tbmuKtnJN`/EKVP0-0=pqr$5:r$#?,>>#.^PW.>;gF4D)2u$TTF=$`^1,)xeNT/x3b=$60GTmOHxmd5ZD$jBw+&49<9,/vZbGIR11%0)S/L5:jl&$H>G2-c:?#m3F4WRHZ)44f*F3;rlS.4tFA#spN+.A`TDN>XF%$(;=CLnbnO&?WxK#QiIfL'SG8.H#Yn>AO7gAE+9/r7/W22iL#Qq'#%)###W4$$#aq32'Yq$##Sm9u$<`v8/3BR)*K)EG)S(Ls-)Fj?#jCXI)fVwGZ&N_V%MW8f3Bb^u.ak4D#NNg@#..<=$O*tpuJDgQZ" "$Axr62jY=$&NibV5P,>uV.qx$.Cl`#[bjaaG7`Z#9jJW&C#6<*v`_pL#o'mAPE^=cQlmmLEF9;6>wCZ#i-nYu?vg4fkI>_.,)*^ud(YgLemj?#4xZQ:R(CTDc<3?#/',YutHa+M0d[5/" "JMOV-=+(X3@Dn;%_RZY#q^D.36'mf(^7o]4Gw%?5A7[s$`r8t6pAx8'P_Ho[o9D41J]W4b_,3,@6-^+4GjFV71uZsQNbKr6T4E]b0*@S#JTHk'FaH$Ta6ePReTxN'oiu.NZSRfLfc$##" "5f?>lw758.ESXV-eBf[#/1a8.J:8Y.s3^e%wgOA#4?)[K)>M#$]ER-'dN<;jtw-Mf;w@T#`<4/1UPSv^,ESeU:%Ar;9//p^I*F#qE4>?(u$*W8f30w/g:1Px.*,/rv-5-70)AS<+3,87<.D&;9/::n8%.Odv$$`^F*,LZ?$7td)4intD#f*19&Z,GA8[8Ht-C#G5Ct61=Xt$8d)L0Ps?" "8[F=.OO.A,+OroPOxf?5gaDf'TOc=qqx8;-F$u8&0V18.+0v1B[.d;-__+w$-#ubJ2a>1=$2MKf,,1XA-2)NWY3V`&+93+f*S#P<-j@KoLULSs$jiL5S#o$LMiUn20E%=&-;KBk/WJ+XCb%+[$/p'7%LkhS0D@C'+fp]iZ1w`4'0-8D;" "l*]?7-,6&#:8E)#;Qe+4PDRv$dZ'u$TekD#I07IMkqEb3nC)W-Fn=X(2?0W-DHMk+G1$o1tHUMB]b,LHn9'SSXk@(H+rY_+s@k;M;)dD6YxZJ#r8W^'g76J_<[1+Gr'1rm,x9J)060cG" "SJg`*,x'/)2p;ZK,u'/)Pu5SJY5PJ#9m1&(N)###NnX/L_2i+MR#Y/j<.]p*P(*A0+*HwaINZ5AW$CsC$^NO1F*$$6P03M4)>l>dG]@t.nL])jR[@l6S#Mdadt^#cFM-^FU%WTVxH" "EjiS0g6jrs2KB5&.3N$6M-]`Ed*xTZ1D4kunL9@ttBbW6$T>h0f-cK;XF+6'@%$##qN*F.,m@d)HQ`]Jwx2Ru5.2s@kehR#%CGb7'JWK1R,Qr#o1wcuZC`2MG_0U^kZSS%=d;A+l[erm" "1.no%A9GJ(*G#REB[*20WKBD3Lmc)+06;hL/R1N(g#4jL80H)4B=>s.@IVX-?J.`&`hKSu*4qWJd_D&Mmh#v,$Rtko$%iI_vCcPT,eLk+N+.f_@YGH$2)-_#G/fu-PqiuLfjQ'$me3+u" "fv,iWA6.bNxN>p3'&>uu@cUV$)[I%#bTr,#VQUV$9F[6%bG+jL7B&],%C[x6ep5V/olOjLfHo8%.0ihL=2%E3LrSfL/5,G43=S_#x#>*vD#" "Jhx60dkTkuUX:+HS#$JVh]?KG+D=8&7vpn/Wn?/=P^w+_T_,e[ar?F8'##C0^M'(4+qI=E(a4eFsY$-FLF*XQ_&$lH3Q/0d%H)&Ub,26P[]4g<7f3*^B.*2T^@#" "-lLZLuD4l`n]4d3+gMtH[q0O#ovGUR5CH)(sd8%06X:>()O1i_M$J+Sl##)]$s$&6_s-le*;?34vr-$GQ)4d-X^6Z)E.3D=C_#<1Wq.s5Tv-bEVN(F,bv>Q^GX$a&DD3(1J[#3hjI)" "@@k<%GxNW8ZG>v,8ihk)^rMn8F@H_%mFmY#ZI,G*[e@<$ZxIT&Hu>e#.))q%FY(Z#_2ux#hY]s&blS2'_pSm&JtMD+Moc>#6]II2n*J[#S_pkt(h+Qu]=^'D'[W'DQ>m+2]Xl[tMQcjL" "f=?&>VlBZ%UPA#,?Zu^ZZSNM>+f/9&]V][teu7=%9S(v#MKE*E+QQ_#HLtu5]3Prd>eap%9#I&4:7[XA:S(Z#N,YO^D`M(&SNbP&?wXJ(:Ie8%Ewat$?iUv#i8C^#WFN5&F,wd)@?_]$" "tLsu$6@bc2wBk3'X_7w#g^bx#8*-g&V/)VTdl$')>;-ew,?8T;R204JVS9mRubV7Y0L5iMK$30KlS$7>.V" "o:;QVWIkILH2.?8vH&5q(EaZx#%VWcr/TQ[oAPB.nNSch%Oi#?<-xojwYXjEYP/4br/n$,##7&>uule=n*Wsvv-*Me;8l(`Jsece`*OsTp7Q:kM(Y.C#$Zrv98`wXTw<28n`Z$uY29/&S4HPvg7%)<19h(kx62LDq#,._WZ`*Lg*EWkPwA-,l>+X&BuC.jH@E+Q9N1&W9CxNvg;+rJN28])1T49aPVs)gG8b*aC)<-Zfav%.PHr)lNu%1nVS(#" "%/5##7U*=$_w7-#h^''#>3PJ(ZHpT.al+c4,`aU%H:p$R`-?/CPph?8RWX]uU)8A,u6[V#:RUc<)5uuDOg6+;.<2B.*Q%a*.AwUB#[H-?\?fjDH6w8sg;/.@uY?#r3M-6hqs3M%q3m/7N&(H#d+9'#Vu^##fOJfL" ">^o8%(eAj0NaVa4)'L)M@G$_#MQPT1$K$ca;3TJ16vt=Sh[*)$;%o./,+w7/Fd6&4vhB>LFJ=;kP(nDm0(G+#=6r@dl/uS,##3>5>#uo)[K?f+'#V1]/L-hTwKewfi'M,@D*6t@Y-Yu/RN&Jk(NM+q,N" "gcBK-g+Zd.Fc*w$=IY)N7[b/MLf2E4:A,Z,xa:hL-@'/L$)wILMHgiuU26c$Y0Q<-ipLE3xv]au:j^O/G2q,+gYOo71chV$OLKZ-C,)B#S]iZ9:4SN" ")jH2XCj54GZqrQu9Wj^.apBf'AmdfL-U3N0Al2B#:Ut5(G%juL)R_I&>a3U7tYBr_t9%##)&>uu/lUV$Rrun%nVou,x5^f1e<%##:_G)4SBo8%Jm:)3qe+`#Hv-&4hqC.3fmKL)vq0+*" "&?8+4&4H)40LR1M4F%U.m]WI))WhV%'HL8.-/w_u-g$s?3FTlSou_+Q+<9GQ=uc3JA=cfXD7=J'p2ZO%[9q5[VZrLTu>SiORuQ,p_u'GF,i" ";jDbNf9H[,;QYbX-*Gk;@aHS8ZbMT=YDp8;GlNG+*c68%I>OeO^EW$#gWt&#iG@2.RkYq9w$_/)=Ie<_TNkT`)+3v#6gE.3.j5+%?Wc8/ih5R*;O^,28C'>.hQ9)3GbtD#<_G)42IgT%" "[D0YPd_RSV:Fhj:oJgVWtS'w`E#dm8_,mN#`%$nWTk_273eFk2MgCV$,(pu>]uOg1I-PLp&Z<_0PC>Jg(du3b=SD4YT<&pGgMZuS^$In?c4[T'B#x,Tv-5QQJ(oiE.3rld(#9Fsr$;O55Q_$'YPTKP`+9Xl&-V/64i?#" "@4n8%hoAF*Rq4D##mCT/E^wmsf91,)T35N'-aNjL]OE^..+F9%`s9^#;o+KRi*k_,OC__(WO$9.0vN/L0s;1)ojBd%:%'ZYe)Jl/EBCxb'nbb5`PPqu7JkD=r.9L(e3UD4c8LB#8PL8*L(ou.:&E[.?>rZ#>1Yb@fK'.>_O>JCG7Th(4@qFuor]N,T.[8%=ZS]FL^VA(Zm*5]Tb]:`_DR*-YEUG)`'qC4" "'f_4S#B/K)&EQ7&,=#F#?Lkv=nLW[>c/AZ8Al(v#D((X6';G##lELZ%-g,T.Me[%#U[bq%6K%xce:L'#PDRv$=?E1)1+Y/,.b6g)va5T%tNv)4/rU%6w0tD#k&B.*^TD.3$lnLA>x0QM" "P+lq?D=Z>uF64]#m@jt(kdLO'Z1k3GQZ/I$-=:h(4GNfDBxK*$?B[U*4K`5M^RSk480TxkO0u,)Ujv@+6LL'#nJ;h(*Z_.G)Lke$hbi?#%t;U/$h*wKbKh5MF2f'#1GY##<(ku5aVTc;" "'Km8I=Bic[:e$/CGXeA,*-PK.*wt(31ac;-0iSCN).v;-Sk0v_&BsNO#Q_q1P-wp1P-xU:&OQ[Cf'6Cs#l=N`]uTT#:2_-V'8F6o%ue>N0:^&-Z$" "q`V.0b>(u$1EPA#0;-gjY8." "tu%[uv;w8/,dZb3vLO&#;7JV%8=ai0coP`-E&L/)X-?W.(36N'.fbX18uXn*=n$/C'e9T7jZVnu3=0b+8HNJM4.E>)ljVoA" "R];il0N*p_'L0IM9AF-).3$E@,dEN[&iF(h)qj[E33=DW-&((B#o%dL:u*Sp.=r&X%+#Bs&Q-g+Y++p+MO0I##<$(,)" "-c:?#8n@X-U+:W-4TWjLYot1)*JH##c7v@#k$]/1MFE.hk;T[u7V7+MBsKJ1]$E+`l&%e,1bWA#e:/b,8mTA#R($##e,k-$FRj(&F@C/#UQk,3)#P%T*#-n@-#Kst.#.rs1#LwP3#" "4>(7#otgo.?]d8/e2M_=A_g/)P'DOB_n[U/.J,c4dbL+*2b;H*,VW/2)rY<-i$BK1p*,V/IdE.3EK^:%K$HR*vX7%-eX?iMAoG<-UXeQ/s<6u%R;.H)GDhCP7C#w1?1MlV@D*Z)Id;N&7)*H$TM'R306&B:%@#NXjp%Kens$Fh82'PN#3'vlC`)I:.[#U6^M']wF]#cCgF*O,EA+sk2S&Yfse)C+06A" "`6'm&hVD4'w2_w''oNp%Zwns$^*egu7>H7&NWuf(Nts9%]^-.)mGc'&4h2W%&^v9)':][#X?tT%n$h%Om4Dk'L^vTMAd)I)]wxN'Z$&@#L35/(,*4e'c<8@#=:rZ#ItaT%>(M;$Moq.u" "Mbl$,H=1S#lDkC5PspU*.WAt#TjuN'KelHhXqWp%@(D?#[K($%E1.W$Ed&i^WFB'&4KT'&dZW/&&d&0&Ag(PosBfQ&n*wW$/wX3'A1Cw,tj]q%hpw5%Ce*]#aGY6s>cB*sijKR&=xVKr" ">VkHrm$XR&;*rfqAv/X#AZP3'uTk4ot(_N&;WDjp<9cN'c/Mc);8i0(_IJloNX`Zu2$6h(*sKcH_30j'@I*T%=k4gH?c(4'v>_7&Tvp$b9=@;$#&5>#9N_]4K>W]+0M3>5CD4;-RRYI)" "r5pV.HS/)*JC$?$4F1DN@5gF4jlX(j]fIAfvef1B]ixMIo;`$(NU4GV2A)ZNL=u5$#$5cYQlmmLG1t4>b*X%'OYLEO)qjM0gw72LX6h*%#Zig1Pke%#NTr,#O5C/#B,(o*7eim0e&&J3" "4-U:%YsHd)5NI&4r/Tv-KmLT/kHuD#inL+*1P,G4ko)C&Y'q+M$@o8%#A8I$g^Kf3j&N9/=0w)46QC:%2P3X%$6NT/;47W$a4XF3q01]$]f.'5/^@+0j.8$$H33-,+VxA&" "W@1,'##coG3JY:j,DcP>#wpn-N00.DT[#'b*7=@<$CjSV'DT*c4[Aa4'qq>,*bZgq%*AcY#+fbx+)BdO:m#h3'2i(?#)5G>#4-;QN+2tX$K[d%5(&Am*xTWR'1u%oS$eq58" "YoB],:Ks[,(8G>#U<3d*`G$S%>CW5&OKAU1?olY#Eub[Kl:0r/'`sw$KY+Z,2xOkuZS(%0#4FZ0W3q#$+5ofL//I>#I]G>#1HFc+((qP89lb.5ds=A#1m)eF,0Wb$-Ph;-w3B*/H76g)" "9O7x,x9[x6L_=F3.%p+M$J>c4ZL3]-,1M8./^,,2cDC:%iVC_&cQ0QC*rPI#ha3b$VMaHZFU.;Q.p2s$-V(Z#=a9'@;pfgWKqWVUFx-/=0/LABCO)nm0u$oubV-*v8<-" "mwPC+Z8QWENZkI#7)U#$n1#C+S-X]#Rso&$>jLx7>`Qs.FoFGMa0L+*T)5H3.u587?&V*3,N/i))XpU/Jj:9/H.,Q'bCSfLCwZ;-%$KJ1,Js*9Rir0E9Vc>#6R/m&/x8F#WO(ua;_r_;" "J5%[#8XLB#IXC,DA7L28^kp8oPa5/(P>k''/(v%$6%J,V50M7n<754E2jEX$Haq,)64C.#cuc%&6#Ls-FIEdX*0;hL/P^I*lYWI)b6Aj0J#:-mcEnb4?_#V/1EQJ(cnCA-M5mxF/$@m:" ",FcK;no.f_)'t$-B[_G3S2*u4$,M7)Z]kI=rUm^XvjZw'eI=`-)9/=#_MQxgLgu(3wl=C#mc4c4br9s-;va.3[UtQb(r$0ufu'L#>Y[OVk1k3GL-7B#euita$X82Lj+T&Gxvmo%3l8H2" "-Mc##=(V$#qvK'#O7p*#$x=K.mMO1)w_B#$'YbA#<2@R/tt?X-BL75/]Psw-^gx9.]L3]-_`&+**r+gLsx+c4*krI3_]B.*W,`x$Qd[NO4Lql8Pn65LO6cY#ac.WQ[uVd)mJM1*c,=7;" "(M>C$$U9>#$VtA#N?YLUX)R5LK*cY#^F,o+k4G1F?Lw:7s@N)Ol('Epq7-YE^4sOo)*vBxU%=&Sx(h_=h(uvY.:7QAi)YKkVJ:o8L(2rvju-&jUR:N&M)>EOM)" ";c/=cOR'i';p7W)MT/;]@A4)H/<&A('/L$Uah3-bW/1fARI)F*Bq%$i)p%Vhoh.OK`QNWxSfL_(^fL2Y:@MSK=5&<`sp%j9@&v81o(#a?H#8xvw5/-@XA#R4r?#" "fgGj'x%MT/ObE]-QtfM'-Wgf16HSP/kK(E#_3rhLE)t1)ter0,R8tZqd]g^%11uU&FIJa^d/Gb%KIsYlnp)6.]Ya7Q.sc7Iw<6AO2CL97LA>B$jv-tLEWOjL$:HErwNw5/*vwA#;nn0#" "Q*66Q`_r7%xcE#$+PY8&w@o%u(L1_%Y),##=($c$17###Z,>>#h>Zv$8@[s$1wX5&-'R,*l%^F*dl`^#K)'J3?DXI)[1ur-xUXa=%_(KCLbfuu#/vVm/;xL$#JL7%#j2h'#HQPJ(V4=V/W2QZ$" "(4aV$4K_q%QQFX$`eEX$=38q$a@u)4Kk4D#NNg@#pH>8@4MpL^2L[D31jZp.lfZv;$wYIqJK8M#o(xL$h$qL^*lW@X#s#&uG,Eh)2=Rv-9lHb%PW=W6VR6]F:7>l.Ub+%kKQCpk#YPa^" "tp&,D*7B.qw#_S.k=Tiupvh[k@8h[kb4(s-24)s-2S(s-pog[kh3n0#tlIfLcNn##lY8;-%*&##XAic)-E.3sm-H3C4ChL%WMG)+2pb4R^s/Meg9s.VGiY$FOMsJ" "qq>Z,gxi>R$HUV%^``8.ZRS=AP^Zb#9F1@:R]lJ_DQwd&vfUlu.'8$TgC&@^HZ##t*4=-A_i=-+Y$2M3=9lu>FK[M'=75/>U<#.u(cuMHkk&#$&>uue>*l$rAO&#:[e[#r5pV.`?7f3PDTi)" "RVWI)Lq2v6;P8N0@J^.*UFn`aTOG%b-%E%bX`)S#um[quVmmCpm%j8ZD)1=k[;EIb/nV>M5l#d;b##/H&##_$L_4LpC:%" "TBOA#B`or6>cl-$O^,,2-XaJ1CG#v,ZT(02+(tO')k$1,53+Q'Bo-x0.d2@$W.>H3;`eV%IXwBnO`&i%sJs>#wn_)50wc6:I`%%71<+',i>Z3'te)Z-jrD4)tqPK)FO[h-h^?)*hpk.D" "s9-.)RV..26F>r9)e^P:4mhP0CmmN'k3jm/kKtq8X_(/)Zb^quJ(lmuKvrh#e`+5JZ&eS%x/5#T.6U035SbM(]0AhG@Bmo/UpCwGZ2F`+WL@#-0]$CG(>Vm9r5cY'3%v%5;n8Q13ltM(" "]94EIv(Nh=:3v3'RG^88VoInCTSXaulL-'nYSAA=Oaj870GY##J;W]+FpO`c4%nS8%:.Tq)Kps/M" "Xo)T/YlE<%FAg;-'RViL=/^I*=Lgkw?#U,'-h5hpn&^T36D:0eEi26)6HfOi0N.]t11nrA5H9OE$?Bbc+)4&<.5lCA5gOn8/(V*)5B[hlAH2-Im7Q-]XSFJ]NxO?;6gW:;6q)0*,9XAmC" "=+tPZ7>PC5Zs$v&9t->6.$QQ#w[I&5LtD-GE%`5.=fe58^15819gx_#Oss^>GNEm;c5hKq;=J*)^tW[@Dx4K1_B#(9::A6&cZr/W/e+98[rSV0hqA'5jRkSu>>Dw]&(A),xDo:C&IO]-" "ZqPn*r)w^>-4fBJru3GMm].7O>3s+Vx4ct?xv+>%mV2>5'TNcDpui+M]b>K)'K8f3h3))NF[p_417Hv?R52H*hiWI)LOB_,ku8+4(xkj1pC,c4le/g1r[=F3oUFb3S%(f)%lxfL3<+Z6" "J]B.*28P/M#HGA#kIQ1M'8k9/*'#q81RP.BDXmh2Ojpp.M5qY#V_j@t&W8f3m#JdDHVW;6[tF/(@?:g(6JLW7d/14:" "Sr,k2bU,1Fvi=Dm;n1E#hN_%@l6VK,;G123YRcJ(cpPx#up4U8VvGe8@/Gv,)aZj'kKO%,Ra(h+c2Zt1+/._uP8SpIo%^r#mnib*?9J,$%@u0/(?bd*[+Ka4-Ld)4'1[q_*1h%%2^^##" ":t+/(Rdw.:]Hx7I'.Pd3QNRIq5Waf$mI&fOsZMCacT22Bv3R;@sT##]tUF?6nEZD#9s-s$28u=.69VO$=s=I$TL))?F>F,#'Buu>LlXU&>u###Sj^#$Z>-$$6Z)F3;CU-2ZT=5&^D#J)" "c*3K#jNi+i;CTH2.QV+rG2741csv_uJW-4$K68c&1^#pCt8rWx)I6lU0Q0h3u^u#joHU3TEjL" "$lT2'q&i*%@PBSD,>WO'c$0GIcY#lB3O)cbNZ#[saSp^U+]73(qT7TCXS=U[E/>M)jS&+(X5&%3DXIA=wS%SUaB#EgZD*4SYX-BOc**" "OB0M#YXVd4L;*/)c5x0ZT'j%`V$fE9cd<3vu'6q.x,pYPMT%5Xj1pKKu$k5F.)/Jc>#'c7$$R[Su.DlY#FrHd`Ln440uo:?#Fa2,))5###jgn##Js95&Z:PV-D?ucCwtb" "=>2i[302q#tv)j4I&+3Mx^bO#6LSO#NE^5&XX5r/1lFlA_VGb+Di%C#f)>U%SYVMT]0X9<(DN5&e4aiK?T)v,8>vFW$l2S7&q*;^6u6uqn-hWPPbF>#x(>>#5VY##A($##BC)?#upF3b" "?>r#$]R>^=CU)P(#^(9/S@4D#pw9x$/[vuuQS@P'K7DZu-/qw,d+BF*VO,.hk,u#$#4K/L]QbX$T5#EtX#:U%fOC(jg.:W-D&4E$I,?3W@<@0)EH&$#uX9^#oOm-Hn26I+ijvBq%twm10r%L8.wsf]u.A<+D,-ZPAK2M@K,43f_nrZQ364Z30x:R`aFC3X$EDi:O0D?:m_P1t-#u7nLhTA[#Yw/+a0L.Z$j_)e$gc``3QvQJ(SgJ,34.wHf" ",,c[tXi?%bdDDO'eHqT7_Dw`*cG4[-`eQb6WFblAPKhRjpDW]+V'q?-bC:[,0b9a#c_-##Q699.O;O=u;b*W-_5>F%3'ic@$N?Z$M8tr*6*qW-9@l)$kVvv$-8[0#XQUV$[GUv-?]d8/" "xH:a#twX%$sf6<.t?]s$guJF*`;UweSM?p/q#fF4Ufjj1U1#[(]4AXYG>#vDf/3VSR.2" "5WMBYHnRx,jd)hL&:eY#G6Bq%l3FX.;aqN_OpH`0Ml@m0fg3jLE$oI3:Iv>L7&J)ed)TE68*QAA>,:fs<%5B/]," "Zt86&DV*&$G6Ob+bNjd*SVA#,x7L41#3P]#)TS_OXLjR&I,nd)sn=uL4jT7/(1j0,-V`V$w;+1uaeK7&h<[],jR$##$&###97jrm+>NfLB]ZX$fFn8%d(4I)x3vr-^gx9.Q_Y8/+P`S%" "YD,c4E-m70qcY=$$@O+3J[Vv#;2N1+j<*E+axW;R1sMZ7hI@jF7L7]kSbqP8v[0E#-;*'4204V.'cuu#M,@D*^7pu,<@,87Xp[i9^kYg)" "&hq,3hhjm&/8s9)ks7u(>#%S6[0#" "I,>>#,RXt$(W8f3SIi8.]4tB4p>:r.aScD4hlE(4?MeZ$Yb@W$NjpwM;_XCs#2T1T5b,C&XCka@JZo+`PEU?`,.:^ul?P>#?F8##T[U/`**dn]:4x:.P58o&k)e'&G19U)O,wd2(dZ(#" "Lw]:/Ak3Q/AHaa4Zo7>8ukXI)-S8U)6FUhLPV5J*k_gb*wjIb3S1EH?SGCt#SdD)>'tNa[)`L67)G[m/ToMPqU$0Q#qIUT&8f(aKIn5O'e`FSK'XIH?A+xJ5^.UK5aEi;?#`2c:6Wv;%" "tNa%=Z,-O(;7gr6s$+;?Pb`uG].$k1:@i?#^4^F*PwXw6=n+D#o4K+*^s-)*46tR%VS/C4of^I*7c7%-ahh8.R=^I,xqbI).Gw@',KoDcdcfF4d`eU/IqL`$:va.3/+5gLw.<9/#&AA4" ";p=^%$*cN)*.KLX1G,(+x96k(41x.+WYgKr#iHU7S75nuUt5rug@>iFwS.vP$:u2)V+=dtPET6&E%06&Vfg>&.;)S&E%tp%V`T#&oh,nAv>9I$#Fr$,08gV-ouE[0KTxB/3Utp%],fL)" "mc1rE&t]W$C`Y*.a/.#2.-Fn<4u7_^uJZ91H[`V$?&u]79UTE#;MLlLTJ,lp*Dg;-7:)=-4PvD-,n4(.jjFKN-C'g-n@u>@[kH##mcZ(#N2QZ$s[EMKuP8N0C?lD#&1CF*7Q(Y$7-p8%" "F=3Q/E1#`4XMe)*ra70)W&]H#%g()FlPG&=bQs20;5KvCqY0CS)bnXl)+vnpqX45q>OTA#4QccH:-diO=]Slfu$>o[(CPhjba=at6:j:$L-SP8ribtJ+LPT;fIC(a]#E]tEJ>^u8BXT/" "g87q//:jl&$i''#Zr@/L2/^Q(Osh*#;H4.#&`W1##Wx5#Ztgo.acXo$eCDs-R'WYP79EYP[21s.#BOZ6A2Bb./k'C0+=UZ-@Xj;$umf*%[$n^(9MB/:Z-?iFB#p#baawDBI$" "0r0^#70L40&r28/iW[a+-^Jj,)&GD#Jn4uu%&[Kubaue2'pPul&>*mL3)eP<-@6.BOnb`D/]RGk+$<3;3I2n@'CsS>#[*iK(<1Uk;7*J^5^VI/'-g[u^#K)t-U4Sn'>G##WbOF+aJTr*U49qu:di?#fwR[#w&ms-" "iKP+M@u7%bNgAE+<@hcD%`Sa#:pP9M&O,L1QNcx#s`Z]4Zm>h(xA^e$#MK`N@rIiLCQcI)IE^:%U#LB#Mw75/7cJD*gHILMTo@A4OVew.tP)WVfhDP_p8_Q#2$'IWA]*;QMD8R*ZX?W#" "?j'mARC+^uor,UWu6[e-qN#>c()xYQ+wpqL0g=W#2d;;$XXJ1pqcb##AQ_c)pvm+D83LG)I]OjL7/B.*DRXx[A4kp^x%iY$J8^F4)*4L#0lF+31x4^$$XLg(=@[s$URk%$YkRP/v4M_&" "Y*.0)xg;E4qSID*q.X_$TfA_4v>D;?W**tL7&AH#L<&a?+A8&@io,K5uiu$l.w;%C*(K*^flK3fD(bcX33ME+#" "Xsgo.G4[s$(&MT/HD#FujL(]+i(1=`9.mP;^4O$+a4M_gC-a2[W%[Z+Q#:/N>5,O=u.%N.>2k*w9.Aq>De>+]@uMNg`5>?ub%a^]c;N'&=]8oMZ#-8@.2^==*Z:BIL(Qm1)#ZLOgLR-SS%o+C0G`(:c+sp&/1[w$##" "xm@X-L_G)4hbtM(:n-^O,5um%##Fi80%Ux]_4A=vr-+FId$rHuD#CcK+*S7v>#sFCkLjNJw#l;hW.*m(?-;$]:.Px;9/-FZ;%65>&OF^.)$F%JAK^#ge#" "F1GwKqD)RSOkR5nUN8QS:*,n&-#GN>Bc5e5,:4E&xY-K#LPpSM#I]l&ae].L.IX.LSxUK(-iUn#E-F]#/@>#dobV-(6Hj'<*5N's3vr-mZU&$S]u_5P3q_4]xql/:&^F*&QC:%)iUP/v?]s$q29Z-ZQ(cH/03i,x@;))]Zw7.>,[Z$fWjV$umL(*kI-9.hHSW$ae^O1,RlB[Gr@f*6]U;$>M%w1" "OVKiOP'V[#,d1Zu32(#$[J'C,sq0mK3,(,$jEkfua%l.)GbuB+ZL,%57`_:53koR/uKK^9mPY>#++8WE_=Vu/6gS>u['Q,*+l;8/tu]dW'>cuuYKf+%f9cf(e-el/<^K.3okQX-/O:E4" "e4n8%@d#wn@sZNe_F*Av+K-Mr]mA*h,L<*+bigswqi0V[^809@UGDR];%kO1O,)[Q^n)mX6,$1U=oRC?/J_6^o9.H11Vbxt'#,<='VZpu,c`OZ/YG" ">eiP/9.8V?&[SG2_6JJ1ib^'+cUuFD*8###W4$$#[CVS%J)[`*(Sfr6q$FV?Gf98.-opr6x+)Y$;>:Z-V)q#$KkRP/n3*v#<^?Z$?;Rv$GlR@>s%902u4WF30>Kf3.=/+4L8^F46B,<." "-nTD3fh_F*kB%/&#o=0l@t.j^HNN%$Bq/m&;qcV&YKft#lVqi'hvEuHN:'Q#])pXDT06B97N$O#cU<:/#pNV9`i?/8JCaZ=SIsVf1^tdj=lwLH8%" "d0320[%DW6ht(G#uI31#nG5<.kmqc)5WLD3`l`^#uTa$?$" "+gB.*1;%@'_@3(&79wG*`id8/=W8f3QJ,G4G8pF4T2v]#k#L:%k8v;%xTIp.;U^:/KL5gLiPP,M&R8f3(WSiLMQ5W-ZD&RN:kHv$x.6h-]cM*ICF%H3'VZ1M-lXI)1TxQE]f)T/ebrD4" "Yw3eH;-WM]b-fGF=Cw'J,*ZQOa4DT#w-o`C]M_$w.Pi$/>-+j>D/v=[v$sK_hL*&lI)1rSfL/mZ=7sO,G4/Y<9/D4ji-mjXtA,n2b$ZObPAcd>n`" ",&'iNc+3?L^@0NW.28sKcVN#A#6-N`#.PY>#_CF.)t7+i(o(cL6Lm2DNL^rhLoS%`*D9tU.Z?P>#PTr^#*GlY#-P(Z#qxXt(" "]p]b`B3o=-x6vc*:^bY-HQ+^,kpOM(Qc29/trB6];fG(+qo<**V%4/2+_;)+)b3Y-A5Hb%+p?I2T$s%,?v%I,Z#cY-oxWe)+59_.=mlZ,qTXT%oaAR/-mMO'p=9F*p].1(-3OY-=hxl'" "TrVT/E*rdM+R@A,U80X%A^ol'q,,',ugfnLHNME/-]L;$Z1x+M.u,=MQUd>#fHEV&SZvuYeGMU`8FKtN6_eI#F*nc=XmWpukYrH#N9%UJPbqnuKQQe-AdLqLlEx%uj/cJ(fMeH)K=DZu" "l@N5&.PC;$7LwW$Q_Q(+cU=x>EAdb%F*j)+Ho[A,=bC^#VuRfLq4RE.+;P>#@w$@'m_ai*r:5c*p(?:;:Kg3MF'P=(q&Ds/xoQv$BHlj'mC0b*;M2C&?&kE*tLK'+Cu-d+#k@Y6+05$-" ">((+**FM<-/i/Z.^MB#,b$GS0Yn`?#0>Eo&^VS7N9**QN^DH7a9wN?6;`ffLs`)v#.SuY#sCbA#&+-$$.V(Z#UuRfL.bJVm<;hW-s3K&vcu.9&OJW]+/+(582K;MBTb)>G+((AOiI(##" "Ek[s$c3rI3R<0r.F$9K1X*gm0END.30ubF3<.+2B+4Z]:.$MfnU/-u;OFKoAa-d1XT#/_7>6IoH)," ")w$n7.S.,t45eXA62v?6p#;E#6G.D,0OM@,k/SB53RPj1*Vu$,UfmO0`qnX73c%60VSFm1pF&q/0aOq:5N*480i$ou4B7[ud?iD+_EB;E%23@SSf##:W7paPB0I,Hs@#R#[?KR;%MYnb#4sjD+GRJ5'$Mhr:Y_>H/SD_c;u]*L)^>V0(OxMt.$8j50R0Km&?;r11GsV80_5p/3`6Yg;?WjYC?8)j'c-dYL^W`^#=aw`%cG5?#:axqujk]x?3U,`umCY*<" "9g4l]v7o`tYe51<,3M*MvqJfLA<[q7*.]v50f1$#FL7%#cKb&#.,3)##I`,#*$-;#$Pl>#R^0B#qvI-#;FoU/PF@<.N#G:.TRB(4ExrB#n90u.%VbA#F),^$_hCN(P*s8.TA2T/.cg/)" "X;*F31/NG)(Tc8/Vnnq.(n@X-*n,O49%1N(v/v-$qYWI):k>l$J,0J3ex#J*osfX-4SVC,C+7`,LThU)9=Hg)uQvT/O>[&4O/6<.2v6@'qRo3iJ0)iLBe6g)=5kvLvg3Q/jsx`4Q*SH3" "*lOF3)^B.*/54C&eN@K)OKOA#D.Y)4/9x/Mn*B.*7k7:.jLo$$+Ei;.7.9U)426N(E]058L-+O4QS7C#SrU%6)jTv-CxSC490Si)(9*gL?N>g1BK+;.V'cJ(FVUs-1@%lLk]d8/@c.R3" "4LXD#]uJL(p2W=IBYuo7;)`kPSm)pB[2If=CjqP0FlW^uIn.T%&k&m?OLM78H]/QM#w&P9&HT4Eax`lSt-Zc*?`8t%Ed4(v#hs`<]w`euM2a-T&+4/h#H-T%cP8`4F'0@Ga2;8&]+gF*" "@Gux%ri)xluj89+3eTL9Ax8f2YUAn0M%r:#^u3i(u;ws2I2_HihP'dRT=fa#" ")r[ZKvv2.3$JcjLiuBg2*_1$+*fqd-]:Et.qCGNLGeDJdjUR`cY#hF``5M54kL1KihLbL<#_X(@,Zd4Nh$,,##uJPfL<$RQ8cACV&^O18.[lL]=mxIcM" "r)RrZQm1Vdwd8A=8Q5s.5wM<%x3YD#$]`V$x1md3B4vr-ImZ)**[^<7AY2)3*)TF4KLmLMNS6<.*M2T.VVAd)P?f>-MPhw-3^s/MMLit-4emeM@44D#YK(C-ff-x-$R[LM/k.H)8Zr]." "k.i?#7G?L-pjGx'(v-^3fh^,37sq#$W(r?-Sdqg(mao@#LH,B,o1K@5R#(%7pato7)enG;LI7@#h+b**5*iH#lOFX(^KJw#05rQCPE/>66CD39WV8i%28H9%%bvJ(Mo;Q/[5p:'0:1'#" "E/#q;D'%w#kOKV#YFUW-<8Z'6LQvn&Rmhc)" "2Si/U-dRW$vgEI$^:T6&S.d.NMDD@]K`E#lB]OjL(##Ek[s$pT)*4ont[$IuU5/(xkj1-E1l:0%" "iL0+*oAic)M]d8/E5WF3on+D#mTIo'-FYI)1@dKCs?&]$oGUv-%a><.Yb'C4$P=F3,PI5J%=Wt(5_eLMgCgg%EDtH?.ZnS/nqg8/.X(u][k7f$>Vq/=n6Y%-:,?-;(P`uC2bm1G5KS[DV[vAtB_.Ec:q?5lCLF*q*nc;Na#B=*g.<.,2a]>" "A?-v7nMiO'DL1G-FLwa5L;kE*(fFi(bG&60>EqONpOc,D@bH^,3wb)3;(h.$Cuw_uIm5%-U+c+i?p`f3YV7lJm(+$5Xg^@MS)&_uU:2Z7,KkH6_xo*-1LLR'&C^5_nIGo$M`95%.f1$#" "$Ja)#Mc8F*,39Z-0Zc8/a6re3oNv)4MiXI)V69u$WLd5/ZI:E4j@u)4$F7f3>(>>/n?vg)^KOA#23f.*08=W6;?T_ue,40S5b+/(9MERZk_ipjC?1*TAaATF+5" "FI6:4cTq3+d1Alu_kmL;$,e8E.Gp(6IZY3D9k_^+._gf%hr_pL>hEL-`T`AR:QE%TX1'/)%>l(5/veh(oa9DE;FG&#$(6?$#&5>#Iraf/`^''#vG:;$s-sH3]D6C##F/[#'(L`N+hE]-" "@qVl(b12Xi$;=GM^GLEua<%Y0)mXj*KCQN0QhPj#mxvcF(]r2MTD%T-e+ob1adD`s=#%TBBAtIL6#=ns4q>R#0toIUBL0wp;*G6sw.xfLmf9e$r=F&#,-(Q/aH`,#8%Fb3'=Es-wh#c*" "^p6@P;.ZV-dV_Z-Jj6d)XSU69Rrac6RUw[-x]DD3VW8x,v:^;-N+0bGcBwTKxQfT%.r>V#%;u5&LDC9%a^GO'waH)u:3]vAdDDO'YF:q'0;PS7D8uN9$f8h(rX;G@,#EO'n#Ln3]@`pH" "91*p%pc<309GKxIR]%/_'v_$'&BY+/X16aX85>##Ta]*%S6[0#68E)#m,>>#]q.[#Hjq%4hqC.3c9FA#04vr-ZG+V&cf1E4Rq@.*h&ZP*$iWMK=^.K54p`W#uD2a=%T,5(vKt<:R;omP" "X7ss$RZG#u@9rV%.1c;F:/Y-*+tjMeX(T^+/8KPVkurOn8Z6pBj%9Nj1]$ks20" "87E5&Rl&=UPWwJJ4A-#,pC`G#40$%FCFLLXJ`KpMn`_FZg(R>#C`D:82b`]Ugk2$:`:px$Jq&Q&Ab:c*otwo%LfL5#" "0GY##oKel/9?$)*Z&ID*^nr?#&Y@C#VAqB#B@t'4D+GPAME_s-[Z*G4UpKB#?u4N`+EC@&$qHB+:,[@XI:#5v_7L'/pcZnMZb6hkE*eo#8(=%b:6(nul-#`Dm%NPgWYHt.:A.##)hiw0" "vp;b7GSlHlAD%NM0dM7#_'Mv$`=%#1]pB'#mp@.*S4d##>a?T%mv)D#c?XA#)*Tv-Q#6`,n1pb4ftjD2d8/HLD8.[=@8%PsO5S$.;8.SrU%6qs5D-PcjfL" "#;/;%h+A&4_G6WQvae##E_=eb+N:n2`+Ar'gaV=J&,nc>]PRwd(+fk#uuu[jUV$SBP##OMOV-Hf*F3`oXV-+UMW%GAr.LOIB0/`xC`a" "GO*C&%@&I$M3Eh#NGNDu)@#29evlca:7'L5###[X>eux=%)@=qIx:FB+wDi1B^/S3M&TIlf($Oe)M7=h(r5A&l@'_L(#_pb.gaYDMLnqj(l/h)M(kd##8EZlAU[SM)s`[D*Vg'u$G+kw$" "IRM8.jghc)^^D.3`aFD%BMCv-`?7f3twC.36XqhLsY]+4`;nW%tX8f3:'PA#(Tl]#9)MT/oGUv-D*K6&NR&Y.c;ZpgVh+4w5<**6%(O+'8Pk2^:c#%Rgxa+2@SSq(48E4L4fQ<+n.lDq/X@]tZmjAR7*-.*QVvUwL(sD^qx>/YdH3N(5V@d;2Z?6QMiL1tBW6(KriL$stxT&" ")I-jB*'ic)Y:G'$^c<,#6->>#YlR_#X48C#2*kH3PXd,*jeNT/W%H9iF'r-M_12#$^69u$ikkj1&.,Q'@W849uB(a4dOSv$;jE.3v]H;%)$&f&1V*T%OckDoF(0t%)A`X.*hLG)p,D9&" "cPwenAZ3Zj'2jCY$dZC;24^_;:7USBC" "d]MQG26?(F5:qiHn/HCI--8>@8&ha+QxYcCJjX&#SXsYfO@$##Q3=&#U#oa&<-)fPW-LXsU2_[Q*=q3/tu>jk6@R]F]X'`6q7kCh'#0iUV$6@%%#_QZ`*GtUH-Z5Xf-R`0r_*h`[,HX4SMDf9kNw?45]CJoA#DoUs$QH'<-&72P-1Vx'.ZOb,M" "eCFQ'M2[`*V=AS@ESXV-Vq'E#?;Rv$Y^D.3/%T:/rcXV-[jb=$AX%u-lf,(F^Dj%$iL0+*S.`$#W97f3diMB#d)UM'AG+jLrME.3b%Vv-<)'J3L5vS/mZ3T@NW?A40Gu@t4UN<.,pv5:" "Pv6[MPMfw_6)1>GdL>V-`cnX$PAp$u)tT@tWF+nGcJ8Y+5<,A#Xa4Q>B3ST%1JpJ)EPrSCOPwZ9q$BJ`jLEkQ<3uYR;gw9D1obS%" "IRK=u2#%R&ODaPA=+HR#v%3X:QAUJ7uhwE+WXG8%IlC8%m^`d3xB1tLi8#]ukS$##d%c^%dkfi'nZai0oZ%##(uv;-6i(P%/K6C#:5Rv$ImZ)*5HSF4]*`+v0YqJDovsY-U*m<.^ct1)" "Qw&?-hFO.)bVq8.(4k0E%'(<-[Wa8.dmcO*Ch:_$+W*;Q1=(&KQG?(WSYM.[LI#q5Y/M>.Pqu;:>tu3fw?Mh8RtLLGdc2XSaoRDOm,3-EjK3&5p_>#7P=.]_l1YXf10]Om21DJXx*];k6e9di" "ax7@'^s_*kwFR'j[Yqr$g%b&#D5fZ/%jp%#p:L/#s->>#/`j'4HduA#iJ=c49Z5=4'jE.31N5<.cQ_G)RtC.3?_#V/#/hcL(&Jp'&=wAUi-:])+5oKsP,Lx;J>U+Ld6`]RR=i#]1%-iw60o`8x.DXIh6Z=L6A(KamF^.VR$w8Hw)dT**5>N.]%peI8%kpH[B5G_W$" ".Y]O.6mnDXEK0b*D3hUB6P3fUmngoW%g%#`H`,#.->>#u)=g&U$1EunVl]#FNHpSoSUZ-0%ugLGtZC#$`^F*q%K+*J9v`4.QYx6jB@X-n8jQfUAV6Wd45cRTB9m$bO3>7On4V/*(PKf" "#thR*U*;s6M-(V%Gkhg2=&O+-,8P$,mT+fUaYa`$+hxJ1=oaw$)q]/1km5,)90r`$*k4g1P@Q=#4sTB^.daeoNY5T953.4:P:I.QY+EK;Zvnl6KqR[#`,7j'+$c$92I&4u4*Y$B4vr-[5MG)@$HIX@OZ<-&ZFkL0o@d)X#Y?->bPb==odZ$@)xtd" "KdIiLrpea+Y%l,4%Ct%,a8Hu7KBw_+$#P%,KH<%,%#5`+2Zp[#<%^_ulAOmLk`F;7.s7TK.601gJX2%B@qXjN'E$8MqL3j0>PLu7W(m,41d_tml?eumW%QwHvC^v7(I^n)X7;t74a.f6" "#j'##D7NT..Yu##555S.,PYV-&:;s%x'5U%;H^iu'j7W#k61nu(FLR#273h#V+%/u/7ElY)5-1I>x?o#8&MK$w%G>#:@E7O[305#B9t87:&>uu1rqr$qH5+#2*]-#Tst.#j`-0#-SE1#" "DLg2#]9v3#oji4#&9J5#<8u6#N]U7#bUw8#>*'u$Xo&f)LI#<.>AIv$J[G<.*W8f37K6C#_DuD4%8?1M@9MhLaP&J3oncD4SmfG38`/v.]pOA#*NTe$n`e;.5er=-?j>116TID*C#*w$" "dhlG*)Qf]%_^<(N_DYP3Q_V%[Bc=-hW)(+#UPcM[+?iuI>kq(QK.H#R&pV$N3_?`@OgxX`)vn#E,vG(WRxP#AZE[,dg*ci@0h;(e-MG#" ";xV=G)'2cu((7h(KXo`uGOYXW.*[S%2$[N#f+1S$eP]v#<(oRR&@BU#,_tAue;Nrmt#to.E%_>#u*Zn$wEGF#fgSXW43s@$;/Z$0NHluYN=4Z#2CU>$&0pp%MvQ#5O=3E**2OI)#a-V%" ".'`C$imAIK#J9GYud31R#5;Q7n9.3rm])X7m3PD@&84r?#8_pQ=(/5##(S_V$T6###Kqn%#I#fF4$&QN)" "DuDT/MD,d$24^L(8ghn^;JmV#gKF0uW&mN$i[Sm1W(?X7B/E;?#]`fCNl_6a?\?7%:8QaMc)?C%##AEpD6]dUV$Ua($#U-4&#M,>>#P7H5/nsFU.NJS)*EOI6/^c>>#5aAgM_6$J#J4kbM*" "V%*IF4;F)9(vrW%uVA=#e&U'#[U4G/Px;9/HUP,M1ZBj09x;]-+'&J37q@.*1+cR*4`8a#f_.u-+vk/M$Fo8%TbS['fI#KC4f:HdF3*dRgT7DLwpv2lUnvfTURkY#ePRBfYD-Pch_M2l" "%xfpDs%+&eBKZ00ht>CgY:]gGA)7.T^MfSIgx+>@6ctG5`#J6Ej^xO5_:nC<48c*uK@n<.u@xA#,=n33I@NG8ZZL##(AP##&R9f%JUcGG]=dV@3C`_>6uG'Z.Pkd=(jPA#rC>Z,$r&r," "rob[,$Yk]uJ5ALC8%0I$1Y=R*@KCW-D,2ZX,)x'pbNIdVwq`R1LZ_-SIQVENUHd%k4Fqf)^>Eb72=h-M53ULp#YkA#%O,W-ZKX_&=9Y_&b&Pe$R#]RXnGhLHe?*T/1mSp^4mJ4SEQCGj" "J.HP/bVw77/GY##0+no%A9GJ(QDw%+sIdCFS/AZ5D>N)#ToA*#eI5+#u$),#/Ur,#A3#I*b9#gbtM(,Z&KMPX3]-.nE:.W86/$F>`:%@iP8." ",F^:%(MbA#lHuY-d]m--p-h_4n=EH*9EsI3*pP/$OBW)+=;_j0X&l]#CDXI)^]?<.LIEW-xg)I-*^DD3aiaF3]ei8.[:.s$m;8Xus`BQt0lPj#1W:;=IVPS.?Rxt'=5T;-H4r5/S9rkD" "Ax%&4dHkL:n4aw$oNv)4L29f3G.,Q'-.2t-uBQcM;v8S4ohH;$YXb'VU2HgG3IK`InOZmb&YWQieF@&,5@C=6Rhc-LiYiL#[BiVh`ew6NeO?nM4G*/D" "#`bM(@,CJETsZj'=aGY[D1JV$;jgge@JJBg`l8pM_VEg4x9.w_xO_>,r:0b*<(RFHOC8T#iW-lX*/SYJ8AM'/a8h*,p41L04(XD#?S<+348aKcf''u$+dfF4Nv6Zc1&=qk3^,/[l3+8dVI/nb^d3`Et7/-okAua.97;JYHAF*^5#3J75Jjfd7&hRr<1C]8P'L$Fv#c@76/x0?,*MaNjLYFPO/Y3=&#vZ=oLb$^:/gEPJ()=Zv$H/XjLt6LF*N/ob4JUh3/-4Yd3" "nqR*I&)]b3^c,##FJ1I$9nJ>_8.VtQ;s7iLgIu_jO>9e?X'1,)8^;v-,T&BXUiD<%#,>>#]u@/L*VUV$8Ujl&G^CG)I@$##d%lV-2vDs%7;LZ-v$TfLti8TAe+A#.%E6C#p9%J3Mw:q#" "h,'U#jJVGuj5jouV3v7$h^FU%0+k[bFCkou/(1J#]f#ru$KiG#o@>/(WaH[5-0&6(`.s.L0%9/LEs]=u#X^2uRx7/L$)wILNT+2T>(Ld2`]sduvdHO(HSNI)h2h-2Qj;A+&,###ZY9)j" "sb:J:[=*GV_)dA4'r@8%$;Ls-JS%L$Wrv#'XqZ1Mao^;-@X/KNI1F*Ll_v#?VX1V&Xic)PYi=.l((=%(BW1)OnAf=&xE_=GN_mSkW>mT^TUItNeEnL;,;]7" "96`[,VX0##N=n2Ln#jHOwTBhLhL*KKGM1P8Y-Yik-6aak4)uP2E#HpKG+PSND#Qbr0#]5?q5.sg[u,G5()eU*I-'3j>$sfXkLF1$##(?&W6Yu^##-l68%" "2oZrHW@T/)h-1,)Z.65/aGUv-]:He4gpo8%p&PA#?,7E3']0v5x42#$1kVW%&,]]4dWZdF7Gn]4.-w)4kPu-$ox>H3)'SF4Dwl05&[LVS%TclY#BLnW$_MRh(DoNj1XHpQ&QBT6&@R#6'i#?R&D@7w#0m0QAv=e(Wn%fOSUp9?,21Dx?*O*Abq>lZ.O.[cElW:21iugQ(09H^+:j.^?ux?`acckILgX_5L^9*Z#B%mY#" "DlL;$H:R8%W>)W%aHB:%P)E&+EXZ(+0Hu=$N&.H)fRb)5FlIwa0Q&,###0Lsp%skUf:Al,AF:E-)*3`jj1Rg;E4" "OW=*EtrnP'b3Za3B4vr-DrU%6w+m]#PY?<.6iZx6+.;t-SiY1MSjW@,j^Aj03),J*vE')3)pCv-f8t1)?;Rv$s`UB#*5@:(iIj1'cdl?D$jXn&j#6tA&1p[uIbdT%:VAO;Wteg7NgAE+" "1dpwB7BpuGF%F8/kB`d*G&KO9)=+MC[-DV]:#%/Q/#E6H[g8uc(g@L(AghKMxVG/L@hh3?0-[C#sVgtNg4o;mBRr(:Fdi(M/WQG,OI8M1h(^:/N0.,*[1RG*9NSeGdMH24O3JJ70+lTu" "?=g+-#Eic):r9%tgr`cGs7w(#&,###Su@/L>Rx%4u$fu>XIpJ),5*j1x-@x6S+h.*^tn8%Zi=Z,EKU&$_'oP/sMYx6]81#$PVjPJN:T;._R3<->LJv$b/D/LbP6tu^84gJD.Mv9sB&W$" "L4irA?Us?#;FspLOjr$Me%[>#IX`rAFZqY$`rGl9Qa*au$x3V7du5>#iX.H+vN#D#/CYtAidj9Mkm8b6Y-bPCo']I4uJKt:5[n:&(2S1(u;K;.2=`[,wBS<$&@)`+&RZ7d#gQS@#_69R)mHJ@#HT+B#0R)6kOCiV$J$Mc#qGD`+XjZnTaq9.1JY@W." "&s_ds%2PuutLC;$d;V$#YDpkL*^/%#X-xZTg)Cm/(_Aj0TAOZ6dMI%-/()]v7/08F^uq@3sTUi8*U7.#H2W@'O#U8Ai'SI2?uT5LJ#oRVE/LfI/L" "rL#JC[Imv$b0HHe$hX0MN6fK#8/'_-IfEFeq3n0#[)###Ro7/LgJIV6iH%##b:Xe)SaHd)HLc+3_vq%4rRx:/7GU%66T&],&hJr8B9d;%6QCH/R5t(]Z(@_M]s@QMdTWZ52/`0]Ju_#%" "L`(k)Z0e*p56-?,5Utt$9+<7O0TtxbS?HvX'[Mt*F#@MMVjdn*FlmtX7$=tAjW9J)R'b6Ejl0q[Ylf[g>3[Cs4DQs-2%AnL+]fF4(Q@dF8[kD#lb3nk-rdY#scR]4V?9r.oNv)4SS=?$" "Dbi?#o$=G%5Nllka8I*Ma%>;-E+UR?cxm['D&44O[Kwxk.*AE+$rCp.u#X-vWGF2liwoP#H%0T#ahQ683eLO':=;7jR/5##)]$s$T6###c?x=^TC)'#@n>V/iQ+,2=C587ZW^^-;a*P(" "^v:s%5&JD*_6Z=?e>cD4@vU2'845B$N$2quknhOC+aCH2KhHdDHGqT7tb^B#v][h(x>ge>A%[v?90brQ_[3E4`Idi9Itk64P;[S%'9)8&g@-:Mf36e%?Zh2NO2H-5QDx89n'%##uJ]9v" ":Uws$nuv(#W=#+#*b.-#>#Av)w$JKnb4?D,c49ZY&#EnOJ(?Y-U;OAgkLK]Uv-jCXI)E.ZYu;[iNSOmXW-*N?HFtwgN(=aTJfmCG/f1gfRRfusma" "3oT^Tb+gmu'fCZ#@r_DIS6jP_$WN@tJGb7/[AYjukPJn8M1`CA9gNv539m0)4H$p)]c#'tf'M*1bILV3`>#fB5+k^sT@tLx.R#37;X-RM)=(A&WZ8Q$YUAHBKmu2-X+jIhvNWAV)Co92s2MjD1dOup4XA[to+):HRX)Z:twX0Hh'Ys)]],[HOv.'RS@t/+@8%?HDX-" "xmBX(X>cuuqqZS%)5###i[P+#)9j$8tDvS/Y#*K,*Vv8.+jE.3D]Y58$7U'#CqC.3s=9_4&Z^88(Qt2(reJ/LNNYN0:3T=-Z6Ppk$>o@9>..nTvbK(+xA;6l>iaid'YMp.O0PZh'an)VBAtuJmS*%]%*)#f,>>#cVWI))fjj1/whj(d?Y4:.,`*4,VW/2i_Z=7Vb7%-PXw9%'PMT.Uj,/(" "5Zq]4+xOU#$jF+ilCDuOZ=99r%U9kLW`4o7M#8^#%+3q-E`sn*Gv%_$&U1qu,aSM0ge:dMA>1wM?.LLpNA2R/Xu^##Y+pu," "VZ9g:leC*4:vq%4uY2)369.+ZtN#EBXW-e?Wk)" "7r/gLcK$##Tx^##x@PS.25f&4Vf*F3g+4?;Rv$$cGg)mx6:eX@$qYVO'<]d8/nNGj'IlOjLW;K_401$gL+,Ad)^^D.3$F7f3m:n>Pk?`[,Tg'u$ikkj1M6vHZFu5O#VE:E=GVcw8JSRT.7)dO0<9Cq%jXlA%9i%`6Z:'^7)xCj2-WMk[Ns,@+" "8@6,*bNYI##N<&*%YZ<1#7DW)#+Mit-Z3rhLg46N'$%$xL" "/of+4O2'J3f[Y4H$J4$gTWa*.B`w<(mNBR)-7YI)9Ko.*pcI)*M@.s$ARgY%AR/7/*l0C4bwc@YKvq0(*iNiMU-.7:1]6h*eZg:%UtET%mEEs-awwv&,rIuK)[X9C7%[+M<>fYI&Bh-." "o:JD*T2:)ejfVmb`0WjN*e7p#g;UW$K@&U/VmCwQ_hn]%09?x#7TNbN=vw<&g64[79.eYuk@emLFoe?Numo%au/'#Zr@/LYsf*%#R(,)b[18." "vsai0R[$##'G3]-.-B;Hh67`&3KkBI*t@X-jj8.$wiK##QWs-$TF:&54HNf.#1O]ukBuSK%Up9)n24m<$[A2+;X6/<0N(11&lLpT?##UjxE%L*_4.7a2JO[NL+*]nr?#HXX/2`,^e$v#h;7*8_e$9jE.3TruLMK8-9/<=[s$C^eiLnopcN" "d/S=-V.dNhb-xk8_3_A1th5^.UKu.UOw0uRdLW(>`H[-V+KfLQh$##0AP##ODB`kA#M4B0%ejS@#YQfU+DQj@tI(65/SEt7/&AY>h*m:n$rwnB/JN3@VKb4R*0Y8E#>h_>$nvm8/UHlDMPf$ju)#6X1%gEJ:x#T.UI)aPCNEp_u?OoR#inJE#6a/auob#4%#o0gaxx3%b']Ps-fKP+MC_8+Mhk0A=7Ls9D(,pu,2SBqDX;/d)Unn8%$rh8.wS0<73>%&4kg-H3',Bf3" "0d%H)U4Do%X;jP_1*31^/(b**&6Q1(eo?pt+f:BqEn$SV=b&]tf'Y+`Sf5tLf)@)(Mp%tdg%q-$5JbTtUfB8/[hMlfQcR+Mi2$##[wDdMA9V'#6hiH-O9iH-%(Wx0G>(?AH:[S7Y,FYu" "+u'B#dIGIS=fB(MRo.QMV&pBS.)e%'m3hA#V<6),d%mxkS_$##$QR12.1Fs%bDL:%iL0+*5hUhLuiYA#qc4c4K30@#9Y&>(id#V/)x^M##G>5I$GjLWH1^Y#'It46u%U4Iu9hCZ#:H,V+8vtX-EiG*R8]li9Vm.T&R*6r@gB'Z-:^c)6Nl^=#-8bR'S]mRt)5###6Dt[t4;Rs?R5QlJmm5Q8Ai8*#" "os4Y#=F7@#fd9B#<>WD#ghlF#CabI#M]4Q#iB9U#a+Pu#3PUV$?1[s$xg;E4V#vX$`a&],:@i?#[P[]4?&?g)vSC_&fA9F.1I@1MFT()38R`l%J)TF4/]NT/5=Yj1lk8a#YH-)*lU9+*" "s)wS/Tcq@-9RGw.CKWa4Rp#f$P#JekAIB(4Xq.>-fj,P0[]8)*Eh_F*gw)mL_,<9/9WRl1(N^D4t7IH*p`[D*/N%I6&n/I$:^Rl1t%2B#/.aa4,+H87;'UfL@B:u$.aJ<%K@[s$wqSfL" "cc6lL7xSfLW,f/M2Ci8.`20X:T),J*r3Ye$'8^F*G@q-MB%NT/./:1Mb0WY0$g(T/e2ob4]L#gLpVI'MdaDE-MlP<-w1i&Mjtgx$oFSx$-rxfLnHPA#i,&Z2al@d)a&SF4a*J5/&Y])*" "TZT408]sD#VeTx$.saHZ4(ro.IMQ,*:lbk1MQT:%5M]C49>1<7F/ahLtA&$M;FNT/cDZv$cIR8%EE*jL+RcGMOxMT/OEV#$7,$C/%Ij?#7qfG*K&(RNlR.K),*ihLGEo8%(QK,.ClLGx3+37N/R.x^[+4)]9T/)GPjLpQ,@.8:8C#MVk;%7k'`04R%6/0l<`#jUBiLH9dt3t3v_+Ye#&4I`.60gTUK2DG]w-,35;'i7Fk:1Guj1ZZ?+GN=2+GI_]:/dabu-6mTnBt+?`F" "k.?c#8E9:%6#rN4kM(@uN:AY*iZj4`>HU,)XG%P'Y'KQ&2PA5'>6&E+[6F9%pl)q%69vb#7mUY$psJw#c=S9&GB/o8E0$/,q#v/(m70&$3+[8%ONQL2'&%927E45Ob[*]-nB^]=M1WE6" "Mo`V$2MlY##ZOJ*EBId)a4xF6LZrK(c6c,s'CJ)#pb)+InB5'AK7J3S6_P'.59+*`i1Cai&OW-@/Zo/UwC'+XfnE3" "xM:g_N8PU.^6*D+n$BK(GjhK(;2f`*=wfYX:`%S4TQC8%@H[--4GPYu%uU;$U)T;$]U$t-QJG?(QxAh(8@[W$S$4p.g:DCX,w[kT[-cJ(r=Y%5)oi;$<..s$GtjT%R'==$,U:m&pdX]#" "333P]Mnc12ug:K(/5HA#xOMn8E@xG?Y0,O4&FdE*i6AcBG>$E*Y#hm&nh@@#;J.@>KRGJCn'_h<`[@Z7rSN>#9M/a*H()v#$xtQ'^s>/(wn>mc8*Y;?1N)69BsLZ>El5kOidXp%R6E78" "uv.i)uW&W$Rf#(++-i5KOp0W$X^_;.@fQd+@>.3'Xw]*F1W@D$x>>sDVFDF*j,Ba+BJ-*j=`w)*qa06&qec?,XsTY$1tnK:Tl9-4" ")F0^-']''+Oenw#.Ml>#`A6$$PfbV-e.j.5SJ(F*lSn1(Z3gM't%;>$(A,,4;XYj'IUIw#BD8=>#&xw#gD)O'wLxL(*Cl(G4^1^#^MvZ$p-0_-Tr_3=Ur2V%eQN;7EXxR9x)oe*B1@W$" "q%p#,[N9q%'@qf)PRrP,;.L$/(i==$.(`h5mVvN'==Pk't=ixJx)uq23xr@,jR:@,WWjP'i>Iw$=PE$8bkZjFIt@@#h/hP/Q8jh(uTq-M<,x+MXp/2X]P>#u09N'%7;/:(5S;?" "=))v#8=C`$8K056m+fs$L,'N,wVZ4'5-Ti2LU/e)0>cY#ZlxV0)[4T%os+T%_1ffL,jOI#ern-)4AP>#aGWv%trQ3'o-s;$afZ['Q%.^&[1[L4W3oY#_3])59:teN>#VZ#O>w-)^KpQ&" "TO%seh?>s2c=;v#gh65LwKj:8dE]c;##pa-w%=Q17#9(V$#-jKS.T6mH2S^Bm&ROr_,?IR8%t05^$7o7T%i:0=%[l`jNmo6Lu681%B" "e9d7@.n.4O2MXP/m%EtOs#eT1Yu%hEbPw^C^-TvA@TLEEE*H9u4:2-<%8n,K@H5k3i/(pIY;-detX%[`c;-2g(Jb>e6s_M/)$o%p%(gB.*lf/+*sc;;(tui0(Uh:7;.gDO'Kl1@,;-h(WmQ]v*bF.<-^m7u-jm/UM&.#pu2a$mA6>aILNgAE+(oCp.Mf:kk@mx4FL:LxBlE4OM`FoC)kup0'OVEtC#$@nRJVff:2P%L9cNw*B.*pve*.86&;QVM/@#Bj.^#h7MrMx?H#$^nG^#HLv_P%9X1B" "w6qA#gt.)/UiK##t@J&Q&B6##'7WM:tlIfLS$w##?H?D*+t[.4Ss2R'BhE=-oAJI-+BKe.$h.##x11V$a6###@,>>#jCh8.tm9u$`Ld5/Ti$s$ax;9/*-+c4+g^I*pleM(57T+M#@gb*" ")KYU&i2NA)(O&n/)/p^+Bwls,@4Vo.'$@/;;OlA#Yo#50i+*[$D8GX$r^HwBYA(v#T6###I,>>#GA*F3+S4I)J=[20<=2W-$o[@-F?Ke$d:ZLMGO^C4N,k%$N0FCL%B7Z7olGftm&'%#Uqn%#n&U'#4pm(#xCDmLQV1N(iRG)4LS)W-6Q,F%Mc.Z$S_x<(pA+P(aZ'r.ElP0P3H6qV=jlX$,xkA#" "GW'W$$YbA#ES2h),XK

  • k=#rj9qV&pT##OS9>#40AU)$bj-$w&PF%/G]q))rdgu%#@KuNt?KuR3>uuQK&I$]&=44J8>>#jach#ncn+M%4pfLw0YCNS@$>#'5>##N`9##@M=U2WFQ9&" "#&5>#2GY##:Ba(-0%J(#Pc/*#O,8GP/-:4.DN`hLAw9S-esvl._:8u..h6T-[K-T-CYlS.@.Y)4V4Av$1tc05hS%_omqdgufHjqrpPr.L)EGO-%G5s-%SjfLsbA+MKC6##" "1%g*%VHM#$#-.#N:#7A-lwQ2MH*oJMPjLs]1_pt[&uH-7E.'VZO&9hRNUM;k=#Op.'5eaQk+JFDb.woEUMKCY'#" ")&>uu]mUV$1TXgLI=2'#dtu+#2$###PD)c<`;YD4GAv,*-tuJ(*vC]0O3ng)c?XA#vk-lL49[d3Hi^F*b^,,2ZQ/[#9&e]4.%^:/jBuD#XYPs-gV4jL6RP_(rvK,VlH'6&ix]T%'%QG*" "Ix0lOIpHD*esV`;,$m24UQiB#Fm-)C?EvAJ3^qQ2CIMlK@:e31x2kWC^[8>81)j=8N]);(;hTT_i0h3.o2Z#gx?8['Vd>#5*mxk$H2oeRY&)GDcG>#FGj=%U$/bB+b0(GBolY#" "W81uAq=?u/GqBP4#8nS%dOs:8(5cu#iKFf*eJP<-CqbW%e@NP&lg]f1b3%##D_i?#I,=jLDU0N(l@@[#EO=j1KJ=l(mOd>#ULD8.m_)Z#cE4=$=;-x6)eIk9;@h)3p]HRM;$RQMTL18@" "RxXEVp[M*A&0i?#s7.[#[`1?r*Vcj[ZQ8/[SppP#+FnH_Yi&j*D^YQ/X`t1^^;>&aO?I60@[aB#a]hnui:1E5kU?O#lUijuBm.[XQEF+ie9$`juS?(p2uXCf;uUJ:92R#6qwL/:?fK/)" "/b$B#=tjlaIw1x5nWx)vD-L/LUS$%bdD24'24K-)@X-dt8w%?AA]n;84L.nNKI,XV?1&pA0/973u,q-O(&BH#&oqN)#;aX.#NoXV-xb0B#" "J?1K(--w8@i;BZ-5kRP/NDHT.Uq@.*Qb?d*RK$<-ED9c$J.@x6q(b.3bn%W$Ew)w$gDa-$wdP9Maik1^E:s^#a^[h(q>B@M[[klAB0OZuCUnm/24UOBn)V@#2+,t6'r'32s*>@$3t(GR" "'.n(AS/oQDBrln(gk(eGNLw7RPOlS7$hJ`a:*1/LmvUDt$IqT7v22I$,cXgLMD`9.$UfE559O2(j8,22cPbT:r2)Z-.I@X&H$j#`t7e;%H+%9Prswn8VPO&#-7ni0HdSc;4e4/(T`*i(" ".Av;-_Xxv$Am6/(?l`^#_#aI&.6MG)6oor6;?rJ)#o$],AdS=%k*eX-Yq[P/hHeF4uRh^VC2*3)*[8N-,a3N1@L,87[=vm0q$LF*e#W-MkF4jLTioB2`qvo%c:cm8TbN$n]1hx8^J/:82u(l8rJL&L=l#']AdKY>,OW9`Eav>`'K6C#'@j?#" "_LX'1'5;G>]fD?D`@gT4*D89f>YGi'$SuQ0b(-N=-e#r@-k]?3#-4Dd4%)k]7PCOa,f#tr74OrA?W1g=R^UZ##'b)kbGd`&4eUs)#9->>#jBFA#+U^:/.m@d)>Ydb%ejgH*" "dCXI)kHL,3+DXn-KKTe$uu+gLnXMaOWE--3+jE.3?Cq%Qnh)3Nw+T%4@0;8Yu:a+Aj-A'" "WXJlMmUqC2EFUh/tY29/NVmW.&:x50g)uU%l5,$0[G958*T?Q3Ljr.L46Ei2k523s0'Bc;+4:+GlRUpLj?do7q&:'#" ":j]##Urdu>Qegv-sZw9.[xU8%Lr@['%If@#kHL,3/%:C4)e[FNe%Pp7<_:E4t(4I)^Y%_Qr%MB#p/2T%JPEb3+g^I*W&4e@$SDZ@gsOW7jV-A#b+La#3g#>%`Ds9)Z)u87I39.H%h%lB" "e9`d%Ls13=q[3,FOJ%R3OU=13>1R.)`6`B8m+_f#;<,<8cY*3fWvDo0xEBD3^)YoRR^;fq2(P]uk`hV%90At#ApA(:UWWxB08GrD.rwm0FKYOD6i6##jI2@S]-S&Cu8vlL=2-Z$NV%JL" "Zr@/L)vq%4%$;MBQY'##?f)T/a,hf1pC,c443hZ$PWN^%eo`GZ,0g/E39%i;$>LRI7roE_$u>8@SmG.;1u)l8EJ&6;HbP4@S=B=rZN>TTW+jam1OK9A=*+QS7x.[)E/gii(XCh97'+8@#Y5kVnq7X+*KeXt.]uiIL$Us-4T1Q)2EC)S:" ".`kE4pK2oeo`DZ@H^]f3g8)^u-bar2F`NYH/vq5SgNh$,M82@S%>q8EjPdfOQl-]#59DU'AGv98xYYa<-jRfLK[`MMh@Kf)&,dX7hL+_48x$o%d`?980Sj2;`0LecFJ9-uAlTY&38w.U" "C)#e-Z0j'2Qg9qfoJ:X%rLJ3:&;'?Ib3n##MiKS./H&##.e_F*18qW$]Vd8/$:Z-uiWI)B76u68B7g)A5mG*JIRQ/?DXI)B.i?#c0cB,,]WF3=s(Y$" "(TLC&F0(A$se7`.H@?/GCQ:n&gC-LBfQN^L6F-Itk$bO)<$L81]:/YLFj1G2:?-HO1R'?9dr/u2cR,_D;B-_U/gU?Ga@cvrgs7%MJ=%T6###u4C/#mJc8/SFu)4UA^;-tk>_$#k4A#HHJ,3q&(T.q$5^$#YjY$#2h8." "UBo8%%?#g1%r8k$@MrC&0TID*3QCD3Ye4D#)p6^ZaP8f3P%;iM_l$A-w3]T%jT5#B&nfvw-n5'@S=:ar$jNC:/8D#%Lw]X;/qKHGM=aes6" "iZ$'$UDwS%:K)]-(%Ew-Nhx1;NmY]u'`['$iaKU/M;]M+QW&&v$fAF#NFiO13P3u+1wbC&H`m0=u/%;ZQ$(,?-$Yj*Lc?8%2m`S&k7&(7=>5cMcAvT2J9rc#lc2:8m:)?ukb$*/**ER'" "mB[&,$iNxF2E,A#Agcg3Q9t7m5xU?#vpGR&Bk9:/^,txF_+iq8_ZJp7^wVw?9a;MB4W&##bl@d)FjFdX[R?2&dc``3*bsO9n&/n16bWj0a[NT/4tFA#+g^I*<_$@'?o`U.Hl*F3+4.m/" "&7X1;ZZYg3ZL*r$^SU:.*pI%5b&lV79_9B-$XU1;I2]IE<#ZjBB?VCGVw)8A.5s8(SQvC3ElV20O$H'6:v`>-Wa/.$A$C/Lw:bILOj`h3p1->#2RS@#0A_mi>?dr/lH5<8#K1g4SU*J<2EYkj,0$x>?H;mi?,)VQT;x^$TuB[S+gP,E6&*L#,iA.$]=rs'+5v&#K1g*#]4n0#n#]I*?*X)4VxRji:W8x,o:gF4<)]L(*^B.*b5Hj'43,H2d,]+4bT=u->r_v#iL0+*.qL]$" "TYDB#wCbe)x3YD#@vE?%0Vh;-JVM21sbfM':]d8/'BqB#5AsU/m>:Z-gEPJ(xAJa3FND222)fl)jXrIC%&xd(M>A4Mg^W>h/f849Ve.a4OK/e4Jn4NT5'a;**H?V%VC168G$uU%w+HT7" "b3v`sfwn`c9-97;'*X68%W'6ri^Ml.k31q5uY'O+H#u/=B6&9XIG;JK-.)+jjO]TB96&W%G+'" ">m*%t+1r8.IZq,)Z74R-#7$]%%fDM0MHKuKH4<9/>Z)F3)d4+N::.$$bmRx%;)'J3*s,l9gkP,*WpqP'Y@@[#MEG,,6r7Y.b-X=$w')6:6ghp%@QVW)FcAw(-Z;h(kU65/DW@VB" "Jg$K1-+LEp7,n0H21KqPbQ/$F=B$^w#'(5Y%St*t$G$Tj:En44)@+:J)EUsP&#kxJ1PuFI#vtTRcQawT/tOx9&C]AuYK#9ZHV:C%X" "'0DU%:WrHaro%])pZx<$OM0u&7I*t$Z0iQ;=>Wm&PeR<$9%M;$Q*_h(rdPZ-2^f'/fMut7&+lA#R5p%)(r5Z5;m8e$Nf1$#Cumo%mH3Q/nnbu%F`5J*b=4gLU-9GV$)wIL$Q:GVtHaau" "<@I=bO&?GV$c]1B7e$C#:d()bOo8du0mpquh1Zn*hu#7*`2Kb.4A5O45nZH#nUZX/Tbd##wOd-HnC$##d$872Kx:?#L['t%iPaa4[PD<%o'Mw5Xrvi'%n`ianU;W#9&hrK6vB/1$.^u5" ",*QD*8XLB#Kaa/0]v[$R85dQ#Oak;.[sKD**k82L<3_88RAIh5[#l6<)7j6?NVWsSh-*$#_QI1&$Nb^aoHm#K8;D4$J82igX7MrHD,O)?0'.&=AA[+M$7xi'Rlg>#lqMv%$b8%t(X>#=Z_=?>XF=&NQo]hTZCZ51(N9N#/w=V#P+>#eB[##?\?(,)sg%##" "#dq%4UM>s-Z4TiBD=_B#R7.[#N/*E*;v+r$e4NT/opc20/%?87Jwkj1=(e'&BU%],n(TF4$5)mL3Q6_#,TWhu&oC?#P^(Zu$_j9M7E3/1jMIBougxYoL5h_J)" "d?h3:aURN1*+d&5mIQX7JU278qZ/>@6LLZ-eJM^#`T_,`9[:I4>%AR#Qx=^@9%P#AgX]P'b^pM'ToWF3,YOi(gu2'o" "a_d%F>kM<%BLgr6rd%##*h#30`4n8%&Nc8/59l'&05^F*^t[s$dq$x,VxG=77C#hLaSAf3$JYQs_n=/(*9d/(KYNV9Wpm/Vk-Y#A;aX:&V@O8&j+R*I_E.#6:0,o/'KRS3eYC+*@GP/*" "%J]h(nxsI)BjW*4$wKV2)i5#Hrv3V0YKF'4H)nf(sc'@M&l+Sn/_jJ'mUlQsHIG/L^ndl/VB')3t(4I)R4U8." "<2`^#)$fF4@x(RUWq;?#keJT%.1jr7@uLruDVllu[Qtb@V`T@2VGU)/Af3=.GbI(a@F879T)Gg-EmL#8v6olu/&RRNQ8uY[tO1Z@p-sA#.xvh2SRP7elRQ59S/Z]uCvJfLa#6.[s$OS)'#HLD8.)V3]-`)RD*1A]C4?l`^#xa)*4jnrdcl1>c42kDE4Rx-x6AqXt(kg?)*&eff1%a$W%Bv[s$6%@W$A%7=+ZFAE#OBd@X_L`DHD`li958^4(>Z^W1FPL[9O;f78=%)5###E_R%#n4n0#O6^l8T$K)(LD8.0VKF*a[2Q/?;Rv$m1h8.Ww9a#'sUv-n%qk1dx+G4m-mm'_V8f3XWLD3sMN?5=PsD#ffWF3" "g@AC#+g^I*0SEF3V2QA#xDc'&L@'E#TC@[#q-63`YiK-'$Fkj-I5qv-6Qf]%DC=WHBw/*$E%*TI?kad#5o;#,3>4w54h1=(=LIs$rM;n:]ej`*`5[)*LiHrUG>VQ&=u:'FfM1>$rFOI)" ":nuw'1g=_/Rs8k9[c3d/$f@aFt.2;&$[QS'#Topu`,umu'(/wK$#UB#jRNjhoemq(;+:O+C0[f64E829BFbsL?'ub`BLt8M/C^oYS)d3'^e%VU[9'O=fV,eDmlL>$#27$$9quw',4W*I" "V.n;fM=I1(Tjln&X&'k,T,F[$n,M.5psc2;=_vZ#N^Xv-:oe`M2X&4OX#BJL>aQU%t%B?f8#$crs[uY&fKhFt3c34]P)-5Jt0.t%])cxX1SW%FYRMcRHi.^-%C`mjR2`:Sj3[@k^m^['o<@L#bD/gLx3XStd3d#v" "$i?8%IDI8#]=oT%H:IP/g$+A#GVsD#[+]]4hk$],Y#:u$ACI8%0x5Z,GQ:a#an@8%kCXQ'kVPA#&_*G4RV,<-+^Rh%D2(,)J1i?#[TEhueAqgEN`tsSi9PZGhQbfM'dZr=6FIDw[5b*i+rgMQ1_'`l'Hp%p%Pk)Z#Hu,qud1G>##1EL#j%^E#=dhRnApY'=?5iTfwLI<$)wA&=?vdI2Yxsp0vY.;%3fi^#2iM^#QEtT%793Y&" "IJVM:;lJAerlPa=qYnr?J'9`Eh%u,vfI$&C2;#ERjRS=%)5###(pm(#nG5<._-5N'_qh[,UgX=$qf)T/@2`^#*l0C4DM/)*>[e[#rO8U)C'Rl(a-]P/+g^I*&TJJh&gWjuqCG_?" "%DF5;:pRkTYAwfuqQXP'&(bOm*.xW#'LvxXP3G`W%`f'I03t/d.5iPN%BV_SE8=(R3t]XP3QD4AfF7lE9='TR_Y_v[nnY6q'3(/u2s`:Zn-l+5O[d7miO(]8SG)f3/E#k#7]," ":qvO]QgFP2/f=0EEx4)JbKn*tkbo(Hq08$2,h+u#jYZ6Q:#'v>9rFMcj+iWrr9bJ#%d8L6-MQ3san`W#AmIH#L5.SB;H6`^5M2VB]DIoF$hdg>PTNHko9pf:/3A7#+LQ_#NV%JL0JE/L" "fs9D3Mml0+rF5o$A*Bg4S;w[H0+l3+h9(,)MfbF']6=t$.9_20MFblAdDDO'jXZe$[ZrGuBu%?ACcn;8PXB#$BFg%uYrh/)tmG+M0bB*@@A4i*FF56R/@#mAC/LhLYxH" "gw*bA2RmMp,Ylw8Ie?.M*.8DtSh7TgpF1U1F6*r&4JUo8GP7LdV&hW7_YNE*^V>2CSM&S5$p=:vWaA*%HWt&#j%/5#BRUV$=@[s$;Wc:(R^Va48I`GM-8E.3&L(E#GY;H*Xv)E*UFJ^G" "t*l:_Uc$]-[GOw9x1ur-679_-G,cw9L6nO(vTFv-<07IM)T,G4c9OA#I5^+4sf6<.hp?d)Z^D.3N,n['v*TM'&c7C#)$fF4ijaL)Vf*F3'1Mb7m1L-QsfaI)kX2I6P)JwBHkjMglK[DE" "sZb]TD=LdRml'T0E6iI3W:l$,I->9LM?brMksm5&xaaU.d-/?7ufVk'b_[;8Q,`0(,4q58PVti()VKp7ZXi`+G)@O19Y&'rs5Mr0q2Qa3l?*?6I7'nDC+qGgBm`(,m%JP'v2JHDVWeND" "/asGFA5e;NN#J.dq:Bf*XLUW--1$g)nx3f,k+0U#d4a*F>rDw,w5O9cWc6SVJ)G9UKe>lif#,rfV;9I;aK4M[@lLVsDv#Z/CA=1gj5J]A[^$" "RW(O'ctw;8hjOX$+_E[,nX_MF5c4/wLG)dBXA#3^,,2*UYQ'6D.&4'D+^4?=tG2aOQp." "wiVD36N%d)f[K+*klaX%vbUM'.u`-(>%1t6?aL4I9]r8Xa4/<$EhwW$,%ScM)#[R#Ab3I)FrSh(,nHO(#kiD+9jqB#H$bp%4c:v#@_H)ET?8gudW)9/Jdw.0M3QR&W2*mN3Ur'7T^YaI" "Z;)i)cbBd)7#1m(.FLw?t+l9C,`t,+`CR<8BU_P'v;E%83ao>,$'`+=1fZ>@(1;t%Afl>#):EX[/wOE(kxN3LL`08.DqCP8+m/DEejbm8JoH#6,$1&AiAGA#[Q>H2.A0+*s;-dDDO'0]oDt6mAxt(/Lg*h1h&ODe0p&" "oQ(,)$Z:D3$xix=m,C6;B2B.*xm@X-595H(j,8B([Hfp78uPH3EY8/LWc6%bqWd^#+M;$u@2MBo^66t/<7(p7UgkA#.3(M)H:kL;.6)I6NLej(MdN##CFE'N(T(x7#/eJ;6l)Y$Ip+3)" "ru1'#`5ZX$3AFa*Z#(9.iE(E#xb1NKD,vG*@'2?%u[vo1cR%H`c1Zr%wx6d`3TRd$E%hJ`[R+V-))n@-wUknLH#>c-tQ$32Q30%#dj9'#cNi,#3%%s$>L75/34#j$URbv.&+*m9gbI[u" "Q8v7&^5#-+'khU#`@)W-,Bx/*ioA;64Xjp%JM@dF''BOM(6Nu5xFbR0$&>uu0oqr$/9fo8B$CB#*^B.*+a5+%F%am/2CfU+uSwL(OQlD33,EILNgAE+jH@E+T0?VZq,g[uv+J`tGRKe$" "v++,M*>5,M^.<$#4HW/MKTPf*p[)<->R9E#O0q,3fhM13FC=+3N;gF4P7i#7%hvE7/PiM#M+_^uN2Mcu^TJM'=,(tQ2Rbi(H6:((=IS$K=f&#(bu+.-v8$C#bnj0,)OH;M7NVJYU'Rw$" "57###dWt&#[_/A=K1T;.#Sm29699Z-0He`*SDTa*1K6<-Ss5X$/eH)4bEM;Z6N6##wclb`)Ga+M23cS74uSDtaBv@POHi^#(J:;$L#7iLidAE+emo7/+I9W7mCTqu" "S029/'aVI/t2l'&%X0F.%DS7#&sxXu,uqr$-qO,/fKb&#)v=']F)4I)7u$s$%=Js$ax;9/)$fF4S<+J*3[B]$p#'n_Bsi<[X-/%d<-@2.b3&:&P&htDL']0HR$m4CV$OP(P&[l3_$Uoqr$bw9hLfv[(#51/Z$*@c;.1WnuLuIIa$5JOQ)@c)T/2g6*0EsH-)Z#d;%-l1T." "fl,<$'Q9k0+3ks$J;w-)=YYYu8?/x$>+-Bt*>2vuGm14'Z(eU%?BNvPbbZuu;4dBt1.xw#(xCT._bO-)+_AG2'&>uuNfUV$*Mc##IXI%#g@;=-iAhW$VWeA%2Q$9.9.M;$@V*w$;@[s$" "#qVa4#%Ql1JJ=l(nX)Z#O-97;PAo7e6E_s-mvTQrNdMlu+RKp&Vs)a*'h%X-jM;k'SGF@qU30SnG[BGMD7s+OOakA#IPVkui_0XZj]Y>#bfW**'*=q.64NU828Y:QPt^#Z9E@C92B*x^" "vldu>S?4<-*Y+R',e^>$iL0+*P1[s$KK(E#a^D.3_)l6/>#MXkAuZW,7$s;9quK+q@MMdFD>#1m=da9(M,;+c`$'d;,##'1EH_tp_4" "eh5UCA.4K50.X]=`ks0p)%w@=x[DO#dOnG;Z]n&0@W+KL;'Qr>a.AO>SPh%Od(JfLs'^fLQwT*%+$-tL5Lo9&U_?X-YR)v#njxw#%aa@tBow+kdpn3kDq+^$JwF>#CW$K#w%bTu'b<9#" "'8I6/8:r$#>0_1N`f+E*:/5J*5F>V/BVw;%x(V:%?oCkL);Hv$$cGg)Y(^L(MCr?#a',V/=SsD#)'xb41M6]6CH:a#6-bn/o:^+4t++E*[j=?-:spb%T;e%'h5hFEh&7/;9Np@-d#>K-" "e'bJ.e-]hMiqOO)/b,F#/9#:C[W$4vP$'WVO`+bo)xb1a(v#:(;Z#" "XnW:%(Pa]'8jCZ>'/###9)g##Z'x+2XVl%=)6&##BS%W?RlW>-+Zp;-o4oi$m6it6)c=s6<&$D6RwJu.xL]C4*utA#K-bTB5;@A4r]qv-[1ur-RLn20sN%],A9uD#*e`Q;hi)T)BK7/3" "?f,VQX4CrQvU5x6'?7D6G9B?HMti?#pd8%t`AaS%6[#++1:*`H]=eZ#Lq[w#" "I;:kL(6)&7Hg7t%mCNfu*NtK4;vlZ&a096&s_]Q0a@uv,?$6u%049FM6RD0?J$###$&>uuQ3N)%SD-(#Pf5x6Z2E.3rHV@,gV1#$Ub;P(^XQP/Cm:9/&'k?#ZmHl1f5UM'72i?>vrM>#" "es:AF=o8.U`v8%hk(5[@]SmCWg8mt#e*r^2BdHPJ.piJ<;=D+*[1@cTrN4EnYdOrgcW7c`Sw$D-^qJ_u.FRb#YkclA0Txx=NBwBAul-+5N`G>#<#(_SbhT&#aH=3G:9St%A9GJ(>u###" "FctM(8t&T.:_G)4@>pV-1:lHZH;gF4i;w4A6>w;8Z7wK#R)mTiE#%&4vcMD3e7#`4^AUv-?'>/(" "-K_D3.%#cjIb/YmiM1^W8-s&<_IQ:*9+dE&DmE" "4tbbK&CBqu$KPW/AwJauF(bCjKnOT%a&R3o8SHO#r>l(5O;G##)]$s$?7###-Mc##=(V$#e5Z]4(VTN(UvPJ(PNkA#4<0iT*f#Jt5^4,Va->1p6Mv1'/_(/C:tTfLatfRHBb#A+1hm[X" "JEciK<<-v5C@n8.J?-/q=aUI*KG'##d,;o0eAGA#PJ))3[qwm/lbtM(PDRv$Er8gL+HGA#wCvhM^<&fN:q9a#N&u6/8:=m/4JJC4'cXF3`c&gLq[i8.[GUv-R#SF4VO^-6P-9_8IA*F3" "2=L^#$)A9(vX0^#,4Vp.^I%SV+T+7*G&5^$GL%@#]f6[-VNeg)#/u<6FC*e+e1in/nqs9%9st_/c&E^#XUL'Od;-J(%h:+GN1B%b6?q0(3gErLCSJ874SY>#g13x'HKX>-(,&L([;`0(" "w(2k'boK>#NQA#GYiC3(2%32G4),##/$Jt%S6[0#9->>#Ht%K:MLaZ6s0_F*-JWD#JTfG3,DsG2:2Cv-Ut;8.J-xP/C*9Z-A3gg1<)'J3aiaF3x1f]4_4jlCIN2L)?]d8/H.,Q';Fn8%" "(YE^-e?T9V5tA%bC[39%QUW+/<(`w,51lM(Oci?#@^[h(T((c'Eit]5lcHS/&:D%,>6T[u`ogI?%2n8E/LSID[]Y',1*BR/)p4_5&]POBTjo3/D=EFEtlOw9XWCh1rphD-oErk%mD*l$" "o3c0Lh6KW.aCu2(p/G^%+i,nAYho:/Jq;*4rpH&><6OKSO.tM:7rjT/<&Dc+(r=*G`'hE5a,4v6h%se5*7ZR&)lnT.;4i$#[Z>L1jAqB#D@A(#H>:Z-J+w'&Q2kA%8CXMKQ`_XulTSi^" "T^st]-+>DN_#&4Ej8ZF$/vQYtpdJ@]Tp&tv:b='p?b+v7HcE'J-ASLCd:AJ1hl'b]-=0" "Khg-da*P`LB&sl0CwJ[#5%Bc3PbCJ)*[fs.TQ`9&dQ5-?>d8T:=W67&a5#sK+#/sKwDL9[sGb/<;Bx+>uiS-)@btX.-wcV/HDYb+UuXfC>fk31vR[w-t]Sx?wfu2<'STH5(QjnDNAOq0" "gvhg(cgOJ4HlG>#BsXd*@Su$6tY=G4mX`H4Ji$##SDMT.Q3=&#FuPP(Zas]/%M3MKj9;X.`YH`aCP5>#dDDO'w@g;-4=Z<-dX4f'T&od#d=^E=U*^+,K:HuuHm_N'?_l'$b<3$#bd0'#" "Z####-svW(&+6;-K'Ch1S6j?#;#hv-8o<_=&W`B6;O2X-UB%9iN:NfU/T87R3c*cixXkA#E2OJ-1@tVM7Z/vPTJ;7[o,O44_OFO'0+W3`a9W$#/:7R(u6e%Xk3>->N*J%PO6q7td?6sZnvu#w%>>#3PY##S=ho.a0%###wT:%:2Cv-f8t1)l$U/)b/v[-?S<+3vZM`NB2B.*tZ'u$<3r8/=$5eb>@tgH*Y-p/t3;dKke$iUN0v4Y29/S:h(EB/GON'=bNlCIC(%M:Ji)v5#,2RjUv-Z)`3X/Oj`%@Dh=#k=RvGPpO9`ws(L+kQ'^#" "_YUe$03#A#`%U)Mshs.L6(SpAG(>d3s`rM1)sN&+v[4'AWf`$PM>hU_ShP.@WjnQMS'aQ1=-I_u6?>aXC[@##xoaEu48RA6mJJvL;:@=ljD,A#Zk$?$q(b1BwNM(&c3YD#Vvw;%IJ+FNN*QZ%" "GEgh7eH@Yu$oR[uU3]]4JL@<$$ue[uMsGa*'9tp%KNU+M>]h+(EqNYdXet?0$lwZ74F>HMeqdi9ve+%lY^D(&0Owu%&),##sD3`srq5>#,7s#laRDt*L[%@#m(9gLJUSx*;-JY-a]Wk+" ">JMYNd;-n&hH]s-wv(tI,?Mj9YWt&#BE^:%UX`v#CXew#KjHD*6@@[#.A`76U-C#4.r/$,L52uWmNT#W%720" ":+m3#?Q'`a?*9U2poteuhDHld)BgqJ(4ED#03MiMtYQe%+w/sNeVio.uFB_4hF;?#fc%t%9fh*%wOmZZ2Sk,2Qs@HuL^LwE$rg=Pg0$_#_E8MZA<8MZY)uIU%AeuciGsI#&frlEprduc" "aY^V$>h=N09(V$#dpB'#Q_/A=U8=l;tc-/(*O13(KVFI)]$Aj0LNv)4qc@A4Rq@.*CZ0S/2E:ODxnhHu-PNh#4CmElS]kUlF_s?'3`>=-g#56'(5?F%)v)3NWIRAMmm)($KAoJ;JFnt1" "IKP`apoMIL<=1J)n#g*%FHD7*N####%p=:v%)%W$=ivA19xL$#Qke%#@F;?#R1E+2bE1,)kg`.3Sm9u$c:o+MmwcG*NPr$u&a*Ri:Z%kvf4&" ")[/k0kGq'u6KDGu=V#O*s?5oeo9*?u+Ci*M?QrhL=&gA$CGFV-f+vxk5_fi'hmXc2WKBD3]s$&4]_d5/+'PA#Y@ZV-=ZrG)jCXI)=]d8/Dd(T/x,Tv-=D,c4]WEb$Hc:@#=>+1$9krRN" ",k4;?1?jguwt?Ku6`6wB2FfI_eG?2)6Xo:fS>mXu'VvW#TGmV#u$Q`a3c(k@T5EPA+AN:B.Xe/lV.5xC3F7%E+I1;?3I@$Lh7]Eg#l`Jf@JnNX9P^p7R8gqBcZ&%#w&U'#h^g8.N#b1)" "x_'B#m?&fN=+Fb3w_H>#*TE-Z&N[L(Lov[-oi[]4#UNh#R?)U%Q#^xtijUfq$2;>>$Q:GVVfgP/VKF]uN7Mpu3x^m&jJ=Gi31gXYHb'f#iJ7I$*]&&71u'a>?D?Gi+2;>G$UBuuxTKY#" "%X0##'Jo%uPKA70%9f1Z8_jT%cc8_8A_m>SC:o'Omcjr96@_'#0GY##*SJV6J+65/`0uJ1h@^Y,kh^F*s+K+*'4(:)&%ff1r5B?-&*(V%u>@8%cO:8.cNof1g2jTD/8+3.'#QQ/F]mE?" "I31R#" "i8%P';P[Hd](]s%]MR]4mbeu>@:D3k-IA8%=f)9/vBhhL#N/[#g7+gLslE.3&_)rV%+PMw&fM0xt[j7xt<=q^+pg@f#(mmr%fMQr%" "vP:U%PCqN(H*c01jF^+*m';D+q@MLb?pQ?;95k0E8>Rl*Q#pa3H[`V$*9,buIx-Mf=$AT#$,JkW?jw$" "8sDu0ms5ulK(]qFV=fV$Huo'&R_=w$9q'&$LZ-YRh,0mQh&sbIgFBpR7Spc5RghZ+pb+Sn:3Pk09Q@>0sc?_R$V1@EY.2@=0a)e6t6MQJ;CaHWx(RY9>hR[5qbQ?Z_B;fc'n'ZJp(<(3&##I^u,;M&wC#NCI8%Q6FA#jAqB#TekD#%8o]47/rAMNBo8%)4`/2hF.$AcaO[T*H'#GGSC4$L[+4^dw>@bXfA@6PmV8" "txhG%?.[8%KJMcVF#$QH'u$d^a5$nuAu/C7w#I2dOG&eQu@far+*s1/1(6^.duelJW$_<830pmKon,MlY#b(JfLX`;<%WuLulL8A#,07NP&xGYc2)B7JCMM'##`QsV$" "TMrB#%)TF4o2Zm:,ce;%:2Cv-cc@A4k&B.*t:7@'v)@d2I$Jw#9tT&$qU5l1I1%`,NAa[(;Jh@#wK.v#x+NK4s^7Iu^oLO'rg%[uTUjg(@5E.)h.St%;pSU'ro?ct@XDh'Zhi?#<:[lS" "7wHY66Q8B5OcG>#/:Y%51#1w6cA5J_q[3v6RcD)+CDJP^1o;&5w[dR*sAfY,+;J1?&n^gGN>q1'8Qr/1;d,U.:oVh'&@BiK$t.[#9n.[ux;vGET&xN1%&Bg+jw,;@nh?22w`jJ+XhX@>" "cuM[$F=j<#uNi,#i4n0#h>wmi.%o$$qwkj1L5=c4Sa]G3*tBp.G$5N'Y)c4McaJw#[(KF*ZY7%>S&vG*sKNh#],d8/OD^+4.UZd3dbL+*Z#[)*Jx(t-'9J*Nm&u9%pXNv66Jg,NXkep(" ">fCZ#nKjJ)-f$E5CT##-.V@:/#SVc+2Z>v#^+(J).c;V.7Rap%wN2H*tYf5'@R*T%p%;B#@Ows$tmQ7Aw;Lq%7ScY#qr9R+Q5ds.N&X1)2[t0_<#+.)?X1@'l4'TW0JHv?o_F5ME#R-F" "i'K=T5mlT%vs-C>[vP9%#<[M'aTM^/OJH>#1VbW6qd<^I#3Fb+OH^Q&n0;@,')wILmUbe)LZYN'xR*@$[5&*$n-b1):26a2NQ.0)Lk/4)3RWb3;K;;6MV7U.R/?>SOaRq.kB4##TGdt(" "KG.on,j1oni4n0#26k-$&/]/LHCZf:<1(<-jd0'#4pm(#T%T*#u0;,#?P0UucM0.G(NQAYTR+/I]-fI8F@$]'^#gX[8A2(5+%G^A:)/Mo%um;nqMp7;J#rDQ<--L;=-8@G)Nq%GKM7I.&G,Yu##*f?8%" "1G>##9(V$#Qqn%#otu+#^`-0#q@$)*^8p;-a(;T.?Y(?#gJ*$5Hq.[#Ps$d)-Zc8/a;T,3fE9dOHYb/Mi1V7BFdZh,aNI,*ltn8%9GtT/Jc7C#[`JD*" "*DWX(YA4Lsco]M/-RZd3'U_r?'I:VZI&9a#'@&Y.S268/#w@R+IGU+E(9sX.dxZW.TnLuPmd.F.neMZh03ZH@(>2:2dermL-BZ'A7Ok*%$.>T#L#4AOfMQr%mcd;%wmlU%8N8i)`Xis%" "is#n&4i3#fa)i0(Tv$ZXeR^8/o2%Q/QX6>#[A'DN6R_'#IaF52)Nkv6fRbNlj5x9S(qKH>20Ne3w/*R#26]e_%pfYH,f?qM+E-73n?GX(UIg9M6`Nj08']5Q%kA<$u[=jHgJb#9oUv#W=18.cGMfL?$85/GF;8.uiWI)7#WF3NP,G4W:AC#Xkw6/M&e)*1rSfLigTM'4C=X(jNRF4ae_F*L@[s$jWm3+]@i?#/DnA-[BpK1@XI5/W>3,)" ".9+G4:X)I-k)k<:ON[;%3ar<1Dx'+*PNdN&/N57TauO_:@.c8fL2" "=G[S@kMH_+.Ate)0x=M(K`g&%-Mq[kXjAn/Cs_N'[]Z0+&KYI+_3FS(pKnNX7Vx9&/+RtJ2VTe-1e]-U7qf3*b#be-E8VX.g9qV.5NI&#u_^>$R[Tg1%i8*##Oi,#)c[:/" "NhVR8.>lD4<)v'&Bap_,q-6QU(<2,)4[EE%+#K+*peH5/l%AA4SENJMIWx;%w'^:/" "1_4t$UE3t-%REl9Q-eYfU&Af&f&);?6^&##M^5N'7a-#5?]d8/OM>c4*^B.*P[NT/@Dn;%jo%&4_@Rm/]]WI)^JbL)d&Z[$L.@x6b^#V/B-Tv-%%(4+g+]]4M^Ks-x2shLMtW9`5w(($" "rU830?U&Q&[#ff36k@G*8(JrmK?D4'a86v#6t^11XUY/_G+pT%rw@S8[grU&7]fiB9>NG/52#8hruuLU5JCXT^`3C0Tv-GTqc)5WLD3VC9a#/%L_4u*'u$bH24+a@i?#_FL8.R<3*.p+WO'1]DY$" "dWe+4SGiB#LW@,MmdxZ3k6f[#+=tD#iT&],C;*P$6gpR/11xU(k3>@$jp>7&0gs5(:fV-(B8mb<8GN@_`u=?,$Ai5M^j/:VSsq:/n93j1^mb>-V/Eo0Obs5&rLMulG5Gp`Rf+D#CCOv#" "C492*)b#61#]JT6rN0)X[8)hoR/:cVZ-_>T&Id@WZ#U>5tln^dRP,ET1TK;ne.Uff8'B*&v#uu=>#fq7T%^l1A=Uf'##" "w(ZA#6JG8.<4i?#B/W;.,b&T.]Vd8/:IQP.+E6C#axQ#6(g&KMuu=O/2^A.*cmZ.<$vi<%o-3v#Jj:9/IR7lLVX190Sm1,)O7%s$-k`*.Kf@C#@Dn;%@E+v-uLOcM9^e*N)xBF*G)IW%" "H.k.3FurA-6C6j21l/0:wc,Aui<'+&5np:/hoNo74CnY#B2Hf_uwF-381ou.en#ruwD'x$3%]v$xW^wi@ZHD*$T$L.%%Uf)7r+T.mCY>#0t<#-n,LM#^70j(4?t<$PCk^4KJsvQDTR4." "<@qSo8E0Z->x<5&GV&f)v[DO)m.Ae)uXdR(q@JZ,J+rZ#90&'5,?0UR^rjx17EnE-UM2A-4e2E4XaL80k_PS7`nR<.Jk7?&.Y4N1V-=B#Hc]Q*1;LvdCM@5/0i_V$U9=.+Jum:Rmsj5A" "fVE]XWdLn:7j6D4#1Wi6tg=r.$qB)=+=r<-6nXucg*hh(drIo@5';G##HpP;%5,J-#(Ur,#Vst.#GjL_lXb$2RB4pm<:.Ff@C#Qo=Z,c:FI)ACq/)@5]iLqbZ##^^D.3l[I,*BA3T%YNNH*$BO;$n,li)ln`u'`980mSB3&RH(&$W?pm0ovb^&)C;)ET4;^#S$c2$EWQJ(s(L4ob.(dunPS[>Sh4',j#N@#:q/m]l5/g@0/AH)jo<**AYB]t'vO-)d]dWmbACmnOKGZ[8%/-Y`3'&>uunZ_r$V4=dZ(#t,>>#'U*r$H.@x6Kf^I*%@,1Oh/[D4?\?EE4w'dd3" "4DXI)Qsd)*+^Ol(3SMT/xwmt-o1)E4q=@8%fSc8.&,]]4d6,WQ=xC;$L(4,nf$-pNa/bd>/*Vj;<*GV#d4R884a>s4U@e3:4BhA,R`Sn4cM4/FGPe0jU:WM0BpWv-lb]+6TcRh*eOYrZ" "3-UtV&6QSsS;&Z74X7lYXoWi?YE+QB-iw-.Fn]`g)i(Z$gq*)3[,Jfh@*7uuvX?vKK_:aQ($-v.16:_,,8`iDZA,j;X9c(do8g%#%9q'#>bFoL>*#V/gK9t8_J8f3F%>,M+@j?#u^3H$CB&K:et*&%$u]A$YRF31X<8,U@W'P1gt.v7_+MT#Uu3H/3+te)Zq8%-.ks`<<$;JLnYn:9[3>kMl>b%9is?.<>FDJ:BUbT%L5CB)j'JeiBeXahYvaFHL^o.$JtQcQx,_e*Dgw2UQj/b>)I+w7;-a0C6x;.^l8mA;;[GtnYl]#Yk[s$TRX^," "l(TF4h]q*%dI*C&Z%Wv6DXHu@Yt&&vU[0I,RkJU/;h&n/?7IW$4eFL>MIHX$fH&n/=#4jLnN2T7K_9i#VsPn&sd/W7@w,n0Oe#?.,GN0(ptp%OLmUd,GoPLMPS[>#GcK+*&D(ed_fj'&l`.$p''PA#QH)P(C&;j$" "5H7l1I9fOCu=Xs6?W8f3GU*v#OmuT5dguN'Q^3@,#6-@7'u2R,#p&$5`@.W$^/pa+^%R<.b0Eq.%0lP9^9#n&LE0oL_KRK)Xs^r.XCJV21_QCJeh3t-ja2?8v1#V7hF-Z$rABW$TkAU/:bsm/@7IW$4hXh>O[mt$g<8306>2T/k[1T7" "LeBi#V#m3'sjJs7G18j0t]wa3VH0U%Zu0##M=aQ/&Y#N'+K%R&IL4K1_2j[.?gdF/:tdb#=w>B$mfZN';bR)*BUsM01I>B$kx%-)kwNb6KjY6/GWC*<`:*UUo$9#i,ZLIpSm/Wlux0k1TxF[8@KpT.m8be-" "Sg7m1:Fbg)v?_&='<[FrZ01bUR:]WiG(>2'x9GxF$LMVQ$45V6'<(#curx=#S`%/LwAC*i4AnFqV#Ksl>MaK]AN'XDdXrU'h./Q0c(3X8%FSe-K]`roTj&Wl=GWK]BH0XD" "chiU'h'FO#vf'TUth95j/jv5/SlfY,Nc7fLOS9YujXARePSr]4$1CfCH$G8@5>So7iT5/L=./;?\?J,^XZu^##a'*20Yq$##n0;W-rM[L(%cK+*[jTv-oUFb3^%fC#t>Z&4QD^+4^mCD3" "jb?X-n*vM(1t`a4AqS]=F#P@ufkC*JfpAR1BJ:5$nreu,ucf+4n0?(7(TPI)Q%(D``/uqmN%0AXU>qLCjN$3:+SWXu01^X$o=w.$V5r=jNs`D>bX,KQ)`$o/T,31-3o*h_+D#s5Tv-h?7f34jWI)]]-f;EmA,3GcV-*T>CR/NDn;%Ic'gM]7XF3fs?i;AkG,*" "=C[d3B-Tv-C_^-6%fMI3?DXI)ogaV$F4[s$Ljhc)l@<>.Dd(T/IFp;.$xH1Mgo=c4xO[t1i.<9/#RU&$j+:%/&,]]4@hJe$8uj-$sI6Q'x/[iLcF5gLtaW$5*>O&5xtHlL/=B60447?Z" "/CK606CnvZKM#<-vWuD3.*E$Pgab7AAT$92op'5" "i&<&AD0*>9eXG5;>?>i(@tU@8ISBF*FwN5&h4Jw>93Ea+B#)G5TAI-)lw03(%rk:.;cpD$OD%1219L=>`]=n0Sj:21q5UMT*L%Ckuts(/3>X%?5fYAH#;;x$%L4q%I" "VJbuxW3rE]pc6Fecwt$ih1J)ccYiF;iQZ7N+KYGQ2o*7)IaU8>2oF#hXLB%hh+/5@9D=UGcjC,Y0'u$EHIK)[doS7n4@W$Ww@@#S?4t$%'7t,i.pp0f#1h$8iho." "Tb$##K+`Z-&gkkuu" "`<;4%Jd0'#IA3I)v;Tv->Dn;%A>Mh1o:gF4?DXI)BGDC=h_e,;S7[x6J]B.*9]hwZIYO:m7A)^V;'bZ^C=@/a<$)X'lY8-9h;-n14e)t-'$HJ/6C5#Kh-4d?F5&(X0'-m>u#Ah@:hXNf89,r[@=1]mou." "L@rO)@*ha3TINh>eX`S%[0xC)aaEdhFX.m>:S?F?,P3r'`s-)(S;-NkhF*DgU>$(RhV%17(V&sdeKWQx1v-QqpA$wJjv#@RAGV5T'_m" "S1D;.St^a#xF7.3>8N1BY?xw#qbD?8%?&'$?fG^GSv.Z,Rw6c*e2_V.T%2*uU%UIF<%atr?#;69[#u8rk'ZY?C#Zb@W$Lq'02tTI5/[mLT/df_a4As(Y$9nLhLKLL+*hG+G4YHIf3Anf*%uWTM'':p6*.Ex>#tJUJiIWlf(VrapurH@hrI[TV6'GMO#$I+,D" "$X<)t#hS2J_jnA-o)oIE$09[Jk0X7g2]6u+`x,4lVnmVs#sS+U$@O%<$PTx>#gCoJ1dX)MgddaL#pHPYuFseV6QQmPJXB;#5ogMMK" "`)^I$&qE.$tFrg$,+1^4Zu^##h0IP/#$&##4Fo$$%D:s-HK#w-du_8.Zqb%$+mGs-Xn`7Bfc5g)4qd7&wK7X-V>hQClKc9B9MwpE,D`OEMcA`<:QA$l`#&Z$gak8Ag_KO'VF72L*o''#'/###6HK-m8o`i0;;OcD83LG)QNv)4" "+gB.*%>M>$,b&e3KDWD#b;,x6@E4v-FBo$P]=OfM9;0r-L3sOYB,DMw_#Wg#nA,7EbN%sCm&kk@wu?4H^t+e0s.^bO-)fDQBo" "$Z*tq2XT0.OtdP;_Tm6D]CP2EsF?v,&7GgLo7wR&T_S2',964'_The$^Fu,Mm:#gL)s24'2w/D6)GY##Vs=b%S6[0#^?O&#@Vs)#?;L/#0R5l1q8^S%-j/+*Vrw_#PDRv$+G[C#+87<." "XxMu$$HSF4YS>*(x8eH+Uf-]-]iRn3LiM(&AD@T%>dY=$Y$pdCFtKU'#d:0cVRsP6i$O?&##jn-N)5a'##akh8.lEZd3`m#`,EKU&$V#QA#&XH&%H0LgE:kkD#7%x[-" "?;'lURK*785>>)4uMK/1ELlS]kUlF3x=lUPV1^EOT1^r`VGZj.K(U" "IXBe=IM,qe`9QJ[mttr62u):/CS>oRS$L?OKY5<-WG@^$Yoqr$3.`$#Kp/kL:<().)SIXHq&:B#pe4`#^/6c%dTqc)>M3F3n>j.3[Cl;-Zfv@-^]X`EEarsPUSV1^i8S1^a,d%.<>g;D" "&wfsR0oDL#XQRWY-[03&l#MlJRiP;B+OMtRH.:FtqWDx*L^unv,4fm.N" "c[M?d;r4PPc,av@Hl:.=OJQ#aH`kFV:bFW-mVHWUupW+MdT]BK'Q)h'e8OwgN2:[jE^w#NAuB3K$]9X1fArJDRYd*NR9IXl`YmW#=_'wK[%N,qFmNfLv<5,MTpQ##:hFJ(`U18.F(bj;" "C%=+33wjW-F%uH=kG&J3,fj%AKkK,3:&vp%1>Of<+Fk+=qN'7aG@ZR#*v0,)K*:[.^DL'ucu%?A.cwp(h_=h(%&(vfJ:C,$5F5T(_Z`q-PwM%75mA4YN-)Y2VVtQK%Z$@@*9." "4mQS%a5]v5Qqn%#42<)#uH`,#S;L/#1U5l1q9Ms-'F/[#@>(H3Gqf79,]@Mg$9.-4Mt-:`O5_N*-$.II&C#eVR5LkKb.GJx^r((wDT'Wk.[#" "`is]unSMZu6TBj(s7s9)iAO03jrDO'h6G(/vWxE%=%q&tC3[;%F_K-2Ra^)?^+h/3Eu?c4c*-DWD_C&G%8&Hk[aTM'H$M(&:7uA#T4`3OHvxp7vlKE>gc8f3W$J.*2]r_,*d5M*Vxkd=" ".:#gL<=*hD&@lD4n,&'HTK*782x>-3QkcE7&d=81PiG=&`Kqu.[l0,)@vDaGaoj;&fJIi;2<7Q:*/BfhEn$SVG=X1:`7UiqD5Y'Oc)]O]$-lbVfl=03w[s`##&5>#MNa##)ibo74e4/(" "ml:^#483F3jX4@$Ak3Q/*^B.*ODDD3nFL8.Gq[P/=J-W.`?7f3^2.WI%GxJLKKOA#n$(A$,roXkCtB(;vqlD4NB)k155V^BxbZ8;rd73cS92IZ3B;f?$Si.Ic$<9/h]Rm-DSR6WkN)8_wq'F*sAL>$" "b_4<%)%x[---`G),vXa*M?=W-U+Nq2?CR)4`]3-,'rXI)^`WI)<%M,3UWkV.ikkj1uL]#%h.<9/GdE.3>?>H*8jhD3.j$A-T@Mt-CC#RA'Y:a4w($lLokkj10WpoLPNo.*dK]@#ucS@#" "_*@HlbA*A/MwwSB$6-63M?.P'/AX87'o8:dNpxA,Koq7/[V)Y?m*F9%`CCkL'GNX(x#sH**453''Si;$MQ;E4qDcB,hbfM'#cj:I%4rT9Ph``+#AL@6wl,',D%Vv#R#`K(3&do/(9$6:" "lXOWOiK.+>Vk_]5]WVE0R_me#cpPR&OpAO9qQ,w&lRhX-_K[K#udjL#iZ)F3+2Z_+8O8(d-YafgC+ZA+4UpnJRjAE+00AjKXRpwBd@A7&i#0O*N0O3=�WH(#" "nuclLmM6&%sR+F3kSID*ra-5CoZ31uN3iE6'9i$$@5r*3" "*GP-NneY?`[sT@tFXfa^I'$AM:A3Y5^CQ=L*0FcM1rFS72>>^#S?S2`5&I]O*Co0.8<=78dKo`OU6OI3sE]T.Gqn%#3%[6%dx.H+#-[%-#Mgb.#nrH0#8(02#X3m3#N`aI)m8Hw$#3hf1O@7<.rM[L(sl>x6K]B.*Hq_F*/p^I*IP(o2s0;s-6I7lL*8T;-,fG<-JEVIM-7Ms-vlhQSZ*kJN]eC)NF.AT%" "A(OE&o(ID&N5t=&`[d3)w)a3EaYs%=>=w3EV%d>f>O2O+qn]:/OYDB#s@M)Eq;+Au&]kA#[BbY$7+CO+sgU%0S'CXOS=lCN1dh@-%NOgMU9f8%m1vQN+XPG+HU`]n$Ck8E$DP##%(Y4=" "YJHB,O?:6&0-_k43qxf$_SA[Bg(nVQwi3RQpYIm-2%s@0nPHJ(#&5>#0GY##ftho.05r%4PK%29Cwo1K6[$>PVr-JUw27VZAI@c`>w)##TpB:%6vGT.:2Cv-XIV9.27.##c5h<-v_Cq7" "`9cD4t0`EN(t&4MJoor/u3YD#')'J3[;dX$,N.)*aHX,2nb:H4B&B.*6%tx9lsXS*PA5#%D=HO'nI$:7Nmjo7nChT7qscuu" "#`$s$1fl##qOj)#2#(/#?3B:%V(l;-i.<9/X5dA#D.[s$#CT_b^s(t)K^ROH#:s:I%,GY>#=boi'r'e1JikMPa[VRoW^&1CMB%Dt_;r5R#B7O^%RsvD*[I7;8V-RoM>3:6&Xc4fFZp+k's'I,YGF/30" "oOes$IJ49MG's8%HebY#NV%JLZr@/L9-(,)j,KZ-1rt^.YF-##$df=#t?r5%HP]^$ZTn8L28alA>sK<-jHg?._-ki'M00LadW><%:-n%leQO8Ac>^;-OLM*%+@P'AY5>##U^''#_>QJ(" "+f?X-Z]B.*AfmR<,xTN(7%x[-DYSfLr+$>#8v-./oi;?8NlW;8h>$)U:d-GLrQW3-2F%EPTx':c5q79)lA#ld$eNNtL4fmwx&$AU629" ":J6$$6]###OKkA#*&Rn/-E$Cui,^m$QNg%)_JOe##N3T#Y5w>)*7,F@OMY##^*pE@scc&#Ai8*#j*b9#X4OQ':t-u6Q4Ls-1m+c4dbL+*[t[s$8;f`*erUs-T+2EOMkGQ'%c7C#;)^F*" "W@i?#GCS_#BgS=%-@XA#kntD#=PsD#3cNT/CCh0,.TID*Jj:9/u`$w-'7b;7YCv?05HvA4PuOn*K&>m'H<3B/M@[s$]I?lLb%S_#Jo`D31D^+4maihL/B)m0&HT7/s,I)*CNNl(S9Hb%" "p]Ol(ib2[5rX+q&+nZ4(F66E*AU*9%=P.gU-;o5'nEm/S8IO0bC_S.0S:v#AKl5&5^nfE3C7T.NE7_>DsN5(GQ70)" "#eP3'CHD7'/](?#@1_+*DL3Z-E_+@#aiYf*s/mN'p=)-ERD.5'iU5,*gt7[#h`7)*2>NO'7lt^cr`i%IA9VRDekQtPqW4mu[-cAq2.xW#4gkI#4W#T.*@$k(24I2h" "Q2n)*k/-.*^QQ3'08f5'0FaQ/LKC8Ms[rS%7G0u?&3#',=^UP)'Zrc)^]ed)ubgb*f0D@,At`j9-[pQ&*x/O1u8C6&j@0(>B:$E36b;q:WVkS7O-qo)t-mC+tP9(,1h(E8#,Q12S'" ";9X72s]2':]/%h(HFgL(>Mm]#8r_V$?f(?#X^m)4@<#FHwQSs$p@L<7W6Ya,Th.],wlq?-PT>Q#@Q*oKb,Tf=Mv^oIv[rt-$*5>>t*(m9I`ZO(ZK(E#MV&E#:13:.KkRP/vD83%_9qfL" "n<s^+uG2dFeu>[QXoI9q_,HU`V$4X-_#" "ax;9/+r,s6G?UU)Xax9.][rS%C)MT/F$nO(,^YX$]1O[$?G._#=Qd*3ub4V/bR0]$=oCkLe;[&4v@v`4t/eU%lYL>#@6>N'K0'U%hM7;64LsP&=+i;$5+7W$9uLv#$P_LJgng;ET_vn&" "Q'*L;SOXi$i6.=-2oOe)/]1Z#a2cAYa;G>#@iHt-X6YYH;B3/23k3HA3:^T%GG9f^U&v/(6VY>#fuhv#]6rkBhO#V%Kq/6&'Q<9%?+iv#=h/Q&&HaW#$v^B#c(1Z:g@['5+n:87F_T1(" "^tnW$A/%F3s@PF*MmNL,BqIt-X%t^,D;*g(;EhT%(3###[,m&4@[jl&RMt2q/" "$L8<$j+_YWLB7j'H=Q2t__hs.%N(>$6O5pu3&RE00ij^/l6'jb/EiB+IYL^2ch5^.,.Qrue?'s$2cD]-l(Rn960)#$6Ikr/Au5?^%VcMlFZ,M3&2?" "s3cpuS76),=sb+4GlXa#l*[o1#8=tVEOMHK8?dlC^G2u$H8A>,-3UQ&Y/CC6<@Kt5.?cs8nsTq%t;$k*m0G=$o2a#8x)T7/ZrQK#';VtfMxoc-Ut%w#7Y;2'5dUK83FU6oWnMPiGquBf,5h:G($(HiN%##'&P:v>pHk$:[I%#>Pj)#=aX.#+on:/*@&s$^4^F*#o$],pJUM'&SNj1FPYx6(.uA+U=US.VP/H)rt-'9/K5g1@YXCt3e9.Y(ic+,4Ft.hgpQ&)QYl3o#C+rnt,0^Jloi'5&`D3)Sxx=5$lr?LX`+r52I*g?],lMNCCJ#gT]ru0>eou_;8i^s(k[$H9wQlgSqLf[Y?A6" "TM.wsIvMA+]85%BE9raQa=57`p)g.q[6UV/1(6G*9iU;$o33q.aJCZ-GAg=u5vjEB^G6na_dTC0)?v>'#HEhukE^dVI>]<$)ug>a08^IOWkf87FFj)C%KB;s0xYxVo,%hgascH*n8;53" "'$^TrqIo^$3,2X@mHDgf#`3d#^iX`fXIVS%TD###Tx^##8Ufi'r)#,2]V5DxhQtadO&5@pFnEw@b,M@V3B-/O$<-)Laf1wo=:vUPvv$_2B2#PJZ5Jn)B02W#:u$CO.p.QDnB42`&02Sg'u$TekD#hHff1" "EK(E#j1ffLEb'E#SJn/1c:pr6nsoJ1R=h8.p#]JM(dYA#hMg.*djuJ(B2Q,*EdPg$UsZ]4,:OA#JEPJ(E1tD#+HZ]4VrH,*RQ1OFbf)T/&Jqo.Zg-W%`gdvXe.Q3'5-gh_6Pwn92.#fq" "t:n`*CJH$GjEg&G@?3d*Z44pu%+)k9T)3l_2/[3'T],qX8$BN0#v)D#xvisul[S^+)lC`++btD+;gtw9`P0_QC>5dsO0/'J+KV-Jp83;)PEERIp02&8^PU$,WS.Wb>,MvtCR'#X5[.?^'O#_36[.26'O#Iq5[.MF3X.jQ5[.RB_k1Qi=4%mg88%)5###[^''#" "3bGl1+RPQ'Pl4Z,w2kU.Ua-)*Do:Z#4`l>#d^*G4ro+G4kSjL%L$d:H)%+2t**bXe/;MHh)3]=bU3dOCU]7u='*CYHG2wjWT#F0=tpa_TU=HR'sJ)[gqu" "B+*+hFHoT#0PsD#R6Na;*[:'u9R05A#W7PU2//4C&4XO[9HUatCxvmS/ZGRq;^qwX$FwUe3OOeG;=+@-Dv[Dv#64R8%5f:v#HkaT%^x4Z,ta5/(XdgQ&a43-EL%/u.QsvU9.K1:%3qOv,TU;Z#knpD3*hp]=Mmje)" "qc`iKD0vh2K$w03xIe/(]TXx#TdX]#ZPUs-;xXgLcP`(*fj*D++_ChLr'#^$)J/$5](q^+Ju,@97dE/F?5Bh673hQrHgh]=)ekv6@.J.EXK$:VB'*hN*+vw$(BK=-S$Fq%3OC7'2#Wm/" "^&et-YBC,)e#:>$KeWI)vxRd)km4AuvVP$,Fxj0(SN:a#ApLk'jphtLe+n'(9(TC4W*V*4)IuI)0]e.2qdHNC9II[#*AY>#X:Mo%-oa5&2PY>#PO4W'UWbk5X^^i=9vZK582M:%" "?[aX:MW-6D0The2.s;bMoX;I.mGIL('XV@$-6fM)cZ-d)wwi;$nJrh+9mln%/Oeu6RBg=>RLDv#l=pB+r3fZl9YNk'Zew@-//5##6UEt$ZN*1#dBV,#3.i?#0ljj1ilMG)ulnD*ZK(E#" "#Px+MFT+Q/F.@x6H%AA4APfD*mPwh(uX<9/#Cs?#4's<%-A*F3#dE.3T9@+4;h$@'bn`]k9@vAgfs`C0viOv,pg9c5H@w(/3kXK16jqMd`]2(6me`Z#D-?-3DdQ3'=B?c$BXkF&YUhJ3" "S^Z/9L=2C8@30NMvJi&Z7Tb(K?()>YIYu'+KZ5r%6>V11cf8P'=-uf(rYG+%jZX5&[f>B?1>#[rb;%RLe=-'scT%p,Qv$j99%'nEkc%DG+(fZW2?%.t[XJ1cpP'H=AN0b7RW8'J,5A>Q?KN>Kd^$lEVP-'A^8%V6ar7t@U'UP5&RJ@,9" "32Af$tr[fLp%:e$Mw60#vsboL:;x/3Xpb]#[BFA#6+[8%N$(cK+*OV>c4(e*G4&k`[,:=@8%*mLT/@Q><.d>l'&p@#s6L*H1gU,@T#VH^=cB7h?-" "+u@T%;:/?#Q/cHoKEU#.Q-(O1dORW$dXb[$6uWN1E7;W-Q_e>#4(r;$=_J8%'@c#%J0%f33c1Z#.l$W$b+pFVPXL;$OP-DacVbD(+MuY#EZNM9,jOU%8_uAofG:burw2`u&+q32c@6c4" "p%:s-cC?42whj5#7>##v(1r$p5###*AP##YuQ+,Yu'94)S6Ku]4U?[(swLcY#Q*RKupZZfC37n8%Z`-jo[sD>,>b.4q>$1YuivF/(aDGjCZMep#" "3`,L&p5=VZ'vAA=&<,>uh2af3UiU:mr'JYu2j86&f54]%rc&Z#8(F?%g?-/q9MLm'^FJ?pn)g;-,fB@%,R;8.63@M05##(S_V$u0hw/q3n0#4=K,3Hl0[/cR*X$x'P#%okn9%n:i?#t7^Y,Y]wD*2oS&$sX#`4`3f<$Y$*W6[t@`,u,pf1T?5V/a4[s$gP]#,YLU8." "CLD8..gds(UsK#$F/lv6@f6<.=S]=@IJD&I1JjoMG5R>-sNfZ7xPmAu:ukU%gZ/N,T8Y?,93S>#5pTnLrwAO25t.?36DW5&pauV/#,801+w_h;rei;$@`0H2HE4?#RgcT%Q'J[#eK(TR" "s4x-)$ucc*OgH*3MUUf)X:;?#Pggq%5iqV$x[-,u2d6w9,j?f*5>cY#X2FZ6w?nnKF36C@iF@,DUD[e2kY$'=u%MNE8B6K1dGUm2d2eS%v.oL(ON+vGn=$%####.IPh%&818.T&t+;>_Za*nA.K18+7s$$]K+*f5xb4I^4L#CD,c4S?]s$BQwb4(MHW-(_m3+'IA8%q[k/%5&_s$Mw60)r#+/h" "Ni*&75+(a>Rq(rV.X[h(7-$(-d',MI/Z$0%Uct:Hbc>6_M[%6],A+Vc.o0OU_/)kI`S%RsLK(RialAAxl>u.f^&+.]Ht7" "]?_U/X&_V.BL%L2O3a%,Erc>#]Suu#MY.JLPF/mJ`*EM0^'%##4:n8%W3D*15g(T/kZ*G4Jwt(3EAd,*GHVhL$Q`iL3?M8.>/>u-Dvuan)>_'/a(t;H2cBo$:h86&UeTK2Oo@a5XaH9e" "4Hb,8wW[0)1vhp/g(/?AICc4:TlIZ54g5bF-),g3r*HI)7S*mJkOY%,l8QR&i&1S,3%BQ:dXGbu5$Ff2n/v89KUM<9l+'t%VX`D<;O%Zu25K+*3L,s8s1/(#[^417eX$k$M,85#1^;W#" "a>-C#NFP,G4" "7=Nb7&hWp7EulG*J4pGM.qugLbW,<-S4PDNVPI?8W,VT/mKd12ebXcMB_u]#w-ikLqHZh-5^Oe-;;Rv$Yp@v$nNTm/o8ZZ$&R:a#;OTC-P>AYgTGC@-^DSb-&)=hY@c^N2HxNj.+#Vv-" "'G1p$MXp+Md;T;-I^Ma-nGKb.2R[LM2pVE-sKX(M1PPA#28GjL;_W#.2f'dM:I8f3dS>d3Td/KM&Bo8%Jx(Q'%/NbMo.L+*7jXj;YJ+kLxU@C#L`oS/C1T;.*H&<%+RG,M7YjY.l[KF*" "^[=SM7b2E4$OnF46Y&_o^0ZwTX#?th6Z)NM:?/?Mdw;9/]K=b72_Tu.R]jj1%#Qt$gIc;%?+i;-8xr*/W<7f3ci1I$u2K.6<%p+M3>3L?1Mmv$^NT:%_Mox%PTx_#Jt;<'BR*9%6]6[J" "c#HR&7Wpa<0Aw$$^HtT%7eLa4k>[8%u4''+bZ53'QskV-f/M0(2$B30>efM'3_/7/'Ll#%>k86&SuM_=`6xs$^/s[?81L+*1j#I>uJ%L(uRKF*kWPj'YK=t$[2Qn&bAe`*WN'?o:v#6;7i1l1FZ%6PvW.fBqQ&eEuT/(knT.NLTc35t_0(XH,,Fh0)3>uH8%LUKl'IvA]X_4gd)f'sm/" "vX#lCpl8QV3*6$urv#0PcY#Q'g2'#O'g(JeAQ&]g,11UdGN',n,wHUGG>#W`N**FriH2Rh(" "1AI21^[2%,E9IW&>uq;$Oe3T%,sH.259jOf0+wo%kxV8&pEKP:wCa=.2iU;$b#dN'XbHP(q]w)*?p6`#Z:lZ,T5E&+;.%s$69PY>4w<**5tbq?'>)v#-]_V$3Qj)+=PxfLs2J='Yts5&" "jL#(+)mOD+?=nS%mtG)4*5,]#KMjE*N6,3'QoLv#E0kT%MHB#$RtRs$CXI<$U$'m&T_*9%KIrZ#J-Gj'&4li(Tcf.&3'JA,AC7<$Xm'u$b.xP'IK*%,@_Fo&JZ57&_.%O=CX(_$At4/(" "W*lDjOU[8%sk5;%BX[W$WoY=7v;#s.qjgD3*Y8=%WLRt743^b*:9#T%pPlA#[8RH)%aM/DXnN'`ojE*jkP2(@tQg)PeWT%CFVv#" "lpS@#:F[s$_;`0(7Rap%0c_;$>BB;._gFx#'c4^.Z-=T%t*P6'UIE9/awi?#/Lwp.U-;V&p$>Y%lp&s$8fP>#wjaU._rND#nHhiBK'1I,7#si:pK(U%l)T&6-PBPs#'*a*0]oa=Mh`u3" "]%X.)=Ax;6r8qH2JUV?#%EFF+kDHW.9LZ?,>:es$M8)6=mX/HPRd5R&9llY#" "IgH)*x,o(+$;Wf+cq_%,@Blj';C3T%b=Vo(aQBq%0MtE*1]b+3-wa)%2@G-3*+4X.[P2N*9Sc>#AZ-d)JB^30AQMK(SZgq%E&:G5hAwD*>q0P>#,TQa3" "#80+*lS?r%-chV$_u&F*gAbD+hYwH)xdgq%jfFx#9_l;HDlL;$RXns$CLV?#m[hx,&49Q&3+/C#qG/#6]ohV$61[S%647<$PBgQ&X5`N$PQ-)*(Kn-38X#j'L^q,)(5Q:A1YAx$rP?I2" "@1EO)cx?s$&?Ji)ou1@,)V$##%&>uu+H/]$=EW)#w,>>#xk$],:8,d$m0^M'Rf]Y,X#:u$YKVT/kZ*G4QOTfL:=o$$/,-J*6*YA#[j:9/%IuD#,iM2g&F9a#@a2@$s^0#$%rP29TK;p&" ";clY#6PAIag1YS&<+wo%U:q^+w_b4UYx?j)e3ZCHbM02F`QuW[o_jP2/;d[&RmU0(Q'-Tq%$Jm%TLd?6pwva5K+hq#E$K2'VH(D-g3=)+n'p;8I9gF%^p&X7dOLW-$]QLM5449/Ar?4)" ">&E@.T;.*3KjtSKv*Im00F9u.IHWb4u`rK*4q=I%`OHYu$#Dp/K%Mb$J/Ri;KYqr$LV.JL$qK2K-l68%=wfi'ZLLS.ESXV-2j'.$3ctM(6QK/)HY2-*baGj'Dck/M#Z`G#NNg@#Gw,ru" "tM?C#vi`4uPY8a#=<5/$9drx=`AfuPMeqF*h)w`$Fe7[#Ymg>&6trRR<%P+D$b``E$$SxF%.r._QU+Mp4vug1D8>j)WU)?#Ucc##&16$$--W1^()5>ufv/Q'JxtKPPe_F*0K'b%5pXV-" "*$SX-ai?<.5DZP&W,L@#Tf@-)jJ-K#FVDqK6aG5uSmv3)Sh@f1S2L)/[m'?-i_=Iuq?sReNA7eOk>Yt$km2<#>g7-#M(wr:]ZW/2iq[0>+VFb35s*Q'?[e<$rfeD*k=8C#+&^F*cn%nL" "bf+G43HkQ',I6u6Ei``3R2NFMOk?Z,k375/DIVs-@Cr?#H;j%$1E.H)QNv)46RL,3%>8T%PhvlSUB$=E1Q0Y,DKxe#,;J_4'fAZ$Gd/a+CWe'5J$kD+h.oN'A.M;$jg&v-3/1mE^Dke3" "nt$M3.mdd5%a8B+3WQ3'p94Z-JC]4*COb.?AvAQA>oDW-(m[8/.Y8l:HbZfCPB1l:)6iloW;h'j:46OW+7HDW?ZxFDeQs6/-AM)F;$+`$M5>^,(@>m'-Ukt$2GlY#[4K'+f>H7&&s;W%" "wP0k9:lMT/1HbhW1tf(+*xmY#:Tal(?]%7&iTXg1GXHu63k*S5=YU`5:Al(59Waf'oP/X52#$rS.d)c[m5/v*H87_L4gL" "=u;9/$$(<-FE#w-vTK>$sim$$q;>x6Nnpr67eFT%%VkSC;WbPD8@fS%O76p." "3:TK2NL7/=W#$9'r1Pc4HW?%HV/VR/i3#f4VtI>#J/JT%S/1C(%#u%,G)Ft&`4'F*rUoN0N=ce)0Cu@51MceWF&8a%6grO1I#jR'R@gp&M`q7/01lM(#FS@#CZH)*0G;t.xOU+$*/:2)" "Y_qK^*4)fjDJX($0_'#GYjR7mWPfLMUQuu3+$c$" "B%WuLDD_kLn^p:/KC9a#%:As$/xOQ'SK]@#qe-m8?,X^,8@[s$RZ.HbH4/i1U3^cVd=5g$ax7Z$V9M:O-)1#G2KIig7H=[7#?VgU+M%&>Y#:fulTKk02N$5l,_SW7fMCk)='*%$)i^14" "O(.;:p%ed;v3WMA6rX&#I3T9VCt:/q-PUV$]Z3-vaY###n0UN(dW$jgp2umupUu]u'fu0wjpu_h&]t<$K>>PDNq#N:G)i9P/U#RkLxh'G:'Mu6%##%&>uu" "UV2w$&5>##3umo%BIVZ#:?:1p$[^G)pf>F%%bfF`S%UVQ'<329JlnfLvt2vuLd]*%7^t[65ji4#1Z)<#,](?#WN9W-`RAtfbAE.3;#K+*P1[s$" "$-p8.[,wD*is9)+m+G4ucF/2hsMT/B-Tv-oYc'&oBmD4UK0jMah_F*8alk0Kp%J3YjQD*e%JZ$v9k63)o7X1(*@k=c;eHbn+D#&<8.M" "qHv$V1N,%Q-K2'5$uP&" ":1DITkXR<$r_U%6Di1v#fkYC+ERXX.ah`V$]pXu-UslN'`Ak2C4GFT%Y81;cf*Qt5u`>][[>[#>A#>Y9m;wRYQ'" ":bX.`8m38&Y&R#%F053'ZfbI)54Qi(:1MZ#t(L*+Z(TlUT*m>#TKf[#S2_m&R3=T%cVbW%vpBQ&wK4=$QdCK((F3q.kM-v$Ab>?5Bndk(*S8t%qY'F.lg^q%pALQ&0((X67]Cv#iXw-)" "ZQng)@.Mv#DNR4(K%D%,=EPv-N8$<.8Ui&/W,>>-J,RH)^oBu&?_e5/VX8&exRUJ(p0fA,7I&W$FkV[,;P-f*U(;v#)]+@50@4x#7ZoA,nsFZGog2-,@6JM)5#j+k,*c,IEZJ]IS/nk'" "ZH8J*EKok9)F%,*-n8M)qwbR0O(bB#/bMAd[o[Iq`7amJg8be)j'Z1=56'F%;v#QPE**?KIg)u_G29HpoM)Qw?a+Pdf&,nHbP&/lZ#-a)MK(XIVS%Zn_Frl9nSRqV<>,lQ%##GO=F3ja/r." "[h)Q/@)D^#xV0<7wU7C#A93E40uZ5/kCh8.WiWI)oHs?#jCF.)Ir#c*3oAT%38oP/VF;8.eY8f3$9$$$@.x88P9wS.'wA5&,+_[sj89du$PE28xoN(TX:s=cg8D;$1;*T%EeGN>t_)5(" "q+T.FDdnr[6Wqr80IU['`I-%)[OH;N67l31Z0[guKlr]r8d4#WtMqjuTWU;k5Nc)nx9BE#=0&pnq/.x#d2@j']]h-1+J8?1QtnrA?db(?b.vx>:;*o&=@J^@*Duu#:k%>GhGD/Lw#r.C" "6oNfL)g]$M5xPA#`69u$Uo=Z,X,U:%k?j?#CCc8/Znnq.;7Ms-I^4L#fKJ5/[P[]4D+%]6AnE" "pa_W/*7YK/a_QP/k%AA4cV8f3FPH=7S4A8@`F_H3Br@*6(#7s$ps]=-,Y];6e&v'=LHZ9)DI-t0aYiH%wDd7&St%T0E_lnAjUt<%,c$s$V,S@fCITnT*gm4&YFtILd+B>,tmvbbdqPx." ":w3=3^K3sMK+8a^vul6%rJ%d3:(/n&V2bo(OX%a?E@W4)odZo/p8)79I.tZuXorE#6Ls;$Y[&e?36(i-H9j#9-1e_/nwvP/<6JL#=;ZU.>%)j9.=?&>Un%j0'os.$b&[D4Tk:Ic%5YY#gJ=>#1Pu>#oWEM0Zg>A4#;+i(FAYV$wE>V/inrS%" "lp:T/?2J_4CmQv$a&SF4L+)s-c]fkDk5Kfh7BaIh=p`Bl;gVBlOb@0rItmUm3cY3;oW)>8o`4CA3?>>#*(.eua0Ii0$cv7/>EuX1k5@e/<0JI#js/fDD=6QM&0K;-9=JV%ts70#U>$(#" "gbtM(ruSF*ipPJ(]nr?#a',V/C&RJ(&uJL(#9KmAsw(*4xr%&4V+%s$uuF>#KkoN'3;=+Fa=Cw,jA;G#j[F?#**dbul0Hp$I@M'NKq@t6rQ'=+Sl##SWAe$_+#>#4kWN0#([0#OUu>#jhtgLqr;W-0Wic)Kw75/QJ,G4OM>c4KJjD#iB1&4UL7s$ex;9/" "QXkD#w_NT/-W8f3YJ1I$-moF4Rjxc3,]Q)4mVcL#XnL+*BU:+*;rql/xL'f)jJ@d)?7sY$did8/e`$w-RJ-(8xFl/MK+#V/[O#gLO]-lL?r.>-squ-MCB0oLgVkD##%NwBFsH#-%mR>/" "YpB:%rHUhLkRv-.LLTfLeiW^-t//L,M^WbNr2]jLkbUd-%0Q$KKLTfLQWOjLOTx'.9R7lL[]+c4$a3B#>3lX$GRhV]>*np*R:(5]w7li^.S:v#-PC;$#Q('-lgC&$XuRfLJ@h]t`7n0#" "LGY>#):6_#6k(I3I(;v#VrRfLV'*Z#X[)Q/m@R<$ikB)NjLQ>#C2Uk+toRfL&?-9/DveO(j:ofLm(^fLY-Sp.hoLZ#;%`v#+MuY#D)]fLRkiV$H`x8/&=g2'((h>$;79Y%Q>cY#6(@s$" "NYak'SG2[$=Ln`$+Ab,4CS(ciu)wqmBxEQ9vXD/:U)+X&uIU9&Y/*A+Ant0($b*a%5s0s-_l6?,LgcN':[.EjnsJI*IqWP&:4rZ#K99u$VBXX$@kj9%q4Fs6Fgrf<+Nfi)FtS2-xVK0)" ";LwW$I.ad%r0kX$=_Np%:+2Z#_8Mo&^5%H)[UWu$_uXZ,bMvr%O3SA,OUcfCdk->6/a(u$#=T*@Z.`?#U>Na*@o*7B3hJu%>bZl1xC/40=[Et$3;5&$O)MO'FF.[#EU_hCp;)t%-xtR0" "e3.I)C:8bIgfhV$n7j4'D`g58W)nA4><:99t$Tb@3>=GM9QRXlJ#(V:n,GuuRafE%Zv$m7ME4+xkj1(lR_#]>Qc4,EjkW6rL;$?_RXD54*5&TEop.a:p,3,+CB#kISX#XHNh#@VeeYHBv/:-mwD*nH,n&_pQ-3F[`n'KH,3'1AY>#@W*)$" "SDs&+6SWs%wbj;$.JcY#b]Os:U90m&;p5<+I@dUA^Ct<%oE&30.9,8/m&>u#n'Ab.smf_@/;c^Q/2M0T%/-dwrS" "thv(+dj7_8D+h`$<$#N'h>#,W*i(_-f<$1QvJ(@ooA$dOvP/Dc=`sPIaUeu6e-PvL?BD`1*RM" "7$uKNACsT#c=-LcUTBPJ.]_4ah`J>CY/,I?ZG$>QFga*c;x_L[2xR.:&sGjec4V3__4aF,l$-(+D#JSfx$HO%s$" "G?L]$HH3-*aSID*Jdus.W0pi'nQhhL1%0d9/*kRP/p*UfLYe@`," "118C#s`$w-(#;9/hMg.*'6$9/u&8f3*%@lL[&FV0R=n8%Lp:9/-<3jLrkT7/:8eERH^NjL7^J_1wO>c4cb2Q/C7r?#PZ3[9:*(kbjKBu$slTK-4vGpL(ht/MCi?lL8fn5/J9EtCmf^I*" "3c#=(f?[j1V<#;/pC:68buCT/ZD]C4(W#)/&_*G4BEc'&;D,c4Ofd,*eL4gLr.QA#`gZ)*i73D#ij,V/lvB:%NpuA#/tHT/uB$>%F`*v1ndqA$0d]Y,V4ur-?3rhLq5dd/-fqV$+XC;&" "3l?8%Bb82'kC3*35`In&86B01(bMIh^s>j',jMs%`v9Y$juG8%_&2S&SB=:(G4)?#59]],,BD7DSrH>#2x?8%MtDtS$GF(7Y8TC+/OJ30pHXZ#EjRj2q+wb*G/(@K_G)6@ns$6x6W$B@Vv#;iuY#?cc>#0](?#@*^2'(H5<.M@vY#*#IW%*1s]+%.Cs$5Vl>#Tp9u$SSn1(MRGH3F^eD*@`.s$D[1]5fjK>$+/MB#'dL*6" "F4bP&iE>p%`&ZJ(87Ow$34nS%H0?gKCp/.*3D=&>LKX>-2m,<.;g$I2v=@C#-LMn8@rLZ#FReW$_a4A#rnl$,lYiO'E_*X$Q6#N'gt'V&%Qv[19]_V$+s-m0K.ugL].G&+1jCx7Uakx#" "/,@:B'_u>#CHlj'IT^Q&$ktl&YKcf%/W8s$5(Is$7uIV%Wd=]#9`U;$HdcR&1M.GV).;@,5,721R=Od)@%Y+b3`_V$FXRs$ts`uP1fhV$[cYXl$b=C?(8[O(Fr+`4$k&V.K7Z=-,QE**" "SP4E$GIE5&^U.<$i0lI<3.9W$cFX@RZ+=+37C[>#faS-DjFa.?sbap%Vvdl1Ip.H#nkt>$fAIL(&5[E&xjT6&5&6s.;Rd%/5mPo/#TKp2'77[S%i)67&RhRw#1uq;$#I^Y3'#`JT&pDmr%un#O(" "4Xgl'GYxD$C<5N'4(5`4sd]/1ruTS.viXv,^rF5;.VVOBkSjOUFbnS%e>l=$PDi/:1x$<$cm9H2;CuuYdUV$^)V$#$1oH>sCJWTXnFb3l@n8%_cWI)tfeD*ZHuD#C;XQ')(4@$gG^.*Mgs9)n1/>8VbNT/')ZA#KjE.3w(]L(Yx`=.1i:8.f%gGMt.,G4^_R`a" "fS'JI=%Me$tX@>>L^Cd)PvuA#5UlD4h?LbI<3we)d>=mB78$=7p[2Z#0I>PM?[lQ&U9Uk1Q,rUqg5[',fkYP;=W+8;0h`4;LJX[$BVKC-*h+^%/>SD3NYG=7?o<-.&iP_ATjv;%PKtp%" "B7GN'9$P/(TTe,*PUVv#<>@+6MU(12GRv22j+*`#+c%12)#:=@rTl`*ne0BTx^-on&nwi304n0#&hj-$vCv##xqni'[1pu,^l1A==;4GDHK?gtW>6#>0X?T.r^[g)/>g+4hHE:.IKj[," "o1pb4N^.*I5^+4ZL#gL]bRq.,'A.*Som92s-g:/On,D-wS`]$Rpt`%Iaus8bt=)M,*)c#`qke3S=4%$$0,V1W`mZ1dhoM'(sbv62BL:%7PY>#" "mT2AXW'caa<_&f1O[#MEk,KC.Z6^B##n0Z-'WL^#7tYj>9OPN18wd/9:xKhLd1RQ24&qq8vtGg3OufP'`:=BV8cx-F>u;*4t,kEEGbjp%Pt*=$P3:T.?1)VQuCY`-,Ds;K#VAVF6MtbF" "Hg4C5H/u$6#n1Z-)8[s.2(V$#BId(%BV^2#_UG+#/b.-#G=G?%Kt6VZQTp=c/H0YlfA+##qqSfLK>6N'X7^F*OINs-_)VV?3#ra4Jc7C#OM>c4,fZj9gwc,*#/`]=8']n3$AF,MkQrhL" "`(NT/6s6@'J_lS/bYu`4E5=h>,.ikLIfN^-)NPa?U3Js$2+m<-2WgoL'lx70+g^I*Y.i?#v+6U;V=8C#BoF#$aEb9DrOd;-Zmq9MjA,gLSW7Y/@f)T/Nwc12+)e3FIvZ]4-l)mL^c_9M" "@btD#%31" "`L$P;lDqZ-m0l/2O:O_&/pL_#E*^K:l;jo&cLaC=dXD-*Co9_5EpsI3d[^80ah.<$I@;0>K3CMo'+YR#B8P:6V@" "h>/r8X6RdIVuS,3>QV,)oO:Z@fn4^@'Afr2<:E=S>omW_GVQ;RC=dp8^ktX$N@>/C:Xf2hF0w_#Ha#9<QDEkg;V`7<$UC5jBJSXvm8`^u$Sxfb*E,,@&<3weMQVW786l84;" "@Cpg2/8Jk1@a;0(F*[J<`3Ks$5*Dt83WvS9h*ST%h`p/9Urnw>.#JC:I6`g(3_x(>2M;?=1n&Irxrx&F5c72JBRp0AxLl,RR2B+]#Lu$x1)G*Lb`e7TJpl8" "&B)Y0UN=E?.*P@7pSOl]%]B12w[/[#,g08DE'N]Fidcp.b?65&NV%JLUM)mJMDW]+9lCYGQ]BuuNM&#,&NGG2CD4;-bA.gYi/?/((6pV.W-Qs.h:C58_Yc8/j85L#Ei<<%#,B;-Kfcs-" "t@SfLv,k?#qwkj1I=x]4nNJw#(cK+*c$`L$/a#-Uv68>c(Z#TPTI*d%)?#Vq7/1>swd)%<<*4X*F9%T006&HK#R&JU@W$" ".YCv#It*t$S2I-)<33P]9x.r%ff+c4]qvYuC]o>,%vdn&9.[S%PcYYui'mY#Z'bp%QLEQ&Qx(?#.fi&J)*HruHoh1f:q7T#$,7q#n&)#fZKJKV^#`uuVfKoP:%vVh,DG_L6&^]C#>u5$,xoVO'*AP>#D3YC-1$DA$p`A9A" "*L.K:<2`;$X^O9%I,=BOc_#j'C*no'LYG>#A953'04`f:=VwS%PKP3'TsBY$<(7s$ru@L(_4)v#rN4X$oC#Z,Q'Ot$SmuN'x#0r.D^B56,vK1(<1ru0FQas-H]rv#MnWp%03_oSgj^q%" "Tb#V//Xah#Ij:9/@X^:/N)b.36:,gL" "_P,J*dchU81>Ok4)NL_&]-_fLUP7C#-`H)4]x(t-olOjLv975/qiO[K/C7lL2Vob--nv3+N;`^#j^ZC#V?ocH66Zru[2GDM)U>b#Mj+T8R1hU@vEa`+(BbB,]Ysa*Kspn/`qN5&^rvC#" "'e-K)%EM3;J9dR&JZ$d))sq11#+eNx@`Kx8%&./<$niZ)Ea-]s$dWgm&ZlCZ#-chV$hG$7&m]@-)%MM%>N);7HK)EkjT%370P'Gh?0)fYIP'uED)+(t*B,la9:%D*Z]4c?." "i6>k'>q7K)fr<.)'?^V.(Et^,$7@`%;d(Z#3oLv#FNL,)*c^J)a`Qv$d_YE*,=%T.FjZ)*mWIa+iTb5&>^Cu$,[Ix,'r2Q/a0Tm&sPdA4TGlY#JbJi'hvJs$xFX.)sC0J)=r_;$$dRG=" "xBJN0IA5##l(UAn(-VpJ']wCW1O)##Y>2g(YcX;-l,Ih(G:Pm';CI8%&@vr-lj-H)humPhbrV<%pa5N'[/l]#tfeD*O=@8%Y&dV%D`E+3+2pb4/N/W&Yrjj1[KA8%B;Nv5V.@x6N;Nv%" "Z/QA#c.8C#$mi`3Jj:9/#0Tv-VsR$$EV?x6pIsO'1W[iL.v+s6Ak1B#]K5,22-_3'@Ds4fP?ZlfBH4O)pS-;%N'd$%qkX2(hk[8%/]U;$64nS%hf$tHL(/$$SaOA#LwI<$5CZ$,eWK6&" "/SuY#J`@tBqe=gL`==Q'RTG3'NqI<$1l'F*lG4C5]pL%.Mc$s$/`hV$>%)Z#-AY>#<0CT.7.@s$oK=T%:hAm&M^U7/j-VD+]$jjVJ0lJ(<%I8%H=h+$#WW32JF`;$s,'v-CWHE3UB,mJ" "ReG`'EFWB#fTYn&+AP>#FfGd$7uh;$0JP>#_fY/*O)]k(SB`f)'ULh0qW+T%qrrS&[.]fL[]bA#/]Cv#" "Nm*Z6lK0*<`oS1(Q&.-)q[)[#LQ#n&RWYj'%hRx$.i#,*uM6;%m]$V%tg+9%HQM,#wq>v$a6W;nGsD&+;]vP3WI$##pQXt$H<4U.@l>a*^$&<-b'd97PC@A=^t^7[=6HlfYO.NRd0%FU" "8o'O#00G#7+d/d)re&<7T#sA$a2L<.eRpI=6xB`&KPUV$I>x/&]`3>5X&=J:&a$7/RBo8%mSvJ;4WCa4U#'KA@S$lSu#4tv_#Gigl,5tm`>UfAD6l)G]Y7qa['C9p4MM^C1pTSNlWJtn48hXSR9>xBHM%+B/LsfRGEqYa^u3=X04Z>+GJ*c/qLq3#X7ZXr&88@f;HgdZrLsqOrL[P,s-Rr[fL" "L:7v$a0-;#gFKsLCHY/2cu+G4[5ZA#Rc@A4pFxU/Rt)?#d(4I)lOufjY>ujFIsZr3LT&;YDQ&ia4`+IIa1-7^u]#$MKb,-Z5C&sueCN$I:-PBXbT%^r6T.=YN'@>f4*Ql=B@T(Ke8%8Ah<$9?^jWFq[TU" "0WAOl#[XU%Xq@s$:Zl>#Q>%[#iql>#EKPYupp(?uhC>/C>g0C,b4IQ&bt@f1Ul+g(;5bt6KO(l.:UjxF*k%VQ'Y4Au3CxT%Ac&^':DQ3:Z?CQ&[:`C,i^j@,W/v^=2^7+HGBPj'`dL/+" "uieH)^xUeGXUgA469s[$SBP##;PUV$?@;?#:.G)4D%TfLlkx=%bw@8%$ImCEZx$/USjMigPn`W#Zk:xX-Pqfu^xnK#O8vN#vYw8u($K@E.3m10j(.@C)N5-HD-[UYHMGqLa3g<7f3j?]s$" "K?0u$(cK+*QG,c4XTcoIxtsY-^`Pn*QlvG*GKNe-6q5V/w4NT/NaNjL5+F:%30Dh5]x?n?M)pxX+O#j-uLdH$=oVL,bqmk,ShI:.+C`2PipTSK`/RG#B8k+NrQ[MKmr$vZZ8Ml#Eke@=" "1.j.$?jxJLE=DmOT=ad?HE&;Qf:*NAwjT$-($:2'gL/C#sotV$MnmG*8PoL(M?'Y$S?BU%j6@9.u4f-)9%rP/j34x#SdGN'`Mq58tN@x,HHF#-8S%;mh45)+a:_s-kQlf(Nj=;$hJ=uu7ao>#NdWf:>Jk(E:E-)*ACI8%l&PA#?1[s$Z_d5/K@gfL" "<9+Q/&SQP/1?Ea4:TID*#7^fLL?uD#iq_F*)0dA4CmLT/96Tv-(SJfLV.[x6YP6C#+IA8%hUK+*FO0R3vdit6C3&ofvn&;78Y#+P&+:ONT%vH)bNJ`4?,V)_B#VJ%P'IWbq#m9`k%``DO''i-W$QUMM0C>t(s9iC;$KOPC)JKWl]4o:?#k)7W$RiVN'OQX]#FTG(#7&>uuMtvc$Xa($#IR@%#bEX&#$9q'#" "<,3)#TuJ*#mhc+#3tI-#V;L/#-fa1#s->>#7U_,35Z5<.3H)^4=xCT.W76J*TQ&q.u3Cx$_9#44Sxw34%`r'8BAv,*r[2Q/bT#L1lT&],q2Gg1$$4Q/bSf`:%" "A+e'&n.<9/xH:a#x>VG)+[)I-;9bs$b9I)5x'b%$5)gf3>(g2B)F,$Qnc9xH:]7x`kS8I&QEtt@'^-?mtl]NKTj0C&3P$9#M>$G*=]#fC;(ten`G)s;92^#)*t." "/-su/4#>v6];?=8+s%ft)Ki<-&8@60EKuc2>Lqw>OSv(%Rl=?,NDW&+hq;@#DsW?%=X)n'/*t@=)Z:50=$6X?DIO'TR*Lv:gVNAa%[HS8%:&_n/U#Q01L;-o/" "$iMU8_&dS9Ef2u7VX)C?P'T?A(>ZB?pJ?$Amt'[BLkT>A&jqpC5J1/C3XMcuoYb8(h*?x'*;Wi:vlkE,ui&E-Tn[8%q@f[RS/uUH@)" "A`U^J];N@WeKHnkoel8.cM9##-T-T%>glf$cH4.#`;L/#EK;4#Gj@+4uY2)3b6FA#[Bs?#irne2ZsF:.ZGD=.G>#VuRfLJvX?-" "D<`IMe3[>#-J(v#(f$PSR8cN#gFXLUX%>M^Ihd&4g0NPWY7RC#%5oG#(tFd3hiIKN`=(13W,8n1wK8xk2?E`#&'Fqe" "eeLwFxAqeuN/'5Sr*Y'TNN@@uGko@#0FH3<9$7x:;$D#Le$0hTD3@^A.*4_a/1#5NT/0XNv#HmE.3U?'W$" "OFtY-LHW[$8-U:%^h)Q/Mw60);@sAP):#'$25Uf#jYQ_u0Z2WuJcMsu'o)`#T>xs:3d*s%,hW2)Kq6gFdbrQLeB-l35rWt.f#)K(GXM+$..@*./6Kf3bRbX(c41>9Vuo-)PFru&wmMl(" "Z4[79Wxo-)Sb4U%'6CkuovbmuS?]O#/7#F#squXP[PXS.:[DW#CXs;.sQSOur';n&&L$L2(eED5..vW-[FA@'m(WM'cnEr(85G>#ju6`&P####$&>uuvdUV$$GqhL5oL(ilWI)X8%H)" "SdGj':=@8%V)uVH,>`.3RV>c4rquh2Ch_F*U4kD#U`wv$wv9GdZ)E.3OVq/)KPsD#4RNk+=jcrH]rUpj/?51pLvPm8[a=T%3U=]#(>cY#7VG>#3r6s$2SSHFWs9B#h`:B#3MlY#Ui98." "Yb/6&AvgG43?Y?GE3[o&kCw]%P`Ei(sCIW$@J9C-l'+v/0MYb%-IvXP''MX/,JuY#Ip_k'-G'C#INBY$^,tD5_QHD*][NP(WFGJ&CE%'5X?#LNSa1[#CK0K#jp#g(uIwA-qx8;-3f%V%" "6$q%4&e#5AMT>4Dbt)Z#jvBu$^4^F*vb^>$l%o*%@Gg+48+R1Mk1,G4ef6<.&W6C#K5/.M3Q_:%BNk;-<0=r./0w)4M%qNOV#p.*+x4gL6*4Q/H5f)*;vZ]4V%c-?_J-W.CP,G4bI)9BM(v]o-(;T^lN'f:Hs.o-:vB(OIx60fe.w#x5]VQ(`4RD" "dA598Ti9t6V,bN(.VSL(PC.D%xt?x6jCYZ,p]]&;/T_0A.Bq1TJB/T)Ab(D<$6Fs]uC*?>@<7jw,P?*OqOXP&5a46%&4Eo71$DBZ/h?LJLu0sV$2r]l'" "2&2m3L/[b=4;%[-:hs6/UPvk0NMI60tIB'+8C^t%LuB8@eOTc&1Mt[Z4(`aU@O:AnR&L3Ft$O,77T&n))+t6@t-hMIf2-6bv6" "odwA,I6>/(_7$##V[V&&F]>M9rd%##:H/i)DPP8.M)]F4>.e;-FORm/i>[L(^FxU/j.LM96;d;%KEJU.8_Y)49]rS%,Eo'RhR.d#w2/'5o#kH*tJ]B5_gJa+IoZj#K&%-)3IL/)QL%[#" "kLL>#XSnh(vMRL([TgQ&hYTsL^'M_$:Pb?.KEb]u4)c-*@SWb34#ES&Q>(i:@BpM#N4-g)`KB6&g7BF*k?jZuH1v[-s==.)E4i;$o[#G*gsHo#a*0Y$Qt^=#onY&m['3$#8hJ]=L8DX." "j,%1(6tC.34+gm0?rWEe1Huv*VIgK1Ocx=CmSJBeSeCBf[.]Oi7-.AOHuoR<%tL*M8%cW%xiou,&N>G2=/Rk037K,3>U^:/jBuD#P'm<.P]B.*(_Aj0IZD.3-4UB#-uU;b4,PvqmhR:1EM[UgC*+F+?$tl89I&49TQ)G>#$$)u`581n>#/o$W$>R9&+wAaZ,[0@>urA%K:" "#" "KXfi1Z#[.<1F@vn4kVO*Y%Sq/%<;R*R$rP.J.39BL`W->^^W7ECR8%tX-r[K%OB,);2304Pc>#s(]1(vL'97*idT.Hbv?,#b,r%rI6#Jqf$@-K,(@-[OjM1Zr1F4q17Q85o6s$mn([,[hfM'ne2v#" "Cbj5&>:w#-sR?-2[;j61=eD11(I'6&5WxY6Ft)+3o3Fp%:#>r&<4oku;W'S/1ZhM1;ECT%j]_r$Yg1$#Vrgo.[OQP/nnbu%F[VZ#N%&47A8&/CU>2O#^SRiTQb8`u9WuYuSG%E#fU-b6" "`47fUBsZQM^uX%tY:VCaZLOgLQ:SS%n,W<#Q>?pI5w@I*^7pu,nBIP/hV)F3BBMhL#Fl(NHajvPU1BO;/6YV#s=cV#,w2XSMvXYP&0wJ;co&8M?7rp.7k'/q+IA1$bJDT.+&>uu9UeW$" "GAO&#L1g*#3n@-#[;L/#Z->>#NqSM'xZ75//s8n$MqV[,P)n>%kodi$W=8C#MK1h$;29f3Yh7:.?]d8/#i.+4FQPA#$DXI)(#;9/1m+c46i%b%4m@d)[S<+3EI[hM(tI/3SPS)*&1v,*" "('e)*it_F*[pLT/*H)w$-7hcN8,[CsU7io?lm;C$CvfB+@6Me3>&>B891*5l2v#,OV.=]3;au[EBOG[7HI4g`]P1IsL4Di5`_/3*exBh=>5A'XK=865RR2Q/>mB" "T%f_,->'32&Zg],894#-E:1t6R%iA?N>D2UVmpp.mWT5:o*l'4::_b*XA###$&>uu(Mjd$0qm(#1U5l1&`wv$Y^D.3P`&E#UWTM'WUHp.;wkU%;Pd4(9jE.3hNXA#q[R2'&.]n9;K'.[" "V6kQ1gXV?#Y^aL#0_Hu6+_>ucdsgg4D`YY/YX+v#b22[]21xg3SulY#nfQ/(#fjX.o#]fhn))[+0bP70_,Hr%d88GGgtV>#%TGS/emFL#ba.>Pj6.q8Fona?;48%#rtre.^&%W$nqI3%" "#Y$##;EsI3o[rS%Nc?X-#Qd*3ecjj1*RPQ';U,d3=/^F*guJ+*@a'_ac4G&ahL]>]s$[d*j1Y7_t(h2ahL" "OgY=$ax%C#T((+*xCXI)aR_8.bjn--v^v)4+s=JMGIk%$M-M$B(B%<.qm`a4nKc>-bt1IM1&DT/qsoX-x1f]4[/.-^UkV2k)]bY4o]DW#bT1^" "-`K[6BL?8.nbL<-h75xtk(/:b^].<$b0&s$Ruj4SVrw@#.a0)Db1?#_odp#3?N=u%NTkfQ-@8." "VP`Q<1WxmE#O3q.r$].4/2T=^u(.602-qY.fc*`-W?T9VVM$9/;wUu?ZHg;:noxf3K[@$7qLExJ(:2;0=ithX7C%RS%EEWm+scn]+V/2NX7%V2Cv-V4wP/Ne_F*-vY8/ChlA#Nd511+-NigG$s-Gn](Md`?C#i&MlG%x&YYVLeo/?Jr$b93dr//QspA=KGSIULS:d=vRdu75]Cut0Trd8YVIN" "qj5@R<=$/rVB#jn+##(8P:v3px>#&59;-=n?M9u$fu>^r<$%4['u$:5Rv$1-Tv-xg;E4x]DD3%kH)4PP,G4MG9(%gjCD3" "6'PA#]::8.:=6g)lh)Q/CU)P(7%x[-nn=`#W*,T%TVS(#0Zc8/m[x_#+542>##&5>#4`:Z#w#[Qs1EDg(P;c^,]&PA#xOi2:qiDw$" "kUKF*4Yc##@th0,)AW&$bfVW?rgs3C0KaPD/X(43WUwHD%PY4]rsL;$g)QuJtrpiu4m)GiOsfKHl4g>.8-NA+:VXHAGfH1pHep&,3?/@%h?eoK6iMe31O19%[WCQ86&X>LGqAPJ+bs[I" "Rx4Y]@=%_SL5r%bY1vr$DTCG)WkQX-EoEb3?\?QJ(9TN/M:k&K1LEYYu3`'83.5F%p6=A#YxF>#@oZCuHBeM0O0x1$" "(C@D$MbOoLm5?uu6qtM0Iqn%#j*2,#O_S5_/_>:Z-/?ut$2lqL5N9*I-c&Fe-Ni2H*)JJ]$?Iv=(" "GZ6U%>[&b(_Z4>'P^ZD*kJ)g(E8qp%9i,7&'6E9'KL7@#i)HmSR'=9%SO4h(@M)4'Rf.@#^lwd)x*L)Nm#sbriLdF#FaF20L9'6&PXRW$B[@w#$(@j'6>H5&L]iZ>Rsu3'=`qB>Gb7@#" "NPTU[b;)4'l=:[-i9Gh5f*qh5+aWk+v2v3'@DLV%[Y>##*8###,`1?#r/))*&Zu(3v3FV?t<7SR7-CG)81[s$wkH>#VNGs8#]CE4E+ro.wsMhL>/G:.+;@<.T-h_45t6l1O@@<.gs#&4" "U.p6*U5oSDXB]s$l#a#ned]s$Y$D.3O29f3GMrB#I[1EN'U[5/Q$F7%05B>,[M8f3d$f8.iL0+*/=4Z6/kqb*i48K1Fk[@uD;Rc<^^xOS<,Qb%ps^^#NS4U%xg;J2V>Pt27EU[s.oSVk'E@:+*VSh$--4(E-uXti(_.N3*^^^Q&+v'NCRr81Jxh2[-X<-mtkX?B2Z8/LntuH4baOMiZBcN/,ChG*qx[ui.suLJ#x&G3w-ou" "R/)UB]mp3SKQ#3'WL:[,6F0F#[)xN'_%3X.rB8@#K78Q0bZ8QAt>vx4>J%m0t3)YP[%0+*3%:+*OG@&<0c8m&k7v1:'q0Y$5)ab=DHGv#$3540_rTF*C@@s$$&###kC.&bscWY,*`$s$" ";J-W.`?7f3r;Ea48-U:%[YWI)RtC.3N^t87V#PJ_<1b0lsw-Mf-.DS#b?2O(^p4A@glO,I=/gP'5t@>eb%AT#wI`N#5`?*%AY:$-I1R`RKa7l(#?:'#-;b#v'`$s$-75>##E3$5FEuJ(" "lh)Q/x:Ls-_%Is$bp*P(g.<9/Ouu;[Pf$@a''#2jd(#cO>+#=gb.#]/mQW2%x[-/H+G4`@_Y,]crk'4Ta'%iwhWh2O@lL7]fF4o`[@>" "ctkA#&C+G%,uVE4^8d/(JZn4(Xvk7%LARv$Gq;Q/K4pjK@`ifU)jC$'Q,W.-SmG5&Vu" "5A1g_;;o*`.sxtJK5N$5X/iT9mpeS'%0;3=Cw0f$,qF.%50F[#bu.1(Zb5F*>Ne$9hWQD*S`R0(mq8uc;5*i#WJi/8Eqv.MMOWul*([DmvPkiUIfgO_I-GjBb/QY-;PX8f_s9Id)#%&>uu%hUV$YqB'#" "X,>>#j::8.@Oi8.K&.&4f#o6837AjKk0Vt6Z&PA#hg9u$F0Da4px*F3O.rv-d(4I)WEq=%M,#PS'IjPbPus4SQq&KJarwh#P[HG>9H,29j*S]FWKbcDJs[A?49SI#n+^4SQ_k2##CqfC" "[++^f]jt)fj.:>JJSqJ>#fpp_RF#YRC/UJCkPE#7*;1JWmvH4#2*s[$#&5>#Zu^##x/BJ1B_co7^/Vq)aR(f)g`*i(n/1#$xkh8.+cLs-xxxiLAj8w6MJ=l(?W8f3]]wD*.%v,*Q35V/" "YE/[#k.YV-A06l1[X>g)^^D.3*57X1o1x`*s_J)av'UA?(]`h3#DY>h-(Og3LqjC?1*TAaam2`>UAcD4khI:.'lR_#D>s<1" "fGAh>fw(73Ku-LG'`:KMHL/[#oqFgL:L>'$aL+c>mp[RQlEig%#-Kl)e?'X'3nE6/`F1lBSukFTdkTxiYh16&X0D-M4Wvg2ZH^j0EUKq%)Ab61?]=U&qSQR&ZLVS%N(^2'oblZ,c$;=6" "4;n7&Dg0e;U15)4V^k78knWD<70FL)%+n$Rxb;-_t`;$=sqL1t2^[#" "NZPN'#qYJ(E6TU%&OuQ'M:DZ#WHkt$1O2<-bkxW?qHQAOY)vJ(@(m#@,UHo'>S4Q'Gi1Z#gm%5]?=c9CYPZJ,#*#lFp4MC4JPej'nn$t&JcZ/[tNn5GH,$4m0YuG4<=B*uIiwd)d@.FO" "WmWE4R;)Z-Yj^m&o48$$3fL;$g2((,$>^F*B/-@-,,;Z-QFft1R7_S.%vnh(^*u=8.6iI;djUb,9Z']6V]Uf)4&V11b&?l3`M%-)[WGN'PsJm%$oU,)8xj%.J6a%,oi'h=:#3l*Pb)s7" "9DD;.rd*g=tB(R)^Euk0`oaB4D;e&4Nr.3Di?A^5@@Da$ofUr..-Q,2^o-V)*J/].'Yg(>f+*K*+U&'PILW:2uU_CG^*wS'IQSB5DL8j0GcVL1HUW:8n<(8#%/5##Hg#Z$4$q:#[x6V8" "4XBN(1d(T/U&iX%'@t(3[Z*G49&m,*_&ID*(4Qv$6Qv?.QKZd3d^s/Mds1AX-RZd3=U4mu/]29/ESu>#'Wq0*:5*g%Fg*]%7o8gL:a@.M)D.V%3=@sZ3J^&=HCHE+v_v7/]9]nLk0vN+" "AF5buDb)+O7SIA-=xZ9iWeIf$PSv,OL--05x.?'9:h9Dt7j;B%N=?>#1fb+DE@(gC&-&##BC)?#L&nD*n,U:%Z(U8.'c*w$p^&+%r;Nv%x:.fNr$[x6%c7C#5o68%c3hfL35`[*:p?A4" "'2f]4[#[]4A?Ea4b+E1'b'Vk%N3B0KJRns$wJaruZj`X@(mSf&MXWT%s2$E3OBou@6[UPDAg&-))x3W8(4hj(-H:q%ZcRP';4n+2@P3Z6fh8@#^jTU%9wVh)^#md*BXBx$?=q@gR=IP)" "Dme](x=rY$-vdE3l'qh#i_3ku>p*T%YHF&@iA1)Aq[#%A'g&F*1=99&^;VK(iV.5'rhbGM;t8Y>JA/?0C..w#s(,u@vK#H5'kAR/*fM>P05YY##&5>#0GY##%gw7Ed6b#+uA-#N'JQ@5;crhv#ovPN'LLhY$EOnW$C]Yk,##)]$s$'7###(0f-#9->>#,W*i(wqq8.sfEm$6g&F*)>WD#':2-*/7?[5,FYI)*)TF4%eOv-9O#,MhIPs6dim;%xH-1,u4YJML'8;4Xf@C#Cm:9/tbg/)k[i8]" "KDb6RSk3D,#1I>#*@C&5vENK;cGO/ddC2,TopR$.U-t*,Wv=*4ArwC#vh5)4o^Y>BeZ[c*VK]coA5b`+&lCZ-065x65JPg3@-IEN#6&BLu*f.%DN7subfuXB,sqaUmL]1%6)pxJ3#%,44#36>>YKe.:IDw(<-(35&x[kGY##xB>N02Vs)#FXN1#`+O$MS)B.*86YJcNoT,N;4Vp." "8o0N(X3etJEx;9/XSNJ%8cK+*I5^+4OK+Z-=kiWJ&o]L(3'p8%?@i?#ax;9/Y3Zt1d&Mj0x<7f3aGUv-YiWI)p_UItGWX;.+.5I)A1iG3^12X-7(it:@oGj1XL(KME=/GOtZ6#YM:2+G" "h&HAMJ>&`$_+vW-C5(+%c5rFMYY--)^*conL(u(*=.3//P'f%k**Pfil0o6-D4YOg1EZ2%$a=Ho@YlI%-plAB+Ab$g)l`nH)k$Nm/eKOs4Bx#&F2s8'+QfMp/C:-lLC$r_&PdlN'" "83o],[,1;.t%SL(^QKq%eO7Z7/rK+*2S4m'W>Ea*JpX>-wP)o&o^b(3e&67&U2*E*9JY(jH1/Z.lcIh(%jNU09R[-)t[^F*rx>#TNb&#FcLu76&vG*0(#hOhr=c4U3niLZ(RW.t6]8%?$.-33.5GM[i)T/-vgs7.OYH3,T/i)MSEF3-_qk$#ir*49,B+4noa.3Np+u-'i9mAIWeA,6wnU.r50i)XvnY/" "PR(f)g>Zv$%4Ag)i-tm3r7i.xP'p$m81VqZG$2+xh(T$OT%E^1O'IN4>-m$BQ&_KA@u1<-g[*E:due]uou)MLw[+cjE*VZQD*-iX.)K=rv#]%b**Y5:8Isq>2(RJW**" "O'96&+E5W.moK;$+>G>#0Pl>#Zk7[#RhmY#a3c/(ErD^0)71(*b7a+9QWH*oVrK(oS`Y5UXE$$_Fl?,(vWi(h0830Msg#$o[^b*#qH-3LkN9%5Mc>#" "?ncc2nskK1/i.@-v.+**Un%[#)8G>#m3fh(LKuY#MKG3'aSw.)#-Dc##O+LS.XT^`3R4K1(3=+D#T5Du$[fv8/(S/C4]NeG*@GUv-]]WI)N5lf_'Kw&_&vlXc8'+DrW@Nmu>[PiPmRa9^%lvpmL^bug`7gN#Z;*hY8J.XuE(aVP%Z4AnWreW#" "7):J#QoMx^a62sT]%Ujug$[V$eRZ3;dd/%#r2h'#X*+S(#rw@#jKPJ(bB:a#h=S_#8a)F3?DXI)WTb&#$)d;-5s=L)`pN#FT@qo.]?L-5^#^?Ca'j>U`SV,FCp4W0?No^5.1^U%U>FI#" "f]GFu$[vVufv:ONK4[3F/>$g#0Cd,-qDN80AwTS0ZB7qVi9@###>_7%MB5##j$),#YQUV$Jj:9/6cGg)n&PA#(cK+*BxF)4H)TF4[C[x6mm/R/Jc7C#`]J,3TQO;.W$5N'B.^;.i#c?-" "?:2=-N=9k$0PsD#+<;[01EQJ(2`*D#Ph%d3ef(a48AEY.$:*Q/dFMX-+0*F7#2K+*wtu+UlNBTH0q%2w%49U5487+CAs8Zor?#XNLw." "lh&7&ti.?5F2$a=$bb5&.-2e/9'4t&v17%JYYokTCp>7CIq8Q&m?'JN%hOXA>XnW$q*du/:PlY#Z-1H6ncu4/gGUZ-RJLKCmd+45Wthu-Z_wW$-T'Z-pTKm&EM?N#:Y^Z+%4'q%/Jba*" "pK;N2k.X-EMZa1)HMSduIQC,3dF9/)FL@[#I&]*+rN/h389]9$%O0g9tT%/:jl&CIX7eo.tS7:nk.LU`Aig#.xi'" ";Ilo7OqerHS7/DW?.tX?`eb0NNebF3^q[s$@=@8%=qBd2N9K:%xt>v$-CJp.lTnF4nN5Ls/@Rm/N5^F4CV*f2.Gpn$H:[x6FQ:a#sbPhLH=3NMREL:%.7Om/h_4V/%bqk1g9^Z.mHW[," "ik6mL(FUF*U'D.3lEA5/.LRI-*47m/0?6N')VEj1.Ow20WK]@#_R(f)GmxB/H*Rit4O@q.OoX;-U4fw'maD.3&Y@#6;n_aNZf-<.uiWI),5*j1lmd8/5^-@'DwhhLt&Ol(-Jns.:'#-*" "829f3@;ClLYOj?#BS7C#I[nLMCIiIM3r%Y-[`.XLpVSv$0dS$9%,^v$wCbcMK4&+Od4Ms-?\?UX:5nBX:Cp0j(,CF@9fP,C/7kHpIMGMe?_g2V&X>W'4^FvF+Qf`>#Y(L9A#c-.&,@&<1+[l7),IiXjLWea3BWn([.m(P0p)WL+6gV0(Pf/F*>rb.)gE[A,BsdO*,>5M(An5R*G-uB,fuc6++EZ#O8K>0N_3>6#ELcB6OJP#_u@BoE-I9%]Tja*'fNT%$;#NBW" "i*W<-69NL)#i%@#2'7L(+T;K(dG(C&:wu31#2S5'9'Sf=cnKdM^bM<-k`O;-fKlJ(Ue,Z%M&&A.f*/t-;W8.*fR6U7+64#-/u8E#.a5F+7a>01UGk:0#Dd0'E/.M18`j0(2-3E*;WwiL" "3AIf5Tl&l'g,0@6'$Dt%LDxl'f(*X.N-Mv%Y0H`uo4`;ZdF$ACA8=b%3MV/UPWwJJ4A-#,1&'q%`.C(j&svCpTE2NTOB.jI-v0&+*Wm0MTn8*A-h5@D*V_[s$9@i?#@FIP/r2+G4g3clA9MD-*3`<9/)7aV$CNO;.gJ=c4_l_*4TV[Z$]I.[#gYYx6O7bc3+%%],P]Ol(>%vr-^4^F*ZZ*G4,B-$>J/4Q'_I+gL" ">eVa4Ldw*7EC5s.'-jGM9P7C##x`smL2;p+6Og*#'`=Y6e>K9O@p@OTCxT%;K);pHHaA,o*8j0-mE_$[*s20OO3:m_E#3'2l3n0s*Gn0ORK" "1hQ$S&WWD>[5&b6PhE;$s^=x#O0i/)X>w-)'8sL(<8a>,>E_Z>?okf^f59q9E#LU.hu9[G40F/$)>#]rS^$*)4I)J`?p.ZVd8/NHHsgfo+G4H`NV?CD28_r'P5Alr:pAkew8%4o+'.ej#M0eKQ@-5H#j9g(A'" "(+%RR?rj^-t<)%9,(UhLGxdMM3gfrQ/`F&##_AjY#m;T1T)qcOK(45d1S5#>uf?Tlo1Yqr$2Xx.(soIJq+,7A4e%m%=09ZlA+]Lv#9Z[V6cBeY#9EsI3&L(E#n?XA#N#G:.O1)2MRQrB#Njhc)Z0m3+<8Uv-GZ1T/ZPWe)" "H;d%-u'kD#%*YA#K5TF4``Qv$eIfm0*KrZ-k'4]-bI*9/&XD[%<8eX-BwO?.WvC60g>PL#'VrB#6l<;1IB#&4.J_GPr8CV@/J_fM5tNTB**C_+$v5M@cR#(NZp.XgA.$7qrY#b>#UkFJ(Y]OV-Hfm4(Icb;-Q,r0(-]is0(Z$w9.0^k-$cVfF4l/^I*p;N.3rGU#$tf?K#,Gluuhp`suEL#juh]oX#rZFU%>%lOf28e?j(6ki0)Cw=>`GeOoq$p@##$fh(" "TAJ[t&gfXuP=T%OLAbtu)oaX%82Zxk5l(v#'CxquV1/$jP2vS#:^ZC##u+YuXSYF#_CDl*7djQfH>D0#u_^>$KRJ)+x%'K;cMi+M1?_F*V_[s$9B@.&_?7f3LhwLMqG]s$W8h*<'=Wt(" "8,l4<^EA8%B-Tv-$]K+*,,6J*x&`;.wl+4%==:4+b9mS/5H+wpSf9K#-18<8Q#ssL,9N,]mU)XL`'u2MHgBSI-Dn'&GeJ7m:^WU3M9tL$%EsYLKQ4b7Rdx#xZhM:UdZ$>RBI@%" "%P%(#ZIJK'=O1hLuk@d)-AIj09Fj?#BkY)4iVp.*?C0T%3pD,)WFn8%wO,G4-a0i)(@n5/v?]s$o5:#$NAf4(ed;?%`=^,=6iiEH^.a?-cZ8P*+#b##N<ZxL#q;)P)J?@g)dBCa#0S>r8Z%-n0B;_+%.`h4(qAhQ&2N5vep7'&4" "`PpJs4u@(#Uhc+#o@058['qN(UPOV-ba^u.]]cj)EYUv-i4NT/9,B+4EI.lL+o*w$vOK+*-7MH*=ajU-Oci:%@7*u7[$[)E4Z/i)*fmS%iHYIqCQa7Rhvv_s0VcY#RXE2'#tc(3d;Ot-" "<>l2#=(4B*JL4lfT68t4>RIE+jl#-KZ+VMi`FLIWM'M;2.L'[uJ8f*.EXZZsI=wIBV%rngnD>.aFi=m@Y[" "I4+0jm.FD35^St44eSb+eOcf.,jwi134ap'#pu&#w:@v7)FHg)W,O/MXT,V/)F9u.Nn`$#/2E<%_mq&$ZQHH3>S#KL1YPkjfs-8O1#9kx,lh7J>rH$6BrH" "$T/xtRCT%OUl9uuPF=gL*9tU(]2t-blZh*P^Uk0]/Ea4hBk]#t?(E#AKmD3iB7f3Ev@d)dWX=$+SEF3pe4`#lJ_5/E]DD3-rY/C" "30h^#]hkI#Go=J?WI=W6IPwS#+7Wxt@E)<@=<GxJrCIpn0a,?2n:H%1GDpL/krr$Zg>N0Q3=&*)#;iWs87/<6LUC<9/`o%l'C.ET/iu4c43*j[$>Si=.B?lX$kHSP/l[o=%U1]d/4KnL(xR[Q&F;`Tn,Rg+rCmQF#$3p.U" "7D,LPDEj*8BTDW-C%Ro%Ip2Ab*m''n=;-`Ev--VQjDqUW.up56J80(U)7D&mqD>&#ni1)2stC.3$DXI)v;Tv->=J79O-VT/@Dn;%,aFaX*_,S7-u6?hw=(XL*Fn[**Z/IAVDT+46_>Xf:)(S/)QQ$01Q-Tv-bp*P(QV>c4/6aQ.vNBD3cP>H3J%)W-:KMInJc>/*qKA[u0E2`bcpY3'2q^1pSIMZu>WqN'vkIoI" "o)GoIF,=%q>C[&,epGo)40H_bW3o[#;.mN'*xCT.Gr[H#D8`T.#N,lf*q)>&o&'%#ipB'#sa.-#t`p_,K$Jw#UAr`3G=P*t72Gc>#0.>tVQ.D8%gk^v7c#=ZG20@3lmW-[tZV[iV$9rj46LH6Z'^L/`@LL>cJL(" "eF2.N(dC)3?2'gLLh,:@aUq^#xa96tu1A;6%YX&uJ`M)SnJwUQ0lO]uS>;X-MTP=(JC]_M;Ls:m9e;w$#J$s$+)[o#`DT;-/4T?.E:&GD(0[-HcdHb%k^gdOj&#t$q1,>#lUs)#2rs1#" "9AXjL3cUv-A^$7&s$ru_$'BiEX(G(XD#]=:8.bJL@-EuAgL" "<9MhLbim66XCC8.w8.,rVCT@OU1tM(cf8h(c_mY#d-BT9[vm/(_Irv#aZk,2c_W4:u5kw[#WAdV%:owC#Q/;8&q]d/(T?s@,-xHe4veOU&OiOv,qn)30kwC%,N:>l*-8i@G#=pN0qp&#G)Eol>A(>D#" "F5X'Gwp.G>HV+>/Dox9&o(#G+D9.>_S(#P[0d2c0[##Or`r?<&=fhY'3:.Jd=L#L^?A4O,k.3OW#A#q)YA#>lsY-rwsZ6vuGA#=Fn8%kc>C/29kM(/+WE4;5c$," "Wm=A#li)U/DdJ.*$H/J3tDj63ND*?8CT=D<<[IU/7Mh@63h'a#CYK+*c]]iL,N#<-Vc+p7ZGGF%)xd2(0Sc3FT`c##5tf$Tpwkj1&c7C#l?r8CKJXJM_.L+*ojrv$ACI8%p/EJ33Du`O" "@ril0?Y1v#;['E#-PC;$WYBa#+]sc)pCCp.2P&S@DmIc*PjYR&MR7w#@ksP&S$HGM?@c>%s^12BsVhC#[ZFVH)DD=.ZTEU*YghG)`FrZ#M1-p.,;1[,swGirG;50V)2L1Y>h)?" "-o_l0Ha$W%7J1A5GdGu>Z'8/1$pH@-2[T31S0pW$Fr$s$Q+Q',=4@W$6w?O(B5^:'BHeG*2l-s$_kbD##2x/G3A8k@tXhU)+lJg=uaF3p#cI4gLt1LB#N9XT%" "C78u.M/Pu#@_Am&lIB+*WEDt,'hoN0i+`Umn(`nE^$[iLK.gfLj@gI$RNY3'0P+W6k=Z>#4x$<$i-Qg)lK=T%C<1p9$1s(E&x/T&;)%f5%_VN(irCv#SaKq%3%wX7Mw(H)jF-Yu[S%;4" ";X>`4=GP>##Rd5/%vZ7&Y#]M1b05j'-Gc>#1oIw-.R2)+27lQ'-G(v#M+WP0kCm]6Dt92'IJWI/*=q+*;S5##=m$K1b-[##Q.AS@S*m7[*J#9K@Q/J3NtRpKnOb'4%[*G4woq_,/h_F*" "N$n680euS/pBtR/._9:%@I.[#/sEW8^o598mkj/2S2ic)N#Cp./k>A4n@A2NY$wLM+oT&$GXe8.O;^+4tsq;.NXPcM^iXI)%V-iM^M,W-g_PsSO+p+MP6]8%w3D3,d`I:/MBbD<8.`v#" "@?cx#Or4$,.:o[#e=xfLcGrH,Iu?s$Vh'L%$0vN1cRht6Nn=_PC`A#,HPC;$7C*T%kk.=RH;Nm$dG39QFQ%PAMq%2=WP&IG%_u`-bw7b[8T%GpuV$4SG>#<04*$^1)v#ZvpAT-Wf.*CPlY#C]HS/d_=<$]7-Yuia71$4f1Z#3,*5A7%DZ#oGM,)Qgun&0_v5&" "Xn./1TXWq.d3F]#thOgLjZ5F#;Fws$;Rn<$W@_1(D%*GY#MXm'Y*]@#$####-p=:v[lDw$h]5N#mrVW#-%`Z#xkQg#42CN$8xM[$rfl##14n8%*j:9/,ZtlV4[tD#dDMg1&_*G40U%]," "n1pb4wF]fLs<]s$d[EH*6vD+3WAc#@Vb6lL(dID*GW$@'_v`$'v%K+*j@p^$';h;-e4:lL&4_F*7qjnL%umLMWKihLef4_$HRl3+HpgDExM^T905J'.1O?IMZIWY.k(TF4Q[GhLu?A4g@2=-7Gp;-e9b_MN+r]$(a[D*Rk@W-*IR$9l9T9VHq[P/l.bj.`-xP/e:9K/CO[8%#15GMDW&7.7Mu/Mo`;Q0^'oP/G#;9/" "aLTfL?Iau.ep5V/>3NtCHR,gLKlR_#:C&s$(cd-HoP=j1GVK$Z(R,*VQ+?-7>Hh-;m7nNH7Iq;Y;'U'Ve_q7w_l8/uNdcMZvf:/hL_GtLjW;NDw-L+*$YgBJ^[-th1jB)4lPf;%4oEB-rmIJMcsW88-*+Q'_q#qr)F)HGbf+G4xgaQ'eF#v,g[):8V3Hv$K>DmMx0L+*MUPHM*#JnM" "7#:rAKpVEe0C.lLDF5gL)=>A#uFuZF6eu8/::Ox-B9vv-Jc7C#J(i9;g>JIMC#UgMYmkj1D*)iL'7S_#Wsf.*s`[D*" "UO?S'T,H;%]0N,3[t_H-WY@Q-$t0<.a4n8%FKF1L(FZv$cBsJ:.cMmLCM,J*W-vE7/$_)33)=9/x?,q4K/3v/s'>8'#X^M[%T8V;$]]f#," "3SP>#iBNU.MrCv#LL39%Z]3**=Fn8%gYQ$$I@2Z#?f_;$91iV$]xo>,5+%w#MfkV-d#Lu$wm[a+%rtE*('cY#1u-s$=a,l0QuXZ,?F@W$4.e8%>7wDNO$sZ#Ewn@#4rh;$@-cJ(7Csl&E0t;$s4UH4IkLI,L*@S[" "T0=X$I]uY#fn6=-AL*T%bg^q%NQ.v,J8?[-dJ`,)oMd;%Ss:,)jhl$,PNBY$&Y:%,&OO=$@$gM'fNBQ&OHbt$6:P>#-MY>#-SC;$bCt2(mi%p&QvYN'gDmR&m&HR&6l1v#D51Z-TLd>#Qp_,)AS=I#ahtgLGEZv$" "J[Rw#*P%$$6FN5&0DP>#fGjA+2r-s$UZ1k'a$It-%_ugLwOSffL[jP&dQ&V.Ttw[#9;P>#GdUK(:(Vv#imA;.OtxM'r'DW-SGRL(wi`s/;IcY%-g@H)&1D)++Wvv$,xc_+($9j0Is+Y-" "J^^V.F('u.1L:k1F?W%,nkcZ,VuVT/[H&*+H7PU&$Z%P'gZ9^#k&:H2;0bV7O9B6&vGiG)^G%h(eg44M.pch:g#?n&YdI<&/F-l1GWHR&KVv+<@hk_=Mx1H4OJ+a*/?8/cFofLru,x#.c_;$RXs5&H,3a*:lc>#DOWp%" "fLGv,RWTq%v_L_%eu-W$GLIs$7_J2'QW-d)F0':%R@.@#Y15?,D@vY##-q[g:Wcu3)" "MjDK(I=V?#_)Q/(FHlj'wC_0G8YMq%;l-s$C*0q%=7.W$*;G>#M-Bq%R3k9%(]fh(5;ss%nc,q.9+iv#tE&7/+Q;s%#a6V%W'gm&Tew<$F'F9%v1K^+5BV?%5w37/adcj'Wu[fLCJ[>#" "L3b=$Xju3'8+VZ#6F#DO%w#VV*a*I-+A#" ".]1Z#OeO7eGa_,).`4E*L^Yn&OHUG)CFh_#t&2S&>D2Q&F'G/(Fh#o#ss#Q:iv#Xsuj'1Y8L(HFeX-" "iJT%6k^@LR3p%A[3`#B6T6&,ZS#,a&YX$LvhZH/2nv$jg:g2IY-s.VH[(+3xU?#T`ae)S&:[0G78N'HW^Y$%7Wm/grW/#48G>#/McY#'hsU.#)]h(j-x<$CnW5&S3OT%@+iv#-,N'2r_v#`Hpq%9+VZ#7@N5&N#rc);u_V$f7Kb*H9G3'=n8m&c`%p&ZA.-)_Xn<$a:9'+KRI8%f^5N'Crh;$=w4j'b#$3'WQ#7&@[N5&Gh3X$dv(0(Mkn<$GohV$,DcY#)CZ?$FXiv#" "TD%l'jI8r/6+`v#MdB>$w5:V%$ifM'sx1?#c&b39svTdOJPae5$].q;oXi_%lEw=-%7ro.dgo<$O0J=.s$Q-X=$e@PZ,0Mc>#(<_s-ROVv#M'4]#S>*I)NFIw#Lmv`*" "k&Q&Nt*=$2iCv#" "G'92'5IjP&Uk7@#YSn`*KDWE*X/u8274.w#w(9^+Y,2S&Q'/W$14vD#AZuY#I8*e)?F7W$COR8%[_Vv#DrC?#6VP>#EqMe-9^AqD(e(E*J[60)Bh@@#k^%K#DtNX$c3s?#D?'>$hDq2'" "Lna5&ah/6&BZ6)*u7Al'[0O=$5lu>#6?8],b..01X-B6&lfU>$Wg]2)(ehk1UD6O0J_M;$v$v$,pgLK(s?*m/Ibp?5gb&60A_1n'R;2=.hfO;7C5>$6Q9XB,uaE>-ZMeN1CFsa4qZ5r%" "]aGn&[tQ>#rCJX%X;;S&?_82'bHEY-o`dW.OSUfD@CSB-G5Ow$ePCB#]Cc_+?bD@,MdC,)FOws$qYNe)8L39%K9G/(=(%<$>:7w#rnmW_*g^[#aOUW-?QqG)[#N,@tV6V%x)0s$Gn8m&" "YSeH)Hv--)D=iv#_b&2NIn7p.50S=-B*Qu%g/5^,Y/%e2aT3L#UeX=%3SC;$Mwr%" "`a,7&;(7W$:UW5&0Vc>#STG3'O/n`*:FW5&RD71(`)Hj'4#%;%2]c>#]i%p&@nVs@?aFF+Z1r;$Or?#vK(hLJb(u$>e&6&;UWT%FlY>#LqwZTo9=x#5LjP&4aTb%ui1v#" "9FIw#Uwiv#Q/WA+;x1Z#?]Cv#n#<[W5&I*9Q&" "9RMA$;%%s$>u:Z#9=e8%'0q>$K_ww#I_E9%ce>=ZG*_EeS%$ThV%=BY>#&(9v77YeX$sKa[$T>Qo/2J(52v#g<$ruMs%OjdD*Q8^87)6]##6INP&L#%)*I;[L(#edu%]Zxo%v*(f)obQP/1QCW-$5V#$CVV*.7:-;uYSl>#`f57g^@WReN/L#NH2>98" "&46L,VITa#USW5$NI2X7@$5,mweOIulr22%M66a3=898.8u$;H,IZuPaZS7/wWdd3Cd#A#GR7lLZVxb4Hnc4w?lD#]A-+YBf?<.=@r8.VxZg)Y;.)*6>#s-hfV$>" "-,EBUG)@rn21?[aP&R/M0(+G(v#T^^U%T;2iK]oP'.>X[?p4]$5c)+5]p.V9/dcCZ#>jbxkAUSY.IS(v#vCLW-do,Bt$=wG*YUv>#-TC;$ZK4]#,5G>#" "30J`j[WKU%:MgHQB0qi'8cCuGiISL(>7%[#HJ;/(N:Vv#Jnnw#%b&.3flHPo9Cdg9;t>>p%f8Ev/F/###3&>uut#/p$bGSt#" "1&<`#ZOPb#+b@d#N#:f#%fsh#Q3)k#$W4m#FJ?D*-K?C#FN(KE)i,G4r9PQ-qSID*x1fL(dWt9%?1[s$Shc12)n?g)H3K01[P[]4-@XA#9'ed3i6+;.BP,G4dn]A,1rHH3fBSP/9R7lL" "^%YI)`uSF**[R1MNP^Y@JHl)4M2'J3>:cS0jA%&4w4NT/6I@1M/L]s$`&YA#pltKMrRcGMawsnL$HF/M[N,J*--.[B8$4mLjNa.303Y,2lqU?^`G>)4BOw`4rDJn34]K+*r]G1MQZH.N" "M17:M5,'_-c^*@9)@fg)YiWI)T:q0,PZRv$fX7hGd;Qw92uPkO9p=nE9tVNtE(XD#'>)mLhN4Z-wvkT`;;Rv$%$;v-N3mA#bws^-^0V'8)E&gLJ,,G4(L]s$o90u.,N$=.OHOA#g#Jn3" "XaV_&m,wD*[2.`GRMW=(ThtD#sn-L5^p-j7l^%;%@21<,$<.$/%?$>D]H)tI+6'Wd14'/7Tk1;c'b*U#T@M;$[6J&,J^p;.h2rT9eoR1(+x_T58xFDv#OHas*kLlXu2r*H;xM1v#-t4@l:AG>#MET6&E@VZ#om>r%=:rZuqiN9%K996&0BDa*K9gm&[gl0(Nh%@#Vu>V%E:DZuIBg9;)C9Q&va*.'LUV?#" "(aoT$3+[8%fCofLECR>u2X[s$WBl/(5XXM$Icc>#<=`?uA#YXGL2@9PN'W.GZ,tO0'+" "nAVY5-mtV-v9'q%e`w-)%6^],6p9Z-Zl32(f'`,DpOQ>#)m5E4)5/h(d>`0(d2ZR&s@>(5hoqV$/q``+/_q7'8IK41MuB#,r4x]kx%oP'eb$dDVnX)^'--N'4Hr0(,=D<-8S/p&31h'+" "5&C8.F)Guu2CegDm_#c*Wm:0(4YlZ,x<+g1EFAW.CW1k'n*S[#j%te)S4vY#0.MB+Lg'v-3pek;&.`<-`g=1:o,Tv-AM4%$[rEI)5bCn'v1A?5skb@$AS4**/;iL1JjlR&.R][#'?*@t" "4LsP&?+ha>wFKZ$=[3t$qOeG]kLlXuGoaT%0G(v#oVtq$A+lfC>L39%[]/B+E-p2'NgUg(2'Bp%InnW$`=1<-F'tT%Tm(k'Xv10()K?T.2;>N'PN,n&i;dJ(=:R8%Fqx-%B4i?#Mbe8%" "?RET%4Y1v#x1C&6RN>3'SKBU%l#OE2sB:Qw)*t]gA,5ISiTRKW62[K_(*t]$8(" ":ZMD*.9hs.9)&ouZW(q0Ox6c.O5=?)g^1k1k.FX?RX$tobXrcnxb&LclY#dC>(+M1]n&G]sS&doQd)" "U3K2't[+2(VhSN0vt)?#^WX0=Nr[[-t?oJ1hj.51PYNS&2K,@7obR<$j`O?6?s^S/?G;U8kkRs.6Yu>#gF9f)1eD@,)5AT&<(f.2UN_G)X-':%3l&c3fwl,**BG]u9)hB7'n96&/5[M1" "%MSY8nh.W$w>-e2#9]cGKZ=O<-BRc,Gn$T:[`[/;Ew3?@>#WRp@On?fA=?Jd$'%NId)g=4gLS?o8%)7-_#K^x;9/T:2=-x.n=.@I.[#fYYD4l7Qn*#((02Mt587kiE.3a^D.3.r-*N@3Q#%T4&F.s^^D#HEBF(Nj@/34WG>>>6+^,O^^A01]_V$Y:5c*AGb*3_Y>X7uAG>#2:WP&" "huSB+%ta>-'64:.WrPZ%d+l]H4Wn&4Q:?o1E396`j'XIL<-(8/5'N0FT%C,KPB&f$k(:st?63K7C>as7UJl]IY:@lu>@VC8:/^J]t/xIJ60m8g@#9vJU'=Pa4:RlLZ#GB)2UAl8xk" "5e]I*<%`Z#3PlY#FJVp5cNbc2?xHJ#4lf)6LG)kUJfLWt?##" ",wpf%5iH(#Mqn%#F,>>#>::E3)$fF44c?X-b1tM(rW4A#^u98.=1h)3t=Ir8uH:gs?AovAl6;cu^PipuPRhLhir$S#Ae5rm;obUAhW1+9,ZSB$Yc4gt:cF4MpjD7[iD`Iq5dl:?2bu)M" "e%=,#$&P:v-*8p$9$-;#>ugo.Km:9/[K*dMtBRP/SUT;.p--W?^kB#$45DT.PCI8%ho[^$MC[x6IQ:a#r9JG;59Gb%hD]eM/R)*4QhOh#M(pQ_Y$wLMIs0[/*1O[$wS))3mKY^,.^A.*" "Lh>b@9=,F%sbfrg'wsnLn9::@V3Z;%_E;s?r[,g)ogegL]+.e-P=hk+jnr?#:xNh#&j[)4hm@d#e6@29T_1Z%H-:X%iX0$5RNgU%INpm;^di'+0$OM0viEO'IB9U%c*AW$Z-=X$+M8h(" "i/6?$Nm_g(^1B^+fvcN'/i$s$e`T&X^=>C+;=[s$DwUp7Um$$$>cuY#;pfDE4N?$$,VL;$D3wU7pNJ=-AL`Z#U)@)*'>E@$Mg?d)e2N&+ZtIW$HKR'50K=h)j`vj'_nIu0Z_Ts'`[g41" "Tjp6&RZtX$]_qhCl289&lY-+<8pp[#XlJ@%j`=a*=FR<$Jne<$4@lE*@jR21p9O5&W=Cw,C)VUdFLDv#K3F]#CFi;$^Z$d)[A7],)cR;%S6lJ(8q#[H6Z2p&micY#lHMu$R7qS.$n;)+" "PW1k'DWgV.fC9/)P%@#Q>G.?$1OfJ1ipJ,;aho4(3DP>#S.w40(MG$,^-,j'[n[9(Gff8/;FIW$owo]$(cxB=CEYN'`lAr0JkUQ;dR5j9VaY3'8/Y',>Qo9&(VWW%62Z40Gq;[,+i>G*" "Z#-Z$aBqU@^lsLC`D+>&&IoW$:uhV$CmN)>vYUQ&AI*T%?(2v#9x<[$e4#E*O^^u$CElj'`+8t%.rO**>la[$Y*TQ&U)6?$P-0:%g?jM0gb)6/`c.T&,>>>#tKN`c4QJ,c401b20QG,c4Kq'E#OJSq)r*H87HZ7JM^bP-Mri=c4B.FN0LA#c4&^B.*#<8.Mp.*j$(*YA#sQj-$" ",o$],gU'f)7Gp;-6PP8.rYRD*MYHg)3OqhL8fG<-bO`X-Fa9[0*x6x,fn$k7o]44wgBJJn9@Khn^b%hS))33Y7%-4WqE@TP_nN*KjGMBhID*I[nLM" "HABoL]qR:.9mLT/EC,<.E9Gj'nG.a*LQIgLcGdw*gx)9.YPjc)HS#2+@W$;..s$:(`Z#7oq;$6l(?#4(r;$9[/m&84I8%7:*T%7cY>#,pia-ii_$'gR<9%" "1VlY#BkET%7+7<$m&7617ic>#+MuY#3`uY#/`Pl2ECes$:FjP&:o?8%?U3T%md-[B'1Ft$G'96&Hnw8%1f1Z#?3P/(AN:K(`M'9&=C@8%0e+I-M;P>#;Uw<$MYF_#5rH8%<1DZ#BFwS%" "Th_;%gvjp&1cL;$];9G.2.[8%tZZ^#<7[s$ND;21'P*n0MDYj'8I*9%N@BK/;+M?#[:OcMJ[)Z##qm>$]]>D/3CaP&cXXgLn:av#6icY##<@vW%HRwW$AIes$^CSg5:%.<$Eq]M'" "I<,j'>O3p%>uhv#-VL;$`ROgLDaSr/-V1v#/GP>#1.QXMZP+T%4oLZ#:chq&Ra^u$IH5n&8.Is$7le34k'b[Ep%6Cgg2P'_j:YR_J)$wt=$/(wo%.s$n&d0fS%N8nB$@L'80LcC%6" "<7@s$GljMECP4&+g^mE3#RTRC,GsV$=0Y/(Za0Y$Z;e)*EqjP&Ckjp%/xZS%@XjP&V#vJ(FxSj0Pj>7&T[&m&J?XX$_)%L(Y^t9%FF#@qn@#,DlY#$Y$Q'-V,52" "9q4j';=Rs$6LET%0lhV$sO9^#@dB8/5uU;$Y4ofL7j6j'Ep?H)9@@w#Nj)&+8R*X$V^uN')=-L,,;$p.X#m3'CI%W$m=kM(*tChL1%_2't*1hL>G/w#:(.s$G6.Z$C(QI7Uq&Q&BF_GD" "$=7I)a'T6&ZT>/(S)2O'TtnS%3Gc>#v_B^#^:ffLZ>/<$97.[#<.j,*ht'hL%;&w#@58nNUYc>#717<$+E9hY:F2x$7@*p%9=nS%?(.<$/i-s$NAUw-X7+gLt)^fLJO+T%N#<&+4sXp&" "vbO,M(W)<-:H*T'qnGc*EXp%j18P'nLkM(?.nS%R^0u$[d_K(%$>[/m&HETq%84r?#0f$s$`>eKYLJlY#J)/C&V%VZ#&T.>/9Yc>#rekgL2miV$" "%r+kkkE[>#Elxh(5VMZ#k<.X-0fL;$cmCs$)s6$$m$Z$,&V$A6RG0J)-sjW@6?RH)WH0Y$J2n)*DFnxkYUsH?E3>X$&&###%&>uu&[Vo$Qld(#e@$)*SL1@%dHWl(inL+*7:'E#-NYx6" "IS'i)M@i?#@Cr?#FnPb%Rr$<$k2Pb%n5>W-'W>_/T,P)4TU3F5Y=Ad=r&2O't3?K)1DcY#mX:&V0YXo&#@+Q&.1X#+Qsno',a.u6U]&V#KlsL(RS8B+" ">(T].7u/5'^sTqBtlOs%H)Le;_&0uu@.6x$brVM)BO2COi#[S%=C^G6m'&Z?5Y(Z##@:J)(v&'+dgRJ=921fFD)#RE]QEv@P,f'.inFa=u=$9.6Tp1Rc(4%,>N+&#.iLvu1:ns$?C5##" "gJ>F#+p`s#YBic#F3)k#SIuu#8PUV$Jd=L#UD.&4Y>Y)48J.aFaWN/2W]b>&pwEe-']_6(a2E.3bMul9L1YD4@&dG*+GpGMASu)%c9Gj'fPH.%QV-g)H9k0,JbuS/YD]'.*r+gLh9j?#" "9v_T.xD-_#k8on$Qf_8.Dh_F*5<2?>8[uS/&E.^$iq'02@+[hYG8#'$tBr8._MPd3?]d8/e^nI-IlP<-o3IE.[ujI)R8rnE]*UfL61B.*u8Zf;;`E-Z(rn*dl4;&0,O%],oT7x,bkNB-" ">s<_$ua)*4VQ>wTckf['h($dN^I$iMjG5gL3A8+OoUPf*_/E.3X/L6a&'4LkF,DSfL=SQs.4PP/2&nM#&d`DD3VuQ,*#.SY-A^CUqm2Te>;i1T/S_S;8PO:a4CORLMT&1f)+14N0@Cr?#/P,G45c.3:XO,<.g<'u$VaOZ-G=tEed,4j1#IsM-" "NC#[.V4@]6n*6&%ZS[]4,Q1u7<7-SD/w(hL1RKh;..pAZ*gi&.x2shLv6bF3&VI)cG[:H-GBMiL`4YG-v#lU%h?>)2CSRV%/DlY#@PY>#EvH-)0ASn&w#_6&M4?5/n-K6&@B2R',sro0" "%+Wv#5vR)$>RlH34C2b*8%J>K_IT/)NIbp/%c;v#*7,uBR/;E+l1f1(=fC;$#CAN0Cs2&+Qk'&$$FV)+65CC,E[[w#lGh-2/ot**,_7(+x@6hGU$A8%US(Z#Wk[S%dth%,Ymf=-H,[H)" "wjR*+DhwB,K0#3'L;Hc%PU2)+tBac+wJQn&:uU;$TMe-)RVW&+MC860?McY#lO:x$E/jA+bUC[,Q=$H=b)(e;li#@w86&gG'w6N$,<%8+`;$7[_B#[;h>$OqjT%a]x]%rNlN'?e8Q&iJ6r%[PWq0eurB#:h,12UE1#$.[?G*j:8T)" "=@6:7*CoJ1H.TP'W(1hPw]Am8`g>N'Tnwo%8ccY#Y#dR&5;G>#Onn8%g1'F**$FY-%7L%O]k[S%A-53':_oi'jZFg1mmg6&R0F5&5Sc>#A[N9%7Y1v#X8q[us=R-)c0Hu/Qt;R51la+3" "I8l%,BPeS@JjP>#8%MZ#B5%?@%[#-AP>#T=C8KBB:,)_X*X$;(b8&T($#-nVXjL=CJ<$V(Ik(A5ag(ha4,2R6P/(7CDx$" "GFws$Jt3=$Hm14'`n`20sX=gLoWxr1Dp?-)%=.Z#Hhew#UrRfLZ*(V%HaC;$*J(v#b]Yf*sxEC$5uUZ#50G[CM$xW$E/jA+<>mZ#T]:Z#E<9:%0ix=%3FjP&0gLm&SOeS%,DcY#2i1?#" "0`(Z#;*cJ(.(bk'>F3T%g8m3'<3Yj'Rh_[,8F+]#i)Z]4WlPE*EpQ)*9#/'.#ubgLL$7v$7YT:/$16qT-X6:<;5?^Cb$*m/2.pfL6#iP0?-9:%CS1v#.DG>#OZpU%D0D+*o_Bf)OkWP&" "u4BPNINff<,knE$.l$W$BgQ)*a_:@,xQWq.sv57&Yt%_Sqk8Q&CwWX$@kmP&hAGA#KdHD*T*4t$0]1O1$c=%5xN?%5)JI?#U-i&2hPe-)WWG3'ER,M(X*8W$Ow/6&qfj+*`/7uLEBxd#K$F=$H4rV$PQ>3'LQ:g(HL*T%,YL;$Y%V?#uRZn(5hq`-UGUr.XJl`<" "^q9#?w/HY'fI7[#a<&n/?`:Z#0u$<$0O(3(w2Kr.H50u%BX,3'Qe[S%]EJ&@g:;?#]UiS%viJmAfSe)*.g?=$JW57&4bhN(-]>I-A0';.VO3t$>l$W$q-V[,Lqns$%<[t.KGf1(FeE9%" "2-3P]X+]fLm%[>#.SlY#B-0q%hOC<-a=]fLqrYF#[P.1(xmmS'Q?Xp%8#)[7T&-3%iLV;Th(57eS%ek,AOCC9K25<***DEe*$LMG>#VsP7&$jF&$c&_e;K>fH)GMF&+6M*+3=h6S[HHpm&?]C;$^%6^$4@WP&c8(SIN/7L(WnH(++;*0(/RG2(" "q^BY$^Ggl%)lG(m&^e-X-58YEENJpB+U-eTiN@H>#OJ*I)QTa%,UgjD+Li;=.>ltI#QU7w#N'Ij1t-9AbZKsJW[$W:[8%" "hk$],af`O'5pCv>$Qsv6RjDE4_S2v>HZLa4%[*G4Ub<30S`jj1d^Tu.b?+C/GnHh,joXjLIQrhLrGPA#&-UW.%iH>#YjO?-up>`-ZFFX(cV))3G.cU%/BiAJouWe@-mNT@0?oI)#wo7(" ".=Zg)s]v_,=46q7ZWiW/J%.s$``G>#2CBa#*V%)@[JuY#XJBPUOY02O'x*4TLtpBT(J[ET%U.;$-0:0kMQU]wY%Bie)W+>$,/mxC++xS'h/C5L$$Q)" "89hQO1:b]iF?ceRW$XYqZ-,Ger%7l:v#ZN4:K9F7@#HJxu,N?533AMvk18%" "_kHP/U>#)]_FO1&TGg1UpVa4x?7f3>DRKs&kn5/Y;i`3TSUR'4xUv#hk,K)N00u$pW;E4+X9[6hPIl1-RPQ'" "8=Ps6kbhlLokkj1OoK1&X@[s$^K]*7lmAW-ILpE@ed`m1hueD*Lp%32TUa=.E1NM-9DNY.DfWF3Z6h%1R@k@$onXgLGYC;$mU8u(uN+m&)OYV)CL82'7S(v#L`x>," "<>cY##ND[K5+m*s%x)Wl(R+5C+M`VM0Ye3bcr,d31crwlDB]#Y+MO3'QF@,ASvmS`*>o07r1$@jN:a#AlU;$TdIYPFFvg)NfZ),0,mA#GB#n&T#oB5PL%;%xi7P'P,K]$$+J[u3+vA#S/ic);W07/7rR>#^IF,M5)Sd#3%Is$" "$5jb3Lhw.4E3D^+R_'^>P5mj3iG=a5O]>',EPx6:p7=<%+oJl'Rc4Z,Cfw3'WMp88904v:F9HO0<[:+dm?U]A2pQx#[UEk:_/SHF=4ZV@oWLJH:VC_%S1'Q&6&#B?jcxi(.?=V7koj&+" "VYH981l:?#(Q=4L$$8^5XCIA#xwNmJlYdn&Ip_0(L*3p1_I]*Fkd7^5SDj#?m7.X$I3Er7Cl]605S3N1wRB_4cqj5&]kI$7%7;R1wX15/)&>uuTtUxLjTw##^d0'#6&*)#-->>#+dfF4" "^IcI)7%W(&k1TV6#@n=7@oq_,V5MG)9*([KvW#C/ojHD*p;Tv--LBu.gag20?.xf1Mt587DY4Fqf)w;PA#f]w20iCV5&Rk*9%rpJF%Z9j0G1;Ml,v$?q&O:ri0" "dpOh#?vlFVnWi0*,)V_V$.U@p.eLBN(bMq>$M,Ih(,6pV.(x@[#@;@Z$$bsL#0Q&au&[_R#3i+uurb8T;&(^Ho&V@W#$6xH#lp8lO'.jH]J,NU#Y:-uu#?PiH*pwaon_*UiBuV)XL)>M#$*iBv5XAic)Whi?#E8JC4*%C(4BS7C#1m>x6llE.3:2aF3YZf<$BKc8/PD[w'NvMF3$/WO'cDQJ(u3YD#:mnD*" ":]5g)c.5^4n82,)w<@+4@f)T/xCXI)]L65/OM>c4gS#-3T4)v#7AFXCaNAd3NiSfLv?o8%]O)jp@G.$$Of3^*b5***NtI*5?IKQ&8%ED+^j+k&S6cBGo?[p0#FZrum[`99f_`v#j5%D*07rW-Uf[5'Dwk4o" "XtRw#RD>59dl?+`@Rrv/#<1B#k@V*4@:*R2?h&@#caHR&iGOZ6dW,,2/WLBuI_7%siS=#$_,3#BZ)<#ho+Y#7.i?#_QtA#3_aL##JpeXN1CkLk][`*6ggW-JP7.OZ;_B#_^#V/KlR_#d4r?#O]jj1YPOZ6&In=77W&],YDic)_oJF*C]<+3e@;=-$VY8.abL+*sC$Q'" "h[^JCL?DH*L@[s$dW.L,sGnA#xL,W-a`p?9*uLkL&I8[#A9$j4`E4o=I%-N^D.3_;[6W=GOq2=D^+4pk0B@97ggL/Kco.Lq[s$ElVI." "-d%H)n$6T/gG+jL*gMO=8+dg)GqC.37i#OOiHuD#lCY-Z7BiA#R)]EnPWIv$njKDMv;.-&%KM8&Z>$L7pCn_s7*,R&aF#G*=.Rh*(Le>#_$fs$_0tl&g5[(>kKi4'xOK.=F4#`4>^uGi" "5&)o0O;RR&j[iV$*Pgm&*6PM*buLq8knap%" ">$2.36V/mA:YG>#MwjUmA)`K(-6V0(GUET%g]W&+:rqV$r2lg1'UKD38[TD3bKbR$A+n]u.)EZ#3'HN;Y@%Z#g8wS%7huh2Dejp%#R,n&H+iV&H=k`ueqEK(,qe&,#th$%/rH8%/,5Yu" "D)2cY.c_;$'$#N'fX8u.3vk3+TAG>#>qsT%nEf@#B`rh)h2-*3q$4T%@,vx#H0kT%t&1r%^G#lw6x,'/'Q&/rEnu_M>5ndEB+4w/a<%`=bF*j*.);e#/3Lv=V1Xw-f=xtd2=.?`m:Vx),>$38iF" "?:B@8`vE(5&g9v#TWJR6uRBZ/`Hg8%fL#G*=20]tS0xN0Oi1v##l),:.g_jO:MwAs$`H's$J8D;$p?#ip>oNt$Kqo9%KBHV3k.A;%<_sP&Lu>dN4:Lga6t]6&;96#[_ww#avIiFooCG%68Bl8p^r#nCx$8%s=m=l^-(e9*H+8R41<>l)jJXu127DW@/NFr^BK(Wm<[SRRm_CjP9h_'" "oIB,-f9BU[s2Xi&]XE5&M,_X$-+tar$3q')3A@rT.@Cr?#xb(p$n_@K)iA@d)8XiX-c2Jh,@W_aE]5Qv$ZT_*@R6>h>+_#V/N--R#5:t70h&<&+d/Z3'Bjm`*HYr11S+vY#7&5B,BX&W$`)vx4watl2i04t$6;m925w879b[:&$?:2Z#]]H_#Zk;20B/j^4iRm>#" "Dd_K(IAcY#L'Y_-4=<5&D?GN'ck;3,GYVY$x%Q]#hhcG*6lm#72NS],&QHR&H*g2'[;24'0/5>#1Yc>#.chV$fj[iLPlNv#*rgf)JoB8.&.MIGpDGP(:8G>#67E#7GV=**JP(Z%baa0G" "YB:i:_.vY#RY8'+?IGMEq3F?#Lgv`*J;`B7;4:GDp#^g)9Fws$TZP/(hCj0E)6v]#QnW=.l;D&$T]7++D`O<6f%CD$Men<$QiCd4R]h@-`TWB/``*.)WAXjL/g'^#4vhv>bhPG*FiUv#" "%#IM1Enjp%Adk',[Q>N'.5,##-w3Q'W9LcMP:$##$$I:NS@-##HP48NTF6##aN3;NUL?##.]9)NVRH##R3+0NWXQ##0I#5N,@,gLVO[3#+MC;$-,>>#4h.nMS@-##;kY5NaF6##WCL9N" "UL?##Z*'F,5N" "?0n+#;1SnL0NpnL+v:T.-9q'#[(m<-c3S>-d'LW.#-3)#K)B;-/>9C-4cpC-IA;=-]Lx>-DgG<-9N#<--JKC-]qefM.jkjL>F[L-vpTK-?6v5M@F.2.p;ajNV)m.#UF`.M6%T,MK^u5Q" ";X$lLei?lLN=UkL*/K-#DBg;-OoWB-,x26.ch%nLcBqS-$.b+.cYHTcgER)=ELYUhBdF,Pr'#w5[qL.Y,.#(bqpLCA]qL" "g3C'#f6%F-b@?PEbGsVC.BoUC2.vLF?eo*H'ditB%dOVC6*TMF*'FG-I6eW%/1(O;%ibN;)3Rh2H),FHr(622F1vdG:C+,HEu^kEEr'8Dk-M[xS^q68;8xLY#@rGG&#pu#-3/WBJ14Gl-$Rm>G281.L2.amdFgkqdF-4%F-.oBo-6gN:MsXEA-Bd&F4:K*.3%tLb]T3nKP17auGQLH]FJj7kO[V+XC?NPwTV3H@-4gCSC" "7;ZhFhXHL28-IL25+lEWG8$##T?*1#l[-0#B=3ZPx-gfL8;?>#1ZS#,Gc>#0Su>#4`1?#8lC?#,lQ#B8(R#FD:R#JPLR#N]_R#RiqR#Vu-S#Z+@S#_7RS#" "cCeS#gOwS#k[3T#ohET#stWT#w*kT#%7'U#)C9U#-OKU#1[^U#5hpU#9t,V#=*?V#A6QV#EBdV#INvV#MZ2W#QgDW#UsVW#Y)jW#^5&X#bA8X#fMJX#jY]X#nfoX#rr+Y#v(>Y#%>lu#" "(AcY#,MuY#0Y1Z#MW9^#6lLZ#:x_Z#>.rZ#B:.[#FF@[#JRR[#N_e[#Rkw[#Vw3]#Z-F]#_9X]#cEk]#gQ'^#k^9^#ojK^#sv^^#w,q^#%9-_#)E?_#-QQ_#1^d_#5jv_#9v2`#=,E`#" "A8W`#EDj`#IP&a#M]8a#QiJa#Uu]a#Y+pa#^7,b#bC>b#fOPb#j[cb#nhub#rt1c#I)'q#x0Mc#&=`c#*Irc#.U.d#2b@d#6nRd#:$fd#>0xd#B<4e#FHFe#JTXe#Nake#Rm'f#V#:f#" "Z/Lf#_;_f#cGqf#gS-g#k`?g#olQg#sxdg#w.wg#%;3h#)GEh#-SWh#1`jh#5l&i#9x8i#=.Ki#A:^i#EFpi#IR,j#M_>j#QkPj#Uwcj#Y-vj#^92k#bEDk#fQVk#j^ik#nj%l#rv7l#" "v,Jl#$9]l#(Eol#Zl/i#.W4m#2dFm#6pXm#:&lm#>2(n#B>:n#FJLn#JV_n#Ncqn#Ro-o#V%@o#Z1Ro#ulj1#g;eo#cIwo#gU3p#kbEp#onWp#s$kp#w0'q#%=9q#)IKq#-U^q#1bpq#" "5n,r#9$?r#=0Qr#A8:3$BDL3$" "FP_3$J]q3$Ni-4$Ru?4$V+R4$Z7e4$_Cw4$cO35$g[E5$khW5$otj5$pe*9#@/06$#=B6$'IT6$+Ug6$/b#7$3n57$7$H7$;0Z7$?:@<$BFR<$FRe<$J_w<$cqGkEqcqc$8GhoDf(LVCn)fQDxmE(I*SV.G*xIc$Elw6/.U9GH+BJ,M" "Qs5bFvwOVCjMBnD$co;H1PK=Be$Je#5*S,M:;p*Hi5bQD]W'c$)0oUCuvcq;RvElEI/(*NvUr)F9C4,H.HkCIB#8bFj7AvGoa`=BfougF#RbfG85MU1o:MhF)h.gLRC3'/jquhF2$w9)" ":2j=Bd.)hFM?%rLv/w3BDOkCI:%VeGDlDb.akE#0SgLjPE-G$HxUC1LxiFJZ.rLs7GqC4l><-" "V.%I->*tj0+Da>Gxve:CSKDBhp,[&?CkGH2v%eMZZL$HDq16MID2wGIS1aNwY'DiGN1Y?D5/G<0[,Mrd-ZG/8uVC(7,wG" "1c`.G:vCU1$i3GHlq>lEki`]&UQ3N1,gpKFi-D#HVT#c%s`8NB2bFnBoa@?H1[6pD9A2eGP7*Q/^vusBu+;iFZ.v;-Jf(e$WBDVC'6l+$rS6H$&G`*H*kK[1)YQSD1#2*HcO0[H49%`&" "#WXt%4)ddG1#kjE_>=UCG`lO1xRdoD@m7bF3Y*bEw2]UC;aN4NEl1HM$nh?HaJV='e38kO-5kjEmNx>-Wc-x-.-/gLE4.SD*Ch-Oe'Go0&OHlE`9tB%'))iF';^Z$/5vLFgR%ZnBtHQ8" ":IwM1w$8>vhFa)gjB3/XZ14pN5/Gmn1-MD5gC(dXVCt@idGgkE`StW%,/r*HA4o+HuVoc4C&8bFo_,-G" "vM'kElAGgC5c`.G?+f(%2kEs-n,lpLF0%oDX`0[Hx?>F%Au`='<>_oD&jTSD7/C8D#:SMF7H[rL9)8qL`1rjE]2S=B]94b$8j+vBrCHoD)BmH.+xO;(2=2^Q#af-D+^KkE=wElEOK*u(" "@(Ku(6[%iF%5/B&k5FVCCI*hFAT=dM4>5/GM^;dEoxr]&[u0_G&>.FHjh>lE=lI+HNCXn-(%9I$?CpTC1*xGM0fipLBCJ;%j0f/N&4pfL)&Jc$sMkVCpl=>Bw+Z1F,,NM-X%15%AN'A&" "4a?T.7o.G$+oRFH&h7FHsV,-Gq7sXB)^#lE^f#kE$^pgFg;6[&uANn3u2jXB-5,KCt0)=Bm;;X'-+4cHBhUh.pE;9CZ_U68Eui]HFGRV1tOovG/jTSD.m#hFu@SvG/HxuBbZ+F$H.k,5" "c1FrC[K'C%2imlE*fJ^&p)fUCMw*_I/N`a/&&_kErGX7Dni^-6E_7FH8g7bF(s-rLH%IKF`SH&Fm8tnDnZq[-G'S?gChPUC:.v@.lY(HDk)Op7(HkM(,]>e?:h3cHP&c58Q3VDFEJ)=-" "iDFR-Y#GZ-vJ]o3=$kCIB:ae-g]tS&pYt051m__&[:b4Nq18n0hnL*H8lV.GhR,-GBmN>HOxHa.%`%iFaxBS-UcFo$k6vAG7mXVCFF$dM*T@u/x-LoD-/2eGQM?9/q'Q-GV,LQ8FO3N1" "nov`%9s'<-2))6&@3+D%8j8b@4F'jC?`4,/2l?&F+:(@'=)00FjH;9CxdE$JtocdG*+f(%jW76DRrXHM,wcQDhg[UChN9_%25v1Ft5kjE_ue:C5v)IHK[#dEi$nm%gY*dEQ_4k)s,adG" "3V9?$.fV.GkaMb4CR7fGgJbQD4;.V1(8$PEe>ucDsYD]&[Lnp.268/GG;FIts(ZvG4l+(&7I.eG%>2eG:2HAJGd1U1qBDtBj4-oD6`&KDwcr9(hR:0Etx>vGr>9kE.Hpa>Rm5bFw-VeG" ">K(_I,HX7D3pKSDtR&ZGf`5-0m5S=B'9gKF;0aB%1$Bp.3g@qCMf5;)6D+7DJC/[P>>5/G2M]4C(QCc$/;-lE3@7*H1PU2BxYPhFD>[WACFd6Bo)0NB:]7+HrM$@&vV'oD9`r*HLHlC&" "9wJZG?e>T%B>$t-5G%7MGpxv$wxg;-]^(]$c8tN1mYbUCC#rU1CgOdMXanI-t^/k&aUa*,TvJO9DwSQ(IaSK:7vM<%)PD.G)7C8)R#XDN[5U0M;E,[P>A5/G4*GU%;D+7Di&TJCv25,D" "oU]VHhpkcDrM1)E-VaYGj&LDEsjWMBfWxfChs^$&cH/<-vV6i$;f0SD1[&*H.g3]'A,3kN3d&iFT#48MMB.eMZ[G-MTnn6//ToUC;XC6MO?rHM`hP-M9,v;HD:Is-Evt)NP@Kg/:Q4cH" "*h`TC;&l;-9[@q.x?\?LFs*9I$CE8p&-%wP10Pw#JqBViF3(0`I%SA>B9d7bF-KbrC*>W&&8h$=(B#/>Bjo>kE#2ieGZ1gKFm37FHuMbNE@]-bN-d@Y/+t;2Fr:A>'Ij]U)>trhF2.f6B" "DOkCIF$kCI8jNx'ah>iO6XcUCCodBODW[oDoYZD%J<7rLL-OD%pL5nW1?=b$2r*cH%J%eG_hcWBn.8vG3s4VC#n3cH]q@n$>NbfG&8vhFc=T0FZE+F$(:vV%`Ew?H-]w#J*$WMF3rH&F" "5fj*%64`dG$Yn'IdIeaHoe`PEoL=nDnI&ZG&>Rh#xOo=B0i)UD_V&&8,:gE#P)gk9:Li`F?*,d;0pH-db]F-Mu^20CWo5($2%&9In29kEe^nmD,r)pDQ?W%8)*h#$;x+?'olig1@',wG" "i0iTCLkIbHPQ%rL[6K=BO.O*qrFN+jF2S@fGvl6)%,gpKFq[FWHk%61/'/Ms*%hG1k(Cu;2FxC.bH0bZ*&G]8N0c.9kE" "t`YhFuvA/CbTt'%548/GbML)E1,-lEZ5J=B%6J>BYWofCK86N9;R8]$pS^kE]>o=B.4x.Gu/(G$og`TC.:R20fp[TCja@uB$bPF%Xn_Z$'Rd%-G3$J[8(_I0#rU146r$'NHkCI0cDiFLGKPN90w0FpO(N1C%[h,(X`DN9Q]aH" "=psON2a*pD&(c$'Bu3nB4K1U1wX)pD,wR,M:Q2VCxww*HgEV9Ck]HaE0Q1U1*HX7Dr%4Z%U'oFHg.sYGh)9kEm0D.Go8$@&D/05Np0gfL'QAHDdg[UCA+vUC:=GWIwRs#GDfd*.1pM=B9/HBOJH5bFpLFX,dQU<_4.3&&nk`8.vbO;(f:hwK_n^MBkZ'_%+d]YBFg7bF3/$&JhR>LF-8vlEoVUG$2&C8D%LENM" "MvY;HRIZEe+F-WC9Zx,M^_Y@0x_2pDas]jBUj7O4_?.w$4o[/G@dK68e;BO1*Q#lEh,BjB>*+pD20ogL#LT=B8A2eGj,+;C8I7q.sAouB:kE*[67f5Bx%a&&tRr'8MM0$H9Av-GZ#]TC" ")-H'63Nw&O>OTO1)LbfGkM?@&w&a9C;c`.Gw_s#G&ieFHEtNcHo#^NB1;USD:fLF0@Hv$udg,.4pkdMx/0o%6/o6D=;C&g9kEp/g/CHDRnBiKB_%6FOcHi?%UCNVVn3#aF'%oIP#H/VHSDi#b%H(8iaH$fovG" ",8HlE3p#pD*oSvG3JDEH-sFt%$i3GHM$obH3ku'&(rem/Y82=B(?]:CuY/032n0,HFGO$Ho;FVC)l%iFS#=SM;XmvG*q%UCO*+pDro1HD^_M[%ppcB'*8UC#g1eGAL`T.=CRFHW>1@-6eXg$]:o344bV8&UsEX(YQY3F15]UC]2+gMHmHwHM?HKDsH.bH$aDA&Mb>dE+%cV(;8`m/tvEnDi&kjE#pm*&=0l8I*l*,HlPq(%upIvH3^+HM" "b]ElEEg4HM;)ooDm&:,$VEtB%s*vsBp&Cc$L)K^4uOAvG)3]>BvYkUC)S;2F9vFnBwswmD,GiiF-4S.GG;.V17rI+HxMd`%,gpKF$i3GH(tR/GpeC?H)ow+H`ZD(+'Gc92=BAkAvGjScdG_8bQD" "-BoUCm-VeG,40`InR4VCrf?eD3A2eGx1u413YHlE2;2eGt_9kE_HZi4qA_(%.%fFH.rK&4m@7`IYGV=B5>Su'jQfs-MpwrL)a*bN5dKW$hlg7:Ddh?HAmJ-PF^BW$6YCdD4%4,H5A3E%" ":/@V1uJZ%&F)X#H+YI+H+fPW-skJe$>J7N0oJmw&&5H1FCpnrLHE5bFvs3cH>45sHA_LaF]DM=B1rd9Dp%PgC.EvfD>`9#H78Qt$05'oDap]JCdDVt'0G?x%Tqd6Bp2KjBq^IUCg<+F$" "2cw^IxQ7fGH*>BI.MZ1FuT0,HuH=fG%?+vBMBGbH&8[&F*a'kEsmX'%+a^oDg:&$G(#PVC(Dq;-DhI6/>qovGS)b4NJ^EBOB05bFQeSV%r876DI<'k018iEHhb(*Htp76DgQeZH1c;iF" "nmJNBU-7B4viO,D$'N=BxZF/Gg#OnD-/2eG?rIrL5C>+HtmE(IqVM9(tBb20*=f6BnlL*H6>mQUigQT-CXl`'BwIc$ur>LF4STauitoTC'KCm/)l0S)@xnbH/mWO7=4ffGGpR'G$HxUC" "ai.>Bv2fUC1ew+H3GqoDC6;eEM/NPC&HX7D[jX,H3M@+H%mnUCo$QdlEmisqgkXi69om@p&>OVN8bO4U&kj[:CwpNNE2k#>'A7*9.,gpKF[wh,MXm5bFnq>LFivYw&k`(eG" "Gx[V1%/$PE?:mW-dF1l+(JcdGYX`.MB-5bFf0S/:*.x5'9>2eG&4-gL7(kN0i>+:C#t:9C$n7gLWY_@-=-Kg16:W>G1BpCFVCFD&qLf>DnBkYQ`%$teUCwJ00FuA83/5;Z1F)6`0>" ":@vlEEJt=(pY,$P;MF)0bV$wj;?$?]`.G5,HT%4D6@&rp%UCr&sXBf1s0:P8o*F*sOVC&p1eGU))XB" "liRu'047Q8fa;w$,B4VCf%sYG'>BW2g=b7D+5QpDbxGkE2E1U1AiNj0xitUC5T'kE'si9(m$&7N;f3rL,e#+H2KoFHscH`%ggaNEo7w#JkecdGxf9kEa]/n$HD+-Go.)LFtTx*$s8q(%" "#5D.Ga>L)E.d'oD2:ka%,rgnDnB.UCd/^JCuoMa%.HtnDjs@>BfX#1FnY0nDu5A>B" "sZiTCWE<2B>9&gLoUa*Fq6SMF*'s=BV<+[gZxXVC/Fx.G98rU1c?DtBpX%iFx=&vGu5>gCACViF&N)I.$BoUC9QUmB%bVeG%Vnq$" "c`O%JHOGH'?76MpH[oDH`d*.Pa^x&so(*H)W>-G7rw+Hhw$n8QZZ$$_W0c$.s'oDl0XbHN+9PC/:S.G2UFnB&3fUC0(o'Ip-4fGa)Qw&l8ZMC[.=0Dh5_$&" ".;qOE_M^Y%k5N2B+T^0FlnuhF/7=GHaJV='tocdGi)00FfN%UCseeaH&=duB8X@U.2F'OCHjGW-DdJR*0@We$GsL6M3'DVCK,X8M'U5>BM>X#Hp5FVC" "kdvI3:GViFr$vLFMfs=B9A2eG%.SMF*5Rd$-VmLFu4n0#L,P:v%)###TQj-$ePb-TSbNj04+0oQ#####54K4R" "m:Pse(#)##"; ================================================ FILE: src/fps_limiter.h ================================================ #pragma once #include "overlay_params.h" #include class fpsLimiter { private: int64_t target = 0; int64_t overhead = 0; size_t fps_limits_idx = 0; int64_t frame_start = 0; int64_t frame_end = 0; int64_t calc_sleep(int64_t start, int64_t end) { if (target <= 0 || start <= 0) return 0; int64_t work = start - end; if (work < 0) work = 0; int64_t sleep = (target - work) - overhead; return sleep > 0 ? sleep : 0; } void do_sleep(int64_t sleep_time) { if (sleep_time <= 0) return; int64_t t0 = os_time_get_nano(); std::this_thread::sleep_for(std::chrono::nanoseconds(sleep_time)); int64_t over = (os_time_get_nano() - t0) - sleep_time; if (over < 0 || over > (target / 2)) over = 0; overhead = over; } public: bool use_early; bool active = false; fpsLimiter(bool use_early) : use_early(use_early) { auto& fps_limit = get_params()->fps_limit; if (fps_limit.empty()) return; active = true; float tar = fps_limit[fps_limits_idx]; target = tar <= 0.0f ? 0 : int64_t(1'000'000'000.0f / tar); } void limit(bool is_early) { if (!active || target <= 0) return; frame_start = os_time_get_nano();; if (is_early != use_early) return; int64_t sleep_time = calc_sleep(frame_start, frame_end); if (sleep_time > 0) do_sleep(sleep_time); frame_end = os_time_get_nano(); } void next_limit() { auto& v = get_params()->fps_limit; if (v.empty()) return; fps_limits_idx = (fps_limits_idx + 1) % v.size(); auto next_target = v[fps_limits_idx]; target = next_target <= 0.0f ? 0 : int64_t(1'000'000'000.0f / next_target); SPDLOG_DEBUG("Changed fps limit to {}", next_target); } int current_limit() { auto& v = get_params()->fps_limit; return v[fps_limits_idx]; } }; extern std::shared_ptr fps_limiter; ================================================ FILE: src/fps_metrics.h ================================================ #pragma once #include #include #include #include #include #include #include #include #include #include #include #include struct metric_t { std::string name; float value; std::string display_name; }; class fpsMetrics { private: std::vector frametimes; std::thread thread; std::mutex mtx; std::condition_variable cv; bool run = false; bool thread_init = false; bool terminate = false; bool resetting = false; size_t max_size = 10000; std::vector metrics; void _thread() { thread_init = true; while (true){ std::unique_lock lock(mtx); cv.wait(lock, [this] { return run; }); if (terminate) break; calculate(); run = false; } } void calculate(){ if (frametimes.empty()) return; std::vector sorted_values = frametimes; std::sort(sorted_values.begin(), sorted_values.end(), std::greater()); auto it = metrics.begin(); while (it != metrics.end()) { if (it->name == "AVG") { it->display_name = it->name; float sum = 0.0f; for (const auto& f : sorted_values) sum += f; float avg = 1000.f / (sum / sorted_values.size()); it->value = avg; } else { try { float val = std::stof(it->name); if (val <= 0.0f || val >= 1.0f) { SPDLOG_DEBUG("Failed to use fps metric, it's out of range {}", it->name); it = metrics.erase(it); continue; } // Format display name as a percentage float multiplied_val = val * 100; std::ostringstream stream; stream << std::fixed << std::setprecision(multiplied_val == static_cast(multiplied_val) ? 0 : 1) << multiplied_val << "%"; it->display_name = stream.str(); uint64_t idx = val * sorted_values.size() - 1; if (idx >= sorted_values.size()) break; it->value = 1000.f / sorted_values[idx]; } catch (const std::invalid_argument& e) { SPDLOG_DEBUG("Failed to use fps metric value {}", it->name); it = metrics.erase(it); continue; } } ++it; } } std::vector add_metrics_to_vector(std::vector values) { std::vector _metrics; for (auto& val : values){ for(char& c : val) { c = std::toupper(static_cast(c)); } _metrics.push_back({val, 0.0f}); } return _metrics; } public: fpsMetrics(std::vector values){ metrics = add_metrics_to_vector(values); if (!thread_init) { thread = std::thread(&fpsMetrics::_thread, this); // "mangohud-fpsmetrics" wouldn't fit in the 15 byte limit pthread_setname_np(thread.native_handle(), "mangohud-fpsmet"); } }; fpsMetrics(std::vector values, std::vector only_frametime) { metrics = add_metrics_to_vector(values); for (auto& frametime : only_frametime) frametimes.push_back(frametime); calculate(); }; void update(float new_frametime) { if (resetting) return; if (new_frametime > 100000) return; // Ignore extremely long frames // lock before modifying vector std::lock_guard lock(mtx); if (frametimes.size() >= max_size) frametimes.erase(frametimes.begin()); frametimes.push_back(new_frametime); } void update_thread(){ if (resetting) return; { std::lock_guard lock(mtx); run = true; } cv.notify_one(); } void reset_metrics(){ resetting = true; while (run){} frametimes.clear(); resetting = false; } std::vector copy_metrics() { std::lock_guard lock(mtx); return metrics; } ~fpsMetrics(){ terminate = true; { std::lock_guard lock(mtx); run = true; } cv.notify_one(); if (thread.joinable()) thread.join(); } }; extern std::unique_ptr fpsmetrics; ================================================ FILE: src/ftrace.cpp ================================================ #include "ftrace.h" #ifdef HAVE_FTRACE #include #include #include #include #include #include "mesa/util/macros.h" #include "string_utils.h" namespace FTrace { FTrace::FTrace(const overlay_params::ftrace_options& options) { assert(options.enabled); trace_pipe_fd = open("/sys/kernel/tracing/trace_pipe", O_RDONLY | O_NONBLOCK); if (trace_pipe_fd == -1) { SPDLOG_ERROR("could not open ftrace pipe: {}", strerror(errno)); return; } thread = std::thread(&FTrace::ftrace_thread, this); pthread_setname_np(thread.native_handle(), "mangohud-ftrace"); for (auto& tp : options.tracepoints) { data.tracepoints.push_back(tp); collection.map.emplace(tp, Tracepoint::CollectionValue { }); switch (tp->type) { case TracepointType::Histogram: SPDLOG_DEBUG("ftrace: will collect tracepoint '{}' for histogram display", tp->name); break; case TracepointType::LineGraph: SPDLOG_DEBUG("ftrace: will collect tracepoint '{}' (parameter '{}') for line graph display", tp->name, tp->field_name); break; case TracepointType::Label: SPDLOG_DEBUG("ftrace: will collect tracepoint '{}' (parameter '{}') for label display", tp->name, tp->field_name); break; default: SPDLOG_ERROR("ftrace: unknown tracepoint type for tracepoint '{}'", tp->name); } } } FTrace::~FTrace() { stop_thread = true; if (thread.joinable()) thread.join(); if (trace_pipe_fd != -1) close(trace_pipe_fd); } void FTrace::ftrace_thread() { struct { std::array data; size_t size { 0 }; } buffer; while (!stop_thread) { struct pollfd fd = { .fd = trace_pipe_fd, .events = POLLIN, .revents = 0, }; int ret = poll(&fd, 1, 500); if (ret < 0) { SPDLOG_ERROR("FTrace: polling on trace_pipe failed: {}", strerror(errno)); break; } if (!(fd.revents & POLLIN)) continue; ssize_t size_read = read(trace_pipe_fd, &buffer.data[buffer.size], buffer.data.size() - buffer.size); if (size_read < 0) { SPDLOG_ERROR("FTrace: reading from trace_pipe failed: {}", strerror(errno)); break; } buffer.size += size_t(size_read); { char *it = buffer.data.begin(); char *end_it = std::next(it, buffer.size); while (std::distance(it, end_it)) { char *newline_it = std::find(it, end_it, '\n'); if (newline_it == end_it) break; handle_ftrace_entry(std::string { it, size_t(std::distance(it, newline_it)) }); it = std::next(newline_it, 1); } buffer.size = std::distance(it, end_it); if (buffer.size) std::move(it, end_it, buffer.data.begin()); } } } static std::string get_field_value(std::string fields_str, std::string target_field_name) { // Parsing print-formatted ftrace entries isn't ideal because there's no standardized // way of reporting trace event fields. ftrace will also print out numerical values // in both decimal and hexadecimal. It's still the simplest approach as otherwise we'd // have to wrangle with raw trace data that we don't have access to, and trace event // field formats that are hard to define and apply. // Most common print format is `field=value`, with `value` possibly containing spaces. // Iteration below accounts for that and returns the field value for the desired name, // if present. auto fields_data = str_tokenize(fields_str, " "); for (auto it = fields_data.begin(); it != fields_data.end();) { auto assign_pos = it->find('='); if (assign_pos == std::string::npos) { ++it; continue; } auto field_name = it->substr(0, assign_pos); auto field_value = it->substr(std::min(it->size(), assign_pos + 1)); ++it; while (it != fields_data.end()) { if (it->find('=') != std::string::npos) break; field_value += " " + *it; ++it; } if (field_name == target_field_name) return field_value; } return { }; } void FTrace::handle_ftrace_entry(std::string entry) { std::unique_lock lock(collection.mutex); for (auto& collection_entry : collection.map) { auto& tp = collection_entry.first; // Search for the tracepoint name in the entry. It's expected either // at the beginning of string or with a space before it. auto name_pos = entry.find(tp->name + ":"); if (name_pos == std::string::npos) continue; if (!(name_pos == 0 || (name_pos > 0 && entry[name_pos - 1] == ' '))) continue; // Remainder of entry is field data. We use it as necessary, // depending on the tracepoint type. auto fields_str = entry.substr(name_pos + tp->name.size() + 1); switch (tp->type) { case TracepointType::Histogram: collection_entry.second.f += 1; break; case TracepointType::LineGraph: { auto field_value = get_field_value(fields_str, tp->field_name); if (!field_value.empty()) { char *value_end; uint64_t value = strtoull(field_value.c_str(), &value_end, 16); if (value != ULLONG_MAX) collection_entry.second.f += (float) value; } break; } case TracepointType::Label: { auto field_value = get_field_value(fields_str, tp->field_name); if (!field_value.empty()) collection_entry.second.field_value = field_value; break; } default: UNREACHABLE("invalid tracepoint type"); } } } void FTrace::update() { auto update_index = ++data.update_index % Tracepoint::PLOT_DATA_CAPACITY; for (auto& tp : data.tracepoints) { tp->update_index = update_index; // Iterate over the stored plot values often enough to keep // the data range updated and plot presentation visually useful. if (!(update_index % (Tracepoint::PLOT_DATA_CAPACITY / 4))) { auto max = tp->data.plot.values[0]; for (auto v : tp->data.plot.values) max = std::max(max, v); tp->data.plot.range = { 0, max }; } } std::unique_lock lock(collection.mutex); for (auto& it : collection.map) { auto& tp = it.first; auto& value = it.second; switch (tp->type) { case TracepointType::Histogram: case TracepointType::LineGraph: { tp->data.plot.values[tp->update_index] = value.f; auto max = std::max(tp->data.plot.range.max, value.f); tp->data.plot.range = { 0, max }; break; } case TracepointType::Label: { if (!value.field_value.empty()) tp->data.field_value = value.field_value; break; } default: UNREACHABLE("invalid tracepoint type"); } value = { }; } } float FTrace::get_plot_values(void *data, int index) { const Tracepoint& tp = *((const Tracepoint *) data); return tp.data.plot.values[(index + tp.update_index + 1) % Tracepoint::PLOT_DATA_CAPACITY]; } std::unique_ptr object = nullptr; } // namespace FTrace #endif // HAVE_FTRACE ================================================ FILE: src/ftrace.h ================================================ #pragma once #ifdef HAVE_FTRACE #include #include #include #include #include #include #include "overlay_params.h" namespace FTrace { enum class TracepointType { Histogram, LineGraph, Label, }; struct Tracepoint { uint32_t update_index { 0 }; std::string name; TracepointType type; std::string field_name; static constexpr unsigned PLOT_DATA_CAPACITY = 200; struct CollectionValue { float f { 0 }; std::string field_value; }; struct { struct { std::array values; struct { float min { 0 }; float max { 0 }; } range; } plot; std::string field_value; } data; }; class FTrace { private: int trace_pipe_fd { -1 }; std::thread thread; std::atomic stop_thread { false }; void ftrace_thread(); void handle_ftrace_entry(std::string entry); struct { std::mutex mutex; std::unordered_map, Tracepoint::CollectionValue> map; } collection; struct { std::vector> tracepoints; uint32_t update_index { 0 }; } data; public: FTrace(const overlay_params::ftrace_options& options); ~FTrace(); void update(); const std::vector>& tracepoints() { return data.tracepoints; } static float get_plot_values(void *data, int index); }; extern std::unique_ptr object; } // namespace FTrace #endif // HAVE_FTRACE ================================================ FILE: src/gl/gl.h ================================================ #pragma once #ifndef MANGOHUD_GL_GL_H #define MANGOHUD_GL_GL_H #ifdef __cplusplus extern "C" { #endif //__cplusplus void * glXCreateContext(void *, void *, void *, int); void glXDestroyContext(void *, void*); void glXSwapBuffers(void*, void*); void glXSwapIntervalEXT(void*, void*, int); int glXSwapIntervalSGI(int); int glXSwapIntervalMESA(unsigned int); int glXGetSwapIntervalMESA(void); int glXMakeContextCurrent(void*, void*, void*, void*); int glXMakeCurrent(void*, void*, void*); void *glXGetCurrentContext(); void *glXGetCurrentDrawable(); void *glXGetCurrentReadDrawable(); void *glXCreateContextAttribsARB(void *dpy, void *config,void *share_context, int direct, const int *attrib_list); void* glXGetProcAddress(const unsigned char*); void* glXGetProcAddressARB(const unsigned char*); int glXQueryDrawable(void *dpy, void* glxdraw, int attr, unsigned int * value); int64_t glXSwapBuffersMscOML(void* dpy, void* drawable, int64_t target_msc, int64_t divisor, int64_t remainder); unsigned int eglSwapBuffers( void*, void* ); void* eglGetPlatformDisplay( unsigned int, void*, const intptr_t* ); void* eglGetDisplay( void* ); unsigned int eglDestroyContext( void*, void* ); void* eglGetProcAddress( const char* ); int eglTerminate( void* ); #ifdef __cplusplus } #endif //__cplusplus #endif //MANGOHUD_GL_GL_H ================================================ FILE: src/gl/gl_hud.cpp ================================================ #include #include #include #include #include #include #include #include #include #include #ifdef __linux__ #include #endif #include "imgui_utils.h" #include "gl_hud.h" #include "file_utils.h" #include "notify.h" #include "blacklist.h" #include #define GLX_RENDERER_VENDOR_ID_MESA 0x8183 #define GLX_RENDERER_DEVICE_ID_MESA 0x8184 #ifdef HAVE_X11 bool glx_mesa_queryInteger(int attrib, unsigned int *value); #endif namespace MangoHud { namespace GL { struct GLVec { GLint v[4]; GLint operator[] (size_t i) { return v[i]; } bool operator== (const GLVec& r) { return v[0] == r.v[0] && v[1] == r.v[1] && v[2] == r.v[2] && v[3] == r.v[3]; } bool operator!= (const GLVec& r) { return !(*this == r); } }; static GLVec last_vp {}, last_sb {}; swapchain_stats sw_stats {}; static struct imgui_contexts imgui_contexts; static uint32_t vendorID; static std::string deviceName; static notify_thread notifier; static bool cfg_inited = false; static ImVec2 window_size; static bool inited = false; overlay_params params {}; // seems to quit by itself though static std::unique_ptr> stop_it(¬ifier, [](notify_thread *n){ stop_notifier(*n); }); void imgui_init() { if (cfg_inited) return; init_spdlog(); if (is_blacklisted()) return; parse_overlay_config(¶ms, getenv("MANGOHUD_CONFIG"), false); //check for blacklist item in the config file for (auto& item : params.blacklist) { add_blacklist(item); } if (sw_stats.engine != EngineTypes::ZINK){ sw_stats.engine = OPENGL; if (lib_loaded("wined3d", HUDElements.g_gamescopePid)) sw_stats.engine = WINED3D; if (lib_loaded("libtogl.so", HUDElements.g_gamescopePid) || lib_loaded("libtogl_client.so", HUDElements.g_gamescopePid)) sw_stats.engine = TOGL; } is_blacklisted(true); notifier.params = ¶ms; start_notifier(notifier); window_size = ImVec2(params.width, params.height); init_system_info(); cfg_inited = true; init_cpu_stats(params); } void imgui_create(gl_context *ctx, const gl_wsi plat) { //SPDLOG_DEBUG("ctx {}", (void *)ctx); if (!ctx) return; if (inited) return; imgui_init(); if (!gladLoadGL()) spdlog::error("Failed to initialize OpenGL context, crash incoming"); deviceName = (char*)glGetString(GL_RENDERER); // If we're running zink we want to rely on the vulkan loader for the hud instead. if (deviceName.find("zink") != std::string::npos) return; GetOpenGLVersion(sw_stats.version_gl.major, sw_stats.version_gl.minor, sw_stats.version_gl.is_gles); std::string vendor = (char*)glGetString(GL_VENDOR); SPDLOG_DEBUG("vendor: {}, deviceName: {}", vendor, deviceName); sw_stats.deviceName = deviceName; if (vendor.find("AMD") != std::string::npos || deviceName.find("AMD") != std::string::npos || deviceName.find("Radeon") != std::string::npos || deviceName.find("NAVI") != std::string::npos) { vendorID = 0x1002; } else if (vendor.find("Intel") != std::string::npos || deviceName.find("Intel") != std::string::npos) { vendorID = 0x8086; } else if (vendor.find("freedreno") != std::string::npos) { vendorID = 0x5143; } else { vendorID = 0x10de; } HUDElements.vendorID = vendorID; uint32_t device_id = 0; #ifdef HAVE_X11 if (plat == gl_wsi::GL_WSI_GLX) glx_mesa_queryInteger(GLX_RENDERER_DEVICE_ID_MESA, &device_id); #endif SPDLOG_DEBUG("GL device id: {:04X}", device_id); sw_stats.gpuName = gpu = remove_parentheses(deviceName); SPDLOG_DEBUG("gpu: {}", gpu); // Setup Dear ImGui context IMGUI_CHECKVERSION(); if (!imgui_contexts.imgui) imgui_contexts = create_imgui_contexts(); auto saved_imgui_contexts = get_current_imgui_contexts(); make_imgui_contexts_current(imgui_contexts); ImGuiIO& io = ImGui::GetIO(); (void)io; //io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls //io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls // Setup Dear ImGui style ImGui::StyleColorsDark(); //ImGui::StyleColorsClassic(); HUDElements.convert_colors(false, params); glGetIntegerv (GL_VIEWPORT, last_vp.v); glGetIntegerv (GL_SCISSOR_BOX, last_sb.v); ImGui::GetIO().IniFilename = NULL; ImGui::GetIO().DisplaySize = ImVec2(last_vp[2], last_vp[3]); ImGui_ImplOpenGL3_Init(ctx); create_fonts(nullptr, params, sw_stats.font_small, sw_stats.font_text, sw_stats.font_secondary); sw_stats.font_params_hash = params.font_params_hash; inited = true; // Restore global context or ours might clash with apps that use Dear ImGui make_imgui_contexts_current(saved_imgui_contexts); } void imgui_shutdown(gl_context *ctx, bool last) { //SPDLOG_DEBUG("destroying ctx {}, imgui_ctx {}, last {}", (void *)ctx, (void *)state.imgui_ctx, last); if (imgui_contexts.imgui) { auto saved_imgui_contexts = get_current_imgui_contexts(); make_imgui_contexts_current(imgui_contexts); ImGui_ImplOpenGL3_Shutdown(ctx); make_imgui_contexts_current(saved_imgui_contexts); if (last) { destroy_imgui_contexts(imgui_contexts); inited = false; } } } void imgui_render(gl_context *ctx, unsigned int width, unsigned int height) { //SPDLOG_DEBUG("imgui_ctx {}", (void *)state.imgui_ctx); if (!imgui_contexts.imgui) return; static int control_client = -1; if (params.control >= 0) { control_client_check(params.control, control_client, deviceName); process_control_socket(control_client, params); } check_keybinds(params); update_hud_info(sw_stats, params, vendorID); auto saved_imgui_contexts = get_current_imgui_contexts(); make_imgui_contexts_current(imgui_contexts); ImGui::GetIO().DisplaySize = ImVec2(width, height); if (HUDElements.colors.update) HUDElements.convert_colors(params); ImGui_ImplOpenGL3_NewFrame(ctx); ImGui::NewFrame(); { std::lock_guard lk(notifier.mutex); overlay_new_frame(params); position_layer(sw_stats, params, window_size); render_imgui(sw_stats, params, window_size, false); overlay_end_frame(); } ImGui::Render(); ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); if (sw_stats.font_params_hash != params.font_params_hash) { sw_stats.font_params_hash = params.font_params_hash; create_fonts(nullptr, params, sw_stats.font_small, sw_stats.font_text, sw_stats.font_secondary); // Previus texture is created in ImGui_ImplOpenGL3_CreateDeviceObjects in first call of ImGui_ImplOpenGL3_NewFrame ImGui_ImplOpenGL3_DestroyFontsTexture(ctx); ImGui_ImplOpenGL3_CreateFontsTexture(ctx); } make_imgui_contexts_current(saved_imgui_contexts); } }} // namespaces ================================================ FILE: src/gl/gl_hud.h ================================================ #pragma once #ifndef MANGOHUD_GL_IMGUI_HUD_H #define MANGOHUD_GL_IMGUI_HUD_H #include "overlay.h" #include "gl_renderer.h" namespace MangoHud { namespace GL { enum gl_wsi { GL_WSI_UNKNOWN, GL_WSI_GLX, GL_WSI_EGL, }; void imgui_init(); void imgui_create(gl_context *ctx, const gl_wsi plat); void imgui_shutdown(gl_context *ctx, bool last); void imgui_render(gl_context *ctx, unsigned int width, unsigned int height); }} // namespace #endif //MANGOHUD_GL_IMGUI_HUD_H ================================================ FILE: src/gl/gl_renderer.cpp ================================================ // dear imgui: Renderer for modern OpenGL with shaders / programmatic pipeline // - Desktop GL: 2.x 3.x 4.x // - Embedded GL: ES 2.0 (WebGL 1.0), ES 3.0 (WebGL 2.0) // This needs to be used along with a Platform Binding (e.g. GLFW, SDL, Win32, custom..) // Implemented features: // [X] Renderer: User texture binding. Use 'GLuint' OpenGL texture identifier as void*/ImTextureID. Read the FAQ about ImTextureID! // [x] Renderer: Desktop GL only: Support for large meshes (64k+ vertices) with 16-bit indices. // You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this. // If you are new to dear imgui, read examples/README.txt and read the documentation at the top of imgui.cpp. // https://github.com/ocornut/imgui // CHANGELOG // (minor and older changes stripped away, please see git history for details) // 2020-04-12: OpenGL: Fixed context version check mistakenly testing for 4.0+ instead of 3.2+ to enable ImGuiBackendFlags_RendererHasVtxOffset. // 2020-01-07: OpenGL: Added support for glbindings OpenGL loader. // 2019-10-25: OpenGL: Using a combination of GL define and runtime GL version to decide whether to use glDrawElementsBaseVertex(). Fix building with pre-3.2 GL loaders. // 2019-09-22: OpenGL: Detect default GL loader using __has_include compiler facility. // 2019-09-16: OpenGL: Tweak initialization code to allow application calling ImGui_ImplOpenGL3_CreateFontsTexture() before the first NewFrame() call. // 2019-05-29: OpenGL: Desktop GL only: Added support for large mesh (64K+ vertices), enable ImGuiBackendFlags_RendererHasVtxOffset flag. // 2019-04-30: OpenGL: Added support for special ImDrawCallback_ResetRenderState callback to reset render state. // 2019-03-29: OpenGL: Not calling glBindBuffer more than necessary in the render loop. // 2019-03-15: OpenGL: Added a dummy GL call + comments in ImGui_ImplOpenGL3_Init() to detect uninitialized GL function loaders early. // 2019-03-03: OpenGL: Fix support for ES 2.0 (WebGL 1.0). // 2019-02-20: OpenGL: Fix for OSX not supporting OpenGL 4.5, we don't try to read GL_CLIP_ORIGIN even if defined by the headers/loader. // 2019-02-11: OpenGL: Projecting clipping rectangles correctly using draw_data->FramebufferScale to allow multi-viewports for retina display. // 2019-02-01: OpenGL: Using GLSL 410 shaders for any version over 410 (e.g. 430, 450). // 2018-11-30: Misc: Setting up io.BackendRendererName so it can be displayed in the About Window. // 2018-11-13: OpenGL: Support for GL 4.5's glClipControl(GL_UPPER_LEFT) / GL_CLIP_ORIGIN. // 2018-08-29: OpenGL: Added support for more OpenGL loaders: glew and glad, with comments indicative that any loader can be used. // 2018-08-09: OpenGL: Default to OpenGL ES 3 on iOS and Android. GLSL version default to "#version 300 ES". // 2018-07-30: OpenGL: Support for GLSL 300 ES and 410 core. Fixes for Emscripten compilation. // 2018-07-10: OpenGL: Support for more GLSL versions (based on the GLSL version string). Added error output when shaders fail to compile/link. // 2018-06-08: Misc: Extracted imgui_impl_opengl3.cpp/.h away from the old combined GLFW/SDL+OpenGL3 examples. // 2018-06-08: OpenGL: Use draw_data->DisplayPos and draw_data->DisplaySize to setup projection matrix and clipping rectangle. // 2018-05-25: OpenGL: Removed unnecessary backup/restore of GL_ELEMENT_ARRAY_BUFFER_BINDING since this is part of the VAO state. // 2018-05-14: OpenGL: Making the call to glBindSampler() optional so 3.2 context won't fail if the function is a NULL pointer. // 2018-03-06: OpenGL: Added const char* glsl_version parameter to ImGui_ImplOpenGL3_Init() so user can override the GLSL version e.g. "#version 150". // 2018-02-23: OpenGL: Create the VAO in the render function so the setup can more easily be used with multiple shared GL context. // 2018-02-16: Misc: Obsoleted the io.RenderDrawListsFn callback and exposed ImGui_ImplSdlGL3_RenderDrawData() in the .h file so you can call it yourself. // 2018-01-07: OpenGL: Changed GLSL shader version from 330 to 150. // 2017-09-01: OpenGL: Save and restore current bound sampler. Save and restore current polygon mode. // 2017-05-01: OpenGL: Fixed save and restore of current blend func state. // 2017-05-01: OpenGL: Fixed save and restore of current GL_ACTIVE_TEXTURE. // 2016-09-05: OpenGL: Fixed save and restore of current scissor rectangle. // 2016-07-29: OpenGL: Explicitly setting GL_UNPACK_ROW_LENGTH to reduce issues because SDL changes it. (#752) //---------------------------------------- // OpenGL GLSL GLSL // version version string //---------------------------------------- // 2.0 110 "#version 110" // 2.1 120 "#version 120" // 3.0 130 "#version 130" // 3.1 140 "#version 140" // 3.2 150 "#version 150" // 3.3 330 "#version 330 core" // 4.0 400 "#version 400 core" // 4.1 410 "#version 410 core" // 4.2 420 "#version 410 core" // 4.3 430 "#version 430 core" // ES 2.0 100 "#version 100" = WebGL 1.0 // ES 3.0 300 "#version 300 es" = WebGL 2.0 //---------------------------------------- #include #include #include "gl_renderer.h" #include #include // intptr_t #include #include #include #include "overlay.h" namespace MangoHud { namespace GL { extern overlay_params params; // OpenGL Data static gl_context* g_current_ctx; static GLuint g_GlVersion = 0; // Extracted at runtime using GL_MAJOR_VERSION, GL_MINOR_VERSION queries. static char g_GlslVersionString[32] = ""; // Specified by user or detected based on compile time GL settings. static bool g_IsGLES = false; // Functions void ImGui_ImplOpenGL3_DestroyFontsTexture(gl_context *ctx) { if (ctx->FontTexture) { ImGuiIO& io = ImGui::GetIO(); glDeleteTextures(1, &ctx->FontTexture); io.Fonts->SetTexID(0); ctx->FontTexture = 0; } } bool ImGui_ImplOpenGL3_CreateFontsTexture(gl_context *ctx) { // Build texture atlas ImGuiIO& io = ImGui::GetIO(); unsigned char* pixels; int width, height; io.Fonts->GetTexDataAsAlpha8(&pixels, &width, &height); // OpenGL specification defaults, overwritten by glGet but initialized just in case. GLint last_texture = 0; GLint last_unpack_buffer = 0; GLint last_unpack_row_length = 0; GLint last_unpack_skip_pixels = 0; GLint last_unpack_skip_rows = 0; GLint last_unpack_alignment = 4; // Upload texture to graphics system glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture); glGenTextures(1, &ctx->FontTexture); glBindTexture(GL_TEXTURE_2D, ctx->FontTexture); if ((g_IsGLES && g_GlVersion >= 300) || (!g_IsGLES && g_GlVersion >= 210)) { glGetIntegerv(GL_PIXEL_UNPACK_BUFFER_BINDING, &last_unpack_buffer); glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); glGetIntegerv(GL_UNPACK_ROW_LENGTH, &last_unpack_row_length); glGetIntegerv(GL_UNPACK_SKIP_PIXELS, &last_unpack_skip_pixels); glGetIntegerv(GL_UNPACK_SKIP_ROWS, &last_unpack_skip_rows); // Values here are OpenGL specification default glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0); glPixelStorei(GL_UNPACK_SKIP_ROWS, 0); } glGetIntegerv(GL_UNPACK_ALIGNMENT, &last_unpack_alignment); glPixelStorei(GL_UNPACK_ALIGNMENT, 4); // OpenGL specification default glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, width, height, 0, GL_RED, GL_UNSIGNED_BYTE, pixels); // Store our identifier io.Fonts->SetTexID((ImTextureID)(intptr_t)ctx->FontTexture); // Restore state glBindTexture(GL_TEXTURE_2D, last_texture); if ((g_IsGLES && g_GlVersion >= 300) || (!g_IsGLES && g_GlVersion >= 210)) { glBindBuffer(GL_PIXEL_UNPACK_BUFFER, last_unpack_buffer); glPixelStorei(GL_UNPACK_ROW_LENGTH, last_unpack_row_length); glPixelStorei(GL_UNPACK_SKIP_PIXELS, last_unpack_skip_pixels); glPixelStorei(GL_UNPACK_SKIP_ROWS, last_unpack_skip_rows); } glPixelStorei(GL_UNPACK_ALIGNMENT, last_unpack_alignment); return true; } // If you get an error please report on github. You may try different GL context version or GLSL version. See GL<>GLSL version table at the top of this file. static bool CheckShader(GLuint handle, const char* desc) { GLint status = 0, log_length = 0; glGetShaderiv(handle, GL_COMPILE_STATUS, &status); glGetShaderiv(handle, GL_INFO_LOG_LENGTH, &log_length); if ((GLboolean)status == GL_FALSE) SPDLOG_ERROR("ImGui_ImplOpenGL3_CreateDeviceObjects: failed to compile {}!", desc); if (log_length > 1) { ImVector buf; buf.resize((int)(log_length + 1)); glGetShaderInfoLog(handle, log_length, NULL, (GLchar*)buf.begin()); SPDLOG_ERROR("{}", buf.begin()); } return (GLboolean)status == GL_TRUE; } // If you get an error please report on GitHub. You may try different GL context version or GLSL version. static bool CheckProgram(GLuint handle, const char* desc) { GLint status = 0, log_length = 0; glGetProgramiv(handle, GL_LINK_STATUS, &status); glGetProgramiv(handle, GL_INFO_LOG_LENGTH, &log_length); if ((GLboolean)status == GL_FALSE) SPDLOG_ERROR("ImGui_ImplOpenGL3_CreateDeviceObjects: failed to link {}! (with GLSL '{}')", desc, g_GlslVersionString); if (log_length > 1) { ImVector buf; buf.resize((int)(log_length + 1)); glGetProgramInfoLog(handle, log_length, NULL, (GLchar*)buf.begin()); SPDLOG_ERROR("{}", buf.begin()); } return (GLboolean)status == GL_TRUE; } static bool ImGui_ImplOpenGL3_CreateDeviceObjects(gl_context *ctx) { // Parse GLSL version string int glsl_version = 120; sscanf(g_GlslVersionString, "#version %d", &glsl_version); const GLchar* vertex_shader_glsl_120 = "uniform mat4 ProjMtx;\n" "attribute vec2 Position;\n" "attribute vec2 UV;\n" "attribute vec4 Color;\n" "varying vec2 Frag_UV;\n" "varying vec4 Frag_Color;\n" "void main()\n" "{\n" " Frag_UV = UV;\n" " Frag_Color = Color;\n" " gl_Position = ProjMtx * vec4(Position.xy,0,1);\n" "}\n"; const GLchar* vertex_shader_glsl_130 = "uniform mat4 ProjMtx;\n" "in vec2 Position;\n" "in vec2 UV;\n" "in vec4 Color;\n" "out vec2 Frag_UV;\n" "out vec4 Frag_Color;\n" "void main()\n" "{\n" " Frag_UV = UV;\n" " Frag_Color = Color;\n" " gl_Position = ProjMtx * vec4(Position.xy,0,1);\n" "}\n"; const GLchar* vertex_shader_glsl_300_es = "precision mediump float;\n" "layout (location = 0) in vec2 Position;\n" "layout (location = 1) in vec2 UV;\n" "layout (location = 2) in vec4 Color;\n" "uniform mat4 ProjMtx;\n" "out vec2 Frag_UV;\n" "out vec4 Frag_Color;\n" "void main()\n" "{\n" " Frag_UV = UV;\n" " Frag_Color = Color;\n" " gl_Position = ProjMtx * vec4(Position.xy,0,1);\n" "}\n"; const GLchar* vertex_shader_glsl_410_core = "layout (location = 0) in vec2 Position;\n" "layout (location = 1) in vec2 UV;\n" "layout (location = 2) in vec4 Color;\n" "uniform mat4 ProjMtx;\n" "out vec2 Frag_UV;\n" "out vec4 Frag_Color;\n" "void main()\n" "{\n" " Frag_UV = UV;\n" " Frag_Color = Color;\n" " gl_Position = ProjMtx * vec4(Position.xy,0,1);\n" //" gl_Position = ProjMtx * vec4(Position.xy,0,1) * vec4(1.0, -1.0, 1, 1);\n" "}\n"; const GLchar* fragment_shader_glsl_120 = "#ifdef GL_ES\n" " precision mediump float;\n" "#endif\n" "uniform sampler2D Texture;\n" "varying vec2 Frag_UV;\n" "varying vec4 Frag_Color;\n" "void main()\n" "{\n" " gl_FragColor = Frag_Color * vec4(1, 1, 1, texture2D(Texture, Frag_UV.st).r);\n" "}\n"; const GLchar* fragment_shader_glsl_130 = "uniform sampler2D Texture;\n" "in vec2 Frag_UV;\n" "in vec4 Frag_Color;\n" "out vec4 Out_Color;\n" "void main()\n" "{\n" " Out_Color = Frag_Color * vec4(1, 1, 1, texture(Texture, Frag_UV.st).r);\n" "}\n"; const GLchar* fragment_shader_glsl_300_es = "precision mediump float;\n" "uniform sampler2D Texture;\n" "in vec2 Frag_UV;\n" "in vec4 Frag_Color;\n" "layout (location = 0) out vec4 Out_Color;\n" "void main()\n" "{\n" " Out_Color = Frag_Color * vec4(1, 1, 1, texture(Texture, Frag_UV.st).r);\n" "}\n"; const GLchar* fragment_shader_glsl_410_core = "in vec2 Frag_UV;\n" "in vec4 Frag_Color;\n" "uniform sampler2D Texture;\n" "layout (location = 0) out vec4 Out_Color;\n" "void main()\n" "{\n" " Out_Color = Frag_Color * vec4(1, 1, 1, texture(Texture, Frag_UV.st).r);\n" "}\n"; SPDLOG_DEBUG("glsl_version: {}", glsl_version); // Select shaders matching our GLSL versions const GLchar* vertex_shader = NULL; const GLchar* fragment_shader = NULL; if (glsl_version < 130) { vertex_shader = vertex_shader_glsl_120; fragment_shader = fragment_shader_glsl_120; } else if (glsl_version >= 410) { vertex_shader = vertex_shader_glsl_410_core; fragment_shader = fragment_shader_glsl_410_core; } else if (glsl_version == 300) { vertex_shader = vertex_shader_glsl_300_es; fragment_shader = fragment_shader_glsl_300_es; } else { vertex_shader = vertex_shader_glsl_130; fragment_shader = fragment_shader_glsl_130; } std::stringstream ss; ss << g_GlslVersionString << vertex_shader; std::string shader = ss.str(); // Create shaders //const GLchar* vertex_shader_with_version[2] = { g_GlslVersionString, vertex_shader }; const GLchar* vertex_shader_with_version[1] = { shader.c_str() }; ctx->VertHandle = glCreateShader(GL_VERTEX_SHADER); glShaderSource(ctx->VertHandle, 1, vertex_shader_with_version, NULL); glCompileShader(ctx->VertHandle); CheckShader(ctx->VertHandle, "vertex shader"); ss.str(""); ss.clear(); ss << g_GlslVersionString << fragment_shader; shader = ss.str(); const GLchar* fragment_shader_with_version[1] = { shader.c_str() }; ctx->FragHandle = glCreateShader(GL_FRAGMENT_SHADER); glShaderSource(ctx->FragHandle, 1, fragment_shader_with_version, NULL); glCompileShader(ctx->FragHandle); CheckShader(ctx->FragHandle, "fragment shader"); ctx->ShaderHandle = glCreateProgram(); glAttachShader(ctx->ShaderHandle, ctx->VertHandle); glAttachShader(ctx->ShaderHandle, ctx->FragHandle); glLinkProgram(ctx->ShaderHandle); CheckProgram(ctx->ShaderHandle, "shader program"); SPDLOG_DEBUG("g_ShaderHandle {}", ctx->ShaderHandle); ctx->AttribLocationTex = glGetUniformLocation(ctx->ShaderHandle, "Texture"); ctx->AttribLocationProjMtx = glGetUniformLocation(ctx->ShaderHandle, "ProjMtx"); ctx->AttribLocationVtxPos = glGetAttribLocation(ctx->ShaderHandle, "Position"); ctx->AttribLocationVtxUV = glGetAttribLocation(ctx->ShaderHandle, "UV"); ctx->AttribLocationVtxColor = glGetAttribLocation(ctx->ShaderHandle, "Color"); SPDLOG_DEBUG("g_AttribLocationTex {}, g_AttribLocationProjMtx {}, g_AttribLocationVtxPos {}, g_AttribLocationVtxUV {}, g_AttribLocationVtxColor {}", ctx->AttribLocationTex, ctx->AttribLocationProjMtx, ctx->AttribLocationVtxPos, ctx->AttribLocationVtxUV, ctx->AttribLocationVtxColor); // Create buffers glGenBuffers(1, &ctx->VboHandle); glGenBuffers(1, &ctx->ElementsHandle); ImGui_ImplOpenGL3_CreateFontsTexture(ctx); return true; } static void ImGui_ImplOpenGL3_DestroyDeviceObjects(gl_context *ctx) { if (ctx->VboHandle) { glDeleteBuffers(1, &ctx->VboHandle); ctx->VboHandle = 0; } if (ctx->ElementsHandle) { glDeleteBuffers(1, &ctx->ElementsHandle); ctx->ElementsHandle = 0; } if (ctx->ShaderHandle && ctx->VertHandle) { glDetachShader(ctx->ShaderHandle, ctx->VertHandle); } if (ctx->ShaderHandle && ctx->FragHandle) { glDetachShader(ctx->ShaderHandle, ctx->FragHandle); } if (ctx->VertHandle) { glDeleteShader(ctx->VertHandle); ctx->VertHandle = 0; } if (ctx->FragHandle) { glDeleteShader(ctx->FragHandle); ctx->FragHandle = 0; } if (ctx->ShaderHandle) { glDeleteProgram(ctx->ShaderHandle); ctx->ShaderHandle = 0; } ImGui_ImplOpenGL3_DestroyFontsTexture(ctx); } void GetOpenGLVersion(int& major, int& minor, bool& isGLES) { //glGetIntegerv(GL_MAJOR_VERSION, &major); //glGetIntegerv(GL_MINOR_VERSION, &minor); const char* version; const char* prefixes[] = { "OpenGL ES-CM ", "OpenGL ES-CL ", "OpenGL ES ", nullptr }; version = (const char*) glGetString(GL_VERSION); if (!version) { SPDLOG_ERROR("couldn't get GL version string"); return; } //if (glGetError() == 0x500) { for (int i = 0; prefixes[i]; i++) { const size_t length = strlen(prefixes[i]); if (strncmp(version, prefixes[i], length) == 0) { version += length; isGLES = true; break; } } sscanf(version, "%d.%d", &major, &minor); } } bool ImGui_ImplOpenGL3_Init(gl_context* ctx, const char* glsl_version) { if (ctx != g_current_ctx) { //SPDLOG_TRACE("switched to ctx {}", (void*)ctx); g_current_ctx = ctx; } GLint major = 0, minor = 0; GetOpenGLVersion(major, minor, g_IsGLES); SPDLOG_DEBUG("GL version: {}.{} {}", major, minor, g_IsGLES ? "ES" : ""); if (!g_IsGLES) { // Not GL ES glsl_version = "#version 120"; g_GlVersion = major * 100 + minor * 10; if (major >= 4 && minor >= 1) glsl_version = "#version 410"; else if (major > 3 || (major == 3 && minor >= 2)) glsl_version = "#version 150"; else if (major == 3) glsl_version = "#version 130"; else if (major < 2) glsl_version = "#version 100"; } else { if (major >= 3) g_GlVersion = major * 100 + minor * 10; // GLES >= 3 else g_GlVersion = 200; // GLES 2 // Store GLSL version string so we can refer to it later in case we recreate shaders. // Note: GLSL version is NOT the same as GL version. Leave this to NULL if unsure. if (g_GlVersion == 200) glsl_version = "#version 100"; else if (g_GlVersion >= 300) glsl_version = "#version 300 es"; else glsl_version = "#version 120"; } // Setup back-end capabilities flags ImGuiIO& io = ImGui::GetIO(); io.BackendRendererName = "mangohud_opengl3"; //#if IMGUI_IMPL_OPENGL_MAY_HAVE_VTX_OFFSET if (g_GlVersion >= 320) // GL/GLES 3.2+ io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes. // Store GLSL version string so we can refer to it later in case we recreate shaders. // Note: GLSL version is NOT the same as GL version. Leave this to NULL if unsure. if (glsl_version == NULL) glsl_version = "#version 120"; IM_ASSERT((int)strlen(glsl_version) + 2 < IM_ARRAYSIZE(g_GlslVersionString)); strcpy(g_GlslVersionString, glsl_version); strcat(g_GlslVersionString, "\n"); // Make a dummy GL call (we don't actually need the result) // IF YOU GET A CRASH HERE: it probably means that you haven't initialized the OpenGL function loader used by this code. // Desktop OpenGL 3/4 need a function loader. See the IMGUI_IMPL_OPENGL_LOADER_xxx explanation above. GLint current_texture; glGetIntegerv(GL_TEXTURE_BINDING_2D, ¤t_texture); return true; } void ImGui_ImplOpenGL3_Shutdown(gl_context* ctx) { ImGui_ImplOpenGL3_DestroyDeviceObjects(ctx); if (ctx == g_current_ctx) { //SPDLOG_TRACE("current_ctx {} destroyed", (void*)ctx); g_current_ctx = nullptr; } } void ImGui_ImplOpenGL3_NewFrame(gl_context* ctx) { if (ctx != g_current_ctx) { ImGuiIO& io = ImGui::GetIO(); //SPDLOG_TRACE("switched to ctx {}", (void*)ctx); g_current_ctx = ctx; io.Fonts->SetTexID((ImTextureID)(intptr_t)ctx->FontTexture); } //SPDLOG_DEBUG("g_ShaderHandle {}", g_current_ctx->ShaderHandle); if (!ctx->ShaderHandle) { SPDLOG_TRACE("No shader object, creating device objects"); ImGui_ImplOpenGL3_CreateDeviceObjects(ctx); } } static void ImGui_ImplOpenGL3_SetupRenderState(ImDrawData* draw_data, int fb_width, int fb_height, GLuint vertex_array_object) { // Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled, polygon fill if (params.gl_bind_framebuffer >= 0 && (g_IsGLES || g_GlVersion >= 300)) glBindFramebuffer(GL_DRAW_FRAMEBUFFER, params.gl_bind_framebuffer); glEnable(GL_BLEND); glBlendEquation(GL_FUNC_ADD); glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); glDisable(GL_CULL_FACE); glDisable(GL_DEPTH_TEST); glDisable(GL_STENCIL_TEST); glEnable(GL_SCISSOR_TEST); glDisable(GL_FRAMEBUFFER_SRGB); glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); if (!g_IsGLES) { //#ifdef GL_POLYGON_MODE if (g_GlVersion >= 200) glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); if (g_GlVersion >= 310) glDisable(GL_PRIMITIVE_RESTART); } bool clip_origin_lower_left = true; GLenum last_clip_origin = 0; if (!g_IsGLES && /*g_GlVersion >= 450*/ (glad_glClipControl || glad_glClipControlEXT)) { glGetIntegerv(GL_CLIP_ORIGIN, (GLint*)&last_clip_origin); // Support for GL 4.5's glClipControl(GL_UPPER_LEFT) if (last_clip_origin == GL_UPPER_LEFT) clip_origin_lower_left = false; } // Setup viewport, orthographic projection matrix // Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayPos is (0,0) for single viewport apps. glViewport(0, 0, (GLsizei)fb_width, (GLsizei)fb_height); float L = draw_data->DisplayPos.x; float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x; float T = draw_data->DisplayPos.y; float B = draw_data->DisplayPos.y + draw_data->DisplaySize.y; if (!params.gl_dont_flip && !clip_origin_lower_left) { float tmp = T; T = B; B = tmp; } // Swap top and bottom if origin is upper left const float ortho_projection[4][4] = { { 2.0f/(R-L), 0.0f, 0.0f, 0.0f }, { 0.0f, 2.0f/(T-B), 0.0f, 0.0f }, { 0.0f, 0.0f, -1.0f, 0.0f }, { (R+L)/(L-R), (T+B)/(B-T), 0.0f, 1.0f }, }; glUseProgram(g_current_ctx->ShaderHandle); glUniform1i(g_current_ctx->AttribLocationTex, 0); glUniformMatrix4fv(g_current_ctx->AttribLocationProjMtx, 1, GL_FALSE, &ortho_projection[0][0]); if (g_GlVersion >= 330) glBindSampler(0, 0); // We use combined texture/sampler state. Applications using GL 3.3 may set that otherwise. (void)vertex_array_object; //#ifndef IMGUI_IMPL_OPENGL_ES2 if (g_GlVersion >= 300) glBindVertexArray(vertex_array_object); // Bind vertex/index buffers and setup attributes for ImDrawVert glBindBuffer(GL_ARRAY_BUFFER, g_current_ctx->VboHandle); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, g_current_ctx->ElementsHandle); glEnableVertexAttribArray(g_current_ctx->AttribLocationVtxPos); glEnableVertexAttribArray(g_current_ctx->AttribLocationVtxUV); glEnableVertexAttribArray(g_current_ctx->AttribLocationVtxColor); glVertexAttribPointer(g_current_ctx->AttribLocationVtxPos, 2, GL_FLOAT, GL_FALSE, sizeof(ImDrawVert), (GLvoid*)IM_OFFSETOF(ImDrawVert, pos)); glVertexAttribPointer(g_current_ctx->AttribLocationVtxUV, 2, GL_FLOAT, GL_FALSE, sizeof(ImDrawVert), (GLvoid*)IM_OFFSETOF(ImDrawVert, uv)); glVertexAttribPointer(g_current_ctx->AttribLocationVtxColor, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(ImDrawVert), (GLvoid*)IM_OFFSETOF(ImDrawVert, col)); } // OpenGL3 Render function. // (this used to be set in io.RenderDrawListsFn and called by ImGui::Render(), but you can now call this directly from your main loop) // Note that this implementation is little overcomplicated because we are saving/setting up/restoring every OpenGL state explicitly, in order to be able to run within any OpenGL engine that doesn't do so. void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data) { // Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates) int fb_width = (int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x); int fb_height = (int)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y); if (fb_width <= 0 || fb_height <= 0 || draw_data->TotalVtxCount == 0) return; // Backup GL state GLint last_fb = -1; if (params.gl_bind_framebuffer >= 0 && (g_IsGLES || g_GlVersion >= 300)) glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &last_fb); GLenum last_active_texture; glGetIntegerv(GL_ACTIVE_TEXTURE, (GLint*)&last_active_texture); glActiveTexture(GL_TEXTURE0); GLint last_program; glGetIntegerv(GL_CURRENT_PROGRAM, &last_program); GLint last_texture; glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture); // GL_SAMPLER_BINDING GLint last_sampler; if (!g_IsGLES && g_GlVersion >= 330) glGetIntegerv(GL_SAMPLER_BINDING, &last_sampler); GLint last_array_buffer; glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &last_array_buffer); //#ifndef IMGUI_IMPL_OPENGL_ES2 GLint last_vertex_array_object; if (g_GlVersion >= 300) glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &last_vertex_array_object); GLint last_polygon_mode[2]; if (!g_IsGLES && g_GlVersion >= 200) glGetIntegerv(GL_POLYGON_MODE, last_polygon_mode); GLint last_viewport[4]; glGetIntegerv(GL_VIEWPORT, last_viewport); GLint last_scissor_box[4]; glGetIntegerv(GL_SCISSOR_BOX, last_scissor_box); GLenum last_blend_src_rgb; glGetIntegerv(GL_BLEND_SRC_RGB, (GLint*)&last_blend_src_rgb); GLenum last_blend_dst_rgb; glGetIntegerv(GL_BLEND_DST_RGB, (GLint*)&last_blend_dst_rgb); GLenum last_blend_src_alpha; glGetIntegerv(GL_BLEND_SRC_ALPHA, (GLint*)&last_blend_src_alpha); GLenum last_blend_dst_alpha; glGetIntegerv(GL_BLEND_DST_ALPHA, (GLint*)&last_blend_dst_alpha); GLenum last_blend_equation_rgb; glGetIntegerv(GL_BLEND_EQUATION_RGB, (GLint*)&last_blend_equation_rgb); GLenum last_blend_equation_alpha; glGetIntegerv(GL_BLEND_EQUATION_ALPHA, (GLint*)&last_blend_equation_alpha); GLboolean last_enable_blend = glIsEnabled(GL_BLEND); GLboolean last_enable_cull_face = glIsEnabled(GL_CULL_FACE); GLboolean last_enable_depth_test = glIsEnabled(GL_DEPTH_TEST); GLboolean last_enable_stencil_test = glIsEnabled(GL_STENCIL_TEST); GLboolean last_enable_scissor_test = glIsEnabled(GL_SCISSOR_TEST); // Disable and store SRGB state. GLboolean last_srgb_enabled = glIsEnabled(GL_FRAMEBUFFER_SRGB); GLboolean last_enable_primitive_restart = (!g_IsGLES && g_GlVersion >= 310) ? glIsEnabled(GL_PRIMITIVE_RESTART) : GL_FALSE; // Setup desired GL state // Recreate the VAO every time (this is to easily allow multiple GL contexts to be rendered to. VAO are not shared among GL contexts) // The renderer would actually work without any VAO bound, but then our VertexAttrib calls would overwrite the default one currently bound. GLuint vertex_array_object = 0; if (g_GlVersion >= 300) glGenVertexArrays(1, &vertex_array_object); ImGui_ImplOpenGL3_SetupRenderState(draw_data, fb_width, fb_height, vertex_array_object); // Will project scissor/clipping rectangles into framebuffer space ImVec2 clip_off = draw_data->DisplayPos; // (0,0) unless using multi-viewports ImVec2 clip_scale = draw_data->FramebufferScale; // (1,1) unless using retina display which are often (2,2) //SPDLOG_DEBUG("draw_data->CmdListsCount {}", draw_data->CmdListsCount); // Render command lists for (int n = 0; n < draw_data->CmdListsCount; n++) { const ImDrawList* cmd_list = draw_data->CmdLists[n]; // Upload vertex/index buffers glBufferData(GL_ARRAY_BUFFER, (GLsizeiptr)cmd_list->VtxBuffer.Size * sizeof(ImDrawVert), (const GLvoid*)cmd_list->VtxBuffer.Data, GL_STREAM_DRAW); glBufferData(GL_ELEMENT_ARRAY_BUFFER, (GLsizeiptr)cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx), (const GLvoid*)cmd_list->IdxBuffer.Data, GL_STREAM_DRAW); for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) { const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i]; if (pcmd->UserCallback != NULL) { // User callback, registered via ImDrawList::AddCallback() // (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.) if (pcmd->UserCallback == ImDrawCallback_ResetRenderState) ImGui_ImplOpenGL3_SetupRenderState(draw_data, fb_width, fb_height, vertex_array_object); else pcmd->UserCallback(cmd_list, pcmd); } else { // Project scissor/clipping rectangles into framebuffer space ImVec4 clip_rect; clip_rect.x = (pcmd->ClipRect.x - clip_off.x) * clip_scale.x; clip_rect.y = (pcmd->ClipRect.y - clip_off.y) * clip_scale.y; clip_rect.z = (pcmd->ClipRect.z - clip_off.x) * clip_scale.x; clip_rect.w = (pcmd->ClipRect.w - clip_off.y) * clip_scale.y; if (clip_rect.x < fb_width && clip_rect.y < fb_height && clip_rect.z >= 0.0f && clip_rect.w >= 0.0f) { // Apply scissor/clipping rectangle if (!params.gl_dont_flip) glScissor((int)clip_rect.x, (int)(fb_height - clip_rect.w), (int)(clip_rect.z - clip_rect.x), (int)(clip_rect.w - clip_rect.y)); else glScissor((int)clip_rect.x, (int)clip_rect.y, (int)clip_rect.z, (int)clip_rect.w); // Bind texture, Draw glBindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->TextureId); //#if IMGUI_IMPL_OPENGL_MAY_HAVE_VTX_OFFSET if (g_GlVersion >= 320) // OGL and OGL ES glDrawElementsBaseVertex(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, (void*)(intptr_t)(pcmd->IdxOffset * sizeof(ImDrawIdx)), (GLint)pcmd->VtxOffset); else glDrawElements(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, (void*)(intptr_t)(pcmd->IdxOffset * sizeof(ImDrawIdx))); } } } } // Destroy the temporary VAO if (g_GlVersion >= 300) glDeleteVertexArrays(1, &vertex_array_object); // Restore modified GL state glUseProgram(last_program); glBindTexture(GL_TEXTURE_2D, last_texture); if (!g_IsGLES && g_GlVersion >= 330) glBindSampler(0, last_sampler); glActiveTexture(last_active_texture); if (g_GlVersion >= 300) glBindVertexArray(last_vertex_array_object); glBindBuffer(GL_ARRAY_BUFFER, last_array_buffer); glBlendEquationSeparate(last_blend_equation_rgb, last_blend_equation_alpha); glBlendFuncSeparate(last_blend_src_rgb, last_blend_dst_rgb, last_blend_src_alpha, last_blend_dst_alpha); if (last_enable_blend) glEnable(GL_BLEND); else glDisable(GL_BLEND); if (last_enable_cull_face) glEnable(GL_CULL_FACE); else glDisable(GL_CULL_FACE); if (last_enable_depth_test) glEnable(GL_DEPTH_TEST); else glDisable(GL_DEPTH_TEST); if (last_enable_stencil_test) glEnable(GL_STENCIL_TEST); else glDisable(GL_STENCIL_TEST); if (last_enable_scissor_test) glEnable(GL_SCISSOR_TEST); else glDisable(GL_SCISSOR_TEST); if (!g_IsGLES && g_GlVersion >= 310) { if (last_enable_primitive_restart) glEnable(GL_PRIMITIVE_RESTART); } if (!g_IsGLES && g_GlVersion >= 200) glPolygonMode(GL_FRONT_AND_BACK, (GLenum)last_polygon_mode[0]); glViewport(last_viewport[0], last_viewport[1], (GLsizei)last_viewport[2], (GLsizei)last_viewport[3]); glScissor(last_scissor_box[0], last_scissor_box[1], (GLsizei)last_scissor_box[2], (GLsizei)last_scissor_box[3]); if (last_srgb_enabled) glEnable(GL_FRAMEBUFFER_SRGB); if (last_fb >= 0) glBindFramebuffer(GL_DRAW_FRAMEBUFFER, last_fb); } }} // namespace ================================================ FILE: src/gl/gl_renderer.h ================================================ // dear imgui: Renderer for modern OpenGL with shaders / programmatic pipeline // - Desktop GL: 2.x 3.x 4.x // - Embedded GL: ES 2.0 (WebGL 1.0), ES 3.0 (WebGL 2.0) // This needs to be used along with a Platform Binding (e.g. GLFW, SDL, Win32, custom..) // Implemented features: // [X] Renderer: User texture binding. Use 'GLuint' OpenGL texture identifier as void*/ImTextureID. Read the FAQ about ImTextureID! // [x] Renderer: Desktop GL only: Support for large meshes (64k+ vertices) with 16-bit indices. // You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this. // If you are new to dear imgui, read examples/README.txt and read the documentation at the top of imgui.cpp. // https://github.com/ocornut/imgui // About Desktop OpenGL function loaders: // Modern desktop OpenGL doesn't have a standard portable header file to load OpenGL function pointers. // Helper libraries are often used for this purpose! Here we are supporting a few common ones (gl3w, glew, glad). // You may use another loader/header of your choice (glext, glLoadGen, etc.), or chose to manually implement your own. // About GLSL version: // The 'glsl_version' initialization parameter should be NULL (default) or a "#version XXX" string. // On computer platform the GLSL version default to "#version 130". On OpenGL ES 3 platform it defaults to "#version 300 es" // Only override if your GL version doesn't handle this GLSL version. See GLSL version table at the top of imgui_impl_opengl3.cpp. #pragma once #ifndef MANGOHUD_IMGUI_IMPL_OPENGL3_H #define MANGOHUD_IMGUI_IMPL_OPENGL3_H #include namespace MangoHud { namespace GL { struct gl_context { void *ctx; GLuint FontTexture = 0; GLuint ShaderHandle = 0, VertHandle = 0, FragHandle = 0; int AttribLocationTex = 0, AttribLocationProjMtx = 0; // Uniforms location int AttribLocationVtxPos = 0, AttribLocationVtxUV = 0, AttribLocationVtxColor = 0; // Vertex attributes location unsigned int VboHandle = 0, ElementsHandle = 0; bool swap_interval_set = false; }; void GetOpenGLVersion(int& major, int& minor, bool& isGLES); // Backend API IMGUI_IMPL_API bool ImGui_ImplOpenGL3_Init(gl_context* ctx, const char* glsl_version = nullptr); IMGUI_IMPL_API void ImGui_ImplOpenGL3_Shutdown(gl_context* ctx); IMGUI_IMPL_API void ImGui_ImplOpenGL3_NewFrame(gl_context* ctx); IMGUI_IMPL_API void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data); IMGUI_IMPL_API void ImGui_ImplOpenGL3_DestroyFontsTexture(gl_context* ctx); IMGUI_IMPL_API bool ImGui_ImplOpenGL3_CreateFontsTexture(gl_context* ctx); // (Optional) Called by Init/NewFrame/Shutdown //IMGUI_IMPL_API bool ImGui_ImplOpenGL3_CreateFontsTexture(); //IMGUI_IMPL_API void ImGui_ImplOpenGL3_DestroyFontsTexture(); //IMGUI_IMPL_API bool ImGui_ImplOpenGL3_CreateDeviceObjects(); //IMGUI_IMPL_API void ImGui_ImplOpenGL3_DestroyDeviceObjects(); }} #endif //MANGOHUD_IMGUI_IMPL_OPENGL3_H ================================================ FILE: src/gl/glad.c ================================================ /* OpenGL, OpenGL ES loader generated by glad 0.1.33 on Thu Apr 9 12:37:38 2020. Language/Generator: C/C++ Specification: gl APIs: gl=4.6, gles2=3.2 Profile: compatibility Extensions: GL_ARB_clip_control, GL_EXT_clip_control Loader: True Local files: False Omit khrplatform: False Reproducible: False Commandline: --profile="compatibility" --api="gl=4.6,gles2=3.2" --generator="c" --spec="gl" --extensions="GL_ARB_clip_control,GL_EXT_clip_control" Online: https://glad.dav1d.de/#profile=compatibility&language=c&specification=gl&loader=on&api=gl%3D4.6&api=gles2%3D3.2&extensions=GL_ARB_clip_control&extensions=GL_EXT_clip_control */ #include #include #include #include static void* get_proc(const char *namez); #if defined(_WIN32) || defined(__CYGWIN__) #ifndef _WINDOWS_ #undef APIENTRY #endif #include static HMODULE libGL; typedef void* (APIENTRYP PFNWGLGETPROCADDRESSPROC_PRIVATE)(const char*); static PFNWGLGETPROCADDRESSPROC_PRIVATE gladGetProcAddressPtr; #ifdef _MSC_VER #ifdef __has_include #if __has_include() #define HAVE_WINAPIFAMILY 1 #endif #elif _MSC_VER >= 1700 && !_USING_V110_SDK71_ #define HAVE_WINAPIFAMILY 1 #endif #endif #ifdef HAVE_WINAPIFAMILY #include #if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) #define IS_UWP 1 #endif #endif static int open_gl(void) { #ifndef IS_UWP libGL = LoadLibraryW(L"opengl32.dll"); if(libGL != NULL) { void (* tmp)(void); tmp = (void(*)(void)) GetProcAddress(libGL, "wglGetProcAddress"); gladGetProcAddressPtr = (PFNWGLGETPROCADDRESSPROC_PRIVATE) tmp; return gladGetProcAddressPtr != NULL; } #endif return 0; } static void close_gl(void) { if(libGL != NULL) { FreeLibrary((HMODULE) libGL); libGL = NULL; } } #else #include static void* libGL; #if !defined(__APPLE__) && !defined(__HAIKU__) typedef void* (APIENTRYP PFNGLXGETPROCADDRESSPROC_PRIVATE)(const char*); static PFNGLXGETPROCADDRESSPROC_PRIVATE gladGetProcAddressPtr; #endif static int open_gl(void) { #ifdef __APPLE__ static const char *NAMES[] = { "../Frameworks/OpenGL.framework/OpenGL", "/Library/Frameworks/OpenGL.framework/OpenGL", "/System/Library/Frameworks/OpenGL.framework/OpenGL", "/System/Library/Frameworks/OpenGL.framework/Versions/Current/OpenGL" }; #else static const char *NAMES[] = {"libGL.so.1", "libGL.so"}; #endif unsigned int index = 0; for(index = 0; index < (sizeof(NAMES) / sizeof(NAMES[0])); index++) { libGL = dlopen(NAMES[index], RTLD_NOW | RTLD_GLOBAL); if(libGL != NULL) { #if defined(__APPLE__) || defined(__HAIKU__) return 1; #else gladGetProcAddressPtr = (PFNGLXGETPROCADDRESSPROC_PRIVATE)dlsym(libGL, "glXGetProcAddressARB"); return gladGetProcAddressPtr != NULL; #endif } } return 0; } static void close_gl(void) { if(libGL != NULL) { dlclose(libGL); libGL = NULL; } } #endif static void* get_proc(const char *namez) { void* result = NULL; if(libGL == NULL) return NULL; #if !defined(__APPLE__) && !defined(__HAIKU__) if(gladGetProcAddressPtr != NULL) { result = gladGetProcAddressPtr(namez); } #endif if(result == NULL) { #if defined(_WIN32) || defined(__CYGWIN__) result = (void*)GetProcAddress((HMODULE) libGL, namez); #else result = dlsym(libGL, namez); #endif } return result; } int gladLoadGL(void) { int status = 0; if(open_gl()) { status = gladLoadGLLoader(&get_proc); close_gl(); } return status; } struct gladGLversionStruct GLVersion = { 0, 0 }; #if defined(GL_ES_VERSION_3_0) || defined(GL_VERSION_3_0) #define _GLAD_IS_SOME_NEW_VERSION 1 #endif static int max_loaded_major; static int max_loaded_minor; static const char *exts = NULL; static int num_exts_i = 0; static char **exts_i = NULL; static int get_exts(void) { #ifdef _GLAD_IS_SOME_NEW_VERSION if(max_loaded_major < 3) { #endif exts = (const char *)glGetString(GL_EXTENSIONS); #ifdef _GLAD_IS_SOME_NEW_VERSION } else { unsigned int index; num_exts_i = 0; glGetIntegerv(GL_NUM_EXTENSIONS, &num_exts_i); if (num_exts_i > 0) { exts_i = (char **)malloc((size_t)num_exts_i * (sizeof *exts_i)); } if (exts_i == NULL) { return 0; } for(index = 0; index < (unsigned)num_exts_i; index++) { const char *gl_str_tmp = (const char*)glGetStringi(GL_EXTENSIONS, index); size_t len = strlen(gl_str_tmp); char *local_str = (char*)malloc((len+1) * sizeof(char)); if(local_str != NULL) { memcpy(local_str, gl_str_tmp, (len+1) * sizeof(char)); } exts_i[index] = local_str; } } #endif return 1; } static void free_exts(void) { if (exts_i != NULL) { int index; for(index = 0; index < num_exts_i; index++) { free((char *)exts_i[index]); } free((void *)exts_i); exts_i = NULL; } } static int has_ext(const char *ext) { #ifdef _GLAD_IS_SOME_NEW_VERSION if(max_loaded_major < 3) { #endif const char *extensions; const char *loc; const char *terminator; extensions = exts; if(extensions == NULL || ext == NULL) { return 0; } while(1) { loc = strstr(extensions, ext); if(loc == NULL) { return 0; } terminator = loc + strlen(ext); if((loc == extensions || *(loc - 1) == ' ') && (*terminator == ' ' || *terminator == '\0')) { return 1; } extensions = terminator; } #ifdef _GLAD_IS_SOME_NEW_VERSION } else { int index; if(exts_i == NULL) return 0; for(index = 0; index < num_exts_i; index++) { const char *e = exts_i[index]; if(exts_i[index] != NULL && strcmp(e, ext) == 0) { return 1; } } } #endif return 0; } int GLAD_GL_VERSION_1_0 = 0; int GLAD_GL_VERSION_1_1 = 0; int GLAD_GL_VERSION_1_2 = 0; int GLAD_GL_VERSION_1_3 = 0; int GLAD_GL_VERSION_1_4 = 0; int GLAD_GL_VERSION_1_5 = 0; int GLAD_GL_VERSION_2_0 = 0; int GLAD_GL_VERSION_2_1 = 0; int GLAD_GL_VERSION_3_0 = 0; int GLAD_GL_VERSION_3_1 = 0; int GLAD_GL_VERSION_3_2 = 0; int GLAD_GL_VERSION_3_3 = 0; int GLAD_GL_VERSION_4_0 = 0; int GLAD_GL_VERSION_4_1 = 0; int GLAD_GL_VERSION_4_2 = 0; int GLAD_GL_VERSION_4_3 = 0; int GLAD_GL_VERSION_4_4 = 0; int GLAD_GL_VERSION_4_5 = 0; int GLAD_GL_VERSION_4_6 = 0; int GLAD_GL_ES_VERSION_2_0 = 0; int GLAD_GL_ES_VERSION_3_0 = 0; int GLAD_GL_ES_VERSION_3_1 = 0; int GLAD_GL_ES_VERSION_3_2 = 0; PFNGLACCUMPROC glad_glAccum = NULL; PFNGLACTIVESHADERPROGRAMPROC glad_glActiveShaderProgram = NULL; PFNGLACTIVETEXTUREPROC glad_glActiveTexture = NULL; PFNGLALPHAFUNCPROC glad_glAlphaFunc = NULL; PFNGLARETEXTURESRESIDENTPROC glad_glAreTexturesResident = NULL; PFNGLARRAYELEMENTPROC glad_glArrayElement = NULL; PFNGLATTACHSHADERPROC glad_glAttachShader = NULL; PFNGLBEGINPROC glad_glBegin = NULL; PFNGLBEGINCONDITIONALRENDERPROC glad_glBeginConditionalRender = NULL; PFNGLBEGINQUERYPROC glad_glBeginQuery = NULL; PFNGLBEGINQUERYINDEXEDPROC glad_glBeginQueryIndexed = NULL; PFNGLBEGINTRANSFORMFEEDBACKPROC glad_glBeginTransformFeedback = NULL; PFNGLBINDATTRIBLOCATIONPROC glad_glBindAttribLocation = NULL; PFNGLBINDBUFFERPROC glad_glBindBuffer = NULL; PFNGLBINDBUFFERBASEPROC glad_glBindBufferBase = NULL; PFNGLBINDBUFFERRANGEPROC glad_glBindBufferRange = NULL; PFNGLBINDBUFFERSBASEPROC glad_glBindBuffersBase = NULL; PFNGLBINDBUFFERSRANGEPROC glad_glBindBuffersRange = NULL; PFNGLBINDFRAGDATALOCATIONPROC glad_glBindFragDataLocation = NULL; PFNGLBINDFRAGDATALOCATIONINDEXEDPROC glad_glBindFragDataLocationIndexed = NULL; PFNGLBINDFRAMEBUFFERPROC glad_glBindFramebuffer = NULL; PFNGLBINDIMAGETEXTUREPROC glad_glBindImageTexture = NULL; PFNGLBINDIMAGETEXTURESPROC glad_glBindImageTextures = NULL; PFNGLBINDPROGRAMPIPELINEPROC glad_glBindProgramPipeline = NULL; PFNGLBINDRENDERBUFFERPROC glad_glBindRenderbuffer = NULL; PFNGLBINDSAMPLERPROC glad_glBindSampler = NULL; PFNGLBINDSAMPLERSPROC glad_glBindSamplers = NULL; PFNGLBINDTEXTUREPROC glad_glBindTexture = NULL; PFNGLBINDTEXTUREUNITPROC glad_glBindTextureUnit = NULL; PFNGLBINDTEXTURESPROC glad_glBindTextures = NULL; PFNGLBINDTRANSFORMFEEDBACKPROC glad_glBindTransformFeedback = NULL; PFNGLBINDVERTEXARRAYPROC glad_glBindVertexArray = NULL; PFNGLBINDVERTEXBUFFERPROC glad_glBindVertexBuffer = NULL; PFNGLBINDVERTEXBUFFERSPROC glad_glBindVertexBuffers = NULL; PFNGLBITMAPPROC glad_glBitmap = NULL; PFNGLBLENDBARRIERPROC glad_glBlendBarrier = NULL; PFNGLBLENDCOLORPROC glad_glBlendColor = NULL; PFNGLBLENDEQUATIONPROC glad_glBlendEquation = NULL; PFNGLBLENDEQUATIONSEPARATEPROC glad_glBlendEquationSeparate = NULL; PFNGLBLENDEQUATIONSEPARATEIPROC glad_glBlendEquationSeparatei = NULL; PFNGLBLENDEQUATIONIPROC glad_glBlendEquationi = NULL; PFNGLBLENDFUNCPROC glad_glBlendFunc = NULL; PFNGLBLENDFUNCSEPARATEPROC glad_glBlendFuncSeparate = NULL; PFNGLBLENDFUNCSEPARATEIPROC glad_glBlendFuncSeparatei = NULL; PFNGLBLENDFUNCIPROC glad_glBlendFunci = NULL; PFNGLBLITFRAMEBUFFERPROC glad_glBlitFramebuffer = NULL; PFNGLBLITNAMEDFRAMEBUFFERPROC glad_glBlitNamedFramebuffer = NULL; PFNGLBUFFERDATAPROC glad_glBufferData = NULL; PFNGLBUFFERSTORAGEPROC glad_glBufferStorage = NULL; PFNGLBUFFERSUBDATAPROC glad_glBufferSubData = NULL; PFNGLCALLLISTPROC glad_glCallList = NULL; PFNGLCALLLISTSPROC glad_glCallLists = NULL; PFNGLCHECKFRAMEBUFFERSTATUSPROC glad_glCheckFramebufferStatus = NULL; PFNGLCHECKNAMEDFRAMEBUFFERSTATUSPROC glad_glCheckNamedFramebufferStatus = NULL; PFNGLCLAMPCOLORPROC glad_glClampColor = NULL; PFNGLCLEARPROC glad_glClear = NULL; PFNGLCLEARACCUMPROC glad_glClearAccum = NULL; PFNGLCLEARBUFFERDATAPROC glad_glClearBufferData = NULL; PFNGLCLEARBUFFERSUBDATAPROC glad_glClearBufferSubData = NULL; PFNGLCLEARBUFFERFIPROC glad_glClearBufferfi = NULL; PFNGLCLEARBUFFERFVPROC glad_glClearBufferfv = NULL; PFNGLCLEARBUFFERIVPROC glad_glClearBufferiv = NULL; PFNGLCLEARBUFFERUIVPROC glad_glClearBufferuiv = NULL; PFNGLCLEARCOLORPROC glad_glClearColor = NULL; PFNGLCLEARDEPTHPROC glad_glClearDepth = NULL; PFNGLCLEARDEPTHFPROC glad_glClearDepthf = NULL; PFNGLCLEARINDEXPROC glad_glClearIndex = NULL; PFNGLCLEARNAMEDBUFFERDATAPROC glad_glClearNamedBufferData = NULL; PFNGLCLEARNAMEDBUFFERSUBDATAPROC glad_glClearNamedBufferSubData = NULL; PFNGLCLEARNAMEDFRAMEBUFFERFIPROC glad_glClearNamedFramebufferfi = NULL; PFNGLCLEARNAMEDFRAMEBUFFERFVPROC glad_glClearNamedFramebufferfv = NULL; PFNGLCLEARNAMEDFRAMEBUFFERIVPROC glad_glClearNamedFramebufferiv = NULL; PFNGLCLEARNAMEDFRAMEBUFFERUIVPROC glad_glClearNamedFramebufferuiv = NULL; PFNGLCLEARSTENCILPROC glad_glClearStencil = NULL; PFNGLCLEARTEXIMAGEPROC glad_glClearTexImage = NULL; PFNGLCLEARTEXSUBIMAGEPROC glad_glClearTexSubImage = NULL; PFNGLCLIENTACTIVETEXTUREPROC glad_glClientActiveTexture = NULL; PFNGLCLIENTWAITSYNCPROC glad_glClientWaitSync = NULL; PFNGLCLIPCONTROLPROC glad_glClipControl = NULL; PFNGLCLIPPLANEPROC glad_glClipPlane = NULL; PFNGLCOLOR3BPROC glad_glColor3b = NULL; PFNGLCOLOR3BVPROC glad_glColor3bv = NULL; PFNGLCOLOR3DPROC glad_glColor3d = NULL; PFNGLCOLOR3DVPROC glad_glColor3dv = NULL; PFNGLCOLOR3FPROC glad_glColor3f = NULL; PFNGLCOLOR3FVPROC glad_glColor3fv = NULL; PFNGLCOLOR3IPROC glad_glColor3i = NULL; PFNGLCOLOR3IVPROC glad_glColor3iv = NULL; PFNGLCOLOR3SPROC glad_glColor3s = NULL; PFNGLCOLOR3SVPROC glad_glColor3sv = NULL; PFNGLCOLOR3UBPROC glad_glColor3ub = NULL; PFNGLCOLOR3UBVPROC glad_glColor3ubv = NULL; PFNGLCOLOR3UIPROC glad_glColor3ui = NULL; PFNGLCOLOR3UIVPROC glad_glColor3uiv = NULL; PFNGLCOLOR3USPROC glad_glColor3us = NULL; PFNGLCOLOR3USVPROC glad_glColor3usv = NULL; PFNGLCOLOR4BPROC glad_glColor4b = NULL; PFNGLCOLOR4BVPROC glad_glColor4bv = NULL; PFNGLCOLOR4DPROC glad_glColor4d = NULL; PFNGLCOLOR4DVPROC glad_glColor4dv = NULL; PFNGLCOLOR4FPROC glad_glColor4f = NULL; PFNGLCOLOR4FVPROC glad_glColor4fv = NULL; PFNGLCOLOR4IPROC glad_glColor4i = NULL; PFNGLCOLOR4IVPROC glad_glColor4iv = NULL; PFNGLCOLOR4SPROC glad_glColor4s = NULL; PFNGLCOLOR4SVPROC glad_glColor4sv = NULL; PFNGLCOLOR4UBPROC glad_glColor4ub = NULL; PFNGLCOLOR4UBVPROC glad_glColor4ubv = NULL; PFNGLCOLOR4UIPROC glad_glColor4ui = NULL; PFNGLCOLOR4UIVPROC glad_glColor4uiv = NULL; PFNGLCOLOR4USPROC glad_glColor4us = NULL; PFNGLCOLOR4USVPROC glad_glColor4usv = NULL; PFNGLCOLORMASKPROC glad_glColorMask = NULL; PFNGLCOLORMASKIPROC glad_glColorMaski = NULL; PFNGLCOLORMATERIALPROC glad_glColorMaterial = NULL; PFNGLCOLORP3UIPROC glad_glColorP3ui = NULL; PFNGLCOLORP3UIVPROC glad_glColorP3uiv = NULL; PFNGLCOLORP4UIPROC glad_glColorP4ui = NULL; PFNGLCOLORP4UIVPROC glad_glColorP4uiv = NULL; PFNGLCOLORPOINTERPROC glad_glColorPointer = NULL; PFNGLCOMPILESHADERPROC glad_glCompileShader = NULL; PFNGLCOMPRESSEDTEXIMAGE1DPROC glad_glCompressedTexImage1D = NULL; PFNGLCOMPRESSEDTEXIMAGE2DPROC glad_glCompressedTexImage2D = NULL; PFNGLCOMPRESSEDTEXIMAGE3DPROC glad_glCompressedTexImage3D = NULL; PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC glad_glCompressedTexSubImage1D = NULL; PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC glad_glCompressedTexSubImage2D = NULL; PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC glad_glCompressedTexSubImage3D = NULL; PFNGLCOMPRESSEDTEXTURESUBIMAGE1DPROC glad_glCompressedTextureSubImage1D = NULL; PFNGLCOMPRESSEDTEXTURESUBIMAGE2DPROC glad_glCompressedTextureSubImage2D = NULL; PFNGLCOMPRESSEDTEXTURESUBIMAGE3DPROC glad_glCompressedTextureSubImage3D = NULL; PFNGLCOPYBUFFERSUBDATAPROC glad_glCopyBufferSubData = NULL; PFNGLCOPYIMAGESUBDATAPROC glad_glCopyImageSubData = NULL; PFNGLCOPYNAMEDBUFFERSUBDATAPROC glad_glCopyNamedBufferSubData = NULL; PFNGLCOPYPIXELSPROC glad_glCopyPixels = NULL; PFNGLCOPYTEXIMAGE1DPROC glad_glCopyTexImage1D = NULL; PFNGLCOPYTEXIMAGE2DPROC glad_glCopyTexImage2D = NULL; PFNGLCOPYTEXSUBIMAGE1DPROC glad_glCopyTexSubImage1D = NULL; PFNGLCOPYTEXSUBIMAGE2DPROC glad_glCopyTexSubImage2D = NULL; PFNGLCOPYTEXSUBIMAGE3DPROC glad_glCopyTexSubImage3D = NULL; PFNGLCOPYTEXTURESUBIMAGE1DPROC glad_glCopyTextureSubImage1D = NULL; PFNGLCOPYTEXTURESUBIMAGE2DPROC glad_glCopyTextureSubImage2D = NULL; PFNGLCOPYTEXTURESUBIMAGE3DPROC glad_glCopyTextureSubImage3D = NULL; PFNGLCREATEBUFFERSPROC glad_glCreateBuffers = NULL; PFNGLCREATEFRAMEBUFFERSPROC glad_glCreateFramebuffers = NULL; PFNGLCREATEPROGRAMPROC glad_glCreateProgram = NULL; PFNGLCREATEPROGRAMPIPELINESPROC glad_glCreateProgramPipelines = NULL; PFNGLCREATEQUERIESPROC glad_glCreateQueries = NULL; PFNGLCREATERENDERBUFFERSPROC glad_glCreateRenderbuffers = NULL; PFNGLCREATESAMPLERSPROC glad_glCreateSamplers = NULL; PFNGLCREATESHADERPROC glad_glCreateShader = NULL; PFNGLCREATESHADERPROGRAMVPROC glad_glCreateShaderProgramv = NULL; PFNGLCREATETEXTURESPROC glad_glCreateTextures = NULL; PFNGLCREATETRANSFORMFEEDBACKSPROC glad_glCreateTransformFeedbacks = NULL; PFNGLCREATEVERTEXARRAYSPROC glad_glCreateVertexArrays = NULL; PFNGLCULLFACEPROC glad_glCullFace = NULL; PFNGLDEBUGMESSAGECALLBACKPROC glad_glDebugMessageCallback = NULL; PFNGLDEBUGMESSAGECONTROLPROC glad_glDebugMessageControl = NULL; PFNGLDEBUGMESSAGEINSERTPROC glad_glDebugMessageInsert = NULL; PFNGLDELETEBUFFERSPROC glad_glDeleteBuffers = NULL; PFNGLDELETEFRAMEBUFFERSPROC glad_glDeleteFramebuffers = NULL; PFNGLDELETELISTSPROC glad_glDeleteLists = NULL; PFNGLDELETEPROGRAMPROC glad_glDeleteProgram = NULL; PFNGLDELETEPROGRAMPIPELINESPROC glad_glDeleteProgramPipelines = NULL; PFNGLDELETEQUERIESPROC glad_glDeleteQueries = NULL; PFNGLDELETERENDERBUFFERSPROC glad_glDeleteRenderbuffers = NULL; PFNGLDELETESAMPLERSPROC glad_glDeleteSamplers = NULL; PFNGLDELETESHADERPROC glad_glDeleteShader = NULL; PFNGLDELETESYNCPROC glad_glDeleteSync = NULL; PFNGLDELETETEXTURESPROC glad_glDeleteTextures = NULL; PFNGLDELETETRANSFORMFEEDBACKSPROC glad_glDeleteTransformFeedbacks = NULL; PFNGLDELETEVERTEXARRAYSPROC glad_glDeleteVertexArrays = NULL; PFNGLDEPTHFUNCPROC glad_glDepthFunc = NULL; PFNGLDEPTHMASKPROC glad_glDepthMask = NULL; PFNGLDEPTHRANGEPROC glad_glDepthRange = NULL; PFNGLDEPTHRANGEARRAYVPROC glad_glDepthRangeArrayv = NULL; PFNGLDEPTHRANGEINDEXEDPROC glad_glDepthRangeIndexed = NULL; PFNGLDEPTHRANGEFPROC glad_glDepthRangef = NULL; PFNGLDETACHSHADERPROC glad_glDetachShader = NULL; PFNGLDISABLEPROC glad_glDisable = NULL; PFNGLDISABLECLIENTSTATEPROC glad_glDisableClientState = NULL; PFNGLDISABLEVERTEXARRAYATTRIBPROC glad_glDisableVertexArrayAttrib = NULL; PFNGLDISABLEVERTEXATTRIBARRAYPROC glad_glDisableVertexAttribArray = NULL; PFNGLDISABLEIPROC glad_glDisablei = NULL; PFNGLDISPATCHCOMPUTEPROC glad_glDispatchCompute = NULL; PFNGLDISPATCHCOMPUTEINDIRECTPROC glad_glDispatchComputeIndirect = NULL; PFNGLDRAWARRAYSPROC glad_glDrawArrays = NULL; PFNGLDRAWARRAYSINDIRECTPROC glad_glDrawArraysIndirect = NULL; PFNGLDRAWARRAYSINSTANCEDPROC glad_glDrawArraysInstanced = NULL; PFNGLDRAWARRAYSINSTANCEDBASEINSTANCEPROC glad_glDrawArraysInstancedBaseInstance = NULL; PFNGLDRAWBUFFERPROC glad_glDrawBuffer = NULL; PFNGLDRAWBUFFERSPROC glad_glDrawBuffers = NULL; PFNGLDRAWELEMENTSPROC glad_glDrawElements = NULL; PFNGLDRAWELEMENTSBASEVERTEXPROC glad_glDrawElementsBaseVertex = NULL; PFNGLDRAWELEMENTSINDIRECTPROC glad_glDrawElementsIndirect = NULL; PFNGLDRAWELEMENTSINSTANCEDPROC glad_glDrawElementsInstanced = NULL; PFNGLDRAWELEMENTSINSTANCEDBASEINSTANCEPROC glad_glDrawElementsInstancedBaseInstance = NULL; PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC glad_glDrawElementsInstancedBaseVertex = NULL; PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEPROC glad_glDrawElementsInstancedBaseVertexBaseInstance = NULL; PFNGLDRAWPIXELSPROC glad_glDrawPixels = NULL; PFNGLDRAWRANGEELEMENTSPROC glad_glDrawRangeElements = NULL; PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC glad_glDrawRangeElementsBaseVertex = NULL; PFNGLDRAWTRANSFORMFEEDBACKPROC glad_glDrawTransformFeedback = NULL; PFNGLDRAWTRANSFORMFEEDBACKINSTANCEDPROC glad_glDrawTransformFeedbackInstanced = NULL; PFNGLDRAWTRANSFORMFEEDBACKSTREAMPROC glad_glDrawTransformFeedbackStream = NULL; PFNGLDRAWTRANSFORMFEEDBACKSTREAMINSTANCEDPROC glad_glDrawTransformFeedbackStreamInstanced = NULL; PFNGLEDGEFLAGPROC glad_glEdgeFlag = NULL; PFNGLEDGEFLAGPOINTERPROC glad_glEdgeFlagPointer = NULL; PFNGLEDGEFLAGVPROC glad_glEdgeFlagv = NULL; PFNGLENABLEPROC glad_glEnable = NULL; PFNGLENABLECLIENTSTATEPROC glad_glEnableClientState = NULL; PFNGLENABLEVERTEXARRAYATTRIBPROC glad_glEnableVertexArrayAttrib = NULL; PFNGLENABLEVERTEXATTRIBARRAYPROC glad_glEnableVertexAttribArray = NULL; PFNGLENABLEIPROC glad_glEnablei = NULL; PFNGLENDPROC glad_glEnd = NULL; PFNGLENDCONDITIONALRENDERPROC glad_glEndConditionalRender = NULL; PFNGLENDLISTPROC glad_glEndList = NULL; PFNGLENDQUERYPROC glad_glEndQuery = NULL; PFNGLENDQUERYINDEXEDPROC glad_glEndQueryIndexed = NULL; PFNGLENDTRANSFORMFEEDBACKPROC glad_glEndTransformFeedback = NULL; PFNGLEVALCOORD1DPROC glad_glEvalCoord1d = NULL; PFNGLEVALCOORD1DVPROC glad_glEvalCoord1dv = NULL; PFNGLEVALCOORD1FPROC glad_glEvalCoord1f = NULL; PFNGLEVALCOORD1FVPROC glad_glEvalCoord1fv = NULL; PFNGLEVALCOORD2DPROC glad_glEvalCoord2d = NULL; PFNGLEVALCOORD2DVPROC glad_glEvalCoord2dv = NULL; PFNGLEVALCOORD2FPROC glad_glEvalCoord2f = NULL; PFNGLEVALCOORD2FVPROC glad_glEvalCoord2fv = NULL; PFNGLEVALMESH1PROC glad_glEvalMesh1 = NULL; PFNGLEVALMESH2PROC glad_glEvalMesh2 = NULL; PFNGLEVALPOINT1PROC glad_glEvalPoint1 = NULL; PFNGLEVALPOINT2PROC glad_glEvalPoint2 = NULL; PFNGLFEEDBACKBUFFERPROC glad_glFeedbackBuffer = NULL; PFNGLFENCESYNCPROC glad_glFenceSync = NULL; PFNGLFINISHPROC glad_glFinish = NULL; PFNGLFLUSHPROC glad_glFlush = NULL; PFNGLFLUSHMAPPEDBUFFERRANGEPROC glad_glFlushMappedBufferRange = NULL; PFNGLFLUSHMAPPEDNAMEDBUFFERRANGEPROC glad_glFlushMappedNamedBufferRange = NULL; PFNGLFOGCOORDPOINTERPROC glad_glFogCoordPointer = NULL; PFNGLFOGCOORDDPROC glad_glFogCoordd = NULL; PFNGLFOGCOORDDVPROC glad_glFogCoorddv = NULL; PFNGLFOGCOORDFPROC glad_glFogCoordf = NULL; PFNGLFOGCOORDFVPROC glad_glFogCoordfv = NULL; PFNGLFOGFPROC glad_glFogf = NULL; PFNGLFOGFVPROC glad_glFogfv = NULL; PFNGLFOGIPROC glad_glFogi = NULL; PFNGLFOGIVPROC glad_glFogiv = NULL; PFNGLFRAMEBUFFERPARAMETERIPROC glad_glFramebufferParameteri = NULL; PFNGLFRAMEBUFFERRENDERBUFFERPROC glad_glFramebufferRenderbuffer = NULL; PFNGLFRAMEBUFFERTEXTUREPROC glad_glFramebufferTexture = NULL; PFNGLFRAMEBUFFERTEXTURE1DPROC glad_glFramebufferTexture1D = NULL; PFNGLFRAMEBUFFERTEXTURE2DPROC glad_glFramebufferTexture2D = NULL; PFNGLFRAMEBUFFERTEXTURE3DPROC glad_glFramebufferTexture3D = NULL; PFNGLFRAMEBUFFERTEXTURELAYERPROC glad_glFramebufferTextureLayer = NULL; PFNGLFRONTFACEPROC glad_glFrontFace = NULL; PFNGLFRUSTUMPROC glad_glFrustum = NULL; PFNGLGENBUFFERSPROC glad_glGenBuffers = NULL; PFNGLGENFRAMEBUFFERSPROC glad_glGenFramebuffers = NULL; PFNGLGENLISTSPROC glad_glGenLists = NULL; PFNGLGENPROGRAMPIPELINESPROC glad_glGenProgramPipelines = NULL; PFNGLGENQUERIESPROC glad_glGenQueries = NULL; PFNGLGENRENDERBUFFERSPROC glad_glGenRenderbuffers = NULL; PFNGLGENSAMPLERSPROC glad_glGenSamplers = NULL; PFNGLGENTEXTURESPROC glad_glGenTextures = NULL; PFNGLGENTRANSFORMFEEDBACKSPROC glad_glGenTransformFeedbacks = NULL; PFNGLGENVERTEXARRAYSPROC glad_glGenVertexArrays = NULL; PFNGLGENERATEMIPMAPPROC glad_glGenerateMipmap = NULL; PFNGLGENERATETEXTUREMIPMAPPROC glad_glGenerateTextureMipmap = NULL; PFNGLGETACTIVEATOMICCOUNTERBUFFERIVPROC glad_glGetActiveAtomicCounterBufferiv = NULL; PFNGLGETACTIVEATTRIBPROC glad_glGetActiveAttrib = NULL; PFNGLGETACTIVESUBROUTINENAMEPROC glad_glGetActiveSubroutineName = NULL; PFNGLGETACTIVESUBROUTINEUNIFORMNAMEPROC glad_glGetActiveSubroutineUniformName = NULL; PFNGLGETACTIVESUBROUTINEUNIFORMIVPROC glad_glGetActiveSubroutineUniformiv = NULL; PFNGLGETACTIVEUNIFORMPROC glad_glGetActiveUniform = NULL; PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC glad_glGetActiveUniformBlockName = NULL; PFNGLGETACTIVEUNIFORMBLOCKIVPROC glad_glGetActiveUniformBlockiv = NULL; PFNGLGETACTIVEUNIFORMNAMEPROC glad_glGetActiveUniformName = NULL; PFNGLGETACTIVEUNIFORMSIVPROC glad_glGetActiveUniformsiv = NULL; PFNGLGETATTACHEDSHADERSPROC glad_glGetAttachedShaders = NULL; PFNGLGETATTRIBLOCATIONPROC glad_glGetAttribLocation = NULL; PFNGLGETBOOLEANI_VPROC glad_glGetBooleani_v = NULL; PFNGLGETBOOLEANVPROC glad_glGetBooleanv = NULL; PFNGLGETBUFFERPARAMETERI64VPROC glad_glGetBufferParameteri64v = NULL; PFNGLGETBUFFERPARAMETERIVPROC glad_glGetBufferParameteriv = NULL; PFNGLGETBUFFERPOINTERVPROC glad_glGetBufferPointerv = NULL; PFNGLGETBUFFERSUBDATAPROC glad_glGetBufferSubData = NULL; PFNGLGETCLIPPLANEPROC glad_glGetClipPlane = NULL; PFNGLGETCOMPRESSEDTEXIMAGEPROC glad_glGetCompressedTexImage = NULL; PFNGLGETCOMPRESSEDTEXTUREIMAGEPROC glad_glGetCompressedTextureImage = NULL; PFNGLGETCOMPRESSEDTEXTURESUBIMAGEPROC glad_glGetCompressedTextureSubImage = NULL; PFNGLGETDEBUGMESSAGELOGPROC glad_glGetDebugMessageLog = NULL; PFNGLGETDOUBLEI_VPROC glad_glGetDoublei_v = NULL; PFNGLGETDOUBLEVPROC glad_glGetDoublev = NULL; PFNGLGETERRORPROC glad_glGetError = NULL; PFNGLGETFLOATI_VPROC glad_glGetFloati_v = NULL; PFNGLGETFLOATVPROC glad_glGetFloatv = NULL; PFNGLGETFRAGDATAINDEXPROC glad_glGetFragDataIndex = NULL; PFNGLGETFRAGDATALOCATIONPROC glad_glGetFragDataLocation = NULL; PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC glad_glGetFramebufferAttachmentParameteriv = NULL; PFNGLGETFRAMEBUFFERPARAMETERIVPROC glad_glGetFramebufferParameteriv = NULL; PFNGLGETGRAPHICSRESETSTATUSPROC glad_glGetGraphicsResetStatus = NULL; PFNGLGETINTEGER64I_VPROC glad_glGetInteger64i_v = NULL; PFNGLGETINTEGER64VPROC glad_glGetInteger64v = NULL; PFNGLGETINTEGERI_VPROC glad_glGetIntegeri_v = NULL; PFNGLGETINTEGERVPROC glad_glGetIntegerv = NULL; PFNGLGETINTERNALFORMATI64VPROC glad_glGetInternalformati64v = NULL; PFNGLGETINTERNALFORMATIVPROC glad_glGetInternalformativ = NULL; PFNGLGETLIGHTFVPROC glad_glGetLightfv = NULL; PFNGLGETLIGHTIVPROC glad_glGetLightiv = NULL; PFNGLGETMAPDVPROC glad_glGetMapdv = NULL; PFNGLGETMAPFVPROC glad_glGetMapfv = NULL; PFNGLGETMAPIVPROC glad_glGetMapiv = NULL; PFNGLGETMATERIALFVPROC glad_glGetMaterialfv = NULL; PFNGLGETMATERIALIVPROC glad_glGetMaterialiv = NULL; PFNGLGETMULTISAMPLEFVPROC glad_glGetMultisamplefv = NULL; PFNGLGETNAMEDBUFFERPARAMETERI64VPROC glad_glGetNamedBufferParameteri64v = NULL; PFNGLGETNAMEDBUFFERPARAMETERIVPROC glad_glGetNamedBufferParameteriv = NULL; PFNGLGETNAMEDBUFFERPOINTERVPROC glad_glGetNamedBufferPointerv = NULL; PFNGLGETNAMEDBUFFERSUBDATAPROC glad_glGetNamedBufferSubData = NULL; PFNGLGETNAMEDFRAMEBUFFERATTACHMENTPARAMETERIVPROC glad_glGetNamedFramebufferAttachmentParameteriv = NULL; PFNGLGETNAMEDFRAMEBUFFERPARAMETERIVPROC glad_glGetNamedFramebufferParameteriv = NULL; PFNGLGETNAMEDRENDERBUFFERPARAMETERIVPROC glad_glGetNamedRenderbufferParameteriv = NULL; PFNGLGETOBJECTLABELPROC glad_glGetObjectLabel = NULL; PFNGLGETOBJECTPTRLABELPROC glad_glGetObjectPtrLabel = NULL; PFNGLGETPIXELMAPFVPROC glad_glGetPixelMapfv = NULL; PFNGLGETPIXELMAPUIVPROC glad_glGetPixelMapuiv = NULL; PFNGLGETPIXELMAPUSVPROC glad_glGetPixelMapusv = NULL; PFNGLGETPOINTERVPROC glad_glGetPointerv = NULL; PFNGLGETPOLYGONSTIPPLEPROC glad_glGetPolygonStipple = NULL; PFNGLGETPROGRAMBINARYPROC glad_glGetProgramBinary = NULL; PFNGLGETPROGRAMINFOLOGPROC glad_glGetProgramInfoLog = NULL; PFNGLGETPROGRAMINTERFACEIVPROC glad_glGetProgramInterfaceiv = NULL; PFNGLGETPROGRAMPIPELINEINFOLOGPROC glad_glGetProgramPipelineInfoLog = NULL; PFNGLGETPROGRAMPIPELINEIVPROC glad_glGetProgramPipelineiv = NULL; PFNGLGETPROGRAMRESOURCEINDEXPROC glad_glGetProgramResourceIndex = NULL; PFNGLGETPROGRAMRESOURCELOCATIONPROC glad_glGetProgramResourceLocation = NULL; PFNGLGETPROGRAMRESOURCELOCATIONINDEXPROC glad_glGetProgramResourceLocationIndex = NULL; PFNGLGETPROGRAMRESOURCENAMEPROC glad_glGetProgramResourceName = NULL; PFNGLGETPROGRAMRESOURCEIVPROC glad_glGetProgramResourceiv = NULL; PFNGLGETPROGRAMSTAGEIVPROC glad_glGetProgramStageiv = NULL; PFNGLGETPROGRAMIVPROC glad_glGetProgramiv = NULL; PFNGLGETQUERYBUFFEROBJECTI64VPROC glad_glGetQueryBufferObjecti64v = NULL; PFNGLGETQUERYBUFFEROBJECTIVPROC glad_glGetQueryBufferObjectiv = NULL; PFNGLGETQUERYBUFFEROBJECTUI64VPROC glad_glGetQueryBufferObjectui64v = NULL; PFNGLGETQUERYBUFFEROBJECTUIVPROC glad_glGetQueryBufferObjectuiv = NULL; PFNGLGETQUERYINDEXEDIVPROC glad_glGetQueryIndexediv = NULL; PFNGLGETQUERYOBJECTI64VPROC glad_glGetQueryObjecti64v = NULL; PFNGLGETQUERYOBJECTIVPROC glad_glGetQueryObjectiv = NULL; PFNGLGETQUERYOBJECTUI64VPROC glad_glGetQueryObjectui64v = NULL; PFNGLGETQUERYOBJECTUIVPROC glad_glGetQueryObjectuiv = NULL; PFNGLGETQUERYIVPROC glad_glGetQueryiv = NULL; PFNGLGETRENDERBUFFERPARAMETERIVPROC glad_glGetRenderbufferParameteriv = NULL; PFNGLGETSAMPLERPARAMETERIIVPROC glad_glGetSamplerParameterIiv = NULL; PFNGLGETSAMPLERPARAMETERIUIVPROC glad_glGetSamplerParameterIuiv = NULL; PFNGLGETSAMPLERPARAMETERFVPROC glad_glGetSamplerParameterfv = NULL; PFNGLGETSAMPLERPARAMETERIVPROC glad_glGetSamplerParameteriv = NULL; PFNGLGETSHADERINFOLOGPROC glad_glGetShaderInfoLog = NULL; PFNGLGETSHADERPRECISIONFORMATPROC glad_glGetShaderPrecisionFormat = NULL; PFNGLGETSHADERSOURCEPROC glad_glGetShaderSource = NULL; PFNGLGETSHADERIVPROC glad_glGetShaderiv = NULL; PFNGLGETSTRINGPROC glad_glGetString = NULL; PFNGLGETSTRINGIPROC glad_glGetStringi = NULL; PFNGLGETSUBROUTINEINDEXPROC glad_glGetSubroutineIndex = NULL; PFNGLGETSUBROUTINEUNIFORMLOCATIONPROC glad_glGetSubroutineUniformLocation = NULL; PFNGLGETSYNCIVPROC glad_glGetSynciv = NULL; PFNGLGETTEXENVFVPROC glad_glGetTexEnvfv = NULL; PFNGLGETTEXENVIVPROC glad_glGetTexEnviv = NULL; PFNGLGETTEXGENDVPROC glad_glGetTexGendv = NULL; PFNGLGETTEXGENFVPROC glad_glGetTexGenfv = NULL; PFNGLGETTEXGENIVPROC glad_glGetTexGeniv = NULL; PFNGLGETTEXIMAGEPROC glad_glGetTexImage = NULL; PFNGLGETTEXLEVELPARAMETERFVPROC glad_glGetTexLevelParameterfv = NULL; PFNGLGETTEXLEVELPARAMETERIVPROC glad_glGetTexLevelParameteriv = NULL; PFNGLGETTEXPARAMETERIIVPROC glad_glGetTexParameterIiv = NULL; PFNGLGETTEXPARAMETERIUIVPROC glad_glGetTexParameterIuiv = NULL; PFNGLGETTEXPARAMETERFVPROC glad_glGetTexParameterfv = NULL; PFNGLGETTEXPARAMETERIVPROC glad_glGetTexParameteriv = NULL; PFNGLGETTEXTUREIMAGEPROC glad_glGetTextureImage = NULL; PFNGLGETTEXTURELEVELPARAMETERFVPROC glad_glGetTextureLevelParameterfv = NULL; PFNGLGETTEXTURELEVELPARAMETERIVPROC glad_glGetTextureLevelParameteriv = NULL; PFNGLGETTEXTUREPARAMETERIIVPROC glad_glGetTextureParameterIiv = NULL; PFNGLGETTEXTUREPARAMETERIUIVPROC glad_glGetTextureParameterIuiv = NULL; PFNGLGETTEXTUREPARAMETERFVPROC glad_glGetTextureParameterfv = NULL; PFNGLGETTEXTUREPARAMETERIVPROC glad_glGetTextureParameteriv = NULL; PFNGLGETTEXTURESUBIMAGEPROC glad_glGetTextureSubImage = NULL; PFNGLGETTRANSFORMFEEDBACKVARYINGPROC glad_glGetTransformFeedbackVarying = NULL; PFNGLGETTRANSFORMFEEDBACKI64_VPROC glad_glGetTransformFeedbacki64_v = NULL; PFNGLGETTRANSFORMFEEDBACKI_VPROC glad_glGetTransformFeedbacki_v = NULL; PFNGLGETTRANSFORMFEEDBACKIVPROC glad_glGetTransformFeedbackiv = NULL; PFNGLGETUNIFORMBLOCKINDEXPROC glad_glGetUniformBlockIndex = NULL; PFNGLGETUNIFORMINDICESPROC glad_glGetUniformIndices = NULL; PFNGLGETUNIFORMLOCATIONPROC glad_glGetUniformLocation = NULL; PFNGLGETUNIFORMSUBROUTINEUIVPROC glad_glGetUniformSubroutineuiv = NULL; PFNGLGETUNIFORMDVPROC glad_glGetUniformdv = NULL; PFNGLGETUNIFORMFVPROC glad_glGetUniformfv = NULL; PFNGLGETUNIFORMIVPROC glad_glGetUniformiv = NULL; PFNGLGETUNIFORMUIVPROC glad_glGetUniformuiv = NULL; PFNGLGETVERTEXARRAYINDEXED64IVPROC glad_glGetVertexArrayIndexed64iv = NULL; PFNGLGETVERTEXARRAYINDEXEDIVPROC glad_glGetVertexArrayIndexediv = NULL; PFNGLGETVERTEXARRAYIVPROC glad_glGetVertexArrayiv = NULL; PFNGLGETVERTEXATTRIBIIVPROC glad_glGetVertexAttribIiv = NULL; PFNGLGETVERTEXATTRIBIUIVPROC glad_glGetVertexAttribIuiv = NULL; PFNGLGETVERTEXATTRIBLDVPROC glad_glGetVertexAttribLdv = NULL; PFNGLGETVERTEXATTRIBPOINTERVPROC glad_glGetVertexAttribPointerv = NULL; PFNGLGETVERTEXATTRIBDVPROC glad_glGetVertexAttribdv = NULL; PFNGLGETVERTEXATTRIBFVPROC glad_glGetVertexAttribfv = NULL; PFNGLGETVERTEXATTRIBIVPROC glad_glGetVertexAttribiv = NULL; PFNGLGETNCOLORTABLEPROC glad_glGetnColorTable = NULL; PFNGLGETNCOMPRESSEDTEXIMAGEPROC glad_glGetnCompressedTexImage = NULL; PFNGLGETNCONVOLUTIONFILTERPROC glad_glGetnConvolutionFilter = NULL; PFNGLGETNHISTOGRAMPROC glad_glGetnHistogram = NULL; PFNGLGETNMAPDVPROC glad_glGetnMapdv = NULL; PFNGLGETNMAPFVPROC glad_glGetnMapfv = NULL; PFNGLGETNMAPIVPROC glad_glGetnMapiv = NULL; PFNGLGETNMINMAXPROC glad_glGetnMinmax = NULL; PFNGLGETNPIXELMAPFVPROC glad_glGetnPixelMapfv = NULL; PFNGLGETNPIXELMAPUIVPROC glad_glGetnPixelMapuiv = NULL; PFNGLGETNPIXELMAPUSVPROC glad_glGetnPixelMapusv = NULL; PFNGLGETNPOLYGONSTIPPLEPROC glad_glGetnPolygonStipple = NULL; PFNGLGETNSEPARABLEFILTERPROC glad_glGetnSeparableFilter = NULL; PFNGLGETNTEXIMAGEPROC glad_glGetnTexImage = NULL; PFNGLGETNUNIFORMDVPROC glad_glGetnUniformdv = NULL; PFNGLGETNUNIFORMFVPROC glad_glGetnUniformfv = NULL; PFNGLGETNUNIFORMIVPROC glad_glGetnUniformiv = NULL; PFNGLGETNUNIFORMUIVPROC glad_glGetnUniformuiv = NULL; PFNGLHINTPROC glad_glHint = NULL; PFNGLINDEXMASKPROC glad_glIndexMask = NULL; PFNGLINDEXPOINTERPROC glad_glIndexPointer = NULL; PFNGLINDEXDPROC glad_glIndexd = NULL; PFNGLINDEXDVPROC glad_glIndexdv = NULL; PFNGLINDEXFPROC glad_glIndexf = NULL; PFNGLINDEXFVPROC glad_glIndexfv = NULL; PFNGLINDEXIPROC glad_glIndexi = NULL; PFNGLINDEXIVPROC glad_glIndexiv = NULL; PFNGLINDEXSPROC glad_glIndexs = NULL; PFNGLINDEXSVPROC glad_glIndexsv = NULL; PFNGLINDEXUBPROC glad_glIndexub = NULL; PFNGLINDEXUBVPROC glad_glIndexubv = NULL; PFNGLINITNAMESPROC glad_glInitNames = NULL; PFNGLINTERLEAVEDARRAYSPROC glad_glInterleavedArrays = NULL; PFNGLINVALIDATEBUFFERDATAPROC glad_glInvalidateBufferData = NULL; PFNGLINVALIDATEBUFFERSUBDATAPROC glad_glInvalidateBufferSubData = NULL; PFNGLINVALIDATEFRAMEBUFFERPROC glad_glInvalidateFramebuffer = NULL; PFNGLINVALIDATENAMEDFRAMEBUFFERDATAPROC glad_glInvalidateNamedFramebufferData = NULL; PFNGLINVALIDATENAMEDFRAMEBUFFERSUBDATAPROC glad_glInvalidateNamedFramebufferSubData = NULL; PFNGLINVALIDATESUBFRAMEBUFFERPROC glad_glInvalidateSubFramebuffer = NULL; PFNGLINVALIDATETEXIMAGEPROC glad_glInvalidateTexImage = NULL; PFNGLINVALIDATETEXSUBIMAGEPROC glad_glInvalidateTexSubImage = NULL; PFNGLISBUFFERPROC glad_glIsBuffer = NULL; PFNGLISENABLEDPROC glad_glIsEnabled = NULL; PFNGLISENABLEDIPROC glad_glIsEnabledi = NULL; PFNGLISFRAMEBUFFERPROC glad_glIsFramebuffer = NULL; PFNGLISLISTPROC glad_glIsList = NULL; PFNGLISPROGRAMPROC glad_glIsProgram = NULL; PFNGLISPROGRAMPIPELINEPROC glad_glIsProgramPipeline = NULL; PFNGLISQUERYPROC glad_glIsQuery = NULL; PFNGLISRENDERBUFFERPROC glad_glIsRenderbuffer = NULL; PFNGLISSAMPLERPROC glad_glIsSampler = NULL; PFNGLISSHADERPROC glad_glIsShader = NULL; PFNGLISSYNCPROC glad_glIsSync = NULL; PFNGLISTEXTUREPROC glad_glIsTexture = NULL; PFNGLISTRANSFORMFEEDBACKPROC glad_glIsTransformFeedback = NULL; PFNGLISVERTEXARRAYPROC glad_glIsVertexArray = NULL; PFNGLLIGHTMODELFPROC glad_glLightModelf = NULL; PFNGLLIGHTMODELFVPROC glad_glLightModelfv = NULL; PFNGLLIGHTMODELIPROC glad_glLightModeli = NULL; PFNGLLIGHTMODELIVPROC glad_glLightModeliv = NULL; PFNGLLIGHTFPROC glad_glLightf = NULL; PFNGLLIGHTFVPROC glad_glLightfv = NULL; PFNGLLIGHTIPROC glad_glLighti = NULL; PFNGLLIGHTIVPROC glad_glLightiv = NULL; PFNGLLINESTIPPLEPROC glad_glLineStipple = NULL; PFNGLLINEWIDTHPROC glad_glLineWidth = NULL; PFNGLLINKPROGRAMPROC glad_glLinkProgram = NULL; PFNGLLISTBASEPROC glad_glListBase = NULL; PFNGLLOADIDENTITYPROC glad_glLoadIdentity = NULL; PFNGLLOADMATRIXDPROC glad_glLoadMatrixd = NULL; PFNGLLOADMATRIXFPROC glad_glLoadMatrixf = NULL; PFNGLLOADNAMEPROC glad_glLoadName = NULL; PFNGLLOADTRANSPOSEMATRIXDPROC glad_glLoadTransposeMatrixd = NULL; PFNGLLOADTRANSPOSEMATRIXFPROC glad_glLoadTransposeMatrixf = NULL; PFNGLLOGICOPPROC glad_glLogicOp = NULL; PFNGLMAP1DPROC glad_glMap1d = NULL; PFNGLMAP1FPROC glad_glMap1f = NULL; PFNGLMAP2DPROC glad_glMap2d = NULL; PFNGLMAP2FPROC glad_glMap2f = NULL; PFNGLMAPBUFFERPROC glad_glMapBuffer = NULL; PFNGLMAPBUFFERRANGEPROC glad_glMapBufferRange = NULL; PFNGLMAPGRID1DPROC glad_glMapGrid1d = NULL; PFNGLMAPGRID1FPROC glad_glMapGrid1f = NULL; PFNGLMAPGRID2DPROC glad_glMapGrid2d = NULL; PFNGLMAPGRID2FPROC glad_glMapGrid2f = NULL; PFNGLMAPNAMEDBUFFERPROC glad_glMapNamedBuffer = NULL; PFNGLMAPNAMEDBUFFERRANGEPROC glad_glMapNamedBufferRange = NULL; PFNGLMATERIALFPROC glad_glMaterialf = NULL; PFNGLMATERIALFVPROC glad_glMaterialfv = NULL; PFNGLMATERIALIPROC glad_glMateriali = NULL; PFNGLMATERIALIVPROC glad_glMaterialiv = NULL; PFNGLMATRIXMODEPROC glad_glMatrixMode = NULL; PFNGLMEMORYBARRIERPROC glad_glMemoryBarrier = NULL; PFNGLMEMORYBARRIERBYREGIONPROC glad_glMemoryBarrierByRegion = NULL; PFNGLMINSAMPLESHADINGPROC glad_glMinSampleShading = NULL; PFNGLMULTMATRIXDPROC glad_glMultMatrixd = NULL; PFNGLMULTMATRIXFPROC glad_glMultMatrixf = NULL; PFNGLMULTTRANSPOSEMATRIXDPROC glad_glMultTransposeMatrixd = NULL; PFNGLMULTTRANSPOSEMATRIXFPROC glad_glMultTransposeMatrixf = NULL; PFNGLMULTIDRAWARRAYSPROC glad_glMultiDrawArrays = NULL; PFNGLMULTIDRAWARRAYSINDIRECTPROC glad_glMultiDrawArraysIndirect = NULL; PFNGLMULTIDRAWARRAYSINDIRECTCOUNTPROC glad_glMultiDrawArraysIndirectCount = NULL; PFNGLMULTIDRAWELEMENTSPROC glad_glMultiDrawElements = NULL; PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC glad_glMultiDrawElementsBaseVertex = NULL; PFNGLMULTIDRAWELEMENTSINDIRECTPROC glad_glMultiDrawElementsIndirect = NULL; PFNGLMULTIDRAWELEMENTSINDIRECTCOUNTPROC glad_glMultiDrawElementsIndirectCount = NULL; PFNGLMULTITEXCOORD1DPROC glad_glMultiTexCoord1d = NULL; PFNGLMULTITEXCOORD1DVPROC glad_glMultiTexCoord1dv = NULL; PFNGLMULTITEXCOORD1FPROC glad_glMultiTexCoord1f = NULL; PFNGLMULTITEXCOORD1FVPROC glad_glMultiTexCoord1fv = NULL; PFNGLMULTITEXCOORD1IPROC glad_glMultiTexCoord1i = NULL; PFNGLMULTITEXCOORD1IVPROC glad_glMultiTexCoord1iv = NULL; PFNGLMULTITEXCOORD1SPROC glad_glMultiTexCoord1s = NULL; PFNGLMULTITEXCOORD1SVPROC glad_glMultiTexCoord1sv = NULL; PFNGLMULTITEXCOORD2DPROC glad_glMultiTexCoord2d = NULL; PFNGLMULTITEXCOORD2DVPROC glad_glMultiTexCoord2dv = NULL; PFNGLMULTITEXCOORD2FPROC glad_glMultiTexCoord2f = NULL; PFNGLMULTITEXCOORD2FVPROC glad_glMultiTexCoord2fv = NULL; PFNGLMULTITEXCOORD2IPROC glad_glMultiTexCoord2i = NULL; PFNGLMULTITEXCOORD2IVPROC glad_glMultiTexCoord2iv = NULL; PFNGLMULTITEXCOORD2SPROC glad_glMultiTexCoord2s = NULL; PFNGLMULTITEXCOORD2SVPROC glad_glMultiTexCoord2sv = NULL; PFNGLMULTITEXCOORD3DPROC glad_glMultiTexCoord3d = NULL; PFNGLMULTITEXCOORD3DVPROC glad_glMultiTexCoord3dv = NULL; PFNGLMULTITEXCOORD3FPROC glad_glMultiTexCoord3f = NULL; PFNGLMULTITEXCOORD3FVPROC glad_glMultiTexCoord3fv = NULL; PFNGLMULTITEXCOORD3IPROC glad_glMultiTexCoord3i = NULL; PFNGLMULTITEXCOORD3IVPROC glad_glMultiTexCoord3iv = NULL; PFNGLMULTITEXCOORD3SPROC glad_glMultiTexCoord3s = NULL; PFNGLMULTITEXCOORD3SVPROC glad_glMultiTexCoord3sv = NULL; PFNGLMULTITEXCOORD4DPROC glad_glMultiTexCoord4d = NULL; PFNGLMULTITEXCOORD4DVPROC glad_glMultiTexCoord4dv = NULL; PFNGLMULTITEXCOORD4FPROC glad_glMultiTexCoord4f = NULL; PFNGLMULTITEXCOORD4FVPROC glad_glMultiTexCoord4fv = NULL; PFNGLMULTITEXCOORD4IPROC glad_glMultiTexCoord4i = NULL; PFNGLMULTITEXCOORD4IVPROC glad_glMultiTexCoord4iv = NULL; PFNGLMULTITEXCOORD4SPROC glad_glMultiTexCoord4s = NULL; PFNGLMULTITEXCOORD4SVPROC glad_glMultiTexCoord4sv = NULL; PFNGLMULTITEXCOORDP1UIPROC glad_glMultiTexCoordP1ui = NULL; PFNGLMULTITEXCOORDP1UIVPROC glad_glMultiTexCoordP1uiv = NULL; PFNGLMULTITEXCOORDP2UIPROC glad_glMultiTexCoordP2ui = NULL; PFNGLMULTITEXCOORDP2UIVPROC glad_glMultiTexCoordP2uiv = NULL; PFNGLMULTITEXCOORDP3UIPROC glad_glMultiTexCoordP3ui = NULL; PFNGLMULTITEXCOORDP3UIVPROC glad_glMultiTexCoordP3uiv = NULL; PFNGLMULTITEXCOORDP4UIPROC glad_glMultiTexCoordP4ui = NULL; PFNGLMULTITEXCOORDP4UIVPROC glad_glMultiTexCoordP4uiv = NULL; PFNGLNAMEDBUFFERDATAPROC glad_glNamedBufferData = NULL; PFNGLNAMEDBUFFERSTORAGEPROC glad_glNamedBufferStorage = NULL; PFNGLNAMEDBUFFERSUBDATAPROC glad_glNamedBufferSubData = NULL; PFNGLNAMEDFRAMEBUFFERDRAWBUFFERPROC glad_glNamedFramebufferDrawBuffer = NULL; PFNGLNAMEDFRAMEBUFFERDRAWBUFFERSPROC glad_glNamedFramebufferDrawBuffers = NULL; PFNGLNAMEDFRAMEBUFFERPARAMETERIPROC glad_glNamedFramebufferParameteri = NULL; PFNGLNAMEDFRAMEBUFFERREADBUFFERPROC glad_glNamedFramebufferReadBuffer = NULL; PFNGLNAMEDFRAMEBUFFERRENDERBUFFERPROC glad_glNamedFramebufferRenderbuffer = NULL; PFNGLNAMEDFRAMEBUFFERTEXTUREPROC glad_glNamedFramebufferTexture = NULL; PFNGLNAMEDFRAMEBUFFERTEXTURELAYERPROC glad_glNamedFramebufferTextureLayer = NULL; PFNGLNAMEDRENDERBUFFERSTORAGEPROC glad_glNamedRenderbufferStorage = NULL; PFNGLNAMEDRENDERBUFFERSTORAGEMULTISAMPLEPROC glad_glNamedRenderbufferStorageMultisample = NULL; PFNGLNEWLISTPROC glad_glNewList = NULL; PFNGLNORMAL3BPROC glad_glNormal3b = NULL; PFNGLNORMAL3BVPROC glad_glNormal3bv = NULL; PFNGLNORMAL3DPROC glad_glNormal3d = NULL; PFNGLNORMAL3DVPROC glad_glNormal3dv = NULL; PFNGLNORMAL3FPROC glad_glNormal3f = NULL; PFNGLNORMAL3FVPROC glad_glNormal3fv = NULL; PFNGLNORMAL3IPROC glad_glNormal3i = NULL; PFNGLNORMAL3IVPROC glad_glNormal3iv = NULL; PFNGLNORMAL3SPROC glad_glNormal3s = NULL; PFNGLNORMAL3SVPROC glad_glNormal3sv = NULL; PFNGLNORMALP3UIPROC glad_glNormalP3ui = NULL; PFNGLNORMALP3UIVPROC glad_glNormalP3uiv = NULL; PFNGLNORMALPOINTERPROC glad_glNormalPointer = NULL; PFNGLOBJECTLABELPROC glad_glObjectLabel = NULL; PFNGLOBJECTPTRLABELPROC glad_glObjectPtrLabel = NULL; PFNGLORTHOPROC glad_glOrtho = NULL; PFNGLPASSTHROUGHPROC glad_glPassThrough = NULL; PFNGLPATCHPARAMETERFVPROC glad_glPatchParameterfv = NULL; PFNGLPATCHPARAMETERIPROC glad_glPatchParameteri = NULL; PFNGLPAUSETRANSFORMFEEDBACKPROC glad_glPauseTransformFeedback = NULL; PFNGLPIXELMAPFVPROC glad_glPixelMapfv = NULL; PFNGLPIXELMAPUIVPROC glad_glPixelMapuiv = NULL; PFNGLPIXELMAPUSVPROC glad_glPixelMapusv = NULL; PFNGLPIXELSTOREFPROC glad_glPixelStoref = NULL; PFNGLPIXELSTOREIPROC glad_glPixelStorei = NULL; PFNGLPIXELTRANSFERFPROC glad_glPixelTransferf = NULL; PFNGLPIXELTRANSFERIPROC glad_glPixelTransferi = NULL; PFNGLPIXELZOOMPROC glad_glPixelZoom = NULL; PFNGLPOINTPARAMETERFPROC glad_glPointParameterf = NULL; PFNGLPOINTPARAMETERFVPROC glad_glPointParameterfv = NULL; PFNGLPOINTPARAMETERIPROC glad_glPointParameteri = NULL; PFNGLPOINTPARAMETERIVPROC glad_glPointParameteriv = NULL; PFNGLPOINTSIZEPROC glad_glPointSize = NULL; PFNGLPOLYGONMODEPROC glad_glPolygonMode = NULL; PFNGLPOLYGONOFFSETPROC glad_glPolygonOffset = NULL; PFNGLPOLYGONOFFSETCLAMPPROC glad_glPolygonOffsetClamp = NULL; PFNGLPOLYGONSTIPPLEPROC glad_glPolygonStipple = NULL; PFNGLPOPATTRIBPROC glad_glPopAttrib = NULL; PFNGLPOPCLIENTATTRIBPROC glad_glPopClientAttrib = NULL; PFNGLPOPDEBUGGROUPPROC glad_glPopDebugGroup = NULL; PFNGLPOPMATRIXPROC glad_glPopMatrix = NULL; PFNGLPOPNAMEPROC glad_glPopName = NULL; PFNGLPRIMITIVEBOUNDINGBOXPROC glad_glPrimitiveBoundingBox = NULL; PFNGLPRIMITIVERESTARTINDEXPROC glad_glPrimitiveRestartIndex = NULL; PFNGLPRIORITIZETEXTURESPROC glad_glPrioritizeTextures = NULL; PFNGLPROGRAMBINARYPROC glad_glProgramBinary = NULL; PFNGLPROGRAMPARAMETERIPROC glad_glProgramParameteri = NULL; PFNGLPROGRAMUNIFORM1DPROC glad_glProgramUniform1d = NULL; PFNGLPROGRAMUNIFORM1DVPROC glad_glProgramUniform1dv = NULL; PFNGLPROGRAMUNIFORM1FPROC glad_glProgramUniform1f = NULL; PFNGLPROGRAMUNIFORM1FVPROC glad_glProgramUniform1fv = NULL; PFNGLPROGRAMUNIFORM1IPROC glad_glProgramUniform1i = NULL; PFNGLPROGRAMUNIFORM1IVPROC glad_glProgramUniform1iv = NULL; PFNGLPROGRAMUNIFORM1UIPROC glad_glProgramUniform1ui = NULL; PFNGLPROGRAMUNIFORM1UIVPROC glad_glProgramUniform1uiv = NULL; PFNGLPROGRAMUNIFORM2DPROC glad_glProgramUniform2d = NULL; PFNGLPROGRAMUNIFORM2DVPROC glad_glProgramUniform2dv = NULL; PFNGLPROGRAMUNIFORM2FPROC glad_glProgramUniform2f = NULL; PFNGLPROGRAMUNIFORM2FVPROC glad_glProgramUniform2fv = NULL; PFNGLPROGRAMUNIFORM2IPROC glad_glProgramUniform2i = NULL; PFNGLPROGRAMUNIFORM2IVPROC glad_glProgramUniform2iv = NULL; PFNGLPROGRAMUNIFORM2UIPROC glad_glProgramUniform2ui = NULL; PFNGLPROGRAMUNIFORM2UIVPROC glad_glProgramUniform2uiv = NULL; PFNGLPROGRAMUNIFORM3DPROC glad_glProgramUniform3d = NULL; PFNGLPROGRAMUNIFORM3DVPROC glad_glProgramUniform3dv = NULL; PFNGLPROGRAMUNIFORM3FPROC glad_glProgramUniform3f = NULL; PFNGLPROGRAMUNIFORM3FVPROC glad_glProgramUniform3fv = NULL; PFNGLPROGRAMUNIFORM3IPROC glad_glProgramUniform3i = NULL; PFNGLPROGRAMUNIFORM3IVPROC glad_glProgramUniform3iv = NULL; PFNGLPROGRAMUNIFORM3UIPROC glad_glProgramUniform3ui = NULL; PFNGLPROGRAMUNIFORM3UIVPROC glad_glProgramUniform3uiv = NULL; PFNGLPROGRAMUNIFORM4DPROC glad_glProgramUniform4d = NULL; PFNGLPROGRAMUNIFORM4DVPROC glad_glProgramUniform4dv = NULL; PFNGLPROGRAMUNIFORM4FPROC glad_glProgramUniform4f = NULL; PFNGLPROGRAMUNIFORM4FVPROC glad_glProgramUniform4fv = NULL; PFNGLPROGRAMUNIFORM4IPROC glad_glProgramUniform4i = NULL; PFNGLPROGRAMUNIFORM4IVPROC glad_glProgramUniform4iv = NULL; PFNGLPROGRAMUNIFORM4UIPROC glad_glProgramUniform4ui = NULL; PFNGLPROGRAMUNIFORM4UIVPROC glad_glProgramUniform4uiv = NULL; PFNGLPROGRAMUNIFORMMATRIX2DVPROC glad_glProgramUniformMatrix2dv = NULL; PFNGLPROGRAMUNIFORMMATRIX2FVPROC glad_glProgramUniformMatrix2fv = NULL; PFNGLPROGRAMUNIFORMMATRIX2X3DVPROC glad_glProgramUniformMatrix2x3dv = NULL; PFNGLPROGRAMUNIFORMMATRIX2X3FVPROC glad_glProgramUniformMatrix2x3fv = NULL; PFNGLPROGRAMUNIFORMMATRIX2X4DVPROC glad_glProgramUniformMatrix2x4dv = NULL; PFNGLPROGRAMUNIFORMMATRIX2X4FVPROC glad_glProgramUniformMatrix2x4fv = NULL; PFNGLPROGRAMUNIFORMMATRIX3DVPROC glad_glProgramUniformMatrix3dv = NULL; PFNGLPROGRAMUNIFORMMATRIX3FVPROC glad_glProgramUniformMatrix3fv = NULL; PFNGLPROGRAMUNIFORMMATRIX3X2DVPROC glad_glProgramUniformMatrix3x2dv = NULL; PFNGLPROGRAMUNIFORMMATRIX3X2FVPROC glad_glProgramUniformMatrix3x2fv = NULL; PFNGLPROGRAMUNIFORMMATRIX3X4DVPROC glad_glProgramUniformMatrix3x4dv = NULL; PFNGLPROGRAMUNIFORMMATRIX3X4FVPROC glad_glProgramUniformMatrix3x4fv = NULL; PFNGLPROGRAMUNIFORMMATRIX4DVPROC glad_glProgramUniformMatrix4dv = NULL; PFNGLPROGRAMUNIFORMMATRIX4FVPROC glad_glProgramUniformMatrix4fv = NULL; PFNGLPROGRAMUNIFORMMATRIX4X2DVPROC glad_glProgramUniformMatrix4x2dv = NULL; PFNGLPROGRAMUNIFORMMATRIX4X2FVPROC glad_glProgramUniformMatrix4x2fv = NULL; PFNGLPROGRAMUNIFORMMATRIX4X3DVPROC glad_glProgramUniformMatrix4x3dv = NULL; PFNGLPROGRAMUNIFORMMATRIX4X3FVPROC glad_glProgramUniformMatrix4x3fv = NULL; PFNGLPROVOKINGVERTEXPROC glad_glProvokingVertex = NULL; PFNGLPUSHATTRIBPROC glad_glPushAttrib = NULL; PFNGLPUSHCLIENTATTRIBPROC glad_glPushClientAttrib = NULL; PFNGLPUSHDEBUGGROUPPROC glad_glPushDebugGroup = NULL; PFNGLPUSHMATRIXPROC glad_glPushMatrix = NULL; PFNGLPUSHNAMEPROC glad_glPushName = NULL; PFNGLQUERYCOUNTERPROC glad_glQueryCounter = NULL; PFNGLRASTERPOS2DPROC glad_glRasterPos2d = NULL; PFNGLRASTERPOS2DVPROC glad_glRasterPos2dv = NULL; PFNGLRASTERPOS2FPROC glad_glRasterPos2f = NULL; PFNGLRASTERPOS2FVPROC glad_glRasterPos2fv = NULL; PFNGLRASTERPOS2IPROC glad_glRasterPos2i = NULL; PFNGLRASTERPOS2IVPROC glad_glRasterPos2iv = NULL; PFNGLRASTERPOS2SPROC glad_glRasterPos2s = NULL; PFNGLRASTERPOS2SVPROC glad_glRasterPos2sv = NULL; PFNGLRASTERPOS3DPROC glad_glRasterPos3d = NULL; PFNGLRASTERPOS3DVPROC glad_glRasterPos3dv = NULL; PFNGLRASTERPOS3FPROC glad_glRasterPos3f = NULL; PFNGLRASTERPOS3FVPROC glad_glRasterPos3fv = NULL; PFNGLRASTERPOS3IPROC glad_glRasterPos3i = NULL; PFNGLRASTERPOS3IVPROC glad_glRasterPos3iv = NULL; PFNGLRASTERPOS3SPROC glad_glRasterPos3s = NULL; PFNGLRASTERPOS3SVPROC glad_glRasterPos3sv = NULL; PFNGLRASTERPOS4DPROC glad_glRasterPos4d = NULL; PFNGLRASTERPOS4DVPROC glad_glRasterPos4dv = NULL; PFNGLRASTERPOS4FPROC glad_glRasterPos4f = NULL; PFNGLRASTERPOS4FVPROC glad_glRasterPos4fv = NULL; PFNGLRASTERPOS4IPROC glad_glRasterPos4i = NULL; PFNGLRASTERPOS4IVPROC glad_glRasterPos4iv = NULL; PFNGLRASTERPOS4SPROC glad_glRasterPos4s = NULL; PFNGLRASTERPOS4SVPROC glad_glRasterPos4sv = NULL; PFNGLREADBUFFERPROC glad_glReadBuffer = NULL; PFNGLREADPIXELSPROC glad_glReadPixels = NULL; PFNGLREADNPIXELSPROC glad_glReadnPixels = NULL; PFNGLRECTDPROC glad_glRectd = NULL; PFNGLRECTDVPROC glad_glRectdv = NULL; PFNGLRECTFPROC glad_glRectf = NULL; PFNGLRECTFVPROC glad_glRectfv = NULL; PFNGLRECTIPROC glad_glRecti = NULL; PFNGLRECTIVPROC glad_glRectiv = NULL; PFNGLRECTSPROC glad_glRects = NULL; PFNGLRECTSVPROC glad_glRectsv = NULL; PFNGLRELEASESHADERCOMPILERPROC glad_glReleaseShaderCompiler = NULL; PFNGLRENDERMODEPROC glad_glRenderMode = NULL; PFNGLRENDERBUFFERSTORAGEPROC glad_glRenderbufferStorage = NULL; PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC glad_glRenderbufferStorageMultisample = NULL; PFNGLRESUMETRANSFORMFEEDBACKPROC glad_glResumeTransformFeedback = NULL; PFNGLROTATEDPROC glad_glRotated = NULL; PFNGLROTATEFPROC glad_glRotatef = NULL; PFNGLSAMPLECOVERAGEPROC glad_glSampleCoverage = NULL; PFNGLSAMPLEMASKIPROC glad_glSampleMaski = NULL; PFNGLSAMPLERPARAMETERIIVPROC glad_glSamplerParameterIiv = NULL; PFNGLSAMPLERPARAMETERIUIVPROC glad_glSamplerParameterIuiv = NULL; PFNGLSAMPLERPARAMETERFPROC glad_glSamplerParameterf = NULL; PFNGLSAMPLERPARAMETERFVPROC glad_glSamplerParameterfv = NULL; PFNGLSAMPLERPARAMETERIPROC glad_glSamplerParameteri = NULL; PFNGLSAMPLERPARAMETERIVPROC glad_glSamplerParameteriv = NULL; PFNGLSCALEDPROC glad_glScaled = NULL; PFNGLSCALEFPROC glad_glScalef = NULL; PFNGLSCISSORPROC glad_glScissor = NULL; PFNGLSCISSORARRAYVPROC glad_glScissorArrayv = NULL; PFNGLSCISSORINDEXEDPROC glad_glScissorIndexed = NULL; PFNGLSCISSORINDEXEDVPROC glad_glScissorIndexedv = NULL; PFNGLSECONDARYCOLOR3BPROC glad_glSecondaryColor3b = NULL; PFNGLSECONDARYCOLOR3BVPROC glad_glSecondaryColor3bv = NULL; PFNGLSECONDARYCOLOR3DPROC glad_glSecondaryColor3d = NULL; PFNGLSECONDARYCOLOR3DVPROC glad_glSecondaryColor3dv = NULL; PFNGLSECONDARYCOLOR3FPROC glad_glSecondaryColor3f = NULL; PFNGLSECONDARYCOLOR3FVPROC glad_glSecondaryColor3fv = NULL; PFNGLSECONDARYCOLOR3IPROC glad_glSecondaryColor3i = NULL; PFNGLSECONDARYCOLOR3IVPROC glad_glSecondaryColor3iv = NULL; PFNGLSECONDARYCOLOR3SPROC glad_glSecondaryColor3s = NULL; PFNGLSECONDARYCOLOR3SVPROC glad_glSecondaryColor3sv = NULL; PFNGLSECONDARYCOLOR3UBPROC glad_glSecondaryColor3ub = NULL; PFNGLSECONDARYCOLOR3UBVPROC glad_glSecondaryColor3ubv = NULL; PFNGLSECONDARYCOLOR3UIPROC glad_glSecondaryColor3ui = NULL; PFNGLSECONDARYCOLOR3UIVPROC glad_glSecondaryColor3uiv = NULL; PFNGLSECONDARYCOLOR3USPROC glad_glSecondaryColor3us = NULL; PFNGLSECONDARYCOLOR3USVPROC glad_glSecondaryColor3usv = NULL; PFNGLSECONDARYCOLORP3UIPROC glad_glSecondaryColorP3ui = NULL; PFNGLSECONDARYCOLORP3UIVPROC glad_glSecondaryColorP3uiv = NULL; PFNGLSECONDARYCOLORPOINTERPROC glad_glSecondaryColorPointer = NULL; PFNGLSELECTBUFFERPROC glad_glSelectBuffer = NULL; PFNGLSHADEMODELPROC glad_glShadeModel = NULL; PFNGLSHADERBINARYPROC glad_glShaderBinary = NULL; PFNGLSHADERSOURCEPROC glad_glShaderSource = NULL; PFNGLSHADERSTORAGEBLOCKBINDINGPROC glad_glShaderStorageBlockBinding = NULL; PFNGLSPECIALIZESHADERPROC glad_glSpecializeShader = NULL; PFNGLSTENCILFUNCPROC glad_glStencilFunc = NULL; PFNGLSTENCILFUNCSEPARATEPROC glad_glStencilFuncSeparate = NULL; PFNGLSTENCILMASKPROC glad_glStencilMask = NULL; PFNGLSTENCILMASKSEPARATEPROC glad_glStencilMaskSeparate = NULL; PFNGLSTENCILOPPROC glad_glStencilOp = NULL; PFNGLSTENCILOPSEPARATEPROC glad_glStencilOpSeparate = NULL; PFNGLTEXBUFFERPROC glad_glTexBuffer = NULL; PFNGLTEXBUFFERRANGEPROC glad_glTexBufferRange = NULL; PFNGLTEXCOORD1DPROC glad_glTexCoord1d = NULL; PFNGLTEXCOORD1DVPROC glad_glTexCoord1dv = NULL; PFNGLTEXCOORD1FPROC glad_glTexCoord1f = NULL; PFNGLTEXCOORD1FVPROC glad_glTexCoord1fv = NULL; PFNGLTEXCOORD1IPROC glad_glTexCoord1i = NULL; PFNGLTEXCOORD1IVPROC glad_glTexCoord1iv = NULL; PFNGLTEXCOORD1SPROC glad_glTexCoord1s = NULL; PFNGLTEXCOORD1SVPROC glad_glTexCoord1sv = NULL; PFNGLTEXCOORD2DPROC glad_glTexCoord2d = NULL; PFNGLTEXCOORD2DVPROC glad_glTexCoord2dv = NULL; PFNGLTEXCOORD2FPROC glad_glTexCoord2f = NULL; PFNGLTEXCOORD2FVPROC glad_glTexCoord2fv = NULL; PFNGLTEXCOORD2IPROC glad_glTexCoord2i = NULL; PFNGLTEXCOORD2IVPROC glad_glTexCoord2iv = NULL; PFNGLTEXCOORD2SPROC glad_glTexCoord2s = NULL; PFNGLTEXCOORD2SVPROC glad_glTexCoord2sv = NULL; PFNGLTEXCOORD3DPROC glad_glTexCoord3d = NULL; PFNGLTEXCOORD3DVPROC glad_glTexCoord3dv = NULL; PFNGLTEXCOORD3FPROC glad_glTexCoord3f = NULL; PFNGLTEXCOORD3FVPROC glad_glTexCoord3fv = NULL; PFNGLTEXCOORD3IPROC glad_glTexCoord3i = NULL; PFNGLTEXCOORD3IVPROC glad_glTexCoord3iv = NULL; PFNGLTEXCOORD3SPROC glad_glTexCoord3s = NULL; PFNGLTEXCOORD3SVPROC glad_glTexCoord3sv = NULL; PFNGLTEXCOORD4DPROC glad_glTexCoord4d = NULL; PFNGLTEXCOORD4DVPROC glad_glTexCoord4dv = NULL; PFNGLTEXCOORD4FPROC glad_glTexCoord4f = NULL; PFNGLTEXCOORD4FVPROC glad_glTexCoord4fv = NULL; PFNGLTEXCOORD4IPROC glad_glTexCoord4i = NULL; PFNGLTEXCOORD4IVPROC glad_glTexCoord4iv = NULL; PFNGLTEXCOORD4SPROC glad_glTexCoord4s = NULL; PFNGLTEXCOORD4SVPROC glad_glTexCoord4sv = NULL; PFNGLTEXCOORDP1UIPROC glad_glTexCoordP1ui = NULL; PFNGLTEXCOORDP1UIVPROC glad_glTexCoordP1uiv = NULL; PFNGLTEXCOORDP2UIPROC glad_glTexCoordP2ui = NULL; PFNGLTEXCOORDP2UIVPROC glad_glTexCoordP2uiv = NULL; PFNGLTEXCOORDP3UIPROC glad_glTexCoordP3ui = NULL; PFNGLTEXCOORDP3UIVPROC glad_glTexCoordP3uiv = NULL; PFNGLTEXCOORDP4UIPROC glad_glTexCoordP4ui = NULL; PFNGLTEXCOORDP4UIVPROC glad_glTexCoordP4uiv = NULL; PFNGLTEXCOORDPOINTERPROC glad_glTexCoordPointer = NULL; PFNGLTEXENVFPROC glad_glTexEnvf = NULL; PFNGLTEXENVFVPROC glad_glTexEnvfv = NULL; PFNGLTEXENVIPROC glad_glTexEnvi = NULL; PFNGLTEXENVIVPROC glad_glTexEnviv = NULL; PFNGLTEXGENDPROC glad_glTexGend = NULL; PFNGLTEXGENDVPROC glad_glTexGendv = NULL; PFNGLTEXGENFPROC glad_glTexGenf = NULL; PFNGLTEXGENFVPROC glad_glTexGenfv = NULL; PFNGLTEXGENIPROC glad_glTexGeni = NULL; PFNGLTEXGENIVPROC glad_glTexGeniv = NULL; PFNGLTEXIMAGE1DPROC glad_glTexImage1D = NULL; PFNGLTEXIMAGE2DPROC glad_glTexImage2D = NULL; PFNGLTEXIMAGE2DMULTISAMPLEPROC glad_glTexImage2DMultisample = NULL; PFNGLTEXIMAGE3DPROC glad_glTexImage3D = NULL; PFNGLTEXIMAGE3DMULTISAMPLEPROC glad_glTexImage3DMultisample = NULL; PFNGLTEXPARAMETERIIVPROC glad_glTexParameterIiv = NULL; PFNGLTEXPARAMETERIUIVPROC glad_glTexParameterIuiv = NULL; PFNGLTEXPARAMETERFPROC glad_glTexParameterf = NULL; PFNGLTEXPARAMETERFVPROC glad_glTexParameterfv = NULL; PFNGLTEXPARAMETERIPROC glad_glTexParameteri = NULL; PFNGLTEXPARAMETERIVPROC glad_glTexParameteriv = NULL; PFNGLTEXSTORAGE1DPROC glad_glTexStorage1D = NULL; PFNGLTEXSTORAGE2DPROC glad_glTexStorage2D = NULL; PFNGLTEXSTORAGE2DMULTISAMPLEPROC glad_glTexStorage2DMultisample = NULL; PFNGLTEXSTORAGE3DPROC glad_glTexStorage3D = NULL; PFNGLTEXSTORAGE3DMULTISAMPLEPROC glad_glTexStorage3DMultisample = NULL; PFNGLTEXSUBIMAGE1DPROC glad_glTexSubImage1D = NULL; PFNGLTEXSUBIMAGE2DPROC glad_glTexSubImage2D = NULL; PFNGLTEXSUBIMAGE3DPROC glad_glTexSubImage3D = NULL; PFNGLTEXTUREBARRIERPROC glad_glTextureBarrier = NULL; PFNGLTEXTUREBUFFERPROC glad_glTextureBuffer = NULL; PFNGLTEXTUREBUFFERRANGEPROC glad_glTextureBufferRange = NULL; PFNGLTEXTUREPARAMETERIIVPROC glad_glTextureParameterIiv = NULL; PFNGLTEXTUREPARAMETERIUIVPROC glad_glTextureParameterIuiv = NULL; PFNGLTEXTUREPARAMETERFPROC glad_glTextureParameterf = NULL; PFNGLTEXTUREPARAMETERFVPROC glad_glTextureParameterfv = NULL; PFNGLTEXTUREPARAMETERIPROC glad_glTextureParameteri = NULL; PFNGLTEXTUREPARAMETERIVPROC glad_glTextureParameteriv = NULL; PFNGLTEXTURESTORAGE1DPROC glad_glTextureStorage1D = NULL; PFNGLTEXTURESTORAGE2DPROC glad_glTextureStorage2D = NULL; PFNGLTEXTURESTORAGE2DMULTISAMPLEPROC glad_glTextureStorage2DMultisample = NULL; PFNGLTEXTURESTORAGE3DPROC glad_glTextureStorage3D = NULL; PFNGLTEXTURESTORAGE3DMULTISAMPLEPROC glad_glTextureStorage3DMultisample = NULL; PFNGLTEXTURESUBIMAGE1DPROC glad_glTextureSubImage1D = NULL; PFNGLTEXTURESUBIMAGE2DPROC glad_glTextureSubImage2D = NULL; PFNGLTEXTURESUBIMAGE3DPROC glad_glTextureSubImage3D = NULL; PFNGLTEXTUREVIEWPROC glad_glTextureView = NULL; PFNGLTRANSFORMFEEDBACKBUFFERBASEPROC glad_glTransformFeedbackBufferBase = NULL; PFNGLTRANSFORMFEEDBACKBUFFERRANGEPROC glad_glTransformFeedbackBufferRange = NULL; PFNGLTRANSFORMFEEDBACKVARYINGSPROC glad_glTransformFeedbackVaryings = NULL; PFNGLTRANSLATEDPROC glad_glTranslated = NULL; PFNGLTRANSLATEFPROC glad_glTranslatef = NULL; PFNGLUNIFORM1DPROC glad_glUniform1d = NULL; PFNGLUNIFORM1DVPROC glad_glUniform1dv = NULL; PFNGLUNIFORM1FPROC glad_glUniform1f = NULL; PFNGLUNIFORM1FVPROC glad_glUniform1fv = NULL; PFNGLUNIFORM1IPROC glad_glUniform1i = NULL; PFNGLUNIFORM1IVPROC glad_glUniform1iv = NULL; PFNGLUNIFORM1UIPROC glad_glUniform1ui = NULL; PFNGLUNIFORM1UIVPROC glad_glUniform1uiv = NULL; PFNGLUNIFORM2DPROC glad_glUniform2d = NULL; PFNGLUNIFORM2DVPROC glad_glUniform2dv = NULL; PFNGLUNIFORM2FPROC glad_glUniform2f = NULL; PFNGLUNIFORM2FVPROC glad_glUniform2fv = NULL; PFNGLUNIFORM2IPROC glad_glUniform2i = NULL; PFNGLUNIFORM2IVPROC glad_glUniform2iv = NULL; PFNGLUNIFORM2UIPROC glad_glUniform2ui = NULL; PFNGLUNIFORM2UIVPROC glad_glUniform2uiv = NULL; PFNGLUNIFORM3DPROC glad_glUniform3d = NULL; PFNGLUNIFORM3DVPROC glad_glUniform3dv = NULL; PFNGLUNIFORM3FPROC glad_glUniform3f = NULL; PFNGLUNIFORM3FVPROC glad_glUniform3fv = NULL; PFNGLUNIFORM3IPROC glad_glUniform3i = NULL; PFNGLUNIFORM3IVPROC glad_glUniform3iv = NULL; PFNGLUNIFORM3UIPROC glad_glUniform3ui = NULL; PFNGLUNIFORM3UIVPROC glad_glUniform3uiv = NULL; PFNGLUNIFORM4DPROC glad_glUniform4d = NULL; PFNGLUNIFORM4DVPROC glad_glUniform4dv = NULL; PFNGLUNIFORM4FPROC glad_glUniform4f = NULL; PFNGLUNIFORM4FVPROC glad_glUniform4fv = NULL; PFNGLUNIFORM4IPROC glad_glUniform4i = NULL; PFNGLUNIFORM4IVPROC glad_glUniform4iv = NULL; PFNGLUNIFORM4UIPROC glad_glUniform4ui = NULL; PFNGLUNIFORM4UIVPROC glad_glUniform4uiv = NULL; PFNGLUNIFORMBLOCKBINDINGPROC glad_glUniformBlockBinding = NULL; PFNGLUNIFORMMATRIX2DVPROC glad_glUniformMatrix2dv = NULL; PFNGLUNIFORMMATRIX2FVPROC glad_glUniformMatrix2fv = NULL; PFNGLUNIFORMMATRIX2X3DVPROC glad_glUniformMatrix2x3dv = NULL; PFNGLUNIFORMMATRIX2X3FVPROC glad_glUniformMatrix2x3fv = NULL; PFNGLUNIFORMMATRIX2X4DVPROC glad_glUniformMatrix2x4dv = NULL; PFNGLUNIFORMMATRIX2X4FVPROC glad_glUniformMatrix2x4fv = NULL; PFNGLUNIFORMMATRIX3DVPROC glad_glUniformMatrix3dv = NULL; PFNGLUNIFORMMATRIX3FVPROC glad_glUniformMatrix3fv = NULL; PFNGLUNIFORMMATRIX3X2DVPROC glad_glUniformMatrix3x2dv = NULL; PFNGLUNIFORMMATRIX3X2FVPROC glad_glUniformMatrix3x2fv = NULL; PFNGLUNIFORMMATRIX3X4DVPROC glad_glUniformMatrix3x4dv = NULL; PFNGLUNIFORMMATRIX3X4FVPROC glad_glUniformMatrix3x4fv = NULL; PFNGLUNIFORMMATRIX4DVPROC glad_glUniformMatrix4dv = NULL; PFNGLUNIFORMMATRIX4FVPROC glad_glUniformMatrix4fv = NULL; PFNGLUNIFORMMATRIX4X2DVPROC glad_glUniformMatrix4x2dv = NULL; PFNGLUNIFORMMATRIX4X2FVPROC glad_glUniformMatrix4x2fv = NULL; PFNGLUNIFORMMATRIX4X3DVPROC glad_glUniformMatrix4x3dv = NULL; PFNGLUNIFORMMATRIX4X3FVPROC glad_glUniformMatrix4x3fv = NULL; PFNGLUNIFORMSUBROUTINESUIVPROC glad_glUniformSubroutinesuiv = NULL; PFNGLUNMAPBUFFERPROC glad_glUnmapBuffer = NULL; PFNGLUNMAPNAMEDBUFFERPROC glad_glUnmapNamedBuffer = NULL; PFNGLUSEPROGRAMPROC glad_glUseProgram = NULL; PFNGLUSEPROGRAMSTAGESPROC glad_glUseProgramStages = NULL; PFNGLVALIDATEPROGRAMPROC glad_glValidateProgram = NULL; PFNGLVALIDATEPROGRAMPIPELINEPROC glad_glValidateProgramPipeline = NULL; PFNGLVERTEX2DPROC glad_glVertex2d = NULL; PFNGLVERTEX2DVPROC glad_glVertex2dv = NULL; PFNGLVERTEX2FPROC glad_glVertex2f = NULL; PFNGLVERTEX2FVPROC glad_glVertex2fv = NULL; PFNGLVERTEX2IPROC glad_glVertex2i = NULL; PFNGLVERTEX2IVPROC glad_glVertex2iv = NULL; PFNGLVERTEX2SPROC glad_glVertex2s = NULL; PFNGLVERTEX2SVPROC glad_glVertex2sv = NULL; PFNGLVERTEX3DPROC glad_glVertex3d = NULL; PFNGLVERTEX3DVPROC glad_glVertex3dv = NULL; PFNGLVERTEX3FPROC glad_glVertex3f = NULL; PFNGLVERTEX3FVPROC glad_glVertex3fv = NULL; PFNGLVERTEX3IPROC glad_glVertex3i = NULL; PFNGLVERTEX3IVPROC glad_glVertex3iv = NULL; PFNGLVERTEX3SPROC glad_glVertex3s = NULL; PFNGLVERTEX3SVPROC glad_glVertex3sv = NULL; PFNGLVERTEX4DPROC glad_glVertex4d = NULL; PFNGLVERTEX4DVPROC glad_glVertex4dv = NULL; PFNGLVERTEX4FPROC glad_glVertex4f = NULL; PFNGLVERTEX4FVPROC glad_glVertex4fv = NULL; PFNGLVERTEX4IPROC glad_glVertex4i = NULL; PFNGLVERTEX4IVPROC glad_glVertex4iv = NULL; PFNGLVERTEX4SPROC glad_glVertex4s = NULL; PFNGLVERTEX4SVPROC glad_glVertex4sv = NULL; PFNGLVERTEXARRAYATTRIBBINDINGPROC glad_glVertexArrayAttribBinding = NULL; PFNGLVERTEXARRAYATTRIBFORMATPROC glad_glVertexArrayAttribFormat = NULL; PFNGLVERTEXARRAYATTRIBIFORMATPROC glad_glVertexArrayAttribIFormat = NULL; PFNGLVERTEXARRAYATTRIBLFORMATPROC glad_glVertexArrayAttribLFormat = NULL; PFNGLVERTEXARRAYBINDINGDIVISORPROC glad_glVertexArrayBindingDivisor = NULL; PFNGLVERTEXARRAYELEMENTBUFFERPROC glad_glVertexArrayElementBuffer = NULL; PFNGLVERTEXARRAYVERTEXBUFFERPROC glad_glVertexArrayVertexBuffer = NULL; PFNGLVERTEXARRAYVERTEXBUFFERSPROC glad_glVertexArrayVertexBuffers = NULL; PFNGLVERTEXATTRIB1DPROC glad_glVertexAttrib1d = NULL; PFNGLVERTEXATTRIB1DVPROC glad_glVertexAttrib1dv = NULL; PFNGLVERTEXATTRIB1FPROC glad_glVertexAttrib1f = NULL; PFNGLVERTEXATTRIB1FVPROC glad_glVertexAttrib1fv = NULL; PFNGLVERTEXATTRIB1SPROC glad_glVertexAttrib1s = NULL; PFNGLVERTEXATTRIB1SVPROC glad_glVertexAttrib1sv = NULL; PFNGLVERTEXATTRIB2DPROC glad_glVertexAttrib2d = NULL; PFNGLVERTEXATTRIB2DVPROC glad_glVertexAttrib2dv = NULL; PFNGLVERTEXATTRIB2FPROC glad_glVertexAttrib2f = NULL; PFNGLVERTEXATTRIB2FVPROC glad_glVertexAttrib2fv = NULL; PFNGLVERTEXATTRIB2SPROC glad_glVertexAttrib2s = NULL; PFNGLVERTEXATTRIB2SVPROC glad_glVertexAttrib2sv = NULL; PFNGLVERTEXATTRIB3DPROC glad_glVertexAttrib3d = NULL; PFNGLVERTEXATTRIB3DVPROC glad_glVertexAttrib3dv = NULL; PFNGLVERTEXATTRIB3FPROC glad_glVertexAttrib3f = NULL; PFNGLVERTEXATTRIB3FVPROC glad_glVertexAttrib3fv = NULL; PFNGLVERTEXATTRIB3SPROC glad_glVertexAttrib3s = NULL; PFNGLVERTEXATTRIB3SVPROC glad_glVertexAttrib3sv = NULL; PFNGLVERTEXATTRIB4NBVPROC glad_glVertexAttrib4Nbv = NULL; PFNGLVERTEXATTRIB4NIVPROC glad_glVertexAttrib4Niv = NULL; PFNGLVERTEXATTRIB4NSVPROC glad_glVertexAttrib4Nsv = NULL; PFNGLVERTEXATTRIB4NUBPROC glad_glVertexAttrib4Nub = NULL; PFNGLVERTEXATTRIB4NUBVPROC glad_glVertexAttrib4Nubv = NULL; PFNGLVERTEXATTRIB4NUIVPROC glad_glVertexAttrib4Nuiv = NULL; PFNGLVERTEXATTRIB4NUSVPROC glad_glVertexAttrib4Nusv = NULL; PFNGLVERTEXATTRIB4BVPROC glad_glVertexAttrib4bv = NULL; PFNGLVERTEXATTRIB4DPROC glad_glVertexAttrib4d = NULL; PFNGLVERTEXATTRIB4DVPROC glad_glVertexAttrib4dv = NULL; PFNGLVERTEXATTRIB4FPROC glad_glVertexAttrib4f = NULL; PFNGLVERTEXATTRIB4FVPROC glad_glVertexAttrib4fv = NULL; PFNGLVERTEXATTRIB4IVPROC glad_glVertexAttrib4iv = NULL; PFNGLVERTEXATTRIB4SPROC glad_glVertexAttrib4s = NULL; PFNGLVERTEXATTRIB4SVPROC glad_glVertexAttrib4sv = NULL; PFNGLVERTEXATTRIB4UBVPROC glad_glVertexAttrib4ubv = NULL; PFNGLVERTEXATTRIB4UIVPROC glad_glVertexAttrib4uiv = NULL; PFNGLVERTEXATTRIB4USVPROC glad_glVertexAttrib4usv = NULL; PFNGLVERTEXATTRIBBINDINGPROC glad_glVertexAttribBinding = NULL; PFNGLVERTEXATTRIBDIVISORPROC glad_glVertexAttribDivisor = NULL; PFNGLVERTEXATTRIBFORMATPROC glad_glVertexAttribFormat = NULL; PFNGLVERTEXATTRIBI1IPROC glad_glVertexAttribI1i = NULL; PFNGLVERTEXATTRIBI1IVPROC glad_glVertexAttribI1iv = NULL; PFNGLVERTEXATTRIBI1UIPROC glad_glVertexAttribI1ui = NULL; PFNGLVERTEXATTRIBI1UIVPROC glad_glVertexAttribI1uiv = NULL; PFNGLVERTEXATTRIBI2IPROC glad_glVertexAttribI2i = NULL; PFNGLVERTEXATTRIBI2IVPROC glad_glVertexAttribI2iv = NULL; PFNGLVERTEXATTRIBI2UIPROC glad_glVertexAttribI2ui = NULL; PFNGLVERTEXATTRIBI2UIVPROC glad_glVertexAttribI2uiv = NULL; PFNGLVERTEXATTRIBI3IPROC glad_glVertexAttribI3i = NULL; PFNGLVERTEXATTRIBI3IVPROC glad_glVertexAttribI3iv = NULL; PFNGLVERTEXATTRIBI3UIPROC glad_glVertexAttribI3ui = NULL; PFNGLVERTEXATTRIBI3UIVPROC glad_glVertexAttribI3uiv = NULL; PFNGLVERTEXATTRIBI4BVPROC glad_glVertexAttribI4bv = NULL; PFNGLVERTEXATTRIBI4IPROC glad_glVertexAttribI4i = NULL; PFNGLVERTEXATTRIBI4IVPROC glad_glVertexAttribI4iv = NULL; PFNGLVERTEXATTRIBI4SVPROC glad_glVertexAttribI4sv = NULL; PFNGLVERTEXATTRIBI4UBVPROC glad_glVertexAttribI4ubv = NULL; PFNGLVERTEXATTRIBI4UIPROC glad_glVertexAttribI4ui = NULL; PFNGLVERTEXATTRIBI4UIVPROC glad_glVertexAttribI4uiv = NULL; PFNGLVERTEXATTRIBI4USVPROC glad_glVertexAttribI4usv = NULL; PFNGLVERTEXATTRIBIFORMATPROC glad_glVertexAttribIFormat = NULL; PFNGLVERTEXATTRIBIPOINTERPROC glad_glVertexAttribIPointer = NULL; PFNGLVERTEXATTRIBL1DPROC glad_glVertexAttribL1d = NULL; PFNGLVERTEXATTRIBL1DVPROC glad_glVertexAttribL1dv = NULL; PFNGLVERTEXATTRIBL2DPROC glad_glVertexAttribL2d = NULL; PFNGLVERTEXATTRIBL2DVPROC glad_glVertexAttribL2dv = NULL; PFNGLVERTEXATTRIBL3DPROC glad_glVertexAttribL3d = NULL; PFNGLVERTEXATTRIBL3DVPROC glad_glVertexAttribL3dv = NULL; PFNGLVERTEXATTRIBL4DPROC glad_glVertexAttribL4d = NULL; PFNGLVERTEXATTRIBL4DVPROC glad_glVertexAttribL4dv = NULL; PFNGLVERTEXATTRIBLFORMATPROC glad_glVertexAttribLFormat = NULL; PFNGLVERTEXATTRIBLPOINTERPROC glad_glVertexAttribLPointer = NULL; PFNGLVERTEXATTRIBP1UIPROC glad_glVertexAttribP1ui = NULL; PFNGLVERTEXATTRIBP1UIVPROC glad_glVertexAttribP1uiv = NULL; PFNGLVERTEXATTRIBP2UIPROC glad_glVertexAttribP2ui = NULL; PFNGLVERTEXATTRIBP2UIVPROC glad_glVertexAttribP2uiv = NULL; PFNGLVERTEXATTRIBP3UIPROC glad_glVertexAttribP3ui = NULL; PFNGLVERTEXATTRIBP3UIVPROC glad_glVertexAttribP3uiv = NULL; PFNGLVERTEXATTRIBP4UIPROC glad_glVertexAttribP4ui = NULL; PFNGLVERTEXATTRIBP4UIVPROC glad_glVertexAttribP4uiv = NULL; PFNGLVERTEXATTRIBPOINTERPROC glad_glVertexAttribPointer = NULL; PFNGLVERTEXBINDINGDIVISORPROC glad_glVertexBindingDivisor = NULL; PFNGLVERTEXP2UIPROC glad_glVertexP2ui = NULL; PFNGLVERTEXP2UIVPROC glad_glVertexP2uiv = NULL; PFNGLVERTEXP3UIPROC glad_glVertexP3ui = NULL; PFNGLVERTEXP3UIVPROC glad_glVertexP3uiv = NULL; PFNGLVERTEXP4UIPROC glad_glVertexP4ui = NULL; PFNGLVERTEXP4UIVPROC glad_glVertexP4uiv = NULL; PFNGLVERTEXPOINTERPROC glad_glVertexPointer = NULL; PFNGLVIEWPORTPROC glad_glViewport = NULL; PFNGLVIEWPORTARRAYVPROC glad_glViewportArrayv = NULL; PFNGLVIEWPORTINDEXEDFPROC glad_glViewportIndexedf = NULL; PFNGLVIEWPORTINDEXEDFVPROC glad_glViewportIndexedfv = NULL; PFNGLWAITSYNCPROC glad_glWaitSync = NULL; PFNGLWINDOWPOS2DPROC glad_glWindowPos2d = NULL; PFNGLWINDOWPOS2DVPROC glad_glWindowPos2dv = NULL; PFNGLWINDOWPOS2FPROC glad_glWindowPos2f = NULL; PFNGLWINDOWPOS2FVPROC glad_glWindowPos2fv = NULL; PFNGLWINDOWPOS2IPROC glad_glWindowPos2i = NULL; PFNGLWINDOWPOS2IVPROC glad_glWindowPos2iv = NULL; PFNGLWINDOWPOS2SPROC glad_glWindowPos2s = NULL; PFNGLWINDOWPOS2SVPROC glad_glWindowPos2sv = NULL; PFNGLWINDOWPOS3DPROC glad_glWindowPos3d = NULL; PFNGLWINDOWPOS3DVPROC glad_glWindowPos3dv = NULL; PFNGLWINDOWPOS3FPROC glad_glWindowPos3f = NULL; PFNGLWINDOWPOS3FVPROC glad_glWindowPos3fv = NULL; PFNGLWINDOWPOS3IPROC glad_glWindowPos3i = NULL; PFNGLWINDOWPOS3IVPROC glad_glWindowPos3iv = NULL; PFNGLWINDOWPOS3SPROC glad_glWindowPos3s = NULL; PFNGLWINDOWPOS3SVPROC glad_glWindowPos3sv = NULL; int GLAD_GL_ARB_clip_control = 0; int GLAD_GL_EXT_clip_control = 0; PFNGLCLIPCONTROLEXTPROC glad_glClipControlEXT = NULL; static void load_GL_VERSION_1_0(GLADloadproc load) { if(!GLAD_GL_VERSION_1_0) return; glad_glCullFace = (PFNGLCULLFACEPROC)load("glCullFace"); glad_glFrontFace = (PFNGLFRONTFACEPROC)load("glFrontFace"); glad_glHint = (PFNGLHINTPROC)load("glHint"); glad_glLineWidth = (PFNGLLINEWIDTHPROC)load("glLineWidth"); glad_glPointSize = (PFNGLPOINTSIZEPROC)load("glPointSize"); glad_glPolygonMode = (PFNGLPOLYGONMODEPROC)load("glPolygonMode"); glad_glScissor = (PFNGLSCISSORPROC)load("glScissor"); glad_glTexParameterf = (PFNGLTEXPARAMETERFPROC)load("glTexParameterf"); glad_glTexParameterfv = (PFNGLTEXPARAMETERFVPROC)load("glTexParameterfv"); glad_glTexParameteri = (PFNGLTEXPARAMETERIPROC)load("glTexParameteri"); glad_glTexParameteriv = (PFNGLTEXPARAMETERIVPROC)load("glTexParameteriv"); glad_glTexImage1D = (PFNGLTEXIMAGE1DPROC)load("glTexImage1D"); glad_glTexImage2D = (PFNGLTEXIMAGE2DPROC)load("glTexImage2D"); glad_glDrawBuffer = (PFNGLDRAWBUFFERPROC)load("glDrawBuffer"); glad_glClear = (PFNGLCLEARPROC)load("glClear"); glad_glClearColor = (PFNGLCLEARCOLORPROC)load("glClearColor"); glad_glClearStencil = (PFNGLCLEARSTENCILPROC)load("glClearStencil"); glad_glClearDepth = (PFNGLCLEARDEPTHPROC)load("glClearDepth"); glad_glStencilMask = (PFNGLSTENCILMASKPROC)load("glStencilMask"); glad_glColorMask = (PFNGLCOLORMASKPROC)load("glColorMask"); glad_glDepthMask = (PFNGLDEPTHMASKPROC)load("glDepthMask"); glad_glDisable = (PFNGLDISABLEPROC)load("glDisable"); glad_glEnable = (PFNGLENABLEPROC)load("glEnable"); glad_glFinish = (PFNGLFINISHPROC)load("glFinish"); glad_glFlush = (PFNGLFLUSHPROC)load("glFlush"); glad_glBlendFunc = (PFNGLBLENDFUNCPROC)load("glBlendFunc"); glad_glLogicOp = (PFNGLLOGICOPPROC)load("glLogicOp"); glad_glStencilFunc = (PFNGLSTENCILFUNCPROC)load("glStencilFunc"); glad_glStencilOp = (PFNGLSTENCILOPPROC)load("glStencilOp"); glad_glDepthFunc = (PFNGLDEPTHFUNCPROC)load("glDepthFunc"); glad_glPixelStoref = (PFNGLPIXELSTOREFPROC)load("glPixelStoref"); glad_glPixelStorei = (PFNGLPIXELSTOREIPROC)load("glPixelStorei"); glad_glReadBuffer = (PFNGLREADBUFFERPROC)load("glReadBuffer"); glad_glReadPixels = (PFNGLREADPIXELSPROC)load("glReadPixels"); glad_glGetBooleanv = (PFNGLGETBOOLEANVPROC)load("glGetBooleanv"); glad_glGetDoublev = (PFNGLGETDOUBLEVPROC)load("glGetDoublev"); glad_glGetError = (PFNGLGETERRORPROC)load("glGetError"); glad_glGetFloatv = (PFNGLGETFLOATVPROC)load("glGetFloatv"); glad_glGetIntegerv = (PFNGLGETINTEGERVPROC)load("glGetIntegerv"); glad_glGetString = (PFNGLGETSTRINGPROC)load("glGetString"); glad_glGetTexImage = (PFNGLGETTEXIMAGEPROC)load("glGetTexImage"); glad_glGetTexParameterfv = (PFNGLGETTEXPARAMETERFVPROC)load("glGetTexParameterfv"); glad_glGetTexParameteriv = (PFNGLGETTEXPARAMETERIVPROC)load("glGetTexParameteriv"); glad_glGetTexLevelParameterfv = (PFNGLGETTEXLEVELPARAMETERFVPROC)load("glGetTexLevelParameterfv"); glad_glGetTexLevelParameteriv = (PFNGLGETTEXLEVELPARAMETERIVPROC)load("glGetTexLevelParameteriv"); glad_glIsEnabled = (PFNGLISENABLEDPROC)load("glIsEnabled"); glad_glDepthRange = (PFNGLDEPTHRANGEPROC)load("glDepthRange"); glad_glViewport = (PFNGLVIEWPORTPROC)load("glViewport"); glad_glNewList = (PFNGLNEWLISTPROC)load("glNewList"); glad_glEndList = (PFNGLENDLISTPROC)load("glEndList"); glad_glCallList = (PFNGLCALLLISTPROC)load("glCallList"); glad_glCallLists = (PFNGLCALLLISTSPROC)load("glCallLists"); glad_glDeleteLists = (PFNGLDELETELISTSPROC)load("glDeleteLists"); glad_glGenLists = (PFNGLGENLISTSPROC)load("glGenLists"); glad_glListBase = (PFNGLLISTBASEPROC)load("glListBase"); glad_glBegin = (PFNGLBEGINPROC)load("glBegin"); glad_glBitmap = (PFNGLBITMAPPROC)load("glBitmap"); glad_glColor3b = (PFNGLCOLOR3BPROC)load("glColor3b"); glad_glColor3bv = (PFNGLCOLOR3BVPROC)load("glColor3bv"); glad_glColor3d = (PFNGLCOLOR3DPROC)load("glColor3d"); glad_glColor3dv = (PFNGLCOLOR3DVPROC)load("glColor3dv"); glad_glColor3f = (PFNGLCOLOR3FPROC)load("glColor3f"); glad_glColor3fv = (PFNGLCOLOR3FVPROC)load("glColor3fv"); glad_glColor3i = (PFNGLCOLOR3IPROC)load("glColor3i"); glad_glColor3iv = (PFNGLCOLOR3IVPROC)load("glColor3iv"); glad_glColor3s = (PFNGLCOLOR3SPROC)load("glColor3s"); glad_glColor3sv = (PFNGLCOLOR3SVPROC)load("glColor3sv"); glad_glColor3ub = (PFNGLCOLOR3UBPROC)load("glColor3ub"); glad_glColor3ubv = (PFNGLCOLOR3UBVPROC)load("glColor3ubv"); glad_glColor3ui = (PFNGLCOLOR3UIPROC)load("glColor3ui"); glad_glColor3uiv = (PFNGLCOLOR3UIVPROC)load("glColor3uiv"); glad_glColor3us = (PFNGLCOLOR3USPROC)load("glColor3us"); glad_glColor3usv = (PFNGLCOLOR3USVPROC)load("glColor3usv"); glad_glColor4b = (PFNGLCOLOR4BPROC)load("glColor4b"); glad_glColor4bv = (PFNGLCOLOR4BVPROC)load("glColor4bv"); glad_glColor4d = (PFNGLCOLOR4DPROC)load("glColor4d"); glad_glColor4dv = (PFNGLCOLOR4DVPROC)load("glColor4dv"); glad_glColor4f = (PFNGLCOLOR4FPROC)load("glColor4f"); glad_glColor4fv = (PFNGLCOLOR4FVPROC)load("glColor4fv"); glad_glColor4i = (PFNGLCOLOR4IPROC)load("glColor4i"); glad_glColor4iv = (PFNGLCOLOR4IVPROC)load("glColor4iv"); glad_glColor4s = (PFNGLCOLOR4SPROC)load("glColor4s"); glad_glColor4sv = (PFNGLCOLOR4SVPROC)load("glColor4sv"); glad_glColor4ub = (PFNGLCOLOR4UBPROC)load("glColor4ub"); glad_glColor4ubv = (PFNGLCOLOR4UBVPROC)load("glColor4ubv"); glad_glColor4ui = (PFNGLCOLOR4UIPROC)load("glColor4ui"); glad_glColor4uiv = (PFNGLCOLOR4UIVPROC)load("glColor4uiv"); glad_glColor4us = (PFNGLCOLOR4USPROC)load("glColor4us"); glad_glColor4usv = (PFNGLCOLOR4USVPROC)load("glColor4usv"); glad_glEdgeFlag = (PFNGLEDGEFLAGPROC)load("glEdgeFlag"); glad_glEdgeFlagv = (PFNGLEDGEFLAGVPROC)load("glEdgeFlagv"); glad_glEnd = (PFNGLENDPROC)load("glEnd"); glad_glIndexd = (PFNGLINDEXDPROC)load("glIndexd"); glad_glIndexdv = (PFNGLINDEXDVPROC)load("glIndexdv"); glad_glIndexf = (PFNGLINDEXFPROC)load("glIndexf"); glad_glIndexfv = (PFNGLINDEXFVPROC)load("glIndexfv"); glad_glIndexi = (PFNGLINDEXIPROC)load("glIndexi"); glad_glIndexiv = (PFNGLINDEXIVPROC)load("glIndexiv"); glad_glIndexs = (PFNGLINDEXSPROC)load("glIndexs"); glad_glIndexsv = (PFNGLINDEXSVPROC)load("glIndexsv"); glad_glNormal3b = (PFNGLNORMAL3BPROC)load("glNormal3b"); glad_glNormal3bv = (PFNGLNORMAL3BVPROC)load("glNormal3bv"); glad_glNormal3d = (PFNGLNORMAL3DPROC)load("glNormal3d"); glad_glNormal3dv = (PFNGLNORMAL3DVPROC)load("glNormal3dv"); glad_glNormal3f = (PFNGLNORMAL3FPROC)load("glNormal3f"); glad_glNormal3fv = (PFNGLNORMAL3FVPROC)load("glNormal3fv"); glad_glNormal3i = (PFNGLNORMAL3IPROC)load("glNormal3i"); glad_glNormal3iv = (PFNGLNORMAL3IVPROC)load("glNormal3iv"); glad_glNormal3s = (PFNGLNORMAL3SPROC)load("glNormal3s"); glad_glNormal3sv = (PFNGLNORMAL3SVPROC)load("glNormal3sv"); glad_glRasterPos2d = (PFNGLRASTERPOS2DPROC)load("glRasterPos2d"); glad_glRasterPos2dv = (PFNGLRASTERPOS2DVPROC)load("glRasterPos2dv"); glad_glRasterPos2f = (PFNGLRASTERPOS2FPROC)load("glRasterPos2f"); glad_glRasterPos2fv = (PFNGLRASTERPOS2FVPROC)load("glRasterPos2fv"); glad_glRasterPos2i = (PFNGLRASTERPOS2IPROC)load("glRasterPos2i"); glad_glRasterPos2iv = (PFNGLRASTERPOS2IVPROC)load("glRasterPos2iv"); glad_glRasterPos2s = (PFNGLRASTERPOS2SPROC)load("glRasterPos2s"); glad_glRasterPos2sv = (PFNGLRASTERPOS2SVPROC)load("glRasterPos2sv"); glad_glRasterPos3d = (PFNGLRASTERPOS3DPROC)load("glRasterPos3d"); glad_glRasterPos3dv = (PFNGLRASTERPOS3DVPROC)load("glRasterPos3dv"); glad_glRasterPos3f = (PFNGLRASTERPOS3FPROC)load("glRasterPos3f"); glad_glRasterPos3fv = (PFNGLRASTERPOS3FVPROC)load("glRasterPos3fv"); glad_glRasterPos3i = (PFNGLRASTERPOS3IPROC)load("glRasterPos3i"); glad_glRasterPos3iv = (PFNGLRASTERPOS3IVPROC)load("glRasterPos3iv"); glad_glRasterPos3s = (PFNGLRASTERPOS3SPROC)load("glRasterPos3s"); glad_glRasterPos3sv = (PFNGLRASTERPOS3SVPROC)load("glRasterPos3sv"); glad_glRasterPos4d = (PFNGLRASTERPOS4DPROC)load("glRasterPos4d"); glad_glRasterPos4dv = (PFNGLRASTERPOS4DVPROC)load("glRasterPos4dv"); glad_glRasterPos4f = (PFNGLRASTERPOS4FPROC)load("glRasterPos4f"); glad_glRasterPos4fv = (PFNGLRASTERPOS4FVPROC)load("glRasterPos4fv"); glad_glRasterPos4i = (PFNGLRASTERPOS4IPROC)load("glRasterPos4i"); glad_glRasterPos4iv = (PFNGLRASTERPOS4IVPROC)load("glRasterPos4iv"); glad_glRasterPos4s = (PFNGLRASTERPOS4SPROC)load("glRasterPos4s"); glad_glRasterPos4sv = (PFNGLRASTERPOS4SVPROC)load("glRasterPos4sv"); glad_glRectd = (PFNGLRECTDPROC)load("glRectd"); glad_glRectdv = (PFNGLRECTDVPROC)load("glRectdv"); glad_glRectf = (PFNGLRECTFPROC)load("glRectf"); glad_glRectfv = (PFNGLRECTFVPROC)load("glRectfv"); glad_glRecti = (PFNGLRECTIPROC)load("glRecti"); glad_glRectiv = (PFNGLRECTIVPROC)load("glRectiv"); glad_glRects = (PFNGLRECTSPROC)load("glRects"); glad_glRectsv = (PFNGLRECTSVPROC)load("glRectsv"); glad_glTexCoord1d = (PFNGLTEXCOORD1DPROC)load("glTexCoord1d"); glad_glTexCoord1dv = (PFNGLTEXCOORD1DVPROC)load("glTexCoord1dv"); glad_glTexCoord1f = (PFNGLTEXCOORD1FPROC)load("glTexCoord1f"); glad_glTexCoord1fv = (PFNGLTEXCOORD1FVPROC)load("glTexCoord1fv"); glad_glTexCoord1i = (PFNGLTEXCOORD1IPROC)load("glTexCoord1i"); glad_glTexCoord1iv = (PFNGLTEXCOORD1IVPROC)load("glTexCoord1iv"); glad_glTexCoord1s = (PFNGLTEXCOORD1SPROC)load("glTexCoord1s"); glad_glTexCoord1sv = (PFNGLTEXCOORD1SVPROC)load("glTexCoord1sv"); glad_glTexCoord2d = (PFNGLTEXCOORD2DPROC)load("glTexCoord2d"); glad_glTexCoord2dv = (PFNGLTEXCOORD2DVPROC)load("glTexCoord2dv"); glad_glTexCoord2f = (PFNGLTEXCOORD2FPROC)load("glTexCoord2f"); glad_glTexCoord2fv = (PFNGLTEXCOORD2FVPROC)load("glTexCoord2fv"); glad_glTexCoord2i = (PFNGLTEXCOORD2IPROC)load("glTexCoord2i"); glad_glTexCoord2iv = (PFNGLTEXCOORD2IVPROC)load("glTexCoord2iv"); glad_glTexCoord2s = (PFNGLTEXCOORD2SPROC)load("glTexCoord2s"); glad_glTexCoord2sv = (PFNGLTEXCOORD2SVPROC)load("glTexCoord2sv"); glad_glTexCoord3d = (PFNGLTEXCOORD3DPROC)load("glTexCoord3d"); glad_glTexCoord3dv = (PFNGLTEXCOORD3DVPROC)load("glTexCoord3dv"); glad_glTexCoord3f = (PFNGLTEXCOORD3FPROC)load("glTexCoord3f"); glad_glTexCoord3fv = (PFNGLTEXCOORD3FVPROC)load("glTexCoord3fv"); glad_glTexCoord3i = (PFNGLTEXCOORD3IPROC)load("glTexCoord3i"); glad_glTexCoord3iv = (PFNGLTEXCOORD3IVPROC)load("glTexCoord3iv"); glad_glTexCoord3s = (PFNGLTEXCOORD3SPROC)load("glTexCoord3s"); glad_glTexCoord3sv = (PFNGLTEXCOORD3SVPROC)load("glTexCoord3sv"); glad_glTexCoord4d = (PFNGLTEXCOORD4DPROC)load("glTexCoord4d"); glad_glTexCoord4dv = (PFNGLTEXCOORD4DVPROC)load("glTexCoord4dv"); glad_glTexCoord4f = (PFNGLTEXCOORD4FPROC)load("glTexCoord4f"); glad_glTexCoord4fv = (PFNGLTEXCOORD4FVPROC)load("glTexCoord4fv"); glad_glTexCoord4i = (PFNGLTEXCOORD4IPROC)load("glTexCoord4i"); glad_glTexCoord4iv = (PFNGLTEXCOORD4IVPROC)load("glTexCoord4iv"); glad_glTexCoord4s = (PFNGLTEXCOORD4SPROC)load("glTexCoord4s"); glad_glTexCoord4sv = (PFNGLTEXCOORD4SVPROC)load("glTexCoord4sv"); glad_glVertex2d = (PFNGLVERTEX2DPROC)load("glVertex2d"); glad_glVertex2dv = (PFNGLVERTEX2DVPROC)load("glVertex2dv"); glad_glVertex2f = (PFNGLVERTEX2FPROC)load("glVertex2f"); glad_glVertex2fv = (PFNGLVERTEX2FVPROC)load("glVertex2fv"); glad_glVertex2i = (PFNGLVERTEX2IPROC)load("glVertex2i"); glad_glVertex2iv = (PFNGLVERTEX2IVPROC)load("glVertex2iv"); glad_glVertex2s = (PFNGLVERTEX2SPROC)load("glVertex2s"); glad_glVertex2sv = (PFNGLVERTEX2SVPROC)load("glVertex2sv"); glad_glVertex3d = (PFNGLVERTEX3DPROC)load("glVertex3d"); glad_glVertex3dv = (PFNGLVERTEX3DVPROC)load("glVertex3dv"); glad_glVertex3f = (PFNGLVERTEX3FPROC)load("glVertex3f"); glad_glVertex3fv = (PFNGLVERTEX3FVPROC)load("glVertex3fv"); glad_glVertex3i = (PFNGLVERTEX3IPROC)load("glVertex3i"); glad_glVertex3iv = (PFNGLVERTEX3IVPROC)load("glVertex3iv"); glad_glVertex3s = (PFNGLVERTEX3SPROC)load("glVertex3s"); glad_glVertex3sv = (PFNGLVERTEX3SVPROC)load("glVertex3sv"); glad_glVertex4d = (PFNGLVERTEX4DPROC)load("glVertex4d"); glad_glVertex4dv = (PFNGLVERTEX4DVPROC)load("glVertex4dv"); glad_glVertex4f = (PFNGLVERTEX4FPROC)load("glVertex4f"); glad_glVertex4fv = (PFNGLVERTEX4FVPROC)load("glVertex4fv"); glad_glVertex4i = (PFNGLVERTEX4IPROC)load("glVertex4i"); glad_glVertex4iv = (PFNGLVERTEX4IVPROC)load("glVertex4iv"); glad_glVertex4s = (PFNGLVERTEX4SPROC)load("glVertex4s"); glad_glVertex4sv = (PFNGLVERTEX4SVPROC)load("glVertex4sv"); glad_glClipPlane = (PFNGLCLIPPLANEPROC)load("glClipPlane"); glad_glColorMaterial = (PFNGLCOLORMATERIALPROC)load("glColorMaterial"); glad_glFogf = (PFNGLFOGFPROC)load("glFogf"); glad_glFogfv = (PFNGLFOGFVPROC)load("glFogfv"); glad_glFogi = (PFNGLFOGIPROC)load("glFogi"); glad_glFogiv = (PFNGLFOGIVPROC)load("glFogiv"); glad_glLightf = (PFNGLLIGHTFPROC)load("glLightf"); glad_glLightfv = (PFNGLLIGHTFVPROC)load("glLightfv"); glad_glLighti = (PFNGLLIGHTIPROC)load("glLighti"); glad_glLightiv = (PFNGLLIGHTIVPROC)load("glLightiv"); glad_glLightModelf = (PFNGLLIGHTMODELFPROC)load("glLightModelf"); glad_glLightModelfv = (PFNGLLIGHTMODELFVPROC)load("glLightModelfv"); glad_glLightModeli = (PFNGLLIGHTMODELIPROC)load("glLightModeli"); glad_glLightModeliv = (PFNGLLIGHTMODELIVPROC)load("glLightModeliv"); glad_glLineStipple = (PFNGLLINESTIPPLEPROC)load("glLineStipple"); glad_glMaterialf = (PFNGLMATERIALFPROC)load("glMaterialf"); glad_glMaterialfv = (PFNGLMATERIALFVPROC)load("glMaterialfv"); glad_glMateriali = (PFNGLMATERIALIPROC)load("glMateriali"); glad_glMaterialiv = (PFNGLMATERIALIVPROC)load("glMaterialiv"); glad_glPolygonStipple = (PFNGLPOLYGONSTIPPLEPROC)load("glPolygonStipple"); glad_glShadeModel = (PFNGLSHADEMODELPROC)load("glShadeModel"); glad_glTexEnvf = (PFNGLTEXENVFPROC)load("glTexEnvf"); glad_glTexEnvfv = (PFNGLTEXENVFVPROC)load("glTexEnvfv"); glad_glTexEnvi = (PFNGLTEXENVIPROC)load("glTexEnvi"); glad_glTexEnviv = (PFNGLTEXENVIVPROC)load("glTexEnviv"); glad_glTexGend = (PFNGLTEXGENDPROC)load("glTexGend"); glad_glTexGendv = (PFNGLTEXGENDVPROC)load("glTexGendv"); glad_glTexGenf = (PFNGLTEXGENFPROC)load("glTexGenf"); glad_glTexGenfv = (PFNGLTEXGENFVPROC)load("glTexGenfv"); glad_glTexGeni = (PFNGLTEXGENIPROC)load("glTexGeni"); glad_glTexGeniv = (PFNGLTEXGENIVPROC)load("glTexGeniv"); glad_glFeedbackBuffer = (PFNGLFEEDBACKBUFFERPROC)load("glFeedbackBuffer"); glad_glSelectBuffer = (PFNGLSELECTBUFFERPROC)load("glSelectBuffer"); glad_glRenderMode = (PFNGLRENDERMODEPROC)load("glRenderMode"); glad_glInitNames = (PFNGLINITNAMESPROC)load("glInitNames"); glad_glLoadName = (PFNGLLOADNAMEPROC)load("glLoadName"); glad_glPassThrough = (PFNGLPASSTHROUGHPROC)load("glPassThrough"); glad_glPopName = (PFNGLPOPNAMEPROC)load("glPopName"); glad_glPushName = (PFNGLPUSHNAMEPROC)load("glPushName"); glad_glClearAccum = (PFNGLCLEARACCUMPROC)load("glClearAccum"); glad_glClearIndex = (PFNGLCLEARINDEXPROC)load("glClearIndex"); glad_glIndexMask = (PFNGLINDEXMASKPROC)load("glIndexMask"); glad_glAccum = (PFNGLACCUMPROC)load("glAccum"); glad_glPopAttrib = (PFNGLPOPATTRIBPROC)load("glPopAttrib"); glad_glPushAttrib = (PFNGLPUSHATTRIBPROC)load("glPushAttrib"); glad_glMap1d = (PFNGLMAP1DPROC)load("glMap1d"); glad_glMap1f = (PFNGLMAP1FPROC)load("glMap1f"); glad_glMap2d = (PFNGLMAP2DPROC)load("glMap2d"); glad_glMap2f = (PFNGLMAP2FPROC)load("glMap2f"); glad_glMapGrid1d = (PFNGLMAPGRID1DPROC)load("glMapGrid1d"); glad_glMapGrid1f = (PFNGLMAPGRID1FPROC)load("glMapGrid1f"); glad_glMapGrid2d = (PFNGLMAPGRID2DPROC)load("glMapGrid2d"); glad_glMapGrid2f = (PFNGLMAPGRID2FPROC)load("glMapGrid2f"); glad_glEvalCoord1d = (PFNGLEVALCOORD1DPROC)load("glEvalCoord1d"); glad_glEvalCoord1dv = (PFNGLEVALCOORD1DVPROC)load("glEvalCoord1dv"); glad_glEvalCoord1f = (PFNGLEVALCOORD1FPROC)load("glEvalCoord1f"); glad_glEvalCoord1fv = (PFNGLEVALCOORD1FVPROC)load("glEvalCoord1fv"); glad_glEvalCoord2d = (PFNGLEVALCOORD2DPROC)load("glEvalCoord2d"); glad_glEvalCoord2dv = (PFNGLEVALCOORD2DVPROC)load("glEvalCoord2dv"); glad_glEvalCoord2f = (PFNGLEVALCOORD2FPROC)load("glEvalCoord2f"); glad_glEvalCoord2fv = (PFNGLEVALCOORD2FVPROC)load("glEvalCoord2fv"); glad_glEvalMesh1 = (PFNGLEVALMESH1PROC)load("glEvalMesh1"); glad_glEvalPoint1 = (PFNGLEVALPOINT1PROC)load("glEvalPoint1"); glad_glEvalMesh2 = (PFNGLEVALMESH2PROC)load("glEvalMesh2"); glad_glEvalPoint2 = (PFNGLEVALPOINT2PROC)load("glEvalPoint2"); glad_glAlphaFunc = (PFNGLALPHAFUNCPROC)load("glAlphaFunc"); glad_glPixelZoom = (PFNGLPIXELZOOMPROC)load("glPixelZoom"); glad_glPixelTransferf = (PFNGLPIXELTRANSFERFPROC)load("glPixelTransferf"); glad_glPixelTransferi = (PFNGLPIXELTRANSFERIPROC)load("glPixelTransferi"); glad_glPixelMapfv = (PFNGLPIXELMAPFVPROC)load("glPixelMapfv"); glad_glPixelMapuiv = (PFNGLPIXELMAPUIVPROC)load("glPixelMapuiv"); glad_glPixelMapusv = (PFNGLPIXELMAPUSVPROC)load("glPixelMapusv"); glad_glCopyPixels = (PFNGLCOPYPIXELSPROC)load("glCopyPixels"); glad_glDrawPixels = (PFNGLDRAWPIXELSPROC)load("glDrawPixels"); glad_glGetClipPlane = (PFNGLGETCLIPPLANEPROC)load("glGetClipPlane"); glad_glGetLightfv = (PFNGLGETLIGHTFVPROC)load("glGetLightfv"); glad_glGetLightiv = (PFNGLGETLIGHTIVPROC)load("glGetLightiv"); glad_glGetMapdv = (PFNGLGETMAPDVPROC)load("glGetMapdv"); glad_glGetMapfv = (PFNGLGETMAPFVPROC)load("glGetMapfv"); glad_glGetMapiv = (PFNGLGETMAPIVPROC)load("glGetMapiv"); glad_glGetMaterialfv = (PFNGLGETMATERIALFVPROC)load("glGetMaterialfv"); glad_glGetMaterialiv = (PFNGLGETMATERIALIVPROC)load("glGetMaterialiv"); glad_glGetPixelMapfv = (PFNGLGETPIXELMAPFVPROC)load("glGetPixelMapfv"); glad_glGetPixelMapuiv = (PFNGLGETPIXELMAPUIVPROC)load("glGetPixelMapuiv"); glad_glGetPixelMapusv = (PFNGLGETPIXELMAPUSVPROC)load("glGetPixelMapusv"); glad_glGetPolygonStipple = (PFNGLGETPOLYGONSTIPPLEPROC)load("glGetPolygonStipple"); glad_glGetTexEnvfv = (PFNGLGETTEXENVFVPROC)load("glGetTexEnvfv"); glad_glGetTexEnviv = (PFNGLGETTEXENVIVPROC)load("glGetTexEnviv"); glad_glGetTexGendv = (PFNGLGETTEXGENDVPROC)load("glGetTexGendv"); glad_glGetTexGenfv = (PFNGLGETTEXGENFVPROC)load("glGetTexGenfv"); glad_glGetTexGeniv = (PFNGLGETTEXGENIVPROC)load("glGetTexGeniv"); glad_glIsList = (PFNGLISLISTPROC)load("glIsList"); glad_glFrustum = (PFNGLFRUSTUMPROC)load("glFrustum"); glad_glLoadIdentity = (PFNGLLOADIDENTITYPROC)load("glLoadIdentity"); glad_glLoadMatrixf = (PFNGLLOADMATRIXFPROC)load("glLoadMatrixf"); glad_glLoadMatrixd = (PFNGLLOADMATRIXDPROC)load("glLoadMatrixd"); glad_glMatrixMode = (PFNGLMATRIXMODEPROC)load("glMatrixMode"); glad_glMultMatrixf = (PFNGLMULTMATRIXFPROC)load("glMultMatrixf"); glad_glMultMatrixd = (PFNGLMULTMATRIXDPROC)load("glMultMatrixd"); glad_glOrtho = (PFNGLORTHOPROC)load("glOrtho"); glad_glPopMatrix = (PFNGLPOPMATRIXPROC)load("glPopMatrix"); glad_glPushMatrix = (PFNGLPUSHMATRIXPROC)load("glPushMatrix"); glad_glRotated = (PFNGLROTATEDPROC)load("glRotated"); glad_glRotatef = (PFNGLROTATEFPROC)load("glRotatef"); glad_glScaled = (PFNGLSCALEDPROC)load("glScaled"); glad_glScalef = (PFNGLSCALEFPROC)load("glScalef"); glad_glTranslated = (PFNGLTRANSLATEDPROC)load("glTranslated"); glad_glTranslatef = (PFNGLTRANSLATEFPROC)load("glTranslatef"); } static void load_GL_VERSION_1_1(GLADloadproc load) { if(!GLAD_GL_VERSION_1_1) return; glad_glDrawArrays = (PFNGLDRAWARRAYSPROC)load("glDrawArrays"); glad_glDrawElements = (PFNGLDRAWELEMENTSPROC)load("glDrawElements"); glad_glGetPointerv = (PFNGLGETPOINTERVPROC)load("glGetPointerv"); glad_glPolygonOffset = (PFNGLPOLYGONOFFSETPROC)load("glPolygonOffset"); glad_glCopyTexImage1D = (PFNGLCOPYTEXIMAGE1DPROC)load("glCopyTexImage1D"); glad_glCopyTexImage2D = (PFNGLCOPYTEXIMAGE2DPROC)load("glCopyTexImage2D"); glad_glCopyTexSubImage1D = (PFNGLCOPYTEXSUBIMAGE1DPROC)load("glCopyTexSubImage1D"); glad_glCopyTexSubImage2D = (PFNGLCOPYTEXSUBIMAGE2DPROC)load("glCopyTexSubImage2D"); glad_glTexSubImage1D = (PFNGLTEXSUBIMAGE1DPROC)load("glTexSubImage1D"); glad_glTexSubImage2D = (PFNGLTEXSUBIMAGE2DPROC)load("glTexSubImage2D"); glad_glBindTexture = (PFNGLBINDTEXTUREPROC)load("glBindTexture"); glad_glDeleteTextures = (PFNGLDELETETEXTURESPROC)load("glDeleteTextures"); glad_glGenTextures = (PFNGLGENTEXTURESPROC)load("glGenTextures"); glad_glIsTexture = (PFNGLISTEXTUREPROC)load("glIsTexture"); glad_glArrayElement = (PFNGLARRAYELEMENTPROC)load("glArrayElement"); glad_glColorPointer = (PFNGLCOLORPOINTERPROC)load("glColorPointer"); glad_glDisableClientState = (PFNGLDISABLECLIENTSTATEPROC)load("glDisableClientState"); glad_glEdgeFlagPointer = (PFNGLEDGEFLAGPOINTERPROC)load("glEdgeFlagPointer"); glad_glEnableClientState = (PFNGLENABLECLIENTSTATEPROC)load("glEnableClientState"); glad_glIndexPointer = (PFNGLINDEXPOINTERPROC)load("glIndexPointer"); glad_glInterleavedArrays = (PFNGLINTERLEAVEDARRAYSPROC)load("glInterleavedArrays"); glad_glNormalPointer = (PFNGLNORMALPOINTERPROC)load("glNormalPointer"); glad_glTexCoordPointer = (PFNGLTEXCOORDPOINTERPROC)load("glTexCoordPointer"); glad_glVertexPointer = (PFNGLVERTEXPOINTERPROC)load("glVertexPointer"); glad_glAreTexturesResident = (PFNGLARETEXTURESRESIDENTPROC)load("glAreTexturesResident"); glad_glPrioritizeTextures = (PFNGLPRIORITIZETEXTURESPROC)load("glPrioritizeTextures"); glad_glIndexub = (PFNGLINDEXUBPROC)load("glIndexub"); glad_glIndexubv = (PFNGLINDEXUBVPROC)load("glIndexubv"); glad_glPopClientAttrib = (PFNGLPOPCLIENTATTRIBPROC)load("glPopClientAttrib"); glad_glPushClientAttrib = (PFNGLPUSHCLIENTATTRIBPROC)load("glPushClientAttrib"); } static void load_GL_VERSION_1_2(GLADloadproc load) { if(!GLAD_GL_VERSION_1_2) return; glad_glDrawRangeElements = (PFNGLDRAWRANGEELEMENTSPROC)load("glDrawRangeElements"); glad_glTexImage3D = (PFNGLTEXIMAGE3DPROC)load("glTexImage3D"); glad_glTexSubImage3D = (PFNGLTEXSUBIMAGE3DPROC)load("glTexSubImage3D"); glad_glCopyTexSubImage3D = (PFNGLCOPYTEXSUBIMAGE3DPROC)load("glCopyTexSubImage3D"); } static void load_GL_VERSION_1_3(GLADloadproc load) { if(!GLAD_GL_VERSION_1_3) return; glad_glActiveTexture = (PFNGLACTIVETEXTUREPROC)load("glActiveTexture"); glad_glSampleCoverage = (PFNGLSAMPLECOVERAGEPROC)load("glSampleCoverage"); glad_glCompressedTexImage3D = (PFNGLCOMPRESSEDTEXIMAGE3DPROC)load("glCompressedTexImage3D"); glad_glCompressedTexImage2D = (PFNGLCOMPRESSEDTEXIMAGE2DPROC)load("glCompressedTexImage2D"); glad_glCompressedTexImage1D = (PFNGLCOMPRESSEDTEXIMAGE1DPROC)load("glCompressedTexImage1D"); glad_glCompressedTexSubImage3D = (PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC)load("glCompressedTexSubImage3D"); glad_glCompressedTexSubImage2D = (PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC)load("glCompressedTexSubImage2D"); glad_glCompressedTexSubImage1D = (PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC)load("glCompressedTexSubImage1D"); glad_glGetCompressedTexImage = (PFNGLGETCOMPRESSEDTEXIMAGEPROC)load("glGetCompressedTexImage"); glad_glClientActiveTexture = (PFNGLCLIENTACTIVETEXTUREPROC)load("glClientActiveTexture"); glad_glMultiTexCoord1d = (PFNGLMULTITEXCOORD1DPROC)load("glMultiTexCoord1d"); glad_glMultiTexCoord1dv = (PFNGLMULTITEXCOORD1DVPROC)load("glMultiTexCoord1dv"); glad_glMultiTexCoord1f = (PFNGLMULTITEXCOORD1FPROC)load("glMultiTexCoord1f"); glad_glMultiTexCoord1fv = (PFNGLMULTITEXCOORD1FVPROC)load("glMultiTexCoord1fv"); glad_glMultiTexCoord1i = (PFNGLMULTITEXCOORD1IPROC)load("glMultiTexCoord1i"); glad_glMultiTexCoord1iv = (PFNGLMULTITEXCOORD1IVPROC)load("glMultiTexCoord1iv"); glad_glMultiTexCoord1s = (PFNGLMULTITEXCOORD1SPROC)load("glMultiTexCoord1s"); glad_glMultiTexCoord1sv = (PFNGLMULTITEXCOORD1SVPROC)load("glMultiTexCoord1sv"); glad_glMultiTexCoord2d = (PFNGLMULTITEXCOORD2DPROC)load("glMultiTexCoord2d"); glad_glMultiTexCoord2dv = (PFNGLMULTITEXCOORD2DVPROC)load("glMultiTexCoord2dv"); glad_glMultiTexCoord2f = (PFNGLMULTITEXCOORD2FPROC)load("glMultiTexCoord2f"); glad_glMultiTexCoord2fv = (PFNGLMULTITEXCOORD2FVPROC)load("glMultiTexCoord2fv"); glad_glMultiTexCoord2i = (PFNGLMULTITEXCOORD2IPROC)load("glMultiTexCoord2i"); glad_glMultiTexCoord2iv = (PFNGLMULTITEXCOORD2IVPROC)load("glMultiTexCoord2iv"); glad_glMultiTexCoord2s = (PFNGLMULTITEXCOORD2SPROC)load("glMultiTexCoord2s"); glad_glMultiTexCoord2sv = (PFNGLMULTITEXCOORD2SVPROC)load("glMultiTexCoord2sv"); glad_glMultiTexCoord3d = (PFNGLMULTITEXCOORD3DPROC)load("glMultiTexCoord3d"); glad_glMultiTexCoord3dv = (PFNGLMULTITEXCOORD3DVPROC)load("glMultiTexCoord3dv"); glad_glMultiTexCoord3f = (PFNGLMULTITEXCOORD3FPROC)load("glMultiTexCoord3f"); glad_glMultiTexCoord3fv = (PFNGLMULTITEXCOORD3FVPROC)load("glMultiTexCoord3fv"); glad_glMultiTexCoord3i = (PFNGLMULTITEXCOORD3IPROC)load("glMultiTexCoord3i"); glad_glMultiTexCoord3iv = (PFNGLMULTITEXCOORD3IVPROC)load("glMultiTexCoord3iv"); glad_glMultiTexCoord3s = (PFNGLMULTITEXCOORD3SPROC)load("glMultiTexCoord3s"); glad_glMultiTexCoord3sv = (PFNGLMULTITEXCOORD3SVPROC)load("glMultiTexCoord3sv"); glad_glMultiTexCoord4d = (PFNGLMULTITEXCOORD4DPROC)load("glMultiTexCoord4d"); glad_glMultiTexCoord4dv = (PFNGLMULTITEXCOORD4DVPROC)load("glMultiTexCoord4dv"); glad_glMultiTexCoord4f = (PFNGLMULTITEXCOORD4FPROC)load("glMultiTexCoord4f"); glad_glMultiTexCoord4fv = (PFNGLMULTITEXCOORD4FVPROC)load("glMultiTexCoord4fv"); glad_glMultiTexCoord4i = (PFNGLMULTITEXCOORD4IPROC)load("glMultiTexCoord4i"); glad_glMultiTexCoord4iv = (PFNGLMULTITEXCOORD4IVPROC)load("glMultiTexCoord4iv"); glad_glMultiTexCoord4s = (PFNGLMULTITEXCOORD4SPROC)load("glMultiTexCoord4s"); glad_glMultiTexCoord4sv = (PFNGLMULTITEXCOORD4SVPROC)load("glMultiTexCoord4sv"); glad_glLoadTransposeMatrixf = (PFNGLLOADTRANSPOSEMATRIXFPROC)load("glLoadTransposeMatrixf"); glad_glLoadTransposeMatrixd = (PFNGLLOADTRANSPOSEMATRIXDPROC)load("glLoadTransposeMatrixd"); glad_glMultTransposeMatrixf = (PFNGLMULTTRANSPOSEMATRIXFPROC)load("glMultTransposeMatrixf"); glad_glMultTransposeMatrixd = (PFNGLMULTTRANSPOSEMATRIXDPROC)load("glMultTransposeMatrixd"); } static void load_GL_VERSION_1_4(GLADloadproc load) { if(!GLAD_GL_VERSION_1_4) return; glad_glBlendFuncSeparate = (PFNGLBLENDFUNCSEPARATEPROC)load("glBlendFuncSeparate"); glad_glMultiDrawArrays = (PFNGLMULTIDRAWARRAYSPROC)load("glMultiDrawArrays"); glad_glMultiDrawElements = (PFNGLMULTIDRAWELEMENTSPROC)load("glMultiDrawElements"); glad_glPointParameterf = (PFNGLPOINTPARAMETERFPROC)load("glPointParameterf"); glad_glPointParameterfv = (PFNGLPOINTPARAMETERFVPROC)load("glPointParameterfv"); glad_glPointParameteri = (PFNGLPOINTPARAMETERIPROC)load("glPointParameteri"); glad_glPointParameteriv = (PFNGLPOINTPARAMETERIVPROC)load("glPointParameteriv"); glad_glFogCoordf = (PFNGLFOGCOORDFPROC)load("glFogCoordf"); glad_glFogCoordfv = (PFNGLFOGCOORDFVPROC)load("glFogCoordfv"); glad_glFogCoordd = (PFNGLFOGCOORDDPROC)load("glFogCoordd"); glad_glFogCoorddv = (PFNGLFOGCOORDDVPROC)load("glFogCoorddv"); glad_glFogCoordPointer = (PFNGLFOGCOORDPOINTERPROC)load("glFogCoordPointer"); glad_glSecondaryColor3b = (PFNGLSECONDARYCOLOR3BPROC)load("glSecondaryColor3b"); glad_glSecondaryColor3bv = (PFNGLSECONDARYCOLOR3BVPROC)load("glSecondaryColor3bv"); glad_glSecondaryColor3d = (PFNGLSECONDARYCOLOR3DPROC)load("glSecondaryColor3d"); glad_glSecondaryColor3dv = (PFNGLSECONDARYCOLOR3DVPROC)load("glSecondaryColor3dv"); glad_glSecondaryColor3f = (PFNGLSECONDARYCOLOR3FPROC)load("glSecondaryColor3f"); glad_glSecondaryColor3fv = (PFNGLSECONDARYCOLOR3FVPROC)load("glSecondaryColor3fv"); glad_glSecondaryColor3i = (PFNGLSECONDARYCOLOR3IPROC)load("glSecondaryColor3i"); glad_glSecondaryColor3iv = (PFNGLSECONDARYCOLOR3IVPROC)load("glSecondaryColor3iv"); glad_glSecondaryColor3s = (PFNGLSECONDARYCOLOR3SPROC)load("glSecondaryColor3s"); glad_glSecondaryColor3sv = (PFNGLSECONDARYCOLOR3SVPROC)load("glSecondaryColor3sv"); glad_glSecondaryColor3ub = (PFNGLSECONDARYCOLOR3UBPROC)load("glSecondaryColor3ub"); glad_glSecondaryColor3ubv = (PFNGLSECONDARYCOLOR3UBVPROC)load("glSecondaryColor3ubv"); glad_glSecondaryColor3ui = (PFNGLSECONDARYCOLOR3UIPROC)load("glSecondaryColor3ui"); glad_glSecondaryColor3uiv = (PFNGLSECONDARYCOLOR3UIVPROC)load("glSecondaryColor3uiv"); glad_glSecondaryColor3us = (PFNGLSECONDARYCOLOR3USPROC)load("glSecondaryColor3us"); glad_glSecondaryColor3usv = (PFNGLSECONDARYCOLOR3USVPROC)load("glSecondaryColor3usv"); glad_glSecondaryColorPointer = (PFNGLSECONDARYCOLORPOINTERPROC)load("glSecondaryColorPointer"); glad_glWindowPos2d = (PFNGLWINDOWPOS2DPROC)load("glWindowPos2d"); glad_glWindowPos2dv = (PFNGLWINDOWPOS2DVPROC)load("glWindowPos2dv"); glad_glWindowPos2f = (PFNGLWINDOWPOS2FPROC)load("glWindowPos2f"); glad_glWindowPos2fv = (PFNGLWINDOWPOS2FVPROC)load("glWindowPos2fv"); glad_glWindowPos2i = (PFNGLWINDOWPOS2IPROC)load("glWindowPos2i"); glad_glWindowPos2iv = (PFNGLWINDOWPOS2IVPROC)load("glWindowPos2iv"); glad_glWindowPos2s = (PFNGLWINDOWPOS2SPROC)load("glWindowPos2s"); glad_glWindowPos2sv = (PFNGLWINDOWPOS2SVPROC)load("glWindowPos2sv"); glad_glWindowPos3d = (PFNGLWINDOWPOS3DPROC)load("glWindowPos3d"); glad_glWindowPos3dv = (PFNGLWINDOWPOS3DVPROC)load("glWindowPos3dv"); glad_glWindowPos3f = (PFNGLWINDOWPOS3FPROC)load("glWindowPos3f"); glad_glWindowPos3fv = (PFNGLWINDOWPOS3FVPROC)load("glWindowPos3fv"); glad_glWindowPos3i = (PFNGLWINDOWPOS3IPROC)load("glWindowPos3i"); glad_glWindowPos3iv = (PFNGLWINDOWPOS3IVPROC)load("glWindowPos3iv"); glad_glWindowPos3s = (PFNGLWINDOWPOS3SPROC)load("glWindowPos3s"); glad_glWindowPos3sv = (PFNGLWINDOWPOS3SVPROC)load("glWindowPos3sv"); glad_glBlendColor = (PFNGLBLENDCOLORPROC)load("glBlendColor"); glad_glBlendEquation = (PFNGLBLENDEQUATIONPROC)load("glBlendEquation"); } static void load_GL_VERSION_1_5(GLADloadproc load) { if(!GLAD_GL_VERSION_1_5) return; glad_glGenQueries = (PFNGLGENQUERIESPROC)load("glGenQueries"); glad_glDeleteQueries = (PFNGLDELETEQUERIESPROC)load("glDeleteQueries"); glad_glIsQuery = (PFNGLISQUERYPROC)load("glIsQuery"); glad_glBeginQuery = (PFNGLBEGINQUERYPROC)load("glBeginQuery"); glad_glEndQuery = (PFNGLENDQUERYPROC)load("glEndQuery"); glad_glGetQueryiv = (PFNGLGETQUERYIVPROC)load("glGetQueryiv"); glad_glGetQueryObjectiv = (PFNGLGETQUERYOBJECTIVPROC)load("glGetQueryObjectiv"); glad_glGetQueryObjectuiv = (PFNGLGETQUERYOBJECTUIVPROC)load("glGetQueryObjectuiv"); glad_glBindBuffer = (PFNGLBINDBUFFERPROC)load("glBindBuffer"); glad_glDeleteBuffers = (PFNGLDELETEBUFFERSPROC)load("glDeleteBuffers"); glad_glGenBuffers = (PFNGLGENBUFFERSPROC)load("glGenBuffers"); glad_glIsBuffer = (PFNGLISBUFFERPROC)load("glIsBuffer"); glad_glBufferData = (PFNGLBUFFERDATAPROC)load("glBufferData"); glad_glBufferSubData = (PFNGLBUFFERSUBDATAPROC)load("glBufferSubData"); glad_glGetBufferSubData = (PFNGLGETBUFFERSUBDATAPROC)load("glGetBufferSubData"); glad_glMapBuffer = (PFNGLMAPBUFFERPROC)load("glMapBuffer"); glad_glUnmapBuffer = (PFNGLUNMAPBUFFERPROC)load("glUnmapBuffer"); glad_glGetBufferParameteriv = (PFNGLGETBUFFERPARAMETERIVPROC)load("glGetBufferParameteriv"); glad_glGetBufferPointerv = (PFNGLGETBUFFERPOINTERVPROC)load("glGetBufferPointerv"); } static void load_GL_VERSION_2_0(GLADloadproc load) { if(!GLAD_GL_VERSION_2_0) return; glad_glBlendEquationSeparate = (PFNGLBLENDEQUATIONSEPARATEPROC)load("glBlendEquationSeparate"); glad_glDrawBuffers = (PFNGLDRAWBUFFERSPROC)load("glDrawBuffers"); glad_glStencilOpSeparate = (PFNGLSTENCILOPSEPARATEPROC)load("glStencilOpSeparate"); glad_glStencilFuncSeparate = (PFNGLSTENCILFUNCSEPARATEPROC)load("glStencilFuncSeparate"); glad_glStencilMaskSeparate = (PFNGLSTENCILMASKSEPARATEPROC)load("glStencilMaskSeparate"); glad_glAttachShader = (PFNGLATTACHSHADERPROC)load("glAttachShader"); glad_glBindAttribLocation = (PFNGLBINDATTRIBLOCATIONPROC)load("glBindAttribLocation"); glad_glCompileShader = (PFNGLCOMPILESHADERPROC)load("glCompileShader"); glad_glCreateProgram = (PFNGLCREATEPROGRAMPROC)load("glCreateProgram"); glad_glCreateShader = (PFNGLCREATESHADERPROC)load("glCreateShader"); glad_glDeleteProgram = (PFNGLDELETEPROGRAMPROC)load("glDeleteProgram"); glad_glDeleteShader = (PFNGLDELETESHADERPROC)load("glDeleteShader"); glad_glDetachShader = (PFNGLDETACHSHADERPROC)load("glDetachShader"); glad_glDisableVertexAttribArray = (PFNGLDISABLEVERTEXATTRIBARRAYPROC)load("glDisableVertexAttribArray"); glad_glEnableVertexAttribArray = (PFNGLENABLEVERTEXATTRIBARRAYPROC)load("glEnableVertexAttribArray"); glad_glGetActiveAttrib = (PFNGLGETACTIVEATTRIBPROC)load("glGetActiveAttrib"); glad_glGetActiveUniform = (PFNGLGETACTIVEUNIFORMPROC)load("glGetActiveUniform"); glad_glGetAttachedShaders = (PFNGLGETATTACHEDSHADERSPROC)load("glGetAttachedShaders"); glad_glGetAttribLocation = (PFNGLGETATTRIBLOCATIONPROC)load("glGetAttribLocation"); glad_glGetProgramiv = (PFNGLGETPROGRAMIVPROC)load("glGetProgramiv"); glad_glGetProgramInfoLog = (PFNGLGETPROGRAMINFOLOGPROC)load("glGetProgramInfoLog"); glad_glGetShaderiv = (PFNGLGETSHADERIVPROC)load("glGetShaderiv"); glad_glGetShaderInfoLog = (PFNGLGETSHADERINFOLOGPROC)load("glGetShaderInfoLog"); glad_glGetShaderSource = (PFNGLGETSHADERSOURCEPROC)load("glGetShaderSource"); glad_glGetUniformLocation = (PFNGLGETUNIFORMLOCATIONPROC)load("glGetUniformLocation"); glad_glGetUniformfv = (PFNGLGETUNIFORMFVPROC)load("glGetUniformfv"); glad_glGetUniformiv = (PFNGLGETUNIFORMIVPROC)load("glGetUniformiv"); glad_glGetVertexAttribdv = (PFNGLGETVERTEXATTRIBDVPROC)load("glGetVertexAttribdv"); glad_glGetVertexAttribfv = (PFNGLGETVERTEXATTRIBFVPROC)load("glGetVertexAttribfv"); glad_glGetVertexAttribiv = (PFNGLGETVERTEXATTRIBIVPROC)load("glGetVertexAttribiv"); glad_glGetVertexAttribPointerv = (PFNGLGETVERTEXATTRIBPOINTERVPROC)load("glGetVertexAttribPointerv"); glad_glIsProgram = (PFNGLISPROGRAMPROC)load("glIsProgram"); glad_glIsShader = (PFNGLISSHADERPROC)load("glIsShader"); glad_glLinkProgram = (PFNGLLINKPROGRAMPROC)load("glLinkProgram"); glad_glShaderSource = (PFNGLSHADERSOURCEPROC)load("glShaderSource"); glad_glUseProgram = (PFNGLUSEPROGRAMPROC)load("glUseProgram"); glad_glUniform1f = (PFNGLUNIFORM1FPROC)load("glUniform1f"); glad_glUniform2f = (PFNGLUNIFORM2FPROC)load("glUniform2f"); glad_glUniform3f = (PFNGLUNIFORM3FPROC)load("glUniform3f"); glad_glUniform4f = (PFNGLUNIFORM4FPROC)load("glUniform4f"); glad_glUniform1i = (PFNGLUNIFORM1IPROC)load("glUniform1i"); glad_glUniform2i = (PFNGLUNIFORM2IPROC)load("glUniform2i"); glad_glUniform3i = (PFNGLUNIFORM3IPROC)load("glUniform3i"); glad_glUniform4i = (PFNGLUNIFORM4IPROC)load("glUniform4i"); glad_glUniform1fv = (PFNGLUNIFORM1FVPROC)load("glUniform1fv"); glad_glUniform2fv = (PFNGLUNIFORM2FVPROC)load("glUniform2fv"); glad_glUniform3fv = (PFNGLUNIFORM3FVPROC)load("glUniform3fv"); glad_glUniform4fv = (PFNGLUNIFORM4FVPROC)load("glUniform4fv"); glad_glUniform1iv = (PFNGLUNIFORM1IVPROC)load("glUniform1iv"); glad_glUniform2iv = (PFNGLUNIFORM2IVPROC)load("glUniform2iv"); glad_glUniform3iv = (PFNGLUNIFORM3IVPROC)load("glUniform3iv"); glad_glUniform4iv = (PFNGLUNIFORM4IVPROC)load("glUniform4iv"); glad_glUniformMatrix2fv = (PFNGLUNIFORMMATRIX2FVPROC)load("glUniformMatrix2fv"); glad_glUniformMatrix3fv = (PFNGLUNIFORMMATRIX3FVPROC)load("glUniformMatrix3fv"); glad_glUniformMatrix4fv = (PFNGLUNIFORMMATRIX4FVPROC)load("glUniformMatrix4fv"); glad_glValidateProgram = (PFNGLVALIDATEPROGRAMPROC)load("glValidateProgram"); glad_glVertexAttrib1d = (PFNGLVERTEXATTRIB1DPROC)load("glVertexAttrib1d"); glad_glVertexAttrib1dv = (PFNGLVERTEXATTRIB1DVPROC)load("glVertexAttrib1dv"); glad_glVertexAttrib1f = (PFNGLVERTEXATTRIB1FPROC)load("glVertexAttrib1f"); glad_glVertexAttrib1fv = (PFNGLVERTEXATTRIB1FVPROC)load("glVertexAttrib1fv"); glad_glVertexAttrib1s = (PFNGLVERTEXATTRIB1SPROC)load("glVertexAttrib1s"); glad_glVertexAttrib1sv = (PFNGLVERTEXATTRIB1SVPROC)load("glVertexAttrib1sv"); glad_glVertexAttrib2d = (PFNGLVERTEXATTRIB2DPROC)load("glVertexAttrib2d"); glad_glVertexAttrib2dv = (PFNGLVERTEXATTRIB2DVPROC)load("glVertexAttrib2dv"); glad_glVertexAttrib2f = (PFNGLVERTEXATTRIB2FPROC)load("glVertexAttrib2f"); glad_glVertexAttrib2fv = (PFNGLVERTEXATTRIB2FVPROC)load("glVertexAttrib2fv"); glad_glVertexAttrib2s = (PFNGLVERTEXATTRIB2SPROC)load("glVertexAttrib2s"); glad_glVertexAttrib2sv = (PFNGLVERTEXATTRIB2SVPROC)load("glVertexAttrib2sv"); glad_glVertexAttrib3d = (PFNGLVERTEXATTRIB3DPROC)load("glVertexAttrib3d"); glad_glVertexAttrib3dv = (PFNGLVERTEXATTRIB3DVPROC)load("glVertexAttrib3dv"); glad_glVertexAttrib3f = (PFNGLVERTEXATTRIB3FPROC)load("glVertexAttrib3f"); glad_glVertexAttrib3fv = (PFNGLVERTEXATTRIB3FVPROC)load("glVertexAttrib3fv"); glad_glVertexAttrib3s = (PFNGLVERTEXATTRIB3SPROC)load("glVertexAttrib3s"); glad_glVertexAttrib3sv = (PFNGLVERTEXATTRIB3SVPROC)load("glVertexAttrib3sv"); glad_glVertexAttrib4Nbv = (PFNGLVERTEXATTRIB4NBVPROC)load("glVertexAttrib4Nbv"); glad_glVertexAttrib4Niv = (PFNGLVERTEXATTRIB4NIVPROC)load("glVertexAttrib4Niv"); glad_glVertexAttrib4Nsv = (PFNGLVERTEXATTRIB4NSVPROC)load("glVertexAttrib4Nsv"); glad_glVertexAttrib4Nub = (PFNGLVERTEXATTRIB4NUBPROC)load("glVertexAttrib4Nub"); glad_glVertexAttrib4Nubv = (PFNGLVERTEXATTRIB4NUBVPROC)load("glVertexAttrib4Nubv"); glad_glVertexAttrib4Nuiv = (PFNGLVERTEXATTRIB4NUIVPROC)load("glVertexAttrib4Nuiv"); glad_glVertexAttrib4Nusv = (PFNGLVERTEXATTRIB4NUSVPROC)load("glVertexAttrib4Nusv"); glad_glVertexAttrib4bv = (PFNGLVERTEXATTRIB4BVPROC)load("glVertexAttrib4bv"); glad_glVertexAttrib4d = (PFNGLVERTEXATTRIB4DPROC)load("glVertexAttrib4d"); glad_glVertexAttrib4dv = (PFNGLVERTEXATTRIB4DVPROC)load("glVertexAttrib4dv"); glad_glVertexAttrib4f = (PFNGLVERTEXATTRIB4FPROC)load("glVertexAttrib4f"); glad_glVertexAttrib4fv = (PFNGLVERTEXATTRIB4FVPROC)load("glVertexAttrib4fv"); glad_glVertexAttrib4iv = (PFNGLVERTEXATTRIB4IVPROC)load("glVertexAttrib4iv"); glad_glVertexAttrib4s = (PFNGLVERTEXATTRIB4SPROC)load("glVertexAttrib4s"); glad_glVertexAttrib4sv = (PFNGLVERTEXATTRIB4SVPROC)load("glVertexAttrib4sv"); glad_glVertexAttrib4ubv = (PFNGLVERTEXATTRIB4UBVPROC)load("glVertexAttrib4ubv"); glad_glVertexAttrib4uiv = (PFNGLVERTEXATTRIB4UIVPROC)load("glVertexAttrib4uiv"); glad_glVertexAttrib4usv = (PFNGLVERTEXATTRIB4USVPROC)load("glVertexAttrib4usv"); glad_glVertexAttribPointer = (PFNGLVERTEXATTRIBPOINTERPROC)load("glVertexAttribPointer"); } static void load_GL_VERSION_2_1(GLADloadproc load) { if(!GLAD_GL_VERSION_2_1) return; glad_glUniformMatrix2x3fv = (PFNGLUNIFORMMATRIX2X3FVPROC)load("glUniformMatrix2x3fv"); glad_glUniformMatrix3x2fv = (PFNGLUNIFORMMATRIX3X2FVPROC)load("glUniformMatrix3x2fv"); glad_glUniformMatrix2x4fv = (PFNGLUNIFORMMATRIX2X4FVPROC)load("glUniformMatrix2x4fv"); glad_glUniformMatrix4x2fv = (PFNGLUNIFORMMATRIX4X2FVPROC)load("glUniformMatrix4x2fv"); glad_glUniformMatrix3x4fv = (PFNGLUNIFORMMATRIX3X4FVPROC)load("glUniformMatrix3x4fv"); glad_glUniformMatrix4x3fv = (PFNGLUNIFORMMATRIX4X3FVPROC)load("glUniformMatrix4x3fv"); } static void load_GL_VERSION_3_0(GLADloadproc load) { if(!GLAD_GL_VERSION_3_0) return; glad_glColorMaski = (PFNGLCOLORMASKIPROC)load("glColorMaski"); glad_glGetBooleani_v = (PFNGLGETBOOLEANI_VPROC)load("glGetBooleani_v"); glad_glGetIntegeri_v = (PFNGLGETINTEGERI_VPROC)load("glGetIntegeri_v"); glad_glEnablei = (PFNGLENABLEIPROC)load("glEnablei"); glad_glDisablei = (PFNGLDISABLEIPROC)load("glDisablei"); glad_glIsEnabledi = (PFNGLISENABLEDIPROC)load("glIsEnabledi"); glad_glBeginTransformFeedback = (PFNGLBEGINTRANSFORMFEEDBACKPROC)load("glBeginTransformFeedback"); glad_glEndTransformFeedback = (PFNGLENDTRANSFORMFEEDBACKPROC)load("glEndTransformFeedback"); glad_glBindBufferRange = (PFNGLBINDBUFFERRANGEPROC)load("glBindBufferRange"); glad_glBindBufferBase = (PFNGLBINDBUFFERBASEPROC)load("glBindBufferBase"); glad_glTransformFeedbackVaryings = (PFNGLTRANSFORMFEEDBACKVARYINGSPROC)load("glTransformFeedbackVaryings"); glad_glGetTransformFeedbackVarying = (PFNGLGETTRANSFORMFEEDBACKVARYINGPROC)load("glGetTransformFeedbackVarying"); glad_glClampColor = (PFNGLCLAMPCOLORPROC)load("glClampColor"); glad_glBeginConditionalRender = (PFNGLBEGINCONDITIONALRENDERPROC)load("glBeginConditionalRender"); glad_glEndConditionalRender = (PFNGLENDCONDITIONALRENDERPROC)load("glEndConditionalRender"); glad_glVertexAttribIPointer = (PFNGLVERTEXATTRIBIPOINTERPROC)load("glVertexAttribIPointer"); glad_glGetVertexAttribIiv = (PFNGLGETVERTEXATTRIBIIVPROC)load("glGetVertexAttribIiv"); glad_glGetVertexAttribIuiv = (PFNGLGETVERTEXATTRIBIUIVPROC)load("glGetVertexAttribIuiv"); glad_glVertexAttribI1i = (PFNGLVERTEXATTRIBI1IPROC)load("glVertexAttribI1i"); glad_glVertexAttribI2i = (PFNGLVERTEXATTRIBI2IPROC)load("glVertexAttribI2i"); glad_glVertexAttribI3i = (PFNGLVERTEXATTRIBI3IPROC)load("glVertexAttribI3i"); glad_glVertexAttribI4i = (PFNGLVERTEXATTRIBI4IPROC)load("glVertexAttribI4i"); glad_glVertexAttribI1ui = (PFNGLVERTEXATTRIBI1UIPROC)load("glVertexAttribI1ui"); glad_glVertexAttribI2ui = (PFNGLVERTEXATTRIBI2UIPROC)load("glVertexAttribI2ui"); glad_glVertexAttribI3ui = (PFNGLVERTEXATTRIBI3UIPROC)load("glVertexAttribI3ui"); glad_glVertexAttribI4ui = (PFNGLVERTEXATTRIBI4UIPROC)load("glVertexAttribI4ui"); glad_glVertexAttribI1iv = (PFNGLVERTEXATTRIBI1IVPROC)load("glVertexAttribI1iv"); glad_glVertexAttribI2iv = (PFNGLVERTEXATTRIBI2IVPROC)load("glVertexAttribI2iv"); glad_glVertexAttribI3iv = (PFNGLVERTEXATTRIBI3IVPROC)load("glVertexAttribI3iv"); glad_glVertexAttribI4iv = (PFNGLVERTEXATTRIBI4IVPROC)load("glVertexAttribI4iv"); glad_glVertexAttribI1uiv = (PFNGLVERTEXATTRIBI1UIVPROC)load("glVertexAttribI1uiv"); glad_glVertexAttribI2uiv = (PFNGLVERTEXATTRIBI2UIVPROC)load("glVertexAttribI2uiv"); glad_glVertexAttribI3uiv = (PFNGLVERTEXATTRIBI3UIVPROC)load("glVertexAttribI3uiv"); glad_glVertexAttribI4uiv = (PFNGLVERTEXATTRIBI4UIVPROC)load("glVertexAttribI4uiv"); glad_glVertexAttribI4bv = (PFNGLVERTEXATTRIBI4BVPROC)load("glVertexAttribI4bv"); glad_glVertexAttribI4sv = (PFNGLVERTEXATTRIBI4SVPROC)load("glVertexAttribI4sv"); glad_glVertexAttribI4ubv = (PFNGLVERTEXATTRIBI4UBVPROC)load("glVertexAttribI4ubv"); glad_glVertexAttribI4usv = (PFNGLVERTEXATTRIBI4USVPROC)load("glVertexAttribI4usv"); glad_glGetUniformuiv = (PFNGLGETUNIFORMUIVPROC)load("glGetUniformuiv"); glad_glBindFragDataLocation = (PFNGLBINDFRAGDATALOCATIONPROC)load("glBindFragDataLocation"); glad_glGetFragDataLocation = (PFNGLGETFRAGDATALOCATIONPROC)load("glGetFragDataLocation"); glad_glUniform1ui = (PFNGLUNIFORM1UIPROC)load("glUniform1ui"); glad_glUniform2ui = (PFNGLUNIFORM2UIPROC)load("glUniform2ui"); glad_glUniform3ui = (PFNGLUNIFORM3UIPROC)load("glUniform3ui"); glad_glUniform4ui = (PFNGLUNIFORM4UIPROC)load("glUniform4ui"); glad_glUniform1uiv = (PFNGLUNIFORM1UIVPROC)load("glUniform1uiv"); glad_glUniform2uiv = (PFNGLUNIFORM2UIVPROC)load("glUniform2uiv"); glad_glUniform3uiv = (PFNGLUNIFORM3UIVPROC)load("glUniform3uiv"); glad_glUniform4uiv = (PFNGLUNIFORM4UIVPROC)load("glUniform4uiv"); glad_glTexParameterIiv = (PFNGLTEXPARAMETERIIVPROC)load("glTexParameterIiv"); glad_glTexParameterIuiv = (PFNGLTEXPARAMETERIUIVPROC)load("glTexParameterIuiv"); glad_glGetTexParameterIiv = (PFNGLGETTEXPARAMETERIIVPROC)load("glGetTexParameterIiv"); glad_glGetTexParameterIuiv = (PFNGLGETTEXPARAMETERIUIVPROC)load("glGetTexParameterIuiv"); glad_glClearBufferiv = (PFNGLCLEARBUFFERIVPROC)load("glClearBufferiv"); glad_glClearBufferuiv = (PFNGLCLEARBUFFERUIVPROC)load("glClearBufferuiv"); glad_glClearBufferfv = (PFNGLCLEARBUFFERFVPROC)load("glClearBufferfv"); glad_glClearBufferfi = (PFNGLCLEARBUFFERFIPROC)load("glClearBufferfi"); glad_glGetStringi = (PFNGLGETSTRINGIPROC)load("glGetStringi"); glad_glIsRenderbuffer = (PFNGLISRENDERBUFFERPROC)load("glIsRenderbuffer"); glad_glBindRenderbuffer = (PFNGLBINDRENDERBUFFERPROC)load("glBindRenderbuffer"); glad_glDeleteRenderbuffers = (PFNGLDELETERENDERBUFFERSPROC)load("glDeleteRenderbuffers"); glad_glGenRenderbuffers = (PFNGLGENRENDERBUFFERSPROC)load("glGenRenderbuffers"); glad_glRenderbufferStorage = (PFNGLRENDERBUFFERSTORAGEPROC)load("glRenderbufferStorage"); glad_glGetRenderbufferParameteriv = (PFNGLGETRENDERBUFFERPARAMETERIVPROC)load("glGetRenderbufferParameteriv"); glad_glIsFramebuffer = (PFNGLISFRAMEBUFFERPROC)load("glIsFramebuffer"); glad_glBindFramebuffer = (PFNGLBINDFRAMEBUFFERPROC)load("glBindFramebuffer"); glad_glDeleteFramebuffers = (PFNGLDELETEFRAMEBUFFERSPROC)load("glDeleteFramebuffers"); glad_glGenFramebuffers = (PFNGLGENFRAMEBUFFERSPROC)load("glGenFramebuffers"); glad_glCheckFramebufferStatus = (PFNGLCHECKFRAMEBUFFERSTATUSPROC)load("glCheckFramebufferStatus"); glad_glFramebufferTexture1D = (PFNGLFRAMEBUFFERTEXTURE1DPROC)load("glFramebufferTexture1D"); glad_glFramebufferTexture2D = (PFNGLFRAMEBUFFERTEXTURE2DPROC)load("glFramebufferTexture2D"); glad_glFramebufferTexture3D = (PFNGLFRAMEBUFFERTEXTURE3DPROC)load("glFramebufferTexture3D"); glad_glFramebufferRenderbuffer = (PFNGLFRAMEBUFFERRENDERBUFFERPROC)load("glFramebufferRenderbuffer"); glad_glGetFramebufferAttachmentParameteriv = (PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC)load("glGetFramebufferAttachmentParameteriv"); glad_glGenerateMipmap = (PFNGLGENERATEMIPMAPPROC)load("glGenerateMipmap"); glad_glBlitFramebuffer = (PFNGLBLITFRAMEBUFFERPROC)load("glBlitFramebuffer"); glad_glRenderbufferStorageMultisample = (PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC)load("glRenderbufferStorageMultisample"); glad_glFramebufferTextureLayer = (PFNGLFRAMEBUFFERTEXTURELAYERPROC)load("glFramebufferTextureLayer"); glad_glMapBufferRange = (PFNGLMAPBUFFERRANGEPROC)load("glMapBufferRange"); glad_glFlushMappedBufferRange = (PFNGLFLUSHMAPPEDBUFFERRANGEPROC)load("glFlushMappedBufferRange"); glad_glBindVertexArray = (PFNGLBINDVERTEXARRAYPROC)load("glBindVertexArray"); glad_glDeleteVertexArrays = (PFNGLDELETEVERTEXARRAYSPROC)load("glDeleteVertexArrays"); glad_glGenVertexArrays = (PFNGLGENVERTEXARRAYSPROC)load("glGenVertexArrays"); glad_glIsVertexArray = (PFNGLISVERTEXARRAYPROC)load("glIsVertexArray"); } static void load_GL_VERSION_3_1(GLADloadproc load) { if(!GLAD_GL_VERSION_3_1) return; glad_glDrawArraysInstanced = (PFNGLDRAWARRAYSINSTANCEDPROC)load("glDrawArraysInstanced"); glad_glDrawElementsInstanced = (PFNGLDRAWELEMENTSINSTANCEDPROC)load("glDrawElementsInstanced"); glad_glTexBuffer = (PFNGLTEXBUFFERPROC)load("glTexBuffer"); glad_glPrimitiveRestartIndex = (PFNGLPRIMITIVERESTARTINDEXPROC)load("glPrimitiveRestartIndex"); glad_glCopyBufferSubData = (PFNGLCOPYBUFFERSUBDATAPROC)load("glCopyBufferSubData"); glad_glGetUniformIndices = (PFNGLGETUNIFORMINDICESPROC)load("glGetUniformIndices"); glad_glGetActiveUniformsiv = (PFNGLGETACTIVEUNIFORMSIVPROC)load("glGetActiveUniformsiv"); glad_glGetActiveUniformName = (PFNGLGETACTIVEUNIFORMNAMEPROC)load("glGetActiveUniformName"); glad_glGetUniformBlockIndex = (PFNGLGETUNIFORMBLOCKINDEXPROC)load("glGetUniformBlockIndex"); glad_glGetActiveUniformBlockiv = (PFNGLGETACTIVEUNIFORMBLOCKIVPROC)load("glGetActiveUniformBlockiv"); glad_glGetActiveUniformBlockName = (PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC)load("glGetActiveUniformBlockName"); glad_glUniformBlockBinding = (PFNGLUNIFORMBLOCKBINDINGPROC)load("glUniformBlockBinding"); glad_glBindBufferRange = (PFNGLBINDBUFFERRANGEPROC)load("glBindBufferRange"); glad_glBindBufferBase = (PFNGLBINDBUFFERBASEPROC)load("glBindBufferBase"); glad_glGetIntegeri_v = (PFNGLGETINTEGERI_VPROC)load("glGetIntegeri_v"); } static void load_GL_VERSION_3_2(GLADloadproc load) { if(!GLAD_GL_VERSION_3_2) return; glad_glDrawElementsBaseVertex = (PFNGLDRAWELEMENTSBASEVERTEXPROC)load("glDrawElementsBaseVertex"); glad_glDrawRangeElementsBaseVertex = (PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC)load("glDrawRangeElementsBaseVertex"); glad_glDrawElementsInstancedBaseVertex = (PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC)load("glDrawElementsInstancedBaseVertex"); glad_glMultiDrawElementsBaseVertex = (PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC)load("glMultiDrawElementsBaseVertex"); glad_glProvokingVertex = (PFNGLPROVOKINGVERTEXPROC)load("glProvokingVertex"); glad_glFenceSync = (PFNGLFENCESYNCPROC)load("glFenceSync"); glad_glIsSync = (PFNGLISSYNCPROC)load("glIsSync"); glad_glDeleteSync = (PFNGLDELETESYNCPROC)load("glDeleteSync"); glad_glClientWaitSync = (PFNGLCLIENTWAITSYNCPROC)load("glClientWaitSync"); glad_glWaitSync = (PFNGLWAITSYNCPROC)load("glWaitSync"); glad_glGetInteger64v = (PFNGLGETINTEGER64VPROC)load("glGetInteger64v"); glad_glGetSynciv = (PFNGLGETSYNCIVPROC)load("glGetSynciv"); glad_glGetInteger64i_v = (PFNGLGETINTEGER64I_VPROC)load("glGetInteger64i_v"); glad_glGetBufferParameteri64v = (PFNGLGETBUFFERPARAMETERI64VPROC)load("glGetBufferParameteri64v"); glad_glFramebufferTexture = (PFNGLFRAMEBUFFERTEXTUREPROC)load("glFramebufferTexture"); glad_glTexImage2DMultisample = (PFNGLTEXIMAGE2DMULTISAMPLEPROC)load("glTexImage2DMultisample"); glad_glTexImage3DMultisample = (PFNGLTEXIMAGE3DMULTISAMPLEPROC)load("glTexImage3DMultisample"); glad_glGetMultisamplefv = (PFNGLGETMULTISAMPLEFVPROC)load("glGetMultisamplefv"); glad_glSampleMaski = (PFNGLSAMPLEMASKIPROC)load("glSampleMaski"); } static void load_GL_VERSION_3_3(GLADloadproc load) { if(!GLAD_GL_VERSION_3_3) return; glad_glBindFragDataLocationIndexed = (PFNGLBINDFRAGDATALOCATIONINDEXEDPROC)load("glBindFragDataLocationIndexed"); glad_glGetFragDataIndex = (PFNGLGETFRAGDATAINDEXPROC)load("glGetFragDataIndex"); glad_glGenSamplers = (PFNGLGENSAMPLERSPROC)load("glGenSamplers"); glad_glDeleteSamplers = (PFNGLDELETESAMPLERSPROC)load("glDeleteSamplers"); glad_glIsSampler = (PFNGLISSAMPLERPROC)load("glIsSampler"); glad_glBindSampler = (PFNGLBINDSAMPLERPROC)load("glBindSampler"); glad_glSamplerParameteri = (PFNGLSAMPLERPARAMETERIPROC)load("glSamplerParameteri"); glad_glSamplerParameteriv = (PFNGLSAMPLERPARAMETERIVPROC)load("glSamplerParameteriv"); glad_glSamplerParameterf = (PFNGLSAMPLERPARAMETERFPROC)load("glSamplerParameterf"); glad_glSamplerParameterfv = (PFNGLSAMPLERPARAMETERFVPROC)load("glSamplerParameterfv"); glad_glSamplerParameterIiv = (PFNGLSAMPLERPARAMETERIIVPROC)load("glSamplerParameterIiv"); glad_glSamplerParameterIuiv = (PFNGLSAMPLERPARAMETERIUIVPROC)load("glSamplerParameterIuiv"); glad_glGetSamplerParameteriv = (PFNGLGETSAMPLERPARAMETERIVPROC)load("glGetSamplerParameteriv"); glad_glGetSamplerParameterIiv = (PFNGLGETSAMPLERPARAMETERIIVPROC)load("glGetSamplerParameterIiv"); glad_glGetSamplerParameterfv = (PFNGLGETSAMPLERPARAMETERFVPROC)load("glGetSamplerParameterfv"); glad_glGetSamplerParameterIuiv = (PFNGLGETSAMPLERPARAMETERIUIVPROC)load("glGetSamplerParameterIuiv"); glad_glQueryCounter = (PFNGLQUERYCOUNTERPROC)load("glQueryCounter"); glad_glGetQueryObjecti64v = (PFNGLGETQUERYOBJECTI64VPROC)load("glGetQueryObjecti64v"); glad_glGetQueryObjectui64v = (PFNGLGETQUERYOBJECTUI64VPROC)load("glGetQueryObjectui64v"); glad_glVertexAttribDivisor = (PFNGLVERTEXATTRIBDIVISORPROC)load("glVertexAttribDivisor"); glad_glVertexAttribP1ui = (PFNGLVERTEXATTRIBP1UIPROC)load("glVertexAttribP1ui"); glad_glVertexAttribP1uiv = (PFNGLVERTEXATTRIBP1UIVPROC)load("glVertexAttribP1uiv"); glad_glVertexAttribP2ui = (PFNGLVERTEXATTRIBP2UIPROC)load("glVertexAttribP2ui"); glad_glVertexAttribP2uiv = (PFNGLVERTEXATTRIBP2UIVPROC)load("glVertexAttribP2uiv"); glad_glVertexAttribP3ui = (PFNGLVERTEXATTRIBP3UIPROC)load("glVertexAttribP3ui"); glad_glVertexAttribP3uiv = (PFNGLVERTEXATTRIBP3UIVPROC)load("glVertexAttribP3uiv"); glad_glVertexAttribP4ui = (PFNGLVERTEXATTRIBP4UIPROC)load("glVertexAttribP4ui"); glad_glVertexAttribP4uiv = (PFNGLVERTEXATTRIBP4UIVPROC)load("glVertexAttribP4uiv"); glad_glVertexP2ui = (PFNGLVERTEXP2UIPROC)load("glVertexP2ui"); glad_glVertexP2uiv = (PFNGLVERTEXP2UIVPROC)load("glVertexP2uiv"); glad_glVertexP3ui = (PFNGLVERTEXP3UIPROC)load("glVertexP3ui"); glad_glVertexP3uiv = (PFNGLVERTEXP3UIVPROC)load("glVertexP3uiv"); glad_glVertexP4ui = (PFNGLVERTEXP4UIPROC)load("glVertexP4ui"); glad_glVertexP4uiv = (PFNGLVERTEXP4UIVPROC)load("glVertexP4uiv"); glad_glTexCoordP1ui = (PFNGLTEXCOORDP1UIPROC)load("glTexCoordP1ui"); glad_glTexCoordP1uiv = (PFNGLTEXCOORDP1UIVPROC)load("glTexCoordP1uiv"); glad_glTexCoordP2ui = (PFNGLTEXCOORDP2UIPROC)load("glTexCoordP2ui"); glad_glTexCoordP2uiv = (PFNGLTEXCOORDP2UIVPROC)load("glTexCoordP2uiv"); glad_glTexCoordP3ui = (PFNGLTEXCOORDP3UIPROC)load("glTexCoordP3ui"); glad_glTexCoordP3uiv = (PFNGLTEXCOORDP3UIVPROC)load("glTexCoordP3uiv"); glad_glTexCoordP4ui = (PFNGLTEXCOORDP4UIPROC)load("glTexCoordP4ui"); glad_glTexCoordP4uiv = (PFNGLTEXCOORDP4UIVPROC)load("glTexCoordP4uiv"); glad_glMultiTexCoordP1ui = (PFNGLMULTITEXCOORDP1UIPROC)load("glMultiTexCoordP1ui"); glad_glMultiTexCoordP1uiv = (PFNGLMULTITEXCOORDP1UIVPROC)load("glMultiTexCoordP1uiv"); glad_glMultiTexCoordP2ui = (PFNGLMULTITEXCOORDP2UIPROC)load("glMultiTexCoordP2ui"); glad_glMultiTexCoordP2uiv = (PFNGLMULTITEXCOORDP2UIVPROC)load("glMultiTexCoordP2uiv"); glad_glMultiTexCoordP3ui = (PFNGLMULTITEXCOORDP3UIPROC)load("glMultiTexCoordP3ui"); glad_glMultiTexCoordP3uiv = (PFNGLMULTITEXCOORDP3UIVPROC)load("glMultiTexCoordP3uiv"); glad_glMultiTexCoordP4ui = (PFNGLMULTITEXCOORDP4UIPROC)load("glMultiTexCoordP4ui"); glad_glMultiTexCoordP4uiv = (PFNGLMULTITEXCOORDP4UIVPROC)load("glMultiTexCoordP4uiv"); glad_glNormalP3ui = (PFNGLNORMALP3UIPROC)load("glNormalP3ui"); glad_glNormalP3uiv = (PFNGLNORMALP3UIVPROC)load("glNormalP3uiv"); glad_glColorP3ui = (PFNGLCOLORP3UIPROC)load("glColorP3ui"); glad_glColorP3uiv = (PFNGLCOLORP3UIVPROC)load("glColorP3uiv"); glad_glColorP4ui = (PFNGLCOLORP4UIPROC)load("glColorP4ui"); glad_glColorP4uiv = (PFNGLCOLORP4UIVPROC)load("glColorP4uiv"); glad_glSecondaryColorP3ui = (PFNGLSECONDARYCOLORP3UIPROC)load("glSecondaryColorP3ui"); glad_glSecondaryColorP3uiv = (PFNGLSECONDARYCOLORP3UIVPROC)load("glSecondaryColorP3uiv"); } static void load_GL_VERSION_4_0(GLADloadproc load) { if(!GLAD_GL_VERSION_4_0) return; glad_glMinSampleShading = (PFNGLMINSAMPLESHADINGPROC)load("glMinSampleShading"); glad_glBlendEquationi = (PFNGLBLENDEQUATIONIPROC)load("glBlendEquationi"); glad_glBlendEquationSeparatei = (PFNGLBLENDEQUATIONSEPARATEIPROC)load("glBlendEquationSeparatei"); glad_glBlendFunci = (PFNGLBLENDFUNCIPROC)load("glBlendFunci"); glad_glBlendFuncSeparatei = (PFNGLBLENDFUNCSEPARATEIPROC)load("glBlendFuncSeparatei"); glad_glDrawArraysIndirect = (PFNGLDRAWARRAYSINDIRECTPROC)load("glDrawArraysIndirect"); glad_glDrawElementsIndirect = (PFNGLDRAWELEMENTSINDIRECTPROC)load("glDrawElementsIndirect"); glad_glUniform1d = (PFNGLUNIFORM1DPROC)load("glUniform1d"); glad_glUniform2d = (PFNGLUNIFORM2DPROC)load("glUniform2d"); glad_glUniform3d = (PFNGLUNIFORM3DPROC)load("glUniform3d"); glad_glUniform4d = (PFNGLUNIFORM4DPROC)load("glUniform4d"); glad_glUniform1dv = (PFNGLUNIFORM1DVPROC)load("glUniform1dv"); glad_glUniform2dv = (PFNGLUNIFORM2DVPROC)load("glUniform2dv"); glad_glUniform3dv = (PFNGLUNIFORM3DVPROC)load("glUniform3dv"); glad_glUniform4dv = (PFNGLUNIFORM4DVPROC)load("glUniform4dv"); glad_glUniformMatrix2dv = (PFNGLUNIFORMMATRIX2DVPROC)load("glUniformMatrix2dv"); glad_glUniformMatrix3dv = (PFNGLUNIFORMMATRIX3DVPROC)load("glUniformMatrix3dv"); glad_glUniformMatrix4dv = (PFNGLUNIFORMMATRIX4DVPROC)load("glUniformMatrix4dv"); glad_glUniformMatrix2x3dv = (PFNGLUNIFORMMATRIX2X3DVPROC)load("glUniformMatrix2x3dv"); glad_glUniformMatrix2x4dv = (PFNGLUNIFORMMATRIX2X4DVPROC)load("glUniformMatrix2x4dv"); glad_glUniformMatrix3x2dv = (PFNGLUNIFORMMATRIX3X2DVPROC)load("glUniformMatrix3x2dv"); glad_glUniformMatrix3x4dv = (PFNGLUNIFORMMATRIX3X4DVPROC)load("glUniformMatrix3x4dv"); glad_glUniformMatrix4x2dv = (PFNGLUNIFORMMATRIX4X2DVPROC)load("glUniformMatrix4x2dv"); glad_glUniformMatrix4x3dv = (PFNGLUNIFORMMATRIX4X3DVPROC)load("glUniformMatrix4x3dv"); glad_glGetUniformdv = (PFNGLGETUNIFORMDVPROC)load("glGetUniformdv"); glad_glGetSubroutineUniformLocation = (PFNGLGETSUBROUTINEUNIFORMLOCATIONPROC)load("glGetSubroutineUniformLocation"); glad_glGetSubroutineIndex = (PFNGLGETSUBROUTINEINDEXPROC)load("glGetSubroutineIndex"); glad_glGetActiveSubroutineUniformiv = (PFNGLGETACTIVESUBROUTINEUNIFORMIVPROC)load("glGetActiveSubroutineUniformiv"); glad_glGetActiveSubroutineUniformName = (PFNGLGETACTIVESUBROUTINEUNIFORMNAMEPROC)load("glGetActiveSubroutineUniformName"); glad_glGetActiveSubroutineName = (PFNGLGETACTIVESUBROUTINENAMEPROC)load("glGetActiveSubroutineName"); glad_glUniformSubroutinesuiv = (PFNGLUNIFORMSUBROUTINESUIVPROC)load("glUniformSubroutinesuiv"); glad_glGetUniformSubroutineuiv = (PFNGLGETUNIFORMSUBROUTINEUIVPROC)load("glGetUniformSubroutineuiv"); glad_glGetProgramStageiv = (PFNGLGETPROGRAMSTAGEIVPROC)load("glGetProgramStageiv"); glad_glPatchParameteri = (PFNGLPATCHPARAMETERIPROC)load("glPatchParameteri"); glad_glPatchParameterfv = (PFNGLPATCHPARAMETERFVPROC)load("glPatchParameterfv"); glad_glBindTransformFeedback = (PFNGLBINDTRANSFORMFEEDBACKPROC)load("glBindTransformFeedback"); glad_glDeleteTransformFeedbacks = (PFNGLDELETETRANSFORMFEEDBACKSPROC)load("glDeleteTransformFeedbacks"); glad_glGenTransformFeedbacks = (PFNGLGENTRANSFORMFEEDBACKSPROC)load("glGenTransformFeedbacks"); glad_glIsTransformFeedback = (PFNGLISTRANSFORMFEEDBACKPROC)load("glIsTransformFeedback"); glad_glPauseTransformFeedback = (PFNGLPAUSETRANSFORMFEEDBACKPROC)load("glPauseTransformFeedback"); glad_glResumeTransformFeedback = (PFNGLRESUMETRANSFORMFEEDBACKPROC)load("glResumeTransformFeedback"); glad_glDrawTransformFeedback = (PFNGLDRAWTRANSFORMFEEDBACKPROC)load("glDrawTransformFeedback"); glad_glDrawTransformFeedbackStream = (PFNGLDRAWTRANSFORMFEEDBACKSTREAMPROC)load("glDrawTransformFeedbackStream"); glad_glBeginQueryIndexed = (PFNGLBEGINQUERYINDEXEDPROC)load("glBeginQueryIndexed"); glad_glEndQueryIndexed = (PFNGLENDQUERYINDEXEDPROC)load("glEndQueryIndexed"); glad_glGetQueryIndexediv = (PFNGLGETQUERYINDEXEDIVPROC)load("glGetQueryIndexediv"); } static void load_GL_VERSION_4_1(GLADloadproc load) { if(!GLAD_GL_VERSION_4_1) return; glad_glReleaseShaderCompiler = (PFNGLRELEASESHADERCOMPILERPROC)load("glReleaseShaderCompiler"); glad_glShaderBinary = (PFNGLSHADERBINARYPROC)load("glShaderBinary"); glad_glGetShaderPrecisionFormat = (PFNGLGETSHADERPRECISIONFORMATPROC)load("glGetShaderPrecisionFormat"); glad_glDepthRangef = (PFNGLDEPTHRANGEFPROC)load("glDepthRangef"); glad_glClearDepthf = (PFNGLCLEARDEPTHFPROC)load("glClearDepthf"); glad_glGetProgramBinary = (PFNGLGETPROGRAMBINARYPROC)load("glGetProgramBinary"); glad_glProgramBinary = (PFNGLPROGRAMBINARYPROC)load("glProgramBinary"); glad_glProgramParameteri = (PFNGLPROGRAMPARAMETERIPROC)load("glProgramParameteri"); glad_glUseProgramStages = (PFNGLUSEPROGRAMSTAGESPROC)load("glUseProgramStages"); glad_glActiveShaderProgram = (PFNGLACTIVESHADERPROGRAMPROC)load("glActiveShaderProgram"); glad_glCreateShaderProgramv = (PFNGLCREATESHADERPROGRAMVPROC)load("glCreateShaderProgramv"); glad_glBindProgramPipeline = (PFNGLBINDPROGRAMPIPELINEPROC)load("glBindProgramPipeline"); glad_glDeleteProgramPipelines = (PFNGLDELETEPROGRAMPIPELINESPROC)load("glDeleteProgramPipelines"); glad_glGenProgramPipelines = (PFNGLGENPROGRAMPIPELINESPROC)load("glGenProgramPipelines"); glad_glIsProgramPipeline = (PFNGLISPROGRAMPIPELINEPROC)load("glIsProgramPipeline"); glad_glGetProgramPipelineiv = (PFNGLGETPROGRAMPIPELINEIVPROC)load("glGetProgramPipelineiv"); glad_glProgramParameteri = (PFNGLPROGRAMPARAMETERIPROC)load("glProgramParameteri"); glad_glProgramUniform1i = (PFNGLPROGRAMUNIFORM1IPROC)load("glProgramUniform1i"); glad_glProgramUniform1iv = (PFNGLPROGRAMUNIFORM1IVPROC)load("glProgramUniform1iv"); glad_glProgramUniform1f = (PFNGLPROGRAMUNIFORM1FPROC)load("glProgramUniform1f"); glad_glProgramUniform1fv = (PFNGLPROGRAMUNIFORM1FVPROC)load("glProgramUniform1fv"); glad_glProgramUniform1d = (PFNGLPROGRAMUNIFORM1DPROC)load("glProgramUniform1d"); glad_glProgramUniform1dv = (PFNGLPROGRAMUNIFORM1DVPROC)load("glProgramUniform1dv"); glad_glProgramUniform1ui = (PFNGLPROGRAMUNIFORM1UIPROC)load("glProgramUniform1ui"); glad_glProgramUniform1uiv = (PFNGLPROGRAMUNIFORM1UIVPROC)load("glProgramUniform1uiv"); glad_glProgramUniform2i = (PFNGLPROGRAMUNIFORM2IPROC)load("glProgramUniform2i"); glad_glProgramUniform2iv = (PFNGLPROGRAMUNIFORM2IVPROC)load("glProgramUniform2iv"); glad_glProgramUniform2f = (PFNGLPROGRAMUNIFORM2FPROC)load("glProgramUniform2f"); glad_glProgramUniform2fv = (PFNGLPROGRAMUNIFORM2FVPROC)load("glProgramUniform2fv"); glad_glProgramUniform2d = (PFNGLPROGRAMUNIFORM2DPROC)load("glProgramUniform2d"); glad_glProgramUniform2dv = (PFNGLPROGRAMUNIFORM2DVPROC)load("glProgramUniform2dv"); glad_glProgramUniform2ui = (PFNGLPROGRAMUNIFORM2UIPROC)load("glProgramUniform2ui"); glad_glProgramUniform2uiv = (PFNGLPROGRAMUNIFORM2UIVPROC)load("glProgramUniform2uiv"); glad_glProgramUniform3i = (PFNGLPROGRAMUNIFORM3IPROC)load("glProgramUniform3i"); glad_glProgramUniform3iv = (PFNGLPROGRAMUNIFORM3IVPROC)load("glProgramUniform3iv"); glad_glProgramUniform3f = (PFNGLPROGRAMUNIFORM3FPROC)load("glProgramUniform3f"); glad_glProgramUniform3fv = (PFNGLPROGRAMUNIFORM3FVPROC)load("glProgramUniform3fv"); glad_glProgramUniform3d = (PFNGLPROGRAMUNIFORM3DPROC)load("glProgramUniform3d"); glad_glProgramUniform3dv = (PFNGLPROGRAMUNIFORM3DVPROC)load("glProgramUniform3dv"); glad_glProgramUniform3ui = (PFNGLPROGRAMUNIFORM3UIPROC)load("glProgramUniform3ui"); glad_glProgramUniform3uiv = (PFNGLPROGRAMUNIFORM3UIVPROC)load("glProgramUniform3uiv"); glad_glProgramUniform4i = (PFNGLPROGRAMUNIFORM4IPROC)load("glProgramUniform4i"); glad_glProgramUniform4iv = (PFNGLPROGRAMUNIFORM4IVPROC)load("glProgramUniform4iv"); glad_glProgramUniform4f = (PFNGLPROGRAMUNIFORM4FPROC)load("glProgramUniform4f"); glad_glProgramUniform4fv = (PFNGLPROGRAMUNIFORM4FVPROC)load("glProgramUniform4fv"); glad_glProgramUniform4d = (PFNGLPROGRAMUNIFORM4DPROC)load("glProgramUniform4d"); glad_glProgramUniform4dv = (PFNGLPROGRAMUNIFORM4DVPROC)load("glProgramUniform4dv"); glad_glProgramUniform4ui = (PFNGLPROGRAMUNIFORM4UIPROC)load("glProgramUniform4ui"); glad_glProgramUniform4uiv = (PFNGLPROGRAMUNIFORM4UIVPROC)load("glProgramUniform4uiv"); glad_glProgramUniformMatrix2fv = (PFNGLPROGRAMUNIFORMMATRIX2FVPROC)load("glProgramUniformMatrix2fv"); glad_glProgramUniformMatrix3fv = (PFNGLPROGRAMUNIFORMMATRIX3FVPROC)load("glProgramUniformMatrix3fv"); glad_glProgramUniformMatrix4fv = (PFNGLPROGRAMUNIFORMMATRIX4FVPROC)load("glProgramUniformMatrix4fv"); glad_glProgramUniformMatrix2dv = (PFNGLPROGRAMUNIFORMMATRIX2DVPROC)load("glProgramUniformMatrix2dv"); glad_glProgramUniformMatrix3dv = (PFNGLPROGRAMUNIFORMMATRIX3DVPROC)load("glProgramUniformMatrix3dv"); glad_glProgramUniformMatrix4dv = (PFNGLPROGRAMUNIFORMMATRIX4DVPROC)load("glProgramUniformMatrix4dv"); glad_glProgramUniformMatrix2x3fv = (PFNGLPROGRAMUNIFORMMATRIX2X3FVPROC)load("glProgramUniformMatrix2x3fv"); glad_glProgramUniformMatrix3x2fv = (PFNGLPROGRAMUNIFORMMATRIX3X2FVPROC)load("glProgramUniformMatrix3x2fv"); glad_glProgramUniformMatrix2x4fv = (PFNGLPROGRAMUNIFORMMATRIX2X4FVPROC)load("glProgramUniformMatrix2x4fv"); glad_glProgramUniformMatrix4x2fv = (PFNGLPROGRAMUNIFORMMATRIX4X2FVPROC)load("glProgramUniformMatrix4x2fv"); glad_glProgramUniformMatrix3x4fv = (PFNGLPROGRAMUNIFORMMATRIX3X4FVPROC)load("glProgramUniformMatrix3x4fv"); glad_glProgramUniformMatrix4x3fv = (PFNGLPROGRAMUNIFORMMATRIX4X3FVPROC)load("glProgramUniformMatrix4x3fv"); glad_glProgramUniformMatrix2x3dv = (PFNGLPROGRAMUNIFORMMATRIX2X3DVPROC)load("glProgramUniformMatrix2x3dv"); glad_glProgramUniformMatrix3x2dv = (PFNGLPROGRAMUNIFORMMATRIX3X2DVPROC)load("glProgramUniformMatrix3x2dv"); glad_glProgramUniformMatrix2x4dv = (PFNGLPROGRAMUNIFORMMATRIX2X4DVPROC)load("glProgramUniformMatrix2x4dv"); glad_glProgramUniformMatrix4x2dv = (PFNGLPROGRAMUNIFORMMATRIX4X2DVPROC)load("glProgramUniformMatrix4x2dv"); glad_glProgramUniformMatrix3x4dv = (PFNGLPROGRAMUNIFORMMATRIX3X4DVPROC)load("glProgramUniformMatrix3x4dv"); glad_glProgramUniformMatrix4x3dv = (PFNGLPROGRAMUNIFORMMATRIX4X3DVPROC)load("glProgramUniformMatrix4x3dv"); glad_glValidateProgramPipeline = (PFNGLVALIDATEPROGRAMPIPELINEPROC)load("glValidateProgramPipeline"); glad_glGetProgramPipelineInfoLog = (PFNGLGETPROGRAMPIPELINEINFOLOGPROC)load("glGetProgramPipelineInfoLog"); glad_glVertexAttribL1d = (PFNGLVERTEXATTRIBL1DPROC)load("glVertexAttribL1d"); glad_glVertexAttribL2d = (PFNGLVERTEXATTRIBL2DPROC)load("glVertexAttribL2d"); glad_glVertexAttribL3d = (PFNGLVERTEXATTRIBL3DPROC)load("glVertexAttribL3d"); glad_glVertexAttribL4d = (PFNGLVERTEXATTRIBL4DPROC)load("glVertexAttribL4d"); glad_glVertexAttribL1dv = (PFNGLVERTEXATTRIBL1DVPROC)load("glVertexAttribL1dv"); glad_glVertexAttribL2dv = (PFNGLVERTEXATTRIBL2DVPROC)load("glVertexAttribL2dv"); glad_glVertexAttribL3dv = (PFNGLVERTEXATTRIBL3DVPROC)load("glVertexAttribL3dv"); glad_glVertexAttribL4dv = (PFNGLVERTEXATTRIBL4DVPROC)load("glVertexAttribL4dv"); glad_glVertexAttribLPointer = (PFNGLVERTEXATTRIBLPOINTERPROC)load("glVertexAttribLPointer"); glad_glGetVertexAttribLdv = (PFNGLGETVERTEXATTRIBLDVPROC)load("glGetVertexAttribLdv"); glad_glViewportArrayv = (PFNGLVIEWPORTARRAYVPROC)load("glViewportArrayv"); glad_glViewportIndexedf = (PFNGLVIEWPORTINDEXEDFPROC)load("glViewportIndexedf"); glad_glViewportIndexedfv = (PFNGLVIEWPORTINDEXEDFVPROC)load("glViewportIndexedfv"); glad_glScissorArrayv = (PFNGLSCISSORARRAYVPROC)load("glScissorArrayv"); glad_glScissorIndexed = (PFNGLSCISSORINDEXEDPROC)load("glScissorIndexed"); glad_glScissorIndexedv = (PFNGLSCISSORINDEXEDVPROC)load("glScissorIndexedv"); glad_glDepthRangeArrayv = (PFNGLDEPTHRANGEARRAYVPROC)load("glDepthRangeArrayv"); glad_glDepthRangeIndexed = (PFNGLDEPTHRANGEINDEXEDPROC)load("glDepthRangeIndexed"); glad_glGetFloati_v = (PFNGLGETFLOATI_VPROC)load("glGetFloati_v"); glad_glGetDoublei_v = (PFNGLGETDOUBLEI_VPROC)load("glGetDoublei_v"); } static void load_GL_VERSION_4_2(GLADloadproc load) { if(!GLAD_GL_VERSION_4_2) return; glad_glDrawArraysInstancedBaseInstance = (PFNGLDRAWARRAYSINSTANCEDBASEINSTANCEPROC)load("glDrawArraysInstancedBaseInstance"); glad_glDrawElementsInstancedBaseInstance = (PFNGLDRAWELEMENTSINSTANCEDBASEINSTANCEPROC)load("glDrawElementsInstancedBaseInstance"); glad_glDrawElementsInstancedBaseVertexBaseInstance = (PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEPROC)load("glDrawElementsInstancedBaseVertexBaseInstance"); glad_glGetInternalformativ = (PFNGLGETINTERNALFORMATIVPROC)load("glGetInternalformativ"); glad_glGetActiveAtomicCounterBufferiv = (PFNGLGETACTIVEATOMICCOUNTERBUFFERIVPROC)load("glGetActiveAtomicCounterBufferiv"); glad_glBindImageTexture = (PFNGLBINDIMAGETEXTUREPROC)load("glBindImageTexture"); glad_glMemoryBarrier = (PFNGLMEMORYBARRIERPROC)load("glMemoryBarrier"); glad_glTexStorage1D = (PFNGLTEXSTORAGE1DPROC)load("glTexStorage1D"); glad_glTexStorage2D = (PFNGLTEXSTORAGE2DPROC)load("glTexStorage2D"); glad_glTexStorage3D = (PFNGLTEXSTORAGE3DPROC)load("glTexStorage3D"); glad_glDrawTransformFeedbackInstanced = (PFNGLDRAWTRANSFORMFEEDBACKINSTANCEDPROC)load("glDrawTransformFeedbackInstanced"); glad_glDrawTransformFeedbackStreamInstanced = (PFNGLDRAWTRANSFORMFEEDBACKSTREAMINSTANCEDPROC)load("glDrawTransformFeedbackStreamInstanced"); } static void load_GL_VERSION_4_3(GLADloadproc load) { if(!GLAD_GL_VERSION_4_3) return; glad_glClearBufferData = (PFNGLCLEARBUFFERDATAPROC)load("glClearBufferData"); glad_glClearBufferSubData = (PFNGLCLEARBUFFERSUBDATAPROC)load("glClearBufferSubData"); glad_glDispatchCompute = (PFNGLDISPATCHCOMPUTEPROC)load("glDispatchCompute"); glad_glDispatchComputeIndirect = (PFNGLDISPATCHCOMPUTEINDIRECTPROC)load("glDispatchComputeIndirect"); glad_glCopyImageSubData = (PFNGLCOPYIMAGESUBDATAPROC)load("glCopyImageSubData"); glad_glFramebufferParameteri = (PFNGLFRAMEBUFFERPARAMETERIPROC)load("glFramebufferParameteri"); glad_glGetFramebufferParameteriv = (PFNGLGETFRAMEBUFFERPARAMETERIVPROC)load("glGetFramebufferParameteriv"); glad_glGetInternalformati64v = (PFNGLGETINTERNALFORMATI64VPROC)load("glGetInternalformati64v"); glad_glInvalidateTexSubImage = (PFNGLINVALIDATETEXSUBIMAGEPROC)load("glInvalidateTexSubImage"); glad_glInvalidateTexImage = (PFNGLINVALIDATETEXIMAGEPROC)load("glInvalidateTexImage"); glad_glInvalidateBufferSubData = (PFNGLINVALIDATEBUFFERSUBDATAPROC)load("glInvalidateBufferSubData"); glad_glInvalidateBufferData = (PFNGLINVALIDATEBUFFERDATAPROC)load("glInvalidateBufferData"); glad_glInvalidateFramebuffer = (PFNGLINVALIDATEFRAMEBUFFERPROC)load("glInvalidateFramebuffer"); glad_glInvalidateSubFramebuffer = (PFNGLINVALIDATESUBFRAMEBUFFERPROC)load("glInvalidateSubFramebuffer"); glad_glMultiDrawArraysIndirect = (PFNGLMULTIDRAWARRAYSINDIRECTPROC)load("glMultiDrawArraysIndirect"); glad_glMultiDrawElementsIndirect = (PFNGLMULTIDRAWELEMENTSINDIRECTPROC)load("glMultiDrawElementsIndirect"); glad_glGetProgramInterfaceiv = (PFNGLGETPROGRAMINTERFACEIVPROC)load("glGetProgramInterfaceiv"); glad_glGetProgramResourceIndex = (PFNGLGETPROGRAMRESOURCEINDEXPROC)load("glGetProgramResourceIndex"); glad_glGetProgramResourceName = (PFNGLGETPROGRAMRESOURCENAMEPROC)load("glGetProgramResourceName"); glad_glGetProgramResourceiv = (PFNGLGETPROGRAMRESOURCEIVPROC)load("glGetProgramResourceiv"); glad_glGetProgramResourceLocation = (PFNGLGETPROGRAMRESOURCELOCATIONPROC)load("glGetProgramResourceLocation"); glad_glGetProgramResourceLocationIndex = (PFNGLGETPROGRAMRESOURCELOCATIONINDEXPROC)load("glGetProgramResourceLocationIndex"); glad_glShaderStorageBlockBinding = (PFNGLSHADERSTORAGEBLOCKBINDINGPROC)load("glShaderStorageBlockBinding"); glad_glTexBufferRange = (PFNGLTEXBUFFERRANGEPROC)load("glTexBufferRange"); glad_glTexStorage2DMultisample = (PFNGLTEXSTORAGE2DMULTISAMPLEPROC)load("glTexStorage2DMultisample"); glad_glTexStorage3DMultisample = (PFNGLTEXSTORAGE3DMULTISAMPLEPROC)load("glTexStorage3DMultisample"); glad_glTextureView = (PFNGLTEXTUREVIEWPROC)load("glTextureView"); glad_glBindVertexBuffer = (PFNGLBINDVERTEXBUFFERPROC)load("glBindVertexBuffer"); glad_glVertexAttribFormat = (PFNGLVERTEXATTRIBFORMATPROC)load("glVertexAttribFormat"); glad_glVertexAttribIFormat = (PFNGLVERTEXATTRIBIFORMATPROC)load("glVertexAttribIFormat"); glad_glVertexAttribLFormat = (PFNGLVERTEXATTRIBLFORMATPROC)load("glVertexAttribLFormat"); glad_glVertexAttribBinding = (PFNGLVERTEXATTRIBBINDINGPROC)load("glVertexAttribBinding"); glad_glVertexBindingDivisor = (PFNGLVERTEXBINDINGDIVISORPROC)load("glVertexBindingDivisor"); glad_glDebugMessageControl = (PFNGLDEBUGMESSAGECONTROLPROC)load("glDebugMessageControl"); glad_glDebugMessageInsert = (PFNGLDEBUGMESSAGEINSERTPROC)load("glDebugMessageInsert"); glad_glDebugMessageCallback = (PFNGLDEBUGMESSAGECALLBACKPROC)load("glDebugMessageCallback"); glad_glGetDebugMessageLog = (PFNGLGETDEBUGMESSAGELOGPROC)load("glGetDebugMessageLog"); glad_glPushDebugGroup = (PFNGLPUSHDEBUGGROUPPROC)load("glPushDebugGroup"); glad_glPopDebugGroup = (PFNGLPOPDEBUGGROUPPROC)load("glPopDebugGroup"); glad_glObjectLabel = (PFNGLOBJECTLABELPROC)load("glObjectLabel"); glad_glGetObjectLabel = (PFNGLGETOBJECTLABELPROC)load("glGetObjectLabel"); glad_glObjectPtrLabel = (PFNGLOBJECTPTRLABELPROC)load("glObjectPtrLabel"); glad_glGetObjectPtrLabel = (PFNGLGETOBJECTPTRLABELPROC)load("glGetObjectPtrLabel"); glad_glGetPointerv = (PFNGLGETPOINTERVPROC)load("glGetPointerv"); } static void load_GL_VERSION_4_4(GLADloadproc load) { if(!GLAD_GL_VERSION_4_4) return; glad_glBufferStorage = (PFNGLBUFFERSTORAGEPROC)load("glBufferStorage"); glad_glClearTexImage = (PFNGLCLEARTEXIMAGEPROC)load("glClearTexImage"); glad_glClearTexSubImage = (PFNGLCLEARTEXSUBIMAGEPROC)load("glClearTexSubImage"); glad_glBindBuffersBase = (PFNGLBINDBUFFERSBASEPROC)load("glBindBuffersBase"); glad_glBindBuffersRange = (PFNGLBINDBUFFERSRANGEPROC)load("glBindBuffersRange"); glad_glBindTextures = (PFNGLBINDTEXTURESPROC)load("glBindTextures"); glad_glBindSamplers = (PFNGLBINDSAMPLERSPROC)load("glBindSamplers"); glad_glBindImageTextures = (PFNGLBINDIMAGETEXTURESPROC)load("glBindImageTextures"); glad_glBindVertexBuffers = (PFNGLBINDVERTEXBUFFERSPROC)load("glBindVertexBuffers"); } static void load_GL_VERSION_4_5(GLADloadproc load) { if(!GLAD_GL_VERSION_4_5) return; glad_glClipControl = (PFNGLCLIPCONTROLPROC)load("glClipControl"); glad_glCreateTransformFeedbacks = (PFNGLCREATETRANSFORMFEEDBACKSPROC)load("glCreateTransformFeedbacks"); glad_glTransformFeedbackBufferBase = (PFNGLTRANSFORMFEEDBACKBUFFERBASEPROC)load("glTransformFeedbackBufferBase"); glad_glTransformFeedbackBufferRange = (PFNGLTRANSFORMFEEDBACKBUFFERRANGEPROC)load("glTransformFeedbackBufferRange"); glad_glGetTransformFeedbackiv = (PFNGLGETTRANSFORMFEEDBACKIVPROC)load("glGetTransformFeedbackiv"); glad_glGetTransformFeedbacki_v = (PFNGLGETTRANSFORMFEEDBACKI_VPROC)load("glGetTransformFeedbacki_v"); glad_glGetTransformFeedbacki64_v = (PFNGLGETTRANSFORMFEEDBACKI64_VPROC)load("glGetTransformFeedbacki64_v"); glad_glCreateBuffers = (PFNGLCREATEBUFFERSPROC)load("glCreateBuffers"); glad_glNamedBufferStorage = (PFNGLNAMEDBUFFERSTORAGEPROC)load("glNamedBufferStorage"); glad_glNamedBufferData = (PFNGLNAMEDBUFFERDATAPROC)load("glNamedBufferData"); glad_glNamedBufferSubData = (PFNGLNAMEDBUFFERSUBDATAPROC)load("glNamedBufferSubData"); glad_glCopyNamedBufferSubData = (PFNGLCOPYNAMEDBUFFERSUBDATAPROC)load("glCopyNamedBufferSubData"); glad_glClearNamedBufferData = (PFNGLCLEARNAMEDBUFFERDATAPROC)load("glClearNamedBufferData"); glad_glClearNamedBufferSubData = (PFNGLCLEARNAMEDBUFFERSUBDATAPROC)load("glClearNamedBufferSubData"); glad_glMapNamedBuffer = (PFNGLMAPNAMEDBUFFERPROC)load("glMapNamedBuffer"); glad_glMapNamedBufferRange = (PFNGLMAPNAMEDBUFFERRANGEPROC)load("glMapNamedBufferRange"); glad_glUnmapNamedBuffer = (PFNGLUNMAPNAMEDBUFFERPROC)load("glUnmapNamedBuffer"); glad_glFlushMappedNamedBufferRange = (PFNGLFLUSHMAPPEDNAMEDBUFFERRANGEPROC)load("glFlushMappedNamedBufferRange"); glad_glGetNamedBufferParameteriv = (PFNGLGETNAMEDBUFFERPARAMETERIVPROC)load("glGetNamedBufferParameteriv"); glad_glGetNamedBufferParameteri64v = (PFNGLGETNAMEDBUFFERPARAMETERI64VPROC)load("glGetNamedBufferParameteri64v"); glad_glGetNamedBufferPointerv = (PFNGLGETNAMEDBUFFERPOINTERVPROC)load("glGetNamedBufferPointerv"); glad_glGetNamedBufferSubData = (PFNGLGETNAMEDBUFFERSUBDATAPROC)load("glGetNamedBufferSubData"); glad_glCreateFramebuffers = (PFNGLCREATEFRAMEBUFFERSPROC)load("glCreateFramebuffers"); glad_glNamedFramebufferRenderbuffer = (PFNGLNAMEDFRAMEBUFFERRENDERBUFFERPROC)load("glNamedFramebufferRenderbuffer"); glad_glNamedFramebufferParameteri = (PFNGLNAMEDFRAMEBUFFERPARAMETERIPROC)load("glNamedFramebufferParameteri"); glad_glNamedFramebufferTexture = (PFNGLNAMEDFRAMEBUFFERTEXTUREPROC)load("glNamedFramebufferTexture"); glad_glNamedFramebufferTextureLayer = (PFNGLNAMEDFRAMEBUFFERTEXTURELAYERPROC)load("glNamedFramebufferTextureLayer"); glad_glNamedFramebufferDrawBuffer = (PFNGLNAMEDFRAMEBUFFERDRAWBUFFERPROC)load("glNamedFramebufferDrawBuffer"); glad_glNamedFramebufferDrawBuffers = (PFNGLNAMEDFRAMEBUFFERDRAWBUFFERSPROC)load("glNamedFramebufferDrawBuffers"); glad_glNamedFramebufferReadBuffer = (PFNGLNAMEDFRAMEBUFFERREADBUFFERPROC)load("glNamedFramebufferReadBuffer"); glad_glInvalidateNamedFramebufferData = (PFNGLINVALIDATENAMEDFRAMEBUFFERDATAPROC)load("glInvalidateNamedFramebufferData"); glad_glInvalidateNamedFramebufferSubData = (PFNGLINVALIDATENAMEDFRAMEBUFFERSUBDATAPROC)load("glInvalidateNamedFramebufferSubData"); glad_glClearNamedFramebufferiv = (PFNGLCLEARNAMEDFRAMEBUFFERIVPROC)load("glClearNamedFramebufferiv"); glad_glClearNamedFramebufferuiv = (PFNGLCLEARNAMEDFRAMEBUFFERUIVPROC)load("glClearNamedFramebufferuiv"); glad_glClearNamedFramebufferfv = (PFNGLCLEARNAMEDFRAMEBUFFERFVPROC)load("glClearNamedFramebufferfv"); glad_glClearNamedFramebufferfi = (PFNGLCLEARNAMEDFRAMEBUFFERFIPROC)load("glClearNamedFramebufferfi"); glad_glBlitNamedFramebuffer = (PFNGLBLITNAMEDFRAMEBUFFERPROC)load("glBlitNamedFramebuffer"); glad_glCheckNamedFramebufferStatus = (PFNGLCHECKNAMEDFRAMEBUFFERSTATUSPROC)load("glCheckNamedFramebufferStatus"); glad_glGetNamedFramebufferParameteriv = (PFNGLGETNAMEDFRAMEBUFFERPARAMETERIVPROC)load("glGetNamedFramebufferParameteriv"); glad_glGetNamedFramebufferAttachmentParameteriv = (PFNGLGETNAMEDFRAMEBUFFERATTACHMENTPARAMETERIVPROC)load("glGetNamedFramebufferAttachmentParameteriv"); glad_glCreateRenderbuffers = (PFNGLCREATERENDERBUFFERSPROC)load("glCreateRenderbuffers"); glad_glNamedRenderbufferStorage = (PFNGLNAMEDRENDERBUFFERSTORAGEPROC)load("glNamedRenderbufferStorage"); glad_glNamedRenderbufferStorageMultisample = (PFNGLNAMEDRENDERBUFFERSTORAGEMULTISAMPLEPROC)load("glNamedRenderbufferStorageMultisample"); glad_glGetNamedRenderbufferParameteriv = (PFNGLGETNAMEDRENDERBUFFERPARAMETERIVPROC)load("glGetNamedRenderbufferParameteriv"); glad_glCreateTextures = (PFNGLCREATETEXTURESPROC)load("glCreateTextures"); glad_glTextureBuffer = (PFNGLTEXTUREBUFFERPROC)load("glTextureBuffer"); glad_glTextureBufferRange = (PFNGLTEXTUREBUFFERRANGEPROC)load("glTextureBufferRange"); glad_glTextureStorage1D = (PFNGLTEXTURESTORAGE1DPROC)load("glTextureStorage1D"); glad_glTextureStorage2D = (PFNGLTEXTURESTORAGE2DPROC)load("glTextureStorage2D"); glad_glTextureStorage3D = (PFNGLTEXTURESTORAGE3DPROC)load("glTextureStorage3D"); glad_glTextureStorage2DMultisample = (PFNGLTEXTURESTORAGE2DMULTISAMPLEPROC)load("glTextureStorage2DMultisample"); glad_glTextureStorage3DMultisample = (PFNGLTEXTURESTORAGE3DMULTISAMPLEPROC)load("glTextureStorage3DMultisample"); glad_glTextureSubImage1D = (PFNGLTEXTURESUBIMAGE1DPROC)load("glTextureSubImage1D"); glad_glTextureSubImage2D = (PFNGLTEXTURESUBIMAGE2DPROC)load("glTextureSubImage2D"); glad_glTextureSubImage3D = (PFNGLTEXTURESUBIMAGE3DPROC)load("glTextureSubImage3D"); glad_glCompressedTextureSubImage1D = (PFNGLCOMPRESSEDTEXTURESUBIMAGE1DPROC)load("glCompressedTextureSubImage1D"); glad_glCompressedTextureSubImage2D = (PFNGLCOMPRESSEDTEXTURESUBIMAGE2DPROC)load("glCompressedTextureSubImage2D"); glad_glCompressedTextureSubImage3D = (PFNGLCOMPRESSEDTEXTURESUBIMAGE3DPROC)load("glCompressedTextureSubImage3D"); glad_glCopyTextureSubImage1D = (PFNGLCOPYTEXTURESUBIMAGE1DPROC)load("glCopyTextureSubImage1D"); glad_glCopyTextureSubImage2D = (PFNGLCOPYTEXTURESUBIMAGE2DPROC)load("glCopyTextureSubImage2D"); glad_glCopyTextureSubImage3D = (PFNGLCOPYTEXTURESUBIMAGE3DPROC)load("glCopyTextureSubImage3D"); glad_glTextureParameterf = (PFNGLTEXTUREPARAMETERFPROC)load("glTextureParameterf"); glad_glTextureParameterfv = (PFNGLTEXTUREPARAMETERFVPROC)load("glTextureParameterfv"); glad_glTextureParameteri = (PFNGLTEXTUREPARAMETERIPROC)load("glTextureParameteri"); glad_glTextureParameterIiv = (PFNGLTEXTUREPARAMETERIIVPROC)load("glTextureParameterIiv"); glad_glTextureParameterIuiv = (PFNGLTEXTUREPARAMETERIUIVPROC)load("glTextureParameterIuiv"); glad_glTextureParameteriv = (PFNGLTEXTUREPARAMETERIVPROC)load("glTextureParameteriv"); glad_glGenerateTextureMipmap = (PFNGLGENERATETEXTUREMIPMAPPROC)load("glGenerateTextureMipmap"); glad_glBindTextureUnit = (PFNGLBINDTEXTUREUNITPROC)load("glBindTextureUnit"); glad_glGetTextureImage = (PFNGLGETTEXTUREIMAGEPROC)load("glGetTextureImage"); glad_glGetCompressedTextureImage = (PFNGLGETCOMPRESSEDTEXTUREIMAGEPROC)load("glGetCompressedTextureImage"); glad_glGetTextureLevelParameterfv = (PFNGLGETTEXTURELEVELPARAMETERFVPROC)load("glGetTextureLevelParameterfv"); glad_glGetTextureLevelParameteriv = (PFNGLGETTEXTURELEVELPARAMETERIVPROC)load("glGetTextureLevelParameteriv"); glad_glGetTextureParameterfv = (PFNGLGETTEXTUREPARAMETERFVPROC)load("glGetTextureParameterfv"); glad_glGetTextureParameterIiv = (PFNGLGETTEXTUREPARAMETERIIVPROC)load("glGetTextureParameterIiv"); glad_glGetTextureParameterIuiv = (PFNGLGETTEXTUREPARAMETERIUIVPROC)load("glGetTextureParameterIuiv"); glad_glGetTextureParameteriv = (PFNGLGETTEXTUREPARAMETERIVPROC)load("glGetTextureParameteriv"); glad_glCreateVertexArrays = (PFNGLCREATEVERTEXARRAYSPROC)load("glCreateVertexArrays"); glad_glDisableVertexArrayAttrib = (PFNGLDISABLEVERTEXARRAYATTRIBPROC)load("glDisableVertexArrayAttrib"); glad_glEnableVertexArrayAttrib = (PFNGLENABLEVERTEXARRAYATTRIBPROC)load("glEnableVertexArrayAttrib"); glad_glVertexArrayElementBuffer = (PFNGLVERTEXARRAYELEMENTBUFFERPROC)load("glVertexArrayElementBuffer"); glad_glVertexArrayVertexBuffer = (PFNGLVERTEXARRAYVERTEXBUFFERPROC)load("glVertexArrayVertexBuffer"); glad_glVertexArrayVertexBuffers = (PFNGLVERTEXARRAYVERTEXBUFFERSPROC)load("glVertexArrayVertexBuffers"); glad_glVertexArrayAttribBinding = (PFNGLVERTEXARRAYATTRIBBINDINGPROC)load("glVertexArrayAttribBinding"); glad_glVertexArrayAttribFormat = (PFNGLVERTEXARRAYATTRIBFORMATPROC)load("glVertexArrayAttribFormat"); glad_glVertexArrayAttribIFormat = (PFNGLVERTEXARRAYATTRIBIFORMATPROC)load("glVertexArrayAttribIFormat"); glad_glVertexArrayAttribLFormat = (PFNGLVERTEXARRAYATTRIBLFORMATPROC)load("glVertexArrayAttribLFormat"); glad_glVertexArrayBindingDivisor = (PFNGLVERTEXARRAYBINDINGDIVISORPROC)load("glVertexArrayBindingDivisor"); glad_glGetVertexArrayiv = (PFNGLGETVERTEXARRAYIVPROC)load("glGetVertexArrayiv"); glad_glGetVertexArrayIndexediv = (PFNGLGETVERTEXARRAYINDEXEDIVPROC)load("glGetVertexArrayIndexediv"); glad_glGetVertexArrayIndexed64iv = (PFNGLGETVERTEXARRAYINDEXED64IVPROC)load("glGetVertexArrayIndexed64iv"); glad_glCreateSamplers = (PFNGLCREATESAMPLERSPROC)load("glCreateSamplers"); glad_glCreateProgramPipelines = (PFNGLCREATEPROGRAMPIPELINESPROC)load("glCreateProgramPipelines"); glad_glCreateQueries = (PFNGLCREATEQUERIESPROC)load("glCreateQueries"); glad_glGetQueryBufferObjecti64v = (PFNGLGETQUERYBUFFEROBJECTI64VPROC)load("glGetQueryBufferObjecti64v"); glad_glGetQueryBufferObjectiv = (PFNGLGETQUERYBUFFEROBJECTIVPROC)load("glGetQueryBufferObjectiv"); glad_glGetQueryBufferObjectui64v = (PFNGLGETQUERYBUFFEROBJECTUI64VPROC)load("glGetQueryBufferObjectui64v"); glad_glGetQueryBufferObjectuiv = (PFNGLGETQUERYBUFFEROBJECTUIVPROC)load("glGetQueryBufferObjectuiv"); glad_glMemoryBarrierByRegion = (PFNGLMEMORYBARRIERBYREGIONPROC)load("glMemoryBarrierByRegion"); glad_glGetTextureSubImage = (PFNGLGETTEXTURESUBIMAGEPROC)load("glGetTextureSubImage"); glad_glGetCompressedTextureSubImage = (PFNGLGETCOMPRESSEDTEXTURESUBIMAGEPROC)load("glGetCompressedTextureSubImage"); glad_glGetGraphicsResetStatus = (PFNGLGETGRAPHICSRESETSTATUSPROC)load("glGetGraphicsResetStatus"); glad_glGetnCompressedTexImage = (PFNGLGETNCOMPRESSEDTEXIMAGEPROC)load("glGetnCompressedTexImage"); glad_glGetnTexImage = (PFNGLGETNTEXIMAGEPROC)load("glGetnTexImage"); glad_glGetnUniformdv = (PFNGLGETNUNIFORMDVPROC)load("glGetnUniformdv"); glad_glGetnUniformfv = (PFNGLGETNUNIFORMFVPROC)load("glGetnUniformfv"); glad_glGetnUniformiv = (PFNGLGETNUNIFORMIVPROC)load("glGetnUniformiv"); glad_glGetnUniformuiv = (PFNGLGETNUNIFORMUIVPROC)load("glGetnUniformuiv"); glad_glReadnPixels = (PFNGLREADNPIXELSPROC)load("glReadnPixels"); glad_glGetnMapdv = (PFNGLGETNMAPDVPROC)load("glGetnMapdv"); glad_glGetnMapfv = (PFNGLGETNMAPFVPROC)load("glGetnMapfv"); glad_glGetnMapiv = (PFNGLGETNMAPIVPROC)load("glGetnMapiv"); glad_glGetnPixelMapfv = (PFNGLGETNPIXELMAPFVPROC)load("glGetnPixelMapfv"); glad_glGetnPixelMapuiv = (PFNGLGETNPIXELMAPUIVPROC)load("glGetnPixelMapuiv"); glad_glGetnPixelMapusv = (PFNGLGETNPIXELMAPUSVPROC)load("glGetnPixelMapusv"); glad_glGetnPolygonStipple = (PFNGLGETNPOLYGONSTIPPLEPROC)load("glGetnPolygonStipple"); glad_glGetnColorTable = (PFNGLGETNCOLORTABLEPROC)load("glGetnColorTable"); glad_glGetnConvolutionFilter = (PFNGLGETNCONVOLUTIONFILTERPROC)load("glGetnConvolutionFilter"); glad_glGetnSeparableFilter = (PFNGLGETNSEPARABLEFILTERPROC)load("glGetnSeparableFilter"); glad_glGetnHistogram = (PFNGLGETNHISTOGRAMPROC)load("glGetnHistogram"); glad_glGetnMinmax = (PFNGLGETNMINMAXPROC)load("glGetnMinmax"); glad_glTextureBarrier = (PFNGLTEXTUREBARRIERPROC)load("glTextureBarrier"); } static void load_GL_VERSION_4_6(GLADloadproc load) { if(!GLAD_GL_VERSION_4_6) return; glad_glSpecializeShader = (PFNGLSPECIALIZESHADERPROC)load("glSpecializeShader"); glad_glMultiDrawArraysIndirectCount = (PFNGLMULTIDRAWARRAYSINDIRECTCOUNTPROC)load("glMultiDrawArraysIndirectCount"); glad_glMultiDrawElementsIndirectCount = (PFNGLMULTIDRAWELEMENTSINDIRECTCOUNTPROC)load("glMultiDrawElementsIndirectCount"); glad_glPolygonOffsetClamp = (PFNGLPOLYGONOFFSETCLAMPPROC)load("glPolygonOffsetClamp"); } static void load_GL_ARB_clip_control(GLADloadproc load) { if(!GLAD_GL_ARB_clip_control) return; glad_glClipControl = (PFNGLCLIPCONTROLPROC)load("glClipControl"); } static int find_extensionsGL(void) { if (!get_exts()) return 0; GLAD_GL_ARB_clip_control = has_ext("GL_ARB_clip_control"); free_exts(); return 1; } static void find_coreGL(void) { /* Thank you @elmindreda * https://github.com/elmindreda/greg/blob/master/templates/greg.c.in#L176 * https://github.com/glfw/glfw/blob/master/src/context.c#L36 */ int i, major, minor; const char* version; const char* prefixes[] = { "OpenGL ES-CM ", "OpenGL ES-CL ", "OpenGL ES ", NULL }; version = (const char*) glGetString(GL_VERSION); if (!version) return; for (i = 0; prefixes[i]; i++) { const size_t length = strlen(prefixes[i]); if (strncmp(version, prefixes[i], length) == 0) { version += length; break; } } /* PR #18 */ #ifdef _MSC_VER sscanf_s(version, "%d.%d", &major, &minor); #else sscanf(version, "%d.%d", &major, &minor); #endif GLVersion.major = major; GLVersion.minor = minor; max_loaded_major = major; max_loaded_minor = minor; GLAD_GL_VERSION_1_0 = (major == 1 && minor >= 0) || major > 1; GLAD_GL_VERSION_1_1 = (major == 1 && minor >= 1) || major > 1; GLAD_GL_VERSION_1_2 = (major == 1 && minor >= 2) || major > 1; GLAD_GL_VERSION_1_3 = (major == 1 && minor >= 3) || major > 1; GLAD_GL_VERSION_1_4 = (major == 1 && minor >= 4) || major > 1; GLAD_GL_VERSION_1_5 = (major == 1 && minor >= 5) || major > 1; GLAD_GL_VERSION_2_0 = (major == 2 && minor >= 0) || major > 2; GLAD_GL_VERSION_2_1 = (major == 2 && minor >= 1) || major > 2; GLAD_GL_VERSION_3_0 = (major == 3 && minor >= 0) || major > 3; GLAD_GL_VERSION_3_1 = (major == 3 && minor >= 1) || major > 3; GLAD_GL_VERSION_3_2 = (major == 3 && minor >= 2) || major > 3; GLAD_GL_VERSION_3_3 = (major == 3 && minor >= 3) || major > 3; GLAD_GL_VERSION_4_0 = (major == 4 && minor >= 0) || major > 4; GLAD_GL_VERSION_4_1 = (major == 4 && minor >= 1) || major > 4; GLAD_GL_VERSION_4_2 = (major == 4 && minor >= 2) || major > 4; GLAD_GL_VERSION_4_3 = (major == 4 && minor >= 3) || major > 4; GLAD_GL_VERSION_4_4 = (major == 4 && minor >= 4) || major > 4; GLAD_GL_VERSION_4_5 = (major == 4 && minor >= 5) || major > 4; GLAD_GL_VERSION_4_6 = (major == 4 && minor >= 6) || major > 4; if (GLVersion.major > 4 || (GLVersion.major >= 4 && GLVersion.minor >= 6)) { max_loaded_major = 4; max_loaded_minor = 6; } } int gladLoadGLLoader(GLADloadproc load) { GLVersion.major = 0; GLVersion.minor = 0; glGetString = (PFNGLGETSTRINGPROC)load("glGetString"); if(glGetString == NULL) return 0; if(glGetString(GL_VERSION) == NULL) return 0; find_coreGL(); load_GL_VERSION_1_0(load); load_GL_VERSION_1_1(load); load_GL_VERSION_1_2(load); load_GL_VERSION_1_3(load); load_GL_VERSION_1_4(load); load_GL_VERSION_1_5(load); load_GL_VERSION_2_0(load); load_GL_VERSION_2_1(load); load_GL_VERSION_3_0(load); load_GL_VERSION_3_1(load); load_GL_VERSION_3_2(load); load_GL_VERSION_3_3(load); load_GL_VERSION_4_0(load); load_GL_VERSION_4_1(load); load_GL_VERSION_4_2(load); load_GL_VERSION_4_3(load); load_GL_VERSION_4_4(load); load_GL_VERSION_4_5(load); load_GL_VERSION_4_6(load); if (!find_extensionsGL()) return 0; load_GL_ARB_clip_control(load); return GLVersion.major != 0 || GLVersion.minor != 0; } static void load_GL_ES_VERSION_2_0(GLADloadproc load) { if(!GLAD_GL_ES_VERSION_2_0) return; glad_glActiveTexture = (PFNGLACTIVETEXTUREPROC)load("glActiveTexture"); glad_glAttachShader = (PFNGLATTACHSHADERPROC)load("glAttachShader"); glad_glBindAttribLocation = (PFNGLBINDATTRIBLOCATIONPROC)load("glBindAttribLocation"); glad_glBindBuffer = (PFNGLBINDBUFFERPROC)load("glBindBuffer"); glad_glBindFramebuffer = (PFNGLBINDFRAMEBUFFERPROC)load("glBindFramebuffer"); glad_glBindRenderbuffer = (PFNGLBINDRENDERBUFFERPROC)load("glBindRenderbuffer"); glad_glBindTexture = (PFNGLBINDTEXTUREPROC)load("glBindTexture"); glad_glBlendColor = (PFNGLBLENDCOLORPROC)load("glBlendColor"); glad_glBlendEquation = (PFNGLBLENDEQUATIONPROC)load("glBlendEquation"); glad_glBlendEquationSeparate = (PFNGLBLENDEQUATIONSEPARATEPROC)load("glBlendEquationSeparate"); glad_glBlendFunc = (PFNGLBLENDFUNCPROC)load("glBlendFunc"); glad_glBlendFuncSeparate = (PFNGLBLENDFUNCSEPARATEPROC)load("glBlendFuncSeparate"); glad_glBufferData = (PFNGLBUFFERDATAPROC)load("glBufferData"); glad_glBufferSubData = (PFNGLBUFFERSUBDATAPROC)load("glBufferSubData"); glad_glCheckFramebufferStatus = (PFNGLCHECKFRAMEBUFFERSTATUSPROC)load("glCheckFramebufferStatus"); glad_glClear = (PFNGLCLEARPROC)load("glClear"); glad_glClearColor = (PFNGLCLEARCOLORPROC)load("glClearColor"); glad_glClearDepthf = (PFNGLCLEARDEPTHFPROC)load("glClearDepthf"); glad_glClearStencil = (PFNGLCLEARSTENCILPROC)load("glClearStencil"); glad_glColorMask = (PFNGLCOLORMASKPROC)load("glColorMask"); glad_glCompileShader = (PFNGLCOMPILESHADERPROC)load("glCompileShader"); glad_glCompressedTexImage2D = (PFNGLCOMPRESSEDTEXIMAGE2DPROC)load("glCompressedTexImage2D"); glad_glCompressedTexSubImage2D = (PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC)load("glCompressedTexSubImage2D"); glad_glCopyTexImage2D = (PFNGLCOPYTEXIMAGE2DPROC)load("glCopyTexImage2D"); glad_glCopyTexSubImage2D = (PFNGLCOPYTEXSUBIMAGE2DPROC)load("glCopyTexSubImage2D"); glad_glCreateProgram = (PFNGLCREATEPROGRAMPROC)load("glCreateProgram"); glad_glCreateShader = (PFNGLCREATESHADERPROC)load("glCreateShader"); glad_glCullFace = (PFNGLCULLFACEPROC)load("glCullFace"); glad_glDeleteBuffers = (PFNGLDELETEBUFFERSPROC)load("glDeleteBuffers"); glad_glDeleteFramebuffers = (PFNGLDELETEFRAMEBUFFERSPROC)load("glDeleteFramebuffers"); glad_glDeleteProgram = (PFNGLDELETEPROGRAMPROC)load("glDeleteProgram"); glad_glDeleteRenderbuffers = (PFNGLDELETERENDERBUFFERSPROC)load("glDeleteRenderbuffers"); glad_glDeleteShader = (PFNGLDELETESHADERPROC)load("glDeleteShader"); glad_glDeleteTextures = (PFNGLDELETETEXTURESPROC)load("glDeleteTextures"); glad_glDepthFunc = (PFNGLDEPTHFUNCPROC)load("glDepthFunc"); glad_glDepthMask = (PFNGLDEPTHMASKPROC)load("glDepthMask"); glad_glDepthRangef = (PFNGLDEPTHRANGEFPROC)load("glDepthRangef"); glad_glDetachShader = (PFNGLDETACHSHADERPROC)load("glDetachShader"); glad_glDisable = (PFNGLDISABLEPROC)load("glDisable"); glad_glDisableVertexAttribArray = (PFNGLDISABLEVERTEXATTRIBARRAYPROC)load("glDisableVertexAttribArray"); glad_glDrawArrays = (PFNGLDRAWARRAYSPROC)load("glDrawArrays"); glad_glDrawElements = (PFNGLDRAWELEMENTSPROC)load("glDrawElements"); glad_glEnable = (PFNGLENABLEPROC)load("glEnable"); glad_glEnableVertexAttribArray = (PFNGLENABLEVERTEXATTRIBARRAYPROC)load("glEnableVertexAttribArray"); glad_glFinish = (PFNGLFINISHPROC)load("glFinish"); glad_glFlush = (PFNGLFLUSHPROC)load("glFlush"); glad_glFramebufferRenderbuffer = (PFNGLFRAMEBUFFERRENDERBUFFERPROC)load("glFramebufferRenderbuffer"); glad_glFramebufferTexture2D = (PFNGLFRAMEBUFFERTEXTURE2DPROC)load("glFramebufferTexture2D"); glad_glFrontFace = (PFNGLFRONTFACEPROC)load("glFrontFace"); glad_glGenBuffers = (PFNGLGENBUFFERSPROC)load("glGenBuffers"); glad_glGenerateMipmap = (PFNGLGENERATEMIPMAPPROC)load("glGenerateMipmap"); glad_glGenFramebuffers = (PFNGLGENFRAMEBUFFERSPROC)load("glGenFramebuffers"); glad_glGenRenderbuffers = (PFNGLGENRENDERBUFFERSPROC)load("glGenRenderbuffers"); glad_glGenTextures = (PFNGLGENTEXTURESPROC)load("glGenTextures"); glad_glGetActiveAttrib = (PFNGLGETACTIVEATTRIBPROC)load("glGetActiveAttrib"); glad_glGetActiveUniform = (PFNGLGETACTIVEUNIFORMPROC)load("glGetActiveUniform"); glad_glGetAttachedShaders = (PFNGLGETATTACHEDSHADERSPROC)load("glGetAttachedShaders"); glad_glGetAttribLocation = (PFNGLGETATTRIBLOCATIONPROC)load("glGetAttribLocation"); glad_glGetBooleanv = (PFNGLGETBOOLEANVPROC)load("glGetBooleanv"); glad_glGetBufferParameteriv = (PFNGLGETBUFFERPARAMETERIVPROC)load("glGetBufferParameteriv"); glad_glGetError = (PFNGLGETERRORPROC)load("glGetError"); glad_glGetFloatv = (PFNGLGETFLOATVPROC)load("glGetFloatv"); glad_glGetFramebufferAttachmentParameteriv = (PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC)load("glGetFramebufferAttachmentParameteriv"); glad_glGetIntegerv = (PFNGLGETINTEGERVPROC)load("glGetIntegerv"); glad_glGetProgramiv = (PFNGLGETPROGRAMIVPROC)load("glGetProgramiv"); glad_glGetProgramInfoLog = (PFNGLGETPROGRAMINFOLOGPROC)load("glGetProgramInfoLog"); glad_glGetRenderbufferParameteriv = (PFNGLGETRENDERBUFFERPARAMETERIVPROC)load("glGetRenderbufferParameteriv"); glad_glGetShaderiv = (PFNGLGETSHADERIVPROC)load("glGetShaderiv"); glad_glGetShaderInfoLog = (PFNGLGETSHADERINFOLOGPROC)load("glGetShaderInfoLog"); glad_glGetShaderPrecisionFormat = (PFNGLGETSHADERPRECISIONFORMATPROC)load("glGetShaderPrecisionFormat"); glad_glGetShaderSource = (PFNGLGETSHADERSOURCEPROC)load("glGetShaderSource"); glad_glGetString = (PFNGLGETSTRINGPROC)load("glGetString"); glad_glGetTexParameterfv = (PFNGLGETTEXPARAMETERFVPROC)load("glGetTexParameterfv"); glad_glGetTexParameteriv = (PFNGLGETTEXPARAMETERIVPROC)load("glGetTexParameteriv"); glad_glGetUniformfv = (PFNGLGETUNIFORMFVPROC)load("glGetUniformfv"); glad_glGetUniformiv = (PFNGLGETUNIFORMIVPROC)load("glGetUniformiv"); glad_glGetUniformLocation = (PFNGLGETUNIFORMLOCATIONPROC)load("glGetUniformLocation"); glad_glGetVertexAttribfv = (PFNGLGETVERTEXATTRIBFVPROC)load("glGetVertexAttribfv"); glad_glGetVertexAttribiv = (PFNGLGETVERTEXATTRIBIVPROC)load("glGetVertexAttribiv"); glad_glGetVertexAttribPointerv = (PFNGLGETVERTEXATTRIBPOINTERVPROC)load("glGetVertexAttribPointerv"); glad_glHint = (PFNGLHINTPROC)load("glHint"); glad_glIsBuffer = (PFNGLISBUFFERPROC)load("glIsBuffer"); glad_glIsEnabled = (PFNGLISENABLEDPROC)load("glIsEnabled"); glad_glIsFramebuffer = (PFNGLISFRAMEBUFFERPROC)load("glIsFramebuffer"); glad_glIsProgram = (PFNGLISPROGRAMPROC)load("glIsProgram"); glad_glIsRenderbuffer = (PFNGLISRENDERBUFFERPROC)load("glIsRenderbuffer"); glad_glIsShader = (PFNGLISSHADERPROC)load("glIsShader"); glad_glIsTexture = (PFNGLISTEXTUREPROC)load("glIsTexture"); glad_glLineWidth = (PFNGLLINEWIDTHPROC)load("glLineWidth"); glad_glLinkProgram = (PFNGLLINKPROGRAMPROC)load("glLinkProgram"); glad_glPixelStorei = (PFNGLPIXELSTOREIPROC)load("glPixelStorei"); glad_glPolygonOffset = (PFNGLPOLYGONOFFSETPROC)load("glPolygonOffset"); glad_glReadPixels = (PFNGLREADPIXELSPROC)load("glReadPixels"); glad_glReleaseShaderCompiler = (PFNGLRELEASESHADERCOMPILERPROC)load("glReleaseShaderCompiler"); glad_glRenderbufferStorage = (PFNGLRENDERBUFFERSTORAGEPROC)load("glRenderbufferStorage"); glad_glSampleCoverage = (PFNGLSAMPLECOVERAGEPROC)load("glSampleCoverage"); glad_glScissor = (PFNGLSCISSORPROC)load("glScissor"); glad_glShaderBinary = (PFNGLSHADERBINARYPROC)load("glShaderBinary"); glad_glShaderSource = (PFNGLSHADERSOURCEPROC)load("glShaderSource"); glad_glStencilFunc = (PFNGLSTENCILFUNCPROC)load("glStencilFunc"); glad_glStencilFuncSeparate = (PFNGLSTENCILFUNCSEPARATEPROC)load("glStencilFuncSeparate"); glad_glStencilMask = (PFNGLSTENCILMASKPROC)load("glStencilMask"); glad_glStencilMaskSeparate = (PFNGLSTENCILMASKSEPARATEPROC)load("glStencilMaskSeparate"); glad_glStencilOp = (PFNGLSTENCILOPPROC)load("glStencilOp"); glad_glStencilOpSeparate = (PFNGLSTENCILOPSEPARATEPROC)load("glStencilOpSeparate"); glad_glTexImage2D = (PFNGLTEXIMAGE2DPROC)load("glTexImage2D"); glad_glTexParameterf = (PFNGLTEXPARAMETERFPROC)load("glTexParameterf"); glad_glTexParameterfv = (PFNGLTEXPARAMETERFVPROC)load("glTexParameterfv"); glad_glTexParameteri = (PFNGLTEXPARAMETERIPROC)load("glTexParameteri"); glad_glTexParameteriv = (PFNGLTEXPARAMETERIVPROC)load("glTexParameteriv"); glad_glTexSubImage2D = (PFNGLTEXSUBIMAGE2DPROC)load("glTexSubImage2D"); glad_glUniform1f = (PFNGLUNIFORM1FPROC)load("glUniform1f"); glad_glUniform1fv = (PFNGLUNIFORM1FVPROC)load("glUniform1fv"); glad_glUniform1i = (PFNGLUNIFORM1IPROC)load("glUniform1i"); glad_glUniform1iv = (PFNGLUNIFORM1IVPROC)load("glUniform1iv"); glad_glUniform2f = (PFNGLUNIFORM2FPROC)load("glUniform2f"); glad_glUniform2fv = (PFNGLUNIFORM2FVPROC)load("glUniform2fv"); glad_glUniform2i = (PFNGLUNIFORM2IPROC)load("glUniform2i"); glad_glUniform2iv = (PFNGLUNIFORM2IVPROC)load("glUniform2iv"); glad_glUniform3f = (PFNGLUNIFORM3FPROC)load("glUniform3f"); glad_glUniform3fv = (PFNGLUNIFORM3FVPROC)load("glUniform3fv"); glad_glUniform3i = (PFNGLUNIFORM3IPROC)load("glUniform3i"); glad_glUniform3iv = (PFNGLUNIFORM3IVPROC)load("glUniform3iv"); glad_glUniform4f = (PFNGLUNIFORM4FPROC)load("glUniform4f"); glad_glUniform4fv = (PFNGLUNIFORM4FVPROC)load("glUniform4fv"); glad_glUniform4i = (PFNGLUNIFORM4IPROC)load("glUniform4i"); glad_glUniform4iv = (PFNGLUNIFORM4IVPROC)load("glUniform4iv"); glad_glUniformMatrix2fv = (PFNGLUNIFORMMATRIX2FVPROC)load("glUniformMatrix2fv"); glad_glUniformMatrix3fv = (PFNGLUNIFORMMATRIX3FVPROC)load("glUniformMatrix3fv"); glad_glUniformMatrix4fv = (PFNGLUNIFORMMATRIX4FVPROC)load("glUniformMatrix4fv"); glad_glUseProgram = (PFNGLUSEPROGRAMPROC)load("glUseProgram"); glad_glValidateProgram = (PFNGLVALIDATEPROGRAMPROC)load("glValidateProgram"); glad_glVertexAttrib1f = (PFNGLVERTEXATTRIB1FPROC)load("glVertexAttrib1f"); glad_glVertexAttrib1fv = (PFNGLVERTEXATTRIB1FVPROC)load("glVertexAttrib1fv"); glad_glVertexAttrib2f = (PFNGLVERTEXATTRIB2FPROC)load("glVertexAttrib2f"); glad_glVertexAttrib2fv = (PFNGLVERTEXATTRIB2FVPROC)load("glVertexAttrib2fv"); glad_glVertexAttrib3f = (PFNGLVERTEXATTRIB3FPROC)load("glVertexAttrib3f"); glad_glVertexAttrib3fv = (PFNGLVERTEXATTRIB3FVPROC)load("glVertexAttrib3fv"); glad_glVertexAttrib4f = (PFNGLVERTEXATTRIB4FPROC)load("glVertexAttrib4f"); glad_glVertexAttrib4fv = (PFNGLVERTEXATTRIB4FVPROC)load("glVertexAttrib4fv"); glad_glVertexAttribPointer = (PFNGLVERTEXATTRIBPOINTERPROC)load("glVertexAttribPointer"); glad_glViewport = (PFNGLVIEWPORTPROC)load("glViewport"); } static void load_GL_ES_VERSION_3_0(GLADloadproc load) { if(!GLAD_GL_ES_VERSION_3_0) return; glad_glReadBuffer = (PFNGLREADBUFFERPROC)load("glReadBuffer"); glad_glDrawRangeElements = (PFNGLDRAWRANGEELEMENTSPROC)load("glDrawRangeElements"); glad_glTexImage3D = (PFNGLTEXIMAGE3DPROC)load("glTexImage3D"); glad_glTexSubImage3D = (PFNGLTEXSUBIMAGE3DPROC)load("glTexSubImage3D"); glad_glCopyTexSubImage3D = (PFNGLCOPYTEXSUBIMAGE3DPROC)load("glCopyTexSubImage3D"); glad_glCompressedTexImage3D = (PFNGLCOMPRESSEDTEXIMAGE3DPROC)load("glCompressedTexImage3D"); glad_glCompressedTexSubImage3D = (PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC)load("glCompressedTexSubImage3D"); glad_glGenQueries = (PFNGLGENQUERIESPROC)load("glGenQueries"); glad_glDeleteQueries = (PFNGLDELETEQUERIESPROC)load("glDeleteQueries"); glad_glIsQuery = (PFNGLISQUERYPROC)load("glIsQuery"); glad_glBeginQuery = (PFNGLBEGINQUERYPROC)load("glBeginQuery"); glad_glEndQuery = (PFNGLENDQUERYPROC)load("glEndQuery"); glad_glGetQueryiv = (PFNGLGETQUERYIVPROC)load("glGetQueryiv"); glad_glGetQueryObjectuiv = (PFNGLGETQUERYOBJECTUIVPROC)load("glGetQueryObjectuiv"); glad_glUnmapBuffer = (PFNGLUNMAPBUFFERPROC)load("glUnmapBuffer"); glad_glGetBufferPointerv = (PFNGLGETBUFFERPOINTERVPROC)load("glGetBufferPointerv"); glad_glDrawBuffers = (PFNGLDRAWBUFFERSPROC)load("glDrawBuffers"); glad_glUniformMatrix2x3fv = (PFNGLUNIFORMMATRIX2X3FVPROC)load("glUniformMatrix2x3fv"); glad_glUniformMatrix3x2fv = (PFNGLUNIFORMMATRIX3X2FVPROC)load("glUniformMatrix3x2fv"); glad_glUniformMatrix2x4fv = (PFNGLUNIFORMMATRIX2X4FVPROC)load("glUniformMatrix2x4fv"); glad_glUniformMatrix4x2fv = (PFNGLUNIFORMMATRIX4X2FVPROC)load("glUniformMatrix4x2fv"); glad_glUniformMatrix3x4fv = (PFNGLUNIFORMMATRIX3X4FVPROC)load("glUniformMatrix3x4fv"); glad_glUniformMatrix4x3fv = (PFNGLUNIFORMMATRIX4X3FVPROC)load("glUniformMatrix4x3fv"); glad_glBlitFramebuffer = (PFNGLBLITFRAMEBUFFERPROC)load("glBlitFramebuffer"); glad_glRenderbufferStorageMultisample = (PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC)load("glRenderbufferStorageMultisample"); glad_glFramebufferTextureLayer = (PFNGLFRAMEBUFFERTEXTURELAYERPROC)load("glFramebufferTextureLayer"); glad_glMapBufferRange = (PFNGLMAPBUFFERRANGEPROC)load("glMapBufferRange"); glad_glFlushMappedBufferRange = (PFNGLFLUSHMAPPEDBUFFERRANGEPROC)load("glFlushMappedBufferRange"); glad_glBindVertexArray = (PFNGLBINDVERTEXARRAYPROC)load("glBindVertexArray"); glad_glDeleteVertexArrays = (PFNGLDELETEVERTEXARRAYSPROC)load("glDeleteVertexArrays"); glad_glGenVertexArrays = (PFNGLGENVERTEXARRAYSPROC)load("glGenVertexArrays"); glad_glIsVertexArray = (PFNGLISVERTEXARRAYPROC)load("glIsVertexArray"); glad_glGetIntegeri_v = (PFNGLGETINTEGERI_VPROC)load("glGetIntegeri_v"); glad_glBeginTransformFeedback = (PFNGLBEGINTRANSFORMFEEDBACKPROC)load("glBeginTransformFeedback"); glad_glEndTransformFeedback = (PFNGLENDTRANSFORMFEEDBACKPROC)load("glEndTransformFeedback"); glad_glBindBufferRange = (PFNGLBINDBUFFERRANGEPROC)load("glBindBufferRange"); glad_glBindBufferBase = (PFNGLBINDBUFFERBASEPROC)load("glBindBufferBase"); glad_glTransformFeedbackVaryings = (PFNGLTRANSFORMFEEDBACKVARYINGSPROC)load("glTransformFeedbackVaryings"); glad_glGetTransformFeedbackVarying = (PFNGLGETTRANSFORMFEEDBACKVARYINGPROC)load("glGetTransformFeedbackVarying"); glad_glVertexAttribIPointer = (PFNGLVERTEXATTRIBIPOINTERPROC)load("glVertexAttribIPointer"); glad_glGetVertexAttribIiv = (PFNGLGETVERTEXATTRIBIIVPROC)load("glGetVertexAttribIiv"); glad_glGetVertexAttribIuiv = (PFNGLGETVERTEXATTRIBIUIVPROC)load("glGetVertexAttribIuiv"); glad_glVertexAttribI4i = (PFNGLVERTEXATTRIBI4IPROC)load("glVertexAttribI4i"); glad_glVertexAttribI4ui = (PFNGLVERTEXATTRIBI4UIPROC)load("glVertexAttribI4ui"); glad_glVertexAttribI4iv = (PFNGLVERTEXATTRIBI4IVPROC)load("glVertexAttribI4iv"); glad_glVertexAttribI4uiv = (PFNGLVERTEXATTRIBI4UIVPROC)load("glVertexAttribI4uiv"); glad_glGetUniformuiv = (PFNGLGETUNIFORMUIVPROC)load("glGetUniformuiv"); glad_glGetFragDataLocation = (PFNGLGETFRAGDATALOCATIONPROC)load("glGetFragDataLocation"); glad_glUniform1ui = (PFNGLUNIFORM1UIPROC)load("glUniform1ui"); glad_glUniform2ui = (PFNGLUNIFORM2UIPROC)load("glUniform2ui"); glad_glUniform3ui = (PFNGLUNIFORM3UIPROC)load("glUniform3ui"); glad_glUniform4ui = (PFNGLUNIFORM4UIPROC)load("glUniform4ui"); glad_glUniform1uiv = (PFNGLUNIFORM1UIVPROC)load("glUniform1uiv"); glad_glUniform2uiv = (PFNGLUNIFORM2UIVPROC)load("glUniform2uiv"); glad_glUniform3uiv = (PFNGLUNIFORM3UIVPROC)load("glUniform3uiv"); glad_glUniform4uiv = (PFNGLUNIFORM4UIVPROC)load("glUniform4uiv"); glad_glClearBufferiv = (PFNGLCLEARBUFFERIVPROC)load("glClearBufferiv"); glad_glClearBufferuiv = (PFNGLCLEARBUFFERUIVPROC)load("glClearBufferuiv"); glad_glClearBufferfv = (PFNGLCLEARBUFFERFVPROC)load("glClearBufferfv"); glad_glClearBufferfi = (PFNGLCLEARBUFFERFIPROC)load("glClearBufferfi"); glad_glGetStringi = (PFNGLGETSTRINGIPROC)load("glGetStringi"); glad_glCopyBufferSubData = (PFNGLCOPYBUFFERSUBDATAPROC)load("glCopyBufferSubData"); glad_glGetUniformIndices = (PFNGLGETUNIFORMINDICESPROC)load("glGetUniformIndices"); glad_glGetActiveUniformsiv = (PFNGLGETACTIVEUNIFORMSIVPROC)load("glGetActiveUniformsiv"); glad_glGetUniformBlockIndex = (PFNGLGETUNIFORMBLOCKINDEXPROC)load("glGetUniformBlockIndex"); glad_glGetActiveUniformBlockiv = (PFNGLGETACTIVEUNIFORMBLOCKIVPROC)load("glGetActiveUniformBlockiv"); glad_glGetActiveUniformBlockName = (PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC)load("glGetActiveUniformBlockName"); glad_glUniformBlockBinding = (PFNGLUNIFORMBLOCKBINDINGPROC)load("glUniformBlockBinding"); glad_glDrawArraysInstanced = (PFNGLDRAWARRAYSINSTANCEDPROC)load("glDrawArraysInstanced"); glad_glDrawElementsInstanced = (PFNGLDRAWELEMENTSINSTANCEDPROC)load("glDrawElementsInstanced"); glad_glFenceSync = (PFNGLFENCESYNCPROC)load("glFenceSync"); glad_glIsSync = (PFNGLISSYNCPROC)load("glIsSync"); glad_glDeleteSync = (PFNGLDELETESYNCPROC)load("glDeleteSync"); glad_glClientWaitSync = (PFNGLCLIENTWAITSYNCPROC)load("glClientWaitSync"); glad_glWaitSync = (PFNGLWAITSYNCPROC)load("glWaitSync"); glad_glGetInteger64v = (PFNGLGETINTEGER64VPROC)load("glGetInteger64v"); glad_glGetSynciv = (PFNGLGETSYNCIVPROC)load("glGetSynciv"); glad_glGetInteger64i_v = (PFNGLGETINTEGER64I_VPROC)load("glGetInteger64i_v"); glad_glGetBufferParameteri64v = (PFNGLGETBUFFERPARAMETERI64VPROC)load("glGetBufferParameteri64v"); glad_glGenSamplers = (PFNGLGENSAMPLERSPROC)load("glGenSamplers"); glad_glDeleteSamplers = (PFNGLDELETESAMPLERSPROC)load("glDeleteSamplers"); glad_glIsSampler = (PFNGLISSAMPLERPROC)load("glIsSampler"); glad_glBindSampler = (PFNGLBINDSAMPLERPROC)load("glBindSampler"); glad_glSamplerParameteri = (PFNGLSAMPLERPARAMETERIPROC)load("glSamplerParameteri"); glad_glSamplerParameteriv = (PFNGLSAMPLERPARAMETERIVPROC)load("glSamplerParameteriv"); glad_glSamplerParameterf = (PFNGLSAMPLERPARAMETERFPROC)load("glSamplerParameterf"); glad_glSamplerParameterfv = (PFNGLSAMPLERPARAMETERFVPROC)load("glSamplerParameterfv"); glad_glGetSamplerParameteriv = (PFNGLGETSAMPLERPARAMETERIVPROC)load("glGetSamplerParameteriv"); glad_glGetSamplerParameterfv = (PFNGLGETSAMPLERPARAMETERFVPROC)load("glGetSamplerParameterfv"); glad_glVertexAttribDivisor = (PFNGLVERTEXATTRIBDIVISORPROC)load("glVertexAttribDivisor"); glad_glBindTransformFeedback = (PFNGLBINDTRANSFORMFEEDBACKPROC)load("glBindTransformFeedback"); glad_glDeleteTransformFeedbacks = (PFNGLDELETETRANSFORMFEEDBACKSPROC)load("glDeleteTransformFeedbacks"); glad_glGenTransformFeedbacks = (PFNGLGENTRANSFORMFEEDBACKSPROC)load("glGenTransformFeedbacks"); glad_glIsTransformFeedback = (PFNGLISTRANSFORMFEEDBACKPROC)load("glIsTransformFeedback"); glad_glPauseTransformFeedback = (PFNGLPAUSETRANSFORMFEEDBACKPROC)load("glPauseTransformFeedback"); glad_glResumeTransformFeedback = (PFNGLRESUMETRANSFORMFEEDBACKPROC)load("glResumeTransformFeedback"); glad_glGetProgramBinary = (PFNGLGETPROGRAMBINARYPROC)load("glGetProgramBinary"); glad_glProgramBinary = (PFNGLPROGRAMBINARYPROC)load("glProgramBinary"); glad_glProgramParameteri = (PFNGLPROGRAMPARAMETERIPROC)load("glProgramParameteri"); glad_glInvalidateFramebuffer = (PFNGLINVALIDATEFRAMEBUFFERPROC)load("glInvalidateFramebuffer"); glad_glInvalidateSubFramebuffer = (PFNGLINVALIDATESUBFRAMEBUFFERPROC)load("glInvalidateSubFramebuffer"); glad_glTexStorage2D = (PFNGLTEXSTORAGE2DPROC)load("glTexStorage2D"); glad_glTexStorage3D = (PFNGLTEXSTORAGE3DPROC)load("glTexStorage3D"); glad_glGetInternalformativ = (PFNGLGETINTERNALFORMATIVPROC)load("glGetInternalformativ"); } static void load_GL_ES_VERSION_3_1(GLADloadproc load) { if(!GLAD_GL_ES_VERSION_3_1) return; glad_glDispatchCompute = (PFNGLDISPATCHCOMPUTEPROC)load("glDispatchCompute"); glad_glDispatchComputeIndirect = (PFNGLDISPATCHCOMPUTEINDIRECTPROC)load("glDispatchComputeIndirect"); glad_glDrawArraysIndirect = (PFNGLDRAWARRAYSINDIRECTPROC)load("glDrawArraysIndirect"); glad_glDrawElementsIndirect = (PFNGLDRAWELEMENTSINDIRECTPROC)load("glDrawElementsIndirect"); glad_glFramebufferParameteri = (PFNGLFRAMEBUFFERPARAMETERIPROC)load("glFramebufferParameteri"); glad_glGetFramebufferParameteriv = (PFNGLGETFRAMEBUFFERPARAMETERIVPROC)load("glGetFramebufferParameteriv"); glad_glGetProgramInterfaceiv = (PFNGLGETPROGRAMINTERFACEIVPROC)load("glGetProgramInterfaceiv"); glad_glGetProgramResourceIndex = (PFNGLGETPROGRAMRESOURCEINDEXPROC)load("glGetProgramResourceIndex"); glad_glGetProgramResourceName = (PFNGLGETPROGRAMRESOURCENAMEPROC)load("glGetProgramResourceName"); glad_glGetProgramResourceiv = (PFNGLGETPROGRAMRESOURCEIVPROC)load("glGetProgramResourceiv"); glad_glGetProgramResourceLocation = (PFNGLGETPROGRAMRESOURCELOCATIONPROC)load("glGetProgramResourceLocation"); glad_glUseProgramStages = (PFNGLUSEPROGRAMSTAGESPROC)load("glUseProgramStages"); glad_glActiveShaderProgram = (PFNGLACTIVESHADERPROGRAMPROC)load("glActiveShaderProgram"); glad_glCreateShaderProgramv = (PFNGLCREATESHADERPROGRAMVPROC)load("glCreateShaderProgramv"); glad_glBindProgramPipeline = (PFNGLBINDPROGRAMPIPELINEPROC)load("glBindProgramPipeline"); glad_glDeleteProgramPipelines = (PFNGLDELETEPROGRAMPIPELINESPROC)load("glDeleteProgramPipelines"); glad_glGenProgramPipelines = (PFNGLGENPROGRAMPIPELINESPROC)load("glGenProgramPipelines"); glad_glIsProgramPipeline = (PFNGLISPROGRAMPIPELINEPROC)load("glIsProgramPipeline"); glad_glGetProgramPipelineiv = (PFNGLGETPROGRAMPIPELINEIVPROC)load("glGetProgramPipelineiv"); glad_glProgramUniform1i = (PFNGLPROGRAMUNIFORM1IPROC)load("glProgramUniform1i"); glad_glProgramUniform2i = (PFNGLPROGRAMUNIFORM2IPROC)load("glProgramUniform2i"); glad_glProgramUniform3i = (PFNGLPROGRAMUNIFORM3IPROC)load("glProgramUniform3i"); glad_glProgramUniform4i = (PFNGLPROGRAMUNIFORM4IPROC)load("glProgramUniform4i"); glad_glProgramUniform1ui = (PFNGLPROGRAMUNIFORM1UIPROC)load("glProgramUniform1ui"); glad_glProgramUniform2ui = (PFNGLPROGRAMUNIFORM2UIPROC)load("glProgramUniform2ui"); glad_glProgramUniform3ui = (PFNGLPROGRAMUNIFORM3UIPROC)load("glProgramUniform3ui"); glad_glProgramUniform4ui = (PFNGLPROGRAMUNIFORM4UIPROC)load("glProgramUniform4ui"); glad_glProgramUniform1f = (PFNGLPROGRAMUNIFORM1FPROC)load("glProgramUniform1f"); glad_glProgramUniform2f = (PFNGLPROGRAMUNIFORM2FPROC)load("glProgramUniform2f"); glad_glProgramUniform3f = (PFNGLPROGRAMUNIFORM3FPROC)load("glProgramUniform3f"); glad_glProgramUniform4f = (PFNGLPROGRAMUNIFORM4FPROC)load("glProgramUniform4f"); glad_glProgramUniform1iv = (PFNGLPROGRAMUNIFORM1IVPROC)load("glProgramUniform1iv"); glad_glProgramUniform2iv = (PFNGLPROGRAMUNIFORM2IVPROC)load("glProgramUniform2iv"); glad_glProgramUniform3iv = (PFNGLPROGRAMUNIFORM3IVPROC)load("glProgramUniform3iv"); glad_glProgramUniform4iv = (PFNGLPROGRAMUNIFORM4IVPROC)load("glProgramUniform4iv"); glad_glProgramUniform1uiv = (PFNGLPROGRAMUNIFORM1UIVPROC)load("glProgramUniform1uiv"); glad_glProgramUniform2uiv = (PFNGLPROGRAMUNIFORM2UIVPROC)load("glProgramUniform2uiv"); glad_glProgramUniform3uiv = (PFNGLPROGRAMUNIFORM3UIVPROC)load("glProgramUniform3uiv"); glad_glProgramUniform4uiv = (PFNGLPROGRAMUNIFORM4UIVPROC)load("glProgramUniform4uiv"); glad_glProgramUniform1fv = (PFNGLPROGRAMUNIFORM1FVPROC)load("glProgramUniform1fv"); glad_glProgramUniform2fv = (PFNGLPROGRAMUNIFORM2FVPROC)load("glProgramUniform2fv"); glad_glProgramUniform3fv = (PFNGLPROGRAMUNIFORM3FVPROC)load("glProgramUniform3fv"); glad_glProgramUniform4fv = (PFNGLPROGRAMUNIFORM4FVPROC)load("glProgramUniform4fv"); glad_glProgramUniformMatrix2fv = (PFNGLPROGRAMUNIFORMMATRIX2FVPROC)load("glProgramUniformMatrix2fv"); glad_glProgramUniformMatrix3fv = (PFNGLPROGRAMUNIFORMMATRIX3FVPROC)load("glProgramUniformMatrix3fv"); glad_glProgramUniformMatrix4fv = (PFNGLPROGRAMUNIFORMMATRIX4FVPROC)load("glProgramUniformMatrix4fv"); glad_glProgramUniformMatrix2x3fv = (PFNGLPROGRAMUNIFORMMATRIX2X3FVPROC)load("glProgramUniformMatrix2x3fv"); glad_glProgramUniformMatrix3x2fv = (PFNGLPROGRAMUNIFORMMATRIX3X2FVPROC)load("glProgramUniformMatrix3x2fv"); glad_glProgramUniformMatrix2x4fv = (PFNGLPROGRAMUNIFORMMATRIX2X4FVPROC)load("glProgramUniformMatrix2x4fv"); glad_glProgramUniformMatrix4x2fv = (PFNGLPROGRAMUNIFORMMATRIX4X2FVPROC)load("glProgramUniformMatrix4x2fv"); glad_glProgramUniformMatrix3x4fv = (PFNGLPROGRAMUNIFORMMATRIX3X4FVPROC)load("glProgramUniformMatrix3x4fv"); glad_glProgramUniformMatrix4x3fv = (PFNGLPROGRAMUNIFORMMATRIX4X3FVPROC)load("glProgramUniformMatrix4x3fv"); glad_glValidateProgramPipeline = (PFNGLVALIDATEPROGRAMPIPELINEPROC)load("glValidateProgramPipeline"); glad_glGetProgramPipelineInfoLog = (PFNGLGETPROGRAMPIPELINEINFOLOGPROC)load("glGetProgramPipelineInfoLog"); glad_glBindImageTexture = (PFNGLBINDIMAGETEXTUREPROC)load("glBindImageTexture"); glad_glGetBooleani_v = (PFNGLGETBOOLEANI_VPROC)load("glGetBooleani_v"); glad_glMemoryBarrier = (PFNGLMEMORYBARRIERPROC)load("glMemoryBarrier"); glad_glMemoryBarrierByRegion = (PFNGLMEMORYBARRIERBYREGIONPROC)load("glMemoryBarrierByRegion"); glad_glTexStorage2DMultisample = (PFNGLTEXSTORAGE2DMULTISAMPLEPROC)load("glTexStorage2DMultisample"); glad_glGetMultisamplefv = (PFNGLGETMULTISAMPLEFVPROC)load("glGetMultisamplefv"); glad_glSampleMaski = (PFNGLSAMPLEMASKIPROC)load("glSampleMaski"); glad_glGetTexLevelParameteriv = (PFNGLGETTEXLEVELPARAMETERIVPROC)load("glGetTexLevelParameteriv"); glad_glGetTexLevelParameterfv = (PFNGLGETTEXLEVELPARAMETERFVPROC)load("glGetTexLevelParameterfv"); glad_glBindVertexBuffer = (PFNGLBINDVERTEXBUFFERPROC)load("glBindVertexBuffer"); glad_glVertexAttribFormat = (PFNGLVERTEXATTRIBFORMATPROC)load("glVertexAttribFormat"); glad_glVertexAttribIFormat = (PFNGLVERTEXATTRIBIFORMATPROC)load("glVertexAttribIFormat"); glad_glVertexAttribBinding = (PFNGLVERTEXATTRIBBINDINGPROC)load("glVertexAttribBinding"); glad_glVertexBindingDivisor = (PFNGLVERTEXBINDINGDIVISORPROC)load("glVertexBindingDivisor"); } static void load_GL_ES_VERSION_3_2(GLADloadproc load) { if(!GLAD_GL_ES_VERSION_3_2) return; glad_glBlendBarrier = (PFNGLBLENDBARRIERPROC)load("glBlendBarrier"); glad_glCopyImageSubData = (PFNGLCOPYIMAGESUBDATAPROC)load("glCopyImageSubData"); glad_glDebugMessageControl = (PFNGLDEBUGMESSAGECONTROLPROC)load("glDebugMessageControl"); glad_glDebugMessageInsert = (PFNGLDEBUGMESSAGEINSERTPROC)load("glDebugMessageInsert"); glad_glDebugMessageCallback = (PFNGLDEBUGMESSAGECALLBACKPROC)load("glDebugMessageCallback"); glad_glGetDebugMessageLog = (PFNGLGETDEBUGMESSAGELOGPROC)load("glGetDebugMessageLog"); glad_glPushDebugGroup = (PFNGLPUSHDEBUGGROUPPROC)load("glPushDebugGroup"); glad_glPopDebugGroup = (PFNGLPOPDEBUGGROUPPROC)load("glPopDebugGroup"); glad_glObjectLabel = (PFNGLOBJECTLABELPROC)load("glObjectLabel"); glad_glGetObjectLabel = (PFNGLGETOBJECTLABELPROC)load("glGetObjectLabel"); glad_glObjectPtrLabel = (PFNGLOBJECTPTRLABELPROC)load("glObjectPtrLabel"); glad_glGetObjectPtrLabel = (PFNGLGETOBJECTPTRLABELPROC)load("glGetObjectPtrLabel"); glad_glGetPointerv = (PFNGLGETPOINTERVPROC)load("glGetPointerv"); glad_glEnablei = (PFNGLENABLEIPROC)load("glEnablei"); glad_glDisablei = (PFNGLDISABLEIPROC)load("glDisablei"); glad_glBlendEquationi = (PFNGLBLENDEQUATIONIPROC)load("glBlendEquationi"); glad_glBlendEquationSeparatei = (PFNGLBLENDEQUATIONSEPARATEIPROC)load("glBlendEquationSeparatei"); glad_glBlendFunci = (PFNGLBLENDFUNCIPROC)load("glBlendFunci"); glad_glBlendFuncSeparatei = (PFNGLBLENDFUNCSEPARATEIPROC)load("glBlendFuncSeparatei"); glad_glColorMaski = (PFNGLCOLORMASKIPROC)load("glColorMaski"); glad_glIsEnabledi = (PFNGLISENABLEDIPROC)load("glIsEnabledi"); glad_glDrawElementsBaseVertex = (PFNGLDRAWELEMENTSBASEVERTEXPROC)load("glDrawElementsBaseVertex"); glad_glDrawRangeElementsBaseVertex = (PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC)load("glDrawRangeElementsBaseVertex"); glad_glDrawElementsInstancedBaseVertex = (PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC)load("glDrawElementsInstancedBaseVertex"); glad_glFramebufferTexture = (PFNGLFRAMEBUFFERTEXTUREPROC)load("glFramebufferTexture"); glad_glPrimitiveBoundingBox = (PFNGLPRIMITIVEBOUNDINGBOXPROC)load("glPrimitiveBoundingBox"); glad_glGetGraphicsResetStatus = (PFNGLGETGRAPHICSRESETSTATUSPROC)load("glGetGraphicsResetStatus"); glad_glReadnPixels = (PFNGLREADNPIXELSPROC)load("glReadnPixels"); glad_glGetnUniformfv = (PFNGLGETNUNIFORMFVPROC)load("glGetnUniformfv"); glad_glGetnUniformiv = (PFNGLGETNUNIFORMIVPROC)load("glGetnUniformiv"); glad_glGetnUniformuiv = (PFNGLGETNUNIFORMUIVPROC)load("glGetnUniformuiv"); glad_glMinSampleShading = (PFNGLMINSAMPLESHADINGPROC)load("glMinSampleShading"); glad_glPatchParameteri = (PFNGLPATCHPARAMETERIPROC)load("glPatchParameteri"); glad_glTexParameterIiv = (PFNGLTEXPARAMETERIIVPROC)load("glTexParameterIiv"); glad_glTexParameterIuiv = (PFNGLTEXPARAMETERIUIVPROC)load("glTexParameterIuiv"); glad_glGetTexParameterIiv = (PFNGLGETTEXPARAMETERIIVPROC)load("glGetTexParameterIiv"); glad_glGetTexParameterIuiv = (PFNGLGETTEXPARAMETERIUIVPROC)load("glGetTexParameterIuiv"); glad_glSamplerParameterIiv = (PFNGLSAMPLERPARAMETERIIVPROC)load("glSamplerParameterIiv"); glad_glSamplerParameterIuiv = (PFNGLSAMPLERPARAMETERIUIVPROC)load("glSamplerParameterIuiv"); glad_glGetSamplerParameterIiv = (PFNGLGETSAMPLERPARAMETERIIVPROC)load("glGetSamplerParameterIiv"); glad_glGetSamplerParameterIuiv = (PFNGLGETSAMPLERPARAMETERIUIVPROC)load("glGetSamplerParameterIuiv"); glad_glTexBuffer = (PFNGLTEXBUFFERPROC)load("glTexBuffer"); glad_glTexBufferRange = (PFNGLTEXBUFFERRANGEPROC)load("glTexBufferRange"); glad_glTexStorage3DMultisample = (PFNGLTEXSTORAGE3DMULTISAMPLEPROC)load("glTexStorage3DMultisample"); } static void load_GL_EXT_clip_control(GLADloadproc load) { if(!GLAD_GL_EXT_clip_control) return; glad_glClipControlEXT = (PFNGLCLIPCONTROLEXTPROC)load("glClipControlEXT"); } static int find_extensionsGLES2(void) { if (!get_exts()) return 0; GLAD_GL_EXT_clip_control = has_ext("GL_EXT_clip_control"); free_exts(); return 1; } static void find_coreGLES2(void) { /* Thank you @elmindreda * https://github.com/elmindreda/greg/blob/master/templates/greg.c.in#L176 * https://github.com/glfw/glfw/blob/master/src/context.c#L36 */ int i, major, minor; const char* version; const char* prefixes[] = { "OpenGL ES-CM ", "OpenGL ES-CL ", "OpenGL ES ", NULL }; version = (const char*) glGetString(GL_VERSION); if (!version) return; for (i = 0; prefixes[i]; i++) { const size_t length = strlen(prefixes[i]); if (strncmp(version, prefixes[i], length) == 0) { version += length; break; } } /* PR #18 */ #ifdef _MSC_VER sscanf_s(version, "%d.%d", &major, &minor); #else sscanf(version, "%d.%d", &major, &minor); #endif GLVersion.major = major; GLVersion.minor = minor; max_loaded_major = major; max_loaded_minor = minor; GLAD_GL_ES_VERSION_2_0 = (major == 2 && minor >= 0) || major > 2; GLAD_GL_ES_VERSION_3_0 = (major == 3 && minor >= 0) || major > 3; GLAD_GL_ES_VERSION_3_1 = (major == 3 && minor >= 1) || major > 3; GLAD_GL_ES_VERSION_3_2 = (major == 3 && minor >= 2) || major > 3; if (GLVersion.major > 3 || (GLVersion.major >= 3 && GLVersion.minor >= 2)) { max_loaded_major = 3; max_loaded_minor = 2; } } int gladLoadGLES2Loader(GLADloadproc load) { GLVersion.major = 0; GLVersion.minor = 0; glGetString = (PFNGLGETSTRINGPROC)load("glGetString"); if(glGetString == NULL) return 0; if(glGetString(GL_VERSION) == NULL) return 0; find_coreGLES2(); load_GL_ES_VERSION_2_0(load); load_GL_ES_VERSION_3_0(load); load_GL_ES_VERSION_3_1(load); load_GL_ES_VERSION_3_2(load); if (!find_extensionsGLES2()) return 0; load_GL_EXT_clip_control(load); return GLVersion.major != 0 || GLVersion.minor != 0; } ================================================ FILE: src/gl/inject_egl.cpp ================================================ #include #include #include #include #include #include #include #include #include "real_dlsym.h" #include "mesa/util/macros.h" #include "mesa/util/os_time.h" #include "blacklist.h" #include "gl_hud.h" #include "elfhacks.h" #ifdef HAVE_WAYLAND #include "wayland_hook.h" #endif #include "../fps_limiter.h" using namespace MangoHud::GL; #ifndef EGL_WIDTH #define EGL_HEIGHT 0x3056 #define EGL_WIDTH 0x3057 #define EGL_DRAW 0x3059 #define EGL_READ 0x305A #endif #define EGL_PLATFORM_WAYLAND_KHR 0x31D8 // single global lock, for simplicity static std::mutex global_lock; typedef std::lock_guard scoped_lock; static std::unordered_map gl_contexts; EXPORT_C_(void *) eglGetProcAddress(const char* procName); static void* get_egl_proc_address(const char* name) { void *func = nullptr; static void *(*pfn_eglGetProcAddress)(const char*) = nullptr; const char *libs[] = { "*libEGL.so.*", "*libEGL_mesa.so.*", "*libEGL_nvidia.so.*" }; if (!pfn_eglGetProcAddress) { eh_obj_t lib_egl; int ret; for (uint i = 0; i < sizeof(libs)/sizeof(*libs); i++) { ret = eh_find_obj(&lib_egl, libs[i]); if (ret) continue; eh_find_sym(&lib_egl, "eglGetProcAddress", (void **)&pfn_eglGetProcAddress); eh_destroy_obj(&lib_egl); if (pfn_eglGetProcAddress) break; } } if (pfn_eglGetProcAddress) func = pfn_eglGetProcAddress(name); if (!func) func = get_proc_address( name ); if (!func) { SPDLOG_ERROR("Failed to get function '{}'", name); } return func; } static gl_context *create_gl_context(void *ctx) { gl_context *gl_ctx; gl_ctx = (gl_context *)calloc(1, sizeof(*gl_ctx)); gl_ctx->ctx = ctx; gl_contexts[ctx] = gl_ctx; //SPDLOG_DEBUG("created gl_context {} for GLX context {}", (void *)gl_ctx, ctx); return gl_ctx; } static void destroy_gl_context(gl_context *gl_ctx) { //SPDLOG_DEBUG("destroying gl_context {} for GLX context {}", (void *)gl_ctx, gl_ctx->ctx); gl_contexts.erase(gl_ctx->ctx); free(gl_ctx); } EXPORT_C_(unsigned int) eglDestroyContext(void* dpy, void* ctx); EXPORT_C_(unsigned int) eglDestroyContext(void* dpy, void* ctx) { static unsigned int (*pfn_eglDestroyContext)(void* dpy, void* ctx) = nullptr; ::scoped_lock lk(global_lock); gl_context *gl_ctx = gl_contexts[ctx]; void *current_ctx, *draw, *read = nullptr; int r; if (!pfn_eglDestroyContext) pfn_eglDestroyContext = reinterpret_cast(get_egl_proc_address("eglDestroyContext")); if (gl_ctx) { static void* (*pfn_eglGetCurrentContext)() = nullptr; if (!pfn_eglGetCurrentContext) pfn_eglGetCurrentContext = reinterpret_cast(get_egl_proc_address("eglGetCurrentContext")); static void* (*pfn_eglGetCurrentSurface)(int readdraw) = nullptr; if (!pfn_eglGetCurrentSurface) pfn_eglGetCurrentSurface = reinterpret_cast(get_egl_proc_address("eglGetCurrentSurface")); static unsigned int (*pfn_eglMakeCurrent)(void* dpy, void* draw, void* read, void* ctx) = nullptr; if (!pfn_eglMakeCurrent) pfn_eglMakeCurrent = reinterpret_cast(get_egl_proc_address("eglMakeCurrent")); current_ctx = pfn_eglGetCurrentContext(); draw = pfn_eglGetCurrentSurface(EGL_DRAW); read = pfn_eglGetCurrentSurface(EGL_READ); //SPDLOG_DEBUG("gl_context {}, current_ctx {}, draw {}, read {}", (void *)gl_ctx, current_ctx, draw, read); r = pfn_eglMakeCurrent(dpy, draw, read, ctx); if (r) { imgui_shutdown(gl_ctx, gl_contexts.size() == 1); pfn_eglMakeCurrent(dpy, draw, read, current_ctx); } destroy_gl_context(gl_ctx); } return pfn_eglDestroyContext(dpy, ctx); } EXPORT_C_(unsigned int) eglSwapBuffers(void* dpy, void* surf); EXPORT_C_(unsigned int) eglSwapBuffers(void* dpy, void* surf) { static int (*pfn_eglSwapBuffers)(void*, void*) = nullptr; if (!pfn_eglSwapBuffers) pfn_eglSwapBuffers = reinterpret_cast(get_egl_proc_address("eglSwapBuffers")); if (!is_blacklisted()) { static int (*pfn_eglQuerySurface)(void* dpy, void* surface, int attribute, int *value) = nullptr; if (!pfn_eglQuerySurface) pfn_eglQuerySurface = reinterpret_cast(get_egl_proc_address("eglQuerySurface")); static void* (*pfn_eglGetCurrentContext)() = nullptr; if (!pfn_eglGetCurrentContext) pfn_eglGetCurrentContext = reinterpret_cast(get_egl_proc_address("eglGetCurrentContext")); ::scoped_lock lk(global_lock); void* ctx = pfn_eglGetCurrentContext(); gl_context *gl_ctx = gl_contexts[ctx]; if (!gl_ctx) gl_ctx = create_gl_context(ctx); imgui_create(gl_ctx, gl_wsi::GL_WSI_EGL); int width=0, height=0; if (pfn_eglQuerySurface(dpy, surf, EGL_HEIGHT, &height) && pfn_eglQuerySurface(dpy, surf, EGL_WIDTH, &width)) imgui_render(gl_ctx, width, height); if (fps_limiter) fps_limiter->limit(true); } int res = pfn_eglSwapBuffers(dpy, surf); if (!is_blacklisted()) { if (fps_limiter) fps_limiter->limit(false); } return res; } EXPORT_C_(void*) eglGetPlatformDisplay( unsigned int platform, void* native_display, const intptr_t* attrib_list); EXPORT_C_(void*) eglGetPlatformDisplay( unsigned int platform, void* native_display, const intptr_t* attrib_list) { void *ret; static void* (*pfn_eglGetPlatformDisplay)(unsigned int, void*, const intptr_t*) = nullptr; if (!pfn_eglGetPlatformDisplay) pfn_eglGetPlatformDisplay = reinterpret_cast(get_egl_proc_address("eglGetPlatformDisplay")); ret = pfn_eglGetPlatformDisplay(platform, native_display, attrib_list); #ifdef HAVE_WAYLAND if (platform == EGL_PLATFORM_WAYLAND_KHR && ret) { HUDElements.display_server = HUDElements.display_servers::WAYLAND; init_wayland_data((struct wl_display*)native_display, ret); } #endif return ret; } EXPORT_C_(void*) eglGetDisplay( void* native_display ); EXPORT_C_(void*) eglGetDisplay( void* native_display ) { void *ret; static void* (*pfn_eglGetDisplay)(void*) = nullptr; if (!pfn_eglGetDisplay) pfn_eglGetDisplay = reinterpret_cast(get_egl_proc_address("eglGetDisplay")); ret = pfn_eglGetDisplay(native_display); #ifdef HAVE_WAYLAND try { void** display_ptr = (void**)native_display; if (native_display && ret) { wl_interface* iface = (wl_interface*)*display_ptr; if (iface && strcmp(iface->name, wl_display_interface.name) == 0) { HUDElements.display_server = HUDElements.display_servers::WAYLAND; init_wayland_data((struct wl_display*)native_display, ret); } } } catch(...) { } #endif return ret; } EXPORT_C_(int) eglTerminate(void *display); EXPORT_C_(int) eglTerminate(void *display) { int ret; static int (*pfn_eglTerminate)(void*) = nullptr; if (!pfn_eglTerminate) pfn_eglTerminate = reinterpret_cast(get_egl_proc_address("eglTerminate")); ret = pfn_eglTerminate(display); #ifdef HAVE_WAYLAND if (ret) { wayland_data_unref(NULL, display); } #endif return ret; } struct func_ptr { const char *name; void *ptr; }; static std::array name_to_funcptr_map = {{ #define ADD_HOOK(fn) { #fn, (void *) fn } ADD_HOOK(eglDestroyContext), ADD_HOOK(eglGetDisplay), ADD_HOOK(eglGetPlatformDisplay), ADD_HOOK(eglGetProcAddress), ADD_HOOK(eglSwapBuffers), ADD_HOOK(eglTerminate) #undef ADD_HOOK }}; EXPORT_C_(void *) mangohud_find_egl_ptr(const char *name); EXPORT_C_(void *) mangohud_find_egl_ptr(const char *name) { if (is_blacklisted()) return nullptr; for (auto& func : name_to_funcptr_map) { if (strcmp(name, func.name) == 0) return func.ptr; } return nullptr; } EXPORT_C_(void *) eglGetProcAddress(const char* procName) { void* real_func = get_egl_proc_address(procName); void* func = mangohud_find_egl_ptr(procName); SPDLOG_TRACE("{}: proc: {}, real: {}, fun: {}", __func__, procName, real_func, func); if (func && real_func) return func; return real_func; } ================================================ FILE: src/gl/inject_glx.cpp ================================================ #include #include #include #include #include #include #include #include #include #include #include "real_dlsym.h" #include "loaders/loader_glx.h" #include "loaders/loader_x11.h" #include "mesa/util/macros.h" #include "mesa/util/os_time.h" #include "blacklist.h" #include #include #include #include "gl_hud.h" #include "../config.h" #include "../fps_limiter.h" using namespace MangoHud::GL; #ifndef GLX_WIDTH #define GLX_WIDTH 0x801D #define GLX_HEIGHT 0x801E #endif static glx_loader glx; // single global lock, for simplicity static std::mutex global_lock; typedef std::lock_guard scoped_lock; static std::unordered_map gl_contexts; static void* get_glx_proc_address(const char* name) { glx.Load(); void *func = nullptr; if (glx.GetProcAddress) func = glx.GetProcAddress( (const unsigned char*) name ); if (!func && glx.GetProcAddressARB) func = glx.GetProcAddressARB( (const unsigned char*) name ); if (!func) func = get_proc_address( name ); if (!func) { SPDLOG_ERROR("Failed to get function '{}'", name); } return func; } bool glx_mesa_queryInteger(int attrib, unsigned int *value); bool glx_mesa_queryInteger(int attrib, unsigned int *value) { static int (*pfn_queryInteger)(int attribute, unsigned int *value) = reinterpret_cast(get_glx_proc_address( "glXQueryCurrentRendererIntegerMESA")); if (pfn_queryInteger) return !!pfn_queryInteger(attrib, value); return false; } static gl_context *create_gl_context(void *ctx) { gl_context *gl_ctx; gl_ctx = (gl_context *)calloc(1, sizeof(*gl_ctx)); gl_ctx->ctx = ctx; gl_contexts[ctx] = gl_ctx; //SPDLOG_DEBUG("created gl_context {} for GLX context {}", (void *)gl_ctx, ctx); return gl_ctx; } static void destroy_gl_context(gl_context *gl_ctx) { //SPDLOG_DEBUG("destroying gl_context {} for GLX context {}", (void *)gl_ctx, gl_ctx->ctx); gl_contexts.erase(gl_ctx->ctx); free(gl_ctx); } EXPORT_C_(void) glXDestroyContext(void *dpy, void *ctx) { ::scoped_lock lk(global_lock); gl_context *gl_ctx = gl_contexts[ctx]; void *current_ctx, *draw, *read = nullptr; int r; SPDLOG_DEBUG("{}: {}", __func__, ctx); glx.Load(); if (gl_ctx) { current_ctx = glx.GetCurrentContext(); draw = glx.GetCurrentDrawable(); if (glx.GetCurrentReadDrawable) read = glx.GetCurrentReadDrawable(); //SPDLOG_DEBUG("gl_context {}, current_ctx {}, draw {}, read {}", (void *)gl_ctx, current_ctx, draw, read); if (glx.MakeContextCurrent) r = glx.MakeContextCurrent(dpy, draw, read, ctx); else r = glx.MakeCurrent(dpy, draw, ctx); if (r) { imgui_shutdown(gl_ctx, gl_contexts.size() == 1); if (glx.MakeContextCurrent) glx.MakeContextCurrent(dpy, draw, read, current_ctx); else glx.MakeCurrent(dpy, draw, current_ctx); } destroy_gl_context(gl_ctx); } glx.DestroyContext(dpy, ctx); } #ifndef GLX_SWAP_INTERVAL_EXT #define GLX_SWAP_INTERVAL_EXT 0x20F1 #endif static void do_imgui_swap(void *dpy, void *drawable) { static auto last_time = std::chrono::steady_clock::now(); auto current_time = std::chrono::steady_clock::now(); // if bufferSize is 0 then glXQueryDrawable is probably not working // this is the case with llvmpipe unsigned int bufferSize; glx.QueryDrawable(dpy, drawable, GL_BUFFER_SIZE, &bufferSize); std::chrono::duration elapsed_seconds = current_time - last_time; if (bufferSize != 0 && (HUDElements.vsync == 10 || elapsed_seconds.count() > 5.0)) glx.QueryDrawable(dpy, drawable, GLX_SWAP_INTERVAL_EXT, &HUDElements.vsync); GLint vp[4]; if (!is_blacklisted()) { ::scoped_lock lk(global_lock); void *ctx = glx.GetCurrentContext(); gl_context *gl_ctx = gl_contexts[ctx]; //SPDLOG_TRACE("ctx {}, gl_ctx {}", ctx, (void *)gl_ctx); if (!gl_ctx) gl_ctx = create_gl_context(ctx); imgui_create(gl_ctx, gl_wsi::GL_WSI_GLX); unsigned int width = -1, height = -1; switch (get_params()->gl_size_query) { case GL_SIZE_VIEWPORT: glGetIntegerv (GL_VIEWPORT, vp); width = vp[2]; height = vp[3]; break; case GL_SIZE_SCISSORBOX: glGetIntegerv (GL_SCISSOR_BOX, vp); width = vp[2]; height = vp[3]; break; default: glx.QueryDrawable(dpy, drawable, GLX_WIDTH, &width); glx.QueryDrawable(dpy, drawable, GLX_HEIGHT, &height); break; } SPDLOG_TRACE("swap buffers: {}x{}", width, height); imgui_render(gl_ctx, width, height); } } static void set_swap_interval(void* dpy, void* drawable, int interval) { ::scoped_lock lk(global_lock); void* ctx = glx.GetCurrentContext(); gl_context *gl_ctx = gl_contexts[ctx]; if (!is_blacklisted() || interval >= 0) { std::shared_ptr real_params; if (gl_ctx) { if (gl_ctx->swap_interval_set && interval < -1) return; if (!is_blacklisted()) { imgui_create(gl_ctx, gl_wsi::GL_WSI_GLX); real_params = get_params(); } } // Disabled: -1 is outside of the GLX_SWAP_INTERVAL_EXT spec and will crash with BadValue in Zink. // Original code kept for reference: // if (glx.SwapIntervalEXT && ((real_params && real_params->gl_vsync >= -1) || (interval >= -1 && dpy && drawable))) // { // glx.SwapIntervalEXT(dpy, drawable, real_params && real_params->gl_vsync >= -1 ? real_params->gl_vsync : interval); // } if ((real_params && real_params->gl_vsync >= 0) || interval >= 0) { if (glx.SwapIntervalSGI) glx.SwapIntervalSGI(real_params && real_params->gl_vsync >= 0 ? real_params->gl_vsync : interval); if (glx.SwapIntervalMESA) glx.SwapIntervalMESA(real_params && real_params->gl_vsync >= 0 ? real_params->gl_vsync : interval); } if (gl_ctx) gl_ctx->swap_interval_set = true; } } EXPORT_C_(void) glXSwapBuffers(void* dpy, void* drawable) { glx.Load(); SPDLOG_TRACE("{}: {}", __func__, drawable); do_imgui_swap(dpy, drawable); set_swap_interval(dpy, drawable, -2); if (fps_limiter) fps_limiter->limit(true); glx.SwapBuffers(dpy, drawable); if (!is_blacklisted()) if (fps_limiter) fps_limiter->limit(false); } EXPORT_C_(int64_t) glXSwapBuffersMscOML(void* dpy, void* drawable, int64_t target_msc, int64_t divisor, int64_t remainder) { glx.Load(); SPDLOG_DEBUG("{}: {}, {}, {}, {}", __func__, drawable, target_msc, divisor, remainder); if (!glx.SwapBuffersMscOML) return -1; do_imgui_swap(dpy, drawable); set_swap_interval(dpy, drawable, -2); if (fps_limiter) fps_limiter->limit(true); int64_t ret = glx.SwapBuffersMscOML(dpy, drawable, target_msc, divisor, remainder); if (!is_blacklisted()) if (fps_limiter) fps_limiter->limit(true); return ret; } EXPORT_C_(void) glXSwapIntervalEXT(void *dpy, void *draw, int interval) { SPDLOG_DEBUG("{}: {}, {}", __func__, draw, interval); glx.Load(); if (!glx.SwapIntervalEXT) return; set_swap_interval(dpy, draw, interval); } EXPORT_C_(int) glXSwapIntervalSGI(int interval) { SPDLOG_DEBUG("{}: {}", __func__, interval); glx.Load(); if (!glx.SwapIntervalSGI) return -1; set_swap_interval(nullptr, nullptr, interval); return 0; } EXPORT_C_(int) glXSwapIntervalMESA(unsigned int interval) { SPDLOG_DEBUG("{}: {}", __func__, interval); glx.Load(); if (!glx.SwapIntervalMESA) return -1; set_swap_interval(nullptr, nullptr, interval); return 0; } EXPORT_C_(int) glXGetSwapIntervalMESA() { glx.Load(); if (!glx.GetSwapIntervalMESA) return 0; int interval = glx.GetSwapIntervalMESA(); if (!is_blacklisted()) { static bool first_call = true; if (first_call) { first_call = false; if (get_params()->gl_vsync >= 0) { interval = get_params()->gl_vsync; glx.SwapIntervalMESA(interval); } } } SPDLOG_DEBUG("{}: {}", __func__, interval); return interval; } struct func_ptr { const char *name; void *ptr; }; static std::array name_to_funcptr_map = {{ #define ADD_HOOK(fn) { #fn, (void *) fn } ADD_HOOK(glXGetProcAddress), ADD_HOOK(glXGetProcAddressARB), ADD_HOOK(glXDestroyContext), ADD_HOOK(glXSwapBuffers), ADD_HOOK(glXSwapBuffersMscOML), ADD_HOOK(glXSwapIntervalEXT), ADD_HOOK(glXSwapIntervalSGI), ADD_HOOK(glXSwapIntervalMESA), ADD_HOOK(glXGetSwapIntervalMESA), #undef ADD_HOOK }}; EXPORT_C_(void *) mangohud_find_glx_ptr(const char *name); EXPORT_C_(void *) mangohud_find_glx_ptr(const char *name) { if (is_blacklisted()) return nullptr; for (auto& func : name_to_funcptr_map) { if (strcmp(name, func.name) == 0) return func.ptr; } return nullptr; } EXPORT_C_(void *) glXGetProcAddress(const unsigned char* procName) { void *real_func = get_glx_proc_address((const char*)procName); void *func = mangohud_find_glx_ptr( (const char*)procName ); SPDLOG_TRACE("{}: '{}', real: {}, fun: {}", __func__, reinterpret_cast(procName), real_func, func); if (func && real_func) return func; return real_func; } EXPORT_C_(void *) glXGetProcAddressARB(const unsigned char* procName) { void *real_func = get_glx_proc_address((const char*)procName); void *func = mangohud_find_glx_ptr( (const char*)procName ); SPDLOG_TRACE("{}: '{}', real: {}, fun: {}", __func__, reinterpret_cast(procName), real_func, func); if (func && real_func) return func; return real_func; } ================================================ FILE: src/gl/shim.c ================================================ #include #include #include #include #include #include "gl.h" #include "real_dlsym.h" #include #include #include #ifndef RTLD_DEEPBIND #define RTLD_DEEPBIND 0 #endif static void* handle = NULL; static bool mangoHudLoaded = false; #ifdef __GLIBC__ static inline void free_indirect(char **p) { free(*p); } static bool load_adjacent_opengl_lib(void) { __attribute__((cleanup(free_indirect))) char *location = NULL; __attribute__((cleanup(free_indirect))) char *lib = NULL; Dl_info info = {}; void *extra_info = NULL; // The first argument can be any symbol in this shared library, // mangoHudLoaded is a convenient one if (!dladdr1(&mangoHudLoaded, &info, &extra_info, RTLD_DL_LINKMAP)) { fprintf(stderr, "shim: Unable to find my own location: %s\n", dlerror()); return false; } const struct link_map *map = extra_info; if (map == NULL) { fprintf(stderr, "shim: Unable to find my own location: NULL link_map\n"); return false; } if (map->l_name == NULL) { fprintf(stderr, "shim: Unable to find my own location: NULL l_name\n"); return false; } location = realpath(map->l_name, NULL); char *slash = strrchr(location, '/'); if (slash == NULL) { fprintf(stderr, "shim: Unable to find my own location: no directory separator\n"); return false; } *slash = '\0'; if (asprintf(&lib, "%s/libMangoHud_opengl.so", location) < 0) { fprintf(stderr, "shim: asprintf: %s\n", strerror(errno)); return false; } handle = dlopen(lib, RTLD_NOW | RTLD_LOCAL | RTLD_DEEPBIND); if (handle == NULL) { fprintf(stderr, "shim: Failed to load from \"%s\": %s\n", lib, dlerror()); return false; } return true; } #endif // Load MangoHud after EGL/GLX functions have been intercepted static void loadMangoHud(void); static void loadMangoHud() { if (mangoHudLoaded) return; // allow user to load custom mangohud libs (useful for testing) char *libs = getenv("MANGOHUD_OPENGL_LIBS"); char *lib = NULL; if (libs) { lib = strtok(libs, ":"); // when user specifies only one path if (!lib) lib = libs; while (lib != NULL) { handle = dlopen(lib, RTLD_NOW | RTLD_LOCAL | RTLD_DEEPBIND); if (handle) { mangoHudLoaded = true; return; } else fprintf(stderr, "shim: Failed to load from \"%s\": %s\n", lib, dlerror()); lib = strtok(NULL, ":"); } } #ifdef __GLIBC__ if (load_adjacent_opengl_lib()) { mangoHudLoaded = true; return; } #endif if (!mangoHudLoaded) { handle = dlopen("${ORIGIN}/libMangoHud_opengl.so", RTLD_NOW | RTLD_LOCAL | RTLD_DEEPBIND); if (handle) mangoHudLoaded = true; else { fprintf(stderr, "shim: Failed to load from ${ORIGIN}/libMangoHud_opengl.so: %s\n", dlerror()); handle = RTLD_NEXT; } } } #define CREATE_FWD_VOID(name, params, ...) \ void name params { \ loadMangoHud(); \ void (*p##name) params = real_dlsym(handle, #name); \ if (p##name) p##name(__VA_ARGS__); \ } #define CREATE_FWD(ret_type, name, params, ...) \ ret_type name params { \ loadMangoHud(); \ ret_type (*p##name) params = real_dlsym(handle, #name); \ if (p##name) return p##name(__VA_ARGS__); \ return (ret_type)0; \ } #ifdef HAVE_X11 CREATE_FWD_VOID(glXSwapBuffers, (void* dpy, void* drawable), dpy, drawable) CREATE_FWD(int64_t, glXSwapBuffersMscOML, (void* dpy, void* drawable, int64_t target_msc, int64_t divisor, int64_t remainder), dpy, drawable, target_msc, divisor, remainder) CREATE_FWD_VOID(glXDestroyContext, (void *dpy, void *ctx), dpy, ctx) CREATE_FWD(void*, glXGetProcAddress, (const unsigned char* procName), procName) CREATE_FWD(void*, glXGetProcAddressARB, (const unsigned char* procName), procName) #endif CREATE_FWD(void*, eglGetDisplay, (void* native_dpy), native_dpy) CREATE_FWD(void*, eglGetPlatformDisplay, (unsigned int platform, void* native_display, const intptr_t* attrib_list), platform, native_display, attrib_list) CREATE_FWD(unsigned int, eglSwapBuffers, (void* dpy, void* surf), dpy, surf) CREATE_FWD(void*, eglGetProcAddress, (const char* procName), procName) CREATE_FWD(int, eglTerminate, (void *display), display) CREATE_FWD(unsigned int, eglDestroyContext, (void *dpy, void *ctx), dpy, ctx) #undef CREATE_FWD #undef CREATE_FWD_VOID struct func_ptr { const char* name; void* ptr; }; #define ADD_HOOK(fn) { #fn, (void*)fn } static struct func_ptr hooks[] = { #ifdef HAVE_X11 ADD_HOOK(glXGetProcAddress), ADD_HOOK(glXGetProcAddressARB), ADD_HOOK(glXDestroyContext), ADD_HOOK(glXSwapBuffers), ADD_HOOK(glXSwapBuffersMscOML), #endif ADD_HOOK(eglDestroyContext), ADD_HOOK(eglSwapBuffers), ADD_HOOK(eglGetPlatformDisplay), ADD_HOOK(eglGetDisplay), ADD_HOOK(eglGetProcAddress), ADD_HOOK(eglTerminate) }; #undef ADD_HOOK #ifndef ARRAY_SIZE #define ARRAY_SIZE(arr) sizeof(arr)/sizeof(arr[0]) #endif #include // Glibc has nonconformance behaviour // which is Glibc clears dlerror if dlsym succeded instead // leaving it as it is as required by standard // Reference: https://pubs.opengroup.org/onlinepubs/009604299/functions/dlsym.html // // Lets disable dlerror override to avoid risking programs // which already relying on Glibc's behaviour so to keep // glibc's behaviour // while on conformance system such as Musl it fixes bugs #ifdef __GLIBC__ # define USE_DLERROR_OVERRIDE 0 #else # define USE_DLERROR_OVERRIDE 1 #endif static _Thread_local char *error_override = NULL; static _Thread_local bool activate_override = false; char *dlerror(void) { if (!USE_DLERROR_OVERRIDE) return real_dlerror(); if (activate_override) { // Deactivate the override for next call to allow // real_dlerror to be used activate_override = false; return error_override; } else if (error_override) { // Free resources that was allocated for error override // because the override is now deactivated free(error_override); error_override = NULL; } return real_dlerror(); } static void save_and_consume_real_dlerror() { if (!USE_DLERROR_OVERRIDE) return; char* recent_error = real_dlerror(); if (!recent_error) { error_override = recent_error; return; } size_t error_length = strlen(recent_error); error_override = malloc(error_length + 1); memcpy(error_override, recent_error, error_length + 1); } void* dlsym(void *handle, const char *name) { save_and_consume_real_dlerror(); // const char* dlsym_enabled = getenv("MANGOHUD_DLSYM"); // const char* dlsym_RTLD_NEXT_env = getenv("MANGOHUD_DLSYM_RTLD_NEXT"); // const bool bypass_RTLD_NEXT = dlsym_RTLD_NEXT_env ? dlsym_RTLD_NEXT_env[0] == '0' : false; void* is_angle = real_dlsym(handle, "eglStreamPostD3DTextureANGLE"); // Consume error message if there was an error if (!is_angle) { (void) real_dlerror(); } void* fn_ptr = real_dlsym(handle, name); // Overriding dlsym makes it behave differently due to the change in search scope // this results in name resolution failure when no handle or default handles are used // as a mitigation we get a handle to the caller, and use it instead. // This makes RTLD_DEFAULT behave better, but RTLD_NEXT is still broken. // Note, RTLD_DEFAULT might still be broken for edge cases. // this causes issues with nvidia and will crash. Needs to be reworked // if (!fn_ptr && (handle == RTLD_DEFAULT || (handle == RTLD_NEXT && !bypass_RTLD_NEXT))) // { // void* ret_addr = __builtin_extract_return_addr(__builtin_return_address(0)); // Dl_info dl_info = {}; // if (dladdr(ret_addr, &dl_info) && dl_info.dli_fname && dl_info.dli_fname[0]) // { // void* caller_handle = dlopen(dl_info.dli_fname, RTLD_LAZY | RTLD_NOLOAD); // if (caller_handle) // { // // last real_dlsym call failed so we consume the last error // (void) real_dlerror(); // fn_ptr = real_dlsym(caller_handle, name); // if (handle == RTLD_NEXT) // { // fprintf(stderr, "MANGOHUD: WARNING dlsym called with RTLD_NEXT, if you are facing issues try to disable mangohud.\n"); // fprintf(stderr, "MANGOHUD: or you can try MANGOHUD_DLSYM_RTLD_NEXT=0\n"); // } // } // } // } // Activate override if there wasn't any new error // from real_dlsym activate_override = fn_ptr != NULL; if (!is_angle && fn_ptr) { for (unsigned i = 0; i < ARRAY_SIZE(hooks); i++) { if (!strcmp(hooks[i].name, name)) { return hooks[i].ptr; } } } return fn_ptr; } ================================================ FILE: src/gpu.cpp ================================================ #include "gpu.h" #include "file_utils.h" #include "hud_elements.h" namespace fs = ghc::filesystem; GPUS::GPUS(const overlay_params* early_params) { std::set gpu_entries; auto params = early_params ? early_params : get_params().get(); for (const auto& entry : fs::directory_iterator("/sys/class/drm")) { if (!entry.is_directory()) continue; std::string node_name = entry.path().filename().string(); // Check if the directory is a render node (e.g., renderD128, renderD129, etc.) if (node_name.find("renderD") == 0 && node_name.length() > 7) { // Ensure the rest of the string after "renderD" is numeric std::string render_number = node_name.substr(7); if (std::all_of(render_number.begin(), render_number.end(), ::isdigit)) { gpu_entries.insert(node_name); // Store the render entry } } } // Now process the sorted GPU entries uint8_t idx = 0, total_active = 0; for (const auto& node_name : gpu_entries) { const std::string driver = get_driver(node_name); if (driver.empty()) { SPDLOG_DEBUG("Failed to query driver name of node \"{}\"", node_name); continue; } { const std::string* d = std::find(std::begin(supported_drivers), std::end(supported_drivers), driver); if (d == std::end(supported_drivers)) { SPDLOG_WARN( "node \"{}\" is using driver \"{}\" which is unsupported by MangoHud. Skipping...", node_name, driver ); continue; } } std::string path = "/sys/class/drm/" + node_name; std::string device_address = get_pci_device_address(path); // Store the result const char* pci_dev = device_address.c_str(); uint32_t vendor_id = 0; uint32_t device_id = 0; if (!device_address.empty()) { try { vendor_id = std::stoul(read_line("/sys/bus/pci/devices/" + device_address + "/vendor"), nullptr, 16); } catch(...) { SPDLOG_ERROR("stoul failed on: {}", "/sys/bus/pci/devices/" + device_address + "/vendor"); } try { device_id = std::stoul(read_line("/sys/bus/pci/devices/" + device_address + "/device"), nullptr, 16); } catch (...) { SPDLOG_ERROR("stoul failed on: {}", "/sys/bus/pci/devices/" + device_address + "/device"); } } std::shared_ptr ptr = std::make_shared(node_name, vendor_id, device_id, pci_dev, driver); if (params->gpu_list.size() == 1 && params->gpu_list[0] == idx++) ptr->is_active = true; if (!params->pci_dev.empty() && pci_dev == params->pci_dev) ptr->is_active = true; available_gpus.emplace_back(ptr); SPDLOG_DEBUG( "GPU Found: node_name: {}, driver: {}, vendor_id: {:x} device_id: {:x} pci_dev: {}", node_name, driver, vendor_id, device_id, pci_dev ); if (ptr->is_active) { SPDLOG_INFO( "Set {} as active GPU (driver={} id={:x}:{:x} pci_dev={})", node_name, driver, vendor_id, device_id, pci_dev ); total_active++; } } if (total_active < 2) return; for (auto& gpu : available_gpus) { if (!gpu->is_active) continue; SPDLOG_WARN( "You have more than 1 active GPU, check if you use both pci_dev " "and gpu_list. If you use fps logging, MangoHud will log only " "this GPU: name = {}, driver = {}, vendor = {:x}, pci_dev = {}", gpu->drm_node, gpu->driver, gpu->vendor_id, gpu->pci_dev ); break; } } std::string GPUS::get_driver(const std::string& node) { std::string path = "/sys/class/drm/" + node + "/device/driver"; if (!fs::exists(path)) { SPDLOG_ERROR("{} doesn't exist", path); return ""; } if (!fs::is_symlink(path)) { SPDLOG_ERROR("{} is not a symlink (it should be)", path); return ""; } std::string driver = fs::read_symlink(path).string(); driver = driver.substr(driver.rfind("/") + 1); return driver; } std::string GPUS::get_pci_device_address(const std::string& drm_card_path) { // /sys/class/drm/renderD128/device/subsystem -> /sys/bus/pci auto subsystem = fs::canonical(drm_card_path + "/device/subsystem").string(); auto idx = subsystem.rfind("/") + 1; // /sys/bus/pci // ^ // |- find this guy if (subsystem.substr(idx) != "pci") return ""; // /sys/class/drm/renderD128/device -> /sys/devices/pci0000:00/0000:00:01.0/0000:01:00.0/0000:02:01.0/0000:03:00.0 auto pci_addr = fs::read_symlink(drm_card_path + "/device").string(); idx = pci_addr.rfind("/") + 1; // /sys/.../0000:03:00.0 // ^ // |- find this guy return pci_addr.substr(idx); // 0000:03:00.0 } int GPU::index_in_selected_gpus() { auto selected_gpus = gpus->selected_gpus(); auto it = std::find_if(selected_gpus.begin(), selected_gpus.end(), [this](const std::shared_ptr& gpu) { return gpu.get() == this; }); if (it != selected_gpus.end()) { return std::distance(selected_gpus.begin(), it); } return -1; } std::string GPU::gpu_text() { std::string gpu_text; size_t index = this->index_in_selected_gpus(); if (gpus->selected_gpus().size() == 1) { // When there's exactly one selected GPU, return "GPU" without index gpu_text = "GPU"; if (gpus->params()->gpu_text.size() > 0) { gpu_text = gpus->params()->gpu_text[0]; } } else if (gpus->selected_gpus().size() > 1) { // When there are multiple selected GPUs, use GPU+index or matching gpu_text gpu_text = "GPU" + std::to_string(index); if (gpus->params()->gpu_text.size() > index) { gpu_text = gpus->params()->gpu_text[index]; } } else { // Default case for no selected GPUs gpu_text = "GPU"; } return gpu_text; } std::string GPU::vram_text() { std::string vram_text; size_t index = this->index_in_selected_gpus(); if (gpus->selected_gpus().size() > 1) vram_text = "VRAM" + std::to_string(index); else vram_text = "VRAM"; return vram_text; } std::shared_ptr GPUS::params() { return get_params(); } std::unique_ptr gpus = nullptr; ================================================ FILE: src/gpu.h ================================================ #pragma once #ifndef MANGOHUD_GPU_H #define MANGOHUD_GPU_H #include #include #include "overlay_params.h" #include #include #include #include #include #include #include #include "amdgpu.h" #include "nvidia.h" #include "gpu_metrics_util.h" #include "gpu_fdinfo.h" class GPU { public: gpu_metrics metrics; std::string drm_node; std::unique_ptr nvidia = nullptr; std::unique_ptr amdgpu = nullptr; std::unique_ptr fdinfo = nullptr; bool is_active = false; std::string pci_dev; uint32_t vendor_id = 0; uint32_t device_id = 0; const std::string driver; GPU( std::string drm_node, uint32_t vendor_id, uint32_t device_id, const char* pci_dev, std::string driver ) : drm_node(drm_node), pci_dev(pci_dev), vendor_id(vendor_id), device_id(device_id), driver(driver) { if (vendor_id == 0x10de) nvidia = std::make_unique(pci_dev); if (vendor_id == 0x1002) amdgpu = std::make_unique(pci_dev, device_id, vendor_id); if ( driver == "i915" || driver == "xe" || driver == "panfrost" || driver == "panthor" || driver == "msm_dpu" || driver == "msm_drm" ) fdinfo = std::make_unique(driver, pci_dev, drm_node); } gpu_metrics get_metrics() { if (nvidia) this->metrics = nvidia->copy_metrics(); if (amdgpu) this->metrics = amdgpu->copy_metrics(); if (fdinfo) this->metrics = fdinfo->copy_metrics(); return metrics; }; std::vector nvidia_pids() { #ifdef HAVE_NVML if (nvidia) return nvidia->pids(); #endif return std::vector(); } void pause() { if (nvidia) nvidia->pause(); if (amdgpu) amdgpu->pause(); if (fdinfo) fdinfo->pause(); } void resume() { if (nvidia) nvidia->resume(); if (amdgpu) amdgpu->resume(); if (fdinfo) fdinfo->resume(); } bool is_apu() { if (amdgpu) return amdgpu->is_apu; else return false; } std::shared_ptr throttling() { if (nvidia) return nvidia->throttling; if (amdgpu) return amdgpu->throttling; return nullptr; } std::string gpu_text(); std::string vram_text(); private: std::thread thread; int index_in_selected_gpus(); }; class GPUS { public: std::vector> available_gpus; std::mutex mutex; explicit GPUS(const overlay_params* early_params = nullptr); std::shared_ptr params(); void pause() { for (auto& gpu : available_gpus) gpu->pause(); } void resume() { for (auto& gpu : available_gpus) gpu->resume(); } std::shared_ptr active_gpu() { if (available_gpus.empty()) return nullptr; for (auto gpu : available_gpus) { if (gpu->is_active) return gpu; } // if no GPU is marked as active, just set it to the last one // because integrated gpus are usually first return available_gpus.back(); } void update_throttling() { for (auto gpu : available_gpus) if (gpu->throttling()) gpu->throttling()->update(); } void get_metrics() { std::lock_guard lock(mutex); for (auto gpu : available_gpus) gpu->get_metrics(); } std::vector> selected_gpus() { std::lock_guard lock(mutex); std::vector> vec; if (params()->gpu_list.empty() && params()->pci_dev.empty()) return available_gpus; if (!params()->gpu_list.empty()) { for (unsigned index : params()->gpu_list) { if (index < available_gpus.size()) { if (available_gpus[index]) vec.push_back(available_gpus[index]); } } return vec; } if (!params()->pci_dev.empty()) { for (auto &gpu : available_gpus) { if (gpu->pci_dev == params()->pci_dev) { vec.push_back(gpu); return vec; } } return vec; } return vec; } private: std::string get_pci_device_address(const std::string& drm_card_path); std::string get_driver(const std::string& node); const std::array supported_drivers = { "amdgpu", "nvidia", "i915", "xe", "panfrost", "panthor", "msm_dpu", "msm_drm" }; }; extern std::unique_ptr gpus; void getNvidiaGpuInfo(const struct overlay_params& params); void getAmdGpuInfo(void); void getIntelGpuInfo(); bool checkNvidia(const char *pci_dev); extern void nvapi_util(); extern bool checkNVAPI(); #endif //MANGOHUD_GPU_H ================================================ FILE: src/gpu_fdinfo.cpp ================================================ #include "gpu_fdinfo.h" #ifndef TEST_ONLY #include "hud_elements.h" #endif namespace fs = ghc::filesystem; void GPU_fdinfo::find_fd() { fdinfo.clear(); fdinfo_data.clear(); auto dir = std::string("/proc/") + std::to_string(pid) + "/fdinfo"; auto path = fs::path(dir); SPDLOG_TRACE("fdinfo_dir = {}", dir); if (!fs::exists(path)) { SPDLOG_DEBUG("{} does not exist", path.string()); return; } // Here we store client-ids, if ids match, we dont open this file, // because it will have same readings and it becomes a duplicate std::set client_ids; int total = 0; for (const auto& entry : fs::directory_iterator(path)) { auto fd_path = entry.path().string(); auto file = std::ifstream(fd_path); if (!file.is_open()) continue; std::string driver, pdev, client_id; for (std::string line; std::getline(file, line);) { size_t colon = line.find(":"); if (line[0] == ' ' || line[0] == '\t') continue; if (colon == std::string::npos || colon + 2 >= line.length()) continue; auto key = line.substr(0, colon); auto val = line.substr(key.length() + 2); if (key == "drm-driver") driver = val; else if (key == "drm-pdev") pdev = val; else if (key == "drm-client-id") client_id = val; } if (!driver.empty() && driver == module) { total++; SPDLOG_TRACE( "driver = \"{}\", pdev = \"{}\", " "client_id = \"{}\", client_id_exists = \"{}\"", driver, pdev, client_id, client_ids.find(client_id) != client_ids.end() ); } if ( driver.empty() || client_id.empty() || driver != module || pdev != pci_dev || client_ids.find(client_id) != client_ids.end() ) continue; client_ids.insert(client_id); open_fdinfo_fd(fd_path); } SPDLOG_TRACE( "Found {} total fds. Opened {} unique fds.", total, fdinfo.size() ); } void GPU_fdinfo::open_fdinfo_fd(std::string path) { fdinfo.push_back(std::ifstream(path)); fdinfo_data.push_back({}); } void GPU_fdinfo::gather_fdinfo_data() { for (size_t i = 0; i < fdinfo.size(); i++) { fdinfo[i].clear(); fdinfo[i].seekg(0); for (std::string line; std::getline(fdinfo[i], line);) { size_t colon = line.find(":"); if (line[0] == ' ' || line[0] == '\t') continue; if (colon == std::string::npos || colon + 2 >= line.length()) continue; auto key = line.substr(0, line.find(":")); auto val = line.substr(key.length() + 2); fdinfo_data[i][key] = val; } } } uint64_t GPU_fdinfo::get_gpu_time() { uint64_t total = 0; if (module == "panfrost") return get_gpu_time_panfrost(); for (auto& fd : fdinfo_data) { auto time = fd[drm_engine_type]; if (time.empty()) continue; total += std::stoull(time); } return total; } uint64_t GPU_fdinfo::get_gpu_time_panfrost() { uint64_t total = 0; for (auto& fd : fdinfo_data) { auto frag = fd["drm-engine-fragment"]; auto vert = fd["drm-engine-vertex-tiler"]; if (!frag.empty()) total += std::stoull(frag); if (!vert.empty()) total += std::stoull(vert); } return total; } float GPU_fdinfo::get_memory_used() { uint64_t total = 0; for (auto& fd : fdinfo_data) { auto mem = fd[drm_memory_type]; if (mem.empty()) continue; std::string unit = mem.substr(mem.rfind(" ") + 1); uint64_t val = std::stoull(mem); if (unit == "KiB") val *= 1024; else if (unit == "MiB") val *= 1024 * 1024; else if (unit == "GiB") val *= 1024 * 1024 * 1024; total += val; } return static_cast(total) / 1024 / 1024 / 1024; } void GPU_fdinfo::find_hwmon_sensors() { std::string hwmon; if (module == "msm") hwmon = find_hwmon_sensor_dir("gpu"); else if (module == "panfrost" || module == "panthor") hwmon = find_hwmon_sensor_dir("gpu_thermal"); else hwmon = find_hwmon_dir(); if (hwmon.empty()) { SPDLOG_DEBUG("hwmon: failed to find hwmon directory"); return; } SPDLOG_DEBUG("hwmon: checking \"{}\" directory", hwmon); for (const auto &entry : fs::directory_iterator(hwmon)) { auto filename = entry.path().filename().string(); for (auto& hs : hwmon_sensors) { auto key = hs.first; auto sensor = &hs.second; std::smatch matches; if ( !std::regex_match(filename, matches, sensor->rx) || matches.size() != 2 ) continue; auto cur_id = std::stoull(matches[1].str()); if (sensor->filename.empty() || cur_id < sensor->id) { sensor->filename = entry.path().string(); sensor->id = cur_id; } } } for (auto& hs : hwmon_sensors) { auto key = hs.first; auto sensor = &hs.second; if (sensor->filename.empty()) { SPDLOG_DEBUG("hwmon: {} reading not found at {}", key, hwmon); continue; } SPDLOG_DEBUG("hwmon: {} reading found at {}", key, sensor->filename); sensor->stream.open(sensor->filename); if (!sensor->stream.good()) { SPDLOG_DEBUG( "hwmon: failed to open {} reading {}", key, sensor->filename ); continue; } } } std::string GPU_fdinfo::find_hwmon_dir() { std::string d = "/sys/class/drm/" + drm_node + "/device/hwmon"; if (!fs::exists(d)) { SPDLOG_DEBUG("hwmon: hwmon directory \"{}\" doesn't exist", d); return ""; } auto dir_iterator = fs::directory_iterator(d); auto hwmon = dir_iterator->path().string(); if (hwmon.empty()) { SPDLOG_DEBUG("hwmon: hwmon directory \"{}\" is empty.", d); return ""; } return hwmon; } std::string GPU_fdinfo::find_hwmon_sensor_dir(std::string name) { std::string d = "/sys/class/hwmon/"; if (!fs::exists(d)) return ""; for (const auto &entry : fs::directory_iterator(d)) { auto hwmon_dir = entry.path().string(); auto hwmon_name = hwmon_dir + "/name"; std::ifstream name_stream(hwmon_name); std::string name_content; if (!name_stream.is_open()) continue; std::getline(name_stream, name_content); if (name_content.find(name) == std::string::npos) continue; // return the first gpu sensor return hwmon_dir; } return ""; } void GPU_fdinfo::get_current_hwmon_readings() { for (auto& hs : hwmon_sensors) { auto key = hs.first; auto sensor = &hs.second; if (!sensor->stream.is_open()) continue; sensor->stream.seekg(0); std::stringstream ss; ss << sensor->stream.rdbuf(); if (ss.str().empty()) continue; sensor->val = std::stoull(ss.str()); } } float GPU_fdinfo::get_power_usage() { if (!hwmon_sensors["power"].filename.empty()) return static_cast(hwmon_sensors["power"].val) / 1'000'000; float now = hwmon_sensors["energy"].val; // Initialize value for the first time, otherwise delta will be very large // and your gpu power usage will be like 1 million watts for a second. if (this->last_power == 0.f) this->last_power = now; float delta = now - this->last_power; delta /= METRICS_UPDATE_PERIOD_MS / 1000.f; this->last_power = now; return delta / 1'000'000; } int GPU_fdinfo::get_xe_load() { double load = 0; for (auto& fd : fdinfo_data) { std::string client_id = fd["drm-client-id"]; std::string cur_cycles_str = fd["drm-cycles-rcs"]; std::string cur_total_cycles_str = fd["drm-total-cycles-rcs"]; if ( client_id.empty() || cur_cycles_str.empty() || cur_total_cycles_str.empty() ) continue; auto cur_cycles = std::stoull(cur_cycles_str); auto cur_total_cycles = std::stoull(cur_total_cycles_str); if (prev_xe_cycles.find(client_id) == prev_xe_cycles.end()) { prev_xe_cycles[client_id] = { cur_cycles, cur_total_cycles }; continue; } auto prev_cycles = prev_xe_cycles[client_id].first; auto prev_total_cycles = prev_xe_cycles[client_id].second; auto delta_cycles = cur_cycles - prev_cycles; auto delta_total_cycles = cur_total_cycles - prev_total_cycles; prev_xe_cycles[client_id] = { cur_cycles, cur_total_cycles }; if (delta_cycles <= 0 || delta_total_cycles <= 0) continue; auto fd_load = static_cast(delta_cycles) / delta_total_cycles * 100; load += fd_load; } if (load > 100.f) load = 100.f; return std::lround(load); } int GPU_fdinfo::get_gpu_load() { if (module == "xe") return get_xe_load(); else if (module == "msm_drm") return get_kgsl_load(); uint64_t now = os_time_get_nano(); uint64_t gpu_time_now = get_gpu_time(); if (previous_time == 0) { previous_gpu_time = gpu_time_now; previous_time = now; return 0; } float delta_time = now - previous_time; float delta_gpu_time = gpu_time_now - previous_gpu_time; int result = delta_gpu_time / delta_time * 100; if (result > 100) result = 100; previous_gpu_time = gpu_time_now; previous_time = now; return std::round(result); } void GPU_fdinfo::find_i915_gt_dir() { std::string device = "/sys/bus/pci/devices/" + pci_dev + "/drm"; // Find first dir which starts with name "card" for (const auto& entry : fs::directory_iterator(device)) { auto path = entry.path().string(); if (path.substr(device.size() + 1, 4) == "card") { device = path; break; } } auto gpu_clock_path = device + "/gt_act_freq_mhz"; gpu_clock_stream.open(gpu_clock_path); if (!gpu_clock_stream.good()) SPDLOG_WARN("Intel i915 gt dir: failed to open {}", device); // Assuming gt0 since all recent GPUs have the RCS engine on gt0, // and latest GPUs need Xe anyway auto throttle_folder = device + "/gt/gt0/throttle_"; auto throttle_status_path = throttle_folder + "reason_status"; throttle_status_stream.open(throttle_status_path); if (!throttle_status_stream.good()) { SPDLOG_WARN("Intel i915 gt dir: failed to open {}", throttle_status_path); } else { load_xe_i915_throttle_reasons(throttle_folder, intel_throttle_power, throttle_power_streams); load_xe_i915_throttle_reasons(throttle_folder, intel_throttle_current, throttle_current_streams); load_xe_i915_throttle_reasons(throttle_folder, intel_throttle_temp, throttle_temp_streams); } } void GPU_fdinfo::find_xe_gt_dir() { std::string device = "/sys/bus/pci/devices/" + pci_dev + "/tile0"; if (!fs::exists(device)) { SPDLOG_WARN( "\"{}\" doesn't exist. GPU clock will be unavailable.", device ); return; } bool has_rcs = true; // Check every "gt" dir if it has "engines/rcs" inside for (const auto& entry : fs::directory_iterator(device)) { auto path = entry.path().string(); if (path.substr(device.size() + 1, 2) != "gt") continue; SPDLOG_DEBUG("Checking \"{}\" for rcs.", path); if (!fs::exists(path + "/engines/rcs")) { SPDLOG_DEBUG("Skipping \"{}\" because rcs doesn't exist.", path); continue; } SPDLOG_DEBUG("Found rcs in \"{}\"", path); has_rcs = true; device = path; break; } if (!has_rcs) { SPDLOG_WARN( "rcs not found inside \"{}\". GPU clock will not be available.", device ); return; } auto gpu_clock_path = device + "/freq0/act_freq"; gpu_clock_stream.open(gpu_clock_path); if (!gpu_clock_stream.good()) SPDLOG_WARN("Intel xe gt dir: failed to open {}", gpu_clock_path); auto throttle_folder = device + "/freq0/throttle/"; auto throttle_status_path = throttle_folder + "status"; throttle_status_stream.open(throttle_status_path); if (!throttle_status_stream.good()) { SPDLOG_WARN("Intel xe gt dir: failed to open {}", throttle_status_path); } else { load_xe_i915_throttle_reasons(throttle_folder, intel_throttle_power, throttle_power_streams); load_xe_i915_throttle_reasons(throttle_folder, intel_throttle_current, throttle_current_streams); load_xe_i915_throttle_reasons(throttle_folder, intel_throttle_temp, throttle_temp_streams); } } void GPU_fdinfo::load_xe_i915_throttle_reasons( std::string throttle_folder, std::vector throttle_reasons, std::vector& throttle_reason_streams ) { for (const auto& throttle_reason : throttle_reasons) { std::string throttle_path = throttle_folder + throttle_reason; if (!fs::exists(throttle_path)) { SPDLOG_WARN( "Intel xe/i915 gt dir: Throttle file {} not found", throttle_path ); continue; } auto throttle_stream = std::ifstream(throttle_path); if (!throttle_stream.good()) { SPDLOG_WARN("Intel xe/i915 gt dir: failed to open {}", throttle_path); continue; } throttle_reason_streams.push_back(std::move(throttle_stream)); } } int GPU_fdinfo::get_gpu_clock() { if (module == "panfrost" || module == "panthor") return get_gpu_clock_mali(); if (!gpu_clock_stream.is_open()) return 0; std::string clock_str; gpu_clock_stream.seekg(0); std::getline(gpu_clock_stream, clock_str); if (clock_str.empty()) return 0; return std::stoi(clock_str); } int GPU_fdinfo::get_gpu_clock_mali() { if (fdinfo_data.empty()) return 0; std::string key; if (module == "panfrost") key = "drm-curfreq-fragment"; else if (module == "panthor") key = "drm-curfreq-panthor"; std::string freq_str = fdinfo_data[0][key]; if (freq_str.empty()) return 0; float freq = std::stoull(freq_str) / 1'000'000; return std::round(freq); } bool GPU_fdinfo::check_throttle_reasons( std::vector& throttle_reason_streams) { for (auto& throttle_reason_stream : throttle_reason_streams) { std::string throttle_reason_str; throttle_reason_stream.seekg(0); std::getline(throttle_reason_stream, throttle_reason_str); if (throttle_reason_str == "1") return true; } return false; } int GPU_fdinfo::get_throttling_status() { if (!throttle_status_stream.is_open()) return 0; std::string throttle_status_str; throttle_status_stream.seekg(0); std::getline(throttle_status_stream, throttle_status_str); if (throttle_status_str != "1") return 0; int reasons = check_throttle_reasons(throttle_power_streams) * GPU_throttle_status::POWER + check_throttle_reasons(throttle_current_streams) * GPU_throttle_status::CURRENT + check_throttle_reasons(throttle_temp_streams) * GPU_throttle_status::TEMP; // No throttle reasons for OTHER currently if (reasons == 0) reasons |= GPU_throttle_status::OTHER; return reasons; } float GPU_fdinfo::amdgpu_helper_get_proc_vram() { #ifndef TEST_ONLY if (HUDElements.g_gamescopePid > 0 && HUDElements.g_gamescopePid != pid) { pid = HUDElements.g_gamescopePid; find_fd(); } #endif // Recheck fds every 10secs, fixes Mass Effect 1, maybe some others too { auto t = os_time_get_nano() / 1'000'000; if (t - fdinfo_last_update_ms >= 10'000) { find_fd(); fdinfo_last_update_ms = t; } } gather_fdinfo_data(); return get_memory_used(); } void GPU_fdinfo::init_kgsl() { const std::string sys_path = "/sys/class/kgsl/kgsl-3d0"; try { if (!fs::exists(sys_path)) { SPDLOG_WARN("kgsl: {} is not found. kgsl stats will not work!", sys_path); return; } } catch (fs::filesystem_error& ex) { SPDLOG_WARN("kgsl: {}", ex.what()); return; } for (std::string metric : {"gpu_busy_percentage", "temp", "clock_mhz" }) { std::string p = sys_path + "/" + metric; if (!fs::exists(p)) { SPDLOG_WARN("kgsl: {} is not found", p); continue; } SPDLOG_DEBUG("kgsl: {} found", p); if (metric == "clock_mhz") gpu_clock_stream.open(p); else kgsl_streams[metric].open(p); } } int GPU_fdinfo::get_kgsl_load() { std::ifstream* s = &kgsl_streams["gpu_busy_percentage"]; if (!s->is_open()) return 0; std::string usage_str; s->seekg(0); std::getline(*s, usage_str); if (usage_str.empty()) return 0; return std::stoi(usage_str); } int GPU_fdinfo::get_kgsl_temp() { std::ifstream* s = &kgsl_streams["temp"]; if (!s->is_open()) return 0; std::string temp_str; s->seekg(0); std::getline(*s, temp_str); if (temp_str.empty()) return 0; return std::round(std::stoi(temp_str) / 1'000.f); } void GPU_fdinfo::main_thread() { while (!stop_thread) { std::unique_lock lock(metrics_mutex); cond_var.wait(lock, [this]() { return !paused || stop_thread; }); #ifndef TEST_ONLY if (HUDElements.g_gamescopePid > 0 && HUDElements.g_gamescopePid != pid) { pid = HUDElements.g_gamescopePid; find_fd(); } #endif // Recheck fds every 10secs, fixes Mass Effect 1, maybe some others too { auto t = os_time_get_nano() / 1'000'000; if (t - fdinfo_last_update_ms >= 10'000) { find_fd(); fdinfo_last_update_ms = t; } } gather_fdinfo_data(); get_current_hwmon_readings(); metrics.load = get_gpu_load(); metrics.proc_vram_used = get_memory_used(); metrics.powerUsage = get_power_usage(); metrics.powerLimit = static_cast(hwmon_sensors["power_limit"].val) / 1'000'000; metrics.CoreClock = get_gpu_clock(); metrics.voltage = hwmon_sensors["voltage"].val; if (module == "msm_drm") metrics.temp = get_kgsl_temp(); else metrics.temp = hwmon_sensors["temp"].val / 1000.f; metrics.memory_temp = hwmon_sensors["vram_temp"].val / 1000.f; metrics.fan_speed = hwmon_sensors["fan_speed"].val; metrics.fan_rpm = true; // Fan data is pulled from hwmon int throttling = get_throttling_status(); metrics.is_power_throttled = throttling & GPU_throttle_status::POWER; metrics.is_current_throttled = throttling & GPU_throttle_status::CURRENT; metrics.is_temp_throttled = throttling & GPU_throttle_status::TEMP; metrics.is_other_throttled = throttling & GPU_throttle_status::OTHER; SPDLOG_DEBUG( "pci_dev = {}, pid = {}, module = {}, " "load = {}, proc_vram = {}, power = {}, " "core = {}, temp = {}, fan = {}, " "voltage = {}", pci_dev, pid, module, metrics.load, metrics.proc_vram_used, metrics.powerUsage, metrics.CoreClock, metrics.temp, metrics.fan_speed, metrics.voltage ); std::this_thread::sleep_for( std::chrono::milliseconds(METRICS_UPDATE_PERIOD_MS) ); } } ================================================ FILE: src/gpu_fdinfo.h ================================================ #pragma once #include #include #include #include #include #include #include #include #include #include #include #ifdef TEST_ONLY #include <../src/mesa/util/os_time.h> #else #include "mesa/util/os_time.h" #endif #include #include #include "gpu_metrics_util.h" struct hwmon_sensor { std::regex rx; std::ifstream stream; std::string filename; unsigned char id = 0; uint64_t val = 0; }; enum GPU_throttle_status : int { POWER = 0b0001, CURRENT = 0b0010, TEMP = 0b0100, OTHER = 0b1000, }; class GPU_fdinfo { private: pid_t pid = getpid(); const std::string module; const std::string pci_dev; const std::string drm_node; std::thread thread; std::condition_variable cond_var; std::atomic stop_thread { false }; std::atomic paused { false }; struct gpu_metrics metrics; mutable std::mutex metrics_mutex; std::vector fdinfo; uint64_t fdinfo_last_update_ms = 0; std::map hwmon_sensors; std::string drm_engine_type = "EMPTY"; std::string drm_memory_type = "EMPTY"; std::vector> fdinfo_data; void gather_fdinfo_data(); void main_thread(); void find_fd(); void open_fdinfo_fd(std::string path); int get_gpu_load(); uint64_t get_gpu_time(); uint64_t previous_gpu_time = 0, previous_time = 0; std::vector xe_fdinfo_last_cycles; std::map> prev_xe_cycles; int get_xe_load(); float get_memory_used(); void find_hwmon_sensors(); std::string find_hwmon_dir(); std::string find_hwmon_sensor_dir(std::string name); void get_current_hwmon_readings(); float get_power_usage(); float last_power = 0; std::ifstream gpu_clock_stream; void find_i915_gt_dir(); void find_xe_gt_dir(); int get_gpu_clock(); uint64_t get_gpu_time_panfrost(); int get_gpu_clock_mali(); std::ifstream throttle_status_stream; std::vector throttle_power_streams; std::vector throttle_current_streams; std::vector throttle_temp_streams; bool check_throttle_reasons(std::vector &throttle_reason_streams); int get_throttling_status(); const std::vector intel_throttle_power = {"reason_pl1", "reason_pl2"}; const std::vector intel_throttle_current = {"reason_pl4", "reason_vr_tdc"}; const std::vector intel_throttle_temp = { "reason_prochot", "reason_ratl", "reason_thermal", "reason_vr_thermalert"}; void load_xe_i915_throttle_reasons( std::string throttle_folder, std::vector throttle_reasons, std::vector &throttle_reason_streams); std::map kgsl_streams; void init_kgsl(); int get_kgsl_load(); int get_kgsl_temp(); public: GPU_fdinfo( const std::string module, const std::string pci_dev, const std::string drm_node, const bool called_from_amdgpu_cpp=false ) : module(module) , pci_dev(pci_dev) , drm_node(drm_node) { SPDLOG_DEBUG("GPU driver is \"{}\"", module); find_fd(); gather_fdinfo_data(); if (module == "i915") { drm_engine_type = "drm-engine-render"; drm_memory_type = "drm-resident-local0"; } else if (module == "xe") { drm_engine_type = "drm-total-cycles-rcs"; drm_memory_type = "drm-resident-vram0"; } else if (module == "amdgpu") { drm_engine_type = "drm-engine-gfx"; drm_memory_type = "drm-memory-vram"; } else if (module == "msm_dpu") { // msm driver does not report vram usage drm_engine_type = "drm-engine-gpu"; } else if (module == "msm_drm") { init_kgsl(); } else if (module == "panfrost") { drm_engine_type = "drm-engine-fragment"; drm_memory_type = "drm-resident-memory"; } else if (module == "panthor") { drm_engine_type = "drm-engine-panthor"; drm_memory_type = "drm-resident-memory"; } if (fdinfo_data.size() > 0 && fdinfo_data[0].find(drm_memory_type) == fdinfo_data[0].end()) { auto old_type = drm_memory_type; if (module == "i915") drm_memory_type = "drm-resident-system0"; else if (module == "xe") drm_memory_type = "drm-resident-gtt"; SPDLOG_DEBUG( "\"{}\" is not found, you probably have an integrated GPU. " "Using \"{}\"", old_type, drm_memory_type ); } SPDLOG_DEBUG( "drm_engine_type = {}, drm_memory_type = {}", drm_engine_type, drm_memory_type ); if (called_from_amdgpu_cpp) return; // i915: Documentation/ABI/testing/sysfs-driver-intel-i915-hwmon // xe : Documentation/ABI/testing/sysfs-driver-intel-xe-hwmon if (module == "i915") { hwmon_sensors["voltage"] = { .rx = std::regex("in(0)_input") }; hwmon_sensors["fan_speed"] = { .rx = std::regex("fan(1)_input") }; hwmon_sensors["temp"] = { .rx = std::regex("temp(1)_input") }; hwmon_sensors["energy"] = { .rx = std::regex("energy(1)_input") }; hwmon_sensors["power_limit"] = { .rx = std::regex("power(1)_max") }; } else if (module == "xe") { hwmon_sensors["voltage"] = { .rx = std::regex("in(1)_input") }; // technically, there are 3 fan sensors, but just pick first one hwmon_sensors["fan_speed"] = { .rx = std::regex("fan(1)_input") }; hwmon_sensors["temp"] = { .rx = std::regex("temp(2)_input") }; hwmon_sensors["vram_temp"] = { .rx = std::regex("temp(3)_input") }; hwmon_sensors["energy"] = { .rx = std::regex("energy(2)_input") }; hwmon_sensors["power_limit"] = { .rx = std::regex("power(2)_max") }; } else { // For everyone else just guess hwmon_sensors["voltage"] = { .rx = std::regex("in(\\d+)_input") }; hwmon_sensors["fan_speed"] = { .rx = std::regex("fan(\\d+)_input") }; hwmon_sensors["temp"] = { .rx = std::regex("temp(\\d+)_input") }; hwmon_sensors["power"] = { .rx = std::regex("power(\\d+)_input") }; hwmon_sensors["energy"] = { .rx = std::regex("energy(\\d+)_input") }; } find_hwmon_sensors(); if (module == "i915") find_i915_gt_dir(); else if (module == "xe") find_xe_gt_dir(); thread = std::thread(&GPU_fdinfo::main_thread, this); // "mangohud-gpufdinfo" wouldn't fit in the 15 byte limit pthread_setname_np(thread.native_handle(), "mangohud-gpufd"); } ~GPU_fdinfo() { stop_thread = true; if (thread.joinable()) thread.join(); } gpu_metrics copy_metrics() const { return metrics; }; void pause() { paused = true; cond_var.notify_one(); } void resume() { paused = false; cond_var.notify_one(); } float amdgpu_helper_get_proc_vram(); }; ================================================ FILE: src/gpu_metrics_util.h ================================================ #pragma once #include struct gpu_metrics { int load; int temp; int junction_temp {-1}; int memory_temp {-1}; float sys_vram_used; float proc_vram_used; float memoryTotal; int MemClock; int CoreClock; float powerUsage; float powerLimit; float apu_cpu_power; int apu_cpu_temp; bool is_power_throttled; bool is_current_throttled; bool is_temp_throttled; bool is_other_throttled; float gtt_used; int fan_speed; int voltage; bool fan_rpm; gpu_metrics() : load(0), temp(0), junction_temp(0), memory_temp(0), sys_vram_used(0.0f), proc_vram_used(0.0f), memoryTotal(0.0f), MemClock(0), CoreClock(0), powerUsage(0.0f), powerLimit(0.0f), apu_cpu_power(0.0f), apu_cpu_temp(0), is_power_throttled(false), is_current_throttled(false), is_temp_throttled(false), is_other_throttled(false), gtt_used(0.0f), fan_speed(0), voltage(0), fan_rpm(false) {} }; #define METRICS_UPDATE_PERIOD_MS 500 #define METRICS_POLLING_PERIOD_MS 25 #define METRICS_SAMPLE_COUNT (METRICS_UPDATE_PERIOD_MS/METRICS_POLLING_PERIOD_MS) #define GPU_UPDATE_METRIC_AVERAGE(FIELD) do { int value_sum = 0; for (size_t s=0; s < METRICS_SAMPLE_COUNT; s++) { value_sum += metrics_buffer[s].FIELD; } metrics.FIELD = value_sum / METRICS_SAMPLE_COUNT; } while(0) #define GPU_UPDATE_METRIC_AVERAGE_FLOAT(FIELD) do { float value_sum = 0; for (size_t s=0; s < METRICS_SAMPLE_COUNT; s++) { value_sum += metrics_buffer[s].FIELD; } metrics.FIELD = value_sum / METRICS_SAMPLE_COUNT; } while(0) #define GPU_UPDATE_METRIC_MAX(FIELD) do { int cur_max = metrics_buffer[0].FIELD; for (size_t s=1; s < METRICS_SAMPLE_COUNT; s++) { cur_max = MAX(cur_max, metrics_buffer[s].FIELD); }; metrics.FIELD = cur_max; } while(0) #define GPU_UPDATE_METRIC_LAST(FIELD) do { metrics.FIELD = metrics_buffer[METRICS_SAMPLE_COUNT - 1].FIELD; } while(0) class Throttling { public: std::vector power; std::vector thermal; int64_t indep_throttle_status = 0; bool use_v3; std::atomic v3_power {false}; std::atomic v3_thermal {false}; uint32_t vendor_id; // CORE, HOTSPOT, SOC bits // trying to roughly match the bits that are exposed in v3 uint64_t indep_temp_mask = ((1ULL << 33) | (1ULL << 36) | (1ULL << 37)); Throttling(uint32_t vendor_id) : power(200, 0.0f), thermal(200, 0.0f), vendor_id(vendor_id) {} void update(){ if (vendor_id == 0x10de) { if (vendor_id == 0x10de && use_v3) { power.push_back(v3_power.load() ? 0.1f : 0.0f); thermal.push_back(v3_thermal.load() ? 0.1f : 0.0f); } else { power.push_back((indep_throttle_status & (1ULL << 4)) != 0 ? 0.1f : 0.0f); thermal.push_back((indep_throttle_status & indep_temp_mask) != 0 ? 0.1f : 0.0f); } } else if (vendor_id == 0x1002) { power.push_back(((indep_throttle_status >> 0 & 0xFF) != 0) ? 0.1f : 0.0f); thermal.push_back(((indep_throttle_status >> 32 & 0xFFFF) != 0) ? 0.1f : 0.0f ); } power.erase(power.begin()); thermal.erase(thermal.begin()); } bool power_throttling(){ return std::find(power.begin(), power.end(), 0.1f) != power.end(); } bool thermal_throttling(){ return std::find(thermal.begin(), thermal.end(), 0.1f) != thermal.end(); } }; ================================================ FILE: src/hud_elements.cpp ================================================ #include #include #include #include #include #include #include "overlay.h" #include "overlay_params.h" #include "hud_elements.h" #include "logging.h" #include "battery.h" #include "device.h" #include "cpu.h" #include "gpu.h" #include "memory.h" #include "iostats.h" #include "mesa/util/macros.h" #include "string_utils.h" #include "app/mangoapp.h" #include #include "version.h" #include "blacklist.h" #ifdef __linux__ #include "implot.h" #endif #include "amdgpu.h" #include "fps_metrics.h" #include "fex.h" #include "ftrace.h" #include "winesync.h" #include "fps_limiter.h" #define CHAR_CELSIUS "\xe2\x84\x83" #define CHAR_FAHRENHEIT "\xe2\x84\x89" using namespace std; // Cut from https://github.com/ocornut/imgui/pull/2943 // Probably move to ImGui static float SRGBToLinear(float in) { if (in <= 0.04045f) return in / 12.92f; else return powf((in + 0.055f) / 1.055f, 2.4f); } static ImVec4 SRGBToLinear(ImVec4 col) { col.x = SRGBToLinear(col.x); col.y = SRGBToLinear(col.y); col.z = SRGBToLinear(col.z); // Alpha component is already linear return col; } static float LinearToPQ(float in) { const float m1 = 0.1593017578125f; const float m2 = 78.84375f; const float c1 = 0.8359375f; const float c2 = 18.8515625f; const float c3 = 18.6875f; /* target 200 cd/m^2 as our maximum rather than 10000 cd/m^2 */ const float targetL = 200.f; const float maxL = 10000.0f; in = powf(in * (targetL / maxL), m1); in = (c1 + c2 * in) / (1.0f + c3 * in); return powf(in, m2); } static double dot(const ImVec4& a, const ImVec4& b) { return a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w; } static ImVec4 SRGBtoBT2020(ImVec4 col) { const ImVec4 to2020[4] = { {0.627392, 0.32903, 0.0432691, 0.0}, {0.0691229, 0.9195232, 0.0113204, 0.0}, {0.0164229, 0.088042, 0.8956166, 0.0}, {0.0, 0.0, 0.0, 1.0} }; col.x = dot(to2020[0], col); col.y = dot(to2020[1], col); col.z = dot(to2020[2], col); col.w = dot(to2020[3], col); return col; } static ImVec4 LinearToPQ(ImVec4 col) { col = SRGBtoBT2020(col); col.x = LinearToPQ(col.x); col.y = LinearToPQ(col.y); col.z = LinearToPQ(col.z); return col; } static float LinearToHLG(float in) { const float a = 0.17883277f; const float b = 0.28466892f; const float c = 0.55991073f; if (in <= 1.0f/12.0f) return sqrtf(3.0f * in); else return a * logf(12.0f * in - b) + c; } static ImVec4 LinearToHLG(ImVec4 col) { col = SRGBtoBT2020(col); col.x = LinearToHLG(col.x); col.y = LinearToHLG(col.y); col.z = LinearToHLG(col.z); return col; } template R format_units(T value, const char*& unit) { static const char* const units[] = {"B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB"}; size_t u = 0; R out_value = value; while (out_value > 1023 && u < ARRAY_SIZE(units)) { out_value /= 1024; ++u; } unit = units[u]; return out_value; } void HudElements::convert_colors(const struct overlay_params& params) { HUDElements.colors.update = false; auto convert = [¶ms](unsigned color) -> ImVec4 { ImVec4 fc = ImGui::ColorConvertU32ToFloat4(color); fc.w = params.alpha; if (HUDElements.colors.convert) { switch (params.transfer_function) { case PQ: fc = SRGBToLinear(fc); return LinearToPQ(fc); case HLG: fc = SRGBToLinear(fc); return LinearToHLG(fc); case SRGB: return SRGBToLinear(fc); default: break; } } return fc; }; HUDElements.colors.cpu = convert(params.cpu_color); HUDElements.colors.gpu = convert(params.gpu_color); HUDElements.colors.vram = convert(params.vram_color); HUDElements.colors.ram = convert(params.ram_color); HUDElements.colors.engine = convert(params.engine_color); HUDElements.colors.io = convert(params.io_color); HUDElements.colors.frametime = convert(params.frametime_color); HUDElements.colors.background = convert(params.background_color); HUDElements.colors.text = convert(params.text_color); HUDElements.colors.media_player = convert(params.media_player_color); HUDElements.colors.wine = convert(params.wine_color); HUDElements.colors.horizontal_separator = convert(params.horizontal_separator_color); HUDElements.colors.battery = convert(params.battery_color); HUDElements.colors.gpu_load_low = convert(params.gpu_load_color[0]); HUDElements.colors.gpu_load_med = convert(params.gpu_load_color[1]); HUDElements.colors.gpu_load_high = convert(params.gpu_load_color[2]); HUDElements.colors.cpu_load_low = convert(params.cpu_load_color[0]); HUDElements.colors.cpu_load_med = convert(params.cpu_load_color[1]); HUDElements.colors.cpu_load_high = convert(params.cpu_load_color[2]); HUDElements.colors.fps_value_low = convert(params.fps_color[0]); HUDElements.colors.fps_value_med = convert(params.fps_color[1]); HUDElements.colors.fps_value_high = convert(params.fps_color[2]); HUDElements.colors.text_outline = convert(params.text_outline_color); HUDElements.colors.network = convert(params.network_color); ImGuiStyle& style = ImGui::GetStyle(); style.Colors[ImGuiCol_PlotLines] = convert(params.frametime_color); style.Colors[ImGuiCol_PlotHistogram] = convert(params.frametime_color); style.Colors[ImGuiCol_WindowBg] = convert(params.background_color); style.Colors[ImGuiCol_Text] = convert(params.text_color); style.CellPadding.y = params.cellpadding_y * real_font_size.y; style.WindowRounding = params.round_corners; style.AntiAliasedLines = false; } void HudElements::convert_colors(bool do_conv, const struct overlay_params& params) { HUDElements.colors.convert = do_conv; convert_colors(params); } void HudElements::TextColored(ImVec4 col, const char *fmt, ...){ auto textColor = ImGui::ColorConvertFloat4ToU32(col); char buffer[128] {}; va_list args; va_start(args, fmt); vsnprintf(buffer, sizeof(buffer), fmt, args); va_end(args); RenderOutlinedText(buffer, textColor); } int HudElements::convert_to_fahrenheit(int celsius){ int fahrenheit = (celsius * 9 / 5) + 32; return fahrenheit; } static void ImguiNextColumnFirstItem() { ImGui::TableNextColumn(); HUDElements.table_columns_count += 1; } /** * Go to next column or second column on new row */ static void ImguiNextColumnOrNewRow(int column = -1) { if (column > -1 && column < ImGui::TableGetColumnCount()) ImGui::TableSetColumnIndex(column); else { ImGui::TableNextColumn(); HUDElements.table_columns_count += 1; if (ImGui::TableGetColumnIndex() == 0 && ImGui::TableGetColumnCount() > 1) { ImGui::TableNextColumn(); HUDElements.table_columns_count += 1; } } } static bool ImGuiTextOverflow(const char* text) { return ImGui::CalcTextSize(text).x > ImGui::CalcItemWidth() + HUDElements.ralign_width / 2; } // This function is only used in battery and battery is not used in windows builds // Battery should probably be reworked to not use this func since nothing else needs it #ifdef __linux__ static void ImGuiTableSetColumnIndex(int column) { ImGui::TableSetColumnIndex(std::max(0, std::min(column, ImGui::TableGetColumnCount() - 1))); } #endif void HudElements::time(){ if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_time]){ if (!HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_horizontal] && !HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_hud_compact] && !HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_time_no_label]){ ImguiNextColumnFirstItem(); HUDElements.TextColored(HUDElements.colors.text, "Time"); ImguiNextColumnOrNewRow(); right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, "%s", HUDElements.sw_stats->time.c_str()); } else { ImguiNextColumnFirstItem(); HUDElements.TextColored(HUDElements.colors.text, "%s", HUDElements.sw_stats->time.c_str()); } } } void HudElements::version(){ if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_version]){ ImguiNextColumnFirstItem(); HUDElements.TextColored(HUDElements.colors.text, "%s", MANGOHUD_VERSION); } } void HudElements::gpu_stats(){ if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_gpu_stats] && gpus){ for (auto& gpu : gpus->selected_gpus()) { ImguiNextColumnFirstItem(); HUDElements.TextColored(HUDElements.colors.gpu, "%s", gpu->gpu_text().c_str()); ImguiNextColumnOrNewRow(); auto text_color = HUDElements.colors.text; if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_gpu_load_change]){ struct LOAD_DATA gpu_data = { HUDElements.colors.gpu_load_low, HUDElements.colors.gpu_load_med, HUDElements.colors.gpu_load_high, HUDElements.params->gpu_load_value[0], HUDElements.params->gpu_load_value[1] }; auto load_color = change_on_load_temp(gpu_data, gpu->metrics.load); right_aligned_text(load_color, HUDElements.ralign_width, "%i", gpu->metrics.load); ImGui::SameLine(0, 1.0f); HUDElements.TextColored(load_color,"%%"); } else { right_aligned_text(text_color, HUDElements.ralign_width, "%i", gpu->metrics.load); ImGui::SameLine(0, 1.0f); HUDElements.TextColored(text_color,"%%"); // ImGui::SameLine(150); // ImGui::Text("%s", "%"); } if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_gpu_temp]){ ImguiNextColumnOrNewRow(); if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_temp_fahrenheit]) right_aligned_text(text_color, HUDElements.ralign_width, "%i", HUDElements.convert_to_fahrenheit(gpu->metrics.temp)); else right_aligned_text(text_color, HUDElements.ralign_width, "%i", gpu->metrics.temp); ImGui::SameLine(0, 1.0f); if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_hud_compact]) HUDElements.TextColored(HUDElements.colors.text, "°"); else if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_temp_fahrenheit]) HUDElements.TextColored(HUDElements.colors.text, "°F"); else HUDElements.TextColored(HUDElements.colors.text, "°C"); } if (gpu->metrics.junction_temp > -1 && HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_gpu_junction_temp]) { ImguiNextColumnOrNewRow(); if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_temp_fahrenheit]) right_aligned_text(text_color, HUDElements.ralign_width, "%i", HUDElements.convert_to_fahrenheit(gpu->metrics.junction_temp)); else right_aligned_text(text_color, HUDElements.ralign_width, "%i", gpu->metrics.junction_temp); ImGui::SameLine(0, 1.0f); if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_temp_fahrenheit]) HUDElements.TextColored(HUDElements.colors.text, "°F"); else HUDElements.TextColored(HUDElements.colors.text, "°C"); ImGui::SameLine(0, 1.0f); ImGui::PushFont(HUDElements.sw_stats->font_small); HUDElements.TextColored(HUDElements.colors.text, "Jnc"); ImGui::PopFont(); } if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_gpu_fan] && !gpu->is_apu()){ ImguiNextColumnOrNewRow(); right_aligned_text(text_color, HUDElements.ralign_width, "%i", gpu->metrics.fan_speed); ImGui::SameLine(0, 1.0f); if (gpu->metrics.fan_rpm) { ImGui::PushFont(HUDElements.sw_stats->font_small); HUDElements.TextColored(HUDElements.colors.text, "RPM"); } else { HUDElements.TextColored(HUDElements.colors.text, "%%"); ImGui::PushFont(HUDElements.sw_stats->font_small); ImGui::SameLine(0, 1.0f); HUDElements.TextColored(HUDElements.colors.text, "FAN"); } ImGui::PopFont(); } if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_gpu_core_clock]){ ImguiNextColumnOrNewRow(); right_aligned_text(text_color, HUDElements.ralign_width, "%i", gpu->metrics.CoreClock); ImGui::SameLine(0, 1.0f); ImGui::PushFont(HUDElements.sw_stats->font_small); HUDElements.TextColored(HUDElements.colors.text, "MHz"); ImGui::PopFont(); } if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_gpu_power]) { ImguiNextColumnOrNewRow(); char str[16]; snprintf(str, sizeof(str), "%.1f", gpu->metrics.powerUsage); if (strlen(str) > 4) right_aligned_text(text_color, HUDElements.ralign_width, "%.0f", gpu->metrics.powerUsage); else right_aligned_text(text_color, HUDElements.ralign_width, "%.1f", gpu->metrics.powerUsage); ImGui::SameLine(0, 1.0f); ImGui::PushFont(HUDElements.sw_stats->font_small); if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_gpu_power_limit]) HUDElements.TextColored(HUDElements.colors.text, "/%.0fW", gpu->metrics.powerLimit); else HUDElements.TextColored(HUDElements.colors.text, "W"); ImGui::PopFont(); } if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_gpu_efficiency]) { ImguiNextColumnOrNewRow(); float efficiency; const char* efficiency_unit; if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_flip_efficiency]) { efficiency=gpu->metrics.powerUsage/HUDElements.sw_stats->fps; efficiency_unit="J/F"; } else { efficiency=HUDElements.sw_stats->fps/gpu->metrics.powerUsage; efficiency_unit="F/J"; } right_aligned_text(text_color, HUDElements.ralign_width, "%.2f", efficiency); ImGui::SameLine(0, 1.0f); ImGui::PushFont(HUDElements.sw_stats->font_small); HUDElements.TextColored(HUDElements.colors.text, efficiency_unit); ImGui::PopFont(); } if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_gpu_voltage]) { ImguiNextColumnOrNewRow(); right_aligned_text(text_color, HUDElements.ralign_width, "%i", gpu->metrics.voltage); ImGui::SameLine(0, 1.0f); ImGui::PushFont(HUDElements.sw_stats->font_small); HUDElements.TextColored(HUDElements.colors.text, "mV"); ImGui::PopFont(); } if (!HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_horizontal]) ImGui::TableNextRow(); } } } void HudElements::cpu_stats(){ if(HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_cpu_stats]){ ImguiNextColumnFirstItem(); const char* cpu_text; if (HUDElements.params->cpu_text.empty()) cpu_text = "CPU"; else cpu_text = HUDElements.params->cpu_text.c_str(); HUDElements.TextColored(HUDElements.colors.cpu, "%s", cpu_text); ImguiNextColumnOrNewRow(); auto text_color = HUDElements.colors.text; if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_cpu_load_change]){ int cpu_load_percent = int(cpuStats.GetCPUDataTotal().percent); struct LOAD_DATA cpu_data = { HUDElements.colors.cpu_load_low, HUDElements.colors.cpu_load_med, HUDElements.colors.cpu_load_high, HUDElements.params->cpu_load_value[0], HUDElements.params->cpu_load_value[1] }; auto load_color = change_on_load_temp(cpu_data, cpu_load_percent); right_aligned_text(load_color, HUDElements.ralign_width, "%d", cpu_load_percent); ImGui::SameLine(0, 1.0f); HUDElements.TextColored(load_color, "%%"); } else { right_aligned_text(text_color, HUDElements.ralign_width, "%d", int(cpuStats.GetCPUDataTotal().percent)); ImGui::SameLine(0, 1.0f); HUDElements.TextColored(HUDElements.colors.text, "%%"); } if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_cpu_temp]){ ImguiNextColumnOrNewRow(); if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_temp_fahrenheit]) right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, "%i", HUDElements.convert_to_fahrenheit(cpuStats.GetCPUDataTotal().temp)); else right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, "%i", cpuStats.GetCPUDataTotal().temp); ImGui::SameLine(0, 1.0f); if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_hud_compact]) HUDElements.TextColored(HUDElements.colors.text, "°"); else if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_temp_fahrenheit]) HUDElements.TextColored(HUDElements.colors.text, "°F"); else HUDElements.TextColored(HUDElements.colors.text, "°C"); } if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_cpu_mhz]){ ImguiNextColumnOrNewRow(); right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, "%i", cpuStats.GetCPUDataTotal().cpu_mhz); ImGui::SameLine(0, 1.0f); ImGui::PushFont(HUDElements.sw_stats->font_small); HUDElements.TextColored(HUDElements.colors.text, "MHz"); ImGui::PopFont(); } if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_cpu_power]){ ImguiNextColumnOrNewRow(); char str[16]; snprintf(str, sizeof(str), "%.1f", cpuStats.GetCPUDataTotal().power); if (strlen(str) > 4) right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, "%.0f", cpuStats.GetCPUDataTotal().power); else right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, "%.1f", cpuStats.GetCPUDataTotal().power); ImGui::SameLine(0, 1.0f); ImGui::PushFont(HUDElements.sw_stats->font_small); HUDElements.TextColored(HUDElements.colors.text, "W"); ImGui::PopFont(); } if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_cpu_efficiency]) { ImguiNextColumnOrNewRow(); float efficiency; const char* efficiency_unit; if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_flip_efficiency]) { efficiency=cpuStats.GetCPUDataTotal().power/HUDElements.sw_stats->fps; efficiency_unit="J/F"; } else { efficiency=HUDElements.sw_stats->fps/cpuStats.GetCPUDataTotal().power; efficiency_unit="F/J"; } right_aligned_text(text_color, HUDElements.ralign_width, "%.2f", efficiency); ImGui::SameLine(0, 1.0f); ImGui::PushFont(HUDElements.sw_stats->font_small); HUDElements.TextColored(HUDElements.colors.text, efficiency_unit); ImGui::PopFont(); } } } static float get_core_load_stat(void*,int); static float get_core_load_stat(void *data, int idx){ return ((CPUStats *)data)->GetCPUData().at(idx).percent; } void HudElements::core_load(){ if (!HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_core_load]) return; if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_core_bars]){ ImguiNextColumnFirstItem(); ImGui::PushFont(HUDElements.sw_stats->font_small); if (!HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_horizontal] && !HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_hud_compact]){ ImGui::Dummy(ImVec2(0.0f, real_font_size.y)); HUDElements.TextColored(HUDElements.colors.cpu, "CPU Cores"); ImGui::TableSetColumnIndex(ImGui::TableGetColumnCount() - 1); ImGui::Dummy(ImVec2(0.0f, real_font_size.y)); ImguiNextColumnFirstItem(); } char hash[40]; snprintf(hash, sizeof(hash), "##%s", overlay_param_names[OVERLAY_PARAM_ENABLED_core_bars]); ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(0.0f, 0.0f, 0.0f, 0.0f)); float width, height = 0; if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_horizontal]){ width = 150; height = HUDElements.params->font_size; } else { width = (ImGui::GetWindowContentRegionMax().x - ImGui::GetWindowContentRegionMin().x); height = 50; } if (ImGui::BeginChild("core_bars_window", ImVec2(width, height))) { ImGui::PlotHistogram(hash, get_core_load_stat, &cpuStats, cpuStats.GetCPUData().size(), 0, NULL, 0.0, 100.0, ImVec2(width, height)); } ImGui::EndChild(); ImGui::PopFont(); ImGui::PopStyleColor(); } else { for (const CPUData &cpuData : cpuStats.GetCPUData()) { ImguiNextColumnFirstItem(); HUDElements.TextColored(HUDElements.colors.cpu, "CPU"); ImGui::SameLine(0, 1.0f); ImGui::PushFont(HUDElements.sw_stats->font_small); if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_core_type]) HUDElements.TextColored(HUDElements.colors.cpu, cpuData.label.c_str()); else HUDElements.TextColored(HUDElements.colors.cpu, "%i", cpuData.cpu_id); ImGui::PopFont(); ImguiNextColumnOrNewRow(); auto text_color = HUDElements.colors.text; if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_core_load_change]){ int cpu_load_percent = int(cpuData.percent); struct LOAD_DATA cpu_data = { HUDElements.colors.cpu_load_low, HUDElements.colors.cpu_load_med, HUDElements.colors.cpu_load_high, HUDElements.params->cpu_load_value[0], HUDElements.params->cpu_load_value[1] }; auto load_color = change_on_load_temp(cpu_data, cpu_load_percent); right_aligned_text(load_color, HUDElements.ralign_width, "%d", cpu_load_percent); ImGui::SameLine(0, 1.0f); HUDElements.TextColored(load_color, "%%"); ImguiNextColumnOrNewRow(); } else { right_aligned_text(text_color, HUDElements.ralign_width, "%i", int(cpuData.percent)); ImGui::SameLine(0, 1.0f); HUDElements.TextColored(HUDElements.colors.text, "%%"); ImguiNextColumnOrNewRow(); } right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, "%i", cpuData.mhz); ImGui::SameLine(0, 1.0f); ImGui::PushFont(HUDElements.sw_stats->font_small); HUDElements.TextColored(HUDElements.colors.text, "MHz"); ImGui::PopFont(); } } } void HudElements::io_stats(){ #ifndef _WIN32 if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_io_read] || HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_io_write]){ ImguiNextColumnFirstItem(); if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_io_read] && !HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_io_write]) HUDElements.TextColored(HUDElements.colors.io, "IO RD"); else if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_io_read] && HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_io_write]) HUDElements.TextColored(HUDElements.colors.io, "IO RW"); else if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_io_write] && !HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_io_read]) HUDElements.TextColored(HUDElements.colors.io, "IO WR"); if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_io_read]){ ImguiNextColumnOrNewRow(); const float val = g_io_stats.per_second.read; right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, val < 100 ? "%.1f" : "%.f", val); ImGui::SameLine(0,1.0f); ImGui::PushFont(HUDElements.sw_stats->font_small); HUDElements.TextColored(HUDElements.colors.text, "MiB/s"); ImGui::PopFont(); } if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_io_write]){ ImguiNextColumnOrNewRow(); const float val = g_io_stats.per_second.write; right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, val < 100 ? "%.1f" : "%.f", val); ImGui::SameLine(0,1.0f); ImGui::PushFont(HUDElements.sw_stats->font_small); HUDElements.TextColored(HUDElements.colors.text, "MiB/s"); ImGui::PopFont(); } } #endif } void HudElements::vram(){ if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_vram] && gpus){ size_t i = 0; if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_gpu_stats]){ for (auto& gpu : gpus->selected_gpus()) { ImguiNextColumnFirstItem(); // Just iterate through the user selected GPUs if (!HUDElements.params->gpu_list.empty()) for (auto& gpu_index : HUDElements.params->gpu_list) if (gpu_index < gpus->available_gpus.size()) if (i != gpu_index) continue; HUDElements.TextColored(HUDElements.colors.vram, gpu->vram_text().c_str()); ImguiNextColumnOrNewRow(); // Add gtt_used to vram usage for APUs if (gpu->is_apu()) right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, "%.1f", gpu->metrics.sys_vram_used + gpu->metrics.gtt_used); else right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, "%.1f", gpu->metrics.sys_vram_used); if (!HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_hud_compact]){ ImGui::SameLine(0,1.0f); ImGui::PushFont(HUDElements.sw_stats->font_small); HUDElements.TextColored(HUDElements.colors.text, "GiB"); ImGui::PopFont(); } if (gpu->metrics.memory_temp > -1 && HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_gpu_mem_temp]) { ImguiNextColumnOrNewRow(); if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_temp_fahrenheit]) right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, "%i", HUDElements.convert_to_fahrenheit(gpu->metrics.memory_temp)); else right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, "%i", gpu->metrics.memory_temp); ImGui::SameLine(0, 1.0f); if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_temp_fahrenheit]) HUDElements.TextColored(HUDElements.colors.text, "°F"); else HUDElements.TextColored(HUDElements.colors.text, "°C"); } if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_gpu_mem_clock]){ ImguiNextColumnOrNewRow(); right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, "%i", gpu->metrics.MemClock); ImGui::SameLine(0, 1.0f); ImGui::PushFont(HUDElements.sw_stats->font_small); HUDElements.TextColored(HUDElements.colors.text, "MHz"); ImGui::PopFont(); } if (!HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_horizontal]) ImGui::TableNextRow(); i++; } } } } void HudElements::proc_vram() { if ( !HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_proc_vram] || !HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_gpu_stats] ) return; if (!gpus) return; size_t idx = 0; for (const std::shared_ptr& gpu : gpus->selected_gpus()) { ImguiNextColumnFirstItem(); if (gpus->selected_gpus().size() > 1) HUDElements.TextColored(HUDElements.colors.vram, "PVRAM%i", idx++); else HUDElements.TextColored(HUDElements.colors.vram, "PVRAM"); ImguiNextColumnOrNewRow(); right_aligned_text( HUDElements.colors.text, HUDElements.ralign_width, "%.1f", gpu->metrics.proc_vram_used ); if (!HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_hud_compact]) { ImGui::SameLine(0, 1.0f); ImGui::PushFont(HUDElements.sw_stats->font_small); HUDElements.TextColored(HUDElements.colors.text, "GiB"); ImGui::PopFont(); } // show only if vram is not enabled if ( !HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_vram] && HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_gpu_mem_temp] ) { ImguiNextColumnOrNewRow(); int temp; std::string unit; if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_temp_fahrenheit]) { temp = HUDElements.convert_to_fahrenheit(gpu->metrics.memory_temp); unit = "°F"; } else { temp = gpu->metrics.memory_temp; unit = "°C"; } right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, "%i", temp); ImGui::SameLine(0, 1.0f); HUDElements.TextColored(HUDElements.colors.text, unit.c_str()); } if (!HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_horizontal]) ImGui::TableNextRow(); } } void HudElements::ram(){ #ifdef __linux__ if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_ram] || HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_ram_temp]) { ImguiNextColumnFirstItem(); HUDElements.TextColored(HUDElements.colors.ram, "RAM"); } if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_ram]) { ImguiNextColumnOrNewRow(); right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, "%.1f", memused); if (!HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_hud_compact]){ ImGui::SameLine(0, 1.0f); ImGui::PushFont(HUDElements.sw_stats->font_small); HUDElements.TextColored(HUDElements.colors.text, "GiB"); ImGui::PopFont(); } } if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_ram] && HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_swap]){ ImguiNextColumnOrNewRow(); right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, "%.1f", swapused); ImGui::SameLine(0, 1.0f); ImGui::PushFont(HUDElements.sw_stats->font_small); HUDElements.TextColored(HUDElements.colors.text, "GiB"); ImGui::PopFont(); } if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_ram_temp]) { ImguiNextColumnOrNewRow(); if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_temp_fahrenheit]) right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, "%i", HUDElements.convert_to_fahrenheit(mem_temp)); else right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, "%i", mem_temp); ImGui::SameLine(0, 1.0f); if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_hud_compact]) HUDElements.TextColored(HUDElements.colors.text, "°"); else if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_temp_fahrenheit]) HUDElements.TextColored(HUDElements.colors.text, "°F"); else HUDElements.TextColored(HUDElements.colors.text, "°C"); } #endif } void HudElements::procmem() { #ifdef __linux__ const char* unit = nullptr; if (!HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_procmem]) return; ImguiNextColumnFirstItem(); HUDElements.TextColored(HUDElements.colors.ram, "PMEM"); ImguiNextColumnOrNewRow(); right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, "%.1f", format_units(proc_mem_resident, unit)); ImGui::SameLine(0, 1.0f); ImGui::PushFont(HUDElements.sw_stats->font_small); HUDElements.TextColored(HUDElements.colors.text, "%s", unit); ImGui::PopFont(); if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_procmem_shared]) { ImguiNextColumnOrNewRow(); right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, "%.1f", format_units(proc_mem_shared, unit)); ImGui::SameLine(0,1.0f); ImGui::PushFont(HUDElements.sw_stats->font_small); HUDElements.TextColored(HUDElements.colors.text, "%s", unit); ImGui::PopFont(); } if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_procmem_virt]) { ImguiNextColumnOrNewRow(); right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, "%.1f", format_units(proc_mem_virt, unit)); ImGui::SameLine(0, 1.0f); ImGui::PushFont(HUDElements.sw_stats->font_small); HUDElements.TextColored(HUDElements.colors.text, "%s", unit); ImGui::PopFont(); } #endif } void HudElements::fps(){ if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_fps] && !HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_fps_only]){ ImguiNextColumnFirstItem(); HUDElements.TextColored(HUDElements.colors.engine, "%s", engine_name(*HUDElements.sw_stats)); ImguiNextColumnOrNewRow(); if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_fps_color_change]){ int fps = int(HUDElements.sw_stats->fps); struct LOAD_DATA fps_data = { HUDElements.colors.fps_value_low, HUDElements.colors.fps_value_med, HUDElements.colors.fps_value_high, HUDElements.params->fps_value[0], HUDElements.params->fps_value[1] }; auto load_color = change_on_load_temp(fps_data, fps); right_aligned_text(load_color, HUDElements.ralign_width, "%.0f", HUDElements.sw_stats->fps); } else { right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, "%.0f", HUDElements.sw_stats->fps); } ImGui::SameLine(0, 1.0f); if(!HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_hide_fps_superscript]){ ImGui::PushFont(HUDElements.sw_stats->font_small); HUDElements.TextColored(HUDElements.colors.text, "FPS"); ImGui::PopFont(); } if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_frametime]){ ImguiNextColumnOrNewRow(); right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, "%.1f", 1000 / HUDElements.sw_stats->fps); ImGui::SameLine(0, 1.0f); ImGui::PushFont(HUDElements.sw_stats->font_small); HUDElements.TextColored(HUDElements.colors.text, "ms"); ImGui::PopFont(); } } else if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_engine_version]){ ImguiNextColumnOrNewRow(); HUDElements.TextColored(HUDElements.colors.engine, "%s", HUDElements.sw_stats->engineName.c_str()); } } void HudElements::fps_only(){ if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_fps_only]){ ImguiNextColumnFirstItem(); auto load_color = HUDElements.colors.text; if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_fps_color_change]){ int fps = int(HUDElements.sw_stats->fps); struct LOAD_DATA fps_data = { HUDElements.colors.fps_value_low, HUDElements.colors.fps_value_med, HUDElements.colors.fps_value_high, HUDElements.params->fps_value[0], HUDElements.params->fps_value[1] }; load_color = change_on_load_temp(fps_data, fps); } HUDElements.TextColored(load_color, "%.0f", HUDElements.sw_stats->fps); } } void HudElements::gpu_name(){ if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_gpu_name] && !HUDElements.sw_stats->gpuName.empty()){ ImguiNextColumnFirstItem(); ImGui::PushFont(HUDElements.sw_stats->font_secondary); HUDElements.TextColored(HUDElements.colors.engine, "%s", HUDElements.sw_stats->gpuName.c_str()); ImGui::PopFont(); } } void HudElements::engine_version(){ if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_engine_version]){ ImguiNextColumnFirstItem(); ImGui::PushFont(HUDElements.sw_stats->font_secondary); if (HUDElements.is_vulkan) { if ((HUDElements.sw_stats->engine == EngineTypes::DXVK || HUDElements.sw_stats->engine == EngineTypes::VKD3D)){ HUDElements.TextColored(HUDElements.colors.engine, "%s/%d.%d.%d", HUDElements.sw_stats->engineVersion.c_str(), HUDElements.sw_stats->version_vk.major, HUDElements.sw_stats->version_vk.minor, HUDElements.sw_stats->version_vk.patch); } else { HUDElements.TextColored(HUDElements.colors.engine, "%d.%d.%d", HUDElements.sw_stats->version_vk.major, HUDElements.sw_stats->version_vk.minor, HUDElements.sw_stats->version_vk.patch); } } else { HUDElements.TextColored(HUDElements.colors.engine, "%d.%d%s", HUDElements.sw_stats->version_gl.major, HUDElements.sw_stats->version_gl.minor, HUDElements.sw_stats->version_gl.is_gles ? " ES" : ""); } ImGui::PopFont(); } } void HudElements::vulkan_driver(){ if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_vulkan_driver] && !HUDElements.sw_stats->driverName.empty()){ ImguiNextColumnFirstItem(); ImGui::PushFont(HUDElements.sw_stats->font_secondary); HUDElements.TextColored(HUDElements.colors.engine, "%s", HUDElements.sw_stats->driverName.c_str()); ImGui::PopFont(); } } void HudElements::arch(){ if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_arch]){ ImguiNextColumnFirstItem(); ImGui::PushFont(HUDElements.sw_stats->font_secondary); HUDElements.TextColored(HUDElements.colors.engine, "%s", "" MANGOHUD_ARCH); ImGui::PopFont(); } } void HudElements::wine(){ if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_wine]){ ImguiNextColumnFirstItem(); if (!wineVersion.empty()){ ImGui::PushFont(HUDElements.sw_stats->font_secondary); HUDElements.TextColored(HUDElements.colors.wine, "%s", wineVersion.c_str()); ImGui::PopFont(); } } } static inline double TransformForward_Custom(double v, void*) { if (v > 50) v = 49.9; return v; } static inline double TransformInverse_Custom(double v, void*) { return v; } void HudElements::frame_timing(){ if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_frame_timing]){ ImguiNextColumnFirstItem(); ImGui::PushFont(HUDElements.sw_stats->font_small); if (!HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_horizontal] && !HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_hud_compact]){ ImGui::Dummy(ImVec2(0.0f, real_font_size.y)); HUDElements.TextColored(HUDElements.colors.engine, "%s", "Frametime"); ImGui::TableSetColumnIndex(ImGui::TableGetColumnCount() - 1); ImGui::Dummy(ImVec2(0.0f, real_font_size.y)); right_aligned_text(HUDElements.colors.text, ImGui::GetContentRegionAvail().x, "min: %.1fms, max: %.1fms", min_frametime, max_frametime); ImGui::Dummy(ImVec2(0.0f, real_font_size.y / 2)); ImguiNextColumnFirstItem(); } char hash[40]; snprintf(hash, sizeof(hash), "##%s", overlay_param_names[OVERLAY_PARAM_ENABLED_frame_timing]); HUDElements.sw_stats->stat_selector = OVERLAY_PLOTS_frame_timing; HUDElements.sw_stats->time_dividor = 1000000.0f; /* ns -> ms */ ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(0.0f, 0.0f, 0.0f, 0.0f)); double min_time = 0.0f; double max_time = 50.0f; float width, height = 0; if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_horizontal]){ width = 150; height = HUDElements.params->font_size * 0.85; } else { width = (ImGui::GetWindowContentRegionMax().x - ImGui::GetWindowContentRegionMin().x); height = max_time; } if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_dynamic_frame_timing]){ min_time = min_frametime; max_time = max_frametime; } if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_frame_timing_detailed]){ height = 125; } if (ImGui::BeginChild("my_child_window", ImVec2(width, height), false, ImGuiWindowFlags_NoDecoration)) { if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_histogram]){ ImGui::PlotHistogram(hash, get_time_stat, HUDElements.sw_stats, ARRAY_SIZE(HUDElements.sw_stats->frames_stats), 0, NULL, min_time, max_time, ImVec2(width, height)); } else { #ifndef __linux__ ImGui::PlotLines(hash, get_time_stat, HUDElements.sw_stats, ARRAY_SIZE(HUDElements.sw_stats->frames_stats), 0, NULL, min_time, max_time, ImVec2(width, height)); #else if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_horizontal]) { ImGui::PlotLines(hash, get_time_stat, HUDElements.sw_stats, ARRAY_SIZE(HUDElements.sw_stats->frames_stats), 0, NULL, min_time, max_time, ImVec2(width, height)); } else { if (ImPlot::BeginPlot("My Plot", ImVec2(width, height), ImPlotFlags_CanvasOnly | ImPlotFlags_NoInputs)) { ImPlotStyle& style = ImPlot::GetStyle(); style.Colors[ImPlotCol_PlotBg] = ImVec4(0.92f, 0.92f, 0.95f, 0.00f); style.Colors[ImPlotCol_AxisGrid] = ImVec4(0.0f, 0.0f, 0.0f, 1.0f); style.Colors[ImPlotCol_AxisTick] = ImVec4(0.0f, 0.0f, 0.0f, 1.0f); ImPlotAxisFlags ax_flags_x = ImPlotAxisFlags_NoDecorations; ImPlotAxisFlags ax_flags_y = ImPlotAxisFlags_NoDecorations; if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_frame_timing_detailed]) ax_flags_y = ImPlotAxisFlags_Opposite | ImPlotAxisFlags_NoMenus; ImPlot::SetupAxes(nullptr, nullptr, ax_flags_x, ax_flags_y); ImPlot::SetupAxisScale(ImAxis_Y1, TransformForward_Custom, TransformInverse_Custom); ImPlot::SetupAxesLimits(0, 200, min_time, max_time, ImGuiCond_Always); ImPlot::SetNextLineStyle(HUDElements.colors.frametime, 1.5); ImPlot::PlotLine("frametime line", frametime_data.data(), frametime_data.size()); if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_throttling_status_graph] && gpus && gpus->active_gpu() && gpus->active_gpu()->throttling()){ ImPlot::SetNextLineStyle(ImVec4(1.0f, 1.0f, 0.0f, 1.0f), 1.5); ImPlot::PlotLine("power line", gpus->active_gpu()->throttling()->power.data(), gpus->active_gpu()->throttling()->power.size()); ImPlot::SetNextLineStyle(ImVec4(1.0f, 0.0f, 0.0f, 1.0f), 1.5); ImPlot::PlotLine("thermal line", gpus->active_gpu()->throttling()->thermal.data(), gpus->active_gpu()->throttling()->thermal.size()); } ImPlot::EndPlot(); } } #endif } } ImGui::EndChild(); #ifdef __linux__ if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_throttling_status_graph] && gpus && gpus->active_gpu() && gpus->active_gpu()->throttling()){ ImGui::Dummy(ImVec2(0.0f, real_font_size.y / 2)); if (gpus->active_gpu()->throttling()->power_throttling()) { ImGui::TextColored(ImVec4(1.0f, 1.0f, 0.0f, 1.0f), "%s", ICON_FK_SQUARE); ImGui::SameLine(); ImGui::Text("Power throttling"); } ImGui::Dummy(ImVec2(0.0f, real_font_size.y / 2)); if (gpus->active_gpu()->throttling()->thermal_throttling()) { ImGui::TextColored(ImVec4(1.0f, 0.0f, 0.0f, 1.0f), "%s", ICON_FK_SQUARE); ImGui::SameLine(); ImGui::Text("Thermal throttling"); } } ImGui::PopFont(); ImGui::PopStyleColor(); #endif } } void HudElements::media_player(){ #ifdef HAVE_DBUS if (!HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_media_player]) return; ImguiNextColumnFirstItem(); uint32_t f_idx = (HUDElements.sw_stats->n_frames - 1) % ARRAY_SIZE(HUDElements.sw_stats->frames_stats); uint64_t frame_timing = HUDElements.sw_stats->frames_stats[f_idx].stats[OVERLAY_PLOTS_frame_timing]; ImFont scaled_font = *HUDElements.sw_stats->font_text; scaled_font.Scale = HUDElements.params->font_scale_media_player; ImGui::PushFont(&scaled_font); { std::unique_lock lck(main_metadata.mtx, std::try_to_lock); if (lck.owns_lock()) render_mpris_metadata(*HUDElements.params, main_metadata, frame_timing); else SPDLOG_DEBUG("failed to acquire lock"); } if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_horizontal]) { ImguiNextColumnFirstItem(); } if (!main_metadata.meta.playing) { HUDElements.TextColored(HUDElements.colors.media_player, "(paused)"); } ImGui::PopFont(); #endif } void HudElements::resolution(){ if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_resolution]){ ImguiNextColumnFirstItem(); const auto res = ImGui::GetIO().DisplaySize; ImGui::PushFont(HUDElements.sw_stats->font_secondary); const char * title = "Resolution"; HUDElements.TextColored(HUDElements.colors.engine, title); ImguiNextColumnOrNewRow(); // Jump a column if title is overflowing if (ImGuiTextOverflow(title)) ImguiNextColumnOrNewRow(); right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width * 1.5f, "%.0fx%.0f", res.x, res.y); ImGui::PopFont(); } } void HudElements::show_fps_limit(){ if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_show_fps_limit]){ if (fps_limiter && fps_limiter->active) { ImguiNextColumnFirstItem(); ImGui::PushFont(HUDElements.sw_stats->font_secondary); const char* method = fps_limiter->use_early ? "early" : "late"; HUDElements.TextColored(HUDElements.colors.engine, "%s","FPS limit"); ImguiNextColumnOrNewRow(); right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, "%s", method); ImguiNextColumnOrNewRow(); right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, "%i", fps_limiter->current_limit()); ImGui::PopFont(); } } } void HudElements::custom_text_center(){ if (HUDElements.place >= 0 && static_cast(HUDElements.place) < HUDElements.ordered_functions.size()) { if (!HUDElements.sw_stats || !HUDElements.sw_stats->font_secondary) { return; } ImguiNextColumnFirstItem(); ImGui::PushFont(HUDElements.sw_stats->font_secondary); const std::string& value = HUDElements.ordered_functions[HUDElements.place].value; center_text(value); HUDElements.TextColored(HUDElements.colors.text, "%s", value.c_str()); ImGui::NewLine(); ImGui::PopFont(); } } void HudElements::custom_text(){ ImguiNextColumnFirstItem(); ImGui::PushFont(HUDElements.sw_stats->font_secondary); const char* value; if (size_t(HUDElements.place) < HUDElements.ordered_functions.size()) value = HUDElements.ordered_functions[HUDElements.place].value.c_str(); else { ImGui::PopFont(); return; } HUDElements.TextColored(HUDElements.colors.text, "%s",value); ImGui::PopFont(); } void HudElements::_exec(){ //const std::string& value = HUDElements.ordered_functions[HUDElements.place].second; ImGui::PushFont(HUDElements.sw_stats->font_secondary); ImguiNextColumnFirstItem(); for (auto& item : HUDElements.exec_list){ if (item.pos == HUDElements.place){ if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_horizontal]) HUDElements.TextColored(HUDElements.colors.text, "%s",item.ret.c_str()); else right_aligned_text(HUDElements.colors.text,HUDElements.ralign_width, "%s", item.ret.c_str()); } } ImGui::PopFont(); } void HudElements::gamemode(){ if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_gamemode]){ ImguiNextColumnFirstItem(); ImGui::PushFont(HUDElements.sw_stats->font_secondary); HUDElements.TextColored(HUDElements.colors.engine, "%s", "GAMEMODE"); ImguiNextColumnOrNewRow(); right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, "%s", HUDElements.gamemode_bol ? "ON" : "OFF"); ImGui::PopFont(); } } void HudElements::vkbasalt(){ if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_vkbasalt]){ ImguiNextColumnFirstItem(); ImGui::PushFont(HUDElements.sw_stats->font_secondary); HUDElements.TextColored(HUDElements.colors.engine, "%s", "VKBASALT"); ImguiNextColumnOrNewRow(); right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, "%s", HUDElements.vkbasalt_bol ? "ON" : "OFF"); ImGui::PopFont(); } } void HudElements::battery(){ #ifdef __linux__ if (Battery_Stats.batt_count > 0) { if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_battery]) { ImguiNextColumnFirstItem(); if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_hud_compact]) HUDElements.TextColored(HUDElements.colors.battery, "BAT"); else HUDElements.TextColored(HUDElements.colors.battery, "BATT"); ImguiNextColumnOrNewRow(); if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_battery_icon]) { switch(int(Battery_Stats.current_percent)){ case 0 ... 33: right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, "%s", ICON_FK_BATTERY_QUARTER); break; case 34 ... 66: right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, "%s", ICON_FK_BATTERY_HALF); break; case 67 ... 97: right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, "%s", ICON_FK_BATTERY_THREE_QUARTERS); break; case 98 ... 100: right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, "%s", ICON_FK_BATTERY_FULL); break; } } else { right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, "%.0f", Battery_Stats.current_percent); ImGui::SameLine(0,1.0f); HUDElements.TextColored(HUDElements.colors.text, "%%"); } if (Battery_Stats.current_watt != 0) { if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_battery_watt]){ ImguiNextColumnOrNewRow(); if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_hud_compact] && Battery_Stats.current_watt >= 10.0f) right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, "%.0f", Battery_Stats.current_watt); else right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, "%.1f", Battery_Stats.current_watt); ImGui::SameLine(0,1.0f); ImGui::PushFont(HUDElements.sw_stats->font_small); HUDElements.TextColored(HUDElements.colors.text, "W"); ImGui::PopFont(); } if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_battery_time]) { float hours; float minutes; minutes = std::modf(Battery_Stats.remaining_time, &hours); minutes *= 60; char time_buffer[32]; snprintf(time_buffer, sizeof(time_buffer), "%02d:%02d", static_cast(hours), static_cast(minutes)); if (!HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_horizontal] && !HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_hud_compact]){ ImGui::TableNextRow(); ImGui::NextColumn(); ImGui::PushFont(HUDElements.sw_stats->font_small); ImGuiTableSetColumnIndex(0); HUDElements.TextColored(HUDElements.colors.text, "%s", "Remaining Time"); ImGui::PopFont(); ImGuiTableSetColumnIndex(2); } else { if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_horizontal]) ImguiNextColumnOrNewRow(); ImguiNextColumnOrNewRow(); } if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_hud_compact]) ImGuiTableSetColumnIndex(0); right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, "%s", time_buffer); } } else { ImguiNextColumnOrNewRow(); right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, "%s", ICON_FK_PLUG); } } } #endif } void HudElements::gamescope_fsr(){ if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_fsr] && HUDElements.g_fsrUpscale >= 0) { ImguiNextColumnFirstItem(); string FSR_TEXT; ImVec4 FSR_COLOR; if (HUDElements.g_fsrUpscale){ FSR_TEXT = "ON"; FSR_COLOR = HUDElements.colors.fps_value_high; } else { FSR_TEXT = "OFF"; FSR_COLOR = HUDElements.colors.fps_value_low; } HUDElements.TextColored(HUDElements.colors.engine, "%s", "FSR"); ImguiNextColumnOrNewRow(); right_aligned_text(FSR_COLOR, HUDElements.ralign_width, "%s", FSR_TEXT.c_str()); if (HUDElements.g_fsrUpscale){ if (!HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_hide_fsr_sharpness]) { ImguiNextColumnOrNewRow(); right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, "%i", HUDElements.g_fsrSharpness); ImGui::SameLine(0,1.0f); ImGui::PushFont(HUDElements.sw_stats->font_small); HUDElements.TextColored(HUDElements.colors.text, "Sharp"); ImGui::PopFont(); } } } } void HudElements::gamescope_frame_timing(){ if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_debug]) { static std::vector::iterator min, max; static double min_time = 0.0f; static double max_time = 50.0f; if (HUDElements.gamescope_debug_app.size() > 0 && HUDElements.gamescope_debug_app.back() > -1){ auto min = std::min_element(HUDElements.gamescope_debug_app.begin(), HUDElements.gamescope_debug_app.end()); auto max = std::max_element(HUDElements.gamescope_debug_app.begin(), HUDElements.gamescope_debug_app.end()); ImGui::PushFont(HUDElements.sw_stats->font_small); ImGui::Dummy(ImVec2(0.0f, real_font_size.y)); HUDElements.TextColored(HUDElements.colors.engine, "%s", "App"); ImGui::TableSetColumnIndex(ImGui::TableGetColumnCount() - 1); right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width * 1.3, "min: %.1fms, max: %.1fms", min[0], max[0]); ImGui::Dummy(ImVec2(0.0f, real_font_size.y / 2)); ImguiNextColumnFirstItem(); ImGui::PopFont(); char hash[40]; snprintf(hash, sizeof(hash), "##%s", overlay_param_names[OVERLAY_PARAM_ENABLED_frame_timing]); HUDElements.sw_stats->stat_selector = OVERLAY_PLOTS_frame_timing; HUDElements.sw_stats->time_dividor = 1000000.0f; /* ns -> ms */ ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(0.0f, 0.0f, 0.0f, 0.0f)); if (ImGui::BeginChild("gamescope_app_window", ImVec2((ImGui::GetWindowContentRegionMax().x - ImGui::GetWindowContentRegionMin().x), 50))) { ImGui::PlotLines("gamescope debug lines", HUDElements.gamescope_debug_app.data(), HUDElements.gamescope_debug_app.size(), 0, NULL, min_time, max_time, ImVec2((ImGui::GetWindowContentRegionMax().x - ImGui::GetWindowContentRegionMin().x), 50)); } ImGui::PopStyleColor(); ImGui::EndChild(); } if (HUDElements.gamescope_debug_latency.size() > 0 && HUDElements.gamescope_debug_latency.back() > -1){ ImguiNextColumnOrNewRow(); ImGui::Dummy(ImVec2(0.0f, real_font_size.y)); ImGui::PushFont(HUDElements.sw_stats->font_small); HUDElements.TextColored(HUDElements.colors.engine, "%s", "Latency"); ImGui::TableNextRow(); ImGui::Dummy(ImVec2(0.0f, real_font_size.y)); min = std::min_element(HUDElements.gamescope_debug_latency.begin(), HUDElements.gamescope_debug_latency.end()); max = std::max_element(HUDElements.gamescope_debug_latency.begin(), HUDElements.gamescope_debug_latency.end()); right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width * 1.3, "min: %.1fms, max: %.1fms", min[0], max[0]); ImGui::PopFont(); ImguiNextColumnFirstItem(); ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(0.0f, 0.0f, 0.0f, 0.0f)); ImGui::PushStyleColor(ImGuiCol_PlotLines, ImVec4(0,0,1,1)); if (ImGui::BeginChild("gamescope_latency_window", ImVec2((ImGui::GetWindowContentRegionMax().x - ImGui::GetWindowContentRegionMin().x), 50))) { ImGui::PlotLines("gamescope debug latency lines", HUDElements.gamescope_debug_latency.data(), HUDElements.gamescope_debug_latency.size(), 0, NULL, min_time, max_time, ImVec2((ImGui::GetWindowContentRegionMax().x - ImGui::GetWindowContentRegionMin().x), 50)); } ImGui::PopStyleColor(2); ImGui::EndChild(); } } } void HudElements::device_battery() { #ifdef __linux__ std::unique_lock l(device_lock); if (!HUDElements.params->device_battery.empty()) { if (device_found) { for (int i = 0; i < device_count; i++) { std::string battery = device_data[i].battery; std::string name = device_data[i].name; std::string battery_percent = device_data[i].battery_percent; bool report_percent = device_data[i].report_percent; bool charging = device_data[i].is_charging; ImguiNextColumnFirstItem(); ImGui::PushFont(HUDElements.sw_stats->font_secondary); HUDElements.TextColored(HUDElements.colors.engine, "%s", name.c_str()); ImguiNextColumnOrNewRow(); if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_device_battery_icon]) { if (charging) right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, "%s", ICON_FK_USB); else { if (battery == "Full") right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, "%s", ICON_FK_BATTERY_FULL); else if (battery == "High") right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, "%s", ICON_FK_BATTERY_THREE_QUARTERS); else if (battery == "Normal") right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, "%s", ICON_FK_BATTERY_HALF); else if (battery == "Low") right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, "%s", ICON_FK_BATTERY_QUARTER); else if (battery == "Unknown") right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, "%s", ICON_FK_USB); } } else { if (charging) right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, "%s", ICON_FK_USB); else if (report_percent) { right_aligned_text(HUDElements.colors.text,HUDElements.ralign_width, "%s", battery_percent.c_str()); ImGui::SameLine(0,1.0f); HUDElements.TextColored(HUDElements.colors.text, "%%"); } else { if (battery == "Unknown") right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, "%s", ICON_FK_USB); else right_aligned_text(HUDElements.colors.text,HUDElements.ralign_width, "%s", battery.c_str()); } } if (device_count > 1 && !HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_horizontal]) ImGui::TableNextRow(); ImGui::PopFont(); } } } #endif } void HudElements::frame_count(){ if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_frame_count]){ ImguiNextColumnFirstItem(); ImGui::PushFont(HUDElements.sw_stats->font_secondary); HUDElements.TextColored(HUDElements.colors.engine, "Frame Count"); ImguiNextColumnOrNewRow(); right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, "%" PRIu64, HUDElements.sw_stats->n_frames); ImGui::PopFont(); } } void HudElements::fan(){ if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_fan] && fan_speed != -1) { ImguiNextColumnFirstItem(); HUDElements.TextColored(HUDElements.colors.engine, "%s", "FAN"); ImguiNextColumnOrNewRow(); right_aligned_text(HUDElements.colors.text,HUDElements.ralign_width, "%i", fan_speed); ImGui::SameLine(0, 1.0f); ImGui::PushFont(HUDElements.sw_stats->font_small); HUDElements.TextColored(HUDElements.colors.text, "RPM"); ImGui::PopFont(); } } void HudElements::throttling_status(){ if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_throttling_status] && gpus){ auto gpu = gpus->active_gpu(); if (!gpu) return; if ((gpu->metrics.is_power_throttled || gpu->metrics.is_current_throttled || gpu->metrics.is_temp_throttled || gpu->metrics.is_other_throttled)){ ImguiNextColumnFirstItem(); HUDElements.TextColored(HUDElements.colors.engine, "%s", "Throttling"); ImguiNextColumnOrNewRow(); ImguiNextColumnOrNewRow(); if (gpu->metrics.is_power_throttled) right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, "Power"); if (gpu->metrics.is_current_throttled) right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, "Current"); if (gpu->metrics.is_temp_throttled) right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, "Temp"); if (gpu->metrics.is_other_throttled) right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, "Other"); } } } void HudElements::duration(){ ImGui::PushFont(HUDElements.sw_stats->font_secondary); ImguiNextColumnFirstItem(); HUDElements.TextColored(HUDElements.colors.engine, "%s", "Duration"); ImguiNextColumnOrNewRow(); std::chrono::steady_clock::time_point currentTime = std::chrono::steady_clock::now(); std::chrono::duration elapsedTime = currentTime - HUDElements.overlay_start; int hours = std::chrono::duration_cast(elapsedTime).count(); int minutes = std::chrono::duration_cast(elapsedTime).count() % 60; int seconds = std::chrono::duration_cast(elapsedTime).count() % 60; if (hours > 0) right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, "%02d:%02d:%02d", hours, minutes, seconds); else if (minutes > 0) right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, "%02d:%02d", minutes, seconds); else right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, "%02d", seconds); ImGui::PopFont(); } void HudElements::graphs(){ ImguiNextColumnFirstItem(); ImGui::Dummy(ImVec2(0.0f, real_font_size.y)); const std::string& value = HUDElements.ordered_functions[HUDElements.place].value; assert(kMaxGraphEntries >= graph_data.size()); std::vector arr(kMaxGraphEntries - graph_data.size()); ImGui::PushFont(HUDElements.sw_stats->font_small); if (value == "cpu_load"){ for (auto& it : graph_data){ arr.push_back(float(it.cpu_load)); } HUDElements.max = 100; HUDElements.min = 0; HUDElements.TextColored(HUDElements.colors.engine, "%s", "CPU Load"); } if (value == "gpu_load"){ for (auto& it : graph_data){ arr.push_back(float(it.gpu_load)); } HUDElements.max = 100; HUDElements.min = 0; HUDElements.TextColored(HUDElements.colors.engine, "%s", "GPU Load"); } if (value == "cpu_temp"){ for (auto& it : graph_data){ arr.push_back(float(it.cpu_temp)); } if (int(arr.back()) > HUDElements.cpu_temp_max) HUDElements.cpu_temp_max = arr.back(); HUDElements.max = HUDElements.cpu_temp_max; HUDElements.min = 0; HUDElements.TextColored(HUDElements.colors.engine, "%s", "CPU Temp"); } if (value == "gpu_temp"){ for (auto& it : graph_data){ arr.push_back(float(it.gpu_temp)); } if (int(arr.back()) > HUDElements.gpu_temp_max) HUDElements.gpu_temp_max = arr.back(); HUDElements.max = HUDElements.gpu_temp_max; HUDElements.min = 0; HUDElements.TextColored(HUDElements.colors.engine, "%s", "GPU Temp"); } if (value == "gpu_core_clock"){ for (auto& it : graph_data){ arr.push_back(float(it.gpu_core_clock)); } if (int(arr.back()) > HUDElements.gpu_core_max) HUDElements.gpu_core_max = arr.back(); HUDElements.max = HUDElements.gpu_core_max; HUDElements.min = 0; HUDElements.TextColored(HUDElements.colors.engine, "%s", "GPU Core Clock"); } if (value == "gpu_mem_clock"){ for (auto& it : graph_data){ arr.push_back(float(it.gpu_mem_clock)); } if (int(arr.back()) > HUDElements.gpu_mem_max) HUDElements.gpu_mem_max = arr.back(); HUDElements.max = HUDElements.gpu_mem_max; HUDElements.min = 0; HUDElements.TextColored(HUDElements.colors.engine, "%s", "GPU Mem Clock"); } if (value == "vram" && gpus){ for (auto& it : graph_data){ arr.push_back(float(it.gpu_vram_used)); } auto gpu = gpus->active_gpu(); if (!gpu) return; HUDElements.max = gpu->metrics.memoryTotal; HUDElements.min = 0; HUDElements.TextColored(HUDElements.colors.engine, "%s", "VRAM"); } #ifdef __linux__ if (value == "ram"){ for (auto& it : graph_data){ arr.push_back(float(it.ram_used)); } HUDElements.max = memmax; HUDElements.min = 0; HUDElements.TextColored(HUDElements.colors.engine, "%s", "RAM"); } #endif ImGui::PopFont(); ImGui::Dummy(ImVec2(0.0f,5.0f)); ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(0.0f, 0.0f, 0.0f, 0.0f)); if (!HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_histogram]){ ImGui::PlotLines("", arr.data(), arr.size(), 0, NULL, HUDElements.min, HUDElements.max, ImVec2((ImGui::GetWindowContentRegionMax().x - ImGui::GetWindowContentRegionMin().x), 50)); } else { ImGui::PlotHistogram("", arr.data(), arr.size(), 0, NULL, HUDElements.min, HUDElements.max, ImVec2((ImGui::GetWindowContentRegionMax().x - ImGui::GetWindowContentRegionMin().x), 50)); } ImGui::Dummy(ImVec2(0.0f,5.0f)); ImGui::PopStyleColor(1); } void HudElements::exec_name(){ if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_exec_name]){ ImGui::PushFont(HUDElements.sw_stats->font_secondary); ImguiNextColumnFirstItem(); HUDElements.TextColored(HUDElements.colors.engine, "%s", "Exe name"); ImguiNextColumnOrNewRow(); ImVec2 text_size = ImGui::CalcTextSize(global_proc_name.c_str()); right_aligned_text(HUDElements.colors.text, text_size.x, global_proc_name.c_str()); ImGui::PopFont(); } } void HudElements::fps_metrics(){ if (!fpsmetrics) return; for (auto& metric : fpsmetrics->copy_metrics()){ if (!HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_horizontal]) ImGui::TableNextRow(); ImguiNextColumnFirstItem(); HUDElements.TextColored(HUDElements.colors.engine, "%s", metric.display_name.c_str()); ImguiNextColumnOrNewRow(); right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, "%.0f", metric.value); ImGui::SameLine(0, 1.0f); ImGui::PushFont(HUDElements.sw_stats->font_small); HUDElements.TextColored(HUDElements.colors.text, "FPS"); ImGui::PopFont(); ImguiNextColumnOrNewRow(); } } void HudElements::hdr() { if (HUDElements.hdr_status > 0) { ImguiNextColumnFirstItem(); HUDElements.TextColored(HUDElements.colors.engine, "%s", "HDR"); ImguiNextColumnOrNewRow(); right_aligned_text(HUDElements.colors.fps_value_high, HUDElements.ralign_width, "ON"); } } void HudElements::refresh_rate() { if (HUDElements.refresh > 0) { ImGui::PushFont(HUDElements.sw_stats->font_secondary); ImguiNextColumnFirstItem(); HUDElements.TextColored(HUDElements.colors.engine, "%s", "Display Hz"); ImguiNextColumnOrNewRow(); right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, "%i", HUDElements.refresh); ImGui::PopFont(); } } void HudElements::winesync() { static std::unique_ptr winesync_ptr = nullptr; if (!winesync_ptr) winesync_ptr = std::make_unique(); if (winesync_ptr->valid()) { winesync_ptr->set_pid(HUDElements.g_gamescopePid); ImGui::PushFont(HUDElements.sw_stats->font_secondary); ImguiNextColumnFirstItem(); HUDElements.TextColored(HUDElements.colors.engine, "%s", "WSYNC"); ImguiNextColumnOrNewRow(); right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, "%s", winesync_ptr->get_method()); ImGui::PopFont(); } } void HudElements::present_mode() { ImguiNextColumnFirstItem(); ImGui::PushFont(HUDElements.sw_stats->font_secondary); const char* title; if (HUDElements.is_vulkan) title = "Present Mode"; else title = "VSYNC"; HUDElements.TextColored(HUDElements.colors.engine, "%s", title); ImguiNextColumnOrNewRow(); // Jump a column if title is overflowing if (ImGuiTextOverflow(title)) ImguiNextColumnOrNewRow(); right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width * 2.0f, "%s\n", HUDElements.get_present_mode().c_str()); ImGui::PopFont(); } void HudElements::network() { #ifdef __linux__ if (HUDElements.net && HUDElements.net->should_reset) HUDElements.net.reset(new Net); if (!HUDElements.net) HUDElements.net = std::make_unique(); for (auto& iface : HUDElements.net->interfaces){ ImguiNextColumnFirstItem(); HUDElements.TextColored(HUDElements.colors.network, "%.8s", iface.name.c_str()); ImguiNextColumnOrNewRow(); right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, "%.0f", iface.txBps / 1000.f); ImGui::SameLine(0,1.0f); ImGui::PushFont(HUDElements.sw_stats->font_small); HUDElements.TextColored(HUDElements.colors.text, "KB/s %s", ICON_FK_ARROW_UP); ImGui::PopFont(); ImguiNextColumnOrNewRow(); right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, "%.0f", iface.rxBps / 1000.f); ImGui::SameLine(0,1.0f); ImGui::PushFont(HUDElements.sw_stats->font_small); HUDElements.TextColored(HUDElements.colors.text, "KB/s %s", ICON_FK_ARROW_DOWN); ImGui::PopFont(); } #endif } void HudElements::_display_session() { if (not HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_display_server]) return; ImGui::PushFont(HUDElements.sw_stats->font_secondary); ImguiNextColumnFirstItem(); const char* title = "Display Server"; HUDElements.TextColored(HUDElements.colors.engine, "%s", title); ImguiNextColumnOrNewRow(); // Jump a column if title is overflowing if (ImGuiTextOverflow(title)) ImguiNextColumnOrNewRow(); static std::map servers { {WAYLAND, {"WAYLAND"}}, {XWAYLAND, {"XWAYLAND"}}, {XORG, {"XORG"}} }; right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width * 1.5f, "%s", servers[HUDElements.display_server].c_str()); ImGui::PopFont(); } void HudElements::fex_stats() { #ifdef HAVE_FEX if (!HUDElements.params->fex_stats.enabled) { return; } ImGui::PushFont(HUDElements.sw_stats->font_small); if (HUDElements.params->fex_stats.status) { ImguiNextColumnFirstItem(); HUDElements.TextColored(HUDElements.colors.engine, "%s", "FEX"); ImguiNextColumnOrNewRow(); ImGui::Dummy(ImVec2(0.0f, real_font_size.y)); ImguiNextColumnOrNewRow(); right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, "%s", fex::fex_status); } if (!fex::is_fex_pid_found()) { ImGui::PopFont(); return; } if (HUDElements.params->fex_stats.app_type) { ImguiNextColumnFirstItem(); HUDElements.TextColored(HUDElements.colors.engine, "%s", "Type"); ImguiNextColumnOrNewRow(); ImGui::Dummy(ImVec2(0.0f, real_font_size.y)); ImguiNextColumnOrNewRow(); right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, "%s", fex::get_fex_app_type()); } if (HUDElements.params->fex_stats.sigbus_counts) { ImguiNextColumnFirstItem(); HUDElements.TextColored(HUDElements.colors.engine, "%s", "SIGBUS"); ImguiNextColumnOrNewRow(); ImGui::Dummy(ImVec2(0.0f, real_font_size.y)); ImguiNextColumnOrNewRow(); right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, "%" PRIu64 " - %.0f avg/s", fex::sigbus_counts.Count(), fex::sigbus_counts.Avg()); } if (HUDElements.params->fex_stats.smc_counts) { ImguiNextColumnFirstItem(); HUDElements.TextColored(HUDElements.colors.engine, "%s", "SMC"); ImguiNextColumnOrNewRow(); ImGui::Dummy(ImVec2(0.0f, real_font_size.y)); ImguiNextColumnOrNewRow(); right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, "%" PRIu64 " - %.0f avg/s", fex::smc_counts.Count(), fex::smc_counts.Avg()); } if (HUDElements.params->fex_stats.softfloat_counts) { ImguiNextColumnFirstItem(); HUDElements.TextColored(HUDElements.colors.engine, "%s", "Softfloat"); ImguiNextColumnOrNewRow(); ImGui::Dummy(ImVec2(0.0f, real_font_size.y)); ImguiNextColumnOrNewRow(); right_aligned_text(HUDElements.colors.text, HUDElements.ralign_width, "%" PRIu64 " - %.0f avg/s", fex::softfloat_counts.Count(), fex::softfloat_counts.Avg()); } ImGui::PopFont(); ImguiNextColumnFirstItem(); ImGui::Dummy(ImVec2(0.0f, real_font_size.y)); if (HUDElements.params->fex_stats.hot_threads) { // Draw hot threads bool Warning = false; ImVec4 WarningColor; for (auto it : fex::fex_max_thread_loads){ if (it >= 75.0) { Warning = true; WarningColor = ImVec4(1.0f, 0.0f, 0.0f, 1.0f); } else if (it >= 50.0) { Warning = true; WarningColor = ImVec4(1.0f, 1.0f, 0.0f, 1.0f); } } ImGui::PushFont(HUDElements.sw_stats->font_small); HUDElements.TextColored(HUDElements.colors.engine, "%s", "FEX JIT top loaded threads"); ImGui::PopFont(); ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(0.0f, 0.0f, 0.0f, 0.0f)); if (Warning) { ImGui::PushStyleColor(ImGuiCol_PlotHistogram, WarningColor); } ImGui::PlotHistogram("", fex::fex_max_thread_loads.data(), fex::fex_max_thread_loads.size(), 0, NULL, 0, 100, ImVec2((ImGui::GetWindowContentRegionMax().x - ImGui::GetWindowContentRegionMin().x), 50)); ImGui::PopStyleColor(1 + (Warning ? 1 : 0)); } if (HUDElements.params->fex_stats.jit_load) { ImGui::PushFont(HUDElements.sw_stats->font_small); HUDElements.TextColored(HUDElements.colors.engine, "%s", "FEX JIT Load"); ImGui::PopFont(); ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(0.0f, 0.0f, 0.0f, 0.0f)); ImGui::PlotLines("", fex::fex_load_data.data(), fex::fex_load_data.size(), 0, NULL, 0, 100, ImVec2((ImGui::GetWindowContentRegionMax().x - ImGui::GetWindowContentRegionMin().x), 50)); ImGui::PopStyleColor(1); } #endif //HAVE_FEX } void HudElements::ftrace() { #ifdef HAVE_FTRACE if (!HUDElements.params->ftrace.enabled || !FTrace::object) return; float width = (ImGui::GetWindowContentRegionMax().x - ImGui::GetWindowContentRegionMin().x); float height = 100; for (auto& tp : FTrace::object->tracepoints()) { switch (tp->type) { case FTrace::TracepointType::Histogram: case FTrace::TracepointType::LineGraph: { char hash[40]; snprintf(hash, sizeof(hash), "##%s", tp->name.c_str()); ImGui::TableNextRow(); ImguiNextColumnFirstItem(); ImGui::PushFont(HUDElements.sw_stats->font_small); ImGui::Dummy(ImVec2(0.0f, real_font_size.y)); HUDElements.TextColored(HUDElements.colors.text, "ftrace %s: %s", tp->type == FTrace::TracepointType::Histogram ? "histogram" : "line graph", tp->name.c_str()); ImGui::Dummy(ImVec2(0.0f, real_font_size.y / 2)); if (tp->type == FTrace::TracepointType::LineGraph) { HUDElements.TextColored(HUDElements.colors.text, " parameter: %s", tp->field_name.c_str()); ImGui::Dummy(ImVec2(0.0f, real_font_size.y / 2)); } ImGui::PopFont(); if (ImGui::BeginChild(tp->name.c_str(), ImVec2(width, height), false, ImGuiWindowFlags_NoDecoration)) { if (tp->type == FTrace::TracepointType::Histogram) { ImGui::PlotHistogram(hash, FTrace::FTrace::get_plot_values, tp.get(), FTrace::Tracepoint::PLOT_DATA_CAPACITY, 0, NULL, tp->data.plot.range.min, tp->data.plot.range.max, ImVec2(width, height)); } else { ImGui::PlotLines(hash, FTrace::FTrace::get_plot_values, tp.get(), FTrace::Tracepoint::PLOT_DATA_CAPACITY, 0, NULL, tp->data.plot.range.min, tp->data.plot.range.max, ImVec2(width, height)); } } ImGui::EndChild(); break; } case FTrace::TracepointType::Label: { ImGui::TableNextRow(); ImguiNextColumnFirstItem(); ImGui::PushFont(HUDElements.sw_stats->font_small); ImGui::Dummy(ImVec2(0.0f, real_font_size.y)); HUDElements.TextColored(HUDElements.colors.text, "ftrace label: %s:", tp->name.c_str()); ImGui::Dummy(ImVec2(0.0f, real_font_size.y / 2)); HUDElements.TextColored(HUDElements.colors.text, " %s=%s", tp->field_name.c_str(), tp->data.field_value.c_str()); ImGui::Dummy(ImVec2(0.0f, real_font_size.y / 2)); ImGui::PopFont(); break; } default: UNREACHABLE("invalid tracepoint type"); } } #endif // HAVE_FTRACE } void HudElements::sort_elements(const std::pair& option) { const auto& param = option.first; const auto& value = option.second; // Initialize a map of display parameters and their corresponding functions. const std::map display_params = { {"version", {version}}, {"time", {time}}, {"gpu_stats", {gpu_stats}}, {"cpu_stats", {cpu_stats}}, {"core_load", {core_load}}, {"io_read", {io_stats}}, {"io_write", {io_stats}}, {"arch", {arch}}, {"wine", {wine}}, {"procmem", {procmem}}, {"gamemode", {gamemode}}, {"vkbasalt", {vkbasalt}}, {"engine_version", {engine_version}}, {"vulkan_driver", {vulkan_driver}}, {"resolution", {resolution}}, {"show_fps_limit", {show_fps_limit}}, {"vram", {vram}}, {"proc_vram", {proc_vram}}, {"ram", {ram}}, {"fps", {fps}}, {"gpu_name", {gpu_name}}, {"frame_timing", {frame_timing}}, {"media_player", {media_player}}, {"custom_text", {custom_text}}, {"custom_text_center", {custom_text_center}}, {"exec", {_exec}}, {"battery", {battery}}, {"fps_only", {fps_only}}, {"fsr", {gamescope_fsr}}, {"debug", {gamescope_frame_timing}}, {"device_battery", {device_battery}}, {"frame_count", {frame_count}}, {"fan", {fan}}, {"throttling_status", {throttling_status}}, {"exec_name", {exec_name}}, {"duration", {duration}}, {"graphs", {graphs}}, {"fps_metrics", {fps_metrics}}, {"hdr", {hdr}}, {"refresh_rate", {refresh_rate}}, {"winesync", {winesync}}, {"present_mode", {present_mode}}, {"network", {network}}, {"display_server", {_display_session}}, {"fex_stats", {fex_stats}}, {"ftrace", {ftrace}}, }; auto check_param = display_params.find(param); if (check_param != display_params.end()) { const Function& func = check_param->second; if (param == "debug") { ordered_functions.push_back({gamescope_frame_timing, "gamescope_frame_timing", value}); } else if (param == "fsr") { ordered_functions.push_back({gamescope_fsr, "gamescope_fsr", value}); } else if (param == "io_read" || param == "io_write") { // Don't add twice if (std::none_of(ordered_functions.begin(), ordered_functions.end(), [](const auto& a) { return a.name == "io_stats"; })) { ordered_functions.push_back({io_stats, "io_stats", value}); } } else if (param == "exec") { ordered_functions.push_back({_exec, "exec", value}); exec_list.push_back({int(ordered_functions.size() - 1), value}); } else if (param == "graphs") { auto values = str_tokenize(value); for (auto& val : values) { if (find(permitted_params.begin(), permitted_params.end(), val) != permitted_params.end()) { ordered_functions.push_back({graphs, "graph: " + val, val}); } else { SPDLOG_ERROR("Unrecognized graph type: {}", val); } } } else { // Use this to always add to the front of the vector // ordered_functions.insert(ordered_functions.begin(), std::make_pair(param, value)); ordered_functions.push_back({func.run, param, value}); } } return; } void HudElements::legacy_elements(const overlay_params* temp_params){ string value = "NULL"; ordered_functions.clear(); if (temp_params->enabled[OVERLAY_PARAM_ENABLED_time]) ordered_functions.push_back({time, "time", value}); if (temp_params->enabled[OVERLAY_PARAM_ENABLED_version]) ordered_functions.push_back({version, "version", value}); if (temp_params->enabled[OVERLAY_PARAM_ENABLED_gpu_stats]) ordered_functions.push_back({gpu_stats, "gpu_stats", value}); if (temp_params->enabled[OVERLAY_PARAM_ENABLED_cpu_stats]) ordered_functions.push_back({cpu_stats, "cpu_stats", value}); if (temp_params->enabled[OVERLAY_PARAM_ENABLED_core_load]) ordered_functions.push_back({core_load, "core_load", value}); if (temp_params->enabled[OVERLAY_PARAM_ENABLED_io_read] || temp_params->enabled[OVERLAY_PARAM_ENABLED_io_write]) ordered_functions.push_back({io_stats, "io_stats", value}); if (temp_params->enabled[OVERLAY_PARAM_ENABLED_vram]) ordered_functions.push_back({vram, "vram", value}); if (temp_params->enabled[OVERLAY_PARAM_ENABLED_proc_vram]) ordered_functions.push_back({proc_vram, "proc_vram", value}); if (temp_params->enabled[OVERLAY_PARAM_ENABLED_ram]) ordered_functions.push_back({ram, "ram", value}); if (temp_params->enabled[OVERLAY_PARAM_ENABLED_procmem]) ordered_functions.push_back({procmem, "procmem", value}); if (!temp_params->network.empty()) ordered_functions.push_back({network, "network", value}); if (temp_params->enabled[OVERLAY_PARAM_ENABLED_battery]) ordered_functions.push_back({battery, "battery", value}); if (temp_params->enabled[OVERLAY_PARAM_ENABLED_fan]) ordered_functions.push_back({fan, "fan", value}); if (temp_params->enabled[OVERLAY_PARAM_ENABLED_fsr]) ordered_functions.push_back({gamescope_fsr, "gamescope_fsr", value}); if (temp_params->enabled[OVERLAY_PARAM_ENABLED_hdr]) ordered_functions.push_back({hdr, "hdr", value}); if (temp_params->enabled[OVERLAY_PARAM_ENABLED_throttling_status]) ordered_functions.push_back({throttling_status, "throttling_status", value}); if (temp_params->enabled[OVERLAY_PARAM_ENABLED_fps]) ordered_functions.push_back({fps, "fps", value}); for (const auto& pair : options) { if (pair.first.find("graphs") != std::string::npos) { std::stringstream ss(pair.second); std::string token; while (std::getline(ss, token, ',')){ ordered_functions.push_back({graphs, "graphs", token}); } } } if (!temp_params->fps_metrics.empty()) ordered_functions.push_back({fps_metrics, "fps_metrics", value}); if (temp_params->enabled[OVERLAY_PARAM_ENABLED_fps_only]) ordered_functions.push_back({fps_only, "fps_only", value}); if (temp_params->enabled[OVERLAY_PARAM_ENABLED_engine_version]) ordered_functions.push_back({engine_version, "engine_version", value}); if (temp_params->enabled[OVERLAY_PARAM_ENABLED_gpu_name]) ordered_functions.push_back({gpu_name, "gpu_name", value}); if (temp_params->enabled[OVERLAY_PARAM_ENABLED_vulkan_driver]) ordered_functions.push_back({vulkan_driver, "vulkan_driver", value}); if (temp_params->enabled[OVERLAY_PARAM_ENABLED_arch]) ordered_functions.push_back({arch, "arch", value}); if (temp_params->enabled[OVERLAY_PARAM_ENABLED_wine]) ordered_functions.push_back({wine, "wine", value}); if (temp_params->enabled[OVERLAY_PARAM_ENABLED_frame_timing]) ordered_functions.push_back({frame_timing, "frame_timing", value}); if (temp_params->enabled[OVERLAY_PARAM_ENABLED_frame_count]) ordered_functions.push_back({frame_count, "frame_count", value}); if (temp_params->enabled[OVERLAY_PARAM_ENABLED_debug] && !temp_params->enabled[OVERLAY_PARAM_ENABLED_horizontal]) ordered_functions.push_back({gamescope_frame_timing, "gamescope_frame_timing", value}); if (temp_params->enabled[OVERLAY_PARAM_ENABLED_gamemode]) ordered_functions.push_back({gamemode, "gamemode", value}); if (temp_params->enabled[OVERLAY_PARAM_ENABLED_vkbasalt]) ordered_functions.push_back({vkbasalt, "vkbasalt", value}); if (temp_params->enabled[OVERLAY_PARAM_ENABLED_show_fps_limit]) ordered_functions.push_back({show_fps_limit, "show_fps_limit", value}); if (temp_params->enabled[OVERLAY_PARAM_ENABLED_resolution]) ordered_functions.push_back({resolution, "resolution", value}); if (!temp_params->device_battery.empty() ) ordered_functions.push_back({device_battery, "device_battery", value}); if (temp_params->enabled[OVERLAY_PARAM_ENABLED_media_player]) ordered_functions.push_back({media_player, "media_player", value}); if (temp_params->enabled[OVERLAY_PARAM_ENABLED_exec_name]) ordered_functions.push_back({exec_name, "exec_name", value}); if (temp_params->enabled[OVERLAY_PARAM_ENABLED_duration]) ordered_functions.push_back({duration, "duration", value}); if (temp_params->enabled[OVERLAY_PARAM_ENABLED_winesync]) ordered_functions.push_back({winesync, "winesync", value}); if (temp_params->enabled[OVERLAY_PARAM_ENABLED_present_mode]) ordered_functions.push_back({present_mode, "present_mode", value}); if (temp_params->enabled[OVERLAY_PARAM_ENABLED_refresh_rate]) ordered_functions.push_back({refresh_rate, "refresh_rate", value}); if (temp_params->enabled[OVERLAY_PARAM_ENABLED_display_server]) ordered_functions.push_back({_display_session, "display_session", value}); if (temp_params->fex_stats.enabled) ordered_functions.push_back({fex_stats, "fex_stats", value}); #ifdef HAVE_FTRACE if (temp_params->ftrace.enabled) ordered_functions.push_back({ftrace, "ftrace", value}); #endif } void HudElements::update_exec(){ #ifdef __linux__ // TODO: exec needs a rewrite using as using fork() is not safe in multithread. // We should probably use posix_spawn instead. // This currently stalls games using feral launcher. // For now don't init shell unless we have some exec options. if (exec_list.empty()) return; if (!HUDElements.shell) HUDElements.shell = std::make_unique(); for(auto& item : exec_list){ std::string ret = HUDElements.shell->exec(item.value + "\n"); // use the previous ret if we get bad system call if (ret.find("Bad system call") == std::string::npos) item.ret = ret; } #endif } std::string_view HudElements::get_vulkan_present_mode_short_name(VkPresentModeKHR mode) { static constexpr std::string_view prefix = "VK_PRESENT_MODE_"; static constexpr std::string_view suffix = "_KHR"; auto name = std::string_view{string_VkPresentModeKHR(mode)}; name = strip_prefix(name, prefix); name = strip_suffix(name, suffix); return name; } HudElements HUDElements; ================================================ FILE: src/hud_elements.h ================================================ #pragma once #include #include #include #include #include #include "timing.hpp" #include #include #include #include #include "net.h" #include "overlay_params.h" #include "shell.h" #include "gpu.h" struct Function { std::function run; // Using std::function instead of a raw function pointer for more flexibility std::string name; std::string value; }; class HudElements{ public: struct swapchain_stats *sw_stats; std::shared_ptr params; struct exec_entry { int pos; std::string value; std::string ret; }; float ralign_width; float old_scale; float res_width, res_height; bool is_vulkan = true, gamemode_bol = false, vkbasalt_bol = false; int place; int text_column = 1; int table_columns_count = 0; pid_t g_gamescopePid = -1; int g_fsrUpscale = -1; int g_fsrSharpness = -1; Clock::time_point last_exec; std::vector> options; std::vector ordered_functions; std::vector gamescope_debug_latency {}; std::vector gamescope_debug_app {}; int min, max, gpu_core_max, gpu_mem_max, cpu_temp_max, gpu_temp_max; const std::vector permitted_params = { "gpu_load", "cpu_load", "gpu_core_clock", "gpu_mem_clock", "vram", "ram", "cpu_temp", "gpu_temp" }; std::vector exec_list; std::chrono::steady_clock::time_point overlay_start = std::chrono::steady_clock::now(); uint32_t vendorID; int hdr_status = 0; int refresh = 0; unsigned int vsync = 10; enum display_servers { UNKNOWN, WAYLAND, XWAYLAND, XORG }; display_servers display_server = UNKNOWN; std::unique_ptr net = nullptr; #ifdef __linux__ std::unique_ptr shell = nullptr; #endif void sort_elements(const std::pair& option); void legacy_elements(const overlay_params* temp_params); void update_exec(); int convert_to_fahrenheit(int celsius); static void version(); static void time(); static void gpu_stats(); static void cpu_stats(); static void core_load(); static void io_stats(); static void vram(); static void proc_vram(); static void ram(); static void procmem(); static void fps(); static void engine_version(); static void gpu_name(); static void vulkan_driver(); static void arch(); static void wine(); static void frame_timing(); static void media_player(); static void resolution(); static void show_fps_limit(); static void custom_text_center(); static void custom_text(); static void vkbasalt(); static void gamemode(); static void graphs(); static void _exec(); static void battery(); static void fps_only(); static void gamescope_fsr(); static void gamescope_frame_timing(); static void device_battery(); static void frame_count(); static void fan(); static void throttling_status(); static void exec_name(); static void duration(); static void fps_metrics(); static void hdr(); static void refresh_rate(); static void winesync(); static void present_mode(); static void network(); static void _display_session(); static void fex_stats(); static void ftrace(); void convert_colors(const struct overlay_params& params); void convert_colors(bool do_conv, const struct overlay_params& params); struct hud_colors { bool convert, update; ImVec4 cpu, gpu, vram, ram, swap, engine, io, frametime, background, text, media_player, wine, horizontal_separator, battery, gpu_load_low, gpu_load_med, gpu_load_high, cpu_load_low, cpu_load_med, cpu_load_high, fps_value_low, fps_value_med, fps_value_high, text_outline, network; } colors {}; void TextColored(ImVec4 col, const char *fmt, ...); std::array presentModes = { VK_PRESENT_MODE_FIFO_RELAXED_KHR, VK_PRESENT_MODE_IMMEDIATE_KHR, VK_PRESENT_MODE_MAILBOX_KHR, VK_PRESENT_MODE_FIFO_KHR, VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR, VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR}; VkPresentModeKHR cur_present_mode; std::string get_present_mode() { if (is_vulkan) return std::string(HudElements::get_vulkan_present_mode_short_name(cur_present_mode)); else return vsync == 0 ? "OFF" : "ON"; } static std::string_view get_vulkan_present_mode_short_name(VkPresentModeKHR mode); }; extern HudElements HUDElements; ================================================ FILE: src/imgui_utils.h ================================================ #pragma once #include #ifdef __linux__ #include #endif struct imgui_contexts { ImGuiContext* imgui = nullptr; #ifdef IMPLOT_API ImPlotContext* implot = nullptr; #endif }; static imgui_contexts create_imgui_contexts(ImFontAtlas* shared_font_atlas = NULL) { imgui_contexts contexts; contexts.imgui = ImGui::CreateContext(shared_font_atlas); #ifdef IMPLOT_API contexts.implot = ImPlot::CreateContext(); #endif return contexts; } static void destroy_imgui_contexts(imgui_contexts& contexts) { ImGui::DestroyContext(contexts.imgui); contexts.imgui = nullptr; #ifdef IMPLOT_API ImPlot::DestroyContext(contexts.implot); contexts.implot = nullptr; #endif } static imgui_contexts get_current_imgui_contexts() { imgui_contexts saved_contexts; saved_contexts.imgui = ImGui::GetCurrentContext(); #ifdef IMPLOT_API saved_contexts.implot = ImPlot::GetCurrentContext(); #endif return saved_contexts; } static void make_imgui_contexts_current(imgui_contexts contexts) { ImGui::SetCurrentContext(contexts.imgui); #ifdef IMPLOT_API ImPlot::SetCurrentContext(contexts.implot); #endif } ================================================ FILE: src/iostats.cpp ================================================ #include "iostats.h" #include "string_utils.h" #include #include "hud_elements.h" struct iostats g_io_stats; void getIoStats(iostats& io) { Clock::time_point now = Clock::now(); /* ns */ std::chrono::duration time_diff = now - io.last_update; io.prev.read_bytes = io.curr.read_bytes; io.prev.write_bytes = io.curr.write_bytes; std::string f = "/proc/"; { auto gs_pid = HUDElements.g_gamescopePid; f += gs_pid < 1 ? "self" : std::to_string(gs_pid); f += "/io"; } std::ifstream file(f); if (!file.is_open()) { SPDLOG_ERROR("can't open {}", f); return; } for (std::string line; std::getline(file, line);) { if (starts_with(line, "read_bytes:")) { try_stoull(io.curr.read_bytes, line.substr(12)); } else if (starts_with(line, "write_bytes:")) { try_stoull(io.curr.write_bytes, line.substr(13)); } } if (io.last_update.time_since_epoch().count()) { io.diff.read = (io.curr.read_bytes - io.prev.read_bytes) / (1024.f * 1024.f); io.diff.write = (io.curr.write_bytes - io.prev.write_bytes) / (1024.f * 1024.f); io.per_second.read = io.diff.read / time_diff.count(); io.per_second.write = io.diff.write / time_diff.count(); } io.last_update = now; } ================================================ FILE: src/iostats.h ================================================ #pragma once #ifndef MANGOHUD_IOSTATS_H #define MANGOHUD_IOSTATS_H #include #include "timing.hpp" struct iostats { struct { unsigned long long read_bytes; unsigned long long write_bytes; } curr; struct { unsigned long long read_bytes; unsigned long long write_bytes; } prev; struct { float read; float write; } diff; struct { float read; float write; } per_second; Clock::time_point last_update; }; extern iostats g_io_stats; void getIoStats(iostats& io); #endif //MANGOHUD_IOSTATS_H ================================================ FILE: src/keybinds.cpp ================================================ #include #include #include #include #include #include "hud_elements.h" #include "overlay.h" #include "timing.hpp" #include "logging.h" #include "keybinds.h" #include "fps_metrics.h" #include "fps_limiter.h" Clock::time_point last_f2_press, toggle_fps_limit_press, toggle_preset_press, last_f12_press, reload_cfg_press, last_upload_press; void check_keybinds(struct overlay_params& params){ auto real_params = get_params(); using namespace std::chrono_literals; auto now = Clock::now(); /* us */ auto elapsedF2 = now - last_f2_press; auto elapsedFpsLimitToggle = now - toggle_fps_limit_press; auto elapsedPresetToggle = now - toggle_preset_press; auto elapsedF12 = now - last_f12_press; auto elapsedReloadCfg = now - reload_cfg_press; auto elapsedUpload = now - last_upload_press; static Clock::time_point last_check; if (now - last_check < 100ms) return; last_check = now; const auto keyPressDelay = 400ms; if (elapsedF2 >= keyPressDelay && keys_are_pressed(real_params->toggle_logging)) { last_f2_press = now; if (logger->is_active()) { logger->stop_logging(); } else { logger->start_logging(); benchmark.fps_data.clear(); } } if (elapsedFpsLimitToggle >= keyPressDelay && keys_are_pressed(real_params->toggle_fps_limit)) { toggle_fps_limit_press = now; fps_limiter->next_limit(); } if (elapsedPresetToggle >= keyPressDelay && keys_are_pressed(real_params->toggle_preset)) { toggle_preset_press = now; size_t size = real_params->preset.size(); for (size_t i = 0; i < size; i++){ if(real_params->preset[i] == current_preset) { current_preset = real_params->preset[++i%size]; parse_overlay_config(¶ms, getenv("MANGOHUD_CONFIG"), true); break; } } } if (elapsedF12 >= keyPressDelay && keys_are_pressed(real_params->toggle_hud)) { last_f12_press = now; real_params->no_display = !real_params->no_display; } if (elapsedReloadCfg >= keyPressDelay && keys_are_pressed(real_params->reload_cfg)) { parse_overlay_config(¶ms, getenv("MANGOHUD_CONFIG"), false); reload_cfg_press = now; } if (real_params->permit_upload && elapsedUpload >= keyPressDelay && keys_are_pressed(real_params->upload_log)) { last_upload_press = now; logger->upload_last_log(); } if (real_params->permit_upload && elapsedUpload >= keyPressDelay && keys_are_pressed(real_params->upload_logs)) { last_upload_press = now; logger->upload_last_logs(); } if (elapsedF12 >= keyPressDelay && keys_are_pressed(real_params->toggle_hud_position)) { next_hud_position(); last_f12_press = now; } if (elapsedF12 >= keyPressDelay && keys_are_pressed(real_params->reset_fps_metrics)) { last_f12_press = now; if (fpsmetrics) fpsmetrics->reset_metrics(); } } ================================================ FILE: src/keybinds.h ================================================ #pragma once #ifndef MANGOHUD_KEYBINDS_H #define MANGOHUD_KEYBINDS_H #ifdef HAVE_X11 #include "shared_x11.h" #include "loaders/loader_x11.h" #endif #ifdef HAVE_WAYLAND #include "wayland_hook.h" #endif #ifndef KeySym typedef unsigned long KeySym; #endif #if defined(HAVE_X11) || defined(HAVE_WAYLAND) static inline bool keys_are_pressed(const std::vector& keys) { if (keys.size() == 0) return false; #if defined(HAVE_WAYLAND) if (wl_handle) { update_wl_queue(); if (wayland_has_keys_pressed(keys)) return true; } #endif #if defined(HAVE_X11) if (init_x11()) { char keys_return[32]; size_t pressed = 0; auto libx11 = get_libx11(); libx11->XQueryKeymap(get_xdisplay(), keys_return); for (KeySym ks : keys) { KeyCode kc2 = libx11->XKeysymToKeycode(get_xdisplay(), ks); bool isPressed = !!(keys_return[kc2 >> 3] & (1 << (kc2 & 7))); if (isPressed) pressed++; } if (pressed == keys.size()) { return true; } } #endif return false; } #elif defined(_WIN32) #include static inline bool keys_are_pressed(const std::vector& keys) { size_t pressed = 0; for (KeySym ks : keys) { if (GetAsyncKeyState(ks) & 0x8000) pressed++; } if (pressed > 0 && pressed == keys.size()) { return true; } return false; } #endif #endif //MANGOHUD_KEYBINDS_H ================================================ FILE: src/loaders/loader_dbus.cpp ================================================ #include "loaders/loader_dbus.h" #include #include // Put these sanity checks here so that they fire at most once // (to avoid cluttering the build output). #if !defined(LIBRARY_LOADER_DBUS_H_DLOPEN) && !defined(LIBRARY_LOADER_DBUS_H_DT_NEEDED) #error neither LIBRARY_LOADER_DBUS_H_DLOPEN nor LIBRARY_LOADER_DBUS_H_DT_NEEDED defined #endif #if defined(LIBRARY_LOADER_DBUS_H_DLOPEN) && defined(LIBRARY_LOADER_DBUS_H_DT_NEEDED) #error both LIBRARY_LOADER_DBUS_H_DLOPEN and LIBRARY_LOADER_DBUS_H_DT_NEEDED defined #endif libdbus_loader::libdbus_loader() : loaded_(false) { } libdbus_loader::~libdbus_loader() { CleanUp(loaded_); } bool libdbus_loader::Load(const std::string& library_name) { if (loaded_) { return false; } #if defined(LIBRARY_LOADER_DBUS_H_DLOPEN) library_ = dlopen(library_name.c_str(), RTLD_LAZY); if (!library_) { SPDLOG_ERROR("Failed to open " MANGOHUD_ARCH " {}: {}", library_name, dlerror()); return false; } bus_add_match = reinterpret_castbus_add_match)>( dlsym(library_, "dbus_bus_add_match")); if (!bus_add_match) { CleanUp(true); return false; } bus_get = reinterpret_castbus_get)>( dlsym(library_, "dbus_bus_get")); if (!bus_get) { CleanUp(true); return false; } bus_get_unique_name = reinterpret_castbus_get_unique_name)>( dlsym(library_, "dbus_bus_get_unique_name")); if (!bus_get_unique_name) { CleanUp(true); return false; } bus_remove_match = reinterpret_castbus_remove_match)>( dlsym(library_, "dbus_bus_remove_match")); if (!bus_remove_match) { CleanUp(true); return false; } connection_add_filter = reinterpret_castconnection_add_filter)>( dlsym(library_, "dbus_connection_add_filter")); if (!connection_add_filter) { CleanUp(true); return false; } connection_pop_message = reinterpret_castconnection_pop_message)>( dlsym(library_, "dbus_connection_pop_message")); if (!connection_pop_message) { CleanUp(true); return false; } connection_read_write = reinterpret_castconnection_read_write)>( dlsym(library_, "dbus_connection_read_write")); if (!connection_read_write) { CleanUp(true); return false; } connection_read_write_dispatch = reinterpret_castconnection_read_write)>( dlsym(library_, "dbus_connection_read_write_dispatch")); if (!connection_read_write_dispatch) { CleanUp(true); return false; } connection_remove_filter = reinterpret_castconnection_remove_filter)>( dlsym(library_, "dbus_connection_remove_filter")); if (!connection_remove_filter) { CleanUp(true); return false; } connection_send_with_reply_and_block = reinterpret_castconnection_send_with_reply_and_block)>( dlsym(library_, "dbus_connection_send_with_reply_and_block")); if (!connection_send_with_reply_and_block) { CleanUp(true); return false; } connection_unref = reinterpret_castconnection_unref)>( dlsym(library_, "dbus_connection_unref")); if (!connection_unref) { CleanUp(true); return false; } error_free = reinterpret_casterror_free)>( dlsym(library_, "dbus_error_free")); if (!error_free) { CleanUp(true); return false; } error_init = reinterpret_casterror_init)>( dlsym(library_, "dbus_error_init")); if (!error_init) { CleanUp(true); return false; } error_is_set = reinterpret_casterror_is_set)>( dlsym(library_, "dbus_error_is_set")); if (!error_is_set) { CleanUp(true); return false; } message_append_args = reinterpret_castmessage_append_args)>( dlsym(library_, "dbus_message_append_args")); if (!message_append_args) { CleanUp(true); return false; } message_get_interface = reinterpret_castmessage_get_interface)>( dlsym(library_, "dbus_message_get_interface")); if (!message_get_interface) { CleanUp(true); return false; } message_get_member = reinterpret_castmessage_get_member)>( dlsym(library_, "dbus_message_get_member")); if (!message_get_member) { CleanUp(true); return false; } message_is_signal = reinterpret_castmessage_is_signal)>( dlsym(library_, "dbus_message_is_signal")); if (!message_is_signal) { CleanUp(true); return false; } message_iter_get_arg_type = reinterpret_castmessage_iter_get_arg_type)>( dlsym(library_, "dbus_message_iter_get_arg_type")); if (!message_iter_get_arg_type) { CleanUp(true); return false; } message_iter_get_basic = reinterpret_castmessage_iter_get_basic)>( dlsym(library_, "dbus_message_iter_get_basic")); if (!message_iter_get_basic) { CleanUp(true); return false; } message_iter_init = reinterpret_castmessage_iter_init)>( dlsym(library_, "dbus_message_iter_init")); if (!message_iter_init) { CleanUp(true); return false; } message_iter_next = reinterpret_castmessage_iter_next)>( dlsym(library_, "dbus_message_iter_next")); if (!message_iter_next) { CleanUp(true); return false; } message_iter_recurse = reinterpret_castmessage_iter_recurse)>( dlsym(library_, "dbus_message_iter_recurse")); if (!message_iter_recurse) { CleanUp(true); return false; } message_new_method_call = reinterpret_castmessage_new_method_call)>( dlsym(library_, "dbus_message_new_method_call")); if (!message_new_method_call) { CleanUp(true); return false; } message_unref = reinterpret_castmessage_unref)>( dlsym(library_, "dbus_message_unref")); if (!message_unref) { CleanUp(true); return false; } move_error = reinterpret_castmove_error)>( dlsym(library_, "dbus_move_error")); if (!move_error) { CleanUp(true); return false; } threads_init_default = reinterpret_castthreads_init_default)>( dlsym(library_, "dbus_threads_init_default")); if (!threads_init_default) { CleanUp(true); return false; } message_get_sender = reinterpret_castmessage_get_sender)>( dlsym(library_, "dbus_message_get_sender")); if (!message_get_sender) { CleanUp(true); return false; } #endif #if defined(LIBRARY_LOADER_DBUS_H_DT_NEEDED) bus_add_match = &::dbus_bus_add_match; bus_get = &::dbus_bus_get; bus_get_unique_name = &::dbus_bus_get_unique_name; bus_remove_match = &::dbus_bus_remove_match; connection_pop_message = &::dbus_connection_pop_message; connection_read_write = &::dbus_connection_read_write; connection_send_with_reply_and_block = &::dbus_connection_send_with_reply_and_block; connection_unref = &::dbus_connection_unref; error_free = &::dbus_error_free; error_init = &::dbus_error_init; error_is_set = &::dbus_error_is_set; message_append_args = &::dbus_message_append_args; message_is_signal = &::dbus_message_is_signal; message_iter_get_arg_type = &::dbus_message_iter_get_arg_type; message_iter_get_basic = &::dbus_message_iter_get_basic; message_iter_init = &::dbus_message_iter_init; message_iter_next = &::dbus_message_iter_next; message_iter_recurse = &::dbus_message_iter_recurse; message_new_method_call = &::dbus_message_new_method_call; message_unref = &::dbus_message_unref; move_error = &::dbus_move_error; threads_init_default = &::dbus_threads_init_default; #endif loaded_ = true; return true; } void libdbus_loader::CleanUp(bool unload) { #if defined(LIBRARY_LOADER_DBUS_H_DLOPEN) if (unload) { dlclose(library_); library_ = NULL; } #endif loaded_ = false; bus_add_match = NULL; bus_get = NULL; bus_get_unique_name = NULL; bus_remove_match = NULL; connection_pop_message = NULL; connection_read_write = NULL; connection_send_with_reply_and_block = NULL; connection_unref = NULL; error_free = NULL; error_init = NULL; error_is_set = NULL; message_append_args = NULL; message_is_signal = NULL; message_iter_get_arg_type = NULL; message_iter_get_basic = NULL; message_iter_init = NULL; message_iter_next = NULL; message_iter_recurse = NULL; message_new_method_call = NULL; message_unref = NULL; move_error = NULL; threads_init_default = NULL; } ================================================ FILE: src/loaders/loader_dbus.h ================================================ #ifndef LIBRARY_LOADER_DBUS_H #define LIBRARY_LOADER_DBUS_H #include #define LIBRARY_LOADER_DBUS_H_DLOPEN #include #include class libdbus_loader { public: libdbus_loader(); libdbus_loader(const std::string& library_name) : libdbus_loader() { Load(library_name); } ~libdbus_loader(); bool Load(const std::string& library_name); bool IsLoaded() { return loaded_; } decltype(&::dbus_bus_add_match) bus_add_match; decltype(&::dbus_bus_get) bus_get; decltype(&::dbus_bus_get_unique_name) bus_get_unique_name; decltype(&::dbus_bus_remove_match) bus_remove_match; decltype(&::dbus_connection_add_filter) connection_add_filter; decltype(&::dbus_connection_pop_message) connection_pop_message; decltype(&::dbus_connection_read_write) connection_read_write; decltype(&::dbus_connection_read_write_dispatch) connection_read_write_dispatch; decltype(&::dbus_connection_remove_filter) connection_remove_filter; decltype(&::dbus_connection_send_with_reply_and_block) connection_send_with_reply_and_block; decltype(&::dbus_connection_unref) connection_unref; decltype(&::dbus_error_free) error_free; decltype(&::dbus_error_init) error_init; decltype(&::dbus_error_is_set) error_is_set; decltype(&::dbus_message_append_args) message_append_args; decltype(&::dbus_message_get_sender) message_get_sender; decltype(&::dbus_message_get_interface) message_get_interface; decltype(&::dbus_message_get_member) message_get_member; decltype(&::dbus_message_is_signal) message_is_signal; decltype(&::dbus_message_iter_get_arg_type) message_iter_get_arg_type; decltype(&::dbus_message_iter_get_basic) message_iter_get_basic; decltype(&::dbus_message_iter_init) message_iter_init; decltype(&::dbus_message_iter_next) message_iter_next; decltype(&::dbus_message_iter_recurse) message_iter_recurse; decltype(&::dbus_message_new_method_call) message_new_method_call; decltype(&::dbus_message_unref) message_unref; decltype(&::dbus_move_error) move_error; decltype(&::dbus_threads_init_default) threads_init_default; private: void CleanUp(bool unload); #if defined(LIBRARY_LOADER_DBUS_H_DLOPEN) void* library_; #endif bool loaded_; // Disallow copy constructor and assignment operator. libdbus_loader(const libdbus_loader&); void operator=(const libdbus_loader&); }; #endif // LIBRARY_LOADER_DBUS_H ================================================ FILE: src/loaders/loader_glx.cpp ================================================ #include #include #include "real_dlsym.h" #include "loaders/loader_glx.h" glx_loader::glx_loader() : loaded_(false) { } glx_loader::~glx_loader() { CleanUp(loaded_); } bool glx_loader::Load() { if (loaded_) { return true; } // Force load libGL void *handle = nullptr; #ifndef NDEBUG // Use apitrace's glxtrace.so for debugging // Assumes glxtrace.so lives outside of usual library paths and is only preloaded handle = real_dlopen("glxtrace.so", RTLD_LAZY); #endif if (!handle) handle = real_dlopen("libGL.so.1", RTLD_LAZY); if (!handle) { SPDLOG_ERROR("Failed to open " MANGOHUD_ARCH " libGL.so.1: {}", dlerror()); return false; } GetProcAddress = reinterpret_castGetProcAddress)>( real_dlsym(handle, "glXGetProcAddress")); GetProcAddressARB = reinterpret_castGetProcAddressARB)>( real_dlsym(handle, "glXGetProcAddressARB")); if (!GetProcAddress) { CleanUp(true); return false; } CreateContext = reinterpret_castCreateContext)>( GetProcAddress((const unsigned char *)"glXCreateContext")); if (!CreateContext) { CleanUp(true); return false; } CreateContextAttribs = reinterpret_castCreateContextAttribs)>( GetProcAddress((const unsigned char *)"glXCreateContextAttribs")); // if (!CreateContextAttribs) { // CleanUp(true); // return false; // } CreateContextAttribsARB = reinterpret_castCreateContextAttribsARB)>( GetProcAddress((const unsigned char *)"glXCreateContextAttribsARB")); // if (!CreateContextAttribsARB) { // CleanUp(true); // return false; // } DestroyContext = reinterpret_castDestroyContext)>( GetProcAddress((const unsigned char *)"glXDestroyContext")); if (!DestroyContext) { CleanUp(true); return false; } GetCurrentContext = reinterpret_castGetCurrentContext)>( GetProcAddress((const unsigned char *)"glXGetCurrentContext")); if (!GetCurrentContext) { CleanUp(true); return false; } GetCurrentDrawable = reinterpret_castGetCurrentDrawable)>( GetProcAddress((const unsigned char *)"glXGetCurrentDrawable")); if (!GetCurrentDrawable) { CleanUp(true); return false; } GetCurrentReadDrawable = reinterpret_castGetCurrentReadDrawable)>( GetProcAddress((const unsigned char *)"glXGetCurrentReadDrawable")); SwapBuffers = reinterpret_castSwapBuffers)>( GetProcAddress((const unsigned char *)"glXSwapBuffers")); if (!SwapBuffers) { CleanUp(true); return false; } SwapBuffersMscOML = reinterpret_castSwapBuffersMscOML)>( GetProcAddress((const unsigned char *)"glXSwapBuffersMscOML")); /*if (!SwapBuffersMscOML) { CleanUp(true); return false; }*/ SwapIntervalEXT = reinterpret_castSwapIntervalEXT)>( GetProcAddress((const unsigned char *)"glXSwapIntervalEXT")); SwapIntervalSGI = reinterpret_castSwapIntervalSGI)>( GetProcAddress((const unsigned char *)"glXSwapIntervalSGI")); SwapIntervalMESA = reinterpret_castSwapIntervalMESA)>( GetProcAddress((const unsigned char *)"glXSwapIntervalMESA")); GetSwapIntervalMESA = reinterpret_castGetSwapIntervalMESA)>( GetProcAddress((const unsigned char *)"glXGetSwapIntervalMESA")); QueryDrawable = reinterpret_castQueryDrawable)>( GetProcAddress((const unsigned char *)"glXQueryDrawable")); MakeContextCurrent = reinterpret_castMakeContextCurrent)>( GetProcAddress((const unsigned char *)"glXMakeContextCurrent")); MakeCurrent = reinterpret_castMakeCurrent)>( GetProcAddress((const unsigned char *)"glXMakeCurrent")); if (!MakeCurrent) { CleanUp(true); return false; } loaded_ = true; return true; } void glx_loader::CleanUp(bool unload) { loaded_ = false; GetProcAddress = nullptr; GetProcAddressARB = nullptr; CreateContext = nullptr; DestroyContext = nullptr; SwapBuffers = nullptr; SwapIntervalEXT = nullptr; SwapIntervalSGI = nullptr; SwapIntervalMESA = nullptr; QueryDrawable = nullptr; MakeContextCurrent = nullptr; MakeCurrent = nullptr; } glx_loader glx; ================================================ FILE: src/loaders/loader_glx.h ================================================ #pragma once #include "gl/gl.h" #include class glx_loader { public: glx_loader(); ~glx_loader(); bool Load(); bool IsLoaded() { return loaded_; } decltype(&::glXGetProcAddress) GetProcAddress; decltype(&::glXGetProcAddressARB) GetProcAddressARB; decltype(&::glXCreateContext) CreateContext; decltype(&::glXCreateContextAttribsARB) CreateContextAttribs; decltype(&::glXCreateContextAttribsARB) CreateContextAttribsARB; decltype(&::glXDestroyContext) DestroyContext; decltype(&::glXGetCurrentDrawable) GetCurrentDrawable; decltype(&::glXGetCurrentReadDrawable) GetCurrentReadDrawable; decltype(&::glXSwapBuffers) SwapBuffers; decltype(&::glXSwapIntervalEXT) SwapIntervalEXT; decltype(&::glXSwapIntervalSGI) SwapIntervalSGI; decltype(&::glXSwapIntervalMESA) SwapIntervalMESA; decltype(&::glXGetSwapIntervalMESA) GetSwapIntervalMESA; decltype(&::glXMakeContextCurrent) MakeContextCurrent; decltype(&::glXMakeCurrent) MakeCurrent; decltype(&::glXGetCurrentContext) GetCurrentContext; decltype(&::glXQueryDrawable) QueryDrawable; decltype(&::glXSwapBuffersMscOML) SwapBuffersMscOML; private: void CleanUp(bool unload); bool loaded_; // Disallow copy constructor and assignment operator. glx_loader(const glx_loader&); void operator=(const glx_loader&); }; ================================================ FILE: src/loaders/loader_nvctrl.cpp ================================================ #include "loader_nvctrl.h" #include #include // Put these sanity checks here so that they fire at most once // (to avoid cluttering the build output). #if !defined(LIBRARY_LOADER_NVCTRL_H_DLOPEN) && !defined(LIBRARY_LOADER_NVCTRL_H_DT_NEEDED) #error neither LIBRARY_LOADER_NVCTRL_H_DLOPEN nor LIBRARY_LOADER_NVCTRL_H_DT_NEEDED defined #endif #if defined(LIBRARY_LOADER_NVCTRL_H_DLOPEN) && defined(LIBRARY_LOADER_NVCTRL_H_DT_NEEDED) #error both LIBRARY_LOADER_NVCTRL_H_DLOPEN and LIBRARY_LOADER_NVCTRL_H_DT_NEEDED defined #endif static std::shared_ptr libnvctrl_; std::shared_ptr get_libnvctrl_loader() { if (!libnvctrl_) libnvctrl_ = std::make_shared("libXNVCtrl.so.0"); return libnvctrl_; } libnvctrl_loader::libnvctrl_loader() : loaded_(false) { } libnvctrl_loader::~libnvctrl_loader() { CleanUp(loaded_); } bool libnvctrl_loader::Load(const std::string& library_name) { if (loaded_) { return false; } #if defined(LIBRARY_LOADER_NVCTRL_H_DLOPEN) library_ = dlopen(library_name.c_str(), RTLD_LAZY | RTLD_NODELETE); if (!library_) { SPDLOG_DEBUG("Failed to open " MANGOHUD_ARCH " {}: {}", library_name, dlerror()); return false; } XNVCTRLIsNvScreen = reinterpret_castXNVCTRLIsNvScreen)>( dlsym(library_, "XNVCTRLIsNvScreen")); if (!XNVCTRLIsNvScreen) { CleanUp(true); return false; } XNVCTRLQueryVersion = reinterpret_castXNVCTRLQueryVersion)>( dlsym(library_, "XNVCTRLQueryVersion")); if (!XNVCTRLQueryVersion) { CleanUp(true); return false; } XNVCTRLQueryAttribute = reinterpret_castXNVCTRLQueryAttribute)>( dlsym(library_, "XNVCTRLQueryAttribute")); if (!XNVCTRLQueryAttribute) { CleanUp(true); return false; } XNVCTRLQueryTargetStringAttribute = reinterpret_castXNVCTRLQueryTargetStringAttribute)>( dlsym(library_, "XNVCTRLQueryTargetStringAttribute")); if (!XNVCTRLQueryTargetStringAttribute) { CleanUp(true); return false; } XNVCTRLQueryTargetAttribute64 = reinterpret_castXNVCTRLQueryTargetAttribute64)>( dlsym(library_, "XNVCTRLQueryTargetAttribute64")); if (!XNVCTRLQueryTargetAttribute64) { CleanUp(true); return false; } XNVCTRLQueryTargetCount = reinterpret_castXNVCTRLQueryTargetCount)>( dlsym(library_, "XNVCTRLQueryTargetCount")); if (!XNVCTRLQueryTargetCount) { CleanUp(true); return false; } #endif #if defined(LIBRARY_LOADER_NVCTRL_H_DT_NEEDED) XNVCTRLQueryVersion = &::XNVCTRLQueryVersion; XNVCTRLQueryAttribute = &::XNVCTRLQueryAttribute; #endif loaded_ = true; return true; } void libnvctrl_loader::CleanUp(bool unload) { #if defined(LIBRARY_LOADER_NVCTRL_H_DLOPEN) if (unload) { dlclose(library_); library_ = NULL; } #endif loaded_ = false; XNVCTRLQueryVersion = NULL; XNVCTRLQueryAttribute = NULL; } ================================================ FILE: src/loaders/loader_nvctrl.h ================================================ #pragma once #ifndef LIBRARY_LOADER_NVCTRL_H #define LIBRARY_LOADER_NVCTRL_H // #define Bool bool #include #include "NVCtrl/NVCtrlLib.h" #define LIBRARY_LOADER_NVCTRL_H_DLOPEN #include #include #include class libnvctrl_loader { public: libnvctrl_loader(); libnvctrl_loader(const std::string& library_name) : libnvctrl_loader() { Load(library_name); } ~libnvctrl_loader(); bool Load(const std::string& library_name); bool IsLoaded() { return loaded_; } decltype(&::XNVCTRLIsNvScreen) XNVCTRLIsNvScreen; decltype(&::XNVCTRLQueryVersion) XNVCTRLQueryVersion; decltype(&::XNVCTRLQueryAttribute) XNVCTRLQueryAttribute; decltype(&::XNVCTRLQueryTargetStringAttribute) XNVCTRLQueryTargetStringAttribute; decltype(&::XNVCTRLQueryTargetAttribute64) XNVCTRLQueryTargetAttribute64; decltype(&::XNVCTRLQueryTargetCount) XNVCTRLQueryTargetCount; private: void CleanUp(bool unload); #if defined(LIBRARY_LOADER_NVCTRL_H_DLOPEN) void* library_; #endif bool loaded_; // Disallow copy constructor and assignment operator. libnvctrl_loader(const libnvctrl_loader&); void operator=(const libnvctrl_loader&); }; std::shared_ptr get_libnvctrl_loader(); #endif // LIBRARY_LOADER_NVCTRL_H ================================================ FILE: src/loaders/loader_nvml.cpp ================================================ // This is generated file. Do not modify directly. // Path to the code generator: /home/crz/git/MangoHud/generate_library_loader.py . #include "loader_nvml.h" #include #include // Put these sanity checks here so that they fire at most once // (to avoid cluttering the build output). #if !defined(LIBRARY_LOADER_NVML_H_DLOPEN) && !defined(LIBRARY_LOADER_NVML_H_DT_NEEDED) #error neither LIBRARY_LOADER_NVML_H_DLOPEN nor LIBRARY_LOADER_NVML_H_DT_NEEDED defined #endif #if defined(LIBRARY_LOADER_NVML_H_DLOPEN) && defined(LIBRARY_LOADER_NVML_H_DT_NEEDED) #error both LIBRARY_LOADER_NVML_H_DLOPEN and LIBRARY_LOADER_NVML_H_DT_NEEDED defined #endif static std::shared_ptr libnvml_; std::shared_ptr get_libnvml_loader() { if (!libnvml_) libnvml_ = std::make_shared("libnvidia-ml.so.1"); return libnvml_; } libnvml_loader::libnvml_loader() : loaded_(false) { } libnvml_loader::~libnvml_loader() { CleanUp(loaded_); } bool libnvml_loader::Load(const std::string& library_name) { if (loaded_) { return false; } #if defined(LIBRARY_LOADER_NVML_H_DLOPEN) library_ = dlopen(library_name.c_str(), RTLD_LAZY | RTLD_NODELETE); if (!library_) { SPDLOG_ERROR("Failed to open " MANGOHUD_ARCH " {}: {}", library_name, dlerror()); return false; } #endif #if defined(LIBRARY_LOADER_NVML_H_DLOPEN) nvmlInit_v2 = reinterpret_castnvmlInit_v2)>( dlsym(library_, "nvmlInit_v2")); #endif #if defined(LIBRARY_LOADER_NVML_H_DT_NEEDED) nvmlInit_v2 = &::nvmlInit_v2; #endif if (!nvmlInit_v2) { CleanUp(true); return false; } #if defined(LIBRARY_LOADER_NVML_H_DLOPEN) nvmlShutdown = reinterpret_castnvmlShutdown)>( dlsym(library_, "nvmlShutdown")); #endif #if defined(LIBRARY_LOADER_NVML_H_DT_NEEDED) nvmlShutdown = &::nvmlShutdown; #endif if (!nvmlShutdown) { CleanUp(true); return false; } #if defined(LIBRARY_LOADER_NVML_H_DLOPEN) nvmlDeviceGetUtilizationRates = reinterpret_castnvmlDeviceGetUtilizationRates)>( dlsym(library_, "nvmlDeviceGetUtilizationRates")); #endif #if defined(LIBRARY_LOADER_NVML_H_DT_NEEDED) nvmlDeviceGetUtilizationRates = &::nvmlDeviceGetUtilizationRates; #endif if (!nvmlDeviceGetUtilizationRates) { CleanUp(true); return false; } #if defined(LIBRARY_LOADER_NVML_H_DLOPEN) nvmlDeviceGetTemperature = reinterpret_castnvmlDeviceGetTemperature)>( dlsym(library_, "nvmlDeviceGetTemperature")); #endif #if defined(LIBRARY_LOADER_NVML_H_DT_NEEDED) nvmlDeviceGetTemperature = &::nvmlDeviceGetTemperature; #endif if (!nvmlDeviceGetTemperature) { CleanUp(true); return false; } #if defined(LIBRARY_LOADER_NVML_H_DLOPEN) nvmlDeviceGetPciInfo_v3 = reinterpret_castnvmlDeviceGetPciInfo_v3)>( dlsym(library_, "nvmlDeviceGetPciInfo_v3")); #endif #if defined(LIBRARY_LOADER_NVML_H_DT_NEEDED) nvmlDeviceGetPciInfo_v3 = &::nvmlDeviceGetPciInfo_v3; #endif if (!nvmlDeviceGetPciInfo_v3) { CleanUp(true); return false; } #if defined(LIBRARY_LOADER_NVML_H_DLOPEN) nvmlDeviceGetCount_v2 = reinterpret_castnvmlDeviceGetCount_v2)>( dlsym(library_, "nvmlDeviceGetCount_v2")); #endif #if defined(LIBRARY_LOADER_NVML_H_DT_NEEDED) nvmlDeviceGetCount_v2 = &::nvmlDeviceGetCount_v2; #endif if (!nvmlDeviceGetCount_v2) { CleanUp(true); return false; } #if defined(LIBRARY_LOADER_NVML_H_DLOPEN) nvmlDeviceGetHandleByIndex_v2 = reinterpret_castnvmlDeviceGetHandleByIndex_v2)>( dlsym(library_, "nvmlDeviceGetHandleByIndex_v2")); #endif #if defined(LIBRARY_LOADER_NVML_H_DT_NEEDED) nvmlDeviceGetHandleByIndex_v2 = &::nvmlDeviceGetHandleByIndex_v2; #endif if (!nvmlDeviceGetHandleByIndex_v2) { CleanUp(true); return false; } #if defined(LIBRARY_LOADER_NVML_H_DLOPEN) nvmlDeviceGetHandleByPciBusId_v2 = reinterpret_castnvmlDeviceGetHandleByPciBusId_v2)>( dlsym(library_, "nvmlDeviceGetHandleByPciBusId_v2")); #endif #if defined(LIBRARY_LOADER_NVML_H_DT_NEEDED) nvmlDeviceGetHandleByPciBusId_v2 = &::nvmlDeviceGetHandleByPciBusId_v2; #endif if (!nvmlDeviceGetHandleByPciBusId_v2) { CleanUp(true); return false; } #if defined(LIBRARY_LOADER_NVML_H_DLOPEN) nvmlDeviceGetMemoryInfo = reinterpret_castnvmlDeviceGetMemoryInfo)>( dlsym(library_, "nvmlDeviceGetMemoryInfo")); #endif #if defined(LIBRARY_LOADER_NVML_H_DT_NEEDED) nvmlDeviceGetMemoryInfo = &::nvmlDeviceGetMemoryInfo; #endif if (!nvmlDeviceGetMemoryInfo) { CleanUp(true); return false; } #if defined(LIBRARY_LOADER_NVML_H_DLOPEN) nvmlDeviceGetClockInfo = reinterpret_castnvmlDeviceGetClockInfo)>( dlsym(library_, "nvmlDeviceGetClockInfo")); #endif #if defined(LIBRARY_LOADER_NVML_H_DT_NEEDED) nvmlDeviceGetClockInfo = &::nvmlDeviceGetClockInfo; #endif if (!nvmlDeviceGetClockInfo) { CleanUp(true); return false; } #if defined(LIBRARY_LOADER_NVML_H_DLOPEN) nvmlErrorString = reinterpret_castnvmlErrorString)>( dlsym(library_, "nvmlErrorString")); #endif #if defined(LIBRARY_LOADER_NVML_H_DT_NEEDED) nvmlErrorString = &::nvmlErrorString; #endif if (!nvmlErrorString) { CleanUp(true); return false; } #if defined(LIBRARY_LOADER_NVML_H_DLOPEN) nvmlDeviceGetCurrentClocksThrottleReasons = reinterpret_castnvmlDeviceGetCurrentClocksThrottleReasons)>( dlsym(library_, "nvmlDeviceGetCurrentClocksThrottleReasons")); #endif #if defined(LIBRARY_LOADER_NVML_H_DT_NEEDED) nvmlDeviceGetCurrentClocksThrottleReasons = &::nvmlDeviceGetCurrentClocksThrottleReasons; #endif if (!nvmlErrorString) { CleanUp(true); return false; } #if defined(LIBRARY_LOADER_NVML_H_DLOPEN) nvmlDeviceGetPowerUsage = reinterpret_castnvmlDeviceGetPowerUsage)>( dlsym(library_, "nvmlDeviceGetPowerUsage")); #endif #if defined(LIBRARY_LOADER_NVML_H_DT_NEEDED) nvmlDeviceGetPowerUsage = &::nvmlDeviceGetPowerUsage; #endif if (!nvmlDeviceGetPowerUsage) { CleanUp(true); return false; } #if defined(LIBRARY_LOADER_NVML_H_DLOPEN) nvmlDeviceGetPowerManagementLimit = reinterpret_castnvmlDeviceGetPowerManagementLimit)>( dlsym(library_, "nvmlDeviceGetPowerManagementLimit")); #endif #if defined(LIBRARY_LOADER_NVML_H_DT_NEEDED) nvmlDeviceGetPowerManagementLimit = &::nvmlDeviceGetPowerManagementLimit; #endif if (!nvmlDeviceGetPowerManagementLimit) { CleanUp(true); return false; } #if defined(LIBRARY_LOADER_NVML_H_DLOPEN) nvmlUnitGetFanSpeedInfo = reinterpret_castnvmlUnitGetFanSpeedInfo)>( dlsym(library_, "nvmlUnitGetFanSpeedInfo")); #endif #if defined(LIBRARY_LOADER_NVML_H_DT_NEEDED) nvmlUnitGetFanSpeedInfo = &::nvmlUnitGetFanSpeedInfo; #endif if (!nvmlUnitGetFanSpeedInfo) { CleanUp(true); return false; } #if defined(LIBRARY_LOADER_NVML_H_DLOPEN) nvmlUnitGetHandleByIndex = reinterpret_castnvmlUnitGetHandleByIndex)>( dlsym(library_, "nvmlUnitGetHandleByIndex")); #endif #if defined(LIBRARY_LOADER_NVML_H_DT_NEEDED) nvmlUnitGetHandleByIndex = &::nvmlUnitGetHandleByIndex; #endif if (!nvmlUnitGetHandleByIndex) { CleanUp(true); return false; } #if defined(LIBRARY_LOADER_NVML_H_DLOPEN) nvmlDeviceGetFanSpeed = reinterpret_castnvmlDeviceGetFanSpeed)>( dlsym(library_, "nvmlDeviceGetFanSpeed")); #endif #if defined(LIBRARY_LOADER_NVML_H_DT_NEEDED) nvmlDeviceGetFanSpeed = &::nvmlDeviceGetFanSpeed; #endif if (!nvmlDeviceGetFanSpeed) { CleanUp(true); return false; } #if defined(LIBRARY_LOADER_NVML_H_DLOPEN) nvmlDeviceGetGraphicsRunningProcesses = reinterpret_castnvmlDeviceGetGraphicsRunningProcesses)>( dlsym(library_, "nvmlDeviceGetGraphicsRunningProcesses")); #endif #if defined(LIBRARY_LOADER_NVML_H_DT_NEEDED) nvmlDeviceGetGraphicsRunningProcesses = &::nvmlDeviceGetGraphicsRunningProcesses; #endif if (!nvmlDeviceGetGraphicsRunningProcesses) { CleanUp(true); return false; } loaded_ = true; return true; } void libnvml_loader::CleanUp(bool unload) { #if defined(LIBRARY_LOADER_NVML_H_DLOPEN) if (unload) { dlclose(library_); library_ = NULL; } #endif loaded_ = false; nvmlInit_v2 = NULL; nvmlShutdown = NULL; nvmlDeviceGetUtilizationRates = NULL; nvmlDeviceGetTemperature = NULL; nvmlDeviceGetPciInfo_v3 = NULL; nvmlDeviceGetCount_v2 = NULL; nvmlDeviceGetHandleByIndex_v2 = NULL; nvmlDeviceGetHandleByPciBusId_v2 = NULL; nvmlDeviceGetCurrentClocksThrottleReasons = NULL; nvmlUnitGetFanSpeedInfo = NULL; nvmlUnitGetHandleByIndex = NULL; nvmlDeviceGetFanSpeed = NULL; nvmlDeviceGetGraphicsRunningProcesses = NULL; } ================================================ FILE: src/loaders/loader_nvml.h ================================================ // This is generated file. Do not modify directly. // Path to the code generator: /home/crz/git/MangoHud/generate_library_loader.py . #ifndef LIBRARY_LOADER_NVML_H #define LIBRARY_LOADER_NVML_H #if USE_SYSTEM_NVML #include #else #include "nvml.h" typedef nvmlProcessInfo_t nvmlProcessInfo_v1_t; #endif #define LIBRARY_LOADER_NVML_H_DLOPEN #include #include #include class libnvml_loader { public: libnvml_loader(); libnvml_loader(const std::string& library_name) : libnvml_loader() { Load(library_name); } ~libnvml_loader(); bool Load(const std::string& library_name); bool IsLoaded() { return loaded_; } decltype(&::nvmlInit_v2) nvmlInit_v2; decltype(&::nvmlShutdown) nvmlShutdown; decltype(&::nvmlDeviceGetUtilizationRates) nvmlDeviceGetUtilizationRates; decltype(&::nvmlDeviceGetTemperature) nvmlDeviceGetTemperature; decltype(&::nvmlDeviceGetPciInfo_v3) nvmlDeviceGetPciInfo_v3; decltype(&::nvmlDeviceGetCount_v2) nvmlDeviceGetCount_v2; decltype(&::nvmlDeviceGetHandleByIndex_v2) nvmlDeviceGetHandleByIndex_v2; decltype(&::nvmlDeviceGetHandleByPciBusId_v2) nvmlDeviceGetHandleByPciBusId_v2; decltype(&::nvmlDeviceGetMemoryInfo) nvmlDeviceGetMemoryInfo; decltype(&::nvmlDeviceGetClockInfo) nvmlDeviceGetClockInfo; decltype(&::nvmlErrorString) nvmlErrorString; decltype(&::nvmlDeviceGetPowerUsage) nvmlDeviceGetPowerUsage; decltype(&::nvmlDeviceGetPowerManagementLimit) nvmlDeviceGetPowerManagementLimit; decltype(&::nvmlDeviceGetCurrentClocksThrottleReasons) nvmlDeviceGetCurrentClocksThrottleReasons; decltype(&::nvmlUnitGetFanSpeedInfo) nvmlUnitGetFanSpeedInfo; decltype(&::nvmlUnitGetHandleByIndex) nvmlUnitGetHandleByIndex; decltype(&::nvmlDeviceGetFanSpeed) nvmlDeviceGetFanSpeed; decltype(&::nvmlDeviceGetGraphicsRunningProcesses) nvmlDeviceGetGraphicsRunningProcesses; private: void CleanUp(bool unload); #if defined(LIBRARY_LOADER_NVML_H_DLOPEN) void* library_ = nullptr; #endif bool loaded_; // Disallow copy constructor and assignment operator. libnvml_loader(const libnvml_loader&); void operator=(const libnvml_loader&); }; std::shared_ptr get_libnvml_loader(); #endif // LIBRARY_LOADER_NVML_H ================================================ FILE: src/loaders/loader_x11.cpp ================================================ #include "loader_x11.h" #include #include libx11_loader::libx11_loader() : loaded_(false) { } libx11_loader::~libx11_loader() { CleanUp(loaded_); } bool libx11_loader::Load(const std::string& library_name) { if (loaded_) { return false; } library_ = dlopen(library_name.c_str(), RTLD_LAZY | RTLD_NODELETE); if (!library_) { SPDLOG_ERROR("Failed to open " MANGOHUD_ARCH " {}: {}", library_name, dlerror()); return false; } XOpenDisplay = reinterpret_castXOpenDisplay)>( dlsym(library_, "XOpenDisplay")); if (!XOpenDisplay) { CleanUp(true); return false; } XCloseDisplay = reinterpret_castXCloseDisplay)>( dlsym(library_, "XCloseDisplay")); if (!XCloseDisplay) { CleanUp(true); return false; } XDefaultScreen = reinterpret_castXDefaultScreen)>( dlsym(library_, "XDefaultScreen")); if (!XDefaultScreen) { CleanUp(true); return false; } XQueryKeymap = reinterpret_castXQueryKeymap)>( dlsym(library_, "XQueryKeymap")); if (!XQueryKeymap) { CleanUp(true); return false; } XKeysymToKeycode = reinterpret_castXKeysymToKeycode)>( dlsym(library_, "XKeysymToKeycode")); if (!XKeysymToKeycode) { CleanUp(true); return false; } XStringToKeysym = reinterpret_castXStringToKeysym)>( dlsym(library_, "XStringToKeysym")); if (!XStringToKeysym) { CleanUp(true); return false; } XGetGeometry = reinterpret_castXGetGeometry)>( dlsym(library_, "XGetGeometry")); if (!XGetGeometry) { CleanUp(true); return false; } XQueryExtension = reinterpret_castXQueryExtension)>( dlsym(library_, "XQueryExtension")); if (!XQueryExtension) { CleanUp(true); return false; } loaded_ = true; return true; } void libx11_loader::CleanUp(bool unload) { if (unload) { dlclose(library_); library_ = NULL; } loaded_ = false; XOpenDisplay = NULL; XCloseDisplay = NULL; XQueryKeymap = NULL; XKeysymToKeycode = NULL; XStringToKeysym = NULL; XGetGeometry = NULL; XQueryExtension = NULL; } static std::shared_ptr loader; std::shared_ptr get_libx11() { if (!loader) loader = std::make_shared("libX11.so.6"); return loader; } ================================================ FILE: src/loaders/loader_x11.h ================================================ #pragma once #include #include #include #include class libx11_loader { public: libx11_loader(); libx11_loader(const std::string& library_name) { Load(library_name); } ~libx11_loader(); bool Load(const std::string& library_name); bool IsLoaded() { return loaded_; } decltype(&::XOpenDisplay) XOpenDisplay; decltype(&::XCloseDisplay) XCloseDisplay; decltype(&::XDefaultScreen) XDefaultScreen; decltype(&::XQueryKeymap) XQueryKeymap; decltype(&::XKeysymToKeycode) XKeysymToKeycode; decltype(&::XStringToKeysym) XStringToKeysym; decltype(&::XGetGeometry) XGetGeometry; decltype(&::XQueryExtension) XQueryExtension; private: void CleanUp(bool unload); void* library_ = nullptr; bool loaded_ = false; // Disallow copy constructor and assignment operator. libx11_loader(const libx11_loader&); void operator=(const libx11_loader&); }; std::shared_ptr get_libx11(); ================================================ FILE: src/logging.cpp ================================================ #include #include #include #include #include #include "logging.h" #include "overlay.h" #include "config.h" #include "file_utils.h" #include "string_utils.h" #include "version.h" #include "fps_metrics.h" using namespace std; string os, cpu, gpu, ram, kernel, driver, cpusched; bool sysInfoFetched = false; double fps; float frametime; logData currentLogData = {}; std::shared_ptr logger; ofstream output_file; std::thread log_thread; string exec(string command) { #ifndef _WIN32 command = "unset LD_PRELOAD; " + command; #endif std::array buffer; std::string result; auto deleter = [](FILE* ptr){ pclose(ptr); }; std::unique_ptr pipe(popen(command.c_str(), "r"), deleter); if (!pipe) { return "popen failed!"; } while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr) { result += buffer.data(); } return result; } static void upload_file(std::string logFile){ std::string command = "curl --include --request POST https://flightlessmango.com/logs -F 'log[game_id]=26506' -F 'log[user_id]=176' -F 'attachment=true' -A 'mangohud' "; command += " -F 'log[uploads][]=@" + logFile + "'"; command += " | grep Location | cut -c11-"; std::string url = exec(command); std::cout << "upload url: " << url; exec("xdg-open " + url); } static void upload_files(const std::vector& logFiles){ std::string command = "curl --include --request POST https://flightlessmango.com/logs -F 'log[game_id]=26506' -F 'log[user_id]=176' -F 'attachment=true' -A 'mangohud' "; for (auto& file : logFiles) command += " -F 'log[uploads][]=@" + file + "'"; command += " | grep Location | cut -c11-"; std::string url = exec(command); std::cout << "upload url: " << url; exec("xdg-open " + url); } static bool compareByFps(const logData &a, const logData &b) { return a.fps < b.fps; } static void writeSummary(string filename){ auto& logArray = logger->get_log_data(); // if the log is stopped/started too fast we might end up with an empty vector. // in that case, just bail. if (logArray.size() == 0){ logger->stop_logging(); return; } filename = filename.substr(0, filename.size() - 4); filename += "_summary.csv"; SPDLOG_INFO("{}", filename); SPDLOG_DEBUG("Writing summary log file [{}]", filename); std::ofstream out(filename, ios::out | ios::app); if (out){ out << "0.1% Min FPS," << "1% Min FPS," << "97% Percentile FPS," << "Average FPS," << "GPU Load," << "CPU Load," << "Average Frame Time," << "Average GPU Temp," << "Average CPU Temp," << "Average VRAM Used," << "Average RAM Used," << "Average Swap Used," << "Peak GPU Load," << "Peak CPU Load," << "Peak GPU Temp," << "Peak CPU Temp," << "Peak VRAM Used," << "Peak RAM Used," << "Peak Swap Used" << "\n"; std::vector sorted = logArray; std::sort(sorted.begin(), sorted.end(), compareByFps); float total = 0.0f; float total_gpu = 0.0f; float total_cpu = 0.0f; int total_gpu_temp = 0.0f; int total_cpu_temp = 0.0f; float total_vram = 0.0f; float total_ram = 0.0f; float total_swap = 0.0f; int peak_gpu = 0.0f; float peak_cpu = 0.0f; int peak_gpu_temp = 0.0f; int peak_cpu_temp = 0.0f; float peak_vram = 0.0f; float peak_ram = 0.0f; float peak_swap = 0.0f; float result; std::vector fps_values; for (auto& data : sorted) fps_values.push_back(data.frametime); std::unique_ptr fpsmetrics; std::vector metrics {"0.001", "0.01", "0.97"}; fpsmetrics = std::make_unique(metrics, fps_values); auto metrics_copy = fpsmetrics->copy_metrics(); for (auto& metric : metrics_copy) out << metric.value << ","; fpsmetrics.reset(); total = 0; for (auto input : sorted){ total = total + input.frametime; total_gpu = total_gpu + input.gpu_load; total_cpu = total_cpu + input.cpu_load; total_gpu_temp = total_gpu_temp + input.gpu_temp; total_cpu_temp = total_cpu_temp + input.cpu_temp; total_vram = total_vram + input.gpu_vram_used; total_ram = total_ram + input.ram_used; total_swap = total_swap + input.swap_used; peak_gpu = std::max(peak_gpu, input.gpu_load); peak_cpu = std::max(peak_cpu, input.cpu_load); peak_gpu_temp = std::max(peak_gpu_temp, input.gpu_temp); peak_cpu_temp = std::max(peak_cpu_temp, input.cpu_temp); peak_vram = std::max(peak_vram, input.gpu_vram_used); peak_ram = std::max(peak_ram, input.ram_used); peak_swap = std::max(peak_swap, input.swap_used); } // Average FPS result = 1000 / (total / sorted.size()); out << fixed << setprecision(1) << result << ","; // GPU Load (Average) result = total_gpu / sorted.size(); out << result << ","; // CPU Load (Average) result = total_cpu / sorted.size(); out << result << ","; // Average Frame Time result = total / sorted.size(); out << result << ","; // Average GPU Temp result = total_gpu_temp / sorted.size(); out << result << ","; // Average CPU Temp result = total_cpu_temp / sorted.size(); out << result << ","; // Average VRAM Used result = total_vram / sorted.size(); out << result << ","; // Average RAM Used result = total_ram / sorted.size(); out << result << ","; // Average Swap Used result = total_swap / sorted.size(); out << result << ","; // Peak GPU Load out << peak_gpu << ","; // Peak CPU Load out << peak_cpu << ","; // Peak GPU Temp out << peak_gpu_temp << ","; // Peak CPU Temp out << peak_cpu_temp << ","; // Peak VRAM Used out << peak_vram << ","; // Peak RAM Used out << peak_ram << ","; // Peak Swap Used out << peak_swap; } else { SPDLOG_ERROR("Failed to write log file"); } out.close(); } static void writeFileHeaders(ofstream& out){ auto params = get_params(); if (params->enabled[OVERLAY_PARAM_ENABLED_log_versioning]){ printf("log versioning"); out << "v1" << endl; out << MANGOHUD_VERSION << endl; out << "---------------------SYSTEM INFO---------------------" << endl; } out << "os," << "cpu," << "gpu," << "ram," << "kernel," << "driver," << "cpuscheduler" << endl; out << os << "," << cpu << "," << gpu << "," << ram << "," << kernel << "," << driver << "," << cpusched << endl; if (params->enabled[OVERLAY_PARAM_ENABLED_log_versioning]) out << "--------------------FRAME METRICS--------------------" << endl; out << "fps," << "frametime," << "cpu_load," << "cpu_power," << "gpu_load," << "cpu_temp," << "gpu_temp," << "gpu_core_clock," << "gpu_mem_clock," << "gpu_vram_used," << "gpu_power," << "ram_used," << "swap_used," << "process_rss," << "cpu_mhz," << "elapsed" << endl; } void Logger::writeToFile(){ if (!output_file){ output_file.open(m_log_files.back(), ios::out | ios::app); writeFileHeaders(output_file); } auto& logArray = logger->get_log_data(); if (output_file && !logArray.empty()){ output_file << logArray.back().fps << ","; output_file << logArray.back().frametime << ","; output_file << logArray.back().cpu_load << ","; output_file << logArray.back().cpu_power << ","; output_file << logArray.back().gpu_load << ","; output_file << logArray.back().cpu_temp << ","; output_file << logArray.back().gpu_temp << ","; output_file << logArray.back().gpu_core_clock << ","; output_file << logArray.back().gpu_mem_clock << ","; output_file << logArray.back().gpu_vram_used << ","; output_file << logArray.back().gpu_power << ","; output_file << logArray.back().ram_used << ","; output_file << logArray.back().swap_used << ","; output_file << logArray.back().process_rss << ","; output_file << logArray.back().cpu_mhz << ","; output_file << std::chrono::duration_cast(logArray.back().previous).count() << "\n"; output_file.flush(); } else { printf("MANGOHUD: Failed to write log file\n"); } } static string get_log_suffix(){ time_t now_log = time(0); tm *log_time = localtime(&now_log); std::ostringstream buffer; buffer << std::put_time(log_time, "%Y-%m-%d_%H-%M-%S") << ".csv"; string log_name = buffer.str(); return log_name; } Logger::Logger(const overlay_params* in_params) : output_folder(in_params->output_folder), log_interval(in_params->log_interval), log_duration(in_params->log_duration), m_logging_on(false), m_values_valid(false) { if(output_folder.empty()) output_folder = std::getenv("HOME"); m_log_end = Clock::now() - 15s; SPDLOG_DEBUG("Logger constructed!"); } void Logger::start_logging() { if(m_logging_on) return; m_values_valid = false; m_logging_on = true; m_log_start = Clock::now(); std::string program = get_wine_exe_name(); if (program.empty()) program = get_program_name(); m_log_files.emplace_back(output_folder + "/" + program + "_" + get_log_suffix()); if(log_interval != 0){ std::thread log_thread(&Logger::logging, this); // "mangohud-logging" wouldn't fit in the 15 byte limit pthread_setname_np(log_thread.native_handle(), "mangohud-log"); log_thread.detach(); } } void Logger::stop_logging() { if(!m_logging_on) return; m_logging_on = false; m_log_end = Clock::now(); if (log_thread.joinable()) log_thread.join(); calculate_benchmark_data(); try { if (output_file.is_open()) { output_file.close(); } } catch (...) { SPDLOG_INFO("Something went wrong when closing output_file"); } if (!m_log_files.empty()) writeSummary(m_log_files.back()); else SPDLOG_INFO("Can't write summary because m_log_files is empty"); clear_log_data(); #ifdef __linux__ control_client_check(get_params()->control, global_control_client, gpu.c_str()); const char * cmd = "LoggingFinished"; control_send(global_control_client, cmd, strlen(cmd), 0, 0); #endif } void Logger::logging(){ wait_until_data_valid(); while (is_active()){ try_log(); this_thread::sleep_for(std::chrono::milliseconds(log_interval)); } clear_log_data(); } void Logger::try_log() { if(!is_active()) return; if(!m_values_valid) return; auto now = Clock::now(); auto elapsedLog = now - m_log_start; currentLogData.previous = elapsedLog; currentLogData.fps = fps; currentLogData.frametime = frametime; m_log_array.push_back(currentLogData); writeToFile(); if(log_duration && (elapsedLog >= std::chrono::seconds(log_duration))){ stop_logging(); } } void Logger::wait_until_data_valid() { std::unique_lock lck(m_values_valid_mtx); while(! m_values_valid) m_values_valid_cv.wait(lck); } void Logger::notify_data_valid() { std::unique_lock lck(m_values_valid_mtx); m_values_valid = true; m_values_valid_cv.notify_all(); } void Logger::upload_last_log() { if(m_log_files.empty()) return; std::thread(upload_file, m_log_files.back()).detach(); } void Logger::upload_last_logs() { if(m_log_files.empty()) return; std::thread(upload_files, m_log_files).detach(); } void autostart_log(int sleep) { // os_time_sleep() causes freezes with zink + autologging :frog_donut: this_thread::sleep_for(chrono::seconds(sleep)); logger->start_logging(); } void Logger::calculate_benchmark_data(){ vector fps_values {}; for (auto& point : m_log_array) fps_values.push_back(point.frametime); benchmark.percentile_data.clear(); std::vector metrics {"0.97", "avg", "0.01", "0.001"}; std::unique_ptr fpsmetrics; auto params = get_params(); if (!params->fps_metrics.empty()) metrics = params->fps_metrics; fpsmetrics = std::make_unique(metrics, fps_values); auto metrics_copy = fpsmetrics->copy_metrics(); for (auto& metric : metrics_copy) benchmark.percentile_data.push_back({metric.display_name, metric.value}); fpsmetrics.reset(); } ================================================ FILE: src/logging.h ================================================ #pragma once #ifndef MANGOHUD_LOGGING_H #define MANGOHUD_LOGGING_H #include #include #include #include #include #include #include "timing.hpp" #include "overlay_params.h" struct logData{ double fps; float frametime; float cpu_load; float cpu_power; int cpu_mhz; int gpu_load; int cpu_temp; int gpu_temp; int gpu_core_clock; int gpu_mem_clock; int gpu_power; float gpu_vram_used; float ram_used; float swap_used; float process_rss; Clock::duration previous; }; class Logger { public: Logger(const overlay_params* in_params); void start_logging(); void stop_logging(); void logging(); void try_log(); bool is_active() const { return m_logging_on; } void wait_until_data_valid(); void notify_data_valid(); auto last_log_end() const noexcept { return m_log_end; } auto last_log_begin() const noexcept { return m_log_start; } const std::vector& get_log_data() const noexcept { return m_log_array; } void clear_log_data() noexcept { m_log_array.clear(); } void writeToFile(); void upload_last_log(); void upload_last_logs(); void calculate_benchmark_data(); std::string output_folder; const int64_t log_interval; const int64_t log_duration; bool autostart_init = false; private: std::vector m_log_array; std::vector m_log_files; Clock::time_point m_log_start; Clock::time_point m_log_end; bool m_logging_on; std::mutex m_values_valid_mtx; std::condition_variable m_values_valid_cv; bool m_values_valid; }; extern std::shared_ptr logger; extern std::string os, cpu, gpu, ram, kernel, driver, cpusched; extern bool sysInfoFetched; extern double fps; extern float frametime; extern logData currentLogData; std::string exec(std::string command); void autostart_log(int sleep); #endif //MANGOHUD_LOGGING_H ================================================ FILE: src/mangohud.json.in ================================================ { "file_format_version" : "1.0.0", "layer" : { "name": "VK_LAYER_MANGOHUD_overlay_@cpu_family@", "type": "GLOBAL", "api_version": "1.3.0", "library_path": "@ld_libdir_mangohud_abs@/libMangoHud.so", "implementation_version": "1", "description": "Vulkan Hud Overlay", "functions": { "vkGetInstanceProcAddr": "overlay_GetInstanceProcAddr", "vkGetDeviceProcAddr": "overlay_GetDeviceProcAddr" }, "enable_environment": { "MANGOHUD": "1" }, "disable_environment": { "DISABLE_MANGOHUD": "1" } } } ================================================ FILE: src/mangohud.version ================================================ # in base { global: overlay_GetInstanceProcAddr; overlay_GetDeviceProcAddr; glX*; egl*; dlsym; mangohud_find_glx_ptr; mangohud_find_egl_ptr; local: *; }; ================================================ FILE: src/memory.cpp ================================================ #include #include #include #include #include #include #include #include "memory.h" #include "file_utils.h" #include "hud_elements.h" float memused, memmax, swapused; int mem_temp; uint64_t proc_mem_resident, proc_mem_shared, proc_mem_virt; void update_meminfo() { std::ifstream file("/proc/meminfo"); std::map meminfo; if (!file.is_open()) { SPDLOG_ERROR("can't open /proc/meminfo"); return; } for (std::string line; std::getline(file, line);) { auto key = line.substr(0, line.find(":")); auto val = line.substr(key.length() + 2); meminfo[key] = std::stoull(val) / 1024.f / 1024.f; } memmax = meminfo["MemTotal"]; memused = meminfo["MemTotal"] - meminfo["MemAvailable"]; swapused = meminfo["SwapTotal"] - meminfo["SwapFree"]; } void update_mem_temp() { static bool inited = false; static std::vector mem_temp_files; if (!inited) { inited = true; std::string path = "/sys/class/hwmon/"; auto dirs = ls(path.c_str(), "hwmon", LS_DIRS); for (auto &dir : dirs) { if (read_line(path + dir + "/name") == "spd5118") mem_temp_files.emplace_back(path + dir + "/temp1_input"); } if (mem_temp_files.empty()) SPDLOG_ERROR("failed to find known ram temp sensors"); } int temp = 0; for (auto &file : mem_temp_files) { int _temp; file.clear(); file.seekg(0); if ((file >> _temp) && _temp > temp) temp = _temp; } mem_temp = temp / 1000; } void update_procmem() { auto page_size = sysconf(_SC_PAGESIZE); if (page_size < 0) page_size = 4096; std::string f = "/proc/"; { auto gs_pid = HUDElements.g_gamescopePid; f += gs_pid < 1 ? "self" : std::to_string(gs_pid); f += "/statm"; } std::ifstream file(f); if (!file.is_open()) { SPDLOG_ERROR("can't open {}", f); return; } size_t last_idx = 0; std::string line; std::getline(file, line); if (line.empty()) return; std::array meminfo; for (auto i = 0; i < 3; i++) { auto idx = line.find(" ", last_idx); auto val = line.substr(last_idx, idx); meminfo[i] = std::stoull(val) * page_size; last_idx = idx + 1; } proc_mem_virt = meminfo[0]; proc_mem_resident = meminfo[1]; proc_mem_shared = meminfo[2]; } ================================================ FILE: src/memory.h ================================================ #pragma once #ifndef MANGOHUD_MEMORY_H #define MANGOHUD_MEMORY_H #include extern float memused, memmax, swapused; extern int mem_temp; extern uint64_t proc_mem_resident, proc_mem_shared, proc_mem_virt; void update_meminfo(); void update_mem_temp(); void update_procmem(); #endif //MANGOHUD_MEMORY_H ================================================ FILE: src/mesa/c11_compat.h ================================================ /* Copyright 2019 Intel Corporation */ /* SPDX-License-Identifier: MIT */ #include "no_extern_c.h" #ifndef _C11_COMPAT_H_ #define _C11_COMPAT_H_ #if defined(__cplusplus) /* This is C++ code, not C */ #elif (__STDC_VERSION__ >= 201112L) /* Already C11 */ #else /* * C11 static_assert() macro * assert.h only defines that name for C11 and above */ #ifndef static_assert #define static_assert _Static_assert #endif #endif /* !C++ && !C11 */ #endif /* _C11_COMPAT_H_ */ ================================================ FILE: src/mesa/c99_compat.h ================================================ /************************************************************************** * * Copyright 2007-2013 VMware, Inc. * All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sub license, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice (including the * next paragraph) shall be included in all copies or substantial portions * of the Software. * * 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 NON-INFRINGEMENT. * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS 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. * **************************************************************************/ #include "no_extern_c.h" #ifndef _C99_COMPAT_H_ #define _C99_COMPAT_H_ /* * MSVC hacks. */ #if defined(_MSC_VER) # if _MSC_VER < 1900 # error "Microsoft Visual Studio 2015 or higher required" # endif /* * Visual Studio will complain if we define the `inline` keyword, but * actually it only supports the keyword on C++. * * To avoid this the _ALLOW_KEYWORD_MACROS must be set. */ # if !defined(_ALLOW_KEYWORD_MACROS) # define _ALLOW_KEYWORD_MACROS # endif /* * XXX: MSVC has a `__restrict` keyword, but it also has a * `__declspec(restrict)` modifier, so it is impossible to define a * `restrict` macro without interfering with the latter. Furthermore the * MSVC standard library uses __declspec(restrict) under the _CRTRESTRICT * macro. For now resolve this issue by redefining _CRTRESTRICT, but going * forward we should probably should stop using restrict, especially * considering that our code does not obbey strict aliasing rules any way. */ # include # undef _CRTRESTRICT # define _CRTRESTRICT #endif /* * C99 inline keyword */ #ifndef inline # ifdef __cplusplus /* C++ supports inline keyword */ # elif defined(__GNUC__) # define inline __inline__ # elif defined(_MSC_VER) # define inline __inline # elif defined(__ICL) # define inline __inline # elif defined(__INTEL_COMPILER) /* Intel compiler supports inline keyword */ # elif defined(__WATCOMC__) && (__WATCOMC__ >= 1100) # define inline __inline # elif (__STDC_VERSION__ >= 199901L) /* C99 supports inline keyword */ # else # define inline # endif #endif /* * C99 restrict keyword * * See also: * - http://cellperformance.beyond3d.com/articles/2006/05/demystifying-the-restrict-keyword.html */ #ifndef restrict # if (__STDC_VERSION__ >= 199901L) && !defined(__cplusplus) /* C99 */ # elif defined(__GNUC__) # define restrict __restrict__ # elif defined(_MSC_VER) # define restrict __restrict # else # define restrict /* */ # endif #endif /* * C99 __func__ macro */ #ifndef __func__ # if (__STDC_VERSION__ >= 199901L) /* C99 */ # elif defined(__GNUC__) # define __func__ __FUNCTION__ # elif defined(_MSC_VER) # define __func__ __FUNCTION__ # else # define __func__ "" # endif #endif /* Simple test case for debugging */ #if 0 static inline const char * test_c99_compat_h(const void * restrict a, const void * restrict b) { return __func__; } #endif /* Fallback definitions, for scons which doesn't auto-detect these things. */ #ifdef HAVE_SCONS # ifndef _WIN32 # define HAVE_PTHREAD # define HAVE_POSIX_MEMALIGN # endif # ifdef __GNUC__ # if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 2) # error "GCC version 4.2 or higher required" # endif /* https://gcc.gnu.org/onlinedocs/gcc-4.2.4/gcc/Other-Builtins.html */ # define HAVE___BUILTIN_CLZ 1 # define HAVE___BUILTIN_CLZLL 1 # define HAVE___BUILTIN_CTZ 1 # define HAVE___BUILTIN_EXPECT 1 # define HAVE___BUILTIN_FFS 1 # define HAVE___BUILTIN_FFSLL 1 # define HAVE___BUILTIN_POPCOUNT 1 # define HAVE___BUILTIN_POPCOUNTLL 1 /* https://gcc.gnu.org/onlinedocs/gcc-4.2.4/gcc/Function-Attributes.html */ # define HAVE_FUNC_ATTRIBUTE_FLATTEN 1 # define HAVE_FUNC_ATTRIBUTE_UNUSED 1 # define HAVE_FUNC_ATTRIBUTE_FORMAT 1 # define HAVE_FUNC_ATTRIBUTE_PACKED 1 # define HAVE_FUNC_ATTRIBUTE_ALIAS 1 # define HAVE_FUNC_ATTRIBUTE_NORETURN 1 # if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3) /* https://gcc.gnu.org/onlinedocs/gcc-4.3.6/gcc/Other-Builtins.html */ # define HAVE___BUILTIN_BSWAP32 1 # define HAVE___BUILTIN_BSWAP64 1 # endif # if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5) # define HAVE___BUILTIN_UNREACHABLE 1 # endif # endif /* __GNUC__ */ #endif /* HAVE_SCONS */ #endif /* _C99_COMPAT_H_ */ ================================================ FILE: src/mesa/no_extern_c.h ================================================ /************************************************************************** * * Copyright 2014 VMware, Inc. * All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * 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 OR COPYRIGHT HOLDERS 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. * **************************************************************************/ /* * Including system's headers inside `extern "C" { ... }` is not safe, as system * headers may have C++ code in them, and C++ code inside extern "C" * leads to syntatically incorrect code. * * This is because putting code inside extern "C" won't make __cplusplus define * go away, that is, the system header being included thinks is free to use C++ * as it sees fits. * * Including non-system headers inside extern "C" is not safe either, because * non-system headers end up including system headers, hence fall in the above * case too. * * Conclusion, includes inside extern "C" is simply not portable. * * * This header helps surface these issues. */ #ifdef __cplusplus template class _IncludeInsideExternCNotPortable; #endif ================================================ FILE: src/mesa/util/detect_os.h ================================================ /* SPDX-License-Identifier: MIT */ /* Copyright 2008 VMware, Inc. */ /** * Auto-detect the operating system family. * * See also: * - http://gcc.gnu.org/onlinedocs/cpp/Common-Predefined-Macros.html * - echo | gcc -dM -E - | sort * - http://msdn.microsoft.com/en-us/library/b0084kay.aspx * * @author José Fonseca */ #ifndef DETECT_OS_H #define DETECT_OS_H #if defined(__linux__) #define DETECT_OS_LINUX 1 #define DETECT_OS_UNIX 1 #endif /* * Android defines __linux__, so DETECT_OS_LINUX and DETECT_OS_UNIX will * also be defined. */ #if defined(ANDROID) #define DETECT_OS_ANDROID 1 #endif #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) #define DETECT_OS_FREEBSD 1 #define DETECT_OS_BSD 1 #define DETECT_OS_UNIX 1 #endif #if defined(__OpenBSD__) #define DETECT_OS_OPENBSD 1 #define DETECT_OS_BSD 1 #define DETECT_OS_UNIX 1 #endif #if defined(__NetBSD__) #define DETECT_OS_NETBSD 1 #define DETECT_OS_BSD 1 #define DETECT_OS_UNIX 1 #endif #if defined(__DragonFly__) #define DETECT_OS_DRAGONFLY 1 #define DETECT_OS_BSD 1 #define DETECT_OS_UNIX 1 #endif #if defined(__GNU__) #define DETECT_OS_HURD 1 #define DETECT_OS_UNIX 1 #endif #if defined(__sun) #define DETECT_OS_SOLARIS 1 #define DETECT_OS_UNIX 1 #endif #if defined(__APPLE__) #define DETECT_OS_APPLE 1 #define DETECT_OS_UNIX 1 #endif #if defined(_WIN32) || defined(WIN32) #define DETECT_OS_WINDOWS 1 #endif #if defined(__HAIKU__) #define DETECT_OS_HAIKU 1 #define DETECT_OS_UNIX 1 #endif #if defined(__CYGWIN__) #define DETECT_OS_CYGWIN 1 #define DETECT_OS_UNIX 1 #endif /* * Make sure DETECT_OS_* are always defined, so that they can be used with #if */ #ifndef DETECT_OS_ANDROID #define DETECT_OS_ANDROID 0 #endif #ifndef DETECT_OS_APPLE #define DETECT_OS_APPLE 0 #endif #ifndef DETECT_OS_BSD #define DETECT_OS_BSD 0 #endif #ifndef DETECT_OS_CYGWIN #define DETECT_OS_CYGWIN 0 #endif #ifndef DETECT_OS_DRAGONFLY #define DETECT_OS_DRAGONFLY 0 #endif #ifndef DETECT_OS_FREEBSD #define DETECT_OS_FREEBSD 0 #endif #ifndef DETECT_OS_HAIKU #define DETECT_OS_HAIKU 0 #endif #ifndef DETECT_OS_HURD #define DETECT_OS_HURD 0 #endif #ifndef DETECT_OS_LINUX #define DETECT_OS_LINUX 0 #endif #ifndef DETECT_OS_NETBSD #define DETECT_OS_NETBSD 0 #endif #ifndef DETECT_OS_OPENBSD #define DETECT_OS_OPENBSD 0 #endif #ifndef DETECT_OS_SOLARIS #define DETECT_OS_SOLARIS 0 #endif #ifndef DETECT_OS_UNIX #define DETECT_OS_UNIX 0 #endif #ifndef DETECT_OS_WINDOWS #define DETECT_OS_WINDOWS 0 #endif #endif /* DETECT_OS_H */ ================================================ FILE: src/mesa/util/macros.h ================================================ // /* // * Copyright © 2014 Intel Corporation // * // * Permission is hereby granted, free of charge, to any person obtaining a // * copy of this software and associated documentation files (the "Software"), // * to deal in the Software without restriction, including without limitation // * the rights to use, copy, modify, merge, publish, distribute, sublicense, // * and/or sell copies of the Software, and to permit persons to whom the // * Software is furnished to do so, subject to the following conditions: // * // * The above copyright notice and this permission notice (including the next // * paragraph) shall be included in all copies or substantial portions of the // * Software. // * // * 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 OR COPYRIGHT HOLDERS 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. // */ #ifndef UTIL_MACROS_H #define UTIL_MACROS_H #include #include "../c99_compat.h" #include "../c11_compat.h" #if defined(__HAIKU__) && !defined(__cplusplus) #define static_assert _Static_assert #endif #include #include #include #include // /* Compute the size of an array */ #ifndef ARRAY_SIZE # define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) #endif #if defined(HAVE___BUILTIN_UNREACHABLE) || __has_builtin(__builtin_unreachable) #define UNREACHABLE(str) \ do { \ (void)"" str; /* str must be a string literal */ \ assert(!str); \ __builtin_unreachable(); \ } while (0) #elif defined (_MSC_VER) #define UNREACHABLE(str) \ do { \ (void)"" str; /* str must be a string literal */ \ assert(!str); \ __assume(0); \ } while (0) #else #define UNREACHABLE(str) \ do { \ (void)"" str; /* str must be a string literal */ \ assert(!str); \ } while (0) #endif #define PUBLIC __attribute__((visibility("default"))) #endif /* UTIL_MACROS_H */ ================================================ FILE: src/mesa/util/os_socket.c ================================================ /* * Copyright 2019 Intel Corporation * SPDX-License-Identifier: MIT */ #include #include "os_socket.h" #if defined(__linux__) #include #include #include #include #include #include #include int os_socket_listen_abstract(const char *path, int count) { int s = socket(AF_UNIX, SOCK_STREAM, 0); if (s < 0) return -1; struct sockaddr_un addr; memset(&addr, 0, sizeof(addr)); addr.sun_family = AF_UNIX; strncpy(addr.sun_path + 1, path, sizeof(addr.sun_path) - 2); /* Create an abstract socket */ int ret = bind(s, (struct sockaddr*)&addr, offsetof(struct sockaddr_un, sun_path) + strlen(path) + 1); if (ret < 0) return -1; listen(s, count); return s; } int os_socket_accept(int s) { return accept(s, NULL, NULL); } ssize_t os_socket_recv(int socket, void *buffer, size_t length, int flags) { return recv(socket, buffer, length, flags); } ssize_t os_socket_send(int socket, const void *buffer, size_t length, int flags) { return send(socket, buffer, length, flags); } void os_socket_block(int s, bool block) { int old = fcntl(s, F_GETFL, 0); if (old == -1) return; /* TODO obey block */ if (block) fcntl(s, F_SETFL, old & ~O_NONBLOCK); else fcntl(s, F_SETFL, old | O_NONBLOCK); } void os_socket_close(int s) { close(s); } #else int os_socket_listen_abstract(const char *path, int count) { errno = -ENOSYS; return -1; } int os_socket_accept(int s) { errno = -ENOSYS; return -1; } ssize_t os_socket_recv(int socket, void *buffer, size_t length, int flags) { errno = -ENOSYS; return -1; } ssize_t os_socket_send(int socket, const void *buffer, size_t length, int flags) { errno = -ENOSYS; return -1; } void os_socket_block(int s, bool block) { } void os_socket_close(int s) { } #endif ================================================ FILE: src/mesa/util/os_socket.h ================================================ /* * Copyright 2019 Intel Corporation * SPDX-License-Identifier: MIT * * Socket operations helpers */ #ifndef _OS_SOCKET_H_ #define _OS_SOCKET_H_ #include #include #ifdef _MSC_VER #include typedef SSIZE_T ssize_t; #endif #ifdef __cplusplus extern "C" { #endif int os_socket_accept(int s); int os_socket_listen_abstract(const char *path, int count); ssize_t os_socket_recv(int socket, void *buffer, size_t length, int flags); ssize_t os_socket_send(int socket, const void *buffer, size_t length, int flags); void os_socket_block(int s, bool block); void os_socket_close(int s); #ifdef __cplusplus } #endif #endif /* _OS_SOCKET_H_ */ ================================================ FILE: src/mesa/util/os_time.c ================================================ /************************************************************************** * * Copyright 2008-2010 VMware, Inc. * All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sub license, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice (including the * next paragraph) shall be included in all copies or substantial portions * of the Software. * * 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 NON-INFRINGEMENT. * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS 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. * **************************************************************************/ /** * @file * OS independent time-manipulation functions. * * @author Jose Fonseca */ #include "os_time.h" #include "detect_os.h" #if defined(USE_GCC_ATOMIC_BUILTINS) /* The builtins with explicit memory model are available since GCC 4.7. */ #define p_atomic_read(_v) __atomic_load_n((_v), __ATOMIC_ACQUIRE) #else #define p_atomic_read(_v) (*(_v)) #endif #if DETECT_OS_UNIX # include /* usleep */ # include /* timeval */ # include /* timeval */ # include /* sched_yield */ # include #elif DETECT_OS_WINDOWS # include #else # error Unsupported OS #endif #if defined(CLOCK_MONOTONIC_RAW) /* linux */ #define MANGOHUD_CLOCKTYPE CLOCK_MONOTONIC_RAW #elif defined(CLOCK_MONOTONIC_FAST) /* freebsd */ #define MANGOHUD_CLOCKTYPE CLOCK_MONOTONIC_FAST #else /* fallback */ #define MANGOHUD_CLOCKTYPE CLOCK_MONOTONIC #endif int64_t os_time_get_nano(void) { #if DETECT_OS_LINUX || DETECT_OS_BSD struct timespec tv; clock_gettime(MANGOHUD_CLOCKTYPE, &tv); return tv.tv_nsec + tv.tv_sec*INT64_C(1000000000); #elif DETECT_OS_UNIX struct timeval tv; gettimeofday(&tv, NULL); return tv.tv_usec*INT64_C(1000) + tv.tv_sec*INT64_C(1000000000); #elif DETECT_OS_WINDOWS static LARGE_INTEGER frequency; LARGE_INTEGER counter; int64_t secs, nanosecs; if(!frequency.QuadPart) QueryPerformanceFrequency(&frequency); QueryPerformanceCounter(&counter); /* Compute seconds and nanoseconds parts separately to * reduce severity of precision loss. */ secs = counter.QuadPart / frequency.QuadPart; nanosecs = (counter.QuadPart % frequency.QuadPart) * INT64_C(1000000000) / frequency.QuadPart; return secs*INT64_C(1000000000) + nanosecs; #else #error Unsupported OS #endif } void os_time_sleep(int64_t usecs) { #if DETECT_OS_LINUX struct timespec time; time.tv_sec = usecs / 1000000; time.tv_nsec = (usecs % 1000000) * 1000; while (clock_nanosleep(MANGOHUD_CLOCKTYPE, 0, &time, &time) == EINTR); #elif DETECT_OS_UNIX usleep(usecs); #elif DETECT_OS_WINDOWS DWORD dwMilliseconds = (DWORD) ((usecs + 999) / 1000); /* Avoid Sleep(O) as that would cause to sleep for an undetermined duration */ if (dwMilliseconds) { Sleep(dwMilliseconds); } #else # error Unsupported OS #endif } int64_t os_time_get_absolute_timeout(uint64_t timeout) { int64_t time, abs_timeout; /* Also check for the type upper bound. */ if (timeout == OS_TIMEOUT_INFINITE || timeout > INT64_MAX) return OS_TIMEOUT_INFINITE; time = os_time_get_nano(); abs_timeout = time + (int64_t)timeout; /* Check for overflow. */ if (abs_timeout < time) return OS_TIMEOUT_INFINITE; return abs_timeout; } bool os_wait_until_zero(volatile int *var, uint64_t timeout) { if (!p_atomic_read(var)) return true; if (!timeout) return false; if (timeout == OS_TIMEOUT_INFINITE) { while (p_atomic_read(var)) { #if DETECT_OS_UNIX sched_yield(); #endif } return true; } else { int64_t start_time = os_time_get_nano(); int64_t end_time = start_time + timeout; while (p_atomic_read(var)) { if (os_time_timeout(start_time, end_time, os_time_get_nano())) return false; #if DETECT_OS_UNIX sched_yield(); #endif } return true; } } bool os_wait_until_zero_abs_timeout(volatile int *var, int64_t timeout) { if (!p_atomic_read(var)) return true; if (timeout == (int64_t)OS_TIMEOUT_INFINITE) return os_wait_until_zero(var, OS_TIMEOUT_INFINITE); while (p_atomic_read(var)) { if (os_time_get_nano() >= timeout) return false; #if DETECT_OS_UNIX sched_yield(); #endif } return true; } ================================================ FILE: src/mesa/util/os_time.h ================================================ /************************************************************************** * * Copyright 2008-2010 VMware, Inc. * All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sub license, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice (including the * next paragraph) shall be included in all copies or substantial portions * of the Software. * * 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 NON-INFRINGEMENT. * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS 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. * **************************************************************************/ /** * @file * OS independent time-manipulation functions. * * @author Jose Fonseca */ #ifndef _OS_TIME_H_ #define _OS_TIME_H_ #include #include #ifdef __cplusplus extern "C" { #endif /* must be equal to PIPE_TIMEOUT_INFINITE */ #define OS_TIMEOUT_INFINITE 0xffffffffffffffffull /* * Get the current time in nanoseconds from an unknown base. */ int64_t os_time_get_nano(void); /* * Sleep. */ void os_time_sleep(int64_t usecs); /* * Helper function for detecting time outs, taking in account overflow. * * Returns true if the current time has elapsed beyond the specified interval. */ static inline bool os_time_timeout(int64_t start, int64_t end, int64_t curr) { if (start <= end) return !(start <= curr && curr < end); else return !((start <= curr) || (curr < end)); } /** * Convert a relative timeout in nanoseconds into an absolute timeout, * in other words, it returns current time + timeout. * os_time_get_nano() must be monotonic. * OS_TIMEOUT_INFINITE is passed through unchanged. If the calculation * overflows, OS_TIMEOUT_INFINITE is returned. */ int64_t os_time_get_absolute_timeout(uint64_t timeout); /** * Wait until the variable at the given memory location is zero. * * \param var variable * \param timeout timeout in ns, can be anything from 0 (no wait) to * OS_TIMEOUT_INFINITE (wait forever) * \return true if the variable is zero */ bool os_wait_until_zero(volatile int *var, uint64_t timeout); /** * Wait until the variable at the given memory location is zero. * The timeout is the absolute time when the waiting should stop. If it is * less than or equal to the current time, it only returns the status and * doesn't wait. OS_TIMEOUT_INFINITE waits forever. This requires that * os_time_get_nano is monotonic. * * \param var variable * \param timeout the time in ns when the waiting should stop * \return true if the variable is zero */ bool os_wait_until_zero_abs_timeout(volatile int *var, int64_t timeout); #ifdef __cplusplus } #endif #endif /* _OS_TIME_H_ */ ================================================ FILE: src/meson.build ================================================ glslang = find_program('glslang', 'glslangValidator') if get_option('dynamic_string_tokens') ld_prefix = get_option('prefix') + '/\$LIB/' else ld_prefix = join_paths(get_option('prefix') ,get_option('libdir')) + '/' endif # Needs prefix for configure_file() if get_option('append_libdir_mangohud') libdir_mangohud = join_paths(get_option('prefix'), get_option('libdir'), 'mangohud') ld_libdir_mangohud = ld_prefix + 'mangohud/' else libdir_mangohud = join_paths(get_option('prefix'), get_option('libdir')) ld_libdir_mangohud = ld_prefix endif git = find_program('git', required: false) if git.found() git_describe = run_command([git, 'describe', '--tags', '--dirty=+'], check: false) endif if git.found() and git_describe.returncode() == 0 describe_ver = git_describe.stdout().strip() else describe_ver = meson.project_version() endif conf_data = configuration_data() conf_data.set('ld_libdir_mangohud_abs', libdir_mangohud) conf_data.set('ld_libdir_mangohud', ld_libdir_mangohud) conf_data.set('cpu_family', host_machine.cpu_family()) conf_data.set('version', describe_ver) overlay_shaders = [ 'overlay.frag', 'overlay.vert', ] overlay_spv = [] foreach s : ['overlay.frag', 'overlay.vert'] overlay_spv += custom_target( s + '.spv.h', input : s, output : s + '.spv.h', command : [glslang, '-V', '-x', '-o', '@OUTPUT@', '@INPUT@']) endforeach util_files = files( 'mesa/util/os_socket.c', 'mesa/util/os_time.c', ) vklayer_files = files( 'hud_elements.cpp', 'overlay.cpp', 'overlay_params.cpp', 'font.cpp', 'keybinds.cpp', 'font_unispace.c', 'logging.cpp', 'config.cpp', 'gpu.cpp', 'blacklist.cpp', 'file_utils.cpp', 'nvidia.cpp', 'gpu_fdinfo.cpp', 'amdgpu.cpp' ) opengl_files = [] if ['windows', 'mingw'].contains(host_machine.system()) vklayer_files += files( 'file_utils_win32.cpp', 'cpu_win32.cpp', 'nvapi.cpp', 'win/dxgi.cpp', 'win/main.cpp', 'win/kiero.cpp', 'win/d3d12_hook.cpp', 'win/d3d11_hook.cpp', 'win/d3d_shared.cpp', ) endif if is_unixy vklayer_files += files( 'cpu.cpp', 'memory.cpp', 'iostats.cpp', 'notify.cpp', 'elfhacks.c', 'real_dlsym.c', 'pci_ids.cpp', 'battery.cpp', 'control.cpp', 'device.cpp', 'net.cpp', 'shell.cpp', 'ftrace.cpp', ) if get_option('with_fex') pre_args += '-DHAVE_FEX' vklayer_files += files( 'fex.cpp', ) endif opengl_files = files( 'gl/glad.c', 'gl/gl_renderer.cpp', 'gl/gl_hud.cpp', 'gl/inject_egl.cpp', ) nvml_h_found = get_option('with_nvml') == 'enabled' if get_option('with_nvml') == 'system' nvml_h_found = cc.has_header('nvml.h') if not nvml_h_found error('nvml.h was not found. Disable with \'-Dwith_nvml=disabled\' if gpu stats by NVML are not needed.') endif pre_args += '-DUSE_SYSTEM_NVML' endif if nvml_h_found pre_args += '-DHAVE_NVML' pre_args += '-DNVML_NO_UNVERSIONED_FUNC_DEFS' vklayer_files += files( 'loaders/loader_nvml.cpp', ) endif if get_option('with_xnvctrl').enabled() if not get_option('with_x11').enabled() error('XNVCtrl also needs \'with_x11\'') endif xnvctrl_h_found = cc.has_header('NVCtrl/NVCtrl.h') if not xnvctrl_h_found error('NVCtrl.h was not found. Disable with \'-Dwith_xnvctrl=disabled\' if gpu stats by XNVCtrl are not needed.') endif pre_args += '-DHAVE_XNVCTRL' vklayer_files += files( 'loaders/loader_nvctrl.cpp' ) endif if get_option('with_x11').enabled() pre_args += '-DHAVE_X11' vklayer_files += files( 'loaders/loader_x11.cpp', 'shared_x11.cpp', ) opengl_files += files( 'loaders/loader_glx.cpp', 'gl/inject_glx.cpp', ) endif if get_option('with_wayland').enabled() pre_args += '-DHAVE_WAYLAND' vklayer_files += files( 'wayland_keybinds.cpp' ) endif if dbus_dep.found() and get_option('with_dbus').enabled() pre_args += '-DHAVE_DBUS' vklayer_files += files( 'dbus.cpp', 'loaders/loader_dbus.cpp', ) endif endif link_args = cc.get_supported_link_arguments(['-Wl,-Bsymbolic-functions', '-Wl,-z,relro', '-Wl,--exclude-libs,ALL', '-lGL', '-static-libstdc++']) # meson fails to check version-script so just force add link_args += '-Wl,--version-script,@0@'.format(join_paths(meson.current_source_dir(), 'mangohud.version')) mangohud_static_lib = static_library( 'MangoHud', mangohud_version, files('vulkan.cpp'), util_files, vk_enum_to_str, vk_dispatch_table, vk_extensions, vklayer_files, overlay_spv, c_args : [ pre_args, vulkan_wsi_args ], cpp_args : [ pre_args, vulkan_wsi_args ], gnu_symbol_visibility : 'hidden', dependencies : [ mangohud_version_dep, vulkan_wsi_deps, dearimgui_dep, spdlog_dep, dbus_dep, dep_dl, dep_rt, dep_pthread, dep_vulkan_headers, dep_vulkan_utility_libraries, windows_deps, implot_dep], include_directories : [inc_common], link_args : link_args, install_dir : libdir_mangohud, install : false ) mangohud_shared_lib = shared_library( 'MangoHud', objects: mangohud_static_lib.extract_all_objects(), link_with: mangohud_static_lib, link_args : link_args, install_dir : libdir_mangohud, install: true ) mangohud_opengl_shared_lib = shared_library( 'MangoHud_opengl', mangohud_version, opengl_files, vklayer_files, util_files, c_args : [ pre_args, vulkan_wsi_args ], cpp_args : [ pre_args, vulkan_wsi_args ], dependencies : [ mangohud_version_dep, vulkan_wsi_deps, dearimgui_dep, spdlog_dep, dbus_dep, dep_dl, dep_rt, dep_pthread, dep_vulkan_headers, dep_vulkan_utility_libraries, windows_deps, implot_dep], include_directories : [inc_common], link_args : link_args, link_with: mangohud_static_lib, install_dir : libdir_mangohud, install: true ) if get_option('mangoapp') if not get_option('with_x11').enabled() error('mangoapp also needs \'with_x11\'') endif pre_args += '-DMANGOAPP' mangoapp = executable( 'mangoapp', files( 'app/main.cpp', ), c_args : [ pre_args, vulkan_wsi_args ], cpp_args : [ pre_args, vulkan_wsi_args ], gnu_symbol_visibility : 'hidden', dependencies : [ dearimgui_dep, dep_dl, dep_vulkan_headers, dep_vulkan_utility_libraries, spdlog_dep, dbus_dep, dep_x11, dep_wayland_client, glfw3_dep, implot_dep ], include_directories : [inc_common], install_tag : 'mangoapp', link_with: mangohud_static_lib, link_args : link_args, install : true ) endif if get_option('mangohudctl') mangoapp = executable( 'mangohudctl', files('app/control.c'), install_tag : 'mangoapp', #TODO MangoHud layer itself currently doesn't support it install : true ) endif if is_unixy mangohud_shim = shared_library( 'MangoHud_shim', files( 'gl/shim.c', 'real_dlsym.c', 'elfhacks.c' ), dependencies : [ dep_dl ], c_args : [ pre_args ], cpp_args : [ pre_args ], include_directories : [inc_common], install_dir : libdir_mangohud, install: true ) endif configure_file(input : 'mangohud.json.in', output : '@0@.@1@.json'.format(meson.project_name(), host_machine.cpu_family()), configuration : conf_data, install : true, install_dir : join_paths(get_option('datadir'), 'vulkan', 'implicit_layer.d'), install_tag : 'runtime', ) configure_file(input : '../bin/mangohud.in', output : 'mangohud', configuration : conf_data, install_dir : get_option('bindir'), install_tag : 'scripts', ) ================================================ FILE: src/net.cpp ================================================ #include "net.h" #include "hud_elements.h" Net::Net() { auto params = get_params(); should_reset = false; fs::path net_dir(NETDIR); if (fs::exists(net_dir) && fs::is_directory(net_dir)) { for (const auto& entry : fs::directory_iterator(net_dir)) { if (fs::is_directory(entry.status())) { auto val = entry.path().filename().string(); if (val == "lo") continue; if (!params->network.empty() && params->network.front() == "1") { interfaces.push_back({entry.path().filename().string(), 0, 0}); } else if (!params->network.empty()){ auto it = std::find(params->network.begin(), params->network.end(), val); if (it != params->network.end()) interfaces.push_back({entry.path().filename().string(), 0, 0}); } } } } if (interfaces.empty()) SPDLOG_ERROR("Network: couldn't find any interfaces"); } long long safe_stoll(const std::string& str, long long default_value); long long safe_stoll(const std::string& str, long long default_value = 0) { if (str.empty()) { SPDLOG_DEBUG("tx or rx returned an empty string"); return default_value; } try { return std::stoll(str); } catch (const std::invalid_argument& e) { SPDLOG_DEBUG("stoll invalid argument"); } catch (const std::out_of_range& e) { SPDLOG_DEBUG("stoll out of range"); } return default_value; } void Net::update() { if (!interfaces.empty()) { for (auto& iface : interfaces) { // path to tx_bytes and rx_bytes std::string txfile = (NETDIR + iface.name + TXFILE); std::string rxfile = (NETDIR + iface.name + RXFILE); // amount of bytes at previous update uint64_t prevTx = iface.txBytes; uint64_t prevRx = iface.rxBytes; // current amount of bytes iface.txBytes = safe_stoll(read_line(txfile)); iface.rxBytes = safe_stoll(read_line(rxfile)); auto now = std::chrono::steady_clock::now(); // calculate the bytes per second since last update iface.txBps = calculateThroughput(iface.txBytes, prevTx, iface.previousTime, now); iface.rxBps = calculateThroughput(iface.rxBytes, prevRx, iface.previousTime, now); iface.previousTime = now; } } } uint64_t Net::calculateThroughput(long long currentBytes, long long previousBytes, std::chrono::steady_clock::time_point previousTime, std::chrono::steady_clock::time_point currentTime) { std::chrono::duration elapsed = (currentTime - previousTime); return static_cast((currentBytes - previousBytes) / elapsed.count()); } ================================================ FILE: src/net.h ================================================ #pragma once #include #include #include #include "filesystem.h" #include "file_utils.h" #include #include namespace fs = ghc::filesystem; #ifndef NETDIR #define NETDIR "/sys/class/net/" #endif #ifndef TXFILE #define TXFILE "/statistics/tx_bytes" #endif #ifndef RXFILE #define RXFILE "/statistics/rx_bytes" #endif class Net { public: bool should_reset = false; struct networkInterface { std::string name; uint64_t txBytes; uint64_t rxBytes; uint64_t txBps; uint64_t rxBps; std::chrono::steady_clock::time_point previousTime; }; Net(); void update(); std::vector interfaces = {}; private: uint64_t calculateThroughput(long long currentBytes, long long previousBytes, std::chrono::steady_clock::time_point previousTime, std::chrono::steady_clock::time_point currentTime); }; extern std::unique_ptr net; ================================================ FILE: src/notify.cpp ================================================ #include #include #include #include #include #include #include "config.h" #include "notify.h" #define EVENT_SIZE ( sizeof (struct inotify_event) ) #define EVENT_BUF_LEN ( 1024 * ( EVENT_SIZE + 16 ) ) static void fileChanged(notify_thread *nt) { int length, i = 0; char buffer[EVENT_BUF_LEN]; overlay_params local_params = *nt->params; while (!nt->quit) { length = read( nt->fd, buffer, EVENT_BUF_LEN ); while (i < length) { struct inotify_event *event = (struct inotify_event *) &buffer[i]; i += EVENT_SIZE + event->len; if (event->mask & IN_MODIFY || event->mask & IN_DELETE_SELF) { // In the case of IN_DELETE_SELF, some editors may do a save-to-temp-file/delete-original/move-temp-file // so sleep a little to let file to be replaced std::this_thread::sleep_for(std::chrono::milliseconds(100)); parse_overlay_config(&local_params, getenv("MANGOHUD_CONFIG"), false); if ((event->mask & IN_DELETE_SELF) || (nt->params->config_file_path != local_params.config_file_path)) { SPDLOG_DEBUG("Watching config file: {}", local_params.config_file_path.c_str()); inotify_rm_watch(nt->fd, nt->wd); nt->wd = inotify_add_watch(nt->fd, local_params.config_file_path.c_str(), IN_MODIFY | IN_DELETE_SELF); } std::lock_guard lk(nt->mutex); *nt->params = local_params; } } i = 0; std::this_thread::sleep_for(std::chrono::milliseconds(100)); } } bool start_notifier(notify_thread& nt) { nt.fd = inotify_init1(IN_NONBLOCK); if (nt.fd < 0) { SPDLOG_ERROR("inotify_init1 failed: {}", strerror(errno)); return false; } nt.wd = inotify_add_watch(nt.fd, nt.params->config_file_path.c_str(), IN_MODIFY | IN_DELETE_SELF); if (nt.wd < 0) { close(nt.fd); nt.fd = -1; return false; } if (nt.thread.joinable()) nt.thread.join(); nt.thread = std::thread(fileChanged, &nt); return true; } void stop_notifier(notify_thread& nt) { if (nt.fd < 0) return; nt.quit = true; if (nt.thread.joinable()) nt.thread.join(); inotify_rm_watch(nt.fd, nt.wd); close(nt.fd); nt.fd = -1; } ================================================ FILE: src/notify.h ================================================ #pragma once #ifndef MANGOHUD_NOTIFY_H #define MANGOHUD_NOTIFY_H #include #include #include "overlay_params.h" struct notify_thread { int fd = -1, wd = -1; overlay_params *params = nullptr; bool quit = false; std::mutex mutex; std::thread thread; }; bool start_notifier(notify_thread& nt); void stop_notifier(notify_thread& nt); #endif //MANGOHUD_NOTIFY_H ================================================ FILE: src/nvapi.cpp ================================================ #include #include #include "gpu.h" // magic numbers, do not change them #define NVAPI_MAX_PHYSICAL_GPUS 64 #define NVAPI_MAX_USAGES_PER_GPU 34 // function pointer types typedef int *(*NvAPI_QueryInterface_t)(unsigned int offset); typedef int (*NvAPI_Initialize_t)(); typedef int (*NvAPI_EnumPhysicalGPUs_t)(int **handles, int *count); typedef int (*NvAPI_GPU_GetUsages_t)(int *handle, unsigned int *usages); NvAPI_QueryInterface_t NvAPI_QueryInterface = NULL; NvAPI_Initialize_t NvAPI_Initialize = NULL; NvAPI_EnumPhysicalGPUs_t NvAPI_EnumPhysicalGPUs = NULL; NvAPI_GPU_GetUsages_t NvAPI_GPU_GetUsages = NULL; HMODULE hmod; bool init_nvapi_bool; int *gpuHandles[NVAPI_MAX_PHYSICAL_GPUS] = { NULL }; int gpuCount = 0; unsigned int gpuUsages[NVAPI_MAX_USAGES_PER_GPU] = { 0 }; bool checkNVAPI(){ #if _WIN64 hmod = LoadLibraryA("nvapi64.dll"); #else hmod = LoadLibraryA("nvapi.dll"); #endif if (hmod == NULL) { printf("Failed to load nvapi.dll"); return false; } NvAPI_QueryInterface = (NvAPI_QueryInterface_t) GetProcAddress(hmod, "nvapi_QueryInterface"); NvAPI_Initialize = (NvAPI_Initialize_t) (*NvAPI_QueryInterface)(0x0150E828); NvAPI_EnumPhysicalGPUs = (NvAPI_EnumPhysicalGPUs_t) (*NvAPI_QueryInterface)(0xE5AC921F); NvAPI_GPU_GetUsages = (NvAPI_GPU_GetUsages_t) (*NvAPI_QueryInterface)(0x189A1FDF); if (NvAPI_Initialize == NULL || NvAPI_EnumPhysicalGPUs == NULL || NvAPI_EnumPhysicalGPUs == NULL || NvAPI_GPU_GetUsages == NULL) { std::cerr << "Couldn't get functions in nvapi.dll" << std::endl; return 2; } (*NvAPI_Initialize)(); int *gpuHandles[NVAPI_MAX_PHYSICAL_GPUS] = { NULL }; return true; } void nvapi_util() { if (!init_nvapi_bool){ init_nvapi_bool = checkNVAPI(); } gpuUsages[0] = (NVAPI_MAX_USAGES_PER_GPU * 4) | 0x10000; (*NvAPI_EnumPhysicalGPUs)(gpuHandles, &gpuCount); (*NvAPI_GPU_GetUsages)(gpuHandles[0], gpuUsages); // TODO: create a GPU class for nvapi // otherwise we can't display information // gpu_info.load = gpuUsages[3]; } ================================================ FILE: src/nvidia.cpp ================================================ #ifdef HAVE_NVML #include "nvml.h" #endif #include "hud_elements.h" #include "logging.h" #include "string_utils.h" #include #include #include "mesa/util/macros.h" #if defined(HAVE_XNVCTRL) && defined(HAVE_X11) void NVIDIA::parse_token(const std::string& token, std::unordered_map& options) { std::string param, value; size_t equal = token.find('='); if (equal == std::string::npos) return; value = token.substr(equal+1); param = token.substr(0, equal); trim(param); trim(value); if (!param.empty()) options[param] = value; } #endif NVIDIA::NVIDIA(const char* pciBusId) { #ifdef HAVE_NVML if (nvml && nvml->IsLoaded()) { nvmlReturn_t result = nvml->nvmlInit_v2(); if (NVML_SUCCESS != result) { SPDLOG_ERROR("Nvidia module initialization failed: {}", nvml->nvmlErrorString(result)); nvml_available = false; } else { nvml_available = true; // NVML initialized successfully if (pciBusId) { result = nvml->nvmlDeviceGetHandleByPciBusId_v2(pciBusId, &device); if (NVML_SUCCESS != result) { SPDLOG_ERROR("Getting device handle by PCI bus ID failed: {}", nvml->nvmlErrorString(result)); nvml_available = false; // Revert if getting device handle fails } } } } #endif #if defined(HAVE_XNVCTRL) && defined(HAVE_X11) if (!get_libx11()->IsLoaded()) SPDLOG_DEBUG("XNVCtrl: X11 not loaded"); if (!nvctrl || !nvctrl->IsLoaded()) { SPDLOG_DEBUG("XNVCtrl loader failed to load"); nvctrl_available = false; } else { nvctrl_available = find_nv_x11(display); } if (nvctrl && nvctrl_available) { nvctrl->XNVCTRLQueryTargetCount(display, NV_CTRL_TARGET_TYPE_COOLER, &num_coolers); } #endif if (nvml_available || nvctrl_available) { throttling = std::make_shared(0x10de); thread = std::thread(&NVIDIA::get_samples_and_copy, this); pthread_setname_np(thread.native_handle(), "mangohud-nvidia"); } else { SPDLOG_WARN("NVML and NVCTRL are unavailable. Unable to get NVIDIA info. User is on DFSG version of mangohud?"); } } #ifdef HAVE_NVML void NVIDIA::get_instant_metrics_nvml(struct gpu_metrics *metrics, struct overlay_params *params) { nvmlReturn_t response; if (nvml && nvml_available) { nvml_get_process_info(); struct nvmlUtilization_st nvml_utilization; response = nvml->nvmlDeviceGetUtilizationRates(device, &nvml_utilization); if (response == NVML_ERROR_NOT_SUPPORTED) { SPDLOG_ERROR("nvmlDeviceGetUtilizationRates failed, disabling nvml metrics"); nvml_available = false; return; } metrics->load = nvml_utilization.gpu; if (params->enabled[OVERLAY_PARAM_ENABLED_gpu_temp] || (logger && logger->is_active())) { unsigned int temp; nvml->nvmlDeviceGetTemperature(device, NVML_TEMPERATURE_GPU, &temp); metrics->temp = temp; } if (params->enabled[OVERLAY_PARAM_ENABLED_vram] || (logger && logger->is_active())) { struct nvmlMemory_st nvml_memory; nvml->nvmlDeviceGetMemoryInfo(device, &nvml_memory); metrics->memoryTotal = nvml_memory.total / (1024.f * 1024.f * 1024.f); metrics->sys_vram_used = nvml_memory.used / (1024.f * 1024.f * 1024.f); } if (params->enabled[OVERLAY_PARAM_ENABLED_proc_vram]) metrics->proc_vram_used = get_proc_vram() / (1024.f * 1024.f * 1024.f); if (params->enabled[OVERLAY_PARAM_ENABLED_gpu_core_clock] || (logger && logger->is_active())) { unsigned int core_clock; nvml->nvmlDeviceGetClockInfo(device, NVML_CLOCK_GRAPHICS, &core_clock); metrics->CoreClock = core_clock; } if (params->enabled[OVERLAY_PARAM_ENABLED_gpu_mem_clock] || (logger && logger->is_active())) { unsigned int memory_clock; nvml->nvmlDeviceGetClockInfo(device, NVML_CLOCK_MEM, &memory_clock); metrics->MemClock = memory_clock; } if (params->enabled[OVERLAY_PARAM_ENABLED_gpu_power] || (logger && logger->is_active())) { unsigned int power, limit; nvml->nvmlDeviceGetPowerUsage(device, &power); nvml->nvmlDeviceGetPowerManagementLimit(device, &limit); metrics->powerUsage = power / 1000; metrics->powerLimit = limit / 1000; } if (params->enabled[OVERLAY_PARAM_ENABLED_throttling_status]) { unsigned long long nvml_throttle_reasons; nvml->nvmlDeviceGetCurrentClocksThrottleReasons(device, &nvml_throttle_reasons); metrics->is_temp_throttled = (nvml_throttle_reasons & 0x0000000000000060LL) != 0; metrics->is_power_throttled = (nvml_throttle_reasons & 0x000000000000008CLL) != 0; metrics->is_other_throttled = (nvml_throttle_reasons & 0x0000000000000112LL) != 0; if (throttling) throttling->indep_throttle_status = nvml_throttle_reasons; } if (params->enabled[OVERLAY_PARAM_ENABLED_gpu_fan] || (logger && logger->is_active())){ unsigned int fan_speed; nvml->nvmlDeviceGetFanSpeed(device, &fan_speed); metrics->fan_speed = fan_speed; metrics->fan_rpm = false; } #ifdef HAVE_XNVCTRL if (nvctrl_available) { metrics->fan_rpm = true; metrics->fan_speed = NVIDIA::get_nvctrl_fan_speed(); } #endif } } #endif #if defined(HAVE_XNVCTRL) && defined(HAVE_X11) void NVIDIA::get_instant_metrics_xnvctrl(struct gpu_metrics *metrics) { std::unordered_map xnvctrl_params; std::string token; if (!display) nvctrl_available = false; if (nvctrl && nvctrl_available && !nvml_available) { int enums[] = { NV_CTRL_STRING_GPU_UTILIZATION, NV_CTRL_STRING_GPU_CURRENT_CLOCK_FREQS, 0 // keep null }; for (size_t i=0; enums[i]; i++) { char* str = get_attr_target_string(enums[i], NV_CTRL_TARGET_TYPE_GPU, 0); if (!str) continue; std::stringstream ss (str); while (std::getline(ss, token, ',')) { parse_token(token, xnvctrl_params); } free(str); } if (!try_stoi(metrics->load, xnvctrl_params["graphics"])) metrics->load = 0; if (!try_stoi(metrics->CoreClock, xnvctrl_params["nvclock"])) metrics->CoreClock = 0; if (!try_stoi(metrics->MemClock, xnvctrl_params["memclock"])) metrics->MemClock = 0; int64_t temp = 0; nvctrl->XNVCTRLQueryTargetAttribute64(display, NV_CTRL_TARGET_TYPE_GPU, 0, 0, NV_CTRL_GPU_CORE_TEMPERATURE, &temp); metrics->temp = temp; int64_t memtotal = 0; nvctrl->XNVCTRLQueryTargetAttribute64(display, NV_CTRL_TARGET_TYPE_GPU, 0, 0, NV_CTRL_TOTAL_DEDICATED_GPU_MEMORY, &memtotal); metrics->memoryTotal = static_cast(memtotal) / 1024.f; int64_t memused = 0; nvctrl->XNVCTRLQueryTargetAttribute64(display, NV_CTRL_TARGET_TYPE_GPU, 0, 0, NV_CTRL_USED_DEDICATED_GPU_MEMORY, &memused); metrics->sys_vram_used = static_cast(memused) / 1024.f; metrics->fan_speed = NVIDIA::get_nvctrl_fan_speed(); } } #endif void NVIDIA::get_samples_and_copy() { struct gpu_metrics metrics_buffer[METRICS_SAMPLE_COUNT] {}; auto logger_ref = logger; // inc ref count, to avoid destruction of logger. auto params = get_params(); auto params_p = params.get(); // avoid destruction while we are getting samples... while(!stop_thread) { #ifndef TEST_ONLY if (HUDElements.g_gamescopePid > 0 && HUDElements.g_gamescopePid != pid) { pid = HUDElements.g_gamescopePid; } #endif for (size_t cur_sample_id=0; cur_sample_id < METRICS_SAMPLE_COUNT; cur_sample_id++) { #ifdef HAVE_NVML if (nvml_available) NVIDIA::get_instant_metrics_nvml(&metrics_buffer[cur_sample_id], params_p); #endif #if defined(HAVE_XNVCTRL) && defined(HAVE_X11) if (nvctrl_available) NVIDIA::get_instant_metrics_xnvctrl(&metrics_buffer[cur_sample_id]); #endif usleep(METRICS_POLLING_PERIOD_MS * 1000); } if (stop_thread) break; std::unique_lock lock(metrics_mutex); cond_var.wait(lock, [this]() { return !paused || stop_thread; }); GPU_UPDATE_METRIC_AVERAGE(load); GPU_UPDATE_METRIC_AVERAGE_FLOAT(powerUsage); GPU_UPDATE_METRIC_MAX(powerLimit); GPU_UPDATE_METRIC_AVERAGE(CoreClock); GPU_UPDATE_METRIC_AVERAGE(MemClock); GPU_UPDATE_METRIC_AVERAGE(temp); GPU_UPDATE_METRIC_AVERAGE_FLOAT(memoryTotal); GPU_UPDATE_METRIC_AVERAGE_FLOAT(sys_vram_used); GPU_UPDATE_METRIC_AVERAGE_FLOAT(proc_vram_used); GPU_UPDATE_METRIC_MAX(is_power_throttled); GPU_UPDATE_METRIC_MAX(is_current_throttled); GPU_UPDATE_METRIC_MAX(is_temp_throttled); GPU_UPDATE_METRIC_MAX(is_other_throttled); GPU_UPDATE_METRIC_MAX(fan_speed); } } #if defined(HAVE_XNVCTRL) && defined(HAVE_X11) int64_t NVIDIA::get_nvctrl_fan_speed(){ int64_t fan_speed = 0; if (num_coolers >= 1) { nvctrl->XNVCTRLQueryTargetAttribute64(display, NV_CTRL_TARGET_TYPE_COOLER, 0, 0, NV_CTRL_THERMAL_COOLER_SPEED, &fan_speed); } metrics.fan_rpm = true; return fan_speed; } #endif #ifdef HAVE_XNVCTRL char* NVIDIA::get_attr_target_string(int attr, int target_type, int target_id) { char* c = nullptr; if (nvctrl && !nvctrl->XNVCTRLQueryTargetStringAttribute(NVIDIA::display, target_type, target_id, 0, attr, &c)) { SPDLOG_ERROR("Failed to query attribute '{}'", attr); } return c; } #endif #if defined(HAVE_XNVCTRL) && defined(HAVE_X11) bool NVIDIA::find_nv_x11(Display*& dpy) { const char *displayid = getenv("DISPLAY"); auto libx11 = get_libx11(); if (displayid) { Display *d = libx11->XOpenDisplay(displayid); if (d) { int s = libx11->XDefaultScreen(d); if (nvctrl && nvctrl->XNVCTRLIsNvScreen(d, s)) { dpy = d; SPDLOG_DEBUG("XNVCtrl is using display {}", displayid); return true; } libx11->XCloseDisplay(d); } } SPDLOG_DEBUG("XNVCtrl didn't find the correct display"); return false; } #endif ================================================ FILE: src/nvidia.h ================================================ #pragma once #include "gpu.h" #ifdef HAVE_NVML #include "loaders/loader_nvml.h" #endif #ifdef HAVE_XNVCTRL #include "loaders/loader_nvctrl.h" #include "loaders/loader_x11.h" #endif class NVIDIA { public: std::shared_ptr throttling; bool nvml_available = false; bool nvctrl_available = false; gpu_metrics copy_metrics() { std::lock_guard lock(metrics_mutex); return metrics; }; void get_samples_and_copy(); NVIDIA(const char* pciBusId); ~NVIDIA() { stop_thread = true; if (thread.joinable()) thread.join(); }; #ifdef HAVE_NVML void nvml_get_process_info() { if (!nvml_available || !nvml) return; unsigned int infoCount = 0; std::vector cur_process_info(infoCount); nvmlReturn_t ret = nvml->nvmlDeviceGetGraphicsRunningProcesses(device, &infoCount, cur_process_info.data()); if (ret != NVML_ERROR_INSUFFICIENT_SIZE) return; cur_process_info.resize(infoCount); ret = nvml->nvmlDeviceGetGraphicsRunningProcesses(device, &infoCount, cur_process_info.data()); if (ret != NVML_SUCCESS) return; process_info = cur_process_info; }; std::vector pids() { std::vector vec; for (const auto& proc : process_info) vec.push_back(static_cast (proc.pid)); return vec; }; float get_proc_vram() { for (const auto& proc : process_info) { if (static_cast(proc.pid) != pid) continue; return static_cast(proc.usedGpuMemory); } return 0.f; }; #endif void pause() { paused = true; cond_var.notify_one(); }; void resume() { paused = false; cond_var.notify_one(); } private: pid_t pid = getpid(); std::mutex metrics_mutex; gpu_metrics metrics; std::thread thread; std::condition_variable cond_var; std::atomic stop_thread{false}; std::atomic paused{false}; #ifdef HAVE_NVML nvmlDevice_t device; std::vector process_info = {}; void get_instant_metrics_nvml(struct gpu_metrics *metrics, struct overlay_params *params); std::shared_ptr nvml = get_libnvml_loader(); #endif #if defined(HAVE_XNVCTRL) && defined(HAVE_X11) Display* display; // std::unique_ptr> display; int num_coolers; int64_t get_nvctrl_fan_speed(); std::shared_ptr nvctrl = get_libnvctrl_loader(); void get_instant_metrics_xnvctrl(struct gpu_metrics *metrics); void parse_token(const std::string& token, std::unordered_map& options); bool find_nv_x11(Display*& dpy); char* get_attr_target_string(int attr, int target_type, int target_id); #endif }; ================================================ FILE: src/overlay.cpp ================================================ #include #include #include #include #include #include #include #include #include #include // #include #include "overlay.h" #include "cpu.h" #include "gpu.h" #include "hud_elements.h" #include "memory.h" #include "timing.hpp" #include "fcat.h" #include "mesa/util/macros.h" #include "battery.h" #include "device.h" #include "string_utils.h" #include "file_utils.h" #include "pci_ids.h" #include "iostats.h" #include "amdgpu.h" #include "fps_metrics.h" #include "net.h" #include "fex.h" #include "ftrace.h" #ifdef __linux__ #include #include #endif namespace fs = ghc::filesystem; using namespace std; string gpuString,wineVersion,wineProcess; uint32_t deviceID; bool gui_open = false; bool fcat_open = false; struct benchmark_stats benchmark; ImVec2 real_font_size; std::deque graph_data; overlay_params *_params {}; double min_frametime, max_frametime; bool gpu_metrics_exists = false; bool steam_focused = false; vector frametime_data(200,0.f); int fan_speed; fcatoverlay fcatstatus; std::string drm_dev; int current_preset; void init_spdlog() { if (spdlog::get("MANGOHUD")) return; spdlog::set_default_logger(spdlog::stderr_color_mt("MANGOHUD")); // Just to get the name in log if (getenv("MANGOHUD_USE_LOGFILE")) { try { // Not rotating when opening log as proton/wine create multiple (sub)processes auto log = std::make_shared (get_config_dir() + "/MangoHud/MangoHud.log", 10*1024*1024, 5, false); spdlog::get("MANGOHUD")->sinks().push_back(log); } catch (const spdlog::spdlog_ex &ex) { SPDLOG_ERROR("{}", ex.what()); } } #ifdef DEBUG spdlog::set_level(spdlog::level::level_enum::debug); #endif spdlog::cfg::load_env_levels(); // Use MANGOHUD_LOG_LEVEL to correspond to SPDLOG_LEVEL if (getenv("MANGOHUD_LOG_LEVEL")) { std::string log_level = getenv("MANGOHUD_LOG_LEVEL"); vector levels; levels = {"trace","debug","info","warning","error","critical","off"}; for (auto & element : levels) { transform(log_level.begin(), log_level.end(), log_level.begin(), ::tolower); if(log_level == element ) { spdlog::set_level(spdlog::level::from_str(log_level)); } } #ifndef DEBUG } else { std::string log_level = "info"; transform(log_level.begin(), log_level.end(), log_level.begin(), ::tolower); spdlog::set_level(spdlog::level::from_str(log_level)); #endif } } void update_hw_info(const struct overlay_params& params, uint32_t vendorID) { auto real_params = get_params(); if (real_params->enabled[OVERLAY_PARAM_ENABLED_fan]) update_fan(); if (real_params->enabled[OVERLAY_PARAM_ENABLED_cpu_stats] || logger->is_active()) { cpuStats.UpdateCPUData(); #ifdef __linux__ if (real_params->enabled[OVERLAY_PARAM_ENABLED_core_load] || real_params->enabled[OVERLAY_PARAM_ENABLED_cpu_mhz] || logger->is_active()) cpuStats.UpdateCoreMhz(); if (real_params->enabled[OVERLAY_PARAM_ENABLED_cpu_temp] || logger->is_active() || real_params->enabled[OVERLAY_PARAM_ENABLED_graphs]) cpuStats.UpdateCpuTemp(); if (real_params->enabled[OVERLAY_PARAM_ENABLED_cpu_power] || logger->is_active()) cpuStats.UpdateCpuPower(); #endif } if (real_params->enabled[OVERLAY_PARAM_ENABLED_gpu_stats] || logger->is_active()) { if (gpus) gpus->get_metrics(); } #ifdef __linux__ if (real_params->enabled[OVERLAY_PARAM_ENABLED_battery]) Battery_Stats.update(); if (!real_params->device_battery.empty()) { device_update(params); if (device_found) { device_info(); } } if (real_params->enabled[OVERLAY_PARAM_ENABLED_ram] || real_params->enabled[OVERLAY_PARAM_ENABLED_swap] || logger->is_active()) update_meminfo(); if (real_params->enabled[OVERLAY_PARAM_ENABLED_ram_temp]) update_mem_temp(); if (real_params->enabled[OVERLAY_PARAM_ENABLED_procmem]) update_procmem(); if (real_params->enabled[OVERLAY_PARAM_ENABLED_io_read] || real_params->enabled[OVERLAY_PARAM_ENABLED_io_write]) getIoStats(g_io_stats); #endif if (gpus && gpus->active_gpu()) { currentLogData.gpu_load = gpus->active_gpu()->metrics.load; currentLogData.gpu_temp = gpus->active_gpu()->metrics.temp; currentLogData.gpu_core_clock = gpus->active_gpu()->metrics.CoreClock; currentLogData.gpu_mem_clock = gpus->active_gpu()->metrics.MemClock; currentLogData.gpu_vram_used = gpus->active_gpu()->metrics.sys_vram_used; currentLogData.gpu_power = gpus->active_gpu()->metrics.powerUsage; } #ifdef __linux__ currentLogData.ram_used = memused; currentLogData.swap_used = swapused; currentLogData.process_rss = proc_mem_resident / float((2 << 29)); // GiB, consistent w/ other mem stats #endif currentLogData.cpu_load = cpuStats.GetCPUDataTotal().percent; currentLogData.cpu_temp = cpuStats.GetCPUDataTotal().temp; currentLogData.cpu_power = cpuStats.GetCPUDataTotal().power; currentLogData.cpu_mhz = cpuStats.GetCPUDataTotal().cpu_mhz; // Save data for graphs if (graph_data.size() >= kMaxGraphEntries) graph_data.pop_front(); graph_data.push_back(currentLogData); if (logger) logger->notify_data_valid(); HUDElements.update_exec(); } struct hw_info_updater { bool quit = false; std::thread thread {}; const struct overlay_params* params = nullptr; uint32_t vendorID; bool update_hw_info_thread = false; std::condition_variable cv_hwupdate; std::mutex m_cv_hwupdate, m_hw_updating; hw_info_updater() { thread = std::thread(&hw_info_updater::run, this); // Anything longer than this wouldn't fit in the 15 byte limit pthread_setname_np(thread.native_handle(), "mangohud-hwinfo"); } ~hw_info_updater() { quit = true; cv_hwupdate.notify_all(); if (thread.joinable()) thread.join(); } void update(const struct overlay_params* params_, uint32_t vendorID_) { std::unique_lock lk_hw_updating(m_hw_updating, std::try_to_lock); if (lk_hw_updating.owns_lock()) { params = params_; vendorID = vendorID_; update_hw_info_thread = true; cv_hwupdate.notify_all(); } } void run(){ while (!quit){ std::unique_lock lk_cv_hwupdate(m_cv_hwupdate); cv_hwupdate.wait(lk_cv_hwupdate, [&]{ return update_hw_info_thread || quit; }); if (quit) break; if (params) { std::unique_lock lk_hw_updating(m_hw_updating); update_hw_info(*params, vendorID); } update_hw_info_thread = false; } } }; static std::unique_ptr hw_update_thread; void stop_hw_updater() { if (hw_update_thread) hw_update_thread.reset(); } void update_hud_info_with_frametime(struct swapchain_stats& sw_stats, const struct overlay_params& params, uint32_t vendorID, uint64_t frametime_ns){ auto real_params = get_params(); uint32_t f_idx = sw_stats.n_frames % ARRAY_SIZE(sw_stats.frames_stats); uint64_t now = os_time_get_nano(); /* ns */ auto elapsed = now - sw_stats.last_fps_update; /* ns */ float frametime_ms = frametime_ns / 1000000.f; if (sw_stats.last_present_time) { sw_stats.frames_stats[f_idx].stats[OVERLAY_PLOTS_frame_timing] = frametime_ns; frametime_data.push_back(frametime_ms); frametime_data.erase(frametime_data.begin()); } #ifdef __linux__ if (gpus) gpus->update_throttling(); #endif #ifdef HAVE_FEX fex::update_fex_stats(); #endif #ifdef HAVE_FTRACE if (real_params->ftrace.enabled) { if (!FTrace::object) FTrace::object = std::make_unique(real_params->ftrace); FTrace::object->update(); } #endif frametime = frametime_ms; fps = double(1000 / frametime_ms); if (fpsmetrics) fpsmetrics->update(frametime_ms); if (elapsed >= real_params->fps_sampling_period) { if (!hw_update_thread) hw_update_thread = std::make_unique(); hw_update_thread->update(¶ms, vendorID); if (fpsmetrics) fpsmetrics->update_thread(); #ifdef __linux__ if (HUDElements.net) HUDElements.net->update(); #endif sw_stats.fps = 1000000000.0 * sw_stats.n_frames_since_update / elapsed; if (real_params->enabled[OVERLAY_PARAM_ENABLED_time]) { std::time_t t = std::time(nullptr); std::stringstream time; time << std::put_time(std::localtime(&t), real_params->time_format.c_str()); sw_stats.time = time.str(); } if (real_params->autostart_log && logger && !logger->autostart_init) { if ((std::chrono::steady_clock::now() - HUDElements.overlay_start) > std::chrono::seconds(real_params->autostart_log)){ logger->start_logging(); logger->autostart_init = true; } } sw_stats.n_frames_since_update = 0; sw_stats.last_fps_update = now; } auto min = std::min_element(frametime_data.begin(), frametime_data.end()); auto max = std::max_element(frametime_data.begin(), frametime_data.end()); min_frametime = min[0]; max_frametime = max[0]; // double min_time = UINT64_MAX, max_time = 0; // for (auto& stat : sw_stats.frames_stats ){ // min_time = MIN2(stat.stats[0], min_time); // max_time = MAX2(stat.stats[0], min_time); // } // min_frametime = min_time / sw_stats.time_dividor; // max_frametime = max_time / sw_stats.time_dividor; if (real_params->log_interval == 0){ logger->try_log(); } sw_stats.last_present_time = now; sw_stats.n_frames++; sw_stats.n_frames_since_update++; } void update_hud_info(struct swapchain_stats& sw_stats, const struct overlay_params& params, uint32_t vendorID){ uint64_t now = os_time_get_nano(); /* ns */ uint64_t frametime_ns = now - sw_stats.last_present_time; if (!get_params()->no_display || logger->is_active()) update_hud_info_with_frametime(sw_stats, params, vendorID, frametime_ns); } float get_time_stat(void *_data, int _idx) { struct swapchain_stats *data = (struct swapchain_stats *) _data; if ((ARRAY_SIZE(data->frames_stats) - _idx) > data->n_frames) return 0.0f; int idx = ARRAY_SIZE(data->frames_stats) + data->n_frames < ARRAY_SIZE(data->frames_stats) ? _idx - data->n_frames : _idx + data->n_frames; idx %= ARRAY_SIZE(data->frames_stats); /* Time stats are in us. */ return data->frames_stats[idx].stats[data->stat_selector] / data->time_dividor; } void overlay_new_frame(const struct overlay_params& params) { ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f); ImGui::PushStyleVar(ImGuiStyleVar_WindowMinSize, ImVec2(4,4)); ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(8,-3)); ImGui::PushStyleVar(ImGuiStyleVar_Alpha, params.alpha); if (!params.enabled[OVERLAY_PARAM_ENABLED_hud_compact]){ ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(5,5)); } else { ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0,0)); } } void overlay_end_frame() { ImGui::PopStyleVar(5); } void position_layer(struct swapchain_stats& data, const struct overlay_params& params, const ImVec2& window_size) { auto real_params = get_params(); unsigned width = ImGui::GetIO().DisplaySize.x; unsigned height = ImGui::GetIO().DisplaySize.y; float margin = 10.0f; if (real_params->offset_x > 0 || real_params->offset_y > 0 || real_params->enabled[OVERLAY_PARAM_ENABLED_hud_no_margin]) margin = 0.0f; ImGui::SetNextWindowBgAlpha(real_params->background_alpha); ImGui::SetNextWindowSize(window_size, ImGuiCond_Always); switch (real_params->position) { case LAYER_POSITION_TOP_LEFT: data.main_window_pos = ImVec2(margin + real_params->offset_x, margin + real_params->offset_y); ImGui::SetNextWindowPos(data.main_window_pos, ImGuiCond_Always); break; case LAYER_POSITION_TOP_RIGHT: data.main_window_pos = ImVec2(width - window_size.x - margin + real_params->offset_x, margin + real_params->offset_y); ImGui::SetNextWindowPos(data.main_window_pos, ImGuiCond_Always); break; case LAYER_POSITION_MIDDLE_LEFT: data.main_window_pos = ImVec2(margin + params.offset_x, height / 2 - window_size.y / 2 - margin + real_params->offset_y); ImGui::SetNextWindowPos(data.main_window_pos, ImGuiCond_Always); break; case LAYER_POSITION_MIDDLE_RIGHT: data.main_window_pos = ImVec2(width - window_size.x - margin + real_params->offset_x, height / 2 - window_size.y / 2 - margin + real_params->offset_y); ImGui::SetNextWindowPos(data.main_window_pos, ImGuiCond_Always); break; case LAYER_POSITION_BOTTOM_LEFT: data.main_window_pos = ImVec2(margin +real_params->offset_x, height - window_size.y - margin + real_params->offset_y); ImGui::SetNextWindowPos(data.main_window_pos, ImGuiCond_Always); break; case LAYER_POSITION_BOTTOM_RIGHT: data.main_window_pos = ImVec2(width - window_size.x - margin + real_params->offset_x, height - window_size.y - margin + real_params->offset_y); ImGui::SetNextWindowPos(data.main_window_pos, ImGuiCond_Always); break; case LAYER_POSITION_TOP_CENTER: if (real_params->enabled[OVERLAY_PARAM_ENABLED_horizontal] && !real_params->enabled[OVERLAY_PARAM_ENABLED_horizontal_stretch]) { float content_width = ( real_params->table_columns * 64); data.main_window_pos = ImVec2((width / 2) - (window_size.x / 2) - content_width, margin + real_params->offset_y); } else data.main_window_pos = ImVec2((width / 2) - (window_size.x / 2), margin + real_params->offset_y); ImGui::SetNextWindowPos(data.main_window_pos, ImGuiCond_Always); break; case LAYER_POSITION_BOTTOM_CENTER: if (real_params->enabled[OVERLAY_PARAM_ENABLED_horizontal] && !real_params->enabled[OVERLAY_PARAM_ENABLED_horizontal_stretch]) { float content_width = (real_params->table_columns * 64); data.main_window_pos = ImVec2((width / 2) - (window_size.x / 2) - content_width, height - window_size.y - margin + real_params->offset_y); } else data.main_window_pos = ImVec2((width / 2) - (window_size.x / 2), height - window_size.y - margin + real_params->offset_y); ImGui::SetNextWindowPos(data.main_window_pos, ImGuiCond_Always); break; case LAYER_POSITION_COUNT: break; } } void RenderOutlinedText(const char* text, ImU32 textColor) { ImGuiWindow* window = ImGui::GetCurrentWindow(); ImGuiContext& g = *GImGui; const ImGuiStyle& style = g.Style; float outlineThickness = HUDElements.params->text_outline_thickness; ImVec2 textSize = ImGui::CalcTextSize(text); ImU32 outlineColor = ImGui::ColorConvertFloat4ToU32(HUDElements.colors.text_outline); ImVec2 pos = window->DC.CursorPos; ImDrawList* drawList = ImGui::GetWindowDrawList(); if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_text_outline] && outlineThickness > 0.0f) { drawList->AddText(ImGui::GetFont(), ImGui::GetFontSize(), ImVec2(pos.x - outlineThickness, pos.y), outlineColor, text); drawList->AddText(ImGui::GetFont(), ImGui::GetFontSize(), ImVec2(pos.x + outlineThickness, pos.y), outlineColor, text); drawList->AddText(ImGui::GetFont(), ImGui::GetFontSize(), ImVec2(pos.x, pos.y - outlineThickness), outlineColor, text); drawList->AddText(ImGui::GetFont(), ImGui::GetFontSize(), ImVec2(pos.x, pos.y + outlineThickness), outlineColor, text); } drawList->AddText(ImGui::GetFont(), ImGui::GetFontSize(), pos, textColor, text); ImGui::ItemSize(textSize, style.FramePadding.y); } void right_aligned_text(ImVec4& col, float off_x, const char *fmt, ...) { ImVec2 pos = ImGui::GetCursorPos(); char buffer[32] {}; va_list args; va_start(args, fmt); vsnprintf(buffer, sizeof(buffer), fmt, args); va_end(args); if (!HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_hud_compact]){ ImVec2 sz = ImGui::CalcTextSize(buffer); ImGui::SetCursorPosX(pos.x + off_x - sz.x); } RenderOutlinedText(buffer, ImGui::ColorConvertFloat4ToU32(col)); // ImGui::TextColored(col,"%s", buffer); } void center_text(const std::string& text) { ImGui::SetCursorPosX((ImGui::GetWindowSize().x / 2 )- (ImGui::CalcTextSize(text.c_str()).x / 2)); } #ifdef HAVE_DBUS static float get_ticker_limited_pos(float pos, float tw, float& left_limit, float& right_limit) { //float cw = ImGui::GetContentRegionAvailWidth() * 3; // only table cell worth of width float cw = ImGui::GetWindowContentRegionMax().x - ImGui::GetStyle().WindowPadding.x; float new_pos_x = ImGui::GetCursorPosX(); left_limit = cw - tw + new_pos_x; right_limit = new_pos_x; if (cw < tw) { new_pos_x += pos; // acts as a delay before it starts scrolling again if (new_pos_x < left_limit) return left_limit; else if (new_pos_x > right_limit) return right_limit; else return new_pos_x; } return new_pos_x; } void render_mpris_metadata(const struct overlay_params& params, mutexed_metadata& meta, uint64_t frame_timing) { static const float overflow = 50.f /* 3333ms * 0.5 / 16.6667 / 2 (to edge and back) */; if (meta.meta.valid) { auto color = ImGui::ColorConvertU32ToFloat4(params.media_player_color); ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(8,0)); if (!params.enabled[OVERLAY_PARAM_ENABLED_horizontal]) { ImGui::Dummy(ImVec2(0.0f, 20.0f)); } if (meta.ticker.needs_recalc) { meta.ticker.formatted.clear(); meta.ticker.longest = 0; for (const auto& f : params.media_player_format) { std::string str; try { str = fmt::format(f, fmt::arg("artist", meta.meta.artists), fmt::arg("title", meta.meta.title), fmt::arg("album", meta.meta.album)); } catch (const fmt::format_error& err) { SPDLOG_ERROR("formatting error in '{}': {}", f, err.what()); } float w = ImGui::CalcTextSize(str.c_str()).x; meta.ticker.longest = std::max(meta.ticker.longest, w); meta.ticker.formatted.push_back({str, w}); } meta.ticker.needs_recalc = false; } float new_pos, left_limit = 0, right_limit = 0; get_ticker_limited_pos(meta.ticker.pos, meta.ticker.longest, left_limit, right_limit); if (meta.ticker.pos < left_limit - overflow * .5f) { meta.ticker.dir = -1; meta.ticker.pos = (left_limit - overflow * .5f) + 1.f /* random */; } else if (meta.ticker.pos > right_limit + overflow) { meta.ticker.dir = 1; meta.ticker.pos = (right_limit + overflow) - 1.f /* random */; } meta.ticker.pos -= .5f * (frame_timing / 16666666.7f /* ns */) * meta.ticker.dir; for (const auto& fmt : meta.ticker.formatted) { if (fmt.text.empty()) continue; new_pos = get_ticker_limited_pos(meta.ticker.pos, fmt.width, left_limit, right_limit); ImGui::SetCursorPosX(new_pos); HUDElements.TextColored(color, "%s", fmt.text.c_str()); } ImGui::PopStyleVar(); } } #endif static void render_benchmark(swapchain_stats& data, const struct overlay_params& params, const ImVec2& window_size, unsigned height, Clock::time_point now){ // TODO, FIX LOG_DURATION FOR BENCHMARK int benchHeight = (2 + benchmark.percentile_data.size()) * real_font_size.x + 10.0f + 58; ImGui::SetNextWindowSize(ImVec2(window_size.x, benchHeight), ImGuiCond_Always); if (height - (window_size.y + data.main_window_pos.y + 5) < benchHeight) ImGui::SetNextWindowPos(ImVec2(data.main_window_pos.x, data.main_window_pos.y - benchHeight - 5), ImGuiCond_Always); else ImGui::SetNextWindowPos(ImVec2(data.main_window_pos.x, data.main_window_pos.y + window_size.y + 5), ImGuiCond_Always); #ifdef MANGOAPP ImGui::SetNextWindowPos(ImVec2(data.main_window_pos.x, data.main_window_pos.y + window_size.y + 5), ImGuiCond_Always); #endif float display_time = std::chrono::duration(now - logger->last_log_end()).count(); static float display_for = 10.0f; float alpha; if (params.background_alpha != 0){ if (display_for >= display_time){ alpha = display_time * params.background_alpha; if (alpha >= params.background_alpha){ ImGui::SetNextWindowBgAlpha(params.background_alpha); }else{ ImGui::SetNextWindowBgAlpha(alpha); } } else { alpha = 6.0 - display_time * params.background_alpha; if (alpha >= params.background_alpha){ ImGui::SetNextWindowBgAlpha(params.background_alpha); }else{ ImGui::SetNextWindowBgAlpha(alpha); } } } else { if (display_for >= display_time){ alpha = display_time * 0.0001; ImGui::SetNextWindowBgAlpha(params.background_alpha); } else { alpha = 6.0 - display_time * 0.0001; ImGui::SetNextWindowBgAlpha(params.background_alpha); } } ImGui::Begin("Benchmark", &gui_open, ImGuiWindowFlags_NoDecoration); static const char* finished = "Logging Finished"; ImGui::SetCursorPosX((ImGui::GetWindowSize().x / 2 )- (ImGui::CalcTextSize(finished).x / 2)); ImGui::TextColored(ImVec4(1.0, 1.0, 1.0, alpha / params.background_alpha), "%s", finished); ImGui::Dummy(ImVec2(0.0f, 8.0f)); char duration[20]; snprintf(duration, sizeof(duration), "Duration: %.1fs", std::chrono::duration(logger->last_log_end() - logger->last_log_begin()).count()); ImGui::SetCursorPosX((ImGui::GetWindowSize().x / 2 )- (ImGui::CalcTextSize(duration).x / 2)); ImGui::TextColored(ImVec4(1.0, 1.0, 1.0, alpha / params.background_alpha), "%s", duration); for (auto& data_ : benchmark.percentile_data){ char buffer[20]; snprintf(buffer, sizeof(buffer), "%s %.1f", data_.first.c_str(), data_.second); ImGui::SetCursorPosX((ImGui::GetWindowSize().x / 2 )- (ImGui::CalcTextSize(buffer).x / 2)); ImGui::TextColored(ImVec4(1.0, 1.0, 1.0, alpha / params.background_alpha), "%s %.1f", data_.first.c_str(), data_.second); } float max = benchmark.fps_data.empty() ? 0.0f : *max_element(benchmark.fps_data.begin(), benchmark.fps_data.end()); ImVec4 plotColor = HUDElements.colors.frametime; plotColor.w = alpha / params.background_alpha; ImGui::PushStyleColor(ImGuiCol_PlotLines, plotColor); ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(0.0, 0.0, 0.0, alpha / params.background_alpha)); ImGui::Dummy(ImVec2(0.0f, 8.0f)); if (params.enabled[OVERLAY_PARAM_ENABLED_histogram]) ImGui::PlotHistogram("##plot_histogram", benchmark.fps_data.data(), benchmark.fps_data.size(), 0, "", 0.0f, max + 10, ImVec2(ImGui::GetContentRegionAvail().x, 50)); else ImGui::PlotLines("##plot_lines", benchmark.fps_data.data(), benchmark.fps_data.size(), 0, "", 0.0f, max + 10, ImVec2(ImGui::GetContentRegionAvail().x, 50)); ImGui::PopStyleColor(2); ImGui::End(); } ImVec4 change_on_load_temp(LOAD_DATA& data, unsigned current) { if (current >= data.high_load){ return data.color_high; } else if (current >= data.med_load){ float diff = float(current - data.med_load) / float(data.high_load - data.med_load); float x = (data.color_high.x - data.color_med.x) * diff; float y = (data.color_high.y - data.color_med.y) * diff; float z = (data.color_high.z - data.color_med.z) * diff; return ImVec4(data.color_med.x + x, data.color_med.y + y, data.color_med.z + z, HUDElements.params->alpha); } else { float diff = float(current) / float(data.med_load); float x = (data.color_med.x - data.color_low.x) * diff; float y = (data.color_med.y - data.color_low.y) * diff; float z = (data.color_med.z - data.color_low.z) * diff; return ImVec4(data.color_low.x + x, data.color_low.y + y, data.color_low.z + z, HUDElements.params->alpha); } } void horizontal_separator(struct overlay_params& params) { ImGui::SameLine(); ImGui::Spacing(); ImGui::SameLine(); ImDrawList* drawList = ImGui::GetWindowDrawList(); ImVec2 cursorPos = ImGui::GetCursorScreenPos(); ImVec2 startPos(cursorPos.x - 5, cursorPos.y + 2); ImVec2 endPos(startPos.x, cursorPos.y + params.font_size * 0.85); float outlineThickness = 1.0f; if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_text_outline]){ // Draw the black outline drawList->AddLine(ImVec2(startPos.x - outlineThickness, startPos.y), ImVec2(startPos.x - outlineThickness, endPos.y), IM_COL32_BLACK, outlineThickness + 2); drawList->AddLine(ImVec2(startPos.x + outlineThickness, startPos.y), ImVec2(startPos.x + outlineThickness, endPos.y), IM_COL32_BLACK, outlineThickness + 2); drawList->AddLine(ImVec2(startPos.x - outlineThickness, startPos.y - outlineThickness/2), ImVec2(startPos.x + outlineThickness, startPos.y - outlineThickness/2), IM_COL32_BLACK, outlineThickness + 2); drawList->AddLine(ImVec2(startPos.x - outlineThickness, endPos.y + outlineThickness/2), ImVec2(startPos.x + outlineThickness, endPos.y + outlineThickness/2), IM_COL32_BLACK, outlineThickness + 2); } else { outlineThickness *= 2; } // Draw the separator line ImU32 separator_color = ImGui::ColorConvertFloat4ToU32(HUDElements.colors.horizontal_separator); drawList->AddLine(startPos, endPos, separator_color, outlineThickness); ImGui::SameLine(); ImGui::Spacing(); } void render_imgui(swapchain_stats& data, struct overlay_params& params, ImVec2& window_size, bool is_vulkan) { { std::unique_lock lock(config_mtx); config_cv.wait(lock, []{ return config_ready; }); } // data.engine = EngineTypes::GAMESCOPE; HUDElements.sw_stats = &data; auto real_params = get_params(); if (real_params) HUDElements.params = real_params; HUDElements.is_vulkan = is_vulkan; ImGui::GetIO().FontGlobalScale = real_params->font_scale; static float ralign_width = 0, old_scale = 0; auto io = ImGui::GetIO(); if (real_params->enabled[OVERLAY_PARAM_ENABLED_fps_only]){ window_size = ImVec2((to_string(int(HUDElements.sw_stats->fps)).length() * ImGui::CalcTextSize("A").x) + 15.f, get_params()->height); } else if (real_params->enabled[OVERLAY_PARAM_ENABLED_horizontal]) { window_size = ImVec2(io.DisplaySize.x, real_params->height); } else { window_size = ImVec2(real_params->width, real_params->height); } unsigned height = io.DisplaySize.y; auto now = Clock::now(); if (old_scale != real_params->font_scale) { HUDElements.ralign_width = ralign_width = ImGui::CalcTextSize("A").x * 4 /* characters */; old_scale = real_params->font_scale; } ImGuiTableFlags table_flags = ImGuiTableFlags_NoClip; if(real_params->enabled[OVERLAY_PARAM_ENABLED_horizontal]) table_flags = ImGuiTableFlags_NoClip | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_NoHostExtendX; if (!real_params->no_display && !steam_focused && get_params()->table_columns){ ImGui::Begin("Main", &gui_open, ImGuiWindowFlags_NoDecoration); if (ImGui::BeginTable("hud", real_params->table_columns, table_flags )) { HUDElements.place = 0; for (auto& func : HUDElements.ordered_functions){ if(!real_params->enabled[OVERLAY_PARAM_ENABLED_horizontal] && func.name != "exec") ImGui::TableNextRow(); func.run(); HUDElements.place += 1; if(!HUDElements.ordered_functions.empty() && real_params->enabled[OVERLAY_PARAM_ENABLED_horizontal] && HUDElements.ordered_functions.size() != (size_t)HUDElements.place) horizontal_separator(params); } if (real_params->enabled[OVERLAY_PARAM_ENABLED_horizontal]) { if (HUDElements.table_columns_count > 0 && HUDElements.table_columns_count < 65 ) real_params->table_columns = HUDElements.table_columns_count; if(!real_params->enabled[OVERLAY_PARAM_ENABLED_horizontal_stretch]) { float content_width = ImGui::GetContentRegionAvail().x - (real_params->table_columns * 64); window_size = ImVec2(content_width, real_params->height); } } ImGui::EndTable(); HUDElements.table_columns_count = 0; } if(logger->is_active()) ImGui::GetWindowDrawList()->AddCircleFilled(ImVec2(data.main_window_pos.x + window_size.x - 15, data.main_window_pos.y + 15), 10, real_params->engine_color, 20); window_size = ImVec2(window_size.x, ImGui::GetCursorPosY() + 11.0f); ImGui::End(); if((now - logger->last_log_end()) < 12s && !logger->is_active()) render_benchmark(data, params, window_size, height, now); } if(real_params->enabled[OVERLAY_PARAM_ENABLED_fcat]) { fcatstatus.update(¶ms); auto window_corners = fcatstatus.get_overlay_corners(); auto p_min=window_corners[0]; auto p_max=window_corners[1]; auto window_size= window_corners[2]; ImGui::SetNextWindowPos(p_min, ImGuiCond_Always); ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0,0)); ImGui::SetNextWindowSize(window_size); ImGui::Begin("FCAT", &fcat_open, ImGuiWindowFlags_NoDecoration| ImGuiWindowFlags_NoBackground); ImGui::GetWindowDrawList()->AddRectFilled(p_min,p_max,fcatstatus.get_next_color(data),0.0); ImGui::End(); ImGui::PopStyleVar(); } } void init_cpu_stats(overlay_params& params) { #ifdef __linux__ auto& enabled = params.enabled; enabled[OVERLAY_PARAM_ENABLED_cpu_stats] = cpuStats.Init() && enabled[OVERLAY_PARAM_ENABLED_cpu_stats]; enabled[OVERLAY_PARAM_ENABLED_cpu_temp] = cpuStats.GetCpuFile() && enabled[OVERLAY_PARAM_ENABLED_cpu_temp]; #endif } struct pci_bus { int domain; int bus; int slot; int func; }; void init_system_info(){ #ifdef __linux__ const char* ld_preload = getenv("LD_PRELOAD"); if (ld_preload) unsetenv("LD_PRELOAD"); ram = exec("sed -n 's/^MemTotal: *\\([0-9]*\\).*/\\1/p' /proc/meminfo"); trim(ram); cpu = exec("sed -n 's/^model name.*: \\(.*\\)/\\1/p' /proc/cpuinfo | sed 's/([^)]*)//g' | tail -n1"); trim(cpu); kernel = exec("uname -r"); trim(kernel); os = exec("sed -n 's/PRETTY_NAME=\\(.*\\)/\\1/p' /etc/os-release"); os.erase(remove(os.begin(), os.end(), '\"' ), os.end()); trim(os); cpusched = read_line("/sys/devices/system/cpu/cpu0/cpufreq/scaling_governor"); const char* mangohud_recursion = getenv("MANGOHUD_RECURSION"); if (!mangohud_recursion) { setenv("MANGOHUD_RECURSION", "1", 1); // driver = exec("glxinfo -B | sed -n 's/^OpenGL version.*: \\(.*\\)/\\1/p' | sed 's/([^)]*)//g;s/ / /g'"); // trim(driver); unsetenv("MANGOHUD_RECURSION"); } else { driver = "MangoHud glxinfo recursion detected"; } // Get WINE version wineProcess = get_exe_path(); auto n = wineProcess.find_last_of('/'); string preloader = wineProcess.substr(n + 1); if (preloader == "wine-preloader" || preloader == "wine64-preloader") { // Check if using Proton if (wineProcess.find("/dist/bin/wine") != std::string::npos || wineProcess.find("/files/bin/wine") != std::string::npos || wineProcess.find("/dist/bin-wow64/wine") != std::string::npos || wineProcess.find("/files/bin-wow64/wine") != std::string::npos) { stringstream ss; ss << dirname((char*)wineProcess.c_str()) << "/../../version"; string protonVersion = ss.str(); ss.str(""); ss.clear(); ss << read_line(protonVersion); std::getline(ss, wineVersion, ' '); // skip first number string std::getline(ss, wineVersion, ' '); trim(wineVersion); string toReplace = "proton-"; size_t pos = wineVersion.find(toReplace); if (pos != std::string::npos) { // If found replace wineVersion.replace(pos, toReplace.length(), "Proton "); } else { // If not found insert for non official proton builds wineVersion.insert(0, "Proton "); } } else { char *dir = dirname((char*)wineProcess.c_str()); stringstream findVersion; if (preloader == "wine-preloader") findVersion << "\"" << dir << "/wine\" --version"; else findVersion << "\"" << dir << "/wine64\" --version"; const char *wine_env = getenv("WINELOADERNOEXEC"); if (wine_env) unsetenv("WINELOADERNOEXEC"); wineVersion = exec(findVersion.str()); trim(wineVersion); SPDLOG_DEBUG("WINE version: {}", wineVersion); if (wine_env) setenv("WINELOADERNOEXEC", wine_env, 1); } } else { wineVersion = ""; } check_for_vkbasalt_and_gamemode(); if (ld_preload) setenv("LD_PRELOAD", ld_preload, 1); SPDLOG_DEBUG("Ram:{}", ram); SPDLOG_DEBUG("Cpu:{}", cpu); SPDLOG_DEBUG("Kernel:{}", kernel); SPDLOG_DEBUG("Os:{}", os); SPDLOG_DEBUG("Driver:{}", driver); SPDLOG_DEBUG("CPU Scheduler:{}", cpusched); #endif } void check_for_vkbasalt_and_gamemode() { #ifdef __linux__ static bool checked = false; if (checked) return; if (lib_loaded("gamemode", HUDElements.g_gamescopePid)) HUDElements.gamemode_bol = true; if (lib_loaded("vkbasalt", HUDElements.g_gamescopePid)) HUDElements.vkbasalt_bol = true; checked = true; #endif } void update_fan(){ // This just handles steam deck fan for now static bool init; string hwmon_path; if (!init){ string path = "/sys/class/hwmon/"; auto dirs = ls(path.c_str(), "hwmon", LS_DIRS); for (auto& dir : dirs) { string full_path = (path + dir + "/name").c_str(); if (read_line(full_path).find("steamdeck_hwmon") != string::npos){ hwmon_path = path + dir + "/fan1_input"; break; } } } if (!hwmon_path.empty()) fan_speed = stoi(read_line(hwmon_path)); else fan_speed = -1; } void next_hud_position(){ auto params = get_params(); if (params->position < (overlay_param_position::LAYER_POSITION_COUNT - 1)){ params->position = static_cast(params->position + 1); } else { params->position = static_cast(0); } } ================================================ FILE: src/overlay.frag ================================================ #version 450 core layout(location = 0) out vec4 fColor; layout(set=0, binding=0) uniform sampler2D sTexture; layout(location = 0) in struct{ vec4 Color; vec2 UV; } In; void main() { fColor = In.Color * vec4(1, 1, 1, texture(sTexture, In.UV.st).r); } ================================================ FILE: src/overlay.h ================================================ #pragma once #ifndef MANGOHUD_OVERLAY_H #define MANGOHUD_OVERLAY_H #include #include #include #include #include #include "imgui_internal.h" #include "overlay_params.h" #include "hud_elements.h" #include "dbus_info.h" #include "logging.h" struct frame_stat { uint64_t stats[OVERLAY_PLOTS_MAX]; }; static const int kMaxGraphEntries = 50; enum EngineTypes { UNKNOWN, OPENGL, VULKAN, DXVK, VKD3D, DAMAVAND, ZINK, WINED3D, FERAL3D, TOGL, GAMESCOPE, SDL }; struct swapchain_stats { uint64_t n_frames; enum overlay_plots stat_selector; double time_dividor; struct frame_stat stats_min, stats_max; struct frame_stat frames_stats[200]; ImFont* font_small = nullptr; ImFont* font_text = nullptr; ImFont* font_secondary = nullptr; size_t font_params_hash = 0; std::string time; double fps; uint64_t last_present_time; unsigned n_frames_since_update; uint64_t last_fps_update; ImVec2 main_window_pos; struct { int32_t major; int32_t minor; bool is_gles; } version_gl; struct { int32_t major; int32_t minor; int32_t patch; } version_vk; std::string engineName; std::string engineVersion; std::string deviceName; std::string gpuName; std::string driverName; uint32_t applicationVersion; enum EngineTypes engine; }; struct benchmark_stats { float total; std::vector fps_data; std::vector> percentile_data; }; struct LOAD_DATA { ImVec4 color_low; ImVec4 color_med; ImVec4 color_high; unsigned med_load; unsigned high_load; }; inline const char* engine_name(const swapchain_stats& sw_stats) { const char* engines[] = { "Unknown", "OpenGL", "VULKAN", "DXVK", "VKD3D", "DAMAVAND", "ZINK", "WINED3D", "Feral3D", "ToGL", "GAMESCOPE", "SDL" }; const char* engines_short[] = { "Unknown", "OGL", "VK", "DXVK", "VKD3D", "DV", "ZINK", "WD3D", "Feral3D", "ToGL", "GS", "SDL" }; auto engine = sw_stats.engine; auto params = get_params(); if (!params) return "Unknown"; if (!params->fps_text.empty()) return params->fps_text.c_str(); auto& en = params->enabled; if (en[OVERLAY_PARAM_ENABLED_hide_engine_names]) { en[OVERLAY_PARAM_ENABLED_hide_fps_superscript] = true; return "FPS"; } if (en[OVERLAY_PARAM_ENABLED_horizontal] && !en[OVERLAY_PARAM_ENABLED_engine_short_names]) { en[OVERLAY_PARAM_ENABLED_hide_fps_superscript] = true; return "FPS"; } if (en[OVERLAY_PARAM_ENABLED_dx_api]) { if (engine == EngineTypes::VKD3D) return "DX12"; if (engine == EngineTypes::DXVK) { if (sw_stats.applicationVersion == 1) return "DX9"; if (sw_stats.applicationVersion == 2) return "DX11"; return "DX?"; } } return en[OVERLAY_PARAM_ENABLED_engine_short_names] ? engines_short[engine] : engines[engine]; } extern uint32_t deviceID; extern struct benchmark_stats benchmark; extern ImVec2 real_font_size; extern std::string wineVersion; extern std::deque graph_data; extern double min_frametime, max_frametime; extern bool steam_focused; extern int fan_speed; extern int current_preset; extern std::vector frametime_data; void init_spdlog(); void overlay_new_frame(const struct overlay_params& params); void overlay_end_frame(); void position_layer(struct swapchain_stats& data, const struct overlay_params& params, const ImVec2& window_size); void render_imgui(swapchain_stats& data, struct overlay_params& params, ImVec2& window_size, bool is_vulkan); void update_hud_info(struct swapchain_stats& sw_stats, const struct overlay_params& params, uint32_t vendorID); void update_hud_info_with_frametime(struct swapchain_stats& sw_stats, const struct overlay_params& params, uint32_t vendorID, uint64_t frametime_ns); void update_hw_info(const struct overlay_params& params, uint32_t vendorID); void init_cpu_stats(overlay_params& params); void check_keybinds(overlay_params& params); void init_system_info(void); void check_for_vkbasalt_and_gamemode(); void create_fonts(ImFontAtlas* font_atlas, const overlay_params& params, ImFont*& small_font, ImFont*& text_font, ImFont*& secondary_font); void right_aligned_text(ImVec4& col, float off_x, const char *fmt, ...); void center_text(const std::string& text); ImVec4 change_on_load_temp(LOAD_DATA& data, unsigned current); float get_time_stat(void *_data, int _idx); void stop_hw_updater(); extern void control_client_check(int control, int& control_client, const std::string& deviceName); extern void process_control_socket(int& control_client, overlay_params ¶ms); extern void control_send(int control_client, const char *cmd, unsigned cmdlen, const char *param, unsigned paramlen); extern int global_control_client; #ifdef HAVE_DBUS void render_mpris_metadata(const overlay_params& params, mutexed_metadata& meta, uint64_t frame_timing); #endif void update_fan(); void next_hud_position(); void horizontal_separator(struct overlay_params& params); void RenderOutlinedText(const char* text, ImU32 textColor); #endif //MANGOHUD_OVERLAY_H ================================================ FILE: src/overlay.vert ================================================ #version 450 core layout(location = 0) in vec2 aPos; layout(location = 1) in vec2 aUV; layout(location = 2) in vec4 aColor; layout(push_constant) uniform uPushConstant{ vec2 uScale; vec2 uTranslate; } pc; out gl_PerVertex{ vec4 gl_Position; }; layout(location = 0) out struct{ vec4 Color; vec2 UV; } Out; void main() { Out.Color = aColor; Out.UV = aUV; gl_Position = vec4(aPos*pc.uScale+pc.uTranslate, 0, 1); } ================================================ FILE: src/overlay_params.cpp ================================================ #include #ifdef _WIN32 #include #endif #include #include #include #include #ifdef __linux__ #include #include #endif #include "imgui.h" #include #include #include #include #include #include #include #include #include #include #include "overlay_params.h" #include "overlay.h" #include "config.h" #include "string_utils.h" #include "hud_elements.h" #include "blacklist.h" #include "mesa/util/os_socket.h" #include "file_utils.h" #include "fex.h" #include "ftrace.h" #include "fps_limiter.h" #if defined(HAVE_X11) || defined(HAVE_WAYLAND) #include #endif #include "dbus_info.h" #include "app/mangoapp.h" #include "fps_metrics.h" #include "version.h" std::unique_ptr fpsmetrics; std::mutex config_mtx; std::condition_variable config_cv; bool config_ready = false; static std::shared_ptr g_params; std::shared_ptr fps_limiter; #if __cplusplus >= 201703L template size_t get_hash(Ts const&... args) { size_t hash = 0; ( (hash ^= std::hash{}(args) << 1), ...); return hash; } #else // C++17 has `if constexpr` so this won't be needed then template size_t get_hash() { return 0; } template size_t get_hash(T const& first, Ts const&... rest) { size_t hash = std::hash{}(first); #if __cplusplus >= 201703L if constexpr (sizeof...(rest) > 0) #endif hash ^= get_hash(rest...) << 1; return hash; } #endif namespace { bool parse_vulkan_present_mode_name(std::string_view name, VkPresentModeKHR& mode) { static constexpr std::string_view prefix = "VK_PRESENT_MODE_"; static constexpr std::string_view suffix = "_KHR"; static constexpr std::pair present_mode_table[] = { { "IMMEDIATE", VK_PRESENT_MODE_IMMEDIATE_KHR }, { "MAILBOX", VK_PRESENT_MODE_MAILBOX_KHR }, { "FIFO", VK_PRESENT_MODE_FIFO_KHR }, { "FIFO_RELAXED", VK_PRESENT_MODE_FIFO_RELAXED_KHR }, { "SHARED_DEMAND_REFRESH", VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR }, { "SHARED_CONTINUOUS_REFRESH", VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR }, { "FIFO_LATEST_READY", VK_PRESENT_MODE_FIFO_LATEST_READY_KHR }, }; name = strip_prefix(name, prefix); name = strip_suffix(name, suffix); const auto elem = std::find_if( std::begin(present_mode_table), std::end(present_mode_table), [&](const auto &entry) { return iequal(entry.first, name); }); if (elem == std::end(present_mode_table)) return false; mode = elem->second; return true; } } static enum overlay_param_position parse_position(const char *str) { if (!str || !strcmp(str, "top-left")) return LAYER_POSITION_TOP_LEFT; if (!strcmp(str, "top-right")) return LAYER_POSITION_TOP_RIGHT; if (!strcmp(str, "middle-left")) return LAYER_POSITION_MIDDLE_LEFT; if (!strcmp(str, "middle-right")) return LAYER_POSITION_MIDDLE_RIGHT; if (!strcmp(str, "bottom-left")) return LAYER_POSITION_BOTTOM_LEFT; if (!strcmp(str, "bottom-right")) return LAYER_POSITION_BOTTOM_RIGHT; if (!strcmp(str, "top-center")) return LAYER_POSITION_TOP_CENTER; if (!strcmp(str, "bottom-center")) return LAYER_POSITION_BOTTOM_CENTER; return LAYER_POSITION_TOP_LEFT; } static int parse_control(const char *str) { std::string path(str); size_t npos = path.find("%p"); if (npos != std::string::npos) path.replace(npos, 2, std::to_string(getpid())); SPDLOG_DEBUG("Socket: {}", path); int ret = os_socket_listen_abstract(path.c_str(), 1); if (ret < 0) { SPDLOG_DEBUG("Couldn't create socket pipe at '{}'", path); SPDLOG_DEBUG("ERROR: '{}'", strerror(errno)); return ret; } os_socket_block(ret, false); return ret; } static float parse_float(const char *str) { float val = 0; std::stringstream ss(str); ss.imbue(std::locale::classic()); ss >> val; return val; } #if defined(HAVE_X11) || defined(HAVE_WAYLAND) static std::vector parse_string_to_keysym_vec(const char *str) { std::vector keys; auto keyStrings = str_tokenize(str); for (auto& ks : keyStrings) { trim(ks); xkb_keysym_t xk = xkb_keysym_from_name(ks.c_str(), XKB_KEYSYM_CASE_INSENSITIVE); if (xk != XKB_KEY_NoSymbol) keys.push_back(xk); else SPDLOG_ERROR("Unrecognized key: '{}'", ks); } return keys; } #define parse_toggle_hud parse_string_to_keysym_vec #define parse_toggle_hud_position parse_string_to_keysym_vec #define parse_toggle_logging parse_string_to_keysym_vec #define parse_reload_cfg parse_string_to_keysym_vec #define parse_upload_log parse_string_to_keysym_vec #define parse_upload_logs parse_string_to_keysym_vec #define parse_toggle_fps_limit parse_string_to_keysym_vec #define parse_toggle_preset parse_string_to_keysym_vec #define parse_reset_fps_metrics parse_string_to_keysym_vec #else #define parse_toggle_hud(x) {} #define parse_toggle_hud_position(x) {} #define parse_toggle_logging(x) {} #define parse_reload_cfg(x) {} #define parse_upload_log(x) {} #define parse_upload_logs(x) {} #define parse_toggle_fps_limit(x) {} #define parse_toggle_preset(x) {} #define parse_reset_fps_metrics(x) {} #endif // NOTE: This is NOT defined as an OVERLAY_PARAM and will be called manually static std::vector parse_preset(const char *str) { std::vector presets; auto preset_strings = str_tokenize(str); for (auto& value : preset_strings) { trim(value); uint32_t as_int; try { as_int = static_cast(std::stoi(value)); } catch (const std::invalid_argument&) { SPDLOG_ERROR("invalid preset value: '{}'", value); continue; } presets.push_back(as_int); } return presets; } static std::map parse_cpu_custom_temp_sensor(const std::string str) { size_t pos = str.find(","); std::map map; if (pos != std::string::npos && pos != str.length() - 1) { map["hwmon_name"] = str.substr(0, pos); map["hwmon_input"] = str.substr(pos + 1); } SPDLOG_DEBUG( "cpu_custom_temp_sensor: name=\"{}\" input=\"{}\"", map["hwmon_name"], map["hwmon_input"] ); return map; } static uint32_t parse_fps_sampling_period(const char *str) { return strtol(str, NULL, 0) * 1000000; /* ms to ns */ } static std::vector parse_fps_limit(const char *str) { std::vector fps_limit; auto fps_limit_strings = str_tokenize(str); for (auto& value : fps_limit_strings) { trim(value); float as_float; try { as_float = std::stof(value); } catch (const std::invalid_argument&) { SPDLOG_ERROR("invalid fps_limit value: '{}'", value); continue; } catch (const std::out_of_range&) { SPDLOG_ERROR("fps_limit value out of range: '{}'", value); continue; } fps_limit.push_back(as_float); } return fps_limit; } static enum fps_limit_method parse_fps_limit_method(const char *str) { if (!strcmp(str, "early")) { return FPS_LIMIT_METHOD_EARLY; } return FPS_LIMIT_METHOD_LATE; } static bool parse_no_display(const char *str) { return strtol(str, NULL, 0) != 0; } static unsigned parse_color(const char *str) { return strtol(str, NULL, 16); } static std::vector parse_load_color(const char *str) { std::vector load_colors; auto tokens = str_tokenize(str); std::string token; for (auto& token : tokens) { trim(token); load_colors.push_back(std::stoi(token, NULL, 16)); } // pad vec with white color so we always have at least 3 while (load_colors.size() < 3) { load_colors.push_back(std::stoi("FFFFFF" , NULL, 16)); } return load_colors; } static std::vector parse_load_value(const char *str) { std::vector load_value; auto tokens = str_tokenize(str); std::string token; for (auto& token : tokens) { trim(token); load_value.push_back(std::stoi(token)); } return load_value; } static std::vector parse_str_tokenize(const char *str, const std::string& delims = ",:+", bool btrim = true) { std::vector data; auto tokens = str_tokenize(str, delims); std::string token; for (auto& token : tokens) { if (btrim) trim(token); data.push_back(token); } return data; } static std::vector parse_gpu_list(const char *str) { std::vector result; auto gpu_list_strings = str_tokenize(str); for (auto& value : gpu_list_strings) { trim(value); unsigned int num = stoul(value); result.push_back(num); } return result; } static unsigned parse_unsigned(const char *str) { return strtol(str, NULL, 0); } static signed parse_signed(const char *str) { return strtol(str, NULL, 0); } static std::string parse_str(const char *str) { return str; } static std::string parse_path(const char *str) { #ifdef _XOPEN_SOURCE // Expand ~/ to home dir if (str[0] == '~') { std::stringstream s; wordexp_t e; int ret; if (!(ret = wordexp(str, &e, 0))) { for(size_t i = 0; i < e.we_wordc; i++) { if (i > 0) s << " "; s << e.we_wordv[i]; } } wordfree(&e); if (!ret) return s.str(); } #endif return str; } static std::vector parse_benchmark_percentiles(const char *str) { SPDLOG_INFO("benchmark_percetile is obsolete and will be removed. Use fps_metrics instead"); std::vector percentiles; return percentiles; } static uint32_t parse_font_glyph_ranges(const char *str) { uint32_t fg = 0; auto tokens = str_tokenize(str); for (auto& token : tokens) { trim(token); std::transform(token.begin(), token.end(), token.begin(), ::tolower); if (token == "korean") fg |= FG_KOREAN; else if (token == "chinese") fg |= FG_CHINESE_FULL; else if (token == "chinese_simplified") fg |= FG_CHINESE_SIMPLIFIED; else if (token == "japanese") fg |= FG_JAPANESE; else if (token == "cyrillic") fg |= FG_CYRILLIC; else if (token == "thai") fg |= FG_THAI; else if (token == "vietnamese") fg |= FG_VIETNAMESE; else if (token == "latin_ext_a") fg |= FG_LATIN_EXT_A; else if (token == "latin_ext_b") fg |= FG_LATIN_EXT_B; } return fg; } static gl_size_query parse_gl_size_query(const char *str) { std::string value(str); trim(value); std::transform(value.begin(), value.end(), value.begin(), ::tolower); if (value == "viewport") return GL_SIZE_VIEWPORT; if (value == "scissorbox") return GL_SIZE_SCISSORBOX; return GL_SIZE_DRAWABLE; } static std::vector parse_fps_metrics(const char *str){ std::vector metrics; auto tokens = str_tokenize(str); for (auto& token : tokens) { metrics.push_back(token); } fpsmetrics = std::make_unique(metrics); return metrics; } static overlay_params::fex_stats_options parse_fex_stats(const char *str) { overlay_params::fex_stats_options options { #ifdef HAVE_FEX .enabled = fex::is_fex_capable(), #endif }; auto tokens = str_tokenize(str); #define option_check(str, option) do { \ if (token == #str) options.option = true; \ } while (0) // If we have any tokens then default disable. if (!tokens.empty()) { options.status = false; options.app_type = false; options.hot_threads = false; options.jit_load = false; options.sigbus_counts = false; options.smc_counts = false; options.softfloat_counts = false; } for (auto& token : tokens) { option_check(status, status); option_check(apptype, app_type); option_check(hotthreads, hot_threads); option_check(jitload, jit_load); option_check(sigbus, sigbus_counts); option_check(smc, smc_counts); option_check(softfloat, softfloat_counts); } return options; } static overlay_params::ftrace_options parse_ftrace(const char *str) { overlay_params::ftrace_options options; #ifdef HAVE_FTRACE auto ftrace_params = str_tokenize(str, "+"); for (auto& param : ftrace_params) { auto tokenized_param = str_tokenize(param, "/"); if (tokenized_param.empty()) { SPDLOG_ERROR("Failed to parse ftrace parameter '{}'", param); continue; } if (tokenized_param[0] == "histogram") { if (tokenized_param.size() != 2) { SPDLOG_ERROR("Failed to parse ftrace histogram parameter '{}'", param); continue; } SPDLOG_DEBUG("Using ftrace histogram for '{}'", tokenized_param[1]); options.tracepoints.push_back(std::make_shared( FTrace::Tracepoint { .name = tokenized_param[1], .type = FTrace::TracepointType::Histogram, })); } else if (tokenized_param[0] == "linegraph") { if (tokenized_param.size() != 3) { SPDLOG_ERROR("Failed to parse ftrace linegraph parameter '{}'", param); continue; } SPDLOG_DEBUG("Using ftrace line graph for '{}'", tokenized_param[1]); options.tracepoints.push_back(std::make_shared( FTrace::Tracepoint { .name = tokenized_param[1], .type = FTrace::TracepointType::LineGraph, .field_name = tokenized_param[2], })); } else if (tokenized_param[0] == "label") { if (tokenized_param.size() != 3) { SPDLOG_ERROR("Failed to parse ftrace label parameter '{}'", param); continue; } SPDLOG_DEBUG("Using ftrace label for '{}', label name '{}'", tokenized_param[1], tokenized_param[2]); options.tracepoints.push_back(std::make_shared( FTrace::Tracepoint { .name = tokenized_param[1], .type = FTrace::TracepointType::Label, .field_name = tokenized_param[2], })); } else { SPDLOG_ERROR("Failed to parse ftrace parameter '{}'", param); } } options.enabled = !options.tracepoints.empty(); #endif // HAVE_FTRACE return options; } #define parse_width(s) parse_unsigned(s) #define parse_height(s) parse_unsigned(s) #define parse_vulkan_present_mode(s) parse_str(s) #define parse_vsync(s) parse_unsigned(s) #define parse_gl_vsync(s) parse_signed(s) #define parse_offset_x(s) parse_unsigned(s) #define parse_offset_y(s) parse_unsigned(s) #define parse_log_duration(s) parse_unsigned(s) #define parse_time_format(s) parse_str(s) #define parse_output_folder(s) parse_path(s) #define parse_output_file(s) parse_path(s) #define parse_font_file(s) parse_path(s) #define parse_font_file_text(s) parse_path(s) #define parse_io_read(s) parse_unsigned(s) #define parse_io_write(s) parse_unsigned(s) #define parse_pci_dev(s) parse_str(s) #define parse_media_player_name(s) parse_str(s) #define parse_font_scale_media_player(s) parse_float(s) #define parse_cpu_text(s) parse_str(s) #define parse_fps_text(s) parse_str(s) #define parse_log_interval(s) parse_unsigned(s) #define parse_font_size(s) parse_float(s) #define parse_font_size_secondary(s) parse_float(s) #define parse_font_size_text(s) parse_float(s) #define parse_font_scale(s) parse_float(s) #define parse_background_alpha(s) parse_float(s) #define parse_alpha(s) parse_float(s) #define parse_permit_upload(s) parse_unsigned(s) #define parse_no_small_font(s) parse_unsigned(s) != 0 #define parse_cellpadding_y(s) parse_float(s) #define parse_table_columns(s) parse_unsigned(s) #define parse_autostart_log(s) parse_unsigned(s) #define parse_gl_bind_framebuffer(s) parse_unsigned(s) #define parse_gl_dont_flip(s) parse_unsigned(s) != 0 #define parse_round_corners(s) parse_unsigned(s) #define parse_fcat_overlay_width(s) parse_unsigned(s) #define parse_fcat_screen_edge(s) parse_unsigned(s) #define parse_picmip(s) parse_signed(s) #define parse_af(s) parse_signed(s) #define parse_cpu_color(s) parse_color(s) #define parse_gpu_color(s) parse_color(s) #define parse_vram_color(s) parse_color(s) #define parse_ram_color(s) parse_color(s) #define parse_engine_color(s) parse_color(s) #define parse_io_color(s) parse_color(s) #define parse_frametime_color(s) parse_color(s) #define parse_background_color(s) parse_color(s) #define parse_text_color(s) parse_color(s) #define parse_media_player_color(s) parse_color(s) #define parse_wine_color(s) parse_color(s) #define parse_horizontal_separator_color(s) parse_color(s) #define parse_network_color(s) parse_color(s) #define parse_gpu_load_color(s) parse_load_color(s) #define parse_cpu_load_color(s) parse_load_color(s) #define parse_gpu_load_value(s) parse_load_value(s) #define parse_cpu_load_value(s) parse_load_value(s) #define parse_blacklist(s) parse_str_tokenize(s) #define parse_custom_text_center(s) parse_str(s) #define parse_custom_text(s) parse_str(s) #define parse_fps_value(s) parse_load_value(s) #define parse_fps_color(s) parse_load_color(s) #define parse_battery_color(s) parse_color(s) #define parse_media_player_format(s) parse_str_tokenize(s, ";", false) #define parse_fsr_steam_sharpness(s) parse_float(s) #define parse_text_outline_color(s) parse_color(s) #define parse_text_outline_thickness(s) parse_float(s) #define parse_device_battery(s) parse_str_tokenize(s) #define parse_network(s) parse_str_tokenize(s) #define parse_gpu_text(s) parse_str_tokenize(s) static bool parse_help(const char *str) { fprintf(stderr, "Layer params using MANGOHUD_CONFIG=\n"); #define OVERLAY_PARAM_BOOL(name) \ fprintf(stderr, "\t%s=0|1\n", #name); #define OVERLAY_PARAM_CUSTOM(name) OVERLAY_PARAMS #undef OVERLAY_PARAM_BOOL #undef OVERLAY_PARAM_CUSTOM fprintf(stderr, "\tposition=top-left|top-right|bottom-left|bottom-right\n"); fprintf(stderr, "\tfps_sampling_period=number-of-milliseconds\n"); fprintf(stderr, "\tno_display=0|1\n"); fprintf(stderr, "\toutput_folder=/path/to/folder\n"); fprintf(stderr, "\twidth=width-in-pixels\n"); fprintf(stderr, "\theight=height-in-pixels\n"); return true; } static bool is_delimiter(char c) { return c == 0 || c == ',' || c == ':' || c == ';' || c == '='; } static int parse_string(const char *s, char *out_param, char *out_value) { int i = 0; for (; !is_delimiter(*s); s++, out_param++, i++) *out_param = *s; *out_param = 0; if (*s == '=') { s++; i++; for (; !is_delimiter(*s); s++, out_value++, i++) { *out_value = *s; // Consume escaped delimiter, but don't escape null. Might be end of string. if (*s == '\\' && *(s + 1) != 0 && is_delimiter(*(s + 1))) { s++; i++; *out_value = *s; } } } else *(out_value++) = '1'; *out_value = 0; if (*s && is_delimiter(*s)) { s++; i++; } if (*s && !i) { SPDLOG_ERROR("syntax error: unexpected '{0:c}' ({0:d}) while " "parsing a string", *s); } return i; } const char *overlay_param_names[] = { #define OVERLAY_PARAM_BOOL(name) #name, #define OVERLAY_PARAM_CUSTOM(name) OVERLAY_PARAMS #undef OVERLAY_PARAM_BOOL #undef OVERLAY_PARAM_CUSTOM }; static void initialize_preset(struct overlay_params *params) { if (params->options.find("preset") != params->options.end()) { auto presets = parse_preset(params->options.find("preset")->second.c_str()); if (!presets.empty()) params->preset = presets; } current_preset = params->preset[0]; } static void set_parameters_from_options(struct overlay_params *params) { bool read_cfg = false; if (params->options.find("read_cfg") != params->options.end() && params->options.find("read_cfg")->second != "0") read_cfg = true; if (params->options.find("full") != params->options.end() && params->options.find("full")->second != "0") { #define OVERLAY_PARAM_BOOL(name) \ params->enabled[OVERLAY_PARAM_ENABLED_##name] = 1; #define OVERLAY_PARAM_CUSTOM(name) OVERLAY_PARAMS #undef OVERLAY_PARAM_BOOL #undef OVERLAY_PARAM_CUSTOM params->enabled[OVERLAY_PARAM_ENABLED_histogram] = 0; params->enabled[OVERLAY_PARAM_ENABLED_fps_only] = 0; params->enabled[OVERLAY_PARAM_ENABLED_battery_icon] = 0; params->enabled[OVERLAY_PARAM_ENABLED_mangoapp_steam] = 0; params->enabled[OVERLAY_PARAM_ENABLED_hide_fsr_sharpness] = 0; params->enabled[OVERLAY_PARAM_ENABLED_throttling_status] = 0; params->enabled[OVERLAY_PARAM_ENABLED_fcat] = 0; params->enabled[OVERLAY_PARAM_ENABLED_horizontal] = 0; params->enabled[OVERLAY_PARAM_ENABLED_hud_no_margin] = 0; params->enabled[OVERLAY_PARAM_ENABLED_log_versioning] = 0; params->enabled[OVERLAY_PARAM_ENABLED_hud_compact] = 0; params->enabled[OVERLAY_PARAM_ENABLED_exec_name] = 0; params->enabled[OVERLAY_PARAM_ENABLED_trilinear] = 0; params->enabled[OVERLAY_PARAM_ENABLED_bicubic] = 0; params->enabled[OVERLAY_PARAM_ENABLED_retro] = 0; params->enabled[OVERLAY_PARAM_ENABLED_debug] = 0; params->enabled[OVERLAY_PARAM_ENABLED_engine_short_names] = 0; params->enabled[OVERLAY_PARAM_ENABLED_hide_engine_names] = 0; params->enabled[OVERLAY_PARAM_ENABLED_hide_fps_superscript] = 0; params->enabled[OVERLAY_PARAM_ENABLED_dynamic_frame_timing] = 0; params->enabled[OVERLAY_PARAM_ENABLED_temp_fahrenheit] = 0; params->enabled[OVERLAY_PARAM_ENABLED_duration] = false; params->enabled[OVERLAY_PARAM_ENABLED_core_bars] = false; params->enabled[OVERLAY_PARAM_ENABLED_read_cfg] = read_cfg; params->enabled[OVERLAY_PARAM_ENABLED_time_no_label] = false; params->enabled[OVERLAY_PARAM_ENABLED_core_type] = false; params->options.erase("full"); } for (auto& it : params->options) { #define OVERLAY_PARAM_BOOL(name) \ if (it.first == #name) { \ params->enabled[OVERLAY_PARAM_ENABLED_##name] = \ strtol(it.second.c_str(), NULL, 0); \ continue; \ } #define OVERLAY_PARAM_CUSTOM(name) \ if (it.first == #name) { \ params->name = parse_##name(it.second.c_str()); \ continue; \ } OVERLAY_PARAMS #undef OVERLAY_PARAM_BOOL #undef OVERLAY_PARAM_CUSTOM if (it.first == "preset") { continue; // Handled above } SPDLOG_ERROR("Unknown option '{}'", it.first.c_str()); } } static void parse_overlay_env(struct overlay_params *params, const char *env, bool use_existing_preset) { const char *env_start = env; uint32_t num; char key[256], value[256]; while ((num = parse_string(env, key, value)) != 0) { trim_char(key); trim_char(value); env += num; if (!strcmp("preset", key)) { if (!use_existing_preset) { add_to_options(params, key, value); initialize_preset(params); } break; } } presets(current_preset, params); env = env_start; while ((num = parse_string(env, key, value)) != 0) { trim_char(key); trim_char(value); env += num; if (!strcmp("preset", key)) { continue; // Avoid 'Unknown option' error } #define OVERLAY_PARAM_BOOL(name) \ if (!strcmp(#name, key)) { \ add_to_options(params, key, value); \ continue; \ } #define OVERLAY_PARAM_CUSTOM(name) \ if (!strcmp(#name, key)) { \ add_to_options(params, key, value); \ continue; \ } OVERLAY_PARAMS #undef OVERLAY_PARAM_BOOL #undef OVERLAY_PARAM_CUSTOM SPDLOG_ERROR("Unknown option '{}'", key); } set_parameters_from_options(params); } static void set_param_defaults(struct overlay_params *params){ params->enabled[OVERLAY_PARAM_ENABLED_fps] = true; params->enabled[OVERLAY_PARAM_ENABLED_frame_timing] = true; params->enabled[OVERLAY_PARAM_ENABLED_core_load] = false; params->enabled[OVERLAY_PARAM_ENABLED_core_bars] = false; params->enabled[OVERLAY_PARAM_ENABLED_cpu_temp] = false; params->enabled[OVERLAY_PARAM_ENABLED_cpu_power] = false; params->enabled[OVERLAY_PARAM_ENABLED_gpu_temp] = false; params->enabled[OVERLAY_PARAM_ENABLED_gpu_junction_temp] = false; params->enabled[OVERLAY_PARAM_ENABLED_gpu_mem_temp] = false; params->enabled[OVERLAY_PARAM_ENABLED_cpu_stats] = true; params->enabled[OVERLAY_PARAM_ENABLED_gpu_stats] = true; params->enabled[OVERLAY_PARAM_ENABLED_ram] = false; params->enabled[OVERLAY_PARAM_ENABLED_ram_temp] = false; params->enabled[OVERLAY_PARAM_ENABLED_swap] = false; params->enabled[OVERLAY_PARAM_ENABLED_vram] = false; params->enabled[OVERLAY_PARAM_ENABLED_read_cfg] = false; params->enabled[OVERLAY_PARAM_ENABLED_io_read] = false; params->enabled[OVERLAY_PARAM_ENABLED_io_write] = false; params->enabled[OVERLAY_PARAM_ENABLED_wine] = false; params->enabled[OVERLAY_PARAM_ENABLED_gpu_load_change] = false; params->enabled[OVERLAY_PARAM_ENABLED_cpu_load_change] = false; params->enabled[OVERLAY_PARAM_ENABLED_core_load_change] = false; params->enabled[OVERLAY_PARAM_ENABLED_gpu_voltage] = false; params->enabled[OVERLAY_PARAM_ENABLED_legacy_layout] = true; params->enabled[OVERLAY_PARAM_ENABLED_frametime] = true; params->enabled[OVERLAY_PARAM_ENABLED_fps_only] = false; params->enabled[OVERLAY_PARAM_ENABLED_device_battery_icon] = false; params->enabled[OVERLAY_PARAM_ENABLED_throttling_status] = false; params->enabled[OVERLAY_PARAM_ENABLED_fcat] = false; params->enabled[OVERLAY_PARAM_ENABLED_horizontal_stretch] = true; params->enabled[OVERLAY_PARAM_ENABLED_engine_short_names] = false; params->enabled[OVERLAY_PARAM_ENABLED_hide_engine_names] = false; params->enabled[OVERLAY_PARAM_ENABLED_hide_fps_superscript] = false; params->enabled[OVERLAY_PARAM_ENABLED_text_outline] = true; params->enabled[OVERLAY_PARAM_ENABLED_dynamic_frame_timing] = false; params->enabled[OVERLAY_PARAM_ENABLED_temp_fahrenheit] = false; params->enabled[OVERLAY_PARAM_ENABLED_duration] = false; params->enabled[OVERLAY_PARAM_ENABLED_frame_timing_detailed] = false; params->fps_sampling_period = 500000000; /* 500ms */ params->width = 0; params->height = 140; params->control = -1; params->fps_limit = { 0 }; params->fps_limit_method = FPS_LIMIT_METHOD_LATE; params->vsync = -1; params->gl_vsync = -2; params->offset_x = 0; params->offset_y = 0; params->background_alpha = 0.5; params->alpha = 1.0; params->fcat_screen_edge = 0; params->fcat_overlay_width = 24; params->time_format = "%T"; params->gpu_color = 0x2e9762; params->cpu_color = 0x2e97cb; params->vram_color = 0xad64c1; params->ram_color = 0xc26693; params->engine_color = 0xeb5b5b; params->io_color = 0xa491d3; params->frametime_color = 0x00ff00; params->background_color = 0x020202; params->text_color = 0xffffff; params->media_player_color = 0xffffff; params->network_color = 0xe07b85; params->media_player_name = ""; params->font_scale = 1.0f; params->wine_color = 0xeb5b5b; params->horizontal_separator_color = 0xad64c1; params->gpu_load_color = { 0x39f900, 0xfdfd09, 0xb22222 }; params->cpu_load_color = { 0x39f900, 0xfdfd09, 0xb22222 }; params->font_scale_media_player = 0.55f; params->log_interval = 0; params->media_player_format = { "{title}", "{artist}", "{album}" }; params->permit_upload = 0; params->benchmark_percentiles = { "97", "AVG"}; params->gpu_load_value = { 60, 90 }; params->cpu_load_value = { 60, 90 }; params->cellpadding_y = -0.085; params->fps_color = { 0xb22222, 0xfdfd09, 0x39f900 }; params->fps_value = { 30, 60 }; params->round_corners = 0; params->battery_color =0xff9078; params->fsr_steam_sharpness = -1; params->picmip = -17; params->af = -1; params->font_size = 24; params->table_columns = 3; params->text_outline_color = 0x000000; params->text_outline_thickness = 1.5; } static std::string verify_pci_dev(std::string pci_dev) { uint32_t domain, bus, slot, func; if ( sscanf( pci_dev.c_str(), "%04x:%02x:%02x.%x", &domain, &bus, &slot, &func ) != 4) { SPDLOG_ERROR("Failed to parse PCI device ID: '{}'", pci_dev); return pci_dev; } std::stringstream ss; ss << std::hex << std::setw(4) << std::setfill('0') << domain << ":" << std::setw(2) << bus << ":" << std::setw(2) << slot << "." << std::setw(1) << func; SPDLOG_DEBUG("pci_dev = {}", ss.str()); return ss.str(); } void parse_overlay_config(struct overlay_params *params, const char *env, bool use_existing_preset) { SPDLOG_DEBUG("Version: {}", MANGOHUD_VERSION); std::vector default_preset = {-1, 0, 1, 2, 3, 4}; auto preset = std::move(params->preset); int transfer_function = params->transfer_function; *params = {}; params->transfer_function = transfer_function; params->preset = use_existing_preset ? std::move(preset) : default_preset; set_param_defaults(params); if (!use_existing_preset) { current_preset = params->preset[0]; } #if defined(HAVE_X11) || defined(HAVE_WAYLAND) params->toggle_hud = { XKB_KEY_Shift_R, XKB_KEY_F12 }; params->toggle_hud_position = { XKB_KEY_Shift_R, XKB_KEY_F11 }; params->toggle_preset = { XKB_KEY_Shift_R, XKB_KEY_F10 }; params->reset_fps_metrics = { XKB_KEY_Shift_R, XKB_KEY_F9}; params->toggle_fps_limit = { XKB_KEY_Shift_L, XKB_KEY_F1 }; params->toggle_logging = { XKB_KEY_Shift_L, XKB_KEY_F2 }; params->reload_cfg = { XKB_KEY_Shift_L, XKB_KEY_F4 }; params->upload_log = { XKB_KEY_Shift_L, XKB_KEY_F3 }; params->upload_logs = { XKB_KEY_Control_L, XKB_KEY_F3 }; #endif #ifdef _WIN32 params->toggle_hud = { VK_F12 }; params->toggle_preset = { VK_F10 }; params->reset_fps_metrics = { VK_F9}; params->toggle_fps_limit = { VK_F3 }; params->toggle_logging = { VK_F2 }; params->reload_cfg = { VK_F4 }; #undef parse_toggle_hud #undef parse_toggle_fps_limit #undef parse_toggle_preset #undef parse_toggle_logging #undef parse_reload_cfg #define parse_toggle_hud(x) params->toggle_hud #define parse_toggle_preset(x) params->toggle_preset #define parse_toggle_fps_limit(x) params->toggle_fps_limit #define parse_toggle_logging(x) params->toggle_logging #define parse_reload_cfg(x) params->reload_cfg #endif HUDElements.ordered_functions.clear(); HUDElements.exec_list.clear(); params->options.clear(); HUDElements.options.clear(); // first pass with env var if (env) parse_overlay_env(params, env, use_existing_preset); bool read_cfg = params->enabled[OVERLAY_PARAM_ENABLED_read_cfg]; bool env_contains_preset = params->options.find("preset") != params->options.end(); if (!env || read_cfg) { parseConfigFile(*params); if (!use_existing_preset && !env_contains_preset) { initialize_preset(params); } // clear options since we don't want config options to appear first params->options.clear(); HUDElements.options.clear(); // add preset options presets(current_preset, params); // potentially override preset options with config options parseConfigFile(*params); set_parameters_from_options(params); } if (params->enabled[OVERLAY_PARAM_ENABLED_legacy_layout]) HUDElements.ordered_functions.clear(); if (env && read_cfg) { HUDElements.ordered_functions.clear(); parse_overlay_env(params, env, true); } // If fps_only param is enabled disable legacy_layout if (params->enabled[OVERLAY_PARAM_ENABLED_fps_only]) params->enabled[OVERLAY_PARAM_ENABLED_legacy_layout] = false; if (is_blacklisted()) return; if (params->font_scale_media_player <= 0.f) params->font_scale_media_player = 0.55f; // Convert from 0xRRGGBB to ImGui's format std::array colors = { ¶ms->cpu_color, ¶ms->gpu_color, ¶ms->vram_color, ¶ms->ram_color, ¶ms->engine_color, ¶ms->io_color, ¶ms->background_color, ¶ms->frametime_color, ¶ms->text_color, ¶ms->media_player_color, ¶ms->wine_color, ¶ms->horizontal_separator_color, ¶ms->battery_color, ¶ms->gpu_load_color[0], ¶ms->gpu_load_color[1], ¶ms->gpu_load_color[2], ¶ms->cpu_load_color[0], ¶ms->cpu_load_color[1], ¶ms->cpu_load_color[2], ¶ms->fps_color[0], ¶ms->fps_color[1], ¶ms->fps_color[2], ¶ms->text_outline_color, ¶ms->network_color, }; for (auto color : colors){ *color = IM_COL32(RGBGetRValue(*color), RGBGetGValue(*color), RGBGetBValue(*color), 255); } params->table_columns = std::max(1u, std::min(64u, params->table_columns)); //increase hud width if io read and write if (!params->width && !params->enabled[OVERLAY_PARAM_ENABLED_horizontal]) { params->width = params->font_size * params->font_scale * params->table_columns * 4.6; if ((params->enabled[OVERLAY_PARAM_ENABLED_io_read] || params->enabled[OVERLAY_PARAM_ENABLED_io_write])) { params->width += 2 * params->font_size * params->font_scale; } // Treat it like hud would need to be ~7 characters wider with default font. if (params->no_small_font) params->width += 7 * params->font_size * params->font_scale; } // If secondary font size not set, compute it from main font_size if (!params->font_size_secondary) { float coeff = params->no_small_font ? 1 : 0.55; params->font_size_secondary = params->font_size * coeff; } params->font_params_hash = get_hash(params->font_size, params->font_size_text, params->no_small_font, params->font_file, params->font_file_text, params->font_glyph_ranges, params->font_scale, params->font_size_secondary ); // check if user specified an env for fps limiter instead const char *fps_limit_env = getenv("MANGOHUD_FPS_LIMIT"); if (fps_limit_env) { try { int fps = std::stof(fps_limit_env); auto front = params->fps_limit.begin(); params->fps_limit.insert(front, fps); } catch(...) {} } #ifdef HAVE_DBUS if (params->enabled[OVERLAY_PARAM_ENABLED_media_player]) { if (dbusmgr::dbus_mgr.init(dbusmgr::SRV_MPRIS)) dbusmgr::dbus_mgr.init_mpris(params->media_player_name); } else { dbusmgr::dbus_mgr.deinit(dbusmgr::SRV_MPRIS); main_metadata.meta.valid = false; } // if (params->enabled[OVERLAY_PARAM_ENABLED_gamemode]) // { // if (dbusmgr::dbus_mgr.init(dbusmgr::SRV_GAMEMODE)) // HUDElements.gamemode_bol = dbusmgr::dbus_mgr.gamemode_enabled(getpid()); // } // else // dbusmgr::dbus_mgr.deinit(dbusmgr::SRV_GAMEMODE); #endif if(!params->output_file.empty()) { SPDLOG_INFO("output_file is deprecated, use output_folder instead"); } auto real_size = params->font_size * params->font_scale; real_font_size = ImVec2(real_size, real_size / 2); for (const auto& option : HUDElements.options) { SPDLOG_DEBUG("Param: '{}' = '{}'", option.first, option.second); } // Needs ImGui context but it is null here for OpenGL so just note it and update somewhere else HUDElements.colors.update = true; if (params->no_small_font) HUDElements.text_column = 2; else HUDElements.text_column = 1; if(logger && logger->is_active()){ SPDLOG_DEBUG("Stopped logging because config reloaded"); logger->stop_logging(); } logger = std::make_unique(params); #ifdef MANGOAPP { extern bool new_frame; std::lock_guard lk(mangoapp_m); params->no_display = params->no_display; new_frame = true; // we probably changed how we look. } mangoapp_cv.notify_one(); g_fsrSharpness = params->fsr_steam_sharpness; #endif if (HUDElements.net) HUDElements.net->should_reset = true; // If both options are specified, GPUS::selected_gpus() is going // to return only GPUs listed in gpu_list if (!params->gpu_list.empty() && !params->pci_dev.empty()) { SPDLOG_WARN( "You have specified both gpu_list and pci_dev, " "ignoring pci_dev." ); } if (!params->pci_dev.empty()) params->pci_dev = verify_pci_dev(params->pci_dev); if (!params->vulkan_present_mode.empty()) { VkPresentModeKHR present_mode; if (parse_vulkan_present_mode_name(params->vulkan_present_mode, present_mode)) { params->m_vulkan_present_mode = present_mode; } } else if ((int)params->vsync != -1) { if (params->vsync < HUDElements.presentModes.size()) { params->m_vulkan_present_mode = HUDElements.presentModes[params->vsync]; } else { SPDLOG_WARN("vsync={} out of range for [0 .. {}] (ignoring)", params->vsync, HUDElements.presentModes.size() - 1); } } { std::lock_guard lock(config_mtx); config_ready = true; config_cv.notify_one(); } auto snapshot = std::make_shared(*params); std::atomic_store_explicit(&g_params, std::move(snapshot), std::memory_order_release); fps_limiter = std::make_unique(params->fps_limit_method ? false : true); if (!gpus) gpus = std::make_unique(); if (params->enabled[OVERLAY_PARAM_ENABLED_legacy_layout]) { HUDElements.legacy_elements(get_params().get()); } else { HUDElements.ordered_functions.clear(); for (auto& option : HUDElements.options) { HUDElements.sort_elements(option); } } } std::shared_ptr get_params() { for (;;) { auto p = std::atomic_load_explicit(&g_params, std::memory_order_acquire); if (p) return p; std::this_thread::sleep_for(std::chrono::milliseconds(25)); } } bool parse_preset_config(int preset, struct overlay_params *params){ const char *presets_file_env = getenv("MANGOHUD_PRESETSFILE"); const std::string config_dir = get_config_dir(); std::string preset_path = presets_file_env ? presets_file_env : config_dir + "/MangoHud/" + "presets.conf"; char preset_string[20]; snprintf(preset_string, sizeof(preset_string), "[preset %d]", preset); std::ifstream stream(preset_path); stream.imbue(std::locale::classic()); if (!stream.good()) { SPDLOG_DEBUG("Failed to read presets file: '{}'. Falling back to default presets", preset_path); return false; } std::string line; bool found_preset = false; while (std::getline(stream, line)) { trim(line); if (line == "") continue; if (line == preset_string) { found_preset = true; continue; } if (found_preset) { if (line.front() == '[' && line.back() == ']') break; if (line == "inherit") presets(preset, params, true); parseConfigLine(line, params->options); } } return found_preset; } void add_to_options(struct overlay_params *params, std::string option, std::string value){ HUDElements.options.push_back({option, value}); params->options[option] = value; } void presets(int preset, struct overlay_params *params, bool inherit) { if (!inherit && parse_preset_config(preset, params)) return; switch(preset) { case 0: params->no_display = 1; break; case 1: params->width = 40; add_to_options(params, "legacy_layout", "0"); add_to_options(params, "cpu_stats", "0"); add_to_options(params, "gpu_stats", "0"); add_to_options(params, "fps", "1"); add_to_options(params, "fps_only", "1"); add_to_options(params, "frametime", "0"); add_to_options(params, "debug", "0"); break; case 2: params->table_columns = 20; add_to_options(params, "horizontal", "1"); add_to_options(params, "legacy_layout", "0"); add_to_options(params, "fps", "1"); add_to_options(params, "table_columns", "20"); add_to_options(params, "frame_timing", "1"); add_to_options(params, "frametime", "0"); add_to_options(params, "cpu_stats", "1"); add_to_options(params, "gpu_stats", "1"); add_to_options(params, "ram", "1"); add_to_options(params, "vram", "1"); add_to_options(params, "battery", "1"); add_to_options(params, "hud_no_margin", "1"); add_to_options(params, "gpu_power", "1"); add_to_options(params, "cpu_power", "1"); add_to_options(params, "battery_watt", "1"); add_to_options(params, "battery_time", "1"); break; case 3: add_to_options(params, "cpu_temp", "1"); add_to_options(params, "gpu_temp", "1"); add_to_options(params, "ram", "1"); add_to_options(params, "vram", "1"); add_to_options(params, "cpu_power", "1"); add_to_options(params, "gpu_power", "1"); add_to_options(params, "cpu_mhz", "1"); add_to_options(params, "gpu_mem_clock", "1"); add_to_options(params, "gpu_core_clock", "1"); add_to_options(params, "battery", "1"); add_to_options(params, "hdr", "1"); add_to_options(params, "debug", "0"); break; case 4: add_to_options(params, "full", "1"); add_to_options(params, "throttling_status", "0"); add_to_options(params, "throttling_status_graph", "0"); add_to_options(params, "io_read", "0"); add_to_options(params, "io_write", "0"); add_to_options(params, "arch", "0"); add_to_options(params, "engine_version", "0"); add_to_options(params, "battery", "1"); add_to_options(params, "gamemode", "0"); add_to_options(params, "vkbasalt", "0"); add_to_options(params, "frame_count", "0"); add_to_options(params, "show_fps_limit", "0"); add_to_options(params, "resolution", "0"); add_to_options(params, "gpu_load_change", "0"); add_to_options(params, "core_load_change", "0"); add_to_options(params, "cpu_load_change", "0"); add_to_options(params, "fps_color_change", "0"); add_to_options(params, "hdr", "1"); add_to_options(params, "refresh_rate", "1"); add_to_options(params, "media_player", "0"); add_to_options(params, "debug", "1"); add_to_options(params, "version", "0"); add_to_options(params, "frame_timing_detailed", "1"); add_to_options(params, "network", "1"); add_to_options(params, "present_mode", "0"); add_to_options(params, "proc_vram", "0"); add_to_options(params, "procmem", "0"); add_to_options(params, "display_server", "0"); add_to_options(params, "gpu_efficiency", "0"); add_to_options(params, "cpu_efficiency", "0"); // Disable some options if steamdeck / other known handhelds if (!gpus) gpus = std::make_unique(params); for (auto gpu : gpus->available_gpus) { if (gpu->device_id == 0x1435 || gpu->device_id == 0x163f || gpu->device_id == 0x1681 || gpu->device_id == 0x15bf){ add_to_options(params, "gpu_fan", "0"); add_to_options(params, "gpu_junction_temp", "0"); add_to_options(params, "gpu_voltage", "0"); add_to_options(params, "gpu_mem_temp", "0"); add_to_options(params, "gpu_efficiency", "0"); } // Rembrandt and Phoenix APUs (Z1, Z1E, Z2 Go) if (gpu->device_id == 0x1681 || gpu->device_id == 0x15bf){ add_to_options(params, "gpu_power_limit", "0"); } } break; } } ================================================ FILE: src/overlay_params.h ================================================ #pragma once #ifndef MANGOHUD_OVERLAY_PARAMS_H #define MANGOHUD_OVERLAY_PARAMS_H #include #include #include #include #include #include #include #include #include #ifdef __cplusplus extern "C" { #endif #include #include #include #ifndef KeySym typedef unsigned long KeySym; #endif #ifdef HAVE_FTRACE namespace FTrace { struct Tracepoint; } #endif #define RGBGetBValue(rgb) (rgb & 0x000000FF) #define RGBGetGValue(rgb) ((rgb >> 8) & 0x000000FF) #define RGBGetRValue(rgb) ((rgb >> 16) & 0x000000FF) #define ToRGBColor(r, g, b, a) ((r << 16) | (g << 8) | (b)); #define OVERLAY_PARAMS \ OVERLAY_PARAM_BOOL(fps) \ OVERLAY_PARAM_BOOL(frame_timing) \ OVERLAY_PARAM_BOOL(core_load) \ OVERLAY_PARAM_BOOL(core_bars) \ OVERLAY_PARAM_BOOL(core_type) \ OVERLAY_PARAM_BOOL(cpu_temp) \ OVERLAY_PARAM_CUSTOM(cpu_custom_temp_sensor) \ OVERLAY_PARAM_BOOL(cpu_power) \ OVERLAY_PARAM_BOOL(gpu_temp) \ OVERLAY_PARAM_BOOL(gpu_junction_temp) \ OVERLAY_PARAM_BOOL(gpu_mem_temp) \ OVERLAY_PARAM_BOOL(cpu_stats) \ OVERLAY_PARAM_BOOL(gpu_stats) \ OVERLAY_PARAM_BOOL(ram) \ OVERLAY_PARAM_BOOL(ram_temp) \ OVERLAY_PARAM_BOOL(swap) \ OVERLAY_PARAM_BOOL(vram) \ OVERLAY_PARAM_BOOL(proc_vram) \ OVERLAY_PARAM_BOOL(procmem) \ OVERLAY_PARAM_BOOL(procmem_shared) \ OVERLAY_PARAM_BOOL(procmem_virt) \ OVERLAY_PARAM_BOOL(time) \ OVERLAY_PARAM_BOOL(full) \ OVERLAY_PARAM_BOOL(read_cfg) \ OVERLAY_PARAM_BOOL(io_read) \ OVERLAY_PARAM_BOOL(io_write) \ OVERLAY_PARAM_BOOL(gpu_mem_clock) \ OVERLAY_PARAM_BOOL(gpu_core_clock) \ OVERLAY_PARAM_BOOL(gpu_power) \ OVERLAY_PARAM_BOOL(arch) \ OVERLAY_PARAM_BOOL(media_player) \ OVERLAY_PARAM_BOOL(version) \ OVERLAY_PARAM_BOOL(vulkan_driver) \ OVERLAY_PARAM_BOOL(gpu_name) \ OVERLAY_PARAM_BOOL(engine_version) \ OVERLAY_PARAM_BOOL(histogram) \ OVERLAY_PARAM_BOOL(wine) \ OVERLAY_PARAM_BOOL(gpu_load_change) \ OVERLAY_PARAM_BOOL(cpu_load_change) \ OVERLAY_PARAM_BOOL(core_load_change) \ OVERLAY_PARAM_BOOL(graphs) \ OVERLAY_PARAM_BOOL(legacy_layout) \ OVERLAY_PARAM_BOOL(cpu_mhz) \ OVERLAY_PARAM_BOOL(frametime) \ OVERLAY_PARAM_BOOL(frame_count) \ OVERLAY_PARAM_BOOL(resolution) \ OVERLAY_PARAM_BOOL(show_fps_limit) \ OVERLAY_PARAM_BOOL(fps_color_change) \ OVERLAY_PARAM_BOOL(custom_text_center) \ OVERLAY_PARAM_BOOL(custom_text) \ OVERLAY_PARAM_BOOL(exec) \ OVERLAY_PARAM_BOOL(vkbasalt) \ OVERLAY_PARAM_BOOL(gamemode) \ OVERLAY_PARAM_BOOL(battery) \ OVERLAY_PARAM_BOOL(battery_icon) \ OVERLAY_PARAM_BOOL(fps_only) \ OVERLAY_PARAM_BOOL(fsr) \ OVERLAY_PARAM_BOOL(mangoapp_steam) \ OVERLAY_PARAM_BOOL(debug) \ OVERLAY_PARAM_BOOL(device_battery_icon) \ OVERLAY_PARAM_BOOL(hide_fsr_sharpness) \ OVERLAY_PARAM_BOOL(fan) \ OVERLAY_PARAM_BOOL(throttling_status) \ OVERLAY_PARAM_BOOL(throttling_status_graph) \ OVERLAY_PARAM_BOOL(fcat) \ OVERLAY_PARAM_BOOL(log_versioning) \ OVERLAY_PARAM_BOOL(horizontal) \ OVERLAY_PARAM_BOOL(horizontal_stretch) \ OVERLAY_PARAM_BOOL(hud_no_margin) \ OVERLAY_PARAM_BOOL(hud_compact) \ OVERLAY_PARAM_BOOL(battery_watt) \ OVERLAY_PARAM_BOOL(battery_time) \ OVERLAY_PARAM_BOOL(exec_name) \ OVERLAY_PARAM_BOOL(trilinear) \ OVERLAY_PARAM_BOOL(bicubic) \ OVERLAY_PARAM_BOOL(retro) \ OVERLAY_PARAM_BOOL(gpu_fan) \ OVERLAY_PARAM_BOOL(gpu_voltage) \ OVERLAY_PARAM_BOOL(engine_short_names) \ OVERLAY_PARAM_BOOL(hide_engine_names) \ OVERLAY_PARAM_BOOL(hide_fps_superscript) \ OVERLAY_PARAM_BOOL(text_outline) \ OVERLAY_PARAM_BOOL(temp_fahrenheit) \ OVERLAY_PARAM_BOOL(dynamic_frame_timing) \ OVERLAY_PARAM_BOOL(duration) \ OVERLAY_PARAM_BOOL(inherit) \ OVERLAY_PARAM_BOOL(hdr) \ OVERLAY_PARAM_BOOL(refresh_rate) \ OVERLAY_PARAM_BOOL(frame_timing_detailed) \ OVERLAY_PARAM_BOOL(winesync) \ OVERLAY_PARAM_BOOL(present_mode) \ OVERLAY_PARAM_BOOL(time_no_label) \ OVERLAY_PARAM_BOOL(display_server) \ OVERLAY_PARAM_BOOL(cpu_efficiency) \ OVERLAY_PARAM_BOOL(gpu_efficiency) \ OVERLAY_PARAM_BOOL(flip_efficiency) \ OVERLAY_PARAM_BOOL(gpu_power_limit) \ OVERLAY_PARAM_BOOL(dx_api) \ OVERLAY_PARAM_CUSTOM(fps_sampling_period) \ OVERLAY_PARAM_CUSTOM(output_folder) \ OVERLAY_PARAM_CUSTOM(output_file) \ OVERLAY_PARAM_CUSTOM(font_file) \ OVERLAY_PARAM_CUSTOM(font_file_text) \ OVERLAY_PARAM_CUSTOM(font_glyph_ranges) \ OVERLAY_PARAM_CUSTOM(no_small_font) \ OVERLAY_PARAM_CUSTOM(font_size) \ OVERLAY_PARAM_CUSTOM(font_size_text) \ OVERLAY_PARAM_CUSTOM(font_size_secondary) \ OVERLAY_PARAM_CUSTOM(font_scale) \ OVERLAY_PARAM_CUSTOM(font_scale_media_player) \ OVERLAY_PARAM_CUSTOM(position) \ OVERLAY_PARAM_CUSTOM(width) \ OVERLAY_PARAM_CUSTOM(height) \ OVERLAY_PARAM_CUSTOM(no_display) \ OVERLAY_PARAM_CUSTOM(control) \ OVERLAY_PARAM_CUSTOM(fps_limit) \ OVERLAY_PARAM_CUSTOM(fps_limit_method) \ OVERLAY_PARAM_CUSTOM(vulkan_present_mode) \ OVERLAY_PARAM_CUSTOM(vsync) \ OVERLAY_PARAM_CUSTOM(gl_vsync) \ OVERLAY_PARAM_CUSTOM(gl_size_query) \ OVERLAY_PARAM_CUSTOM(gl_bind_framebuffer) \ OVERLAY_PARAM_CUSTOM(gl_dont_flip) \ OVERLAY_PARAM_CUSTOM(toggle_hud) \ OVERLAY_PARAM_CUSTOM(toggle_hud_position) \ OVERLAY_PARAM_CUSTOM(toggle_preset) \ OVERLAY_PARAM_CUSTOM(toggle_fps_limit) \ OVERLAY_PARAM_CUSTOM(toggle_logging) \ OVERLAY_PARAM_CUSTOM(reset_fps_metrics) \ OVERLAY_PARAM_CUSTOM(reload_cfg) \ OVERLAY_PARAM_CUSTOM(upload_log) \ OVERLAY_PARAM_CUSTOM(upload_logs) \ OVERLAY_PARAM_CUSTOM(offset_x) \ OVERLAY_PARAM_CUSTOM(offset_y) \ OVERLAY_PARAM_CUSTOM(background_alpha) \ OVERLAY_PARAM_CUSTOM(time_format) \ OVERLAY_PARAM_CUSTOM(io_read) \ OVERLAY_PARAM_CUSTOM(io_write) \ OVERLAY_PARAM_CUSTOM(cpu_color) \ OVERLAY_PARAM_CUSTOM(gpu_color) \ OVERLAY_PARAM_CUSTOM(vram_color) \ OVERLAY_PARAM_CUSTOM(ram_color) \ OVERLAY_PARAM_CUSTOM(engine_color) \ OVERLAY_PARAM_CUSTOM(frametime_color) \ OVERLAY_PARAM_CUSTOM(background_color) \ OVERLAY_PARAM_CUSTOM(io_color) \ OVERLAY_PARAM_CUSTOM(text_color) \ OVERLAY_PARAM_CUSTOM(wine_color) \ OVERLAY_PARAM_CUSTOM(horizontal_separator_color) \ OVERLAY_PARAM_CUSTOM(battery_color) \ OVERLAY_PARAM_CUSTOM(network_color) \ OVERLAY_PARAM_CUSTOM(alpha) \ OVERLAY_PARAM_CUSTOM(log_duration) \ OVERLAY_PARAM_CUSTOM(pci_dev) \ OVERLAY_PARAM_CUSTOM(media_player_name) \ OVERLAY_PARAM_CUSTOM(media_player_color) \ OVERLAY_PARAM_CUSTOM(media_player_format) \ OVERLAY_PARAM_CUSTOM(cpu_text) \ OVERLAY_PARAM_CUSTOM(gpu_text) \ OVERLAY_PARAM_CUSTOM(log_interval) \ OVERLAY_PARAM_CUSTOM(permit_upload) \ OVERLAY_PARAM_CUSTOM(benchmark_percentiles) \ OVERLAY_PARAM_CUSTOM(help) \ OVERLAY_PARAM_CUSTOM(gpu_load_value) \ OVERLAY_PARAM_CUSTOM(cpu_load_value) \ OVERLAY_PARAM_CUSTOM(gpu_load_color) \ OVERLAY_PARAM_CUSTOM(cpu_load_color) \ OVERLAY_PARAM_CUSTOM(fps_value) \ OVERLAY_PARAM_CUSTOM(fps_color) \ OVERLAY_PARAM_CUSTOM(cellpadding_y) \ OVERLAY_PARAM_CUSTOM(table_columns) \ OVERLAY_PARAM_CUSTOM(blacklist) \ OVERLAY_PARAM_CUSTOM(autostart_log) \ OVERLAY_PARAM_CUSTOM(round_corners) \ OVERLAY_PARAM_CUSTOM(fsr_steam_sharpness) \ OVERLAY_PARAM_CUSTOM(fcat_screen_edge) \ OVERLAY_PARAM_CUSTOM(fcat_overlay_width) \ OVERLAY_PARAM_CUSTOM(picmip) \ OVERLAY_PARAM_CUSTOM(af) \ OVERLAY_PARAM_CUSTOM(text_outline_color) \ OVERLAY_PARAM_CUSTOM(text_outline_thickness) \ OVERLAY_PARAM_CUSTOM(fps_text) \ OVERLAY_PARAM_CUSTOM(device_battery) \ OVERLAY_PARAM_CUSTOM(fps_metrics) \ OVERLAY_PARAM_CUSTOM(network) \ OVERLAY_PARAM_CUSTOM(gpu_list) \ OVERLAY_PARAM_CUSTOM(fex_stats) \ OVERLAY_PARAM_CUSTOM(ftrace) \ enum overlay_param_position { LAYER_POSITION_TOP_LEFT, LAYER_POSITION_TOP_CENTER, LAYER_POSITION_TOP_RIGHT, LAYER_POSITION_MIDDLE_LEFT, LAYER_POSITION_MIDDLE_RIGHT, LAYER_POSITION_BOTTOM_LEFT, LAYER_POSITION_BOTTOM_CENTER, LAYER_POSITION_BOTTOM_RIGHT, // Count must always be the last entry LAYER_POSITION_COUNT, }; enum overlay_plots { OVERLAY_PLOTS_frame_timing, OVERLAY_PLOTS_MAX, }; enum font_glyph_ranges { FG_KOREAN = (1u << 0), FG_CHINESE_FULL = (1u << 1), FG_CHINESE_SIMPLIFIED = (1u << 2), FG_JAPANESE = (1u << 3), FG_CYRILLIC = (1u << 4), FG_THAI = (1u << 5), FG_VIETNAMESE = (1u << 6), FG_LATIN_EXT_A = (1u << 7), FG_LATIN_EXT_B = (1u << 8), }; enum gl_size_query { GL_SIZE_DRAWABLE, GL_SIZE_VIEWPORT, GL_SIZE_SCISSORBOX, // needed? }; enum fps_limit_method { FPS_LIMIT_METHOD_EARLY, FPS_LIMIT_METHOD_LATE }; enum overlay_param_enabled { #define OVERLAY_PARAM_BOOL(name) OVERLAY_PARAM_ENABLED_##name, #define OVERLAY_PARAM_CUSTOM(name) OVERLAY_PARAMS #undef OVERLAY_PARAM_BOOL #undef OVERLAY_PARAM_CUSTOM OVERLAY_PARAM_ENABLED_MAX }; /* avoid importing vulkan headers * also combine colorspaces that use the same transfer function */ enum overlay_transfer_function { NONE = 0, SRGB = (1 << 0), PQ = (1 << 1), /* HDR10 ST2084 */ HLG = (1 << 2) /* HDR10 */ }; struct overlay_params { bool enabled[OVERLAY_PARAM_ENABLED_MAX]; enum overlay_param_position position; int control; uint32_t fps_sampling_period; /* ns */ std::vector fps_limit; enum fps_limit_method fps_limit_method; bool help; bool no_display; bool full; bool io_read, io_write, io_stats; unsigned width; unsigned height; int offset_x, offset_y; float round_corners; unsigned vsync; std::string vulkan_present_mode; std::optional m_vulkan_present_mode; int gl_vsync; int gl_bind_framebuffer {0}; enum gl_size_query gl_size_query {GL_SIZE_DRAWABLE}; bool gl_dont_flip {false}; int64_t log_duration, log_interval; unsigned cpu_color, gpu_color, vram_color, ram_color, engine_color, io_color, frametime_color, background_color, text_color, wine_color, battery_color, network_color, horizontal_separator_color; std::vector gpu_load_color; std::vector cpu_load_color; std::vector gpu_load_value; std::vector cpu_load_value; std::vector fps_color; std::vector fps_value; unsigned media_player_color; unsigned table_columns; bool no_small_font; float font_size, font_scale; float font_size_text, font_size_secondary; float font_scale_media_player; float background_alpha, alpha; float cellpadding_y; std::vector toggle_hud; std::vector toggle_preset; std::vector toggle_fps_limit; std::vector toggle_logging; std::vector reload_cfg; std::vector upload_log; std::vector upload_logs; std::vector toggle_hud_position; std::vector reset_fps_metrics; std::string time_format, output_folder, output_file; std::string pci_dev; std::string media_player_name; std::string cpu_text, fps_text; std::map cpu_custom_temp_sensor; std::vector blacklist; unsigned autostart_log; std::vector media_player_format; std::vector benchmark_percentiles; std::vector gpu_text; std::string font_file, font_file_text; uint32_t font_glyph_ranges; std::string custom_text_center; std::string custom_text; std::string config_file_path; std::unordered_map options; int permit_upload; int fsr_steam_sharpness; unsigned short fcat_screen_edge; unsigned short fcat_overlay_width; int picmip; int af; std::vector preset; size_t font_params_hash; unsigned text_outline_color; float text_outline_thickness; std::vector device_battery; std::vector fps_metrics; std::vector network; std::vector gpu_list; int transfer_function; struct fex_stats_options { bool enabled {false}; // Enabled Texts bool status {true}; bool app_type {true}; // Graphs bool hot_threads {true}; bool jit_load {true}; // Counts bool sigbus_counts {true}; bool smc_counts {true}; bool softfloat_counts {true}; }; fex_stats_options fex_stats{}; struct ftrace_options { bool enabled {false}; #ifdef HAVE_FTRACE std::vector> tracepoints; #endif }; ftrace_options ftrace {}; }; const extern char *overlay_param_names[]; void parse_overlay_config(struct overlay_params *params, const char *env, bool ignore_preset); void presets(int preset, struct overlay_params *params, bool inherit=false); bool parse_preset_config(int preset, struct overlay_params *params); void add_to_options(struct overlay_params *params, std::string option, std::string value); #ifdef __cplusplus } #endif extern std::mutex config_mtx; extern std::condition_variable config_cv; extern bool config_ready; std::shared_ptr get_params(); #endif /* MANGOHUD_OVERLAY_PARAMS_H */ ================================================ FILE: src/pci_ids.cpp ================================================ #include #include #include #include #include #include #include "pci_ids.h" std::map>> pci_ids; static std::istream& get_uncommented_line(std::istream& is, std::string &line) { while (std::getline(is, line)) { auto c = line.find("#"); if (c!=std::string::npos) line.erase(c, std::string::npos); if (line.size()) break; } return is; } void parse_pciids() { std::ifstream file; file.open("/usr/share/hwdata/pci.ids"); if (file.fail()){ file.open("/usr/share/misc/pci.ids"); if (file.fail()) SPDLOG_ERROR("can't find file pci.ids"); } std::string line; size_t tabs = 0; uint32_t ven_id = 0, dev_id = 0, subsys_ven_id = 0, subsys_dev_id = 0; std::string desc; std::stringstream ss; while(get_uncommented_line(file, line)) { tabs = line.find_first_not_of("\t"); ss.str(""); ss.clear(); ss << line; switch(tabs) { case 0: ss >> std::hex >> ven_id; if (ven_id == 0xFFFF) return; std::getline(ss, desc); pci_ids[ven_id].first = desc; break; case 1: { ss >> std::hex >> dev_id; std::getline(ss, desc); //TODO trim whitespace auto& dev = pci_ids[ven_id].second[dev_id]; dev.desc = desc; } break; case 2: { ss >> std::hex >> subsys_ven_id; ss >> subsys_dev_id; std::getline(ss, desc); auto& dev = pci_ids[ven_id].second[dev_id]; dev.subsys.push_back({subsys_ven_id, subsys_dev_id, desc}); } break; default: break; } } } ================================================ FILE: src/pci_ids.h ================================================ #pragma once #ifndef MANGOHUD_PCI_IDS_H #define MANGOHUD_PCI_IDS_H #include #include struct subsys_device { uint32_t vendor_id; uint32_t device_id; std::string desc; }; struct device { std::string desc; std::vector subsys; }; extern std::map>> pci_ids; void parse_pciids(void); #endif //MANGOHUD_PCI_IDS_H ================================================ FILE: src/real_dlsym.c ================================================ /** * \author Pyry Haulos * \date 2007-2008 * For conditions of distribution and use, see copyright notice in elfhacks.h */ #include #include #include #include #include "real_dlsym.h" #include "elfhacks.h" void *(*__dlopen)(const char *, int) = NULL; void *(*__dlsym)(void *, const char *) = NULL; char *(*__dlerror)(void) = NULL; static bool print_dlopen; static bool print_dlsym; static void get_real_functions() { eh_obj_t libdl; int ret; const char* libs[] = { #if defined(__GLIBC__) "*libdl.so*", #endif "*libc.so*", "*libc.*.so*", "*ld-musl-*.so*", }; print_dlopen = getenv("MANGOHUD_DEBUG_DLOPEN") != NULL; print_dlsym = getenv("MANGOHUD_DEBUG_DLSYM") != NULL; for (size_t i = 0; i < sizeof(libs) / sizeof(*libs); i++) { ret = eh_find_obj(&libdl, libs[i]); if (ret) continue; eh_find_sym(&libdl, "dlopen", (void **) &__dlopen); eh_find_sym(&libdl, "dlsym", (void **) &__dlsym); eh_find_sym(&libdl, "dlerror", (void **) &__dlerror); eh_destroy_obj(&libdl); if (__dlopen && __dlsym && __dlerror) break; __dlopen = NULL; __dlsym = NULL; __dlerror = NULL; } if (!__dlopen && !__dlsym && !__dlerror) { fprintf(stderr, "MANGOHUD: Can't get dlopen(), dlsym() and dlerror()\n"); exit(ret ? ret : 1); } } /** * \brief dlopen() wrapper, just passes calls to real dlopen() * and writes information to standard output */ void *real_dlopen(const char *filename, int flag) { if (__dlopen == NULL) get_real_functions(); void *result = __dlopen(filename, flag); if (print_dlopen) { printf("dlopen(%s, ", filename); const char *fmt = "%s"; #define FLAG(test) if (flag & test) { printf(fmt, #test); fmt = "|%s"; } FLAG(RTLD_LAZY) FLAG(RTLD_NOW) FLAG(RTLD_GLOBAL) FLAG(RTLD_LOCAL) FLAG(RTLD_NODELETE) FLAG(RTLD_NOLOAD) #ifdef RTLD_DEEPBIND FLAG(RTLD_DEEPBIND) #endif #undef FLAG printf(") = %p\n", result); } return result; } /** * \brief dlsym() wrapper, passes calls to real dlsym() and * writes information to standard output */ void *real_dlsym(void *handle, const char *symbol) { if (__dlsym == NULL) get_real_functions(); void *result = __dlsym(handle, symbol); if (print_dlsym) printf("dlsym(%p, %s) = %p\n", handle, symbol, result); return result; } char* real_dlerror(void) { if (__dlerror == NULL) get_real_functions(); return __dlerror(); } void* get_proc_address(const char* name) { return real_dlsym(RTLD_NEXT, name); } ================================================ FILE: src/real_dlsym.h ================================================ #pragma once #ifndef MANGOHUD_REAL_DLSYM_H #define MANGOHUD_REAL_DLSYM_H #define EXPORT_C_(type) extern "C" __attribute__((__visibility__("default"))) type #ifdef __cplusplus extern "C" { #endif void *real_dlopen(const char *filename, int flag); void* real_dlsym( void*, const char* ); void* get_proc_address(const char* name); char* real_dlerror(void); #ifdef __cplusplus } #endif #endif //MANGOHUD_REAL_DLSYM_H ================================================ FILE: src/shared_x11.cpp ================================================ #include #include #include #include #include #include "shared_x11.h" #include "loaders/loader_x11.h" #include "hud_elements.h" static std::unique_ptr> display; bool init_x11() { static bool failed = false; if (failed) return false; if (display) return true; auto libx11 = get_libx11(); if (!libx11->IsLoaded()) { SPDLOG_ERROR("X11 loader failed to load"); failed = true; return false; } const char *displayid = getenv("DISPLAY"); if (!displayid || !*displayid) { SPDLOG_DEBUG("DISPLAY env is not set or empty"); failed = true; return false; } display = { libx11->XOpenDisplay(displayid), [libx11](Display* dpy) { if (dpy) libx11->XCloseDisplay(dpy); } }; failed = !display; if (failed) { SPDLOG_ERROR("XOpenDisplay failed to open display '{}'", displayid); return false; } if (HUDElements.display_server == HUDElements.display_servers::UNKNOWN) { int opcode, event, error; if (libx11->XQueryExtension(display.get(), "XWAYLAND", &opcode, &event, &error)) HUDElements.display_server = HUDElements.display_servers::XWAYLAND; else HUDElements.display_server = HUDElements.display_servers::XORG; } return !!display; } Display* get_xdisplay() { return display.get(); } ================================================ FILE: src/shared_x11.h ================================================ #pragma once #ifndef MANGOHUD_SHARED_X11_H #define MANGOHUD_SHARED_X11_H #include Display* get_xdisplay(); bool init_x11(); #endif //MANGOHUD_SHARED_X11_H ================================================ FILE: src/shell.cpp ================================================ #include "shell.h" #include #include #include #include #include "string_utils.h" #include std::string Shell::readOutput() { std::this_thread::sleep_for(std::chrono::milliseconds(50)); std::array buffer; std::string result; ssize_t count; while ((count = ::read(from_shell[0], buffer.data(), buffer.size())) > 0) { result.append(buffer.data(), count); } // Split the result into lines and return the last line std::istringstream stream(result); std::string line; std::string last_line; while (std::getline(stream, line)) { last_line = line; } SPDLOG_DEBUG("Shell: recieved output: {}", last_line); return last_line; } Shell::Shell() { if (stat("/run/pressure-vessel", &stat_buffer) == 0) runtime = true; static bool failed; if (pipe(to_shell) == -1) { SPDLOG_ERROR("Failed to create to_shell pipe: {}", strerror(errno)); failed = true; } if (pipe(from_shell) == -1) { SPDLOG_ERROR("Failed to create from_shell pipe: {}", strerror(errno)); failed = true; } // if either pipe fails, there's no point in continuing. if (failed){ SPDLOG_ERROR("Shell has failed, will not be able to use exec"); return; } shell_pid = fork(); if (shell_pid == 0) { // Child process close(to_shell[1]); close(from_shell[0]); dup2(to_shell[0], STDIN_FILENO); dup2(from_shell[1], STDOUT_FILENO); dup2(from_shell[1], STDERR_FILENO); execl("/bin/sh", "sh", "-c", "unset LD_PRELOAD; exec /bin/sh", nullptr); exit(1); // Exit if execl fails } else { close(to_shell[0]); close(from_shell[1]); // Set the read end of the from_shell pipe to non-blocking setNonBlocking(from_shell[0]); } success = true; } std::string Shell::exec(std::string cmd) { if (!success) return ""; writeCommand(cmd); return readOutput(); } void Shell::writeCommand(std::string command) { if (write(to_shell[1], command.c_str(), command.length()) == -1) SPDLOG_ERROR("Failed to write to shell"); if (runtime) command = "steam-runtime-launch-client --alongside-steam --host -- " + command; trim(command); SPDLOG_DEBUG("Shell: wrote command: {}", command); } Shell::~Shell() { close(to_shell[1]); close(from_shell[0]); waitpid(shell_pid, nullptr, 0); } ================================================ FILE: src/shell.h ================================================ #pragma once #include #include #include #ifdef __linux__ #include #endif #include #include #include class Shell { private: int to_shell[2]; int from_shell[2]; pid_t shell_pid; bool success; struct stat stat_buffer; bool runtime = false; #ifdef __linux__ void setNonBlocking(int fd) { int flags = fcntl(fd, F_GETFL, 0); fcntl(fd, F_SETFL, flags | O_NONBLOCK); } #endif void writeCommand(std::string command); std::string readOutput(); public: Shell(); ~Shell(); std::string exec(std::string cmd); }; extern std::unique_ptr shell; ================================================ FILE: src/string_utils.h ================================================ #pragma once #ifndef MANGOHUD_STRING_UTILS_H #define MANGOHUD_STRING_UTILS_H #include #include #include #include #include #include #include #include #include #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-function" #ifdef __LCC__ #pragma diag_suppress 3313 // Suppress unused function warnings #endif // https://stackoverflow.com/questions/216823/whats-the-best-way-to-trim-stdstring#217605 // trim from start (in place) static inline void ltrim(std::string &s) { s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](int ch) { return !std::isspace(ch); })); } // trim from end (in place) static inline void rtrim(std::string &s) { s.erase(std::find_if(s.rbegin(), s.rend(), [](int ch) { return !std::isspace(ch); }).base(), s.end()); } // trim from both ends (in place) static inline void trim(std::string &s) { ltrim(s); rtrim(s); } // trim from start (copying) static inline std::string ltrim_copy(std::string s) { ltrim(s); return s; } // trim from end (copying) static inline std::string rtrim_copy(std::string s) { rtrim(s); return s; } // trim from both ends (copying) static inline std::string trim_copy(std::string s) { trim(s); return s; } static bool starts_with(const std::string& s, const char *t) { return s.rfind(t, 0) == 0; } static bool ends_with(const std::string& s, const char *t, bool icase = false) { std::string s0(s); std::string s1(t); if (s0.size() < s1.size()) return false; if (icase) { std::transform(s0.begin(), s0.end(), s0.begin(), ::tolower); std::transform(s1.begin(), s1.end(), s1.begin(), ::tolower); } size_t pos = s0.size() - s1.size(); return (s0.rfind(s1, pos) == pos); } static bool iequal(std::string_view lhs, std::string_view rhs) { return lhs.size() == rhs.size() && std::equal(lhs.begin(), lhs.end(), rhs.begin(), [](unsigned char x, unsigned char y) { return std::toupper(x) == std::toupper(y); }); }; static std::string_view strip_prefix(const std::string_view input, const std::string_view prefix) { if (input.size() >= prefix.size() && iequal(input.substr(0, prefix.size()), prefix)) return input.substr(prefix.size()); return input; }; static std::string_view strip_suffix(const std::string_view input, const std::string_view suffix) { if (input.size() >= suffix.size() && iequal(input.substr(input.size() - suffix.size()), suffix)) return input.substr(0, input.size() - suffix.size()); return input; }; template static std::string itox(T i) { std::stringstream ss; ss << "0x" << std::setfill ('0') << std::setw(sizeof(T) * 2) << std::hex << i; return ss.str(); } static bool try_stoi(int& val, const std::string& str) { if (sscanf(str.c_str(), "%d", &val) == 1) return true; return false; } static bool try_stoull(unsigned long long& val, const std::string& str) { if (sscanf(str.c_str(), "%llu", &val) == 1) return true; return false; } static float parse_float(const std::string& s, std::size_t* float_len = nullptr){ std::stringstream ss(s); ss.imbue(std::locale::classic()); float ret; ss >> ret; if(ss.fail()) throw std::invalid_argument("parse_float: Not a float"); if(float_len != nullptr){ auto pos = ss.tellg(); if(ss.fail()) *float_len = s.size(); else *float_len = pos; } return ret; } static std::vector str_tokenize(const std::string& s, const std::string& delims = ",:+") { std::vector v; size_t old_n = 0, new_n = 0; while (old_n < s.size()){ new_n = s.find_first_of(delims, old_n); auto c = s.substr(old_n, new_n - old_n); if (old_n != new_n) v.push_back(c); if (new_n == std::string::npos) break; old_n = new_n + 1; } return v; } static void trim_char(char* str) { if(!str) return; char* ptr = str; int len = strlen(ptr); while(len-1 > 0 && isspace(ptr[len-1])) ptr[--len] = 0; while(*ptr && isspace(*ptr)) ++ptr, --len; memmove(str, ptr, len + 1); } #pragma GCC diagnostic pop #endif //MANGOHUD_STRING_UTILS_H ================================================ FILE: src/timing.hpp ================================================ #pragma once #ifndef MANGOHUD_TIMING_HPP #define MANGOHUD_TIMING_HPP #include #include "mesa/util/os_time.h" class MesaClock { public: using rep = int64_t; using period = std::nano; using duration = std::chrono::duration; using time_point = std::chrono::time_point; const static bool is_steady = true; static time_point now() noexcept { return time_point(duration(os_time_get_nano())); } }; using Clock = MesaClock; #endif //MANGOHUD_TIMING_HPP ================================================ FILE: src/vulkan.cpp ================================================ /* * Copyright © 2019 Intel Corporation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice (including the next * paragraph) shall be included in all copies or substantial portions of the * Software. * * 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 OR COPYRIGHT HOLDERS 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. */ #ifdef _WIN32 #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "mesa/util/macros.h" // defines "restrict" for vk_util.h #include "mesa/util/os_socket.h" #include #include #include #include #include "vk_enum_to_str.h" #include "vk_dispatch_table.h" #include "overlay.h" #include "notify.h" #include "blacklist.h" #include "pci_ids.h" #if defined(HAVE_WAYLAND) #include "wayland_hook.h" #endif #include "real_dlsym.h" #include "file_utils.h" #ifdef __linux__ #include #include "implot.h" #endif #include "imgui_utils.h" #include "fps_limiter.h" using namespace std; float offset_x, offset_y, hudSpacing; int hudFirstRow, hudSecondRow; VkPhysicalDeviceDriverProperties driverProps = {}; #if !defined(_WIN32) namespace MangoHud { namespace GL { extern swapchain_stats sw_stats; }} #endif /* Mapped from VkInstace/VkPhysicalDevice */ struct instance_data { struct vk_instance_dispatch_table vtable; struct vk_physical_device_dispatch_table pd_vtable; VkInstance instance; struct overlay_params params; uint32_t api_version; string engineName, engineVersion; enum EngineTypes engine; notify_thread notifier; int control_client; uint32_t applicationVersion; }; /* Mapped from VkDevice */ struct queue_data; struct device_data { struct instance_data *instance; PFN_vkSetDeviceLoaderData set_device_loader_data; struct vk_device_dispatch_table vtable; VkPhysicalDevice physical_device; VkDevice device; VkPhysicalDeviceProperties properties; struct queue_data *graphic_queue; std::vector queues; }; /* Mapped from VkCommandBuffer */ struct command_buffer_data { struct device_data *device; VkCommandBufferLevel level; VkCommandBuffer cmd_buffer; struct queue_data *queue_data; }; /* Mapped from VkQueue */ struct queue_data { struct device_data *device; VkQueue queue; VkQueueFlags flags; uint32_t family_index; }; struct overlay_draw { VkCommandBuffer command_buffer; VkSemaphore cross_engine_semaphore; VkSemaphore semaphore; VkFence fence; VkBuffer vertex_buffer; VkDeviceMemory vertex_buffer_mem; VkDeviceSize vertex_buffer_size; VkBuffer index_buffer; VkDeviceMemory index_buffer_mem; VkDeviceSize index_buffer_size; }; /* Mapped from VkSwapchainKHR */ struct swapchain_data { struct device_data *device; VkSwapchainKHR swapchain; unsigned width, height; VkFormat format; std::vector images; std::vector image_views; std::vector framebuffers; VkRenderPass render_pass; VkDescriptorPool descriptor_pool; VkDescriptorSetLayout descriptor_layout; VkDescriptorSet descriptor_set; VkSampler font_sampler; VkPipelineLayout pipeline_layout; VkPipeline pipeline; VkCommandPool command_pool; std::vector draws; /* vector of struct overlay_draw */ bool font_uploaded; VkImage font_image; VkImageView font_image_view; VkDeviceMemory font_mem; VkBuffer upload_font_buffer; VkDeviceMemory upload_font_buffer_mem; struct imgui_contexts imgui_contexts; ImFontAtlas* font_atlas; ImVec2 window_size; struct swapchain_stats sw_stats; }; // single global lock, for simplicity std::mutex global_lock; typedef std::lock_guard scoped_lock; std::unordered_map vk_object_to_data; thread_local ImGuiContext* __MesaImGui; #define HKEY(obj) ((uint64_t)(obj)) #define FIND(type, obj) (reinterpret_cast(find_object_data(HKEY(obj)))) static void *find_object_data(uint64_t obj) { ::scoped_lock lk(global_lock); return vk_object_to_data[obj]; } static void map_object(uint64_t obj, void *data) { ::scoped_lock lk(global_lock); vk_object_to_data[obj] = data; } static void unmap_object(uint64_t obj) { ::scoped_lock lk(global_lock); vk_object_to_data.erase(obj); } /**/ #define VK_CHECK(expr) \ do { \ VkResult __result = (expr); \ if (__result != VK_SUCCESS) { \ SPDLOG_ERROR("'{}' line {} failed with {}", \ #expr, __LINE__, vk_Result_to_str(__result)); \ } \ } while (0) namespace { // Walks a chain and returns a pointer-to-pointer handle to the given type or `nullptr` if not found. // The handle allows the caller to modify and relink the chain. VkBaseInStructure ** vk_find_next_struct(void **chain, VkStructureType type) { VkBaseInStructure **pPrev = (VkBaseInStructure **)chain; while (*pPrev) { if ((*pPrev)->sType == type) return pPrev; pPrev = (VkBaseInStructure **)&(*pPrev)->pNext; } return nullptr; } } /**/ static void shutdown_swapchain_font(struct swapchain_data*); static VkLayerInstanceCreateInfo *get_instance_chain_info(const VkInstanceCreateInfo *pCreateInfo, VkLayerFunction func) { vk_foreach_struct(item, pCreateInfo->pNext) { if (item->sType == VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO && ((VkLayerInstanceCreateInfo *) item)->function == func) return (VkLayerInstanceCreateInfo *) item; } UNREACHABLE("instance chain info not found"); return NULL; } static VkLayerDeviceCreateInfo *get_device_chain_info(const VkDeviceCreateInfo *pCreateInfo, VkLayerFunction func) { vk_foreach_struct(item, pCreateInfo->pNext) { if (item->sType == VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO && ((VkLayerDeviceCreateInfo *) item)->function == func) return (VkLayerDeviceCreateInfo *)item; } UNREACHABLE("device chain info not found"); return NULL; } /**/ static struct instance_data *new_instance_data(VkInstance instance) { struct instance_data *data = new instance_data(); data->instance = instance; data->params = {}; data->params.control = -1; data->control_client = -1; map_object(HKEY(data->instance), data); return data; } static void destroy_instance_data(struct instance_data *data) { if (data->params.control >= 0) os_socket_close(data->params.control); unmap_object(HKEY(data->instance)); delete data; } static void instance_data_map_physical_devices(struct instance_data *instance_data, bool map) { uint32_t physicalDeviceCount = 0; instance_data->vtable.EnumeratePhysicalDevices(instance_data->instance, &physicalDeviceCount, NULL); std::vector physicalDevices(physicalDeviceCount); instance_data->vtable.EnumeratePhysicalDevices(instance_data->instance, &physicalDeviceCount, physicalDevices.data()); for (uint32_t i = 0; i < physicalDeviceCount; i++) { if (map) map_object(HKEY(physicalDevices[i]), instance_data); else unmap_object(HKEY(physicalDevices[i])); } } /**/ static struct device_data *new_device_data(VkDevice device, struct instance_data *instance) { struct device_data *data = new device_data(); data->instance = instance; data->device = device; map_object(HKEY(data->device), data); return data; } static struct queue_data *new_queue_data(VkQueue queue, const VkQueueFamilyProperties *family_props, uint32_t family_index, struct device_data *device_data) { struct queue_data *data = new queue_data(); data->device = device_data; data->queue = queue; data->flags = family_props->queueFlags; data->family_index = family_index; map_object(HKEY(data->queue), data); if (data->flags & VK_QUEUE_GRAPHICS_BIT) device_data->graphic_queue = data; return data; } static void destroy_queue(struct queue_data *data) { unmap_object(HKEY(data->queue)); delete data; } static void device_map_queues(struct device_data *data, const VkDeviceCreateInfo *pCreateInfo) { uint32_t n_queues = 0; for (uint32_t i = 0; i < pCreateInfo->queueCreateInfoCount; i++) n_queues += pCreateInfo->pQueueCreateInfos[i].queueCount; data->queues.resize(n_queues); struct instance_data *instance_data = data->instance; uint32_t n_family_props; instance_data->pd_vtable.GetPhysicalDeviceQueueFamilyProperties(data->physical_device, &n_family_props, NULL); std::vector family_props(n_family_props); instance_data->pd_vtable.GetPhysicalDeviceQueueFamilyProperties(data->physical_device, &n_family_props, family_props.data()); uint32_t queue_index = 0; for (uint32_t i = 0; i < pCreateInfo->queueCreateInfoCount; i++) { for (uint32_t j = 0; j < pCreateInfo->pQueueCreateInfos[i].queueCount; j++) { VkQueue queue; data->vtable.GetDeviceQueue(data->device, pCreateInfo->pQueueCreateInfos[i].queueFamilyIndex, j, &queue); VK_CHECK(data->set_device_loader_data(data->device, queue)); data->queues[queue_index++] = new_queue_data(queue, &family_props[pCreateInfo->pQueueCreateInfos[i].queueFamilyIndex], pCreateInfo->pQueueCreateInfos[i].queueFamilyIndex, data); } } } static void device_unmap_queues(struct device_data *data) { for (auto q : data->queues) destroy_queue(q); } static void destroy_device_data(struct device_data *data) { unmap_object(HKEY(data->device)); delete data; } /**/ static struct command_buffer_data *new_command_buffer_data(VkCommandBuffer cmd_buffer, VkCommandBufferLevel level, struct device_data *device_data) { struct command_buffer_data *data = new command_buffer_data(); data->device = device_data; data->cmd_buffer = cmd_buffer; data->level = level; map_object(HKEY(data->cmd_buffer), data); return data; } static void destroy_command_buffer_data(struct command_buffer_data *data) { unmap_object(HKEY(data->cmd_buffer)); delete data; } /**/ static struct swapchain_data *new_swapchain_data(VkSwapchainKHR swapchain, struct device_data *device_data) { struct instance_data *instance_data = device_data->instance; struct swapchain_data *data = new swapchain_data(); data->device = device_data; data->swapchain = swapchain; data->window_size = ImVec2(instance_data->params.width, instance_data->params.height); data->font_atlas = IM_NEW(ImFontAtlas); map_object(HKEY(data->swapchain), data); return data; } static void destroy_swapchain_data(struct swapchain_data *data) { unmap_object(HKEY(data->swapchain)); delete data; } static struct overlay_draw *get_overlay_draw(struct swapchain_data *data, unsigned image_idx) { struct device_data *device_data = data->device; const size_t images_count = data->images.size(); if (data->draws.size() < images_count) { data->draws.resize(images_count, nullptr); } struct overlay_draw *draw = data->draws[image_idx]; VkSemaphoreCreateInfo sem_info = {}; sem_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; if (draw) { VK_CHECK(device_data->vtable.WaitForFences(device_data->device, 1, &draw->fence, VK_TRUE, ~0ull)); VK_CHECK(device_data->vtable.ResetFences(device_data->device, 1, &draw->fence)); return draw; } draw = new overlay_draw(); VkCommandBufferAllocateInfo cmd_buffer_info = {}; cmd_buffer_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; cmd_buffer_info.commandPool = data->command_pool; cmd_buffer_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; cmd_buffer_info.commandBufferCount = 1; VK_CHECK(device_data->vtable.AllocateCommandBuffers(device_data->device, &cmd_buffer_info, &draw->command_buffer)); VK_CHECK(device_data->set_device_loader_data(device_data->device, draw->command_buffer)); VkFenceCreateInfo fence_info = {}; fence_info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; VK_CHECK(device_data->vtable.CreateFence(device_data->device, &fence_info, NULL, &draw->fence)); VK_CHECK(device_data->vtable.CreateSemaphore(device_data->device, &sem_info, NULL, &draw->semaphore)); VK_CHECK(device_data->vtable.CreateSemaphore(device_data->device, &sem_info, NULL, &draw->cross_engine_semaphore)); data->draws[image_idx] = draw; return draw; } static void snapshot_swapchain_frame(struct swapchain_data *data) { struct device_data *device_data = data->device; struct instance_data *instance_data = device_data->instance; update_hud_info(data->sw_stats, instance_data->params, device_data->properties.vendorID); check_keybinds(instance_data->params); #ifdef __linux__ if (instance_data->params.control >= 0) { control_client_check(instance_data->params.control, instance_data->control_client, gpu.c_str()); process_control_socket(instance_data->control_client, instance_data->params); } #endif } static void compute_swapchain_display(struct swapchain_data *data) { struct device_data *device_data = data->device; struct instance_data *instance_data = device_data->instance; if (get_params()->no_display) return; auto saved_imgui_context = get_current_imgui_contexts(); make_imgui_contexts_current(data->imgui_contexts); if (HUDElements.colors.update) HUDElements.convert_colors(instance_data->params); ImGui::NewFrame(); { ::scoped_lock lk(instance_data->notifier.mutex); overlay_new_frame(instance_data->params); position_layer(data->sw_stats, instance_data->params, data->window_size); render_imgui(data->sw_stats, instance_data->params, data->window_size, true); overlay_end_frame(); } ImGui::EndFrame(); ImGui::Render(); make_imgui_contexts_current(saved_imgui_context); } static uint32_t vk_memory_type(struct device_data *data, VkMemoryPropertyFlags properties, uint32_t type_bits) { VkPhysicalDeviceMemoryProperties prop; data->instance->pd_vtable.GetPhysicalDeviceMemoryProperties(data->physical_device, &prop); for (uint32_t i = 0; i < prop.memoryTypeCount; i++) if ((prop.memoryTypes[i].propertyFlags & properties) == properties && type_bits & (1<device; /* Descriptor set */ VkDescriptorImageInfo desc_image[1] = {}; desc_image[0].sampler = data->font_sampler; desc_image[0].imageView = image_view; desc_image[0].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; VkWriteDescriptorSet write_desc[1] = {}; write_desc[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; write_desc[0].dstSet = set; write_desc[0].descriptorCount = 1; write_desc[0].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; write_desc[0].pImageInfo = desc_image; device_data->vtable.UpdateDescriptorSets(device_data->device, 1, write_desc, 0, NULL); } static void upload_image_data(struct device_data *device_data, VkCommandBuffer command_buffer, void *pixels, VkDeviceSize upload_size, uint32_t width, uint32_t height, VkBuffer& upload_buffer, VkDeviceMemory& upload_buffer_mem, VkImage image) { /* Upload buffer */ VkBufferCreateInfo buffer_info = {}; buffer_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; buffer_info.size = upload_size; buffer_info.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; VK_CHECK(device_data->vtable.CreateBuffer(device_data->device, &buffer_info, NULL, &upload_buffer)); VkMemoryRequirements upload_buffer_req; device_data->vtable.GetBufferMemoryRequirements(device_data->device, upload_buffer, &upload_buffer_req); VkMemoryAllocateInfo upload_alloc_info = {}; upload_alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; upload_alloc_info.allocationSize = upload_buffer_req.size; upload_alloc_info.memoryTypeIndex = vk_memory_type(device_data, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, upload_buffer_req.memoryTypeBits); VK_CHECK(device_data->vtable.AllocateMemory(device_data->device, &upload_alloc_info, NULL, &upload_buffer_mem)); VK_CHECK(device_data->vtable.BindBufferMemory(device_data->device, upload_buffer, upload_buffer_mem, 0)); /* Upload to Buffer */ char* map = NULL; VK_CHECK(device_data->vtable.MapMemory(device_data->device, upload_buffer_mem, 0, upload_size, 0, (void**)(&map))); memcpy(map, pixels, upload_size); VkMappedMemoryRange range[1] = {}; range[0].sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE; range[0].memory = upload_buffer_mem; range[0].size = upload_size; VK_CHECK(device_data->vtable.FlushMappedMemoryRanges(device_data->device, 1, range)); device_data->vtable.UnmapMemory(device_data->device, upload_buffer_mem); /* Copy buffer to image */ VkImageMemoryBarrier copy_barrier[1] = {}; copy_barrier[0].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; copy_barrier[0].dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; copy_barrier[0].oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; copy_barrier[0].newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; copy_barrier[0].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; copy_barrier[0].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; copy_barrier[0].image = image; copy_barrier[0].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; copy_barrier[0].subresourceRange.levelCount = 1; copy_barrier[0].subresourceRange.layerCount = 1; device_data->vtable.CmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, NULL, 0, NULL, 1, copy_barrier); VkBufferImageCopy region = {}; region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; region.imageSubresource.layerCount = 1; region.imageExtent.width = width; region.imageExtent.height = height; region.imageExtent.depth = 1; device_data->vtable.CmdCopyBufferToImage(command_buffer, upload_buffer, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion); VkImageMemoryBarrier use_barrier[1] = {}; use_barrier[0].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; use_barrier[0].srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; use_barrier[0].dstAccessMask = VK_ACCESS_SHADER_READ_BIT; use_barrier[0].oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; use_barrier[0].newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; use_barrier[0].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; use_barrier[0].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; use_barrier[0].image = image; use_barrier[0].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; use_barrier[0].subresourceRange.levelCount = 1; use_barrier[0].subresourceRange.layerCount = 1; device_data->vtable.CmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, NULL, 0, NULL, 1, use_barrier); } static void create_image(struct swapchain_data *data, VkDescriptorSet descriptor_set, uint32_t width, uint32_t height, VkFormat format, VkImage& image, VkDeviceMemory& image_mem, VkImageView& image_view) { struct device_data *device_data = data->device; VkImageCreateInfo image_info = {}; image_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; image_info.imageType = VK_IMAGE_TYPE_2D; image_info.format = format; image_info.extent.width = width; image_info.extent.height = height; image_info.extent.depth = 1; image_info.mipLevels = 1; image_info.arrayLayers = 1; image_info.samples = VK_SAMPLE_COUNT_1_BIT; image_info.tiling = VK_IMAGE_TILING_OPTIMAL; image_info.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT; image_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; image_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; VK_CHECK(device_data->vtable.CreateImage(device_data->device, &image_info, NULL, &image)); VkMemoryRequirements font_image_req; device_data->vtable.GetImageMemoryRequirements(device_data->device, image, &font_image_req); VkMemoryAllocateInfo image_alloc_info = {}; image_alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; image_alloc_info.allocationSize = font_image_req.size; image_alloc_info.memoryTypeIndex = vk_memory_type(device_data, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, font_image_req.memoryTypeBits); VK_CHECK(device_data->vtable.AllocateMemory(device_data->device, &image_alloc_info, NULL, &image_mem)); VK_CHECK(device_data->vtable.BindImageMemory(device_data->device, image, image_mem, 0)); /* Font image view */ VkImageViewCreateInfo view_info = {}; view_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; view_info.image = image; view_info.viewType = VK_IMAGE_VIEW_TYPE_2D; view_info.format = format; view_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; view_info.subresourceRange.levelCount = 1; view_info.subresourceRange.layerCount = 1; VK_CHECK(device_data->vtable.CreateImageView(device_data->device, &view_info, NULL, &image_view)); update_image_descriptor(data, image_view, descriptor_set); } static VkDescriptorSet create_image_with_desc(struct swapchain_data *data, uint32_t width, uint32_t height, VkFormat format, VkImage& image, VkDeviceMemory& image_mem, VkImageView& image_view) { struct device_data *device_data = data->device; VkDescriptorSet descriptor_set {}; VkDescriptorSetAllocateInfo alloc_info {}; alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; alloc_info.descriptorPool = data->descriptor_pool; alloc_info.descriptorSetCount = 1; alloc_info.pSetLayouts = &data->descriptor_layout; VK_CHECK(device_data->vtable.AllocateDescriptorSets(device_data->device, &alloc_info, &descriptor_set)); create_image(data, descriptor_set, width, height, format, image, image_mem, image_view); return descriptor_set; } static void check_fonts(struct swapchain_data* data) { struct device_data *device_data = data->device; struct instance_data *instance_data = device_data->instance; auto& params = instance_data->params; if (params.font_params_hash != data->sw_stats.font_params_hash) { SPDLOG_DEBUG("Recreating font image"); VkDescriptorSet desc_set = (VkDescriptorSet)data->font_atlas->TexID; create_fonts(data->font_atlas, instance_data->params, data->sw_stats.font_small, data->sw_stats.font_text, data->sw_stats.font_secondary); unsigned char* pixels; int width, height; data->font_atlas->GetTexDataAsAlpha8(&pixels, &width, &height); // wait for rendering to complete, if any device_data->vtable.DeviceWaitIdle(device_data->device); shutdown_swapchain_font(data); if (desc_set) create_image(data, desc_set, width, height, VK_FORMAT_R8_UNORM, data->font_image, data->font_mem, data->font_image_view); else desc_set = create_image_with_desc(data, width, height, VK_FORMAT_R8_UNORM, data->font_image, data->font_mem, data->font_image_view); data->font_atlas->SetTexID((ImTextureID)desc_set); data->font_uploaded = false; data->sw_stats.font_params_hash = params.font_params_hash; SPDLOG_DEBUG("Default font tex size: {}x{}px", width, height); } } static void ensure_swapchain_fonts(struct swapchain_data *data, VkCommandBuffer command_buffer) { struct device_data *device_data = data->device; check_fonts(data); if (data->font_uploaded) return; data->font_uploaded = true; unsigned char* pixels; int width, height; data->font_atlas->GetTexDataAsAlpha8(&pixels, &width, &height); size_t upload_size = width * height * 1 * sizeof(char); upload_image_data(device_data, command_buffer, pixels, upload_size, width, height, data->upload_font_buffer, data->upload_font_buffer_mem, data->font_image); } static void CreateOrResizeBuffer(struct device_data *data, VkBuffer *buffer, VkDeviceMemory *buffer_memory, VkDeviceSize *buffer_size, size_t new_size, VkBufferUsageFlagBits usage) { if (*buffer != VK_NULL_HANDLE) data->vtable.DestroyBuffer(data->device, *buffer, NULL); if (*buffer_memory) data->vtable.FreeMemory(data->device, *buffer_memory, NULL); if (data->properties.limits.nonCoherentAtomSize > 0) { VkDeviceSize atom_size = data->properties.limits.nonCoherentAtomSize - 1; new_size = (new_size + atom_size) & ~atom_size; } VkBufferCreateInfo buffer_info = {}; buffer_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; buffer_info.size = new_size; buffer_info.usage = usage; buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; VK_CHECK(data->vtable.CreateBuffer(data->device, &buffer_info, NULL, buffer)); VkMemoryRequirements req; data->vtable.GetBufferMemoryRequirements(data->device, *buffer, &req); VkMemoryAllocateInfo alloc_info = {}; alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; alloc_info.allocationSize = req.size; alloc_info.memoryTypeIndex = vk_memory_type(data, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, req.memoryTypeBits); VK_CHECK(data->vtable.AllocateMemory(data->device, &alloc_info, NULL, buffer_memory)); VK_CHECK(data->vtable.BindBufferMemory(data->device, *buffer, *buffer_memory, 0)); *buffer_size = new_size; } static struct overlay_draw *render_swapchain_display(struct swapchain_data *data, struct queue_data *present_queue, const VkSemaphore *wait_semaphores, unsigned n_wait_semaphores, unsigned image_index) { auto saved_imgui_context = get_current_imgui_contexts(); make_imgui_contexts_current(data->imgui_contexts); ImDrawData* draw_data = ImGui::GetDrawData(); struct device_data *device_data = data->device; if (!draw_data || draw_data->TotalVtxCount == 0 || get_params()->no_display) { make_imgui_contexts_current(saved_imgui_context); return nullptr; } struct overlay_draw *draw = get_overlay_draw(data, image_index); device_data->vtable.ResetCommandBuffer(draw->command_buffer, 0); VkRenderPassBeginInfo render_pass_info = {}; render_pass_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; render_pass_info.renderPass = data->render_pass; render_pass_info.framebuffer = data->framebuffers[image_index]; render_pass_info.renderArea.extent.width = data->width; render_pass_info.renderArea.extent.height = data->height; VkCommandBufferBeginInfo buffer_begin_info = {}; buffer_begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; device_data->vtable.BeginCommandBuffer(draw->command_buffer, &buffer_begin_info); ensure_swapchain_fonts(data, draw->command_buffer); /* Bounce the image to display back to color attachment layout for * rendering on top of it. */ VkImageMemoryBarrier imb; imb.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; imb.pNext = nullptr; imb.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; imb.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; imb.oldLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; imb.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; imb.image = data->images[image_index]; imb.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; imb.subresourceRange.baseMipLevel = 0; imb.subresourceRange.levelCount = 1; imb.subresourceRange.baseArrayLayer = 0; imb.subresourceRange.layerCount = 1; imb.srcQueueFamilyIndex = present_queue->family_index; imb.dstQueueFamilyIndex = device_data->graphic_queue->family_index; device_data->vtable.CmdPipelineBarrier(draw->command_buffer, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, 0, /* dependency flags */ 0, nullptr, /* memory barriers */ 0, nullptr, /* buffer memory barriers */ 1, &imb); /* image memory barriers */ device_data->vtable.CmdBeginRenderPass(draw->command_buffer, &render_pass_info, VK_SUBPASS_CONTENTS_INLINE); /* Create/Resize vertex & index buffers */ size_t vertex_size = draw_data->TotalVtxCount * sizeof(ImDrawVert); size_t index_size = draw_data->TotalIdxCount * sizeof(ImDrawIdx); if (draw->vertex_buffer_size < vertex_size) { CreateOrResizeBuffer(device_data, &draw->vertex_buffer, &draw->vertex_buffer_mem, &draw->vertex_buffer_size, vertex_size, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT); } if (draw->index_buffer_size < index_size) { CreateOrResizeBuffer(device_data, &draw->index_buffer, &draw->index_buffer_mem, &draw->index_buffer_size, index_size, VK_BUFFER_USAGE_INDEX_BUFFER_BIT); } /* Upload vertex & index data */ ImDrawVert* vtx_dst = NULL; ImDrawIdx* idx_dst = NULL; VK_CHECK(device_data->vtable.MapMemory(device_data->device, draw->vertex_buffer_mem, 0, draw->vertex_buffer_size, 0, (void**)(&vtx_dst))); VK_CHECK(device_data->vtable.MapMemory(device_data->device, draw->index_buffer_mem, 0, draw->index_buffer_size, 0, (void**)(&idx_dst))); for (int n = 0; n < draw_data->CmdListsCount; n++) { const ImDrawList* cmd_list = draw_data->CmdLists[n]; memcpy(vtx_dst, cmd_list->VtxBuffer.Data, cmd_list->VtxBuffer.Size * sizeof(ImDrawVert)); memcpy(idx_dst, cmd_list->IdxBuffer.Data, cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx)); vtx_dst += cmd_list->VtxBuffer.Size; idx_dst += cmd_list->IdxBuffer.Size; } VkMappedMemoryRange range[2] = {}; range[0].sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE; range[0].memory = draw->vertex_buffer_mem; range[0].size = VK_WHOLE_SIZE; range[1].sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE; range[1].memory = draw->index_buffer_mem; range[1].size = VK_WHOLE_SIZE; VK_CHECK(device_data->vtable.FlushMappedMemoryRanges(device_data->device, 2, range)); device_data->vtable.UnmapMemory(device_data->device, draw->vertex_buffer_mem); device_data->vtable.UnmapMemory(device_data->device, draw->index_buffer_mem); /* Bind pipeline and descriptor sets */ device_data->vtable.CmdBindPipeline(draw->command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, data->pipeline); #if 1 // disable if using >1 font textures VkDescriptorSet desc_set[1] = { //data->descriptor_set reinterpret_cast(data->font_atlas->TexID) }; device_data->vtable.CmdBindDescriptorSets(draw->command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, data->pipeline_layout, 0, 1, desc_set, 0, NULL); #endif /* Bind vertex & index buffers */ VkBuffer vertex_buffers[1] = { draw->vertex_buffer }; VkDeviceSize vertex_offset[1] = { 0 }; device_data->vtable.CmdBindVertexBuffers(draw->command_buffer, 0, 1, vertex_buffers, vertex_offset); device_data->vtable.CmdBindIndexBuffer(draw->command_buffer, draw->index_buffer, 0, VK_INDEX_TYPE_UINT16); /* Setup viewport */ VkViewport viewport; viewport.x = 0; viewport.y = 0; viewport.width = draw_data->DisplaySize.x; viewport.height = draw_data->DisplaySize.y; viewport.minDepth = 0.0f; viewport.maxDepth = 1.0f; device_data->vtable.CmdSetViewport(draw->command_buffer, 0, 1, &viewport); /* Setup scale and translation through push constants : * * Our visible imgui space lies from draw_data->DisplayPos (top left) to * draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayMin * is typically (0,0) for single viewport apps. */ float scale[2]; scale[0] = 2.0f / draw_data->DisplaySize.x; scale[1] = 2.0f / draw_data->DisplaySize.y; float translate[2]; translate[0] = -1.0f - draw_data->DisplayPos.x * scale[0]; translate[1] = -1.0f - draw_data->DisplayPos.y * scale[1]; device_data->vtable.CmdPushConstants(draw->command_buffer, data->pipeline_layout, VK_SHADER_STAGE_VERTEX_BIT, sizeof(float) * 0, sizeof(float) * 2, scale); device_data->vtable.CmdPushConstants(draw->command_buffer, data->pipeline_layout, VK_SHADER_STAGE_VERTEX_BIT, sizeof(float) * 2, sizeof(float) * 2, translate); // Render the command lists: int vtx_offset = 0; int idx_offset = 0; ImVec2 display_pos = draw_data->DisplayPos; for (int n = 0; n < draw_data->CmdListsCount; n++) { const ImDrawList* cmd_list = draw_data->CmdLists[n]; for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) { const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i]; // Apply scissor/clipping rectangle // FIXME: We could clamp width/height based on clamped min/max values. VkRect2D scissor; scissor.offset.x = (int32_t)(pcmd->ClipRect.x - display_pos.x) > 0 ? (int32_t)(pcmd->ClipRect.x - display_pos.x) : 0; scissor.offset.y = (int32_t)(pcmd->ClipRect.y - display_pos.y) > 0 ? (int32_t)(pcmd->ClipRect.y - display_pos.y) : 0; scissor.extent.width = (uint32_t)(pcmd->ClipRect.z - pcmd->ClipRect.x); scissor.extent.height = (uint32_t)(pcmd->ClipRect.w - pcmd->ClipRect.y + 1); // FIXME: Why +1 here? device_data->vtable.CmdSetScissor(draw->command_buffer, 0, 1, &scissor); #if 0 //enable if using >1 font textures or use texture array VkDescriptorSet desc_set[1] = { (VkDescriptorSet)pcmd->TextureId }; device_data->vtable.CmdBindDescriptorSets(draw->command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, data->pipeline_layout, 0, 1, desc_set, 0, NULL); #endif // Draw device_data->vtable.CmdDrawIndexed(draw->command_buffer, pcmd->ElemCount, 1, idx_offset, vtx_offset, 0); idx_offset += pcmd->ElemCount; } vtx_offset += cmd_list->VtxBuffer.Size; } device_data->vtable.CmdEndRenderPass(draw->command_buffer); if (device_data->graphic_queue->family_index != present_queue->family_index) { /* Transfer the image back to the present queue family * image layout was already changed to present by the render pass */ imb.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; imb.pNext = nullptr; imb.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; imb.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; imb.oldLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; imb.newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; imb.image = data->images[image_index]; imb.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; imb.subresourceRange.baseMipLevel = 0; imb.subresourceRange.levelCount = 1; imb.subresourceRange.baseArrayLayer = 0; imb.subresourceRange.layerCount = 1; imb.srcQueueFamilyIndex = device_data->graphic_queue->family_index; imb.dstQueueFamilyIndex = present_queue->family_index; device_data->vtable.CmdPipelineBarrier(draw->command_buffer, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, 0, /* dependency flags */ 0, nullptr, /* memory barriers */ 0, nullptr, /* buffer memory barriers */ 1, &imb); /* image memory barriers */ } device_data->vtable.EndCommandBuffer(draw->command_buffer); /* When presenting on a different queue than where we're drawing the * overlay *AND* when the application does not provide a semaphore to * vkQueuePresent, insert our own cross engine synchronization * semaphore. */ if (n_wait_semaphores == 0 && device_data->graphic_queue->queue != present_queue->queue) { VkPipelineStageFlags stages_wait = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT; VkSubmitInfo submit_info = {}; submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; submit_info.commandBufferCount = 0; submit_info.pWaitDstStageMask = &stages_wait; submit_info.waitSemaphoreCount = 0; submit_info.signalSemaphoreCount = 1; submit_info.pSignalSemaphores = &draw->cross_engine_semaphore; device_data->vtable.QueueSubmit(present_queue->queue, 1, &submit_info, VK_NULL_HANDLE); submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; submit_info.commandBufferCount = 1; submit_info.pWaitDstStageMask = &stages_wait; submit_info.pCommandBuffers = &draw->command_buffer; submit_info.waitSemaphoreCount = 1; submit_info.pWaitSemaphores = &draw->cross_engine_semaphore; submit_info.signalSemaphoreCount = 1; submit_info.pSignalSemaphores = &draw->semaphore; device_data->vtable.QueueSubmit(device_data->graphic_queue->queue, 1, &submit_info, draw->fence); } else { // wait in the fragment stage until the swapchain image is ready std::vector stages_wait(n_wait_semaphores, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); VkSubmitInfo submit_info = {}; submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; submit_info.commandBufferCount = 1; submit_info.pCommandBuffers = &draw->command_buffer; submit_info.pWaitDstStageMask = stages_wait.data(); submit_info.waitSemaphoreCount = n_wait_semaphores; submit_info.pWaitSemaphores = wait_semaphores; submit_info.signalSemaphoreCount = 1; submit_info.pSignalSemaphores = &draw->semaphore; device_data->vtable.QueueSubmit(device_data->graphic_queue->queue, 1, &submit_info, draw->fence); } make_imgui_contexts_current(saved_imgui_context); return draw; } static const uint32_t overlay_vert_spv[] = { #include "overlay.vert.spv.h" }; static const uint32_t overlay_frag_spv[] = { #include "overlay.frag.spv.h" }; static void setup_swapchain_data_pipeline(struct swapchain_data *data) { struct device_data *device_data = data->device; VkShaderModule vert_module, frag_module; /* Create shader modules */ VkShaderModuleCreateInfo vert_info = {}; vert_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; vert_info.codeSize = sizeof(overlay_vert_spv); vert_info.pCode = overlay_vert_spv; VK_CHECK(device_data->vtable.CreateShaderModule(device_data->device, &vert_info, NULL, &vert_module)); VkShaderModuleCreateInfo frag_info = {}; frag_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; frag_info.codeSize = sizeof(overlay_frag_spv); frag_info.pCode = (uint32_t*)overlay_frag_spv; VK_CHECK(device_data->vtable.CreateShaderModule(device_data->device, &frag_info, NULL, &frag_module)); /* Font sampler */ VkSamplerCreateInfo sampler_info = {}; sampler_info.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; sampler_info.magFilter = VK_FILTER_LINEAR; sampler_info.minFilter = VK_FILTER_LINEAR; sampler_info.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; sampler_info.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT; sampler_info.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT; sampler_info.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT; sampler_info.minLod = -1000; sampler_info.maxLod = 1000; sampler_info.maxAnisotropy = 1.0f; VK_CHECK(device_data->vtable.CreateSampler(device_data->device, &sampler_info, NULL, &data->font_sampler)); /* Descriptor pool */ VkDescriptorPoolSize sampler_pool_size = {}; sampler_pool_size.type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; sampler_pool_size.descriptorCount = 1; VkDescriptorPoolCreateInfo desc_pool_info = {}; desc_pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; desc_pool_info.maxSets = 1; desc_pool_info.poolSizeCount = 1; desc_pool_info.pPoolSizes = &sampler_pool_size; VK_CHECK(device_data->vtable.CreateDescriptorPool(device_data->device, &desc_pool_info, NULL, &data->descriptor_pool)); /* Descriptor layout */ VkSampler sampler[1] = { data->font_sampler }; VkDescriptorSetLayoutBinding binding[1] = {}; binding[0].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; binding[0].descriptorCount = 1; binding[0].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; binding[0].pImmutableSamplers = sampler; VkDescriptorSetLayoutCreateInfo set_layout_info = {}; set_layout_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; set_layout_info.bindingCount = 1; set_layout_info.pBindings = binding; VK_CHECK(device_data->vtable.CreateDescriptorSetLayout(device_data->device, &set_layout_info, NULL, &data->descriptor_layout)); /* Descriptor set */ /* VkDescriptorSetAllocateInfo alloc_info = {}; alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; alloc_info.descriptorPool = data->descriptor_pool; alloc_info.descriptorSetCount = 1; alloc_info.pSetLayouts = &data->descriptor_layout; VK_CHECK(device_data->vtable.AllocateDescriptorSets(device_data->device, &alloc_info, &data->descriptor_set)); */ /* Constants: we are using 'vec2 offset' and 'vec2 scale' instead of a full * 3d projection matrix */ VkPushConstantRange push_constants[1] = {}; push_constants[0].stageFlags = VK_SHADER_STAGE_VERTEX_BIT; push_constants[0].offset = sizeof(float) * 0; push_constants[0].size = sizeof(float) * 4; VkPipelineLayoutCreateInfo layout_info = {}; layout_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; layout_info.setLayoutCount = 1; layout_info.pSetLayouts = &data->descriptor_layout; layout_info.pushConstantRangeCount = 1; layout_info.pPushConstantRanges = push_constants; VK_CHECK(device_data->vtable.CreatePipelineLayout(device_data->device, &layout_info, NULL, &data->pipeline_layout)); VkPipelineShaderStageCreateInfo stage[2] = {}; stage[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; stage[0].stage = VK_SHADER_STAGE_VERTEX_BIT; stage[0].module = vert_module; stage[0].pName = "main"; stage[1].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; stage[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT; stage[1].module = frag_module; stage[1].pName = "main"; VkVertexInputBindingDescription binding_desc[1] = {}; binding_desc[0].stride = sizeof(ImDrawVert); binding_desc[0].inputRate = VK_VERTEX_INPUT_RATE_VERTEX; VkVertexInputAttributeDescription attribute_desc[3] = {}; attribute_desc[0].location = 0; attribute_desc[0].binding = binding_desc[0].binding; attribute_desc[0].format = VK_FORMAT_R32G32_SFLOAT; attribute_desc[0].offset = IM_OFFSETOF(ImDrawVert, pos); attribute_desc[1].location = 1; attribute_desc[1].binding = binding_desc[0].binding; attribute_desc[1].format = VK_FORMAT_R32G32_SFLOAT; attribute_desc[1].offset = IM_OFFSETOF(ImDrawVert, uv); attribute_desc[2].location = 2; attribute_desc[2].binding = binding_desc[0].binding; attribute_desc[2].format = VK_FORMAT_R8G8B8A8_UNORM; attribute_desc[2].offset = IM_OFFSETOF(ImDrawVert, col); VkPipelineVertexInputStateCreateInfo vertex_info = {}; vertex_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; vertex_info.vertexBindingDescriptionCount = 1; vertex_info.pVertexBindingDescriptions = binding_desc; vertex_info.vertexAttributeDescriptionCount = 3; vertex_info.pVertexAttributeDescriptions = attribute_desc; VkPipelineInputAssemblyStateCreateInfo ia_info = {}; ia_info.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; ia_info.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; VkPipelineViewportStateCreateInfo viewport_info = {}; viewport_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; viewport_info.viewportCount = 1; viewport_info.scissorCount = 1; VkPipelineRasterizationStateCreateInfo raster_info = {}; raster_info.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; raster_info.polygonMode = VK_POLYGON_MODE_FILL; raster_info.cullMode = VK_CULL_MODE_NONE; raster_info.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE; raster_info.lineWidth = 1.0f; VkPipelineMultisampleStateCreateInfo ms_info = {}; ms_info.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; ms_info.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; VkPipelineColorBlendAttachmentState color_attachment[1] = {}; color_attachment[0].blendEnable = VK_TRUE; color_attachment[0].srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA; color_attachment[0].dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; color_attachment[0].colorBlendOp = VK_BLEND_OP_ADD; color_attachment[0].srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE; color_attachment[0].dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; color_attachment[0].alphaBlendOp = VK_BLEND_OP_ADD; color_attachment[0].colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; VkPipelineDepthStencilStateCreateInfo depth_info = {}; depth_info.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; VkPipelineColorBlendStateCreateInfo blend_info = {}; blend_info.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; blend_info.attachmentCount = 1; blend_info.pAttachments = color_attachment; VkDynamicState dynamic_states[2] = { VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR }; VkPipelineDynamicStateCreateInfo dynamic_state = {}; dynamic_state.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; dynamic_state.dynamicStateCount = (uint32_t)IM_ARRAYSIZE(dynamic_states); dynamic_state.pDynamicStates = dynamic_states; VkGraphicsPipelineCreateInfo info = {}; info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; info.flags = 0; info.stageCount = 2; info.pStages = stage; info.pVertexInputState = &vertex_info; info.pInputAssemblyState = &ia_info; info.pViewportState = &viewport_info; info.pRasterizationState = &raster_info; info.pMultisampleState = &ms_info; info.pDepthStencilState = &depth_info; info.pColorBlendState = &blend_info; info.pDynamicState = &dynamic_state; info.layout = data->pipeline_layout; info.renderPass = data->render_pass; VK_CHECK( device_data->vtable.CreateGraphicsPipelines(device_data->device, VK_NULL_HANDLE, 1, &info, NULL, &data->pipeline)); device_data->vtable.DestroyShaderModule(device_data->device, vert_module, NULL); device_data->vtable.DestroyShaderModule(device_data->device, frag_module, NULL); check_fonts(data); // if (data->descriptor_set) // update_image_descriptor(data, data->font_image_view[0], data->descriptor_set); } static void convert_colors_vk(VkFormat format, VkColorSpaceKHR colorspace, struct swapchain_stats& sw_stats, struct overlay_params& params) { /* TODO: Support more colorspacess */ switch (colorspace) { case VK_COLOR_SPACE_HDR10_ST2084_EXT: params.transfer_function = PQ; break; case VK_COLOR_SPACE_HDR10_HLG_EXT: params.transfer_function = HLG; break; case VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT: params.transfer_function = SRGB; break; /* use no conversion for rest of the colorspaces */ default: params.transfer_function = NONE; break; } if (params.transfer_function == NONE) { switch (format) { case VK_FORMAT_R8_SRGB: case VK_FORMAT_R8G8_SRGB: case VK_FORMAT_R8G8B8_SRGB: case VK_FORMAT_B8G8R8_SRGB: case VK_FORMAT_R8G8B8A8_SRGB: case VK_FORMAT_B8G8R8A8_SRGB: case VK_FORMAT_A8B8G8R8_SRGB_PACK32: case VK_FORMAT_BC1_RGB_SRGB_BLOCK: case VK_FORMAT_BC1_RGBA_SRGB_BLOCK: case VK_FORMAT_BC2_SRGB_BLOCK: case VK_FORMAT_BC3_SRGB_BLOCK: case VK_FORMAT_BC7_SRGB_BLOCK: case VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK: case VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK: case VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK: case VK_FORMAT_ASTC_4x4_SRGB_BLOCK: case VK_FORMAT_ASTC_5x4_SRGB_BLOCK: case VK_FORMAT_ASTC_5x5_SRGB_BLOCK: case VK_FORMAT_ASTC_6x5_SRGB_BLOCK: case VK_FORMAT_ASTC_6x6_SRGB_BLOCK: case VK_FORMAT_ASTC_8x5_SRGB_BLOCK: case VK_FORMAT_ASTC_8x6_SRGB_BLOCK: case VK_FORMAT_ASTC_8x8_SRGB_BLOCK: case VK_FORMAT_ASTC_10x5_SRGB_BLOCK: case VK_FORMAT_ASTC_10x6_SRGB_BLOCK: case VK_FORMAT_ASTC_10x8_SRGB_BLOCK: case VK_FORMAT_ASTC_10x10_SRGB_BLOCK: case VK_FORMAT_ASTC_12x10_SRGB_BLOCK: case VK_FORMAT_ASTC_12x12_SRGB_BLOCK: case VK_FORMAT_PVRTC1_2BPP_SRGB_BLOCK_IMG: case VK_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG: case VK_FORMAT_PVRTC2_2BPP_SRGB_BLOCK_IMG: case VK_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG: params.transfer_function = SRGB; break; default: break; } } HUDElements.convert_colors(params.transfer_function != NONE, params); } static void setup_swapchain_data(struct swapchain_data *data, const VkSwapchainCreateInfoKHR *pCreateInfo) { struct device_data *device_data = data->device; data->width = pCreateInfo->imageExtent.width; data->height = pCreateInfo->imageExtent.height; data->format = pCreateInfo->imageFormat; if (!data->imgui_contexts.imgui) data->imgui_contexts = create_imgui_contexts(data->font_atlas); auto saved_imgui_contexts = get_current_imgui_contexts(); make_imgui_contexts_current(data->imgui_contexts); ImGui::GetIO().IniFilename = NULL; ImGui::GetIO().DisplaySize = ImVec2((float)data->width, (float)data->height); convert_colors_vk(pCreateInfo->imageFormat, pCreateInfo->imageColorSpace, data->sw_stats, device_data->instance->params); /* Render pass */ VkAttachmentDescription attachment_desc = {}; attachment_desc.format = pCreateInfo->imageFormat; attachment_desc.samples = VK_SAMPLE_COUNT_1_BIT; attachment_desc.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; attachment_desc.storeOp = VK_ATTACHMENT_STORE_OP_STORE; attachment_desc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; attachment_desc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; attachment_desc.initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; attachment_desc.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; VkAttachmentReference color_attachment = {}; color_attachment.attachment = 0; color_attachment.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; VkSubpassDescription subpass = {}; subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; subpass.colorAttachmentCount = 1; subpass.pColorAttachments = &color_attachment; VkSubpassDependency dependency = {}; dependency.srcSubpass = VK_SUBPASS_EXTERNAL; dependency.dstSubpass = 0; dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; dependency.srcAccessMask = 0; dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; VkRenderPassCreateInfo render_pass_info = {}; render_pass_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; render_pass_info.attachmentCount = 1; render_pass_info.pAttachments = &attachment_desc; render_pass_info.subpassCount = 1; render_pass_info.pSubpasses = &subpass; render_pass_info.dependencyCount = 1; render_pass_info.pDependencies = &dependency; VK_CHECK(device_data->vtable.CreateRenderPass(device_data->device, &render_pass_info, NULL, &data->render_pass)); setup_swapchain_data_pipeline(data); uint32_t n_images = 0; VK_CHECK(device_data->vtable.GetSwapchainImagesKHR(device_data->device, data->swapchain, &n_images, NULL)); data->images.resize(n_images); data->image_views.resize(n_images); data->framebuffers.resize(n_images); VK_CHECK(device_data->vtable.GetSwapchainImagesKHR(device_data->device, data->swapchain, &n_images, data->images.data())); if (n_images != data->images.size()) { data->images.resize(n_images); data->image_views.resize(n_images); data->framebuffers.resize(n_images); } /* Image views */ VkImageViewCreateInfo view_info = {}; view_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; view_info.viewType = VK_IMAGE_VIEW_TYPE_2D; view_info.format = pCreateInfo->imageFormat; view_info.components.r = VK_COMPONENT_SWIZZLE_R; view_info.components.g = VK_COMPONENT_SWIZZLE_G; view_info.components.b = VK_COMPONENT_SWIZZLE_B; view_info.components.a = VK_COMPONENT_SWIZZLE_A; view_info.subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 }; for (size_t i = 0; i < data->images.size(); i++) { view_info.image = data->images[i]; VK_CHECK(device_data->vtable.CreateImageView(device_data->device, &view_info, NULL, &data->image_views[i])); } /* Framebuffers */ VkImageView attachment[1]; VkFramebufferCreateInfo fb_info = {}; fb_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; fb_info.renderPass = data->render_pass; fb_info.attachmentCount = 1; fb_info.pAttachments = attachment; fb_info.width = data->width; fb_info.height = data->height; fb_info.layers = 1; for (size_t i = 0; i < data->image_views.size(); i++) { attachment[0] = data->image_views[i]; VK_CHECK(device_data->vtable.CreateFramebuffer(device_data->device, &fb_info, NULL, &data->framebuffers[i])); } /* Command buffer pool */ VkCommandPoolCreateInfo cmd_buffer_pool_info = {}; cmd_buffer_pool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; cmd_buffer_pool_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; cmd_buffer_pool_info.queueFamilyIndex = device_data->graphic_queue->family_index; VK_CHECK(device_data->vtable.CreateCommandPool(device_data->device, &cmd_buffer_pool_info, NULL, &data->command_pool)); make_imgui_contexts_current(saved_imgui_contexts); } static void shutdown_swapchain_font(struct swapchain_data *data) { struct device_data *device_data = data->device; device_data->vtable.DestroyImageView(device_data->device, data->font_image_view, NULL); device_data->vtable.DestroyImage(device_data->device, data->font_image, NULL); device_data->vtable.FreeMemory(device_data->device, data->font_mem, NULL); device_data->vtable.DestroyBuffer(device_data->device, data->upload_font_buffer, NULL); device_data->vtable.FreeMemory(device_data->device, data->upload_font_buffer_mem, NULL); } static void shutdown_swapchain_data(struct swapchain_data *data) { struct device_data *device_data = data->device; for (auto draw : data->draws) { if (!draw) continue; device_data->vtable.FreeCommandBuffers(device_data->device, data->command_pool, 1, &draw->command_buffer); device_data->vtable.DestroySemaphore(device_data->device, draw->cross_engine_semaphore, NULL); device_data->vtable.DestroySemaphore(device_data->device, draw->semaphore, NULL); device_data->vtable.DestroyFence(device_data->device, draw->fence, NULL); device_data->vtable.DestroyBuffer(device_data->device, draw->vertex_buffer, NULL); device_data->vtable.DestroyBuffer(device_data->device, draw->index_buffer, NULL); device_data->vtable.FreeMemory(device_data->device, draw->vertex_buffer_mem, NULL); device_data->vtable.FreeMemory(device_data->device, draw->index_buffer_mem, NULL); delete draw; } for (size_t i = 0; i < data->images.size(); i++) { device_data->vtable.DestroyImageView(device_data->device, data->image_views[i], NULL); device_data->vtable.DestroyFramebuffer(device_data->device, data->framebuffers[i], NULL); } device_data->vtable.DestroyRenderPass(device_data->device, data->render_pass, NULL); device_data->vtable.DestroyCommandPool(device_data->device, data->command_pool, NULL); device_data->vtable.DestroyPipeline(device_data->device, data->pipeline, NULL); device_data->vtable.DestroyPipelineLayout(device_data->device, data->pipeline_layout, NULL); device_data->vtable.DestroyDescriptorPool(device_data->device, data->descriptor_pool, NULL); device_data->vtable.DestroyDescriptorSetLayout(device_data->device, data->descriptor_layout, NULL); device_data->vtable.DestroySampler(device_data->device, data->font_sampler, NULL); shutdown_swapchain_font(data); IM_DELETE(data->font_atlas); destroy_imgui_contexts(data->imgui_contexts); } static struct overlay_draw *before_present(struct swapchain_data *swapchain_data, struct queue_data *present_queue, const VkSemaphore *wait_semaphores, unsigned n_wait_semaphores, unsigned imageIndex) { struct overlay_draw *draw = NULL; snapshot_swapchain_frame(swapchain_data); if (swapchain_data->sw_stats.n_frames > 0) { compute_swapchain_display(swapchain_data); draw = render_swapchain_display(swapchain_data, present_queue, wait_semaphores, n_wait_semaphores, imageIndex); } return draw; } static bool is_present_mode_supported(VkPhysicalDevice device, VkSurfaceKHR surface, VkPresentModeKHR targetPresentMode) { struct instance_data *instance_data = FIND(struct instance_data, device); PFN_vkGetPhysicalDeviceSurfacePresentModesKHR fpGetPhysicalDeviceSurfacePresentModesKHR = (PFN_vkGetPhysicalDeviceSurfacePresentModesKHR) instance_data->vtable.GetInstanceProcAddr(instance_data->instance, "vkGetPhysicalDeviceSurfacePresentModesKHR"); if (fpGetPhysicalDeviceSurfacePresentModesKHR != NULL) { uint32_t presentModeCount = 0; VkResult result; result = fpGetPhysicalDeviceSurfacePresentModesKHR(device, surface, &presentModeCount, NULL); if (result != VK_SUCCESS) { SPDLOG_ERROR("Failed to get presentModeCount: vkGetPhysicalDeviceSurfacePresentModesKHR with {}", vk_Result_to_str(result)); return false; } std::vector presentModes(presentModeCount); presentModes.resize(presentModeCount); result = fpGetPhysicalDeviceSurfacePresentModesKHR(device, surface, &presentModeCount, presentModes.data()); if (result == VK_SUCCESS) { for (const auto& mode : presentModes) if (mode == targetPresentMode) return true; } else { SPDLOG_ERROR("Failed to get presentModes: vkGetPhysicalDeviceSurfacePresentModesKHR failed with {}", vk_Result_to_str(result)); } } return false; } static VkResult overlay_CreateSwapchainKHR( VkDevice device, const VkSwapchainCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSwapchainKHR* pSwapchain) { VkSwapchainCreateInfoKHR createInfo = *pCreateInfo; createInfo.imageUsage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; struct device_data *device_data = FIND(struct device_data, device); const auto& params = device_data->instance->params; std::optional target_present_mode; if (params.m_vulkan_present_mode.has_value()) { target_present_mode = params.m_vulkan_present_mode; } if (target_present_mode.has_value()) { if (is_present_mode_supported(device_data->physical_device, createInfo.surface, target_present_mode.value())) { createInfo.presentMode = target_present_mode.value(); } else { SPDLOG_WARN("Present mode is not supported: {}", string_VkPresentModeKHR(target_present_mode.value())); } } HUDElements.cur_present_mode = createInfo.presentMode; SPDLOG_DEBUG("Present mode : {}", string_VkPresentModeKHR(HUDElements.cur_present_mode)); VkResult result = device_data->vtable.CreateSwapchainKHR(device, &createInfo, pAllocator, pSwapchain); if (result != VK_SUCCESS) return result; struct swapchain_data *swapchain_data = new_swapchain_data(*pSwapchain, device_data); setup_swapchain_data(swapchain_data, pCreateInfo); const VkPhysicalDeviceProperties& prop = device_data->properties; swapchain_data->sw_stats.version_vk.major = VK_VERSION_MAJOR(prop.apiVersion); swapchain_data->sw_stats.version_vk.minor = VK_VERSION_MINOR(prop.apiVersion); swapchain_data->sw_stats.version_vk.patch = VK_VERSION_PATCH(prop.apiVersion); swapchain_data->sw_stats.engineName = device_data->instance->engineName; swapchain_data->sw_stats.engineVersion = device_data->instance->engineVersion; swapchain_data->sw_stats.engine = device_data->instance->engine; swapchain_data->sw_stats.applicationVersion = device_data->instance->applicationVersion; HUDElements.vendorID = prop.vendorID; std::stringstream ss; // ss << prop.deviceName; if (prop.vendorID == 0x10de) { ss << " " << ((prop.driverVersion >> 22) & 0x3ff); ss << "." << ((prop.driverVersion >> 14) & 0x0ff); ss << "." << std::setw(2) << std::setfill('0') << ((prop.driverVersion >> 6) & 0x0ff); } #ifdef _WIN32 else if (prop.vendorID == 0x8086) { ss << " " << (prop.driverVersion >> 14); ss << "." << (prop.driverVersion & 0x3fff); } #endif else { ss << " " << VK_VERSION_MAJOR(prop.driverVersion); ss << "." << VK_VERSION_MINOR(prop.driverVersion); ss << "." << VK_VERSION_PATCH(prop.driverVersion); } std::string driverVersion = ss.str(); std::string deviceName = prop.deviceName; if (!is_blacklisted()) { #ifdef __linux__ swapchain_data->sw_stats.gpuName = remove_parentheses(deviceName); #endif } swapchain_data->sw_stats.driverName = driverProps.driverInfo; return result; } static void overlay_DestroySwapchainKHR( VkDevice device, VkSwapchainKHR swapchain, const VkAllocationCallbacks* pAllocator) { if (swapchain == VK_NULL_HANDLE) { struct device_data *device_data = FIND(struct device_data, device); device_data->vtable.DestroySwapchainKHR(device, swapchain, pAllocator); return; } struct swapchain_data *swapchain_data = FIND(struct swapchain_data, swapchain); shutdown_swapchain_data(swapchain_data); swapchain_data->device->vtable.DestroySwapchainKHR(device, swapchain, pAllocator); destroy_swapchain_data(swapchain_data); } static VkResult overlay_QueuePresentKHR( VkQueue queue, const VkPresentInfoKHR* pPresentInfo) { if (fps_limiter) fps_limiter->limit(true); struct queue_data *queue_data = FIND(struct queue_data, queue); /* Otherwise we need to add our overlay drawing semaphore to the list of * semaphores to wait on. If we don't do that the presented picture might * be have incomplete overlay drawings. */ VkResult result = VK_SUCCESS; for (uint32_t i = 0; i < pPresentInfo->swapchainCount; i++) { VkSwapchainKHR swapchain = pPresentInfo->pSwapchains[i]; struct swapchain_data *swapchain_data = FIND(struct swapchain_data, swapchain); uint32_t image_index = pPresentInfo->pImageIndices[i]; VkPresentInfoKHR present_info = *pPresentInfo; present_info.swapchainCount = 1; present_info.pSwapchains = &swapchain; present_info.pImageIndices = &image_index; VkBaseInStructure **mode_info_node = vk_find_next_struct( (void**)&present_info.pNext, VK_STRUCTURE_TYPE_SWAPCHAIN_PRESENT_MODE_INFO_EXT); VkSwapchainPresentModeInfoEXT mode_info_patched; VkPresentModeKHR present_mode_override; if (mode_info_node) { const auto *mode_info = (const VkSwapchainPresentModeInfoEXT *)*mode_info_node; HUDElements.cur_present_mode = mode_info->pPresentModes[i]; // Check if there is a user-specified present mode override. if (get_params()->m_vulkan_present_mode.has_value()) { present_mode_override = get_params()->m_vulkan_present_mode.value(); // Patch `mode_info` so that the user-specified override is not // clobbered by the application from swapchain maintenance. mode_info_patched = *mode_info; mode_info_patched.swapchainCount = 1; mode_info_patched.pPresentModes = &present_mode_override; *mode_info_node = (VkBaseInStructure *)&mode_info_patched; HUDElements.cur_present_mode = present_mode_override; } } struct overlay_draw *draw = before_present(swapchain_data, queue_data, pPresentInfo->pWaitSemaphores, i == 0 ? pPresentInfo->waitSemaphoreCount : 0, image_index); /* Because the submission of the overlay draw waits on the semaphores * handed for present, we don't need to have this present operation * wait on them as well, we can just wait on the overlay submission * semaphore. */ if (draw) { present_info.pWaitSemaphores = &draw->semaphore; present_info.waitSemaphoreCount = 1; } VkResult chain_result = queue_data->device->vtable.QueuePresentKHR(queue, &present_info); if (pPresentInfo->pResults) pPresentInfo->pResults[i] = chain_result; if (chain_result != VK_SUCCESS && result == VK_SUCCESS) result = chain_result; } if (fps_limiter) fps_limiter->limit(false); return result; } static VkResult overlay_BeginCommandBuffer( VkCommandBuffer commandBuffer, const VkCommandBufferBeginInfo* pBeginInfo) { struct command_buffer_data *cmd_buffer_data = FIND(struct command_buffer_data, commandBuffer); struct device_data *device_data = cmd_buffer_data->device; /* Otherwise record a begin query as first command. */ VkResult result = device_data->vtable.BeginCommandBuffer(commandBuffer, pBeginInfo); return result; } static VkResult overlay_EndCommandBuffer( VkCommandBuffer commandBuffer) { struct command_buffer_data *cmd_buffer_data = FIND(struct command_buffer_data, commandBuffer); struct device_data *device_data = cmd_buffer_data->device; return device_data->vtable.EndCommandBuffer(commandBuffer); } static VkResult overlay_ResetCommandBuffer( VkCommandBuffer commandBuffer, VkCommandBufferResetFlags flags) { struct command_buffer_data *cmd_buffer_data = FIND(struct command_buffer_data, commandBuffer); struct device_data *device_data = cmd_buffer_data->device; return device_data->vtable.ResetCommandBuffer(commandBuffer, flags); } static void overlay_CmdExecuteCommands( VkCommandBuffer commandBuffer, uint32_t commandBufferCount, const VkCommandBuffer* pCommandBuffers) { struct command_buffer_data *cmd_buffer_data = FIND(struct command_buffer_data, commandBuffer); struct device_data *device_data = cmd_buffer_data->device; device_data->vtable.CmdExecuteCommands(commandBuffer, commandBufferCount, pCommandBuffers); } static VkResult overlay_AllocateCommandBuffers( VkDevice device, const VkCommandBufferAllocateInfo* pAllocateInfo, VkCommandBuffer* pCommandBuffers) { struct device_data *device_data = FIND(struct device_data, device); VkResult result = device_data->vtable.AllocateCommandBuffers(device, pAllocateInfo, pCommandBuffers); if (result != VK_SUCCESS) return result; for (uint32_t i = 0; i < pAllocateInfo->commandBufferCount; i++) { new_command_buffer_data(pCommandBuffers[i], pAllocateInfo->level, device_data); } return result; } static void overlay_FreeCommandBuffers( VkDevice device, VkCommandPool commandPool, uint32_t commandBufferCount, const VkCommandBuffer* pCommandBuffers) { struct device_data *device_data = FIND(struct device_data, device); for (uint32_t i = 0; i < commandBufferCount; i++) { struct command_buffer_data *cmd_buffer_data = FIND(struct command_buffer_data, pCommandBuffers[i]); /* It is legal to free a NULL command buffer*/ if (!cmd_buffer_data) continue; destroy_command_buffer_data(cmd_buffer_data); } device_data->vtable.FreeCommandBuffers(device, commandPool, commandBufferCount, pCommandBuffers); } static VkResult overlay_QueueSubmit( VkQueue queue, uint32_t submitCount, const VkSubmitInfo* pSubmits, VkFence fence) { struct queue_data *queue_data = FIND(struct queue_data, queue); struct device_data *device_data = queue_data->device; return device_data->vtable.QueueSubmit(queue, submitCount, pSubmits, fence); } static VkResult overlay_CreateDevice( VkPhysicalDevice physicalDevice, const VkDeviceCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDevice* pDevice) { struct instance_data *instance_data = FIND(struct instance_data, physicalDevice); VkLayerDeviceCreateInfo *chain_info = get_device_chain_info(pCreateInfo, VK_LAYER_LINK_INFO); assert(chain_info->u.pLayerInfo); PFN_vkGetInstanceProcAddr fpGetInstanceProcAddr = chain_info->u.pLayerInfo->pfnNextGetInstanceProcAddr; PFN_vkGetDeviceProcAddr fpGetDeviceProcAddr = chain_info->u.pLayerInfo->pfnNextGetDeviceProcAddr; PFN_vkCreateDevice fpCreateDevice = (PFN_vkCreateDevice)fpGetInstanceProcAddr(instance_data->instance, "vkCreateDevice"); if (fpCreateDevice == NULL) { return VK_ERROR_INITIALIZATION_FAILED; } // Advance the link info for the next element on the chain chain_info->u.pLayerInfo = chain_info->u.pLayerInfo->pNext; std::vector enabled_extensions(pCreateInfo->ppEnabledExtensionNames, pCreateInfo->ppEnabledExtensionNames + pCreateInfo->enabledExtensionCount); uint32_t extension_count; instance_data->pd_vtable.EnumerateDeviceExtensionProperties(physicalDevice, nullptr, &extension_count, nullptr); std::vector available_extensions(extension_count); instance_data->pd_vtable.EnumerateDeviceExtensionProperties(physicalDevice, nullptr, &extension_count, available_extensions.data()); auto has_extension = [](const auto& list, const char *name) { return std::any_of(list.begin(), list.end(), [&](const auto& e) { return e == std::string_view(name); }); }; bool can_get_driver_info = false; for (auto& extension : available_extensions) { if (extension.extensionName == std::string_view(VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME)) { can_get_driver_info = true; if (instance_data->api_version < VK_API_VERSION_1_2) { if (!has_extension(enabled_extensions, VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME)) { enabled_extensions.push_back(VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME); } } } if (extension.extensionName == std::string_view(VK_KHR_PRESENT_MODE_FIFO_LATEST_READY_EXTENSION_NAME)) { if (!has_extension(enabled_extensions, VK_KHR_PRESENT_MODE_FIFO_LATEST_READY_EXTENSION_NAME)) { enabled_extensions.push_back(VK_KHR_PRESENT_MODE_FIFO_LATEST_READY_EXTENSION_NAME); } } } VkDeviceCreateInfo pCreateInfoPatched = *pCreateInfo; pCreateInfoPatched.ppEnabledExtensionNames = enabled_extensions.data(); pCreateInfoPatched.enabledExtensionCount = (uint32_t) enabled_extensions.size(); VkResult result = fpCreateDevice(physicalDevice, &pCreateInfoPatched, pAllocator, pDevice); if (result != VK_SUCCESS) return result; struct device_data *device_data = new_device_data(*pDevice, instance_data); vk_device_dispatch_table_load(&device_data->vtable, fpGetDeviceProcAddr, *pDevice); device_data->physical_device = physicalDevice; vk_instance_dispatch_table_load(&instance_data->vtable, fpGetInstanceProcAddr, instance_data->instance); instance_data->pd_vtable.GetPhysicalDeviceProperties(device_data->physical_device, &device_data->properties); VkLayerDeviceCreateInfo *load_data_info = get_device_chain_info(pCreateInfo, VK_LOADER_DATA_CALLBACK); device_data->set_device_loader_data = load_data_info->u.pfnSetDeviceLoaderData; driverProps.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES; driverProps.pNext = nullptr; if (can_get_driver_info) { VkPhysicalDeviceProperties2 deviceProps = {VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2, &driverProps}; instance_data->pd_vtable.GetPhysicalDeviceProperties2(device_data->physical_device, &deviceProps); } if (!is_blacklisted()) { device_map_queues(device_data, pCreateInfo); #ifdef __linux__ gpu = device_data->properties.deviceName; SPDLOG_DEBUG("gpu: {}", gpu); #endif } return result; } static void overlay_DestroyDevice( VkDevice device, const VkAllocationCallbacks* pAllocator) { struct device_data *device_data = FIND(struct device_data, device); if (!is_blacklisted()) device_unmap_queues(device_data); device_data->vtable.DestroyDevice(device, pAllocator); destroy_device_data(device_data); } static VkResult overlay_CreateInstance( const VkInstanceCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkInstance* pInstance) { VkLayerInstanceCreateInfo *chain_info = get_instance_chain_info(pCreateInfo, VK_LAYER_LINK_INFO); std::string engineVersion, engineName; enum EngineTypes engine = EngineTypes::UNKNOWN; const char* pEngineName = nullptr; struct instance_data *instance_data = new_instance_data(*pInstance); if (pCreateInfo->pApplicationInfo) { pEngineName = pCreateInfo->pApplicationInfo->pEngineName; instance_data->applicationVersion = pCreateInfo->pApplicationInfo->applicationVersion; } if (pEngineName) { engineName = pEngineName; global_engine_name = engineName; } if (!is_blacklisted(true)) { if (engineName == "DXVK" || engineName == "vkd3d") { int engineVer = pCreateInfo->pApplicationInfo->engineVersion; engineVersion = to_string(VK_VERSION_MAJOR(engineVer)) + "." + to_string(VK_VERSION_MINOR(engineVer)) + "." + to_string(VK_VERSION_PATCH(engineVer)); } if (engineName == "DXVK") engine = DXVK; else if (engineName == "vkd3d") engine = VKD3D; else if(engineName == "mesa zink") { engine = ZINK; } else if (engineName == "Damavand") engine = DAMAVAND; else if (engineName == "Feral3D") engine = FERAL3D; else if (engineName == "SDLGPU") engine = SDL; else engine = VULKAN; } assert(chain_info->u.pLayerInfo); PFN_vkGetInstanceProcAddr fpGetInstanceProcAddr = chain_info->u.pLayerInfo->pfnNextGetInstanceProcAddr; PFN_vkCreateInstance fpCreateInstance = (PFN_vkCreateInstance)fpGetInstanceProcAddr(NULL, "vkCreateInstance"); if (fpCreateInstance == NULL) { return VK_ERROR_INITIALIZATION_FAILED; } // Advance the link info for the next element on the chain chain_info->u.pLayerInfo = chain_info->u.pLayerInfo->pNext; VkResult result = fpCreateInstance(pCreateInfo, pAllocator, pInstance); if (result != VK_SUCCESS) return result; vk_instance_dispatch_table_load(&instance_data->vtable, fpGetInstanceProcAddr, instance_data->instance); vk_physical_device_dispatch_table_load(&instance_data->pd_vtable, fpGetInstanceProcAddr, instance_data->instance); instance_data_map_physical_devices(instance_data, true); if (is_blacklisted()) return result; parse_overlay_config(&instance_data->params, getenv("MANGOHUD_CONFIG"), false); //check for blacklist item in the config file for (auto& item : instance_data->params.blacklist) { add_blacklist(item); } if (!is_blacklisted()) { #ifdef __linux__ init_system_info(); instance_data->notifier.params = &instance_data->params; start_notifier(instance_data->notifier); #endif init_cpu_stats(instance_data->params); instance_data->engine = engine; instance_data->engineName = engineName; instance_data->engineVersion = engineVersion; } instance_data->api_version = pCreateInfo->pApplicationInfo ? pCreateInfo->pApplicationInfo->apiVersion : VK_API_VERSION_1_0; return result; } static VkResult overlay_CreateSampler( VkDevice device, const VkSamplerCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSampler* pSampler) { struct device_data *device_data = FIND(struct device_data, device); auto params = device_data->instance->params; VkSamplerCreateInfo sampler = *pCreateInfo; if (params.picmip > -17 && params.picmip < 17) sampler.mipLodBias = params.picmip; if (params.af > 0){ sampler.anisotropyEnable = VK_TRUE; sampler.maxAnisotropy = params.af; } else if (params.af == 0) sampler.anisotropyEnable = VK_FALSE; if (params.enabled[OVERLAY_PARAM_ENABLED_trilinear]){ sampler.magFilter = VK_FILTER_LINEAR; sampler.minFilter = VK_FILTER_LINEAR; sampler.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; } if (params.enabled[OVERLAY_PARAM_ENABLED_bicubic]){ sampler.magFilter = VK_FILTER_CUBIC_IMG; sampler.minFilter = VK_FILTER_CUBIC_IMG; sampler.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; } if (params.enabled[OVERLAY_PARAM_ENABLED_retro]){ sampler.magFilter = VK_FILTER_NEAREST; sampler.minFilter = VK_FILTER_NEAREST; sampler.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST; } VkResult result = device_data->vtable.CreateSampler(device, &sampler, pAllocator, pSampler); return result; } static void overlay_DestroyInstance( VkInstance instance, const VkAllocationCallbacks* pAllocator) { struct instance_data *instance_data = FIND(struct instance_data, instance); instance_data_map_physical_devices(instance_data, false); instance_data->vtable.DestroyInstance(instance, pAllocator); #ifdef __linux__ if (!is_blacklisted()) stop_notifier(instance_data->notifier); #endif destroy_instance_data(instance_data); } #ifdef VK_USE_PLATFORM_WAYLAND_KHR static VkResult overlay_CreateWaylandSurfaceKHR( VkInstance instance, const VkWaylandSurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface ) { VkResult ret; struct instance_data *instance_data = FIND(struct instance_data, instance); HUDElements.display_server = HUDElements.display_servers::WAYLAND; ret = instance_data->vtable.CreateWaylandSurfaceKHR(instance, pCreateInfo, pAllocator, pSurface); if (ret == VK_SUCCESS) init_wayland_data(pCreateInfo->display, (void *) *pSurface); return ret; } static void overlay_DestroySurfaceKHR( VkInstance instance, VkSurfaceKHR surface, const VkAllocationCallbacks* pAllocator ) { struct instance_data *instance_data = FIND(struct instance_data, instance); wayland_data_unref(NULL, (void *) surface); instance_data->vtable.DestroySurfaceKHR(instance, surface, pAllocator); } #endif extern "C" PUBLIC VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL overlay_GetDeviceProcAddr(VkDevice dev, const char *funcName); extern "C" PUBLIC VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL overlay_GetInstanceProcAddr(VkInstance instance, const char *funcName); static const struct { const char *name; void *ptr; } name_to_funcptr_map[] = { { "vkGetInstanceProcAddr", (void *) overlay_GetInstanceProcAddr }, { "vkGetDeviceProcAddr", (void *) overlay_GetDeviceProcAddr }, #define ADD_HOOK(fn) { "vk" # fn, (void *) overlay_ ## fn } #define ADD_ALIAS_HOOK(alias, fn) { "vk" # alias, (void *) overlay_ ## fn } ADD_HOOK(AllocateCommandBuffers), ADD_HOOK(FreeCommandBuffers), ADD_HOOK(ResetCommandBuffer), ADD_HOOK(BeginCommandBuffer), ADD_HOOK(EndCommandBuffer), ADD_HOOK(CmdExecuteCommands), #ifdef VK_USE_PLATFORM_WAYLAND_KHR ADD_HOOK(CreateWaylandSurfaceKHR), ADD_HOOK(DestroySurfaceKHR), #endif ADD_HOOK(CreateSwapchainKHR), ADD_HOOK(QueuePresentKHR), ADD_HOOK(DestroySwapchainKHR), ADD_HOOK(CreateSampler), ADD_HOOK(QueueSubmit), ADD_HOOK(CreateDevice), ADD_HOOK(DestroyDevice), ADD_HOOK(CreateInstance), ADD_HOOK(DestroyInstance), #undef ADD_HOOK }; static void *find_ptr(const char *name) { std::string f(name); if (is_blacklisted() && (f != "vkCreateInstance" && f != "vkDestroyInstance" && f != "vkCreateDevice" && f != "vkDestroyDevice")) { return NULL; } for (uint32_t i = 0; i < ARRAY_SIZE(name_to_funcptr_map); i++) { if (strcmp(name, name_to_funcptr_map[i].name) == 0) return name_to_funcptr_map[i].ptr; } return NULL; } extern "C" PUBLIC VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL overlay_GetDeviceProcAddr(VkDevice dev, const char *funcName) { init_spdlog(); void *ptr = find_ptr(funcName); if (ptr) return reinterpret_cast(ptr); if (dev == NULL) return NULL; struct device_data *device_data = FIND(struct device_data, dev); if (device_data->vtable.GetDeviceProcAddr == NULL) return NULL; return device_data->vtable.GetDeviceProcAddr(dev, funcName); } extern "C" PUBLIC VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL overlay_GetInstanceProcAddr(VkInstance instance, const char *funcName) { init_spdlog(); void *ptr = find_ptr(funcName); if (ptr) return reinterpret_cast(ptr); if (instance == NULL) return NULL; struct instance_data *instance_data = FIND(struct instance_data, instance); if (instance_data->vtable.GetInstanceProcAddr == NULL) return NULL; return instance_data->vtable.GetInstanceProcAddr(instance, funcName); } ================================================ FILE: src/wayland_hook.h ================================================ #include #include #include #ifndef KeySym typedef unsigned long KeySym; #endif extern void* wl_handle; bool has_wayland_display(struct wl_display *display); bool wayland_has_keys_pressed(const std::vector& keys); void init_wayland_data(struct wl_display *display, void *vk_surface); void wayland_data_unref(struct wl_display *display, void *vk_surface); void update_wl_queue(); ================================================ FILE: src/wayland_keybinds.cpp ================================================ #include #include #include #include #include #include #include #include #include #include "wayland_hook.h" #include "real_dlsym.h" #include "keybinds.h" void* wl_handle = NULL; struct xkb_context *context_xkb = NULL; struct wayland_display { int ref; struct wl_event_queue *queue; struct wl_seat *seat; struct wl_keyboard *keyboard; struct xkb_keymap *keymap_xkb; struct xkb_state *state_xkb; std::set vk_surfaces; std::set wl_pressed_keys; wayland_display() { ref = 1; queue = NULL; keyboard = NULL; keymap_xkb = NULL; state_xkb = NULL; seat = NULL; } ~wayland_display() { wl_pressed_keys.clear(); vk_surfaces.clear(); wl_seat_destroy(this->seat); wl_keyboard_destroy(this->keyboard); wl_event_queue_destroy(this->queue); if (this->keymap_xkb) xkb_keymap_unref(this->keymap_xkb); if (this->state_xkb) xkb_state_unref(this->state_xkb); } }; std::map displays; // fixes wl_array_for_each with C++ #ifdef wl_array_for_each #undef wl_array_for_each #define wl_array_for_each(pos, array) \ for (pos = (decltype(pos)) (array)->data; \ (array)->size != 0 && \ (const char *) pos < ((const char *) (array)->data + (array)->size); \ (pos)++) #endif static void seat_handle_capabilities(void *data, struct wl_seat *seat, uint32_t caps); static void seat_handle_name(void *data, struct wl_seat *seat, const char *name) {} struct wl_seat_listener seat_listener { .capabilities = seat_handle_capabilities, .name = seat_handle_name, }; static void registry_handle_global(void *data, struct wl_registry* registry, uint32_t name, const char *interface, uint32_t version) { if (!data) return; struct wayland_display *wayland = (wayland_display *)data; if (strcmp(interface, wl_seat_interface.name) == 0 && !wayland->seat) { wayland->seat = (struct wl_seat*)wl_registry_bind(registry, name, &wl_seat_interface, version < 5 ? version : 5); wl_seat_add_listener(wayland->seat, &seat_listener, data); } } static void registry_handle_global_remove(void *data, struct wl_registry *registry, uint32_t name){} static void wl_keyboard_keymap(void *data, struct wl_keyboard *wl_keyboard, uint32_t format, int32_t fd, uint32_t size) { wayland_display *wayland = (wayland_display *)data; char* map_shm = (char*)mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0); if (!context_xkb) context_xkb = xkb_context_new(XKB_CONTEXT_NO_FLAGS); if (wayland->keymap_xkb && wayland->state_xkb) { xkb_keymap_unref(wayland->keymap_xkb); xkb_state_unref(wayland->state_xkb); wayland->keymap_xkb = NULL; wayland->state_xkb = NULL; } wayland->keymap_xkb = xkb_keymap_new_from_string( context_xkb, map_shm, XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS); wayland->state_xkb = xkb_state_new(wayland->keymap_xkb); munmap((void*)map_shm, size); close(fd); } static void wl_keyboard_enter(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial, struct wl_surface *surface, struct wl_array *keys) { if (!data) return; wayland_display *wayland = (wayland_display *)data; if (!wayland->state_xkb) return; uint32_t *key; wl_array_for_each(key, keys) { xkb_keycode_t keycode = *key + 8; xkb_keysym_t keysym = xkb_state_key_get_one_sym(wayland->state_xkb, keycode); wayland->wl_pressed_keys.insert(keysym); } } static void wl_keyboard_leave(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial, struct wl_surface *surface) { wayland_display *wayland = (wayland_display *)data; wayland->wl_pressed_keys.clear(); } static void wl_keyboard_key(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial, uint32_t time, uint32_t key, uint32_t state) { if (!data) return; wayland_display *wayland = (wayland_display *)data; if (!wayland->state_xkb) return; xkb_keycode_t keycode = key + 8; xkb_keysym_t keysym = xkb_state_key_get_one_sym(wayland->state_xkb, keycode); if (state) wayland->wl_pressed_keys.insert(keysym); else wayland->wl_pressed_keys.erase(keysym); } static void wl_keyboard_modifiers(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial, uint32_t depressed, uint32_t latched, uint32_t locked, uint32_t group) { if (!data) return; wayland_display *wayland = (wayland_display *)data; if (!wayland->state_xkb) return; xkb_state_update_mask(wayland->state_xkb, depressed, latched, locked, 0, 0, group); } static void wl_keyboard_repeat_info(void *data, struct wl_keyboard *wl_keyboard, int32_t rate, int32_t delay){} struct wl_registry_listener registry_listener { .global = registry_handle_global, .global_remove = registry_handle_global_remove }; struct wl_keyboard_listener keyboard_listener { .keymap = wl_keyboard_keymap, .enter = wl_keyboard_enter, .leave = wl_keyboard_leave, .key = wl_keyboard_key, .modifiers = wl_keyboard_modifiers, .repeat_info = wl_keyboard_repeat_info }; static void seat_handle_capabilities(void *data, struct wl_seat *seat, uint32_t caps) { if (!data) return; wayland_display *wayland = (wayland_display *)data; if (caps & WL_SEAT_CAPABILITY_KEYBOARD) { if (!wayland->keyboard) { wayland->keyboard = wl_seat_get_keyboard(seat); wl_keyboard_add_listener(wayland->keyboard, &keyboard_listener, data); } } } void update_wl_queue() { for (const auto& display : displays) wl_display_dispatch_queue_pending(display.first, display.second.queue); } // Track vk_surface for reference counting void init_wayland_data(struct wl_display *display, void *vk_surface) { if (!display) return; if (!wl_handle) wl_handle = real_dlopen("libwayland-client.so.0", RTLD_LAZY); // failed to load if (!wl_handle) return; // if we already have the display then just increase its reference count // and add its vk_surface if (has_wayland_display(display)) { displays[display].ref++; if (vk_surface) displays[display].vk_surfaces.insert(vk_surface); return; } // create a new element displays[display].ref = 1; displays[display].queue = wl_display_create_queue(display); if (vk_surface) displays[display].vk_surfaces.insert(vk_surface); struct wl_display *display_wrapped = (struct wl_display*)wl_proxy_create_wrapper(display); wl_proxy_set_queue((struct wl_proxy*)display_wrapped, displays[display].queue); struct wl_registry *registry = wl_display_get_registry(display_wrapped); wl_proxy_wrapper_destroy(display_wrapped); wl_registry_add_listener(registry, ®istry_listener, &displays[display]); wl_display_roundtrip_queue(display, displays[display].queue); wl_display_roundtrip_queue(display, displays[display].queue); wl_registry_destroy(registry); } void wayland_data_unref(struct wl_display *display, void *vk_surface) { if (has_wayland_display(display)) { displays[display].ref--; } // use the VkSurface to remove reference count else if (vk_surface) { for (auto& display : displays) { if (display.second.vk_surfaces.count(vk_surface)) display.second.ref--; } } // clear out all displays with 0 ref count for (auto it = displays.begin(); it != displays.end(); it++) { if (it->second.ref == 0) it = displays.erase(it); if (it == displays.end()) break; } } bool has_wayland_display(struct wl_display *display) { return displays.find(display) != displays.end(); } bool wayland_has_keys_pressed(const std::vector& keys) { std::map counter; for (const auto& display : displays) { for (const KeySym& k : keys) if (display.second.wl_pressed_keys.count(k)) counter[display.first]++; } /* if any of the displays has count == keys.size then it has all required keys pressed */ for (const auto& count : counter) { if (count.second == keys.size()) return true; } return false; } ================================================ FILE: src/win/d3d11_hook.cpp ================================================ #include "kiero.h" #if KIERO_INCLUDE_D3D11 #include "d3d11_hook.h" #include #include #include "d3d_shared.h" typedef long(__stdcall* Present)(IDXGISwapChain*, UINT, UINT); static Present oPresent = NULL; long __stdcall hkPresent11(IDXGISwapChain* pSwapChain, UINT SyncInterval, UINT Flags) { dx_version = kiero::RenderType::D3D11; #ifdef _MSC_VER static auto addr = _ReturnAddress(); if(addr == _ReturnAddress()){ #else static auto addr = __builtin_return_address(0); if(addr == __builtin_return_address(0)){ #endif d3d_run(); } return oPresent(pSwapChain, SyncInterval, Flags); } void impl::d3d11::init() { printf("init d3d11\n"); auto ret = kiero::bind(8, (void**)&oPresent, reinterpret_cast(hkPresent11)); assert(ret == kiero::Status::Success); init_d3d_shared(); } #endif // KIERO_INCLUDE_D3D11 ================================================ FILE: src/win/d3d11_hook.h ================================================ #pragma once #ifndef __D3D11_IMPL_H__ #define __D3D11_IMPL_H__ #include namespace impl { namespace d3d11 { void init(); } } long __stdcall hkPresent11(IDXGISwapChain* pSwapChain, UINT SyncInterval, UINT Flags); #endif // __D3D11_IMPL_H__ ================================================ FILE: src/win/d3d12_hook.cpp ================================================ #include #include #include "kiero.h" #include "d3d12_hook.h" #include "d3d_shared.h" #include "../overlay.h" typedef long(__fastcall* PresentD3D12) (IDXGISwapChain* pSwapChain, UINT SyncInterval, UINT Flags); PresentD3D12 oPresentD3D12; long __fastcall hkPresent12(IDXGISwapChain3* pSwapChain, UINT SyncInterval, UINT Flags){ dx_version = kiero::RenderType::D3D12; d3d_run(); return oPresentD3D12(pSwapChain, SyncInterval, Flags); } void impl::d3d12::init() { printf("init d3d12\n"); auto ret = kiero::bind(140, (void**)&oPresentD3D12, reinterpret_cast(hkPresent12)); assert(ret == kiero::Status::Success); init_d3d_shared(); } ================================================ FILE: src/win/d3d12_hook.h ================================================ #pragma once #include #include #include #ifdef _MSC_VER #include #else #include "/usr/i686-w64-mingw32/include/d3d12.h" #endif #ifndef __D3D12_IMPL_H__ #define __D3D12_IMPL_H__ namespace impl { namespace d3d12 { void init(); } } long __fastcall hkPresent12(IDXGISwapChain3* pSwapChain, UINT SyncInterval, UINT Flags); #endif // __D3D12_IMPL_H__ ================================================ FILE: src/win/d3d_shared.cpp ================================================ #include "d3d_shared.h" #include "overlay.h" bool cfg_inited = false; ImVec2 window_size; overlay_params params {}; struct swapchain_stats sw_stats {}; uint32_t vendorID; kiero::RenderType::Enum dx_version; void init_d3d_shared(){ if (!logger) logger = std::make_unique(¶ms); vendorID = get_device_id_dxgi(); if (cfg_inited) return; parse_overlay_config(¶ms, getenv("MANGOHUD_CONFIG"), false); cfg_inited = true; // init_cpu_stats(params); } void d3d_run(){ check_keybinds(params); update_hud_info(sw_stats, params, vendorID); } ================================================ FILE: src/win/d3d_shared.h ================================================ #include "../overlay.h" #include "kiero.h" extern bool cfg_inited; extern ImVec2 window_size; extern struct overlay_params params; extern struct swapchain_stats sw_stats; extern uint32_t vendorID; extern kiero::RenderType::Enum dx_version; extern void init_d3d_shared(void); extern void d3d_run(void); extern uint32_t get_device_id_dxgi(void); ================================================ FILE: src/win/dxgi.cpp ================================================ #include "kiero.h" #include "windows.h" #include #include #include "dxgi.h" #ifdef _UNICODE # define KIERO_TEXT(text) L##text #else # define KIERO_TEXT(text) text #endif uint32_t get_device_id_dxgi(){ HMODULE libDXGI; if ((libDXGI = ::GetModuleHandle(KIERO_TEXT("dxgi.dll"))) == NULL){ printf("dxgi not found\n"); return 0; } auto CreateDXGIFactory = reinterpret_cast(::GetProcAddress(libDXGI, "CreateDXGIFactory")); if (!CreateDXGIFactory) { printf("can't create dxgi factory\n"); return 0; } IDXGIAdapter* dxgi_adapter; IDXGIFactory* dxgi_factory; if (((long(__stdcall*)(const IID&, void**))(CreateDXGIFactory))(__uuidof(IDXGIFactory), (void**)&dxgi_factory) < 0) { printf("can't assign factory\n"); return 0; } DXGI_ADAPTER_DESC AdapterDesc; int i; for (i = 0; SUCCEEDED(dxgi_factory->EnumAdapters(i, &dxgi_adapter)); i++) { dxgi_adapter->GetDesc(&AdapterDesc); if (AdapterDesc.VendorId == 0x10de) return AdapterDesc.VendorId; if (AdapterDesc.VendorId == 0x1002) return AdapterDesc.VendorId; if (AdapterDesc.VendorId == 0x8086) return AdapterDesc.VendorId; } return 0; } ================================================ FILE: src/win/dxgi.h ================================================ #pragma once uint32_t get_device_id_dxgi(); ================================================ FILE: src/win/kiero.cpp ================================================ #include "kiero.h" #include #include #include #if KIERO_INCLUDE_D3D9 # include #endif #if KIERO_INCLUDE_D3D10 # include # include # include #endif #if KIERO_INCLUDE_D3D11 # include # include #endif #if KIERO_INCLUDE_D3D12 # include #ifdef _MSC_VER #include #else #include "/usr/i686-w64-mingw32/include/d3d12.h" #endif #endif #if KIERO_INCLUDE_OPENGL # include #endif #if KIERO_INCLUDE_VULKAN # include #endif #if KIERO_USE_MINHOOK # include "MinHook.h" #endif #ifdef _UNICODE # define KIERO_TEXT(text) L##text #else # define KIERO_TEXT(text) text #endif #define KIERO_ARRAY_SIZE(arr) ((size_t)(sizeof(arr)/sizeof(arr[0]))) static kiero::RenderType::Enum g_renderType = kiero::RenderType::None; static uint150_t* g_methodsTable = NULL; kiero::Status::Enum kiero::init(RenderType::Enum _renderType) { if (g_renderType != RenderType::None) { return Status::AlreadyInitializedError; } if (_renderType != RenderType::None) { if (_renderType >= RenderType::D3D9 && _renderType <= RenderType::D3D12) { WNDCLASSEX windowClass; windowClass.cbSize = sizeof(WNDCLASSEX); windowClass.style = CS_HREDRAW | CS_VREDRAW; windowClass.lpfnWndProc = DefWindowProc; windowClass.cbClsExtra = 0; windowClass.cbWndExtra = 0; windowClass.hInstance = GetModuleHandle(NULL); windowClass.hIcon = NULL; windowClass.hCursor = NULL; windowClass.hbrBackground = NULL; windowClass.lpszMenuName = NULL; windowClass.lpszClassName = KIERO_TEXT("Kiero"); windowClass.hIconSm = NULL; ::RegisterClassEx(&windowClass); HWND window = ::CreateWindow(windowClass.lpszClassName, KIERO_TEXT("Kiero DirectX Window"), WS_OVERLAPPEDWINDOW, 0, 0, 100, 100, NULL, NULL, windowClass.hInstance, NULL); if (_renderType == RenderType::D3D9) { #if KIERO_INCLUDE_D3D9 HMODULE libD3D9; if ((libD3D9 = ::GetModuleHandle(KIERO_TEXT("d3d9.dll"))) == NULL) { ::DestroyWindow(window); ::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance); return Status::ModuleNotFoundError; } void* Direct3DCreate9; if ((Direct3DCreate9 = ::GetProcAddress(libD3D9, "Direct3DCreate9")) == NULL) { ::DestroyWindow(window); ::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance); return Status::UnknownError; } LPDIRECT3D9 direct3D9; if ((direct3D9 = ((LPDIRECT3D9(__stdcall*)(uint32_t))(Direct3DCreate9))(D3D_SDK_VERSION)) == NULL) { ::DestroyWindow(window); ::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance); return Status::UnknownError; } D3DDISPLAYMODE displayMode; if (direct3D9->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &displayMode) < 0) { ::DestroyWindow(window); ::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance); return Status::UnknownError; } D3DPRESENT_PARAMETERS params; params.BackBufferWidth = 0; params.BackBufferHeight = 0; params.BackBufferFormat = displayMode.Format; params.BackBufferCount = 0; params.MultiSampleType = D3DMULTISAMPLE_NONE; params.MultiSampleQuality = NULL; params.SwapEffect = D3DSWAPEFFECT_DISCARD; params.hDeviceWindow = window; params.Windowed = 1; params.EnableAutoDepthStencil = 0; params.AutoDepthStencilFormat = D3DFMT_UNKNOWN; params.Flags = NULL; params.FullScreen_RefreshRateInHz = 0; params.PresentationInterval = 0; LPDIRECT3DDEVICE9 device; if (direct3D9->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, window, D3DCREATE_SOFTWARE_VERTEXPROCESSING | D3DCREATE_DISABLE_DRIVER_MANAGEMENT, ¶ms, &device) < 0) { direct3D9->Release(); ::DestroyWindow(window); ::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance); return Status::UnknownError; } g_methodsTable = (uint150_t*)::calloc(119, sizeof(uint150_t)); ::memcpy(g_methodsTable, *(uint150_t**)device, 119 * sizeof(uint150_t)); #if KIERO_USE_MINHOOK MH_Initialize(); #endif direct3D9->Release(); direct3D9 = NULL; device->Release(); device = NULL; g_renderType = RenderType::D3D9; ::DestroyWindow(window); ::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance); return Status::Success; #endif } else if (_renderType == RenderType::D3D10) { #if KIERO_INCLUDE_D3D10 HMODULE libDXGI; HMODULE libD3D10; if ((libDXGI = ::GetModuleHandle(KIERO_TEXT("dxgi.dll"))) == NULL || (libD3D10 = ::GetModuleHandle(KIERO_TEXT("d3d10.dll"))) == NULL) { ::DestroyWindow(window); ::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance); return Status::ModuleNotFoundError; } void* CreateDXGIFactory; if ((CreateDXGIFactory = ::GetProcAddress(libDXGI, "CreateDXGIFactory")) == NULL) { ::DestroyWindow(window); ::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance); return Status::UnknownError; } IDXGIFactory* factory; if (((long(__stdcall*)(const IID&, void**))(CreateDXGIFactory))(__uuidof(IDXGIFactory), (void**)&factory) < 0) { ::DestroyWindow(window); ::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance); return Status::UnknownError; } IDXGIAdapter* adapter; if (factory->EnumAdapters(0, &adapter) == DXGI_ERROR_NOT_FOUND) { ::DestroyWindow(window); ::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance); return Status::UnknownError; } void* D3D10CreateDeviceAndSwapChain; if ((D3D10CreateDeviceAndSwapChain = ::GetProcAddress(libD3D10, "D3D10CreateDeviceAndSwapChain")) == NULL) { ::DestroyWindow(window); ::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance); return Status::UnknownError; } DXGI_RATIONAL refreshRate; refreshRate.Numerator = 60; refreshRate.Denominator = 1; DXGI_MODE_DESC bufferDesc; bufferDesc.Width = 100; bufferDesc.Height = 100; bufferDesc.RefreshRate = refreshRate; bufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; bufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED; bufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED; DXGI_SAMPLE_DESC sampleDesc; sampleDesc.Count = 1; sampleDesc.Quality = 0; DXGI_SWAP_CHAIN_DESC swapChainDesc; swapChainDesc.BufferDesc = bufferDesc; swapChainDesc.SampleDesc = sampleDesc; swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; swapChainDesc.BufferCount = 1; swapChainDesc.OutputWindow = window; swapChainDesc.Windowed = 1; swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; swapChainDesc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH; IDXGISwapChain* swapChain; ID3D10Device* device; if (((long(__stdcall*)( IDXGIAdapter*, D3D10_DRIVER_TYPE, HMODULE, UINT, UINT, DXGI_SWAP_CHAIN_DESC*, IDXGISwapChain**, ID3D10Device**))(D3D10CreateDeviceAndSwapChain))(adapter, D3D10_DRIVER_TYPE_HARDWARE, NULL, 0, D3D10_SDK_VERSION, &swapChainDesc, &swapChain, &device) < 0) { ::DestroyWindow(window); ::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance); return Status::UnknownError; } g_methodsTable = (uint150_t*)::calloc(116, sizeof(uint150_t)); ::memcpy(g_methodsTable, *(uint150_t**)swapChain, 18 * sizeof(uint150_t)); ::memcpy(g_methodsTable + 18, *(uint150_t**)device, 98 * sizeof(uint150_t)); #if KIERO_USE_MINHOOK MH_Initialize(); #endif swapChain->Release(); swapChain = NULL; device->Release(); device = NULL; ::DestroyWindow(window); ::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance); g_renderType = RenderType::D3D10; return Status::Success; #endif } else if (_renderType == RenderType::D3D11) { #if KIERO_INCLUDE_D3D11 HMODULE libD3D11; if ((libD3D11 = ::GetModuleHandle(KIERO_TEXT("d3d11.dll"))) == NULL) { ::DestroyWindow(window); ::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance); return Status::ModuleNotFoundError; } auto D3D11CreateDeviceAndSwapChain = reinterpret_cast(::GetProcAddress(libD3D11, "D3D11CreateDeviceAndSwapChain")); if (!D3D11CreateDeviceAndSwapChain) { ::DestroyWindow(window); ::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance); return Status::UnknownError; } D3D_FEATURE_LEVEL featureLevel; const D3D_FEATURE_LEVEL featureLevels[] = { D3D_FEATURE_LEVEL_10_1, D3D_FEATURE_LEVEL_11_0 }; DXGI_RATIONAL refreshRate; refreshRate.Numerator = 60; refreshRate.Denominator = 1; DXGI_MODE_DESC bufferDesc; bufferDesc.Width = 100; bufferDesc.Height = 100; bufferDesc.RefreshRate = refreshRate; bufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; bufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED; bufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED; DXGI_SAMPLE_DESC sampleDesc; sampleDesc.Count = 1; sampleDesc.Quality = 0; DXGI_SWAP_CHAIN_DESC swapChainDesc; swapChainDesc.BufferDesc = bufferDesc; swapChainDesc.SampleDesc = sampleDesc; swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; swapChainDesc.BufferCount = 1; swapChainDesc.OutputWindow = window; swapChainDesc.Windowed = 1; swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; swapChainDesc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH; IDXGISwapChain* swapChain; ID3D11Device* device; ID3D11DeviceContext* context; if (((long(__stdcall*)( IDXGIAdapter*, D3D_DRIVER_TYPE, HMODULE, UINT, const D3D_FEATURE_LEVEL*, UINT, UINT, const DXGI_SWAP_CHAIN_DESC*, IDXGISwapChain**, ID3D11Device**, D3D_FEATURE_LEVEL*, ID3D11DeviceContext**))(D3D11CreateDeviceAndSwapChain))(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, 0, featureLevels, 2, D3D11_SDK_VERSION, &swapChainDesc, &swapChain, &device, &featureLevel, &context) < 0) { ::DestroyWindow(window); ::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance); return Status::UnknownError; } g_methodsTable = (uint150_t*)::calloc(205, sizeof(uint150_t)); ::memcpy(g_methodsTable, *(uint150_t**)swapChain, 18 * sizeof(uint150_t)); ::memcpy(g_methodsTable + 18, *(uint150_t**)device, 43 * sizeof(uint150_t)); ::memcpy(g_methodsTable + 18 + 43, *(uint150_t**)context, 144 * sizeof(uint150_t)); #if KIERO_USE_MINHOOK MH_Initialize(); #endif swapChain->Release(); swapChain = NULL; device->Release(); device = NULL; context->Release(); context = NULL; ::DestroyWindow(window); ::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance); g_renderType = RenderType::D3D11; return Status::Success; #endif } else if (_renderType == RenderType::D3D12) { #if KIERO_INCLUDE_D3D12 HMODULE libDXGI; HMODULE libD3D12; if ((libDXGI = ::GetModuleHandle(KIERO_TEXT("dxgi.dll"))) == NULL || (libD3D12 = ::GetModuleHandle(KIERO_TEXT("d3d12.dll"))) == NULL) { ::DestroyWindow(window); ::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance); return Status::ModuleNotFoundError; } auto CreateDXGIFactory = reinterpret_cast(::GetProcAddress(libDXGI, "CreateDXGIFactory")); if (!CreateDXGIFactory) { ::DestroyWindow(window); ::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance); return Status::UnknownError; } IDXGIFactory* factory; if (((long(__stdcall*)(const IID&, void**))(CreateDXGIFactory))(__uuidof(IDXGIFactory), (void**)&factory) < 0) { ::DestroyWindow(window); ::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance); return Status::UnknownError; } IDXGIAdapter* adapter; if (factory->EnumAdapters(0, &adapter) == DXGI_ERROR_NOT_FOUND) { ::DestroyWindow(window); ::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance); return Status::UnknownError; } auto D3D12CreateDevice = reinterpret_cast(::GetProcAddress(libD3D12, "D3D12CreateDevice")); if (!D3D12CreateDevice) { ::DestroyWindow(window); ::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance); return Status::UnknownError; } ID3D12Device* device; if (((long(__stdcall*)(IUnknown*, D3D_FEATURE_LEVEL, const IID&, void**))(D3D12CreateDevice))(adapter, D3D_FEATURE_LEVEL_11_0, __uuidof(ID3D12Device), (void**)&device) < 0) { ::DestroyWindow(window); ::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance); return Status::UnknownError; } D3D12_COMMAND_QUEUE_DESC queueDesc; queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT; queueDesc.Priority = 0; queueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE; queueDesc.NodeMask = 0; ID3D12CommandQueue* commandQueue; if (device->CreateCommandQueue(&queueDesc, __uuidof(ID3D12CommandQueue), (void**)&commandQueue) < 0) { ::DestroyWindow(window); ::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance); return Status::UnknownError; } ID3D12CommandAllocator* commandAllocator; if (device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, __uuidof(ID3D12CommandAllocator), (void**)&commandAllocator) < 0) { ::DestroyWindow(window); ::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance); return Status::UnknownError; } ID3D12GraphicsCommandList* commandList; if (device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, commandAllocator, NULL, __uuidof(ID3D12GraphicsCommandList), (void**)&commandList) < 0) { ::DestroyWindow(window); ::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance); return Status::UnknownError; } DXGI_RATIONAL refreshRate; refreshRate.Numerator = 60; refreshRate.Denominator = 1; DXGI_MODE_DESC bufferDesc; bufferDesc.Width = 100; bufferDesc.Height = 100; bufferDesc.RefreshRate = refreshRate; bufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; bufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED; bufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED; DXGI_SAMPLE_DESC sampleDesc; sampleDesc.Count = 1; sampleDesc.Quality = 0; DXGI_SWAP_CHAIN_DESC swapChainDesc = {}; swapChainDesc.BufferDesc = bufferDesc; swapChainDesc.SampleDesc = sampleDesc; swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; swapChainDesc.BufferCount = 2; swapChainDesc.OutputWindow = window; swapChainDesc.Windowed = 1; swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; swapChainDesc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH; IDXGISwapChain* swapChain; if (factory->CreateSwapChain(commandQueue, &swapChainDesc, &swapChain) < 0) { ::DestroyWindow(window); ::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance); return Status::UnknownError; } g_methodsTable = (uint150_t*)::calloc(150, sizeof(uint150_t)); ::memcpy(g_methodsTable, *(uint150_t**)device, 44 * sizeof(uint150_t)); ::memcpy(g_methodsTable + 44, *(uint150_t**)commandQueue, 19 * sizeof(uint150_t)); ::memcpy(g_methodsTable + 44 + 19, *(uint150_t**)commandAllocator, 9 * sizeof(uint150_t)); ::memcpy(g_methodsTable + 44 + 19 + 9, *(uint150_t**)commandList, 60 * sizeof(uint150_t)); ::memcpy(g_methodsTable + 44 + 19 + 9 + 60, *(uint150_t**)swapChain, 18 * sizeof(uint150_t)); #if KIERO_USE_MINHOOK MH_Initialize(); #endif device->Release(); device = NULL; commandQueue->Release(); commandQueue = NULL; commandAllocator->Release(); commandAllocator = NULL; commandList->Release(); commandList = NULL; swapChain->Release(); swapChain = NULL; ::DestroyWindow(window); ::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance); g_renderType = RenderType::D3D12; return Status::Success; #endif } ::DestroyWindow(window); ::UnregisterClass(windowClass.lpszClassName, windowClass.hInstance); return Status::NotSupportedError; } else if (_renderType != RenderType::Auto) { if (_renderType == RenderType::OpenGL) { #if KIERO_INCLUDE_OPENGL HMODULE libOpenGL32; if ((libOpenGL32 = ::GetModuleHandle(KIERO_TEXT("opengl32.dll"))) == NULL) { return Status::ModuleNotFoundError; } const char* const methodsNames[] = { "glAccum", "glAlphaFunc", "glAreTexturesResident", "glArrayElement", "glBegin", "glBindTexture", "glBitmap", "glBlendFunc", "glCallList", "glCallLists", "glClear", "glClearAccum", "glClearColor", "glClearDepth", "glClearIndex", "glClearStencil", "glClipPlane", "glColor3b", "glColor3bv", "glColor3d", "glColor3dv", "glColor3f", "glColor3fv", "glColor3i", "glColor3iv", "glColor3s", "glColor3sv", "glColor3ub", "glColor3ubv", "glColor3ui", "glColor3uiv", "glColor3us", "glColor3usv", "glColor4b", "glColor4bv", "glColor4d", "glColor4dv", "glColor4f", "glColor4fv", "glColor4i", "glColor4iv", "glColor4s", "glColor4sv", "glColor4ub", "glColor4ubv", "glColor4ui", "glColor4uiv", "glColor4us", "glColor4usv", "glColorMask", "glColorMaterial", "glColorPointer", "glCopyPixels", "glCopyTexImage1D", "glCopyTexImage2D", "glCopyTexSubImage1D", "glCopyTexSubImage2D", "glCullFaceglCullFace", "glDeleteLists", "glDeleteTextures", "glDepthFunc", "glDepthMask", "glDepthRange", "glDisable", "glDisableClientState", "glDrawArrays", "glDrawBuffer", "glDrawElements", "glDrawPixels", "glEdgeFlag", "glEdgeFlagPointer", "glEdgeFlagv", "glEnable", "glEnableClientState", "glEnd", "glEndList", "glEvalCoord1d", "glEvalCoord1dv", "glEvalCoord1f", "glEvalCoord1fv", "glEvalCoord2d", "glEvalCoord2dv", "glEvalCoord2f", "glEvalCoord2fv", "glEvalMesh1", "glEvalMesh2", "glEvalPoint1", "glEvalPoint2", "glFeedbackBuffer", "glFinish", "glFlush", "glFogf", "glFogfv", "glFogi", "glFogiv", "glFrontFace", "glFrustum", "glGenLists", "glGenTextures", "glGetBooleanv", "glGetClipPlane", "glGetDoublev", "glGetError", "glGetFloatv", "glGetIntegerv", "glGetLightfv", "glGetLightiv", "glGetMapdv", "glGetMapfv", "glGetMapiv", "glGetMaterialfv", "glGetMaterialiv", "glGetPixelMapfv", "glGetPixelMapuiv", "glGetPixelMapusv", "glGetPointerv", "glGetPolygonStipple", "glGetString", "glGetTexEnvfv", "glGetTexEnviv", "glGetTexGendv", "glGetTexGenfv", "glGetTexGeniv", "glGetTexImage", "glGetTexLevelParameterfv", "glGetTexLevelParameteriv", "glGetTexParameterfv", "glGetTexParameteriv", "glHint", "glIndexMask", "glIndexPointer", "glIndexd", "glIndexdv", "glIndexf", "glIndexfv", "glIndexi", "glIndexiv", "glIndexs", "glIndexsv", "glIndexub", "glIndexubv", "glInitNames", "glInterleavedArrays", "glIsEnabled", "glIsList", "glIsTexture", "glLightModelf", "glLightModelfv", "glLightModeli", "glLightModeliv", "glLightf", "glLightfv", "glLighti", "glLightiv", "glLineStipple", "glLineWidth", "glListBase", "glLoadIdentity", "glLoadMatrixd", "glLoadMatrixf", "glLoadName", "glLogicOp", "glMap1d", "glMap1f", "glMap2d", "glMap2f", "glMapGrid1d", "glMapGrid1f", "glMapGrid2d", "glMapGrid2f", "glMaterialf", "glMaterialfv", "glMateriali", "glMaterialiv", "glMatrixMode", "glMultMatrixd", "glMultMatrixf", "glNewList", "glNormal3b", "glNormal3bv", "glNormal3d", "glNormal3dv", "glNormal3f", "glNormal3fv", "glNormal3i", "glNormal3iv", "glNormal3s", "glNormal3sv", "glNormalPointer", "glOrtho", "glPassThrough", "glPixelMapfv", "glPixelMapuiv", "glPixelMapusv", "glPixelStoref", "glPixelStorei", "glPixelTransferf", "glPixelTransferi", "glPixelZoom", "glPointSize", "glPolygonMode", "glPolygonOffset", "glPolygonStipple", "glPopAttrib", "glPopClientAttrib", "glPopMatrix", "glPopName", "glPrioritizeTextures", "glPushAttrib", "glPushClientAttrib", "glPushMatrix", "glPushName", "glRasterPos2d", "glRasterPos2dv", "glRasterPos2f", "glRasterPos2fv", "glRasterPos2i", "glRasterPos2iv", "glRasterPos2s", "glRasterPos2sv", "glRasterPos3d", "glRasterPos3dv", "glRasterPos3f", "glRasterPos3fv", "glRasterPos3i", "glRasterPos3iv", "glRasterPos3s", "glRasterPos3sv", "glRasterPos4d", "glRasterPos4dv", "glRasterPos4f", "glRasterPos4fv", "glRasterPos4i", "glRasterPos4iv", "glRasterPos4s", "glRasterPos4sv", "glReadBuffer", "glReadPixels", "glRectd", "glRectdv", "glRectf", "glRectfv", "glRecti", "glRectiv", "glRects", "glRectsv", "glRenderMode", "glRotated", "glRotatef", "glScaled", "glScalef", "glScissor", "glSelectBuffer", "glShadeModel", "glStencilFunc", "glStencilMask", "glStencilOp", "glTexCoord1d", "glTexCoord1dv", "glTexCoord1f", "glTexCoord1fv", "glTexCoord1i", "glTexCoord1iv", "glTexCoord1s", "glTexCoord1sv", "glTexCoord2d", "glTexCoord2dv", "glTexCoord2f", "glTexCoord2fv", "glTexCoord2i", "glTexCoord2iv", "glTexCoord2s", "glTexCoord2sv", "glTexCoord3d", "glTexCoord3dv", "glTexCoord3f", "glTexCoord3fv", "glTexCoord3i", "glTexCoord3iv", "glTexCoord3s", "glTexCoord3sv", "glTexCoord4d", "glTexCoord4dv", "glTexCoord4f", "glTexCoord4fv", "glTexCoord4i", "glTexCoord4iv", "glTexCoord4s", "glTexCoord4sv", "glTexCoordPointer", "glTexEnvf", "glTexEnvfv", "glTexEnvi", "glTexEnviv", "glTexGend", "glTexGendv", "glTexGenf", "glTexGenfv", "glTexGeni", "glTexGeniv", "glTexImage1D", "glTexImage2D", "glTexParameterf", "glTexParameterfv", "glTexParameteri", "glTexParameteriv", "glTexSubImage1D", "glTexSubImage2D", "glTranslated", "glTranslatef", "glVertex2d", "glVertex2dv", "glVertex2f", "glVertex2fv", "glVertex2i", "glVertex2iv", "glVertex2s", "glVertex2sv", "glVertex3d", "glVertex3dv", "glVertex3f", "glVertex3fv", "glVertex3i", "glVertex3iv", "glVertex3s", "glVertex3sv", "glVertex4d", "glVertex4dv", "glVertex4f", "glVertex4fv", "glVertex4i", "glVertex4iv", "glVertex4s", "glVertex4sv", "glVertexPointer", "glViewport" }; size_t size = KIERO_ARRAY_SIZE(methodsNames); g_methodsTable = (uint150_t*)::calloc(size, sizeof(uint150_t)); for (int i = 0; i < size; i++) { g_methodsTable[i] = (uint150_t)::GetProcAddress(libOpenGL32, methodsNames[i]); } #if KIERO_USE_MINHOOK MH_Initialize(); #endif g_renderType = RenderType::OpenGL; return Status::Success; #endif } else if (_renderType == RenderType::Vulkan) { #if KIERO_INCLUDE_VULKAN HMODULE libVulkan; if ((libVulkan = GetModuleHandle(KIERO_TEXT("vulkan-1.dll"))) == NULL) { return Status::ModuleNotFoundError; } const char* const methodsNames[] = { "vkCreateInstance", "vkDestroyInstance", "vkEnumeratePhysicalDevices", "vkGetPhysicalDeviceFeatures", "vkGetPhysicalDeviceFormatProperties", "vkGetPhysicalDeviceImageFormatProperties", "vkGetPhysicalDeviceProperties", "vkGetPhysicalDeviceQueueFamilyProperties", "vkGetPhysicalDeviceMemoryProperties", "vkGetInstanceProcAddr", "vkGetDeviceProcAddr", "vkCreateDevice", "vkDestroyDevice", "vkEnumerateInstanceExtensionProperties", "vkEnumerateDeviceExtensionProperties", "vkEnumerateDeviceLayerProperties", "vkGetDeviceQueue", "vkQueueSubmit", "vkQueueWaitIdle", "vkDeviceWaitIdle", "vkAllocateMemory", "vkFreeMemory", "vkMapMemory", "vkUnmapMemory", "vkFlushMappedMemoryRanges", "vkInvalidateMappedMemoryRanges", "vkGetDeviceMemoryCommitment", "vkBindBufferMemory", "vkBindImageMemory", "vkGetBufferMemoryRequirements", "vkGetImageMemoryRequirements", "vkGetImageSparseMemoryRequirements", "vkGetPhysicalDeviceSparseImageFormatProperties", "vkQueueBindSparse", "vkCreateFence", "vkDestroyFence", "vkResetFences", "vkGetFenceStatus", "vkWaitForFences", "vkCreateSemaphore", "vkDestroySemaphore", "vkCreateEvent", "vkDestroyEvent", "vkGetEventStatus", "vkSetEvent", "vkResetEvent", "vkCreateQueryPool", "vkDestroyQueryPool", "vkGetQueryPoolResults", "vkCreateBuffer", "vkDestroyBuffer", "vkCreateBufferView", "vkDestroyBufferView", "vkCreateImage", "vkDestroyImage", "vkGetImageSubresourceLayout", "vkCreateImageView", "vkDestroyImageView", "vkCreateShaderModule", "vkDestroyShaderModule", "vkCreatePipelineCache", "vkDestroyPipelineCache", "vkGetPipelineCacheData", "vkMergePipelineCaches", "vkCreateGraphicsPipelines", "vkCreateComputePipelines", "vkDestroyPipeline", "vkCreatePipelineLayout", "vkDestroyPipelineLayout", "vkCreateSampler", "vkDestroySampler", "vkCreateDescriptorSetLayout", "vkDestroyDescriptorSetLayout", "vkCreateDescriptorPool", "vkDestroyDescriptorPool", "vkResetDescriptorPool", "vkAllocateDescriptorSets", "vkFreeDescriptorSets", "vkUpdateDescriptorSets", "vkCreateFramebuffer", "vkDestroyFramebuffer", "vkCreateRenderPass", "vkDestroyRenderPass", "vkGetRenderAreaGranularity", "vkCreateCommandPool", "vkDestroyCommandPool", "vkResetCommandPool", "vkAllocateCommandBuffers", "vkFreeCommandBuffers", "vkBeginCommandBuffer", "vkEndCommandBuffer", "vkResetCommandBuffer", "vkCmdBindPipeline", "vkCmdSetViewport", "vkCmdSetScissor", "vkCmdSetLineWidth", "vkCmdSetDepthBias", "vkCmdSetBlendConstants", "vkCmdSetDepthBounds", "vkCmdSetStencilCompareMask", "vkCmdSetStencilWriteMask", "vkCmdSetStencilReference", "vkCmdBindDescriptorSets", "vkCmdBindIndexBuffer", "vkCmdBindVertexBuffers", "vkCmdDraw", "vkCmdDrawIndexed", "vkCmdDrawIndirect", "vkCmdDrawIndexedIndirect", "vkCmdDispatch", "vkCmdDispatchIndirect", "vkCmdCopyBuffer", "vkCmdCopyImage", "vkCmdBlitImage", "vkCmdCopyBufferToImage", "vkCmdCopyImageToBuffer", "vkCmdUpdateBuffer", "vkCmdFillBuffer", "vkCmdClearColorImage", "vkCmdClearDepthStencilImage", "vkCmdClearAttachments", "vkCmdResolveImage", "vkCmdSetEvent", "vkCmdResetEvent", "vkCmdWaitEvents", "vkCmdPipelineBarrier", "vkCmdBeginQuery", "vkCmdEndQuery", "vkCmdResetQueryPool", "vkCmdWriteTimestamp", "vkCmdCopyQueryPoolResults", "vkCmdPushConstants", "vkCmdBeginRenderPass", "vkCmdNextSubpass", "vkCmdEndRenderPass", "vkCmdExecuteCommands" }; size_t size = KIERO_ARRAY_SIZE(methodsNames); g_methodsTable = (uint150_t*)::calloc(size, sizeof(uint150_t)); for (int i = 0; i < size; i++) { g_methodsTable[i] = (uint150_t)::GetProcAddress(libVulkan, methodsNames[i]); } #if KIERO_USE_MINHOOK MH_Initialize(); #endif g_renderType = RenderType::Vulkan; return Status::Success; #endif } return Status::NotSupportedError; } } return Status::Success; } void kiero::shutdown() { if (g_renderType != RenderType::None) { #if KIERO_USE_MINHOOK MH_DisableHook(MH_ALL_HOOKS); #endif ::free(g_methodsTable); g_methodsTable = NULL; g_renderType = RenderType::None; } } kiero::Status::Enum kiero::bind(uint16_t _index, void** _original, void* _function) { // TODO: Need own detour function assert(_original != NULL && _function != NULL); if (g_renderType != RenderType::None) { #if KIERO_USE_MINHOOK void* target = (void*)g_methodsTable[_index]; if (MH_CreateHook(target, _function, _original) != MH_OK || MH_EnableHook(target) != MH_OK) { return Status::UnknownError; } #endif return Status::Success; } return Status::NotInitializedError; } void kiero::unbind(uint16_t _index) { if (g_renderType != RenderType::None) { #if KIERO_USE_MINHOOK MH_DisableHook((void*)g_methodsTable[_index]); #endif } } kiero::RenderType::Enum kiero::getRenderType() { return g_renderType; } uint150_t* kiero::getMethodsTable() { return g_methodsTable; } ================================================ FILE: src/win/kiero.h ================================================ #ifndef __KIERO_H__ #define __KIERO_H__ #include #define KIERO_VERSION "1.2.10" #define KIERO_INCLUDE_D3D9 0 // 1 if you need D3D9 hook #define KIERO_INCLUDE_D3D10 0 // 1 if you need D3D10 hook #define KIERO_INCLUDE_D3D11 1 // 1 if you need D3D11 hook #define KIERO_INCLUDE_D3D12 1 // 1 if you need D3D12 hook #define KIERO_INCLUDE_OPENGL 0 // 1 if you need OpenGL hook #define KIERO_INCLUDE_VULKAN 1 // 1 if you need Vulkan hook #define KIERO_USE_MINHOOK 1 // 1 if you will use kiero::bind function #define KIERO_ARCH_X64 0 #define KIERO_ARCH_X86 0 #if defined(_M_X64) # undef KIERO_ARCH_X64 # define KIERO_ARCH_X64 1 #else # undef KIERO_ARCH_X86 # define KIERO_ARCH_X86 1 #endif #if KIERO_ARCH_X64 typedef uint64_t uint150_t; #else typedef uint32_t uint150_t; #endif namespace kiero { struct Status { enum Enum { UnknownError = -1, NotSupportedError = -2, ModuleNotFoundError = -3, AlreadyInitializedError = -4, NotInitializedError = -5, Success = 0, }; }; struct RenderType { enum Enum { None, D3D9, D3D10, D3D11, D3D12, OpenGL, Vulkan, Auto }; }; Status::Enum init(RenderType::Enum renderType); void shutdown(); Status::Enum bind(uint16_t index, void** original, void* function); void unbind(uint16_t index); RenderType::Enum getRenderType(); uint150_t* getMethodsTable(); } #endif // __KIERO_H__ ================================================ FILE: src/win/main.cpp ================================================ #include #include "kiero.h" #include #include "win_shared.h" #if KIERO_INCLUDE_D3D11 # include "d3d11_hook.h" #endif #if KIERO_INCLUDE_D3D12 # include "d3d12_hook.h" #endif #ifdef _UNICODE # define KIERO_TEXT(text) L##text #else # define KIERO_TEXT(text) text #endif std::vector render_types; void ConsoleSetup() { // With this trick we'll be able to print content to the console, and if we have luck we could get information printed by the game. AllocConsole(); SetConsoleTitle("MangoHud"); freopen("CONOUT$", "w", stdout); freopen("CONOUT$", "w", stderr); freopen("CONIN$", "r", stdin); } void renderTypes() { render_types.clear(); if (::GetModuleHandle(KIERO_TEXT("d3d9.dll")) != NULL) { render_types.push_back(kiero::RenderType::D3D9); } if (::GetModuleHandle(KIERO_TEXT("d3d10.dll")) != NULL) { render_types.push_back(kiero::RenderType::D3D10); } if (::GetModuleHandle(KIERO_TEXT("d3d11.dll")) != NULL) { render_types.push_back(kiero::RenderType::D3D11); } if (::GetModuleHandle(KIERO_TEXT("d3d12.dll")) != NULL) { render_types.push_back(kiero::RenderType::D3D12); } if (::GetModuleHandle(KIERO_TEXT("opengl32.dll")) != NULL) { render_types.push_back(kiero::RenderType::OpenGL); } for (auto& _type : render_types) kiero::init(_type); } int MainThread() { ConsoleSetup(); printf("MangoHud Attached!\n"); renderTypes(); if (!render_types.empty()){ impl::d3d11::init(); impl::d3d12::init(); return 1; } return 0; } BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD fdwReason, LPVOID) { DisableThreadLibraryCalls(hInstance); switch (fdwReason) { case DLL_PROCESS_ATTACH: CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)MainThread, NULL, 0, NULL); break; } return TRUE; } ================================================ FILE: src/win/win_shared.h ================================================ #pragma once #include "windows.h" void ConsoleSetup(); void renderTypes(); int MainThread(); BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD fdwReason, LPVOID); ================================================ FILE: src/winesync.h ================================================ #include "file_utils.h" #include #include #include #include "hud_elements.h" #include "overlay.h" namespace fs = ghc::filesystem; class WineSync { private: inline static const std::unordered_map methods { {"NONE", "NONE"}, {"winesync", "Wserver"}, {"esync", "Esync"}, {"fsync", "Fsync"}, {"ntsync", "NTsync"}, }; pid_t pid; std::string method = "NONE"; bool inside_wine = true; public: void determine_sync_variant() { #ifdef __linux__ // check that's were inside wine std::string wineProcess = get_exe_path(); auto n = wineProcess.find_last_of('/'); std::string preloader = wineProcess.substr(n + 1); if (preloader != "wine-preloader" && preloader != "wine64-preloader"){ inside_wine = false; return; } for (auto& [key, val] : methods) { if (lib_loaded(key, pid)) { method = key; break; } } SPDLOG_DEBUG("Wine sync method: {}", methods.at(method)); #endif } bool valid() { return inside_wine; } // return sync method as display name const char* get_method() { return methods.at(method).c_str(); } void set_pid(pid_t _pid) { if (_pid != pid) { pid = _pid; determine_sync_variant(); } } }; extern std::unique_ptr winesync_ptr; ================================================ FILE: steamrt.Dockerfile.in ================================================ FROM scratch ADD com.valvesoftware.SteamRuntime.Sdk-amd64,i386-%RUNTIME%-sysroot.tar.gz / WORKDIR /build RUN \ set -e; \ mkdir -p /run/systemd; \ echo 'docker' > /run/systemd/container; \ mkdir -p /prep; cd /prep; \ if [ -f /usr/bin/python3.5 ]; then \ ln -sf python3.5 /usr/bin/python3; \ curl https://bootstrap.pypa.io/pip/3.5/get-pip.py -o get-pip.py; \ else \ curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py; \ fi; \ if [ ! -f /usr/bin/unzip ]; then apt-get update; apt-get -y install unzip; fi; \ python3 ./get-pip.py; \ pip3 install meson mako; \ curl -LO http://mirrors.kernel.org/ubuntu/pool/main/n/nvidia-settings/libxnvctrl0_440.64-0ubuntu1_amd64.deb; \ curl -LO http://mirrors.kernel.org/ubuntu/pool/main/n/nvidia-settings/libxnvctrl-dev_440.64-0ubuntu1_amd64.deb; \ dpkg -i libxnvctrl0_440.64-0ubuntu1_amd64.deb libxnvctrl-dev_440.64-0ubuntu1_amd64.deb; \ cd /; rm -fr /prep; \ : CMD ["/bin/bash"] ================================================ FILE: subprojects/cmocka.wrap ================================================ [wrap-git] url = https://gitlab.com/cmocka/cmocka.git revision = 59dc0013f9f29fcf212fe4911c78e734263ce24c depth = 1 branch = master ================================================ FILE: subprojects/imgui.wrap ================================================ [wrap-file] directory = imgui-1.91.6 source_url = https://github.com/ocornut/imgui/archive/refs/tags/v1.91.6.tar.gz source_filename = imgui-1.91.6.tar.gz source_hash = c5fbc5dcab1d46064001c3b84d7a88812985cde7e0e9ced03f5677bec1ba502a patch_filename = imgui_1.91.6-3_patch.zip patch_url = https://wrapdb.mesonbuild.com/v2/imgui_1.91.6-3/get_patch patch_hash = 2f7977114ba07d06559aaf8890a92a4ebd25186592d4447954605aaf2244634d source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/imgui_1.91.6-3/imgui-1.91.6.tar.gz wrapdb_version = 1.91.6-3 [provide] imgui = imgui_dep ================================================ FILE: subprojects/implot.wrap ================================================ [wrap-file] directory = implot-0.16 source_url = https://github.com/epezent/implot/archive/refs/tags/v0.16.zip source_filename = implot-0.16.zip source_hash = 24f772c688f6b8a6e19d7efc10e4923a04a915f13d487b08b83553aa62ae1708 patch_filename = implot_0.16-1_patch.zip patch_url = https://wrapdb.mesonbuild.com/v2/implot_0.16-1/get_patch patch_hash = 1c6b1462066a5452fa50c1da1dd47fed841f28232972c82d778f2962936568c7 source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/implot_0.16-1/implot-0.16.zip wrapdb_version = 0.16-1 [provide] implot = implot_dep ================================================ FILE: subprojects/minhook.wrap ================================================ [wrap-git] url = https://github.com/flightlessmango/minhook.git revision = 81d6f8c775b0be984a91ea927b7beadb4f2d9d86 depth = 1 branch = master ================================================ FILE: subprojects/packagefiles/vulkan-headers/meson.build ================================================ project( 'vulkan-headers', 'c', license: 'Apache-2.0', version: '1.4.345', meson_version: '>=0.56.0', ) vulkan_api_xml = files('registry/vk.xml') vulkan_headers_dep = declare_dependency( include_directories: include_directories('include'), ) meson.override_dependency('VulkanHeaders', vulkan_headers_dep) ================================================ FILE: subprojects/packagefiles/vulkan-utility-libraries/meson.build ================================================ project( 'vulkan-utility-libraries', 'c', license: 'Apache-2.0', version: '1.4.346', meson_version: '>=0.56.0', ) vulkan_utility_libraries_dep = declare_dependency( include_directories: include_directories('include'), ) meson.override_dependency('VulkanUtilityLibraries', vulkan_utility_libraries_dep) ================================================ FILE: subprojects/spdlog.wrap ================================================ [wrap-file] directory = spdlog-1.14.1 source_url = https://github.com/gabime/spdlog/archive/refs/tags/v1.14.1.tar.gz source_filename = spdlog-1.14.1.tar.gz source_hash = 1586508029a7d0670dfcb2d97575dcdc242d3868a259742b69f100801ab4e16b patch_filename = spdlog_1.14.1-1_patch.zip patch_url = https://wrapdb.mesonbuild.com/v2/spdlog_1.14.1-1/get_patch patch_hash = ae878e732330ea1048f90d7e117c40c0cd2a6fb8ae5492c7955818ce3aaade6c source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/spdlog_1.14.1-1/spdlog-1.14.1.tar.gz wrapdb_version = 1.14.1-1 [provide] spdlog = spdlog_dep ================================================ FILE: subprojects/vulkan-headers.wrap ================================================ [wrap-file] directory = Vulkan-Headers-1.4.346 source_url = https://github.com/KhronosGroup/Vulkan-Headers/archive/v1.4.346.tar.gz source_filename = vulkan-headers-1.4.346.tar.gz source_hash = 5bb77f5d7b460e255a9e51affc00d64354986b55cf577d8eab28529cad01fc80 patch_directory = vulkan-headers [provide] dependency_names = VulkanHeaders ================================================ FILE: subprojects/vulkan-utility-libraries.wrap ================================================ [wrap-file] directory = Vulkan-Utility-Libraries-1.4.346 source_url = https://github.com/KhronosGroup/Vulkan-Utility-Libraries/archive/v1.4.346.tar.gz source_filename = vulkan-utility-libraries-1.4.346.tar.gz source_hash = 372eb525103ecb4e3a04d030b2a9778ebc67853bbdc82ce6747de3757d432ad9 patch_directory = vulkan-utility-libraries [provide] dependency_names = VulkanUtilityLibraries ================================================ FILE: tests/params.py ================================================ import re import subprocess class Test: def __init__(self): self.options = {} self.error_count = 0 self.ignore_params = ["pci_dev", "mangoapp_steam", "fsr_steam_sharpness", "blacklist", "media_player_format"] # self.files_changed() self.get_options() self.get_param_defaults() self.find_options_in_readme() self.find_options_in_conf() if self.error_count > 0: print(f"number of errors: {self.error_count}") exit(1) def get_options(self): regex = r"\((.*?)\)" with open('../src/overlay_params.h') as f: for line in f: if ("OVERLAY_PARAM_BOOL" in line or "OVERLAY_PARAM_CUSTOM" in line) and not "#" in line: match = re.search(regex, line) if match: key = match.group(1) if key in self.ignore_params: continue else: self.options[key] = None def find_options_in_readme(self): with open("../README.md") as f: file = f.read() for option in self.options: if not option in file: self.error_count += 1 print(f"Option: {option} is not found in README.md") def find_options_in_conf(self): with open("../data/MangoHud.conf") as f: file = f.read() for option, val in self.options.items(): if not option in file: self.error_count += 1 print(f"Option: {option} is not found in MangoHud.conf") if option in file: option = "# " + option for line in file.splitlines(): if option in line: line = line.strip().split("=") if len(line) != 2: continue key = line[0].strip("#").strip() if key not in self.options: continue value = line[1].strip() if "," in value: value = value.split(",") if self.options[key] != value: self.error_count += 1 print(f"Sample config: option: {key} value is not the same as default") print(f"default: {self.options[key]}, config: {value}") print("") def get_param_defaults(self): # Open the C++ file with open('../src/overlay_params.cpp', 'r') as f: # Read the contents of the file contents = f.read() # Define the name of the function to search for function_name = 'set_param_defaults' # Define a regular expression to match the function definition function_regex = re.compile(r"void\s+" + function_name + r"\s*\(([^)]*)\)\s*{(.+?)\s*}\s*\n", re.MULTILINE | re.DOTALL) # Find the match of the regular expression in the file contents match = function_regex.search(contents) # If the function is found, extract the contents if match: # Extract the contents of the function function_contents = match.group(2) for line in function_contents.splitlines(): # FIXME: Some variables get stored as string in a string if not "enabled" in line: line = line.replace("params->", "") line = line.strip().strip(";").split("=") if len(line) != 2: continue key = line[0].strip() value = line[1].strip() if key not in self.options: continue # convert to a list if it contains curly bracket if "{" in value: value = value.replace("{", "").replace("}", "").strip().split(", ") # If option has color in it's name we can assume it's value is # one or more colors and that they are in binary. # We want to convert this from binary because the config # will not be in this format if "color" in key: value = [hex[2:] for hex in value] value = [string.upper() for string in value] # same reasoning as above if "color" in key and type(value) is str: value = value[2:] value = value.upper() if "fps_sampling_period" in key: value = re.sub(r';\s*/\*.*?\*/', '', value) value = str(int(int(value) / 1000000)) # if value is a list, make sure we don't store str in str if type(value) == list: value = [element.strip('"') for element in value] self.options[key] = value Test() ================================================ FILE: tests/test_amdgpu.cpp ================================================ #include #include #include #include extern "C" { #include } #include "stdio.h" #include "../src/amdgpu.h" #define UNUSED(x) (void)(x) static void test_amdgpu_verify_metrics(void **state) { UNUSED(state); AMDGPU amdgpu("", 0x744c, 0x1002); assert_false(amdgpu.verify_metrics("./missing_file")); // unsupported struct size, format and content revision assert_false(amdgpu.verify_metrics("./gpu_metrics_invalid")); assert_true (amdgpu.verify_metrics("./gpu_metrics")); } static void test_amdgpu_get_instant_metrics(void **state) { UNUSED(state); struct amdgpu_common_metrics metrics; AMDGPU amdgpu("", 0x744c, 0x1002); std::string metrics_path; // fail fetch gpu_metrics file metrics_path = "./missing_file"; amdgpu.get_instant_metrics(&metrics); // DGPU metrics_path = "./gpu_metrics"; metrics = {}; amdgpu.get_instant_metrics(&metrics); assert_int_equal(metrics.gpu_load_percent, 64); assert_float_equal(metrics.average_gfx_power_w, 33, 0); assert_float_equal(metrics.average_cpu_power_w, 0, 0); assert_int_equal(metrics.current_gfxclk_mhz, 2165); assert_int_equal(metrics.current_uclk_mhz, 1000); assert_int_equal(metrics.gpu_temp_c, 36); assert_int_equal(metrics.soc_temp_c, 0); assert_int_equal(metrics.apu_cpu_temp_c, 0); assert_false(metrics.is_power_throttled); assert_false(metrics.is_current_throttled); assert_false(metrics.is_temp_throttled); assert_false(metrics.is_other_throttled); // DGPU metrics_path = "./gpu_metrics_reserved_throttle_bits"; metrics = {}; amdgpu.get_instant_metrics(&metrics); assert_false(metrics.is_power_throttled); assert_false(metrics.is_current_throttled); assert_false(metrics.is_temp_throttled); assert_false(metrics.is_other_throttled); metrics_path = "./gpu_metrics_apu"; metrics = {}; amdgpu.get_instant_metrics(&metrics); assert_int_equal(metrics.gpu_load_percent, 100); assert_float_equal(metrics.average_gfx_power_w, 6.161, 0); assert_float_equal(metrics.average_cpu_power_w, 9.235, 0); assert_int_equal(metrics.current_gfxclk_mhz, 1040); assert_int_equal(metrics.current_uclk_mhz, 687); assert_int_equal(metrics.gpu_temp_c, 81); assert_int_equal(metrics.soc_temp_c, 71); assert_int_equal(metrics.apu_cpu_temp_c, 80); assert_true(metrics.is_power_throttled); assert_false(metrics.is_current_throttled); assert_false(metrics.is_temp_throttled); assert_false(metrics.is_other_throttled); // amdgpu binary with everything throttled } static void test_amdgpu_get_samples_and_copy(void **state) { UNUSED(state); AMDGPU amdgpu("", 0x744c, 0x1002); struct amdgpu_common_metrics metrics_buffer[100]; bool gpu_load_needs_dividing = false; //some GPUs report load as centipercent amdgpu.get_samples_and_copy(metrics_buffer, gpu_load_needs_dividing); gpu_load_needs_dividing = true; amdgpu.get_samples_and_copy(metrics_buffer, gpu_load_needs_dividing); } static void test_amdgpu_get_metrics(void **state) { UNUSED(state); AMDGPU amdgpu("", 0x744c, 0x1002); amdgpu.copy_metrics(); } const struct CMUnitTest amdgpu_tests[] = { cmocka_unit_test(test_amdgpu_verify_metrics), cmocka_unit_test(test_amdgpu_get_instant_metrics), cmocka_unit_test(test_amdgpu_get_samples_and_copy), cmocka_unit_test(test_amdgpu_get_metrics) }; int main(void) { return cmocka_run_group_tests(amdgpu_tests, NULL, NULL); } ================================================ FILE: version.h.in ================================================ #pragma once #define MANGOHUD_VERSION "@VCS_TAG@"