Compare commits

...

98 Commits

Author SHA1 Message Date
Carter Li b79a336576 Release: 2.65.1
Revision to make github happy
2026-06-24 10:21:03 +08:00
Carter Li d36e3a793b Merge pull request #2410 from fastfetch-cli/dev
Release v2.65.0
2026-06-23 20:39:21 -05:00
Carter Li d48bb48e4f Codec (Linux): fixes potential memleaks 2026-06-24 08:45:45 +08:00
李通洲 835001eb2f Doc: updates changelog 2026-06-23 15:51:42 +08:00
李通洲 5647703e4d WM (Linux): adds weston detection support 2026-06-23 15:51:42 +08:00
李通洲 eff0108bb5 Codec (Linux): adds va-x11 method 2026-06-23 15:33:58 +08:00
Carter Li 31c1431ac6 Release: v2.65.0 2026-06-23 13:16:49 +08:00
Carter Li fa2c56cb9f Global: fixes bugs found by CI
The code quality is to be improved...
2026-06-23 13:16:49 +08:00
Carter Li 104b33c1f7 Display: defaults disableLinewrap to false 2026-06-23 11:05:11 +08:00
Gretagen ZETA cb4502dacc Logo (Builtin): adds Zerene OS mainline (#2404)
* Create zerene.txt

* Update z.inc

* Fixed z.inc

Changed the problematic line mismatch

* Update z.inc

* Update z.inc

more fixes to z.inc

* Remove duplicate name entry for Zerene logo

---------

Co-authored-by: Carter Li <CarterLi@users.noreply.github.com>
2026-06-22 20:24:55 +08:00
Carter Li 3dc86391ab Doc: update changelog [ci skip] 2026-06-22 16:11:44 +08:00
Carter Li f5a67b25f4 Packages (Linux): cleanups install-release package count code 2026-06-22 13:28:18 +08:00
Jess d8be61411e Packages (Linux): add install-release package count support (#2342)
* feat: add install-release package count support

* Apply suggestion from @codacy-production[bot]

Co-authored-by: codacy-production[bot] <61871480+codacy-production[bot]@users.noreply.github.com>

* Fix formatting of ffParsePropFileValues call

---------

Co-authored-by: Carter Li <CarterLi@users.noreply.github.com>
Co-authored-by: codacy-production[bot] <61871480+codacy-production[bot]@users.noreply.github.com>
2026-06-22 00:23:21 -05:00
Carter Li 61968ca95c Chore: tidy 2026-06-22 13:18:27 +08:00
Carter Li 9f190b46c9 DisplayServer (macOS): detects string serial number for Apple Silicon 2026-06-22 13:18:27 +08:00
Kerem Gökcek a6aac70a5e Packages (Linux): Improve emerge detection speed (#2406)
* Packages (Linux): Improve emerge detection speed

* Fix code styling
2026-06-21 21:56:01 -05:00
yabobay 3aa43212ff Packages (Linux): support porg 2026-06-22 10:45:08 +08:00
李通洲 7c39b64fb4 CMake: extracts package managers from source code 2026-06-20 19:24:19 +08:00
Carter Li e1963e41be Networking (Linux): don't use MSG_DONTWAIT to send HTTP request
Ref #2401
2026-06-20 10:17:04 +08:00
Carter Li a1d4cbf67f DisplayServer (Wayland): correctly reports platform api 2026-06-20 08:59:31 +08:00
Carter Li f5b9e09d91 DisplayServer (macOS): detects string serial number 2026-06-20 01:21:39 +08:00
Carter Li 9742dda795 Wifi (FreeBSD): adds WPA version detection support 2026-06-19 23:30:01 +08:00
Carter Li 677c213397 Codec (Linux): fixes bug in ffDetectCodecByVdpau 2026-06-19 23:02:13 +08:00
李通洲 8f0a12323b Doc: updates changelog 2026-06-19 20:30:32 +08:00
李通洲 b49f0b3d9c Fastfetch: improves error message for config errors 2026-06-19 20:19:50 +08:00
李通洲 bc686b2c84 Logo: improves error message for chafa options 2026-06-19 20:14:58 +08:00
Carter Li 7c2f7fa4f2 DisplayServer (Linux): detects preferred resolution from EDID 2026-06-19 19:21:00 +08:00
Carter Li 5fd059827d Display: fetch text serial if available instead of the 4-byte integer 2026-06-19 18:56:08 +08:00
Carter Li 240928138e GPU: adds egl-ext detection method 2026-06-18 21:03:28 +08:00
Carter Li 508a50f803 OpenGL (EGL): optimises code 2026-06-18 21:03:28 +08:00
Carter Li bd40d8756e GPU (FreeBSD): adds a missing var-init 2026-06-18 19:33:40 +08:00
Carter Li b732e0c6d7 Codec (Linux): fixes a crash 2026-06-18 18:11:48 +08:00
Carter Li 96685b7ebe Global: cleanups FF_HAVE_DRM macro 2026-06-18 17:45:19 +08:00
Carter Li 49a1e42efd CI: updates spellcheck 2026-06-18 13:39:56 +08:00
Carter Li b0fd11fcbd Global: simplifies code 2026-06-18 10:59:36 +08:00
Carter Li b6127ff2c9 Codec (Linux): removes usage of libdrm 2026-06-18 10:56:28 +08:00
Carter Li f3babe3187 Codec (Linux): fixes memleaks 2026-06-18 10:44:11 +08:00
Carter Li e9c0d886d1 DisplayServer (Linux): be compatible with KDE 6.7
This PR also removes usage of `kde-output-order-v1-protocol`, which disables detection of primary monitor for old KDE versions
2026-06-18 10:31:37 +08:00
Carter Li d6a4946511 DisplayServer (Linux): fixes memleaks 2026-06-18 10:06:52 +08:00
Carter Li 43e0cc22ff GPU: initializes pcieSpeed everywhere 2026-06-18 08:44:01 +08:00
Carter Li c42ea6eeea DisplayServer (Linux): adds HDR detection support
Fixes #2356
2026-06-17 20:07:37 +08:00
Carter Li fe7962d5d2 DisplayServer (Linux): embeds definitions of wl-output-* 2026-06-17 15:32:27 +08:00
Carter Li e84195bca0 Linux (Wayland): drops zwlr-output.c
It doesn't expose much more functions than `wl-output`
2026-06-17 15:10:24 +08:00
Carter Li bf0133fe60 Packaging: updates debian stuff [ci skip] 2026-06-17 15:06:15 +08:00
李通洲 942c15b7b0 CPU (X86): fixes detection for AMD Carrizo
Ref: https://github.com/anrieff/libcpuid/commit/b0c4959cf4a8b8351ab33add3f83ee0dcf37faf1
2026-06-15 18:41:48 +08:00
Carter Li 61a0bbcc8d GPU (Linux): fixes building for old kernel headers 2026-06-14 19:51:30 +08:00
Carter Li 8b3673eb38 GPU (Nvidia): replaces deprecated API nvmlDeviceGetTemperature with suggested one 2026-06-14 19:51:30 +08:00
Carter Li 22f9948497 GPU: detect current pcie link speed 2026-06-14 19:51:30 +08:00
李通洲 107f39eb15 JsonSchema: update moduleFormat 2026-06-14 19:51:30 +08:00
Carter Li 4e44c0520b GPU: detects max PCI gen & link width 2026-06-14 19:51:29 +08:00
Carter Li 55eb3c59d4 GPU (Linux): replaces amdgpu library with raw ioctl calls 2026-06-14 19:51:29 +08:00
Carter Li 878ccf1375 DisplayServer (Linux): use kernel headers if libdrm is not available 2026-06-13 12:29:51 +08:00
Carter Li ebb0cf77bd CMake: checks linux kernel headers 2026-06-13 12:29:51 +08:00
Carter Li 17914dc29e Global: unifies FF_STR macro 2026-06-13 12:29:51 +08:00
李通洲 14dfe171fb GPU (OpenBSD): adds DRM method 2026-06-13 12:29:51 +08:00
Carter Li 265c334399 GPU (FreeBSD): moves DRM detection to global space for OpenBSD use 2026-06-13 12:29:51 +08:00
Carter Li fc303c58db GPU: adds unified ffGPUFillVendorByDeviceName 2026-06-13 12:29:51 +08:00
Carter Li 01e7503263 GPU (BSD): uses direct ioctl calls (WIP) 2026-06-13 12:29:50 +08:00
Carter Li ffd0455fe3 DisplayServer (Linux): rewrites libdrm calls with plain ioctls 2026-06-12 14:34:36 +08:00
Carter Li 7df2ed2251 Packages: reorders package variables in custom format 2026-06-12 14:34:36 +08:00
Carter Li 2edc41dd9a CI (OpenBSD): updates packages 2026-06-11 15:14:39 +08:00
Carter Li cada77163e Chore: update .gitignore 2026-06-11 15:07:47 +08:00
Carter Li 7cecdb0e6d DisplayServer (Linux): don't return success if no devices are successfully connected 2026-06-11 10:49:07 +08:00
Carter Li 420a9e9d7b TerminalFont (Linux): adds kmscon support
Fixes #2393
2026-06-11 10:49:00 +08:00
Carter Li b96d8ad00b Terminal (Linux): adds kmscon version detection support 2026-06-11 10:15:50 +08:00
Carter Li 52970e2d13 Processing (Linux): don't use /proc/pid/exe as exePath when the file is not executable (no permission) 2026-06-11 10:15:50 +08:00
Carter Li 4594734b66 CI (OpenBSD): updates OS version 2026-06-09 16:07:56 +08:00
Carter Li eb54c89b4a OS (macOS): adds the code name of macOS 27 2026-06-09 14:05:23 +08:00
Carter Li 43301afc47 CPU: enables showPeCoreCount by default 2026-06-09 14:04:54 +08:00
Carter Li 09e28451ec CPU (Linux): simplifies code of frequency detection 2026-06-09 13:38:49 +08:00
Carter Li 35c2f8c924 CPU (Linux): fixes physical core detection on non-x86 2026-06-09 13:09:58 +08:00
李通洲 3ec7e94b47 CPU (Windows): uses a better way to fetch core types 2026-06-08 19:03:23 +08:00
Carter Li a720e1f945 Fastfetch (Windows): moves SetConsoleMode and SetConsoleOutputCP to the start of process
Fixes #2383
2026-06-08 10:58:14 +08:00
Carter Li 70061625f7 Chore: adds FF_A_COLD 2026-06-08 10:38:28 +08:00
李通洲 5cd4316f98 CPU (X86): uses normalized cpu brand name for pattern matching 2026-06-08 00:41:08 +08:00
李通洲 e946861eb0 Codec (Windows): fixes compatibility of Win 8.1 2026-06-08 00:41:01 +08:00
李通洲 f09aebecd5 CPU (X86): updates comments 2026-06-07 16:48:15 +08:00
李通洲 8f266eb2a7 Chore: don't check spelling in cpu_x86.c 2026-06-07 16:41:59 +08:00
李通洲 8ee08d0067 CI: don't run heavy tests if the light one failed 2026-06-07 16:40:40 +08:00
李通洲 e936ddef6b CPU (X86): adds code name and tech detection
Fixes #1501
2026-06-07 10:46:37 +08:00
李通洲 c706201282 Global: adds some always_inline 2026-06-06 23:01:18 +08:00
李通洲 e24e3b6b29 Global: returns false when an error is printed 2026-06-05 22:34:53 +08:00
李通洲 135547fd50 Logo: don't accept chafa options when chafa is disabled 2026-06-05 22:19:35 +08:00
李通洲 da05bed32f CMake: exposes pre-defined macros to fastfetch.c to avoid imcompatiblity with libfastfetch 2026-06-05 22:19:35 +08:00
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
114 changed files with 7385 additions and 3140 deletions
+2 -2
View File
@@ -1,5 +1,5 @@
[codespell]
check-filenames =
builtin = clear,rare,usage,informal
skip = */.git,*/cmake-build-*,*/.idea,*/completions,*/presets,*/screenshots,*/tests,*/3rdparty,*/logo/ascii,./src/detection/gpu/asahi_drm.h
ignore-words-list = iterm,compiletime,unknwn,pengwin,siduction,master,slave,sur,doas,conexant,ags,bu
skip = */.git,*/cmake-build-*,*/.idea,*/completions,*/presets,*/screenshots,*/tests,*/3rdparty,*/logo/ascii,./src/detection/gpu/asahi_drm.h,./src/detection/cpu/cpu_x86.c,./src/detection/gpu/gpu_bsddrm.c,./src/detection/displayserver/linux/wayland/*-protocol.*,./build,./build-*,./build_*
ignore-words-list = iterm,compiletime,unknwn,pengwin,siduction,master,slave,sur,doas,conexant,ags,bu,renderD,SME,Carmel,kinda
+2 -2
View File
@@ -20,12 +20,12 @@ jobs:
architecture: x86-64
cpu_count: 4
shell: bash
version: '7.8'
version: '7.9'
environment_variables: 'CMAKE_BUILD_TYPE'
run: |
uname -a
sudo pkg_add -u
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
sudo pkg_add -r llvm-21.1.8p4 cmake git wayland vulkan-headers vulkan-loader glib2 dconf dbus sqlite3 imagemagick chafa lua-5.4.8p0 # 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
+2 -5
View File
@@ -3,9 +3,6 @@ name: Reusable Spellcheck
on:
workflow_call:
env:
CMAKE_BUILD_TYPE: ${{ vars.CMAKE_BUILD_TYPE || 'RelWithDebInfo' }}
jobs:
spellcheck:
runs-on: ubuntu-latest
@@ -17,8 +14,8 @@ jobs:
- name: Install codespell
shell: bash
run: |
sudo apt-get update || true
sudo apt-get install -y codespell
pip3 install codespell
codespell --version
- name: Run Spellchecker
run: codespell
+16
View File
@@ -9,6 +9,7 @@ jobs:
uses: ./.github/workflows/build-spellcheck.yml
no-features-test:
needs: spellcheck
name: No-features-test
permissions:
security-events: write
@@ -17,6 +18,7 @@ jobs:
secrets: inherit
linux-hosts:
needs: no-features-test
name: Linux-${{ matrix.arch }}
permissions:
security-events: write
@@ -35,6 +37,7 @@ jobs:
secrets: inherit
linux-i686:
needs: no-features-test
name: Linux-i686
permissions:
security-events: write
@@ -43,6 +46,7 @@ jobs:
secrets: inherit
linux-armv7l:
needs: no-features-test
name: Linux-armv7l
permissions:
security-events: write
@@ -51,6 +55,7 @@ jobs:
secrets: inherit
linux-armv6l:
needs: no-features-test
name: Linux-armv6l
permissions:
security-events: write
@@ -59,6 +64,7 @@ jobs:
secrets: inherit
linux-vms:
needs: no-features-test
name: Linux-${{ matrix.arch }}
permissions:
security-events: write
@@ -75,11 +81,13 @@ jobs:
secrets: inherit
musl-amd64:
needs: no-features-test
name: Musl-amd64
uses: ./.github/workflows/build-musl-amd64.yml
secrets: inherit
macos-hosts:
needs: no-features-test
name: macOS-${{ matrix.arch }}
permissions:
security-events: write
@@ -98,16 +106,19 @@ jobs:
secrets: inherit
omnios-amd64:
needs: no-features-test
name: OmniOS-amd64
uses: ./.github/workflows/build-omnios-amd64.yml
secrets: inherit
solaris-amd64:
needs: no-features-test
name: Solaris-amd64
uses: ./.github/workflows/build-solaris-amd64.yml
secrets: inherit
freebsd-amd64:
needs: no-features-test
name: FreeBSD-amd64
permissions:
security-events: write
@@ -116,6 +127,7 @@ jobs:
secrets: inherit
openbsd-amd64:
needs: no-features-test
name: OpenBSD-amd64
permissions:
security-events: write
@@ -124,6 +136,7 @@ jobs:
secrets: inherit
netbsd-amd64:
needs: no-features-test
name: NetBSD-amd64
permissions:
security-events: write
@@ -132,6 +145,7 @@ jobs:
secrets: inherit
dragonfly-amd64:
needs: no-features-test
name: DragonFly-amd64
permissions:
security-events: write
@@ -140,6 +154,7 @@ jobs:
secrets: inherit
haiku-amd64:
needs: no-features-test
name: Haiku-amd64
permissions:
security-events: write
@@ -148,6 +163,7 @@ jobs:
secrets: inherit
windows-hosts:
needs: no-features-test
name: Windows-${{ matrix.arch }}
permissions:
security-events: write
+7 -5
View File
@@ -1,8 +1,10 @@
build/
.vs/
.vscode/
.cache/
.kdev4/
/build/
/build_*/
/build-*/
/.vs/
/.vscode/
/.cache/
/.kdev4/
.DS_Store
cscope.*
tags
+56
View File
@@ -1,3 +1,59 @@
# 2.65.0
Changes:
* `display.disableLinewrap` now defaults to `false`.
* This allows long lines to wrap instead of being truncated, preventing confusion for new users.
* Wrapped lines may overlap with the image logo. Users who prefer the old behavior can set `display.disableLinewrap: true` in their config file or use `--disable-linewrap true` on the command line.
* Reorders package manager variables in custom format strings, moving aggregate variables (e.g., `all`, `brew-all`, `flatpak-all`) to the end. (Packages)
* This is a breaking change for users relying on numeric placeholders (e.g., `{1}`). Numeric placeholders are a long-deprecated feature; named placeholders (e.g., `{pacman}`) are always preferred and future-proof.
* Enables `showPeCoreCount` by default to better display hybrid-architecture core counts. (CPU)
* No longer accepts `chafa` options in config files if `chafa` support was disabled at compile time. (Logo)
* This may affect users who generated their config files using `fastfetch --gen-full-config`. To resolve this, simply remove the `chafa` section from the config file.
Features:
* Adds detection for CPU code names (e.g., "Alder Lake", "Zen 4") and manufacturing technologies (e.g., "Intel 7", "TSMC N4") on x86 processors. (#1501, CPU, X86)
* These can be used in custom formats via `{code-name}` and `{technology}`.
* Adds PCIe link speed detection (current and max generation & lanes) for GPUs on Linux and Windows.
* These can be used in custom formats via `{pcie-max-speed}` and `{pcie-curr-speed}`.
* Adds HDR display detection via the `wp-color-management-v1` Wayland protocol. (#2356, Display, Linux)
* Previously, HDR detection was only supported on KDE Plasma.
* Adds the `egl-ext` detection method, which uses `EGL_EXT_device_enumeration` for GPU enumeration. (GPU)
* Adds terminal version and font detection for `kmscon`. (#2393, Terminal / TerminalFont, Linux)
* Adds the currently-in-beta code name "Golden Gate" for macOS 27. (OS, macOS)
* Adds WPA version detection on FreeBSD. (Wifi, FreeBSD)
* Adds package manager support for `porg` (#2405) and `install-release` (#2342). (Packages, Linux)
* Adds Weston version detection. (WM, Linux)
* Improves the core type (P-Core/E-Core) fetching mechanism on Windows by using `EfficiencyClass` instead of legacy frequency inference. (CPU, Windows)
* Improves display detection compatibility with KDE 6.7. (Display, Linux)
* Improves display serial number detection, now preferring alphanumeric serial numbers when available. (Display)
* This can be used in custom formats via `{serial}`.
* Improves the performance of `emerge` package manager detection. (#2406, Packages, Linux)
* Improves error messages for config file parsing errors.
* Improves reliability of the `Codec` module on Linux (Codec, Linux)
* Adds `va-x11` backend for VA-API and VDPAU, which is used if `va-drm` backend fails to initialize.
* Fixes an issue where the Codec module incorrectly reports no results when the `codec.showType` option is set.
Bugfixes:
* Fixes physical core detection on non-x86 architectures and simplifies the frequency detection code. (CPU, Linux)
* Fixes console mode and output code page initialization issues when running `fastfetch` in `Conhost`. (#2383, Windows)
* Fixes public IP detection randomly failing on Linux. (#2401, PublicIP, Linux)
* Fixes several memory leaks.
Logos:
* Adds Zerene OS. (#2404)
# 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:
+66 -73
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.64.1
VERSION 2.65.1
LANGUAGES C
DESCRIPTION "Fast neofetch-like system information tool"
HOMEPAGE_URL "https://github.com/fastfetch-cli/fastfetch"
@@ -63,6 +63,13 @@ endif()
include(CheckIncludeFile)
if(LINUX)
CHECK_INCLUDE_FILE("linux/version.h" HAVE_LINUX_VERSION_H)
if(NOT HAVE_LINUX_VERSION_H)
message(FATAL_ERROR "Linux headers (linux/version.h) not found! Please install linux-headers package.")
endif()
endif()
#####################
# Configure options #
#####################
@@ -70,13 +77,13 @@ include(CheckIncludeFile)
include(CMakeDependentOption)
cmake_dependent_option(ENABLE_VULKAN "Enable vulkan" ON "LINUX OR APPLE OR FreeBSD OR OpenBSD OR NetBSD OR WIN32 OR ANDROID OR SunOS OR Haiku OR GNU" OFF)
cmake_dependent_option(ENABLE_WAYLAND "Enable wayland-client" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR GNU" OFF)
cmake_dependent_option(ENABLE_WAYLAND "Enable wayland-client" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD" OFF)
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_VADRM "Enable libva-drm" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR SunOS OR GNU" OFF)
cmake_dependent_option(ENABLE_VAX11 "Enable libva-x11" 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)
cmake_dependent_option(ENABLE_EET "Enable eet" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR ANDROID OR SunOS OR GNU" OFF)
@@ -134,25 +141,10 @@ 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 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)
file(READ "${CMAKE_CURRENT_SOURCE_DIR}/src/modules/packages/option.h" PACKAGE_MANAGERS)
string(REGEX MATCHALL "FF_PACKAGES_FLAG_[A-Z]+_BIT" PACKAGE_MANAGERS "${PACKAGE_MANAGERS}")
string(REGEX REPLACE "FF_PACKAGES_FLAG_([A-Z]+)_BIT" "\\1" PACKAGE_MANAGERS "${PACKAGE_MANAGERS}")
list(SORT PACKAGE_MANAGERS)
foreach(package_manager ${PACKAGE_MANAGERS})
if(package_manager STREQUAL "WINGET")
option(PACKAGES_DISABLE_${package_manager} "Disable ${package_manager} package manager detection by default" ON)
@@ -327,7 +319,7 @@ if(Python_FOUND)
endif()
else()
message(WARNING "Python3 is not found, 'help.json' will not be minified")
file(READ "doc/help.json" DATATEXT_JSON_HELP)
file(READ "${CMAKE_CURRENT_SOURCE_DIR}/doc/help.json" DATATEXT_JSON_HELP)
endif()
if(ENABLE_EMBEDDED_PCIIDS AND NOT EXISTS "${PROJECT_BINARY_DIR}/fastfetch_pciids.c.inc")
@@ -447,6 +439,7 @@ set(LIBFASTFETCH_SRC
src/detection/codec/codec.c
src/detection/codec/codec_vulkan.c
src/detection/cpu/cpu.c
src/detection/cpu/cpu_x86.c
src/detection/cpuusage/cpuusage.c
src/detection/command/command.c
src/detection/disk/disk.c
@@ -591,11 +584,10 @@ if(LINUX)
src/detection/displayserver/linux/drm.c
src/detection/displayserver/linux/wayland/wayland.c
src/detection/displayserver/linux/wayland/global-output.c
src/detection/displayserver/linux/wayland/zwlr-output.c
src/detection/displayserver/linux/wayland/wl-output-protocol.c
src/detection/displayserver/linux/wayland/wp-color-management-v1-protocol.c
src/detection/displayserver/linux/wayland/kde-output.c
src/detection/displayserver/linux/wayland/wlr-output-management-unstable-v1-protocol.c
src/detection/displayserver/linux/wayland/kde-output-device-v2-protocol.c
src/detection/displayserver/linux/wayland/kde-output-order-v1-protocol.c
src/detection/displayserver/linux/wayland/xdg-output-unstable-v1-protocol.c
src/detection/displayserver/linux/wmde.c
src/detection/displayserver/linux/xcb.c
@@ -752,11 +744,10 @@ elseif(FreeBSD)
src/detection/displayserver/linux/drm.c
src/detection/displayserver/linux/wayland/wayland.c
src/detection/displayserver/linux/wayland/global-output.c
src/detection/displayserver/linux/wayland/zwlr-output.c
src/detection/displayserver/linux/wayland/kde-output.c
src/detection/displayserver/linux/wayland/wlr-output-management-unstable-v1-protocol.c
src/detection/displayserver/linux/wayland/wl-output-protocol.c
src/detection/displayserver/linux/wayland/wp-color-management-v1-protocol.c
src/detection/displayserver/linux/wayland/kde-output-device-v2-protocol.c
src/detection/displayserver/linux/wayland/kde-output-order-v1-protocol.c
src/detection/displayserver/linux/wayland/xdg-output-unstable-v1-protocol.c
src/detection/displayserver/linux/wmde.c
src/detection/displayserver/linux/xcb.c
@@ -765,6 +756,7 @@ elseif(FreeBSD)
src/detection/gpu/gpu_bsd.c
src/detection/gpu/gpu_drm.c
src/detection/gpu/gpu_pci.c
src/detection/gpu/gpu_bsddrm.c
src/detection/gtk_qt/gtk.c
src/detection/host/host_bsd.c
src/detection/lm/lm_linux.c
@@ -847,11 +839,10 @@ elseif(NetBSD)
src/detection/displayserver/linux/drm.c
src/detection/displayserver/linux/wayland/wayland.c
src/detection/displayserver/linux/wayland/global-output.c
src/detection/displayserver/linux/wayland/zwlr-output.c
src/detection/displayserver/linux/wayland/kde-output.c
src/detection/displayserver/linux/wayland/wlr-output-management-unstable-v1-protocol.c
src/detection/displayserver/linux/wayland/wl-output-protocol.c
src/detection/displayserver/linux/wayland/wp-color-management-v1-protocol.c
src/detection/displayserver/linux/wayland/kde-output-device-v2-protocol.c
src/detection/displayserver/linux/wayland/kde-output-order-v1-protocol.c
src/detection/displayserver/linux/wayland/xdg-output-unstable-v1-protocol.c
src/detection/displayserver/linux/wmde.c
src/detection/displayserver/linux/xcb.c
@@ -932,11 +923,10 @@ elseif(OpenBSD)
src/detection/displayserver/linux/drm.c
src/detection/displayserver/linux/wayland/wayland.c
src/detection/displayserver/linux/wayland/global-output.c
src/detection/displayserver/linux/wayland/zwlr-output.c
src/detection/displayserver/linux/wayland/kde-output.c
src/detection/displayserver/linux/wayland/wlr-output-management-unstable-v1-protocol.c
src/detection/displayserver/linux/wayland/wl-output-protocol.c
src/detection/displayserver/linux/wayland/wp-color-management-v1-protocol.c
src/detection/displayserver/linux/wayland/kde-output-device-v2-protocol.c
src/detection/displayserver/linux/wayland/kde-output-order-v1-protocol.c
src/detection/displayserver/linux/wayland/xdg-output-unstable-v1-protocol.c
src/detection/displayserver/linux/wmde.c
src/detection/displayserver/linux/xcb.c
@@ -944,6 +934,8 @@ elseif(OpenBSD)
src/detection/font/font_linux.c
src/detection/gpu/gpu_pci.c
src/detection/gpu/gpu_obsd.c
src/detection/gpu/gpu_drm.c
src/detection/gpu/gpu_bsddrm.c
src/detection/gtk_qt/gtk.c
src/detection/host/host_obsd.c
src/detection/lm/lm_nosupport.c
@@ -1175,11 +1167,10 @@ elseif(SunOS)
src/detection/displayserver/linux/drm.c
src/detection/displayserver/linux/wayland/wayland.c
src/detection/displayserver/linux/wayland/global-output.c
src/detection/displayserver/linux/wayland/zwlr-output.c
src/detection/displayserver/linux/wayland/kde-output.c
src/detection/displayserver/linux/wayland/wlr-output-management-unstable-v1-protocol.c
src/detection/displayserver/linux/wayland/wl-output-protocol.c
src/detection/displayserver/linux/wayland/wp-color-management-v1-protocol.c
src/detection/displayserver/linux/wayland/kde-output-device-v2-protocol.c
src/detection/displayserver/linux/wayland/kde-output-order-v1-protocol.c
src/detection/displayserver/linux/wayland/xdg-output-unstable-v1-protocol.c
src/detection/displayserver/linux/wmde.c
src/detection/displayserver/linux/xcb.c
@@ -1325,12 +1316,9 @@ elseif(GNU)
src/detection/physicalmemory/physicalmemory_nosupport.c
src/detection/diskio/diskio_nosupport.c
src/detection/displayserver/linux/displayserver_linux.c
src/detection/displayserver/linux/wayland/wayland.c
src/detection/displayserver/linux/common.c
src/detection/displayserver/linux/drm.c
src/detection/displayserver/linux/wayland/wayland.c
src/detection/displayserver/linux/wayland/global-output.c
src/detection/displayserver/linux/wayland/zwlr-output.c
src/detection/displayserver/linux/wayland/wlr-output-management-unstable-v1-protocol.c
src/detection/displayserver/linux/wmde.c
src/detection/displayserver/linux/xcb.c
src/detection/displayserver/linux/xlib.c
@@ -1576,24 +1564,24 @@ endif()
if(NOT "${CUSTOM_PCI_IDS_PATH}" STREQUAL "")
message(STATUS "Custom file path of pci.ids: ${CUSTOM_PCI_IDS_PATH}")
target_compile_definitions(libfastfetch PRIVATE FF_CUSTOM_PCI_IDS_PATH=${CUSTOM_PCI_IDS_PATH})
target_compile_definitions(libfastfetch PUBLIC FF_CUSTOM_PCI_IDS_PATH=${CUSTOM_PCI_IDS_PATH})
endif()
if(NOT "${CUSTOM_AMDGPU_IDS_PATH}" STREQUAL "")
message(STATUS "Custom file path of amdgpu.ids: ${CUSTOM_AMDGPU_IDS_PATH}")
target_compile_definitions(libfastfetch PRIVATE FF_CUSTOM_AMDGPU_IDS_PATH=${CUSTOM_AMDGPU_IDS_PATH})
target_compile_definitions(libfastfetch PUBLIC FF_CUSTOM_AMDGPU_IDS_PATH=${CUSTOM_AMDGPU_IDS_PATH})
endif()
if(NOT "${CUSTOM_OS_RELEASE_PATH}" STREQUAL "")
message(STATUS "Custom file path of os_release: ${CUSTOM_OS_RELEASE_PATH}")
target_compile_definitions(libfastfetch PRIVATE FF_CUSTOM_OS_RELEASE_PATH=${CUSTOM_OS_RELEASE_PATH})
target_compile_definitions(libfastfetch PUBLIC FF_CUSTOM_OS_RELEASE_PATH=${CUSTOM_OS_RELEASE_PATH})
endif()
if(NOT "${CUSTOM_LSB_RELEASE_PATH}" STREQUAL "")
message(STATUS "Custom file path of lsb_release: ${CUSTOM_LSB_RELEASE_PATH}")
target_compile_definitions(libfastfetch PRIVATE FF_CUSTOM_LSB_RELEASE_PATH=${CUSTOM_LSB_RELEASE_PATH})
target_compile_definitions(libfastfetch PUBLIC FF_CUSTOM_LSB_RELEASE_PATH=${CUSTOM_LSB_RELEASE_PATH})
endif()
if(NOT BINARY_LINK_TYPE STREQUAL "dlopen")
message(STATUS "Enabling custom link type: ${BINARY_LINK_TYPE}")
target_compile_definitions(libfastfetch PRIVATE FF_DISABLE_DLOPEN=1)
target_compile_definitions(libfastfetch PUBLIC FF_DISABLE_DLOPEN=1)
if(NOT WIN32)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--copy-dt-needed-entries")
endif()
@@ -1638,6 +1626,11 @@ function(ff_lib_enable VARNAME PKGCONFIG_NAMES CMAKE_NAME) # [CMAKE_TARGET_NAME]
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})
@@ -1654,18 +1647,18 @@ function(ff_lib_enable VARNAME PKGCONFIG_NAMES CMAKE_NAME) # [CMAKE_TARGET_NAME]
message(STATUS "Library: found ${VARNAME} by ${${VARNAME}_FOUND}")
target_compile_definitions(libfastfetch PRIVATE FF_HAVE_${VARNAME}=1)
target_compile_definitions(libfastfetch PUBLIC FF_HAVE_${VARNAME}=1)
target_include_directories(libfastfetch PRIVATE ${${VARNAME}_INCLUDE_DIRS})
if(NOT BINARY_LINK_TYPE STREQUAL "dlopen")
target_link_directories(libfastfetch PUBLIC ${${VARNAME}_LIBRARY_DIRS})
target_link_directories(libfastfetch PRIVATE ${${VARNAME}_LIBRARY_DIRS})
target_link_libraries(libfastfetch PRIVATE ${${VARNAME}_LIBRARIES})
endif()
foreach(FLAG ${${VARNAME}_CFLAGS_OTHER})
if(FLAG MATCHES "-D.*")
string(SUBSTRING ${FLAG} 2 -1 FLAG)
target_compile_definitions(libfastfetch PRIVATE ${FLAG})
target_compile_definitions(libfastfetch PUBLIC ${FLAG})
endif()
endforeach()
endfunction()
@@ -1690,18 +1683,18 @@ ff_lib_enable(DRM
"libdrm"
"Libdrm"
)
ff_lib_enable(VA
"libva"
"Libva"
ff_lib_enable(VADRM
"libva-drm"
"Libva-drm"
)
ff_lib_enable(VAX11
"libva-x11"
"Libva-x11"
)
ff_lib_enable(VDPAU
"vdpau"
"vdpau"
)
ff_lib_enable(DRM_AMDGPU
"libdrm_amdgpu"
"Libdrm_Amdgpu"
)
ff_lib_enable(GIO
"gio-2.0"
"GIO"
@@ -1795,8 +1788,8 @@ if(ENABLE_LUA)
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})
target_compile_definitions(libfastfetch PUBLIC FF_HAVE_LUA=1)
target_include_directories(libfastfetch PUBLIC ${LUA_INCLUDE_DIR})
if(NOT BINARY_LINK_TYPE STREQUAL "dlopen")
target_link_libraries(libfastfetch PRIVATE ${LUA_LIBRARIES})
@@ -1809,20 +1802,20 @@ if(ENABLE_LUA)
endif()
if(ENABLE_THREADS)
target_compile_definitions(libfastfetch PRIVATE FF_HAVE_THREADS=1)
target_compile_definitions(libfastfetch PUBLIC FF_HAVE_THREADS=1)
if(CMAKE_USE_PTHREADS_INIT) #Threads::Threads is not set for WIN32
target_link_libraries(libfastfetch PRIVATE Threads::Threads)
endif()
endif()
if(ENABLE_EMBEDDED_PCIIDS)
target_compile_definitions(libfastfetch PRIVATE FF_HAVE_EMBEDDED_PCIIDS=1)
target_compile_definitions(libfastfetch PUBLIC FF_HAVE_EMBEDDED_PCIIDS=1)
endif()
if(ENABLE_EMBEDDED_AMDGPUIDS)
target_compile_definitions(libfastfetch PRIVATE FF_HAVE_EMBEDDED_AMDGPUIDS=1)
target_compile_definitions(libfastfetch PUBLIC FF_HAVE_EMBEDDED_AMDGPUIDS=1)
endif()
if(ENABLE_LIBZFS)
target_compile_definitions(libfastfetch PRIVATE FF_HAVE_LIBZFS=1)
target_compile_definitions(libfastfetch PUBLIC FF_HAVE_LIBZFS=1)
if(NOT BINARY_LINK_TYPE STREQUAL "dlopen")
target_link_libraries(libfastfetch
@@ -1979,7 +1972,7 @@ target_link_libraries(libfastfetch
PRIVATE ${CMAKE_DL_LIBS}
)
target_compile_options(libfastfetch PRIVATE
target_compile_options(libfastfetch PUBLIC
$<$<COMPILE_LANGUAGE:CXX>:-fno-exceptions -fno-rtti>)
if(FreeBSD)
@@ -1988,18 +1981,18 @@ endif()
if(LINUX OR FreeBSD OR OpenBSD OR NetBSD)
CHECK_INCLUDE_FILE("linux/videodev2.h" HAVE_LINUX_VIDEODEV2)
if(HAVE_LINUX_VIDEODEV2)
target_compile_definitions(libfastfetch PRIVATE FF_HAVE_LINUX_VIDEODEV2=1)
target_compile_definitions(libfastfetch PUBLIC FF_HAVE_LINUX_VIDEODEV2=1)
endif()
endif()
if(NOT WIN32)
CHECK_INCLUDE_FILE("utmpx.h" HAVE_UTMPX)
if(HAVE_UTMPX)
target_compile_definitions(libfastfetch PRIVATE FF_HAVE_UTMPX=1)
target_compile_definitions(libfastfetch PUBLIC FF_HAVE_UTMPX=1)
endif()
if(ENABLE_WORDEXP)
CHECK_INCLUDE_FILE("wordexp.h" HAVE_WORDEXP)
if(HAVE_WORDEXP)
target_compile_definitions(libfastfetch PRIVATE FF_HAVE_WORDEXP=1)
target_compile_definitions(libfastfetch PUBLIC FF_HAVE_WORDEXP=1)
message(STATUS "wordexp.h found, wordexp support enabled")
else()
set(ENABLE_WORDEXP OFF)
@@ -2011,19 +2004,19 @@ if(NOT WIN32)
if(ENABLE_THREADS AND CMAKE_USE_PTHREADS_INIT)
CHECK_INCLUDE_FILE("pthread_np.h" HAVE_PTHREAD_NP)
if(HAVE_PTHREAD_NP)
target_compile_definitions(libfastfetch PRIVATE FF_HAVE_PTHREAD_NP=1)
target_compile_definitions(libfastfetch PUBLIC FF_HAVE_PTHREAD_NP=1)
set(CMAKE_REQUIRED_INCLUDES ${CMAKE_REQUIRED_INCLUDES} pthread_np.h)
endif()
set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} Threads::Threads)
check_function_exists("pthread_timedjoin_np" HAVE_TIMEDJOIN_NP)
if(HAVE_TIMEDJOIN_NP)
target_compile_definitions(libfastfetch PRIVATE FF_HAVE_TIMEDJOIN_NP=1)
target_compile_definitions(libfastfetch PUBLIC FF_HAVE_TIMEDJOIN_NP=1)
else()
message(WARNING "pthread_timedjoin_np was not found; networking timeout will not work")
endif()
endif()
elseif(HAVE_WINRT)
target_compile_definitions(libfastfetch PRIVATE FF_HAVE_WINRT=1)
target_compile_definitions(libfastfetch PUBLIC FF_HAVE_WINRT=1)
endif()
set(PACKAGES_DISABLE_LIST "")
@@ -2040,9 +2033,9 @@ 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 PUBLIC "FF_PACKAGES_DISABLE_LIST=${PACKAGES_DISABLE_LIST}")
if(PACKAGES_REMOVE_DISABLED)
target_compile_definitions(libfastfetch PRIVATE FF_PACKAGES_REMOVE_DISABLED=1)
target_compile_definitions(libfastfetch PUBLIC FF_PACKAGES_REMOVE_DISABLED=1)
endif()
######################
+6
View File
@@ -1,3 +1,9 @@
fastfetch (2.64.2~#UBUNTU_CODENAME#) #UBUNTU_CODENAME#; urgency=medium
* Update to 2.64.2
-- Carter Li <zhangsongcui@live.cn> Mon, 08 Jun 2026 15:45:11 +0800
fastfetch (2.63.1~#UBUNTU_CODENAME#) #UBUNTU_CODENAME#; urgency=medium
* Update to 2.63.1
+7 -3
View File
@@ -322,7 +322,7 @@
"type": "string"
},
"cpuFormat": {
"description": "Output format for the `CPU` module. See Wiki for formatting syntax\n 1. {name}: Name\n 2. {vendor}: Vendor\n 3. {cores-physical}: Physical core count\n 4. {cores-logical}: Logical core count\n 5. {cores-online}: Online core count\n 6. {freq-base}: Base frequency (formatted)\n 7. {freq-max}: Max frequency (formatted)\n 8. {temperature}: Temperature (formatted)\n 9. {core-types}: Logical core count grouped by frequency\n 10. {packages}: Processor package count\n 11. {march}: CPU microarchitecture\n 12. {numa-nodes}: NUMA node count",
"description": "Output format for the `CPU` module. See Wiki for formatting syntax\n 1. {name}: Name\n 2. {vendor}: Vendor\n 3. {cores-physical}: Physical core count\n 4. {cores-logical}: Logical core count\n 5. {cores-online}: Online core count\n 6. {freq-base}: Base frequency (formatted)\n 7. {freq-max}: Max frequency (formatted)\n 8. {temperature}: Temperature (formatted)\n 9. {core-types}: Logical core count grouped by frequency\n 10. {packages}: Processor package count\n 11. {march}: CPU microarchitecture\n 12. {numa-nodes}: NUMA node count\n 13. {code-name}: CPU code name\n 14. {technology}: CPU technology",
"type": "string"
},
"cpucacheFormat": {
@@ -374,7 +374,7 @@
"type": "string"
},
"gpuFormat": {
"description": "Output format for the `GPU` module. See Wiki for formatting syntax\n 1. {vendor}: GPU vendor\n 2. {name}: GPU name\n 3. {driver}: GPU driver\n 4. {temperature}: GPU temperature\n 5. {core-count}: GPU core count\n 6. {type}: GPU type\n 7. {dedicated-total}: GPU total dedicated memory\n 8. {dedicated-used}: GPU used dedicated memory\n 9. {shared-total}: GPU total shared memory\n 10. {shared-used}: GPU used shared memory\n 11. {platform-api}: The platform API used when detecting the GPU\n 12. {frequency}: Current frequency in GHz\n 13. {index}: GPU vendor specific index\n 14. {dedicated-percentage-num}: Dedicated memory usage percentage num\n 15. {dedicated-percentage-bar}: Dedicated memory usage percentage bar\n 16. {shared-percentage-num}: Shared memory usage percentage num\n 17. {shared-percentage-bar}: Shared memory usage percentage bar\n 18. {core-usage-num}: Core usage percentage num\n 19. {core-usage-bar}: Core usage percentage bar\n 20. {memory-type}: Memory type (Windows only)",
"description": "Output format for the `GPU` module. See Wiki for formatting syntax\n 1. {vendor}: GPU vendor\n 2. {name}: GPU name\n 3. {driver}: GPU driver\n 4. {temperature}: GPU temperature\n 5. {core-count}: GPU core count\n 6. {type}: GPU type\n 7. {dedicated-total}: GPU total dedicated memory\n 8. {dedicated-used}: GPU used dedicated memory\n 9. {shared-total}: GPU total shared memory\n 10. {shared-used}: GPU used shared memory\n 11. {platform-api}: The platform API used when detecting the GPU\n 12. {frequency}: Current frequency in GHz\n 13. {index}: GPU vendor specific index\n 14. {dedicated-percentage-num}: Dedicated memory usage percentage num\n 15. {dedicated-percentage-bar}: Dedicated memory usage percentage bar\n 16. {shared-percentage-num}: Shared memory usage percentage num\n 17. {shared-percentage-bar}: Shared memory usage percentage bar\n 18. {core-usage-num}: Core usage percentage num\n 19. {core-usage-bar}: Core usage percentage bar\n 20. {memory-type}: Memory type (Windows only)\n 21. {pcie-max-speed}: PCIe maximum speed in gen and lanes\n 22. {pcie-curr-speed}: PCIe current speed in gen and lanes",
"type": "string"
},
"hostFormat": {
@@ -446,7 +446,7 @@
"type": "string"
},
"packagesFormat": {
"description": "Output format for the `Packages` module. See Wiki for formatting syntax\n 1. {all}: Number of all packages\n 2. {am-system}: Number of am-system packages\n 3. {am-user}: Number of am-user (aka appman) packages\n 4. {appimage}: Number of appimage packages\n 5. {apk}: Number of apk packages\n 6. {brew}: Number of brew packages\n 7. {brew-all}: Total number of all brew packages\n 8. {brew-cask}: Number of brew-cask packages\n 9. {cards}: Number of cards packages\n 10. {choco}: Number of choco packages\n 11. {dpkg}: Number of dpkg packages\n 12. {emerge}: Number of emerge packages\n 13. {eopkg}: Number of eopkg packages\n 14. {flatpak-all}: Total number of all flatpak app packages\n 15. {flatpak-system}: Number of flatpak-system app packages\n 16. {flatpak-user}: Number of flatpak-user app packages\n 17. {guix-all}: Total number of all guix packages\n 18. {guix-home}: Number of guix-home packages\n 19. {guix-system}: Number of guix-system packages\n 20. {guix-user}: Number of guix-user packages\n 21. {hpkg-all}: Total number of all hpkg packages\n 22. {hpkg-system}: Number of hpkg-system packages\n 23. {hpkg-user}: Number of hpkg-user packages\n 24. {kiss}: Number of kiss packages\n 25. {linglong}: Number of linglong packages\n 26. {lpkg}: Number of lpkg packages\n 27. {lpkgbuild}: Number of lpkgbuild packages\n 28. {macports}: Number of macports packages\n 29. {mport}: Number of mport packages\n 30. {moss}: Number of moss packages\n 31. {nix-all}: Total number of all nix packages\n 32. {nix-default}: Number of nix-default packages\n 33. {nix-system}: Number of nix-system packages\n 34. {nix-user}: Number of nix-user packages\n 35. {opkg}: Number of opkg packages\n 36. {pacman}: Number of pacman packages\n 37. {pacman-branch}: Pacman branch on manjaro\n 38. {pacstall}: Number of pacstall packages\n 39. {paludis}: Number of paludis packages\n 40. {pisi}: Number of pisi packages\n 41. {pkg}: Number of pkg packages\n 42. {pkgsrc}: Number of pkgsrc packages\n 43. {pkgtool}: Number of pkgtool packages\n 44. {rpm}: Number of rpm packages\n 45. {scoop-global}: Number of scoop-global packages\n 46. {scoop-user}: Number of scoop-user packages\n 47. {snap}: Number of snap packages\n 48. {soar}: Number of soar packages\n 49. {sorcery}: Number of sorcery packages\n 50. {winget}: Number of winget packages\n 51. {xbps}: Number of xbps packages",
"description": "Output format for the `Packages` module. See Wiki for formatting syntax\n 1. {am-system}: Number of am-system packages\n 2. {am-user}: Number of am-user (aka appman) packages\n 3. {appimage}: Number of appimage packages\n 4. {apk}: Number of apk packages\n 5. {brew}: Number of brew packages\n 6. {brew-cask}: Number of brew-cask packages\n 7. {cards}: Number of cards packages\n 8. {choco}: Number of choco packages\n 9. {dpkg}: Number of dpkg packages\n 10. {emerge}: Number of emerge packages\n 11. {eopkg}: Number of eopkg packages\n 12. {flatpak-system}: Number of flatpak-system app packages\n 13. {flatpak-user}: Number of flatpak-user app packages\n 14. {guix-home}: Number of guix-home packages\n 15. {guix-system}: Number of guix-system packages\n 16. {guix-user}: Number of guix-user packages\n 17. {hpkg-system}: Number of hpkg-system packages\n 18. {hpkg-user}: Number of hpkg-user packages\n 19. {install-release}: Number of install-release packages\n 20. {kiss}: Number of kiss packages\n 21. {linglong}: Number of linglong packages\n 22. {lpkg}: Number of lpkg packages\n 23. {lpkgbuild}: Number of lpkgbuild packages\n 24. {macports}: Number of macports packages\n 25. {mport}: Number of mport packages\n 26. {moss}: Number of moss packages\n 27. {nix-default}: Number of nix-default packages\n 28. {nix-system}: Number of nix-system packages\n 29. {nix-user}: Number of nix-user packages\n 30. {opkg}: Number of opkg packages\n 31. {pacman}: Number of pacman packages\n 32. {pacman-branch}: Pacman branch on manjaro\n 33. {pacstall}: Number of pacstall packages\n 34. {paludis}: Number of paludis packages\n 35. {pisi}: Number of pisi packages\n 36. {pkg}: Number of pkg packages\n 37. {pkgsrc}: Number of pkgsrc packages\n 38. {pkgtool}: Number of pkgtool packages\n 39. {porg}: Number of porg packages\n 40. {rpm}: Number of rpm packages\n 41. {scoop-global}: Number of scoop-global packages\n 42. {scoop-user}: Number of scoop-user packages\n 43. {snap}: Number of snap packages\n 44. {soar}: Number of soar packages\n 45. {sorcery}: Number of sorcery packages\n 46. {winget}: Number of winget packages\n 47. {xbps}: Number of xbps packages\n 48. {brew-all}: Total number of all brew packages\n 49. {flatpak-all}: Total number of all flatpak app packages\n 50. {guix-all}: Total number of all guix packages\n 51. {hpkg-all}: Total number of all hpkg packages\n 52. {nix-all}: Total number of all nix packages\n 53. {all}: Number of all packages",
"type": "string"
},
"physicaldiskFormat": {
@@ -2850,6 +2850,10 @@
"const": "opencl",
"description": "Use OpenCL API.\nSlow and requires proper OpenCL drivers to be installed"
},
{
"const": "egl-ext",
"description": "Use EGL_EXT_device_enumeration and EGL_EXT_device_query APIs.\nSlow and only detects GPUs that support these extensions"
},
{
"const": "opengl",
"description": "Use OpenGL API.\nSlow and only detects one GPU.\nUsed for OpenBSD"
+1
View File
@@ -17,3 +17,4 @@
#define FF_A_PACKED __attribute__((__packed__))
#define FF_A_WEAK_IMPORT __attribute__((__weak_import__))
#define FF_A_ALWAYS_INLINE __attribute__((__always_inline__))
#define FF_A_COLD __attribute__((__cold__))
+1
View File
@@ -33,5 +33,6 @@ static inline const char* ffFindFileName(const char* file) {
#if _WIN32
const char* ffDebugWin32Error(DWORD errorCode);
const char* ffDebugNtStatus(NTSTATUS status);
const char* ffDebugConfigRet(unsigned long /*CONFIGRET*/ ret);
const char* ffDebugHResult(HRESULT hr);
#endif
+2 -1
View File
@@ -8,6 +8,7 @@ bool ffEdidGetName(const uint8_t edid[128], FFstrbuf* name);
void ffEdidGetPreferredResolutionAndRefreshRate(const uint8_t edid[128], uint32_t* width, uint32_t* height, double* refreshRate);
void ffEdidGetPhysicalResolution(const uint8_t edid[128], uint32_t* width, uint32_t* height);
void ffEdidGetPhysicalSize(const uint8_t edid[128], uint32_t* width, uint32_t* height); // in mm
void ffEdidGetSerialAndManufactureDate(const uint8_t edid[128], uint32_t* serial, uint16_t* year, uint16_t* week);
void ffEdidGetManufactureDate(const uint8_t edid[128], uint16_t* year, uint16_t* week);
bool ffEdidGetSerial(const uint8_t edid[128], FFstrbuf* result);
bool ffEdidGetHdrCompatible(const uint8_t* edid, uint32_t length);
bool ffEdidIsValid(const uint8_t edid[128], uint32_t length);
+2 -2
View File
@@ -30,7 +30,7 @@ static void getExePath(FFPlatform* platform) {
char exePath[PATH_MAX];
#if defined(__linux__) || defined(__GNU__)
ssize_t exePathLen = readlink("/proc/self/exe", exePath, sizeof(exePath) - 1);
if (exePathLen >= 0) {
if (exePathLen > 0) {
exePath[exePathLen] = '\0';
}
#elif defined(__APPLE__)
@@ -128,7 +128,7 @@ static void getExePath(FFPlatform* platform) {
}
#elif defined(__sun)
ssize_t exePathLen = readlink("/proc/self/path/a.out", exePath, sizeof(exePath) - 1);
if (exePathLen >= 0) {
if (exePathLen > 0) {
exePath[exePathLen] = '\0';
}
#elif defined(__HAIKU__)
+5
View File
@@ -2,6 +2,7 @@
#include "common/windows/nt.h"
#include <windows.h>
#include <cfgmgr32.h>
const char* ffDebugWin32Error(DWORD errorCode) {
static char buffer[512];
@@ -34,6 +35,10 @@ const char* ffDebugWin32Error(DWORD errorCode) {
return buffer;
}
const char* ffDebugConfigRet(CONFIGRET ret) {
return ffDebugWin32Error(CM_MapCrToWin32Err(ret, ERROR_INTERNAL_ERROR));
}
const char* ffDebugNtStatus(NTSTATUS status) {
return ffDebugWin32Error(RtlNtStatusToDosError(status));
}
+43 -2
View File
@@ -66,7 +66,7 @@ void ffEdidGetPhysicalSize(const uint8_t edid[128], uint32_t* width, uint32_t* h
}
}
void ffEdidGetSerialAndManufactureDate(const uint8_t edid[128], uint32_t* serial, uint16_t* year, uint16_t* week) {
void ffEdidGetManufactureDate(const uint8_t edid[128], uint16_t* year, uint16_t* week) {
if (edid[17] > 0 && edid[17] < 0xFF) {
*year = (uint16_t) (edid[17] + 1990);
*week = (uint16_t) edid[16];
@@ -76,8 +76,49 @@ void ffEdidGetSerialAndManufactureDate(const uint8_t edid[128], uint32_t* serial
} else {
*year = *week = 0;
}
}
*serial = *(uint32_t*) &edid[12];
bool ffEdidGetSerial(const uint8_t edid[128], FFstrbuf* result) {
int descriptor_offsets[4] = {54, 72, 90, 108};
for (int i = 0; i < 4; i++) {
int offset = descriptor_offsets[i];
const uint8_t* desc = edid + offset;
if (desc[0] == 0x00 && desc[1] == 0x00) { // Monitor Descriptor
uint8_t tag = desc[3]; // Descriptor Type Tag
if (tag == 0xFF) { // Display Product Serial Number
ffStrbufClear(result);
for (int j = 0; j < 13; j++) {
uint8_t ch = desc[5 + j];
if (ch == 0x0A || ch == 0x00) {
break;
}
ffStrbufAppendC(result, (char) ch);
}
ffStrbufTrim(result, ' ');
if (result->length > 0) {
return true;
}
}
}
}
uint32_t int_serial = 0;
int_serial |= (uint32_t)edid[12];
int_serial |= (uint32_t)edid[13] << 8;
int_serial |= (uint32_t)edid[14] << 16;
int_serial |= (uint32_t)edid[15] << 24;
if (int_serial != 0 && int_serial != 0xFFFFFFFF) {
ffStrbufSetF(result, "0x%08X", int_serial);
return true;
}
return false;
}
bool ffEdidGetHdrCompatible(const uint8_t* edid, uint32_t length) {
+32 -23
View File
@@ -3,6 +3,7 @@
#include "common/parsing.h"
#include "common/thread.h"
#include "common/textModifier.h"
#include "common/strutil.h"
#include "detection/displayserver/displayserver.h"
#include "detection/terminaltheme/terminaltheme.h"
#include "logo/logo.h"
@@ -16,6 +17,9 @@
#else
#include <signal.h>
#endif
#if __linux__
#include <linux/version.h>
#endif
FFinstance instance; // Global singleton
@@ -46,10 +50,30 @@ static void defaultConfig(void) {
ffOptionsInitDisplay(&instance.config.display);
}
#ifdef _WIN32
static volatile UINT oldCp = CP_UTF8;
void resetConsoleCP(void) {
if (oldCp != CP_UTF8) {
SetConsoleOutputCP(oldCp);
}
}
#endif
void ffInitInstance(void) {
#ifdef _WIN32
// https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/setlocale-wsetlocale?source=recommendat>
setlocale(LC_ALL, ".UTF8");
HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
DWORD mode = 0;
if (GetConsoleMode(hStdout, &mode)) {
SetConsoleMode(hStdout, mode | ENABLE_PROCESSED_OUTPUT | ENABLE_VIRTUAL_TERMINAL_PROCESSING);
oldCp = GetConsoleOutputCP();
if (oldCp != CP_UTF8) {
SetConsoleOutputCP(CP_UTF8);
atexit(resetConsoleCP);
}
}
#else
// Never use `setlocale(LC_ALL, "")`
setlocale(LC_TIME, "");
@@ -61,9 +85,6 @@ void ffInitInstance(void) {
static volatile bool ffDisableLinewrap = false;
static volatile bool ffHideCursor = false;
#ifdef _WIN32
static volatile UINT oldCp = CP_UTF8;
#endif
static void resetConsole(void) {
if (ffDisableLinewrap) {
@@ -80,10 +101,6 @@ static void resetConsole(void) {
#if defined(_WIN32)
fflush(stdout);
if (oldCp != CP_UTF8) {
SetConsoleOutputCP(oldCp);
}
#endif
}
@@ -111,15 +128,6 @@ void ffStart(void) {
setvbuf(stdout, NULL, _IOFBF, 4096);
}
SetConsoleCtrlHandler(consoleHandler, TRUE);
HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
DWORD mode = 0;
if (GetConsoleMode(hStdout, &mode)) {
SetConsoleMode(hStdout, mode | ENABLE_PROCESSED_OUTPUT | ENABLE_VIRTUAL_TERMINAL_PROCESSING);
oldCp = GetConsoleOutputCP();
if (oldCp != CP_UTF8) {
SetConsoleOutputCP(CP_UTF8);
}
}
#else
if (instance.config.display.noBuffer) {
setvbuf(stdout, NULL, _IONBF, 0);
@@ -180,13 +188,14 @@ void ffDestroyInstance(void) {
#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(
#if __linux__
"linux-headers " FF_STR(LINUX_VERSION_MAJOR) "." FF_STR(LINUX_VERSION_PATCHLEVEL) "." FF_STR(LINUX_VERSION_SUBLEVEL) "\n"
#endif
#if FF_HAVE_THREADS
"threads\n"
#endif
@@ -205,9 +214,6 @@ void ffListFeatures(void) {
#if FF_HAVE_DRM
"drm\n"
#endif
#if FF_HAVE_DRM_AMDGPU
"drm_amdgpu\n"
#endif
#if FF_HAVE_GIO
"gio\n"
#endif
@@ -262,8 +268,11 @@ void ffListFeatures(void) {
#if FF_HAVE_LIBZFS
"libzfs\n"
#endif
#if FF_HAVE_VA
"va\n"
#if FF_HAVE_VADRM
"va-drm\n"
#endif
#if FF_HAVE_VAX11
"va-x11\n"
#endif
#if FF_HAVE_VDPAU
"vdpau\n"
+5 -4
View File
@@ -9,9 +9,7 @@ static yyjson_mut_val* lua2yyjson(lua_State* L, int idx, yyjson_mut_doc* doc, in
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")
);
L, "yyjson: recursion depth exceeded; possible circular reference", strlen("yyjson: recursion depth exceeded; possible circular reference"));
lua_error(L); // noreturn
__builtin_unreachable();
}
@@ -140,7 +138,7 @@ static int yyjsonEncode(lua_State* L) {
}
}
const char* ffLuaLoadState() {
const char* ffLuaLoadState(void) {
if (luaData.inited) {
if (luaData.L == NULL) {
return "Lua library is not available";
@@ -180,6 +178,8 @@ const char* ffLuaLoadState() {
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)
@@ -208,6 +208,7 @@ const char* ffLuaLoadState() {
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) {
+1 -3
View File
@@ -1,12 +1,10 @@
#include "common/netif.h"
#include "common/io.h"
#include "common/strutil.h"
#include <net/if.h>
#include <stdio.h>
#define FF_STR_INDIR(x) #x
#define FF_STR(x) FF_STR_INDIR(x)
bool ffNetifGetDefaultRouteImplV4(FFNetifDefaultRouteResult* result) {
FILE* FF_AUTO_CLOSE_FILE netRoute = fopen("/proc/route", "r");
+9 -2
View File
@@ -56,7 +56,14 @@ static const char* tryNonThreadingFastPath(FFNetworkingState* state) {
}
#ifndef __APPLE__
FF_DEBUG("Using sendto() + MSG_DONTWAIT to send %u bytes of data", state->command.length);
FF_DEBUG("Using sendto() "
#ifdef MSG_FASTOPEN
"+ MSG_FASTOPEN "
#endif
#ifdef MSG_NOSIGNAL
"+ MSG_NOSIGNAL "
#endif
"to send %u bytes of data", state->command.length);
ssize_t sent = sendto(state->sockfd,
state->command.chars,
state->command.length,
@@ -66,7 +73,7 @@ static const char* tryNonThreadingFastPath(FFNetworkingState* state) {
#ifdef MSG_NOSIGNAL
MSG_NOSIGNAL |
#endif
MSG_DONTWAIT,
0,
state->addr->ai_addr,
state->addr->ai_addrlen);
#else
+2 -2
View File
@@ -269,7 +269,7 @@ void ffProcessGetInfoLinux(pid_t pid, FFstrbuf* processName, FFstrbuf* exe, cons
}
}
if (exePath->length == 0) {
if (exePath->length == 0 && access(filePath, X_OK) == 0) {
ffStrbufSetS(exePath, filePath);
}
}
@@ -546,7 +546,7 @@ const char* ffProcessGetBasicInfoLinux(pid_t pid, FFstrbuf* name, pid_t* ppid, i
return "sysctl(KERN_PROC_PID) failed";
}
ffStrbufSetS(name, proc.kp_proc.p_comm); // trancated to 16 chars
ffStrbufSetS(name, proc.kp_proc.p_comm); // truncated to 16 chars
if (ppid) {
*ppid = (pid_t) proc.kp_eproc.e_ppid;
}
+17 -25
View File
@@ -40,6 +40,7 @@ HANDLE openat(HANDLE dfd, const char* fileName, int oflag);
HANDLE openatW(HANDLE dfd, const wchar_t* fileName, uint16_t fileNameLen, bool directory);
#endif
FF_A_ALWAYS_INLINE
static inline bool ffIsValidNativeFD(FFNativeFD fd) {
#ifndef _WIN32
return fd >= 0;
@@ -49,20 +50,17 @@ static inline bool ffIsValidNativeFD(FFNativeFD fd) {
#endif
}
FF_A_NONNULL(1) static inline bool wrapClose(FFNativeFD* pfd) {
FF_A_ALWAYS_INLINE FF_A_NONNULL(1)
static inline void wrapClose(FFNativeFD* pfd) {
assert(pfd);
if (!ffIsValidNativeFD(*pfd)) {
return false;
}
if (ffIsValidNativeFD(*pfd)) {
#ifndef _WIN32
close(*pfd);
close(*pfd);
#else
NtClose(*pfd);
NtClose(*pfd);
#endif
return true;
}
}
#define FF_AUTO_CLOSE_FD FF_A_CLEANUP(wrapClose)
@@ -250,34 +248,28 @@ static inline void ffUnsuppressIO(bool* suppressed) {
void ffListFilesRecursively(const char* path, bool pretty);
FF_A_NONNULL(1) static inline bool wrapFclose(FILE** pfile) {
FF_A_NONNULL(1) FF_A_ALWAYS_INLINE static inline void wrapFclose(FILE** pfile) {
assert(pfile);
if (!*pfile) {
return false;
if (*pfile) {
fclose(*pfile);
}
fclose(*pfile);
return true;
}
#define FF_AUTO_CLOSE_FILE FF_A_CLEANUP(wrapFclose)
FF_A_NONNULL(1)
FF_A_NONNULL(1) FF_A_ALWAYS_INLINE
#ifndef _WIN32
static inline bool wrapClosedir(DIR** pdir) {
static inline void wrapClosedir(DIR** pdir) {
assert(pdir);
if (!*pdir) {
return false;
if (*pdir) {
closedir(*pdir);
}
closedir(*pdir);
return true;
}
#else
static inline bool wrapClosedir(HANDLE* pdir) {
static inline void wrapClosedir(HANDLE* pdir) {
assert(pdir);
if (!*pdir) {
return false;
if (*pdir) {
FindClose(*pdir);
}
FindClose(*pdir);
return true;
}
#endif
#define FF_AUTO_CLOSE_DIR FF_A_CLEANUP(wrapClosedir)
+21 -14
View File
@@ -3,16 +3,19 @@
#include "fastfetch.h"
#if FF_HAVE_LUA
// Hack. LUA_API is defined as extern which prevents us from implementing the functions ourselves.
#include <luaconf.h>
#undef LUA_API
#undef LUALIB_API
#undef LUAMOD_API
#define LUA_API static inline
#define LUALIB_API LUA_API
#define LUAMOD_API LUA_API
#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
#pragma GCC diagnostic ignored "-Wunused-function"
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
@@ -24,6 +27,7 @@
#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)
@@ -52,13 +56,13 @@ extern struct FFLuaData {
FF_LIBRARY_SYMBOL(lua_tolstring)
FF_LIBRARY_SYMBOL(lua_tonumberx)
FF_LIBRARY_SYMBOL(lua_type)
#endif
lua_State* L;
bool inited;
} luaData;
const char* ffLuaLoadState();
#if !FF_DISABLE_DLOPEN
FF_A_ALWAYS_INLINE void(lua_settop)(lua_State* L, int idx) {
return luaData.fflua_settop(L, idx);
}
@@ -148,11 +152,11 @@ FF_A_ALWAYS_INLINE int(lua_rawgeti)(lua_State* L, int idx, lua_Integer n) {
}
FF_A_ALWAYS_INLINE
#if LUA_VERSION_NUM > 503
#if LUA_VERSION_NUM > 503
lua_Unsigned
#else
#else
size_t
#endif
#endif
(lua_rawlen)(lua_State* L, int idx) {
return luaData.fflua_rawlen(L, idx);
}
@@ -176,5 +180,8 @@ FF_A_ALWAYS_INLINE lua_Number(lua_tonumberx)(lua_State* L, int idx, int* 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
+2
View File
@@ -2,6 +2,7 @@
#include <stdlib.h>
#include <assert.h>
#include "common/attributes.h"
#if FF_HAVE_MALLOC_USABLE_SIZE || FF_HAVE_MSVC_MSIZE
#if __has_include(<malloc.h>)
@@ -13,6 +14,7 @@
#include <malloc/malloc.h>
#endif
FF_A_ALWAYS_INLINE FF_A_NONNULL(1)
static inline void ffWrapFree(const void* pPtr) {
assert(pPtr);
if (*(void**) pPtr) {
+14
View File
@@ -5,6 +5,7 @@
#include <string.h>
#include <ctype.h>
#include "common/attributes.h"
#include "common/wcwidth.h"
#ifdef _WIN32
@@ -13,6 +14,9 @@ __stdcall char* StrStrIA(const char* lpFirst, const char* lpSrch);
#define strcasestr StrStrIA
#endif
#define FF_STR_INDIR(x) #x
#define FF_STR(x) FF_STR_INDIR(x)
static inline bool ffStrSet(const char* str) {
if (str == NULL) {
return false;
@@ -25,14 +29,17 @@ static inline bool ffStrSet(const char* str) {
return *str != '\0';
}
FF_A_ALWAYS_INLINE
static inline bool ffStrStartsWithIgnCase(const char* str, const char* compareTo) {
return strncasecmp(str, compareTo, strlen(compareTo)) == 0;
}
FF_A_ALWAYS_INLINE
static inline bool ffStrEqualsIgnCase(const char* str, const char* compareTo) {
return strcasecmp(str, compareTo) == 0;
}
FF_A_ALWAYS_INLINE
static inline bool ffStrStartsWith(const char* str, const char* compareTo) {
return strncmp(str, compareTo, strlen(compareTo)) == 0;
}
@@ -55,26 +62,32 @@ static inline bool ffStrEndsWithIgnCase(const char* str, const char* compareTo)
return strncasecmp(str + strLength - compareToLength, compareTo, compareToLength) == 0;
}
FF_A_ALWAYS_INLINE
static inline bool ffStrEquals(const char* str, const char* compareTo) {
return strcmp(str, compareTo) == 0;
}
FF_A_ALWAYS_INLINE
static inline bool ffStrContains(const char* str, const char* compareTo) {
return strstr(str, compareTo) != NULL;
}
FF_A_ALWAYS_INLINE
static inline bool ffStrContainsIgnCase(const char* str, const char* compareTo) {
return strcasestr(str, compareTo) != NULL;
}
FF_A_ALWAYS_INLINE
static inline bool ffStrContainsC(const char* str, char compareTo) {
return strchr(str, compareTo) != NULL;
}
FF_A_ALWAYS_INLINE
static inline bool ffCharIsEnglishAlphabet(char c) {
return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z');
}
FF_A_ALWAYS_INLINE
static inline bool ffCharIsDigit(char c) {
return '0' <= c && c <= '9';
}
@@ -86,6 +99,7 @@ uint8_t ffUtf8CharLenWidth(const char* str, uint32_t length, uint8_t* width);
uint32_t ffUtf8StrWidth(const char* str, uint32_t length);
FF_A_ALWAYS_INLINE
static inline bool ffCharIsHexDigit(char c) {
return ffCharIsDigit(c) || ('a' <= c && c <= 'f') || ('A' <= c && c <= 'F');
}
+1 -3
View File
@@ -10,7 +10,7 @@ static const char* detectWithBacklight(FFlist* result) {
// https://www.kernel.org/doc/Documentation/ABI/stable/sysfs-class-backlight
const char* backlightDirPath = "/sys/class/backlight/";
DIR* dirp = opendir(backlightDirPath);
FF_AUTO_CLOSE_DIR DIR* dirp = opendir(backlightDirPath);
if (dirp == NULL) {
return "Failed to open `/sys/class/backlight/`";
}
@@ -72,8 +72,6 @@ static const char* detectWithBacklight(FFlist* result) {
ffStrbufSubstrBefore(&backlightDir, backlightDirLength);
}
closedir(dirp);
return NULL;
}
+188 -186
View File
@@ -1,35 +1,33 @@
#include "codec.h"
#if (FF_HAVE_DRM && FF_HAVE_VA) || FF_HAVE_VDPAU
#if FF_HAVE_VADRM || FF_HAVE_VAX11
#define FF_HAVE_VA 1
#endif
#if FF_HAVE_VA || FF_HAVE_VDPAU
#include "common/library.h"
#include "common/mallocHelper.h"
#include "common/strutil.h"
#include "common/io.h"
#if FF_HAVE_DRM && FF_HAVE_VA
#include "detection/gpu/gpu.h"
#if FF_HAVE_VA
#include <fcntl.h>
#include <va/va.h>
#include <va/va_drm.h>
#include <xf86drm.h>
#endif
#include <string.h>
typedef struct FFVAData {
FF_LIBRARY_SYMBOL(vaInitialize)
FF_LIBRARY_SYMBOL(vaTerminate)
FF_LIBRARY_SYMBOL(vaMaxNumProfiles)
FF_LIBRARY_SYMBOL(vaMaxNumEntrypoints)
FF_LIBRARY_SYMBOL(vaQueryConfigProfiles)
FF_LIBRARY_SYMBOL(vaQueryConfigEntrypoints)
FF_LIBRARY_SYMBOL(vaQueryVendorString)
FF_LIBRARY_SYMBOL(vaGetConfigAttributes)
} FFVAData;
#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) {
static FFCodecType vaProfileToType(VAProfile profile) {
switch (profile) {
case 11: // VAProfileH263Baseline
return FF_CODEC_TYPE_H263;
@@ -98,7 +96,7 @@ static FFCodecType ffCodecProfileToType(VAProfile profile) {
}
}
static FFCodecShowType ffCodecGetEntrypointType(VAEntrypoint entrypoint) {
static FFCodecShowType vaGetEntrypointType(VAEntrypoint entrypoint) {
switch (entrypoint) {
case VAEntrypointVLD:
case VAEntrypointIDCT:
@@ -113,21 +111,20 @@ static FFCodecShowType ffCodecGetEntrypointType(VAEntrypoint entrypoint) {
}
}
static bool ffCodecProfileHasOutput(
static bool vaProfileHasOutput(
FFVAData* vaData,
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) {
if (vaData->ffvaQueryConfigEntrypoints(display, profile, entrypoints, &numEntrypoints) != VA_STATUS_SUCCESS) {
return false;
}
for (int i = 0; i < numEntrypoints; ++i) {
if (ffCodecGetEntrypointType(entrypoints[i]) != entrypointType) {
if (vaGetEntrypointType(entrypoints[i]) != entrypointType) {
continue;
}
@@ -136,7 +133,7 @@ static bool ffCodecProfileHasOutput(
.value = 0,
};
if (ffvaGetConfigAttributes(display, profile, entrypoints[i], &attrib, 1) == VA_STATUS_SUCCESS &&
if (vaData->ffvaGetConfigAttributes(display, profile, entrypoints[i], &attrib, 1) == VA_STATUS_SUCCESS &&
attrib.value != VA_ATTRIB_NOT_SUPPORTED &&
attrib.value != 0) {
return true;
@@ -146,91 +143,101 @@ static bool ffCodecProfileHasOutput(
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;
static bool vaDetectDisplay(VADisplay display, FFVAData* vaData, FFCodecOptions* options, FFlist* result, const char* api) {
int major = 0, minor = 0;
if (vaData->ffvaInitialize(display, &major, &minor) != VA_STATUS_SUCCESS) {
vaData->ffvaTerminate(display);
return false;
}
if (!name->length && path && *path) {
const char* base = strrchr(path, '/');
ffStrbufSetS(name, base ? base + 1 : path);
int maxProfiles = vaData->ffvaMaxNumProfiles(display);
int maxEntrypoints = vaData->ffvaMaxNumEntrypoints(display);
if (maxProfiles <= 0 || maxEntrypoints <= 0) {
vaData->ffvaTerminate(display);
return false;
}
if (!name->length) {
ffStrbufSetStatic(name, "Unknown GPU");
}
}
FF_AUTO_FREE VAProfile* profiles = (VAProfile*) malloc(sizeof(VAProfile) * (size_t) maxProfiles);
FF_AUTO_FREE VAEntrypoint* entrypoints = (VAEntrypoint*) malloc(sizeof(VAEntrypoint) * (size_t) maxEntrypoints);
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";
int numProfiles = maxProfiles;
if (vaData->ffvaQueryConfigProfiles(display, profiles, &numProfiles) != VA_STATUS_SUCCESS) {
vaData->ffvaTerminate(display);
return false;
}
const char* error = "No DRM device could initialize VA-API";
FFCodecType decoderTypes = FF_CODEC_TYPE_NONE;
FFCodecType encoderTypes = FF_CODEC_TYPE_NONE;
for (int j = 0; j < numProfiles; ++j) {
FFCodecType type = vaProfileToType(profiles[j]);
for (int i = 0; i < numDevices; ++i) {
drmDevice* dev = devices[i];
bool hasDecoder = (options->showType & FF_CODEC_SHOW_TYPE_DECODER) &&
!(decoderTypes & type) &&
vaProfileHasOutput(
vaData,
display,
maxEntrypoints,
entrypoints,
profiles[j],
FF_CODEC_SHOW_TYPE_DECODER);
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 {
bool hasEncoder = (options->showType & FF_CODEC_SHOW_TYPE_ENCODER) &&
!(encoderTypes & type) &&
vaProfileHasOutput(
vaData,
display,
maxEntrypoints,
entrypoints,
profiles[j],
FF_CODEC_SHOW_TYPE_ENCODER);
if (!hasDecoder && !hasEncoder) {
continue;
}
FF_AUTO_CLOSE_FD int fd = open(path, O_RDWR | O_CLOEXEC);
if (fd < 0) {
fd = open(path, O_RDONLY | O_CLOEXEC);
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);
ffStrbufInitS(&item->gpu, vaData->ffvaQueryVendorString(display));
item->decoders = decoderTypes;
item->encoders = encoderTypes;
item->platformApi = api;
}
vaData->ffvaTerminate(display);
return true;
}
#if FF_HAVE_VADRM
#include <va/va_drm.h>
static const char* detectCodecByVaDrm(FFVAData* vaData, FFCodecOptions* options, FFlist* result) {
FF_LIBRARY_LOAD_MESSAGE(libvaDrm, "libva-drm" FF_LIBRARY_EXTENSION, 2)
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libvaDrm, vaGetDisplayDRM)
const char* error = "No DRM device could initialize VA-API";
FF_AUTO_CLOSE_DIR DIR* dirp = opendir("/dev/dri/");
if (dirp == NULL) {
return "opendir(/dev/dri/) failed";
}
int drifd = dirfd(dirp);
struct dirent* entry;
while ((entry = readdir(dirp)) != NULL) {
if (entry->d_name[0] == '.' || !ffStrStartsWith(entry->d_name, "renderD")) {
continue;
}
FF_AUTO_CLOSE_FD int fd = openat(drifd, entry->d_name, O_RDONLY | O_CLOEXEC);
if (fd < 0) {
continue;
}
@@ -240,84 +247,77 @@ static const char* ffDetectCodecByVa(FFCodecOptions* options, FFlist* result) {
continue;
}
int major = 0, minor = 0;
if (ffvaInitialize(display, &major, &minor) != VA_STATUS_SUCCESS) {
continue;
if (vaDetectDisplay(display, vaData, options, result, "VA-API (DRM)")) {
error = NULL;
}
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_VAX11
#include <va/va_x11.h>
static const char* detectCodecByVaX11(FFVAData* vaData, FFCodecOptions* options, FFlist* result) {
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_MESSAGE(libvaX11, "libva-x11" FF_LIBRARY_EXTENSION, 2)
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libvaX11, vaGetDisplay)
Display* x11Display = ffXOpenDisplay(NULL);
if (!x11Display) {
return "XOpenDisplay() failed";
}
VADisplay display = ffvaGetDisplay(x11Display);
if (!display) {
ffXCloseDisplay(x11Display);
return "vaGetDisplay() failed";
}
if (!vaDetectDisplay(display, vaData, options, result, "VA-API (X11)")) {
ffXCloseDisplay(x11Display);
return "VA-API could not detect any supported codec via X11";
}
ffXCloseDisplay(x11Display);
return NULL;
}
#endif
static const char* detectCodecByVa(FFCodecOptions* options, FFlist* result) {
FFVAData vaData = {};
FF_LIBRARY_LOAD_MESSAGE(libva, "libva" FF_LIBRARY_EXTENSION, 2)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libva, vaData, vaInitialize)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libva, vaData, vaTerminate)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libva, vaData, vaMaxNumProfiles)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libva, vaData, vaMaxNumEntrypoints)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libva, vaData, vaQueryConfigProfiles)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libva, vaData, vaQueryConfigEntrypoints)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libva, vaData, vaQueryVendorString)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libva, vaData, vaGetConfigAttributes)
#if FF_HAVE_VADRM
if (detectCodecByVaDrm(&vaData, options, result) == NULL) {
return NULL;
}
#endif
#if FF_HAVE_VAX11
if (detectCodecByVaX11(&vaData, options, result) == NULL) {
return NULL;
}
#endif
return "VA-API could not detect any supported codec via DRM or X11";
}
#endif
#if FF_HAVE_VDPAU
#include <vdpau/vdpau_x11.h>
static const struct FFCodecVdpauCodec {
VdpDecoderProfile profile;
@@ -326,6 +326,13 @@ static const struct FFCodecVdpauCodec {
{ 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
{ 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
{ 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
{ 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
@@ -336,17 +343,16 @@ static const struct FFCodecVdpauCodec {
{ 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
{ 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
{ 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
@@ -354,17 +360,13 @@ static const struct FFCodecVdpauCodec {
{ 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) {
static const char* detectCodecByVdpau(FFCodecOptions* options, FFlist* result) {
if (!(options->showType & FF_CODEC_SHOW_TYPE_DECODER)) {
return "VDPAU only supports decoding";
}
@@ -376,7 +378,7 @@ static const char* ffDetectCodecByVdpau(FFCodecOptions* options, FFlist* result)
FF_LIBRARY_LOAD_MESSAGE(libvdpau, "libvdpau" FF_LIBRARY_EXTENSION, 1)
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libvdpau, vdp_device_create_x11)
void* x11Display = ffXOpenDisplay(NULL);
Display* x11Display = ffXOpenDisplay(NULL);
if (!x11Display) {
return "XOpenDisplay() failed";
}
@@ -446,13 +448,13 @@ static const char* ffDetectCodecByVdpau(FFCodecOptions* options, FFlist* result)
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) {
#if FF_HAVE_VA
if (detectCodecByVa(options, result) == NULL) {
return NULL;
}
#endif
#if FF_HAVE_VDPAU
if (ffDetectCodecByVdpau(options, result) == NULL) {
if (detectCodecByVdpau(options, result) == NULL) {
return NULL;
}
#endif
@@ -464,7 +466,7 @@ const char* ffDetectCodecNative(FFCodecOptions* options, FFlist* result /* list
const char* ffDetectCodecNative(FFCodecOptions* options, FFlist* result /* list of FFCodecResult */) {
FF_UNUSED(options, result);
return "Fastfetch was built without DRM / VA-API / VDPAU headers";
return "Fastfetch was built without VA-API / VDPAU headers";
}
#endif
+3 -3
View File
@@ -408,13 +408,13 @@ const char* detectD3d11va(FFCodecOptions* options, FFlist* result /*list of FFCo
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)
FF_LIBRARY_LOAD_SYMBOL_LAZY(mfplat, MFTEnum2) // Not available on Windows 8.1
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)
FFCodecType encoders = ffMFTEnum2 && (options->showType & FF_CODEC_SHOW_TYPE_ENCODER)
? ffDetectD3d11MftEncoders(desc.AdapterLuid, ffMFCreateAttributes, ffMFTEnum2)
: FF_CODEC_TYPE_NONE;
@@ -426,7 +426,7 @@ const char* detectD3d11va(FFCodecOptions* options, FFlist* result /*list of FFCo
ffStrbufInitWS(&gpuResult->gpu, desc.Description);
gpuResult->decoders = decoders;
gpuResult->encoders = encoders;
gpuResult->platformApi = "D3D11VA+MFT";
gpuResult->platformApi = ffMFTEnum2 ? "D3D11VA+MFT" : "D3D11VA";
});
return nullptr;
+5
View File
@@ -22,6 +22,11 @@ const char* ffDetectCPU(const FFCPUOptions* options, FFCPUResult* cpu) {
ffStrbufSubstrBeforeFirstC(&cpu->name, '@'); // Cut the speed output in the name as we append our own
ffStrbufTrimRight(&cpu->name, ' '); // If we removed the @ in previous step there was most likely a space before it
ffStrbufRemoveDupWhitespaces(&cpu->name);
#if __i386__ || __x86_64__
ffCPUDetectX86Specific(cpu);
#endif
return NULL;
}
+11
View File
@@ -27,9 +27,20 @@ typedef struct FFCPUResult {
FFCPUCore coreTypes[16]; // number of P cores, E cores, etc.
double temperature;
#if __i386__ || __x86_64__
const char* codeName;
const char* technology;
#endif
} FFCPUResult;
const char* ffDetectCPU(const FFCPUOptions* options, FFCPUResult* cpu);
const char* ffCPUAppleCodeToName(uint32_t code);
const char* ffCPUQualcommCodeToName(uint32_t code);
void ffCPUDetectByCpuid(FFCPUResult* cpu);
#if __i386__ || __x86_64__
bool ffCPUDetectX86Specific(FFCPUResult* cpu);
#endif
+43 -66
View File
@@ -619,19 +619,14 @@ static const char* parseCpuInfo(
return NULL;
}
static uint32_t getFrequency(FFstrbuf* basePath, const char* cpuinfoFileName, const char* scalingFileName, FFstrbuf* buffer) {
uint32_t baseLen = basePath->length;
ffStrbufAppendS(basePath, cpuinfoFileName);
bool ok = ffReadFileBuffer(basePath->chars, buffer);
ffStrbufSubstrBefore(basePath, baseLen);
static uint32_t getFrequency(int policyFd, const char* cpuinfoFileName, const char* scalingFileName, FFstrbuf* buffer) {
bool ok = ffReadFileBufferRelative(policyFd, cpuinfoFileName, buffer);
if (ok) {
return (uint32_t) (ffStrbufToUInt(buffer, 0) / 1000);
}
if (scalingFileName) {
ffStrbufAppendS(basePath, scalingFileName);
ok = ffReadFileBuffer(basePath->chars, buffer);
ffStrbufSubstrBefore(basePath, baseLen);
ok = ffReadFileBufferRelative(policyFd, scalingFileName, buffer);
if (ok) {
return (uint32_t) (ffStrbufToUInt(buffer, 0) / 1000);
}
@@ -640,55 +635,38 @@ static uint32_t getFrequency(FFstrbuf* basePath, const char* cpuinfoFileName, co
return 0;
}
static uint8_t getNumCores(FFstrbuf* basePath, FFstrbuf* buffer) {
uint32_t baseLen = basePath->length;
ffStrbufAppendS(basePath, "/affected_cpus");
bool ok = ffReadFileBuffer(basePath->chars, buffer);
ffStrbufSubstrBefore(basePath, baseLen);
if (ok) {
return (uint8_t) (ffStrbufCountC(buffer, ' ') + 1);
}
ffStrbufAppendS(basePath, "/related_cpus");
ok = ffReadFileBuffer(basePath->chars, buffer);
ffStrbufSubstrBefore(basePath, baseLen);
if (ok) {
return (uint8_t) (ffStrbufCountC(buffer, ' ') + 1);
}
return 0;
}
static bool detectFrequency(FFCPUResult* cpu, const FFCPUOptions* options) {
FF_STRBUF_AUTO_DESTROY path = ffStrbufCreateS("/sys/devices/system/cpu/cpufreq/");
FF_AUTO_CLOSE_DIR DIR* dir = opendir(path.chars);
const char* basePath = "/sys/devices/system/cpu/cpufreq/";
FF_AUTO_CLOSE_DIR DIR* dir = opendir(basePath);
if (!dir) {
return false;
}
int freqFd = dirfd(dir);
FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreate();
uint32_t baseLen = path.length;
struct dirent* entry;
while ((entry = readdir(dir)) != NULL) {
if (ffStrStartsWith(entry->d_name, "policy") && ffCharIsDigit(entry->d_name[strlen("policy")])) {
ffStrbufAppendS(&path, entry->d_name);
FF_AUTO_CLOSE_FD int policyFd = openat(freqFd, entry->d_name, O_RDONLY | O_DIRECTORY | O_CLOEXEC | O_PATH);
if (policyFd < 0) {
continue;
}
uint32_t fmax = getFrequency(&path, "/cpuinfo_max_freq", "/scaling_max_freq", &buffer);
uint32_t fmax = getFrequency(policyFd, "cpuinfo_max_freq", "scaling_max_freq", &buffer);
if (fmax == 0) {
continue;
}
if (cpu->frequencyMax >= fmax) {
if (!options->showPeCoreCount) {
ffStrbufSubstrBefore(&path, baseLen);
continue;
}
} else {
cpu->frequencyMax = fmax;
}
uint32_t fbase = getFrequency(&path, "/base_frequency", NULL, &buffer);
uint32_t fbase = getFrequency(policyFd, "base_frequency", NULL, &buffer);
if (fbase > 0) {
cpu->frequencyBase = cpu->frequencyBase > fbase ? cpu->frequencyBase : fbase;
}
@@ -702,9 +680,10 @@ static bool detectFrequency(FFCPUResult* cpu, const FFCPUOptions* options) {
if (cpu->coreTypes[ifreq].freq == 0) {
cpu->coreTypes[ifreq].freq = freq;
}
cpu->coreTypes[ifreq].count += getNumCores(&path, &buffer);
if (ffReadFileBufferRelative(policyFd, "affected_cpus", &buffer)) {
cpu->coreTypes[ifreq].count += ffStrbufCountC(&buffer, ' ') + 1;
}
}
ffStrbufSubstrBefore(&path, baseLen);
}
}
return true;
@@ -773,6 +752,7 @@ static const char* detectPhysicalCores(FFCPUResult* cpu) {
FF_AUTO_CLOSE_DIR DIR* dir = fdopendir(dfd);
if (!dir) {
close(dfd);
return "fdopendir(dfd) failed";
}
@@ -785,7 +765,7 @@ static const char* detectPhysicalCores(FFCPUResult* cpu) {
continue;
}
FF_AUTO_CLOSE_FD int cpuxfd = openat(dirfd(dir), entry->d_name, O_RDONLY | O_DIRECTORY);
FF_AUTO_CLOSE_FD int cpuxfd = openat(dirfd(dir), entry->d_name, O_RDONLY | O_DIRECTORY | O_CLOEXEC);
if (cpuxfd < 0) {
continue;
}
@@ -798,45 +778,42 @@ static const char* detectPhysicalCores(FFCPUResult* cpu) {
ssize_t len = ffReadFileDataRelative(cpuxfd, "topology/physical_package_id", sizeof(buf) - 1, buf);
if (len > 0) {
buf[len] = '\0';
unsigned long long id = strtoul(buf, NULL, 10);
if (__builtin_expect(id > 64, false)) { // Do 129-socket boards exist?
pkgHigh |= 1ULL << (id - 64);
} else {
pkgLow |= 1ULL << id;
unsigned long long id = strtoull(buf, NULL, 10);
if (__builtin_expect(id < 128, true)) {
// Do 129-socket boards exist?
if (__builtin_expect(id >= 64, false)) {
pkgHigh |= 1ULL << (id - 64);
} else {
pkgLow |= 1ULL << id;
}
}
}
// Check if the directory contains a file named "topology/core_cpus_list"
// that lists the physical cores in the package.
// that lists the logical cores in the same physical core.
len = ffReadFileDataRelative(cpuxfd, "topology/core_cpus_list", sizeof(buf) - 1, buf);
if (len > 0) {
buf[len] = '\0'; // low-high or low
buf[len] = '\0'; // low[-high, low-high, ...]
for (const char* p = buf; *p;) {
char* pend;
uint32_t coreId = (uint32_t) strtoul(p, &pend, 10);
if (pend == p) {
char* pend;
// We assume that the different physical cores exposes different logical core ids,
// so that the first `low` is always different between different physical cores.
uint32_t coreId = (uint32_t) strtoul(buf, &pend, 10);
if (pend == buf) {
break;
}
bool found = false;
FF_LIST_FOR_EACH (uint32_t, id, cpuList) {
if (*id == coreId) {
// This core is already counted
found = true;
break;
}
bool found = false;
FF_LIST_FOR_EACH (uint32_t, id, cpuList) {
if (*id == coreId) {
// This core is already counted
found = true;
break;
}
}
if (!found) {
*FF_LIST_ADD(uint32_t, cpuList) = coreId;
}
p = strchr(pend, ',');
if (!p) {
break;
}
++p;
}
if (!found) {
*FF_LIST_ADD(uint32_t, cpuList) = coreId;
}
}
}
+30 -29
View File
@@ -216,7 +216,21 @@ static const char* detectMaxSpeedBySmbios(FFCPUResult* cpu) {
return NULL;
}
static const char* detectNCores(FFCPUResult* cpu) {
static uint32_t getNumLogicalCores(const SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX* ptr) {
uint32_t num = 0;
for (uint32_t i = 0; i < ptr->Processor.GroupCount; ++i) {
num += (uint32_t)
#if _WIN64
__builtin_popcountll
#else
__builtin_popcountl
#endif
(ptr->Processor.GroupMask[i].Mask);
}
return num;
}
static const char* detectNCores(const FFCPUOptions* options, FFCPUResult* cpu) {
LOGICAL_PROCESSOR_RELATIONSHIP lpr = RelationAll;
ULONG length = 0;
NtQuerySystemInformationEx(SystemLogicalProcessorAndGroupInformation, &lpr, sizeof(lpr), NULL, 0, &length);
@@ -242,6 +256,19 @@ static const char* detectNCores(FFCPUResult* cpu) {
}
} else if (ptr->Relationship == RelationProcessorCore) {
++cpu->coresPhysical;
if (options->showPeCoreCount) {
for (uint32_t i = 0; i < ARRAY_SIZE(cpu->coreTypes); ++i) {
if (ptr->Processor.EfficiencyClass + 1 == cpu->coreTypes[i].freq) {
cpu->coreTypes[i].count += getNumLogicalCores(ptr);
break;
} else if (cpu->coreTypes[i].freq == 0) {
cpu->coreTypes[i].freq = ptr->Processor.EfficiencyClass + 1;
cpu->coreTypes[i].count += getNumLogicalCores(ptr);
break;
}
}
}
} else if (ptr->Relationship == RelationProcessorPackage) {
++cpu->packages;
} else if (ptr->Relationship == RelationNumaNode) {
@@ -258,7 +285,7 @@ static const char* detectByRegistry(FFCPUResult* cpu) {
return "ffRegOpenKeyForRead(HKEY_LOCAL_MACHINE, L\"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0\", &hKey, NULL) failed";
}
if (ffRegReadValues(hKey, 3, (FFRegValueArg[]) {
if (ffRegReadValues(hKey, 3, (FFRegValueArg[]){
FF_ARG(cpu->name, L"ProcessorNameString"),
FF_ARG(cpu->vendor, L"VendorIdentifier"),
FF_ARG(cpu->frequencyBase, L"~MHz"),
@@ -272,31 +299,8 @@ static const char* detectByRegistry(FFCPUResult* cpu) {
return NULL;
}
static const char* detectCoreTypes(FFCPUResult* cpu) {
FF_AUTO_FREE PROCESSOR_POWER_INFORMATION* pinfo = calloc(cpu->coresLogical, sizeof(PROCESSOR_POWER_INFORMATION));
if (!NT_SUCCESS(NtPowerInformation(ProcessorInformation, NULL, 0, pinfo, (ULONG) sizeof(PROCESSOR_POWER_INFORMATION) * cpu->coresLogical))) {
return "NtPowerInformation(ProcessorInformation, NULL, 0, pinfo, size) failed";
}
for (uint32_t icore = 0; icore < cpu->coresLogical && pinfo[icore].MhzLimit; ++icore) {
uint32_t ifreq = 0;
while (cpu->coreTypes[ifreq].freq != pinfo[icore].MhzLimit && cpu->coreTypes[ifreq].freq > 0) {
++ifreq;
}
if (cpu->coreTypes[ifreq].freq == 0) {
cpu->coreTypes[ifreq].freq = pinfo[icore].MhzLimit;
}
++cpu->coreTypes[ifreq].count;
}
if (cpu->frequencyBase == 0) {
cpu->frequencyBase = pinfo->MaxMhz;
}
return NULL;
}
const char* ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu) {
detectNCores(cpu);
detectNCores(options, cpu);
const char* error = detectByRegistry(cpu);
if (error) {
@@ -304,9 +308,6 @@ const char* ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu) {
}
ffCPUDetectByCpuid(cpu);
if (options->showPeCoreCount) {
detectCoreTypes(cpu);
}
if (cpu->frequencyMax == 0) {
detectMaxSpeedBySmbios(cpu);
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -42,7 +42,7 @@ FFDisplayResult* ffdsAppendDisplay(
display->hdrStatus = FF_DISPLAY_HDR_STATUS_UNKNOWN;
display->manufactureYear = 0;
display->manufactureWeek = 0;
display->serial = 0;
ffStrbufInit(&display->serial);
display->drrStatus = FF_DISPLAY_DRR_STATUS_UNKNOWN;
return display;
+1 -1
View File
@@ -89,7 +89,7 @@ typedef struct FFDisplayResult {
FFDisplayHdrStatus hdrStatus;
uint16_t manufactureYear;
uint16_t manufactureWeek;
uint32_t serial;
FFstrbuf serial;
FFDisplayVrrStatus drrStatus;
} FFDisplayResult;
@@ -9,6 +9,7 @@
#include <assert.h>
#include <CoreGraphics/CGDirectDisplay.h>
#include <CoreVideo/CVDisplayLink.h>
#include <IOKit/IOKitLib.h>
#ifdef MAC_OS_X_VERSION_10_15
extern Boolean CoreDisplay_Display_SupportsHDRMode(CGDirectDisplayID display) FF_A_WEAK_IMPORT;
@@ -28,6 +29,7 @@ static void detectDisplays(FFDisplayServerResult* ds) {
FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreate();
for (uint32_t i = 0; i < screenCount; i++) {
CGDirectDisplayID screen = screens[i];
boolean_t builtin = CGDisplayIsBuiltin(screen);
CGDisplayModeRef mode = CGDisplayCopyDisplayMode(screen);
if (mode) {
// https://github.com/glfw/glfw/commit/aab08712dd8142b642e2042e7b7ba563acd07a45
@@ -63,20 +65,37 @@ static void detectDisplays(FFDisplayServerResult* ds) {
uint32_t physicalWidth = 0, physicalHeight = 0;
uint32_t preferredWidth = 0, preferredHeight = 0;
double preferredRefreshRate = 0;
FF_STRBUF_AUTO_DESTROY serial = ffStrbufCreate();
if (displayInfo) {
CFDictionaryRef productNames;
if (ffCfDictGetDict(displayInfo, CFSTR(kDisplayProductName), &productNames) == NULL) {
ffCfDictGetString(productNames, CFSTR("en_US"), &buffer);
}
// CGDisplayScreenSize reports invalid result for external displays on old Intel MacBook Pro
CFDataRef edidRef = (CFDataRef) CFDictionaryGetValue(displayInfo, CFSTR(kIODisplayEDIDKey));
if (edidRef && CFGetTypeID(edidRef) == CFDataGetTypeID()) {
const uint8_t* edidData = CFDataGetBytePtr(edidRef);
uint32_t edidLength = (uint32_t) CFDataGetLength(edidRef);
if (edidLength >= 128) {
if (ffEdidIsValid(edidData, edidLength)) {
ffEdidGetPhysicalSize(edidData, &physicalWidth, &physicalHeight);
ffEdidGetSerial(edidData, &serial);
}
} else if (!builtin && ffCfDictGetString(displayInfo, CFSTR(kIODisplayLocationKey), &buffer) == NULL) {
FF_IOOBJECT_AUTO_RELEASE io_registry_entry_t ioDisplay = IORegistryEntryFromPath(MACH_PORT_NULL, buffer.chars);
ffStrbufClear(&buffer);
if (ioDisplay) {
FF_CFTYPE_AUTO_RELEASE CFDictionaryRef displayAttrRef = IORegistryEntryCreateCFProperty(ioDisplay, CFSTR("DisplayAttributes"), kCFAllocatorDefault, kNilOptions);
if (displayAttrRef && CFGetTypeID(displayAttrRef) == CFDictionaryGetTypeID()) {
CFDictionaryRef productAttrs;
if (ffCfDictGetDict(displayAttrRef, CFSTR("ProductAttributes"), &productAttrs) == NULL) {
ffCfDictGetString(productAttrs, CFSTR("AlphanumericSerialNumber"), &serial);
ffCfDictGetString(productAttrs, CFSTR("ProductName"), &buffer);
}
}
}
}
if (!buffer.length) {
CFDictionaryRef productNames;
if (ffCfDictGetDict(displayInfo, CFSTR(kDisplayProductName), &productNames) == NULL) {
ffCfDictGetString(productNames, CFSTR("en_US"), &buffer);
}
}
@@ -125,7 +144,7 @@ static void detectDisplays(FFDisplayServerResult* ds) {
preferredRefreshRate,
(uint32_t) CGDisplayRotation(screen),
&buffer,
CGDisplayIsBuiltin(screen) ? FF_DISPLAY_TYPE_BUILTIN : FF_DISPLAY_TYPE_EXTERNAL,
builtin ? FF_DISPLAY_TYPE_BUILTIN : FF_DISPLAY_TYPE_EXTERNAL,
CGDisplayIsMain(screen),
(uint64_t) screen,
physicalWidth,
@@ -166,7 +185,14 @@ static void detectDisplays(FFDisplayServerResult* ds) {
}
#endif
display->serial = CGDisplaySerialNumber(screen);
if (serial.length) {
ffStrbufInitMove(&display->serial, &serial);
} else {
uint32_t int_serial = CGDisplaySerialNumber(screen);
if (int_serial != 0 && int_serial != 0xFFFFFFFF) {
ffStrbufSetF(&display->serial, "0x%08X", int_serial);
}
}
if (displayInfo) {
int value;
@@ -196,7 +196,8 @@ static void detectDisplays(FFDisplayServerResult* ds) {
}
}
if (edid.length > 0) {
ffEdidGetSerialAndManufactureDate(edid.data, &display->serial, &display->manufactureYear, &display->manufactureWeek);
ffEdidGetManufactureDate(edid.data, &display->manufactureYear, &display->manufactureWeek);
ffEdidGetSerial(edid.data, &display->serial);
}
display->drrStatus = path->flags & DISPLAYCONFIG_PATH_BOOST_REFRESH_RATE ? FF_DISPLAY_DRR_STATUS_ENABLED : FF_DISPLAY_DRR_STATUS_DISABLED;
}
+215 -201
View File
@@ -2,6 +2,7 @@
#include "common/io.h"
#include "common/edidHelper.h"
#include "common/strutil.h"
#include "common/mallocHelper.h"
#ifdef __linux__
#include <dirent.h>
@@ -43,8 +44,8 @@ static const char* drmParseSysfs(FFDisplayServerResult* result) {
}
}
unsigned width = 0, height = 0, physicalWidth = 0, physicalHeight = 0;
double refreshRate = 0;
uint32_t width = 0, height = 0, physicalWidth = 0, physicalHeight = 0, preferredWidth = 0, preferredHeight = 0;
double preferredRefreshRate = 0;
FF_STRBUF_AUTO_DESTROY name = ffStrbufCreate();
ffStrbufSubstrBefore(&drmDir, drmDirWithDnameLength);
@@ -58,33 +59,35 @@ static const char* drmParseSysfs(FFDisplayServerResult* result) {
}
}
uint8_t edidData[512];
ssize_t edidLength = ffReadFileData(drmDir.chars, ARRAY_SIZE(edidData), edidData);
if (edidLength <= 0 || edidLength % 128 != 0) {
edidLength = 0;
ffStrbufSubstrBefore(&drmDir, drmDirWithDnameLength);
ffStrbufAppendS(&drmDir, "/modes");
ffStrbufSubstrBefore(&drmDir, drmDirWithDnameLength);
ffStrbufAppendS(&drmDir, "/modes");
char modes[32];
if (ffReadFileData(drmDir.chars, ARRAY_SIZE(modes), modes) >= 3) {
sscanf(modes, "%ux%u", &width, &height);
ffStrbufAppendS(&name, plainName);
}
} else {
char modes[32];
if (ffReadFileData(drmDir.chars, ARRAY_SIZE(modes), modes) >= 3) {
// This is actually preferred resolution
sscanf(modes, "%ux%u", &width, &height);
ffStrbufAppendS(&name, plainName);
}
uint8_t edidData[1024];
ssize_t edidLength = ffReadFileData(drmDir.chars, ARRAY_SIZE(edidData), edidData);
if (edidLength > 0 && ffEdidIsValid(edidData, (uint32_t) edidLength)) {
ffEdidGetName(edidData, &name);
ffEdidGetPreferredResolutionAndRefreshRate(edidData, &width, &height, &refreshRate);
ffEdidGetPreferredResolutionAndRefreshRate(edidData, &preferredWidth, &preferredHeight, &preferredRefreshRate);
ffEdidGetPhysicalSize(edidData, &physicalWidth, &physicalHeight);
} else {
edidLength = 0;
}
FFDisplayResult* item = ffdsAppendDisplay(
result,
width,
height,
refreshRate,
0,
0,
0,
0,
preferredWidth,
preferredHeight,
preferredRefreshRate,
0,
&name,
ffdsGetDisplayType(plainName),
@@ -95,7 +98,8 @@ static const char* drmParseSysfs(FFDisplayServerResult* result) {
"sysfs-drm");
if (item && edidLength) {
item->hdrStatus = ffEdidGetHdrCompatible(edidData, (uint32_t) edidLength) ? FF_DISPLAY_HDR_STATUS_SUPPORTED : FF_DISPLAY_HDR_STATUS_UNSUPPORTED;
ffEdidGetSerialAndManufactureDate(edidData, &item->serial, &item->manufactureYear, &item->manufactureWeek);
ffEdidGetManufactureDate(edidData, &item->manufactureYear, &item->manufactureWeek);
ffEdidGetSerial(edidData, &item->serial);
}
ffStrbufSubstrBefore(&drmDir, drmDirLength);
@@ -105,13 +109,18 @@ static const char* drmParseSysfs(FFDisplayServerResult* result) {
}
#endif
#ifdef FF_HAVE_DRM
#if FF_HAVE_DRM || __has_include(<drm/drm.h>)
#include "common/library.h"
#include <xf86drm.h>
#include <xf86drmMode.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#if FF_HAVE_DRM
#include <drm.h>
#include <drm_mode.h>
#else
#define FF_HAVE_DRM 1
#include <drm/drm.h>
#include <drm/drm_mode.h>
#endif
// https://gitlab.freedesktop.org/mesa/drm/-/blob/main/xf86drmMode.c#L1785
// It's not supported on Ubuntu 20.04
@@ -207,221 +216,226 @@ FF_A_UNUSED static const char* drmGetEdidByConnId(uint32_t connId, uint8_t* edid
}
static const char* drmConnectLibdrm(FFDisplayServerResult* result) {
FF_LIBRARY_LOAD_MESSAGE(libdrm, "libdrm" FF_LIBRARY_EXTENSION, 2)
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, drmGetDevices)
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, drmModeGetResources)
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, drmModeGetConnectorCurrent)
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, drmModeGetCrtc)
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, drmModeGetEncoder)
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, drmModeGetFB)
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, drmModeGetProperty)
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, drmModeGetPropertyBlob)
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, drmModeFreeResources)
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, drmModeFreeCrtc)
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, drmModeFreeConnector)
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, drmModeFreeEncoder)
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, drmModeFreeFB)
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, drmModeFreeProperty)
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, drmModeFreePropertyBlob)
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, drmFreeDevices)
drmDevice* devices[64];
int nDevices = ffdrmGetDevices(devices, ARRAY_SIZE(devices));
if (nDevices <= 0) {
return "drmGetDevices() failed";
FF_AUTO_CLOSE_DIR DIR* dirp = opendir("/dev/dri/");
if (dirp == NULL) {
return "opendir(/dev/dri/) failed";
}
int drifd = dirfd(dirp);
FF_STRBUF_AUTO_DESTROY name = ffStrbufCreate();
int nSuccess = 0;
for (int iDev = 0; iDev < nDevices; ++iDev) {
drmDevice* dev = devices[iDev];
if (!(dev->available_nodes & (1 << DRM_NODE_PRIMARY))) {
struct dirent* entry;
while ((entry = readdir(dirp)) != NULL) {
if (entry->d_name[0] == '.' || !ffStrStartsWith(entry->d_name, "card")) {
continue;
}
const char* path = dev->nodes[DRM_NODE_PRIMARY];
#if __linux__
ffStrbufSetF(&name, "/sys/class/drm/%s/device/power/runtime_status", strrchr(path, '/') + 1);
char powerStatusBuf[512];
snprintf(powerStatusBuf, ARRAY_SIZE(powerStatusBuf), "/sys/class/drm/%s/device/power/runtime_status", entry->d_name);
char buffer[8] = "";
if (ffReadFileData(name.chars, strlen("suspend"), buffer) > 0 && ffStrStartsWith(buffer, "suspend")) {
if (ffReadFileData(powerStatusBuf, strlen("suspend"), buffer) > 0 && ffStrStartsWith(buffer, "suspend")) {
continue;
}
#endif
FF_AUTO_CLOSE_FD int primaryFd = open(path, O_RDWR | O_CLOEXEC);
FF_AUTO_CLOSE_FD int primaryFd = openat(drifd, entry->d_name, O_RDWR | O_CLOEXEC);
if (primaryFd < 0) {
continue;
}
drmModeRes* res = ffdrmModeGetResources(primaryFd);
if (!res) {
struct drm_mode_card_res res_ = {};
if (ioctl(primaryFd, DRM_IOCTL_MODE_GETRESOURCES, &res_) < 0 || res_.count_connectors <= 0) {
continue;
}
for (int iConn = 0; iConn < res->count_connectors; ++iConn) {
drmModeConnector* conn = ffdrmModeGetConnectorCurrent(primaryFd, res->connectors[iConn]);
if (!conn) {
FF_AUTO_FREE uint32_t* connectors = malloc(res_.count_connectors * sizeof(*connectors));
struct drm_mode_card_res res = {
.count_connectors = res_.count_connectors,
.connector_id_ptr = (uintptr_t) connectors,
};
if (ioctl(primaryFd, DRM_IOCTL_MODE_GETRESOURCES, &res) < 0) {
continue;
}
++nSuccess;
for (uint32_t iConn = 0; iConn < res.count_connectors; ++iConn) {
struct drm_mode_get_connector conn = {
.connector_id = connectors[iConn]
};
if (ioctl(primaryFd, DRM_IOCTL_MODE_GETCONNECTOR, &conn) < 0) {
continue;
}
if (conn->connection != DRM_MODE_DISCONNECTED) {
drmModeEncoder* encoder = ffdrmModeGetEncoder(primaryFd, conn->encoder_id);
uint32_t width = 0, height = 0, refreshRate = 0;
uint8_t bitDepth = 0;
if (conn.connection == 2 /* connector_status_disconnected */) {
continue;
}
if (encoder) {
drmModeCrtc* crtc = ffdrmModeGetCrtc(primaryFd, encoder->crtc_id);
if (crtc) {
width = crtc->mode.hdisplay;
height = crtc->mode.vdisplay;
refreshRate = crtc->mode.vrefresh;
if (refreshRate == 0) {
// There are weird cases that we can't get the refresh rate from the CRTC but from the modes
for (int iMode = 0; iMode < conn->count_modes; ++iMode) {
drmModeModeInfo* mode = &conn->modes[iMode];
if (mode->clock == crtc->mode.clock && mode->htotal == crtc->mode.htotal) {
refreshRate = mode->vrefresh;
break;
}
uint32_t width = 0, height = 0, refreshRate = 0;
uint8_t bitDepth = 0;
if (conn.encoder_id > 0) {
struct drm_mode_get_encoder enc = {
.encoder_id = conn.encoder_id
};
if (ioctl(primaryFd, DRM_IOCTL_MODE_GETENCODER, &enc) >= 0 && enc.crtc_id > 0) {
struct drm_mode_crtc crtc = {
.crtc_id = enc.crtc_id,
};
if (ioctl(primaryFd, DRM_IOCTL_MODE_GETCRTC, &crtc) >= 0) {
width = crtc.mode.hdisplay;
height = crtc.mode.vdisplay;
refreshRate = crtc.mode.vrefresh;
if (crtc.fb_id > 0) {
struct drm_mode_fb_cmd fb = {
.fb_id = crtc.fb_id,
};
if (ioctl(primaryFd, DRM_IOCTL_MODE_GETFB, &fb) >= 0) {
bitDepth = (uint8_t) (fb.depth / 3);
}
}
drmModeFBPtr fb = ffdrmModeGetFB(primaryFd, crtc->buffer_id);
if (fb) {
bitDepth = (uint8_t) (fb->depth / 3);
ffdrmModeFreeFB(fb);
}
ffdrmModeFreeCrtc(crtc);
}
ffdrmModeFreeEncoder(encoder);
}
uint32_t preferredWidth = 0, preferredHeight = 0, preferredRefreshRate = 0;
for (int iMode = 0; iMode < conn->count_modes; ++iMode) {
drmModeModeInfo* mode = &conn->modes[iMode];
if (mode->type & DRM_MODE_TYPE_PREFERRED) {
preferredWidth = mode->hdisplay;
preferredHeight = mode->vdisplay;
preferredRefreshRate = mode->vrefresh;
break;
}
}
// NVIDIA DRM driver seems incomplete and conn->encoder_id == 0
// Assume preferred resolution is used as what we do in drmParseSys
if (width == 0 || height == 0) {
width = preferredWidth;
height = preferredHeight;
refreshRate = preferredRefreshRate;
}
ffStrbufClear(&name);
uint16_t myear = 0, mweak = 0;
uint32_t serial = 0;
FFDisplayHdrStatus hdrStatus = FF_DISPLAY_HDR_STATUS_UNKNOWN;
for (int iProp = 0; iProp < conn->count_props; ++iProp) {
drmModePropertyRes* prop = ffdrmModeGetProperty(primaryFd, conn->props[iProp]);
if (!prop) {
continue;
}
uint32_t type = prop->flags & (DRM_MODE_PROP_LEGACY_TYPE | DRM_MODE_PROP_EXTENDED_TYPE);
if (type == DRM_MODE_PROP_BLOB && ffStrEquals(prop->name, "EDID")) {
drmModePropertyBlobPtr blob = NULL;
if (prop->count_blobs > 0 && prop->blob_ids != NULL) {
blob = ffdrmModeGetPropertyBlob(primaryFd, prop->blob_ids[0]);
} else {
blob = ffdrmModeGetPropertyBlob(primaryFd, (uint32_t) conn->prop_values[iProp]);
}
if (blob) {
if (blob->length >= 128) {
ffEdidGetName(blob->data, &name);
hdrStatus = ffEdidGetHdrCompatible(blob->data, blob->length) ? FF_DISPLAY_HDR_STATUS_SUPPORTED : FF_DISPLAY_HDR_STATUS_UNSUPPORTED;
ffEdidGetSerialAndManufactureDate(blob->data, &serial, &myear, &mweak);
}
ffdrmModeFreePropertyBlob(blob);
}
break;
}
ffdrmModeFreeProperty(prop);
}
#if __linux__
if (name.length == 0) {
uint8_t edidData[512];
ssize_t edidLength = 0;
drmGetEdidByConnId(conn->connector_id, edidData, &edidLength);
if (edidLength > 0 && edidLength % 128 == 0) {
ffEdidGetName(edidData, &name);
hdrStatus = ffEdidGetHdrCompatible(edidData, (uint32_t) edidLength) ? FF_DISPLAY_HDR_STATUS_SUPPORTED : FF_DISPLAY_HDR_STATUS_UNSUPPORTED;
ffEdidGetSerialAndManufactureDate(edidData, &serial, &myear, &mweak);
}
}
#endif
if (name.length == 0) {
const char* connectorTypeName = drmType2Name(conn->connector_type);
if (connectorTypeName == NULL) {
connectorTypeName = "Unknown";
}
ffStrbufSetF(&name, "%s-%d", connectorTypeName, iConn + 1);
}
FFDisplayResult* item = ffdsAppendDisplay(result,
width,
height,
refreshRate,
0,
preferredWidth,
preferredHeight,
preferredRefreshRate,
0,
&name,
conn->connector_type == DRM_MODE_CONNECTOR_eDP || conn->connector_type == DRM_MODE_CONNECTOR_LVDS
? FF_DISPLAY_TYPE_BUILTIN
: conn->connector_type == DRM_MODE_CONNECTOR_HDMIA || conn->connector_type == DRM_MODE_CONNECTOR_HDMIB || conn->connector_type == DRM_MODE_CONNECTOR_DisplayPort
? FF_DISPLAY_TYPE_EXTERNAL
: FF_DISPLAY_TYPE_UNKNOWN,
false,
conn->connector_id,
conn->mmWidth,
conn->mmHeight,
"libdrm");
if (item) {
item->hdrStatus = hdrStatus;
item->serial = serial;
item->manufactureYear = myear;
item->manufactureWeek = mweak;
item->bitDepth = bitDepth;
}
}
ffdrmModeFreeConnector(conn);
}
uint32_t preferredWidth = 0, preferredHeight = 0, preferredRefreshRate = 0;
if (conn.count_modes > 0) {
FF_AUTO_FREE struct drm_mode_modeinfo* modes = malloc(conn.count_modes * sizeof(*modes));
struct drm_mode_get_connector connModes = {
.connector_id = connectors[iConn],
.modes_ptr = (uintptr_t) modes,
.count_modes = conn.count_modes
};
if (ioctl(primaryFd, DRM_IOCTL_MODE_GETCONNECTOR, &connModes) >= 0) {
for (uint32_t iMode = 0; iMode < connModes.count_modes; ++iMode) {
if (modes[iMode].type & DRM_MODE_TYPE_PREFERRED) {
preferredWidth = modes[iMode].hdisplay;
preferredHeight = modes[iMode].vdisplay;
preferredRefreshRate = modes[iMode].vrefresh;
break;
}
}
}
}
ffdrmModeFreeResources(res);
if (width == 0 || height == 0) {
width = preferredWidth;
height = preferredHeight;
refreshRate = preferredRefreshRate;
}
FF_STRBUF_AUTO_DESTROY name = ffStrbufCreate();
uint16_t myear = 0, mweak = 0;
FF_STRBUF_AUTO_DESTROY serial = ffStrbufCreate();
FFDisplayHdrStatus hdrStatus = FF_DISPLAY_HDR_STATUS_UNKNOWN;
uint32_t* props = malloc(conn.count_props * sizeof(uint32_t));
uint64_t* propValues = malloc(conn.count_props * sizeof(uint64_t));
if (props && propValues && conn.count_props > 0) {
struct drm_mode_get_connector connProps = {
.connector_id = connectors[iConn],
.props_ptr = (uintptr_t) props,
.prop_values_ptr = (uintptr_t) propValues,
.count_props = conn.count_props,
};
if (ioctl(primaryFd, DRM_IOCTL_MODE_GETCONNECTOR, &connProps) >= 0) {
for (uint32_t iProp = 0; iProp < connProps.count_props; ++iProp) {
struct drm_mode_get_property prop = {
.prop_id = props[iProp],
};
if (ioctl(primaryFd, DRM_IOCTL_MODE_GETPROPERTY, &prop) < 0) {
continue;
}
uint32_t type = prop.flags & (DRM_MODE_PROP_LEGACY_TYPE | DRM_MODE_PROP_EXTENDED_TYPE);
if (type == DRM_MODE_PROP_BLOB && ffStrEquals(prop.name, "EDID")) {
struct drm_mode_get_blob blob_ = {
.blob_id = (uint32_t) propValues[iProp]
};
if (ioctl(primaryFd, DRM_IOCTL_MODE_GETPROPBLOB, &blob_) >= 0 && blob_.length > 0) {
FF_AUTO_FREE void* blobData = malloc(blob_.length);
struct drm_mode_get_blob blob = {
.blob_id = blob_.blob_id,
.length = blob_.length,
.data = (uintptr_t) blobData
};
if (ioctl(primaryFd, DRM_IOCTL_MODE_GETPROPBLOB, &blob) >= 0 && ffEdidIsValid(blobData, blob.length)) {
ffEdidGetName(blobData, &name);
hdrStatus = ffEdidGetHdrCompatible(blobData, blob.length) ? FF_DISPLAY_HDR_STATUS_SUPPORTED : FF_DISPLAY_HDR_STATUS_UNSUPPORTED;
ffEdidGetManufactureDate(blobData, &myear, &mweak);
ffEdidGetSerial(blobData, &serial);
}
}
break;
}
}
}
}
#if __linux__
if (name.length == 0) {
uint8_t edidData[512];
ssize_t edidLength = 0;
drmGetEdidByConnId(conn.connector_id, edidData, &edidLength);
if (edidLength > 0 && ffEdidIsValid(edidData, (uint32_t) edidLength)) {
ffEdidGetName(edidData, &name);
hdrStatus = ffEdidGetHdrCompatible(edidData, (uint32_t) edidLength) ? FF_DISPLAY_HDR_STATUS_SUPPORTED : FF_DISPLAY_HDR_STATUS_UNSUPPORTED;
ffEdidGetManufactureDate(edidData, &myear, &mweak);
ffEdidGetSerial(edidData, &serial);
}
}
#endif
if (name.length == 0) {
const char* connectorTypeName = drmType2Name(conn.connector_type);
if (connectorTypeName == NULL) {
connectorTypeName = "Unknown";
}
ffStrbufSetF(&name, "%s-%d", connectorTypeName, iConn + 1);
}
FFDisplayResult* item = ffdsAppendDisplay(result,
width,
height,
refreshRate,
0,
preferredWidth,
preferredHeight,
preferredRefreshRate,
0,
&name,
conn.connector_type == DRM_MODE_CONNECTOR_eDP || conn.connector_type == DRM_MODE_CONNECTOR_LVDS
? FF_DISPLAY_TYPE_BUILTIN
: conn.connector_type == DRM_MODE_CONNECTOR_HDMIA || conn.connector_type == DRM_MODE_CONNECTOR_HDMIB || conn.connector_type == DRM_MODE_CONNECTOR_DisplayPort
? FF_DISPLAY_TYPE_EXTERNAL
: FF_DISPLAY_TYPE_UNKNOWN,
false,
conn.connector_id,
conn.mm_width,
conn.mm_height,
"libdrm");
if (item) {
item->hdrStatus = hdrStatus;
ffStrbufInitMove(&item->serial, &serial);
item->manufactureYear = myear;
item->manufactureWeek = mweak;
item->bitDepth = bitDepth;
}
}
}
ffdrmFreeDevices(devices, nDevices);
return NULL;
return nSuccess > 0 ? NULL : "No connectors found using libdrm";
}
#endif
const char* ffdsConnectDrm(FF_A_UNUSED FFDisplayServerResult* result) {
#ifdef FF_HAVE_DRM
#if FF_HAVE_DRM
if (instance.config.general.dsForceDrm != FF_DS_FORCE_DRM_TYPE_SYSFS_ONLY) {
if (drmConnectLibdrm(result) == NULL) {
return NULL;
@@ -3,6 +3,7 @@
#include "wayland.h"
#include "common/strutil.h"
#include "xdg-output-unstable-v1-client-protocol.h"
#include "wp-color-management-v1-client-protocol.h"
static void waylandOutputModeListener(void* data, FF_A_UNUSED struct wl_output* output, uint32_t flags, int32_t width, int32_t height, int32_t refreshRate) {
WaylandDisplay* display = data;
@@ -70,10 +71,36 @@ static struct zxdg_output_v1_listener zxdgOutputListener = {
.description = (void*) ffWaylandOutputDescriptionListener,
};
static void handleWpTfNamed(void *data, FF_A_UNUSED struct wp_image_description_info_v1* wp_image_description_info_v1, uint32_t tf) {
// KDE reports `gamma 2.2` even in HDR mode, but it should be handled in KDE specific path
WaylandDisplay* display = data;
switch (tf) {
case WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_ST2084_PQ:
case WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_HLG:
display->hdrInfoAvailable = true;
display->hdrEnabled = true;
break;
}
}
static const struct wp_image_description_info_v1_listener wpImageDescInfoListener = {
.done = (void*) stubListener,
.icc_file = (void*) stubListener,
.primaries = (void*) stubListener,
.primaries_named = (void*) stubListener,
.tf_power = (void*) stubListener,
.tf_named = (void*) handleWpTfNamed,
.luminances = (void*) stubListener,
.target_primaries = (void*) stubListener,
.target_luminance = (void*) stubListener,
.target_max_cll = (void*) stubListener,
.target_max_fall = (void*) stubListener,
};
const char* ffWaylandHandleGlobalOutput(WaylandData* wldata, struct wl_registry* registry, uint32_t name, uint32_t version) {
const char* api = "wayland-global";
const char* api = "wayland-base";
uint32_t bindVersion = min(version, WL_OUTPUT_DESCRIPTION_SINCE_VERSION);
struct wl_proxy* output = wldata->ffwl_proxy_marshal_constructor_versioned((struct wl_proxy*) registry, WL_REGISTRY_BIND, wldata->ffwl_output_interface, bindVersion, name, wldata->ffwl_output_interface->name, bindVersion, NULL);
struct wl_proxy* output = wldata->ffwl_proxy_marshal_constructor_versioned((struct wl_proxy*) registry, WL_REGISTRY_BIND, &wl_output_interface, bindVersion, name, wl_output_interface.name, bindVersion, NULL);
if (output == NULL) {
return "Failed to create wl_output";
}
@@ -104,7 +131,28 @@ const char* ffWaylandHandleGlobalOutput(WaylandData* wldata, struct wl_registry*
wldata->ffwl_proxy_add_listener(zxdgOutput, (void (**)(void)) &zxdgOutputListener, &display);
wldata->ffwl_display_roundtrip(wldata->display);
wldata->ffwl_proxy_destroy(zxdgOutput);
api = "wayland-global-zxdg";
api = "wayland-zxdg";
}
}
if (wldata->wpColorManager) {
uint32_t bindVersion = min(version, WP_COLOR_MANAGER_V1_GET_OUTPUT_SINCE_VERSION);
struct wl_proxy* wpColorOutput = wldata->ffwl_proxy_marshal_constructor_versioned(wldata->wpColorManager, WP_COLOR_MANAGER_V1_GET_OUTPUT, &wp_color_management_output_v1_interface, bindVersion, NULL, output);
if (wpColorOutput) {
struct wl_proxy* wpImageDesc = wldata->ffwl_proxy_marshal_constructor_versioned(wpColorOutput, WP_COLOR_MANAGEMENT_OUTPUT_V1_GET_IMAGE_DESCRIPTION, &wp_image_description_v1_interface, bindVersion, NULL);
if (wpImageDesc) {
struct wl_proxy* wpImageDescInfo = wldata->ffwl_proxy_marshal_constructor_versioned(wpImageDesc, WP_IMAGE_DESCRIPTION_V1_GET_INFORMATION, &wp_image_description_info_v1_interface, bindVersion, NULL);
if (wpImageDescInfo) {
wldata->ffwl_proxy_add_listener(wpImageDescInfo, (void (**)(void)) &wpImageDescInfoListener, &display);
wldata->ffwl_display_roundtrip(wldata->display);
wldata->ffwl_proxy_destroy(wpImageDescInfo);
}
wldata->ffwl_proxy_destroy(wpImageDesc);
}
wldata->ffwl_proxy_destroy(wpColorOutput);
wldata->ffwl_display_roundtrip(wldata->display);
api = api[strlen("wayland-")] == 'z' ? "wayland-zxdg+wpcolor" : "wayland-wpcolor";
}
}
@@ -138,7 +186,9 @@ const char* ffWaylandHandleGlobalOutput(WaylandData* wldata, struct wl_registry*
(uint32_t) display.physicalHeight,
api);
if (item) {
if (display.hdrSupported) {
if (display.hdrEnabled) {
item->hdrStatus = FF_DISPLAY_HDR_STATUS_ENABLED;
} else if (display.hdrSupported) {
item->hdrStatus = FF_DISPLAY_HDR_STATUS_SUPPORTED;
} else if (display.hdrInfoAvailable) {
item->hdrStatus = FF_DISPLAY_HDR_STATUS_UNSUPPORTED;
@@ -148,7 +198,7 @@ const char* ffWaylandHandleGlobalOutput(WaylandData* wldata, struct wl_registry*
item->manufactureYear = display.myear;
item->manufactureWeek = display.mweek;
item->serial = display.serial;
ffStrbufInitMove(&item->serial, &display.serial);
}
ffStrbufDestroy(&display.description);
@@ -170,4 +220,16 @@ const char* ffWaylandHandleZxdgOutput(WaylandData* wldata, struct wl_registry* r
return NULL;
}
const char* ffWaylandHandleWpColor(WaylandData* wldata, struct wl_registry* registry, uint32_t name, uint32_t version) {
uint32_t bindVersion = min(version, WP_COLOR_MANAGER_V1_GET_OUTPUT_SINCE_VERSION);
struct wl_proxy* manager = wldata->ffwl_proxy_marshal_constructor_versioned((struct wl_proxy*) registry, WL_REGISTRY_BIND, &wp_color_manager_v1_interface, bindVersion, name, wp_color_manager_v1_interface.name, bindVersion, NULL);
if (manager == NULL) {
return "Failed to create wp_color_manager_v1";
}
wldata->wpColorManager = manager;
return NULL;
}
#endif
@@ -1,134 +0,0 @@
/* Generated by wayland-scanner 1.22.0 */
#ifndef KDE_OUTPUT_ORDER_V1_CLIENT_PROTOCOL_H
#define KDE_OUTPUT_ORDER_V1_CLIENT_PROTOCOL_H
#include <stdint.h>
#include <stddef.h>
#include "wayland-client.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @page page_kde_output_order_v1 The kde_output_order_v1 protocol
* @section page_ifaces_kde_output_order_v1 Interfaces
* - @subpage page_iface_kde_output_order_v1 - announce order of outputs
* @section page_copyright_kde_output_order_v1 Copyright
* <pre>
*
* SPDX-FileCopyrightText: 2022 Xaver Hugl <xaver.hugl@gmail.com>
*
* SPDX-License-Identifier: MIT-CMU
* </pre>
*/
struct kde_output_order_v1;
#ifndef KDE_OUTPUT_ORDER_V1_INTERFACE
#define KDE_OUTPUT_ORDER_V1_INTERFACE
/**
* @page page_iface_kde_output_order_v1 kde_output_order_v1
* @section page_iface_kde_output_order_v1_desc Description
*
* Announce the order in which desktop environment components should be placed on outputs.
* The compositor will send the list of outputs when the global is bound and whenever there is a change.
* @section page_iface_kde_output_order_v1_api API
* See @ref iface_kde_output_order_v1.
*/
/**
* @defgroup iface_kde_output_order_v1 The kde_output_order_v1 interface
*
* Announce the order in which desktop environment components should be placed on outputs.
* The compositor will send the list of outputs when the global is bound and whenever there is a change.
*/
extern const struct wl_interface kde_output_order_v1_interface;
#endif
/**
* @ingroup iface_kde_output_order_v1
* @struct kde_output_order_v1_listener
*/
struct kde_output_order_v1_listener {
/**
* output name
*
* Specifies the output identified by their wl_output.name.
* @param output_name the name of the output
*/
void (*output)(void* data,
struct kde_output_order_v1* kde_output_order_v1,
const char* output_name);
/**
* done
*
* Specifies that the output list is complete. On the next output
* event, a new list begins.
*/
void (*done)(void* data,
struct kde_output_order_v1* kde_output_order_v1);
};
/**
* @ingroup iface_kde_output_order_v1
*/
static inline int
kde_output_order_v1_add_listener(struct kde_output_order_v1* kde_output_order_v1,
const struct kde_output_order_v1_listener* listener,
void* data) {
return wl_proxy_add_listener((struct wl_proxy*) kde_output_order_v1,
(void (**)(void)) listener,
data);
}
#define KDE_OUTPUT_ORDER_V1_DESTROY 0
/**
* @ingroup iface_kde_output_order_v1
*/
#define KDE_OUTPUT_ORDER_V1_OUTPUT_SINCE_VERSION 1
/**
* @ingroup iface_kde_output_order_v1
*/
#define KDE_OUTPUT_ORDER_V1_DONE_SINCE_VERSION 1
/**
* @ingroup iface_kde_output_order_v1
*/
#define KDE_OUTPUT_ORDER_V1_DESTROY_SINCE_VERSION 1
// /** @ingroup iface_kde_output_order_v1 */
// static inline void
// kde_output_order_v1_set_user_data(struct kde_output_order_v1 *kde_output_order_v1, void *user_data)
// {
// wl_proxy_set_user_data((struct wl_proxy *) kde_output_order_v1, user_data);
// }
// /** @ingroup iface_kde_output_order_v1 */
// static inline void *
// kde_output_order_v1_get_user_data(struct kde_output_order_v1 *kde_output_order_v1)
// {
// return wl_proxy_get_user_data((struct wl_proxy *) kde_output_order_v1);
// }
// static inline uint32_t
// kde_output_order_v1_get_version(struct kde_output_order_v1 *kde_output_order_v1)
// {
// return wl_proxy_get_version((struct wl_proxy *) kde_output_order_v1);
// }
// /**
// * @ingroup iface_kde_output_order_v1
// */
// static inline void
// kde_output_order_v1_destroy(struct kde_output_order_v1 *kde_output_order_v1)
// {
// wl_proxy_marshal_flags((struct wl_proxy *) kde_output_order_v1,
// KDE_OUTPUT_ORDER_V1_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) kde_output_order_v1), WL_MARSHAL_FLAG_DESTROY);
// }
#ifdef __cplusplus
}
#endif
#endif
@@ -1,37 +0,0 @@
#ifdef FF_HAVE_WAYLAND
/* Generated by wayland-scanner 1.22.0 */
/*
* SPDX-FileCopyrightText: 2022 Xaver Hugl <xaver.hugl@gmail.com>
*
* SPDX-License-Identifier: MIT-CMU
*/
#include <stdlib.h>
#include <stdint.h>
#include "wayland-util.h"
static const struct wl_interface* kde_output_order_v1_types[] = {
NULL,
};
static const struct wl_message kde_output_order_v1_requests[] = {
{ "destroy", "", kde_output_order_v1_types + 0 },
};
static const struct wl_message kde_output_order_v1_events[] = {
{ "output", "s", kde_output_order_v1_types + 0 },
{ "done", "", kde_output_order_v1_types + 0 },
};
WL_EXPORT const struct wl_interface kde_output_order_v1_interface = {
"kde_output_order_v1",
1,
1,
kde_output_order_v1_requests,
2,
kde_output_order_v1_events,
};
#endif
@@ -2,7 +2,6 @@
#include "wayland.h"
#include "kde-output-device-v2-client-protocol.h"
#include "kde-output-order-v1-client-protocol.h"
#include "common/edidHelper.h"
#include "common/base64.h"
@@ -96,7 +95,8 @@ static void waylandKdeEdidListener(void* data, FF_A_UNUSED struct kde_output_dev
}
ffEdidGetName((const uint8_t*) edid.chars, &wldata->edidName);
wldata->hdrSupported = ffEdidGetHdrCompatible((const uint8_t*) edid.chars, edid.length);
ffEdidGetSerialAndManufactureDate((const uint8_t*) edid.chars, &wldata->serial, &wldata->myear, &wldata->mweek);
ffEdidGetManufactureDate((const uint8_t*) edid.chars, &wldata->myear, &wldata->mweek);
ffEdidGetSerial((const uint8_t*) edid.chars, &wldata->serial);
wldata->hdrInfoAvailable = true;
}
@@ -142,6 +142,11 @@ static void waylandKdeMaxBitsPerColorListener(void* data, FF_A_UNUSED struct kde
display->bitDepth = (uint8_t) max_bpc;
}
static void waylandKdePriorityListener(void* data, FF_A_UNUSED struct kde_output_device_v2* kde_output_device_v2, uint32_t priority) {
WaylandDisplay* display = data;
display->primary = priority == 1;
}
static struct kde_output_device_v2_listener outputListener = {
.geometry = waylandKdeGeometryListener,
.current_mode = waylandKdeCurrentModeListener,
@@ -176,15 +181,16 @@ static struct kde_output_device_v2_listener outputListener = {
.max_bits_per_color_range = (void*) stubListener,
.automatic_max_bits_per_color_limit = (void*) stubListener,
.edr_policy = (void*) stubListener,
.sharpness = (void*) stubListener,
.priority = waylandKdePriorityListener,
.auto_brightness = (void*) stubListener,
.removed = (void*) stubListener,
.hdr_icc_profile_path = (void*) stubListener,
.hdr_color_profile_source = (void*) stubListener,
.abm_level = (void*) stubListener,
};
const char* ffWaylandHandleKdeOutput(WaylandData* wldata, struct wl_registry* registry, uint32_t name, uint32_t version) {
uint32_t bindVersion = min(version, KDE_OUTPUT_DEVICE_V2_MAX_BITS_PER_COLOR_SINCE_VERSION);
struct wl_proxy* output = wldata->ffwl_proxy_marshal_constructor_versioned((struct wl_proxy*) registry, WL_REGISTRY_BIND, &kde_output_device_v2_interface, bindVersion, name, kde_output_device_v2_interface.name, bindVersion, NULL);
if (output == NULL) {
return "Failed to create kde_output_device_v2";
}
static const char* waylandKdeHandleOutput(WaylandData* wldata, struct wl_proxy* output) {
FF_LIST_AUTO_DESTROY modes = ffListCreate();
WaylandDisplay display = {
.parent = wldata,
@@ -236,7 +242,7 @@ const char* ffWaylandHandleKdeOutput(WaylandData* wldata, struct wl_registry* re
? &display.edidName
: &display.name,
display.type,
false,
display.primary,
display.id,
(uint32_t) display.physicalWidth,
(uint32_t) display.physicalHeight,
@@ -254,7 +260,7 @@ const char* ffWaylandHandleKdeOutput(WaylandData* wldata, struct wl_registry* re
item->manufactureYear = display.myear;
item->manufactureWeek = display.mweek;
item->serial = display.serial;
ffStrbufInitMove(&item->serial, &display.serial);
item->bitDepth = display.bitDepth;
}
@@ -265,35 +271,42 @@ const char* ffWaylandHandleKdeOutput(WaylandData* wldata, struct wl_registry* re
return NULL;
}
static void waylandKdeOutputOrderListener(void* data, FF_A_UNUSED struct kde_output_order_v1* _, const char* output_name) {
uint64_t* id = (uint64_t*) data;
if (*id == 0) {
*id = ffWaylandGenerateIdFromName(output_name);
const char* ffWaylandHandleKdeOutput(WaylandData* wldata, struct wl_registry* registry, uint32_t name, uint32_t version) {
// TODO: remove this in future versions
uint32_t bindVersion = min(version, KDE_OUTPUT_DEVICE_V2_PRIORITY_SINCE_VERSION);
struct wl_proxy* output = wldata->ffwl_proxy_marshal_constructor_versioned((struct wl_proxy*) registry, WL_REGISTRY_BIND, &kde_output_device_v2_interface, bindVersion, name, kde_output_device_v2_interface.name, bindVersion, NULL);
if (output == NULL) {
return "Failed to create kde_output_device_v2";
}
return waylandKdeHandleOutput(wldata, output);
}
static const struct kde_output_order_v1_listener orderListener = {
.output = waylandKdeOutputOrderListener,
.done = (void*) stubListener,
static void waylandKdeOutputListener(void* data, FF_A_UNUSED struct kde_output_device_registry_v2* kde_output_device_registry_v2, struct kde_output_device_v2* output) {
waylandKdeHandleOutput((WaylandData*) data, (struct wl_proxy*) output);
}
static struct kde_output_device_registry_v2_listener registryListener = {
.output = waylandKdeOutputListener,
.finished = (void*) stubListener,
};
const char* ffWaylandHandleKdeOutputOrder(WaylandData* wldata, struct wl_registry* registry, uint32_t name, uint32_t version) {
uint32_t bindVersion = min(version, KDE_OUTPUT_ORDER_V1_OUTPUT_SINCE_VERSION);
struct wl_proxy* output = wldata->ffwl_proxy_marshal_constructor_versioned((struct wl_proxy*) registry, WL_REGISTRY_BIND, &kde_output_order_v1_interface, bindVersion, name, kde_output_order_v1_interface.name, bindVersion, NULL);
if (output == NULL) {
return "Failed to create kde_output_order_v1";
const char* ffWaylandHandleKdeOutputRegistry(WaylandData* wldata, struct wl_registry* registry, uint32_t name, uint32_t version) {
uint32_t bindVersion = min(version, KDE_OUTPUT_DEVICE_REGISTRY_V2_OUTPUT_SINCE_VERSION);
struct wl_proxy* outputRegistry = wldata->ffwl_proxy_marshal_constructor_versioned((struct wl_proxy*) registry, WL_REGISTRY_BIND, &kde_output_device_registry_v2_interface, bindVersion, name, kde_output_device_registry_v2_interface.name, bindVersion, NULL);
if (outputRegistry == NULL) {
return "Failed to create kde_output_device_registry_v2";
}
if (wldata->ffwl_proxy_add_listener(output, (void (**)(void)) &orderListener, &wldata->primaryDisplayId) < 0) {
wldata->ffwl_proxy_destroy(output);
return "Failed to add listener to kde_output_order_v1";
if (wldata->ffwl_proxy_add_listener(outputRegistry, (void (**)(void)) &registryListener, wldata) < 0) {
wldata->ffwl_proxy_destroy(outputRegistry);
return "Failed to add listener to kde_output_device_registry_v2";
}
if (wldata->ffwl_display_roundtrip(wldata->display) < 0) {
wldata->ffwl_proxy_destroy(output);
return "Failed to roundtrip kde_output_order_v1";
wldata->ffwl_proxy_destroy(outputRegistry);
return "Failed to roundtrip kde_output_device_registry_v2";
}
wldata->ffwl_proxy_destroy(output);
wldata->ffwl_proxy_destroy(outputRegistry);
return NULL;
}
@@ -13,10 +13,9 @@
#include "common/properties.h"
#include "wayland.h"
#include "wlr-output-management-unstable-v1-client-protocol.h"
#include "kde-output-device-v2-client-protocol.h"
#include "kde-output-order-v1-client-protocol.h"
#include "xdg-output-unstable-v1-client-protocol.h"
#include "wp-color-management-v1-client-protocol.h"
#if __FreeBSD__
#include <sys/un.h>
@@ -81,25 +80,25 @@ static bool waylandDetectWM(int fd, FFDisplayServerResult* result) {
static void waylandGlobalAddListener(void* data, struct wl_registry* registry, uint32_t name, const char* interface, uint32_t version) {
WaylandData* wldata = data;
if ((wldata->protocolType == FF_WAYLAND_PROTOCOL_TYPE_NONE || wldata->protocolType == FF_WAYLAND_PROTOCOL_TYPE_GLOBAL) && ffStrEquals(interface, wldata->ffwl_output_interface->name)) {
if ((wldata->protocolType == FF_WAYLAND_PROTOCOL_TYPE_NONE || wldata->protocolType == FF_WAYLAND_PROTOCOL_TYPE_GLOBAL) && ffStrEquals(interface, wl_output_interface.name)) {
wldata->protocolType = FF_WAYLAND_PROTOCOL_TYPE_GLOBAL;
if (ffWaylandHandleGlobalOutput(wldata, registry, name, version) != NULL) {
wldata->protocolType = FF_WAYLAND_PROTOCOL_TYPE_NONE;
}
} else if ((wldata->protocolType == FF_WAYLAND_PROTOCOL_TYPE_NONE || wldata->protocolType == FF_WAYLAND_PROTOCOL_TYPE_ZWLR) && ffStrEquals(interface, zwlr_output_manager_v1_interface.name)) {
wldata->protocolType = FF_WAYLAND_PROTOCOL_TYPE_ZWLR;
if (ffWaylandHandleZwlrOutput(wldata, registry, name, version) != NULL) {
} else if ((wldata->protocolType == FF_WAYLAND_PROTOCOL_TYPE_NONE) && ffStrEquals(interface, kde_output_device_registry_v2_interface.name)) {
wldata->protocolType = FF_WAYLAND_PROTOCOL_TYPE_KDE_REGISTRY;
if (ffWaylandHandleKdeOutputRegistry(wldata, registry, name, version) != NULL) {
wldata->protocolType = FF_WAYLAND_PROTOCOL_TYPE_NONE;
}
} else if ((wldata->protocolType == FF_WAYLAND_PROTOCOL_TYPE_NONE || wldata->protocolType == FF_WAYLAND_PROTOCOL_TYPE_KDE) && ffStrEquals(interface, kde_output_device_v2_interface.name)) {
wldata->protocolType = FF_WAYLAND_PROTOCOL_TYPE_KDE;
} else if ((wldata->protocolType == FF_WAYLAND_PROTOCOL_TYPE_NONE || wldata->protocolType == FF_WAYLAND_PROTOCOL_TYPE_KDE_DEPRECATED) && ffStrEquals(interface, kde_output_device_v2_interface.name)) {
wldata->protocolType = FF_WAYLAND_PROTOCOL_TYPE_KDE_DEPRECATED;
if (ffWaylandHandleKdeOutput(wldata, registry, name, version) != NULL) {
wldata->protocolType = FF_WAYLAND_PROTOCOL_TYPE_NONE;
}
} else if (ffStrEquals(interface, kde_output_order_v1_interface.name)) {
ffWaylandHandleKdeOutputOrder(wldata, registry, name, version);
} else if ((wldata->protocolType == FF_WAYLAND_PROTOCOL_TYPE_GLOBAL || wldata->protocolType == FF_WAYLAND_PROTOCOL_TYPE_NONE) && ffStrEquals(interface, zxdg_output_manager_v1_interface.name)) {
ffWaylandHandleZxdgOutput(wldata, registry, name, version);
} else if ((wldata->protocolType == FF_WAYLAND_PROTOCOL_TYPE_GLOBAL || wldata->protocolType == FF_WAYLAND_PROTOCOL_TYPE_NONE) && ffStrEquals(interface, wp_color_manager_v1_interface.name)) {
ffWaylandHandleWpColor(wldata, registry, name, version);
}
}
@@ -128,10 +127,19 @@ static FF_A_UNUSED bool matchDrmConnector(const char* connName, WaylandDisplay*
uint8_t edidData[512];
ssize_t edidLength = ffReadFileData(path.chars, ARRAY_SIZE(edidData), edidData);
if (edidLength > 0 && edidLength % 128 == 0) {
if (edidLength > 0 && ffEdidIsValid(edidData, (uint32_t) edidLength)) {
ffEdidGetName(edidData, &wldata->edidName);
ffEdidGetHdrCompatible(edidData, (uint32_t) edidLength);
ffEdidGetSerialAndManufactureDate(edidData, &wldata->serial, &wldata->myear, &wldata->mweek);
wldata->hdrSupported = ffEdidGetHdrCompatible(edidData, (uint32_t) edidLength);
ffEdidGetManufactureDate((const uint8_t*) edidData, &wldata->myear, &wldata->mweek);
ffEdidGetSerial((const uint8_t*) edidData, &wldata->serial);
if (wldata->preferredWidth == 0) {
uint32_t preferredWidth = 0, preferredHeight = 0;
double preferredRefreshRate = 0;
ffEdidGetPreferredResolutionAndRefreshRate(edidData, &preferredWidth, &preferredHeight, &preferredRefreshRate);
wldata->preferredWidth = (int32_t) preferredWidth;
wldata->preferredHeight = (int32_t) preferredHeight;
wldata->preferredRefreshRate = (int32_t) (preferredRefreshRate * 1000.);
}
wldata->hdrInfoAvailable = true;
return true;
}
@@ -220,7 +228,6 @@ const char* ffdsConnectWayland(FFDisplayServerResult* result) {
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(wayland, wl_display_get_fd)
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(wayland, wl_proxy_marshal_constructor)
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(wayland, wl_display_disconnect)
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(wayland, wl_registry_interface)
WaylandData data = {};
@@ -228,7 +235,6 @@ const char* ffdsConnectWayland(FFDisplayServerResult* result) {
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(wayland, data, wl_proxy_add_listener)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(wayland, data, wl_proxy_destroy)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(wayland, data, wl_display_roundtrip)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(wayland, data, wl_output_interface)
data.display = ffwl_display_connect(NULL);
if (data.display == NULL) {
@@ -237,7 +243,7 @@ const char* ffdsConnectWayland(FFDisplayServerResult* result) {
waylandDetectWM(ffwl_display_get_fd(data.display), result);
struct wl_proxy* registry = ffwl_proxy_marshal_constructor((struct wl_proxy*) data.display, WL_DISPLAY_GET_REGISTRY, ffwl_registry_interface, NULL);
struct wl_proxy* registry = ffwl_proxy_marshal_constructor((struct wl_proxy*) data.display, WL_DISPLAY_GET_REGISTRY, &wl_registry_interface, NULL);
if (registry == NULL) {
ffwl_display_disconnect(data.display);
return "wl_display_get_registry returned NULL";
@@ -257,10 +263,14 @@ const char* ffdsConnectWayland(FFDisplayServerResult* result) {
data.ffwl_proxy_destroy(data.zxdgOutputManager);
}
if (data.wpColorManager) {
data.ffwl_proxy_destroy(data.wpColorManager);
}
data.ffwl_proxy_destroy(registry);
ffwl_display_disconnect(data.display);
if (data.primaryDisplayId == 0 && result->wmProcessName.length > 0) {
{
const char* fileName = ffStrbufEqualS(&result->wmProcessName, "gnome-shell")
? "monitors.xml"
: ffStrbufEqualS(&result->wmProcessName, "cinnamon")
@@ -307,7 +317,14 @@ const char* ffdsConnectWayland(FFDisplayServerResult* result) {
if (end < monitorsXml.length) {
ffStrbufSubstrBefore(&monitorsXml, end);
const char* name = monitorsXml.chars + start + strlen("<connector>");
data.primaryDisplayId = ffWaylandGenerateIdFromName(name);
uint64_t primaryDisplayId = ffWaylandGenerateIdFromName(name);
FF_LIST_FOR_EACH (FFDisplayResult, d, data.result->displays) {
if (d->id == primaryDisplayId) {
d->primary = true;
break;
}
}
}
}
}
@@ -315,15 +332,6 @@ const char* ffdsConnectWayland(FFDisplayServerResult* result) {
}
}
if (data.primaryDisplayId) {
FF_LIST_FOR_EACH (FFDisplayResult, d, data.result->displays) {
if (d->id == data.primaryDisplayId) {
d->primary = true;
break;
}
}
}
// We successfully connected to wayland and detected the display.
// So we can set set the session type to wayland.
// This is used as an indicator that we are running wayland by the x11 backends.
@@ -16,8 +16,8 @@ static inline uint32_t min(uint32_t a, uint32_t b) {
typedef enum FF_A_PACKED WaylandProtocolType {
FF_WAYLAND_PROTOCOL_TYPE_NONE,
FF_WAYLAND_PROTOCOL_TYPE_GLOBAL,
FF_WAYLAND_PROTOCOL_TYPE_ZWLR,
FF_WAYLAND_PROTOCOL_TYPE_KDE,
FF_WAYLAND_PROTOCOL_TYPE_KDE_DEPRECATED,
FF_WAYLAND_PROTOCOL_TYPE_KDE_REGISTRY,
} WaylandProtocolType;
typedef struct WaylandData {
@@ -27,10 +27,9 @@ typedef struct WaylandData {
FF_LIBRARY_SYMBOL(wl_proxy_destroy)
FF_LIBRARY_SYMBOL(wl_display_roundtrip)
struct wl_display* display;
const struct wl_interface* ffwl_output_interface;
WaylandProtocolType protocolType;
uint64_t primaryDisplayId;
struct wl_proxy* zxdgOutputManager;
struct wl_proxy* wpColorManager;
} WaylandData;
typedef struct WaylandDisplay {
@@ -56,8 +55,9 @@ typedef struct WaylandDisplay {
bool hdrEnabled;
uint16_t myear;
uint16_t mweek;
uint32_t serial;
FFstrbuf serial;
uint8_t bitDepth;
bool primary;
} WaylandDisplay;
inline static void stubListener(void* data, ...) {
@@ -81,9 +81,10 @@ void ffWaylandOutputDescriptionListener(void* data, FF_A_UNUSED void* output, co
uint32_t ffWaylandHandleRotation(WaylandDisplay* display);
const char* ffWaylandHandleGlobalOutput(WaylandData* wldata, struct wl_registry* registry, uint32_t name, uint32_t version);
const char* ffWaylandHandleZwlrOutput(WaylandData* wldata, struct wl_registry* registry, uint32_t name, uint32_t version);
const char* ffWaylandHandleKdeOutputRegistry(WaylandData* wldata, struct wl_registry* registry, uint32_t name, uint32_t version);
const char* ffWaylandHandleKdeOutput(WaylandData* wldata, struct wl_registry* registry, uint32_t name, uint32_t version);
const char* ffWaylandHandleKdeOutputOrder(WaylandData* wldata, struct wl_registry* registry, uint32_t name, uint32_t version);
const char* ffWaylandHandleZxdgOutput(WaylandData* wldata, struct wl_registry* registry, uint32_t name, uint32_t version);
const char* ffWaylandHandleWpColor(WaylandData* wldata, struct wl_registry* registry, uint32_t name, uint32_t version);
#endif
@@ -0,0 +1,531 @@
#ifdef FF_HAVE_WAYLAND
/* Generated by wayland-scanner 1.24.0 */
/*
* Copyright © 2008-2011 Kristian Høgsberg
* Copyright © 2010-2011 Intel Corporation
* Copyright © 2012-2013 Collabora, Ltd.
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <stdbool.h>
#include <stdlib.h>
#include <stdint.h>
#include <wayland-util.h>
extern const struct wl_interface wl_buffer_interface;
extern const struct wl_interface wl_callback_interface;
extern const struct wl_interface wl_data_device_interface;
extern const struct wl_interface wl_data_offer_interface;
extern const struct wl_interface wl_data_source_interface;
extern const struct wl_interface wl_keyboard_interface;
extern const struct wl_interface wl_output_interface;
extern const struct wl_interface wl_pointer_interface;
extern const struct wl_interface wl_region_interface;
extern const struct wl_interface wl_registry_interface;
extern const struct wl_interface wl_seat_interface;
extern const struct wl_interface wl_shell_surface_interface;
extern const struct wl_interface wl_shm_pool_interface;
extern const struct wl_interface wl_subsurface_interface;
extern const struct wl_interface wl_surface_interface;
extern const struct wl_interface wl_touch_interface;
static const struct wl_interface *wayland_types[] = {
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
&wl_callback_interface,
&wl_registry_interface,
&wl_surface_interface,
&wl_region_interface,
&wl_buffer_interface,
NULL,
NULL,
NULL,
NULL,
NULL,
&wl_shm_pool_interface,
NULL,
NULL,
&wl_data_source_interface,
&wl_surface_interface,
&wl_surface_interface,
NULL,
&wl_data_source_interface,
NULL,
&wl_data_offer_interface,
NULL,
&wl_surface_interface,
NULL,
NULL,
&wl_data_offer_interface,
&wl_data_offer_interface,
&wl_data_source_interface,
&wl_data_device_interface,
&wl_seat_interface,
&wl_shell_surface_interface,
&wl_surface_interface,
&wl_seat_interface,
NULL,
&wl_seat_interface,
NULL,
NULL,
&wl_surface_interface,
NULL,
NULL,
NULL,
NULL,
NULL,
&wl_output_interface,
&wl_seat_interface,
NULL,
&wl_surface_interface,
NULL,
NULL,
NULL,
&wl_output_interface,
&wl_buffer_interface,
NULL,
NULL,
&wl_callback_interface,
&wl_region_interface,
&wl_region_interface,
&wl_output_interface,
&wl_output_interface,
&wl_pointer_interface,
&wl_keyboard_interface,
&wl_touch_interface,
NULL,
&wl_surface_interface,
NULL,
NULL,
NULL,
&wl_surface_interface,
NULL,
NULL,
NULL,
&wl_surface_interface,
NULL,
&wl_surface_interface,
NULL,
NULL,
&wl_surface_interface,
NULL,
NULL,
&wl_surface_interface,
NULL,
NULL,
NULL,
&wl_subsurface_interface,
&wl_surface_interface,
&wl_surface_interface,
&wl_surface_interface,
&wl_surface_interface,
&wl_registry_interface,
};
static const struct wl_message wl_display_requests[] = {
{ "sync", "n", wayland_types + 8 },
{ "get_registry", "n", wayland_types + 9 },
};
static const struct wl_message wl_display_events[] = {
{ "error", "ous", wayland_types + 0 },
{ "delete_id", "u", wayland_types + 0 },
};
WL_EXPORT const struct wl_interface wl_display_interface = {
"wl_display", 1,
2, wl_display_requests,
2, wl_display_events,
};
static const struct wl_message wl_registry_requests[] = {
{ "bind", "usun", wayland_types + 0 },
};
static const struct wl_message wl_registry_events[] = {
{ "global", "usu", wayland_types + 0 },
{ "global_remove", "u", wayland_types + 0 },
};
WL_EXPORT const struct wl_interface wl_registry_interface = {
"wl_registry", 1,
1, wl_registry_requests,
2, wl_registry_events,
};
static const struct wl_message wl_callback_events[] = {
{ "done", "u", wayland_types + 0 },
};
WL_EXPORT const struct wl_interface wl_callback_interface = {
"wl_callback", 1,
0, NULL,
1, wl_callback_events,
};
static const struct wl_message wl_compositor_requests[] = {
{ "create_surface", "n", wayland_types + 10 },
{ "create_region", "n", wayland_types + 11 },
};
WL_EXPORT const struct wl_interface wl_compositor_interface = {
"wl_compositor", 6,
2, wl_compositor_requests,
0, NULL,
};
static const struct wl_message wl_shm_pool_requests[] = {
{ "create_buffer", "niiiiu", wayland_types + 12 },
{ "destroy", "", wayland_types + 0 },
{ "resize", "i", wayland_types + 0 },
};
WL_EXPORT const struct wl_interface wl_shm_pool_interface = {
"wl_shm_pool", 2,
3, wl_shm_pool_requests,
0, NULL,
};
static const struct wl_message wl_shm_requests[] = {
{ "create_pool", "nhi", wayland_types + 18 },
{ "release", "2", wayland_types + 0 },
};
static const struct wl_message wl_shm_events[] = {
{ "format", "u", wayland_types + 0 },
};
WL_EXPORT const struct wl_interface wl_shm_interface = {
"wl_shm", 2,
2, wl_shm_requests,
1, wl_shm_events,
};
static const struct wl_message wl_buffer_requests[] = {
{ "destroy", "", wayland_types + 0 },
};
static const struct wl_message wl_buffer_events[] = {
{ "release", "", wayland_types + 0 },
};
WL_EXPORT const struct wl_interface wl_buffer_interface = {
"wl_buffer", 1,
1, wl_buffer_requests,
1, wl_buffer_events,
};
static const struct wl_message wl_data_offer_requests[] = {
{ "accept", "u?s", wayland_types + 0 },
{ "receive", "sh", wayland_types + 0 },
{ "destroy", "", wayland_types + 0 },
{ "finish", "3", wayland_types + 0 },
{ "set_actions", "3uu", wayland_types + 0 },
};
static const struct wl_message wl_data_offer_events[] = {
{ "offer", "s", wayland_types + 0 },
{ "source_actions", "3u", wayland_types + 0 },
{ "action", "3u", wayland_types + 0 },
};
WL_EXPORT const struct wl_interface wl_data_offer_interface = {
"wl_data_offer", 3,
5, wl_data_offer_requests,
3, wl_data_offer_events,
};
static const struct wl_message wl_data_source_requests[] = {
{ "offer", "s", wayland_types + 0 },
{ "destroy", "", wayland_types + 0 },
{ "set_actions", "3u", wayland_types + 0 },
};
static const struct wl_message wl_data_source_events[] = {
{ "target", "?s", wayland_types + 0 },
{ "send", "sh", wayland_types + 0 },
{ "cancelled", "", wayland_types + 0 },
{ "dnd_drop_performed", "3", wayland_types + 0 },
{ "dnd_finished", "3", wayland_types + 0 },
{ "action", "3u", wayland_types + 0 },
};
WL_EXPORT const struct wl_interface wl_data_source_interface = {
"wl_data_source", 3,
3, wl_data_source_requests,
6, wl_data_source_events,
};
static const struct wl_message wl_data_device_requests[] = {
{ "start_drag", "?oo?ou", wayland_types + 21 },
{ "set_selection", "?ou", wayland_types + 25 },
{ "release", "2", wayland_types + 0 },
};
static const struct wl_message wl_data_device_events[] = {
{ "data_offer", "n", wayland_types + 27 },
{ "enter", "uoff?o", wayland_types + 28 },
{ "leave", "", wayland_types + 0 },
{ "motion", "uff", wayland_types + 0 },
{ "drop", "", wayland_types + 0 },
{ "selection", "?o", wayland_types + 33 },
};
WL_EXPORT const struct wl_interface wl_data_device_interface = {
"wl_data_device", 3,
3, wl_data_device_requests,
6, wl_data_device_events,
};
static const struct wl_message wl_data_device_manager_requests[] = {
{ "create_data_source", "n", wayland_types + 34 },
{ "get_data_device", "no", wayland_types + 35 },
};
WL_EXPORT const struct wl_interface wl_data_device_manager_interface = {
"wl_data_device_manager", 3,
2, wl_data_device_manager_requests,
0, NULL,
};
static const struct wl_message wl_shell_requests[] = {
{ "get_shell_surface", "no", wayland_types + 37 },
};
WL_EXPORT const struct wl_interface wl_shell_interface = {
"wl_shell", 1,
1, wl_shell_requests,
0, NULL,
};
static const struct wl_message wl_shell_surface_requests[] = {
{ "pong", "u", wayland_types + 0 },
{ "move", "ou", wayland_types + 39 },
{ "resize", "ouu", wayland_types + 41 },
{ "set_toplevel", "", wayland_types + 0 },
{ "set_transient", "oiiu", wayland_types + 44 },
{ "set_fullscreen", "uu?o", wayland_types + 48 },
{ "set_popup", "ouoiiu", wayland_types + 51 },
{ "set_maximized", "?o", wayland_types + 57 },
{ "set_title", "s", wayland_types + 0 },
{ "set_class", "s", wayland_types + 0 },
};
static const struct wl_message wl_shell_surface_events[] = {
{ "ping", "u", wayland_types + 0 },
{ "configure", "uii", wayland_types + 0 },
{ "popup_done", "", wayland_types + 0 },
};
WL_EXPORT const struct wl_interface wl_shell_surface_interface = {
"wl_shell_surface", 1,
10, wl_shell_surface_requests,
3, wl_shell_surface_events,
};
static const struct wl_message wl_surface_requests[] = {
{ "destroy", "", wayland_types + 0 },
{ "attach", "?oii", wayland_types + 58 },
{ "damage", "iiii", wayland_types + 0 },
{ "frame", "n", wayland_types + 61 },
{ "set_opaque_region", "?o", wayland_types + 62 },
{ "set_input_region", "?o", wayland_types + 63 },
{ "commit", "", wayland_types + 0 },
{ "set_buffer_transform", "2i", wayland_types + 0 },
{ "set_buffer_scale", "3i", wayland_types + 0 },
{ "damage_buffer", "4iiii", wayland_types + 0 },
{ "offset", "5ii", wayland_types + 0 },
};
static const struct wl_message wl_surface_events[] = {
{ "enter", "o", wayland_types + 64 },
{ "leave", "o", wayland_types + 65 },
{ "preferred_buffer_scale", "6i", wayland_types + 0 },
{ "preferred_buffer_transform", "6u", wayland_types + 0 },
};
WL_EXPORT const struct wl_interface wl_surface_interface = {
"wl_surface", 6,
11, wl_surface_requests,
4, wl_surface_events,
};
static const struct wl_message wl_seat_requests[] = {
{ "get_pointer", "n", wayland_types + 66 },
{ "get_keyboard", "n", wayland_types + 67 },
{ "get_touch", "n", wayland_types + 68 },
{ "release", "5", wayland_types + 0 },
};
static const struct wl_message wl_seat_events[] = {
{ "capabilities", "u", wayland_types + 0 },
{ "name", "2s", wayland_types + 0 },
};
WL_EXPORT const struct wl_interface wl_seat_interface = {
"wl_seat", 10,
4, wl_seat_requests,
2, wl_seat_events,
};
static const struct wl_message wl_pointer_requests[] = {
{ "set_cursor", "u?oii", wayland_types + 69 },
{ "release", "3", wayland_types + 0 },
};
static const struct wl_message wl_pointer_events[] = {
{ "enter", "uoff", wayland_types + 73 },
{ "leave", "uo", wayland_types + 77 },
{ "motion", "uff", wayland_types + 0 },
{ "button", "uuuu", wayland_types + 0 },
{ "axis", "uuf", wayland_types + 0 },
{ "frame", "5", wayland_types + 0 },
{ "axis_source", "5u", wayland_types + 0 },
{ "axis_stop", "5uu", wayland_types + 0 },
{ "axis_discrete", "5ui", wayland_types + 0 },
{ "axis_value120", "8ui", wayland_types + 0 },
{ "axis_relative_direction", "9uu", wayland_types + 0 },
};
WL_EXPORT const struct wl_interface wl_pointer_interface = {
"wl_pointer", 10,
2, wl_pointer_requests,
11, wl_pointer_events,
};
static const struct wl_message wl_keyboard_requests[] = {
{ "release", "3", wayland_types + 0 },
};
static const struct wl_message wl_keyboard_events[] = {
{ "keymap", "uhu", wayland_types + 0 },
{ "enter", "uoa", wayland_types + 79 },
{ "leave", "uo", wayland_types + 82 },
{ "key", "uuuu", wayland_types + 0 },
{ "modifiers", "uuuuu", wayland_types + 0 },
{ "repeat_info", "4ii", wayland_types + 0 },
};
WL_EXPORT const struct wl_interface wl_keyboard_interface = {
"wl_keyboard", 10,
1, wl_keyboard_requests,
6, wl_keyboard_events,
};
static const struct wl_message wl_touch_requests[] = {
{ "release", "3", wayland_types + 0 },
};
static const struct wl_message wl_touch_events[] = {
{ "down", "uuoiff", wayland_types + 84 },
{ "up", "uui", wayland_types + 0 },
{ "motion", "uiff", wayland_types + 0 },
{ "frame", "", wayland_types + 0 },
{ "cancel", "", wayland_types + 0 },
{ "shape", "6iff", wayland_types + 0 },
{ "orientation", "6if", wayland_types + 0 },
};
WL_EXPORT const struct wl_interface wl_touch_interface = {
"wl_touch", 10,
1, wl_touch_requests,
7, wl_touch_events,
};
static const struct wl_message wl_output_requests[] = {
{ "release", "3", wayland_types + 0 },
};
static const struct wl_message wl_output_events[] = {
{ "geometry", "iiiiissi", wayland_types + 0 },
{ "mode", "uiii", wayland_types + 0 },
{ "done", "2", wayland_types + 0 },
{ "scale", "2i", wayland_types + 0 },
{ "name", "4s", wayland_types + 0 },
{ "description", "4s", wayland_types + 0 },
};
WL_EXPORT const struct wl_interface wl_output_interface = {
"wl_output", 4,
1, wl_output_requests,
6, wl_output_events,
};
static const struct wl_message wl_region_requests[] = {
{ "destroy", "", wayland_types + 0 },
{ "add", "iiii", wayland_types + 0 },
{ "subtract", "iiii", wayland_types + 0 },
};
WL_EXPORT const struct wl_interface wl_region_interface = {
"wl_region", 1,
3, wl_region_requests,
0, NULL,
};
static const struct wl_message wl_subcompositor_requests[] = {
{ "destroy", "", wayland_types + 0 },
{ "get_subsurface", "noo", wayland_types + 90 },
};
WL_EXPORT const struct wl_interface wl_subcompositor_interface = {
"wl_subcompositor", 1,
2, wl_subcompositor_requests,
0, NULL,
};
static const struct wl_message wl_subsurface_requests[] = {
{ "destroy", "", wayland_types + 0 },
{ "set_position", "ii", wayland_types + 0 },
{ "place_above", "o", wayland_types + 93 },
{ "place_below", "o", wayland_types + 94 },
{ "set_sync", "", wayland_types + 0 },
{ "set_desync", "", wayland_types + 0 },
};
WL_EXPORT const struct wl_interface wl_subsurface_interface = {
"wl_subsurface", 1,
6, wl_subsurface_requests,
0, NULL,
};
static const struct wl_message wl_fixes_requests[] = {
{ "destroy", "", wayland_types + 0 },
{ "destroy_registry", "o", wayland_types + 95 },
};
WL_EXPORT const struct wl_interface wl_fixes_interface = {
"wl_fixes", 1,
2, wl_fixes_requests,
0, NULL,
};
#endif
@@ -1,176 +0,0 @@
#ifdef FF_HAVE_WAYLAND
/* Generated by wayland-scanner 1.24.0 */
/*
* Copyright © 2019 Purism SPC
*
* Permission to use, copy, modify, distribute, and sell this
* software and its documentation for any purpose is hereby granted
* without fee, provided that the above copyright notice appear in
* all copies and that both that copyright notice and this permission
* notice appear in supporting documentation, and that the name of
* the copyright holders not be used in advertising or publicity
* pertaining to distribution of the software without specific,
* written prior permission. The copyright holders make no
* representations about the suitability of this software for any
* purpose. It is provided "as is" without express or implied
* warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
* AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
* ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
* THIS SOFTWARE.
*/
#include <stdbool.h>
#include <stdlib.h>
#include <stdint.h>
#include <wayland-util.h>
#ifndef __has_attribute
#define __has_attribute(x) 0 /* Compatibility with non-clang compilers. */
#endif
#if (__has_attribute(visibility) || defined(__GNUC__) && __GNUC__ >= 4)
#define WL_PRIVATE __attribute__((visibility("hidden")))
#else
#define WL_PRIVATE
#endif
extern const struct wl_interface zwlr_output_configuration_head_v1_interface;
extern const struct wl_interface zwlr_output_configuration_v1_interface;
extern const struct wl_interface zwlr_output_head_v1_interface;
extern const struct wl_interface zwlr_output_mode_v1_interface;
static const struct wl_interface* wlr_output_management_unstable_v1_types[] = {
NULL,
NULL,
NULL,
&zwlr_output_configuration_v1_interface,
NULL,
&zwlr_output_head_v1_interface,
&zwlr_output_mode_v1_interface,
&zwlr_output_mode_v1_interface,
&zwlr_output_configuration_head_v1_interface,
&zwlr_output_head_v1_interface,
&zwlr_output_head_v1_interface,
&zwlr_output_mode_v1_interface,
};
static const struct wl_message zwlr_output_manager_v1_requests[] = {
{ "create_configuration", "nu", wlr_output_management_unstable_v1_types + 3 },
{ "stop", "", wlr_output_management_unstable_v1_types + 0 },
};
static const struct wl_message zwlr_output_manager_v1_events[] = {
{ "head", "n", wlr_output_management_unstable_v1_types + 5 },
{ "done", "u", wlr_output_management_unstable_v1_types + 0 },
{ "finished", "", wlr_output_management_unstable_v1_types + 0 },
};
WL_PRIVATE const struct wl_interface zwlr_output_manager_v1_interface = {
"zwlr_output_manager_v1",
4,
2,
zwlr_output_manager_v1_requests,
3,
zwlr_output_manager_v1_events,
};
static const struct wl_message zwlr_output_head_v1_requests[] = {
{ "release", "3", wlr_output_management_unstable_v1_types + 0 },
};
static const struct wl_message zwlr_output_head_v1_events[] = {
{ "name", "s", wlr_output_management_unstable_v1_types + 0 },
{ "description", "s", wlr_output_management_unstable_v1_types + 0 },
{ "physical_size", "ii", wlr_output_management_unstable_v1_types + 0 },
{ "mode", "n", wlr_output_management_unstable_v1_types + 6 },
{ "enabled", "i", wlr_output_management_unstable_v1_types + 0 },
{ "current_mode", "o", wlr_output_management_unstable_v1_types + 7 },
{ "position", "ii", wlr_output_management_unstable_v1_types + 0 },
{ "transform", "i", wlr_output_management_unstable_v1_types + 0 },
{ "scale", "f", wlr_output_management_unstable_v1_types + 0 },
{ "finished", "", wlr_output_management_unstable_v1_types + 0 },
{ "make", "2s", wlr_output_management_unstable_v1_types + 0 },
{ "model", "2s", wlr_output_management_unstable_v1_types + 0 },
{ "serial_number", "2s", wlr_output_management_unstable_v1_types + 0 },
{ "adaptive_sync", "4u", wlr_output_management_unstable_v1_types + 0 },
};
WL_PRIVATE const struct wl_interface zwlr_output_head_v1_interface = {
"zwlr_output_head_v1",
4,
1,
zwlr_output_head_v1_requests,
14,
zwlr_output_head_v1_events,
};
static const struct wl_message zwlr_output_mode_v1_requests[] = {
{ "release", "3", wlr_output_management_unstable_v1_types + 0 },
};
static const struct wl_message zwlr_output_mode_v1_events[] = {
{ "size", "ii", wlr_output_management_unstable_v1_types + 0 },
{ "refresh", "i", wlr_output_management_unstable_v1_types + 0 },
{ "preferred", "", wlr_output_management_unstable_v1_types + 0 },
{ "finished", "", wlr_output_management_unstable_v1_types + 0 },
};
WL_PRIVATE const struct wl_interface zwlr_output_mode_v1_interface = {
"zwlr_output_mode_v1",
3,
1,
zwlr_output_mode_v1_requests,
4,
zwlr_output_mode_v1_events,
};
static const struct wl_message zwlr_output_configuration_v1_requests[] = {
{ "enable_head", "no", wlr_output_management_unstable_v1_types + 8 },
{ "disable_head", "o", wlr_output_management_unstable_v1_types + 10 },
{ "apply", "", wlr_output_management_unstable_v1_types + 0 },
{ "test", "", wlr_output_management_unstable_v1_types + 0 },
{ "destroy", "", wlr_output_management_unstable_v1_types + 0 },
};
static const struct wl_message zwlr_output_configuration_v1_events[] = {
{ "succeeded", "", wlr_output_management_unstable_v1_types + 0 },
{ "failed", "", wlr_output_management_unstable_v1_types + 0 },
{ "cancelled", "", wlr_output_management_unstable_v1_types + 0 },
};
WL_PRIVATE const struct wl_interface zwlr_output_configuration_v1_interface = {
"zwlr_output_configuration_v1",
4,
5,
zwlr_output_configuration_v1_requests,
3,
zwlr_output_configuration_v1_events,
};
static const struct wl_message zwlr_output_configuration_head_v1_requests[] = {
{ "set_mode", "o", wlr_output_management_unstable_v1_types + 11 },
{ "set_custom_mode", "iii", wlr_output_management_unstable_v1_types + 0 },
{ "set_position", "ii", wlr_output_management_unstable_v1_types + 0 },
{ "set_transform", "i", wlr_output_management_unstable_v1_types + 0 },
{ "set_scale", "f", wlr_output_management_unstable_v1_types + 0 },
{ "set_adaptive_sync", "4u", wlr_output_management_unstable_v1_types + 0 },
};
WL_PRIVATE const struct wl_interface zwlr_output_configuration_head_v1_interface = {
"zwlr_output_configuration_head_v1",
4,
6,
zwlr_output_configuration_head_v1_requests,
0,
NULL,
};
#endif
@@ -0,0 +1,225 @@
#ifdef FF_HAVE_WAYLAND
/* Generated by wayland-scanner 1.24.0 */
/*
* Copyright 2019 Sebastian Wick
* Copyright 2019 Erwin Burema
* Copyright 2020 AMD
* Copyright 2020-2024 Collabora, Ltd.
* Copyright 2024 Xaver Hugl
* Copyright 2022-2025 Red Hat, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include <stdbool.h>
#include <stdlib.h>
#include <stdint.h>
#include <wayland-util.h>
extern const struct wl_interface wl_output_interface;
extern const struct wl_interface wl_surface_interface;
extern const struct wl_interface wp_color_management_output_v1_interface;
extern const struct wl_interface wp_color_management_surface_feedback_v1_interface;
extern const struct wl_interface wp_color_management_surface_v1_interface;
extern const struct wl_interface wp_image_description_creator_icc_v1_interface;
extern const struct wl_interface wp_image_description_creator_params_v1_interface;
extern const struct wl_interface wp_image_description_info_v1_interface;
extern const struct wl_interface wp_image_description_reference_v1_interface;
extern const struct wl_interface wp_image_description_v1_interface;
static const struct wl_interface *color_management_v1_types[] = {
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
&wp_color_management_output_v1_interface,
&wl_output_interface,
&wp_color_management_surface_v1_interface,
&wl_surface_interface,
&wp_color_management_surface_feedback_v1_interface,
&wl_surface_interface,
&wp_image_description_creator_icc_v1_interface,
&wp_image_description_creator_params_v1_interface,
&wp_image_description_v1_interface,
&wp_image_description_v1_interface,
&wp_image_description_reference_v1_interface,
&wp_image_description_v1_interface,
&wp_image_description_v1_interface,
NULL,
&wp_image_description_v1_interface,
&wp_image_description_v1_interface,
&wp_image_description_v1_interface,
&wp_image_description_v1_interface,
&wp_image_description_info_v1_interface,
};
static const struct wl_message wp_color_manager_v1_requests[] = {
{ "destroy", "", color_management_v1_types + 0 },
{ "get_output", "no", color_management_v1_types + 8 },
{ "get_surface", "no", color_management_v1_types + 10 },
{ "get_surface_feedback", "no", color_management_v1_types + 12 },
{ "create_icc_creator", "n", color_management_v1_types + 14 },
{ "create_parametric_creator", "n", color_management_v1_types + 15 },
{ "create_windows_scrgb", "n", color_management_v1_types + 16 },
{ "get_image_description", "2no", color_management_v1_types + 17 },
};
static const struct wl_message wp_color_manager_v1_events[] = {
{ "supported_intent", "u", color_management_v1_types + 0 },
{ "supported_feature", "u", color_management_v1_types + 0 },
{ "supported_tf_named", "u", color_management_v1_types + 0 },
{ "supported_primaries_named", "u", color_management_v1_types + 0 },
{ "done", "", color_management_v1_types + 0 },
};
WL_EXPORT const struct wl_interface wp_color_manager_v1_interface = {
"wp_color_manager_v1", 2,
8, wp_color_manager_v1_requests,
5, wp_color_manager_v1_events,
};
static const struct wl_message wp_color_management_output_v1_requests[] = {
{ "destroy", "", color_management_v1_types + 0 },
{ "get_image_description", "n", color_management_v1_types + 19 },
};
static const struct wl_message wp_color_management_output_v1_events[] = {
{ "image_description_changed", "", color_management_v1_types + 0 },
};
WL_EXPORT const struct wl_interface wp_color_management_output_v1_interface = {
"wp_color_management_output_v1", 2,
2, wp_color_management_output_v1_requests,
1, wp_color_management_output_v1_events,
};
static const struct wl_message wp_color_management_surface_v1_requests[] = {
{ "destroy", "", color_management_v1_types + 0 },
{ "set_image_description", "ou", color_management_v1_types + 20 },
{ "unset_image_description", "", color_management_v1_types + 0 },
};
WL_EXPORT const struct wl_interface wp_color_management_surface_v1_interface = {
"wp_color_management_surface_v1", 2,
3, wp_color_management_surface_v1_requests,
0, NULL,
};
static const struct wl_message wp_color_management_surface_feedback_v1_requests[] = {
{ "destroy", "", color_management_v1_types + 0 },
{ "get_preferred", "n", color_management_v1_types + 22 },
{ "get_preferred_parametric", "n", color_management_v1_types + 23 },
};
static const struct wl_message wp_color_management_surface_feedback_v1_events[] = {
{ "preferred_changed", "u", color_management_v1_types + 0 },
{ "preferred_changed2", "2uu", color_management_v1_types + 0 },
};
WL_EXPORT const struct wl_interface wp_color_management_surface_feedback_v1_interface = {
"wp_color_management_surface_feedback_v1", 2,
3, wp_color_management_surface_feedback_v1_requests,
2, wp_color_management_surface_feedback_v1_events,
};
static const struct wl_message wp_image_description_creator_icc_v1_requests[] = {
{ "create", "n", color_management_v1_types + 24 },
{ "set_icc_file", "huu", color_management_v1_types + 0 },
};
WL_EXPORT const struct wl_interface wp_image_description_creator_icc_v1_interface = {
"wp_image_description_creator_icc_v1", 2,
2, wp_image_description_creator_icc_v1_requests,
0, NULL,
};
static const struct wl_message wp_image_description_creator_params_v1_requests[] = {
{ "create", "n", color_management_v1_types + 25 },
{ "set_tf_named", "u", color_management_v1_types + 0 },
{ "set_tf_power", "u", color_management_v1_types + 0 },
{ "set_primaries_named", "u", color_management_v1_types + 0 },
{ "set_primaries", "iiiiiiii", color_management_v1_types + 0 },
{ "set_luminances", "uuu", color_management_v1_types + 0 },
{ "set_mastering_display_primaries", "iiiiiiii", color_management_v1_types + 0 },
{ "set_mastering_luminance", "uu", color_management_v1_types + 0 },
{ "set_max_cll", "u", color_management_v1_types + 0 },
{ "set_max_fall", "u", color_management_v1_types + 0 },
};
WL_EXPORT const struct wl_interface wp_image_description_creator_params_v1_interface = {
"wp_image_description_creator_params_v1", 2,
10, wp_image_description_creator_params_v1_requests,
0, NULL,
};
static const struct wl_message wp_image_description_v1_requests[] = {
{ "destroy", "", color_management_v1_types + 0 },
{ "get_information", "n", color_management_v1_types + 26 },
};
static const struct wl_message wp_image_description_v1_events[] = {
{ "failed", "us", color_management_v1_types + 0 },
{ "ready", "u", color_management_v1_types + 0 },
{ "ready2", "2uu", color_management_v1_types + 0 },
};
WL_EXPORT const struct wl_interface wp_image_description_v1_interface = {
"wp_image_description_v1", 2,
2, wp_image_description_v1_requests,
3, wp_image_description_v1_events,
};
static const struct wl_message wp_image_description_info_v1_events[] = {
{ "done", "", color_management_v1_types + 0 },
{ "icc_file", "hu", color_management_v1_types + 0 },
{ "primaries", "iiiiiiii", color_management_v1_types + 0 },
{ "primaries_named", "u", color_management_v1_types + 0 },
{ "tf_power", "u", color_management_v1_types + 0 },
{ "tf_named", "u", color_management_v1_types + 0 },
{ "luminances", "uuu", color_management_v1_types + 0 },
{ "target_primaries", "iiiiiiii", color_management_v1_types + 0 },
{ "target_luminance", "uu", color_management_v1_types + 0 },
{ "target_max_cll", "u", color_management_v1_types + 0 },
{ "target_max_fall", "u", color_management_v1_types + 0 },
};
WL_EXPORT const struct wl_interface wp_image_description_info_v1_interface = {
"wp_image_description_info_v1", 2,
0, NULL,
11, wp_image_description_info_v1_events,
};
static const struct wl_message wp_image_description_reference_v1_requests[] = {
{ "destroy", "", color_management_v1_types + 0 },
};
WL_EXPORT const struct wl_interface wp_image_description_reference_v1_interface = {
"wp_image_description_reference_v1", 1,
1, wp_image_description_reference_v1_requests,
0, NULL,
};
#endif
@@ -35,7 +35,7 @@ static const struct wl_interface* xdg_output_unstable_v1_types[] = {
NULL,
NULL,
&zxdg_output_v1_interface,
NULL, // &wl_output_interface,
&wl_output_interface,
};
static const struct wl_message zxdg_output_manager_v1_requests[] = {
@@ -1,212 +0,0 @@
#ifdef FF_HAVE_WAYLAND
#include "wayland.h"
#include "wlr-output-management-unstable-v1-client-protocol.h"
static void waylandZwlrTransformListener(void* data, FF_A_UNUSED struct zwlr_output_head_v1* zwlr_output_head_v1, int32_t transform) {
WaylandDisplay* wldata = (WaylandDisplay*) data;
wldata->transform = (enum wl_output_transform) transform;
}
static void waylandZwlrScaleListener(void* data, FF_A_UNUSED struct zwlr_output_head_v1* zwlr_output_head_v1, wl_fixed_t scale) {
WaylandDisplay* wldata = (WaylandDisplay*) data;
wldata->dpi = (uint32_t) scale * 3 / 8; // wl_fixed_to_double(scale) * 96;
}
typedef struct WaylandZwlrMode {
int32_t width;
int32_t height;
int32_t refreshRate;
bool preferred;
struct zwlr_output_mode_v1* pMode;
} WaylandZwlrMode;
static void waylandZwlrModeSizeListener(void* data, FF_A_UNUSED struct zwlr_output_mode_v1* zwlr_output_mode_v1, int32_t width, int32_t height) {
WaylandZwlrMode* mode = (WaylandZwlrMode*) data;
mode->width = width;
mode->height = height;
}
static void waylandZwlrModeRefreshListener(void* data, FF_A_UNUSED struct zwlr_output_mode_v1* zwlr_output_mode_v1, int32_t rate) {
WaylandZwlrMode* mode = (WaylandZwlrMode*) data;
mode->refreshRate = rate;
}
static void waylandZwlrModePreferredListener(void* data, FF_A_UNUSED struct zwlr_output_mode_v1* zwlr_output_mode_v1) {
WaylandZwlrMode* mode = (WaylandZwlrMode*) data;
mode->preferred = true;
}
static const struct zwlr_output_mode_v1_listener modeListener = {
.size = waylandZwlrModeSizeListener,
.refresh = waylandZwlrModeRefreshListener,
.preferred = waylandZwlrModePreferredListener,
.finished = (void*) stubListener,
};
static void waylandZwlrModeListener(void* data, FF_A_UNUSED struct zwlr_output_head_v1* zwlr_output_head_v1, struct zwlr_output_mode_v1* mode) {
WaylandDisplay* wldata = (WaylandDisplay*) data;
if (!wldata->internal) {
return;
}
WaylandZwlrMode* newMode = FF_LIST_ADD(WaylandZwlrMode, *(FFlist*) wldata->internal);
*newMode = (WaylandZwlrMode) { .pMode = mode };
// Strangely, the listener is called only in this function, but not in `waylandZwlrCurrentModeListener`
wldata->parent->ffwl_proxy_add_listener((struct wl_proxy*) mode, (void (**)(void)) &modeListener, newMode);
}
static void waylandZwlrCurrentModeListener(void* data, FF_A_UNUSED struct zwlr_output_head_v1* zwlr_output_head_v1, struct zwlr_output_mode_v1* mode) {
// waylandZwlrModeListener is always run before this
WaylandDisplay* wldata = (WaylandDisplay*) data;
if (!wldata->internal) {
return;
}
int set = 0;
FF_LIST_FOR_EACH (WaylandZwlrMode, m, *(FFlist*) wldata->internal) {
if (m->pMode == mode) {
wldata->width = m->width;
wldata->height = m->height;
wldata->refreshRate = m->refreshRate;
if (++set == 2) {
break;
}
}
if (m->preferred) {
wldata->preferredWidth = m->width;
wldata->preferredHeight = m->height;
wldata->preferredRefreshRate = m->refreshRate;
if (++set == 2) {
break;
}
}
}
}
static void waylandZwlrPhysicalSizeListener(void* data, FF_A_UNUSED struct zwlr_output_head_v1* zwlr_output_head_v1, int32_t width, int32_t height) {
WaylandDisplay* wldata = (WaylandDisplay*) data;
wldata->physicalWidth = width;
wldata->physicalHeight = height;
}
static void waylandZwlrEnabledListener(void* data, FF_A_UNUSED struct zwlr_output_head_v1* zwlr_output_head_v1, bool enabled) {
WaylandDisplay* wldata = (WaylandDisplay*) data;
if (!enabled) {
wldata->internal = NULL;
}
}
static const struct zwlr_output_head_v1_listener headListener = {
.name = (void*) ffWaylandOutputNameListener,
.description = (void*) ffWaylandOutputDescriptionListener,
.physical_size = waylandZwlrPhysicalSizeListener,
.mode = waylandZwlrModeListener,
.enabled = (void*) waylandZwlrEnabledListener,
.current_mode = waylandZwlrCurrentModeListener,
.position = (void*) stubListener,
.transform = waylandZwlrTransformListener,
.scale = waylandZwlrScaleListener,
.finished = (void*) stubListener,
.make = (void*) stubListener,
.model = (void*) stubListener,
.serial_number = (void*) stubListener,
.adaptive_sync = (void*) stubListener,
};
static void waylandHandleZwlrHead(void* data, FF_A_UNUSED struct zwlr_output_manager_v1* zwlr_output_manager_v1, struct zwlr_output_head_v1* head) {
WaylandData* wldata = data;
FF_LIST_AUTO_DESTROY modes = ffListCreate();
WaylandDisplay display = {
.parent = wldata,
.transform = WL_OUTPUT_TRANSFORM_NORMAL,
.type = FF_DISPLAY_TYPE_UNKNOWN,
.name = ffStrbufCreate(),
.description = ffStrbufCreate(),
.edidName = ffStrbufCreate(),
.internal = &modes,
};
wldata->ffwl_proxy_add_listener((struct wl_proxy*) head, (void (**)(void)) &headListener, &display);
wldata->ffwl_display_roundtrip(wldata->display);
if (display.width <= 0 || display.height <= 0 || !display.internal) {
return;
}
uint32_t rotation = ffWaylandHandleRotation(&display);
FFDisplayResult* item = ffdsAppendDisplay(wldata->result,
(uint32_t) display.width,
(uint32_t) display.height,
display.refreshRate / 1000.0,
(uint32_t) display.dpi,
(uint32_t) display.preferredWidth,
(uint32_t) display.preferredHeight,
display.preferredRefreshRate / 1000.0,
rotation,
display.edidName.length
? &display.edidName
: display.description.length && !ffStrbufContain(&display.description, &display.name)
? &display.description
: &display.name,
display.type,
false,
display.id,
(uint32_t) display.physicalWidth,
(uint32_t) display.physicalHeight,
"wayland-zwlr");
if (item) {
if (display.hdrSupported) {
item->hdrStatus = FF_DISPLAY_HDR_STATUS_SUPPORTED;
} else if (display.hdrInfoAvailable) {
item->hdrStatus = FF_DISPLAY_HDR_STATUS_UNSUPPORTED;
} else {
item->hdrStatus = FF_DISPLAY_HDR_STATUS_UNKNOWN;
}
item->manufactureYear = display.myear;
item->manufactureWeek = display.mweek;
item->serial = display.serial;
}
ffStrbufDestroy(&display.description);
ffStrbufDestroy(&display.name);
ffStrbufDestroy(&display.edidName);
// These must be released manually
FF_LIST_FOR_EACH (WaylandZwlrMode, m, modes) {
wldata->ffwl_proxy_destroy((void*) m->pMode);
}
wldata->ffwl_proxy_destroy((void*) head);
}
static const struct zwlr_output_manager_v1_listener outputListener = {
.head = waylandHandleZwlrHead,
.done = (void*) stubListener,
.finished = (void*) stubListener,
};
const char* ffWaylandHandleZwlrOutput(WaylandData* wldata, struct wl_registry* registry, uint32_t name, uint32_t version) {
uint32_t bindVersion = min(version, ZWLR_OUTPUT_MANAGER_V1_HEAD_SINCE_VERSION);
struct wl_proxy* output = wldata->ffwl_proxy_marshal_constructor_versioned((struct wl_proxy*) registry, WL_REGISTRY_BIND, &zwlr_output_manager_v1_interface, bindVersion, name, zwlr_output_manager_v1_interface.name, bindVersion, NULL);
if (output == NULL) {
return "Failed to bind zwlr_output_manager_v1";
}
if (wldata->ffwl_proxy_add_listener(output, (void (**)(void)) &outputListener, wldata) < 0) {
wldata->ffwl_proxy_destroy(output);
return "Failed to add listener to zwlr_output_manager_v1";
}
if (wldata->ffwl_display_roundtrip(wldata->display) < 0) {
wldata->ffwl_proxy_destroy(output);
return "Failed to roundtrip display";
}
wldata->ffwl_proxy_destroy(output);
return NULL;
}
#endif
+2 -1
View File
@@ -227,7 +227,8 @@ static bool xcbRandrHandleOutput(XcbRandrData* data, xcb_randr_output_t output,
if (item) {
if (edidData && edidLength >= 128) {
item->hdrStatus = ffEdidGetHdrCompatible(edidData, (uint32_t) edidLength) ? FF_DISPLAY_HDR_STATUS_SUPPORTED : FF_DISPLAY_HDR_STATUS_UNSUPPORTED;
ffEdidGetSerialAndManufactureDate(edidData, &item->serial, &item->manufactureYear, &item->manufactureWeek);
ffEdidGetManufactureDate(edidData, &item->manufactureYear, &item->manufactureWeek);
ffEdidGetSerial(edidData, &item->serial);
}
item->bitDepth = bitDepth;
if ((rotation == 90 || rotation == 180) && !randrEmulation) {
+2 -1
View File
@@ -161,7 +161,8 @@ static bool xrandrHandleCrtc(XrandrData* data, XRROutputInfo* output, FFstrbuf*
if (item) {
if (edidLength) {
item->hdrStatus = ffEdidGetHdrCompatible(edidData, edidLength) ? FF_DISPLAY_HDR_STATUS_SUPPORTED : FF_DISPLAY_HDR_STATUS_UNSUPPORTED;
ffEdidGetSerialAndManufactureDate(edidData, &item->serial, &item->manufactureYear, &item->manufactureWeek);
ffEdidGetManufactureDate(edidData, &item->manufactureYear, &item->manufactureWeek);
ffEdidGetSerial(edidData, &item->serial);
}
item->bitDepth = bitDepth;
if ((rotation == 90 || rotation == 180) && !randrEmulation) {
+3
View File
@@ -26,6 +26,9 @@ extern int ADL2_Adapter_DedicatedVRAMUsage_Get(ADL_CONTEXT_HANDLE context, int i
// Function to get the ASICFamilyType from the adapter.
extern int ADL2_Adapter_ASICFamilyType_Get(ADL_CONTEXT_HANDLE context, int iAdapterIndex, int* lpAsicTypes, int* lpValids);
// This function retrieves the chipset information for a specified adapter.
extern int ADL2_Adapter_ChipSetInfo_Get(ADL_CONTEXT_HANDLE context, int iAdapterIndex, ADLChipSetInfo* lpChipSetInfo);
// Function to retrieve current power management capabilities.
extern int ADL2_Overdrive_Caps(ADL_CONTEXT_HANDLE context, int iAdapterIndex, int* iSupported, int* iEnabled, int* iVersion);
+5 -1
View File
@@ -7,7 +7,11 @@
#ifndef _ASAHI_DRM_H_
#define _ASAHI_DRM_H_
#include <drm.h>
#if __has_include(<drm.h>)
#include <drm.h>
#else
#include <drm/drm.h>
#endif
#if defined(__cplusplus)
extern "C" {
+13
View File
@@ -152,6 +152,18 @@ typedef struct _D3DKMT_QUERY_DEVICE_IDS {
D3DKMT_DEVICE_IDS DeviceIds; // out:
} D3DKMT_QUERY_DEVICE_IDS;
typedef enum _D3DKMT_PNP_KEY_TYPE {
D3DKMT_PNP_KEY_HARDWARE,
D3DKMT_PNP_KEY_SOFTWARE
} D3DKMT_PNP_KEY_TYPE;
typedef struct _D3DKMT_QUERY_PHYSICAL_ADAPTER_PNP_KEY {
UINT PhysicalAdapterIndex;
D3DKMT_PNP_KEY_TYPE PnPKeyType;
WCHAR* pDest;
UINT* pCchDest;
} D3DKMT_QUERY_PHYSICAL_ADAPTER_PNP_KEY;
typedef enum _QAI_DRIVERVERSION {
KMT_DRIVERVERSION_WDDM_1_0 = 1000, // Windows Vista
KMT_DRIVERVERSION_WDDM_1_1_PRERELEASE = 1102, // Windows Vista with prereleased Win7 features
@@ -187,6 +199,7 @@ typedef enum _KMTQUERYADAPTERINFOTYPE {
KMTQAITYPE_UMD_DRIVER_VERSION = 18,
KMTQAITYPE_NODEMETADATA = 25, // WDDM 2.0, Windows 10
KMTQAITYPE_PHYSICALADAPTERDEVICEIDS = 31,
KMTQAITYPE_PHYSICALADAPTERPNPKEY = 41, // WDDM 2.2, Windows 10 (1703)
KMTQAITYPE_QUERY_ADAPTER_UNIQUE_GUID = 60, // WDDM 2.4, Windows 10 (1803)
KMTQAITYPE_NODEPERFDATA = 61,
KMTQAITYPE_ADAPTERPERFDATA = 62,
+159 -12
View File
@@ -77,6 +77,25 @@ const char* ffGPUGetVendorString(unsigned vendorId) {
}
}
static bool normalizeVendorName(FFGPUResult* gpu) {
if (ffStrbufContainS(&gpu->name, "Apple")) {
ffStrbufSetStatic(&gpu->vendor, FF_GPU_VENDOR_NAME_APPLE);
gpu->type = FF_GPU_TYPE_INTEGRATED;
} else if (ffStrbufContainS(&gpu->name, "Intel")) {
ffStrbufSetStatic(&gpu->vendor, FF_GPU_VENDOR_NAME_INTEL);
} else if (ffStrbufContainS(&gpu->name, "AMD") || ffStrbufContainS(&gpu->name, "ATI")) {
ffStrbufSetStatic(&gpu->vendor, FF_GPU_VENDOR_NAME_AMD);
} else if (ffStrbufContainS(&gpu->name, "NVIDIA")) {
ffStrbufSetStatic(&gpu->vendor, FF_GPU_VENDOR_NAME_NVIDIA);
} else if (ffStrbufContainS(&gpu->name, "MTT")) {
ffStrbufSetStatic(&gpu->vendor, FF_GPU_VENDOR_NAME_MTHREADS);
} else {
return false;
}
return true;
}
const char* detectByOpenGL(FFlist* gpus) {
FF_DEBUG("Starting OpenGL GPU detection fallback");
@@ -107,24 +126,14 @@ const char* detectByOpenGL(FFlist* gpus) {
gpu->coreUsage = FF_GPU_CORE_USAGE_UNSET;
gpu->dedicated = gpu->shared = (FFGPUMemory) { 0, 0 };
gpu->deviceId = 0;
gpu->pcieSpeed = FF_GPU_PCIE_SPEED_UNSET;
FF_DEBUG("OpenGL reported renderer='%s', vendor='%s', version='%s'",
gpu->name.chars,
gpu->vendor.chars,
result.version.chars);
if (ffStrbufContainS(&gpu->name, "Apple")) {
ffStrbufSetStatic(&gpu->vendor, FF_GPU_VENDOR_NAME_APPLE);
gpu->type = FF_GPU_TYPE_INTEGRATED;
} else if (ffStrbufContainS(&gpu->name, "Intel")) {
ffStrbufSetStatic(&gpu->vendor, FF_GPU_VENDOR_NAME_INTEL);
} else if (ffStrbufContainS(&gpu->name, "AMD") || ffStrbufContainS(&gpu->name, "ATI")) {
ffStrbufSetStatic(&gpu->vendor, FF_GPU_VENDOR_NAME_AMD);
} else if (ffStrbufContainS(&gpu->name, "NVIDIA")) {
ffStrbufSetStatic(&gpu->vendor, FF_GPU_VENDOR_NAME_NVIDIA);
} else if (ffStrbufContainS(&gpu->name, "MTT")) {
ffStrbufSetStatic(&gpu->vendor, FF_GPU_VENDOR_NAME_MTHREADS);
}
normalizeVendorName(gpu);
FF_DEBUG("OpenGL fallback produced GPU: name='%s', vendor='%s', type=%u",
gpu->name.chars,
@@ -140,6 +149,98 @@ const char* detectByOpenGL(FFlist* gpus) {
return error;
}
#if defined(FF_HAVE_EGL) || __has_include(<EGL/egl.h>)
#include <EGL/egl.h>
#include <EGL/eglext.h>
#if EGL_EXT_device_base && EGL_EXT_device_persistent_id && EGL_EXT_device_query_name
#define FF_HAVE_EGL_EXT 1
#include <inttypes.h>
#include "common/library.h"
#include "common/strutil.h"
#include "common/io.h"
const char* detectByEglext(FFlist* result) {
FF_LIBRARY_LOAD_MESSAGE(egl, "libEGL" FF_LIBRARY_EXTENSION, 1);
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(egl, eglGetProcAddress);
PFNEGLQUERYDEVICESEXTPROC ffeglQueryDevicesEXT = (PFNEGLQUERYDEVICESEXTPROC) ffeglGetProcAddress("eglQueryDevicesEXT");
if (!ffeglQueryDevicesEXT) {
return "eglQueryDevicesEXT is unavailable";
}
PFNEGLQUERYDEVICESTRINGEXTPROC ffeglQueryDeviceStringEXT = (PFNEGLQUERYDEVICESTRINGEXTPROC) ffeglGetProcAddress("eglQueryDeviceStringEXT");
if (!ffeglQueryDeviceStringEXT) {
return "eglQueryDeviceStringEXT is unavailable";
}
PFNEGLQUERYDEVICEBINARYEXTPROC ffeglQueryDeviceBinaryEXT = (PFNEGLQUERYDEVICEBINARYEXTPROC) ffeglGetProcAddress("eglQueryDeviceBinaryEXT");
if (!ffeglQueryDeviceBinaryEXT) {
return "eglQueryDeviceBinaryEXT is unavailable";
}
FF_DEBUG("Loaded EGL library and required symbols");
FF_SUPPRESS_IO();
EGLDeviceEXT devices[16];
EGLint numDevices;
if (ffeglQueryDevicesEXT(ARRAY_SIZE(devices), devices, &numDevices) == EGL_TRUE) {
FF_DEBUG("eglQueryDevicesEXT() returned %d device(s)", numDevices);
for (EGLint i = 0; i < numDevices; i++) {
const EGLDeviceEXT device = devices[i];
if (device == (EGLDeviceEXT) EGL_NO_DEVICE_EXT || device == (EGLDeviceEXT) EGL_BAD_DEVICE_EXT) {
FF_DEBUG("eglQueryDevicesEXT() returned invalid device at index %d", i);
continue;
}
const char* exts = (const char*) ffeglQueryDeviceStringEXT(device, EGL_EXTENSIONS);
FF_DEBUG("eglQueryDeviceStringEXT() returned extensions for device %d: %s", i, exts);
if (exts && ffStrContains(exts, "EGL_MESA_device_software")) {
FF_DEBUG("eglQueryDeviceStringEXT() returned software device at index %d, skipping", i);
continue;
}
const char* name = ffeglQueryDeviceStringEXT(device, EGL_RENDERER_EXT);
if (!name) {
FF_DEBUG("eglQueryDeviceStringEXT() returned NULL name for device %d, skipping", i);
continue;
}
FFGPUResult* gpu = FF_LIST_ADD(FFGPUResult, *result);
ffStrbufInitS(&gpu->name, name);
ffStrbufInit(&gpu->vendor);
ffStrbufInitS(&gpu->driver, ffeglQueryDeviceStringEXT(device, EGL_DRIVER_NAME_EXT));
ffStrbufInitF(&gpu->platformApi, "egl-ext");
ffStrbufInit(&gpu->memoryType);
gpu->index = FF_GPU_INDEX_UNSET;
gpu->temperature = FF_GPU_TEMP_UNSET;
gpu->coreCount = FF_GPU_CORE_COUNT_UNSET;
gpu->coreUsage = FF_GPU_CORE_USAGE_UNSET;
gpu->type = FF_GPU_TYPE_UNKNOWN;
gpu->dedicated.total = gpu->dedicated.used = gpu->shared.total = gpu->shared.used = FF_GPU_VMEM_SIZE_UNSET;
gpu->deviceId = 0;
gpu->frequency = FF_GPU_FREQUENCY_UNSET;
gpu->pcieSpeed = FF_GPU_PCIE_SPEED_UNSET;
ffeglQueryDeviceBinaryEXT(device, EGL_DEVICE_UUID_EXT, sizeof(gpu->deviceId), &gpu->deviceId, NULL);
if (!normalizeVendorName(gpu)) {
ffStrbufSetS(&gpu->vendor, ffeglQueryDeviceStringEXT(device, EGL_VENDOR));
}
FF_DEBUG("Detected GPU %d: vendor='%s', name='%s', driver='%s', id='%16" PRIX64 "'", i, gpu->vendor.chars, gpu->name.chars, gpu->driver.chars, gpu->deviceId);
}
} else {
FF_DEBUG("eglQueryDevicesEXT() returned EGL_FALSE");
}
return NULL;
}
#endif
#endif
const char* ffDetectGPU(const FFGPUOptions* options, FFlist* result) {
FF_DEBUG("Starting GPU detection with method=%d", (int) options->detectionMethod);
@@ -192,6 +293,22 @@ const char* ffDetectGPU(const FFGPUOptions* options, FFlist* result) {
opencl->error ?: "none",
opencl->gpus.length);
}
if (options->detectionMethod <= FF_GPU_DETECTION_METHOD_EGL_EXT) {
#if FF_HAVE_EGL_EXT
FF_DEBUG("Trying EGL_EXT GPU detection fallback");
const char* error = detectByEglext(result);
if (!error && result->length > 0) {
FF_DEBUG("EGL_EXT GPU detection succeeded with %u GPU(s)", result->length);
return NULL;
}
FF_DEBUG("EGL_EXT GPU detection did not produce results (error=%s, gpuCount=%u)",
error ?: "none",
result->length);
#else
FF_DEBUG("EGL_EXT GPU detection is unavailable");
#endif
}
if (options->detectionMethod <= FF_GPU_DETECTION_METHOD_OPENGL) {
FF_DEBUG("Trying OpenGL GPU detection fallback");
const char* error = detectByOpenGL(result);
@@ -206,3 +323,33 @@ const char* ffDetectGPU(const FFGPUOptions* options, FFlist* result) {
FF_DEBUG("GPU detection failed in all enabled backends");
return "GPU detection failed";
}
bool ffGPUFillVendorByDeviceName(FFGPUResult* gpu) {
if (gpu->type != FF_GPU_TYPE_UNKNOWN) {
return true;
}
FF_DEBUG("Using fallback GPU type detection");
if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_NVIDIA) {
if (ffStrbufStartsWithIgnCaseS(&gpu->name, "GeForce") ||
ffStrbufStartsWithIgnCaseS(&gpu->name, "Quadro") ||
ffStrbufStartsWithIgnCaseS(&gpu->name, "Tesla")) {
gpu->type = FF_GPU_TYPE_DISCRETE;
}
} else if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_MTHREADS) {
if (ffStrbufStartsWithIgnCaseS(&gpu->name, "MTT ")) { gpu->type = FF_GPU_TYPE_DISCRETE; }
} else if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_INTEL) {
// 0000:00:02.0 is reserved for Intel integrated graphics
gpu->type = gpu->deviceId == ffGPUPciAddr2Id(0, 0, 2, 0) ? FF_GPU_TYPE_INTEGRATED : FF_GPU_TYPE_DISCRETE;
} else if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_VMWARE || gpu->vendor.chars == FF_GPU_VENDOR_NAME_PARALLELS) {
// Virtualized GPUs
gpu->type = FF_GPU_TYPE_INTEGRATED;
}
if (gpu->type != FF_GPU_TYPE_UNKNOWN) {
FF_DEBUG("Determined GPU type based on vendor (%s) and name: %u", gpu->vendor.chars, gpu->type);
return true;
}
return false;
}
+20 -2
View File
@@ -7,6 +7,7 @@
#define FF_GPU_CORE_COUNT_UNSET -1
#define FF_GPU_VMEM_SIZE_UNSET ((uint64_t) -1)
#define FF_GPU_FREQUENCY_UNSET 0
#define FF_GPU_PCIE_SPEED_UNSET 0
#define FF_GPU_CORE_USAGE_UNSET (-DBL_MAX)
#define FF_GPU_INDEX_UNSET ((uint32_t) -1)
@@ -34,6 +35,11 @@ typedef struct FFGPUMemory {
uint64_t used;
} FFGPUMemory;
typedef struct FFGPUPcieSpeed {
uint16_t gen;
uint16_t lanes;
} FFGPUPcieSpeed;
typedef struct FFGPUResult {
uint32_t index;
FFGPUType type;
@@ -46,6 +52,13 @@ typedef struct FFGPUResult {
double coreUsage;
int32_t coreCount;
uint32_t frequency; // Maximum time clock frequency in MHz
union {
struct {
FFGPUPcieSpeed psMax;
FFGPUPcieSpeed psCurr;
};
uint64_t pcieSpeed;
};
FFGPUMemory dedicated;
FFGPUMemory shared;
uint64_t deviceId;
@@ -67,14 +80,17 @@ typedef struct FFGpuDriverPciBusId {
void ffGPUFillVendorAndName(uint8_t subclass, uint16_t vendor, uint16_t device, FFGPUResult* gpu);
void ffGPUQueryAmdGpuName(uint16_t deviceId, uint8_t revisionId, FFGPUResult* gpu);
#if FF_HAVE_DRM
#if FF_HAVE_DRM || __has_include(<drm/drm.h>)
const char* ffDrmDetectRadeon(const FFGPUOptions* options, FFGPUResult* gpu, const char* renderPath);
const char* ffDrmDetectAmdgpu(const FFGPUOptions* options, FFGPUResult* gpu, const char* renderPath);
const char* ffDrmDetectI915(FFGPUResult* gpu, int fd);
const char* ffDrmDetectXe(FFGPUResult* gpu, int fd);
const char* ffDrmDetectAsahi(FFGPUResult* gpu, int fd);
const char* ffDrmDetectNouveau(FFGPUResult* gpu, int fd);
#endif // FF_HAVE_DRM
#if __FreeBSD__ || __OpenBSD__ // DRM is not available on NetBSD
const char* ffGPUDetectByDrmBSD(const FFGPUOptions* options, FFlist* gpus);
#endif
#endif // FF_HAVE_DRM || __has_include(<drm/drm.h>)
const char* ffGPUDetectDriverSpecific(const FFGPUOptions* options, FFGPUResult* gpu, FFGpuDriverPciBusId pciBusId);
#endif // defined(XXX)
@@ -87,3 +103,5 @@ static inline uint64_t ffGPUGeneral2Id(uint64_t originalId) {
// Note: originalId may already have the MSB set
return (1ULL << 63) | originalId;
}
bool ffGPUFillVendorByDeviceName(FFGPUResult* gpu);
+36
View File
@@ -52,6 +52,7 @@ struct FFAdlData {
FF_LIBRARY_SYMBOL(ADL2_Adapter_MemoryInfo2_Get)
FF_LIBRARY_SYMBOL(ADL2_Adapter_DedicatedVRAMUsage_Get)
FF_LIBRARY_SYMBOL(ADL2_Adapter_ASICFamilyType_Get)
FF_LIBRARY_SYMBOL(ADL2_Adapter_ChipSetInfo_Get)
FF_LIBRARY_SYMBOL(ADL2_Overdrive_Caps)
FF_LIBRARY_SYMBOL(ADL2_OverdriveN_CapabilitiesX2_Get)
FF_LIBRARY_SYMBOL(ADL2_OverdriveN_SystemClocksX2_Get)
@@ -89,6 +90,7 @@ const char* ffDetectAmdGpuInfo(const FFGpuDriverCondition* cond, FFGpuDriverResu
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(atiadl, adlData, ADL2_Adapter_MemoryInfo2_Get)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(atiadl, adlData, ADL2_Adapter_DedicatedVRAMUsage_Get)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(atiadl, adlData, ADL2_Adapter_ASICFamilyType_Get)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(atiadl, adlData, ADL2_Adapter_ChipSetInfo_Get)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(atiadl, adlData, ADL2_Overdrive_Caps)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(atiadl, adlData, ADL2_OverdriveN_CapabilitiesX2_Get)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(atiadl, adlData, ADL2_OverdriveN_SystemClocksX2_Get)
@@ -233,6 +235,40 @@ const char* ffDetectAmdGpuInfo(const FFGpuDriverCondition* cond, FFGpuDriverResu
FF_DEBUG("Setting adapter name: %s; UDID: %s, Present: %d, Exist: %d", device->strAdapterName, device->strUDID, device->iPresent, device->iExist);
}
if (result.psMax || result.psCurr) {
ADLChipSetInfo chipSetInfo;
int status = adlData.ffADL2_Adapter_ChipSetInfo_Get(adlData.apiHandle, device->iAdapterIndex, &chipSetInfo);
FF_DEBUG("ADL2_Adapter_ChipSetInfo_Get returned %s (%d)", ffAdlStatusToString(status), status);
if (status == ADL_OK) {
FF_DEBUG("Chipset info - iBusSpeedType: %d, iMaxPCIELaneWidth: %d", chipSetInfo.iBusSpeedType, chipSetInfo.iMaxPCIELaneWidth);
if (result.psMax) {
if (chipSetInfo.iBusSpeedType >= 2) {
result.psMax->gen = (uint16_t) (chipSetInfo.iBusSpeedType - 2);
FF_DEBUG("Got PCIe Max Gen: %u", result.psMax->gen);
}
if (chipSetInfo.iMaxPCIELaneWidth > 0) {
result.psMax->lanes = (uint16_t) chipSetInfo.iMaxPCIELaneWidth;
FF_DEBUG("Got PCIe Max Lanes: %u", result.psMax->lanes);
}
}
FF_DEBUG("Chipset info - iBusType: %d, iCurrentPCIELaneWidth: %d", chipSetInfo.iBusType, chipSetInfo.iCurrentPCIELaneWidth);
if (result.psCurr) {
if (chipSetInfo.iBusType >= 2) {
result.psCurr->gen = (uint16_t) (chipSetInfo.iBusType - 2);
FF_DEBUG("Got PCIe Current Gen: %u", result.psCurr->gen);
}
if (chipSetInfo.iCurrentPCIELaneWidth > 0) {
result.psCurr->lanes = (uint16_t) chipSetInfo.iCurrentPCIELaneWidth;
FF_DEBUG("Got PCIe Current Lanes: %u", result.psCurr->lanes);
}
}
} else {
FF_DEBUG("Failed to get chipset information");
}
}
int odVersion = 0;
{
+1
View File
@@ -118,6 +118,7 @@ const char* ffDetectGPUImpl(const FFGPUOptions* options, FFlist* gpus) {
gpu->dedicated.total = gpu->dedicated.used = gpu->shared.total = gpu->shared.used = FF_GPU_VMEM_SIZE_UNSET;
gpu->type = FF_GPU_TYPE_UNKNOWN;
gpu->frequency = FF_GPU_FREQUENCY_UNSET;
gpu->pcieSpeed = FF_GPU_PCIE_SPEED_UNSET;
IORegistryEntryGetRegistryEntryID(registryEntry, &gpu->deviceId);
ffStrbufInitStatic(&gpu->platformApi, "IOKit");
+4 -137
View File
@@ -1,7 +1,7 @@
#include "gpu.h"
#include "gpu_driver_specific.h"
#include "common/io.h"
#include "common/mallocHelper.h"
#include <sys/pciio.h>
#include <fcntl.h>
@@ -11,140 +11,6 @@
#include <bus/pci/pcireg.h> // DragonFly
#endif
static void fillGPUTypeGeneric(FFGPUResult* gpu) {
if (gpu->type == FF_GPU_TYPE_UNKNOWN) {
if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_NVIDIA) {
if (ffStrbufStartsWithIgnCaseS(&gpu->name, "GeForce") ||
ffStrbufStartsWithIgnCaseS(&gpu->name, "Quadro") ||
ffStrbufStartsWithIgnCaseS(&gpu->name, "Tesla")) {
gpu->type = FF_GPU_TYPE_DISCRETE;
}
} else if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_MTHREADS) {
if (ffStrbufStartsWithIgnCaseS(&gpu->name, "MTT ")) {
gpu->type = FF_GPU_TYPE_DISCRETE;
}
} else if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_INTEL) {
// 0000:00:02.0 is reserved for Intel integrated graphics
gpu->type = gpu->deviceId == ffGPUPciAddr2Id(0, 0, 2, 0) ? FF_GPU_TYPE_INTEGRATED : FF_GPU_TYPE_DISCRETE;
}
}
}
#if FF_HAVE_DRM
#include "common/library.h"
#include "common/strutil.h"
#include <xf86drm.h>
static const char* detectByDrm(const FFGPUOptions* options, FFlist* gpus) {
FF_LIBRARY_LOAD_MESSAGE(libdrm, "libdrm" FF_LIBRARY_EXTENSION, 2)
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, drmGetDevices)
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, drmFreeDevices)
drmDevicePtr devices[64];
int nDevices = ffdrmGetDevices(devices, ARRAY_SIZE(devices));
if (nDevices < 0) {
return "drmGetDevices() failed";
}
for (int iDev = 0; iDev < nDevices; ++iDev) {
drmDevice* dev = devices[iDev];
if (!(dev->available_nodes & (1 << DRM_NODE_PRIMARY))) {
continue;
}
const char* path = dev->nodes[DRM_NODE_PRIMARY];
FFGPUResult* gpu = FF_LIST_ADD(FFGPUResult, *gpus);
ffStrbufInit(&gpu->vendor);
ffStrbufInit(&gpu->name);
ffStrbufInit(&gpu->driver);
ffStrbufInitS(&gpu->platformApi, path);
ffStrbufInit(&gpu->memoryType);
gpu->index = FF_GPU_INDEX_UNSET;
gpu->temperature = FF_GPU_TEMP_UNSET;
gpu->coreCount = FF_GPU_CORE_COUNT_UNSET;
gpu->coreUsage = FF_GPU_CORE_USAGE_UNSET;
gpu->type = FF_GPU_TYPE_UNKNOWN;
gpu->dedicated.total = gpu->dedicated.used = gpu->shared.total = gpu->shared.used = FF_GPU_VMEM_SIZE_UNSET;
gpu->deviceId = 0;
gpu->frequency = FF_GPU_FREQUENCY_UNSET;
switch (dev->bustype) {
case DRM_BUS_PCI:
ffStrbufInitStatic(&gpu->vendor, ffGPUGetVendorString(dev->deviceinfo.pci->vendor_id));
gpu->deviceId = ffGPUPciAddr2Id(dev->businfo.pci->domain, dev->businfo.pci->bus, dev->businfo.pci->dev, dev->businfo.pci->func);
break;
case DRM_BUS_HOST1X:
ffStrbufSetS(&gpu->name, dev->deviceinfo.host1x->compatible[0]);
gpu->type = FF_GPU_TYPE_INTEGRATED;
break;
case DRM_BUS_PLATFORM:
ffStrbufSetS(&gpu->name, dev->deviceinfo.platform->compatible[0]);
gpu->type = FF_GPU_TYPE_INTEGRATED;
break;
case DRM_BUS_USB:
ffStrbufSetF(&gpu->name, "USB Device (%u-%u)", dev->deviceinfo.usb->vendor, dev->deviceinfo.usb->product);
gpu->type = FF_GPU_TYPE_DISCRETE;
break;
}
FF_AUTO_CLOSE_FD int fd = open(path, O_RDONLY | O_CLOEXEC);
if (fd < 0) {
continue;
}
char driverName[64];
driverName[0] = '\0';
struct drm_version ver = {
.name = driverName,
.name_len = ARRAY_SIZE(driverName),
};
if (ioctl(fd, DRM_IOCTL_VERSION, &ver) == 0) {
driverName[ver.name_len] = '\0';
ffStrbufSetF(&gpu->driver, "%s %d.%d.%d", ver.name, ver.version_major, ver.version_minor, ver.version_patchlevel);
}
if (ffStrStartsWith(driverName, "i915")) {
ffDrmDetectI915(gpu, fd);
} else if (ffStrStartsWith(driverName, "amdgpu")) {
ffDrmDetectAmdgpu(options, gpu, dev->nodes[DRM_NODE_RENDER]);
} else if (ffStrStartsWith(driverName, "radeon")) {
ffDrmDetectRadeon(options, gpu, dev->nodes[DRM_NODE_RENDER]);
} else if (ffStrStartsWith(driverName, "xe")) {
ffDrmDetectXe(gpu, fd);
} else if (ffStrStartsWith(driverName, "asahi")) {
ffDrmDetectAsahi(gpu, fd);
} else if (ffStrStartsWith(driverName, "nouveau")) {
ffDrmDetectNouveau(gpu, fd);
} else if (dev->bustype == DRM_BUS_PCI) {
ffGPUDetectDriverSpecific(options, gpu, (FFGpuDriverPciBusId) {
.domain = (uint32_t) dev->businfo.pci->domain,
.bus = dev->businfo.pci->bus,
.device = dev->businfo.pci->dev,
.func = dev->businfo.pci->func,
});
}
if (gpu->name.length == 0) {
if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_AMD) {
ffGPUQueryAmdGpuName(dev->deviceinfo.pci->device_id, dev->deviceinfo.pci->revision_id, gpu);
}
if (gpu->name.length == 0) {
ffGPUFillVendorAndName(0, dev->deviceinfo.pci->vendor_id, dev->deviceinfo.pci->device_id, gpu);
}
}
fillGPUTypeGeneric(gpu);
}
ffdrmFreeDevices(devices, nDevices);
return NULL;
}
#endif
static const char* detectByPci(const FFGPUOptions* options, FFlist* gpus) {
FF_AUTO_CLOSE_FD int fd = open("/dev/pci", O_RDONLY | O_CLOEXEC);
if (fd < 0) {
@@ -193,6 +59,7 @@ static const char* detectByPci(const FFGPUOptions* options, FFlist* gpus) {
gpu->dedicated.total = gpu->dedicated.used = gpu->shared.total = gpu->shared.used = FF_GPU_VMEM_SIZE_UNSET;
gpu->deviceId = ffGPUPciAddr2Id(pc->pc_sel.pc_domain, pc->pc_sel.pc_bus, pc->pc_sel.pc_dev, pc->pc_sel.pc_func);
gpu->frequency = FF_GPU_FREQUENCY_UNSET;
gpu->pcieSpeed = FF_GPU_PCIE_SPEED_UNSET;
ffGPUDetectDriverSpecific(options, gpu, (FFGpuDriverPciBusId) {
.domain = (uint32_t) pc->pc_sel.pc_domain,
@@ -210,7 +77,7 @@ static const char* detectByPci(const FFGPUOptions* options, FFlist* gpus) {
}
}
fillGPUTypeGeneric(gpu);
ffGPUFillVendorByDeviceName(gpu);
}
return NULL;
@@ -219,7 +86,7 @@ static const char* detectByPci(const FFGPUOptions* options, FFlist* gpus) {
const char* ffDetectGPUImpl(const FFGPUOptions* options, FFlist* gpus) {
#if FF_HAVE_DRM
if (options->detectionMethod == FF_GPU_DETECTION_METHOD_AUTO) {
detectByDrm(options, gpus);
ffGPUDetectByDrmBSD(options, gpus);
if (gpus->length > 0) {
return NULL;
}
+204
View File
@@ -0,0 +1,204 @@
#if FF_HAVE_DRM
#include "gpu.h"
#include "common/strutil.h"
#include "common/io.h"
#include <drm.h>
#include <sys/ioctl.h>
#if __FreeBSD__
#include <sys/sysctl.h>
#include <inttypes.h>
#include <sys/pciio.h>
#include <fcntl.h>
#if __has_include(<dev/pci/pcireg.h>)
#include <dev/pci/pcireg.h> // FreeBSD
#else
#include <bus/pci/pcireg.h> // DragonFly
#endif
#endif
// https://github.com/freebsd/drm-kmod/blob/8fea1f06b3ac3fa24217e24ba7b2133abad705a9/include/uapi/drm/drm.h#L1095
struct drm_pciinfo {
uint16_t domain;
uint8_t bus;
uint8_t dev;
uint8_t func;
uint16_t vendor_id;
uint16_t device_id;
uint16_t subvendor_id;
uint16_t subdevice_id;
uint8_t revision_id;
};
#define DRM_IOCTL_GET_PCIINFO DRM_IOR(0x15, struct drm_pciinfo)
static const char* drmGetPciinfo(int drmfd, const char* drmId, struct drm_pciinfo* result) {
#if !__FreeBSD__
FF_UNUSED(drmId);
if (ioctl(drmfd, DRM_IOCTL_GET_PCIINFO, result) < 0) {
return "ioctl(DRM_IOCTL_GET_PCIINFO) failed";
}
#else
FF_UNUSED(drmfd);
char requestBuf[64];
snprintf(requestBuf, ARRAY_SIZE(requestBuf), "hw.dri.%s.busid", drmId);
char pciidBuf[64];
size_t pciidLen = ARRAY_SIZE(pciidBuf);
if (sysctlbyname(requestBuf, pciidBuf, &pciidLen, NULL, 0) < 0) {
return "sysctlbyname(hw.dri.%s.busid) failed";
}
// hw.dri.0.busid: pci:0000:01:00.0
struct pci_match_conf match = {
.pc_class = PCIC_DISPLAY,
.flags = PCI_GETCONF_MATCH_CLASS | PCI_GETCONF_MATCH_DOMAIN | PCI_GETCONF_MATCH_BUS | PCI_GETCONF_MATCH_DEV | PCI_GETCONF_MATCH_FUNC,
};
if (sscanf(pciidBuf, "pci:%" SCNx32 ":%" SCNx8 ":%" SCNx8 ".%" SCNx8, &match.pc_sel.pc_domain, &match.pc_sel.pc_bus, &match.pc_sel.pc_dev, &match.pc_sel.pc_func) != 4) {
return "Invalid PCI busid found";
}
FF_AUTO_CLOSE_FD int pcifd = open("/dev/pci", O_RDONLY | O_CLOEXEC);
if (pcifd < 0) {
return "open(\"/dev/pci\", O_RDONLY | O_CLOEXEC, 0) failed";
}
struct pci_conf conf;
struct pci_conf_io pcio = {
.pat_buf_len = sizeof(match),
.num_patterns = 1,
.patterns = &match,
.match_buf_len = sizeof(conf),
.matches = &conf,
};
if (ioctl(pcifd, PCIOCGETCONF, &pcio) < 0) {
perror("ioctl");
return "ioctl(pcifd, PCIOCGETCONF, &pc) failed";
}
if (pcio.status == PCI_GETCONF_ERROR) {
return "ioctl(pcifd, PCIOCGETCONF, &pc) returned error";
}
if (pcio.num_matches != 1) {
return "ioctl(pcifd, PCIOCGETCONF, &pc) returned no results";
}
*result = (struct drm_pciinfo){
.domain = (uint16_t) conf.pc_sel.pc_domain,
.bus = conf.pc_sel.pc_bus,
.dev = conf.pc_sel.pc_dev,
.func = conf.pc_sel.pc_func,
.vendor_id = conf.pc_vendor,
.device_id = conf.pc_device,
.subvendor_id = conf.pc_subvendor,
.subdevice_id = conf.pc_subdevice,
.revision_id = conf.pc_revid,
};
// This sysctl can also be useful
// dev.drm.0.PCI_ID: 10de:2782
#endif
return NULL;
}
const char* ffGPUDetectByDrmBSD(const FFGPUOptions* options, FFlist* gpus) {
FF_AUTO_CLOSE_DIR DIR* dirp = opendir("/dev/dri/");
if (dirp == NULL) {
return "opendir(/dev/dri/) failed";
}
int drifd = dirfd(dirp);
struct dirent* entry;
while ((entry = readdir(dirp)) != NULL) {
if (entry->d_name[0] == '.' || !ffStrStartsWith(entry->d_name, "card")) {
continue;
}
FF_AUTO_CLOSE_FD int fd = openat(drifd, entry->d_name, O_RDWR | O_CLOEXEC);
if (fd < 0) {
continue;
}
// Currently, DRM_BUS_PCI is the only bus type supported by drm-kmod on BSD (hard-coded in libdrm source tree)
struct drm_pciinfo pciInfo;
if (drmGetPciinfo(fd, entry->d_name + strlen("card"), &pciInfo) != NULL) {
continue;
}
FFGPUResult* gpu = FF_LIST_ADD(FFGPUResult, *gpus);
ffStrbufInitStatic(&gpu->vendor, ffGPUGetVendorString(pciInfo.vendor_id));
ffStrbufInit(&gpu->name);
ffStrbufInit(&gpu->driver);
ffStrbufInitF(&gpu->platformApi, "/dev/dri/%s", entry->d_name);
ffStrbufInit(&gpu->memoryType);
gpu->index = FF_GPU_INDEX_UNSET;
gpu->temperature = FF_GPU_TEMP_UNSET;
gpu->coreCount = FF_GPU_CORE_COUNT_UNSET;
gpu->coreUsage = FF_GPU_CORE_USAGE_UNSET;
gpu->type = FF_GPU_TYPE_UNKNOWN;
gpu->dedicated.total = gpu->dedicated.used = gpu->shared.total = gpu->shared.used = FF_GPU_VMEM_SIZE_UNSET;
gpu->deviceId = ffGPUPciAddr2Id(pciInfo.domain, pciInfo.bus, pciInfo.dev, pciInfo.func);
gpu->frequency = FF_GPU_FREQUENCY_UNSET;
gpu->pcieSpeed = FF_GPU_PCIE_SPEED_UNSET;
char driverName[64];
driverName[0] = '\0';
struct drm_version ver = {
.name = driverName,
.name_len = ARRAY_SIZE(driverName) - 1,
};
if (ioctl(fd, DRM_IOCTL_VERSION, &ver) == 0) {
driverName[ver.name_len] = '\0';
ffStrbufSetF(&gpu->driver, "%s %d.%d.%d", ver.name, ver.version_major, ver.version_minor, ver.version_patchlevel);
}
if (ffStrStartsWith(driverName, "i915")) {
ffDrmDetectI915(gpu, fd);
} else if (ffStrStartsWith(driverName, "amdgpu")) {
uint32_t primaryNodeId = (uint32_t) strtoul(entry->d_name + strlen("card"), NULL, 10);
FF_STRBUF_AUTO_DESTROY renderNode = ffStrbufCreateF("/dev/dri/renderD%d", primaryNodeId + 128);
ffDrmDetectAmdgpu(options, gpu, renderNode.chars);
} else if (ffStrStartsWith(driverName, "radeon")) {
uint32_t primaryNodeId = (uint32_t) strtoul(entry->d_name + strlen("card"), NULL, 10);
FF_STRBUF_AUTO_DESTROY renderNode = ffStrbufCreateF("/dev/dri/renderD%d", primaryNodeId + 128);
ffDrmDetectRadeon(options, gpu, renderNode.chars);
} else if (ffStrStartsWith(driverName, "xe")) {
ffDrmDetectXe(gpu, fd);
} else if (ffStrStartsWith(driverName, "asahi")) {
ffDrmDetectAsahi(gpu, fd);
} else if (ffStrStartsWith(driverName, "nouveau")) {
ffDrmDetectNouveau(gpu, fd);
} else {
ffGPUDetectDriverSpecific(options, gpu, (FFGpuDriverPciBusId){
.domain = pciInfo.domain,
.bus = pciInfo.bus,
.device = pciInfo.dev,
.func = pciInfo.func,
});
}
if (gpu->name.length == 0) {
if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_AMD) {
ffGPUQueryAmdGpuName(pciInfo.device_id, pciInfo.revision_id, gpu);
}
if (gpu->name.length == 0) {
ffGPUFillVendorAndName(0, pciInfo.vendor_id, pciInfo.device_id, gpu);
}
}
ffGPUFillVendorByDeviceName(gpu);
}
return NULL;
}
#else
const char* ffGPUDetectByDrmBSD(const FFGPUOptions* options, FFlist* gpus) {
FF_UNUSED(options, gpus);
return "Fastfetch was built without libdrm support";
}
#endif // __FreeBSD__ || __OpenBSD__
+2
View File
@@ -36,6 +36,8 @@ typedef struct FFGpuDriverResult {
FFGPUType* type;
uint32_t* frequency;
FFstrbuf* name;
FFGPUPcieSpeed* psMax;
FFGPUPcieSpeed* psCurr;
} FFGpuDriverResult;
const char* ffDetectNvidiaGpuInfo(const FFGpuDriverCondition* cond, FFGpuDriverResult result, const char* soName);
+70 -55
View File
@@ -1,19 +1,26 @@
#include "gpu.h"
#if FF_HAVE_DRM
#include <drm.h>
#if FF_HAVE_DRM || __has_include(<drm/drm.h>)
#include <fcntl.h>
#include <sys/ioctl.h>
#include "common/io.h"
#include "common/library.h"
#include "common/mallocHelper.h"
#include "common/strutil.h"
#if FF_HAVE_DRM
#include <drm.h>
#include <radeon_drm.h>
#include <nouveau_drm.h>
#include <amdgpu_drm.h>
#else
#define FF_HAVE_DRM 1
#include <drm/drm.h>
#include <drm/radeon_drm.h>
#include <drm/nouveau_drm.h>
#include <drm/amdgpu_drm.h>
#endif
#include "intel_drm.h"
#include "asahi_drm.h"
#include <radeon_drm.h>
#include <nouveau_drm.h>
const char* ffDrmDetectRadeon(const FFGPUOptions* options, FFGPUResult* gpu, const char* renderPath) {
FF_AUTO_CLOSE_FD int fd = open(renderPath, O_RDONLY | O_CLOEXEC);
@@ -76,52 +83,50 @@ const char* ffDrmDetectRadeon(const FFGPUOptions* options, FFGPUResult* gpu, con
return NULL;
}
#ifdef FF_HAVE_DRM_AMDGPU
#include <amdgpu.h>
#include <amdgpu_drm.h>
const char* ffDrmDetectAmdgpu(const FFGPUOptions* options, FFGPUResult* gpu, const char* renderPath) {
#if FF_HAVE_DRM_AMDGPU
FF_LIBRARY_LOAD_MESSAGE(libdrm, "libdrm_amdgpu" FF_LIBRARY_EXTENSION, 1)
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, amdgpu_device_initialize)
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, amdgpu_get_marketing_name)
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, amdgpu_query_gpu_info)
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, amdgpu_query_sensor_info)
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, amdgpu_query_heap_info)
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, amdgpu_device_deinitialize)
FF_AUTO_CLOSE_FD int fd = open(renderPath, O_RDONLY | O_CLOEXEC);
if (fd < 0) {
return "Failed to open DRM render device";
}
amdgpu_device_handle handle;
uint32_t majorVersion, minorVersion;
if (ffamdgpu_device_initialize(fd, &majorVersion, &minorVersion, &handle) < 0) {
return "Failed to initialize AMDGPU device";
}
uint32_t value;
if (options->temp) {
if (ffamdgpu_query_sensor_info(handle, AMDGPU_INFO_SENSOR_GPU_TEMP, sizeof(value), &value) >= 0) {
if (ioctl(fd, DRM_IOCTL_AMDGPU_INFO,
&(struct drm_amdgpu_info) {
.return_pointer = (uintptr_t) &value,
.return_size = sizeof(value),
.query = AMDGPU_INFO_SENSOR,
.query_hw_ip.type = AMDGPU_INFO_SENSOR_GPU_TEMP,
}) >= 0 && value != 0) {
gpu->temperature = value / 1000.;
}
}
ffStrbufSetS(&gpu->name, ffamdgpu_get_marketing_name(handle));
struct amdgpu_gpu_info gpuInfo;
if (ffamdgpu_query_gpu_info(handle, &gpuInfo) >= 0) {
gpu->coreCount = (int32_t) gpuInfo.cu_active_number;
gpu->frequency = (uint32_t) (gpuInfo.max_engine_clk / 1000u);
struct drm_amdgpu_info_device devInfo;
if (ioctl(fd, DRM_IOCTL_AMDGPU_INFO,
&(struct drm_amdgpu_info) {
.return_pointer = (uintptr_t) &devInfo,
.return_size = sizeof(devInfo),
.query = AMDGPU_INFO_DEV_INFO,
}) >= 0) {
gpu->coreCount = (int32_t) devInfo.cu_active_number;
gpu->frequency = (uint32_t) (devInfo.max_engine_clock / 1000u);
gpu->index = FF_GPU_INDEX_UNSET;
gpu->type = gpuInfo.ids_flags & AMDGPU_IDS_FLAGS_FUSION ? FF_GPU_TYPE_INTEGRATED : FF_GPU_TYPE_DISCRETE;
#define FF_VRAM_CASE(name, value) \
case value /* AMDGPU_VRAM_TYPE_ ## name */: \
gpu->type = devInfo.ids_flags & AMDGPU_IDS_FLAGS_FUSION ? FF_GPU_TYPE_INTEGRATED : FF_GPU_TYPE_DISCRETE;
// Was `_pad`. Introduced in commit https://github.com/sailfishos-mirror/drm/commit/22b698a5990292bce0eeb2782754d1eba3fe7a2e
#ifdef AMDGPU_FAMILY_GC_11_0_0
gpu->psMax.gen = (uint16_t) devInfo.pcie_gen;
gpu->psMax.lanes = (uint16_t) devInfo.pcie_num_lanes;
#else
gpu->psMax.gen = (uint16_t) devInfo._pad;
gpu->psMax.lanes = (uint16_t) devInfo._pad1;
#endif
#define FF_VRAM_CASE(name, value) \
case value /* AMDGPU_VRAM_TYPE_ ## name */: \
ffStrbufSetStatic(&gpu->memoryType, #name); \
break
switch (gpuInfo.vram_type) {
switch (devInfo.vram_type) {
FF_VRAM_CASE(UNKNOWN, 0);
FF_VRAM_CASE(GDDR1, 1);
FF_VRAM_CASE(DDR2, 2);
@@ -135,35 +140,39 @@ const char* ffDrmDetectAmdgpu(const FFGPUOptions* options, FFGPUResult* gpu, con
FF_VRAM_CASE(DDR5, 10);
FF_VRAM_CASE(LPDDR4, 11);
FF_VRAM_CASE(LPDDR5, 12);
FF_VRAM_CASE(HBM3E, 13);
FF_VRAM_CASE(HBM4, 14);
default:
ffStrbufAppendF(&gpu->memoryType, "Unknown (%u)", gpuInfo.vram_type);
ffStrbufAppendF(&gpu->memoryType, "Unknown (%u)", devInfo.vram_type);
break;
}
struct amdgpu_heap_info heapInfo;
if (ffamdgpu_query_heap_info(handle, AMDGPU_GEM_DOMAIN_VRAM, 0, &heapInfo) >= 0) {
gpu->dedicated.total = heapInfo.heap_size;
gpu->dedicated.used = heapInfo.heap_usage;
}
if (ffamdgpu_query_heap_info(handle, AMDGPU_GEM_DOMAIN_GTT, 0, &heapInfo) >= 0) {
gpu->shared.total = heapInfo.heap_size;
gpu->shared.used = heapInfo.heap_usage;
}
}
if (ffamdgpu_query_sensor_info(handle, AMDGPU_INFO_SENSOR_GPU_LOAD, sizeof(value), &value) >= 0) {
struct drm_amdgpu_memory_info memInfo;
if (ioctl(fd, DRM_IOCTL_AMDGPU_INFO,
&(struct drm_amdgpu_info) {
.return_pointer = (uintptr_t) &memInfo,
.return_size = sizeof(memInfo),
.query = AMDGPU_INFO_MEMORY,
}) >= 0) {
gpu->dedicated.total = memInfo.vram.total_heap_size;
gpu->dedicated.used = memInfo.vram.heap_usage;
gpu->shared.total = memInfo.gtt.total_heap_size;
gpu->shared.used = memInfo.gtt.heap_usage;
}
if (ioctl(fd, DRM_IOCTL_AMDGPU_INFO,
&(struct drm_amdgpu_info) {
.return_pointer = (uintptr_t) &value,
.return_size = sizeof(value),
.query = AMDGPU_INFO_SENSOR,
.query_hw_ip.type = AMDGPU_INFO_SENSOR_GPU_LOAD,
}) >= 0) {
gpu->coreUsage = value;
}
ffamdgpu_device_deinitialize(handle);
return NULL;
#else
FF_UNUSED(options, gpu, renderPath);
return "Fastfetch is compiled without libdrm support";
#endif
}
#endif
const char* ffDrmDetectI915(FFGPUResult* gpu, int fd) {
{
@@ -356,6 +365,7 @@ const char* ffDrmDetectNouveau(FFGPUResult* gpu, int fd) {
#include "gpu_driver_specific.h"
const char* ffGPUDetectDriverSpecific(const FFGPUOptions* options, FFGPUResult* gpu, FFGpuDriverPciBusId pciBusId) {
#if !__OpenBSD__
__typeof__(&ffDetectNvidiaGpuInfo) detectFn;
const char* soName;
if (getDriverSpecificDetectionFn(gpu->vendor.chars, &detectFn, &soName) && (options->temp || options->driverSpecific)) {
@@ -367,14 +377,19 @@ const char* ffGPUDetectDriverSpecific(const FFGPUOptions* options, FFGPUResult*
.index = &gpu->index,
.temp = options->temp ? &gpu->temperature : NULL,
.memory = options->driverSpecific ? &gpu->dedicated : NULL,
.sharedMemory = options->driverSpecific ? &gpu->shared : NULL,
.memoryType = options->driverSpecific ? &gpu->memoryType : NULL,
.coreCount = options->driverSpecific ? (uint32_t*) &gpu->coreCount : NULL,
.coreUsage = options->driverSpecific ? &gpu->coreUsage : NULL,
.type = &gpu->type,
.frequency = options->driverSpecific ? &gpu->frequency : NULL,
.name = &gpu->name,
.psCurr = options->driverSpecific ? &gpu->psCurr : NULL,
.psMax = options->driverSpecific ? &gpu->psMax : NULL,
},
soName);
}
#endif
return "No driver-specific detection function found for the GPU vendor";
}
+1
View File
@@ -130,6 +130,7 @@ const char* ffDetectGPUImpl(FF_A_UNUSED const FFGPUOptions* options, FFlist* gpu
gpu->dedicated.total = gpu->dedicated.used = gpu->shared.total = gpu->shared.used = FF_GPU_VMEM_SIZE_UNSET;
gpu->deviceId = ffGPUPciAddr2Id(0, pciBus, pciDev, pciFunc);
gpu->frequency = FF_GPU_FREQUENCY_UNSET;
gpu->pcieSpeed = FF_GPU_PCIE_SPEED_UNSET;
if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_AMD) {
ffGPUQueryAmdGpuName(deviceId, revision, gpu);
+1
View File
@@ -37,6 +37,7 @@ const char* ffDetectGPUImpl(FF_A_UNUSED const FFGPUOptions* options, FFlist* gpu
gpu->dedicated.total = gpu->dedicated.used = gpu->shared.total = gpu->shared.used = FF_GPU_VMEM_SIZE_UNSET;
gpu->deviceId = ffGPUPciAddr2Id(0, dev.bus, dev.device, dev.function);
gpu->frequency = FF_GPU_FREQUENCY_UNSET;
gpu->pcieSpeed = FF_GPU_PCIE_SPEED_UNSET;
if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_AMD) {
ffGPUQueryAmdGpuName(dev.device_id, dev.revision, gpu);
+27
View File
@@ -16,6 +16,8 @@ struct FFIgclData {
FF_LIBRARY_SYMBOL(ctlMemoryGetState)
FF_LIBRARY_SYMBOL(ctlEnumFrequencyDomains)
FF_LIBRARY_SYMBOL(ctlFrequencyGetProperties)
FF_LIBRARY_SYMBOL(ctlPciGetProperties)
FF_LIBRARY_SYMBOL(ctlPciGetState)
bool inited;
ctl_api_handle_t apiHandle;
@@ -43,6 +45,8 @@ const char* ffDetectIntelGpuInfo(const FFGpuDriverCondition* cond, FFGpuDriverRe
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libigcl, igclData, ctlMemoryGetState)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libigcl, igclData, ctlEnumFrequencyDomains)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libigcl, igclData, ctlFrequencyGetProperties)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libigcl, igclData, ctlPciGetProperties)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libigcl, igclData, ctlPciGetState)
if (ffctlInit(&(ctl_init_args_t) {
.AppVersion = CTL_IMPL_VERSION,
@@ -227,5 +231,28 @@ const char* ffDetectIntelGpuInfo(const FFGpuDriverCondition* cond, FFGpuDriverRe
ffStrbufSetS(result.name, properties.name);
}
if (result.psMax) {
ctl_pci_properties_t pciProps = { .Size = sizeof(pciProps), .Version = 0 };
if (igclData.ffctlPciGetProperties(device, &pciProps) == CTL_RESULT_SUCCESS) {
if (pciProps.maxSpeed.gen > 0) {
result.psMax->gen = (uint16_t) pciProps.maxSpeed.gen;
}
if (pciProps.maxSpeed.width > 0) {
result.psMax->lanes = (uint16_t) pciProps.maxSpeed.width;
}
}
}
if (result.psCurr) {
ctl_pci_state_t pciState = { .Size = sizeof(pciState), .Version = 0 };
if (igclData.ffctlPciGetState(device, &pciState) == CTL_RESULT_SUCCESS) {
if (pciState.speed.gen > 0) {
result.psCurr->gen = (uint16_t) pciState.speed.gen;
}
if (pciState.speed.width > 0) {
result.psCurr->lanes = (uint16_t) pciState.speed.width;
}
}
}
return NULL;
}
+58 -63
View File
@@ -1,40 +1,12 @@
#include "detection/gpu/gpu.h"
#include "detection/vulkan/vulkan.h"
#include "detection/cpu/cpu.h"
#include "detection/gpu/gpu_driver_specific.h"
#include "common/io.h"
#include "common/library.h"
#include "common/FFstrbuf.h"
#include "common/strutil.h"
#include "common/mallocHelper.h"
#include "modules/gpu/option.h"
#include <inttypes.h>
#include <stdint.h>
#ifdef FF_HAVE_DRM_AMDGPU
#include <amdgpu.h>
#include <amdgpu_drm.h>
#include <fcntl.h>
#endif
#ifdef FF_HAVE_DRM
#include "intel_drm.h"
#include <fcntl.h>
#include <sys/ioctl.h>
#endif
#if defined(FF_HAVE_DRM) && defined(__aarch64__)
// https://github.com/alyssarosenzweig/linux/blob/agx-uapi-v7/include/uapi/drm/asahi_drm.h
// Found in kernel-headers-6.14.4-400.asahi.fc42.aarch64
#if __has_include(<drm/asahi_drm.h>)
#include <drm/asahi_drm.h>
#else
#include "asahi_drm.h"
#endif
#define FF_HAVE_DRM_ASAHI 1
#endif
static bool pciDetectDriver(FFstrbuf* result, FFstrbuf* pciDir, FFstrbuf* buffer, FF_A_UNUSED const char* drmKey) {
uint32_t pciDirLength = pciDir->length;
ffStrbufAppendS(pciDir, "/driver");
@@ -100,7 +72,6 @@ FF_A_UNUSED static const char* drmFindRenderFromCard(const char* drmCardKey, FFs
}
static const char* drmDetectAmdSpecific(const FFGPUOptions* options, FFGPUResult* gpu, const char* drmKey, FFstrbuf* buffer) {
#if FF_HAVE_DRM
const char* error = drmFindRenderFromCard(drmKey, buffer);
if (error) {
return error;
@@ -108,17 +79,8 @@ static const char* drmDetectAmdSpecific(const FFGPUOptions* options, FFGPUResult
if (ffStrbufEqualS(&gpu->driver, "radeon")) {
return ffDrmDetectRadeon(options, gpu, buffer->chars);
} else {
#if FF_HAVE_DRM_AMDGPU
return ffDrmDetectAmdgpu(options, gpu, buffer->chars);
#else
FF_UNUSED(options, gpu, drmKey, buffer);
return "Fastfetch is not compiled with libdrm_amdgpu support";
#endif
}
#else
FF_UNUSED(options, gpu, drmKey, buffer);
return "Fastfetch is not compiled with drm support";
#endif
}
static void pciDetectAmdSpecific(const FFGPUOptions* options, FFGPUResult* gpu, FFstrbuf* pciDir, FFstrbuf* buffer) {
@@ -246,7 +208,6 @@ static void pciDetectIntelSpecific(const FFGPUOptions* options, FFGPUResult* gpu
}
static const char* drmDetectIntelSpecific(FFGPUResult* gpu, const char* drmKey, FFstrbuf* buffer) {
#if FF_HAVE_DRM
ffStrbufSetS(buffer, "/dev/dri/");
ffStrbufAppendS(buffer, drmKey);
FF_AUTO_CLOSE_FD int fd = open(buffer->chars, O_RDONLY | O_CLOEXEC);
@@ -260,10 +221,6 @@ static const char* drmDetectIntelSpecific(FFGPUResult* gpu, const char* drmKey,
return ffDrmDetectI915(gpu, fd);
}
return "Unknown Intel GPU driver";
#else
FF_UNUSED(gpu, drmKey, buffer);
return "Fastfetch is not compiled with drm support";
#endif
}
static const char* pciDetectTempGeneral(const FFGPUOptions* options, FFGPUResult* gpu, FFstrbuf* pciDir, FFstrbuf* buffer) {
@@ -294,7 +251,6 @@ static const char* pciDetectTempGeneral(const FFGPUOptions* options, FFGPUResult
}
static const char* drmDetectNouveauSpecific(FFGPUResult* gpu, const char* drmKey, FFstrbuf* buffer) {
#if FF_HAVE_DRM
ffStrbufSetS(buffer, "/dev/dri/");
ffStrbufAppendS(buffer, drmKey);
FF_AUTO_CLOSE_FD int fd = open(buffer->chars, O_RDONLY | O_CLOEXEC);
@@ -303,10 +259,6 @@ static const char* drmDetectNouveauSpecific(FFGPUResult* gpu, const char* drmKey
}
return ffDrmDetectNouveau(gpu, fd);
#else
FF_UNUSED(gpu, drmKey, buffer);
return "Fastfetch is not compiled with drm support";
#endif
}
static const char* pciDetectZxSpecific(const FFGPUOptions* options, FFGPUResult* gpu, FFstrbuf* pciDir, FFstrbuf* buffer) {
@@ -351,6 +303,32 @@ static const char* pciDetectZxSpecific(const FFGPUOptions* options, FFGPUResult*
return NULL;
}
static inline uint16_t pcieLinkSpeedToGen(const FFstrbuf* buffer) {
int64_t speed = ffStrbufToSInt(buffer, FF_GPU_PCIE_SPEED_UNSET);
if (speed >= 64) {
return 6;
} else if (speed >= 32) {
return 5;
} else if (speed >= 16) {
return 4;
} else if (speed >= 8) {
return 3;
} else if (speed >= 5) {
return 2;
} else if (speed >= 2) { // 2.5
return 1;
}
return FF_GPU_PCIE_SPEED_UNSET;
}
static inline uint16_t pcieWidthToLanes(const FFstrbuf* buffer) {
int64_t width = ffStrbufToSInt(buffer, FF_GPU_PCIE_SPEED_UNSET);
if (width > 0 && width < 255) { // kernel returns 255 if the value is unknown
return (uint16_t) width;
}
return FF_GPU_PCIE_SPEED_UNSET;
}
static const char* detectPci(const FFGPUOptions* options, FFlist* gpus, FFstrbuf* buffer, FFstrbuf* deviceDir, const char* drmKey) {
const uint32_t drmDirPathLength = deviceDir->length;
uint32_t vendorId, deviceId, subVendorId, subDeviceId;
@@ -406,6 +384,7 @@ static const char* detectPci(const FFGPUOptions* options, FFlist* gpus, FFstrbuf
gpu->dedicated.total = gpu->dedicated.used = gpu->shared.total = gpu->shared.used = FF_GPU_VMEM_SIZE_UNSET;
gpu->deviceId = ffGPUPciAddr2Id(pciDomain, pciBus, pciDevice, pciFunc);
gpu->frequency = FF_GPU_FREQUENCY_UNSET;
gpu->pcieSpeed = FF_GPU_PCIE_SPEED_UNSET;
char drmKeyBuffer[8];
if (!drmKey) {
@@ -431,6 +410,34 @@ static const char* detectPci(const FFGPUOptions* options, FFlist* gpus, FFstrbuf
pciDetectDriver(&gpu->driver, deviceDir, buffer, drmKey);
ffStrbufSubstrBefore(deviceDir, drmDirPathLength);
ffStrbufAppendS(deviceDir, "/max_link_speed");
if (ffReadFileBuffer(deviceDir->chars, buffer)) {
gpu->psMax.gen = pcieLinkSpeedToGen(buffer);
}
ffStrbufSubstrBefore(deviceDir, drmDirPathLength);
if (gpu->psMax.gen != FF_GPU_PCIE_SPEED_UNSET) {
ffStrbufAppendS(deviceDir, "/max_link_width");
if (ffReadFileBuffer(deviceDir->chars, buffer)) {
gpu->psMax.lanes = pcieWidthToLanes(buffer);
}
ffStrbufSubstrBefore(deviceDir, drmDirPathLength);
}
ffStrbufAppendS(deviceDir, "/current_link_speed");
if (ffReadFileBuffer(deviceDir->chars, buffer)) {
gpu->psCurr.gen = pcieLinkSpeedToGen(buffer);
}
ffStrbufSubstrBefore(deviceDir, drmDirPathLength);
if (gpu->psCurr.gen != FF_GPU_PCIE_SPEED_UNSET) {
ffStrbufAppendS(deviceDir, "/current_link_width");
if (ffReadFileBuffer(deviceDir->chars, buffer)) {
gpu->psCurr.lanes = pcieWidthToLanes(buffer);
}
ffStrbufSubstrBefore(deviceDir, drmDirPathLength);
}
if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_AMD) {
bool ok = false;
if (drmKey && options->driverSpecific) {
@@ -478,24 +485,13 @@ static const char* detectPci(const FFGPUOptions* options, FFlist* gpus, FFstrbuf
ffGPUFillVendorAndName(subclassId, (uint16_t) vendorId, (uint16_t) deviceId, gpu);
}
if (gpu->type == FF_GPU_TYPE_UNKNOWN) {
if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_NVIDIA) {
if (ffStrbufStartsWithIgnCaseS(&gpu->name, "GeForce") ||
ffStrbufStartsWithIgnCaseS(&gpu->name, "Quadro") ||
ffStrbufStartsWithIgnCaseS(&gpu->name, "Tesla")) {
gpu->type = FF_GPU_TYPE_DISCRETE;
}
} else if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_MTHREADS) {
if (ffStrbufStartsWithIgnCaseS(&gpu->name, "MTT ")) {
gpu->type = FF_GPU_TYPE_DISCRETE;
}
}
}
ffGPUFillVendorByDeviceName(gpu);
return NULL;
}
#if __aarch64__
#include "detection/cpu/cpu.h"
FF_A_UNUSED static const char* drmDetectAsahiSpecific(FFGPUResult* gpu, const char* name, FF_A_UNUSED FFstrbuf* buffer, FF_A_UNUSED const char* drmKey) {
if (sscanf(name, "agx-t%lu", &gpu->deviceId) == 1) {
@@ -503,14 +499,12 @@ FF_A_UNUSED static const char* drmDetectAsahiSpecific(FFGPUResult* gpu, const ch
}
ffStrbufSetStatic(&gpu->vendor, FF_GPU_VENDOR_NAME_APPLE);
#if FF_HAVE_DRM_ASAHI
ffStrbufSetS(buffer, "/dev/dri/");
ffStrbufAppendS(buffer, drmKey);
FF_AUTO_CLOSE_FD int fd = open(buffer->chars, O_RDONLY | O_CLOEXEC);
if (fd >= 0) {
return ffDrmDetectAsahi(gpu, fd);
}
#endif
return NULL;
}
@@ -542,6 +536,7 @@ static const char* detectOf(FFlist* gpus, FFstrbuf* buffer, FFstrbuf* drmDir, co
gpu->type = FF_GPU_TYPE_INTEGRATED;
gpu->dedicated.total = gpu->dedicated.used = gpu->shared.total = gpu->shared.used = FF_GPU_VMEM_SIZE_UNSET;
gpu->frequency = FF_GPU_FREQUENCY_UNSET;
gpu->pcieSpeed = FF_GPU_PCIE_SPEED_UNSET;
pciDetectDriver(&gpu->driver, drmDir, buffer, drmKey);
+1
View File
@@ -97,6 +97,7 @@ const char* ffDetectGPUImpl(FF_A_UNUSED const FFGPUOptions* options, FFlist* gpu
gpu->dedicated.total = gpu->dedicated.used = gpu->shared.total = gpu->shared.used = FF_GPU_VMEM_SIZE_UNSET;
gpu->deviceId = ffGPUPciAddr2Id(0, bus, dev, func);
gpu->frequency = FF_GPU_FREQUENCY_UNSET;
gpu->pcieSpeed = FF_GPU_PCIE_SPEED_UNSET;
if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_AMD) {
ffGPUQueryAmdGpuName(PCI_PRODUCT(pciid), PCI_REVISION(pciid), gpu);
+36 -5
View File
@@ -8,12 +8,16 @@ struct FFNvmlData {
FF_LIBRARY_SYMBOL(nvmlDeviceGetHandleByIndex_v2)
FF_LIBRARY_SYMBOL(nvmlDeviceGetHandleByPciBusId_v2)
FF_LIBRARY_SYMBOL(nvmlDeviceGetPciInfo_v3)
FF_LIBRARY_SYMBOL(nvmlDeviceGetTemperature)
FF_LIBRARY_SYMBOL(nvmlDeviceGetTemperatureV)
FF_LIBRARY_SYMBOL(nvmlDeviceGetMemoryInfo_v2)
FF_LIBRARY_SYMBOL(nvmlDeviceGetMemoryInfo)
FF_LIBRARY_SYMBOL(nvmlDeviceGetNumGpuCores)
FF_LIBRARY_SYMBOL(nvmlDeviceGetMaxClockInfo)
FF_LIBRARY_SYMBOL(nvmlDeviceGetUtilizationRates)
FF_LIBRARY_SYMBOL(nvmlDeviceGetMaxPcieLinkGeneration)
FF_LIBRARY_SYMBOL(nvmlDeviceGetMaxPcieLinkWidth)
FF_LIBRARY_SYMBOL(nvmlDeviceGetCurrPcieLinkGeneration)
FF_LIBRARY_SYMBOL(nvmlDeviceGetCurrPcieLinkWidth)
FF_LIBRARY_SYMBOL(nvmlDeviceGetBrand)
FF_LIBRARY_SYMBOL(nvmlDeviceGetIndex)
FF_LIBRARY_SYMBOL(nvmlDeviceGetName)
@@ -154,11 +158,15 @@ const char* ffDetectNvidiaGpuInfo(const FFGpuDriverCondition* cond, FFGpuDriverR
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libnvml, nvmlData, nvmlDeviceGetHandleByIndex_v2)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libnvml, nvmlData, nvmlDeviceGetHandleByPciBusId_v2)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libnvml, nvmlData, nvmlDeviceGetPciInfo_v3)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libnvml, nvmlData, nvmlDeviceGetTemperature)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libnvml, nvmlData, nvmlDeviceGetTemperatureV)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libnvml, nvmlData, nvmlDeviceGetMemoryInfo_v2)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libnvml, nvmlData, nvmlDeviceGetMemoryInfo)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libnvml, nvmlData, nvmlDeviceGetNumGpuCores)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libnvml, nvmlData, nvmlDeviceGetMaxClockInfo)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libnvml, nvmlData, nvmlDeviceGetMaxPcieLinkGeneration)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libnvml, nvmlData, nvmlDeviceGetMaxPcieLinkWidth)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libnvml, nvmlData, nvmlDeviceGetCurrPcieLinkGeneration)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libnvml, nvmlData, nvmlDeviceGetCurrPcieLinkWidth)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libnvml, nvmlData, nvmlDeviceGetUtilizationRates)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libnvml, nvmlData, nvmlDeviceGetBrand)
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libnvml, nvmlData, nvmlDeviceGetIndex)
@@ -246,9 +254,12 @@ const char* ffDetectNvidiaGpuInfo(const FFGpuDriverCondition* cond, FFGpuDriverR
}
if (result.temp) {
uint32_t value;
if (nvmlData.ffnvmlDeviceGetTemperature(device, NVML_TEMPERATURE_GPU, &value) == NVML_SUCCESS) {
*result.temp = value;
nvmlTemperature_v1_t temp = {
.version = nvmlTemperature_v1,
.sensorType = NVML_TEMPERATURE_GPU,
};
if (nvmlData.ffnvmlDeviceGetTemperatureV(device, &temp) == NVML_SUCCESS) {
*result.temp = temp.temperature;
}
}
@@ -288,6 +299,26 @@ const char* ffDetectNvidiaGpuInfo(const FFGpuDriverCondition* cond, FFGpuDriverR
}
}
if (result.psMax) {
unsigned int value;
if (nvmlData.ffnvmlDeviceGetMaxPcieLinkGeneration(device, &value) == NVML_SUCCESS) {
result.psMax->gen = (uint16_t) value;
}
if (nvmlData.ffnvmlDeviceGetMaxPcieLinkWidth(device, &value) == NVML_SUCCESS) {
result.psMax->lanes = (uint16_t) value;
}
}
if (result.psCurr) {
unsigned int value;
if (nvmlData.ffnvmlDeviceGetCurrPcieLinkGeneration(device, &value) == NVML_SUCCESS) {
result.psCurr->gen = (uint16_t) value;
}
if (nvmlData.ffnvmlDeviceGetCurrPcieLinkWidth(device, &value) == NVML_SUCCESS) {
result.psCurr->lanes = (uint16_t) value;
}
}
return NULL;
#else
+15 -1
View File
@@ -27,7 +27,7 @@ static inline int pciReadConf(int fd, uint8_t bus, uint8_t device, uint8_t func,
return 0;
}
const char* ffDetectGPUImpl(FF_A_UNUSED const FFGPUOptions* options, FFlist* gpus) {
const char* detectByPci(FF_A_UNUSED const FFGPUOptions* options, FFlist* gpus) {
char pciDevPath[] = "/dev/pci0";
FF_AUTO_CLOSE_FD int pcifd = open(pciDevPath, O_RDONLY | O_CLOEXEC);
if (pcifd < 0) {
@@ -86,6 +86,7 @@ const char* ffDetectGPUImpl(FF_A_UNUSED const FFGPUOptions* options, FFlist* gpu
gpu->dedicated.total = gpu->dedicated.used = gpu->shared.total = gpu->shared.used = FF_GPU_VMEM_SIZE_UNSET;
gpu->deviceId = ffGPUPciAddr2Id(0, bus, dev, func);
gpu->frequency = FF_GPU_FREQUENCY_UNSET;
gpu->pcieSpeed = FF_GPU_PCIE_SPEED_UNSET;
if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_AMD) {
ffGPUQueryAmdGpuName(PCI_PRODUCT(pciid), PCI_REVISION(pciid), gpu);
@@ -99,3 +100,16 @@ const char* ffDetectGPUImpl(FF_A_UNUSED const FFGPUOptions* options, FFlist* gpu
return NULL;
}
const char* ffDetectGPUImpl(const FFGPUOptions* options, FFlist* gpus) {
#if FF_HAVE_DRM
if (options->detectionMethod == FF_GPU_DETECTION_METHOD_AUTO) {
ffGPUDetectByDrmBSD(options, gpus);
if (gpus->length > 0) {
return NULL;
}
}
#endif
return detectByPci(options, gpus);
}
+1 -3
View File
@@ -2,6 +2,7 @@
#include "common/io.h"
#include "common/properties.h"
#include "common/memrchr.h"
#include "common/strutil.h"
#include <stdlib.h>
#ifdef __FreeBSD__
@@ -22,9 +23,6 @@
#include "fastfetch_amdgpuids.c.inc"
#endif
#define FF_STR_INDIR(x) #x
#define FF_STR(x) FF_STR_INDIR(x)
static const FFstrbuf* loadPciIds() {
static FFstrbuf pciids;
+1
View File
@@ -21,6 +21,7 @@ static int walkDevTree(di_node_t node, FF_A_UNUSED di_minor_t minor, FFlist* gpu
gpu->dedicated.total = gpu->dedicated.used = gpu->shared.total = gpu->shared.used = FF_GPU_VMEM_SIZE_UNSET;
gpu->deviceId = strtoul(di_bus_addr(node), NULL, 16);
gpu->frequency = FF_GPU_FREQUENCY_UNSET;
gpu->pcieSpeed = FF_GPU_PCIE_SPEED_UNSET;
if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_AMD) {
int* revId;
+95 -69
View File
@@ -11,31 +11,28 @@
#if _WIN32
#include "common/windows/unicode.h"
#include "common/windows/registry.h"
#include "common/mallocHelper.h"
#if FF_WIN81_COMPAT
#include "common/mallocHelper.h"
#include <windows.h>
#include <cfgmgr32.h>
#include <devguid.h>
#define INITGUID
#include <windows.h>
#include <cfgmgr32.h>
#include <devguid.h>
#include <pciprop.h>
#define GUID_DEVCLASS_DISPLAY_STRING L"{4d36e968-e325-11ce-bfc1-08002be10318}" // Found in <devguid.h>
#define GUID_DEVCLASS_DISPLAY_STRING L"{4d36e968-e325-11ce-bfc1-08002be10318}" // Found in <devguid.h>
static bool queryDeviceIdsFallback(D3DKMT_ADAPTERADDRESS adapterAddress, D3DKMT_DEVICE_IDS* outDeviceIds) {
FF_DEBUG("KMTQAITYPE_PHYSICALADAPTERDEVICEIDS failed. Attempting queryDeviceIdsFallback: bus=%u device=%u function=%u",
adapterAddress.BusNumber,
adapterAddress.DeviceNumber,
adapterAddress.FunctionNumber);
if (adapterAddress.BusNumber == -1u) {
FF_DEBUG("Invalid adapter address, cannot query device IDs");
return false;
}
static bool queryPciDeviceInfo(FFGPUResult* gpu, D3DKMT_DEVICE_IDS* outDeviceIds) {
FF_DEBUG("Query PCI device info: %08llX", gpu->deviceId);
static FFlist deviceIdsCache;
static bool initialized;
typedef struct {
uint32_t currentLinkSpeed;
uint32_t currentLinkWidth;
uint32_t maxLinkSpeed;
uint32_t maxLinkWidth;
D3DKMT_DEVICE_IDS deviceIds;
D3DKMT_ADAPTERADDRESS adapterAddress;
uint64_t adapterAddress;
} CacheEntry;
if (!initialized) {
@@ -79,34 +76,29 @@ static bool queryDeviceIdsFallback(D3DKMT_ADAPTERADDRESS adapterAddress, D3DKMT_
continue;
}
uint32_t pciBus = 0;
CacheEntry* entry = FF_LIST_ADD(CacheEntry, deviceIdsCache);
*entry = (CacheEntry) {};
// L"PCI\\VEN_10DE&DEV_2782&SUBSYS_513417AA&REV_A1\\4&3674a6b9&0&0008"
if (swscanf(devId + 4, L"VEN_%x&DEV_%x&SUBSYS_%4x%4x&REV_%x", &entry->deviceIds.VendorID, &entry->deviceIds.DeviceID, &entry->deviceIds.SubSystemID, &entry->deviceIds.SubVendorID, &entry->deviceIds.RevisionID) >= 2) {
FF_DEBUG("Parsed PCI IDs - Vendor: 0x%04x, Device: 0x%04x, SubVendor: 0x%04x, SubSystem: 0x%04x, Rev: 0x%04x", entry->deviceIds.VendorID, entry->deviceIds.DeviceID, entry->deviceIds.SubVendorID, entry->deviceIds.SubSystemID, entry->deviceIds.RevisionID);
// I thought it was DXGKMDT_OPM_BUS_TYPE_PCI, but it turns out to be false
// Who TF knows what 1 actually means. It's just reported by most graphic cards
// And yeah, DXGKMDT_OPM_BUS_TYPE_PCIEXPRESS (3) exists
entry->deviceIds.BusType = 1;
} else {
FF_DEBUG("Failed to parse PCI IDs from device ID string");
deviceIdsCache.length--; // remove the cache entry since it's not valid
continue;
}
uint32_t pciBus = 0;
ULONG pciBufLen = sizeof(pciBus);
if (CM_Get_DevNode_Registry_PropertyW(devInst, CM_DRP_BUSNUMBER, NULL, &pciBus, &pciBufLen, 0) == CR_SUCCESS) {
uint32_t pciAddr = 0;
pciBufLen = sizeof(pciAddr);
if (CM_Get_DevNode_Registry_PropertyW(devInst, CM_DRP_ADDRESS, NULL, &pciAddr, &pciBufLen, 0) == CR_SUCCESS) {
CacheEntry* entry = FF_LIST_ADD(CacheEntry, deviceIdsCache);
entry->deviceIds = (D3DKMT_DEVICE_IDS) {};
// L"PCI\\VEN_10DE&DEV_2782&SUBSYS_513417AA&REV_A1\\4&3674a6b9&0&0008"
if (swscanf(devId + 4, L"VEN_%x&DEV_%x&SUBSYS_%4x%4x&REV_%x", &entry->deviceIds.VendorID, &entry->deviceIds.DeviceID, &entry->deviceIds.SubSystemID, &entry->deviceIds.SubVendorID, &entry->deviceIds.RevisionID) >= 2) {
FF_DEBUG("Parsed PCI IDs - Vendor: 0x%04x, Device: 0x%04x, SubVendor: 0x%04x, SubSystem: 0x%04x, Rev: 0x%04x", entry->deviceIds.VendorID, entry->deviceIds.DeviceID, entry->deviceIds.SubVendorID, entry->deviceIds.SubSystemID, entry->deviceIds.RevisionID);
// I thought it was DXGKMDT_OPM_BUS_TYPE_PCI, but it turns out to be false
// Who TF knows what 1 actually means. It's just reported by most graphic cards
// And yeah, DXGKMDT_OPM_BUS_TYPE_PCIEXPRESS (3) exists
entry->deviceIds.BusType = 1;
} else {
FF_DEBUG("Failed to parse PCI IDs from device ID string");
deviceIdsCache.length--; // remove the cache entry since it's not valid
continue;
}
entry->adapterAddress = (D3DKMT_ADAPTERADDRESS) {
.BusNumber = pciBus,
.DeviceNumber = (pciAddr >> 16) & 0xFFFF,
.FunctionNumber = pciAddr & 0xFFFF,
};
entry->adapterAddress = ffGPUPciAddr2Id(0, pciBus, (pciAddr >> 16) & 0xFFFF, pciAddr & 0xFFFF);
FF_DEBUG("Cached device IDs for PCI bus %u: vendor=0x%04x device=0x%04x", pciBus, entry->deviceIds.VendorID, entry->deviceIds.DeviceID);
} else {
FF_DEBUG("Failed to get PCI address");
@@ -114,21 +106,65 @@ static bool queryDeviceIdsFallback(D3DKMT_ADAPTERADDRESS adapterAddress, D3DKMT_
} else {
FF_DEBUG("Failed to get PCI bus number");
}
DEVPROPTYPE propType;
pciBufLen = sizeof(entry->maxLinkSpeed);
// Reports PCEe gen despite the PKEY name
CONFIGRET ret = CM_Get_DevNode_PropertyW(devInst, &DEVPKEY_PciDevice_MaxLinkSpeed, &propType, (PBYTE) &entry->maxLinkSpeed, &pciBufLen, 0);
if (ret == CR_SUCCESS) {
FF_DEBUG("PCIe max GEN: %u", entry->maxLinkSpeed);
} else {
FF_DEBUG("Failed to get PCIe max GEN: %s", ffDebugConfigRet(ret));
}
if (entry->maxLinkSpeed != FF_GPU_PCIE_SPEED_UNSET) {
pciBufLen = sizeof(entry->maxLinkWidth);
ret = CM_Get_DevNode_PropertyW(devInst, &DEVPKEY_PciDevice_MaxLinkWidth, &propType, (PBYTE) &entry->maxLinkWidth, &pciBufLen, 0);
if (ret == CR_SUCCESS) {
FF_DEBUG("PCIe max link width: %u", entry->maxLinkWidth);
} else {
FF_DEBUG("Failed to get PCIe max link width: %s", ffDebugConfigRet(ret));
}
}
pciBufLen = sizeof(entry->currentLinkSpeed);
ret = CM_Get_DevNode_PropertyW(devInst, &DEVPKEY_PciDevice_CurrentLinkSpeed, &propType, (PBYTE) &entry->currentLinkSpeed, &pciBufLen, 0);
if (ret == CR_SUCCESS) {
FF_DEBUG("PCIe GEN: %u", entry->currentLinkSpeed);
} else {
FF_DEBUG("Failed to get PCIe GEN: %s", ffDebugConfigRet(ret));
}
if (entry->currentLinkSpeed != FF_GPU_PCIE_SPEED_UNSET) {
pciBufLen = sizeof(entry->currentLinkWidth);
ret = CM_Get_DevNode_PropertyW(devInst, &DEVPKEY_PciDevice_CurrentLinkWidth, &propType, (PBYTE) &entry->currentLinkWidth, &pciBufLen, 0);
if (ret == CR_SUCCESS) {
FF_DEBUG("PCIe current link width: %u", entry->currentLinkWidth);
} else {
FF_DEBUG("Failed to get PCIe current link width: %s", ffDebugConfigRet(ret));
}
}
}
}
FF_LIST_FOR_EACH (CacheEntry, entry, deviceIdsCache) {
if (memcmp(&entry->adapterAddress, &adapterAddress, sizeof(adapterAddress)) == 0) {
FF_DEBUG("Cache hit for adapter address: bus=%u device=%u function=%u", adapterAddress.BusNumber, adapterAddress.DeviceNumber, adapterAddress.FunctionNumber);
*outDeviceIds = entry->deviceIds;
if (gpu->deviceId == entry->adapterAddress) {
FF_DEBUG("Cache hit for adapter address: %08llX", gpu->deviceId);
if (outDeviceIds->VendorID != -1u) {
*outDeviceIds = entry->deviceIds;
}
gpu->psMax.gen = (uint16_t) entry->maxLinkSpeed;
gpu->psMax.lanes = (uint16_t) entry->maxLinkWidth;
gpu->psCurr.gen = (uint16_t) entry->currentLinkSpeed;
gpu->psCurr.lanes = (uint16_t) entry->currentLinkWidth;
return true;
}
}
FF_DEBUG("Cache miss for adapter address: bus=%u device=%u function=%u", adapterAddress.BusNumber, adapterAddress.DeviceNumber, adapterAddress.FunctionNumber);
FF_DEBUG("Cache miss for adapter address: %08llX", gpu->deviceId);
return false;
}
#endif // FF_WIN81_COMPAT
static bool queryVendorNameViaRegistry(FFstrbuf* vendor, D3DKMT_HANDLE hAdapter) {
// `KMTQAITYPE_QUERY_ADAPTER_UNIQUE_GUID` reports the GUID value used by the adapter's registry key (DirectX and Video)
@@ -278,6 +314,7 @@ ffGPUDetectWsl2
: adapterType.HybridDiscrete
? FF_GPU_TYPE_DISCRETE
: FF_GPU_TYPE_UNKNOWN;
gpu->pcieSpeed = FF_GPU_PCIE_SPEED_UNSET;
D3DKMT_DRIVERVERSION wddmVersion = KMT_DRIVERVERSION_WDDM_2_0;
status = D3DKMTQueryAdapterInfo(&(D3DKMT_QUERYADAPTERINFO) {
@@ -323,11 +360,7 @@ ffGPUDetectWsl2
.pPrivateDriverData = &deviceIds,
.PrivateDriverDataSize = sizeof(deviceIds),
});
if (NT_SUCCESS(status)
#if FF_WIN81_COMPAT
|| queryDeviceIdsFallback(adapterAddress, &deviceIds.DeviceIds)
#endif
) {
if (NT_SUCCESS(status)) {
ffStrbufSetStatic(&gpu->vendor, ffGPUGetVendorString(deviceIds.DeviceIds.VendorID));
FF_DEBUG("Adapter #%u vendor/device IDs: vendor=0x%04x device=0x%04x",
i,
@@ -338,6 +371,14 @@ ffGPUDetectWsl2
FF_DEBUG("KMTQAITYPE_PHYSICALADAPTERDEVICEIDS query failed for adapter #%u: %s", i, ffDebugNtStatus(status));
}
#if _WIN32
if (adapterAddress.BusNumber != -1u) {
if (queryPciDeviceInfo(gpu, &deviceIds.DeviceIds) && gpu->vendor.length == 0) {
ffStrbufSetStatic(&gpu->vendor, ffGPUGetVendorString(deviceIds.DeviceIds.VendorID));
}
}
#endif
D3DKMT_UMD_DRIVER_VERSION umdDriverVersion;
status = D3DKMTQueryAdapterInfo(&(D3DKMT_QUERYADAPTERINFO) {
.hAdapter = adapter->hAdapter,
@@ -389,8 +430,10 @@ ffGPUDetectWsl2
.coreCount = options->driverSpecific ? (uint32_t*) &gpu->coreCount : NULL,
.coreUsage = options->driverSpecific ? &gpu->coreUsage : NULL,
.type = &gpu->type,
.name = &gpu->name,
.frequency = options->driverSpecific ? &gpu->frequency : NULL,
.name = &gpu->name,
.psCurr = options->driverSpecific ? &gpu->psCurr : NULL,
.psMax = options->driverSpecific ? &gpu->psMax : NULL,
},
dllName);
FF_DEBUG("Driver-specific detection completed: %s", error ?: "Success");
@@ -553,25 +596,8 @@ ffGPUDetectWsl2
}
if (gpu->type == FF_GPU_TYPE_UNKNOWN) {
FF_DEBUG("Using fallback GPU type detection");
if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_NVIDIA) {
if (ffStrbufStartsWithIgnCaseS(&gpu->name, "GeForce") ||
ffStrbufStartsWithIgnCaseS(&gpu->name, "Quadro") ||
ffStrbufStartsWithIgnCaseS(&gpu->name, "Tesla")) {
gpu->type = FF_GPU_TYPE_DISCRETE;
}
} else if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_MTHREADS) {
if (ffStrbufStartsWithIgnCaseS(&gpu->name, "MTT ")) { gpu->type = FF_GPU_TYPE_DISCRETE; }
} else if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_INTEL) {
// 0000:00:02.0 is reserved for Intel integrated graphics
gpu->type = gpu->deviceId == ffGPUPciAddr2Id(0, 0, 2, 0) ? FF_GPU_TYPE_INTEGRATED : FF_GPU_TYPE_DISCRETE;
} else if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_VMWARE || gpu->vendor.chars == FF_GPU_VENDOR_NAME_PARALLELS) {
// Virtualized GPUs
gpu->type = FF_GPU_TYPE_INTEGRATED;
}
if (gpu->type != FF_GPU_TYPE_UNKNOWN) {
FF_DEBUG("Determined GPU type based on vendor (%s) and name: %u", gpu->vendor.chars, gpu->type);
if (ffGPUFillVendorByDeviceName(gpu)) {
// OK
}
#if _WIN32
else if (ffIsWindows10OrGreater()) {
+45 -1
View File
@@ -5,6 +5,7 @@
// DOCUMENTATION REFERENCED BELOW, IN ORDER TO MAKE FASTFETCH MIT COMPLIANT.
#include <stdint.h>
#include <stdbool.h>
// https://intel.github.io/drivers.gpu.control-library/Control/api.html#_CPPv412ctl_result_t
typedef enum ctl_result_t {
@@ -73,7 +74,7 @@ typedef struct ctl_adapter_bdf_t {
} ctl_adapter_bdf_t;
#define IGCL_CTL_MAX_DEVICE_NAME_LEN 100
#define IGCL_CTL_MAX_RESERVED_SIZE 112
#define IGCL_CTL_MAX_RESERVED_SIZE 108
typedef enum ctl_adapter_properties_flag_t {
CTL_ADAPTER_PROPERTIES_FLAG_INTEGRATED = 1,
@@ -101,6 +102,7 @@ typedef struct ctl_device_adapter_properties_t {
uint16_t pci_subsys_id;
uint16_t pci_subsys_vendor_id;
ctl_adapter_bdf_t adapter_bdf;
uint32_t num_xe_cores;
char reserved[IGCL_CTL_MAX_RESERVED_SIZE];
} ctl_device_adapter_properties_t;
@@ -214,3 +216,45 @@ typedef struct ctl_freq_properties_t {
// https://intel.github.io/drivers.gpu.control-library/Control/api.html#_CPPv425ctlFrequencyGetProperties17ctl_freq_handle_tP21ctl_freq_properties_t
extern ctl_result_t ctlFrequencyGetProperties(ctl_freq_handle_t hFrequency, ctl_freq_properties_t* pProperties);
// https://intel.github.io/drivers.gpu.control-library/Control/api.html#_CPPv415ctl_pci_speed_t
typedef struct ctl_pci_speed_t {
uint32_t Size;
uint8_t Version;
int32_t gen;
int32_t width;
int64_t maxBandwidth;
} ctl_pci_speed_t;
// https://intel.github.io/drivers.gpu.control-library/Control/api.html#_CPPv417ctl_pci_address_t
typedef struct ctl_pci_address_t {
uint32_t Size;
uint8_t Version;
uint32_t domain;
uint32_t bus;
uint32_t device;
uint32_t function;
} ctl_pci_address_t;
// https://intel.github.io/drivers.gpu.control-library/Control/api.html#_CPPv420ctl_pci_properties_t
typedef struct ctl_pci_properties_t {
uint32_t Size;
uint8_t Version;
ctl_pci_address_t address;
ctl_pci_speed_t maxSpeed;
bool resizable_bar_supported;
bool resizable_bar_enabled;
} ctl_pci_properties_t;
// https://intel.github.io/drivers.gpu.control-library/Control/api.html#ctlpcigetproperties
extern ctl_result_t ctlPciGetProperties(ctl_device_adapter_handle_t hDAhandle, ctl_pci_properties_t* pProperties);
// https://intel.github.io/drivers.gpu.control-library/Control/api.html#ctl-pci-state-t
typedef struct _ctl_pci_state_t {
uint32_t Size;
uint8_t Version;
ctl_pci_speed_t speed;
} ctl_pci_state_t;
// https://intel.github.io/drivers.gpu.control-library/Control/api.html#ctlpcigetstate
extern ctl_result_t ctlPciGetState(ctl_device_adapter_handle_t hDAhandle, ctl_pci_state_t* pState);
+5 -1
View File
@@ -1,7 +1,11 @@
#pragma once
/* SPDX-License-Identifier: MIT */
#include <drm.h>
#if __has_include(<drm.h>)
#include <drm.h>
#else
#include <drm/drm.h>
#endif
// xe_drm.h
+60 -21
View File
@@ -4,6 +4,8 @@
// THIS FILE IS CREATED FROM SCRATCH, BY READING THE OFFICIAL NVML API
// DOCUMENTATION REFERENCED BELOW, IN ORDER TO MAKE FASTFETCH MIT COMPLIANT.
// https://docs.nvidia.com/deploy/pdf/NVML_API_Reference_Guide.pdf
// https://docs.nvidia.com/deploy/nvml-api/group__nvmlDeviceStructs.html
#define NVML_DEVICE_PCI_BUS_ID_BUFFER_SIZE 32
#define NVML_DEVICE_PCI_BUS_ID_BUFFER_V2_SIZE 16
@@ -11,6 +13,7 @@
typedef enum { NVML_SUCCESS = 0 } nvmlReturn_t;
typedef struct nvmlDevice_t* nvmlDevice_t;
#define NVML_STRUCT_VERSION(data, ver) (unsigned int)(sizeof(nvml##data##_v##ver##_t) | (ver << 24U))
// https://docs.nvidia.com/deploy/nvml-api/structnvmlPciInfo__t.html
// PCI information about a GPU device
@@ -54,7 +57,6 @@ typedef struct {
unsigned long long used;
} nvmlMemory_v2_t;
// https://github.com/NVIDIA/nvidia-settings/issues/78#issuecomment-1012837988
enum { nvmlMemory_v2 = (unsigned int) (sizeof(nvmlMemory_v2_t) | (2 << 24U)) };
// https://docs.nvidia.com/deploy/nvml-api/structnvmlMemory__t.html#structnvmlMemory__t
// Memory allocation information for a device (v1)
@@ -117,36 +119,73 @@ typedef struct
unsigned int memory;
} nvmlUtilization_t;
typedef struct {
// v1
unsigned int version;
// input
nvmlTemperatureSensors_t sensorType;
// output
int temperature;
} nvmlTemperature_v1_t;
// https://docs.nvidia.com/deploy/nvml-api/group__nvmlInitializationAndCleanup.html#group__nvmlInitializationAndCleanup
// Initialize NVML, but don't initialize any GPUs yet
nvmlReturn_t nvmlInit_v2(void);
extern nvmlReturn_t nvmlInit_v2(void);
// Shut down NVML by releasing all GPU resources previously allocated with nvmlInit_v2()
nvmlReturn_t nvmlShutdown(void);
extern nvmlReturn_t nvmlShutdown(void);
// https://docs.nvidia.com/deploy/nvml-api/group__nvmlDeviceQueries.html
// v545
// Retrieves the PCI attributes of this device
extern nvmlReturn_t nvmlDeviceGetPciInfo_v3(nvmlDevice_t device, nvmlPciInfo_t* pci);
// v510
// Gets the device's core count
extern nvmlReturn_t nvmlDeviceGetNumGpuCores(nvmlDevice_t device, unsigned int* numCores);
// Retrieves the amount of used, free, reserved and total memory available on the device, in bytes. The reserved amount is supported on version 2 only
extern nvmlReturn_t nvmlDeviceGetMemoryInfo_v2(nvmlDevice_t device, nvmlMemory_v2_t* memory);
// v361
// Retrieves the maximum clock speeds for the device
extern nvmlReturn_t nvmlDeviceGetMaxClockInfo(nvmlDevice_t device, nvmlClockType_t type, unsigned int* clock);
// v340
// Retrieves the brand of this device
extern nvmlReturn_t nvmlDeviceGetBrand(nvmlDevice_t device, nvmlBrandType_t* type);
// v5.319 RC
// Retrieves the number of compute devices in the system. A compute device is a single GPU
extern nvmlReturn_t nvmlDeviceGetCount_v2(unsigned int* deviceCount);
// Acquire the handle for a particular device, based on its index
extern nvmlReturn_t nvmlDeviceGetHandleByIndex_v2(unsigned int index, nvmlDevice_t* device);
// Acquire the handle for a particular device, based on its PCI bus id
extern nvmlReturn_t nvmlDeviceGetHandleByPciBusId_v2(const char* pciBusId, nvmlDevice_t* device);
// Retrieves the PCI attributes of this device
extern nvmlReturn_t nvmlDeviceGetPciInfo_v3(nvmlDevice_t device, nvmlPciInfo_t* pci);
// Retrieves the current temperature readings for the device, in degrees C
extern nvmlReturn_t nvmlDeviceGetTemperature(nvmlDevice_t device, nvmlTemperatureSensors_t sensorType, unsigned int* temp);
// Retrieves the amount of used, free, reserved and total memory available on the device, in bytes. The reserved amount is supported on version 2 only
extern nvmlReturn_t nvmlDeviceGetMemoryInfo_v2(nvmlDevice_t device, nvmlMemory_v2_t* memory);
// Retrieves the amount of used, free, total memory available on the device, in bytes.
extern nvmlReturn_t nvmlDeviceGetMemoryInfo(nvmlDevice_t device, nvmlMemory_t* memory);
// Gets the device's core count
extern nvmlReturn_t nvmlDeviceGetNumGpuCores(nvmlDevice_t device, unsigned int* numCores);
// Retrieves the maximum clock speeds for the device
extern nvmlReturn_t nvmlDeviceGetMaxClockInfo(nvmlDevice_t device, nvmlClockType_t type, unsigned int* clock);
// Retrieves the brand of this device
extern nvmlReturn_t nvmlDeviceGetBrand(nvmlDevice_t device, nvmlBrandType_t* type);
// Retrieves the current utilization rates for the device
extern nvmlReturn_t nvmlDeviceGetUtilizationRates(nvmlDevice_t device, nvmlUtilization_t* utilization);
// Retrieves the globally unique immutable UUID associated with this device, as a 5 part hexadecimal string, that augments the immutable, board serial identifier.
extern nvmlReturn_t nvmlDeviceGetIndex(nvmlDevice_t device, unsigned int* index);
// v3.295
// Retrieves the maximum PCIe link generation possible with this device and system
extern nvmlReturn_t nvmlDeviceGetMaxPcieLinkGeneration(nvmlDevice_t device, unsigned int* maxLinkGen);
// Retrieves the maximum PCIe link width possible with this device and system
extern nvmlReturn_t nvmlDeviceGetMaxPcieLinkWidth(nvmlDevice_t device, unsigned int* maxLinkWidth);
// Retrieves the current PCIe link generation
extern nvmlReturn_t nvmlDeviceGetCurrPcieLinkGeneration(nvmlDevice_t device, unsigned int* currLinkGen);
// Retrieves the current PCIe link width
extern nvmlReturn_t nvmlDeviceGetCurrPcieLinkWidth(nvmlDevice_t device, unsigned int* currLinkWidth);
// v0
// Acquire the handle for a particular device, based on its PCI bus id
extern nvmlReturn_t nvmlDeviceGetHandleByPciBusId_v2(const char* pciBusId, nvmlDevice_t* device);
// Retrieves the amount of used, free, total memory available on the device, in bytes.
extern nvmlReturn_t nvmlDeviceGetMemoryInfo(nvmlDevice_t device, nvmlMemory_t* memory);
// Retrieves the current utilization rates for the device
extern nvmlReturn_t nvmlDeviceGetUtilizationRates(nvmlDevice_t device, nvmlUtilization_t* utilization);
// Retrieves the name of this device.
extern nvmlReturn_t nvmlDeviceGetName(nvmlDevice_t device, char* name, unsigned int length);
// Retrieves the current temperature readings (in degrees C) for the given device
extern nvmlReturn_t nvmlDeviceGetTemperatureV(nvmlDevice_t device, nvmlTemperature_v1_t* temperature);
enum {
nvmlMemory_v2 = NVML_STRUCT_VERSION(Memory, 2),
nvmlTemperature_v1 = NVML_STRUCT_VERSION(Temperature, 1),
};
+1 -3
View File
@@ -1,7 +1,5 @@
#include "libc.h"
#define FF_STR_INDIR(x) #x
#define FF_STR(x) FF_STR_INDIR(x)
#include "common/strutil.h"
#include <features.h>
+1 -3
View File
@@ -1,7 +1,5 @@
#include "libc.h"
#define FF_STR_INDIR(x) #x
#define FF_STR(x) FF_STR_INDIR(x)
#include "common/strutil.h"
#include <features.h>
+1
View File
@@ -101,6 +101,7 @@ static const char* openCLHandleData(OpenCLData* data, FFOpenCLResult* result) {
gpu->deviceId = (size_t) deviceID;
gpu->frequency = FF_GPU_FREQUENCY_UNSET;
gpu->coreUsage = FF_GPU_CORE_USAGE_UNSET;
gpu->pcieSpeed = FF_GPU_PCIE_SPEED_UNSET;
if (data->ffclGetDeviceInfo(deviceID, CL_DEVICE_VERSION, sizeof(buffer), buffer, NULL) == CL_SUCCESS) {
ffStrbufSetS(&gpu->platformApi, buffer);
+43 -38
View File
@@ -1,6 +1,7 @@
#include "opengl.h"
#include "common/debug.h"
#include "common/library.h"
#include "common/io.h"
#if __has_include(<GL/gl.h>)
#include <GL/gl.h>
@@ -34,8 +35,6 @@ void ffOpenGLHandleResult(FFOpenGLResult* result, __typeof__(&glGetString) ffglG
typedef struct EGLData {
FF_LIBRARY_SYMBOL(glGetString)
FF_LIBRARY_SYMBOL(eglGetProcAddress)
FF_LIBRARY_SYMBOL(eglGetDisplay)
FF_LIBRARY_SYMBOL(eglQueryString)
FF_LIBRARY_SYMBOL(eglInitialize)
FF_LIBRARY_SYMBOL(eglBindAPI)
@@ -132,38 +131,7 @@ static const char* eglHandleDisplay(FFOpenGLResult* result, EGLData* data) {
return error;
}
static const char* eglHandleData(FFOpenGLResult* result, EGLData* data) {
FF_DEBUG("Resolving glGetString via eglGetProcAddress()");
data->ffglGetString = (__typeof__(&glGetString)) data->ffeglGetProcAddress("glGetString");
if (!data->ffglGetString) {
FF_DEBUG("eglGetProcAddress('glGetString') returned NULL");
return "eglGetProcAddress(glGetString) returned NULL";
}
#if EGL_VERSION_1_5
PFNEGLGETPLATFORMDISPLAYEXTPROC ffeglGetPlatformDisplay = (PFNEGLGETPLATFORMDISPLAYEXTPROC) data->ffeglGetProcAddress("eglGetPlatformDisplay");
if (ffeglGetPlatformDisplay) {
FF_DEBUG("Trying eglGetPlatformDisplay(EGL_PLATFORM_SURFACELESS_MESA)");
data->display = ffeglGetPlatformDisplay(EGL_PLATFORM_SURFACELESS_MESA, NULL, NULL);
FF_DEBUG("eglGetPlatformDisplay() %s", data->display == EGL_NO_DISPLAY ? "failed" : "succeeded");
} else {
FF_DEBUG("eglGetPlatformDisplay is unavailable, falling back to eglGetDisplay");
}
if (!ffeglGetPlatformDisplay || data->display == EGL_NO_DISPLAY)
#endif
{
FF_DEBUG("Trying eglGetDisplay(EGL_DEFAULT_DISPLAY)");
data->display = data->ffeglGetDisplay(EGL_DEFAULT_DISPLAY);
if (data->display == EGL_NO_DISPLAY) {
FF_DEBUG("eglGetDisplay() returned EGL_NO_DISPLAY");
return "eglGetDisplay returned EGL_NO_DISPLAY";
}
FF_DEBUG("eglGetDisplay() succeeded");
}
static const char* eglHandlePreDisplay(FFOpenGLResult* result, EGLData* data) {
EGLint major, minor;
if (data->ffeglInitialize(data->display, &major, &minor) == EGL_FALSE) {
FF_DEBUG("eglInitialize() returned EGL_FALSE");
@@ -185,8 +153,7 @@ const char* ffOpenGLDetectByEGL(FFOpenGLResult* result) {
EGLData eglData;
FF_LIBRARY_LOAD_MESSAGE(egl, "libEGL" FF_LIBRARY_EXTENSION, 1);
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(egl, eglData, eglGetProcAddress);
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(egl, eglData, eglGetDisplay);
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(egl, eglGetProcAddress);
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(egl, eglData, eglQueryString);
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(egl, eglData, eglInitialize);
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(egl, eglData, eglBindAPI);
@@ -198,12 +165,50 @@ const char* ffOpenGLDetectByEGL(FFOpenGLResult* result) {
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(egl, eglData, eglDestroySurface);
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(egl, eglData, eglTerminate);
FF_DEBUG("Resolving glGetString via eglGetProcAddress()");
eglData.ffglGetString = (__typeof__(&glGetString)) ffeglGetProcAddress("glGetString");
if (!eglData.ffglGetString) {
FF_DEBUG("eglGetProcAddress('glGetString') returned NULL");
return "eglGetProcAddress(glGetString) returned NULL";
}
FF_DEBUG("Loaded EGL library and required symbols");
FF_SUPPRESS_IO();
FF_DEBUG("Suppressed stdout/stderr during EGL probing");
const char* error = eglHandleData(result, &eglData);
EGLDisplay display = EGL_NO_DISPLAY;
#if EGL_VERSION_1_5
PFNEGLGETPLATFORMDISPLAYEXTPROC ffeglGetPlatformDisplay = (PFNEGLGETPLATFORMDISPLAYEXTPROC) ffeglGetProcAddress("eglGetPlatformDisplay");
if (!ffeglGetPlatformDisplay) {
ffeglGetPlatformDisplay = (PFNEGLGETPLATFORMDISPLAYEXTPROC) ffeglGetProcAddress("eglGetPlatformDisplayEXT");
}
if (ffeglGetPlatformDisplay) {
FF_DEBUG("Trying eglGetPlatformDisplay(EGL_PLATFORM_SURFACELESS_MESA)");
display = ffeglGetPlatformDisplay(EGL_PLATFORM_SURFACELESS_MESA, EGL_DEFAULT_DISPLAY, NULL);
FF_DEBUG("eglGetPlatformDisplay() %s", display == EGL_NO_DISPLAY ? "failed" : "succeeded");
} else {
FF_DEBUG("eglGetPlatformDisplay is unavailable, falling back to eglGetDisplay");
}
if (display == EGL_NO_DISPLAY)
#endif
{
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(egl, eglGetDisplay);
FF_DEBUG("Trying eglGetDisplay(EGL_DEFAULT_DISPLAY)");
display = ffeglGetDisplay(EGL_DEFAULT_DISPLAY);
if (display == EGL_NO_DISPLAY) {
FF_DEBUG("eglGetDisplay() returned EGL_NO_DISPLAY");
return "eglGetDisplay returned EGL_NO_DISPLAY";
}
FF_DEBUG("eglGetDisplay() succeeded");
}
eglData.display = display;
const char* error = eglHandlePreDisplay(result, &eglData);
FF_DEBUG("OpenGL detection via EGL returns: %s", error ?: "success");
return error;
+1
View File
@@ -44,6 +44,7 @@ static bool detectOSCodeName(FFOSResult* os)
switch (num)
{
case 27: ffStrbufSetStatic(&os->codename, "Golden Gate"); return true;
case 26:
case 16: ffStrbufSetStatic(&os->codename, "Tahoe"); return true;
case 15: ffStrbufSetStatic(&os->codename, "Sequoia"); return true;
-3
View File
@@ -8,9 +8,6 @@
#include <string.h>
#include <stdlib.h>
#define FF_STR_INDIR(x) #x
#define FF_STR(x) FF_STR_INDIR(x)
static bool parseLsbRelease(const char* fileName, FFOSResult* result) {
return ffParsePropFileValues(fileName, 4, (FFpropquery[]) {
{ "DISTRIB_ID =", &result->id },
+2
View File
@@ -22,6 +22,7 @@ typedef struct FFPackagesResult {
uint32_t guixUser;
uint32_t hpkgSystem;
uint32_t hpkgUser;
uint32_t installrelease;
uint32_t kiss;
uint32_t linglong;
uint32_t lpkg;
@@ -40,6 +41,7 @@ typedef struct FFPackagesResult {
uint32_t pkg;
uint32_t pkgsrc;
uint32_t pkgtool;
uint32_t porg;
uint32_t rpm;
uint32_t scoopGlobal;
uint32_t scoopUser;
+56 -5
View File
@@ -84,7 +84,7 @@ static uint32_t countFilesRecursiveImpl(FFstrbuf* baseDirPath, const char* filen
return 1;
}
DIR* dirp = opendir(baseDirPath->chars);
FF_AUTO_CLOSE_DIR DIR* dirp = opendir(baseDirPath->chars);
if (dirp == NULL) {
return 0;
}
@@ -106,7 +106,6 @@ static uint32_t countFilesRecursiveImpl(FFstrbuf* baseDirPath, const char* filen
ffStrbufSubstrBefore(baseDirPath, baseDirPathLength);
}
closedir(dirp);
return sum;
}
@@ -138,7 +137,7 @@ static uint32_t getNumElementsBySuffix(FFstrbuf* baseDir, const char* dirname, c
}
static uint32_t getXBPSImpl(FFstrbuf* baseDir) {
DIR* dir = opendir(baseDir->chars);
FF_AUTO_CLOSE_DIR DIR* dir = opendir(baseDir->chars);
if (dir == NULL) {
return 0;
}
@@ -157,7 +156,6 @@ static uint32_t getXBPSImpl(FFstrbuf* baseDir) {
break;
}
closedir(dir);
return result;
}
@@ -458,6 +456,33 @@ static uint32_t getPacmanPackages(FFstrbuf* baseDir) {
return getNumElements(baseDir, dbPath.chars, true);
}
static uint32_t getEmergePackagesImpl(FFstrbuf* baseDir) {
FF_AUTO_CLOSE_DIR DIR* dirp = opendir(baseDir->chars);
if (dirp == NULL)
return 0;
uint32_t result = 0;
struct dirent *entry;
while ((entry = readdir(dirp)) != NULL)
{
if (entry->d_type != DT_DIR || entry->d_name[0] == '.')
continue;
result += getNumElements(baseDir, entry->d_name, true);
}
return result;
}
static uint32_t getEmergePackages(FFstrbuf* baseDir, const char* dirname) {
uint32_t baseDirLength = baseDir->length;
ffStrbufAppendS(baseDir, dirname);
ffStrbufAppendC(baseDir, '/');
uint32_t result = getEmergePackagesImpl(baseDir);
ffStrbufSubstrBefore(baseDir, baseDirLength);
return result;
}
static void getPackageCounts(FFstrbuf* baseDir, FFPackagesResult* packageCounts, FFPackagesOptions* options) {
if (FF_PACKAGES_IS_ENABLED(options, APK)) {
packageCounts->apk += getNumStrings(baseDir, "/lib/apk/db/installed", "C:Q", "apk");
@@ -469,7 +494,7 @@ static void getPackageCounts(FFstrbuf* baseDir, FFPackagesResult* packageCounts,
packageCounts->lpkg += getNumStrings(baseDir, "/opt/Loc-OS-LPKG/installed-lpkg/Listinstalled-lpkg.list", "\n", "lpkg");
}
if (FF_PACKAGES_IS_ENABLED(options, EMERGE)) {
packageCounts->emerge += countFilesRecursive(baseDir, "/var/db/pkg", "SIZE");
packageCounts->emerge += getEmergePackages(baseDir, "/var/db/pkg");
}
if (FF_PACKAGES_IS_ENABLED(options, EOPKG)) {
packageCounts->eopkg += getNumElements(baseDir, "/var/lib/eopkg/package", true);
@@ -493,6 +518,9 @@ static void getPackageCounts(FFstrbuf* baseDir, FFPackagesResult* packageCounts,
if (FF_PACKAGES_IS_ENABLED(options, PKGTOOL)) {
packageCounts->pkgtool += getNumElements(baseDir, "/var/log/packages", false);
}
if (FF_PACKAGES_IS_ENABLED(options, PORG)) {
packageCounts->porg += getNumElements(baseDir, "/var/log/porg", false);
}
if (FF_PACKAGES_IS_ENABLED(options, RPM)) {
// `Sigmd5` is the only table that doesn't contain the virtual `gpg-pubkey` package
packageCounts->rpm += getSQLite3Int(baseDir, "/var/lib/rpm/rpmdb.sqlite", "SELECT count(*) FROM Sigmd5", "rpm");
@@ -586,6 +614,25 @@ static void getPackageCountsBedrock(FFstrbuf* baseDir, FFPackagesResult* package
ffStrbufSubstrBefore(baseDir, baseDirLength);
}
static uint32_t getInstallReleasePackages(FFstrbuf* baseDir) {
uint32_t result = 0;
uint32_t baseDirLength = baseDir->length;
ffStrbufAppendS(baseDir, ".config/install_release/state.json");
if (ffPathExists(baseDir->chars, FF_PATHTYPE_ANY)) {
yyjson_doc* doc = yyjson_read_file(baseDir->chars, YYJSON_READ_NOFLAG, NULL, NULL);
if (doc != NULL) {
yyjson_val* root = yyjson_doc_get_root(doc);
if (yyjson_is_obj(root)) {
result = (uint32_t) yyjson_obj_size(root);
}
yyjson_doc_free(doc);
}
}
ffStrbufSubstrBefore(baseDir, baseDirLength);
return result;
}
void ffDetectPackagesImpl(FFPackagesResult* result, FFPackagesOptions* options) {
FF_STRBUF_AUTO_DESTROY baseDir = ffStrbufCreateA(512);
ffStrbufAppendS(&baseDir, FASTFETCH_TARGET_DIR_ROOT);
@@ -648,4 +695,8 @@ void ffDetectPackagesImpl(FFPackagesResult* result, FFPackagesOptions* options)
result->appimage += getNumElementsBySuffix(&baseDir, "/AppImages", ".appimage");
result->appimage += getNumElementsBySuffix(&baseDir, "/Applications", ".appimage");
}
if (FF_PACKAGES_IS_ENABLED(options, INSTALLRELEASE)) {
result->installrelease = getInstallReleasePackages(&baseDir);
}
}
@@ -401,6 +401,24 @@ static void detectWestonTerminal(FFTerminalFontResult* terminalFont) {
ffFontInitValues(&terminalFont->font, font.chars, size.chars);
}
static void detectKmscon(FFTerminalFontResult* terminalFont) {
FF_STRBUF_AUTO_DESTROY fontName = ffStrbufCreate();
FF_STRBUF_AUTO_DESTROY fontSize = ffStrbufCreate();
ffParsePropFileConfigValues("kmscon/kmscon.conf", 2, (FFpropquery[]){
{ "font-size=", &fontSize },
{ "font-name=", &fontName },
});
if (fontName.length == 0) {
ffStrbufSetStatic(&fontName, "Hack Nerd Font");
}
if (fontSize.length == 0) {
ffStrbufSetStatic(&fontSize, "18");
}
ffFontInitValues(&terminalFont->font, fontName.chars, fontSize.chars);
}
static void detectUrxvt(FFTerminalFontResult* terminalFont) {
FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreate();
@@ -522,6 +540,8 @@ ffDetectTerminalFontPlatform
detectWarp(terminalFont);
} else if (ffStrbufIgnCaseEqualS(&terminal->processName, "weston-terminal")) {
detectWestonTerminal(terminalFont);
} else if (ffStrbufIgnCaseEqualS(&terminal->processName, "kmscon")) {
detectKmscon(terminalFont);
} else if (ffStrbufStartsWithIgnCaseS(&terminal->processName, "terminator")) {
detectTerminator(terminalFont);
} else if (ffStrbufStartsWithIgnCaseS(&terminal->processName, "sakura")) {
@@ -503,6 +503,36 @@ FF_A_UNUSED static bool getTerminalVersionWeston(FF_A_UNUSED FFstrbuf* exe, FFst
return version->length > 0;
}
FF_A_UNUSED static bool extractKmsconVersion(const char* str, FF_A_UNUSED uint32_t len, void* userdata) {
if (!ffStrStartsWith(str, "v")) {
return true;
}
int count = 0;
sscanf(str, "v%*d.%*d.%*d%n", &count);
if (count == 0) {
return true;
}
ffStrbufSetNS((FFstrbuf*) userdata, (uint32_t) count - 1, str + 1);
return false;
}
FF_A_UNUSED static bool getTerminalVersionKmscon(FFstrbuf* exe, FFstrbuf* version) {
if (ffIsAbsolutePath(exe->chars)) {
ffBinaryExtractStrings(exe->chars, extractKmsconVersion, version, (uint32_t) strlen("v0.0.0"));
if (version->length) {
return true;
}
}
if (!getExeVersionRaw(exe, version)) {
return false;
}
// kmscon version v10.0.0
ffStrbufSubstrAfterLastC(version, ' ');
return version->length > 0;
}
static bool getTerminalVersionContour(FFstrbuf* exe, FFstrbuf* version) {
const char* env = getenv("TERMINAL_VERSION_STRING");
if (env) {
@@ -840,6 +870,14 @@ bool fftsGetTerminalVersion(FFstrbuf* processName, FF_A_UNUSED FFstrbuf* exe, FF
#endif
#ifdef __linux__
if (ffStrbufIgnCaseEqualS(processName, "kmscon")) {
return getTerminalVersionKmscon(exe, version);
}
#endif
#ifdef _WIN32
if (ffStrbufIgnCaseEqualS(processName, "WindowsTerminal.exe")) {
+1 -3
View File
@@ -1,4 +1,5 @@
#include "version.h"
#include "common/strutil.h"
#if defined(__x86_64__)
#define FF_ARCHITECTURE "x86_64"
@@ -62,9 +63,6 @@
#define FF_SYSNAME "Unknown"
#endif
#define FF_STR_INDIR(x) #x
#define FF_STR(x) FF_STR_INDIR(x)
FFVersionResult ffVersionResult = {
.projectName = FASTFETCH_PROJECT_NAME,
.sysName = FF_SYSNAME,
+1
View File
@@ -280,6 +280,7 @@ static const char* detectVulkan(FFVulkanResult* result) {
gpu->temperature = FF_GPU_TEMP_UNSET;
gpu->frequency = FF_GPU_FREQUENCY_UNSET;
gpu->coreUsage = FF_GPU_CORE_USAGE_UNSET;
gpu->pcieSpeed = FF_GPU_PCIE_SPEED_UNSET;
next:
continue;
+13 -3
View File
@@ -133,14 +133,24 @@ const char* ffDetectWifi(FFlist* result) {
ffStrbufSetStatic(&item->conn.security, "Shared");
break;
case IEEE80211_AUTH_8021X:
ffStrbufSetStatic(&item->conn.security, "8021X");
ffStrbufSetStatic(&item->conn.security, "802.1x");
break;
case IEEE80211_AUTH_AUTO:
ffStrbufSetStatic(&item->conn.security, "Auto");
break;
case IEEE80211_AUTH_WPA:
ffStrbufSetStatic(&item->conn.security, "WPA");
case IEEE80211_AUTH_WPA: {
ireq.i_type = IEEE80211_IOC_WPA;
if (ioctl(sock, SIOCG80211, &ireq) >= 0) {
switch (ireq.i_val) {
case 2: ffStrbufSetStatic(&item->conn.security, "WPA2"); break;
case 3: ffStrbufSetStatic(&item->conn.security, "WPA1+2"); break;
default: ffStrbufSetStatic(&item->conn.security, "WPA"); break;
}
} else {
ffStrbufSetStatic(&item->conn.security, "WPA");
}
break;
}
default:
ffStrbufSetF(&item->conn.security, "Unknown (%d)", ireq.i_val);
break;
+20
View File
@@ -169,6 +169,22 @@ static const char* getNiri(FFstrbuf* result) {
return "Failed to run command `niri --version`";
}
static const char* getWeston(FFstrbuf* result) {
FF_STRBUF_AUTO_DESTROY path = ffStrbufCreate();
const char* error = ffFindExecutableInPath("weston", &path);
if (error) {
return "Failed to find weston executable path";
}
if (ffProcessAppendStdOut(result, (char* const[]) { path.chars, "--version", NULL }) == NULL) { // weston 8.0.0\n...
ffStrbufSubstrBeforeFirstC(result, '\n');
ffStrbufSubstrAfterLastC(result, ' ');
return NULL;
}
return "Failed to run command `weston --version`";
}
#ifdef __linux__
static const char* getWslg(FFstrbuf* result) {
if (!ffAppendFileBuffer("/mnt/wslg/versions.txt", result)) {
@@ -307,6 +323,10 @@ const char* ffDetectWMVersion(const FFstrbuf* wmName, FFstrbuf* result, FF_A_UNU
return getNiri(result);
}
if (ffStrbufEqualS(wmName, "weston")) {
return getWeston(result);
}
#if __linux__
if (ffStrbufEqualS(wmName, "WSLg")) {
return getWslg(result);
+31 -10
View File
@@ -15,6 +15,7 @@
#include <ctype.h>
#include <string.h>
FF_A_COLD
static void printCommandFormatHelpJson(void) {
yyjson_mut_doc* doc = yyjson_mut_doc_new(NULL);
yyjson_mut_val* root = yyjson_mut_obj(doc);
@@ -49,6 +50,7 @@ static void printCommandFormatHelpJson(void) {
yyjson_mut_doc_free(doc);
}
FF_A_COLD
static void printCommandFormatHelp(const char* command) {
FF_STRBUF_AUTO_DESTROY type = ffStrbufCreateNS((uint32_t) (strlen(command) - strlen("-format")), command);
ffStrbufLowerCase(&type);
@@ -85,6 +87,7 @@ static void printCommandFormatHelp(const char* command) {
fprintf(stderr, "Error: Module '%s' is not supported\n", type.chars);
}
FF_A_COLD
static void printFullHelp() {
fputs("Fastfetch is a neofetch-like tool for fetching system information and displaying them in a pretty way\n\n", stdout);
if (!instance.config.display.pipe) {
@@ -191,6 +194,7 @@ For detailed information on logo options, module configuration, and formatting,
https://github.com/fastfetch-cli/fastfetch/wiki/Configuration");
}
FF_A_COLD
static bool printSpecificCommandHelp(const char* command) {
yyjson_doc* doc = yyjson_read(FASTFETCH_DATATEXT_JSON_HELP, strlen(FASTFETCH_DATATEXT_JSON_HELP), YYJSON_READ_NOFLAG);
assert(doc);
@@ -301,6 +305,7 @@ static bool printSpecificCommandHelp(const char* command) {
return false;
}
FF_A_COLD
static void printCommandHelp(const char* command) {
if (command == NULL) {
printFullHelp();
@@ -313,6 +318,7 @@ static void printCommandHelp(const char* command) {
}
}
FF_A_COLD
static void listAvailablePresets(bool pretty) {
FF_LIST_FOR_EACH (FFstrbuf, path, instance.state.platform.dataDirs) {
ffStrbufAppendS(path, "fastfetch/presets/");
@@ -327,6 +333,7 @@ static void listAvailablePresets(bool pretty) {
}
}
FF_A_COLD
static void listAvailableLogos(void) {
FF_LIST_FOR_EACH (FFstrbuf, path, instance.state.platform.dataDirs) {
ffStrbufAppendS(path, "fastfetch/logos/");
@@ -334,6 +341,7 @@ static void listAvailableLogos(void) {
}
}
FF_A_COLD
static void listConfigPaths(void) {
FF_LIST_FOR_EACH (FFstrbuf, folder, instance.state.platform.configDirs) {
bool exists = false;
@@ -345,6 +353,7 @@ static void listConfigPaths(void) {
}
}
FF_A_COLD
static void listDataPaths(void) {
FF_LIST_FOR_EACH (FFstrbuf, folder, instance.state.platform.dataDirs) {
ffStrbufAppendS(folder, "fastfetch/");
@@ -352,6 +361,7 @@ static void listDataPaths(void) {
}
}
FF_A_COLD
static void listModules(bool pretty) {
unsigned count = 0;
for (int i = 0; i <= 'Z' - 'A'; ++i) {
@@ -394,20 +404,26 @@ static bool parseJsoncFile(FFdata* data, const char* path, yyjson_read_flag flg)
}
{
const char* error = NULL;
yyjson_val* const root = yyjson_doc_get_root(data->configDoc);
if (!yyjson_is_obj(root)) {
error = "Invalid JSON config format. Root value must be an object";
fputs("JsonConfig Error: Invalid JSON config format. Root value must be an object", stderr);
exit(477);
}
yyjson_val* problematicKey = NULL;
const char* error = NULL;
const char* problematicModule = NULL;
if (
error ||
(error = ffOptionsParseLogoJsonConfig(&instance.config.logo, root)) ||
(error = ffOptionsParseGeneralJsonConfig(&instance.config.general, root)) ||
(error = ffOptionsParseDisplayJsonConfig(&instance.config.display, root)) ||
((error = ffOptionsParseLogoJsonConfig(&instance.config.logo, root, &problematicKey)) && (problematicModule = "logo")) ||
((error = ffOptionsParseGeneralJsonConfig(&instance.config.general, root, &problematicKey)) && (problematicModule = "general")) ||
((error = ffOptionsParseDisplayJsonConfig(&instance.config.display, root, &problematicKey)) && (problematicModule = "display")) ||
false) {
fprintf(stderr, "JsonConfig Error: %s\n", error);
if (problematicKey) {
fprintf(stderr, "JsonConfig Error (%s.%s): %s\n", problematicModule, unsafe_yyjson_get_str(problematicKey), error);
} else {
fprintf(stderr, "JsonConfig Error (%s): %s\n", problematicModule, error);
}
exit(477);
}
}
@@ -415,6 +431,7 @@ static bool parseJsoncFile(FFdata* data, const char* path, yyjson_read_flag flg)
return true;
}
FF_A_COLD
static void generateConfigFile(FFdata* data, bool force, const char* filePath, bool fullConfig) {
if (data->resultDoc) {
fprintf(stderr, "Error: duplicated `--gen-config` or `--format json` flags found\n");
@@ -552,6 +569,7 @@ static void optionParseConfigFile(FFdata* data, const char* key, const char* val
exit(414);
}
FF_A_COLD
static void printVersion() {
FFVersionResult* result = &ffVersionResult;
printf("%s %s%s%s (%s)\n", result->projectName, result->version, result->versionTweak, result->debugMode ? "-debug" : "", result->architecture);
@@ -572,8 +590,7 @@ static void parseCommand(FFdata* data, char* key, char* value) {
if (ffStrEqualsIgnCase(key, "-h") || ffStrEqualsIgnCase(key, "--help")) {
printCommandHelp(value);
exit(0);
}
if (ffStrEqualsIgnCase(key, "--help-raw")) {
} else if (ffStrEqualsIgnCase(key, "--help-raw")) {
puts(FASTFETCH_DATATEXT_JSON_HELP);
exit(0);
} else if (ffStrEqualsIgnCase(key, "-v") || ffStrEqualsIgnCase(key, "--version")) {
@@ -765,9 +782,12 @@ static void run(FFdata* data) {
}
if (instance.state.dynamicInterval > 0) {
ffLogoPrintRemaining(); // `logoLineCacheClear` inside so that ffLogoPrintLine will use `\e[nC` to move the cursor to the right position instead of reprinting the logo
fputs("\e[J", stdout); // Clear from cursor to the end of the screen to prevent artifacts when the new output is shorter than the previous one
fflush(stdout);
ffTimeSleep(instance.state.dynamicInterval);
fputs("\e[H", stdout);
fputs("\e[H", stdout); // Move cursor to the top left corner to overwrite the previous output
instance.state.keysHeight = 0; // Reset keysHeight so `ffLogoPrintRemaining` will recalculate it
} else {
break;
}
@@ -789,6 +809,7 @@ static void run(FFdata* data) {
}
}
FF_A_COLD
static void writeConfigFile(FFdata* data) {
const FFstrbuf* filename = &data->genConfigPath;
+28
View File
@@ -291,6 +291,34 @@ static const FFlogo O[] = {
{
.names = { "openwrt" },
.lines = FASTFETCH_DATATEXT_LOGO_OPENWRT,
.colors = {
FF_COLOR_FG_DEFAULT,
FF_COLOR_FG_BLUE,
},
.colorKeys = FF_COLOR_FG_BLUE,
.colorTitle = FF_COLOR_FG_DEFAULT,
},
#endif
#ifdef FASTFETCH_DATATEXT_LOGO_OPENWRT_SMALL
// OpenWrtSmall
{
.names = { "openwrt_small" },
.type = FF_LOGO_LINE_TYPE_SMALL_BIT,
.lines = FASTFETCH_DATATEXT_LOGO_OPENWRT_SMALL,
.colors = {
FF_COLOR_FG_DEFAULT,
FF_COLOR_FG_BLUE,
},
.colorKeys = FF_COLOR_FG_BLUE,
.colorTitle = FF_COLOR_FG_DEFAULT,
},
#endif
#ifdef FASTFETCH_DATATEXT_LOGO_OPENWRT_OLD
// OpenWrtOld
{
.names = { "openwrt_old" },
.type = FF_LOGO_LINE_TYPE_ALTER_BIT,
.lines = FASTFETCH_DATATEXT_LOGO_OPENWRT_OLD,
.colors = {
FF_COLOR_FG_BLUE,
},
+18 -9
View File
@@ -1,9 +1,18 @@
_______
| |.-----.-----.-----.
| - || _ | -__| |
|_______|| __|_____|__|__|
|__|
________ __
| | | |.----.| |_
| | | || _|| _|
|________||__| |____|
..,,..
,;odOMMMMMMMMObo:.
,odOMMMMMO""''""OMMMMMObo.
.dMMMM" .,,. "OMMMb,
'0" ,;ddMMMMMMMMbb:. "0'
oOMMMMO""''""OMMMMOo
$2;. $1'0" .,,. "0' $2.:
.OMM* $1.odMMMMMMbo. $2*MMO.
MMMO $1"0"````"0" $2OMMM
iOMM $1.oo. $2MMMi
OMMl $1:MMMM: $2lMMO
iMMM $1'oo' $2MMMi
OMMb $2dMMO
'OMMO. ,OMMO'
"MMMb. ,dMMM"
"MMMMbgo-,,-ogdMMMM"
"*MMMMMMMMMM*"
`'""'`
+9
View File
@@ -0,0 +1,9 @@
_______
| |.-----.-----.-----.
| - || _ | -__| |
|_______|| __|_____|__|__|
|__|
________ __
| | | |.----.| |_
| | | || _|| _|
|________||__| |____|
+9
View File
@@ -0,0 +1,9 @@
..,..
,odM"""""Mbo,
`.odMMMMMbo.`
$2d,$1" ,mmm, "$2,b
iM $1" . " $2Mi
Ml $1dMb $2lM
'M, $1' $2.M'
"0b. ,d0"
`"WWWWW"`
+12
View File
@@ -3,6 +3,18 @@
#include "common/color.h"
static const FFlogo Z[] = {
#ifdef FASTFETCH_DATATEXT_LOGO_ZERENE
// Zerene
{
.names = { "Zerene" },
.lines = FASTFETCH_DATATEXT_LOGO_ZERENE,
.colors = {
FF_COLOR_FG_BLUE,
},
.colorKeys = FF_COLOR_FG_BLUE,
.colorTitle = FF_COLOR_FG_BLUE,
},
#endif
#ifdef FASTFETCH_DATATEXT_LOGO_ZORIN
// Zorin
{
+18
View File
@@ -0,0 +1,18 @@
MMM
MMMM
MMMMM
MMMMMM
MMMMMMa
MMMMMMMa
MMMMMMM
MMMMMM
MMMM
M
oxdo aMa
aMd aMMMMMMMMM
aMMMMM MMMMMMMMMMMMMMa
MMMMMMMa MMMMMMMMMMMMMMMa
MMMMMMMMa
MMMMMMMMa
MMMMMMM
MMMM
+13 -19
View File
@@ -727,7 +727,7 @@ FFLogoImageResult ffLogoPrintImageImpl(FFLogoRequestData* requestData, const FFI
bool printSuccessful = false;
if (requestData->type == FF_LOGO_TYPE_IMAGE_CHAFA) {
#ifdef FF_HAVE_CHAFA
#if FF_HAVE_CHAFA
printSuccessful = printImageChafa(requestData, &imageData);
#endif
} else if (requestData->type == FF_LOGO_TYPE_IMAGE_KITTY) {
@@ -782,12 +782,9 @@ static uint32_t readCachedUint32(FFLogoRequestData* requestData, const char* cac
return result;
}
static bool printCachedChars(FFLogoRequestData* requestData) {
FF_STRBUF_AUTO_DESTROY content = ffStrbufCreateA(32768);
if (requestData->type == FF_LOGO_TYPE_IMAGE_CHAFA) {
readCachedStrbuf(requestData, &content, FF_CACHE_FILE_CHAFA);
}
static bool printCachedChars(FFLogoRequestData* requestData, const char* cacheFileName) {
FF_STRBUF_AUTO_DESTROY content = ffStrbufCreate();
readCachedStrbuf(requestData, &content, cacheFileName);
if (content.length == 0) {
return false;
@@ -876,14 +873,6 @@ static bool printCachedPixel(FFLogoRequestData* requestData) {
return true;
}
static bool printCached(FFLogoRequestData* requestData) {
if (requestData->type == FF_LOGO_TYPE_IMAGE_CHAFA) {
return printCachedChars(requestData);
} else {
return printCachedPixel(requestData);
}
}
static bool getCharacterPixelDimensions(FFLogoRequestData* requestData) {
#ifdef _WIN32
@@ -947,9 +936,14 @@ static bool printImageIfExistsSlowPath(FFLogoType type, bool printError) {
ffStrbufEnsureEndsWithC(&requestData.cacheDir, '/');
ffStrbufAppendF(&requestData.cacheDir, "%u*%u/", requestData.logoPixelWidth, requestData.logoPixelHeight);
if (!instance.config.logo.recache && printCached(&requestData)) {
ffStrbufDestroy(&requestData.cacheDir);
return true;
if (!instance.config.logo.recache) {
bool cacheValid = requestData.type == FF_LOGO_TYPE_IMAGE_CHAFA
? printCachedChars(&requestData, FF_CACHE_FILE_CHAFA)
: printCachedPixel(&requestData);
if (cacheValid) {
ffStrbufDestroy(&requestData.cacheDir);
return true;
}
}
FFLogoImageResult result = FF_LOGO_IMAGE_RESULT_INIT_ERROR;
@@ -1018,7 +1012,7 @@ bool ffLogoPrintImageIfExists(FFLogoType type, bool printError) {
return printImageKittyIcat(printError);
}
#if !defined(FF_HAVE_CHAFA)
#if !FF_HAVE_CHAFA
if (type == FF_LOGO_TYPE_IMAGE_CHAFA) {
if (printError) {
fputs("Logo: Chafa support is not compiled in\n", stderr);
+33 -31
View File
@@ -461,7 +461,7 @@ static bool updateLogoPath(void) {
return true;
}
#if !FF_MODULE_DISABLE_MEDIA
#if !FF_MODULE_DISABLE_MEDIA
if (ffStrbufIgnCaseEqualS(&options->source, "media-cover")) {
const FFMediaResult* media = ffDetectMedia(true);
if (media->cover.length == 0) {
@@ -470,7 +470,7 @@ static bool updateLogoPath(void) {
ffStrbufSet(&options->source, &media->cover);
return true;
}
#endif
#endif
FF_STRBUF_AUTO_DESTROY fullPath = ffStrbufCreateA(128);
if (ffPathExpandEnv(options->source.chars, &fullPath) && ffPathExists(fullPath.chars, FF_PATHTYPE_FILE)) {
@@ -639,7 +639,7 @@ void ffLogoPrint(void) {
}
if (!ffStrbufEndsWithIgnCaseS(&options->source, ".txt")) {
#if !FF_MODULE_DISABLE_TERMINAL
#if !FF_MODULE_DISABLE_TERMINAL
const FFTerminalResult* terminal = ffDetectTerminal();
bool supportsIterm2 = ffStrbufEqualS(&terminal->prettyName, "iTerm");
@@ -655,15 +655,15 @@ void ffLogoPrint(void) {
ffStrbufIgnCaseEqualS(&terminal->processName, "wezterm") ||
ffStrbufIgnCaseEqualS(&terminal->processName, "wayst") ||
ffStrbufIgnCaseEqualS(&terminal->processName, "ghostty") ||
#ifdef __APPLE__
#ifdef __APPLE__
ffStrbufIgnCaseEqualS(&terminal->processName, "WarpTerminal") ||
#else
#else
ffStrbufIgnCaseEqualS(&terminal->processName, "warp") ||
#endif
#endif
false;
#else
#else
bool supportsKitty = false;
#endif
#endif
// Try to load the logo as an image. If it succeeds, print it and return.
if (logoPrintImageIfExists(supportsKitty ? FF_LOGO_TYPE_IMAGE_KITTY : FF_LOGO_TYPE_IMAGE_CHAFA, false)) {
@@ -685,37 +685,39 @@ void ffLogoPrint(void) {
}
void ffLogoPrintLine(void) {
uint32_t printedLineWidth = 0;
FFLogoLineCacheState* cache = &instance.state.logoLineCache;
FFOptionsLogo* logo = &instance.config.logo;
if (cache->lines.length > 0 && (logo->position == FF_LOGO_POSITION_LEFT || logo->position == FF_LOGO_POSITION_RIGHT) && cache->nextLine < cache->lines.length) {
FFLogoCachedLine* line = FF_LIST_GET(FFLogoCachedLine, cache->lines, cache->nextLine);
if (cache->lines.length > 0) {
// Line cache is enabled. Always move cursor with whitespaces to make lolcat happy
if (cache->nextLine < cache->lines.length) {
// Print logo line and move cursor
FFLogoCachedLine* line = FF_LIST_GET(FFLogoCachedLine, cache->lines, cache->nextLine);
if (logo->position == FF_LOGO_POSITION_RIGHT && line->chars.length > 0) {
printf("\033[9999999C\033[%uD", cache->rightOffset);
ffStrbufWriteTo(&line->chars, stdout);
fputs("\033[G", stdout);
} else {
ffStrbufWriteTo(&line->chars, stdout);
printedLineWidth = line->width;
if (logo->position == FF_LOGO_POSITION_RIGHT) {
printf("\033[9999999C\033[%uD", cache->rightOffset);
ffStrbufWriteTo(&line->chars, stdout);
fputs("\033[G", stdout);
} else {
ffStrbufWriteTo(&line->chars, stdout);
uint32_t remaining = instance.state.logoWidth;
remaining = line->width < remaining ? remaining - line->width : 0;
ffPrintCharTimes(' ', remaining);
}
++cache->nextLine;
} else if (logo->position == FF_LOGO_POSITION_LEFT) {
// Move cursor to the start position
ffPrintCharTimes(' ', instance.state.logoWidth);
}
++cache->nextLine;
} else if (instance.state.logoWidth > 0) {
printf("\033[%uC", instance.state.logoWidth);
}
if (instance.state.logoWidth > 0) {
if (instance.config.logo.position == FF_LOGO_POSITION_LEFT) {
uint32_t remaining = instance.state.logoWidth;
remaining = printedLineWidth < remaining ? remaining - printedLineWidth : 0;
ffPrintCharTimes(' ', remaining);
} else {
printf("\033[%uC", instance.state.logoWidth);
}
}
if (instance.state.dynamicInterval > 0) {
if (instance.state.dynamicInterval > 0 && logo->position == FF_LOGO_POSITION_LEFT) {
fputs("\033[K", stdout); // Clear to the end of the line
// Note that we don't clear the line when the logo is on the right, as it will also clear the logo itself
}
++instance.state.keysHeight;
+1
View File
@@ -66,6 +66,7 @@ bool ffPrintBluetooth(FFBluetoothOptions* options) {
if (devices.length == 0) {
ffPrintError(FF_BLUETOOTH_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "No bluetooth devices found");
return false;
}
uint8_t i = 1;

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