Compare commits

...

137 Commits

Author SHA1 Message Date
Carter Li 636471c366 Merge pull request #2375 from fastfetch-cli/dev
Release v2.64.2
2026-06-05 18:36:58 +08:00
李通洲 cbc84fda6c Common (Lua): addresses AI's feedback 2026-06-05 18:21:28 +08:00
李通洲 fc7a0a8484 Codec (Linux): supports BINARY_LINK_TYPE=dynamic 2026-06-05 18:05:54 +08:00
李通洲 4d3b6c3b1b Common (QJS): supports BINARY_LINK_TYPE=dynamic 2026-06-05 17:49:49 +08:00
李通洲 70e67177fe Common (Lua): supports BINARY_LINK_TYPE=dynamic 2026-06-05 17:22:16 +08:00
李通洲 9fe7d6dbfa Logo: addresses review comments of AI 2026-06-05 16:34:02 +08:00
Carter Li a139a8c4a5 Doc: updates changelog [ci skip] 2026-06-05 16:22:04 +08:00
Valeriy Kosikhin da568c986e Logo (Builtin): update OpenWrt logo
Update the large logo for OpenWrt based on the official branding.
Add a small logo version.
Keep the old logo as openwrt_old.txt

Signed-off-by: Valeriy Kosikhin <vkosikhin@gmail.com>
2026-06-05 16:15:46 +08:00
Carter Li 727fbc0276 Doc: updates changelog 2026-06-05 15:29:00 +08:00
Carter Li 20aabdfd78 Global: resets keysHeight after every refresh 2026-06-05 15:27:25 +08:00
Carter Li e79aaf5ce1 Global: don't clear line in --logo-position right 2026-06-05 15:27:15 +08:00
Carter Li 53c2d07161 Release: v2.64.2 2026-06-05 14:51:50 +08:00
Carter Li 6b9f594620 Global: prevents ascii logo from being overwritten in --dynamic-interval mode 2026-06-05 14:47:01 +08:00
Carter Li ba3968784f Logo (Image): fixes image renders but quickly gets wiped
Regression from v2.64.0

