Compare commits

...

116 Commits

Author SHA1 Message Date
Carter Li d48bd733f0 Merge pull request #2368 from fastfetch-cli/dev
Release v2.64.0
2026-06-03 19:18:31 +08:00
李通洲 0585ea7797 Doc: update changelog 2026-06-03 18:34:09 +08:00
李通洲 794035f8d9 Shell: sets pretty name of busybox to ash 2026-06-03 18:29:33 +08:00
李通洲 723552f68b Shell: be more robust on busybox version detection 2026-06-03 18:29:10 +08:00
Carter Li 8dd38f5744 Release: v2.64.0 2026-06-03 16:04:00 +08:00
Carter Li 616a5c7aea Codec (Vulkan): be compatible with old Vulkan headers
Fixes #2367
2026-06-03 15:23:42 +08:00
Carter Li 5e1e94473e Bootmgr (macOS): don't hard-code the firmware name 2026-06-03 15:23:42 +08:00
CicaDATA 4eae8ac244 Logo (Builtin): updates NurOS logo and colors (#2366) 2026-06-03 02:21:23 -05:00
李通洲 8aeb7c2f10 Shell (Linux): improves performance of busybox (ash) version detection 2026-06-02 17:44:55 +08:00
Carter Li c20b532c7a Common (Format): adds | for center aligning 2026-06-02 16:03:04 +08:00
Carter Li 3c59161aca Common (Format): handles ANSI escapes when padding/truncating variable strings
Fixes #2364
2026-06-02 15:55:10 +08:00
Carter Li bd454632c3 FFstrbuf: inlines more functions 2026-06-02 15:42:40 +08:00
Carter Li e73adc27a0 Common: fixes wcwidth handling 2026-06-02 15:05:13 +08:00
Carter Li 15c6014c04 Common: don't inline ffUtf8CharLenWidth 2026-06-02 14:01:59 +08:00
Carter Li 54f18982ac Common: renames arrayUtil to arrutil 2026-06-02 10:59:18 +08:00
Carter Li 99c2f2a2c8 JsonSchema: adds codec 2026-06-02 10:58:57 +08:00
Carter Li 45f35b1c4d Library (Linux): adds simple debug log 2026-06-02 09:27:38 +08:00
Carter Li 428c05b9de Codec (Linux): optimises code 2026-06-02 09:10:55 +08:00
李通洲 23ca6d94ab CI: run codec module 2026-06-02 00:15:42 +08:00
李通洲 9e4e0cb838 Codec (Linux): removes VAEntrypointEncPicture 2026-06-01 23:45:17 +08:00
李通洲 95a370e5a2 Codec (macOS): fixes building 2026-06-01 20:48:59 +08:00
李通洲 e013005f34 Code (Vulkan): fixes compiling 2026-06-01 20:16:30 +08:00
李通洲 92b86f7cbb Codec: shows types only specifed by showType 2026-06-01 19:27:37 +08:00
李通洲 2e4b7baf44 Codec (Android): adds showType support 2026-06-01 19:27:37 +08:00
李通洲 a47ff0b2dc Codec (macOS): adds showType support 2026-06-01 19:27:37 +08:00
李通洲 1f13f6c8f5 Codec (Windows): adds showType support 2026-06-01 19:27:37 +08:00
李通洲 b0bb6fb58e Codec: don't show Unknown 2026-06-01 19:27:37 +08:00
Carter Li 37029dbbe3 Codec (Vulkan): adds showType support 2026-06-01 19:27:37 +08:00
Carter Li 35428606e7 Codec (Linux): adds FFCodecShowOptions; code cleanup 2026-06-01 19:27:37 +08:00
Carter Li 2c65eee00f Common (Lua): adds json_encode 2026-06-01 19:27:37 +08:00
Carter Li a1bf014352 Codec: normalizes platformApi string 2026-06-01 10:34:17 +08:00
Carter Li 412fc94dab WM (Linux): fixes possible segfault when detecting sway version
Fixes #2360
2026-06-01 10:16:26 +08:00
Carter Li b65de28805 Logo (Builtin): adds Quasar
Fixes #2338 #2323
2026-06-01 09:34:32 +08:00
李通洲 bc86c66cdd Codec (Windows): detects encoders detection support via MFT on Win10 or older 2026-06-01 09:16:22 +08:00
李通洲 9afa01812d Codec (Vulkan): disables impl if the vulkan headers are too old to use 2026-06-01 00:15:27 +08:00
李通洲 30a8a94cd2 Chore (Haiku): silences compiler warnings 2026-05-31 23:56:45 +08:00
李通洲 3a54617196 Codec: adds vulkan support 2026-05-31 23:45:20 +08:00
李通洲 3e3a03a233 Codec (Android): adds support 2026-05-31 23:37:50 +08:00
李通洲 b407669b69 JsonSchema: update 2026-05-31 23:37:49 +08:00
李通洲 e14ea926a5 Codec (macOS): adds platformApi 2026-05-31 23:37:49 +08:00
李通洲 9d8f794cb9 Codec (Windows): detects encoder support via d3d12va 2026-05-31 23:37:49 +08:00
Carter Li 825b8b8715 Codec (Linux): adds vdpau fallback impl 2026-05-31 23:37:49 +08:00
Carter Li 0c94fd87db Codec: updates default format 2026-05-31 23:37:49 +08:00
Carter Li 473a08d85c Decoder: renames to Codec and adds encoders detection support 2026-05-31 23:37:49 +08:00
Carter Li ae5132c388 Decoder (macOS): adds support 2026-05-31 23:37:49 +08:00
李通洲 1addcec7a2 Decoder (Linux): adds *nix support 2026-05-31 23:37:49 +08:00
李通洲 e75c37c101 Decoder (Windows): adds support 2026-05-31 23:37:49 +08:00
李通洲 b9ab823f77 Decoder: inits module 2026-05-31 23:37:48 +08:00
François Revol a63d854681 OS (Haiku): Fix warnings 2026-05-31 23:37:35 +08:00
François Revol 576548b15e WMTheme (Haiku): implement 2026-05-31 23:37:35 +08:00
François Revol 3043971259 Brightness (Haiku): Implement 2026-05-31 23:37:35 +08:00
François Revol ccf4f22f8b Bootmgr (Haiku): Preliminary implementation 2026-05-31 23:37:35 +08:00
LibereCode f932db713c Logo (Builtin): Minor tweak NixOS_small logo (#2357)
* [fix]: markdown-link to wiki

* [fix]: fix color at 1 spot

* [fix]: fix color at 1 spot, again

* Revert "[fix]: markdown-link to wiki"

This reverts commit 72f4d11c90.

"Remove unrelated changes"
2026-05-31 01:11:53 +08:00
李通洲 d2e8a8fd9e CMake: renames DISABLE_MODULE_* for MODULE_DISABLE_* to align with PACKAGE_DISABLE_* 2026-05-30 18:37:42 +08:00
李通洲 4c1f7c114a Chore: reports if embedded wcwidth is enabled 2026-05-30 18:27:17 +08:00
SirSputnikWiki 90bbfe195f Terminal (Linux): improves terminal name detection for nix packages (#2352)
* Improved terminal name detection for nix packages

* Improved terminal name detection for nix packages

* Update terminalshell_linux.c

Move ffStrbufStartsWithC(&result->processName, '.') before string comparation, as it's much cheaper.
2026-05-30 10:16:12 +08:00
Carter Li 1689fc81e9 Logo (Builtin): adds Origami and Origami_small
Fixes #2321 #2322
2026-05-29 16:05:53 +08:00
Carter Li 4190dd5a6e Logo (Builtin): adds BerserkArch
Fixes #2324 #2310
2026-05-29 16:05:52 +08:00
Carter Li 074f882d7e Wallpaper (Linux): adds COSMIC support 2026-05-29 15:40:27 +08:00
Carter Li 53102380b8 WMTheme (Linux): adds COSMIC support 2026-05-29 15:40:02 +08:00
李通洲 822bc158ba CMake: changes FF_MODULE_XX to FF_DISABLE_MODULE_XX 2026-05-28 23:14:49 +08:00
李通洲 8fbc29a70c Common (strutil): fixes unit tests 2026-05-28 22:41:47 +08:00
李通洲 0ef677a98c Logo (Builtin): add NixOS2
Fixes #2346
2026-05-28 20:12:46 +08:00
Carter Li 10b0d0ca3e CPU (Android): adds Exynos 2600 2026-05-28 19:20:21 +08:00
Carter Li ec4e820e92 Logo: exports ffLogoPrintDetected 2026-05-28 19:18:35 +08:00
Carter Li 6c09fe49e4 Logo (Builtin): warps logo definitions into #ifdef blocks 2026-05-28 18:42:10 +08:00
Carter Li 1ce6398391 Logo (Builtin): splits built-in logos into individual files 2026-05-28 18:42:10 +08:00
Carter Li d1bf208a92 Chore: renames stringUtils to strutil 2026-05-28 15:58:08 +08:00
Carter Li 7ce1e553b8 CMake: makes default structure configurable via CMake 2026-05-28 15:55:43 +08:00
Carter Li 9c878b6943 Chore: moves /src/data/help.json to /doc 2026-05-28 15:54:17 +08:00
Carter Li 6b9a6fd103 CMake: adds MODULE_<module> options to disable modules 2026-05-28 15:41:14 +08:00
Carter Li 896fe60461 CMake: adds option FF_ENABLE_WCWIDTH 2026-05-28 14:47:09 +08:00
Carter Li dadcccdf26 TerminalShell: code refactor 2026-05-28 10:31:35 +08:00
李通洲 0746af7549 Wifi (Linux): adds comments [ci skip] 2026-05-27 17:11:59 +08:00
Carter Li 88c3b7d118 Common (stringUtil): adds ffUtf8CharLenWidth 2026-05-26 16:11:30 +08:00
Carter Li 173d9695b6 Common: removes using of built-in wcwidth, which is locale-dependent 2026-05-26 16:10:01 +08:00
Carter Li 4b265cd56a Common: adds Attr FF_A_ALWAYS_INLINE 2026-05-26 15:37:17 +08:00
李通洲 1f211cf8d1 Brightness: adds ddcciSleep: null to skip DDC/CI detection 2026-05-24 10:58:10 +08:00
李通洲 bac60357c6 Logo: fixes paddingLeft not working with position: top 2026-05-24 08:39:25 +08:00
李通洲 3a0e188570 CMake (Windows): disables usage of WinRT on GCC
Fixes #2341
2026-05-23 22:49:04 +08:00
李通洲 9d5b40686b Global: really prints --stat at the right border 2026-05-23 09:50:49 +08:00
李通洲 a321cd877e Logo: resets color state after printing logo line 2026-05-23 09:44:03 +08:00
李通洲 5f810de1e0 Logo: overrides the auto detected max-width with the configured width, if set 2026-05-23 09:33:58 +08:00
李通洲 3f0a93d057 Logo: reworks position: top; adds a new option --logo-padding-bottom 2026-05-22 20:26:18 +08:00
Carter Li cbca6a965c Logo: prints ASCII logo line by line 2026-05-22 19:09:34 +08:00
Carter Li fde1195c27 TerminalFont (macOS): fixes fallback font detection of Ghostty; adds Muxy terminal support 2026-05-22 14:20:39 +08:00
Carter Li 9856d97bd1 Common (macOS): unifies AppBundle version detection code 2026-05-22 13:37:48 +08:00
Carter Li 2751737ebe CI: builds with quickjs-ng support 2026-05-22 10:24:25 +08:00
Carter Li 834292df29 Brightness (DFBSD): fixes compiling 2026-05-22 10:09:39 +08:00
Carter Li a9a29869a4 Format: tidy 2026-05-22 10:09:39 +08:00
Carter Li 242fb50461 Format: traits undefined result as an error 2026-05-22 09:26:52 +08:00
Carter Li b5c4ffcc85 Format (Lua): simplifies error messages 2026-05-21 09:25:41 +08:00
李通洲 2c3628c630 Format (QJS): converts UINT64 to double and drops usage of BigInt 2026-05-20 23:01:28 +08:00
李通洲 4cca9bf198 Presets: removes invalid comments 2026-05-20 18:40:36 +08:00
李通洲 0ed27d9700 Format: fixes a possible OOB read 2026-05-20 18:40:20 +08:00
李通洲 9bca4eb48f Format: normalizes arg name before pass to script language 2026-05-20 18:39:12 +08:00
李通洲 462b80fc36 CMake: corrects the package name of quickjs-ng 2026-05-20 18:17:38 +08:00
Carter Li f49620a95b CMake: hardens Lua handling 2026-05-20 16:18:50 +08:00
Carter Li 6e0949c739 CMake: fixes finding quickjs 2026-05-20 09:32:02 +08:00
Carter Li 4b18ab0de7 Brightness (macOS): fixes building 2026-05-20 09:31:35 +08:00
Carter Li 8abd75a746 Brightness: refactor 2026-05-20 00:09:09 +08:00
Carter Li d5b215e074 Brightness (FreeBSD): improves DDC/CI handling 2026-05-20 00:07:20 +08:00
Carter Li 0b22427091 WM (Linux): fixes swayfx version detection on NixOS 2026-05-19 17:20:56 +08:00
Carter Li aa34910b6c CMake: actually compiles with quickjs-ng definitions 2026-05-19 15:52:01 +08:00
李通洲 52972ed833 CI (Windows): bundles dlls of lua & qjs 2026-05-18 11:06:30 +08:00
李通洲 68e75effab CMake: adds comments [ci skip] 2026-05-18 11:01:37 +08:00
Carter Li bb79370d03 Brightness (FreeBSD): adds ddc-ci detection support (WIP) 2026-05-18 10:08:31 +08:00
李通洲 9613cdd146 CI: builds with quickjs support 2026-05-18 01:42:13 +08:00
李通洲 724b816252 CI: builds with lua support 2026-05-17 23:21:49 +08:00
李通洲 7c89a10add Common: adds Lua script support for custom format 2026-05-17 20:12:03 +08:00
李通洲 fb5ec76eb3 Global: skips module if format buffer is empty 2026-05-17 19:55:30 +08:00
Carter Li 7141214f95 WM (Linux): fixes swayfx version detection 2026-05-17 09:51:19 +08:00
Carter Li 7d6074968f Packaging: update debian stuff [ci skip] 2026-05-15 09:40:40 +08:00
Carter Li 3bd380802b Merge remote-tracking branch 'origin/master' into dev 2026-05-15 09:40:24 +08:00
李通洲 ec1200dc06 Media (Windows): removes using of C++20 std::bind_front 2026-05-14 19:50:38 +08:00
Carter Li 5c18c061b3 GPU (Linux): silences a warning in Release mode 2026-05-14 09:39:17 +08:00
808 changed files with 11720 additions and 6552 deletions
+1 -1
View File
@@ -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 .
+1 -1
View File
@@ -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
+1 -1
View File
@@ -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
+1 -1
View File
@@ -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
+1 -1
View File
@@ -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
+3 -3
View File
@@ -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
+3 -3
View File
@@ -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
+1 -1
View File
@@ -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
+2 -1
View File
@@ -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 .
+3 -1
View File
@@ -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
+1 -1
View File
@@ -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
+1 -1
View File
@@ -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
+1 -1
View File
@@ -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
+2 -2
View File
@@ -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
+61
View File
@@ -1,3 +1,64 @@
# 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:
+145 -27
View File
@@ -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.1
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()
##################
+6
View File
@@ -1,3 +1,9 @@
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
+83 -4
View File
@@ -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",
+4
View File
@@ -50,6 +50,10 @@
"driverSpecific": true,
"temp": true
},
{
"type": "codec",
"splitGPU": true
},
"memory",
"physicalmemory",
{
+4
View File
@@ -52,6 +52,10 @@
"driverSpecific": true,
"temp": true
},
{
"type": "codec",
"splitGPU": true
},
"memory",
"physicalmemory",
{
-3
View File
@@ -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": {
-3
View File
@@ -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": {
-3
View File
@@ -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
View File
@@ -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
View File
@@ -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 -1
View File
@@ -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>
+5
View File
@@ -0,0 +1,5 @@
#pragma once
#include "fastfetch.h"
bool ffGetAppNameAndVersion(const char* exePath, FFstrbuf* retName, FFstrbuf* retVersion);
+43
View File
@@ -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;
}
+1
View File
@@ -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
View File
@@ -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 -1
View File
@@ -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"
+2 -2
View File
@@ -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 -1
View File
@@ -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 -27
View File
@@ -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 -1
View File
@@ -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>
+1 -1
View File
@@ -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 -1
View File
@@ -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>
+12 -2
View File
@@ -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
@@ -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
}
}
+1 -1
View File
@@ -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 -1
View File
@@ -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
View File
@@ -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);
}
+26
View File
@@ -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 -1
View File
@@ -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 -1
View File
@@ -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"
+16 -2
View File
@@ -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 -1
View File
@@ -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 -1
View File
@@ -1,5 +1,5 @@
#include "common/kmod.h"
#include "common/stringUtils.h"
#include "common/strutil.h"
#include <sys/modctl.h>
#include <errno.h>
+1 -1
View File
@@ -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;
+7 -1
View File
@@ -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);
+216
View File
@@ -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 -1
View File
@@ -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
+1 -1
View File
@@ -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"
+1 -1
View File
@@ -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 -1
View File
@@ -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 -1
View File
@@ -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) {
+1 -1
View File
@@ -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) {
+14 -6
View File
@@ -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 -1
View File
@@ -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>
+80
View File
@@ -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 -1
View File
@@ -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
+5 -5
View File
@@ -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;
+183
View File
@@ -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
View File
@@ -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) {
+1 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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 -1
View File
@@ -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 -1
View File
@@ -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 -1
View File
@@ -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>
+4 -3
View File
@@ -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 -1
View File
@@ -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"
+16 -2
View File
@@ -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);
+17
View File
@@ -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;
}
+14
View File
@@ -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
+12 -11
View File
@@ -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);
}
+106 -12
View File
@@ -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;
}
+6 -4
View File
@@ -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);
}
+14
View File
@@ -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);
}
+44
View File
@@ -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
+102
View File
@@ -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;
}
+96
View File
@@ -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;
}
+470
View File
@@ -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
+270
View File
@@ -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
+553
View File
@@ -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 -1
View File
@@ -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 -1
View File
@@ -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>)
+4 -1
View File
@@ -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 -1
View File
@@ -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 -1
View File
@@ -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 -1
View File
@@ -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 -1
View File
@@ -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 -1
View File
@@ -1,6 +1,6 @@
#include "cpucache.h"
#include "common/smbios.h"
#include "common/stringUtils.h"
#include "common/strutil.h"
typedef struct FFSmbiosCacheInfo {
FFSmbiosHeader Header;
+1 -1
View File
@@ -5,7 +5,7 @@
#include "common/properties.h"
#include "common/parsing.h"
#include "common/settings.h"
#include "common/stringUtils.h"
#include "common/strutil.h"
#include <stdlib.h>

Some files were not shown because too many files have changed in this diff Show More