mirror of
https://github.com/fastfetch-cli/fastfetch.git
synced 2026-09-12 18:32:10 +02:00
Compare commits
122 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d48bd733f0 | |||
| 0585ea7797 | |||
| 794035f8d9 | |||
| 723552f68b | |||
| 8dd38f5744 | |||
| 616a5c7aea | |||
| 5e1e94473e | |||
| 4eae8ac244 | |||
| 8aeb7c2f10 | |||
| c20b532c7a | |||
| 3c59161aca | |||
| bd454632c3 | |||
| e73adc27a0 | |||
| 15c6014c04 | |||
| 54f18982ac | |||
| 99c2f2a2c8 | |||
| 45f35b1c4d | |||
| 428c05b9de | |||
| 23ca6d94ab | |||
| 9e4e0cb838 | |||
| 95a370e5a2 | |||
| e013005f34 | |||
| 92b86f7cbb | |||
| 2e4b7baf44 | |||
| a47ff0b2dc | |||
| 1f13f6c8f5 | |||
| b0bb6fb58e | |||
| 37029dbbe3 | |||
| 35428606e7 | |||
| 2c65eee00f | |||
| a1bf014352 | |||
| 412fc94dab | |||
| b65de28805 | |||
| bc86c66cdd | |||
| 9afa01812d | |||
| 30a8a94cd2 | |||
| 3a54617196 | |||
| 3e3a03a233 | |||
| b407669b69 | |||
| e14ea926a5 | |||
| 9d8f794cb9 | |||
| 825b8b8715 | |||
| 0c94fd87db | |||
| 473a08d85c | |||
| ae5132c388 | |||
| 1addcec7a2 | |||
| e75c37c101 | |||
| b9ab823f77 | |||
| a63d854681 | |||
| 576548b15e | |||
| 3043971259 | |||
| ccf4f22f8b | |||
| f932db713c | |||
| d2e8a8fd9e | |||
| 4c1f7c114a | |||
| 90bbfe195f | |||
| 1689fc81e9 | |||
| 4190dd5a6e | |||
| 074f882d7e | |||
| 53102380b8 | |||
| 822bc158ba | |||
| 8fbc29a70c | |||
| 0ef677a98c | |||
| 10b0d0ca3e | |||
| ec4e820e92 | |||
| 6c09fe49e4 | |||
| 1ce6398391 | |||
| d1bf208a92 | |||
| 7ce1e553b8 | |||
| 9c878b6943 | |||
| 6b9a6fd103 | |||
| 896fe60461 | |||
| dadcccdf26 | |||
| 0746af7549 | |||
| 88c3b7d118 | |||
| 173d9695b6 | |||
| 4b265cd56a | |||
| 1f211cf8d1 | |||
| bac60357c6 | |||
| 3a0e188570 | |||
| 9d5b40686b | |||
| a321cd877e | |||
| 5f810de1e0 | |||
| 3f0a93d057 | |||
| cbca6a965c | |||
| fde1195c27 | |||
| 9856d97bd1 | |||
| 2751737ebe | |||
| 834292df29 | |||
| a9a29869a4 | |||
| 242fb50461 | |||
| b5c4ffcc85 | |||
| 2c3628c630 | |||
| 4cca9bf198 | |||
| 0ed27d9700 | |||
| 9bca4eb48f | |||
| 462b80fc36 | |||
| f49620a95b | |||
| 6e0949c739 | |||
| 4b18ab0de7 | |||
| 8abd75a746 | |||
| d5b215e074 | |||
| 0b22427091 | |||
| aa34910b6c | |||
| 52972ed833 | |||
| 68e75effab | |||
| bb79370d03 | |||
| 9613cdd146 | |||
| 724b816252 | |||
| 7c89a10add | |||
| fb5ec76eb3 | |||
| 7141214f95 | |||
| 7d6074968f | |||
| 3bd380802b | |||
| ec1200dc06 | |||
| 5c18c061b3 | |||
| acf610416c | |||
| 90d3b3d49f | |||
| bbc5b4de98 | |||
| 7f9b6187a6 | |||
| 8067e43631 | |||
| 61dba1ea05 |
@@ -21,7 +21,7 @@ jobs:
|
||||
prepare: |
|
||||
uname -a
|
||||
pkg update
|
||||
pkg install -y llvm cmake git pkgconf binutils wayland vulkan-headers vulkan-loader libxcb libXrandr libX11 libdrm glib dconf dbus sqlite3-tcl egl opencl ocl-icd v4l_compat chafa libelf
|
||||
pkg install -y llvm cmake git pkgconf binutils wayland vulkan-headers vulkan-loader libxcb libXrandr libX11 libdrm glib dconf dbus sqlite3-tcl egl opencl ocl-icd v4l_compat chafa libelf lua54 libva libvdpau
|
||||
|
||||
run: |
|
||||
env CC=clang cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_EMBEDDED_PCIIDS=On -DENABLE_EMBEDDED_AMDGPUIDS=On .
|
||||
|
||||
@@ -25,7 +25,7 @@ jobs:
|
||||
run: |
|
||||
uname -a
|
||||
sudo pkg update
|
||||
sudo pkg install -y cmake git pkgconf binutils wayland vulkan-headers vulkan-loader libxcb libXrandr libX11 libdrm glib dconf dbus sqlite3-tcl egl opencl ocl-icd v4l_compat chafa
|
||||
sudo pkg install -y cmake git pkgconf binutils wayland vulkan-headers vulkan-loader libxcb libXrandr libX11 libdrm glib dconf dbus sqlite3-tcl egl opencl ocl-icd v4l_compat chafa lua54 libva libvdpau
|
||||
cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_EMBEDDED_PCIIDS=On -DENABLE_EMBEDDED_AMDGPUIDS=On .
|
||||
cmake --build . --target package --verbose -j4
|
||||
./fastfetch --list-features
|
||||
|
||||
@@ -24,7 +24,7 @@ jobs:
|
||||
environment_variables: 'CMAKE_BUILD_TYPE'
|
||||
run: |
|
||||
uname -a
|
||||
pkgman install -y git dbus_devel mesa_devel libelf_devel imagemagick_devel opencl_headers ocl_icd_devel vulkan_devel zlib_devel chafa_devel cmake gcc make pkgconfig python3.10 || pkgman install -y git dbus_devel mesa_devel libelf_devel imagemagick_devel opencl_headers ocl_icd_devel vulkan_devel zlib_devel chafa_devel cmake gcc make pkgconfig python3.10
|
||||
pkgman install -y git dbus_devel mesa_devel libelf_devel imagemagick_devel opencl_headers ocl_icd_devel vulkan_devel zlib_devel chafa_devel cmake gcc make pkgconfig python3.10 || pkgman install -y git dbus_devel mesa_devel libelf_devel imagemagick_devel opencl_headers ocl_icd_devel vulkan_devel zlib_devel chafa_devel cmake gcc make pkgconfig python3.10 lua
|
||||
cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_EMBEDDED_PCIIDS=On -DENABLE_EMBEDDED_AMDGPUIDS=On .
|
||||
cmake --build . --target package --verbose -j4
|
||||
./fastfetch --list-features
|
||||
|
||||
@@ -23,7 +23,7 @@ jobs:
|
||||
run: |
|
||||
uname -a
|
||||
apt-get update && apt-get install -y wget
|
||||
apt-get install -y cmake make gcc libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libsqlite3-dev librpm-dev libegl-dev libglx-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libelf-dev libefl-all-dev rpm
|
||||
apt-get install -y cmake make gcc libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libsqlite3-dev librpm-dev libegl-dev libglx-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libelf-dev libefl-all-dev liblua5.4-dev libvdpau-dev libva-dev rpm
|
||||
cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DCMAKE_INSTALL_PREFIX=/usr .
|
||||
cmake --build . --target package --verbose -j4
|
||||
./fastfetch --list-features
|
||||
|
||||
@@ -27,7 +27,7 @@ jobs:
|
||||
curl -L https://apt.kitware.com/keys/kitware-archive-latest.asc | gpg --dearmor - | tee /usr/share/keyrings/kitware-archive-keyring.gpg >/dev/null
|
||||
echo 'deb [signed-by=/usr/share/keyrings/kitware-archive-keyring.gpg] https://apt.kitware.com/ubuntu/ jammy main' | tee /etc/apt/sources.list.d/kitware.list >/dev/null
|
||||
echo -e 'Acquire::https::Verify-Peer "false";\nAcquire::https::Verify-Host "false";' >> /etc/apt/apt.conf.d/99ignore-certificates
|
||||
apt-get update && apt-get install -y cmake make gcc-13 libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libsqlite3-dev librpm-dev libegl-dev libglx-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libelf-dev libefl-all-dev rpm
|
||||
apt-get update && apt-get install -y cmake make gcc-13 libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libsqlite3-dev librpm-dev libegl-dev libglx-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libelf-dev libefl-all-dev liblua5.4-dev libvdpau-dev libva-dev rpm
|
||||
CC=gcc-13 cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DCMAKE_INSTALL_PREFIX=/usr .
|
||||
cmake --build . --target package --verbose -j4
|
||||
./fastfetch --list-features
|
||||
|
||||
@@ -39,12 +39,12 @@ jobs:
|
||||
run: sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test
|
||||
|
||||
- name: install required packages
|
||||
run: sudo apt-get update && sudo apt-get install -y gcc-13 libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libsqlite3-dev librpm-dev libegl-dev libglx-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libelf-dev libddcutil-dev libefl-all-dev libunwind-dev rpm ninja-build
|
||||
run: sudo apt-get update && sudo apt-get install -y gcc-13 libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libsqlite3-dev librpm-dev libegl-dev libglx-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libelf-dev libddcutil-dev libefl-all-dev libunwind-dev liblua5.4-dev libvdpau-dev libva-dev rpm ninja-build
|
||||
|
||||
- name: install linuxbrew packages
|
||||
run: |
|
||||
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
|
||||
/home/linuxbrew/.linuxbrew/bin/brew install imagemagick chafa --ignore-dependencies
|
||||
/home/linuxbrew/.linuxbrew/bin/brew install imagemagick chafa quickjs-ng --ignore-dependencies
|
||||
|
||||
- name: Initialize CodeQL
|
||||
if: inputs.arch == 'amd64'
|
||||
@@ -53,7 +53,7 @@ jobs:
|
||||
languages: c
|
||||
|
||||
- name: configure project
|
||||
run: CC=gcc-13 PKG_CONFIG_PATH=/home/linuxbrew/.linuxbrew/lib/pkgconfig:$PKG_CONFIG_PATH cmake -GNinja -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_EMBEDDED_PCIIDS=On -DENABLE_EMBEDDED_AMDGPUIDS=On -DCMAKE_INSTALL_PREFIX=/usr .
|
||||
run: CC=gcc-13 CMAKE_PREFIX_PATH=/home/linuxbrew/.linuxbrew PKG_CONFIG_PATH=/home/linuxbrew/.linuxbrew/lib/pkgconfig:$PKG_CONFIG_PATH cmake -GNinja -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_EMBEDDED_PCIIDS=On -DENABLE_EMBEDDED_AMDGPUIDS=On -DCMAKE_INSTALL_PREFIX=/usr .
|
||||
|
||||
- name: build project
|
||||
run: cmake --build . --target package --verbose -j4
|
||||
|
||||
@@ -26,18 +26,18 @@ jobs:
|
||||
run: sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test
|
||||
|
||||
- name: install required packages
|
||||
run: sudo apt-get update && sudo apt-get install -y gcc-13 gcc-13-multilib libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libsqlite3-dev librpm-dev libegl-dev libglx-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libelf-dev libddcutil-dev libefl-all-dev libunwind-dev rpm ninja-build
|
||||
run: sudo apt-get update && sudo apt-get install -y gcc-13 gcc-13-multilib libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libsqlite3-dev librpm-dev libegl-dev libglx-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libelf-dev libddcutil-dev libefl-all-dev libunwind-dev liblua5.4-dev libvdpau-dev libva-dev rpm ninja-build
|
||||
|
||||
- name: install linuxbrew packages
|
||||
run: |
|
||||
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
|
||||
/home/linuxbrew/.linuxbrew/bin/brew install imagemagick chafa --ignore-dependencies
|
||||
/home/linuxbrew/.linuxbrew/bin/brew install imagemagick chafa quickjs-ng --ignore-dependencies
|
||||
|
||||
- name: cmake version
|
||||
run: cmake --version
|
||||
|
||||
- name: configure project
|
||||
run: CC=gcc-13 PKG_CONFIG_PATH=/home/linuxbrew/.linuxbrew/lib/pkgconfig:$PKG_CONFIG_PATH cmake -DCMAKE_C_FLAGS="-m32 -march=i686 -mtune=i686" -DCMAKE_SYSTEM_PROCESSOR_OVERRIDE=i686 -DCPACK_DEBIAN_PACKAGE_ARCHITECTURE=i386 -GNinja -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_EMBEDDED_PCIIDS=On -DENABLE_EMBEDDED_AMDGPUIDS=On -DCMAKE_INSTALL_PREFIX=/usr .
|
||||
run: CC=gcc-13 CMAKE_PREFIX_PATH=/home/linuxbrew/.linuxbrew PKG_CONFIG_PATH=/home/linuxbrew/.linuxbrew/lib/pkgconfig:$PKG_CONFIG_PATH cmake -DCMAKE_C_FLAGS="-m32 -march=i686 -mtune=i686" -DCMAKE_SYSTEM_PROCESSOR_OVERRIDE=i686 -DCPACK_DEBIAN_PACKAGE_ARCHITECTURE=i386 -GNinja -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_EMBEDDED_PCIIDS=On -DENABLE_EMBEDDED_AMDGPUIDS=On -DCMAKE_INSTALL_PREFIX=/usr .
|
||||
|
||||
- name: build project
|
||||
run: cmake --build . --target package --verbose -j4
|
||||
|
||||
@@ -28,7 +28,7 @@ jobs:
|
||||
uname -a
|
||||
apt-get update && apt-get install -y software-properties-common
|
||||
add-apt-repository -y ppa:ubuntu-toolchain-r/test
|
||||
apt-get update && apt-get install -y cmake make gcc-13 libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libsqlite3-dev librpm-dev libegl-dev libglx-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libchafa-dev libelf-dev libefl-all-dev rpm
|
||||
apt-get update && apt-get install -y cmake make gcc-13 libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libsqlite3-dev librpm-dev libegl-dev libglx-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libchafa-dev libelf-dev libefl-all-dev liblua5.4-dev libvdpau-dev libva-dev rpm
|
||||
CC=gcc-13 cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DCMAKE_INSTALL_PREFIX=/usr .
|
||||
cmake --build . --target package --verbose -j4
|
||||
./fastfetch --list-features
|
||||
|
||||
@@ -25,7 +25,8 @@ jobs:
|
||||
|
||||
- name: install required packages
|
||||
run: |
|
||||
HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=1 brew install --overwrite vulkan-loader vulkan-headers molten-vk imagemagick chafa
|
||||
HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=1 brew update
|
||||
HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=1 brew install --overwrite vulkan-loader vulkan-headers molten-vk imagemagick chafa lua quickjs-ng
|
||||
|
||||
- name: configure project
|
||||
run: cmake -DSET_TWEAK=Off -DBUILD_TESTS=On .
|
||||
|
||||
@@ -14,12 +14,14 @@ jobs:
|
||||
|
||||
- name: setup alpine linux
|
||||
uses: jirutka/setup-alpine@master
|
||||
with:
|
||||
branch: edge
|
||||
|
||||
- name: install dependencies
|
||||
run: |
|
||||
cat /etc/alpine-release
|
||||
uname -a
|
||||
apk add cmake samurai vulkan-loader-dev libxcb-dev libxrandr-dev rpm-dev wayland-dev libdrm-dev dconf-dev imagemagick-dev chafa-dev zlib-dev dbus-dev mesa-dev opencl-dev sqlite-dev networkmanager-dev pulseaudio-dev ddcutil-dev elfutils-dev gcc g++
|
||||
apk add cmake samurai vulkan-loader-dev libxcb-dev libxrandr-dev rpm-dev wayland-dev libdrm-dev dconf-dev imagemagick-dev chafa-dev zlib-dev dbus-dev mesa-dev opencl-dev sqlite-dev networkmanager-dev pulseaudio-dev ddcutil-dev elfutils-dev lua5.4-dev quickjs-ng-dev libvdpau-dev libva-dev gcc g++
|
||||
shell: alpine.sh --root {0}
|
||||
|
||||
- name: build
|
||||
|
||||
@@ -24,7 +24,7 @@ jobs:
|
||||
environment_variables: 'CMAKE_BUILD_TYPE'
|
||||
run: |
|
||||
uname -a
|
||||
sudo pkgin -y install clang cmake git pkgconf wayland vulkan-headers dconf dbus sqlite3 ImageMagick
|
||||
sudo pkgin -y install clang cmake git pkgconf wayland vulkan-headers dconf dbus sqlite3 ImageMagick libva libvdpau
|
||||
CC=clang cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_EMBEDDED_PCIIDS=On -DENABLE_EMBEDDED_AMDGPUIDS=On .
|
||||
cmake --build . --target package --verbose -j4
|
||||
./fastfetch --list-features
|
||||
|
||||
@@ -25,7 +25,7 @@ jobs:
|
||||
run: |
|
||||
uname -a
|
||||
sudo pkg_add -u
|
||||
sudo pkg_add -r llvm-21.1.2p0 cmake git pkgconf wayland vulkan-headers vulkan-loader glib2 dconf dbus sqlite3 imagemagick chafa
|
||||
sudo pkg_add -r llvm-21.1.2p0 cmake git wayland vulkan-headers vulkan-loader glib2 dconf dbus sqlite3 imagemagick chafa lua-5.4.7 # pkg-config is preinstalled
|
||||
CC=clang-21 cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_EMBEDDED_PCIIDS=On -DENABLE_EMBEDDED_AMDGPUIDS=On .
|
||||
cmake --build . --target package --verbose -j4
|
||||
./fastfetch --list-features
|
||||
|
||||
@@ -21,7 +21,7 @@ jobs:
|
||||
release: "11.4-gcc-14"
|
||||
prepare: |
|
||||
uname -a
|
||||
pkg install cmake git pkg-config glib2 dbus sqlite-3 imagemagick ninja dconf mesa
|
||||
pkg install cmake git pkg-config glib2 dbus sqlite-3 imagemagick ninja dconf mesa lua
|
||||
|
||||
run: |
|
||||
export PKG_CONFIG_PATH=/usr/lib/64/pkgconfig
|
||||
|
||||
@@ -37,7 +37,7 @@ jobs:
|
||||
with:
|
||||
msystem: ${{ inputs.msystem }}
|
||||
update: true
|
||||
install: git mingw-w64-clang-${{ inputs.msys-arch }}-7zip mingw-w64-clang-${{ inputs.msys-arch }}-cmake mingw-w64-clang-${{ inputs.msys-arch }}-clang mingw-w64-clang-${{ inputs.msys-arch }}-vulkan-loader mingw-w64-clang-${{ inputs.msys-arch }}-vulkan-headers mingw-w64-clang-${{ inputs.msys-arch }}-opencl-icd mingw-w64-clang-${{ inputs.msys-arch }}-opencl-headers mingw-w64-clang-${{ inputs.msys-arch }}-cppwinrt mingw-w64-clang-${{ inputs.msys-arch }}-imagemagick mingw-w64-clang-${{ inputs.msys-arch }}-chafa mingw-w64-clang-${{ inputs.msys-arch }}-directx-headers
|
||||
install: git mingw-w64-clang-${{ inputs.msys-arch }}-7zip mingw-w64-clang-${{ inputs.msys-arch }}-cmake mingw-w64-clang-${{ inputs.msys-arch }}-clang mingw-w64-clang-${{ inputs.msys-arch }}-vulkan-loader mingw-w64-clang-${{ inputs.msys-arch }}-vulkan-headers mingw-w64-clang-${{ inputs.msys-arch }}-opencl-icd mingw-w64-clang-${{ inputs.msys-arch }}-opencl-headers mingw-w64-clang-${{ inputs.msys-arch }}-cppwinrt mingw-w64-clang-${{ inputs.msys-arch }}-imagemagick mingw-w64-clang-${{ inputs.msys-arch }}-chafa mingw-w64-clang-${{ inputs.msys-arch }}-lua mingw-w64-clang-${{ inputs.msys-arch }}-quickjs-ng mingw-w64-clang-${{ inputs.msys-arch }}-directx-headers
|
||||
|
||||
- name: print msys version
|
||||
run: uname -a
|
||||
@@ -49,7 +49,7 @@ jobs:
|
||||
run: cmake --build . --verbose -j4
|
||||
|
||||
- name: copy necessary dlls
|
||||
run: cp /${{ inputs.msystem-lower }}/bin/{OpenCL,vulkan-1}.dll .
|
||||
run: cp /${{ inputs.msystem-lower }}/bin/{lua55,libqjs-0}.dll .
|
||||
|
||||
- name: list features
|
||||
run: ./fastfetch --list-features
|
||||
|
||||
+70
-1
@@ -1,7 +1,75 @@
|
||||
# 2.64.0
|
||||
|
||||
New **optional build** dependencies:
|
||||
* [`libva`](https://github.com/intel/libva) and [`libvdpau`](https://www.freedesktop.org/wiki/Software/VDPAU) for the new `Codec` module.
|
||||
* [Lua 5.3 to 5.5](https://www.lua.org/) for Lua scripting support, or [QuickJS](https://github.com/quickjs-ng/quickjs) v0.15.0 or newer for JavaScript scripting support.
|
||||
|
||||
Features:
|
||||
* Adds `Codec` module support for Windows, macOS, Linux, and Android for hardware-accelerated video codec detection (Codec)
|
||||
* Backends used (results may vary depending on the backend due to driver differences):
|
||||
* Linux and BSD: VA-API (default) and VDPAU (fallback for NVIDIA). Fastfetch must be built with `libva` and `libvdpau` support to enable these backends.
|
||||
* Windows: D3D12VA (Windows 11) and D3D11VA+MFT (Windows 10 or older)
|
||||
* macOS: VideoToolbox
|
||||
* Android: AMediaCodec
|
||||
* Common: Vulkan Video (disabled by default; can be enabled with `"useVulkan": true`)
|
||||
* By default, both encoders and decoders are reported. If no codecs are detected for a given type, `None` is reported. This behavior can be configured using the `"showType": "encoder|decoder"` option.
|
||||
* Adds experimental Lua script support for custom formats (Global)
|
||||
* Basic usage (using `Title` as an example): `{ "type": "title", "format": "lua:return string.format('Hello %s@%s', (...).userName, (...).hostName)" }`. The `lua:` prefix indicates a Lua script. A `return` statement is required to pass the final result back to the fastfetch module; otherwise, `nil` is returned implicitly and the entire module output is skipped.
|
||||
* Parameters are passed via variable arguments `(...)`. Users can assign them to named variables for better readability. For example: `lua:local args = ...; string.format('Hello %s@%s', args.userName, args.hostName)`.
|
||||
* The Lua interpreter instance is shared across all modules. This allows users to store and manipulate data across modules. For example:
|
||||
* `{ "type": "shell", "format": "lua:shell = ..." } // Note: no "return" here`
|
||||
* `{ "type": "terminal", "format": "lua:return shell.prettyName .. ' in ' .. (...).prettyName" } // This will print the detected shell and terminal names`
|
||||
* A `json_encode(table, is_pretty)` function has been added to the Lua API for easier debugging. For example, `lua:return json_encode(...)` will print all available variables and their values in JSON format.
|
||||
* Supported Lua versions: Lua 5.3 to 5.5 (Lua 5.1 and LuaJIT are not supported). The Lua version is auto-detected at build time. Once built, users can check the configured Lua version using `fastfetch --list-features`.
|
||||
* Adds experimental QuickJS script support for custom formats as an alternative to Lua (Global)
|
||||
* Basic usage: `{ "type": "title", "format": "qjs:`Hello ${this.userName}@${this.hostName}`" }`. The `qjs:` prefix indicates a JavaScript script. No `return` statement is needed; the final result is simply the evaluated value of the script.
|
||||
* Parameters are passed via the `this` object. Usage is mostly the same as Lua, but using JavaScript syntax.
|
||||
* Requires [quickjs-ng v0.15.0](https://github.com/quickjs-ng/quickjs/releases/tag/v0.15.0) or newer.
|
||||
* Adds CMake options `-DMODULE_DISABLE_<MODULE_NAME>=ON` to disable modules at compile time for a smaller binary size
|
||||
* Use `cmake -L . | grep MODULE_DISABLE_` to list all available options.
|
||||
* These options rely on LTO for dead code elimination (`-DCMAKE_BUILD_TYPE=Release` should enable LTO by default).
|
||||
* Adds the ability to remove unneeded ASCII logos without modifying the fastfetch source code, further reducing binary size
|
||||
* Simply remove the corresponding logo file from the logo directory (`src/logo/ascii/[a-z]/*`) and re-run `cmake`.
|
||||
* Improves string manipulation specifiers in custom formats
|
||||
* They are now ANSI escape-aware and work correctly with colored output (e.g., percentages with `num-color`) (#2364). Limitations:
|
||||
* They are still not wide-character aware and treat CJK and emoji characters as raw bytes.
|
||||
* Escape sequences in the middle of strings are not supported.
|
||||
* A new `|` specifier has been added to center strings. For example, `{user-name|20}` will center the username in a 20-character-wide field.
|
||||
* Adds preliminary `Bootmgr`, `Brightness`, and `WMTheme` detection support for Haiku (#2358, Haiku)
|
||||
* Adds `Wallpaper` and `WMTheme` detection support for the COSMIC desktop environment (Linux)
|
||||
* Improves terminal name detection for Nix packages (#2352, Terminal, Linux)
|
||||
* Adds DDC/CI brightness detection support for FreeBSD (Brightness, FreeBSD)
|
||||
* DDC/CI communication can be very slow. Users can set the `ddcciSleep: null` option to skip DDC/CI detection.
|
||||
* Reworks the built-in logo printing logic. ASCII logos and modules are now printed line by line, avoiding issues like #2239
|
||||
* Note: Image logos are not affected by this change and still print the entire image first before printing any modules.
|
||||
* Adds a new `--logo-padding-bottom` option to control the padding between the bottom of the logo and the first module when `--logo-position top` is used
|
||||
* Previously, `--logo-padding-right` was used for both right and bottom padding.
|
||||
* Adds `Samsung Exynos 2600` to CPU detection (CPU, Android)
|
||||
* Adds terminal font detection support for the Muxy terminal (TerminalFont, macOS)
|
||||
* Improves the performance of BusyBox (ash) version detection and always reports `ash` as the pretty name (Shell, Linux)
|
||||
|
||||
Bugfixes:
|
||||
* Fixes SwayFX version detection (WM, Linux)
|
||||
* Fixes fallback font detection for Ghostty (TerminalFont, macOS)
|
||||
* Fixes `--stat` output to correctly align with the right border (Global)
|
||||
* Fixes boot manager on macOS 26 (mBoot) is incorrectly reported as `iBoot` (Bootmgr, macOS)
|
||||
|
||||
Logos:
|
||||
* Adds Quasar (#2338, #2323), Origami, Origami_small (#2321, #2322), BerserkArch (#2324, #2310), and NixOS2 (#2346)
|
||||
* Minor tweaks and color fixes for the NixOS_small logo (#2357)
|
||||
* Updates NurOS (#2366)
|
||||
|
||||
# 2.63.1
|
||||
|
||||
Bugfixes:
|
||||
* Fixes media length detection for Chrome on Linux (Media, Linux)
|
||||
* Fixes segmentation fault when specifying unsupported modules on command line
|
||||
* Disables usage of Netlink for Wi-Fi detection on s390x architectures (Wifi, Linux)
|
||||
|
||||
# 2.63.0
|
||||
|
||||
Changes:
|
||||
* Introduces a new optional dependency, `libefl`, for querying the Enlightenment window manager configuration:
|
||||
* Introduces a new **build-only** dependency, `libefl`, for querying the Enlightenment window manager configuration:
|
||||
* `libefl-all-dev` on Debian/Ubuntu
|
||||
* `libefl-devel` on Fedora
|
||||
* `efl` on Arch Linux
|
||||
@@ -14,6 +82,7 @@ Features:
|
||||
* Adds Ubuntu Kylin and Ubuntu Unity flavor detection (OS, Linux)
|
||||
* Adds NebiDE support (WMTheme, Linux)
|
||||
* Adds package counting for `cards` on NuTyX (#2287, Packages, Linux)
|
||||
* Adds `{am-pm}` to custom format for 12-hour time with am/pm (DateTime)
|
||||
* Adds support for the Enlightenment desktop environment (#2165, WM, Linux)
|
||||
* Adds support for playback progress detection (Media)
|
||||
* The module now prints the current playback position and total media duration when supported by the player. If you prefer the previous behavior, you can set `media.percent.type: ["hide-others"]` to hide the new fields.
|
||||
|
||||
+145
-27
@@ -1,7 +1,7 @@
|
||||
cmake_minimum_required(VERSION 3.12.0) # target_link_libraries with OBJECT libs & project homepage url
|
||||
|
||||
project(fastfetch
|
||||
VERSION 2.63.0
|
||||
VERSION 2.64.0
|
||||
LANGUAGES C
|
||||
DESCRIPTION "Fast neofetch-like system information tool"
|
||||
HOMEPAGE_URL "https://github.com/fastfetch-cli/fastfetch"
|
||||
@@ -74,6 +74,8 @@ cmake_dependent_option(ENABLE_WAYLAND "Enable wayland-client" ON "LINUX OR FreeB
|
||||
cmake_dependent_option(ENABLE_XCB_RANDR "Enable xcb-randr" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR ANDROID OR SunOS OR GNU" OFF)
|
||||
cmake_dependent_option(ENABLE_XRANDR "Enable xrandr" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR ANDROID OR SunOS OR GNU" OFF)
|
||||
cmake_dependent_option(ENABLE_DRM "Enable libdrm" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR SunOS OR GNU" OFF)
|
||||
cmake_dependent_option(ENABLE_VA "Enable libva" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR SunOS OR GNU" OFF)
|
||||
cmake_dependent_option(ENABLE_VDPAU "Enable vdpau" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR SunOS OR GNU" OFF)
|
||||
cmake_dependent_option(ENABLE_DRM_AMDGPU "Enable libdrm_amdgpu" ON "LINUX OR FreeBSD OR GNU" OFF)
|
||||
cmake_dependent_option(ENABLE_GIO "Enable gio-2.0" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR ANDROID OR SunOS OR GNU" OFF)
|
||||
cmake_dependent_option(ENABLE_DCONF "Enable dconf" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR ANDROID OR SunOS OR GNU" OFF)
|
||||
@@ -105,7 +107,11 @@ option(INSTALL_LICENSE "Install license into /usr/share/licenses" ON)
|
||||
option(ENABLE_EMBEDDED_PCIIDS "Embed pci.ids into fastfetch, requires `python`" OFF)
|
||||
option(ENABLE_EMBEDDED_AMDGPUIDS "Embed amdgpu.ids into fastfetch, requires `python`" OFF)
|
||||
option(ENABLE_WORDEXP "Enable using of wordexp(3) if available, instead of glob(3)" ON)
|
||||
option(ENABLE_LUA "Enable lua scripting for format strings" ON)
|
||||
option(ENABLE_QUICKJS "Enable quickjs scripting for format strings" ON)
|
||||
option(ENABLE_LIBZFS "Enable libzfs" ON)
|
||||
option(ENABLE_WCWIDTH "Detect wide-width characters with wcwidth when calculating logo and separator width. Disable for a smaller and slightly faster build, but logos containing CJK/emoji may be measured too narrow and render incorrectly. Such usecases are uncommon." ON)
|
||||
set(DEFAULT_STRUCTURE "Title:Separator:OS:Host:Kernel:Uptime:Packages:Shell:Display:DE:WM:WMTheme:Theme:Icons:Font:Cursor:Terminal:TerminalFont:CPU:GPU:Memory:Swap:Disk:LocalIp:Battery:PowerAdapter:Locale:Break:Colors" CACHE STRING "Default module structure for detection")
|
||||
if(WIN32 AND NOT CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64")
|
||||
option(ENABLE_WIN81_COMPAT "Enable legacy Windows compatibility (Windows 8.1 and later; Windows 7 unsupported)" ON)
|
||||
endif()
|
||||
@@ -113,6 +119,14 @@ if(APPLE)
|
||||
option(ENABLE_APPLE_MEMSIZE_USABLE "Use usable memory size as total memory size in Memory module, to match other systems" OFF)
|
||||
endif()
|
||||
|
||||
file(GLOB FF_MODULE_DIRS RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}/src/modules" "${CMAKE_CURRENT_SOURCE_DIR}/src/modules/*/")
|
||||
foreach(FF_MODULE_DIR ${FF_MODULE_DIRS})
|
||||
if(IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/src/modules/${FF_MODULE_DIR}")
|
||||
string(TOUPPER "${FF_MODULE_DIR}" FF_MODULE_UPPER)
|
||||
option(MODULE_DISABLE_${FF_MODULE_UPPER} "Disable module ${FF_MODULE_DIR}" OFF)
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
set(BINARY_LINK_TYPE_OPTIONS dlopen dynamic static)
|
||||
set(BINARY_LINK_TYPE dlopen CACHE STRING "How to link fastfetch")
|
||||
set_property(CACHE BINARY_LINK_TYPE PROPERTY STRINGS ${BINARY_LINK_TYPE_OPTIONS})
|
||||
@@ -287,14 +301,14 @@ find_package(Python)
|
||||
if(Python_FOUND)
|
||||
message(STATUS "Minifying 'help.json'")
|
||||
execute_process(COMMAND ${Python_EXECUTABLE} -c "import json,sys;json.dump(json.load(sys.stdin),sys.stdout,separators=(',',':'))"
|
||||
INPUT_FILE "${CMAKE_CURRENT_SOURCE_DIR}/src/data/help.json"
|
||||
INPUT_FILE "${CMAKE_CURRENT_SOURCE_DIR}/doc/help.json"
|
||||
OUTPUT_VARIABLE DATATEXT_JSON_HELP)
|
||||
if(DATATEXT_JSON_HELP STREQUAL "")
|
||||
message(ERROR "DATATEXT_JSON_HELP is empty, which should not happen!")
|
||||
endif()
|
||||
else()
|
||||
message(WARNING "Python3 is not found, 'help.json' will not be minified")
|
||||
file(READ "src/data/help.json" DATATEXT_JSON_HELP)
|
||||
file(READ "doc/help.json" DATATEXT_JSON_HELP)
|
||||
endif()
|
||||
|
||||
if(ENABLE_EMBEDDED_PCIIDS AND NOT EXISTS "${PROJECT_BINARY_DIR}/fastfetch_pciids.c.inc")
|
||||
@@ -354,7 +368,6 @@ else()
|
||||
endif()
|
||||
|
||||
fastfetch_encode_c_string("${DATATEXT_JSON_HELP}" DATATEXT_JSON_HELP)
|
||||
fastfetch_load_text(src/data/structure.txt DATATEXT_STRUCTURE)
|
||||
|
||||
configure_file(src/fastfetch_config.h.in fastfetch_config.h @ONLY)
|
||||
configure_file(src/fastfetch_datatext.h.in fastfetch_datatext.h @ONLY)
|
||||
@@ -366,7 +379,7 @@ endif()
|
||||
# Ascii image data #
|
||||
####################
|
||||
|
||||
file(GLOB LOGO_FILES CONFIGURE_DEPENDS "src/logo/ascii/*.txt")
|
||||
file(GLOB LOGO_FILES CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/src/logo/ascii/[a-z_]/*.txt")
|
||||
set(LOGO_BUILTIN_H "#pragma once\n#pragma GCC diagnostic ignored \"-Wtrigraphs\"\n\n")
|
||||
foreach(file ${LOGO_FILES})
|
||||
fastfetch_load_text("${file}" content)
|
||||
@@ -389,6 +402,7 @@ set(LIBFASTFETCH_SRC
|
||||
src/common/impl/init.c
|
||||
src/common/impl/jsonconfig.c
|
||||
src/common/impl/library.c
|
||||
src/common/impl/lua.c
|
||||
src/common/impl/netif.c
|
||||
src/common/impl/networking_common.c
|
||||
src/common/impl/option.c
|
||||
@@ -407,9 +421,12 @@ set(LIBFASTFETCH_SRC
|
||||
src/common/impl/path.c
|
||||
src/common/impl/FFPlatform.c
|
||||
src/common/impl/smbios.c
|
||||
src/common/impl/strutil.c
|
||||
src/detection/bluetoothradio/bluetoothradio.c
|
||||
src/detection/bootmgr/bootmgr.c
|
||||
src/detection/chassis/chassis.c
|
||||
src/detection/codec/codec.c
|
||||
src/detection/codec/codec_vulkan.c
|
||||
src/detection/cpu/cpu.c
|
||||
src/detection/cpuusage/cpuusage.c
|
||||
src/detection/command/command.c
|
||||
@@ -451,6 +468,7 @@ set(LIBFASTFETCH_SRC
|
||||
src/modules/btrfs/btrfs.c
|
||||
src/modules/camera/camera.c
|
||||
src/modules/chassis/chassis.c
|
||||
src/modules/codec/codec.c
|
||||
src/modules/colors/colors.c
|
||||
src/modules/cpu/cpu.c
|
||||
src/modules/cpucache/cpucache.c
|
||||
@@ -537,6 +555,7 @@ if(LINUX)
|
||||
src/detection/brightness/brightness_linux.c
|
||||
src/detection/btrfs/btrfs_linux.c
|
||||
src/detection/chassis/chassis_linux.c
|
||||
src/detection/codec/codec_linux.c
|
||||
src/detection/cpu/cpu_linux.c
|
||||
src/detection/cpucache/cpucache_linux.c
|
||||
src/detection/cpuusage/cpuusage_linux.c
|
||||
@@ -624,6 +643,7 @@ elseif(ANDROID)
|
||||
src/detection/brightness/brightness_nosupport.c
|
||||
src/detection/btrfs/btrfs_nosupport.c
|
||||
src/detection/chassis/chassis_nosupport.c
|
||||
src/detection/codec/codec_android.c
|
||||
src/detection/cpu/cpu_linux.c
|
||||
src/detection/cpucache/cpucache_linux.c
|
||||
src/detection/cursor/cursor_linux.c
|
||||
@@ -698,6 +718,7 @@ elseif(FreeBSD)
|
||||
src/detection/brightness/brightness_bsd.c
|
||||
src/detection/btrfs/btrfs_nosupport.c
|
||||
src/detection/chassis/chassis_bsd.c
|
||||
src/detection/codec/codec_linux.c
|
||||
src/detection/cpu/cpu_bsd.c
|
||||
src/detection/cpucache/cpucache_shared.c
|
||||
src/detection/cpuusage/cpuusage_bsd.c
|
||||
@@ -792,6 +813,7 @@ elseif(NetBSD)
|
||||
src/detection/brightness/brightness_nbsd.c
|
||||
src/detection/btrfs/btrfs_nosupport.c
|
||||
src/detection/chassis/chassis_nbsd.c
|
||||
src/detection/codec/codec_linux.c
|
||||
src/detection/cpu/cpu_nbsd.c
|
||||
src/detection/cpucache/cpucache_shared.c
|
||||
src/detection/cpuusage/cpuusage_bsd.c
|
||||
@@ -876,6 +898,7 @@ elseif(OpenBSD)
|
||||
src/detection/brightness/brightness_obsd.c
|
||||
src/detection/btrfs/btrfs_nosupport.c
|
||||
src/detection/chassis/chassis_windows.c
|
||||
src/detection/codec/codec_linux.c
|
||||
src/detection/cpu/cpu_obsd.c
|
||||
src/detection/cpucache/cpucache_shared.c
|
||||
src/detection/cpuusage/cpuusage_bsd.c
|
||||
@@ -952,12 +975,14 @@ elseif(APPLE)
|
||||
src/common/apple/cf_helpers.c
|
||||
src/common/apple/osascript.m
|
||||
src/common/apple/smc_temps.c
|
||||
src/common/apple/version.m
|
||||
src/detection/battery/battery_apple.c
|
||||
src/detection/bluetooth/bluetooth_apple.m
|
||||
src/detection/bluetoothradio/bluetoothradio_apple.m
|
||||
src/detection/bootmgr/bootmgr_apple.c
|
||||
src/detection/brightness/brightness_apple.c
|
||||
src/detection/btrfs/btrfs_nosupport.c
|
||||
src/detection/codec/codec_apple.c
|
||||
src/detection/cpu/cpu_apple.c
|
||||
src/detection/cpucache/cpucache_apple.c
|
||||
src/detection/cpuusage/cpuusage_apple.c
|
||||
@@ -1048,6 +1073,7 @@ elseif(WIN32)
|
||||
src/detection/brightness/brightness_windows.c
|
||||
src/detection/btrfs/btrfs_nosupport.c
|
||||
src/detection/chassis/chassis_windows.c
|
||||
src/detection/codec/codec_windows.cpp
|
||||
src/detection/cpu/cpu_windows.c
|
||||
src/detection/cpucache/cpucache_windows.c
|
||||
src/detection/cpuusage/cpuusage_windows.c
|
||||
@@ -1119,6 +1145,7 @@ elseif(SunOS)
|
||||
src/detection/cursor/cursor_linux.c
|
||||
src/detection/bluetooth/bluetooth_nosupport.c
|
||||
src/detection/bluetoothradio/bluetoothradio_nosupport.c
|
||||
src/detection/codec/codec_linux.c
|
||||
src/detection/disk/disk_sunos.c
|
||||
src/detection/dns/dns_linux.c
|
||||
src/detection/physicaldisk/physicaldisk_sunos.c
|
||||
@@ -1192,8 +1219,8 @@ elseif(Haiku)
|
||||
src/detection/battery/battery_haiku.c
|
||||
src/detection/bios/bios_windows.c
|
||||
src/detection/board/board_windows.c
|
||||
src/detection/bootmgr/bootmgr_nosupport.c
|
||||
src/detection/brightness/brightness_nosupport.c
|
||||
src/detection/bootmgr/bootmgr_haiku.cpp
|
||||
src/detection/brightness/brightness_haiku.cpp
|
||||
src/detection/btrfs/btrfs_nosupport.c
|
||||
src/detection/chassis/chassis_windows.c
|
||||
src/detection/cpu/cpu_haiku.c
|
||||
@@ -1202,6 +1229,7 @@ elseif(Haiku)
|
||||
src/detection/cursor/cursor_nosupport.c
|
||||
src/detection/bluetooth/bluetooth_haiku.cpp
|
||||
src/detection/bluetoothradio/bluetoothradio_nosupport.c
|
||||
src/detection/codec/codec_linux.c
|
||||
src/detection/disk/disk_haiku.cpp
|
||||
src/detection/dns/dns_linux.c
|
||||
src/detection/physicaldisk/physicaldisk_haiku.c
|
||||
@@ -1245,7 +1273,7 @@ elseif(Haiku)
|
||||
src/detection/wifi/wifi_nosupport.c
|
||||
src/detection/wm/wm_nosupport.c
|
||||
src/detection/de/de_nosupport.c
|
||||
src/detection/wmtheme/wmtheme_nosupport.c
|
||||
src/detection/wmtheme/wmtheme_haiku.cpp
|
||||
src/detection/camera/camera_nosupport.c
|
||||
)
|
||||
elseif(GNU)
|
||||
@@ -1271,6 +1299,7 @@ elseif(GNU)
|
||||
src/detection/cursor/cursor_linux.c
|
||||
src/detection/bluetooth/bluetooth_linux.c
|
||||
src/detection/bluetoothradio/bluetoothradio_linux.c
|
||||
src/detection/codec/codec_linux.c
|
||||
src/detection/disk/disk_linux.c
|
||||
src/detection/dns/dns_linux.c
|
||||
src/detection/physicaldisk/physicaldisk_nosupport.c
|
||||
@@ -1338,19 +1367,20 @@ if(WIN32)
|
||||
list(APPEND LIBFASTFETCH_SRC src/detection/gpu/gpu_intel.c)
|
||||
list(APPEND LIBFASTFETCH_SRC src/detection/gpu/gpu_amd.c)
|
||||
|
||||
include(CheckIncludeFileCXX)
|
||||
CHECK_INCLUDE_FILE_CXX("winrt/Windows.Foundation.h" HAVE_WINRT)
|
||||
if(HAVE_WINRT)
|
||||
message(STATUS "WinRT headers are available, media detection will be enabled")
|
||||
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
||||
message(STATUS "WinRT support is disabled due to known issues with g++")
|
||||
set(HAVE_WINRT FALSE)
|
||||
else()
|
||||
message(WARNING "WinRT headers are NOT available, media detection will be disabled")
|
||||
include(CheckIncludeFileCXX)
|
||||
CHECK_INCLUDE_FILE_CXX("winrt/Windows.Foundation.h" HAVE_WINRT)
|
||||
if(HAVE_WINRT)
|
||||
message(STATUS "WinRT headers are available, media detection will be enabled")
|
||||
else()
|
||||
message(WARNING "WinRT headers are NOT available, media detection will be disabled")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
include(CheckFunctionExists)
|
||||
check_function_exists(wcwidth HAVE_WCWIDTH)
|
||||
if(NOT HAVE_WCWIDTH)
|
||||
list(APPEND LIBFASTFETCH_SRC src/common/impl/wcwidth.c)
|
||||
endif()
|
||||
if(NOT WIN32)
|
||||
check_function_exists(pipe2 HAVE_PIPE2)
|
||||
endif()
|
||||
@@ -1358,6 +1388,9 @@ check_function_exists(memrchr HAVE_MEMRCHR)
|
||||
if(NOT HAVE_MEMRCHR)
|
||||
list(APPEND LIBFASTFETCH_SRC src/common/impl/memrchr.c)
|
||||
endif()
|
||||
if(ENABLE_WCWIDTH)
|
||||
list(APPEND LIBFASTFETCH_SRC src/common/impl/wcwidth.c)
|
||||
endif()
|
||||
|
||||
if(ENABLE_SYSTEM_YYJSON)
|
||||
find_package(yyjson)
|
||||
@@ -1376,6 +1409,15 @@ add_library(libfastfetch OBJECT
|
||||
${LIBFASTFETCH_SRC}
|
||||
)
|
||||
|
||||
foreach(FF_MODULE_DIR ${FF_MODULE_DIRS})
|
||||
if(IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/src/modules/${FF_MODULE_DIR}")
|
||||
string(TOUPPER "${FF_MODULE_DIR}" FF_MODULE_UPPER)
|
||||
if(MODULE_DISABLE_${FF_MODULE_UPPER})
|
||||
target_compile_definitions(libfastfetch PUBLIC FF_MODULE_DISABLE_${FF_MODULE_UPPER}=1)
|
||||
endif()
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
include(CheckCSourceCompiles)
|
||||
check_c_source_compiles("int main(void){int arr[1];return _Countof(arr);}" COMPILER_SUPPORTS_COUNT_OF)
|
||||
if(COMPILER_SUPPORTS_COUNT_OF)
|
||||
@@ -1509,10 +1551,6 @@ if(FreeBSD OR OpenBSD OR NetBSD)
|
||||
unset(CMAKE_REQUIRED_DEFINITIONS)
|
||||
endif()
|
||||
|
||||
if(HAVE_WCWIDTH)
|
||||
target_compile_definitions(libfastfetch PUBLIC FF_HAVE_WCWIDTH)
|
||||
endif()
|
||||
|
||||
if(HAVE_PIPE2)
|
||||
target_compile_definitions(libfastfetch PUBLIC FF_HAVE_PIPE2)
|
||||
endif()
|
||||
@@ -1542,22 +1580,52 @@ if(NOT BINARY_LINK_TYPE STREQUAL "dlopen")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
function(ff_lib_enable VARNAME PKGCONFIG_NAMES CMAKE_NAME)
|
||||
function(ff_lib_enable VARNAME PKGCONFIG_NAMES CMAKE_NAME) # [CMAKE_TARGET_NAME]
|
||||
if(NOT ENABLE_${VARNAME})
|
||||
return()
|
||||
endif()
|
||||
|
||||
if(PKG_CONFIG_FOUND)
|
||||
pkg_search_module(${VARNAME} QUIET ${PKGCONFIG_NAMES})
|
||||
if(${VARNAME}_FOUND)
|
||||
set(${VARNAME}_FOUND "pkg-config")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(NOT ${VARNAME}_FOUND)
|
||||
find_package(${CMAKE_NAME} QUIET)
|
||||
|
||||
set(${VARNAME}_FOUND ${${CMAKE_NAME}_FOUND})
|
||||
set(${VARNAME}_INCLUDE_DIRS ${${CMAKE_NAME}_INCLUDE_DIRS})
|
||||
set(${VARNAME}_LIBRARIES ${${CMAKE_NAME}_LIBRARIES})
|
||||
set(${VARNAME}_CFLAGS_OTHER ${${CMAKE_NAME}_CFLAGS_OTHER})
|
||||
if(${VARNAME}_FOUND)
|
||||
set(${VARNAME}_FOUND "CMake")
|
||||
|
||||
# Some CMake packages (e.g. quickjs) are target-based only and
|
||||
# don't expose *_INCLUDE_DIRS/*_LIBRARIES variables.
|
||||
if(ARGC GREATER 3)
|
||||
set(_FF_CMAKE_TARGET ${ARGV3})
|
||||
if(NOT _FF_CMAKE_TARGET STREQUAL "")
|
||||
if(NOT DEFINED ${VARNAME}_INCLUDE_DIRS OR "${${VARNAME}_INCLUDE_DIRS}" STREQUAL "")
|
||||
get_target_property(_FF_CMAKE_TARGET_INCLUDES ${_FF_CMAKE_TARGET} INTERFACE_INCLUDE_DIRECTORIES)
|
||||
if(_FF_CMAKE_TARGET_INCLUDES)
|
||||
set(${VARNAME}_INCLUDE_DIRS ${_FF_CMAKE_TARGET_INCLUDES})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED ${VARNAME}_LIBRARIES OR "${${VARNAME}_LIBRARIES}" STREQUAL "")
|
||||
get_target_property(_FF_CMAKE_TARGET_LIBRARIES ${_FF_CMAKE_TARGET} INTERFACE_LINK_LIBRARIES)
|
||||
if(_FF_CMAKE_TARGET_LIBRARIES)
|
||||
set(${VARNAME}_LIBRARIES ${_FF_CMAKE_TARGET_LIBRARIES})
|
||||
else()
|
||||
set(${VARNAME}_LIBRARIES ${_FF_CMAKE_TARGET})
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
else()
|
||||
set(${VARNAME}_INCLUDE_DIRS ${${CMAKE_NAME}_INCLUDE_DIRS})
|
||||
set(${VARNAME}_LIBRARIES ${${CMAKE_NAME}_LIBRARIES})
|
||||
set(${VARNAME}_CFLAGS_OTHER ${${CMAKE_NAME}_CFLAGS_OTHER})
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(NOT ${VARNAME}_FOUND)
|
||||
@@ -1565,7 +1633,7 @@ function(ff_lib_enable VARNAME PKGCONFIG_NAMES CMAKE_NAME)
|
||||
return()
|
||||
endif()
|
||||
|
||||
message(STATUS "Library: found ${VARNAME}")
|
||||
message(STATUS "Library: found ${VARNAME} by ${${VARNAME}_FOUND}")
|
||||
|
||||
target_compile_definitions(libfastfetch PRIVATE FF_HAVE_${VARNAME}=1)
|
||||
target_include_directories(libfastfetch PRIVATE ${${VARNAME}_INCLUDE_DIRS})
|
||||
@@ -1603,6 +1671,14 @@ ff_lib_enable(DRM
|
||||
"libdrm"
|
||||
"Libdrm"
|
||||
)
|
||||
ff_lib_enable(VA
|
||||
"libva"
|
||||
"Libva"
|
||||
)
|
||||
ff_lib_enable(VDPAU
|
||||
"vdpau"
|
||||
"vdpau"
|
||||
)
|
||||
ff_lib_enable(DRM_AMDGPU
|
||||
"libdrm_amdgpu"
|
||||
"Libdrm_Amdgpu"
|
||||
@@ -1682,6 +1758,36 @@ ff_lib_enable(ELF
|
||||
"libelf"
|
||||
"libelf"
|
||||
)
|
||||
ff_lib_enable(QUICKJS
|
||||
"qjs"
|
||||
"qjs"
|
||||
"qjs"
|
||||
)
|
||||
if(ENABLE_LUA)
|
||||
# Lua is a special case since its CMake config does not follow the usual pattern
|
||||
find_package(Lua QUIET)
|
||||
if(Lua_FOUND AND NOT DEFINED Lua_VERSION) # For CMake 4.2- compatible
|
||||
set(Lua_VERSION ${LUA_VERSION_STRING})
|
||||
set(Lua_VERSION_MAJOR ${LUA_VERSION_MAJOR})
|
||||
set(Lua_VERSION_MINOR ${LUA_VERSION_MINOR})
|
||||
endif()
|
||||
if(Lua_FOUND)
|
||||
if((NOT Lua_VERSION_MAJOR EQUAL 5) OR Lua_VERSION_MINOR LESS 3 OR Lua_VERSION_MINOR GREATER 5)
|
||||
message(STATUS "Library: Lua version ${Lua_VERSION} is not supported, requires 5.3-5.5")
|
||||
unset(Lua_FOUND)
|
||||
else()
|
||||
target_compile_definitions(libfastfetch PRIVATE FF_HAVE_LUA=1)
|
||||
target_include_directories(libfastfetch PRIVATE ${LUA_INCLUDE_DIR})
|
||||
|
||||
if(NOT BINARY_LINK_TYPE STREQUAL "dlopen")
|
||||
target_link_libraries(libfastfetch PRIVATE ${LUA_LIBRARIES})
|
||||
endif()
|
||||
message(STATUS "Library: found LUA ${Lua_VERSION} by CMake")
|
||||
endif()
|
||||
else()
|
||||
message(STATUS "Library: missing: LUA")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(ENABLE_THREADS)
|
||||
target_compile_definitions(libfastfetch PRIVATE FF_HAVE_THREADS=1)
|
||||
@@ -1705,8 +1811,11 @@ if(ENABLE_LIBZFS)
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
if(ENABLE_WCWIDTH)
|
||||
target_compile_definitions(libfastfetch PUBLIC FF_ENABLE_WCWIDTH=1)
|
||||
endif()
|
||||
if(NOT HAVE_MEMRCHR)
|
||||
target_compile_definitions(libfastfetch PRIVATE FF_HAVE_CUSTOM_MEMRCHR=1)
|
||||
target_compile_definitions(libfastfetch PUBLIC FF_HAVE_CUSTOM_MEMRCHR=1)
|
||||
endif()
|
||||
|
||||
if(LINUX)
|
||||
@@ -1736,6 +1845,7 @@ elseif(APPLE)
|
||||
PRIVATE "-framework OpenGL"
|
||||
PRIVATE "-framework OpenCL"
|
||||
PRIVATE "-framework SystemConfiguration"
|
||||
PRIVATE "-framework VideoToolbox"
|
||||
PRIVATE "-weak_framework CoreDisplay"
|
||||
|
||||
PRIVATE "-F /System/Library/PrivateFrameworks"
|
||||
@@ -2015,12 +2125,20 @@ if (BUILD_TESTS)
|
||||
PRIVATE libfastfetch
|
||||
)
|
||||
|
||||
add_executable(fastfetch-test-strutil
|
||||
tests/strutil.c
|
||||
)
|
||||
target_link_libraries(fastfetch-test-strutil
|
||||
PRIVATE libfastfetch
|
||||
)
|
||||
|
||||
enable_testing()
|
||||
add_test(NAME test-strbuf COMMAND fastfetch-test-strbuf)
|
||||
add_test(NAME test-list COMMAND fastfetch-test-list)
|
||||
add_test(NAME test-format COMMAND fastfetch-test-format)
|
||||
add_test(NAME test-color COMMAND fastfetch-test-color)
|
||||
add_test(NAME test-duration COMMAND fastfetch-test-duration)
|
||||
add_test(NAME test-strutil COMMAND fastfetch-test-strutil)
|
||||
endif()
|
||||
|
||||
##################
|
||||
|
||||
Vendored
+18
@@ -1,3 +1,21 @@
|
||||
fastfetch (2.63.1~#UBUNTU_CODENAME#) #UBUNTU_CODENAME#; urgency=medium
|
||||
|
||||
* Update to 2.63.1
|
||||
|
||||
-- Carter Li <zhangsongcui@live.cn> Fri, 15 May 2026 09:31:54 +0800
|
||||
|
||||
fastfetch (2.63.0~#UBUNTU_CODENAME#) #UBUNTU_CODENAME#; urgency=medium
|
||||
|
||||
* Update to 2.63.0
|
||||
|
||||
-- Carter Li <zhangsongcui@live.cn> Wed, 13 May 2026 16:02:28 +0800
|
||||
|
||||
fastfetch (2.62.1~#UBUNTU_CODENAME#) #UBUNTU_CODENAME#; urgency=medium
|
||||
|
||||
* Update to 2.62.1
|
||||
|
||||
-- Carter Li <zhangsongcui@live.cn> Fri, 24 Apr 2026 15:45:15 +0800
|
||||
|
||||
fastfetch (2.62.0~#UBUNTU_CODENAME#) #UBUNTU_CODENAME#; urgency=medium
|
||||
|
||||
* Update to 2.62.0
|
||||
|
||||
Vendored
+1
-1
@@ -2,7 +2,7 @@ Source: fastfetch
|
||||
Section: universe/utils
|
||||
Priority: optional
|
||||
Maintainer: Carter Li <zhangsongcui@live.cn>
|
||||
Build-Depends: libelf-dev, libvulkan-dev, libwayland-dev, libxrandr-dev, libxcb-randr0-dev, libdconf-dev, libdbus-1-dev, libmagickcore-dev, libsqlite3-dev, librpm-dev, libegl-dev, libglx-dev, ocl-icd-opencl-dev, libpulse-dev, libdrm-dev, libddcutil-dev, libchafa-dev, pkgconf, cmake (>= 3.12), debhelper (>= 11.2), dh-cmake, dh-cmake-compat (= 1), dh-sequence-cmake, dh-sequence-ctest, ninja-build, python3-setuptools
|
||||
Build-Depends: libelf-dev, libvulkan-dev, libwayland-dev, libxrandr-dev, libxcb-randr0-dev, libdconf-dev, libdbus-1-dev, libmagickcore-dev, libsqlite3-dev, librpm-dev, libegl-dev, libglx-dev, ocl-icd-opencl-dev, libpulse-dev, libdrm-dev, libddcutil-dev, libchafa-dev, libefl-all-dev, pkgconf, cmake (>= 3.12), debhelper (>= 11.2), dh-cmake, dh-cmake-compat (= 1), dh-sequence-cmake, dh-sequence-ctest, ninja-build, python3-setuptools
|
||||
Standards-Version: 4.0.0
|
||||
Homepage: https://github.com/fastfetch-cli/fastfetch
|
||||
|
||||
|
||||
+83
-4
@@ -313,6 +313,10 @@
|
||||
"description": "Output format for the `Chassis` module. See Wiki for formatting syntax\n 1. {type}: Chassis type\n 2. {vendor}: Chassis vendor\n 3. {version}: Chassis version\n 4. {serial}: Chassis serial number",
|
||||
"type": "string"
|
||||
},
|
||||
"codecFormat": {
|
||||
"description": "Output format for the `Codec` module. See Wiki for formatting syntax\n 1. {gpu}: GPU name\n 2. {direction}: Decoder / Encoder\n 3. {types}: Compatibility alias of codec types\n 4. {platform-api}: Platform API used for detection",
|
||||
"type": "string"
|
||||
},
|
||||
"commandFormat": {
|
||||
"description": "Output format for the `Command` module. See Wiki for formatting syntax\n 1. {result}: Command result",
|
||||
"type": "string"
|
||||
@@ -731,6 +735,11 @@
|
||||
"description": "Top padding of the logo",
|
||||
"minimum": 0
|
||||
},
|
||||
"bottom": {
|
||||
"type": "integer",
|
||||
"description": "Bottom padding of the logo; only supported when position is `top`",
|
||||
"minimum": 0
|
||||
},
|
||||
"left": {
|
||||
"type": "integer",
|
||||
"description": "Left padding of the logo",
|
||||
@@ -1440,6 +1449,7 @@
|
||||
"cpu",
|
||||
"cpucache",
|
||||
"cpuusage",
|
||||
"codec",
|
||||
"command",
|
||||
"colors",
|
||||
"cursor",
|
||||
@@ -1745,10 +1755,18 @@
|
||||
"$ref": "#/$defs/percent"
|
||||
},
|
||||
"ddcciSleep": {
|
||||
"type": "integer",
|
||||
"description": "Sleep time in milliseconds between DDC/CI requests\nSee <https://www.ddcutil.com/performance_options/#option-sleep-multiplier> for details",
|
||||
"minimum": 0,
|
||||
"maximum": 400,
|
||||
"description": "Sleep time in milliseconds between DDC/CI requests\nSet to null to skip DDC/CI detection\nSee <https://www.ddcutil.com/performance_options/#option-sleep-multiplier> for details",
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "null",
|
||||
"description": "Skip DDC/CI detection"
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 400
|
||||
}
|
||||
],
|
||||
"default": 10
|
||||
},
|
||||
"compact": {
|
||||
@@ -1878,6 +1896,67 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"title": "Codec",
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"type": {
|
||||
"const": "codec",
|
||||
"description": "Print hardware video acceleration codec types (decode / encode)"
|
||||
},
|
||||
"splitGPU": {
|
||||
"description": "Whether to print each GPU separately. If false, merge codecs from all GPUs",
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"useVulkan": {
|
||||
"description": "Whether to use Vulkan for codec detection instead of other platform-specific APIs",
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"showType": {
|
||||
"description": "Which types of codecs to detect and show",
|
||||
"type": "string",
|
||||
"oneOf": [
|
||||
{
|
||||
"const": "both",
|
||||
"description": "Show both decoders and encoders"
|
||||
},
|
||||
{
|
||||
"const": "decoder",
|
||||
"description": "Show only decoders"
|
||||
},
|
||||
{
|
||||
"const": "encoder",
|
||||
"description": "Show only encoders"
|
||||
}
|
||||
],
|
||||
"default": "both"
|
||||
},
|
||||
"key": {
|
||||
"$ref": "#/$defs/key"
|
||||
},
|
||||
"keyColor": {
|
||||
"$ref": "#/$defs/keyColor"
|
||||
},
|
||||
"keyIcon": {
|
||||
"$ref": "#/$defs/keyIcon"
|
||||
},
|
||||
"keyWidth": {
|
||||
"$ref": "#/$defs/keyWidth"
|
||||
},
|
||||
"outputColor": {
|
||||
"$ref": "#/$defs/outputColor"
|
||||
},
|
||||
"format": {
|
||||
"$ref": "#/$defs/codecFormat"
|
||||
},
|
||||
"condition": {
|
||||
"$ref": "#/$defs/conditions"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"title": "CPU",
|
||||
"type": "object",
|
||||
|
||||
@@ -50,6 +50,10 @@
|
||||
"driverSpecific": true,
|
||||
"temp": true
|
||||
},
|
||||
{
|
||||
"type": "codec",
|
||||
"splitGPU": true
|
||||
},
|
||||
"memory",
|
||||
"physicalmemory",
|
||||
{
|
||||
|
||||
@@ -52,6 +52,10 @@
|
||||
"driverSpecific": true,
|
||||
"temp": true
|
||||
},
|
||||
{
|
||||
"type": "codec",
|
||||
"splitGPU": true
|
||||
},
|
||||
"memory",
|
||||
"physicalmemory",
|
||||
{
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
// Load with --config examples/2.jsonc
|
||||
// Note that you must replace the image path to an existing image to display it.
|
||||
|
||||
{
|
||||
"$schema": "https://github.com/fastfetch-cli/fastfetch/raw/dev/doc/json_schema.json",
|
||||
"logo": {
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
// Load with --config examples/2.jsonc
|
||||
// Note that you must replace the image path to an existing image to display it.
|
||||
|
||||
{
|
||||
"$schema": "https://github.com/fastfetch-cli/fastfetch/raw/dev/doc/json_schema.json",
|
||||
"display": {
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
// Load with --config examples/2.jsonc
|
||||
// Note that you must replace the image path to an existing image to display it.
|
||||
|
||||
{
|
||||
"$schema": "https://github.com/fastfetch-cli/fastfetch/raw/dev/doc/json_schema.json",
|
||||
"logo": {
|
||||
|
||||
+1
-1
@@ -33,7 +33,7 @@ endBold = r"\fR" # end bold text tag
|
||||
# path to the current directory
|
||||
pathToCurrentDir = path.dirname(__file__)
|
||||
# path to the JSON option file
|
||||
pathToHelpFile = path.join(pathToCurrentDir, "../src/data/help.json")
|
||||
pathToHelpFile = path.join(pathToCurrentDir, "../doc/help.json")
|
||||
# man page section
|
||||
manSection = 1
|
||||
# title (center header)
|
||||
|
||||
+22
-5
@@ -9,6 +9,7 @@
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include "common/memrchr.h"
|
||||
|
||||
#ifdef FF_USE_SYSTEM_YYJSON
|
||||
#include <yyjson.h>
|
||||
@@ -71,11 +72,6 @@ bool ffStrbufRemoveSubstr(FFstrbuf* strbuf, uint32_t startIndex, uint32_t endInd
|
||||
void ffStrbufRemoveS(FFstrbuf* strbuf, const char* str);
|
||||
void ffStrbufRemoveStrings(FFstrbuf* strbuf, uint32_t numStrings, const char* strings[]);
|
||||
|
||||
FF_A_NODISCARD uint32_t ffStrbufNextIndexC(const FFstrbuf* strbuf, uint32_t start, char c);
|
||||
FF_A_NODISCARD uint32_t ffStrbufNextIndexS(const FFstrbuf* strbuf, uint32_t start, const char* str);
|
||||
|
||||
FF_A_NODISCARD uint32_t ffStrbufPreviousIndexC(const FFstrbuf* strbuf, uint32_t start, char c);
|
||||
|
||||
void ffStrbufReplaceAllC(FFstrbuf* strbuf, char find, char replace);
|
||||
|
||||
// Returns true if the strbuf is modified
|
||||
@@ -417,6 +413,27 @@ static inline FF_A_NODISCARD bool ffStrbufContainIgnCase(const FFstrbuf* strbuf,
|
||||
return ffStrbufContainIgnCaseS(strbuf, str->chars);
|
||||
}
|
||||
|
||||
FF_A_NODISCARD static inline uint32_t ffStrbufNextIndexC(const FFstrbuf* strbuf, uint32_t start, char c) {
|
||||
assert(start <= strbuf->length);
|
||||
|
||||
const char* ptr = (const char*) memchr(strbuf->chars + start, c, strbuf->length - start);
|
||||
return ptr ? (uint32_t) (ptr - strbuf->chars) : strbuf->length;
|
||||
}
|
||||
|
||||
FF_A_NODISCARD static inline uint32_t ffStrbufNextIndexS(const FFstrbuf* strbuf, uint32_t start, const char* str) {
|
||||
assert(start <= strbuf->length);
|
||||
|
||||
const char* ptr = strstr(strbuf->chars + start, str);
|
||||
return ptr ? (uint32_t) (ptr - strbuf->chars) : strbuf->length;
|
||||
}
|
||||
|
||||
FF_A_NODISCARD static inline uint32_t ffStrbufPreviousIndexC(const FFstrbuf* strbuf, uint32_t start, char c) {
|
||||
assert(start <= strbuf->length);
|
||||
|
||||
const char* ptr = (const char*) memrchr(strbuf->chars, c, start + 1);
|
||||
return ptr ? (uint32_t) (ptr - strbuf->chars) : strbuf->length;
|
||||
}
|
||||
|
||||
static inline FF_A_NODISCARD uint32_t ffStrbufFirstIndexC(const FFstrbuf* strbuf, char c) {
|
||||
return ffStrbufNextIndexC(strbuf, 0, c);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "smc_temps.h"
|
||||
#include "common/apple/cf_helpers.h"
|
||||
#include "common/stringUtils.h"
|
||||
#include "common/strutil.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <IOKit/IOKitLib.h>
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include "fastfetch.h"
|
||||
|
||||
bool ffGetAppNameAndVersion(const char* exePath, FFstrbuf* retName, FFstrbuf* retVersion);
|
||||
@@ -0,0 +1,43 @@
|
||||
#include "common/apple/version.h"
|
||||
#include "common/strutil.h"
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#define APP_CONTENTS_MACOS ".app/Contents/MacOS"
|
||||
|
||||
bool ffGetAppNameAndVersion(const char* exePath, FFstrbuf* retName, FFstrbuf* retVersion) {
|
||||
char* lastSlash = strrchr(exePath, '/');
|
||||
if (!lastSlash) {
|
||||
return false;
|
||||
}
|
||||
if ((size_t) (lastSlash - exePath) > strlen("X" APP_CONTENTS_MACOS) && memcmp(lastSlash - strlen(APP_CONTENTS_MACOS), APP_CONTENTS_MACOS, strlen(APP_CONTENTS_MACOS)) != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
lastSlash -= strlen("MacOS");
|
||||
char infoPlistPath[PATH_MAX];
|
||||
memcpy(infoPlistPath, exePath, lastSlash - exePath);
|
||||
memcpy(infoPlistPath + (lastSlash - exePath), "Info.plist", sizeof("Info.plist")); // X.app/Contents/Info.plist
|
||||
NSError* error;
|
||||
NSDictionary* dict = [NSDictionary dictionaryWithContentsOfURL:[NSURL fileURLWithPath:@(infoPlistPath)]
|
||||
error:&error];
|
||||
if (!dict) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (retName) {
|
||||
NSString* bundleName = dict[@"CFBundleDisplayName"] ?: dict[@"CFBundleName"];
|
||||
if (bundleName) {
|
||||
ffStrbufSetS(retName, bundleName.UTF8String);
|
||||
}
|
||||
}
|
||||
|
||||
if (retVersion) {
|
||||
NSString* bundleVersion = dict[@"CFBundleShortVersionString"];
|
||||
if (bundleVersion) {
|
||||
ffStrbufSetS(retVersion, bundleVersion.UTF8String);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -16,3 +16,4 @@
|
||||
#define FF_A_UNUSED __attribute__((__unused__))
|
||||
#define FF_A_PACKED __attribute__((__packed__))
|
||||
#define FF_A_WEAK_IMPORT __attribute__((__weak_import__))
|
||||
#define FF_A_ALWAYS_INLINE __attribute__((__always_inline__))
|
||||
|
||||
+1
-1
@@ -9,6 +9,6 @@ typedef struct FFformatarg {
|
||||
} FFformatarg;
|
||||
|
||||
void ffFormatAppendFormatArg(FFstrbuf* buffer, const FFformatarg* formatarg);
|
||||
void ffParseFormatString(FFstrbuf* buffer, const FFstrbuf* formatstr, uint32_t numArgs, const FFformatarg* arguments);
|
||||
bool ffParseFormatString(FFstrbuf* buffer, const FFstrbuf* formatstr, uint32_t numArgs, const FFformatarg* arguments);
|
||||
#define FF_PARSE_FORMAT_STRING_CHECKED(buffer, formatstr, arguments) \
|
||||
ffParseFormatString((buffer), (formatstr), sizeof(arguments) / sizeof(*arguments), (arguments));
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#include "FFPlatform_private.h"
|
||||
#include "common/stringUtils.h"
|
||||
#include "common/strutil.h"
|
||||
#include "common/io.h"
|
||||
#include "detection/version/version.h"
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#include "FFPlatform_private.h"
|
||||
#include "common/FFstrbuf.h"
|
||||
#include "common/arrayUtils.h"
|
||||
#include "common/stringUtils.h"
|
||||
#include "common/arrutil.h"
|
||||
#include "common/strutil.h"
|
||||
#include "common/io.h"
|
||||
#include "fastfetch_config.h"
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#include "FFPlatform_private.h"
|
||||
#include "common/io.h"
|
||||
#include "common/library.h"
|
||||
#include "common/stringUtils.h"
|
||||
#include "common/strutil.h"
|
||||
#include "common/windows/unicode.h"
|
||||
#include "common/windows/registry.h"
|
||||
#include "common/windows/nt.h"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "common/FFstrbuf.h"
|
||||
#include "common/mallocHelper.h"
|
||||
#include "common/stringUtils.h"
|
||||
#include "common/strutil.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <inttypes.h>
|
||||
@@ -411,32 +411,6 @@ void ffStrbufRemoveStrings(FFstrbuf* strbuf, uint32_t numStrings, const char* st
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t ffStrbufNextIndexC(const FFstrbuf* strbuf, uint32_t start, char c) {
|
||||
assert(start <= strbuf->length);
|
||||
|
||||
const char* ptr = (const char*) memchr(strbuf->chars + start, c, strbuf->length - start);
|
||||
return ptr ? (uint32_t) (ptr - strbuf->chars) : strbuf->length;
|
||||
}
|
||||
|
||||
uint32_t ffStrbufNextIndexS(const FFstrbuf* strbuf, uint32_t start, const char* str) {
|
||||
assert(start <= strbuf->length);
|
||||
|
||||
const char* ptr = strstr(strbuf->chars + start, str);
|
||||
return ptr ? (uint32_t) (ptr - strbuf->chars) : strbuf->length;
|
||||
}
|
||||
|
||||
uint32_t ffStrbufPreviousIndexC(const FFstrbuf* strbuf, uint32_t start, char c) {
|
||||
assert(start <= strbuf->length);
|
||||
|
||||
// We need to loop one higher than the actual index, because uint32_t is guaranteed to be >= 0, so this statement would always be true
|
||||
for (uint32_t i = start + 1; i > 0; i--) {
|
||||
if (strbuf->chars[i - 1] == c) {
|
||||
return i - 1;
|
||||
}
|
||||
}
|
||||
return strbuf->length;
|
||||
}
|
||||
|
||||
void ffStrbufReplaceAllC(FFstrbuf* strbuf, char find, char replace) {
|
||||
if (strbuf->length == 0) {
|
||||
return;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "common/binary.h"
|
||||
#include "common/io.h"
|
||||
#include "common/stringUtils.h"
|
||||
#include "common/strutil.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
#include "common/io.h"
|
||||
#include "common/library.h"
|
||||
#include "common/stringUtils.h"
|
||||
#include "common/strutil.h"
|
||||
|
||||
#include <libelf.h> // #1254
|
||||
#include <fcntl.h>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "common/binary.h"
|
||||
#include "common/io.h"
|
||||
#include "common/stringUtils.h"
|
||||
#include "common/strutil.h"
|
||||
#include "common/windows/nt.h"
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
#include "common/printing.h"
|
||||
#include "common/time.h"
|
||||
#include "common/jsonconfig.h"
|
||||
#include "common/stringUtils.h"
|
||||
#include "common/strutil.h"
|
||||
#include "fastfetch_datatext.h"
|
||||
#include "modules/modules.h"
|
||||
|
||||
@@ -70,12 +70,15 @@ void ffPrepareCommandOption(FFdata* data) {
|
||||
#define FF_IF_MODULE_MATCH(moduleNameConstant) if (moduleLen == strlen(moduleNameConstant) && ffStrEqualsIgnCase(moduleType, moduleNameConstant) && !ffStrbufSeparatedContainIgnCaseS(&data->structureDisabled, moduleNameConstant, ':'))
|
||||
|
||||
switch (moduleType[0]) {
|
||||
#if !FF_MODULE_DISABLE_CPUUSAGE
|
||||
case 'C':
|
||||
case 'c':
|
||||
FF_IF_MODULE_MATCH(FF_CPUUSAGE_MODULE_NAME)
|
||||
ffPrepareCPUUsage();
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if !FF_MODULE_DISABLE_DISKIO
|
||||
case 'D':
|
||||
case 'd':
|
||||
FF_IF_MODULE_MATCH(FF_DISKIO_MODULE_NAME) {
|
||||
@@ -84,7 +87,9 @@ void ffPrepareCommandOption(FFdata* data) {
|
||||
ffPrepareDiskIO(&options);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if !FF_MODULE_DISABLE_NETIO
|
||||
case 'N':
|
||||
case 'n':
|
||||
FF_IF_MODULE_MATCH(FF_NETIO_MODULE_NAME) {
|
||||
@@ -93,7 +98,9 @@ void ffPrepareCommandOption(FFdata* data) {
|
||||
ffPrepareNetIO(&options);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if !FF_MODULE_DISABLE_PUBLICIP
|
||||
case 'P':
|
||||
case 'p':
|
||||
FF_IF_MODULE_MATCH(FF_PUBLICIP_MODULE_NAME) {
|
||||
@@ -102,7 +109,9 @@ void ffPrepareCommandOption(FFdata* data) {
|
||||
ffPreparePublicIp(&options);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if !FF_MODULE_DISABLE_WEATHER
|
||||
case 'W':
|
||||
case 'w':
|
||||
FF_IF_MODULE_MATCH(FF_WEATHER_MODULE_NAME) {
|
||||
@@ -111,6 +120,7 @@ void ffPrepareCommandOption(FFdata* data) {
|
||||
ffPrepareWeather(&options);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
|
||||
#undef FF_IF_MODULE_MATCH
|
||||
@@ -178,7 +188,7 @@ static bool parseStructureCommand(
|
||||
}
|
||||
}
|
||||
|
||||
if (fn == genJsonResult) {
|
||||
if (data->resultDoc) {
|
||||
yyjson_mut_doc* doc = data->resultDoc;
|
||||
yyjson_mut_val* module = yyjson_mut_arr_add_obj(doc, doc->root);
|
||||
yyjson_mut_obj_add_str(doc, module, "type", line);
|
||||
@@ -221,7 +231,7 @@ void ffPrintCommandOption(FFdata* data) {
|
||||
: FF_COLOR_FG_RED),
|
||||
ms);
|
||||
}
|
||||
printf("\e7\e[1A\e[9999999C\e[%dD%s\e8", len, str); // Save; Up 1; Right 9999999; Left <len>; Print <str>; Load
|
||||
printf("\e7\e[1A\e[9999999C\e[%dD%s\e8", len - 1, str); // Save; Up 1; Right 9999999; Left <len - 1>; Print <str>; Load
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
#ifdef FF_HAVE_DBUS
|
||||
|
||||
#include "common/thread.h"
|
||||
#include "common/stringUtils.h"
|
||||
#include "common/strutil.h"
|
||||
|
||||
static bool loadLibSymbols(FFDBusLibrary* lib) {
|
||||
FF_LIBRARY_LOAD(dbus, false, "libdbus-1" FF_LIBRARY_EXTENSION, 4);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#include "fastfetch.h"
|
||||
#include "common/FFlist.h"
|
||||
#include "common/FFstrbuf.h"
|
||||
#include "common/stringUtils.h"
|
||||
#include "common/strutil.h"
|
||||
#include "common/font.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
+389
-5
@@ -2,7 +2,8 @@
|
||||
#include "common/format.h"
|
||||
#include "common/parsing.h"
|
||||
#include "common/textModifier.h"
|
||||
#include "common/stringUtils.h"
|
||||
#include "common/strutil.h"
|
||||
#include "common/library.h"
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
@@ -111,7 +112,347 @@ static inline bool formatArgSet(const FFformatarg* arg) {
|
||||
return arg->value != NULL && ((arg->type == FF_ARG_TYPE_DOUBLE && *(double*) arg->value > 0.0) || (arg->type == FF_ARG_TYPE_FLOAT && *(float*) arg->value > 0.0) || (arg->type == FF_ARG_TYPE_INT && *(int32_t*) arg->value > 0) || (arg->type == FF_ARG_TYPE_STRBUF && ((FFstrbuf*) arg->value)->length > 0) || (arg->type == FF_ARG_TYPE_STRING && ffStrSet((char*) arg->value)) || (arg->type == FF_ARG_TYPE_UINT8 && *(uint8_t*) arg->value > 0) || (arg->type == FF_ARG_TYPE_UINT16 && *(uint16_t*) arg->value > 0) || (arg->type == FF_ARG_TYPE_UINT && *(uint32_t*) arg->value > 0) || (arg->type == FF_ARG_TYPE_UINT64 && *(uint64_t*) arg->value > 0) || (arg->type == FF_ARG_TYPE_BOOL && *(bool*) arg->value) || (arg->type == FF_ARG_TYPE_LIST && ((FFlist*) arg->value)->length > 0));
|
||||
}
|
||||
|
||||
void ffParseFormatString(FFstrbuf* buffer, const FFstrbuf* formatstr, uint32_t numArgs, const FFformatarg* arguments) {
|
||||
FF_A_UNUSED static inline void normalizeArgName(FFstrbuf* dst, const char* src) {
|
||||
ffStrbufClear(dst);
|
||||
bool flag = false;
|
||||
for (const char* p = src; *p; ++p) {
|
||||
if (*p == '-') {
|
||||
flag = true;
|
||||
} else if (flag) {
|
||||
ffStrbufAppendC(dst, (char) toupper((unsigned char) *p));
|
||||
flag = false;
|
||||
} else {
|
||||
ffStrbufAppendC(dst, *p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if FF_HAVE_LUA
|
||||
#include "common/lua.h"
|
||||
|
||||
static void appendLuaError(FFstrbuf* buffer, const char* prefix, lua_State* L) {
|
||||
const char* err = lua_tolstring(L, -1, NULL);
|
||||
if (err) {
|
||||
const char* tmp = strchr(err, ':');
|
||||
if (tmp) {
|
||||
err = tmp + 1;
|
||||
while (*err == ' ') {
|
||||
++err;
|
||||
}
|
||||
}
|
||||
}
|
||||
ffStrbufAppendF(buffer, "%s: %s", prefix, err ? err : "unknown");
|
||||
}
|
||||
|
||||
static bool parseLuaString(FFstrbuf* buffer, const char* script, uint32_t scriptLen, uint32_t numArgs, const FFformatarg* arguments) {
|
||||
const char* err = ffLuaLoadState();
|
||||
if (err) {
|
||||
ffStrbufAppendF(buffer, "Lua init error: %s", err);
|
||||
return false;
|
||||
}
|
||||
|
||||
FF_STRBUF_AUTO_DESTROY argNameBuf = ffStrbufCreate();
|
||||
bool ret = false;
|
||||
|
||||
lua_State* L = luaData.L;
|
||||
// Clear stack and load chunk
|
||||
lua_settop(L, 0);
|
||||
if (luaL_loadbuffer(L, script, scriptLen, "") != LUA_OK) {
|
||||
appendLuaError(buffer, "Lua load error", L);
|
||||
} else {
|
||||
// Build args table for name lookup only.
|
||||
lua_createtable(L, 0, 0);
|
||||
|
||||
for (uint32_t i = 0; i < numArgs; ++i) {
|
||||
const FFformatarg* arg = &arguments[i];
|
||||
switch (arg->type) {
|
||||
case FF_ARG_TYPE_INT:
|
||||
lua_pushinteger(L, (lua_Integer) * (int32_t*) arg->value);
|
||||
break;
|
||||
case FF_ARG_TYPE_UINT:
|
||||
lua_pushinteger(L, (lua_Integer) * (uint32_t*) arg->value);
|
||||
break;
|
||||
case FF_ARG_TYPE_UINT64:
|
||||
lua_pushinteger(L, (lua_Integer) * (uint64_t*) arg->value);
|
||||
break;
|
||||
case FF_ARG_TYPE_UINT16:
|
||||
lua_pushinteger(L, (lua_Integer) * (uint16_t*) arg->value);
|
||||
break;
|
||||
case FF_ARG_TYPE_UINT8:
|
||||
lua_pushinteger(L, (lua_Integer) * (uint8_t*) arg->value);
|
||||
break;
|
||||
case FF_ARG_TYPE_FLOAT:
|
||||
lua_pushnumber(L, (lua_Number) * (float*) arg->value);
|
||||
break;
|
||||
case FF_ARG_TYPE_DOUBLE:
|
||||
lua_pushnumber(L, (lua_Number) * (double*) arg->value);
|
||||
break;
|
||||
case FF_ARG_TYPE_BOOL:
|
||||
lua_pushboolean(L, *(bool*) arg->value);
|
||||
break;
|
||||
case FF_ARG_TYPE_STRING:
|
||||
lua_pushstring(L, (const char*) arg->value);
|
||||
break;
|
||||
case FF_ARG_TYPE_STRBUF: {
|
||||
const FFstrbuf* sb = (const FFstrbuf*) arg->value;
|
||||
lua_pushlstring(L, sb->chars, sb->length);
|
||||
break;
|
||||
}
|
||||
case FF_ARG_TYPE_LIST: {
|
||||
const FFlist* list = (const FFlist*) arg->value;
|
||||
lua_createtable(L, 0, 0);
|
||||
for (uint32_t li = 0; li < list->length; ++li) {
|
||||
const FFstrbuf* item = FF_LIST_GET(FFstrbuf, *list, li);
|
||||
lua_pushlstring(L, item->chars, item->length);
|
||||
lua_seti(L, -2, (lua_Integer) (li + 1));
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
lua_pushnil(L);
|
||||
break;
|
||||
}
|
||||
if (arg->name && arg->name[0]) {
|
||||
normalizeArgName(&argNameBuf, arg->name);
|
||||
} else {
|
||||
ffStrbufSetF(&argNameBuf, "arg%" PRIu32, i + 1);
|
||||
}
|
||||
lua_setfield(L, -2, argNameBuf.chars);
|
||||
}
|
||||
|
||||
if (lua_pcall(L, 1, LUA_MULTRET, 0) != LUA_OK) {
|
||||
appendLuaError(buffer, "Lua runtime error", L);
|
||||
} else {
|
||||
int nresults = lua_gettop(L);
|
||||
if (nresults == 0) {
|
||||
ffStrbufAppendS(buffer, "Lua result error: no result");
|
||||
} else {
|
||||
// Convert first result to string
|
||||
const char* res = lua_tolstring(L, 1, NULL);
|
||||
if (res) {
|
||||
ffStrbufAppendS(buffer, res);
|
||||
} else {
|
||||
// Fallback: use luaL_tolstring to get a reasonable representation
|
||||
luaL_tolstring(L, 1, NULL);
|
||||
const char* sval = lua_tolstring(L, -1, NULL);
|
||||
if (sval) {
|
||||
ffStrbufAppendS(buffer, sval);
|
||||
}
|
||||
}
|
||||
ret = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
lua_settop(L, 0);
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if FF_HAVE_QUICKJS
|
||||
#include <quickjs.h>
|
||||
|
||||
struct FFQuickJSData {
|
||||
FF_LIBRARY_SYMBOL(JS_NewRuntime)
|
||||
FF_LIBRARY_SYMBOL(JS_NewContext)
|
||||
FF_LIBRARY_SYMBOL(JS_FreeRuntime)
|
||||
FF_LIBRARY_SYMBOL(JS_EvalThis)
|
||||
FF_LIBRARY_SYMBOL(JS_GetException)
|
||||
FF_LIBRARY_SYMBOL(JS_ToCStringLen2)
|
||||
FF_LIBRARY_SYMBOL(JS_FreeCString)
|
||||
FF_LIBRARY_SYMBOL(JS_NewStringLen)
|
||||
FF_LIBRARY_SYMBOL(JS_NewArray)
|
||||
FF_LIBRARY_SYMBOL(JS_NewBigUint64)
|
||||
FF_LIBRARY_SYMBOL(JS_SetPropertyUint32)
|
||||
FF_LIBRARY_SYMBOL(JS_NewObject)
|
||||
FF_LIBRARY_SYMBOL(JS_SetPropertyStr)
|
||||
FF_LIBRARY_SYMBOL(JS_FreeValue)
|
||||
|
||||
JSRuntime* rt;
|
||||
JSContext* ctx;
|
||||
bool inited;
|
||||
} qjsData;
|
||||
|
||||
static const char* loadQuickJSState(void) {
|
||||
if (qjsData.inited) {
|
||||
if (qjsData.ctx == NULL) {
|
||||
return "QuickJS is not available";
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
qjsData.inited = true;
|
||||
#ifdef _WIN32
|
||||
FF_LIBRARY_LOAD_MESSAGE(libqjs, "libqjs-0" FF_LIBRARY_EXTENSION, 0)
|
||||
#else
|
||||
FF_LIBRARY_LOAD_MESSAGE(libqjs, "libqjs" FF_LIBRARY_EXTENSION, 0)
|
||||
#endif
|
||||
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libqjs, qjsData, JS_NewRuntime)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libqjs, qjsData, JS_NewContext)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libqjs, qjsData, JS_FreeRuntime)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libqjs, qjsData, JS_EvalThis)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libqjs, qjsData, JS_GetException)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libqjs, qjsData, JS_ToCStringLen2)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libqjs, qjsData, JS_FreeCString)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libqjs, qjsData, JS_NewStringLen)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libqjs, qjsData, JS_NewArray)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libqjs, qjsData, JS_SetPropertyUint32)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libqjs, qjsData, JS_NewObject)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libqjs, qjsData, JS_SetPropertyStr)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libqjs, qjsData, JS_FreeValue)
|
||||
|
||||
qjsData.rt = qjsData.ffJS_NewRuntime();
|
||||
if (qjsData.rt == NULL) {
|
||||
return "JS_NewRuntime() failed";
|
||||
}
|
||||
|
||||
qjsData.ctx = qjsData.ffJS_NewContext(qjsData.rt);
|
||||
if (qjsData.ctx == NULL) {
|
||||
qjsData.ffJS_FreeRuntime(qjsData.rt);
|
||||
qjsData.rt = NULL;
|
||||
return "JS_NewContext() failed";
|
||||
}
|
||||
|
||||
libqjs = NULL; // don't close quickjs
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static bool parseQuickJSString(FFstrbuf* buffer, const char* script, uint32_t scriptLen, uint32_t numArgs, const FFformatarg* arguments) {
|
||||
const char* err = loadQuickJSState();
|
||||
if (err) {
|
||||
ffStrbufAppendF(buffer, "Qjs init error: %s", err);
|
||||
return false;
|
||||
}
|
||||
JSContext* ctx = qjsData.ctx;
|
||||
JSValue argsObj = qjsData.ffJS_NewObject(ctx);
|
||||
FF_STRBUF_AUTO_DESTROY argNameBuf = ffStrbufCreate();
|
||||
|
||||
for (uint32_t i = 0; i < numArgs; ++i) {
|
||||
const FFformatarg* arg = &arguments[i];
|
||||
|
||||
JSValue value;
|
||||
switch (arg->type) {
|
||||
case FF_ARG_TYPE_INT:
|
||||
value = JS_NewInt32(ctx, *(int32_t*) arg->value);
|
||||
break;
|
||||
case FF_ARG_TYPE_UINT:
|
||||
value = JS_NewUint32(ctx, *(uint32_t*) arg->value);
|
||||
break;
|
||||
case FF_ARG_TYPE_UINT64: {
|
||||
uint64_t val = *(uint64_t*) arg->value;
|
||||
if (val <= INT32_MAX) {
|
||||
value = JS_NewInt32(ctx, (int32_t) val);
|
||||
} else {
|
||||
value = JS_NewFloat64(ctx, (double) val);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case FF_ARG_TYPE_UINT16:
|
||||
value = JS_NewUint32(ctx, *(uint16_t*) arg->value);
|
||||
break;
|
||||
case FF_ARG_TYPE_UINT8:
|
||||
value = JS_NewUint32(ctx, *(uint8_t*) arg->value);
|
||||
break;
|
||||
case FF_ARG_TYPE_FLOAT:
|
||||
value = JS_NewFloat64(ctx, *(float*) arg->value);
|
||||
break;
|
||||
case FF_ARG_TYPE_DOUBLE:
|
||||
value = JS_NewFloat64(ctx, *(double*) arg->value);
|
||||
break;
|
||||
case FF_ARG_TYPE_BOOL:
|
||||
value = JS_NewBool(ctx, *(bool*) arg->value);
|
||||
break;
|
||||
case FF_ARG_TYPE_STRING:
|
||||
value = qjsData.ffJS_NewStringLen(ctx, (const char*) arg->value, strlen((const char*) arg->value));
|
||||
break;
|
||||
case FF_ARG_TYPE_STRBUF: {
|
||||
const FFstrbuf* sb = (const FFstrbuf*) arg->value;
|
||||
value = qjsData.ffJS_NewStringLen(ctx, sb->chars, sb->length);
|
||||
break;
|
||||
}
|
||||
case FF_ARG_TYPE_LIST: {
|
||||
const FFlist* list = (const FFlist*) arg->value;
|
||||
JSValue arr = qjsData.ffJS_NewArray(ctx);
|
||||
for (uint32_t li = 0; li < list->length; ++li) {
|
||||
const FFstrbuf* item = FF_LIST_GET(FFstrbuf, *list, li);
|
||||
JSValue itemValue = qjsData.ffJS_NewStringLen(ctx, item->chars, item->length);
|
||||
qjsData.ffJS_SetPropertyUint32(ctx, arr, li, itemValue);
|
||||
}
|
||||
|
||||
value = arr;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
value = JS_UNDEFINED;
|
||||
break;
|
||||
}
|
||||
|
||||
if (arg->name && arg->name[0]) {
|
||||
normalizeArgName(&argNameBuf, arg->name);
|
||||
} else {
|
||||
ffStrbufSetF(&argNameBuf, "arg%" PRIu32, i + 1);
|
||||
}
|
||||
qjsData.ffJS_SetPropertyStr(ctx, argsObj, argNameBuf.chars, value);
|
||||
}
|
||||
JSValue result = qjsData.ffJS_EvalThis(ctx, argsObj, script, scriptLen, "", JS_EVAL_TYPE_GLOBAL | JS_EVAL_FLAG_STRICT);
|
||||
|
||||
qjsData.ffJS_FreeValue(ctx, argsObj);
|
||||
|
||||
bool ret = false;
|
||||
if (JS_IsException(result)) {
|
||||
JSValue exc = qjsData.ffJS_GetException(ctx);
|
||||
const char* message = qjsData.ffJS_ToCStringLen2(ctx, NULL, exc, false);
|
||||
qjsData.ffJS_FreeValue(ctx, exc);
|
||||
ffStrbufAppendF(buffer, "Qjs runtime error: %s", message ?: "unknown");
|
||||
if (message) {
|
||||
qjsData.ffJS_FreeCString(ctx, message);
|
||||
}
|
||||
} else if (JS_IsUndefined(result)) {
|
||||
ffStrbufAppendS(buffer, "Qjs result error: undefined result");
|
||||
} else {
|
||||
size_t len;
|
||||
const char* res = qjsData.ffJS_ToCStringLen2(ctx, &len, result, false);
|
||||
if (res) {
|
||||
ffStrbufAppendNS(buffer, (uint32_t) len, res);
|
||||
qjsData.ffJS_FreeCString(ctx, res);
|
||||
}
|
||||
ret = true;
|
||||
}
|
||||
|
||||
qjsData.ffJS_FreeValue(ctx, result);
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
static bool skipAnsiEscape(FFstrbuf* in, FFstrbuf* out, FFstrbuf* trailingEscape) {
|
||||
if (__builtin_expect(in->chars[0] == '\e' && in->chars[1] == '[', false)) {
|
||||
// skip ANSI escape codes at the start of the string for truncation
|
||||
const char* p = in->chars + 2;
|
||||
while (*p && (ffCharIsDigit(*p) || *p == ';')) {
|
||||
++p;
|
||||
}
|
||||
if (*p && isascii(*p)) {
|
||||
++p;
|
||||
}
|
||||
uint32_t prefixLen = (uint32_t) (p - in->chars);
|
||||
ffStrbufAppendNS(out, prefixLen, in->chars);
|
||||
ffStrbufSubstrAfter(in, prefixLen - 1);
|
||||
|
||||
if (trailingEscape) {
|
||||
// likely have a `CSI m` reset at the end of the string
|
||||
uint32_t iLastEscape = ffStrbufLastIndexC(in, '\e');
|
||||
if (iLastEscape != in->length) {
|
||||
ffStrbufSetNS(trailingEscape, in->length - iLastEscape, in->chars + iLastEscape);
|
||||
ffStrbufSubstrBefore(in, iLastEscape);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool parseFormatString(FFstrbuf* buffer, const FFstrbuf* formatstr, uint32_t numArgs, const FFformatarg* arguments) {
|
||||
uint32_t argCounter = 0;
|
||||
|
||||
uint32_t numOpenIfs = 0;
|
||||
@@ -129,6 +470,12 @@ void ffParseFormatString(FFstrbuf* buffer, const FFstrbuf* formatstr, uint32_t n
|
||||
// jump to next char, the start of the placeholder value
|
||||
++i;
|
||||
|
||||
// unmatched trailing '{'
|
||||
if (i >= formatstr->length) {
|
||||
ffStrbufAppendC(buffer, '{');
|
||||
break;
|
||||
}
|
||||
|
||||
// double {{ elvaluates to a single { and doesn't count as start
|
||||
if (formatstr->chars[i] == '{') {
|
||||
ffStrbufAppendC(buffer, '{');
|
||||
@@ -267,7 +614,7 @@ void ffParseFormatString(FFstrbuf* buffer, const FFstrbuf* formatstr, uint32_t n
|
||||
|
||||
char* pSep = placeholderValue.chars;
|
||||
char cSep = '\0';
|
||||
while (*pSep && *pSep != ':' && *pSep != '<' && *pSep != '>' && *pSep != '~') {
|
||||
while (*pSep && *pSep != ':' && *pSep != '<' && *pSep != '>' && *pSep != '|' && *pSep != '~') {
|
||||
++pSep;
|
||||
}
|
||||
if (*pSep) {
|
||||
@@ -297,6 +644,8 @@ void ffParseFormatString(FFstrbuf* buffer, const FFstrbuf* formatstr, uint32_t n
|
||||
} else if (cSep == '~') {
|
||||
FF_STRBUF_AUTO_DESTROY tempString = ffStrbufCreate();
|
||||
ffFormatAppendFormatArg(&tempString, &arguments[index - 1]);
|
||||
FF_STRBUF_AUTO_DESTROY trailingEscape = ffStrbufCreate();
|
||||
skipAnsiEscape(&tempString, buffer, &trailingEscape);
|
||||
|
||||
char* pEnd = NULL;
|
||||
int32_t start = (int32_t) strtol(pSep + 1, &pEnd, 10);
|
||||
@@ -322,6 +671,10 @@ void ffParseFormatString(FFstrbuf* buffer, const FFstrbuf* formatstr, uint32_t n
|
||||
}
|
||||
}
|
||||
|
||||
if (trailingEscape.length > 0) {
|
||||
ffStrbufAppend(buffer, &trailingEscape);
|
||||
}
|
||||
|
||||
if (*pEnd) {
|
||||
*pSep = cSep;
|
||||
appendInvalidPlaceholder(buffer, "{", &placeholderValue, i, formatstr->length);
|
||||
@@ -344,6 +697,9 @@ void ffParseFormatString(FFstrbuf* buffer, const FFstrbuf* formatstr, uint32_t n
|
||||
|
||||
FF_STRBUF_AUTO_DESTROY tempString = ffStrbufCreate();
|
||||
ffFormatAppendFormatArg(&tempString, &arguments[index - 1]);
|
||||
FF_STRBUF_AUTO_DESTROY trailingEscape = ffStrbufCreate();
|
||||
skipAnsiEscape(&tempString, buffer, &trailingEscape);
|
||||
|
||||
if (tempString.length == (uint32_t) truncLength) {
|
||||
ffStrbufAppend(buffer, &tempString);
|
||||
} else if (tempString.length > (uint32_t) truncLength) {
|
||||
@@ -361,18 +717,46 @@ void ffParseFormatString(FFstrbuf* buffer, const FFstrbuf* formatstr, uint32_t n
|
||||
} else if (cSep == ':') {
|
||||
ffStrbufAppend(buffer, &tempString);
|
||||
} else {
|
||||
if (cSep == '<') {
|
||||
if (cSep == '<') { // left align
|
||||
ffStrbufAppend(buffer, &tempString);
|
||||
ffStrbufAppendNC(buffer, (uint32_t) truncLength - tempString.length, ' ');
|
||||
} else {
|
||||
} else if (cSep == '>') { // right align
|
||||
ffStrbufAppendNC(buffer, (uint32_t) truncLength - tempString.length, ' ');
|
||||
ffStrbufAppend(buffer, &tempString);
|
||||
} else if (cSep == '|') { // center align
|
||||
uint32_t padding = ((uint32_t) truncLength - tempString.length) / 2;
|
||||
ffStrbufAppendNC(buffer, padding, ' ');
|
||||
ffStrbufAppend(buffer, &tempString);
|
||||
ffStrbufAppendNC(buffer, (uint32_t) truncLength - tempString.length - padding, ' ');
|
||||
}
|
||||
}
|
||||
|
||||
if (trailingEscape.length > 0) {
|
||||
ffStrbufAppend(buffer, &trailingEscape);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!instance.config.display.pipe) {
|
||||
ffStrbufAppendS(buffer, FASTFETCH_TEXT_MODIFIER_RESET);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ffParseFormatString(FFstrbuf* buffer, const FFstrbuf* formatstr, uint32_t numArgs, const FFformatarg* arguments) {
|
||||
#if FF_HAVE_QUICKJS
|
||||
if (ffStrbufStartsWithS(formatstr, "qjs:")) {
|
||||
return parseQuickJSString(buffer, formatstr->chars + 4, formatstr->length - 4, numArgs, arguments);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if FF_HAVE_LUA
|
||||
if (ffStrbufStartsWithS(formatstr, "lua:")) {
|
||||
// If outputFormat starts with "lua:", treat the rest as a Lua script
|
||||
return parseLuaString(buffer, formatstr->chars + 4, formatstr->length - 4, numArgs, arguments);
|
||||
}
|
||||
#endif
|
||||
|
||||
return parseFormatString(buffer, formatstr, numArgs, arguments);
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ static void initState(FFstate* state) {
|
||||
ffPlatformInit(&state->platform);
|
||||
state->dynamicInterval = 0;
|
||||
|
||||
#if !FF_MODULE_DISABLE_TERMINALTHEME
|
||||
{
|
||||
// don't enable bright color if the terminal is in light mode
|
||||
FFTerminalThemeResult result;
|
||||
@@ -36,6 +37,7 @@ static void initState(FFstate* state) {
|
||||
state->terminalLightTheme = true;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void defaultConfig(void) {
|
||||
@@ -173,6 +175,15 @@ void ffDestroyInstance(void) {
|
||||
destroyState();
|
||||
}
|
||||
|
||||
#if FF_HAVE_LUA
|
||||
#include <lua.h>
|
||||
#endif
|
||||
#if FF_HAVE_QUICKJS
|
||||
#include <quickjs.h>
|
||||
#define FF_STR_INDIR(x) #x
|
||||
#define FF_STR(x) FF_STR_INDIR(x)
|
||||
#endif
|
||||
|
||||
// Must be in a file compiled with the libfastfetch target, because the FF_HAVE* macros are not defined for the executable targets
|
||||
void ffListFeatures(void) {
|
||||
fputs(
|
||||
@@ -251,6 +262,12 @@ void ffListFeatures(void) {
|
||||
#if FF_HAVE_LIBZFS
|
||||
"libzfs\n"
|
||||
#endif
|
||||
#if FF_HAVE_VA
|
||||
"va\n"
|
||||
#endif
|
||||
#if FF_HAVE_VDPAU
|
||||
"vdpau\n"
|
||||
#endif
|
||||
#if FF_USE_SYSTEM_YYJSON
|
||||
"System yyjson\n"
|
||||
#endif
|
||||
@@ -260,6 +277,9 @@ void ffListFeatures(void) {
|
||||
#if FF_HAVE_EMBEDDED_PCIIDS
|
||||
"Embedded pciids\n"
|
||||
#endif
|
||||
#if FF_ENABLE_WCWIDTH
|
||||
"Embedded wcwidth\n"
|
||||
#endif
|
||||
#if FF_HAVE_WINRT
|
||||
"WinRT headers\n"
|
||||
#endif
|
||||
@@ -268,6 +288,12 @@ void ffListFeatures(void) {
|
||||
#endif
|
||||
#if FF_APPLE_MEMSIZE_USABLE
|
||||
"Apple memsize_usable\n"
|
||||
#endif
|
||||
#if FF_HAVE_LUA
|
||||
LUA_VERSION "\n"
|
||||
#endif
|
||||
#if FF_HAVE_QUICKJS
|
||||
"QuickJS " FF_STR(QJS_VERSION_MAJOR) "." FF_STR(QJS_VERSION_MINOR) "." FF_STR(QJS_VERSION_PATCH) QJS_VERSION_SUFFIX "\n"
|
||||
#endif
|
||||
"",
|
||||
stdout);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "common/io.h"
|
||||
#include "fastfetch.h"
|
||||
#include "common/stringUtils.h"
|
||||
#include "common/strutil.h"
|
||||
#include "common/time.h"
|
||||
|
||||
#include <fcntl.h>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "fastfetch.h"
|
||||
#include "common/io.h"
|
||||
#include "common/stringUtils.h"
|
||||
#include "common/strutil.h"
|
||||
#include "common/windows/nt.h"
|
||||
#include "common/windows/unicode.h"
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#include "common/printing.h"
|
||||
#include "common/io.h"
|
||||
#include "common/time.h"
|
||||
#include "common/stringUtils.h"
|
||||
#include "common/strutil.h"
|
||||
#include "detection/version/version.h"
|
||||
#include "modules/modules.h"
|
||||
|
||||
@@ -133,6 +133,7 @@ static bool parseModuleJsonObject(const char* type, yyjson_val* jsonVal, yyjson_
|
||||
|
||||
static void prepareModuleJsonObject(const char* type, yyjson_val* module) {
|
||||
switch (type[0]) {
|
||||
#if !FF_MODULE_DISABLE_CPUUSAGE
|
||||
case 'c':
|
||||
case 'C': {
|
||||
if (ffStrEqualsIgnCase(type, FF_CPUUSAGE_MODULE_NAME)) {
|
||||
@@ -147,6 +148,9 @@ static void prepareModuleJsonObject(const char* type, yyjson_val* module) {
|
||||
}
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !FF_MODULE_DISABLE_DISKIO
|
||||
case 'd':
|
||||
case 'D': {
|
||||
if (ffStrEqualsIgnCase(type, FF_DISKIO_MODULE_NAME)) {
|
||||
@@ -159,6 +163,9 @@ static void prepareModuleJsonObject(const char* type, yyjson_val* module) {
|
||||
}
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !FF_MODULE_DISABLE_NETIO
|
||||
case 'n':
|
||||
case 'N': {
|
||||
if (ffStrEqualsIgnCase(type, FF_NETIO_MODULE_NAME)) {
|
||||
@@ -171,6 +178,9 @@ static void prepareModuleJsonObject(const char* type, yyjson_val* module) {
|
||||
}
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !FF_MODULE_DISABLE_PUBLICIP
|
||||
case 'p':
|
||||
case 'P': {
|
||||
if (ffStrEqualsIgnCase(type, FF_PUBLICIP_MODULE_NAME)) {
|
||||
@@ -183,6 +193,9 @@ static void prepareModuleJsonObject(const char* type, yyjson_val* module) {
|
||||
}
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !FF_MODULE_DISABLE_WEATHER
|
||||
case 'w':
|
||||
case 'W': {
|
||||
if (ffStrEqualsIgnCase(type, FF_WEATHER_MODULE_NAME)) {
|
||||
@@ -195,6 +208,7 @@ static void prepareModuleJsonObject(const char* type, yyjson_val* module) {
|
||||
}
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -322,7 +336,7 @@ static const char* printJsonConfig(FFdata* data, bool prepare) {
|
||||
: FF_COLOR_FG_RED),
|
||||
ms);
|
||||
}
|
||||
printf("\e7\e[1A\e[9999999C\e[%dD%s\e8", len, str); // Save; Up 1; Right 9999999; Left <len>; Print <str>; Load
|
||||
printf("\e7\e[1A\e[9999999C\e[%dD%s\e8", len - 1, str); // Save; Up 1; Right 9999999; Left <len - 1>; Print <str>; Load
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#include "common/kmod.h"
|
||||
#include "common/stringUtils.h"
|
||||
#include "common/strutil.h"
|
||||
|
||||
#include <sys/module.h>
|
||||
#include <sys/param.h>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#include "common/kmod.h"
|
||||
#include "common/stringUtils.h"
|
||||
#include "common/strutil.h"
|
||||
|
||||
#include <sys/modctl.h>
|
||||
#include <errno.h>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#include "common/kmod.h"
|
||||
#include "common/windows/nt.h"
|
||||
#include "common/mallocHelper.h"
|
||||
#include "common/stringUtils.h"
|
||||
#include "common/strutil.h"
|
||||
|
||||
bool ffKmodLoaded(const char* modName) {
|
||||
ULONG bufferSize = 0;
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
#include "fastfetch.h"
|
||||
#include "common/library.h"
|
||||
#include "common/debug.h"
|
||||
|
||||
#if _WIN32
|
||||
#include "common/debug.h"
|
||||
#include "common/windows/nt.h"
|
||||
#include <errno.h>
|
||||
#include <ntstatus.h>
|
||||
@@ -50,6 +50,10 @@ static void* libraryLoad(const char* path, int maxVersion) {
|
||||
|
||||
#else
|
||||
|
||||
if (result == NULL) {
|
||||
FF_DEBUG("dlopen(\"%s\"): %s", path, dlerror());
|
||||
}
|
||||
|
||||
if (result != NULL || maxVersion < 0) {
|
||||
return result;
|
||||
}
|
||||
@@ -65,6 +69,8 @@ static void* libraryLoad(const char* path, int maxVersion) {
|
||||
result = dlopen(pathbuf.chars, FF_DLOPEN_FLAGS);
|
||||
if (result != NULL) {
|
||||
break;
|
||||
} else {
|
||||
FF_DEBUG("dlopen(\"%s\"): %s", pathbuf.chars, dlerror());
|
||||
}
|
||||
|
||||
ffStrbufSubstrBefore(&pathbuf, originalLength);
|
||||
|
||||
@@ -0,0 +1,216 @@
|
||||
#if FF_HAVE_LUA
|
||||
|
||||
#include "common/lua.h"
|
||||
#include "common/mallocHelper.h"
|
||||
|
||||
struct FFLuaData luaData;
|
||||
|
||||
static yyjson_mut_val* lua2yyjson(lua_State* L, int idx, yyjson_mut_doc* doc) {
|
||||
if (idx < 0) {
|
||||
idx = lua_gettop(L) + idx + 1;
|
||||
}
|
||||
int type = lua_type(L, idx);
|
||||
|
||||
switch (type) {
|
||||
case LUA_TNIL:
|
||||
return yyjson_mut_null(doc);
|
||||
|
||||
case LUA_TBOOLEAN:
|
||||
return yyjson_mut_bool(doc, lua_toboolean(L, idx));
|
||||
|
||||
case LUA_TNUMBER: {
|
||||
if (lua_isinteger(L, idx)) {
|
||||
lua_Integer i = lua_tointeger(L, idx);
|
||||
return yyjson_mut_sint(doc, (int64_t) i);
|
||||
} else {
|
||||
return yyjson_mut_real(doc, lua_tonumber(L, idx));
|
||||
}
|
||||
}
|
||||
|
||||
case LUA_TSTRING: {
|
||||
size_t len;
|
||||
const char* str = lua_tolstring(L, idx, &len);
|
||||
return yyjson_mut_strncpy(doc, str, len);
|
||||
}
|
||||
|
||||
case LUA_TTABLE: {
|
||||
lua_Unsigned len = lua_rawlen(L, idx);
|
||||
int is_array = 1;
|
||||
|
||||
if (len == 0) {
|
||||
lua_pushnil(L);
|
||||
is_array = 0;
|
||||
if (lua_next(L, idx) != 0) {
|
||||
lua_pop(L, 2);
|
||||
}
|
||||
} else {
|
||||
lua_pushnil(L);
|
||||
while (lua_next(L, idx) != 0) {
|
||||
if (lua_type(L, -2) != LUA_TNUMBER) {
|
||||
is_array = 0;
|
||||
lua_pop(L, 2);
|
||||
break;
|
||||
}
|
||||
int isnum = false;
|
||||
lua_Integer k = lua_tointegerx(L, -2, &isnum);
|
||||
if (!isnum || (lua_Unsigned) k > len) {
|
||||
is_array = 0;
|
||||
lua_pop(L, 2);
|
||||
break;
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
}
|
||||
|
||||
if (is_array) {
|
||||
yyjson_mut_val* arr = yyjson_mut_arr(doc);
|
||||
for (lua_Unsigned i = 1; i <= len; i++) {
|
||||
lua_rawgeti(L, idx, (lua_Integer) i);
|
||||
yyjson_mut_val* val = lua2yyjson(L, -1, doc);
|
||||
yyjson_mut_arr_append(arr, val);
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
return arr;
|
||||
} else {
|
||||
yyjson_mut_val* obj = yyjson_mut_obj(doc);
|
||||
lua_pushnil(L);
|
||||
while (lua_next(L, idx) != 0) {
|
||||
size_t klen;
|
||||
const char* key_str = luaL_tolstring(L, -2, &klen);
|
||||
yyjson_mut_val* key = yyjson_mut_strncpy(doc, key_str, klen);
|
||||
lua_pop(L, 1);
|
||||
|
||||
yyjson_mut_val* val = lua2yyjson(L, -1, doc);
|
||||
yyjson_mut_obj_add(obj, key, val);
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
|
||||
default:
|
||||
return yyjson_mut_null(doc);
|
||||
}
|
||||
}
|
||||
|
||||
static int yyjsonEncode(lua_State* L) {
|
||||
luaL_checkany(L, 1);
|
||||
|
||||
bool pretty = false;
|
||||
if (lua_isboolean(L, 2)) {
|
||||
pretty = (int) lua_toboolean(L, 2);
|
||||
}
|
||||
|
||||
yyjson_mut_doc* doc = yyjson_mut_doc_new(NULL);
|
||||
if (!doc) {
|
||||
return luaL_error(L, "failed to create yyjson document");
|
||||
}
|
||||
|
||||
yyjson_mut_val* root = lua2yyjson(L, 1, doc);
|
||||
yyjson_mut_doc_set_root(doc, root);
|
||||
|
||||
size_t jsonLen;
|
||||
yyjson_write_err err = {};
|
||||
FF_AUTO_FREE const char* jsonStr = yyjson_mut_write_opts(doc, YYJSON_WRITE_ALLOW_INF_AND_NAN | (pretty ? YYJSON_WRITE_PRETTY_TWO_SPACES : 0), NULL, &jsonLen, &err);
|
||||
|
||||
if (jsonStr) {
|
||||
lua_pushlstring(L, jsonStr, jsonLen);
|
||||
yyjson_mut_doc_free(doc);
|
||||
return 1;
|
||||
} else {
|
||||
yyjson_mut_doc_free(doc);
|
||||
return luaL_error(L, "failed to encode JSON: %s", err.msg);
|
||||
}
|
||||
}
|
||||
|
||||
const char* ffLuaLoadState() {
|
||||
if (luaData.inited) {
|
||||
if (luaData.L == NULL) {
|
||||
return "Lua library is not available";
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
luaData.inited = true;
|
||||
// clang-format off
|
||||
#ifdef _WIN32
|
||||
#define FF_LOAD_LIBLUA(version) FF_LIBRARY_LOAD_MESSAGE(liblua, \
|
||||
"lua5" #version FF_LIBRARY_EXTENSION, 0)
|
||||
#else
|
||||
#define FF_LOAD_LIBLUA(version) FF_LIBRARY_LOAD_MESSAGE(liblua, \
|
||||
"liblua5." #version FF_LIBRARY_EXTENSION, 0, \
|
||||
"liblua-5." #version FF_LIBRARY_EXTENSION, 0, \
|
||||
"liblua5." #version FF_LIBRARY_EXTENSION ".5." #version, 0)
|
||||
#endif
|
||||
// clang-format on
|
||||
#if LUA_VERSION_NUM == 505
|
||||
FF_LOAD_LIBLUA(5)
|
||||
#elif LUA_VERSION_NUM == 504
|
||||
FF_LOAD_LIBLUA(4)
|
||||
#elif LUA_VERSION_NUM == 503
|
||||
FF_LOAD_LIBLUA(3)
|
||||
#else
|
||||
#error "Unsupported Lua version"
|
||||
#endif
|
||||
#undef FF_LOAD_LIBLUA
|
||||
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(liblua, luaL_newstate)
|
||||
#if LUA_VERSION_NUM >= 505
|
||||
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(liblua, luaL_openselectedlibs)
|
||||
#else
|
||||
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(liblua, luaL_requiref)
|
||||
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(liblua, luaopen_base)
|
||||
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(liblua, luaopen_math)
|
||||
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(liblua, luaopen_string)
|
||||
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(liblua, luaopen_table)
|
||||
#endif
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(liblua, luaData, lua_settop)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(liblua, luaData, luaL_loadbufferx)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(liblua, luaData, lua_tolstring)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(liblua, luaData, lua_createtable)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(liblua, luaData, lua_pushinteger)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(liblua, luaData, lua_pushnumber)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(liblua, luaData, lua_pushboolean)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(liblua, luaData, lua_pushstring)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(liblua, luaData, lua_pushlstring)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(liblua, luaData, lua_pushvalue)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(liblua, luaData, lua_seti)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(liblua, luaData, lua_pushnil)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(liblua, luaData, lua_setfield)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(liblua, luaData, lua_pcallk)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(liblua, luaData, lua_gettop)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(liblua, luaData, luaL_tolstring)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(liblua, luaData, luaL_error)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(liblua, luaData, lua_pushcclosure)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(liblua, luaData, luaL_checkany)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(liblua, luaData, lua_callk)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(liblua, luaData, lua_isinteger)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(liblua, luaData, lua_next)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(liblua, luaData, lua_rawgeti)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(liblua, luaData, lua_rawlen)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(liblua, luaData, lua_setglobal)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(liblua, luaData, lua_toboolean)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(liblua, luaData, lua_tointegerx)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(liblua, luaData, lua_tonumberx)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(liblua, luaData, lua_type)
|
||||
|
||||
lua_State* L = ffluaL_newstate();
|
||||
if (L == NULL) {
|
||||
return "luaL_newstate() failed";
|
||||
}
|
||||
#if LUA_VERSION_NUM >= 505
|
||||
ffluaL_openselectedlibs(L, LUA_GLIBK | LUA_MATHLIBK | LUA_STRLIBK | LUA_TABLIBK, 0);
|
||||
#else
|
||||
ffluaL_requiref(L, LUA_GNAME, ffluaopen_base, 1);
|
||||
ffluaL_requiref(L, LUA_MATHLIBNAME, ffluaopen_math, 1);
|
||||
ffluaL_requiref(L, LUA_STRLIBNAME, ffluaopen_string, 1);
|
||||
ffluaL_requiref(L, LUA_TABLIBNAME, ffluaopen_table, 1);
|
||||
lua_settop(L, 0);
|
||||
#endif
|
||||
lua_pushcfunction(L, yyjsonEncode);
|
||||
lua_setglobal(L, "json_encode");
|
||||
luaData.L = L;
|
||||
liblua = NULL; // don't close lua
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,7 +1,7 @@
|
||||
#include "fastfetch.h"
|
||||
#include "common/library.h"
|
||||
#include "common/networking.h"
|
||||
#include "common/stringUtils.h"
|
||||
#include "common/strutil.h"
|
||||
#include "common/debug.h"
|
||||
|
||||
#ifdef FF_HAVE_ZLIB
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#include "common/networking.h"
|
||||
#include "common/time.h"
|
||||
#include "common/library.h"
|
||||
#include "common/stringUtils.h"
|
||||
#include "common/strutil.h"
|
||||
#include "common/mallocHelper.h"
|
||||
#include "common/debug.h"
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
// Must be included after <mswsock.h>
|
||||
#include "fastfetch.h"
|
||||
#include "common/networking.h"
|
||||
#include "common/stringUtils.h"
|
||||
#include "common/strutil.h"
|
||||
#include "common/debug.h"
|
||||
|
||||
static LPFN_CONNECTEX ConnectEx;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#include "fastfetch.h"
|
||||
#include "common/option.h"
|
||||
#include "common/color.h"
|
||||
#include "common/stringUtils.h"
|
||||
#include "common/strutil.h"
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "common/path.h"
|
||||
#include "common/io.h"
|
||||
#include "common/arrayUtils.h"
|
||||
#include "common/arrutil.h"
|
||||
|
||||
#if !_WIN32
|
||||
const char* ffFindExecutableInPath(const char* name, FFstrbuf* result) {
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#include "common/option.h"
|
||||
#include "common/jsonconfig.h"
|
||||
#include "common/textModifier.h"
|
||||
#include "common/stringUtils.h"
|
||||
#include "common/strutil.h"
|
||||
|
||||
static void appendOutputColor(FFstrbuf* buffer, const FFModuleArgs* module) {
|
||||
if (module->outputColor.length) {
|
||||
|
||||
@@ -81,16 +81,24 @@ void ffPrintLogoAndKey(const char* moduleName, uint8_t moduleIndex, const FFModu
|
||||
}
|
||||
}
|
||||
|
||||
void ffPrintFormat(const char* moduleName, uint8_t moduleIndex, const FFModuleArgs* moduleArgs, FFPrintType printType, uint32_t numArgs, const FFformatarg* arguments) {
|
||||
bool ffPrintFormat(const char* moduleName, uint8_t moduleIndex, const FFModuleArgs* moduleArgs, FFPrintType printType, uint32_t numArgs, const FFformatarg* arguments) {
|
||||
FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreate();
|
||||
if (moduleArgs) {
|
||||
ffParseFormatString(&buffer, &moduleArgs->outputFormat, numArgs, arguments);
|
||||
bool success;
|
||||
if (__builtin_expect(moduleArgs != NULL, 1)) {
|
||||
success = ffParseFormatString(&buffer, &moduleArgs->outputFormat, numArgs, arguments);
|
||||
} else {
|
||||
ffStrbufAppendS(&buffer, "unknown");
|
||||
ffStrbufSetStatic(&buffer, "undefined format");
|
||||
success = false;
|
||||
}
|
||||
|
||||
ffPrintLogoAndKey(moduleName, moduleIndex, moduleArgs, printType);
|
||||
ffStrbufPutTo(&buffer, stdout);
|
||||
if (success) {
|
||||
ffPrintLogoAndKey(moduleName, moduleIndex, moduleArgs, printType);
|
||||
ffStrbufPutTo(&buffer, stdout);
|
||||
} else {
|
||||
ffPrintError(moduleName, moduleIndex, moduleArgs, printType, "%s", buffer.chars);
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
void ffPrintError(const char* moduleName, uint8_t moduleIndex, const FFModuleArgs* moduleArgs, FFPrintType printType, const char* message, ...) {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#include "fastfetch.h"
|
||||
#include "common/processing.h"
|
||||
#include "common/io.h"
|
||||
#include "common/stringUtils.h"
|
||||
#include "common/strutil.h"
|
||||
#include "common/mallocHelper.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
#include "common/strutil.h"
|
||||
|
||||
uint8_t ffUtf8CharLenWidth(const char* str, uint32_t length, uint8_t* width) {
|
||||
if (__builtin_expect(length == 0 || *str == '\0', false)) {
|
||||
if (width) {
|
||||
*width = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned char first = (unsigned char) *str;
|
||||
if (__builtin_expect(first < 0x80, true)) {
|
||||
if (width) {
|
||||
*width = 1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint8_t bytes;
|
||||
if ((first & 0xE0) == 0xC0) {
|
||||
bytes = 2;
|
||||
} else if ((first & 0xF0) == 0xE0) {
|
||||
bytes = 3;
|
||||
} else if ((first & 0xF8) == 0xF0) {
|
||||
bytes = 4;
|
||||
} else {
|
||||
if (width) {
|
||||
*width = 1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (length < bytes) {
|
||||
if (width) {
|
||||
*width = 1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (uint8_t i = 1; i < bytes; ++i) {
|
||||
unsigned char continuation = (unsigned char) str[i];
|
||||
if (continuation == '\0' || (continuation & 0xC0) != 0x80) {
|
||||
if (width) {
|
||||
*width = 1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t ucs = (uint32_t) (first & ((1U << (8 - bytes)) - 1));
|
||||
for (uint8_t i = 1; i < bytes; ++i) {
|
||||
ucs <<= 6;
|
||||
ucs |= (uint32_t) ((unsigned char) str[i] & 0x3F);
|
||||
}
|
||||
|
||||
int wcWidth = mk_wcwidth(ucs);
|
||||
if (width) {
|
||||
*width = (uint8_t) (wcWidth < 0 ? 0 : wcWidth);
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
uint32_t ffUtf8StrWidth(const char* str, uint32_t length) {
|
||||
uint32_t result = 0;
|
||||
const char* ptr = str;
|
||||
|
||||
while (length > 0 && *ptr != '\0') {
|
||||
uint8_t width = 0;
|
||||
uint8_t bytes = ffUtf8CharLenWidth(ptr, length, &width);
|
||||
if (__builtin_expect(bytes == 0, false)) {
|
||||
break;
|
||||
}
|
||||
|
||||
result += width;
|
||||
ptr += bytes;
|
||||
length -= bytes;
|
||||
}
|
||||
|
||||
return result > 0 ? result : (uint32_t) (ptr - str);
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
#include "fastfetch.h"
|
||||
#include "common/temps.h"
|
||||
#include "common/textModifier.h"
|
||||
#include "common/stringUtils.h"
|
||||
#include "common/strutil.h"
|
||||
|
||||
void ffTempsAppendNum(double celsius, FFstrbuf* buffer, FFColorRangeConfig config, const FFModuleArgs* module) {
|
||||
if (celsius == -DBL_MAX) { // ignores invalid value
|
||||
|
||||
@@ -19,11 +19,11 @@ int mk_wcwidth(uint32_t wc) {
|
||||
case widechar_widened_in_9:
|
||||
// Our renderer supports Unicode 9
|
||||
return 2;
|
||||
// case widechar_nonprint:
|
||||
// case widechar_combining:
|
||||
// case widechar_unassigned:
|
||||
// case widechar_non_character:
|
||||
// return -1;
|
||||
case widechar_nonprint:
|
||||
case widechar_combining:
|
||||
case widechar_unassigned:
|
||||
case widechar_non_character:
|
||||
return 0;
|
||||
default:
|
||||
// Use the width widechar_width gave us.
|
||||
return width;
|
||||
|
||||
@@ -0,0 +1,183 @@
|
||||
#pragma once
|
||||
|
||||
#include "fastfetch.h"
|
||||
|
||||
#if FF_HAVE_LUA
|
||||
// Hack. LUA_API is defined as extern which prevents us from implementing the functions ourselves.
|
||||
#include <luaconf.h>
|
||||
#undef LUA_API
|
||||
#undef LUALIB_API
|
||||
#undef LUAMOD_API
|
||||
#define LUA_API static inline
|
||||
#define LUALIB_API LUA_API
|
||||
#define LUAMOD_API LUA_API
|
||||
|
||||
#pragma GCC diagnostic ignored "-Wunused-function"
|
||||
#include <lua.h>
|
||||
#include <lauxlib.h>
|
||||
#include <lualib.h>
|
||||
|
||||
#ifndef LUA_GNAME
|
||||
#define LUA_GNAME "_G"
|
||||
#endif
|
||||
|
||||
#include "common/library.h"
|
||||
|
||||
extern struct FFLuaData {
|
||||
FF_LIBRARY_SYMBOL(luaL_newstate)
|
||||
#if LUA_VERSION_NUM >= 505
|
||||
FF_LIBRARY_SYMBOL(luaL_openselectedlibs)
|
||||
#else
|
||||
FF_LIBRARY_SYMBOL(luaL_openlibs)
|
||||
#endif
|
||||
FF_LIBRARY_SYMBOL(lua_settop)
|
||||
FF_LIBRARY_SYMBOL(luaL_loadbufferx)
|
||||
FF_LIBRARY_SYMBOL(lua_tolstring)
|
||||
FF_LIBRARY_SYMBOL(lua_createtable)
|
||||
FF_LIBRARY_SYMBOL(lua_pushinteger)
|
||||
FF_LIBRARY_SYMBOL(lua_pushnumber)
|
||||
FF_LIBRARY_SYMBOL(lua_pushboolean)
|
||||
FF_LIBRARY_SYMBOL(lua_pushstring)
|
||||
FF_LIBRARY_SYMBOL(lua_pushlstring)
|
||||
FF_LIBRARY_SYMBOL(lua_pushvalue)
|
||||
FF_LIBRARY_SYMBOL(lua_seti)
|
||||
FF_LIBRARY_SYMBOL(lua_pushnil)
|
||||
FF_LIBRARY_SYMBOL(lua_setfield)
|
||||
FF_LIBRARY_SYMBOL(lua_pcallk)
|
||||
FF_LIBRARY_SYMBOL(lua_gettop)
|
||||
FF_LIBRARY_SYMBOL(luaL_tolstring)
|
||||
FF_LIBRARY_SYMBOL(luaL_error)
|
||||
FF_LIBRARY_SYMBOL(lua_pushcclosure)
|
||||
FF_LIBRARY_SYMBOL(luaL_checkany)
|
||||
FF_LIBRARY_SYMBOL(lua_callk)
|
||||
FF_LIBRARY_SYMBOL(lua_isinteger)
|
||||
FF_LIBRARY_SYMBOL(lua_next)
|
||||
FF_LIBRARY_SYMBOL(lua_rawgeti)
|
||||
FF_LIBRARY_SYMBOL(lua_rawlen)
|
||||
FF_LIBRARY_SYMBOL(lua_setglobal)
|
||||
FF_LIBRARY_SYMBOL(lua_toboolean)
|
||||
FF_LIBRARY_SYMBOL(lua_tointegerx)
|
||||
FF_LIBRARY_SYMBOL(lua_tonumberx)
|
||||
FF_LIBRARY_SYMBOL(lua_type)
|
||||
|
||||
lua_State* L;
|
||||
bool inited;
|
||||
} luaData;
|
||||
|
||||
const char* ffLuaLoadState();
|
||||
|
||||
FF_A_ALWAYS_INLINE void(lua_settop)(lua_State* L, int idx) {
|
||||
return luaData.fflua_settop(L, idx);
|
||||
}
|
||||
|
||||
FF_A_ALWAYS_INLINE int(luaL_loadbufferx)(lua_State* L, const char* buff, size_t sz, const char* name, const char* mode) {
|
||||
return luaData.ffluaL_loadbufferx(L, buff, sz, name, mode);
|
||||
}
|
||||
|
||||
FF_A_ALWAYS_INLINE const char*(lua_tolstring) (lua_State * L, int idx, size_t* len) {
|
||||
return luaData.fflua_tolstring(L, idx, len);
|
||||
}
|
||||
|
||||
FF_A_ALWAYS_INLINE void(lua_createtable)(lua_State* L, int narr, int nrec) {
|
||||
return luaData.fflua_createtable(L, narr, nrec);
|
||||
}
|
||||
|
||||
FF_A_ALWAYS_INLINE void(lua_pushinteger)(lua_State* L, lua_Integer n) {
|
||||
return luaData.fflua_pushinteger(L, n);
|
||||
}
|
||||
|
||||
FF_A_ALWAYS_INLINE void(lua_pushnumber)(lua_State* L, lua_Number n) {
|
||||
return luaData.fflua_pushnumber(L, n);
|
||||
}
|
||||
|
||||
FF_A_ALWAYS_INLINE void(lua_pushboolean)(lua_State* L, int b) {
|
||||
return luaData.fflua_pushboolean(L, b);
|
||||
}
|
||||
|
||||
FF_A_ALWAYS_INLINE const char*(lua_pushstring) (lua_State * L, const char* s) {
|
||||
return luaData.fflua_pushstring(L, s);
|
||||
}
|
||||
|
||||
FF_A_ALWAYS_INLINE const char*(lua_pushlstring) (lua_State * L, const char* s, size_t len) {
|
||||
return luaData.fflua_pushlstring(L, s, len);
|
||||
}
|
||||
|
||||
FF_A_ALWAYS_INLINE void(lua_pushvalue)(lua_State* L, int idx) {
|
||||
return luaData.fflua_pushvalue(L, idx);
|
||||
}
|
||||
|
||||
FF_A_ALWAYS_INLINE void(lua_seti)(lua_State* L, int idx, lua_Integer n) {
|
||||
return luaData.fflua_seti(L, idx, n);
|
||||
}
|
||||
|
||||
FF_A_ALWAYS_INLINE void(lua_pushnil)(lua_State* L) {
|
||||
return luaData.fflua_pushnil(L);
|
||||
}
|
||||
|
||||
FF_A_ALWAYS_INLINE void(lua_setfield)(lua_State* L, int idx, const char* k) {
|
||||
return luaData.fflua_setfield(L, idx, k);
|
||||
}
|
||||
|
||||
FF_A_ALWAYS_INLINE int(lua_pcallk)(lua_State* L, int nargs, int nresults, int errfunc, lua_KContext ctx, lua_KFunction k) {
|
||||
return luaData.fflua_pcallk(L, nargs, nresults, errfunc, ctx, k);
|
||||
}
|
||||
|
||||
FF_A_ALWAYS_INLINE int(lua_gettop)(lua_State* L) {
|
||||
return luaData.fflua_gettop(L);
|
||||
}
|
||||
|
||||
FF_A_ALWAYS_INLINE const char*(luaL_tolstring) (lua_State * L, int idx, size_t* len) {
|
||||
return luaData.ffluaL_tolstring(L, idx, len);
|
||||
}
|
||||
|
||||
#define luaL_error(L, fmt, ...) luaData.ffluaL_error(L, fmt, ##__VA_ARGS__)
|
||||
|
||||
FF_A_ALWAYS_INLINE void(lua_pushcclosure)(lua_State* L, lua_CFunction fn, int n) {
|
||||
return luaData.fflua_pushcclosure(L, fn, n);
|
||||
}
|
||||
|
||||
FF_A_ALWAYS_INLINE void(luaL_checkany)(lua_State* L, int idx) {
|
||||
return luaData.ffluaL_checkany(L, idx);
|
||||
}
|
||||
|
||||
FF_A_ALWAYS_INLINE void(lua_callk)(lua_State* L, int nargs, int nresults, lua_KContext ctx, lua_KFunction k) {
|
||||
return luaData.fflua_callk(L, nargs, nresults, ctx, k);
|
||||
}
|
||||
|
||||
FF_A_ALWAYS_INLINE int(lua_isinteger)(lua_State* L, int idx) {
|
||||
return luaData.fflua_isinteger(L, idx);
|
||||
}
|
||||
|
||||
FF_A_ALWAYS_INLINE int(lua_next)(lua_State* L, int idx) {
|
||||
return luaData.fflua_next(L, idx);
|
||||
}
|
||||
|
||||
FF_A_ALWAYS_INLINE int(lua_rawgeti)(lua_State* L, int idx, lua_Integer n) {
|
||||
return luaData.fflua_rawgeti(L, idx, n);
|
||||
}
|
||||
|
||||
FF_A_ALWAYS_INLINE lua_Unsigned(lua_rawlen)(lua_State* L, int idx) {
|
||||
return luaData.fflua_rawlen(L, idx);
|
||||
}
|
||||
|
||||
FF_A_ALWAYS_INLINE void(lua_setglobal)(lua_State* L, const char* name) {
|
||||
return luaData.fflua_setglobal(L, name);
|
||||
}
|
||||
|
||||
FF_A_ALWAYS_INLINE int(lua_toboolean)(lua_State* L, int idx) {
|
||||
return luaData.fflua_toboolean(L, idx);
|
||||
}
|
||||
|
||||
FF_A_ALWAYS_INLINE lua_Integer(lua_tointegerx)(lua_State* L, int idx, int* isnum) {
|
||||
return luaData.fflua_tointegerx(L, idx, isnum);
|
||||
}
|
||||
|
||||
FF_A_ALWAYS_INLINE lua_Number(lua_tonumberx)(lua_State* L, int idx, int* isnum) {
|
||||
return luaData.fflua_tonumberx(L, idx, isnum);
|
||||
}
|
||||
|
||||
FF_A_ALWAYS_INLINE int(lua_type)(lua_State* L, int idx) {
|
||||
return luaData.fflua_type(L, idx);
|
||||
}
|
||||
|
||||
#endif
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "common/FFstrbuf.h"
|
||||
#include "common/stringUtils.h"
|
||||
#include "common/strutil.h"
|
||||
|
||||
const char* ffFindExecutableInPath(const char* name, FFstrbuf* result);
|
||||
static inline bool ffIsAbsolutePath(const char* path) {
|
||||
|
||||
@@ -13,7 +13,7 @@ typedef enum FF_A_PACKED FFPrintType {
|
||||
} FFPrintType;
|
||||
|
||||
void ffPrintLogoAndKey(const char* moduleName, uint8_t moduleIndex, const FFModuleArgs* moduleArgs, FFPrintType printType);
|
||||
void ffPrintFormat(const char* moduleName, uint8_t moduleIndex, const FFModuleArgs* moduleArgs, FFPrintType printType, uint32_t numArgs, const FFformatarg* arguments);
|
||||
bool ffPrintFormat(const char* moduleName, uint8_t moduleIndex, const FFModuleArgs* moduleArgs, FFPrintType printType, uint32_t numArgs, const FFformatarg* arguments);
|
||||
#define FF_PRINT_FORMAT_CHECKED(moduleName, moduleIndex, moduleArgs, printType, arguments) \
|
||||
ffPrintFormat((moduleName), (moduleIndex), (moduleArgs), (printType), (sizeof(arguments) / sizeof(*arguments)), (arguments));
|
||||
FF_A_PRINTF(5, 6) void ffPrintError(const char* moduleName, uint8_t moduleIndex, const FFModuleArgs* moduleArgs, FFPrintType printType, const char* message, ...);
|
||||
|
||||
@@ -5,6 +5,14 @@
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "common/wcwidth.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
// #include <shlwapi.h>
|
||||
__stdcall char* StrStrIA(const char* lpFirst, const char* lpSrch);
|
||||
#define strcasestr StrStrIA
|
||||
#endif
|
||||
|
||||
static inline bool ffStrSet(const char* str) {
|
||||
if (str == NULL) {
|
||||
return false;
|
||||
@@ -71,6 +79,13 @@ static inline bool ffCharIsDigit(char c) {
|
||||
return '0' <= c && c <= '9';
|
||||
}
|
||||
|
||||
// Parse one UTF-8 character, returning consumed byte count and display width.
|
||||
// Invalid / incomplete sequence falls back to one-byte width=1.
|
||||
// If the Unicode codepoint is non-printable, width becomes 0.
|
||||
uint8_t ffUtf8CharLenWidth(const char* str, uint32_t length, uint8_t* width);
|
||||
|
||||
uint32_t ffUtf8StrWidth(const char* str, uint32_t length);
|
||||
|
||||
static inline bool ffCharIsHexDigit(char c) {
|
||||
return ffCharIsDigit(c) || ('a' <= c && c <= 'f') || ('A' <= c && c <= 'F');
|
||||
}
|
||||
+1
-1
@@ -11,7 +11,7 @@
|
||||
#include <OS.h>
|
||||
#endif
|
||||
|
||||
#include "common/arrayUtils.h"
|
||||
#include "common/arrutil.h"
|
||||
|
||||
static inline double ffTimeGetTick(void) // In msec
|
||||
{
|
||||
|
||||
+6
-10
@@ -2,15 +2,11 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef FF_HAVE_WCWIDTH
|
||||
#include <wchar.h>
|
||||
|
||||
// Should be char32_t but it's not defined on macOS
|
||||
static_assert(sizeof(wchar_t) == sizeof(uint32_t), "wcwidth implementation requires wchar_t to be 32 bits");
|
||||
|
||||
static inline int mk_wcwidth(uint32_t ucs) {
|
||||
return wcwidth((wchar_t) ucs);
|
||||
}
|
||||
#else
|
||||
#if FF_ENABLE_WCWIDTH
|
||||
int mk_wcwidth(uint32_t wc);
|
||||
#else
|
||||
static inline int mk_wcwidth(uint32_t wc) {
|
||||
(void) wc;
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
Title:Separator:OS:Host:Kernel:Uptime:Packages:Shell:Display:DE:WM:WMTheme:Theme:Icons:Font:Cursor:Terminal:TerminalFont:CPU:GPU:Memory:Swap:Disk:LocalIp:Battery:PowerAdapter:Locale:Break:Colors
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "fastfetch.h"
|
||||
#include "battery.h"
|
||||
#include "common/stringUtils.h"
|
||||
#include "common/strutil.h"
|
||||
#include "common/processing.h"
|
||||
#include "common/properties.h"
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "battery.h"
|
||||
#include "common/io.h"
|
||||
#include "common/stringUtils.h"
|
||||
#include "common/strutil.h"
|
||||
#include "common/debug.h"
|
||||
|
||||
#include <dirent.h>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#include "battery.h"
|
||||
#include "common/io.h"
|
||||
#include "common/FFstrbuf.h"
|
||||
#include "common/stringUtils.h"
|
||||
#include "common/strutil.h"
|
||||
|
||||
#include <prop/prop_array.h>
|
||||
#include <prop/prop_bool.h>
|
||||
|
||||
@@ -38,9 +38,10 @@ const char* ffDetectBios(FFBiosResult* bios) {
|
||||
|
||||
FF_IOOBJECT_AUTO_RELEASE io_registry_entry_t deviceChosen = IORegistryEntryFromPath(MACH_PORT_NULL, "IODeviceTree:/chosen");
|
||||
if (deviceChosen) {
|
||||
FF_CFTYPE_AUTO_RELEASE CFStringRef systemFirmwareVersion = IORegistryEntryCreateCFProperty(deviceChosen, CFSTR("system-firmware-version"), kCFAllocatorDefault, kNilOptions);
|
||||
if (systemFirmwareVersion) {
|
||||
ffCfStrGetString(systemFirmwareVersion, &bios->version);
|
||||
FF_CFTYPE_AUTO_RELEASE CFStringRef tag = IORegistryEntryCreateCFProperty(deviceChosen, CFSTR("iboot-stage-one-tag"), kCFAllocatorDefault, kNilOptions)
|
||||
?: IORegistryEntryCreateCFProperty(deviceChosen, CFSTR("system-firmware-version"), kCFAllocatorDefault, kNilOptions);
|
||||
if (tag) {
|
||||
ffCfStrGetString(tag, &bios->version);
|
||||
uint32_t index = ffStrbufFirstIndexC(&bios->version, '-');
|
||||
if (index != bios->version.length) {
|
||||
ffStrbufAppendNS(&bios->type, index, bios->version.chars);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#include "bluetooth.h"
|
||||
#include "common/stringUtils.h"
|
||||
#include "common/strutil.h"
|
||||
|
||||
#ifdef FF_HAVE_DBUS
|
||||
#include "common/dbus.h"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#include "bluetoothradio.h"
|
||||
#include "common/stringUtils.h"
|
||||
#include "common/strutil.h"
|
||||
|
||||
#ifdef FF_HAVE_DBUS
|
||||
#include "common/dbus.h"
|
||||
|
||||
@@ -11,7 +11,7 @@ static const char* detectSecureBoot(bool* result) {
|
||||
return "IORegistryEntryFromPath() failed";
|
||||
}
|
||||
|
||||
FF_CFTYPE_AUTO_RELEASE CFTypeRef prop = IORegistryEntryCreateCFProperty(entryDevice, CFSTR("secure-boot"), kCFAllocatorDefault, 0);
|
||||
FF_CFTYPE_AUTO_RELEASE CFTypeRef prop = IORegistryEntryCreateCFProperty(entryDevice, CFSTR("secure-boot"), kCFAllocatorDefault, kNilOptions);
|
||||
if (!prop) {
|
||||
return "IORegistryEntryCreateCFProperty() failed";
|
||||
}
|
||||
@@ -47,7 +47,21 @@ const char* ffDetectBootmgr(FFBootmgrResult* result) {
|
||||
ffStrbufSetStatic(&result->firmware, "/System/Library/CoreServices/boot.efi");
|
||||
}
|
||||
|
||||
ffStrbufSetStatic(&result->name, "iBoot");
|
||||
#ifdef __aarch64__
|
||||
FF_IOOBJECT_AUTO_RELEASE io_registry_entry_t deviceChosen = IORegistryEntryFromPath(MACH_PORT_NULL, "IODeviceTree:/chosen");
|
||||
if (deviceChosen) {
|
||||
FF_CFTYPE_AUTO_RELEASE CFStringRef tag = IORegistryEntryCreateCFProperty(deviceChosen, CFSTR("iboot-stage-two-tag"), kCFAllocatorDefault, kNilOptions)
|
||||
?: IORegistryEntryCreateCFProperty(deviceChosen, CFSTR("system-firmware-version"), kCFAllocatorDefault, kNilOptions);
|
||||
if (tag) {
|
||||
ffCfStrGetString(tag, &result->name);
|
||||
ffStrbufSubstrBeforeFirstC(&result->name, '-');
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!result->name.length) {
|
||||
ffStrbufSetStatic(&result->name, "iBoot");
|
||||
}
|
||||
|
||||
detectSecureBoot(&result->secureBoot);
|
||||
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
extern "C" {
|
||||
#include "bootmgr.h"
|
||||
#include "common/io.h"
|
||||
}
|
||||
|
||||
const char* ffDetectBootmgr(FFBootmgrResult* result) {
|
||||
// TODO: glob haiku_loader.* + check EFI partition
|
||||
if (ffPathExists("/system/haiku_loader.bios_ia32", FF_PATHTYPE_FILE)) {
|
||||
ffStrbufSetStatic(&result->firmware, "/system/haiku_loader.bios_ia32");
|
||||
}
|
||||
|
||||
ffStrbufSetStatic(&result->name, "haiku_loader");
|
||||
|
||||
// TODO: detectSecureBoot(&result->secureBoot);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@@ -9,4 +9,18 @@ typedef struct FFBrightnessResult {
|
||||
bool builtin;
|
||||
} FFBrightnessResult;
|
||||
|
||||
enum {
|
||||
FF_DDC_EDID_ADDR = 0x50u,
|
||||
FF_DDC_CI_ADDR = 0x37u,
|
||||
FF_DDC_CI_WRITE_ADDR = FF_DDC_CI_ADDR << 1,
|
||||
FF_DDC_CI_READ_ADDR = FF_DDC_CI_WRITE_ADDR | 1,
|
||||
FF_DDC_CI_VCP_COMMAND = 0x51u,
|
||||
FF_DDC_CI_GET_VCP = 0x01u,
|
||||
FF_DDC_CI_SET_VCP = 0x03u,
|
||||
FF_DDC_CI_COMMAND_PACKET = 0x80u,
|
||||
FF_DDC_CI_LUMINANCE_OPCODE = 0x10u,
|
||||
};
|
||||
#define FF_BRIGHTNESS_DDCCI_SLEEP_SKIP ((uint32_t) -1)
|
||||
#define FF_DDC_CI_MAKE_HEADER(len) (FF_DDC_CI_COMMAND_PACKET | ((len) & 0x7F))
|
||||
|
||||
const char* ffDetectBrightness(FFBrightnessOptions* options, FFlist* result); // list of FFBrightnessResult
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#include "detection/displayserver/displayserver.h"
|
||||
#include "common/apple/cf_helpers.h"
|
||||
#include "common/edidHelper.h"
|
||||
#include "common/time.h"
|
||||
|
||||
#include <CoreGraphics/CoreGraphics.h>
|
||||
|
||||
@@ -85,17 +86,17 @@ static const char* detectWithDdcci(FF_A_UNUSED const FFDisplayServerResult* disp
|
||||
}
|
||||
|
||||
{
|
||||
uint8_t i2cIn[4] = { 0x82, 0x01, 0x10 /* luminance */ };
|
||||
i2cIn[3] = 0x6e ^ i2cIn[0] ^ i2cIn[1] ^ i2cIn[2];
|
||||
uint8_t i2cIn[4] = { FF_DDC_CI_MAKE_HEADER(2), FF_DDC_CI_GET_VCP, FF_DDC_CI_LUMINANCE_OPCODE };
|
||||
i2cIn[3] = FF_DDC_CI_WRITE_ADDR ^ i2cIn[0] ^ i2cIn[1] ^ i2cIn[2];
|
||||
|
||||
for (uint32_t i = 0; i < 2; ++i) {
|
||||
IOAVServiceWriteI2C(service, 0x37, 0x51, i2cIn, ARRAY_SIZE(i2cIn));
|
||||
usleep(options->ddcciSleep * 1000);
|
||||
IOAVServiceWriteI2C(service, FF_DDC_CI_ADDR, FF_DDC_CI_VCP_COMMAND, i2cIn, ARRAY_SIZE(i2cIn));
|
||||
ffTimeSleep(options->ddcciSleep);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t i2cOut[12] = {};
|
||||
if (IOAVServiceReadI2C(service, 0x37, 0x51, i2cOut, ARRAY_SIZE(i2cOut)) == KERN_SUCCESS) {
|
||||
if (IOAVServiceReadI2C(service, FF_DDC_CI_ADDR, FF_DDC_CI_VCP_COMMAND, i2cOut, ARRAY_SIZE(i2cOut)) == KERN_SUCCESS) {
|
||||
if (i2cOut[2] != 0x02 || i2cOut[3] != 0x00) {
|
||||
continue;
|
||||
}
|
||||
@@ -185,18 +186,18 @@ static const char* detectWithDdcci(const FFDisplayServerResult* displayServer, F
|
||||
continue;
|
||||
}
|
||||
|
||||
uint8_t i2cIn[] = { 0x51, 0x82, 0x01, 0x10 /* luminance */, 0 };
|
||||
i2cIn[4] = 0x6E ^ i2cIn[0] ^ i2cIn[1] ^ i2cIn[2] ^ i2cIn[3];
|
||||
uint8_t i2cIn[] = { FF_DDC_CI_VCP_COMMAND, FF_DDC_CI_MAKE_HEADER(2), FF_DDC_CI_GET_VCP, FF_DDC_CI_LUMINANCE_OPCODE, 0 };
|
||||
i2cIn[4] = FF_DDC_CI_WRITE_ADDR ^ i2cIn[0] ^ i2cIn[1] ^ i2cIn[2] ^ i2cIn[3];
|
||||
|
||||
IOI2CRequest request = {
|
||||
.commFlags = kNilOptions,
|
||||
.sendAddress = 0x6e,
|
||||
.sendAddress = FF_DDC_CI_WRITE_ADDR,
|
||||
.sendTransactionType = kIOI2CSimpleTransactionType,
|
||||
.sendBuffer = (vm_address_t) i2cIn,
|
||||
.sendBytes = ARRAY_SIZE(i2cIn),
|
||||
.minReplyDelay = options->ddcciSleep * 1000ULL,
|
||||
.replyAddress = 0x6F,
|
||||
.replySubAddress = 0x51,
|
||||
.replyAddress = FF_DDC_CI_READ_ADDR,
|
||||
.replySubAddress = FF_DDC_CI_VCP_COMMAND,
|
||||
.replyTransactionType = transactionType,
|
||||
.replyBytes = ARRAY_SIZE(i2cOut),
|
||||
.replyBuffer = (vm_address_t) i2cOut,
|
||||
@@ -235,7 +236,7 @@ const char* ffDetectBrightness(FFBrightnessOptions* options, FFlist* result) {
|
||||
|
||||
detectWithDisplayServices(displayServer, result);
|
||||
|
||||
if (displayServer->displays.length > result->length) {
|
||||
if (options->ddcciSleep != FF_BRIGHTNESS_DDCCI_SLEEP_SKIP && displayServer->displays.length > result->length) {
|
||||
detectWithDdcci(displayServer, options, result);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,28 +1,112 @@
|
||||
#include "brightness.h"
|
||||
#include "common/arrutil.h"
|
||||
#include "common/io.h"
|
||||
#include "common/kmod.h"
|
||||
#include "common/debug.h"
|
||||
#include "common/time.h"
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#if __has_include(<dev/iicbus/iic.h>)
|
||||
#include <dev/iicbus/iic.h>
|
||||
|
||||
const char* detectWithDdcci(FF_A_UNUSED FFBrightnessOptions* options, FFlist* result) {
|
||||
// FIXME: doesn't work for me
|
||||
for (char i = '0'; i <= '9'; ++i) {
|
||||
char path[] = "/dev/iic0";
|
||||
path[ARRAY_SIZE(path) - 2] = i;
|
||||
|
||||
FF_AUTO_CLOSE_FD int fd = open(path, O_RDWR | O_CLOEXEC);
|
||||
if (fd < 0) {
|
||||
int err = errno;
|
||||
if (err == ENOENT) {
|
||||
FF_DEBUG("No more I2C devices");
|
||||
break;
|
||||
} else if (i == '0' && !ffKmodLoaded("iicbus")) {
|
||||
FF_DEBUG("iicbus module is not loaded");
|
||||
return "No I2C devices found and iicbus module is not loaded";
|
||||
}
|
||||
FF_DEBUG("open(/dev/iic%c) failed: %s", i, strerror(errno));
|
||||
continue;
|
||||
}
|
||||
|
||||
uint8_t i2cIn[] = { FF_DDC_CI_VCP_COMMAND, FF_DDC_CI_MAKE_HEADER(2), FF_DDC_CI_GET_VCP, FF_DDC_CI_LUMINANCE_OPCODE, 0 };
|
||||
i2cIn[4] = FF_DDC_CI_WRITE_ADDR ^ i2cIn[0] ^ i2cIn[1] ^ i2cIn[2] ^ i2cIn[3];
|
||||
|
||||
int ret = ioctl(fd, I2CRDWR, &(struct iic_rdwr_data){ .msgs = &(struct iic_msg){ .slave = FF_DDC_CI_WRITE_ADDR, .flags = IIC_M_WR, .len = ARRAY_SIZE(i2cIn), .buf = i2cIn }, .nmsgs = 1 });
|
||||
if (ret < 0) {
|
||||
FF_DEBUG("First ioctl(/dev/iic%c, I2CRDWR) failed: %s", i, strerror(errno));
|
||||
continue;
|
||||
}
|
||||
|
||||
ffTimeSleep(options->ddcciSleep);
|
||||
|
||||
uint8_t i2cOut[12] = {};
|
||||
ret = ioctl(fd, I2CRDWR, &(struct iic_rdwr_data){ .msgs = &(struct iic_msg){ .slave = FF_DDC_CI_READ_ADDR, // LSB will be overridden by kernel to set read bit
|
||||
.flags = IIC_M_RD,
|
||||
.len = ARRAY_SIZE(i2cOut),
|
||||
.buf = i2cOut },
|
||||
.nmsgs = 1 });
|
||||
if (ret < 0) {
|
||||
FF_DEBUG("Second ioctl(/dev/iic%c, I2CRDWR) failed: %s", i, strerror(errno));
|
||||
continue;
|
||||
}
|
||||
if (i2cOut[2] != 0x02 || i2cOut[3] != 0x00) {
|
||||
FF_DEBUG("i2c out validation failed: i2cOut[2] = 0x%02x, i2cOut[3] = 0x%02x", i2cOut[2], i2cOut[3]);
|
||||
continue;
|
||||
}
|
||||
|
||||
uint32_t current = ((uint32_t) i2cOut[8] << 8u) + (uint32_t) i2cOut[9];
|
||||
uint32_t max = ((uint32_t) i2cOut[6] << 8u) + (uint32_t) i2cOut[7];
|
||||
|
||||
FFBrightnessResult* brightness = FF_LIST_ADD(FFBrightnessResult, *result);
|
||||
brightness->max = max;
|
||||
brightness->min = 0;
|
||||
brightness->current = current;
|
||||
ffStrbufInitS(&brightness->name, path + strlen("/dev/"));
|
||||
brightness->builtin = false;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
const char* detectWithDdcci(FF_A_UNUSED FFBrightnessOptions* options, FF_A_UNUSED FFlist* result) {
|
||||
FF_DEBUG("DDC/CI support is not available on this system");
|
||||
return "DDC/CI is supported only on FreeBSD";
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if __has_include(<sys/backlight.h>)
|
||||
|
||||
#include "common/io.h"
|
||||
|
||||
#include <sys/backlight.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
const char* ffDetectBrightness(FF_A_UNUSED FFBrightnessOptions* options, FFlist* result) {
|
||||
const char* detectWithBacklight(FF_A_UNUSED FFBrightnessOptions* options, FFlist* result) {
|
||||
// https://man.freebsd.org/cgi/man.cgi?query=backlight&sektion=9
|
||||
char path[] = "/dev/backlight/backlight0";
|
||||
|
||||
for (char i = '0'; i <= '9'; ++i) {
|
||||
path[ARRAY_SIZE(path) - 2] = i;
|
||||
|
||||
FF_AUTO_CLOSE_FD int blfd = open(path, O_RDONLY | O_CLOEXEC);
|
||||
if (blfd < 0) {
|
||||
FF_AUTO_CLOSE_FD int fd = open(path, O_RDONLY | O_CLOEXEC);
|
||||
if (fd < 0) {
|
||||
int err = errno;
|
||||
if (err == ENOENT) {
|
||||
FF_DEBUG("No more backlight devices");
|
||||
break;
|
||||
} else if (i == '0' && !ffKmodLoaded("backlight")) {
|
||||
FF_DEBUG("backlight module is not loaded");
|
||||
return "No backlight devices found and backlight module is not loaded";
|
||||
}
|
||||
FF_DEBUG("open(/dev/backlight/backlight%c) failed: %s", i, strerror(errno));
|
||||
continue;
|
||||
}
|
||||
|
||||
struct backlight_props status;
|
||||
if (ioctl(blfd, BACKLIGHTGETSTATUS, &status) < 0) {
|
||||
if (ioctl(fd, BACKLIGHTGETSTATUS, &status) < 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -35,7 +119,7 @@ const char* ffDetectBrightness(FF_A_UNUSED FFBrightnessOptions* options, FFlist*
|
||||
brightness->builtin = true;
|
||||
|
||||
struct backlight_info info;
|
||||
if (ioctl(blfd, BACKLIGHTGETINFO, &info) == 0) {
|
||||
if (ioctl(fd, BACKLIGHTGETINFO, &info) == 0) {
|
||||
ffStrbufAppendS(&brightness->name, info.name);
|
||||
} else {
|
||||
ffStrbufAppendS(&brightness->name, path + strlen("/dev/backlight/"));
|
||||
@@ -46,8 +130,18 @@ const char* ffDetectBrightness(FF_A_UNUSED FFBrightnessOptions* options, FFlist*
|
||||
|
||||
#else
|
||||
|
||||
const char* ffDetectBrightness(FF_A_UNUSED FFBrightnessOptions* options, FF_A_UNUSED FFlist* result) {
|
||||
const char* detectWithBacklight(FF_A_UNUSED FFBrightnessOptions* options, FF_A_UNUSED FFlist* result) {
|
||||
FF_DEBUG("Backlight support is not available on this system");
|
||||
return "Backlight is supported only on FreeBSD 13 and newer";
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
const char* ffDetectBrightness(FF_A_UNUSED FFBrightnessOptions* options, FFlist* result) {
|
||||
detectWithBacklight(options, result);
|
||||
|
||||
if (options->ddcciSleep != FF_BRIGHTNESS_DDCCI_SLEEP_SKIP && result->length == 0) {
|
||||
detectWithDdcci(options, result);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
extern "C" {
|
||||
#include "brightness.h"
|
||||
#include "common/strutil.h"
|
||||
}
|
||||
|
||||
#include <Application.h>
|
||||
#include <Screen.h>
|
||||
|
||||
const char* ffDetectBrightness(FF_A_UNUSED FFBrightnessOptions* options, FFlist* result) {
|
||||
// We need a valid be_app to query the app_server here.
|
||||
BApplication app("application/x-vnd.fastfetch-cli-fastfetch");
|
||||
BScreen screen{}; // default screen is the main one
|
||||
|
||||
do {
|
||||
if (!screen.IsValid()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
float value = 1.0f;
|
||||
status_t status = screen.GetBrightness(&value);
|
||||
if (status != B_OK) {
|
||||
continue;
|
||||
}
|
||||
|
||||
monitor_info monitor;
|
||||
// WARNING: This is experimental new Haiku API
|
||||
status_t err = screen.GetMonitorInfo(&monitor);
|
||||
|
||||
FFBrightnessResult* brightness = FF_LIST_ADD(FFBrightnessResult, *result);
|
||||
|
||||
if (err == B_OK) {
|
||||
ffStrbufInitF(&brightness->name, "%s %s (%d)", monitor.vendor, monitor.name, screen.ID().id);
|
||||
ffStrbufTrimRightSpace(&brightness->name);
|
||||
} else {
|
||||
ffStrbufInitF(&brightness->name, "Screen %d", screen.ID().id);
|
||||
}
|
||||
|
||||
brightness->max = 1.0f;
|
||||
brightness->min = 0.0f;
|
||||
brightness->current = value;
|
||||
brightness->builtin = true;
|
||||
|
||||
} while (screen.SetToNext() == B_OK);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
#include "brightness.h"
|
||||
#include "common/io.h"
|
||||
#include "common/edidHelper.h"
|
||||
#include "common/stringUtils.h"
|
||||
#include "common/strutil.h"
|
||||
|
||||
#include <dirent.h>
|
||||
#include <limits.h>
|
||||
@@ -164,9 +164,11 @@ const char* ffDetectBrightness(FF_A_UNUSED FFBrightnessOptions* options, FFlist*
|
||||
detectWithBacklight(result);
|
||||
|
||||
#ifdef FF_HAVE_DDCUTIL
|
||||
const FFDisplayServerResult* displayServer = ffConnectDisplayServer();
|
||||
if (result->length < displayServer->displays.length) {
|
||||
detectWithDdcci(options, result);
|
||||
if (options->ddcciSleep != FF_BRIGHTNESS_DDCCI_SLEEP_SKIP) {
|
||||
const FFDisplayServerResult* displayServer = ffConnectDisplayServer();
|
||||
if (result->length < displayServer->displays.length) {
|
||||
detectWithDdcci(options, result);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -159,7 +159,7 @@ static const char* detectWithDdcci(const FFDisplayServerResult* displayServer, F
|
||||
NTSTATUS monitorStatus = ffGetPhysicalMonitors(&deviceName, 1, &monitorCount, &physicalMonitor);
|
||||
if (NT_SUCCESS(monitorStatus) && monitorCount >= 1) {
|
||||
DWORD curr = 0, max = 0;
|
||||
if (NT_SUCCESS(ffDDCCIGetVCPFeature(physicalMonitor, 0x10 /* luminance */, NULL, &curr, &max))) {
|
||||
if (NT_SUCCESS(ffDDCCIGetVCPFeature(physicalMonitor, FF_DDC_CI_LUMINANCE_OPCODE, NULL, &curr, &max))) {
|
||||
FFBrightnessResult* brightness = FF_LIST_ADD(FFBrightnessResult, *result);
|
||||
if (display->name.length > 0) {
|
||||
ffStrbufInitCopy(&brightness->name, &display->name);
|
||||
@@ -213,7 +213,7 @@ const char* ffDetectBrightness(FF_A_UNUSED FFBrightnessOptions* options, FFlist*
|
||||
detectWithWmi(result);
|
||||
}
|
||||
|
||||
if (result->length < displayServer->displays.length) {
|
||||
if (options->ddcciSleep != FF_BRIGHTNESS_DDCCI_SLEEP_SKIP && result->length < displayServer->displays.length) {
|
||||
FF_DEBUG("resultCount=%u < displayCount=%u, trying DDC/CI", result->length, displayServer->displays.length);
|
||||
detectWithDdcci(displayServer, result);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
#include "codec.h"
|
||||
|
||||
const char* ffDetectCodec(FFCodecOptions* options, FFlist* result /*list of FFCodecResult*/) {
|
||||
if (options->useVulkan) {
|
||||
#ifdef FF_HAVE_VULKAN
|
||||
return ffDetectCodecVulkan(options, result);
|
||||
#else
|
||||
FF_UNUSED(options, result);
|
||||
return "Fastfetch was built without Vulkan support";
|
||||
#endif
|
||||
}
|
||||
|
||||
return ffDetectCodecNative(options, result);
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
#pragma once
|
||||
|
||||
#include "fastfetch.h"
|
||||
#include "modules/codec/option.h"
|
||||
|
||||
typedef enum FF_A_PACKED FFCodecType {
|
||||
FF_CODEC_TYPE_NONE = 0,
|
||||
FF_CODEC_TYPE_UNKNOWN = UINT32_C(1) << 0,
|
||||
FF_CODEC_TYPE_H261 = UINT32_C(1) << 1,
|
||||
FF_CODEC_TYPE_H263 = UINT32_C(1) << 2,
|
||||
FF_CODEC_TYPE_MJPEG = UINT32_C(1) << 3,
|
||||
FF_CODEC_TYPE_MPEG1 = UINT32_C(1) << 4,
|
||||
FF_CODEC_TYPE_MPEG2 = UINT32_C(1) << 5,
|
||||
FF_CODEC_TYPE_DIVX_XVID = UINT32_C(1) << 6,
|
||||
FF_CODEC_TYPE_H264 = UINT32_C(1) << 7,
|
||||
FF_CODEC_TYPE_WMV8 = UINT32_C(1) << 8,
|
||||
FF_CODEC_TYPE_WMV9 = UINT32_C(1) << 9,
|
||||
FF_CODEC_TYPE_VC1 = UINT32_C(1) << 10,
|
||||
FF_CODEC_TYPE_VP8 = UINT32_C(1) << 11,
|
||||
FF_CODEC_TYPE_HEVC = UINT32_C(1) << 12,
|
||||
FF_CODEC_TYPE_VP9 = UINT32_C(1) << 13,
|
||||
FF_CODEC_TYPE_AV1 = UINT32_C(1) << 14,
|
||||
FF_CODEC_TYPE_VVC = UINT32_C(1) << 15,
|
||||
FF_CODEC_TYPE_DOLBY_VISION_HEVC = UINT32_C(1) << 16,
|
||||
FF_CODEC_TYPE_PRORES = UINT32_C(1) << 17,
|
||||
FF_CODEC_TYPE_PRORES_RAW = UINT32_C(1) << 18,
|
||||
FF_CODEC_TYPE_JPEG_XL = UINT32_C(1) << 19,
|
||||
FF_CODEC_TYPE_MAX = FF_CODEC_TYPE_JPEG_XL,
|
||||
FF_CODEC_TYPE_FORCE_UNSIGNED = UINT32_MAX,
|
||||
} FFCodecType;
|
||||
|
||||
typedef struct FFCodecResult {
|
||||
FFstrbuf gpu;
|
||||
FFCodecType decoders;
|
||||
FFCodecType encoders;
|
||||
const char* platformApi;
|
||||
} FFCodecResult;
|
||||
|
||||
const char* ffDetectCodec(FFCodecOptions* options, FFlist* result /*list of FFCodecResult*/);
|
||||
const char* ffDetectCodecNative(FFCodecOptions* options, FFlist* result /*list of FFCodecResult*/);
|
||||
|
||||
#ifdef FF_HAVE_VULKAN
|
||||
const char* ffDetectCodecVulkan(FFCodecOptions* options, FFlist* result /*list of FFCodecResult*/);
|
||||
#endif
|
||||
@@ -0,0 +1,102 @@
|
||||
#include "codec.h"
|
||||
|
||||
#include "common/library.h"
|
||||
#include "common/strutil.h"
|
||||
#undef __INTRODUCED_IN
|
||||
#define __INTRODUCED_IN(...)
|
||||
#include <media/NdkMediaCodec.h>
|
||||
|
||||
static const struct {
|
||||
const char* mime;
|
||||
FFCodecType type;
|
||||
} FF_CODEC_MIME_TO_TYPE[] = {
|
||||
{ "video/3gpp", FF_CODEC_TYPE_H263 },
|
||||
{ "video/h263", FF_CODEC_TYPE_H263 },
|
||||
{ "video/mjpeg", FF_CODEC_TYPE_MJPEG },
|
||||
{ "video/mpeg2", FF_CODEC_TYPE_MPEG2 },
|
||||
{ "video/mp2v-es", FF_CODEC_TYPE_MPEG2 },
|
||||
{ "video/mp4v-es", FF_CODEC_TYPE_DIVX_XVID },
|
||||
{ "video/avc", FF_CODEC_TYPE_H264 },
|
||||
{ "video/hevc", FF_CODEC_TYPE_HEVC },
|
||||
{ "video/x-vnd.on2.vp8", FF_CODEC_TYPE_VP8 },
|
||||
{ "video/x-vnd.on2.vp9", FF_CODEC_TYPE_VP9 },
|
||||
{ "video/av01", FF_CODEC_TYPE_AV1 },
|
||||
{ "video/vvc", FF_CODEC_TYPE_VVC },
|
||||
};
|
||||
|
||||
static bool ffCodecIsLikelySoftware(const char* codecName) {
|
||||
if (!codecName) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return ffStrStartsWith(codecName, "OMX.google.") ||
|
||||
ffStrStartsWith(codecName, "c2.android.") ||
|
||||
ffStrStartsWith(codecName, "OMX.ffmpeg.") ||
|
||||
ffStrStartsWith(codecName, "OMX.PV.");
|
||||
}
|
||||
|
||||
static bool ffCodecIsHardwareAccelerated(
|
||||
AMediaCodec* codec,
|
||||
__typeof__(&AMediaCodec_getName) ffAMediaCodec_getName,
|
||||
__typeof__(&AMediaCodec_releaseName) ffAMediaCodec_releaseName) {
|
||||
if (!codec) {
|
||||
return false;
|
||||
}
|
||||
|
||||
char* codecName = NULL;
|
||||
media_status_t status = ffAMediaCodec_getName(codec, &codecName);
|
||||
if (status != AMEDIA_OK || !codecName) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool isHardware = !ffCodecIsLikelySoftware(codecName);
|
||||
ffAMediaCodec_releaseName(codec, codecName);
|
||||
return isHardware;
|
||||
}
|
||||
|
||||
const char* ffDetectCodecNative(FFCodecOptions* options, FFlist* result /*list of FFCodecResult*/) {
|
||||
FF_LIBRARY_LOAD_MESSAGE(mediandk, "libmediandk.so", 0)
|
||||
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(mediandk, AMediaCodec_createDecoderByType)
|
||||
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(mediandk, AMediaCodec_createEncoderByType)
|
||||
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(mediandk, AMediaCodec_delete)
|
||||
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(mediandk, AMediaCodec_getName)
|
||||
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(mediandk, AMediaCodec_releaseName)
|
||||
|
||||
FFCodecType decoders = FF_CODEC_TYPE_NONE;
|
||||
FFCodecType encoders = FF_CODEC_TYPE_NONE;
|
||||
|
||||
for (uint32_t i = 0; i < ARRAY_SIZE(FF_CODEC_MIME_TO_TYPE); ++i) {
|
||||
const char* mime = FF_CODEC_MIME_TO_TYPE[i].mime;
|
||||
FFCodecType type = FF_CODEC_MIME_TO_TYPE[i].type;
|
||||
|
||||
if ((options->showType & FF_CODEC_SHOW_TYPE_DECODER) && !(decoders & type)) {
|
||||
AMediaCodec* decoder = ffAMediaCodec_createDecoderByType(mime);
|
||||
if (decoder) {
|
||||
if (ffCodecIsHardwareAccelerated(decoder, ffAMediaCodec_getName, ffAMediaCodec_releaseName)) {
|
||||
decoders |= type;
|
||||
}
|
||||
ffAMediaCodec_delete(decoder);
|
||||
}
|
||||
}
|
||||
|
||||
if ((options->showType & FF_CODEC_SHOW_TYPE_ENCODER) && !(encoders & type)) {
|
||||
AMediaCodec* encoder = ffAMediaCodec_createEncoderByType(mime);
|
||||
if (encoder) {
|
||||
if (ffCodecIsHardwareAccelerated(encoder, ffAMediaCodec_getName, ffAMediaCodec_releaseName)) {
|
||||
encoders |= type;
|
||||
}
|
||||
ffAMediaCodec_delete(encoder);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (decoders != FF_CODEC_TYPE_NONE || encoders != FF_CODEC_TYPE_NONE) {
|
||||
FFCodecResult* item = FF_LIST_ADD(FFCodecResult, *result);
|
||||
ffStrbufInitStatic(&item->gpu, "Default");
|
||||
item->decoders = decoders;
|
||||
item->encoders = encoders;
|
||||
item->platformApi = "AMediaCodec";
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
#include "codec.h"
|
||||
|
||||
#include <VideoToolbox/VideoToolbox.h>
|
||||
#include "common/apple/cf_helpers.h"
|
||||
|
||||
static const struct {
|
||||
CMVideoCodecType codec;
|
||||
FFCodecType type;
|
||||
} FF_CODEC_CODECS[] = {
|
||||
{ kCMVideoCodecType_H263, FF_CODEC_TYPE_H263 },
|
||||
{ kCMVideoCodecType_JPEG, FF_CODEC_TYPE_MJPEG },
|
||||
{ kCMVideoCodecType_JPEG_XL, FF_CODEC_TYPE_JPEG_XL },
|
||||
{ kCMVideoCodecType_MPEG1Video, FF_CODEC_TYPE_MPEG1 },
|
||||
{ kCMVideoCodecType_MPEG2Video, FF_CODEC_TYPE_MPEG2 },
|
||||
{ kCMVideoCodecType_MPEG4Video, FF_CODEC_TYPE_DIVX_XVID },
|
||||
{ kCMVideoCodecType_H264, FF_CODEC_TYPE_H264 },
|
||||
{ kCMVideoCodecType_HEVC, FF_CODEC_TYPE_HEVC },
|
||||
{ kCMVideoCodecType_HEVCWithAlpha, FF_CODEC_TYPE_HEVC },
|
||||
{ kCMVideoCodecType_DolbyVisionHEVC, FF_CODEC_TYPE_DOLBY_VISION_HEVC },
|
||||
{ kCMVideoCodecType_DisparityHEVC, FF_CODEC_TYPE_HEVC },
|
||||
{ kCMVideoCodecType_DepthHEVC, FF_CODEC_TYPE_HEVC },
|
||||
{ kCMVideoCodecType_VP9, FF_CODEC_TYPE_VP9 },
|
||||
{ kCMVideoCodecType_AV1, FF_CODEC_TYPE_AV1 },
|
||||
{ kCMVideoCodecType_AppleProRes4444XQ, FF_CODEC_TYPE_PRORES },
|
||||
{ kCMVideoCodecType_AppleProRes4444, FF_CODEC_TYPE_PRORES },
|
||||
{ kCMVideoCodecType_AppleProRes422HQ, FF_CODEC_TYPE_PRORES },
|
||||
{ kCMVideoCodecType_AppleProRes422, FF_CODEC_TYPE_PRORES },
|
||||
{ kCMVideoCodecType_AppleProRes422LT, FF_CODEC_TYPE_PRORES },
|
||||
{ kCMVideoCodecType_AppleProRes422Proxy, FF_CODEC_TYPE_PRORES },
|
||||
{ kCMVideoCodecType_AppleProResRAW, FF_CODEC_TYPE_PRORES_RAW },
|
||||
{ kCMVideoCodecType_AppleProResRAWHQ, FF_CODEC_TYPE_PRORES_RAW },
|
||||
};
|
||||
|
||||
static FFCodecType ffCodecCodecToType(CMVideoCodecType codec) {
|
||||
for (uint32_t i = 0; i < ARRAY_SIZE(FF_CODEC_CODECS); ++i) {
|
||||
if (FF_CODEC_CODECS[i].codec == codec) {
|
||||
return FF_CODEC_CODECS[i].type;
|
||||
}
|
||||
}
|
||||
return FF_CODEC_TYPE_NONE;
|
||||
}
|
||||
|
||||
static FFCodecType ffCodecDetectEncoders(void) {
|
||||
CFArrayRef encoderList = NULL;
|
||||
if (VTCopyVideoEncoderList(NULL, &encoderList) != noErr || !encoderList) {
|
||||
return FF_CODEC_TYPE_NONE;
|
||||
}
|
||||
|
||||
FFCodecType types = FF_CODEC_TYPE_NONE;
|
||||
for (uint32_t i = 0; i < CFArrayGetCount(encoderList); ++i) {
|
||||
CFDictionaryRef encoder = CFArrayGetValueAtIndex(encoderList, i);
|
||||
bool isHardwareAccelerated;
|
||||
int codec;
|
||||
if (ffCfDictGetBool(encoder, CFSTR("IsHardwareAccelerated"), &isHardwareAccelerated) != NULL ||
|
||||
!isHardwareAccelerated ||
|
||||
ffCfDictGetInt(encoder, CFSTR("CodecType"), &codec) != NULL) {
|
||||
continue;
|
||||
}
|
||||
types |= ffCodecCodecToType((CMVideoCodecType) codec);
|
||||
}
|
||||
|
||||
return types;
|
||||
}
|
||||
|
||||
static FFCodecType ffCodecDetectDecoders() {
|
||||
FFCodecType types = FF_CODEC_TYPE_NONE;
|
||||
for (uint32_t i = 0; i < ARRAY_SIZE(FF_CODEC_CODECS); ++i) {
|
||||
if (types & FF_CODEC_CODECS[i].type) {
|
||||
continue;
|
||||
}
|
||||
|
||||
bool supported = VTIsHardwareDecodeSupported(FF_CODEC_CODECS[i].codec);
|
||||
if (!supported) {
|
||||
continue;
|
||||
}
|
||||
|
||||
types |= FF_CODEC_CODECS[i].type;
|
||||
}
|
||||
|
||||
return types;
|
||||
}
|
||||
|
||||
const char* ffDetectCodecNative(FFCodecOptions* options, FFlist* result /* list of FFCodecResult */) {
|
||||
FFCodecType decoders = options->showType & FF_CODEC_SHOW_TYPE_DECODER ? ffCodecDetectDecoders() : FF_CODEC_TYPE_NONE;
|
||||
FFCodecType encoders = options->showType & FF_CODEC_SHOW_TYPE_ENCODER ? ffCodecDetectEncoders() : FF_CODEC_TYPE_NONE;
|
||||
|
||||
if (decoders != FF_CODEC_TYPE_NONE || encoders != FF_CODEC_TYPE_NONE) {
|
||||
FFCodecResult* item = FF_LIST_ADD(FFCodecResult, *result);
|
||||
ffStrbufInitStatic(&item->gpu, "Default");
|
||||
item->decoders = decoders;
|
||||
item->encoders = encoders;
|
||||
item->platformApi = "VideoToolbox";
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@@ -0,0 +1,470 @@
|
||||
#include "codec.h"
|
||||
|
||||
#if (FF_HAVE_DRM && FF_HAVE_VA) || FF_HAVE_VDPAU
|
||||
|
||||
#include "common/library.h"
|
||||
#include "common/mallocHelper.h"
|
||||
#include "common/io.h"
|
||||
|
||||
#if FF_HAVE_DRM && FF_HAVE_VA
|
||||
#include "detection/gpu/gpu.h"
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <va/va.h>
|
||||
#include <va/va_drm.h>
|
||||
#include <xf86drm.h>
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#if FF_HAVE_VDPAU
|
||||
#include <stdlib.h>
|
||||
#include <vdpau/vdpau.h>
|
||||
|
||||
VdpStatus vdp_device_create_x11(void* display, int screen, VdpDevice* device, VdpGetProcAddress** get_proc_address);
|
||||
void* XOpenDisplay(const char* display_name);
|
||||
int XCloseDisplay(void* display);
|
||||
int XDefaultScreen(void* display);
|
||||
#endif
|
||||
|
||||
#if FF_HAVE_DRM && FF_HAVE_VA
|
||||
|
||||
static FFCodecType ffCodecProfileToType(VAProfile profile) {
|
||||
switch (profile) {
|
||||
case 11: // VAProfileH263Baseline
|
||||
return FF_CODEC_TYPE_H263;
|
||||
|
||||
case 12: // VAProfileJPEGBaseline
|
||||
return FF_CODEC_TYPE_MJPEG;
|
||||
|
||||
case 0: // VAProfileMPEG2Simple
|
||||
case 1: // VAProfileMPEG2Main
|
||||
return FF_CODEC_TYPE_MPEG2;
|
||||
|
||||
case 2: // VAProfileMPEG4Simple
|
||||
case 3: // VAProfileMPEG4AdvancedSimple
|
||||
case 4: // VAProfileMPEG4Main
|
||||
return FF_CODEC_TYPE_DIVX_XVID;
|
||||
|
||||
case 5: // VAProfileH264Baseline
|
||||
case 6: // VAProfileH264Main
|
||||
case 7: // VAProfileH264High
|
||||
case 13: // VAProfileH264ConstrainedBaseline
|
||||
case 15: // VAProfileH264MultiviewHigh
|
||||
case 16: // VAProfileH264StereoHigh
|
||||
case 36: // VAProfileH264High10
|
||||
case 40: // VAProfileH264High422
|
||||
return FF_CODEC_TYPE_H264;
|
||||
|
||||
case 8: // VAProfileVC1Simple
|
||||
case 9: // VAProfileVC1Main
|
||||
case 10: // VAProfileVC1Advanced
|
||||
return FF_CODEC_TYPE_VC1;
|
||||
|
||||
case 14: // VAProfileVP8Version0_3
|
||||
return FF_CODEC_TYPE_VP8;
|
||||
|
||||
case 17: // VAProfileHEVCMain
|
||||
case 18: // VAProfileHEVCMain10
|
||||
case 23: // VAProfileHEVCMain12
|
||||
case 24: // VAProfileHEVCMain422_10
|
||||
case 25: // VAProfileHEVCMain422_12
|
||||
case 26: // VAProfileHEVCMain444
|
||||
case 27: // VAProfileHEVCMain444_10
|
||||
case 28: // VAProfileHEVCMain444_12
|
||||
case 29: // VAProfileHEVCSccMain
|
||||
case 30: // VAProfileHEVCSccMain10
|
||||
case 31: // VAProfileHEVCSccMain444
|
||||
case 34: // VAProfileHEVCSccMain444_10
|
||||
return FF_CODEC_TYPE_HEVC;
|
||||
|
||||
case 19: // VAProfileVP9Profile0
|
||||
case 20: // VAProfileVP9Profile1
|
||||
case 21: // VAProfileVP9Profile2
|
||||
case 22: // VAProfileVP9Profile3
|
||||
return FF_CODEC_TYPE_VP9;
|
||||
|
||||
case 32: // VAProfileAV1Profile0
|
||||
case 33: // VAProfileAV1Profile1
|
||||
case 39: // VAProfileAV1Profile2
|
||||
return FF_CODEC_TYPE_AV1;
|
||||
|
||||
case 37: // VAProfileVVCMain10
|
||||
case 38: // VAProfileVVCMultilayerMain10
|
||||
return FF_CODEC_TYPE_VVC;
|
||||
|
||||
default:
|
||||
return FF_CODEC_TYPE_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
static FFCodecShowType ffCodecGetEntrypointType(VAEntrypoint entrypoint) {
|
||||
switch (entrypoint) {
|
||||
case VAEntrypointVLD:
|
||||
case VAEntrypointIDCT:
|
||||
case VAEntrypointMoComp:
|
||||
return FF_CODEC_SHOW_TYPE_DECODER;
|
||||
case VAEntrypointEncSlice:
|
||||
case VAEntrypointEncSliceLP:
|
||||
case VAEntrypointFEI:
|
||||
return FF_CODEC_SHOW_TYPE_ENCODER;
|
||||
default:
|
||||
return FF_CODEC_SHOW_TYPE_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
static bool ffCodecProfileHasOutput(
|
||||
VADisplay display,
|
||||
__typeof__(vaQueryConfigEntrypoints)* ffvaQueryConfigEntrypoints,
|
||||
__typeof__(vaGetConfigAttributes)* ffvaGetConfigAttributes,
|
||||
int maxEntrypoints,
|
||||
VAEntrypoint* entrypoints,
|
||||
VAProfile profile,
|
||||
FFCodecShowType entrypointType) {
|
||||
int numEntrypoints = maxEntrypoints;
|
||||
if (ffvaQueryConfigEntrypoints(display, profile, entrypoints, &numEntrypoints) != VA_STATUS_SUCCESS) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < numEntrypoints; ++i) {
|
||||
if (ffCodecGetEntrypointType(entrypoints[i]) != entrypointType) {
|
||||
continue;
|
||||
}
|
||||
|
||||
VAConfigAttrib attrib = {
|
||||
.type = VAConfigAttribRTFormat,
|
||||
.value = 0,
|
||||
};
|
||||
|
||||
if (ffvaGetConfigAttributes(display, profile, entrypoints[i], &attrib, 1) == VA_STATUS_SUCCESS &&
|
||||
attrib.value != VA_ATTRIB_NOT_SUPPORTED &&
|
||||
attrib.value != 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void ffCodecFillGpuName(const drmDevice* dev, const char* path, FFstrbuf* name) {
|
||||
ffStrbufInit(name);
|
||||
|
||||
switch (dev->bustype) {
|
||||
case DRM_BUS_PCI: {
|
||||
FFGPUResult gpu = {
|
||||
.vendor = ffStrbufCreateStatic(ffGPUGetVendorString(dev->deviceinfo.pci->vendor_id)),
|
||||
.name = ffStrbufCreate(),
|
||||
};
|
||||
|
||||
ffGPUFillVendorAndName(0, dev->deviceinfo.pci->vendor_id, dev->deviceinfo.pci->device_id, &gpu);
|
||||
ffStrbufSetF(name, "%s %s", gpu.vendor.chars, gpu.name.chars);
|
||||
|
||||
ffStrbufDestroy(&gpu.vendor);
|
||||
ffStrbufDestroy(&gpu.name);
|
||||
break;
|
||||
}
|
||||
case DRM_BUS_PLATFORM:
|
||||
ffStrbufSetS(name, dev->deviceinfo.platform->compatible[0]);
|
||||
return;
|
||||
case DRM_BUS_HOST1X:
|
||||
ffStrbufSetS(name, dev->deviceinfo.host1x->compatible[0]);
|
||||
return;
|
||||
case DRM_BUS_USB:
|
||||
ffStrbufSetF(name, "0x%04X 0x%04X", dev->deviceinfo.usb->vendor, dev->deviceinfo.usb->product);
|
||||
return;
|
||||
default:
|
||||
ffStrbufSetStatic(name, "Unknown GPU");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!name->length && path && *path) {
|
||||
const char* base = strrchr(path, '/');
|
||||
ffStrbufSetS(name, base ? base + 1 : path);
|
||||
}
|
||||
|
||||
if (!name->length) {
|
||||
ffStrbufSetStatic(name, "Unknown GPU");
|
||||
}
|
||||
}
|
||||
|
||||
static const char* ffDetectCodecByVa(FFCodecOptions* options, FFlist* result) {
|
||||
FF_LIBRARY_LOAD_MESSAGE(libdrm, "libdrm" FF_LIBRARY_EXTENSION, 2)
|
||||
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, drmGetDevices)
|
||||
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, drmFreeDevices)
|
||||
|
||||
FF_LIBRARY_LOAD_MESSAGE(libva, "libva" FF_LIBRARY_EXTENSION, 2)
|
||||
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libva, vaInitialize)
|
||||
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libva, vaTerminate)
|
||||
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libva, vaMaxNumProfiles)
|
||||
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libva, vaMaxNumEntrypoints)
|
||||
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libva, vaQueryConfigProfiles)
|
||||
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libva, vaQueryConfigEntrypoints)
|
||||
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libva, vaGetConfigAttributes)
|
||||
|
||||
FF_LIBRARY_LOAD_MESSAGE(libvaDrm, "libva-drm" FF_LIBRARY_EXTENSION, 2)
|
||||
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libvaDrm, vaGetDisplayDRM)
|
||||
|
||||
drmDevicePtr devices[64];
|
||||
int numDevices = ffdrmGetDevices(devices, ARRAY_SIZE(devices));
|
||||
if (numDevices < 0) {
|
||||
return "drmGetDevices() failed";
|
||||
}
|
||||
if (numDevices == 0) {
|
||||
return "No DRM devices found";
|
||||
}
|
||||
|
||||
const char* error = "No DRM device could initialize VA-API";
|
||||
|
||||
for (int i = 0; i < numDevices; ++i) {
|
||||
drmDevice* dev = devices[i];
|
||||
|
||||
const char* path = NULL;
|
||||
if (dev->available_nodes & (1 << DRM_NODE_RENDER)) {
|
||||
path = dev->nodes[DRM_NODE_RENDER];
|
||||
} else if (dev->available_nodes & (1 << DRM_NODE_PRIMARY)) {
|
||||
path = dev->nodes[DRM_NODE_PRIMARY];
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
|
||||
FF_AUTO_CLOSE_FD int fd = open(path, O_RDWR | O_CLOEXEC);
|
||||
if (fd < 0) {
|
||||
fd = open(path, O_RDONLY | O_CLOEXEC);
|
||||
}
|
||||
if (fd < 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
VADisplay display = ffvaGetDisplayDRM(fd);
|
||||
if (!display) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int major = 0, minor = 0;
|
||||
if (ffvaInitialize(display, &major, &minor) != VA_STATUS_SUCCESS) {
|
||||
continue;
|
||||
}
|
||||
error = NULL;
|
||||
|
||||
int maxProfiles = ffvaMaxNumProfiles(display);
|
||||
int maxEntrypoints = ffvaMaxNumEntrypoints(display);
|
||||
if (maxProfiles <= 0 || maxEntrypoints <= 0) {
|
||||
ffvaTerminate(display);
|
||||
continue;
|
||||
}
|
||||
|
||||
FF_AUTO_FREE VAProfile* profiles = (VAProfile*) malloc(sizeof(VAProfile) * (size_t) maxProfiles);
|
||||
FF_AUTO_FREE VAEntrypoint* entrypoints = (VAEntrypoint*) malloc(sizeof(VAEntrypoint) * (size_t) maxEntrypoints);
|
||||
|
||||
int numProfiles = maxProfiles;
|
||||
if (ffvaQueryConfigProfiles(display, profiles, &numProfiles) != VA_STATUS_SUCCESS) {
|
||||
ffvaTerminate(display);
|
||||
continue;
|
||||
}
|
||||
|
||||
FFCodecType decoderTypes = FF_CODEC_TYPE_NONE;
|
||||
FFCodecType encoderTypes = FF_CODEC_TYPE_NONE;
|
||||
for (int j = 0; j < numProfiles; ++j) {
|
||||
FFCodecType type = ffCodecProfileToType(profiles[j]);
|
||||
|
||||
bool hasDecoder = (options->showType & FF_CODEC_SHOW_TYPE_DECODER) &&
|
||||
!(decoderTypes & type) &&
|
||||
ffCodecProfileHasOutput(
|
||||
display,
|
||||
ffvaQueryConfigEntrypoints,
|
||||
ffvaGetConfigAttributes,
|
||||
maxEntrypoints,
|
||||
entrypoints,
|
||||
profiles[j],
|
||||
FF_CODEC_SHOW_TYPE_DECODER);
|
||||
|
||||
bool hasEncoder = (options->showType & FF_CODEC_SHOW_TYPE_ENCODER) &&
|
||||
!(encoderTypes & type) &&
|
||||
ffCodecProfileHasOutput(
|
||||
display,
|
||||
ffvaQueryConfigEntrypoints,
|
||||
ffvaGetConfigAttributes,
|
||||
maxEntrypoints,
|
||||
entrypoints,
|
||||
profiles[j],
|
||||
FF_CODEC_SHOW_TYPE_ENCODER);
|
||||
|
||||
if (!hasDecoder && !hasEncoder) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (hasDecoder) {
|
||||
decoderTypes |= type;
|
||||
}
|
||||
if (hasEncoder) {
|
||||
encoderTypes |= type;
|
||||
}
|
||||
}
|
||||
|
||||
if (decoderTypes != FF_CODEC_TYPE_NONE || encoderTypes != FF_CODEC_TYPE_NONE) {
|
||||
FFCodecResult* item = FF_LIST_ADD(FFCodecResult, *result);
|
||||
ffCodecFillGpuName(dev, path, &item->gpu);
|
||||
item->decoders = decoderTypes;
|
||||
item->encoders = encoderTypes;
|
||||
item->platformApi = "VA-API";
|
||||
}
|
||||
|
||||
ffvaTerminate(display);
|
||||
}
|
||||
|
||||
ffdrmFreeDevices(devices, numDevices);
|
||||
return error;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if FF_HAVE_VDPAU
|
||||
|
||||
static const struct FFCodecVdpauCodec {
|
||||
VdpDecoderProfile profile;
|
||||
FFCodecType type;
|
||||
} FF_CODEC_VDPAU_CODECS[] = {
|
||||
{ 0, FF_CODEC_TYPE_MPEG1 }, // VDP_DECODER_PROFILE_MPEG1
|
||||
{ 1, FF_CODEC_TYPE_MPEG2 }, // VDP_DECODER_PROFILE_MPEG2_SIMPLE
|
||||
{ 2, FF_CODEC_TYPE_MPEG2 }, // VDP_DECODER_PROFILE_MPEG2_MAIN
|
||||
{ 12, FF_CODEC_TYPE_DIVX_XVID }, // VDP_DECODER_PROFILE_MPEG4_PART2_SP
|
||||
{ 13, FF_CODEC_TYPE_DIVX_XVID }, // VDP_DECODER_PROFILE_MPEG4_PART2_ASP
|
||||
{ 14, FF_CODEC_TYPE_DIVX_XVID }, // VDP_DECODER_PROFILE_DIVX4_QMOBILE
|
||||
{ 15, FF_CODEC_TYPE_DIVX_XVID }, // VDP_DECODER_PROFILE_DIVX4_MOBILE
|
||||
{ 16, FF_CODEC_TYPE_DIVX_XVID }, // VDP_DECODER_PROFILE_DIVX4_HOME_THEATER
|
||||
{ 17, FF_CODEC_TYPE_DIVX_XVID }, // VDP_DECODER_PROFILE_DIVX4_HD_1080P
|
||||
{ 18, FF_CODEC_TYPE_DIVX_XVID }, // VDP_DECODER_PROFILE_DIVX5_QMOBILE
|
||||
{ 19, FF_CODEC_TYPE_DIVX_XVID }, // VDP_DECODER_PROFILE_DIVX5_MOBILE
|
||||
{ 20, FF_CODEC_TYPE_DIVX_XVID }, // VDP_DECODER_PROFILE_DIVX5_HOME_THEATER
|
||||
{ 21, FF_CODEC_TYPE_DIVX_XVID }, // VDP_DECODER_PROFILE_DIVX5_HD_1080P
|
||||
{ 6, FF_CODEC_TYPE_H264 }, // VDP_DECODER_PROFILE_H264_BASELINE
|
||||
{ 7, FF_CODEC_TYPE_H264 }, // VDP_DECODER_PROFILE_H264_MAIN
|
||||
{ 8, FF_CODEC_TYPE_H264 }, // VDP_DECODER_PROFILE_H264_HIGH
|
||||
{ 22, FF_CODEC_TYPE_H264 }, // VDP_DECODER_PROFILE_H264_CONSTRAINED_BASELINE
|
||||
{ 23, FF_CODEC_TYPE_H264 }, // VDP_DECODER_PROFILE_H264_EXTENDED
|
||||
{ 24, FF_CODEC_TYPE_H264 }, // VDP_DECODER_PROFILE_H264_PROGRESSIVE_HIGH
|
||||
{ 25, FF_CODEC_TYPE_H264 }, // VDP_DECODER_PROFILE_H264_CONSTRAINED_HIGH
|
||||
{ 26, FF_CODEC_TYPE_H264 }, // VDP_DECODER_PROFILE_H264_HIGH_444_PREDICTIVE
|
||||
{ 9, FF_CODEC_TYPE_VC1 }, // VDP_DECODER_PROFILE_VC1_SIMPLE
|
||||
{ 10, FF_CODEC_TYPE_VC1 }, // VDP_DECODER_PROFILE_VC1_MAIN
|
||||
{ 11, FF_CODEC_TYPE_VC1 }, // VDP_DECODER_PROFILE_VC1_ADVANCED
|
||||
{ 100, FF_CODEC_TYPE_HEVC }, // VDP_DECODER_PROFILE_HEVC_MAIN
|
||||
{ 101, FF_CODEC_TYPE_HEVC }, // VDP_DECODER_PROFILE_HEVC_MAIN_10
|
||||
{ 102, FF_CODEC_TYPE_HEVC }, // VDP_DECODER_PROFILE_HEVC_MAIN_STILL
|
||||
{ 103, FF_CODEC_TYPE_HEVC }, // VDP_DECODER_PROFILE_HEVC_MAIN_12
|
||||
{ 104, FF_CODEC_TYPE_HEVC }, // VDP_DECODER_PROFILE_HEVC_MAIN_444
|
||||
{ 105, FF_CODEC_TYPE_HEVC }, // VDP_DECODER_PROFILE_HEVC_MAIN_444_10
|
||||
{ 106, FF_CODEC_TYPE_HEVC }, // VDP_DECODER_PROFILE_HEVC_MAIN_444_12
|
||||
{ 27, FF_CODEC_TYPE_VP9 }, // VDP_DECODER_PROFILE_VP9_PROFILE_0
|
||||
{ 28, FF_CODEC_TYPE_VP9 }, // VDP_DECODER_PROFILE_VP9_PROFILE_1
|
||||
{ 29, FF_CODEC_TYPE_VP9 }, // VDP_DECODER_PROFILE_VP9_PROFILE_2
|
||||
{ 30, FF_CODEC_TYPE_VP9 }, // VDP_DECODER_PROFILE_VP9_PROFILE_3
|
||||
{ 107, FF_CODEC_TYPE_AV1 }, // VDP_DECODER_PROFILE_AV1_MAIN
|
||||
{ 108, FF_CODEC_TYPE_AV1 }, // VDP_DECODER_PROFILE_AV1_HIGH
|
||||
{ 109, FF_CODEC_TYPE_AV1 }, // VDP_DECODER_PROFILE_AV1_PROFESSIONAL
|
||||
};
|
||||
|
||||
static const char* ffDetectCodecByVdpau(FFCodecOptions* options, FFlist* result) {
|
||||
if (options->showType == FF_CODEC_SHOW_TYPE_DECODER) {
|
||||
return "VDPAU only supports decoding";
|
||||
}
|
||||
|
||||
FF_LIBRARY_LOAD_MESSAGE(libX11, "libX11" FF_LIBRARY_EXTENSION, 6)
|
||||
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libX11, XOpenDisplay)
|
||||
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libX11, XCloseDisplay)
|
||||
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libX11, XDefaultScreen)
|
||||
|
||||
FF_LIBRARY_LOAD_MESSAGE(libvdpau, "libvdpau" FF_LIBRARY_EXTENSION, 1)
|
||||
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libvdpau, vdp_device_create_x11)
|
||||
|
||||
void* x11Display = ffXOpenDisplay(NULL);
|
||||
if (!x11Display) {
|
||||
return "XOpenDisplay() failed";
|
||||
}
|
||||
|
||||
VdpDevice device = VDP_INVALID_HANDLE;
|
||||
VdpGetProcAddress* ffvdp_get_proc_address = NULL;
|
||||
if (ffvdp_device_create_x11(x11Display, ffXDefaultScreen(x11Display), &device, &ffvdp_get_proc_address) != VDP_STATUS_OK ||
|
||||
device == VDP_INVALID_HANDLE ||
|
||||
ffvdp_get_proc_address == NULL) {
|
||||
ffXCloseDisplay(x11Display);
|
||||
return "vdp_device_create_x11() failed";
|
||||
}
|
||||
|
||||
VdpDeviceDestroy* ffvdp_device_destroy = NULL;
|
||||
VdpDecoderQueryCapabilities* ffvdp_decoder_query_capabilities = NULL;
|
||||
if (ffvdp_get_proc_address(device, VDP_FUNC_ID_DEVICE_DESTROY, (void**) &ffvdp_device_destroy) != VDP_STATUS_OK ||
|
||||
ffvdp_get_proc_address(device, VDP_FUNC_ID_DECODER_QUERY_CAPABILITIES, (void**) &ffvdp_decoder_query_capabilities) != VDP_STATUS_OK ||
|
||||
ffvdp_device_destroy == NULL ||
|
||||
ffvdp_decoder_query_capabilities == NULL) {
|
||||
if (ffvdp_device_destroy) {
|
||||
ffvdp_device_destroy(device);
|
||||
}
|
||||
ffXCloseDisplay(x11Display);
|
||||
return "ffvdp_get_proc_address() failed";
|
||||
}
|
||||
|
||||
FFCodecType decoderTypes = FF_CODEC_TYPE_NONE;
|
||||
|
||||
for (uint32_t i = 0; i < ARRAY_SIZE(FF_CODEC_VDPAU_CODECS); ++i) {
|
||||
const struct FFCodecVdpauCodec* codec = &FF_CODEC_VDPAU_CODECS[i];
|
||||
if (decoderTypes & codec->type) {
|
||||
continue;
|
||||
}
|
||||
VdpBool isSupported = VDP_FALSE;
|
||||
uint32_t maxLevel = 0, maxMacroblocks = 0, maxWidth = 0, maxHeight = 0;
|
||||
if (ffvdp_decoder_query_capabilities(device, codec->profile, &isSupported, &maxLevel, &maxMacroblocks, &maxWidth, &maxHeight) != VDP_STATUS_OK ||
|
||||
!isSupported) {
|
||||
continue;
|
||||
}
|
||||
|
||||
decoderTypes |= codec->type;
|
||||
}
|
||||
|
||||
ffvdp_device_destroy(device);
|
||||
ffXCloseDisplay(x11Display);
|
||||
|
||||
if (decoderTypes == FF_CODEC_TYPE_NONE) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
FFCodecResult* item = FF_LIST_ADD(FFCodecResult, *result);
|
||||
ffStrbufInit(&item->gpu);
|
||||
const char* driver = getenv("VDPAU_DRIVER");
|
||||
if (driver && *driver) {
|
||||
ffStrbufSetS(&item->gpu, driver);
|
||||
} else {
|
||||
ffStrbufSetStatic(&item->gpu, "Default");
|
||||
}
|
||||
item->decoders = decoderTypes;
|
||||
item->encoders = FF_CODEC_TYPE_NONE;
|
||||
item->platformApi = "VDPAU";
|
||||
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
const char* ffDetectCodecNative(FFCodecOptions* options, FFlist* result /* list of FFCodecResult */) {
|
||||
FF_SUPPRESS_IO();
|
||||
|
||||
#if FF_HAVE_DRM && FF_HAVE_VA
|
||||
if (ffDetectCodecByVa(options, result) == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
#if FF_HAVE_VDPAU
|
||||
if (ffDetectCodecByVdpau(options, result) == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
return "Both libva and libvdpau fail to initialize";
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
const char* ffDetectCodecNative(FFCodecOptions* options, FFlist* result /* list of FFCodecResult */) {
|
||||
FF_UNUSED(options, result);
|
||||
return "Fastfetch was built without DRM / VA-API / VDPAU headers";
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,270 @@
|
||||
#include "codec.h"
|
||||
|
||||
#ifdef FF_HAVE_VULKAN
|
||||
#include <vulkan/vulkan.h>
|
||||
#include "common/strutil.h"
|
||||
|
||||
#if VK_KHR_video_decode_queue && VK_KHR_video_encode_queue
|
||||
|
||||
#include "common/debug.h"
|
||||
#include "common/io.h"
|
||||
#include "common/library.h"
|
||||
#include "common/mallocHelper.h"
|
||||
|
||||
static FFCodecType ffCodecDecodeOperationsToTypes(VkVideoCodecOperationFlagsKHR operations) {
|
||||
FFCodecType types = FF_CODEC_TYPE_NONE;
|
||||
|
||||
if (operations & 0x00000001 /*VK_VIDEO_CODEC_OPERATION_DECODE_H264_BIT_KHR*/) {
|
||||
types |= FF_CODEC_TYPE_H264;
|
||||
}
|
||||
if (operations & 0x00000002 /*VK_VIDEO_CODEC_OPERATION_DECODE_H265_BIT_KHR*/) {
|
||||
types |= FF_CODEC_TYPE_HEVC;
|
||||
}
|
||||
if (operations & 0x00000004 /*VK_VIDEO_CODEC_OPERATION_DECODE_AV1_BIT_KHR*/) {
|
||||
types |= FF_CODEC_TYPE_AV1;
|
||||
}
|
||||
if (operations & 0x00000008 /*VK_VIDEO_CODEC_OPERATION_DECODE_VP9_BIT_KHR*/) {
|
||||
types |= FF_CODEC_TYPE_VP9;
|
||||
}
|
||||
|
||||
return types;
|
||||
}
|
||||
|
||||
static FFCodecType ffCodecEncodeOperationsToTypes(VkVideoCodecOperationFlagsKHR operations) {
|
||||
FFCodecType types = FF_CODEC_TYPE_NONE;
|
||||
|
||||
if (operations & 0x00010000 /*VK_VIDEO_CODEC_OPERATION_ENCODE_H264_BIT_KHR*/) {
|
||||
types |= FF_CODEC_TYPE_H264;
|
||||
}
|
||||
if (operations & 0x00020000 /*VK_VIDEO_CODEC_OPERATION_ENCODE_H265_BIT_KHR*/) {
|
||||
types |= FF_CODEC_TYPE_HEVC;
|
||||
}
|
||||
if (operations & 0x00040000 /*VK_VIDEO_CODEC_OPERATION_ENCODE_AV1_BIT_KHR*/) {
|
||||
types |= FF_CODEC_TYPE_AV1;
|
||||
}
|
||||
|
||||
return types;
|
||||
}
|
||||
|
||||
static bool ffCodecHasDeviceExtension(const VkExtensionProperties* extensions, uint32_t extensionCount, const char* extensionName) {
|
||||
for (uint32_t i = 0; i < extensionCount; ++i) {
|
||||
if (ffStrEquals(extensions[i].extensionName, extensionName)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
const char* ffDetectCodecVulkan(FFCodecOptions* options, FFlist* result /*list of FFCodecResult*/) {
|
||||
FF_DEBUG("Starting Vulkan codec detection");
|
||||
|
||||
FF_LIBRARY_LOAD_MESSAGE(vulkan,
|
||||
#if __APPLE__
|
||||
"libMoltenVK" FF_LIBRARY_EXTENSION,
|
||||
-1
|
||||
#elif _WIN32
|
||||
"vulkan-1" FF_LIBRARY_EXTENSION,
|
||||
-1
|
||||
#else
|
||||
"libvulkan" FF_LIBRARY_EXTENSION,
|
||||
2
|
||||
#endif
|
||||
)
|
||||
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(vulkan, vkGetInstanceProcAddr)
|
||||
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(vulkan, vkCreateInstance)
|
||||
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(vulkan, vkDestroyInstance)
|
||||
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(vulkan, vkEnumeratePhysicalDevices)
|
||||
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(vulkan, vkEnumerateDeviceExtensionProperties)
|
||||
|
||||
FF_SUPPRESS_IO();
|
||||
|
||||
uint32_t apiVersion = VK_API_VERSION_1_0;
|
||||
PFN_vkEnumerateInstanceVersion ffvkEnumerateInstanceVersion = (PFN_vkEnumerateInstanceVersion) ffvkGetInstanceProcAddr(NULL, "vkEnumerateInstanceVersion");
|
||||
if (ffvkEnumerateInstanceVersion != NULL) {
|
||||
uint32_t detectedApiVersion = 0;
|
||||
if (ffvkEnumerateInstanceVersion(&detectedApiVersion) == VK_SUCCESS) {
|
||||
apiVersion = detectedApiVersion;
|
||||
}
|
||||
}
|
||||
|
||||
const uint32_t projectVersion = VK_MAKE_VERSION(
|
||||
FASTFETCH_PROJECT_VERSION_MAJOR,
|
||||
FASTFETCH_PROJECT_VERSION_MINOR,
|
||||
FASTFETCH_PROJECT_VERSION_PATCH);
|
||||
|
||||
VkInstance vkInstance = VK_NULL_HANDLE;
|
||||
VkResult res = ffvkCreateInstance(&(VkInstanceCreateInfo){
|
||||
.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
|
||||
.pApplicationInfo = &(VkApplicationInfo){
|
||||
.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
|
||||
.pApplicationName = FASTFETCH_PROJECT_NAME,
|
||||
.applicationVersion = projectVersion,
|
||||
.pEngineName = "fastfetch-codec-vulkan",
|
||||
.engineVersion = projectVersion,
|
||||
.apiVersion = apiVersion,
|
||||
},
|
||||
},
|
||||
NULL,
|
||||
&vkInstance);
|
||||
if (res != VK_SUCCESS) {
|
||||
FF_DEBUG("ffvkCreateInstance() failed with VkResult=%d", res);
|
||||
switch (res) {
|
||||
case VK_ERROR_OUT_OF_HOST_MEMORY:
|
||||
return "ffvkCreateInstance() failed: VK_ERROR_OUT_OF_HOST_MEMORY";
|
||||
case VK_ERROR_OUT_OF_DEVICE_MEMORY:
|
||||
return "ffvkCreateInstance() failed: VK_ERROR_OUT_OF_DEVICE_MEMORY";
|
||||
case VK_ERROR_INITIALIZATION_FAILED:
|
||||
return "ffvkCreateInstance() failed: VK_ERROR_INITIALIZATION_FAILED";
|
||||
case VK_ERROR_LAYER_NOT_PRESENT:
|
||||
return "ffvkCreateInstance() failed: VK_ERROR_LAYER_NOT_PRESENT";
|
||||
case VK_ERROR_EXTENSION_NOT_PRESENT:
|
||||
return "ffvkCreateInstance() failed: VK_ERROR_EXTENSION_NOT_PRESENT";
|
||||
case VK_ERROR_INCOMPATIBLE_DRIVER:
|
||||
return "ffvkCreateInstance() failed: VK_ERROR_INCOMPATIBLE_DRIVER";
|
||||
default:
|
||||
return "ffvkCreateInstance() failed: unknown error";
|
||||
}
|
||||
}
|
||||
|
||||
PFN_vkGetPhysicalDeviceProperties ffvkGetPhysicalDeviceProperties = (PFN_vkGetPhysicalDeviceProperties) ffvkGetInstanceProcAddr(vkInstance, "vkGetPhysicalDeviceProperties");
|
||||
if (!ffvkGetPhysicalDeviceProperties) {
|
||||
ffvkDestroyInstance(vkInstance, NULL);
|
||||
return "vkGetPhysicalDeviceProperties is not available";
|
||||
}
|
||||
|
||||
PFN_vkGetPhysicalDeviceQueueFamilyProperties2 ffvkGetPhysicalDeviceQueueFamilyProperties2 = (PFN_vkGetPhysicalDeviceQueueFamilyProperties2) ffvkGetInstanceProcAddr(vkInstance, "vkGetPhysicalDeviceQueueFamilyProperties2");
|
||||
if (!ffvkGetPhysicalDeviceQueueFamilyProperties2) {
|
||||
ffvkDestroyInstance(vkInstance, NULL);
|
||||
return "vkGetPhysicalDeviceQueueFamilyProperties2 is not available";
|
||||
}
|
||||
|
||||
uint32_t physicalDeviceCount = 0;
|
||||
res = ffvkEnumeratePhysicalDevices(vkInstance, &physicalDeviceCount, NULL);
|
||||
if (res != VK_SUCCESS) {
|
||||
FF_DEBUG("ffvkEnumeratePhysicalDevices(count) failed with VkResult=%d", res);
|
||||
ffvkDestroyInstance(vkInstance, NULL);
|
||||
return "ffvkEnumeratePhysicalDevices() failed during Vulkan codec detection";
|
||||
}
|
||||
if (physicalDeviceCount == 0) {
|
||||
ffvkDestroyInstance(vkInstance, NULL);
|
||||
return "No Vulkan physical devices found";
|
||||
}
|
||||
|
||||
FF_AUTO_FREE VkPhysicalDevice* physicalDevices = (VkPhysicalDevice*) malloc(sizeof(VkPhysicalDevice) * (size_t) physicalDeviceCount);
|
||||
|
||||
res = ffvkEnumeratePhysicalDevices(vkInstance, &physicalDeviceCount, physicalDevices);
|
||||
if (res != VK_SUCCESS) {
|
||||
FF_DEBUG("ffvkEnumeratePhysicalDevices(list) failed with VkResult=%d", res);
|
||||
ffvkDestroyInstance(vkInstance, NULL);
|
||||
return "ffvkEnumeratePhysicalDevices() failed during Vulkan codec detection";
|
||||
}
|
||||
|
||||
bool sawVideoQueueExtension = false;
|
||||
|
||||
for (uint32_t i = 0; i < physicalDeviceCount; ++i) {
|
||||
VkPhysicalDeviceProperties properties = {};
|
||||
ffvkGetPhysicalDeviceProperties(physicalDevices[i], &properties);
|
||||
|
||||
uint32_t extensionCount = 0;
|
||||
res = ffvkEnumerateDeviceExtensionProperties(physicalDevices[i], NULL, &extensionCount, NULL);
|
||||
if (res != VK_SUCCESS) {
|
||||
FF_DEBUG("vkEnumerateDeviceExtensionProperties(count) failed for '%s' with VkResult=%d", properties.deviceName, res);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (extensionCount == 0) {
|
||||
FF_DEBUG("Skipping Vulkan device '%s' because it has no extensions", properties.deviceName);
|
||||
continue;
|
||||
}
|
||||
|
||||
FF_AUTO_FREE VkExtensionProperties* extensions = (VkExtensionProperties*) malloc(sizeof(VkExtensionProperties) * (size_t) extensionCount);
|
||||
|
||||
res = ffvkEnumerateDeviceExtensionProperties(physicalDevices[i], NULL, &extensionCount, extensions);
|
||||
if (res != VK_SUCCESS) {
|
||||
FF_DEBUG("vkEnumerateDeviceExtensionProperties(list) failed for '%s' with VkResult=%d", properties.deviceName, res);
|
||||
continue;
|
||||
}
|
||||
|
||||
bool hasVideoDecode = (options->showType & FF_CODEC_SHOW_TYPE_DECODER) &&
|
||||
ffCodecHasDeviceExtension(extensions, extensionCount, VK_KHR_VIDEO_DECODE_QUEUE_EXTENSION_NAME);
|
||||
bool hasVideoEncode = (options->showType & FF_CODEC_SHOW_TYPE_ENCODER) &&
|
||||
ffCodecHasDeviceExtension(extensions, extensionCount, VK_KHR_VIDEO_ENCODE_QUEUE_EXTENSION_NAME);
|
||||
|
||||
if (!hasVideoDecode && !hasVideoEncode) {
|
||||
FF_DEBUG("Skipping Vulkan device '%s' because it does not support video queue extensions", properties.deviceName);
|
||||
continue;
|
||||
}
|
||||
sawVideoQueueExtension = true;
|
||||
|
||||
uint32_t queueFamilyCount = 0;
|
||||
ffvkGetPhysicalDeviceQueueFamilyProperties2(physicalDevices[i], &queueFamilyCount, NULL);
|
||||
if (queueFamilyCount == 0) {
|
||||
FF_DEBUG("Skipping Vulkan device '%s' because it has no queue families", properties.deviceName);
|
||||
continue;
|
||||
}
|
||||
|
||||
FF_AUTO_FREE VkQueueFamilyProperties2* queueFamilyProperties = (VkQueueFamilyProperties2*) malloc(sizeof(VkQueueFamilyProperties2) * (size_t) queueFamilyCount);
|
||||
FF_AUTO_FREE VkQueueFamilyVideoPropertiesKHR* queueFamilyVideoProperties = (VkQueueFamilyVideoPropertiesKHR*) malloc(sizeof(VkQueueFamilyVideoPropertiesKHR) * (size_t) queueFamilyCount);
|
||||
|
||||
for (uint32_t queueIndex = 0; queueIndex < queueFamilyCount; ++queueIndex) {
|
||||
queueFamilyVideoProperties[queueIndex] = (VkQueueFamilyVideoPropertiesKHR){
|
||||
.sType = VK_STRUCTURE_TYPE_QUEUE_FAMILY_VIDEO_PROPERTIES_KHR,
|
||||
};
|
||||
queueFamilyProperties[queueIndex] = (VkQueueFamilyProperties2){
|
||||
.sType = VK_STRUCTURE_TYPE_QUEUE_FAMILY_PROPERTIES_2,
|
||||
.pNext = &queueFamilyVideoProperties[queueIndex],
|
||||
};
|
||||
}
|
||||
|
||||
ffvkGetPhysicalDeviceQueueFamilyProperties2(physicalDevices[i], &queueFamilyCount, queueFamilyProperties);
|
||||
|
||||
FFCodecType decoders = FF_CODEC_TYPE_NONE;
|
||||
FFCodecType encoders = FF_CODEC_TYPE_NONE;
|
||||
|
||||
for (uint32_t queueIndex = 0; queueIndex < queueFamilyCount; ++queueIndex) {
|
||||
const VkQueueFlags queueFlags = queueFamilyProperties[queueIndex].queueFamilyProperties.queueFlags;
|
||||
const VkVideoCodecOperationFlagsKHR operations = queueFamilyVideoProperties[queueIndex].videoCodecOperations;
|
||||
|
||||
if (hasVideoDecode && (queueFlags & VK_QUEUE_VIDEO_DECODE_BIT_KHR)) {
|
||||
decoders |= ffCodecDecodeOperationsToTypes(operations);
|
||||
}
|
||||
|
||||
if (hasVideoEncode && (queueFlags & VK_QUEUE_VIDEO_ENCODE_BIT_KHR)) {
|
||||
encoders |= ffCodecEncodeOperationsToTypes(operations);
|
||||
}
|
||||
}
|
||||
|
||||
if (decoders == FF_CODEC_TYPE_NONE && encoders == FF_CODEC_TYPE_NONE) {
|
||||
FF_DEBUG("Skipping Vulkan device '%s' because no supported codec operations were reported", properties.deviceName);
|
||||
continue;
|
||||
}
|
||||
|
||||
FFCodecResult* item = FF_LIST_ADD(FFCodecResult, *result);
|
||||
ffStrbufInitS(&item->gpu, properties.deviceName);
|
||||
item->decoders = decoders;
|
||||
item->encoders = encoders;
|
||||
item->platformApi = "Vulkan Video";
|
||||
FF_DEBUG("Added Vulkan codec result for '%s': decoders=%u encoders=%u", properties.deviceName, (unsigned) decoders, (unsigned) encoders);
|
||||
}
|
||||
|
||||
ffvkDestroyInstance(vkInstance, NULL);
|
||||
|
||||
if (result->length > 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return sawVideoQueueExtension ? "No supported Vulkan video codec operations found"
|
||||
: "VK_KHR_video_queue is not supported by any Vulkan physical device";
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
const char* ffDetectCodecVulkan(FFCodecOptions* options, FFlist* result) {
|
||||
FF_UNUSED(options, result);
|
||||
return "Vulkan video queue extensions are not supported by this Vulkan implementation";
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,553 @@
|
||||
extern "C" {
|
||||
#include "codec.h"
|
||||
#include "common/library.h"
|
||||
#include "common/windows/com.h"
|
||||
#include "common/windows/unicode.h"
|
||||
#include "common/windows/nt.h"
|
||||
}
|
||||
|
||||
#include <d3d11.h>
|
||||
#include <d3d12.h>
|
||||
#include <dxgi.h>
|
||||
#include <initguid.h>
|
||||
#include <dxva.h>
|
||||
#include <d3d12video.h>
|
||||
#include <mfapi.h>
|
||||
|
||||
typedef struct D3D12_FEATURE_DATA_VIDEO_ENCODER_CODEC {
|
||||
UINT NodeIndex;
|
||||
D3D12_VIDEO_ENCODER_CODEC Codec;
|
||||
BOOL IsSupported;
|
||||
} D3D12_FEATURE_DATA_VIDEO_ENCODER_CODEC;
|
||||
|
||||
HRESULT MFTEnum2(
|
||||
_In_ GUID guidCategory,
|
||||
_In_ UINT32 Flags,
|
||||
_In_ const MFT_REGISTER_TYPE_INFO* pInputType,
|
||||
_In_ const MFT_REGISTER_TYPE_INFO* pOutputType,
|
||||
_In_opt_ IMFAttributes* pAttributes,
|
||||
_Out_ IMFActivate*** pppMFTActivate,
|
||||
_Out_ UINT32* pnumMFTActivate);
|
||||
|
||||
// clang-format off
|
||||
#ifndef MFT_ENUM_ADAPTER_LUID
|
||||
// {1D39518C-E220-4DA8-A07F-BA172552D6B1}
|
||||
DEFINE_GUID(MFT_ENUM_ADAPTER_LUID,
|
||||
0x1d39518c, 0xe220, 0x4da8, 0xa0, 0x7f, 0xba, 0x17, 0x25, 0x52, 0xd6, 0xb1);
|
||||
#endif
|
||||
// clang-format on
|
||||
|
||||
static const DXGI_FORMAT FF_NATIVE_CODEC_FORMATS[] = {
|
||||
DXGI_FORMAT_420_OPAQUE,
|
||||
DXGI_FORMAT_NV12,
|
||||
DXGI_FORMAT_P010,
|
||||
DXGI_FORMAT_P016,
|
||||
DXGI_FORMAT_YUY2,
|
||||
DXGI_FORMAT_Y210,
|
||||
DXGI_FORMAT_Y216,
|
||||
DXGI_FORMAT_AYUV,
|
||||
DXGI_FORMAT_Y410,
|
||||
DXGI_FORMAT_Y416,
|
||||
};
|
||||
|
||||
static FFCodecType ffCodecProfileToTypeDx11(const GUID& profile) {
|
||||
// clang-format off
|
||||
if (IsEqualGUID(profile, DXVA_ModeH261_A) ||
|
||||
IsEqualGUID(profile, DXVA_ModeH261_B)) {
|
||||
return FF_CODEC_TYPE_H261;
|
||||
}
|
||||
|
||||
if (IsEqualGUID(profile, DXVA_ModeH263_A) ||
|
||||
IsEqualGUID(profile, DXVA_ModeH263_B) ||
|
||||
IsEqualGUID(profile, DXVA_ModeH263_C) ||
|
||||
IsEqualGUID(profile, DXVA_ModeH263_D) ||
|
||||
IsEqualGUID(profile, DXVA_ModeH263_E) ||
|
||||
IsEqualGUID(profile, DXVA_ModeH263_F)) {
|
||||
return FF_CODEC_TYPE_H263;
|
||||
}
|
||||
|
||||
if (IsEqualGUID(profile, DXVA_ModeMJPEG_VLD_420) ||
|
||||
IsEqualGUID(profile, DXVA_ModeMJPEG_VLD_422) ||
|
||||
IsEqualGUID(profile, DXVA_ModeMJPEG_VLD_444) ||
|
||||
IsEqualGUID(profile, DXVA_ModeMJPEG_VLD_4444) ||
|
||||
IsEqualGUID(profile, DXVA_ModeJPEG_VLD_420) ||
|
||||
IsEqualGUID(profile, DXVA_ModeJPEG_VLD_422) ||
|
||||
IsEqualGUID(profile, DXVA_ModeJPEG_VLD_444)) {
|
||||
return FF_CODEC_TYPE_MJPEG;
|
||||
}
|
||||
|
||||
if (IsEqualGUID(profile, DXVA_ModeMPEG1_A) ||
|
||||
IsEqualGUID(profile, DXVA_ModeMPEG1_VLD)) {
|
||||
return FF_CODEC_TYPE_MPEG1;
|
||||
}
|
||||
|
||||
if (IsEqualGUID(profile, DXVA_ModeMPEG2_A) ||
|
||||
IsEqualGUID(profile, DXVA_ModeMPEG2_B) ||
|
||||
IsEqualGUID(profile, DXVA_ModeMPEG2_C) ||
|
||||
IsEqualGUID(profile, DXVA_ModeMPEG2_D) ||
|
||||
IsEqualGUID(profile, DXVA_ModeMPEG2and1_VLD)) {
|
||||
return FF_CODEC_TYPE_MPEG2;
|
||||
}
|
||||
|
||||
if (IsEqualGUID(profile, DXVA_ModeMPEG4pt2_VLD_Simple) ||
|
||||
IsEqualGUID(profile, DXVA_ModeMPEG4pt2_VLD_AdvSimple_NoGMC) ||
|
||||
IsEqualGUID(profile, DXVA_ModeMPEG4pt2_VLD_AdvSimple_GMC)) {
|
||||
return FF_CODEC_TYPE_DIVX_XVID;
|
||||
}
|
||||
|
||||
if (IsEqualGUID(profile, DXVA_ModeH264_E) ||
|
||||
IsEqualGUID(profile, DXVA_ModeH264_F) ||
|
||||
IsEqualGUID(profile, DXVA_ModeH264_VLD_WithFMOASO_NoFGT) ||
|
||||
IsEqualGUID(profile, DXVA_ModeH264_VLD_Stereo_Progressive_NoFGT) ||
|
||||
IsEqualGUID(profile, DXVA_ModeH264_VLD_Stereo_NoFGT) ||
|
||||
IsEqualGUID(profile, DXVA_ModeH264_VLD_Multiview_NoFGT)) {
|
||||
return FF_CODEC_TYPE_H264;
|
||||
}
|
||||
|
||||
if (IsEqualGUID(profile, DXVA_ModeWMV8_A) ||
|
||||
IsEqualGUID(profile, DXVA_ModeWMV8_B)) {
|
||||
return FF_CODEC_TYPE_WMV8;
|
||||
}
|
||||
|
||||
if (IsEqualGUID(profile, DXVA_ModeWMV9_A) ||
|
||||
IsEqualGUID(profile, DXVA_ModeWMV9_B) ||
|
||||
IsEqualGUID(profile, DXVA_ModeWMV9_C)) {
|
||||
return FF_CODEC_TYPE_WMV9;
|
||||
}
|
||||
|
||||
if (IsEqualGUID(profile, DXVA_ModeVC1_A) ||
|
||||
IsEqualGUID(profile, DXVA_ModeVC1_B) ||
|
||||
IsEqualGUID(profile, DXVA_ModeVC1_C) ||
|
||||
IsEqualGUID(profile, DXVA_ModeVC1_D) ||
|
||||
IsEqualGUID(profile, DXVA_ModeVC1_D2010)) {
|
||||
return FF_CODEC_TYPE_VC1;
|
||||
}
|
||||
|
||||
if (IsEqualGUID(profile, DXVA_ModeVP8_VLD)) {
|
||||
return FF_CODEC_TYPE_VP8;
|
||||
}
|
||||
|
||||
if (IsEqualGUID(profile, DXVA_ModeHEVC_VLD_Main) ||
|
||||
IsEqualGUID(profile, DXVA_ModeHEVC_VLD_Main10) ||
|
||||
IsEqualGUID(profile, DXVA_ModeHEVC_VLD_Main12) ||
|
||||
IsEqualGUID(profile, DXVA_ModeHEVC_VLD_Main10_422) ||
|
||||
IsEqualGUID(profile, DXVA_ModeHEVC_VLD_Main12_422) ||
|
||||
IsEqualGUID(profile, DXVA_ModeHEVC_VLD_Main_444) ||
|
||||
IsEqualGUID(profile, DXVA_ModeHEVC_VLD_Main10_Ext) ||
|
||||
IsEqualGUID(profile, DXVA_ModeHEVC_VLD_Main10_444) ||
|
||||
IsEqualGUID(profile, DXVA_ModeHEVC_VLD_Main12_444) ||
|
||||
IsEqualGUID(profile, DXVA_ModeHEVC_VLD_Main16)) {
|
||||
return FF_CODEC_TYPE_HEVC;
|
||||
}
|
||||
|
||||
if (IsEqualGUID(profile, DXVA_ModeVP9_VLD_Profile0) ||
|
||||
IsEqualGUID(profile, DXVA_ModeVP9_VLD_10bit_Profile2)) {
|
||||
return FF_CODEC_TYPE_VP9;
|
||||
}
|
||||
|
||||
if (IsEqualGUID(profile, DXVA_ModeAV1_VLD_Profile0) ||
|
||||
IsEqualGUID(profile, DXVA_ModeAV1_VLD_Profile1) ||
|
||||
IsEqualGUID(profile, DXVA_ModeAV1_VLD_Profile2) ||
|
||||
IsEqualGUID(profile, DXVA_ModeAV1_VLD_12bit_Profile2) ||
|
||||
IsEqualGUID(profile, DXVA_ModeAV1_VLD_12bit_Profile2_420)) {
|
||||
return FF_CODEC_TYPE_AV1;
|
||||
}
|
||||
// clang-format on
|
||||
|
||||
return FF_CODEC_TYPE_UNKNOWN;
|
||||
}
|
||||
|
||||
static FFCodecType ffCodecProfileToTypeDx12(const GUID& profile) {
|
||||
// clang-format off
|
||||
if (IsEqualGUID(profile, D3D12_VIDEO_DECODE_PROFILE_MPEG1_AND_MPEG2)) {
|
||||
return FFCodecType(FF_CODEC_TYPE_MPEG1 | FF_CODEC_TYPE_MPEG2);
|
||||
}
|
||||
|
||||
if (IsEqualGUID(profile, D3D12_VIDEO_DECODE_PROFILE_MPEG2)) {
|
||||
return FF_CODEC_TYPE_MPEG2;
|
||||
}
|
||||
|
||||
if (IsEqualGUID(profile, D3D12_VIDEO_DECODE_PROFILE_MPEG4PT2_SIMPLE) ||
|
||||
IsEqualGUID(profile, D3D12_VIDEO_DECODE_PROFILE_MPEG4PT2_ADVSIMPLE_NOGMC)) {
|
||||
return FF_CODEC_TYPE_DIVX_XVID;
|
||||
}
|
||||
|
||||
if (IsEqualGUID(profile, D3D12_VIDEO_DECODE_PROFILE_H264) ||
|
||||
IsEqualGUID(profile, D3D12_VIDEO_DECODE_PROFILE_H264_STEREO_PROGRESSIVE) ||
|
||||
IsEqualGUID(profile, D3D12_VIDEO_DECODE_PROFILE_H264_STEREO) ||
|
||||
IsEqualGUID(profile, D3D12_VIDEO_DECODE_PROFILE_H264_MULTIVIEW)) {
|
||||
return FF_CODEC_TYPE_H264;
|
||||
}
|
||||
|
||||
if (IsEqualGUID(profile, D3D12_VIDEO_DECODE_PROFILE_VC1) ||
|
||||
IsEqualGUID(profile, D3D12_VIDEO_DECODE_PROFILE_VC1_D2010)) {
|
||||
return FF_CODEC_TYPE_VC1;
|
||||
}
|
||||
|
||||
if (IsEqualGUID(profile, D3D12_VIDEO_DECODE_PROFILE_VP8)) {
|
||||
return FF_CODEC_TYPE_VP8;
|
||||
}
|
||||
|
||||
if (IsEqualGUID(profile, D3D12_VIDEO_DECODE_PROFILE_HEVC_MAIN) ||
|
||||
IsEqualGUID(profile, D3D12_VIDEO_DECODE_PROFILE_HEVC_MAIN10)) {
|
||||
return FF_CODEC_TYPE_HEVC;
|
||||
}
|
||||
|
||||
if (IsEqualGUID(profile, D3D12_VIDEO_DECODE_PROFILE_VP9) ||
|
||||
IsEqualGUID(profile, D3D12_VIDEO_DECODE_PROFILE_VP9_10BIT_PROFILE2)) {
|
||||
return FF_CODEC_TYPE_VP9;
|
||||
}
|
||||
|
||||
if (IsEqualGUID(profile, D3D12_VIDEO_DECODE_PROFILE_AV1_PROFILE0) ||
|
||||
IsEqualGUID(profile, D3D12_VIDEO_DECODE_PROFILE_AV1_PROFILE1) ||
|
||||
IsEqualGUID(profile, D3D12_VIDEO_DECODE_PROFILE_AV1_PROFILE2) ||
|
||||
IsEqualGUID(profile, D3D12_VIDEO_DECODE_PROFILE_AV1_12BIT_PROFILE2) ||
|
||||
IsEqualGUID(profile, D3D12_VIDEO_DECODE_PROFILE_AV1_12BIT_PROFILE2_420)) {
|
||||
return FF_CODEC_TYPE_AV1;
|
||||
}
|
||||
// clang-format on
|
||||
|
||||
return FF_CODEC_TYPE_UNKNOWN;
|
||||
}
|
||||
|
||||
static bool ffCodecProfileHasNativeOutput(ID3D11VideoDevice* videoDevice, const GUID& profile) {
|
||||
for (uint32_t i = 0; i < ARRAY_SIZE(FF_NATIVE_CODEC_FORMATS); ++i) {
|
||||
BOOL supported = FALSE;
|
||||
if (SUCCEEDED(videoDevice->CheckVideoDecoderFormat(&profile, FF_NATIVE_CODEC_FORMATS[i], &supported)) && supported) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool ffCodecProfileHasNativeOutput(ID3D12VideoDevice* videoDevice, const GUID& profile, UINT nodeIndex) {
|
||||
for (uint32_t i = 0; i < ARRAY_SIZE(FF_NATIVE_CODEC_FORMATS); ++i) {
|
||||
D3D12_FEATURE_DATA_VIDEO_DECODE_SUPPORT support = {
|
||||
.NodeIndex = nodeIndex,
|
||||
.Configuration = {
|
||||
.DecodeProfile = profile,
|
||||
.BitstreamEncryption = D3D12_BITSTREAM_ENCRYPTION_TYPE_NONE,
|
||||
.InterlaceType = D3D12_VIDEO_FRAME_CODED_INTERLACE_TYPE_NONE,
|
||||
},
|
||||
.Width = 1920,
|
||||
.Height = 1080,
|
||||
.DecodeFormat = FF_NATIVE_CODEC_FORMATS[i],
|
||||
.FrameRate = {
|
||||
.Numerator = 30,
|
||||
.Denominator = 1,
|
||||
},
|
||||
.BitRate = 10000000,
|
||||
.SupportFlags = D3D12_VIDEO_DECODE_SUPPORT_FLAG_NONE,
|
||||
.ConfigurationFlags = D3D12_VIDEO_DECODE_CONFIGURATION_FLAG_NONE,
|
||||
.DecodeTier = D3D12_VIDEO_DECODE_TIER_NOT_SUPPORTED,
|
||||
};
|
||||
|
||||
if (SUCCEEDED(videoDevice->CheckFeatureSupport(D3D12_FEATURE_VIDEO_DECODE_SUPPORT, &support, sizeof(support))) &&
|
||||
(support.SupportFlags & D3D12_VIDEO_DECODE_SUPPORT_FLAG_SUPPORTED)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool ffCodecEncoderSupportedD3d12(ID3D12VideoDevice* videoDevice, D3D12_VIDEO_ENCODER_CODEC codec, UINT nodeIndex) {
|
||||
D3D12_FEATURE_DATA_VIDEO_ENCODER_CODEC encoderCodec = {
|
||||
.NodeIndex = nodeIndex,
|
||||
.Codec = codec,
|
||||
.IsSupported = FALSE,
|
||||
};
|
||||
|
||||
return SUCCEEDED(videoDevice->CheckFeatureSupport(
|
||||
D3D12_FEATURE_VIDEO_ENCODER_CODEC,
|
||||
&encoderCodec,
|
||||
sizeof(encoderCodec))) &&
|
||||
encoderCodec.IsSupported;
|
||||
}
|
||||
|
||||
typedef struct FFCodecMftEncoderSubtype {
|
||||
const GUID* subtype;
|
||||
FFCodecType codecType;
|
||||
} FFCodecMftEncoderSubtype;
|
||||
|
||||
static const FFCodecMftEncoderSubtype FF_D3D11VA_MFT_ENCODER_SUBTYPES[] = {
|
||||
{ &MFVideoFormat_H264, FF_CODEC_TYPE_H264 },
|
||||
{ &MFVideoFormat_HEVC, FF_CODEC_TYPE_HEVC },
|
||||
{ &MFVideoFormat_AV1, FF_CODEC_TYPE_AV1 },
|
||||
};
|
||||
|
||||
static FFCodecType ffDetectD3d11vaDecoders(IDXGIAdapter1* adapter, __typeof__(&D3D11CreateDevice) ffD3D11CreateDevice) {
|
||||
ID3D11Device* FF_AUTO_RELEASE_COM_OBJECT d3dDevice = nullptr;
|
||||
D3D_FEATURE_LEVEL featureLevel;
|
||||
if (FAILED(ffD3D11CreateDevice(
|
||||
adapter,
|
||||
D3D_DRIVER_TYPE_UNKNOWN,
|
||||
nullptr,
|
||||
D3D11_CREATE_DEVICE_VIDEO_SUPPORT,
|
||||
nullptr,
|
||||
0,
|
||||
D3D11_SDK_VERSION,
|
||||
&d3dDevice,
|
||||
&featureLevel,
|
||||
nullptr)) ||
|
||||
!d3dDevice) {
|
||||
return FF_CODEC_TYPE_NONE;
|
||||
}
|
||||
|
||||
ID3D11VideoDevice* FF_AUTO_RELEASE_COM_OBJECT videoDevice = nullptr;
|
||||
if (FAILED(d3dDevice->QueryInterface(__uuidof(ID3D11VideoDevice), (void**) &videoDevice)) || !videoDevice) {
|
||||
return FF_CODEC_TYPE_NONE;
|
||||
}
|
||||
|
||||
FFCodecType decoders = FF_CODEC_TYPE_NONE;
|
||||
UINT profileCount = videoDevice->GetVideoDecoderProfileCount();
|
||||
for (UINT profileIndex = 0; profileIndex < profileCount; ++profileIndex) {
|
||||
GUID profile;
|
||||
if (FAILED(videoDevice->GetVideoDecoderProfile(profileIndex, &profile))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
FFCodecType type = ffCodecProfileToTypeDx11(profile);
|
||||
|
||||
if ((decoders & type) || !ffCodecProfileHasNativeOutput(videoDevice, profile)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
decoders = (FFCodecType) (((uint32_t) decoders) | ((uint32_t) type));
|
||||
}
|
||||
return decoders;
|
||||
}
|
||||
|
||||
static FFCodecType ffDetectD3d11MftEncoders(const LUID& adapterLuid, __typeof__(&MFCreateAttributes) ffMFCreateAttributes, __typeof__(&MFTEnum2) ffMFTEnum2) {
|
||||
IMFAttributes* FF_AUTO_RELEASE_COM_OBJECT attributes = nullptr;
|
||||
if (FAILED(ffMFCreateAttributes(&attributes, 1)) || !attributes) {
|
||||
return FF_CODEC_TYPE_NONE;
|
||||
}
|
||||
|
||||
if (FAILED(attributes->SetBlob(MFT_ENUM_ADAPTER_LUID, (const UINT8*) &adapterLuid, sizeof(adapterLuid)))) {
|
||||
return FF_CODEC_TYPE_NONE;
|
||||
}
|
||||
|
||||
FFCodecType encoders = FF_CODEC_TYPE_NONE;
|
||||
|
||||
for (uint32_t subtypeIndex = 0; subtypeIndex < ARRAY_SIZE(FF_D3D11VA_MFT_ENCODER_SUBTYPES); ++subtypeIndex) {
|
||||
const FFCodecMftEncoderSubtype& subtype = FF_D3D11VA_MFT_ENCODER_SUBTYPES[subtypeIndex];
|
||||
if (encoders & subtype.codecType) {
|
||||
continue;
|
||||
}
|
||||
|
||||
MFT_REGISTER_TYPE_INFO outputType = {
|
||||
.guidMajorType = MFMediaType_Video,
|
||||
.guidSubtype = *subtype.subtype,
|
||||
};
|
||||
|
||||
IMFActivate** activateList = nullptr;
|
||||
UINT32 activateCount = 0;
|
||||
|
||||
if (SUCCEEDED(ffMFTEnum2(
|
||||
MFT_CATEGORY_VIDEO_ENCODER,
|
||||
MFT_ENUM_FLAG_HARDWARE | MFT_ENUM_FLAG_SORTANDFILTER,
|
||||
nullptr,
|
||||
&outputType,
|
||||
attributes,
|
||||
&activateList,
|
||||
&activateCount)) &&
|
||||
activateCount > 0) {
|
||||
encoders = (FFCodecType) (((uint32_t) encoders) | ((uint32_t) subtype.codecType));
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < activateCount; ++i) {
|
||||
activateList[i]->Release();
|
||||
}
|
||||
CoTaskMemFree(activateList);
|
||||
}
|
||||
|
||||
return encoders;
|
||||
}
|
||||
|
||||
static FFCodecType ffCodecEncoderToType(D3D12_VIDEO_ENCODER_CODEC codec) {
|
||||
switch (codec) {
|
||||
case D3D12_VIDEO_ENCODER_CODEC_H264:
|
||||
return FF_CODEC_TYPE_H264;
|
||||
case D3D12_VIDEO_ENCODER_CODEC_HEVC:
|
||||
return FF_CODEC_TYPE_HEVC;
|
||||
case D3D12_VIDEO_ENCODER_CODEC_AV1:
|
||||
return FF_CODEC_TYPE_AV1;
|
||||
default:
|
||||
return FF_CODEC_TYPE_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Func>
|
||||
static void ffEnumHardwareAdapters(IDXGIFactory1* factory, Func&& onAdapter) {
|
||||
for (UINT adapterIndex = 0;; ++adapterIndex) {
|
||||
IDXGIAdapter1* FF_AUTO_RELEASE_COM_OBJECT adapter = nullptr;
|
||||
HRESULT adapterStatus = factory->EnumAdapters1(adapterIndex, &adapter);
|
||||
if (adapterStatus == DXGI_ERROR_NOT_FOUND) {
|
||||
break;
|
||||
}
|
||||
if (FAILED(adapterStatus) || !adapter) {
|
||||
continue;
|
||||
}
|
||||
|
||||
DXGI_ADAPTER_DESC1 desc;
|
||||
if (FAILED(adapter->GetDesc1(&desc))) {
|
||||
continue;
|
||||
}
|
||||
if (desc.Flags & DXGI_ADAPTER_FLAG_SOFTWARE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
onAdapter(adapter, desc);
|
||||
}
|
||||
}
|
||||
|
||||
const char* detectD3d11va(FFCodecOptions* options, FFlist* result /*list of FFCodecResult*/, IDXGIFactory1* factory) {
|
||||
FF_LIBRARY_LOAD_MESSAGE(d3d11, "d3d11" FF_LIBRARY_EXTENSION, 1)
|
||||
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(d3d11, D3D11CreateDevice)
|
||||
FF_LIBRARY_LOAD_MESSAGE(mfplat, "mfplat" FF_LIBRARY_EXTENSION, 1)
|
||||
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(mfplat, MFCreateAttributes)
|
||||
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(mfplat, MFTEnum2)
|
||||
|
||||
ffEnumHardwareAdapters(factory, [&](IDXGIAdapter1* adapter, const DXGI_ADAPTER_DESC1& desc) {
|
||||
FFCodecType decoders = (options->showType & FF_CODEC_SHOW_TYPE_DECODER)
|
||||
? ffDetectD3d11vaDecoders(adapter, ffD3D11CreateDevice)
|
||||
: FF_CODEC_TYPE_NONE;
|
||||
FFCodecType encoders = (options->showType & FF_CODEC_SHOW_TYPE_ENCODER)
|
||||
? ffDetectD3d11MftEncoders(desc.AdapterLuid, ffMFCreateAttributes, ffMFTEnum2)
|
||||
: FF_CODEC_TYPE_NONE;
|
||||
|
||||
if (decoders == FF_CODEC_TYPE_NONE && encoders == FF_CODEC_TYPE_NONE) {
|
||||
return;
|
||||
}
|
||||
|
||||
FFCodecResult* gpuResult = FF_LIST_ADD(FFCodecResult, *result);
|
||||
ffStrbufInitWS(&gpuResult->gpu, desc.Description);
|
||||
gpuResult->decoders = decoders;
|
||||
gpuResult->encoders = encoders;
|
||||
gpuResult->platformApi = "D3D11VA+MFT";
|
||||
});
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const char* detectD3d12va(FFCodecOptions* options, FFlist* result /*list of FFCodecResult*/, IDXGIFactory1* factory) {
|
||||
FF_LIBRARY_LOAD_MESSAGE(d3d12, "d3d12" FF_LIBRARY_EXTENSION, 1)
|
||||
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(d3d12, D3D12CreateDevice)
|
||||
|
||||
static const GUID FF_D3D12_DECODE_PROFILES[] = {
|
||||
D3D12_VIDEO_DECODE_PROFILE_MPEG2,
|
||||
D3D12_VIDEO_DECODE_PROFILE_MPEG1_AND_MPEG2,
|
||||
D3D12_VIDEO_DECODE_PROFILE_H264,
|
||||
D3D12_VIDEO_DECODE_PROFILE_H264_STEREO_PROGRESSIVE,
|
||||
D3D12_VIDEO_DECODE_PROFILE_H264_STEREO,
|
||||
D3D12_VIDEO_DECODE_PROFILE_H264_MULTIVIEW,
|
||||
D3D12_VIDEO_DECODE_PROFILE_VC1,
|
||||
D3D12_VIDEO_DECODE_PROFILE_VC1_D2010,
|
||||
D3D12_VIDEO_DECODE_PROFILE_MPEG4PT2_SIMPLE,
|
||||
D3D12_VIDEO_DECODE_PROFILE_MPEG4PT2_ADVSIMPLE_NOGMC,
|
||||
D3D12_VIDEO_DECODE_PROFILE_HEVC_MAIN,
|
||||
D3D12_VIDEO_DECODE_PROFILE_HEVC_MAIN10,
|
||||
D3D12_VIDEO_DECODE_PROFILE_VP9,
|
||||
D3D12_VIDEO_DECODE_PROFILE_VP9_10BIT_PROFILE2,
|
||||
D3D12_VIDEO_DECODE_PROFILE_VP8,
|
||||
D3D12_VIDEO_DECODE_PROFILE_AV1_PROFILE0,
|
||||
D3D12_VIDEO_DECODE_PROFILE_AV1_PROFILE1,
|
||||
D3D12_VIDEO_DECODE_PROFILE_AV1_PROFILE2,
|
||||
D3D12_VIDEO_DECODE_PROFILE_AV1_12BIT_PROFILE2,
|
||||
D3D12_VIDEO_DECODE_PROFILE_AV1_12BIT_PROFILE2_420,
|
||||
};
|
||||
|
||||
static const D3D12_VIDEO_ENCODER_CODEC FF_D3D12_ENCODER_CODECS[] = {
|
||||
D3D12_VIDEO_ENCODER_CODEC_H264,
|
||||
D3D12_VIDEO_ENCODER_CODEC_HEVC,
|
||||
D3D12_VIDEO_ENCODER_CODEC_AV1,
|
||||
};
|
||||
|
||||
const uint32_t resultLengthBefore = result->length;
|
||||
|
||||
ffEnumHardwareAdapters(factory, [&](IDXGIAdapter1* adapter, const DXGI_ADAPTER_DESC1& desc) {
|
||||
ID3D12Device* FF_AUTO_RELEASE_COM_OBJECT d3dDevice = nullptr;
|
||||
if (FAILED(ffD3D12CreateDevice(
|
||||
adapter,
|
||||
D3D_FEATURE_LEVEL_11_0,
|
||||
__uuidof(ID3D12Device),
|
||||
(void**) &d3dDevice)) ||
|
||||
!d3dDevice) {
|
||||
return;
|
||||
}
|
||||
|
||||
ID3D12VideoDevice* FF_AUTO_RELEASE_COM_OBJECT videoDevice = nullptr;
|
||||
if (FAILED(d3dDevice->QueryInterface(__uuidof(ID3D12VideoDevice), (void**) &videoDevice)) || !videoDevice) {
|
||||
return;
|
||||
}
|
||||
|
||||
FFCodecType decoders = FF_CODEC_TYPE_NONE;
|
||||
if (options->showType & FF_CODEC_SHOW_TYPE_DECODER) {
|
||||
for (uint32_t profileIndex = 0; profileIndex < ARRAY_SIZE(FF_D3D12_DECODE_PROFILES); ++profileIndex) {
|
||||
const GUID& profile = FF_D3D12_DECODE_PROFILES[profileIndex];
|
||||
FFCodecType codecType = ffCodecProfileToTypeDx12(profile);
|
||||
|
||||
if ((decoders & codecType) || !ffCodecProfileHasNativeOutput(videoDevice, profile, 0)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
decoders = (FFCodecType) (((uint32_t) decoders) | ((uint32_t) codecType));
|
||||
}
|
||||
}
|
||||
|
||||
FFCodecType encoders = FF_CODEC_TYPE_NONE;
|
||||
if (options->showType & FF_CODEC_SHOW_TYPE_ENCODER) {
|
||||
for (uint32_t codecIndex = 0; codecIndex < ARRAY_SIZE(FF_D3D12_ENCODER_CODECS); ++codecIndex) {
|
||||
D3D12_VIDEO_ENCODER_CODEC codec = FF_D3D12_ENCODER_CODECS[codecIndex];
|
||||
FFCodecType codecType = ffCodecEncoderToType(codec);
|
||||
|
||||
if ((encoders & codecType) || !ffCodecEncoderSupportedD3d12(videoDevice, codec, 0)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
encoders = (FFCodecType) (((uint32_t) encoders) | ((uint32_t) codecType));
|
||||
}
|
||||
}
|
||||
|
||||
if (decoders == FF_CODEC_TYPE_NONE && encoders == FF_CODEC_TYPE_NONE) {
|
||||
return;
|
||||
}
|
||||
|
||||
FFCodecResult* gpuResult = FF_LIST_ADD(FFCodecResult, *result);
|
||||
ffStrbufInitWS(&gpuResult->gpu, desc.Description);
|
||||
gpuResult->decoders = decoders;
|
||||
gpuResult->encoders = encoders;
|
||||
gpuResult->platformApi = "D3D12VA";
|
||||
});
|
||||
|
||||
if (result->length == resultLengthBefore) {
|
||||
return "No D3D12 video acceleration support";
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const char* ffDetectCodecNative(FFCodecOptions* options, FFlist* result /*list of FFCodecResult*/) {
|
||||
FF_LIBRARY_LOAD_MESSAGE(dxgi, "dxgi" FF_LIBRARY_EXTENSION, 1)
|
||||
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(dxgi, CreateDXGIFactory1)
|
||||
|
||||
const char* error = ffInitCom();
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
|
||||
IDXGIFactory1* FF_AUTO_RELEASE_COM_OBJECT factory = nullptr;
|
||||
if (FAILED(ffCreateDXGIFactory1(__uuidof(IDXGIFactory1), (void**) &factory)) || !factory) {
|
||||
return "CreateDXGIFactory1() failed";
|
||||
}
|
||||
|
||||
if (ffIsWindows11OrGreater()) {
|
||||
// D3D12 video encoding is supported only on Windows 11
|
||||
if (detectD3d12va(options, result, factory) == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
return detectD3d11va(options, result, factory);
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
#include "cpu.h"
|
||||
#include "common/sysctl.h"
|
||||
#include "common/apple/smc_temps.h"
|
||||
#include "common/stringUtils.h"
|
||||
#include "common/strutil.h"
|
||||
|
||||
static double detectCpuTemp(const FFCPUOptions* options, const FFstrbuf* cpuName) {
|
||||
double result = 0;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "cpu.h"
|
||||
#include "common/sysctl.h"
|
||||
#include "common/stringUtils.h"
|
||||
#include "common/strutil.h"
|
||||
|
||||
#include <sys/param.h>
|
||||
#if __has_include(<sys/cpuset.h>)
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
#include "common/processing.h"
|
||||
#include "common/properties.h"
|
||||
#include "common/mallocHelper.h"
|
||||
#include "common/stringUtils.h"
|
||||
#include "common/strutil.h"
|
||||
#include "common/path.h"
|
||||
|
||||
#include <sys/sysinfo.h>
|
||||
@@ -357,6 +357,9 @@ static void detectExynos(FFCPUResult* cpu) {
|
||||
const char* name = NULL;
|
||||
|
||||
switch (code) {
|
||||
case 9965:
|
||||
name = "2600";
|
||||
break;
|
||||
case 9955:
|
||||
name = "2500";
|
||||
break;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "cpu.h"
|
||||
#include "common/sysctl.h"
|
||||
#include "common/stringUtils.h"
|
||||
#include "common/strutil.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "cpu.h"
|
||||
#include "common/processing.h"
|
||||
#include "common/stringUtils.h"
|
||||
#include "common/strutil.h"
|
||||
#include <kstat.h>
|
||||
|
||||
static const char* detectCPUTempByKstat(const FFCPUOptions* options, kstat_ctl_t* kc, FFCPUResult* cpu) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "cpucache.h"
|
||||
#include "common/sysctl.h"
|
||||
#include "common/stringUtils.h"
|
||||
#include "common/strutil.h"
|
||||
|
||||
const char* ffDetectCPUCache(FFCPUCacheResult* result) {
|
||||
// https://developer.apple.com/documentation/kernel/1387446-sysctlbyname/determining_system_capabilities#3901385
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "cpucache.h"
|
||||
#include "common/io.h"
|
||||
#include "common/stringUtils.h"
|
||||
#include "common/strutil.h"
|
||||
|
||||
static const char* parseCpuCacheIndex(FFstrbuf* path, FFCPUCacheResult* result, FFstrbuf* buffer, FFstrbuf* added) {
|
||||
uint32_t baseLen = path->length;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "cpucache.h"
|
||||
#include "common/smbios.h"
|
||||
#include "common/stringUtils.h"
|
||||
#include "common/strutil.h"
|
||||
|
||||
typedef struct FFSmbiosCacheInfo {
|
||||
FFSmbiosHeader Header;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user