Fixes: #2374
2026-06-05 13:12:07 +08:00
Carter Li 021ece1681 Merge pull request #2370 from fastfetch-cli/dev
Release: v2.64.1
2026-06-04 23:45:19 +08:00
李通洲 9787b56460 Release: v2.64.1 2026-06-04 20:15:54 +08:00
李通洲 54792e61ff Common (Lua): detects circular reference in encode_json 2026-06-04 20:15:54 +08:00
Carter Li b34e2a4055 Common (Base64): adds static to internal functions 2026-06-04 17:22:24 +08:00
Carter Li 3b56200ee4 Packages: adds option PACKAGES_REMOVE_DISABLED to remove disabled package managers from the build entirely 2026-06-04 17:22:24 +08:00
Carter Li de95a62e2f Codec (macOS): removes usage of JPEG XL; replaces enums with raw constants 2026-06-04 10:48:01 +08:00
Carter Li 72cb64a500 Common (Lua): optimises code; fixes incompatibility against lua 5.3 2026-06-04 10:48:01 +08:00
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
818 changed files with 11964 additions and 6656 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
+83
View File
@@ -1,3 +1,86 @@
# 2.64.2
Bugfixes:
* Fixes image rendering being wiped quickly (#2374)
* Regression from v2.64.0
* Fixes ASCII logo being overwritten in `--dynamic-interval` mode
* Regression from v2.64.0
Logos:
* Updates OpenWrt and adds a small variant (#2376)
* The old one is renamed to `openwrt_old`
# 2.64.1
Features:
* Adds a CMake option `-DPACKAGES_REMOVE_DISABLED` to remove detection code of disabled packages (`-DPACKAGES_DISABLE_<PACKAGE_NAME>`) for slightly smaller binary size (Packages)
Bugfixes:
* Fixes compatibility issues with Lua 5.3
* Avoid possible infinite recursion in `encode_json` when encoding deeply nested tables or circular references
* Fixes compilation issues when building with old macOS SDKs
# 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:
+174 -29
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.2
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})
@@ -120,7 +134,25 @@ if(NOT BINARY_LINK_TYPE IN_LIST BINARY_LINK_TYPE_OPTIONS)
message(FATAL_ERROR "BINARY_LINK_TYPE must be one of ${BINARY_LINK_TYPE_OPTIONS}")
endif()
set(PACKAGE_MANAGERS AM APPIMAGE APK BREW CHOCO DPKG EMERGE EOPKG FLATPAK GUIX LINGLONG LPKG LPKGBUILD MACPORTS NIX OPKG PACMAN PACSTALL PALUDIS PISI PKG PKGTOOL RPM SCOOP SNAP SOAR SORCERY WINGET XBPS)
set(PACKAGE_MANAGERS
AM APK APPIMAGE
BREW
CARDS CHOCO
DPKG
EMERGE EOPKG
FLATPAK
GUIX
HPKG
KISS
LINGLONG LPKG LPKGBUILD
MACPORTS MOSS MPORT
NIX
OPKG
PACMAN PACSTALL PALUDIS PISI PKG PKGSRC PKGTOOL
RPM
SCOOP SNAP SOAR SORCERY
WINGET
XBPS)
foreach(package_manager ${PACKAGE_MANAGERS})
if(package_manager STREQUAL "WINGET")
option(PACKAGES_DISABLE_${package_manager} "Disable ${package_manager} package manager detection by default" ON)
@@ -128,6 +160,7 @@ foreach(package_manager ${PACKAGE_MANAGERS})
option(PACKAGES_DISABLE_${package_manager} "Disable ${package_manager} package manager detection by default" OFF)
endif()
endforeach()
option(PACKAGES_REMOVE_DISABLED "Remove disabled package managers from the build entirely, instead of just skipping them at runtime" OFF)
if (LINUX)
set(CUSTOM_PCI_IDS_PATH "" CACHE STRING "Custom path to file pci.ids, defaults to `/usr/share/hwdata/pci.ids`")
@@ -287,14 +320,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 +387,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 +398,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 +421,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 +440,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 +487,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 +574,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 +662,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 +737,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 +832,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 +917,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 +994,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 +1092,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 +1164,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 +1238,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 +1248,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 +1292,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 +1318,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 +1386,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 +1407,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 +1428,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 +1570,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 +1599,57 @@ 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()
if(NOT BINARY_LINK_TYPE STREQUAL "dlopen")
# INTERFACE_LINK_LIBRARIES doesn't expose libvarname.a
target_link_libraries(libfastfetch PRIVATE ${_FF_CMAKE_TARGET})
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 +1657,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 +1695,14 @@ ff_lib_enable(DRM
"libdrm"
"Libdrm"
)
ff_lib_enable(VA
"libva-drm"
"Libva-drm"
)
ff_lib_enable(VDPAU
"vdpau"
"vdpau"
)
ff_lib_enable(DRM_AMDGPU
"libdrm_amdgpu"
"Libdrm_Amdgpu"
@@ -1682,6 +1782,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 +1835,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 +1869,7 @@ elseif(APPLE)
PRIVATE "-framework OpenGL"
PRIVATE "-framework OpenCL"
PRIVATE "-framework SystemConfiguration"
PRIVATE "-framework VideoToolbox"
PRIVATE "-weak_framework CoreDisplay"
PRIVATE "-F /System/Library/PrivateFrameworks"
@@ -1911,7 +2045,10 @@ else()
list(TRANSFORM PACKAGES_DISABLE_LIST APPEND "_BIT")
list(JOIN PACKAGES_DISABLE_LIST " | " PACKAGES_DISABLE_LIST)
endif()
target_compile_definitions(libfastfetch PRIVATE FF_PACKAGES_DISABLE_LIST=${PACKAGES_DISABLE_LIST})
target_compile_definitions(libfastfetch PRIVATE "FF_PACKAGES_DISABLE_LIST=${PACKAGES_DISABLE_LIST}")
if(PACKAGES_REMOVE_DISABLED)
target_compile_definitions(libfastfetch PRIVATE FF_PACKAGES_REMOVE_DISABLED=1)
endif()
######################
# Executable targets #
@@ -2015,12 +2152,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
@@ -34,7 +34,7 @@ void ffBase64EncodeRaw(uint32_t size, const char* str, uint32_t* out_size, char*
static uint8_t decode_table[256];
void init_decode_table() {
static void init_decode_table() {
uint8_t ch = 0;
do {
int32_t code = -1;
+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>
+388 -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,346 @@ 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_pushlstring(L, (const char*) arg->value, strlen((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 {
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 +469,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 +613,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 +643,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 +670,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 +696,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 +716,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);
+233
View File
@@ -0,0 +1,233 @@
#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, int depth) {
if (__builtin_expect(depth > 15, false)) {
yyjson_mut_doc_free(doc);
lua_pushlstring(
L, "yyjson: recursion depth exceeded; possible circular reference", strlen("yyjson: recursion depth exceeded; possible circular reference"));
lua_error(L); // noreturn
__builtin_unreachable();
}
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, depth + 1);
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, depth + 1);
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 (__builtin_expect(!doc, false)) {
lua_pushlstring(L, "yyjson: yyjson_mut_doc_new() failed", strlen("yyjson: yyjson_mut_doc_new() failed"));
return lua_error(L);
}
yyjson_mut_val* root = lua2yyjson(L, 1, doc, 0);
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 (__builtin_expect(jsonStr != NULL, true)) {
lua_pushlstring(L, jsonStr, jsonLen);
yyjson_mut_doc_free(doc);
return 1;
} else {
yyjson_mut_doc_free(doc);
{
FF_STRBUF_AUTO_DESTROY errBuf = ffStrbufCreateStatic("yyjson: yyjson_mut_write_opts() failed: ");
ffStrbufAppendS(&errBuf, err.msg);
lua_pushlstring(L, errBuf.chars, errBuf.length);
}
return lua_error(L); // longjmp
}
}
const char* ffLuaLoadState(void) {
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
#if !FF_DISABLE_DLOPEN
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(liblua, luaData, luaL_checkany)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(liblua, luaData, luaL_loadbufferx)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(liblua, luaData, luaL_tolstring)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(liblua, luaData, lua_callk)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(liblua, luaData, lua_createtable)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(liblua, luaData, lua_error)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(liblua, luaData, lua_gettop)
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_pcallk)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(liblua, luaData, lua_pushboolean)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(liblua, luaData, lua_pushcclosure)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(liblua, luaData, lua_pushinteger)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(liblua, luaData, lua_pushlstring)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(liblua, luaData, lua_pushnil)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(liblua, luaData, lua_pushnumber)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(liblua, luaData, lua_pushvalue)
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_setfield)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(liblua, luaData, lua_setglobal)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(liblua, luaData, lua_seti)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(liblua, luaData, lua_settop)
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_tolstring)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(liblua, luaData, lua_tonumberx)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(liblua, luaData, lua_type)
#endif
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;
+187
View File
@@ -0,0 +1,187 @@
#pragma once
#include "fastfetch.h"
#if FF_HAVE_LUA
#if !FF_DISABLE_DLOPEN
// 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"
#endif
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
#ifndef LUA_GNAME
#define LUA_GNAME "_G"
#endif
#include "common/library.h"
extern struct FFLuaData {
#if !FF_DISABLE_DLOPEN
FF_LIBRARY_SYMBOL(luaL_checkany)
FF_LIBRARY_SYMBOL(luaL_loadbufferx)
FF_LIBRARY_SYMBOL(luaL_tolstring)
FF_LIBRARY_SYMBOL(lua_callk)
FF_LIBRARY_SYMBOL(lua_createtable)
FF_LIBRARY_SYMBOL(lua_error)
FF_LIBRARY_SYMBOL(lua_gettop)
FF_LIBRARY_SYMBOL(lua_isinteger)
FF_LIBRARY_SYMBOL(lua_next)
FF_LIBRARY_SYMBOL(lua_pcallk)
FF_LIBRARY_SYMBOL(lua_pushboolean)
FF_LIBRARY_SYMBOL(lua_pushcclosure)
FF_LIBRARY_SYMBOL(lua_pushinteger)
FF_LIBRARY_SYMBOL(lua_pushlstring)
FF_LIBRARY_SYMBOL(lua_pushnil)
FF_LIBRARY_SYMBOL(lua_pushnumber)
FF_LIBRARY_SYMBOL(lua_pushvalue)
FF_LIBRARY_SYMBOL(lua_rawgeti)
FF_LIBRARY_SYMBOL(lua_rawlen)
FF_LIBRARY_SYMBOL(lua_setfield)
FF_LIBRARY_SYMBOL(lua_setglobal)
FF_LIBRARY_SYMBOL(lua_seti)
FF_LIBRARY_SYMBOL(lua_settop)
FF_LIBRARY_SYMBOL(lua_toboolean)
FF_LIBRARY_SYMBOL(lua_tointegerx)
FF_LIBRARY_SYMBOL(lua_tolstring)
FF_LIBRARY_SYMBOL(lua_tonumberx)
FF_LIBRARY_SYMBOL(lua_type)
#endif
lua_State* L;
bool inited;
} luaData;
#if !FF_DISABLE_DLOPEN
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_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);
}
FF_A_ALWAYS_INLINE int(lua_error)(lua_State* L) {
return luaData.fflua_error(L);
}
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
#if LUA_VERSION_NUM > 503
lua_Unsigned
#else
size_t
#endif
(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
const char* ffLuaLoadState(void);
#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);
}
+43
View File
@@ -0,0 +1,43 @@
#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_MAX = FF_CODEC_TYPE_PRORES_RAW,
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[] = {
{ 'h263', FF_CODEC_TYPE_H263 }, // kCMVideoCodecType_H263
{ 'jpeg', FF_CODEC_TYPE_MJPEG }, // kCMVideoCodecType_JPEG
{ 'dmb1', FF_CODEC_TYPE_MJPEG }, // kCMVideoCodecType_JPEG_OpenDML
{ 'mp1v', FF_CODEC_TYPE_MPEG1 }, // kCMVideoCodecType_MPEG1Video
{ 'mp2v', FF_CODEC_TYPE_MPEG2 }, // kCMVideoCodecType_MPEG2Video
{ 'mp4v', FF_CODEC_TYPE_DIVX_XVID }, // kCMVideoCodecType_MPEG4Video
{ 'avc1', FF_CODEC_TYPE_H264 }, // kCMVideoCodecType_H264
{ 'hvc1', FF_CODEC_TYPE_HEVC }, // kCMVideoCodecType_HEVC
{ 'muxa', FF_CODEC_TYPE_HEVC }, // kCMVideoCodecType_HEVCWithAlpha
{ 'dvh1', FF_CODEC_TYPE_DOLBY_VISION_HEVC }, // kCMVideoCodecType_DolbyVisionHEVC
{ 'dish', FF_CODEC_TYPE_HEVC }, // kCMVideoCodecType_DisparityHEVC
{ 'deph', FF_CODEC_TYPE_HEVC }, // kCMVideoCodecType_DepthHEVC
{ 'vp09', FF_CODEC_TYPE_VP9 }, // kCMVideoCodecType_VP9
{ 'av01', FF_CODEC_TYPE_AV1 }, // kCMVideoCodecType_AV1
{ 'ap4x', FF_CODEC_TYPE_PRORES }, // kCMVideoCodecType_AppleProRes4444XQ
{ 'ap4h', FF_CODEC_TYPE_PRORES }, // kCMVideoCodecType_AppleProRes4444
{ 'apch', FF_CODEC_TYPE_PRORES }, // kCMVideoCodecType_AppleProRes422HQ
{ 'apcn', FF_CODEC_TYPE_PRORES }, // kCMVideoCodecType_AppleProRes422
{ 'apcs', FF_CODEC_TYPE_PRORES }, // kCMVideoCodecType_AppleProRes422LT
{ 'apco', FF_CODEC_TYPE_PRORES }, // kCMVideoCodecType_AppleProRes422Proxy
{ 'aprn', FF_CODEC_TYPE_PRORES_RAW }, // kCMVideoCodecType_AppleProResRAW
{ 'aprh', FF_CODEC_TYPE_PRORES_RAW }, // kCMVideoCodecType_AppleProResRAWHQ
};
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;

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